diff --git a/build/three.cjs b/build/three.cjs deleted file mode 100644 index 39ee6663fb0a7a..00000000000000 --- a/build/three.cjs +++ /dev/null @@ -1,53667 +0,0 @@ -/** - * @license - * Copyright 2010-2023 Three.js Authors - * SPDX-License-Identifier: MIT - */ -'use strict'; - -const REVISION = '162dev'; - -const MOUSE = { LEFT: 0, MIDDLE: 1, RIGHT: 2, ROTATE: 0, DOLLY: 1, PAN: 2 }; -const TOUCH = { ROTATE: 0, PAN: 1, DOLLY_PAN: 2, DOLLY_ROTATE: 3 }; -const CullFaceNone = 0; -const CullFaceBack = 1; -const CullFaceFront = 2; -const CullFaceFrontBack = 3; -const BasicShadowMap = 0; -const PCFShadowMap = 1; -const PCFSoftShadowMap = 2; -const VSMShadowMap = 3; -const FrontSide = 0; -const BackSide = 1; -const DoubleSide = 2; -const NoBlending = 0; -const NormalBlending = 1; -const AdditiveBlending = 2; -const SubtractiveBlending = 3; -const MultiplyBlending = 4; -const CustomBlending = 5; -const AddEquation = 100; -const SubtractEquation = 101; -const ReverseSubtractEquation = 102; -const MinEquation = 103; -const MaxEquation = 104; -const ZeroFactor = 200; -const OneFactor = 201; -const SrcColorFactor = 202; -const OneMinusSrcColorFactor = 203; -const SrcAlphaFactor = 204; -const OneMinusSrcAlphaFactor = 205; -const DstAlphaFactor = 206; -const OneMinusDstAlphaFactor = 207; -const DstColorFactor = 208; -const OneMinusDstColorFactor = 209; -const SrcAlphaSaturateFactor = 210; -const ConstantColorFactor = 211; -const OneMinusConstantColorFactor = 212; -const ConstantAlphaFactor = 213; -const OneMinusConstantAlphaFactor = 214; -const NeverDepth = 0; -const AlwaysDepth = 1; -const LessDepth = 2; -const LessEqualDepth = 3; -const EqualDepth = 4; -const GreaterEqualDepth = 5; -const GreaterDepth = 6; -const NotEqualDepth = 7; -const MultiplyOperation = 0; -const MixOperation = 1; -const AddOperation = 2; -const NoToneMapping = 0; -const LinearToneMapping = 1; -const ReinhardToneMapping = 2; -const CineonToneMapping = 3; -const ACESFilmicToneMapping = 4; -const CustomToneMapping = 5; -const AgXToneMapping = 6; -const AttachedBindMode = 'attached'; -const DetachedBindMode = 'detached'; - -const UVMapping = 300; -const CubeReflectionMapping = 301; -const CubeRefractionMapping = 302; -const EquirectangularReflectionMapping = 303; -const EquirectangularRefractionMapping = 304; -const CubeUVReflectionMapping = 306; -const RepeatWrapping = 1000; -const ClampToEdgeWrapping = 1001; -const MirroredRepeatWrapping = 1002; -const NearestFilter = 1003; -const NearestMipmapNearestFilter = 1004; -const NearestMipMapNearestFilter = 1004; -const NearestMipmapLinearFilter = 1005; -const NearestMipMapLinearFilter = 1005; -const LinearFilter = 1006; -const LinearMipmapNearestFilter = 1007; -const LinearMipMapNearestFilter = 1007; -const LinearMipmapLinearFilter = 1008; -const LinearMipMapLinearFilter = 1008; -const UnsignedByteType = 1009; -const ByteType = 1010; -const ShortType = 1011; -const UnsignedShortType = 1012; -const IntType = 1013; -const UnsignedIntType = 1014; -const FloatType = 1015; -const HalfFloatType = 1016; -const UnsignedShort4444Type = 1017; -const UnsignedShort5551Type = 1018; -const UnsignedInt248Type = 1020; -const AlphaFormat = 1021; -const RGBAFormat = 1023; -const LuminanceFormat = 1024; -const LuminanceAlphaFormat = 1025; -const DepthFormat = 1026; -const DepthStencilFormat = 1027; -const RedFormat = 1028; -const RedIntegerFormat = 1029; -const RGFormat = 1030; -const RGIntegerFormat = 1031; -const RGBAIntegerFormat = 1033; - -const RGB_S3TC_DXT1_Format = 33776; -const RGBA_S3TC_DXT1_Format = 33777; -const RGBA_S3TC_DXT3_Format = 33778; -const RGBA_S3TC_DXT5_Format = 33779; -const RGB_PVRTC_4BPPV1_Format = 35840; -const RGB_PVRTC_2BPPV1_Format = 35841; -const RGBA_PVRTC_4BPPV1_Format = 35842; -const RGBA_PVRTC_2BPPV1_Format = 35843; -const RGB_ETC1_Format = 36196; -const RGB_ETC2_Format = 37492; -const RGBA_ETC2_EAC_Format = 37496; -const RGBA_ASTC_4x4_Format = 37808; -const RGBA_ASTC_5x4_Format = 37809; -const RGBA_ASTC_5x5_Format = 37810; -const RGBA_ASTC_6x5_Format = 37811; -const RGBA_ASTC_6x6_Format = 37812; -const RGBA_ASTC_8x5_Format = 37813; -const RGBA_ASTC_8x6_Format = 37814; -const RGBA_ASTC_8x8_Format = 37815; -const RGBA_ASTC_10x5_Format = 37816; -const RGBA_ASTC_10x6_Format = 37817; -const RGBA_ASTC_10x8_Format = 37818; -const RGBA_ASTC_10x10_Format = 37819; -const RGBA_ASTC_12x10_Format = 37820; -const RGBA_ASTC_12x12_Format = 37821; -const RGBA_BPTC_Format = 36492; -const RGB_BPTC_SIGNED_Format = 36494; -const RGB_BPTC_UNSIGNED_Format = 36495; -const RED_RGTC1_Format = 36283; -const SIGNED_RED_RGTC1_Format = 36284; -const RED_GREEN_RGTC2_Format = 36285; -const SIGNED_RED_GREEN_RGTC2_Format = 36286; -const LoopOnce = 2200; -const LoopRepeat = 2201; -const LoopPingPong = 2202; -const InterpolateDiscrete = 2300; -const InterpolateLinear = 2301; -const InterpolateSmooth = 2302; -const ZeroCurvatureEnding = 2400; -const ZeroSlopeEnding = 2401; -const WrapAroundEnding = 2402; -const NormalAnimationBlendMode = 2500; -const AdditiveAnimationBlendMode = 2501; -const TrianglesDrawMode = 0; -const TriangleStripDrawMode = 1; -const TriangleFanDrawMode = 2; -const BasicDepthPacking = 3200; -const RGBADepthPacking = 3201; -const TangentSpaceNormalMap = 0; -const ObjectSpaceNormalMap = 1; - -// Color space string identifiers, matching CSS Color Module Level 4 and WebGPU names where available. -const NoColorSpace = ''; -const SRGBColorSpace = 'srgb'; -const LinearSRGBColorSpace = 'srgb-linear'; -const DisplayP3ColorSpace = 'display-p3'; -const LinearDisplayP3ColorSpace = 'display-p3-linear'; - -const LinearTransfer = 'linear'; -const SRGBTransfer = 'srgb'; - -const Rec709Primaries = 'rec709'; -const P3Primaries = 'p3'; - -const ZeroStencilOp = 0; -const KeepStencilOp = 7680; -const ReplaceStencilOp = 7681; -const IncrementStencilOp = 7682; -const DecrementStencilOp = 7683; -const IncrementWrapStencilOp = 34055; -const DecrementWrapStencilOp = 34056; -const InvertStencilOp = 5386; - -const NeverStencilFunc = 512; -const LessStencilFunc = 513; -const EqualStencilFunc = 514; -const LessEqualStencilFunc = 515; -const GreaterStencilFunc = 516; -const NotEqualStencilFunc = 517; -const GreaterEqualStencilFunc = 518; -const AlwaysStencilFunc = 519; - -const NeverCompare = 512; -const LessCompare = 513; -const EqualCompare = 514; -const LessEqualCompare = 515; -const GreaterCompare = 516; -const NotEqualCompare = 517; -const GreaterEqualCompare = 518; -const AlwaysCompare = 519; - -const StaticDrawUsage = 35044; -const DynamicDrawUsage = 35048; -const StreamDrawUsage = 35040; -const StaticReadUsage = 35045; -const DynamicReadUsage = 35049; -const StreamReadUsage = 35041; -const StaticCopyUsage = 35046; -const DynamicCopyUsage = 35050; -const StreamCopyUsage = 35042; - -const GLSL1 = '100'; -const GLSL3 = '300 es'; - -const _SRGBAFormat = 1035; // fallback for WebGL 1 - -const WebGLCoordinateSystem = 2000; -const WebGPUCoordinateSystem = 2001; - -/** - * https://github.com/mrdoob/eventdispatcher.js/ - */ - -class EventDispatcher { - - addEventListener( type, listener ) { - - if ( this._listeners === undefined ) this._listeners = {}; - - const listeners = this._listeners; - - if ( listeners[ type ] === undefined ) { - - listeners[ type ] = []; - - } - - if ( listeners[ type ].indexOf( listener ) === - 1 ) { - - listeners[ type ].push( listener ); - - } - - } - - hasEventListener( type, listener ) { - - if ( this._listeners === undefined ) return false; - - const listeners = this._listeners; - - return listeners[ type ] !== undefined && listeners[ type ].indexOf( listener ) !== - 1; - - } - - removeEventListener( type, listener ) { - - if ( this._listeners === undefined ) return; - - const listeners = this._listeners; - const listenerArray = listeners[ type ]; - - if ( listenerArray !== undefined ) { - - const index = listenerArray.indexOf( listener ); - - if ( index !== - 1 ) { - - listenerArray.splice( index, 1 ); - - } - - } - - } - - dispatchEvent( event ) { - - if ( this._listeners === undefined ) return; - - const listeners = this._listeners; - const listenerArray = listeners[ event.type ]; - - if ( listenerArray !== undefined ) { - - event.target = this; - - // Make a copy, in case listeners are removed while iterating. - const array = listenerArray.slice( 0 ); - - for ( let i = 0, l = array.length; i < l; i ++ ) { - - array[ i ].call( this, event ); - - } - - event.target = null; - - } - - } - -} - -const _lut = [ '00', '01', '02', '03', '04', '05', '06', '07', '08', '09', '0a', '0b', '0c', '0d', '0e', '0f', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '1a', '1b', '1c', '1d', '1e', '1f', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '2a', '2b', '2c', '2d', '2e', '2f', '30', '31', '32', '33', '34', '35', '36', '37', '38', '39', '3a', '3b', '3c', '3d', '3e', '3f', '40', '41', '42', '43', '44', '45', '46', '47', '48', '49', '4a', '4b', '4c', '4d', '4e', '4f', '50', '51', '52', '53', '54', '55', '56', '57', '58', '59', '5a', '5b', '5c', '5d', '5e', '5f', '60', '61', '62', '63', '64', '65', '66', '67', '68', '69', '6a', '6b', '6c', '6d', '6e', '6f', '70', '71', '72', '73', '74', '75', '76', '77', '78', '79', '7a', '7b', '7c', '7d', '7e', '7f', '80', '81', '82', '83', '84', '85', '86', '87', '88', '89', '8a', '8b', '8c', '8d', '8e', '8f', '90', '91', '92', '93', '94', '95', '96', '97', '98', '99', '9a', '9b', '9c', '9d', '9e', '9f', 'a0', 'a1', 'a2', 'a3', 'a4', 'a5', 'a6', 'a7', 'a8', 'a9', 'aa', 'ab', 'ac', 'ad', 'ae', 'af', 'b0', 'b1', 'b2', 'b3', 'b4', 'b5', 'b6', 'b7', 'b8', 'b9', 'ba', 'bb', 'bc', 'bd', 'be', 'bf', 'c0', 'c1', 'c2', 'c3', 'c4', 'c5', 'c6', 'c7', 'c8', 'c9', 'ca', 'cb', 'cc', 'cd', 'ce', 'cf', 'd0', 'd1', 'd2', 'd3', 'd4', 'd5', 'd6', 'd7', 'd8', 'd9', 'da', 'db', 'dc', 'dd', 'de', 'df', 'e0', 'e1', 'e2', 'e3', 'e4', 'e5', 'e6', 'e7', 'e8', 'e9', 'ea', 'eb', 'ec', 'ed', 'ee', 'ef', 'f0', 'f1', 'f2', 'f3', 'f4', 'f5', 'f6', 'f7', 'f8', 'f9', 'fa', 'fb', 'fc', 'fd', 'fe', 'ff' ]; - -let _seed = 1234567; - - -const DEG2RAD = Math.PI / 180; -const RAD2DEG = 180 / Math.PI; - -// http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/21963136#21963136 -function generateUUID() { - - const d0 = Math.random() * 0xffffffff | 0; - const d1 = Math.random() * 0xffffffff | 0; - const d2 = Math.random() * 0xffffffff | 0; - const d3 = Math.random() * 0xffffffff | 0; - const uuid = _lut[ d0 & 0xff ] + _lut[ d0 >> 8 & 0xff ] + _lut[ d0 >> 16 & 0xff ] + _lut[ d0 >> 24 & 0xff ] + '-' + - _lut[ d1 & 0xff ] + _lut[ d1 >> 8 & 0xff ] + '-' + _lut[ d1 >> 16 & 0x0f | 0x40 ] + _lut[ d1 >> 24 & 0xff ] + '-' + - _lut[ d2 & 0x3f | 0x80 ] + _lut[ d2 >> 8 & 0xff ] + '-' + _lut[ d2 >> 16 & 0xff ] + _lut[ d2 >> 24 & 0xff ] + - _lut[ d3 & 0xff ] + _lut[ d3 >> 8 & 0xff ] + _lut[ d3 >> 16 & 0xff ] + _lut[ d3 >> 24 & 0xff ]; - - // .toLowerCase() here flattens concatenated strings to save heap memory space. - return uuid.toLowerCase(); - -} - -function clamp( value, min, max ) { - - return Math.max( min, Math.min( max, value ) ); - -} - -// compute euclidean modulo of m % n -// https://en.wikipedia.org/wiki/Modulo_operation -function euclideanModulo( n, m ) { - - return ( ( n % m ) + m ) % m; - -} - -// Linear mapping from range to range -function mapLinear( x, a1, a2, b1, b2 ) { - - return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 ); - -} - -// https://www.gamedev.net/tutorials/programming/general-and-gameplay-programming/inverse-lerp-a-super-useful-yet-often-overlooked-function-r5230/ -function inverseLerp( x, y, value ) { - - if ( x !== y ) { - - return ( value - x ) / ( y - x ); - - } else { - - return 0; - - } - -} - -// https://en.wikipedia.org/wiki/Linear_interpolation -function lerp( x, y, t ) { - - return ( 1 - t ) * x + t * y; - -} - -// http://www.rorydriscoll.com/2016/03/07/frame-rate-independent-damping-using-lerp/ -function damp( x, y, lambda, dt ) { - - return lerp( x, y, 1 - Math.exp( - lambda * dt ) ); - -} - -// https://www.desmos.com/calculator/vcsjnyz7x4 -function pingpong( x, length = 1 ) { - - return length - Math.abs( euclideanModulo( x, length * 2 ) - length ); - -} - -// http://en.wikipedia.org/wiki/Smoothstep -function smoothstep( x, min, max ) { - - if ( x <= min ) return 0; - if ( x >= max ) return 1; - - x = ( x - min ) / ( max - min ); - - return x * x * ( 3 - 2 * x ); - -} - -function smootherstep( x, min, max ) { - - if ( x <= min ) return 0; - if ( x >= max ) return 1; - - x = ( x - min ) / ( max - min ); - - return x * x * x * ( x * ( x * 6 - 15 ) + 10 ); - -} - -// Random integer from interval -function randInt( low, high ) { - - return low + Math.floor( Math.random() * ( high - low + 1 ) ); - -} - -// Random float from interval -function randFloat( low, high ) { - - return low + Math.random() * ( high - low ); - -} - -// Random float from <-range/2, range/2> interval -function randFloatSpread( range ) { - - return range * ( 0.5 - Math.random() ); - -} - -// Deterministic pseudo-random float in the interval [ 0, 1 ] -function seededRandom( s ) { - - if ( s !== undefined ) _seed = s; - - // Mulberry32 generator - - let t = _seed += 0x6D2B79F5; - - t = Math.imul( t ^ t >>> 15, t | 1 ); - - t ^= t + Math.imul( t ^ t >>> 7, t | 61 ); - - return ( ( t ^ t >>> 14 ) >>> 0 ) / 4294967296; - -} - -function degToRad( degrees ) { - - return degrees * DEG2RAD; - -} - -function radToDeg( radians ) { - - return radians * RAD2DEG; - -} - -function isPowerOfTwo( value ) { - - return ( value & ( value - 1 ) ) === 0 && value !== 0; - -} - -function ceilPowerOfTwo( value ) { - - return Math.pow( 2, Math.ceil( Math.log( value ) / Math.LN2 ) ); - -} - -function floorPowerOfTwo( value ) { - - return Math.pow( 2, Math.floor( Math.log( value ) / Math.LN2 ) ); - -} - -function setQuaternionFromProperEuler( q, a, b, c, order ) { - - // Intrinsic Proper Euler Angles - see https://en.wikipedia.org/wiki/Euler_angles - - // rotations are applied to the axes in the order specified by 'order' - // rotation by angle 'a' is applied first, then by angle 'b', then by angle 'c' - // angles are in radians - - const cos = Math.cos; - const sin = Math.sin; - - const c2 = cos( b / 2 ); - const s2 = sin( b / 2 ); - - const c13 = cos( ( a + c ) / 2 ); - const s13 = sin( ( a + c ) / 2 ); - - const c1_3 = cos( ( a - c ) / 2 ); - const s1_3 = sin( ( a - c ) / 2 ); - - const c3_1 = cos( ( c - a ) / 2 ); - const s3_1 = sin( ( c - a ) / 2 ); - - switch ( order ) { - - case 'XYX': - q.set( c2 * s13, s2 * c1_3, s2 * s1_3, c2 * c13 ); - break; - - case 'YZY': - q.set( s2 * s1_3, c2 * s13, s2 * c1_3, c2 * c13 ); - break; - - case 'ZXZ': - q.set( s2 * c1_3, s2 * s1_3, c2 * s13, c2 * c13 ); - break; - - case 'XZX': - q.set( c2 * s13, s2 * s3_1, s2 * c3_1, c2 * c13 ); - break; - - case 'YXY': - q.set( s2 * c3_1, c2 * s13, s2 * s3_1, c2 * c13 ); - break; - - case 'ZYZ': - q.set( s2 * s3_1, s2 * c3_1, c2 * s13, c2 * c13 ); - break; - - default: - console.warn( 'THREE.MathUtils: .setQuaternionFromProperEuler() encountered an unknown order: ' + order ); - - } - -} - -function denormalize( value, array ) { - - switch ( array.constructor ) { - - case Float32Array: - - return value; - - case Uint32Array: - - return value / 4294967295.0; - - case Uint16Array: - - return value / 65535.0; - - case Uint8Array: - - return value / 255.0; - - case Int32Array: - - return Math.max( value / 2147483647.0, - 1.0 ); - - case Int16Array: - - return Math.max( value / 32767.0, - 1.0 ); - - case Int8Array: - - return Math.max( value / 127.0, - 1.0 ); - - default: - - throw new Error( 'Invalid component type.' ); - - } - -} - -function normalize( value, array ) { - - switch ( array.constructor ) { - - case Float32Array: - - return value; - - case Uint32Array: - - return Math.round( value * 4294967295.0 ); - - case Uint16Array: - - return Math.round( value * 65535.0 ); - - case Uint8Array: - - return Math.round( value * 255.0 ); - - case Int32Array: - - return Math.round( value * 2147483647.0 ); - - case Int16Array: - - return Math.round( value * 32767.0 ); - - case Int8Array: - - return Math.round( value * 127.0 ); - - default: - - throw new Error( 'Invalid component type.' ); - - } - -} - -const MathUtils = { - DEG2RAD: DEG2RAD, - RAD2DEG: RAD2DEG, - generateUUID: generateUUID, - clamp: clamp, - euclideanModulo: euclideanModulo, - mapLinear: mapLinear, - inverseLerp: inverseLerp, - lerp: lerp, - damp: damp, - pingpong: pingpong, - smoothstep: smoothstep, - smootherstep: smootherstep, - randInt: randInt, - randFloat: randFloat, - randFloatSpread: randFloatSpread, - seededRandom: seededRandom, - degToRad: degToRad, - radToDeg: radToDeg, - isPowerOfTwo: isPowerOfTwo, - ceilPowerOfTwo: ceilPowerOfTwo, - floorPowerOfTwo: floorPowerOfTwo, - setQuaternionFromProperEuler: setQuaternionFromProperEuler, - normalize: normalize, - denormalize: denormalize -}; - -class Vector2 { - - constructor( x = 0, y = 0 ) { - - Vector2.prototype.isVector2 = true; - - this.x = x; - this.y = y; - - } - - get width() { - - return this.x; - - } - - set width( value ) { - - this.x = value; - - } - - get height() { - - return this.y; - - } - - set height( value ) { - - this.y = value; - - } - - set( x, y ) { - - this.x = x; - this.y = y; - - return this; - - } - - setScalar( scalar ) { - - this.x = scalar; - this.y = scalar; - - return this; - - } - - setX( x ) { - - this.x = x; - - return this; - - } - - setY( y ) { - - this.y = y; - - return this; - - } - - setComponent( index, value ) { - - switch ( index ) { - - case 0: this.x = value; break; - case 1: this.y = value; break; - default: throw new Error( 'index is out of range: ' + index ); - - } - - return this; - - } - - getComponent( index ) { - - switch ( index ) { - - case 0: return this.x; - case 1: return this.y; - default: throw new Error( 'index is out of range: ' + index ); - - } - - } - - clone() { - - return new this.constructor( this.x, this.y ); - - } - - copy( v ) { - - this.x = v.x; - this.y = v.y; - - return this; - - } - - add( v ) { - - this.x += v.x; - this.y += v.y; - - return this; - - } - - addScalar( s ) { - - this.x += s; - this.y += s; - - return this; - - } - - addVectors( a, b ) { - - this.x = a.x + b.x; - this.y = a.y + b.y; - - return this; - - } - - addScaledVector( v, s ) { - - this.x += v.x * s; - this.y += v.y * s; - - return this; - - } - - sub( v ) { - - this.x -= v.x; - this.y -= v.y; - - return this; - - } - - subScalar( s ) { - - this.x -= s; - this.y -= s; - - return this; - - } - - subVectors( a, b ) { - - this.x = a.x - b.x; - this.y = a.y - b.y; - - return this; - - } - - multiply( v ) { - - this.x *= v.x; - this.y *= v.y; - - return this; - - } - - multiplyScalar( scalar ) { - - this.x *= scalar; - this.y *= scalar; - - return this; - - } - - divide( v ) { - - this.x /= v.x; - this.y /= v.y; - - return this; - - } - - divideScalar( scalar ) { - - return this.multiplyScalar( 1 / scalar ); - - } - - applyMatrix3( m ) { - - const x = this.x, y = this.y; - const e = m.elements; - - this.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ]; - this.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ]; - - return this; - - } - - min( v ) { - - this.x = Math.min( this.x, v.x ); - this.y = Math.min( this.y, v.y ); - - return this; - - } - - max( v ) { - - this.x = Math.max( this.x, v.x ); - this.y = Math.max( this.y, v.y ); - - return this; - - } - - clamp( min, max ) { - - // assumes min < max, componentwise - - this.x = Math.max( min.x, Math.min( max.x, this.x ) ); - this.y = Math.max( min.y, Math.min( max.y, this.y ) ); - - return this; - - } - - clampScalar( minVal, maxVal ) { - - this.x = Math.max( minVal, Math.min( maxVal, this.x ) ); - this.y = Math.max( minVal, Math.min( maxVal, this.y ) ); - - return this; - - } - - clampLength( min, max ) { - - const length = this.length(); - - return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) ); - - } - - floor() { - - this.x = Math.floor( this.x ); - this.y = Math.floor( this.y ); - - return this; - - } - - ceil() { - - this.x = Math.ceil( this.x ); - this.y = Math.ceil( this.y ); - - return this; - - } - - round() { - - this.x = Math.round( this.x ); - this.y = Math.round( this.y ); - - return this; - - } - - roundToZero() { - - this.x = Math.trunc( this.x ); - this.y = Math.trunc( this.y ); - - return this; - - } - - negate() { - - this.x = - this.x; - this.y = - this.y; - - return this; - - } - - dot( v ) { - - return this.x * v.x + this.y * v.y; - - } - - cross( v ) { - - return this.x * v.y - this.y * v.x; - - } - - lengthSq() { - - return this.x * this.x + this.y * this.y; - - } - - length() { - - return Math.sqrt( this.x * this.x + this.y * this.y ); - - } - - manhattanLength() { - - return Math.abs( this.x ) + Math.abs( this.y ); - - } - - normalize() { - - return this.divideScalar( this.length() || 1 ); - - } - - angle() { - - // computes the angle in radians with respect to the positive x-axis - - const angle = Math.atan2( - this.y, - this.x ) + Math.PI; - - return angle; - - } - - angleTo( v ) { - - const denominator = Math.sqrt( this.lengthSq() * v.lengthSq() ); - - if ( denominator === 0 ) return Math.PI / 2; - - const theta = this.dot( v ) / denominator; - - // clamp, to handle numerical problems - - return Math.acos( clamp( theta, - 1, 1 ) ); - - } - - distanceTo( v ) { - - return Math.sqrt( this.distanceToSquared( v ) ); - - } - - distanceToSquared( v ) { - - const dx = this.x - v.x, dy = this.y - v.y; - return dx * dx + dy * dy; - - } - - manhattanDistanceTo( v ) { - - return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y ); - - } - - setLength( length ) { - - return this.normalize().multiplyScalar( length ); - - } - - lerp( v, alpha ) { - - this.x += ( v.x - this.x ) * alpha; - this.y += ( v.y - this.y ) * alpha; - - return this; - - } - - lerpVectors( v1, v2, alpha ) { - - this.x = v1.x + ( v2.x - v1.x ) * alpha; - this.y = v1.y + ( v2.y - v1.y ) * alpha; - - return this; - - } - - equals( v ) { - - return ( ( v.x === this.x ) && ( v.y === this.y ) ); - - } - - fromArray( array, offset = 0 ) { - - this.x = array[ offset ]; - this.y = array[ offset + 1 ]; - - return this; - - } - - toArray( array = [], offset = 0 ) { - - array[ offset ] = this.x; - array[ offset + 1 ] = this.y; - - return array; - - } - - fromBufferAttribute( attribute, index ) { - - this.x = attribute.getX( index ); - this.y = attribute.getY( index ); - - return this; - - } - - rotateAround( center, angle ) { - - const c = Math.cos( angle ), s = Math.sin( angle ); - - const x = this.x - center.x; - const y = this.y - center.y; - - this.x = x * c - y * s + center.x; - this.y = x * s + y * c + center.y; - - return this; - - } - - random() { - - this.x = Math.random(); - this.y = Math.random(); - - return this; - - } - - *[ Symbol.iterator ]() { - - yield this.x; - yield this.y; - - } - -} - -class Matrix3 { - - constructor( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) { - - Matrix3.prototype.isMatrix3 = true; - - this.elements = [ - - 1, 0, 0, - 0, 1, 0, - 0, 0, 1 - - ]; - - if ( n11 !== undefined ) { - - this.set( n11, n12, n13, n21, n22, n23, n31, n32, n33 ); - - } - - } - - set( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) { - - const te = this.elements; - - te[ 0 ] = n11; te[ 1 ] = n21; te[ 2 ] = n31; - te[ 3 ] = n12; te[ 4 ] = n22; te[ 5 ] = n32; - te[ 6 ] = n13; te[ 7 ] = n23; te[ 8 ] = n33; - - return this; - - } - - identity() { - - this.set( - - 1, 0, 0, - 0, 1, 0, - 0, 0, 1 - - ); - - return this; - - } - - copy( m ) { - - const te = this.elements; - const me = m.elements; - - te[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ]; - te[ 3 ] = me[ 3 ]; te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ]; - te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ]; te[ 8 ] = me[ 8 ]; - - return this; - - } - - extractBasis( xAxis, yAxis, zAxis ) { - - xAxis.setFromMatrix3Column( this, 0 ); - yAxis.setFromMatrix3Column( this, 1 ); - zAxis.setFromMatrix3Column( this, 2 ); - - return this; - - } - - setFromMatrix4( m ) { - - const me = m.elements; - - this.set( - - me[ 0 ], me[ 4 ], me[ 8 ], - me[ 1 ], me[ 5 ], me[ 9 ], - me[ 2 ], me[ 6 ], me[ 10 ] - - ); - - return this; - - } - - multiply( m ) { - - return this.multiplyMatrices( this, m ); - - } - - premultiply( m ) { - - return this.multiplyMatrices( m, this ); - - } - - multiplyMatrices( a, b ) { - - const ae = a.elements; - const be = b.elements; - const te = this.elements; - - const a11 = ae[ 0 ], a12 = ae[ 3 ], a13 = ae[ 6 ]; - const a21 = ae[ 1 ], a22 = ae[ 4 ], a23 = ae[ 7 ]; - const a31 = ae[ 2 ], a32 = ae[ 5 ], a33 = ae[ 8 ]; - - const b11 = be[ 0 ], b12 = be[ 3 ], b13 = be[ 6 ]; - const b21 = be[ 1 ], b22 = be[ 4 ], b23 = be[ 7 ]; - const b31 = be[ 2 ], b32 = be[ 5 ], b33 = be[ 8 ]; - - te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31; - te[ 3 ] = a11 * b12 + a12 * b22 + a13 * b32; - te[ 6 ] = a11 * b13 + a12 * b23 + a13 * b33; - - te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31; - te[ 4 ] = a21 * b12 + a22 * b22 + a23 * b32; - te[ 7 ] = a21 * b13 + a22 * b23 + a23 * b33; - - te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31; - te[ 5 ] = a31 * b12 + a32 * b22 + a33 * b32; - te[ 8 ] = a31 * b13 + a32 * b23 + a33 * b33; - - return this; - - } - - multiplyScalar( s ) { - - const te = this.elements; - - te[ 0 ] *= s; te[ 3 ] *= s; te[ 6 ] *= s; - te[ 1 ] *= s; te[ 4 ] *= s; te[ 7 ] *= s; - te[ 2 ] *= s; te[ 5 ] *= s; te[ 8 ] *= s; - - return this; - - } - - determinant() { - - const te = this.elements; - - const a = te[ 0 ], b = te[ 1 ], c = te[ 2 ], - d = te[ 3 ], e = te[ 4 ], f = te[ 5 ], - g = te[ 6 ], h = te[ 7 ], i = te[ 8 ]; - - return a * e * i - a * f * h - b * d * i + b * f * g + c * d * h - c * e * g; - - } - - invert() { - - const te = this.elements, - - n11 = te[ 0 ], n21 = te[ 1 ], n31 = te[ 2 ], - n12 = te[ 3 ], n22 = te[ 4 ], n32 = te[ 5 ], - n13 = te[ 6 ], n23 = te[ 7 ], n33 = te[ 8 ], - - t11 = n33 * n22 - n32 * n23, - t12 = n32 * n13 - n33 * n12, - t13 = n23 * n12 - n22 * n13, - - det = n11 * t11 + n21 * t12 + n31 * t13; - - if ( det === 0 ) return this.set( 0, 0, 0, 0, 0, 0, 0, 0, 0 ); - - const detInv = 1 / det; - - te[ 0 ] = t11 * detInv; - te[ 1 ] = ( n31 * n23 - n33 * n21 ) * detInv; - te[ 2 ] = ( n32 * n21 - n31 * n22 ) * detInv; - - te[ 3 ] = t12 * detInv; - te[ 4 ] = ( n33 * n11 - n31 * n13 ) * detInv; - te[ 5 ] = ( n31 * n12 - n32 * n11 ) * detInv; - - te[ 6 ] = t13 * detInv; - te[ 7 ] = ( n21 * n13 - n23 * n11 ) * detInv; - te[ 8 ] = ( n22 * n11 - n21 * n12 ) * detInv; - - return this; - - } - - transpose() { - - let tmp; - const m = this.elements; - - tmp = m[ 1 ]; m[ 1 ] = m[ 3 ]; m[ 3 ] = tmp; - tmp = m[ 2 ]; m[ 2 ] = m[ 6 ]; m[ 6 ] = tmp; - tmp = m[ 5 ]; m[ 5 ] = m[ 7 ]; m[ 7 ] = tmp; - - return this; - - } - - getNormalMatrix( matrix4 ) { - - return this.setFromMatrix4( matrix4 ).invert().transpose(); - - } - - transposeIntoArray( r ) { - - const m = this.elements; - - r[ 0 ] = m[ 0 ]; - r[ 1 ] = m[ 3 ]; - r[ 2 ] = m[ 6 ]; - r[ 3 ] = m[ 1 ]; - r[ 4 ] = m[ 4 ]; - r[ 5 ] = m[ 7 ]; - r[ 6 ] = m[ 2 ]; - r[ 7 ] = m[ 5 ]; - r[ 8 ] = m[ 8 ]; - - return this; - - } - - setUvTransform( tx, ty, sx, sy, rotation, cx, cy ) { - - const c = Math.cos( rotation ); - const s = Math.sin( rotation ); - - this.set( - sx * c, sx * s, - sx * ( c * cx + s * cy ) + cx + tx, - - sy * s, sy * c, - sy * ( - s * cx + c * cy ) + cy + ty, - 0, 0, 1 - ); - - return this; - - } - - // - - scale( sx, sy ) { - - this.premultiply( _m3.makeScale( sx, sy ) ); - - return this; - - } - - rotate( theta ) { - - this.premultiply( _m3.makeRotation( - theta ) ); - - return this; - - } - - translate( tx, ty ) { - - this.premultiply( _m3.makeTranslation( tx, ty ) ); - - return this; - - } - - // for 2D Transforms - - makeTranslation( x, y ) { - - if ( x.isVector2 ) { - - this.set( - - 1, 0, x.x, - 0, 1, x.y, - 0, 0, 1 - - ); - - } else { - - this.set( - - 1, 0, x, - 0, 1, y, - 0, 0, 1 - - ); - - } - - return this; - - } - - makeRotation( theta ) { - - // counterclockwise - - const c = Math.cos( theta ); - const s = Math.sin( theta ); - - this.set( - - c, - s, 0, - s, c, 0, - 0, 0, 1 - - ); - - return this; - - } - - makeScale( x, y ) { - - this.set( - - x, 0, 0, - 0, y, 0, - 0, 0, 1 - - ); - - return this; - - } - - // - - equals( matrix ) { - - const te = this.elements; - const me = matrix.elements; - - for ( let i = 0; i < 9; i ++ ) { - - if ( te[ i ] !== me[ i ] ) return false; - - } - - return true; - - } - - fromArray( array, offset = 0 ) { - - for ( let i = 0; i < 9; i ++ ) { - - this.elements[ i ] = array[ i + offset ]; - - } - - return this; - - } - - toArray( array = [], offset = 0 ) { - - const te = this.elements; - - array[ offset ] = te[ 0 ]; - array[ offset + 1 ] = te[ 1 ]; - array[ offset + 2 ] = te[ 2 ]; - - array[ offset + 3 ] = te[ 3 ]; - array[ offset + 4 ] = te[ 4 ]; - array[ offset + 5 ] = te[ 5 ]; - - array[ offset + 6 ] = te[ 6 ]; - array[ offset + 7 ] = te[ 7 ]; - array[ offset + 8 ] = te[ 8 ]; - - return array; - - } - - clone() { - - return new this.constructor().fromArray( this.elements ); - - } - -} - -const _m3 = /*@__PURE__*/ new Matrix3(); - -function arrayNeedsUint32( array ) { - - // assumes larger values usually on last - - for ( let i = array.length - 1; i >= 0; -- i ) { - - if ( array[ i ] >= 65535 ) return true; // account for PRIMITIVE_RESTART_FIXED_INDEX, #24565 - - } - - return false; - -} - -const TYPED_ARRAYS = { - Int8Array: Int8Array, - Uint8Array: Uint8Array, - Uint8ClampedArray: Uint8ClampedArray, - Int16Array: Int16Array, - Uint16Array: Uint16Array, - Int32Array: Int32Array, - Uint32Array: Uint32Array, - Float32Array: Float32Array, - Float64Array: Float64Array -}; - -function getTypedArray( type, buffer ) { - - return new TYPED_ARRAYS[ type ]( buffer ); - -} - -function createElementNS( name ) { - - return document.createElementNS( 'http://www.w3.org/1999/xhtml', name ); - -} - -function createCanvasElement() { - - const canvas = createElementNS( 'canvas' ); - canvas.style.display = 'block'; - return canvas; - -} - -const _cache = {}; - -function warnOnce( message ) { - - if ( message in _cache ) return; - - _cache[ message ] = true; - - console.warn( message ); - -} - -/** - * Matrices converting P3 <-> Rec. 709 primaries, without gamut mapping - * or clipping. Based on W3C specifications for sRGB and Display P3, - * and ICC specifications for the D50 connection space. Values in/out - * are _linear_ sRGB and _linear_ Display P3. - * - * Note that both sRGB and Display P3 use the sRGB transfer functions. - * - * Reference: - * - http://www.russellcottrell.com/photo/matrixCalculator.htm - */ - -const LINEAR_SRGB_TO_LINEAR_DISPLAY_P3 = /*@__PURE__*/ new Matrix3().set( - 0.8224621, 0.177538, 0.0, - 0.0331941, 0.9668058, 0.0, - 0.0170827, 0.0723974, 0.9105199, -); - -const LINEAR_DISPLAY_P3_TO_LINEAR_SRGB = /*@__PURE__*/ new Matrix3().set( - 1.2249401, - 0.2249404, 0.0, - - 0.0420569, 1.0420571, 0.0, - - 0.0196376, - 0.0786361, 1.0982735 -); - -/** - * Defines supported color spaces by transfer function and primaries, - * and provides conversions to/from the Linear-sRGB reference space. - */ -const COLOR_SPACES = { - [ LinearSRGBColorSpace ]: { - transfer: LinearTransfer, - primaries: Rec709Primaries, - toReference: ( color ) => color, - fromReference: ( color ) => color, - }, - [ SRGBColorSpace ]: { - transfer: SRGBTransfer, - primaries: Rec709Primaries, - toReference: ( color ) => color.convertSRGBToLinear(), - fromReference: ( color ) => color.convertLinearToSRGB(), - }, - [ LinearDisplayP3ColorSpace ]: { - transfer: LinearTransfer, - primaries: P3Primaries, - toReference: ( color ) => color.applyMatrix3( LINEAR_DISPLAY_P3_TO_LINEAR_SRGB ), - fromReference: ( color ) => color.applyMatrix3( LINEAR_SRGB_TO_LINEAR_DISPLAY_P3 ), - }, - [ DisplayP3ColorSpace ]: { - transfer: SRGBTransfer, - primaries: P3Primaries, - toReference: ( color ) => color.convertSRGBToLinear().applyMatrix3( LINEAR_DISPLAY_P3_TO_LINEAR_SRGB ), - fromReference: ( color ) => color.applyMatrix3( LINEAR_SRGB_TO_LINEAR_DISPLAY_P3 ).convertLinearToSRGB(), - }, -}; - -const SUPPORTED_WORKING_COLOR_SPACES = new Set( [ LinearSRGBColorSpace, LinearDisplayP3ColorSpace ] ); - -const ColorManagement = { - - enabled: true, - - _workingColorSpace: LinearSRGBColorSpace, - - get workingColorSpace() { - - return this._workingColorSpace; - - }, - - set workingColorSpace( colorSpace ) { - - if ( ! SUPPORTED_WORKING_COLOR_SPACES.has( colorSpace ) ) { - - throw new Error( `Unsupported working color space, "${ colorSpace }".` ); - - } - - this._workingColorSpace = colorSpace; - - }, - - convert: function ( color, sourceColorSpace, targetColorSpace ) { - - if ( this.enabled === false || sourceColorSpace === targetColorSpace || ! sourceColorSpace || ! targetColorSpace ) { - - return color; - - } - - const sourceToReference = COLOR_SPACES[ sourceColorSpace ].toReference; - const targetFromReference = COLOR_SPACES[ targetColorSpace ].fromReference; - - return targetFromReference( sourceToReference( color ) ); - - }, - - fromWorkingColorSpace: function ( color, targetColorSpace ) { - - return this.convert( color, this._workingColorSpace, targetColorSpace ); - - }, - - toWorkingColorSpace: function ( color, sourceColorSpace ) { - - return this.convert( color, sourceColorSpace, this._workingColorSpace ); - - }, - - getPrimaries: function ( colorSpace ) { - - return COLOR_SPACES[ colorSpace ].primaries; - - }, - - getTransfer: function ( colorSpace ) { - - if ( colorSpace === NoColorSpace ) return LinearTransfer; - - return COLOR_SPACES[ colorSpace ].transfer; - - }, - -}; - - -function SRGBToLinear( c ) { - - return ( c < 0.04045 ) ? c * 0.0773993808 : Math.pow( c * 0.9478672986 + 0.0521327014, 2.4 ); - -} - -function LinearToSRGB( c ) { - - return ( c < 0.0031308 ) ? c * 12.92 : 1.055 * ( Math.pow( c, 0.41666 ) ) - 0.055; - -} - -let _canvas; - -class ImageUtils { - - static getDataURL( image ) { - - if ( /^data:/i.test( image.src ) ) { - - return image.src; - - } - - if ( typeof HTMLCanvasElement === 'undefined' ) { - - return image.src; - - } - - let canvas; - - if ( image instanceof HTMLCanvasElement ) { - - canvas = image; - - } else { - - if ( _canvas === undefined ) _canvas = createElementNS( 'canvas' ); - - _canvas.width = image.width; - _canvas.height = image.height; - - const context = _canvas.getContext( '2d' ); - - if ( image instanceof ImageData ) { - - context.putImageData( image, 0, 0 ); - - } else { - - context.drawImage( image, 0, 0, image.width, image.height ); - - } - - canvas = _canvas; - - } - - if ( canvas.width > 2048 || canvas.height > 2048 ) { - - console.warn( 'THREE.ImageUtils.getDataURL: Image converted to jpg for performance reasons', image ); - - return canvas.toDataURL( 'image/jpeg', 0.6 ); - - } else { - - return canvas.toDataURL( 'image/png' ); - - } - - } - - static sRGBToLinear( image ) { - - if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) || - ( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) || - ( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) { - - const canvas = createElementNS( 'canvas' ); - - canvas.width = image.width; - canvas.height = image.height; - - const context = canvas.getContext( '2d' ); - context.drawImage( image, 0, 0, image.width, image.height ); - - const imageData = context.getImageData( 0, 0, image.width, image.height ); - const data = imageData.data; - - for ( let i = 0; i < data.length; i ++ ) { - - data[ i ] = SRGBToLinear( data[ i ] / 255 ) * 255; - - } - - context.putImageData( imageData, 0, 0 ); - - return canvas; - - } else if ( image.data ) { - - const data = image.data.slice( 0 ); - - for ( let i = 0; i < data.length; i ++ ) { - - if ( data instanceof Uint8Array || data instanceof Uint8ClampedArray ) { - - data[ i ] = Math.floor( SRGBToLinear( data[ i ] / 255 ) * 255 ); - - } else { - - // assuming float - - data[ i ] = SRGBToLinear( data[ i ] ); - - } - - } - - return { - data: data, - width: image.width, - height: image.height - }; - - } else { - - console.warn( 'THREE.ImageUtils.sRGBToLinear(): Unsupported image type. No color space conversion applied.' ); - return image; - - } - - } - -} - -let _sourceId = 0; - -class Source { - - constructor( data = null ) { - - this.isSource = true; - - Object.defineProperty( this, 'id', { value: _sourceId ++ } ); - - this.uuid = generateUUID(); - - this.data = data; - this.dataReady = true; - - this.version = 0; - - } - - set needsUpdate( value ) { - - if ( value === true ) this.version ++; - - } - - toJSON( meta ) { - - const isRootObject = ( meta === undefined || typeof meta === 'string' ); - - if ( ! isRootObject && meta.images[ this.uuid ] !== undefined ) { - - return meta.images[ this.uuid ]; - - } - - const output = { - uuid: this.uuid, - url: '' - }; - - const data = this.data; - - if ( data !== null ) { - - let url; - - if ( Array.isArray( data ) ) { - - // cube texture - - url = []; - - for ( let i = 0, l = data.length; i < l; i ++ ) { - - if ( data[ i ].isDataTexture ) { - - url.push( serializeImage( data[ i ].image ) ); - - } else { - - url.push( serializeImage( data[ i ] ) ); - - } - - } - - } else { - - // texture - - url = serializeImage( data ); - - } - - output.url = url; - - } - - if ( ! isRootObject ) { - - meta.images[ this.uuid ] = output; - - } - - return output; - - } - -} - -function serializeImage( image ) { - - if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) || - ( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) || - ( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) { - - // default images - - return ImageUtils.getDataURL( image ); - - } else { - - if ( image.data ) { - - // images of DataTexture - - return { - data: Array.from( image.data ), - width: image.width, - height: image.height, - type: image.data.constructor.name - }; - - } else { - - console.warn( 'THREE.Texture: Unable to serialize Texture.' ); - return {}; - - } - - } - -} - -let _textureId = 0; - -class Texture extends EventDispatcher { - - constructor( image = Texture.DEFAULT_IMAGE, mapping = Texture.DEFAULT_MAPPING, wrapS = ClampToEdgeWrapping, wrapT = ClampToEdgeWrapping, magFilter = LinearFilter, minFilter = LinearMipmapLinearFilter, format = RGBAFormat, type = UnsignedByteType, anisotropy = Texture.DEFAULT_ANISOTROPY, colorSpace = NoColorSpace ) { - - super(); - - this.isTexture = true; - - Object.defineProperty( this, 'id', { value: _textureId ++ } ); - - this.uuid = generateUUID(); - - this.name = ''; - - this.source = new Source( image ); - this.mipmaps = []; - - this.mapping = mapping; - this.channel = 0; - - this.wrapS = wrapS; - this.wrapT = wrapT; - - this.magFilter = magFilter; - this.minFilter = minFilter; - - this.anisotropy = anisotropy; - - this.format = format; - this.internalFormat = null; - this.type = type; - - this.offset = new Vector2( 0, 0 ); - this.repeat = new Vector2( 1, 1 ); - this.center = new Vector2( 0, 0 ); - this.rotation = 0; - - this.matrixAutoUpdate = true; - this.matrix = new Matrix3(); - - this.generateMipmaps = true; - this.premultiplyAlpha = false; - this.flipY = true; - this.unpackAlignment = 4; // valid values: 1, 2, 4, 8 (see http://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml) - - this.colorSpace = colorSpace; - - this.userData = {}; - - this.version = 0; - this.onUpdate = null; - - this.isRenderTargetTexture = false; // indicates whether a texture belongs to a render target or not - this.needsPMREMUpdate = false; // indicates whether this texture should be processed by PMREMGenerator or not (only relevant for render target textures) - - } - - get image() { - - return this.source.data; - - } - - set image( value = null ) { - - this.source.data = value; - - } - - updateMatrix() { - - this.matrix.setUvTransform( this.offset.x, this.offset.y, this.repeat.x, this.repeat.y, this.rotation, this.center.x, this.center.y ); - - } - - clone() { - - return new this.constructor().copy( this ); - - } - - copy( source ) { - - this.name = source.name; - - this.source = source.source; - this.mipmaps = source.mipmaps.slice( 0 ); - - this.mapping = source.mapping; - this.channel = source.channel; - - this.wrapS = source.wrapS; - this.wrapT = source.wrapT; - - this.magFilter = source.magFilter; - this.minFilter = source.minFilter; - - this.anisotropy = source.anisotropy; - - this.format = source.format; - this.internalFormat = source.internalFormat; - this.type = source.type; - - this.offset.copy( source.offset ); - this.repeat.copy( source.repeat ); - this.center.copy( source.center ); - this.rotation = source.rotation; - - this.matrixAutoUpdate = source.matrixAutoUpdate; - this.matrix.copy( source.matrix ); - - this.generateMipmaps = source.generateMipmaps; - this.premultiplyAlpha = source.premultiplyAlpha; - this.flipY = source.flipY; - this.unpackAlignment = source.unpackAlignment; - this.colorSpace = source.colorSpace; - - this.userData = JSON.parse( JSON.stringify( source.userData ) ); - - this.needsUpdate = true; - - return this; - - } - - toJSON( meta ) { - - const isRootObject = ( meta === undefined || typeof meta === 'string' ); - - if ( ! isRootObject && meta.textures[ this.uuid ] !== undefined ) { - - return meta.textures[ this.uuid ]; - - } - - const output = { - - metadata: { - version: 4.6, - type: 'Texture', - generator: 'Texture.toJSON' - }, - - uuid: this.uuid, - name: this.name, - - image: this.source.toJSON( meta ).uuid, - - mapping: this.mapping, - channel: this.channel, - - repeat: [ this.repeat.x, this.repeat.y ], - offset: [ this.offset.x, this.offset.y ], - center: [ this.center.x, this.center.y ], - rotation: this.rotation, - - wrap: [ this.wrapS, this.wrapT ], - - format: this.format, - internalFormat: this.internalFormat, - type: this.type, - colorSpace: this.colorSpace, - - minFilter: this.minFilter, - magFilter: this.magFilter, - anisotropy: this.anisotropy, - - flipY: this.flipY, - - generateMipmaps: this.generateMipmaps, - premultiplyAlpha: this.premultiplyAlpha, - unpackAlignment: this.unpackAlignment - - }; - - if ( Object.keys( this.userData ).length > 0 ) output.userData = this.userData; - - if ( ! isRootObject ) { - - meta.textures[ this.uuid ] = output; - - } - - return output; - - } - - dispose() { - - this.dispatchEvent( { type: 'dispose' } ); - - } - - transformUv( uv ) { - - if ( this.mapping !== UVMapping ) return uv; - - uv.applyMatrix3( this.matrix ); - - if ( uv.x < 0 || uv.x > 1 ) { - - switch ( this.wrapS ) { - - case RepeatWrapping: - - uv.x = uv.x - Math.floor( uv.x ); - break; - - case ClampToEdgeWrapping: - - uv.x = uv.x < 0 ? 0 : 1; - break; - - case MirroredRepeatWrapping: - - if ( Math.abs( Math.floor( uv.x ) % 2 ) === 1 ) { - - uv.x = Math.ceil( uv.x ) - uv.x; - - } else { - - uv.x = uv.x - Math.floor( uv.x ); - - } - - break; - - } - - } - - if ( uv.y < 0 || uv.y > 1 ) { - - switch ( this.wrapT ) { - - case RepeatWrapping: - - uv.y = uv.y - Math.floor( uv.y ); - break; - - case ClampToEdgeWrapping: - - uv.y = uv.y < 0 ? 0 : 1; - break; - - case MirroredRepeatWrapping: - - if ( Math.abs( Math.floor( uv.y ) % 2 ) === 1 ) { - - uv.y = Math.ceil( uv.y ) - uv.y; - - } else { - - uv.y = uv.y - Math.floor( uv.y ); - - } - - break; - - } - - } - - if ( this.flipY ) { - - uv.y = 1 - uv.y; - - } - - return uv; - - } - - set needsUpdate( value ) { - - if ( value === true ) { - - this.version ++; - this.source.needsUpdate = true; - - } - - } - -} - -Texture.DEFAULT_IMAGE = null; -Texture.DEFAULT_MAPPING = UVMapping; -Texture.DEFAULT_ANISOTROPY = 1; - -class Vector4 { - - constructor( x = 0, y = 0, z = 0, w = 1 ) { - - Vector4.prototype.isVector4 = true; - - this.x = x; - this.y = y; - this.z = z; - this.w = w; - - } - - get width() { - - return this.z; - - } - - set width( value ) { - - this.z = value; - - } - - get height() { - - return this.w; - - } - - set height( value ) { - - this.w = value; - - } - - set( x, y, z, w ) { - - this.x = x; - this.y = y; - this.z = z; - this.w = w; - - return this; - - } - - setScalar( scalar ) { - - this.x = scalar; - this.y = scalar; - this.z = scalar; - this.w = scalar; - - return this; - - } - - setX( x ) { - - this.x = x; - - return this; - - } - - setY( y ) { - - this.y = y; - - return this; - - } - - setZ( z ) { - - this.z = z; - - return this; - - } - - setW( w ) { - - this.w = w; - - return this; - - } - - setComponent( index, value ) { - - switch ( index ) { - - case 0: this.x = value; break; - case 1: this.y = value; break; - case 2: this.z = value; break; - case 3: this.w = value; break; - default: throw new Error( 'index is out of range: ' + index ); - - } - - return this; - - } - - getComponent( index ) { - - switch ( index ) { - - case 0: return this.x; - case 1: return this.y; - case 2: return this.z; - case 3: return this.w; - default: throw new Error( 'index is out of range: ' + index ); - - } - - } - - clone() { - - return new this.constructor( this.x, this.y, this.z, this.w ); - - } - - copy( v ) { - - this.x = v.x; - this.y = v.y; - this.z = v.z; - this.w = ( v.w !== undefined ) ? v.w : 1; - - return this; - - } - - add( v ) { - - this.x += v.x; - this.y += v.y; - this.z += v.z; - this.w += v.w; - - return this; - - } - - addScalar( s ) { - - this.x += s; - this.y += s; - this.z += s; - this.w += s; - - return this; - - } - - addVectors( a, b ) { - - this.x = a.x + b.x; - this.y = a.y + b.y; - this.z = a.z + b.z; - this.w = a.w + b.w; - - return this; - - } - - addScaledVector( v, s ) { - - this.x += v.x * s; - this.y += v.y * s; - this.z += v.z * s; - this.w += v.w * s; - - return this; - - } - - sub( v ) { - - this.x -= v.x; - this.y -= v.y; - this.z -= v.z; - this.w -= v.w; - - return this; - - } - - subScalar( s ) { - - this.x -= s; - this.y -= s; - this.z -= s; - this.w -= s; - - return this; - - } - - subVectors( a, b ) { - - this.x = a.x - b.x; - this.y = a.y - b.y; - this.z = a.z - b.z; - this.w = a.w - b.w; - - return this; - - } - - multiply( v ) { - - this.x *= v.x; - this.y *= v.y; - this.z *= v.z; - this.w *= v.w; - - return this; - - } - - multiplyScalar( scalar ) { - - this.x *= scalar; - this.y *= scalar; - this.z *= scalar; - this.w *= scalar; - - return this; - - } - - applyMatrix4( m ) { - - const x = this.x, y = this.y, z = this.z, w = this.w; - const e = m.elements; - - this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] * w; - this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] * w; - this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] * w; - this.w = e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] * w; - - return this; - - } - - divideScalar( scalar ) { - - return this.multiplyScalar( 1 / scalar ); - - } - - setAxisAngleFromQuaternion( q ) { - - // http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm - - // q is assumed to be normalized - - this.w = 2 * Math.acos( q.w ); - - const s = Math.sqrt( 1 - q.w * q.w ); - - if ( s < 0.0001 ) { - - this.x = 1; - this.y = 0; - this.z = 0; - - } else { - - this.x = q.x / s; - this.y = q.y / s; - this.z = q.z / s; - - } - - return this; - - } - - setAxisAngleFromRotationMatrix( m ) { - - // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm - - // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) - - let angle, x, y, z; // variables for result - const epsilon = 0.01, // margin to allow for rounding errors - epsilon2 = 0.1, // margin to distinguish between 0 and 180 degrees - - te = m.elements, - - m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ], - m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ], - m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ]; - - if ( ( Math.abs( m12 - m21 ) < epsilon ) && - ( Math.abs( m13 - m31 ) < epsilon ) && - ( Math.abs( m23 - m32 ) < epsilon ) ) { - - // singularity found - // first check for identity matrix which must have +1 for all terms - // in leading diagonal and zero in other terms - - if ( ( Math.abs( m12 + m21 ) < epsilon2 ) && - ( Math.abs( m13 + m31 ) < epsilon2 ) && - ( Math.abs( m23 + m32 ) < epsilon2 ) && - ( Math.abs( m11 + m22 + m33 - 3 ) < epsilon2 ) ) { - - // this singularity is identity matrix so angle = 0 - - this.set( 1, 0, 0, 0 ); - - return this; // zero angle, arbitrary axis - - } - - // otherwise this singularity is angle = 180 - - angle = Math.PI; - - const xx = ( m11 + 1 ) / 2; - const yy = ( m22 + 1 ) / 2; - const zz = ( m33 + 1 ) / 2; - const xy = ( m12 + m21 ) / 4; - const xz = ( m13 + m31 ) / 4; - const yz = ( m23 + m32 ) / 4; - - if ( ( xx > yy ) && ( xx > zz ) ) { - - // m11 is the largest diagonal term - - if ( xx < epsilon ) { - - x = 0; - y = 0.707106781; - z = 0.707106781; - - } else { - - x = Math.sqrt( xx ); - y = xy / x; - z = xz / x; - - } - - } else if ( yy > zz ) { - - // m22 is the largest diagonal term - - if ( yy < epsilon ) { - - x = 0.707106781; - y = 0; - z = 0.707106781; - - } else { - - y = Math.sqrt( yy ); - x = xy / y; - z = yz / y; - - } - - } else { - - // m33 is the largest diagonal term so base result on this - - if ( zz < epsilon ) { - - x = 0.707106781; - y = 0.707106781; - z = 0; - - } else { - - z = Math.sqrt( zz ); - x = xz / z; - y = yz / z; - - } - - } - - this.set( x, y, z, angle ); - - return this; // return 180 deg rotation - - } - - // as we have reached here there are no singularities so we can handle normally - - let s = Math.sqrt( ( m32 - m23 ) * ( m32 - m23 ) + - ( m13 - m31 ) * ( m13 - m31 ) + - ( m21 - m12 ) * ( m21 - m12 ) ); // used to normalize - - if ( Math.abs( s ) < 0.001 ) s = 1; - - // prevent divide by zero, should not happen if matrix is orthogonal and should be - // caught by singularity test above, but I've left it in just in case - - this.x = ( m32 - m23 ) / s; - this.y = ( m13 - m31 ) / s; - this.z = ( m21 - m12 ) / s; - this.w = Math.acos( ( m11 + m22 + m33 - 1 ) / 2 ); - - return this; - - } - - min( v ) { - - this.x = Math.min( this.x, v.x ); - this.y = Math.min( this.y, v.y ); - this.z = Math.min( this.z, v.z ); - this.w = Math.min( this.w, v.w ); - - return this; - - } - - max( v ) { - - this.x = Math.max( this.x, v.x ); - this.y = Math.max( this.y, v.y ); - this.z = Math.max( this.z, v.z ); - this.w = Math.max( this.w, v.w ); - - return this; - - } - - clamp( min, max ) { - - // assumes min < max, componentwise - - this.x = Math.max( min.x, Math.min( max.x, this.x ) ); - this.y = Math.max( min.y, Math.min( max.y, this.y ) ); - this.z = Math.max( min.z, Math.min( max.z, this.z ) ); - this.w = Math.max( min.w, Math.min( max.w, this.w ) ); - - return this; - - } - - clampScalar( minVal, maxVal ) { - - this.x = Math.max( minVal, Math.min( maxVal, this.x ) ); - this.y = Math.max( minVal, Math.min( maxVal, this.y ) ); - this.z = Math.max( minVal, Math.min( maxVal, this.z ) ); - this.w = Math.max( minVal, Math.min( maxVal, this.w ) ); - - return this; - - } - - clampLength( min, max ) { - - const length = this.length(); - - return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) ); - - } - - floor() { - - this.x = Math.floor( this.x ); - this.y = Math.floor( this.y ); - this.z = Math.floor( this.z ); - this.w = Math.floor( this.w ); - - return this; - - } - - ceil() { - - this.x = Math.ceil( this.x ); - this.y = Math.ceil( this.y ); - this.z = Math.ceil( this.z ); - this.w = Math.ceil( this.w ); - - return this; - - } - - round() { - - this.x = Math.round( this.x ); - this.y = Math.round( this.y ); - this.z = Math.round( this.z ); - this.w = Math.round( this.w ); - - return this; - - } - - roundToZero() { - - this.x = Math.trunc( this.x ); - this.y = Math.trunc( this.y ); - this.z = Math.trunc( this.z ); - this.w = Math.trunc( this.w ); - - return this; - - } - - negate() { - - this.x = - this.x; - this.y = - this.y; - this.z = - this.z; - this.w = - this.w; - - return this; - - } - - dot( v ) { - - return this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w; - - } - - lengthSq() { - - return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w; - - } - - length() { - - return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w ); - - } - - manhattanLength() { - - return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ) + Math.abs( this.w ); - - } - - normalize() { - - return this.divideScalar( this.length() || 1 ); - - } - - setLength( length ) { - - return this.normalize().multiplyScalar( length ); - - } - - lerp( v, alpha ) { - - this.x += ( v.x - this.x ) * alpha; - this.y += ( v.y - this.y ) * alpha; - this.z += ( v.z - this.z ) * alpha; - this.w += ( v.w - this.w ) * alpha; - - return this; - - } - - lerpVectors( v1, v2, alpha ) { - - this.x = v1.x + ( v2.x - v1.x ) * alpha; - this.y = v1.y + ( v2.y - v1.y ) * alpha; - this.z = v1.z + ( v2.z - v1.z ) * alpha; - this.w = v1.w + ( v2.w - v1.w ) * alpha; - - return this; - - } - - equals( v ) { - - return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) && ( v.w === this.w ) ); - - } - - fromArray( array, offset = 0 ) { - - this.x = array[ offset ]; - this.y = array[ offset + 1 ]; - this.z = array[ offset + 2 ]; - this.w = array[ offset + 3 ]; - - return this; - - } - - toArray( array = [], offset = 0 ) { - - array[ offset ] = this.x; - array[ offset + 1 ] = this.y; - array[ offset + 2 ] = this.z; - array[ offset + 3 ] = this.w; - - return array; - - } - - fromBufferAttribute( attribute, index ) { - - this.x = attribute.getX( index ); - this.y = attribute.getY( index ); - this.z = attribute.getZ( index ); - this.w = attribute.getW( index ); - - return this; - - } - - random() { - - this.x = Math.random(); - this.y = Math.random(); - this.z = Math.random(); - this.w = Math.random(); - - return this; - - } - - *[ Symbol.iterator ]() { - - yield this.x; - yield this.y; - yield this.z; - yield this.w; - - } - -} - -/* - In options, we can specify: - * Texture parameters for an auto-generated target texture - * depthBuffer/stencilBuffer: Booleans to indicate if we should generate these buffers -*/ -class RenderTarget extends EventDispatcher { - - constructor( width = 1, height = 1, options = {} ) { - - super(); - - this.isRenderTarget = true; - - this.width = width; - this.height = height; - this.depth = 1; - - this.scissor = new Vector4( 0, 0, width, height ); - this.scissorTest = false; - - this.viewport = new Vector4( 0, 0, width, height ); - - const image = { width: width, height: height, depth: 1 }; - - options = Object.assign( { - generateMipmaps: false, - internalFormat: null, - minFilter: LinearFilter, - depthBuffer: true, - stencilBuffer: false, - depthTexture: null, - samples: 0 - }, options ); - - this.texture = new Texture( image, options.mapping, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.colorSpace ); - this.texture.isRenderTargetTexture = true; - - this.texture.flipY = false; - this.texture.generateMipmaps = options.generateMipmaps; - this.texture.internalFormat = options.internalFormat; - - this.depthBuffer = options.depthBuffer; - this.stencilBuffer = options.stencilBuffer; - - this.depthTexture = options.depthTexture; - - this.samples = options.samples; - - } - - setSize( width, height, depth = 1 ) { - - if ( this.width !== width || this.height !== height || this.depth !== depth ) { - - this.width = width; - this.height = height; - this.depth = depth; - - this.texture.image.width = width; - this.texture.image.height = height; - this.texture.image.depth = depth; - - this.dispose(); - - } - - this.viewport.set( 0, 0, width, height ); - this.scissor.set( 0, 0, width, height ); - - } - - clone() { - - return new this.constructor().copy( this ); - - } - - copy( source ) { - - this.width = source.width; - this.height = source.height; - this.depth = source.depth; - - this.scissor.copy( source.scissor ); - this.scissorTest = source.scissorTest; - - this.viewport.copy( source.viewport ); - - this.texture = source.texture.clone(); - this.texture.isRenderTargetTexture = true; - - // ensure image object is not shared, see #20328 - - const image = Object.assign( {}, source.texture.image ); - this.texture.source = new Source( image ); - - this.depthBuffer = source.depthBuffer; - this.stencilBuffer = source.stencilBuffer; - - if ( source.depthTexture !== null ) this.depthTexture = source.depthTexture.clone(); - - this.samples = source.samples; - - return this; - - } - - dispose() { - - this.dispatchEvent( { type: 'dispose' } ); - - } - -} - -class WebGLRenderTarget extends RenderTarget { - - constructor( width = 1, height = 1, options = {} ) { - - super( width, height, options ); - - this.isWebGLRenderTarget = true; - - } - -} - -class DataArrayTexture extends Texture { - - constructor( data = null, width = 1, height = 1, depth = 1 ) { - - super( null ); - - this.isDataArrayTexture = true; - - this.image = { data, width, height, depth }; - - this.magFilter = NearestFilter; - this.minFilter = NearestFilter; - - this.wrapR = ClampToEdgeWrapping; - - this.generateMipmaps = false; - this.flipY = false; - this.unpackAlignment = 1; - - } - -} - -class WebGLArrayRenderTarget extends WebGLRenderTarget { - - constructor( width = 1, height = 1, depth = 1, options = {} ) { - - super( width, height, options ); - - this.isWebGLArrayRenderTarget = true; - - this.depth = depth; - - this.texture = new DataArrayTexture( null, width, height, depth ); - - this.texture.isRenderTargetTexture = true; - - } - -} - -class Data3DTexture extends Texture { - - constructor( data = null, width = 1, height = 1, depth = 1 ) { - - // We're going to add .setXXX() methods for setting properties later. - // Users can still set in DataTexture3D directly. - // - // const texture = new THREE.DataTexture3D( data, width, height, depth ); - // texture.anisotropy = 16; - // - // See #14839 - - super( null ); - - this.isData3DTexture = true; - - this.image = { data, width, height, depth }; - - this.magFilter = NearestFilter; - this.minFilter = NearestFilter; - - this.wrapR = ClampToEdgeWrapping; - - this.generateMipmaps = false; - this.flipY = false; - this.unpackAlignment = 1; - - } - -} - -class WebGL3DRenderTarget extends WebGLRenderTarget { - - constructor( width = 1, height = 1, depth = 1, options = {} ) { - - super( width, height, options ); - - this.isWebGL3DRenderTarget = true; - - this.depth = depth; - - this.texture = new Data3DTexture( null, width, height, depth ); - - this.texture.isRenderTargetTexture = true; - - } - -} - -class WebGLMultipleRenderTargets extends WebGLRenderTarget { - - constructor( width = 1, height = 1, count = 1, options = {} ) { - - super( width, height, options ); - - this.isWebGLMultipleRenderTargets = true; - - const texture = this.texture; - - this.texture = []; - - for ( let i = 0; i < count; i ++ ) { - - this.texture[ i ] = texture.clone(); - this.texture[ i ].isRenderTargetTexture = true; - - } - - } - - setSize( width, height, depth = 1 ) { - - if ( this.width !== width || this.height !== height || this.depth !== depth ) { - - this.width = width; - this.height = height; - this.depth = depth; - - for ( let i = 0, il = this.texture.length; i < il; i ++ ) { - - this.texture[ i ].image.width = width; - this.texture[ i ].image.height = height; - this.texture[ i ].image.depth = depth; - - } - - this.dispose(); - - } - - this.viewport.set( 0, 0, width, height ); - this.scissor.set( 0, 0, width, height ); - - } - - copy( source ) { - - this.dispose(); - - this.width = source.width; - this.height = source.height; - this.depth = source.depth; - - this.scissor.copy( source.scissor ); - this.scissorTest = source.scissorTest; - - this.viewport.copy( source.viewport ); - - this.depthBuffer = source.depthBuffer; - this.stencilBuffer = source.stencilBuffer; - - if ( source.depthTexture !== null ) this.depthTexture = source.depthTexture.clone(); - - this.texture.length = 0; - - for ( let i = 0, il = source.texture.length; i < il; i ++ ) { - - this.texture[ i ] = source.texture[ i ].clone(); - this.texture[ i ].isRenderTargetTexture = true; - - } - - return this; - - } - -} - -class Quaternion { - - constructor( x = 0, y = 0, z = 0, w = 1 ) { - - this.isQuaternion = true; - - this._x = x; - this._y = y; - this._z = z; - this._w = w; - - } - - static slerpFlat( dst, dstOffset, src0, srcOffset0, src1, srcOffset1, t ) { - - // fuzz-free, array-based Quaternion SLERP operation - - let x0 = src0[ srcOffset0 + 0 ], - y0 = src0[ srcOffset0 + 1 ], - z0 = src0[ srcOffset0 + 2 ], - w0 = src0[ srcOffset0 + 3 ]; - - const x1 = src1[ srcOffset1 + 0 ], - y1 = src1[ srcOffset1 + 1 ], - z1 = src1[ srcOffset1 + 2 ], - w1 = src1[ srcOffset1 + 3 ]; - - if ( t === 0 ) { - - dst[ dstOffset + 0 ] = x0; - dst[ dstOffset + 1 ] = y0; - dst[ dstOffset + 2 ] = z0; - dst[ dstOffset + 3 ] = w0; - return; - - } - - if ( t === 1 ) { - - dst[ dstOffset + 0 ] = x1; - dst[ dstOffset + 1 ] = y1; - dst[ dstOffset + 2 ] = z1; - dst[ dstOffset + 3 ] = w1; - return; - - } - - if ( w0 !== w1 || x0 !== x1 || y0 !== y1 || z0 !== z1 ) { - - let s = 1 - t; - const cos = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1, - dir = ( cos >= 0 ? 1 : - 1 ), - sqrSin = 1 - cos * cos; - - // Skip the Slerp for tiny steps to avoid numeric problems: - if ( sqrSin > Number.EPSILON ) { - - const sin = Math.sqrt( sqrSin ), - len = Math.atan2( sin, cos * dir ); - - s = Math.sin( s * len ) / sin; - t = Math.sin( t * len ) / sin; - - } - - const tDir = t * dir; - - x0 = x0 * s + x1 * tDir; - y0 = y0 * s + y1 * tDir; - z0 = z0 * s + z1 * tDir; - w0 = w0 * s + w1 * tDir; - - // Normalize in case we just did a lerp: - if ( s === 1 - t ) { - - const f = 1 / Math.sqrt( x0 * x0 + y0 * y0 + z0 * z0 + w0 * w0 ); - - x0 *= f; - y0 *= f; - z0 *= f; - w0 *= f; - - } - - } - - dst[ dstOffset ] = x0; - dst[ dstOffset + 1 ] = y0; - dst[ dstOffset + 2 ] = z0; - dst[ dstOffset + 3 ] = w0; - - } - - static multiplyQuaternionsFlat( dst, dstOffset, src0, srcOffset0, src1, srcOffset1 ) { - - const x0 = src0[ srcOffset0 ]; - const y0 = src0[ srcOffset0 + 1 ]; - const z0 = src0[ srcOffset0 + 2 ]; - const w0 = src0[ srcOffset0 + 3 ]; - - const x1 = src1[ srcOffset1 ]; - const y1 = src1[ srcOffset1 + 1 ]; - const z1 = src1[ srcOffset1 + 2 ]; - const w1 = src1[ srcOffset1 + 3 ]; - - dst[ dstOffset ] = x0 * w1 + w0 * x1 + y0 * z1 - z0 * y1; - dst[ dstOffset + 1 ] = y0 * w1 + w0 * y1 + z0 * x1 - x0 * z1; - dst[ dstOffset + 2 ] = z0 * w1 + w0 * z1 + x0 * y1 - y0 * x1; - dst[ dstOffset + 3 ] = w0 * w1 - x0 * x1 - y0 * y1 - z0 * z1; - - return dst; - - } - - get x() { - - return this._x; - - } - - set x( value ) { - - this._x = value; - this._onChangeCallback(); - - } - - get y() { - - return this._y; - - } - - set y( value ) { - - this._y = value; - this._onChangeCallback(); - - } - - get z() { - - return this._z; - - } - - set z( value ) { - - this._z = value; - this._onChangeCallback(); - - } - - get w() { - - return this._w; - - } - - set w( value ) { - - this._w = value; - this._onChangeCallback(); - - } - - set( x, y, z, w ) { - - this._x = x; - this._y = y; - this._z = z; - this._w = w; - - this._onChangeCallback(); - - return this; - - } - - clone() { - - return new this.constructor( this._x, this._y, this._z, this._w ); - - } - - copy( quaternion ) { - - this._x = quaternion.x; - this._y = quaternion.y; - this._z = quaternion.z; - this._w = quaternion.w; - - this._onChangeCallback(); - - return this; - - } - - setFromEuler( euler, update = true ) { - - const x = euler._x, y = euler._y, z = euler._z, order = euler._order; - - // http://www.mathworks.com/matlabcentral/fileexchange/ - // 20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/ - // content/SpinCalc.m - - const cos = Math.cos; - const sin = Math.sin; - - const c1 = cos( x / 2 ); - const c2 = cos( y / 2 ); - const c3 = cos( z / 2 ); - - const s1 = sin( x / 2 ); - const s2 = sin( y / 2 ); - const s3 = sin( z / 2 ); - - switch ( order ) { - - case 'XYZ': - this._x = s1 * c2 * c3 + c1 * s2 * s3; - this._y = c1 * s2 * c3 - s1 * c2 * s3; - this._z = c1 * c2 * s3 + s1 * s2 * c3; - this._w = c1 * c2 * c3 - s1 * s2 * s3; - break; - - case 'YXZ': - this._x = s1 * c2 * c3 + c1 * s2 * s3; - this._y = c1 * s2 * c3 - s1 * c2 * s3; - this._z = c1 * c2 * s3 - s1 * s2 * c3; - this._w = c1 * c2 * c3 + s1 * s2 * s3; - break; - - case 'ZXY': - this._x = s1 * c2 * c3 - c1 * s2 * s3; - this._y = c1 * s2 * c3 + s1 * c2 * s3; - this._z = c1 * c2 * s3 + s1 * s2 * c3; - this._w = c1 * c2 * c3 - s1 * s2 * s3; - break; - - case 'ZYX': - this._x = s1 * c2 * c3 - c1 * s2 * s3; - this._y = c1 * s2 * c3 + s1 * c2 * s3; - this._z = c1 * c2 * s3 - s1 * s2 * c3; - this._w = c1 * c2 * c3 + s1 * s2 * s3; - break; - - case 'YZX': - this._x = s1 * c2 * c3 + c1 * s2 * s3; - this._y = c1 * s2 * c3 + s1 * c2 * s3; - this._z = c1 * c2 * s3 - s1 * s2 * c3; - this._w = c1 * c2 * c3 - s1 * s2 * s3; - break; - - case 'XZY': - this._x = s1 * c2 * c3 - c1 * s2 * s3; - this._y = c1 * s2 * c3 - s1 * c2 * s3; - this._z = c1 * c2 * s3 + s1 * s2 * c3; - this._w = c1 * c2 * c3 + s1 * s2 * s3; - break; - - default: - console.warn( 'THREE.Quaternion: .setFromEuler() encountered an unknown order: ' + order ); - - } - - if ( update === true ) this._onChangeCallback(); - - return this; - - } - - setFromAxisAngle( axis, angle ) { - - // http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm - - // assumes axis is normalized - - const halfAngle = angle / 2, s = Math.sin( halfAngle ); - - this._x = axis.x * s; - this._y = axis.y * s; - this._z = axis.z * s; - this._w = Math.cos( halfAngle ); - - this._onChangeCallback(); - - return this; - - } - - setFromRotationMatrix( m ) { - - // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm - - // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) - - const te = m.elements, - - m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ], - m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ], - m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ], - - trace = m11 + m22 + m33; - - if ( trace > 0 ) { - - const s = 0.5 / Math.sqrt( trace + 1.0 ); - - this._w = 0.25 / s; - this._x = ( m32 - m23 ) * s; - this._y = ( m13 - m31 ) * s; - this._z = ( m21 - m12 ) * s; - - } else if ( m11 > m22 && m11 > m33 ) { - - const s = 2.0 * Math.sqrt( 1.0 + m11 - m22 - m33 ); - - this._w = ( m32 - m23 ) / s; - this._x = 0.25 * s; - this._y = ( m12 + m21 ) / s; - this._z = ( m13 + m31 ) / s; - - } else if ( m22 > m33 ) { - - const s = 2.0 * Math.sqrt( 1.0 + m22 - m11 - m33 ); - - this._w = ( m13 - m31 ) / s; - this._x = ( m12 + m21 ) / s; - this._y = 0.25 * s; - this._z = ( m23 + m32 ) / s; - - } else { - - const s = 2.0 * Math.sqrt( 1.0 + m33 - m11 - m22 ); - - this._w = ( m21 - m12 ) / s; - this._x = ( m13 + m31 ) / s; - this._y = ( m23 + m32 ) / s; - this._z = 0.25 * s; - - } - - this._onChangeCallback(); - - return this; - - } - - setFromUnitVectors( vFrom, vTo ) { - - // assumes direction vectors vFrom and vTo are normalized - - let r = vFrom.dot( vTo ) + 1; - - if ( r < Number.EPSILON ) { - - // vFrom and vTo point in opposite directions - - r = 0; - - if ( Math.abs( vFrom.x ) > Math.abs( vFrom.z ) ) { - - this._x = - vFrom.y; - this._y = vFrom.x; - this._z = 0; - this._w = r; - - } else { - - this._x = 0; - this._y = - vFrom.z; - this._z = vFrom.y; - this._w = r; - - } - - } else { - - // crossVectors( vFrom, vTo ); // inlined to avoid cyclic dependency on Vector3 - - this._x = vFrom.y * vTo.z - vFrom.z * vTo.y; - this._y = vFrom.z * vTo.x - vFrom.x * vTo.z; - this._z = vFrom.x * vTo.y - vFrom.y * vTo.x; - this._w = r; - - } - - return this.normalize(); - - } - - angleTo( q ) { - - return 2 * Math.acos( Math.abs( clamp( this.dot( q ), - 1, 1 ) ) ); - - } - - rotateTowards( q, step ) { - - const angle = this.angleTo( q ); - - if ( angle === 0 ) return this; - - const t = Math.min( 1, step / angle ); - - this.slerp( q, t ); - - return this; - - } - - identity() { - - return this.set( 0, 0, 0, 1 ); - - } - - invert() { - - // quaternion is assumed to have unit length - - return this.conjugate(); - - } - - conjugate() { - - this._x *= - 1; - this._y *= - 1; - this._z *= - 1; - - this._onChangeCallback(); - - return this; - - } - - dot( v ) { - - return this._x * v._x + this._y * v._y + this._z * v._z + this._w * v._w; - - } - - lengthSq() { - - return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w; - - } - - length() { - - return Math.sqrt( this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w ); - - } - - normalize() { - - let l = this.length(); - - if ( l === 0 ) { - - this._x = 0; - this._y = 0; - this._z = 0; - this._w = 1; - - } else { - - l = 1 / l; - - this._x = this._x * l; - this._y = this._y * l; - this._z = this._z * l; - this._w = this._w * l; - - } - - this._onChangeCallback(); - - return this; - - } - - multiply( q ) { - - return this.multiplyQuaternions( this, q ); - - } - - premultiply( q ) { - - return this.multiplyQuaternions( q, this ); - - } - - multiplyQuaternions( a, b ) { - - // from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm - - const qax = a._x, qay = a._y, qaz = a._z, qaw = a._w; - const qbx = b._x, qby = b._y, qbz = b._z, qbw = b._w; - - this._x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby; - this._y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz; - this._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx; - this._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz; - - this._onChangeCallback(); - - return this; - - } - - slerp( qb, t ) { - - if ( t === 0 ) return this; - if ( t === 1 ) return this.copy( qb ); - - const x = this._x, y = this._y, z = this._z, w = this._w; - - // http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/ - - let cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z; - - if ( cosHalfTheta < 0 ) { - - this._w = - qb._w; - this._x = - qb._x; - this._y = - qb._y; - this._z = - qb._z; - - cosHalfTheta = - cosHalfTheta; - - } else { - - this.copy( qb ); - - } - - if ( cosHalfTheta >= 1.0 ) { - - this._w = w; - this._x = x; - this._y = y; - this._z = z; - - return this; - - } - - const sqrSinHalfTheta = 1.0 - cosHalfTheta * cosHalfTheta; - - if ( sqrSinHalfTheta <= Number.EPSILON ) { - - const s = 1 - t; - this._w = s * w + t * this._w; - this._x = s * x + t * this._x; - this._y = s * y + t * this._y; - this._z = s * z + t * this._z; - - this.normalize(); // normalize calls _onChangeCallback() - - return this; - - } - - const sinHalfTheta = Math.sqrt( sqrSinHalfTheta ); - const halfTheta = Math.atan2( sinHalfTheta, cosHalfTheta ); - const ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta, - ratioB = Math.sin( t * halfTheta ) / sinHalfTheta; - - this._w = ( w * ratioA + this._w * ratioB ); - this._x = ( x * ratioA + this._x * ratioB ); - this._y = ( y * ratioA + this._y * ratioB ); - this._z = ( z * ratioA + this._z * ratioB ); - - this._onChangeCallback(); - - return this; - - } - - slerpQuaternions( qa, qb, t ) { - - return this.copy( qa ).slerp( qb, t ); - - } - - random() { - - // Derived from http://planning.cs.uiuc.edu/node198.html - // Note, this source uses w, x, y, z ordering, - // so we swap the order below. - - const u1 = Math.random(); - const sqrt1u1 = Math.sqrt( 1 - u1 ); - const sqrtu1 = Math.sqrt( u1 ); - - const u2 = 2 * Math.PI * Math.random(); - - const u3 = 2 * Math.PI * Math.random(); - - return this.set( - sqrt1u1 * Math.cos( u2 ), - sqrtu1 * Math.sin( u3 ), - sqrtu1 * Math.cos( u3 ), - sqrt1u1 * Math.sin( u2 ), - ); - - } - - equals( quaternion ) { - - return ( quaternion._x === this._x ) && ( quaternion._y === this._y ) && ( quaternion._z === this._z ) && ( quaternion._w === this._w ); - - } - - fromArray( array, offset = 0 ) { - - this._x = array[ offset ]; - this._y = array[ offset + 1 ]; - this._z = array[ offset + 2 ]; - this._w = array[ offset + 3 ]; - - this._onChangeCallback(); - - return this; - - } - - toArray( array = [], offset = 0 ) { - - array[ offset ] = this._x; - array[ offset + 1 ] = this._y; - array[ offset + 2 ] = this._z; - array[ offset + 3 ] = this._w; - - return array; - - } - - fromBufferAttribute( attribute, index ) { - - this._x = attribute.getX( index ); - this._y = attribute.getY( index ); - this._z = attribute.getZ( index ); - this._w = attribute.getW( index ); - - this._onChangeCallback(); - - return this; - - } - - toJSON() { - - return this.toArray(); - - } - - _onChange( callback ) { - - this._onChangeCallback = callback; - - return this; - - } - - _onChangeCallback() {} - - *[ Symbol.iterator ]() { - - yield this._x; - yield this._y; - yield this._z; - yield this._w; - - } - -} - -class Vector3 { - - constructor( x = 0, y = 0, z = 0 ) { - - Vector3.prototype.isVector3 = true; - - this.x = x; - this.y = y; - this.z = z; - - } - - set( x, y, z ) { - - if ( z === undefined ) z = this.z; // sprite.scale.set(x,y) - - this.x = x; - this.y = y; - this.z = z; - - return this; - - } - - setScalar( scalar ) { - - this.x = scalar; - this.y = scalar; - this.z = scalar; - - return this; - - } - - setX( x ) { - - this.x = x; - - return this; - - } - - setY( y ) { - - this.y = y; - - return this; - - } - - setZ( z ) { - - this.z = z; - - return this; - - } - - setComponent( index, value ) { - - switch ( index ) { - - case 0: this.x = value; break; - case 1: this.y = value; break; - case 2: this.z = value; break; - default: throw new Error( 'index is out of range: ' + index ); - - } - - return this; - - } - - getComponent( index ) { - - switch ( index ) { - - case 0: return this.x; - case 1: return this.y; - case 2: return this.z; - default: throw new Error( 'index is out of range: ' + index ); - - } - - } - - clone() { - - return new this.constructor( this.x, this.y, this.z ); - - } - - copy( v ) { - - this.x = v.x; - this.y = v.y; - this.z = v.z; - - return this; - - } - - add( v ) { - - this.x += v.x; - this.y += v.y; - this.z += v.z; - - return this; - - } - - addScalar( s ) { - - this.x += s; - this.y += s; - this.z += s; - - return this; - - } - - addVectors( a, b ) { - - this.x = a.x + b.x; - this.y = a.y + b.y; - this.z = a.z + b.z; - - return this; - - } - - addScaledVector( v, s ) { - - this.x += v.x * s; - this.y += v.y * s; - this.z += v.z * s; - - return this; - - } - - sub( v ) { - - this.x -= v.x; - this.y -= v.y; - this.z -= v.z; - - return this; - - } - - subScalar( s ) { - - this.x -= s; - this.y -= s; - this.z -= s; - - return this; - - } - - subVectors( a, b ) { - - this.x = a.x - b.x; - this.y = a.y - b.y; - this.z = a.z - b.z; - - return this; - - } - - multiply( v ) { - - this.x *= v.x; - this.y *= v.y; - this.z *= v.z; - - return this; - - } - - multiplyScalar( scalar ) { - - this.x *= scalar; - this.y *= scalar; - this.z *= scalar; - - return this; - - } - - multiplyVectors( a, b ) { - - this.x = a.x * b.x; - this.y = a.y * b.y; - this.z = a.z * b.z; - - return this; - - } - - applyEuler( euler ) { - - return this.applyQuaternion( _quaternion$4.setFromEuler( euler ) ); - - } - - applyAxisAngle( axis, angle ) { - - return this.applyQuaternion( _quaternion$4.setFromAxisAngle( axis, angle ) ); - - } - - applyMatrix3( m ) { - - const x = this.x, y = this.y, z = this.z; - const e = m.elements; - - this.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ] * z; - this.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ] * z; - this.z = e[ 2 ] * x + e[ 5 ] * y + e[ 8 ] * z; - - return this; - - } - - applyNormalMatrix( m ) { - - return this.applyMatrix3( m ).normalize(); - - } - - applyMatrix4( m ) { - - const x = this.x, y = this.y, z = this.z; - const e = m.elements; - - const w = 1 / ( e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] ); - - this.x = ( e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] ) * w; - this.y = ( e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] ) * w; - this.z = ( e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] ) * w; - - return this; - - } - - applyQuaternion( q ) { - - // quaternion q is assumed to have unit length - - const vx = this.x, vy = this.y, vz = this.z; - const qx = q.x, qy = q.y, qz = q.z, qw = q.w; - - // t = 2 * cross( q.xyz, v ); - const tx = 2 * ( qy * vz - qz * vy ); - const ty = 2 * ( qz * vx - qx * vz ); - const tz = 2 * ( qx * vy - qy * vx ); - - // v + q.w * t + cross( q.xyz, t ); - this.x = vx + qw * tx + qy * tz - qz * ty; - this.y = vy + qw * ty + qz * tx - qx * tz; - this.z = vz + qw * tz + qx * ty - qy * tx; - - return this; - - } - - project( camera ) { - - return this.applyMatrix4( camera.matrixWorldInverse ).applyMatrix4( camera.projectionMatrix ); - - } - - unproject( camera ) { - - return this.applyMatrix4( camera.projectionMatrixInverse ).applyMatrix4( camera.matrixWorld ); - - } - - transformDirection( m ) { - - // input: THREE.Matrix4 affine matrix - // vector interpreted as a direction - - const x = this.x, y = this.y, z = this.z; - const e = m.elements; - - this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z; - this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z; - this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z; - - return this.normalize(); - - } - - divide( v ) { - - this.x /= v.x; - this.y /= v.y; - this.z /= v.z; - - return this; - - } - - divideScalar( scalar ) { - - return this.multiplyScalar( 1 / scalar ); - - } - - min( v ) { - - this.x = Math.min( this.x, v.x ); - this.y = Math.min( this.y, v.y ); - this.z = Math.min( this.z, v.z ); - - return this; - - } - - max( v ) { - - this.x = Math.max( this.x, v.x ); - this.y = Math.max( this.y, v.y ); - this.z = Math.max( this.z, v.z ); - - return this; - - } - - clamp( min, max ) { - - // assumes min < max, componentwise - - this.x = Math.max( min.x, Math.min( max.x, this.x ) ); - this.y = Math.max( min.y, Math.min( max.y, this.y ) ); - this.z = Math.max( min.z, Math.min( max.z, this.z ) ); - - return this; - - } - - clampScalar( minVal, maxVal ) { - - this.x = Math.max( minVal, Math.min( maxVal, this.x ) ); - this.y = Math.max( minVal, Math.min( maxVal, this.y ) ); - this.z = Math.max( minVal, Math.min( maxVal, this.z ) ); - - return this; - - } - - clampLength( min, max ) { - - const length = this.length(); - - return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) ); - - } - - floor() { - - this.x = Math.floor( this.x ); - this.y = Math.floor( this.y ); - this.z = Math.floor( this.z ); - - return this; - - } - - ceil() { - - this.x = Math.ceil( this.x ); - this.y = Math.ceil( this.y ); - this.z = Math.ceil( this.z ); - - return this; - - } - - round() { - - this.x = Math.round( this.x ); - this.y = Math.round( this.y ); - this.z = Math.round( this.z ); - - return this; - - } - - roundToZero() { - - this.x = Math.trunc( this.x ); - this.y = Math.trunc( this.y ); - this.z = Math.trunc( this.z ); - - return this; - - } - - negate() { - - this.x = - this.x; - this.y = - this.y; - this.z = - this.z; - - return this; - - } - - dot( v ) { - - return this.x * v.x + this.y * v.y + this.z * v.z; - - } - - // TODO lengthSquared? - - lengthSq() { - - return this.x * this.x + this.y * this.y + this.z * this.z; - - } - - length() { - - return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z ); - - } - - manhattanLength() { - - return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ); - - } - - normalize() { - - return this.divideScalar( this.length() || 1 ); - - } - - setLength( length ) { - - return this.normalize().multiplyScalar( length ); - - } - - lerp( v, alpha ) { - - this.x += ( v.x - this.x ) * alpha; - this.y += ( v.y - this.y ) * alpha; - this.z += ( v.z - this.z ) * alpha; - - return this; - - } - - lerpVectors( v1, v2, alpha ) { - - this.x = v1.x + ( v2.x - v1.x ) * alpha; - this.y = v1.y + ( v2.y - v1.y ) * alpha; - this.z = v1.z + ( v2.z - v1.z ) * alpha; - - return this; - - } - - cross( v ) { - - return this.crossVectors( this, v ); - - } - - crossVectors( a, b ) { - - const ax = a.x, ay = a.y, az = a.z; - const bx = b.x, by = b.y, bz = b.z; - - this.x = ay * bz - az * by; - this.y = az * bx - ax * bz; - this.z = ax * by - ay * bx; - - return this; - - } - - projectOnVector( v ) { - - const denominator = v.lengthSq(); - - if ( denominator === 0 ) return this.set( 0, 0, 0 ); - - const scalar = v.dot( this ) / denominator; - - return this.copy( v ).multiplyScalar( scalar ); - - } - - projectOnPlane( planeNormal ) { - - _vector$c.copy( this ).projectOnVector( planeNormal ); - - return this.sub( _vector$c ); - - } - - reflect( normal ) { - - // reflect incident vector off plane orthogonal to normal - // normal is assumed to have unit length - - return this.sub( _vector$c.copy( normal ).multiplyScalar( 2 * this.dot( normal ) ) ); - - } - - angleTo( v ) { - - const denominator = Math.sqrt( this.lengthSq() * v.lengthSq() ); - - if ( denominator === 0 ) return Math.PI / 2; - - const theta = this.dot( v ) / denominator; - - // clamp, to handle numerical problems - - return Math.acos( clamp( theta, - 1, 1 ) ); - - } - - distanceTo( v ) { - - return Math.sqrt( this.distanceToSquared( v ) ); - - } - - distanceToSquared( v ) { - - const dx = this.x - v.x, dy = this.y - v.y, dz = this.z - v.z; - - return dx * dx + dy * dy + dz * dz; - - } - - manhattanDistanceTo( v ) { - - return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y ) + Math.abs( this.z - v.z ); - - } - - setFromSpherical( s ) { - - return this.setFromSphericalCoords( s.radius, s.phi, s.theta ); - - } - - setFromSphericalCoords( radius, phi, theta ) { - - const sinPhiRadius = Math.sin( phi ) * radius; - - this.x = sinPhiRadius * Math.sin( theta ); - this.y = Math.cos( phi ) * radius; - this.z = sinPhiRadius * Math.cos( theta ); - - return this; - - } - - setFromCylindrical( c ) { - - return this.setFromCylindricalCoords( c.radius, c.theta, c.y ); - - } - - setFromCylindricalCoords( radius, theta, y ) { - - this.x = radius * Math.sin( theta ); - this.y = y; - this.z = radius * Math.cos( theta ); - - return this; - - } - - setFromMatrixPosition( m ) { - - const e = m.elements; - - this.x = e[ 12 ]; - this.y = e[ 13 ]; - this.z = e[ 14 ]; - - return this; - - } - - setFromMatrixScale( m ) { - - const sx = this.setFromMatrixColumn( m, 0 ).length(); - const sy = this.setFromMatrixColumn( m, 1 ).length(); - const sz = this.setFromMatrixColumn( m, 2 ).length(); - - this.x = sx; - this.y = sy; - this.z = sz; - - return this; - - } - - setFromMatrixColumn( m, index ) { - - return this.fromArray( m.elements, index * 4 ); - - } - - setFromMatrix3Column( m, index ) { - - return this.fromArray( m.elements, index * 3 ); - - } - - setFromEuler( e ) { - - this.x = e._x; - this.y = e._y; - this.z = e._z; - - return this; - - } - - setFromColor( c ) { - - this.x = c.r; - this.y = c.g; - this.z = c.b; - - return this; - - } - - equals( v ) { - - return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) ); - - } - - fromArray( array, offset = 0 ) { - - this.x = array[ offset ]; - this.y = array[ offset + 1 ]; - this.z = array[ offset + 2 ]; - - return this; - - } - - toArray( array = [], offset = 0 ) { - - array[ offset ] = this.x; - array[ offset + 1 ] = this.y; - array[ offset + 2 ] = this.z; - - return array; - - } - - fromBufferAttribute( attribute, index ) { - - this.x = attribute.getX( index ); - this.y = attribute.getY( index ); - this.z = attribute.getZ( index ); - - return this; - - } - - random() { - - this.x = Math.random(); - this.y = Math.random(); - this.z = Math.random(); - - return this; - - } - - randomDirection() { - - // Derived from https://mathworld.wolfram.com/SpherePointPicking.html - - const u = ( Math.random() - 0.5 ) * 2; - const t = Math.random() * Math.PI * 2; - const f = Math.sqrt( 1 - u ** 2 ); - - this.x = f * Math.cos( t ); - this.y = f * Math.sin( t ); - this.z = u; - - return this; - - } - - *[ Symbol.iterator ]() { - - yield this.x; - yield this.y; - yield this.z; - - } - -} - -const _vector$c = /*@__PURE__*/ new Vector3(); -const _quaternion$4 = /*@__PURE__*/ new Quaternion(); - -class Box3 { - - constructor( min = new Vector3( + Infinity, + Infinity, + Infinity ), max = new Vector3( - Infinity, - Infinity, - Infinity ) ) { - - this.isBox3 = true; - - this.min = min; - this.max = max; - - } - - set( min, max ) { - - this.min.copy( min ); - this.max.copy( max ); - - return this; - - } - - setFromArray( array ) { - - this.makeEmpty(); - - for ( let i = 0, il = array.length; i < il; i += 3 ) { - - this.expandByPoint( _vector$b.fromArray( array, i ) ); - - } - - return this; - - } - - setFromBufferAttribute( attribute ) { - - this.makeEmpty(); - - for ( let i = 0, il = attribute.count; i < il; i ++ ) { - - this.expandByPoint( _vector$b.fromBufferAttribute( attribute, i ) ); - - } - - return this; - - } - - setFromPoints( points ) { - - this.makeEmpty(); - - for ( let i = 0, il = points.length; i < il; i ++ ) { - - this.expandByPoint( points[ i ] ); - - } - - return this; - - } - - setFromCenterAndSize( center, size ) { - - const halfSize = _vector$b.copy( size ).multiplyScalar( 0.5 ); - - this.min.copy( center ).sub( halfSize ); - this.max.copy( center ).add( halfSize ); - - return this; - - } - - setFromObject( object, precise = false ) { - - this.makeEmpty(); - - return this.expandByObject( object, precise ); - - } - - clone() { - - return new this.constructor().copy( this ); - - } - - copy( box ) { - - this.min.copy( box.min ); - this.max.copy( box.max ); - - return this; - - } - - makeEmpty() { - - this.min.x = this.min.y = this.min.z = + Infinity; - this.max.x = this.max.y = this.max.z = - Infinity; - - return this; - - } - - isEmpty() { - - // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes - - return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ) || ( this.max.z < this.min.z ); - - } - - getCenter( target ) { - - return this.isEmpty() ? target.set( 0, 0, 0 ) : target.addVectors( this.min, this.max ).multiplyScalar( 0.5 ); - - } - - getSize( target ) { - - return this.isEmpty() ? target.set( 0, 0, 0 ) : target.subVectors( this.max, this.min ); - - } - - expandByPoint( point ) { - - this.min.min( point ); - this.max.max( point ); - - return this; - - } - - expandByVector( vector ) { - - this.min.sub( vector ); - this.max.add( vector ); - - return this; - - } - - expandByScalar( scalar ) { - - this.min.addScalar( - scalar ); - this.max.addScalar( scalar ); - - return this; - - } - - expandByObject( object, precise = false ) { - - // Computes the world-axis-aligned bounding box of an object (including its children), - // accounting for both the object's, and children's, world transforms - - object.updateWorldMatrix( false, false ); - - const geometry = object.geometry; - - if ( geometry !== undefined ) { - - const positionAttribute = geometry.getAttribute( 'position' ); - - // precise AABB computation based on vertex data requires at least a position attribute. - // instancing isn't supported so far and uses the normal (conservative) code path. - - if ( precise === true && positionAttribute !== undefined && object.isInstancedMesh !== true ) { - - for ( let i = 0, l = positionAttribute.count; i < l; i ++ ) { - - if ( object.isMesh === true ) { - - object.getVertexPosition( i, _vector$b ); - - } else { - - _vector$b.fromBufferAttribute( positionAttribute, i ); - - } - - _vector$b.applyMatrix4( object.matrixWorld ); - this.expandByPoint( _vector$b ); - - } - - } else { - - if ( object.boundingBox !== undefined ) { - - // object-level bounding box - - if ( object.boundingBox === null ) { - - object.computeBoundingBox(); - - } - - _box$4.copy( object.boundingBox ); - - - } else { - - // geometry-level bounding box - - if ( geometry.boundingBox === null ) { - - geometry.computeBoundingBox(); - - } - - _box$4.copy( geometry.boundingBox ); - - } - - _box$4.applyMatrix4( object.matrixWorld ); - - this.union( _box$4 ); - - } - - } - - const children = object.children; - - for ( let i = 0, l = children.length; i < l; i ++ ) { - - this.expandByObject( children[ i ], precise ); - - } - - return this; - - } - - containsPoint( point ) { - - return point.x < this.min.x || point.x > this.max.x || - point.y < this.min.y || point.y > this.max.y || - point.z < this.min.z || point.z > this.max.z ? false : true; - - } - - containsBox( box ) { - - return this.min.x <= box.min.x && box.max.x <= this.max.x && - this.min.y <= box.min.y && box.max.y <= this.max.y && - this.min.z <= box.min.z && box.max.z <= this.max.z; - - } - - getParameter( point, target ) { - - // This can potentially have a divide by zero if the box - // has a size dimension of 0. - - return target.set( - ( point.x - this.min.x ) / ( this.max.x - this.min.x ), - ( point.y - this.min.y ) / ( this.max.y - this.min.y ), - ( point.z - this.min.z ) / ( this.max.z - this.min.z ) - ); - - } - - intersectsBox( box ) { - - // using 6 splitting planes to rule out intersections. - return box.max.x < this.min.x || box.min.x > this.max.x || - box.max.y < this.min.y || box.min.y > this.max.y || - box.max.z < this.min.z || box.min.z > this.max.z ? false : true; - - } - - intersectsSphere( sphere ) { - - // Find the point on the AABB closest to the sphere center. - this.clampPoint( sphere.center, _vector$b ); - - // If that point is inside the sphere, the AABB and sphere intersect. - return _vector$b.distanceToSquared( sphere.center ) <= ( sphere.radius * sphere.radius ); - - } - - intersectsPlane( plane ) { - - // We compute the minimum and maximum dot product values. If those values - // are on the same side (back or front) of the plane, then there is no intersection. - - let min, max; - - if ( plane.normal.x > 0 ) { - - min = plane.normal.x * this.min.x; - max = plane.normal.x * this.max.x; - - } else { - - min = plane.normal.x * this.max.x; - max = plane.normal.x * this.min.x; - - } - - if ( plane.normal.y > 0 ) { - - min += plane.normal.y * this.min.y; - max += plane.normal.y * this.max.y; - - } else { - - min += plane.normal.y * this.max.y; - max += plane.normal.y * this.min.y; - - } - - if ( plane.normal.z > 0 ) { - - min += plane.normal.z * this.min.z; - max += plane.normal.z * this.max.z; - - } else { - - min += plane.normal.z * this.max.z; - max += plane.normal.z * this.min.z; - - } - - return ( min <= - plane.constant && max >= - plane.constant ); - - } - - intersectsTriangle( triangle ) { - - if ( this.isEmpty() ) { - - return false; - - } - - // compute box center and extents - this.getCenter( _center ); - _extents.subVectors( this.max, _center ); - - // translate triangle to aabb origin - _v0$2.subVectors( triangle.a, _center ); - _v1$7.subVectors( triangle.b, _center ); - _v2$4.subVectors( triangle.c, _center ); - - // compute edge vectors for triangle - _f0.subVectors( _v1$7, _v0$2 ); - _f1.subVectors( _v2$4, _v1$7 ); - _f2.subVectors( _v0$2, _v2$4 ); - - // test against axes that are given by cross product combinations of the edges of the triangle and the edges of the aabb - // make an axis testing of each of the 3 sides of the aabb against each of the 3 sides of the triangle = 9 axis of separation - // axis_ij = u_i x f_j (u0, u1, u2 = face normals of aabb = x,y,z axes vectors since aabb is axis aligned) - let axes = [ - 0, - _f0.z, _f0.y, 0, - _f1.z, _f1.y, 0, - _f2.z, _f2.y, - _f0.z, 0, - _f0.x, _f1.z, 0, - _f1.x, _f2.z, 0, - _f2.x, - - _f0.y, _f0.x, 0, - _f1.y, _f1.x, 0, - _f2.y, _f2.x, 0 - ]; - if ( ! satForAxes( axes, _v0$2, _v1$7, _v2$4, _extents ) ) { - - return false; - - } - - // test 3 face normals from the aabb - axes = [ 1, 0, 0, 0, 1, 0, 0, 0, 1 ]; - if ( ! satForAxes( axes, _v0$2, _v1$7, _v2$4, _extents ) ) { - - return false; - - } - - // finally testing the face normal of the triangle - // use already existing triangle edge vectors here - _triangleNormal.crossVectors( _f0, _f1 ); - axes = [ _triangleNormal.x, _triangleNormal.y, _triangleNormal.z ]; - - return satForAxes( axes, _v0$2, _v1$7, _v2$4, _extents ); - - } - - clampPoint( point, target ) { - - return target.copy( point ).clamp( this.min, this.max ); - - } - - distanceToPoint( point ) { - - return this.clampPoint( point, _vector$b ).distanceTo( point ); - - } - - getBoundingSphere( target ) { - - if ( this.isEmpty() ) { - - target.makeEmpty(); - - } else { - - this.getCenter( target.center ); - - target.radius = this.getSize( _vector$b ).length() * 0.5; - - } - - return target; - - } - - intersect( box ) { - - this.min.max( box.min ); - this.max.min( box.max ); - - // ensure that if there is no overlap, the result is fully empty, not slightly empty with non-inf/+inf values that will cause subsequence intersects to erroneously return valid values. - if ( this.isEmpty() ) this.makeEmpty(); - - return this; - - } - - union( box ) { - - this.min.min( box.min ); - this.max.max( box.max ); - - return this; - - } - - applyMatrix4( matrix ) { - - // transform of empty box is an empty box. - if ( this.isEmpty() ) return this; - - // NOTE: I am using a binary pattern to specify all 2^3 combinations below - _points[ 0 ].set( this.min.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 000 - _points[ 1 ].set( this.min.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 001 - _points[ 2 ].set( this.min.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 010 - _points[ 3 ].set( this.min.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 011 - _points[ 4 ].set( this.max.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 100 - _points[ 5 ].set( this.max.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 101 - _points[ 6 ].set( this.max.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 110 - _points[ 7 ].set( this.max.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 111 - - this.setFromPoints( _points ); - - return this; - - } - - translate( offset ) { - - this.min.add( offset ); - this.max.add( offset ); - - return this; - - } - - equals( box ) { - - return box.min.equals( this.min ) && box.max.equals( this.max ); - - } - -} - -const _points = [ - /*@__PURE__*/ new Vector3(), - /*@__PURE__*/ new Vector3(), - /*@__PURE__*/ new Vector3(), - /*@__PURE__*/ new Vector3(), - /*@__PURE__*/ new Vector3(), - /*@__PURE__*/ new Vector3(), - /*@__PURE__*/ new Vector3(), - /*@__PURE__*/ new Vector3() -]; - -const _vector$b = /*@__PURE__*/ new Vector3(); - -const _box$4 = /*@__PURE__*/ new Box3(); - -// triangle centered vertices - -const _v0$2 = /*@__PURE__*/ new Vector3(); -const _v1$7 = /*@__PURE__*/ new Vector3(); -const _v2$4 = /*@__PURE__*/ new Vector3(); - -// triangle edge vectors - -const _f0 = /*@__PURE__*/ new Vector3(); -const _f1 = /*@__PURE__*/ new Vector3(); -const _f2 = /*@__PURE__*/ new Vector3(); - -const _center = /*@__PURE__*/ new Vector3(); -const _extents = /*@__PURE__*/ new Vector3(); -const _triangleNormal = /*@__PURE__*/ new Vector3(); -const _testAxis = /*@__PURE__*/ new Vector3(); - -function satForAxes( axes, v0, v1, v2, extents ) { - - for ( let i = 0, j = axes.length - 3; i <= j; i += 3 ) { - - _testAxis.fromArray( axes, i ); - // project the aabb onto the separating axis - const r = extents.x * Math.abs( _testAxis.x ) + extents.y * Math.abs( _testAxis.y ) + extents.z * Math.abs( _testAxis.z ); - // project all 3 vertices of the triangle onto the separating axis - const p0 = v0.dot( _testAxis ); - const p1 = v1.dot( _testAxis ); - const p2 = v2.dot( _testAxis ); - // actual test, basically see if either of the most extreme of the triangle points intersects r - if ( Math.max( - Math.max( p0, p1, p2 ), Math.min( p0, p1, p2 ) ) > r ) { - - // points of the projected triangle are outside the projected half-length of the aabb - // the axis is separating and we can exit - return false; - - } - - } - - return true; - -} - -const _box$3 = /*@__PURE__*/ new Box3(); -const _v1$6 = /*@__PURE__*/ new Vector3(); -const _v2$3 = /*@__PURE__*/ new Vector3(); - -class Sphere { - - constructor( center = new Vector3(), radius = - 1 ) { - - this.isSphere = true; - - this.center = center; - this.radius = radius; - - } - - set( center, radius ) { - - this.center.copy( center ); - this.radius = radius; - - return this; - - } - - setFromPoints( points, optionalCenter ) { - - const center = this.center; - - if ( optionalCenter !== undefined ) { - - center.copy( optionalCenter ); - - } else { - - _box$3.setFromPoints( points ).getCenter( center ); - - } - - let maxRadiusSq = 0; - - for ( let i = 0, il = points.length; i < il; i ++ ) { - - maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( points[ i ] ) ); - - } - - this.radius = Math.sqrt( maxRadiusSq ); - - return this; - - } - - copy( sphere ) { - - this.center.copy( sphere.center ); - this.radius = sphere.radius; - - return this; - - } - - isEmpty() { - - return ( this.radius < 0 ); - - } - - makeEmpty() { - - this.center.set( 0, 0, 0 ); - this.radius = - 1; - - return this; - - } - - containsPoint( point ) { - - return ( point.distanceToSquared( this.center ) <= ( this.radius * this.radius ) ); - - } - - distanceToPoint( point ) { - - return ( point.distanceTo( this.center ) - this.radius ); - - } - - intersectsSphere( sphere ) { - - const radiusSum = this.radius + sphere.radius; - - return sphere.center.distanceToSquared( this.center ) <= ( radiusSum * radiusSum ); - - } - - intersectsBox( box ) { - - return box.intersectsSphere( this ); - - } - - intersectsPlane( plane ) { - - return Math.abs( plane.distanceToPoint( this.center ) ) <= this.radius; - - } - - clampPoint( point, target ) { - - const deltaLengthSq = this.center.distanceToSquared( point ); - - target.copy( point ); - - if ( deltaLengthSq > ( this.radius * this.radius ) ) { - - target.sub( this.center ).normalize(); - target.multiplyScalar( this.radius ).add( this.center ); - - } - - return target; - - } - - getBoundingBox( target ) { - - if ( this.isEmpty() ) { - - // Empty sphere produces empty bounding box - target.makeEmpty(); - return target; - - } - - target.set( this.center, this.center ); - target.expandByScalar( this.radius ); - - return target; - - } - - applyMatrix4( matrix ) { - - this.center.applyMatrix4( matrix ); - this.radius = this.radius * matrix.getMaxScaleOnAxis(); - - return this; - - } - - translate( offset ) { - - this.center.add( offset ); - - return this; - - } - - expandByPoint( point ) { - - if ( this.isEmpty() ) { - - this.center.copy( point ); - - this.radius = 0; - - return this; - - } - - _v1$6.subVectors( point, this.center ); - - const lengthSq = _v1$6.lengthSq(); - - if ( lengthSq > ( this.radius * this.radius ) ) { - - // calculate the minimal sphere - - const length = Math.sqrt( lengthSq ); - - const delta = ( length - this.radius ) * 0.5; - - this.center.addScaledVector( _v1$6, delta / length ); - - this.radius += delta; - - } - - return this; - - } - - union( sphere ) { - - if ( sphere.isEmpty() ) { - - return this; - - } - - if ( this.isEmpty() ) { - - this.copy( sphere ); - - return this; - - } - - if ( this.center.equals( sphere.center ) === true ) { - - this.radius = Math.max( this.radius, sphere.radius ); - - } else { - - _v2$3.subVectors( sphere.center, this.center ).setLength( sphere.radius ); - - this.expandByPoint( _v1$6.copy( sphere.center ).add( _v2$3 ) ); - - this.expandByPoint( _v1$6.copy( sphere.center ).sub( _v2$3 ) ); - - } - - return this; - - } - - equals( sphere ) { - - return sphere.center.equals( this.center ) && ( sphere.radius === this.radius ); - - } - - clone() { - - return new this.constructor().copy( this ); - - } - -} - -const _vector$a = /*@__PURE__*/ new Vector3(); -const _segCenter = /*@__PURE__*/ new Vector3(); -const _segDir = /*@__PURE__*/ new Vector3(); -const _diff = /*@__PURE__*/ new Vector3(); - -const _edge1 = /*@__PURE__*/ new Vector3(); -const _edge2 = /*@__PURE__*/ new Vector3(); -const _normal$1 = /*@__PURE__*/ new Vector3(); - -class Ray { - - constructor( origin = new Vector3(), direction = new Vector3( 0, 0, - 1 ) ) { - - this.origin = origin; - this.direction = direction; - - } - - set( origin, direction ) { - - this.origin.copy( origin ); - this.direction.copy( direction ); - - return this; - - } - - copy( ray ) { - - this.origin.copy( ray.origin ); - this.direction.copy( ray.direction ); - - return this; - - } - - at( t, target ) { - - return target.copy( this.origin ).addScaledVector( this.direction, t ); - - } - - lookAt( v ) { - - this.direction.copy( v ).sub( this.origin ).normalize(); - - return this; - - } - - recast( t ) { - - this.origin.copy( this.at( t, _vector$a ) ); - - return this; - - } - - closestPointToPoint( point, target ) { - - target.subVectors( point, this.origin ); - - const directionDistance = target.dot( this.direction ); - - if ( directionDistance < 0 ) { - - return target.copy( this.origin ); - - } - - return target.copy( this.origin ).addScaledVector( this.direction, directionDistance ); - - } - - distanceToPoint( point ) { - - return Math.sqrt( this.distanceSqToPoint( point ) ); - - } - - distanceSqToPoint( point ) { - - const directionDistance = _vector$a.subVectors( point, this.origin ).dot( this.direction ); - - // point behind the ray - - if ( directionDistance < 0 ) { - - return this.origin.distanceToSquared( point ); - - } - - _vector$a.copy( this.origin ).addScaledVector( this.direction, directionDistance ); - - return _vector$a.distanceToSquared( point ); - - } - - distanceSqToSegment( v0, v1, optionalPointOnRay, optionalPointOnSegment ) { - - // from https://github.com/pmjoniak/GeometricTools/blob/master/GTEngine/Include/Mathematics/GteDistRaySegment.h - // It returns the min distance between the ray and the segment - // defined by v0 and v1 - // It can also set two optional targets : - // - The closest point on the ray - // - The closest point on the segment - - _segCenter.copy( v0 ).add( v1 ).multiplyScalar( 0.5 ); - _segDir.copy( v1 ).sub( v0 ).normalize(); - _diff.copy( this.origin ).sub( _segCenter ); - - const segExtent = v0.distanceTo( v1 ) * 0.5; - const a01 = - this.direction.dot( _segDir ); - const b0 = _diff.dot( this.direction ); - const b1 = - _diff.dot( _segDir ); - const c = _diff.lengthSq(); - const det = Math.abs( 1 - a01 * a01 ); - let s0, s1, sqrDist, extDet; - - if ( det > 0 ) { - - // The ray and segment are not parallel. - - s0 = a01 * b1 - b0; - s1 = a01 * b0 - b1; - extDet = segExtent * det; - - if ( s0 >= 0 ) { - - if ( s1 >= - extDet ) { - - if ( s1 <= extDet ) { - - // region 0 - // Minimum at interior points of ray and segment. - - const invDet = 1 / det; - s0 *= invDet; - s1 *= invDet; - sqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c; - - } else { - - // region 1 - - s1 = segExtent; - s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); - sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; - - } - - } else { - - // region 5 - - s1 = - segExtent; - s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); - sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; - - } - - } else { - - if ( s1 <= - extDet ) { - - // region 4 - - s0 = Math.max( 0, - ( - a01 * segExtent + b0 ) ); - s1 = ( s0 > 0 ) ? - segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent ); - sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; - - } else if ( s1 <= extDet ) { - - // region 3 - - s0 = 0; - s1 = Math.min( Math.max( - segExtent, - b1 ), segExtent ); - sqrDist = s1 * ( s1 + 2 * b1 ) + c; - - } else { - - // region 2 - - s0 = Math.max( 0, - ( a01 * segExtent + b0 ) ); - s1 = ( s0 > 0 ) ? segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent ); - sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; - - } - - } - - } else { - - // Ray and segment are parallel. - - s1 = ( a01 > 0 ) ? - segExtent : segExtent; - s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); - sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; - - } - - if ( optionalPointOnRay ) { - - optionalPointOnRay.copy( this.origin ).addScaledVector( this.direction, s0 ); - - } - - if ( optionalPointOnSegment ) { - - optionalPointOnSegment.copy( _segCenter ).addScaledVector( _segDir, s1 ); - - } - - return sqrDist; - - } - - intersectSphere( sphere, target ) { - - _vector$a.subVectors( sphere.center, this.origin ); - const tca = _vector$a.dot( this.direction ); - const d2 = _vector$a.dot( _vector$a ) - tca * tca; - const radius2 = sphere.radius * sphere.radius; - - if ( d2 > radius2 ) return null; - - const thc = Math.sqrt( radius2 - d2 ); - - // t0 = first intersect point - entrance on front of sphere - const t0 = tca - thc; - - // t1 = second intersect point - exit point on back of sphere - const t1 = tca + thc; - - // test to see if t1 is behind the ray - if so, return null - if ( t1 < 0 ) return null; - - // test to see if t0 is behind the ray: - // if it is, the ray is inside the sphere, so return the second exit point scaled by t1, - // in order to always return an intersect point that is in front of the ray. - if ( t0 < 0 ) return this.at( t1, target ); - - // else t0 is in front of the ray, so return the first collision point scaled by t0 - return this.at( t0, target ); - - } - - intersectsSphere( sphere ) { - - return this.distanceSqToPoint( sphere.center ) <= ( sphere.radius * sphere.radius ); - - } - - distanceToPlane( plane ) { - - const denominator = plane.normal.dot( this.direction ); - - if ( denominator === 0 ) { - - // line is coplanar, return origin - if ( plane.distanceToPoint( this.origin ) === 0 ) { - - return 0; - - } - - // Null is preferable to undefined since undefined means.... it is undefined - - return null; - - } - - const t = - ( this.origin.dot( plane.normal ) + plane.constant ) / denominator; - - // Return if the ray never intersects the plane - - return t >= 0 ? t : null; - - } - - intersectPlane( plane, target ) { - - const t = this.distanceToPlane( plane ); - - if ( t === null ) { - - return null; - - } - - return this.at( t, target ); - - } - - intersectsPlane( plane ) { - - // check if the ray lies on the plane first - - const distToPoint = plane.distanceToPoint( this.origin ); - - if ( distToPoint === 0 ) { - - return true; - - } - - const denominator = plane.normal.dot( this.direction ); - - if ( denominator * distToPoint < 0 ) { - - return true; - - } - - // ray origin is behind the plane (and is pointing behind it) - - return false; - - } - - intersectBox( box, target ) { - - let tmin, tmax, tymin, tymax, tzmin, tzmax; - - const invdirx = 1 / this.direction.x, - invdiry = 1 / this.direction.y, - invdirz = 1 / this.direction.z; - - const origin = this.origin; - - if ( invdirx >= 0 ) { - - tmin = ( box.min.x - origin.x ) * invdirx; - tmax = ( box.max.x - origin.x ) * invdirx; - - } else { - - tmin = ( box.max.x - origin.x ) * invdirx; - tmax = ( box.min.x - origin.x ) * invdirx; - - } - - if ( invdiry >= 0 ) { - - tymin = ( box.min.y - origin.y ) * invdiry; - tymax = ( box.max.y - origin.y ) * invdiry; - - } else { - - tymin = ( box.max.y - origin.y ) * invdiry; - tymax = ( box.min.y - origin.y ) * invdiry; - - } - - if ( ( tmin > tymax ) || ( tymin > tmax ) ) return null; - - if ( tymin > tmin || isNaN( tmin ) ) tmin = tymin; - - if ( tymax < tmax || isNaN( tmax ) ) tmax = tymax; - - if ( invdirz >= 0 ) { - - tzmin = ( box.min.z - origin.z ) * invdirz; - tzmax = ( box.max.z - origin.z ) * invdirz; - - } else { - - tzmin = ( box.max.z - origin.z ) * invdirz; - tzmax = ( box.min.z - origin.z ) * invdirz; - - } - - if ( ( tmin > tzmax ) || ( tzmin > tmax ) ) return null; - - if ( tzmin > tmin || tmin !== tmin ) tmin = tzmin; - - if ( tzmax < tmax || tmax !== tmax ) tmax = tzmax; - - //return point closest to the ray (positive side) - - if ( tmax < 0 ) return null; - - return this.at( tmin >= 0 ? tmin : tmax, target ); - - } - - intersectsBox( box ) { - - return this.intersectBox( box, _vector$a ) !== null; - - } - - intersectTriangle( a, b, c, backfaceCulling, target ) { - - // Compute the offset origin, edges, and normal. - - // from https://github.com/pmjoniak/GeometricTools/blob/master/GTEngine/Include/Mathematics/GteIntrRay3Triangle3.h - - _edge1.subVectors( b, a ); - _edge2.subVectors( c, a ); - _normal$1.crossVectors( _edge1, _edge2 ); - - // Solve Q + t*D = b1*E1 + b2*E2 (Q = kDiff, D = ray direction, - // E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by - // |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2)) - // |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q)) - // |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N) - let DdN = this.direction.dot( _normal$1 ); - let sign; - - if ( DdN > 0 ) { - - if ( backfaceCulling ) return null; - sign = 1; - - } else if ( DdN < 0 ) { - - sign = - 1; - DdN = - DdN; - - } else { - - return null; - - } - - _diff.subVectors( this.origin, a ); - const DdQxE2 = sign * this.direction.dot( _edge2.crossVectors( _diff, _edge2 ) ); - - // b1 < 0, no intersection - if ( DdQxE2 < 0 ) { - - return null; - - } - - const DdE1xQ = sign * this.direction.dot( _edge1.cross( _diff ) ); - - // b2 < 0, no intersection - if ( DdE1xQ < 0 ) { - - return null; - - } - - // b1+b2 > 1, no intersection - if ( DdQxE2 + DdE1xQ > DdN ) { - - return null; - - } - - // Line intersects triangle, check if ray does. - const QdN = - sign * _diff.dot( _normal$1 ); - - // t < 0, no intersection - if ( QdN < 0 ) { - - return null; - - } - - // Ray intersects triangle. - return this.at( QdN / DdN, target ); - - } - - applyMatrix4( matrix4 ) { - - this.origin.applyMatrix4( matrix4 ); - this.direction.transformDirection( matrix4 ); - - return this; - - } - - equals( ray ) { - - return ray.origin.equals( this.origin ) && ray.direction.equals( this.direction ); - - } - - clone() { - - return new this.constructor().copy( this ); - - } - -} - -class Matrix4 { - - constructor( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) { - - Matrix4.prototype.isMatrix4 = true; - - this.elements = [ - - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1 - - ]; - - if ( n11 !== undefined ) { - - this.set( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ); - - } - - } - - set( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) { - - const te = this.elements; - - te[ 0 ] = n11; te[ 4 ] = n12; te[ 8 ] = n13; te[ 12 ] = n14; - te[ 1 ] = n21; te[ 5 ] = n22; te[ 9 ] = n23; te[ 13 ] = n24; - te[ 2 ] = n31; te[ 6 ] = n32; te[ 10 ] = n33; te[ 14 ] = n34; - te[ 3 ] = n41; te[ 7 ] = n42; te[ 11 ] = n43; te[ 15 ] = n44; - - return this; - - } - - identity() { - - this.set( - - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1 - - ); - - return this; - - } - - clone() { - - return new Matrix4().fromArray( this.elements ); - - } - - copy( m ) { - - const te = this.elements; - const me = m.elements; - - te[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ]; te[ 3 ] = me[ 3 ]; - te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ]; te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ]; - te[ 8 ] = me[ 8 ]; te[ 9 ] = me[ 9 ]; te[ 10 ] = me[ 10 ]; te[ 11 ] = me[ 11 ]; - te[ 12 ] = me[ 12 ]; te[ 13 ] = me[ 13 ]; te[ 14 ] = me[ 14 ]; te[ 15 ] = me[ 15 ]; - - return this; - - } - - copyPosition( m ) { - - const te = this.elements, me = m.elements; - - te[ 12 ] = me[ 12 ]; - te[ 13 ] = me[ 13 ]; - te[ 14 ] = me[ 14 ]; - - return this; - - } - - setFromMatrix3( m ) { - - const me = m.elements; - - this.set( - - me[ 0 ], me[ 3 ], me[ 6 ], 0, - me[ 1 ], me[ 4 ], me[ 7 ], 0, - me[ 2 ], me[ 5 ], me[ 8 ], 0, - 0, 0, 0, 1 - - ); - - return this; - - } - - extractBasis( xAxis, yAxis, zAxis ) { - - xAxis.setFromMatrixColumn( this, 0 ); - yAxis.setFromMatrixColumn( this, 1 ); - zAxis.setFromMatrixColumn( this, 2 ); - - return this; - - } - - makeBasis( xAxis, yAxis, zAxis ) { - - this.set( - xAxis.x, yAxis.x, zAxis.x, 0, - xAxis.y, yAxis.y, zAxis.y, 0, - xAxis.z, yAxis.z, zAxis.z, 0, - 0, 0, 0, 1 - ); - - return this; - - } - - extractRotation( m ) { - - // this method does not support reflection matrices - - const te = this.elements; - const me = m.elements; - - const scaleX = 1 / _v1$5.setFromMatrixColumn( m, 0 ).length(); - const scaleY = 1 / _v1$5.setFromMatrixColumn( m, 1 ).length(); - const scaleZ = 1 / _v1$5.setFromMatrixColumn( m, 2 ).length(); - - te[ 0 ] = me[ 0 ] * scaleX; - te[ 1 ] = me[ 1 ] * scaleX; - te[ 2 ] = me[ 2 ] * scaleX; - te[ 3 ] = 0; - - te[ 4 ] = me[ 4 ] * scaleY; - te[ 5 ] = me[ 5 ] * scaleY; - te[ 6 ] = me[ 6 ] * scaleY; - te[ 7 ] = 0; - - te[ 8 ] = me[ 8 ] * scaleZ; - te[ 9 ] = me[ 9 ] * scaleZ; - te[ 10 ] = me[ 10 ] * scaleZ; - te[ 11 ] = 0; - - te[ 12 ] = 0; - te[ 13 ] = 0; - te[ 14 ] = 0; - te[ 15 ] = 1; - - return this; - - } - - makeRotationFromEuler( euler ) { - - const te = this.elements; - - const x = euler.x, y = euler.y, z = euler.z; - const a = Math.cos( x ), b = Math.sin( x ); - const c = Math.cos( y ), d = Math.sin( y ); - const e = Math.cos( z ), f = Math.sin( z ); - - if ( euler.order === 'XYZ' ) { - - const ae = a * e, af = a * f, be = b * e, bf = b * f; - - te[ 0 ] = c * e; - te[ 4 ] = - c * f; - te[ 8 ] = d; - - te[ 1 ] = af + be * d; - te[ 5 ] = ae - bf * d; - te[ 9 ] = - b * c; - - te[ 2 ] = bf - ae * d; - te[ 6 ] = be + af * d; - te[ 10 ] = a * c; - - } else if ( euler.order === 'YXZ' ) { - - const ce = c * e, cf = c * f, de = d * e, df = d * f; - - te[ 0 ] = ce + df * b; - te[ 4 ] = de * b - cf; - te[ 8 ] = a * d; - - te[ 1 ] = a * f; - te[ 5 ] = a * e; - te[ 9 ] = - b; - - te[ 2 ] = cf * b - de; - te[ 6 ] = df + ce * b; - te[ 10 ] = a * c; - - } else if ( euler.order === 'ZXY' ) { - - const ce = c * e, cf = c * f, de = d * e, df = d * f; - - te[ 0 ] = ce - df * b; - te[ 4 ] = - a * f; - te[ 8 ] = de + cf * b; - - te[ 1 ] = cf + de * b; - te[ 5 ] = a * e; - te[ 9 ] = df - ce * b; - - te[ 2 ] = - a * d; - te[ 6 ] = b; - te[ 10 ] = a * c; - - } else if ( euler.order === 'ZYX' ) { - - const ae = a * e, af = a * f, be = b * e, bf = b * f; - - te[ 0 ] = c * e; - te[ 4 ] = be * d - af; - te[ 8 ] = ae * d + bf; - - te[ 1 ] = c * f; - te[ 5 ] = bf * d + ae; - te[ 9 ] = af * d - be; - - te[ 2 ] = - d; - te[ 6 ] = b * c; - te[ 10 ] = a * c; - - } else if ( euler.order === 'YZX' ) { - - const ac = a * c, ad = a * d, bc = b * c, bd = b * d; - - te[ 0 ] = c * e; - te[ 4 ] = bd - ac * f; - te[ 8 ] = bc * f + ad; - - te[ 1 ] = f; - te[ 5 ] = a * e; - te[ 9 ] = - b * e; - - te[ 2 ] = - d * e; - te[ 6 ] = ad * f + bc; - te[ 10 ] = ac - bd * f; - - } else if ( euler.order === 'XZY' ) { - - const ac = a * c, ad = a * d, bc = b * c, bd = b * d; - - te[ 0 ] = c * e; - te[ 4 ] = - f; - te[ 8 ] = d * e; - - te[ 1 ] = ac * f + bd; - te[ 5 ] = a * e; - te[ 9 ] = ad * f - bc; - - te[ 2 ] = bc * f - ad; - te[ 6 ] = b * e; - te[ 10 ] = bd * f + ac; - - } - - // bottom row - te[ 3 ] = 0; - te[ 7 ] = 0; - te[ 11 ] = 0; - - // last column - te[ 12 ] = 0; - te[ 13 ] = 0; - te[ 14 ] = 0; - te[ 15 ] = 1; - - return this; - - } - - makeRotationFromQuaternion( q ) { - - return this.compose( _zero, q, _one ); - - } - - lookAt( eye, target, up ) { - - const te = this.elements; - - _z.subVectors( eye, target ); - - if ( _z.lengthSq() === 0 ) { - - // eye and target are in the same position - - _z.z = 1; - - } - - _z.normalize(); - _x.crossVectors( up, _z ); - - if ( _x.lengthSq() === 0 ) { - - // up and z are parallel - - if ( Math.abs( up.z ) === 1 ) { - - _z.x += 0.0001; - - } else { - - _z.z += 0.0001; - - } - - _z.normalize(); - _x.crossVectors( up, _z ); - - } - - _x.normalize(); - _y.crossVectors( _z, _x ); - - te[ 0 ] = _x.x; te[ 4 ] = _y.x; te[ 8 ] = _z.x; - te[ 1 ] = _x.y; te[ 5 ] = _y.y; te[ 9 ] = _z.y; - te[ 2 ] = _x.z; te[ 6 ] = _y.z; te[ 10 ] = _z.z; - - return this; - - } - - multiply( m ) { - - return this.multiplyMatrices( this, m ); - - } - - premultiply( m ) { - - return this.multiplyMatrices( m, this ); - - } - - multiplyMatrices( a, b ) { - - const ae = a.elements; - const be = b.elements; - const te = this.elements; - - const a11 = ae[ 0 ], a12 = ae[ 4 ], a13 = ae[ 8 ], a14 = ae[ 12 ]; - const a21 = ae[ 1 ], a22 = ae[ 5 ], a23 = ae[ 9 ], a24 = ae[ 13 ]; - const a31 = ae[ 2 ], a32 = ae[ 6 ], a33 = ae[ 10 ], a34 = ae[ 14 ]; - const a41 = ae[ 3 ], a42 = ae[ 7 ], a43 = ae[ 11 ], a44 = ae[ 15 ]; - - const b11 = be[ 0 ], b12 = be[ 4 ], b13 = be[ 8 ], b14 = be[ 12 ]; - const b21 = be[ 1 ], b22 = be[ 5 ], b23 = be[ 9 ], b24 = be[ 13 ]; - const b31 = be[ 2 ], b32 = be[ 6 ], b33 = be[ 10 ], b34 = be[ 14 ]; - const b41 = be[ 3 ], b42 = be[ 7 ], b43 = be[ 11 ], b44 = be[ 15 ]; - - te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41; - te[ 4 ] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42; - te[ 8 ] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43; - te[ 12 ] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44; - - te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41; - te[ 5 ] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42; - te[ 9 ] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43; - te[ 13 ] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44; - - te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41; - te[ 6 ] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42; - te[ 10 ] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43; - te[ 14 ] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44; - - te[ 3 ] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41; - te[ 7 ] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42; - te[ 11 ] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43; - te[ 15 ] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44; - - return this; - - } - - multiplyScalar( s ) { - - const te = this.elements; - - te[ 0 ] *= s; te[ 4 ] *= s; te[ 8 ] *= s; te[ 12 ] *= s; - te[ 1 ] *= s; te[ 5 ] *= s; te[ 9 ] *= s; te[ 13 ] *= s; - te[ 2 ] *= s; te[ 6 ] *= s; te[ 10 ] *= s; te[ 14 ] *= s; - te[ 3 ] *= s; te[ 7 ] *= s; te[ 11 ] *= s; te[ 15 ] *= s; - - return this; - - } - - determinant() { - - const te = this.elements; - - const n11 = te[ 0 ], n12 = te[ 4 ], n13 = te[ 8 ], n14 = te[ 12 ]; - const n21 = te[ 1 ], n22 = te[ 5 ], n23 = te[ 9 ], n24 = te[ 13 ]; - const n31 = te[ 2 ], n32 = te[ 6 ], n33 = te[ 10 ], n34 = te[ 14 ]; - const n41 = te[ 3 ], n42 = te[ 7 ], n43 = te[ 11 ], n44 = te[ 15 ]; - - //TODO: make this more efficient - //( based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm ) - - return ( - n41 * ( - + n14 * n23 * n32 - - n13 * n24 * n32 - - n14 * n22 * n33 - + n12 * n24 * n33 - + n13 * n22 * n34 - - n12 * n23 * n34 - ) + - n42 * ( - + n11 * n23 * n34 - - n11 * n24 * n33 - + n14 * n21 * n33 - - n13 * n21 * n34 - + n13 * n24 * n31 - - n14 * n23 * n31 - ) + - n43 * ( - + n11 * n24 * n32 - - n11 * n22 * n34 - - n14 * n21 * n32 - + n12 * n21 * n34 - + n14 * n22 * n31 - - n12 * n24 * n31 - ) + - n44 * ( - - n13 * n22 * n31 - - n11 * n23 * n32 - + n11 * n22 * n33 - + n13 * n21 * n32 - - n12 * n21 * n33 - + n12 * n23 * n31 - ) - - ); - - } - - transpose() { - - const te = this.elements; - let tmp; - - tmp = te[ 1 ]; te[ 1 ] = te[ 4 ]; te[ 4 ] = tmp; - tmp = te[ 2 ]; te[ 2 ] = te[ 8 ]; te[ 8 ] = tmp; - tmp = te[ 6 ]; te[ 6 ] = te[ 9 ]; te[ 9 ] = tmp; - - tmp = te[ 3 ]; te[ 3 ] = te[ 12 ]; te[ 12 ] = tmp; - tmp = te[ 7 ]; te[ 7 ] = te[ 13 ]; te[ 13 ] = tmp; - tmp = te[ 11 ]; te[ 11 ] = te[ 14 ]; te[ 14 ] = tmp; - - return this; - - } - - setPosition( x, y, z ) { - - const te = this.elements; - - if ( x.isVector3 ) { - - te[ 12 ] = x.x; - te[ 13 ] = x.y; - te[ 14 ] = x.z; - - } else { - - te[ 12 ] = x; - te[ 13 ] = y; - te[ 14 ] = z; - - } - - return this; - - } - - invert() { - - // based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm - const te = this.elements, - - n11 = te[ 0 ], n21 = te[ 1 ], n31 = te[ 2 ], n41 = te[ 3 ], - n12 = te[ 4 ], n22 = te[ 5 ], n32 = te[ 6 ], n42 = te[ 7 ], - n13 = te[ 8 ], n23 = te[ 9 ], n33 = te[ 10 ], n43 = te[ 11 ], - n14 = te[ 12 ], n24 = te[ 13 ], n34 = te[ 14 ], n44 = te[ 15 ], - - t11 = n23 * n34 * n42 - n24 * n33 * n42 + n24 * n32 * n43 - n22 * n34 * n43 - n23 * n32 * n44 + n22 * n33 * n44, - t12 = n14 * n33 * n42 - n13 * n34 * n42 - n14 * n32 * n43 + n12 * n34 * n43 + n13 * n32 * n44 - n12 * n33 * n44, - t13 = n13 * n24 * n42 - n14 * n23 * n42 + n14 * n22 * n43 - n12 * n24 * n43 - n13 * n22 * n44 + n12 * n23 * n44, - t14 = n14 * n23 * n32 - n13 * n24 * n32 - n14 * n22 * n33 + n12 * n24 * n33 + n13 * n22 * n34 - n12 * n23 * n34; - - const det = n11 * t11 + n21 * t12 + n31 * t13 + n41 * t14; - - if ( det === 0 ) return this.set( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ); - - const detInv = 1 / det; - - te[ 0 ] = t11 * detInv; - te[ 1 ] = ( n24 * n33 * n41 - n23 * n34 * n41 - n24 * n31 * n43 + n21 * n34 * n43 + n23 * n31 * n44 - n21 * n33 * n44 ) * detInv; - te[ 2 ] = ( n22 * n34 * n41 - n24 * n32 * n41 + n24 * n31 * n42 - n21 * n34 * n42 - n22 * n31 * n44 + n21 * n32 * n44 ) * detInv; - te[ 3 ] = ( n23 * n32 * n41 - n22 * n33 * n41 - n23 * n31 * n42 + n21 * n33 * n42 + n22 * n31 * n43 - n21 * n32 * n43 ) * detInv; - - te[ 4 ] = t12 * detInv; - te[ 5 ] = ( n13 * n34 * n41 - n14 * n33 * n41 + n14 * n31 * n43 - n11 * n34 * n43 - n13 * n31 * n44 + n11 * n33 * n44 ) * detInv; - te[ 6 ] = ( n14 * n32 * n41 - n12 * n34 * n41 - n14 * n31 * n42 + n11 * n34 * n42 + n12 * n31 * n44 - n11 * n32 * n44 ) * detInv; - te[ 7 ] = ( n12 * n33 * n41 - n13 * n32 * n41 + n13 * n31 * n42 - n11 * n33 * n42 - n12 * n31 * n43 + n11 * n32 * n43 ) * detInv; - - te[ 8 ] = t13 * detInv; - te[ 9 ] = ( n14 * n23 * n41 - n13 * n24 * n41 - n14 * n21 * n43 + n11 * n24 * n43 + n13 * n21 * n44 - n11 * n23 * n44 ) * detInv; - te[ 10 ] = ( n12 * n24 * n41 - n14 * n22 * n41 + n14 * n21 * n42 - n11 * n24 * n42 - n12 * n21 * n44 + n11 * n22 * n44 ) * detInv; - te[ 11 ] = ( n13 * n22 * n41 - n12 * n23 * n41 - n13 * n21 * n42 + n11 * n23 * n42 + n12 * n21 * n43 - n11 * n22 * n43 ) * detInv; - - te[ 12 ] = t14 * detInv; - te[ 13 ] = ( n13 * n24 * n31 - n14 * n23 * n31 + n14 * n21 * n33 - n11 * n24 * n33 - n13 * n21 * n34 + n11 * n23 * n34 ) * detInv; - te[ 14 ] = ( n14 * n22 * n31 - n12 * n24 * n31 - n14 * n21 * n32 + n11 * n24 * n32 + n12 * n21 * n34 - n11 * n22 * n34 ) * detInv; - te[ 15 ] = ( n12 * n23 * n31 - n13 * n22 * n31 + n13 * n21 * n32 - n11 * n23 * n32 - n12 * n21 * n33 + n11 * n22 * n33 ) * detInv; - - return this; - - } - - scale( v ) { - - const te = this.elements; - const x = v.x, y = v.y, z = v.z; - - te[ 0 ] *= x; te[ 4 ] *= y; te[ 8 ] *= z; - te[ 1 ] *= x; te[ 5 ] *= y; te[ 9 ] *= z; - te[ 2 ] *= x; te[ 6 ] *= y; te[ 10 ] *= z; - te[ 3 ] *= x; te[ 7 ] *= y; te[ 11 ] *= z; - - return this; - - } - - getMaxScaleOnAxis() { - - const te = this.elements; - - const scaleXSq = te[ 0 ] * te[ 0 ] + te[ 1 ] * te[ 1 ] + te[ 2 ] * te[ 2 ]; - const scaleYSq = te[ 4 ] * te[ 4 ] + te[ 5 ] * te[ 5 ] + te[ 6 ] * te[ 6 ]; - const scaleZSq = te[ 8 ] * te[ 8 ] + te[ 9 ] * te[ 9 ] + te[ 10 ] * te[ 10 ]; - - return Math.sqrt( Math.max( scaleXSq, scaleYSq, scaleZSq ) ); - - } - - makeTranslation( x, y, z ) { - - if ( x.isVector3 ) { - - this.set( - - 1, 0, 0, x.x, - 0, 1, 0, x.y, - 0, 0, 1, x.z, - 0, 0, 0, 1 - - ); - - } else { - - this.set( - - 1, 0, 0, x, - 0, 1, 0, y, - 0, 0, 1, z, - 0, 0, 0, 1 - - ); - - } - - return this; - - } - - makeRotationX( theta ) { - - const c = Math.cos( theta ), s = Math.sin( theta ); - - this.set( - - 1, 0, 0, 0, - 0, c, - s, 0, - 0, s, c, 0, - 0, 0, 0, 1 - - ); - - return this; - - } - - makeRotationY( theta ) { - - const c = Math.cos( theta ), s = Math.sin( theta ); - - this.set( - - c, 0, s, 0, - 0, 1, 0, 0, - - s, 0, c, 0, - 0, 0, 0, 1 - - ); - - return this; - - } - - makeRotationZ( theta ) { - - const c = Math.cos( theta ), s = Math.sin( theta ); - - this.set( - - c, - s, 0, 0, - s, c, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1 - - ); - - return this; - - } - - makeRotationAxis( axis, angle ) { - - // Based on http://www.gamedev.net/reference/articles/article1199.asp - - const c = Math.cos( angle ); - const s = Math.sin( angle ); - const t = 1 - c; - const x = axis.x, y = axis.y, z = axis.z; - const tx = t * x, ty = t * y; - - this.set( - - tx * x + c, tx * y - s * z, tx * z + s * y, 0, - tx * y + s * z, ty * y + c, ty * z - s * x, 0, - tx * z - s * y, ty * z + s * x, t * z * z + c, 0, - 0, 0, 0, 1 - - ); - - return this; - - } - - makeScale( x, y, z ) { - - this.set( - - x, 0, 0, 0, - 0, y, 0, 0, - 0, 0, z, 0, - 0, 0, 0, 1 - - ); - - return this; - - } - - makeShear( xy, xz, yx, yz, zx, zy ) { - - this.set( - - 1, yx, zx, 0, - xy, 1, zy, 0, - xz, yz, 1, 0, - 0, 0, 0, 1 - - ); - - return this; - - } - - compose( position, quaternion, scale ) { - - const te = this.elements; - - const x = quaternion._x, y = quaternion._y, z = quaternion._z, w = quaternion._w; - const x2 = x + x, y2 = y + y, z2 = z + z; - const xx = x * x2, xy = x * y2, xz = x * z2; - const yy = y * y2, yz = y * z2, zz = z * z2; - const wx = w * x2, wy = w * y2, wz = w * z2; - - const sx = scale.x, sy = scale.y, sz = scale.z; - - te[ 0 ] = ( 1 - ( yy + zz ) ) * sx; - te[ 1 ] = ( xy + wz ) * sx; - te[ 2 ] = ( xz - wy ) * sx; - te[ 3 ] = 0; - - te[ 4 ] = ( xy - wz ) * sy; - te[ 5 ] = ( 1 - ( xx + zz ) ) * sy; - te[ 6 ] = ( yz + wx ) * sy; - te[ 7 ] = 0; - - te[ 8 ] = ( xz + wy ) * sz; - te[ 9 ] = ( yz - wx ) * sz; - te[ 10 ] = ( 1 - ( xx + yy ) ) * sz; - te[ 11 ] = 0; - - te[ 12 ] = position.x; - te[ 13 ] = position.y; - te[ 14 ] = position.z; - te[ 15 ] = 1; - - return this; - - } - - decompose( position, quaternion, scale ) { - - const te = this.elements; - - let sx = _v1$5.set( te[ 0 ], te[ 1 ], te[ 2 ] ).length(); - const sy = _v1$5.set( te[ 4 ], te[ 5 ], te[ 6 ] ).length(); - const sz = _v1$5.set( te[ 8 ], te[ 9 ], te[ 10 ] ).length(); - - // if determine is negative, we need to invert one scale - const det = this.determinant(); - if ( det < 0 ) sx = - sx; - - position.x = te[ 12 ]; - position.y = te[ 13 ]; - position.z = te[ 14 ]; - - // scale the rotation part - _m1$2.copy( this ); - - const invSX = 1 / sx; - const invSY = 1 / sy; - const invSZ = 1 / sz; - - _m1$2.elements[ 0 ] *= invSX; - _m1$2.elements[ 1 ] *= invSX; - _m1$2.elements[ 2 ] *= invSX; - - _m1$2.elements[ 4 ] *= invSY; - _m1$2.elements[ 5 ] *= invSY; - _m1$2.elements[ 6 ] *= invSY; - - _m1$2.elements[ 8 ] *= invSZ; - _m1$2.elements[ 9 ] *= invSZ; - _m1$2.elements[ 10 ] *= invSZ; - - quaternion.setFromRotationMatrix( _m1$2 ); - - scale.x = sx; - scale.y = sy; - scale.z = sz; - - return this; - - } - - makePerspective( left, right, top, bottom, near, far, coordinateSystem = WebGLCoordinateSystem ) { - - const te = this.elements; - const x = 2 * near / ( right - left ); - const y = 2 * near / ( top - bottom ); - - const a = ( right + left ) / ( right - left ); - const b = ( top + bottom ) / ( top - bottom ); - - let c, d; - - if ( coordinateSystem === WebGLCoordinateSystem ) { - - c = - ( far + near ) / ( far - near ); - d = ( - 2 * far * near ) / ( far - near ); - - } else if ( coordinateSystem === WebGPUCoordinateSystem ) { - - c = - far / ( far - near ); - d = ( - far * near ) / ( far - near ); - - } else { - - throw new Error( 'THREE.Matrix4.makePerspective(): Invalid coordinate system: ' + coordinateSystem ); - - } - - te[ 0 ] = x; te[ 4 ] = 0; te[ 8 ] = a; te[ 12 ] = 0; - te[ 1 ] = 0; te[ 5 ] = y; te[ 9 ] = b; te[ 13 ] = 0; - te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = c; te[ 14 ] = d; - te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = - 1; te[ 15 ] = 0; - - return this; - - } - - makeOrthographic( left, right, top, bottom, near, far, coordinateSystem = WebGLCoordinateSystem ) { - - const te = this.elements; - const w = 1.0 / ( right - left ); - const h = 1.0 / ( top - bottom ); - const p = 1.0 / ( far - near ); - - const x = ( right + left ) * w; - const y = ( top + bottom ) * h; - - let z, zInv; - - if ( coordinateSystem === WebGLCoordinateSystem ) { - - z = ( far + near ) * p; - zInv = - 2 * p; - - } else if ( coordinateSystem === WebGPUCoordinateSystem ) { - - z = near * p; - zInv = - 1 * p; - - } else { - - throw new Error( 'THREE.Matrix4.makeOrthographic(): Invalid coordinate system: ' + coordinateSystem ); - - } - - te[ 0 ] = 2 * w; te[ 4 ] = 0; te[ 8 ] = 0; te[ 12 ] = - x; - te[ 1 ] = 0; te[ 5 ] = 2 * h; te[ 9 ] = 0; te[ 13 ] = - y; - te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = zInv; te[ 14 ] = - z; - te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = 0; te[ 15 ] = 1; - - return this; - - } - - equals( matrix ) { - - const te = this.elements; - const me = matrix.elements; - - for ( let i = 0; i < 16; i ++ ) { - - if ( te[ i ] !== me[ i ] ) return false; - - } - - return true; - - } - - fromArray( array, offset = 0 ) { - - for ( let i = 0; i < 16; i ++ ) { - - this.elements[ i ] = array[ i + offset ]; - - } - - return this; - - } - - toArray( array = [], offset = 0 ) { - - const te = this.elements; - - array[ offset ] = te[ 0 ]; - array[ offset + 1 ] = te[ 1 ]; - array[ offset + 2 ] = te[ 2 ]; - array[ offset + 3 ] = te[ 3 ]; - - array[ offset + 4 ] = te[ 4 ]; - array[ offset + 5 ] = te[ 5 ]; - array[ offset + 6 ] = te[ 6 ]; - array[ offset + 7 ] = te[ 7 ]; - - array[ offset + 8 ] = te[ 8 ]; - array[ offset + 9 ] = te[ 9 ]; - array[ offset + 10 ] = te[ 10 ]; - array[ offset + 11 ] = te[ 11 ]; - - array[ offset + 12 ] = te[ 12 ]; - array[ offset + 13 ] = te[ 13 ]; - array[ offset + 14 ] = te[ 14 ]; - array[ offset + 15 ] = te[ 15 ]; - - return array; - - } - -} - -const _v1$5 = /*@__PURE__*/ new Vector3(); -const _m1$2 = /*@__PURE__*/ new Matrix4(); -const _zero = /*@__PURE__*/ new Vector3( 0, 0, 0 ); -const _one = /*@__PURE__*/ new Vector3( 1, 1, 1 ); -const _x = /*@__PURE__*/ new Vector3(); -const _y = /*@__PURE__*/ new Vector3(); -const _z = /*@__PURE__*/ new Vector3(); - -const _matrix$1 = /*@__PURE__*/ new Matrix4(); -const _quaternion$3 = /*@__PURE__*/ new Quaternion(); - -class Euler { - - constructor( x = 0, y = 0, z = 0, order = Euler.DEFAULT_ORDER ) { - - this.isEuler = true; - - this._x = x; - this._y = y; - this._z = z; - this._order = order; - - } - - get x() { - - return this._x; - - } - - set x( value ) { - - this._x = value; - this._onChangeCallback(); - - } - - get y() { - - return this._y; - - } - - set y( value ) { - - this._y = value; - this._onChangeCallback(); - - } - - get z() { - - return this._z; - - } - - set z( value ) { - - this._z = value; - this._onChangeCallback(); - - } - - get order() { - - return this._order; - - } - - set order( value ) { - - this._order = value; - this._onChangeCallback(); - - } - - set( x, y, z, order = this._order ) { - - this._x = x; - this._y = y; - this._z = z; - this._order = order; - - this._onChangeCallback(); - - return this; - - } - - clone() { - - return new this.constructor( this._x, this._y, this._z, this._order ); - - } - - copy( euler ) { - - this._x = euler._x; - this._y = euler._y; - this._z = euler._z; - this._order = euler._order; - - this._onChangeCallback(); - - return this; - - } - - setFromRotationMatrix( m, order = this._order, update = true ) { - - // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) - - const te = m.elements; - const m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ]; - const m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ]; - const m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ]; - - switch ( order ) { - - case 'XYZ': - - this._y = Math.asin( clamp( m13, - 1, 1 ) ); - - if ( Math.abs( m13 ) < 0.9999999 ) { - - this._x = Math.atan2( - m23, m33 ); - this._z = Math.atan2( - m12, m11 ); - - } else { - - this._x = Math.atan2( m32, m22 ); - this._z = 0; - - } - - break; - - case 'YXZ': - - this._x = Math.asin( - clamp( m23, - 1, 1 ) ); - - if ( Math.abs( m23 ) < 0.9999999 ) { - - this._y = Math.atan2( m13, m33 ); - this._z = Math.atan2( m21, m22 ); - - } else { - - this._y = Math.atan2( - m31, m11 ); - this._z = 0; - - } - - break; - - case 'ZXY': - - this._x = Math.asin( clamp( m32, - 1, 1 ) ); - - if ( Math.abs( m32 ) < 0.9999999 ) { - - this._y = Math.atan2( - m31, m33 ); - this._z = Math.atan2( - m12, m22 ); - - } else { - - this._y = 0; - this._z = Math.atan2( m21, m11 ); - - } - - break; - - case 'ZYX': - - this._y = Math.asin( - clamp( m31, - 1, 1 ) ); - - if ( Math.abs( m31 ) < 0.9999999 ) { - - this._x = Math.atan2( m32, m33 ); - this._z = Math.atan2( m21, m11 ); - - } else { - - this._x = 0; - this._z = Math.atan2( - m12, m22 ); - - } - - break; - - case 'YZX': - - this._z = Math.asin( clamp( m21, - 1, 1 ) ); - - if ( Math.abs( m21 ) < 0.9999999 ) { - - this._x = Math.atan2( - m23, m22 ); - this._y = Math.atan2( - m31, m11 ); - - } else { - - this._x = 0; - this._y = Math.atan2( m13, m33 ); - - } - - break; - - case 'XZY': - - this._z = Math.asin( - clamp( m12, - 1, 1 ) ); - - if ( Math.abs( m12 ) < 0.9999999 ) { - - this._x = Math.atan2( m32, m22 ); - this._y = Math.atan2( m13, m11 ); - - } else { - - this._x = Math.atan2( - m23, m33 ); - this._y = 0; - - } - - break; - - default: - - console.warn( 'THREE.Euler: .setFromRotationMatrix() encountered an unknown order: ' + order ); - - } - - this._order = order; - - if ( update === true ) this._onChangeCallback(); - - return this; - - } - - setFromQuaternion( q, order, update ) { - - _matrix$1.makeRotationFromQuaternion( q ); - - return this.setFromRotationMatrix( _matrix$1, order, update ); - - } - - setFromVector3( v, order = this._order ) { - - return this.set( v.x, v.y, v.z, order ); - - } - - reorder( newOrder ) { - - // WARNING: this discards revolution information -bhouston - - _quaternion$3.setFromEuler( this ); - - return this.setFromQuaternion( _quaternion$3, newOrder ); - - } - - equals( euler ) { - - return ( euler._x === this._x ) && ( euler._y === this._y ) && ( euler._z === this._z ) && ( euler._order === this._order ); - - } - - fromArray( array ) { - - this._x = array[ 0 ]; - this._y = array[ 1 ]; - this._z = array[ 2 ]; - if ( array[ 3 ] !== undefined ) this._order = array[ 3 ]; - - this._onChangeCallback(); - - return this; - - } - - toArray( array = [], offset = 0 ) { - - array[ offset ] = this._x; - array[ offset + 1 ] = this._y; - array[ offset + 2 ] = this._z; - array[ offset + 3 ] = this._order; - - return array; - - } - - _onChange( callback ) { - - this._onChangeCallback = callback; - - return this; - - } - - _onChangeCallback() {} - - *[ Symbol.iterator ]() { - - yield this._x; - yield this._y; - yield this._z; - yield this._order; - - } - -} - -Euler.DEFAULT_ORDER = 'XYZ'; - -class Layers { - - constructor() { - - this.mask = 1 | 0; - - } - - set( channel ) { - - this.mask = ( 1 << channel | 0 ) >>> 0; - - } - - enable( channel ) { - - this.mask |= 1 << channel | 0; - - } - - enableAll() { - - this.mask = 0xffffffff | 0; - - } - - toggle( channel ) { - - this.mask ^= 1 << channel | 0; - - } - - disable( channel ) { - - this.mask &= ~ ( 1 << channel | 0 ); - - } - - disableAll() { - - this.mask = 0; - - } - - test( layers ) { - - return ( this.mask & layers.mask ) !== 0; - - } - - isEnabled( channel ) { - - return ( this.mask & ( 1 << channel | 0 ) ) !== 0; - - } - -} - -let _object3DId = 0; - -const _v1$4 = /*@__PURE__*/ new Vector3(); -const _q1 = /*@__PURE__*/ new Quaternion(); -const _m1$1 = /*@__PURE__*/ new Matrix4(); -const _target = /*@__PURE__*/ new Vector3(); - -const _position$3 = /*@__PURE__*/ new Vector3(); -const _scale$2 = /*@__PURE__*/ new Vector3(); -const _quaternion$2 = /*@__PURE__*/ new Quaternion(); - -const _xAxis = /*@__PURE__*/ new Vector3( 1, 0, 0 ); -const _yAxis = /*@__PURE__*/ new Vector3( 0, 1, 0 ); -const _zAxis = /*@__PURE__*/ new Vector3( 0, 0, 1 ); - -const _addedEvent = { type: 'added' }; -const _removedEvent = { type: 'removed' }; - -class Object3D extends EventDispatcher { - - constructor() { - - super(); - - this.isObject3D = true; - - Object.defineProperty( this, 'id', { value: _object3DId ++ } ); - - this.uuid = generateUUID(); - - this.name = ''; - this.type = 'Object3D'; - - this.parent = null; - this.children = []; - - this.up = Object3D.DEFAULT_UP.clone(); - - const position = new Vector3(); - const rotation = new Euler(); - const quaternion = new Quaternion(); - const scale = new Vector3( 1, 1, 1 ); - - function onRotationChange() { - - quaternion.setFromEuler( rotation, false ); - - } - - function onQuaternionChange() { - - rotation.setFromQuaternion( quaternion, undefined, false ); - - } - - rotation._onChange( onRotationChange ); - quaternion._onChange( onQuaternionChange ); - - Object.defineProperties( this, { - position: { - configurable: true, - enumerable: true, - value: position - }, - rotation: { - configurable: true, - enumerable: true, - value: rotation - }, - quaternion: { - configurable: true, - enumerable: true, - value: quaternion - }, - scale: { - configurable: true, - enumerable: true, - value: scale - }, - modelViewMatrix: { - value: new Matrix4() - }, - normalMatrix: { - value: new Matrix3() - } - } ); - - this.matrix = new Matrix4(); - this.matrixWorld = new Matrix4(); - - this.matrixAutoUpdate = Object3D.DEFAULT_MATRIX_AUTO_UPDATE; - - this.matrixWorldAutoUpdate = Object3D.DEFAULT_MATRIX_WORLD_AUTO_UPDATE; // checked by the renderer - this.matrixWorldNeedsUpdate = false; - - this.layers = new Layers(); - this.visible = true; - - this.castShadow = false; - this.receiveShadow = false; - - this.frustumCulled = true; - this.renderOrder = 0; - - this.animations = []; - - this.userData = {}; - - } - - onBeforeShadow( /* renderer, object, camera, shadowCamera, geometry, depthMaterial, group */ ) {} - - onAfterShadow( /* renderer, object, camera, shadowCamera, geometry, depthMaterial, group */ ) {} - - onBeforeRender( /* renderer, scene, camera, geometry, material, group */ ) {} - - onAfterRender( /* renderer, scene, camera, geometry, material, group */ ) {} - - applyMatrix4( matrix ) { - - if ( this.matrixAutoUpdate ) this.updateMatrix(); - - this.matrix.premultiply( matrix ); - - this.matrix.decompose( this.position, this.quaternion, this.scale ); - - } - - applyQuaternion( q ) { - - this.quaternion.premultiply( q ); - - return this; - - } - - setRotationFromAxisAngle( axis, angle ) { - - // assumes axis is normalized - - this.quaternion.setFromAxisAngle( axis, angle ); - - } - - setRotationFromEuler( euler ) { - - this.quaternion.setFromEuler( euler, true ); - - } - - setRotationFromMatrix( m ) { - - // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) - - this.quaternion.setFromRotationMatrix( m ); - - } - - setRotationFromQuaternion( q ) { - - // assumes q is normalized - - this.quaternion.copy( q ); - - } - - rotateOnAxis( axis, angle ) { - - // rotate object on axis in object space - // axis is assumed to be normalized - - _q1.setFromAxisAngle( axis, angle ); - - this.quaternion.multiply( _q1 ); - - return this; - - } - - rotateOnWorldAxis( axis, angle ) { - - // rotate object on axis in world space - // axis is assumed to be normalized - // method assumes no rotated parent - - _q1.setFromAxisAngle( axis, angle ); - - this.quaternion.premultiply( _q1 ); - - return this; - - } - - rotateX( angle ) { - - return this.rotateOnAxis( _xAxis, angle ); - - } - - rotateY( angle ) { - - return this.rotateOnAxis( _yAxis, angle ); - - } - - rotateZ( angle ) { - - return this.rotateOnAxis( _zAxis, angle ); - - } - - translateOnAxis( axis, distance ) { - - // translate object by distance along axis in object space - // axis is assumed to be normalized - - _v1$4.copy( axis ).applyQuaternion( this.quaternion ); - - this.position.add( _v1$4.multiplyScalar( distance ) ); - - return this; - - } - - translateX( distance ) { - - return this.translateOnAxis( _xAxis, distance ); - - } - - translateY( distance ) { - - return this.translateOnAxis( _yAxis, distance ); - - } - - translateZ( distance ) { - - return this.translateOnAxis( _zAxis, distance ); - - } - - localToWorld( vector ) { - - this.updateWorldMatrix( true, false ); - - return vector.applyMatrix4( this.matrixWorld ); - - } - - worldToLocal( vector ) { - - this.updateWorldMatrix( true, false ); - - return vector.applyMatrix4( _m1$1.copy( this.matrixWorld ).invert() ); - - } - - lookAt( x, y, z ) { - - // This method does not support objects having non-uniformly-scaled parent(s) - - if ( x.isVector3 ) { - - _target.copy( x ); - - } else { - - _target.set( x, y, z ); - - } - - const parent = this.parent; - - this.updateWorldMatrix( true, false ); - - _position$3.setFromMatrixPosition( this.matrixWorld ); - - if ( this.isCamera || this.isLight ) { - - _m1$1.lookAt( _position$3, _target, this.up ); - - } else { - - _m1$1.lookAt( _target, _position$3, this.up ); - - } - - this.quaternion.setFromRotationMatrix( _m1$1 ); - - if ( parent ) { - - _m1$1.extractRotation( parent.matrixWorld ); - _q1.setFromRotationMatrix( _m1$1 ); - this.quaternion.premultiply( _q1.invert() ); - - } - - } - - add( object ) { - - if ( arguments.length > 1 ) { - - for ( let i = 0; i < arguments.length; i ++ ) { - - this.add( arguments[ i ] ); - - } - - return this; - - } - - if ( object === this ) { - - console.error( 'THREE.Object3D.add: object can\'t be added as a child of itself.', object ); - return this; - - } - - if ( object && object.isObject3D ) { - - if ( object.parent !== null ) { - - object.parent.remove( object ); - - } - - object.parent = this; - this.children.push( object ); - - object.dispatchEvent( _addedEvent ); - - } else { - - console.error( 'THREE.Object3D.add: object not an instance of THREE.Object3D.', object ); - - } - - return this; - - } - - remove( object ) { - - if ( arguments.length > 1 ) { - - for ( let i = 0; i < arguments.length; i ++ ) { - - this.remove( arguments[ i ] ); - - } - - return this; - - } - - const index = this.children.indexOf( object ); - - if ( index !== - 1 ) { - - object.parent = null; - this.children.splice( index, 1 ); - - object.dispatchEvent( _removedEvent ); - - } - - return this; - - } - - removeFromParent() { - - const parent = this.parent; - - if ( parent !== null ) { - - parent.remove( this ); - - } - - return this; - - } - - clear() { - - return this.remove( ... this.children ); - - } - - attach( object ) { - - // adds object as a child of this, while maintaining the object's world transform - - // Note: This method does not support scene graphs having non-uniformly-scaled nodes(s) - - this.updateWorldMatrix( true, false ); - - _m1$1.copy( this.matrixWorld ).invert(); - - if ( object.parent !== null ) { - - object.parent.updateWorldMatrix( true, false ); - - _m1$1.multiply( object.parent.matrixWorld ); - - } - - object.applyMatrix4( _m1$1 ); - - this.add( object ); - - object.updateWorldMatrix( false, true ); - - return this; - - } - - getObjectById( id ) { - - return this.getObjectByProperty( 'id', id ); - - } - - getObjectByName( name ) { - - return this.getObjectByProperty( 'name', name ); - - } - - getObjectByProperty( name, value ) { - - if ( this[ name ] === value ) return this; - - for ( let i = 0, l = this.children.length; i < l; i ++ ) { - - const child = this.children[ i ]; - const object = child.getObjectByProperty( name, value ); - - if ( object !== undefined ) { - - return object; - - } - - } - - return undefined; - - } - - getObjectsByProperty( name, value, result = [] ) { - - if ( this[ name ] === value ) result.push( this ); - - const children = this.children; - - for ( let i = 0, l = children.length; i < l; i ++ ) { - - children[ i ].getObjectsByProperty( name, value, result ); - - } - - return result; - - } - - getWorldPosition( target ) { - - this.updateWorldMatrix( true, false ); - - return target.setFromMatrixPosition( this.matrixWorld ); - - } - - getWorldQuaternion( target ) { - - this.updateWorldMatrix( true, false ); - - this.matrixWorld.decompose( _position$3, target, _scale$2 ); - - return target; - - } - - getWorldScale( target ) { - - this.updateWorldMatrix( true, false ); - - this.matrixWorld.decompose( _position$3, _quaternion$2, target ); - - return target; - - } - - getWorldDirection( target ) { - - this.updateWorldMatrix( true, false ); - - const e = this.matrixWorld.elements; - - return target.set( e[ 8 ], e[ 9 ], e[ 10 ] ).normalize(); - - } - - raycast( /* raycaster, intersects */ ) {} - - traverse( callback ) { - - callback( this ); - - const children = this.children; - - for ( let i = 0, l = children.length; i < l; i ++ ) { - - children[ i ].traverse( callback ); - - } - - } - - traverseVisible( callback ) { - - if ( this.visible === false ) return; - - callback( this ); - - const children = this.children; - - for ( let i = 0, l = children.length; i < l; i ++ ) { - - children[ i ].traverseVisible( callback ); - - } - - } - - traverseAncestors( callback ) { - - const parent = this.parent; - - if ( parent !== null ) { - - callback( parent ); - - parent.traverseAncestors( callback ); - - } - - } - - updateMatrix() { - - this.matrix.compose( this.position, this.quaternion, this.scale ); - - this.matrixWorldNeedsUpdate = true; - - } - - updateMatrixWorld( force ) { - - if ( this.matrixAutoUpdate ) this.updateMatrix(); - - if ( this.matrixWorldNeedsUpdate || force ) { - - if ( this.parent === null ) { - - this.matrixWorld.copy( this.matrix ); - - } else { - - this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); - - } - - this.matrixWorldNeedsUpdate = false; - - force = true; - - } - - // update children - - const children = this.children; - - for ( let i = 0, l = children.length; i < l; i ++ ) { - - const child = children[ i ]; - - if ( child.matrixWorldAutoUpdate === true || force === true ) { - - child.updateMatrixWorld( force ); - - } - - } - - } - - updateWorldMatrix( updateParents, updateChildren ) { - - const parent = this.parent; - - if ( updateParents === true && parent !== null && parent.matrixWorldAutoUpdate === true ) { - - parent.updateWorldMatrix( true, false ); - - } - - if ( this.matrixAutoUpdate ) this.updateMatrix(); - - if ( this.parent === null ) { - - this.matrixWorld.copy( this.matrix ); - - } else { - - this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); - - } - - // update children - - if ( updateChildren === true ) { - - const children = this.children; - - for ( let i = 0, l = children.length; i < l; i ++ ) { - - const child = children[ i ]; - - if ( child.matrixWorldAutoUpdate === true ) { - - child.updateWorldMatrix( false, true ); - - } - - } - - } - - } - - toJSON( meta ) { - - // meta is a string when called from JSON.stringify - const isRootObject = ( meta === undefined || typeof meta === 'string' ); - - const output = {}; - - // meta is a hash used to collect geometries, materials. - // not providing it implies that this is the root object - // being serialized. - if ( isRootObject ) { - - // initialize meta obj - meta = { - geometries: {}, - materials: {}, - textures: {}, - images: {}, - shapes: {}, - skeletons: {}, - animations: {}, - nodes: {} - }; - - output.metadata = { - version: 4.6, - type: 'Object', - generator: 'Object3D.toJSON' - }; - - } - - // standard Object3D serialization - - const object = {}; - - object.uuid = this.uuid; - object.type = this.type; - - if ( this.name !== '' ) object.name = this.name; - if ( this.castShadow === true ) object.castShadow = true; - if ( this.receiveShadow === true ) object.receiveShadow = true; - if ( this.visible === false ) object.visible = false; - if ( this.frustumCulled === false ) object.frustumCulled = false; - if ( this.renderOrder !== 0 ) object.renderOrder = this.renderOrder; - if ( Object.keys( this.userData ).length > 0 ) object.userData = this.userData; - - object.layers = this.layers.mask; - object.matrix = this.matrix.toArray(); - object.up = this.up.toArray(); - - if ( this.matrixAutoUpdate === false ) object.matrixAutoUpdate = false; - - // object specific properties - - if ( this.isInstancedMesh ) { - - object.type = 'InstancedMesh'; - object.count = this.count; - object.instanceMatrix = this.instanceMatrix.toJSON(); - if ( this.instanceColor !== null ) object.instanceColor = this.instanceColor.toJSON(); - - } - - if ( this.isBatchedMesh ) { - - object.type = 'BatchedMesh'; - object.perObjectFrustumCulled = this.perObjectFrustumCulled; - object.sortObjects = this.sortObjects; - - object.drawRanges = this._drawRanges; - object.reservedRanges = this._reservedRanges; - - object.visibility = this._visibility; - object.active = this._active; - object.bounds = this._bounds.map( bound => ( { - boxInitialized: bound.boxInitialized, - boxMin: bound.box.min.toArray(), - boxMax: bound.box.max.toArray(), - - sphereInitialized: bound.sphereInitialized, - sphereRadius: bound.sphere.radius, - sphereCenter: bound.sphere.center.toArray() - } ) ); - - object.maxGeometryCount = this._maxGeometryCount; - object.maxVertexCount = this._maxVertexCount; - object.maxIndexCount = this._maxIndexCount; - - object.geometryInitialized = this._geometryInitialized; - object.geometryCount = this._geometryCount; - - object.matricesTexture = this._matricesTexture.toJSON( meta ); - - if ( this.boundingSphere !== null ) { - - object.boundingSphere = { - center: object.boundingSphere.center.toArray(), - radius: object.boundingSphere.radius - }; - - } - - if ( this.boundingBox !== null ) { - - object.boundingBox = { - min: object.boundingBox.min.toArray(), - max: object.boundingBox.max.toArray() - }; - - } - - } - - // - - function serialize( library, element ) { - - if ( library[ element.uuid ] === undefined ) { - - library[ element.uuid ] = element.toJSON( meta ); - - } - - return element.uuid; - - } - - if ( this.isScene ) { - - if ( this.background ) { - - if ( this.background.isColor ) { - - object.background = this.background.toJSON(); - - } else if ( this.background.isTexture ) { - - object.background = this.background.toJSON( meta ).uuid; - - } - - } - - if ( this.environment && this.environment.isTexture && this.environment.isRenderTargetTexture !== true ) { - - object.environment = this.environment.toJSON( meta ).uuid; - - } - - } else if ( this.isMesh || this.isLine || this.isPoints ) { - - object.geometry = serialize( meta.geometries, this.geometry ); - - const parameters = this.geometry.parameters; - - if ( parameters !== undefined && parameters.shapes !== undefined ) { - - const shapes = parameters.shapes; - - if ( Array.isArray( shapes ) ) { - - for ( let i = 0, l = shapes.length; i < l; i ++ ) { - - const shape = shapes[ i ]; - - serialize( meta.shapes, shape ); - - } - - } else { - - serialize( meta.shapes, shapes ); - - } - - } - - } - - if ( this.isSkinnedMesh ) { - - object.bindMode = this.bindMode; - object.bindMatrix = this.bindMatrix.toArray(); - - if ( this.skeleton !== undefined ) { - - serialize( meta.skeletons, this.skeleton ); - - object.skeleton = this.skeleton.uuid; - - } - - } - - if ( this.material !== undefined ) { - - if ( Array.isArray( this.material ) ) { - - const uuids = []; - - for ( let i = 0, l = this.material.length; i < l; i ++ ) { - - uuids.push( serialize( meta.materials, this.material[ i ] ) ); - - } - - object.material = uuids; - - } else { - - object.material = serialize( meta.materials, this.material ); - - } - - } - - // - - if ( this.children.length > 0 ) { - - object.children = []; - - for ( let i = 0; i < this.children.length; i ++ ) { - - object.children.push( this.children[ i ].toJSON( meta ).object ); - - } - - } - - // - - if ( this.animations.length > 0 ) { - - object.animations = []; - - for ( let i = 0; i < this.animations.length; i ++ ) { - - const animation = this.animations[ i ]; - - object.animations.push( serialize( meta.animations, animation ) ); - - } - - } - - if ( isRootObject ) { - - const geometries = extractFromCache( meta.geometries ); - const materials = extractFromCache( meta.materials ); - const textures = extractFromCache( meta.textures ); - const images = extractFromCache( meta.images ); - const shapes = extractFromCache( meta.shapes ); - const skeletons = extractFromCache( meta.skeletons ); - const animations = extractFromCache( meta.animations ); - const nodes = extractFromCache( meta.nodes ); - - if ( geometries.length > 0 ) output.geometries = geometries; - if ( materials.length > 0 ) output.materials = materials; - if ( textures.length > 0 ) output.textures = textures; - if ( images.length > 0 ) output.images = images; - if ( shapes.length > 0 ) output.shapes = shapes; - if ( skeletons.length > 0 ) output.skeletons = skeletons; - if ( animations.length > 0 ) output.animations = animations; - if ( nodes.length > 0 ) output.nodes = nodes; - - } - - output.object = object; - - return output; - - // extract data from the cache hash - // remove metadata on each item - // and return as array - function extractFromCache( cache ) { - - const values = []; - for ( const key in cache ) { - - const data = cache[ key ]; - delete data.metadata; - values.push( data ); - - } - - return values; - - } - - } - - clone( recursive ) { - - return new this.constructor().copy( this, recursive ); - - } - - copy( source, recursive = true ) { - - this.name = source.name; - - this.up.copy( source.up ); - - this.position.copy( source.position ); - this.rotation.order = source.rotation.order; - this.quaternion.copy( source.quaternion ); - this.scale.copy( source.scale ); - - this.matrix.copy( source.matrix ); - this.matrixWorld.copy( source.matrixWorld ); - - this.matrixAutoUpdate = source.matrixAutoUpdate; - - this.matrixWorldAutoUpdate = source.matrixWorldAutoUpdate; - this.matrixWorldNeedsUpdate = source.matrixWorldNeedsUpdate; - - this.layers.mask = source.layers.mask; - this.visible = source.visible; - - this.castShadow = source.castShadow; - this.receiveShadow = source.receiveShadow; - - this.frustumCulled = source.frustumCulled; - this.renderOrder = source.renderOrder; - - this.animations = source.animations.slice(); - - this.userData = JSON.parse( JSON.stringify( source.userData ) ); - - if ( recursive === true ) { - - for ( let i = 0; i < source.children.length; i ++ ) { - - const child = source.children[ i ]; - this.add( child.clone() ); - - } - - } - - return this; - - } - -} - -Object3D.DEFAULT_UP = /*@__PURE__*/ new Vector3( 0, 1, 0 ); -Object3D.DEFAULT_MATRIX_AUTO_UPDATE = true; -Object3D.DEFAULT_MATRIX_WORLD_AUTO_UPDATE = true; - -const _v0$1 = /*@__PURE__*/ new Vector3(); -const _v1$3 = /*@__PURE__*/ new Vector3(); -const _v2$2 = /*@__PURE__*/ new Vector3(); -const _v3$2 = /*@__PURE__*/ new Vector3(); - -const _vab = /*@__PURE__*/ new Vector3(); -const _vac = /*@__PURE__*/ new Vector3(); -const _vbc = /*@__PURE__*/ new Vector3(); -const _vap = /*@__PURE__*/ new Vector3(); -const _vbp = /*@__PURE__*/ new Vector3(); -const _vcp = /*@__PURE__*/ new Vector3(); - -class Triangle { - - constructor( a = new Vector3(), b = new Vector3(), c = new Vector3() ) { - - this.a = a; - this.b = b; - this.c = c; - - } - - static getNormal( a, b, c, target ) { - - target.subVectors( c, b ); - _v0$1.subVectors( a, b ); - target.cross( _v0$1 ); - - const targetLengthSq = target.lengthSq(); - if ( targetLengthSq > 0 ) { - - return target.multiplyScalar( 1 / Math.sqrt( targetLengthSq ) ); - - } - - return target.set( 0, 0, 0 ); - - } - - // static/instance method to calculate barycentric coordinates - // based on: http://www.blackpawn.com/texts/pointinpoly/default.html - static getBarycoord( point, a, b, c, target ) { - - _v0$1.subVectors( c, a ); - _v1$3.subVectors( b, a ); - _v2$2.subVectors( point, a ); - - const dot00 = _v0$1.dot( _v0$1 ); - const dot01 = _v0$1.dot( _v1$3 ); - const dot02 = _v0$1.dot( _v2$2 ); - const dot11 = _v1$3.dot( _v1$3 ); - const dot12 = _v1$3.dot( _v2$2 ); - - const denom = ( dot00 * dot11 - dot01 * dot01 ); - - // collinear or singular triangle - if ( denom === 0 ) { - - target.set( 0, 0, 0 ); - return null; - - } - - const invDenom = 1 / denom; - const u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom; - const v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom; - - // barycentric coordinates must always sum to 1 - return target.set( 1 - u - v, v, u ); - - } - - static containsPoint( point, a, b, c ) { - - // if the triangle is degenerate then we can't contain a point - if ( this.getBarycoord( point, a, b, c, _v3$2 ) === null ) { - - return false; - - } - - return ( _v3$2.x >= 0 ) && ( _v3$2.y >= 0 ) && ( ( _v3$2.x + _v3$2.y ) <= 1 ); - - } - - static getInterpolation( point, p1, p2, p3, v1, v2, v3, target ) { - - if ( this.getBarycoord( point, p1, p2, p3, _v3$2 ) === null ) { - - target.x = 0; - target.y = 0; - if ( 'z' in target ) target.z = 0; - if ( 'w' in target ) target.w = 0; - return null; - - } - - target.setScalar( 0 ); - target.addScaledVector( v1, _v3$2.x ); - target.addScaledVector( v2, _v3$2.y ); - target.addScaledVector( v3, _v3$2.z ); - - return target; - - } - - static isFrontFacing( a, b, c, direction ) { - - _v0$1.subVectors( c, b ); - _v1$3.subVectors( a, b ); - - // strictly front facing - return ( _v0$1.cross( _v1$3 ).dot( direction ) < 0 ) ? true : false; - - } - - set( a, b, c ) { - - this.a.copy( a ); - this.b.copy( b ); - this.c.copy( c ); - - return this; - - } - - setFromPointsAndIndices( points, i0, i1, i2 ) { - - this.a.copy( points[ i0 ] ); - this.b.copy( points[ i1 ] ); - this.c.copy( points[ i2 ] ); - - return this; - - } - - setFromAttributeAndIndices( attribute, i0, i1, i2 ) { - - this.a.fromBufferAttribute( attribute, i0 ); - this.b.fromBufferAttribute( attribute, i1 ); - this.c.fromBufferAttribute( attribute, i2 ); - - return this; - - } - - clone() { - - return new this.constructor().copy( this ); - - } - - copy( triangle ) { - - this.a.copy( triangle.a ); - this.b.copy( triangle.b ); - this.c.copy( triangle.c ); - - return this; - - } - - getArea() { - - _v0$1.subVectors( this.c, this.b ); - _v1$3.subVectors( this.a, this.b ); - - return _v0$1.cross( _v1$3 ).length() * 0.5; - - } - - getMidpoint( target ) { - - return target.addVectors( this.a, this.b ).add( this.c ).multiplyScalar( 1 / 3 ); - - } - - getNormal( target ) { - - return Triangle.getNormal( this.a, this.b, this.c, target ); - - } - - getPlane( target ) { - - return target.setFromCoplanarPoints( this.a, this.b, this.c ); - - } - - getBarycoord( point, target ) { - - return Triangle.getBarycoord( point, this.a, this.b, this.c, target ); - - } - - getInterpolation( point, v1, v2, v3, target ) { - - return Triangle.getInterpolation( point, this.a, this.b, this.c, v1, v2, v3, target ); - - } - - containsPoint( point ) { - - return Triangle.containsPoint( point, this.a, this.b, this.c ); - - } - - isFrontFacing( direction ) { - - return Triangle.isFrontFacing( this.a, this.b, this.c, direction ); - - } - - intersectsBox( box ) { - - return box.intersectsTriangle( this ); - - } - - closestPointToPoint( p, target ) { - - const a = this.a, b = this.b, c = this.c; - let v, w; - - // algorithm thanks to Real-Time Collision Detection by Christer Ericson, - // published by Morgan Kaufmann Publishers, (c) 2005 Elsevier Inc., - // under the accompanying license; see chapter 5.1.5 for detailed explanation. - // basically, we're distinguishing which of the voronoi regions of the triangle - // the point lies in with the minimum amount of redundant computation. - - _vab.subVectors( b, a ); - _vac.subVectors( c, a ); - _vap.subVectors( p, a ); - const d1 = _vab.dot( _vap ); - const d2 = _vac.dot( _vap ); - if ( d1 <= 0 && d2 <= 0 ) { - - // vertex region of A; barycentric coords (1, 0, 0) - return target.copy( a ); - - } - - _vbp.subVectors( p, b ); - const d3 = _vab.dot( _vbp ); - const d4 = _vac.dot( _vbp ); - if ( d3 >= 0 && d4 <= d3 ) { - - // vertex region of B; barycentric coords (0, 1, 0) - return target.copy( b ); - - } - - const vc = d1 * d4 - d3 * d2; - if ( vc <= 0 && d1 >= 0 && d3 <= 0 ) { - - v = d1 / ( d1 - d3 ); - // edge region of AB; barycentric coords (1-v, v, 0) - return target.copy( a ).addScaledVector( _vab, v ); - - } - - _vcp.subVectors( p, c ); - const d5 = _vab.dot( _vcp ); - const d6 = _vac.dot( _vcp ); - if ( d6 >= 0 && d5 <= d6 ) { - - // vertex region of C; barycentric coords (0, 0, 1) - return target.copy( c ); - - } - - const vb = d5 * d2 - d1 * d6; - if ( vb <= 0 && d2 >= 0 && d6 <= 0 ) { - - w = d2 / ( d2 - d6 ); - // edge region of AC; barycentric coords (1-w, 0, w) - return target.copy( a ).addScaledVector( _vac, w ); - - } - - const va = d3 * d6 - d5 * d4; - if ( va <= 0 && ( d4 - d3 ) >= 0 && ( d5 - d6 ) >= 0 ) { - - _vbc.subVectors( c, b ); - w = ( d4 - d3 ) / ( ( d4 - d3 ) + ( d5 - d6 ) ); - // edge region of BC; barycentric coords (0, 1-w, w) - return target.copy( b ).addScaledVector( _vbc, w ); // edge region of BC - - } - - // face region - const denom = 1 / ( va + vb + vc ); - // u = va * denom - v = vb * denom; - w = vc * denom; - - return target.copy( a ).addScaledVector( _vab, v ).addScaledVector( _vac, w ); - - } - - equals( triangle ) { - - return triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c ); - - } - -} - -const _colorKeywords = { 'aliceblue': 0xF0F8FF, 'antiquewhite': 0xFAEBD7, 'aqua': 0x00FFFF, 'aquamarine': 0x7FFFD4, 'azure': 0xF0FFFF, - 'beige': 0xF5F5DC, 'bisque': 0xFFE4C4, 'black': 0x000000, 'blanchedalmond': 0xFFEBCD, 'blue': 0x0000FF, 'blueviolet': 0x8A2BE2, - 'brown': 0xA52A2A, 'burlywood': 0xDEB887, 'cadetblue': 0x5F9EA0, 'chartreuse': 0x7FFF00, 'chocolate': 0xD2691E, 'coral': 0xFF7F50, - 'cornflowerblue': 0x6495ED, 'cornsilk': 0xFFF8DC, 'crimson': 0xDC143C, 'cyan': 0x00FFFF, 'darkblue': 0x00008B, 'darkcyan': 0x008B8B, - 'darkgoldenrod': 0xB8860B, 'darkgray': 0xA9A9A9, 'darkgreen': 0x006400, 'darkgrey': 0xA9A9A9, 'darkkhaki': 0xBDB76B, 'darkmagenta': 0x8B008B, - 'darkolivegreen': 0x556B2F, 'darkorange': 0xFF8C00, 'darkorchid': 0x9932CC, 'darkred': 0x8B0000, 'darksalmon': 0xE9967A, 'darkseagreen': 0x8FBC8F, - 'darkslateblue': 0x483D8B, 'darkslategray': 0x2F4F4F, 'darkslategrey': 0x2F4F4F, 'darkturquoise': 0x00CED1, 'darkviolet': 0x9400D3, - 'deeppink': 0xFF1493, 'deepskyblue': 0x00BFFF, 'dimgray': 0x696969, 'dimgrey': 0x696969, 'dodgerblue': 0x1E90FF, 'firebrick': 0xB22222, - 'floralwhite': 0xFFFAF0, 'forestgreen': 0x228B22, 'fuchsia': 0xFF00FF, 'gainsboro': 0xDCDCDC, 'ghostwhite': 0xF8F8FF, 'gold': 0xFFD700, - 'goldenrod': 0xDAA520, 'gray': 0x808080, 'green': 0x008000, 'greenyellow': 0xADFF2F, 'grey': 0x808080, 'honeydew': 0xF0FFF0, 'hotpink': 0xFF69B4, - 'indianred': 0xCD5C5C, 'indigo': 0x4B0082, 'ivory': 0xFFFFF0, 'khaki': 0xF0E68C, 'lavender': 0xE6E6FA, 'lavenderblush': 0xFFF0F5, 'lawngreen': 0x7CFC00, - 'lemonchiffon': 0xFFFACD, 'lightblue': 0xADD8E6, 'lightcoral': 0xF08080, 'lightcyan': 0xE0FFFF, 'lightgoldenrodyellow': 0xFAFAD2, 'lightgray': 0xD3D3D3, - 'lightgreen': 0x90EE90, 'lightgrey': 0xD3D3D3, 'lightpink': 0xFFB6C1, 'lightsalmon': 0xFFA07A, 'lightseagreen': 0x20B2AA, 'lightskyblue': 0x87CEFA, - 'lightslategray': 0x778899, 'lightslategrey': 0x778899, 'lightsteelblue': 0xB0C4DE, 'lightyellow': 0xFFFFE0, 'lime': 0x00FF00, 'limegreen': 0x32CD32, - 'linen': 0xFAF0E6, 'magenta': 0xFF00FF, 'maroon': 0x800000, 'mediumaquamarine': 0x66CDAA, 'mediumblue': 0x0000CD, 'mediumorchid': 0xBA55D3, - 'mediumpurple': 0x9370DB, 'mediumseagreen': 0x3CB371, 'mediumslateblue': 0x7B68EE, 'mediumspringgreen': 0x00FA9A, 'mediumturquoise': 0x48D1CC, - 'mediumvioletred': 0xC71585, 'midnightblue': 0x191970, 'mintcream': 0xF5FFFA, 'mistyrose': 0xFFE4E1, 'moccasin': 0xFFE4B5, 'navajowhite': 0xFFDEAD, - 'navy': 0x000080, 'oldlace': 0xFDF5E6, 'olive': 0x808000, 'olivedrab': 0x6B8E23, 'orange': 0xFFA500, 'orangered': 0xFF4500, 'orchid': 0xDA70D6, - 'palegoldenrod': 0xEEE8AA, 'palegreen': 0x98FB98, 'paleturquoise': 0xAFEEEE, 'palevioletred': 0xDB7093, 'papayawhip': 0xFFEFD5, 'peachpuff': 0xFFDAB9, - 'peru': 0xCD853F, 'pink': 0xFFC0CB, 'plum': 0xDDA0DD, 'powderblue': 0xB0E0E6, 'purple': 0x800080, 'rebeccapurple': 0x663399, 'red': 0xFF0000, 'rosybrown': 0xBC8F8F, - 'royalblue': 0x4169E1, 'saddlebrown': 0x8B4513, 'salmon': 0xFA8072, 'sandybrown': 0xF4A460, 'seagreen': 0x2E8B57, 'seashell': 0xFFF5EE, - 'sienna': 0xA0522D, 'silver': 0xC0C0C0, 'skyblue': 0x87CEEB, 'slateblue': 0x6A5ACD, 'slategray': 0x708090, 'slategrey': 0x708090, 'snow': 0xFFFAFA, - 'springgreen': 0x00FF7F, 'steelblue': 0x4682B4, 'tan': 0xD2B48C, 'teal': 0x008080, 'thistle': 0xD8BFD8, 'tomato': 0xFF6347, 'turquoise': 0x40E0D0, - 'violet': 0xEE82EE, 'wheat': 0xF5DEB3, 'white': 0xFFFFFF, 'whitesmoke': 0xF5F5F5, 'yellow': 0xFFFF00, 'yellowgreen': 0x9ACD32 }; - -const _hslA = { h: 0, s: 0, l: 0 }; -const _hslB = { h: 0, s: 0, l: 0 }; - -function hue2rgb( p, q, t ) { - - if ( t < 0 ) t += 1; - if ( t > 1 ) t -= 1; - if ( t < 1 / 6 ) return p + ( q - p ) * 6 * t; - if ( t < 1 / 2 ) return q; - if ( t < 2 / 3 ) return p + ( q - p ) * 6 * ( 2 / 3 - t ); - return p; - -} - -class Color { - - constructor( r, g, b ) { - - this.isColor = true; - - this.r = 1; - this.g = 1; - this.b = 1; - - return this.set( r, g, b ); - - } - - set( r, g, b ) { - - if ( g === undefined && b === undefined ) { - - // r is THREE.Color, hex or string - - const value = r; - - if ( value && value.isColor ) { - - this.copy( value ); - - } else if ( typeof value === 'number' ) { - - this.setHex( value ); - - } else if ( typeof value === 'string' ) { - - this.setStyle( value ); - - } - - } else { - - this.setRGB( r, g, b ); - - } - - return this; - - } - - setScalar( scalar ) { - - this.r = scalar; - this.g = scalar; - this.b = scalar; - - return this; - - } - - setHex( hex, colorSpace = SRGBColorSpace ) { - - hex = Math.floor( hex ); - - this.r = ( hex >> 16 & 255 ) / 255; - this.g = ( hex >> 8 & 255 ) / 255; - this.b = ( hex & 255 ) / 255; - - ColorManagement.toWorkingColorSpace( this, colorSpace ); - - return this; - - } - - setRGB( r, g, b, colorSpace = ColorManagement.workingColorSpace ) { - - this.r = r; - this.g = g; - this.b = b; - - ColorManagement.toWorkingColorSpace( this, colorSpace ); - - return this; - - } - - setHSL( h, s, l, colorSpace = ColorManagement.workingColorSpace ) { - - // h,s,l ranges are in 0.0 - 1.0 - h = euclideanModulo( h, 1 ); - s = clamp( s, 0, 1 ); - l = clamp( l, 0, 1 ); - - if ( s === 0 ) { - - this.r = this.g = this.b = l; - - } else { - - const p = l <= 0.5 ? l * ( 1 + s ) : l + s - ( l * s ); - const q = ( 2 * l ) - p; - - this.r = hue2rgb( q, p, h + 1 / 3 ); - this.g = hue2rgb( q, p, h ); - this.b = hue2rgb( q, p, h - 1 / 3 ); - - } - - ColorManagement.toWorkingColorSpace( this, colorSpace ); - - return this; - - } - - setStyle( style, colorSpace = SRGBColorSpace ) { - - function handleAlpha( string ) { - - if ( string === undefined ) return; - - if ( parseFloat( string ) < 1 ) { - - console.warn( 'THREE.Color: Alpha component of ' + style + ' will be ignored.' ); - - } - - } - - - let m; - - if ( m = /^(\w+)\(([^\)]*)\)/.exec( style ) ) { - - // rgb / hsl - - let color; - const name = m[ 1 ]; - const components = m[ 2 ]; - - switch ( name ) { - - case 'rgb': - case 'rgba': - - if ( color = /^\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) { - - // rgb(255,0,0) rgba(255,0,0,0.5) - - handleAlpha( color[ 4 ] ); - - return this.setRGB( - Math.min( 255, parseInt( color[ 1 ], 10 ) ) / 255, - Math.min( 255, parseInt( color[ 2 ], 10 ) ) / 255, - Math.min( 255, parseInt( color[ 3 ], 10 ) ) / 255, - colorSpace - ); - - } - - if ( color = /^\s*(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) { - - // rgb(100%,0%,0%) rgba(100%,0%,0%,0.5) - - handleAlpha( color[ 4 ] ); - - return this.setRGB( - Math.min( 100, parseInt( color[ 1 ], 10 ) ) / 100, - Math.min( 100, parseInt( color[ 2 ], 10 ) ) / 100, - Math.min( 100, parseInt( color[ 3 ], 10 ) ) / 100, - colorSpace - ); - - } - - break; - - case 'hsl': - case 'hsla': - - if ( color = /^\s*(\d*\.?\d+)\s*,\s*(\d*\.?\d+)\%\s*,\s*(\d*\.?\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) { - - // hsl(120,50%,50%) hsla(120,50%,50%,0.5) - - handleAlpha( color[ 4 ] ); - - return this.setHSL( - parseFloat( color[ 1 ] ) / 360, - parseFloat( color[ 2 ] ) / 100, - parseFloat( color[ 3 ] ) / 100, - colorSpace - ); - - } - - break; - - default: - - console.warn( 'THREE.Color: Unknown color model ' + style ); - - } - - } else if ( m = /^\#([A-Fa-f\d]+)$/.exec( style ) ) { - - // hex color - - const hex = m[ 1 ]; - const size = hex.length; - - if ( size === 3 ) { - - // #ff0 - return this.setRGB( - parseInt( hex.charAt( 0 ), 16 ) / 15, - parseInt( hex.charAt( 1 ), 16 ) / 15, - parseInt( hex.charAt( 2 ), 16 ) / 15, - colorSpace - ); - - } else if ( size === 6 ) { - - // #ff0000 - return this.setHex( parseInt( hex, 16 ), colorSpace ); - - } else { - - console.warn( 'THREE.Color: Invalid hex color ' + style ); - - } - - } else if ( style && style.length > 0 ) { - - return this.setColorName( style, colorSpace ); - - } - - return this; - - } - - setColorName( style, colorSpace = SRGBColorSpace ) { - - // color keywords - const hex = _colorKeywords[ style.toLowerCase() ]; - - if ( hex !== undefined ) { - - // red - this.setHex( hex, colorSpace ); - - } else { - - // unknown color - console.warn( 'THREE.Color: Unknown color ' + style ); - - } - - return this; - - } - - clone() { - - return new this.constructor( this.r, this.g, this.b ); - - } - - copy( color ) { - - this.r = color.r; - this.g = color.g; - this.b = color.b; - - return this; - - } - - copySRGBToLinear( color ) { - - this.r = SRGBToLinear( color.r ); - this.g = SRGBToLinear( color.g ); - this.b = SRGBToLinear( color.b ); - - return this; - - } - - copyLinearToSRGB( color ) { - - this.r = LinearToSRGB( color.r ); - this.g = LinearToSRGB( color.g ); - this.b = LinearToSRGB( color.b ); - - return this; - - } - - convertSRGBToLinear() { - - this.copySRGBToLinear( this ); - - return this; - - } - - convertLinearToSRGB() { - - this.copyLinearToSRGB( this ); - - return this; - - } - - getHex( colorSpace = SRGBColorSpace ) { - - ColorManagement.fromWorkingColorSpace( _color.copy( this ), colorSpace ); - - return Math.round( clamp( _color.r * 255, 0, 255 ) ) * 65536 + Math.round( clamp( _color.g * 255, 0, 255 ) ) * 256 + Math.round( clamp( _color.b * 255, 0, 255 ) ); - - } - - getHexString( colorSpace = SRGBColorSpace ) { - - return ( '000000' + this.getHex( colorSpace ).toString( 16 ) ).slice( - 6 ); - - } - - getHSL( target, colorSpace = ColorManagement.workingColorSpace ) { - - // h,s,l ranges are in 0.0 - 1.0 - - ColorManagement.fromWorkingColorSpace( _color.copy( this ), colorSpace ); - - const r = _color.r, g = _color.g, b = _color.b; - - const max = Math.max( r, g, b ); - const min = Math.min( r, g, b ); - - let hue, saturation; - const lightness = ( min + max ) / 2.0; - - if ( min === max ) { - - hue = 0; - saturation = 0; - - } else { - - const delta = max - min; - - saturation = lightness <= 0.5 ? delta / ( max + min ) : delta / ( 2 - max - min ); - - switch ( max ) { - - case r: hue = ( g - b ) / delta + ( g < b ? 6 : 0 ); break; - case g: hue = ( b - r ) / delta + 2; break; - case b: hue = ( r - g ) / delta + 4; break; - - } - - hue /= 6; - - } - - target.h = hue; - target.s = saturation; - target.l = lightness; - - return target; - - } - - getRGB( target, colorSpace = ColorManagement.workingColorSpace ) { - - ColorManagement.fromWorkingColorSpace( _color.copy( this ), colorSpace ); - - target.r = _color.r; - target.g = _color.g; - target.b = _color.b; - - return target; - - } - - getStyle( colorSpace = SRGBColorSpace ) { - - ColorManagement.fromWorkingColorSpace( _color.copy( this ), colorSpace ); - - const r = _color.r, g = _color.g, b = _color.b; - - if ( colorSpace !== SRGBColorSpace ) { - - // Requires CSS Color Module Level 4 (https://www.w3.org/TR/css-color-4/). - return `color(${ colorSpace } ${ r.toFixed( 3 ) } ${ g.toFixed( 3 ) } ${ b.toFixed( 3 ) })`; - - } - - return `rgb(${ Math.round( r * 255 ) },${ Math.round( g * 255 ) },${ Math.round( b * 255 ) })`; - - } - - offsetHSL( h, s, l ) { - - this.getHSL( _hslA ); - - return this.setHSL( _hslA.h + h, _hslA.s + s, _hslA.l + l ); - - } - - add( color ) { - - this.r += color.r; - this.g += color.g; - this.b += color.b; - - return this; - - } - - addColors( color1, color2 ) { - - this.r = color1.r + color2.r; - this.g = color1.g + color2.g; - this.b = color1.b + color2.b; - - return this; - - } - - addScalar( s ) { - - this.r += s; - this.g += s; - this.b += s; - - return this; - - } - - sub( color ) { - - this.r = Math.max( 0, this.r - color.r ); - this.g = Math.max( 0, this.g - color.g ); - this.b = Math.max( 0, this.b - color.b ); - - return this; - - } - - multiply( color ) { - - this.r *= color.r; - this.g *= color.g; - this.b *= color.b; - - return this; - - } - - multiplyScalar( s ) { - - this.r *= s; - this.g *= s; - this.b *= s; - - return this; - - } - - lerp( color, alpha ) { - - this.r += ( color.r - this.r ) * alpha; - this.g += ( color.g - this.g ) * alpha; - this.b += ( color.b - this.b ) * alpha; - - return this; - - } - - lerpColors( color1, color2, alpha ) { - - this.r = color1.r + ( color2.r - color1.r ) * alpha; - this.g = color1.g + ( color2.g - color1.g ) * alpha; - this.b = color1.b + ( color2.b - color1.b ) * alpha; - - return this; - - } - - lerpHSL( color, alpha ) { - - this.getHSL( _hslA ); - color.getHSL( _hslB ); - - const h = lerp( _hslA.h, _hslB.h, alpha ); - const s = lerp( _hslA.s, _hslB.s, alpha ); - const l = lerp( _hslA.l, _hslB.l, alpha ); - - this.setHSL( h, s, l ); - - return this; - - } - - setFromVector3( v ) { - - this.r = v.x; - this.g = v.y; - this.b = v.z; - - return this; - - } - - applyMatrix3( m ) { - - const r = this.r, g = this.g, b = this.b; - const e = m.elements; - - this.r = e[ 0 ] * r + e[ 3 ] * g + e[ 6 ] * b; - this.g = e[ 1 ] * r + e[ 4 ] * g + e[ 7 ] * b; - this.b = e[ 2 ] * r + e[ 5 ] * g + e[ 8 ] * b; - - return this; - - } - - equals( c ) { - - return ( c.r === this.r ) && ( c.g === this.g ) && ( c.b === this.b ); - - } - - fromArray( array, offset = 0 ) { - - this.r = array[ offset ]; - this.g = array[ offset + 1 ]; - this.b = array[ offset + 2 ]; - - return this; - - } - - toArray( array = [], offset = 0 ) { - - array[ offset ] = this.r; - array[ offset + 1 ] = this.g; - array[ offset + 2 ] = this.b; - - return array; - - } - - fromBufferAttribute( attribute, index ) { - - this.r = attribute.getX( index ); - this.g = attribute.getY( index ); - this.b = attribute.getZ( index ); - - return this; - - } - - toJSON() { - - return this.getHex(); - - } - - *[ Symbol.iterator ]() { - - yield this.r; - yield this.g; - yield this.b; - - } - -} - -const _color = /*@__PURE__*/ new Color(); - -Color.NAMES = _colorKeywords; - -let _materialId = 0; - -class Material extends EventDispatcher { - - constructor() { - - super(); - - this.isMaterial = true; - - Object.defineProperty( this, 'id', { value: _materialId ++ } ); - - this.uuid = generateUUID(); - - this.name = ''; - this.type = 'Material'; - - this.blending = NormalBlending; - this.side = FrontSide; - this.vertexColors = false; - - this.opacity = 1; - this.transparent = false; - this.alphaHash = false; - - this.blendSrc = SrcAlphaFactor; - this.blendDst = OneMinusSrcAlphaFactor; - this.blendEquation = AddEquation; - this.blendSrcAlpha = null; - this.blendDstAlpha = null; - this.blendEquationAlpha = null; - this.blendColor = new Color( 0, 0, 0 ); - this.blendAlpha = 0; - - this.depthFunc = LessEqualDepth; - this.depthTest = true; - this.depthWrite = true; - - this.stencilWriteMask = 0xff; - this.stencilFunc = AlwaysStencilFunc; - this.stencilRef = 0; - this.stencilFuncMask = 0xff; - this.stencilFail = KeepStencilOp; - this.stencilZFail = KeepStencilOp; - this.stencilZPass = KeepStencilOp; - this.stencilWrite = false; - - this.clippingPlanes = null; - this.clipIntersection = false; - this.clipShadows = false; - - this.shadowSide = null; - - this.colorWrite = true; - - this.precision = null; // override the renderer's default precision for this material - - this.polygonOffset = false; - this.polygonOffsetFactor = 0; - this.polygonOffsetUnits = 0; - - this.dithering = false; - - this.alphaToCoverage = false; - this.premultipliedAlpha = false; - this.forceSinglePass = false; - - this.visible = true; - - this.toneMapped = true; - - this.userData = {}; - - this.version = 0; - - this._alphaTest = 0; - - } - - get alphaTest() { - - return this._alphaTest; - - } - - set alphaTest( value ) { - - if ( this._alphaTest > 0 !== value > 0 ) { - - this.version ++; - - } - - this._alphaTest = value; - - } - - onBuild( /* shaderobject, renderer */ ) {} - - onBeforeRender( /* renderer, scene, camera, geometry, object, group */ ) {} - - onBeforeCompile( /* shaderobject, renderer */ ) {} - - customProgramCacheKey() { - - return this.onBeforeCompile.toString(); - - } - - setValues( values ) { - - if ( values === undefined ) return; - - for ( const key in values ) { - - const newValue = values[ key ]; - - if ( newValue === undefined ) { - - console.warn( `THREE.Material: parameter '${ key }' has value of undefined.` ); - continue; - - } - - const currentValue = this[ key ]; - - if ( currentValue === undefined ) { - - console.warn( `THREE.Material: '${ key }' is not a property of THREE.${ this.type }.` ); - continue; - - } - - if ( currentValue && currentValue.isColor ) { - - currentValue.set( newValue ); - - } else if ( ( currentValue && currentValue.isVector3 ) && ( newValue && newValue.isVector3 ) ) { - - currentValue.copy( newValue ); - - } else { - - this[ key ] = newValue; - - } - - } - - } - - toJSON( meta ) { - - const isRootObject = ( meta === undefined || typeof meta === 'string' ); - - if ( isRootObject ) { - - meta = { - textures: {}, - images: {} - }; - - } - - const data = { - metadata: { - version: 4.6, - type: 'Material', - generator: 'Material.toJSON' - } - }; - - // standard Material serialization - data.uuid = this.uuid; - data.type = this.type; - - if ( this.name !== '' ) data.name = this.name; - - if ( this.color && this.color.isColor ) data.color = this.color.getHex(); - - if ( this.roughness !== undefined ) data.roughness = this.roughness; - if ( this.metalness !== undefined ) data.metalness = this.metalness; - - if ( this.sheen !== undefined ) data.sheen = this.sheen; - if ( this.sheenColor && this.sheenColor.isColor ) data.sheenColor = this.sheenColor.getHex(); - if ( this.sheenRoughness !== undefined ) data.sheenRoughness = this.sheenRoughness; - if ( this.emissive && this.emissive.isColor ) data.emissive = this.emissive.getHex(); - if ( this.emissiveIntensity && this.emissiveIntensity !== 1 ) data.emissiveIntensity = this.emissiveIntensity; - - if ( this.specular && this.specular.isColor ) data.specular = this.specular.getHex(); - if ( this.specularIntensity !== undefined ) data.specularIntensity = this.specularIntensity; - if ( this.specularColor && this.specularColor.isColor ) data.specularColor = this.specularColor.getHex(); - if ( this.shininess !== undefined ) data.shininess = this.shininess; - if ( this.clearcoat !== undefined ) data.clearcoat = this.clearcoat; - if ( this.clearcoatRoughness !== undefined ) data.clearcoatRoughness = this.clearcoatRoughness; - - if ( this.clearcoatMap && this.clearcoatMap.isTexture ) { - - data.clearcoatMap = this.clearcoatMap.toJSON( meta ).uuid; - - } - - if ( this.clearcoatRoughnessMap && this.clearcoatRoughnessMap.isTexture ) { - - data.clearcoatRoughnessMap = this.clearcoatRoughnessMap.toJSON( meta ).uuid; - - } - - if ( this.clearcoatNormalMap && this.clearcoatNormalMap.isTexture ) { - - data.clearcoatNormalMap = this.clearcoatNormalMap.toJSON( meta ).uuid; - data.clearcoatNormalScale = this.clearcoatNormalScale.toArray(); - - } - - if ( this.iridescence !== undefined ) data.iridescence = this.iridescence; - if ( this.iridescenceIOR !== undefined ) data.iridescenceIOR = this.iridescenceIOR; - if ( this.iridescenceThicknessRange !== undefined ) data.iridescenceThicknessRange = this.iridescenceThicknessRange; - - if ( this.iridescenceMap && this.iridescenceMap.isTexture ) { - - data.iridescenceMap = this.iridescenceMap.toJSON( meta ).uuid; - - } - - if ( this.iridescenceThicknessMap && this.iridescenceThicknessMap.isTexture ) { - - data.iridescenceThicknessMap = this.iridescenceThicknessMap.toJSON( meta ).uuid; - - } - - if ( this.anisotropy !== undefined ) data.anisotropy = this.anisotropy; - if ( this.anisotropyRotation !== undefined ) data.anisotropyRotation = this.anisotropyRotation; - - if ( this.anisotropyMap && this.anisotropyMap.isTexture ) { - - data.anisotropyMap = this.anisotropyMap.toJSON( meta ).uuid; - - } - - if ( this.map && this.map.isTexture ) data.map = this.map.toJSON( meta ).uuid; - if ( this.matcap && this.matcap.isTexture ) data.matcap = this.matcap.toJSON( meta ).uuid; - if ( this.alphaMap && this.alphaMap.isTexture ) data.alphaMap = this.alphaMap.toJSON( meta ).uuid; - - if ( this.lightMap && this.lightMap.isTexture ) { - - data.lightMap = this.lightMap.toJSON( meta ).uuid; - data.lightMapIntensity = this.lightMapIntensity; - - } - - if ( this.aoMap && this.aoMap.isTexture ) { - - data.aoMap = this.aoMap.toJSON( meta ).uuid; - data.aoMapIntensity = this.aoMapIntensity; - - } - - if ( this.bumpMap && this.bumpMap.isTexture ) { - - data.bumpMap = this.bumpMap.toJSON( meta ).uuid; - data.bumpScale = this.bumpScale; - - } - - if ( this.normalMap && this.normalMap.isTexture ) { - - data.normalMap = this.normalMap.toJSON( meta ).uuid; - data.normalMapType = this.normalMapType; - data.normalScale = this.normalScale.toArray(); - - } - - if ( this.displacementMap && this.displacementMap.isTexture ) { - - data.displacementMap = this.displacementMap.toJSON( meta ).uuid; - data.displacementScale = this.displacementScale; - data.displacementBias = this.displacementBias; - - } - - if ( this.roughnessMap && this.roughnessMap.isTexture ) data.roughnessMap = this.roughnessMap.toJSON( meta ).uuid; - if ( this.metalnessMap && this.metalnessMap.isTexture ) data.metalnessMap = this.metalnessMap.toJSON( meta ).uuid; - - if ( this.emissiveMap && this.emissiveMap.isTexture ) data.emissiveMap = this.emissiveMap.toJSON( meta ).uuid; - if ( this.specularMap && this.specularMap.isTexture ) data.specularMap = this.specularMap.toJSON( meta ).uuid; - if ( this.specularIntensityMap && this.specularIntensityMap.isTexture ) data.specularIntensityMap = this.specularIntensityMap.toJSON( meta ).uuid; - if ( this.specularColorMap && this.specularColorMap.isTexture ) data.specularColorMap = this.specularColorMap.toJSON( meta ).uuid; - - if ( this.envMap && this.envMap.isTexture ) { - - data.envMap = this.envMap.toJSON( meta ).uuid; - - if ( this.combine !== undefined ) data.combine = this.combine; - - } - - if ( this.envMapIntensity !== undefined ) data.envMapIntensity = this.envMapIntensity; - if ( this.reflectivity !== undefined ) data.reflectivity = this.reflectivity; - if ( this.refractionRatio !== undefined ) data.refractionRatio = this.refractionRatio; - - if ( this.gradientMap && this.gradientMap.isTexture ) { - - data.gradientMap = this.gradientMap.toJSON( meta ).uuid; - - } - - if ( this.transmission !== undefined ) data.transmission = this.transmission; - if ( this.transmissionMap && this.transmissionMap.isTexture ) data.transmissionMap = this.transmissionMap.toJSON( meta ).uuid; - if ( this.thickness !== undefined ) data.thickness = this.thickness; - if ( this.thicknessMap && this.thicknessMap.isTexture ) data.thicknessMap = this.thicknessMap.toJSON( meta ).uuid; - if ( this.attenuationDistance !== undefined && this.attenuationDistance !== Infinity ) data.attenuationDistance = this.attenuationDistance; - if ( this.attenuationColor !== undefined ) data.attenuationColor = this.attenuationColor.getHex(); - - if ( this.size !== undefined ) data.size = this.size; - if ( this.shadowSide !== null ) data.shadowSide = this.shadowSide; - if ( this.sizeAttenuation !== undefined ) data.sizeAttenuation = this.sizeAttenuation; - - if ( this.blending !== NormalBlending ) data.blending = this.blending; - if ( this.side !== FrontSide ) data.side = this.side; - if ( this.vertexColors === true ) data.vertexColors = true; - - if ( this.opacity < 1 ) data.opacity = this.opacity; - if ( this.transparent === true ) data.transparent = true; - - if ( this.blendSrc !== SrcAlphaFactor ) data.blendSrc = this.blendSrc; - if ( this.blendDst !== OneMinusSrcAlphaFactor ) data.blendDst = this.blendDst; - if ( this.blendEquation !== AddEquation ) data.blendEquation = this.blendEquation; - if ( this.blendSrcAlpha !== null ) data.blendSrcAlpha = this.blendSrcAlpha; - if ( this.blendDstAlpha !== null ) data.blendDstAlpha = this.blendDstAlpha; - if ( this.blendEquationAlpha !== null ) data.blendEquationAlpha = this.blendEquationAlpha; - if ( this.blendColor && this.blendColor.isColor ) data.blendColor = this.blendColor.getHex(); - if ( this.blendAlpha !== 0 ) data.blendAlpha = this.blendAlpha; - - if ( this.depthFunc !== LessEqualDepth ) data.depthFunc = this.depthFunc; - if ( this.depthTest === false ) data.depthTest = this.depthTest; - if ( this.depthWrite === false ) data.depthWrite = this.depthWrite; - if ( this.colorWrite === false ) data.colorWrite = this.colorWrite; - - if ( this.stencilWriteMask !== 0xff ) data.stencilWriteMask = this.stencilWriteMask; - if ( this.stencilFunc !== AlwaysStencilFunc ) data.stencilFunc = this.stencilFunc; - if ( this.stencilRef !== 0 ) data.stencilRef = this.stencilRef; - if ( this.stencilFuncMask !== 0xff ) data.stencilFuncMask = this.stencilFuncMask; - if ( this.stencilFail !== KeepStencilOp ) data.stencilFail = this.stencilFail; - if ( this.stencilZFail !== KeepStencilOp ) data.stencilZFail = this.stencilZFail; - if ( this.stencilZPass !== KeepStencilOp ) data.stencilZPass = this.stencilZPass; - if ( this.stencilWrite === true ) data.stencilWrite = this.stencilWrite; - - // rotation (SpriteMaterial) - if ( this.rotation !== undefined && this.rotation !== 0 ) data.rotation = this.rotation; - - if ( this.polygonOffset === true ) data.polygonOffset = true; - if ( this.polygonOffsetFactor !== 0 ) data.polygonOffsetFactor = this.polygonOffsetFactor; - if ( this.polygonOffsetUnits !== 0 ) data.polygonOffsetUnits = this.polygonOffsetUnits; - - if ( this.linewidth !== undefined && this.linewidth !== 1 ) data.linewidth = this.linewidth; - if ( this.dashSize !== undefined ) data.dashSize = this.dashSize; - if ( this.gapSize !== undefined ) data.gapSize = this.gapSize; - if ( this.scale !== undefined ) data.scale = this.scale; - - if ( this.dithering === true ) data.dithering = true; - - if ( this.alphaTest > 0 ) data.alphaTest = this.alphaTest; - if ( this.alphaHash === true ) data.alphaHash = true; - if ( this.alphaToCoverage === true ) data.alphaToCoverage = true; - if ( this.premultipliedAlpha === true ) data.premultipliedAlpha = true; - if ( this.forceSinglePass === true ) data.forceSinglePass = true; - - if ( this.wireframe === true ) data.wireframe = true; - if ( this.wireframeLinewidth > 1 ) data.wireframeLinewidth = this.wireframeLinewidth; - if ( this.wireframeLinecap !== 'round' ) data.wireframeLinecap = this.wireframeLinecap; - if ( this.wireframeLinejoin !== 'round' ) data.wireframeLinejoin = this.wireframeLinejoin; - - if ( this.flatShading === true ) data.flatShading = true; - - if ( this.visible === false ) data.visible = false; - - if ( this.toneMapped === false ) data.toneMapped = false; - - if ( this.fog === false ) data.fog = false; - - if ( Object.keys( this.userData ).length > 0 ) data.userData = this.userData; - - // TODO: Copied from Object3D.toJSON - - function extractFromCache( cache ) { - - const values = []; - - for ( const key in cache ) { - - const data = cache[ key ]; - delete data.metadata; - values.push( data ); - - } - - return values; - - } - - if ( isRootObject ) { - - const textures = extractFromCache( meta.textures ); - const images = extractFromCache( meta.images ); - - if ( textures.length > 0 ) data.textures = textures; - if ( images.length > 0 ) data.images = images; - - } - - return data; - - } - - clone() { - - return new this.constructor().copy( this ); - - } - - copy( source ) { - - this.name = source.name; - - this.blending = source.blending; - this.side = source.side; - this.vertexColors = source.vertexColors; - - this.opacity = source.opacity; - this.transparent = source.transparent; - - this.blendSrc = source.blendSrc; - this.blendDst = source.blendDst; - this.blendEquation = source.blendEquation; - this.blendSrcAlpha = source.blendSrcAlpha; - this.blendDstAlpha = source.blendDstAlpha; - this.blendEquationAlpha = source.blendEquationAlpha; - this.blendColor.copy( source.blendColor ); - this.blendAlpha = source.blendAlpha; - - this.depthFunc = source.depthFunc; - this.depthTest = source.depthTest; - this.depthWrite = source.depthWrite; - - this.stencilWriteMask = source.stencilWriteMask; - this.stencilFunc = source.stencilFunc; - this.stencilRef = source.stencilRef; - this.stencilFuncMask = source.stencilFuncMask; - this.stencilFail = source.stencilFail; - this.stencilZFail = source.stencilZFail; - this.stencilZPass = source.stencilZPass; - this.stencilWrite = source.stencilWrite; - - const srcPlanes = source.clippingPlanes; - let dstPlanes = null; - - if ( srcPlanes !== null ) { - - const n = srcPlanes.length; - dstPlanes = new Array( n ); - - for ( let i = 0; i !== n; ++ i ) { - - dstPlanes[ i ] = srcPlanes[ i ].clone(); - - } - - } - - this.clippingPlanes = dstPlanes; - this.clipIntersection = source.clipIntersection; - this.clipShadows = source.clipShadows; - - this.shadowSide = source.shadowSide; - - this.colorWrite = source.colorWrite; - - this.precision = source.precision; - - this.polygonOffset = source.polygonOffset; - this.polygonOffsetFactor = source.polygonOffsetFactor; - this.polygonOffsetUnits = source.polygonOffsetUnits; - - this.dithering = source.dithering; - - this.alphaTest = source.alphaTest; - this.alphaHash = source.alphaHash; - this.alphaToCoverage = source.alphaToCoverage; - this.premultipliedAlpha = source.premultipliedAlpha; - this.forceSinglePass = source.forceSinglePass; - - this.visible = source.visible; - - this.toneMapped = source.toneMapped; - - this.userData = JSON.parse( JSON.stringify( source.userData ) ); - - return this; - - } - - dispose() { - - this.dispatchEvent( { type: 'dispose' } ); - - } - - set needsUpdate( value ) { - - if ( value === true ) this.version ++; - - } - -} - -class MeshBasicMaterial extends Material { - - constructor( parameters ) { - - super(); - - this.isMeshBasicMaterial = true; - - this.type = 'MeshBasicMaterial'; - - this.color = new Color( 0xffffff ); // emissive - - this.map = null; - - this.lightMap = null; - this.lightMapIntensity = 1.0; - - this.aoMap = null; - this.aoMapIntensity = 1.0; - - this.specularMap = null; - - this.alphaMap = null; - - this.envMap = null; - this.combine = MultiplyOperation; - this.reflectivity = 1; - this.refractionRatio = 0.98; - - this.wireframe = false; - this.wireframeLinewidth = 1; - this.wireframeLinecap = 'round'; - this.wireframeLinejoin = 'round'; - - this.fog = true; - - this.setValues( parameters ); - - } - - copy( source ) { - - super.copy( source ); - - this.color.copy( source.color ); - - this.map = source.map; - - this.lightMap = source.lightMap; - this.lightMapIntensity = source.lightMapIntensity; - - this.aoMap = source.aoMap; - this.aoMapIntensity = source.aoMapIntensity; - - this.specularMap = source.specularMap; - - this.alphaMap = source.alphaMap; - - this.envMap = source.envMap; - this.combine = source.combine; - this.reflectivity = source.reflectivity; - this.refractionRatio = source.refractionRatio; - - this.wireframe = source.wireframe; - this.wireframeLinewidth = source.wireframeLinewidth; - this.wireframeLinecap = source.wireframeLinecap; - this.wireframeLinejoin = source.wireframeLinejoin; - - this.fog = source.fog; - - return this; - - } - -} - -// Fast Half Float Conversions, http://www.fox-toolkit.org/ftp/fasthalffloatconversion.pdf - -const _tables = /*@__PURE__*/ _generateTables(); - -function _generateTables() { - - // float32 to float16 helpers - - const buffer = new ArrayBuffer( 4 ); - const floatView = new Float32Array( buffer ); - const uint32View = new Uint32Array( buffer ); - - const baseTable = new Uint32Array( 512 ); - const shiftTable = new Uint32Array( 512 ); - - for ( let i = 0; i < 256; ++ i ) { - - const e = i - 127; - - // very small number (0, -0) - - if ( e < - 27 ) { - - baseTable[ i ] = 0x0000; - baseTable[ i | 0x100 ] = 0x8000; - shiftTable[ i ] = 24; - shiftTable[ i | 0x100 ] = 24; - - // small number (denorm) - - } else if ( e < - 14 ) { - - baseTable[ i ] = 0x0400 >> ( - e - 14 ); - baseTable[ i | 0x100 ] = ( 0x0400 >> ( - e - 14 ) ) | 0x8000; - shiftTable[ i ] = - e - 1; - shiftTable[ i | 0x100 ] = - e - 1; - - // normal number - - } else if ( e <= 15 ) { - - baseTable[ i ] = ( e + 15 ) << 10; - baseTable[ i | 0x100 ] = ( ( e + 15 ) << 10 ) | 0x8000; - shiftTable[ i ] = 13; - shiftTable[ i | 0x100 ] = 13; - - // large number (Infinity, -Infinity) - - } else if ( e < 128 ) { - - baseTable[ i ] = 0x7c00; - baseTable[ i | 0x100 ] = 0xfc00; - shiftTable[ i ] = 24; - shiftTable[ i | 0x100 ] = 24; - - // stay (NaN, Infinity, -Infinity) - - } else { - - baseTable[ i ] = 0x7c00; - baseTable[ i | 0x100 ] = 0xfc00; - shiftTable[ i ] = 13; - shiftTable[ i | 0x100 ] = 13; - - } - - } - - // float16 to float32 helpers - - const mantissaTable = new Uint32Array( 2048 ); - const exponentTable = new Uint32Array( 64 ); - const offsetTable = new Uint32Array( 64 ); - - for ( let i = 1; i < 1024; ++ i ) { - - let m = i << 13; // zero pad mantissa bits - let e = 0; // zero exponent - - // normalized - while ( ( m & 0x00800000 ) === 0 ) { - - m <<= 1; - e -= 0x00800000; // decrement exponent - - } - - m &= ~ 0x00800000; // clear leading 1 bit - e += 0x38800000; // adjust bias - - mantissaTable[ i ] = m | e; - - } - - for ( let i = 1024; i < 2048; ++ i ) { - - mantissaTable[ i ] = 0x38000000 + ( ( i - 1024 ) << 13 ); - - } - - for ( let i = 1; i < 31; ++ i ) { - - exponentTable[ i ] = i << 23; - - } - - exponentTable[ 31 ] = 0x47800000; - exponentTable[ 32 ] = 0x80000000; - - for ( let i = 33; i < 63; ++ i ) { - - exponentTable[ i ] = 0x80000000 + ( ( i - 32 ) << 23 ); - - } - - exponentTable[ 63 ] = 0xc7800000; - - for ( let i = 1; i < 64; ++ i ) { - - if ( i !== 32 ) { - - offsetTable[ i ] = 1024; - - } - - } - - return { - floatView: floatView, - uint32View: uint32View, - baseTable: baseTable, - shiftTable: shiftTable, - mantissaTable: mantissaTable, - exponentTable: exponentTable, - offsetTable: offsetTable - }; - -} - -// float32 to float16 - -function toHalfFloat( val ) { - - if ( Math.abs( val ) > 65504 ) console.warn( 'THREE.DataUtils.toHalfFloat(): Value out of range.' ); - - val = clamp( val, - 65504, 65504 ); - - _tables.floatView[ 0 ] = val; - const f = _tables.uint32View[ 0 ]; - const e = ( f >> 23 ) & 0x1ff; - return _tables.baseTable[ e ] + ( ( f & 0x007fffff ) >> _tables.shiftTable[ e ] ); - -} - -// float16 to float32 - -function fromHalfFloat( val ) { - - const m = val >> 10; - _tables.uint32View[ 0 ] = _tables.mantissaTable[ _tables.offsetTable[ m ] + ( val & 0x3ff ) ] + _tables.exponentTable[ m ]; - return _tables.floatView[ 0 ]; - -} - -const DataUtils = { - toHalfFloat: toHalfFloat, - fromHalfFloat: fromHalfFloat, -}; - -const _vector$9 = /*@__PURE__*/ new Vector3(); -const _vector2$1 = /*@__PURE__*/ new Vector2(); - -class BufferAttribute { - - constructor( array, itemSize, normalized = false ) { - - if ( Array.isArray( array ) ) { - - throw new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' ); - - } - - this.isBufferAttribute = true; - - this.name = ''; - - this.array = array; - this.itemSize = itemSize; - this.count = array !== undefined ? array.length / itemSize : 0; - this.normalized = normalized; - - this.usage = StaticDrawUsage; - this._updateRange = { offset: 0, count: - 1 }; - this.updateRanges = []; - this.gpuType = FloatType; - - this.version = 0; - - } - - onUploadCallback() {} - - set needsUpdate( value ) { - - if ( value === true ) this.version ++; - - } - - get updateRange() { - - warnOnce( 'THREE.BufferAttribute: updateRange() is deprecated and will be removed in r169. Use addUpdateRange() instead.' ); // @deprecated, r159 - return this._updateRange; - - } - - setUsage( value ) { - - this.usage = value; - - return this; - - } - - addUpdateRange( start, count ) { - - this.updateRanges.push( { start, count } ); - - } - - clearUpdateRanges() { - - this.updateRanges.length = 0; - - } - - copy( source ) { - - this.name = source.name; - this.array = new source.array.constructor( source.array ); - this.itemSize = source.itemSize; - this.count = source.count; - this.normalized = source.normalized; - - this.usage = source.usage; - this.gpuType = source.gpuType; - - return this; - - } - - copyAt( index1, attribute, index2 ) { - - index1 *= this.itemSize; - index2 *= attribute.itemSize; - - for ( let i = 0, l = this.itemSize; i < l; i ++ ) { - - this.array[ index1 + i ] = attribute.array[ index2 + i ]; - - } - - return this; - - } - - copyArray( array ) { - - this.array.set( array ); - - return this; - - } - - applyMatrix3( m ) { - - if ( this.itemSize === 2 ) { - - for ( let i = 0, l = this.count; i < l; i ++ ) { - - _vector2$1.fromBufferAttribute( this, i ); - _vector2$1.applyMatrix3( m ); - - this.setXY( i, _vector2$1.x, _vector2$1.y ); - - } - - } else if ( this.itemSize === 3 ) { - - for ( let i = 0, l = this.count; i < l; i ++ ) { - - _vector$9.fromBufferAttribute( this, i ); - _vector$9.applyMatrix3( m ); - - this.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z ); - - } - - } - - return this; - - } - - applyMatrix4( m ) { - - for ( let i = 0, l = this.count; i < l; i ++ ) { - - _vector$9.fromBufferAttribute( this, i ); - - _vector$9.applyMatrix4( m ); - - this.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z ); - - } - - return this; - - } - - applyNormalMatrix( m ) { - - for ( let i = 0, l = this.count; i < l; i ++ ) { - - _vector$9.fromBufferAttribute( this, i ); - - _vector$9.applyNormalMatrix( m ); - - this.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z ); - - } - - return this; - - } - - transformDirection( m ) { - - for ( let i = 0, l = this.count; i < l; i ++ ) { - - _vector$9.fromBufferAttribute( this, i ); - - _vector$9.transformDirection( m ); - - this.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z ); - - } - - return this; - - } - - set( value, offset = 0 ) { - - // Matching BufferAttribute constructor, do not normalize the array. - this.array.set( value, offset ); - - return this; - - } - - getComponent( index, component ) { - - let value = this.array[ index * this.itemSize + component ]; - - if ( this.normalized ) value = denormalize( value, this.array ); - - return value; - - } - - setComponent( index, component, value ) { - - if ( this.normalized ) value = normalize( value, this.array ); - - this.array[ index * this.itemSize + component ] = value; - - return this; - - } - - getX( index ) { - - let x = this.array[ index * this.itemSize ]; - - if ( this.normalized ) x = denormalize( x, this.array ); - - return x; - - } - - setX( index, x ) { - - if ( this.normalized ) x = normalize( x, this.array ); - - this.array[ index * this.itemSize ] = x; - - return this; - - } - - getY( index ) { - - let y = this.array[ index * this.itemSize + 1 ]; - - if ( this.normalized ) y = denormalize( y, this.array ); - - return y; - - } - - setY( index, y ) { - - if ( this.normalized ) y = normalize( y, this.array ); - - this.array[ index * this.itemSize + 1 ] = y; - - return this; - - } - - getZ( index ) { - - let z = this.array[ index * this.itemSize + 2 ]; - - if ( this.normalized ) z = denormalize( z, this.array ); - - return z; - - } - - setZ( index, z ) { - - if ( this.normalized ) z = normalize( z, this.array ); - - this.array[ index * this.itemSize + 2 ] = z; - - return this; - - } - - getW( index ) { - - let w = this.array[ index * this.itemSize + 3 ]; - - if ( this.normalized ) w = denormalize( w, this.array ); - - return w; - - } - - setW( index, w ) { - - if ( this.normalized ) w = normalize( w, this.array ); - - this.array[ index * this.itemSize + 3 ] = w; - - return this; - - } - - setXY( index, x, y ) { - - index *= this.itemSize; - - if ( this.normalized ) { - - x = normalize( x, this.array ); - y = normalize( y, this.array ); - - } - - this.array[ index + 0 ] = x; - this.array[ index + 1 ] = y; - - return this; - - } - - setXYZ( index, x, y, z ) { - - index *= this.itemSize; - - if ( this.normalized ) { - - x = normalize( x, this.array ); - y = normalize( y, this.array ); - z = normalize( z, this.array ); - - } - - this.array[ index + 0 ] = x; - this.array[ index + 1 ] = y; - this.array[ index + 2 ] = z; - - return this; - - } - - setXYZW( index, x, y, z, w ) { - - index *= this.itemSize; - - if ( this.normalized ) { - - x = normalize( x, this.array ); - y = normalize( y, this.array ); - z = normalize( z, this.array ); - w = normalize( w, this.array ); - - } - - this.array[ index + 0 ] = x; - this.array[ index + 1 ] = y; - this.array[ index + 2 ] = z; - this.array[ index + 3 ] = w; - - return this; - - } - - onUpload( callback ) { - - this.onUploadCallback = callback; - - return this; - - } - - clone() { - - return new this.constructor( this.array, this.itemSize ).copy( this ); - - } - - toJSON() { - - const data = { - itemSize: this.itemSize, - type: this.array.constructor.name, - array: Array.from( this.array ), - normalized: this.normalized - }; - - if ( this.name !== '' ) data.name = this.name; - if ( this.usage !== StaticDrawUsage ) data.usage = this.usage; - - return data; - - } - -} - -// - -class Int8BufferAttribute extends BufferAttribute { - - constructor( array, itemSize, normalized ) { - - super( new Int8Array( array ), itemSize, normalized ); - - } - -} - -class Uint8BufferAttribute extends BufferAttribute { - - constructor( array, itemSize, normalized ) { - - super( new Uint8Array( array ), itemSize, normalized ); - - } - -} - -class Uint8ClampedBufferAttribute extends BufferAttribute { - - constructor( array, itemSize, normalized ) { - - super( new Uint8ClampedArray( array ), itemSize, normalized ); - - } - -} - -class Int16BufferAttribute extends BufferAttribute { - - constructor( array, itemSize, normalized ) { - - super( new Int16Array( array ), itemSize, normalized ); - - } - -} - -class Uint16BufferAttribute extends BufferAttribute { - - constructor( array, itemSize, normalized ) { - - super( new Uint16Array( array ), itemSize, normalized ); - - } - -} - -class Int32BufferAttribute extends BufferAttribute { - - constructor( array, itemSize, normalized ) { - - super( new Int32Array( array ), itemSize, normalized ); - - } - -} - -class Uint32BufferAttribute extends BufferAttribute { - - constructor( array, itemSize, normalized ) { - - super( new Uint32Array( array ), itemSize, normalized ); - - } - -} - -class Float16BufferAttribute extends BufferAttribute { - - constructor( array, itemSize, normalized ) { - - super( new Uint16Array( array ), itemSize, normalized ); - - this.isFloat16BufferAttribute = true; - - } - - getX( index ) { - - let x = fromHalfFloat( this.array[ index * this.itemSize ] ); - - if ( this.normalized ) x = denormalize( x, this.array ); - - return x; - - } - - setX( index, x ) { - - if ( this.normalized ) x = normalize( x, this.array ); - - this.array[ index * this.itemSize ] = toHalfFloat( x ); - - return this; - - } - - getY( index ) { - - let y = fromHalfFloat( this.array[ index * this.itemSize + 1 ] ); - - if ( this.normalized ) y = denormalize( y, this.array ); - - return y; - - } - - setY( index, y ) { - - if ( this.normalized ) y = normalize( y, this.array ); - - this.array[ index * this.itemSize + 1 ] = toHalfFloat( y ); - - return this; - - } - - getZ( index ) { - - let z = fromHalfFloat( this.array[ index * this.itemSize + 2 ] ); - - if ( this.normalized ) z = denormalize( z, this.array ); - - return z; - - } - - setZ( index, z ) { - - if ( this.normalized ) z = normalize( z, this.array ); - - this.array[ index * this.itemSize + 2 ] = toHalfFloat( z ); - - return this; - - } - - getW( index ) { - - let w = fromHalfFloat( this.array[ index * this.itemSize + 3 ] ); - - if ( this.normalized ) w = denormalize( w, this.array ); - - return w; - - } - - setW( index, w ) { - - if ( this.normalized ) w = normalize( w, this.array ); - - this.array[ index * this.itemSize + 3 ] = toHalfFloat( w ); - - return this; - - } - - setXY( index, x, y ) { - - index *= this.itemSize; - - if ( this.normalized ) { - - x = normalize( x, this.array ); - y = normalize( y, this.array ); - - } - - this.array[ index + 0 ] = toHalfFloat( x ); - this.array[ index + 1 ] = toHalfFloat( y ); - - return this; - - } - - setXYZ( index, x, y, z ) { - - index *= this.itemSize; - - if ( this.normalized ) { - - x = normalize( x, this.array ); - y = normalize( y, this.array ); - z = normalize( z, this.array ); - - } - - this.array[ index + 0 ] = toHalfFloat( x ); - this.array[ index + 1 ] = toHalfFloat( y ); - this.array[ index + 2 ] = toHalfFloat( z ); - - return this; - - } - - setXYZW( index, x, y, z, w ) { - - index *= this.itemSize; - - if ( this.normalized ) { - - x = normalize( x, this.array ); - y = normalize( y, this.array ); - z = normalize( z, this.array ); - w = normalize( w, this.array ); - - } - - this.array[ index + 0 ] = toHalfFloat( x ); - this.array[ index + 1 ] = toHalfFloat( y ); - this.array[ index + 2 ] = toHalfFloat( z ); - this.array[ index + 3 ] = toHalfFloat( w ); - - return this; - - } - -} - - -class Float32BufferAttribute extends BufferAttribute { - - constructor( array, itemSize, normalized ) { - - super( new Float32Array( array ), itemSize, normalized ); - - } - -} - -class Float64BufferAttribute extends BufferAttribute { - - constructor( array, itemSize, normalized ) { - - super( new Float64Array( array ), itemSize, normalized ); - - } - -} - -let _id$2 = 0; - -const _m1 = /*@__PURE__*/ new Matrix4(); -const _obj = /*@__PURE__*/ new Object3D(); -const _offset = /*@__PURE__*/ new Vector3(); -const _box$2 = /*@__PURE__*/ new Box3(); -const _boxMorphTargets = /*@__PURE__*/ new Box3(); -const _vector$8 = /*@__PURE__*/ new Vector3(); - -class BufferGeometry extends EventDispatcher { - - constructor() { - - super(); - - this.isBufferGeometry = true; - - Object.defineProperty( this, 'id', { value: _id$2 ++ } ); - - this.uuid = generateUUID(); - - this.name = ''; - this.type = 'BufferGeometry'; - - this.index = null; - this.attributes = {}; - - this.morphAttributes = {}; - this.morphTargetsRelative = false; - - this.groups = []; - - this.boundingBox = null; - this.boundingSphere = null; - - this.drawRange = { start: 0, count: Infinity }; - - this.userData = {}; - - } - - getIndex() { - - return this.index; - - } - - setIndex( index ) { - - if ( Array.isArray( index ) ) { - - this.index = new ( arrayNeedsUint32( index ) ? Uint32BufferAttribute : Uint16BufferAttribute )( index, 1 ); - - } else { - - this.index = index; - - } - - return this; - - } - - getAttribute( name ) { - - return this.attributes[ name ]; - - } - - setAttribute( name, attribute ) { - - this.attributes[ name ] = attribute; - - return this; - - } - - deleteAttribute( name ) { - - delete this.attributes[ name ]; - - return this; - - } - - hasAttribute( name ) { - - return this.attributes[ name ] !== undefined; - - } - - addGroup( start, count, materialIndex = 0 ) { - - this.groups.push( { - - start: start, - count: count, - materialIndex: materialIndex - - } ); - - } - - clearGroups() { - - this.groups = []; - - } - - setDrawRange( start, count ) { - - this.drawRange.start = start; - this.drawRange.count = count; - - } - - applyMatrix4( matrix ) { - - const position = this.attributes.position; - - if ( position !== undefined ) { - - position.applyMatrix4( matrix ); - - position.needsUpdate = true; - - } - - const normal = this.attributes.normal; - - if ( normal !== undefined ) { - - const normalMatrix = new Matrix3().getNormalMatrix( matrix ); - - normal.applyNormalMatrix( normalMatrix ); - - normal.needsUpdate = true; - - } - - const tangent = this.attributes.tangent; - - if ( tangent !== undefined ) { - - tangent.transformDirection( matrix ); - - tangent.needsUpdate = true; - - } - - if ( this.boundingBox !== null ) { - - this.computeBoundingBox(); - - } - - if ( this.boundingSphere !== null ) { - - this.computeBoundingSphere(); - - } - - return this; - - } - - applyQuaternion( q ) { - - _m1.makeRotationFromQuaternion( q ); - - this.applyMatrix4( _m1 ); - - return this; - - } - - rotateX( angle ) { - - // rotate geometry around world x-axis - - _m1.makeRotationX( angle ); - - this.applyMatrix4( _m1 ); - - return this; - - } - - rotateY( angle ) { - - // rotate geometry around world y-axis - - _m1.makeRotationY( angle ); - - this.applyMatrix4( _m1 ); - - return this; - - } - - rotateZ( angle ) { - - // rotate geometry around world z-axis - - _m1.makeRotationZ( angle ); - - this.applyMatrix4( _m1 ); - - return this; - - } - - translate( x, y, z ) { - - // translate geometry - - _m1.makeTranslation( x, y, z ); - - this.applyMatrix4( _m1 ); - - return this; - - } - - scale( x, y, z ) { - - // scale geometry - - _m1.makeScale( x, y, z ); - - this.applyMatrix4( _m1 ); - - return this; - - } - - lookAt( vector ) { - - _obj.lookAt( vector ); - - _obj.updateMatrix(); - - this.applyMatrix4( _obj.matrix ); - - return this; - - } - - center() { - - this.computeBoundingBox(); - - this.boundingBox.getCenter( _offset ).negate(); - - this.translate( _offset.x, _offset.y, _offset.z ); - - return this; - - } - - setFromPoints( points ) { - - const position = []; - - for ( let i = 0, l = points.length; i < l; i ++ ) { - - const point = points[ i ]; - position.push( point.x, point.y, point.z || 0 ); - - } - - this.setAttribute( 'position', new Float32BufferAttribute( position, 3 ) ); - - return this; - - } - - computeBoundingBox() { - - if ( this.boundingBox === null ) { - - this.boundingBox = new Box3(); - - } - - const position = this.attributes.position; - const morphAttributesPosition = this.morphAttributes.position; - - if ( position && position.isGLBufferAttribute ) { - - console.error( 'THREE.BufferGeometry.computeBoundingBox(): GLBufferAttribute requires a manual bounding box. Alternatively set "mesh.frustumCulled" to "false".', this ); - - this.boundingBox.set( - new Vector3( - Infinity, - Infinity, - Infinity ), - new Vector3( + Infinity, + Infinity, + Infinity ) - ); - - return; - - } - - if ( position !== undefined ) { - - this.boundingBox.setFromBufferAttribute( position ); - - // process morph attributes if present - - if ( morphAttributesPosition ) { - - for ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) { - - const morphAttribute = morphAttributesPosition[ i ]; - _box$2.setFromBufferAttribute( morphAttribute ); - - if ( this.morphTargetsRelative ) { - - _vector$8.addVectors( this.boundingBox.min, _box$2.min ); - this.boundingBox.expandByPoint( _vector$8 ); - - _vector$8.addVectors( this.boundingBox.max, _box$2.max ); - this.boundingBox.expandByPoint( _vector$8 ); - - } else { - - this.boundingBox.expandByPoint( _box$2.min ); - this.boundingBox.expandByPoint( _box$2.max ); - - } - - } - - } - - } else { - - this.boundingBox.makeEmpty(); - - } - - if ( isNaN( this.boundingBox.min.x ) || isNaN( this.boundingBox.min.y ) || isNaN( this.boundingBox.min.z ) ) { - - console.error( 'THREE.BufferGeometry.computeBoundingBox(): Computed min/max have NaN values. The "position" attribute is likely to have NaN values.', this ); - - } - - } - - computeBoundingSphere() { - - if ( this.boundingSphere === null ) { - - this.boundingSphere = new Sphere(); - - } - - const position = this.attributes.position; - const morphAttributesPosition = this.morphAttributes.position; - - if ( position && position.isGLBufferAttribute ) { - - console.error( 'THREE.BufferGeometry.computeBoundingSphere(): GLBufferAttribute requires a manual bounding sphere. Alternatively set "mesh.frustumCulled" to "false".', this ); - - this.boundingSphere.set( new Vector3(), Infinity ); - - return; - - } - - if ( position ) { - - // first, find the center of the bounding sphere - - const center = this.boundingSphere.center; - - _box$2.setFromBufferAttribute( position ); - - // process morph attributes if present - - if ( morphAttributesPosition ) { - - for ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) { - - const morphAttribute = morphAttributesPosition[ i ]; - _boxMorphTargets.setFromBufferAttribute( morphAttribute ); - - if ( this.morphTargetsRelative ) { - - _vector$8.addVectors( _box$2.min, _boxMorphTargets.min ); - _box$2.expandByPoint( _vector$8 ); - - _vector$8.addVectors( _box$2.max, _boxMorphTargets.max ); - _box$2.expandByPoint( _vector$8 ); - - } else { - - _box$2.expandByPoint( _boxMorphTargets.min ); - _box$2.expandByPoint( _boxMorphTargets.max ); - - } - - } - - } - - _box$2.getCenter( center ); - - // second, try to find a boundingSphere with a radius smaller than the - // boundingSphere of the boundingBox: sqrt(3) smaller in the best case - - let maxRadiusSq = 0; - - for ( let i = 0, il = position.count; i < il; i ++ ) { - - _vector$8.fromBufferAttribute( position, i ); - - maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( _vector$8 ) ); - - } - - // process morph attributes if present - - if ( morphAttributesPosition ) { - - for ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) { - - const morphAttribute = morphAttributesPosition[ i ]; - const morphTargetsRelative = this.morphTargetsRelative; - - for ( let j = 0, jl = morphAttribute.count; j < jl; j ++ ) { - - _vector$8.fromBufferAttribute( morphAttribute, j ); - - if ( morphTargetsRelative ) { - - _offset.fromBufferAttribute( position, j ); - _vector$8.add( _offset ); - - } - - maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( _vector$8 ) ); - - } - - } - - } - - this.boundingSphere.radius = Math.sqrt( maxRadiusSq ); - - if ( isNaN( this.boundingSphere.radius ) ) { - - console.error( 'THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.', this ); - - } - - } - - } - - computeTangents() { - - const index = this.index; - const attributes = this.attributes; - - // based on http://www.terathon.com/code/tangent.html - // (per vertex tangents) - - if ( index === null || - attributes.position === undefined || - attributes.normal === undefined || - attributes.uv === undefined ) { - - console.error( 'THREE.BufferGeometry: .computeTangents() failed. Missing required attributes (index, position, normal or uv)' ); - return; - - } - - const indices = index.array; - const positions = attributes.position.array; - const normals = attributes.normal.array; - const uvs = attributes.uv.array; - - const nVertices = positions.length / 3; - - if ( this.hasAttribute( 'tangent' ) === false ) { - - this.setAttribute( 'tangent', new BufferAttribute( new Float32Array( 4 * nVertices ), 4 ) ); - - } - - const tangents = this.getAttribute( 'tangent' ).array; - - const tan1 = [], tan2 = []; - - for ( let i = 0; i < nVertices; i ++ ) { - - tan1[ i ] = new Vector3(); - tan2[ i ] = new Vector3(); - - } - - const vA = new Vector3(), - vB = new Vector3(), - vC = new Vector3(), - - uvA = new Vector2(), - uvB = new Vector2(), - uvC = new Vector2(), - - sdir = new Vector3(), - tdir = new Vector3(); - - function handleTriangle( a, b, c ) { - - vA.fromArray( positions, a * 3 ); - vB.fromArray( positions, b * 3 ); - vC.fromArray( positions, c * 3 ); - - uvA.fromArray( uvs, a * 2 ); - uvB.fromArray( uvs, b * 2 ); - uvC.fromArray( uvs, c * 2 ); - - vB.sub( vA ); - vC.sub( vA ); - - uvB.sub( uvA ); - uvC.sub( uvA ); - - const r = 1.0 / ( uvB.x * uvC.y - uvC.x * uvB.y ); - - // silently ignore degenerate uv triangles having coincident or colinear vertices - - if ( ! isFinite( r ) ) return; - - sdir.copy( vB ).multiplyScalar( uvC.y ).addScaledVector( vC, - uvB.y ).multiplyScalar( r ); - tdir.copy( vC ).multiplyScalar( uvB.x ).addScaledVector( vB, - uvC.x ).multiplyScalar( r ); - - tan1[ a ].add( sdir ); - tan1[ b ].add( sdir ); - tan1[ c ].add( sdir ); - - tan2[ a ].add( tdir ); - tan2[ b ].add( tdir ); - tan2[ c ].add( tdir ); - - } - - let groups = this.groups; - - if ( groups.length === 0 ) { - - groups = [ { - start: 0, - count: indices.length - } ]; - - } - - for ( let i = 0, il = groups.length; i < il; ++ i ) { - - const group = groups[ i ]; - - const start = group.start; - const count = group.count; - - for ( let j = start, jl = start + count; j < jl; j += 3 ) { - - handleTriangle( - indices[ j + 0 ], - indices[ j + 1 ], - indices[ j + 2 ] - ); - - } - - } - - const tmp = new Vector3(), tmp2 = new Vector3(); - const n = new Vector3(), n2 = new Vector3(); - - function handleVertex( v ) { - - n.fromArray( normals, v * 3 ); - n2.copy( n ); - - const t = tan1[ v ]; - - // Gram-Schmidt orthogonalize - - tmp.copy( t ); - tmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize(); - - // Calculate handedness - - tmp2.crossVectors( n2, t ); - const test = tmp2.dot( tan2[ v ] ); - const w = ( test < 0.0 ) ? - 1.0 : 1.0; - - tangents[ v * 4 ] = tmp.x; - tangents[ v * 4 + 1 ] = tmp.y; - tangents[ v * 4 + 2 ] = tmp.z; - tangents[ v * 4 + 3 ] = w; - - } - - for ( let i = 0, il = groups.length; i < il; ++ i ) { - - const group = groups[ i ]; - - const start = group.start; - const count = group.count; - - for ( let j = start, jl = start + count; j < jl; j += 3 ) { - - handleVertex( indices[ j + 0 ] ); - handleVertex( indices[ j + 1 ] ); - handleVertex( indices[ j + 2 ] ); - - } - - } - - } - - computeVertexNormals() { - - const index = this.index; - const positionAttribute = this.getAttribute( 'position' ); - - if ( positionAttribute !== undefined ) { - - let normalAttribute = this.getAttribute( 'normal' ); - - if ( normalAttribute === undefined ) { - - normalAttribute = new BufferAttribute( new Float32Array( positionAttribute.count * 3 ), 3 ); - this.setAttribute( 'normal', normalAttribute ); - - } else { - - // reset existing normals to zero - - for ( let i = 0, il = normalAttribute.count; i < il; i ++ ) { - - normalAttribute.setXYZ( i, 0, 0, 0 ); - - } - - } - - const pA = new Vector3(), pB = new Vector3(), pC = new Vector3(); - const nA = new Vector3(), nB = new Vector3(), nC = new Vector3(); - const cb = new Vector3(), ab = new Vector3(); - - // indexed elements - - if ( index ) { - - for ( let i = 0, il = index.count; i < il; i += 3 ) { - - const vA = index.getX( i + 0 ); - const vB = index.getX( i + 1 ); - const vC = index.getX( i + 2 ); - - pA.fromBufferAttribute( positionAttribute, vA ); - pB.fromBufferAttribute( positionAttribute, vB ); - pC.fromBufferAttribute( positionAttribute, vC ); - - cb.subVectors( pC, pB ); - ab.subVectors( pA, pB ); - cb.cross( ab ); - - nA.fromBufferAttribute( normalAttribute, vA ); - nB.fromBufferAttribute( normalAttribute, vB ); - nC.fromBufferAttribute( normalAttribute, vC ); - - nA.add( cb ); - nB.add( cb ); - nC.add( cb ); - - normalAttribute.setXYZ( vA, nA.x, nA.y, nA.z ); - normalAttribute.setXYZ( vB, nB.x, nB.y, nB.z ); - normalAttribute.setXYZ( vC, nC.x, nC.y, nC.z ); - - } - - } else { - - // non-indexed elements (unconnected triangle soup) - - for ( let i = 0, il = positionAttribute.count; i < il; i += 3 ) { - - pA.fromBufferAttribute( positionAttribute, i + 0 ); - pB.fromBufferAttribute( positionAttribute, i + 1 ); - pC.fromBufferAttribute( positionAttribute, i + 2 ); - - cb.subVectors( pC, pB ); - ab.subVectors( pA, pB ); - cb.cross( ab ); - - normalAttribute.setXYZ( i + 0, cb.x, cb.y, cb.z ); - normalAttribute.setXYZ( i + 1, cb.x, cb.y, cb.z ); - normalAttribute.setXYZ( i + 2, cb.x, cb.y, cb.z ); - - } - - } - - this.normalizeNormals(); - - normalAttribute.needsUpdate = true; - - } - - } - - normalizeNormals() { - - const normals = this.attributes.normal; - - for ( let i = 0, il = normals.count; i < il; i ++ ) { - - _vector$8.fromBufferAttribute( normals, i ); - - _vector$8.normalize(); - - normals.setXYZ( i, _vector$8.x, _vector$8.y, _vector$8.z ); - - } - - } - - toNonIndexed() { - - function convertBufferAttribute( attribute, indices ) { - - const array = attribute.array; - const itemSize = attribute.itemSize; - const normalized = attribute.normalized; - - const array2 = new array.constructor( indices.length * itemSize ); - - let index = 0, index2 = 0; - - for ( let i = 0, l = indices.length; i < l; i ++ ) { - - if ( attribute.isInterleavedBufferAttribute ) { - - index = indices[ i ] * attribute.data.stride + attribute.offset; - - } else { - - index = indices[ i ] * itemSize; - - } - - for ( let j = 0; j < itemSize; j ++ ) { - - array2[ index2 ++ ] = array[ index ++ ]; - - } - - } - - return new BufferAttribute( array2, itemSize, normalized ); - - } - - // - - if ( this.index === null ) { - - console.warn( 'THREE.BufferGeometry.toNonIndexed(): BufferGeometry is already non-indexed.' ); - return this; - - } - - const geometry2 = new BufferGeometry(); - - const indices = this.index.array; - const attributes = this.attributes; - - // attributes - - for ( const name in attributes ) { - - const attribute = attributes[ name ]; - - const newAttribute = convertBufferAttribute( attribute, indices ); - - geometry2.setAttribute( name, newAttribute ); - - } - - // morph attributes - - const morphAttributes = this.morphAttributes; - - for ( const name in morphAttributes ) { - - const morphArray = []; - const morphAttribute = morphAttributes[ name ]; // morphAttribute: array of Float32BufferAttributes - - for ( let i = 0, il = morphAttribute.length; i < il; i ++ ) { - - const attribute = morphAttribute[ i ]; - - const newAttribute = convertBufferAttribute( attribute, indices ); - - morphArray.push( newAttribute ); - - } - - geometry2.morphAttributes[ name ] = morphArray; - - } - - geometry2.morphTargetsRelative = this.morphTargetsRelative; - - // groups - - const groups = this.groups; - - for ( let i = 0, l = groups.length; i < l; i ++ ) { - - const group = groups[ i ]; - geometry2.addGroup( group.start, group.count, group.materialIndex ); - - } - - return geometry2; - - } - - toJSON() { - - const data = { - metadata: { - version: 4.6, - type: 'BufferGeometry', - generator: 'BufferGeometry.toJSON' - } - }; - - // standard BufferGeometry serialization - - data.uuid = this.uuid; - data.type = this.type; - if ( this.name !== '' ) data.name = this.name; - if ( Object.keys( this.userData ).length > 0 ) data.userData = this.userData; - - if ( this.parameters !== undefined ) { - - const parameters = this.parameters; - - for ( const key in parameters ) { - - if ( parameters[ key ] !== undefined ) data[ key ] = parameters[ key ]; - - } - - return data; - - } - - // for simplicity the code assumes attributes are not shared across geometries, see #15811 - - data.data = { attributes: {} }; - - const index = this.index; - - if ( index !== null ) { - - data.data.index = { - type: index.array.constructor.name, - array: Array.prototype.slice.call( index.array ) - }; - - } - - const attributes = this.attributes; - - for ( const key in attributes ) { - - const attribute = attributes[ key ]; - - data.data.attributes[ key ] = attribute.toJSON( data.data ); - - } - - const morphAttributes = {}; - let hasMorphAttributes = false; - - for ( const key in this.morphAttributes ) { - - const attributeArray = this.morphAttributes[ key ]; - - const array = []; - - for ( let i = 0, il = attributeArray.length; i < il; i ++ ) { - - const attribute = attributeArray[ i ]; - - array.push( attribute.toJSON( data.data ) ); - - } - - if ( array.length > 0 ) { - - morphAttributes[ key ] = array; - - hasMorphAttributes = true; - - } - - } - - if ( hasMorphAttributes ) { - - data.data.morphAttributes = morphAttributes; - data.data.morphTargetsRelative = this.morphTargetsRelative; - - } - - const groups = this.groups; - - if ( groups.length > 0 ) { - - data.data.groups = JSON.parse( JSON.stringify( groups ) ); - - } - - const boundingSphere = this.boundingSphere; - - if ( boundingSphere !== null ) { - - data.data.boundingSphere = { - center: boundingSphere.center.toArray(), - radius: boundingSphere.radius - }; - - } - - return data; - - } - - clone() { - - return new this.constructor().copy( this ); - - } - - copy( source ) { - - // reset - - this.index = null; - this.attributes = {}; - this.morphAttributes = {}; - this.groups = []; - this.boundingBox = null; - this.boundingSphere = null; - - // used for storing cloned, shared data - - const data = {}; - - // name - - this.name = source.name; - - // index - - const index = source.index; - - if ( index !== null ) { - - this.setIndex( index.clone( data ) ); - - } - - // attributes - - const attributes = source.attributes; - - for ( const name in attributes ) { - - const attribute = attributes[ name ]; - this.setAttribute( name, attribute.clone( data ) ); - - } - - // morph attributes - - const morphAttributes = source.morphAttributes; - - for ( const name in morphAttributes ) { - - const array = []; - const morphAttribute = morphAttributes[ name ]; // morphAttribute: array of Float32BufferAttributes - - for ( let i = 0, l = morphAttribute.length; i < l; i ++ ) { - - array.push( morphAttribute[ i ].clone( data ) ); - - } - - this.morphAttributes[ name ] = array; - - } - - this.morphTargetsRelative = source.morphTargetsRelative; - - // groups - - const groups = source.groups; - - for ( let i = 0, l = groups.length; i < l; i ++ ) { - - const group = groups[ i ]; - this.addGroup( group.start, group.count, group.materialIndex ); - - } - - // bounding box - - const boundingBox = source.boundingBox; - - if ( boundingBox !== null ) { - - this.boundingBox = boundingBox.clone(); - - } - - // bounding sphere - - const boundingSphere = source.boundingSphere; - - if ( boundingSphere !== null ) { - - this.boundingSphere = boundingSphere.clone(); - - } - - // draw range - - this.drawRange.start = source.drawRange.start; - this.drawRange.count = source.drawRange.count; - - // user data - - this.userData = source.userData; - - return this; - - } - - dispose() { - - this.dispatchEvent( { type: 'dispose' } ); - - } - -} - -const _inverseMatrix$3 = /*@__PURE__*/ new Matrix4(); -const _ray$3 = /*@__PURE__*/ new Ray(); -const _sphere$6 = /*@__PURE__*/ new Sphere(); -const _sphereHitAt = /*@__PURE__*/ new Vector3(); - -const _vA$1 = /*@__PURE__*/ new Vector3(); -const _vB$1 = /*@__PURE__*/ new Vector3(); -const _vC$1 = /*@__PURE__*/ new Vector3(); - -const _tempA = /*@__PURE__*/ new Vector3(); -const _morphA = /*@__PURE__*/ new Vector3(); - -const _uvA$1 = /*@__PURE__*/ new Vector2(); -const _uvB$1 = /*@__PURE__*/ new Vector2(); -const _uvC$1 = /*@__PURE__*/ new Vector2(); - -const _normalA = /*@__PURE__*/ new Vector3(); -const _normalB = /*@__PURE__*/ new Vector3(); -const _normalC = /*@__PURE__*/ new Vector3(); - -const _intersectionPoint = /*@__PURE__*/ new Vector3(); -const _intersectionPointWorld = /*@__PURE__*/ new Vector3(); - -class Mesh extends Object3D { - - constructor( geometry = new BufferGeometry(), material = new MeshBasicMaterial() ) { - - super(); - - this.isMesh = true; - - this.type = 'Mesh'; - - this.geometry = geometry; - this.material = material; - - this.updateMorphTargets(); - - } - - copy( source, recursive ) { - - super.copy( source, recursive ); - - if ( source.morphTargetInfluences !== undefined ) { - - this.morphTargetInfluences = source.morphTargetInfluences.slice(); - - } - - if ( source.morphTargetDictionary !== undefined ) { - - this.morphTargetDictionary = Object.assign( {}, source.morphTargetDictionary ); - - } - - this.material = Array.isArray( source.material ) ? source.material.slice() : source.material; - this.geometry = source.geometry; - - return this; - - } - - updateMorphTargets() { - - const geometry = this.geometry; - - const morphAttributes = geometry.morphAttributes; - const keys = Object.keys( morphAttributes ); - - if ( keys.length > 0 ) { - - const morphAttribute = morphAttributes[ keys[ 0 ] ]; - - if ( morphAttribute !== undefined ) { - - this.morphTargetInfluences = []; - this.morphTargetDictionary = {}; - - for ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) { - - const name = morphAttribute[ m ].name || String( m ); - - this.morphTargetInfluences.push( 0 ); - this.morphTargetDictionary[ name ] = m; - - } - - } - - } - - } - - getVertexPosition( index, target ) { - - const geometry = this.geometry; - const position = geometry.attributes.position; - const morphPosition = geometry.morphAttributes.position; - const morphTargetsRelative = geometry.morphTargetsRelative; - - target.fromBufferAttribute( position, index ); - - const morphInfluences = this.morphTargetInfluences; - - if ( morphPosition && morphInfluences ) { - - _morphA.set( 0, 0, 0 ); - - for ( let i = 0, il = morphPosition.length; i < il; i ++ ) { - - const influence = morphInfluences[ i ]; - const morphAttribute = morphPosition[ i ]; - - if ( influence === 0 ) continue; - - _tempA.fromBufferAttribute( morphAttribute, index ); - - if ( morphTargetsRelative ) { - - _morphA.addScaledVector( _tempA, influence ); - - } else { - - _morphA.addScaledVector( _tempA.sub( target ), influence ); - - } - - } - - target.add( _morphA ); - - } - - return target; - - } - - raycast( raycaster, intersects ) { - - const geometry = this.geometry; - const material = this.material; - const matrixWorld = this.matrixWorld; - - if ( material === undefined ) return; - - // test with bounding sphere in world space - - if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); - - _sphere$6.copy( geometry.boundingSphere ); - _sphere$6.applyMatrix4( matrixWorld ); - - // check distance from ray origin to bounding sphere - - _ray$3.copy( raycaster.ray ).recast( raycaster.near ); - - if ( _sphere$6.containsPoint( _ray$3.origin ) === false ) { - - if ( _ray$3.intersectSphere( _sphere$6, _sphereHitAt ) === null ) return; - - if ( _ray$3.origin.distanceToSquared( _sphereHitAt ) > ( raycaster.far - raycaster.near ) ** 2 ) return; - - } - - // convert ray to local space of mesh - - _inverseMatrix$3.copy( matrixWorld ).invert(); - _ray$3.copy( raycaster.ray ).applyMatrix4( _inverseMatrix$3 ); - - // test with bounding box in local space - - if ( geometry.boundingBox !== null ) { - - if ( _ray$3.intersectsBox( geometry.boundingBox ) === false ) return; - - } - - // test for intersections with geometry - - this._computeIntersections( raycaster, intersects, _ray$3 ); - - } - - _computeIntersections( raycaster, intersects, rayLocalSpace ) { - - let intersection; - - const geometry = this.geometry; - const material = this.material; - - const index = geometry.index; - const position = geometry.attributes.position; - const uv = geometry.attributes.uv; - const uv1 = geometry.attributes.uv1; - const normal = geometry.attributes.normal; - const groups = geometry.groups; - const drawRange = geometry.drawRange; - - if ( index !== null ) { - - // indexed buffer geometry - - if ( Array.isArray( material ) ) { - - for ( let i = 0, il = groups.length; i < il; i ++ ) { - - const group = groups[ i ]; - const groupMaterial = material[ group.materialIndex ]; - - const start = Math.max( group.start, drawRange.start ); - const end = Math.min( index.count, Math.min( ( group.start + group.count ), ( drawRange.start + drawRange.count ) ) ); - - for ( let j = start, jl = end; j < jl; j += 3 ) { - - const a = index.getX( j ); - const b = index.getX( j + 1 ); - const c = index.getX( j + 2 ); - - intersection = checkGeometryIntersection( this, groupMaterial, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c ); - - if ( intersection ) { - - intersection.faceIndex = Math.floor( j / 3 ); // triangle number in indexed buffer semantics - intersection.face.materialIndex = group.materialIndex; - intersects.push( intersection ); - - } - - } - - } - - } else { - - const start = Math.max( 0, drawRange.start ); - const end = Math.min( index.count, ( drawRange.start + drawRange.count ) ); - - for ( let i = start, il = end; i < il; i += 3 ) { - - const a = index.getX( i ); - const b = index.getX( i + 1 ); - const c = index.getX( i + 2 ); - - intersection = checkGeometryIntersection( this, material, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c ); - - if ( intersection ) { - - intersection.faceIndex = Math.floor( i / 3 ); // triangle number in indexed buffer semantics - intersects.push( intersection ); - - } - - } - - } - - } else if ( position !== undefined ) { - - // non-indexed buffer geometry - - if ( Array.isArray( material ) ) { - - for ( let i = 0, il = groups.length; i < il; i ++ ) { - - const group = groups[ i ]; - const groupMaterial = material[ group.materialIndex ]; - - const start = Math.max( group.start, drawRange.start ); - const end = Math.min( position.count, Math.min( ( group.start + group.count ), ( drawRange.start + drawRange.count ) ) ); - - for ( let j = start, jl = end; j < jl; j += 3 ) { - - const a = j; - const b = j + 1; - const c = j + 2; - - intersection = checkGeometryIntersection( this, groupMaterial, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c ); - - if ( intersection ) { - - intersection.faceIndex = Math.floor( j / 3 ); // triangle number in non-indexed buffer semantics - intersection.face.materialIndex = group.materialIndex; - intersects.push( intersection ); - - } - - } - - } - - } else { - - const start = Math.max( 0, drawRange.start ); - const end = Math.min( position.count, ( drawRange.start + drawRange.count ) ); - - for ( let i = start, il = end; i < il; i += 3 ) { - - const a = i; - const b = i + 1; - const c = i + 2; - - intersection = checkGeometryIntersection( this, material, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c ); - - if ( intersection ) { - - intersection.faceIndex = Math.floor( i / 3 ); // triangle number in non-indexed buffer semantics - intersects.push( intersection ); - - } - - } - - } - - } - - } - -} - -function checkIntersection( object, material, raycaster, ray, pA, pB, pC, point ) { - - let intersect; - - if ( material.side === BackSide ) { - - intersect = ray.intersectTriangle( pC, pB, pA, true, point ); - - } else { - - intersect = ray.intersectTriangle( pA, pB, pC, ( material.side === FrontSide ), point ); - - } - - if ( intersect === null ) return null; - - _intersectionPointWorld.copy( point ); - _intersectionPointWorld.applyMatrix4( object.matrixWorld ); - - const distance = raycaster.ray.origin.distanceTo( _intersectionPointWorld ); - - if ( distance < raycaster.near || distance > raycaster.far ) return null; - - return { - distance: distance, - point: _intersectionPointWorld.clone(), - object: object - }; - -} - -function checkGeometryIntersection( object, material, raycaster, ray, uv, uv1, normal, a, b, c ) { - - object.getVertexPosition( a, _vA$1 ); - object.getVertexPosition( b, _vB$1 ); - object.getVertexPosition( c, _vC$1 ); - - const intersection = checkIntersection( object, material, raycaster, ray, _vA$1, _vB$1, _vC$1, _intersectionPoint ); - - if ( intersection ) { - - if ( uv ) { - - _uvA$1.fromBufferAttribute( uv, a ); - _uvB$1.fromBufferAttribute( uv, b ); - _uvC$1.fromBufferAttribute( uv, c ); - - intersection.uv = Triangle.getInterpolation( _intersectionPoint, _vA$1, _vB$1, _vC$1, _uvA$1, _uvB$1, _uvC$1, new Vector2() ); - - } - - if ( uv1 ) { - - _uvA$1.fromBufferAttribute( uv1, a ); - _uvB$1.fromBufferAttribute( uv1, b ); - _uvC$1.fromBufferAttribute( uv1, c ); - - intersection.uv1 = Triangle.getInterpolation( _intersectionPoint, _vA$1, _vB$1, _vC$1, _uvA$1, _uvB$1, _uvC$1, new Vector2() ); - - } - - if ( normal ) { - - _normalA.fromBufferAttribute( normal, a ); - _normalB.fromBufferAttribute( normal, b ); - _normalC.fromBufferAttribute( normal, c ); - - intersection.normal = Triangle.getInterpolation( _intersectionPoint, _vA$1, _vB$1, _vC$1, _normalA, _normalB, _normalC, new Vector3() ); - - if ( intersection.normal.dot( ray.direction ) > 0 ) { - - intersection.normal.multiplyScalar( - 1 ); - - } - - } - - const face = { - a: a, - b: b, - c: c, - normal: new Vector3(), - materialIndex: 0 - }; - - Triangle.getNormal( _vA$1, _vB$1, _vC$1, face.normal ); - - intersection.face = face; - - } - - return intersection; - -} - -class BoxGeometry extends BufferGeometry { - - constructor( width = 1, height = 1, depth = 1, widthSegments = 1, heightSegments = 1, depthSegments = 1 ) { - - super(); - - this.type = 'BoxGeometry'; - - this.parameters = { - width: width, - height: height, - depth: depth, - widthSegments: widthSegments, - heightSegments: heightSegments, - depthSegments: depthSegments - }; - - const scope = this; - - // segments - - widthSegments = Math.floor( widthSegments ); - heightSegments = Math.floor( heightSegments ); - depthSegments = Math.floor( depthSegments ); - - // buffers - - const indices = []; - const vertices = []; - const normals = []; - const uvs = []; - - // helper variables - - let numberOfVertices = 0; - let groupStart = 0; - - // build each side of the box geometry - - buildPlane( 'z', 'y', 'x', - 1, - 1, depth, height, width, depthSegments, heightSegments, 0 ); // px - buildPlane( 'z', 'y', 'x', 1, - 1, depth, height, - width, depthSegments, heightSegments, 1 ); // nx - buildPlane( 'x', 'z', 'y', 1, 1, width, depth, height, widthSegments, depthSegments, 2 ); // py - buildPlane( 'x', 'z', 'y', 1, - 1, width, depth, - height, widthSegments, depthSegments, 3 ); // ny - buildPlane( 'x', 'y', 'z', 1, - 1, width, height, depth, widthSegments, heightSegments, 4 ); // pz - buildPlane( 'x', 'y', 'z', - 1, - 1, width, height, - depth, widthSegments, heightSegments, 5 ); // nz - - // build geometry - - this.setIndex( indices ); - this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - - function buildPlane( u, v, w, udir, vdir, width, height, depth, gridX, gridY, materialIndex ) { - - const segmentWidth = width / gridX; - const segmentHeight = height / gridY; - - const widthHalf = width / 2; - const heightHalf = height / 2; - const depthHalf = depth / 2; - - const gridX1 = gridX + 1; - const gridY1 = gridY + 1; - - let vertexCounter = 0; - let groupCount = 0; - - const vector = new Vector3(); - - // generate vertices, normals and uvs - - for ( let iy = 0; iy < gridY1; iy ++ ) { - - const y = iy * segmentHeight - heightHalf; - - for ( let ix = 0; ix < gridX1; ix ++ ) { - - const x = ix * segmentWidth - widthHalf; - - // set values to correct vector component - - vector[ u ] = x * udir; - vector[ v ] = y * vdir; - vector[ w ] = depthHalf; - - // now apply vector to vertex buffer - - vertices.push( vector.x, vector.y, vector.z ); - - // set values to correct vector component - - vector[ u ] = 0; - vector[ v ] = 0; - vector[ w ] = depth > 0 ? 1 : - 1; - - // now apply vector to normal buffer - - normals.push( vector.x, vector.y, vector.z ); - - // uvs - - uvs.push( ix / gridX ); - uvs.push( 1 - ( iy / gridY ) ); - - // counters - - vertexCounter += 1; - - } - - } - - // indices - - // 1. you need three indices to draw a single face - // 2. a single segment consists of two faces - // 3. so we need to generate six (2*3) indices per segment - - for ( let iy = 0; iy < gridY; iy ++ ) { - - for ( let ix = 0; ix < gridX; ix ++ ) { - - const a = numberOfVertices + ix + gridX1 * iy; - const b = numberOfVertices + ix + gridX1 * ( iy + 1 ); - const c = numberOfVertices + ( ix + 1 ) + gridX1 * ( iy + 1 ); - const d = numberOfVertices + ( ix + 1 ) + gridX1 * iy; - - // faces - - indices.push( a, b, d ); - indices.push( b, c, d ); - - // increase counter - - groupCount += 6; - - } - - } - - // add a group to the geometry. this will ensure multi material support - - scope.addGroup( groupStart, groupCount, materialIndex ); - - // calculate new start value for groups - - groupStart += groupCount; - - // update total number of vertices - - numberOfVertices += vertexCounter; - - } - - } - - copy( source ) { - - super.copy( source ); - - this.parameters = Object.assign( {}, source.parameters ); - - return this; - - } - - static fromJSON( data ) { - - return new BoxGeometry( data.width, data.height, data.depth, data.widthSegments, data.heightSegments, data.depthSegments ); - - } - -} - -/** - * Uniform Utilities - */ - -function cloneUniforms( src ) { - - const dst = {}; - - for ( const u in src ) { - - dst[ u ] = {}; - - for ( const p in src[ u ] ) { - - const property = src[ u ][ p ]; - - if ( property && ( property.isColor || - property.isMatrix3 || property.isMatrix4 || - property.isVector2 || property.isVector3 || property.isVector4 || - property.isTexture || property.isQuaternion ) ) { - - if ( property.isRenderTargetTexture ) { - - console.warn( 'UniformsUtils: Textures of render targets cannot be cloned via cloneUniforms() or mergeUniforms().' ); - dst[ u ][ p ] = null; - - } else { - - dst[ u ][ p ] = property.clone(); - - } - - } else if ( Array.isArray( property ) ) { - - dst[ u ][ p ] = property.slice(); - - } else { - - dst[ u ][ p ] = property; - - } - - } - - } - - return dst; - -} - -function mergeUniforms( uniforms ) { - - const merged = {}; - - for ( let u = 0; u < uniforms.length; u ++ ) { - - const tmp = cloneUniforms( uniforms[ u ] ); - - for ( const p in tmp ) { - - merged[ p ] = tmp[ p ]; - - } - - } - - return merged; - -} - -function cloneUniformsGroups( src ) { - - const dst = []; - - for ( let u = 0; u < src.length; u ++ ) { - - dst.push( src[ u ].clone() ); - - } - - return dst; - -} - -function getUnlitUniformColorSpace( renderer ) { - - if ( renderer.getRenderTarget() === null ) { - - // https://github.com/mrdoob/three.js/pull/23937#issuecomment-1111067398 - return renderer.outputColorSpace; - - } - - return ColorManagement.workingColorSpace; - -} - -// Legacy - -const UniformsUtils = { clone: cloneUniforms, merge: mergeUniforms }; - -var default_vertex = "void main() {\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}"; - -var default_fragment = "void main() {\n\tgl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );\n}"; - -class ShaderMaterial extends Material { - - constructor( parameters ) { - - super(); - - this.isShaderMaterial = true; - - this.type = 'ShaderMaterial'; - - this.defines = {}; - this.uniforms = {}; - this.uniformsGroups = []; - - this.vertexShader = default_vertex; - this.fragmentShader = default_fragment; - - this.linewidth = 1; - - this.wireframe = false; - this.wireframeLinewidth = 1; - - this.fog = false; // set to use scene fog - this.lights = false; // set to use scene lights - this.clipping = false; // set to use user-defined clipping planes - - this.forceSinglePass = true; - - this.extensions = { - derivatives: false, // set to use derivatives - fragDepth: false, // set to use fragment depth values - drawBuffers: false, // set to use draw buffers - shaderTextureLOD: false, // set to use shader texture LOD - clipCullDistance: false, // set to use vertex shader clipping - multiDraw: false // set to use vertex shader multi_draw / enable gl_DrawID - }; - - // When rendered geometry doesn't include these attributes but the material does, - // use these default values in WebGL. This avoids errors when buffer data is missing. - this.defaultAttributeValues = { - 'color': [ 1, 1, 1 ], - 'uv': [ 0, 0 ], - 'uv1': [ 0, 0 ] - }; - - this.index0AttributeName = undefined; - this.uniformsNeedUpdate = false; - - this.glslVersion = null; - - if ( parameters !== undefined ) { - - this.setValues( parameters ); - - } - - } - - copy( source ) { - - super.copy( source ); - - this.fragmentShader = source.fragmentShader; - this.vertexShader = source.vertexShader; - - this.uniforms = cloneUniforms( source.uniforms ); - this.uniformsGroups = cloneUniformsGroups( source.uniformsGroups ); - - this.defines = Object.assign( {}, source.defines ); - - this.wireframe = source.wireframe; - this.wireframeLinewidth = source.wireframeLinewidth; - - this.fog = source.fog; - this.lights = source.lights; - this.clipping = source.clipping; - - this.extensions = Object.assign( {}, source.extensions ); - - this.glslVersion = source.glslVersion; - - return this; - - } - - toJSON( meta ) { - - const data = super.toJSON( meta ); - - data.glslVersion = this.glslVersion; - data.uniforms = {}; - - for ( const name in this.uniforms ) { - - const uniform = this.uniforms[ name ]; - const value = uniform.value; - - if ( value && value.isTexture ) { - - data.uniforms[ name ] = { - type: 't', - value: value.toJSON( meta ).uuid - }; - - } else if ( value && value.isColor ) { - - data.uniforms[ name ] = { - type: 'c', - value: value.getHex() - }; - - } else if ( value && value.isVector2 ) { - - data.uniforms[ name ] = { - type: 'v2', - value: value.toArray() - }; - - } else if ( value && value.isVector3 ) { - - data.uniforms[ name ] = { - type: 'v3', - value: value.toArray() - }; - - } else if ( value && value.isVector4 ) { - - data.uniforms[ name ] = { - type: 'v4', - value: value.toArray() - }; - - } else if ( value && value.isMatrix3 ) { - - data.uniforms[ name ] = { - type: 'm3', - value: value.toArray() - }; - - } else if ( value && value.isMatrix4 ) { - - data.uniforms[ name ] = { - type: 'm4', - value: value.toArray() - }; - - } else { - - data.uniforms[ name ] = { - value: value - }; - - // note: the array variants v2v, v3v, v4v, m4v and tv are not supported so far - - } - - } - - if ( Object.keys( this.defines ).length > 0 ) data.defines = this.defines; - - data.vertexShader = this.vertexShader; - data.fragmentShader = this.fragmentShader; - - data.lights = this.lights; - data.clipping = this.clipping; - - const extensions = {}; - - for ( const key in this.extensions ) { - - if ( this.extensions[ key ] === true ) extensions[ key ] = true; - - } - - if ( Object.keys( extensions ).length > 0 ) data.extensions = extensions; - - return data; - - } - -} - -class Camera extends Object3D { - - constructor() { - - super(); - - this.isCamera = true; - - this.type = 'Camera'; - - this.matrixWorldInverse = new Matrix4(); - - this.projectionMatrix = new Matrix4(); - this.projectionMatrixInverse = new Matrix4(); - - this.coordinateSystem = WebGLCoordinateSystem; - - } - - copy( source, recursive ) { - - super.copy( source, recursive ); - - this.matrixWorldInverse.copy( source.matrixWorldInverse ); - - this.projectionMatrix.copy( source.projectionMatrix ); - this.projectionMatrixInverse.copy( source.projectionMatrixInverse ); - - this.coordinateSystem = source.coordinateSystem; - - return this; - - } - - getWorldDirection( target ) { - - return super.getWorldDirection( target ).negate(); - - } - - updateMatrixWorld( force ) { - - super.updateMatrixWorld( force ); - - this.matrixWorldInverse.copy( this.matrixWorld ).invert(); - - } - - updateWorldMatrix( updateParents, updateChildren ) { - - super.updateWorldMatrix( updateParents, updateChildren ); - - this.matrixWorldInverse.copy( this.matrixWorld ).invert(); - - } - - clone() { - - return new this.constructor().copy( this ); - - } - -} - -const _v3$1 = /*@__PURE__*/ new Vector3(); -const _minTarget = /*@__PURE__*/ new Vector2(); -const _maxTarget = /*@__PURE__*/ new Vector2(); - - -class PerspectiveCamera extends Camera { - - constructor( fov = 50, aspect = 1, near = 0.1, far = 2000 ) { - - super(); - - this.isPerspectiveCamera = true; - - this.type = 'PerspectiveCamera'; - - this.fov = fov; - this.zoom = 1; - - this.near = near; - this.far = far; - this.focus = 10; - - this.aspect = aspect; - this.view = null; - - this.filmGauge = 35; // width of the film (default in millimeters) - this.filmOffset = 0; // horizontal film offset (same unit as gauge) - - this.updateProjectionMatrix(); - - } - - copy( source, recursive ) { - - super.copy( source, recursive ); - - this.fov = source.fov; - this.zoom = source.zoom; - - this.near = source.near; - this.far = source.far; - this.focus = source.focus; - - this.aspect = source.aspect; - this.view = source.view === null ? null : Object.assign( {}, source.view ); - - this.filmGauge = source.filmGauge; - this.filmOffset = source.filmOffset; - - return this; - - } - - /** - * Sets the FOV by focal length in respect to the current .filmGauge. - * - * The default film gauge is 35, so that the focal length can be specified for - * a 35mm (full frame) camera. - * - * Values for focal length and film gauge must have the same unit. - */ - setFocalLength( focalLength ) { - - /** see {@link http://www.bobatkins.com/photography/technical/field_of_view.html} */ - const vExtentSlope = 0.5 * this.getFilmHeight() / focalLength; - - this.fov = RAD2DEG * 2 * Math.atan( vExtentSlope ); - this.updateProjectionMatrix(); - - } - - /** - * Calculates the focal length from the current .fov and .filmGauge. - */ - getFocalLength() { - - const vExtentSlope = Math.tan( DEG2RAD * 0.5 * this.fov ); - - return 0.5 * this.getFilmHeight() / vExtentSlope; - - } - - getEffectiveFOV() { - - return RAD2DEG * 2 * Math.atan( - Math.tan( DEG2RAD * 0.5 * this.fov ) / this.zoom ); - - } - - getFilmWidth() { - - // film not completely covered in portrait format (aspect < 1) - return this.filmGauge * Math.min( this.aspect, 1 ); - - } - - getFilmHeight() { - - // film not completely covered in landscape format (aspect > 1) - return this.filmGauge / Math.max( this.aspect, 1 ); - - } - - /** - * Computes the 2D bounds of the camera's viewable rectangle at a given distance along the viewing direction. - * Sets minTarget and maxTarget to the coordinates of the lower-left and upper-right corners of the view rectangle. - */ - getViewBounds( distance, minTarget, maxTarget ) { - - _v3$1.set( - 1, - 1, 0.5 ).applyMatrix4( this.projectionMatrixInverse ); - - minTarget.set( _v3$1.x, _v3$1.y ).multiplyScalar( - distance / _v3$1.z ); - - _v3$1.set( 1, 1, 0.5 ).applyMatrix4( this.projectionMatrixInverse ); - - maxTarget.set( _v3$1.x, _v3$1.y ).multiplyScalar( - distance / _v3$1.z ); - - } - - /** - * Computes the width and height of the camera's viewable rectangle at a given distance along the viewing direction. - * Copies the result into the target Vector2, where x is width and y is height. - */ - getViewSize( distance, target ) { - - this.getViewBounds( distance, _minTarget, _maxTarget ); - - return target.subVectors( _maxTarget, _minTarget ); - - } - - /** - * Sets an offset in a larger frustum. This is useful for multi-window or - * multi-monitor/multi-machine setups. - * - * For example, if you have 3x2 monitors and each monitor is 1920x1080 and - * the monitors are in grid like this - * - * +---+---+---+ - * | A | B | C | - * +---+---+---+ - * | D | E | F | - * +---+---+---+ - * - * then for each monitor you would call it like this - * - * const w = 1920; - * const h = 1080; - * const fullWidth = w * 3; - * const fullHeight = h * 2; - * - * --A-- - * camera.setViewOffset( fullWidth, fullHeight, w * 0, h * 0, w, h ); - * --B-- - * camera.setViewOffset( fullWidth, fullHeight, w * 1, h * 0, w, h ); - * --C-- - * camera.setViewOffset( fullWidth, fullHeight, w * 2, h * 0, w, h ); - * --D-- - * camera.setViewOffset( fullWidth, fullHeight, w * 0, h * 1, w, h ); - * --E-- - * camera.setViewOffset( fullWidth, fullHeight, w * 1, h * 1, w, h ); - * --F-- - * camera.setViewOffset( fullWidth, fullHeight, w * 2, h * 1, w, h ); - * - * Note there is no reason monitors have to be the same size or in a grid. - */ - setViewOffset( fullWidth, fullHeight, x, y, width, height ) { - - this.aspect = fullWidth / fullHeight; - - if ( this.view === null ) { - - this.view = { - enabled: true, - fullWidth: 1, - fullHeight: 1, - offsetX: 0, - offsetY: 0, - width: 1, - height: 1 - }; - - } - - this.view.enabled = true; - this.view.fullWidth = fullWidth; - this.view.fullHeight = fullHeight; - this.view.offsetX = x; - this.view.offsetY = y; - this.view.width = width; - this.view.height = height; - - this.updateProjectionMatrix(); - - } - - clearViewOffset() { - - if ( this.view !== null ) { - - this.view.enabled = false; - - } - - this.updateProjectionMatrix(); - - } - - updateProjectionMatrix() { - - const near = this.near; - let top = near * Math.tan( DEG2RAD * 0.5 * this.fov ) / this.zoom; - let height = 2 * top; - let width = this.aspect * height; - let left = - 0.5 * width; - const view = this.view; - - if ( this.view !== null && this.view.enabled ) { - - const fullWidth = view.fullWidth, - fullHeight = view.fullHeight; - - left += view.offsetX * width / fullWidth; - top -= view.offsetY * height / fullHeight; - width *= view.width / fullWidth; - height *= view.height / fullHeight; - - } - - const skew = this.filmOffset; - if ( skew !== 0 ) left += near * skew / this.getFilmWidth(); - - this.projectionMatrix.makePerspective( left, left + width, top, top - height, near, this.far, this.coordinateSystem ); - - this.projectionMatrixInverse.copy( this.projectionMatrix ).invert(); - - } - - toJSON( meta ) { - - const data = super.toJSON( meta ); - - data.object.fov = this.fov; - data.object.zoom = this.zoom; - - data.object.near = this.near; - data.object.far = this.far; - data.object.focus = this.focus; - - data.object.aspect = this.aspect; - - if ( this.view !== null ) data.object.view = Object.assign( {}, this.view ); - - data.object.filmGauge = this.filmGauge; - data.object.filmOffset = this.filmOffset; - - return data; - - } - -} - -const fov = - 90; // negative fov is not an error -const aspect = 1; - -class CubeCamera extends Object3D { - - constructor( near, far, renderTarget ) { - - super(); - - this.type = 'CubeCamera'; - - this.renderTarget = renderTarget; - this.coordinateSystem = null; - this.activeMipmapLevel = 0; - - const cameraPX = new PerspectiveCamera( fov, aspect, near, far ); - cameraPX.layers = this.layers; - this.add( cameraPX ); - - const cameraNX = new PerspectiveCamera( fov, aspect, near, far ); - cameraNX.layers = this.layers; - this.add( cameraNX ); - - const cameraPY = new PerspectiveCamera( fov, aspect, near, far ); - cameraPY.layers = this.layers; - this.add( cameraPY ); - - const cameraNY = new PerspectiveCamera( fov, aspect, near, far ); - cameraNY.layers = this.layers; - this.add( cameraNY ); - - const cameraPZ = new PerspectiveCamera( fov, aspect, near, far ); - cameraPZ.layers = this.layers; - this.add( cameraPZ ); - - const cameraNZ = new PerspectiveCamera( fov, aspect, near, far ); - cameraNZ.layers = this.layers; - this.add( cameraNZ ); - - } - - updateCoordinateSystem() { - - const coordinateSystem = this.coordinateSystem; - - const cameras = this.children.concat(); - - const [ cameraPX, cameraNX, cameraPY, cameraNY, cameraPZ, cameraNZ ] = cameras; - - for ( const camera of cameras ) this.remove( camera ); - - if ( coordinateSystem === WebGLCoordinateSystem ) { - - cameraPX.up.set( 0, 1, 0 ); - cameraPX.lookAt( 1, 0, 0 ); - - cameraNX.up.set( 0, 1, 0 ); - cameraNX.lookAt( - 1, 0, 0 ); - - cameraPY.up.set( 0, 0, - 1 ); - cameraPY.lookAt( 0, 1, 0 ); - - cameraNY.up.set( 0, 0, 1 ); - cameraNY.lookAt( 0, - 1, 0 ); - - cameraPZ.up.set( 0, 1, 0 ); - cameraPZ.lookAt( 0, 0, 1 ); - - cameraNZ.up.set( 0, 1, 0 ); - cameraNZ.lookAt( 0, 0, - 1 ); - - } else if ( coordinateSystem === WebGPUCoordinateSystem ) { - - cameraPX.up.set( 0, - 1, 0 ); - cameraPX.lookAt( - 1, 0, 0 ); - - cameraNX.up.set( 0, - 1, 0 ); - cameraNX.lookAt( 1, 0, 0 ); - - cameraPY.up.set( 0, 0, 1 ); - cameraPY.lookAt( 0, 1, 0 ); - - cameraNY.up.set( 0, 0, - 1 ); - cameraNY.lookAt( 0, - 1, 0 ); - - cameraPZ.up.set( 0, - 1, 0 ); - cameraPZ.lookAt( 0, 0, 1 ); - - cameraNZ.up.set( 0, - 1, 0 ); - cameraNZ.lookAt( 0, 0, - 1 ); - - } else { - - throw new Error( 'THREE.CubeCamera.updateCoordinateSystem(): Invalid coordinate system: ' + coordinateSystem ); - - } - - for ( const camera of cameras ) { - - this.add( camera ); - - camera.updateMatrixWorld(); - - } - - } - - update( renderer, scene ) { - - if ( this.parent === null ) this.updateMatrixWorld(); - - const { renderTarget, activeMipmapLevel } = this; - - if ( this.coordinateSystem !== renderer.coordinateSystem ) { - - this.coordinateSystem = renderer.coordinateSystem; - - this.updateCoordinateSystem(); - - } - - const [ cameraPX, cameraNX, cameraPY, cameraNY, cameraPZ, cameraNZ ] = this.children; - - const currentRenderTarget = renderer.getRenderTarget(); - const currentActiveCubeFace = renderer.getActiveCubeFace(); - const currentActiveMipmapLevel = renderer.getActiveMipmapLevel(); - - const currentXrEnabled = renderer.xr.enabled; - - renderer.xr.enabled = false; - - const generateMipmaps = renderTarget.texture.generateMipmaps; - - renderTarget.texture.generateMipmaps = false; - - renderer.setRenderTarget( renderTarget, 0, activeMipmapLevel ); - renderer.render( scene, cameraPX ); - - renderer.setRenderTarget( renderTarget, 1, activeMipmapLevel ); - renderer.render( scene, cameraNX ); - - renderer.setRenderTarget( renderTarget, 2, activeMipmapLevel ); - renderer.render( scene, cameraPY ); - - renderer.setRenderTarget( renderTarget, 3, activeMipmapLevel ); - renderer.render( scene, cameraNY ); - - renderer.setRenderTarget( renderTarget, 4, activeMipmapLevel ); - renderer.render( scene, cameraPZ ); - - // mipmaps are generated during the last call of render() - // at this point, all sides of the cube render target are defined - - renderTarget.texture.generateMipmaps = generateMipmaps; - - renderer.setRenderTarget( renderTarget, 5, activeMipmapLevel ); - renderer.render( scene, cameraNZ ); - - renderer.setRenderTarget( currentRenderTarget, currentActiveCubeFace, currentActiveMipmapLevel ); - - renderer.xr.enabled = currentXrEnabled; - - renderTarget.texture.needsPMREMUpdate = true; - - } - -} - -class CubeTexture extends Texture { - - constructor( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, colorSpace ) { - - images = images !== undefined ? images : []; - mapping = mapping !== undefined ? mapping : CubeReflectionMapping; - - super( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, colorSpace ); - - this.isCubeTexture = true; - - this.flipY = false; - - } - - get images() { - - return this.image; - - } - - set images( value ) { - - this.image = value; - - } - -} - -class WebGLCubeRenderTarget extends WebGLRenderTarget { - - constructor( size = 1, options = {} ) { - - super( size, size, options ); - - this.isWebGLCubeRenderTarget = true; - - const image = { width: size, height: size, depth: 1 }; - const images = [ image, image, image, image, image, image ]; - - this.texture = new CubeTexture( images, options.mapping, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.colorSpace ); - - // By convention -- likely based on the RenderMan spec from the 1990's -- cube maps are specified by WebGL (and three.js) - // in a coordinate system in which positive-x is to the right when looking up the positive-z axis -- in other words, - // in a left-handed coordinate system. By continuing this convention, preexisting cube maps continued to render correctly. - - // three.js uses a right-handed coordinate system. So environment maps used in three.js appear to have px and nx swapped - // and the flag isRenderTargetTexture controls this conversion. The flip is not required when using WebGLCubeRenderTarget.texture - // as a cube texture (this is detected when isRenderTargetTexture is set to true for cube textures). - - this.texture.isRenderTargetTexture = true; - - this.texture.generateMipmaps = options.generateMipmaps !== undefined ? options.generateMipmaps : false; - this.texture.minFilter = options.minFilter !== undefined ? options.minFilter : LinearFilter; - - } - - fromEquirectangularTexture( renderer, texture ) { - - this.texture.type = texture.type; - this.texture.colorSpace = texture.colorSpace; - - this.texture.generateMipmaps = texture.generateMipmaps; - this.texture.minFilter = texture.minFilter; - this.texture.magFilter = texture.magFilter; - - const shader = { - - uniforms: { - tEquirect: { value: null }, - }, - - vertexShader: /* glsl */` - - varying vec3 vWorldDirection; - - vec3 transformDirection( in vec3 dir, in mat4 matrix ) { - - return normalize( ( matrix * vec4( dir, 0.0 ) ).xyz ); - - } - - void main() { - - vWorldDirection = transformDirection( position, modelMatrix ); - - #include - #include - - } - `, - - fragmentShader: /* glsl */` - - uniform sampler2D tEquirect; - - varying vec3 vWorldDirection; - - #include - - void main() { - - vec3 direction = normalize( vWorldDirection ); - - vec2 sampleUV = equirectUv( direction ); - - gl_FragColor = texture2D( tEquirect, sampleUV ); - - } - ` - }; - - const geometry = new BoxGeometry( 5, 5, 5 ); - - const material = new ShaderMaterial( { - - name: 'CubemapFromEquirect', - - uniforms: cloneUniforms( shader.uniforms ), - vertexShader: shader.vertexShader, - fragmentShader: shader.fragmentShader, - side: BackSide, - blending: NoBlending - - } ); - - material.uniforms.tEquirect.value = texture; - - const mesh = new Mesh( geometry, material ); - - const currentMinFilter = texture.minFilter; - - // Avoid blurred poles - if ( texture.minFilter === LinearMipmapLinearFilter ) texture.minFilter = LinearFilter; - - const camera = new CubeCamera( 1, 10, this ); - camera.update( renderer, mesh ); - - texture.minFilter = currentMinFilter; - - mesh.geometry.dispose(); - mesh.material.dispose(); - - return this; - - } - - clear( renderer, color, depth, stencil ) { - - const currentRenderTarget = renderer.getRenderTarget(); - - for ( let i = 0; i < 6; i ++ ) { - - renderer.setRenderTarget( this, i ); - - renderer.clear( color, depth, stencil ); - - } - - renderer.setRenderTarget( currentRenderTarget ); - - } - -} - -const _vector1 = /*@__PURE__*/ new Vector3(); -const _vector2 = /*@__PURE__*/ new Vector3(); -const _normalMatrix = /*@__PURE__*/ new Matrix3(); - -class Plane { - - constructor( normal = new Vector3( 1, 0, 0 ), constant = 0 ) { - - this.isPlane = true; - - // normal is assumed to be normalized - - this.normal = normal; - this.constant = constant; - - } - - set( normal, constant ) { - - this.normal.copy( normal ); - this.constant = constant; - - return this; - - } - - setComponents( x, y, z, w ) { - - this.normal.set( x, y, z ); - this.constant = w; - - return this; - - } - - setFromNormalAndCoplanarPoint( normal, point ) { - - this.normal.copy( normal ); - this.constant = - point.dot( this.normal ); - - return this; - - } - - setFromCoplanarPoints( a, b, c ) { - - const normal = _vector1.subVectors( c, b ).cross( _vector2.subVectors( a, b ) ).normalize(); - - // Q: should an error be thrown if normal is zero (e.g. degenerate plane)? - - this.setFromNormalAndCoplanarPoint( normal, a ); - - return this; - - } - - copy( plane ) { - - this.normal.copy( plane.normal ); - this.constant = plane.constant; - - return this; - - } - - normalize() { - - // Note: will lead to a divide by zero if the plane is invalid. - - const inverseNormalLength = 1.0 / this.normal.length(); - this.normal.multiplyScalar( inverseNormalLength ); - this.constant *= inverseNormalLength; - - return this; - - } - - negate() { - - this.constant *= - 1; - this.normal.negate(); - - return this; - - } - - distanceToPoint( point ) { - - return this.normal.dot( point ) + this.constant; - - } - - distanceToSphere( sphere ) { - - return this.distanceToPoint( sphere.center ) - sphere.radius; - - } - - projectPoint( point, target ) { - - return target.copy( point ).addScaledVector( this.normal, - this.distanceToPoint( point ) ); - - } - - intersectLine( line, target ) { - - const direction = line.delta( _vector1 ); - - const denominator = this.normal.dot( direction ); - - if ( denominator === 0 ) { - - // line is coplanar, return origin - if ( this.distanceToPoint( line.start ) === 0 ) { - - return target.copy( line.start ); - - } - - // Unsure if this is the correct method to handle this case. - return null; - - } - - const t = - ( line.start.dot( this.normal ) + this.constant ) / denominator; - - if ( t < 0 || t > 1 ) { - - return null; - - } - - return target.copy( line.start ).addScaledVector( direction, t ); - - } - - intersectsLine( line ) { - - // Note: this tests if a line intersects the plane, not whether it (or its end-points) are coplanar with it. - - const startSign = this.distanceToPoint( line.start ); - const endSign = this.distanceToPoint( line.end ); - - return ( startSign < 0 && endSign > 0 ) || ( endSign < 0 && startSign > 0 ); - - } - - intersectsBox( box ) { - - return box.intersectsPlane( this ); - - } - - intersectsSphere( sphere ) { - - return sphere.intersectsPlane( this ); - - } - - coplanarPoint( target ) { - - return target.copy( this.normal ).multiplyScalar( - this.constant ); - - } - - applyMatrix4( matrix, optionalNormalMatrix ) { - - const normalMatrix = optionalNormalMatrix || _normalMatrix.getNormalMatrix( matrix ); - - const referencePoint = this.coplanarPoint( _vector1 ).applyMatrix4( matrix ); - - const normal = this.normal.applyMatrix3( normalMatrix ).normalize(); - - this.constant = - referencePoint.dot( normal ); - - return this; - - } - - translate( offset ) { - - this.constant -= offset.dot( this.normal ); - - return this; - - } - - equals( plane ) { - - return plane.normal.equals( this.normal ) && ( plane.constant === this.constant ); - - } - - clone() { - - return new this.constructor().copy( this ); - - } - -} - -const _sphere$5 = /*@__PURE__*/ new Sphere(); -const _vector$7 = /*@__PURE__*/ new Vector3(); - -class Frustum { - - constructor( p0 = new Plane(), p1 = new Plane(), p2 = new Plane(), p3 = new Plane(), p4 = new Plane(), p5 = new Plane() ) { - - this.planes = [ p0, p1, p2, p3, p4, p5 ]; - - } - - set( p0, p1, p2, p3, p4, p5 ) { - - const planes = this.planes; - - planes[ 0 ].copy( p0 ); - planes[ 1 ].copy( p1 ); - planes[ 2 ].copy( p2 ); - planes[ 3 ].copy( p3 ); - planes[ 4 ].copy( p4 ); - planes[ 5 ].copy( p5 ); - - return this; - - } - - copy( frustum ) { - - const planes = this.planes; - - for ( let i = 0; i < 6; i ++ ) { - - planes[ i ].copy( frustum.planes[ i ] ); - - } - - return this; - - } - - setFromProjectionMatrix( m, coordinateSystem = WebGLCoordinateSystem ) { - - const planes = this.planes; - const me = m.elements; - const me0 = me[ 0 ], me1 = me[ 1 ], me2 = me[ 2 ], me3 = me[ 3 ]; - const me4 = me[ 4 ], me5 = me[ 5 ], me6 = me[ 6 ], me7 = me[ 7 ]; - const me8 = me[ 8 ], me9 = me[ 9 ], me10 = me[ 10 ], me11 = me[ 11 ]; - const me12 = me[ 12 ], me13 = me[ 13 ], me14 = me[ 14 ], me15 = me[ 15 ]; - - planes[ 0 ].setComponents( me3 - me0, me7 - me4, me11 - me8, me15 - me12 ).normalize(); - planes[ 1 ].setComponents( me3 + me0, me7 + me4, me11 + me8, me15 + me12 ).normalize(); - planes[ 2 ].setComponents( me3 + me1, me7 + me5, me11 + me9, me15 + me13 ).normalize(); - planes[ 3 ].setComponents( me3 - me1, me7 - me5, me11 - me9, me15 - me13 ).normalize(); - planes[ 4 ].setComponents( me3 - me2, me7 - me6, me11 - me10, me15 - me14 ).normalize(); - - if ( coordinateSystem === WebGLCoordinateSystem ) { - - planes[ 5 ].setComponents( me3 + me2, me7 + me6, me11 + me10, me15 + me14 ).normalize(); - - } else if ( coordinateSystem === WebGPUCoordinateSystem ) { - - planes[ 5 ].setComponents( me2, me6, me10, me14 ).normalize(); - - } else { - - throw new Error( 'THREE.Frustum.setFromProjectionMatrix(): Invalid coordinate system: ' + coordinateSystem ); - - } - - return this; - - } - - intersectsObject( object ) { - - if ( object.boundingSphere !== undefined ) { - - if ( object.boundingSphere === null ) object.computeBoundingSphere(); - - _sphere$5.copy( object.boundingSphere ).applyMatrix4( object.matrixWorld ); - - } else { - - const geometry = object.geometry; - - if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); - - _sphere$5.copy( geometry.boundingSphere ).applyMatrix4( object.matrixWorld ); - - } - - return this.intersectsSphere( _sphere$5 ); - - } - - intersectsSprite( sprite ) { - - _sphere$5.center.set( 0, 0, 0 ); - _sphere$5.radius = 0.7071067811865476; - _sphere$5.applyMatrix4( sprite.matrixWorld ); - - return this.intersectsSphere( _sphere$5 ); - - } - - intersectsSphere( sphere ) { - - const planes = this.planes; - const center = sphere.center; - const negRadius = - sphere.radius; - - for ( let i = 0; i < 6; i ++ ) { - - const distance = planes[ i ].distanceToPoint( center ); - - if ( distance < negRadius ) { - - return false; - - } - - } - - return true; - - } - - intersectsBox( box ) { - - const planes = this.planes; - - for ( let i = 0; i < 6; i ++ ) { - - const plane = planes[ i ]; - - // corner at max distance - - _vector$7.x = plane.normal.x > 0 ? box.max.x : box.min.x; - _vector$7.y = plane.normal.y > 0 ? box.max.y : box.min.y; - _vector$7.z = plane.normal.z > 0 ? box.max.z : box.min.z; - - if ( plane.distanceToPoint( _vector$7 ) < 0 ) { - - return false; - - } - - } - - return true; - - } - - containsPoint( point ) { - - const planes = this.planes; - - for ( let i = 0; i < 6; i ++ ) { - - if ( planes[ i ].distanceToPoint( point ) < 0 ) { - - return false; - - } - - } - - return true; - - } - - clone() { - - return new this.constructor().copy( this ); - - } - -} - -function WebGLAnimation() { - - let context = null; - let isAnimating = false; - let animationLoop = null; - let requestId = null; - - function onAnimationFrame( time, frame ) { - - animationLoop( time, frame ); - - requestId = context.requestAnimationFrame( onAnimationFrame ); - - } - - return { - - start: function () { - - if ( isAnimating === true ) return; - if ( animationLoop === null ) return; - - requestId = context.requestAnimationFrame( onAnimationFrame ); - - isAnimating = true; - - }, - - stop: function () { - - context.cancelAnimationFrame( requestId ); - - isAnimating = false; - - }, - - setAnimationLoop: function ( callback ) { - - animationLoop = callback; - - }, - - setContext: function ( value ) { - - context = value; - - } - - }; - -} - -function WebGLAttributes( gl, capabilities ) { - - const isWebGL2 = capabilities.isWebGL2; - - const buffers = new WeakMap(); - - function createBuffer( attribute, bufferType ) { - - const array = attribute.array; - const usage = attribute.usage; - const size = array.byteLength; - - const buffer = gl.createBuffer(); - - gl.bindBuffer( bufferType, buffer ); - gl.bufferData( bufferType, array, usage ); - - attribute.onUploadCallback(); - - let type; - - if ( array instanceof Float32Array ) { - - type = gl.FLOAT; - - } else if ( array instanceof Uint16Array ) { - - if ( attribute.isFloat16BufferAttribute ) { - - if ( isWebGL2 ) { - - type = gl.HALF_FLOAT; - - } else { - - throw new Error( 'THREE.WebGLAttributes: Usage of Float16BufferAttribute requires WebGL2.' ); - - } - - } else { - - type = gl.UNSIGNED_SHORT; - - } - - } else if ( array instanceof Int16Array ) { - - type = gl.SHORT; - - } else if ( array instanceof Uint32Array ) { - - type = gl.UNSIGNED_INT; - - } else if ( array instanceof Int32Array ) { - - type = gl.INT; - - } else if ( array instanceof Int8Array ) { - - type = gl.BYTE; - - } else if ( array instanceof Uint8Array ) { - - type = gl.UNSIGNED_BYTE; - - } else if ( array instanceof Uint8ClampedArray ) { - - type = gl.UNSIGNED_BYTE; - - } else { - - throw new Error( 'THREE.WebGLAttributes: Unsupported buffer data format: ' + array ); - - } - - return { - buffer: buffer, - type: type, - bytesPerElement: array.BYTES_PER_ELEMENT, - version: attribute.version, - size: size - }; - - } - - function updateBuffer( buffer, attribute, bufferType ) { - - const array = attribute.array; - const updateRange = attribute._updateRange; // @deprecated, r159 - const updateRanges = attribute.updateRanges; - - gl.bindBuffer( bufferType, buffer ); - - if ( updateRange.count === - 1 && updateRanges.length === 0 ) { - - // Not using update ranges - gl.bufferSubData( bufferType, 0, array ); - - } - - if ( updateRanges.length !== 0 ) { - - for ( let i = 0, l = updateRanges.length; i < l; i ++ ) { - - const range = updateRanges[ i ]; - if ( isWebGL2 ) { - - gl.bufferSubData( bufferType, range.start * array.BYTES_PER_ELEMENT, - array, range.start, range.count ); - - } else { - - gl.bufferSubData( bufferType, range.start * array.BYTES_PER_ELEMENT, - array.subarray( range.start, range.start + range.count ) ); - - } - - } - - attribute.clearUpdateRanges(); - - } - - // @deprecated, r159 - if ( updateRange.count !== - 1 ) { - - if ( isWebGL2 ) { - - gl.bufferSubData( bufferType, updateRange.offset * array.BYTES_PER_ELEMENT, - array, updateRange.offset, updateRange.count ); - - } else { - - gl.bufferSubData( bufferType, updateRange.offset * array.BYTES_PER_ELEMENT, - array.subarray( updateRange.offset, updateRange.offset + updateRange.count ) ); - - } - - updateRange.count = - 1; // reset range - - } - - attribute.onUploadCallback(); - - } - - // - - function get( attribute ) { - - if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data; - - return buffers.get( attribute ); - - } - - function remove( attribute ) { - - if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data; - - const data = buffers.get( attribute ); - - if ( data ) { - - gl.deleteBuffer( data.buffer ); - - buffers.delete( attribute ); - - } - - } - - function update( attribute, bufferType ) { - - if ( attribute.isGLBufferAttribute ) { - - const cached = buffers.get( attribute ); - - if ( ! cached || cached.version < attribute.version ) { - - buffers.set( attribute, { - buffer: attribute.buffer, - type: attribute.type, - bytesPerElement: attribute.elementSize, - version: attribute.version - } ); - - } - - return; - - } - - if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data; - - const data = buffers.get( attribute ); - - if ( data === undefined ) { - - buffers.set( attribute, createBuffer( attribute, bufferType ) ); - - } else if ( data.version < attribute.version ) { - - if ( data.size !== attribute.array.byteLength ) { - - throw new Error( 'THREE.WebGLAttributes: The size of the buffer attribute\'s array buffer does not match the original size. Resizing buffer attributes is not supported.' ); - - } - - updateBuffer( data.buffer, attribute, bufferType ); - - data.version = attribute.version; - - } - - } - - return { - - get: get, - remove: remove, - update: update - - }; - -} - -class PlaneGeometry extends BufferGeometry { - - constructor( width = 1, height = 1, widthSegments = 1, heightSegments = 1 ) { - - super(); - - this.type = 'PlaneGeometry'; - - this.parameters = { - width: width, - height: height, - widthSegments: widthSegments, - heightSegments: heightSegments - }; - - const width_half = width / 2; - const height_half = height / 2; - - const gridX = Math.floor( widthSegments ); - const gridY = Math.floor( heightSegments ); - - const gridX1 = gridX + 1; - const gridY1 = gridY + 1; - - const segment_width = width / gridX; - const segment_height = height / gridY; - - // - - const indices = []; - const vertices = []; - const normals = []; - const uvs = []; - - for ( let iy = 0; iy < gridY1; iy ++ ) { - - const y = iy * segment_height - height_half; - - for ( let ix = 0; ix < gridX1; ix ++ ) { - - const x = ix * segment_width - width_half; - - vertices.push( x, - y, 0 ); - - normals.push( 0, 0, 1 ); - - uvs.push( ix / gridX ); - uvs.push( 1 - ( iy / gridY ) ); - - } - - } - - for ( let iy = 0; iy < gridY; iy ++ ) { - - for ( let ix = 0; ix < gridX; ix ++ ) { - - const a = ix + gridX1 * iy; - const b = ix + gridX1 * ( iy + 1 ); - const c = ( ix + 1 ) + gridX1 * ( iy + 1 ); - const d = ( ix + 1 ) + gridX1 * iy; - - indices.push( a, b, d ); - indices.push( b, c, d ); - - } - - } - - this.setIndex( indices ); - this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - - } - - copy( source ) { - - super.copy( source ); - - this.parameters = Object.assign( {}, source.parameters ); - - return this; - - } - - static fromJSON( data ) { - - return new PlaneGeometry( data.width, data.height, data.widthSegments, data.heightSegments ); - - } - -} - -var alphahash_fragment = "#ifdef USE_ALPHAHASH\n\tif ( diffuseColor.a < getAlphaHashThreshold( vPosition ) ) discard;\n#endif"; - -var alphahash_pars_fragment = "#ifdef USE_ALPHAHASH\n\tconst float ALPHA_HASH_SCALE = 0.05;\n\tfloat hash2D( vec2 value ) {\n\t\treturn fract( 1.0e4 * sin( 17.0 * value.x + 0.1 * value.y ) * ( 0.1 + abs( sin( 13.0 * value.y + value.x ) ) ) );\n\t}\n\tfloat hash3D( vec3 value ) {\n\t\treturn hash2D( vec2( hash2D( value.xy ), value.z ) );\n\t}\n\tfloat getAlphaHashThreshold( vec3 position ) {\n\t\tfloat maxDeriv = max(\n\t\t\tlength( dFdx( position.xyz ) ),\n\t\t\tlength( dFdy( position.xyz ) )\n\t\t);\n\t\tfloat pixScale = 1.0 / ( ALPHA_HASH_SCALE * maxDeriv );\n\t\tvec2 pixScales = vec2(\n\t\t\texp2( floor( log2( pixScale ) ) ),\n\t\t\texp2( ceil( log2( pixScale ) ) )\n\t\t);\n\t\tvec2 alpha = vec2(\n\t\t\thash3D( floor( pixScales.x * position.xyz ) ),\n\t\t\thash3D( floor( pixScales.y * position.xyz ) )\n\t\t);\n\t\tfloat lerpFactor = fract( log2( pixScale ) );\n\t\tfloat x = ( 1.0 - lerpFactor ) * alpha.x + lerpFactor * alpha.y;\n\t\tfloat a = min( lerpFactor, 1.0 - lerpFactor );\n\t\tvec3 cases = vec3(\n\t\t\tx * x / ( 2.0 * a * ( 1.0 - a ) ),\n\t\t\t( x - 0.5 * a ) / ( 1.0 - a ),\n\t\t\t1.0 - ( ( 1.0 - x ) * ( 1.0 - x ) / ( 2.0 * a * ( 1.0 - a ) ) )\n\t\t);\n\t\tfloat threshold = ( x < ( 1.0 - a ) )\n\t\t\t? ( ( x < a ) ? cases.x : cases.y )\n\t\t\t: cases.z;\n\t\treturn clamp( threshold , 1.0e-6, 1.0 );\n\t}\n#endif"; - -var alphamap_fragment = "#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, vAlphaMapUv ).g;\n#endif"; - -var alphamap_pars_fragment = "#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif"; - -var alphatest_fragment = "#ifdef USE_ALPHATEST\n\t#ifdef ALPHA_TO_COVERAGE\n\tdiffuseColor.a = smoothstep( alphaTest, alphaTest + fwidth( diffuseColor.a ), diffuseColor.a );\n\tif ( diffuseColor.a == 0.0 ) discard;\n\t#else\n\tif ( diffuseColor.a < alphaTest ) discard;\n\t#endif\n#endif"; - -var alphatest_pars_fragment = "#ifdef USE_ALPHATEST\n\tuniform float alphaTest;\n#endif"; - -var aomap_fragment = "#ifdef USE_AOMAP\n\tfloat ambientOcclusion = ( texture2D( aoMap, vAoMapUv ).r - 1.0 ) * aoMapIntensity + 1.0;\n\treflectedLight.indirectDiffuse *= ambientOcclusion;\n\t#if defined( USE_CLEARCOAT ) \n\t\tclearcoatSpecularIndirect *= ambientOcclusion;\n\t#endif\n\t#if defined( USE_SHEEN ) \n\t\tsheenSpecularIndirect *= ambientOcclusion;\n\t#endif\n\t#if defined( USE_ENVMAP ) && defined( STANDARD )\n\t\tfloat dotNV = saturate( dot( geometryNormal, geometryViewDir ) );\n\t\treflectedLight.indirectSpecular *= computeSpecularOcclusion( dotNV, ambientOcclusion, material.roughness );\n\t#endif\n#endif"; - -var aomap_pars_fragment = "#ifdef USE_AOMAP\n\tuniform sampler2D aoMap;\n\tuniform float aoMapIntensity;\n#endif"; - -var batching_pars_vertex = "#ifdef USE_BATCHING\n\tattribute float batchId;\n\tuniform highp sampler2D batchingTexture;\n\tmat4 getBatchingMatrix( const in float i ) {\n\t\tint size = textureSize( batchingTexture, 0 ).x;\n\t\tint j = int( i ) * 4;\n\t\tint x = j % size;\n\t\tint y = j / size;\n\t\tvec4 v1 = texelFetch( batchingTexture, ivec2( x, y ), 0 );\n\t\tvec4 v2 = texelFetch( batchingTexture, ivec2( x + 1, y ), 0 );\n\t\tvec4 v3 = texelFetch( batchingTexture, ivec2( x + 2, y ), 0 );\n\t\tvec4 v4 = texelFetch( batchingTexture, ivec2( x + 3, y ), 0 );\n\t\treturn mat4( v1, v2, v3, v4 );\n\t}\n#endif"; - -var batching_vertex = "#ifdef USE_BATCHING\n\tmat4 batchingMatrix = getBatchingMatrix( batchId );\n#endif"; - -var begin_vertex = "vec3 transformed = vec3( position );\n#ifdef USE_ALPHAHASH\n\tvPosition = vec3( position );\n#endif"; - -var beginnormal_vertex = "vec3 objectNormal = vec3( normal );\n#ifdef USE_TANGENT\n\tvec3 objectTangent = vec3( tangent.xyz );\n#endif"; - -var bsdfs = "float G_BlinnPhong_Implicit( ) {\n\treturn 0.25;\n}\nfloat D_BlinnPhong( const in float shininess, const in float dotNH ) {\n\treturn RECIPROCAL_PI * ( shininess * 0.5 + 1.0 ) * pow( dotNH, shininess );\n}\nvec3 BRDF_BlinnPhong( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in vec3 specularColor, const in float shininess ) {\n\tvec3 halfDir = normalize( lightDir + viewDir );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat dotVH = saturate( dot( viewDir, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, 1.0, dotVH );\n\tfloat G = G_BlinnPhong_Implicit( );\n\tfloat D = D_BlinnPhong( shininess, dotNH );\n\treturn F * ( G * D );\n} // validated"; - -var iridescence_fragment = "#ifdef USE_IRIDESCENCE\n\tconst mat3 XYZ_TO_REC709 = mat3(\n\t\t 3.2404542, -0.9692660, 0.0556434,\n\t\t-1.5371385, 1.8760108, -0.2040259,\n\t\t-0.4985314, 0.0415560, 1.0572252\n\t);\n\tvec3 Fresnel0ToIor( vec3 fresnel0 ) {\n\t\tvec3 sqrtF0 = sqrt( fresnel0 );\n\t\treturn ( vec3( 1.0 ) + sqrtF0 ) / ( vec3( 1.0 ) - sqrtF0 );\n\t}\n\tvec3 IorToFresnel0( vec3 transmittedIor, float incidentIor ) {\n\t\treturn pow2( ( transmittedIor - vec3( incidentIor ) ) / ( transmittedIor + vec3( incidentIor ) ) );\n\t}\n\tfloat IorToFresnel0( float transmittedIor, float incidentIor ) {\n\t\treturn pow2( ( transmittedIor - incidentIor ) / ( transmittedIor + incidentIor ));\n\t}\n\tvec3 evalSensitivity( float OPD, vec3 shift ) {\n\t\tfloat phase = 2.0 * PI * OPD * 1.0e-9;\n\t\tvec3 val = vec3( 5.4856e-13, 4.4201e-13, 5.2481e-13 );\n\t\tvec3 pos = vec3( 1.6810e+06, 1.7953e+06, 2.2084e+06 );\n\t\tvec3 var = vec3( 4.3278e+09, 9.3046e+09, 6.6121e+09 );\n\t\tvec3 xyz = val * sqrt( 2.0 * PI * var ) * cos( pos * phase + shift ) * exp( - pow2( phase ) * var );\n\t\txyz.x += 9.7470e-14 * sqrt( 2.0 * PI * 4.5282e+09 ) * cos( 2.2399e+06 * phase + shift[ 0 ] ) * exp( - 4.5282e+09 * pow2( phase ) );\n\t\txyz /= 1.0685e-7;\n\t\tvec3 rgb = XYZ_TO_REC709 * xyz;\n\t\treturn rgb;\n\t}\n\tvec3 evalIridescence( float outsideIOR, float eta2, float cosTheta1, float thinFilmThickness, vec3 baseF0 ) {\n\t\tvec3 I;\n\t\tfloat iridescenceIOR = mix( outsideIOR, eta2, smoothstep( 0.0, 0.03, thinFilmThickness ) );\n\t\tfloat sinTheta2Sq = pow2( outsideIOR / iridescenceIOR ) * ( 1.0 - pow2( cosTheta1 ) );\n\t\tfloat cosTheta2Sq = 1.0 - sinTheta2Sq;\n\t\tif ( cosTheta2Sq < 0.0 ) {\n\t\t\treturn vec3( 1.0 );\n\t\t}\n\t\tfloat cosTheta2 = sqrt( cosTheta2Sq );\n\t\tfloat R0 = IorToFresnel0( iridescenceIOR, outsideIOR );\n\t\tfloat R12 = F_Schlick( R0, 1.0, cosTheta1 );\n\t\tfloat T121 = 1.0 - R12;\n\t\tfloat phi12 = 0.0;\n\t\tif ( iridescenceIOR < outsideIOR ) phi12 = PI;\n\t\tfloat phi21 = PI - phi12;\n\t\tvec3 baseIOR = Fresnel0ToIor( clamp( baseF0, 0.0, 0.9999 ) );\t\tvec3 R1 = IorToFresnel0( baseIOR, iridescenceIOR );\n\t\tvec3 R23 = F_Schlick( R1, 1.0, cosTheta2 );\n\t\tvec3 phi23 = vec3( 0.0 );\n\t\tif ( baseIOR[ 0 ] < iridescenceIOR ) phi23[ 0 ] = PI;\n\t\tif ( baseIOR[ 1 ] < iridescenceIOR ) phi23[ 1 ] = PI;\n\t\tif ( baseIOR[ 2 ] < iridescenceIOR ) phi23[ 2 ] = PI;\n\t\tfloat OPD = 2.0 * iridescenceIOR * thinFilmThickness * cosTheta2;\n\t\tvec3 phi = vec3( phi21 ) + phi23;\n\t\tvec3 R123 = clamp( R12 * R23, 1e-5, 0.9999 );\n\t\tvec3 r123 = sqrt( R123 );\n\t\tvec3 Rs = pow2( T121 ) * R23 / ( vec3( 1.0 ) - R123 );\n\t\tvec3 C0 = R12 + Rs;\n\t\tI = C0;\n\t\tvec3 Cm = Rs - T121;\n\t\tfor ( int m = 1; m <= 2; ++ m ) {\n\t\t\tCm *= r123;\n\t\t\tvec3 Sm = 2.0 * evalSensitivity( float( m ) * OPD, float( m ) * phi );\n\t\t\tI += Cm * Sm;\n\t\t}\n\t\treturn max( I, vec3( 0.0 ) );\n\t}\n#endif"; - -var bumpmap_pars_fragment = "#ifdef USE_BUMPMAP\n\tuniform sampler2D bumpMap;\n\tuniform float bumpScale;\n\tvec2 dHdxy_fwd() {\n\t\tvec2 dSTdx = dFdx( vBumpMapUv );\n\t\tvec2 dSTdy = dFdy( vBumpMapUv );\n\t\tfloat Hll = bumpScale * texture2D( bumpMap, vBumpMapUv ).x;\n\t\tfloat dBx = bumpScale * texture2D( bumpMap, vBumpMapUv + dSTdx ).x - Hll;\n\t\tfloat dBy = bumpScale * texture2D( bumpMap, vBumpMapUv + dSTdy ).x - Hll;\n\t\treturn vec2( dBx, dBy );\n\t}\n\tvec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy, float faceDirection ) {\n\t\tvec3 vSigmaX = normalize( dFdx( surf_pos.xyz ) );\n\t\tvec3 vSigmaY = normalize( dFdy( surf_pos.xyz ) );\n\t\tvec3 vN = surf_norm;\n\t\tvec3 R1 = cross( vSigmaY, vN );\n\t\tvec3 R2 = cross( vN, vSigmaX );\n\t\tfloat fDet = dot( vSigmaX, R1 ) * faceDirection;\n\t\tvec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );\n\t\treturn normalize( abs( fDet ) * surf_norm - vGrad );\n\t}\n#endif"; - -var clipping_planes_fragment = "#if NUM_CLIPPING_PLANES > 0\n\tvec4 plane;\n\t#ifdef ALPHA_TO_COVERAGE\n\t\tfloat distanceToPlane, distanceGradient;\n\t\tfloat clipOpacity = 1.0;\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < UNION_CLIPPING_PLANES; i ++ ) {\n\t\t\tplane = clippingPlanes[ i ];\n\t\t\tdistanceToPlane = - dot( vClipPosition, plane.xyz ) + plane.w;\n\t\t\tdistanceGradient = fwidth( distanceToPlane ) / 2.0;\n\t\t\tclipOpacity *= smoothstep( - distanceGradient, distanceGradient, distanceToPlane );\n\t\t\tif ( clipOpacity == 0.0 ) discard;\n\t\t}\n\t\t#pragma unroll_loop_end\n\t\t#if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES\n\t\t\tfloat unionClipOpacity = 1.0;\n\t\t\t#pragma unroll_loop_start\n\t\t\tfor ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; i ++ ) {\n\t\t\t\tplane = clippingPlanes[ i ];\n\t\t\t\tdistanceToPlane = - dot( vClipPosition, plane.xyz ) + plane.w;\n\t\t\t\tdistanceGradient = fwidth( distanceToPlane ) / 2.0;\n\t\t\t\tunionClipOpacity *= 1.0 - smoothstep( - distanceGradient, distanceGradient, distanceToPlane );\n\t\t\t}\n\t\t\t#pragma unroll_loop_end\n\t\t\tclipOpacity *= 1.0 - unionClipOpacity;\n\t\t#endif\n\t\tdiffuseColor.a *= clipOpacity;\n\t\tif ( diffuseColor.a == 0.0 ) discard;\n\t#else\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < UNION_CLIPPING_PLANES; i ++ ) {\n\t\t\tplane = clippingPlanes[ i ];\n\t\t\tif ( dot( vClipPosition, plane.xyz ) > plane.w ) discard;\n\t\t}\n\t\t#pragma unroll_loop_end\n\t\t#if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES\n\t\t\tbool clipped = true;\n\t\t\t#pragma unroll_loop_start\n\t\t\tfor ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; i ++ ) {\n\t\t\t\tplane = clippingPlanes[ i ];\n\t\t\t\tclipped = ( dot( vClipPosition, plane.xyz ) > plane.w ) && clipped;\n\t\t\t}\n\t\t\t#pragma unroll_loop_end\n\t\t\tif ( clipped ) discard;\n\t\t#endif\n\t#endif\n#endif"; - -var clipping_planes_pars_fragment = "#if NUM_CLIPPING_PLANES > 0\n\tvarying vec3 vClipPosition;\n\tuniform vec4 clippingPlanes[ NUM_CLIPPING_PLANES ];\n#endif"; - -var clipping_planes_pars_vertex = "#if NUM_CLIPPING_PLANES > 0\n\tvarying vec3 vClipPosition;\n#endif"; - -var clipping_planes_vertex = "#if NUM_CLIPPING_PLANES > 0\n\tvClipPosition = - mvPosition.xyz;\n#endif"; - -var color_fragment = "#if defined( USE_COLOR_ALPHA )\n\tdiffuseColor *= vColor;\n#elif defined( USE_COLOR )\n\tdiffuseColor.rgb *= vColor;\n#endif"; - -var color_pars_fragment = "#if defined( USE_COLOR_ALPHA )\n\tvarying vec4 vColor;\n#elif defined( USE_COLOR )\n\tvarying vec3 vColor;\n#endif"; - -var color_pars_vertex = "#if defined( USE_COLOR_ALPHA )\n\tvarying vec4 vColor;\n#elif defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR )\n\tvarying vec3 vColor;\n#endif"; - -var color_vertex = "#if defined( USE_COLOR_ALPHA )\n\tvColor = vec4( 1.0 );\n#elif defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR )\n\tvColor = vec3( 1.0 );\n#endif\n#ifdef USE_COLOR\n\tvColor *= color;\n#endif\n#ifdef USE_INSTANCING_COLOR\n\tvColor.xyz *= instanceColor.xyz;\n#endif"; - -var common = "#define PI 3.141592653589793\n#define PI2 6.283185307179586\n#define PI_HALF 1.5707963267948966\n#define RECIPROCAL_PI 0.3183098861837907\n#define RECIPROCAL_PI2 0.15915494309189535\n#define EPSILON 1e-6\n#ifndef saturate\n#define saturate( a ) clamp( a, 0.0, 1.0 )\n#endif\n#define whiteComplement( a ) ( 1.0 - saturate( a ) )\nfloat pow2( const in float x ) { return x*x; }\nvec3 pow2( const in vec3 x ) { return x*x; }\nfloat pow3( const in float x ) { return x*x*x; }\nfloat pow4( const in float x ) { float x2 = x*x; return x2*x2; }\nfloat max3( const in vec3 v ) { return max( max( v.x, v.y ), v.z ); }\nfloat average( const in vec3 v ) { return dot( v, vec3( 0.3333333 ) ); }\nhighp float rand( const in vec2 uv ) {\n\tconst highp float a = 12.9898, b = 78.233, c = 43758.5453;\n\thighp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI );\n\treturn fract( sin( sn ) * c );\n}\n#ifdef HIGH_PRECISION\n\tfloat precisionSafeLength( vec3 v ) { return length( v ); }\n#else\n\tfloat precisionSafeLength( vec3 v ) {\n\t\tfloat maxComponent = max3( abs( v ) );\n\t\treturn length( v / maxComponent ) * maxComponent;\n\t}\n#endif\nstruct IncidentLight {\n\tvec3 color;\n\tvec3 direction;\n\tbool visible;\n};\nstruct ReflectedLight {\n\tvec3 directDiffuse;\n\tvec3 directSpecular;\n\tvec3 indirectDiffuse;\n\tvec3 indirectSpecular;\n};\n#ifdef USE_ALPHAHASH\n\tvarying vec3 vPosition;\n#endif\nvec3 transformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );\n}\nvec3 inverseTransformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( vec4( dir, 0.0 ) * matrix ).xyz );\n}\nmat3 transposeMat3( const in mat3 m ) {\n\tmat3 tmp;\n\ttmp[ 0 ] = vec3( m[ 0 ].x, m[ 1 ].x, m[ 2 ].x );\n\ttmp[ 1 ] = vec3( m[ 0 ].y, m[ 1 ].y, m[ 2 ].y );\n\ttmp[ 2 ] = vec3( m[ 0 ].z, m[ 1 ].z, m[ 2 ].z );\n\treturn tmp;\n}\nfloat luminance( const in vec3 rgb ) {\n\tconst vec3 weights = vec3( 0.2126729, 0.7151522, 0.0721750 );\n\treturn dot( weights, rgb );\n}\nbool isPerspectiveMatrix( mat4 m ) {\n\treturn m[ 2 ][ 3 ] == - 1.0;\n}\nvec2 equirectUv( in vec3 dir ) {\n\tfloat u = atan( dir.z, dir.x ) * RECIPROCAL_PI2 + 0.5;\n\tfloat v = asin( clamp( dir.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;\n\treturn vec2( u, v );\n}\nvec3 BRDF_Lambert( const in vec3 diffuseColor ) {\n\treturn RECIPROCAL_PI * diffuseColor;\n}\nvec3 F_Schlick( const in vec3 f0, const in float f90, const in float dotVH ) {\n\tfloat fresnel = exp2( ( - 5.55473 * dotVH - 6.98316 ) * dotVH );\n\treturn f0 * ( 1.0 - fresnel ) + ( f90 * fresnel );\n}\nfloat F_Schlick( const in float f0, const in float f90, const in float dotVH ) {\n\tfloat fresnel = exp2( ( - 5.55473 * dotVH - 6.98316 ) * dotVH );\n\treturn f0 * ( 1.0 - fresnel ) + ( f90 * fresnel );\n} // validated"; - -var cube_uv_reflection_fragment = "#ifdef ENVMAP_TYPE_CUBE_UV\n\t#define cubeUV_minMipLevel 4.0\n\t#define cubeUV_minTileSize 16.0\n\tfloat getFace( vec3 direction ) {\n\t\tvec3 absDirection = abs( direction );\n\t\tfloat face = - 1.0;\n\t\tif ( absDirection.x > absDirection.z ) {\n\t\t\tif ( absDirection.x > absDirection.y )\n\t\t\t\tface = direction.x > 0.0 ? 0.0 : 3.0;\n\t\t\telse\n\t\t\t\tface = direction.y > 0.0 ? 1.0 : 4.0;\n\t\t} else {\n\t\t\tif ( absDirection.z > absDirection.y )\n\t\t\t\tface = direction.z > 0.0 ? 2.0 : 5.0;\n\t\t\telse\n\t\t\t\tface = direction.y > 0.0 ? 1.0 : 4.0;\n\t\t}\n\t\treturn face;\n\t}\n\tvec2 getUV( vec3 direction, float face ) {\n\t\tvec2 uv;\n\t\tif ( face == 0.0 ) {\n\t\t\tuv = vec2( direction.z, direction.y ) / abs( direction.x );\n\t\t} else if ( face == 1.0 ) {\n\t\t\tuv = vec2( - direction.x, - direction.z ) / abs( direction.y );\n\t\t} else if ( face == 2.0 ) {\n\t\t\tuv = vec2( - direction.x, direction.y ) / abs( direction.z );\n\t\t} else if ( face == 3.0 ) {\n\t\t\tuv = vec2( - direction.z, direction.y ) / abs( direction.x );\n\t\t} else if ( face == 4.0 ) {\n\t\t\tuv = vec2( - direction.x, direction.z ) / abs( direction.y );\n\t\t} else {\n\t\t\tuv = vec2( direction.x, direction.y ) / abs( direction.z );\n\t\t}\n\t\treturn 0.5 * ( uv + 1.0 );\n\t}\n\tvec3 bilinearCubeUV( sampler2D envMap, vec3 direction, float mipInt ) {\n\t\tfloat face = getFace( direction );\n\t\tfloat filterInt = max( cubeUV_minMipLevel - mipInt, 0.0 );\n\t\tmipInt = max( mipInt, cubeUV_minMipLevel );\n\t\tfloat faceSize = exp2( mipInt );\n\t\thighp vec2 uv = getUV( direction, face ) * ( faceSize - 2.0 ) + 1.0;\n\t\tif ( face > 2.0 ) {\n\t\t\tuv.y += faceSize;\n\t\t\tface -= 3.0;\n\t\t}\n\t\tuv.x += face * faceSize;\n\t\tuv.x += filterInt * 3.0 * cubeUV_minTileSize;\n\t\tuv.y += 4.0 * ( exp2( CUBEUV_MAX_MIP ) - faceSize );\n\t\tuv.x *= CUBEUV_TEXEL_WIDTH;\n\t\tuv.y *= CUBEUV_TEXEL_HEIGHT;\n\t\t#ifdef texture2DGradEXT\n\t\t\treturn texture2DGradEXT( envMap, uv, vec2( 0.0 ), vec2( 0.0 ) ).rgb;\n\t\t#else\n\t\t\treturn texture2D( envMap, uv ).rgb;\n\t\t#endif\n\t}\n\t#define cubeUV_r0 1.0\n\t#define cubeUV_m0 - 2.0\n\t#define cubeUV_r1 0.8\n\t#define cubeUV_m1 - 1.0\n\t#define cubeUV_r4 0.4\n\t#define cubeUV_m4 2.0\n\t#define cubeUV_r5 0.305\n\t#define cubeUV_m5 3.0\n\t#define cubeUV_r6 0.21\n\t#define cubeUV_m6 4.0\n\tfloat roughnessToMip( float roughness ) {\n\t\tfloat mip = 0.0;\n\t\tif ( roughness >= cubeUV_r1 ) {\n\t\t\tmip = ( cubeUV_r0 - roughness ) * ( cubeUV_m1 - cubeUV_m0 ) / ( cubeUV_r0 - cubeUV_r1 ) + cubeUV_m0;\n\t\t} else if ( roughness >= cubeUV_r4 ) {\n\t\t\tmip = ( cubeUV_r1 - roughness ) * ( cubeUV_m4 - cubeUV_m1 ) / ( cubeUV_r1 - cubeUV_r4 ) + cubeUV_m1;\n\t\t} else if ( roughness >= cubeUV_r5 ) {\n\t\t\tmip = ( cubeUV_r4 - roughness ) * ( cubeUV_m5 - cubeUV_m4 ) / ( cubeUV_r4 - cubeUV_r5 ) + cubeUV_m4;\n\t\t} else if ( roughness >= cubeUV_r6 ) {\n\t\t\tmip = ( cubeUV_r5 - roughness ) * ( cubeUV_m6 - cubeUV_m5 ) / ( cubeUV_r5 - cubeUV_r6 ) + cubeUV_m5;\n\t\t} else {\n\t\t\tmip = - 2.0 * log2( 1.16 * roughness );\t\t}\n\t\treturn mip;\n\t}\n\tvec4 textureCubeUV( sampler2D envMap, vec3 sampleDir, float roughness ) {\n\t\tfloat mip = clamp( roughnessToMip( roughness ), cubeUV_m0, CUBEUV_MAX_MIP );\n\t\tfloat mipF = fract( mip );\n\t\tfloat mipInt = floor( mip );\n\t\tvec3 color0 = bilinearCubeUV( envMap, sampleDir, mipInt );\n\t\tif ( mipF == 0.0 ) {\n\t\t\treturn vec4( color0, 1.0 );\n\t\t} else {\n\t\t\tvec3 color1 = bilinearCubeUV( envMap, sampleDir, mipInt + 1.0 );\n\t\t\treturn vec4( mix( color0, color1, mipF ), 1.0 );\n\t\t}\n\t}\n#endif"; - -var defaultnormal_vertex = "vec3 transformedNormal = objectNormal;\n#ifdef USE_TANGENT\n\tvec3 transformedTangent = objectTangent;\n#endif\n#ifdef USE_BATCHING\n\tmat3 bm = mat3( batchingMatrix );\n\ttransformedNormal /= vec3( dot( bm[ 0 ], bm[ 0 ] ), dot( bm[ 1 ], bm[ 1 ] ), dot( bm[ 2 ], bm[ 2 ] ) );\n\ttransformedNormal = bm * transformedNormal;\n\t#ifdef USE_TANGENT\n\t\ttransformedTangent = bm * transformedTangent;\n\t#endif\n#endif\n#ifdef USE_INSTANCING\n\tmat3 im = mat3( instanceMatrix );\n\ttransformedNormal /= vec3( dot( im[ 0 ], im[ 0 ] ), dot( im[ 1 ], im[ 1 ] ), dot( im[ 2 ], im[ 2 ] ) );\n\ttransformedNormal = im * transformedNormal;\n\t#ifdef USE_TANGENT\n\t\ttransformedTangent = im * transformedTangent;\n\t#endif\n#endif\ntransformedNormal = normalMatrix * transformedNormal;\n#ifdef FLIP_SIDED\n\ttransformedNormal = - transformedNormal;\n#endif\n#ifdef USE_TANGENT\n\ttransformedTangent = ( modelViewMatrix * vec4( transformedTangent, 0.0 ) ).xyz;\n\t#ifdef FLIP_SIDED\n\t\ttransformedTangent = - transformedTangent;\n\t#endif\n#endif"; - -var displacementmap_pars_vertex = "#ifdef USE_DISPLACEMENTMAP\n\tuniform sampler2D displacementMap;\n\tuniform float displacementScale;\n\tuniform float displacementBias;\n#endif"; - -var displacementmap_vertex = "#ifdef USE_DISPLACEMENTMAP\n\ttransformed += normalize( objectNormal ) * ( texture2D( displacementMap, vDisplacementMapUv ).x * displacementScale + displacementBias );\n#endif"; - -var emissivemap_fragment = "#ifdef USE_EMISSIVEMAP\n\tvec4 emissiveColor = texture2D( emissiveMap, vEmissiveMapUv );\n\ttotalEmissiveRadiance *= emissiveColor.rgb;\n#endif"; - -var emissivemap_pars_fragment = "#ifdef USE_EMISSIVEMAP\n\tuniform sampler2D emissiveMap;\n#endif"; - -var colorspace_fragment = "gl_FragColor = linearToOutputTexel( gl_FragColor );"; - -var colorspace_pars_fragment = "\nconst mat3 LINEAR_SRGB_TO_LINEAR_DISPLAY_P3 = mat3(\n\tvec3( 0.8224621, 0.177538, 0.0 ),\n\tvec3( 0.0331941, 0.9668058, 0.0 ),\n\tvec3( 0.0170827, 0.0723974, 0.9105199 )\n);\nconst mat3 LINEAR_DISPLAY_P3_TO_LINEAR_SRGB = mat3(\n\tvec3( 1.2249401, - 0.2249404, 0.0 ),\n\tvec3( - 0.0420569, 1.0420571, 0.0 ),\n\tvec3( - 0.0196376, - 0.0786361, 1.0982735 )\n);\nvec4 LinearSRGBToLinearDisplayP3( in vec4 value ) {\n\treturn vec4( value.rgb * LINEAR_SRGB_TO_LINEAR_DISPLAY_P3, value.a );\n}\nvec4 LinearDisplayP3ToLinearSRGB( in vec4 value ) {\n\treturn vec4( value.rgb * LINEAR_DISPLAY_P3_TO_LINEAR_SRGB, value.a );\n}\nvec4 LinearTransferOETF( in vec4 value ) {\n\treturn value;\n}\nvec4 sRGBTransferOETF( in vec4 value ) {\n\treturn vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.a );\n}\nvec4 LinearToLinear( in vec4 value ) {\n\treturn value;\n}\nvec4 LinearTosRGB( in vec4 value ) {\n\treturn sRGBTransferOETF( value );\n}"; - -var envmap_fragment = "#ifdef USE_ENVMAP\n\t#ifdef ENV_WORLDPOS\n\t\tvec3 cameraToFrag;\n\t\tif ( isOrthographic ) {\n\t\t\tcameraToFrag = normalize( vec3( - viewMatrix[ 0 ][ 2 ], - viewMatrix[ 1 ][ 2 ], - viewMatrix[ 2 ][ 2 ] ) );\n\t\t} else {\n\t\t\tcameraToFrag = normalize( vWorldPosition - cameraPosition );\n\t\t}\n\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvec3 reflectVec = reflect( cameraToFrag, worldNormal );\n\t\t#else\n\t\t\tvec3 reflectVec = refract( cameraToFrag, worldNormal, refractionRatio );\n\t\t#endif\n\t#else\n\t\tvec3 reflectVec = vReflect;\n\t#endif\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tvec4 envColor = textureCube( envMap, vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\n\t#else\n\t\tvec4 envColor = vec4( 0.0 );\n\t#endif\n\t#ifdef ENVMAP_BLENDING_MULTIPLY\n\t\toutgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_MIX )\n\t\toutgoingLight = mix( outgoingLight, envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_ADD )\n\t\toutgoingLight += envColor.xyz * specularStrength * reflectivity;\n\t#endif\n#endif"; - -var envmap_common_pars_fragment = "#ifdef USE_ENVMAP\n\tuniform float envMapIntensity;\n\tuniform float flipEnvMap;\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tuniform samplerCube envMap;\n\t#else\n\t\tuniform sampler2D envMap;\n\t#endif\n\t\n#endif"; - -var envmap_pars_fragment = "#ifdef USE_ENVMAP\n\tuniform float reflectivity;\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) || defined( LAMBERT )\n\t\t#define ENV_WORLDPOS\n\t#endif\n\t#ifdef ENV_WORLDPOS\n\t\tvarying vec3 vWorldPosition;\n\t\tuniform float refractionRatio;\n\t#else\n\t\tvarying vec3 vReflect;\n\t#endif\n#endif"; - -var envmap_pars_vertex = "#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) || defined( LAMBERT )\n\t\t#define ENV_WORLDPOS\n\t#endif\n\t#ifdef ENV_WORLDPOS\n\t\t\n\t\tvarying vec3 vWorldPosition;\n\t#else\n\t\tvarying vec3 vReflect;\n\t\tuniform float refractionRatio;\n\t#endif\n#endif"; - -var envmap_vertex = "#ifdef USE_ENVMAP\n\t#ifdef ENV_WORLDPOS\n\t\tvWorldPosition = worldPosition.xyz;\n\t#else\n\t\tvec3 cameraToVertex;\n\t\tif ( isOrthographic ) {\n\t\t\tcameraToVertex = normalize( vec3( - viewMatrix[ 0 ][ 2 ], - viewMatrix[ 1 ][ 2 ], - viewMatrix[ 2 ][ 2 ] ) );\n\t\t} else {\n\t\t\tcameraToVertex = normalize( worldPosition.xyz - cameraPosition );\n\t\t}\n\t\tvec3 worldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvReflect = reflect( cameraToVertex, worldNormal );\n\t\t#else\n\t\t\tvReflect = refract( cameraToVertex, worldNormal, refractionRatio );\n\t\t#endif\n\t#endif\n#endif"; - -var fog_vertex = "#ifdef USE_FOG\n\tvFogDepth = - mvPosition.z;\n#endif"; - -var fog_pars_vertex = "#ifdef USE_FOG\n\tvarying float vFogDepth;\n#endif"; - -var fog_fragment = "#ifdef USE_FOG\n\t#ifdef FOG_EXP2\n\t\tfloat fogFactor = 1.0 - exp( - fogDensity * fogDensity * vFogDepth * vFogDepth );\n\t#else\n\t\tfloat fogFactor = smoothstep( fogNear, fogFar, vFogDepth );\n\t#endif\n\tgl_FragColor.rgb = mix( gl_FragColor.rgb, fogColor, fogFactor );\n#endif"; - -var fog_pars_fragment = "#ifdef USE_FOG\n\tuniform vec3 fogColor;\n\tvarying float vFogDepth;\n\t#ifdef FOG_EXP2\n\t\tuniform float fogDensity;\n\t#else\n\t\tuniform float fogNear;\n\t\tuniform float fogFar;\n\t#endif\n#endif"; - -var gradientmap_pars_fragment = "#ifdef USE_GRADIENTMAP\n\tuniform sampler2D gradientMap;\n#endif\nvec3 getGradientIrradiance( vec3 normal, vec3 lightDirection ) {\n\tfloat dotNL = dot( normal, lightDirection );\n\tvec2 coord = vec2( dotNL * 0.5 + 0.5, 0.0 );\n\t#ifdef USE_GRADIENTMAP\n\t\treturn vec3( texture2D( gradientMap, coord ).r );\n\t#else\n\t\tvec2 fw = fwidth( coord ) * 0.5;\n\t\treturn mix( vec3( 0.7 ), vec3( 1.0 ), smoothstep( 0.7 - fw.x, 0.7 + fw.x, coord.x ) );\n\t#endif\n}"; - -var lightmap_fragment = "#ifdef USE_LIGHTMAP\n\tvec4 lightMapTexel = texture2D( lightMap, vLightMapUv );\n\tvec3 lightMapIrradiance = lightMapTexel.rgb * lightMapIntensity;\n\treflectedLight.indirectDiffuse += lightMapIrradiance;\n#endif"; - -var lightmap_pars_fragment = "#ifdef USE_LIGHTMAP\n\tuniform sampler2D lightMap;\n\tuniform float lightMapIntensity;\n#endif"; - -var lights_lambert_fragment = "LambertMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularStrength = specularStrength;"; - -var lights_lambert_pars_fragment = "varying vec3 vViewPosition;\nstruct LambertMaterial {\n\tvec3 diffuseColor;\n\tfloat specularStrength;\n};\nvoid RE_Direct_Lambert( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in LambertMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometryNormal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Lambert( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in LambertMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_Lambert\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Lambert"; - -var lights_pars_begin = "uniform bool receiveShadow;\nuniform vec3 ambientLightColor;\n#if defined( USE_LIGHT_PROBES )\n\tuniform vec3 lightProbe[ 9 ];\n#endif\nvec3 shGetIrradianceAt( in vec3 normal, in vec3 shCoefficients[ 9 ] ) {\n\tfloat x = normal.x, y = normal.y, z = normal.z;\n\tvec3 result = shCoefficients[ 0 ] * 0.886227;\n\tresult += shCoefficients[ 1 ] * 2.0 * 0.511664 * y;\n\tresult += shCoefficients[ 2 ] * 2.0 * 0.511664 * z;\n\tresult += shCoefficients[ 3 ] * 2.0 * 0.511664 * x;\n\tresult += shCoefficients[ 4 ] * 2.0 * 0.429043 * x * y;\n\tresult += shCoefficients[ 5 ] * 2.0 * 0.429043 * y * z;\n\tresult += shCoefficients[ 6 ] * ( 0.743125 * z * z - 0.247708 );\n\tresult += shCoefficients[ 7 ] * 2.0 * 0.429043 * x * z;\n\tresult += shCoefficients[ 8 ] * 0.429043 * ( x * x - y * y );\n\treturn result;\n}\nvec3 getLightProbeIrradiance( const in vec3 lightProbe[ 9 ], const in vec3 normal ) {\n\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\tvec3 irradiance = shGetIrradianceAt( worldNormal, lightProbe );\n\treturn irradiance;\n}\nvec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) {\n\tvec3 irradiance = ambientLightColor;\n\treturn irradiance;\n}\nfloat getDistanceAttenuation( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) {\n\t#if defined ( LEGACY_LIGHTS )\n\t\tif ( cutoffDistance > 0.0 && decayExponent > 0.0 ) {\n\t\t\treturn pow( saturate( - lightDistance / cutoffDistance + 1.0 ), decayExponent );\n\t\t}\n\t\treturn 1.0;\n\t#else\n\t\tfloat distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 );\n\t\tif ( cutoffDistance > 0.0 ) {\n\t\t\tdistanceFalloff *= pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );\n\t\t}\n\t\treturn distanceFalloff;\n\t#endif\n}\nfloat getSpotAttenuation( const in float coneCosine, const in float penumbraCosine, const in float angleCosine ) {\n\treturn smoothstep( coneCosine, penumbraCosine, angleCosine );\n}\n#if NUM_DIR_LIGHTS > 0\n\tstruct DirectionalLight {\n\t\tvec3 direction;\n\t\tvec3 color;\n\t};\n\tuniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ];\n\tvoid getDirectionalLightInfo( const in DirectionalLight directionalLight, out IncidentLight light ) {\n\t\tlight.color = directionalLight.color;\n\t\tlight.direction = directionalLight.direction;\n\t\tlight.visible = true;\n\t}\n#endif\n#if NUM_POINT_LIGHTS > 0\n\tstruct PointLight {\n\t\tvec3 position;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t};\n\tuniform PointLight pointLights[ NUM_POINT_LIGHTS ];\n\tvoid getPointLightInfo( const in PointLight pointLight, const in vec3 geometryPosition, out IncidentLight light ) {\n\t\tvec3 lVector = pointLight.position - geometryPosition;\n\t\tlight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tlight.color = pointLight.color;\n\t\tlight.color *= getDistanceAttenuation( lightDistance, pointLight.distance, pointLight.decay );\n\t\tlight.visible = ( light.color != vec3( 0.0 ) );\n\t}\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\tstruct SpotLight {\n\t\tvec3 position;\n\t\tvec3 direction;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t\tfloat coneCos;\n\t\tfloat penumbraCos;\n\t};\n\tuniform SpotLight spotLights[ NUM_SPOT_LIGHTS ];\n\tvoid getSpotLightInfo( const in SpotLight spotLight, const in vec3 geometryPosition, out IncidentLight light ) {\n\t\tvec3 lVector = spotLight.position - geometryPosition;\n\t\tlight.direction = normalize( lVector );\n\t\tfloat angleCos = dot( light.direction, spotLight.direction );\n\t\tfloat spotAttenuation = getSpotAttenuation( spotLight.coneCos, spotLight.penumbraCos, angleCos );\n\t\tif ( spotAttenuation > 0.0 ) {\n\t\t\tfloat lightDistance = length( lVector );\n\t\t\tlight.color = spotLight.color * spotAttenuation;\n\t\t\tlight.color *= getDistanceAttenuation( lightDistance, spotLight.distance, spotLight.decay );\n\t\t\tlight.visible = ( light.color != vec3( 0.0 ) );\n\t\t} else {\n\t\t\tlight.color = vec3( 0.0 );\n\t\t\tlight.visible = false;\n\t\t}\n\t}\n#endif\n#if NUM_RECT_AREA_LIGHTS > 0\n\tstruct RectAreaLight {\n\t\tvec3 color;\n\t\tvec3 position;\n\t\tvec3 halfWidth;\n\t\tvec3 halfHeight;\n\t};\n\tuniform sampler2D ltc_1;\tuniform sampler2D ltc_2;\n\tuniform RectAreaLight rectAreaLights[ NUM_RECT_AREA_LIGHTS ];\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\tstruct HemisphereLight {\n\t\tvec3 direction;\n\t\tvec3 skyColor;\n\t\tvec3 groundColor;\n\t};\n\tuniform HemisphereLight hemisphereLights[ NUM_HEMI_LIGHTS ];\n\tvec3 getHemisphereLightIrradiance( const in HemisphereLight hemiLight, const in vec3 normal ) {\n\t\tfloat dotNL = dot( normal, hemiLight.direction );\n\t\tfloat hemiDiffuseWeight = 0.5 * dotNL + 0.5;\n\t\tvec3 irradiance = mix( hemiLight.groundColor, hemiLight.skyColor, hemiDiffuseWeight );\n\t\treturn irradiance;\n\t}\n#endif"; - -var envmap_physical_pars_fragment = "#ifdef USE_ENVMAP\n\tvec3 getIBLIrradiance( const in vec3 normal ) {\n\t\t#ifdef ENVMAP_TYPE_CUBE_UV\n\t\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, worldNormal, 1.0 );\n\t\t\treturn PI * envMapColor.rgb * envMapIntensity;\n\t\t#else\n\t\t\treturn vec3( 0.0 );\n\t\t#endif\n\t}\n\tvec3 getIBLRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness ) {\n\t\t#ifdef ENVMAP_TYPE_CUBE_UV\n\t\t\tvec3 reflectVec = reflect( - viewDir, normal );\n\t\t\treflectVec = normalize( mix( reflectVec, normal, roughness * roughness) );\n\t\t\treflectVec = inverseTransformDirection( reflectVec, viewMatrix );\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, reflectVec, roughness );\n\t\t\treturn envMapColor.rgb * envMapIntensity;\n\t\t#else\n\t\t\treturn vec3( 0.0 );\n\t\t#endif\n\t}\n\t#ifdef USE_ANISOTROPY\n\t\tvec3 getIBLAnisotropyRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness, const in vec3 bitangent, const in float anisotropy ) {\n\t\t\t#ifdef ENVMAP_TYPE_CUBE_UV\n\t\t\t\tvec3 bentNormal = cross( bitangent, viewDir );\n\t\t\t\tbentNormal = normalize( cross( bentNormal, bitangent ) );\n\t\t\t\tbentNormal = normalize( mix( bentNormal, normal, pow2( pow2( 1.0 - anisotropy * ( 1.0 - roughness ) ) ) ) );\n\t\t\t\treturn getIBLRadiance( viewDir, bentNormal, roughness );\n\t\t\t#else\n\t\t\t\treturn vec3( 0.0 );\n\t\t\t#endif\n\t\t}\n\t#endif\n#endif"; - -var lights_toon_fragment = "ToonMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;"; - -var lights_toon_pars_fragment = "varying vec3 vViewPosition;\nstruct ToonMaterial {\n\tvec3 diffuseColor;\n};\nvoid RE_Direct_Toon( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in ToonMaterial material, inout ReflectedLight reflectedLight ) {\n\tvec3 irradiance = getGradientIrradiance( geometryNormal, directLight.direction ) * directLight.color;\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Toon( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in ToonMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_Toon\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Toon"; - -var lights_phong_fragment = "BlinnPhongMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularColor = specular;\nmaterial.specularShininess = shininess;\nmaterial.specularStrength = specularStrength;"; - -var lights_phong_pars_fragment = "varying vec3 vViewPosition;\nstruct BlinnPhongMaterial {\n\tvec3 diffuseColor;\n\tvec3 specularColor;\n\tfloat specularShininess;\n\tfloat specularStrength;\n};\nvoid RE_Direct_BlinnPhong( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometryNormal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n\treflectedLight.directSpecular += irradiance * BRDF_BlinnPhong( directLight.direction, geometryViewDir, geometryNormal, material.specularColor, material.specularShininess ) * material.specularStrength;\n}\nvoid RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_BlinnPhong\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_BlinnPhong"; - -var lights_physical_fragment = "PhysicalMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb * ( 1.0 - metalnessFactor );\nvec3 dxy = max( abs( dFdx( nonPerturbedNormal ) ), abs( dFdy( nonPerturbedNormal ) ) );\nfloat geometryRoughness = max( max( dxy.x, dxy.y ), dxy.z );\nmaterial.roughness = max( roughnessFactor, 0.0525 );material.roughness += geometryRoughness;\nmaterial.roughness = min( material.roughness, 1.0 );\n#ifdef IOR\n\tmaterial.ior = ior;\n\t#ifdef USE_SPECULAR\n\t\tfloat specularIntensityFactor = specularIntensity;\n\t\tvec3 specularColorFactor = specularColor;\n\t\t#ifdef USE_SPECULAR_COLORMAP\n\t\t\tspecularColorFactor *= texture2D( specularColorMap, vSpecularColorMapUv ).rgb;\n\t\t#endif\n\t\t#ifdef USE_SPECULAR_INTENSITYMAP\n\t\t\tspecularIntensityFactor *= texture2D( specularIntensityMap, vSpecularIntensityMapUv ).a;\n\t\t#endif\n\t\tmaterial.specularF90 = mix( specularIntensityFactor, 1.0, metalnessFactor );\n\t#else\n\t\tfloat specularIntensityFactor = 1.0;\n\t\tvec3 specularColorFactor = vec3( 1.0 );\n\t\tmaterial.specularF90 = 1.0;\n\t#endif\n\tmaterial.specularColor = mix( min( pow2( ( material.ior - 1.0 ) / ( material.ior + 1.0 ) ) * specularColorFactor, vec3( 1.0 ) ) * specularIntensityFactor, diffuseColor.rgb, metalnessFactor );\n#else\n\tmaterial.specularColor = mix( vec3( 0.04 ), diffuseColor.rgb, metalnessFactor );\n\tmaterial.specularF90 = 1.0;\n#endif\n#ifdef USE_CLEARCOAT\n\tmaterial.clearcoat = clearcoat;\n\tmaterial.clearcoatRoughness = clearcoatRoughness;\n\tmaterial.clearcoatF0 = vec3( 0.04 );\n\tmaterial.clearcoatF90 = 1.0;\n\t#ifdef USE_CLEARCOATMAP\n\t\tmaterial.clearcoat *= texture2D( clearcoatMap, vClearcoatMapUv ).x;\n\t#endif\n\t#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\t\tmaterial.clearcoatRoughness *= texture2D( clearcoatRoughnessMap, vClearcoatRoughnessMapUv ).y;\n\t#endif\n\tmaterial.clearcoat = saturate( material.clearcoat );\tmaterial.clearcoatRoughness = max( material.clearcoatRoughness, 0.0525 );\n\tmaterial.clearcoatRoughness += geometryRoughness;\n\tmaterial.clearcoatRoughness = min( material.clearcoatRoughness, 1.0 );\n#endif\n#ifdef USE_IRIDESCENCE\n\tmaterial.iridescence = iridescence;\n\tmaterial.iridescenceIOR = iridescenceIOR;\n\t#ifdef USE_IRIDESCENCEMAP\n\t\tmaterial.iridescence *= texture2D( iridescenceMap, vIridescenceMapUv ).r;\n\t#endif\n\t#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\t\tmaterial.iridescenceThickness = (iridescenceThicknessMaximum - iridescenceThicknessMinimum) * texture2D( iridescenceThicknessMap, vIridescenceThicknessMapUv ).g + iridescenceThicknessMinimum;\n\t#else\n\t\tmaterial.iridescenceThickness = iridescenceThicknessMaximum;\n\t#endif\n#endif\n#ifdef USE_SHEEN\n\tmaterial.sheenColor = sheenColor;\n\t#ifdef USE_SHEEN_COLORMAP\n\t\tmaterial.sheenColor *= texture2D( sheenColorMap, vSheenColorMapUv ).rgb;\n\t#endif\n\tmaterial.sheenRoughness = clamp( sheenRoughness, 0.07, 1.0 );\n\t#ifdef USE_SHEEN_ROUGHNESSMAP\n\t\tmaterial.sheenRoughness *= texture2D( sheenRoughnessMap, vSheenRoughnessMapUv ).a;\n\t#endif\n#endif\n#ifdef USE_ANISOTROPY\n\t#ifdef USE_ANISOTROPYMAP\n\t\tmat2 anisotropyMat = mat2( anisotropyVector.x, anisotropyVector.y, - anisotropyVector.y, anisotropyVector.x );\n\t\tvec3 anisotropyPolar = texture2D( anisotropyMap, vAnisotropyMapUv ).rgb;\n\t\tvec2 anisotropyV = anisotropyMat * normalize( 2.0 * anisotropyPolar.rg - vec2( 1.0 ) ) * anisotropyPolar.b;\n\t#else\n\t\tvec2 anisotropyV = anisotropyVector;\n\t#endif\n\tmaterial.anisotropy = length( anisotropyV );\n\tif( material.anisotropy == 0.0 ) {\n\t\tanisotropyV = vec2( 1.0, 0.0 );\n\t} else {\n\t\tanisotropyV /= material.anisotropy;\n\t\tmaterial.anisotropy = saturate( material.anisotropy );\n\t}\n\tmaterial.alphaT = mix( pow2( material.roughness ), 1.0, pow2( material.anisotropy ) );\n\tmaterial.anisotropyT = tbn[ 0 ] * anisotropyV.x + tbn[ 1 ] * anisotropyV.y;\n\tmaterial.anisotropyB = tbn[ 1 ] * anisotropyV.x - tbn[ 0 ] * anisotropyV.y;\n#endif"; - -var lights_physical_pars_fragment = "struct PhysicalMaterial {\n\tvec3 diffuseColor;\n\tfloat roughness;\n\tvec3 specularColor;\n\tfloat specularF90;\n\t#ifdef USE_CLEARCOAT\n\t\tfloat clearcoat;\n\t\tfloat clearcoatRoughness;\n\t\tvec3 clearcoatF0;\n\t\tfloat clearcoatF90;\n\t#endif\n\t#ifdef USE_IRIDESCENCE\n\t\tfloat iridescence;\n\t\tfloat iridescenceIOR;\n\t\tfloat iridescenceThickness;\n\t\tvec3 iridescenceFresnel;\n\t\tvec3 iridescenceF0;\n\t#endif\n\t#ifdef USE_SHEEN\n\t\tvec3 sheenColor;\n\t\tfloat sheenRoughness;\n\t#endif\n\t#ifdef IOR\n\t\tfloat ior;\n\t#endif\n\t#ifdef USE_TRANSMISSION\n\t\tfloat transmission;\n\t\tfloat transmissionAlpha;\n\t\tfloat thickness;\n\t\tfloat attenuationDistance;\n\t\tvec3 attenuationColor;\n\t#endif\n\t#ifdef USE_ANISOTROPY\n\t\tfloat anisotropy;\n\t\tfloat alphaT;\n\t\tvec3 anisotropyT;\n\t\tvec3 anisotropyB;\n\t#endif\n};\nvec3 clearcoatSpecularDirect = vec3( 0.0 );\nvec3 clearcoatSpecularIndirect = vec3( 0.0 );\nvec3 sheenSpecularDirect = vec3( 0.0 );\nvec3 sheenSpecularIndirect = vec3(0.0 );\nvec3 Schlick_to_F0( const in vec3 f, const in float f90, const in float dotVH ) {\n float x = clamp( 1.0 - dotVH, 0.0, 1.0 );\n float x2 = x * x;\n float x5 = clamp( x * x2 * x2, 0.0, 0.9999 );\n return ( f - vec3( f90 ) * x5 ) / ( 1.0 - x5 );\n}\nfloat V_GGX_SmithCorrelated( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\tfloat gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\treturn 0.5 / max( gv + gl, EPSILON );\n}\nfloat D_GGX( const in float alpha, const in float dotNH ) {\n\tfloat a2 = pow2( alpha );\n\tfloat denom = pow2( dotNH ) * ( a2 - 1.0 ) + 1.0;\n\treturn RECIPROCAL_PI * a2 / pow2( denom );\n}\n#ifdef USE_ANISOTROPY\n\tfloat V_GGX_SmithCorrelated_Anisotropic( const in float alphaT, const in float alphaB, const in float dotTV, const in float dotBV, const in float dotTL, const in float dotBL, const in float dotNV, const in float dotNL ) {\n\t\tfloat gv = dotNL * length( vec3( alphaT * dotTV, alphaB * dotBV, dotNV ) );\n\t\tfloat gl = dotNV * length( vec3( alphaT * dotTL, alphaB * dotBL, dotNL ) );\n\t\tfloat v = 0.5 / ( gv + gl );\n\t\treturn saturate(v);\n\t}\n\tfloat D_GGX_Anisotropic( const in float alphaT, const in float alphaB, const in float dotNH, const in float dotTH, const in float dotBH ) {\n\t\tfloat a2 = alphaT * alphaB;\n\t\thighp vec3 v = vec3( alphaB * dotTH, alphaT * dotBH, a2 * dotNH );\n\t\thighp float v2 = dot( v, v );\n\t\tfloat w2 = a2 / v2;\n\t\treturn RECIPROCAL_PI * a2 * pow2 ( w2 );\n\t}\n#endif\n#ifdef USE_CLEARCOAT\n\tvec3 BRDF_GGX_Clearcoat( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in PhysicalMaterial material) {\n\t\tvec3 f0 = material.clearcoatF0;\n\t\tfloat f90 = material.clearcoatF90;\n\t\tfloat roughness = material.clearcoatRoughness;\n\t\tfloat alpha = pow2( roughness );\n\t\tvec3 halfDir = normalize( lightDir + viewDir );\n\t\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\t\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\t\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\t\tfloat dotVH = saturate( dot( viewDir, halfDir ) );\n\t\tvec3 F = F_Schlick( f0, f90, dotVH );\n\t\tfloat V = V_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\t\tfloat D = D_GGX( alpha, dotNH );\n\t\treturn F * ( V * D );\n\t}\n#endif\nvec3 BRDF_GGX( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in PhysicalMaterial material ) {\n\tvec3 f0 = material.specularColor;\n\tfloat f90 = material.specularF90;\n\tfloat roughness = material.roughness;\n\tfloat alpha = pow2( roughness );\n\tvec3 halfDir = normalize( lightDir + viewDir );\n\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat dotVH = saturate( dot( viewDir, halfDir ) );\n\tvec3 F = F_Schlick( f0, f90, dotVH );\n\t#ifdef USE_IRIDESCENCE\n\t\tF = mix( F, material.iridescenceFresnel, material.iridescence );\n\t#endif\n\t#ifdef USE_ANISOTROPY\n\t\tfloat dotTL = dot( material.anisotropyT, lightDir );\n\t\tfloat dotTV = dot( material.anisotropyT, viewDir );\n\t\tfloat dotTH = dot( material.anisotropyT, halfDir );\n\t\tfloat dotBL = dot( material.anisotropyB, lightDir );\n\t\tfloat dotBV = dot( material.anisotropyB, viewDir );\n\t\tfloat dotBH = dot( material.anisotropyB, halfDir );\n\t\tfloat V = V_GGX_SmithCorrelated_Anisotropic( material.alphaT, alpha, dotTV, dotBV, dotTL, dotBL, dotNV, dotNL );\n\t\tfloat D = D_GGX_Anisotropic( material.alphaT, alpha, dotNH, dotTH, dotBH );\n\t#else\n\t\tfloat V = V_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\t\tfloat D = D_GGX( alpha, dotNH );\n\t#endif\n\treturn F * ( V * D );\n}\nvec2 LTC_Uv( const in vec3 N, const in vec3 V, const in float roughness ) {\n\tconst float LUT_SIZE = 64.0;\n\tconst float LUT_SCALE = ( LUT_SIZE - 1.0 ) / LUT_SIZE;\n\tconst float LUT_BIAS = 0.5 / LUT_SIZE;\n\tfloat dotNV = saturate( dot( N, V ) );\n\tvec2 uv = vec2( roughness, sqrt( 1.0 - dotNV ) );\n\tuv = uv * LUT_SCALE + LUT_BIAS;\n\treturn uv;\n}\nfloat LTC_ClippedSphereFormFactor( const in vec3 f ) {\n\tfloat l = length( f );\n\treturn max( ( l * l + f.z ) / ( l + 1.0 ), 0.0 );\n}\nvec3 LTC_EdgeVectorFormFactor( const in vec3 v1, const in vec3 v2 ) {\n\tfloat x = dot( v1, v2 );\n\tfloat y = abs( x );\n\tfloat a = 0.8543985 + ( 0.4965155 + 0.0145206 * y ) * y;\n\tfloat b = 3.4175940 + ( 4.1616724 + y ) * y;\n\tfloat v = a / b;\n\tfloat theta_sintheta = ( x > 0.0 ) ? v : 0.5 * inversesqrt( max( 1.0 - x * x, 1e-7 ) ) - v;\n\treturn cross( v1, v2 ) * theta_sintheta;\n}\nvec3 LTC_Evaluate( const in vec3 N, const in vec3 V, const in vec3 P, const in mat3 mInv, const in vec3 rectCoords[ 4 ] ) {\n\tvec3 v1 = rectCoords[ 1 ] - rectCoords[ 0 ];\n\tvec3 v2 = rectCoords[ 3 ] - rectCoords[ 0 ];\n\tvec3 lightNormal = cross( v1, v2 );\n\tif( dot( lightNormal, P - rectCoords[ 0 ] ) < 0.0 ) return vec3( 0.0 );\n\tvec3 T1, T2;\n\tT1 = normalize( V - N * dot( V, N ) );\n\tT2 = - cross( N, T1 );\n\tmat3 mat = mInv * transposeMat3( mat3( T1, T2, N ) );\n\tvec3 coords[ 4 ];\n\tcoords[ 0 ] = mat * ( rectCoords[ 0 ] - P );\n\tcoords[ 1 ] = mat * ( rectCoords[ 1 ] - P );\n\tcoords[ 2 ] = mat * ( rectCoords[ 2 ] - P );\n\tcoords[ 3 ] = mat * ( rectCoords[ 3 ] - P );\n\tcoords[ 0 ] = normalize( coords[ 0 ] );\n\tcoords[ 1 ] = normalize( coords[ 1 ] );\n\tcoords[ 2 ] = normalize( coords[ 2 ] );\n\tcoords[ 3 ] = normalize( coords[ 3 ] );\n\tvec3 vectorFormFactor = vec3( 0.0 );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 0 ], coords[ 1 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 1 ], coords[ 2 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 2 ], coords[ 3 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 3 ], coords[ 0 ] );\n\tfloat result = LTC_ClippedSphereFormFactor( vectorFormFactor );\n\treturn vec3( result );\n}\n#if defined( USE_SHEEN )\nfloat D_Charlie( float roughness, float dotNH ) {\n\tfloat alpha = pow2( roughness );\n\tfloat invAlpha = 1.0 / alpha;\n\tfloat cos2h = dotNH * dotNH;\n\tfloat sin2h = max( 1.0 - cos2h, 0.0078125 );\n\treturn ( 2.0 + invAlpha ) * pow( sin2h, invAlpha * 0.5 ) / ( 2.0 * PI );\n}\nfloat V_Neubelt( float dotNV, float dotNL ) {\n\treturn saturate( 1.0 / ( 4.0 * ( dotNL + dotNV - dotNL * dotNV ) ) );\n}\nvec3 BRDF_Sheen( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, vec3 sheenColor, const in float sheenRoughness ) {\n\tvec3 halfDir = normalize( lightDir + viewDir );\n\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat D = D_Charlie( sheenRoughness, dotNH );\n\tfloat V = V_Neubelt( dotNV, dotNL );\n\treturn sheenColor * ( D * V );\n}\n#endif\nfloat IBLSheenBRDF( const in vec3 normal, const in vec3 viewDir, const in float roughness ) {\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat r2 = roughness * roughness;\n\tfloat a = roughness < 0.25 ? -339.2 * r2 + 161.4 * roughness - 25.9 : -8.48 * r2 + 14.3 * roughness - 9.95;\n\tfloat b = roughness < 0.25 ? 44.0 * r2 - 23.7 * roughness + 3.26 : 1.97 * r2 - 3.27 * roughness + 0.72;\n\tfloat DG = exp( a * dotNV + b ) + ( roughness < 0.25 ? 0.0 : 0.1 * ( roughness - 0.25 ) );\n\treturn saturate( DG * RECIPROCAL_PI );\n}\nvec2 DFGApprox( const in vec3 normal, const in vec3 viewDir, const in float roughness ) {\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tconst vec4 c0 = vec4( - 1, - 0.0275, - 0.572, 0.022 );\n\tconst vec4 c1 = vec4( 1, 0.0425, 1.04, - 0.04 );\n\tvec4 r = roughness * c0 + c1;\n\tfloat a004 = min( r.x * r.x, exp2( - 9.28 * dotNV ) ) * r.x + r.y;\n\tvec2 fab = vec2( - 1.04, 1.04 ) * a004 + r.zw;\n\treturn fab;\n}\nvec3 EnvironmentBRDF( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float roughness ) {\n\tvec2 fab = DFGApprox( normal, viewDir, roughness );\n\treturn specularColor * fab.x + specularF90 * fab.y;\n}\n#ifdef USE_IRIDESCENCE\nvoid computeMultiscatteringIridescence( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float iridescence, const in vec3 iridescenceF0, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter ) {\n#else\nvoid computeMultiscattering( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter ) {\n#endif\n\tvec2 fab = DFGApprox( normal, viewDir, roughness );\n\t#ifdef USE_IRIDESCENCE\n\t\tvec3 Fr = mix( specularColor, iridescenceF0, iridescence );\n\t#else\n\t\tvec3 Fr = specularColor;\n\t#endif\n\tvec3 FssEss = Fr * fab.x + specularF90 * fab.y;\n\tfloat Ess = fab.x + fab.y;\n\tfloat Ems = 1.0 - Ess;\n\tvec3 Favg = Fr + ( 1.0 - Fr ) * 0.047619;\tvec3 Fms = FssEss * Favg / ( 1.0 - Ems * Favg );\n\tsingleScatter += FssEss;\n\tmultiScatter += Fms * Ems;\n}\n#if NUM_RECT_AREA_LIGHTS > 0\n\tvoid RE_Direct_RectArea_Physical( const in RectAreaLight rectAreaLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\t\tvec3 normal = geometryNormal;\n\t\tvec3 viewDir = geometryViewDir;\n\t\tvec3 position = geometryPosition;\n\t\tvec3 lightPos = rectAreaLight.position;\n\t\tvec3 halfWidth = rectAreaLight.halfWidth;\n\t\tvec3 halfHeight = rectAreaLight.halfHeight;\n\t\tvec3 lightColor = rectAreaLight.color;\n\t\tfloat roughness = material.roughness;\n\t\tvec3 rectCoords[ 4 ];\n\t\trectCoords[ 0 ] = lightPos + halfWidth - halfHeight;\t\trectCoords[ 1 ] = lightPos - halfWidth - halfHeight;\n\t\trectCoords[ 2 ] = lightPos - halfWidth + halfHeight;\n\t\trectCoords[ 3 ] = lightPos + halfWidth + halfHeight;\n\t\tvec2 uv = LTC_Uv( normal, viewDir, roughness );\n\t\tvec4 t1 = texture2D( ltc_1, uv );\n\t\tvec4 t2 = texture2D( ltc_2, uv );\n\t\tmat3 mInv = mat3(\n\t\t\tvec3( t1.x, 0, t1.y ),\n\t\t\tvec3( 0, 1, 0 ),\n\t\t\tvec3( t1.z, 0, t1.w )\n\t\t);\n\t\tvec3 fresnel = ( material.specularColor * t2.x + ( vec3( 1.0 ) - material.specularColor ) * t2.y );\n\t\treflectedLight.directSpecular += lightColor * fresnel * LTC_Evaluate( normal, viewDir, position, mInv, rectCoords );\n\t\treflectedLight.directDiffuse += lightColor * material.diffuseColor * LTC_Evaluate( normal, viewDir, position, mat3( 1.0 ), rectCoords );\n\t}\n#endif\nvoid RE_Direct_Physical( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometryNormal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\t#ifdef USE_CLEARCOAT\n\t\tfloat dotNLcc = saturate( dot( geometryClearcoatNormal, directLight.direction ) );\n\t\tvec3 ccIrradiance = dotNLcc * directLight.color;\n\t\tclearcoatSpecularDirect += ccIrradiance * BRDF_GGX_Clearcoat( directLight.direction, geometryViewDir, geometryClearcoatNormal, material );\n\t#endif\n\t#ifdef USE_SHEEN\n\t\tsheenSpecularDirect += irradiance * BRDF_Sheen( directLight.direction, geometryViewDir, geometryNormal, material.sheenColor, material.sheenRoughness );\n\t#endif\n\treflectedLight.directSpecular += irradiance * BRDF_GGX( directLight.direction, geometryViewDir, geometryNormal, material );\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Physical( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 irradiance, const in vec3 clearcoatRadiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight) {\n\t#ifdef USE_CLEARCOAT\n\t\tclearcoatSpecularIndirect += clearcoatRadiance * EnvironmentBRDF( geometryClearcoatNormal, geometryViewDir, material.clearcoatF0, material.clearcoatF90, material.clearcoatRoughness );\n\t#endif\n\t#ifdef USE_SHEEN\n\t\tsheenSpecularIndirect += irradiance * material.sheenColor * IBLSheenBRDF( geometryNormal, geometryViewDir, material.sheenRoughness );\n\t#endif\n\tvec3 singleScattering = vec3( 0.0 );\n\tvec3 multiScattering = vec3( 0.0 );\n\tvec3 cosineWeightedIrradiance = irradiance * RECIPROCAL_PI;\n\t#ifdef USE_IRIDESCENCE\n\t\tcomputeMultiscatteringIridescence( geometryNormal, geometryViewDir, material.specularColor, material.specularF90, material.iridescence, material.iridescenceFresnel, material.roughness, singleScattering, multiScattering );\n\t#else\n\t\tcomputeMultiscattering( geometryNormal, geometryViewDir, material.specularColor, material.specularF90, material.roughness, singleScattering, multiScattering );\n\t#endif\n\tvec3 totalScattering = singleScattering + multiScattering;\n\tvec3 diffuse = material.diffuseColor * ( 1.0 - max( max( totalScattering.r, totalScattering.g ), totalScattering.b ) );\n\treflectedLight.indirectSpecular += radiance * singleScattering;\n\treflectedLight.indirectSpecular += multiScattering * cosineWeightedIrradiance;\n\treflectedLight.indirectDiffuse += diffuse * cosineWeightedIrradiance;\n}\n#define RE_Direct\t\t\t\tRE_Direct_Physical\n#define RE_Direct_RectArea\t\tRE_Direct_RectArea_Physical\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Physical\n#define RE_IndirectSpecular\t\tRE_IndirectSpecular_Physical\nfloat computeSpecularOcclusion( const in float dotNV, const in float ambientOcclusion, const in float roughness ) {\n\treturn saturate( pow( dotNV + ambientOcclusion, exp2( - 16.0 * roughness - 1.0 ) ) - 1.0 + ambientOcclusion );\n}"; - -var lights_fragment_begin = "\nvec3 geometryPosition = - vViewPosition;\nvec3 geometryNormal = normal;\nvec3 geometryViewDir = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( vViewPosition );\nvec3 geometryClearcoatNormal = vec3( 0.0 );\n#ifdef USE_CLEARCOAT\n\tgeometryClearcoatNormal = clearcoatNormal;\n#endif\n#ifdef USE_IRIDESCENCE\n\tfloat dotNVi = saturate( dot( normal, geometryViewDir ) );\n\tif ( material.iridescenceThickness == 0.0 ) {\n\t\tmaterial.iridescence = 0.0;\n\t} else {\n\t\tmaterial.iridescence = saturate( material.iridescence );\n\t}\n\tif ( material.iridescence > 0.0 ) {\n\t\tmaterial.iridescenceFresnel = evalIridescence( 1.0, material.iridescenceIOR, dotNVi, material.iridescenceThickness, material.specularColor );\n\t\tmaterial.iridescenceF0 = Schlick_to_F0( material.iridescenceFresnel, 1.0, dotNVi );\n\t}\n#endif\nIncidentLight directLight;\n#if ( NUM_POINT_LIGHTS > 0 ) && defined( RE_Direct )\n\tPointLight pointLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_POINT_LIGHT_SHADOWS > 0\n\tPointLightShadow pointLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tpointLight = pointLights[ i ];\n\t\tgetPointLightInfo( pointLight, geometryPosition, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_POINT_LIGHT_SHADOWS )\n\t\tpointLightShadow = pointLightShadows[ i ];\n\t\tdirectLight.color *= ( directLight.visible && receiveShadow ) ? getPointShadow( pointShadowMap[ i ], pointLightShadow.shadowMapSize, pointLightShadow.shadowBias, pointLightShadow.shadowRadius, vPointShadowCoord[ i ], pointLightShadow.shadowCameraNear, pointLightShadow.shadowCameraFar ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct )\n\tSpotLight spotLight;\n\tvec4 spotColor;\n\tvec3 spotLightCoord;\n\tbool inSpotLightMap;\n\t#if defined( USE_SHADOWMAP ) && NUM_SPOT_LIGHT_SHADOWS > 0\n\tSpotLightShadow spotLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tspotLight = spotLights[ i ];\n\t\tgetSpotLightInfo( spotLight, geometryPosition, directLight );\n\t\t#if ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS )\n\t\t#define SPOT_LIGHT_MAP_INDEX UNROLLED_LOOP_INDEX\n\t\t#elif ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\t#define SPOT_LIGHT_MAP_INDEX NUM_SPOT_LIGHT_MAPS\n\t\t#else\n\t\t#define SPOT_LIGHT_MAP_INDEX ( UNROLLED_LOOP_INDEX - NUM_SPOT_LIGHT_SHADOWS + NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS )\n\t\t#endif\n\t\t#if ( SPOT_LIGHT_MAP_INDEX < NUM_SPOT_LIGHT_MAPS )\n\t\t\tspotLightCoord = vSpotLightCoord[ i ].xyz / vSpotLightCoord[ i ].w;\n\t\t\tinSpotLightMap = all( lessThan( abs( spotLightCoord * 2. - 1. ), vec3( 1.0 ) ) );\n\t\t\tspotColor = texture2D( spotLightMap[ SPOT_LIGHT_MAP_INDEX ], spotLightCoord.xy );\n\t\t\tdirectLight.color = inSpotLightMap ? directLight.color * spotColor.rgb : directLight.color;\n\t\t#endif\n\t\t#undef SPOT_LIGHT_MAP_INDEX\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\tspotLightShadow = spotLightShadows[ i ];\n\t\tdirectLight.color *= ( directLight.visible && receiveShadow ) ? getShadow( spotShadowMap[ i ], spotLightShadow.shadowMapSize, spotLightShadow.shadowBias, spotLightShadow.shadowRadius, vSpotLightCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_DIR_LIGHTS > 0 ) && defined( RE_Direct )\n\tDirectionalLight directionalLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_DIR_LIGHT_SHADOWS > 0\n\tDirectionalLightShadow directionalLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tdirectionalLight = directionalLights[ i ];\n\t\tgetDirectionalLightInfo( directionalLight, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_DIR_LIGHT_SHADOWS )\n\t\tdirectionalLightShadow = directionalLightShadows[ i ];\n\t\tdirectLight.color *= ( directLight.visible && receiveShadow ) ? getShadow( directionalShadowMap[ i ], directionalLightShadow.shadowMapSize, directionalLightShadow.shadowBias, directionalLightShadow.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_RECT_AREA_LIGHTS > 0 ) && defined( RE_Direct_RectArea )\n\tRectAreaLight rectAreaLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_RECT_AREA_LIGHTS; i ++ ) {\n\t\trectAreaLight = rectAreaLights[ i ];\n\t\tRE_Direct_RectArea( rectAreaLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if defined( RE_IndirectDiffuse )\n\tvec3 iblIrradiance = vec3( 0.0 );\n\tvec3 irradiance = getAmbientLightIrradiance( ambientLightColor );\n\t#if defined( USE_LIGHT_PROBES )\n\t\tirradiance += getLightProbeIrradiance( lightProbe, geometryNormal );\n\t#endif\n\t#if ( NUM_HEMI_LIGHTS > 0 )\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\t\tirradiance += getHemisphereLightIrradiance( hemisphereLights[ i ], geometryNormal );\n\t\t}\n\t\t#pragma unroll_loop_end\n\t#endif\n#endif\n#if defined( RE_IndirectSpecular )\n\tvec3 radiance = vec3( 0.0 );\n\tvec3 clearcoatRadiance = vec3( 0.0 );\n#endif"; - -var lights_fragment_maps = "#if defined( RE_IndirectDiffuse )\n\t#ifdef USE_LIGHTMAP\n\t\tvec4 lightMapTexel = texture2D( lightMap, vLightMapUv );\n\t\tvec3 lightMapIrradiance = lightMapTexel.rgb * lightMapIntensity;\n\t\tirradiance += lightMapIrradiance;\n\t#endif\n\t#if defined( USE_ENVMAP ) && defined( STANDARD ) && defined( ENVMAP_TYPE_CUBE_UV )\n\t\tiblIrradiance += getIBLIrradiance( geometryNormal );\n\t#endif\n#endif\n#if defined( USE_ENVMAP ) && defined( RE_IndirectSpecular )\n\t#ifdef USE_ANISOTROPY\n\t\tradiance += getIBLAnisotropyRadiance( geometryViewDir, geometryNormal, material.roughness, material.anisotropyB, material.anisotropy );\n\t#else\n\t\tradiance += getIBLRadiance( geometryViewDir, geometryNormal, material.roughness );\n\t#endif\n\t#ifdef USE_CLEARCOAT\n\t\tclearcoatRadiance += getIBLRadiance( geometryViewDir, geometryClearcoatNormal, material.clearcoatRoughness );\n\t#endif\n#endif"; - -var lights_fragment_end = "#if defined( RE_IndirectDiffuse )\n\tRE_IndirectDiffuse( irradiance, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n#endif\n#if defined( RE_IndirectSpecular )\n\tRE_IndirectSpecular( radiance, iblIrradiance, clearcoatRadiance, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n#endif"; - -var logdepthbuf_fragment = "#if defined( USE_LOGDEPTHBUF ) && defined( USE_LOGDEPTHBUF_EXT )\n\tgl_FragDepthEXT = vIsPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;\n#endif"; - -var logdepthbuf_pars_fragment = "#if defined( USE_LOGDEPTHBUF ) && defined( USE_LOGDEPTHBUF_EXT )\n\tuniform float logDepthBufFC;\n\tvarying float vFragDepth;\n\tvarying float vIsPerspective;\n#endif"; - -var logdepthbuf_pars_vertex = "#ifdef USE_LOGDEPTHBUF\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvarying float vFragDepth;\n\t\tvarying float vIsPerspective;\n\t#else\n\t\tuniform float logDepthBufFC;\n\t#endif\n#endif"; - -var logdepthbuf_vertex = "#ifdef USE_LOGDEPTHBUF\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvFragDepth = 1.0 + gl_Position.w;\n\t\tvIsPerspective = float( isPerspectiveMatrix( projectionMatrix ) );\n\t#else\n\t\tif ( isPerspectiveMatrix( projectionMatrix ) ) {\n\t\t\tgl_Position.z = log2( max( EPSILON, gl_Position.w + 1.0 ) ) * logDepthBufFC - 1.0;\n\t\t\tgl_Position.z *= gl_Position.w;\n\t\t}\n\t#endif\n#endif"; - -var map_fragment = "#ifdef USE_MAP\n\tvec4 sampledDiffuseColor = texture2D( map, vMapUv );\n\t#ifdef DECODE_VIDEO_TEXTURE\n\t\tsampledDiffuseColor = vec4( mix( pow( sampledDiffuseColor.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), sampledDiffuseColor.rgb * 0.0773993808, vec3( lessThanEqual( sampledDiffuseColor.rgb, vec3( 0.04045 ) ) ) ), sampledDiffuseColor.w );\n\t\n\t#endif\n\tdiffuseColor *= sampledDiffuseColor;\n#endif"; - -var map_pars_fragment = "#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif"; - -var map_particle_fragment = "#if defined( USE_MAP ) || defined( USE_ALPHAMAP )\n\t#if defined( USE_POINTS_UV )\n\t\tvec2 uv = vUv;\n\t#else\n\t\tvec2 uv = ( uvTransform * vec3( gl_PointCoord.x, 1.0 - gl_PointCoord.y, 1 ) ).xy;\n\t#endif\n#endif\n#ifdef USE_MAP\n\tdiffuseColor *= texture2D( map, uv );\n#endif\n#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, uv ).g;\n#endif"; - -var map_particle_pars_fragment = "#if defined( USE_POINTS_UV )\n\tvarying vec2 vUv;\n#else\n\t#if defined( USE_MAP ) || defined( USE_ALPHAMAP )\n\t\tuniform mat3 uvTransform;\n\t#endif\n#endif\n#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif\n#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif"; - -var metalnessmap_fragment = "float metalnessFactor = metalness;\n#ifdef USE_METALNESSMAP\n\tvec4 texelMetalness = texture2D( metalnessMap, vMetalnessMapUv );\n\tmetalnessFactor *= texelMetalness.b;\n#endif"; - -var metalnessmap_pars_fragment = "#ifdef USE_METALNESSMAP\n\tuniform sampler2D metalnessMap;\n#endif"; - -var morphcolor_vertex = "#if defined( USE_MORPHCOLORS ) && defined( MORPHTARGETS_TEXTURE )\n\tvColor *= morphTargetBaseInfluence;\n\tfor ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) {\n\t\t#if defined( USE_COLOR_ALPHA )\n\t\t\tif ( morphTargetInfluences[ i ] != 0.0 ) vColor += getMorph( gl_VertexID, i, 2 ) * morphTargetInfluences[ i ];\n\t\t#elif defined( USE_COLOR )\n\t\t\tif ( morphTargetInfluences[ i ] != 0.0 ) vColor += getMorph( gl_VertexID, i, 2 ).rgb * morphTargetInfluences[ i ];\n\t\t#endif\n\t}\n#endif"; - -var morphnormal_vertex = "#ifdef USE_MORPHNORMALS\n\tobjectNormal *= morphTargetBaseInfluence;\n\t#ifdef MORPHTARGETS_TEXTURE\n\t\tfor ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) {\n\t\t\tif ( morphTargetInfluences[ i ] != 0.0 ) objectNormal += getMorph( gl_VertexID, i, 1 ).xyz * morphTargetInfluences[ i ];\n\t\t}\n\t#else\n\t\tobjectNormal += morphNormal0 * morphTargetInfluences[ 0 ];\n\t\tobjectNormal += morphNormal1 * morphTargetInfluences[ 1 ];\n\t\tobjectNormal += morphNormal2 * morphTargetInfluences[ 2 ];\n\t\tobjectNormal += morphNormal3 * morphTargetInfluences[ 3 ];\n\t#endif\n#endif"; - -var morphtarget_pars_vertex = "#ifdef USE_MORPHTARGETS\n\tuniform float morphTargetBaseInfluence;\n\t#ifdef MORPHTARGETS_TEXTURE\n\t\tuniform float morphTargetInfluences[ MORPHTARGETS_COUNT ];\n\t\tuniform sampler2DArray morphTargetsTexture;\n\t\tuniform ivec2 morphTargetsTextureSize;\n\t\tvec4 getMorph( const in int vertexIndex, const in int morphTargetIndex, const in int offset ) {\n\t\t\tint texelIndex = vertexIndex * MORPHTARGETS_TEXTURE_STRIDE + offset;\n\t\t\tint y = texelIndex / morphTargetsTextureSize.x;\n\t\t\tint x = texelIndex - y * morphTargetsTextureSize.x;\n\t\t\tivec3 morphUV = ivec3( x, y, morphTargetIndex );\n\t\t\treturn texelFetch( morphTargetsTexture, morphUV, 0 );\n\t\t}\n\t#else\n\t\t#ifndef USE_MORPHNORMALS\n\t\t\tuniform float morphTargetInfluences[ 8 ];\n\t\t#else\n\t\t\tuniform float morphTargetInfluences[ 4 ];\n\t\t#endif\n\t#endif\n#endif"; - -var morphtarget_vertex = "#ifdef USE_MORPHTARGETS\n\ttransformed *= morphTargetBaseInfluence;\n\t#ifdef MORPHTARGETS_TEXTURE\n\t\tfor ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) {\n\t\t\tif ( morphTargetInfluences[ i ] != 0.0 ) transformed += getMorph( gl_VertexID, i, 0 ).xyz * morphTargetInfluences[ i ];\n\t\t}\n\t#else\n\t\ttransformed += morphTarget0 * morphTargetInfluences[ 0 ];\n\t\ttransformed += morphTarget1 * morphTargetInfluences[ 1 ];\n\t\ttransformed += morphTarget2 * morphTargetInfluences[ 2 ];\n\t\ttransformed += morphTarget3 * morphTargetInfluences[ 3 ];\n\t\t#ifndef USE_MORPHNORMALS\n\t\t\ttransformed += morphTarget4 * morphTargetInfluences[ 4 ];\n\t\t\ttransformed += morphTarget5 * morphTargetInfluences[ 5 ];\n\t\t\ttransformed += morphTarget6 * morphTargetInfluences[ 6 ];\n\t\t\ttransformed += morphTarget7 * morphTargetInfluences[ 7 ];\n\t\t#endif\n\t#endif\n#endif"; - -var normal_fragment_begin = "float faceDirection = gl_FrontFacing ? 1.0 : - 1.0;\n#ifdef FLAT_SHADED\n\tvec3 fdx = dFdx( vViewPosition );\n\tvec3 fdy = dFdy( vViewPosition );\n\tvec3 normal = normalize( cross( fdx, fdy ) );\n#else\n\tvec3 normal = normalize( vNormal );\n\t#ifdef DOUBLE_SIDED\n\t\tnormal *= faceDirection;\n\t#endif\n#endif\n#if defined( USE_NORMALMAP_TANGENTSPACE ) || defined( USE_CLEARCOAT_NORMALMAP ) || defined( USE_ANISOTROPY )\n\t#ifdef USE_TANGENT\n\t\tmat3 tbn = mat3( normalize( vTangent ), normalize( vBitangent ), normal );\n\t#else\n\t\tmat3 tbn = getTangentFrame( - vViewPosition, normal,\n\t\t#if defined( USE_NORMALMAP )\n\t\t\tvNormalMapUv\n\t\t#elif defined( USE_CLEARCOAT_NORMALMAP )\n\t\t\tvClearcoatNormalMapUv\n\t\t#else\n\t\t\tvUv\n\t\t#endif\n\t\t);\n\t#endif\n\t#if defined( DOUBLE_SIDED ) && ! defined( FLAT_SHADED )\n\t\ttbn[0] *= faceDirection;\n\t\ttbn[1] *= faceDirection;\n\t#endif\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\t#ifdef USE_TANGENT\n\t\tmat3 tbn2 = mat3( normalize( vTangent ), normalize( vBitangent ), normal );\n\t#else\n\t\tmat3 tbn2 = getTangentFrame( - vViewPosition, normal, vClearcoatNormalMapUv );\n\t#endif\n\t#if defined( DOUBLE_SIDED ) && ! defined( FLAT_SHADED )\n\t\ttbn2[0] *= faceDirection;\n\t\ttbn2[1] *= faceDirection;\n\t#endif\n#endif\nvec3 nonPerturbedNormal = normal;"; - -var normal_fragment_maps = "#ifdef USE_NORMALMAP_OBJECTSPACE\n\tnormal = texture2D( normalMap, vNormalMapUv ).xyz * 2.0 - 1.0;\n\t#ifdef FLIP_SIDED\n\t\tnormal = - normal;\n\t#endif\n\t#ifdef DOUBLE_SIDED\n\t\tnormal = normal * faceDirection;\n\t#endif\n\tnormal = normalize( normalMatrix * normal );\n#elif defined( USE_NORMALMAP_TANGENTSPACE )\n\tvec3 mapN = texture2D( normalMap, vNormalMapUv ).xyz * 2.0 - 1.0;\n\tmapN.xy *= normalScale;\n\tnormal = normalize( tbn * mapN );\n#elif defined( USE_BUMPMAP )\n\tnormal = perturbNormalArb( - vViewPosition, normal, dHdxy_fwd(), faceDirection );\n#endif"; - -var normal_pars_fragment = "#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n\t#ifdef USE_TANGENT\n\t\tvarying vec3 vTangent;\n\t\tvarying vec3 vBitangent;\n\t#endif\n#endif"; - -var normal_pars_vertex = "#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n\t#ifdef USE_TANGENT\n\t\tvarying vec3 vTangent;\n\t\tvarying vec3 vBitangent;\n\t#endif\n#endif"; - -var normal_vertex = "#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n\t#ifdef USE_TANGENT\n\t\tvTangent = normalize( transformedTangent );\n\t\tvBitangent = normalize( cross( vNormal, vTangent ) * tangent.w );\n\t#endif\n#endif"; - -var normalmap_pars_fragment = "#ifdef USE_NORMALMAP\n\tuniform sampler2D normalMap;\n\tuniform vec2 normalScale;\n#endif\n#ifdef USE_NORMALMAP_OBJECTSPACE\n\tuniform mat3 normalMatrix;\n#endif\n#if ! defined ( USE_TANGENT ) && ( defined ( USE_NORMALMAP_TANGENTSPACE ) || defined ( USE_CLEARCOAT_NORMALMAP ) || defined( USE_ANISOTROPY ) )\n\tmat3 getTangentFrame( vec3 eye_pos, vec3 surf_norm, vec2 uv ) {\n\t\tvec3 q0 = dFdx( eye_pos.xyz );\n\t\tvec3 q1 = dFdy( eye_pos.xyz );\n\t\tvec2 st0 = dFdx( uv.st );\n\t\tvec2 st1 = dFdy( uv.st );\n\t\tvec3 N = surf_norm;\n\t\tvec3 q1perp = cross( q1, N );\n\t\tvec3 q0perp = cross( N, q0 );\n\t\tvec3 T = q1perp * st0.x + q0perp * st1.x;\n\t\tvec3 B = q1perp * st0.y + q0perp * st1.y;\n\t\tfloat det = max( dot( T, T ), dot( B, B ) );\n\t\tfloat scale = ( det == 0.0 ) ? 0.0 : inversesqrt( det );\n\t\treturn mat3( T * scale, B * scale, N );\n\t}\n#endif"; - -var clearcoat_normal_fragment_begin = "#ifdef USE_CLEARCOAT\n\tvec3 clearcoatNormal = nonPerturbedNormal;\n#endif"; - -var clearcoat_normal_fragment_maps = "#ifdef USE_CLEARCOAT_NORMALMAP\n\tvec3 clearcoatMapN = texture2D( clearcoatNormalMap, vClearcoatNormalMapUv ).xyz * 2.0 - 1.0;\n\tclearcoatMapN.xy *= clearcoatNormalScale;\n\tclearcoatNormal = normalize( tbn2 * clearcoatMapN );\n#endif"; - -var clearcoat_pars_fragment = "#ifdef USE_CLEARCOATMAP\n\tuniform sampler2D clearcoatMap;\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\tuniform sampler2D clearcoatNormalMap;\n\tuniform vec2 clearcoatNormalScale;\n#endif\n#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\tuniform sampler2D clearcoatRoughnessMap;\n#endif"; - -var iridescence_pars_fragment = "#ifdef USE_IRIDESCENCEMAP\n\tuniform sampler2D iridescenceMap;\n#endif\n#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\tuniform sampler2D iridescenceThicknessMap;\n#endif"; - -var opaque_fragment = "#ifdef OPAQUE\ndiffuseColor.a = 1.0;\n#endif\n#ifdef USE_TRANSMISSION\ndiffuseColor.a *= material.transmissionAlpha;\n#endif\ngl_FragColor = vec4( outgoingLight, diffuseColor.a );"; - -var packing = "vec3 packNormalToRGB( const in vec3 normal ) {\n\treturn normalize( normal ) * 0.5 + 0.5;\n}\nvec3 unpackRGBToNormal( const in vec3 rgb ) {\n\treturn 2.0 * rgb.xyz - 1.0;\n}\nconst float PackUpscale = 256. / 255.;const float UnpackDownscale = 255. / 256.;\nconst vec3 PackFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );\nconst vec4 UnpackFactors = UnpackDownscale / vec4( PackFactors, 1. );\nconst float ShiftRight8 = 1. / 256.;\nvec4 packDepthToRGBA( const in float v ) {\n\tvec4 r = vec4( fract( v * PackFactors ), v );\n\tr.yzw -= r.xyz * ShiftRight8;\treturn r * PackUpscale;\n}\nfloat unpackRGBAToDepth( const in vec4 v ) {\n\treturn dot( v, UnpackFactors );\n}\nvec2 packDepthToRG( in highp float v ) {\n\treturn packDepthToRGBA( v ).yx;\n}\nfloat unpackRGToDepth( const in highp vec2 v ) {\n\treturn unpackRGBAToDepth( vec4( v.xy, 0.0, 0.0 ) );\n}\nvec4 pack2HalfToRGBA( vec2 v ) {\n\tvec4 r = vec4( v.x, fract( v.x * 255.0 ), v.y, fract( v.y * 255.0 ) );\n\treturn vec4( r.x - r.y / 255.0, r.y, r.z - r.w / 255.0, r.w );\n}\nvec2 unpackRGBATo2Half( vec4 v ) {\n\treturn vec2( v.x + ( v.y / 255.0 ), v.z + ( v.w / 255.0 ) );\n}\nfloat viewZToOrthographicDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn ( viewZ + near ) / ( near - far );\n}\nfloat orthographicDepthToViewZ( const in float depth, const in float near, const in float far ) {\n\treturn depth * ( near - far ) - near;\n}\nfloat viewZToPerspectiveDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn ( ( near + viewZ ) * far ) / ( ( far - near ) * viewZ );\n}\nfloat perspectiveDepthToViewZ( const in float depth, const in float near, const in float far ) {\n\treturn ( near * far ) / ( ( far - near ) * depth - far );\n}"; - -var premultiplied_alpha_fragment = "#ifdef PREMULTIPLIED_ALPHA\n\tgl_FragColor.rgb *= gl_FragColor.a;\n#endif"; - -var project_vertex = "vec4 mvPosition = vec4( transformed, 1.0 );\n#ifdef USE_BATCHING\n\tmvPosition = batchingMatrix * mvPosition;\n#endif\n#ifdef USE_INSTANCING\n\tmvPosition = instanceMatrix * mvPosition;\n#endif\nmvPosition = modelViewMatrix * mvPosition;\ngl_Position = projectionMatrix * mvPosition;"; - -var dithering_fragment = "#ifdef DITHERING\n\tgl_FragColor.rgb = dithering( gl_FragColor.rgb );\n#endif"; - -var dithering_pars_fragment = "#ifdef DITHERING\n\tvec3 dithering( vec3 color ) {\n\t\tfloat grid_position = rand( gl_FragCoord.xy );\n\t\tvec3 dither_shift_RGB = vec3( 0.25 / 255.0, -0.25 / 255.0, 0.25 / 255.0 );\n\t\tdither_shift_RGB = mix( 2.0 * dither_shift_RGB, -2.0 * dither_shift_RGB, grid_position );\n\t\treturn color + dither_shift_RGB;\n\t}\n#endif"; - -var roughnessmap_fragment = "float roughnessFactor = roughness;\n#ifdef USE_ROUGHNESSMAP\n\tvec4 texelRoughness = texture2D( roughnessMap, vRoughnessMapUv );\n\troughnessFactor *= texelRoughness.g;\n#endif"; - -var roughnessmap_pars_fragment = "#ifdef USE_ROUGHNESSMAP\n\tuniform sampler2D roughnessMap;\n#endif"; - -var shadowmap_pars_fragment = "#if NUM_SPOT_LIGHT_COORDS > 0\n\tvarying vec4 vSpotLightCoord[ NUM_SPOT_LIGHT_COORDS ];\n#endif\n#if NUM_SPOT_LIGHT_MAPS > 0\n\tuniform sampler2D spotLightMap[ NUM_SPOT_LIGHT_MAPS ];\n#endif\n#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D directionalShadowMap[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tstruct DirectionalLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D spotShadowMap[ NUM_SPOT_LIGHT_SHADOWS ];\n\t\tstruct SpotLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D pointShadowMap[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tstruct PointLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t\tfloat shadowCameraNear;\n\t\t\tfloat shadowCameraFar;\n\t\t};\n\t\tuniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ];\n\t#endif\n\tfloat texture2DCompare( sampler2D depths, vec2 uv, float compare ) {\n\t\treturn step( compare, unpackRGBAToDepth( texture2D( depths, uv ) ) );\n\t}\n\tvec2 texture2DDistribution( sampler2D shadow, vec2 uv ) {\n\t\treturn unpackRGBATo2Half( texture2D( shadow, uv ) );\n\t}\n\tfloat VSMShadow (sampler2D shadow, vec2 uv, float compare ){\n\t\tfloat occlusion = 1.0;\n\t\tvec2 distribution = texture2DDistribution( shadow, uv );\n\t\tfloat hard_shadow = step( compare , distribution.x );\n\t\tif (hard_shadow != 1.0 ) {\n\t\t\tfloat distance = compare - distribution.x ;\n\t\t\tfloat variance = max( 0.00000, distribution.y * distribution.y );\n\t\t\tfloat softness_probability = variance / (variance + distance * distance );\t\t\tsoftness_probability = clamp( ( softness_probability - 0.3 ) / ( 0.95 - 0.3 ), 0.0, 1.0 );\t\t\tocclusion = clamp( max( hard_shadow, softness_probability ), 0.0, 1.0 );\n\t\t}\n\t\treturn occlusion;\n\t}\n\tfloat getShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord ) {\n\t\tfloat shadow = 1.0;\n\t\tshadowCoord.xyz /= shadowCoord.w;\n\t\tshadowCoord.z += shadowBias;\n\t\tbool inFrustum = shadowCoord.x >= 0.0 && shadowCoord.x <= 1.0 && shadowCoord.y >= 0.0 && shadowCoord.y <= 1.0;\n\t\tbool frustumTest = inFrustum && shadowCoord.z <= 1.0;\n\t\tif ( frustumTest ) {\n\t\t#if defined( SHADOWMAP_TYPE_PCF )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx0 = - texelSize.x * shadowRadius;\n\t\t\tfloat dy0 = - texelSize.y * shadowRadius;\n\t\t\tfloat dx1 = + texelSize.x * shadowRadius;\n\t\t\tfloat dy1 = + texelSize.y * shadowRadius;\n\t\t\tfloat dx2 = dx0 / 2.0;\n\t\t\tfloat dy2 = dy0 / 2.0;\n\t\t\tfloat dx3 = dx1 / 2.0;\n\t\t\tfloat dy3 = dy1 / 2.0;\n\t\t\tshadow = (\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )\n\t\t\t) * ( 1.0 / 17.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_PCF_SOFT )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx = texelSize.x;\n\t\t\tfloat dy = texelSize.y;\n\t\t\tvec2 uv = shadowCoord.xy;\n\t\t\tvec2 f = fract( uv * shadowMapSize + 0.5 );\n\t\t\tuv -= f * texelSize;\n\t\t\tshadow = (\n\t\t\t\ttexture2DCompare( shadowMap, uv, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + vec2( dx, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + vec2( 0.0, dy ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + texelSize, shadowCoord.z ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( -dx, 0.0 ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 0.0 ), shadowCoord.z ),\n\t\t\t\t\t f.x ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( -dx, dy ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, dy ), shadowCoord.z ),\n\t\t\t\t\t f.x ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( 0.0, -dy ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 0.0, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t f.y ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( dx, -dy ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t f.y ) +\n\t\t\t\tmix( mix( texture2DCompare( shadowMap, uv + vec2( -dx, -dy ), shadowCoord.z ),\n\t\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, -dy ), shadowCoord.z ),\n\t\t\t\t\t\t f.x ),\n\t\t\t\t\t mix( texture2DCompare( shadowMap, uv + vec2( -dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t\t f.x ),\n\t\t\t\t\t f.y )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_VSM )\n\t\t\tshadow = VSMShadow( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#else\n\t\t\tshadow = texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#endif\n\t\t}\n\t\treturn shadow;\n\t}\n\tvec2 cubeToUV( vec3 v, float texelSizeY ) {\n\t\tvec3 absV = abs( v );\n\t\tfloat scaleToCube = 1.0 / max( absV.x, max( absV.y, absV.z ) );\n\t\tabsV *= scaleToCube;\n\t\tv *= scaleToCube * ( 1.0 - 2.0 * texelSizeY );\n\t\tvec2 planar = v.xy;\n\t\tfloat almostATexel = 1.5 * texelSizeY;\n\t\tfloat almostOne = 1.0 - almostATexel;\n\t\tif ( absV.z >= almostOne ) {\n\t\t\tif ( v.z > 0.0 )\n\t\t\t\tplanar.x = 4.0 - v.x;\n\t\t} else if ( absV.x >= almostOne ) {\n\t\t\tfloat signX = sign( v.x );\n\t\t\tplanar.x = v.z * signX + 2.0 * signX;\n\t\t} else if ( absV.y >= almostOne ) {\n\t\t\tfloat signY = sign( v.y );\n\t\t\tplanar.x = v.x + 2.0 * signY + 2.0;\n\t\t\tplanar.y = v.z * signY - 2.0;\n\t\t}\n\t\treturn vec2( 0.125, 0.25 ) * planar + vec2( 0.375, 0.75 );\n\t}\n\tfloat getPointShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord, float shadowCameraNear, float shadowCameraFar ) {\n\t\tvec2 texelSize = vec2( 1.0 ) / ( shadowMapSize * vec2( 4.0, 2.0 ) );\n\t\tvec3 lightToPosition = shadowCoord.xyz;\n\t\tfloat dp = ( length( lightToPosition ) - shadowCameraNear ) / ( shadowCameraFar - shadowCameraNear );\t\tdp += shadowBias;\n\t\tvec3 bd3D = normalize( lightToPosition );\n\t\t#if defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_PCF_SOFT ) || defined( SHADOWMAP_TYPE_VSM )\n\t\t\tvec2 offset = vec2( - 1, 1 ) * shadowRadius * texelSize.y;\n\t\t\treturn (\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxx, texelSize.y ), dp )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#else\n\t\t\treturn texture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp );\n\t\t#endif\n\t}\n#endif"; - -var shadowmap_pars_vertex = "#if NUM_SPOT_LIGHT_COORDS > 0\n\tuniform mat4 spotLightMatrix[ NUM_SPOT_LIGHT_COORDS ];\n\tvarying vec4 vSpotLightCoord[ NUM_SPOT_LIGHT_COORDS ];\n#endif\n#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\tuniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tstruct DirectionalLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t\tstruct SpotLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\tuniform mat4 pointShadowMatrix[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tstruct PointLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t\tfloat shadowCameraNear;\n\t\t\tfloat shadowCameraFar;\n\t\t};\n\t\tuniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ];\n\t#endif\n#endif"; - -var shadowmap_vertex = "#if ( defined( USE_SHADOWMAP ) && ( NUM_DIR_LIGHT_SHADOWS > 0 || NUM_POINT_LIGHT_SHADOWS > 0 ) ) || ( NUM_SPOT_LIGHT_COORDS > 0 )\n\tvec3 shadowWorldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\n\tvec4 shadowWorldPosition;\n#endif\n#if defined( USE_SHADOWMAP )\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {\n\t\t\tshadowWorldPosition = worldPosition + vec4( shadowWorldNormal * directionalLightShadows[ i ].shadowNormalBias, 0 );\n\t\t\tvDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * shadowWorldPosition;\n\t\t}\n\t\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {\n\t\t\tshadowWorldPosition = worldPosition + vec4( shadowWorldNormal * pointLightShadows[ i ].shadowNormalBias, 0 );\n\t\t\tvPointShadowCoord[ i ] = pointShadowMatrix[ i ] * shadowWorldPosition;\n\t\t}\n\t\t#pragma unroll_loop_end\n\t#endif\n#endif\n#if NUM_SPOT_LIGHT_COORDS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHT_COORDS; i ++ ) {\n\t\tshadowWorldPosition = worldPosition;\n\t\t#if ( defined( USE_SHADOWMAP ) && UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\t\tshadowWorldPosition.xyz += shadowWorldNormal * spotLightShadows[ i ].shadowNormalBias;\n\t\t#endif\n\t\tvSpotLightCoord[ i ] = spotLightMatrix[ i ] * shadowWorldPosition;\n\t}\n\t#pragma unroll_loop_end\n#endif"; - -var shadowmask_pars_fragment = "float getShadowMask() {\n\tfloat shadow = 1.0;\n\t#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\tDirectionalLightShadow directionalLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {\n\t\tdirectionalLight = directionalLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\tSpotLightShadow spotLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHT_SHADOWS; i ++ ) {\n\t\tspotLight = spotLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotLightCoord[ i ] ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\tPointLightShadow pointLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {\n\t\tpointLight = pointLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ], pointLight.shadowCameraNear, pointLight.shadowCameraFar ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#endif\n\treturn shadow;\n}"; - -var skinbase_vertex = "#ifdef USE_SKINNING\n\tmat4 boneMatX = getBoneMatrix( skinIndex.x );\n\tmat4 boneMatY = getBoneMatrix( skinIndex.y );\n\tmat4 boneMatZ = getBoneMatrix( skinIndex.z );\n\tmat4 boneMatW = getBoneMatrix( skinIndex.w );\n#endif"; - -var skinning_pars_vertex = "#ifdef USE_SKINNING\n\tuniform mat4 bindMatrix;\n\tuniform mat4 bindMatrixInverse;\n\tuniform highp sampler2D boneTexture;\n\tmat4 getBoneMatrix( const in float i ) {\n\t\tint size = textureSize( boneTexture, 0 ).x;\n\t\tint j = int( i ) * 4;\n\t\tint x = j % size;\n\t\tint y = j / size;\n\t\tvec4 v1 = texelFetch( boneTexture, ivec2( x, y ), 0 );\n\t\tvec4 v2 = texelFetch( boneTexture, ivec2( x + 1, y ), 0 );\n\t\tvec4 v3 = texelFetch( boneTexture, ivec2( x + 2, y ), 0 );\n\t\tvec4 v4 = texelFetch( boneTexture, ivec2( x + 3, y ), 0 );\n\t\treturn mat4( v1, v2, v3, v4 );\n\t}\n#endif"; - -var skinning_vertex = "#ifdef USE_SKINNING\n\tvec4 skinVertex = bindMatrix * vec4( transformed, 1.0 );\n\tvec4 skinned = vec4( 0.0 );\n\tskinned += boneMatX * skinVertex * skinWeight.x;\n\tskinned += boneMatY * skinVertex * skinWeight.y;\n\tskinned += boneMatZ * skinVertex * skinWeight.z;\n\tskinned += boneMatW * skinVertex * skinWeight.w;\n\ttransformed = ( bindMatrixInverse * skinned ).xyz;\n#endif"; - -var skinnormal_vertex = "#ifdef USE_SKINNING\n\tmat4 skinMatrix = mat4( 0.0 );\n\tskinMatrix += skinWeight.x * boneMatX;\n\tskinMatrix += skinWeight.y * boneMatY;\n\tskinMatrix += skinWeight.z * boneMatZ;\n\tskinMatrix += skinWeight.w * boneMatW;\n\tskinMatrix = bindMatrixInverse * skinMatrix * bindMatrix;\n\tobjectNormal = vec4( skinMatrix * vec4( objectNormal, 0.0 ) ).xyz;\n\t#ifdef USE_TANGENT\n\t\tobjectTangent = vec4( skinMatrix * vec4( objectTangent, 0.0 ) ).xyz;\n\t#endif\n#endif"; - -var specularmap_fragment = "float specularStrength;\n#ifdef USE_SPECULARMAP\n\tvec4 texelSpecular = texture2D( specularMap, vSpecularMapUv );\n\tspecularStrength = texelSpecular.r;\n#else\n\tspecularStrength = 1.0;\n#endif"; - -var specularmap_pars_fragment = "#ifdef USE_SPECULARMAP\n\tuniform sampler2D specularMap;\n#endif"; - -var tonemapping_fragment = "#if defined( TONE_MAPPING )\n\tgl_FragColor.rgb = toneMapping( gl_FragColor.rgb );\n#endif"; - -var tonemapping_pars_fragment = "#ifndef saturate\n#define saturate( a ) clamp( a, 0.0, 1.0 )\n#endif\nuniform float toneMappingExposure;\nvec3 LinearToneMapping( vec3 color ) {\n\treturn saturate( toneMappingExposure * color );\n}\nvec3 ReinhardToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\treturn saturate( color / ( vec3( 1.0 ) + color ) );\n}\nvec3 OptimizedCineonToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\tcolor = max( vec3( 0.0 ), color - 0.004 );\n\treturn pow( ( color * ( 6.2 * color + 0.5 ) ) / ( color * ( 6.2 * color + 1.7 ) + 0.06 ), vec3( 2.2 ) );\n}\nvec3 RRTAndODTFit( vec3 v ) {\n\tvec3 a = v * ( v + 0.0245786 ) - 0.000090537;\n\tvec3 b = v * ( 0.983729 * v + 0.4329510 ) + 0.238081;\n\treturn a / b;\n}\nvec3 ACESFilmicToneMapping( vec3 color ) {\n\tconst mat3 ACESInputMat = mat3(\n\t\tvec3( 0.59719, 0.07600, 0.02840 ),\t\tvec3( 0.35458, 0.90834, 0.13383 ),\n\t\tvec3( 0.04823, 0.01566, 0.83777 )\n\t);\n\tconst mat3 ACESOutputMat = mat3(\n\t\tvec3( 1.60475, -0.10208, -0.00327 ),\t\tvec3( -0.53108, 1.10813, -0.07276 ),\n\t\tvec3( -0.07367, -0.00605, 1.07602 )\n\t);\n\tcolor *= toneMappingExposure / 0.6;\n\tcolor = ACESInputMat * color;\n\tcolor = RRTAndODTFit( color );\n\tcolor = ACESOutputMat * color;\n\treturn saturate( color );\n}\nconst mat3 LINEAR_REC2020_TO_LINEAR_SRGB = mat3(\n\tvec3( 1.6605, - 0.1246, - 0.0182 ),\n\tvec3( - 0.5876, 1.1329, - 0.1006 ),\n\tvec3( - 0.0728, - 0.0083, 1.1187 )\n);\nconst mat3 LINEAR_SRGB_TO_LINEAR_REC2020 = mat3(\n\tvec3( 0.6274, 0.0691, 0.0164 ),\n\tvec3( 0.3293, 0.9195, 0.0880 ),\n\tvec3( 0.0433, 0.0113, 0.8956 )\n);\nvec3 agxDefaultContrastApprox( vec3 x ) {\n\tvec3 x2 = x * x;\n\tvec3 x4 = x2 * x2;\n\treturn + 15.5 * x4 * x2\n\t\t- 40.14 * x4 * x\n\t\t+ 31.96 * x4\n\t\t- 6.868 * x2 * x\n\t\t+ 0.4298 * x2\n\t\t+ 0.1191 * x\n\t\t- 0.00232;\n}\nvec3 AgXToneMapping( vec3 color ) {\n\tconst mat3 AgXInsetMatrix = mat3(\n\t\tvec3( 0.856627153315983, 0.137318972929847, 0.11189821299995 ),\n\t\tvec3( 0.0951212405381588, 0.761241990602591, 0.0767994186031903 ),\n\t\tvec3( 0.0482516061458583, 0.101439036467562, 0.811302368396859 )\n\t);\n\tconst mat3 AgXOutsetMatrix = mat3(\n\t\tvec3( 1.1271005818144368, - 0.1413297634984383, - 0.14132976349843826 ),\n\t\tvec3( - 0.11060664309660323, 1.157823702216272, - 0.11060664309660294 ),\n\t\tvec3( - 0.016493938717834573, - 0.016493938717834257, 1.2519364065950405 )\n\t);\n\tconst float AgxMinEv = - 12.47393;\tconst float AgxMaxEv = 4.026069;\n\tcolor *= toneMappingExposure;\n\tcolor = LINEAR_SRGB_TO_LINEAR_REC2020 * color;\n\tcolor = AgXInsetMatrix * color;\n\tcolor = max( color, 1e-10 );\tcolor = log2( color );\n\tcolor = ( color - AgxMinEv ) / ( AgxMaxEv - AgxMinEv );\n\tcolor = clamp( color, 0.0, 1.0 );\n\tcolor = agxDefaultContrastApprox( color );\n\tcolor = AgXOutsetMatrix * color;\n\tcolor = pow( max( vec3( 0.0 ), color ), vec3( 2.2 ) );\n\tcolor = LINEAR_REC2020_TO_LINEAR_SRGB * color;\n\tcolor = clamp( color, 0.0, 1.0 );\n\treturn color;\n}\nvec3 CustomToneMapping( vec3 color ) { return color; }"; - -var transmission_fragment = "#ifdef USE_TRANSMISSION\n\tmaterial.transmission = transmission;\n\tmaterial.transmissionAlpha = 1.0;\n\tmaterial.thickness = thickness;\n\tmaterial.attenuationDistance = attenuationDistance;\n\tmaterial.attenuationColor = attenuationColor;\n\t#ifdef USE_TRANSMISSIONMAP\n\t\tmaterial.transmission *= texture2D( transmissionMap, vTransmissionMapUv ).r;\n\t#endif\n\t#ifdef USE_THICKNESSMAP\n\t\tmaterial.thickness *= texture2D( thicknessMap, vThicknessMapUv ).g;\n\t#endif\n\tvec3 pos = vWorldPosition;\n\tvec3 v = normalize( cameraPosition - pos );\n\tvec3 n = inverseTransformDirection( normal, viewMatrix );\n\tvec4 transmitted = getIBLVolumeRefraction(\n\t\tn, v, material.roughness, material.diffuseColor, material.specularColor, material.specularF90,\n\t\tpos, modelMatrix, viewMatrix, projectionMatrix, material.ior, material.thickness,\n\t\tmaterial.attenuationColor, material.attenuationDistance );\n\tmaterial.transmissionAlpha = mix( material.transmissionAlpha, transmitted.a, material.transmission );\n\ttotalDiffuse = mix( totalDiffuse, transmitted.rgb, material.transmission );\n#endif"; - -var transmission_pars_fragment = "#ifdef USE_TRANSMISSION\n\tuniform float transmission;\n\tuniform float thickness;\n\tuniform float attenuationDistance;\n\tuniform vec3 attenuationColor;\n\t#ifdef USE_TRANSMISSIONMAP\n\t\tuniform sampler2D transmissionMap;\n\t#endif\n\t#ifdef USE_THICKNESSMAP\n\t\tuniform sampler2D thicknessMap;\n\t#endif\n\tuniform vec2 transmissionSamplerSize;\n\tuniform sampler2D transmissionSamplerMap;\n\tuniform mat4 modelMatrix;\n\tuniform mat4 projectionMatrix;\n\tvarying vec3 vWorldPosition;\n\tfloat w0( float a ) {\n\t\treturn ( 1.0 / 6.0 ) * ( a * ( a * ( - a + 3.0 ) - 3.0 ) + 1.0 );\n\t}\n\tfloat w1( float a ) {\n\t\treturn ( 1.0 / 6.0 ) * ( a * a * ( 3.0 * a - 6.0 ) + 4.0 );\n\t}\n\tfloat w2( float a ){\n\t\treturn ( 1.0 / 6.0 ) * ( a * ( a * ( - 3.0 * a + 3.0 ) + 3.0 ) + 1.0 );\n\t}\n\tfloat w3( float a ) {\n\t\treturn ( 1.0 / 6.0 ) * ( a * a * a );\n\t}\n\tfloat g0( float a ) {\n\t\treturn w0( a ) + w1( a );\n\t}\n\tfloat g1( float a ) {\n\t\treturn w2( a ) + w3( a );\n\t}\n\tfloat h0( float a ) {\n\t\treturn - 1.0 + w1( a ) / ( w0( a ) + w1( a ) );\n\t}\n\tfloat h1( float a ) {\n\t\treturn 1.0 + w3( a ) / ( w2( a ) + w3( a ) );\n\t}\n\tvec4 bicubic( sampler2D tex, vec2 uv, vec4 texelSize, float lod ) {\n\t\tuv = uv * texelSize.zw + 0.5;\n\t\tvec2 iuv = floor( uv );\n\t\tvec2 fuv = fract( uv );\n\t\tfloat g0x = g0( fuv.x );\n\t\tfloat g1x = g1( fuv.x );\n\t\tfloat h0x = h0( fuv.x );\n\t\tfloat h1x = h1( fuv.x );\n\t\tfloat h0y = h0( fuv.y );\n\t\tfloat h1y = h1( fuv.y );\n\t\tvec2 p0 = ( vec2( iuv.x + h0x, iuv.y + h0y ) - 0.5 ) * texelSize.xy;\n\t\tvec2 p1 = ( vec2( iuv.x + h1x, iuv.y + h0y ) - 0.5 ) * texelSize.xy;\n\t\tvec2 p2 = ( vec2( iuv.x + h0x, iuv.y + h1y ) - 0.5 ) * texelSize.xy;\n\t\tvec2 p3 = ( vec2( iuv.x + h1x, iuv.y + h1y ) - 0.5 ) * texelSize.xy;\n\t\treturn g0( fuv.y ) * ( g0x * textureLod( tex, p0, lod ) + g1x * textureLod( tex, p1, lod ) ) +\n\t\t\tg1( fuv.y ) * ( g0x * textureLod( tex, p2, lod ) + g1x * textureLod( tex, p3, lod ) );\n\t}\n\tvec4 textureBicubic( sampler2D sampler, vec2 uv, float lod ) {\n\t\tvec2 fLodSize = vec2( textureSize( sampler, int( lod ) ) );\n\t\tvec2 cLodSize = vec2( textureSize( sampler, int( lod + 1.0 ) ) );\n\t\tvec2 fLodSizeInv = 1.0 / fLodSize;\n\t\tvec2 cLodSizeInv = 1.0 / cLodSize;\n\t\tvec4 fSample = bicubic( sampler, uv, vec4( fLodSizeInv, fLodSize ), floor( lod ) );\n\t\tvec4 cSample = bicubic( sampler, uv, vec4( cLodSizeInv, cLodSize ), ceil( lod ) );\n\t\treturn mix( fSample, cSample, fract( lod ) );\n\t}\n\tvec3 getVolumeTransmissionRay( const in vec3 n, const in vec3 v, const in float thickness, const in float ior, const in mat4 modelMatrix ) {\n\t\tvec3 refractionVector = refract( - v, normalize( n ), 1.0 / ior );\n\t\tvec3 modelScale;\n\t\tmodelScale.x = length( vec3( modelMatrix[ 0 ].xyz ) );\n\t\tmodelScale.y = length( vec3( modelMatrix[ 1 ].xyz ) );\n\t\tmodelScale.z = length( vec3( modelMatrix[ 2 ].xyz ) );\n\t\treturn normalize( refractionVector ) * thickness * modelScale;\n\t}\n\tfloat applyIorToRoughness( const in float roughness, const in float ior ) {\n\t\treturn roughness * clamp( ior * 2.0 - 2.0, 0.0, 1.0 );\n\t}\n\tvec4 getTransmissionSample( const in vec2 fragCoord, const in float roughness, const in float ior ) {\n\t\tfloat lod = log2( transmissionSamplerSize.x ) * applyIorToRoughness( roughness, ior );\n\t\treturn textureBicubic( transmissionSamplerMap, fragCoord.xy, lod );\n\t}\n\tvec3 volumeAttenuation( const in float transmissionDistance, const in vec3 attenuationColor, const in float attenuationDistance ) {\n\t\tif ( isinf( attenuationDistance ) ) {\n\t\t\treturn vec3( 1.0 );\n\t\t} else {\n\t\t\tvec3 attenuationCoefficient = -log( attenuationColor ) / attenuationDistance;\n\t\t\tvec3 transmittance = exp( - attenuationCoefficient * transmissionDistance );\t\t\treturn transmittance;\n\t\t}\n\t}\n\tvec4 getIBLVolumeRefraction( const in vec3 n, const in vec3 v, const in float roughness, const in vec3 diffuseColor,\n\t\tconst in vec3 specularColor, const in float specularF90, const in vec3 position, const in mat4 modelMatrix,\n\t\tconst in mat4 viewMatrix, const in mat4 projMatrix, const in float ior, const in float thickness,\n\t\tconst in vec3 attenuationColor, const in float attenuationDistance ) {\n\t\tvec3 transmissionRay = getVolumeTransmissionRay( n, v, thickness, ior, modelMatrix );\n\t\tvec3 refractedRayExit = position + transmissionRay;\n\t\tvec4 ndcPos = projMatrix * viewMatrix * vec4( refractedRayExit, 1.0 );\n\t\tvec2 refractionCoords = ndcPos.xy / ndcPos.w;\n\t\trefractionCoords += 1.0;\n\t\trefractionCoords /= 2.0;\n\t\tvec4 transmittedLight = getTransmissionSample( refractionCoords, roughness, ior );\n\t\tvec3 transmittance = diffuseColor * volumeAttenuation( length( transmissionRay ), attenuationColor, attenuationDistance );\n\t\tvec3 attenuatedColor = transmittance * transmittedLight.rgb;\n\t\tvec3 F = EnvironmentBRDF( n, v, specularColor, specularF90, roughness );\n\t\tfloat transmittanceFactor = ( transmittance.r + transmittance.g + transmittance.b ) / 3.0;\n\t\treturn vec4( ( 1.0 - F ) * attenuatedColor, 1.0 - ( 1.0 - transmittedLight.a ) * transmittanceFactor );\n\t}\n#endif"; - -var uv_pars_fragment = "#if defined( USE_UV ) || defined( USE_ANISOTROPY )\n\tvarying vec2 vUv;\n#endif\n#ifdef USE_MAP\n\tvarying vec2 vMapUv;\n#endif\n#ifdef USE_ALPHAMAP\n\tvarying vec2 vAlphaMapUv;\n#endif\n#ifdef USE_LIGHTMAP\n\tvarying vec2 vLightMapUv;\n#endif\n#ifdef USE_AOMAP\n\tvarying vec2 vAoMapUv;\n#endif\n#ifdef USE_BUMPMAP\n\tvarying vec2 vBumpMapUv;\n#endif\n#ifdef USE_NORMALMAP\n\tvarying vec2 vNormalMapUv;\n#endif\n#ifdef USE_EMISSIVEMAP\n\tvarying vec2 vEmissiveMapUv;\n#endif\n#ifdef USE_METALNESSMAP\n\tvarying vec2 vMetalnessMapUv;\n#endif\n#ifdef USE_ROUGHNESSMAP\n\tvarying vec2 vRoughnessMapUv;\n#endif\n#ifdef USE_ANISOTROPYMAP\n\tvarying vec2 vAnisotropyMapUv;\n#endif\n#ifdef USE_CLEARCOATMAP\n\tvarying vec2 vClearcoatMapUv;\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\tvarying vec2 vClearcoatNormalMapUv;\n#endif\n#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\tvarying vec2 vClearcoatRoughnessMapUv;\n#endif\n#ifdef USE_IRIDESCENCEMAP\n\tvarying vec2 vIridescenceMapUv;\n#endif\n#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\tvarying vec2 vIridescenceThicknessMapUv;\n#endif\n#ifdef USE_SHEEN_COLORMAP\n\tvarying vec2 vSheenColorMapUv;\n#endif\n#ifdef USE_SHEEN_ROUGHNESSMAP\n\tvarying vec2 vSheenRoughnessMapUv;\n#endif\n#ifdef USE_SPECULARMAP\n\tvarying vec2 vSpecularMapUv;\n#endif\n#ifdef USE_SPECULAR_COLORMAP\n\tvarying vec2 vSpecularColorMapUv;\n#endif\n#ifdef USE_SPECULAR_INTENSITYMAP\n\tvarying vec2 vSpecularIntensityMapUv;\n#endif\n#ifdef USE_TRANSMISSIONMAP\n\tuniform mat3 transmissionMapTransform;\n\tvarying vec2 vTransmissionMapUv;\n#endif\n#ifdef USE_THICKNESSMAP\n\tuniform mat3 thicknessMapTransform;\n\tvarying vec2 vThicknessMapUv;\n#endif"; - -var uv_pars_vertex = "#if defined( USE_UV ) || defined( USE_ANISOTROPY )\n\tvarying vec2 vUv;\n#endif\n#ifdef USE_MAP\n\tuniform mat3 mapTransform;\n\tvarying vec2 vMapUv;\n#endif\n#ifdef USE_ALPHAMAP\n\tuniform mat3 alphaMapTransform;\n\tvarying vec2 vAlphaMapUv;\n#endif\n#ifdef USE_LIGHTMAP\n\tuniform mat3 lightMapTransform;\n\tvarying vec2 vLightMapUv;\n#endif\n#ifdef USE_AOMAP\n\tuniform mat3 aoMapTransform;\n\tvarying vec2 vAoMapUv;\n#endif\n#ifdef USE_BUMPMAP\n\tuniform mat3 bumpMapTransform;\n\tvarying vec2 vBumpMapUv;\n#endif\n#ifdef USE_NORMALMAP\n\tuniform mat3 normalMapTransform;\n\tvarying vec2 vNormalMapUv;\n#endif\n#ifdef USE_DISPLACEMENTMAP\n\tuniform mat3 displacementMapTransform;\n\tvarying vec2 vDisplacementMapUv;\n#endif\n#ifdef USE_EMISSIVEMAP\n\tuniform mat3 emissiveMapTransform;\n\tvarying vec2 vEmissiveMapUv;\n#endif\n#ifdef USE_METALNESSMAP\n\tuniform mat3 metalnessMapTransform;\n\tvarying vec2 vMetalnessMapUv;\n#endif\n#ifdef USE_ROUGHNESSMAP\n\tuniform mat3 roughnessMapTransform;\n\tvarying vec2 vRoughnessMapUv;\n#endif\n#ifdef USE_ANISOTROPYMAP\n\tuniform mat3 anisotropyMapTransform;\n\tvarying vec2 vAnisotropyMapUv;\n#endif\n#ifdef USE_CLEARCOATMAP\n\tuniform mat3 clearcoatMapTransform;\n\tvarying vec2 vClearcoatMapUv;\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\tuniform mat3 clearcoatNormalMapTransform;\n\tvarying vec2 vClearcoatNormalMapUv;\n#endif\n#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\tuniform mat3 clearcoatRoughnessMapTransform;\n\tvarying vec2 vClearcoatRoughnessMapUv;\n#endif\n#ifdef USE_SHEEN_COLORMAP\n\tuniform mat3 sheenColorMapTransform;\n\tvarying vec2 vSheenColorMapUv;\n#endif\n#ifdef USE_SHEEN_ROUGHNESSMAP\n\tuniform mat3 sheenRoughnessMapTransform;\n\tvarying vec2 vSheenRoughnessMapUv;\n#endif\n#ifdef USE_IRIDESCENCEMAP\n\tuniform mat3 iridescenceMapTransform;\n\tvarying vec2 vIridescenceMapUv;\n#endif\n#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\tuniform mat3 iridescenceThicknessMapTransform;\n\tvarying vec2 vIridescenceThicknessMapUv;\n#endif\n#ifdef USE_SPECULARMAP\n\tuniform mat3 specularMapTransform;\n\tvarying vec2 vSpecularMapUv;\n#endif\n#ifdef USE_SPECULAR_COLORMAP\n\tuniform mat3 specularColorMapTransform;\n\tvarying vec2 vSpecularColorMapUv;\n#endif\n#ifdef USE_SPECULAR_INTENSITYMAP\n\tuniform mat3 specularIntensityMapTransform;\n\tvarying vec2 vSpecularIntensityMapUv;\n#endif\n#ifdef USE_TRANSMISSIONMAP\n\tuniform mat3 transmissionMapTransform;\n\tvarying vec2 vTransmissionMapUv;\n#endif\n#ifdef USE_THICKNESSMAP\n\tuniform mat3 thicknessMapTransform;\n\tvarying vec2 vThicknessMapUv;\n#endif"; - -var uv_vertex = "#if defined( USE_UV ) || defined( USE_ANISOTROPY )\n\tvUv = vec3( uv, 1 ).xy;\n#endif\n#ifdef USE_MAP\n\tvMapUv = ( mapTransform * vec3( MAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_ALPHAMAP\n\tvAlphaMapUv = ( alphaMapTransform * vec3( ALPHAMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_LIGHTMAP\n\tvLightMapUv = ( lightMapTransform * vec3( LIGHTMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_AOMAP\n\tvAoMapUv = ( aoMapTransform * vec3( AOMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_BUMPMAP\n\tvBumpMapUv = ( bumpMapTransform * vec3( BUMPMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_NORMALMAP\n\tvNormalMapUv = ( normalMapTransform * vec3( NORMALMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_DISPLACEMENTMAP\n\tvDisplacementMapUv = ( displacementMapTransform * vec3( DISPLACEMENTMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_EMISSIVEMAP\n\tvEmissiveMapUv = ( emissiveMapTransform * vec3( EMISSIVEMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_METALNESSMAP\n\tvMetalnessMapUv = ( metalnessMapTransform * vec3( METALNESSMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_ROUGHNESSMAP\n\tvRoughnessMapUv = ( roughnessMapTransform * vec3( ROUGHNESSMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_ANISOTROPYMAP\n\tvAnisotropyMapUv = ( anisotropyMapTransform * vec3( ANISOTROPYMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_CLEARCOATMAP\n\tvClearcoatMapUv = ( clearcoatMapTransform * vec3( CLEARCOATMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\tvClearcoatNormalMapUv = ( clearcoatNormalMapTransform * vec3( CLEARCOAT_NORMALMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\tvClearcoatRoughnessMapUv = ( clearcoatRoughnessMapTransform * vec3( CLEARCOAT_ROUGHNESSMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_IRIDESCENCEMAP\n\tvIridescenceMapUv = ( iridescenceMapTransform * vec3( IRIDESCENCEMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\tvIridescenceThicknessMapUv = ( iridescenceThicknessMapTransform * vec3( IRIDESCENCE_THICKNESSMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_SHEEN_COLORMAP\n\tvSheenColorMapUv = ( sheenColorMapTransform * vec3( SHEEN_COLORMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_SHEEN_ROUGHNESSMAP\n\tvSheenRoughnessMapUv = ( sheenRoughnessMapTransform * vec3( SHEEN_ROUGHNESSMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_SPECULARMAP\n\tvSpecularMapUv = ( specularMapTransform * vec3( SPECULARMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_SPECULAR_COLORMAP\n\tvSpecularColorMapUv = ( specularColorMapTransform * vec3( SPECULAR_COLORMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_SPECULAR_INTENSITYMAP\n\tvSpecularIntensityMapUv = ( specularIntensityMapTransform * vec3( SPECULAR_INTENSITYMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_TRANSMISSIONMAP\n\tvTransmissionMapUv = ( transmissionMapTransform * vec3( TRANSMISSIONMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_THICKNESSMAP\n\tvThicknessMapUv = ( thicknessMapTransform * vec3( THICKNESSMAP_UV, 1 ) ).xy;\n#endif"; - -var worldpos_vertex = "#if defined( USE_ENVMAP ) || defined( DISTANCE ) || defined ( USE_SHADOWMAP ) || defined ( USE_TRANSMISSION ) || NUM_SPOT_LIGHT_COORDS > 0\n\tvec4 worldPosition = vec4( transformed, 1.0 );\n\t#ifdef USE_BATCHING\n\t\tworldPosition = batchingMatrix * worldPosition;\n\t#endif\n\t#ifdef USE_INSTANCING\n\t\tworldPosition = instanceMatrix * worldPosition;\n\t#endif\n\tworldPosition = modelMatrix * worldPosition;\n#endif"; - -const vertex$h = "varying vec2 vUv;\nuniform mat3 uvTransform;\nvoid main() {\n\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n\tgl_Position = vec4( position.xy, 1.0, 1.0 );\n}"; - -const fragment$h = "uniform sampler2D t2D;\nuniform float backgroundIntensity;\nvarying vec2 vUv;\nvoid main() {\n\tvec4 texColor = texture2D( t2D, vUv );\n\t#ifdef DECODE_VIDEO_TEXTURE\n\t\ttexColor = vec4( mix( pow( texColor.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), texColor.rgb * 0.0773993808, vec3( lessThanEqual( texColor.rgb, vec3( 0.04045 ) ) ) ), texColor.w );\n\t#endif\n\ttexColor.rgb *= backgroundIntensity;\n\tgl_FragColor = texColor;\n\t#include \n\t#include \n}"; - -const vertex$g = "varying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n\tgl_Position.z = gl_Position.w;\n}"; - -const fragment$g = "#ifdef ENVMAP_TYPE_CUBE\n\tuniform samplerCube envMap;\n#elif defined( ENVMAP_TYPE_CUBE_UV )\n\tuniform sampler2D envMap;\n#endif\nuniform float flipEnvMap;\nuniform float backgroundBlurriness;\nuniform float backgroundIntensity;\nvarying vec3 vWorldDirection;\n#include \nvoid main() {\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tvec4 texColor = textureCube( envMap, vec3( flipEnvMap * vWorldDirection.x, vWorldDirection.yz ) );\n\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\tvec4 texColor = textureCubeUV( envMap, vWorldDirection, backgroundBlurriness );\n\t#else\n\t\tvec4 texColor = vec4( 0.0, 0.0, 0.0, 1.0 );\n\t#endif\n\ttexColor.rgb *= backgroundIntensity;\n\tgl_FragColor = texColor;\n\t#include \n\t#include \n}"; - -const vertex$f = "varying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n\tgl_Position.z = gl_Position.w;\n}"; - -const fragment$f = "uniform samplerCube tCube;\nuniform float tFlip;\nuniform float opacity;\nvarying vec3 vWorldDirection;\nvoid main() {\n\tvec4 texColor = textureCube( tCube, vec3( tFlip * vWorldDirection.x, vWorldDirection.yz ) );\n\tgl_FragColor = texColor;\n\tgl_FragColor.a *= opacity;\n\t#include \n\t#include \n}"; - -const vertex$e = "#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvarying vec2 vHighPrecisionZW;\nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include \n\t\t#include \n\t\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvHighPrecisionZW = gl_Position.zw;\n}"; - -const fragment$e = "#if DEPTH_PACKING == 3200\n\tuniform float opacity;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvarying vec2 vHighPrecisionZW;\nvoid main() {\n\tvec4 diffuseColor = vec4( 1.0 );\n\t#include \n\t#if DEPTH_PACKING == 3200\n\t\tdiffuseColor.a = opacity;\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tfloat fragCoordZ = 0.5 * vHighPrecisionZW[0] / vHighPrecisionZW[1] + 0.5;\n\t#if DEPTH_PACKING == 3200\n\t\tgl_FragColor = vec4( vec3( 1.0 - fragCoordZ ), opacity );\n\t#elif DEPTH_PACKING == 3201\n\t\tgl_FragColor = packDepthToRGBA( fragCoordZ );\n\t#endif\n}"; - -const vertex$d = "#define DISTANCE\nvarying vec3 vWorldPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include \n\t\t#include \n\t\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvWorldPosition = worldPosition.xyz;\n}"; - -const fragment$d = "#define DISTANCE\nuniform vec3 referencePosition;\nuniform float nearDistance;\nuniform float farDistance;\nvarying vec3 vWorldPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main () {\n\tvec4 diffuseColor = vec4( 1.0 );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tfloat dist = length( vWorldPosition - referencePosition );\n\tdist = ( dist - nearDistance ) / ( farDistance - nearDistance );\n\tdist = saturate( dist );\n\tgl_FragColor = packDepthToRGBA( dist );\n}"; - -const vertex$c = "varying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n}"; - -const fragment$c = "uniform sampler2D tEquirect;\nvarying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvec3 direction = normalize( vWorldDirection );\n\tvec2 sampleUV = equirectUv( direction );\n\tgl_FragColor = texture2D( tEquirect, sampleUV );\n\t#include \n\t#include \n}"; - -const vertex$b = "uniform float scale;\nattribute float lineDistance;\nvarying float vLineDistance;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvLineDistance = scale * lineDistance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - -const fragment$b = "uniform vec3 diffuse;\nuniform float opacity;\nuniform float dashSize;\nuniform float totalSize;\nvarying float vLineDistance;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\tif ( mod( vLineDistance, totalSize ) > dashSize ) {\n\t\tdiscard;\n\t}\n\tvec3 outgoingLight = vec3( 0.0 );\n\t#include \n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - -const vertex$a = "#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#if defined ( USE_ENVMAP ) || defined ( USE_SKINNING )\n\t\t#include \n\t\t#include \n\t\t#include \n\t\t#include \n\t\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - -const fragment$a = "uniform vec3 diffuse;\nuniform float opacity;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\t#ifdef USE_LIGHTMAP\n\t\tvec4 lightMapTexel = texture2D( lightMap, vLightMapUv );\n\t\treflectedLight.indirectDiffuse += lightMapTexel.rgb * lightMapIntensity * RECIPROCAL_PI;\n\t#else\n\t\treflectedLight.indirectDiffuse += vec3( 1.0 );\n\t#endif\n\t#include \n\treflectedLight.indirectDiffuse *= diffuseColor.rgb;\n\tvec3 outgoingLight = reflectedLight.indirectDiffuse;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - -const vertex$9 = "#define LAMBERT\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n\t#include \n}"; - -const fragment$9 = "#define LAMBERT\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - -const vertex$8 = "#define MATCAP\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n}"; - -const fragment$8 = "#define MATCAP\nuniform vec3 diffuse;\nuniform float opacity;\nuniform sampler2D matcap;\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 viewDir = normalize( vViewPosition );\n\tvec3 x = normalize( vec3( viewDir.z, 0.0, - viewDir.x ) );\n\tvec3 y = cross( viewDir, x );\n\tvec2 uv = vec2( dot( x, normal ), dot( y, normal ) ) * 0.495 + 0.5;\n\t#ifdef USE_MATCAP\n\t\tvec4 matcapColor = texture2D( matcap, uv );\n\t#else\n\t\tvec4 matcapColor = vec4( vec3( mix( 0.2, 0.8, uv.y ) ), 1.0 );\n\t#endif\n\tvec3 outgoingLight = diffuseColor.rgb * matcapColor.rgb;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - -const vertex$7 = "#define NORMAL\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP_TANGENTSPACE )\n\tvarying vec3 vViewPosition;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP_TANGENTSPACE )\n\tvViewPosition = - mvPosition.xyz;\n#endif\n}"; - -const fragment$7 = "#define NORMAL\nuniform float opacity;\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP_TANGENTSPACE )\n\tvarying vec3 vViewPosition;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvec4 diffuseColor = vec4( 0.0, 0.0, 0.0, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\tgl_FragColor = vec4( packNormalToRGB( normal ), diffuseColor.a );\n\t#ifdef OPAQUE\n\t\tgl_FragColor.a = 1.0;\n\t#endif\n}"; - -const vertex$6 = "#define PHONG\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n\t#include \n}"; - -const fragment$6 = "#define PHONG\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform vec3 specular;\nuniform float shininess;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - -const vertex$5 = "#define STANDARD\nvarying vec3 vViewPosition;\n#ifdef USE_TRANSMISSION\n\tvarying vec3 vWorldPosition;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n#ifdef USE_TRANSMISSION\n\tvWorldPosition = worldPosition.xyz;\n#endif\n}"; - -const fragment$5 = "#define STANDARD\n#ifdef PHYSICAL\n\t#define IOR\n\t#define USE_SPECULAR\n#endif\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float roughness;\nuniform float metalness;\nuniform float opacity;\n#ifdef IOR\n\tuniform float ior;\n#endif\n#ifdef USE_SPECULAR\n\tuniform float specularIntensity;\n\tuniform vec3 specularColor;\n\t#ifdef USE_SPECULAR_COLORMAP\n\t\tuniform sampler2D specularColorMap;\n\t#endif\n\t#ifdef USE_SPECULAR_INTENSITYMAP\n\t\tuniform sampler2D specularIntensityMap;\n\t#endif\n#endif\n#ifdef USE_CLEARCOAT\n\tuniform float clearcoat;\n\tuniform float clearcoatRoughness;\n#endif\n#ifdef USE_IRIDESCENCE\n\tuniform float iridescence;\n\tuniform float iridescenceIOR;\n\tuniform float iridescenceThicknessMinimum;\n\tuniform float iridescenceThicknessMaximum;\n#endif\n#ifdef USE_SHEEN\n\tuniform vec3 sheenColor;\n\tuniform float sheenRoughness;\n\t#ifdef USE_SHEEN_COLORMAP\n\t\tuniform sampler2D sheenColorMap;\n\t#endif\n\t#ifdef USE_SHEEN_ROUGHNESSMAP\n\t\tuniform sampler2D sheenRoughnessMap;\n\t#endif\n#endif\n#ifdef USE_ANISOTROPY\n\tuniform vec2 anisotropyVector;\n\t#ifdef USE_ANISOTROPYMAP\n\t\tuniform sampler2D anisotropyMap;\n\t#endif\n#endif\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 totalDiffuse = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse;\n\tvec3 totalSpecular = reflectedLight.directSpecular + reflectedLight.indirectSpecular;\n\t#include \n\tvec3 outgoingLight = totalDiffuse + totalSpecular + totalEmissiveRadiance;\n\t#ifdef USE_SHEEN\n\t\tfloat sheenEnergyComp = 1.0 - 0.157 * max3( material.sheenColor );\n\t\toutgoingLight = outgoingLight * sheenEnergyComp + sheenSpecularDirect + sheenSpecularIndirect;\n\t#endif\n\t#ifdef USE_CLEARCOAT\n\t\tfloat dotNVcc = saturate( dot( geometryClearcoatNormal, geometryViewDir ) );\n\t\tvec3 Fcc = F_Schlick( material.clearcoatF0, material.clearcoatF90, dotNVcc );\n\t\toutgoingLight = outgoingLight * ( 1.0 - material.clearcoat * Fcc ) + ( clearcoatSpecularDirect + clearcoatSpecularIndirect ) * material.clearcoat;\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - -const vertex$4 = "#define TOON\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n}"; - -const fragment$4 = "#define TOON\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - -const vertex$3 = "uniform float size;\nuniform float scale;\n#include \n#include \n#include \n#include \n#include \n#include \n#ifdef USE_POINTS_UV\n\tvarying vec2 vUv;\n\tuniform mat3 uvTransform;\n#endif\nvoid main() {\n\t#ifdef USE_POINTS_UV\n\t\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tgl_PointSize = size;\n\t#ifdef USE_SIZEATTENUATION\n\t\tbool isPerspective = isPerspectiveMatrix( projectionMatrix );\n\t\tif ( isPerspective ) gl_PointSize *= ( scale / - mvPosition.z );\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n}"; - -const fragment$3 = "uniform vec3 diffuse;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\tvec3 outgoingLight = vec3( 0.0 );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - -const vertex$2 = "#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - -const fragment$2 = "uniform vec3 color;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tgl_FragColor = vec4( color, opacity * ( 1.0 - getShadowMask() ) );\n\t#include \n\t#include \n\t#include \n}"; - -const vertex$1 = "uniform float rotation;\nuniform vec2 center;\n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 mvPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );\n\tvec2 scale;\n\tscale.x = length( vec3( modelMatrix[ 0 ].x, modelMatrix[ 0 ].y, modelMatrix[ 0 ].z ) );\n\tscale.y = length( vec3( modelMatrix[ 1 ].x, modelMatrix[ 1 ].y, modelMatrix[ 1 ].z ) );\n\t#ifndef USE_SIZEATTENUATION\n\t\tbool isPerspective = isPerspectiveMatrix( projectionMatrix );\n\t\tif ( isPerspective ) scale *= - mvPosition.z;\n\t#endif\n\tvec2 alignedPosition = ( position.xy - ( center - vec2( 0.5 ) ) ) * scale;\n\tvec2 rotatedPosition;\n\trotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;\n\trotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;\n\tmvPosition.xy += rotatedPosition;\n\tgl_Position = projectionMatrix * mvPosition;\n\t#include \n\t#include \n\t#include \n}"; - -const fragment$1 = "uniform vec3 diffuse;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\tvec3 outgoingLight = vec3( 0.0 );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\t#include \n\t#include \n\t#include \n\t#include \n}"; - -const ShaderChunk = { - alphahash_fragment: alphahash_fragment, - alphahash_pars_fragment: alphahash_pars_fragment, - alphamap_fragment: alphamap_fragment, - alphamap_pars_fragment: alphamap_pars_fragment, - alphatest_fragment: alphatest_fragment, - alphatest_pars_fragment: alphatest_pars_fragment, - aomap_fragment: aomap_fragment, - aomap_pars_fragment: aomap_pars_fragment, - batching_pars_vertex: batching_pars_vertex, - batching_vertex: batching_vertex, - begin_vertex: begin_vertex, - beginnormal_vertex: beginnormal_vertex, - bsdfs: bsdfs, - iridescence_fragment: iridescence_fragment, - bumpmap_pars_fragment: bumpmap_pars_fragment, - clipping_planes_fragment: clipping_planes_fragment, - clipping_planes_pars_fragment: clipping_planes_pars_fragment, - clipping_planes_pars_vertex: clipping_planes_pars_vertex, - clipping_planes_vertex: clipping_planes_vertex, - color_fragment: color_fragment, - color_pars_fragment: color_pars_fragment, - color_pars_vertex: color_pars_vertex, - color_vertex: color_vertex, - common: common, - cube_uv_reflection_fragment: cube_uv_reflection_fragment, - defaultnormal_vertex: defaultnormal_vertex, - displacementmap_pars_vertex: displacementmap_pars_vertex, - displacementmap_vertex: displacementmap_vertex, - emissivemap_fragment: emissivemap_fragment, - emissivemap_pars_fragment: emissivemap_pars_fragment, - colorspace_fragment: colorspace_fragment, - colorspace_pars_fragment: colorspace_pars_fragment, - envmap_fragment: envmap_fragment, - envmap_common_pars_fragment: envmap_common_pars_fragment, - envmap_pars_fragment: envmap_pars_fragment, - envmap_pars_vertex: envmap_pars_vertex, - envmap_physical_pars_fragment: envmap_physical_pars_fragment, - envmap_vertex: envmap_vertex, - fog_vertex: fog_vertex, - fog_pars_vertex: fog_pars_vertex, - fog_fragment: fog_fragment, - fog_pars_fragment: fog_pars_fragment, - gradientmap_pars_fragment: gradientmap_pars_fragment, - lightmap_fragment: lightmap_fragment, - lightmap_pars_fragment: lightmap_pars_fragment, - lights_lambert_fragment: lights_lambert_fragment, - lights_lambert_pars_fragment: lights_lambert_pars_fragment, - lights_pars_begin: lights_pars_begin, - lights_toon_fragment: lights_toon_fragment, - lights_toon_pars_fragment: lights_toon_pars_fragment, - lights_phong_fragment: lights_phong_fragment, - lights_phong_pars_fragment: lights_phong_pars_fragment, - lights_physical_fragment: lights_physical_fragment, - lights_physical_pars_fragment: lights_physical_pars_fragment, - lights_fragment_begin: lights_fragment_begin, - lights_fragment_maps: lights_fragment_maps, - lights_fragment_end: lights_fragment_end, - logdepthbuf_fragment: logdepthbuf_fragment, - logdepthbuf_pars_fragment: logdepthbuf_pars_fragment, - logdepthbuf_pars_vertex: logdepthbuf_pars_vertex, - logdepthbuf_vertex: logdepthbuf_vertex, - map_fragment: map_fragment, - map_pars_fragment: map_pars_fragment, - map_particle_fragment: map_particle_fragment, - map_particle_pars_fragment: map_particle_pars_fragment, - metalnessmap_fragment: metalnessmap_fragment, - metalnessmap_pars_fragment: metalnessmap_pars_fragment, - morphcolor_vertex: morphcolor_vertex, - morphnormal_vertex: morphnormal_vertex, - morphtarget_pars_vertex: morphtarget_pars_vertex, - morphtarget_vertex: morphtarget_vertex, - normal_fragment_begin: normal_fragment_begin, - normal_fragment_maps: normal_fragment_maps, - normal_pars_fragment: normal_pars_fragment, - normal_pars_vertex: normal_pars_vertex, - normal_vertex: normal_vertex, - normalmap_pars_fragment: normalmap_pars_fragment, - clearcoat_normal_fragment_begin: clearcoat_normal_fragment_begin, - clearcoat_normal_fragment_maps: clearcoat_normal_fragment_maps, - clearcoat_pars_fragment: clearcoat_pars_fragment, - iridescence_pars_fragment: iridescence_pars_fragment, - opaque_fragment: opaque_fragment, - packing: packing, - premultiplied_alpha_fragment: premultiplied_alpha_fragment, - project_vertex: project_vertex, - dithering_fragment: dithering_fragment, - dithering_pars_fragment: dithering_pars_fragment, - roughnessmap_fragment: roughnessmap_fragment, - roughnessmap_pars_fragment: roughnessmap_pars_fragment, - shadowmap_pars_fragment: shadowmap_pars_fragment, - shadowmap_pars_vertex: shadowmap_pars_vertex, - shadowmap_vertex: shadowmap_vertex, - shadowmask_pars_fragment: shadowmask_pars_fragment, - skinbase_vertex: skinbase_vertex, - skinning_pars_vertex: skinning_pars_vertex, - skinning_vertex: skinning_vertex, - skinnormal_vertex: skinnormal_vertex, - specularmap_fragment: specularmap_fragment, - specularmap_pars_fragment: specularmap_pars_fragment, - tonemapping_fragment: tonemapping_fragment, - tonemapping_pars_fragment: tonemapping_pars_fragment, - transmission_fragment: transmission_fragment, - transmission_pars_fragment: transmission_pars_fragment, - uv_pars_fragment: uv_pars_fragment, - uv_pars_vertex: uv_pars_vertex, - uv_vertex: uv_vertex, - worldpos_vertex: worldpos_vertex, - - background_vert: vertex$h, - background_frag: fragment$h, - backgroundCube_vert: vertex$g, - backgroundCube_frag: fragment$g, - cube_vert: vertex$f, - cube_frag: fragment$f, - depth_vert: vertex$e, - depth_frag: fragment$e, - distanceRGBA_vert: vertex$d, - distanceRGBA_frag: fragment$d, - equirect_vert: vertex$c, - equirect_frag: fragment$c, - linedashed_vert: vertex$b, - linedashed_frag: fragment$b, - meshbasic_vert: vertex$a, - meshbasic_frag: fragment$a, - meshlambert_vert: vertex$9, - meshlambert_frag: fragment$9, - meshmatcap_vert: vertex$8, - meshmatcap_frag: fragment$8, - meshnormal_vert: vertex$7, - meshnormal_frag: fragment$7, - meshphong_vert: vertex$6, - meshphong_frag: fragment$6, - meshphysical_vert: vertex$5, - meshphysical_frag: fragment$5, - meshtoon_vert: vertex$4, - meshtoon_frag: fragment$4, - points_vert: vertex$3, - points_frag: fragment$3, - shadow_vert: vertex$2, - shadow_frag: fragment$2, - sprite_vert: vertex$1, - sprite_frag: fragment$1 -}; - -/** - * Uniforms library for shared webgl shaders - */ - -const UniformsLib = { - - common: { - - diffuse: { value: /*@__PURE__*/ new Color( 0xffffff ) }, - opacity: { value: 1.0 }, - - map: { value: null }, - mapTransform: { value: /*@__PURE__*/ new Matrix3() }, - - alphaMap: { value: null }, - alphaMapTransform: { value: /*@__PURE__*/ new Matrix3() }, - - alphaTest: { value: 0 } - - }, - - specularmap: { - - specularMap: { value: null }, - specularMapTransform: { value: /*@__PURE__*/ new Matrix3() } - - }, - - envmap: { - - envMap: { value: null }, - flipEnvMap: { value: - 1 }, - reflectivity: { value: 1.0 }, // basic, lambert, phong - ior: { value: 1.5 }, // physical - refractionRatio: { value: 0.98 }, // basic, lambert, phong - - }, - - aomap: { - - aoMap: { value: null }, - aoMapIntensity: { value: 1 }, - aoMapTransform: { value: /*@__PURE__*/ new Matrix3() } - - }, - - lightmap: { - - lightMap: { value: null }, - lightMapIntensity: { value: 1 }, - lightMapTransform: { value: /*@__PURE__*/ new Matrix3() } - - }, - - bumpmap: { - - bumpMap: { value: null }, - bumpMapTransform: { value: /*@__PURE__*/ new Matrix3() }, - bumpScale: { value: 1 } - - }, - - normalmap: { - - normalMap: { value: null }, - normalMapTransform: { value: /*@__PURE__*/ new Matrix3() }, - normalScale: { value: /*@__PURE__*/ new Vector2( 1, 1 ) } - - }, - - displacementmap: { - - displacementMap: { value: null }, - displacementMapTransform: { value: /*@__PURE__*/ new Matrix3() }, - displacementScale: { value: 1 }, - displacementBias: { value: 0 } - - }, - - emissivemap: { - - emissiveMap: { value: null }, - emissiveMapTransform: { value: /*@__PURE__*/ new Matrix3() } - - }, - - metalnessmap: { - - metalnessMap: { value: null }, - metalnessMapTransform: { value: /*@__PURE__*/ new Matrix3() } - - }, - - roughnessmap: { - - roughnessMap: { value: null }, - roughnessMapTransform: { value: /*@__PURE__*/ new Matrix3() } - - }, - - gradientmap: { - - gradientMap: { value: null } - - }, - - fog: { - - fogDensity: { value: 0.00025 }, - fogNear: { value: 1 }, - fogFar: { value: 2000 }, - fogColor: { value: /*@__PURE__*/ new Color( 0xffffff ) } - - }, - - lights: { - - ambientLightColor: { value: [] }, - - lightProbe: { value: [] }, - - directionalLights: { value: [], properties: { - direction: {}, - color: {} - } }, - - directionalLightShadows: { value: [], properties: { - shadowBias: {}, - shadowNormalBias: {}, - shadowRadius: {}, - shadowMapSize: {} - } }, - - directionalShadowMap: { value: [] }, - directionalShadowMatrix: { value: [] }, - - spotLights: { value: [], properties: { - color: {}, - position: {}, - direction: {}, - distance: {}, - coneCos: {}, - penumbraCos: {}, - decay: {} - } }, - - spotLightShadows: { value: [], properties: { - shadowBias: {}, - shadowNormalBias: {}, - shadowRadius: {}, - shadowMapSize: {} - } }, - - spotLightMap: { value: [] }, - spotShadowMap: { value: [] }, - spotLightMatrix: { value: [] }, - - pointLights: { value: [], properties: { - color: {}, - position: {}, - decay: {}, - distance: {} - } }, - - pointLightShadows: { value: [], properties: { - shadowBias: {}, - shadowNormalBias: {}, - shadowRadius: {}, - shadowMapSize: {}, - shadowCameraNear: {}, - shadowCameraFar: {} - } }, - - pointShadowMap: { value: [] }, - pointShadowMatrix: { value: [] }, - - hemisphereLights: { value: [], properties: { - direction: {}, - skyColor: {}, - groundColor: {} - } }, - - // TODO (abelnation): RectAreaLight BRDF data needs to be moved from example to main src - rectAreaLights: { value: [], properties: { - color: {}, - position: {}, - width: {}, - height: {} - } }, - - ltc_1: { value: null }, - ltc_2: { value: null } - - }, - - points: { - - diffuse: { value: /*@__PURE__*/ new Color( 0xffffff ) }, - opacity: { value: 1.0 }, - size: { value: 1.0 }, - scale: { value: 1.0 }, - map: { value: null }, - alphaMap: { value: null }, - alphaMapTransform: { value: /*@__PURE__*/ new Matrix3() }, - alphaTest: { value: 0 }, - uvTransform: { value: /*@__PURE__*/ new Matrix3() } - - }, - - sprite: { - - diffuse: { value: /*@__PURE__*/ new Color( 0xffffff ) }, - opacity: { value: 1.0 }, - center: { value: /*@__PURE__*/ new Vector2( 0.5, 0.5 ) }, - rotation: { value: 0.0 }, - map: { value: null }, - mapTransform: { value: /*@__PURE__*/ new Matrix3() }, - alphaMap: { value: null }, - alphaMapTransform: { value: /*@__PURE__*/ new Matrix3() }, - alphaTest: { value: 0 } - - } - -}; - -const ShaderLib = { - - basic: { - - uniforms: /*@__PURE__*/ mergeUniforms( [ - UniformsLib.common, - UniformsLib.specularmap, - UniformsLib.envmap, - UniformsLib.aomap, - UniformsLib.lightmap, - UniformsLib.fog - ] ), - - vertexShader: ShaderChunk.meshbasic_vert, - fragmentShader: ShaderChunk.meshbasic_frag - - }, - - lambert: { - - uniforms: /*@__PURE__*/ mergeUniforms( [ - UniformsLib.common, - UniformsLib.specularmap, - UniformsLib.envmap, - UniformsLib.aomap, - UniformsLib.lightmap, - UniformsLib.emissivemap, - UniformsLib.bumpmap, - UniformsLib.normalmap, - UniformsLib.displacementmap, - UniformsLib.fog, - UniformsLib.lights, - { - emissive: { value: /*@__PURE__*/ new Color( 0x000000 ) } - } - ] ), - - vertexShader: ShaderChunk.meshlambert_vert, - fragmentShader: ShaderChunk.meshlambert_frag - - }, - - phong: { - - uniforms: /*@__PURE__*/ mergeUniforms( [ - UniformsLib.common, - UniformsLib.specularmap, - UniformsLib.envmap, - UniformsLib.aomap, - UniformsLib.lightmap, - UniformsLib.emissivemap, - UniformsLib.bumpmap, - UniformsLib.normalmap, - UniformsLib.displacementmap, - UniformsLib.fog, - UniformsLib.lights, - { - emissive: { value: /*@__PURE__*/ new Color( 0x000000 ) }, - specular: { value: /*@__PURE__*/ new Color( 0x111111 ) }, - shininess: { value: 30 } - } - ] ), - - vertexShader: ShaderChunk.meshphong_vert, - fragmentShader: ShaderChunk.meshphong_frag - - }, - - standard: { - - uniforms: /*@__PURE__*/ mergeUniforms( [ - UniformsLib.common, - UniformsLib.envmap, - UniformsLib.aomap, - UniformsLib.lightmap, - UniformsLib.emissivemap, - UniformsLib.bumpmap, - UniformsLib.normalmap, - UniformsLib.displacementmap, - UniformsLib.roughnessmap, - UniformsLib.metalnessmap, - UniformsLib.fog, - UniformsLib.lights, - { - emissive: { value: /*@__PURE__*/ new Color( 0x000000 ) }, - roughness: { value: 1.0 }, - metalness: { value: 0.0 }, - envMapIntensity: { value: 1 } // temporary - } - ] ), - - vertexShader: ShaderChunk.meshphysical_vert, - fragmentShader: ShaderChunk.meshphysical_frag - - }, - - toon: { - - uniforms: /*@__PURE__*/ mergeUniforms( [ - UniformsLib.common, - UniformsLib.aomap, - UniformsLib.lightmap, - UniformsLib.emissivemap, - UniformsLib.bumpmap, - UniformsLib.normalmap, - UniformsLib.displacementmap, - UniformsLib.gradientmap, - UniformsLib.fog, - UniformsLib.lights, - { - emissive: { value: /*@__PURE__*/ new Color( 0x000000 ) } - } - ] ), - - vertexShader: ShaderChunk.meshtoon_vert, - fragmentShader: ShaderChunk.meshtoon_frag - - }, - - matcap: { - - uniforms: /*@__PURE__*/ mergeUniforms( [ - UniformsLib.common, - UniformsLib.bumpmap, - UniformsLib.normalmap, - UniformsLib.displacementmap, - UniformsLib.fog, - { - matcap: { value: null } - } - ] ), - - vertexShader: ShaderChunk.meshmatcap_vert, - fragmentShader: ShaderChunk.meshmatcap_frag - - }, - - points: { - - uniforms: /*@__PURE__*/ mergeUniforms( [ - UniformsLib.points, - UniformsLib.fog - ] ), - - vertexShader: ShaderChunk.points_vert, - fragmentShader: ShaderChunk.points_frag - - }, - - dashed: { - - uniforms: /*@__PURE__*/ mergeUniforms( [ - UniformsLib.common, - UniformsLib.fog, - { - scale: { value: 1 }, - dashSize: { value: 1 }, - totalSize: { value: 2 } - } - ] ), - - vertexShader: ShaderChunk.linedashed_vert, - fragmentShader: ShaderChunk.linedashed_frag - - }, - - depth: { - - uniforms: /*@__PURE__*/ mergeUniforms( [ - UniformsLib.common, - UniformsLib.displacementmap - ] ), - - vertexShader: ShaderChunk.depth_vert, - fragmentShader: ShaderChunk.depth_frag - - }, - - normal: { - - uniforms: /*@__PURE__*/ mergeUniforms( [ - UniformsLib.common, - UniformsLib.bumpmap, - UniformsLib.normalmap, - UniformsLib.displacementmap, - { - opacity: { value: 1.0 } - } - ] ), - - vertexShader: ShaderChunk.meshnormal_vert, - fragmentShader: ShaderChunk.meshnormal_frag - - }, - - sprite: { - - uniforms: /*@__PURE__*/ mergeUniforms( [ - UniformsLib.sprite, - UniformsLib.fog - ] ), - - vertexShader: ShaderChunk.sprite_vert, - fragmentShader: ShaderChunk.sprite_frag - - }, - - background: { - - uniforms: { - uvTransform: { value: /*@__PURE__*/ new Matrix3() }, - t2D: { value: null }, - backgroundIntensity: { value: 1 } - }, - - vertexShader: ShaderChunk.background_vert, - fragmentShader: ShaderChunk.background_frag - - }, - - backgroundCube: { - - uniforms: { - envMap: { value: null }, - flipEnvMap: { value: - 1 }, - backgroundBlurriness: { value: 0 }, - backgroundIntensity: { value: 1 } - }, - - vertexShader: ShaderChunk.backgroundCube_vert, - fragmentShader: ShaderChunk.backgroundCube_frag - - }, - - cube: { - - uniforms: { - tCube: { value: null }, - tFlip: { value: - 1 }, - opacity: { value: 1.0 } - }, - - vertexShader: ShaderChunk.cube_vert, - fragmentShader: ShaderChunk.cube_frag - - }, - - equirect: { - - uniforms: { - tEquirect: { value: null }, - }, - - vertexShader: ShaderChunk.equirect_vert, - fragmentShader: ShaderChunk.equirect_frag - - }, - - distanceRGBA: { - - uniforms: /*@__PURE__*/ mergeUniforms( [ - UniformsLib.common, - UniformsLib.displacementmap, - { - referencePosition: { value: /*@__PURE__*/ new Vector3() }, - nearDistance: { value: 1 }, - farDistance: { value: 1000 } - } - ] ), - - vertexShader: ShaderChunk.distanceRGBA_vert, - fragmentShader: ShaderChunk.distanceRGBA_frag - - }, - - shadow: { - - uniforms: /*@__PURE__*/ mergeUniforms( [ - UniformsLib.lights, - UniformsLib.fog, - { - color: { value: /*@__PURE__*/ new Color( 0x00000 ) }, - opacity: { value: 1.0 } - }, - ] ), - - vertexShader: ShaderChunk.shadow_vert, - fragmentShader: ShaderChunk.shadow_frag - - } - -}; - -ShaderLib.physical = { - - uniforms: /*@__PURE__*/ mergeUniforms( [ - ShaderLib.standard.uniforms, - { - clearcoat: { value: 0 }, - clearcoatMap: { value: null }, - clearcoatMapTransform: { value: /*@__PURE__*/ new Matrix3() }, - clearcoatNormalMap: { value: null }, - clearcoatNormalMapTransform: { value: /*@__PURE__*/ new Matrix3() }, - clearcoatNormalScale: { value: /*@__PURE__*/ new Vector2( 1, 1 ) }, - clearcoatRoughness: { value: 0 }, - clearcoatRoughnessMap: { value: null }, - clearcoatRoughnessMapTransform: { value: /*@__PURE__*/ new Matrix3() }, - iridescence: { value: 0 }, - iridescenceMap: { value: null }, - iridescenceMapTransform: { value: /*@__PURE__*/ new Matrix3() }, - iridescenceIOR: { value: 1.3 }, - iridescenceThicknessMinimum: { value: 100 }, - iridescenceThicknessMaximum: { value: 400 }, - iridescenceThicknessMap: { value: null }, - iridescenceThicknessMapTransform: { value: /*@__PURE__*/ new Matrix3() }, - sheen: { value: 0 }, - sheenColor: { value: /*@__PURE__*/ new Color( 0x000000 ) }, - sheenColorMap: { value: null }, - sheenColorMapTransform: { value: /*@__PURE__*/ new Matrix3() }, - sheenRoughness: { value: 1 }, - sheenRoughnessMap: { value: null }, - sheenRoughnessMapTransform: { value: /*@__PURE__*/ new Matrix3() }, - transmission: { value: 0 }, - transmissionMap: { value: null }, - transmissionMapTransform: { value: /*@__PURE__*/ new Matrix3() }, - transmissionSamplerSize: { value: /*@__PURE__*/ new Vector2() }, - transmissionSamplerMap: { value: null }, - thickness: { value: 0 }, - thicknessMap: { value: null }, - thicknessMapTransform: { value: /*@__PURE__*/ new Matrix3() }, - attenuationDistance: { value: 0 }, - attenuationColor: { value: /*@__PURE__*/ new Color( 0x000000 ) }, - specularColor: { value: /*@__PURE__*/ new Color( 1, 1, 1 ) }, - specularColorMap: { value: null }, - specularColorMapTransform: { value: /*@__PURE__*/ new Matrix3() }, - specularIntensity: { value: 1 }, - specularIntensityMap: { value: null }, - specularIntensityMapTransform: { value: /*@__PURE__*/ new Matrix3() }, - anisotropyVector: { value: /*@__PURE__*/ new Vector2() }, - anisotropyMap: { value: null }, - anisotropyMapTransform: { value: /*@__PURE__*/ new Matrix3() }, - } - ] ), - - vertexShader: ShaderChunk.meshphysical_vert, - fragmentShader: ShaderChunk.meshphysical_frag - -}; - -const _rgb = { r: 0, b: 0, g: 0 }; - -function WebGLBackground( renderer, cubemaps, cubeuvmaps, state, objects, alpha, premultipliedAlpha ) { - - const clearColor = new Color( 0x000000 ); - let clearAlpha = alpha === true ? 0 : 1; - - let planeMesh; - let boxMesh; - - let currentBackground = null; - let currentBackgroundVersion = 0; - let currentTonemapping = null; - - function render( renderList, scene ) { - - let forceClear = false; - let background = scene.isScene === true ? scene.background : null; - - if ( background && background.isTexture ) { - - const usePMREM = scene.backgroundBlurriness > 0; // use PMREM if the user wants to blur the background - background = ( usePMREM ? cubeuvmaps : cubemaps ).get( background ); - - } - - if ( background === null ) { - - setClear( clearColor, clearAlpha ); - - } else if ( background && background.isColor ) { - - setClear( background, 1 ); - forceClear = true; - - } - - const environmentBlendMode = renderer.xr.getEnvironmentBlendMode(); - - if ( environmentBlendMode === 'additive' ) { - - state.buffers.color.setClear( 0, 0, 0, 1, premultipliedAlpha ); - - } else if ( environmentBlendMode === 'alpha-blend' ) { - - state.buffers.color.setClear( 0, 0, 0, 0, premultipliedAlpha ); - - } - - if ( renderer.autoClear || forceClear ) { - - renderer.clear( renderer.autoClearColor, renderer.autoClearDepth, renderer.autoClearStencil ); - - } - - if ( background && ( background.isCubeTexture || background.mapping === CubeUVReflectionMapping ) ) { - - if ( boxMesh === undefined ) { - - boxMesh = new Mesh( - new BoxGeometry( 1, 1, 1 ), - new ShaderMaterial( { - name: 'BackgroundCubeMaterial', - uniforms: cloneUniforms( ShaderLib.backgroundCube.uniforms ), - vertexShader: ShaderLib.backgroundCube.vertexShader, - fragmentShader: ShaderLib.backgroundCube.fragmentShader, - side: BackSide, - depthTest: false, - depthWrite: false, - fog: false - } ) - ); - - boxMesh.geometry.deleteAttribute( 'normal' ); - boxMesh.geometry.deleteAttribute( 'uv' ); - - boxMesh.onBeforeRender = function ( renderer, scene, camera ) { - - this.matrixWorld.copyPosition( camera.matrixWorld ); - - }; - - // add "envMap" material property so the renderer can evaluate it like for built-in materials - Object.defineProperty( boxMesh.material, 'envMap', { - - get: function () { - - return this.uniforms.envMap.value; - - } - - } ); - - objects.update( boxMesh ); - - } - - boxMesh.material.uniforms.envMap.value = background; - boxMesh.material.uniforms.flipEnvMap.value = ( background.isCubeTexture && background.isRenderTargetTexture === false ) ? - 1 : 1; - boxMesh.material.uniforms.backgroundBlurriness.value = scene.backgroundBlurriness; - boxMesh.material.uniforms.backgroundIntensity.value = scene.backgroundIntensity; - boxMesh.material.toneMapped = ColorManagement.getTransfer( background.colorSpace ) !== SRGBTransfer; - - if ( currentBackground !== background || - currentBackgroundVersion !== background.version || - currentTonemapping !== renderer.toneMapping ) { - - boxMesh.material.needsUpdate = true; - - currentBackground = background; - currentBackgroundVersion = background.version; - currentTonemapping = renderer.toneMapping; - - } - - boxMesh.layers.enableAll(); - - // push to the pre-sorted opaque render list - renderList.unshift( boxMesh, boxMesh.geometry, boxMesh.material, 0, 0, null ); - - } else if ( background && background.isTexture ) { - - if ( planeMesh === undefined ) { - - planeMesh = new Mesh( - new PlaneGeometry( 2, 2 ), - new ShaderMaterial( { - name: 'BackgroundMaterial', - uniforms: cloneUniforms( ShaderLib.background.uniforms ), - vertexShader: ShaderLib.background.vertexShader, - fragmentShader: ShaderLib.background.fragmentShader, - side: FrontSide, - depthTest: false, - depthWrite: false, - fog: false - } ) - ); - - planeMesh.geometry.deleteAttribute( 'normal' ); - - // add "map" material property so the renderer can evaluate it like for built-in materials - Object.defineProperty( planeMesh.material, 'map', { - - get: function () { - - return this.uniforms.t2D.value; - - } - - } ); - - objects.update( planeMesh ); - - } - - planeMesh.material.uniforms.t2D.value = background; - planeMesh.material.uniforms.backgroundIntensity.value = scene.backgroundIntensity; - planeMesh.material.toneMapped = ColorManagement.getTransfer( background.colorSpace ) !== SRGBTransfer; - - if ( background.matrixAutoUpdate === true ) { - - background.updateMatrix(); - - } - - planeMesh.material.uniforms.uvTransform.value.copy( background.matrix ); - - if ( currentBackground !== background || - currentBackgroundVersion !== background.version || - currentTonemapping !== renderer.toneMapping ) { - - planeMesh.material.needsUpdate = true; - - currentBackground = background; - currentBackgroundVersion = background.version; - currentTonemapping = renderer.toneMapping; - - } - - planeMesh.layers.enableAll(); - - // push to the pre-sorted opaque render list - renderList.unshift( planeMesh, planeMesh.geometry, planeMesh.material, 0, 0, null ); - - } - - } - - function setClear( color, alpha ) { - - color.getRGB( _rgb, getUnlitUniformColorSpace( renderer ) ); - - state.buffers.color.setClear( _rgb.r, _rgb.g, _rgb.b, alpha, premultipliedAlpha ); - - } - - return { - - getClearColor: function () { - - return clearColor; - - }, - setClearColor: function ( color, alpha = 1 ) { - - clearColor.set( color ); - clearAlpha = alpha; - setClear( clearColor, clearAlpha ); - - }, - getClearAlpha: function () { - - return clearAlpha; - - }, - setClearAlpha: function ( alpha ) { - - clearAlpha = alpha; - setClear( clearColor, clearAlpha ); - - }, - render: render - - }; - -} - -function WebGLBindingStates( gl, extensions, attributes, capabilities ) { - - const maxVertexAttributes = gl.getParameter( gl.MAX_VERTEX_ATTRIBS ); - - const extension = capabilities.isWebGL2 ? null : extensions.get( 'OES_vertex_array_object' ); - const vaoAvailable = capabilities.isWebGL2 || extension !== null; - - const bindingStates = {}; - - const defaultState = createBindingState( null ); - let currentState = defaultState; - let forceUpdate = false; - - function setup( object, material, program, geometry, index ) { - - let updateBuffers = false; - - if ( vaoAvailable ) { - - const state = getBindingState( geometry, program, material ); - - if ( currentState !== state ) { - - currentState = state; - bindVertexArrayObject( currentState.object ); - - } - - updateBuffers = needsUpdate( object, geometry, program, index ); - - if ( updateBuffers ) saveCache( object, geometry, program, index ); - - } else { - - const wireframe = ( material.wireframe === true ); - - if ( currentState.geometry !== geometry.id || - currentState.program !== program.id || - currentState.wireframe !== wireframe ) { - - currentState.geometry = geometry.id; - currentState.program = program.id; - currentState.wireframe = wireframe; - - updateBuffers = true; - - } - - } - - if ( index !== null ) { - - attributes.update( index, gl.ELEMENT_ARRAY_BUFFER ); - - } - - if ( updateBuffers || forceUpdate ) { - - forceUpdate = false; - - setupVertexAttributes( object, material, program, geometry ); - - if ( index !== null ) { - - gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, attributes.get( index ).buffer ); - - } - - } - - } - - function createVertexArrayObject() { - - if ( capabilities.isWebGL2 ) return gl.createVertexArray(); - - return extension.createVertexArrayOES(); - - } - - function bindVertexArrayObject( vao ) { - - if ( capabilities.isWebGL2 ) return gl.bindVertexArray( vao ); - - return extension.bindVertexArrayOES( vao ); - - } - - function deleteVertexArrayObject( vao ) { - - if ( capabilities.isWebGL2 ) return gl.deleteVertexArray( vao ); - - return extension.deleteVertexArrayOES( vao ); - - } - - function getBindingState( geometry, program, material ) { - - const wireframe = ( material.wireframe === true ); - - let programMap = bindingStates[ geometry.id ]; - - if ( programMap === undefined ) { - - programMap = {}; - bindingStates[ geometry.id ] = programMap; - - } - - let stateMap = programMap[ program.id ]; - - if ( stateMap === undefined ) { - - stateMap = {}; - programMap[ program.id ] = stateMap; - - } - - let state = stateMap[ wireframe ]; - - if ( state === undefined ) { - - state = createBindingState( createVertexArrayObject() ); - stateMap[ wireframe ] = state; - - } - - return state; - - } - - function createBindingState( vao ) { - - const newAttributes = []; - const enabledAttributes = []; - const attributeDivisors = []; - - for ( let i = 0; i < maxVertexAttributes; i ++ ) { - - newAttributes[ i ] = 0; - enabledAttributes[ i ] = 0; - attributeDivisors[ i ] = 0; - - } - - return { - - // for backward compatibility on non-VAO support browser - geometry: null, - program: null, - wireframe: false, - - newAttributes: newAttributes, - enabledAttributes: enabledAttributes, - attributeDivisors: attributeDivisors, - object: vao, - attributes: {}, - index: null - - }; - - } - - function needsUpdate( object, geometry, program, index ) { - - const cachedAttributes = currentState.attributes; - const geometryAttributes = geometry.attributes; - - let attributesNum = 0; - - const programAttributes = program.getAttributes(); - - for ( const name in programAttributes ) { - - const programAttribute = programAttributes[ name ]; - - if ( programAttribute.location >= 0 ) { - - const cachedAttribute = cachedAttributes[ name ]; - let geometryAttribute = geometryAttributes[ name ]; - - if ( geometryAttribute === undefined ) { - - if ( name === 'instanceMatrix' && object.instanceMatrix ) geometryAttribute = object.instanceMatrix; - if ( name === 'instanceColor' && object.instanceColor ) geometryAttribute = object.instanceColor; - - } - - if ( cachedAttribute === undefined ) return true; - - if ( cachedAttribute.attribute !== geometryAttribute ) return true; - - if ( geometryAttribute && cachedAttribute.data !== geometryAttribute.data ) return true; - - attributesNum ++; - - } - - } - - if ( currentState.attributesNum !== attributesNum ) return true; - - if ( currentState.index !== index ) return true; - - return false; - - } - - function saveCache( object, geometry, program, index ) { - - const cache = {}; - const attributes = geometry.attributes; - let attributesNum = 0; - - const programAttributes = program.getAttributes(); - - for ( const name in programAttributes ) { - - const programAttribute = programAttributes[ name ]; - - if ( programAttribute.location >= 0 ) { - - let attribute = attributes[ name ]; - - if ( attribute === undefined ) { - - if ( name === 'instanceMatrix' && object.instanceMatrix ) attribute = object.instanceMatrix; - if ( name === 'instanceColor' && object.instanceColor ) attribute = object.instanceColor; - - } - - const data = {}; - data.attribute = attribute; - - if ( attribute && attribute.data ) { - - data.data = attribute.data; - - } - - cache[ name ] = data; - - attributesNum ++; - - } - - } - - currentState.attributes = cache; - currentState.attributesNum = attributesNum; - - currentState.index = index; - - } - - function initAttributes() { - - const newAttributes = currentState.newAttributes; - - for ( let i = 0, il = newAttributes.length; i < il; i ++ ) { - - newAttributes[ i ] = 0; - - } - - } - - function enableAttribute( attribute ) { - - enableAttributeAndDivisor( attribute, 0 ); - - } - - function enableAttributeAndDivisor( attribute, meshPerAttribute ) { - - const newAttributes = currentState.newAttributes; - const enabledAttributes = currentState.enabledAttributes; - const attributeDivisors = currentState.attributeDivisors; - - newAttributes[ attribute ] = 1; - - if ( enabledAttributes[ attribute ] === 0 ) { - - gl.enableVertexAttribArray( attribute ); - enabledAttributes[ attribute ] = 1; - - } - - if ( attributeDivisors[ attribute ] !== meshPerAttribute ) { - - const extension = capabilities.isWebGL2 ? gl : extensions.get( 'ANGLE_instanced_arrays' ); - - extension[ capabilities.isWebGL2 ? 'vertexAttribDivisor' : 'vertexAttribDivisorANGLE' ]( attribute, meshPerAttribute ); - attributeDivisors[ attribute ] = meshPerAttribute; - - } - - } - - function disableUnusedAttributes() { - - const newAttributes = currentState.newAttributes; - const enabledAttributes = currentState.enabledAttributes; - - for ( let i = 0, il = enabledAttributes.length; i < il; i ++ ) { - - if ( enabledAttributes[ i ] !== newAttributes[ i ] ) { - - gl.disableVertexAttribArray( i ); - enabledAttributes[ i ] = 0; - - } - - } - - } - - function vertexAttribPointer( index, size, type, normalized, stride, offset, integer ) { - - if ( integer === true ) { - - gl.vertexAttribIPointer( index, size, type, stride, offset ); - - } else { - - gl.vertexAttribPointer( index, size, type, normalized, stride, offset ); - - } - - } - - function setupVertexAttributes( object, material, program, geometry ) { - - if ( capabilities.isWebGL2 === false && ( object.isInstancedMesh || geometry.isInstancedBufferGeometry ) ) { - - if ( extensions.get( 'ANGLE_instanced_arrays' ) === null ) return; - - } - - initAttributes(); - - const geometryAttributes = geometry.attributes; - - const programAttributes = program.getAttributes(); - - const materialDefaultAttributeValues = material.defaultAttributeValues; - - for ( const name in programAttributes ) { - - const programAttribute = programAttributes[ name ]; - - if ( programAttribute.location >= 0 ) { - - let geometryAttribute = geometryAttributes[ name ]; - - if ( geometryAttribute === undefined ) { - - if ( name === 'instanceMatrix' && object.instanceMatrix ) geometryAttribute = object.instanceMatrix; - if ( name === 'instanceColor' && object.instanceColor ) geometryAttribute = object.instanceColor; - - } - - if ( geometryAttribute !== undefined ) { - - const normalized = geometryAttribute.normalized; - const size = geometryAttribute.itemSize; - - const attribute = attributes.get( geometryAttribute ); - - // TODO Attribute may not be available on context restore - - if ( attribute === undefined ) continue; - - const buffer = attribute.buffer; - const type = attribute.type; - const bytesPerElement = attribute.bytesPerElement; - - // check for integer attributes (WebGL 2 only) - - const integer = ( capabilities.isWebGL2 === true && ( type === gl.INT || type === gl.UNSIGNED_INT || geometryAttribute.gpuType === IntType ) ); - - if ( geometryAttribute.isInterleavedBufferAttribute ) { - - const data = geometryAttribute.data; - const stride = data.stride; - const offset = geometryAttribute.offset; - - if ( data.isInstancedInterleavedBuffer ) { - - for ( let i = 0; i < programAttribute.locationSize; i ++ ) { - - enableAttributeAndDivisor( programAttribute.location + i, data.meshPerAttribute ); - - } - - if ( object.isInstancedMesh !== true && geometry._maxInstanceCount === undefined ) { - - geometry._maxInstanceCount = data.meshPerAttribute * data.count; - - } - - } else { - - for ( let i = 0; i < programAttribute.locationSize; i ++ ) { - - enableAttribute( programAttribute.location + i ); - - } - - } - - gl.bindBuffer( gl.ARRAY_BUFFER, buffer ); - - for ( let i = 0; i < programAttribute.locationSize; i ++ ) { - - vertexAttribPointer( - programAttribute.location + i, - size / programAttribute.locationSize, - type, - normalized, - stride * bytesPerElement, - ( offset + ( size / programAttribute.locationSize ) * i ) * bytesPerElement, - integer - ); - - } - - } else { - - if ( geometryAttribute.isInstancedBufferAttribute ) { - - for ( let i = 0; i < programAttribute.locationSize; i ++ ) { - - enableAttributeAndDivisor( programAttribute.location + i, geometryAttribute.meshPerAttribute ); - - } - - if ( object.isInstancedMesh !== true && geometry._maxInstanceCount === undefined ) { - - geometry._maxInstanceCount = geometryAttribute.meshPerAttribute * geometryAttribute.count; - - } - - } else { - - for ( let i = 0; i < programAttribute.locationSize; i ++ ) { - - enableAttribute( programAttribute.location + i ); - - } - - } - - gl.bindBuffer( gl.ARRAY_BUFFER, buffer ); - - for ( let i = 0; i < programAttribute.locationSize; i ++ ) { - - vertexAttribPointer( - programAttribute.location + i, - size / programAttribute.locationSize, - type, - normalized, - size * bytesPerElement, - ( size / programAttribute.locationSize ) * i * bytesPerElement, - integer - ); - - } - - } - - } else if ( materialDefaultAttributeValues !== undefined ) { - - const value = materialDefaultAttributeValues[ name ]; - - if ( value !== undefined ) { - - switch ( value.length ) { - - case 2: - gl.vertexAttrib2fv( programAttribute.location, value ); - break; - - case 3: - gl.vertexAttrib3fv( programAttribute.location, value ); - break; - - case 4: - gl.vertexAttrib4fv( programAttribute.location, value ); - break; - - default: - gl.vertexAttrib1fv( programAttribute.location, value ); - - } - - } - - } - - } - - } - - disableUnusedAttributes(); - - } - - function dispose() { - - reset(); - - for ( const geometryId in bindingStates ) { - - const programMap = bindingStates[ geometryId ]; - - for ( const programId in programMap ) { - - const stateMap = programMap[ programId ]; - - for ( const wireframe in stateMap ) { - - deleteVertexArrayObject( stateMap[ wireframe ].object ); - - delete stateMap[ wireframe ]; - - } - - delete programMap[ programId ]; - - } - - delete bindingStates[ geometryId ]; - - } - - } - - function releaseStatesOfGeometry( geometry ) { - - if ( bindingStates[ geometry.id ] === undefined ) return; - - const programMap = bindingStates[ geometry.id ]; - - for ( const programId in programMap ) { - - const stateMap = programMap[ programId ]; - - for ( const wireframe in stateMap ) { - - deleteVertexArrayObject( stateMap[ wireframe ].object ); - - delete stateMap[ wireframe ]; - - } - - delete programMap[ programId ]; - - } - - delete bindingStates[ geometry.id ]; - - } - - function releaseStatesOfProgram( program ) { - - for ( const geometryId in bindingStates ) { - - const programMap = bindingStates[ geometryId ]; - - if ( programMap[ program.id ] === undefined ) continue; - - const stateMap = programMap[ program.id ]; - - for ( const wireframe in stateMap ) { - - deleteVertexArrayObject( stateMap[ wireframe ].object ); - - delete stateMap[ wireframe ]; - - } - - delete programMap[ program.id ]; - - } - - } - - function reset() { - - resetDefaultState(); - forceUpdate = true; - - if ( currentState === defaultState ) return; - - currentState = defaultState; - bindVertexArrayObject( currentState.object ); - - } - - // for backward-compatibility - - function resetDefaultState() { - - defaultState.geometry = null; - defaultState.program = null; - defaultState.wireframe = false; - - } - - return { - - setup: setup, - reset: reset, - resetDefaultState: resetDefaultState, - dispose: dispose, - releaseStatesOfGeometry: releaseStatesOfGeometry, - releaseStatesOfProgram: releaseStatesOfProgram, - - initAttributes: initAttributes, - enableAttribute: enableAttribute, - disableUnusedAttributes: disableUnusedAttributes - - }; - -} - -function WebGLBufferRenderer( gl, extensions, info, capabilities ) { - - const isWebGL2 = capabilities.isWebGL2; - - let mode; - - function setMode( value ) { - - mode = value; - - } - - function render( start, count ) { - - gl.drawArrays( mode, start, count ); - - info.update( count, mode, 1 ); - - } - - function renderInstances( start, count, primcount ) { - - if ( primcount === 0 ) return; - - let extension, methodName; - - if ( isWebGL2 ) { - - extension = gl; - methodName = 'drawArraysInstanced'; - - } else { - - extension = extensions.get( 'ANGLE_instanced_arrays' ); - methodName = 'drawArraysInstancedANGLE'; - - if ( extension === null ) { - - console.error( 'THREE.WebGLBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' ); - return; - - } - - } - - extension[ methodName ]( mode, start, count, primcount ); - - info.update( count, mode, primcount ); - - } - - function renderMultiDraw( starts, counts, drawCount ) { - - if ( drawCount === 0 ) return; - - const extension = extensions.get( 'WEBGL_multi_draw' ); - if ( extension === null ) { - - for ( let i = 0; i < drawCount; i ++ ) { - - this.render( starts[ i ], counts[ i ] ); - - } - - } else { - - extension.multiDrawArraysWEBGL( mode, starts, 0, counts, 0, drawCount ); - - let elementCount = 0; - for ( let i = 0; i < drawCount; i ++ ) { - - elementCount += counts[ i ]; - - } - - info.update( elementCount, mode, 1 ); - - } - - } - - // - - this.setMode = setMode; - this.render = render; - this.renderInstances = renderInstances; - this.renderMultiDraw = renderMultiDraw; - -} - -function WebGLCapabilities( gl, extensions, parameters ) { - - let maxAnisotropy; - - function getMaxAnisotropy() { - - if ( maxAnisotropy !== undefined ) return maxAnisotropy; - - if ( extensions.has( 'EXT_texture_filter_anisotropic' ) === true ) { - - const extension = extensions.get( 'EXT_texture_filter_anisotropic' ); - - maxAnisotropy = gl.getParameter( extension.MAX_TEXTURE_MAX_ANISOTROPY_EXT ); - - } else { - - maxAnisotropy = 0; - - } - - return maxAnisotropy; - - } - - function getMaxPrecision( precision ) { - - if ( precision === 'highp' ) { - - if ( gl.getShaderPrecisionFormat( gl.VERTEX_SHADER, gl.HIGH_FLOAT ).precision > 0 && - gl.getShaderPrecisionFormat( gl.FRAGMENT_SHADER, gl.HIGH_FLOAT ).precision > 0 ) { - - return 'highp'; - - } - - precision = 'mediump'; - - } - - if ( precision === 'mediump' ) { - - if ( gl.getShaderPrecisionFormat( gl.VERTEX_SHADER, gl.MEDIUM_FLOAT ).precision > 0 && - gl.getShaderPrecisionFormat( gl.FRAGMENT_SHADER, gl.MEDIUM_FLOAT ).precision > 0 ) { - - return 'mediump'; - - } - - } - - return 'lowp'; - - } - - const isWebGL2 = typeof WebGL2RenderingContext !== 'undefined' && gl.constructor.name === 'WebGL2RenderingContext'; - - let precision = parameters.precision !== undefined ? parameters.precision : 'highp'; - const maxPrecision = getMaxPrecision( precision ); - - if ( maxPrecision !== precision ) { - - console.warn( 'THREE.WebGLRenderer:', precision, 'not supported, using', maxPrecision, 'instead.' ); - precision = maxPrecision; - - } - - const drawBuffers = isWebGL2 || extensions.has( 'WEBGL_draw_buffers' ); - - const logarithmicDepthBuffer = parameters.logarithmicDepthBuffer === true; - - const maxTextures = gl.getParameter( gl.MAX_TEXTURE_IMAGE_UNITS ); - const maxVertexTextures = gl.getParameter( gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS ); - const maxTextureSize = gl.getParameter( gl.MAX_TEXTURE_SIZE ); - const maxCubemapSize = gl.getParameter( gl.MAX_CUBE_MAP_TEXTURE_SIZE ); - - const maxAttributes = gl.getParameter( gl.MAX_VERTEX_ATTRIBS ); - const maxVertexUniforms = gl.getParameter( gl.MAX_VERTEX_UNIFORM_VECTORS ); - const maxVaryings = gl.getParameter( gl.MAX_VARYING_VECTORS ); - const maxFragmentUniforms = gl.getParameter( gl.MAX_FRAGMENT_UNIFORM_VECTORS ); - - const vertexTextures = maxVertexTextures > 0; - const floatFragmentTextures = isWebGL2 || extensions.has( 'OES_texture_float' ); - const floatVertexTextures = vertexTextures && floatFragmentTextures; - - const maxSamples = isWebGL2 ? gl.getParameter( gl.MAX_SAMPLES ) : 0; - - return { - - isWebGL2: isWebGL2, - - drawBuffers: drawBuffers, - - getMaxAnisotropy: getMaxAnisotropy, - getMaxPrecision: getMaxPrecision, - - precision: precision, - logarithmicDepthBuffer: logarithmicDepthBuffer, - - maxTextures: maxTextures, - maxVertexTextures: maxVertexTextures, - maxTextureSize: maxTextureSize, - maxCubemapSize: maxCubemapSize, - - maxAttributes: maxAttributes, - maxVertexUniforms: maxVertexUniforms, - maxVaryings: maxVaryings, - maxFragmentUniforms: maxFragmentUniforms, - - vertexTextures: vertexTextures, - floatFragmentTextures: floatFragmentTextures, - floatVertexTextures: floatVertexTextures, - - maxSamples: maxSamples - - }; - -} - -function WebGLClipping( properties ) { - - const scope = this; - - let globalState = null, - numGlobalPlanes = 0, - localClippingEnabled = false, - renderingShadows = false; - - const plane = new Plane(), - viewNormalMatrix = new Matrix3(), - - uniform = { value: null, needsUpdate: false }; - - this.uniform = uniform; - this.numPlanes = 0; - this.numIntersection = 0; - - this.init = function ( planes, enableLocalClipping ) { - - const enabled = - planes.length !== 0 || - enableLocalClipping || - // enable state of previous frame - the clipping code has to - // run another frame in order to reset the state: - numGlobalPlanes !== 0 || - localClippingEnabled; - - localClippingEnabled = enableLocalClipping; - - numGlobalPlanes = planes.length; - - return enabled; - - }; - - this.beginShadows = function () { - - renderingShadows = true; - projectPlanes( null ); - - }; - - this.endShadows = function () { - - renderingShadows = false; - - }; - - this.setGlobalState = function ( planes, camera ) { - - globalState = projectPlanes( planes, camera, 0 ); - - }; - - this.setState = function ( material, camera, useCache ) { - - const planes = material.clippingPlanes, - clipIntersection = material.clipIntersection, - clipShadows = material.clipShadows; - - const materialProperties = properties.get( material ); - - if ( ! localClippingEnabled || planes === null || planes.length === 0 || renderingShadows && ! clipShadows ) { - - // there's no local clipping - - if ( renderingShadows ) { - - // there's no global clipping - - projectPlanes( null ); - - } else { - - resetGlobalState(); - - } - - } else { - - const nGlobal = renderingShadows ? 0 : numGlobalPlanes, - lGlobal = nGlobal * 4; - - let dstArray = materialProperties.clippingState || null; - - uniform.value = dstArray; // ensure unique state - - dstArray = projectPlanes( planes, camera, lGlobal, useCache ); - - for ( let i = 0; i !== lGlobal; ++ i ) { - - dstArray[ i ] = globalState[ i ]; - - } - - materialProperties.clippingState = dstArray; - this.numIntersection = clipIntersection ? this.numPlanes : 0; - this.numPlanes += nGlobal; - - } - - - }; - - function resetGlobalState() { - - if ( uniform.value !== globalState ) { - - uniform.value = globalState; - uniform.needsUpdate = numGlobalPlanes > 0; - - } - - scope.numPlanes = numGlobalPlanes; - scope.numIntersection = 0; - - } - - function projectPlanes( planes, camera, dstOffset, skipTransform ) { - - const nPlanes = planes !== null ? planes.length : 0; - let dstArray = null; - - if ( nPlanes !== 0 ) { - - dstArray = uniform.value; - - if ( skipTransform !== true || dstArray === null ) { - - const flatSize = dstOffset + nPlanes * 4, - viewMatrix = camera.matrixWorldInverse; - - viewNormalMatrix.getNormalMatrix( viewMatrix ); - - if ( dstArray === null || dstArray.length < flatSize ) { - - dstArray = new Float32Array( flatSize ); - - } - - for ( let i = 0, i4 = dstOffset; i !== nPlanes; ++ i, i4 += 4 ) { - - plane.copy( planes[ i ] ).applyMatrix4( viewMatrix, viewNormalMatrix ); - - plane.normal.toArray( dstArray, i4 ); - dstArray[ i4 + 3 ] = plane.constant; - - } - - } - - uniform.value = dstArray; - uniform.needsUpdate = true; - - } - - scope.numPlanes = nPlanes; - scope.numIntersection = 0; - - return dstArray; - - } - -} - -function WebGLCubeMaps( renderer ) { - - let cubemaps = new WeakMap(); - - function mapTextureMapping( texture, mapping ) { - - if ( mapping === EquirectangularReflectionMapping ) { - - texture.mapping = CubeReflectionMapping; - - } else if ( mapping === EquirectangularRefractionMapping ) { - - texture.mapping = CubeRefractionMapping; - - } - - return texture; - - } - - function get( texture ) { - - if ( texture && texture.isTexture ) { - - const mapping = texture.mapping; - - if ( mapping === EquirectangularReflectionMapping || mapping === EquirectangularRefractionMapping ) { - - if ( cubemaps.has( texture ) ) { - - const cubemap = cubemaps.get( texture ).texture; - return mapTextureMapping( cubemap, texture.mapping ); - - } else { - - const image = texture.image; - - if ( image && image.height > 0 ) { - - const renderTarget = new WebGLCubeRenderTarget( image.height ); - renderTarget.fromEquirectangularTexture( renderer, texture ); - cubemaps.set( texture, renderTarget ); - - texture.addEventListener( 'dispose', onTextureDispose ); - - return mapTextureMapping( renderTarget.texture, texture.mapping ); - - } else { - - // image not yet ready. try the conversion next frame - - return null; - - } - - } - - } - - } - - return texture; - - } - - function onTextureDispose( event ) { - - const texture = event.target; - - texture.removeEventListener( 'dispose', onTextureDispose ); - - const cubemap = cubemaps.get( texture ); - - if ( cubemap !== undefined ) { - - cubemaps.delete( texture ); - cubemap.dispose(); - - } - - } - - function dispose() { - - cubemaps = new WeakMap(); - - } - - return { - get: get, - dispose: dispose - }; - -} - -class OrthographicCamera extends Camera { - - constructor( left = - 1, right = 1, top = 1, bottom = - 1, near = 0.1, far = 2000 ) { - - super(); - - this.isOrthographicCamera = true; - - this.type = 'OrthographicCamera'; - - this.zoom = 1; - this.view = null; - - this.left = left; - this.right = right; - this.top = top; - this.bottom = bottom; - - this.near = near; - this.far = far; - - this.updateProjectionMatrix(); - - } - - copy( source, recursive ) { - - super.copy( source, recursive ); - - this.left = source.left; - this.right = source.right; - this.top = source.top; - this.bottom = source.bottom; - this.near = source.near; - this.far = source.far; - - this.zoom = source.zoom; - this.view = source.view === null ? null : Object.assign( {}, source.view ); - - return this; - - } - - setViewOffset( fullWidth, fullHeight, x, y, width, height ) { - - if ( this.view === null ) { - - this.view = { - enabled: true, - fullWidth: 1, - fullHeight: 1, - offsetX: 0, - offsetY: 0, - width: 1, - height: 1 - }; - - } - - this.view.enabled = true; - this.view.fullWidth = fullWidth; - this.view.fullHeight = fullHeight; - this.view.offsetX = x; - this.view.offsetY = y; - this.view.width = width; - this.view.height = height; - - this.updateProjectionMatrix(); - - } - - clearViewOffset() { - - if ( this.view !== null ) { - - this.view.enabled = false; - - } - - this.updateProjectionMatrix(); - - } - - updateProjectionMatrix() { - - const dx = ( this.right - this.left ) / ( 2 * this.zoom ); - const dy = ( this.top - this.bottom ) / ( 2 * this.zoom ); - const cx = ( this.right + this.left ) / 2; - const cy = ( this.top + this.bottom ) / 2; - - let left = cx - dx; - let right = cx + dx; - let top = cy + dy; - let bottom = cy - dy; - - if ( this.view !== null && this.view.enabled ) { - - const scaleW = ( this.right - this.left ) / this.view.fullWidth / this.zoom; - const scaleH = ( this.top - this.bottom ) / this.view.fullHeight / this.zoom; - - left += scaleW * this.view.offsetX; - right = left + scaleW * this.view.width; - top -= scaleH * this.view.offsetY; - bottom = top - scaleH * this.view.height; - - } - - this.projectionMatrix.makeOrthographic( left, right, top, bottom, this.near, this.far, this.coordinateSystem ); - - this.projectionMatrixInverse.copy( this.projectionMatrix ).invert(); - - } - - toJSON( meta ) { - - const data = super.toJSON( meta ); - - data.object.zoom = this.zoom; - data.object.left = this.left; - data.object.right = this.right; - data.object.top = this.top; - data.object.bottom = this.bottom; - data.object.near = this.near; - data.object.far = this.far; - - if ( this.view !== null ) data.object.view = Object.assign( {}, this.view ); - - return data; - - } - -} - -const LOD_MIN = 4; - -// The standard deviations (radians) associated with the extra mips. These are -// chosen to approximate a Trowbridge-Reitz distribution function times the -// geometric shadowing function. These sigma values squared must match the -// variance #defines in cube_uv_reflection_fragment.glsl.js. -const EXTRA_LOD_SIGMA = [ 0.125, 0.215, 0.35, 0.446, 0.526, 0.582 ]; - -// The maximum length of the blur for loop. Smaller sigmas will use fewer -// samples and exit early, but not recompile the shader. -const MAX_SAMPLES = 20; - -const _flatCamera = /*@__PURE__*/ new OrthographicCamera(); -const _clearColor = /*@__PURE__*/ new Color(); -let _oldTarget = null; -let _oldActiveCubeFace = 0; -let _oldActiveMipmapLevel = 0; - -// Golden Ratio -const PHI = ( 1 + Math.sqrt( 5 ) ) / 2; -const INV_PHI = 1 / PHI; - -// Vertices of a dodecahedron (except the opposites, which represent the -// same axis), used as axis directions evenly spread on a sphere. -const _axisDirections = [ - /*@__PURE__*/ new Vector3( 1, 1, 1 ), - /*@__PURE__*/ new Vector3( - 1, 1, 1 ), - /*@__PURE__*/ new Vector3( 1, 1, - 1 ), - /*@__PURE__*/ new Vector3( - 1, 1, - 1 ), - /*@__PURE__*/ new Vector3( 0, PHI, INV_PHI ), - /*@__PURE__*/ new Vector3( 0, PHI, - INV_PHI ), - /*@__PURE__*/ new Vector3( INV_PHI, 0, PHI ), - /*@__PURE__*/ new Vector3( - INV_PHI, 0, PHI ), - /*@__PURE__*/ new Vector3( PHI, INV_PHI, 0 ), - /*@__PURE__*/ new Vector3( - PHI, INV_PHI, 0 ) ]; - -/** - * This class generates a Prefiltered, Mipmapped Radiance Environment Map - * (PMREM) from a cubeMap environment texture. This allows different levels of - * blur to be quickly accessed based on material roughness. It is packed into a - * special CubeUV format that allows us to perform custom interpolation so that - * we can support nonlinear formats such as RGBE. Unlike a traditional mipmap - * chain, it only goes down to the LOD_MIN level (above), and then creates extra - * even more filtered 'mips' at the same LOD_MIN resolution, associated with - * higher roughness levels. In this way we maintain resolution to smoothly - * interpolate diffuse lighting while limiting sampling computation. - * - * Paper: Fast, Accurate Image-Based Lighting - * https://drive.google.com/file/d/15y8r_UpKlU9SvV4ILb0C3qCPecS8pvLz/view -*/ - -class PMREMGenerator { - - constructor( renderer ) { - - this._renderer = renderer; - this._pingPongRenderTarget = null; - - this._lodMax = 0; - this._cubeSize = 0; - this._lodPlanes = []; - this._sizeLods = []; - this._sigmas = []; - - this._blurMaterial = null; - this._cubemapMaterial = null; - this._equirectMaterial = null; - - this._compileMaterial( this._blurMaterial ); - - } - - /** - * Generates a PMREM from a supplied Scene, which can be faster than using an - * image if networking bandwidth is low. Optional sigma specifies a blur radius - * in radians to be applied to the scene before PMREM generation. Optional near - * and far planes ensure the scene is rendered in its entirety (the cubeCamera - * is placed at the origin). - */ - fromScene( scene, sigma = 0, near = 0.1, far = 100 ) { - - _oldTarget = this._renderer.getRenderTarget(); - _oldActiveCubeFace = this._renderer.getActiveCubeFace(); - _oldActiveMipmapLevel = this._renderer.getActiveMipmapLevel(); - - this._setSize( 256 ); - - const cubeUVRenderTarget = this._allocateTargets(); - cubeUVRenderTarget.depthBuffer = true; - - this._sceneToCubeUV( scene, near, far, cubeUVRenderTarget ); - - if ( sigma > 0 ) { - - this._blur( cubeUVRenderTarget, 0, 0, sigma ); - - } - - this._applyPMREM( cubeUVRenderTarget ); - this._cleanup( cubeUVRenderTarget ); - - return cubeUVRenderTarget; - - } - - /** - * Generates a PMREM from an equirectangular texture, which can be either LDR - * or HDR. The ideal input image size is 1k (1024 x 512), - * as this matches best with the 256 x 256 cubemap output. - */ - fromEquirectangular( equirectangular, renderTarget = null ) { - - return this._fromTexture( equirectangular, renderTarget ); - - } - - /** - * Generates a PMREM from an cubemap texture, which can be either LDR - * or HDR. The ideal input cube size is 256 x 256, - * as this matches best with the 256 x 256 cubemap output. - */ - fromCubemap( cubemap, renderTarget = null ) { - - return this._fromTexture( cubemap, renderTarget ); - - } - - /** - * Pre-compiles the cubemap shader. You can get faster start-up by invoking this method during - * your texture's network fetch for increased concurrency. - */ - compileCubemapShader() { - - if ( this._cubemapMaterial === null ) { - - this._cubemapMaterial = _getCubemapMaterial(); - this._compileMaterial( this._cubemapMaterial ); - - } - - } - - /** - * Pre-compiles the equirectangular shader. You can get faster start-up by invoking this method during - * your texture's network fetch for increased concurrency. - */ - compileEquirectangularShader() { - - if ( this._equirectMaterial === null ) { - - this._equirectMaterial = _getEquirectMaterial(); - this._compileMaterial( this._equirectMaterial ); - - } - - } - - /** - * Disposes of the PMREMGenerator's internal memory. Note that PMREMGenerator is a static class, - * so you should not need more than one PMREMGenerator object. If you do, calling dispose() on - * one of them will cause any others to also become unusable. - */ - dispose() { - - this._dispose(); - - if ( this._cubemapMaterial !== null ) this._cubemapMaterial.dispose(); - if ( this._equirectMaterial !== null ) this._equirectMaterial.dispose(); - - } - - // private interface - - _setSize( cubeSize ) { - - this._lodMax = Math.floor( Math.log2( cubeSize ) ); - this._cubeSize = Math.pow( 2, this._lodMax ); - - } - - _dispose() { - - if ( this._blurMaterial !== null ) this._blurMaterial.dispose(); - - if ( this._pingPongRenderTarget !== null ) this._pingPongRenderTarget.dispose(); - - for ( let i = 0; i < this._lodPlanes.length; i ++ ) { - - this._lodPlanes[ i ].dispose(); - - } - - } - - _cleanup( outputTarget ) { - - this._renderer.setRenderTarget( _oldTarget, _oldActiveCubeFace, _oldActiveMipmapLevel ); - outputTarget.scissorTest = false; - _setViewport( outputTarget, 0, 0, outputTarget.width, outputTarget.height ); - - } - - _fromTexture( texture, renderTarget ) { - - if ( texture.mapping === CubeReflectionMapping || texture.mapping === CubeRefractionMapping ) { - - this._setSize( texture.image.length === 0 ? 16 : ( texture.image[ 0 ].width || texture.image[ 0 ].image.width ) ); - - } else { // Equirectangular - - this._setSize( texture.image.width / 4 ); - - } - - _oldTarget = this._renderer.getRenderTarget(); - _oldActiveCubeFace = this._renderer.getActiveCubeFace(); - _oldActiveMipmapLevel = this._renderer.getActiveMipmapLevel(); - - const cubeUVRenderTarget = renderTarget || this._allocateTargets(); - this._textureToCubeUV( texture, cubeUVRenderTarget ); - this._applyPMREM( cubeUVRenderTarget ); - this._cleanup( cubeUVRenderTarget ); - - return cubeUVRenderTarget; - - } - - _allocateTargets() { - - const width = 3 * Math.max( this._cubeSize, 16 * 7 ); - const height = 4 * this._cubeSize; - - const params = { - magFilter: LinearFilter, - minFilter: LinearFilter, - generateMipmaps: false, - type: HalfFloatType, - format: RGBAFormat, - colorSpace: LinearSRGBColorSpace, - depthBuffer: false - }; - - const cubeUVRenderTarget = _createRenderTarget( width, height, params ); - - if ( this._pingPongRenderTarget === null || this._pingPongRenderTarget.width !== width || this._pingPongRenderTarget.height !== height ) { - - if ( this._pingPongRenderTarget !== null ) { - - this._dispose(); - - } - - this._pingPongRenderTarget = _createRenderTarget( width, height, params ); - - const { _lodMax } = this; - ( { sizeLods: this._sizeLods, lodPlanes: this._lodPlanes, sigmas: this._sigmas } = _createPlanes( _lodMax ) ); - - this._blurMaterial = _getBlurShader( _lodMax, width, height ); - - } - - return cubeUVRenderTarget; - - } - - _compileMaterial( material ) { - - const tmpMesh = new Mesh( this._lodPlanes[ 0 ], material ); - this._renderer.compile( tmpMesh, _flatCamera ); - - } - - _sceneToCubeUV( scene, near, far, cubeUVRenderTarget ) { - - const fov = 90; - const aspect = 1; - const cubeCamera = new PerspectiveCamera( fov, aspect, near, far ); - const upSign = [ 1, - 1, 1, 1, 1, 1 ]; - const forwardSign = [ 1, 1, 1, - 1, - 1, - 1 ]; - const renderer = this._renderer; - - const originalAutoClear = renderer.autoClear; - const toneMapping = renderer.toneMapping; - renderer.getClearColor( _clearColor ); - - renderer.toneMapping = NoToneMapping; - renderer.autoClear = false; - - const backgroundMaterial = new MeshBasicMaterial( { - name: 'PMREM.Background', - side: BackSide, - depthWrite: false, - depthTest: false, - } ); - - const backgroundBox = new Mesh( new BoxGeometry(), backgroundMaterial ); - - let useSolidColor = false; - const background = scene.background; - - if ( background ) { - - if ( background.isColor ) { - - backgroundMaterial.color.copy( background ); - scene.background = null; - useSolidColor = true; - - } - - } else { - - backgroundMaterial.color.copy( _clearColor ); - useSolidColor = true; - - } - - for ( let i = 0; i < 6; i ++ ) { - - const col = i % 3; - - if ( col === 0 ) { - - cubeCamera.up.set( 0, upSign[ i ], 0 ); - cubeCamera.lookAt( forwardSign[ i ], 0, 0 ); - - } else if ( col === 1 ) { - - cubeCamera.up.set( 0, 0, upSign[ i ] ); - cubeCamera.lookAt( 0, forwardSign[ i ], 0 ); - - } else { - - cubeCamera.up.set( 0, upSign[ i ], 0 ); - cubeCamera.lookAt( 0, 0, forwardSign[ i ] ); - - } - - const size = this._cubeSize; - - _setViewport( cubeUVRenderTarget, col * size, i > 2 ? size : 0, size, size ); - - renderer.setRenderTarget( cubeUVRenderTarget ); - - if ( useSolidColor ) { - - renderer.render( backgroundBox, cubeCamera ); - - } - - renderer.render( scene, cubeCamera ); - - } - - backgroundBox.geometry.dispose(); - backgroundBox.material.dispose(); - - renderer.toneMapping = toneMapping; - renderer.autoClear = originalAutoClear; - scene.background = background; - - } - - _textureToCubeUV( texture, cubeUVRenderTarget ) { - - const renderer = this._renderer; - - const isCubeTexture = ( texture.mapping === CubeReflectionMapping || texture.mapping === CubeRefractionMapping ); - - if ( isCubeTexture ) { - - if ( this._cubemapMaterial === null ) { - - this._cubemapMaterial = _getCubemapMaterial(); - - } - - this._cubemapMaterial.uniforms.flipEnvMap.value = ( texture.isRenderTargetTexture === false ) ? - 1 : 1; - - } else { - - if ( this._equirectMaterial === null ) { - - this._equirectMaterial = _getEquirectMaterial(); - - } - - } - - const material = isCubeTexture ? this._cubemapMaterial : this._equirectMaterial; - const mesh = new Mesh( this._lodPlanes[ 0 ], material ); - - const uniforms = material.uniforms; - - uniforms[ 'envMap' ].value = texture; - - const size = this._cubeSize; - - _setViewport( cubeUVRenderTarget, 0, 0, 3 * size, 2 * size ); - - renderer.setRenderTarget( cubeUVRenderTarget ); - renderer.render( mesh, _flatCamera ); - - } - - _applyPMREM( cubeUVRenderTarget ) { - - const renderer = this._renderer; - const autoClear = renderer.autoClear; - renderer.autoClear = false; - - for ( let i = 1; i < this._lodPlanes.length; i ++ ) { - - const sigma = Math.sqrt( this._sigmas[ i ] * this._sigmas[ i ] - this._sigmas[ i - 1 ] * this._sigmas[ i - 1 ] ); - - const poleAxis = _axisDirections[ ( i - 1 ) % _axisDirections.length ]; - - this._blur( cubeUVRenderTarget, i - 1, i, sigma, poleAxis ); - - } - - renderer.autoClear = autoClear; - - } - - /** - * This is a two-pass Gaussian blur for a cubemap. Normally this is done - * vertically and horizontally, but this breaks down on a cube. Here we apply - * the blur latitudinally (around the poles), and then longitudinally (towards - * the poles) to approximate the orthogonally-separable blur. It is least - * accurate at the poles, but still does a decent job. - */ - _blur( cubeUVRenderTarget, lodIn, lodOut, sigma, poleAxis ) { - - const pingPongRenderTarget = this._pingPongRenderTarget; - - this._halfBlur( - cubeUVRenderTarget, - pingPongRenderTarget, - lodIn, - lodOut, - sigma, - 'latitudinal', - poleAxis ); - - this._halfBlur( - pingPongRenderTarget, - cubeUVRenderTarget, - lodOut, - lodOut, - sigma, - 'longitudinal', - poleAxis ); - - } - - _halfBlur( targetIn, targetOut, lodIn, lodOut, sigmaRadians, direction, poleAxis ) { - - const renderer = this._renderer; - const blurMaterial = this._blurMaterial; - - if ( direction !== 'latitudinal' && direction !== 'longitudinal' ) { - - console.error( - 'blur direction must be either latitudinal or longitudinal!' ); - - } - - // Number of standard deviations at which to cut off the discrete approximation. - const STANDARD_DEVIATIONS = 3; - - const blurMesh = new Mesh( this._lodPlanes[ lodOut ], blurMaterial ); - const blurUniforms = blurMaterial.uniforms; - - const pixels = this._sizeLods[ lodIn ] - 1; - const radiansPerPixel = isFinite( sigmaRadians ) ? Math.PI / ( 2 * pixels ) : 2 * Math.PI / ( 2 * MAX_SAMPLES - 1 ); - const sigmaPixels = sigmaRadians / radiansPerPixel; - const samples = isFinite( sigmaRadians ) ? 1 + Math.floor( STANDARD_DEVIATIONS * sigmaPixels ) : MAX_SAMPLES; - - if ( samples > MAX_SAMPLES ) { - - console.warn( `sigmaRadians, ${ - sigmaRadians}, is too large and will clip, as it requested ${ - samples} samples when the maximum is set to ${MAX_SAMPLES}` ); - - } - - const weights = []; - let sum = 0; - - for ( let i = 0; i < MAX_SAMPLES; ++ i ) { - - const x = i / sigmaPixels; - const weight = Math.exp( - x * x / 2 ); - weights.push( weight ); - - if ( i === 0 ) { - - sum += weight; - - } else if ( i < samples ) { - - sum += 2 * weight; - - } - - } - - for ( let i = 0; i < weights.length; i ++ ) { - - weights[ i ] = weights[ i ] / sum; - - } - - blurUniforms[ 'envMap' ].value = targetIn.texture; - blurUniforms[ 'samples' ].value = samples; - blurUniforms[ 'weights' ].value = weights; - blurUniforms[ 'latitudinal' ].value = direction === 'latitudinal'; - - if ( poleAxis ) { - - blurUniforms[ 'poleAxis' ].value = poleAxis; - - } - - const { _lodMax } = this; - blurUniforms[ 'dTheta' ].value = radiansPerPixel; - blurUniforms[ 'mipInt' ].value = _lodMax - lodIn; - - const outputSize = this._sizeLods[ lodOut ]; - const x = 3 * outputSize * ( lodOut > _lodMax - LOD_MIN ? lodOut - _lodMax + LOD_MIN : 0 ); - const y = 4 * ( this._cubeSize - outputSize ); - - _setViewport( targetOut, x, y, 3 * outputSize, 2 * outputSize ); - renderer.setRenderTarget( targetOut ); - renderer.render( blurMesh, _flatCamera ); - - } - -} - - - -function _createPlanes( lodMax ) { - - const lodPlanes = []; - const sizeLods = []; - const sigmas = []; - - let lod = lodMax; - - const totalLods = lodMax - LOD_MIN + 1 + EXTRA_LOD_SIGMA.length; - - for ( let i = 0; i < totalLods; i ++ ) { - - const sizeLod = Math.pow( 2, lod ); - sizeLods.push( sizeLod ); - let sigma = 1.0 / sizeLod; - - if ( i > lodMax - LOD_MIN ) { - - sigma = EXTRA_LOD_SIGMA[ i - lodMax + LOD_MIN - 1 ]; - - } else if ( i === 0 ) { - - sigma = 0; - - } - - sigmas.push( sigma ); - - const texelSize = 1.0 / ( sizeLod - 2 ); - const min = - texelSize; - const max = 1 + texelSize; - const uv1 = [ min, min, max, min, max, max, min, min, max, max, min, max ]; - - const cubeFaces = 6; - const vertices = 6; - const positionSize = 3; - const uvSize = 2; - const faceIndexSize = 1; - - const position = new Float32Array( positionSize * vertices * cubeFaces ); - const uv = new Float32Array( uvSize * vertices * cubeFaces ); - const faceIndex = new Float32Array( faceIndexSize * vertices * cubeFaces ); - - for ( let face = 0; face < cubeFaces; face ++ ) { - - const x = ( face % 3 ) * 2 / 3 - 1; - const y = face > 2 ? 0 : - 1; - const coordinates = [ - x, y, 0, - x + 2 / 3, y, 0, - x + 2 / 3, y + 1, 0, - x, y, 0, - x + 2 / 3, y + 1, 0, - x, y + 1, 0 - ]; - position.set( coordinates, positionSize * vertices * face ); - uv.set( uv1, uvSize * vertices * face ); - const fill = [ face, face, face, face, face, face ]; - faceIndex.set( fill, faceIndexSize * vertices * face ); - - } - - const planes = new BufferGeometry(); - planes.setAttribute( 'position', new BufferAttribute( position, positionSize ) ); - planes.setAttribute( 'uv', new BufferAttribute( uv, uvSize ) ); - planes.setAttribute( 'faceIndex', new BufferAttribute( faceIndex, faceIndexSize ) ); - lodPlanes.push( planes ); - - if ( lod > LOD_MIN ) { - - lod --; - - } - - } - - return { lodPlanes, sizeLods, sigmas }; - -} - -function _createRenderTarget( width, height, params ) { - - const cubeUVRenderTarget = new WebGLRenderTarget( width, height, params ); - cubeUVRenderTarget.texture.mapping = CubeUVReflectionMapping; - cubeUVRenderTarget.texture.name = 'PMREM.cubeUv'; - cubeUVRenderTarget.scissorTest = true; - return cubeUVRenderTarget; - -} - -function _setViewport( target, x, y, width, height ) { - - target.viewport.set( x, y, width, height ); - target.scissor.set( x, y, width, height ); - -} - -function _getBlurShader( lodMax, width, height ) { - - const weights = new Float32Array( MAX_SAMPLES ); - const poleAxis = new Vector3( 0, 1, 0 ); - const shaderMaterial = new ShaderMaterial( { - - name: 'SphericalGaussianBlur', - - defines: { - 'n': MAX_SAMPLES, - 'CUBEUV_TEXEL_WIDTH': 1.0 / width, - 'CUBEUV_TEXEL_HEIGHT': 1.0 / height, - 'CUBEUV_MAX_MIP': `${lodMax}.0`, - }, - - uniforms: { - 'envMap': { value: null }, - 'samples': { value: 1 }, - 'weights': { value: weights }, - 'latitudinal': { value: false }, - 'dTheta': { value: 0 }, - 'mipInt': { value: 0 }, - 'poleAxis': { value: poleAxis } - }, - - vertexShader: _getCommonVertexShader(), - - fragmentShader: /* glsl */` - - precision mediump float; - precision mediump int; - - varying vec3 vOutputDirection; - - uniform sampler2D envMap; - uniform int samples; - uniform float weights[ n ]; - uniform bool latitudinal; - uniform float dTheta; - uniform float mipInt; - uniform vec3 poleAxis; - - #define ENVMAP_TYPE_CUBE_UV - #include - - vec3 getSample( float theta, vec3 axis ) { - - float cosTheta = cos( theta ); - // Rodrigues' axis-angle rotation - vec3 sampleDirection = vOutputDirection * cosTheta - + cross( axis, vOutputDirection ) * sin( theta ) - + axis * dot( axis, vOutputDirection ) * ( 1.0 - cosTheta ); - - return bilinearCubeUV( envMap, sampleDirection, mipInt ); - - } - - void main() { - - vec3 axis = latitudinal ? poleAxis : cross( poleAxis, vOutputDirection ); - - if ( all( equal( axis, vec3( 0.0 ) ) ) ) { - - axis = vec3( vOutputDirection.z, 0.0, - vOutputDirection.x ); - - } - - axis = normalize( axis ); - - gl_FragColor = vec4( 0.0, 0.0, 0.0, 1.0 ); - gl_FragColor.rgb += weights[ 0 ] * getSample( 0.0, axis ); - - for ( int i = 1; i < n; i++ ) { - - if ( i >= samples ) { - - break; - - } - - float theta = dTheta * float( i ); - gl_FragColor.rgb += weights[ i ] * getSample( -1.0 * theta, axis ); - gl_FragColor.rgb += weights[ i ] * getSample( theta, axis ); - - } - - } - `, - - blending: NoBlending, - depthTest: false, - depthWrite: false - - } ); - - return shaderMaterial; - -} - -function _getEquirectMaterial() { - - return new ShaderMaterial( { - - name: 'EquirectangularToCubeUV', - - uniforms: { - 'envMap': { value: null } - }, - - vertexShader: _getCommonVertexShader(), - - fragmentShader: /* glsl */` - - precision mediump float; - precision mediump int; - - varying vec3 vOutputDirection; - - uniform sampler2D envMap; - - #include - - void main() { - - vec3 outputDirection = normalize( vOutputDirection ); - vec2 uv = equirectUv( outputDirection ); - - gl_FragColor = vec4( texture2D ( envMap, uv ).rgb, 1.0 ); - - } - `, - - blending: NoBlending, - depthTest: false, - depthWrite: false - - } ); - -} - -function _getCubemapMaterial() { - - return new ShaderMaterial( { - - name: 'CubemapToCubeUV', - - uniforms: { - 'envMap': { value: null }, - 'flipEnvMap': { value: - 1 } - }, - - vertexShader: _getCommonVertexShader(), - - fragmentShader: /* glsl */` - - precision mediump float; - precision mediump int; - - uniform float flipEnvMap; - - varying vec3 vOutputDirection; - - uniform samplerCube envMap; - - void main() { - - gl_FragColor = textureCube( envMap, vec3( flipEnvMap * vOutputDirection.x, vOutputDirection.yz ) ); - - } - `, - - blending: NoBlending, - depthTest: false, - depthWrite: false - - } ); - -} - -function _getCommonVertexShader() { - - return /* glsl */` - - precision mediump float; - precision mediump int; - - attribute float faceIndex; - - varying vec3 vOutputDirection; - - // RH coordinate system; PMREM face-indexing convention - vec3 getDirection( vec2 uv, float face ) { - - uv = 2.0 * uv - 1.0; - - vec3 direction = vec3( uv, 1.0 ); - - if ( face == 0.0 ) { - - direction = direction.zyx; // ( 1, v, u ) pos x - - } else if ( face == 1.0 ) { - - direction = direction.xzy; - direction.xz *= -1.0; // ( -u, 1, -v ) pos y - - } else if ( face == 2.0 ) { - - direction.x *= -1.0; // ( -u, v, 1 ) pos z - - } else if ( face == 3.0 ) { - - direction = direction.zyx; - direction.xz *= -1.0; // ( -1, v, -u ) neg x - - } else if ( face == 4.0 ) { - - direction = direction.xzy; - direction.xy *= -1.0; // ( -u, -1, v ) neg y - - } else if ( face == 5.0 ) { - - direction.z *= -1.0; // ( u, v, -1 ) neg z - - } - - return direction; - - } - - void main() { - - vOutputDirection = getDirection( uv, faceIndex ); - gl_Position = vec4( position, 1.0 ); - - } - `; - -} - -function WebGLCubeUVMaps( renderer ) { - - let cubeUVmaps = new WeakMap(); - - let pmremGenerator = null; - - function get( texture ) { - - if ( texture && texture.isTexture ) { - - const mapping = texture.mapping; - - const isEquirectMap = ( mapping === EquirectangularReflectionMapping || mapping === EquirectangularRefractionMapping ); - const isCubeMap = ( mapping === CubeReflectionMapping || mapping === CubeRefractionMapping ); - - // equirect/cube map to cubeUV conversion - - if ( isEquirectMap || isCubeMap ) { - - if ( texture.isRenderTargetTexture && texture.needsPMREMUpdate === true ) { - - texture.needsPMREMUpdate = false; - - let renderTarget = cubeUVmaps.get( texture ); - - if ( pmremGenerator === null ) pmremGenerator = new PMREMGenerator( renderer ); - - renderTarget = isEquirectMap ? pmremGenerator.fromEquirectangular( texture, renderTarget ) : pmremGenerator.fromCubemap( texture, renderTarget ); - cubeUVmaps.set( texture, renderTarget ); - - return renderTarget.texture; - - } else { - - if ( cubeUVmaps.has( texture ) ) { - - return cubeUVmaps.get( texture ).texture; - - } else { - - const image = texture.image; - - if ( ( isEquirectMap && image && image.height > 0 ) || ( isCubeMap && image && isCubeTextureComplete( image ) ) ) { - - if ( pmremGenerator === null ) pmremGenerator = new PMREMGenerator( renderer ); - - const renderTarget = isEquirectMap ? pmremGenerator.fromEquirectangular( texture ) : pmremGenerator.fromCubemap( texture ); - cubeUVmaps.set( texture, renderTarget ); - - texture.addEventListener( 'dispose', onTextureDispose ); - - return renderTarget.texture; - - } else { - - // image not yet ready. try the conversion next frame - - return null; - - } - - } - - } - - } - - } - - return texture; - - } - - function isCubeTextureComplete( image ) { - - let count = 0; - const length = 6; - - for ( let i = 0; i < length; i ++ ) { - - if ( image[ i ] !== undefined ) count ++; - - } - - return count === length; - - - } - - function onTextureDispose( event ) { - - const texture = event.target; - - texture.removeEventListener( 'dispose', onTextureDispose ); - - const cubemapUV = cubeUVmaps.get( texture ); - - if ( cubemapUV !== undefined ) { - - cubeUVmaps.delete( texture ); - cubemapUV.dispose(); - - } - - } - - function dispose() { - - cubeUVmaps = new WeakMap(); - - if ( pmremGenerator !== null ) { - - pmremGenerator.dispose(); - pmremGenerator = null; - - } - - } - - return { - get: get, - dispose: dispose - }; - -} - -function WebGLExtensions( gl ) { - - const extensions = {}; - - function getExtension( name ) { - - if ( extensions[ name ] !== undefined ) { - - return extensions[ name ]; - - } - - let extension; - - switch ( name ) { - - case 'WEBGL_depth_texture': - extension = gl.getExtension( 'WEBGL_depth_texture' ) || gl.getExtension( 'MOZ_WEBGL_depth_texture' ) || gl.getExtension( 'WEBKIT_WEBGL_depth_texture' ); - break; - - case 'EXT_texture_filter_anisotropic': - extension = gl.getExtension( 'EXT_texture_filter_anisotropic' ) || gl.getExtension( 'MOZ_EXT_texture_filter_anisotropic' ) || gl.getExtension( 'WEBKIT_EXT_texture_filter_anisotropic' ); - break; - - case 'WEBGL_compressed_texture_s3tc': - extension = gl.getExtension( 'WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'MOZ_WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_s3tc' ); - break; - - case 'WEBGL_compressed_texture_pvrtc': - extension = gl.getExtension( 'WEBGL_compressed_texture_pvrtc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_pvrtc' ); - break; - - default: - extension = gl.getExtension( name ); - - } - - extensions[ name ] = extension; - - return extension; - - } - - return { - - has: function ( name ) { - - return getExtension( name ) !== null; - - }, - - init: function ( capabilities ) { - - if ( capabilities.isWebGL2 ) { - - getExtension( 'EXT_color_buffer_float' ); - getExtension( 'WEBGL_clip_cull_distance' ); - - } else { - - getExtension( 'WEBGL_depth_texture' ); - getExtension( 'OES_texture_float' ); - getExtension( 'OES_texture_half_float' ); - getExtension( 'OES_texture_half_float_linear' ); - getExtension( 'OES_standard_derivatives' ); - getExtension( 'OES_element_index_uint' ); - getExtension( 'OES_vertex_array_object' ); - getExtension( 'ANGLE_instanced_arrays' ); - - } - - getExtension( 'OES_texture_float_linear' ); - getExtension( 'EXT_color_buffer_half_float' ); - getExtension( 'WEBGL_multisampled_render_to_texture' ); - - }, - - get: function ( name ) { - - const extension = getExtension( name ); - - if ( extension === null ) { - - console.warn( 'THREE.WebGLRenderer: ' + name + ' extension not supported.' ); - - } - - return extension; - - } - - }; - -} - -function WebGLGeometries( gl, attributes, info, bindingStates ) { - - const geometries = {}; - const wireframeAttributes = new WeakMap(); - - function onGeometryDispose( event ) { - - const geometry = event.target; - - if ( geometry.index !== null ) { - - attributes.remove( geometry.index ); - - } - - for ( const name in geometry.attributes ) { - - attributes.remove( geometry.attributes[ name ] ); - - } - - for ( const name in geometry.morphAttributes ) { - - const array = geometry.morphAttributes[ name ]; - - for ( let i = 0, l = array.length; i < l; i ++ ) { - - attributes.remove( array[ i ] ); - - } - - } - - geometry.removeEventListener( 'dispose', onGeometryDispose ); - - delete geometries[ geometry.id ]; - - const attribute = wireframeAttributes.get( geometry ); - - if ( attribute ) { - - attributes.remove( attribute ); - wireframeAttributes.delete( geometry ); - - } - - bindingStates.releaseStatesOfGeometry( geometry ); - - if ( geometry.isInstancedBufferGeometry === true ) { - - delete geometry._maxInstanceCount; - - } - - // - - info.memory.geometries --; - - } - - function get( object, geometry ) { - - if ( geometries[ geometry.id ] === true ) return geometry; - - geometry.addEventListener( 'dispose', onGeometryDispose ); - - geometries[ geometry.id ] = true; - - info.memory.geometries ++; - - return geometry; - - } - - function update( geometry ) { - - const geometryAttributes = geometry.attributes; - - // Updating index buffer in VAO now. See WebGLBindingStates. - - for ( const name in geometryAttributes ) { - - attributes.update( geometryAttributes[ name ], gl.ARRAY_BUFFER ); - - } - - // morph targets - - const morphAttributes = geometry.morphAttributes; - - for ( const name in morphAttributes ) { - - const array = morphAttributes[ name ]; - - for ( let i = 0, l = array.length; i < l; i ++ ) { - - attributes.update( array[ i ], gl.ARRAY_BUFFER ); - - } - - } - - } - - function updateWireframeAttribute( geometry ) { - - const indices = []; - - const geometryIndex = geometry.index; - const geometryPosition = geometry.attributes.position; - let version = 0; - - if ( geometryIndex !== null ) { - - const array = geometryIndex.array; - version = geometryIndex.version; - - for ( let i = 0, l = array.length; i < l; i += 3 ) { - - const a = array[ i + 0 ]; - const b = array[ i + 1 ]; - const c = array[ i + 2 ]; - - indices.push( a, b, b, c, c, a ); - - } - - } else if ( geometryPosition !== undefined ) { - - const array = geometryPosition.array; - version = geometryPosition.version; - - for ( let i = 0, l = ( array.length / 3 ) - 1; i < l; i += 3 ) { - - const a = i + 0; - const b = i + 1; - const c = i + 2; - - indices.push( a, b, b, c, c, a ); - - } - - } else { - - return; - - } - - const attribute = new ( arrayNeedsUint32( indices ) ? Uint32BufferAttribute : Uint16BufferAttribute )( indices, 1 ); - attribute.version = version; - - // Updating index buffer in VAO now. See WebGLBindingStates - - // - - const previousAttribute = wireframeAttributes.get( geometry ); - - if ( previousAttribute ) attributes.remove( previousAttribute ); - - // - - wireframeAttributes.set( geometry, attribute ); - - } - - function getWireframeAttribute( geometry ) { - - const currentAttribute = wireframeAttributes.get( geometry ); - - if ( currentAttribute ) { - - const geometryIndex = geometry.index; - - if ( geometryIndex !== null ) { - - // if the attribute is obsolete, create a new one - - if ( currentAttribute.version < geometryIndex.version ) { - - updateWireframeAttribute( geometry ); - - } - - } - - } else { - - updateWireframeAttribute( geometry ); - - } - - return wireframeAttributes.get( geometry ); - - } - - return { - - get: get, - update: update, - - getWireframeAttribute: getWireframeAttribute - - }; - -} - -function WebGLIndexedBufferRenderer( gl, extensions, info, capabilities ) { - - const isWebGL2 = capabilities.isWebGL2; - - let mode; - - function setMode( value ) { - - mode = value; - - } - - let type, bytesPerElement; - - function setIndex( value ) { - - type = value.type; - bytesPerElement = value.bytesPerElement; - - } - - function render( start, count ) { - - gl.drawElements( mode, count, type, start * bytesPerElement ); - - info.update( count, mode, 1 ); - - } - - function renderInstances( start, count, primcount ) { - - if ( primcount === 0 ) return; - - let extension, methodName; - - if ( isWebGL2 ) { - - extension = gl; - methodName = 'drawElementsInstanced'; - - } else { - - extension = extensions.get( 'ANGLE_instanced_arrays' ); - methodName = 'drawElementsInstancedANGLE'; - - if ( extension === null ) { - - console.error( 'THREE.WebGLIndexedBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' ); - return; - - } - - } - - extension[ methodName ]( mode, count, type, start * bytesPerElement, primcount ); - - info.update( count, mode, primcount ); - - } - - function renderMultiDraw( starts, counts, drawCount ) { - - if ( drawCount === 0 ) return; - - const extension = extensions.get( 'WEBGL_multi_draw' ); - if ( extension === null ) { - - for ( let i = 0; i < drawCount; i ++ ) { - - this.render( starts[ i ] / bytesPerElement, counts[ i ] ); - - } - - } else { - - extension.multiDrawElementsWEBGL( mode, counts, 0, type, starts, 0, drawCount ); - - let elementCount = 0; - for ( let i = 0; i < drawCount; i ++ ) { - - elementCount += counts[ i ]; - - } - - info.update( elementCount, mode, 1 ); - - } - - } - - // - - this.setMode = setMode; - this.setIndex = setIndex; - this.render = render; - this.renderInstances = renderInstances; - this.renderMultiDraw = renderMultiDraw; - -} - -function WebGLInfo( gl ) { - - const memory = { - geometries: 0, - textures: 0 - }; - - const render = { - frame: 0, - calls: 0, - triangles: 0, - points: 0, - lines: 0 - }; - - function update( count, mode, instanceCount ) { - - render.calls ++; - - switch ( mode ) { - - case gl.TRIANGLES: - render.triangles += instanceCount * ( count / 3 ); - break; - - case gl.LINES: - render.lines += instanceCount * ( count / 2 ); - break; - - case gl.LINE_STRIP: - render.lines += instanceCount * ( count - 1 ); - break; - - case gl.LINE_LOOP: - render.lines += instanceCount * count; - break; - - case gl.POINTS: - render.points += instanceCount * count; - break; - - default: - console.error( 'THREE.WebGLInfo: Unknown draw mode:', mode ); - break; - - } - - } - - function reset() { - - render.calls = 0; - render.triangles = 0; - render.points = 0; - render.lines = 0; - - } - - return { - memory: memory, - render: render, - programs: null, - autoReset: true, - reset: reset, - update: update - }; - -} - -function numericalSort( a, b ) { - - return a[ 0 ] - b[ 0 ]; - -} - -function absNumericalSort( a, b ) { - - return Math.abs( b[ 1 ] ) - Math.abs( a[ 1 ] ); - -} - -function WebGLMorphtargets( gl, capabilities, textures ) { - - const influencesList = {}; - const morphInfluences = new Float32Array( 8 ); - const morphTextures = new WeakMap(); - const morph = new Vector4(); - - const workInfluences = []; - - for ( let i = 0; i < 8; i ++ ) { - - workInfluences[ i ] = [ i, 0 ]; - - } - - function update( object, geometry, program ) { - - const objectInfluences = object.morphTargetInfluences; - - if ( capabilities.isWebGL2 === true ) { - - // instead of using attributes, the WebGL 2 code path encodes morph targets - // into an array of data textures. Each layer represents a single morph target. - - const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color; - const morphTargetsCount = ( morphAttribute !== undefined ) ? morphAttribute.length : 0; - - let entry = morphTextures.get( geometry ); - - if ( entry === undefined || entry.count !== morphTargetsCount ) { - - if ( entry !== undefined ) entry.texture.dispose(); - - const hasMorphPosition = geometry.morphAttributes.position !== undefined; - const hasMorphNormals = geometry.morphAttributes.normal !== undefined; - const hasMorphColors = geometry.morphAttributes.color !== undefined; - - const morphTargets = geometry.morphAttributes.position || []; - const morphNormals = geometry.morphAttributes.normal || []; - const morphColors = geometry.morphAttributes.color || []; - - let vertexDataCount = 0; - - if ( hasMorphPosition === true ) vertexDataCount = 1; - if ( hasMorphNormals === true ) vertexDataCount = 2; - if ( hasMorphColors === true ) vertexDataCount = 3; - - let width = geometry.attributes.position.count * vertexDataCount; - let height = 1; - - if ( width > capabilities.maxTextureSize ) { - - height = Math.ceil( width / capabilities.maxTextureSize ); - width = capabilities.maxTextureSize; - - } - - const buffer = new Float32Array( width * height * 4 * morphTargetsCount ); - - const texture = new DataArrayTexture( buffer, width, height, morphTargetsCount ); - texture.type = FloatType; - texture.needsUpdate = true; - - // fill buffer - - const vertexDataStride = vertexDataCount * 4; - - for ( let i = 0; i < morphTargetsCount; i ++ ) { - - const morphTarget = morphTargets[ i ]; - const morphNormal = morphNormals[ i ]; - const morphColor = morphColors[ i ]; - - const offset = width * height * 4 * i; - - for ( let j = 0; j < morphTarget.count; j ++ ) { - - const stride = j * vertexDataStride; - - if ( hasMorphPosition === true ) { - - morph.fromBufferAttribute( morphTarget, j ); - - buffer[ offset + stride + 0 ] = morph.x; - buffer[ offset + stride + 1 ] = morph.y; - buffer[ offset + stride + 2 ] = morph.z; - buffer[ offset + stride + 3 ] = 0; - - } - - if ( hasMorphNormals === true ) { - - morph.fromBufferAttribute( morphNormal, j ); - - buffer[ offset + stride + 4 ] = morph.x; - buffer[ offset + stride + 5 ] = morph.y; - buffer[ offset + stride + 6 ] = morph.z; - buffer[ offset + stride + 7 ] = 0; - - } - - if ( hasMorphColors === true ) { - - morph.fromBufferAttribute( morphColor, j ); - - buffer[ offset + stride + 8 ] = morph.x; - buffer[ offset + stride + 9 ] = morph.y; - buffer[ offset + stride + 10 ] = morph.z; - buffer[ offset + stride + 11 ] = ( morphColor.itemSize === 4 ) ? morph.w : 1; - - } - - } - - } - - entry = { - count: morphTargetsCount, - texture: texture, - size: new Vector2( width, height ) - }; - - morphTextures.set( geometry, entry ); - - function disposeTexture() { - - texture.dispose(); - - morphTextures.delete( geometry ); - - geometry.removeEventListener( 'dispose', disposeTexture ); - - } - - geometry.addEventListener( 'dispose', disposeTexture ); - - } - - // - - let morphInfluencesSum = 0; - - for ( let i = 0; i < objectInfluences.length; i ++ ) { - - morphInfluencesSum += objectInfluences[ i ]; - - } - - const morphBaseInfluence = geometry.morphTargetsRelative ? 1 : 1 - morphInfluencesSum; - - program.getUniforms().setValue( gl, 'morphTargetBaseInfluence', morphBaseInfluence ); - program.getUniforms().setValue( gl, 'morphTargetInfluences', objectInfluences ); - - program.getUniforms().setValue( gl, 'morphTargetsTexture', entry.texture, textures ); - program.getUniforms().setValue( gl, 'morphTargetsTextureSize', entry.size ); - - - } else { - - // When object doesn't have morph target influences defined, we treat it as a 0-length array - // This is important to make sure we set up morphTargetBaseInfluence / morphTargetInfluences - - const length = objectInfluences === undefined ? 0 : objectInfluences.length; - - let influences = influencesList[ geometry.id ]; - - if ( influences === undefined || influences.length !== length ) { - - // initialise list - - influences = []; - - for ( let i = 0; i < length; i ++ ) { - - influences[ i ] = [ i, 0 ]; - - } - - influencesList[ geometry.id ] = influences; - - } - - // Collect influences - - for ( let i = 0; i < length; i ++ ) { - - const influence = influences[ i ]; - - influence[ 0 ] = i; - influence[ 1 ] = objectInfluences[ i ]; - - } - - influences.sort( absNumericalSort ); - - for ( let i = 0; i < 8; i ++ ) { - - if ( i < length && influences[ i ][ 1 ] ) { - - workInfluences[ i ][ 0 ] = influences[ i ][ 0 ]; - workInfluences[ i ][ 1 ] = influences[ i ][ 1 ]; - - } else { - - workInfluences[ i ][ 0 ] = Number.MAX_SAFE_INTEGER; - workInfluences[ i ][ 1 ] = 0; - - } - - } - - workInfluences.sort( numericalSort ); - - const morphTargets = geometry.morphAttributes.position; - const morphNormals = geometry.morphAttributes.normal; - - let morphInfluencesSum = 0; - - for ( let i = 0; i < 8; i ++ ) { - - const influence = workInfluences[ i ]; - const index = influence[ 0 ]; - const value = influence[ 1 ]; - - if ( index !== Number.MAX_SAFE_INTEGER && value ) { - - if ( morphTargets && geometry.getAttribute( 'morphTarget' + i ) !== morphTargets[ index ] ) { - - geometry.setAttribute( 'morphTarget' + i, morphTargets[ index ] ); - - } - - if ( morphNormals && geometry.getAttribute( 'morphNormal' + i ) !== morphNormals[ index ] ) { - - geometry.setAttribute( 'morphNormal' + i, morphNormals[ index ] ); - - } - - morphInfluences[ i ] = value; - morphInfluencesSum += value; - - } else { - - if ( morphTargets && geometry.hasAttribute( 'morphTarget' + i ) === true ) { - - geometry.deleteAttribute( 'morphTarget' + i ); - - } - - if ( morphNormals && geometry.hasAttribute( 'morphNormal' + i ) === true ) { - - geometry.deleteAttribute( 'morphNormal' + i ); - - } - - morphInfluences[ i ] = 0; - - } - - } - - // GLSL shader uses formula baseinfluence * base + sum(target * influence) - // This allows us to switch between absolute morphs and relative morphs without changing shader code - // When baseinfluence = 1 - sum(influence), the above is equivalent to sum((target - base) * influence) - const morphBaseInfluence = geometry.morphTargetsRelative ? 1 : 1 - morphInfluencesSum; - - program.getUniforms().setValue( gl, 'morphTargetBaseInfluence', morphBaseInfluence ); - program.getUniforms().setValue( gl, 'morphTargetInfluences', morphInfluences ); - - } - - } - - return { - - update: update - - }; - -} - -function WebGLObjects( gl, geometries, attributes, info ) { - - let updateMap = new WeakMap(); - - function update( object ) { - - const frame = info.render.frame; - - const geometry = object.geometry; - const buffergeometry = geometries.get( object, geometry ); - - // Update once per frame - - if ( updateMap.get( buffergeometry ) !== frame ) { - - geometries.update( buffergeometry ); - - updateMap.set( buffergeometry, frame ); - - } - - if ( object.isInstancedMesh ) { - - if ( object.hasEventListener( 'dispose', onInstancedMeshDispose ) === false ) { - - object.addEventListener( 'dispose', onInstancedMeshDispose ); - - } - - if ( updateMap.get( object ) !== frame ) { - - attributes.update( object.instanceMatrix, gl.ARRAY_BUFFER ); - - if ( object.instanceColor !== null ) { - - attributes.update( object.instanceColor, gl.ARRAY_BUFFER ); - - } - - updateMap.set( object, frame ); - - } - - } - - if ( object.isSkinnedMesh ) { - - const skeleton = object.skeleton; - - if ( updateMap.get( skeleton ) !== frame ) { - - skeleton.update(); - - updateMap.set( skeleton, frame ); - - } - - } - - return buffergeometry; - - } - - function dispose() { - - updateMap = new WeakMap(); - - } - - function onInstancedMeshDispose( event ) { - - const instancedMesh = event.target; - - instancedMesh.removeEventListener( 'dispose', onInstancedMeshDispose ); - - attributes.remove( instancedMesh.instanceMatrix ); - - if ( instancedMesh.instanceColor !== null ) attributes.remove( instancedMesh.instanceColor ); - - } - - return { - - update: update, - dispose: dispose - - }; - -} - -class DepthTexture extends Texture { - - constructor( width, height, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, format ) { - - format = format !== undefined ? format : DepthFormat; - - if ( format !== DepthFormat && format !== DepthStencilFormat ) { - - throw new Error( 'DepthTexture format must be either THREE.DepthFormat or THREE.DepthStencilFormat' ); - - } - - if ( type === undefined && format === DepthFormat ) type = UnsignedIntType; - if ( type === undefined && format === DepthStencilFormat ) type = UnsignedInt248Type; - - super( null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); - - this.isDepthTexture = true; - - this.image = { width: width, height: height }; - - this.magFilter = magFilter !== undefined ? magFilter : NearestFilter; - this.minFilter = minFilter !== undefined ? minFilter : NearestFilter; - - this.flipY = false; - this.generateMipmaps = false; - - this.compareFunction = null; - - } - - - copy( source ) { - - super.copy( source ); - - this.compareFunction = source.compareFunction; - - return this; - - } - - toJSON( meta ) { - - const data = super.toJSON( meta ); - - if ( this.compareFunction !== null ) data.compareFunction = this.compareFunction; - - return data; - - } - -} - -/** - * Uniforms of a program. - * Those form a tree structure with a special top-level container for the root, - * which you get by calling 'new WebGLUniforms( gl, program )'. - * - * - * Properties of inner nodes including the top-level container: - * - * .seq - array of nested uniforms - * .map - nested uniforms by name - * - * - * Methods of all nodes except the top-level container: - * - * .setValue( gl, value, [textures] ) - * - * uploads a uniform value(s) - * the 'textures' parameter is needed for sampler uniforms - * - * - * Static methods of the top-level container (textures factorizations): - * - * .upload( gl, seq, values, textures ) - * - * sets uniforms in 'seq' to 'values[id].value' - * - * .seqWithValue( seq, values ) : filteredSeq - * - * filters 'seq' entries with corresponding entry in values - * - * - * Methods of the top-level container (textures factorizations): - * - * .setValue( gl, name, value, textures ) - * - * sets uniform with name 'name' to 'value' - * - * .setOptional( gl, obj, prop ) - * - * like .set for an optional property of the object - * - */ - - -const emptyTexture = /*@__PURE__*/ new Texture(); - -const emptyShadowTexture = /*@__PURE__*/ new DepthTexture( 1, 1 ); -emptyShadowTexture.compareFunction = LessEqualCompare; - -const emptyArrayTexture = /*@__PURE__*/ new DataArrayTexture(); -const empty3dTexture = /*@__PURE__*/ new Data3DTexture(); -const emptyCubeTexture = /*@__PURE__*/ new CubeTexture(); - -// --- Utilities --- - -// Array Caches (provide typed arrays for temporary by size) - -const arrayCacheF32 = []; -const arrayCacheI32 = []; - -// Float32Array caches used for uploading Matrix uniforms - -const mat4array = new Float32Array( 16 ); -const mat3array = new Float32Array( 9 ); -const mat2array = new Float32Array( 4 ); - -// Flattening for arrays of vectors and matrices - -function flatten( array, nBlocks, blockSize ) { - - const firstElem = array[ 0 ]; - - if ( firstElem <= 0 || firstElem > 0 ) return array; - // unoptimized: ! isNaN( firstElem ) - // see http://jacksondunstan.com/articles/983 - - const n = nBlocks * blockSize; - let r = arrayCacheF32[ n ]; - - if ( r === undefined ) { - - r = new Float32Array( n ); - arrayCacheF32[ n ] = r; - - } - - if ( nBlocks !== 0 ) { - - firstElem.toArray( r, 0 ); - - for ( let i = 1, offset = 0; i !== nBlocks; ++ i ) { - - offset += blockSize; - array[ i ].toArray( r, offset ); - - } - - } - - return r; - -} - -function arraysEqual( a, b ) { - - if ( a.length !== b.length ) return false; - - for ( let i = 0, l = a.length; i < l; i ++ ) { - - if ( a[ i ] !== b[ i ] ) return false; - - } - - return true; - -} - -function copyArray( a, b ) { - - for ( let i = 0, l = b.length; i < l; i ++ ) { - - a[ i ] = b[ i ]; - - } - -} - -// Texture unit allocation - -function allocTexUnits( textures, n ) { - - let r = arrayCacheI32[ n ]; - - if ( r === undefined ) { - - r = new Int32Array( n ); - arrayCacheI32[ n ] = r; - - } - - for ( let i = 0; i !== n; ++ i ) { - - r[ i ] = textures.allocateTextureUnit(); - - } - - return r; - -} - -// --- Setters --- - -// Note: Defining these methods externally, because they come in a bunch -// and this way their names minify. - -// Single scalar - -function setValueV1f( gl, v ) { - - const cache = this.cache; - - if ( cache[ 0 ] === v ) return; - - gl.uniform1f( this.addr, v ); - - cache[ 0 ] = v; - -} - -// Single float vector (from flat array or THREE.VectorN) - -function setValueV2f( gl, v ) { - - const cache = this.cache; - - if ( v.x !== undefined ) { - - if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y ) { - - gl.uniform2f( this.addr, v.x, v.y ); - - cache[ 0 ] = v.x; - cache[ 1 ] = v.y; - - } - - } else { - - if ( arraysEqual( cache, v ) ) return; - - gl.uniform2fv( this.addr, v ); - - copyArray( cache, v ); - - } - -} - -function setValueV3f( gl, v ) { - - const cache = this.cache; - - if ( v.x !== undefined ) { - - if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z ) { - - gl.uniform3f( this.addr, v.x, v.y, v.z ); - - cache[ 0 ] = v.x; - cache[ 1 ] = v.y; - cache[ 2 ] = v.z; - - } - - } else if ( v.r !== undefined ) { - - if ( cache[ 0 ] !== v.r || cache[ 1 ] !== v.g || cache[ 2 ] !== v.b ) { - - gl.uniform3f( this.addr, v.r, v.g, v.b ); - - cache[ 0 ] = v.r; - cache[ 1 ] = v.g; - cache[ 2 ] = v.b; - - } - - } else { - - if ( arraysEqual( cache, v ) ) return; - - gl.uniform3fv( this.addr, v ); - - copyArray( cache, v ); - - } - -} - -function setValueV4f( gl, v ) { - - const cache = this.cache; - - if ( v.x !== undefined ) { - - if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z || cache[ 3 ] !== v.w ) { - - gl.uniform4f( this.addr, v.x, v.y, v.z, v.w ); - - cache[ 0 ] = v.x; - cache[ 1 ] = v.y; - cache[ 2 ] = v.z; - cache[ 3 ] = v.w; - - } - - } else { - - if ( arraysEqual( cache, v ) ) return; - - gl.uniform4fv( this.addr, v ); - - copyArray( cache, v ); - - } - -} - -// Single matrix (from flat array or THREE.MatrixN) - -function setValueM2( gl, v ) { - - const cache = this.cache; - const elements = v.elements; - - if ( elements === undefined ) { - - if ( arraysEqual( cache, v ) ) return; - - gl.uniformMatrix2fv( this.addr, false, v ); - - copyArray( cache, v ); - - } else { - - if ( arraysEqual( cache, elements ) ) return; - - mat2array.set( elements ); - - gl.uniformMatrix2fv( this.addr, false, mat2array ); - - copyArray( cache, elements ); - - } - -} - -function setValueM3( gl, v ) { - - const cache = this.cache; - const elements = v.elements; - - if ( elements === undefined ) { - - if ( arraysEqual( cache, v ) ) return; - - gl.uniformMatrix3fv( this.addr, false, v ); - - copyArray( cache, v ); - - } else { - - if ( arraysEqual( cache, elements ) ) return; - - mat3array.set( elements ); - - gl.uniformMatrix3fv( this.addr, false, mat3array ); - - copyArray( cache, elements ); - - } - -} - -function setValueM4( gl, v ) { - - const cache = this.cache; - const elements = v.elements; - - if ( elements === undefined ) { - - if ( arraysEqual( cache, v ) ) return; - - gl.uniformMatrix4fv( this.addr, false, v ); - - copyArray( cache, v ); - - } else { - - if ( arraysEqual( cache, elements ) ) return; - - mat4array.set( elements ); - - gl.uniformMatrix4fv( this.addr, false, mat4array ); - - copyArray( cache, elements ); - - } - -} - -// Single integer / boolean - -function setValueV1i( gl, v ) { - - const cache = this.cache; - - if ( cache[ 0 ] === v ) return; - - gl.uniform1i( this.addr, v ); - - cache[ 0 ] = v; - -} - -// Single integer / boolean vector (from flat array or THREE.VectorN) - -function setValueV2i( gl, v ) { - - const cache = this.cache; - - if ( v.x !== undefined ) { - - if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y ) { - - gl.uniform2i( this.addr, v.x, v.y ); - - cache[ 0 ] = v.x; - cache[ 1 ] = v.y; - - } - - } else { - - if ( arraysEqual( cache, v ) ) return; - - gl.uniform2iv( this.addr, v ); - - copyArray( cache, v ); - - } - -} - -function setValueV3i( gl, v ) { - - const cache = this.cache; - - if ( v.x !== undefined ) { - - if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z ) { - - gl.uniform3i( this.addr, v.x, v.y, v.z ); - - cache[ 0 ] = v.x; - cache[ 1 ] = v.y; - cache[ 2 ] = v.z; - - } - - } else { - - if ( arraysEqual( cache, v ) ) return; - - gl.uniform3iv( this.addr, v ); - - copyArray( cache, v ); - - } - -} - -function setValueV4i( gl, v ) { - - const cache = this.cache; - - if ( v.x !== undefined ) { - - if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z || cache[ 3 ] !== v.w ) { - - gl.uniform4i( this.addr, v.x, v.y, v.z, v.w ); - - cache[ 0 ] = v.x; - cache[ 1 ] = v.y; - cache[ 2 ] = v.z; - cache[ 3 ] = v.w; - - } - - } else { - - if ( arraysEqual( cache, v ) ) return; - - gl.uniform4iv( this.addr, v ); - - copyArray( cache, v ); - - } - -} - -// Single unsigned integer - -function setValueV1ui( gl, v ) { - - const cache = this.cache; - - if ( cache[ 0 ] === v ) return; - - gl.uniform1ui( this.addr, v ); - - cache[ 0 ] = v; - -} - -// Single unsigned integer vector (from flat array or THREE.VectorN) - -function setValueV2ui( gl, v ) { - - const cache = this.cache; - - if ( v.x !== undefined ) { - - if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y ) { - - gl.uniform2ui( this.addr, v.x, v.y ); - - cache[ 0 ] = v.x; - cache[ 1 ] = v.y; - - } - - } else { - - if ( arraysEqual( cache, v ) ) return; - - gl.uniform2uiv( this.addr, v ); - - copyArray( cache, v ); - - } - -} - -function setValueV3ui( gl, v ) { - - const cache = this.cache; - - if ( v.x !== undefined ) { - - if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z ) { - - gl.uniform3ui( this.addr, v.x, v.y, v.z ); - - cache[ 0 ] = v.x; - cache[ 1 ] = v.y; - cache[ 2 ] = v.z; - - } - - } else { - - if ( arraysEqual( cache, v ) ) return; - - gl.uniform3uiv( this.addr, v ); - - copyArray( cache, v ); - - } - -} - -function setValueV4ui( gl, v ) { - - const cache = this.cache; - - if ( v.x !== undefined ) { - - if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z || cache[ 3 ] !== v.w ) { - - gl.uniform4ui( this.addr, v.x, v.y, v.z, v.w ); - - cache[ 0 ] = v.x; - cache[ 1 ] = v.y; - cache[ 2 ] = v.z; - cache[ 3 ] = v.w; - - } - - } else { - - if ( arraysEqual( cache, v ) ) return; - - gl.uniform4uiv( this.addr, v ); - - copyArray( cache, v ); - - } - -} - - -// Single texture (2D / Cube) - -function setValueT1( gl, v, textures ) { - - const cache = this.cache; - const unit = textures.allocateTextureUnit(); - - if ( cache[ 0 ] !== unit ) { - - gl.uniform1i( this.addr, unit ); - cache[ 0 ] = unit; - - } - - const emptyTexture2D = ( this.type === gl.SAMPLER_2D_SHADOW ) ? emptyShadowTexture : emptyTexture; - - textures.setTexture2D( v || emptyTexture2D, unit ); - -} - -function setValueT3D1( gl, v, textures ) { - - const cache = this.cache; - const unit = textures.allocateTextureUnit(); - - if ( cache[ 0 ] !== unit ) { - - gl.uniform1i( this.addr, unit ); - cache[ 0 ] = unit; - - } - - textures.setTexture3D( v || empty3dTexture, unit ); - -} - -function setValueT6( gl, v, textures ) { - - const cache = this.cache; - const unit = textures.allocateTextureUnit(); - - if ( cache[ 0 ] !== unit ) { - - gl.uniform1i( this.addr, unit ); - cache[ 0 ] = unit; - - } - - textures.setTextureCube( v || emptyCubeTexture, unit ); - -} - -function setValueT2DArray1( gl, v, textures ) { - - const cache = this.cache; - const unit = textures.allocateTextureUnit(); - - if ( cache[ 0 ] !== unit ) { - - gl.uniform1i( this.addr, unit ); - cache[ 0 ] = unit; - - } - - textures.setTexture2DArray( v || emptyArrayTexture, unit ); - -} - -// Helper to pick the right setter for the singular case - -function getSingularSetter( type ) { - - switch ( type ) { - - case 0x1406: return setValueV1f; // FLOAT - case 0x8b50: return setValueV2f; // _VEC2 - case 0x8b51: return setValueV3f; // _VEC3 - case 0x8b52: return setValueV4f; // _VEC4 - - case 0x8b5a: return setValueM2; // _MAT2 - case 0x8b5b: return setValueM3; // _MAT3 - case 0x8b5c: return setValueM4; // _MAT4 - - case 0x1404: case 0x8b56: return setValueV1i; // INT, BOOL - case 0x8b53: case 0x8b57: return setValueV2i; // _VEC2 - case 0x8b54: case 0x8b58: return setValueV3i; // _VEC3 - case 0x8b55: case 0x8b59: return setValueV4i; // _VEC4 - - case 0x1405: return setValueV1ui; // UINT - case 0x8dc6: return setValueV2ui; // _VEC2 - case 0x8dc7: return setValueV3ui; // _VEC3 - case 0x8dc8: return setValueV4ui; // _VEC4 - - case 0x8b5e: // SAMPLER_2D - case 0x8d66: // SAMPLER_EXTERNAL_OES - case 0x8dca: // INT_SAMPLER_2D - case 0x8dd2: // UNSIGNED_INT_SAMPLER_2D - case 0x8b62: // SAMPLER_2D_SHADOW - return setValueT1; - - case 0x8b5f: // SAMPLER_3D - case 0x8dcb: // INT_SAMPLER_3D - case 0x8dd3: // UNSIGNED_INT_SAMPLER_3D - return setValueT3D1; - - case 0x8b60: // SAMPLER_CUBE - case 0x8dcc: // INT_SAMPLER_CUBE - case 0x8dd4: // UNSIGNED_INT_SAMPLER_CUBE - case 0x8dc5: // SAMPLER_CUBE_SHADOW - return setValueT6; - - case 0x8dc1: // SAMPLER_2D_ARRAY - case 0x8dcf: // INT_SAMPLER_2D_ARRAY - case 0x8dd7: // UNSIGNED_INT_SAMPLER_2D_ARRAY - case 0x8dc4: // SAMPLER_2D_ARRAY_SHADOW - return setValueT2DArray1; - - } - -} - - -// Array of scalars - -function setValueV1fArray( gl, v ) { - - gl.uniform1fv( this.addr, v ); - -} - -// Array of vectors (from flat array or array of THREE.VectorN) - -function setValueV2fArray( gl, v ) { - - const data = flatten( v, this.size, 2 ); - - gl.uniform2fv( this.addr, data ); - -} - -function setValueV3fArray( gl, v ) { - - const data = flatten( v, this.size, 3 ); - - gl.uniform3fv( this.addr, data ); - -} - -function setValueV4fArray( gl, v ) { - - const data = flatten( v, this.size, 4 ); - - gl.uniform4fv( this.addr, data ); - -} - -// Array of matrices (from flat array or array of THREE.MatrixN) - -function setValueM2Array( gl, v ) { - - const data = flatten( v, this.size, 4 ); - - gl.uniformMatrix2fv( this.addr, false, data ); - -} - -function setValueM3Array( gl, v ) { - - const data = flatten( v, this.size, 9 ); - - gl.uniformMatrix3fv( this.addr, false, data ); - -} - -function setValueM4Array( gl, v ) { - - const data = flatten( v, this.size, 16 ); - - gl.uniformMatrix4fv( this.addr, false, data ); - -} - -// Array of integer / boolean - -function setValueV1iArray( gl, v ) { - - gl.uniform1iv( this.addr, v ); - -} - -// Array of integer / boolean vectors (from flat array) - -function setValueV2iArray( gl, v ) { - - gl.uniform2iv( this.addr, v ); - -} - -function setValueV3iArray( gl, v ) { - - gl.uniform3iv( this.addr, v ); - -} - -function setValueV4iArray( gl, v ) { - - gl.uniform4iv( this.addr, v ); - -} - -// Array of unsigned integer - -function setValueV1uiArray( gl, v ) { - - gl.uniform1uiv( this.addr, v ); - -} - -// Array of unsigned integer vectors (from flat array) - -function setValueV2uiArray( gl, v ) { - - gl.uniform2uiv( this.addr, v ); - -} - -function setValueV3uiArray( gl, v ) { - - gl.uniform3uiv( this.addr, v ); - -} - -function setValueV4uiArray( gl, v ) { - - gl.uniform4uiv( this.addr, v ); - -} - - -// Array of textures (2D / 3D / Cube / 2DArray) - -function setValueT1Array( gl, v, textures ) { - - const cache = this.cache; - - const n = v.length; - - const units = allocTexUnits( textures, n ); - - if ( ! arraysEqual( cache, units ) ) { - - gl.uniform1iv( this.addr, units ); - - copyArray( cache, units ); - - } - - for ( let i = 0; i !== n; ++ i ) { - - textures.setTexture2D( v[ i ] || emptyTexture, units[ i ] ); - - } - -} - -function setValueT3DArray( gl, v, textures ) { - - const cache = this.cache; - - const n = v.length; - - const units = allocTexUnits( textures, n ); - - if ( ! arraysEqual( cache, units ) ) { - - gl.uniform1iv( this.addr, units ); - - copyArray( cache, units ); - - } - - for ( let i = 0; i !== n; ++ i ) { - - textures.setTexture3D( v[ i ] || empty3dTexture, units[ i ] ); - - } - -} - -function setValueT6Array( gl, v, textures ) { - - const cache = this.cache; - - const n = v.length; - - const units = allocTexUnits( textures, n ); - - if ( ! arraysEqual( cache, units ) ) { - - gl.uniform1iv( this.addr, units ); - - copyArray( cache, units ); - - } - - for ( let i = 0; i !== n; ++ i ) { - - textures.setTextureCube( v[ i ] || emptyCubeTexture, units[ i ] ); - - } - -} - -function setValueT2DArrayArray( gl, v, textures ) { - - const cache = this.cache; - - const n = v.length; - - const units = allocTexUnits( textures, n ); - - if ( ! arraysEqual( cache, units ) ) { - - gl.uniform1iv( this.addr, units ); - - copyArray( cache, units ); - - } - - for ( let i = 0; i !== n; ++ i ) { - - textures.setTexture2DArray( v[ i ] || emptyArrayTexture, units[ i ] ); - - } - -} - - -// Helper to pick the right setter for a pure (bottom-level) array - -function getPureArraySetter( type ) { - - switch ( type ) { - - case 0x1406: return setValueV1fArray; // FLOAT - case 0x8b50: return setValueV2fArray; // _VEC2 - case 0x8b51: return setValueV3fArray; // _VEC3 - case 0x8b52: return setValueV4fArray; // _VEC4 - - case 0x8b5a: return setValueM2Array; // _MAT2 - case 0x8b5b: return setValueM3Array; // _MAT3 - case 0x8b5c: return setValueM4Array; // _MAT4 - - case 0x1404: case 0x8b56: return setValueV1iArray; // INT, BOOL - case 0x8b53: case 0x8b57: return setValueV2iArray; // _VEC2 - case 0x8b54: case 0x8b58: return setValueV3iArray; // _VEC3 - case 0x8b55: case 0x8b59: return setValueV4iArray; // _VEC4 - - case 0x1405: return setValueV1uiArray; // UINT - case 0x8dc6: return setValueV2uiArray; // _VEC2 - case 0x8dc7: return setValueV3uiArray; // _VEC3 - case 0x8dc8: return setValueV4uiArray; // _VEC4 - - case 0x8b5e: // SAMPLER_2D - case 0x8d66: // SAMPLER_EXTERNAL_OES - case 0x8dca: // INT_SAMPLER_2D - case 0x8dd2: // UNSIGNED_INT_SAMPLER_2D - case 0x8b62: // SAMPLER_2D_SHADOW - return setValueT1Array; - - case 0x8b5f: // SAMPLER_3D - case 0x8dcb: // INT_SAMPLER_3D - case 0x8dd3: // UNSIGNED_INT_SAMPLER_3D - return setValueT3DArray; - - case 0x8b60: // SAMPLER_CUBE - case 0x8dcc: // INT_SAMPLER_CUBE - case 0x8dd4: // UNSIGNED_INT_SAMPLER_CUBE - case 0x8dc5: // SAMPLER_CUBE_SHADOW - return setValueT6Array; - - case 0x8dc1: // SAMPLER_2D_ARRAY - case 0x8dcf: // INT_SAMPLER_2D_ARRAY - case 0x8dd7: // UNSIGNED_INT_SAMPLER_2D_ARRAY - case 0x8dc4: // SAMPLER_2D_ARRAY_SHADOW - return setValueT2DArrayArray; - - } - -} - -// --- Uniform Classes --- - -class SingleUniform { - - constructor( id, activeInfo, addr ) { - - this.id = id; - this.addr = addr; - this.cache = []; - this.type = activeInfo.type; - this.setValue = getSingularSetter( activeInfo.type ); - - // this.path = activeInfo.name; // DEBUG - - } - -} - -class PureArrayUniform { - - constructor( id, activeInfo, addr ) { - - this.id = id; - this.addr = addr; - this.cache = []; - this.type = activeInfo.type; - this.size = activeInfo.size; - this.setValue = getPureArraySetter( activeInfo.type ); - - // this.path = activeInfo.name; // DEBUG - - } - -} - -class StructuredUniform { - - constructor( id ) { - - this.id = id; - - this.seq = []; - this.map = {}; - - } - - setValue( gl, value, textures ) { - - const seq = this.seq; - - for ( let i = 0, n = seq.length; i !== n; ++ i ) { - - const u = seq[ i ]; - u.setValue( gl, value[ u.id ], textures ); - - } - - } - -} - -// --- Top-level --- - -// Parser - builds up the property tree from the path strings - -const RePathPart = /(\w+)(\])?(\[|\.)?/g; - -// extracts -// - the identifier (member name or array index) -// - followed by an optional right bracket (found when array index) -// - followed by an optional left bracket or dot (type of subscript) -// -// Note: These portions can be read in a non-overlapping fashion and -// allow straightforward parsing of the hierarchy that WebGL encodes -// in the uniform names. - -function addUniform( container, uniformObject ) { - - container.seq.push( uniformObject ); - container.map[ uniformObject.id ] = uniformObject; - -} - -function parseUniform( activeInfo, addr, container ) { - - const path = activeInfo.name, - pathLength = path.length; - - // reset RegExp object, because of the early exit of a previous run - RePathPart.lastIndex = 0; - - while ( true ) { - - const match = RePathPart.exec( path ), - matchEnd = RePathPart.lastIndex; - - let id = match[ 1 ]; - const idIsIndex = match[ 2 ] === ']', - subscript = match[ 3 ]; - - if ( idIsIndex ) id = id | 0; // convert to integer - - if ( subscript === undefined || subscript === '[' && matchEnd + 2 === pathLength ) { - - // bare name or "pure" bottom-level array "[0]" suffix - - addUniform( container, subscript === undefined ? - new SingleUniform( id, activeInfo, addr ) : - new PureArrayUniform( id, activeInfo, addr ) ); - - break; - - } else { - - // step into inner node / create it in case it doesn't exist - - const map = container.map; - let next = map[ id ]; - - if ( next === undefined ) { - - next = new StructuredUniform( id ); - addUniform( container, next ); - - } - - container = next; - - } - - } - -} - -// Root Container - -class WebGLUniforms { - - constructor( gl, program ) { - - this.seq = []; - this.map = {}; - - const n = gl.getProgramParameter( program, gl.ACTIVE_UNIFORMS ); - - for ( let i = 0; i < n; ++ i ) { - - const info = gl.getActiveUniform( program, i ), - addr = gl.getUniformLocation( program, info.name ); - - parseUniform( info, addr, this ); - - } - - } - - setValue( gl, name, value, textures ) { - - const u = this.map[ name ]; - - if ( u !== undefined ) u.setValue( gl, value, textures ); - - } - - setOptional( gl, object, name ) { - - const v = object[ name ]; - - if ( v !== undefined ) this.setValue( gl, name, v ); - - } - - static upload( gl, seq, values, textures ) { - - for ( let i = 0, n = seq.length; i !== n; ++ i ) { - - const u = seq[ i ], - v = values[ u.id ]; - - if ( v.needsUpdate !== false ) { - - // note: always updating when .needsUpdate is undefined - u.setValue( gl, v.value, textures ); - - } - - } - - } - - static seqWithValue( seq, values ) { - - const r = []; - - for ( let i = 0, n = seq.length; i !== n; ++ i ) { - - const u = seq[ i ]; - if ( u.id in values ) r.push( u ); - - } - - return r; - - } - -} - -function WebGLShader( gl, type, string ) { - - const shader = gl.createShader( type ); - - gl.shaderSource( shader, string ); - gl.compileShader( shader ); - - return shader; - -} - -// From https://www.khronos.org/registry/webgl/extensions/KHR_parallel_shader_compile/ -const COMPLETION_STATUS_KHR = 0x91B1; - -let programIdCount = 0; - -function handleSource( string, errorLine ) { - - const lines = string.split( '\n' ); - const lines2 = []; - - const from = Math.max( errorLine - 6, 0 ); - const to = Math.min( errorLine + 6, lines.length ); - - for ( let i = from; i < to; i ++ ) { - - const line = i + 1; - lines2.push( `${line === errorLine ? '>' : ' '} ${line}: ${lines[ i ]}` ); - - } - - return lines2.join( '\n' ); - -} - -function getEncodingComponents( colorSpace ) { - - const workingPrimaries = ColorManagement.getPrimaries( ColorManagement.workingColorSpace ); - const encodingPrimaries = ColorManagement.getPrimaries( colorSpace ); - - let gamutMapping; - - if ( workingPrimaries === encodingPrimaries ) { - - gamutMapping = ''; - - } else if ( workingPrimaries === P3Primaries && encodingPrimaries === Rec709Primaries ) { - - gamutMapping = 'LinearDisplayP3ToLinearSRGB'; - - } else if ( workingPrimaries === Rec709Primaries && encodingPrimaries === P3Primaries ) { - - gamutMapping = 'LinearSRGBToLinearDisplayP3'; - - } - - switch ( colorSpace ) { - - case LinearSRGBColorSpace: - case LinearDisplayP3ColorSpace: - return [ gamutMapping, 'LinearTransferOETF' ]; - - case SRGBColorSpace: - case DisplayP3ColorSpace: - return [ gamutMapping, 'sRGBTransferOETF' ]; - - default: - console.warn( 'THREE.WebGLProgram: Unsupported color space:', colorSpace ); - return [ gamutMapping, 'LinearTransferOETF' ]; - - } - -} - -function getShaderErrors( gl, shader, type ) { - - const status = gl.getShaderParameter( shader, gl.COMPILE_STATUS ); - const errors = gl.getShaderInfoLog( shader ).trim(); - - if ( status && errors === '' ) return ''; - - const errorMatches = /ERROR: 0:(\d+)/.exec( errors ); - if ( errorMatches ) { - - // --enable-privileged-webgl-extension - // console.log( '**' + type + '**', gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( shader ) ); - - const errorLine = parseInt( errorMatches[ 1 ] ); - return type.toUpperCase() + '\n\n' + errors + '\n\n' + handleSource( gl.getShaderSource( shader ), errorLine ); - - } else { - - return errors; - - } - -} - -function getTexelEncodingFunction( functionName, colorSpace ) { - - const components = getEncodingComponents( colorSpace ); - return `vec4 ${functionName}( vec4 value ) { return ${components[ 0 ]}( ${components[ 1 ]}( value ) ); }`; - -} - -function getToneMappingFunction( functionName, toneMapping ) { - - let toneMappingName; - - switch ( toneMapping ) { - - case LinearToneMapping: - toneMappingName = 'Linear'; - break; - - case ReinhardToneMapping: - toneMappingName = 'Reinhard'; - break; - - case CineonToneMapping: - toneMappingName = 'OptimizedCineon'; - break; - - case ACESFilmicToneMapping: - toneMappingName = 'ACESFilmic'; - break; - - case AgXToneMapping: - toneMappingName = 'AgX'; - break; - - case CustomToneMapping: - toneMappingName = 'Custom'; - break; - - default: - console.warn( 'THREE.WebGLProgram: Unsupported toneMapping:', toneMapping ); - toneMappingName = 'Linear'; - - } - - return 'vec3 ' + functionName + '( vec3 color ) { return ' + toneMappingName + 'ToneMapping( color ); }'; - -} - -function generateExtensions( parameters ) { - - const chunks = [ - ( parameters.extensionDerivatives || !! parameters.envMapCubeUVHeight || parameters.bumpMap || parameters.normalMapTangentSpace || parameters.clearcoatNormalMap || parameters.flatShading || parameters.alphaToCoverage || parameters.shaderID === 'physical' ) ? '#extension GL_OES_standard_derivatives : enable' : '', - ( parameters.extensionFragDepth || parameters.logarithmicDepthBuffer ) && parameters.rendererExtensionFragDepth ? '#extension GL_EXT_frag_depth : enable' : '', - ( parameters.extensionDrawBuffers && parameters.rendererExtensionDrawBuffers ) ? '#extension GL_EXT_draw_buffers : require' : '', - ( parameters.extensionShaderTextureLOD || parameters.envMap || parameters.transmission ) && parameters.rendererExtensionShaderTextureLod ? '#extension GL_EXT_shader_texture_lod : enable' : '' - ]; - - return chunks.filter( filterEmptyLine ).join( '\n' ); - -} - -function generateVertexExtensions( parameters ) { - - const chunks = [ - parameters.extensionClipCullDistance ? '#extension GL_ANGLE_clip_cull_distance : require' : '', - parameters.extensionMultiDraw ? '#extension GL_ANGLE_multi_draw : require' : '', - ]; - - return chunks.filter( filterEmptyLine ).join( '\n' ); - -} - -function generateDefines( defines ) { - - const chunks = []; - - for ( const name in defines ) { - - const value = defines[ name ]; - - if ( value === false ) continue; - - chunks.push( '#define ' + name + ' ' + value ); - - } - - return chunks.join( '\n' ); - -} - -function fetchAttributeLocations( gl, program ) { - - const attributes = {}; - - const n = gl.getProgramParameter( program, gl.ACTIVE_ATTRIBUTES ); - - for ( let i = 0; i < n; i ++ ) { - - const info = gl.getActiveAttrib( program, i ); - const name = info.name; - - let locationSize = 1; - if ( info.type === gl.FLOAT_MAT2 ) locationSize = 2; - if ( info.type === gl.FLOAT_MAT3 ) locationSize = 3; - if ( info.type === gl.FLOAT_MAT4 ) locationSize = 4; - - // console.log( 'THREE.WebGLProgram: ACTIVE VERTEX ATTRIBUTE:', name, i ); - - attributes[ name ] = { - type: info.type, - location: gl.getAttribLocation( program, name ), - locationSize: locationSize - }; - - } - - return attributes; - -} - -function filterEmptyLine( string ) { - - return string !== ''; - -} - -function replaceLightNums( string, parameters ) { - - const numSpotLightCoords = parameters.numSpotLightShadows + parameters.numSpotLightMaps - parameters.numSpotLightShadowsWithMaps; - - return string - .replace( /NUM_DIR_LIGHTS/g, parameters.numDirLights ) - .replace( /NUM_SPOT_LIGHTS/g, parameters.numSpotLights ) - .replace( /NUM_SPOT_LIGHT_MAPS/g, parameters.numSpotLightMaps ) - .replace( /NUM_SPOT_LIGHT_COORDS/g, numSpotLightCoords ) - .replace( /NUM_RECT_AREA_LIGHTS/g, parameters.numRectAreaLights ) - .replace( /NUM_POINT_LIGHTS/g, parameters.numPointLights ) - .replace( /NUM_HEMI_LIGHTS/g, parameters.numHemiLights ) - .replace( /NUM_DIR_LIGHT_SHADOWS/g, parameters.numDirLightShadows ) - .replace( /NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS/g, parameters.numSpotLightShadowsWithMaps ) - .replace( /NUM_SPOT_LIGHT_SHADOWS/g, parameters.numSpotLightShadows ) - .replace( /NUM_POINT_LIGHT_SHADOWS/g, parameters.numPointLightShadows ); - -} - -function replaceClippingPlaneNums( string, parameters ) { - - return string - .replace( /NUM_CLIPPING_PLANES/g, parameters.numClippingPlanes ) - .replace( /UNION_CLIPPING_PLANES/g, ( parameters.numClippingPlanes - parameters.numClipIntersection ) ); - -} - -// Resolve Includes - -const includePattern = /^[ \t]*#include +<([\w\d./]+)>/gm; - -function resolveIncludes( string ) { - - return string.replace( includePattern, includeReplacer ); - -} - -const shaderChunkMap = new Map( [ - [ 'encodings_fragment', 'colorspace_fragment' ], // @deprecated, r154 - [ 'encodings_pars_fragment', 'colorspace_pars_fragment' ], // @deprecated, r154 - [ 'output_fragment', 'opaque_fragment' ], // @deprecated, r154 -] ); - -function includeReplacer( match, include ) { - - let string = ShaderChunk[ include ]; - - if ( string === undefined ) { - - const newInclude = shaderChunkMap.get( include ); - - if ( newInclude !== undefined ) { - - string = ShaderChunk[ newInclude ]; - console.warn( 'THREE.WebGLRenderer: Shader chunk "%s" has been deprecated. Use "%s" instead.', include, newInclude ); - - } else { - - throw new Error( 'Can not resolve #include <' + include + '>' ); - - } - - } - - return resolveIncludes( string ); - -} - -// Unroll Loops - -const unrollLoopPattern = /#pragma unroll_loop_start\s+for\s*\(\s*int\s+i\s*=\s*(\d+)\s*;\s*i\s*<\s*(\d+)\s*;\s*i\s*\+\+\s*\)\s*{([\s\S]+?)}\s+#pragma unroll_loop_end/g; - -function unrollLoops( string ) { - - return string.replace( unrollLoopPattern, loopReplacer ); - -} - -function loopReplacer( match, start, end, snippet ) { - - let string = ''; - - for ( let i = parseInt( start ); i < parseInt( end ); i ++ ) { - - string += snippet - .replace( /\[\s*i\s*\]/g, '[ ' + i + ' ]' ) - .replace( /UNROLLED_LOOP_INDEX/g, i ); - - } - - return string; - -} - -// - -function generatePrecision( parameters ) { - - let precisionstring = `precision ${parameters.precision} float; - precision ${parameters.precision} int; - precision ${parameters.precision} sampler2D; - precision ${parameters.precision} samplerCube; - `; - - if ( parameters.isWebGL2 ) { - - precisionstring += `precision ${parameters.precision} sampler3D; - precision ${parameters.precision} sampler2DArray; - precision ${parameters.precision} sampler2DShadow; - precision ${parameters.precision} samplerCubeShadow; - precision ${parameters.precision} sampler2DArrayShadow; - precision ${parameters.precision} isampler2D; - precision ${parameters.precision} isampler3D; - precision ${parameters.precision} isamplerCube; - precision ${parameters.precision} isampler2DArray; - precision ${parameters.precision} usampler2D; - precision ${parameters.precision} usampler3D; - precision ${parameters.precision} usamplerCube; - precision ${parameters.precision} usampler2DArray; - `; - - } - - if ( parameters.precision === 'highp' ) { - - precisionstring += '\n#define HIGH_PRECISION'; - - } else if ( parameters.precision === 'mediump' ) { - - precisionstring += '\n#define MEDIUM_PRECISION'; - - } else if ( parameters.precision === 'lowp' ) { - - precisionstring += '\n#define LOW_PRECISION'; - - } - - return precisionstring; - -} - -function generateShadowMapTypeDefine( parameters ) { - - let shadowMapTypeDefine = 'SHADOWMAP_TYPE_BASIC'; - - if ( parameters.shadowMapType === PCFShadowMap ) { - - shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF'; - - } else if ( parameters.shadowMapType === PCFSoftShadowMap ) { - - shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF_SOFT'; - - } else if ( parameters.shadowMapType === VSMShadowMap ) { - - shadowMapTypeDefine = 'SHADOWMAP_TYPE_VSM'; - - } - - return shadowMapTypeDefine; - -} - -function generateEnvMapTypeDefine( parameters ) { - - let envMapTypeDefine = 'ENVMAP_TYPE_CUBE'; - - if ( parameters.envMap ) { - - switch ( parameters.envMapMode ) { - - case CubeReflectionMapping: - case CubeRefractionMapping: - envMapTypeDefine = 'ENVMAP_TYPE_CUBE'; - break; - - case CubeUVReflectionMapping: - envMapTypeDefine = 'ENVMAP_TYPE_CUBE_UV'; - break; - - } - - } - - return envMapTypeDefine; - -} - -function generateEnvMapModeDefine( parameters ) { - - let envMapModeDefine = 'ENVMAP_MODE_REFLECTION'; - - if ( parameters.envMap ) { - - switch ( parameters.envMapMode ) { - - case CubeRefractionMapping: - - envMapModeDefine = 'ENVMAP_MODE_REFRACTION'; - break; - - } - - } - - return envMapModeDefine; - -} - -function generateEnvMapBlendingDefine( parameters ) { - - let envMapBlendingDefine = 'ENVMAP_BLENDING_NONE'; - - if ( parameters.envMap ) { - - switch ( parameters.combine ) { - - case MultiplyOperation: - envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY'; - break; - - case MixOperation: - envMapBlendingDefine = 'ENVMAP_BLENDING_MIX'; - break; - - case AddOperation: - envMapBlendingDefine = 'ENVMAP_BLENDING_ADD'; - break; - - } - - } - - return envMapBlendingDefine; - -} - -function generateCubeUVSize( parameters ) { - - const imageHeight = parameters.envMapCubeUVHeight; - - if ( imageHeight === null ) return null; - - const maxMip = Math.log2( imageHeight ) - 2; - - const texelHeight = 1.0 / imageHeight; - - const texelWidth = 1.0 / ( 3 * Math.max( Math.pow( 2, maxMip ), 7 * 16 ) ); - - return { texelWidth, texelHeight, maxMip }; - -} - -function WebGLProgram( renderer, cacheKey, parameters, bindingStates ) { - - // TODO Send this event to Three.js DevTools - // console.log( 'WebGLProgram', cacheKey ); - - const gl = renderer.getContext(); - - const defines = parameters.defines; - - let vertexShader = parameters.vertexShader; - let fragmentShader = parameters.fragmentShader; - - const shadowMapTypeDefine = generateShadowMapTypeDefine( parameters ); - const envMapTypeDefine = generateEnvMapTypeDefine( parameters ); - const envMapModeDefine = generateEnvMapModeDefine( parameters ); - const envMapBlendingDefine = generateEnvMapBlendingDefine( parameters ); - const envMapCubeUVSize = generateCubeUVSize( parameters ); - - const customExtensions = parameters.isWebGL2 ? '' : generateExtensions( parameters ); - - const customVertexExtensions = generateVertexExtensions( parameters ); - - const customDefines = generateDefines( defines ); - - const program = gl.createProgram(); - - let prefixVertex, prefixFragment; - let versionString = parameters.glslVersion ? '#version ' + parameters.glslVersion + '\n' : ''; - - if ( parameters.isRawShaderMaterial ) { - - prefixVertex = [ - - '#define SHADER_TYPE ' + parameters.shaderType, - '#define SHADER_NAME ' + parameters.shaderName, - - customDefines - - ].filter( filterEmptyLine ).join( '\n' ); - - if ( prefixVertex.length > 0 ) { - - prefixVertex += '\n'; - - } - - prefixFragment = [ - - customExtensions, - - '#define SHADER_TYPE ' + parameters.shaderType, - '#define SHADER_NAME ' + parameters.shaderName, - - customDefines - - ].filter( filterEmptyLine ).join( '\n' ); - - if ( prefixFragment.length > 0 ) { - - prefixFragment += '\n'; - - } - - } else { - - prefixVertex = [ - - generatePrecision( parameters ), - - '#define SHADER_TYPE ' + parameters.shaderType, - '#define SHADER_NAME ' + parameters.shaderName, - - customDefines, - - parameters.extensionClipCullDistance ? '#define USE_CLIP_DISTANCE' : '', - parameters.batching ? '#define USE_BATCHING' : '', - parameters.instancing ? '#define USE_INSTANCING' : '', - parameters.instancingColor ? '#define USE_INSTANCING_COLOR' : '', - - parameters.useFog && parameters.fog ? '#define USE_FOG' : '', - parameters.useFog && parameters.fogExp2 ? '#define FOG_EXP2' : '', - - parameters.map ? '#define USE_MAP' : '', - parameters.envMap ? '#define USE_ENVMAP' : '', - parameters.envMap ? '#define ' + envMapModeDefine : '', - parameters.lightMap ? '#define USE_LIGHTMAP' : '', - parameters.aoMap ? '#define USE_AOMAP' : '', - parameters.bumpMap ? '#define USE_BUMPMAP' : '', - parameters.normalMap ? '#define USE_NORMALMAP' : '', - parameters.normalMapObjectSpace ? '#define USE_NORMALMAP_OBJECTSPACE' : '', - parameters.normalMapTangentSpace ? '#define USE_NORMALMAP_TANGENTSPACE' : '', - parameters.displacementMap ? '#define USE_DISPLACEMENTMAP' : '', - parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '', - - parameters.anisotropy ? '#define USE_ANISOTROPY' : '', - parameters.anisotropyMap ? '#define USE_ANISOTROPYMAP' : '', - - parameters.clearcoatMap ? '#define USE_CLEARCOATMAP' : '', - parameters.clearcoatRoughnessMap ? '#define USE_CLEARCOAT_ROUGHNESSMAP' : '', - parameters.clearcoatNormalMap ? '#define USE_CLEARCOAT_NORMALMAP' : '', - - parameters.iridescenceMap ? '#define USE_IRIDESCENCEMAP' : '', - parameters.iridescenceThicknessMap ? '#define USE_IRIDESCENCE_THICKNESSMAP' : '', - - parameters.specularMap ? '#define USE_SPECULARMAP' : '', - parameters.specularColorMap ? '#define USE_SPECULAR_COLORMAP' : '', - parameters.specularIntensityMap ? '#define USE_SPECULAR_INTENSITYMAP' : '', - - parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '', - parameters.metalnessMap ? '#define USE_METALNESSMAP' : '', - parameters.alphaMap ? '#define USE_ALPHAMAP' : '', - parameters.alphaHash ? '#define USE_ALPHAHASH' : '', - - parameters.transmission ? '#define USE_TRANSMISSION' : '', - parameters.transmissionMap ? '#define USE_TRANSMISSIONMAP' : '', - parameters.thicknessMap ? '#define USE_THICKNESSMAP' : '', - - parameters.sheenColorMap ? '#define USE_SHEEN_COLORMAP' : '', - parameters.sheenRoughnessMap ? '#define USE_SHEEN_ROUGHNESSMAP' : '', - - // - - parameters.mapUv ? '#define MAP_UV ' + parameters.mapUv : '', - parameters.alphaMapUv ? '#define ALPHAMAP_UV ' + parameters.alphaMapUv : '', - parameters.lightMapUv ? '#define LIGHTMAP_UV ' + parameters.lightMapUv : '', - parameters.aoMapUv ? '#define AOMAP_UV ' + parameters.aoMapUv : '', - parameters.emissiveMapUv ? '#define EMISSIVEMAP_UV ' + parameters.emissiveMapUv : '', - parameters.bumpMapUv ? '#define BUMPMAP_UV ' + parameters.bumpMapUv : '', - parameters.normalMapUv ? '#define NORMALMAP_UV ' + parameters.normalMapUv : '', - parameters.displacementMapUv ? '#define DISPLACEMENTMAP_UV ' + parameters.displacementMapUv : '', - - parameters.metalnessMapUv ? '#define METALNESSMAP_UV ' + parameters.metalnessMapUv : '', - parameters.roughnessMapUv ? '#define ROUGHNESSMAP_UV ' + parameters.roughnessMapUv : '', - - parameters.anisotropyMapUv ? '#define ANISOTROPYMAP_UV ' + parameters.anisotropyMapUv : '', - - parameters.clearcoatMapUv ? '#define CLEARCOATMAP_UV ' + parameters.clearcoatMapUv : '', - parameters.clearcoatNormalMapUv ? '#define CLEARCOAT_NORMALMAP_UV ' + parameters.clearcoatNormalMapUv : '', - parameters.clearcoatRoughnessMapUv ? '#define CLEARCOAT_ROUGHNESSMAP_UV ' + parameters.clearcoatRoughnessMapUv : '', - - parameters.iridescenceMapUv ? '#define IRIDESCENCEMAP_UV ' + parameters.iridescenceMapUv : '', - parameters.iridescenceThicknessMapUv ? '#define IRIDESCENCE_THICKNESSMAP_UV ' + parameters.iridescenceThicknessMapUv : '', - - parameters.sheenColorMapUv ? '#define SHEEN_COLORMAP_UV ' + parameters.sheenColorMapUv : '', - parameters.sheenRoughnessMapUv ? '#define SHEEN_ROUGHNESSMAP_UV ' + parameters.sheenRoughnessMapUv : '', - - parameters.specularMapUv ? '#define SPECULARMAP_UV ' + parameters.specularMapUv : '', - parameters.specularColorMapUv ? '#define SPECULAR_COLORMAP_UV ' + parameters.specularColorMapUv : '', - parameters.specularIntensityMapUv ? '#define SPECULAR_INTENSITYMAP_UV ' + parameters.specularIntensityMapUv : '', - - parameters.transmissionMapUv ? '#define TRANSMISSIONMAP_UV ' + parameters.transmissionMapUv : '', - parameters.thicknessMapUv ? '#define THICKNESSMAP_UV ' + parameters.thicknessMapUv : '', - - // - - parameters.vertexTangents && parameters.flatShading === false ? '#define USE_TANGENT' : '', - parameters.vertexColors ? '#define USE_COLOR' : '', - parameters.vertexAlphas ? '#define USE_COLOR_ALPHA' : '', - parameters.vertexUv1s ? '#define USE_UV1' : '', - parameters.vertexUv2s ? '#define USE_UV2' : '', - parameters.vertexUv3s ? '#define USE_UV3' : '', - - parameters.pointsUvs ? '#define USE_POINTS_UV' : '', - - parameters.flatShading ? '#define FLAT_SHADED' : '', - - parameters.skinning ? '#define USE_SKINNING' : '', - - parameters.morphTargets ? '#define USE_MORPHTARGETS' : '', - parameters.morphNormals && parameters.flatShading === false ? '#define USE_MORPHNORMALS' : '', - ( parameters.morphColors && parameters.isWebGL2 ) ? '#define USE_MORPHCOLORS' : '', - ( parameters.morphTargetsCount > 0 && parameters.isWebGL2 ) ? '#define MORPHTARGETS_TEXTURE' : '', - ( parameters.morphTargetsCount > 0 && parameters.isWebGL2 ) ? '#define MORPHTARGETS_TEXTURE_STRIDE ' + parameters.morphTextureStride : '', - ( parameters.morphTargetsCount > 0 && parameters.isWebGL2 ) ? '#define MORPHTARGETS_COUNT ' + parameters.morphTargetsCount : '', - parameters.doubleSided ? '#define DOUBLE_SIDED' : '', - parameters.flipSided ? '#define FLIP_SIDED' : '', - - parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '', - parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '', - - parameters.sizeAttenuation ? '#define USE_SIZEATTENUATION' : '', - - parameters.numLightProbes > 0 ? '#define USE_LIGHT_PROBES' : '', - - parameters.useLegacyLights ? '#define LEGACY_LIGHTS' : '', - - parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '', - ( parameters.logarithmicDepthBuffer && parameters.rendererExtensionFragDepth ) ? '#define USE_LOGDEPTHBUF_EXT' : '', - - 'uniform mat4 modelMatrix;', - 'uniform mat4 modelViewMatrix;', - 'uniform mat4 projectionMatrix;', - 'uniform mat4 viewMatrix;', - 'uniform mat3 normalMatrix;', - 'uniform vec3 cameraPosition;', - 'uniform bool isOrthographic;', - - '#ifdef USE_INSTANCING', - - ' attribute mat4 instanceMatrix;', - - '#endif', - - '#ifdef USE_INSTANCING_COLOR', - - ' attribute vec3 instanceColor;', - - '#endif', - - 'attribute vec3 position;', - 'attribute vec3 normal;', - 'attribute vec2 uv;', - - '#ifdef USE_UV1', - - ' attribute vec2 uv1;', - - '#endif', - - '#ifdef USE_UV2', - - ' attribute vec2 uv2;', - - '#endif', - - '#ifdef USE_UV3', - - ' attribute vec2 uv3;', - - '#endif', - - '#ifdef USE_TANGENT', - - ' attribute vec4 tangent;', - - '#endif', - - '#if defined( USE_COLOR_ALPHA )', - - ' attribute vec4 color;', - - '#elif defined( USE_COLOR )', - - ' attribute vec3 color;', - - '#endif', - - '#if ( defined( USE_MORPHTARGETS ) && ! defined( MORPHTARGETS_TEXTURE ) )', - - ' attribute vec3 morphTarget0;', - ' attribute vec3 morphTarget1;', - ' attribute vec3 morphTarget2;', - ' attribute vec3 morphTarget3;', - - ' #ifdef USE_MORPHNORMALS', - - ' attribute vec3 morphNormal0;', - ' attribute vec3 morphNormal1;', - ' attribute vec3 morphNormal2;', - ' attribute vec3 morphNormal3;', - - ' #else', - - ' attribute vec3 morphTarget4;', - ' attribute vec3 morphTarget5;', - ' attribute vec3 morphTarget6;', - ' attribute vec3 morphTarget7;', - - ' #endif', - - '#endif', - - '#ifdef USE_SKINNING', - - ' attribute vec4 skinIndex;', - ' attribute vec4 skinWeight;', - - '#endif', - - '\n' - - ].filter( filterEmptyLine ).join( '\n' ); - - prefixFragment = [ - - customExtensions, - - generatePrecision( parameters ), - - '#define SHADER_TYPE ' + parameters.shaderType, - '#define SHADER_NAME ' + parameters.shaderName, - - customDefines, - - parameters.useFog && parameters.fog ? '#define USE_FOG' : '', - parameters.useFog && parameters.fogExp2 ? '#define FOG_EXP2' : '', - - parameters.alphaToCoverage ? '#define ALPHA_TO_COVERAGE' : '', - parameters.map ? '#define USE_MAP' : '', - parameters.matcap ? '#define USE_MATCAP' : '', - parameters.envMap ? '#define USE_ENVMAP' : '', - parameters.envMap ? '#define ' + envMapTypeDefine : '', - parameters.envMap ? '#define ' + envMapModeDefine : '', - parameters.envMap ? '#define ' + envMapBlendingDefine : '', - envMapCubeUVSize ? '#define CUBEUV_TEXEL_WIDTH ' + envMapCubeUVSize.texelWidth : '', - envMapCubeUVSize ? '#define CUBEUV_TEXEL_HEIGHT ' + envMapCubeUVSize.texelHeight : '', - envMapCubeUVSize ? '#define CUBEUV_MAX_MIP ' + envMapCubeUVSize.maxMip + '.0' : '', - parameters.lightMap ? '#define USE_LIGHTMAP' : '', - parameters.aoMap ? '#define USE_AOMAP' : '', - parameters.bumpMap ? '#define USE_BUMPMAP' : '', - parameters.normalMap ? '#define USE_NORMALMAP' : '', - parameters.normalMapObjectSpace ? '#define USE_NORMALMAP_OBJECTSPACE' : '', - parameters.normalMapTangentSpace ? '#define USE_NORMALMAP_TANGENTSPACE' : '', - parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '', - - parameters.anisotropy ? '#define USE_ANISOTROPY' : '', - parameters.anisotropyMap ? '#define USE_ANISOTROPYMAP' : '', - - parameters.clearcoat ? '#define USE_CLEARCOAT' : '', - parameters.clearcoatMap ? '#define USE_CLEARCOATMAP' : '', - parameters.clearcoatRoughnessMap ? '#define USE_CLEARCOAT_ROUGHNESSMAP' : '', - parameters.clearcoatNormalMap ? '#define USE_CLEARCOAT_NORMALMAP' : '', - - parameters.iridescence ? '#define USE_IRIDESCENCE' : '', - parameters.iridescenceMap ? '#define USE_IRIDESCENCEMAP' : '', - parameters.iridescenceThicknessMap ? '#define USE_IRIDESCENCE_THICKNESSMAP' : '', - - parameters.specularMap ? '#define USE_SPECULARMAP' : '', - parameters.specularColorMap ? '#define USE_SPECULAR_COLORMAP' : '', - parameters.specularIntensityMap ? '#define USE_SPECULAR_INTENSITYMAP' : '', - - parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '', - parameters.metalnessMap ? '#define USE_METALNESSMAP' : '', - - parameters.alphaMap ? '#define USE_ALPHAMAP' : '', - parameters.alphaTest ? '#define USE_ALPHATEST' : '', - parameters.alphaHash ? '#define USE_ALPHAHASH' : '', - - parameters.sheen ? '#define USE_SHEEN' : '', - parameters.sheenColorMap ? '#define USE_SHEEN_COLORMAP' : '', - parameters.sheenRoughnessMap ? '#define USE_SHEEN_ROUGHNESSMAP' : '', - - parameters.transmission ? '#define USE_TRANSMISSION' : '', - parameters.transmissionMap ? '#define USE_TRANSMISSIONMAP' : '', - parameters.thicknessMap ? '#define USE_THICKNESSMAP' : '', - - parameters.vertexTangents && parameters.flatShading === false ? '#define USE_TANGENT' : '', - parameters.vertexColors || parameters.instancingColor ? '#define USE_COLOR' : '', - parameters.vertexAlphas ? '#define USE_COLOR_ALPHA' : '', - parameters.vertexUv1s ? '#define USE_UV1' : '', - parameters.vertexUv2s ? '#define USE_UV2' : '', - parameters.vertexUv3s ? '#define USE_UV3' : '', - - parameters.pointsUvs ? '#define USE_POINTS_UV' : '', - - parameters.gradientMap ? '#define USE_GRADIENTMAP' : '', - - parameters.flatShading ? '#define FLAT_SHADED' : '', - - parameters.doubleSided ? '#define DOUBLE_SIDED' : '', - parameters.flipSided ? '#define FLIP_SIDED' : '', - - parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '', - parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '', - - parameters.premultipliedAlpha ? '#define PREMULTIPLIED_ALPHA' : '', - - parameters.numLightProbes > 0 ? '#define USE_LIGHT_PROBES' : '', - - parameters.useLegacyLights ? '#define LEGACY_LIGHTS' : '', - - parameters.decodeVideoTexture ? '#define DECODE_VIDEO_TEXTURE' : '', - - parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '', - ( parameters.logarithmicDepthBuffer && parameters.rendererExtensionFragDepth ) ? '#define USE_LOGDEPTHBUF_EXT' : '', - - 'uniform mat4 viewMatrix;', - 'uniform vec3 cameraPosition;', - 'uniform bool isOrthographic;', - - ( parameters.toneMapping !== NoToneMapping ) ? '#define TONE_MAPPING' : '', - ( parameters.toneMapping !== NoToneMapping ) ? ShaderChunk[ 'tonemapping_pars_fragment' ] : '', // this code is required here because it is used by the toneMapping() function defined below - ( parameters.toneMapping !== NoToneMapping ) ? getToneMappingFunction( 'toneMapping', parameters.toneMapping ) : '', - - parameters.dithering ? '#define DITHERING' : '', - parameters.opaque ? '#define OPAQUE' : '', - - ShaderChunk[ 'colorspace_pars_fragment' ], // this code is required here because it is used by the various encoding/decoding function defined below - getTexelEncodingFunction( 'linearToOutputTexel', parameters.outputColorSpace ), - - parameters.useDepthPacking ? '#define DEPTH_PACKING ' + parameters.depthPacking : '', - - '\n' - - ].filter( filterEmptyLine ).join( '\n' ); - - } - - vertexShader = resolveIncludes( vertexShader ); - vertexShader = replaceLightNums( vertexShader, parameters ); - vertexShader = replaceClippingPlaneNums( vertexShader, parameters ); - - fragmentShader = resolveIncludes( fragmentShader ); - fragmentShader = replaceLightNums( fragmentShader, parameters ); - fragmentShader = replaceClippingPlaneNums( fragmentShader, parameters ); - - vertexShader = unrollLoops( vertexShader ); - fragmentShader = unrollLoops( fragmentShader ); - - if ( parameters.isWebGL2 && parameters.isRawShaderMaterial !== true ) { - - // GLSL 3.0 conversion for built-in materials and ShaderMaterial - - versionString = '#version 300 es\n'; - - prefixVertex = [ - customVertexExtensions, - 'precision mediump sampler2DArray;', - '#define attribute in', - '#define varying out', - '#define texture2D texture' - ].join( '\n' ) + '\n' + prefixVertex; - - prefixFragment = [ - 'precision mediump sampler2DArray;', - '#define varying in', - ( parameters.glslVersion === GLSL3 ) ? '' : 'layout(location = 0) out highp vec4 pc_fragColor;', - ( parameters.glslVersion === GLSL3 ) ? '' : '#define gl_FragColor pc_fragColor', - '#define gl_FragDepthEXT gl_FragDepth', - '#define texture2D texture', - '#define textureCube texture', - '#define texture2DProj textureProj', - '#define texture2DLodEXT textureLod', - '#define texture2DProjLodEXT textureProjLod', - '#define textureCubeLodEXT textureLod', - '#define texture2DGradEXT textureGrad', - '#define texture2DProjGradEXT textureProjGrad', - '#define textureCubeGradEXT textureGrad' - ].join( '\n' ) + '\n' + prefixFragment; - - } - - const vertexGlsl = versionString + prefixVertex + vertexShader; - const fragmentGlsl = versionString + prefixFragment + fragmentShader; - - // console.log( '*VERTEX*', vertexGlsl ); - // console.log( '*FRAGMENT*', fragmentGlsl ); - - const glVertexShader = WebGLShader( gl, gl.VERTEX_SHADER, vertexGlsl ); - const glFragmentShader = WebGLShader( gl, gl.FRAGMENT_SHADER, fragmentGlsl ); - - gl.attachShader( program, glVertexShader ); - gl.attachShader( program, glFragmentShader ); - - // Force a particular attribute to index 0. - - if ( parameters.index0AttributeName !== undefined ) { - - gl.bindAttribLocation( program, 0, parameters.index0AttributeName ); - - } else if ( parameters.morphTargets === true ) { - - // programs with morphTargets displace position out of attribute 0 - gl.bindAttribLocation( program, 0, 'position' ); - - } - - gl.linkProgram( program ); - - function onFirstUse( self ) { - - // check for link errors - if ( renderer.debug.checkShaderErrors ) { - - const programLog = gl.getProgramInfoLog( program ).trim(); - const vertexLog = gl.getShaderInfoLog( glVertexShader ).trim(); - const fragmentLog = gl.getShaderInfoLog( glFragmentShader ).trim(); - - let runnable = true; - let haveDiagnostics = true; - - if ( gl.getProgramParameter( program, gl.LINK_STATUS ) === false ) { - - runnable = false; - - if ( typeof renderer.debug.onShaderError === 'function' ) { - - renderer.debug.onShaderError( gl, program, glVertexShader, glFragmentShader ); - - } else { - - // default error reporting - - const vertexErrors = getShaderErrors( gl, glVertexShader, 'vertex' ); - const fragmentErrors = getShaderErrors( gl, glFragmentShader, 'fragment' ); - - console.error( - 'THREE.WebGLProgram: Shader Error ' + gl.getError() + ' - ' + - 'VALIDATE_STATUS ' + gl.getProgramParameter( program, gl.VALIDATE_STATUS ) + '\n\n' + - 'Material Name: ' + self.name + '\n' + - 'Material Type: ' + self.type + '\n\n' + - 'Program Info Log: ' + programLog + '\n' + - vertexErrors + '\n' + - fragmentErrors - ); - - } - - } else if ( programLog !== '' ) { - - console.warn( 'THREE.WebGLProgram: Program Info Log:', programLog ); - - } else if ( vertexLog === '' || fragmentLog === '' ) { - - haveDiagnostics = false; - - } - - if ( haveDiagnostics ) { - - self.diagnostics = { - - runnable: runnable, - - programLog: programLog, - - vertexShader: { - - log: vertexLog, - prefix: prefixVertex - - }, - - fragmentShader: { - - log: fragmentLog, - prefix: prefixFragment - - } - - }; - - } - - } - - // Clean up - - // Crashes in iOS9 and iOS10. #18402 - // gl.detachShader( program, glVertexShader ); - // gl.detachShader( program, glFragmentShader ); - - gl.deleteShader( glVertexShader ); - gl.deleteShader( glFragmentShader ); - - cachedUniforms = new WebGLUniforms( gl, program ); - cachedAttributes = fetchAttributeLocations( gl, program ); - - } - - // set up caching for uniform locations - - let cachedUniforms; - - this.getUniforms = function () { - - if ( cachedUniforms === undefined ) { - - // Populates cachedUniforms and cachedAttributes - onFirstUse( this ); - - } - - return cachedUniforms; - - }; - - // set up caching for attribute locations - - let cachedAttributes; - - this.getAttributes = function () { - - if ( cachedAttributes === undefined ) { - - // Populates cachedAttributes and cachedUniforms - onFirstUse( this ); - - } - - return cachedAttributes; - - }; - - // indicate when the program is ready to be used. if the KHR_parallel_shader_compile extension isn't supported, - // flag the program as ready immediately. It may cause a stall when it's first used. - - let programReady = ( parameters.rendererExtensionParallelShaderCompile === false ); - - this.isReady = function () { - - if ( programReady === false ) { - - programReady = gl.getProgramParameter( program, COMPLETION_STATUS_KHR ); - - } - - return programReady; - - }; - - // free resource - - this.destroy = function () { - - bindingStates.releaseStatesOfProgram( this ); - - gl.deleteProgram( program ); - this.program = undefined; - - }; - - // - - this.type = parameters.shaderType; - this.name = parameters.shaderName; - this.id = programIdCount ++; - this.cacheKey = cacheKey; - this.usedTimes = 1; - this.program = program; - this.vertexShader = glVertexShader; - this.fragmentShader = glFragmentShader; - - return this; - -} - -let _id$1 = 0; - -class WebGLShaderCache { - - constructor() { - - this.shaderCache = new Map(); - this.materialCache = new Map(); - - } - - update( material ) { - - const vertexShader = material.vertexShader; - const fragmentShader = material.fragmentShader; - - const vertexShaderStage = this._getShaderStage( vertexShader ); - const fragmentShaderStage = this._getShaderStage( fragmentShader ); - - const materialShaders = this._getShaderCacheForMaterial( material ); - - if ( materialShaders.has( vertexShaderStage ) === false ) { - - materialShaders.add( vertexShaderStage ); - vertexShaderStage.usedTimes ++; - - } - - if ( materialShaders.has( fragmentShaderStage ) === false ) { - - materialShaders.add( fragmentShaderStage ); - fragmentShaderStage.usedTimes ++; - - } - - return this; - - } - - remove( material ) { - - const materialShaders = this.materialCache.get( material ); - - for ( const shaderStage of materialShaders ) { - - shaderStage.usedTimes --; - - if ( shaderStage.usedTimes === 0 ) this.shaderCache.delete( shaderStage.code ); - - } - - this.materialCache.delete( material ); - - return this; - - } - - getVertexShaderID( material ) { - - return this._getShaderStage( material.vertexShader ).id; - - } - - getFragmentShaderID( material ) { - - return this._getShaderStage( material.fragmentShader ).id; - - } - - dispose() { - - this.shaderCache.clear(); - this.materialCache.clear(); - - } - - _getShaderCacheForMaterial( material ) { - - const cache = this.materialCache; - let set = cache.get( material ); - - if ( set === undefined ) { - - set = new Set(); - cache.set( material, set ); - - } - - return set; - - } - - _getShaderStage( code ) { - - const cache = this.shaderCache; - let stage = cache.get( code ); - - if ( stage === undefined ) { - - stage = new WebGLShaderStage( code ); - cache.set( code, stage ); - - } - - return stage; - - } - -} - -class WebGLShaderStage { - - constructor( code ) { - - this.id = _id$1 ++; - - this.code = code; - this.usedTimes = 0; - - } - -} - -function WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities, bindingStates, clipping ) { - - const _programLayers = new Layers(); - const _customShaders = new WebGLShaderCache(); - const _activeChannels = new Set(); - const programs = []; - - const IS_WEBGL2 = capabilities.isWebGL2; - const logarithmicDepthBuffer = capabilities.logarithmicDepthBuffer; - const SUPPORTS_VERTEX_TEXTURES = capabilities.vertexTextures; - - let precision = capabilities.precision; - - const shaderIDs = { - MeshDepthMaterial: 'depth', - MeshDistanceMaterial: 'distanceRGBA', - MeshNormalMaterial: 'normal', - MeshBasicMaterial: 'basic', - MeshLambertMaterial: 'lambert', - MeshPhongMaterial: 'phong', - MeshToonMaterial: 'toon', - MeshStandardMaterial: 'physical', - MeshPhysicalMaterial: 'physical', - MeshMatcapMaterial: 'matcap', - LineBasicMaterial: 'basic', - LineDashedMaterial: 'dashed', - PointsMaterial: 'points', - ShadowMaterial: 'shadow', - SpriteMaterial: 'sprite' - }; - - function getChannel( value ) { - - _activeChannels.add( value ); - - if ( value === 0 ) return 'uv'; - - return `uv${ value }`; - - } - - function getParameters( material, lights, shadows, scene, object ) { - - const fog = scene.fog; - const geometry = object.geometry; - const environment = material.isMeshStandardMaterial ? scene.environment : null; - - const envMap = ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get( material.envMap || environment ); - const envMapCubeUVHeight = ( !! envMap ) && ( envMap.mapping === CubeUVReflectionMapping ) ? envMap.image.height : null; - - const shaderID = shaderIDs[ material.type ]; - - // heuristics to create shader parameters according to lights in the scene - // (not to blow over maxLights budget) - - if ( material.precision !== null ) { - - precision = capabilities.getMaxPrecision( material.precision ); - - if ( precision !== material.precision ) { - - console.warn( 'THREE.WebGLProgram.getParameters:', material.precision, 'not supported, using', precision, 'instead.' ); - - } - - } - - // - - const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color; - const morphTargetsCount = ( morphAttribute !== undefined ) ? morphAttribute.length : 0; - - let morphTextureStride = 0; - - if ( geometry.morphAttributes.position !== undefined ) morphTextureStride = 1; - if ( geometry.morphAttributes.normal !== undefined ) morphTextureStride = 2; - if ( geometry.morphAttributes.color !== undefined ) morphTextureStride = 3; - - // - - let vertexShader, fragmentShader; - let customVertexShaderID, customFragmentShaderID; - - if ( shaderID ) { - - const shader = ShaderLib[ shaderID ]; - - vertexShader = shader.vertexShader; - fragmentShader = shader.fragmentShader; - - } else { - - vertexShader = material.vertexShader; - fragmentShader = material.fragmentShader; - - _customShaders.update( material ); - - customVertexShaderID = _customShaders.getVertexShaderID( material ); - customFragmentShaderID = _customShaders.getFragmentShaderID( material ); - - } - - const currentRenderTarget = renderer.getRenderTarget(); - - const IS_INSTANCEDMESH = object.isInstancedMesh === true; - const IS_BATCHEDMESH = object.isBatchedMesh === true; - - const HAS_MAP = !! material.map; - const HAS_MATCAP = !! material.matcap; - const HAS_ENVMAP = !! envMap; - const HAS_AOMAP = !! material.aoMap; - const HAS_LIGHTMAP = !! material.lightMap; - const HAS_BUMPMAP = !! material.bumpMap; - const HAS_NORMALMAP = !! material.normalMap; - const HAS_DISPLACEMENTMAP = !! material.displacementMap; - const HAS_EMISSIVEMAP = !! material.emissiveMap; - - const HAS_METALNESSMAP = !! material.metalnessMap; - const HAS_ROUGHNESSMAP = !! material.roughnessMap; - - const HAS_ANISOTROPY = material.anisotropy > 0; - const HAS_CLEARCOAT = material.clearcoat > 0; - const HAS_IRIDESCENCE = material.iridescence > 0; - const HAS_SHEEN = material.sheen > 0; - const HAS_TRANSMISSION = material.transmission > 0; - - const HAS_ANISOTROPYMAP = HAS_ANISOTROPY && !! material.anisotropyMap; - - const HAS_CLEARCOATMAP = HAS_CLEARCOAT && !! material.clearcoatMap; - const HAS_CLEARCOAT_NORMALMAP = HAS_CLEARCOAT && !! material.clearcoatNormalMap; - const HAS_CLEARCOAT_ROUGHNESSMAP = HAS_CLEARCOAT && !! material.clearcoatRoughnessMap; - - const HAS_IRIDESCENCEMAP = HAS_IRIDESCENCE && !! material.iridescenceMap; - const HAS_IRIDESCENCE_THICKNESSMAP = HAS_IRIDESCENCE && !! material.iridescenceThicknessMap; - - const HAS_SHEEN_COLORMAP = HAS_SHEEN && !! material.sheenColorMap; - const HAS_SHEEN_ROUGHNESSMAP = HAS_SHEEN && !! material.sheenRoughnessMap; - - const HAS_SPECULARMAP = !! material.specularMap; - const HAS_SPECULAR_COLORMAP = !! material.specularColorMap; - const HAS_SPECULAR_INTENSITYMAP = !! material.specularIntensityMap; - - const HAS_TRANSMISSIONMAP = HAS_TRANSMISSION && !! material.transmissionMap; - const HAS_THICKNESSMAP = HAS_TRANSMISSION && !! material.thicknessMap; - - const HAS_GRADIENTMAP = !! material.gradientMap; - - const HAS_ALPHAMAP = !! material.alphaMap; - - const HAS_ALPHATEST = material.alphaTest > 0; - - const HAS_ALPHAHASH = !! material.alphaHash; - - const HAS_EXTENSIONS = !! material.extensions; - - let toneMapping = NoToneMapping; - - if ( material.toneMapped ) { - - if ( currentRenderTarget === null || currentRenderTarget.isXRRenderTarget === true ) { - - toneMapping = renderer.toneMapping; - - } - - } - - const parameters = { - - isWebGL2: IS_WEBGL2, - - shaderID: shaderID, - shaderType: material.type, - shaderName: material.name, - - vertexShader: vertexShader, - fragmentShader: fragmentShader, - defines: material.defines, - - customVertexShaderID: customVertexShaderID, - customFragmentShaderID: customFragmentShaderID, - - isRawShaderMaterial: material.isRawShaderMaterial === true, - glslVersion: material.glslVersion, - - precision: precision, - - batching: IS_BATCHEDMESH, - instancing: IS_INSTANCEDMESH, - instancingColor: IS_INSTANCEDMESH && object.instanceColor !== null, - - supportsVertexTextures: SUPPORTS_VERTEX_TEXTURES, - outputColorSpace: ( currentRenderTarget === null ) ? renderer.outputColorSpace : ( currentRenderTarget.isXRRenderTarget === true ? currentRenderTarget.texture.colorSpace : LinearSRGBColorSpace ), - alphaToCoverage: !! material.alphaToCoverage, - - map: HAS_MAP, - matcap: HAS_MATCAP, - envMap: HAS_ENVMAP, - envMapMode: HAS_ENVMAP && envMap.mapping, - envMapCubeUVHeight: envMapCubeUVHeight, - aoMap: HAS_AOMAP, - lightMap: HAS_LIGHTMAP, - bumpMap: HAS_BUMPMAP, - normalMap: HAS_NORMALMAP, - displacementMap: SUPPORTS_VERTEX_TEXTURES && HAS_DISPLACEMENTMAP, - emissiveMap: HAS_EMISSIVEMAP, - - normalMapObjectSpace: HAS_NORMALMAP && material.normalMapType === ObjectSpaceNormalMap, - normalMapTangentSpace: HAS_NORMALMAP && material.normalMapType === TangentSpaceNormalMap, - - metalnessMap: HAS_METALNESSMAP, - roughnessMap: HAS_ROUGHNESSMAP, - - anisotropy: HAS_ANISOTROPY, - anisotropyMap: HAS_ANISOTROPYMAP, - - clearcoat: HAS_CLEARCOAT, - clearcoatMap: HAS_CLEARCOATMAP, - clearcoatNormalMap: HAS_CLEARCOAT_NORMALMAP, - clearcoatRoughnessMap: HAS_CLEARCOAT_ROUGHNESSMAP, - - iridescence: HAS_IRIDESCENCE, - iridescenceMap: HAS_IRIDESCENCEMAP, - iridescenceThicknessMap: HAS_IRIDESCENCE_THICKNESSMAP, - - sheen: HAS_SHEEN, - sheenColorMap: HAS_SHEEN_COLORMAP, - sheenRoughnessMap: HAS_SHEEN_ROUGHNESSMAP, - - specularMap: HAS_SPECULARMAP, - specularColorMap: HAS_SPECULAR_COLORMAP, - specularIntensityMap: HAS_SPECULAR_INTENSITYMAP, - - transmission: HAS_TRANSMISSION, - transmissionMap: HAS_TRANSMISSIONMAP, - thicknessMap: HAS_THICKNESSMAP, - - gradientMap: HAS_GRADIENTMAP, - - opaque: material.transparent === false && material.blending === NormalBlending && material.alphaToCoverage === false, - - alphaMap: HAS_ALPHAMAP, - alphaTest: HAS_ALPHATEST, - alphaHash: HAS_ALPHAHASH, - - combine: material.combine, - - // - - mapUv: HAS_MAP && getChannel( material.map.channel ), - aoMapUv: HAS_AOMAP && getChannel( material.aoMap.channel ), - lightMapUv: HAS_LIGHTMAP && getChannel( material.lightMap.channel ), - bumpMapUv: HAS_BUMPMAP && getChannel( material.bumpMap.channel ), - normalMapUv: HAS_NORMALMAP && getChannel( material.normalMap.channel ), - displacementMapUv: HAS_DISPLACEMENTMAP && getChannel( material.displacementMap.channel ), - emissiveMapUv: HAS_EMISSIVEMAP && getChannel( material.emissiveMap.channel ), - - metalnessMapUv: HAS_METALNESSMAP && getChannel( material.metalnessMap.channel ), - roughnessMapUv: HAS_ROUGHNESSMAP && getChannel( material.roughnessMap.channel ), - - anisotropyMapUv: HAS_ANISOTROPYMAP && getChannel( material.anisotropyMap.channel ), - - clearcoatMapUv: HAS_CLEARCOATMAP && getChannel( material.clearcoatMap.channel ), - clearcoatNormalMapUv: HAS_CLEARCOAT_NORMALMAP && getChannel( material.clearcoatNormalMap.channel ), - clearcoatRoughnessMapUv: HAS_CLEARCOAT_ROUGHNESSMAP && getChannel( material.clearcoatRoughnessMap.channel ), - - iridescenceMapUv: HAS_IRIDESCENCEMAP && getChannel( material.iridescenceMap.channel ), - iridescenceThicknessMapUv: HAS_IRIDESCENCE_THICKNESSMAP && getChannel( material.iridescenceThicknessMap.channel ), - - sheenColorMapUv: HAS_SHEEN_COLORMAP && getChannel( material.sheenColorMap.channel ), - sheenRoughnessMapUv: HAS_SHEEN_ROUGHNESSMAP && getChannel( material.sheenRoughnessMap.channel ), - - specularMapUv: HAS_SPECULARMAP && getChannel( material.specularMap.channel ), - specularColorMapUv: HAS_SPECULAR_COLORMAP && getChannel( material.specularColorMap.channel ), - specularIntensityMapUv: HAS_SPECULAR_INTENSITYMAP && getChannel( material.specularIntensityMap.channel ), - - transmissionMapUv: HAS_TRANSMISSIONMAP && getChannel( material.transmissionMap.channel ), - thicknessMapUv: HAS_THICKNESSMAP && getChannel( material.thicknessMap.channel ), - - alphaMapUv: HAS_ALPHAMAP && getChannel( material.alphaMap.channel ), - - // - - vertexTangents: !! geometry.attributes.tangent && ( HAS_NORMALMAP || HAS_ANISOTROPY ), - vertexColors: material.vertexColors, - vertexAlphas: material.vertexColors === true && !! geometry.attributes.color && geometry.attributes.color.itemSize === 4, - - pointsUvs: object.isPoints === true && !! geometry.attributes.uv && ( HAS_MAP || HAS_ALPHAMAP ), - - fog: !! fog, - useFog: material.fog === true, - fogExp2: ( !! fog && fog.isFogExp2 ), - - flatShading: material.flatShading === true, - - sizeAttenuation: material.sizeAttenuation === true, - logarithmicDepthBuffer: logarithmicDepthBuffer, - - skinning: object.isSkinnedMesh === true, - - morphTargets: geometry.morphAttributes.position !== undefined, - morphNormals: geometry.morphAttributes.normal !== undefined, - morphColors: geometry.morphAttributes.color !== undefined, - morphTargetsCount: morphTargetsCount, - morphTextureStride: morphTextureStride, - - numDirLights: lights.directional.length, - numPointLights: lights.point.length, - numSpotLights: lights.spot.length, - numSpotLightMaps: lights.spotLightMap.length, - numRectAreaLights: lights.rectArea.length, - numHemiLights: lights.hemi.length, - - numDirLightShadows: lights.directionalShadowMap.length, - numPointLightShadows: lights.pointShadowMap.length, - numSpotLightShadows: lights.spotShadowMap.length, - numSpotLightShadowsWithMaps: lights.numSpotLightShadowsWithMaps, - - numLightProbes: lights.numLightProbes, - - numClippingPlanes: clipping.numPlanes, - numClipIntersection: clipping.numIntersection, - - dithering: material.dithering, - - shadowMapEnabled: renderer.shadowMap.enabled && shadows.length > 0, - shadowMapType: renderer.shadowMap.type, - - toneMapping: toneMapping, - useLegacyLights: renderer._useLegacyLights, - - decodeVideoTexture: HAS_MAP && ( material.map.isVideoTexture === true ) && ( ColorManagement.getTransfer( material.map.colorSpace ) === SRGBTransfer ), - - premultipliedAlpha: material.premultipliedAlpha, - - doubleSided: material.side === DoubleSide, - flipSided: material.side === BackSide, - - useDepthPacking: material.depthPacking >= 0, - depthPacking: material.depthPacking || 0, - - index0AttributeName: material.index0AttributeName, - - extensionDerivatives: HAS_EXTENSIONS && material.extensions.derivatives === true, - extensionFragDepth: HAS_EXTENSIONS && material.extensions.fragDepth === true, - extensionDrawBuffers: HAS_EXTENSIONS && material.extensions.drawBuffers === true, - extensionShaderTextureLOD: HAS_EXTENSIONS && material.extensions.shaderTextureLOD === true, - extensionClipCullDistance: HAS_EXTENSIONS && material.extensions.clipCullDistance === true && extensions.has( 'WEBGL_clip_cull_distance' ), - extensionMultiDraw: HAS_EXTENSIONS && material.extensions.multiDraw === true && extensions.has( 'WEBGL_multi_draw' ), - - rendererExtensionFragDepth: IS_WEBGL2 || extensions.has( 'EXT_frag_depth' ), - rendererExtensionDrawBuffers: IS_WEBGL2 || extensions.has( 'WEBGL_draw_buffers' ), - rendererExtensionShaderTextureLod: IS_WEBGL2 || extensions.has( 'EXT_shader_texture_lod' ), - rendererExtensionParallelShaderCompile: extensions.has( 'KHR_parallel_shader_compile' ), - - customProgramCacheKey: material.customProgramCacheKey() - - }; - - // the usage of getChannel() determines the active texture channels for this shader - - parameters.vertexUv1s = _activeChannels.has( 1 ); - parameters.vertexUv2s = _activeChannels.has( 2 ); - parameters.vertexUv3s = _activeChannels.has( 3 ); - - _activeChannels.clear(); - - return parameters; - - } - - function getProgramCacheKey( parameters ) { - - const array = []; - - if ( parameters.shaderID ) { - - array.push( parameters.shaderID ); - - } else { - - array.push( parameters.customVertexShaderID ); - array.push( parameters.customFragmentShaderID ); - - } - - if ( parameters.defines !== undefined ) { - - for ( const name in parameters.defines ) { - - array.push( name ); - array.push( parameters.defines[ name ] ); - - } - - } - - if ( parameters.isRawShaderMaterial === false ) { - - getProgramCacheKeyParameters( array, parameters ); - getProgramCacheKeyBooleans( array, parameters ); - array.push( renderer.outputColorSpace ); - - } - - array.push( parameters.customProgramCacheKey ); - - return array.join(); - - } - - function getProgramCacheKeyParameters( array, parameters ) { - - array.push( parameters.precision ); - array.push( parameters.outputColorSpace ); - array.push( parameters.envMapMode ); - array.push( parameters.envMapCubeUVHeight ); - array.push( parameters.mapUv ); - array.push( parameters.alphaMapUv ); - array.push( parameters.lightMapUv ); - array.push( parameters.aoMapUv ); - array.push( parameters.bumpMapUv ); - array.push( parameters.normalMapUv ); - array.push( parameters.displacementMapUv ); - array.push( parameters.emissiveMapUv ); - array.push( parameters.metalnessMapUv ); - array.push( parameters.roughnessMapUv ); - array.push( parameters.anisotropyMapUv ); - array.push( parameters.clearcoatMapUv ); - array.push( parameters.clearcoatNormalMapUv ); - array.push( parameters.clearcoatRoughnessMapUv ); - array.push( parameters.iridescenceMapUv ); - array.push( parameters.iridescenceThicknessMapUv ); - array.push( parameters.sheenColorMapUv ); - array.push( parameters.sheenRoughnessMapUv ); - array.push( parameters.specularMapUv ); - array.push( parameters.specularColorMapUv ); - array.push( parameters.specularIntensityMapUv ); - array.push( parameters.transmissionMapUv ); - array.push( parameters.thicknessMapUv ); - array.push( parameters.combine ); - array.push( parameters.fogExp2 ); - array.push( parameters.sizeAttenuation ); - array.push( parameters.morphTargetsCount ); - array.push( parameters.morphAttributeCount ); - array.push( parameters.numDirLights ); - array.push( parameters.numPointLights ); - array.push( parameters.numSpotLights ); - array.push( parameters.numSpotLightMaps ); - array.push( parameters.numHemiLights ); - array.push( parameters.numRectAreaLights ); - array.push( parameters.numDirLightShadows ); - array.push( parameters.numPointLightShadows ); - array.push( parameters.numSpotLightShadows ); - array.push( parameters.numSpotLightShadowsWithMaps ); - array.push( parameters.numLightProbes ); - array.push( parameters.shadowMapType ); - array.push( parameters.toneMapping ); - array.push( parameters.numClippingPlanes ); - array.push( parameters.numClipIntersection ); - array.push( parameters.depthPacking ); - - } - - function getProgramCacheKeyBooleans( array, parameters ) { - - _programLayers.disableAll(); - - if ( parameters.isWebGL2 ) - _programLayers.enable( 0 ); - if ( parameters.supportsVertexTextures ) - _programLayers.enable( 1 ); - if ( parameters.instancing ) - _programLayers.enable( 2 ); - if ( parameters.instancingColor ) - _programLayers.enable( 3 ); - if ( parameters.matcap ) - _programLayers.enable( 4 ); - if ( parameters.envMap ) - _programLayers.enable( 5 ); - if ( parameters.normalMapObjectSpace ) - _programLayers.enable( 6 ); - if ( parameters.normalMapTangentSpace ) - _programLayers.enable( 7 ); - if ( parameters.clearcoat ) - _programLayers.enable( 8 ); - if ( parameters.iridescence ) - _programLayers.enable( 9 ); - if ( parameters.alphaTest ) - _programLayers.enable( 10 ); - if ( parameters.vertexColors ) - _programLayers.enable( 11 ); - if ( parameters.vertexAlphas ) - _programLayers.enable( 12 ); - if ( parameters.vertexUv1s ) - _programLayers.enable( 13 ); - if ( parameters.vertexUv2s ) - _programLayers.enable( 14 ); - if ( parameters.vertexUv3s ) - _programLayers.enable( 15 ); - if ( parameters.vertexTangents ) - _programLayers.enable( 16 ); - if ( parameters.anisotropy ) - _programLayers.enable( 17 ); - if ( parameters.alphaHash ) - _programLayers.enable( 18 ); - if ( parameters.batching ) - _programLayers.enable( 19 ); - - array.push( _programLayers.mask ); - _programLayers.disableAll(); - - if ( parameters.fog ) - _programLayers.enable( 0 ); - if ( parameters.useFog ) - _programLayers.enable( 1 ); - if ( parameters.flatShading ) - _programLayers.enable( 2 ); - if ( parameters.logarithmicDepthBuffer ) - _programLayers.enable( 3 ); - if ( parameters.skinning ) - _programLayers.enable( 4 ); - if ( parameters.morphTargets ) - _programLayers.enable( 5 ); - if ( parameters.morphNormals ) - _programLayers.enable( 6 ); - if ( parameters.morphColors ) - _programLayers.enable( 7 ); - if ( parameters.premultipliedAlpha ) - _programLayers.enable( 8 ); - if ( parameters.shadowMapEnabled ) - _programLayers.enable( 9 ); - if ( parameters.useLegacyLights ) - _programLayers.enable( 10 ); - if ( parameters.doubleSided ) - _programLayers.enable( 11 ); - if ( parameters.flipSided ) - _programLayers.enable( 12 ); - if ( parameters.useDepthPacking ) - _programLayers.enable( 13 ); - if ( parameters.dithering ) - _programLayers.enable( 14 ); - if ( parameters.transmission ) - _programLayers.enable( 15 ); - if ( parameters.sheen ) - _programLayers.enable( 16 ); - if ( parameters.opaque ) - _programLayers.enable( 17 ); - if ( parameters.pointsUvs ) - _programLayers.enable( 18 ); - if ( parameters.decodeVideoTexture ) - _programLayers.enable( 19 ); - if ( parameters.alphaToCoverage ) - _programLayers.enable( 20 ); - - array.push( _programLayers.mask ); - - } - - function getUniforms( material ) { - - const shaderID = shaderIDs[ material.type ]; - let uniforms; - - if ( shaderID ) { - - const shader = ShaderLib[ shaderID ]; - uniforms = UniformsUtils.clone( shader.uniforms ); - - } else { - - uniforms = material.uniforms; - - } - - return uniforms; - - } - - function acquireProgram( parameters, cacheKey ) { - - let program; - - // Check if code has been already compiled - for ( let p = 0, pl = programs.length; p < pl; p ++ ) { - - const preexistingProgram = programs[ p ]; - - if ( preexistingProgram.cacheKey === cacheKey ) { - - program = preexistingProgram; - ++ program.usedTimes; - - break; - - } - - } - - if ( program === undefined ) { - - program = new WebGLProgram( renderer, cacheKey, parameters, bindingStates ); - programs.push( program ); - - } - - return program; - - } - - function releaseProgram( program ) { - - if ( -- program.usedTimes === 0 ) { - - // Remove from unordered set - const i = programs.indexOf( program ); - programs[ i ] = programs[ programs.length - 1 ]; - programs.pop(); - - // Free WebGL resources - program.destroy(); - - } - - } - - function releaseShaderCache( material ) { - - _customShaders.remove( material ); - - } - - function dispose() { - - _customShaders.dispose(); - - } - - return { - getParameters: getParameters, - getProgramCacheKey: getProgramCacheKey, - getUniforms: getUniforms, - acquireProgram: acquireProgram, - releaseProgram: releaseProgram, - releaseShaderCache: releaseShaderCache, - // Exposed for resource monitoring & error feedback via renderer.info: - programs: programs, - dispose: dispose - }; - -} - -function WebGLProperties() { - - let properties = new WeakMap(); - - function get( object ) { - - let map = properties.get( object ); - - if ( map === undefined ) { - - map = {}; - properties.set( object, map ); - - } - - return map; - - } - - function remove( object ) { - - properties.delete( object ); - - } - - function update( object, key, value ) { - - properties.get( object )[ key ] = value; - - } - - function dispose() { - - properties = new WeakMap(); - - } - - return { - get: get, - remove: remove, - update: update, - dispose: dispose - }; - -} - -function painterSortStable( a, b ) { - - if ( a.groupOrder !== b.groupOrder ) { - - return a.groupOrder - b.groupOrder; - - } else if ( a.renderOrder !== b.renderOrder ) { - - return a.renderOrder - b.renderOrder; - - } else if ( a.material.id !== b.material.id ) { - - return a.material.id - b.material.id; - - } else if ( a.z !== b.z ) { - - return a.z - b.z; - - } else { - - return a.id - b.id; - - } - -} - -function reversePainterSortStable( a, b ) { - - if ( a.groupOrder !== b.groupOrder ) { - - return a.groupOrder - b.groupOrder; - - } else if ( a.renderOrder !== b.renderOrder ) { - - return a.renderOrder - b.renderOrder; - - } else if ( a.z !== b.z ) { - - return b.z - a.z; - - } else { - - return a.id - b.id; - - } - -} - - -function WebGLRenderList() { - - const renderItems = []; - let renderItemsIndex = 0; - - const opaque = []; - const transmissive = []; - const transparent = []; - - function init() { - - renderItemsIndex = 0; - - opaque.length = 0; - transmissive.length = 0; - transparent.length = 0; - - } - - function getNextRenderItem( object, geometry, material, groupOrder, z, group ) { - - let renderItem = renderItems[ renderItemsIndex ]; - - if ( renderItem === undefined ) { - - renderItem = { - id: object.id, - object: object, - geometry: geometry, - material: material, - groupOrder: groupOrder, - renderOrder: object.renderOrder, - z: z, - group: group - }; - - renderItems[ renderItemsIndex ] = renderItem; - - } else { - - renderItem.id = object.id; - renderItem.object = object; - renderItem.geometry = geometry; - renderItem.material = material; - renderItem.groupOrder = groupOrder; - renderItem.renderOrder = object.renderOrder; - renderItem.z = z; - renderItem.group = group; - - } - - renderItemsIndex ++; - - return renderItem; - - } - - function push( object, geometry, material, groupOrder, z, group ) { - - const renderItem = getNextRenderItem( object, geometry, material, groupOrder, z, group ); - - if ( material.transmission > 0.0 ) { - - transmissive.push( renderItem ); - - } else if ( material.transparent === true ) { - - transparent.push( renderItem ); - - } else { - - opaque.push( renderItem ); - - } - - } - - function unshift( object, geometry, material, groupOrder, z, group ) { - - const renderItem = getNextRenderItem( object, geometry, material, groupOrder, z, group ); - - if ( material.transmission > 0.0 ) { - - transmissive.unshift( renderItem ); - - } else if ( material.transparent === true ) { - - transparent.unshift( renderItem ); - - } else { - - opaque.unshift( renderItem ); - - } - - } - - function sort( customOpaqueSort, customTransparentSort ) { - - if ( opaque.length > 1 ) opaque.sort( customOpaqueSort || painterSortStable ); - if ( transmissive.length > 1 ) transmissive.sort( customTransparentSort || reversePainterSortStable ); - if ( transparent.length > 1 ) transparent.sort( customTransparentSort || reversePainterSortStable ); - - } - - function finish() { - - // Clear references from inactive renderItems in the list - - for ( let i = renderItemsIndex, il = renderItems.length; i < il; i ++ ) { - - const renderItem = renderItems[ i ]; - - if ( renderItem.id === null ) break; - - renderItem.id = null; - renderItem.object = null; - renderItem.geometry = null; - renderItem.material = null; - renderItem.group = null; - - } - - } - - return { - - opaque: opaque, - transmissive: transmissive, - transparent: transparent, - - init: init, - push: push, - unshift: unshift, - finish: finish, - - sort: sort - }; - -} - -function WebGLRenderLists() { - - let lists = new WeakMap(); - - function get( scene, renderCallDepth ) { - - const listArray = lists.get( scene ); - let list; - - if ( listArray === undefined ) { - - list = new WebGLRenderList(); - lists.set( scene, [ list ] ); - - } else { - - if ( renderCallDepth >= listArray.length ) { - - list = new WebGLRenderList(); - listArray.push( list ); - - } else { - - list = listArray[ renderCallDepth ]; - - } - - } - - return list; - - } - - function dispose() { - - lists = new WeakMap(); - - } - - return { - get: get, - dispose: dispose - }; - -} - -function UniformsCache() { - - const lights = {}; - - return { - - get: function ( light ) { - - if ( lights[ light.id ] !== undefined ) { - - return lights[ light.id ]; - - } - - let uniforms; - - switch ( light.type ) { - - case 'DirectionalLight': - uniforms = { - direction: new Vector3(), - color: new Color() - }; - break; - - case 'SpotLight': - uniforms = { - position: new Vector3(), - direction: new Vector3(), - color: new Color(), - distance: 0, - coneCos: 0, - penumbraCos: 0, - decay: 0 - }; - break; - - case 'PointLight': - uniforms = { - position: new Vector3(), - color: new Color(), - distance: 0, - decay: 0 - }; - break; - - case 'HemisphereLight': - uniforms = { - direction: new Vector3(), - skyColor: new Color(), - groundColor: new Color() - }; - break; - - case 'RectAreaLight': - uniforms = { - color: new Color(), - position: new Vector3(), - halfWidth: new Vector3(), - halfHeight: new Vector3() - }; - break; - - } - - lights[ light.id ] = uniforms; - - return uniforms; - - } - - }; - -} - -function ShadowUniformsCache() { - - const lights = {}; - - return { - - get: function ( light ) { - - if ( lights[ light.id ] !== undefined ) { - - return lights[ light.id ]; - - } - - let uniforms; - - switch ( light.type ) { - - case 'DirectionalLight': - uniforms = { - shadowBias: 0, - shadowNormalBias: 0, - shadowRadius: 1, - shadowMapSize: new Vector2() - }; - break; - - case 'SpotLight': - uniforms = { - shadowBias: 0, - shadowNormalBias: 0, - shadowRadius: 1, - shadowMapSize: new Vector2() - }; - break; - - case 'PointLight': - uniforms = { - shadowBias: 0, - shadowNormalBias: 0, - shadowRadius: 1, - shadowMapSize: new Vector2(), - shadowCameraNear: 1, - shadowCameraFar: 1000 - }; - break; - - // TODO (abelnation): set RectAreaLight shadow uniforms - - } - - lights[ light.id ] = uniforms; - - return uniforms; - - } - - }; - -} - - - -let nextVersion = 0; - -function shadowCastingAndTexturingLightsFirst( lightA, lightB ) { - - return ( lightB.castShadow ? 2 : 0 ) - ( lightA.castShadow ? 2 : 0 ) + ( lightB.map ? 1 : 0 ) - ( lightA.map ? 1 : 0 ); - -} - -function WebGLLights( extensions, capabilities ) { - - const cache = new UniformsCache(); - - const shadowCache = ShadowUniformsCache(); - - const state = { - - version: 0, - - hash: { - directionalLength: - 1, - pointLength: - 1, - spotLength: - 1, - rectAreaLength: - 1, - hemiLength: - 1, - - numDirectionalShadows: - 1, - numPointShadows: - 1, - numSpotShadows: - 1, - numSpotMaps: - 1, - - numLightProbes: - 1 - }, - - ambient: [ 0, 0, 0 ], - probe: [], - directional: [], - directionalShadow: [], - directionalShadowMap: [], - directionalShadowMatrix: [], - spot: [], - spotLightMap: [], - spotShadow: [], - spotShadowMap: [], - spotLightMatrix: [], - rectArea: [], - rectAreaLTC1: null, - rectAreaLTC2: null, - point: [], - pointShadow: [], - pointShadowMap: [], - pointShadowMatrix: [], - hemi: [], - numSpotLightShadowsWithMaps: 0, - numLightProbes: 0 - - }; - - for ( let i = 0; i < 9; i ++ ) state.probe.push( new Vector3() ); - - const vector3 = new Vector3(); - const matrix4 = new Matrix4(); - const matrix42 = new Matrix4(); - - function setup( lights, useLegacyLights ) { - - let r = 0, g = 0, b = 0; - - for ( let i = 0; i < 9; i ++ ) state.probe[ i ].set( 0, 0, 0 ); - - let directionalLength = 0; - let pointLength = 0; - let spotLength = 0; - let rectAreaLength = 0; - let hemiLength = 0; - - let numDirectionalShadows = 0; - let numPointShadows = 0; - let numSpotShadows = 0; - let numSpotMaps = 0; - let numSpotShadowsWithMaps = 0; - - let numLightProbes = 0; - - // ordering : [shadow casting + map texturing, map texturing, shadow casting, none ] - lights.sort( shadowCastingAndTexturingLightsFirst ); - - // artist-friendly light intensity scaling factor - const scaleFactor = ( useLegacyLights === true ) ? Math.PI : 1; - - for ( let i = 0, l = lights.length; i < l; i ++ ) { - - const light = lights[ i ]; - - const color = light.color; - const intensity = light.intensity; - const distance = light.distance; - - const shadowMap = ( light.shadow && light.shadow.map ) ? light.shadow.map.texture : null; - - if ( light.isAmbientLight ) { - - r += color.r * intensity * scaleFactor; - g += color.g * intensity * scaleFactor; - b += color.b * intensity * scaleFactor; - - } else if ( light.isLightProbe ) { - - for ( let j = 0; j < 9; j ++ ) { - - state.probe[ j ].addScaledVector( light.sh.coefficients[ j ], intensity ); - - } - - numLightProbes ++; - - } else if ( light.isDirectionalLight ) { - - const uniforms = cache.get( light ); - - uniforms.color.copy( light.color ).multiplyScalar( light.intensity * scaleFactor ); - - if ( light.castShadow ) { - - const shadow = light.shadow; - - const shadowUniforms = shadowCache.get( light ); - - shadowUniforms.shadowBias = shadow.bias; - shadowUniforms.shadowNormalBias = shadow.normalBias; - shadowUniforms.shadowRadius = shadow.radius; - shadowUniforms.shadowMapSize = shadow.mapSize; - - state.directionalShadow[ directionalLength ] = shadowUniforms; - state.directionalShadowMap[ directionalLength ] = shadowMap; - state.directionalShadowMatrix[ directionalLength ] = light.shadow.matrix; - - numDirectionalShadows ++; - - } - - state.directional[ directionalLength ] = uniforms; - - directionalLength ++; - - } else if ( light.isSpotLight ) { - - const uniforms = cache.get( light ); - - uniforms.position.setFromMatrixPosition( light.matrixWorld ); - - uniforms.color.copy( color ).multiplyScalar( intensity * scaleFactor ); - uniforms.distance = distance; - - uniforms.coneCos = Math.cos( light.angle ); - uniforms.penumbraCos = Math.cos( light.angle * ( 1 - light.penumbra ) ); - uniforms.decay = light.decay; - - state.spot[ spotLength ] = uniforms; - - const shadow = light.shadow; - - if ( light.map ) { - - state.spotLightMap[ numSpotMaps ] = light.map; - numSpotMaps ++; - - // make sure the lightMatrix is up to date - // TODO : do it if required only - shadow.updateMatrices( light ); - - if ( light.castShadow ) numSpotShadowsWithMaps ++; - - } - - state.spotLightMatrix[ spotLength ] = shadow.matrix; - - if ( light.castShadow ) { - - const shadowUniforms = shadowCache.get( light ); - - shadowUniforms.shadowBias = shadow.bias; - shadowUniforms.shadowNormalBias = shadow.normalBias; - shadowUniforms.shadowRadius = shadow.radius; - shadowUniforms.shadowMapSize = shadow.mapSize; - - state.spotShadow[ spotLength ] = shadowUniforms; - state.spotShadowMap[ spotLength ] = shadowMap; - - numSpotShadows ++; - - } - - spotLength ++; - - } else if ( light.isRectAreaLight ) { - - const uniforms = cache.get( light ); - - uniforms.color.copy( color ).multiplyScalar( intensity ); - - uniforms.halfWidth.set( light.width * 0.5, 0.0, 0.0 ); - uniforms.halfHeight.set( 0.0, light.height * 0.5, 0.0 ); - - state.rectArea[ rectAreaLength ] = uniforms; - - rectAreaLength ++; - - } else if ( light.isPointLight ) { - - const uniforms = cache.get( light ); - - uniforms.color.copy( light.color ).multiplyScalar( light.intensity * scaleFactor ); - uniforms.distance = light.distance; - uniforms.decay = light.decay; - - if ( light.castShadow ) { - - const shadow = light.shadow; - - const shadowUniforms = shadowCache.get( light ); - - shadowUniforms.shadowBias = shadow.bias; - shadowUniforms.shadowNormalBias = shadow.normalBias; - shadowUniforms.shadowRadius = shadow.radius; - shadowUniforms.shadowMapSize = shadow.mapSize; - shadowUniforms.shadowCameraNear = shadow.camera.near; - shadowUniforms.shadowCameraFar = shadow.camera.far; - - state.pointShadow[ pointLength ] = shadowUniforms; - state.pointShadowMap[ pointLength ] = shadowMap; - state.pointShadowMatrix[ pointLength ] = light.shadow.matrix; - - numPointShadows ++; - - } - - state.point[ pointLength ] = uniforms; - - pointLength ++; - - } else if ( light.isHemisphereLight ) { - - const uniforms = cache.get( light ); - - uniforms.skyColor.copy( light.color ).multiplyScalar( intensity * scaleFactor ); - uniforms.groundColor.copy( light.groundColor ).multiplyScalar( intensity * scaleFactor ); - - state.hemi[ hemiLength ] = uniforms; - - hemiLength ++; - - } - - } - - if ( rectAreaLength > 0 ) { - - if ( capabilities.isWebGL2 ) { - - // WebGL 2 - - if ( extensions.has( 'OES_texture_float_linear' ) === true ) { - - state.rectAreaLTC1 = UniformsLib.LTC_FLOAT_1; - state.rectAreaLTC2 = UniformsLib.LTC_FLOAT_2; - - } else { - - state.rectAreaLTC1 = UniformsLib.LTC_HALF_1; - state.rectAreaLTC2 = UniformsLib.LTC_HALF_2; - - } - - } else { - - // WebGL 1 - - if ( extensions.has( 'OES_texture_float_linear' ) === true ) { - - state.rectAreaLTC1 = UniformsLib.LTC_FLOAT_1; - state.rectAreaLTC2 = UniformsLib.LTC_FLOAT_2; - - } else if ( extensions.has( 'OES_texture_half_float_linear' ) === true ) { - - state.rectAreaLTC1 = UniformsLib.LTC_HALF_1; - state.rectAreaLTC2 = UniformsLib.LTC_HALF_2; - - } else { - - console.error( 'THREE.WebGLRenderer: Unable to use RectAreaLight. Missing WebGL extensions.' ); - - } - - } - - } - - state.ambient[ 0 ] = r; - state.ambient[ 1 ] = g; - state.ambient[ 2 ] = b; - - const hash = state.hash; - - if ( hash.directionalLength !== directionalLength || - hash.pointLength !== pointLength || - hash.spotLength !== spotLength || - hash.rectAreaLength !== rectAreaLength || - hash.hemiLength !== hemiLength || - hash.numDirectionalShadows !== numDirectionalShadows || - hash.numPointShadows !== numPointShadows || - hash.numSpotShadows !== numSpotShadows || - hash.numSpotMaps !== numSpotMaps || - hash.numLightProbes !== numLightProbes ) { - - state.directional.length = directionalLength; - state.spot.length = spotLength; - state.rectArea.length = rectAreaLength; - state.point.length = pointLength; - state.hemi.length = hemiLength; - - state.directionalShadow.length = numDirectionalShadows; - state.directionalShadowMap.length = numDirectionalShadows; - state.pointShadow.length = numPointShadows; - state.pointShadowMap.length = numPointShadows; - state.spotShadow.length = numSpotShadows; - state.spotShadowMap.length = numSpotShadows; - state.directionalShadowMatrix.length = numDirectionalShadows; - state.pointShadowMatrix.length = numPointShadows; - state.spotLightMatrix.length = numSpotShadows + numSpotMaps - numSpotShadowsWithMaps; - state.spotLightMap.length = numSpotMaps; - state.numSpotLightShadowsWithMaps = numSpotShadowsWithMaps; - state.numLightProbes = numLightProbes; - - hash.directionalLength = directionalLength; - hash.pointLength = pointLength; - hash.spotLength = spotLength; - hash.rectAreaLength = rectAreaLength; - hash.hemiLength = hemiLength; - - hash.numDirectionalShadows = numDirectionalShadows; - hash.numPointShadows = numPointShadows; - hash.numSpotShadows = numSpotShadows; - hash.numSpotMaps = numSpotMaps; - - hash.numLightProbes = numLightProbes; - - state.version = nextVersion ++; - - } - - } - - function setupView( lights, camera ) { - - let directionalLength = 0; - let pointLength = 0; - let spotLength = 0; - let rectAreaLength = 0; - let hemiLength = 0; - - const viewMatrix = camera.matrixWorldInverse; - - for ( let i = 0, l = lights.length; i < l; i ++ ) { - - const light = lights[ i ]; - - if ( light.isDirectionalLight ) { - - const uniforms = state.directional[ directionalLength ]; - - uniforms.direction.setFromMatrixPosition( light.matrixWorld ); - vector3.setFromMatrixPosition( light.target.matrixWorld ); - uniforms.direction.sub( vector3 ); - uniforms.direction.transformDirection( viewMatrix ); - - directionalLength ++; - - } else if ( light.isSpotLight ) { - - const uniforms = state.spot[ spotLength ]; - - uniforms.position.setFromMatrixPosition( light.matrixWorld ); - uniforms.position.applyMatrix4( viewMatrix ); - - uniforms.direction.setFromMatrixPosition( light.matrixWorld ); - vector3.setFromMatrixPosition( light.target.matrixWorld ); - uniforms.direction.sub( vector3 ); - uniforms.direction.transformDirection( viewMatrix ); - - spotLength ++; - - } else if ( light.isRectAreaLight ) { - - const uniforms = state.rectArea[ rectAreaLength ]; - - uniforms.position.setFromMatrixPosition( light.matrixWorld ); - uniforms.position.applyMatrix4( viewMatrix ); - - // extract local rotation of light to derive width/height half vectors - matrix42.identity(); - matrix4.copy( light.matrixWorld ); - matrix4.premultiply( viewMatrix ); - matrix42.extractRotation( matrix4 ); - - uniforms.halfWidth.set( light.width * 0.5, 0.0, 0.0 ); - uniforms.halfHeight.set( 0.0, light.height * 0.5, 0.0 ); - - uniforms.halfWidth.applyMatrix4( matrix42 ); - uniforms.halfHeight.applyMatrix4( matrix42 ); - - rectAreaLength ++; - - } else if ( light.isPointLight ) { - - const uniforms = state.point[ pointLength ]; - - uniforms.position.setFromMatrixPosition( light.matrixWorld ); - uniforms.position.applyMatrix4( viewMatrix ); - - pointLength ++; - - } else if ( light.isHemisphereLight ) { - - const uniforms = state.hemi[ hemiLength ]; - - uniforms.direction.setFromMatrixPosition( light.matrixWorld ); - uniforms.direction.transformDirection( viewMatrix ); - - hemiLength ++; - - } - - } - - } - - return { - setup: setup, - setupView: setupView, - state: state - }; - -} - -function WebGLRenderState( extensions, capabilities ) { - - const lights = new WebGLLights( extensions, capabilities ); - - const lightsArray = []; - const shadowsArray = []; - - function init() { - - lightsArray.length = 0; - shadowsArray.length = 0; - - } - - function pushLight( light ) { - - lightsArray.push( light ); - - } - - function pushShadow( shadowLight ) { - - shadowsArray.push( shadowLight ); - - } - - function setupLights( useLegacyLights ) { - - lights.setup( lightsArray, useLegacyLights ); - - } - - function setupLightsView( camera ) { - - lights.setupView( lightsArray, camera ); - - } - - const state = { - lightsArray: lightsArray, - shadowsArray: shadowsArray, - - lights: lights - }; - - return { - init: init, - state: state, - setupLights: setupLights, - setupLightsView: setupLightsView, - - pushLight: pushLight, - pushShadow: pushShadow - }; - -} - -function WebGLRenderStates( extensions, capabilities ) { - - let renderStates = new WeakMap(); - - function get( scene, renderCallDepth = 0 ) { - - const renderStateArray = renderStates.get( scene ); - let renderState; - - if ( renderStateArray === undefined ) { - - renderState = new WebGLRenderState( extensions, capabilities ); - renderStates.set( scene, [ renderState ] ); - - } else { - - if ( renderCallDepth >= renderStateArray.length ) { - - renderState = new WebGLRenderState( extensions, capabilities ); - renderStateArray.push( renderState ); - - } else { - - renderState = renderStateArray[ renderCallDepth ]; - - } - - } - - return renderState; - - } - - function dispose() { - - renderStates = new WeakMap(); - - } - - return { - get: get, - dispose: dispose - }; - -} - -class MeshDepthMaterial extends Material { - - constructor( parameters ) { - - super(); - - this.isMeshDepthMaterial = true; - - this.type = 'MeshDepthMaterial'; - - this.depthPacking = BasicDepthPacking; - - this.map = null; - - this.alphaMap = null; - - this.displacementMap = null; - this.displacementScale = 1; - this.displacementBias = 0; - - this.wireframe = false; - this.wireframeLinewidth = 1; - - this.setValues( parameters ); - - } - - copy( source ) { - - super.copy( source ); - - this.depthPacking = source.depthPacking; - - this.map = source.map; - - this.alphaMap = source.alphaMap; - - this.displacementMap = source.displacementMap; - this.displacementScale = source.displacementScale; - this.displacementBias = source.displacementBias; - - this.wireframe = source.wireframe; - this.wireframeLinewidth = source.wireframeLinewidth; - - return this; - - } - -} - -class MeshDistanceMaterial extends Material { - - constructor( parameters ) { - - super(); - - this.isMeshDistanceMaterial = true; - - this.type = 'MeshDistanceMaterial'; - - this.map = null; - - this.alphaMap = null; - - this.displacementMap = null; - this.displacementScale = 1; - this.displacementBias = 0; - - this.setValues( parameters ); - - } - - copy( source ) { - - super.copy( source ); - - this.map = source.map; - - this.alphaMap = source.alphaMap; - - this.displacementMap = source.displacementMap; - this.displacementScale = source.displacementScale; - this.displacementBias = source.displacementBias; - - return this; - - } - -} - -const vertex = "void main() {\n\tgl_Position = vec4( position, 1.0 );\n}"; - -const fragment = "uniform sampler2D shadow_pass;\nuniform vec2 resolution;\nuniform float radius;\n#include \nvoid main() {\n\tconst float samples = float( VSM_SAMPLES );\n\tfloat mean = 0.0;\n\tfloat squared_mean = 0.0;\n\tfloat uvStride = samples <= 1.0 ? 0.0 : 2.0 / ( samples - 1.0 );\n\tfloat uvStart = samples <= 1.0 ? 0.0 : - 1.0;\n\tfor ( float i = 0.0; i < samples; i ++ ) {\n\t\tfloat uvOffset = uvStart + i * uvStride;\n\t\t#ifdef HORIZONTAL_PASS\n\t\t\tvec2 distribution = unpackRGBATo2Half( texture2D( shadow_pass, ( gl_FragCoord.xy + vec2( uvOffset, 0.0 ) * radius ) / resolution ) );\n\t\t\tmean += distribution.x;\n\t\t\tsquared_mean += distribution.y * distribution.y + distribution.x * distribution.x;\n\t\t#else\n\t\t\tfloat depth = unpackRGBAToDepth( texture2D( shadow_pass, ( gl_FragCoord.xy + vec2( 0.0, uvOffset ) * radius ) / resolution ) );\n\t\t\tmean += depth;\n\t\t\tsquared_mean += depth * depth;\n\t\t#endif\n\t}\n\tmean = mean / samples;\n\tsquared_mean = squared_mean / samples;\n\tfloat std_dev = sqrt( squared_mean - mean * mean );\n\tgl_FragColor = pack2HalfToRGBA( vec2( mean, std_dev ) );\n}"; - -function WebGLShadowMap( _renderer, _objects, _capabilities ) { - - let _frustum = new Frustum(); - - const _shadowMapSize = new Vector2(), - _viewportSize = new Vector2(), - - _viewport = new Vector4(), - - _depthMaterial = new MeshDepthMaterial( { depthPacking: RGBADepthPacking } ), - _distanceMaterial = new MeshDistanceMaterial(), - - _materialCache = {}, - - _maxTextureSize = _capabilities.maxTextureSize; - - const shadowSide = { [ FrontSide ]: BackSide, [ BackSide ]: FrontSide, [ DoubleSide ]: DoubleSide }; - - const shadowMaterialVertical = new ShaderMaterial( { - defines: { - VSM_SAMPLES: 8 - }, - uniforms: { - shadow_pass: { value: null }, - resolution: { value: new Vector2() }, - radius: { value: 4.0 } - }, - - vertexShader: vertex, - fragmentShader: fragment - - } ); - - const shadowMaterialHorizontal = shadowMaterialVertical.clone(); - shadowMaterialHorizontal.defines.HORIZONTAL_PASS = 1; - - const fullScreenTri = new BufferGeometry(); - fullScreenTri.setAttribute( - 'position', - new BufferAttribute( - new Float32Array( [ - 1, - 1, 0.5, 3, - 1, 0.5, - 1, 3, 0.5 ] ), - 3 - ) - ); - - const fullScreenMesh = new Mesh( fullScreenTri, shadowMaterialVertical ); - - const scope = this; - - this.enabled = false; - - this.autoUpdate = true; - this.needsUpdate = false; - - this.type = PCFShadowMap; - let _previousType = this.type; - - this.render = function ( lights, scene, camera ) { - - if ( scope.enabled === false ) return; - if ( scope.autoUpdate === false && scope.needsUpdate === false ) return; - - if ( lights.length === 0 ) return; - - const currentRenderTarget = _renderer.getRenderTarget(); - const activeCubeFace = _renderer.getActiveCubeFace(); - const activeMipmapLevel = _renderer.getActiveMipmapLevel(); - - const _state = _renderer.state; - - // Set GL state for depth map. - _state.setBlending( NoBlending ); - _state.buffers.color.setClear( 1, 1, 1, 1 ); - _state.buffers.depth.setTest( true ); - _state.setScissorTest( false ); - - // check for shadow map type changes - - const toVSM = ( _previousType !== VSMShadowMap && this.type === VSMShadowMap ); - const fromVSM = ( _previousType === VSMShadowMap && this.type !== VSMShadowMap ); - - // render depth map - - for ( let i = 0, il = lights.length; i < il; i ++ ) { - - const light = lights[ i ]; - const shadow = light.shadow; - - if ( shadow === undefined ) { - - console.warn( 'THREE.WebGLShadowMap:', light, 'has no shadow.' ); - continue; - - } - - if ( shadow.autoUpdate === false && shadow.needsUpdate === false ) continue; - - _shadowMapSize.copy( shadow.mapSize ); - - const shadowFrameExtents = shadow.getFrameExtents(); - - _shadowMapSize.multiply( shadowFrameExtents ); - - _viewportSize.copy( shadow.mapSize ); - - if ( _shadowMapSize.x > _maxTextureSize || _shadowMapSize.y > _maxTextureSize ) { - - if ( _shadowMapSize.x > _maxTextureSize ) { - - _viewportSize.x = Math.floor( _maxTextureSize / shadowFrameExtents.x ); - _shadowMapSize.x = _viewportSize.x * shadowFrameExtents.x; - shadow.mapSize.x = _viewportSize.x; - - } - - if ( _shadowMapSize.y > _maxTextureSize ) { - - _viewportSize.y = Math.floor( _maxTextureSize / shadowFrameExtents.y ); - _shadowMapSize.y = _viewportSize.y * shadowFrameExtents.y; - shadow.mapSize.y = _viewportSize.y; - - } - - } - - if ( shadow.map === null || toVSM === true || fromVSM === true ) { - - const pars = ( this.type !== VSMShadowMap ) ? { minFilter: NearestFilter, magFilter: NearestFilter } : {}; - - if ( shadow.map !== null ) { - - shadow.map.dispose(); - - } - - shadow.map = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y, pars ); - shadow.map.texture.name = light.name + '.shadowMap'; - - shadow.camera.updateProjectionMatrix(); - - } - - _renderer.setRenderTarget( shadow.map ); - _renderer.clear(); - - const viewportCount = shadow.getViewportCount(); - - for ( let vp = 0; vp < viewportCount; vp ++ ) { - - const viewport = shadow.getViewport( vp ); - - _viewport.set( - _viewportSize.x * viewport.x, - _viewportSize.y * viewport.y, - _viewportSize.x * viewport.z, - _viewportSize.y * viewport.w - ); - - _state.viewport( _viewport ); - - shadow.updateMatrices( light, vp ); - - _frustum = shadow.getFrustum(); - - renderObject( scene, camera, shadow.camera, light, this.type ); - - } - - // do blur pass for VSM - - if ( shadow.isPointLightShadow !== true && this.type === VSMShadowMap ) { - - VSMPass( shadow, camera ); - - } - - shadow.needsUpdate = false; - - } - - _previousType = this.type; - - scope.needsUpdate = false; - - _renderer.setRenderTarget( currentRenderTarget, activeCubeFace, activeMipmapLevel ); - - }; - - function VSMPass( shadow, camera ) { - - const geometry = _objects.update( fullScreenMesh ); - - if ( shadowMaterialVertical.defines.VSM_SAMPLES !== shadow.blurSamples ) { - - shadowMaterialVertical.defines.VSM_SAMPLES = shadow.blurSamples; - shadowMaterialHorizontal.defines.VSM_SAMPLES = shadow.blurSamples; - - shadowMaterialVertical.needsUpdate = true; - shadowMaterialHorizontal.needsUpdate = true; - - } - - if ( shadow.mapPass === null ) { - - shadow.mapPass = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y ); - - } - - // vertical pass - - shadowMaterialVertical.uniforms.shadow_pass.value = shadow.map.texture; - shadowMaterialVertical.uniforms.resolution.value = shadow.mapSize; - shadowMaterialVertical.uniforms.radius.value = shadow.radius; - _renderer.setRenderTarget( shadow.mapPass ); - _renderer.clear(); - _renderer.renderBufferDirect( camera, null, geometry, shadowMaterialVertical, fullScreenMesh, null ); - - // horizontal pass - - shadowMaterialHorizontal.uniforms.shadow_pass.value = shadow.mapPass.texture; - shadowMaterialHorizontal.uniforms.resolution.value = shadow.mapSize; - shadowMaterialHorizontal.uniforms.radius.value = shadow.radius; - _renderer.setRenderTarget( shadow.map ); - _renderer.clear(); - _renderer.renderBufferDirect( camera, null, geometry, shadowMaterialHorizontal, fullScreenMesh, null ); - - } - - function getDepthMaterial( object, material, light, type ) { - - let result = null; - - const customMaterial = ( light.isPointLight === true ) ? object.customDistanceMaterial : object.customDepthMaterial; - - if ( customMaterial !== undefined ) { - - result = customMaterial; - - } else { - - result = ( light.isPointLight === true ) ? _distanceMaterial : _depthMaterial; - - if ( ( _renderer.localClippingEnabled && material.clipShadows === true && Array.isArray( material.clippingPlanes ) && material.clippingPlanes.length !== 0 ) || - ( material.displacementMap && material.displacementScale !== 0 ) || - ( material.alphaMap && material.alphaTest > 0 ) || - ( material.map && material.alphaTest > 0 ) ) { - - // in this case we need a unique material instance reflecting the - // appropriate state - - const keyA = result.uuid, keyB = material.uuid; - - let materialsForVariant = _materialCache[ keyA ]; - - if ( materialsForVariant === undefined ) { - - materialsForVariant = {}; - _materialCache[ keyA ] = materialsForVariant; - - } - - let cachedMaterial = materialsForVariant[ keyB ]; - - if ( cachedMaterial === undefined ) { - - cachedMaterial = result.clone(); - materialsForVariant[ keyB ] = cachedMaterial; - material.addEventListener( 'dispose', onMaterialDispose ); - - } - - result = cachedMaterial; - - } - - } - - result.visible = material.visible; - result.wireframe = material.wireframe; - - if ( type === VSMShadowMap ) { - - result.side = ( material.shadowSide !== null ) ? material.shadowSide : material.side; - - } else { - - result.side = ( material.shadowSide !== null ) ? material.shadowSide : shadowSide[ material.side ]; - - } - - result.alphaMap = material.alphaMap; - result.alphaTest = material.alphaTest; - result.map = material.map; - - result.clipShadows = material.clipShadows; - result.clippingPlanes = material.clippingPlanes; - result.clipIntersection = material.clipIntersection; - - result.displacementMap = material.displacementMap; - result.displacementScale = material.displacementScale; - result.displacementBias = material.displacementBias; - - result.wireframeLinewidth = material.wireframeLinewidth; - result.linewidth = material.linewidth; - - if ( light.isPointLight === true && result.isMeshDistanceMaterial === true ) { - - const materialProperties = _renderer.properties.get( result ); - materialProperties.light = light; - - } - - return result; - - } - - function renderObject( object, camera, shadowCamera, light, type ) { - - if ( object.visible === false ) return; - - const visible = object.layers.test( camera.layers ); - - if ( visible && ( object.isMesh || object.isLine || object.isPoints ) ) { - - if ( ( object.castShadow || ( object.receiveShadow && type === VSMShadowMap ) ) && ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) ) { - - object.modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld ); - - const geometry = _objects.update( object ); - const material = object.material; - - if ( Array.isArray( material ) ) { - - const groups = geometry.groups; - - for ( let k = 0, kl = groups.length; k < kl; k ++ ) { - - const group = groups[ k ]; - const groupMaterial = material[ group.materialIndex ]; - - if ( groupMaterial && groupMaterial.visible ) { - - const depthMaterial = getDepthMaterial( object, groupMaterial, light, type ); - - object.onBeforeShadow( _renderer, object, camera, shadowCamera, geometry, depthMaterial, group ); - - _renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, group ); - - object.onAfterShadow( _renderer, object, camera, shadowCamera, geometry, depthMaterial, group ); - - } - - } - - } else if ( material.visible ) { - - const depthMaterial = getDepthMaterial( object, material, light, type ); - - object.onBeforeShadow( _renderer, object, camera, shadowCamera, geometry, depthMaterial, null ); - - _renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, null ); - - object.onAfterShadow( _renderer, object, camera, shadowCamera, geometry, depthMaterial, null ); - - } - - } - - } - - const children = object.children; - - for ( let i = 0, l = children.length; i < l; i ++ ) { - - renderObject( children[ i ], camera, shadowCamera, light, type ); - - } - - } - - function onMaterialDispose( event ) { - - const material = event.target; - - material.removeEventListener( 'dispose', onMaterialDispose ); - - // make sure to remove the unique distance/depth materials used for shadow map rendering - - for ( const id in _materialCache ) { - - const cache = _materialCache[ id ]; - - const uuid = event.target.uuid; - - if ( uuid in cache ) { - - const shadowMaterial = cache[ uuid ]; - shadowMaterial.dispose(); - delete cache[ uuid ]; - - } - - } - - } - -} - -function WebGLState( gl, extensions, capabilities ) { - - const isWebGL2 = capabilities.isWebGL2; - - function ColorBuffer() { - - let locked = false; - - const color = new Vector4(); - let currentColorMask = null; - const currentColorClear = new Vector4( 0, 0, 0, 0 ); - - return { - - setMask: function ( colorMask ) { - - if ( currentColorMask !== colorMask && ! locked ) { - - gl.colorMask( colorMask, colorMask, colorMask, colorMask ); - currentColorMask = colorMask; - - } - - }, - - setLocked: function ( lock ) { - - locked = lock; - - }, - - setClear: function ( r, g, b, a, premultipliedAlpha ) { - - if ( premultipliedAlpha === true ) { - - r *= a; g *= a; b *= a; - - } - - color.set( r, g, b, a ); - - if ( currentColorClear.equals( color ) === false ) { - - gl.clearColor( r, g, b, a ); - currentColorClear.copy( color ); - - } - - }, - - reset: function () { - - locked = false; - - currentColorMask = null; - currentColorClear.set( - 1, 0, 0, 0 ); // set to invalid state - - } - - }; - - } - - function DepthBuffer() { - - let locked = false; - - let currentDepthMask = null; - let currentDepthFunc = null; - let currentDepthClear = null; - - return { - - setTest: function ( depthTest ) { - - if ( depthTest ) { - - enable( gl.DEPTH_TEST ); - - } else { - - disable( gl.DEPTH_TEST ); - - } - - }, - - setMask: function ( depthMask ) { - - if ( currentDepthMask !== depthMask && ! locked ) { - - gl.depthMask( depthMask ); - currentDepthMask = depthMask; - - } - - }, - - setFunc: function ( depthFunc ) { - - if ( currentDepthFunc !== depthFunc ) { - - switch ( depthFunc ) { - - case NeverDepth: - - gl.depthFunc( gl.NEVER ); - break; - - case AlwaysDepth: - - gl.depthFunc( gl.ALWAYS ); - break; - - case LessDepth: - - gl.depthFunc( gl.LESS ); - break; - - case LessEqualDepth: - - gl.depthFunc( gl.LEQUAL ); - break; - - case EqualDepth: - - gl.depthFunc( gl.EQUAL ); - break; - - case GreaterEqualDepth: - - gl.depthFunc( gl.GEQUAL ); - break; - - case GreaterDepth: - - gl.depthFunc( gl.GREATER ); - break; - - case NotEqualDepth: - - gl.depthFunc( gl.NOTEQUAL ); - break; - - default: - - gl.depthFunc( gl.LEQUAL ); - - } - - currentDepthFunc = depthFunc; - - } - - }, - - setLocked: function ( lock ) { - - locked = lock; - - }, - - setClear: function ( depth ) { - - if ( currentDepthClear !== depth ) { - - gl.clearDepth( depth ); - currentDepthClear = depth; - - } - - }, - - reset: function () { - - locked = false; - - currentDepthMask = null; - currentDepthFunc = null; - currentDepthClear = null; - - } - - }; - - } - - function StencilBuffer() { - - let locked = false; - - let currentStencilMask = null; - let currentStencilFunc = null; - let currentStencilRef = null; - let currentStencilFuncMask = null; - let currentStencilFail = null; - let currentStencilZFail = null; - let currentStencilZPass = null; - let currentStencilClear = null; - - return { - - setTest: function ( stencilTest ) { - - if ( ! locked ) { - - if ( stencilTest ) { - - enable( gl.STENCIL_TEST ); - - } else { - - disable( gl.STENCIL_TEST ); - - } - - } - - }, - - setMask: function ( stencilMask ) { - - if ( currentStencilMask !== stencilMask && ! locked ) { - - gl.stencilMask( stencilMask ); - currentStencilMask = stencilMask; - - } - - }, - - setFunc: function ( stencilFunc, stencilRef, stencilMask ) { - - if ( currentStencilFunc !== stencilFunc || - currentStencilRef !== stencilRef || - currentStencilFuncMask !== stencilMask ) { - - gl.stencilFunc( stencilFunc, stencilRef, stencilMask ); - - currentStencilFunc = stencilFunc; - currentStencilRef = stencilRef; - currentStencilFuncMask = stencilMask; - - } - - }, - - setOp: function ( stencilFail, stencilZFail, stencilZPass ) { - - if ( currentStencilFail !== stencilFail || - currentStencilZFail !== stencilZFail || - currentStencilZPass !== stencilZPass ) { - - gl.stencilOp( stencilFail, stencilZFail, stencilZPass ); - - currentStencilFail = stencilFail; - currentStencilZFail = stencilZFail; - currentStencilZPass = stencilZPass; - - } - - }, - - setLocked: function ( lock ) { - - locked = lock; - - }, - - setClear: function ( stencil ) { - - if ( currentStencilClear !== stencil ) { - - gl.clearStencil( stencil ); - currentStencilClear = stencil; - - } - - }, - - reset: function () { - - locked = false; - - currentStencilMask = null; - currentStencilFunc = null; - currentStencilRef = null; - currentStencilFuncMask = null; - currentStencilFail = null; - currentStencilZFail = null; - currentStencilZPass = null; - currentStencilClear = null; - - } - - }; - - } - - // - - const colorBuffer = new ColorBuffer(); - const depthBuffer = new DepthBuffer(); - const stencilBuffer = new StencilBuffer(); - - const uboBindings = new WeakMap(); - const uboProgramMap = new WeakMap(); - - let enabledCapabilities = {}; - - let currentBoundFramebuffers = {}; - let currentDrawbuffers = new WeakMap(); - let defaultDrawbuffers = []; - - let currentProgram = null; - - let currentBlendingEnabled = false; - let currentBlending = null; - let currentBlendEquation = null; - let currentBlendSrc = null; - let currentBlendDst = null; - let currentBlendEquationAlpha = null; - let currentBlendSrcAlpha = null; - let currentBlendDstAlpha = null; - let currentBlendColor = new Color( 0, 0, 0 ); - let currentBlendAlpha = 0; - let currentPremultipledAlpha = false; - - let currentFlipSided = null; - let currentCullFace = null; - - let currentLineWidth = null; - - let currentPolygonOffsetFactor = null; - let currentPolygonOffsetUnits = null; - - const maxTextures = gl.getParameter( gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS ); - - let lineWidthAvailable = false; - let version = 0; - const glVersion = gl.getParameter( gl.VERSION ); - - if ( glVersion.indexOf( 'WebGL' ) !== - 1 ) { - - version = parseFloat( /^WebGL (\d)/.exec( glVersion )[ 1 ] ); - lineWidthAvailable = ( version >= 1.0 ); - - } else if ( glVersion.indexOf( 'OpenGL ES' ) !== - 1 ) { - - version = parseFloat( /^OpenGL ES (\d)/.exec( glVersion )[ 1 ] ); - lineWidthAvailable = ( version >= 2.0 ); - - } - - let currentTextureSlot = null; - let currentBoundTextures = {}; - - const scissorParam = gl.getParameter( gl.SCISSOR_BOX ); - const viewportParam = gl.getParameter( gl.VIEWPORT ); - - const currentScissor = new Vector4().fromArray( scissorParam ); - const currentViewport = new Vector4().fromArray( viewportParam ); - - function createTexture( type, target, count, dimensions ) { - - const data = new Uint8Array( 4 ); // 4 is required to match default unpack alignment of 4. - const texture = gl.createTexture(); - - gl.bindTexture( type, texture ); - gl.texParameteri( type, gl.TEXTURE_MIN_FILTER, gl.NEAREST ); - gl.texParameteri( type, gl.TEXTURE_MAG_FILTER, gl.NEAREST ); - - for ( let i = 0; i < count; i ++ ) { - - if ( isWebGL2 && ( type === gl.TEXTURE_3D || type === gl.TEXTURE_2D_ARRAY ) ) { - - gl.texImage3D( target, 0, gl.RGBA, 1, 1, dimensions, 0, gl.RGBA, gl.UNSIGNED_BYTE, data ); - - } else { - - gl.texImage2D( target + i, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, data ); - - } - - } - - return texture; - - } - - const emptyTextures = {}; - emptyTextures[ gl.TEXTURE_2D ] = createTexture( gl.TEXTURE_2D, gl.TEXTURE_2D, 1 ); - emptyTextures[ gl.TEXTURE_CUBE_MAP ] = createTexture( gl.TEXTURE_CUBE_MAP, gl.TEXTURE_CUBE_MAP_POSITIVE_X, 6 ); - - if ( isWebGL2 ) { - - emptyTextures[ gl.TEXTURE_2D_ARRAY ] = createTexture( gl.TEXTURE_2D_ARRAY, gl.TEXTURE_2D_ARRAY, 1, 1 ); - emptyTextures[ gl.TEXTURE_3D ] = createTexture( gl.TEXTURE_3D, gl.TEXTURE_3D, 1, 1 ); - - } - - // init - - colorBuffer.setClear( 0, 0, 0, 1 ); - depthBuffer.setClear( 1 ); - stencilBuffer.setClear( 0 ); - - enable( gl.DEPTH_TEST ); - depthBuffer.setFunc( LessEqualDepth ); - - setFlipSided( false ); - setCullFace( CullFaceBack ); - enable( gl.CULL_FACE ); - - setBlending( NoBlending ); - - // - - function enable( id ) { - - if ( enabledCapabilities[ id ] !== true ) { - - gl.enable( id ); - enabledCapabilities[ id ] = true; - - } - - } - - function disable( id ) { - - if ( enabledCapabilities[ id ] !== false ) { - - gl.disable( id ); - enabledCapabilities[ id ] = false; - - } - - } - - function bindFramebuffer( target, framebuffer ) { - - if ( currentBoundFramebuffers[ target ] !== framebuffer ) { - - gl.bindFramebuffer( target, framebuffer ); - - currentBoundFramebuffers[ target ] = framebuffer; - - if ( isWebGL2 ) { - - // gl.DRAW_FRAMEBUFFER is equivalent to gl.FRAMEBUFFER - - if ( target === gl.DRAW_FRAMEBUFFER ) { - - currentBoundFramebuffers[ gl.FRAMEBUFFER ] = framebuffer; - - } - - if ( target === gl.FRAMEBUFFER ) { - - currentBoundFramebuffers[ gl.DRAW_FRAMEBUFFER ] = framebuffer; - - } - - } - - return true; - - } - - return false; - - } - - function drawBuffers( renderTarget, framebuffer ) { - - let drawBuffers = defaultDrawbuffers; - - let needsUpdate = false; - - if ( renderTarget ) { - - drawBuffers = currentDrawbuffers.get( framebuffer ); - - if ( drawBuffers === undefined ) { - - drawBuffers = []; - currentDrawbuffers.set( framebuffer, drawBuffers ); - - } - - if ( renderTarget.isWebGLMultipleRenderTargets ) { - - const textures = renderTarget.texture; - - if ( drawBuffers.length !== textures.length || drawBuffers[ 0 ] !== gl.COLOR_ATTACHMENT0 ) { - - for ( let i = 0, il = textures.length; i < il; i ++ ) { - - drawBuffers[ i ] = gl.COLOR_ATTACHMENT0 + i; - - } - - drawBuffers.length = textures.length; - - needsUpdate = true; - - } - - } else { - - if ( drawBuffers[ 0 ] !== gl.COLOR_ATTACHMENT0 ) { - - drawBuffers[ 0 ] = gl.COLOR_ATTACHMENT0; - - needsUpdate = true; - - } - - } - - } else { - - if ( drawBuffers[ 0 ] !== gl.BACK ) { - - drawBuffers[ 0 ] = gl.BACK; - - needsUpdate = true; - - } - - } - - if ( needsUpdate ) { - - if ( capabilities.isWebGL2 ) { - - gl.drawBuffers( drawBuffers ); - - } else { - - extensions.get( 'WEBGL_draw_buffers' ).drawBuffersWEBGL( drawBuffers ); - - } - - } - - - } - - function useProgram( program ) { - - if ( currentProgram !== program ) { - - gl.useProgram( program ); - - currentProgram = program; - - return true; - - } - - return false; - - } - - const equationToGL = { - [ AddEquation ]: gl.FUNC_ADD, - [ SubtractEquation ]: gl.FUNC_SUBTRACT, - [ ReverseSubtractEquation ]: gl.FUNC_REVERSE_SUBTRACT - }; - - if ( isWebGL2 ) { - - equationToGL[ MinEquation ] = gl.MIN; - equationToGL[ MaxEquation ] = gl.MAX; - - } else { - - const extension = extensions.get( 'EXT_blend_minmax' ); - - if ( extension !== null ) { - - equationToGL[ MinEquation ] = extension.MIN_EXT; - equationToGL[ MaxEquation ] = extension.MAX_EXT; - - } - - } - - const factorToGL = { - [ ZeroFactor ]: gl.ZERO, - [ OneFactor ]: gl.ONE, - [ SrcColorFactor ]: gl.SRC_COLOR, - [ SrcAlphaFactor ]: gl.SRC_ALPHA, - [ SrcAlphaSaturateFactor ]: gl.SRC_ALPHA_SATURATE, - [ DstColorFactor ]: gl.DST_COLOR, - [ DstAlphaFactor ]: gl.DST_ALPHA, - [ OneMinusSrcColorFactor ]: gl.ONE_MINUS_SRC_COLOR, - [ OneMinusSrcAlphaFactor ]: gl.ONE_MINUS_SRC_ALPHA, - [ OneMinusDstColorFactor ]: gl.ONE_MINUS_DST_COLOR, - [ OneMinusDstAlphaFactor ]: gl.ONE_MINUS_DST_ALPHA, - [ ConstantColorFactor ]: gl.CONSTANT_COLOR, - [ OneMinusConstantColorFactor ]: gl.ONE_MINUS_CONSTANT_COLOR, - [ ConstantAlphaFactor ]: gl.CONSTANT_ALPHA, - [ OneMinusConstantAlphaFactor ]: gl.ONE_MINUS_CONSTANT_ALPHA - }; - - function setBlending( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha, blendColor, blendAlpha, premultipliedAlpha ) { - - if ( blending === NoBlending ) { - - if ( currentBlendingEnabled === true ) { - - disable( gl.BLEND ); - currentBlendingEnabled = false; - - } - - return; - - } - - if ( currentBlendingEnabled === false ) { - - enable( gl.BLEND ); - currentBlendingEnabled = true; - - } - - if ( blending !== CustomBlending ) { - - if ( blending !== currentBlending || premultipliedAlpha !== currentPremultipledAlpha ) { - - if ( currentBlendEquation !== AddEquation || currentBlendEquationAlpha !== AddEquation ) { - - gl.blendEquation( gl.FUNC_ADD ); - - currentBlendEquation = AddEquation; - currentBlendEquationAlpha = AddEquation; - - } - - if ( premultipliedAlpha ) { - - switch ( blending ) { - - case NormalBlending: - gl.blendFuncSeparate( gl.ONE, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA ); - break; - - case AdditiveBlending: - gl.blendFunc( gl.ONE, gl.ONE ); - break; - - case SubtractiveBlending: - gl.blendFuncSeparate( gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ZERO, gl.ONE ); - break; - - case MultiplyBlending: - gl.blendFuncSeparate( gl.ZERO, gl.SRC_COLOR, gl.ZERO, gl.SRC_ALPHA ); - break; - - default: - console.error( 'THREE.WebGLState: Invalid blending: ', blending ); - break; - - } - - } else { - - switch ( blending ) { - - case NormalBlending: - gl.blendFuncSeparate( gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA ); - break; - - case AdditiveBlending: - gl.blendFunc( gl.SRC_ALPHA, gl.ONE ); - break; - - case SubtractiveBlending: - gl.blendFuncSeparate( gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ZERO, gl.ONE ); - break; - - case MultiplyBlending: - gl.blendFunc( gl.ZERO, gl.SRC_COLOR ); - break; - - default: - console.error( 'THREE.WebGLState: Invalid blending: ', blending ); - break; - - } - - } - - currentBlendSrc = null; - currentBlendDst = null; - currentBlendSrcAlpha = null; - currentBlendDstAlpha = null; - currentBlendColor.set( 0, 0, 0 ); - currentBlendAlpha = 0; - - currentBlending = blending; - currentPremultipledAlpha = premultipliedAlpha; - - } - - return; - - } - - // custom blending - - blendEquationAlpha = blendEquationAlpha || blendEquation; - blendSrcAlpha = blendSrcAlpha || blendSrc; - blendDstAlpha = blendDstAlpha || blendDst; - - if ( blendEquation !== currentBlendEquation || blendEquationAlpha !== currentBlendEquationAlpha ) { - - gl.blendEquationSeparate( equationToGL[ blendEquation ], equationToGL[ blendEquationAlpha ] ); - - currentBlendEquation = blendEquation; - currentBlendEquationAlpha = blendEquationAlpha; - - } - - if ( blendSrc !== currentBlendSrc || blendDst !== currentBlendDst || blendSrcAlpha !== currentBlendSrcAlpha || blendDstAlpha !== currentBlendDstAlpha ) { - - gl.blendFuncSeparate( factorToGL[ blendSrc ], factorToGL[ blendDst ], factorToGL[ blendSrcAlpha ], factorToGL[ blendDstAlpha ] ); - - currentBlendSrc = blendSrc; - currentBlendDst = blendDst; - currentBlendSrcAlpha = blendSrcAlpha; - currentBlendDstAlpha = blendDstAlpha; - - } - - if ( blendColor.equals( currentBlendColor ) === false || blendAlpha !== currentBlendAlpha ) { - - gl.blendColor( blendColor.r, blendColor.g, blendColor.b, blendAlpha ); - - currentBlendColor.copy( blendColor ); - currentBlendAlpha = blendAlpha; - - } - - currentBlending = blending; - currentPremultipledAlpha = false; - - } - - function setMaterial( material, frontFaceCW ) { - - material.side === DoubleSide - ? disable( gl.CULL_FACE ) - : enable( gl.CULL_FACE ); - - let flipSided = ( material.side === BackSide ); - if ( frontFaceCW ) flipSided = ! flipSided; - - setFlipSided( flipSided ); - - ( material.blending === NormalBlending && material.transparent === false ) - ? setBlending( NoBlending ) - : setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.blendColor, material.blendAlpha, material.premultipliedAlpha ); - - depthBuffer.setFunc( material.depthFunc ); - depthBuffer.setTest( material.depthTest ); - depthBuffer.setMask( material.depthWrite ); - colorBuffer.setMask( material.colorWrite ); - - const stencilWrite = material.stencilWrite; - stencilBuffer.setTest( stencilWrite ); - if ( stencilWrite ) { - - stencilBuffer.setMask( material.stencilWriteMask ); - stencilBuffer.setFunc( material.stencilFunc, material.stencilRef, material.stencilFuncMask ); - stencilBuffer.setOp( material.stencilFail, material.stencilZFail, material.stencilZPass ); - - } - - setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits ); - - material.alphaToCoverage === true - ? enable( gl.SAMPLE_ALPHA_TO_COVERAGE ) - : disable( gl.SAMPLE_ALPHA_TO_COVERAGE ); - - } - - // - - function setFlipSided( flipSided ) { - - if ( currentFlipSided !== flipSided ) { - - if ( flipSided ) { - - gl.frontFace( gl.CW ); - - } else { - - gl.frontFace( gl.CCW ); - - } - - currentFlipSided = flipSided; - - } - - } - - function setCullFace( cullFace ) { - - if ( cullFace !== CullFaceNone ) { - - enable( gl.CULL_FACE ); - - if ( cullFace !== currentCullFace ) { - - if ( cullFace === CullFaceBack ) { - - gl.cullFace( gl.BACK ); - - } else if ( cullFace === CullFaceFront ) { - - gl.cullFace( gl.FRONT ); - - } else { - - gl.cullFace( gl.FRONT_AND_BACK ); - - } - - } - - } else { - - disable( gl.CULL_FACE ); - - } - - currentCullFace = cullFace; - - } - - function setLineWidth( width ) { - - if ( width !== currentLineWidth ) { - - if ( lineWidthAvailable ) gl.lineWidth( width ); - - currentLineWidth = width; - - } - - } - - function setPolygonOffset( polygonOffset, factor, units ) { - - if ( polygonOffset ) { - - enable( gl.POLYGON_OFFSET_FILL ); - - if ( currentPolygonOffsetFactor !== factor || currentPolygonOffsetUnits !== units ) { - - gl.polygonOffset( factor, units ); - - currentPolygonOffsetFactor = factor; - currentPolygonOffsetUnits = units; - - } - - } else { - - disable( gl.POLYGON_OFFSET_FILL ); - - } - - } - - function setScissorTest( scissorTest ) { - - if ( scissorTest ) { - - enable( gl.SCISSOR_TEST ); - - } else { - - disable( gl.SCISSOR_TEST ); - - } - - } - - // texture - - function activeTexture( webglSlot ) { - - if ( webglSlot === undefined ) webglSlot = gl.TEXTURE0 + maxTextures - 1; - - if ( currentTextureSlot !== webglSlot ) { - - gl.activeTexture( webglSlot ); - currentTextureSlot = webglSlot; - - } - - } - - function bindTexture( webglType, webglTexture, webglSlot ) { - - if ( webglSlot === undefined ) { - - if ( currentTextureSlot === null ) { - - webglSlot = gl.TEXTURE0 + maxTextures - 1; - - } else { - - webglSlot = currentTextureSlot; - - } - - } - - let boundTexture = currentBoundTextures[ webglSlot ]; - - if ( boundTexture === undefined ) { - - boundTexture = { type: undefined, texture: undefined }; - currentBoundTextures[ webglSlot ] = boundTexture; - - } - - if ( boundTexture.type !== webglType || boundTexture.texture !== webglTexture ) { - - if ( currentTextureSlot !== webglSlot ) { - - gl.activeTexture( webglSlot ); - currentTextureSlot = webglSlot; - - } - - gl.bindTexture( webglType, webglTexture || emptyTextures[ webglType ] ); - - boundTexture.type = webglType; - boundTexture.texture = webglTexture; - - } - - } - - function unbindTexture() { - - const boundTexture = currentBoundTextures[ currentTextureSlot ]; - - if ( boundTexture !== undefined && boundTexture.type !== undefined ) { - - gl.bindTexture( boundTexture.type, null ); - - boundTexture.type = undefined; - boundTexture.texture = undefined; - - } - - } - - function compressedTexImage2D() { - - try { - - gl.compressedTexImage2D.apply( gl, arguments ); - - } catch ( error ) { - - console.error( 'THREE.WebGLState:', error ); - - } - - } - - function compressedTexImage3D() { - - try { - - gl.compressedTexImage3D.apply( gl, arguments ); - - } catch ( error ) { - - console.error( 'THREE.WebGLState:', error ); - - } - - } - - function texSubImage2D() { - - try { - - gl.texSubImage2D.apply( gl, arguments ); - - } catch ( error ) { - - console.error( 'THREE.WebGLState:', error ); - - } - - } - - function texSubImage3D() { - - try { - - gl.texSubImage3D.apply( gl, arguments ); - - } catch ( error ) { - - console.error( 'THREE.WebGLState:', error ); - - } - - } - - function compressedTexSubImage2D() { - - try { - - gl.compressedTexSubImage2D.apply( gl, arguments ); - - } catch ( error ) { - - console.error( 'THREE.WebGLState:', error ); - - } - - } - - function compressedTexSubImage3D() { - - try { - - gl.compressedTexSubImage3D.apply( gl, arguments ); - - } catch ( error ) { - - console.error( 'THREE.WebGLState:', error ); - - } - - } - - function texStorage2D() { - - try { - - gl.texStorage2D.apply( gl, arguments ); - - } catch ( error ) { - - console.error( 'THREE.WebGLState:', error ); - - } - - } - - function texStorage3D() { - - try { - - gl.texStorage3D.apply( gl, arguments ); - - } catch ( error ) { - - console.error( 'THREE.WebGLState:', error ); - - } - - } - - function texImage2D() { - - try { - - gl.texImage2D.apply( gl, arguments ); - - } catch ( error ) { - - console.error( 'THREE.WebGLState:', error ); - - } - - } - - function texImage3D() { - - try { - - gl.texImage3D.apply( gl, arguments ); - - } catch ( error ) { - - console.error( 'THREE.WebGLState:', error ); - - } - - } - - // - - function scissor( scissor ) { - - if ( currentScissor.equals( scissor ) === false ) { - - gl.scissor( scissor.x, scissor.y, scissor.z, scissor.w ); - currentScissor.copy( scissor ); - - } - - } - - function viewport( viewport ) { - - if ( currentViewport.equals( viewport ) === false ) { - - gl.viewport( viewport.x, viewport.y, viewport.z, viewport.w ); - currentViewport.copy( viewport ); - - } - - } - - function updateUBOMapping( uniformsGroup, program ) { - - let mapping = uboProgramMap.get( program ); - - if ( mapping === undefined ) { - - mapping = new WeakMap(); - - uboProgramMap.set( program, mapping ); - - } - - let blockIndex = mapping.get( uniformsGroup ); - - if ( blockIndex === undefined ) { - - blockIndex = gl.getUniformBlockIndex( program, uniformsGroup.name ); - - mapping.set( uniformsGroup, blockIndex ); - - } - - } - - function uniformBlockBinding( uniformsGroup, program ) { - - const mapping = uboProgramMap.get( program ); - const blockIndex = mapping.get( uniformsGroup ); - - if ( uboBindings.get( program ) !== blockIndex ) { - - // bind shader specific block index to global block point - gl.uniformBlockBinding( program, blockIndex, uniformsGroup.__bindingPointIndex ); - - uboBindings.set( program, blockIndex ); - - } - - } - - // - - function reset() { - - // reset state - - gl.disable( gl.BLEND ); - gl.disable( gl.CULL_FACE ); - gl.disable( gl.DEPTH_TEST ); - gl.disable( gl.POLYGON_OFFSET_FILL ); - gl.disable( gl.SCISSOR_TEST ); - gl.disable( gl.STENCIL_TEST ); - gl.disable( gl.SAMPLE_ALPHA_TO_COVERAGE ); - - gl.blendEquation( gl.FUNC_ADD ); - gl.blendFunc( gl.ONE, gl.ZERO ); - gl.blendFuncSeparate( gl.ONE, gl.ZERO, gl.ONE, gl.ZERO ); - gl.blendColor( 0, 0, 0, 0 ); - - gl.colorMask( true, true, true, true ); - gl.clearColor( 0, 0, 0, 0 ); - - gl.depthMask( true ); - gl.depthFunc( gl.LESS ); - gl.clearDepth( 1 ); - - gl.stencilMask( 0xffffffff ); - gl.stencilFunc( gl.ALWAYS, 0, 0xffffffff ); - gl.stencilOp( gl.KEEP, gl.KEEP, gl.KEEP ); - gl.clearStencil( 0 ); - - gl.cullFace( gl.BACK ); - gl.frontFace( gl.CCW ); - - gl.polygonOffset( 0, 0 ); - - gl.activeTexture( gl.TEXTURE0 ); - - gl.bindFramebuffer( gl.FRAMEBUFFER, null ); - - if ( isWebGL2 === true ) { - - gl.bindFramebuffer( gl.DRAW_FRAMEBUFFER, null ); - gl.bindFramebuffer( gl.READ_FRAMEBUFFER, null ); - - } - - gl.useProgram( null ); - - gl.lineWidth( 1 ); - - gl.scissor( 0, 0, gl.canvas.width, gl.canvas.height ); - gl.viewport( 0, 0, gl.canvas.width, gl.canvas.height ); - - // reset internals - - enabledCapabilities = {}; - - currentTextureSlot = null; - currentBoundTextures = {}; - - currentBoundFramebuffers = {}; - currentDrawbuffers = new WeakMap(); - defaultDrawbuffers = []; - - currentProgram = null; - - currentBlendingEnabled = false; - currentBlending = null; - currentBlendEquation = null; - currentBlendSrc = null; - currentBlendDst = null; - currentBlendEquationAlpha = null; - currentBlendSrcAlpha = null; - currentBlendDstAlpha = null; - currentBlendColor = new Color( 0, 0, 0 ); - currentBlendAlpha = 0; - currentPremultipledAlpha = false; - - currentFlipSided = null; - currentCullFace = null; - - currentLineWidth = null; - - currentPolygonOffsetFactor = null; - currentPolygonOffsetUnits = null; - - currentScissor.set( 0, 0, gl.canvas.width, gl.canvas.height ); - currentViewport.set( 0, 0, gl.canvas.width, gl.canvas.height ); - - colorBuffer.reset(); - depthBuffer.reset(); - stencilBuffer.reset(); - - } - - return { - - buffers: { - color: colorBuffer, - depth: depthBuffer, - stencil: stencilBuffer - }, - - enable: enable, - disable: disable, - - bindFramebuffer: bindFramebuffer, - drawBuffers: drawBuffers, - - useProgram: useProgram, - - setBlending: setBlending, - setMaterial: setMaterial, - - setFlipSided: setFlipSided, - setCullFace: setCullFace, - - setLineWidth: setLineWidth, - setPolygonOffset: setPolygonOffset, - - setScissorTest: setScissorTest, - - activeTexture: activeTexture, - bindTexture: bindTexture, - unbindTexture: unbindTexture, - compressedTexImage2D: compressedTexImage2D, - compressedTexImage3D: compressedTexImage3D, - texImage2D: texImage2D, - texImage3D: texImage3D, - - updateUBOMapping: updateUBOMapping, - uniformBlockBinding: uniformBlockBinding, - - texStorage2D: texStorage2D, - texStorage3D: texStorage3D, - texSubImage2D: texSubImage2D, - texSubImage3D: texSubImage3D, - compressedTexSubImage2D: compressedTexSubImage2D, - compressedTexSubImage3D: compressedTexSubImage3D, - - scissor: scissor, - viewport: viewport, - - reset: reset - - }; - -} - -function WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info ) { - - const isWebGL2 = capabilities.isWebGL2; - const multisampledRTTExt = extensions.has( 'WEBGL_multisampled_render_to_texture' ) ? extensions.get( 'WEBGL_multisampled_render_to_texture' ) : null; - const supportsInvalidateFramebuffer = typeof navigator === 'undefined' ? false : /OculusBrowser/g.test( navigator.userAgent ); - - const _videoTextures = new WeakMap(); - let _canvas; - - const _sources = new WeakMap(); // maps WebglTexture objects to instances of Source - - // cordova iOS (as of 5.0) still uses UIWebView, which provides OffscreenCanvas, - // also OffscreenCanvas.getContext("webgl"), but not OffscreenCanvas.getContext("2d")! - // Some implementations may only implement OffscreenCanvas partially (e.g. lacking 2d). - - let useOffscreenCanvas = false; - - try { - - useOffscreenCanvas = typeof OffscreenCanvas !== 'undefined' - // eslint-disable-next-line compat/compat - && ( new OffscreenCanvas( 1, 1 ).getContext( '2d' ) ) !== null; - - } catch ( err ) { - - // Ignore any errors - - } - - function createCanvas( width, height ) { - - // Use OffscreenCanvas when available. Specially needed in web workers - - return useOffscreenCanvas ? - // eslint-disable-next-line compat/compat - new OffscreenCanvas( width, height ) : createElementNS( 'canvas' ); - - } - - function resizeImage( image, needsPowerOfTwo, needsNewCanvas, maxSize ) { - - let scale = 1; - - // handle case if texture exceeds max size - - if ( image.width > maxSize || image.height > maxSize ) { - - scale = maxSize / Math.max( image.width, image.height ); - - } - - // only perform resize if necessary - - if ( scale < 1 || needsPowerOfTwo === true ) { - - // only perform resize for certain image types - - if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) || - ( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) || - ( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) { - - const floor = needsPowerOfTwo ? floorPowerOfTwo : Math.floor; - - const width = floor( scale * image.width ); - const height = floor( scale * image.height ); - - if ( _canvas === undefined ) _canvas = createCanvas( width, height ); - - // cube textures can't reuse the same canvas - - const canvas = needsNewCanvas ? createCanvas( width, height ) : _canvas; - - canvas.width = width; - canvas.height = height; - - const context = canvas.getContext( '2d' ); - context.drawImage( image, 0, 0, width, height ); - - console.warn( 'THREE.WebGLRenderer: Texture has been resized from (' + image.width + 'x' + image.height + ') to (' + width + 'x' + height + ').' ); - - return canvas; - - } else { - - if ( 'data' in image ) { - - console.warn( 'THREE.WebGLRenderer: Image in DataTexture is too big (' + image.width + 'x' + image.height + ').' ); - - } - - return image; - - } - - } - - return image; - - } - - function isPowerOfTwo$1( image ) { - - return isPowerOfTwo( image.width ) && isPowerOfTwo( image.height ); - - } - - function textureNeedsPowerOfTwo( texture ) { - - if ( isWebGL2 ) return false; - - return ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) || - ( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ); - - } - - function textureNeedsGenerateMipmaps( texture, supportsMips ) { - - return texture.generateMipmaps && supportsMips && - texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter; - - } - - function generateMipmap( target ) { - - _gl.generateMipmap( target ); - - } - - function getInternalFormat( internalFormatName, glFormat, glType, colorSpace, forceLinearTransfer = false ) { - - if ( isWebGL2 === false ) return glFormat; - - if ( internalFormatName !== null ) { - - if ( _gl[ internalFormatName ] !== undefined ) return _gl[ internalFormatName ]; - - console.warn( 'THREE.WebGLRenderer: Attempt to use non-existing WebGL internal format \'' + internalFormatName + '\'' ); - - } - - let internalFormat = glFormat; - - if ( glFormat === _gl.RED ) { - - if ( glType === _gl.FLOAT ) internalFormat = _gl.R32F; - if ( glType === _gl.HALF_FLOAT ) internalFormat = _gl.R16F; - if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.R8; - - } - - if ( glFormat === _gl.RED_INTEGER ) { - - if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.R8UI; - if ( glType === _gl.UNSIGNED_SHORT ) internalFormat = _gl.R16UI; - if ( glType === _gl.UNSIGNED_INT ) internalFormat = _gl.R32UI; - if ( glType === _gl.BYTE ) internalFormat = _gl.R8I; - if ( glType === _gl.SHORT ) internalFormat = _gl.R16I; - if ( glType === _gl.INT ) internalFormat = _gl.R32I; - - } - - if ( glFormat === _gl.RG ) { - - if ( glType === _gl.FLOAT ) internalFormat = _gl.RG32F; - if ( glType === _gl.HALF_FLOAT ) internalFormat = _gl.RG16F; - if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.RG8; - - } - - if ( glFormat === _gl.RGBA ) { - - const transfer = forceLinearTransfer ? LinearTransfer : ColorManagement.getTransfer( colorSpace ); - - if ( glType === _gl.FLOAT ) internalFormat = _gl.RGBA32F; - if ( glType === _gl.HALF_FLOAT ) internalFormat = _gl.RGBA16F; - if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = ( transfer === SRGBTransfer ) ? _gl.SRGB8_ALPHA8 : _gl.RGBA8; - if ( glType === _gl.UNSIGNED_SHORT_4_4_4_4 ) internalFormat = _gl.RGBA4; - if ( glType === _gl.UNSIGNED_SHORT_5_5_5_1 ) internalFormat = _gl.RGB5_A1; - - } - - if ( internalFormat === _gl.R16F || internalFormat === _gl.R32F || - internalFormat === _gl.RG16F || internalFormat === _gl.RG32F || - internalFormat === _gl.RGBA16F || internalFormat === _gl.RGBA32F ) { - - extensions.get( 'EXT_color_buffer_float' ); - - } - - return internalFormat; - - } - - function getMipLevels( texture, image, supportsMips ) { - - if ( textureNeedsGenerateMipmaps( texture, supportsMips ) === true || ( texture.isFramebufferTexture && texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ) ) { - - return Math.log2( Math.max( image.width, image.height ) ) + 1; - - } else if ( texture.mipmaps !== undefined && texture.mipmaps.length > 0 ) { - - // user-defined mipmaps - - return texture.mipmaps.length; - - } else if ( texture.isCompressedTexture && Array.isArray( texture.image ) ) { - - return image.mipmaps.length; - - } else { - - // texture without mipmaps (only base level) - - return 1; - - } - - } - - // Fallback filters for non-power-of-2 textures - - function filterFallback( f ) { - - if ( f === NearestFilter || f === NearestMipmapNearestFilter || f === NearestMipmapLinearFilter ) { - - return _gl.NEAREST; - - } - - return _gl.LINEAR; - - } - - // - - function onTextureDispose( event ) { - - const texture = event.target; - - texture.removeEventListener( 'dispose', onTextureDispose ); - - deallocateTexture( texture ); - - if ( texture.isVideoTexture ) { - - _videoTextures.delete( texture ); - - } - - } - - function onRenderTargetDispose( event ) { - - const renderTarget = event.target; - - renderTarget.removeEventListener( 'dispose', onRenderTargetDispose ); - - deallocateRenderTarget( renderTarget ); - - } - - // - - function deallocateTexture( texture ) { - - const textureProperties = properties.get( texture ); - - if ( textureProperties.__webglInit === undefined ) return; - - // check if it's necessary to remove the WebGLTexture object - - const source = texture.source; - const webglTextures = _sources.get( source ); - - if ( webglTextures ) { - - const webglTexture = webglTextures[ textureProperties.__cacheKey ]; - webglTexture.usedTimes --; - - // the WebGLTexture object is not used anymore, remove it - - if ( webglTexture.usedTimes === 0 ) { - - deleteTexture( texture ); - - } - - // remove the weak map entry if no WebGLTexture uses the source anymore - - if ( Object.keys( webglTextures ).length === 0 ) { - - _sources.delete( source ); - - } - - } - - properties.remove( texture ); - - } - - function deleteTexture( texture ) { - - const textureProperties = properties.get( texture ); - _gl.deleteTexture( textureProperties.__webglTexture ); - - const source = texture.source; - const webglTextures = _sources.get( source ); - delete webglTextures[ textureProperties.__cacheKey ]; - - info.memory.textures --; - - } - - function deallocateRenderTarget( renderTarget ) { - - const texture = renderTarget.texture; - - const renderTargetProperties = properties.get( renderTarget ); - const textureProperties = properties.get( texture ); - - if ( textureProperties.__webglTexture !== undefined ) { - - _gl.deleteTexture( textureProperties.__webglTexture ); - - info.memory.textures --; - - } - - if ( renderTarget.depthTexture ) { - - renderTarget.depthTexture.dispose(); - - } - - if ( renderTarget.isWebGLCubeRenderTarget ) { - - for ( let i = 0; i < 6; i ++ ) { - - if ( Array.isArray( renderTargetProperties.__webglFramebuffer[ i ] ) ) { - - for ( let level = 0; level < renderTargetProperties.__webglFramebuffer[ i ].length; level ++ ) _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ i ][ level ] ); - - } else { - - _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ i ] ); - - } - - if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer[ i ] ); - - } - - } else { - - if ( Array.isArray( renderTargetProperties.__webglFramebuffer ) ) { - - for ( let level = 0; level < renderTargetProperties.__webglFramebuffer.length; level ++ ) _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ level ] ); - - } else { - - _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer ); - - } - - if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer ); - if ( renderTargetProperties.__webglMultisampledFramebuffer ) _gl.deleteFramebuffer( renderTargetProperties.__webglMultisampledFramebuffer ); - - if ( renderTargetProperties.__webglColorRenderbuffer ) { - - for ( let i = 0; i < renderTargetProperties.__webglColorRenderbuffer.length; i ++ ) { - - if ( renderTargetProperties.__webglColorRenderbuffer[ i ] ) _gl.deleteRenderbuffer( renderTargetProperties.__webglColorRenderbuffer[ i ] ); - - } - - } - - if ( renderTargetProperties.__webglDepthRenderbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthRenderbuffer ); - - } - - if ( renderTarget.isWebGLMultipleRenderTargets ) { - - for ( let i = 0, il = texture.length; i < il; i ++ ) { - - const attachmentProperties = properties.get( texture[ i ] ); - - if ( attachmentProperties.__webglTexture ) { - - _gl.deleteTexture( attachmentProperties.__webglTexture ); - - info.memory.textures --; - - } - - properties.remove( texture[ i ] ); - - } - - } - - properties.remove( texture ); - properties.remove( renderTarget ); - - } - - // - - let textureUnits = 0; - - function resetTextureUnits() { - - textureUnits = 0; - - } - - function allocateTextureUnit() { - - const textureUnit = textureUnits; - - if ( textureUnit >= capabilities.maxTextures ) { - - console.warn( 'THREE.WebGLTextures: Trying to use ' + textureUnit + ' texture units while this GPU supports only ' + capabilities.maxTextures ); - - } - - textureUnits += 1; - - return textureUnit; - - } - - function getTextureCacheKey( texture ) { - - const array = []; - - array.push( texture.wrapS ); - array.push( texture.wrapT ); - array.push( texture.wrapR || 0 ); - array.push( texture.magFilter ); - array.push( texture.minFilter ); - array.push( texture.anisotropy ); - array.push( texture.internalFormat ); - array.push( texture.format ); - array.push( texture.type ); - array.push( texture.generateMipmaps ); - array.push( texture.premultiplyAlpha ); - array.push( texture.flipY ); - array.push( texture.unpackAlignment ); - array.push( texture.colorSpace ); - - return array.join(); - - } - - // - - function setTexture2D( texture, slot ) { - - const textureProperties = properties.get( texture ); - - if ( texture.isVideoTexture ) updateVideoTexture( texture ); - - if ( texture.isRenderTargetTexture === false && texture.version > 0 && textureProperties.__version !== texture.version ) { - - const image = texture.image; - - if ( image === null ) { - - console.warn( 'THREE.WebGLRenderer: Texture marked for update but no image data found.' ); - - } else if ( image.complete === false ) { - - console.warn( 'THREE.WebGLRenderer: Texture marked for update but image is incomplete' ); - - } else { - - uploadTexture( textureProperties, texture, slot ); - return; - - } - - } - - state.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture, _gl.TEXTURE0 + slot ); - - } - - function setTexture2DArray( texture, slot ) { - - const textureProperties = properties.get( texture ); - - if ( texture.version > 0 && textureProperties.__version !== texture.version ) { - - uploadTexture( textureProperties, texture, slot ); - return; - - } - - state.bindTexture( _gl.TEXTURE_2D_ARRAY, textureProperties.__webglTexture, _gl.TEXTURE0 + slot ); - - } - - function setTexture3D( texture, slot ) { - - const textureProperties = properties.get( texture ); - - if ( texture.version > 0 && textureProperties.__version !== texture.version ) { - - uploadTexture( textureProperties, texture, slot ); - return; - - } - - state.bindTexture( _gl.TEXTURE_3D, textureProperties.__webglTexture, _gl.TEXTURE0 + slot ); - - } - - function setTextureCube( texture, slot ) { - - const textureProperties = properties.get( texture ); - - if ( texture.version > 0 && textureProperties.__version !== texture.version ) { - - uploadCubeTexture( textureProperties, texture, slot ); - return; - - } - - state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture, _gl.TEXTURE0 + slot ); - - } - - const wrappingToGL = { - [ RepeatWrapping ]: _gl.REPEAT, - [ ClampToEdgeWrapping ]: _gl.CLAMP_TO_EDGE, - [ MirroredRepeatWrapping ]: _gl.MIRRORED_REPEAT - }; - - const filterToGL = { - [ NearestFilter ]: _gl.NEAREST, - [ NearestMipmapNearestFilter ]: _gl.NEAREST_MIPMAP_NEAREST, - [ NearestMipmapLinearFilter ]: _gl.NEAREST_MIPMAP_LINEAR, - - [ LinearFilter ]: _gl.LINEAR, - [ LinearMipmapNearestFilter ]: _gl.LINEAR_MIPMAP_NEAREST, - [ LinearMipmapLinearFilter ]: _gl.LINEAR_MIPMAP_LINEAR - }; - - const compareToGL = { - [ NeverCompare ]: _gl.NEVER, - [ AlwaysCompare ]: _gl.ALWAYS, - [ LessCompare ]: _gl.LESS, - [ LessEqualCompare ]: _gl.LEQUAL, - [ EqualCompare ]: _gl.EQUAL, - [ GreaterEqualCompare ]: _gl.GEQUAL, - [ GreaterCompare ]: _gl.GREATER, - [ NotEqualCompare ]: _gl.NOTEQUAL - }; - - function setTextureParameters( textureType, texture, supportsMips ) { - - if ( texture.type === FloatType && extensions.has( 'OES_texture_float_linear' ) === false && - ( texture.magFilter === LinearFilter || texture.magFilter === LinearMipmapNearestFilter || texture.magFilter === NearestMipmapLinearFilter || texture.magFilter === LinearMipmapLinearFilter || - texture.minFilter === LinearFilter || texture.minFilter === LinearMipmapNearestFilter || texture.minFilter === NearestMipmapLinearFilter || texture.minFilter === LinearMipmapLinearFilter ) ) { - - console.warn( 'THREE.WebGLRenderer: Unable to use linear filtering with floating point textures. OES_texture_float_linear not supported on this device.' ); - - } - - if ( supportsMips ) { - - _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, wrappingToGL[ texture.wrapS ] ); - _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, wrappingToGL[ texture.wrapT ] ); - - if ( textureType === _gl.TEXTURE_3D || textureType === _gl.TEXTURE_2D_ARRAY ) { - - _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_R, wrappingToGL[ texture.wrapR ] ); - - } - - _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterToGL[ texture.magFilter ] ); - _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterToGL[ texture.minFilter ] ); - - } else { - - _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE ); - _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE ); - - if ( textureType === _gl.TEXTURE_3D || textureType === _gl.TEXTURE_2D_ARRAY ) { - - _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_R, _gl.CLAMP_TO_EDGE ); - - } - - if ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) { - - console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.wrapS and Texture.wrapT should be set to THREE.ClampToEdgeWrapping.' ); - - } - - _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterFallback( texture.magFilter ) ); - _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterFallback( texture.minFilter ) ); - - if ( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ) { - - console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.minFilter should be set to THREE.NearestFilter or THREE.LinearFilter.' ); - - } - - } - - if ( texture.compareFunction ) { - - _gl.texParameteri( textureType, _gl.TEXTURE_COMPARE_MODE, _gl.COMPARE_REF_TO_TEXTURE ); - _gl.texParameteri( textureType, _gl.TEXTURE_COMPARE_FUNC, compareToGL[ texture.compareFunction ] ); - - } - - if ( extensions.has( 'EXT_texture_filter_anisotropic' ) === true ) { - - const extension = extensions.get( 'EXT_texture_filter_anisotropic' ); - - if ( texture.magFilter === NearestFilter ) return; - if ( texture.minFilter !== NearestMipmapLinearFilter && texture.minFilter !== LinearMipmapLinearFilter ) return; - if ( texture.type === FloatType && extensions.has( 'OES_texture_float_linear' ) === false ) return; // verify extension for WebGL 1 and WebGL 2 - if ( isWebGL2 === false && ( texture.type === HalfFloatType && extensions.has( 'OES_texture_half_float_linear' ) === false ) ) return; // verify extension for WebGL 1 only - - if ( texture.anisotropy > 1 || properties.get( texture ).__currentAnisotropy ) { - - _gl.texParameterf( textureType, extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, capabilities.getMaxAnisotropy() ) ); - properties.get( texture ).__currentAnisotropy = texture.anisotropy; - - } - - } - - } - - function initTexture( textureProperties, texture ) { - - let forceUpload = false; - - if ( textureProperties.__webglInit === undefined ) { - - textureProperties.__webglInit = true; - - texture.addEventListener( 'dispose', onTextureDispose ); - - } - - // create Source <-> WebGLTextures mapping if necessary - - const source = texture.source; - let webglTextures = _sources.get( source ); - - if ( webglTextures === undefined ) { - - webglTextures = {}; - _sources.set( source, webglTextures ); - - } - - // check if there is already a WebGLTexture object for the given texture parameters - - const textureCacheKey = getTextureCacheKey( texture ); - - if ( textureCacheKey !== textureProperties.__cacheKey ) { - - // if not, create a new instance of WebGLTexture - - if ( webglTextures[ textureCacheKey ] === undefined ) { - - // create new entry - - webglTextures[ textureCacheKey ] = { - texture: _gl.createTexture(), - usedTimes: 0 - }; - - info.memory.textures ++; - - // when a new instance of WebGLTexture was created, a texture upload is required - // even if the image contents are identical - - forceUpload = true; - - } - - webglTextures[ textureCacheKey ].usedTimes ++; - - // every time the texture cache key changes, it's necessary to check if an instance of - // WebGLTexture can be deleted in order to avoid a memory leak. - - const webglTexture = webglTextures[ textureProperties.__cacheKey ]; - - if ( webglTexture !== undefined ) { - - webglTextures[ textureProperties.__cacheKey ].usedTimes --; - - if ( webglTexture.usedTimes === 0 ) { - - deleteTexture( texture ); - - } - - } - - // store references to cache key and WebGLTexture object - - textureProperties.__cacheKey = textureCacheKey; - textureProperties.__webglTexture = webglTextures[ textureCacheKey ].texture; - - } - - return forceUpload; - - } - - function uploadTexture( textureProperties, texture, slot ) { - - let textureType = _gl.TEXTURE_2D; - - if ( texture.isDataArrayTexture || texture.isCompressedArrayTexture ) textureType = _gl.TEXTURE_2D_ARRAY; - if ( texture.isData3DTexture ) textureType = _gl.TEXTURE_3D; - - const forceUpload = initTexture( textureProperties, texture ); - const source = texture.source; - - state.bindTexture( textureType, textureProperties.__webglTexture, _gl.TEXTURE0 + slot ); - - const sourceProperties = properties.get( source ); - - if ( source.version !== sourceProperties.__version || forceUpload === true ) { - - state.activeTexture( _gl.TEXTURE0 + slot ); - - const workingPrimaries = ColorManagement.getPrimaries( ColorManagement.workingColorSpace ); - const texturePrimaries = texture.colorSpace === NoColorSpace ? null : ColorManagement.getPrimaries( texture.colorSpace ); - const unpackConversion = texture.colorSpace === NoColorSpace || workingPrimaries === texturePrimaries ? _gl.NONE : _gl.BROWSER_DEFAULT_WEBGL; - - _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY ); - _gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha ); - _gl.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment ); - _gl.pixelStorei( _gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, unpackConversion ); - - const needsPowerOfTwo = textureNeedsPowerOfTwo( texture ) && isPowerOfTwo$1( texture.image ) === false; - let image = resizeImage( texture.image, needsPowerOfTwo, false, capabilities.maxTextureSize ); - image = verifyColorSpace( texture, image ); - - const supportsMips = isPowerOfTwo$1( image ) || isWebGL2, - glFormat = utils.convert( texture.format, texture.colorSpace ); - - let glType = utils.convert( texture.type ), - glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace, texture.isVideoTexture ); - - setTextureParameters( textureType, texture, supportsMips ); - - let mipmap; - const mipmaps = texture.mipmaps; - - const useTexStorage = ( isWebGL2 && texture.isVideoTexture !== true && glInternalFormat !== RGB_ETC1_Format ); - const allocateMemory = ( sourceProperties.__version === undefined ) || ( forceUpload === true ); - const dataReady = source.dataReady; - const levels = getMipLevels( texture, image, supportsMips ); - - if ( texture.isDepthTexture ) { - - // populate depth texture with dummy data - - glInternalFormat = _gl.DEPTH_COMPONENT; - - if ( isWebGL2 ) { - - if ( texture.type === FloatType ) { - - glInternalFormat = _gl.DEPTH_COMPONENT32F; - - } else if ( texture.type === UnsignedIntType ) { - - glInternalFormat = _gl.DEPTH_COMPONENT24; - - } else if ( texture.type === UnsignedInt248Type ) { - - glInternalFormat = _gl.DEPTH24_STENCIL8; - - } else { - - glInternalFormat = _gl.DEPTH_COMPONENT16; // WebGL2 requires sized internalformat for glTexImage2D - - } - - } else { - - if ( texture.type === FloatType ) { - - console.error( 'WebGLRenderer: Floating point depth texture requires WebGL2.' ); - - } - - } - - // validation checks for WebGL 1 - - if ( texture.format === DepthFormat && glInternalFormat === _gl.DEPTH_COMPONENT ) { - - // The error INVALID_OPERATION is generated by texImage2D if format and internalformat are - // DEPTH_COMPONENT and type is not UNSIGNED_SHORT or UNSIGNED_INT - // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/) - if ( texture.type !== UnsignedShortType && texture.type !== UnsignedIntType ) { - - console.warn( 'THREE.WebGLRenderer: Use UnsignedShortType or UnsignedIntType for DepthFormat DepthTexture.' ); - - texture.type = UnsignedIntType; - glType = utils.convert( texture.type ); - - } - - } - - if ( texture.format === DepthStencilFormat && glInternalFormat === _gl.DEPTH_COMPONENT ) { - - // Depth stencil textures need the DEPTH_STENCIL internal format - // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/) - glInternalFormat = _gl.DEPTH_STENCIL; - - // The error INVALID_OPERATION is generated by texImage2D if format and internalformat are - // DEPTH_STENCIL and type is not UNSIGNED_INT_24_8_WEBGL. - // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/) - if ( texture.type !== UnsignedInt248Type ) { - - console.warn( 'THREE.WebGLRenderer: Use UnsignedInt248Type for DepthStencilFormat DepthTexture.' ); - - texture.type = UnsignedInt248Type; - glType = utils.convert( texture.type ); - - } - - } - - // - - if ( allocateMemory ) { - - if ( useTexStorage ) { - - state.texStorage2D( _gl.TEXTURE_2D, 1, glInternalFormat, image.width, image.height ); - - } else { - - state.texImage2D( _gl.TEXTURE_2D, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, null ); - - } - - } - - } else if ( texture.isDataTexture ) { - - // use manually created mipmaps if available - // if there are no manual mipmaps - // set 0 level mipmap and then use GL to generate other mipmap levels - - if ( mipmaps.length > 0 && supportsMips ) { - - if ( useTexStorage && allocateMemory ) { - - state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height ); - - } - - for ( let i = 0, il = mipmaps.length; i < il; i ++ ) { - - mipmap = mipmaps[ i ]; - - if ( useTexStorage ) { - - if ( dataReady ) { - - state.texSubImage2D( _gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data ); - - } - - } else { - - state.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); - - } - - } - - texture.generateMipmaps = false; - - } else { - - if ( useTexStorage ) { - - if ( allocateMemory ) { - - state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, image.width, image.height ); - - } - - if ( dataReady ) { - - state.texSubImage2D( _gl.TEXTURE_2D, 0, 0, 0, image.width, image.height, glFormat, glType, image.data ); - - } - - } else { - - state.texImage2D( _gl.TEXTURE_2D, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, image.data ); - - } - - } - - } else if ( texture.isCompressedTexture ) { - - if ( texture.isCompressedArrayTexture ) { - - if ( useTexStorage && allocateMemory ) { - - state.texStorage3D( _gl.TEXTURE_2D_ARRAY, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height, image.depth ); - - } - - for ( let i = 0, il = mipmaps.length; i < il; i ++ ) { - - mipmap = mipmaps[ i ]; - - if ( texture.format !== RGBAFormat ) { - - if ( glFormat !== null ) { - - if ( useTexStorage ) { - - if ( dataReady ) { - - state.compressedTexSubImage3D( _gl.TEXTURE_2D_ARRAY, i, 0, 0, 0, mipmap.width, mipmap.height, image.depth, glFormat, mipmap.data, 0, 0 ); - - } - - } else { - - state.compressedTexImage3D( _gl.TEXTURE_2D_ARRAY, i, glInternalFormat, mipmap.width, mipmap.height, image.depth, 0, mipmap.data, 0, 0 ); - - } - - } else { - - console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()' ); - - } - - } else { - - if ( useTexStorage ) { - - if ( dataReady ) { - - state.texSubImage3D( _gl.TEXTURE_2D_ARRAY, i, 0, 0, 0, mipmap.width, mipmap.height, image.depth, glFormat, glType, mipmap.data ); - - } - - } else { - - state.texImage3D( _gl.TEXTURE_2D_ARRAY, i, glInternalFormat, mipmap.width, mipmap.height, image.depth, 0, glFormat, glType, mipmap.data ); - - } - - } - - } - - } else { - - if ( useTexStorage && allocateMemory ) { - - state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height ); - - } - - for ( let i = 0, il = mipmaps.length; i < il; i ++ ) { - - mipmap = mipmaps[ i ]; - - if ( texture.format !== RGBAFormat ) { - - if ( glFormat !== null ) { - - if ( useTexStorage ) { - - if ( dataReady ) { - - state.compressedTexSubImage2D( _gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, mipmap.data ); - - } - - } else { - - state.compressedTexImage2D( _gl.TEXTURE_2D, i, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data ); - - } - - } else { - - console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()' ); - - } - - } else { - - if ( useTexStorage ) { - - if ( dataReady ) { - - state.texSubImage2D( _gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data ); - - } - - } else { - - state.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); - - } - - } - - } - - } - - } else if ( texture.isDataArrayTexture ) { - - if ( useTexStorage ) { - - if ( allocateMemory ) { - - state.texStorage3D( _gl.TEXTURE_2D_ARRAY, levels, glInternalFormat, image.width, image.height, image.depth ); - - } - - if ( dataReady ) { - - state.texSubImage3D( _gl.TEXTURE_2D_ARRAY, 0, 0, 0, 0, image.width, image.height, image.depth, glFormat, glType, image.data ); - - } - - } else { - - state.texImage3D( _gl.TEXTURE_2D_ARRAY, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data ); - - } - - } else if ( texture.isData3DTexture ) { - - if ( useTexStorage ) { - - if ( allocateMemory ) { - - state.texStorage3D( _gl.TEXTURE_3D, levels, glInternalFormat, image.width, image.height, image.depth ); - - } - - if ( dataReady ) { - - state.texSubImage3D( _gl.TEXTURE_3D, 0, 0, 0, 0, image.width, image.height, image.depth, glFormat, glType, image.data ); - - } - - } else { - - state.texImage3D( _gl.TEXTURE_3D, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data ); - - } - - } else if ( texture.isFramebufferTexture ) { - - if ( allocateMemory ) { - - if ( useTexStorage ) { - - state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, image.width, image.height ); - - } else { - - let width = image.width, height = image.height; - - for ( let i = 0; i < levels; i ++ ) { - - state.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, width, height, 0, glFormat, glType, null ); - - width >>= 1; - height >>= 1; - - } - - } - - } - - } else { - - // regular Texture (image, video, canvas) - - // use manually created mipmaps if available - // if there are no manual mipmaps - // set 0 level mipmap and then use GL to generate other mipmap levels - - if ( mipmaps.length > 0 && supportsMips ) { - - if ( useTexStorage && allocateMemory ) { - - state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height ); - - } - - for ( let i = 0, il = mipmaps.length; i < il; i ++ ) { - - mipmap = mipmaps[ i ]; - - if ( useTexStorage ) { - - if ( dataReady ) { - - state.texSubImage2D( _gl.TEXTURE_2D, i, 0, 0, glFormat, glType, mipmap ); - - } - - } else { - - state.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, glFormat, glType, mipmap ); - - } - - } - - texture.generateMipmaps = false; - - } else { - - if ( useTexStorage ) { - - if ( allocateMemory ) { - - state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, image.width, image.height ); - - } - - if ( dataReady ) { - - state.texSubImage2D( _gl.TEXTURE_2D, 0, 0, 0, glFormat, glType, image ); - - } - - } else { - - state.texImage2D( _gl.TEXTURE_2D, 0, glInternalFormat, glFormat, glType, image ); - - } - - } - - } - - if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) { - - generateMipmap( textureType ); - - } - - sourceProperties.__version = source.version; - - if ( texture.onUpdate ) texture.onUpdate( texture ); - - } - - textureProperties.__version = texture.version; - - } - - function uploadCubeTexture( textureProperties, texture, slot ) { - - if ( texture.image.length !== 6 ) return; - - const forceUpload = initTexture( textureProperties, texture ); - const source = texture.source; - - state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture, _gl.TEXTURE0 + slot ); - - const sourceProperties = properties.get( source ); - - if ( source.version !== sourceProperties.__version || forceUpload === true ) { - - state.activeTexture( _gl.TEXTURE0 + slot ); - - const workingPrimaries = ColorManagement.getPrimaries( ColorManagement.workingColorSpace ); - const texturePrimaries = texture.colorSpace === NoColorSpace ? null : ColorManagement.getPrimaries( texture.colorSpace ); - const unpackConversion = texture.colorSpace === NoColorSpace || workingPrimaries === texturePrimaries ? _gl.NONE : _gl.BROWSER_DEFAULT_WEBGL; - - _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY ); - _gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha ); - _gl.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment ); - _gl.pixelStorei( _gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, unpackConversion ); - - const isCompressed = ( texture.isCompressedTexture || texture.image[ 0 ].isCompressedTexture ); - const isDataTexture = ( texture.image[ 0 ] && texture.image[ 0 ].isDataTexture ); - - const cubeImage = []; - - for ( let i = 0; i < 6; i ++ ) { - - if ( ! isCompressed && ! isDataTexture ) { - - cubeImage[ i ] = resizeImage( texture.image[ i ], false, true, capabilities.maxCubemapSize ); - - } else { - - cubeImage[ i ] = isDataTexture ? texture.image[ i ].image : texture.image[ i ]; - - } - - cubeImage[ i ] = verifyColorSpace( texture, cubeImage[ i ] ); - - } - - const image = cubeImage[ 0 ], - supportsMips = isPowerOfTwo$1( image ) || isWebGL2, - glFormat = utils.convert( texture.format, texture.colorSpace ), - glType = utils.convert( texture.type ), - glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace ); - - const useTexStorage = ( isWebGL2 && texture.isVideoTexture !== true ); - const allocateMemory = ( sourceProperties.__version === undefined ) || ( forceUpload === true ); - const dataReady = source.dataReady; - let levels = getMipLevels( texture, image, supportsMips ); - - setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture, supportsMips ); - - let mipmaps; - - if ( isCompressed ) { - - if ( useTexStorage && allocateMemory ) { - - state.texStorage2D( _gl.TEXTURE_CUBE_MAP, levels, glInternalFormat, image.width, image.height ); - - } - - for ( let i = 0; i < 6; i ++ ) { - - mipmaps = cubeImage[ i ].mipmaps; - - for ( let j = 0; j < mipmaps.length; j ++ ) { - - const mipmap = mipmaps[ j ]; - - if ( texture.format !== RGBAFormat ) { - - if ( glFormat !== null ) { - - if ( useTexStorage ) { - - if ( dataReady ) { - - state.compressedTexSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, 0, 0, mipmap.width, mipmap.height, glFormat, mipmap.data ); - - } - - } else { - - state.compressedTexImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data ); - - } - - } else { - - console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .setTextureCube()' ); - - } - - } else { - - if ( useTexStorage ) { - - if ( dataReady ) { - - state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data ); - - } - - } else { - - state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); - - } - - } - - } - - } - - } else { - - mipmaps = texture.mipmaps; - - if ( useTexStorage && allocateMemory ) { - - // TODO: Uniformly handle mipmap definitions - // Normal textures and compressed cube textures define base level + mips with their mipmap array - // Uncompressed cube textures use their mipmap array only for mips (no base level) - - if ( mipmaps.length > 0 ) levels ++; - - state.texStorage2D( _gl.TEXTURE_CUBE_MAP, levels, glInternalFormat, cubeImage[ 0 ].width, cubeImage[ 0 ].height ); - - } - - for ( let i = 0; i < 6; i ++ ) { - - if ( isDataTexture ) { - - if ( useTexStorage ) { - - if ( dataReady ) { - - state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, 0, 0, cubeImage[ i ].width, cubeImage[ i ].height, glFormat, glType, cubeImage[ i ].data ); - - } - - } else { - - state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glInternalFormat, cubeImage[ i ].width, cubeImage[ i ].height, 0, glFormat, glType, cubeImage[ i ].data ); - - } - - for ( let j = 0; j < mipmaps.length; j ++ ) { - - const mipmap = mipmaps[ j ]; - const mipmapImage = mipmap.image[ i ].image; - - if ( useTexStorage ) { - - if ( dataReady ) { - - state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, 0, 0, mipmapImage.width, mipmapImage.height, glFormat, glType, mipmapImage.data ); - - } - - } else { - - state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, glInternalFormat, mipmapImage.width, mipmapImage.height, 0, glFormat, glType, mipmapImage.data ); - - } - - } - - } else { - - if ( useTexStorage ) { - - if ( dataReady ) { - - state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, 0, 0, glFormat, glType, cubeImage[ i ] ); - - } - - } else { - - state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glInternalFormat, glFormat, glType, cubeImage[ i ] ); - - } - - for ( let j = 0; j < mipmaps.length; j ++ ) { - - const mipmap = mipmaps[ j ]; - - if ( useTexStorage ) { - - if ( dataReady ) { - - state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, 0, 0, glFormat, glType, mipmap.image[ i ] ); - - } - - } else { - - state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, glInternalFormat, glFormat, glType, mipmap.image[ i ] ); - - } - - } - - } - - } - - } - - if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) { - - // We assume images for cube map have the same size. - generateMipmap( _gl.TEXTURE_CUBE_MAP ); - - } - - sourceProperties.__version = source.version; - - if ( texture.onUpdate ) texture.onUpdate( texture ); - - } - - textureProperties.__version = texture.version; - - } - - // Render targets - - // Setup storage for target texture and bind it to correct framebuffer - function setupFrameBufferTexture( framebuffer, renderTarget, texture, attachment, textureTarget, level ) { - - const glFormat = utils.convert( texture.format, texture.colorSpace ); - const glType = utils.convert( texture.type ); - const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace ); - const renderTargetProperties = properties.get( renderTarget ); - - if ( ! renderTargetProperties.__hasExternalTextures ) { - - const width = Math.max( 1, renderTarget.width >> level ); - const height = Math.max( 1, renderTarget.height >> level ); - - if ( textureTarget === _gl.TEXTURE_3D || textureTarget === _gl.TEXTURE_2D_ARRAY ) { - - state.texImage3D( textureTarget, level, glInternalFormat, width, height, renderTarget.depth, 0, glFormat, glType, null ); - - } else { - - state.texImage2D( textureTarget, level, glInternalFormat, width, height, 0, glFormat, glType, null ); - - } - - } - - state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); - - if ( useMultisampledRTT( renderTarget ) ) { - - multisampledRTTExt.framebufferTexture2DMultisampleEXT( _gl.FRAMEBUFFER, attachment, textureTarget, properties.get( texture ).__webglTexture, 0, getRenderTargetSamples( renderTarget ) ); - - } else if ( textureTarget === _gl.TEXTURE_2D || ( textureTarget >= _gl.TEXTURE_CUBE_MAP_POSITIVE_X && textureTarget <= _gl.TEXTURE_CUBE_MAP_NEGATIVE_Z ) ) { // see #24753 - - _gl.framebufferTexture2D( _gl.FRAMEBUFFER, attachment, textureTarget, properties.get( texture ).__webglTexture, level ); - - } - - state.bindFramebuffer( _gl.FRAMEBUFFER, null ); - - } - - - // Setup storage for internal depth/stencil buffers and bind to correct framebuffer - function setupRenderBufferStorage( renderbuffer, renderTarget, isMultisample ) { - - _gl.bindRenderbuffer( _gl.RENDERBUFFER, renderbuffer ); - - if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) { - - let glInternalFormat = ( isWebGL2 === true ) ? _gl.DEPTH_COMPONENT24 : _gl.DEPTH_COMPONENT16; - - if ( isMultisample || useMultisampledRTT( renderTarget ) ) { - - const depthTexture = renderTarget.depthTexture; - - if ( depthTexture && depthTexture.isDepthTexture ) { - - if ( depthTexture.type === FloatType ) { - - glInternalFormat = _gl.DEPTH_COMPONENT32F; - - } else if ( depthTexture.type === UnsignedIntType ) { - - glInternalFormat = _gl.DEPTH_COMPONENT24; - - } - - } - - const samples = getRenderTargetSamples( renderTarget ); - - if ( useMultisampledRTT( renderTarget ) ) { - - multisampledRTTExt.renderbufferStorageMultisampleEXT( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height ); - - } else { - - _gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height ); - - } - - } else { - - _gl.renderbufferStorage( _gl.RENDERBUFFER, glInternalFormat, renderTarget.width, renderTarget.height ); - - } - - _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer ); - - } else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) { - - const samples = getRenderTargetSamples( renderTarget ); - - if ( isMultisample && useMultisampledRTT( renderTarget ) === false ) { - - _gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, _gl.DEPTH24_STENCIL8, renderTarget.width, renderTarget.height ); - - } else if ( useMultisampledRTT( renderTarget ) ) { - - multisampledRTTExt.renderbufferStorageMultisampleEXT( _gl.RENDERBUFFER, samples, _gl.DEPTH24_STENCIL8, renderTarget.width, renderTarget.height ); - - } else { - - _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_STENCIL, renderTarget.width, renderTarget.height ); - - } - - - _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer ); - - } else { - - const textures = renderTarget.isWebGLMultipleRenderTargets === true ? renderTarget.texture : [ renderTarget.texture ]; - - for ( let i = 0; i < textures.length; i ++ ) { - - const texture = textures[ i ]; - - const glFormat = utils.convert( texture.format, texture.colorSpace ); - const glType = utils.convert( texture.type ); - const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace ); - const samples = getRenderTargetSamples( renderTarget ); - - if ( isMultisample && useMultisampledRTT( renderTarget ) === false ) { - - _gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height ); - - } else if ( useMultisampledRTT( renderTarget ) ) { - - multisampledRTTExt.renderbufferStorageMultisampleEXT( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height ); - - } else { - - _gl.renderbufferStorage( _gl.RENDERBUFFER, glInternalFormat, renderTarget.width, renderTarget.height ); - - } - - } - - } - - _gl.bindRenderbuffer( _gl.RENDERBUFFER, null ); - - } - - // Setup resources for a Depth Texture for a FBO (needs an extension) - function setupDepthTexture( framebuffer, renderTarget ) { - - const isCube = ( renderTarget && renderTarget.isWebGLCubeRenderTarget ); - if ( isCube ) throw new Error( 'Depth Texture with cube render targets is not supported' ); - - state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); - - if ( ! ( renderTarget.depthTexture && renderTarget.depthTexture.isDepthTexture ) ) { - - throw new Error( 'renderTarget.depthTexture must be an instance of THREE.DepthTexture' ); - - } - - // upload an empty depth texture with framebuffer size - if ( ! properties.get( renderTarget.depthTexture ).__webglTexture || - renderTarget.depthTexture.image.width !== renderTarget.width || - renderTarget.depthTexture.image.height !== renderTarget.height ) { - - renderTarget.depthTexture.image.width = renderTarget.width; - renderTarget.depthTexture.image.height = renderTarget.height; - renderTarget.depthTexture.needsUpdate = true; - - } - - setTexture2D( renderTarget.depthTexture, 0 ); - - const webglDepthTexture = properties.get( renderTarget.depthTexture ).__webglTexture; - const samples = getRenderTargetSamples( renderTarget ); - - if ( renderTarget.depthTexture.format === DepthFormat ) { - - if ( useMultisampledRTT( renderTarget ) ) { - - multisampledRTTExt.framebufferTexture2DMultisampleEXT( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0, samples ); - - } else { - - _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0 ); - - } - - } else if ( renderTarget.depthTexture.format === DepthStencilFormat ) { - - if ( useMultisampledRTT( renderTarget ) ) { - - multisampledRTTExt.framebufferTexture2DMultisampleEXT( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0, samples ); - - } else { - - _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0 ); - - } - - } else { - - throw new Error( 'Unknown depthTexture format' ); - - } - - } - - // Setup GL resources for a non-texture depth buffer - function setupDepthRenderbuffer( renderTarget ) { - - const renderTargetProperties = properties.get( renderTarget ); - const isCube = ( renderTarget.isWebGLCubeRenderTarget === true ); - - if ( renderTarget.depthTexture && ! renderTargetProperties.__autoAllocateDepthBuffer ) { - - if ( isCube ) throw new Error( 'target.depthTexture not supported in Cube render targets' ); - - setupDepthTexture( renderTargetProperties.__webglFramebuffer, renderTarget ); - - } else { - - if ( isCube ) { - - renderTargetProperties.__webglDepthbuffer = []; - - for ( let i = 0; i < 6; i ++ ) { - - state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer[ i ] ); - renderTargetProperties.__webglDepthbuffer[ i ] = _gl.createRenderbuffer(); - setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer[ i ], renderTarget, false ); - - } - - } else { - - state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer ); - renderTargetProperties.__webglDepthbuffer = _gl.createRenderbuffer(); - setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer, renderTarget, false ); - - } - - } - - state.bindFramebuffer( _gl.FRAMEBUFFER, null ); - - } - - // rebind framebuffer with external textures - function rebindTextures( renderTarget, colorTexture, depthTexture ) { - - const renderTargetProperties = properties.get( renderTarget ); - - if ( colorTexture !== undefined ) { - - setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, renderTarget.texture, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D, 0 ); - - } - - if ( depthTexture !== undefined ) { - - setupDepthRenderbuffer( renderTarget ); - - } - - } - - // Set up GL resources for the render target - function setupRenderTarget( renderTarget ) { - - const texture = renderTarget.texture; - - const renderTargetProperties = properties.get( renderTarget ); - const textureProperties = properties.get( texture ); - - renderTarget.addEventListener( 'dispose', onRenderTargetDispose ); - - if ( renderTarget.isWebGLMultipleRenderTargets !== true ) { - - if ( textureProperties.__webglTexture === undefined ) { - - textureProperties.__webglTexture = _gl.createTexture(); - - } - - textureProperties.__version = texture.version; - info.memory.textures ++; - - } - - const isCube = ( renderTarget.isWebGLCubeRenderTarget === true ); - const isMultipleRenderTargets = ( renderTarget.isWebGLMultipleRenderTargets === true ); - const supportsMips = isPowerOfTwo$1( renderTarget ) || isWebGL2; - - // Setup framebuffer - - if ( isCube ) { - - renderTargetProperties.__webglFramebuffer = []; - - for ( let i = 0; i < 6; i ++ ) { - - if ( isWebGL2 && texture.mipmaps && texture.mipmaps.length > 0 ) { - - renderTargetProperties.__webglFramebuffer[ i ] = []; - - for ( let level = 0; level < texture.mipmaps.length; level ++ ) { - - renderTargetProperties.__webglFramebuffer[ i ][ level ] = _gl.createFramebuffer(); - - } - - } else { - - renderTargetProperties.__webglFramebuffer[ i ] = _gl.createFramebuffer(); - - } - - } - - } else { - - if ( isWebGL2 && texture.mipmaps && texture.mipmaps.length > 0 ) { - - renderTargetProperties.__webglFramebuffer = []; - - for ( let level = 0; level < texture.mipmaps.length; level ++ ) { - - renderTargetProperties.__webglFramebuffer[ level ] = _gl.createFramebuffer(); - - } - - } else { - - renderTargetProperties.__webglFramebuffer = _gl.createFramebuffer(); - - } - - if ( isMultipleRenderTargets ) { - - if ( capabilities.drawBuffers ) { - - const textures = renderTarget.texture; - - for ( let i = 0, il = textures.length; i < il; i ++ ) { - - const attachmentProperties = properties.get( textures[ i ] ); - - if ( attachmentProperties.__webglTexture === undefined ) { - - attachmentProperties.__webglTexture = _gl.createTexture(); - - info.memory.textures ++; - - } - - } - - } else { - - console.warn( 'THREE.WebGLRenderer: WebGLMultipleRenderTargets can only be used with WebGL2 or WEBGL_draw_buffers extension.' ); - - } - - } - - if ( ( isWebGL2 && renderTarget.samples > 0 ) && useMultisampledRTT( renderTarget ) === false ) { - - const textures = isMultipleRenderTargets ? texture : [ texture ]; - - renderTargetProperties.__webglMultisampledFramebuffer = _gl.createFramebuffer(); - renderTargetProperties.__webglColorRenderbuffer = []; - - state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer ); - - for ( let i = 0; i < textures.length; i ++ ) { - - const texture = textures[ i ]; - renderTargetProperties.__webglColorRenderbuffer[ i ] = _gl.createRenderbuffer(); - - _gl.bindRenderbuffer( _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer[ i ] ); - - const glFormat = utils.convert( texture.format, texture.colorSpace ); - const glType = utils.convert( texture.type ); - const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace, renderTarget.isXRRenderTarget === true ); - const samples = getRenderTargetSamples( renderTarget ); - _gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height ); - - _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer[ i ] ); - - } - - _gl.bindRenderbuffer( _gl.RENDERBUFFER, null ); - - if ( renderTarget.depthBuffer ) { - - renderTargetProperties.__webglDepthRenderbuffer = _gl.createRenderbuffer(); - setupRenderBufferStorage( renderTargetProperties.__webglDepthRenderbuffer, renderTarget, true ); - - } - - state.bindFramebuffer( _gl.FRAMEBUFFER, null ); - - } - - } - - // Setup color buffer - - if ( isCube ) { - - state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture ); - setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture, supportsMips ); - - for ( let i = 0; i < 6; i ++ ) { - - if ( isWebGL2 && texture.mipmaps && texture.mipmaps.length > 0 ) { - - for ( let level = 0; level < texture.mipmaps.length; level ++ ) { - - setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ i ][ level ], renderTarget, texture, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, level ); - - } - - } else { - - setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ i ], renderTarget, texture, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0 ); - - } - - } - - if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) { - - generateMipmap( _gl.TEXTURE_CUBE_MAP ); - - } - - state.unbindTexture(); - - } else if ( isMultipleRenderTargets ) { - - const textures = renderTarget.texture; - - for ( let i = 0, il = textures.length; i < il; i ++ ) { - - const attachment = textures[ i ]; - const attachmentProperties = properties.get( attachment ); - - state.bindTexture( _gl.TEXTURE_2D, attachmentProperties.__webglTexture ); - setTextureParameters( _gl.TEXTURE_2D, attachment, supportsMips ); - setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, attachment, _gl.COLOR_ATTACHMENT0 + i, _gl.TEXTURE_2D, 0 ); - - if ( textureNeedsGenerateMipmaps( attachment, supportsMips ) ) { - - generateMipmap( _gl.TEXTURE_2D ); - - } - - } - - state.unbindTexture(); - - } else { - - let glTextureType = _gl.TEXTURE_2D; - - if ( renderTarget.isWebGL3DRenderTarget || renderTarget.isWebGLArrayRenderTarget ) { - - if ( isWebGL2 ) { - - glTextureType = renderTarget.isWebGL3DRenderTarget ? _gl.TEXTURE_3D : _gl.TEXTURE_2D_ARRAY; - - } else { - - console.error( 'THREE.WebGLTextures: THREE.Data3DTexture and THREE.DataArrayTexture only supported with WebGL2.' ); - - } - - } - - state.bindTexture( glTextureType, textureProperties.__webglTexture ); - setTextureParameters( glTextureType, texture, supportsMips ); - - if ( isWebGL2 && texture.mipmaps && texture.mipmaps.length > 0 ) { - - for ( let level = 0; level < texture.mipmaps.length; level ++ ) { - - setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ level ], renderTarget, texture, _gl.COLOR_ATTACHMENT0, glTextureType, level ); - - } - - } else { - - setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, texture, _gl.COLOR_ATTACHMENT0, glTextureType, 0 ); - - } - - if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) { - - generateMipmap( glTextureType ); - - } - - state.unbindTexture(); - - } - - // Setup depth and stencil buffers - - if ( renderTarget.depthBuffer ) { - - setupDepthRenderbuffer( renderTarget ); - - } - - } - - function updateRenderTargetMipmap( renderTarget ) { - - const supportsMips = isPowerOfTwo$1( renderTarget ) || isWebGL2; - - const textures = renderTarget.isWebGLMultipleRenderTargets === true ? renderTarget.texture : [ renderTarget.texture ]; - - for ( let i = 0, il = textures.length; i < il; i ++ ) { - - const texture = textures[ i ]; - - if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) { - - const target = renderTarget.isWebGLCubeRenderTarget ? _gl.TEXTURE_CUBE_MAP : _gl.TEXTURE_2D; - const webglTexture = properties.get( texture ).__webglTexture; - - state.bindTexture( target, webglTexture ); - generateMipmap( target ); - state.unbindTexture(); - - } - - } - - } - - function updateMultisampleRenderTarget( renderTarget ) { - - if ( ( isWebGL2 && renderTarget.samples > 0 ) && useMultisampledRTT( renderTarget ) === false ) { - - const textures = renderTarget.isWebGLMultipleRenderTargets ? renderTarget.texture : [ renderTarget.texture ]; - const width = renderTarget.width; - const height = renderTarget.height; - let mask = _gl.COLOR_BUFFER_BIT; - const invalidationArray = []; - const depthStyle = renderTarget.stencilBuffer ? _gl.DEPTH_STENCIL_ATTACHMENT : _gl.DEPTH_ATTACHMENT; - const renderTargetProperties = properties.get( renderTarget ); - const isMultipleRenderTargets = ( renderTarget.isWebGLMultipleRenderTargets === true ); - - // If MRT we need to remove FBO attachments - if ( isMultipleRenderTargets ) { - - for ( let i = 0; i < textures.length; i ++ ) { - - state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer ); - _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.RENDERBUFFER, null ); - - state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer ); - _gl.framebufferTexture2D( _gl.DRAW_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.TEXTURE_2D, null, 0 ); - - } - - } - - state.bindFramebuffer( _gl.READ_FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer ); - state.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, renderTargetProperties.__webglFramebuffer ); - - for ( let i = 0; i < textures.length; i ++ ) { - - invalidationArray.push( _gl.COLOR_ATTACHMENT0 + i ); - - if ( renderTarget.depthBuffer ) { - - invalidationArray.push( depthStyle ); - - } - - const ignoreDepthValues = ( renderTargetProperties.__ignoreDepthValues !== undefined ) ? renderTargetProperties.__ignoreDepthValues : false; - - if ( ignoreDepthValues === false ) { - - if ( renderTarget.depthBuffer ) mask |= _gl.DEPTH_BUFFER_BIT; - if ( renderTarget.stencilBuffer ) mask |= _gl.STENCIL_BUFFER_BIT; - - } - - if ( isMultipleRenderTargets ) { - - _gl.framebufferRenderbuffer( _gl.READ_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer[ i ] ); - - } - - if ( ignoreDepthValues === true ) { - - _gl.invalidateFramebuffer( _gl.READ_FRAMEBUFFER, [ depthStyle ] ); - _gl.invalidateFramebuffer( _gl.DRAW_FRAMEBUFFER, [ depthStyle ] ); - - } - - if ( isMultipleRenderTargets ) { - - const webglTexture = properties.get( textures[ i ] ).__webglTexture; - _gl.framebufferTexture2D( _gl.DRAW_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D, webglTexture, 0 ); - - } - - _gl.blitFramebuffer( 0, 0, width, height, 0, 0, width, height, mask, _gl.NEAREST ); - - if ( supportsInvalidateFramebuffer ) { - - _gl.invalidateFramebuffer( _gl.READ_FRAMEBUFFER, invalidationArray ); - - } - - - } - - state.bindFramebuffer( _gl.READ_FRAMEBUFFER, null ); - state.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, null ); - - // If MRT since pre-blit we removed the FBO we need to reconstruct the attachments - if ( isMultipleRenderTargets ) { - - for ( let i = 0; i < textures.length; i ++ ) { - - state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer ); - _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer[ i ] ); - - const webglTexture = properties.get( textures[ i ] ).__webglTexture; - - state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer ); - _gl.framebufferTexture2D( _gl.DRAW_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.TEXTURE_2D, webglTexture, 0 ); - - } - - } - - state.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer ); - - } - - } - - function getRenderTargetSamples( renderTarget ) { - - return Math.min( capabilities.maxSamples, renderTarget.samples ); - - } - - function useMultisampledRTT( renderTarget ) { - - const renderTargetProperties = properties.get( renderTarget ); - - return isWebGL2 && renderTarget.samples > 0 && extensions.has( 'WEBGL_multisampled_render_to_texture' ) === true && renderTargetProperties.__useRenderToTexture !== false; - - } - - function updateVideoTexture( texture ) { - - const frame = info.render.frame; - - // Check the last frame we updated the VideoTexture - - if ( _videoTextures.get( texture ) !== frame ) { - - _videoTextures.set( texture, frame ); - texture.update(); - - } - - } - - function verifyColorSpace( texture, image ) { - - const colorSpace = texture.colorSpace; - const format = texture.format; - const type = texture.type; - - if ( texture.isCompressedTexture === true || texture.isVideoTexture === true || texture.format === _SRGBAFormat ) return image; - - if ( colorSpace !== LinearSRGBColorSpace && colorSpace !== NoColorSpace ) { - - // sRGB - - if ( ColorManagement.getTransfer( colorSpace ) === SRGBTransfer ) { - - if ( isWebGL2 === false ) { - - // in WebGL 1, try to use EXT_sRGB extension and unsized formats - - if ( extensions.has( 'EXT_sRGB' ) === true && format === RGBAFormat ) { - - texture.format = _SRGBAFormat; - - // it's not possible to generate mips in WebGL 1 with this extension - - texture.minFilter = LinearFilter; - texture.generateMipmaps = false; - - } else { - - // slow fallback (CPU decode) - - image = ImageUtils.sRGBToLinear( image ); - - } - - } else { - - // in WebGL 2 uncompressed textures can only be sRGB encoded if they have the RGBA8 format - - if ( format !== RGBAFormat || type !== UnsignedByteType ) { - - console.warn( 'THREE.WebGLTextures: sRGB encoded textures have to use RGBAFormat and UnsignedByteType.' ); - - } - - } - - } else { - - console.error( 'THREE.WebGLTextures: Unsupported texture color space:', colorSpace ); - - } - - } - - return image; - - } - - // - - this.allocateTextureUnit = allocateTextureUnit; - this.resetTextureUnits = resetTextureUnits; - - this.setTexture2D = setTexture2D; - this.setTexture2DArray = setTexture2DArray; - this.setTexture3D = setTexture3D; - this.setTextureCube = setTextureCube; - this.rebindTextures = rebindTextures; - this.setupRenderTarget = setupRenderTarget; - this.updateRenderTargetMipmap = updateRenderTargetMipmap; - this.updateMultisampleRenderTarget = updateMultisampleRenderTarget; - this.setupDepthRenderbuffer = setupDepthRenderbuffer; - this.setupFrameBufferTexture = setupFrameBufferTexture; - this.useMultisampledRTT = useMultisampledRTT; - -} - -function WebGLUtils( gl, extensions, capabilities ) { - - const isWebGL2 = capabilities.isWebGL2; - - function convert( p, colorSpace = NoColorSpace ) { - - let extension; - - const transfer = ColorManagement.getTransfer( colorSpace ); - - if ( p === UnsignedByteType ) return gl.UNSIGNED_BYTE; - if ( p === UnsignedShort4444Type ) return gl.UNSIGNED_SHORT_4_4_4_4; - if ( p === UnsignedShort5551Type ) return gl.UNSIGNED_SHORT_5_5_5_1; - - if ( p === ByteType ) return gl.BYTE; - if ( p === ShortType ) return gl.SHORT; - if ( p === UnsignedShortType ) return gl.UNSIGNED_SHORT; - if ( p === IntType ) return gl.INT; - if ( p === UnsignedIntType ) return gl.UNSIGNED_INT; - if ( p === FloatType ) return gl.FLOAT; - - if ( p === HalfFloatType ) { - - if ( isWebGL2 ) return gl.HALF_FLOAT; - - extension = extensions.get( 'OES_texture_half_float' ); - - if ( extension !== null ) { - - return extension.HALF_FLOAT_OES; - - } else { - - return null; - - } - - } - - if ( p === AlphaFormat ) return gl.ALPHA; - if ( p === RGBAFormat ) return gl.RGBA; - if ( p === LuminanceFormat ) return gl.LUMINANCE; - if ( p === LuminanceAlphaFormat ) return gl.LUMINANCE_ALPHA; - if ( p === DepthFormat ) return gl.DEPTH_COMPONENT; - if ( p === DepthStencilFormat ) return gl.DEPTH_STENCIL; - - // WebGL 1 sRGB fallback - - if ( p === _SRGBAFormat ) { - - extension = extensions.get( 'EXT_sRGB' ); - - if ( extension !== null ) { - - return extension.SRGB_ALPHA_EXT; - - } else { - - return null; - - } - - } - - // WebGL2 formats. - - if ( p === RedFormat ) return gl.RED; - if ( p === RedIntegerFormat ) return gl.RED_INTEGER; - if ( p === RGFormat ) return gl.RG; - if ( p === RGIntegerFormat ) return gl.RG_INTEGER; - if ( p === RGBAIntegerFormat ) return gl.RGBA_INTEGER; - - // S3TC - - if ( p === RGB_S3TC_DXT1_Format || p === RGBA_S3TC_DXT1_Format || p === RGBA_S3TC_DXT3_Format || p === RGBA_S3TC_DXT5_Format ) { - - if ( transfer === SRGBTransfer ) { - - extension = extensions.get( 'WEBGL_compressed_texture_s3tc_srgb' ); - - if ( extension !== null ) { - - if ( p === RGB_S3TC_DXT1_Format ) return extension.COMPRESSED_SRGB_S3TC_DXT1_EXT; - if ( p === RGBA_S3TC_DXT1_Format ) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT; - if ( p === RGBA_S3TC_DXT3_Format ) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT; - if ( p === RGBA_S3TC_DXT5_Format ) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT; - - } else { - - return null; - - } - - } else { - - extension = extensions.get( 'WEBGL_compressed_texture_s3tc' ); - - if ( extension !== null ) { - - if ( p === RGB_S3TC_DXT1_Format ) return extension.COMPRESSED_RGB_S3TC_DXT1_EXT; - if ( p === RGBA_S3TC_DXT1_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT1_EXT; - if ( p === RGBA_S3TC_DXT3_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT3_EXT; - if ( p === RGBA_S3TC_DXT5_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT5_EXT; - - } else { - - return null; - - } - - } - - } - - // PVRTC - - if ( p === RGB_PVRTC_4BPPV1_Format || p === RGB_PVRTC_2BPPV1_Format || p === RGBA_PVRTC_4BPPV1_Format || p === RGBA_PVRTC_2BPPV1_Format ) { - - extension = extensions.get( 'WEBGL_compressed_texture_pvrtc' ); - - if ( extension !== null ) { - - if ( p === RGB_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_4BPPV1_IMG; - if ( p === RGB_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_2BPPV1_IMG; - if ( p === RGBA_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; - if ( p === RGBA_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG; - - } else { - - return null; - - } - - } - - // ETC1 - - if ( p === RGB_ETC1_Format ) { - - extension = extensions.get( 'WEBGL_compressed_texture_etc1' ); - - if ( extension !== null ) { - - return extension.COMPRESSED_RGB_ETC1_WEBGL; - - } else { - - return null; - - } - - } - - // ETC2 - - if ( p === RGB_ETC2_Format || p === RGBA_ETC2_EAC_Format ) { - - extension = extensions.get( 'WEBGL_compressed_texture_etc' ); - - if ( extension !== null ) { - - if ( p === RGB_ETC2_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ETC2 : extension.COMPRESSED_RGB8_ETC2; - if ( p === RGBA_ETC2_EAC_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC : extension.COMPRESSED_RGBA8_ETC2_EAC; - - } else { - - return null; - - } - - } - - // ASTC - - if ( p === RGBA_ASTC_4x4_Format || p === RGBA_ASTC_5x4_Format || p === RGBA_ASTC_5x5_Format || - p === RGBA_ASTC_6x5_Format || p === RGBA_ASTC_6x6_Format || p === RGBA_ASTC_8x5_Format || - p === RGBA_ASTC_8x6_Format || p === RGBA_ASTC_8x8_Format || p === RGBA_ASTC_10x5_Format || - p === RGBA_ASTC_10x6_Format || p === RGBA_ASTC_10x8_Format || p === RGBA_ASTC_10x10_Format || - p === RGBA_ASTC_12x10_Format || p === RGBA_ASTC_12x12_Format ) { - - extension = extensions.get( 'WEBGL_compressed_texture_astc' ); - - if ( extension !== null ) { - - if ( p === RGBA_ASTC_4x4_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR : extension.COMPRESSED_RGBA_ASTC_4x4_KHR; - if ( p === RGBA_ASTC_5x4_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR : extension.COMPRESSED_RGBA_ASTC_5x4_KHR; - if ( p === RGBA_ASTC_5x5_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR : extension.COMPRESSED_RGBA_ASTC_5x5_KHR; - if ( p === RGBA_ASTC_6x5_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR : extension.COMPRESSED_RGBA_ASTC_6x5_KHR; - if ( p === RGBA_ASTC_6x6_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR : extension.COMPRESSED_RGBA_ASTC_6x6_KHR; - if ( p === RGBA_ASTC_8x5_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR : extension.COMPRESSED_RGBA_ASTC_8x5_KHR; - if ( p === RGBA_ASTC_8x6_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR : extension.COMPRESSED_RGBA_ASTC_8x6_KHR; - if ( p === RGBA_ASTC_8x8_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR : extension.COMPRESSED_RGBA_ASTC_8x8_KHR; - if ( p === RGBA_ASTC_10x5_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR : extension.COMPRESSED_RGBA_ASTC_10x5_KHR; - if ( p === RGBA_ASTC_10x6_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR : extension.COMPRESSED_RGBA_ASTC_10x6_KHR; - if ( p === RGBA_ASTC_10x8_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR : extension.COMPRESSED_RGBA_ASTC_10x8_KHR; - if ( p === RGBA_ASTC_10x10_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR : extension.COMPRESSED_RGBA_ASTC_10x10_KHR; - if ( p === RGBA_ASTC_12x10_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR : extension.COMPRESSED_RGBA_ASTC_12x10_KHR; - if ( p === RGBA_ASTC_12x12_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR : extension.COMPRESSED_RGBA_ASTC_12x12_KHR; - - } else { - - return null; - - } - - } - - // BPTC - - if ( p === RGBA_BPTC_Format || p === RGB_BPTC_SIGNED_Format || p === RGB_BPTC_UNSIGNED_Format ) { - - extension = extensions.get( 'EXT_texture_compression_bptc' ); - - if ( extension !== null ) { - - if ( p === RGBA_BPTC_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT : extension.COMPRESSED_RGBA_BPTC_UNORM_EXT; - if ( p === RGB_BPTC_SIGNED_Format ) return extension.COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT; - if ( p === RGB_BPTC_UNSIGNED_Format ) return extension.COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT; - - } else { - - return null; - - } - - } - - // RGTC - - if ( p === RED_RGTC1_Format || p === SIGNED_RED_RGTC1_Format || p === RED_GREEN_RGTC2_Format || p === SIGNED_RED_GREEN_RGTC2_Format ) { - - extension = extensions.get( 'EXT_texture_compression_rgtc' ); - - if ( extension !== null ) { - - if ( p === RGBA_BPTC_Format ) return extension.COMPRESSED_RED_RGTC1_EXT; - if ( p === SIGNED_RED_RGTC1_Format ) return extension.COMPRESSED_SIGNED_RED_RGTC1_EXT; - if ( p === RED_GREEN_RGTC2_Format ) return extension.COMPRESSED_RED_GREEN_RGTC2_EXT; - if ( p === SIGNED_RED_GREEN_RGTC2_Format ) return extension.COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT; - - } else { - - return null; - - } - - } - - // - - if ( p === UnsignedInt248Type ) { - - if ( isWebGL2 ) return gl.UNSIGNED_INT_24_8; - - extension = extensions.get( 'WEBGL_depth_texture' ); - - if ( extension !== null ) { - - return extension.UNSIGNED_INT_24_8_WEBGL; - - } else { - - return null; - - } - - } - - // if "p" can't be resolved, assume the user defines a WebGL constant as a string (fallback/workaround for packed RGB formats) - - return ( gl[ p ] !== undefined ) ? gl[ p ] : null; - - } - - return { convert: convert }; - -} - -class ArrayCamera extends PerspectiveCamera { - - constructor( array = [] ) { - - super(); - - this.isArrayCamera = true; - - this.cameras = array; - - } - -} - -class Group extends Object3D { - - constructor() { - - super(); - - this.isGroup = true; - - this.type = 'Group'; - - } - -} - -const _moveEvent = { type: 'move' }; - -class WebXRController { - - constructor() { - - this._targetRay = null; - this._grip = null; - this._hand = null; - - } - - getHandSpace() { - - if ( this._hand === null ) { - - this._hand = new Group(); - this._hand.matrixAutoUpdate = false; - this._hand.visible = false; - - this._hand.joints = {}; - this._hand.inputState = { pinching: false }; - - } - - return this._hand; - - } - - getTargetRaySpace() { - - if ( this._targetRay === null ) { - - this._targetRay = new Group(); - this._targetRay.matrixAutoUpdate = false; - this._targetRay.visible = false; - this._targetRay.hasLinearVelocity = false; - this._targetRay.linearVelocity = new Vector3(); - this._targetRay.hasAngularVelocity = false; - this._targetRay.angularVelocity = new Vector3(); - - } - - return this._targetRay; - - } - - getGripSpace() { - - if ( this._grip === null ) { - - this._grip = new Group(); - this._grip.matrixAutoUpdate = false; - this._grip.visible = false; - this._grip.hasLinearVelocity = false; - this._grip.linearVelocity = new Vector3(); - this._grip.hasAngularVelocity = false; - this._grip.angularVelocity = new Vector3(); - - } - - return this._grip; - - } - - dispatchEvent( event ) { - - if ( this._targetRay !== null ) { - - this._targetRay.dispatchEvent( event ); - - } - - if ( this._grip !== null ) { - - this._grip.dispatchEvent( event ); - - } - - if ( this._hand !== null ) { - - this._hand.dispatchEvent( event ); - - } - - return this; - - } - - connect( inputSource ) { - - if ( inputSource && inputSource.hand ) { - - const hand = this._hand; - - if ( hand ) { - - for ( const inputjoint of inputSource.hand.values() ) { - - // Initialize hand with joints when connected - this._getHandJoint( hand, inputjoint ); - - } - - } - - } - - this.dispatchEvent( { type: 'connected', data: inputSource } ); - - return this; - - } - - disconnect( inputSource ) { - - this.dispatchEvent( { type: 'disconnected', data: inputSource } ); - - if ( this._targetRay !== null ) { - - this._targetRay.visible = false; - - } - - if ( this._grip !== null ) { - - this._grip.visible = false; - - } - - if ( this._hand !== null ) { - - this._hand.visible = false; - - } - - return this; - - } - - update( inputSource, frame, referenceSpace ) { - - let inputPose = null; - let gripPose = null; - let handPose = null; - - const targetRay = this._targetRay; - const grip = this._grip; - const hand = this._hand; - - if ( inputSource && frame.session.visibilityState !== 'visible-blurred' ) { - - if ( hand && inputSource.hand ) { - - handPose = true; - - for ( const inputjoint of inputSource.hand.values() ) { - - // Update the joints groups with the XRJoint poses - const jointPose = frame.getJointPose( inputjoint, referenceSpace ); - - // The transform of this joint will be updated with the joint pose on each frame - const joint = this._getHandJoint( hand, inputjoint ); - - if ( jointPose !== null ) { - - joint.matrix.fromArray( jointPose.transform.matrix ); - joint.matrix.decompose( joint.position, joint.rotation, joint.scale ); - joint.matrixWorldNeedsUpdate = true; - joint.jointRadius = jointPose.radius; - - } - - joint.visible = jointPose !== null; - - } - - // Custom events - - // Check pinchz - const indexTip = hand.joints[ 'index-finger-tip' ]; - const thumbTip = hand.joints[ 'thumb-tip' ]; - const distance = indexTip.position.distanceTo( thumbTip.position ); - - const distanceToPinch = 0.02; - const threshold = 0.005; - - if ( hand.inputState.pinching && distance > distanceToPinch + threshold ) { - - hand.inputState.pinching = false; - this.dispatchEvent( { - type: 'pinchend', - handedness: inputSource.handedness, - target: this - } ); - - } else if ( ! hand.inputState.pinching && distance <= distanceToPinch - threshold ) { - - hand.inputState.pinching = true; - this.dispatchEvent( { - type: 'pinchstart', - handedness: inputSource.handedness, - target: this - } ); - - } - - } else { - - if ( grip !== null && inputSource.gripSpace ) { - - gripPose = frame.getPose( inputSource.gripSpace, referenceSpace ); - - if ( gripPose !== null ) { - - grip.matrix.fromArray( gripPose.transform.matrix ); - grip.matrix.decompose( grip.position, grip.rotation, grip.scale ); - grip.matrixWorldNeedsUpdate = true; - - if ( gripPose.linearVelocity ) { - - grip.hasLinearVelocity = true; - grip.linearVelocity.copy( gripPose.linearVelocity ); - - } else { - - grip.hasLinearVelocity = false; - - } - - if ( gripPose.angularVelocity ) { - - grip.hasAngularVelocity = true; - grip.angularVelocity.copy( gripPose.angularVelocity ); - - } else { - - grip.hasAngularVelocity = false; - - } - - } - - } - - } - - if ( targetRay !== null ) { - - inputPose = frame.getPose( inputSource.targetRaySpace, referenceSpace ); - - // Some runtimes (namely Vive Cosmos with Vive OpenXR Runtime) have only grip space and ray space is equal to it - if ( inputPose === null && gripPose !== null ) { - - inputPose = gripPose; - - } - - if ( inputPose !== null ) { - - targetRay.matrix.fromArray( inputPose.transform.matrix ); - targetRay.matrix.decompose( targetRay.position, targetRay.rotation, targetRay.scale ); - targetRay.matrixWorldNeedsUpdate = true; - - if ( inputPose.linearVelocity ) { - - targetRay.hasLinearVelocity = true; - targetRay.linearVelocity.copy( inputPose.linearVelocity ); - - } else { - - targetRay.hasLinearVelocity = false; - - } - - if ( inputPose.angularVelocity ) { - - targetRay.hasAngularVelocity = true; - targetRay.angularVelocity.copy( inputPose.angularVelocity ); - - } else { - - targetRay.hasAngularVelocity = false; - - } - - this.dispatchEvent( _moveEvent ); - - } - - } - - - } - - if ( targetRay !== null ) { - - targetRay.visible = ( inputPose !== null ); - - } - - if ( grip !== null ) { - - grip.visible = ( gripPose !== null ); - - } - - if ( hand !== null ) { - - hand.visible = ( handPose !== null ); - - } - - return this; - - } - - // private method - - _getHandJoint( hand, inputjoint ) { - - if ( hand.joints[ inputjoint.jointName ] === undefined ) { - - const joint = new Group(); - joint.matrixAutoUpdate = false; - joint.visible = false; - hand.joints[ inputjoint.jointName ] = joint; - - hand.add( joint ); - - } - - return hand.joints[ inputjoint.jointName ]; - - } - -} - -const _occlusion_vertex = ` -void main() { - - gl_Position = vec4( position, 1.0 ); - -}`; - -const _occlusion_fragment = ` -uniform sampler2DArray depthColor; -uniform float depthWidth; -uniform float depthHeight; - -void main() { - - vec2 coord = vec2( gl_FragCoord.x / depthWidth, gl_FragCoord.y / depthHeight ); - - if ( coord.x >= 1.0 ) { - - gl_FragDepthEXT = texture( depthColor, vec3( coord.x - 1.0, coord.y, 1 ) ).r; - - } else { - - gl_FragDepthEXT = texture( depthColor, vec3( coord.x, coord.y, 0 ) ).r; - - } - -}`; - -class WebXRDepthSensing { - - constructor() { - - this.texture = null; - this.mesh = null; - - this.depthNear = 0; - this.depthFar = 0; - - } - - init( renderer, depthData, renderState ) { - - if ( this.texture === null ) { - - const texture = new Texture(); - - const texProps = renderer.properties.get( texture ); - texProps.__webglTexture = depthData.texture; - - if ( ( depthData.depthNear != renderState.depthNear ) || ( depthData.depthFar != renderState.depthFar ) ) { - - this.depthNear = depthData.depthNear; - this.depthFar = depthData.depthFar; - - } - - this.texture = texture; - - } - - } - - render( renderer, cameraXR ) { - - if ( this.texture !== null ) { - - if ( this.mesh === null ) { - - const viewport = cameraXR.cameras[ 0 ].viewport; - const material = new ShaderMaterial( { - extensions: { fragDepth: true }, - vertexShader: _occlusion_vertex, - fragmentShader: _occlusion_fragment, - uniforms: { - depthColor: { value: this.texture }, - depthWidth: { value: viewport.z }, - depthHeight: { value: viewport.w } - } - } ); - - this.mesh = new Mesh( new PlaneGeometry( 20, 20 ), material ); - - } - - renderer.render( this.mesh, cameraXR ); - - } - - } - - reset() { - - this.texture = null; - this.mesh = null; - - } - -} - -class WebXRManager extends EventDispatcher { - - constructor( renderer, gl ) { - - super(); - - const scope = this; - - let session = null; - - let framebufferScaleFactor = 1.0; - - let referenceSpace = null; - let referenceSpaceType = 'local-floor'; - // Set default foveation to maximum. - let foveation = 1.0; - let customReferenceSpace = null; - - let pose = null; - let glBinding = null; - let glProjLayer = null; - let glBaseLayer = null; - let xrFrame = null; - - const depthSensing = new WebXRDepthSensing(); - const attributes = gl.getContextAttributes(); - - let initialRenderTarget = null; - let newRenderTarget = null; - - const controllers = []; - const controllerInputSources = []; - - const currentSize = new Vector2(); - let currentPixelRatio = null; - - // - - const cameraL = new PerspectiveCamera(); - cameraL.layers.enable( 1 ); - cameraL.viewport = new Vector4(); - - const cameraR = new PerspectiveCamera(); - cameraR.layers.enable( 2 ); - cameraR.viewport = new Vector4(); - - const cameras = [ cameraL, cameraR ]; - - const cameraXR = new ArrayCamera(); - cameraXR.layers.enable( 1 ); - cameraXR.layers.enable( 2 ); - - let _currentDepthNear = null; - let _currentDepthFar = null; - - // - - this.cameraAutoUpdate = true; - this.enabled = false; - - this.isPresenting = false; - - this.getController = function ( index ) { - - let controller = controllers[ index ]; - - if ( controller === undefined ) { - - controller = new WebXRController(); - controllers[ index ] = controller; - - } - - return controller.getTargetRaySpace(); - - }; - - this.getControllerGrip = function ( index ) { - - let controller = controllers[ index ]; - - if ( controller === undefined ) { - - controller = new WebXRController(); - controllers[ index ] = controller; - - } - - return controller.getGripSpace(); - - }; - - this.getHand = function ( index ) { - - let controller = controllers[ index ]; - - if ( controller === undefined ) { - - controller = new WebXRController(); - controllers[ index ] = controller; - - } - - return controller.getHandSpace(); - - }; - - // - - function onSessionEvent( event ) { - - const controllerIndex = controllerInputSources.indexOf( event.inputSource ); - - if ( controllerIndex === - 1 ) { - - return; - - } - - const controller = controllers[ controllerIndex ]; - - if ( controller !== undefined ) { - - controller.update( event.inputSource, event.frame, customReferenceSpace || referenceSpace ); - controller.dispatchEvent( { type: event.type, data: event.inputSource } ); - - } - - } - - function onSessionEnd() { - - session.removeEventListener( 'select', onSessionEvent ); - session.removeEventListener( 'selectstart', onSessionEvent ); - session.removeEventListener( 'selectend', onSessionEvent ); - session.removeEventListener( 'squeeze', onSessionEvent ); - session.removeEventListener( 'squeezestart', onSessionEvent ); - session.removeEventListener( 'squeezeend', onSessionEvent ); - session.removeEventListener( 'end', onSessionEnd ); - session.removeEventListener( 'inputsourceschange', onInputSourcesChange ); - - for ( let i = 0; i < controllers.length; i ++ ) { - - const inputSource = controllerInputSources[ i ]; - - if ( inputSource === null ) continue; - - controllerInputSources[ i ] = null; - - controllers[ i ].disconnect( inputSource ); - - } - - _currentDepthNear = null; - _currentDepthFar = null; - - depthSensing.reset(); - - // restore framebuffer/rendering state - - renderer.setRenderTarget( initialRenderTarget ); - - glBaseLayer = null; - glProjLayer = null; - glBinding = null; - session = null; - newRenderTarget = null; - - // - - animation.stop(); - - scope.isPresenting = false; - - renderer.setPixelRatio( currentPixelRatio ); - renderer.setSize( currentSize.width, currentSize.height, false ); - - scope.dispatchEvent( { type: 'sessionend' } ); - - } - - this.setFramebufferScaleFactor = function ( value ) { - - framebufferScaleFactor = value; - - if ( scope.isPresenting === true ) { - - console.warn( 'THREE.WebXRManager: Cannot change framebuffer scale while presenting.' ); - - } - - }; - - this.setReferenceSpaceType = function ( value ) { - - referenceSpaceType = value; - - if ( scope.isPresenting === true ) { - - console.warn( 'THREE.WebXRManager: Cannot change reference space type while presenting.' ); - - } - - }; - - this.getReferenceSpace = function () { - - return customReferenceSpace || referenceSpace; - - }; - - this.setReferenceSpace = function ( space ) { - - customReferenceSpace = space; - - }; - - this.getBaseLayer = function () { - - return glProjLayer !== null ? glProjLayer : glBaseLayer; - - }; - - this.getBinding = function () { - - return glBinding; - - }; - - this.getFrame = function () { - - return xrFrame; - - }; - - this.getSession = function () { - - return session; - - }; - - this.setSession = async function ( value ) { - - session = value; - - if ( session !== null ) { - - initialRenderTarget = renderer.getRenderTarget(); - - session.addEventListener( 'select', onSessionEvent ); - session.addEventListener( 'selectstart', onSessionEvent ); - session.addEventListener( 'selectend', onSessionEvent ); - session.addEventListener( 'squeeze', onSessionEvent ); - session.addEventListener( 'squeezestart', onSessionEvent ); - session.addEventListener( 'squeezeend', onSessionEvent ); - session.addEventListener( 'end', onSessionEnd ); - session.addEventListener( 'inputsourceschange', onInputSourcesChange ); - - if ( attributes.xrCompatible !== true ) { - - await gl.makeXRCompatible(); - - } - - currentPixelRatio = renderer.getPixelRatio(); - renderer.getSize( currentSize ); - - if ( ( session.renderState.layers === undefined ) || ( renderer.capabilities.isWebGL2 === false ) ) { - - const layerInit = { - antialias: ( session.renderState.layers === undefined ) ? attributes.antialias : true, - alpha: true, - depth: attributes.depth, - stencil: attributes.stencil, - framebufferScaleFactor: framebufferScaleFactor - }; - - glBaseLayer = new XRWebGLLayer( session, gl, layerInit ); - - session.updateRenderState( { baseLayer: glBaseLayer } ); - - renderer.setPixelRatio( 1 ); - renderer.setSize( glBaseLayer.framebufferWidth, glBaseLayer.framebufferHeight, false ); - - newRenderTarget = new WebGLRenderTarget( - glBaseLayer.framebufferWidth, - glBaseLayer.framebufferHeight, - { - format: RGBAFormat, - type: UnsignedByteType, - colorSpace: renderer.outputColorSpace, - stencilBuffer: attributes.stencil - } - ); - - } else { - - let depthFormat = null; - let depthType = null; - let glDepthFormat = null; - - if ( attributes.depth ) { - - glDepthFormat = attributes.stencil ? gl.DEPTH24_STENCIL8 : gl.DEPTH_COMPONENT24; - depthFormat = attributes.stencil ? DepthStencilFormat : DepthFormat; - depthType = attributes.stencil ? UnsignedInt248Type : UnsignedIntType; - - } - - const projectionlayerInit = { - colorFormat: gl.RGBA8, - depthFormat: glDepthFormat, - scaleFactor: framebufferScaleFactor - }; - - glBinding = new XRWebGLBinding( session, gl ); - - glProjLayer = glBinding.createProjectionLayer( projectionlayerInit ); - - session.updateRenderState( { layers: [ glProjLayer ] } ); - - renderer.setPixelRatio( 1 ); - renderer.setSize( glProjLayer.textureWidth, glProjLayer.textureHeight, false ); - - newRenderTarget = new WebGLRenderTarget( - glProjLayer.textureWidth, - glProjLayer.textureHeight, - { - format: RGBAFormat, - type: UnsignedByteType, - depthTexture: new DepthTexture( glProjLayer.textureWidth, glProjLayer.textureHeight, depthType, undefined, undefined, undefined, undefined, undefined, undefined, depthFormat ), - stencilBuffer: attributes.stencil, - colorSpace: renderer.outputColorSpace, - samples: attributes.antialias ? 4 : 0 - } ); - - const renderTargetProperties = renderer.properties.get( newRenderTarget ); - renderTargetProperties.__ignoreDepthValues = glProjLayer.ignoreDepthValues; - - } - - newRenderTarget.isXRRenderTarget = true; // TODO Remove this when possible, see #23278 - - this.setFoveation( foveation ); - - customReferenceSpace = null; - referenceSpace = await session.requestReferenceSpace( referenceSpaceType ); - - animation.setContext( session ); - animation.start(); - - scope.isPresenting = true; - - scope.dispatchEvent( { type: 'sessionstart' } ); - - } - - }; - - this.getEnvironmentBlendMode = function () { - - if ( session !== null ) { - - return session.environmentBlendMode; - - } - - }; - - function onInputSourcesChange( event ) { - - // Notify disconnected - - for ( let i = 0; i < event.removed.length; i ++ ) { - - const inputSource = event.removed[ i ]; - const index = controllerInputSources.indexOf( inputSource ); - - if ( index >= 0 ) { - - controllerInputSources[ index ] = null; - controllers[ index ].disconnect( inputSource ); - - } - - } - - // Notify connected - - for ( let i = 0; i < event.added.length; i ++ ) { - - const inputSource = event.added[ i ]; - - let controllerIndex = controllerInputSources.indexOf( inputSource ); - - if ( controllerIndex === - 1 ) { - - // Assign input source a controller that currently has no input source - - for ( let i = 0; i < controllers.length; i ++ ) { - - if ( i >= controllerInputSources.length ) { - - controllerInputSources.push( inputSource ); - controllerIndex = i; - break; - - } else if ( controllerInputSources[ i ] === null ) { - - controllerInputSources[ i ] = inputSource; - controllerIndex = i; - break; - - } - - } - - // If all controllers do currently receive input we ignore new ones - - if ( controllerIndex === - 1 ) break; - - } - - const controller = controllers[ controllerIndex ]; - - if ( controller ) { - - controller.connect( inputSource ); - - } - - } - - } - - // - - const cameraLPos = new Vector3(); - const cameraRPos = new Vector3(); - - /** - * Assumes 2 cameras that are parallel and share an X-axis, and that - * the cameras' projection and world matrices have already been set. - * And that near and far planes are identical for both cameras. - * Visualization of this technique: https://computergraphics.stackexchange.com/a/4765 - */ - function setProjectionFromUnion( camera, cameraL, cameraR ) { - - cameraLPos.setFromMatrixPosition( cameraL.matrixWorld ); - cameraRPos.setFromMatrixPosition( cameraR.matrixWorld ); - - const ipd = cameraLPos.distanceTo( cameraRPos ); - - const projL = cameraL.projectionMatrix.elements; - const projR = cameraR.projectionMatrix.elements; - - // VR systems will have identical far and near planes, and - // most likely identical top and bottom frustum extents. - // Use the left camera for these values. - const near = projL[ 14 ] / ( projL[ 10 ] - 1 ); - const far = projL[ 14 ] / ( projL[ 10 ] + 1 ); - const topFov = ( projL[ 9 ] + 1 ) / projL[ 5 ]; - const bottomFov = ( projL[ 9 ] - 1 ) / projL[ 5 ]; - - const leftFov = ( projL[ 8 ] - 1 ) / projL[ 0 ]; - const rightFov = ( projR[ 8 ] + 1 ) / projR[ 0 ]; - const left = near * leftFov; - const right = near * rightFov; - - // Calculate the new camera's position offset from the - // left camera. xOffset should be roughly half `ipd`. - const zOffset = ipd / ( - leftFov + rightFov ); - const xOffset = zOffset * - leftFov; - - // TODO: Better way to apply this offset? - cameraL.matrixWorld.decompose( camera.position, camera.quaternion, camera.scale ); - camera.translateX( xOffset ); - camera.translateZ( zOffset ); - camera.matrixWorld.compose( camera.position, camera.quaternion, camera.scale ); - camera.matrixWorldInverse.copy( camera.matrixWorld ).invert(); - - // Find the union of the frustum values of the cameras and scale - // the values so that the near plane's position does not change in world space, - // although must now be relative to the new union camera. - const near2 = near + zOffset; - const far2 = far + zOffset; - const left2 = left - xOffset; - const right2 = right + ( ipd - xOffset ); - const top2 = topFov * far / far2 * near2; - const bottom2 = bottomFov * far / far2 * near2; - - camera.projectionMatrix.makePerspective( left2, right2, top2, bottom2, near2, far2 ); - camera.projectionMatrixInverse.copy( camera.projectionMatrix ).invert(); - - } - - function updateCamera( camera, parent ) { - - if ( parent === null ) { - - camera.matrixWorld.copy( camera.matrix ); - - } else { - - camera.matrixWorld.multiplyMatrices( parent.matrixWorld, camera.matrix ); - - } - - camera.matrixWorldInverse.copy( camera.matrixWorld ).invert(); - - } - - this.updateCamera = function ( camera ) { - - if ( session === null ) return; - - if ( depthSensing.texture !== null ) { - - camera.near = depthSensing.depthNear; - camera.far = depthSensing.depthFar; - - } - - cameraXR.near = cameraR.near = cameraL.near = camera.near; - cameraXR.far = cameraR.far = cameraL.far = camera.far; - - if ( _currentDepthNear !== cameraXR.near || _currentDepthFar !== cameraXR.far ) { - - // Note that the new renderState won't apply until the next frame. See #18320 - - session.updateRenderState( { - depthNear: cameraXR.near, - depthFar: cameraXR.far - } ); - - _currentDepthNear = cameraXR.near; - _currentDepthFar = cameraXR.far; - - cameraL.near = _currentDepthNear; - cameraL.far = _currentDepthFar; - cameraR.near = _currentDepthNear; - cameraR.far = _currentDepthFar; - - cameraL.updateProjectionMatrix(); - cameraR.updateProjectionMatrix(); - camera.updateProjectionMatrix(); - - } - - const parent = camera.parent; - const cameras = cameraXR.cameras; - - updateCamera( cameraXR, parent ); - - for ( let i = 0; i < cameras.length; i ++ ) { - - updateCamera( cameras[ i ], parent ); - - } - - // update projection matrix for proper view frustum culling - - if ( cameras.length === 2 ) { - - setProjectionFromUnion( cameraXR, cameraL, cameraR ); - - } else { - - // assume single camera setup (AR) - - cameraXR.projectionMatrix.copy( cameraL.projectionMatrix ); - - } - - // update user camera and its children - - updateUserCamera( camera, cameraXR, parent ); - - }; - - function updateUserCamera( camera, cameraXR, parent ) { - - if ( parent === null ) { - - camera.matrix.copy( cameraXR.matrixWorld ); - - } else { - - camera.matrix.copy( parent.matrixWorld ); - camera.matrix.invert(); - camera.matrix.multiply( cameraXR.matrixWorld ); - - } - - camera.matrix.decompose( camera.position, camera.quaternion, camera.scale ); - camera.updateMatrixWorld( true ); - - camera.projectionMatrix.copy( cameraXR.projectionMatrix ); - camera.projectionMatrixInverse.copy( cameraXR.projectionMatrixInverse ); - - if ( camera.isPerspectiveCamera ) { - - camera.fov = RAD2DEG * 2 * Math.atan( 1 / camera.projectionMatrix.elements[ 5 ] ); - camera.zoom = 1; - - } - - } - - this.getCamera = function () { - - return cameraXR; - - }; - - this.getFoveation = function () { - - if ( glProjLayer === null && glBaseLayer === null ) { - - return undefined; - - } - - return foveation; - - }; - - this.setFoveation = function ( value ) { - - // 0 = no foveation = full resolution - // 1 = maximum foveation = the edges render at lower resolution - - foveation = value; - - if ( glProjLayer !== null ) { - - glProjLayer.fixedFoveation = value; - - } - - if ( glBaseLayer !== null && glBaseLayer.fixedFoveation !== undefined ) { - - glBaseLayer.fixedFoveation = value; - - } - - }; - - this.hasDepthSensing = function () { - - return depthSensing.texture !== null; - - }; - - // Animation Loop - - let onAnimationFrameCallback = null; - - function onAnimationFrame( time, frame ) { - - pose = frame.getViewerPose( customReferenceSpace || referenceSpace ); - xrFrame = frame; - - if ( pose !== null ) { - - const views = pose.views; - - if ( glBaseLayer !== null ) { - - renderer.setRenderTargetFramebuffer( newRenderTarget, glBaseLayer.framebuffer ); - renderer.setRenderTarget( newRenderTarget ); - - } - - let cameraXRNeedsUpdate = false; - - // check if it's necessary to rebuild cameraXR's camera list - - if ( views.length !== cameraXR.cameras.length ) { - - cameraXR.cameras.length = 0; - cameraXRNeedsUpdate = true; - - } - - for ( let i = 0; i < views.length; i ++ ) { - - const view = views[ i ]; - - let viewport = null; - - if ( glBaseLayer !== null ) { - - viewport = glBaseLayer.getViewport( view ); - - } else { - - const glSubImage = glBinding.getViewSubImage( glProjLayer, view ); - viewport = glSubImage.viewport; - - // For side-by-side projection, we only produce a single texture for both eyes. - if ( i === 0 ) { - - renderer.setRenderTargetTextures( - newRenderTarget, - glSubImage.colorTexture, - glProjLayer.ignoreDepthValues ? undefined : glSubImage.depthStencilTexture ); - - renderer.setRenderTarget( newRenderTarget ); - - } - - } - - let camera = cameras[ i ]; - - if ( camera === undefined ) { - - camera = new PerspectiveCamera(); - camera.layers.enable( i ); - camera.viewport = new Vector4(); - cameras[ i ] = camera; - - } - - camera.matrix.fromArray( view.transform.matrix ); - camera.matrix.decompose( camera.position, camera.quaternion, camera.scale ); - camera.projectionMatrix.fromArray( view.projectionMatrix ); - camera.projectionMatrixInverse.copy( camera.projectionMatrix ).invert(); - camera.viewport.set( viewport.x, viewport.y, viewport.width, viewport.height ); - - if ( i === 0 ) { - - cameraXR.matrix.copy( camera.matrix ); - cameraXR.matrix.decompose( cameraXR.position, cameraXR.quaternion, cameraXR.scale ); - - } - - if ( cameraXRNeedsUpdate === true ) { - - cameraXR.cameras.push( camera ); - - } - - } - - // - - const enabledFeatures = session.enabledFeatures; - - if ( enabledFeatures && enabledFeatures.includes( 'depth-sensing' ) ) { - - const depthData = glBinding.getDepthInformation( views[ 0 ] ); - - if ( depthData && depthData.isValid && depthData.texture ) { - - depthSensing.init( renderer, depthData, session.renderState ); - - } - - } - - } - - // - - for ( let i = 0; i < controllers.length; i ++ ) { - - const inputSource = controllerInputSources[ i ]; - const controller = controllers[ i ]; - - if ( inputSource !== null && controller !== undefined ) { - - controller.update( inputSource, frame, customReferenceSpace || referenceSpace ); - - } - - } - - depthSensing.render( renderer, cameraXR ); - - if ( onAnimationFrameCallback ) onAnimationFrameCallback( time, frame ); - - if ( frame.detectedPlanes ) { - - scope.dispatchEvent( { type: 'planesdetected', data: frame } ); - - } - - xrFrame = null; - - } - - const animation = new WebGLAnimation(); - - animation.setAnimationLoop( onAnimationFrame ); - - this.setAnimationLoop = function ( callback ) { - - onAnimationFrameCallback = callback; - - }; - - this.dispose = function () {}; - - } - -} - -function WebGLMaterials( renderer, properties ) { - - function refreshTransformUniform( map, uniform ) { - - if ( map.matrixAutoUpdate === true ) { - - map.updateMatrix(); - - } - - uniform.value.copy( map.matrix ); - - } - - function refreshFogUniforms( uniforms, fog ) { - - fog.color.getRGB( uniforms.fogColor.value, getUnlitUniformColorSpace( renderer ) ); - - if ( fog.isFog ) { - - uniforms.fogNear.value = fog.near; - uniforms.fogFar.value = fog.far; - - } else if ( fog.isFogExp2 ) { - - uniforms.fogDensity.value = fog.density; - - } - - } - - function refreshMaterialUniforms( uniforms, material, pixelRatio, height, transmissionRenderTarget ) { - - if ( material.isMeshBasicMaterial ) { - - refreshUniformsCommon( uniforms, material ); - - } else if ( material.isMeshLambertMaterial ) { - - refreshUniformsCommon( uniforms, material ); - - } else if ( material.isMeshToonMaterial ) { - - refreshUniformsCommon( uniforms, material ); - refreshUniformsToon( uniforms, material ); - - } else if ( material.isMeshPhongMaterial ) { - - refreshUniformsCommon( uniforms, material ); - refreshUniformsPhong( uniforms, material ); - - } else if ( material.isMeshStandardMaterial ) { - - refreshUniformsCommon( uniforms, material ); - refreshUniformsStandard( uniforms, material ); - - if ( material.isMeshPhysicalMaterial ) { - - refreshUniformsPhysical( uniforms, material, transmissionRenderTarget ); - - } - - } else if ( material.isMeshMatcapMaterial ) { - - refreshUniformsCommon( uniforms, material ); - refreshUniformsMatcap( uniforms, material ); - - } else if ( material.isMeshDepthMaterial ) { - - refreshUniformsCommon( uniforms, material ); - - } else if ( material.isMeshDistanceMaterial ) { - - refreshUniformsCommon( uniforms, material ); - refreshUniformsDistance( uniforms, material ); - - } else if ( material.isMeshNormalMaterial ) { - - refreshUniformsCommon( uniforms, material ); - - } else if ( material.isLineBasicMaterial ) { - - refreshUniformsLine( uniforms, material ); - - if ( material.isLineDashedMaterial ) { - - refreshUniformsDash( uniforms, material ); - - } - - } else if ( material.isPointsMaterial ) { - - refreshUniformsPoints( uniforms, material, pixelRatio, height ); - - } else if ( material.isSpriteMaterial ) { - - refreshUniformsSprites( uniforms, material ); - - } else if ( material.isShadowMaterial ) { - - uniforms.color.value.copy( material.color ); - uniforms.opacity.value = material.opacity; - - } else if ( material.isShaderMaterial ) { - - material.uniformsNeedUpdate = false; // #15581 - - } - - } - - function refreshUniformsCommon( uniforms, material ) { - - uniforms.opacity.value = material.opacity; - - if ( material.color ) { - - uniforms.diffuse.value.copy( material.color ); - - } - - if ( material.emissive ) { - - uniforms.emissive.value.copy( material.emissive ).multiplyScalar( material.emissiveIntensity ); - - } - - if ( material.map ) { - - uniforms.map.value = material.map; - - refreshTransformUniform( material.map, uniforms.mapTransform ); - - } - - if ( material.alphaMap ) { - - uniforms.alphaMap.value = material.alphaMap; - - refreshTransformUniform( material.alphaMap, uniforms.alphaMapTransform ); - - } - - if ( material.bumpMap ) { - - uniforms.bumpMap.value = material.bumpMap; - - refreshTransformUniform( material.bumpMap, uniforms.bumpMapTransform ); - - uniforms.bumpScale.value = material.bumpScale; - - if ( material.side === BackSide ) { - - uniforms.bumpScale.value *= - 1; - - } - - } - - if ( material.normalMap ) { - - uniforms.normalMap.value = material.normalMap; - - refreshTransformUniform( material.normalMap, uniforms.normalMapTransform ); - - uniforms.normalScale.value.copy( material.normalScale ); - - if ( material.side === BackSide ) { - - uniforms.normalScale.value.negate(); - - } - - } - - if ( material.displacementMap ) { - - uniforms.displacementMap.value = material.displacementMap; - - refreshTransformUniform( material.displacementMap, uniforms.displacementMapTransform ); - - uniforms.displacementScale.value = material.displacementScale; - uniforms.displacementBias.value = material.displacementBias; - - } - - if ( material.emissiveMap ) { - - uniforms.emissiveMap.value = material.emissiveMap; - - refreshTransformUniform( material.emissiveMap, uniforms.emissiveMapTransform ); - - } - - if ( material.specularMap ) { - - uniforms.specularMap.value = material.specularMap; - - refreshTransformUniform( material.specularMap, uniforms.specularMapTransform ); - - } - - if ( material.alphaTest > 0 ) { - - uniforms.alphaTest.value = material.alphaTest; - - } - - const envMap = properties.get( material ).envMap; - - if ( envMap ) { - - uniforms.envMap.value = envMap; - - uniforms.flipEnvMap.value = ( envMap.isCubeTexture && envMap.isRenderTargetTexture === false ) ? - 1 : 1; - - uniforms.reflectivity.value = material.reflectivity; - uniforms.ior.value = material.ior; - uniforms.refractionRatio.value = material.refractionRatio; - - } - - if ( material.lightMap ) { - - uniforms.lightMap.value = material.lightMap; - - // artist-friendly light intensity scaling factor - const scaleFactor = ( renderer._useLegacyLights === true ) ? Math.PI : 1; - - uniforms.lightMapIntensity.value = material.lightMapIntensity * scaleFactor; - - refreshTransformUniform( material.lightMap, uniforms.lightMapTransform ); - - } - - if ( material.aoMap ) { - - uniforms.aoMap.value = material.aoMap; - uniforms.aoMapIntensity.value = material.aoMapIntensity; - - refreshTransformUniform( material.aoMap, uniforms.aoMapTransform ); - - } - - } - - function refreshUniformsLine( uniforms, material ) { - - uniforms.diffuse.value.copy( material.color ); - uniforms.opacity.value = material.opacity; - - if ( material.map ) { - - uniforms.map.value = material.map; - - refreshTransformUniform( material.map, uniforms.mapTransform ); - - } - - } - - function refreshUniformsDash( uniforms, material ) { - - uniforms.dashSize.value = material.dashSize; - uniforms.totalSize.value = material.dashSize + material.gapSize; - uniforms.scale.value = material.scale; - - } - - function refreshUniformsPoints( uniforms, material, pixelRatio, height ) { - - uniforms.diffuse.value.copy( material.color ); - uniforms.opacity.value = material.opacity; - uniforms.size.value = material.size * pixelRatio; - uniforms.scale.value = height * 0.5; - - if ( material.map ) { - - uniforms.map.value = material.map; - - refreshTransformUniform( material.map, uniforms.uvTransform ); - - } - - if ( material.alphaMap ) { - - uniforms.alphaMap.value = material.alphaMap; - - refreshTransformUniform( material.alphaMap, uniforms.alphaMapTransform ); - - } - - if ( material.alphaTest > 0 ) { - - uniforms.alphaTest.value = material.alphaTest; - - } - - } - - function refreshUniformsSprites( uniforms, material ) { - - uniforms.diffuse.value.copy( material.color ); - uniforms.opacity.value = material.opacity; - uniforms.rotation.value = material.rotation; - - if ( material.map ) { - - uniforms.map.value = material.map; - - refreshTransformUniform( material.map, uniforms.mapTransform ); - - } - - if ( material.alphaMap ) { - - uniforms.alphaMap.value = material.alphaMap; - - refreshTransformUniform( material.alphaMap, uniforms.alphaMapTransform ); - - } - - if ( material.alphaTest > 0 ) { - - uniforms.alphaTest.value = material.alphaTest; - - } - - } - - function refreshUniformsPhong( uniforms, material ) { - - uniforms.specular.value.copy( material.specular ); - uniforms.shininess.value = Math.max( material.shininess, 1e-4 ); // to prevent pow( 0.0, 0.0 ) - - } - - function refreshUniformsToon( uniforms, material ) { - - if ( material.gradientMap ) { - - uniforms.gradientMap.value = material.gradientMap; - - } - - } - - function refreshUniformsStandard( uniforms, material ) { - - uniforms.metalness.value = material.metalness; - - if ( material.metalnessMap ) { - - uniforms.metalnessMap.value = material.metalnessMap; - - refreshTransformUniform( material.metalnessMap, uniforms.metalnessMapTransform ); - - } - - uniforms.roughness.value = material.roughness; - - if ( material.roughnessMap ) { - - uniforms.roughnessMap.value = material.roughnessMap; - - refreshTransformUniform( material.roughnessMap, uniforms.roughnessMapTransform ); - - } - - const envMap = properties.get( material ).envMap; - - if ( envMap ) { - - //uniforms.envMap.value = material.envMap; // part of uniforms common - uniforms.envMapIntensity.value = material.envMapIntensity; - - } - - } - - function refreshUniformsPhysical( uniforms, material, transmissionRenderTarget ) { - - uniforms.ior.value = material.ior; // also part of uniforms common - - if ( material.sheen > 0 ) { - - uniforms.sheenColor.value.copy( material.sheenColor ).multiplyScalar( material.sheen ); - - uniforms.sheenRoughness.value = material.sheenRoughness; - - if ( material.sheenColorMap ) { - - uniforms.sheenColorMap.value = material.sheenColorMap; - - refreshTransformUniform( material.sheenColorMap, uniforms.sheenColorMapTransform ); - - } - - if ( material.sheenRoughnessMap ) { - - uniforms.sheenRoughnessMap.value = material.sheenRoughnessMap; - - refreshTransformUniform( material.sheenRoughnessMap, uniforms.sheenRoughnessMapTransform ); - - } - - } - - if ( material.clearcoat > 0 ) { - - uniforms.clearcoat.value = material.clearcoat; - uniforms.clearcoatRoughness.value = material.clearcoatRoughness; - - if ( material.clearcoatMap ) { - - uniforms.clearcoatMap.value = material.clearcoatMap; - - refreshTransformUniform( material.clearcoatMap, uniforms.clearcoatMapTransform ); - - } - - if ( material.clearcoatRoughnessMap ) { - - uniforms.clearcoatRoughnessMap.value = material.clearcoatRoughnessMap; - - refreshTransformUniform( material.clearcoatRoughnessMap, uniforms.clearcoatRoughnessMapTransform ); - - } - - if ( material.clearcoatNormalMap ) { - - uniforms.clearcoatNormalMap.value = material.clearcoatNormalMap; - - refreshTransformUniform( material.clearcoatNormalMap, uniforms.clearcoatNormalMapTransform ); - - uniforms.clearcoatNormalScale.value.copy( material.clearcoatNormalScale ); - - if ( material.side === BackSide ) { - - uniforms.clearcoatNormalScale.value.negate(); - - } - - } - - } - - if ( material.iridescence > 0 ) { - - uniforms.iridescence.value = material.iridescence; - uniforms.iridescenceIOR.value = material.iridescenceIOR; - uniforms.iridescenceThicknessMinimum.value = material.iridescenceThicknessRange[ 0 ]; - uniforms.iridescenceThicknessMaximum.value = material.iridescenceThicknessRange[ 1 ]; - - if ( material.iridescenceMap ) { - - uniforms.iridescenceMap.value = material.iridescenceMap; - - refreshTransformUniform( material.iridescenceMap, uniforms.iridescenceMapTransform ); - - } - - if ( material.iridescenceThicknessMap ) { - - uniforms.iridescenceThicknessMap.value = material.iridescenceThicknessMap; - - refreshTransformUniform( material.iridescenceThicknessMap, uniforms.iridescenceThicknessMapTransform ); - - } - - } - - if ( material.transmission > 0 ) { - - uniforms.transmission.value = material.transmission; - uniforms.transmissionSamplerMap.value = transmissionRenderTarget.texture; - uniforms.transmissionSamplerSize.value.set( transmissionRenderTarget.width, transmissionRenderTarget.height ); - - if ( material.transmissionMap ) { - - uniforms.transmissionMap.value = material.transmissionMap; - - refreshTransformUniform( material.transmissionMap, uniforms.transmissionMapTransform ); - - } - - uniforms.thickness.value = material.thickness; - - if ( material.thicknessMap ) { - - uniforms.thicknessMap.value = material.thicknessMap; - - refreshTransformUniform( material.thicknessMap, uniforms.thicknessMapTransform ); - - } - - uniforms.attenuationDistance.value = material.attenuationDistance; - uniforms.attenuationColor.value.copy( material.attenuationColor ); - - } - - if ( material.anisotropy > 0 ) { - - uniforms.anisotropyVector.value.set( material.anisotropy * Math.cos( material.anisotropyRotation ), material.anisotropy * Math.sin( material.anisotropyRotation ) ); - - if ( material.anisotropyMap ) { - - uniforms.anisotropyMap.value = material.anisotropyMap; - - refreshTransformUniform( material.anisotropyMap, uniforms.anisotropyMapTransform ); - - } - - } - - uniforms.specularIntensity.value = material.specularIntensity; - uniforms.specularColor.value.copy( material.specularColor ); - - if ( material.specularColorMap ) { - - uniforms.specularColorMap.value = material.specularColorMap; - - refreshTransformUniform( material.specularColorMap, uniforms.specularColorMapTransform ); - - } - - if ( material.specularIntensityMap ) { - - uniforms.specularIntensityMap.value = material.specularIntensityMap; - - refreshTransformUniform( material.specularIntensityMap, uniforms.specularIntensityMapTransform ); - - } - - } - - function refreshUniformsMatcap( uniforms, material ) { - - if ( material.matcap ) { - - uniforms.matcap.value = material.matcap; - - } - - } - - function refreshUniformsDistance( uniforms, material ) { - - const light = properties.get( material ).light; - - uniforms.referencePosition.value.setFromMatrixPosition( light.matrixWorld ); - uniforms.nearDistance.value = light.shadow.camera.near; - uniforms.farDistance.value = light.shadow.camera.far; - - } - - return { - refreshFogUniforms: refreshFogUniforms, - refreshMaterialUniforms: refreshMaterialUniforms - }; - -} - -function WebGLUniformsGroups( gl, info, capabilities, state ) { - - let buffers = {}; - let updateList = {}; - let allocatedBindingPoints = []; - - const maxBindingPoints = ( capabilities.isWebGL2 ) ? gl.getParameter( gl.MAX_UNIFORM_BUFFER_BINDINGS ) : 0; // binding points are global whereas block indices are per shader program - - function bind( uniformsGroup, program ) { - - const webglProgram = program.program; - state.uniformBlockBinding( uniformsGroup, webglProgram ); - - } - - function update( uniformsGroup, program ) { - - let buffer = buffers[ uniformsGroup.id ]; - - if ( buffer === undefined ) { - - prepareUniformsGroup( uniformsGroup ); - - buffer = createBuffer( uniformsGroup ); - buffers[ uniformsGroup.id ] = buffer; - - uniformsGroup.addEventListener( 'dispose', onUniformsGroupsDispose ); - - } - - // ensure to update the binding points/block indices mapping for this program - - const webglProgram = program.program; - state.updateUBOMapping( uniformsGroup, webglProgram ); - - // update UBO once per frame - - const frame = info.render.frame; - - if ( updateList[ uniformsGroup.id ] !== frame ) { - - updateBufferData( uniformsGroup ); - - updateList[ uniformsGroup.id ] = frame; - - } - - } - - function createBuffer( uniformsGroup ) { - - // the setup of an UBO is independent of a particular shader program but global - - const bindingPointIndex = allocateBindingPointIndex(); - uniformsGroup.__bindingPointIndex = bindingPointIndex; - - const buffer = gl.createBuffer(); - const size = uniformsGroup.__size; - const usage = uniformsGroup.usage; - - gl.bindBuffer( gl.UNIFORM_BUFFER, buffer ); - gl.bufferData( gl.UNIFORM_BUFFER, size, usage ); - gl.bindBuffer( gl.UNIFORM_BUFFER, null ); - gl.bindBufferBase( gl.UNIFORM_BUFFER, bindingPointIndex, buffer ); - - return buffer; - - } - - function allocateBindingPointIndex() { - - for ( let i = 0; i < maxBindingPoints; i ++ ) { - - if ( allocatedBindingPoints.indexOf( i ) === - 1 ) { - - allocatedBindingPoints.push( i ); - return i; - - } - - } - - console.error( 'THREE.WebGLRenderer: Maximum number of simultaneously usable uniforms groups reached.' ); - - return 0; - - } - - function updateBufferData( uniformsGroup ) { - - const buffer = buffers[ uniformsGroup.id ]; - const uniforms = uniformsGroup.uniforms; - const cache = uniformsGroup.__cache; - - gl.bindBuffer( gl.UNIFORM_BUFFER, buffer ); - - for ( let i = 0, il = uniforms.length; i < il; i ++ ) { - - const uniformArray = Array.isArray( uniforms[ i ] ) ? uniforms[ i ] : [ uniforms[ i ] ]; - - for ( let j = 0, jl = uniformArray.length; j < jl; j ++ ) { - - const uniform = uniformArray[ j ]; - - if ( hasUniformChanged( uniform, i, j, cache ) === true ) { - - const offset = uniform.__offset; - - const values = Array.isArray( uniform.value ) ? uniform.value : [ uniform.value ]; - - let arrayOffset = 0; - - for ( let k = 0; k < values.length; k ++ ) { - - const value = values[ k ]; - - const info = getUniformSize( value ); - - // TODO add integer and struct support - if ( typeof value === 'number' || typeof value === 'boolean' ) { - - uniform.__data[ 0 ] = value; - gl.bufferSubData( gl.UNIFORM_BUFFER, offset + arrayOffset, uniform.__data ); - - } else if ( value.isMatrix3 ) { - - // manually converting 3x3 to 3x4 - - uniform.__data[ 0 ] = value.elements[ 0 ]; - uniform.__data[ 1 ] = value.elements[ 1 ]; - uniform.__data[ 2 ] = value.elements[ 2 ]; - uniform.__data[ 3 ] = 0; - uniform.__data[ 4 ] = value.elements[ 3 ]; - uniform.__data[ 5 ] = value.elements[ 4 ]; - uniform.__data[ 6 ] = value.elements[ 5 ]; - uniform.__data[ 7 ] = 0; - uniform.__data[ 8 ] = value.elements[ 6 ]; - uniform.__data[ 9 ] = value.elements[ 7 ]; - uniform.__data[ 10 ] = value.elements[ 8 ]; - uniform.__data[ 11 ] = 0; - - } else { - - value.toArray( uniform.__data, arrayOffset ); - - arrayOffset += info.storage / Float32Array.BYTES_PER_ELEMENT; - - } - - } - - gl.bufferSubData( gl.UNIFORM_BUFFER, offset, uniform.__data ); - - } - - } - - } - - gl.bindBuffer( gl.UNIFORM_BUFFER, null ); - - } - - function hasUniformChanged( uniform, index, indexArray, cache ) { - - const value = uniform.value; - const indexString = index + '_' + indexArray; - - if ( cache[ indexString ] === undefined ) { - - // cache entry does not exist so far - - if ( typeof value === 'number' || typeof value === 'boolean' ) { - - cache[ indexString ] = value; - - } else { - - cache[ indexString ] = value.clone(); - - } - - return true; - - } else { - - const cachedObject = cache[ indexString ]; - - // compare current value with cached entry - - if ( typeof value === 'number' || typeof value === 'boolean' ) { - - if ( cachedObject !== value ) { - - cache[ indexString ] = value; - return true; - - } - - } else { - - if ( cachedObject.equals( value ) === false ) { - - cachedObject.copy( value ); - return true; - - } - - } - - } - - return false; - - } - - function prepareUniformsGroup( uniformsGroup ) { - - // determine total buffer size according to the STD140 layout - // Hint: STD140 is the only supported layout in WebGL 2 - - const uniforms = uniformsGroup.uniforms; - - let offset = 0; // global buffer offset in bytes - const chunkSize = 16; // size of a chunk in bytes - - for ( let i = 0, l = uniforms.length; i < l; i ++ ) { - - const uniformArray = Array.isArray( uniforms[ i ] ) ? uniforms[ i ] : [ uniforms[ i ] ]; - - for ( let j = 0, jl = uniformArray.length; j < jl; j ++ ) { - - const uniform = uniformArray[ j ]; - - const values = Array.isArray( uniform.value ) ? uniform.value : [ uniform.value ]; - - for ( let k = 0, kl = values.length; k < kl; k ++ ) { - - const value = values[ k ]; - - const info = getUniformSize( value ); - - // Calculate the chunk offset - const chunkOffsetUniform = offset % chunkSize; - - // Check for chunk overflow - if ( chunkOffsetUniform !== 0 && ( chunkSize - chunkOffsetUniform ) < info.boundary ) { - - // Add padding and adjust offset - offset += ( chunkSize - chunkOffsetUniform ); - - } - - // the following two properties will be used for partial buffer updates - - uniform.__data = new Float32Array( info.storage / Float32Array.BYTES_PER_ELEMENT ); - uniform.__offset = offset; - - - // Update the global offset - offset += info.storage; - - - } - - } - - } - - // ensure correct final padding - - const chunkOffset = offset % chunkSize; - - if ( chunkOffset > 0 ) offset += ( chunkSize - chunkOffset ); - - // - - uniformsGroup.__size = offset; - uniformsGroup.__cache = {}; - - return this; - - } - - function getUniformSize( value ) { - - const info = { - boundary: 0, // bytes - storage: 0 // bytes - }; - - // determine sizes according to STD140 - - if ( typeof value === 'number' || typeof value === 'boolean' ) { - - // float/int/bool - - info.boundary = 4; - info.storage = 4; - - } else if ( value.isVector2 ) { - - // vec2 - - info.boundary = 8; - info.storage = 8; - - } else if ( value.isVector3 || value.isColor ) { - - // vec3 - - info.boundary = 16; - info.storage = 12; // evil: vec3 must start on a 16-byte boundary but it only consumes 12 bytes - - } else if ( value.isVector4 ) { - - // vec4 - - info.boundary = 16; - info.storage = 16; - - } else if ( value.isMatrix3 ) { - - // mat3 (in STD140 a 3x3 matrix is represented as 3x4) - - info.boundary = 48; - info.storage = 48; - - } else if ( value.isMatrix4 ) { - - // mat4 - - info.boundary = 64; - info.storage = 64; - - } else if ( value.isTexture ) { - - console.warn( 'THREE.WebGLRenderer: Texture samplers can not be part of an uniforms group.' ); - - } else { - - console.warn( 'THREE.WebGLRenderer: Unsupported uniform value type.', value ); - - } - - return info; - - } - - function onUniformsGroupsDispose( event ) { - - const uniformsGroup = event.target; - - uniformsGroup.removeEventListener( 'dispose', onUniformsGroupsDispose ); - - const index = allocatedBindingPoints.indexOf( uniformsGroup.__bindingPointIndex ); - allocatedBindingPoints.splice( index, 1 ); - - gl.deleteBuffer( buffers[ uniformsGroup.id ] ); - - delete buffers[ uniformsGroup.id ]; - delete updateList[ uniformsGroup.id ]; - - } - - function dispose() { - - for ( const id in buffers ) { - - gl.deleteBuffer( buffers[ id ] ); - - } - - allocatedBindingPoints = []; - buffers = {}; - updateList = {}; - - } - - return { - - bind: bind, - update: update, - - dispose: dispose - - }; - -} - -class WebGLRenderer { - - constructor( parameters = {} ) { - - const { - canvas = createCanvasElement(), - context = null, - depth = true, - stencil = true, - alpha = false, - antialias = false, - premultipliedAlpha = true, - preserveDrawingBuffer = false, - powerPreference = 'default', - failIfMajorPerformanceCaveat = false, - } = parameters; - - this.isWebGLRenderer = true; - - let _alpha; - - if ( context !== null ) { - - _alpha = context.getContextAttributes().alpha; - - } else { - - _alpha = alpha; - - } - - const uintClearColor = new Uint32Array( 4 ); - const intClearColor = new Int32Array( 4 ); - - let currentRenderList = null; - let currentRenderState = null; - - // render() can be called from within a callback triggered by another render. - // We track this so that the nested render call gets its list and state isolated from the parent render call. - - const renderListStack = []; - const renderStateStack = []; - - // public properties - - this.domElement = canvas; - - // Debug configuration container - this.debug = { - - /** - * Enables error checking and reporting when shader programs are being compiled - * @type {boolean} - */ - checkShaderErrors: true, - /** - * Callback for custom error reporting. - * @type {?Function} - */ - onShaderError: null - }; - - // clearing - - this.autoClear = true; - this.autoClearColor = true; - this.autoClearDepth = true; - this.autoClearStencil = true; - - // scene graph - - this.sortObjects = true; - - // user-defined clipping - - this.clippingPlanes = []; - this.localClippingEnabled = false; - - // physically based shading - - this._outputColorSpace = SRGBColorSpace; - - // physical lights - - this._useLegacyLights = false; - - // tone mapping - - this.toneMapping = NoToneMapping; - this.toneMappingExposure = 1.0; - - // internal properties - - const _this = this; - - let _isContextLost = false; - - // internal state cache - - let _currentActiveCubeFace = 0; - let _currentActiveMipmapLevel = 0; - let _currentRenderTarget = null; - let _currentMaterialId = - 1; - - let _currentCamera = null; - - const _currentViewport = new Vector4(); - const _currentScissor = new Vector4(); - let _currentScissorTest = null; - - const _currentClearColor = new Color( 0x000000 ); - let _currentClearAlpha = 0; - - // - - let _width = canvas.width; - let _height = canvas.height; - - let _pixelRatio = 1; - let _opaqueSort = null; - let _transparentSort = null; - - const _viewport = new Vector4( 0, 0, _width, _height ); - const _scissor = new Vector4( 0, 0, _width, _height ); - let _scissorTest = false; - - // frustum - - const _frustum = new Frustum(); - - // clipping - - let _clippingEnabled = false; - let _localClippingEnabled = false; - - // transmission - - let _transmissionRenderTarget = null; - - // camera matrices cache - - const _projScreenMatrix = new Matrix4(); - - const _vector2 = new Vector2(); - const _vector3 = new Vector3(); - - const _emptyScene = { background: null, fog: null, environment: null, overrideMaterial: null, isScene: true }; - - function getTargetPixelRatio() { - - return _currentRenderTarget === null ? _pixelRatio : 1; - - } - - // initialize - - let _gl = context; - - function getContext( contextNames, contextAttributes ) { - - for ( let i = 0; i < contextNames.length; i ++ ) { - - const contextName = contextNames[ i ]; - const context = canvas.getContext( contextName, contextAttributes ); - if ( context !== null ) return context; - - } - - return null; - - } - - try { - - const contextAttributes = { - alpha: true, - depth, - stencil, - antialias, - premultipliedAlpha, - preserveDrawingBuffer, - powerPreference, - failIfMajorPerformanceCaveat, - }; - - // OffscreenCanvas does not have setAttribute, see #22811 - if ( 'setAttribute' in canvas ) canvas.setAttribute( 'data-engine', `three.js r${REVISION}` ); - - // event listeners must be registered before WebGL context is created, see #12753 - canvas.addEventListener( 'webglcontextlost', onContextLost, false ); - canvas.addEventListener( 'webglcontextrestored', onContextRestore, false ); - canvas.addEventListener( 'webglcontextcreationerror', onContextCreationError, false ); - - if ( _gl === null ) { - - const contextNames = [ 'webgl2', 'webgl', 'experimental-webgl' ]; - - if ( _this.isWebGL1Renderer === true ) { - - contextNames.shift(); - - } - - _gl = getContext( contextNames, contextAttributes ); - - if ( _gl === null ) { - - if ( getContext( contextNames ) ) { - - throw new Error( 'Error creating WebGL context with your selected attributes.' ); - - } else { - - throw new Error( 'Error creating WebGL context.' ); - - } - - } - - } - - if ( typeof WebGLRenderingContext !== 'undefined' && _gl instanceof WebGLRenderingContext ) { // @deprecated, r153 - - console.warn( 'THREE.WebGLRenderer: WebGL 1 support was deprecated in r153 and will be removed in r163.' ); - - } - - // Some experimental-webgl implementations do not have getShaderPrecisionFormat - - if ( _gl.getShaderPrecisionFormat === undefined ) { - - _gl.getShaderPrecisionFormat = function () { - - return { 'rangeMin': 1, 'rangeMax': 1, 'precision': 1 }; - - }; - - } - - } catch ( error ) { - - console.error( 'THREE.WebGLRenderer: ' + error.message ); - throw error; - - } - - let extensions, capabilities, state, info; - let properties, textures, cubemaps, cubeuvmaps, attributes, geometries, objects; - let programCache, materials, renderLists, renderStates, clipping, shadowMap; - - let background, morphtargets, bufferRenderer, indexedBufferRenderer; - - let utils, bindingStates, uniformsGroups; - - function initGLContext() { - - extensions = new WebGLExtensions( _gl ); - - capabilities = new WebGLCapabilities( _gl, extensions, parameters ); - - extensions.init( capabilities ); - - utils = new WebGLUtils( _gl, extensions, capabilities ); - - state = new WebGLState( _gl, extensions, capabilities ); - - info = new WebGLInfo( _gl ); - properties = new WebGLProperties(); - textures = new WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info ); - cubemaps = new WebGLCubeMaps( _this ); - cubeuvmaps = new WebGLCubeUVMaps( _this ); - attributes = new WebGLAttributes( _gl, capabilities ); - bindingStates = new WebGLBindingStates( _gl, extensions, attributes, capabilities ); - geometries = new WebGLGeometries( _gl, attributes, info, bindingStates ); - objects = new WebGLObjects( _gl, geometries, attributes, info ); - morphtargets = new WebGLMorphtargets( _gl, capabilities, textures ); - clipping = new WebGLClipping( properties ); - programCache = new WebGLPrograms( _this, cubemaps, cubeuvmaps, extensions, capabilities, bindingStates, clipping ); - materials = new WebGLMaterials( _this, properties ); - renderLists = new WebGLRenderLists(); - renderStates = new WebGLRenderStates( extensions, capabilities ); - background = new WebGLBackground( _this, cubemaps, cubeuvmaps, state, objects, _alpha, premultipliedAlpha ); - shadowMap = new WebGLShadowMap( _this, objects, capabilities ); - uniformsGroups = new WebGLUniformsGroups( _gl, info, capabilities, state ); - - bufferRenderer = new WebGLBufferRenderer( _gl, extensions, info, capabilities ); - indexedBufferRenderer = new WebGLIndexedBufferRenderer( _gl, extensions, info, capabilities ); - - info.programs = programCache.programs; - - _this.capabilities = capabilities; - _this.extensions = extensions; - _this.properties = properties; - _this.renderLists = renderLists; - _this.shadowMap = shadowMap; - _this.state = state; - _this.info = info; - - } - - initGLContext(); - - // xr - - const xr = new WebXRManager( _this, _gl ); - - this.xr = xr; - - // API - - this.getContext = function () { - - return _gl; - - }; - - this.getContextAttributes = function () { - - return _gl.getContextAttributes(); - - }; - - this.forceContextLoss = function () { - - const extension = extensions.get( 'WEBGL_lose_context' ); - if ( extension ) extension.loseContext(); - - }; - - this.forceContextRestore = function () { - - const extension = extensions.get( 'WEBGL_lose_context' ); - if ( extension ) extension.restoreContext(); - - }; - - this.getPixelRatio = function () { - - return _pixelRatio; - - }; - - this.setPixelRatio = function ( value ) { - - if ( value === undefined ) return; - - _pixelRatio = value; - - this.setSize( _width, _height, false ); - - }; - - this.getSize = function ( target ) { - - return target.set( _width, _height ); - - }; - - this.setSize = function ( width, height, updateStyle = true ) { - - if ( xr.isPresenting ) { - - console.warn( 'THREE.WebGLRenderer: Can\'t change size while VR device is presenting.' ); - return; - - } - - _width = width; - _height = height; - - canvas.width = Math.floor( width * _pixelRatio ); - canvas.height = Math.floor( height * _pixelRatio ); - - if ( updateStyle === true ) { - - canvas.style.width = width + 'px'; - canvas.style.height = height + 'px'; - - } - - this.setViewport( 0, 0, width, height ); - - }; - - this.getDrawingBufferSize = function ( target ) { - - return target.set( _width * _pixelRatio, _height * _pixelRatio ).floor(); - - }; - - this.setDrawingBufferSize = function ( width, height, pixelRatio ) { - - _width = width; - _height = height; - - _pixelRatio = pixelRatio; - - canvas.width = Math.floor( width * pixelRatio ); - canvas.height = Math.floor( height * pixelRatio ); - - this.setViewport( 0, 0, width, height ); - - }; - - this.getCurrentViewport = function ( target ) { - - return target.copy( _currentViewport ); - - }; - - this.getViewport = function ( target ) { - - return target.copy( _viewport ); - - }; - - this.setViewport = function ( x, y, width, height ) { - - if ( x.isVector4 ) { - - _viewport.set( x.x, x.y, x.z, x.w ); - - } else { - - _viewport.set( x, y, width, height ); - - } - - state.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).floor() ); - - }; - - this.getScissor = function ( target ) { - - return target.copy( _scissor ); - - }; - - this.setScissor = function ( x, y, width, height ) { - - if ( x.isVector4 ) { - - _scissor.set( x.x, x.y, x.z, x.w ); - - } else { - - _scissor.set( x, y, width, height ); - - } - - state.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).floor() ); - - }; - - this.getScissorTest = function () { - - return _scissorTest; - - }; - - this.setScissorTest = function ( boolean ) { - - state.setScissorTest( _scissorTest = boolean ); - - }; - - this.setOpaqueSort = function ( method ) { - - _opaqueSort = method; - - }; - - this.setTransparentSort = function ( method ) { - - _transparentSort = method; - - }; - - // Clearing - - this.getClearColor = function ( target ) { - - return target.copy( background.getClearColor() ); - - }; - - this.setClearColor = function () { - - background.setClearColor.apply( background, arguments ); - - }; - - this.getClearAlpha = function () { - - return background.getClearAlpha(); - - }; - - this.setClearAlpha = function () { - - background.setClearAlpha.apply( background, arguments ); - - }; - - this.clear = function ( color = true, depth = true, stencil = true ) { - - let bits = 0; - - if ( color ) { - - // check if we're trying to clear an integer target - let isIntegerFormat = false; - if ( _currentRenderTarget !== null ) { - - const targetFormat = _currentRenderTarget.texture.format; - isIntegerFormat = targetFormat === RGBAIntegerFormat || - targetFormat === RGIntegerFormat || - targetFormat === RedIntegerFormat; - - } - - // use the appropriate clear functions to clear the target if it's a signed - // or unsigned integer target - if ( isIntegerFormat ) { - - const targetType = _currentRenderTarget.texture.type; - const isUnsignedType = targetType === UnsignedByteType || - targetType === UnsignedIntType || - targetType === UnsignedShortType || - targetType === UnsignedInt248Type || - targetType === UnsignedShort4444Type || - targetType === UnsignedShort5551Type; - - const clearColor = background.getClearColor(); - const a = background.getClearAlpha(); - const r = clearColor.r; - const g = clearColor.g; - const b = clearColor.b; - - if ( isUnsignedType ) { - - uintClearColor[ 0 ] = r; - uintClearColor[ 1 ] = g; - uintClearColor[ 2 ] = b; - uintClearColor[ 3 ] = a; - _gl.clearBufferuiv( _gl.COLOR, 0, uintClearColor ); - - } else { - - intClearColor[ 0 ] = r; - intClearColor[ 1 ] = g; - intClearColor[ 2 ] = b; - intClearColor[ 3 ] = a; - _gl.clearBufferiv( _gl.COLOR, 0, intClearColor ); - - } - - } else { - - bits |= _gl.COLOR_BUFFER_BIT; - - } - - } - - if ( depth ) bits |= _gl.DEPTH_BUFFER_BIT; - if ( stencil ) { - - bits |= _gl.STENCIL_BUFFER_BIT; - this.state.buffers.stencil.setMask( 0xffffffff ); - - } - - _gl.clear( bits ); - - }; - - this.clearColor = function () { - - this.clear( true, false, false ); - - }; - - this.clearDepth = function () { - - this.clear( false, true, false ); - - }; - - this.clearStencil = function () { - - this.clear( false, false, true ); - - }; - - // - - this.dispose = function () { - - canvas.removeEventListener( 'webglcontextlost', onContextLost, false ); - canvas.removeEventListener( 'webglcontextrestored', onContextRestore, false ); - canvas.removeEventListener( 'webglcontextcreationerror', onContextCreationError, false ); - - renderLists.dispose(); - renderStates.dispose(); - properties.dispose(); - cubemaps.dispose(); - cubeuvmaps.dispose(); - objects.dispose(); - bindingStates.dispose(); - uniformsGroups.dispose(); - programCache.dispose(); - - xr.dispose(); - - xr.removeEventListener( 'sessionstart', onXRSessionStart ); - xr.removeEventListener( 'sessionend', onXRSessionEnd ); - - if ( _transmissionRenderTarget ) { - - _transmissionRenderTarget.dispose(); - _transmissionRenderTarget = null; - - } - - animation.stop(); - - }; - - // Events - - function onContextLost( event ) { - - event.preventDefault(); - - console.log( 'THREE.WebGLRenderer: Context Lost.' ); - - _isContextLost = true; - - } - - function onContextRestore( /* event */ ) { - - console.log( 'THREE.WebGLRenderer: Context Restored.' ); - - _isContextLost = false; - - const infoAutoReset = info.autoReset; - const shadowMapEnabled = shadowMap.enabled; - const shadowMapAutoUpdate = shadowMap.autoUpdate; - const shadowMapNeedsUpdate = shadowMap.needsUpdate; - const shadowMapType = shadowMap.type; - - initGLContext(); - - info.autoReset = infoAutoReset; - shadowMap.enabled = shadowMapEnabled; - shadowMap.autoUpdate = shadowMapAutoUpdate; - shadowMap.needsUpdate = shadowMapNeedsUpdate; - shadowMap.type = shadowMapType; - - } - - function onContextCreationError( event ) { - - console.error( 'THREE.WebGLRenderer: A WebGL context could not be created. Reason: ', event.statusMessage ); - - } - - function onMaterialDispose( event ) { - - const material = event.target; - - material.removeEventListener( 'dispose', onMaterialDispose ); - - deallocateMaterial( material ); - - } - - // Buffer deallocation - - function deallocateMaterial( material ) { - - releaseMaterialProgramReferences( material ); - - properties.remove( material ); - - } - - - function releaseMaterialProgramReferences( material ) { - - const programs = properties.get( material ).programs; - - if ( programs !== undefined ) { - - programs.forEach( function ( program ) { - - programCache.releaseProgram( program ); - - } ); - - if ( material.isShaderMaterial ) { - - programCache.releaseShaderCache( material ); - - } - - } - - } - - // Buffer rendering - - this.renderBufferDirect = function ( camera, scene, geometry, material, object, group ) { - - if ( scene === null ) scene = _emptyScene; // renderBufferDirect second parameter used to be fog (could be null) - - const frontFaceCW = ( object.isMesh && object.matrixWorld.determinant() < 0 ); - - const program = setProgram( camera, scene, geometry, material, object ); - - state.setMaterial( material, frontFaceCW ); - - // - - let index = geometry.index; - let rangeFactor = 1; - - if ( material.wireframe === true ) { - - index = geometries.getWireframeAttribute( geometry ); - - if ( index === undefined ) return; - - rangeFactor = 2; - - } - - // - - const drawRange = geometry.drawRange; - const position = geometry.attributes.position; - - let drawStart = drawRange.start * rangeFactor; - let drawEnd = ( drawRange.start + drawRange.count ) * rangeFactor; - - if ( group !== null ) { - - drawStart = Math.max( drawStart, group.start * rangeFactor ); - drawEnd = Math.min( drawEnd, ( group.start + group.count ) * rangeFactor ); - - } - - if ( index !== null ) { - - drawStart = Math.max( drawStart, 0 ); - drawEnd = Math.min( drawEnd, index.count ); - - } else if ( position !== undefined && position !== null ) { - - drawStart = Math.max( drawStart, 0 ); - drawEnd = Math.min( drawEnd, position.count ); - - } - - const drawCount = drawEnd - drawStart; - - if ( drawCount < 0 || drawCount === Infinity ) return; - - // - - bindingStates.setup( object, material, program, geometry, index ); - - let attribute; - let renderer = bufferRenderer; - - if ( index !== null ) { - - attribute = attributes.get( index ); - - renderer = indexedBufferRenderer; - renderer.setIndex( attribute ); - - } - - // - - if ( object.isMesh ) { - - if ( material.wireframe === true ) { - - state.setLineWidth( material.wireframeLinewidth * getTargetPixelRatio() ); - renderer.setMode( _gl.LINES ); - - } else { - - renderer.setMode( _gl.TRIANGLES ); - - } - - } else if ( object.isLine ) { - - let lineWidth = material.linewidth; - - if ( lineWidth === undefined ) lineWidth = 1; // Not using Line*Material - - state.setLineWidth( lineWidth * getTargetPixelRatio() ); - - if ( object.isLineSegments ) { - - renderer.setMode( _gl.LINES ); - - } else if ( object.isLineLoop ) { - - renderer.setMode( _gl.LINE_LOOP ); - - } else { - - renderer.setMode( _gl.LINE_STRIP ); - - } - - } else if ( object.isPoints ) { - - renderer.setMode( _gl.POINTS ); - - } else if ( object.isSprite ) { - - renderer.setMode( _gl.TRIANGLES ); - - } - - if ( object.isBatchedMesh ) { - - renderer.renderMultiDraw( object._multiDrawStarts, object._multiDrawCounts, object._multiDrawCount ); - - } else if ( object.isInstancedMesh ) { - - renderer.renderInstances( drawStart, drawCount, object.count ); - - } else if ( geometry.isInstancedBufferGeometry ) { - - const maxInstanceCount = geometry._maxInstanceCount !== undefined ? geometry._maxInstanceCount : Infinity; - const instanceCount = Math.min( geometry.instanceCount, maxInstanceCount ); - - renderer.renderInstances( drawStart, drawCount, instanceCount ); - - } else { - - renderer.render( drawStart, drawCount ); - - } - - }; - - // Compile - - function prepareMaterial( material, scene, object ) { - - if ( material.transparent === true && material.side === DoubleSide && material.forceSinglePass === false ) { - - material.side = BackSide; - material.needsUpdate = true; - getProgram( material, scene, object ); - - material.side = FrontSide; - material.needsUpdate = true; - getProgram( material, scene, object ); - - material.side = DoubleSide; - - } else { - - getProgram( material, scene, object ); - - } - - } - - this.compile = function ( scene, camera, targetScene = null ) { - - if ( targetScene === null ) targetScene = scene; - - currentRenderState = renderStates.get( targetScene ); - currentRenderState.init(); - - renderStateStack.push( currentRenderState ); - - // gather lights from both the target scene and the new object that will be added to the scene. - - targetScene.traverseVisible( function ( object ) { - - if ( object.isLight && object.layers.test( camera.layers ) ) { - - currentRenderState.pushLight( object ); - - if ( object.castShadow ) { - - currentRenderState.pushShadow( object ); - - } - - } - - } ); - - if ( scene !== targetScene ) { - - scene.traverseVisible( function ( object ) { - - if ( object.isLight && object.layers.test( camera.layers ) ) { - - currentRenderState.pushLight( object ); - - if ( object.castShadow ) { - - currentRenderState.pushShadow( object ); - - } - - } - - } ); - - } - - currentRenderState.setupLights( _this._useLegacyLights ); - - // Only initialize materials in the new scene, not the targetScene. - - const materials = new Set(); - - scene.traverse( function ( object ) { - - const material = object.material; - - if ( material ) { - - if ( Array.isArray( material ) ) { - - for ( let i = 0; i < material.length; i ++ ) { - - const material2 = material[ i ]; - - prepareMaterial( material2, targetScene, object ); - materials.add( material2 ); - - } - - } else { - - prepareMaterial( material, targetScene, object ); - materials.add( material ); - - } - - } - - } ); - - renderStateStack.pop(); - currentRenderState = null; - - return materials; - - }; - - // compileAsync - - this.compileAsync = function ( scene, camera, targetScene = null ) { - - const materials = this.compile( scene, camera, targetScene ); - - // Wait for all the materials in the new object to indicate that they're - // ready to be used before resolving the promise. - - return new Promise( ( resolve ) => { - - function checkMaterialsReady() { - - materials.forEach( function ( material ) { - - const materialProperties = properties.get( material ); - const program = materialProperties.currentProgram; - - if ( program.isReady() ) { - - // remove any programs that report they're ready to use from the list - materials.delete( material ); - - } - - } ); - - // once the list of compiling materials is empty, call the callback - - if ( materials.size === 0 ) { - - resolve( scene ); - return; - - } - - // if some materials are still not ready, wait a bit and check again - - setTimeout( checkMaterialsReady, 10 ); - - } - - if ( extensions.get( 'KHR_parallel_shader_compile' ) !== null ) { - - // If we can check the compilation status of the materials without - // blocking then do so right away. - - checkMaterialsReady(); - - } else { - - // Otherwise start by waiting a bit to give the materials we just - // initialized a chance to finish. - - setTimeout( checkMaterialsReady, 10 ); - - } - - } ); - - }; - - // Animation Loop - - let onAnimationFrameCallback = null; - - function onAnimationFrame( time ) { - - if ( onAnimationFrameCallback ) onAnimationFrameCallback( time ); - - } - - function onXRSessionStart() { - - animation.stop(); - - } - - function onXRSessionEnd() { - - animation.start(); - - } - - const animation = new WebGLAnimation(); - animation.setAnimationLoop( onAnimationFrame ); - - if ( typeof self !== 'undefined' ) animation.setContext( self ); - - this.setAnimationLoop = function ( callback ) { - - onAnimationFrameCallback = callback; - xr.setAnimationLoop( callback ); - - ( callback === null ) ? animation.stop() : animation.start(); - - }; - - xr.addEventListener( 'sessionstart', onXRSessionStart ); - xr.addEventListener( 'sessionend', onXRSessionEnd ); - - // Rendering - - this.render = function ( scene, camera ) { - - if ( camera !== undefined && camera.isCamera !== true ) { - - console.error( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' ); - return; - - } - - if ( _isContextLost === true ) return; - - // update scene graph - - if ( scene.matrixWorldAutoUpdate === true ) scene.updateMatrixWorld(); - - // update camera matrices and frustum - - if ( camera.parent === null && camera.matrixWorldAutoUpdate === true ) camera.updateMatrixWorld(); - - if ( xr.enabled === true && xr.isPresenting === true ) { - - if ( xr.cameraAutoUpdate === true ) xr.updateCamera( camera ); - - camera = xr.getCamera(); // use XR camera for rendering - - } - - // - if ( scene.isScene === true ) scene.onBeforeRender( _this, scene, camera, _currentRenderTarget ); - - currentRenderState = renderStates.get( scene, renderStateStack.length ); - currentRenderState.init(); - - renderStateStack.push( currentRenderState ); - - _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); - _frustum.setFromProjectionMatrix( _projScreenMatrix ); - - _localClippingEnabled = this.localClippingEnabled; - _clippingEnabled = clipping.init( this.clippingPlanes, _localClippingEnabled ); - - currentRenderList = renderLists.get( scene, renderListStack.length ); - currentRenderList.init(); - - renderListStack.push( currentRenderList ); - - projectObject( scene, camera, 0, _this.sortObjects ); - - currentRenderList.finish(); - - if ( _this.sortObjects === true ) { - - currentRenderList.sort( _opaqueSort, _transparentSort ); - - } - - // - - this.info.render.frame ++; - - if ( _clippingEnabled === true ) clipping.beginShadows(); - - const shadowsArray = currentRenderState.state.shadowsArray; - - shadowMap.render( shadowsArray, scene, camera ); - - if ( _clippingEnabled === true ) clipping.endShadows(); - - // - - if ( this.info.autoReset === true ) this.info.reset(); - - - // - - if ( xr.enabled === false || xr.isPresenting === false || xr.hasDepthSensing() === false ) { - - background.render( currentRenderList, scene ); - - } - - // render scene - - currentRenderState.setupLights( _this._useLegacyLights ); - - if ( camera.isArrayCamera ) { - - const cameras = camera.cameras; - - for ( let i = 0, l = cameras.length; i < l; i ++ ) { - - const camera2 = cameras[ i ]; - - renderScene( currentRenderList, scene, camera2, camera2.viewport ); - - } - - } else { - - renderScene( currentRenderList, scene, camera ); - - } - - // - - if ( _currentRenderTarget !== null ) { - - // resolve multisample renderbuffers to a single-sample texture if necessary - - textures.updateMultisampleRenderTarget( _currentRenderTarget ); - - // Generate mipmap if we're using any kind of mipmap filtering - - textures.updateRenderTargetMipmap( _currentRenderTarget ); - - } - - // - - if ( scene.isScene === true ) scene.onAfterRender( _this, scene, camera ); - - // _gl.finish(); - - bindingStates.resetDefaultState(); - _currentMaterialId = - 1; - _currentCamera = null; - - renderStateStack.pop(); - - if ( renderStateStack.length > 0 ) { - - currentRenderState = renderStateStack[ renderStateStack.length - 1 ]; - - } else { - - currentRenderState = null; - - } - - renderListStack.pop(); - - if ( renderListStack.length > 0 ) { - - currentRenderList = renderListStack[ renderListStack.length - 1 ]; - - } else { - - currentRenderList = null; - - } - - }; - - function projectObject( object, camera, groupOrder, sortObjects ) { - - if ( object.visible === false ) return; - - const visible = object.layers.test( camera.layers ); - - if ( visible ) { - - if ( object.isGroup ) { - - groupOrder = object.renderOrder; - - } else if ( object.isLOD ) { - - if ( object.autoUpdate === true ) object.update( camera ); - - } else if ( object.isLight ) { - - currentRenderState.pushLight( object ); - - if ( object.castShadow ) { - - currentRenderState.pushShadow( object ); - - } - - } else if ( object.isSprite ) { - - if ( ! object.frustumCulled || _frustum.intersectsSprite( object ) ) { - - if ( sortObjects ) { - - _vector3.setFromMatrixPosition( object.matrixWorld ) - .applyMatrix4( _projScreenMatrix ); - - } - - const geometry = objects.update( object ); - const material = object.material; - - if ( material.visible ) { - - currentRenderList.push( object, geometry, material, groupOrder, _vector3.z, null ); - - } - - } - - } else if ( object.isMesh || object.isLine || object.isPoints ) { - - if ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) { - - const geometry = objects.update( object ); - const material = object.material; - - if ( sortObjects ) { - - if ( object.boundingSphere !== undefined ) { - - if ( object.boundingSphere === null ) object.computeBoundingSphere(); - _vector3.copy( object.boundingSphere.center ); - - } else { - - if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); - _vector3.copy( geometry.boundingSphere.center ); - - } - - _vector3 - .applyMatrix4( object.matrixWorld ) - .applyMatrix4( _projScreenMatrix ); - - } - - if ( Array.isArray( material ) ) { - - const groups = geometry.groups; - - for ( let i = 0, l = groups.length; i < l; i ++ ) { - - const group = groups[ i ]; - const groupMaterial = material[ group.materialIndex ]; - - if ( groupMaterial && groupMaterial.visible ) { - - currentRenderList.push( object, geometry, groupMaterial, groupOrder, _vector3.z, group ); - - } - - } - - } else if ( material.visible ) { - - currentRenderList.push( object, geometry, material, groupOrder, _vector3.z, null ); - - } - - } - - } - - } - - const children = object.children; - - for ( let i = 0, l = children.length; i < l; i ++ ) { - - projectObject( children[ i ], camera, groupOrder, sortObjects ); - - } - - } - - function renderScene( currentRenderList, scene, camera, viewport ) { - - const opaqueObjects = currentRenderList.opaque; - const transmissiveObjects = currentRenderList.transmissive; - const transparentObjects = currentRenderList.transparent; - - currentRenderState.setupLightsView( camera ); - - if ( _clippingEnabled === true ) clipping.setGlobalState( _this.clippingPlanes, camera ); - - if ( transmissiveObjects.length > 0 ) renderTransmissionPass( opaqueObjects, transmissiveObjects, scene, camera ); - - if ( viewport ) state.viewport( _currentViewport.copy( viewport ) ); - - if ( opaqueObjects.length > 0 ) renderObjects( opaqueObjects, scene, camera ); - if ( transmissiveObjects.length > 0 ) renderObjects( transmissiveObjects, scene, camera ); - if ( transparentObjects.length > 0 ) renderObjects( transparentObjects, scene, camera ); - - // Ensure depth buffer writing is enabled so it can be cleared on next render - - state.buffers.depth.setTest( true ); - state.buffers.depth.setMask( true ); - state.buffers.color.setMask( true ); - - state.setPolygonOffset( false ); - - } - - function renderTransmissionPass( opaqueObjects, transmissiveObjects, scene, camera ) { - - const overrideMaterial = scene.isScene === true ? scene.overrideMaterial : null; - - if ( overrideMaterial !== null ) { - - return; - - } - - const isWebGL2 = capabilities.isWebGL2; - - if ( _transmissionRenderTarget === null ) { - - _transmissionRenderTarget = new WebGLRenderTarget( 1, 1, { - generateMipmaps: true, - type: extensions.has( 'EXT_color_buffer_half_float' ) ? HalfFloatType : UnsignedByteType, - minFilter: LinearMipmapLinearFilter, - samples: ( isWebGL2 ) ? 4 : 0 - } ); - - // debug - - /* - const geometry = new PlaneGeometry(); - const material = new MeshBasicMaterial( { map: _transmissionRenderTarget.texture } ); - - const mesh = new Mesh( geometry, material ); - scene.add( mesh ); - */ - - } - - _this.getDrawingBufferSize( _vector2 ); - - if ( isWebGL2 ) { - - _transmissionRenderTarget.setSize( _vector2.x, _vector2.y ); - - } else { - - _transmissionRenderTarget.setSize( floorPowerOfTwo( _vector2.x ), floorPowerOfTwo( _vector2.y ) ); - - } - - // - - const currentRenderTarget = _this.getRenderTarget(); - _this.setRenderTarget( _transmissionRenderTarget ); - - _this.getClearColor( _currentClearColor ); - _currentClearAlpha = _this.getClearAlpha(); - if ( _currentClearAlpha < 1 ) _this.setClearColor( 0xffffff, 0.5 ); - - _this.clear(); - - // Turn off the features which can affect the frag color for opaque objects pass. - // Otherwise they are applied twice in opaque objects pass and transmission objects pass. - const currentToneMapping = _this.toneMapping; - _this.toneMapping = NoToneMapping; - - renderObjects( opaqueObjects, scene, camera ); - - textures.updateMultisampleRenderTarget( _transmissionRenderTarget ); - textures.updateRenderTargetMipmap( _transmissionRenderTarget ); - - let renderTargetNeedsUpdate = false; - - for ( let i = 0, l = transmissiveObjects.length; i < l; i ++ ) { - - const renderItem = transmissiveObjects[ i ]; - - const object = renderItem.object; - const geometry = renderItem.geometry; - const material = renderItem.material; - const group = renderItem.group; - - if ( material.side === DoubleSide && object.layers.test( camera.layers ) ) { - - const currentSide = material.side; - - material.side = BackSide; - material.needsUpdate = true; - - renderObject( object, scene, camera, geometry, material, group ); - - material.side = currentSide; - material.needsUpdate = true; - - renderTargetNeedsUpdate = true; - - } - - } - - if ( renderTargetNeedsUpdate === true ) { - - textures.updateMultisampleRenderTarget( _transmissionRenderTarget ); - textures.updateRenderTargetMipmap( _transmissionRenderTarget ); - - } - - _this.setRenderTarget( currentRenderTarget ); - - _this.setClearColor( _currentClearColor, _currentClearAlpha ); - - _this.toneMapping = currentToneMapping; - - } - - function renderObjects( renderList, scene, camera ) { - - const overrideMaterial = scene.isScene === true ? scene.overrideMaterial : null; - - for ( let i = 0, l = renderList.length; i < l; i ++ ) { - - const renderItem = renderList[ i ]; - - const object = renderItem.object; - const geometry = renderItem.geometry; - const material = overrideMaterial === null ? renderItem.material : overrideMaterial; - const group = renderItem.group; - - if ( object.layers.test( camera.layers ) ) { - - renderObject( object, scene, camera, geometry, material, group ); - - } - - } - - } - - function renderObject( object, scene, camera, geometry, material, group ) { - - object.onBeforeRender( _this, scene, camera, geometry, material, group ); - - object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); - object.normalMatrix.getNormalMatrix( object.modelViewMatrix ); - - material.onBeforeRender( _this, scene, camera, geometry, object, group ); - - if ( material.transparent === true && material.side === DoubleSide && material.forceSinglePass === false ) { - - material.side = BackSide; - material.needsUpdate = true; - _this.renderBufferDirect( camera, scene, geometry, material, object, group ); - - material.side = FrontSide; - material.needsUpdate = true; - _this.renderBufferDirect( camera, scene, geometry, material, object, group ); - - material.side = DoubleSide; - - } else { - - _this.renderBufferDirect( camera, scene, geometry, material, object, group ); - - } - - object.onAfterRender( _this, scene, camera, geometry, material, group ); - - } - - function getProgram( material, scene, object ) { - - if ( scene.isScene !== true ) scene = _emptyScene; // scene could be a Mesh, Line, Points, ... - - const materialProperties = properties.get( material ); - - const lights = currentRenderState.state.lights; - const shadowsArray = currentRenderState.state.shadowsArray; - - const lightsStateVersion = lights.state.version; - - const parameters = programCache.getParameters( material, lights.state, shadowsArray, scene, object ); - const programCacheKey = programCache.getProgramCacheKey( parameters ); - - let programs = materialProperties.programs; - - // always update environment and fog - changing these trigger an getProgram call, but it's possible that the program doesn't change - - materialProperties.environment = material.isMeshStandardMaterial ? scene.environment : null; - materialProperties.fog = scene.fog; - materialProperties.envMap = ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get( material.envMap || materialProperties.environment ); - - if ( programs === undefined ) { - - // new material - - material.addEventListener( 'dispose', onMaterialDispose ); - - programs = new Map(); - materialProperties.programs = programs; - - } - - let program = programs.get( programCacheKey ); - - if ( program !== undefined ) { - - // early out if program and light state is identical - - if ( materialProperties.currentProgram === program && materialProperties.lightsStateVersion === lightsStateVersion ) { - - updateCommonMaterialProperties( material, parameters ); - - return program; - - } - - } else { - - parameters.uniforms = programCache.getUniforms( material ); - - material.onBuild( object, parameters, _this ); - - material.onBeforeCompile( parameters, _this ); - - program = programCache.acquireProgram( parameters, programCacheKey ); - programs.set( programCacheKey, program ); - - materialProperties.uniforms = parameters.uniforms; - - } - - const uniforms = materialProperties.uniforms; - - if ( ( ! material.isShaderMaterial && ! material.isRawShaderMaterial ) || material.clipping === true ) { - - uniforms.clippingPlanes = clipping.uniform; - - } - - updateCommonMaterialProperties( material, parameters ); - - // store the light setup it was created for - - materialProperties.needsLights = materialNeedsLights( material ); - materialProperties.lightsStateVersion = lightsStateVersion; - - if ( materialProperties.needsLights ) { - - // wire up the material to this renderer's lighting state - - uniforms.ambientLightColor.value = lights.state.ambient; - uniforms.lightProbe.value = lights.state.probe; - uniforms.directionalLights.value = lights.state.directional; - uniforms.directionalLightShadows.value = lights.state.directionalShadow; - uniforms.spotLights.value = lights.state.spot; - uniforms.spotLightShadows.value = lights.state.spotShadow; - uniforms.rectAreaLights.value = lights.state.rectArea; - uniforms.ltc_1.value = lights.state.rectAreaLTC1; - uniforms.ltc_2.value = lights.state.rectAreaLTC2; - uniforms.pointLights.value = lights.state.point; - uniforms.pointLightShadows.value = lights.state.pointShadow; - uniforms.hemisphereLights.value = lights.state.hemi; - - uniforms.directionalShadowMap.value = lights.state.directionalShadowMap; - uniforms.directionalShadowMatrix.value = lights.state.directionalShadowMatrix; - uniforms.spotShadowMap.value = lights.state.spotShadowMap; - uniforms.spotLightMatrix.value = lights.state.spotLightMatrix; - uniforms.spotLightMap.value = lights.state.spotLightMap; - uniforms.pointShadowMap.value = lights.state.pointShadowMap; - uniforms.pointShadowMatrix.value = lights.state.pointShadowMatrix; - // TODO (abelnation): add area lights shadow info to uniforms - - } - - materialProperties.currentProgram = program; - materialProperties.uniformsList = null; - - return program; - - } - - function getUniformList( materialProperties ) { - - if ( materialProperties.uniformsList === null ) { - - const progUniforms = materialProperties.currentProgram.getUniforms(); - materialProperties.uniformsList = WebGLUniforms.seqWithValue( progUniforms.seq, materialProperties.uniforms ); - - } - - return materialProperties.uniformsList; - - } - - function updateCommonMaterialProperties( material, parameters ) { - - const materialProperties = properties.get( material ); - - materialProperties.outputColorSpace = parameters.outputColorSpace; - materialProperties.batching = parameters.batching; - materialProperties.instancing = parameters.instancing; - materialProperties.instancingColor = parameters.instancingColor; - materialProperties.skinning = parameters.skinning; - materialProperties.morphTargets = parameters.morphTargets; - materialProperties.morphNormals = parameters.morphNormals; - materialProperties.morphColors = parameters.morphColors; - materialProperties.morphTargetsCount = parameters.morphTargetsCount; - materialProperties.numClippingPlanes = parameters.numClippingPlanes; - materialProperties.numIntersection = parameters.numClipIntersection; - materialProperties.vertexAlphas = parameters.vertexAlphas; - materialProperties.vertexTangents = parameters.vertexTangents; - materialProperties.toneMapping = parameters.toneMapping; - - } - - function setProgram( camera, scene, geometry, material, object ) { - - if ( scene.isScene !== true ) scene = _emptyScene; // scene could be a Mesh, Line, Points, ... - - textures.resetTextureUnits(); - - const fog = scene.fog; - const environment = material.isMeshStandardMaterial ? scene.environment : null; - const colorSpace = ( _currentRenderTarget === null ) ? _this.outputColorSpace : ( _currentRenderTarget.isXRRenderTarget === true ? _currentRenderTarget.texture.colorSpace : LinearSRGBColorSpace ); - const envMap = ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get( material.envMap || environment ); - const vertexAlphas = material.vertexColors === true && !! geometry.attributes.color && geometry.attributes.color.itemSize === 4; - const vertexTangents = !! geometry.attributes.tangent && ( !! material.normalMap || material.anisotropy > 0 ); - const morphTargets = !! geometry.morphAttributes.position; - const morphNormals = !! geometry.morphAttributes.normal; - const morphColors = !! geometry.morphAttributes.color; - - let toneMapping = NoToneMapping; - - if ( material.toneMapped ) { - - if ( _currentRenderTarget === null || _currentRenderTarget.isXRRenderTarget === true ) { - - toneMapping = _this.toneMapping; - - } - - } - - const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color; - const morphTargetsCount = ( morphAttribute !== undefined ) ? morphAttribute.length : 0; - - const materialProperties = properties.get( material ); - const lights = currentRenderState.state.lights; - - if ( _clippingEnabled === true ) { - - if ( _localClippingEnabled === true || camera !== _currentCamera ) { - - const useCache = - camera === _currentCamera && - material.id === _currentMaterialId; - - // we might want to call this function with some ClippingGroup - // object instead of the material, once it becomes feasible - // (#8465, #8379) - clipping.setState( material, camera, useCache ); - - } - - } - - // - - let needsProgramChange = false; - - if ( material.version === materialProperties.__version ) { - - if ( materialProperties.needsLights && ( materialProperties.lightsStateVersion !== lights.state.version ) ) { - - needsProgramChange = true; - - } else if ( materialProperties.outputColorSpace !== colorSpace ) { - - needsProgramChange = true; - - } else if ( object.isBatchedMesh && materialProperties.batching === false ) { - - needsProgramChange = true; - - } else if ( ! object.isBatchedMesh && materialProperties.batching === true ) { - - needsProgramChange = true; - - } else if ( object.isInstancedMesh && materialProperties.instancing === false ) { - - needsProgramChange = true; - - } else if ( ! object.isInstancedMesh && materialProperties.instancing === true ) { - - needsProgramChange = true; - - } else if ( object.isSkinnedMesh && materialProperties.skinning === false ) { - - needsProgramChange = true; - - } else if ( ! object.isSkinnedMesh && materialProperties.skinning === true ) { - - needsProgramChange = true; - - } else if ( object.isInstancedMesh && materialProperties.instancingColor === true && object.instanceColor === null ) { - - needsProgramChange = true; - - } else if ( object.isInstancedMesh && materialProperties.instancingColor === false && object.instanceColor !== null ) { - - needsProgramChange = true; - - } else if ( materialProperties.envMap !== envMap ) { - - needsProgramChange = true; - - } else if ( material.fog === true && materialProperties.fog !== fog ) { - - needsProgramChange = true; - - } else if ( materialProperties.numClippingPlanes !== undefined && - ( materialProperties.numClippingPlanes !== clipping.numPlanes || - materialProperties.numIntersection !== clipping.numIntersection ) ) { - - needsProgramChange = true; - - } else if ( materialProperties.vertexAlphas !== vertexAlphas ) { - - needsProgramChange = true; - - } else if ( materialProperties.vertexTangents !== vertexTangents ) { - - needsProgramChange = true; - - } else if ( materialProperties.morphTargets !== morphTargets ) { - - needsProgramChange = true; - - } else if ( materialProperties.morphNormals !== morphNormals ) { - - needsProgramChange = true; - - } else if ( materialProperties.morphColors !== morphColors ) { - - needsProgramChange = true; - - } else if ( materialProperties.toneMapping !== toneMapping ) { - - needsProgramChange = true; - - } else if ( capabilities.isWebGL2 === true && materialProperties.morphTargetsCount !== morphTargetsCount ) { - - needsProgramChange = true; - - } - - } else { - - needsProgramChange = true; - materialProperties.__version = material.version; - - } - - // - - let program = materialProperties.currentProgram; - - if ( needsProgramChange === true ) { - - program = getProgram( material, scene, object ); - - } - - let refreshProgram = false; - let refreshMaterial = false; - let refreshLights = false; - - const p_uniforms = program.getUniforms(), - m_uniforms = materialProperties.uniforms; - - if ( state.useProgram( program.program ) ) { - - refreshProgram = true; - refreshMaterial = true; - refreshLights = true; - - } - - if ( material.id !== _currentMaterialId ) { - - _currentMaterialId = material.id; - - refreshMaterial = true; - - } - - if ( refreshProgram || _currentCamera !== camera ) { - - // common camera uniforms - - p_uniforms.setValue( _gl, 'projectionMatrix', camera.projectionMatrix ); - p_uniforms.setValue( _gl, 'viewMatrix', camera.matrixWorldInverse ); - - const uCamPos = p_uniforms.map.cameraPosition; - - if ( uCamPos !== undefined ) { - - uCamPos.setValue( _gl, _vector3.setFromMatrixPosition( camera.matrixWorld ) ); - - } - - if ( capabilities.logarithmicDepthBuffer ) { - - p_uniforms.setValue( _gl, 'logDepthBufFC', - 2.0 / ( Math.log( camera.far + 1.0 ) / Math.LN2 ) ); - - } - - // consider moving isOrthographic to UniformLib and WebGLMaterials, see https://github.com/mrdoob/three.js/pull/26467#issuecomment-1645185067 - - if ( material.isMeshPhongMaterial || - material.isMeshToonMaterial || - material.isMeshLambertMaterial || - material.isMeshBasicMaterial || - material.isMeshStandardMaterial || - material.isShaderMaterial ) { - - p_uniforms.setValue( _gl, 'isOrthographic', camera.isOrthographicCamera === true ); - - } - - if ( _currentCamera !== camera ) { - - _currentCamera = camera; - - // lighting uniforms depend on the camera so enforce an update - // now, in case this material supports lights - or later, when - // the next material that does gets activated: - - refreshMaterial = true; // set to true on material change - refreshLights = true; // remains set until update done - - } - - } - - // skinning and morph target uniforms must be set even if material didn't change - // auto-setting of texture unit for bone and morph texture must go before other textures - // otherwise textures used for skinning and morphing can take over texture units reserved for other material textures - - if ( object.isSkinnedMesh ) { - - p_uniforms.setOptional( _gl, object, 'bindMatrix' ); - p_uniforms.setOptional( _gl, object, 'bindMatrixInverse' ); - - const skeleton = object.skeleton; - - if ( skeleton ) { - - if ( capabilities.floatVertexTextures ) { - - if ( skeleton.boneTexture === null ) skeleton.computeBoneTexture(); - - p_uniforms.setValue( _gl, 'boneTexture', skeleton.boneTexture, textures ); - - } else { - - console.warn( 'THREE.WebGLRenderer: SkinnedMesh can only be used with WebGL 2. With WebGL 1 OES_texture_float and vertex textures support is required.' ); - - } - - } - - } - - if ( object.isBatchedMesh ) { - - p_uniforms.setOptional( _gl, object, 'batchingTexture' ); - p_uniforms.setValue( _gl, 'batchingTexture', object._matricesTexture, textures ); - - } - - const morphAttributes = geometry.morphAttributes; - - if ( morphAttributes.position !== undefined || morphAttributes.normal !== undefined || ( morphAttributes.color !== undefined && capabilities.isWebGL2 === true ) ) { - - morphtargets.update( object, geometry, program ); - - } - - if ( refreshMaterial || materialProperties.receiveShadow !== object.receiveShadow ) { - - materialProperties.receiveShadow = object.receiveShadow; - p_uniforms.setValue( _gl, 'receiveShadow', object.receiveShadow ); - - } - - // https://github.com/mrdoob/three.js/pull/24467#issuecomment-1209031512 - - if ( material.isMeshGouraudMaterial && material.envMap !== null ) { - - m_uniforms.envMap.value = envMap; - - m_uniforms.flipEnvMap.value = ( envMap.isCubeTexture && envMap.isRenderTargetTexture === false ) ? - 1 : 1; - - } - - if ( refreshMaterial ) { - - p_uniforms.setValue( _gl, 'toneMappingExposure', _this.toneMappingExposure ); - - if ( materialProperties.needsLights ) { - - // the current material requires lighting info - - // note: all lighting uniforms are always set correctly - // they simply reference the renderer's state for their - // values - // - // use the current material's .needsUpdate flags to set - // the GL state when required - - markUniformsLightsNeedsUpdate( m_uniforms, refreshLights ); - - } - - // refresh uniforms common to several materials - - if ( fog && material.fog === true ) { - - materials.refreshFogUniforms( m_uniforms, fog ); - - } - - materials.refreshMaterialUniforms( m_uniforms, material, _pixelRatio, _height, _transmissionRenderTarget ); - - WebGLUniforms.upload( _gl, getUniformList( materialProperties ), m_uniforms, textures ); - - } - - if ( material.isShaderMaterial && material.uniformsNeedUpdate === true ) { - - WebGLUniforms.upload( _gl, getUniformList( materialProperties ), m_uniforms, textures ); - material.uniformsNeedUpdate = false; - - } - - if ( material.isSpriteMaterial ) { - - p_uniforms.setValue( _gl, 'center', object.center ); - - } - - // common matrices - - p_uniforms.setValue( _gl, 'modelViewMatrix', object.modelViewMatrix ); - p_uniforms.setValue( _gl, 'normalMatrix', object.normalMatrix ); - p_uniforms.setValue( _gl, 'modelMatrix', object.matrixWorld ); - - // UBOs - - if ( material.isShaderMaterial || material.isRawShaderMaterial ) { - - const groups = material.uniformsGroups; - - for ( let i = 0, l = groups.length; i < l; i ++ ) { - - if ( capabilities.isWebGL2 ) { - - const group = groups[ i ]; - - uniformsGroups.update( group, program ); - uniformsGroups.bind( group, program ); - - } else { - - console.warn( 'THREE.WebGLRenderer: Uniform Buffer Objects can only be used with WebGL 2.' ); - - } - - } - - } - - return program; - - } - - // If uniforms are marked as clean, they don't need to be loaded to the GPU. - - function markUniformsLightsNeedsUpdate( uniforms, value ) { - - uniforms.ambientLightColor.needsUpdate = value; - uniforms.lightProbe.needsUpdate = value; - - uniforms.directionalLights.needsUpdate = value; - uniforms.directionalLightShadows.needsUpdate = value; - uniforms.pointLights.needsUpdate = value; - uniforms.pointLightShadows.needsUpdate = value; - uniforms.spotLights.needsUpdate = value; - uniforms.spotLightShadows.needsUpdate = value; - uniforms.rectAreaLights.needsUpdate = value; - uniforms.hemisphereLights.needsUpdate = value; - - } - - function materialNeedsLights( material ) { - - return material.isMeshLambertMaterial || material.isMeshToonMaterial || material.isMeshPhongMaterial || - material.isMeshStandardMaterial || material.isShadowMaterial || - ( material.isShaderMaterial && material.lights === true ); - - } - - this.getActiveCubeFace = function () { - - return _currentActiveCubeFace; - - }; - - this.getActiveMipmapLevel = function () { - - return _currentActiveMipmapLevel; - - }; - - this.getRenderTarget = function () { - - return _currentRenderTarget; - - }; - - this.setRenderTargetTextures = function ( renderTarget, colorTexture, depthTexture ) { - - properties.get( renderTarget.texture ).__webglTexture = colorTexture; - properties.get( renderTarget.depthTexture ).__webglTexture = depthTexture; - - const renderTargetProperties = properties.get( renderTarget ); - renderTargetProperties.__hasExternalTextures = true; - - if ( renderTargetProperties.__hasExternalTextures ) { - - renderTargetProperties.__autoAllocateDepthBuffer = depthTexture === undefined; - - if ( ! renderTargetProperties.__autoAllocateDepthBuffer ) { - - // The multisample_render_to_texture extension doesn't work properly if there - // are midframe flushes and an external depth buffer. Disable use of the extension. - if ( extensions.has( 'WEBGL_multisampled_render_to_texture' ) === true ) { - - console.warn( 'THREE.WebGLRenderer: Render-to-texture extension was disabled because an external texture was provided' ); - renderTargetProperties.__useRenderToTexture = false; - - } - - } - - } - - }; - - this.setRenderTargetFramebuffer = function ( renderTarget, defaultFramebuffer ) { - - const renderTargetProperties = properties.get( renderTarget ); - renderTargetProperties.__webglFramebuffer = defaultFramebuffer; - renderTargetProperties.__useDefaultFramebuffer = defaultFramebuffer === undefined; - - }; - - this.setRenderTarget = function ( renderTarget, activeCubeFace = 0, activeMipmapLevel = 0 ) { - - _currentRenderTarget = renderTarget; - _currentActiveCubeFace = activeCubeFace; - _currentActiveMipmapLevel = activeMipmapLevel; - - let useDefaultFramebuffer = true; - let framebuffer = null; - let isCube = false; - let isRenderTarget3D = false; - - if ( renderTarget ) { - - const renderTargetProperties = properties.get( renderTarget ); - - if ( renderTargetProperties.__useDefaultFramebuffer !== undefined ) { - - // We need to make sure to rebind the framebuffer. - state.bindFramebuffer( _gl.FRAMEBUFFER, null ); - useDefaultFramebuffer = false; - - } else if ( renderTargetProperties.__webglFramebuffer === undefined ) { - - textures.setupRenderTarget( renderTarget ); - - } else if ( renderTargetProperties.__hasExternalTextures ) { - - // Color and depth texture must be rebound in order for the swapchain to update. - textures.rebindTextures( renderTarget, properties.get( renderTarget.texture ).__webglTexture, properties.get( renderTarget.depthTexture ).__webglTexture ); - - } - - const texture = renderTarget.texture; - - if ( texture.isData3DTexture || texture.isDataArrayTexture || texture.isCompressedArrayTexture ) { - - isRenderTarget3D = true; - - } - - const __webglFramebuffer = properties.get( renderTarget ).__webglFramebuffer; - - if ( renderTarget.isWebGLCubeRenderTarget ) { - - if ( Array.isArray( __webglFramebuffer[ activeCubeFace ] ) ) { - - framebuffer = __webglFramebuffer[ activeCubeFace ][ activeMipmapLevel ]; - - } else { - - framebuffer = __webglFramebuffer[ activeCubeFace ]; - - } - - isCube = true; - - } else if ( ( capabilities.isWebGL2 && renderTarget.samples > 0 ) && textures.useMultisampledRTT( renderTarget ) === false ) { - - framebuffer = properties.get( renderTarget ).__webglMultisampledFramebuffer; - - } else { - - if ( Array.isArray( __webglFramebuffer ) ) { - - framebuffer = __webglFramebuffer[ activeMipmapLevel ]; - - } else { - - framebuffer = __webglFramebuffer; - - } - - } - - _currentViewport.copy( renderTarget.viewport ); - _currentScissor.copy( renderTarget.scissor ); - _currentScissorTest = renderTarget.scissorTest; - - } else { - - _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).floor(); - _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).floor(); - _currentScissorTest = _scissorTest; - - } - - const framebufferBound = state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); - - if ( framebufferBound && capabilities.drawBuffers && useDefaultFramebuffer ) { - - state.drawBuffers( renderTarget, framebuffer ); - - } - - state.viewport( _currentViewport ); - state.scissor( _currentScissor ); - state.setScissorTest( _currentScissorTest ); - - if ( isCube ) { - - const textureProperties = properties.get( renderTarget.texture ); - _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + activeCubeFace, textureProperties.__webglTexture, activeMipmapLevel ); - - } else if ( isRenderTarget3D ) { - - const textureProperties = properties.get( renderTarget.texture ); - const layer = activeCubeFace || 0; - _gl.framebufferTextureLayer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, textureProperties.__webglTexture, activeMipmapLevel || 0, layer ); - - } - - _currentMaterialId = - 1; // reset current material to ensure correct uniform bindings - - }; - - this.readRenderTargetPixels = function ( renderTarget, x, y, width, height, buffer, activeCubeFaceIndex ) { - - if ( ! ( renderTarget && renderTarget.isWebGLRenderTarget ) ) { - - console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' ); - return; - - } - - let framebuffer = properties.get( renderTarget ).__webglFramebuffer; - - if ( renderTarget.isWebGLCubeRenderTarget && activeCubeFaceIndex !== undefined ) { - - framebuffer = framebuffer[ activeCubeFaceIndex ]; - - } - - if ( framebuffer ) { - - state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); - - try { - - const texture = renderTarget.texture; - const textureFormat = texture.format; - const textureType = texture.type; - - if ( textureFormat !== RGBAFormat && utils.convert( textureFormat ) !== _gl.getParameter( _gl.IMPLEMENTATION_COLOR_READ_FORMAT ) ) { - - console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.' ); - return; - - } - - const halfFloatSupportedByExt = ( textureType === HalfFloatType ) && ( extensions.has( 'EXT_color_buffer_half_float' ) || ( capabilities.isWebGL2 && extensions.has( 'EXT_color_buffer_float' ) ) ); - - if ( textureType !== UnsignedByteType && utils.convert( textureType ) !== _gl.getParameter( _gl.IMPLEMENTATION_COLOR_READ_TYPE ) && // Edge and Chrome Mac < 52 (#9513) - ! ( textureType === FloatType && ( capabilities.isWebGL2 || extensions.has( 'OES_texture_float' ) || extensions.has( 'WEBGL_color_buffer_float' ) ) ) && // Chrome Mac >= 52 and Firefox - ! halfFloatSupportedByExt ) { - - console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.' ); - return; - - } - - // the following if statement ensures valid read requests (no out-of-bounds pixels, see #8604) - - if ( ( x >= 0 && x <= ( renderTarget.width - width ) ) && ( y >= 0 && y <= ( renderTarget.height - height ) ) ) { - - _gl.readPixels( x, y, width, height, utils.convert( textureFormat ), utils.convert( textureType ), buffer ); - - } - - } finally { - - // restore framebuffer of current render target if necessary - - const framebuffer = ( _currentRenderTarget !== null ) ? properties.get( _currentRenderTarget ).__webglFramebuffer : null; - state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); - - } - - } - - }; - - this.copyFramebufferToTexture = function ( position, texture, level = 0 ) { - - const levelScale = Math.pow( 2, - level ); - const width = Math.floor( texture.image.width * levelScale ); - const height = Math.floor( texture.image.height * levelScale ); - - textures.setTexture2D( texture, 0 ); - - _gl.copyTexSubImage2D( _gl.TEXTURE_2D, level, 0, 0, position.x, position.y, width, height ); - - state.unbindTexture(); - - }; - - this.copyTextureToTexture = function ( position, srcTexture, dstTexture, level = 0 ) { - - const width = srcTexture.image.width; - const height = srcTexture.image.height; - const glFormat = utils.convert( dstTexture.format ); - const glType = utils.convert( dstTexture.type ); - - textures.setTexture2D( dstTexture, 0 ); - - // As another texture upload may have changed pixelStorei - // parameters, make sure they are correct for the dstTexture - _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, dstTexture.flipY ); - _gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, dstTexture.premultiplyAlpha ); - _gl.pixelStorei( _gl.UNPACK_ALIGNMENT, dstTexture.unpackAlignment ); - - if ( srcTexture.isDataTexture ) { - - _gl.texSubImage2D( _gl.TEXTURE_2D, level, position.x, position.y, width, height, glFormat, glType, srcTexture.image.data ); - - } else { - - if ( srcTexture.isCompressedTexture ) { - - _gl.compressedTexSubImage2D( _gl.TEXTURE_2D, level, position.x, position.y, srcTexture.mipmaps[ 0 ].width, srcTexture.mipmaps[ 0 ].height, glFormat, srcTexture.mipmaps[ 0 ].data ); - - } else { - - _gl.texSubImage2D( _gl.TEXTURE_2D, level, position.x, position.y, glFormat, glType, srcTexture.image ); - - } - - } - - // Generate mipmaps only when copying level 0 - if ( level === 0 && dstTexture.generateMipmaps ) _gl.generateMipmap( _gl.TEXTURE_2D ); - - state.unbindTexture(); - - }; - - this.copyTextureToTexture3D = function ( sourceBox, position, srcTexture, dstTexture, level = 0 ) { - - if ( _this.isWebGL1Renderer ) { - - console.warn( 'THREE.WebGLRenderer.copyTextureToTexture3D: can only be used with WebGL2.' ); - return; - - } - - const width = sourceBox.max.x - sourceBox.min.x + 1; - const height = sourceBox.max.y - sourceBox.min.y + 1; - const depth = sourceBox.max.z - sourceBox.min.z + 1; - const glFormat = utils.convert( dstTexture.format ); - const glType = utils.convert( dstTexture.type ); - let glTarget; - - if ( dstTexture.isData3DTexture ) { - - textures.setTexture3D( dstTexture, 0 ); - glTarget = _gl.TEXTURE_3D; - - } else if ( dstTexture.isDataArrayTexture || dstTexture.isCompressedArrayTexture ) { - - textures.setTexture2DArray( dstTexture, 0 ); - glTarget = _gl.TEXTURE_2D_ARRAY; - - } else { - - console.warn( 'THREE.WebGLRenderer.copyTextureToTexture3D: only supports THREE.DataTexture3D and THREE.DataTexture2DArray.' ); - return; - - } - - _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, dstTexture.flipY ); - _gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, dstTexture.premultiplyAlpha ); - _gl.pixelStorei( _gl.UNPACK_ALIGNMENT, dstTexture.unpackAlignment ); - - const unpackRowLen = _gl.getParameter( _gl.UNPACK_ROW_LENGTH ); - const unpackImageHeight = _gl.getParameter( _gl.UNPACK_IMAGE_HEIGHT ); - const unpackSkipPixels = _gl.getParameter( _gl.UNPACK_SKIP_PIXELS ); - const unpackSkipRows = _gl.getParameter( _gl.UNPACK_SKIP_ROWS ); - const unpackSkipImages = _gl.getParameter( _gl.UNPACK_SKIP_IMAGES ); - - const image = srcTexture.isCompressedTexture ? srcTexture.mipmaps[ level ] : srcTexture.image; - - _gl.pixelStorei( _gl.UNPACK_ROW_LENGTH, image.width ); - _gl.pixelStorei( _gl.UNPACK_IMAGE_HEIGHT, image.height ); - _gl.pixelStorei( _gl.UNPACK_SKIP_PIXELS, sourceBox.min.x ); - _gl.pixelStorei( _gl.UNPACK_SKIP_ROWS, sourceBox.min.y ); - _gl.pixelStorei( _gl.UNPACK_SKIP_IMAGES, sourceBox.min.z ); - - if ( srcTexture.isDataTexture || srcTexture.isData3DTexture ) { - - _gl.texSubImage3D( glTarget, level, position.x, position.y, position.z, width, height, depth, glFormat, glType, image.data ); - - } else { - - if ( srcTexture.isCompressedArrayTexture ) { - - console.warn( 'THREE.WebGLRenderer.copyTextureToTexture3D: untested support for compressed srcTexture.' ); - _gl.compressedTexSubImage3D( glTarget, level, position.x, position.y, position.z, width, height, depth, glFormat, image.data ); - - } else { - - _gl.texSubImage3D( glTarget, level, position.x, position.y, position.z, width, height, depth, glFormat, glType, image ); - - } - - } - - _gl.pixelStorei( _gl.UNPACK_ROW_LENGTH, unpackRowLen ); - _gl.pixelStorei( _gl.UNPACK_IMAGE_HEIGHT, unpackImageHeight ); - _gl.pixelStorei( _gl.UNPACK_SKIP_PIXELS, unpackSkipPixels ); - _gl.pixelStorei( _gl.UNPACK_SKIP_ROWS, unpackSkipRows ); - _gl.pixelStorei( _gl.UNPACK_SKIP_IMAGES, unpackSkipImages ); - - // Generate mipmaps only when copying level 0 - if ( level === 0 && dstTexture.generateMipmaps ) _gl.generateMipmap( glTarget ); - - state.unbindTexture(); - - }; - - this.initTexture = function ( texture ) { - - if ( texture.isCubeTexture ) { - - textures.setTextureCube( texture, 0 ); - - } else if ( texture.isData3DTexture ) { - - textures.setTexture3D( texture, 0 ); - - } else if ( texture.isDataArrayTexture || texture.isCompressedArrayTexture ) { - - textures.setTexture2DArray( texture, 0 ); - - } else { - - textures.setTexture2D( texture, 0 ); - - } - - state.unbindTexture(); - - }; - - this.resetState = function () { - - _currentActiveCubeFace = 0; - _currentActiveMipmapLevel = 0; - _currentRenderTarget = null; - - state.reset(); - bindingStates.reset(); - - }; - - if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) { - - __THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'observe', { detail: this } ) ); - - } - - } - - get coordinateSystem() { - - return WebGLCoordinateSystem; - - } - - get outputColorSpace() { - - return this._outputColorSpace; - - } - - set outputColorSpace( colorSpace ) { - - this._outputColorSpace = colorSpace; - - const gl = this.getContext(); - gl.drawingBufferColorSpace = colorSpace === DisplayP3ColorSpace ? 'display-p3' : 'srgb'; - gl.unpackColorSpace = ColorManagement.workingColorSpace === LinearDisplayP3ColorSpace ? 'display-p3' : 'srgb'; - - } - - get useLegacyLights() { // @deprecated, r155 - - console.warn( 'THREE.WebGLRenderer: The property .useLegacyLights has been deprecated. Migrate your lighting according to the following guide: https://discourse.threejs.org/t/updates-to-lighting-in-three-js-r155/53733.' ); - return this._useLegacyLights; - - } - - set useLegacyLights( value ) { // @deprecated, r155 - - console.warn( 'THREE.WebGLRenderer: The property .useLegacyLights has been deprecated. Migrate your lighting according to the following guide: https://discourse.threejs.org/t/updates-to-lighting-in-three-js-r155/53733.' ); - this._useLegacyLights = value; - - } - -} - -class WebGL1Renderer extends WebGLRenderer {} - -WebGL1Renderer.prototype.isWebGL1Renderer = true; - -class FogExp2 { - - constructor( color, density = 0.00025 ) { - - this.isFogExp2 = true; - - this.name = ''; - - this.color = new Color( color ); - this.density = density; - - } - - clone() { - - return new FogExp2( this.color, this.density ); - - } - - toJSON( /* meta */ ) { - - return { - type: 'FogExp2', - name: this.name, - color: this.color.getHex(), - density: this.density - }; - - } - -} - -class Fog { - - constructor( color, near = 1, far = 1000 ) { - - this.isFog = true; - - this.name = ''; - - this.color = new Color( color ); - - this.near = near; - this.far = far; - - } - - clone() { - - return new Fog( this.color, this.near, this.far ); - - } - - toJSON( /* meta */ ) { - - return { - type: 'Fog', - name: this.name, - color: this.color.getHex(), - near: this.near, - far: this.far - }; - - } - -} - -class Scene extends Object3D { - - constructor() { - - super(); - - this.isScene = true; - - this.type = 'Scene'; - - this.background = null; - this.environment = null; - this.fog = null; - - this.backgroundBlurriness = 0; - this.backgroundIntensity = 1; - - this.overrideMaterial = null; - - if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) { - - __THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'observe', { detail: this } ) ); - - } - - } - - copy( source, recursive ) { - - super.copy( source, recursive ); - - if ( source.background !== null ) this.background = source.background.clone(); - if ( source.environment !== null ) this.environment = source.environment.clone(); - if ( source.fog !== null ) this.fog = source.fog.clone(); - - this.backgroundBlurriness = source.backgroundBlurriness; - this.backgroundIntensity = source.backgroundIntensity; - - if ( source.overrideMaterial !== null ) this.overrideMaterial = source.overrideMaterial.clone(); - - this.matrixAutoUpdate = source.matrixAutoUpdate; - - return this; - - } - - toJSON( meta ) { - - const data = super.toJSON( meta ); - - if ( this.fog !== null ) data.object.fog = this.fog.toJSON(); - if ( this.backgroundBlurriness > 0 ) data.object.backgroundBlurriness = this.backgroundBlurriness; - if ( this.backgroundIntensity !== 1 ) data.object.backgroundIntensity = this.backgroundIntensity; - - return data; - - } - -} - -class InterleavedBuffer { - - constructor( array, stride ) { - - this.isInterleavedBuffer = true; - - this.array = array; - this.stride = stride; - this.count = array !== undefined ? array.length / stride : 0; - - this.usage = StaticDrawUsage; - this._updateRange = { offset: 0, count: - 1 }; - this.updateRanges = []; - - this.version = 0; - - this.uuid = generateUUID(); - - } - - onUploadCallback() {} - - set needsUpdate( value ) { - - if ( value === true ) this.version ++; - - } - - get updateRange() { - - warnOnce( 'THREE.InterleavedBuffer: updateRange() is deprecated and will be removed in r169. Use addUpdateRange() instead.' ); // @deprecated, r159 - return this._updateRange; - - } - - setUsage( value ) { - - this.usage = value; - - return this; - - } - - addUpdateRange( start, count ) { - - this.updateRanges.push( { start, count } ); - - } - - clearUpdateRanges() { - - this.updateRanges.length = 0; - - } - - copy( source ) { - - this.array = new source.array.constructor( source.array ); - this.count = source.count; - this.stride = source.stride; - this.usage = source.usage; - - return this; - - } - - copyAt( index1, attribute, index2 ) { - - index1 *= this.stride; - index2 *= attribute.stride; - - for ( let i = 0, l = this.stride; i < l; i ++ ) { - - this.array[ index1 + i ] = attribute.array[ index2 + i ]; - - } - - return this; - - } - - set( value, offset = 0 ) { - - this.array.set( value, offset ); - - return this; - - } - - clone( data ) { - - if ( data.arrayBuffers === undefined ) { - - data.arrayBuffers = {}; - - } - - if ( this.array.buffer._uuid === undefined ) { - - this.array.buffer._uuid = generateUUID(); - - } - - if ( data.arrayBuffers[ this.array.buffer._uuid ] === undefined ) { - - data.arrayBuffers[ this.array.buffer._uuid ] = this.array.slice( 0 ).buffer; - - } - - const array = new this.array.constructor( data.arrayBuffers[ this.array.buffer._uuid ] ); - - const ib = new this.constructor( array, this.stride ); - ib.setUsage( this.usage ); - - return ib; - - } - - onUpload( callback ) { - - this.onUploadCallback = callback; - - return this; - - } - - toJSON( data ) { - - if ( data.arrayBuffers === undefined ) { - - data.arrayBuffers = {}; - - } - - // generate UUID for array buffer if necessary - - if ( this.array.buffer._uuid === undefined ) { - - this.array.buffer._uuid = generateUUID(); - - } - - if ( data.arrayBuffers[ this.array.buffer._uuid ] === undefined ) { - - data.arrayBuffers[ this.array.buffer._uuid ] = Array.from( new Uint32Array( this.array.buffer ) ); - - } - - // - - return { - uuid: this.uuid, - buffer: this.array.buffer._uuid, - type: this.array.constructor.name, - stride: this.stride - }; - - } - -} - -const _vector$6 = /*@__PURE__*/ new Vector3(); - -class InterleavedBufferAttribute { - - constructor( interleavedBuffer, itemSize, offset, normalized = false ) { - - this.isInterleavedBufferAttribute = true; - - this.name = ''; - - this.data = interleavedBuffer; - this.itemSize = itemSize; - this.offset = offset; - - this.normalized = normalized; - - } - - get count() { - - return this.data.count; - - } - - get array() { - - return this.data.array; - - } - - set needsUpdate( value ) { - - this.data.needsUpdate = value; - - } - - applyMatrix4( m ) { - - for ( let i = 0, l = this.data.count; i < l; i ++ ) { - - _vector$6.fromBufferAttribute( this, i ); - - _vector$6.applyMatrix4( m ); - - this.setXYZ( i, _vector$6.x, _vector$6.y, _vector$6.z ); - - } - - return this; - - } - - applyNormalMatrix( m ) { - - for ( let i = 0, l = this.count; i < l; i ++ ) { - - _vector$6.fromBufferAttribute( this, i ); - - _vector$6.applyNormalMatrix( m ); - - this.setXYZ( i, _vector$6.x, _vector$6.y, _vector$6.z ); - - } - - return this; - - } - - transformDirection( m ) { - - for ( let i = 0, l = this.count; i < l; i ++ ) { - - _vector$6.fromBufferAttribute( this, i ); - - _vector$6.transformDirection( m ); - - this.setXYZ( i, _vector$6.x, _vector$6.y, _vector$6.z ); - - } - - return this; - - } - - getComponent( index, component ) { - - let value = this.array[ index * this.data.stride + this.offset + component ]; - - if ( this.normalized ) value = denormalize( value, this.array ); - - return value; - - } - - setComponent( index, component, value ) { - - if ( this.normalized ) value = normalize( value, this.array ); - - this.data.array[ index * this.data.stride + this.offset + component ] = value; - - return this; - - } - - setX( index, x ) { - - if ( this.normalized ) x = normalize( x, this.array ); - - this.data.array[ index * this.data.stride + this.offset ] = x; - - return this; - - } - - setY( index, y ) { - - if ( this.normalized ) y = normalize( y, this.array ); - - this.data.array[ index * this.data.stride + this.offset + 1 ] = y; - - return this; - - } - - setZ( index, z ) { - - if ( this.normalized ) z = normalize( z, this.array ); - - this.data.array[ index * this.data.stride + this.offset + 2 ] = z; - - return this; - - } - - setW( index, w ) { - - if ( this.normalized ) w = normalize( w, this.array ); - - this.data.array[ index * this.data.stride + this.offset + 3 ] = w; - - return this; - - } - - getX( index ) { - - let x = this.data.array[ index * this.data.stride + this.offset ]; - - if ( this.normalized ) x = denormalize( x, this.array ); - - return x; - - } - - getY( index ) { - - let y = this.data.array[ index * this.data.stride + this.offset + 1 ]; - - if ( this.normalized ) y = denormalize( y, this.array ); - - return y; - - } - - getZ( index ) { - - let z = this.data.array[ index * this.data.stride + this.offset + 2 ]; - - if ( this.normalized ) z = denormalize( z, this.array ); - - return z; - - } - - getW( index ) { - - let w = this.data.array[ index * this.data.stride + this.offset + 3 ]; - - if ( this.normalized ) w = denormalize( w, this.array ); - - return w; - - } - - setXY( index, x, y ) { - - index = index * this.data.stride + this.offset; - - if ( this.normalized ) { - - x = normalize( x, this.array ); - y = normalize( y, this.array ); - - } - - this.data.array[ index + 0 ] = x; - this.data.array[ index + 1 ] = y; - - return this; - - } - - setXYZ( index, x, y, z ) { - - index = index * this.data.stride + this.offset; - - if ( this.normalized ) { - - x = normalize( x, this.array ); - y = normalize( y, this.array ); - z = normalize( z, this.array ); - - } - - this.data.array[ index + 0 ] = x; - this.data.array[ index + 1 ] = y; - this.data.array[ index + 2 ] = z; - - return this; - - } - - setXYZW( index, x, y, z, w ) { - - index = index * this.data.stride + this.offset; - - if ( this.normalized ) { - - x = normalize( x, this.array ); - y = normalize( y, this.array ); - z = normalize( z, this.array ); - w = normalize( w, this.array ); - - } - - this.data.array[ index + 0 ] = x; - this.data.array[ index + 1 ] = y; - this.data.array[ index + 2 ] = z; - this.data.array[ index + 3 ] = w; - - return this; - - } - - clone( data ) { - - if ( data === undefined ) { - - console.log( 'THREE.InterleavedBufferAttribute.clone(): Cloning an interleaved buffer attribute will de-interleave buffer data.' ); - - const array = []; - - for ( let i = 0; i < this.count; i ++ ) { - - const index = i * this.data.stride + this.offset; - - for ( let j = 0; j < this.itemSize; j ++ ) { - - array.push( this.data.array[ index + j ] ); - - } - - } - - return new BufferAttribute( new this.array.constructor( array ), this.itemSize, this.normalized ); - - } else { - - if ( data.interleavedBuffers === undefined ) { - - data.interleavedBuffers = {}; - - } - - if ( data.interleavedBuffers[ this.data.uuid ] === undefined ) { - - data.interleavedBuffers[ this.data.uuid ] = this.data.clone( data ); - - } - - return new InterleavedBufferAttribute( data.interleavedBuffers[ this.data.uuid ], this.itemSize, this.offset, this.normalized ); - - } - - } - - toJSON( data ) { - - if ( data === undefined ) { - - console.log( 'THREE.InterleavedBufferAttribute.toJSON(): Serializing an interleaved buffer attribute will de-interleave buffer data.' ); - - const array = []; - - for ( let i = 0; i < this.count; i ++ ) { - - const index = i * this.data.stride + this.offset; - - for ( let j = 0; j < this.itemSize; j ++ ) { - - array.push( this.data.array[ index + j ] ); - - } - - } - - // de-interleave data and save it as an ordinary buffer attribute for now - - return { - itemSize: this.itemSize, - type: this.array.constructor.name, - array: array, - normalized: this.normalized - }; - - } else { - - // save as true interleaved attribute - - if ( data.interleavedBuffers === undefined ) { - - data.interleavedBuffers = {}; - - } - - if ( data.interleavedBuffers[ this.data.uuid ] === undefined ) { - - data.interleavedBuffers[ this.data.uuid ] = this.data.toJSON( data ); - - } - - return { - isInterleavedBufferAttribute: true, - itemSize: this.itemSize, - data: this.data.uuid, - offset: this.offset, - normalized: this.normalized - }; - - } - - } - -} - -class SpriteMaterial extends Material { - - constructor( parameters ) { - - super(); - - this.isSpriteMaterial = true; - - this.type = 'SpriteMaterial'; - - this.color = new Color( 0xffffff ); - - this.map = null; - - this.alphaMap = null; - - this.rotation = 0; - - this.sizeAttenuation = true; - - this.transparent = true; - - this.fog = true; - - this.setValues( parameters ); - - } - - copy( source ) { - - super.copy( source ); - - this.color.copy( source.color ); - - this.map = source.map; - - this.alphaMap = source.alphaMap; - - this.rotation = source.rotation; - - this.sizeAttenuation = source.sizeAttenuation; - - this.fog = source.fog; - - return this; - - } - -} - -let _geometry; - -const _intersectPoint = /*@__PURE__*/ new Vector3(); -const _worldScale = /*@__PURE__*/ new Vector3(); -const _mvPosition = /*@__PURE__*/ new Vector3(); - -const _alignedPosition = /*@__PURE__*/ new Vector2(); -const _rotatedPosition = /*@__PURE__*/ new Vector2(); -const _viewWorldMatrix = /*@__PURE__*/ new Matrix4(); - -const _vA = /*@__PURE__*/ new Vector3(); -const _vB = /*@__PURE__*/ new Vector3(); -const _vC = /*@__PURE__*/ new Vector3(); - -const _uvA = /*@__PURE__*/ new Vector2(); -const _uvB = /*@__PURE__*/ new Vector2(); -const _uvC = /*@__PURE__*/ new Vector2(); - -class Sprite extends Object3D { - - constructor( material = new SpriteMaterial() ) { - - super(); - - this.isSprite = true; - - this.type = 'Sprite'; - - if ( _geometry === undefined ) { - - _geometry = new BufferGeometry(); - - const float32Array = new Float32Array( [ - - 0.5, - 0.5, 0, 0, 0, - 0.5, - 0.5, 0, 1, 0, - 0.5, 0.5, 0, 1, 1, - - 0.5, 0.5, 0, 0, 1 - ] ); - - const interleavedBuffer = new InterleavedBuffer( float32Array, 5 ); - - _geometry.setIndex( [ 0, 1, 2, 0, 2, 3 ] ); - _geometry.setAttribute( 'position', new InterleavedBufferAttribute( interleavedBuffer, 3, 0, false ) ); - _geometry.setAttribute( 'uv', new InterleavedBufferAttribute( interleavedBuffer, 2, 3, false ) ); - - } - - this.geometry = _geometry; - this.material = material; - - this.center = new Vector2( 0.5, 0.5 ); - - } - - raycast( raycaster, intersects ) { - - if ( raycaster.camera === null ) { - - console.error( 'THREE.Sprite: "Raycaster.camera" needs to be set in order to raycast against sprites.' ); - - } - - _worldScale.setFromMatrixScale( this.matrixWorld ); - - _viewWorldMatrix.copy( raycaster.camera.matrixWorld ); - this.modelViewMatrix.multiplyMatrices( raycaster.camera.matrixWorldInverse, this.matrixWorld ); - - _mvPosition.setFromMatrixPosition( this.modelViewMatrix ); - - if ( raycaster.camera.isPerspectiveCamera && this.material.sizeAttenuation === false ) { - - _worldScale.multiplyScalar( - _mvPosition.z ); - - } - - const rotation = this.material.rotation; - let sin, cos; - - if ( rotation !== 0 ) { - - cos = Math.cos( rotation ); - sin = Math.sin( rotation ); - - } - - const center = this.center; - - transformVertex( _vA.set( - 0.5, - 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos ); - transformVertex( _vB.set( 0.5, - 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos ); - transformVertex( _vC.set( 0.5, 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos ); - - _uvA.set( 0, 0 ); - _uvB.set( 1, 0 ); - _uvC.set( 1, 1 ); - - // check first triangle - let intersect = raycaster.ray.intersectTriangle( _vA, _vB, _vC, false, _intersectPoint ); - - if ( intersect === null ) { - - // check second triangle - transformVertex( _vB.set( - 0.5, 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos ); - _uvB.set( 0, 1 ); - - intersect = raycaster.ray.intersectTriangle( _vA, _vC, _vB, false, _intersectPoint ); - if ( intersect === null ) { - - return; - - } - - } - - const distance = raycaster.ray.origin.distanceTo( _intersectPoint ); - - if ( distance < raycaster.near || distance > raycaster.far ) return; - - intersects.push( { - - distance: distance, - point: _intersectPoint.clone(), - uv: Triangle.getInterpolation( _intersectPoint, _vA, _vB, _vC, _uvA, _uvB, _uvC, new Vector2() ), - face: null, - object: this - - } ); - - } - - copy( source, recursive ) { - - super.copy( source, recursive ); - - if ( source.center !== undefined ) this.center.copy( source.center ); - - this.material = source.material; - - return this; - - } - -} - -function transformVertex( vertexPosition, mvPosition, center, scale, sin, cos ) { - - // compute position in camera space - _alignedPosition.subVectors( vertexPosition, center ).addScalar( 0.5 ).multiply( scale ); - - // to check if rotation is not zero - if ( sin !== undefined ) { - - _rotatedPosition.x = ( cos * _alignedPosition.x ) - ( sin * _alignedPosition.y ); - _rotatedPosition.y = ( sin * _alignedPosition.x ) + ( cos * _alignedPosition.y ); - - } else { - - _rotatedPosition.copy( _alignedPosition ); - - } - - - vertexPosition.copy( mvPosition ); - vertexPosition.x += _rotatedPosition.x; - vertexPosition.y += _rotatedPosition.y; - - // transform to world space - vertexPosition.applyMatrix4( _viewWorldMatrix ); - -} - -const _v1$2 = /*@__PURE__*/ new Vector3(); -const _v2$1 = /*@__PURE__*/ new Vector3(); - -class LOD extends Object3D { - - constructor() { - - super(); - - this._currentLevel = 0; - - this.type = 'LOD'; - - Object.defineProperties( this, { - levels: { - enumerable: true, - value: [] - }, - isLOD: { - value: true, - } - } ); - - this.autoUpdate = true; - - } - - copy( source ) { - - super.copy( source, false ); - - const levels = source.levels; - - for ( let i = 0, l = levels.length; i < l; i ++ ) { - - const level = levels[ i ]; - - this.addLevel( level.object.clone(), level.distance, level.hysteresis ); - - } - - this.autoUpdate = source.autoUpdate; - - return this; - - } - - addLevel( object, distance = 0, hysteresis = 0 ) { - - distance = Math.abs( distance ); - - const levels = this.levels; - - let l; - - for ( l = 0; l < levels.length; l ++ ) { - - if ( distance < levels[ l ].distance ) { - - break; - - } - - } - - levels.splice( l, 0, { distance: distance, hysteresis: hysteresis, object: object } ); - - this.add( object ); - - return this; - - } - - getCurrentLevel() { - - return this._currentLevel; - - } - - - - getObjectForDistance( distance ) { - - const levels = this.levels; - - if ( levels.length > 0 ) { - - let i, l; - - for ( i = 1, l = levels.length; i < l; i ++ ) { - - let levelDistance = levels[ i ].distance; - - if ( levels[ i ].object.visible ) { - - levelDistance -= levelDistance * levels[ i ].hysteresis; - - } - - if ( distance < levelDistance ) { - - break; - - } - - } - - return levels[ i - 1 ].object; - - } - - return null; - - } - - raycast( raycaster, intersects ) { - - const levels = this.levels; - - if ( levels.length > 0 ) { - - _v1$2.setFromMatrixPosition( this.matrixWorld ); - - const distance = raycaster.ray.origin.distanceTo( _v1$2 ); - - this.getObjectForDistance( distance ).raycast( raycaster, intersects ); - - } - - } - - update( camera ) { - - const levels = this.levels; - - if ( levels.length > 1 ) { - - _v1$2.setFromMatrixPosition( camera.matrixWorld ); - _v2$1.setFromMatrixPosition( this.matrixWorld ); - - const distance = _v1$2.distanceTo( _v2$1 ) / camera.zoom; - - levels[ 0 ].object.visible = true; - - let i, l; - - for ( i = 1, l = levels.length; i < l; i ++ ) { - - let levelDistance = levels[ i ].distance; - - if ( levels[ i ].object.visible ) { - - levelDistance -= levelDistance * levels[ i ].hysteresis; - - } - - if ( distance >= levelDistance ) { - - levels[ i - 1 ].object.visible = false; - levels[ i ].object.visible = true; - - } else { - - break; - - } - - } - - this._currentLevel = i - 1; - - for ( ; i < l; i ++ ) { - - levels[ i ].object.visible = false; - - } - - } - - } - - toJSON( meta ) { - - const data = super.toJSON( meta ); - - if ( this.autoUpdate === false ) data.object.autoUpdate = false; - - data.object.levels = []; - - const levels = this.levels; - - for ( let i = 0, l = levels.length; i < l; i ++ ) { - - const level = levels[ i ]; - - data.object.levels.push( { - object: level.object.uuid, - distance: level.distance, - hysteresis: level.hysteresis - } ); - - } - - return data; - - } - -} - -const _basePosition = /*@__PURE__*/ new Vector3(); - -const _skinIndex = /*@__PURE__*/ new Vector4(); -const _skinWeight = /*@__PURE__*/ new Vector4(); - -const _vector3 = /*@__PURE__*/ new Vector3(); -const _matrix4 = /*@__PURE__*/ new Matrix4(); -const _vertex = /*@__PURE__*/ new Vector3(); - -const _sphere$4 = /*@__PURE__*/ new Sphere(); -const _inverseMatrix$2 = /*@__PURE__*/ new Matrix4(); -const _ray$2 = /*@__PURE__*/ new Ray(); - -class SkinnedMesh extends Mesh { - - constructor( geometry, material ) { - - super( geometry, material ); - - this.isSkinnedMesh = true; - - this.type = 'SkinnedMesh'; - - this.bindMode = AttachedBindMode; - this.bindMatrix = new Matrix4(); - this.bindMatrixInverse = new Matrix4(); - - this.boundingBox = null; - this.boundingSphere = null; - - } - - computeBoundingBox() { - - const geometry = this.geometry; - - if ( this.boundingBox === null ) { - - this.boundingBox = new Box3(); - - } - - this.boundingBox.makeEmpty(); - - const positionAttribute = geometry.getAttribute( 'position' ); - - for ( let i = 0; i < positionAttribute.count; i ++ ) { - - this.getVertexPosition( i, _vertex ); - this.boundingBox.expandByPoint( _vertex ); - - } - - } - - computeBoundingSphere() { - - const geometry = this.geometry; - - if ( this.boundingSphere === null ) { - - this.boundingSphere = new Sphere(); - - } - - this.boundingSphere.makeEmpty(); - - const positionAttribute = geometry.getAttribute( 'position' ); - - for ( let i = 0; i < positionAttribute.count; i ++ ) { - - this.getVertexPosition( i, _vertex ); - this.boundingSphere.expandByPoint( _vertex ); - - } - - } - - copy( source, recursive ) { - - super.copy( source, recursive ); - - this.bindMode = source.bindMode; - this.bindMatrix.copy( source.bindMatrix ); - this.bindMatrixInverse.copy( source.bindMatrixInverse ); - - this.skeleton = source.skeleton; - - if ( source.boundingBox !== null ) this.boundingBox = source.boundingBox.clone(); - if ( source.boundingSphere !== null ) this.boundingSphere = source.boundingSphere.clone(); - - return this; - - } - - raycast( raycaster, intersects ) { - - const material = this.material; - const matrixWorld = this.matrixWorld; - - if ( material === undefined ) return; - - // test with bounding sphere in world space - - if ( this.boundingSphere === null ) this.computeBoundingSphere(); - - _sphere$4.copy( this.boundingSphere ); - _sphere$4.applyMatrix4( matrixWorld ); - - if ( raycaster.ray.intersectsSphere( _sphere$4 ) === false ) return; - - // convert ray to local space of skinned mesh - - _inverseMatrix$2.copy( matrixWorld ).invert(); - _ray$2.copy( raycaster.ray ).applyMatrix4( _inverseMatrix$2 ); - - // test with bounding box in local space - - if ( this.boundingBox !== null ) { - - if ( _ray$2.intersectsBox( this.boundingBox ) === false ) return; - - } - - // test for intersections with geometry - - this._computeIntersections( raycaster, intersects, _ray$2 ); - - } - - getVertexPosition( index, target ) { - - super.getVertexPosition( index, target ); - - this.applyBoneTransform( index, target ); - - return target; - - } - - bind( skeleton, bindMatrix ) { - - this.skeleton = skeleton; - - if ( bindMatrix === undefined ) { - - this.updateMatrixWorld( true ); - - this.skeleton.calculateInverses(); - - bindMatrix = this.matrixWorld; - - } - - this.bindMatrix.copy( bindMatrix ); - this.bindMatrixInverse.copy( bindMatrix ).invert(); - - } - - pose() { - - this.skeleton.pose(); - - } - - normalizeSkinWeights() { - - const vector = new Vector4(); - - const skinWeight = this.geometry.attributes.skinWeight; - - for ( let i = 0, l = skinWeight.count; i < l; i ++ ) { - - vector.fromBufferAttribute( skinWeight, i ); - - const scale = 1.0 / vector.manhattanLength(); - - if ( scale !== Infinity ) { - - vector.multiplyScalar( scale ); - - } else { - - vector.set( 1, 0, 0, 0 ); // do something reasonable - - } - - skinWeight.setXYZW( i, vector.x, vector.y, vector.z, vector.w ); - - } - - } - - updateMatrixWorld( force ) { - - super.updateMatrixWorld( force ); - - if ( this.bindMode === AttachedBindMode ) { - - this.bindMatrixInverse.copy( this.matrixWorld ).invert(); - - } else if ( this.bindMode === DetachedBindMode ) { - - this.bindMatrixInverse.copy( this.bindMatrix ).invert(); - - } else { - - console.warn( 'THREE.SkinnedMesh: Unrecognized bindMode: ' + this.bindMode ); - - } - - } - - applyBoneTransform( index, vector ) { - - const skeleton = this.skeleton; - const geometry = this.geometry; - - _skinIndex.fromBufferAttribute( geometry.attributes.skinIndex, index ); - _skinWeight.fromBufferAttribute( geometry.attributes.skinWeight, index ); - - _basePosition.copy( vector ).applyMatrix4( this.bindMatrix ); - - vector.set( 0, 0, 0 ); - - for ( let i = 0; i < 4; i ++ ) { - - const weight = _skinWeight.getComponent( i ); - - if ( weight !== 0 ) { - - const boneIndex = _skinIndex.getComponent( i ); - - _matrix4.multiplyMatrices( skeleton.bones[ boneIndex ].matrixWorld, skeleton.boneInverses[ boneIndex ] ); - - vector.addScaledVector( _vector3.copy( _basePosition ).applyMatrix4( _matrix4 ), weight ); - - } - - } - - return vector.applyMatrix4( this.bindMatrixInverse ); - - } - -} - -class Bone extends Object3D { - - constructor() { - - super(); - - this.isBone = true; - - this.type = 'Bone'; - - } - -} - -class DataTexture extends Texture { - - constructor( data = null, width = 1, height = 1, format, type, mapping, wrapS, wrapT, magFilter = NearestFilter, minFilter = NearestFilter, anisotropy, colorSpace ) { - - super( null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, colorSpace ); - - this.isDataTexture = true; - - this.image = { data: data, width: width, height: height }; - - this.generateMipmaps = false; - this.flipY = false; - this.unpackAlignment = 1; - - } - -} - -const _offsetMatrix = /*@__PURE__*/ new Matrix4(); -const _identityMatrix$1 = /*@__PURE__*/ new Matrix4(); - -class Skeleton { - - constructor( bones = [], boneInverses = [] ) { - - this.uuid = generateUUID(); - - this.bones = bones.slice( 0 ); - this.boneInverses = boneInverses; - this.boneMatrices = null; - - this.boneTexture = null; - - this.init(); - - } - - init() { - - const bones = this.bones; - const boneInverses = this.boneInverses; - - this.boneMatrices = new Float32Array( bones.length * 16 ); - - // calculate inverse bone matrices if necessary - - if ( boneInverses.length === 0 ) { - - this.calculateInverses(); - - } else { - - // handle special case - - if ( bones.length !== boneInverses.length ) { - - console.warn( 'THREE.Skeleton: Number of inverse bone matrices does not match amount of bones.' ); - - this.boneInverses = []; - - for ( let i = 0, il = this.bones.length; i < il; i ++ ) { - - this.boneInverses.push( new Matrix4() ); - - } - - } - - } - - } - - calculateInverses() { - - this.boneInverses.length = 0; - - for ( let i = 0, il = this.bones.length; i < il; i ++ ) { - - const inverse = new Matrix4(); - - if ( this.bones[ i ] ) { - - inverse.copy( this.bones[ i ].matrixWorld ).invert(); - - } - - this.boneInverses.push( inverse ); - - } - - } - - pose() { - - // recover the bind-time world matrices - - for ( let i = 0, il = this.bones.length; i < il; i ++ ) { - - const bone = this.bones[ i ]; - - if ( bone ) { - - bone.matrixWorld.copy( this.boneInverses[ i ] ).invert(); - - } - - } - - // compute the local matrices, positions, rotations and scales - - for ( let i = 0, il = this.bones.length; i < il; i ++ ) { - - const bone = this.bones[ i ]; - - if ( bone ) { - - if ( bone.parent && bone.parent.isBone ) { - - bone.matrix.copy( bone.parent.matrixWorld ).invert(); - bone.matrix.multiply( bone.matrixWorld ); - - } else { - - bone.matrix.copy( bone.matrixWorld ); - - } - - bone.matrix.decompose( bone.position, bone.quaternion, bone.scale ); - - } - - } - - } - - update() { - - const bones = this.bones; - const boneInverses = this.boneInverses; - const boneMatrices = this.boneMatrices; - const boneTexture = this.boneTexture; - - // flatten bone matrices to array - - for ( let i = 0, il = bones.length; i < il; i ++ ) { - - // compute the offset between the current and the original transform - - const matrix = bones[ i ] ? bones[ i ].matrixWorld : _identityMatrix$1; - - _offsetMatrix.multiplyMatrices( matrix, boneInverses[ i ] ); - _offsetMatrix.toArray( boneMatrices, i * 16 ); - - } - - if ( boneTexture !== null ) { - - boneTexture.needsUpdate = true; - - } - - } - - clone() { - - return new Skeleton( this.bones, this.boneInverses ); - - } - - computeBoneTexture() { - - // layout (1 matrix = 4 pixels) - // RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4) - // with 8x8 pixel texture max 16 bones * 4 pixels = (8 * 8) - // 16x16 pixel texture max 64 bones * 4 pixels = (16 * 16) - // 32x32 pixel texture max 256 bones * 4 pixels = (32 * 32) - // 64x64 pixel texture max 1024 bones * 4 pixels = (64 * 64) - - let size = Math.sqrt( this.bones.length * 4 ); // 4 pixels needed for 1 matrix - size = Math.ceil( size / 4 ) * 4; - size = Math.max( size, 4 ); - - const boneMatrices = new Float32Array( size * size * 4 ); // 4 floats per RGBA pixel - boneMatrices.set( this.boneMatrices ); // copy current values - - const boneTexture = new DataTexture( boneMatrices, size, size, RGBAFormat, FloatType ); - boneTexture.needsUpdate = true; - - this.boneMatrices = boneMatrices; - this.boneTexture = boneTexture; - - return this; - - } - - getBoneByName( name ) { - - for ( let i = 0, il = this.bones.length; i < il; i ++ ) { - - const bone = this.bones[ i ]; - - if ( bone.name === name ) { - - return bone; - - } - - } - - return undefined; - - } - - dispose( ) { - - if ( this.boneTexture !== null ) { - - this.boneTexture.dispose(); - - this.boneTexture = null; - - } - - } - - fromJSON( json, bones ) { - - this.uuid = json.uuid; - - for ( let i = 0, l = json.bones.length; i < l; i ++ ) { - - const uuid = json.bones[ i ]; - let bone = bones[ uuid ]; - - if ( bone === undefined ) { - - console.warn( 'THREE.Skeleton: No bone found with UUID:', uuid ); - bone = new Bone(); - - } - - this.bones.push( bone ); - this.boneInverses.push( new Matrix4().fromArray( json.boneInverses[ i ] ) ); - - } - - this.init(); - - return this; - - } - - toJSON() { - - const data = { - metadata: { - version: 4.6, - type: 'Skeleton', - generator: 'Skeleton.toJSON' - }, - bones: [], - boneInverses: [] - }; - - data.uuid = this.uuid; - - const bones = this.bones; - const boneInverses = this.boneInverses; - - for ( let i = 0, l = bones.length; i < l; i ++ ) { - - const bone = bones[ i ]; - data.bones.push( bone.uuid ); - - const boneInverse = boneInverses[ i ]; - data.boneInverses.push( boneInverse.toArray() ); - - } - - return data; - - } - -} - -class InstancedBufferAttribute extends BufferAttribute { - - constructor( array, itemSize, normalized, meshPerAttribute = 1 ) { - - super( array, itemSize, normalized ); - - this.isInstancedBufferAttribute = true; - - this.meshPerAttribute = meshPerAttribute; - - } - - copy( source ) { - - super.copy( source ); - - this.meshPerAttribute = source.meshPerAttribute; - - return this; - - } - - toJSON() { - - const data = super.toJSON(); - - data.meshPerAttribute = this.meshPerAttribute; - - data.isInstancedBufferAttribute = true; - - return data; - - } - -} - -const _instanceLocalMatrix = /*@__PURE__*/ new Matrix4(); -const _instanceWorldMatrix = /*@__PURE__*/ new Matrix4(); - -const _instanceIntersects = []; - -const _box3 = /*@__PURE__*/ new Box3(); -const _identity = /*@__PURE__*/ new Matrix4(); -const _mesh$1 = /*@__PURE__*/ new Mesh(); -const _sphere$3 = /*@__PURE__*/ new Sphere(); - -class InstancedMesh extends Mesh { - - constructor( geometry, material, count ) { - - super( geometry, material ); - - this.isInstancedMesh = true; - - this.instanceMatrix = new InstancedBufferAttribute( new Float32Array( count * 16 ), 16 ); - this.instanceColor = null; - - this.count = count; - - this.boundingBox = null; - this.boundingSphere = null; - - for ( let i = 0; i < count; i ++ ) { - - this.setMatrixAt( i, _identity ); - - } - - } - - computeBoundingBox() { - - const geometry = this.geometry; - const count = this.count; - - if ( this.boundingBox === null ) { - - this.boundingBox = new Box3(); - - } - - if ( geometry.boundingBox === null ) { - - geometry.computeBoundingBox(); - - } - - this.boundingBox.makeEmpty(); - - for ( let i = 0; i < count; i ++ ) { - - this.getMatrixAt( i, _instanceLocalMatrix ); - - _box3.copy( geometry.boundingBox ).applyMatrix4( _instanceLocalMatrix ); - - this.boundingBox.union( _box3 ); - - } - - } - - computeBoundingSphere() { - - const geometry = this.geometry; - const count = this.count; - - if ( this.boundingSphere === null ) { - - this.boundingSphere = new Sphere(); - - } - - if ( geometry.boundingSphere === null ) { - - geometry.computeBoundingSphere(); - - } - - this.boundingSphere.makeEmpty(); - - for ( let i = 0; i < count; i ++ ) { - - this.getMatrixAt( i, _instanceLocalMatrix ); - - _sphere$3.copy( geometry.boundingSphere ).applyMatrix4( _instanceLocalMatrix ); - - this.boundingSphere.union( _sphere$3 ); - - } - - } - - copy( source, recursive ) { - - super.copy( source, recursive ); - - this.instanceMatrix.copy( source.instanceMatrix ); - - if ( source.instanceColor !== null ) this.instanceColor = source.instanceColor.clone(); - - this.count = source.count; - - if ( source.boundingBox !== null ) this.boundingBox = source.boundingBox.clone(); - if ( source.boundingSphere !== null ) this.boundingSphere = source.boundingSphere.clone(); - - return this; - - } - - getColorAt( index, color ) { - - color.fromArray( this.instanceColor.array, index * 3 ); - - } - - getMatrixAt( index, matrix ) { - - matrix.fromArray( this.instanceMatrix.array, index * 16 ); - - } - - raycast( raycaster, intersects ) { - - const matrixWorld = this.matrixWorld; - const raycastTimes = this.count; - - _mesh$1.geometry = this.geometry; - _mesh$1.material = this.material; - - if ( _mesh$1.material === undefined ) return; - - // test with bounding sphere first - - if ( this.boundingSphere === null ) this.computeBoundingSphere(); - - _sphere$3.copy( this.boundingSphere ); - _sphere$3.applyMatrix4( matrixWorld ); - - if ( raycaster.ray.intersectsSphere( _sphere$3 ) === false ) return; - - // now test each instance - - for ( let instanceId = 0; instanceId < raycastTimes; instanceId ++ ) { - - // calculate the world matrix for each instance - - this.getMatrixAt( instanceId, _instanceLocalMatrix ); - - _instanceWorldMatrix.multiplyMatrices( matrixWorld, _instanceLocalMatrix ); - - // the mesh represents this single instance - - _mesh$1.matrixWorld = _instanceWorldMatrix; - - _mesh$1.raycast( raycaster, _instanceIntersects ); - - // process the result of raycast - - for ( let i = 0, l = _instanceIntersects.length; i < l; i ++ ) { - - const intersect = _instanceIntersects[ i ]; - intersect.instanceId = instanceId; - intersect.object = this; - intersects.push( intersect ); - - } - - _instanceIntersects.length = 0; - - } - - } - - setColorAt( index, color ) { - - if ( this.instanceColor === null ) { - - this.instanceColor = new InstancedBufferAttribute( new Float32Array( this.instanceMatrix.count * 3 ), 3 ); - - } - - color.toArray( this.instanceColor.array, index * 3 ); - - } - - setMatrixAt( index, matrix ) { - - matrix.toArray( this.instanceMatrix.array, index * 16 ); - - } - - updateMorphTargets() { - - } - - dispose() { - - this.dispatchEvent( { type: 'dispose' } ); - - } - -} - -function sortOpaque( a, b ) { - - return a.z - b.z; - -} - -function sortTransparent( a, b ) { - - return b.z - a.z; - -} - -class MultiDrawRenderList { - - constructor() { - - this.index = 0; - this.pool = []; - this.list = []; - - } - - push( drawRange, z ) { - - const pool = this.pool; - const list = this.list; - if ( this.index >= pool.length ) { - - pool.push( { - - start: - 1, - count: - 1, - z: - 1, - - } ); - - } - - const item = pool[ this.index ]; - list.push( item ); - this.index ++; - - item.start = drawRange.start; - item.count = drawRange.count; - item.z = z; - - } - - reset() { - - this.list.length = 0; - this.index = 0; - - } - -} - -const ID_ATTR_NAME = 'batchId'; -const _matrix = /*@__PURE__*/ new Matrix4(); -const _invMatrixWorld = /*@__PURE__*/ new Matrix4(); -const _identityMatrix = /*@__PURE__*/ new Matrix4(); -const _projScreenMatrix$2 = /*@__PURE__*/ new Matrix4(); -const _frustum = /*@__PURE__*/ new Frustum(); -const _box$1 = /*@__PURE__*/ new Box3(); -const _sphere$2 = /*@__PURE__*/ new Sphere(); -const _vector$5 = /*@__PURE__*/ new Vector3(); -const _renderList = /*@__PURE__*/ new MultiDrawRenderList(); -const _mesh = /*@__PURE__*/ new Mesh(); -const _batchIntersects = []; - -// @TODO: SkinnedMesh support? -// @TODO: geometry.groups support? -// @TODO: geometry.drawRange support? -// @TODO: geometry.morphAttributes support? -// @TODO: Support uniform parameter per geometry -// @TODO: Add an "optimize" function to pack geometry and remove data gaps - -// copies data from attribute "src" into "target" starting at "targetOffset" -function copyAttributeData( src, target, targetOffset = 0 ) { - - const itemSize = target.itemSize; - if ( src.isInterleavedBufferAttribute || src.array.constructor !== target.array.constructor ) { - - // use the component getters and setters if the array data cannot - // be copied directly - const vertexCount = src.count; - for ( let i = 0; i < vertexCount; i ++ ) { - - for ( let c = 0; c < itemSize; c ++ ) { - - target.setComponent( i + targetOffset, c, src.getComponent( i, c ) ); - - } - - } - - } else { - - // faster copy approach using typed array set function - target.array.set( src.array, targetOffset * itemSize ); - - } - - target.needsUpdate = true; - -} - -class BatchedMesh extends Mesh { - - get maxGeometryCount() { - - return this._maxGeometryCount; - - } - - constructor( maxGeometryCount, maxVertexCount, maxIndexCount = maxVertexCount * 2, material ) { - - super( new BufferGeometry(), material ); - - this.isBatchedMesh = true; - this.perObjectFrustumCulled = true; - this.sortObjects = true; - this.boundingBox = null; - this.boundingSphere = null; - this.customSort = null; - - this._drawRanges = []; - this._reservedRanges = []; - - this._visibility = []; - this._active = []; - this._bounds = []; - - this._maxGeometryCount = maxGeometryCount; - this._maxVertexCount = maxVertexCount; - this._maxIndexCount = maxIndexCount; - - this._geometryInitialized = false; - this._geometryCount = 0; - this._multiDrawCounts = new Int32Array( maxGeometryCount ); - this._multiDrawStarts = new Int32Array( maxGeometryCount ); - this._multiDrawCount = 0; - this._visibilityChanged = true; - - // Local matrix per geometry by using data texture - this._matricesTexture = null; - - this._initMatricesTexture(); - - } - - _initMatricesTexture() { - - // layout (1 matrix = 4 pixels) - // RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4) - // with 8x8 pixel texture max 16 matrices * 4 pixels = (8 * 8) - // 16x16 pixel texture max 64 matrices * 4 pixels = (16 * 16) - // 32x32 pixel texture max 256 matrices * 4 pixels = (32 * 32) - // 64x64 pixel texture max 1024 matrices * 4 pixels = (64 * 64) - - let size = Math.sqrt( this._maxGeometryCount * 4 ); // 4 pixels needed for 1 matrix - size = Math.ceil( size / 4 ) * 4; - size = Math.max( size, 4 ); - - const matricesArray = new Float32Array( size * size * 4 ); // 4 floats per RGBA pixel - const matricesTexture = new DataTexture( matricesArray, size, size, RGBAFormat, FloatType ); - - this._matricesTexture = matricesTexture; - - } - - _initializeGeometry( reference ) { - - const geometry = this.geometry; - const maxVertexCount = this._maxVertexCount; - const maxGeometryCount = this._maxGeometryCount; - const maxIndexCount = this._maxIndexCount; - if ( this._geometryInitialized === false ) { - - for ( const attributeName in reference.attributes ) { - - const srcAttribute = reference.getAttribute( attributeName ); - const { array, itemSize, normalized } = srcAttribute; - - const dstArray = new array.constructor( maxVertexCount * itemSize ); - const dstAttribute = new srcAttribute.constructor( dstArray, itemSize, normalized ); - dstAttribute.setUsage( srcAttribute.usage ); - - geometry.setAttribute( attributeName, dstAttribute ); - - } - - if ( reference.getIndex() !== null ) { - - const indexArray = maxVertexCount > 65536 - ? new Uint32Array( maxIndexCount ) - : new Uint16Array( maxIndexCount ); - - geometry.setIndex( new BufferAttribute( indexArray, 1 ) ); - - } - - const idArray = maxGeometryCount > 65536 - ? new Uint32Array( maxVertexCount ) - : new Uint16Array( maxVertexCount ); - geometry.setAttribute( ID_ATTR_NAME, new BufferAttribute( idArray, 1 ) ); - - this._geometryInitialized = true; - - } - - } - - // Make sure the geometry is compatible with the existing combined geometry atributes - _validateGeometry( geometry ) { - - // check that the geometry doesn't have a version of our reserved id attribute - if ( geometry.getAttribute( ID_ATTR_NAME ) ) { - - throw new Error( `BatchedMesh: Geometry cannot use attribute "${ ID_ATTR_NAME }"` ); - - } - - // check to ensure the geometries are using consistent attributes and indices - const batchGeometry = this.geometry; - if ( Boolean( geometry.getIndex() ) !== Boolean( batchGeometry.getIndex() ) ) { - - throw new Error( 'BatchedMesh: All geometries must consistently have "index".' ); - - } - - for ( const attributeName in batchGeometry.attributes ) { - - if ( attributeName === ID_ATTR_NAME ) { - - continue; - - } - - if ( ! geometry.hasAttribute( attributeName ) ) { - - throw new Error( `BatchedMesh: Added geometry missing "${ attributeName }". All geometries must have consistent attributes.` ); - - } - - const srcAttribute = geometry.getAttribute( attributeName ); - const dstAttribute = batchGeometry.getAttribute( attributeName ); - if ( srcAttribute.itemSize !== dstAttribute.itemSize || srcAttribute.normalized !== dstAttribute.normalized ) { - - throw new Error( 'BatchedMesh: All attributes must have a consistent itemSize and normalized value.' ); - - } - - } - - } - - setCustomSort( func ) { - - this.customSort = func; - return this; - - } - - computeBoundingBox() { - - if ( this.boundingBox === null ) { - - this.boundingBox = new Box3(); - - } - - const geometryCount = this._geometryCount; - const boundingBox = this.boundingBox; - const active = this._active; - - boundingBox.makeEmpty(); - for ( let i = 0; i < geometryCount; i ++ ) { - - if ( active[ i ] === false ) continue; - - this.getMatrixAt( i, _matrix ); - this.getBoundingBoxAt( i, _box$1 ).applyMatrix4( _matrix ); - boundingBox.union( _box$1 ); - - } - - } - - computeBoundingSphere() { - - if ( this.boundingSphere === null ) { - - this.boundingSphere = new Sphere(); - - } - - const geometryCount = this._geometryCount; - const boundingSphere = this.boundingSphere; - const active = this._active; - - boundingSphere.makeEmpty(); - for ( let i = 0; i < geometryCount; i ++ ) { - - if ( active[ i ] === false ) continue; - - this.getMatrixAt( i, _matrix ); - this.getBoundingSphereAt( i, _sphere$2 ).applyMatrix4( _matrix ); - boundingSphere.union( _sphere$2 ); - - } - - } - - addGeometry( geometry, vertexCount = - 1, indexCount = - 1 ) { - - this._initializeGeometry( geometry ); - - this._validateGeometry( geometry ); - - // ensure we're not over geometry - if ( this._geometryCount >= this._maxGeometryCount ) { - - throw new Error( 'BatchedMesh: Maximum geometry count reached.' ); - - } - - // get the necessary range fo the geometry - const reservedRange = { - vertexStart: - 1, - vertexCount: - 1, - indexStart: - 1, - indexCount: - 1, - }; - - let lastRange = null; - const reservedRanges = this._reservedRanges; - const drawRanges = this._drawRanges; - const bounds = this._bounds; - if ( this._geometryCount !== 0 ) { - - lastRange = reservedRanges[ reservedRanges.length - 1 ]; - - } - - if ( vertexCount === - 1 ) { - - reservedRange.vertexCount = geometry.getAttribute( 'position' ).count; - - } else { - - reservedRange.vertexCount = vertexCount; - - } - - if ( lastRange === null ) { - - reservedRange.vertexStart = 0; - - } else { - - reservedRange.vertexStart = lastRange.vertexStart + lastRange.vertexCount; - - } - - const index = geometry.getIndex(); - const hasIndex = index !== null; - if ( hasIndex ) { - - if ( indexCount === - 1 ) { - - reservedRange.indexCount = index.count; - - } else { - - reservedRange.indexCount = indexCount; - - } - - if ( lastRange === null ) { - - reservedRange.indexStart = 0; - - } else { - - reservedRange.indexStart = lastRange.indexStart + lastRange.indexCount; - - } - - } - - if ( - reservedRange.indexStart !== - 1 && - reservedRange.indexStart + reservedRange.indexCount > this._maxIndexCount || - reservedRange.vertexStart + reservedRange.vertexCount > this._maxVertexCount - ) { - - throw new Error( 'BatchedMesh: Reserved space request exceeds the maximum buffer size.' ); - - } - - const visibility = this._visibility; - const active = this._active; - const matricesTexture = this._matricesTexture; - const matricesArray = this._matricesTexture.image.data; - - // push new visibility states - visibility.push( true ); - active.push( true ); - - // update id - const geometryId = this._geometryCount; - this._geometryCount ++; - - // initialize matrix information - _identityMatrix.toArray( matricesArray, geometryId * 16 ); - matricesTexture.needsUpdate = true; - - // add the reserved range and draw range objects - reservedRanges.push( reservedRange ); - drawRanges.push( { - start: hasIndex ? reservedRange.indexStart : reservedRange.vertexStart, - count: - 1 - } ); - bounds.push( { - boxInitialized: false, - box: new Box3(), - - sphereInitialized: false, - sphere: new Sphere() - } ); - - // set the id for the geometry - const idAttribute = this.geometry.getAttribute( ID_ATTR_NAME ); - for ( let i = 0; i < reservedRange.vertexCount; i ++ ) { - - idAttribute.setX( reservedRange.vertexStart + i, geometryId ); - - } - - idAttribute.needsUpdate = true; - - // update the geometry - this.setGeometryAt( geometryId, geometry ); - - return geometryId; - - } - - setGeometryAt( id, geometry ) { - - if ( id >= this._geometryCount ) { - - throw new Error( 'BatchedMesh: Maximum geometry count reached.' ); - - } - - this._validateGeometry( geometry ); - - const batchGeometry = this.geometry; - const hasIndex = batchGeometry.getIndex() !== null; - const dstIndex = batchGeometry.getIndex(); - const srcIndex = geometry.getIndex(); - const reservedRange = this._reservedRanges[ id ]; - if ( - hasIndex && - srcIndex.count > reservedRange.indexCount || - geometry.attributes.position.count > reservedRange.vertexCount - ) { - - throw new Error( 'BatchedMesh: Reserved space not large enough for provided geometry.' ); - - } - - // copy geometry over - const vertexStart = reservedRange.vertexStart; - const vertexCount = reservedRange.vertexCount; - for ( const attributeName in batchGeometry.attributes ) { - - if ( attributeName === ID_ATTR_NAME ) { - - continue; - - } - - // copy attribute data - const srcAttribute = geometry.getAttribute( attributeName ); - const dstAttribute = batchGeometry.getAttribute( attributeName ); - copyAttributeData( srcAttribute, dstAttribute, vertexStart ); - - // fill the rest in with zeroes - const itemSize = srcAttribute.itemSize; - for ( let i = srcAttribute.count, l = vertexCount; i < l; i ++ ) { - - const index = vertexStart + i; - for ( let c = 0; c < itemSize; c ++ ) { - - dstAttribute.setComponent( index, c, 0 ); - - } - - } - - dstAttribute.needsUpdate = true; - - } - - // copy index - if ( hasIndex ) { - - const indexStart = reservedRange.indexStart; - - // copy index data over - for ( let i = 0; i < srcIndex.count; i ++ ) { - - dstIndex.setX( indexStart + i, vertexStart + srcIndex.getX( i ) ); - - } - - // fill the rest in with zeroes - for ( let i = srcIndex.count, l = reservedRange.indexCount; i < l; i ++ ) { - - dstIndex.setX( indexStart + i, vertexStart ); - - } - - dstIndex.needsUpdate = true; - - } - - // store the bounding boxes - const bound = this._bounds[ id ]; - if ( geometry.boundingBox !== null ) { - - bound.box.copy( geometry.boundingBox ); - bound.boxInitialized = true; - - } else { - - bound.boxInitialized = false; - - } - - if ( geometry.boundingSphere !== null ) { - - bound.sphere.copy( geometry.boundingSphere ); - bound.sphereInitialized = true; - - } else { - - bound.sphereInitialized = false; - - } - - // set drawRange count - const drawRange = this._drawRanges[ id ]; - const posAttr = geometry.getAttribute( 'position' ); - drawRange.count = hasIndex ? srcIndex.count : posAttr.count; - this._visibilityChanged = true; - - return id; - - } - - deleteGeometry( geometryId ) { - - // Note: User needs to call optimize() afterward to pack the data. - - const active = this._active; - if ( geometryId >= active.length || active[ geometryId ] === false ) { - - return this; - - } - - active[ geometryId ] = false; - this._visibilityChanged = true; - - return this; - - } - - // get bounding box and compute it if it doesn't exist - getBoundingBoxAt( id, target ) { - - const active = this._active; - if ( active[ id ] === false ) { - - return null; - - } - - // compute bounding box - const bound = this._bounds[ id ]; - const box = bound.box; - const geometry = this.geometry; - if ( bound.boxInitialized === false ) { - - box.makeEmpty(); - - const index = geometry.index; - const position = geometry.attributes.position; - const drawRange = this._drawRanges[ id ]; - for ( let i = drawRange.start, l = drawRange.start + drawRange.count; i < l; i ++ ) { - - let iv = i; - if ( index ) { - - iv = index.getX( iv ); - - } - - box.expandByPoint( _vector$5.fromBufferAttribute( position, iv ) ); - - } - - bound.boxInitialized = true; - - } - - target.copy( box ); - return target; - - } - - // get bounding sphere and compute it if it doesn't exist - getBoundingSphereAt( id, target ) { - - const active = this._active; - if ( active[ id ] === false ) { - - return null; - - } - - // compute bounding sphere - const bound = this._bounds[ id ]; - const sphere = bound.sphere; - const geometry = this.geometry; - if ( bound.sphereInitialized === false ) { - - sphere.makeEmpty(); - - this.getBoundingBoxAt( id, _box$1 ); - _box$1.getCenter( sphere.center ); - - const index = geometry.index; - const position = geometry.attributes.position; - const drawRange = this._drawRanges[ id ]; - - let maxRadiusSq = 0; - for ( let i = drawRange.start, l = drawRange.start + drawRange.count; i < l; i ++ ) { - - let iv = i; - if ( index ) { - - iv = index.getX( iv ); - - } - - _vector$5.fromBufferAttribute( position, iv ); - maxRadiusSq = Math.max( maxRadiusSq, sphere.center.distanceToSquared( _vector$5 ) ); - - } - - sphere.radius = Math.sqrt( maxRadiusSq ); - bound.sphereInitialized = true; - - } - - target.copy( sphere ); - return target; - - } - - setMatrixAt( geometryId, matrix ) { - - // @TODO: Map geometryId to index of the arrays because - // optimize() can make geometryId mismatch the index - - const active = this._active; - const matricesTexture = this._matricesTexture; - const matricesArray = this._matricesTexture.image.data; - const geometryCount = this._geometryCount; - if ( geometryId >= geometryCount || active[ geometryId ] === false ) { - - return this; - - } - - matrix.toArray( matricesArray, geometryId * 16 ); - matricesTexture.needsUpdate = true; - - return this; - - } - - getMatrixAt( geometryId, matrix ) { - - const active = this._active; - const matricesArray = this._matricesTexture.image.data; - const geometryCount = this._geometryCount; - if ( geometryId >= geometryCount || active[ geometryId ] === false ) { - - return null; - - } - - return matrix.fromArray( matricesArray, geometryId * 16 ); - - } - - setVisibleAt( geometryId, value ) { - - const visibility = this._visibility; - const active = this._active; - const geometryCount = this._geometryCount; - - // if the geometry is out of range, not active, or visibility state - // does not change then return early - if ( - geometryId >= geometryCount || - active[ geometryId ] === false || - visibility[ geometryId ] === value - ) { - - return this; - - } - - visibility[ geometryId ] = value; - this._visibilityChanged = true; - - return this; - - } - - getVisibleAt( geometryId ) { - - const visibility = this._visibility; - const active = this._active; - const geometryCount = this._geometryCount; - - // return early if the geometry is out of range or not active - if ( geometryId >= geometryCount || active[ geometryId ] === false ) { - - return false; - - } - - return visibility[ geometryId ]; - - } - - raycast( raycaster, intersects ) { - - const visibility = this._visibility; - const active = this._active; - const drawRanges = this._drawRanges; - const geometryCount = this._geometryCount; - const matrixWorld = this.matrixWorld; - const batchGeometry = this.geometry; - - // iterate over each geometry - _mesh.material = this.material; - _mesh.geometry.index = batchGeometry.index; - _mesh.geometry.attributes = batchGeometry.attributes; - if ( _mesh.geometry.boundingBox === null ) { - - _mesh.geometry.boundingBox = new Box3(); - - } - - if ( _mesh.geometry.boundingSphere === null ) { - - _mesh.geometry.boundingSphere = new Sphere(); - - } - - for ( let i = 0; i < geometryCount; i ++ ) { - - if ( ! visibility[ i ] || ! active[ i ] ) { - - continue; - - } - - const drawRange = drawRanges[ i ]; - _mesh.geometry.setDrawRange( drawRange.start, drawRange.count ); - - // ge the intersects - this.getMatrixAt( i, _mesh.matrixWorld ).premultiply( matrixWorld ); - this.getBoundingBoxAt( i, _mesh.geometry.boundingBox ); - this.getBoundingSphereAt( i, _mesh.geometry.boundingSphere ); - _mesh.raycast( raycaster, _batchIntersects ); - - // add batch id to the intersects - for ( let j = 0, l = _batchIntersects.length; j < l; j ++ ) { - - const intersect = _batchIntersects[ j ]; - intersect.object = this; - intersect.batchId = i; - intersects.push( intersect ); - - } - - _batchIntersects.length = 0; - - } - - _mesh.material = null; - _mesh.geometry.index = null; - _mesh.geometry.attributes = {}; - _mesh.geometry.setDrawRange( 0, Infinity ); - - } - - copy( source ) { - - super.copy( source ); - - this.geometry = source.geometry.clone(); - this.perObjectFrustumCulled = source.perObjectFrustumCulled; - this.sortObjects = source.sortObjects; - this.boundingBox = source.boundingBox !== null ? source.boundingBox.clone() : null; - this.boundingSphere = source.boundingSphere !== null ? source.boundingSphere.clone() : null; - - this._drawRanges = source._drawRanges.map( range => ( { ...range } ) ); - this._reservedRanges = source._reservedRanges.map( range => ( { ...range } ) ); - - this._visibility = source._visibility.slice(); - this._active = source._active.slice(); - this._bounds = source._bounds.map( bound => ( { - boxInitialized: bound.boxInitialized, - box: bound.box.clone(), - - sphereInitialized: bound.sphereInitialized, - sphere: bound.sphere.clone() - } ) ); - - this._maxGeometryCount = source._maxGeometryCount; - this._maxVertexCount = source._maxVertexCount; - this._maxIndexCount = source._maxIndexCount; - - this._geometryInitialized = source._geometryInitialized; - this._geometryCount = source._geometryCount; - this._multiDrawCounts = source._multiDrawCounts.slice(); - this._multiDrawStarts = source._multiDrawStarts.slice(); - - this._matricesTexture = source._matricesTexture.clone(); - this._matricesTexture.image.data = this._matricesTexture.image.slice(); - - return this; - - } - - dispose() { - - // Assuming the geometry is not shared with other meshes - this.geometry.dispose(); - - this._matricesTexture.dispose(); - this._matricesTexture = null; - return this; - - } - - onBeforeRender( renderer, scene, camera, geometry, material/*, _group*/ ) { - - // if visibility has not changed and frustum culling and object sorting is not required - // then skip iterating over all items - if ( ! this._visibilityChanged && ! this.perObjectFrustumCulled && ! this.sortObjects ) { - - return; - - } - - // the indexed version of the multi draw function requires specifying the start - // offset in bytes. - const index = geometry.getIndex(); - const bytesPerElement = index === null ? 1 : index.array.BYTES_PER_ELEMENT; - - const active = this._active; - const visibility = this._visibility; - const multiDrawStarts = this._multiDrawStarts; - const multiDrawCounts = this._multiDrawCounts; - const drawRanges = this._drawRanges; - const perObjectFrustumCulled = this.perObjectFrustumCulled; - - // prepare the frustum in the local frame - if ( perObjectFrustumCulled ) { - - _projScreenMatrix$2 - .multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ) - .multiply( this.matrixWorld ); - _frustum.setFromProjectionMatrix( - _projScreenMatrix$2, - renderer.coordinateSystem - ); - - } - - let count = 0; - if ( this.sortObjects ) { - - // get the camera position in the local frame - _invMatrixWorld.copy( this.matrixWorld ).invert(); - _vector$5.setFromMatrixPosition( camera.matrixWorld ).applyMatrix4( _invMatrixWorld ); - - for ( let i = 0, l = visibility.length; i < l; i ++ ) { - - if ( visibility[ i ] && active[ i ] ) { - - // get the bounds in world space - this.getMatrixAt( i, _matrix ); - this.getBoundingSphereAt( i, _sphere$2 ).applyMatrix4( _matrix ); - - // determine whether the batched geometry is within the frustum - let culled = false; - if ( perObjectFrustumCulled ) { - - culled = ! _frustum.intersectsSphere( _sphere$2 ); - - } - - if ( ! culled ) { - - // get the distance from camera used for sorting - const z = _vector$5.distanceTo( _sphere$2.center ); - _renderList.push( drawRanges[ i ], z ); - - } - - } - - } - - // Sort the draw ranges and prep for rendering - const list = _renderList.list; - const customSort = this.customSort; - if ( customSort === null ) { - - list.sort( material.transparent ? sortTransparent : sortOpaque ); - - } else { - - customSort.call( this, list, camera ); - - } - - for ( let i = 0, l = list.length; i < l; i ++ ) { - - const item = list[ i ]; - multiDrawStarts[ count ] = item.start * bytesPerElement; - multiDrawCounts[ count ] = item.count; - count ++; - - } - - _renderList.reset(); - - } else { - - for ( let i = 0, l = visibility.length; i < l; i ++ ) { - - if ( visibility[ i ] && active[ i ] ) { - - // determine whether the batched geometry is within the frustum - let culled = false; - if ( perObjectFrustumCulled ) { - - // get the bounds in world space - this.getMatrixAt( i, _matrix ); - this.getBoundingSphereAt( i, _sphere$2 ).applyMatrix4( _matrix ); - culled = ! _frustum.intersectsSphere( _sphere$2 ); - - } - - if ( ! culled ) { - - const range = drawRanges[ i ]; - multiDrawStarts[ count ] = range.start * bytesPerElement; - multiDrawCounts[ count ] = range.count; - count ++; - - } - - } - - } - - } - - this._multiDrawCount = count; - this._visibilityChanged = false; - - } - - onBeforeShadow( renderer, object, camera, shadowCamera, geometry, depthMaterial/* , group */ ) { - - this.onBeforeRender( renderer, null, shadowCamera, geometry, depthMaterial ); - - } - -} - -class LineBasicMaterial extends Material { - - constructor( parameters ) { - - super(); - - this.isLineBasicMaterial = true; - - this.type = 'LineBasicMaterial'; - - this.color = new Color( 0xffffff ); - - this.map = null; - - this.linewidth = 1; - this.linecap = 'round'; - this.linejoin = 'round'; - - this.fog = true; - - this.setValues( parameters ); - - } - - - copy( source ) { - - super.copy( source ); - - this.color.copy( source.color ); - - this.map = source.map; - - this.linewidth = source.linewidth; - this.linecap = source.linecap; - this.linejoin = source.linejoin; - - this.fog = source.fog; - - return this; - - } - -} - -const _start$1 = /*@__PURE__*/ new Vector3(); -const _end$1 = /*@__PURE__*/ new Vector3(); -const _inverseMatrix$1 = /*@__PURE__*/ new Matrix4(); -const _ray$1 = /*@__PURE__*/ new Ray(); -const _sphere$1 = /*@__PURE__*/ new Sphere(); - -class Line extends Object3D { - - constructor( geometry = new BufferGeometry(), material = new LineBasicMaterial() ) { - - super(); - - this.isLine = true; - - this.type = 'Line'; - - this.geometry = geometry; - this.material = material; - - this.updateMorphTargets(); - - } - - copy( source, recursive ) { - - super.copy( source, recursive ); - - this.material = Array.isArray( source.material ) ? source.material.slice() : source.material; - this.geometry = source.geometry; - - return this; - - } - - computeLineDistances() { - - const geometry = this.geometry; - - // we assume non-indexed geometry - - if ( geometry.index === null ) { - - const positionAttribute = geometry.attributes.position; - const lineDistances = [ 0 ]; - - for ( let i = 1, l = positionAttribute.count; i < l; i ++ ) { - - _start$1.fromBufferAttribute( positionAttribute, i - 1 ); - _end$1.fromBufferAttribute( positionAttribute, i ); - - lineDistances[ i ] = lineDistances[ i - 1 ]; - lineDistances[ i ] += _start$1.distanceTo( _end$1 ); - - } - - geometry.setAttribute( 'lineDistance', new Float32BufferAttribute( lineDistances, 1 ) ); - - } else { - - console.warn( 'THREE.Line.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.' ); - - } - - return this; - - } - - raycast( raycaster, intersects ) { - - const geometry = this.geometry; - const matrixWorld = this.matrixWorld; - const threshold = raycaster.params.Line.threshold; - const drawRange = geometry.drawRange; - - // Checking boundingSphere distance to ray - - if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); - - _sphere$1.copy( geometry.boundingSphere ); - _sphere$1.applyMatrix4( matrixWorld ); - _sphere$1.radius += threshold; - - if ( raycaster.ray.intersectsSphere( _sphere$1 ) === false ) return; - - // - - _inverseMatrix$1.copy( matrixWorld ).invert(); - _ray$1.copy( raycaster.ray ).applyMatrix4( _inverseMatrix$1 ); - - const localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 ); - const localThresholdSq = localThreshold * localThreshold; - - const vStart = new Vector3(); - const vEnd = new Vector3(); - const interSegment = new Vector3(); - const interRay = new Vector3(); - const step = this.isLineSegments ? 2 : 1; - - const index = geometry.index; - const attributes = geometry.attributes; - const positionAttribute = attributes.position; - - if ( index !== null ) { - - const start = Math.max( 0, drawRange.start ); - const end = Math.min( index.count, ( drawRange.start + drawRange.count ) ); - - for ( let i = start, l = end - 1; i < l; i += step ) { - - const a = index.getX( i ); - const b = index.getX( i + 1 ); - - vStart.fromBufferAttribute( positionAttribute, a ); - vEnd.fromBufferAttribute( positionAttribute, b ); - - const distSq = _ray$1.distanceSqToSegment( vStart, vEnd, interRay, interSegment ); - - if ( distSq > localThresholdSq ) continue; - - interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation - - const distance = raycaster.ray.origin.distanceTo( interRay ); - - if ( distance < raycaster.near || distance > raycaster.far ) continue; - - intersects.push( { - - distance: distance, - // What do we want? intersection point on the ray or on the segment?? - // point: raycaster.ray.at( distance ), - point: interSegment.clone().applyMatrix4( this.matrixWorld ), - index: i, - face: null, - faceIndex: null, - object: this - - } ); - - } - - } else { - - const start = Math.max( 0, drawRange.start ); - const end = Math.min( positionAttribute.count, ( drawRange.start + drawRange.count ) ); - - for ( let i = start, l = end - 1; i < l; i += step ) { - - vStart.fromBufferAttribute( positionAttribute, i ); - vEnd.fromBufferAttribute( positionAttribute, i + 1 ); - - const distSq = _ray$1.distanceSqToSegment( vStart, vEnd, interRay, interSegment ); - - if ( distSq > localThresholdSq ) continue; - - interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation - - const distance = raycaster.ray.origin.distanceTo( interRay ); - - if ( distance < raycaster.near || distance > raycaster.far ) continue; - - intersects.push( { - - distance: distance, - // What do we want? intersection point on the ray or on the segment?? - // point: raycaster.ray.at( distance ), - point: interSegment.clone().applyMatrix4( this.matrixWorld ), - index: i, - face: null, - faceIndex: null, - object: this - - } ); - - } - - } - - } - - updateMorphTargets() { - - const geometry = this.geometry; - - const morphAttributes = geometry.morphAttributes; - const keys = Object.keys( morphAttributes ); - - if ( keys.length > 0 ) { - - const morphAttribute = morphAttributes[ keys[ 0 ] ]; - - if ( morphAttribute !== undefined ) { - - this.morphTargetInfluences = []; - this.morphTargetDictionary = {}; - - for ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) { - - const name = morphAttribute[ m ].name || String( m ); - - this.morphTargetInfluences.push( 0 ); - this.morphTargetDictionary[ name ] = m; - - } - - } - - } - - } - -} - -const _start = /*@__PURE__*/ new Vector3(); -const _end = /*@__PURE__*/ new Vector3(); - -class LineSegments extends Line { - - constructor( geometry, material ) { - - super( geometry, material ); - - this.isLineSegments = true; - - this.type = 'LineSegments'; - - } - - computeLineDistances() { - - const geometry = this.geometry; - - // we assume non-indexed geometry - - if ( geometry.index === null ) { - - const positionAttribute = geometry.attributes.position; - const lineDistances = []; - - for ( let i = 0, l = positionAttribute.count; i < l; i += 2 ) { - - _start.fromBufferAttribute( positionAttribute, i ); - _end.fromBufferAttribute( positionAttribute, i + 1 ); - - lineDistances[ i ] = ( i === 0 ) ? 0 : lineDistances[ i - 1 ]; - lineDistances[ i + 1 ] = lineDistances[ i ] + _start.distanceTo( _end ); - - } - - geometry.setAttribute( 'lineDistance', new Float32BufferAttribute( lineDistances, 1 ) ); - - } else { - - console.warn( 'THREE.LineSegments.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.' ); - - } - - return this; - - } - -} - -class LineLoop extends Line { - - constructor( geometry, material ) { - - super( geometry, material ); - - this.isLineLoop = true; - - this.type = 'LineLoop'; - - } - -} - -class PointsMaterial extends Material { - - constructor( parameters ) { - - super(); - - this.isPointsMaterial = true; - - this.type = 'PointsMaterial'; - - this.color = new Color( 0xffffff ); - - this.map = null; - - this.alphaMap = null; - - this.size = 1; - this.sizeAttenuation = true; - - this.fog = true; - - this.setValues( parameters ); - - } - - copy( source ) { - - super.copy( source ); - - this.color.copy( source.color ); - - this.map = source.map; - - this.alphaMap = source.alphaMap; - - this.size = source.size; - this.sizeAttenuation = source.sizeAttenuation; - - this.fog = source.fog; - - return this; - - } - -} - -const _inverseMatrix = /*@__PURE__*/ new Matrix4(); -const _ray = /*@__PURE__*/ new Ray(); -const _sphere = /*@__PURE__*/ new Sphere(); -const _position$2 = /*@__PURE__*/ new Vector3(); - -class Points extends Object3D { - - constructor( geometry = new BufferGeometry(), material = new PointsMaterial() ) { - - super(); - - this.isPoints = true; - - this.type = 'Points'; - - this.geometry = geometry; - this.material = material; - - this.updateMorphTargets(); - - } - - copy( source, recursive ) { - - super.copy( source, recursive ); - - this.material = Array.isArray( source.material ) ? source.material.slice() : source.material; - this.geometry = source.geometry; - - return this; - - } - - raycast( raycaster, intersects ) { - - const geometry = this.geometry; - const matrixWorld = this.matrixWorld; - const threshold = raycaster.params.Points.threshold; - const drawRange = geometry.drawRange; - - // Checking boundingSphere distance to ray - - if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); - - _sphere.copy( geometry.boundingSphere ); - _sphere.applyMatrix4( matrixWorld ); - _sphere.radius += threshold; - - if ( raycaster.ray.intersectsSphere( _sphere ) === false ) return; - - // - - _inverseMatrix.copy( matrixWorld ).invert(); - _ray.copy( raycaster.ray ).applyMatrix4( _inverseMatrix ); - - const localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 ); - const localThresholdSq = localThreshold * localThreshold; - - const index = geometry.index; - const attributes = geometry.attributes; - const positionAttribute = attributes.position; - - if ( index !== null ) { - - const start = Math.max( 0, drawRange.start ); - const end = Math.min( index.count, ( drawRange.start + drawRange.count ) ); - - for ( let i = start, il = end; i < il; i ++ ) { - - const a = index.getX( i ); - - _position$2.fromBufferAttribute( positionAttribute, a ); - - testPoint( _position$2, a, localThresholdSq, matrixWorld, raycaster, intersects, this ); - - } - - } else { - - const start = Math.max( 0, drawRange.start ); - const end = Math.min( positionAttribute.count, ( drawRange.start + drawRange.count ) ); - - for ( let i = start, l = end; i < l; i ++ ) { - - _position$2.fromBufferAttribute( positionAttribute, i ); - - testPoint( _position$2, i, localThresholdSq, matrixWorld, raycaster, intersects, this ); - - } - - } - - } - - updateMorphTargets() { - - const geometry = this.geometry; - - const morphAttributes = geometry.morphAttributes; - const keys = Object.keys( morphAttributes ); - - if ( keys.length > 0 ) { - - const morphAttribute = morphAttributes[ keys[ 0 ] ]; - - if ( morphAttribute !== undefined ) { - - this.morphTargetInfluences = []; - this.morphTargetDictionary = {}; - - for ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) { - - const name = morphAttribute[ m ].name || String( m ); - - this.morphTargetInfluences.push( 0 ); - this.morphTargetDictionary[ name ] = m; - - } - - } - - } - - } - -} - -function testPoint( point, index, localThresholdSq, matrixWorld, raycaster, intersects, object ) { - - const rayPointDistanceSq = _ray.distanceSqToPoint( point ); - - if ( rayPointDistanceSq < localThresholdSq ) { - - const intersectPoint = new Vector3(); - - _ray.closestPointToPoint( point, intersectPoint ); - intersectPoint.applyMatrix4( matrixWorld ); - - const distance = raycaster.ray.origin.distanceTo( intersectPoint ); - - if ( distance < raycaster.near || distance > raycaster.far ) return; - - intersects.push( { - - distance: distance, - distanceToRay: Math.sqrt( rayPointDistanceSq ), - point: intersectPoint, - index: index, - face: null, - object: object - - } ); - - } - -} - -class VideoTexture extends Texture { - - constructor( video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) { - - super( video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); - - this.isVideoTexture = true; - - this.minFilter = minFilter !== undefined ? minFilter : LinearFilter; - this.magFilter = magFilter !== undefined ? magFilter : LinearFilter; - - this.generateMipmaps = false; - - const scope = this; - - function updateVideo() { - - scope.needsUpdate = true; - video.requestVideoFrameCallback( updateVideo ); - - } - - if ( 'requestVideoFrameCallback' in video ) { - - video.requestVideoFrameCallback( updateVideo ); - - } - - } - - clone() { - - return new this.constructor( this.image ).copy( this ); - - } - - update() { - - const video = this.image; - const hasVideoFrameCallback = 'requestVideoFrameCallback' in video; - - if ( hasVideoFrameCallback === false && video.readyState >= video.HAVE_CURRENT_DATA ) { - - this.needsUpdate = true; - - } - - } - -} - -class FramebufferTexture extends Texture { - - constructor( width, height ) { - - super( { width, height } ); - - this.isFramebufferTexture = true; - - this.magFilter = NearestFilter; - this.minFilter = NearestFilter; - - this.generateMipmaps = false; - - this.needsUpdate = true; - - } - -} - -class CompressedTexture extends Texture { - - constructor( mipmaps, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, colorSpace ) { - - super( null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, colorSpace ); - - this.isCompressedTexture = true; - - this.image = { width: width, height: height }; - this.mipmaps = mipmaps; - - // no flipping for cube textures - // (also flipping doesn't work for compressed textures ) - - this.flipY = false; - - // can't generate mipmaps for compressed textures - // mips must be embedded in DDS files - - this.generateMipmaps = false; - - } - -} - -class CompressedArrayTexture extends CompressedTexture { - - constructor( mipmaps, width, height, depth, format, type ) { - - super( mipmaps, width, height, format, type ); - - this.isCompressedArrayTexture = true; - this.image.depth = depth; - this.wrapR = ClampToEdgeWrapping; - - } - -} - -class CompressedCubeTexture extends CompressedTexture { - - constructor( images, format, type ) { - - super( undefined, images[ 0 ].width, images[ 0 ].height, format, type, CubeReflectionMapping ); - - this.isCompressedCubeTexture = true; - this.isCubeTexture = true; - - this.image = images; - - } - -} - -class CanvasTexture extends Texture { - - constructor( canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) { - - super( canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); - - this.isCanvasTexture = true; - - this.needsUpdate = true; - - } - -} - -/** - * Extensible curve object. - * - * Some common of curve methods: - * .getPoint( t, optionalTarget ), .getTangent( t, optionalTarget ) - * .getPointAt( u, optionalTarget ), .getTangentAt( u, optionalTarget ) - * .getPoints(), .getSpacedPoints() - * .getLength() - * .updateArcLengths() - * - * This following curves inherit from THREE.Curve: - * - * -- 2D curves -- - * THREE.ArcCurve - * THREE.CubicBezierCurve - * THREE.EllipseCurve - * THREE.LineCurve - * THREE.QuadraticBezierCurve - * THREE.SplineCurve - * - * -- 3D curves -- - * THREE.CatmullRomCurve3 - * THREE.CubicBezierCurve3 - * THREE.LineCurve3 - * THREE.QuadraticBezierCurve3 - * - * A series of curves can be represented as a THREE.CurvePath. - * - **/ - -class Curve { - - constructor() { - - this.type = 'Curve'; - - this.arcLengthDivisions = 200; - - } - - // Virtual base class method to overwrite and implement in subclasses - // - t [0 .. 1] - - getPoint( /* t, optionalTarget */ ) { - - console.warn( 'THREE.Curve: .getPoint() not implemented.' ); - return null; - - } - - // Get point at relative position in curve according to arc length - // - u [0 .. 1] - - getPointAt( u, optionalTarget ) { - - const t = this.getUtoTmapping( u ); - return this.getPoint( t, optionalTarget ); - - } - - // Get sequence of points using getPoint( t ) - - getPoints( divisions = 5 ) { - - const points = []; - - for ( let d = 0; d <= divisions; d ++ ) { - - points.push( this.getPoint( d / divisions ) ); - - } - - return points; - - } - - // Get sequence of points using getPointAt( u ) - - getSpacedPoints( divisions = 5 ) { - - const points = []; - - for ( let d = 0; d <= divisions; d ++ ) { - - points.push( this.getPointAt( d / divisions ) ); - - } - - return points; - - } - - // Get total curve arc length - - getLength() { - - const lengths = this.getLengths(); - return lengths[ lengths.length - 1 ]; - - } - - // Get list of cumulative segment lengths - - getLengths( divisions = this.arcLengthDivisions ) { - - if ( this.cacheArcLengths && - ( this.cacheArcLengths.length === divisions + 1 ) && - ! this.needsUpdate ) { - - return this.cacheArcLengths; - - } - - this.needsUpdate = false; - - const cache = []; - let current, last = this.getPoint( 0 ); - let sum = 0; - - cache.push( 0 ); - - for ( let p = 1; p <= divisions; p ++ ) { - - current = this.getPoint( p / divisions ); - sum += current.distanceTo( last ); - cache.push( sum ); - last = current; - - } - - this.cacheArcLengths = cache; - - return cache; // { sums: cache, sum: sum }; Sum is in the last element. - - } - - updateArcLengths() { - - this.needsUpdate = true; - this.getLengths(); - - } - - // Given u ( 0 .. 1 ), get a t to find p. This gives you points which are equidistant - - getUtoTmapping( u, distance ) { - - const arcLengths = this.getLengths(); - - let i = 0; - const il = arcLengths.length; - - let targetArcLength; // The targeted u distance value to get - - if ( distance ) { - - targetArcLength = distance; - - } else { - - targetArcLength = u * arcLengths[ il - 1 ]; - - } - - // binary search for the index with largest value smaller than target u distance - - let low = 0, high = il - 1, comparison; - - while ( low <= high ) { - - i = Math.floor( low + ( high - low ) / 2 ); // less likely to overflow, though probably not issue here, JS doesn't really have integers, all numbers are floats - - comparison = arcLengths[ i ] - targetArcLength; - - if ( comparison < 0 ) { - - low = i + 1; - - } else if ( comparison > 0 ) { - - high = i - 1; - - } else { - - high = i; - break; - - // DONE - - } - - } - - i = high; - - if ( arcLengths[ i ] === targetArcLength ) { - - return i / ( il - 1 ); - - } - - // we could get finer grain at lengths, or use simple interpolation between two points - - const lengthBefore = arcLengths[ i ]; - const lengthAfter = arcLengths[ i + 1 ]; - - const segmentLength = lengthAfter - lengthBefore; - - // determine where we are between the 'before' and 'after' points - - const segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength; - - // add that fractional amount to t - - const t = ( i + segmentFraction ) / ( il - 1 ); - - return t; - - } - - // Returns a unit vector tangent at t - // In case any sub curve does not implement its tangent derivation, - // 2 points a small delta apart will be used to find its gradient - // which seems to give a reasonable approximation - - getTangent( t, optionalTarget ) { - - const delta = 0.0001; - let t1 = t - delta; - let t2 = t + delta; - - // Capping in case of danger - - if ( t1 < 0 ) t1 = 0; - if ( t2 > 1 ) t2 = 1; - - const pt1 = this.getPoint( t1 ); - const pt2 = this.getPoint( t2 ); - - const tangent = optionalTarget || ( ( pt1.isVector2 ) ? new Vector2() : new Vector3() ); - - tangent.copy( pt2 ).sub( pt1 ).normalize(); - - return tangent; - - } - - getTangentAt( u, optionalTarget ) { - - const t = this.getUtoTmapping( u ); - return this.getTangent( t, optionalTarget ); - - } - - computeFrenetFrames( segments, closed ) { - - // see http://www.cs.indiana.edu/pub/techreports/TR425.pdf - - const normal = new Vector3(); - - const tangents = []; - const normals = []; - const binormals = []; - - const vec = new Vector3(); - const mat = new Matrix4(); - - // compute the tangent vectors for each segment on the curve - - for ( let i = 0; i <= segments; i ++ ) { - - const u = i / segments; - - tangents[ i ] = this.getTangentAt( u, new Vector3() ); - - } - - // select an initial normal vector perpendicular to the first tangent vector, - // and in the direction of the minimum tangent xyz component - - normals[ 0 ] = new Vector3(); - binormals[ 0 ] = new Vector3(); - let min = Number.MAX_VALUE; - const tx = Math.abs( tangents[ 0 ].x ); - const ty = Math.abs( tangents[ 0 ].y ); - const tz = Math.abs( tangents[ 0 ].z ); - - if ( tx <= min ) { - - min = tx; - normal.set( 1, 0, 0 ); - - } - - if ( ty <= min ) { - - min = ty; - normal.set( 0, 1, 0 ); - - } - - if ( tz <= min ) { - - normal.set( 0, 0, 1 ); - - } - - vec.crossVectors( tangents[ 0 ], normal ).normalize(); - - normals[ 0 ].crossVectors( tangents[ 0 ], vec ); - binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ); - - - // compute the slowly-varying normal and binormal vectors for each segment on the curve - - for ( let i = 1; i <= segments; i ++ ) { - - normals[ i ] = normals[ i - 1 ].clone(); - - binormals[ i ] = binormals[ i - 1 ].clone(); - - vec.crossVectors( tangents[ i - 1 ], tangents[ i ] ); - - if ( vec.length() > Number.EPSILON ) { - - vec.normalize(); - - const theta = Math.acos( clamp( tangents[ i - 1 ].dot( tangents[ i ] ), - 1, 1 ) ); // clamp for floating pt errors - - normals[ i ].applyMatrix4( mat.makeRotationAxis( vec, theta ) ); - - } - - binormals[ i ].crossVectors( tangents[ i ], normals[ i ] ); - - } - - // if the curve is closed, postprocess the vectors so the first and last normal vectors are the same - - if ( closed === true ) { - - let theta = Math.acos( clamp( normals[ 0 ].dot( normals[ segments ] ), - 1, 1 ) ); - theta /= segments; - - if ( tangents[ 0 ].dot( vec.crossVectors( normals[ 0 ], normals[ segments ] ) ) > 0 ) { - - theta = - theta; - - } - - for ( let i = 1; i <= segments; i ++ ) { - - // twist a little... - normals[ i ].applyMatrix4( mat.makeRotationAxis( tangents[ i ], theta * i ) ); - binormals[ i ].crossVectors( tangents[ i ], normals[ i ] ); - - } - - } - - return { - tangents: tangents, - normals: normals, - binormals: binormals - }; - - } - - clone() { - - return new this.constructor().copy( this ); - - } - - copy( source ) { - - this.arcLengthDivisions = source.arcLengthDivisions; - - return this; - - } - - toJSON() { - - const data = { - metadata: { - version: 4.6, - type: 'Curve', - generator: 'Curve.toJSON' - } - }; - - data.arcLengthDivisions = this.arcLengthDivisions; - data.type = this.type; - - return data; - - } - - fromJSON( json ) { - - this.arcLengthDivisions = json.arcLengthDivisions; - - return this; - - } - -} - -class EllipseCurve extends Curve { - - constructor( aX = 0, aY = 0, xRadius = 1, yRadius = 1, aStartAngle = 0, aEndAngle = Math.PI * 2, aClockwise = false, aRotation = 0 ) { - - super(); - - this.isEllipseCurve = true; - - this.type = 'EllipseCurve'; - - this.aX = aX; - this.aY = aY; - - this.xRadius = xRadius; - this.yRadius = yRadius; - - this.aStartAngle = aStartAngle; - this.aEndAngle = aEndAngle; - - this.aClockwise = aClockwise; - - this.aRotation = aRotation; - - } - - getPoint( t, optionalTarget ) { - - const point = optionalTarget || new Vector2(); - - const twoPi = Math.PI * 2; - let deltaAngle = this.aEndAngle - this.aStartAngle; - const samePoints = Math.abs( deltaAngle ) < Number.EPSILON; - - // ensures that deltaAngle is 0 .. 2 PI - while ( deltaAngle < 0 ) deltaAngle += twoPi; - while ( deltaAngle > twoPi ) deltaAngle -= twoPi; - - if ( deltaAngle < Number.EPSILON ) { - - if ( samePoints ) { - - deltaAngle = 0; - - } else { - - deltaAngle = twoPi; - - } - - } - - if ( this.aClockwise === true && ! samePoints ) { - - if ( deltaAngle === twoPi ) { - - deltaAngle = - twoPi; - - } else { - - deltaAngle = deltaAngle - twoPi; - - } - - } - - const angle = this.aStartAngle + t * deltaAngle; - let x = this.aX + this.xRadius * Math.cos( angle ); - let y = this.aY + this.yRadius * Math.sin( angle ); - - if ( this.aRotation !== 0 ) { - - const cos = Math.cos( this.aRotation ); - const sin = Math.sin( this.aRotation ); - - const tx = x - this.aX; - const ty = y - this.aY; - - // Rotate the point about the center of the ellipse. - x = tx * cos - ty * sin + this.aX; - y = tx * sin + ty * cos + this.aY; - - } - - return point.set( x, y ); - - } - - copy( source ) { - - super.copy( source ); - - this.aX = source.aX; - this.aY = source.aY; - - this.xRadius = source.xRadius; - this.yRadius = source.yRadius; - - this.aStartAngle = source.aStartAngle; - this.aEndAngle = source.aEndAngle; - - this.aClockwise = source.aClockwise; - - this.aRotation = source.aRotation; - - return this; - - } - - toJSON() { - - const data = super.toJSON(); - - data.aX = this.aX; - data.aY = this.aY; - - data.xRadius = this.xRadius; - data.yRadius = this.yRadius; - - data.aStartAngle = this.aStartAngle; - data.aEndAngle = this.aEndAngle; - - data.aClockwise = this.aClockwise; - - data.aRotation = this.aRotation; - - return data; - - } - - fromJSON( json ) { - - super.fromJSON( json ); - - this.aX = json.aX; - this.aY = json.aY; - - this.xRadius = json.xRadius; - this.yRadius = json.yRadius; - - this.aStartAngle = json.aStartAngle; - this.aEndAngle = json.aEndAngle; - - this.aClockwise = json.aClockwise; - - this.aRotation = json.aRotation; - - return this; - - } - -} - -class ArcCurve extends EllipseCurve { - - constructor( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { - - super( aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise ); - - this.isArcCurve = true; - - this.type = 'ArcCurve'; - - } - -} - -/** - * Centripetal CatmullRom Curve - which is useful for avoiding - * cusps and self-intersections in non-uniform catmull rom curves. - * http://www.cemyuksel.com/research/catmullrom_param/catmullrom.pdf - * - * curve.type accepts centripetal(default), chordal and catmullrom - * curve.tension is used for catmullrom which defaults to 0.5 - */ - - -/* -Based on an optimized c++ solution in - - http://stackoverflow.com/questions/9489736/catmull-rom-curve-with-no-cusps-and-no-self-intersections/ - - http://ideone.com/NoEbVM - -This CubicPoly class could be used for reusing some variables and calculations, -but for three.js curve use, it could be possible inlined and flatten into a single function call -which can be placed in CurveUtils. -*/ - -function CubicPoly() { - - let c0 = 0, c1 = 0, c2 = 0, c3 = 0; - - /* - * Compute coefficients for a cubic polynomial - * p(s) = c0 + c1*s + c2*s^2 + c3*s^3 - * such that - * p(0) = x0, p(1) = x1 - * and - * p'(0) = t0, p'(1) = t1. - */ - function init( x0, x1, t0, t1 ) { - - c0 = x0; - c1 = t0; - c2 = - 3 * x0 + 3 * x1 - 2 * t0 - t1; - c3 = 2 * x0 - 2 * x1 + t0 + t1; - - } - - return { - - initCatmullRom: function ( x0, x1, x2, x3, tension ) { - - init( x1, x2, tension * ( x2 - x0 ), tension * ( x3 - x1 ) ); - - }, - - initNonuniformCatmullRom: function ( x0, x1, x2, x3, dt0, dt1, dt2 ) { - - // compute tangents when parameterized in [t1,t2] - let t1 = ( x1 - x0 ) / dt0 - ( x2 - x0 ) / ( dt0 + dt1 ) + ( x2 - x1 ) / dt1; - let t2 = ( x2 - x1 ) / dt1 - ( x3 - x1 ) / ( dt1 + dt2 ) + ( x3 - x2 ) / dt2; - - // rescale tangents for parametrization in [0,1] - t1 *= dt1; - t2 *= dt1; - - init( x1, x2, t1, t2 ); - - }, - - calc: function ( t ) { - - const t2 = t * t; - const t3 = t2 * t; - return c0 + c1 * t + c2 * t2 + c3 * t3; - - } - - }; - -} - -// - -const tmp = /*@__PURE__*/ new Vector3(); -const px = /*@__PURE__*/ new CubicPoly(); -const py = /*@__PURE__*/ new CubicPoly(); -const pz = /*@__PURE__*/ new CubicPoly(); - -class CatmullRomCurve3 extends Curve { - - constructor( points = [], closed = false, curveType = 'centripetal', tension = 0.5 ) { - - super(); - - this.isCatmullRomCurve3 = true; - - this.type = 'CatmullRomCurve3'; - - this.points = points; - this.closed = closed; - this.curveType = curveType; - this.tension = tension; - - } - - getPoint( t, optionalTarget = new Vector3() ) { - - const point = optionalTarget; - - const points = this.points; - const l = points.length; - - const p = ( l - ( this.closed ? 0 : 1 ) ) * t; - let intPoint = Math.floor( p ); - let weight = p - intPoint; - - if ( this.closed ) { - - intPoint += intPoint > 0 ? 0 : ( Math.floor( Math.abs( intPoint ) / l ) + 1 ) * l; - - } else if ( weight === 0 && intPoint === l - 1 ) { - - intPoint = l - 2; - weight = 1; - - } - - let p0, p3; // 4 points (p1 & p2 defined below) - - if ( this.closed || intPoint > 0 ) { - - p0 = points[ ( intPoint - 1 ) % l ]; - - } else { - - // extrapolate first point - tmp.subVectors( points[ 0 ], points[ 1 ] ).add( points[ 0 ] ); - p0 = tmp; - - } - - const p1 = points[ intPoint % l ]; - const p2 = points[ ( intPoint + 1 ) % l ]; - - if ( this.closed || intPoint + 2 < l ) { - - p3 = points[ ( intPoint + 2 ) % l ]; - - } else { - - // extrapolate last point - tmp.subVectors( points[ l - 1 ], points[ l - 2 ] ).add( points[ l - 1 ] ); - p3 = tmp; - - } - - if ( this.curveType === 'centripetal' || this.curveType === 'chordal' ) { - - // init Centripetal / Chordal Catmull-Rom - const pow = this.curveType === 'chordal' ? 0.5 : 0.25; - let dt0 = Math.pow( p0.distanceToSquared( p1 ), pow ); - let dt1 = Math.pow( p1.distanceToSquared( p2 ), pow ); - let dt2 = Math.pow( p2.distanceToSquared( p3 ), pow ); - - // safety check for repeated points - if ( dt1 < 1e-4 ) dt1 = 1.0; - if ( dt0 < 1e-4 ) dt0 = dt1; - if ( dt2 < 1e-4 ) dt2 = dt1; - - px.initNonuniformCatmullRom( p0.x, p1.x, p2.x, p3.x, dt0, dt1, dt2 ); - py.initNonuniformCatmullRom( p0.y, p1.y, p2.y, p3.y, dt0, dt1, dt2 ); - pz.initNonuniformCatmullRom( p0.z, p1.z, p2.z, p3.z, dt0, dt1, dt2 ); - - } else if ( this.curveType === 'catmullrom' ) { - - px.initCatmullRom( p0.x, p1.x, p2.x, p3.x, this.tension ); - py.initCatmullRom( p0.y, p1.y, p2.y, p3.y, this.tension ); - pz.initCatmullRom( p0.z, p1.z, p2.z, p3.z, this.tension ); - - } - - point.set( - px.calc( weight ), - py.calc( weight ), - pz.calc( weight ) - ); - - return point; - - } - - copy( source ) { - - super.copy( source ); - - this.points = []; - - for ( let i = 0, l = source.points.length; i < l; i ++ ) { - - const point = source.points[ i ]; - - this.points.push( point.clone() ); - - } - - this.closed = source.closed; - this.curveType = source.curveType; - this.tension = source.tension; - - return this; - - } - - toJSON() { - - const data = super.toJSON(); - - data.points = []; - - for ( let i = 0, l = this.points.length; i < l; i ++ ) { - - const point = this.points[ i ]; - data.points.push( point.toArray() ); - - } - - data.closed = this.closed; - data.curveType = this.curveType; - data.tension = this.tension; - - return data; - - } - - fromJSON( json ) { - - super.fromJSON( json ); - - this.points = []; - - for ( let i = 0, l = json.points.length; i < l; i ++ ) { - - const point = json.points[ i ]; - this.points.push( new Vector3().fromArray( point ) ); - - } - - this.closed = json.closed; - this.curveType = json.curveType; - this.tension = json.tension; - - return this; - - } - -} - -/** - * Bezier Curves formulas obtained from - * https://en.wikipedia.org/wiki/B%C3%A9zier_curve - */ - -function CatmullRom( t, p0, p1, p2, p3 ) { - - const v0 = ( p2 - p0 ) * 0.5; - const v1 = ( p3 - p1 ) * 0.5; - const t2 = t * t; - const t3 = t * t2; - return ( 2 * p1 - 2 * p2 + v0 + v1 ) * t3 + ( - 3 * p1 + 3 * p2 - 2 * v0 - v1 ) * t2 + v0 * t + p1; - -} - -// - -function QuadraticBezierP0( t, p ) { - - const k = 1 - t; - return k * k * p; - -} - -function QuadraticBezierP1( t, p ) { - - return 2 * ( 1 - t ) * t * p; - -} - -function QuadraticBezierP2( t, p ) { - - return t * t * p; - -} - -function QuadraticBezier( t, p0, p1, p2 ) { - - return QuadraticBezierP0( t, p0 ) + QuadraticBezierP1( t, p1 ) + - QuadraticBezierP2( t, p2 ); - -} - -// - -function CubicBezierP0( t, p ) { - - const k = 1 - t; - return k * k * k * p; - -} - -function CubicBezierP1( t, p ) { - - const k = 1 - t; - return 3 * k * k * t * p; - -} - -function CubicBezierP2( t, p ) { - - return 3 * ( 1 - t ) * t * t * p; - -} - -function CubicBezierP3( t, p ) { - - return t * t * t * p; - -} - -function CubicBezier( t, p0, p1, p2, p3 ) { - - return CubicBezierP0( t, p0 ) + CubicBezierP1( t, p1 ) + CubicBezierP2( t, p2 ) + - CubicBezierP3( t, p3 ); - -} - -class CubicBezierCurve extends Curve { - - constructor( v0 = new Vector2(), v1 = new Vector2(), v2 = new Vector2(), v3 = new Vector2() ) { - - super(); - - this.isCubicBezierCurve = true; - - this.type = 'CubicBezierCurve'; - - this.v0 = v0; - this.v1 = v1; - this.v2 = v2; - this.v3 = v3; - - } - - getPoint( t, optionalTarget = new Vector2() ) { - - const point = optionalTarget; - - const v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3; - - point.set( - CubicBezier( t, v0.x, v1.x, v2.x, v3.x ), - CubicBezier( t, v0.y, v1.y, v2.y, v3.y ) - ); - - return point; - - } - - copy( source ) { - - super.copy( source ); - - this.v0.copy( source.v0 ); - this.v1.copy( source.v1 ); - this.v2.copy( source.v2 ); - this.v3.copy( source.v3 ); - - return this; - - } - - toJSON() { - - const data = super.toJSON(); - - data.v0 = this.v0.toArray(); - data.v1 = this.v1.toArray(); - data.v2 = this.v2.toArray(); - data.v3 = this.v3.toArray(); - - return data; - - } - - fromJSON( json ) { - - super.fromJSON( json ); - - this.v0.fromArray( json.v0 ); - this.v1.fromArray( json.v1 ); - this.v2.fromArray( json.v2 ); - this.v3.fromArray( json.v3 ); - - return this; - - } - -} - -class CubicBezierCurve3 extends Curve { - - constructor( v0 = new Vector3(), v1 = new Vector3(), v2 = new Vector3(), v3 = new Vector3() ) { - - super(); - - this.isCubicBezierCurve3 = true; - - this.type = 'CubicBezierCurve3'; - - this.v0 = v0; - this.v1 = v1; - this.v2 = v2; - this.v3 = v3; - - } - - getPoint( t, optionalTarget = new Vector3() ) { - - const point = optionalTarget; - - const v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3; - - point.set( - CubicBezier( t, v0.x, v1.x, v2.x, v3.x ), - CubicBezier( t, v0.y, v1.y, v2.y, v3.y ), - CubicBezier( t, v0.z, v1.z, v2.z, v3.z ) - ); - - return point; - - } - - copy( source ) { - - super.copy( source ); - - this.v0.copy( source.v0 ); - this.v1.copy( source.v1 ); - this.v2.copy( source.v2 ); - this.v3.copy( source.v3 ); - - return this; - - } - - toJSON() { - - const data = super.toJSON(); - - data.v0 = this.v0.toArray(); - data.v1 = this.v1.toArray(); - data.v2 = this.v2.toArray(); - data.v3 = this.v3.toArray(); - - return data; - - } - - fromJSON( json ) { - - super.fromJSON( json ); - - this.v0.fromArray( json.v0 ); - this.v1.fromArray( json.v1 ); - this.v2.fromArray( json.v2 ); - this.v3.fromArray( json.v3 ); - - return this; - - } - -} - -class LineCurve extends Curve { - - constructor( v1 = new Vector2(), v2 = new Vector2() ) { - - super(); - - this.isLineCurve = true; - - this.type = 'LineCurve'; - - this.v1 = v1; - this.v2 = v2; - - } - - getPoint( t, optionalTarget = new Vector2() ) { - - const point = optionalTarget; - - if ( t === 1 ) { - - point.copy( this.v2 ); - - } else { - - point.copy( this.v2 ).sub( this.v1 ); - point.multiplyScalar( t ).add( this.v1 ); - - } - - return point; - - } - - // Line curve is linear, so we can overwrite default getPointAt - getPointAt( u, optionalTarget ) { - - return this.getPoint( u, optionalTarget ); - - } - - getTangent( t, optionalTarget = new Vector2() ) { - - return optionalTarget.subVectors( this.v2, this.v1 ).normalize(); - - } - - getTangentAt( u, optionalTarget ) { - - return this.getTangent( u, optionalTarget ); - - } - - copy( source ) { - - super.copy( source ); - - this.v1.copy( source.v1 ); - this.v2.copy( source.v2 ); - - return this; - - } - - toJSON() { - - const data = super.toJSON(); - - data.v1 = this.v1.toArray(); - data.v2 = this.v2.toArray(); - - return data; - - } - - fromJSON( json ) { - - super.fromJSON( json ); - - this.v1.fromArray( json.v1 ); - this.v2.fromArray( json.v2 ); - - return this; - - } - -} - -class LineCurve3 extends Curve { - - constructor( v1 = new Vector3(), v2 = new Vector3() ) { - - super(); - - this.isLineCurve3 = true; - - this.type = 'LineCurve3'; - - this.v1 = v1; - this.v2 = v2; - - } - - getPoint( t, optionalTarget = new Vector3() ) { - - const point = optionalTarget; - - if ( t === 1 ) { - - point.copy( this.v2 ); - - } else { - - point.copy( this.v2 ).sub( this.v1 ); - point.multiplyScalar( t ).add( this.v1 ); - - } - - return point; - - } - - // Line curve is linear, so we can overwrite default getPointAt - getPointAt( u, optionalTarget ) { - - return this.getPoint( u, optionalTarget ); - - } - - getTangent( t, optionalTarget = new Vector3() ) { - - return optionalTarget.subVectors( this.v2, this.v1 ).normalize(); - - } - - getTangentAt( u, optionalTarget ) { - - return this.getTangent( u, optionalTarget ); - - } - - copy( source ) { - - super.copy( source ); - - this.v1.copy( source.v1 ); - this.v2.copy( source.v2 ); - - return this; - - } - - toJSON() { - - const data = super.toJSON(); - - data.v1 = this.v1.toArray(); - data.v2 = this.v2.toArray(); - - return data; - - } - - fromJSON( json ) { - - super.fromJSON( json ); - - this.v1.fromArray( json.v1 ); - this.v2.fromArray( json.v2 ); - - return this; - - } - -} - -class QuadraticBezierCurve extends Curve { - - constructor( v0 = new Vector2(), v1 = new Vector2(), v2 = new Vector2() ) { - - super(); - - this.isQuadraticBezierCurve = true; - - this.type = 'QuadraticBezierCurve'; - - this.v0 = v0; - this.v1 = v1; - this.v2 = v2; - - } - - getPoint( t, optionalTarget = new Vector2() ) { - - const point = optionalTarget; - - const v0 = this.v0, v1 = this.v1, v2 = this.v2; - - point.set( - QuadraticBezier( t, v0.x, v1.x, v2.x ), - QuadraticBezier( t, v0.y, v1.y, v2.y ) - ); - - return point; - - } - - copy( source ) { - - super.copy( source ); - - this.v0.copy( source.v0 ); - this.v1.copy( source.v1 ); - this.v2.copy( source.v2 ); - - return this; - - } - - toJSON() { - - const data = super.toJSON(); - - data.v0 = this.v0.toArray(); - data.v1 = this.v1.toArray(); - data.v2 = this.v2.toArray(); - - return data; - - } - - fromJSON( json ) { - - super.fromJSON( json ); - - this.v0.fromArray( json.v0 ); - this.v1.fromArray( json.v1 ); - this.v2.fromArray( json.v2 ); - - return this; - - } - -} - -class QuadraticBezierCurve3 extends Curve { - - constructor( v0 = new Vector3(), v1 = new Vector3(), v2 = new Vector3() ) { - - super(); - - this.isQuadraticBezierCurve3 = true; - - this.type = 'QuadraticBezierCurve3'; - - this.v0 = v0; - this.v1 = v1; - this.v2 = v2; - - } - - getPoint( t, optionalTarget = new Vector3() ) { - - const point = optionalTarget; - - const v0 = this.v0, v1 = this.v1, v2 = this.v2; - - point.set( - QuadraticBezier( t, v0.x, v1.x, v2.x ), - QuadraticBezier( t, v0.y, v1.y, v2.y ), - QuadraticBezier( t, v0.z, v1.z, v2.z ) - ); - - return point; - - } - - copy( source ) { - - super.copy( source ); - - this.v0.copy( source.v0 ); - this.v1.copy( source.v1 ); - this.v2.copy( source.v2 ); - - return this; - - } - - toJSON() { - - const data = super.toJSON(); - - data.v0 = this.v0.toArray(); - data.v1 = this.v1.toArray(); - data.v2 = this.v2.toArray(); - - return data; - - } - - fromJSON( json ) { - - super.fromJSON( json ); - - this.v0.fromArray( json.v0 ); - this.v1.fromArray( json.v1 ); - this.v2.fromArray( json.v2 ); - - return this; - - } - -} - -class SplineCurve extends Curve { - - constructor( points = [] ) { - - super(); - - this.isSplineCurve = true; - - this.type = 'SplineCurve'; - - this.points = points; - - } - - getPoint( t, optionalTarget = new Vector2() ) { - - const point = optionalTarget; - - const points = this.points; - const p = ( points.length - 1 ) * t; - - const intPoint = Math.floor( p ); - const weight = p - intPoint; - - const p0 = points[ intPoint === 0 ? intPoint : intPoint - 1 ]; - const p1 = points[ intPoint ]; - const p2 = points[ intPoint > points.length - 2 ? points.length - 1 : intPoint + 1 ]; - const p3 = points[ intPoint > points.length - 3 ? points.length - 1 : intPoint + 2 ]; - - point.set( - CatmullRom( weight, p0.x, p1.x, p2.x, p3.x ), - CatmullRom( weight, p0.y, p1.y, p2.y, p3.y ) - ); - - return point; - - } - - copy( source ) { - - super.copy( source ); - - this.points = []; - - for ( let i = 0, l = source.points.length; i < l; i ++ ) { - - const point = source.points[ i ]; - - this.points.push( point.clone() ); - - } - - return this; - - } - - toJSON() { - - const data = super.toJSON(); - - data.points = []; - - for ( let i = 0, l = this.points.length; i < l; i ++ ) { - - const point = this.points[ i ]; - data.points.push( point.toArray() ); - - } - - return data; - - } - - fromJSON( json ) { - - super.fromJSON( json ); - - this.points = []; - - for ( let i = 0, l = json.points.length; i < l; i ++ ) { - - const point = json.points[ i ]; - this.points.push( new Vector2().fromArray( point ) ); - - } - - return this; - - } - -} - -var Curves = /*#__PURE__*/Object.freeze({ - __proto__: null, - ArcCurve: ArcCurve, - CatmullRomCurve3: CatmullRomCurve3, - CubicBezierCurve: CubicBezierCurve, - CubicBezierCurve3: CubicBezierCurve3, - EllipseCurve: EllipseCurve, - LineCurve: LineCurve, - LineCurve3: LineCurve3, - QuadraticBezierCurve: QuadraticBezierCurve, - QuadraticBezierCurve3: QuadraticBezierCurve3, - SplineCurve: SplineCurve -}); - -/************************************************************** - * Curved Path - a curve path is simply a array of connected - * curves, but retains the api of a curve - **************************************************************/ - -class CurvePath extends Curve { - - constructor() { - - super(); - - this.type = 'CurvePath'; - - this.curves = []; - this.autoClose = false; // Automatically closes the path - - } - - add( curve ) { - - this.curves.push( curve ); - - } - - closePath() { - - // Add a line curve if start and end of lines are not connected - const startPoint = this.curves[ 0 ].getPoint( 0 ); - const endPoint = this.curves[ this.curves.length - 1 ].getPoint( 1 ); - - if ( ! startPoint.equals( endPoint ) ) { - - const lineType = ( startPoint.isVector2 === true ) ? 'LineCurve' : 'LineCurve3'; - this.curves.push( new Curves[ lineType ]( endPoint, startPoint ) ); - - } - - return this; - - } - - // To get accurate point with reference to - // entire path distance at time t, - // following has to be done: - - // 1. Length of each sub path have to be known - // 2. Locate and identify type of curve - // 3. Get t for the curve - // 4. Return curve.getPointAt(t') - - getPoint( t, optionalTarget ) { - - const d = t * this.getLength(); - const curveLengths = this.getCurveLengths(); - let i = 0; - - // To think about boundaries points. - - while ( i < curveLengths.length ) { - - if ( curveLengths[ i ] >= d ) { - - const diff = curveLengths[ i ] - d; - const curve = this.curves[ i ]; - - const segmentLength = curve.getLength(); - const u = segmentLength === 0 ? 0 : 1 - diff / segmentLength; - - return curve.getPointAt( u, optionalTarget ); - - } - - i ++; - - } - - return null; - - // loop where sum != 0, sum > d , sum+1 1 && ! points[ points.length - 1 ].equals( points[ 0 ] ) ) { - - points.push( points[ 0 ] ); - - } - - return points; - - } - - copy( source ) { - - super.copy( source ); - - this.curves = []; - - for ( let i = 0, l = source.curves.length; i < l; i ++ ) { - - const curve = source.curves[ i ]; - - this.curves.push( curve.clone() ); - - } - - this.autoClose = source.autoClose; - - return this; - - } - - toJSON() { - - const data = super.toJSON(); - - data.autoClose = this.autoClose; - data.curves = []; - - for ( let i = 0, l = this.curves.length; i < l; i ++ ) { - - const curve = this.curves[ i ]; - data.curves.push( curve.toJSON() ); - - } - - return data; - - } - - fromJSON( json ) { - - super.fromJSON( json ); - - this.autoClose = json.autoClose; - this.curves = []; - - for ( let i = 0, l = json.curves.length; i < l; i ++ ) { - - const curve = json.curves[ i ]; - this.curves.push( new Curves[ curve.type ]().fromJSON( curve ) ); - - } - - return this; - - } - -} - -class Path extends CurvePath { - - constructor( points ) { - - super(); - - this.type = 'Path'; - - this.currentPoint = new Vector2(); - - if ( points ) { - - this.setFromPoints( points ); - - } - - } - - setFromPoints( points ) { - - this.moveTo( points[ 0 ].x, points[ 0 ].y ); - - for ( let i = 1, l = points.length; i < l; i ++ ) { - - this.lineTo( points[ i ].x, points[ i ].y ); - - } - - return this; - - } - - moveTo( x, y ) { - - this.currentPoint.set( x, y ); // TODO consider referencing vectors instead of copying? - - return this; - - } - - lineTo( x, y ) { - - const curve = new LineCurve( this.currentPoint.clone(), new Vector2( x, y ) ); - this.curves.push( curve ); - - this.currentPoint.set( x, y ); - - return this; - - } - - quadraticCurveTo( aCPx, aCPy, aX, aY ) { - - const curve = new QuadraticBezierCurve( - this.currentPoint.clone(), - new Vector2( aCPx, aCPy ), - new Vector2( aX, aY ) - ); - - this.curves.push( curve ); - - this.currentPoint.set( aX, aY ); - - return this; - - } - - bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) { - - const curve = new CubicBezierCurve( - this.currentPoint.clone(), - new Vector2( aCP1x, aCP1y ), - new Vector2( aCP2x, aCP2y ), - new Vector2( aX, aY ) - ); - - this.curves.push( curve ); - - this.currentPoint.set( aX, aY ); - - return this; - - } - - splineThru( pts /*Array of Vector*/ ) { - - const npts = [ this.currentPoint.clone() ].concat( pts ); - - const curve = new SplineCurve( npts ); - this.curves.push( curve ); - - this.currentPoint.copy( pts[ pts.length - 1 ] ); - - return this; - - } - - arc( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { - - const x0 = this.currentPoint.x; - const y0 = this.currentPoint.y; - - this.absarc( aX + x0, aY + y0, aRadius, - aStartAngle, aEndAngle, aClockwise ); - - return this; - - } - - absarc( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { - - this.absellipse( aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise ); - - return this; - - } - - ellipse( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) { - - const x0 = this.currentPoint.x; - const y0 = this.currentPoint.y; - - this.absellipse( aX + x0, aY + y0, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ); - - return this; - - } - - absellipse( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) { - - const curve = new EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ); - - if ( this.curves.length > 0 ) { - - // if a previous curve is present, attempt to join - const firstPoint = curve.getPoint( 0 ); - - if ( ! firstPoint.equals( this.currentPoint ) ) { - - this.lineTo( firstPoint.x, firstPoint.y ); - - } - - } - - this.curves.push( curve ); - - const lastPoint = curve.getPoint( 1 ); - this.currentPoint.copy( lastPoint ); - - return this; - - } - - copy( source ) { - - super.copy( source ); - - this.currentPoint.copy( source.currentPoint ); - - return this; - - } - - toJSON() { - - const data = super.toJSON(); - - data.currentPoint = this.currentPoint.toArray(); - - return data; - - } - - fromJSON( json ) { - - super.fromJSON( json ); - - this.currentPoint.fromArray( json.currentPoint ); - - return this; - - } - -} - -class LatheGeometry extends BufferGeometry { - - constructor( points = [ new Vector2( 0, - 0.5 ), new Vector2( 0.5, 0 ), new Vector2( 0, 0.5 ) ], segments = 12, phiStart = 0, phiLength = Math.PI * 2 ) { - - super(); - - this.type = 'LatheGeometry'; - - this.parameters = { - points: points, - segments: segments, - phiStart: phiStart, - phiLength: phiLength - }; - - segments = Math.floor( segments ); - - // clamp phiLength so it's in range of [ 0, 2PI ] - - phiLength = clamp( phiLength, 0, Math.PI * 2 ); - - // buffers - - const indices = []; - const vertices = []; - const uvs = []; - const initNormals = []; - const normals = []; - - // helper variables - - const inverseSegments = 1.0 / segments; - const vertex = new Vector3(); - const uv = new Vector2(); - const normal = new Vector3(); - const curNormal = new Vector3(); - const prevNormal = new Vector3(); - let dx = 0; - let dy = 0; - - // pre-compute normals for initial "meridian" - - for ( let j = 0; j <= ( points.length - 1 ); j ++ ) { - - switch ( j ) { - - case 0: // special handling for 1st vertex on path - - dx = points[ j + 1 ].x - points[ j ].x; - dy = points[ j + 1 ].y - points[ j ].y; - - normal.x = dy * 1.0; - normal.y = - dx; - normal.z = dy * 0.0; - - prevNormal.copy( normal ); - - normal.normalize(); - - initNormals.push( normal.x, normal.y, normal.z ); - - break; - - case ( points.length - 1 ): // special handling for last Vertex on path - - initNormals.push( prevNormal.x, prevNormal.y, prevNormal.z ); - - break; - - default: // default handling for all vertices in between - - dx = points[ j + 1 ].x - points[ j ].x; - dy = points[ j + 1 ].y - points[ j ].y; - - normal.x = dy * 1.0; - normal.y = - dx; - normal.z = dy * 0.0; - - curNormal.copy( normal ); - - normal.x += prevNormal.x; - normal.y += prevNormal.y; - normal.z += prevNormal.z; - - normal.normalize(); - - initNormals.push( normal.x, normal.y, normal.z ); - - prevNormal.copy( curNormal ); - - } - - } - - // generate vertices, uvs and normals - - for ( let i = 0; i <= segments; i ++ ) { - - const phi = phiStart + i * inverseSegments * phiLength; - - const sin = Math.sin( phi ); - const cos = Math.cos( phi ); - - for ( let j = 0; j <= ( points.length - 1 ); j ++ ) { - - // vertex - - vertex.x = points[ j ].x * sin; - vertex.y = points[ j ].y; - vertex.z = points[ j ].x * cos; - - vertices.push( vertex.x, vertex.y, vertex.z ); - - // uv - - uv.x = i / segments; - uv.y = j / ( points.length - 1 ); - - uvs.push( uv.x, uv.y ); - - // normal - - const x = initNormals[ 3 * j + 0 ] * sin; - const y = initNormals[ 3 * j + 1 ]; - const z = initNormals[ 3 * j + 0 ] * cos; - - normals.push( x, y, z ); - - } - - } - - // indices - - for ( let i = 0; i < segments; i ++ ) { - - for ( let j = 0; j < ( points.length - 1 ); j ++ ) { - - const base = j + i * points.length; - - const a = base; - const b = base + points.length; - const c = base + points.length + 1; - const d = base + 1; - - // faces - - indices.push( a, b, d ); - indices.push( c, d, b ); - - } - - } - - // build geometry - - this.setIndex( indices ); - this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - - } - - copy( source ) { - - super.copy( source ); - - this.parameters = Object.assign( {}, source.parameters ); - - return this; - - } - - static fromJSON( data ) { - - return new LatheGeometry( data.points, data.segments, data.phiStart, data.phiLength ); - - } - -} - -class CapsuleGeometry extends LatheGeometry { - - constructor( radius = 1, length = 1, capSegments = 4, radialSegments = 8 ) { - - const path = new Path(); - path.absarc( 0, - length / 2, radius, Math.PI * 1.5, 0 ); - path.absarc( 0, length / 2, radius, 0, Math.PI * 0.5 ); - - super( path.getPoints( capSegments ), radialSegments ); - - this.type = 'CapsuleGeometry'; - - this.parameters = { - radius: radius, - length: length, - capSegments: capSegments, - radialSegments: radialSegments, - }; - - } - - static fromJSON( data ) { - - return new CapsuleGeometry( data.radius, data.length, data.capSegments, data.radialSegments ); - - } - -} - -class CircleGeometry extends BufferGeometry { - - constructor( radius = 1, segments = 32, thetaStart = 0, thetaLength = Math.PI * 2 ) { - - super(); - - this.type = 'CircleGeometry'; - - this.parameters = { - radius: radius, - segments: segments, - thetaStart: thetaStart, - thetaLength: thetaLength - }; - - segments = Math.max( 3, segments ); - - // buffers - - const indices = []; - const vertices = []; - const normals = []; - const uvs = []; - - // helper variables - - const vertex = new Vector3(); - const uv = new Vector2(); - - // center point - - vertices.push( 0, 0, 0 ); - normals.push( 0, 0, 1 ); - uvs.push( 0.5, 0.5 ); - - for ( let s = 0, i = 3; s <= segments; s ++, i += 3 ) { - - const segment = thetaStart + s / segments * thetaLength; - - // vertex - - vertex.x = radius * Math.cos( segment ); - vertex.y = radius * Math.sin( segment ); - - vertices.push( vertex.x, vertex.y, vertex.z ); - - // normal - - normals.push( 0, 0, 1 ); - - // uvs - - uv.x = ( vertices[ i ] / radius + 1 ) / 2; - uv.y = ( vertices[ i + 1 ] / radius + 1 ) / 2; - - uvs.push( uv.x, uv.y ); - - } - - // indices - - for ( let i = 1; i <= segments; i ++ ) { - - indices.push( i, i + 1, 0 ); - - } - - // build geometry - - this.setIndex( indices ); - this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - - } - - copy( source ) { - - super.copy( source ); - - this.parameters = Object.assign( {}, source.parameters ); - - return this; - - } - - static fromJSON( data ) { - - return new CircleGeometry( data.radius, data.segments, data.thetaStart, data.thetaLength ); - - } - -} - -class CylinderGeometry extends BufferGeometry { - - constructor( radiusTop = 1, radiusBottom = 1, height = 1, radialSegments = 32, heightSegments = 1, openEnded = false, thetaStart = 0, thetaLength = Math.PI * 2 ) { - - super(); - - this.type = 'CylinderGeometry'; - - this.parameters = { - radiusTop: radiusTop, - radiusBottom: radiusBottom, - height: height, - radialSegments: radialSegments, - heightSegments: heightSegments, - openEnded: openEnded, - thetaStart: thetaStart, - thetaLength: thetaLength - }; - - const scope = this; - - radialSegments = Math.floor( radialSegments ); - heightSegments = Math.floor( heightSegments ); - - // buffers - - const indices = []; - const vertices = []; - const normals = []; - const uvs = []; - - // helper variables - - let index = 0; - const indexArray = []; - const halfHeight = height / 2; - let groupStart = 0; - - // generate geometry - - generateTorso(); - - if ( openEnded === false ) { - - if ( radiusTop > 0 ) generateCap( true ); - if ( radiusBottom > 0 ) generateCap( false ); - - } - - // build geometry - - this.setIndex( indices ); - this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - - function generateTorso() { - - const normal = new Vector3(); - const vertex = new Vector3(); - - let groupCount = 0; - - // this will be used to calculate the normal - const slope = ( radiusBottom - radiusTop ) / height; - - // generate vertices, normals and uvs - - for ( let y = 0; y <= heightSegments; y ++ ) { - - const indexRow = []; - - const v = y / heightSegments; - - // calculate the radius of the current row - - const radius = v * ( radiusBottom - radiusTop ) + radiusTop; - - for ( let x = 0; x <= radialSegments; x ++ ) { - - const u = x / radialSegments; - - const theta = u * thetaLength + thetaStart; - - const sinTheta = Math.sin( theta ); - const cosTheta = Math.cos( theta ); - - // vertex - - vertex.x = radius * sinTheta; - vertex.y = - v * height + halfHeight; - vertex.z = radius * cosTheta; - vertices.push( vertex.x, vertex.y, vertex.z ); - - // normal - - normal.set( sinTheta, slope, cosTheta ).normalize(); - normals.push( normal.x, normal.y, normal.z ); - - // uv - - uvs.push( u, 1 - v ); - - // save index of vertex in respective row - - indexRow.push( index ++ ); - - } - - // now save vertices of the row in our index array - - indexArray.push( indexRow ); - - } - - // generate indices - - for ( let x = 0; x < radialSegments; x ++ ) { - - for ( let y = 0; y < heightSegments; y ++ ) { - - // we use the index array to access the correct indices - - const a = indexArray[ y ][ x ]; - const b = indexArray[ y + 1 ][ x ]; - const c = indexArray[ y + 1 ][ x + 1 ]; - const d = indexArray[ y ][ x + 1 ]; - - // faces - - indices.push( a, b, d ); - indices.push( b, c, d ); - - // update group counter - - groupCount += 6; - - } - - } - - // add a group to the geometry. this will ensure multi material support - - scope.addGroup( groupStart, groupCount, 0 ); - - // calculate new start value for groups - - groupStart += groupCount; - - } - - function generateCap( top ) { - - // save the index of the first center vertex - const centerIndexStart = index; - - const uv = new Vector2(); - const vertex = new Vector3(); - - let groupCount = 0; - - const radius = ( top === true ) ? radiusTop : radiusBottom; - const sign = ( top === true ) ? 1 : - 1; - - // first we generate the center vertex data of the cap. - // because the geometry needs one set of uvs per face, - // we must generate a center vertex per face/segment - - for ( let x = 1; x <= radialSegments; x ++ ) { - - // vertex - - vertices.push( 0, halfHeight * sign, 0 ); - - // normal - - normals.push( 0, sign, 0 ); - - // uv - - uvs.push( 0.5, 0.5 ); - - // increase index - - index ++; - - } - - // save the index of the last center vertex - const centerIndexEnd = index; - - // now we generate the surrounding vertices, normals and uvs - - for ( let x = 0; x <= radialSegments; x ++ ) { - - const u = x / radialSegments; - const theta = u * thetaLength + thetaStart; - - const cosTheta = Math.cos( theta ); - const sinTheta = Math.sin( theta ); - - // vertex - - vertex.x = radius * sinTheta; - vertex.y = halfHeight * sign; - vertex.z = radius * cosTheta; - vertices.push( vertex.x, vertex.y, vertex.z ); - - // normal - - normals.push( 0, sign, 0 ); - - // uv - - uv.x = ( cosTheta * 0.5 ) + 0.5; - uv.y = ( sinTheta * 0.5 * sign ) + 0.5; - uvs.push( uv.x, uv.y ); - - // increase index - - index ++; - - } - - // generate indices - - for ( let x = 0; x < radialSegments; x ++ ) { - - const c = centerIndexStart + x; - const i = centerIndexEnd + x; - - if ( top === true ) { - - // face top - - indices.push( i, i + 1, c ); - - } else { - - // face bottom - - indices.push( i + 1, i, c ); - - } - - groupCount += 3; - - } - - // add a group to the geometry. this will ensure multi material support - - scope.addGroup( groupStart, groupCount, top === true ? 1 : 2 ); - - // calculate new start value for groups - - groupStart += groupCount; - - } - - } - - copy( source ) { - - super.copy( source ); - - this.parameters = Object.assign( {}, source.parameters ); - - return this; - - } - - static fromJSON( data ) { - - return new CylinderGeometry( data.radiusTop, data.radiusBottom, data.height, data.radialSegments, data.heightSegments, data.openEnded, data.thetaStart, data.thetaLength ); - - } - -} - -class ConeGeometry extends CylinderGeometry { - - constructor( radius = 1, height = 1, radialSegments = 32, heightSegments = 1, openEnded = false, thetaStart = 0, thetaLength = Math.PI * 2 ) { - - super( 0, radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ); - - this.type = 'ConeGeometry'; - - this.parameters = { - radius: radius, - height: height, - radialSegments: radialSegments, - heightSegments: heightSegments, - openEnded: openEnded, - thetaStart: thetaStart, - thetaLength: thetaLength - }; - - } - - static fromJSON( data ) { - - return new ConeGeometry( data.radius, data.height, data.radialSegments, data.heightSegments, data.openEnded, data.thetaStart, data.thetaLength ); - - } - -} - -class PolyhedronGeometry extends BufferGeometry { - - constructor( vertices = [], indices = [], radius = 1, detail = 0 ) { - - super(); - - this.type = 'PolyhedronGeometry'; - - this.parameters = { - vertices: vertices, - indices: indices, - radius: radius, - detail: detail - }; - - // default buffer data - - const vertexBuffer = []; - const uvBuffer = []; - - // the subdivision creates the vertex buffer data - - subdivide( detail ); - - // all vertices should lie on a conceptual sphere with a given radius - - applyRadius( radius ); - - // finally, create the uv data - - generateUVs(); - - // build non-indexed geometry - - this.setAttribute( 'position', new Float32BufferAttribute( vertexBuffer, 3 ) ); - this.setAttribute( 'normal', new Float32BufferAttribute( vertexBuffer.slice(), 3 ) ); - this.setAttribute( 'uv', new Float32BufferAttribute( uvBuffer, 2 ) ); - - if ( detail === 0 ) { - - this.computeVertexNormals(); // flat normals - - } else { - - this.normalizeNormals(); // smooth normals - - } - - // helper functions - - function subdivide( detail ) { - - const a = new Vector3(); - const b = new Vector3(); - const c = new Vector3(); - - // iterate over all faces and apply a subdivision with the given detail value - - for ( let i = 0; i < indices.length; i += 3 ) { - - // get the vertices of the face - - getVertexByIndex( indices[ i + 0 ], a ); - getVertexByIndex( indices[ i + 1 ], b ); - getVertexByIndex( indices[ i + 2 ], c ); - - // perform subdivision - - subdivideFace( a, b, c, detail ); - - } - - } - - function subdivideFace( a, b, c, detail ) { - - const cols = detail + 1; - - // we use this multidimensional array as a data structure for creating the subdivision - - const v = []; - - // construct all of the vertices for this subdivision - - for ( let i = 0; i <= cols; i ++ ) { - - v[ i ] = []; - - const aj = a.clone().lerp( c, i / cols ); - const bj = b.clone().lerp( c, i / cols ); - - const rows = cols - i; - - for ( let j = 0; j <= rows; j ++ ) { - - if ( j === 0 && i === cols ) { - - v[ i ][ j ] = aj; - - } else { - - v[ i ][ j ] = aj.clone().lerp( bj, j / rows ); - - } - - } - - } - - // construct all of the faces - - for ( let i = 0; i < cols; i ++ ) { - - for ( let j = 0; j < 2 * ( cols - i ) - 1; j ++ ) { - - const k = Math.floor( j / 2 ); - - if ( j % 2 === 0 ) { - - pushVertex( v[ i ][ k + 1 ] ); - pushVertex( v[ i + 1 ][ k ] ); - pushVertex( v[ i ][ k ] ); - - } else { - - pushVertex( v[ i ][ k + 1 ] ); - pushVertex( v[ i + 1 ][ k + 1 ] ); - pushVertex( v[ i + 1 ][ k ] ); - - } - - } - - } - - } - - function applyRadius( radius ) { - - const vertex = new Vector3(); - - // iterate over the entire buffer and apply the radius to each vertex - - for ( let i = 0; i < vertexBuffer.length; i += 3 ) { - - vertex.x = vertexBuffer[ i + 0 ]; - vertex.y = vertexBuffer[ i + 1 ]; - vertex.z = vertexBuffer[ i + 2 ]; - - vertex.normalize().multiplyScalar( radius ); - - vertexBuffer[ i + 0 ] = vertex.x; - vertexBuffer[ i + 1 ] = vertex.y; - vertexBuffer[ i + 2 ] = vertex.z; - - } - - } - - function generateUVs() { - - const vertex = new Vector3(); - - for ( let i = 0; i < vertexBuffer.length; i += 3 ) { - - vertex.x = vertexBuffer[ i + 0 ]; - vertex.y = vertexBuffer[ i + 1 ]; - vertex.z = vertexBuffer[ i + 2 ]; - - const u = azimuth( vertex ) / 2 / Math.PI + 0.5; - const v = inclination( vertex ) / Math.PI + 0.5; - uvBuffer.push( u, 1 - v ); - - } - - correctUVs(); - - correctSeam(); - - } - - function correctSeam() { - - // handle case when face straddles the seam, see #3269 - - for ( let i = 0; i < uvBuffer.length; i += 6 ) { - - // uv data of a single face - - const x0 = uvBuffer[ i + 0 ]; - const x1 = uvBuffer[ i + 2 ]; - const x2 = uvBuffer[ i + 4 ]; - - const max = Math.max( x0, x1, x2 ); - const min = Math.min( x0, x1, x2 ); - - // 0.9 is somewhat arbitrary - - if ( max > 0.9 && min < 0.1 ) { - - if ( x0 < 0.2 ) uvBuffer[ i + 0 ] += 1; - if ( x1 < 0.2 ) uvBuffer[ i + 2 ] += 1; - if ( x2 < 0.2 ) uvBuffer[ i + 4 ] += 1; - - } - - } - - } - - function pushVertex( vertex ) { - - vertexBuffer.push( vertex.x, vertex.y, vertex.z ); - - } - - function getVertexByIndex( index, vertex ) { - - const stride = index * 3; - - vertex.x = vertices[ stride + 0 ]; - vertex.y = vertices[ stride + 1 ]; - vertex.z = vertices[ stride + 2 ]; - - } - - function correctUVs() { - - const a = new Vector3(); - const b = new Vector3(); - const c = new Vector3(); - - const centroid = new Vector3(); - - const uvA = new Vector2(); - const uvB = new Vector2(); - const uvC = new Vector2(); - - for ( let i = 0, j = 0; i < vertexBuffer.length; i += 9, j += 6 ) { - - a.set( vertexBuffer[ i + 0 ], vertexBuffer[ i + 1 ], vertexBuffer[ i + 2 ] ); - b.set( vertexBuffer[ i + 3 ], vertexBuffer[ i + 4 ], vertexBuffer[ i + 5 ] ); - c.set( vertexBuffer[ i + 6 ], vertexBuffer[ i + 7 ], vertexBuffer[ i + 8 ] ); - - uvA.set( uvBuffer[ j + 0 ], uvBuffer[ j + 1 ] ); - uvB.set( uvBuffer[ j + 2 ], uvBuffer[ j + 3 ] ); - uvC.set( uvBuffer[ j + 4 ], uvBuffer[ j + 5 ] ); - - centroid.copy( a ).add( b ).add( c ).divideScalar( 3 ); - - const azi = azimuth( centroid ); - - correctUV( uvA, j + 0, a, azi ); - correctUV( uvB, j + 2, b, azi ); - correctUV( uvC, j + 4, c, azi ); - - } - - } - - function correctUV( uv, stride, vector, azimuth ) { - - if ( ( azimuth < 0 ) && ( uv.x === 1 ) ) { - - uvBuffer[ stride ] = uv.x - 1; - - } - - if ( ( vector.x === 0 ) && ( vector.z === 0 ) ) { - - uvBuffer[ stride ] = azimuth / 2 / Math.PI + 0.5; - - } - - } - - // Angle around the Y axis, counter-clockwise when looking from above. - - function azimuth( vector ) { - - return Math.atan2( vector.z, - vector.x ); - - } - - - // Angle above the XZ plane. - - function inclination( vector ) { - - return Math.atan2( - vector.y, Math.sqrt( ( vector.x * vector.x ) + ( vector.z * vector.z ) ) ); - - } - - } - - copy( source ) { - - super.copy( source ); - - this.parameters = Object.assign( {}, source.parameters ); - - return this; - - } - - static fromJSON( data ) { - - return new PolyhedronGeometry( data.vertices, data.indices, data.radius, data.details ); - - } - -} - -class DodecahedronGeometry extends PolyhedronGeometry { - - constructor( radius = 1, detail = 0 ) { - - const t = ( 1 + Math.sqrt( 5 ) ) / 2; - const r = 1 / t; - - const vertices = [ - - // (±1, ±1, ±1) - - 1, - 1, - 1, - 1, - 1, 1, - - 1, 1, - 1, - 1, 1, 1, - 1, - 1, - 1, 1, - 1, 1, - 1, 1, - 1, 1, 1, 1, - - // (0, ±1/φ, ±φ) - 0, - r, - t, 0, - r, t, - 0, r, - t, 0, r, t, - - // (±1/φ, ±φ, 0) - - r, - t, 0, - r, t, 0, - r, - t, 0, r, t, 0, - - // (±φ, 0, ±1/φ) - - t, 0, - r, t, 0, - r, - - t, 0, r, t, 0, r - ]; - - const indices = [ - 3, 11, 7, 3, 7, 15, 3, 15, 13, - 7, 19, 17, 7, 17, 6, 7, 6, 15, - 17, 4, 8, 17, 8, 10, 17, 10, 6, - 8, 0, 16, 8, 16, 2, 8, 2, 10, - 0, 12, 1, 0, 1, 18, 0, 18, 16, - 6, 10, 2, 6, 2, 13, 6, 13, 15, - 2, 16, 18, 2, 18, 3, 2, 3, 13, - 18, 1, 9, 18, 9, 11, 18, 11, 3, - 4, 14, 12, 4, 12, 0, 4, 0, 8, - 11, 9, 5, 11, 5, 19, 11, 19, 7, - 19, 5, 14, 19, 14, 4, 19, 4, 17, - 1, 12, 14, 1, 14, 5, 1, 5, 9 - ]; - - super( vertices, indices, radius, detail ); - - this.type = 'DodecahedronGeometry'; - - this.parameters = { - radius: radius, - detail: detail - }; - - } - - static fromJSON( data ) { - - return new DodecahedronGeometry( data.radius, data.detail ); - - } - -} - -const _v0 = /*@__PURE__*/ new Vector3(); -const _v1$1 = /*@__PURE__*/ new Vector3(); -const _normal = /*@__PURE__*/ new Vector3(); -const _triangle = /*@__PURE__*/ new Triangle(); - -class EdgesGeometry extends BufferGeometry { - - constructor( geometry = null, thresholdAngle = 1 ) { - - super(); - - this.type = 'EdgesGeometry'; - - this.parameters = { - geometry: geometry, - thresholdAngle: thresholdAngle - }; - - if ( geometry !== null ) { - - const precisionPoints = 4; - const precision = Math.pow( 10, precisionPoints ); - const thresholdDot = Math.cos( DEG2RAD * thresholdAngle ); - - const indexAttr = geometry.getIndex(); - const positionAttr = geometry.getAttribute( 'position' ); - const indexCount = indexAttr ? indexAttr.count : positionAttr.count; - - const indexArr = [ 0, 0, 0 ]; - const vertKeys = [ 'a', 'b', 'c' ]; - const hashes = new Array( 3 ); - - const edgeData = {}; - const vertices = []; - for ( let i = 0; i < indexCount; i += 3 ) { - - if ( indexAttr ) { - - indexArr[ 0 ] = indexAttr.getX( i ); - indexArr[ 1 ] = indexAttr.getX( i + 1 ); - indexArr[ 2 ] = indexAttr.getX( i + 2 ); - - } else { - - indexArr[ 0 ] = i; - indexArr[ 1 ] = i + 1; - indexArr[ 2 ] = i + 2; - - } - - const { a, b, c } = _triangle; - a.fromBufferAttribute( positionAttr, indexArr[ 0 ] ); - b.fromBufferAttribute( positionAttr, indexArr[ 1 ] ); - c.fromBufferAttribute( positionAttr, indexArr[ 2 ] ); - _triangle.getNormal( _normal ); - - // create hashes for the edge from the vertices - hashes[ 0 ] = `${ Math.round( a.x * precision ) },${ Math.round( a.y * precision ) },${ Math.round( a.z * precision ) }`; - hashes[ 1 ] = `${ Math.round( b.x * precision ) },${ Math.round( b.y * precision ) },${ Math.round( b.z * precision ) }`; - hashes[ 2 ] = `${ Math.round( c.x * precision ) },${ Math.round( c.y * precision ) },${ Math.round( c.z * precision ) }`; - - // skip degenerate triangles - if ( hashes[ 0 ] === hashes[ 1 ] || hashes[ 1 ] === hashes[ 2 ] || hashes[ 2 ] === hashes[ 0 ] ) { - - continue; - - } - - // iterate over every edge - for ( let j = 0; j < 3; j ++ ) { - - // get the first and next vertex making up the edge - const jNext = ( j + 1 ) % 3; - const vecHash0 = hashes[ j ]; - const vecHash1 = hashes[ jNext ]; - const v0 = _triangle[ vertKeys[ j ] ]; - const v1 = _triangle[ vertKeys[ jNext ] ]; - - const hash = `${ vecHash0 }_${ vecHash1 }`; - const reverseHash = `${ vecHash1 }_${ vecHash0 }`; - - if ( reverseHash in edgeData && edgeData[ reverseHash ] ) { - - // if we found a sibling edge add it into the vertex array if - // it meets the angle threshold and delete the edge from the map. - if ( _normal.dot( edgeData[ reverseHash ].normal ) <= thresholdDot ) { - - vertices.push( v0.x, v0.y, v0.z ); - vertices.push( v1.x, v1.y, v1.z ); - - } - - edgeData[ reverseHash ] = null; - - } else if ( ! ( hash in edgeData ) ) { - - // if we've already got an edge here then skip adding a new one - edgeData[ hash ] = { - - index0: indexArr[ j ], - index1: indexArr[ jNext ], - normal: _normal.clone(), - - }; - - } - - } - - } - - // iterate over all remaining, unmatched edges and add them to the vertex array - for ( const key in edgeData ) { - - if ( edgeData[ key ] ) { - - const { index0, index1 } = edgeData[ key ]; - _v0.fromBufferAttribute( positionAttr, index0 ); - _v1$1.fromBufferAttribute( positionAttr, index1 ); - - vertices.push( _v0.x, _v0.y, _v0.z ); - vertices.push( _v1$1.x, _v1$1.y, _v1$1.z ); - - } - - } - - this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - - } - - } - - copy( source ) { - - super.copy( source ); - - this.parameters = Object.assign( {}, source.parameters ); - - return this; - - } - -} - -class Shape extends Path { - - constructor( points ) { - - super( points ); - - this.uuid = generateUUID(); - - this.type = 'Shape'; - - this.holes = []; - - } - - getPointsHoles( divisions ) { - - const holesPts = []; - - for ( let i = 0, l = this.holes.length; i < l; i ++ ) { - - holesPts[ i ] = this.holes[ i ].getPoints( divisions ); - - } - - return holesPts; - - } - - // get points of shape and holes (keypoints based on segments parameter) - - extractPoints( divisions ) { - - return { - - shape: this.getPoints( divisions ), - holes: this.getPointsHoles( divisions ) - - }; - - } - - copy( source ) { - - super.copy( source ); - - this.holes = []; - - for ( let i = 0, l = source.holes.length; i < l; i ++ ) { - - const hole = source.holes[ i ]; - - this.holes.push( hole.clone() ); - - } - - return this; - - } - - toJSON() { - - const data = super.toJSON(); - - data.uuid = this.uuid; - data.holes = []; - - for ( let i = 0, l = this.holes.length; i < l; i ++ ) { - - const hole = this.holes[ i ]; - data.holes.push( hole.toJSON() ); - - } - - return data; - - } - - fromJSON( json ) { - - super.fromJSON( json ); - - this.uuid = json.uuid; - this.holes = []; - - for ( let i = 0, l = json.holes.length; i < l; i ++ ) { - - const hole = json.holes[ i ]; - this.holes.push( new Path().fromJSON( hole ) ); - - } - - return this; - - } - -} - -/** - * Port from https://github.com/mapbox/earcut (v2.2.4) - */ - -const Earcut = { - - triangulate: function ( data, holeIndices, dim = 2 ) { - - const hasHoles = holeIndices && holeIndices.length; - const outerLen = hasHoles ? holeIndices[ 0 ] * dim : data.length; - let outerNode = linkedList( data, 0, outerLen, dim, true ); - const triangles = []; - - if ( ! outerNode || outerNode.next === outerNode.prev ) return triangles; - - let minX, minY, maxX, maxY, x, y, invSize; - - if ( hasHoles ) outerNode = eliminateHoles( data, holeIndices, outerNode, dim ); - - // if the shape is not too simple, we'll use z-order curve hash later; calculate polygon bbox - if ( data.length > 80 * dim ) { - - minX = maxX = data[ 0 ]; - minY = maxY = data[ 1 ]; - - for ( let i = dim; i < outerLen; i += dim ) { - - x = data[ i ]; - y = data[ i + 1 ]; - if ( x < minX ) minX = x; - if ( y < minY ) minY = y; - if ( x > maxX ) maxX = x; - if ( y > maxY ) maxY = y; - - } - - // minX, minY and invSize are later used to transform coords into integers for z-order calculation - invSize = Math.max( maxX - minX, maxY - minY ); - invSize = invSize !== 0 ? 32767 / invSize : 0; - - } - - earcutLinked( outerNode, triangles, dim, minX, minY, invSize, 0 ); - - return triangles; - - } - -}; - -// create a circular doubly linked list from polygon points in the specified winding order -function linkedList( data, start, end, dim, clockwise ) { - - let i, last; - - if ( clockwise === ( signedArea( data, start, end, dim ) > 0 ) ) { - - for ( i = start; i < end; i += dim ) last = insertNode( i, data[ i ], data[ i + 1 ], last ); - - } else { - - for ( i = end - dim; i >= start; i -= dim ) last = insertNode( i, data[ i ], data[ i + 1 ], last ); - - } - - if ( last && equals( last, last.next ) ) { - - removeNode( last ); - last = last.next; - - } - - return last; - -} - -// eliminate colinear or duplicate points -function filterPoints( start, end ) { - - if ( ! start ) return start; - if ( ! end ) end = start; - - let p = start, - again; - do { - - again = false; - - if ( ! p.steiner && ( equals( p, p.next ) || area( p.prev, p, p.next ) === 0 ) ) { - - removeNode( p ); - p = end = p.prev; - if ( p === p.next ) break; - again = true; - - } else { - - p = p.next; - - } - - } while ( again || p !== end ); - - return end; - -} - -// main ear slicing loop which triangulates a polygon (given as a linked list) -function earcutLinked( ear, triangles, dim, minX, minY, invSize, pass ) { - - if ( ! ear ) return; - - // interlink polygon nodes in z-order - if ( ! pass && invSize ) indexCurve( ear, minX, minY, invSize ); - - let stop = ear, - prev, next; - - // iterate through ears, slicing them one by one - while ( ear.prev !== ear.next ) { - - prev = ear.prev; - next = ear.next; - - if ( invSize ? isEarHashed( ear, minX, minY, invSize ) : isEar( ear ) ) { - - // cut off the triangle - triangles.push( prev.i / dim | 0 ); - triangles.push( ear.i / dim | 0 ); - triangles.push( next.i / dim | 0 ); - - removeNode( ear ); - - // skipping the next vertex leads to less sliver triangles - ear = next.next; - stop = next.next; - - continue; - - } - - ear = next; - - // if we looped through the whole remaining polygon and can't find any more ears - if ( ear === stop ) { - - // try filtering points and slicing again - if ( ! pass ) { - - earcutLinked( filterPoints( ear ), triangles, dim, minX, minY, invSize, 1 ); - - // if this didn't work, try curing all small self-intersections locally - - } else if ( pass === 1 ) { - - ear = cureLocalIntersections( filterPoints( ear ), triangles, dim ); - earcutLinked( ear, triangles, dim, minX, minY, invSize, 2 ); - - // as a last resort, try splitting the remaining polygon into two - - } else if ( pass === 2 ) { - - splitEarcut( ear, triangles, dim, minX, minY, invSize ); - - } - - break; - - } - - } - -} - -// check whether a polygon node forms a valid ear with adjacent nodes -function isEar( ear ) { - - const a = ear.prev, - b = ear, - c = ear.next; - - if ( area( a, b, c ) >= 0 ) return false; // reflex, can't be an ear - - // now make sure we don't have other points inside the potential ear - const ax = a.x, bx = b.x, cx = c.x, ay = a.y, by = b.y, cy = c.y; - - // triangle bbox; min & max are calculated like this for speed - const x0 = ax < bx ? ( ax < cx ? ax : cx ) : ( bx < cx ? bx : cx ), - y0 = ay < by ? ( ay < cy ? ay : cy ) : ( by < cy ? by : cy ), - x1 = ax > bx ? ( ax > cx ? ax : cx ) : ( bx > cx ? bx : cx ), - y1 = ay > by ? ( ay > cy ? ay : cy ) : ( by > cy ? by : cy ); - - let p = c.next; - while ( p !== a ) { - - if ( p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && - pointInTriangle( ax, ay, bx, by, cx, cy, p.x, p.y ) && - area( p.prev, p, p.next ) >= 0 ) return false; - p = p.next; - - } - - return true; - -} - -function isEarHashed( ear, minX, minY, invSize ) { - - const a = ear.prev, - b = ear, - c = ear.next; - - if ( area( a, b, c ) >= 0 ) return false; // reflex, can't be an ear - - const ax = a.x, bx = b.x, cx = c.x, ay = a.y, by = b.y, cy = c.y; - - // triangle bbox; min & max are calculated like this for speed - const x0 = ax < bx ? ( ax < cx ? ax : cx ) : ( bx < cx ? bx : cx ), - y0 = ay < by ? ( ay < cy ? ay : cy ) : ( by < cy ? by : cy ), - x1 = ax > bx ? ( ax > cx ? ax : cx ) : ( bx > cx ? bx : cx ), - y1 = ay > by ? ( ay > cy ? ay : cy ) : ( by > cy ? by : cy ); - - // z-order range for the current triangle bbox; - const minZ = zOrder( x0, y0, minX, minY, invSize ), - maxZ = zOrder( x1, y1, minX, minY, invSize ); - - let p = ear.prevZ, - n = ear.nextZ; - - // look for points inside the triangle in both directions - while ( p && p.z >= minZ && n && n.z <= maxZ ) { - - if ( p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== a && p !== c && - pointInTriangle( ax, ay, bx, by, cx, cy, p.x, p.y ) && area( p.prev, p, p.next ) >= 0 ) return false; - p = p.prevZ; - - if ( n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a && n !== c && - pointInTriangle( ax, ay, bx, by, cx, cy, n.x, n.y ) && area( n.prev, n, n.next ) >= 0 ) return false; - n = n.nextZ; - - } - - // look for remaining points in decreasing z-order - while ( p && p.z >= minZ ) { - - if ( p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== a && p !== c && - pointInTriangle( ax, ay, bx, by, cx, cy, p.x, p.y ) && area( p.prev, p, p.next ) >= 0 ) return false; - p = p.prevZ; - - } - - // look for remaining points in increasing z-order - while ( n && n.z <= maxZ ) { - - if ( n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a && n !== c && - pointInTriangle( ax, ay, bx, by, cx, cy, n.x, n.y ) && area( n.prev, n, n.next ) >= 0 ) return false; - n = n.nextZ; - - } - - return true; - -} - -// go through all polygon nodes and cure small local self-intersections -function cureLocalIntersections( start, triangles, dim ) { - - let p = start; - do { - - const a = p.prev, - b = p.next.next; - - if ( ! equals( a, b ) && intersects( a, p, p.next, b ) && locallyInside( a, b ) && locallyInside( b, a ) ) { - - triangles.push( a.i / dim | 0 ); - triangles.push( p.i / dim | 0 ); - triangles.push( b.i / dim | 0 ); - - // remove two nodes involved - removeNode( p ); - removeNode( p.next ); - - p = start = b; - - } - - p = p.next; - - } while ( p !== start ); - - return filterPoints( p ); - -} - -// try splitting polygon into two and triangulate them independently -function splitEarcut( start, triangles, dim, minX, minY, invSize ) { - - // look for a valid diagonal that divides the polygon into two - let a = start; - do { - - let b = a.next.next; - while ( b !== a.prev ) { - - if ( a.i !== b.i && isValidDiagonal( a, b ) ) { - - // split the polygon in two by the diagonal - let c = splitPolygon( a, b ); - - // filter colinear points around the cuts - a = filterPoints( a, a.next ); - c = filterPoints( c, c.next ); - - // run earcut on each half - earcutLinked( a, triangles, dim, minX, minY, invSize, 0 ); - earcutLinked( c, triangles, dim, minX, minY, invSize, 0 ); - return; - - } - - b = b.next; - - } - - a = a.next; - - } while ( a !== start ); - -} - -// link every hole into the outer loop, producing a single-ring polygon without holes -function eliminateHoles( data, holeIndices, outerNode, dim ) { - - const queue = []; - let i, len, start, end, list; - - for ( i = 0, len = holeIndices.length; i < len; i ++ ) { - - start = holeIndices[ i ] * dim; - end = i < len - 1 ? holeIndices[ i + 1 ] * dim : data.length; - list = linkedList( data, start, end, dim, false ); - if ( list === list.next ) list.steiner = true; - queue.push( getLeftmost( list ) ); - - } - - queue.sort( compareX ); - - // process holes from left to right - for ( i = 0; i < queue.length; i ++ ) { - - outerNode = eliminateHole( queue[ i ], outerNode ); - - } - - return outerNode; - -} - -function compareX( a, b ) { - - return a.x - b.x; - -} - -// find a bridge between vertices that connects hole with an outer ring and link it -function eliminateHole( hole, outerNode ) { - - const bridge = findHoleBridge( hole, outerNode ); - if ( ! bridge ) { - - return outerNode; - - } - - const bridgeReverse = splitPolygon( bridge, hole ); - - // filter collinear points around the cuts - filterPoints( bridgeReverse, bridgeReverse.next ); - return filterPoints( bridge, bridge.next ); - -} - -// David Eberly's algorithm for finding a bridge between hole and outer polygon -function findHoleBridge( hole, outerNode ) { - - let p = outerNode, - qx = - Infinity, - m; - - const hx = hole.x, hy = hole.y; - - // find a segment intersected by a ray from the hole's leftmost point to the left; - // segment's endpoint with lesser x will be potential connection point - do { - - if ( hy <= p.y && hy >= p.next.y && p.next.y !== p.y ) { - - const x = p.x + ( hy - p.y ) * ( p.next.x - p.x ) / ( p.next.y - p.y ); - if ( x <= hx && x > qx ) { - - qx = x; - m = p.x < p.next.x ? p : p.next; - if ( x === hx ) return m; // hole touches outer segment; pick leftmost endpoint - - } - - } - - p = p.next; - - } while ( p !== outerNode ); - - if ( ! m ) return null; - - // look for points inside the triangle of hole point, segment intersection and endpoint; - // if there are no points found, we have a valid connection; - // otherwise choose the point of the minimum angle with the ray as connection point - - const stop = m, - mx = m.x, - my = m.y; - let tanMin = Infinity, tan; - - p = m; - - do { - - if ( hx >= p.x && p.x >= mx && hx !== p.x && - pointInTriangle( hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p.x, p.y ) ) { - - tan = Math.abs( hy - p.y ) / ( hx - p.x ); // tangential - - if ( locallyInside( p, hole ) && ( tan < tanMin || ( tan === tanMin && ( p.x > m.x || ( p.x === m.x && sectorContainsSector( m, p ) ) ) ) ) ) { - - m = p; - tanMin = tan; - - } - - } - - p = p.next; - - } while ( p !== stop ); - - return m; - -} - -// whether sector in vertex m contains sector in vertex p in the same coordinates -function sectorContainsSector( m, p ) { - - return area( m.prev, m, p.prev ) < 0 && area( p.next, m, m.next ) < 0; - -} - -// interlink polygon nodes in z-order -function indexCurve( start, minX, minY, invSize ) { - - let p = start; - do { - - if ( p.z === 0 ) p.z = zOrder( p.x, p.y, minX, minY, invSize ); - p.prevZ = p.prev; - p.nextZ = p.next; - p = p.next; - - } while ( p !== start ); - - p.prevZ.nextZ = null; - p.prevZ = null; - - sortLinked( p ); - -} - -// Simon Tatham's linked list merge sort algorithm -// http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html -function sortLinked( list ) { - - let i, p, q, e, tail, numMerges, pSize, qSize, - inSize = 1; - - do { - - p = list; - list = null; - tail = null; - numMerges = 0; - - while ( p ) { - - numMerges ++; - q = p; - pSize = 0; - for ( i = 0; i < inSize; i ++ ) { - - pSize ++; - q = q.nextZ; - if ( ! q ) break; - - } - - qSize = inSize; - - while ( pSize > 0 || ( qSize > 0 && q ) ) { - - if ( pSize !== 0 && ( qSize === 0 || ! q || p.z <= q.z ) ) { - - e = p; - p = p.nextZ; - pSize --; - - } else { - - e = q; - q = q.nextZ; - qSize --; - - } - - if ( tail ) tail.nextZ = e; - else list = e; - - e.prevZ = tail; - tail = e; - - } - - p = q; - - } - - tail.nextZ = null; - inSize *= 2; - - } while ( numMerges > 1 ); - - return list; - -} - -// z-order of a point given coords and inverse of the longer side of data bbox -function zOrder( x, y, minX, minY, invSize ) { - - // coords are transformed into non-negative 15-bit integer range - x = ( x - minX ) * invSize | 0; - y = ( y - minY ) * invSize | 0; - - x = ( x | ( x << 8 ) ) & 0x00FF00FF; - x = ( x | ( x << 4 ) ) & 0x0F0F0F0F; - x = ( x | ( x << 2 ) ) & 0x33333333; - x = ( x | ( x << 1 ) ) & 0x55555555; - - y = ( y | ( y << 8 ) ) & 0x00FF00FF; - y = ( y | ( y << 4 ) ) & 0x0F0F0F0F; - y = ( y | ( y << 2 ) ) & 0x33333333; - y = ( y | ( y << 1 ) ) & 0x55555555; - - return x | ( y << 1 ); - -} - -// find the leftmost node of a polygon ring -function getLeftmost( start ) { - - let p = start, - leftmost = start; - do { - - if ( p.x < leftmost.x || ( p.x === leftmost.x && p.y < leftmost.y ) ) leftmost = p; - p = p.next; - - } while ( p !== start ); - - return leftmost; - -} - -// check if a point lies within a convex triangle -function pointInTriangle( ax, ay, bx, by, cx, cy, px, py ) { - - return ( cx - px ) * ( ay - py ) >= ( ax - px ) * ( cy - py ) && - ( ax - px ) * ( by - py ) >= ( bx - px ) * ( ay - py ) && - ( bx - px ) * ( cy - py ) >= ( cx - px ) * ( by - py ); - -} - -// check if a diagonal between two polygon nodes is valid (lies in polygon interior) -function isValidDiagonal( a, b ) { - - return a.next.i !== b.i && a.prev.i !== b.i && ! intersectsPolygon( a, b ) && // dones't intersect other edges - ( locallyInside( a, b ) && locallyInside( b, a ) && middleInside( a, b ) && // locally visible - ( area( a.prev, a, b.prev ) || area( a, b.prev, b ) ) || // does not create opposite-facing sectors - equals( a, b ) && area( a.prev, a, a.next ) > 0 && area( b.prev, b, b.next ) > 0 ); // special zero-length case - -} - -// signed area of a triangle -function area( p, q, r ) { - - return ( q.y - p.y ) * ( r.x - q.x ) - ( q.x - p.x ) * ( r.y - q.y ); - -} - -// check if two points are equal -function equals( p1, p2 ) { - - return p1.x === p2.x && p1.y === p2.y; - -} - -// check if two segments intersect -function intersects( p1, q1, p2, q2 ) { - - const o1 = sign( area( p1, q1, p2 ) ); - const o2 = sign( area( p1, q1, q2 ) ); - const o3 = sign( area( p2, q2, p1 ) ); - const o4 = sign( area( p2, q2, q1 ) ); - - if ( o1 !== o2 && o3 !== o4 ) return true; // general case - - if ( o1 === 0 && onSegment( p1, p2, q1 ) ) return true; // p1, q1 and p2 are collinear and p2 lies on p1q1 - if ( o2 === 0 && onSegment( p1, q2, q1 ) ) return true; // p1, q1 and q2 are collinear and q2 lies on p1q1 - if ( o3 === 0 && onSegment( p2, p1, q2 ) ) return true; // p2, q2 and p1 are collinear and p1 lies on p2q2 - if ( o4 === 0 && onSegment( p2, q1, q2 ) ) return true; // p2, q2 and q1 are collinear and q1 lies on p2q2 - - return false; - -} - -// for collinear points p, q, r, check if point q lies on segment pr -function onSegment( p, q, r ) { - - return q.x <= Math.max( p.x, r.x ) && q.x >= Math.min( p.x, r.x ) && q.y <= Math.max( p.y, r.y ) && q.y >= Math.min( p.y, r.y ); - -} - -function sign( num ) { - - return num > 0 ? 1 : num < 0 ? - 1 : 0; - -} - -// check if a polygon diagonal intersects any polygon segments -function intersectsPolygon( a, b ) { - - let p = a; - do { - - if ( p.i !== a.i && p.next.i !== a.i && p.i !== b.i && p.next.i !== b.i && - intersects( p, p.next, a, b ) ) return true; - p = p.next; - - } while ( p !== a ); - - return false; - -} - -// check if a polygon diagonal is locally inside the polygon -function locallyInside( a, b ) { - - return area( a.prev, a, a.next ) < 0 ? - area( a, b, a.next ) >= 0 && area( a, a.prev, b ) >= 0 : - area( a, b, a.prev ) < 0 || area( a, a.next, b ) < 0; - -} - -// check if the middle point of a polygon diagonal is inside the polygon -function middleInside( a, b ) { - - let p = a, - inside = false; - const px = ( a.x + b.x ) / 2, - py = ( a.y + b.y ) / 2; - do { - - if ( ( ( p.y > py ) !== ( p.next.y > py ) ) && p.next.y !== p.y && - ( px < ( p.next.x - p.x ) * ( py - p.y ) / ( p.next.y - p.y ) + p.x ) ) - inside = ! inside; - p = p.next; - - } while ( p !== a ); - - return inside; - -} - -// link two polygon vertices with a bridge; if the vertices belong to the same ring, it splits polygon into two; -// if one belongs to the outer ring and another to a hole, it merges it into a single ring -function splitPolygon( a, b ) { - - const a2 = new Node( a.i, a.x, a.y ), - b2 = new Node( b.i, b.x, b.y ), - an = a.next, - bp = b.prev; - - a.next = b; - b.prev = a; - - a2.next = an; - an.prev = a2; - - b2.next = a2; - a2.prev = b2; - - bp.next = b2; - b2.prev = bp; - - return b2; - -} - -// create a node and optionally link it with previous one (in a circular doubly linked list) -function insertNode( i, x, y, last ) { - - const p = new Node( i, x, y ); - - if ( ! last ) { - - p.prev = p; - p.next = p; - - } else { - - p.next = last.next; - p.prev = last; - last.next.prev = p; - last.next = p; - - } - - return p; - -} - -function removeNode( p ) { - - p.next.prev = p.prev; - p.prev.next = p.next; - - if ( p.prevZ ) p.prevZ.nextZ = p.nextZ; - if ( p.nextZ ) p.nextZ.prevZ = p.prevZ; - -} - -function Node( i, x, y ) { - - // vertex index in coordinates array - this.i = i; - - // vertex coordinates - this.x = x; - this.y = y; - - // previous and next vertex nodes in a polygon ring - this.prev = null; - this.next = null; - - // z-order curve value - this.z = 0; - - // previous and next nodes in z-order - this.prevZ = null; - this.nextZ = null; - - // indicates whether this is a steiner point - this.steiner = false; - -} - -function signedArea( data, start, end, dim ) { - - let sum = 0; - for ( let i = start, j = end - dim; i < end; i += dim ) { - - sum += ( data[ j ] - data[ i ] ) * ( data[ i + 1 ] + data[ j + 1 ] ); - j = i; - - } - - return sum; - -} - -class ShapeUtils { - - // calculate area of the contour polygon - - static area( contour ) { - - const n = contour.length; - let a = 0.0; - - for ( let p = n - 1, q = 0; q < n; p = q ++ ) { - - a += contour[ p ].x * contour[ q ].y - contour[ q ].x * contour[ p ].y; - - } - - return a * 0.5; - - } - - static isClockWise( pts ) { - - return ShapeUtils.area( pts ) < 0; - - } - - static triangulateShape( contour, holes ) { - - const vertices = []; // flat array of vertices like [ x0,y0, x1,y1, x2,y2, ... ] - const holeIndices = []; // array of hole indices - const faces = []; // final array of vertex indices like [ [ a,b,d ], [ b,c,d ] ] - - removeDupEndPts( contour ); - addContour( vertices, contour ); - - // - - let holeIndex = contour.length; - - holes.forEach( removeDupEndPts ); - - for ( let i = 0; i < holes.length; i ++ ) { - - holeIndices.push( holeIndex ); - holeIndex += holes[ i ].length; - addContour( vertices, holes[ i ] ); - - } - - // - - const triangles = Earcut.triangulate( vertices, holeIndices ); - - // - - for ( let i = 0; i < triangles.length; i += 3 ) { - - faces.push( triangles.slice( i, i + 3 ) ); - - } - - return faces; - - } - -} - -function removeDupEndPts( points ) { - - const l = points.length; - - if ( l > 2 && points[ l - 1 ].equals( points[ 0 ] ) ) { - - points.pop(); - - } - -} - -function addContour( vertices, contour ) { - - for ( let i = 0; i < contour.length; i ++ ) { - - vertices.push( contour[ i ].x ); - vertices.push( contour[ i ].y ); - - } - -} - -/** - * Creates extruded geometry from a path shape. - * - * parameters = { - * - * curveSegments: , // number of points on the curves - * steps: , // number of points for z-side extrusions / used for subdividing segments of extrude spline too - * depth: , // Depth to extrude the shape - * - * bevelEnabled: , // turn on bevel - * bevelThickness: , // how deep into the original shape bevel goes - * bevelSize: , // how far from shape outline (including bevelOffset) is bevel - * bevelOffset: , // how far from shape outline does bevel start - * bevelSegments: , // number of bevel layers - * - * extrudePath: // curve to extrude shape along - * - * UVGenerator: // object that provides UV generator functions - * - * } - */ - - -class ExtrudeGeometry extends BufferGeometry { - - constructor( shapes = new Shape( [ new Vector2( 0.5, 0.5 ), new Vector2( - 0.5, 0.5 ), new Vector2( - 0.5, - 0.5 ), new Vector2( 0.5, - 0.5 ) ] ), options = {} ) { - - super(); - - this.type = 'ExtrudeGeometry'; - - this.parameters = { - shapes: shapes, - options: options - }; - - shapes = Array.isArray( shapes ) ? shapes : [ shapes ]; - - const scope = this; - - const verticesArray = []; - const uvArray = []; - - for ( let i = 0, l = shapes.length; i < l; i ++ ) { - - const shape = shapes[ i ]; - addShape( shape ); - - } - - // build geometry - - this.setAttribute( 'position', new Float32BufferAttribute( verticesArray, 3 ) ); - this.setAttribute( 'uv', new Float32BufferAttribute( uvArray, 2 ) ); - - this.computeVertexNormals(); - - // functions - - function addShape( shape ) { - - const placeholder = []; - - // options - - const curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12; - const steps = options.steps !== undefined ? options.steps : 1; - const depth = options.depth !== undefined ? options.depth : 1; - - let bevelEnabled = options.bevelEnabled !== undefined ? options.bevelEnabled : true; - let bevelThickness = options.bevelThickness !== undefined ? options.bevelThickness : 0.2; - let bevelSize = options.bevelSize !== undefined ? options.bevelSize : bevelThickness - 0.1; - let bevelOffset = options.bevelOffset !== undefined ? options.bevelOffset : 0; - let bevelSegments = options.bevelSegments !== undefined ? options.bevelSegments : 3; - - const extrudePath = options.extrudePath; - - const uvgen = options.UVGenerator !== undefined ? options.UVGenerator : WorldUVGenerator; - - // - - let extrudePts, extrudeByPath = false; - let splineTube, binormal, normal, position2; - - if ( extrudePath ) { - - extrudePts = extrudePath.getSpacedPoints( steps ); - - extrudeByPath = true; - bevelEnabled = false; // bevels not supported for path extrusion - - // SETUP TNB variables - - // TODO1 - have a .isClosed in spline? - - splineTube = extrudePath.computeFrenetFrames( steps, false ); - - // console.log(splineTube, 'splineTube', splineTube.normals.length, 'steps', steps, 'extrudePts', extrudePts.length); - - binormal = new Vector3(); - normal = new Vector3(); - position2 = new Vector3(); - - } - - // Safeguards if bevels are not enabled - - if ( ! bevelEnabled ) { - - bevelSegments = 0; - bevelThickness = 0; - bevelSize = 0; - bevelOffset = 0; - - } - - // Variables initialization - - const shapePoints = shape.extractPoints( curveSegments ); - - let vertices = shapePoints.shape; - const holes = shapePoints.holes; - - const reverse = ! ShapeUtils.isClockWise( vertices ); - - if ( reverse ) { - - vertices = vertices.reverse(); - - // Maybe we should also check if holes are in the opposite direction, just to be safe ... - - for ( let h = 0, hl = holes.length; h < hl; h ++ ) { - - const ahole = holes[ h ]; - - if ( ShapeUtils.isClockWise( ahole ) ) { - - holes[ h ] = ahole.reverse(); - - } - - } - - } - - - const faces = ShapeUtils.triangulateShape( vertices, holes ); - - /* Vertices */ - - const contour = vertices; // vertices has all points but contour has only points of circumference - - for ( let h = 0, hl = holes.length; h < hl; h ++ ) { - - const ahole = holes[ h ]; - - vertices = vertices.concat( ahole ); - - } - - - function scalePt2( pt, vec, size ) { - - if ( ! vec ) console.error( 'THREE.ExtrudeGeometry: vec does not exist' ); - - return pt.clone().addScaledVector( vec, size ); - - } - - const vlen = vertices.length, flen = faces.length; - - - // Find directions for point movement - - - function getBevelVec( inPt, inPrev, inNext ) { - - // computes for inPt the corresponding point inPt' on a new contour - // shifted by 1 unit (length of normalized vector) to the left - // if we walk along contour clockwise, this new contour is outside the old one - // - // inPt' is the intersection of the two lines parallel to the two - // adjacent edges of inPt at a distance of 1 unit on the left side. - - let v_trans_x, v_trans_y, shrink_by; // resulting translation vector for inPt - - // good reading for geometry algorithms (here: line-line intersection) - // http://geomalgorithms.com/a05-_intersect-1.html - - const v_prev_x = inPt.x - inPrev.x, - v_prev_y = inPt.y - inPrev.y; - const v_next_x = inNext.x - inPt.x, - v_next_y = inNext.y - inPt.y; - - const v_prev_lensq = ( v_prev_x * v_prev_x + v_prev_y * v_prev_y ); - - // check for collinear edges - const collinear0 = ( v_prev_x * v_next_y - v_prev_y * v_next_x ); - - if ( Math.abs( collinear0 ) > Number.EPSILON ) { - - // not collinear - - // length of vectors for normalizing - - const v_prev_len = Math.sqrt( v_prev_lensq ); - const v_next_len = Math.sqrt( v_next_x * v_next_x + v_next_y * v_next_y ); - - // shift adjacent points by unit vectors to the left - - const ptPrevShift_x = ( inPrev.x - v_prev_y / v_prev_len ); - const ptPrevShift_y = ( inPrev.y + v_prev_x / v_prev_len ); - - const ptNextShift_x = ( inNext.x - v_next_y / v_next_len ); - const ptNextShift_y = ( inNext.y + v_next_x / v_next_len ); - - // scaling factor for v_prev to intersection point - - const sf = ( ( ptNextShift_x - ptPrevShift_x ) * v_next_y - - ( ptNextShift_y - ptPrevShift_y ) * v_next_x ) / - ( v_prev_x * v_next_y - v_prev_y * v_next_x ); - - // vector from inPt to intersection point - - v_trans_x = ( ptPrevShift_x + v_prev_x * sf - inPt.x ); - v_trans_y = ( ptPrevShift_y + v_prev_y * sf - inPt.y ); - - // Don't normalize!, otherwise sharp corners become ugly - // but prevent crazy spikes - const v_trans_lensq = ( v_trans_x * v_trans_x + v_trans_y * v_trans_y ); - if ( v_trans_lensq <= 2 ) { - - return new Vector2( v_trans_x, v_trans_y ); - - } else { - - shrink_by = Math.sqrt( v_trans_lensq / 2 ); - - } - - } else { - - // handle special case of collinear edges - - let direction_eq = false; // assumes: opposite - - if ( v_prev_x > Number.EPSILON ) { - - if ( v_next_x > Number.EPSILON ) { - - direction_eq = true; - - } - - } else { - - if ( v_prev_x < - Number.EPSILON ) { - - if ( v_next_x < - Number.EPSILON ) { - - direction_eq = true; - - } - - } else { - - if ( Math.sign( v_prev_y ) === Math.sign( v_next_y ) ) { - - direction_eq = true; - - } - - } - - } - - if ( direction_eq ) { - - // console.log("Warning: lines are a straight sequence"); - v_trans_x = - v_prev_y; - v_trans_y = v_prev_x; - shrink_by = Math.sqrt( v_prev_lensq ); - - } else { - - // console.log("Warning: lines are a straight spike"); - v_trans_x = v_prev_x; - v_trans_y = v_prev_y; - shrink_by = Math.sqrt( v_prev_lensq / 2 ); - - } - - } - - return new Vector2( v_trans_x / shrink_by, v_trans_y / shrink_by ); - - } - - - const contourMovements = []; - - for ( let i = 0, il = contour.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) { - - if ( j === il ) j = 0; - if ( k === il ) k = 0; - - // (j)---(i)---(k) - // console.log('i,j,k', i, j , k) - - contourMovements[ i ] = getBevelVec( contour[ i ], contour[ j ], contour[ k ] ); - - } - - const holesMovements = []; - let oneHoleMovements, verticesMovements = contourMovements.concat(); - - for ( let h = 0, hl = holes.length; h < hl; h ++ ) { - - const ahole = holes[ h ]; - - oneHoleMovements = []; - - for ( let i = 0, il = ahole.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) { - - if ( j === il ) j = 0; - if ( k === il ) k = 0; - - // (j)---(i)---(k) - oneHoleMovements[ i ] = getBevelVec( ahole[ i ], ahole[ j ], ahole[ k ] ); - - } - - holesMovements.push( oneHoleMovements ); - verticesMovements = verticesMovements.concat( oneHoleMovements ); - - } - - - // Loop bevelSegments, 1 for the front, 1 for the back - - for ( let b = 0; b < bevelSegments; b ++ ) { - - //for ( b = bevelSegments; b > 0; b -- ) { - - const t = b / bevelSegments; - const z = bevelThickness * Math.cos( t * Math.PI / 2 ); - const bs = bevelSize * Math.sin( t * Math.PI / 2 ) + bevelOffset; - - // contract shape - - for ( let i = 0, il = contour.length; i < il; i ++ ) { - - const vert = scalePt2( contour[ i ], contourMovements[ i ], bs ); - - v( vert.x, vert.y, - z ); - - } - - // expand holes - - for ( let h = 0, hl = holes.length; h < hl; h ++ ) { - - const ahole = holes[ h ]; - oneHoleMovements = holesMovements[ h ]; - - for ( let i = 0, il = ahole.length; i < il; i ++ ) { - - const vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs ); - - v( vert.x, vert.y, - z ); - - } - - } - - } - - const bs = bevelSize + bevelOffset; - - // Back facing vertices - - for ( let i = 0; i < vlen; i ++ ) { - - const vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ]; - - if ( ! extrudeByPath ) { - - v( vert.x, vert.y, 0 ); - - } else { - - // v( vert.x, vert.y + extrudePts[ 0 ].y, extrudePts[ 0 ].x ); - - normal.copy( splineTube.normals[ 0 ] ).multiplyScalar( vert.x ); - binormal.copy( splineTube.binormals[ 0 ] ).multiplyScalar( vert.y ); - - position2.copy( extrudePts[ 0 ] ).add( normal ).add( binormal ); - - v( position2.x, position2.y, position2.z ); - - } - - } - - // Add stepped vertices... - // Including front facing vertices - - for ( let s = 1; s <= steps; s ++ ) { - - for ( let i = 0; i < vlen; i ++ ) { - - const vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ]; - - if ( ! extrudeByPath ) { - - v( vert.x, vert.y, depth / steps * s ); - - } else { - - // v( vert.x, vert.y + extrudePts[ s - 1 ].y, extrudePts[ s - 1 ].x ); - - normal.copy( splineTube.normals[ s ] ).multiplyScalar( vert.x ); - binormal.copy( splineTube.binormals[ s ] ).multiplyScalar( vert.y ); - - position2.copy( extrudePts[ s ] ).add( normal ).add( binormal ); - - v( position2.x, position2.y, position2.z ); - - } - - } - - } - - - // Add bevel segments planes - - //for ( b = 1; b <= bevelSegments; b ++ ) { - for ( let b = bevelSegments - 1; b >= 0; b -- ) { - - const t = b / bevelSegments; - const z = bevelThickness * Math.cos( t * Math.PI / 2 ); - const bs = bevelSize * Math.sin( t * Math.PI / 2 ) + bevelOffset; - - // contract shape - - for ( let i = 0, il = contour.length; i < il; i ++ ) { - - const vert = scalePt2( contour[ i ], contourMovements[ i ], bs ); - v( vert.x, vert.y, depth + z ); - - } - - // expand holes - - for ( let h = 0, hl = holes.length; h < hl; h ++ ) { - - const ahole = holes[ h ]; - oneHoleMovements = holesMovements[ h ]; - - for ( let i = 0, il = ahole.length; i < il; i ++ ) { - - const vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs ); - - if ( ! extrudeByPath ) { - - v( vert.x, vert.y, depth + z ); - - } else { - - v( vert.x, vert.y + extrudePts[ steps - 1 ].y, extrudePts[ steps - 1 ].x + z ); - - } - - } - - } - - } - - /* Faces */ - - // Top and bottom faces - - buildLidFaces(); - - // Sides faces - - buildSideFaces(); - - - ///// Internal functions - - function buildLidFaces() { - - const start = verticesArray.length / 3; - - if ( bevelEnabled ) { - - let layer = 0; // steps + 1 - let offset = vlen * layer; - - // Bottom faces - - for ( let i = 0; i < flen; i ++ ) { - - const face = faces[ i ]; - f3( face[ 2 ] + offset, face[ 1 ] + offset, face[ 0 ] + offset ); - - } - - layer = steps + bevelSegments * 2; - offset = vlen * layer; - - // Top faces - - for ( let i = 0; i < flen; i ++ ) { - - const face = faces[ i ]; - f3( face[ 0 ] + offset, face[ 1 ] + offset, face[ 2 ] + offset ); - - } - - } else { - - // Bottom faces - - for ( let i = 0; i < flen; i ++ ) { - - const face = faces[ i ]; - f3( face[ 2 ], face[ 1 ], face[ 0 ] ); - - } - - // Top faces - - for ( let i = 0; i < flen; i ++ ) { - - const face = faces[ i ]; - f3( face[ 0 ] + vlen * steps, face[ 1 ] + vlen * steps, face[ 2 ] + vlen * steps ); - - } - - } - - scope.addGroup( start, verticesArray.length / 3 - start, 0 ); - - } - - // Create faces for the z-sides of the shape - - function buildSideFaces() { - - const start = verticesArray.length / 3; - let layeroffset = 0; - sidewalls( contour, layeroffset ); - layeroffset += contour.length; - - for ( let h = 0, hl = holes.length; h < hl; h ++ ) { - - const ahole = holes[ h ]; - sidewalls( ahole, layeroffset ); - - //, true - layeroffset += ahole.length; - - } - - - scope.addGroup( start, verticesArray.length / 3 - start, 1 ); - - - } - - function sidewalls( contour, layeroffset ) { - - let i = contour.length; - - while ( -- i >= 0 ) { - - const j = i; - let k = i - 1; - if ( k < 0 ) k = contour.length - 1; - - //console.log('b', i,j, i-1, k,vertices.length); - - for ( let s = 0, sl = ( steps + bevelSegments * 2 ); s < sl; s ++ ) { - - const slen1 = vlen * s; - const slen2 = vlen * ( s + 1 ); - - const a = layeroffset + j + slen1, - b = layeroffset + k + slen1, - c = layeroffset + k + slen2, - d = layeroffset + j + slen2; - - f4( a, b, c, d ); - - } - - } - - } - - function v( x, y, z ) { - - placeholder.push( x ); - placeholder.push( y ); - placeholder.push( z ); - - } - - - function f3( a, b, c ) { - - addVertex( a ); - addVertex( b ); - addVertex( c ); - - const nextIndex = verticesArray.length / 3; - const uvs = uvgen.generateTopUV( scope, verticesArray, nextIndex - 3, nextIndex - 2, nextIndex - 1 ); - - addUV( uvs[ 0 ] ); - addUV( uvs[ 1 ] ); - addUV( uvs[ 2 ] ); - - } - - function f4( a, b, c, d ) { - - addVertex( a ); - addVertex( b ); - addVertex( d ); - - addVertex( b ); - addVertex( c ); - addVertex( d ); - - - const nextIndex = verticesArray.length / 3; - const uvs = uvgen.generateSideWallUV( scope, verticesArray, nextIndex - 6, nextIndex - 3, nextIndex - 2, nextIndex - 1 ); - - addUV( uvs[ 0 ] ); - addUV( uvs[ 1 ] ); - addUV( uvs[ 3 ] ); - - addUV( uvs[ 1 ] ); - addUV( uvs[ 2 ] ); - addUV( uvs[ 3 ] ); - - } - - function addVertex( index ) { - - verticesArray.push( placeholder[ index * 3 + 0 ] ); - verticesArray.push( placeholder[ index * 3 + 1 ] ); - verticesArray.push( placeholder[ index * 3 + 2 ] ); - - } - - - function addUV( vector2 ) { - - uvArray.push( vector2.x ); - uvArray.push( vector2.y ); - - } - - } - - } - - copy( source ) { - - super.copy( source ); - - this.parameters = Object.assign( {}, source.parameters ); - - return this; - - } - - toJSON() { - - const data = super.toJSON(); - - const shapes = this.parameters.shapes; - const options = this.parameters.options; - - return toJSON$1( shapes, options, data ); - - } - - static fromJSON( data, shapes ) { - - const geometryShapes = []; - - for ( let j = 0, jl = data.shapes.length; j < jl; j ++ ) { - - const shape = shapes[ data.shapes[ j ] ]; - - geometryShapes.push( shape ); - - } - - const extrudePath = data.options.extrudePath; - - if ( extrudePath !== undefined ) { - - data.options.extrudePath = new Curves[ extrudePath.type ]().fromJSON( extrudePath ); - - } - - return new ExtrudeGeometry( geometryShapes, data.options ); - - } - -} - -const WorldUVGenerator = { - - generateTopUV: function ( geometry, vertices, indexA, indexB, indexC ) { - - const a_x = vertices[ indexA * 3 ]; - const a_y = vertices[ indexA * 3 + 1 ]; - const b_x = vertices[ indexB * 3 ]; - const b_y = vertices[ indexB * 3 + 1 ]; - const c_x = vertices[ indexC * 3 ]; - const c_y = vertices[ indexC * 3 + 1 ]; - - return [ - new Vector2( a_x, a_y ), - new Vector2( b_x, b_y ), - new Vector2( c_x, c_y ) - ]; - - }, - - generateSideWallUV: function ( geometry, vertices, indexA, indexB, indexC, indexD ) { - - const a_x = vertices[ indexA * 3 ]; - const a_y = vertices[ indexA * 3 + 1 ]; - const a_z = vertices[ indexA * 3 + 2 ]; - const b_x = vertices[ indexB * 3 ]; - const b_y = vertices[ indexB * 3 + 1 ]; - const b_z = vertices[ indexB * 3 + 2 ]; - const c_x = vertices[ indexC * 3 ]; - const c_y = vertices[ indexC * 3 + 1 ]; - const c_z = vertices[ indexC * 3 + 2 ]; - const d_x = vertices[ indexD * 3 ]; - const d_y = vertices[ indexD * 3 + 1 ]; - const d_z = vertices[ indexD * 3 + 2 ]; - - if ( Math.abs( a_y - b_y ) < Math.abs( a_x - b_x ) ) { - - return [ - new Vector2( a_x, 1 - a_z ), - new Vector2( b_x, 1 - b_z ), - new Vector2( c_x, 1 - c_z ), - new Vector2( d_x, 1 - d_z ) - ]; - - } else { - - return [ - new Vector2( a_y, 1 - a_z ), - new Vector2( b_y, 1 - b_z ), - new Vector2( c_y, 1 - c_z ), - new Vector2( d_y, 1 - d_z ) - ]; - - } - - } - -}; - -function toJSON$1( shapes, options, data ) { - - data.shapes = []; - - if ( Array.isArray( shapes ) ) { - - for ( let i = 0, l = shapes.length; i < l; i ++ ) { - - const shape = shapes[ i ]; - - data.shapes.push( shape.uuid ); - - } - - } else { - - data.shapes.push( shapes.uuid ); - - } - - data.options = Object.assign( {}, options ); - - if ( options.extrudePath !== undefined ) data.options.extrudePath = options.extrudePath.toJSON(); - - return data; - -} - -class IcosahedronGeometry extends PolyhedronGeometry { - - constructor( radius = 1, detail = 0 ) { - - const t = ( 1 + Math.sqrt( 5 ) ) / 2; - - const vertices = [ - - 1, t, 0, 1, t, 0, - 1, - t, 0, 1, - t, 0, - 0, - 1, t, 0, 1, t, 0, - 1, - t, 0, 1, - t, - t, 0, - 1, t, 0, 1, - t, 0, - 1, - t, 0, 1 - ]; - - const indices = [ - 0, 11, 5, 0, 5, 1, 0, 1, 7, 0, 7, 10, 0, 10, 11, - 1, 5, 9, 5, 11, 4, 11, 10, 2, 10, 7, 6, 7, 1, 8, - 3, 9, 4, 3, 4, 2, 3, 2, 6, 3, 6, 8, 3, 8, 9, - 4, 9, 5, 2, 4, 11, 6, 2, 10, 8, 6, 7, 9, 8, 1 - ]; - - super( vertices, indices, radius, detail ); - - this.type = 'IcosahedronGeometry'; - - this.parameters = { - radius: radius, - detail: detail - }; - - } - - static fromJSON( data ) { - - return new IcosahedronGeometry( data.radius, data.detail ); - - } - -} - -class OctahedronGeometry extends PolyhedronGeometry { - - constructor( radius = 1, detail = 0 ) { - - const vertices = [ - 1, 0, 0, - 1, 0, 0, 0, 1, 0, - 0, - 1, 0, 0, 0, 1, 0, 0, - 1 - ]; - - const indices = [ - 0, 2, 4, 0, 4, 3, 0, 3, 5, - 0, 5, 2, 1, 2, 5, 1, 5, 3, - 1, 3, 4, 1, 4, 2 - ]; - - super( vertices, indices, radius, detail ); - - this.type = 'OctahedronGeometry'; - - this.parameters = { - radius: radius, - detail: detail - }; - - } - - static fromJSON( data ) { - - return new OctahedronGeometry( data.radius, data.detail ); - - } - -} - -class RingGeometry extends BufferGeometry { - - constructor( innerRadius = 0.5, outerRadius = 1, thetaSegments = 32, phiSegments = 1, thetaStart = 0, thetaLength = Math.PI * 2 ) { - - super(); - - this.type = 'RingGeometry'; - - this.parameters = { - innerRadius: innerRadius, - outerRadius: outerRadius, - thetaSegments: thetaSegments, - phiSegments: phiSegments, - thetaStart: thetaStart, - thetaLength: thetaLength - }; - - thetaSegments = Math.max( 3, thetaSegments ); - phiSegments = Math.max( 1, phiSegments ); - - // buffers - - const indices = []; - const vertices = []; - const normals = []; - const uvs = []; - - // some helper variables - - let radius = innerRadius; - const radiusStep = ( ( outerRadius - innerRadius ) / phiSegments ); - const vertex = new Vector3(); - const uv = new Vector2(); - - // generate vertices, normals and uvs - - for ( let j = 0; j <= phiSegments; j ++ ) { - - for ( let i = 0; i <= thetaSegments; i ++ ) { - - // values are generate from the inside of the ring to the outside - - const segment = thetaStart + i / thetaSegments * thetaLength; - - // vertex - - vertex.x = radius * Math.cos( segment ); - vertex.y = radius * Math.sin( segment ); - - vertices.push( vertex.x, vertex.y, vertex.z ); - - // normal - - normals.push( 0, 0, 1 ); - - // uv - - uv.x = ( vertex.x / outerRadius + 1 ) / 2; - uv.y = ( vertex.y / outerRadius + 1 ) / 2; - - uvs.push( uv.x, uv.y ); - - } - - // increase the radius for next row of vertices - - radius += radiusStep; - - } - - // indices - - for ( let j = 0; j < phiSegments; j ++ ) { - - const thetaSegmentLevel = j * ( thetaSegments + 1 ); - - for ( let i = 0; i < thetaSegments; i ++ ) { - - const segment = i + thetaSegmentLevel; - - const a = segment; - const b = segment + thetaSegments + 1; - const c = segment + thetaSegments + 2; - const d = segment + 1; - - // faces - - indices.push( a, b, d ); - indices.push( b, c, d ); - - } - - } - - // build geometry - - this.setIndex( indices ); - this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - - } - - copy( source ) { - - super.copy( source ); - - this.parameters = Object.assign( {}, source.parameters ); - - return this; - - } - - static fromJSON( data ) { - - return new RingGeometry( data.innerRadius, data.outerRadius, data.thetaSegments, data.phiSegments, data.thetaStart, data.thetaLength ); - - } - -} - -class ShapeGeometry extends BufferGeometry { - - constructor( shapes = new Shape( [ new Vector2( 0, 0.5 ), new Vector2( - 0.5, - 0.5 ), new Vector2( 0.5, - 0.5 ) ] ), curveSegments = 12 ) { - - super(); - - this.type = 'ShapeGeometry'; - - this.parameters = { - shapes: shapes, - curveSegments: curveSegments - }; - - // buffers - - const indices = []; - const vertices = []; - const normals = []; - const uvs = []; - - // helper variables - - let groupStart = 0; - let groupCount = 0; - - // allow single and array values for "shapes" parameter - - if ( Array.isArray( shapes ) === false ) { - - addShape( shapes ); - - } else { - - for ( let i = 0; i < shapes.length; i ++ ) { - - addShape( shapes[ i ] ); - - this.addGroup( groupStart, groupCount, i ); // enables MultiMaterial support - - groupStart += groupCount; - groupCount = 0; - - } - - } - - // build geometry - - this.setIndex( indices ); - this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - - - // helper functions - - function addShape( shape ) { - - const indexOffset = vertices.length / 3; - const points = shape.extractPoints( curveSegments ); - - let shapeVertices = points.shape; - const shapeHoles = points.holes; - - // check direction of vertices - - if ( ShapeUtils.isClockWise( shapeVertices ) === false ) { - - shapeVertices = shapeVertices.reverse(); - - } - - for ( let i = 0, l = shapeHoles.length; i < l; i ++ ) { - - const shapeHole = shapeHoles[ i ]; - - if ( ShapeUtils.isClockWise( shapeHole ) === true ) { - - shapeHoles[ i ] = shapeHole.reverse(); - - } - - } - - const faces = ShapeUtils.triangulateShape( shapeVertices, shapeHoles ); - - // join vertices of inner and outer paths to a single array - - for ( let i = 0, l = shapeHoles.length; i < l; i ++ ) { - - const shapeHole = shapeHoles[ i ]; - shapeVertices = shapeVertices.concat( shapeHole ); - - } - - // vertices, normals, uvs - - for ( let i = 0, l = shapeVertices.length; i < l; i ++ ) { - - const vertex = shapeVertices[ i ]; - - vertices.push( vertex.x, vertex.y, 0 ); - normals.push( 0, 0, 1 ); - uvs.push( vertex.x, vertex.y ); // world uvs - - } - - // indices - - for ( let i = 0, l = faces.length; i < l; i ++ ) { - - const face = faces[ i ]; - - const a = face[ 0 ] + indexOffset; - const b = face[ 1 ] + indexOffset; - const c = face[ 2 ] + indexOffset; - - indices.push( a, b, c ); - groupCount += 3; - - } - - } - - } - - copy( source ) { - - super.copy( source ); - - this.parameters = Object.assign( {}, source.parameters ); - - return this; - - } - - toJSON() { - - const data = super.toJSON(); - - const shapes = this.parameters.shapes; - - return toJSON( shapes, data ); - - } - - static fromJSON( data, shapes ) { - - const geometryShapes = []; - - for ( let j = 0, jl = data.shapes.length; j < jl; j ++ ) { - - const shape = shapes[ data.shapes[ j ] ]; - - geometryShapes.push( shape ); - - } - - return new ShapeGeometry( geometryShapes, data.curveSegments ); - - } - -} - -function toJSON( shapes, data ) { - - data.shapes = []; - - if ( Array.isArray( shapes ) ) { - - for ( let i = 0, l = shapes.length; i < l; i ++ ) { - - const shape = shapes[ i ]; - - data.shapes.push( shape.uuid ); - - } - - } else { - - data.shapes.push( shapes.uuid ); - - } - - return data; - -} - -class SphereGeometry extends BufferGeometry { - - constructor( radius = 1, widthSegments = 32, heightSegments = 16, phiStart = 0, phiLength = Math.PI * 2, thetaStart = 0, thetaLength = Math.PI ) { - - super(); - - this.type = 'SphereGeometry'; - - this.parameters = { - radius: radius, - widthSegments: widthSegments, - heightSegments: heightSegments, - phiStart: phiStart, - phiLength: phiLength, - thetaStart: thetaStart, - thetaLength: thetaLength - }; - - widthSegments = Math.max( 3, Math.floor( widthSegments ) ); - heightSegments = Math.max( 2, Math.floor( heightSegments ) ); - - const thetaEnd = Math.min( thetaStart + thetaLength, Math.PI ); - - let index = 0; - const grid = []; - - const vertex = new Vector3(); - const normal = new Vector3(); - - // buffers - - const indices = []; - const vertices = []; - const normals = []; - const uvs = []; - - // generate vertices, normals and uvs - - for ( let iy = 0; iy <= heightSegments; iy ++ ) { - - const verticesRow = []; - - const v = iy / heightSegments; - - // special case for the poles - - let uOffset = 0; - - if ( iy === 0 && thetaStart === 0 ) { - - uOffset = 0.5 / widthSegments; - - } else if ( iy === heightSegments && thetaEnd === Math.PI ) { - - uOffset = - 0.5 / widthSegments; - - } - - for ( let ix = 0; ix <= widthSegments; ix ++ ) { - - const u = ix / widthSegments; - - // vertex - - vertex.x = - radius * Math.cos( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength ); - vertex.y = radius * Math.cos( thetaStart + v * thetaLength ); - vertex.z = radius * Math.sin( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength ); - - vertices.push( vertex.x, vertex.y, vertex.z ); - - // normal - - normal.copy( vertex ).normalize(); - normals.push( normal.x, normal.y, normal.z ); - - // uv - - uvs.push( u + uOffset, 1 - v ); - - verticesRow.push( index ++ ); - - } - - grid.push( verticesRow ); - - } - - // indices - - for ( let iy = 0; iy < heightSegments; iy ++ ) { - - for ( let ix = 0; ix < widthSegments; ix ++ ) { - - const a = grid[ iy ][ ix + 1 ]; - const b = grid[ iy ][ ix ]; - const c = grid[ iy + 1 ][ ix ]; - const d = grid[ iy + 1 ][ ix + 1 ]; - - if ( iy !== 0 || thetaStart > 0 ) indices.push( a, b, d ); - if ( iy !== heightSegments - 1 || thetaEnd < Math.PI ) indices.push( b, c, d ); - - } - - } - - // build geometry - - this.setIndex( indices ); - this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - - } - - copy( source ) { - - super.copy( source ); - - this.parameters = Object.assign( {}, source.parameters ); - - return this; - - } - - static fromJSON( data ) { - - return new SphereGeometry( data.radius, data.widthSegments, data.heightSegments, data.phiStart, data.phiLength, data.thetaStart, data.thetaLength ); - - } - -} - -class TetrahedronGeometry extends PolyhedronGeometry { - - constructor( radius = 1, detail = 0 ) { - - const vertices = [ - 1, 1, 1, - 1, - 1, 1, - 1, 1, - 1, 1, - 1, - 1 - ]; - - const indices = [ - 2, 1, 0, 0, 3, 2, 1, 3, 0, 2, 3, 1 - ]; - - super( vertices, indices, radius, detail ); - - this.type = 'TetrahedronGeometry'; - - this.parameters = { - radius: radius, - detail: detail - }; - - } - - static fromJSON( data ) { - - return new TetrahedronGeometry( data.radius, data.detail ); - - } - -} - -class TorusGeometry extends BufferGeometry { - - constructor( radius = 1, tube = 0.4, radialSegments = 12, tubularSegments = 48, arc = Math.PI * 2 ) { - - super(); - - this.type = 'TorusGeometry'; - - this.parameters = { - radius: radius, - tube: tube, - radialSegments: radialSegments, - tubularSegments: tubularSegments, - arc: arc - }; - - radialSegments = Math.floor( radialSegments ); - tubularSegments = Math.floor( tubularSegments ); - - // buffers - - const indices = []; - const vertices = []; - const normals = []; - const uvs = []; - - // helper variables - - const center = new Vector3(); - const vertex = new Vector3(); - const normal = new Vector3(); - - // generate vertices, normals and uvs - - for ( let j = 0; j <= radialSegments; j ++ ) { - - for ( let i = 0; i <= tubularSegments; i ++ ) { - - const u = i / tubularSegments * arc; - const v = j / radialSegments * Math.PI * 2; - - // vertex - - vertex.x = ( radius + tube * Math.cos( v ) ) * Math.cos( u ); - vertex.y = ( radius + tube * Math.cos( v ) ) * Math.sin( u ); - vertex.z = tube * Math.sin( v ); - - vertices.push( vertex.x, vertex.y, vertex.z ); - - // normal - - center.x = radius * Math.cos( u ); - center.y = radius * Math.sin( u ); - normal.subVectors( vertex, center ).normalize(); - - normals.push( normal.x, normal.y, normal.z ); - - // uv - - uvs.push( i / tubularSegments ); - uvs.push( j / radialSegments ); - - } - - } - - // generate indices - - for ( let j = 1; j <= radialSegments; j ++ ) { - - for ( let i = 1; i <= tubularSegments; i ++ ) { - - // indices - - const a = ( tubularSegments + 1 ) * j + i - 1; - const b = ( tubularSegments + 1 ) * ( j - 1 ) + i - 1; - const c = ( tubularSegments + 1 ) * ( j - 1 ) + i; - const d = ( tubularSegments + 1 ) * j + i; - - // faces - - indices.push( a, b, d ); - indices.push( b, c, d ); - - } - - } - - // build geometry - - this.setIndex( indices ); - this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - - } - - copy( source ) { - - super.copy( source ); - - this.parameters = Object.assign( {}, source.parameters ); - - return this; - - } - - static fromJSON( data ) { - - return new TorusGeometry( data.radius, data.tube, data.radialSegments, data.tubularSegments, data.arc ); - - } - -} - -class TorusKnotGeometry extends BufferGeometry { - - constructor( radius = 1, tube = 0.4, tubularSegments = 64, radialSegments = 8, p = 2, q = 3 ) { - - super(); - - this.type = 'TorusKnotGeometry'; - - this.parameters = { - radius: radius, - tube: tube, - tubularSegments: tubularSegments, - radialSegments: radialSegments, - p: p, - q: q - }; - - tubularSegments = Math.floor( tubularSegments ); - radialSegments = Math.floor( radialSegments ); - - // buffers - - const indices = []; - const vertices = []; - const normals = []; - const uvs = []; - - // helper variables - - const vertex = new Vector3(); - const normal = new Vector3(); - - const P1 = new Vector3(); - const P2 = new Vector3(); - - const B = new Vector3(); - const T = new Vector3(); - const N = new Vector3(); - - // generate vertices, normals and uvs - - for ( let i = 0; i <= tubularSegments; ++ i ) { - - // the radian "u" is used to calculate the position on the torus curve of the current tubular segment - - const u = i / tubularSegments * p * Math.PI * 2; - - // now we calculate two points. P1 is our current position on the curve, P2 is a little farther ahead. - // these points are used to create a special "coordinate space", which is necessary to calculate the correct vertex positions - - calculatePositionOnCurve( u, p, q, radius, P1 ); - calculatePositionOnCurve( u + 0.01, p, q, radius, P2 ); - - // calculate orthonormal basis - - T.subVectors( P2, P1 ); - N.addVectors( P2, P1 ); - B.crossVectors( T, N ); - N.crossVectors( B, T ); - - // normalize B, N. T can be ignored, we don't use it - - B.normalize(); - N.normalize(); - - for ( let j = 0; j <= radialSegments; ++ j ) { - - // now calculate the vertices. they are nothing more than an extrusion of the torus curve. - // because we extrude a shape in the xy-plane, there is no need to calculate a z-value. - - const v = j / radialSegments * Math.PI * 2; - const cx = - tube * Math.cos( v ); - const cy = tube * Math.sin( v ); - - // now calculate the final vertex position. - // first we orient the extrusion with our basis vectors, then we add it to the current position on the curve - - vertex.x = P1.x + ( cx * N.x + cy * B.x ); - vertex.y = P1.y + ( cx * N.y + cy * B.y ); - vertex.z = P1.z + ( cx * N.z + cy * B.z ); - - vertices.push( vertex.x, vertex.y, vertex.z ); - - // normal (P1 is always the center/origin of the extrusion, thus we can use it to calculate the normal) - - normal.subVectors( vertex, P1 ).normalize(); - - normals.push( normal.x, normal.y, normal.z ); - - // uv - - uvs.push( i / tubularSegments ); - uvs.push( j / radialSegments ); - - } - - } - - // generate indices - - for ( let j = 1; j <= tubularSegments; j ++ ) { - - for ( let i = 1; i <= radialSegments; i ++ ) { - - // indices - - const a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 ); - const b = ( radialSegments + 1 ) * j + ( i - 1 ); - const c = ( radialSegments + 1 ) * j + i; - const d = ( radialSegments + 1 ) * ( j - 1 ) + i; - - // faces - - indices.push( a, b, d ); - indices.push( b, c, d ); - - } - - } - - // build geometry - - this.setIndex( indices ); - this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - - // this function calculates the current position on the torus curve - - function calculatePositionOnCurve( u, p, q, radius, position ) { - - const cu = Math.cos( u ); - const su = Math.sin( u ); - const quOverP = q / p * u; - const cs = Math.cos( quOverP ); - - position.x = radius * ( 2 + cs ) * 0.5 * cu; - position.y = radius * ( 2 + cs ) * su * 0.5; - position.z = radius * Math.sin( quOverP ) * 0.5; - - } - - } - - copy( source ) { - - super.copy( source ); - - this.parameters = Object.assign( {}, source.parameters ); - - return this; - - } - - static fromJSON( data ) { - - return new TorusKnotGeometry( data.radius, data.tube, data.tubularSegments, data.radialSegments, data.p, data.q ); - - } - -} - -class TubeGeometry extends BufferGeometry { - - constructor( path = new QuadraticBezierCurve3( new Vector3( - 1, - 1, 0 ), new Vector3( - 1, 1, 0 ), new Vector3( 1, 1, 0 ) ), tubularSegments = 64, radius = 1, radialSegments = 8, closed = false ) { - - super(); - - this.type = 'TubeGeometry'; - - this.parameters = { - path: path, - tubularSegments: tubularSegments, - radius: radius, - radialSegments: radialSegments, - closed: closed - }; - - const frames = path.computeFrenetFrames( tubularSegments, closed ); - - // expose internals - - this.tangents = frames.tangents; - this.normals = frames.normals; - this.binormals = frames.binormals; - - // helper variables - - const vertex = new Vector3(); - const normal = new Vector3(); - const uv = new Vector2(); - let P = new Vector3(); - - // buffer - - const vertices = []; - const normals = []; - const uvs = []; - const indices = []; - - // create buffer data - - generateBufferData(); - - // build geometry - - this.setIndex( indices ); - this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - - // functions - - function generateBufferData() { - - for ( let i = 0; i < tubularSegments; i ++ ) { - - generateSegment( i ); - - } - - // if the geometry is not closed, generate the last row of vertices and normals - // at the regular position on the given path - // - // if the geometry is closed, duplicate the first row of vertices and normals (uvs will differ) - - generateSegment( ( closed === false ) ? tubularSegments : 0 ); - - // uvs are generated in a separate function. - // this makes it easy compute correct values for closed geometries - - generateUVs(); - - // finally create faces - - generateIndices(); - - } - - function generateSegment( i ) { - - // we use getPointAt to sample evenly distributed points from the given path - - P = path.getPointAt( i / tubularSegments, P ); - - // retrieve corresponding normal and binormal - - const N = frames.normals[ i ]; - const B = frames.binormals[ i ]; - - // generate normals and vertices for the current segment - - for ( let j = 0; j <= radialSegments; j ++ ) { - - const v = j / radialSegments * Math.PI * 2; - - const sin = Math.sin( v ); - const cos = - Math.cos( v ); - - // normal - - normal.x = ( cos * N.x + sin * B.x ); - normal.y = ( cos * N.y + sin * B.y ); - normal.z = ( cos * N.z + sin * B.z ); - normal.normalize(); - - normals.push( normal.x, normal.y, normal.z ); - - // vertex - - vertex.x = P.x + radius * normal.x; - vertex.y = P.y + radius * normal.y; - vertex.z = P.z + radius * normal.z; - - vertices.push( vertex.x, vertex.y, vertex.z ); - - } - - } - - function generateIndices() { - - for ( let j = 1; j <= tubularSegments; j ++ ) { - - for ( let i = 1; i <= radialSegments; i ++ ) { - - const a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 ); - const b = ( radialSegments + 1 ) * j + ( i - 1 ); - const c = ( radialSegments + 1 ) * j + i; - const d = ( radialSegments + 1 ) * ( j - 1 ) + i; - - // faces - - indices.push( a, b, d ); - indices.push( b, c, d ); - - } - - } - - } - - function generateUVs() { - - for ( let i = 0; i <= tubularSegments; i ++ ) { - - for ( let j = 0; j <= radialSegments; j ++ ) { - - uv.x = i / tubularSegments; - uv.y = j / radialSegments; - - uvs.push( uv.x, uv.y ); - - } - - } - - } - - } - - copy( source ) { - - super.copy( source ); - - this.parameters = Object.assign( {}, source.parameters ); - - return this; - - } - - toJSON() { - - const data = super.toJSON(); - - data.path = this.parameters.path.toJSON(); - - return data; - - } - - static fromJSON( data ) { - - // This only works for built-in curves (e.g. CatmullRomCurve3). - // User defined curves or instances of CurvePath will not be deserialized. - return new TubeGeometry( - new Curves[ data.path.type ]().fromJSON( data.path ), - data.tubularSegments, - data.radius, - data.radialSegments, - data.closed - ); - - } - -} - -class WireframeGeometry extends BufferGeometry { - - constructor( geometry = null ) { - - super(); - - this.type = 'WireframeGeometry'; - - this.parameters = { - geometry: geometry - }; - - if ( geometry !== null ) { - - // buffer - - const vertices = []; - const edges = new Set(); - - // helper variables - - const start = new Vector3(); - const end = new Vector3(); - - if ( geometry.index !== null ) { - - // indexed BufferGeometry - - const position = geometry.attributes.position; - const indices = geometry.index; - let groups = geometry.groups; - - if ( groups.length === 0 ) { - - groups = [ { start: 0, count: indices.count, materialIndex: 0 } ]; - - } - - // create a data structure that contains all edges without duplicates - - for ( let o = 0, ol = groups.length; o < ol; ++ o ) { - - const group = groups[ o ]; - - const groupStart = group.start; - const groupCount = group.count; - - for ( let i = groupStart, l = ( groupStart + groupCount ); i < l; i += 3 ) { - - for ( let j = 0; j < 3; j ++ ) { - - const index1 = indices.getX( i + j ); - const index2 = indices.getX( i + ( j + 1 ) % 3 ); - - start.fromBufferAttribute( position, index1 ); - end.fromBufferAttribute( position, index2 ); - - if ( isUniqueEdge( start, end, edges ) === true ) { - - vertices.push( start.x, start.y, start.z ); - vertices.push( end.x, end.y, end.z ); - - } - - } - - } - - } - - } else { - - // non-indexed BufferGeometry - - const position = geometry.attributes.position; - - for ( let i = 0, l = ( position.count / 3 ); i < l; i ++ ) { - - for ( let j = 0; j < 3; j ++ ) { - - // three edges per triangle, an edge is represented as (index1, index2) - // e.g. the first triangle has the following edges: (0,1),(1,2),(2,0) - - const index1 = 3 * i + j; - const index2 = 3 * i + ( ( j + 1 ) % 3 ); - - start.fromBufferAttribute( position, index1 ); - end.fromBufferAttribute( position, index2 ); - - if ( isUniqueEdge( start, end, edges ) === true ) { - - vertices.push( start.x, start.y, start.z ); - vertices.push( end.x, end.y, end.z ); - - } - - } - - } - - } - - // build geometry - - this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - - } - - } - - copy( source ) { - - super.copy( source ); - - this.parameters = Object.assign( {}, source.parameters ); - - return this; - - } - -} - -function isUniqueEdge( start, end, edges ) { - - const hash1 = `${start.x},${start.y},${start.z}-${end.x},${end.y},${end.z}`; - const hash2 = `${end.x},${end.y},${end.z}-${start.x},${start.y},${start.z}`; // coincident edge - - if ( edges.has( hash1 ) === true || edges.has( hash2 ) === true ) { - - return false; - - } else { - - edges.add( hash1 ); - edges.add( hash2 ); - return true; - - } - -} - -var Geometries = /*#__PURE__*/Object.freeze({ - __proto__: null, - BoxGeometry: BoxGeometry, - CapsuleGeometry: CapsuleGeometry, - CircleGeometry: CircleGeometry, - ConeGeometry: ConeGeometry, - CylinderGeometry: CylinderGeometry, - DodecahedronGeometry: DodecahedronGeometry, - EdgesGeometry: EdgesGeometry, - ExtrudeGeometry: ExtrudeGeometry, - IcosahedronGeometry: IcosahedronGeometry, - LatheGeometry: LatheGeometry, - OctahedronGeometry: OctahedronGeometry, - PlaneGeometry: PlaneGeometry, - PolyhedronGeometry: PolyhedronGeometry, - RingGeometry: RingGeometry, - ShapeGeometry: ShapeGeometry, - SphereGeometry: SphereGeometry, - TetrahedronGeometry: TetrahedronGeometry, - TorusGeometry: TorusGeometry, - TorusKnotGeometry: TorusKnotGeometry, - TubeGeometry: TubeGeometry, - WireframeGeometry: WireframeGeometry -}); - -class ShadowMaterial extends Material { - - constructor( parameters ) { - - super(); - - this.isShadowMaterial = true; - - this.type = 'ShadowMaterial'; - - this.color = new Color( 0x000000 ); - this.transparent = true; - - this.fog = true; - - this.setValues( parameters ); - - } - - copy( source ) { - - super.copy( source ); - - this.color.copy( source.color ); - - this.fog = source.fog; - - return this; - - } - -} - -class RawShaderMaterial extends ShaderMaterial { - - constructor( parameters ) { - - super( parameters ); - - this.isRawShaderMaterial = true; - - this.type = 'RawShaderMaterial'; - - } - -} - -class MeshStandardMaterial extends Material { - - constructor( parameters ) { - - super(); - - this.isMeshStandardMaterial = true; - - this.defines = { 'STANDARD': '' }; - - this.type = 'MeshStandardMaterial'; - - this.color = new Color( 0xffffff ); // diffuse - this.roughness = 1.0; - this.metalness = 0.0; - - this.map = null; - - this.lightMap = null; - this.lightMapIntensity = 1.0; - - this.aoMap = null; - this.aoMapIntensity = 1.0; - - this.emissive = new Color( 0x000000 ); - this.emissiveIntensity = 1.0; - this.emissiveMap = null; - - this.bumpMap = null; - this.bumpScale = 1; - - this.normalMap = null; - this.normalMapType = TangentSpaceNormalMap; - this.normalScale = new Vector2( 1, 1 ); - - this.displacementMap = null; - this.displacementScale = 1; - this.displacementBias = 0; - - this.roughnessMap = null; - - this.metalnessMap = null; - - this.alphaMap = null; - - this.envMap = null; - this.envMapIntensity = 1.0; - - this.wireframe = false; - this.wireframeLinewidth = 1; - this.wireframeLinecap = 'round'; - this.wireframeLinejoin = 'round'; - - this.flatShading = false; - - this.fog = true; - - this.setValues( parameters ); - - } - - copy( source ) { - - super.copy( source ); - - this.defines = { 'STANDARD': '' }; - - this.color.copy( source.color ); - this.roughness = source.roughness; - this.metalness = source.metalness; - - this.map = source.map; - - this.lightMap = source.lightMap; - this.lightMapIntensity = source.lightMapIntensity; - - this.aoMap = source.aoMap; - this.aoMapIntensity = source.aoMapIntensity; - - this.emissive.copy( source.emissive ); - this.emissiveMap = source.emissiveMap; - this.emissiveIntensity = source.emissiveIntensity; - - this.bumpMap = source.bumpMap; - this.bumpScale = source.bumpScale; - - this.normalMap = source.normalMap; - this.normalMapType = source.normalMapType; - this.normalScale.copy( source.normalScale ); - - this.displacementMap = source.displacementMap; - this.displacementScale = source.displacementScale; - this.displacementBias = source.displacementBias; - - this.roughnessMap = source.roughnessMap; - - this.metalnessMap = source.metalnessMap; - - this.alphaMap = source.alphaMap; - - this.envMap = source.envMap; - this.envMapIntensity = source.envMapIntensity; - - this.wireframe = source.wireframe; - this.wireframeLinewidth = source.wireframeLinewidth; - this.wireframeLinecap = source.wireframeLinecap; - this.wireframeLinejoin = source.wireframeLinejoin; - - this.flatShading = source.flatShading; - - this.fog = source.fog; - - return this; - - } - -} - -class MeshPhysicalMaterial extends MeshStandardMaterial { - - constructor( parameters ) { - - super(); - - this.isMeshPhysicalMaterial = true; - - this.defines = { - - 'STANDARD': '', - 'PHYSICAL': '' - - }; - - this.type = 'MeshPhysicalMaterial'; - - this.anisotropyRotation = 0; - this.anisotropyMap = null; - - this.clearcoatMap = null; - this.clearcoatRoughness = 0.0; - this.clearcoatRoughnessMap = null; - this.clearcoatNormalScale = new Vector2( 1, 1 ); - this.clearcoatNormalMap = null; - - this.ior = 1.5; - - Object.defineProperty( this, 'reflectivity', { - get: function () { - - return ( clamp( 2.5 * ( this.ior - 1 ) / ( this.ior + 1 ), 0, 1 ) ); - - }, - set: function ( reflectivity ) { - - this.ior = ( 1 + 0.4 * reflectivity ) / ( 1 - 0.4 * reflectivity ); - - } - } ); - - this.iridescenceMap = null; - this.iridescenceIOR = 1.3; - this.iridescenceThicknessRange = [ 100, 400 ]; - this.iridescenceThicknessMap = null; - - this.sheenColor = new Color( 0x000000 ); - this.sheenColorMap = null; - this.sheenRoughness = 1.0; - this.sheenRoughnessMap = null; - - this.transmissionMap = null; - - this.thickness = 0; - this.thicknessMap = null; - this.attenuationDistance = Infinity; - this.attenuationColor = new Color( 1, 1, 1 ); - - this.specularIntensity = 1.0; - this.specularIntensityMap = null; - this.specularColor = new Color( 1, 1, 1 ); - this.specularColorMap = null; - - this._anisotropy = 0; - this._clearcoat = 0; - this._iridescence = 0; - this._sheen = 0.0; - this._transmission = 0; - - this.setValues( parameters ); - - } - - get anisotropy() { - - return this._anisotropy; - - } - - set anisotropy( value ) { - - if ( this._anisotropy > 0 !== value > 0 ) { - - this.version ++; - - } - - this._anisotropy = value; - - } - - get clearcoat() { - - return this._clearcoat; - - } - - set clearcoat( value ) { - - if ( this._clearcoat > 0 !== value > 0 ) { - - this.version ++; - - } - - this._clearcoat = value; - - } - - get iridescence() { - - return this._iridescence; - - } - - set iridescence( value ) { - - if ( this._iridescence > 0 !== value > 0 ) { - - this.version ++; - - } - - this._iridescence = value; - - } - - get sheen() { - - return this._sheen; - - } - - set sheen( value ) { - - if ( this._sheen > 0 !== value > 0 ) { - - this.version ++; - - } - - this._sheen = value; - - } - - get transmission() { - - return this._transmission; - - } - - set transmission( value ) { - - if ( this._transmission > 0 !== value > 0 ) { - - this.version ++; - - } - - this._transmission = value; - - } - - copy( source ) { - - super.copy( source ); - - this.defines = { - - 'STANDARD': '', - 'PHYSICAL': '' - - }; - - this.anisotropy = source.anisotropy; - this.anisotropyRotation = source.anisotropyRotation; - this.anisotropyMap = source.anisotropyMap; - - this.clearcoat = source.clearcoat; - this.clearcoatMap = source.clearcoatMap; - this.clearcoatRoughness = source.clearcoatRoughness; - this.clearcoatRoughnessMap = source.clearcoatRoughnessMap; - this.clearcoatNormalMap = source.clearcoatNormalMap; - this.clearcoatNormalScale.copy( source.clearcoatNormalScale ); - - this.ior = source.ior; - - this.iridescence = source.iridescence; - this.iridescenceMap = source.iridescenceMap; - this.iridescenceIOR = source.iridescenceIOR; - this.iridescenceThicknessRange = [ ...source.iridescenceThicknessRange ]; - this.iridescenceThicknessMap = source.iridescenceThicknessMap; - - this.sheen = source.sheen; - this.sheenColor.copy( source.sheenColor ); - this.sheenColorMap = source.sheenColorMap; - this.sheenRoughness = source.sheenRoughness; - this.sheenRoughnessMap = source.sheenRoughnessMap; - - this.transmission = source.transmission; - this.transmissionMap = source.transmissionMap; - - this.thickness = source.thickness; - this.thicknessMap = source.thicknessMap; - this.attenuationDistance = source.attenuationDistance; - this.attenuationColor.copy( source.attenuationColor ); - - this.specularIntensity = source.specularIntensity; - this.specularIntensityMap = source.specularIntensityMap; - this.specularColor.copy( source.specularColor ); - this.specularColorMap = source.specularColorMap; - - return this; - - } - -} - -class MeshPhongMaterial extends Material { - - constructor( parameters ) { - - super(); - - this.isMeshPhongMaterial = true; - - this.type = 'MeshPhongMaterial'; - - this.color = new Color( 0xffffff ); // diffuse - this.specular = new Color( 0x111111 ); - this.shininess = 30; - - this.map = null; - - this.lightMap = null; - this.lightMapIntensity = 1.0; - - this.aoMap = null; - this.aoMapIntensity = 1.0; - - this.emissive = new Color( 0x000000 ); - this.emissiveIntensity = 1.0; - this.emissiveMap = null; - - this.bumpMap = null; - this.bumpScale = 1; - - this.normalMap = null; - this.normalMapType = TangentSpaceNormalMap; - this.normalScale = new Vector2( 1, 1 ); - - this.displacementMap = null; - this.displacementScale = 1; - this.displacementBias = 0; - - this.specularMap = null; - - this.alphaMap = null; - - this.envMap = null; - this.combine = MultiplyOperation; - this.reflectivity = 1; - this.refractionRatio = 0.98; - - this.wireframe = false; - this.wireframeLinewidth = 1; - this.wireframeLinecap = 'round'; - this.wireframeLinejoin = 'round'; - - this.flatShading = false; - - this.fog = true; - - this.setValues( parameters ); - - } - - copy( source ) { - - super.copy( source ); - - this.color.copy( source.color ); - this.specular.copy( source.specular ); - this.shininess = source.shininess; - - this.map = source.map; - - this.lightMap = source.lightMap; - this.lightMapIntensity = source.lightMapIntensity; - - this.aoMap = source.aoMap; - this.aoMapIntensity = source.aoMapIntensity; - - this.emissive.copy( source.emissive ); - this.emissiveMap = source.emissiveMap; - this.emissiveIntensity = source.emissiveIntensity; - - this.bumpMap = source.bumpMap; - this.bumpScale = source.bumpScale; - - this.normalMap = source.normalMap; - this.normalMapType = source.normalMapType; - this.normalScale.copy( source.normalScale ); - - this.displacementMap = source.displacementMap; - this.displacementScale = source.displacementScale; - this.displacementBias = source.displacementBias; - - this.specularMap = source.specularMap; - - this.alphaMap = source.alphaMap; - - this.envMap = source.envMap; - this.combine = source.combine; - this.reflectivity = source.reflectivity; - this.refractionRatio = source.refractionRatio; - - this.wireframe = source.wireframe; - this.wireframeLinewidth = source.wireframeLinewidth; - this.wireframeLinecap = source.wireframeLinecap; - this.wireframeLinejoin = source.wireframeLinejoin; - - this.flatShading = source.flatShading; - - this.fog = source.fog; - - return this; - - } - -} - -class MeshToonMaterial extends Material { - - constructor( parameters ) { - - super(); - - this.isMeshToonMaterial = true; - - this.defines = { 'TOON': '' }; - - this.type = 'MeshToonMaterial'; - - this.color = new Color( 0xffffff ); - - this.map = null; - this.gradientMap = null; - - this.lightMap = null; - this.lightMapIntensity = 1.0; - - this.aoMap = null; - this.aoMapIntensity = 1.0; - - this.emissive = new Color( 0x000000 ); - this.emissiveIntensity = 1.0; - this.emissiveMap = null; - - this.bumpMap = null; - this.bumpScale = 1; - - this.normalMap = null; - this.normalMapType = TangentSpaceNormalMap; - this.normalScale = new Vector2( 1, 1 ); - - this.displacementMap = null; - this.displacementScale = 1; - this.displacementBias = 0; - - this.alphaMap = null; - - this.wireframe = false; - this.wireframeLinewidth = 1; - this.wireframeLinecap = 'round'; - this.wireframeLinejoin = 'round'; - - this.fog = true; - - this.setValues( parameters ); - - } - - copy( source ) { - - super.copy( source ); - - this.color.copy( source.color ); - - this.map = source.map; - this.gradientMap = source.gradientMap; - - this.lightMap = source.lightMap; - this.lightMapIntensity = source.lightMapIntensity; - - this.aoMap = source.aoMap; - this.aoMapIntensity = source.aoMapIntensity; - - this.emissive.copy( source.emissive ); - this.emissiveMap = source.emissiveMap; - this.emissiveIntensity = source.emissiveIntensity; - - this.bumpMap = source.bumpMap; - this.bumpScale = source.bumpScale; - - this.normalMap = source.normalMap; - this.normalMapType = source.normalMapType; - this.normalScale.copy( source.normalScale ); - - this.displacementMap = source.displacementMap; - this.displacementScale = source.displacementScale; - this.displacementBias = source.displacementBias; - - this.alphaMap = source.alphaMap; - - this.wireframe = source.wireframe; - this.wireframeLinewidth = source.wireframeLinewidth; - this.wireframeLinecap = source.wireframeLinecap; - this.wireframeLinejoin = source.wireframeLinejoin; - - this.fog = source.fog; - - return this; - - } - -} - -class MeshNormalMaterial extends Material { - - constructor( parameters ) { - - super(); - - this.isMeshNormalMaterial = true; - - this.type = 'MeshNormalMaterial'; - - this.bumpMap = null; - this.bumpScale = 1; - - this.normalMap = null; - this.normalMapType = TangentSpaceNormalMap; - this.normalScale = new Vector2( 1, 1 ); - - this.displacementMap = null; - this.displacementScale = 1; - this.displacementBias = 0; - - this.wireframe = false; - this.wireframeLinewidth = 1; - - this.flatShading = false; - - this.setValues( parameters ); - - } - - copy( source ) { - - super.copy( source ); - - this.bumpMap = source.bumpMap; - this.bumpScale = source.bumpScale; - - this.normalMap = source.normalMap; - this.normalMapType = source.normalMapType; - this.normalScale.copy( source.normalScale ); - - this.displacementMap = source.displacementMap; - this.displacementScale = source.displacementScale; - this.displacementBias = source.displacementBias; - - this.wireframe = source.wireframe; - this.wireframeLinewidth = source.wireframeLinewidth; - - this.flatShading = source.flatShading; - - return this; - - } - -} - -class MeshLambertMaterial extends Material { - - constructor( parameters ) { - - super(); - - this.isMeshLambertMaterial = true; - - this.type = 'MeshLambertMaterial'; - - this.color = new Color( 0xffffff ); // diffuse - - this.map = null; - - this.lightMap = null; - this.lightMapIntensity = 1.0; - - this.aoMap = null; - this.aoMapIntensity = 1.0; - - this.emissive = new Color( 0x000000 ); - this.emissiveIntensity = 1.0; - this.emissiveMap = null; - - this.bumpMap = null; - this.bumpScale = 1; - - this.normalMap = null; - this.normalMapType = TangentSpaceNormalMap; - this.normalScale = new Vector2( 1, 1 ); - - this.displacementMap = null; - this.displacementScale = 1; - this.displacementBias = 0; - - this.specularMap = null; - - this.alphaMap = null; - - this.envMap = null; - this.combine = MultiplyOperation; - this.reflectivity = 1; - this.refractionRatio = 0.98; - - this.wireframe = false; - this.wireframeLinewidth = 1; - this.wireframeLinecap = 'round'; - this.wireframeLinejoin = 'round'; - - this.flatShading = false; - - this.fog = true; - - this.setValues( parameters ); - - } - - copy( source ) { - - super.copy( source ); - - this.color.copy( source.color ); - - this.map = source.map; - - this.lightMap = source.lightMap; - this.lightMapIntensity = source.lightMapIntensity; - - this.aoMap = source.aoMap; - this.aoMapIntensity = source.aoMapIntensity; - - this.emissive.copy( source.emissive ); - this.emissiveMap = source.emissiveMap; - this.emissiveIntensity = source.emissiveIntensity; - - this.bumpMap = source.bumpMap; - this.bumpScale = source.bumpScale; - - this.normalMap = source.normalMap; - this.normalMapType = source.normalMapType; - this.normalScale.copy( source.normalScale ); - - this.displacementMap = source.displacementMap; - this.displacementScale = source.displacementScale; - this.displacementBias = source.displacementBias; - - this.specularMap = source.specularMap; - - this.alphaMap = source.alphaMap; - - this.envMap = source.envMap; - this.combine = source.combine; - this.reflectivity = source.reflectivity; - this.refractionRatio = source.refractionRatio; - - this.wireframe = source.wireframe; - this.wireframeLinewidth = source.wireframeLinewidth; - this.wireframeLinecap = source.wireframeLinecap; - this.wireframeLinejoin = source.wireframeLinejoin; - - this.flatShading = source.flatShading; - - this.fog = source.fog; - - return this; - - } - -} - -class MeshMatcapMaterial extends Material { - - constructor( parameters ) { - - super(); - - this.isMeshMatcapMaterial = true; - - this.defines = { 'MATCAP': '' }; - - this.type = 'MeshMatcapMaterial'; - - this.color = new Color( 0xffffff ); // diffuse - - this.matcap = null; - - this.map = null; - - this.bumpMap = null; - this.bumpScale = 1; - - this.normalMap = null; - this.normalMapType = TangentSpaceNormalMap; - this.normalScale = new Vector2( 1, 1 ); - - this.displacementMap = null; - this.displacementScale = 1; - this.displacementBias = 0; - - this.alphaMap = null; - - this.flatShading = false; - - this.fog = true; - - this.setValues( parameters ); - - } - - - copy( source ) { - - super.copy( source ); - - this.defines = { 'MATCAP': '' }; - - this.color.copy( source.color ); - - this.matcap = source.matcap; - - this.map = source.map; - - this.bumpMap = source.bumpMap; - this.bumpScale = source.bumpScale; - - this.normalMap = source.normalMap; - this.normalMapType = source.normalMapType; - this.normalScale.copy( source.normalScale ); - - this.displacementMap = source.displacementMap; - this.displacementScale = source.displacementScale; - this.displacementBias = source.displacementBias; - - this.alphaMap = source.alphaMap; - - this.flatShading = source.flatShading; - - this.fog = source.fog; - - return this; - - } - -} - -class LineDashedMaterial extends LineBasicMaterial { - - constructor( parameters ) { - - super(); - - this.isLineDashedMaterial = true; - - this.type = 'LineDashedMaterial'; - - this.scale = 1; - this.dashSize = 3; - this.gapSize = 1; - - this.setValues( parameters ); - - } - - copy( source ) { - - super.copy( source ); - - this.scale = source.scale; - this.dashSize = source.dashSize; - this.gapSize = source.gapSize; - - return this; - - } - -} - -// converts an array to a specific type -function convertArray( array, type, forceClone ) { - - if ( ! array || // let 'undefined' and 'null' pass - ! forceClone && array.constructor === type ) return array; - - if ( typeof type.BYTES_PER_ELEMENT === 'number' ) { - - return new type( array ); // create typed array - - } - - return Array.prototype.slice.call( array ); // create Array - -} - -function isTypedArray( object ) { - - return ArrayBuffer.isView( object ) && - ! ( object instanceof DataView ); - -} - -// returns an array by which times and values can be sorted -function getKeyframeOrder( times ) { - - function compareTime( i, j ) { - - return times[ i ] - times[ j ]; - - } - - const n = times.length; - const result = new Array( n ); - for ( let i = 0; i !== n; ++ i ) result[ i ] = i; - - result.sort( compareTime ); - - return result; - -} - -// uses the array previously returned by 'getKeyframeOrder' to sort data -function sortedArray( values, stride, order ) { - - const nValues = values.length; - const result = new values.constructor( nValues ); - - for ( let i = 0, dstOffset = 0; dstOffset !== nValues; ++ i ) { - - const srcOffset = order[ i ] * stride; - - for ( let j = 0; j !== stride; ++ j ) { - - result[ dstOffset ++ ] = values[ srcOffset + j ]; - - } - - } - - return result; - -} - -// function for parsing AOS keyframe formats -function flattenJSON( jsonKeys, times, values, valuePropertyName ) { - - let i = 1, key = jsonKeys[ 0 ]; - - while ( key !== undefined && key[ valuePropertyName ] === undefined ) { - - key = jsonKeys[ i ++ ]; - - } - - if ( key === undefined ) return; // no data - - let value = key[ valuePropertyName ]; - if ( value === undefined ) return; // no data - - if ( Array.isArray( value ) ) { - - do { - - value = key[ valuePropertyName ]; - - if ( value !== undefined ) { - - times.push( key.time ); - values.push.apply( values, value ); // push all elements - - } - - key = jsonKeys[ i ++ ]; - - } while ( key !== undefined ); - - } else if ( value.toArray !== undefined ) { - - // ...assume THREE.Math-ish - - do { - - value = key[ valuePropertyName ]; - - if ( value !== undefined ) { - - times.push( key.time ); - value.toArray( values, values.length ); - - } - - key = jsonKeys[ i ++ ]; - - } while ( key !== undefined ); - - } else { - - // otherwise push as-is - - do { - - value = key[ valuePropertyName ]; - - if ( value !== undefined ) { - - times.push( key.time ); - values.push( value ); - - } - - key = jsonKeys[ i ++ ]; - - } while ( key !== undefined ); - - } - -} - -function subclip( sourceClip, name, startFrame, endFrame, fps = 30 ) { - - const clip = sourceClip.clone(); - - clip.name = name; - - const tracks = []; - - for ( let i = 0; i < clip.tracks.length; ++ i ) { - - const track = clip.tracks[ i ]; - const valueSize = track.getValueSize(); - - const times = []; - const values = []; - - for ( let j = 0; j < track.times.length; ++ j ) { - - const frame = track.times[ j ] * fps; - - if ( frame < startFrame || frame >= endFrame ) continue; - - times.push( track.times[ j ] ); - - for ( let k = 0; k < valueSize; ++ k ) { - - values.push( track.values[ j * valueSize + k ] ); - - } - - } - - if ( times.length === 0 ) continue; - - track.times = convertArray( times, track.times.constructor ); - track.values = convertArray( values, track.values.constructor ); - - tracks.push( track ); - - } - - clip.tracks = tracks; - - // find minimum .times value across all tracks in the trimmed clip - - let minStartTime = Infinity; - - for ( let i = 0; i < clip.tracks.length; ++ i ) { - - if ( minStartTime > clip.tracks[ i ].times[ 0 ] ) { - - minStartTime = clip.tracks[ i ].times[ 0 ]; - - } - - } - - // shift all tracks such that clip begins at t=0 - - for ( let i = 0; i < clip.tracks.length; ++ i ) { - - clip.tracks[ i ].shift( - 1 * minStartTime ); - - } - - clip.resetDuration(); - - return clip; - -} - -function makeClipAdditive( targetClip, referenceFrame = 0, referenceClip = targetClip, fps = 30 ) { - - if ( fps <= 0 ) fps = 30; - - const numTracks = referenceClip.tracks.length; - const referenceTime = referenceFrame / fps; - - // Make each track's values relative to the values at the reference frame - for ( let i = 0; i < numTracks; ++ i ) { - - const referenceTrack = referenceClip.tracks[ i ]; - const referenceTrackType = referenceTrack.ValueTypeName; - - // Skip this track if it's non-numeric - if ( referenceTrackType === 'bool' || referenceTrackType === 'string' ) continue; - - // Find the track in the target clip whose name and type matches the reference track - const targetTrack = targetClip.tracks.find( function ( track ) { - - return track.name === referenceTrack.name - && track.ValueTypeName === referenceTrackType; - - } ); - - if ( targetTrack === undefined ) continue; - - let referenceOffset = 0; - const referenceValueSize = referenceTrack.getValueSize(); - - if ( referenceTrack.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline ) { - - referenceOffset = referenceValueSize / 3; - - } - - let targetOffset = 0; - const targetValueSize = targetTrack.getValueSize(); - - if ( targetTrack.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline ) { - - targetOffset = targetValueSize / 3; - - } - - const lastIndex = referenceTrack.times.length - 1; - let referenceValue; - - // Find the value to subtract out of the track - if ( referenceTime <= referenceTrack.times[ 0 ] ) { - - // Reference frame is earlier than the first keyframe, so just use the first keyframe - const startIndex = referenceOffset; - const endIndex = referenceValueSize - referenceOffset; - referenceValue = referenceTrack.values.slice( startIndex, endIndex ); - - } else if ( referenceTime >= referenceTrack.times[ lastIndex ] ) { - - // Reference frame is after the last keyframe, so just use the last keyframe - const startIndex = lastIndex * referenceValueSize + referenceOffset; - const endIndex = startIndex + referenceValueSize - referenceOffset; - referenceValue = referenceTrack.values.slice( startIndex, endIndex ); - - } else { - - // Interpolate to the reference value - const interpolant = referenceTrack.createInterpolant(); - const startIndex = referenceOffset; - const endIndex = referenceValueSize - referenceOffset; - interpolant.evaluate( referenceTime ); - referenceValue = interpolant.resultBuffer.slice( startIndex, endIndex ); - - } - - // Conjugate the quaternion - if ( referenceTrackType === 'quaternion' ) { - - const referenceQuat = new Quaternion().fromArray( referenceValue ).normalize().conjugate(); - referenceQuat.toArray( referenceValue ); - - } - - // Subtract the reference value from all of the track values - - const numTimes = targetTrack.times.length; - for ( let j = 0; j < numTimes; ++ j ) { - - const valueStart = j * targetValueSize + targetOffset; - - if ( referenceTrackType === 'quaternion' ) { - - // Multiply the conjugate for quaternion track types - Quaternion.multiplyQuaternionsFlat( - targetTrack.values, - valueStart, - referenceValue, - 0, - targetTrack.values, - valueStart - ); - - } else { - - const valueEnd = targetValueSize - targetOffset * 2; - - // Subtract each value for all other numeric track types - for ( let k = 0; k < valueEnd; ++ k ) { - - targetTrack.values[ valueStart + k ] -= referenceValue[ k ]; - - } - - } - - } - - } - - targetClip.blendMode = AdditiveAnimationBlendMode; - - return targetClip; - -} - -const AnimationUtils = { - convertArray: convertArray, - isTypedArray: isTypedArray, - getKeyframeOrder: getKeyframeOrder, - sortedArray: sortedArray, - flattenJSON: flattenJSON, - subclip: subclip, - makeClipAdditive: makeClipAdditive -}; - -/** - * Abstract base class of interpolants over parametric samples. - * - * The parameter domain is one dimensional, typically the time or a path - * along a curve defined by the data. - * - * The sample values can have any dimensionality and derived classes may - * apply special interpretations to the data. - * - * This class provides the interval seek in a Template Method, deferring - * the actual interpolation to derived classes. - * - * Time complexity is O(1) for linear access crossing at most two points - * and O(log N) for random access, where N is the number of positions. - * - * References: - * - * http://www.oodesign.com/template-method-pattern.html - * - */ - -class Interpolant { - - constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) { - - this.parameterPositions = parameterPositions; - this._cachedIndex = 0; - - this.resultBuffer = resultBuffer !== undefined ? - resultBuffer : new sampleValues.constructor( sampleSize ); - this.sampleValues = sampleValues; - this.valueSize = sampleSize; - - this.settings = null; - this.DefaultSettings_ = {}; - - } - - evaluate( t ) { - - const pp = this.parameterPositions; - let i1 = this._cachedIndex, - t1 = pp[ i1 ], - t0 = pp[ i1 - 1 ]; - - validate_interval: { - - seek: { - - let right; - - linear_scan: { - - //- See http://jsperf.com/comparison-to-undefined/3 - //- slower code: - //- - //- if ( t >= t1 || t1 === undefined ) { - forward_scan: if ( ! ( t < t1 ) ) { - - for ( let giveUpAt = i1 + 2; ; ) { - - if ( t1 === undefined ) { - - if ( t < t0 ) break forward_scan; - - // after end - - i1 = pp.length; - this._cachedIndex = i1; - return this.copySampleValue_( i1 - 1 ); - - } - - if ( i1 === giveUpAt ) break; // this loop - - t0 = t1; - t1 = pp[ ++ i1 ]; - - if ( t < t1 ) { - - // we have arrived at the sought interval - break seek; - - } - - } - - // prepare binary search on the right side of the index - right = pp.length; - break linear_scan; - - } - - //- slower code: - //- if ( t < t0 || t0 === undefined ) { - if ( ! ( t >= t0 ) ) { - - // looping? - - const t1global = pp[ 1 ]; - - if ( t < t1global ) { - - i1 = 2; // + 1, using the scan for the details - t0 = t1global; - - } - - // linear reverse scan - - for ( let giveUpAt = i1 - 2; ; ) { - - if ( t0 === undefined ) { - - // before start - - this._cachedIndex = 0; - return this.copySampleValue_( 0 ); - - } - - if ( i1 === giveUpAt ) break; // this loop - - t1 = t0; - t0 = pp[ -- i1 - 1 ]; - - if ( t >= t0 ) { - - // we have arrived at the sought interval - break seek; - - } - - } - - // prepare binary search on the left side of the index - right = i1; - i1 = 0; - break linear_scan; - - } - - // the interval is valid - - break validate_interval; - - } // linear scan - - // binary search - - while ( i1 < right ) { - - const mid = ( i1 + right ) >>> 1; - - if ( t < pp[ mid ] ) { - - right = mid; - - } else { - - i1 = mid + 1; - - } - - } - - t1 = pp[ i1 ]; - t0 = pp[ i1 - 1 ]; - - // check boundary cases, again - - if ( t0 === undefined ) { - - this._cachedIndex = 0; - return this.copySampleValue_( 0 ); - - } - - if ( t1 === undefined ) { - - i1 = pp.length; - this._cachedIndex = i1; - return this.copySampleValue_( i1 - 1 ); - - } - - } // seek - - this._cachedIndex = i1; - - this.intervalChanged_( i1, t0, t1 ); - - } // validate_interval - - return this.interpolate_( i1, t0, t, t1 ); - - } - - getSettings_() { - - return this.settings || this.DefaultSettings_; - - } - - copySampleValue_( index ) { - - // copies a sample value to the result buffer - - const result = this.resultBuffer, - values = this.sampleValues, - stride = this.valueSize, - offset = index * stride; - - for ( let i = 0; i !== stride; ++ i ) { - - result[ i ] = values[ offset + i ]; - - } - - return result; - - } - - // Template methods for derived classes: - - interpolate_( /* i1, t0, t, t1 */ ) { - - throw new Error( 'call to abstract method' ); - // implementations shall return this.resultBuffer - - } - - intervalChanged_( /* i1, t0, t1 */ ) { - - // empty - - } - -} - -/** - * Fast and simple cubic spline interpolant. - * - * It was derived from a Hermitian construction setting the first derivative - * at each sample position to the linear slope between neighboring positions - * over their parameter interval. - */ - -class CubicInterpolant extends Interpolant { - - constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) { - - super( parameterPositions, sampleValues, sampleSize, resultBuffer ); - - this._weightPrev = - 0; - this._offsetPrev = - 0; - this._weightNext = - 0; - this._offsetNext = - 0; - - this.DefaultSettings_ = { - - endingStart: ZeroCurvatureEnding, - endingEnd: ZeroCurvatureEnding - - }; - - } - - intervalChanged_( i1, t0, t1 ) { - - const pp = this.parameterPositions; - let iPrev = i1 - 2, - iNext = i1 + 1, - - tPrev = pp[ iPrev ], - tNext = pp[ iNext ]; - - if ( tPrev === undefined ) { - - switch ( this.getSettings_().endingStart ) { - - case ZeroSlopeEnding: - - // f'(t0) = 0 - iPrev = i1; - tPrev = 2 * t0 - t1; - - break; - - case WrapAroundEnding: - - // use the other end of the curve - iPrev = pp.length - 2; - tPrev = t0 + pp[ iPrev ] - pp[ iPrev + 1 ]; - - break; - - default: // ZeroCurvatureEnding - - // f''(t0) = 0 a.k.a. Natural Spline - iPrev = i1; - tPrev = t1; - - } - - } - - if ( tNext === undefined ) { - - switch ( this.getSettings_().endingEnd ) { - - case ZeroSlopeEnding: - - // f'(tN) = 0 - iNext = i1; - tNext = 2 * t1 - t0; - - break; - - case WrapAroundEnding: - - // use the other end of the curve - iNext = 1; - tNext = t1 + pp[ 1 ] - pp[ 0 ]; - - break; - - default: // ZeroCurvatureEnding - - // f''(tN) = 0, a.k.a. Natural Spline - iNext = i1 - 1; - tNext = t0; - - } - - } - - const halfDt = ( t1 - t0 ) * 0.5, - stride = this.valueSize; - - this._weightPrev = halfDt / ( t0 - tPrev ); - this._weightNext = halfDt / ( tNext - t1 ); - this._offsetPrev = iPrev * stride; - this._offsetNext = iNext * stride; - - } - - interpolate_( i1, t0, t, t1 ) { - - const result = this.resultBuffer, - values = this.sampleValues, - stride = this.valueSize, - - o1 = i1 * stride, o0 = o1 - stride, - oP = this._offsetPrev, oN = this._offsetNext, - wP = this._weightPrev, wN = this._weightNext, - - p = ( t - t0 ) / ( t1 - t0 ), - pp = p * p, - ppp = pp * p; - - // evaluate polynomials - - const sP = - wP * ppp + 2 * wP * pp - wP * p; - const s0 = ( 1 + wP ) * ppp + ( - 1.5 - 2 * wP ) * pp + ( - 0.5 + wP ) * p + 1; - const s1 = ( - 1 - wN ) * ppp + ( 1.5 + wN ) * pp + 0.5 * p; - const sN = wN * ppp - wN * pp; - - // combine data linearly - - for ( let i = 0; i !== stride; ++ i ) { - - result[ i ] = - sP * values[ oP + i ] + - s0 * values[ o0 + i ] + - s1 * values[ o1 + i ] + - sN * values[ oN + i ]; - - } - - return result; - - } - -} - -class LinearInterpolant extends Interpolant { - - constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) { - - super( parameterPositions, sampleValues, sampleSize, resultBuffer ); - - } - - interpolate_( i1, t0, t, t1 ) { - - const result = this.resultBuffer, - values = this.sampleValues, - stride = this.valueSize, - - offset1 = i1 * stride, - offset0 = offset1 - stride, - - weight1 = ( t - t0 ) / ( t1 - t0 ), - weight0 = 1 - weight1; - - for ( let i = 0; i !== stride; ++ i ) { - - result[ i ] = - values[ offset0 + i ] * weight0 + - values[ offset1 + i ] * weight1; - - } - - return result; - - } - -} - -/** - * - * Interpolant that evaluates to the sample value at the position preceding - * the parameter. - */ - -class DiscreteInterpolant extends Interpolant { - - constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) { - - super( parameterPositions, sampleValues, sampleSize, resultBuffer ); - - } - - interpolate_( i1 /*, t0, t, t1 */ ) { - - return this.copySampleValue_( i1 - 1 ); - - } - -} - -class KeyframeTrack { - - constructor( name, times, values, interpolation ) { - - if ( name === undefined ) throw new Error( 'THREE.KeyframeTrack: track name is undefined' ); - if ( times === undefined || times.length === 0 ) throw new Error( 'THREE.KeyframeTrack: no keyframes in track named ' + name ); - - this.name = name; - - this.times = convertArray( times, this.TimeBufferType ); - this.values = convertArray( values, this.ValueBufferType ); - - this.setInterpolation( interpolation || this.DefaultInterpolation ); - - } - - // Serialization (in static context, because of constructor invocation - // and automatic invocation of .toJSON): - - static toJSON( track ) { - - const trackType = track.constructor; - - let json; - - // derived classes can define a static toJSON method - if ( trackType.toJSON !== this.toJSON ) { - - json = trackType.toJSON( track ); - - } else { - - // by default, we assume the data can be serialized as-is - json = { - - 'name': track.name, - 'times': convertArray( track.times, Array ), - 'values': convertArray( track.values, Array ) - - }; - - const interpolation = track.getInterpolation(); - - if ( interpolation !== track.DefaultInterpolation ) { - - json.interpolation = interpolation; - - } - - } - - json.type = track.ValueTypeName; // mandatory - - return json; - - } - - InterpolantFactoryMethodDiscrete( result ) { - - return new DiscreteInterpolant( this.times, this.values, this.getValueSize(), result ); - - } - - InterpolantFactoryMethodLinear( result ) { - - return new LinearInterpolant( this.times, this.values, this.getValueSize(), result ); - - } - - InterpolantFactoryMethodSmooth( result ) { - - return new CubicInterpolant( this.times, this.values, this.getValueSize(), result ); - - } - - setInterpolation( interpolation ) { - - let factoryMethod; - - switch ( interpolation ) { - - case InterpolateDiscrete: - - factoryMethod = this.InterpolantFactoryMethodDiscrete; - - break; - - case InterpolateLinear: - - factoryMethod = this.InterpolantFactoryMethodLinear; - - break; - - case InterpolateSmooth: - - factoryMethod = this.InterpolantFactoryMethodSmooth; - - break; - - } - - if ( factoryMethod === undefined ) { - - const message = 'unsupported interpolation for ' + - this.ValueTypeName + ' keyframe track named ' + this.name; - - if ( this.createInterpolant === undefined ) { - - // fall back to default, unless the default itself is messed up - if ( interpolation !== this.DefaultInterpolation ) { - - this.setInterpolation( this.DefaultInterpolation ); - - } else { - - throw new Error( message ); // fatal, in this case - - } - - } - - console.warn( 'THREE.KeyframeTrack:', message ); - return this; - - } - - this.createInterpolant = factoryMethod; - - return this; - - } - - getInterpolation() { - - switch ( this.createInterpolant ) { - - case this.InterpolantFactoryMethodDiscrete: - - return InterpolateDiscrete; - - case this.InterpolantFactoryMethodLinear: - - return InterpolateLinear; - - case this.InterpolantFactoryMethodSmooth: - - return InterpolateSmooth; - - } - - } - - getValueSize() { - - return this.values.length / this.times.length; - - } - - // move all keyframes either forwards or backwards in time - shift( timeOffset ) { - - if ( timeOffset !== 0.0 ) { - - const times = this.times; - - for ( let i = 0, n = times.length; i !== n; ++ i ) { - - times[ i ] += timeOffset; - - } - - } - - return this; - - } - - // scale all keyframe times by a factor (useful for frame <-> seconds conversions) - scale( timeScale ) { - - if ( timeScale !== 1.0 ) { - - const times = this.times; - - for ( let i = 0, n = times.length; i !== n; ++ i ) { - - times[ i ] *= timeScale; - - } - - } - - return this; - - } - - // removes keyframes before and after animation without changing any values within the range [startTime, endTime]. - // IMPORTANT: We do not shift around keys to the start of the track time, because for interpolated keys this will change their values - trim( startTime, endTime ) { - - const times = this.times, - nKeys = times.length; - - let from = 0, - to = nKeys - 1; - - while ( from !== nKeys && times[ from ] < startTime ) { - - ++ from; - - } - - while ( to !== - 1 && times[ to ] > endTime ) { - - -- to; - - } - - ++ to; // inclusive -> exclusive bound - - if ( from !== 0 || to !== nKeys ) { - - // empty tracks are forbidden, so keep at least one keyframe - if ( from >= to ) { - - to = Math.max( to, 1 ); - from = to - 1; - - } - - const stride = this.getValueSize(); - this.times = times.slice( from, to ); - this.values = this.values.slice( from * stride, to * stride ); - - } - - return this; - - } - - // ensure we do not get a GarbageInGarbageOut situation, make sure tracks are at least minimally viable - validate() { - - let valid = true; - - const valueSize = this.getValueSize(); - if ( valueSize - Math.floor( valueSize ) !== 0 ) { - - console.error( 'THREE.KeyframeTrack: Invalid value size in track.', this ); - valid = false; - - } - - const times = this.times, - values = this.values, - - nKeys = times.length; - - if ( nKeys === 0 ) { - - console.error( 'THREE.KeyframeTrack: Track is empty.', this ); - valid = false; - - } - - let prevTime = null; - - for ( let i = 0; i !== nKeys; i ++ ) { - - const currTime = times[ i ]; - - if ( typeof currTime === 'number' && isNaN( currTime ) ) { - - console.error( 'THREE.KeyframeTrack: Time is not a valid number.', this, i, currTime ); - valid = false; - break; - - } - - if ( prevTime !== null && prevTime > currTime ) { - - console.error( 'THREE.KeyframeTrack: Out of order keys.', this, i, currTime, prevTime ); - valid = false; - break; - - } - - prevTime = currTime; - - } - - if ( values !== undefined ) { - - if ( isTypedArray( values ) ) { - - for ( let i = 0, n = values.length; i !== n; ++ i ) { - - const value = values[ i ]; - - if ( isNaN( value ) ) { - - console.error( 'THREE.KeyframeTrack: Value is not a valid number.', this, i, value ); - valid = false; - break; - - } - - } - - } - - } - - return valid; - - } - - // removes equivalent sequential keys as common in morph target sequences - // (0,0,0,0,1,1,1,0,0,0,0,0,0,0) --> (0,0,1,1,0,0) - optimize() { - - // times or values may be shared with other tracks, so overwriting is unsafe - const times = this.times.slice(), - values = this.values.slice(), - stride = this.getValueSize(), - - smoothInterpolation = this.getInterpolation() === InterpolateSmooth, - - lastIndex = times.length - 1; - - let writeIndex = 1; - - for ( let i = 1; i < lastIndex; ++ i ) { - - let keep = false; - - const time = times[ i ]; - const timeNext = times[ i + 1 ]; - - // remove adjacent keyframes scheduled at the same time - - if ( time !== timeNext && ( i !== 1 || time !== times[ 0 ] ) ) { - - if ( ! smoothInterpolation ) { - - // remove unnecessary keyframes same as their neighbors - - const offset = i * stride, - offsetP = offset - stride, - offsetN = offset + stride; - - for ( let j = 0; j !== stride; ++ j ) { - - const value = values[ offset + j ]; - - if ( value !== values[ offsetP + j ] || - value !== values[ offsetN + j ] ) { - - keep = true; - break; - - } - - } - - } else { - - keep = true; - - } - - } - - // in-place compaction - - if ( keep ) { - - if ( i !== writeIndex ) { - - times[ writeIndex ] = times[ i ]; - - const readOffset = i * stride, - writeOffset = writeIndex * stride; - - for ( let j = 0; j !== stride; ++ j ) { - - values[ writeOffset + j ] = values[ readOffset + j ]; - - } - - } - - ++ writeIndex; - - } - - } - - // flush last keyframe (compaction looks ahead) - - if ( lastIndex > 0 ) { - - times[ writeIndex ] = times[ lastIndex ]; - - for ( let readOffset = lastIndex * stride, writeOffset = writeIndex * stride, j = 0; j !== stride; ++ j ) { - - values[ writeOffset + j ] = values[ readOffset + j ]; - - } - - ++ writeIndex; - - } - - if ( writeIndex !== times.length ) { - - this.times = times.slice( 0, writeIndex ); - this.values = values.slice( 0, writeIndex * stride ); - - } else { - - this.times = times; - this.values = values; - - } - - return this; - - } - - clone() { - - const times = this.times.slice(); - const values = this.values.slice(); - - const TypedKeyframeTrack = this.constructor; - const track = new TypedKeyframeTrack( this.name, times, values ); - - // Interpolant argument to constructor is not saved, so copy the factory method directly. - track.createInterpolant = this.createInterpolant; - - return track; - - } - -} - -KeyframeTrack.prototype.TimeBufferType = Float32Array; -KeyframeTrack.prototype.ValueBufferType = Float32Array; -KeyframeTrack.prototype.DefaultInterpolation = InterpolateLinear; - -/** - * A Track of Boolean keyframe values. - */ -class BooleanKeyframeTrack extends KeyframeTrack {} - -BooleanKeyframeTrack.prototype.ValueTypeName = 'bool'; -BooleanKeyframeTrack.prototype.ValueBufferType = Array; -BooleanKeyframeTrack.prototype.DefaultInterpolation = InterpolateDiscrete; -BooleanKeyframeTrack.prototype.InterpolantFactoryMethodLinear = undefined; -BooleanKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = undefined; - -/** - * A Track of keyframe values that represent color. - */ -class ColorKeyframeTrack extends KeyframeTrack {} - -ColorKeyframeTrack.prototype.ValueTypeName = 'color'; - -/** - * A Track of numeric keyframe values. - */ -class NumberKeyframeTrack extends KeyframeTrack {} - -NumberKeyframeTrack.prototype.ValueTypeName = 'number'; - -/** - * Spherical linear unit quaternion interpolant. - */ - -class QuaternionLinearInterpolant extends Interpolant { - - constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) { - - super( parameterPositions, sampleValues, sampleSize, resultBuffer ); - - } - - interpolate_( i1, t0, t, t1 ) { - - const result = this.resultBuffer, - values = this.sampleValues, - stride = this.valueSize, - - alpha = ( t - t0 ) / ( t1 - t0 ); - - let offset = i1 * stride; - - for ( let end = offset + stride; offset !== end; offset += 4 ) { - - Quaternion.slerpFlat( result, 0, values, offset - stride, values, offset, alpha ); - - } - - return result; - - } - -} - -/** - * A Track of quaternion keyframe values. - */ -class QuaternionKeyframeTrack extends KeyframeTrack { - - InterpolantFactoryMethodLinear( result ) { - - return new QuaternionLinearInterpolant( this.times, this.values, this.getValueSize(), result ); - - } - -} - -QuaternionKeyframeTrack.prototype.ValueTypeName = 'quaternion'; -// ValueBufferType is inherited -QuaternionKeyframeTrack.prototype.DefaultInterpolation = InterpolateLinear; -QuaternionKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = undefined; - -/** - * A Track that interpolates Strings - */ -class StringKeyframeTrack extends KeyframeTrack {} - -StringKeyframeTrack.prototype.ValueTypeName = 'string'; -StringKeyframeTrack.prototype.ValueBufferType = Array; -StringKeyframeTrack.prototype.DefaultInterpolation = InterpolateDiscrete; -StringKeyframeTrack.prototype.InterpolantFactoryMethodLinear = undefined; -StringKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = undefined; - -/** - * A Track of vectored keyframe values. - */ -class VectorKeyframeTrack extends KeyframeTrack {} - -VectorKeyframeTrack.prototype.ValueTypeName = 'vector'; - -class AnimationClip { - - constructor( name, duration = - 1, tracks, blendMode = NormalAnimationBlendMode ) { - - this.name = name; - this.tracks = tracks; - this.duration = duration; - this.blendMode = blendMode; - - this.uuid = generateUUID(); - - // this means it should figure out its duration by scanning the tracks - if ( this.duration < 0 ) { - - this.resetDuration(); - - } - - } - - - static parse( json ) { - - const tracks = [], - jsonTracks = json.tracks, - frameTime = 1.0 / ( json.fps || 1.0 ); - - for ( let i = 0, n = jsonTracks.length; i !== n; ++ i ) { - - tracks.push( parseKeyframeTrack( jsonTracks[ i ] ).scale( frameTime ) ); - - } - - const clip = new this( json.name, json.duration, tracks, json.blendMode ); - clip.uuid = json.uuid; - - return clip; - - } - - static toJSON( clip ) { - - const tracks = [], - clipTracks = clip.tracks; - - const json = { - - 'name': clip.name, - 'duration': clip.duration, - 'tracks': tracks, - 'uuid': clip.uuid, - 'blendMode': clip.blendMode - - }; - - for ( let i = 0, n = clipTracks.length; i !== n; ++ i ) { - - tracks.push( KeyframeTrack.toJSON( clipTracks[ i ] ) ); - - } - - return json; - - } - - static CreateFromMorphTargetSequence( name, morphTargetSequence, fps, noLoop ) { - - const numMorphTargets = morphTargetSequence.length; - const tracks = []; - - for ( let i = 0; i < numMorphTargets; i ++ ) { - - let times = []; - let values = []; - - times.push( - ( i + numMorphTargets - 1 ) % numMorphTargets, - i, - ( i + 1 ) % numMorphTargets ); - - values.push( 0, 1, 0 ); - - const order = getKeyframeOrder( times ); - times = sortedArray( times, 1, order ); - values = sortedArray( values, 1, order ); - - // if there is a key at the first frame, duplicate it as the - // last frame as well for perfect loop. - if ( ! noLoop && times[ 0 ] === 0 ) { - - times.push( numMorphTargets ); - values.push( values[ 0 ] ); - - } - - tracks.push( - new NumberKeyframeTrack( - '.morphTargetInfluences[' + morphTargetSequence[ i ].name + ']', - times, values - ).scale( 1.0 / fps ) ); - - } - - return new this( name, - 1, tracks ); - - } - - static findByName( objectOrClipArray, name ) { - - let clipArray = objectOrClipArray; - - if ( ! Array.isArray( objectOrClipArray ) ) { - - const o = objectOrClipArray; - clipArray = o.geometry && o.geometry.animations || o.animations; - - } - - for ( let i = 0; i < clipArray.length; i ++ ) { - - if ( clipArray[ i ].name === name ) { - - return clipArray[ i ]; - - } - - } - - return null; - - } - - static CreateClipsFromMorphTargetSequences( morphTargets, fps, noLoop ) { - - const animationToMorphTargets = {}; - - // tested with https://regex101.com/ on trick sequences - // such flamingo_flyA_003, flamingo_run1_003, crdeath0059 - const pattern = /^([\w-]*?)([\d]+)$/; - - // sort morph target names into animation groups based - // patterns like Walk_001, Walk_002, Run_001, Run_002 - for ( let i = 0, il = morphTargets.length; i < il; i ++ ) { - - const morphTarget = morphTargets[ i ]; - const parts = morphTarget.name.match( pattern ); - - if ( parts && parts.length > 1 ) { - - const name = parts[ 1 ]; - - let animationMorphTargets = animationToMorphTargets[ name ]; - - if ( ! animationMorphTargets ) { - - animationToMorphTargets[ name ] = animationMorphTargets = []; - - } - - animationMorphTargets.push( morphTarget ); - - } - - } - - const clips = []; - - for ( const name in animationToMorphTargets ) { - - clips.push( this.CreateFromMorphTargetSequence( name, animationToMorphTargets[ name ], fps, noLoop ) ); - - } - - return clips; - - } - - // parse the animation.hierarchy format - static parseAnimation( animation, bones ) { - - if ( ! animation ) { - - console.error( 'THREE.AnimationClip: No animation in JSONLoader data.' ); - return null; - - } - - const addNonemptyTrack = function ( trackType, trackName, animationKeys, propertyName, destTracks ) { - - // only return track if there are actually keys. - if ( animationKeys.length !== 0 ) { - - const times = []; - const values = []; - - flattenJSON( animationKeys, times, values, propertyName ); - - // empty keys are filtered out, so check again - if ( times.length !== 0 ) { - - destTracks.push( new trackType( trackName, times, values ) ); - - } - - } - - }; - - const tracks = []; - - const clipName = animation.name || 'default'; - const fps = animation.fps || 30; - const blendMode = animation.blendMode; - - // automatic length determination in AnimationClip. - let duration = animation.length || - 1; - - const hierarchyTracks = animation.hierarchy || []; - - for ( let h = 0; h < hierarchyTracks.length; h ++ ) { - - const animationKeys = hierarchyTracks[ h ].keys; - - // skip empty tracks - if ( ! animationKeys || animationKeys.length === 0 ) continue; - - // process morph targets - if ( animationKeys[ 0 ].morphTargets ) { - - // figure out all morph targets used in this track - const morphTargetNames = {}; - - let k; - - for ( k = 0; k < animationKeys.length; k ++ ) { - - if ( animationKeys[ k ].morphTargets ) { - - for ( let m = 0; m < animationKeys[ k ].morphTargets.length; m ++ ) { - - morphTargetNames[ animationKeys[ k ].morphTargets[ m ] ] = - 1; - - } - - } - - } - - // create a track for each morph target with all zero - // morphTargetInfluences except for the keys in which - // the morphTarget is named. - for ( const morphTargetName in morphTargetNames ) { - - const times = []; - const values = []; - - for ( let m = 0; m !== animationKeys[ k ].morphTargets.length; ++ m ) { - - const animationKey = animationKeys[ k ]; - - times.push( animationKey.time ); - values.push( ( animationKey.morphTarget === morphTargetName ) ? 1 : 0 ); - - } - - tracks.push( new NumberKeyframeTrack( '.morphTargetInfluence[' + morphTargetName + ']', times, values ) ); - - } - - duration = morphTargetNames.length * fps; - - } else { - - // ...assume skeletal animation - - const boneName = '.bones[' + bones[ h ].name + ']'; - - addNonemptyTrack( - VectorKeyframeTrack, boneName + '.position', - animationKeys, 'pos', tracks ); - - addNonemptyTrack( - QuaternionKeyframeTrack, boneName + '.quaternion', - animationKeys, 'rot', tracks ); - - addNonemptyTrack( - VectorKeyframeTrack, boneName + '.scale', - animationKeys, 'scl', tracks ); - - } - - } - - if ( tracks.length === 0 ) { - - return null; - - } - - const clip = new this( clipName, duration, tracks, blendMode ); - - return clip; - - } - - resetDuration() { - - const tracks = this.tracks; - let duration = 0; - - for ( let i = 0, n = tracks.length; i !== n; ++ i ) { - - const track = this.tracks[ i ]; - - duration = Math.max( duration, track.times[ track.times.length - 1 ] ); - - } - - this.duration = duration; - - return this; - - } - - trim() { - - for ( let i = 0; i < this.tracks.length; i ++ ) { - - this.tracks[ i ].trim( 0, this.duration ); - - } - - return this; - - } - - validate() { - - let valid = true; - - for ( let i = 0; i < this.tracks.length; i ++ ) { - - valid = valid && this.tracks[ i ].validate(); - - } - - return valid; - - } - - optimize() { - - for ( let i = 0; i < this.tracks.length; i ++ ) { - - this.tracks[ i ].optimize(); - - } - - return this; - - } - - clone() { - - const tracks = []; - - for ( let i = 0; i < this.tracks.length; i ++ ) { - - tracks.push( this.tracks[ i ].clone() ); - - } - - return new this.constructor( this.name, this.duration, tracks, this.blendMode ); - - } - - toJSON() { - - return this.constructor.toJSON( this ); - - } - -} - -function getTrackTypeForValueTypeName( typeName ) { - - switch ( typeName.toLowerCase() ) { - - case 'scalar': - case 'double': - case 'float': - case 'number': - case 'integer': - - return NumberKeyframeTrack; - - case 'vector': - case 'vector2': - case 'vector3': - case 'vector4': - - return VectorKeyframeTrack; - - case 'color': - - return ColorKeyframeTrack; - - case 'quaternion': - - return QuaternionKeyframeTrack; - - case 'bool': - case 'boolean': - - return BooleanKeyframeTrack; - - case 'string': - - return StringKeyframeTrack; - - } - - throw new Error( 'THREE.KeyframeTrack: Unsupported typeName: ' + typeName ); - -} - -function parseKeyframeTrack( json ) { - - if ( json.type === undefined ) { - - throw new Error( 'THREE.KeyframeTrack: track type undefined, can not parse' ); - - } - - const trackType = getTrackTypeForValueTypeName( json.type ); - - if ( json.times === undefined ) { - - const times = [], values = []; - - flattenJSON( json.keys, times, values, 'value' ); - - json.times = times; - json.values = values; - - } - - // derived classes can define a static parse method - if ( trackType.parse !== undefined ) { - - return trackType.parse( json ); - - } else { - - // by default, we assume a constructor compatible with the base - return new trackType( json.name, json.times, json.values, json.interpolation ); - - } - -} - -const Cache = { - - enabled: false, - - files: {}, - - add: function ( key, file ) { - - if ( this.enabled === false ) return; - - // console.log( 'THREE.Cache', 'Adding key:', key ); - - this.files[ key ] = file; - - }, - - get: function ( key ) { - - if ( this.enabled === false ) return; - - // console.log( 'THREE.Cache', 'Checking key:', key ); - - return this.files[ key ]; - - }, - - remove: function ( key ) { - - delete this.files[ key ]; - - }, - - clear: function () { - - this.files = {}; - - } - -}; - -class LoadingManager { - - constructor( onLoad, onProgress, onError ) { - - const scope = this; - - let isLoading = false; - let itemsLoaded = 0; - let itemsTotal = 0; - let urlModifier = undefined; - const handlers = []; - - // Refer to #5689 for the reason why we don't set .onStart - // in the constructor - - this.onStart = undefined; - this.onLoad = onLoad; - this.onProgress = onProgress; - this.onError = onError; - - this.itemStart = function ( url ) { - - itemsTotal ++; - - if ( isLoading === false ) { - - if ( scope.onStart !== undefined ) { - - scope.onStart( url, itemsLoaded, itemsTotal ); - - } - - } - - isLoading = true; - - }; - - this.itemEnd = function ( url ) { - - itemsLoaded ++; - - if ( scope.onProgress !== undefined ) { - - scope.onProgress( url, itemsLoaded, itemsTotal ); - - } - - if ( itemsLoaded === itemsTotal ) { - - isLoading = false; - - if ( scope.onLoad !== undefined ) { - - scope.onLoad(); - - } - - } - - }; - - this.itemError = function ( url ) { - - if ( scope.onError !== undefined ) { - - scope.onError( url ); - - } - - }; - - this.resolveURL = function ( url ) { - - if ( urlModifier ) { - - return urlModifier( url ); - - } - - return url; - - }; - - this.setURLModifier = function ( transform ) { - - urlModifier = transform; - - return this; - - }; - - this.addHandler = function ( regex, loader ) { - - handlers.push( regex, loader ); - - return this; - - }; - - this.removeHandler = function ( regex ) { - - const index = handlers.indexOf( regex ); - - if ( index !== - 1 ) { - - handlers.splice( index, 2 ); - - } - - return this; - - }; - - this.getHandler = function ( file ) { - - for ( let i = 0, l = handlers.length; i < l; i += 2 ) { - - const regex = handlers[ i ]; - const loader = handlers[ i + 1 ]; - - if ( regex.global ) regex.lastIndex = 0; // see #17920 - - if ( regex.test( file ) ) { - - return loader; - - } - - } - - return null; - - }; - - } - -} - -const DefaultLoadingManager = /*@__PURE__*/ new LoadingManager(); - -class Loader { - - constructor( manager ) { - - this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; - - this.crossOrigin = 'anonymous'; - this.withCredentials = false; - this.path = ''; - this.resourcePath = ''; - this.requestHeader = {}; - - } - - load( /* url, onLoad, onProgress, onError */ ) {} - - loadAsync( url, onProgress ) { - - const scope = this; - - return new Promise( function ( resolve, reject ) { - - scope.load( url, resolve, onProgress, reject ); - - } ); - - } - - parse( /* data */ ) {} - - setCrossOrigin( crossOrigin ) { - - this.crossOrigin = crossOrigin; - return this; - - } - - setWithCredentials( value ) { - - this.withCredentials = value; - return this; - - } - - setPath( path ) { - - this.path = path; - return this; - - } - - setResourcePath( resourcePath ) { - - this.resourcePath = resourcePath; - return this; - - } - - setRequestHeader( requestHeader ) { - - this.requestHeader = requestHeader; - return this; - - } - -} - -Loader.DEFAULT_MATERIAL_NAME = '__DEFAULT'; - -const loading = {}; - -class HttpError extends Error { - - constructor( message, response ) { - - super( message ); - this.response = response; - - } - -} - -class FileLoader extends Loader { - - constructor( manager ) { - - super( manager ); - - } - - load( url, onLoad, onProgress, onError ) { - - if ( url === undefined ) url = ''; - - if ( this.path !== undefined ) url = this.path + url; - - url = this.manager.resolveURL( url ); - - const cached = Cache.get( url ); - - if ( cached !== undefined ) { - - this.manager.itemStart( url ); - - setTimeout( () => { - - if ( onLoad ) onLoad( cached ); - - this.manager.itemEnd( url ); - - }, 0 ); - - return cached; - - } - - // Check if request is duplicate - - if ( loading[ url ] !== undefined ) { - - loading[ url ].push( { - - onLoad: onLoad, - onProgress: onProgress, - onError: onError - - } ); - - return; - - } - - // Initialise array for duplicate requests - loading[ url ] = []; - - loading[ url ].push( { - onLoad: onLoad, - onProgress: onProgress, - onError: onError, - } ); - - // create request - const req = new Request( url, { - headers: new Headers( this.requestHeader ), - credentials: this.withCredentials ? 'include' : 'same-origin', - // An abort controller could be added within a future PR - } ); - - // record states ( avoid data race ) - const mimeType = this.mimeType; - const responseType = this.responseType; - - // start the fetch - fetch( req ) - .then( response => { - - if ( response.status === 200 || response.status === 0 ) { - - // Some browsers return HTTP Status 0 when using non-http protocol - // e.g. 'file://' or 'data://'. Handle as success. - - if ( response.status === 0 ) { - - console.warn( 'THREE.FileLoader: HTTP Status 0 received.' ); - - } - - // Workaround: Checking if response.body === undefined for Alipay browser #23548 - - if ( typeof ReadableStream === 'undefined' || response.body === undefined || response.body.getReader === undefined ) { - - return response; - - } - - const callbacks = loading[ url ]; - const reader = response.body.getReader(); - - // Nginx needs X-File-Size check - // https://serverfault.com/questions/482875/why-does-nginx-remove-content-length-header-for-chunked-content - const contentLength = response.headers.get( 'Content-Length' ) || response.headers.get( 'X-File-Size' ); - const total = contentLength ? parseInt( contentLength ) : 0; - const lengthComputable = total !== 0; - let loaded = 0; - - // periodically read data into the new stream tracking while download progress - const stream = new ReadableStream( { - start( controller ) { - - readData(); - - function readData() { - - reader.read().then( ( { done, value } ) => { - - if ( done ) { - - controller.close(); - - } else { - - loaded += value.byteLength; - - const event = new ProgressEvent( 'progress', { lengthComputable, loaded, total } ); - for ( let i = 0, il = callbacks.length; i < il; i ++ ) { - - const callback = callbacks[ i ]; - if ( callback.onProgress ) callback.onProgress( event ); - - } - - controller.enqueue( value ); - readData(); - - } - - } ); - - } - - } - - } ); - - return new Response( stream ); - - } else { - - throw new HttpError( `fetch for "${response.url}" responded with ${response.status}: ${response.statusText}`, response ); - - } - - } ) - .then( response => { - - switch ( responseType ) { - - case 'arraybuffer': - - return response.arrayBuffer(); - - case 'blob': - - return response.blob(); - - case 'document': - - return response.text() - .then( text => { - - const parser = new DOMParser(); - return parser.parseFromString( text, mimeType ); - - } ); - - case 'json': - - return response.json(); - - default: - - if ( mimeType === undefined ) { - - return response.text(); - - } else { - - // sniff encoding - const re = /charset="?([^;"\s]*)"?/i; - const exec = re.exec( mimeType ); - const label = exec && exec[ 1 ] ? exec[ 1 ].toLowerCase() : undefined; - const decoder = new TextDecoder( label ); - return response.arrayBuffer().then( ab => decoder.decode( ab ) ); - - } - - } - - } ) - .then( data => { - - // Add to cache only on HTTP success, so that we do not cache - // error response bodies as proper responses to requests. - Cache.add( url, data ); - - const callbacks = loading[ url ]; - delete loading[ url ]; - - for ( let i = 0, il = callbacks.length; i < il; i ++ ) { - - const callback = callbacks[ i ]; - if ( callback.onLoad ) callback.onLoad( data ); - - } - - } ) - .catch( err => { - - // Abort errors and other errors are handled the same - - const callbacks = loading[ url ]; - - if ( callbacks === undefined ) { - - // When onLoad was called and url was deleted in `loading` - this.manager.itemError( url ); - throw err; - - } - - delete loading[ url ]; - - for ( let i = 0, il = callbacks.length; i < il; i ++ ) { - - const callback = callbacks[ i ]; - if ( callback.onError ) callback.onError( err ); - - } - - this.manager.itemError( url ); - - } ) - .finally( () => { - - this.manager.itemEnd( url ); - - } ); - - this.manager.itemStart( url ); - - } - - setResponseType( value ) { - - this.responseType = value; - return this; - - } - - setMimeType( value ) { - - this.mimeType = value; - return this; - - } - -} - -class AnimationLoader extends Loader { - - constructor( manager ) { - - super( manager ); - - } - - load( url, onLoad, onProgress, onError ) { - - const scope = this; - - const loader = new FileLoader( this.manager ); - loader.setPath( this.path ); - loader.setRequestHeader( this.requestHeader ); - loader.setWithCredentials( this.withCredentials ); - loader.load( url, function ( text ) { - - try { - - onLoad( scope.parse( JSON.parse( text ) ) ); - - } catch ( e ) { - - if ( onError ) { - - onError( e ); - - } else { - - console.error( e ); - - } - - scope.manager.itemError( url ); - - } - - }, onProgress, onError ); - - } - - parse( json ) { - - const animations = []; - - for ( let i = 0; i < json.length; i ++ ) { - - const clip = AnimationClip.parse( json[ i ] ); - - animations.push( clip ); - - } - - return animations; - - } - -} - -/** - * Abstract Base class to block based textures loader (dds, pvr, ...) - * - * Sub classes have to implement the parse() method which will be used in load(). - */ - -class CompressedTextureLoader extends Loader { - - constructor( manager ) { - - super( manager ); - - } - - load( url, onLoad, onProgress, onError ) { - - const scope = this; - - const images = []; - - const texture = new CompressedTexture(); - - const loader = new FileLoader( this.manager ); - loader.setPath( this.path ); - loader.setResponseType( 'arraybuffer' ); - loader.setRequestHeader( this.requestHeader ); - loader.setWithCredentials( scope.withCredentials ); - - let loaded = 0; - - function loadTexture( i ) { - - loader.load( url[ i ], function ( buffer ) { - - const texDatas = scope.parse( buffer, true ); - - images[ i ] = { - width: texDatas.width, - height: texDatas.height, - format: texDatas.format, - mipmaps: texDatas.mipmaps - }; - - loaded += 1; - - if ( loaded === 6 ) { - - if ( texDatas.mipmapCount === 1 ) texture.minFilter = LinearFilter; - - texture.image = images; - texture.format = texDatas.format; - texture.needsUpdate = true; - - if ( onLoad ) onLoad( texture ); - - } - - }, onProgress, onError ); - - } - - if ( Array.isArray( url ) ) { - - for ( let i = 0, il = url.length; i < il; ++ i ) { - - loadTexture( i ); - - } - - } else { - - // compressed cubemap texture stored in a single DDS file - - loader.load( url, function ( buffer ) { - - const texDatas = scope.parse( buffer, true ); - - if ( texDatas.isCubemap ) { - - const faces = texDatas.mipmaps.length / texDatas.mipmapCount; - - for ( let f = 0; f < faces; f ++ ) { - - images[ f ] = { mipmaps: [] }; - - for ( let i = 0; i < texDatas.mipmapCount; i ++ ) { - - images[ f ].mipmaps.push( texDatas.mipmaps[ f * texDatas.mipmapCount + i ] ); - images[ f ].format = texDatas.format; - images[ f ].width = texDatas.width; - images[ f ].height = texDatas.height; - - } - - } - - texture.image = images; - - } else { - - texture.image.width = texDatas.width; - texture.image.height = texDatas.height; - texture.mipmaps = texDatas.mipmaps; - - } - - if ( texDatas.mipmapCount === 1 ) { - - texture.minFilter = LinearFilter; - - } - - texture.format = texDatas.format; - texture.needsUpdate = true; - - if ( onLoad ) onLoad( texture ); - - }, onProgress, onError ); - - } - - return texture; - - } - -} - -class ImageLoader extends Loader { - - constructor( manager ) { - - super( manager ); - - } - - load( url, onLoad, onProgress, onError ) { - - if ( this.path !== undefined ) url = this.path + url; - - url = this.manager.resolveURL( url ); - - const scope = this; - - const cached = Cache.get( url ); - - if ( cached !== undefined ) { - - scope.manager.itemStart( url ); - - setTimeout( function () { - - if ( onLoad ) onLoad( cached ); - - scope.manager.itemEnd( url ); - - }, 0 ); - - return cached; - - } - - const image = createElementNS( 'img' ); - - function onImageLoad() { - - removeEventListeners(); - - Cache.add( url, this ); - - if ( onLoad ) onLoad( this ); - - scope.manager.itemEnd( url ); - - } - - function onImageError( event ) { - - removeEventListeners(); - - if ( onError ) onError( event ); - - scope.manager.itemError( url ); - scope.manager.itemEnd( url ); - - } - - function removeEventListeners() { - - image.removeEventListener( 'load', onImageLoad, false ); - image.removeEventListener( 'error', onImageError, false ); - - } - - image.addEventListener( 'load', onImageLoad, false ); - image.addEventListener( 'error', onImageError, false ); - - if ( url.slice( 0, 5 ) !== 'data:' ) { - - if ( this.crossOrigin !== undefined ) image.crossOrigin = this.crossOrigin; - - } - - scope.manager.itemStart( url ); - - image.src = url; - - return image; - - } - -} - -class CubeTextureLoader extends Loader { - - constructor( manager ) { - - super( manager ); - - } - - load( urls, onLoad, onProgress, onError ) { - - const texture = new CubeTexture(); - texture.colorSpace = SRGBColorSpace; - - const loader = new ImageLoader( this.manager ); - loader.setCrossOrigin( this.crossOrigin ); - loader.setPath( this.path ); - - let loaded = 0; - - function loadTexture( i ) { - - loader.load( urls[ i ], function ( image ) { - - texture.images[ i ] = image; - - loaded ++; - - if ( loaded === 6 ) { - - texture.needsUpdate = true; - - if ( onLoad ) onLoad( texture ); - - } - - }, undefined, onError ); - - } - - for ( let i = 0; i < urls.length; ++ i ) { - - loadTexture( i ); - - } - - return texture; - - } - -} - -/** - * Abstract Base class to load generic binary textures formats (rgbe, hdr, ...) - * - * Sub classes have to implement the parse() method which will be used in load(). - */ - -class DataTextureLoader extends Loader { - - constructor( manager ) { - - super( manager ); - - } - - load( url, onLoad, onProgress, onError ) { - - const scope = this; - - const texture = new DataTexture(); - - const loader = new FileLoader( this.manager ); - loader.setResponseType( 'arraybuffer' ); - loader.setRequestHeader( this.requestHeader ); - loader.setPath( this.path ); - loader.setWithCredentials( scope.withCredentials ); - loader.load( url, function ( buffer ) { - - let texData; - - try { - - texData = scope.parse( buffer ); - - } catch ( error ) { - - if ( onError !== undefined ) { - - onError( error ); - - } else { - - console.error( error ); - return; - - } - - } - - if ( texData.image !== undefined ) { - - texture.image = texData.image; - - } else if ( texData.data !== undefined ) { - - texture.image.width = texData.width; - texture.image.height = texData.height; - texture.image.data = texData.data; - - } - - texture.wrapS = texData.wrapS !== undefined ? texData.wrapS : ClampToEdgeWrapping; - texture.wrapT = texData.wrapT !== undefined ? texData.wrapT : ClampToEdgeWrapping; - - texture.magFilter = texData.magFilter !== undefined ? texData.magFilter : LinearFilter; - texture.minFilter = texData.minFilter !== undefined ? texData.minFilter : LinearFilter; - - texture.anisotropy = texData.anisotropy !== undefined ? texData.anisotropy : 1; - - if ( texData.colorSpace !== undefined ) { - - texture.colorSpace = texData.colorSpace; - - } - - if ( texData.flipY !== undefined ) { - - texture.flipY = texData.flipY; - - } - - if ( texData.format !== undefined ) { - - texture.format = texData.format; - - } - - if ( texData.type !== undefined ) { - - texture.type = texData.type; - - } - - if ( texData.mipmaps !== undefined ) { - - texture.mipmaps = texData.mipmaps; - texture.minFilter = LinearMipmapLinearFilter; // presumably... - - } - - if ( texData.mipmapCount === 1 ) { - - texture.minFilter = LinearFilter; - - } - - if ( texData.generateMipmaps !== undefined ) { - - texture.generateMipmaps = texData.generateMipmaps; - - } - - texture.needsUpdate = true; - - if ( onLoad ) onLoad( texture, texData ); - - }, onProgress, onError ); - - - return texture; - - } - -} - -class TextureLoader extends Loader { - - constructor( manager ) { - - super( manager ); - - } - - load( url, onLoad, onProgress, onError ) { - - const texture = new Texture(); - - const loader = new ImageLoader( this.manager ); - loader.setCrossOrigin( this.crossOrigin ); - loader.setPath( this.path ); - - loader.load( url, function ( image ) { - - texture.image = image; - texture.needsUpdate = true; - - if ( onLoad !== undefined ) { - - onLoad( texture ); - - } - - }, onProgress, onError ); - - return texture; - - } - -} - -class Light extends Object3D { - - constructor( color, intensity = 1 ) { - - super(); - - this.isLight = true; - - this.type = 'Light'; - - this.color = new Color( color ); - this.intensity = intensity; - - } - - dispose() { - - // Empty here in base class; some subclasses override. - - } - - copy( source, recursive ) { - - super.copy( source, recursive ); - - this.color.copy( source.color ); - this.intensity = source.intensity; - - return this; - - } - - toJSON( meta ) { - - const data = super.toJSON( meta ); - - data.object.color = this.color.getHex(); - data.object.intensity = this.intensity; - - if ( this.groundColor !== undefined ) data.object.groundColor = this.groundColor.getHex(); - - if ( this.distance !== undefined ) data.object.distance = this.distance; - if ( this.angle !== undefined ) data.object.angle = this.angle; - if ( this.decay !== undefined ) data.object.decay = this.decay; - if ( this.penumbra !== undefined ) data.object.penumbra = this.penumbra; - - if ( this.shadow !== undefined ) data.object.shadow = this.shadow.toJSON(); - - return data; - - } - -} - -class HemisphereLight extends Light { - - constructor( skyColor, groundColor, intensity ) { - - super( skyColor, intensity ); - - this.isHemisphereLight = true; - - this.type = 'HemisphereLight'; - - this.position.copy( Object3D.DEFAULT_UP ); - this.updateMatrix(); - - this.groundColor = new Color( groundColor ); - - } - - copy( source, recursive ) { - - super.copy( source, recursive ); - - this.groundColor.copy( source.groundColor ); - - return this; - - } - -} - -const _projScreenMatrix$1 = /*@__PURE__*/ new Matrix4(); -const _lightPositionWorld$1 = /*@__PURE__*/ new Vector3(); -const _lookTarget$1 = /*@__PURE__*/ new Vector3(); - -class LightShadow { - - constructor( camera ) { - - this.camera = camera; - - this.bias = 0; - this.normalBias = 0; - this.radius = 1; - this.blurSamples = 8; - - this.mapSize = new Vector2( 512, 512 ); - - this.map = null; - this.mapPass = null; - this.matrix = new Matrix4(); - - this.autoUpdate = true; - this.needsUpdate = false; - - this._frustum = new Frustum(); - this._frameExtents = new Vector2( 1, 1 ); - - this._viewportCount = 1; - - this._viewports = [ - - new Vector4( 0, 0, 1, 1 ) - - ]; - - } - - getViewportCount() { - - return this._viewportCount; - - } - - getFrustum() { - - return this._frustum; - - } - - updateMatrices( light ) { - - const shadowCamera = this.camera; - const shadowMatrix = this.matrix; - - _lightPositionWorld$1.setFromMatrixPosition( light.matrixWorld ); - shadowCamera.position.copy( _lightPositionWorld$1 ); - - _lookTarget$1.setFromMatrixPosition( light.target.matrixWorld ); - shadowCamera.lookAt( _lookTarget$1 ); - shadowCamera.updateMatrixWorld(); - - _projScreenMatrix$1.multiplyMatrices( shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse ); - this._frustum.setFromProjectionMatrix( _projScreenMatrix$1 ); - - shadowMatrix.set( - 0.5, 0.0, 0.0, 0.5, - 0.0, 0.5, 0.0, 0.5, - 0.0, 0.0, 0.5, 0.5, - 0.0, 0.0, 0.0, 1.0 - ); - - shadowMatrix.multiply( _projScreenMatrix$1 ); - - } - - getViewport( viewportIndex ) { - - return this._viewports[ viewportIndex ]; - - } - - getFrameExtents() { - - return this._frameExtents; - - } - - dispose() { - - if ( this.map ) { - - this.map.dispose(); - - } - - if ( this.mapPass ) { - - this.mapPass.dispose(); - - } - - } - - copy( source ) { - - this.camera = source.camera.clone(); - - this.bias = source.bias; - this.radius = source.radius; - - this.mapSize.copy( source.mapSize ); - - return this; - - } - - clone() { - - return new this.constructor().copy( this ); - - } - - toJSON() { - - const object = {}; - - if ( this.bias !== 0 ) object.bias = this.bias; - if ( this.normalBias !== 0 ) object.normalBias = this.normalBias; - if ( this.radius !== 1 ) object.radius = this.radius; - if ( this.mapSize.x !== 512 || this.mapSize.y !== 512 ) object.mapSize = this.mapSize.toArray(); - - object.camera = this.camera.toJSON( false ).object; - delete object.camera.matrix; - - return object; - - } - -} - -class SpotLightShadow extends LightShadow { - - constructor() { - - super( new PerspectiveCamera( 50, 1, 0.5, 500 ) ); - - this.isSpotLightShadow = true; - - this.focus = 1; - - } - - updateMatrices( light ) { - - const camera = this.camera; - - const fov = RAD2DEG * 2 * light.angle * this.focus; - const aspect = this.mapSize.width / this.mapSize.height; - const far = light.distance || camera.far; - - if ( fov !== camera.fov || aspect !== camera.aspect || far !== camera.far ) { - - camera.fov = fov; - camera.aspect = aspect; - camera.far = far; - camera.updateProjectionMatrix(); - - } - - super.updateMatrices( light ); - - } - - copy( source ) { - - super.copy( source ); - - this.focus = source.focus; - - return this; - - } - -} - -class SpotLight extends Light { - - constructor( color, intensity, distance = 0, angle = Math.PI / 3, penumbra = 0, decay = 2 ) { - - super( color, intensity ); - - this.isSpotLight = true; - - this.type = 'SpotLight'; - - this.position.copy( Object3D.DEFAULT_UP ); - this.updateMatrix(); - - this.target = new Object3D(); - - this.distance = distance; - this.angle = angle; - this.penumbra = penumbra; - this.decay = decay; - - this.map = null; - - this.shadow = new SpotLightShadow(); - - } - - get power() { - - // compute the light's luminous power (in lumens) from its intensity (in candela) - // by convention for a spotlight, luminous power (lm) = π * luminous intensity (cd) - return this.intensity * Math.PI; - - } - - set power( power ) { - - // set the light's intensity (in candela) from the desired luminous power (in lumens) - this.intensity = power / Math.PI; - - } - - dispose() { - - this.shadow.dispose(); - - } - - copy( source, recursive ) { - - super.copy( source, recursive ); - - this.distance = source.distance; - this.angle = source.angle; - this.penumbra = source.penumbra; - this.decay = source.decay; - - this.target = source.target.clone(); - - this.shadow = source.shadow.clone(); - - return this; - - } - -} - -const _projScreenMatrix = /*@__PURE__*/ new Matrix4(); -const _lightPositionWorld = /*@__PURE__*/ new Vector3(); -const _lookTarget = /*@__PURE__*/ new Vector3(); - -class PointLightShadow extends LightShadow { - - constructor() { - - super( new PerspectiveCamera( 90, 1, 0.5, 500 ) ); - - this.isPointLightShadow = true; - - this._frameExtents = new Vector2( 4, 2 ); - - this._viewportCount = 6; - - this._viewports = [ - // These viewports map a cube-map onto a 2D texture with the - // following orientation: - // - // xzXZ - // y Y - // - // X - Positive x direction - // x - Negative x direction - // Y - Positive y direction - // y - Negative y direction - // Z - Positive z direction - // z - Negative z direction - - // positive X - new Vector4( 2, 1, 1, 1 ), - // negative X - new Vector4( 0, 1, 1, 1 ), - // positive Z - new Vector4( 3, 1, 1, 1 ), - // negative Z - new Vector4( 1, 1, 1, 1 ), - // positive Y - new Vector4( 3, 0, 1, 1 ), - // negative Y - new Vector4( 1, 0, 1, 1 ) - ]; - - this._cubeDirections = [ - new Vector3( 1, 0, 0 ), new Vector3( - 1, 0, 0 ), new Vector3( 0, 0, 1 ), - new Vector3( 0, 0, - 1 ), new Vector3( 0, 1, 0 ), new Vector3( 0, - 1, 0 ) - ]; - - this._cubeUps = [ - new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ), - new Vector3( 0, 1, 0 ), new Vector3( 0, 0, 1 ), new Vector3( 0, 0, - 1 ) - ]; - - } - - updateMatrices( light, viewportIndex = 0 ) { - - const camera = this.camera; - const shadowMatrix = this.matrix; - - const far = light.distance || camera.far; - - if ( far !== camera.far ) { - - camera.far = far; - camera.updateProjectionMatrix(); - - } - - _lightPositionWorld.setFromMatrixPosition( light.matrixWorld ); - camera.position.copy( _lightPositionWorld ); - - _lookTarget.copy( camera.position ); - _lookTarget.add( this._cubeDirections[ viewportIndex ] ); - camera.up.copy( this._cubeUps[ viewportIndex ] ); - camera.lookAt( _lookTarget ); - camera.updateMatrixWorld(); - - shadowMatrix.makeTranslation( - _lightPositionWorld.x, - _lightPositionWorld.y, - _lightPositionWorld.z ); - - _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); - this._frustum.setFromProjectionMatrix( _projScreenMatrix ); - - } - -} - -class PointLight extends Light { - - constructor( color, intensity, distance = 0, decay = 2 ) { - - super( color, intensity ); - - this.isPointLight = true; - - this.type = 'PointLight'; - - this.distance = distance; - this.decay = decay; - - this.shadow = new PointLightShadow(); - - } - - get power() { - - // compute the light's luminous power (in lumens) from its intensity (in candela) - // for an isotropic light source, luminous power (lm) = 4 π luminous intensity (cd) - return this.intensity * 4 * Math.PI; - - } - - set power( power ) { - - // set the light's intensity (in candela) from the desired luminous power (in lumens) - this.intensity = power / ( 4 * Math.PI ); - - } - - dispose() { - - this.shadow.dispose(); - - } - - copy( source, recursive ) { - - super.copy( source, recursive ); - - this.distance = source.distance; - this.decay = source.decay; - - this.shadow = source.shadow.clone(); - - return this; - - } - -} - -class DirectionalLightShadow extends LightShadow { - - constructor() { - - super( new OrthographicCamera( - 5, 5, 5, - 5, 0.5, 500 ) ); - - this.isDirectionalLightShadow = true; - - } - -} - -class DirectionalLight extends Light { - - constructor( color, intensity ) { - - super( color, intensity ); - - this.isDirectionalLight = true; - - this.type = 'DirectionalLight'; - - this.position.copy( Object3D.DEFAULT_UP ); - this.updateMatrix(); - - this.target = new Object3D(); - - this.shadow = new DirectionalLightShadow(); - - } - - dispose() { - - this.shadow.dispose(); - - } - - copy( source ) { - - super.copy( source ); - - this.target = source.target.clone(); - this.shadow = source.shadow.clone(); - - return this; - - } - -} - -class AmbientLight extends Light { - - constructor( color, intensity ) { - - super( color, intensity ); - - this.isAmbientLight = true; - - this.type = 'AmbientLight'; - - } - -} - -class RectAreaLight extends Light { - - constructor( color, intensity, width = 10, height = 10 ) { - - super( color, intensity ); - - this.isRectAreaLight = true; - - this.type = 'RectAreaLight'; - - this.width = width; - this.height = height; - - } - - get power() { - - // compute the light's luminous power (in lumens) from its intensity (in nits) - return this.intensity * this.width * this.height * Math.PI; - - } - - set power( power ) { - - // set the light's intensity (in nits) from the desired luminous power (in lumens) - this.intensity = power / ( this.width * this.height * Math.PI ); - - } - - copy( source ) { - - super.copy( source ); - - this.width = source.width; - this.height = source.height; - - return this; - - } - - toJSON( meta ) { - - const data = super.toJSON( meta ); - - data.object.width = this.width; - data.object.height = this.height; - - return data; - - } - -} - -/** - * Primary reference: - * https://graphics.stanford.edu/papers/envmap/envmap.pdf - * - * Secondary reference: - * https://www.ppsloan.org/publications/StupidSH36.pdf - */ - -// 3-band SH defined by 9 coefficients - -class SphericalHarmonics3 { - - constructor() { - - this.isSphericalHarmonics3 = true; - - this.coefficients = []; - - for ( let i = 0; i < 9; i ++ ) { - - this.coefficients.push( new Vector3() ); - - } - - } - - set( coefficients ) { - - for ( let i = 0; i < 9; i ++ ) { - - this.coefficients[ i ].copy( coefficients[ i ] ); - - } - - return this; - - } - - zero() { - - for ( let i = 0; i < 9; i ++ ) { - - this.coefficients[ i ].set( 0, 0, 0 ); - - } - - return this; - - } - - // get the radiance in the direction of the normal - // target is a Vector3 - getAt( normal, target ) { - - // normal is assumed to be unit length - - const x = normal.x, y = normal.y, z = normal.z; - - const coeff = this.coefficients; - - // band 0 - target.copy( coeff[ 0 ] ).multiplyScalar( 0.282095 ); - - // band 1 - target.addScaledVector( coeff[ 1 ], 0.488603 * y ); - target.addScaledVector( coeff[ 2 ], 0.488603 * z ); - target.addScaledVector( coeff[ 3 ], 0.488603 * x ); - - // band 2 - target.addScaledVector( coeff[ 4 ], 1.092548 * ( x * y ) ); - target.addScaledVector( coeff[ 5 ], 1.092548 * ( y * z ) ); - target.addScaledVector( coeff[ 6 ], 0.315392 * ( 3.0 * z * z - 1.0 ) ); - target.addScaledVector( coeff[ 7 ], 1.092548 * ( x * z ) ); - target.addScaledVector( coeff[ 8 ], 0.546274 * ( x * x - y * y ) ); - - return target; - - } - - // get the irradiance (radiance convolved with cosine lobe) in the direction of the normal - // target is a Vector3 - // https://graphics.stanford.edu/papers/envmap/envmap.pdf - getIrradianceAt( normal, target ) { - - // normal is assumed to be unit length - - const x = normal.x, y = normal.y, z = normal.z; - - const coeff = this.coefficients; - - // band 0 - target.copy( coeff[ 0 ] ).multiplyScalar( 0.886227 ); // π * 0.282095 - - // band 1 - target.addScaledVector( coeff[ 1 ], 2.0 * 0.511664 * y ); // ( 2 * π / 3 ) * 0.488603 - target.addScaledVector( coeff[ 2 ], 2.0 * 0.511664 * z ); - target.addScaledVector( coeff[ 3 ], 2.0 * 0.511664 * x ); - - // band 2 - target.addScaledVector( coeff[ 4 ], 2.0 * 0.429043 * x * y ); // ( π / 4 ) * 1.092548 - target.addScaledVector( coeff[ 5 ], 2.0 * 0.429043 * y * z ); - target.addScaledVector( coeff[ 6 ], 0.743125 * z * z - 0.247708 ); // ( π / 4 ) * 0.315392 * 3 - target.addScaledVector( coeff[ 7 ], 2.0 * 0.429043 * x * z ); - target.addScaledVector( coeff[ 8 ], 0.429043 * ( x * x - y * y ) ); // ( π / 4 ) * 0.546274 - - return target; - - } - - add( sh ) { - - for ( let i = 0; i < 9; i ++ ) { - - this.coefficients[ i ].add( sh.coefficients[ i ] ); - - } - - return this; - - } - - addScaledSH( sh, s ) { - - for ( let i = 0; i < 9; i ++ ) { - - this.coefficients[ i ].addScaledVector( sh.coefficients[ i ], s ); - - } - - return this; - - } - - scale( s ) { - - for ( let i = 0; i < 9; i ++ ) { - - this.coefficients[ i ].multiplyScalar( s ); - - } - - return this; - - } - - lerp( sh, alpha ) { - - for ( let i = 0; i < 9; i ++ ) { - - this.coefficients[ i ].lerp( sh.coefficients[ i ], alpha ); - - } - - return this; - - } - - equals( sh ) { - - for ( let i = 0; i < 9; i ++ ) { - - if ( ! this.coefficients[ i ].equals( sh.coefficients[ i ] ) ) { - - return false; - - } - - } - - return true; - - } - - copy( sh ) { - - return this.set( sh.coefficients ); - - } - - clone() { - - return new this.constructor().copy( this ); - - } - - fromArray( array, offset = 0 ) { - - const coefficients = this.coefficients; - - for ( let i = 0; i < 9; i ++ ) { - - coefficients[ i ].fromArray( array, offset + ( i * 3 ) ); - - } - - return this; - - } - - toArray( array = [], offset = 0 ) { - - const coefficients = this.coefficients; - - for ( let i = 0; i < 9; i ++ ) { - - coefficients[ i ].toArray( array, offset + ( i * 3 ) ); - - } - - return array; - - } - - // evaluate the basis functions - // shBasis is an Array[ 9 ] - static getBasisAt( normal, shBasis ) { - - // normal is assumed to be unit length - - const x = normal.x, y = normal.y, z = normal.z; - - // band 0 - shBasis[ 0 ] = 0.282095; - - // band 1 - shBasis[ 1 ] = 0.488603 * y; - shBasis[ 2 ] = 0.488603 * z; - shBasis[ 3 ] = 0.488603 * x; - - // band 2 - shBasis[ 4 ] = 1.092548 * x * y; - shBasis[ 5 ] = 1.092548 * y * z; - shBasis[ 6 ] = 0.315392 * ( 3 * z * z - 1 ); - shBasis[ 7 ] = 1.092548 * x * z; - shBasis[ 8 ] = 0.546274 * ( x * x - y * y ); - - } - -} - -class LightProbe extends Light { - - constructor( sh = new SphericalHarmonics3(), intensity = 1 ) { - - super( undefined, intensity ); - - this.isLightProbe = true; - - this.sh = sh; - - } - - copy( source ) { - - super.copy( source ); - - this.sh.copy( source.sh ); - - return this; - - } - - fromJSON( json ) { - - this.intensity = json.intensity; // TODO: Move this bit to Light.fromJSON(); - this.sh.fromArray( json.sh ); - - return this; - - } - - toJSON( meta ) { - - const data = super.toJSON( meta ); - - data.object.sh = this.sh.toArray(); - - return data; - - } - -} - -class MaterialLoader extends Loader { - - constructor( manager ) { - - super( manager ); - this.textures = {}; - - } - - load( url, onLoad, onProgress, onError ) { - - const scope = this; - - const loader = new FileLoader( scope.manager ); - loader.setPath( scope.path ); - loader.setRequestHeader( scope.requestHeader ); - loader.setWithCredentials( scope.withCredentials ); - loader.load( url, function ( text ) { - - try { - - onLoad( scope.parse( JSON.parse( text ) ) ); - - } catch ( e ) { - - if ( onError ) { - - onError( e ); - - } else { - - console.error( e ); - - } - - scope.manager.itemError( url ); - - } - - }, onProgress, onError ); - - } - - parse( json ) { - - const textures = this.textures; - - function getTexture( name ) { - - if ( textures[ name ] === undefined ) { - - console.warn( 'THREE.MaterialLoader: Undefined texture', name ); - - } - - return textures[ name ]; - - } - - const material = MaterialLoader.createMaterialFromType( json.type ); - - if ( json.uuid !== undefined ) material.uuid = json.uuid; - if ( json.name !== undefined ) material.name = json.name; - if ( json.color !== undefined && material.color !== undefined ) material.color.setHex( json.color ); - if ( json.roughness !== undefined ) material.roughness = json.roughness; - if ( json.metalness !== undefined ) material.metalness = json.metalness; - if ( json.sheen !== undefined ) material.sheen = json.sheen; - if ( json.sheenColor !== undefined ) material.sheenColor = new Color().setHex( json.sheenColor ); - if ( json.sheenRoughness !== undefined ) material.sheenRoughness = json.sheenRoughness; - if ( json.emissive !== undefined && material.emissive !== undefined ) material.emissive.setHex( json.emissive ); - if ( json.specular !== undefined && material.specular !== undefined ) material.specular.setHex( json.specular ); - if ( json.specularIntensity !== undefined ) material.specularIntensity = json.specularIntensity; - if ( json.specularColor !== undefined && material.specularColor !== undefined ) material.specularColor.setHex( json.specularColor ); - if ( json.shininess !== undefined ) material.shininess = json.shininess; - if ( json.clearcoat !== undefined ) material.clearcoat = json.clearcoat; - if ( json.clearcoatRoughness !== undefined ) material.clearcoatRoughness = json.clearcoatRoughness; - if ( json.iridescence !== undefined ) material.iridescence = json.iridescence; - if ( json.iridescenceIOR !== undefined ) material.iridescenceIOR = json.iridescenceIOR; - if ( json.iridescenceThicknessRange !== undefined ) material.iridescenceThicknessRange = json.iridescenceThicknessRange; - if ( json.transmission !== undefined ) material.transmission = json.transmission; - if ( json.thickness !== undefined ) material.thickness = json.thickness; - if ( json.attenuationDistance !== undefined ) material.attenuationDistance = json.attenuationDistance; - if ( json.attenuationColor !== undefined && material.attenuationColor !== undefined ) material.attenuationColor.setHex( json.attenuationColor ); - if ( json.anisotropy !== undefined ) material.anisotropy = json.anisotropy; - if ( json.anisotropyRotation !== undefined ) material.anisotropyRotation = json.anisotropyRotation; - if ( json.fog !== undefined ) material.fog = json.fog; - if ( json.flatShading !== undefined ) material.flatShading = json.flatShading; - if ( json.blending !== undefined ) material.blending = json.blending; - if ( json.combine !== undefined ) material.combine = json.combine; - if ( json.side !== undefined ) material.side = json.side; - if ( json.shadowSide !== undefined ) material.shadowSide = json.shadowSide; - if ( json.opacity !== undefined ) material.opacity = json.opacity; - if ( json.transparent !== undefined ) material.transparent = json.transparent; - if ( json.alphaTest !== undefined ) material.alphaTest = json.alphaTest; - if ( json.alphaHash !== undefined ) material.alphaHash = json.alphaHash; - if ( json.depthFunc !== undefined ) material.depthFunc = json.depthFunc; - if ( json.depthTest !== undefined ) material.depthTest = json.depthTest; - if ( json.depthWrite !== undefined ) material.depthWrite = json.depthWrite; - if ( json.colorWrite !== undefined ) material.colorWrite = json.colorWrite; - if ( json.blendSrc !== undefined ) material.blendSrc = json.blendSrc; - if ( json.blendDst !== undefined ) material.blendDst = json.blendDst; - if ( json.blendEquation !== undefined ) material.blendEquation = json.blendEquation; - if ( json.blendSrcAlpha !== undefined ) material.blendSrcAlpha = json.blendSrcAlpha; - if ( json.blendDstAlpha !== undefined ) material.blendDstAlpha = json.blendDstAlpha; - if ( json.blendEquationAlpha !== undefined ) material.blendEquationAlpha = json.blendEquationAlpha; - if ( json.blendColor !== undefined && material.blendColor !== undefined ) material.blendColor.setHex( json.blendColor ); - if ( json.blendAlpha !== undefined ) material.blendAlpha = json.blendAlpha; - if ( json.stencilWriteMask !== undefined ) material.stencilWriteMask = json.stencilWriteMask; - if ( json.stencilFunc !== undefined ) material.stencilFunc = json.stencilFunc; - if ( json.stencilRef !== undefined ) material.stencilRef = json.stencilRef; - if ( json.stencilFuncMask !== undefined ) material.stencilFuncMask = json.stencilFuncMask; - if ( json.stencilFail !== undefined ) material.stencilFail = json.stencilFail; - if ( json.stencilZFail !== undefined ) material.stencilZFail = json.stencilZFail; - if ( json.stencilZPass !== undefined ) material.stencilZPass = json.stencilZPass; - if ( json.stencilWrite !== undefined ) material.stencilWrite = json.stencilWrite; - - if ( json.wireframe !== undefined ) material.wireframe = json.wireframe; - if ( json.wireframeLinewidth !== undefined ) material.wireframeLinewidth = json.wireframeLinewidth; - if ( json.wireframeLinecap !== undefined ) material.wireframeLinecap = json.wireframeLinecap; - if ( json.wireframeLinejoin !== undefined ) material.wireframeLinejoin = json.wireframeLinejoin; - - if ( json.rotation !== undefined ) material.rotation = json.rotation; - - if ( json.linewidth !== undefined ) material.linewidth = json.linewidth; - if ( json.dashSize !== undefined ) material.dashSize = json.dashSize; - if ( json.gapSize !== undefined ) material.gapSize = json.gapSize; - if ( json.scale !== undefined ) material.scale = json.scale; - - if ( json.polygonOffset !== undefined ) material.polygonOffset = json.polygonOffset; - if ( json.polygonOffsetFactor !== undefined ) material.polygonOffsetFactor = json.polygonOffsetFactor; - if ( json.polygonOffsetUnits !== undefined ) material.polygonOffsetUnits = json.polygonOffsetUnits; - - if ( json.dithering !== undefined ) material.dithering = json.dithering; - - if ( json.alphaToCoverage !== undefined ) material.alphaToCoverage = json.alphaToCoverage; - if ( json.premultipliedAlpha !== undefined ) material.premultipliedAlpha = json.premultipliedAlpha; - if ( json.forceSinglePass !== undefined ) material.forceSinglePass = json.forceSinglePass; - - if ( json.visible !== undefined ) material.visible = json.visible; - - if ( json.toneMapped !== undefined ) material.toneMapped = json.toneMapped; - - if ( json.userData !== undefined ) material.userData = json.userData; - - if ( json.vertexColors !== undefined ) { - - if ( typeof json.vertexColors === 'number' ) { - - material.vertexColors = ( json.vertexColors > 0 ) ? true : false; - - } else { - - material.vertexColors = json.vertexColors; - - } - - } - - // Shader Material - - if ( json.uniforms !== undefined ) { - - for ( const name in json.uniforms ) { - - const uniform = json.uniforms[ name ]; - - material.uniforms[ name ] = {}; - - switch ( uniform.type ) { - - case 't': - material.uniforms[ name ].value = getTexture( uniform.value ); - break; - - case 'c': - material.uniforms[ name ].value = new Color().setHex( uniform.value ); - break; - - case 'v2': - material.uniforms[ name ].value = new Vector2().fromArray( uniform.value ); - break; - - case 'v3': - material.uniforms[ name ].value = new Vector3().fromArray( uniform.value ); - break; - - case 'v4': - material.uniforms[ name ].value = new Vector4().fromArray( uniform.value ); - break; - - case 'm3': - material.uniforms[ name ].value = new Matrix3().fromArray( uniform.value ); - break; - - case 'm4': - material.uniforms[ name ].value = new Matrix4().fromArray( uniform.value ); - break; - - default: - material.uniforms[ name ].value = uniform.value; - - } - - } - - } - - if ( json.defines !== undefined ) material.defines = json.defines; - if ( json.vertexShader !== undefined ) material.vertexShader = json.vertexShader; - if ( json.fragmentShader !== undefined ) material.fragmentShader = json.fragmentShader; - if ( json.glslVersion !== undefined ) material.glslVersion = json.glslVersion; - - if ( json.extensions !== undefined ) { - - for ( const key in json.extensions ) { - - material.extensions[ key ] = json.extensions[ key ]; - - } - - } - - if ( json.lights !== undefined ) material.lights = json.lights; - if ( json.clipping !== undefined ) material.clipping = json.clipping; - - // for PointsMaterial - - if ( json.size !== undefined ) material.size = json.size; - if ( json.sizeAttenuation !== undefined ) material.sizeAttenuation = json.sizeAttenuation; - - // maps - - if ( json.map !== undefined ) material.map = getTexture( json.map ); - if ( json.matcap !== undefined ) material.matcap = getTexture( json.matcap ); - - if ( json.alphaMap !== undefined ) material.alphaMap = getTexture( json.alphaMap ); - - if ( json.bumpMap !== undefined ) material.bumpMap = getTexture( json.bumpMap ); - if ( json.bumpScale !== undefined ) material.bumpScale = json.bumpScale; - - if ( json.normalMap !== undefined ) material.normalMap = getTexture( json.normalMap ); - if ( json.normalMapType !== undefined ) material.normalMapType = json.normalMapType; - if ( json.normalScale !== undefined ) { - - let normalScale = json.normalScale; - - if ( Array.isArray( normalScale ) === false ) { - - // Blender exporter used to export a scalar. See #7459 - - normalScale = [ normalScale, normalScale ]; - - } - - material.normalScale = new Vector2().fromArray( normalScale ); - - } - - if ( json.displacementMap !== undefined ) material.displacementMap = getTexture( json.displacementMap ); - if ( json.displacementScale !== undefined ) material.displacementScale = json.displacementScale; - if ( json.displacementBias !== undefined ) material.displacementBias = json.displacementBias; - - if ( json.roughnessMap !== undefined ) material.roughnessMap = getTexture( json.roughnessMap ); - if ( json.metalnessMap !== undefined ) material.metalnessMap = getTexture( json.metalnessMap ); - - if ( json.emissiveMap !== undefined ) material.emissiveMap = getTexture( json.emissiveMap ); - if ( json.emissiveIntensity !== undefined ) material.emissiveIntensity = json.emissiveIntensity; - - if ( json.specularMap !== undefined ) material.specularMap = getTexture( json.specularMap ); - if ( json.specularIntensityMap !== undefined ) material.specularIntensityMap = getTexture( json.specularIntensityMap ); - if ( json.specularColorMap !== undefined ) material.specularColorMap = getTexture( json.specularColorMap ); - - if ( json.envMap !== undefined ) material.envMap = getTexture( json.envMap ); - if ( json.envMapIntensity !== undefined ) material.envMapIntensity = json.envMapIntensity; - - if ( json.reflectivity !== undefined ) material.reflectivity = json.reflectivity; - if ( json.refractionRatio !== undefined ) material.refractionRatio = json.refractionRatio; - - if ( json.lightMap !== undefined ) material.lightMap = getTexture( json.lightMap ); - if ( json.lightMapIntensity !== undefined ) material.lightMapIntensity = json.lightMapIntensity; - - if ( json.aoMap !== undefined ) material.aoMap = getTexture( json.aoMap ); - if ( json.aoMapIntensity !== undefined ) material.aoMapIntensity = json.aoMapIntensity; - - if ( json.gradientMap !== undefined ) material.gradientMap = getTexture( json.gradientMap ); - - if ( json.clearcoatMap !== undefined ) material.clearcoatMap = getTexture( json.clearcoatMap ); - if ( json.clearcoatRoughnessMap !== undefined ) material.clearcoatRoughnessMap = getTexture( json.clearcoatRoughnessMap ); - if ( json.clearcoatNormalMap !== undefined ) material.clearcoatNormalMap = getTexture( json.clearcoatNormalMap ); - if ( json.clearcoatNormalScale !== undefined ) material.clearcoatNormalScale = new Vector2().fromArray( json.clearcoatNormalScale ); - - if ( json.iridescenceMap !== undefined ) material.iridescenceMap = getTexture( json.iridescenceMap ); - if ( json.iridescenceThicknessMap !== undefined ) material.iridescenceThicknessMap = getTexture( json.iridescenceThicknessMap ); - - if ( json.transmissionMap !== undefined ) material.transmissionMap = getTexture( json.transmissionMap ); - if ( json.thicknessMap !== undefined ) material.thicknessMap = getTexture( json.thicknessMap ); - - if ( json.anisotropyMap !== undefined ) material.anisotropyMap = getTexture( json.anisotropyMap ); - - if ( json.sheenColorMap !== undefined ) material.sheenColorMap = getTexture( json.sheenColorMap ); - if ( json.sheenRoughnessMap !== undefined ) material.sheenRoughnessMap = getTexture( json.sheenRoughnessMap ); - - return material; - - } - - setTextures( value ) { - - this.textures = value; - return this; - - } - - static createMaterialFromType( type ) { - - const materialLib = { - ShadowMaterial, - SpriteMaterial, - RawShaderMaterial, - ShaderMaterial, - PointsMaterial, - MeshPhysicalMaterial, - MeshStandardMaterial, - MeshPhongMaterial, - MeshToonMaterial, - MeshNormalMaterial, - MeshLambertMaterial, - MeshDepthMaterial, - MeshDistanceMaterial, - MeshBasicMaterial, - MeshMatcapMaterial, - LineDashedMaterial, - LineBasicMaterial, - Material - }; - - return new materialLib[ type ](); - - } - -} - -class LoaderUtils { - - static decodeText( array ) { - - if ( typeof TextDecoder !== 'undefined' ) { - - return new TextDecoder().decode( array ); - - } - - // Avoid the String.fromCharCode.apply(null, array) shortcut, which - // throws a "maximum call stack size exceeded" error for large arrays. - - let s = ''; - - for ( let i = 0, il = array.length; i < il; i ++ ) { - - // Implicitly assumes little-endian. - s += String.fromCharCode( array[ i ] ); - - } - - try { - - // merges multi-byte utf-8 characters. - - return decodeURIComponent( escape( s ) ); - - } catch ( e ) { // see #16358 - - return s; - - } - - } - - static extractUrlBase( url ) { - - const index = url.lastIndexOf( '/' ); - - if ( index === - 1 ) return './'; - - return url.slice( 0, index + 1 ); - - } - - static resolveURL( url, path ) { - - // Invalid URL - if ( typeof url !== 'string' || url === '' ) return ''; - - // Host Relative URL - if ( /^https?:\/\//i.test( path ) && /^\//.test( url ) ) { - - path = path.replace( /(^https?:\/\/[^\/]+).*/i, '$1' ); - - } - - // Absolute URL http://,https://,// - if ( /^(https?:)?\/\//i.test( url ) ) return url; - - // Data URI - if ( /^data:.*,.*$/i.test( url ) ) return url; - - // Blob URL - if ( /^blob:.*$/i.test( url ) ) return url; - - // Relative URL - return path + url; - - } - -} - -class InstancedBufferGeometry extends BufferGeometry { - - constructor() { - - super(); - - this.isInstancedBufferGeometry = true; - - this.type = 'InstancedBufferGeometry'; - this.instanceCount = Infinity; - - } - - copy( source ) { - - super.copy( source ); - - this.instanceCount = source.instanceCount; - - return this; - - } - - toJSON() { - - const data = super.toJSON(); - - data.instanceCount = this.instanceCount; - - data.isInstancedBufferGeometry = true; - - return data; - - } - -} - -class BufferGeometryLoader extends Loader { - - constructor( manager ) { - - super( manager ); - - } - - load( url, onLoad, onProgress, onError ) { - - const scope = this; - - const loader = new FileLoader( scope.manager ); - loader.setPath( scope.path ); - loader.setRequestHeader( scope.requestHeader ); - loader.setWithCredentials( scope.withCredentials ); - loader.load( url, function ( text ) { - - try { - - onLoad( scope.parse( JSON.parse( text ) ) ); - - } catch ( e ) { - - if ( onError ) { - - onError( e ); - - } else { - - console.error( e ); - - } - - scope.manager.itemError( url ); - - } - - }, onProgress, onError ); - - } - - parse( json ) { - - const interleavedBufferMap = {}; - const arrayBufferMap = {}; - - function getInterleavedBuffer( json, uuid ) { - - if ( interleavedBufferMap[ uuid ] !== undefined ) return interleavedBufferMap[ uuid ]; - - const interleavedBuffers = json.interleavedBuffers; - const interleavedBuffer = interleavedBuffers[ uuid ]; - - const buffer = getArrayBuffer( json, interleavedBuffer.buffer ); - - const array = getTypedArray( interleavedBuffer.type, buffer ); - const ib = new InterleavedBuffer( array, interleavedBuffer.stride ); - ib.uuid = interleavedBuffer.uuid; - - interleavedBufferMap[ uuid ] = ib; - - return ib; - - } - - function getArrayBuffer( json, uuid ) { - - if ( arrayBufferMap[ uuid ] !== undefined ) return arrayBufferMap[ uuid ]; - - const arrayBuffers = json.arrayBuffers; - const arrayBuffer = arrayBuffers[ uuid ]; - - const ab = new Uint32Array( arrayBuffer ).buffer; - - arrayBufferMap[ uuid ] = ab; - - return ab; - - } - - const geometry = json.isInstancedBufferGeometry ? new InstancedBufferGeometry() : new BufferGeometry(); - - const index = json.data.index; - - if ( index !== undefined ) { - - const typedArray = getTypedArray( index.type, index.array ); - geometry.setIndex( new BufferAttribute( typedArray, 1 ) ); - - } - - const attributes = json.data.attributes; - - for ( const key in attributes ) { - - const attribute = attributes[ key ]; - let bufferAttribute; - - if ( attribute.isInterleavedBufferAttribute ) { - - const interleavedBuffer = getInterleavedBuffer( json.data, attribute.data ); - bufferAttribute = new InterleavedBufferAttribute( interleavedBuffer, attribute.itemSize, attribute.offset, attribute.normalized ); - - } else { - - const typedArray = getTypedArray( attribute.type, attribute.array ); - const bufferAttributeConstr = attribute.isInstancedBufferAttribute ? InstancedBufferAttribute : BufferAttribute; - bufferAttribute = new bufferAttributeConstr( typedArray, attribute.itemSize, attribute.normalized ); - - } - - if ( attribute.name !== undefined ) bufferAttribute.name = attribute.name; - if ( attribute.usage !== undefined ) bufferAttribute.setUsage( attribute.usage ); - - geometry.setAttribute( key, bufferAttribute ); - - } - - const morphAttributes = json.data.morphAttributes; - - if ( morphAttributes ) { - - for ( const key in morphAttributes ) { - - const attributeArray = morphAttributes[ key ]; - - const array = []; - - for ( let i = 0, il = attributeArray.length; i < il; i ++ ) { - - const attribute = attributeArray[ i ]; - let bufferAttribute; - - if ( attribute.isInterleavedBufferAttribute ) { - - const interleavedBuffer = getInterleavedBuffer( json.data, attribute.data ); - bufferAttribute = new InterleavedBufferAttribute( interleavedBuffer, attribute.itemSize, attribute.offset, attribute.normalized ); - - } else { - - const typedArray = getTypedArray( attribute.type, attribute.array ); - bufferAttribute = new BufferAttribute( typedArray, attribute.itemSize, attribute.normalized ); - - } - - if ( attribute.name !== undefined ) bufferAttribute.name = attribute.name; - array.push( bufferAttribute ); - - } - - geometry.morphAttributes[ key ] = array; - - } - - } - - const morphTargetsRelative = json.data.morphTargetsRelative; - - if ( morphTargetsRelative ) { - - geometry.morphTargetsRelative = true; - - } - - const groups = json.data.groups || json.data.drawcalls || json.data.offsets; - - if ( groups !== undefined ) { - - for ( let i = 0, n = groups.length; i !== n; ++ i ) { - - const group = groups[ i ]; - - geometry.addGroup( group.start, group.count, group.materialIndex ); - - } - - } - - const boundingSphere = json.data.boundingSphere; - - if ( boundingSphere !== undefined ) { - - const center = new Vector3(); - - if ( boundingSphere.center !== undefined ) { - - center.fromArray( boundingSphere.center ); - - } - - geometry.boundingSphere = new Sphere( center, boundingSphere.radius ); - - } - - if ( json.name ) geometry.name = json.name; - if ( json.userData ) geometry.userData = json.userData; - - return geometry; - - } - -} - -class ObjectLoader extends Loader { - - constructor( manager ) { - - super( manager ); - - } - - load( url, onLoad, onProgress, onError ) { - - const scope = this; - - const path = ( this.path === '' ) ? LoaderUtils.extractUrlBase( url ) : this.path; - this.resourcePath = this.resourcePath || path; - - const loader = new FileLoader( this.manager ); - loader.setPath( this.path ); - loader.setRequestHeader( this.requestHeader ); - loader.setWithCredentials( this.withCredentials ); - loader.load( url, function ( text ) { - - let json = null; - - try { - - json = JSON.parse( text ); - - } catch ( error ) { - - if ( onError !== undefined ) onError( error ); - - console.error( 'THREE:ObjectLoader: Can\'t parse ' + url + '.', error.message ); - - return; - - } - - const metadata = json.metadata; - - if ( metadata === undefined || metadata.type === undefined || metadata.type.toLowerCase() === 'geometry' ) { - - if ( onError !== undefined ) onError( new Error( 'THREE.ObjectLoader: Can\'t load ' + url ) ); - - console.error( 'THREE.ObjectLoader: Can\'t load ' + url ); - return; - - } - - scope.parse( json, onLoad ); - - }, onProgress, onError ); - - } - - async loadAsync( url, onProgress ) { - - const scope = this; - - const path = ( this.path === '' ) ? LoaderUtils.extractUrlBase( url ) : this.path; - this.resourcePath = this.resourcePath || path; - - const loader = new FileLoader( this.manager ); - loader.setPath( this.path ); - loader.setRequestHeader( this.requestHeader ); - loader.setWithCredentials( this.withCredentials ); - - const text = await loader.loadAsync( url, onProgress ); - - const json = JSON.parse( text ); - - const metadata = json.metadata; - - if ( metadata === undefined || metadata.type === undefined || metadata.type.toLowerCase() === 'geometry' ) { - - throw new Error( 'THREE.ObjectLoader: Can\'t load ' + url ); - - } - - return await scope.parseAsync( json ); - - } - - parse( json, onLoad ) { - - const animations = this.parseAnimations( json.animations ); - const shapes = this.parseShapes( json.shapes ); - const geometries = this.parseGeometries( json.geometries, shapes ); - - const images = this.parseImages( json.images, function () { - - if ( onLoad !== undefined ) onLoad( object ); - - } ); - - const textures = this.parseTextures( json.textures, images ); - const materials = this.parseMaterials( json.materials, textures ); - - const object = this.parseObject( json.object, geometries, materials, textures, animations ); - const skeletons = this.parseSkeletons( json.skeletons, object ); - - this.bindSkeletons( object, skeletons ); - - // - - if ( onLoad !== undefined ) { - - let hasImages = false; - - for ( const uuid in images ) { - - if ( images[ uuid ].data instanceof HTMLImageElement ) { - - hasImages = true; - break; - - } - - } - - if ( hasImages === false ) onLoad( object ); - - } - - return object; - - } - - async parseAsync( json ) { - - const animations = this.parseAnimations( json.animations ); - const shapes = this.parseShapes( json.shapes ); - const geometries = this.parseGeometries( json.geometries, shapes ); - - const images = await this.parseImagesAsync( json.images ); - - const textures = this.parseTextures( json.textures, images ); - const materials = this.parseMaterials( json.materials, textures ); - - const object = this.parseObject( json.object, geometries, materials, textures, animations ); - const skeletons = this.parseSkeletons( json.skeletons, object ); - - this.bindSkeletons( object, skeletons ); - - return object; - - } - - parseShapes( json ) { - - const shapes = {}; - - if ( json !== undefined ) { - - for ( let i = 0, l = json.length; i < l; i ++ ) { - - const shape = new Shape().fromJSON( json[ i ] ); - - shapes[ shape.uuid ] = shape; - - } - - } - - return shapes; - - } - - parseSkeletons( json, object ) { - - const skeletons = {}; - const bones = {}; - - // generate bone lookup table - - object.traverse( function ( child ) { - - if ( child.isBone ) bones[ child.uuid ] = child; - - } ); - - // create skeletons - - if ( json !== undefined ) { - - for ( let i = 0, l = json.length; i < l; i ++ ) { - - const skeleton = new Skeleton().fromJSON( json[ i ], bones ); - - skeletons[ skeleton.uuid ] = skeleton; - - } - - } - - return skeletons; - - } - - parseGeometries( json, shapes ) { - - const geometries = {}; - - if ( json !== undefined ) { - - const bufferGeometryLoader = new BufferGeometryLoader(); - - for ( let i = 0, l = json.length; i < l; i ++ ) { - - let geometry; - const data = json[ i ]; - - switch ( data.type ) { - - case 'BufferGeometry': - case 'InstancedBufferGeometry': - - geometry = bufferGeometryLoader.parse( data ); - break; - - default: - - if ( data.type in Geometries ) { - - geometry = Geometries[ data.type ].fromJSON( data, shapes ); - - } else { - - console.warn( `THREE.ObjectLoader: Unsupported geometry type "${ data.type }"` ); - - } - - } - - geometry.uuid = data.uuid; - - if ( data.name !== undefined ) geometry.name = data.name; - if ( data.userData !== undefined ) geometry.userData = data.userData; - - geometries[ data.uuid ] = geometry; - - } - - } - - return geometries; - - } - - parseMaterials( json, textures ) { - - const cache = {}; // MultiMaterial - const materials = {}; - - if ( json !== undefined ) { - - const loader = new MaterialLoader(); - loader.setTextures( textures ); - - for ( let i = 0, l = json.length; i < l; i ++ ) { - - const data = json[ i ]; - - if ( cache[ data.uuid ] === undefined ) { - - cache[ data.uuid ] = loader.parse( data ); - - } - - materials[ data.uuid ] = cache[ data.uuid ]; - - } - - } - - return materials; - - } - - parseAnimations( json ) { - - const animations = {}; - - if ( json !== undefined ) { - - for ( let i = 0; i < json.length; i ++ ) { - - const data = json[ i ]; - - const clip = AnimationClip.parse( data ); - - animations[ clip.uuid ] = clip; - - } - - } - - return animations; - - } - - parseImages( json, onLoad ) { - - const scope = this; - const images = {}; - - let loader; - - function loadImage( url ) { - - scope.manager.itemStart( url ); - - return loader.load( url, function () { - - scope.manager.itemEnd( url ); - - }, undefined, function () { - - scope.manager.itemError( url ); - scope.manager.itemEnd( url ); - - } ); - - } - - function deserializeImage( image ) { - - if ( typeof image === 'string' ) { - - const url = image; - - const path = /^(\/\/)|([a-z]+:(\/\/)?)/i.test( url ) ? url : scope.resourcePath + url; - - return loadImage( path ); - - } else { - - if ( image.data ) { - - return { - data: getTypedArray( image.type, image.data ), - width: image.width, - height: image.height - }; - - } else { - - return null; - - } - - } - - } - - if ( json !== undefined && json.length > 0 ) { - - const manager = new LoadingManager( onLoad ); - - loader = new ImageLoader( manager ); - loader.setCrossOrigin( this.crossOrigin ); - - for ( let i = 0, il = json.length; i < il; i ++ ) { - - const image = json[ i ]; - const url = image.url; - - if ( Array.isArray( url ) ) { - - // load array of images e.g CubeTexture - - const imageArray = []; - - for ( let j = 0, jl = url.length; j < jl; j ++ ) { - - const currentUrl = url[ j ]; - - const deserializedImage = deserializeImage( currentUrl ); - - if ( deserializedImage !== null ) { - - if ( deserializedImage instanceof HTMLImageElement ) { - - imageArray.push( deserializedImage ); - - } else { - - // special case: handle array of data textures for cube textures - - imageArray.push( new DataTexture( deserializedImage.data, deserializedImage.width, deserializedImage.height ) ); - - } - - } - - } - - images[ image.uuid ] = new Source( imageArray ); - - } else { - - // load single image - - const deserializedImage = deserializeImage( image.url ); - images[ image.uuid ] = new Source( deserializedImage ); - - - } - - } - - } - - return images; - - } - - async parseImagesAsync( json ) { - - const scope = this; - const images = {}; - - let loader; - - async function deserializeImage( image ) { - - if ( typeof image === 'string' ) { - - const url = image; - - const path = /^(\/\/)|([a-z]+:(\/\/)?)/i.test( url ) ? url : scope.resourcePath + url; - - return await loader.loadAsync( path ); - - } else { - - if ( image.data ) { - - return { - data: getTypedArray( image.type, image.data ), - width: image.width, - height: image.height - }; - - } else { - - return null; - - } - - } - - } - - if ( json !== undefined && json.length > 0 ) { - - loader = new ImageLoader( this.manager ); - loader.setCrossOrigin( this.crossOrigin ); - - for ( let i = 0, il = json.length; i < il; i ++ ) { - - const image = json[ i ]; - const url = image.url; - - if ( Array.isArray( url ) ) { - - // load array of images e.g CubeTexture - - const imageArray = []; - - for ( let j = 0, jl = url.length; j < jl; j ++ ) { - - const currentUrl = url[ j ]; - - const deserializedImage = await deserializeImage( currentUrl ); - - if ( deserializedImage !== null ) { - - if ( deserializedImage instanceof HTMLImageElement ) { - - imageArray.push( deserializedImage ); - - } else { - - // special case: handle array of data textures for cube textures - - imageArray.push( new DataTexture( deserializedImage.data, deserializedImage.width, deserializedImage.height ) ); - - } - - } - - } - - images[ image.uuid ] = new Source( imageArray ); - - } else { - - // load single image - - const deserializedImage = await deserializeImage( image.url ); - images[ image.uuid ] = new Source( deserializedImage ); - - } - - } - - } - - return images; - - } - - parseTextures( json, images ) { - - function parseConstant( value, type ) { - - if ( typeof value === 'number' ) return value; - - console.warn( 'THREE.ObjectLoader.parseTexture: Constant should be in numeric form.', value ); - - return type[ value ]; - - } - - const textures = {}; - - if ( json !== undefined ) { - - for ( let i = 0, l = json.length; i < l; i ++ ) { - - const data = json[ i ]; - - if ( data.image === undefined ) { - - console.warn( 'THREE.ObjectLoader: No "image" specified for', data.uuid ); - - } - - if ( images[ data.image ] === undefined ) { - - console.warn( 'THREE.ObjectLoader: Undefined image', data.image ); - - } - - const source = images[ data.image ]; - const image = source.data; - - let texture; - - if ( Array.isArray( image ) ) { - - texture = new CubeTexture(); - - if ( image.length === 6 ) texture.needsUpdate = true; - - } else { - - if ( image && image.data ) { - - texture = new DataTexture(); - - } else { - - texture = new Texture(); - - } - - if ( image ) texture.needsUpdate = true; // textures can have undefined image data - - } - - texture.source = source; - - texture.uuid = data.uuid; - - if ( data.name !== undefined ) texture.name = data.name; - - if ( data.mapping !== undefined ) texture.mapping = parseConstant( data.mapping, TEXTURE_MAPPING ); - if ( data.channel !== undefined ) texture.channel = data.channel; - - if ( data.offset !== undefined ) texture.offset.fromArray( data.offset ); - if ( data.repeat !== undefined ) texture.repeat.fromArray( data.repeat ); - if ( data.center !== undefined ) texture.center.fromArray( data.center ); - if ( data.rotation !== undefined ) texture.rotation = data.rotation; - - if ( data.wrap !== undefined ) { - - texture.wrapS = parseConstant( data.wrap[ 0 ], TEXTURE_WRAPPING ); - texture.wrapT = parseConstant( data.wrap[ 1 ], TEXTURE_WRAPPING ); - - } - - if ( data.format !== undefined ) texture.format = data.format; - if ( data.internalFormat !== undefined ) texture.internalFormat = data.internalFormat; - if ( data.type !== undefined ) texture.type = data.type; - if ( data.colorSpace !== undefined ) texture.colorSpace = data.colorSpace; - - if ( data.minFilter !== undefined ) texture.minFilter = parseConstant( data.minFilter, TEXTURE_FILTER ); - if ( data.magFilter !== undefined ) texture.magFilter = parseConstant( data.magFilter, TEXTURE_FILTER ); - if ( data.anisotropy !== undefined ) texture.anisotropy = data.anisotropy; - - if ( data.flipY !== undefined ) texture.flipY = data.flipY; - - if ( data.generateMipmaps !== undefined ) texture.generateMipmaps = data.generateMipmaps; - if ( data.premultiplyAlpha !== undefined ) texture.premultiplyAlpha = data.premultiplyAlpha; - if ( data.unpackAlignment !== undefined ) texture.unpackAlignment = data.unpackAlignment; - if ( data.compareFunction !== undefined ) texture.compareFunction = data.compareFunction; - - if ( data.userData !== undefined ) texture.userData = data.userData; - - textures[ data.uuid ] = texture; - - } - - } - - return textures; - - } - - parseObject( data, geometries, materials, textures, animations ) { - - let object; - - function getGeometry( name ) { - - if ( geometries[ name ] === undefined ) { - - console.warn( 'THREE.ObjectLoader: Undefined geometry', name ); - - } - - return geometries[ name ]; - - } - - function getMaterial( name ) { - - if ( name === undefined ) return undefined; - - if ( Array.isArray( name ) ) { - - const array = []; - - for ( let i = 0, l = name.length; i < l; i ++ ) { - - const uuid = name[ i ]; - - if ( materials[ uuid ] === undefined ) { - - console.warn( 'THREE.ObjectLoader: Undefined material', uuid ); - - } - - array.push( materials[ uuid ] ); - - } - - return array; - - } - - if ( materials[ name ] === undefined ) { - - console.warn( 'THREE.ObjectLoader: Undefined material', name ); - - } - - return materials[ name ]; - - } - - function getTexture( uuid ) { - - if ( textures[ uuid ] === undefined ) { - - console.warn( 'THREE.ObjectLoader: Undefined texture', uuid ); - - } - - return textures[ uuid ]; - - } - - let geometry, material; - - switch ( data.type ) { - - case 'Scene': - - object = new Scene(); - - if ( data.background !== undefined ) { - - if ( Number.isInteger( data.background ) ) { - - object.background = new Color( data.background ); - - } else { - - object.background = getTexture( data.background ); - - } - - } - - if ( data.environment !== undefined ) { - - object.environment = getTexture( data.environment ); - - } - - if ( data.fog !== undefined ) { - - if ( data.fog.type === 'Fog' ) { - - object.fog = new Fog( data.fog.color, data.fog.near, data.fog.far ); - - } else if ( data.fog.type === 'FogExp2' ) { - - object.fog = new FogExp2( data.fog.color, data.fog.density ); - - } - - if ( data.fog.name !== '' ) { - - object.fog.name = data.fog.name; - - } - - } - - if ( data.backgroundBlurriness !== undefined ) object.backgroundBlurriness = data.backgroundBlurriness; - if ( data.backgroundIntensity !== undefined ) object.backgroundIntensity = data.backgroundIntensity; - - break; - - case 'PerspectiveCamera': - - object = new PerspectiveCamera( data.fov, data.aspect, data.near, data.far ); - - if ( data.focus !== undefined ) object.focus = data.focus; - if ( data.zoom !== undefined ) object.zoom = data.zoom; - if ( data.filmGauge !== undefined ) object.filmGauge = data.filmGauge; - if ( data.filmOffset !== undefined ) object.filmOffset = data.filmOffset; - if ( data.view !== undefined ) object.view = Object.assign( {}, data.view ); - - break; - - case 'OrthographicCamera': - - object = new OrthographicCamera( data.left, data.right, data.top, data.bottom, data.near, data.far ); - - if ( data.zoom !== undefined ) object.zoom = data.zoom; - if ( data.view !== undefined ) object.view = Object.assign( {}, data.view ); - - break; - - case 'AmbientLight': - - object = new AmbientLight( data.color, data.intensity ); - - break; - - case 'DirectionalLight': - - object = new DirectionalLight( data.color, data.intensity ); - - break; - - case 'PointLight': - - object = new PointLight( data.color, data.intensity, data.distance, data.decay ); - - break; - - case 'RectAreaLight': - - object = new RectAreaLight( data.color, data.intensity, data.width, data.height ); - - break; - - case 'SpotLight': - - object = new SpotLight( data.color, data.intensity, data.distance, data.angle, data.penumbra, data.decay ); - - break; - - case 'HemisphereLight': - - object = new HemisphereLight( data.color, data.groundColor, data.intensity ); - - break; - - case 'LightProbe': - - object = new LightProbe().fromJSON( data ); - - break; - - case 'SkinnedMesh': - - geometry = getGeometry( data.geometry ); - material = getMaterial( data.material ); - - object = new SkinnedMesh( geometry, material ); - - if ( data.bindMode !== undefined ) object.bindMode = data.bindMode; - if ( data.bindMatrix !== undefined ) object.bindMatrix.fromArray( data.bindMatrix ); - if ( data.skeleton !== undefined ) object.skeleton = data.skeleton; - - break; - - case 'Mesh': - - geometry = getGeometry( data.geometry ); - material = getMaterial( data.material ); - - object = new Mesh( geometry, material ); - - break; - - case 'InstancedMesh': - - geometry = getGeometry( data.geometry ); - material = getMaterial( data.material ); - const count = data.count; - const instanceMatrix = data.instanceMatrix; - const instanceColor = data.instanceColor; - - object = new InstancedMesh( geometry, material, count ); - object.instanceMatrix = new InstancedBufferAttribute( new Float32Array( instanceMatrix.array ), 16 ); - if ( instanceColor !== undefined ) object.instanceColor = new InstancedBufferAttribute( new Float32Array( instanceColor.array ), instanceColor.itemSize ); - - break; - - case 'BatchedMesh': - - geometry = getGeometry( data.geometry ); - material = getMaterial( data.material ); - - object = new BatchedMesh( data.maxGeometryCount, data.maxVertexCount, data.maxIndexCount, material ); - object.geometry = geometry; - object.perObjectFrustumCulled = data.perObjectFrustumCulled; - object.sortObjects = data.sortObjects; - - object._drawRanges = data.drawRanges; - object._reservedRanges = data.reservedRanges; - - object._visibility = data.visibility; - object._active = data.active; - object._bounds = data.bounds.map( bound => { - - const box = new Box3(); - box.min.fromArray( bound.boxMin ); - box.max.fromArray( bound.boxMax ); - - const sphere = new Sphere(); - sphere.radius = bound.sphereRadius; - sphere.center.fromArray( bound.sphereCenter ); - - return { - boxInitialized: bound.boxInitialized, - box: box, - - sphereInitialized: bound.sphereInitialized, - sphere: sphere - }; - - } ); - - object._maxGeometryCount = data.maxGeometryCount; - object._maxVertexCount = data.maxVertexCount; - object._maxIndexCount = data.maxIndexCount; - - object._geometryInitialized = data.geometryInitialized; - object._geometryCount = data.geometryCount; - - object._matricesTexture = getTexture( data.matricesTexture.uuid ); - - break; - - case 'LOD': - - object = new LOD(); - - break; - - case 'Line': - - object = new Line( getGeometry( data.geometry ), getMaterial( data.material ) ); - - break; - - case 'LineLoop': - - object = new LineLoop( getGeometry( data.geometry ), getMaterial( data.material ) ); - - break; - - case 'LineSegments': - - object = new LineSegments( getGeometry( data.geometry ), getMaterial( data.material ) ); - - break; - - case 'PointCloud': - case 'Points': - - object = new Points( getGeometry( data.geometry ), getMaterial( data.material ) ); - - break; - - case 'Sprite': - - object = new Sprite( getMaterial( data.material ) ); - - break; - - case 'Group': - - object = new Group(); - - break; - - case 'Bone': - - object = new Bone(); - - break; - - default: - - object = new Object3D(); - - } - - object.uuid = data.uuid; - - if ( data.name !== undefined ) object.name = data.name; - - if ( data.matrix !== undefined ) { - - object.matrix.fromArray( data.matrix ); - - if ( data.matrixAutoUpdate !== undefined ) object.matrixAutoUpdate = data.matrixAutoUpdate; - if ( object.matrixAutoUpdate ) object.matrix.decompose( object.position, object.quaternion, object.scale ); - - } else { - - if ( data.position !== undefined ) object.position.fromArray( data.position ); - if ( data.rotation !== undefined ) object.rotation.fromArray( data.rotation ); - if ( data.quaternion !== undefined ) object.quaternion.fromArray( data.quaternion ); - if ( data.scale !== undefined ) object.scale.fromArray( data.scale ); - - } - - if ( data.up !== undefined ) object.up.fromArray( data.up ); - - if ( data.castShadow !== undefined ) object.castShadow = data.castShadow; - if ( data.receiveShadow !== undefined ) object.receiveShadow = data.receiveShadow; - - if ( data.shadow ) { - - if ( data.shadow.bias !== undefined ) object.shadow.bias = data.shadow.bias; - if ( data.shadow.normalBias !== undefined ) object.shadow.normalBias = data.shadow.normalBias; - if ( data.shadow.radius !== undefined ) object.shadow.radius = data.shadow.radius; - if ( data.shadow.mapSize !== undefined ) object.shadow.mapSize.fromArray( data.shadow.mapSize ); - if ( data.shadow.camera !== undefined ) object.shadow.camera = this.parseObject( data.shadow.camera ); - - } - - if ( data.visible !== undefined ) object.visible = data.visible; - if ( data.frustumCulled !== undefined ) object.frustumCulled = data.frustumCulled; - if ( data.renderOrder !== undefined ) object.renderOrder = data.renderOrder; - if ( data.userData !== undefined ) object.userData = data.userData; - if ( data.layers !== undefined ) object.layers.mask = data.layers; - - if ( data.children !== undefined ) { - - const children = data.children; - - for ( let i = 0; i < children.length; i ++ ) { - - object.add( this.parseObject( children[ i ], geometries, materials, textures, animations ) ); - - } - - } - - if ( data.animations !== undefined ) { - - const objectAnimations = data.animations; - - for ( let i = 0; i < objectAnimations.length; i ++ ) { - - const uuid = objectAnimations[ i ]; - - object.animations.push( animations[ uuid ] ); - - } - - } - - if ( data.type === 'LOD' ) { - - if ( data.autoUpdate !== undefined ) object.autoUpdate = data.autoUpdate; - - const levels = data.levels; - - for ( let l = 0; l < levels.length; l ++ ) { - - const level = levels[ l ]; - const child = object.getObjectByProperty( 'uuid', level.object ); - - if ( child !== undefined ) { - - object.addLevel( child, level.distance, level.hysteresis ); - - } - - } - - } - - return object; - - } - - bindSkeletons( object, skeletons ) { - - if ( Object.keys( skeletons ).length === 0 ) return; - - object.traverse( function ( child ) { - - if ( child.isSkinnedMesh === true && child.skeleton !== undefined ) { - - const skeleton = skeletons[ child.skeleton ]; - - if ( skeleton === undefined ) { - - console.warn( 'THREE.ObjectLoader: No skeleton found with UUID:', child.skeleton ); - - } else { - - child.bind( skeleton, child.bindMatrix ); - - } - - } - - } ); - - } - -} - -const TEXTURE_MAPPING = { - UVMapping: UVMapping, - CubeReflectionMapping: CubeReflectionMapping, - CubeRefractionMapping: CubeRefractionMapping, - EquirectangularReflectionMapping: EquirectangularReflectionMapping, - EquirectangularRefractionMapping: EquirectangularRefractionMapping, - CubeUVReflectionMapping: CubeUVReflectionMapping -}; - -const TEXTURE_WRAPPING = { - RepeatWrapping: RepeatWrapping, - ClampToEdgeWrapping: ClampToEdgeWrapping, - MirroredRepeatWrapping: MirroredRepeatWrapping -}; - -const TEXTURE_FILTER = { - NearestFilter: NearestFilter, - NearestMipmapNearestFilter: NearestMipmapNearestFilter, - NearestMipmapLinearFilter: NearestMipmapLinearFilter, - LinearFilter: LinearFilter, - LinearMipmapNearestFilter: LinearMipmapNearestFilter, - LinearMipmapLinearFilter: LinearMipmapLinearFilter -}; - -class ImageBitmapLoader extends Loader { - - constructor( manager ) { - - super( manager ); - - this.isImageBitmapLoader = true; - - if ( typeof createImageBitmap === 'undefined' ) { - - console.warn( 'THREE.ImageBitmapLoader: createImageBitmap() not supported.' ); - - } - - if ( typeof fetch === 'undefined' ) { - - console.warn( 'THREE.ImageBitmapLoader: fetch() not supported.' ); - - } - - this.options = { premultiplyAlpha: 'none' }; - - } - - setOptions( options ) { - - this.options = options; - - return this; - - } - - load( url, onLoad, onProgress, onError ) { - - if ( url === undefined ) url = ''; - - if ( this.path !== undefined ) url = this.path + url; - - url = this.manager.resolveURL( url ); - - const scope = this; - - const cached = Cache.get( url ); - - if ( cached !== undefined ) { - - scope.manager.itemStart( url ); - - // If cached is a promise, wait for it to resolve - if ( cached.then ) { - - cached.then( imageBitmap => { - - if ( onLoad ) onLoad( imageBitmap ); - - scope.manager.itemEnd( url ); - - } ).catch( e => { - - if ( onError ) onError( e ); - - } ); - return; - - } - - // If cached is not a promise (i.e., it's already an imageBitmap) - setTimeout( function () { - - if ( onLoad ) onLoad( cached ); - - scope.manager.itemEnd( url ); - - }, 0 ); - - return cached; - - } - - const fetchOptions = {}; - fetchOptions.credentials = ( this.crossOrigin === 'anonymous' ) ? 'same-origin' : 'include'; - fetchOptions.headers = this.requestHeader; - - const promise = fetch( url, fetchOptions ).then( function ( res ) { - - return res.blob(); - - } ).then( function ( blob ) { - - return createImageBitmap( blob, Object.assign( scope.options, { colorSpaceConversion: 'none' } ) ); - - } ).then( function ( imageBitmap ) { - - Cache.add( url, imageBitmap ); - - if ( onLoad ) onLoad( imageBitmap ); - - scope.manager.itemEnd( url ); - - return imageBitmap; - - } ).catch( function ( e ) { - - if ( onError ) onError( e ); - - Cache.remove( url ); - - scope.manager.itemError( url ); - scope.manager.itemEnd( url ); - - } ); - - Cache.add( url, promise ); - scope.manager.itemStart( url ); - - } - -} - -let _context; - -class AudioContext { - - static getContext() { - - if ( _context === undefined ) { - - _context = new ( window.AudioContext || window.webkitAudioContext )(); - - } - - return _context; - - } - - static setContext( value ) { - - _context = value; - - } - -} - -class AudioLoader extends Loader { - - constructor( manager ) { - - super( manager ); - - } - - load( url, onLoad, onProgress, onError ) { - - const scope = this; - - const loader = new FileLoader( this.manager ); - loader.setResponseType( 'arraybuffer' ); - loader.setPath( this.path ); - loader.setRequestHeader( this.requestHeader ); - loader.setWithCredentials( this.withCredentials ); - loader.load( url, function ( buffer ) { - - try { - - // Create a copy of the buffer. The `decodeAudioData` method - // detaches the buffer when complete, preventing reuse. - const bufferCopy = buffer.slice( 0 ); - - const context = AudioContext.getContext(); - context.decodeAudioData( bufferCopy, function ( audioBuffer ) { - - onLoad( audioBuffer ); - - } ).catch( handleError ); - - } catch ( e ) { - - handleError( e ); - - } - - }, onProgress, onError ); - - function handleError( e ) { - - if ( onError ) { - - onError( e ); - - } else { - - console.error( e ); - - } - - scope.manager.itemError( url ); - - } - - } - -} - -const _eyeRight = /*@__PURE__*/ new Matrix4(); -const _eyeLeft = /*@__PURE__*/ new Matrix4(); -const _projectionMatrix = /*@__PURE__*/ new Matrix4(); - -class StereoCamera { - - constructor() { - - this.type = 'StereoCamera'; - - this.aspect = 1; - - this.eyeSep = 0.064; - - this.cameraL = new PerspectiveCamera(); - this.cameraL.layers.enable( 1 ); - this.cameraL.matrixAutoUpdate = false; - - this.cameraR = new PerspectiveCamera(); - this.cameraR.layers.enable( 2 ); - this.cameraR.matrixAutoUpdate = false; - - this._cache = { - focus: null, - fov: null, - aspect: null, - near: null, - far: null, - zoom: null, - eyeSep: null - }; - - } - - update( camera ) { - - const cache = this._cache; - - const needsUpdate = cache.focus !== camera.focus || cache.fov !== camera.fov || - cache.aspect !== camera.aspect * this.aspect || cache.near !== camera.near || - cache.far !== camera.far || cache.zoom !== camera.zoom || cache.eyeSep !== this.eyeSep; - - if ( needsUpdate ) { - - cache.focus = camera.focus; - cache.fov = camera.fov; - cache.aspect = camera.aspect * this.aspect; - cache.near = camera.near; - cache.far = camera.far; - cache.zoom = camera.zoom; - cache.eyeSep = this.eyeSep; - - // Off-axis stereoscopic effect based on - // http://paulbourke.net/stereographics/stereorender/ - - _projectionMatrix.copy( camera.projectionMatrix ); - const eyeSepHalf = cache.eyeSep / 2; - const eyeSepOnProjection = eyeSepHalf * cache.near / cache.focus; - const ymax = ( cache.near * Math.tan( DEG2RAD * cache.fov * 0.5 ) ) / cache.zoom; - let xmin, xmax; - - // translate xOffset - - _eyeLeft.elements[ 12 ] = - eyeSepHalf; - _eyeRight.elements[ 12 ] = eyeSepHalf; - - // for left eye - - xmin = - ymax * cache.aspect + eyeSepOnProjection; - xmax = ymax * cache.aspect + eyeSepOnProjection; - - _projectionMatrix.elements[ 0 ] = 2 * cache.near / ( xmax - xmin ); - _projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin ); - - this.cameraL.projectionMatrix.copy( _projectionMatrix ); - - // for right eye - - xmin = - ymax * cache.aspect - eyeSepOnProjection; - xmax = ymax * cache.aspect - eyeSepOnProjection; - - _projectionMatrix.elements[ 0 ] = 2 * cache.near / ( xmax - xmin ); - _projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin ); - - this.cameraR.projectionMatrix.copy( _projectionMatrix ); - - } - - this.cameraL.matrixWorld.copy( camera.matrixWorld ).multiply( _eyeLeft ); - this.cameraR.matrixWorld.copy( camera.matrixWorld ).multiply( _eyeRight ); - - } - -} - -class Clock { - - constructor( autoStart = true ) { - - this.autoStart = autoStart; - - this.startTime = 0; - this.oldTime = 0; - this.elapsedTime = 0; - - this.running = false; - - } - - start() { - - this.startTime = now(); - - this.oldTime = this.startTime; - this.elapsedTime = 0; - this.running = true; - - } - - stop() { - - this.getElapsedTime(); - this.running = false; - this.autoStart = false; - - } - - getElapsedTime() { - - this.getDelta(); - return this.elapsedTime; - - } - - getDelta() { - - let diff = 0; - - if ( this.autoStart && ! this.running ) { - - this.start(); - return 0; - - } - - if ( this.running ) { - - const newTime = now(); - - diff = ( newTime - this.oldTime ) / 1000; - this.oldTime = newTime; - - this.elapsedTime += diff; - - } - - return diff; - - } - -} - -function now() { - - return ( typeof performance === 'undefined' ? Date : performance ).now(); // see #10732 - -} - -const _position$1 = /*@__PURE__*/ new Vector3(); -const _quaternion$1 = /*@__PURE__*/ new Quaternion(); -const _scale$1 = /*@__PURE__*/ new Vector3(); -const _orientation$1 = /*@__PURE__*/ new Vector3(); - -class AudioListener extends Object3D { - - constructor() { - - super(); - - this.type = 'AudioListener'; - - this.context = AudioContext.getContext(); - - this.gain = this.context.createGain(); - this.gain.connect( this.context.destination ); - - this.filter = null; - - this.timeDelta = 0; - - // private - - this._clock = new Clock(); - - } - - getInput() { - - return this.gain; - - } - - removeFilter() { - - if ( this.filter !== null ) { - - this.gain.disconnect( this.filter ); - this.filter.disconnect( this.context.destination ); - this.gain.connect( this.context.destination ); - this.filter = null; - - } - - return this; - - } - - getFilter() { - - return this.filter; - - } - - setFilter( value ) { - - if ( this.filter !== null ) { - - this.gain.disconnect( this.filter ); - this.filter.disconnect( this.context.destination ); - - } else { - - this.gain.disconnect( this.context.destination ); - - } - - this.filter = value; - this.gain.connect( this.filter ); - this.filter.connect( this.context.destination ); - - return this; - - } - - getMasterVolume() { - - return this.gain.gain.value; - - } - - setMasterVolume( value ) { - - this.gain.gain.setTargetAtTime( value, this.context.currentTime, 0.01 ); - - return this; - - } - - updateMatrixWorld( force ) { - - super.updateMatrixWorld( force ); - - const listener = this.context.listener; - const up = this.up; - - this.timeDelta = this._clock.getDelta(); - - this.matrixWorld.decompose( _position$1, _quaternion$1, _scale$1 ); - - _orientation$1.set( 0, 0, - 1 ).applyQuaternion( _quaternion$1 ); - - if ( listener.positionX ) { - - // code path for Chrome (see #14393) - - const endTime = this.context.currentTime + this.timeDelta; - - listener.positionX.linearRampToValueAtTime( _position$1.x, endTime ); - listener.positionY.linearRampToValueAtTime( _position$1.y, endTime ); - listener.positionZ.linearRampToValueAtTime( _position$1.z, endTime ); - listener.forwardX.linearRampToValueAtTime( _orientation$1.x, endTime ); - listener.forwardY.linearRampToValueAtTime( _orientation$1.y, endTime ); - listener.forwardZ.linearRampToValueAtTime( _orientation$1.z, endTime ); - listener.upX.linearRampToValueAtTime( up.x, endTime ); - listener.upY.linearRampToValueAtTime( up.y, endTime ); - listener.upZ.linearRampToValueAtTime( up.z, endTime ); - - } else { - - listener.setPosition( _position$1.x, _position$1.y, _position$1.z ); - listener.setOrientation( _orientation$1.x, _orientation$1.y, _orientation$1.z, up.x, up.y, up.z ); - - } - - } - -} - -class Audio extends Object3D { - - constructor( listener ) { - - super(); - - this.type = 'Audio'; - - this.listener = listener; - this.context = listener.context; - - this.gain = this.context.createGain(); - this.gain.connect( listener.getInput() ); - - this.autoplay = false; - - this.buffer = null; - this.detune = 0; - this.loop = false; - this.loopStart = 0; - this.loopEnd = 0; - this.offset = 0; - this.duration = undefined; - this.playbackRate = 1; - this.isPlaying = false; - this.hasPlaybackControl = true; - this.source = null; - this.sourceType = 'empty'; - - this._startedAt = 0; - this._progress = 0; - this._connected = false; - - this.filters = []; - - } - - getOutput() { - - return this.gain; - - } - - setNodeSource( audioNode ) { - - this.hasPlaybackControl = false; - this.sourceType = 'audioNode'; - this.source = audioNode; - this.connect(); - - return this; - - } - - setMediaElementSource( mediaElement ) { - - this.hasPlaybackControl = false; - this.sourceType = 'mediaNode'; - this.source = this.context.createMediaElementSource( mediaElement ); - this.connect(); - - return this; - - } - - setMediaStreamSource( mediaStream ) { - - this.hasPlaybackControl = false; - this.sourceType = 'mediaStreamNode'; - this.source = this.context.createMediaStreamSource( mediaStream ); - this.connect(); - - return this; - - } - - setBuffer( audioBuffer ) { - - this.buffer = audioBuffer; - this.sourceType = 'buffer'; - - if ( this.autoplay ) this.play(); - - return this; - - } - - play( delay = 0 ) { - - if ( this.isPlaying === true ) { - - console.warn( 'THREE.Audio: Audio is already playing.' ); - return; - - } - - if ( this.hasPlaybackControl === false ) { - - console.warn( 'THREE.Audio: this Audio has no playback control.' ); - return; - - } - - this._startedAt = this.context.currentTime + delay; - - const source = this.context.createBufferSource(); - source.buffer = this.buffer; - source.loop = this.loop; - source.loopStart = this.loopStart; - source.loopEnd = this.loopEnd; - source.onended = this.onEnded.bind( this ); - source.start( this._startedAt, this._progress + this.offset, this.duration ); - - this.isPlaying = true; - - this.source = source; - - this.setDetune( this.detune ); - this.setPlaybackRate( this.playbackRate ); - - return this.connect(); - - } - - pause() { - - if ( this.hasPlaybackControl === false ) { - - console.warn( 'THREE.Audio: this Audio has no playback control.' ); - return; - - } - - if ( this.isPlaying === true ) { - - // update current progress - - this._progress += Math.max( this.context.currentTime - this._startedAt, 0 ) * this.playbackRate; - - if ( this.loop === true ) { - - // ensure _progress does not exceed duration with looped audios - - this._progress = this._progress % ( this.duration || this.buffer.duration ); - - } - - this.source.stop(); - this.source.onended = null; - - this.isPlaying = false; - - } - - return this; - - } - - stop() { - - if ( this.hasPlaybackControl === false ) { - - console.warn( 'THREE.Audio: this Audio has no playback control.' ); - return; - - } - - this._progress = 0; - - if ( this.source !== null ) { - - this.source.stop(); - this.source.onended = null; - - } - - this.isPlaying = false; - - return this; - - } - - connect() { - - if ( this.filters.length > 0 ) { - - this.source.connect( this.filters[ 0 ] ); - - for ( let i = 1, l = this.filters.length; i < l; i ++ ) { - - this.filters[ i - 1 ].connect( this.filters[ i ] ); - - } - - this.filters[ this.filters.length - 1 ].connect( this.getOutput() ); - - } else { - - this.source.connect( this.getOutput() ); - - } - - this._connected = true; - - return this; - - } - - disconnect() { - - if ( this._connected === false ) { - - return; - - } - - if ( this.filters.length > 0 ) { - - this.source.disconnect( this.filters[ 0 ] ); - - for ( let i = 1, l = this.filters.length; i < l; i ++ ) { - - this.filters[ i - 1 ].disconnect( this.filters[ i ] ); - - } - - this.filters[ this.filters.length - 1 ].disconnect( this.getOutput() ); - - } else { - - this.source.disconnect( this.getOutput() ); - - } - - this._connected = false; - - return this; - - } - - getFilters() { - - return this.filters; - - } - - setFilters( value ) { - - if ( ! value ) value = []; - - if ( this._connected === true ) { - - this.disconnect(); - this.filters = value.slice(); - this.connect(); - - } else { - - this.filters = value.slice(); - - } - - return this; - - } - - setDetune( value ) { - - this.detune = value; - - if ( this.isPlaying === true && this.source.detune !== undefined ) { - - this.source.detune.setTargetAtTime( this.detune, this.context.currentTime, 0.01 ); - - } - - return this; - - } - - getDetune() { - - return this.detune; - - } - - getFilter() { - - return this.getFilters()[ 0 ]; - - } - - setFilter( filter ) { - - return this.setFilters( filter ? [ filter ] : [] ); - - } - - setPlaybackRate( value ) { - - if ( this.hasPlaybackControl === false ) { - - console.warn( 'THREE.Audio: this Audio has no playback control.' ); - return; - - } - - this.playbackRate = value; - - if ( this.isPlaying === true ) { - - this.source.playbackRate.setTargetAtTime( this.playbackRate, this.context.currentTime, 0.01 ); - - } - - return this; - - } - - getPlaybackRate() { - - return this.playbackRate; - - } - - onEnded() { - - this.isPlaying = false; - - } - - getLoop() { - - if ( this.hasPlaybackControl === false ) { - - console.warn( 'THREE.Audio: this Audio has no playback control.' ); - return false; - - } - - return this.loop; - - } - - setLoop( value ) { - - if ( this.hasPlaybackControl === false ) { - - console.warn( 'THREE.Audio: this Audio has no playback control.' ); - return; - - } - - this.loop = value; - - if ( this.isPlaying === true ) { - - this.source.loop = this.loop; - - } - - return this; - - } - - setLoopStart( value ) { - - this.loopStart = value; - - return this; - - } - - setLoopEnd( value ) { - - this.loopEnd = value; - - return this; - - } - - getVolume() { - - return this.gain.gain.value; - - } - - setVolume( value ) { - - this.gain.gain.setTargetAtTime( value, this.context.currentTime, 0.01 ); - - return this; - - } - -} - -const _position = /*@__PURE__*/ new Vector3(); -const _quaternion = /*@__PURE__*/ new Quaternion(); -const _scale = /*@__PURE__*/ new Vector3(); -const _orientation = /*@__PURE__*/ new Vector3(); - -class PositionalAudio extends Audio { - - constructor( listener ) { - - super( listener ); - - this.panner = this.context.createPanner(); - this.panner.panningModel = 'HRTF'; - this.panner.connect( this.gain ); - - } - - connect() { - - super.connect(); - - this.panner.connect( this.gain ); - - } - - disconnect() { - - super.disconnect(); - - this.panner.disconnect( this.gain ); - - } - - getOutput() { - - return this.panner; - - } - - getRefDistance() { - - return this.panner.refDistance; - - } - - setRefDistance( value ) { - - this.panner.refDistance = value; - - return this; - - } - - getRolloffFactor() { - - return this.panner.rolloffFactor; - - } - - setRolloffFactor( value ) { - - this.panner.rolloffFactor = value; - - return this; - - } - - getDistanceModel() { - - return this.panner.distanceModel; - - } - - setDistanceModel( value ) { - - this.panner.distanceModel = value; - - return this; - - } - - getMaxDistance() { - - return this.panner.maxDistance; - - } - - setMaxDistance( value ) { - - this.panner.maxDistance = value; - - return this; - - } - - setDirectionalCone( coneInnerAngle, coneOuterAngle, coneOuterGain ) { - - this.panner.coneInnerAngle = coneInnerAngle; - this.panner.coneOuterAngle = coneOuterAngle; - this.panner.coneOuterGain = coneOuterGain; - - return this; - - } - - updateMatrixWorld( force ) { - - super.updateMatrixWorld( force ); - - if ( this.hasPlaybackControl === true && this.isPlaying === false ) return; - - this.matrixWorld.decompose( _position, _quaternion, _scale ); - - _orientation.set( 0, 0, 1 ).applyQuaternion( _quaternion ); - - const panner = this.panner; - - if ( panner.positionX ) { - - // code path for Chrome and Firefox (see #14393) - - const endTime = this.context.currentTime + this.listener.timeDelta; - - panner.positionX.linearRampToValueAtTime( _position.x, endTime ); - panner.positionY.linearRampToValueAtTime( _position.y, endTime ); - panner.positionZ.linearRampToValueAtTime( _position.z, endTime ); - panner.orientationX.linearRampToValueAtTime( _orientation.x, endTime ); - panner.orientationY.linearRampToValueAtTime( _orientation.y, endTime ); - panner.orientationZ.linearRampToValueAtTime( _orientation.z, endTime ); - - } else { - - panner.setPosition( _position.x, _position.y, _position.z ); - panner.setOrientation( _orientation.x, _orientation.y, _orientation.z ); - - } - - } - -} - -class AudioAnalyser { - - constructor( audio, fftSize = 2048 ) { - - this.analyser = audio.context.createAnalyser(); - this.analyser.fftSize = fftSize; - - this.data = new Uint8Array( this.analyser.frequencyBinCount ); - - audio.getOutput().connect( this.analyser ); - - } - - - getFrequencyData() { - - this.analyser.getByteFrequencyData( this.data ); - - return this.data; - - } - - getAverageFrequency() { - - let value = 0; - const data = this.getFrequencyData(); - - for ( let i = 0; i < data.length; i ++ ) { - - value += data[ i ]; - - } - - return value / data.length; - - } - -} - -class PropertyMixer { - - constructor( binding, typeName, valueSize ) { - - this.binding = binding; - this.valueSize = valueSize; - - let mixFunction, - mixFunctionAdditive, - setIdentity; - - // buffer layout: [ incoming | accu0 | accu1 | orig | addAccu | (optional work) ] - // - // interpolators can use .buffer as their .result - // the data then goes to 'incoming' - // - // 'accu0' and 'accu1' are used frame-interleaved for - // the cumulative result and are compared to detect - // changes - // - // 'orig' stores the original state of the property - // - // 'add' is used for additive cumulative results - // - // 'work' is optional and is only present for quaternion types. It is used - // to store intermediate quaternion multiplication results - - switch ( typeName ) { - - case 'quaternion': - mixFunction = this._slerp; - mixFunctionAdditive = this._slerpAdditive; - setIdentity = this._setAdditiveIdentityQuaternion; - - this.buffer = new Float64Array( valueSize * 6 ); - this._workIndex = 5; - break; - - case 'string': - case 'bool': - mixFunction = this._select; - - // Use the regular mix function and for additive on these types, - // additive is not relevant for non-numeric types - mixFunctionAdditive = this._select; - - setIdentity = this._setAdditiveIdentityOther; - - this.buffer = new Array( valueSize * 5 ); - break; - - default: - mixFunction = this._lerp; - mixFunctionAdditive = this._lerpAdditive; - setIdentity = this._setAdditiveIdentityNumeric; - - this.buffer = new Float64Array( valueSize * 5 ); - - } - - this._mixBufferRegion = mixFunction; - this._mixBufferRegionAdditive = mixFunctionAdditive; - this._setIdentity = setIdentity; - this._origIndex = 3; - this._addIndex = 4; - - this.cumulativeWeight = 0; - this.cumulativeWeightAdditive = 0; - - this.useCount = 0; - this.referenceCount = 0; - - } - - // accumulate data in the 'incoming' region into 'accu' - accumulate( accuIndex, weight ) { - - // note: happily accumulating nothing when weight = 0, the caller knows - // the weight and shouldn't have made the call in the first place - - const buffer = this.buffer, - stride = this.valueSize, - offset = accuIndex * stride + stride; - - let currentWeight = this.cumulativeWeight; - - if ( currentWeight === 0 ) { - - // accuN := incoming * weight - - for ( let i = 0; i !== stride; ++ i ) { - - buffer[ offset + i ] = buffer[ i ]; - - } - - currentWeight = weight; - - } else { - - // accuN := accuN + incoming * weight - - currentWeight += weight; - const mix = weight / currentWeight; - this._mixBufferRegion( buffer, offset, 0, mix, stride ); - - } - - this.cumulativeWeight = currentWeight; - - } - - // accumulate data in the 'incoming' region into 'add' - accumulateAdditive( weight ) { - - const buffer = this.buffer, - stride = this.valueSize, - offset = stride * this._addIndex; - - if ( this.cumulativeWeightAdditive === 0 ) { - - // add = identity - - this._setIdentity(); - - } - - // add := add + incoming * weight - - this._mixBufferRegionAdditive( buffer, offset, 0, weight, stride ); - this.cumulativeWeightAdditive += weight; - - } - - // apply the state of 'accu' to the binding when accus differ - apply( accuIndex ) { - - const stride = this.valueSize, - buffer = this.buffer, - offset = accuIndex * stride + stride, - - weight = this.cumulativeWeight, - weightAdditive = this.cumulativeWeightAdditive, - - binding = this.binding; - - this.cumulativeWeight = 0; - this.cumulativeWeightAdditive = 0; - - if ( weight < 1 ) { - - // accuN := accuN + original * ( 1 - cumulativeWeight ) - - const originalValueOffset = stride * this._origIndex; - - this._mixBufferRegion( - buffer, offset, originalValueOffset, 1 - weight, stride ); - - } - - if ( weightAdditive > 0 ) { - - // accuN := accuN + additive accuN - - this._mixBufferRegionAdditive( buffer, offset, this._addIndex * stride, 1, stride ); - - } - - for ( let i = stride, e = stride + stride; i !== e; ++ i ) { - - if ( buffer[ i ] !== buffer[ i + stride ] ) { - - // value has changed -> update scene graph - - binding.setValue( buffer, offset ); - break; - - } - - } - - } - - // remember the state of the bound property and copy it to both accus - saveOriginalState() { - - const binding = this.binding; - - const buffer = this.buffer, - stride = this.valueSize, - - originalValueOffset = stride * this._origIndex; - - binding.getValue( buffer, originalValueOffset ); - - // accu[0..1] := orig -- initially detect changes against the original - for ( let i = stride, e = originalValueOffset; i !== e; ++ i ) { - - buffer[ i ] = buffer[ originalValueOffset + ( i % stride ) ]; - - } - - // Add to identity for additive - this._setIdentity(); - - this.cumulativeWeight = 0; - this.cumulativeWeightAdditive = 0; - - } - - // apply the state previously taken via 'saveOriginalState' to the binding - restoreOriginalState() { - - const originalValueOffset = this.valueSize * 3; - this.binding.setValue( this.buffer, originalValueOffset ); - - } - - _setAdditiveIdentityNumeric() { - - const startIndex = this._addIndex * this.valueSize; - const endIndex = startIndex + this.valueSize; - - for ( let i = startIndex; i < endIndex; i ++ ) { - - this.buffer[ i ] = 0; - - } - - } - - _setAdditiveIdentityQuaternion() { - - this._setAdditiveIdentityNumeric(); - this.buffer[ this._addIndex * this.valueSize + 3 ] = 1; - - } - - _setAdditiveIdentityOther() { - - const startIndex = this._origIndex * this.valueSize; - const targetIndex = this._addIndex * this.valueSize; - - for ( let i = 0; i < this.valueSize; i ++ ) { - - this.buffer[ targetIndex + i ] = this.buffer[ startIndex + i ]; - - } - - } - - - // mix functions - - _select( buffer, dstOffset, srcOffset, t, stride ) { - - if ( t >= 0.5 ) { - - for ( let i = 0; i !== stride; ++ i ) { - - buffer[ dstOffset + i ] = buffer[ srcOffset + i ]; - - } - - } - - } - - _slerp( buffer, dstOffset, srcOffset, t ) { - - Quaternion.slerpFlat( buffer, dstOffset, buffer, dstOffset, buffer, srcOffset, t ); - - } - - _slerpAdditive( buffer, dstOffset, srcOffset, t, stride ) { - - const workOffset = this._workIndex * stride; - - // Store result in intermediate buffer offset - Quaternion.multiplyQuaternionsFlat( buffer, workOffset, buffer, dstOffset, buffer, srcOffset ); - - // Slerp to the intermediate result - Quaternion.slerpFlat( buffer, dstOffset, buffer, dstOffset, buffer, workOffset, t ); - - } - - _lerp( buffer, dstOffset, srcOffset, t, stride ) { - - const s = 1 - t; - - for ( let i = 0; i !== stride; ++ i ) { - - const j = dstOffset + i; - - buffer[ j ] = buffer[ j ] * s + buffer[ srcOffset + i ] * t; - - } - - } - - _lerpAdditive( buffer, dstOffset, srcOffset, t, stride ) { - - for ( let i = 0; i !== stride; ++ i ) { - - const j = dstOffset + i; - - buffer[ j ] = buffer[ j ] + buffer[ srcOffset + i ] * t; - - } - - } - -} - -// Characters [].:/ are reserved for track binding syntax. -const _RESERVED_CHARS_RE = '\\[\\]\\.:\\/'; -const _reservedRe = new RegExp( '[' + _RESERVED_CHARS_RE + ']', 'g' ); - -// Attempts to allow node names from any language. ES5's `\w` regexp matches -// only latin characters, and the unicode \p{L} is not yet supported. So -// instead, we exclude reserved characters and match everything else. -const _wordChar = '[^' + _RESERVED_CHARS_RE + ']'; -const _wordCharOrDot = '[^' + _RESERVED_CHARS_RE.replace( '\\.', '' ) + ']'; - -// Parent directories, delimited by '/' or ':'. Currently unused, but must -// be matched to parse the rest of the track name. -const _directoryRe = /*@__PURE__*/ /((?:WC+[\/:])*)/.source.replace( 'WC', _wordChar ); - -// Target node. May contain word characters (a-zA-Z0-9_) and '.' or '-'. -const _nodeRe = /*@__PURE__*/ /(WCOD+)?/.source.replace( 'WCOD', _wordCharOrDot ); - -// Object on target node, and accessor. May not contain reserved -// characters. Accessor may contain any character except closing bracket. -const _objectRe = /*@__PURE__*/ /(?:\.(WC+)(?:\[(.+)\])?)?/.source.replace( 'WC', _wordChar ); - -// Property and accessor. May not contain reserved characters. Accessor may -// contain any non-bracket characters. -const _propertyRe = /*@__PURE__*/ /\.(WC+)(?:\[(.+)\])?/.source.replace( 'WC', _wordChar ); - -const _trackRe = new RegExp( '' - + '^' - + _directoryRe - + _nodeRe - + _objectRe - + _propertyRe - + '$' -); - -const _supportedObjectNames = [ 'material', 'materials', 'bones', 'map' ]; - -class Composite { - - constructor( targetGroup, path, optionalParsedPath ) { - - const parsedPath = optionalParsedPath || PropertyBinding.parseTrackName( path ); - - this._targetGroup = targetGroup; - this._bindings = targetGroup.subscribe_( path, parsedPath ); - - } - - getValue( array, offset ) { - - this.bind(); // bind all binding - - const firstValidIndex = this._targetGroup.nCachedObjects_, - binding = this._bindings[ firstValidIndex ]; - - // and only call .getValue on the first - if ( binding !== undefined ) binding.getValue( array, offset ); - - } - - setValue( array, offset ) { - - const bindings = this._bindings; - - for ( let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) { - - bindings[ i ].setValue( array, offset ); - - } - - } - - bind() { - - const bindings = this._bindings; - - for ( let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) { - - bindings[ i ].bind(); - - } - - } - - unbind() { - - const bindings = this._bindings; - - for ( let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) { - - bindings[ i ].unbind(); - - } - - } - -} - -// Note: This class uses a State pattern on a per-method basis: -// 'bind' sets 'this.getValue' / 'setValue' and shadows the -// prototype version of these methods with one that represents -// the bound state. When the property is not found, the methods -// become no-ops. -class PropertyBinding { - - constructor( rootNode, path, parsedPath ) { - - this.path = path; - this.parsedPath = parsedPath || PropertyBinding.parseTrackName( path ); - - this.node = PropertyBinding.findNode( rootNode, this.parsedPath.nodeName ); - - this.rootNode = rootNode; - - // initial state of these methods that calls 'bind' - this.getValue = this._getValue_unbound; - this.setValue = this._setValue_unbound; - - } - - - static create( root, path, parsedPath ) { - - if ( ! ( root && root.isAnimationObjectGroup ) ) { - - return new PropertyBinding( root, path, parsedPath ); - - } else { - - return new PropertyBinding.Composite( root, path, parsedPath ); - - } - - } - - /** - * Replaces spaces with underscores and removes unsupported characters from - * node names, to ensure compatibility with parseTrackName(). - * - * @param {string} name Node name to be sanitized. - * @return {string} - */ - static sanitizeNodeName( name ) { - - return name.replace( /\s/g, '_' ).replace( _reservedRe, '' ); - - } - - static parseTrackName( trackName ) { - - const matches = _trackRe.exec( trackName ); - - if ( matches === null ) { - - throw new Error( 'PropertyBinding: Cannot parse trackName: ' + trackName ); - - } - - const results = { - // directoryName: matches[ 1 ], // (tschw) currently unused - nodeName: matches[ 2 ], - objectName: matches[ 3 ], - objectIndex: matches[ 4 ], - propertyName: matches[ 5 ], // required - propertyIndex: matches[ 6 ] - }; - - const lastDot = results.nodeName && results.nodeName.lastIndexOf( '.' ); - - if ( lastDot !== undefined && lastDot !== - 1 ) { - - const objectName = results.nodeName.substring( lastDot + 1 ); - - // Object names must be checked against an allowlist. Otherwise, there - // is no way to parse 'foo.bar.baz': 'baz' must be a property, but - // 'bar' could be the objectName, or part of a nodeName (which can - // include '.' characters). - if ( _supportedObjectNames.indexOf( objectName ) !== - 1 ) { - - results.nodeName = results.nodeName.substring( 0, lastDot ); - results.objectName = objectName; - - } - - } - - if ( results.propertyName === null || results.propertyName.length === 0 ) { - - throw new Error( 'PropertyBinding: can not parse propertyName from trackName: ' + trackName ); - - } - - return results; - - } - - static findNode( root, nodeName ) { - - if ( nodeName === undefined || nodeName === '' || nodeName === '.' || nodeName === - 1 || nodeName === root.name || nodeName === root.uuid ) { - - return root; - - } - - // search into skeleton bones. - if ( root.skeleton ) { - - const bone = root.skeleton.getBoneByName( nodeName ); - - if ( bone !== undefined ) { - - return bone; - - } - - } - - // search into node subtree. - if ( root.children ) { - - const searchNodeSubtree = function ( children ) { - - for ( let i = 0; i < children.length; i ++ ) { - - const childNode = children[ i ]; - - if ( childNode.name === nodeName || childNode.uuid === nodeName ) { - - return childNode; - - } - - const result = searchNodeSubtree( childNode.children ); - - if ( result ) return result; - - } - - return null; - - }; - - const subTreeNode = searchNodeSubtree( root.children ); - - if ( subTreeNode ) { - - return subTreeNode; - - } - - } - - return null; - - } - - // these are used to "bind" a nonexistent property - _getValue_unavailable() {} - _setValue_unavailable() {} - - // Getters - - _getValue_direct( buffer, offset ) { - - buffer[ offset ] = this.targetObject[ this.propertyName ]; - - } - - _getValue_array( buffer, offset ) { - - const source = this.resolvedProperty; - - for ( let i = 0, n = source.length; i !== n; ++ i ) { - - buffer[ offset ++ ] = source[ i ]; - - } - - } - - _getValue_arrayElement( buffer, offset ) { - - buffer[ offset ] = this.resolvedProperty[ this.propertyIndex ]; - - } - - _getValue_toArray( buffer, offset ) { - - this.resolvedProperty.toArray( buffer, offset ); - - } - - // Direct - - _setValue_direct( buffer, offset ) { - - this.targetObject[ this.propertyName ] = buffer[ offset ]; - - } - - _setValue_direct_setNeedsUpdate( buffer, offset ) { - - this.targetObject[ this.propertyName ] = buffer[ offset ]; - this.targetObject.needsUpdate = true; - - } - - _setValue_direct_setMatrixWorldNeedsUpdate( buffer, offset ) { - - this.targetObject[ this.propertyName ] = buffer[ offset ]; - this.targetObject.matrixWorldNeedsUpdate = true; - - } - - // EntireArray - - _setValue_array( buffer, offset ) { - - const dest = this.resolvedProperty; - - for ( let i = 0, n = dest.length; i !== n; ++ i ) { - - dest[ i ] = buffer[ offset ++ ]; - - } - - } - - _setValue_array_setNeedsUpdate( buffer, offset ) { - - const dest = this.resolvedProperty; - - for ( let i = 0, n = dest.length; i !== n; ++ i ) { - - dest[ i ] = buffer[ offset ++ ]; - - } - - this.targetObject.needsUpdate = true; - - } - - _setValue_array_setMatrixWorldNeedsUpdate( buffer, offset ) { - - const dest = this.resolvedProperty; - - for ( let i = 0, n = dest.length; i !== n; ++ i ) { - - dest[ i ] = buffer[ offset ++ ]; - - } - - this.targetObject.matrixWorldNeedsUpdate = true; - - } - - // ArrayElement - - _setValue_arrayElement( buffer, offset ) { - - this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ]; - - } - - _setValue_arrayElement_setNeedsUpdate( buffer, offset ) { - - this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ]; - this.targetObject.needsUpdate = true; - - } - - _setValue_arrayElement_setMatrixWorldNeedsUpdate( buffer, offset ) { - - this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ]; - this.targetObject.matrixWorldNeedsUpdate = true; - - } - - // HasToFromArray - - _setValue_fromArray( buffer, offset ) { - - this.resolvedProperty.fromArray( buffer, offset ); - - } - - _setValue_fromArray_setNeedsUpdate( buffer, offset ) { - - this.resolvedProperty.fromArray( buffer, offset ); - this.targetObject.needsUpdate = true; - - } - - _setValue_fromArray_setMatrixWorldNeedsUpdate( buffer, offset ) { - - this.resolvedProperty.fromArray( buffer, offset ); - this.targetObject.matrixWorldNeedsUpdate = true; - - } - - _getValue_unbound( targetArray, offset ) { - - this.bind(); - this.getValue( targetArray, offset ); - - } - - _setValue_unbound( sourceArray, offset ) { - - this.bind(); - this.setValue( sourceArray, offset ); - - } - - // create getter / setter pair for a property in the scene graph - bind() { - - let targetObject = this.node; - const parsedPath = this.parsedPath; - - const objectName = parsedPath.objectName; - const propertyName = parsedPath.propertyName; - let propertyIndex = parsedPath.propertyIndex; - - if ( ! targetObject ) { - - targetObject = PropertyBinding.findNode( this.rootNode, parsedPath.nodeName ); - - this.node = targetObject; - - } - - // set fail state so we can just 'return' on error - this.getValue = this._getValue_unavailable; - this.setValue = this._setValue_unavailable; - - // ensure there is a value node - if ( ! targetObject ) { - - console.warn( 'THREE.PropertyBinding: No target node found for track: ' + this.path + '.' ); - return; - - } - - if ( objectName ) { - - let objectIndex = parsedPath.objectIndex; - - // special cases were we need to reach deeper into the hierarchy to get the face materials.... - switch ( objectName ) { - - case 'materials': - - if ( ! targetObject.material ) { - - console.error( 'THREE.PropertyBinding: Can not bind to material as node does not have a material.', this ); - return; - - } - - if ( ! targetObject.material.materials ) { - - console.error( 'THREE.PropertyBinding: Can not bind to material.materials as node.material does not have a materials array.', this ); - return; - - } - - targetObject = targetObject.material.materials; - - break; - - case 'bones': - - if ( ! targetObject.skeleton ) { - - console.error( 'THREE.PropertyBinding: Can not bind to bones as node does not have a skeleton.', this ); - return; - - } - - // potential future optimization: skip this if propertyIndex is already an integer - // and convert the integer string to a true integer. - - targetObject = targetObject.skeleton.bones; - - // support resolving morphTarget names into indices. - for ( let i = 0; i < targetObject.length; i ++ ) { - - if ( targetObject[ i ].name === objectIndex ) { - - objectIndex = i; - break; - - } - - } - - break; - - case 'map': - - if ( 'map' in targetObject ) { - - targetObject = targetObject.map; - break; - - } - - if ( ! targetObject.material ) { - - console.error( 'THREE.PropertyBinding: Can not bind to material as node does not have a material.', this ); - return; - - } - - if ( ! targetObject.material.map ) { - - console.error( 'THREE.PropertyBinding: Can not bind to material.map as node.material does not have a map.', this ); - return; - - } - - targetObject = targetObject.material.map; - break; - - default: - - if ( targetObject[ objectName ] === undefined ) { - - console.error( 'THREE.PropertyBinding: Can not bind to objectName of node undefined.', this ); - return; - - } - - targetObject = targetObject[ objectName ]; - - } - - - if ( objectIndex !== undefined ) { - - if ( targetObject[ objectIndex ] === undefined ) { - - console.error( 'THREE.PropertyBinding: Trying to bind to objectIndex of objectName, but is undefined.', this, targetObject ); - return; - - } - - targetObject = targetObject[ objectIndex ]; - - } - - } - - // resolve property - const nodeProperty = targetObject[ propertyName ]; - - if ( nodeProperty === undefined ) { - - const nodeName = parsedPath.nodeName; - - console.error( 'THREE.PropertyBinding: Trying to update property for track: ' + nodeName + - '.' + propertyName + ' but it wasn\'t found.', targetObject ); - return; - - } - - // determine versioning scheme - let versioning = this.Versioning.None; - - this.targetObject = targetObject; - - if ( targetObject.needsUpdate !== undefined ) { // material - - versioning = this.Versioning.NeedsUpdate; - - } else if ( targetObject.matrixWorldNeedsUpdate !== undefined ) { // node transform - - versioning = this.Versioning.MatrixWorldNeedsUpdate; - - } - - // determine how the property gets bound - let bindingType = this.BindingType.Direct; - - if ( propertyIndex !== undefined ) { - - // access a sub element of the property array (only primitives are supported right now) - - if ( propertyName === 'morphTargetInfluences' ) { - - // potential optimization, skip this if propertyIndex is already an integer, and convert the integer string to a true integer. - - // support resolving morphTarget names into indices. - if ( ! targetObject.geometry ) { - - console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.', this ); - return; - - } - - if ( ! targetObject.geometry.morphAttributes ) { - - console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.morphAttributes.', this ); - return; - - } - - if ( targetObject.morphTargetDictionary[ propertyIndex ] !== undefined ) { - - propertyIndex = targetObject.morphTargetDictionary[ propertyIndex ]; - - } - - } - - bindingType = this.BindingType.ArrayElement; - - this.resolvedProperty = nodeProperty; - this.propertyIndex = propertyIndex; - - } else if ( nodeProperty.fromArray !== undefined && nodeProperty.toArray !== undefined ) { - - // must use copy for Object3D.Euler/Quaternion - - bindingType = this.BindingType.HasFromToArray; - - this.resolvedProperty = nodeProperty; - - } else if ( Array.isArray( nodeProperty ) ) { - - bindingType = this.BindingType.EntireArray; - - this.resolvedProperty = nodeProperty; - - } else { - - this.propertyName = propertyName; - - } - - // select getter / setter - this.getValue = this.GetterByBindingType[ bindingType ]; - this.setValue = this.SetterByBindingTypeAndVersioning[ bindingType ][ versioning ]; - - } - - unbind() { - - this.node = null; - - // back to the prototype version of getValue / setValue - // note: avoiding to mutate the shape of 'this' via 'delete' - this.getValue = this._getValue_unbound; - this.setValue = this._setValue_unbound; - - } - -} - -PropertyBinding.Composite = Composite; - -PropertyBinding.prototype.BindingType = { - Direct: 0, - EntireArray: 1, - ArrayElement: 2, - HasFromToArray: 3 -}; - -PropertyBinding.prototype.Versioning = { - None: 0, - NeedsUpdate: 1, - MatrixWorldNeedsUpdate: 2 -}; - -PropertyBinding.prototype.GetterByBindingType = [ - - PropertyBinding.prototype._getValue_direct, - PropertyBinding.prototype._getValue_array, - PropertyBinding.prototype._getValue_arrayElement, - PropertyBinding.prototype._getValue_toArray, - -]; - -PropertyBinding.prototype.SetterByBindingTypeAndVersioning = [ - - [ - // Direct - PropertyBinding.prototype._setValue_direct, - PropertyBinding.prototype._setValue_direct_setNeedsUpdate, - PropertyBinding.prototype._setValue_direct_setMatrixWorldNeedsUpdate, - - ], [ - - // EntireArray - - PropertyBinding.prototype._setValue_array, - PropertyBinding.prototype._setValue_array_setNeedsUpdate, - PropertyBinding.prototype._setValue_array_setMatrixWorldNeedsUpdate, - - ], [ - - // ArrayElement - PropertyBinding.prototype._setValue_arrayElement, - PropertyBinding.prototype._setValue_arrayElement_setNeedsUpdate, - PropertyBinding.prototype._setValue_arrayElement_setMatrixWorldNeedsUpdate, - - ], [ - - // HasToFromArray - PropertyBinding.prototype._setValue_fromArray, - PropertyBinding.prototype._setValue_fromArray_setNeedsUpdate, - PropertyBinding.prototype._setValue_fromArray_setMatrixWorldNeedsUpdate, - - ] - -]; - -/** - * - * A group of objects that receives a shared animation state. - * - * Usage: - * - * - Add objects you would otherwise pass as 'root' to the - * constructor or the .clipAction method of AnimationMixer. - * - * - Instead pass this object as 'root'. - * - * - You can also add and remove objects later when the mixer - * is running. - * - * Note: - * - * Objects of this class appear as one object to the mixer, - * so cache control of the individual objects must be done - * on the group. - * - * Limitation: - * - * - The animated properties must be compatible among the - * all objects in the group. - * - * - A single property can either be controlled through a - * target group or directly, but not both. - */ - -class AnimationObjectGroup { - - constructor() { - - this.isAnimationObjectGroup = true; - - this.uuid = generateUUID(); - - // cached objects followed by the active ones - this._objects = Array.prototype.slice.call( arguments ); - - this.nCachedObjects_ = 0; // threshold - // note: read by PropertyBinding.Composite - - const indices = {}; - this._indicesByUUID = indices; // for bookkeeping - - for ( let i = 0, n = arguments.length; i !== n; ++ i ) { - - indices[ arguments[ i ].uuid ] = i; - - } - - this._paths = []; // inside: string - this._parsedPaths = []; // inside: { we don't care, here } - this._bindings = []; // inside: Array< PropertyBinding > - this._bindingsIndicesByPath = {}; // inside: indices in these arrays - - const scope = this; - - this.stats = { - - objects: { - get total() { - - return scope._objects.length; - - }, - get inUse() { - - return this.total - scope.nCachedObjects_; - - } - }, - get bindingsPerObject() { - - return scope._bindings.length; - - } - - }; - - } - - add() { - - const objects = this._objects, - indicesByUUID = this._indicesByUUID, - paths = this._paths, - parsedPaths = this._parsedPaths, - bindings = this._bindings, - nBindings = bindings.length; - - let knownObject = undefined, - nObjects = objects.length, - nCachedObjects = this.nCachedObjects_; - - for ( let i = 0, n = arguments.length; i !== n; ++ i ) { - - const object = arguments[ i ], - uuid = object.uuid; - let index = indicesByUUID[ uuid ]; - - if ( index === undefined ) { - - // unknown object -> add it to the ACTIVE region - - index = nObjects ++; - indicesByUUID[ uuid ] = index; - objects.push( object ); - - // accounting is done, now do the same for all bindings - - for ( let j = 0, m = nBindings; j !== m; ++ j ) { - - bindings[ j ].push( new PropertyBinding( object, paths[ j ], parsedPaths[ j ] ) ); - - } - - } else if ( index < nCachedObjects ) { - - knownObject = objects[ index ]; - - // move existing object to the ACTIVE region - - const firstActiveIndex = -- nCachedObjects, - lastCachedObject = objects[ firstActiveIndex ]; - - indicesByUUID[ lastCachedObject.uuid ] = index; - objects[ index ] = lastCachedObject; - - indicesByUUID[ uuid ] = firstActiveIndex; - objects[ firstActiveIndex ] = object; - - // accounting is done, now do the same for all bindings - - for ( let j = 0, m = nBindings; j !== m; ++ j ) { - - const bindingsForPath = bindings[ j ], - lastCached = bindingsForPath[ firstActiveIndex ]; - - let binding = bindingsForPath[ index ]; - - bindingsForPath[ index ] = lastCached; - - if ( binding === undefined ) { - - // since we do not bother to create new bindings - // for objects that are cached, the binding may - // or may not exist - - binding = new PropertyBinding( object, paths[ j ], parsedPaths[ j ] ); - - } - - bindingsForPath[ firstActiveIndex ] = binding; - - } - - } else if ( objects[ index ] !== knownObject ) { - - console.error( 'THREE.AnimationObjectGroup: Different objects with the same UUID ' + - 'detected. Clean the caches or recreate your infrastructure when reloading scenes.' ); - - } // else the object is already where we want it to be - - } // for arguments - - this.nCachedObjects_ = nCachedObjects; - - } - - remove() { - - const objects = this._objects, - indicesByUUID = this._indicesByUUID, - bindings = this._bindings, - nBindings = bindings.length; - - let nCachedObjects = this.nCachedObjects_; - - for ( let i = 0, n = arguments.length; i !== n; ++ i ) { - - const object = arguments[ i ], - uuid = object.uuid, - index = indicesByUUID[ uuid ]; - - if ( index !== undefined && index >= nCachedObjects ) { - - // move existing object into the CACHED region - - const lastCachedIndex = nCachedObjects ++, - firstActiveObject = objects[ lastCachedIndex ]; - - indicesByUUID[ firstActiveObject.uuid ] = index; - objects[ index ] = firstActiveObject; - - indicesByUUID[ uuid ] = lastCachedIndex; - objects[ lastCachedIndex ] = object; - - // accounting is done, now do the same for all bindings - - for ( let j = 0, m = nBindings; j !== m; ++ j ) { - - const bindingsForPath = bindings[ j ], - firstActive = bindingsForPath[ lastCachedIndex ], - binding = bindingsForPath[ index ]; - - bindingsForPath[ index ] = firstActive; - bindingsForPath[ lastCachedIndex ] = binding; - - } - - } - - } // for arguments - - this.nCachedObjects_ = nCachedObjects; - - } - - // remove & forget - uncache() { - - const objects = this._objects, - indicesByUUID = this._indicesByUUID, - bindings = this._bindings, - nBindings = bindings.length; - - let nCachedObjects = this.nCachedObjects_, - nObjects = objects.length; - - for ( let i = 0, n = arguments.length; i !== n; ++ i ) { - - const object = arguments[ i ], - uuid = object.uuid, - index = indicesByUUID[ uuid ]; - - if ( index !== undefined ) { - - delete indicesByUUID[ uuid ]; - - if ( index < nCachedObjects ) { - - // object is cached, shrink the CACHED region - - const firstActiveIndex = -- nCachedObjects, - lastCachedObject = objects[ firstActiveIndex ], - lastIndex = -- nObjects, - lastObject = objects[ lastIndex ]; - - // last cached object takes this object's place - indicesByUUID[ lastCachedObject.uuid ] = index; - objects[ index ] = lastCachedObject; - - // last object goes to the activated slot and pop - indicesByUUID[ lastObject.uuid ] = firstActiveIndex; - objects[ firstActiveIndex ] = lastObject; - objects.pop(); - - // accounting is done, now do the same for all bindings - - for ( let j = 0, m = nBindings; j !== m; ++ j ) { - - const bindingsForPath = bindings[ j ], - lastCached = bindingsForPath[ firstActiveIndex ], - last = bindingsForPath[ lastIndex ]; - - bindingsForPath[ index ] = lastCached; - bindingsForPath[ firstActiveIndex ] = last; - bindingsForPath.pop(); - - } - - } else { - - // object is active, just swap with the last and pop - - const lastIndex = -- nObjects, - lastObject = objects[ lastIndex ]; - - if ( lastIndex > 0 ) { - - indicesByUUID[ lastObject.uuid ] = index; - - } - - objects[ index ] = lastObject; - objects.pop(); - - // accounting is done, now do the same for all bindings - - for ( let j = 0, m = nBindings; j !== m; ++ j ) { - - const bindingsForPath = bindings[ j ]; - - bindingsForPath[ index ] = bindingsForPath[ lastIndex ]; - bindingsForPath.pop(); - - } - - } // cached or active - - } // if object is known - - } // for arguments - - this.nCachedObjects_ = nCachedObjects; - - } - - // Internal interface used by befriended PropertyBinding.Composite: - - subscribe_( path, parsedPath ) { - - // returns an array of bindings for the given path that is changed - // according to the contained objects in the group - - const indicesByPath = this._bindingsIndicesByPath; - let index = indicesByPath[ path ]; - const bindings = this._bindings; - - if ( index !== undefined ) return bindings[ index ]; - - const paths = this._paths, - parsedPaths = this._parsedPaths, - objects = this._objects, - nObjects = objects.length, - nCachedObjects = this.nCachedObjects_, - bindingsForPath = new Array( nObjects ); - - index = bindings.length; - - indicesByPath[ path ] = index; - - paths.push( path ); - parsedPaths.push( parsedPath ); - bindings.push( bindingsForPath ); - - for ( let i = nCachedObjects, n = objects.length; i !== n; ++ i ) { - - const object = objects[ i ]; - bindingsForPath[ i ] = new PropertyBinding( object, path, parsedPath ); - - } - - return bindingsForPath; - - } - - unsubscribe_( path ) { - - // tells the group to forget about a property path and no longer - // update the array previously obtained with 'subscribe_' - - const indicesByPath = this._bindingsIndicesByPath, - index = indicesByPath[ path ]; - - if ( index !== undefined ) { - - const paths = this._paths, - parsedPaths = this._parsedPaths, - bindings = this._bindings, - lastBindingsIndex = bindings.length - 1, - lastBindings = bindings[ lastBindingsIndex ], - lastBindingsPath = path[ lastBindingsIndex ]; - - indicesByPath[ lastBindingsPath ] = index; - - bindings[ index ] = lastBindings; - bindings.pop(); - - parsedPaths[ index ] = parsedPaths[ lastBindingsIndex ]; - parsedPaths.pop(); - - paths[ index ] = paths[ lastBindingsIndex ]; - paths.pop(); - - } - - } - -} - -class AnimationAction { - - constructor( mixer, clip, localRoot = null, blendMode = clip.blendMode ) { - - this._mixer = mixer; - this._clip = clip; - this._localRoot = localRoot; - this.blendMode = blendMode; - - const tracks = clip.tracks, - nTracks = tracks.length, - interpolants = new Array( nTracks ); - - const interpolantSettings = { - endingStart: ZeroCurvatureEnding, - endingEnd: ZeroCurvatureEnding - }; - - for ( let i = 0; i !== nTracks; ++ i ) { - - const interpolant = tracks[ i ].createInterpolant( null ); - interpolants[ i ] = interpolant; - interpolant.settings = interpolantSettings; - - } - - this._interpolantSettings = interpolantSettings; - - this._interpolants = interpolants; // bound by the mixer - - // inside: PropertyMixer (managed by the mixer) - this._propertyBindings = new Array( nTracks ); - - this._cacheIndex = null; // for the memory manager - this._byClipCacheIndex = null; // for the memory manager - - this._timeScaleInterpolant = null; - this._weightInterpolant = null; - - this.loop = LoopRepeat; - this._loopCount = - 1; - - // global mixer time when the action is to be started - // it's set back to 'null' upon start of the action - this._startTime = null; - - // scaled local time of the action - // gets clamped or wrapped to 0..clip.duration according to loop - this.time = 0; - - this.timeScale = 1; - this._effectiveTimeScale = 1; - - this.weight = 1; - this._effectiveWeight = 1; - - this.repetitions = Infinity; // no. of repetitions when looping - - this.paused = false; // true -> zero effective time scale - this.enabled = true; // false -> zero effective weight - - this.clampWhenFinished = false;// keep feeding the last frame? - - this.zeroSlopeAtStart = true;// for smooth interpolation w/o separate - this.zeroSlopeAtEnd = true;// clips for start, loop and end - - } - - // State & Scheduling - - play() { - - this._mixer._activateAction( this ); - - return this; - - } - - stop() { - - this._mixer._deactivateAction( this ); - - return this.reset(); - - } - - reset() { - - this.paused = false; - this.enabled = true; - - this.time = 0; // restart clip - this._loopCount = - 1;// forget previous loops - this._startTime = null;// forget scheduling - - return this.stopFading().stopWarping(); - - } - - isRunning() { - - return this.enabled && ! this.paused && this.timeScale !== 0 && - this._startTime === null && this._mixer._isActiveAction( this ); - - } - - // return true when play has been called - isScheduled() { - - return this._mixer._isActiveAction( this ); - - } - - startAt( time ) { - - this._startTime = time; - - return this; - - } - - setLoop( mode, repetitions ) { - - this.loop = mode; - this.repetitions = repetitions; - - return this; - - } - - // Weight - - // set the weight stopping any scheduled fading - // although .enabled = false yields an effective weight of zero, this - // method does *not* change .enabled, because it would be confusing - setEffectiveWeight( weight ) { - - this.weight = weight; - - // note: same logic as when updated at runtime - this._effectiveWeight = this.enabled ? weight : 0; - - return this.stopFading(); - - } - - // return the weight considering fading and .enabled - getEffectiveWeight() { - - return this._effectiveWeight; - - } - - fadeIn( duration ) { - - return this._scheduleFading( duration, 0, 1 ); - - } - - fadeOut( duration ) { - - return this._scheduleFading( duration, 1, 0 ); - - } - - crossFadeFrom( fadeOutAction, duration, warp ) { - - fadeOutAction.fadeOut( duration ); - this.fadeIn( duration ); - - if ( warp ) { - - const fadeInDuration = this._clip.duration, - fadeOutDuration = fadeOutAction._clip.duration, - - startEndRatio = fadeOutDuration / fadeInDuration, - endStartRatio = fadeInDuration / fadeOutDuration; - - fadeOutAction.warp( 1.0, startEndRatio, duration ); - this.warp( endStartRatio, 1.0, duration ); - - } - - return this; - - } - - crossFadeTo( fadeInAction, duration, warp ) { - - return fadeInAction.crossFadeFrom( this, duration, warp ); - - } - - stopFading() { - - const weightInterpolant = this._weightInterpolant; - - if ( weightInterpolant !== null ) { - - this._weightInterpolant = null; - this._mixer._takeBackControlInterpolant( weightInterpolant ); - - } - - return this; - - } - - // Time Scale Control - - // set the time scale stopping any scheduled warping - // although .paused = true yields an effective time scale of zero, this - // method does *not* change .paused, because it would be confusing - setEffectiveTimeScale( timeScale ) { - - this.timeScale = timeScale; - this._effectiveTimeScale = this.paused ? 0 : timeScale; - - return this.stopWarping(); - - } - - // return the time scale considering warping and .paused - getEffectiveTimeScale() { - - return this._effectiveTimeScale; - - } - - setDuration( duration ) { - - this.timeScale = this._clip.duration / duration; - - return this.stopWarping(); - - } - - syncWith( action ) { - - this.time = action.time; - this.timeScale = action.timeScale; - - return this.stopWarping(); - - } - - halt( duration ) { - - return this.warp( this._effectiveTimeScale, 0, duration ); - - } - - warp( startTimeScale, endTimeScale, duration ) { - - const mixer = this._mixer, - now = mixer.time, - timeScale = this.timeScale; - - let interpolant = this._timeScaleInterpolant; - - if ( interpolant === null ) { - - interpolant = mixer._lendControlInterpolant(); - this._timeScaleInterpolant = interpolant; - - } - - const times = interpolant.parameterPositions, - values = interpolant.sampleValues; - - times[ 0 ] = now; - times[ 1 ] = now + duration; - - values[ 0 ] = startTimeScale / timeScale; - values[ 1 ] = endTimeScale / timeScale; - - return this; - - } - - stopWarping() { - - const timeScaleInterpolant = this._timeScaleInterpolant; - - if ( timeScaleInterpolant !== null ) { - - this._timeScaleInterpolant = null; - this._mixer._takeBackControlInterpolant( timeScaleInterpolant ); - - } - - return this; - - } - - // Object Accessors - - getMixer() { - - return this._mixer; - - } - - getClip() { - - return this._clip; - - } - - getRoot() { - - return this._localRoot || this._mixer._root; - - } - - // Interna - - _update( time, deltaTime, timeDirection, accuIndex ) { - - // called by the mixer - - if ( ! this.enabled ) { - - // call ._updateWeight() to update ._effectiveWeight - - this._updateWeight( time ); - return; - - } - - const startTime = this._startTime; - - if ( startTime !== null ) { - - // check for scheduled start of action - - const timeRunning = ( time - startTime ) * timeDirection; - if ( timeRunning < 0 || timeDirection === 0 ) { - - deltaTime = 0; - - } else { - - - this._startTime = null; // unschedule - deltaTime = timeDirection * timeRunning; - - } - - } - - // apply time scale and advance time - - deltaTime *= this._updateTimeScale( time ); - const clipTime = this._updateTime( deltaTime ); - - // note: _updateTime may disable the action resulting in - // an effective weight of 0 - - const weight = this._updateWeight( time ); - - if ( weight > 0 ) { - - const interpolants = this._interpolants; - const propertyMixers = this._propertyBindings; - - switch ( this.blendMode ) { - - case AdditiveAnimationBlendMode: - - for ( let j = 0, m = interpolants.length; j !== m; ++ j ) { - - interpolants[ j ].evaluate( clipTime ); - propertyMixers[ j ].accumulateAdditive( weight ); - - } - - break; - - case NormalAnimationBlendMode: - default: - - for ( let j = 0, m = interpolants.length; j !== m; ++ j ) { - - interpolants[ j ].evaluate( clipTime ); - propertyMixers[ j ].accumulate( accuIndex, weight ); - - } - - } - - } - - } - - _updateWeight( time ) { - - let weight = 0; - - if ( this.enabled ) { - - weight = this.weight; - const interpolant = this._weightInterpolant; - - if ( interpolant !== null ) { - - const interpolantValue = interpolant.evaluate( time )[ 0 ]; - - weight *= interpolantValue; - - if ( time > interpolant.parameterPositions[ 1 ] ) { - - this.stopFading(); - - if ( interpolantValue === 0 ) { - - // faded out, disable - this.enabled = false; - - } - - } - - } - - } - - this._effectiveWeight = weight; - return weight; - - } - - _updateTimeScale( time ) { - - let timeScale = 0; - - if ( ! this.paused ) { - - timeScale = this.timeScale; - - const interpolant = this._timeScaleInterpolant; - - if ( interpolant !== null ) { - - const interpolantValue = interpolant.evaluate( time )[ 0 ]; - - timeScale *= interpolantValue; - - if ( time > interpolant.parameterPositions[ 1 ] ) { - - this.stopWarping(); - - if ( timeScale === 0 ) { - - // motion has halted, pause - this.paused = true; - - } else { - - // warp done - apply final time scale - this.timeScale = timeScale; - - } - - } - - } - - } - - this._effectiveTimeScale = timeScale; - return timeScale; - - } - - _updateTime( deltaTime ) { - - const duration = this._clip.duration; - const loop = this.loop; - - let time = this.time + deltaTime; - let loopCount = this._loopCount; - - const pingPong = ( loop === LoopPingPong ); - - if ( deltaTime === 0 ) { - - if ( loopCount === - 1 ) return time; - - return ( pingPong && ( loopCount & 1 ) === 1 ) ? duration - time : time; - - } - - if ( loop === LoopOnce ) { - - if ( loopCount === - 1 ) { - - // just started - - this._loopCount = 0; - this._setEndings( true, true, false ); - - } - - handle_stop: { - - if ( time >= duration ) { - - time = duration; - - } else if ( time < 0 ) { - - time = 0; - - } else { - - this.time = time; - - break handle_stop; - - } - - if ( this.clampWhenFinished ) this.paused = true; - else this.enabled = false; - - this.time = time; - - this._mixer.dispatchEvent( { - type: 'finished', action: this, - direction: deltaTime < 0 ? - 1 : 1 - } ); - - } - - } else { // repetitive Repeat or PingPong - - if ( loopCount === - 1 ) { - - // just started - - if ( deltaTime >= 0 ) { - - loopCount = 0; - - this._setEndings( true, this.repetitions === 0, pingPong ); - - } else { - - // when looping in reverse direction, the initial - // transition through zero counts as a repetition, - // so leave loopCount at -1 - - this._setEndings( this.repetitions === 0, true, pingPong ); - - } - - } - - if ( time >= duration || time < 0 ) { - - // wrap around - - const loopDelta = Math.floor( time / duration ); // signed - time -= duration * loopDelta; - - loopCount += Math.abs( loopDelta ); - - const pending = this.repetitions - loopCount; - - if ( pending <= 0 ) { - - // have to stop (switch state, clamp time, fire event) - - if ( this.clampWhenFinished ) this.paused = true; - else this.enabled = false; - - time = deltaTime > 0 ? duration : 0; - - this.time = time; - - this._mixer.dispatchEvent( { - type: 'finished', action: this, - direction: deltaTime > 0 ? 1 : - 1 - } ); - - } else { - - // keep running - - if ( pending === 1 ) { - - // entering the last round - - const atStart = deltaTime < 0; - this._setEndings( atStart, ! atStart, pingPong ); - - } else { - - this._setEndings( false, false, pingPong ); - - } - - this._loopCount = loopCount; - - this.time = time; - - this._mixer.dispatchEvent( { - type: 'loop', action: this, loopDelta: loopDelta - } ); - - } - - } else { - - this.time = time; - - } - - if ( pingPong && ( loopCount & 1 ) === 1 ) { - - // invert time for the "pong round" - - return duration - time; - - } - - } - - return time; - - } - - _setEndings( atStart, atEnd, pingPong ) { - - const settings = this._interpolantSettings; - - if ( pingPong ) { - - settings.endingStart = ZeroSlopeEnding; - settings.endingEnd = ZeroSlopeEnding; - - } else { - - // assuming for LoopOnce atStart == atEnd == true - - if ( atStart ) { - - settings.endingStart = this.zeroSlopeAtStart ? ZeroSlopeEnding : ZeroCurvatureEnding; - - } else { - - settings.endingStart = WrapAroundEnding; - - } - - if ( atEnd ) { - - settings.endingEnd = this.zeroSlopeAtEnd ? ZeroSlopeEnding : ZeroCurvatureEnding; - - } else { - - settings.endingEnd = WrapAroundEnding; - - } - - } - - } - - _scheduleFading( duration, weightNow, weightThen ) { - - const mixer = this._mixer, now = mixer.time; - let interpolant = this._weightInterpolant; - - if ( interpolant === null ) { - - interpolant = mixer._lendControlInterpolant(); - this._weightInterpolant = interpolant; - - } - - const times = interpolant.parameterPositions, - values = interpolant.sampleValues; - - times[ 0 ] = now; - values[ 0 ] = weightNow; - times[ 1 ] = now + duration; - values[ 1 ] = weightThen; - - return this; - - } - -} - -const _controlInterpolantsResultBuffer = new Float32Array( 1 ); - - -class AnimationMixer extends EventDispatcher { - - constructor( root ) { - - super(); - - this._root = root; - this._initMemoryManager(); - this._accuIndex = 0; - this.time = 0; - this.timeScale = 1.0; - - } - - _bindAction( action, prototypeAction ) { - - const root = action._localRoot || this._root, - tracks = action._clip.tracks, - nTracks = tracks.length, - bindings = action._propertyBindings, - interpolants = action._interpolants, - rootUuid = root.uuid, - bindingsByRoot = this._bindingsByRootAndName; - - let bindingsByName = bindingsByRoot[ rootUuid ]; - - if ( bindingsByName === undefined ) { - - bindingsByName = {}; - bindingsByRoot[ rootUuid ] = bindingsByName; - - } - - for ( let i = 0; i !== nTracks; ++ i ) { - - const track = tracks[ i ], - trackName = track.name; - - let binding = bindingsByName[ trackName ]; - - if ( binding !== undefined ) { - - ++ binding.referenceCount; - bindings[ i ] = binding; - - } else { - - binding = bindings[ i ]; - - if ( binding !== undefined ) { - - // existing binding, make sure the cache knows - - if ( binding._cacheIndex === null ) { - - ++ binding.referenceCount; - this._addInactiveBinding( binding, rootUuid, trackName ); - - } - - continue; - - } - - const path = prototypeAction && prototypeAction. - _propertyBindings[ i ].binding.parsedPath; - - binding = new PropertyMixer( - PropertyBinding.create( root, trackName, path ), - track.ValueTypeName, track.getValueSize() ); - - ++ binding.referenceCount; - this._addInactiveBinding( binding, rootUuid, trackName ); - - bindings[ i ] = binding; - - } - - interpolants[ i ].resultBuffer = binding.buffer; - - } - - } - - _activateAction( action ) { - - if ( ! this._isActiveAction( action ) ) { - - if ( action._cacheIndex === null ) { - - // this action has been forgotten by the cache, but the user - // appears to be still using it -> rebind - - const rootUuid = ( action._localRoot || this._root ).uuid, - clipUuid = action._clip.uuid, - actionsForClip = this._actionsByClip[ clipUuid ]; - - this._bindAction( action, - actionsForClip && actionsForClip.knownActions[ 0 ] ); - - this._addInactiveAction( action, clipUuid, rootUuid ); - - } - - const bindings = action._propertyBindings; - - // increment reference counts / sort out state - for ( let i = 0, n = bindings.length; i !== n; ++ i ) { - - const binding = bindings[ i ]; - - if ( binding.useCount ++ === 0 ) { - - this._lendBinding( binding ); - binding.saveOriginalState(); - - } - - } - - this._lendAction( action ); - - } - - } - - _deactivateAction( action ) { - - if ( this._isActiveAction( action ) ) { - - const bindings = action._propertyBindings; - - // decrement reference counts / sort out state - for ( let i = 0, n = bindings.length; i !== n; ++ i ) { - - const binding = bindings[ i ]; - - if ( -- binding.useCount === 0 ) { - - binding.restoreOriginalState(); - this._takeBackBinding( binding ); - - } - - } - - this._takeBackAction( action ); - - } - - } - - // Memory manager - - _initMemoryManager() { - - this._actions = []; // 'nActiveActions' followed by inactive ones - this._nActiveActions = 0; - - this._actionsByClip = {}; - // inside: - // { - // knownActions: Array< AnimationAction > - used as prototypes - // actionByRoot: AnimationAction - lookup - // } - - - this._bindings = []; // 'nActiveBindings' followed by inactive ones - this._nActiveBindings = 0; - - this._bindingsByRootAndName = {}; // inside: Map< name, PropertyMixer > - - - this._controlInterpolants = []; // same game as above - this._nActiveControlInterpolants = 0; - - const scope = this; - - this.stats = { - - actions: { - get total() { - - return scope._actions.length; - - }, - get inUse() { - - return scope._nActiveActions; - - } - }, - bindings: { - get total() { - - return scope._bindings.length; - - }, - get inUse() { - - return scope._nActiveBindings; - - } - }, - controlInterpolants: { - get total() { - - return scope._controlInterpolants.length; - - }, - get inUse() { - - return scope._nActiveControlInterpolants; - - } - } - - }; - - } - - // Memory management for AnimationAction objects - - _isActiveAction( action ) { - - const index = action._cacheIndex; - return index !== null && index < this._nActiveActions; - - } - - _addInactiveAction( action, clipUuid, rootUuid ) { - - const actions = this._actions, - actionsByClip = this._actionsByClip; - - let actionsForClip = actionsByClip[ clipUuid ]; - - if ( actionsForClip === undefined ) { - - actionsForClip = { - - knownActions: [ action ], - actionByRoot: {} - - }; - - action._byClipCacheIndex = 0; - - actionsByClip[ clipUuid ] = actionsForClip; - - } else { - - const knownActions = actionsForClip.knownActions; - - action._byClipCacheIndex = knownActions.length; - knownActions.push( action ); - - } - - action._cacheIndex = actions.length; - actions.push( action ); - - actionsForClip.actionByRoot[ rootUuid ] = action; - - } - - _removeInactiveAction( action ) { - - const actions = this._actions, - lastInactiveAction = actions[ actions.length - 1 ], - cacheIndex = action._cacheIndex; - - lastInactiveAction._cacheIndex = cacheIndex; - actions[ cacheIndex ] = lastInactiveAction; - actions.pop(); - - action._cacheIndex = null; - - - const clipUuid = action._clip.uuid, - actionsByClip = this._actionsByClip, - actionsForClip = actionsByClip[ clipUuid ], - knownActionsForClip = actionsForClip.knownActions, - - lastKnownAction = - knownActionsForClip[ knownActionsForClip.length - 1 ], - - byClipCacheIndex = action._byClipCacheIndex; - - lastKnownAction._byClipCacheIndex = byClipCacheIndex; - knownActionsForClip[ byClipCacheIndex ] = lastKnownAction; - knownActionsForClip.pop(); - - action._byClipCacheIndex = null; - - - const actionByRoot = actionsForClip.actionByRoot, - rootUuid = ( action._localRoot || this._root ).uuid; - - delete actionByRoot[ rootUuid ]; - - if ( knownActionsForClip.length === 0 ) { - - delete actionsByClip[ clipUuid ]; - - } - - this._removeInactiveBindingsForAction( action ); - - } - - _removeInactiveBindingsForAction( action ) { - - const bindings = action._propertyBindings; - - for ( let i = 0, n = bindings.length; i !== n; ++ i ) { - - const binding = bindings[ i ]; - - if ( -- binding.referenceCount === 0 ) { - - this._removeInactiveBinding( binding ); - - } - - } - - } - - _lendAction( action ) { - - // [ active actions | inactive actions ] - // [ active actions >| inactive actions ] - // s a - // <-swap-> - // a s - - const actions = this._actions, - prevIndex = action._cacheIndex, - - lastActiveIndex = this._nActiveActions ++, - - firstInactiveAction = actions[ lastActiveIndex ]; - - action._cacheIndex = lastActiveIndex; - actions[ lastActiveIndex ] = action; - - firstInactiveAction._cacheIndex = prevIndex; - actions[ prevIndex ] = firstInactiveAction; - - } - - _takeBackAction( action ) { - - // [ active actions | inactive actions ] - // [ active actions |< inactive actions ] - // a s - // <-swap-> - // s a - - const actions = this._actions, - prevIndex = action._cacheIndex, - - firstInactiveIndex = -- this._nActiveActions, - - lastActiveAction = actions[ firstInactiveIndex ]; - - action._cacheIndex = firstInactiveIndex; - actions[ firstInactiveIndex ] = action; - - lastActiveAction._cacheIndex = prevIndex; - actions[ prevIndex ] = lastActiveAction; - - } - - // Memory management for PropertyMixer objects - - _addInactiveBinding( binding, rootUuid, trackName ) { - - const bindingsByRoot = this._bindingsByRootAndName, - bindings = this._bindings; - - let bindingByName = bindingsByRoot[ rootUuid ]; - - if ( bindingByName === undefined ) { - - bindingByName = {}; - bindingsByRoot[ rootUuid ] = bindingByName; - - } - - bindingByName[ trackName ] = binding; - - binding._cacheIndex = bindings.length; - bindings.push( binding ); - - } - - _removeInactiveBinding( binding ) { - - const bindings = this._bindings, - propBinding = binding.binding, - rootUuid = propBinding.rootNode.uuid, - trackName = propBinding.path, - bindingsByRoot = this._bindingsByRootAndName, - bindingByName = bindingsByRoot[ rootUuid ], - - lastInactiveBinding = bindings[ bindings.length - 1 ], - cacheIndex = binding._cacheIndex; - - lastInactiveBinding._cacheIndex = cacheIndex; - bindings[ cacheIndex ] = lastInactiveBinding; - bindings.pop(); - - delete bindingByName[ trackName ]; - - if ( Object.keys( bindingByName ).length === 0 ) { - - delete bindingsByRoot[ rootUuid ]; - - } - - } - - _lendBinding( binding ) { - - const bindings = this._bindings, - prevIndex = binding._cacheIndex, - - lastActiveIndex = this._nActiveBindings ++, - - firstInactiveBinding = bindings[ lastActiveIndex ]; - - binding._cacheIndex = lastActiveIndex; - bindings[ lastActiveIndex ] = binding; - - firstInactiveBinding._cacheIndex = prevIndex; - bindings[ prevIndex ] = firstInactiveBinding; - - } - - _takeBackBinding( binding ) { - - const bindings = this._bindings, - prevIndex = binding._cacheIndex, - - firstInactiveIndex = -- this._nActiveBindings, - - lastActiveBinding = bindings[ firstInactiveIndex ]; - - binding._cacheIndex = firstInactiveIndex; - bindings[ firstInactiveIndex ] = binding; - - lastActiveBinding._cacheIndex = prevIndex; - bindings[ prevIndex ] = lastActiveBinding; - - } - - - // Memory management of Interpolants for weight and time scale - - _lendControlInterpolant() { - - const interpolants = this._controlInterpolants, - lastActiveIndex = this._nActiveControlInterpolants ++; - - let interpolant = interpolants[ lastActiveIndex ]; - - if ( interpolant === undefined ) { - - interpolant = new LinearInterpolant( - new Float32Array( 2 ), new Float32Array( 2 ), - 1, _controlInterpolantsResultBuffer ); - - interpolant.__cacheIndex = lastActiveIndex; - interpolants[ lastActiveIndex ] = interpolant; - - } - - return interpolant; - - } - - _takeBackControlInterpolant( interpolant ) { - - const interpolants = this._controlInterpolants, - prevIndex = interpolant.__cacheIndex, - - firstInactiveIndex = -- this._nActiveControlInterpolants, - - lastActiveInterpolant = interpolants[ firstInactiveIndex ]; - - interpolant.__cacheIndex = firstInactiveIndex; - interpolants[ firstInactiveIndex ] = interpolant; - - lastActiveInterpolant.__cacheIndex = prevIndex; - interpolants[ prevIndex ] = lastActiveInterpolant; - - } - - // return an action for a clip optionally using a custom root target - // object (this method allocates a lot of dynamic memory in case a - // previously unknown clip/root combination is specified) - clipAction( clip, optionalRoot, blendMode ) { - - const root = optionalRoot || this._root, - rootUuid = root.uuid; - - let clipObject = typeof clip === 'string' ? AnimationClip.findByName( root, clip ) : clip; - - const clipUuid = clipObject !== null ? clipObject.uuid : clip; - - const actionsForClip = this._actionsByClip[ clipUuid ]; - let prototypeAction = null; - - if ( blendMode === undefined ) { - - if ( clipObject !== null ) { - - blendMode = clipObject.blendMode; - - } else { - - blendMode = NormalAnimationBlendMode; - - } - - } - - if ( actionsForClip !== undefined ) { - - const existingAction = actionsForClip.actionByRoot[ rootUuid ]; - - if ( existingAction !== undefined && existingAction.blendMode === blendMode ) { - - return existingAction; - - } - - // we know the clip, so we don't have to parse all - // the bindings again but can just copy - prototypeAction = actionsForClip.knownActions[ 0 ]; - - // also, take the clip from the prototype action - if ( clipObject === null ) - clipObject = prototypeAction._clip; - - } - - // clip must be known when specified via string - if ( clipObject === null ) return null; - - // allocate all resources required to run it - const newAction = new AnimationAction( this, clipObject, optionalRoot, blendMode ); - - this._bindAction( newAction, prototypeAction ); - - // and make the action known to the memory manager - this._addInactiveAction( newAction, clipUuid, rootUuid ); - - return newAction; - - } - - // get an existing action - existingAction( clip, optionalRoot ) { - - const root = optionalRoot || this._root, - rootUuid = root.uuid, - - clipObject = typeof clip === 'string' ? - AnimationClip.findByName( root, clip ) : clip, - - clipUuid = clipObject ? clipObject.uuid : clip, - - actionsForClip = this._actionsByClip[ clipUuid ]; - - if ( actionsForClip !== undefined ) { - - return actionsForClip.actionByRoot[ rootUuid ] || null; - - } - - return null; - - } - - // deactivates all previously scheduled actions - stopAllAction() { - - const actions = this._actions, - nActions = this._nActiveActions; - - for ( let i = nActions - 1; i >= 0; -- i ) { - - actions[ i ].stop(); - - } - - return this; - - } - - // advance the time and update apply the animation - update( deltaTime ) { - - deltaTime *= this.timeScale; - - const actions = this._actions, - nActions = this._nActiveActions, - - time = this.time += deltaTime, - timeDirection = Math.sign( deltaTime ), - - accuIndex = this._accuIndex ^= 1; - - // run active actions - - for ( let i = 0; i !== nActions; ++ i ) { - - const action = actions[ i ]; - - action._update( time, deltaTime, timeDirection, accuIndex ); - - } - - // update scene graph - - const bindings = this._bindings, - nBindings = this._nActiveBindings; - - for ( let i = 0; i !== nBindings; ++ i ) { - - bindings[ i ].apply( accuIndex ); - - } - - return this; - - } - - // Allows you to seek to a specific time in an animation. - setTime( timeInSeconds ) { - - this.time = 0; // Zero out time attribute for AnimationMixer object; - for ( let i = 0; i < this._actions.length; i ++ ) { - - this._actions[ i ].time = 0; // Zero out time attribute for all associated AnimationAction objects. - - } - - return this.update( timeInSeconds ); // Update used to set exact time. Returns "this" AnimationMixer object. - - } - - // return this mixer's root target object - getRoot() { - - return this._root; - - } - - // free all resources specific to a particular clip - uncacheClip( clip ) { - - const actions = this._actions, - clipUuid = clip.uuid, - actionsByClip = this._actionsByClip, - actionsForClip = actionsByClip[ clipUuid ]; - - if ( actionsForClip !== undefined ) { - - // note: just calling _removeInactiveAction would mess up the - // iteration state and also require updating the state we can - // just throw away - - const actionsToRemove = actionsForClip.knownActions; - - for ( let i = 0, n = actionsToRemove.length; i !== n; ++ i ) { - - const action = actionsToRemove[ i ]; - - this._deactivateAction( action ); - - const cacheIndex = action._cacheIndex, - lastInactiveAction = actions[ actions.length - 1 ]; - - action._cacheIndex = null; - action._byClipCacheIndex = null; - - lastInactiveAction._cacheIndex = cacheIndex; - actions[ cacheIndex ] = lastInactiveAction; - actions.pop(); - - this._removeInactiveBindingsForAction( action ); - - } - - delete actionsByClip[ clipUuid ]; - - } - - } - - // free all resources specific to a particular root target object - uncacheRoot( root ) { - - const rootUuid = root.uuid, - actionsByClip = this._actionsByClip; - - for ( const clipUuid in actionsByClip ) { - - const actionByRoot = actionsByClip[ clipUuid ].actionByRoot, - action = actionByRoot[ rootUuid ]; - - if ( action !== undefined ) { - - this._deactivateAction( action ); - this._removeInactiveAction( action ); - - } - - } - - const bindingsByRoot = this._bindingsByRootAndName, - bindingByName = bindingsByRoot[ rootUuid ]; - - if ( bindingByName !== undefined ) { - - for ( const trackName in bindingByName ) { - - const binding = bindingByName[ trackName ]; - binding.restoreOriginalState(); - this._removeInactiveBinding( binding ); - - } - - } - - } - - // remove a targeted clip from the cache - uncacheAction( clip, optionalRoot ) { - - const action = this.existingAction( clip, optionalRoot ); - - if ( action !== null ) { - - this._deactivateAction( action ); - this._removeInactiveAction( action ); - - } - - } - -} - -class Uniform { - - constructor( value ) { - - this.value = value; - - } - - clone() { - - return new Uniform( this.value.clone === undefined ? this.value : this.value.clone() ); - - } - -} - -let _id = 0; - -class UniformsGroup extends EventDispatcher { - - constructor() { - - super(); - - this.isUniformsGroup = true; - - Object.defineProperty( this, 'id', { value: _id ++ } ); - - this.name = ''; - - this.usage = StaticDrawUsage; - this.uniforms = []; - - } - - add( uniform ) { - - this.uniforms.push( uniform ); - - return this; - - } - - remove( uniform ) { - - const index = this.uniforms.indexOf( uniform ); - - if ( index !== - 1 ) this.uniforms.splice( index, 1 ); - - return this; - - } - - setName( name ) { - - this.name = name; - - return this; - - } - - setUsage( value ) { - - this.usage = value; - - return this; - - } - - dispose() { - - this.dispatchEvent( { type: 'dispose' } ); - - return this; - - } - - copy( source ) { - - this.name = source.name; - this.usage = source.usage; - - const uniformsSource = source.uniforms; - - this.uniforms.length = 0; - - for ( let i = 0, l = uniformsSource.length; i < l; i ++ ) { - - const uniforms = Array.isArray( uniformsSource[ i ] ) ? uniformsSource[ i ] : [ uniformsSource[ i ] ]; - - for ( let j = 0; j < uniforms.length; j ++ ) { - - this.uniforms.push( uniforms[ j ].clone() ); - - } - - } - - return this; - - } - - clone() { - - return new this.constructor().copy( this ); - - } - -} - -class InstancedInterleavedBuffer extends InterleavedBuffer { - - constructor( array, stride, meshPerAttribute = 1 ) { - - super( array, stride ); - - this.isInstancedInterleavedBuffer = true; - - this.meshPerAttribute = meshPerAttribute; - - } - - copy( source ) { - - super.copy( source ); - - this.meshPerAttribute = source.meshPerAttribute; - - return this; - - } - - clone( data ) { - - const ib = super.clone( data ); - - ib.meshPerAttribute = this.meshPerAttribute; - - return ib; - - } - - toJSON( data ) { - - const json = super.toJSON( data ); - - json.isInstancedInterleavedBuffer = true; - json.meshPerAttribute = this.meshPerAttribute; - - return json; - - } - -} - -class GLBufferAttribute { - - constructor( buffer, type, itemSize, elementSize, count ) { - - this.isGLBufferAttribute = true; - - this.name = ''; - - this.buffer = buffer; - this.type = type; - this.itemSize = itemSize; - this.elementSize = elementSize; - this.count = count; - - this.version = 0; - - } - - set needsUpdate( value ) { - - if ( value === true ) this.version ++; - - } - - setBuffer( buffer ) { - - this.buffer = buffer; - - return this; - - } - - setType( type, elementSize ) { - - this.type = type; - this.elementSize = elementSize; - - return this; - - } - - setItemSize( itemSize ) { - - this.itemSize = itemSize; - - return this; - - } - - setCount( count ) { - - this.count = count; - - return this; - - } - -} - -class Raycaster { - - constructor( origin, direction, near = 0, far = Infinity ) { - - this.ray = new Ray( origin, direction ); - // direction is assumed to be normalized (for accurate distance calculations) - - this.near = near; - this.far = far; - this.camera = null; - this.layers = new Layers(); - - this.params = { - Mesh: {}, - Line: { threshold: 1 }, - LOD: {}, - Points: { threshold: 1 }, - Sprite: {} - }; - - } - - set( origin, direction ) { - - // direction is assumed to be normalized (for accurate distance calculations) - - this.ray.set( origin, direction ); - - } - - setFromCamera( coords, camera ) { - - if ( camera.isPerspectiveCamera ) { - - this.ray.origin.setFromMatrixPosition( camera.matrixWorld ); - this.ray.direction.set( coords.x, coords.y, 0.5 ).unproject( camera ).sub( this.ray.origin ).normalize(); - this.camera = camera; - - } else if ( camera.isOrthographicCamera ) { - - this.ray.origin.set( coords.x, coords.y, ( camera.near + camera.far ) / ( camera.near - camera.far ) ).unproject( camera ); // set origin in plane of camera - this.ray.direction.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld ); - this.camera = camera; - - } else { - - console.error( 'THREE.Raycaster: Unsupported camera type: ' + camera.type ); - - } - - } - - intersectObject( object, recursive = true, intersects = [] ) { - - intersectObject( object, this, intersects, recursive ); - - intersects.sort( ascSort ); - - return intersects; - - } - - intersectObjects( objects, recursive = true, intersects = [] ) { - - for ( let i = 0, l = objects.length; i < l; i ++ ) { - - intersectObject( objects[ i ], this, intersects, recursive ); - - } - - intersects.sort( ascSort ); - - return intersects; - - } - -} - -function ascSort( a, b ) { - - return a.distance - b.distance; - -} - -function intersectObject( object, raycaster, intersects, recursive ) { - - if ( object.layers.test( raycaster.layers ) ) { - - object.raycast( raycaster, intersects ); - - } - - if ( recursive === true ) { - - const children = object.children; - - for ( let i = 0, l = children.length; i < l; i ++ ) { - - intersectObject( children[ i ], raycaster, intersects, true ); - - } - - } - -} - -/** - * Ref: https://en.wikipedia.org/wiki/Spherical_coordinate_system - * - * The polar angle (phi) is measured from the positive y-axis. The positive y-axis is up. - * The azimuthal angle (theta) is measured from the positive z-axis. - */ - - -class Spherical { - - constructor( radius = 1, phi = 0, theta = 0 ) { - - this.radius = radius; - this.phi = phi; // polar angle - this.theta = theta; // azimuthal angle - - return this; - - } - - set( radius, phi, theta ) { - - this.radius = radius; - this.phi = phi; - this.theta = theta; - - return this; - - } - - copy( other ) { - - this.radius = other.radius; - this.phi = other.phi; - this.theta = other.theta; - - return this; - - } - - // restrict phi to be between EPS and PI-EPS - makeSafe() { - - const EPS = 0.000001; - this.phi = Math.max( EPS, Math.min( Math.PI - EPS, this.phi ) ); - - return this; - - } - - setFromVector3( v ) { - - return this.setFromCartesianCoords( v.x, v.y, v.z ); - - } - - setFromCartesianCoords( x, y, z ) { - - this.radius = Math.sqrt( x * x + y * y + z * z ); - - if ( this.radius === 0 ) { - - this.theta = 0; - this.phi = 0; - - } else { - - this.theta = Math.atan2( x, z ); - this.phi = Math.acos( clamp( y / this.radius, - 1, 1 ) ); - - } - - return this; - - } - - clone() { - - return new this.constructor().copy( this ); - - } - -} - -/** - * Ref: https://en.wikipedia.org/wiki/Cylindrical_coordinate_system - */ - -class Cylindrical { - - constructor( radius = 1, theta = 0, y = 0 ) { - - this.radius = radius; // distance from the origin to a point in the x-z plane - this.theta = theta; // counterclockwise angle in the x-z plane measured in radians from the positive z-axis - this.y = y; // height above the x-z plane - - return this; - - } - - set( radius, theta, y ) { - - this.radius = radius; - this.theta = theta; - this.y = y; - - return this; - - } - - copy( other ) { - - this.radius = other.radius; - this.theta = other.theta; - this.y = other.y; - - return this; - - } - - setFromVector3( v ) { - - return this.setFromCartesianCoords( v.x, v.y, v.z ); - - } - - setFromCartesianCoords( x, y, z ) { - - this.radius = Math.sqrt( x * x + z * z ); - this.theta = Math.atan2( x, z ); - this.y = y; - - return this; - - } - - clone() { - - return new this.constructor().copy( this ); - - } - -} - -const _vector$4 = /*@__PURE__*/ new Vector2(); - -class Box2 { - - constructor( min = new Vector2( + Infinity, + Infinity ), max = new Vector2( - Infinity, - Infinity ) ) { - - this.isBox2 = true; - - this.min = min; - this.max = max; - - } - - set( min, max ) { - - this.min.copy( min ); - this.max.copy( max ); - - return this; - - } - - setFromPoints( points ) { - - this.makeEmpty(); - - for ( let i = 0, il = points.length; i < il; i ++ ) { - - this.expandByPoint( points[ i ] ); - - } - - return this; - - } - - setFromCenterAndSize( center, size ) { - - const halfSize = _vector$4.copy( size ).multiplyScalar( 0.5 ); - this.min.copy( center ).sub( halfSize ); - this.max.copy( center ).add( halfSize ); - - return this; - - } - - clone() { - - return new this.constructor().copy( this ); - - } - - copy( box ) { - - this.min.copy( box.min ); - this.max.copy( box.max ); - - return this; - - } - - makeEmpty() { - - this.min.x = this.min.y = + Infinity; - this.max.x = this.max.y = - Infinity; - - return this; - - } - - isEmpty() { - - // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes - - return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ); - - } - - getCenter( target ) { - - return this.isEmpty() ? target.set( 0, 0 ) : target.addVectors( this.min, this.max ).multiplyScalar( 0.5 ); - - } - - getSize( target ) { - - return this.isEmpty() ? target.set( 0, 0 ) : target.subVectors( this.max, this.min ); - - } - - expandByPoint( point ) { - - this.min.min( point ); - this.max.max( point ); - - return this; - - } - - expandByVector( vector ) { - - this.min.sub( vector ); - this.max.add( vector ); - - return this; - - } - - expandByScalar( scalar ) { - - this.min.addScalar( - scalar ); - this.max.addScalar( scalar ); - - return this; - - } - - containsPoint( point ) { - - return point.x < this.min.x || point.x > this.max.x || - point.y < this.min.y || point.y > this.max.y ? false : true; - - } - - containsBox( box ) { - - return this.min.x <= box.min.x && box.max.x <= this.max.x && - this.min.y <= box.min.y && box.max.y <= this.max.y; - - } - - getParameter( point, target ) { - - // This can potentially have a divide by zero if the box - // has a size dimension of 0. - - return target.set( - ( point.x - this.min.x ) / ( this.max.x - this.min.x ), - ( point.y - this.min.y ) / ( this.max.y - this.min.y ) - ); - - } - - intersectsBox( box ) { - - // using 4 splitting planes to rule out intersections - - return box.max.x < this.min.x || box.min.x > this.max.x || - box.max.y < this.min.y || box.min.y > this.max.y ? false : true; - - } - - clampPoint( point, target ) { - - return target.copy( point ).clamp( this.min, this.max ); - - } - - distanceToPoint( point ) { - - return this.clampPoint( point, _vector$4 ).distanceTo( point ); - - } - - intersect( box ) { - - this.min.max( box.min ); - this.max.min( box.max ); - - if ( this.isEmpty() ) this.makeEmpty(); - - return this; - - } - - union( box ) { - - this.min.min( box.min ); - this.max.max( box.max ); - - return this; - - } - - translate( offset ) { - - this.min.add( offset ); - this.max.add( offset ); - - return this; - - } - - equals( box ) { - - return box.min.equals( this.min ) && box.max.equals( this.max ); - - } - -} - -const _startP = /*@__PURE__*/ new Vector3(); -const _startEnd = /*@__PURE__*/ new Vector3(); - -class Line3 { - - constructor( start = new Vector3(), end = new Vector3() ) { - - this.start = start; - this.end = end; - - } - - set( start, end ) { - - this.start.copy( start ); - this.end.copy( end ); - - return this; - - } - - copy( line ) { - - this.start.copy( line.start ); - this.end.copy( line.end ); - - return this; - - } - - getCenter( target ) { - - return target.addVectors( this.start, this.end ).multiplyScalar( 0.5 ); - - } - - delta( target ) { - - return target.subVectors( this.end, this.start ); - - } - - distanceSq() { - - return this.start.distanceToSquared( this.end ); - - } - - distance() { - - return this.start.distanceTo( this.end ); - - } - - at( t, target ) { - - return this.delta( target ).multiplyScalar( t ).add( this.start ); - - } - - closestPointToPointParameter( point, clampToLine ) { - - _startP.subVectors( point, this.start ); - _startEnd.subVectors( this.end, this.start ); - - const startEnd2 = _startEnd.dot( _startEnd ); - const startEnd_startP = _startEnd.dot( _startP ); - - let t = startEnd_startP / startEnd2; - - if ( clampToLine ) { - - t = clamp( t, 0, 1 ); - - } - - return t; - - } - - closestPointToPoint( point, clampToLine, target ) { - - const t = this.closestPointToPointParameter( point, clampToLine ); - - return this.delta( target ).multiplyScalar( t ).add( this.start ); - - } - - applyMatrix4( matrix ) { - - this.start.applyMatrix4( matrix ); - this.end.applyMatrix4( matrix ); - - return this; - - } - - equals( line ) { - - return line.start.equals( this.start ) && line.end.equals( this.end ); - - } - - clone() { - - return new this.constructor().copy( this ); - - } - -} - -const _vector$3 = /*@__PURE__*/ new Vector3(); - -class SpotLightHelper extends Object3D { - - constructor( light, color ) { - - super(); - - this.light = light; - - this.matrix = light.matrixWorld; - this.matrixAutoUpdate = false; - - this.color = color; - - this.type = 'SpotLightHelper'; - - const geometry = new BufferGeometry(); - - const positions = [ - 0, 0, 0, 0, 0, 1, - 0, 0, 0, 1, 0, 1, - 0, 0, 0, - 1, 0, 1, - 0, 0, 0, 0, 1, 1, - 0, 0, 0, 0, - 1, 1 - ]; - - for ( let i = 0, j = 1, l = 32; i < l; i ++, j ++ ) { - - const p1 = ( i / l ) * Math.PI * 2; - const p2 = ( j / l ) * Math.PI * 2; - - positions.push( - Math.cos( p1 ), Math.sin( p1 ), 1, - Math.cos( p2 ), Math.sin( p2 ), 1 - ); - - } - - geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) ); - - const material = new LineBasicMaterial( { fog: false, toneMapped: false } ); - - this.cone = new LineSegments( geometry, material ); - this.add( this.cone ); - - this.update(); - - } - - dispose() { - - this.cone.geometry.dispose(); - this.cone.material.dispose(); - - } - - update() { - - this.light.updateWorldMatrix( true, false ); - this.light.target.updateWorldMatrix( true, false ); - - const coneLength = this.light.distance ? this.light.distance : 1000; - const coneWidth = coneLength * Math.tan( this.light.angle ); - - this.cone.scale.set( coneWidth, coneWidth, coneLength ); - - _vector$3.setFromMatrixPosition( this.light.target.matrixWorld ); - - this.cone.lookAt( _vector$3 ); - - if ( this.color !== undefined ) { - - this.cone.material.color.set( this.color ); - - } else { - - this.cone.material.color.copy( this.light.color ); - - } - - } - -} - -const _vector$2 = /*@__PURE__*/ new Vector3(); -const _boneMatrix = /*@__PURE__*/ new Matrix4(); -const _matrixWorldInv = /*@__PURE__*/ new Matrix4(); - - -class SkeletonHelper extends LineSegments { - - constructor( object ) { - - const bones = getBoneList( object ); - - const geometry = new BufferGeometry(); - - const vertices = []; - const colors = []; - - const color1 = new Color( 0, 0, 1 ); - const color2 = new Color( 0, 1, 0 ); - - for ( let i = 0; i < bones.length; i ++ ) { - - const bone = bones[ i ]; - - if ( bone.parent && bone.parent.isBone ) { - - vertices.push( 0, 0, 0 ); - vertices.push( 0, 0, 0 ); - colors.push( color1.r, color1.g, color1.b ); - colors.push( color2.r, color2.g, color2.b ); - - } - - } - - geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); - - const material = new LineBasicMaterial( { vertexColors: true, depthTest: false, depthWrite: false, toneMapped: false, transparent: true } ); - - super( geometry, material ); - - this.isSkeletonHelper = true; - - this.type = 'SkeletonHelper'; - - this.root = object; - this.bones = bones; - - this.matrix = object.matrixWorld; - this.matrixAutoUpdate = false; - - } - - updateMatrixWorld( force ) { - - const bones = this.bones; - - const geometry = this.geometry; - const position = geometry.getAttribute( 'position' ); - - _matrixWorldInv.copy( this.root.matrixWorld ).invert(); - - for ( let i = 0, j = 0; i < bones.length; i ++ ) { - - const bone = bones[ i ]; - - if ( bone.parent && bone.parent.isBone ) { - - _boneMatrix.multiplyMatrices( _matrixWorldInv, bone.matrixWorld ); - _vector$2.setFromMatrixPosition( _boneMatrix ); - position.setXYZ( j, _vector$2.x, _vector$2.y, _vector$2.z ); - - _boneMatrix.multiplyMatrices( _matrixWorldInv, bone.parent.matrixWorld ); - _vector$2.setFromMatrixPosition( _boneMatrix ); - position.setXYZ( j + 1, _vector$2.x, _vector$2.y, _vector$2.z ); - - j += 2; - - } - - } - - geometry.getAttribute( 'position' ).needsUpdate = true; - - super.updateMatrixWorld( force ); - - } - - dispose() { - - this.geometry.dispose(); - this.material.dispose(); - - } - -} - - -function getBoneList( object ) { - - const boneList = []; - - if ( object.isBone === true ) { - - boneList.push( object ); - - } - - for ( let i = 0; i < object.children.length; i ++ ) { - - boneList.push.apply( boneList, getBoneList( object.children[ i ] ) ); - - } - - return boneList; - -} - -class PointLightHelper extends Mesh { - - constructor( light, sphereSize, color ) { - - const geometry = new SphereGeometry( sphereSize, 4, 2 ); - const material = new MeshBasicMaterial( { wireframe: true, fog: false, toneMapped: false } ); - - super( geometry, material ); - - this.light = light; - - this.color = color; - - this.type = 'PointLightHelper'; - - this.matrix = this.light.matrixWorld; - this.matrixAutoUpdate = false; - - this.update(); - - - /* - // TODO: delete this comment? - const distanceGeometry = new THREE.IcosahedronGeometry( 1, 2 ); - const distanceMaterial = new THREE.MeshBasicMaterial( { color: hexColor, fog: false, wireframe: true, opacity: 0.1, transparent: true } ); - - this.lightSphere = new THREE.Mesh( bulbGeometry, bulbMaterial ); - this.lightDistance = new THREE.Mesh( distanceGeometry, distanceMaterial ); - - const d = light.distance; - - if ( d === 0.0 ) { - - this.lightDistance.visible = false; - - } else { - - this.lightDistance.scale.set( d, d, d ); - - } - - this.add( this.lightDistance ); - */ - - } - - dispose() { - - this.geometry.dispose(); - this.material.dispose(); - - } - - update() { - - this.light.updateWorldMatrix( true, false ); - - if ( this.color !== undefined ) { - - this.material.color.set( this.color ); - - } else { - - this.material.color.copy( this.light.color ); - - } - - /* - const d = this.light.distance; - - if ( d === 0.0 ) { - - this.lightDistance.visible = false; - - } else { - - this.lightDistance.visible = true; - this.lightDistance.scale.set( d, d, d ); - - } - */ - - } - -} - -const _vector$1 = /*@__PURE__*/ new Vector3(); -const _color1 = /*@__PURE__*/ new Color(); -const _color2 = /*@__PURE__*/ new Color(); - -class HemisphereLightHelper extends Object3D { - - constructor( light, size, color ) { - - super(); - - this.light = light; - - this.matrix = light.matrixWorld; - this.matrixAutoUpdate = false; - - this.color = color; - - this.type = 'HemisphereLightHelper'; - - const geometry = new OctahedronGeometry( size ); - geometry.rotateY( Math.PI * 0.5 ); - - this.material = new MeshBasicMaterial( { wireframe: true, fog: false, toneMapped: false } ); - if ( this.color === undefined ) this.material.vertexColors = true; - - const position = geometry.getAttribute( 'position' ); - const colors = new Float32Array( position.count * 3 ); - - geometry.setAttribute( 'color', new BufferAttribute( colors, 3 ) ); - - this.add( new Mesh( geometry, this.material ) ); - - this.update(); - - } - - dispose() { - - this.children[ 0 ].geometry.dispose(); - this.children[ 0 ].material.dispose(); - - } - - update() { - - const mesh = this.children[ 0 ]; - - if ( this.color !== undefined ) { - - this.material.color.set( this.color ); - - } else { - - const colors = mesh.geometry.getAttribute( 'color' ); - - _color1.copy( this.light.color ); - _color2.copy( this.light.groundColor ); - - for ( let i = 0, l = colors.count; i < l; i ++ ) { - - const color = ( i < ( l / 2 ) ) ? _color1 : _color2; - - colors.setXYZ( i, color.r, color.g, color.b ); - - } - - colors.needsUpdate = true; - - } - - this.light.updateWorldMatrix( true, false ); - - mesh.lookAt( _vector$1.setFromMatrixPosition( this.light.matrixWorld ).negate() ); - - } - -} - -class GridHelper extends LineSegments { - - constructor( size = 10, divisions = 10, color1 = 0x444444, color2 = 0x888888 ) { - - color1 = new Color( color1 ); - color2 = new Color( color2 ); - - const center = divisions / 2; - const step = size / divisions; - const halfSize = size / 2; - - const vertices = [], colors = []; - - for ( let i = 0, j = 0, k = - halfSize; i <= divisions; i ++, k += step ) { - - vertices.push( - halfSize, 0, k, halfSize, 0, k ); - vertices.push( k, 0, - halfSize, k, 0, halfSize ); - - const color = i === center ? color1 : color2; - - color.toArray( colors, j ); j += 3; - color.toArray( colors, j ); j += 3; - color.toArray( colors, j ); j += 3; - color.toArray( colors, j ); j += 3; - - } - - const geometry = new BufferGeometry(); - geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); - - const material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } ); - - super( geometry, material ); - - this.type = 'GridHelper'; - - } - - dispose() { - - this.geometry.dispose(); - this.material.dispose(); - - } - -} - -class PolarGridHelper extends LineSegments { - - constructor( radius = 10, sectors = 16, rings = 8, divisions = 64, color1 = 0x444444, color2 = 0x888888 ) { - - color1 = new Color( color1 ); - color2 = new Color( color2 ); - - const vertices = []; - const colors = []; - - // create the sectors - - if ( sectors > 1 ) { - - for ( let i = 0; i < sectors; i ++ ) { - - const v = ( i / sectors ) * ( Math.PI * 2 ); - - const x = Math.sin( v ) * radius; - const z = Math.cos( v ) * radius; - - vertices.push( 0, 0, 0 ); - vertices.push( x, 0, z ); - - const color = ( i & 1 ) ? color1 : color2; - - colors.push( color.r, color.g, color.b ); - colors.push( color.r, color.g, color.b ); - - } - - } - - // create the rings - - for ( let i = 0; i < rings; i ++ ) { - - const color = ( i & 1 ) ? color1 : color2; - - const r = radius - ( radius / rings * i ); - - for ( let j = 0; j < divisions; j ++ ) { - - // first vertex - - let v = ( j / divisions ) * ( Math.PI * 2 ); - - let x = Math.sin( v ) * r; - let z = Math.cos( v ) * r; - - vertices.push( x, 0, z ); - colors.push( color.r, color.g, color.b ); - - // second vertex - - v = ( ( j + 1 ) / divisions ) * ( Math.PI * 2 ); - - x = Math.sin( v ) * r; - z = Math.cos( v ) * r; - - vertices.push( x, 0, z ); - colors.push( color.r, color.g, color.b ); - - } - - } - - const geometry = new BufferGeometry(); - geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); - - const material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } ); - - super( geometry, material ); - - this.type = 'PolarGridHelper'; - - } - - dispose() { - - this.geometry.dispose(); - this.material.dispose(); - - } - -} - -const _v1 = /*@__PURE__*/ new Vector3(); -const _v2 = /*@__PURE__*/ new Vector3(); -const _v3 = /*@__PURE__*/ new Vector3(); - -class DirectionalLightHelper extends Object3D { - - constructor( light, size, color ) { - - super(); - - this.light = light; - - this.matrix = light.matrixWorld; - this.matrixAutoUpdate = false; - - this.color = color; - - this.type = 'DirectionalLightHelper'; - - if ( size === undefined ) size = 1; - - let geometry = new BufferGeometry(); - geometry.setAttribute( 'position', new Float32BufferAttribute( [ - - size, size, 0, - size, size, 0, - size, - size, 0, - - size, - size, 0, - - size, size, 0 - ], 3 ) ); - - const material = new LineBasicMaterial( { fog: false, toneMapped: false } ); - - this.lightPlane = new Line( geometry, material ); - this.add( this.lightPlane ); - - geometry = new BufferGeometry(); - geometry.setAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 0, 1 ], 3 ) ); - - this.targetLine = new Line( geometry, material ); - this.add( this.targetLine ); - - this.update(); - - } - - dispose() { - - this.lightPlane.geometry.dispose(); - this.lightPlane.material.dispose(); - this.targetLine.geometry.dispose(); - this.targetLine.material.dispose(); - - } - - update() { - - this.light.updateWorldMatrix( true, false ); - this.light.target.updateWorldMatrix( true, false ); - - _v1.setFromMatrixPosition( this.light.matrixWorld ); - _v2.setFromMatrixPosition( this.light.target.matrixWorld ); - _v3.subVectors( _v2, _v1 ); - - this.lightPlane.lookAt( _v2 ); - - if ( this.color !== undefined ) { - - this.lightPlane.material.color.set( this.color ); - this.targetLine.material.color.set( this.color ); - - } else { - - this.lightPlane.material.color.copy( this.light.color ); - this.targetLine.material.color.copy( this.light.color ); - - } - - this.targetLine.lookAt( _v2 ); - this.targetLine.scale.z = _v3.length(); - - } - -} - -const _vector = /*@__PURE__*/ new Vector3(); -const _camera = /*@__PURE__*/ new Camera(); - -/** - * - shows frustum, line of sight and up of the camera - * - suitable for fast updates - * - based on frustum visualization in lightgl.js shadowmap example - * https://github.com/evanw/lightgl.js/blob/master/tests/shadowmap.html - */ - -class CameraHelper extends LineSegments { - - constructor( camera ) { - - const geometry = new BufferGeometry(); - const material = new LineBasicMaterial( { color: 0xffffff, vertexColors: true, toneMapped: false } ); - - const vertices = []; - const colors = []; - - const pointMap = {}; - - // near - - addLine( 'n1', 'n2' ); - addLine( 'n2', 'n4' ); - addLine( 'n4', 'n3' ); - addLine( 'n3', 'n1' ); - - // far - - addLine( 'f1', 'f2' ); - addLine( 'f2', 'f4' ); - addLine( 'f4', 'f3' ); - addLine( 'f3', 'f1' ); - - // sides - - addLine( 'n1', 'f1' ); - addLine( 'n2', 'f2' ); - addLine( 'n3', 'f3' ); - addLine( 'n4', 'f4' ); - - // cone - - addLine( 'p', 'n1' ); - addLine( 'p', 'n2' ); - addLine( 'p', 'n3' ); - addLine( 'p', 'n4' ); - - // up - - addLine( 'u1', 'u2' ); - addLine( 'u2', 'u3' ); - addLine( 'u3', 'u1' ); - - // target - - addLine( 'c', 't' ); - addLine( 'p', 'c' ); - - // cross - - addLine( 'cn1', 'cn2' ); - addLine( 'cn3', 'cn4' ); - - addLine( 'cf1', 'cf2' ); - addLine( 'cf3', 'cf4' ); - - function addLine( a, b ) { - - addPoint( a ); - addPoint( b ); - - } - - function addPoint( id ) { - - vertices.push( 0, 0, 0 ); - colors.push( 0, 0, 0 ); - - if ( pointMap[ id ] === undefined ) { - - pointMap[ id ] = []; - - } - - pointMap[ id ].push( ( vertices.length / 3 ) - 1 ); - - } - - geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); - - super( geometry, material ); - - this.type = 'CameraHelper'; - - this.camera = camera; - if ( this.camera.updateProjectionMatrix ) this.camera.updateProjectionMatrix(); - - this.matrix = camera.matrixWorld; - this.matrixAutoUpdate = false; - - this.pointMap = pointMap; - - this.update(); - - // colors - - const colorFrustum = new Color( 0xffaa00 ); - const colorCone = new Color( 0xff0000 ); - const colorUp = new Color( 0x00aaff ); - const colorTarget = new Color( 0xffffff ); - const colorCross = new Color( 0x333333 ); - - this.setColors( colorFrustum, colorCone, colorUp, colorTarget, colorCross ); - - } - - setColors( frustum, cone, up, target, cross ) { - - const geometry = this.geometry; - - const colorAttribute = geometry.getAttribute( 'color' ); - - // near - - colorAttribute.setXYZ( 0, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 1, frustum.r, frustum.g, frustum.b ); // n1, n2 - colorAttribute.setXYZ( 2, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 3, frustum.r, frustum.g, frustum.b ); // n2, n4 - colorAttribute.setXYZ( 4, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 5, frustum.r, frustum.g, frustum.b ); // n4, n3 - colorAttribute.setXYZ( 6, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 7, frustum.r, frustum.g, frustum.b ); // n3, n1 - - // far - - colorAttribute.setXYZ( 8, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 9, frustum.r, frustum.g, frustum.b ); // f1, f2 - colorAttribute.setXYZ( 10, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 11, frustum.r, frustum.g, frustum.b ); // f2, f4 - colorAttribute.setXYZ( 12, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 13, frustum.r, frustum.g, frustum.b ); // f4, f3 - colorAttribute.setXYZ( 14, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 15, frustum.r, frustum.g, frustum.b ); // f3, f1 - - // sides - - colorAttribute.setXYZ( 16, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 17, frustum.r, frustum.g, frustum.b ); // n1, f1 - colorAttribute.setXYZ( 18, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 19, frustum.r, frustum.g, frustum.b ); // n2, f2 - colorAttribute.setXYZ( 20, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 21, frustum.r, frustum.g, frustum.b ); // n3, f3 - colorAttribute.setXYZ( 22, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 23, frustum.r, frustum.g, frustum.b ); // n4, f4 - - // cone - - colorAttribute.setXYZ( 24, cone.r, cone.g, cone.b ); colorAttribute.setXYZ( 25, cone.r, cone.g, cone.b ); // p, n1 - colorAttribute.setXYZ( 26, cone.r, cone.g, cone.b ); colorAttribute.setXYZ( 27, cone.r, cone.g, cone.b ); // p, n2 - colorAttribute.setXYZ( 28, cone.r, cone.g, cone.b ); colorAttribute.setXYZ( 29, cone.r, cone.g, cone.b ); // p, n3 - colorAttribute.setXYZ( 30, cone.r, cone.g, cone.b ); colorAttribute.setXYZ( 31, cone.r, cone.g, cone.b ); // p, n4 - - // up - - colorAttribute.setXYZ( 32, up.r, up.g, up.b ); colorAttribute.setXYZ( 33, up.r, up.g, up.b ); // u1, u2 - colorAttribute.setXYZ( 34, up.r, up.g, up.b ); colorAttribute.setXYZ( 35, up.r, up.g, up.b ); // u2, u3 - colorAttribute.setXYZ( 36, up.r, up.g, up.b ); colorAttribute.setXYZ( 37, up.r, up.g, up.b ); // u3, u1 - - // target - - colorAttribute.setXYZ( 38, target.r, target.g, target.b ); colorAttribute.setXYZ( 39, target.r, target.g, target.b ); // c, t - colorAttribute.setXYZ( 40, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 41, cross.r, cross.g, cross.b ); // p, c - - // cross - - colorAttribute.setXYZ( 42, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 43, cross.r, cross.g, cross.b ); // cn1, cn2 - colorAttribute.setXYZ( 44, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 45, cross.r, cross.g, cross.b ); // cn3, cn4 - - colorAttribute.setXYZ( 46, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 47, cross.r, cross.g, cross.b ); // cf1, cf2 - colorAttribute.setXYZ( 48, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 49, cross.r, cross.g, cross.b ); // cf3, cf4 - - colorAttribute.needsUpdate = true; - - } - - update() { - - const geometry = this.geometry; - const pointMap = this.pointMap; - - const w = 1, h = 1; - - // we need just camera projection matrix inverse - // world matrix must be identity - - _camera.projectionMatrixInverse.copy( this.camera.projectionMatrixInverse ); - - // center / target - - setPoint( 'c', pointMap, geometry, _camera, 0, 0, - 1 ); - setPoint( 't', pointMap, geometry, _camera, 0, 0, 1 ); - - // near - - setPoint( 'n1', pointMap, geometry, _camera, - w, - h, - 1 ); - setPoint( 'n2', pointMap, geometry, _camera, w, - h, - 1 ); - setPoint( 'n3', pointMap, geometry, _camera, - w, h, - 1 ); - setPoint( 'n4', pointMap, geometry, _camera, w, h, - 1 ); - - // far - - setPoint( 'f1', pointMap, geometry, _camera, - w, - h, 1 ); - setPoint( 'f2', pointMap, geometry, _camera, w, - h, 1 ); - setPoint( 'f3', pointMap, geometry, _camera, - w, h, 1 ); - setPoint( 'f4', pointMap, geometry, _camera, w, h, 1 ); - - // up - - setPoint( 'u1', pointMap, geometry, _camera, w * 0.7, h * 1.1, - 1 ); - setPoint( 'u2', pointMap, geometry, _camera, - w * 0.7, h * 1.1, - 1 ); - setPoint( 'u3', pointMap, geometry, _camera, 0, h * 2, - 1 ); - - // cross - - setPoint( 'cf1', pointMap, geometry, _camera, - w, 0, 1 ); - setPoint( 'cf2', pointMap, geometry, _camera, w, 0, 1 ); - setPoint( 'cf3', pointMap, geometry, _camera, 0, - h, 1 ); - setPoint( 'cf4', pointMap, geometry, _camera, 0, h, 1 ); - - setPoint( 'cn1', pointMap, geometry, _camera, - w, 0, - 1 ); - setPoint( 'cn2', pointMap, geometry, _camera, w, 0, - 1 ); - setPoint( 'cn3', pointMap, geometry, _camera, 0, - h, - 1 ); - setPoint( 'cn4', pointMap, geometry, _camera, 0, h, - 1 ); - - geometry.getAttribute( 'position' ).needsUpdate = true; - - } - - dispose() { - - this.geometry.dispose(); - this.material.dispose(); - - } - -} - - -function setPoint( point, pointMap, geometry, camera, x, y, z ) { - - _vector.set( x, y, z ).unproject( camera ); - - const points = pointMap[ point ]; - - if ( points !== undefined ) { - - const position = geometry.getAttribute( 'position' ); - - for ( let i = 0, l = points.length; i < l; i ++ ) { - - position.setXYZ( points[ i ], _vector.x, _vector.y, _vector.z ); - - } - - } - -} - -const _box = /*@__PURE__*/ new Box3(); - -class BoxHelper extends LineSegments { - - constructor( object, color = 0xffff00 ) { - - const indices = new Uint16Array( [ 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7 ] ); - const positions = new Float32Array( 8 * 3 ); - - const geometry = new BufferGeometry(); - geometry.setIndex( new BufferAttribute( indices, 1 ) ); - geometry.setAttribute( 'position', new BufferAttribute( positions, 3 ) ); - - super( geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) ); - - this.object = object; - this.type = 'BoxHelper'; - - this.matrixAutoUpdate = false; - - this.update(); - - } - - update( object ) { - - if ( object !== undefined ) { - - console.warn( 'THREE.BoxHelper: .update() has no longer arguments.' ); - - } - - if ( this.object !== undefined ) { - - _box.setFromObject( this.object ); - - } - - if ( _box.isEmpty() ) return; - - const min = _box.min; - const max = _box.max; - - /* - 5____4 - 1/___0/| - | 6__|_7 - 2/___3/ - - 0: max.x, max.y, max.z - 1: min.x, max.y, max.z - 2: min.x, min.y, max.z - 3: max.x, min.y, max.z - 4: max.x, max.y, min.z - 5: min.x, max.y, min.z - 6: min.x, min.y, min.z - 7: max.x, min.y, min.z - */ - - const position = this.geometry.attributes.position; - const array = position.array; - - array[ 0 ] = max.x; array[ 1 ] = max.y; array[ 2 ] = max.z; - array[ 3 ] = min.x; array[ 4 ] = max.y; array[ 5 ] = max.z; - array[ 6 ] = min.x; array[ 7 ] = min.y; array[ 8 ] = max.z; - array[ 9 ] = max.x; array[ 10 ] = min.y; array[ 11 ] = max.z; - array[ 12 ] = max.x; array[ 13 ] = max.y; array[ 14 ] = min.z; - array[ 15 ] = min.x; array[ 16 ] = max.y; array[ 17 ] = min.z; - array[ 18 ] = min.x; array[ 19 ] = min.y; array[ 20 ] = min.z; - array[ 21 ] = max.x; array[ 22 ] = min.y; array[ 23 ] = min.z; - - position.needsUpdate = true; - - this.geometry.computeBoundingSphere(); - - } - - setFromObject( object ) { - - this.object = object; - this.update(); - - return this; - - } - - copy( source, recursive ) { - - super.copy( source, recursive ); - - this.object = source.object; - - return this; - - } - - dispose() { - - this.geometry.dispose(); - this.material.dispose(); - - } - -} - -class Box3Helper extends LineSegments { - - constructor( box, color = 0xffff00 ) { - - const indices = new Uint16Array( [ 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7 ] ); - - const positions = [ 1, 1, 1, - 1, 1, 1, - 1, - 1, 1, 1, - 1, 1, 1, 1, - 1, - 1, 1, - 1, - 1, - 1, - 1, 1, - 1, - 1 ]; - - const geometry = new BufferGeometry(); - - geometry.setIndex( new BufferAttribute( indices, 1 ) ); - - geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) ); - - super( geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) ); - - this.box = box; - - this.type = 'Box3Helper'; - - this.geometry.computeBoundingSphere(); - - } - - updateMatrixWorld( force ) { - - const box = this.box; - - if ( box.isEmpty() ) return; - - box.getCenter( this.position ); - - box.getSize( this.scale ); - - this.scale.multiplyScalar( 0.5 ); - - super.updateMatrixWorld( force ); - - } - - dispose() { - - this.geometry.dispose(); - this.material.dispose(); - - } - -} - -class PlaneHelper extends Line { - - constructor( plane, size = 1, hex = 0xffff00 ) { - - const color = hex; - - const positions = [ 1, - 1, 0, - 1, 1, 0, - 1, - 1, 0, 1, 1, 0, - 1, 1, 0, - 1, - 1, 0, 1, - 1, 0, 1, 1, 0 ]; - - const geometry = new BufferGeometry(); - geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) ); - geometry.computeBoundingSphere(); - - super( geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) ); - - this.type = 'PlaneHelper'; - - this.plane = plane; - - this.size = size; - - const positions2 = [ 1, 1, 0, - 1, 1, 0, - 1, - 1, 0, 1, 1, 0, - 1, - 1, 0, 1, - 1, 0 ]; - - const geometry2 = new BufferGeometry(); - geometry2.setAttribute( 'position', new Float32BufferAttribute( positions2, 3 ) ); - geometry2.computeBoundingSphere(); - - this.add( new Mesh( geometry2, new MeshBasicMaterial( { color: color, opacity: 0.2, transparent: true, depthWrite: false, toneMapped: false } ) ) ); - - } - - updateMatrixWorld( force ) { - - this.position.set( 0, 0, 0 ); - - this.scale.set( 0.5 * this.size, 0.5 * this.size, 1 ); - - this.lookAt( this.plane.normal ); - - this.translateZ( - this.plane.constant ); - - super.updateMatrixWorld( force ); - - } - - dispose() { - - this.geometry.dispose(); - this.material.dispose(); - this.children[ 0 ].geometry.dispose(); - this.children[ 0 ].material.dispose(); - - } - -} - -const _axis = /*@__PURE__*/ new Vector3(); -let _lineGeometry, _coneGeometry; - -class ArrowHelper extends Object3D { - - // dir is assumed to be normalized - - constructor( dir = new Vector3( 0, 0, 1 ), origin = new Vector3( 0, 0, 0 ), length = 1, color = 0xffff00, headLength = length * 0.2, headWidth = headLength * 0.2 ) { - - super(); - - this.type = 'ArrowHelper'; - - if ( _lineGeometry === undefined ) { - - _lineGeometry = new BufferGeometry(); - _lineGeometry.setAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 1, 0 ], 3 ) ); - - _coneGeometry = new CylinderGeometry( 0, 0.5, 1, 5, 1 ); - _coneGeometry.translate( 0, - 0.5, 0 ); - - } - - this.position.copy( origin ); - - this.line = new Line( _lineGeometry, new LineBasicMaterial( { color: color, toneMapped: false } ) ); - this.line.matrixAutoUpdate = false; - this.add( this.line ); - - this.cone = new Mesh( _coneGeometry, new MeshBasicMaterial( { color: color, toneMapped: false } ) ); - this.cone.matrixAutoUpdate = false; - this.add( this.cone ); - - this.setDirection( dir ); - this.setLength( length, headLength, headWidth ); - - } - - setDirection( dir ) { - - // dir is assumed to be normalized - - if ( dir.y > 0.99999 ) { - - this.quaternion.set( 0, 0, 0, 1 ); - - } else if ( dir.y < - 0.99999 ) { - - this.quaternion.set( 1, 0, 0, 0 ); - - } else { - - _axis.set( dir.z, 0, - dir.x ).normalize(); - - const radians = Math.acos( dir.y ); - - this.quaternion.setFromAxisAngle( _axis, radians ); - - } - - } - - setLength( length, headLength = length * 0.2, headWidth = headLength * 0.2 ) { - - this.line.scale.set( 1, Math.max( 0.0001, length - headLength ), 1 ); // see #17458 - this.line.updateMatrix(); - - this.cone.scale.set( headWidth, headLength, headWidth ); - this.cone.position.y = length; - this.cone.updateMatrix(); - - } - - setColor( color ) { - - this.line.material.color.set( color ); - this.cone.material.color.set( color ); - - } - - copy( source ) { - - super.copy( source, false ); - - this.line.copy( source.line ); - this.cone.copy( source.cone ); - - return this; - - } - - dispose() { - - this.line.geometry.dispose(); - this.line.material.dispose(); - this.cone.geometry.dispose(); - this.cone.material.dispose(); - - } - -} - -class AxesHelper extends LineSegments { - - constructor( size = 1 ) { - - const vertices = [ - 0, 0, 0, size, 0, 0, - 0, 0, 0, 0, size, 0, - 0, 0, 0, 0, 0, size - ]; - - const colors = [ - 1, 0, 0, 1, 0.6, 0, - 0, 1, 0, 0.6, 1, 0, - 0, 0, 1, 0, 0.6, 1 - ]; - - const geometry = new BufferGeometry(); - geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); - - const material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } ); - - super( geometry, material ); - - this.type = 'AxesHelper'; - - } - - setColors( xAxisColor, yAxisColor, zAxisColor ) { - - const color = new Color(); - const array = this.geometry.attributes.color.array; - - color.set( xAxisColor ); - color.toArray( array, 0 ); - color.toArray( array, 3 ); - - color.set( yAxisColor ); - color.toArray( array, 6 ); - color.toArray( array, 9 ); - - color.set( zAxisColor ); - color.toArray( array, 12 ); - color.toArray( array, 15 ); - - this.geometry.attributes.color.needsUpdate = true; - - return this; - - } - - dispose() { - - this.geometry.dispose(); - this.material.dispose(); - - } - -} - -class ShapePath { - - constructor() { - - this.type = 'ShapePath'; - - this.color = new Color(); - - this.subPaths = []; - this.currentPath = null; - - } - - moveTo( x, y ) { - - this.currentPath = new Path(); - this.subPaths.push( this.currentPath ); - this.currentPath.moveTo( x, y ); - - return this; - - } - - lineTo( x, y ) { - - this.currentPath.lineTo( x, y ); - - return this; - - } - - quadraticCurveTo( aCPx, aCPy, aX, aY ) { - - this.currentPath.quadraticCurveTo( aCPx, aCPy, aX, aY ); - - return this; - - } - - bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) { - - this.currentPath.bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ); - - return this; - - } - - splineThru( pts ) { - - this.currentPath.splineThru( pts ); - - return this; - - } - - toShapes( isCCW ) { - - function toShapesNoHoles( inSubpaths ) { - - const shapes = []; - - for ( let i = 0, l = inSubpaths.length; i < l; i ++ ) { - - const tmpPath = inSubpaths[ i ]; - - const tmpShape = new Shape(); - tmpShape.curves = tmpPath.curves; - - shapes.push( tmpShape ); - - } - - return shapes; - - } - - function isPointInsidePolygon( inPt, inPolygon ) { - - const polyLen = inPolygon.length; - - // inPt on polygon contour => immediate success or - // toggling of inside/outside at every single! intersection point of an edge - // with the horizontal line through inPt, left of inPt - // not counting lowerY endpoints of edges and whole edges on that line - let inside = false; - for ( let p = polyLen - 1, q = 0; q < polyLen; p = q ++ ) { - - let edgeLowPt = inPolygon[ p ]; - let edgeHighPt = inPolygon[ q ]; - - let edgeDx = edgeHighPt.x - edgeLowPt.x; - let edgeDy = edgeHighPt.y - edgeLowPt.y; - - if ( Math.abs( edgeDy ) > Number.EPSILON ) { - - // not parallel - if ( edgeDy < 0 ) { - - edgeLowPt = inPolygon[ q ]; edgeDx = - edgeDx; - edgeHighPt = inPolygon[ p ]; edgeDy = - edgeDy; - - } - - if ( ( inPt.y < edgeLowPt.y ) || ( inPt.y > edgeHighPt.y ) ) continue; - - if ( inPt.y === edgeLowPt.y ) { - - if ( inPt.x === edgeLowPt.x ) return true; // inPt is on contour ? - // continue; // no intersection or edgeLowPt => doesn't count !!! - - } else { - - const perpEdge = edgeDy * ( inPt.x - edgeLowPt.x ) - edgeDx * ( inPt.y - edgeLowPt.y ); - if ( perpEdge === 0 ) return true; // inPt is on contour ? - if ( perpEdge < 0 ) continue; - inside = ! inside; // true intersection left of inPt - - } - - } else { - - // parallel or collinear - if ( inPt.y !== edgeLowPt.y ) continue; // parallel - // edge lies on the same horizontal line as inPt - if ( ( ( edgeHighPt.x <= inPt.x ) && ( inPt.x <= edgeLowPt.x ) ) || - ( ( edgeLowPt.x <= inPt.x ) && ( inPt.x <= edgeHighPt.x ) ) ) return true; // inPt: Point on contour ! - // continue; - - } - - } - - return inside; - - } - - const isClockWise = ShapeUtils.isClockWise; - - const subPaths = this.subPaths; - if ( subPaths.length === 0 ) return []; - - let solid, tmpPath, tmpShape; - const shapes = []; - - if ( subPaths.length === 1 ) { - - tmpPath = subPaths[ 0 ]; - tmpShape = new Shape(); - tmpShape.curves = tmpPath.curves; - shapes.push( tmpShape ); - return shapes; - - } - - let holesFirst = ! isClockWise( subPaths[ 0 ].getPoints() ); - holesFirst = isCCW ? ! holesFirst : holesFirst; - - // console.log("Holes first", holesFirst); - - const betterShapeHoles = []; - const newShapes = []; - let newShapeHoles = []; - let mainIdx = 0; - let tmpPoints; - - newShapes[ mainIdx ] = undefined; - newShapeHoles[ mainIdx ] = []; - - for ( let i = 0, l = subPaths.length; i < l; i ++ ) { - - tmpPath = subPaths[ i ]; - tmpPoints = tmpPath.getPoints(); - solid = isClockWise( tmpPoints ); - solid = isCCW ? ! solid : solid; - - if ( solid ) { - - if ( ( ! holesFirst ) && ( newShapes[ mainIdx ] ) ) mainIdx ++; - - newShapes[ mainIdx ] = { s: new Shape(), p: tmpPoints }; - newShapes[ mainIdx ].s.curves = tmpPath.curves; - - if ( holesFirst ) mainIdx ++; - newShapeHoles[ mainIdx ] = []; - - //console.log('cw', i); - - } else { - - newShapeHoles[ mainIdx ].push( { h: tmpPath, p: tmpPoints[ 0 ] } ); - - //console.log('ccw', i); - - } - - } - - // only Holes? -> probably all Shapes with wrong orientation - if ( ! newShapes[ 0 ] ) return toShapesNoHoles( subPaths ); - - - if ( newShapes.length > 1 ) { - - let ambiguous = false; - let toChange = 0; - - for ( let sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) { - - betterShapeHoles[ sIdx ] = []; - - } - - for ( let sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) { - - const sho = newShapeHoles[ sIdx ]; - - for ( let hIdx = 0; hIdx < sho.length; hIdx ++ ) { - - const ho = sho[ hIdx ]; - let hole_unassigned = true; - - for ( let s2Idx = 0; s2Idx < newShapes.length; s2Idx ++ ) { - - if ( isPointInsidePolygon( ho.p, newShapes[ s2Idx ].p ) ) { - - if ( sIdx !== s2Idx ) toChange ++; - - if ( hole_unassigned ) { - - hole_unassigned = false; - betterShapeHoles[ s2Idx ].push( ho ); - - } else { - - ambiguous = true; - - } - - } - - } - - if ( hole_unassigned ) { - - betterShapeHoles[ sIdx ].push( ho ); - - } - - } - - } - - if ( toChange > 0 && ambiguous === false ) { - - newShapeHoles = betterShapeHoles; - - } - - } - - let tmpHoles; - - for ( let i = 0, il = newShapes.length; i < il; i ++ ) { - - tmpShape = newShapes[ i ].s; - shapes.push( tmpShape ); - tmpHoles = newShapeHoles[ i ]; - - for ( let j = 0, jl = tmpHoles.length; j < jl; j ++ ) { - - tmpShape.holes.push( tmpHoles[ j ].h ); - - } - - } - - //console.log("shape", shapes); - - return shapes; - - } - -} - -if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) { - - __THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'register', { detail: { - revision: REVISION, - } } ) ); - -} - -if ( typeof window !== 'undefined' ) { - - if ( window.__THREE__ ) { - - console.warn( 'WARNING: Multiple instances of Three.js being imported.' ); - - } else { - - window.__THREE__ = REVISION; - - } - -} - -exports.ACESFilmicToneMapping = ACESFilmicToneMapping; -exports.AddEquation = AddEquation; -exports.AddOperation = AddOperation; -exports.AdditiveAnimationBlendMode = AdditiveAnimationBlendMode; -exports.AdditiveBlending = AdditiveBlending; -exports.AgXToneMapping = AgXToneMapping; -exports.AlphaFormat = AlphaFormat; -exports.AlwaysCompare = AlwaysCompare; -exports.AlwaysDepth = AlwaysDepth; -exports.AlwaysStencilFunc = AlwaysStencilFunc; -exports.AmbientLight = AmbientLight; -exports.AnimationAction = AnimationAction; -exports.AnimationClip = AnimationClip; -exports.AnimationLoader = AnimationLoader; -exports.AnimationMixer = AnimationMixer; -exports.AnimationObjectGroup = AnimationObjectGroup; -exports.AnimationUtils = AnimationUtils; -exports.ArcCurve = ArcCurve; -exports.ArrayCamera = ArrayCamera; -exports.ArrowHelper = ArrowHelper; -exports.AttachedBindMode = AttachedBindMode; -exports.Audio = Audio; -exports.AudioAnalyser = AudioAnalyser; -exports.AudioContext = AudioContext; -exports.AudioListener = AudioListener; -exports.AudioLoader = AudioLoader; -exports.AxesHelper = AxesHelper; -exports.BackSide = BackSide; -exports.BasicDepthPacking = BasicDepthPacking; -exports.BasicShadowMap = BasicShadowMap; -exports.BatchedMesh = BatchedMesh; -exports.Bone = Bone; -exports.BooleanKeyframeTrack = BooleanKeyframeTrack; -exports.Box2 = Box2; -exports.Box3 = Box3; -exports.Box3Helper = Box3Helper; -exports.BoxGeometry = BoxGeometry; -exports.BoxHelper = BoxHelper; -exports.BufferAttribute = BufferAttribute; -exports.BufferGeometry = BufferGeometry; -exports.BufferGeometryLoader = BufferGeometryLoader; -exports.ByteType = ByteType; -exports.Cache = Cache; -exports.Camera = Camera; -exports.CameraHelper = CameraHelper; -exports.CanvasTexture = CanvasTexture; -exports.CapsuleGeometry = CapsuleGeometry; -exports.CatmullRomCurve3 = CatmullRomCurve3; -exports.CineonToneMapping = CineonToneMapping; -exports.CircleGeometry = CircleGeometry; -exports.ClampToEdgeWrapping = ClampToEdgeWrapping; -exports.Clock = Clock; -exports.Color = Color; -exports.ColorKeyframeTrack = ColorKeyframeTrack; -exports.ColorManagement = ColorManagement; -exports.CompressedArrayTexture = CompressedArrayTexture; -exports.CompressedCubeTexture = CompressedCubeTexture; -exports.CompressedTexture = CompressedTexture; -exports.CompressedTextureLoader = CompressedTextureLoader; -exports.ConeGeometry = ConeGeometry; -exports.ConstantAlphaFactor = ConstantAlphaFactor; -exports.ConstantColorFactor = ConstantColorFactor; -exports.CubeCamera = CubeCamera; -exports.CubeReflectionMapping = CubeReflectionMapping; -exports.CubeRefractionMapping = CubeRefractionMapping; -exports.CubeTexture = CubeTexture; -exports.CubeTextureLoader = CubeTextureLoader; -exports.CubeUVReflectionMapping = CubeUVReflectionMapping; -exports.CubicBezierCurve = CubicBezierCurve; -exports.CubicBezierCurve3 = CubicBezierCurve3; -exports.CubicInterpolant = CubicInterpolant; -exports.CullFaceBack = CullFaceBack; -exports.CullFaceFront = CullFaceFront; -exports.CullFaceFrontBack = CullFaceFrontBack; -exports.CullFaceNone = CullFaceNone; -exports.Curve = Curve; -exports.CurvePath = CurvePath; -exports.CustomBlending = CustomBlending; -exports.CustomToneMapping = CustomToneMapping; -exports.CylinderGeometry = CylinderGeometry; -exports.Cylindrical = Cylindrical; -exports.Data3DTexture = Data3DTexture; -exports.DataArrayTexture = DataArrayTexture; -exports.DataTexture = DataTexture; -exports.DataTextureLoader = DataTextureLoader; -exports.DataUtils = DataUtils; -exports.DecrementStencilOp = DecrementStencilOp; -exports.DecrementWrapStencilOp = DecrementWrapStencilOp; -exports.DefaultLoadingManager = DefaultLoadingManager; -exports.DepthFormat = DepthFormat; -exports.DepthStencilFormat = DepthStencilFormat; -exports.DepthTexture = DepthTexture; -exports.DetachedBindMode = DetachedBindMode; -exports.DirectionalLight = DirectionalLight; -exports.DirectionalLightHelper = DirectionalLightHelper; -exports.DiscreteInterpolant = DiscreteInterpolant; -exports.DisplayP3ColorSpace = DisplayP3ColorSpace; -exports.DodecahedronGeometry = DodecahedronGeometry; -exports.DoubleSide = DoubleSide; -exports.DstAlphaFactor = DstAlphaFactor; -exports.DstColorFactor = DstColorFactor; -exports.DynamicCopyUsage = DynamicCopyUsage; -exports.DynamicDrawUsage = DynamicDrawUsage; -exports.DynamicReadUsage = DynamicReadUsage; -exports.EdgesGeometry = EdgesGeometry; -exports.EllipseCurve = EllipseCurve; -exports.EqualCompare = EqualCompare; -exports.EqualDepth = EqualDepth; -exports.EqualStencilFunc = EqualStencilFunc; -exports.EquirectangularReflectionMapping = EquirectangularReflectionMapping; -exports.EquirectangularRefractionMapping = EquirectangularRefractionMapping; -exports.Euler = Euler; -exports.EventDispatcher = EventDispatcher; -exports.ExtrudeGeometry = ExtrudeGeometry; -exports.FileLoader = FileLoader; -exports.Float16BufferAttribute = Float16BufferAttribute; -exports.Float32BufferAttribute = Float32BufferAttribute; -exports.Float64BufferAttribute = Float64BufferAttribute; -exports.FloatType = FloatType; -exports.Fog = Fog; -exports.FogExp2 = FogExp2; -exports.FramebufferTexture = FramebufferTexture; -exports.FrontSide = FrontSide; -exports.Frustum = Frustum; -exports.GLBufferAttribute = GLBufferAttribute; -exports.GLSL1 = GLSL1; -exports.GLSL3 = GLSL3; -exports.GreaterCompare = GreaterCompare; -exports.GreaterDepth = GreaterDepth; -exports.GreaterEqualCompare = GreaterEqualCompare; -exports.GreaterEqualDepth = GreaterEqualDepth; -exports.GreaterEqualStencilFunc = GreaterEqualStencilFunc; -exports.GreaterStencilFunc = GreaterStencilFunc; -exports.GridHelper = GridHelper; -exports.Group = Group; -exports.HalfFloatType = HalfFloatType; -exports.HemisphereLight = HemisphereLight; -exports.HemisphereLightHelper = HemisphereLightHelper; -exports.IcosahedronGeometry = IcosahedronGeometry; -exports.ImageBitmapLoader = ImageBitmapLoader; -exports.ImageLoader = ImageLoader; -exports.ImageUtils = ImageUtils; -exports.IncrementStencilOp = IncrementStencilOp; -exports.IncrementWrapStencilOp = IncrementWrapStencilOp; -exports.InstancedBufferAttribute = InstancedBufferAttribute; -exports.InstancedBufferGeometry = InstancedBufferGeometry; -exports.InstancedInterleavedBuffer = InstancedInterleavedBuffer; -exports.InstancedMesh = InstancedMesh; -exports.Int16BufferAttribute = Int16BufferAttribute; -exports.Int32BufferAttribute = Int32BufferAttribute; -exports.Int8BufferAttribute = Int8BufferAttribute; -exports.IntType = IntType; -exports.InterleavedBuffer = InterleavedBuffer; -exports.InterleavedBufferAttribute = InterleavedBufferAttribute; -exports.Interpolant = Interpolant; -exports.InterpolateDiscrete = InterpolateDiscrete; -exports.InterpolateLinear = InterpolateLinear; -exports.InterpolateSmooth = InterpolateSmooth; -exports.InvertStencilOp = InvertStencilOp; -exports.KeepStencilOp = KeepStencilOp; -exports.KeyframeTrack = KeyframeTrack; -exports.LOD = LOD; -exports.LatheGeometry = LatheGeometry; -exports.Layers = Layers; -exports.LessCompare = LessCompare; -exports.LessDepth = LessDepth; -exports.LessEqualCompare = LessEqualCompare; -exports.LessEqualDepth = LessEqualDepth; -exports.LessEqualStencilFunc = LessEqualStencilFunc; -exports.LessStencilFunc = LessStencilFunc; -exports.Light = Light; -exports.LightProbe = LightProbe; -exports.Line = Line; -exports.Line3 = Line3; -exports.LineBasicMaterial = LineBasicMaterial; -exports.LineCurve = LineCurve; -exports.LineCurve3 = LineCurve3; -exports.LineDashedMaterial = LineDashedMaterial; -exports.LineLoop = LineLoop; -exports.LineSegments = LineSegments; -exports.LinearDisplayP3ColorSpace = LinearDisplayP3ColorSpace; -exports.LinearFilter = LinearFilter; -exports.LinearInterpolant = LinearInterpolant; -exports.LinearMipMapLinearFilter = LinearMipMapLinearFilter; -exports.LinearMipMapNearestFilter = LinearMipMapNearestFilter; -exports.LinearMipmapLinearFilter = LinearMipmapLinearFilter; -exports.LinearMipmapNearestFilter = LinearMipmapNearestFilter; -exports.LinearSRGBColorSpace = LinearSRGBColorSpace; -exports.LinearToneMapping = LinearToneMapping; -exports.LinearTransfer = LinearTransfer; -exports.Loader = Loader; -exports.LoaderUtils = LoaderUtils; -exports.LoadingManager = LoadingManager; -exports.LoopOnce = LoopOnce; -exports.LoopPingPong = LoopPingPong; -exports.LoopRepeat = LoopRepeat; -exports.LuminanceAlphaFormat = LuminanceAlphaFormat; -exports.LuminanceFormat = LuminanceFormat; -exports.MOUSE = MOUSE; -exports.Material = Material; -exports.MaterialLoader = MaterialLoader; -exports.MathUtils = MathUtils; -exports.Matrix3 = Matrix3; -exports.Matrix4 = Matrix4; -exports.MaxEquation = MaxEquation; -exports.Mesh = Mesh; -exports.MeshBasicMaterial = MeshBasicMaterial; -exports.MeshDepthMaterial = MeshDepthMaterial; -exports.MeshDistanceMaterial = MeshDistanceMaterial; -exports.MeshLambertMaterial = MeshLambertMaterial; -exports.MeshMatcapMaterial = MeshMatcapMaterial; -exports.MeshNormalMaterial = MeshNormalMaterial; -exports.MeshPhongMaterial = MeshPhongMaterial; -exports.MeshPhysicalMaterial = MeshPhysicalMaterial; -exports.MeshStandardMaterial = MeshStandardMaterial; -exports.MeshToonMaterial = MeshToonMaterial; -exports.MinEquation = MinEquation; -exports.MirroredRepeatWrapping = MirroredRepeatWrapping; -exports.MixOperation = MixOperation; -exports.MultiplyBlending = MultiplyBlending; -exports.MultiplyOperation = MultiplyOperation; -exports.NearestFilter = NearestFilter; -exports.NearestMipMapLinearFilter = NearestMipMapLinearFilter; -exports.NearestMipMapNearestFilter = NearestMipMapNearestFilter; -exports.NearestMipmapLinearFilter = NearestMipmapLinearFilter; -exports.NearestMipmapNearestFilter = NearestMipmapNearestFilter; -exports.NeverCompare = NeverCompare; -exports.NeverDepth = NeverDepth; -exports.NeverStencilFunc = NeverStencilFunc; -exports.NoBlending = NoBlending; -exports.NoColorSpace = NoColorSpace; -exports.NoToneMapping = NoToneMapping; -exports.NormalAnimationBlendMode = NormalAnimationBlendMode; -exports.NormalBlending = NormalBlending; -exports.NotEqualCompare = NotEqualCompare; -exports.NotEqualDepth = NotEqualDepth; -exports.NotEqualStencilFunc = NotEqualStencilFunc; -exports.NumberKeyframeTrack = NumberKeyframeTrack; -exports.Object3D = Object3D; -exports.ObjectLoader = ObjectLoader; -exports.ObjectSpaceNormalMap = ObjectSpaceNormalMap; -exports.OctahedronGeometry = OctahedronGeometry; -exports.OneFactor = OneFactor; -exports.OneMinusConstantAlphaFactor = OneMinusConstantAlphaFactor; -exports.OneMinusConstantColorFactor = OneMinusConstantColorFactor; -exports.OneMinusDstAlphaFactor = OneMinusDstAlphaFactor; -exports.OneMinusDstColorFactor = OneMinusDstColorFactor; -exports.OneMinusSrcAlphaFactor = OneMinusSrcAlphaFactor; -exports.OneMinusSrcColorFactor = OneMinusSrcColorFactor; -exports.OrthographicCamera = OrthographicCamera; -exports.P3Primaries = P3Primaries; -exports.PCFShadowMap = PCFShadowMap; -exports.PCFSoftShadowMap = PCFSoftShadowMap; -exports.PMREMGenerator = PMREMGenerator; -exports.Path = Path; -exports.PerspectiveCamera = PerspectiveCamera; -exports.Plane = Plane; -exports.PlaneGeometry = PlaneGeometry; -exports.PlaneHelper = PlaneHelper; -exports.PointLight = PointLight; -exports.PointLightHelper = PointLightHelper; -exports.Points = Points; -exports.PointsMaterial = PointsMaterial; -exports.PolarGridHelper = PolarGridHelper; -exports.PolyhedronGeometry = PolyhedronGeometry; -exports.PositionalAudio = PositionalAudio; -exports.PropertyBinding = PropertyBinding; -exports.PropertyMixer = PropertyMixer; -exports.QuadraticBezierCurve = QuadraticBezierCurve; -exports.QuadraticBezierCurve3 = QuadraticBezierCurve3; -exports.Quaternion = Quaternion; -exports.QuaternionKeyframeTrack = QuaternionKeyframeTrack; -exports.QuaternionLinearInterpolant = QuaternionLinearInterpolant; -exports.RED_GREEN_RGTC2_Format = RED_GREEN_RGTC2_Format; -exports.RED_RGTC1_Format = RED_RGTC1_Format; -exports.REVISION = REVISION; -exports.RGBADepthPacking = RGBADepthPacking; -exports.RGBAFormat = RGBAFormat; -exports.RGBAIntegerFormat = RGBAIntegerFormat; -exports.RGBA_ASTC_10x10_Format = RGBA_ASTC_10x10_Format; -exports.RGBA_ASTC_10x5_Format = RGBA_ASTC_10x5_Format; -exports.RGBA_ASTC_10x6_Format = RGBA_ASTC_10x6_Format; -exports.RGBA_ASTC_10x8_Format = RGBA_ASTC_10x8_Format; -exports.RGBA_ASTC_12x10_Format = RGBA_ASTC_12x10_Format; -exports.RGBA_ASTC_12x12_Format = RGBA_ASTC_12x12_Format; -exports.RGBA_ASTC_4x4_Format = RGBA_ASTC_4x4_Format; -exports.RGBA_ASTC_5x4_Format = RGBA_ASTC_5x4_Format; -exports.RGBA_ASTC_5x5_Format = RGBA_ASTC_5x5_Format; -exports.RGBA_ASTC_6x5_Format = RGBA_ASTC_6x5_Format; -exports.RGBA_ASTC_6x6_Format = RGBA_ASTC_6x6_Format; -exports.RGBA_ASTC_8x5_Format = RGBA_ASTC_8x5_Format; -exports.RGBA_ASTC_8x6_Format = RGBA_ASTC_8x6_Format; -exports.RGBA_ASTC_8x8_Format = RGBA_ASTC_8x8_Format; -exports.RGBA_BPTC_Format = RGBA_BPTC_Format; -exports.RGBA_ETC2_EAC_Format = RGBA_ETC2_EAC_Format; -exports.RGBA_PVRTC_2BPPV1_Format = RGBA_PVRTC_2BPPV1_Format; -exports.RGBA_PVRTC_4BPPV1_Format = RGBA_PVRTC_4BPPV1_Format; -exports.RGBA_S3TC_DXT1_Format = RGBA_S3TC_DXT1_Format; -exports.RGBA_S3TC_DXT3_Format = RGBA_S3TC_DXT3_Format; -exports.RGBA_S3TC_DXT5_Format = RGBA_S3TC_DXT5_Format; -exports.RGB_BPTC_SIGNED_Format = RGB_BPTC_SIGNED_Format; -exports.RGB_BPTC_UNSIGNED_Format = RGB_BPTC_UNSIGNED_Format; -exports.RGB_ETC1_Format = RGB_ETC1_Format; -exports.RGB_ETC2_Format = RGB_ETC2_Format; -exports.RGB_PVRTC_2BPPV1_Format = RGB_PVRTC_2BPPV1_Format; -exports.RGB_PVRTC_4BPPV1_Format = RGB_PVRTC_4BPPV1_Format; -exports.RGB_S3TC_DXT1_Format = RGB_S3TC_DXT1_Format; -exports.RGFormat = RGFormat; -exports.RGIntegerFormat = RGIntegerFormat; -exports.RawShaderMaterial = RawShaderMaterial; -exports.Ray = Ray; -exports.Raycaster = Raycaster; -exports.Rec709Primaries = Rec709Primaries; -exports.RectAreaLight = RectAreaLight; -exports.RedFormat = RedFormat; -exports.RedIntegerFormat = RedIntegerFormat; -exports.ReinhardToneMapping = ReinhardToneMapping; -exports.RenderTarget = RenderTarget; -exports.RepeatWrapping = RepeatWrapping; -exports.ReplaceStencilOp = ReplaceStencilOp; -exports.ReverseSubtractEquation = ReverseSubtractEquation; -exports.RingGeometry = RingGeometry; -exports.SIGNED_RED_GREEN_RGTC2_Format = SIGNED_RED_GREEN_RGTC2_Format; -exports.SIGNED_RED_RGTC1_Format = SIGNED_RED_RGTC1_Format; -exports.SRGBColorSpace = SRGBColorSpace; -exports.SRGBTransfer = SRGBTransfer; -exports.Scene = Scene; -exports.ShaderChunk = ShaderChunk; -exports.ShaderLib = ShaderLib; -exports.ShaderMaterial = ShaderMaterial; -exports.ShadowMaterial = ShadowMaterial; -exports.Shape = Shape; -exports.ShapeGeometry = ShapeGeometry; -exports.ShapePath = ShapePath; -exports.ShapeUtils = ShapeUtils; -exports.ShortType = ShortType; -exports.Skeleton = Skeleton; -exports.SkeletonHelper = SkeletonHelper; -exports.SkinnedMesh = SkinnedMesh; -exports.Source = Source; -exports.Sphere = Sphere; -exports.SphereGeometry = SphereGeometry; -exports.Spherical = Spherical; -exports.SphericalHarmonics3 = SphericalHarmonics3; -exports.SplineCurve = SplineCurve; -exports.SpotLight = SpotLight; -exports.SpotLightHelper = SpotLightHelper; -exports.Sprite = Sprite; -exports.SpriteMaterial = SpriteMaterial; -exports.SrcAlphaFactor = SrcAlphaFactor; -exports.SrcAlphaSaturateFactor = SrcAlphaSaturateFactor; -exports.SrcColorFactor = SrcColorFactor; -exports.StaticCopyUsage = StaticCopyUsage; -exports.StaticDrawUsage = StaticDrawUsage; -exports.StaticReadUsage = StaticReadUsage; -exports.StereoCamera = StereoCamera; -exports.StreamCopyUsage = StreamCopyUsage; -exports.StreamDrawUsage = StreamDrawUsage; -exports.StreamReadUsage = StreamReadUsage; -exports.StringKeyframeTrack = StringKeyframeTrack; -exports.SubtractEquation = SubtractEquation; -exports.SubtractiveBlending = SubtractiveBlending; -exports.TOUCH = TOUCH; -exports.TangentSpaceNormalMap = TangentSpaceNormalMap; -exports.TetrahedronGeometry = TetrahedronGeometry; -exports.Texture = Texture; -exports.TextureLoader = TextureLoader; -exports.TorusGeometry = TorusGeometry; -exports.TorusKnotGeometry = TorusKnotGeometry; -exports.Triangle = Triangle; -exports.TriangleFanDrawMode = TriangleFanDrawMode; -exports.TriangleStripDrawMode = TriangleStripDrawMode; -exports.TrianglesDrawMode = TrianglesDrawMode; -exports.TubeGeometry = TubeGeometry; -exports.UVMapping = UVMapping; -exports.Uint16BufferAttribute = Uint16BufferAttribute; -exports.Uint32BufferAttribute = Uint32BufferAttribute; -exports.Uint8BufferAttribute = Uint8BufferAttribute; -exports.Uint8ClampedBufferAttribute = Uint8ClampedBufferAttribute; -exports.Uniform = Uniform; -exports.UniformsGroup = UniformsGroup; -exports.UniformsLib = UniformsLib; -exports.UniformsUtils = UniformsUtils; -exports.UnsignedByteType = UnsignedByteType; -exports.UnsignedInt248Type = UnsignedInt248Type; -exports.UnsignedIntType = UnsignedIntType; -exports.UnsignedShort4444Type = UnsignedShort4444Type; -exports.UnsignedShort5551Type = UnsignedShort5551Type; -exports.UnsignedShortType = UnsignedShortType; -exports.VSMShadowMap = VSMShadowMap; -exports.Vector2 = Vector2; -exports.Vector3 = Vector3; -exports.Vector4 = Vector4; -exports.VectorKeyframeTrack = VectorKeyframeTrack; -exports.VideoTexture = VideoTexture; -exports.WebGL1Renderer = WebGL1Renderer; -exports.WebGL3DRenderTarget = WebGL3DRenderTarget; -exports.WebGLArrayRenderTarget = WebGLArrayRenderTarget; -exports.WebGLCoordinateSystem = WebGLCoordinateSystem; -exports.WebGLCubeRenderTarget = WebGLCubeRenderTarget; -exports.WebGLMultipleRenderTargets = WebGLMultipleRenderTargets; -exports.WebGLRenderTarget = WebGLRenderTarget; -exports.WebGLRenderer = WebGLRenderer; -exports.WebGLUtils = WebGLUtils; -exports.WebGPUCoordinateSystem = WebGPUCoordinateSystem; -exports.WireframeGeometry = WireframeGeometry; -exports.WrapAroundEnding = WrapAroundEnding; -exports.ZeroCurvatureEnding = ZeroCurvatureEnding; -exports.ZeroFactor = ZeroFactor; -exports.ZeroSlopeEnding = ZeroSlopeEnding; -exports.ZeroStencilOp = ZeroStencilOp; -exports._SRGBAFormat = _SRGBAFormat; -exports.createCanvasElement = createCanvasElement; -//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGhyZWUuY2pzIiwic291cmNlcyI6WyIuLi9zcmMvY29uc3RhbnRzLmpzIiwiLi4vc3JjL2NvcmUvRXZlbnREaXNwYXRjaGVyLmpzIiwiLi4vc3JjL21hdGgvTWF0aFV0aWxzLmpzIiwiLi4vc3JjL21hdGgvVmVjdG9yMi5qcyIsIi4uL3NyYy9tYXRoL01hdHJpeDMuanMiLCIuLi9zcmMvdXRpbHMuanMiLCIuLi9zcmMvbWF0aC9Db2xvck1hbmFnZW1lbnQuanMiLCIuLi9zcmMvZXh0cmFzL0ltYWdlVXRpbHMuanMiLCIuLi9zcmMvdGV4dHVyZXMvU291cmNlLmpzIiwiLi4vc3JjL3RleHR1cmVzL1RleHR1cmUuanMiLCIuLi9zcmMvbWF0aC9WZWN0b3I0LmpzIiwiLi4vc3JjL2NvcmUvUmVuZGVyVGFyZ2V0LmpzIiwiLi4vc3JjL3JlbmRlcmVycy9XZWJHTFJlbmRlclRhcmdldC5qcyIsIi4uL3NyYy90ZXh0dXJlcy9EYXRhQXJyYXlUZXh0dXJlLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9XZWJHTEFycmF5UmVuZGVyVGFyZ2V0LmpzIiwiLi4vc3JjL3RleHR1cmVzL0RhdGEzRFRleHR1cmUuanMiLCIuLi9zcmMvcmVuZGVyZXJzL1dlYkdMM0RSZW5kZXJUYXJnZXQuanMiLCIuLi9zcmMvcmVuZGVyZXJzL1dlYkdMTXVsdGlwbGVSZW5kZXJUYXJnZXRzLmpzIiwiLi4vc3JjL21hdGgvUXVhdGVybmlvbi5qcyIsIi4uL3NyYy9tYXRoL1ZlY3RvcjMuanMiLCIuLi9zcmMvbWF0aC9Cb3gzLmpzIiwiLi4vc3JjL21hdGgvU3BoZXJlLmpzIiwiLi4vc3JjL21hdGgvUmF5LmpzIiwiLi4vc3JjL21hdGgvTWF0cml4NC5qcyIsIi4uL3NyYy9tYXRoL0V1bGVyLmpzIiwiLi4vc3JjL2NvcmUvTGF5ZXJzLmpzIiwiLi4vc3JjL2NvcmUvT2JqZWN0M0QuanMiLCIuLi9zcmMvbWF0aC9UcmlhbmdsZS5qcyIsIi4uL3NyYy9tYXRoL0NvbG9yLmpzIiwiLi4vc3JjL21hdGVyaWFscy9NYXRlcmlhbC5qcyIsIi4uL3NyYy9tYXRlcmlhbHMvTWVzaEJhc2ljTWF0ZXJpYWwuanMiLCIuLi9zcmMvZXh0cmFzL0RhdGFVdGlscy5qcyIsIi4uL3NyYy9jb3JlL0J1ZmZlckF0dHJpYnV0ZS5qcyIsIi4uL3NyYy9jb3JlL0J1ZmZlckdlb21ldHJ5LmpzIiwiLi4vc3JjL29iamVjdHMvTWVzaC5qcyIsIi4uL3NyYy9nZW9tZXRyaWVzL0JveEdlb21ldHJ5LmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1VuaWZvcm1zVXRpbHMuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvZGVmYXVsdF92ZXJ0ZXguZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9kZWZhdWx0X2ZyYWdtZW50Lmdsc2wuanMiLCIuLi9zcmMvbWF0ZXJpYWxzL1NoYWRlck1hdGVyaWFsLmpzIiwiLi4vc3JjL2NhbWVyYXMvQ2FtZXJhLmpzIiwiLi4vc3JjL2NhbWVyYXMvUGVyc3BlY3RpdmVDYW1lcmEuanMiLCIuLi9zcmMvY2FtZXJhcy9DdWJlQ2FtZXJhLmpzIiwiLi4vc3JjL3RleHR1cmVzL0N1YmVUZXh0dXJlLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9XZWJHTEN1YmVSZW5kZXJUYXJnZXQuanMiLCIuLi9zcmMvbWF0aC9QbGFuZS5qcyIsIi4uL3NyYy9tYXRoL0ZydXN0dW0uanMiLCIuLi9zcmMvcmVuZGVyZXJzL3dlYmdsL1dlYkdMQW5pbWF0aW9uLmpzIiwiLi4vc3JjL3JlbmRlcmVycy93ZWJnbC9XZWJHTEF0dHJpYnV0ZXMuanMiLCIuLi9zcmMvZ2VvbWV0cmllcy9QbGFuZUdlb21ldHJ5LmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL2FscGhhaGFzaF9mcmFnbWVudC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL2FscGhhaGFzaF9wYXJzX2ZyYWdtZW50Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvYWxwaGFtYXBfZnJhZ21lbnQuZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9hbHBoYW1hcF9wYXJzX2ZyYWdtZW50Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvYWxwaGF0ZXN0X2ZyYWdtZW50Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvYWxwaGF0ZXN0X3BhcnNfZnJhZ21lbnQuZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9hb21hcF9mcmFnbWVudC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL2FvbWFwX3BhcnNfZnJhZ21lbnQuZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9iYXRjaGluZ19wYXJzX3ZlcnRleC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL2JhdGNoaW5nX3ZlcnRleC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL2JlZ2luX3ZlcnRleC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL2JlZ2lubm9ybWFsX3ZlcnRleC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL2JzZGZzLmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvaXJpZGVzY2VuY2VfZnJhZ21lbnQuZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9idW1wbWFwX3BhcnNfZnJhZ21lbnQuZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9jbGlwcGluZ19wbGFuZXNfZnJhZ21lbnQuZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9jbGlwcGluZ19wbGFuZXNfcGFyc19mcmFnbWVudC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL2NsaXBwaW5nX3BsYW5lc19wYXJzX3ZlcnRleC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL2NsaXBwaW5nX3BsYW5lc192ZXJ0ZXguZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9jb2xvcl9mcmFnbWVudC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL2NvbG9yX3BhcnNfZnJhZ21lbnQuZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9jb2xvcl9wYXJzX3ZlcnRleC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL2NvbG9yX3ZlcnRleC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL2NvbW1vbi5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL2N1YmVfdXZfcmVmbGVjdGlvbl9mcmFnbWVudC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL2RlZmF1bHRub3JtYWxfdmVydGV4Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvZGlzcGxhY2VtZW50bWFwX3BhcnNfdmVydGV4Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvZGlzcGxhY2VtZW50bWFwX3ZlcnRleC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL2VtaXNzaXZlbWFwX2ZyYWdtZW50Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvZW1pc3NpdmVtYXBfcGFyc19mcmFnbWVudC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL2NvbG9yc3BhY2VfZnJhZ21lbnQuZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9jb2xvcnNwYWNlX3BhcnNfZnJhZ21lbnQuZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9lbnZtYXBfZnJhZ21lbnQuZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9lbnZtYXBfY29tbW9uX3BhcnNfZnJhZ21lbnQuZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9lbnZtYXBfcGFyc19mcmFnbWVudC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL2Vudm1hcF9wYXJzX3ZlcnRleC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL2Vudm1hcF92ZXJ0ZXguZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9mb2dfdmVydGV4Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvZm9nX3BhcnNfdmVydGV4Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvZm9nX2ZyYWdtZW50Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvZm9nX3BhcnNfZnJhZ21lbnQuZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9ncmFkaWVudG1hcF9wYXJzX2ZyYWdtZW50Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvbGlnaHRtYXBfZnJhZ21lbnQuZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9saWdodG1hcF9wYXJzX2ZyYWdtZW50Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvbGlnaHRzX2xhbWJlcnRfZnJhZ21lbnQuZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9saWdodHNfbGFtYmVydF9wYXJzX2ZyYWdtZW50Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvbGlnaHRzX3BhcnNfYmVnaW4uZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9lbnZtYXBfcGh5c2ljYWxfcGFyc19mcmFnbWVudC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL2xpZ2h0c190b29uX2ZyYWdtZW50Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvbGlnaHRzX3Rvb25fcGFyc19mcmFnbWVudC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL2xpZ2h0c19waG9uZ19mcmFnbWVudC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL2xpZ2h0c19waG9uZ19wYXJzX2ZyYWdtZW50Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvbGlnaHRzX3BoeXNpY2FsX2ZyYWdtZW50Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvbGlnaHRzX3BoeXNpY2FsX3BhcnNfZnJhZ21lbnQuZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9saWdodHNfZnJhZ21lbnRfYmVnaW4uZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9saWdodHNfZnJhZ21lbnRfbWFwcy5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL2xpZ2h0c19mcmFnbWVudF9lbmQuZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9sb2dkZXB0aGJ1Zl9mcmFnbWVudC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL2xvZ2RlcHRoYnVmX3BhcnNfZnJhZ21lbnQuZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9sb2dkZXB0aGJ1Zl9wYXJzX3ZlcnRleC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL2xvZ2RlcHRoYnVmX3ZlcnRleC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL21hcF9mcmFnbWVudC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL21hcF9wYXJzX2ZyYWdtZW50Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvbWFwX3BhcnRpY2xlX2ZyYWdtZW50Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvbWFwX3BhcnRpY2xlX3BhcnNfZnJhZ21lbnQuZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9tZXRhbG5lc3NtYXBfZnJhZ21lbnQuZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9tZXRhbG5lc3NtYXBfcGFyc19mcmFnbWVudC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL21vcnBoY29sb3JfdmVydGV4Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvbW9ycGhub3JtYWxfdmVydGV4Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvbW9ycGh0YXJnZXRfcGFyc192ZXJ0ZXguZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9tb3JwaHRhcmdldF92ZXJ0ZXguZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9ub3JtYWxfZnJhZ21lbnRfYmVnaW4uZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9ub3JtYWxfZnJhZ21lbnRfbWFwcy5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL25vcm1hbF9wYXJzX2ZyYWdtZW50Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvbm9ybWFsX3BhcnNfdmVydGV4Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvbm9ybWFsX3ZlcnRleC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL25vcm1hbG1hcF9wYXJzX2ZyYWdtZW50Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvY2xlYXJjb2F0X25vcm1hbF9mcmFnbWVudF9iZWdpbi5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL2NsZWFyY29hdF9ub3JtYWxfZnJhZ21lbnRfbWFwcy5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL2NsZWFyY29hdF9wYXJzX2ZyYWdtZW50Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvaXJpZGVzY2VuY2VfcGFyc19mcmFnbWVudC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL29wYXF1ZV9mcmFnbWVudC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL3BhY2tpbmcuZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9wcmVtdWx0aXBsaWVkX2FscGhhX2ZyYWdtZW50Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvcHJvamVjdF92ZXJ0ZXguZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9kaXRoZXJpbmdfZnJhZ21lbnQuZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9kaXRoZXJpbmdfcGFyc19mcmFnbWVudC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL3JvdWdobmVzc21hcF9mcmFnbWVudC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL3JvdWdobmVzc21hcF9wYXJzX2ZyYWdtZW50Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvc2hhZG93bWFwX3BhcnNfZnJhZ21lbnQuZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9zaGFkb3dtYXBfcGFyc192ZXJ0ZXguZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9zaGFkb3dtYXBfdmVydGV4Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvc2hhZG93bWFza19wYXJzX2ZyYWdtZW50Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvc2tpbmJhc2VfdmVydGV4Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvc2tpbm5pbmdfcGFyc192ZXJ0ZXguZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9za2lubmluZ192ZXJ0ZXguZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9za2lubm9ybWFsX3ZlcnRleC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL3NwZWN1bGFybWFwX2ZyYWdtZW50Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvc3BlY3VsYXJtYXBfcGFyc19mcmFnbWVudC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL3RvbmVtYXBwaW5nX2ZyYWdtZW50Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvdG9uZW1hcHBpbmdfcGFyc19mcmFnbWVudC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL3RyYW5zbWlzc2lvbl9mcmFnbWVudC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL3RyYW5zbWlzc2lvbl9wYXJzX2ZyYWdtZW50Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvdXZfcGFyc19mcmFnbWVudC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL3V2X3BhcnNfdmVydGV4Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvdXZfdmVydGV4Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvd29ybGRwb3NfdmVydGV4Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyTGliL2JhY2tncm91bmQuZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJMaWIvYmFja2dyb3VuZEN1YmUuZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJMaWIvY3ViZS5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckxpYi9kZXB0aC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckxpYi9kaXN0YW5jZVJHQkEuZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJMaWIvZXF1aXJlY3QuZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJMaWIvbGluZWRhc2hlZC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckxpYi9tZXNoYmFzaWMuZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJMaWIvbWVzaGxhbWJlcnQuZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJMaWIvbWVzaG1hdGNhcC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckxpYi9tZXNobm9ybWFsLmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyTGliL21lc2hwaG9uZy5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckxpYi9tZXNocGh5c2ljYWwuZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJMaWIvbWVzaHRvb24uZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJMaWIvcG9pbnRzLmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyTGliL3NoYWRvdy5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckxpYi9zcHJpdGUuZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9Vbmlmb3Jtc0xpYi5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJMaWIuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3dlYmdsL1dlYkdMQmFja2dyb3VuZC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvd2ViZ2wvV2ViR0xCaW5kaW5nU3RhdGVzLmpzIiwiLi4vc3JjL3JlbmRlcmVycy93ZWJnbC9XZWJHTEJ1ZmZlclJlbmRlcmVyLmpzIiwiLi4vc3JjL3JlbmRlcmVycy93ZWJnbC9XZWJHTENhcGFiaWxpdGllcy5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvd2ViZ2wvV2ViR0xDbGlwcGluZy5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvd2ViZ2wvV2ViR0xDdWJlTWFwcy5qcyIsIi4uL3NyYy9jYW1lcmFzL09ydGhvZ3JhcGhpY0NhbWVyYS5qcyIsIi4uL3NyYy9leHRyYXMvUE1SRU1HZW5lcmF0b3IuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3dlYmdsL1dlYkdMQ3ViZVVWTWFwcy5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvd2ViZ2wvV2ViR0xFeHRlbnNpb25zLmpzIiwiLi4vc3JjL3JlbmRlcmVycy93ZWJnbC9XZWJHTEdlb21ldHJpZXMuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3dlYmdsL1dlYkdMSW5kZXhlZEJ1ZmZlclJlbmRlcmVyLmpzIiwiLi4vc3JjL3JlbmRlcmVycy93ZWJnbC9XZWJHTEluZm8uanMiLCIuLi9zcmMvcmVuZGVyZXJzL3dlYmdsL1dlYkdMTW9ycGh0YXJnZXRzLmpzIiwiLi4vc3JjL3JlbmRlcmVycy93ZWJnbC9XZWJHTE9iamVjdHMuanMiLCIuLi9zcmMvdGV4dHVyZXMvRGVwdGhUZXh0dXJlLmpzIiwiLi4vc3JjL3JlbmRlcmVycy93ZWJnbC9XZWJHTFVuaWZvcm1zLmpzIiwiLi4vc3JjL3JlbmRlcmVycy93ZWJnbC9XZWJHTFNoYWRlci5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvd2ViZ2wvV2ViR0xQcm9ncmFtLmpzIiwiLi4vc3JjL3JlbmRlcmVycy93ZWJnbC9XZWJHTFNoYWRlckNhY2hlLmpzIiwiLi4vc3JjL3JlbmRlcmVycy93ZWJnbC9XZWJHTFByb2dyYW1zLmpzIiwiLi4vc3JjL3JlbmRlcmVycy93ZWJnbC9XZWJHTFByb3BlcnRpZXMuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3dlYmdsL1dlYkdMUmVuZGVyTGlzdHMuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3dlYmdsL1dlYkdMTGlnaHRzLmpzIiwiLi4vc3JjL3JlbmRlcmVycy93ZWJnbC9XZWJHTFJlbmRlclN0YXRlcy5qcyIsIi4uL3NyYy9tYXRlcmlhbHMvTWVzaERlcHRoTWF0ZXJpYWwuanMiLCIuLi9zcmMvbWF0ZXJpYWxzL01lc2hEaXN0YW5jZU1hdGVyaWFsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckxpYi92c20uZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvd2ViZ2wvV2ViR0xTaGFkb3dNYXAuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3dlYmdsL1dlYkdMU3RhdGUuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3dlYmdsL1dlYkdMVGV4dHVyZXMuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3dlYmdsL1dlYkdMVXRpbHMuanMiLCIuLi9zcmMvY2FtZXJhcy9BcnJheUNhbWVyYS5qcyIsIi4uL3NyYy9vYmplY3RzL0dyb3VwLmpzIiwiLi4vc3JjL3JlbmRlcmVycy93ZWJ4ci9XZWJYUkNvbnRyb2xsZXIuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3dlYnhyL1dlYlhSRGVwdGhTZW5zaW5nLmpzIiwiLi4vc3JjL3JlbmRlcmVycy93ZWJ4ci9XZWJYUk1hbmFnZXIuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3dlYmdsL1dlYkdMTWF0ZXJpYWxzLmpzIiwiLi4vc3JjL3JlbmRlcmVycy93ZWJnbC9XZWJHTFVuaWZvcm1zR3JvdXBzLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9XZWJHTFJlbmRlcmVyLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9XZWJHTDFSZW5kZXJlci5qcyIsIi4uL3NyYy9zY2VuZXMvRm9nRXhwMi5qcyIsIi4uL3NyYy9zY2VuZXMvRm9nLmpzIiwiLi4vc3JjL3NjZW5lcy9TY2VuZS5qcyIsIi4uL3NyYy9jb3JlL0ludGVybGVhdmVkQnVmZmVyLmpzIiwiLi4vc3JjL2NvcmUvSW50ZXJsZWF2ZWRCdWZmZXJBdHRyaWJ1dGUuanMiLCIuLi9zcmMvbWF0ZXJpYWxzL1Nwcml0ZU1hdGVyaWFsLmpzIiwiLi4vc3JjL29iamVjdHMvU3ByaXRlLmpzIiwiLi4vc3JjL29iamVjdHMvTE9ELmpzIiwiLi4vc3JjL29iamVjdHMvU2tpbm5lZE1lc2guanMiLCIuLi9zcmMvb2JqZWN0cy9Cb25lLmpzIiwiLi4vc3JjL3RleHR1cmVzL0RhdGFUZXh0dXJlLmpzIiwiLi4vc3JjL29iamVjdHMvU2tlbGV0b24uanMiLCIuLi9zcmMvY29yZS9JbnN0YW5jZWRCdWZmZXJBdHRyaWJ1dGUuanMiLCIuLi9zcmMvb2JqZWN0cy9JbnN0YW5jZWRNZXNoLmpzIiwiLi4vc3JjL29iamVjdHMvQmF0Y2hlZE1lc2guanMiLCIuLi9zcmMvbWF0ZXJpYWxzL0xpbmVCYXNpY01hdGVyaWFsLmpzIiwiLi4vc3JjL29iamVjdHMvTGluZS5qcyIsIi4uL3NyYy9vYmplY3RzL0xpbmVTZWdtZW50cy5qcyIsIi4uL3NyYy9vYmplY3RzL0xpbmVMb29wLmpzIiwiLi4vc3JjL21hdGVyaWFscy9Qb2ludHNNYXRlcmlhbC5qcyIsIi4uL3NyYy9vYmplY3RzL1BvaW50cy5qcyIsIi4uL3NyYy90ZXh0dXJlcy9WaWRlb1RleHR1cmUuanMiLCIuLi9zcmMvdGV4dHVyZXMvRnJhbWVidWZmZXJUZXh0dXJlLmpzIiwiLi4vc3JjL3RleHR1cmVzL0NvbXByZXNzZWRUZXh0dXJlLmpzIiwiLi4vc3JjL3RleHR1cmVzL0NvbXByZXNzZWRBcnJheVRleHR1cmUuanMiLCIuLi9zcmMvdGV4dHVyZXMvQ29tcHJlc3NlZEN1YmVUZXh0dXJlLmpzIiwiLi4vc3JjL3RleHR1cmVzL0NhbnZhc1RleHR1cmUuanMiLCIuLi9zcmMvZXh0cmFzL2NvcmUvQ3VydmUuanMiLCIuLi9zcmMvZXh0cmFzL2N1cnZlcy9FbGxpcHNlQ3VydmUuanMiLCIuLi9zcmMvZXh0cmFzL2N1cnZlcy9BcmNDdXJ2ZS5qcyIsIi4uL3NyYy9leHRyYXMvY3VydmVzL0NhdG11bGxSb21DdXJ2ZTMuanMiLCIuLi9zcmMvZXh0cmFzL2NvcmUvSW50ZXJwb2xhdGlvbnMuanMiLCIuLi9zcmMvZXh0cmFzL2N1cnZlcy9DdWJpY0JlemllckN1cnZlLmpzIiwiLi4vc3JjL2V4dHJhcy9jdXJ2ZXMvQ3ViaWNCZXppZXJDdXJ2ZTMuanMiLCIuLi9zcmMvZXh0cmFzL2N1cnZlcy9MaW5lQ3VydmUuanMiLCIuLi9zcmMvZXh0cmFzL2N1cnZlcy9MaW5lQ3VydmUzLmpzIiwiLi4vc3JjL2V4dHJhcy9jdXJ2ZXMvUXVhZHJhdGljQmV6aWVyQ3VydmUuanMiLCIuLi9zcmMvZXh0cmFzL2N1cnZlcy9RdWFkcmF0aWNCZXppZXJDdXJ2ZTMuanMiLCIuLi9zcmMvZXh0cmFzL2N1cnZlcy9TcGxpbmVDdXJ2ZS5qcyIsIi4uL3NyYy9leHRyYXMvY29yZS9DdXJ2ZVBhdGguanMiLCIuLi9zcmMvZXh0cmFzL2NvcmUvUGF0aC5qcyIsIi4uL3NyYy9nZW9tZXRyaWVzL0xhdGhlR2VvbWV0cnkuanMiLCIuLi9zcmMvZ2VvbWV0cmllcy9DYXBzdWxlR2VvbWV0cnkuanMiLCIuLi9zcmMvZ2VvbWV0cmllcy9DaXJjbGVHZW9tZXRyeS5qcyIsIi4uL3NyYy9nZW9tZXRyaWVzL0N5bGluZGVyR2VvbWV0cnkuanMiLCIuLi9zcmMvZ2VvbWV0cmllcy9Db25lR2VvbWV0cnkuanMiLCIuLi9zcmMvZ2VvbWV0cmllcy9Qb2x5aGVkcm9uR2VvbWV0cnkuanMiLCIuLi9zcmMvZ2VvbWV0cmllcy9Eb2RlY2FoZWRyb25HZW9tZXRyeS5qcyIsIi4uL3NyYy9nZW9tZXRyaWVzL0VkZ2VzR2VvbWV0cnkuanMiLCIuLi9zcmMvZXh0cmFzL2NvcmUvU2hhcGUuanMiLCIuLi9zcmMvZXh0cmFzL0VhcmN1dC5qcyIsIi4uL3NyYy9leHRyYXMvU2hhcGVVdGlscy5qcyIsIi4uL3NyYy9nZW9tZXRyaWVzL0V4dHJ1ZGVHZW9tZXRyeS5qcyIsIi4uL3NyYy9nZW9tZXRyaWVzL0ljb3NhaGVkcm9uR2VvbWV0cnkuanMiLCIuLi9zcmMvZ2VvbWV0cmllcy9PY3RhaGVkcm9uR2VvbWV0cnkuanMiLCIuLi9zcmMvZ2VvbWV0cmllcy9SaW5nR2VvbWV0cnkuanMiLCIuLi9zcmMvZ2VvbWV0cmllcy9TaGFwZUdlb21ldHJ5LmpzIiwiLi4vc3JjL2dlb21ldHJpZXMvU3BoZXJlR2VvbWV0cnkuanMiLCIuLi9zcmMvZ2VvbWV0cmllcy9UZXRyYWhlZHJvbkdlb21ldHJ5LmpzIiwiLi4vc3JjL2dlb21ldHJpZXMvVG9ydXNHZW9tZXRyeS5qcyIsIi4uL3NyYy9nZW9tZXRyaWVzL1RvcnVzS25vdEdlb21ldHJ5LmpzIiwiLi4vc3JjL2dlb21ldHJpZXMvVHViZUdlb21ldHJ5LmpzIiwiLi4vc3JjL2dlb21ldHJpZXMvV2lyZWZyYW1lR2VvbWV0cnkuanMiLCIuLi9zcmMvbWF0ZXJpYWxzL1NoYWRvd01hdGVyaWFsLmpzIiwiLi4vc3JjL21hdGVyaWFscy9SYXdTaGFkZXJNYXRlcmlhbC5qcyIsIi4uL3NyYy9tYXRlcmlhbHMvTWVzaFN0YW5kYXJkTWF0ZXJpYWwuanMiLCIuLi9zcmMvbWF0ZXJpYWxzL01lc2hQaHlzaWNhbE1hdGVyaWFsLmpzIiwiLi4vc3JjL21hdGVyaWFscy9NZXNoUGhvbmdNYXRlcmlhbC5qcyIsIi4uL3NyYy9tYXRlcmlhbHMvTWVzaFRvb25NYXRlcmlhbC5qcyIsIi4uL3NyYy9tYXRlcmlhbHMvTWVzaE5vcm1hbE1hdGVyaWFsLmpzIiwiLi4vc3JjL21hdGVyaWFscy9NZXNoTGFtYmVydE1hdGVyaWFsLmpzIiwiLi4vc3JjL21hdGVyaWFscy9NZXNoTWF0Y2FwTWF0ZXJpYWwuanMiLCIuLi9zcmMvbWF0ZXJpYWxzL0xpbmVEYXNoZWRNYXRlcmlhbC5qcyIsIi4uL3NyYy9hbmltYXRpb24vQW5pbWF0aW9uVXRpbHMuanMiLCIuLi9zcmMvbWF0aC9JbnRlcnBvbGFudC5qcyIsIi4uL3NyYy9tYXRoL2ludGVycG9sYW50cy9DdWJpY0ludGVycG9sYW50LmpzIiwiLi4vc3JjL21hdGgvaW50ZXJwb2xhbnRzL0xpbmVhckludGVycG9sYW50LmpzIiwiLi4vc3JjL21hdGgvaW50ZXJwb2xhbnRzL0Rpc2NyZXRlSW50ZXJwb2xhbnQuanMiLCIuLi9zcmMvYW5pbWF0aW9uL0tleWZyYW1lVHJhY2suanMiLCIuLi9zcmMvYW5pbWF0aW9uL3RyYWNrcy9Cb29sZWFuS2V5ZnJhbWVUcmFjay5qcyIsIi4uL3NyYy9hbmltYXRpb24vdHJhY2tzL0NvbG9yS2V5ZnJhbWVUcmFjay5qcyIsIi4uL3NyYy9hbmltYXRpb24vdHJhY2tzL051bWJlcktleWZyYW1lVHJhY2suanMiLCIuLi9zcmMvbWF0aC9pbnRlcnBvbGFudHMvUXVhdGVybmlvbkxpbmVhckludGVycG9sYW50LmpzIiwiLi4vc3JjL2FuaW1hdGlvbi90cmFja3MvUXVhdGVybmlvbktleWZyYW1lVHJhY2suanMiLCIuLi9zcmMvYW5pbWF0aW9uL3RyYWNrcy9TdHJpbmdLZXlmcmFtZVRyYWNrLmpzIiwiLi4vc3JjL2FuaW1hdGlvbi90cmFja3MvVmVjdG9yS2V5ZnJhbWVUcmFjay5qcyIsIi4uL3NyYy9hbmltYXRpb24vQW5pbWF0aW9uQ2xpcC5qcyIsIi4uL3NyYy9sb2FkZXJzL0NhY2hlLmpzIiwiLi4vc3JjL2xvYWRlcnMvTG9hZGluZ01hbmFnZXIuanMiLCIuLi9zcmMvbG9hZGVycy9Mb2FkZXIuanMiLCIuLi9zcmMvbG9hZGVycy9GaWxlTG9hZGVyLmpzIiwiLi4vc3JjL2xvYWRlcnMvQW5pbWF0aW9uTG9hZGVyLmpzIiwiLi4vc3JjL2xvYWRlcnMvQ29tcHJlc3NlZFRleHR1cmVMb2FkZXIuanMiLCIuLi9zcmMvbG9hZGVycy9JbWFnZUxvYWRlci5qcyIsIi4uL3NyYy9sb2FkZXJzL0N1YmVUZXh0dXJlTG9hZGVyLmpzIiwiLi4vc3JjL2xvYWRlcnMvRGF0YVRleHR1cmVMb2FkZXIuanMiLCIuLi9zcmMvbG9hZGVycy9UZXh0dXJlTG9hZGVyLmpzIiwiLi4vc3JjL2xpZ2h0cy9MaWdodC5qcyIsIi4uL3NyYy9saWdodHMvSGVtaXNwaGVyZUxpZ2h0LmpzIiwiLi4vc3JjL2xpZ2h0cy9MaWdodFNoYWRvdy5qcyIsIi4uL3NyYy9saWdodHMvU3BvdExpZ2h0U2hhZG93LmpzIiwiLi4vc3JjL2xpZ2h0cy9TcG90TGlnaHQuanMiLCIuLi9zcmMvbGlnaHRzL1BvaW50TGlnaHRTaGFkb3cuanMiLCIuLi9zcmMvbGlnaHRzL1BvaW50TGlnaHQuanMiLCIuLi9zcmMvbGlnaHRzL0RpcmVjdGlvbmFsTGlnaHRTaGFkb3cuanMiLCIuLi9zcmMvbGlnaHRzL0RpcmVjdGlvbmFsTGlnaHQuanMiLCIuLi9zcmMvbGlnaHRzL0FtYmllbnRMaWdodC5qcyIsIi4uL3NyYy9saWdodHMvUmVjdEFyZWFMaWdodC5qcyIsIi4uL3NyYy9tYXRoL1NwaGVyaWNhbEhhcm1vbmljczMuanMiLCIuLi9zcmMvbGlnaHRzL0xpZ2h0UHJvYmUuanMiLCIuLi9zcmMvbG9hZGVycy9NYXRlcmlhbExvYWRlci5qcyIsIi4uL3NyYy9sb2FkZXJzL0xvYWRlclV0aWxzLmpzIiwiLi4vc3JjL2NvcmUvSW5zdGFuY2VkQnVmZmVyR2VvbWV0cnkuanMiLCIuLi9zcmMvbG9hZGVycy9CdWZmZXJHZW9tZXRyeUxvYWRlci5qcyIsIi4uL3NyYy9sb2FkZXJzL09iamVjdExvYWRlci5qcyIsIi4uL3NyYy9sb2FkZXJzL0ltYWdlQml0bWFwTG9hZGVyLmpzIiwiLi4vc3JjL2F1ZGlvL0F1ZGlvQ29udGV4dC5qcyIsIi4uL3NyYy9sb2FkZXJzL0F1ZGlvTG9hZGVyLmpzIiwiLi4vc3JjL2NhbWVyYXMvU3RlcmVvQ2FtZXJhLmpzIiwiLi4vc3JjL2NvcmUvQ2xvY2suanMiLCIuLi9zcmMvYXVkaW8vQXVkaW9MaXN0ZW5lci5qcyIsIi4uL3NyYy9hdWRpby9BdWRpby5qcyIsIi4uL3NyYy9hdWRpby9Qb3NpdGlvbmFsQXVkaW8uanMiLCIuLi9zcmMvYXVkaW8vQXVkaW9BbmFseXNlci5qcyIsIi4uL3NyYy9hbmltYXRpb24vUHJvcGVydHlNaXhlci5qcyIsIi4uL3NyYy9hbmltYXRpb24vUHJvcGVydHlCaW5kaW5nLmpzIiwiLi4vc3JjL2FuaW1hdGlvbi9BbmltYXRpb25PYmplY3RHcm91cC5qcyIsIi4uL3NyYy9hbmltYXRpb24vQW5pbWF0aW9uQWN0aW9uLmpzIiwiLi4vc3JjL2FuaW1hdGlvbi9BbmltYXRpb25NaXhlci5qcyIsIi4uL3NyYy9jb3JlL1VuaWZvcm0uanMiLCIuLi9zcmMvY29yZS9Vbmlmb3Jtc0dyb3VwLmpzIiwiLi4vc3JjL2NvcmUvSW5zdGFuY2VkSW50ZXJsZWF2ZWRCdWZmZXIuanMiLCIuLi9zcmMvY29yZS9HTEJ1ZmZlckF0dHJpYnV0ZS5qcyIsIi4uL3NyYy9jb3JlL1JheWNhc3Rlci5qcyIsIi4uL3NyYy9tYXRoL1NwaGVyaWNhbC5qcyIsIi4uL3NyYy9tYXRoL0N5bGluZHJpY2FsLmpzIiwiLi4vc3JjL21hdGgvQm94Mi5qcyIsIi4uL3NyYy9tYXRoL0xpbmUzLmpzIiwiLi4vc3JjL2hlbHBlcnMvU3BvdExpZ2h0SGVscGVyLmpzIiwiLi4vc3JjL2hlbHBlcnMvU2tlbGV0b25IZWxwZXIuanMiLCIuLi9zcmMvaGVscGVycy9Qb2ludExpZ2h0SGVscGVyLmpzIiwiLi4vc3JjL2hlbHBlcnMvSGVtaXNwaGVyZUxpZ2h0SGVscGVyLmpzIiwiLi4vc3JjL2hlbHBlcnMvR3JpZEhlbHBlci5qcyIsIi4uL3NyYy9oZWxwZXJzL1BvbGFyR3JpZEhlbHBlci5qcyIsIi4uL3NyYy9oZWxwZXJzL0RpcmVjdGlvbmFsTGlnaHRIZWxwZXIuanMiLCIuLi9zcmMvaGVscGVycy9DYW1lcmFIZWxwZXIuanMiLCIuLi9zcmMvaGVscGVycy9Cb3hIZWxwZXIuanMiLCIuLi9zcmMvaGVscGVycy9Cb3gzSGVscGVyLmpzIiwiLi4vc3JjL2hlbHBlcnMvUGxhbmVIZWxwZXIuanMiLCIuLi9zcmMvaGVscGVycy9BcnJvd0hlbHBlci5qcyIsIi4uL3NyYy9oZWxwZXJzL0F4ZXNIZWxwZXIuanMiLCIuLi9zcmMvZXh0cmFzL2NvcmUvU2hhcGVQYXRoLmpzIiwiLi4vc3JjL1RocmVlLmpzIl0sInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCBjb25zdCBSRVZJU0lPTiA9ICcxNjJkZXYnO1xyXG5cclxuZXhwb3J0IGNvbnN0IE1PVVNFID0geyBMRUZUOiAwLCBNSURETEU6IDEsIFJJR0hUOiAyLCBST1RBVEU6IDAsIERPTExZOiAxLCBQQU46IDIgfTtcclxuZXhwb3J0IGNvbnN0IFRPVUNIID0geyBST1RBVEU6IDAsIFBBTjogMSwgRE9MTFlfUEFOOiAyLCBET0xMWV9ST1RBVEU6IDMgfTtcclxuZXhwb3J0IGNvbnN0IEN1bGxGYWNlTm9uZSA9IDA7XHJcbmV4cG9ydCBjb25zdCBDdWxsRmFjZUJhY2sgPSAxO1xyXG5leHBvcnQgY29uc3QgQ3VsbEZhY2VGcm9udCA9IDI7XHJcbmV4cG9ydCBjb25zdCBDdWxsRmFjZUZyb250QmFjayA9IDM7XHJcbmV4cG9ydCBjb25zdCBCYXNpY1NoYWRvd01hcCA9IDA7XHJcbmV4cG9ydCBjb25zdCBQQ0ZTaGFkb3dNYXAgPSAxO1xyXG5leHBvcnQgY29uc3QgUENGU29mdFNoYWRvd01hcCA9IDI7XHJcbmV4cG9ydCBjb25zdCBWU01TaGFkb3dNYXAgPSAzO1xyXG5leHBvcnQgY29uc3QgRnJvbnRTaWRlID0gMDtcclxuZXhwb3J0IGNvbnN0IEJhY2tTaWRlID0gMTtcclxuZXhwb3J0IGNvbnN0IERvdWJsZVNpZGUgPSAyO1xyXG5leHBvcnQgY29uc3QgTm9CbGVuZGluZyA9IDA7XHJcbmV4cG9ydCBjb25zdCBOb3JtYWxCbGVuZGluZyA9IDE7XHJcbmV4cG9ydCBjb25zdCBBZGRpdGl2ZUJsZW5kaW5nID0gMjtcclxuZXhwb3J0IGNvbnN0IFN1YnRyYWN0aXZlQmxlbmRpbmcgPSAzO1xyXG5leHBvcnQgY29uc3QgTXVsdGlwbHlCbGVuZGluZyA9IDQ7XHJcbmV4cG9ydCBjb25zdCBDdXN0b21CbGVuZGluZyA9IDU7XHJcbmV4cG9ydCBjb25zdCBBZGRFcXVhdGlvbiA9IDEwMDtcclxuZXhwb3J0IGNvbnN0IFN1YnRyYWN0RXF1YXRpb24gPSAxMDE7XHJcbmV4cG9ydCBjb25zdCBSZXZlcnNlU3VidHJhY3RFcXVhdGlvbiA9IDEwMjtcclxuZXhwb3J0IGNvbnN0IE1pbkVxdWF0aW9uID0gMTAzO1xyXG5leHBvcnQgY29uc3QgTWF4RXF1YXRpb24gPSAxMDQ7XHJcbmV4cG9ydCBjb25zdCBaZXJvRmFjdG9yID0gMjAwO1xyXG5leHBvcnQgY29uc3QgT25lRmFjdG9yID0gMjAxO1xyXG5leHBvcnQgY29uc3QgU3JjQ29sb3JGYWN0b3IgPSAyMDI7XHJcbmV4cG9ydCBjb25zdCBPbmVNaW51c1NyY0NvbG9yRmFjdG9yID0gMjAzO1xyXG5leHBvcnQgY29uc3QgU3JjQWxwaGFGYWN0b3IgPSAyMDQ7XHJcbmV4cG9ydCBjb25zdCBPbmVNaW51c1NyY0FscGhhRmFjdG9yID0gMjA1O1xyXG5leHBvcnQgY29uc3QgRHN0QWxwaGFGYWN0b3IgPSAyMDY7XHJcbmV4cG9ydCBjb25zdCBPbmVNaW51c0RzdEFscGhhRmFjdG9yID0gMjA3O1xyXG5leHBvcnQgY29uc3QgRHN0Q29sb3JGYWN0b3IgPSAyMDg7XHJcbmV4cG9ydCBjb25zdCBPbmVNaW51c0RzdENvbG9yRmFjdG9yID0gMjA5O1xyXG5leHBvcnQgY29uc3QgU3JjQWxwaGFTYXR1cmF0ZUZhY3RvciA9IDIxMDtcclxuZXhwb3J0IGNvbnN0IENvbnN0YW50Q29sb3JGYWN0b3IgPSAyMTE7XHJcbmV4cG9ydCBjb25zdCBPbmVNaW51c0NvbnN0YW50Q29sb3JGYWN0b3IgPSAyMTI7XHJcbmV4cG9ydCBjb25zdCBDb25zdGFudEFscGhhRmFjdG9yID0gMjEzO1xyXG5leHBvcnQgY29uc3QgT25lTWludXNDb25zdGFudEFscGhhRmFjdG9yID0gMjE0O1xyXG5leHBvcnQgY29uc3QgTmV2ZXJEZXB0aCA9IDA7XHJcbmV4cG9ydCBjb25zdCBBbHdheXNEZXB0aCA9IDE7XHJcbmV4cG9ydCBjb25zdCBMZXNzRGVwdGggPSAyO1xyXG5leHBvcnQgY29uc3QgTGVzc0VxdWFsRGVwdGggPSAzO1xyXG5leHBvcnQgY29uc3QgRXF1YWxEZXB0aCA9IDQ7XHJcbmV4cG9ydCBjb25zdCBHcmVhdGVyRXF1YWxEZXB0aCA9IDU7XHJcbmV4cG9ydCBjb25zdCBHcmVhdGVyRGVwdGggPSA2O1xyXG5leHBvcnQgY29uc3QgTm90RXF1YWxEZXB0aCA9IDc7XHJcbmV4cG9ydCBjb25zdCBNdWx0aXBseU9wZXJhdGlvbiA9IDA7XHJcbmV4cG9ydCBjb25zdCBNaXhPcGVyYXRpb24gPSAxO1xyXG5leHBvcnQgY29uc3QgQWRkT3BlcmF0aW9uID0gMjtcclxuZXhwb3J0IGNvbnN0IE5vVG9uZU1hcHBpbmcgPSAwO1xyXG5leHBvcnQgY29uc3QgTGluZWFyVG9uZU1hcHBpbmcgPSAxO1xyXG5leHBvcnQgY29uc3QgUmVpbmhhcmRUb25lTWFwcGluZyA9IDI7XHJcbmV4cG9ydCBjb25zdCBDaW5lb25Ub25lTWFwcGluZyA9IDM7XHJcbmV4cG9ydCBjb25zdCBBQ0VTRmlsbWljVG9uZU1hcHBpbmcgPSA0O1xyXG5leHBvcnQgY29uc3QgQ3VzdG9tVG9uZU1hcHBpbmcgPSA1O1xyXG5leHBvcnQgY29uc3QgQWdYVG9uZU1hcHBpbmcgPSA2O1xyXG5leHBvcnQgY29uc3QgQXR0YWNoZWRCaW5kTW9kZSA9ICdhdHRhY2hlZCc7XHJcbmV4cG9ydCBjb25zdCBEZXRhY2hlZEJpbmRNb2RlID0gJ2RldGFjaGVkJztcclxuXHJcbmV4cG9ydCBjb25zdCBVVk1hcHBpbmcgPSAzMDA7XHJcbmV4cG9ydCBjb25zdCBDdWJlUmVmbGVjdGlvbk1hcHBpbmcgPSAzMDE7XHJcbmV4cG9ydCBjb25zdCBDdWJlUmVmcmFjdGlvbk1hcHBpbmcgPSAzMDI7XHJcbmV4cG9ydCBjb25zdCBFcXVpcmVjdGFuZ3VsYXJSZWZsZWN0aW9uTWFwcGluZyA9IDMwMztcclxuZXhwb3J0IGNvbnN0IEVxdWlyZWN0YW5ndWxhclJlZnJhY3Rpb25NYXBwaW5nID0gMzA0O1xyXG5leHBvcnQgY29uc3QgQ3ViZVVWUmVmbGVjdGlvbk1hcHBpbmcgPSAzMDY7XHJcbmV4cG9ydCBjb25zdCBSZXBlYXRXcmFwcGluZyA9IDEwMDA7XHJcbmV4cG9ydCBjb25zdCBDbGFtcFRvRWRnZVdyYXBwaW5nID0gMTAwMTtcclxuZXhwb3J0IGNvbnN0IE1pcnJvcmVkUmVwZWF0V3JhcHBpbmcgPSAxMDAyO1xyXG5leHBvcnQgY29uc3QgTmVhcmVzdEZpbHRlciA9IDEwMDM7XHJcbmV4cG9ydCBjb25zdCBOZWFyZXN0TWlwbWFwTmVhcmVzdEZpbHRlciA9IDEwMDQ7XHJcbmV4cG9ydCBjb25zdCBOZWFyZXN0TWlwTWFwTmVhcmVzdEZpbHRlciA9IDEwMDQ7XHJcbmV4cG9ydCBjb25zdCBOZWFyZXN0TWlwbWFwTGluZWFyRmlsdGVyID0gMTAwNTtcclxuZXhwb3J0IGNvbnN0IE5lYXJlc3RNaXBNYXBMaW5lYXJGaWx0ZXIgPSAxMDA1O1xyXG5leHBvcnQgY29uc3QgTGluZWFyRmlsdGVyID0gMTAwNjtcclxuZXhwb3J0IGNvbnN0IExpbmVhck1pcG1hcE5lYXJlc3RGaWx0ZXIgPSAxMDA3O1xyXG5leHBvcnQgY29uc3QgTGluZWFyTWlwTWFwTmVhcmVzdEZpbHRlciA9IDEwMDc7XHJcbmV4cG9ydCBjb25zdCBMaW5lYXJNaXBtYXBMaW5lYXJGaWx0ZXIgPSAxMDA4O1xyXG5leHBvcnQgY29uc3QgTGluZWFyTWlwTWFwTGluZWFyRmlsdGVyID0gMTAwODtcclxuZXhwb3J0IGNvbnN0IFVuc2lnbmVkQnl0ZVR5cGUgPSAxMDA5O1xyXG5leHBvcnQgY29uc3QgQnl0ZVR5cGUgPSAxMDEwO1xyXG5leHBvcnQgY29uc3QgU2hvcnRUeXBlID0gMTAxMTtcclxuZXhwb3J0IGNvbnN0IFVuc2lnbmVkU2hvcnRUeXBlID0gMTAxMjtcclxuZXhwb3J0IGNvbnN0IEludFR5cGUgPSAxMDEzO1xyXG5leHBvcnQgY29uc3QgVW5zaWduZWRJbnRUeXBlID0gMTAxNDtcclxuZXhwb3J0IGNvbnN0IEZsb2F0VHlwZSA9IDEwMTU7XHJcbmV4cG9ydCBjb25zdCBIYWxmRmxvYXRUeXBlID0gMTAxNjtcclxuZXhwb3J0IGNvbnN0IFVuc2lnbmVkU2hvcnQ0NDQ0VHlwZSA9IDEwMTc7XHJcbmV4cG9ydCBjb25zdCBVbnNpZ25lZFNob3J0NTU1MVR5cGUgPSAxMDE4O1xyXG5leHBvcnQgY29uc3QgVW5zaWduZWRJbnQyNDhUeXBlID0gMTAyMDtcclxuZXhwb3J0IGNvbnN0IEFscGhhRm9ybWF0ID0gMTAyMTtcclxuZXhwb3J0IGNvbnN0IFJHQkFGb3JtYXQgPSAxMDIzO1xyXG5leHBvcnQgY29uc3QgTHVtaW5hbmNlRm9ybWF0ID0gMTAyNDtcclxuZXhwb3J0IGNvbnN0IEx1bWluYW5jZUFscGhhRm9ybWF0ID0gMTAyNTtcclxuZXhwb3J0IGNvbnN0IERlcHRoRm9ybWF0ID0gMTAyNjtcclxuZXhwb3J0IGNvbnN0IERlcHRoU3RlbmNpbEZvcm1hdCA9IDEwMjc7XHJcbmV4cG9ydCBjb25zdCBSZWRGb3JtYXQgPSAxMDI4O1xyXG5leHBvcnQgY29uc3QgUmVkSW50ZWdlckZvcm1hdCA9IDEwMjk7XHJcbmV4cG9ydCBjb25zdCBSR0Zvcm1hdCA9IDEwMzA7XHJcbmV4cG9ydCBjb25zdCBSR0ludGVnZXJGb3JtYXQgPSAxMDMxO1xyXG5leHBvcnQgY29uc3QgUkdCQUludGVnZXJGb3JtYXQgPSAxMDMzO1xyXG5cclxuZXhwb3J0IGNvbnN0IFJHQl9TM1RDX0RYVDFfRm9ybWF0ID0gMzM3NzY7XHJcbmV4cG9ydCBjb25zdCBSR0JBX1MzVENfRFhUMV9Gb3JtYXQgPSAzMzc3NztcclxuZXhwb3J0IGNvbnN0IFJHQkFfUzNUQ19EWFQzX0Zvcm1hdCA9IDMzNzc4O1xyXG5leHBvcnQgY29uc3QgUkdCQV9TM1RDX0RYVDVfRm9ybWF0ID0gMzM3Nzk7XHJcbmV4cG9ydCBjb25zdCBSR0JfUFZSVENfNEJQUFYxX0Zvcm1hdCA9IDM1ODQwO1xyXG5leHBvcnQgY29uc3QgUkdCX1BWUlRDXzJCUFBWMV9Gb3JtYXQgPSAzNTg0MTtcclxuZXhwb3J0IGNvbnN0IFJHQkFfUFZSVENfNEJQUFYxX0Zvcm1hdCA9IDM1ODQyO1xyXG5leHBvcnQgY29uc3QgUkdCQV9QVlJUQ18yQlBQVjFfRm9ybWF0ID0gMzU4NDM7XHJcbmV4cG9ydCBjb25zdCBSR0JfRVRDMV9Gb3JtYXQgPSAzNjE5NjtcclxuZXhwb3J0IGNvbnN0IFJHQl9FVEMyX0Zvcm1hdCA9IDM3NDkyO1xyXG5leHBvcnQgY29uc3QgUkdCQV9FVEMyX0VBQ19Gb3JtYXQgPSAzNzQ5NjtcclxuZXhwb3J0IGNvbnN0IFJHQkFfQVNUQ180eDRfRm9ybWF0ID0gMzc4MDg7XHJcbmV4cG9ydCBjb25zdCBSR0JBX0FTVENfNXg0X0Zvcm1hdCA9IDM3ODA5O1xyXG5leHBvcnQgY29uc3QgUkdCQV9BU1RDXzV4NV9Gb3JtYXQgPSAzNzgxMDtcclxuZXhwb3J0IGNvbnN0IFJHQkFfQVNUQ182eDVfRm9ybWF0ID0gMzc4MTE7XHJcbmV4cG9ydCBjb25zdCBSR0JBX0FTVENfNng2X0Zvcm1hdCA9IDM3ODEyO1xyXG5leHBvcnQgY29uc3QgUkdCQV9BU1RDXzh4NV9Gb3JtYXQgPSAzNzgxMztcclxuZXhwb3J0IGNvbnN0IFJHQkFfQVNUQ184eDZfRm9ybWF0ID0gMzc4MTQ7XHJcbmV4cG9ydCBjb25zdCBSR0JBX0FTVENfOHg4X0Zvcm1hdCA9IDM3ODE1O1xyXG5leHBvcnQgY29uc3QgUkdCQV9BU1RDXzEweDVfRm9ybWF0ID0gMzc4MTY7XHJcbmV4cG9ydCBjb25zdCBSR0JBX0FTVENfMTB4Nl9Gb3JtYXQgPSAzNzgxNztcclxuZXhwb3J0IGNvbnN0IFJHQkFfQVNUQ18xMHg4X0Zvcm1hdCA9IDM3ODE4O1xyXG5leHBvcnQgY29uc3QgUkdCQV9BU1RDXzEweDEwX0Zvcm1hdCA9IDM3ODE5O1xyXG5leHBvcnQgY29uc3QgUkdCQV9BU1RDXzEyeDEwX0Zvcm1hdCA9IDM3ODIwO1xyXG5leHBvcnQgY29uc3QgUkdCQV9BU1RDXzEyeDEyX0Zvcm1hdCA9IDM3ODIxO1xyXG5leHBvcnQgY29uc3QgUkdCQV9CUFRDX0Zvcm1hdCA9IDM2NDkyO1xyXG5leHBvcnQgY29uc3QgUkdCX0JQVENfU0lHTkVEX0Zvcm1hdCA9IDM2NDk0O1xyXG5leHBvcnQgY29uc3QgUkdCX0JQVENfVU5TSUdORURfRm9ybWF0ID0gMzY0OTU7XHJcbmV4cG9ydCBjb25zdCBSRURfUkdUQzFfRm9ybWF0ID0gMzYyODM7XHJcbmV4cG9ydCBjb25zdCBTSUdORURfUkVEX1JHVEMxX0Zvcm1hdCA9IDM2Mjg0O1xyXG5leHBvcnQgY29uc3QgUkVEX0dSRUVOX1JHVEMyX0Zvcm1hdCA9IDM2Mjg1O1xyXG5leHBvcnQgY29uc3QgU0lHTkVEX1JFRF9HUkVFTl9SR1RDMl9Gb3JtYXQgPSAzNjI4NjtcclxuZXhwb3J0IGNvbnN0IExvb3BPbmNlID0gMjIwMDtcclxuZXhwb3J0IGNvbnN0IExvb3BSZXBlYXQgPSAyMjAxO1xyXG5leHBvcnQgY29uc3QgTG9vcFBpbmdQb25nID0gMjIwMjtcclxuZXhwb3J0IGNvbnN0IEludGVycG9sYXRlRGlzY3JldGUgPSAyMzAwO1xyXG5leHBvcnQgY29uc3QgSW50ZXJwb2xhdGVMaW5lYXIgPSAyMzAxO1xyXG5leHBvcnQgY29uc3QgSW50ZXJwb2xhdGVTbW9vdGggPSAyMzAyO1xyXG5leHBvcnQgY29uc3QgWmVyb0N1cnZhdHVyZUVuZGluZyA9IDI0MDA7XHJcbmV4cG9ydCBjb25zdCBaZXJvU2xvcGVFbmRpbmcgPSAyNDAxO1xyXG5leHBvcnQgY29uc3QgV3JhcEFyb3VuZEVuZGluZyA9IDI0MDI7XHJcbmV4cG9ydCBjb25zdCBOb3JtYWxBbmltYXRpb25CbGVuZE1vZGUgPSAyNTAwO1xyXG5leHBvcnQgY29uc3QgQWRkaXRpdmVBbmltYXRpb25CbGVuZE1vZGUgPSAyNTAxO1xyXG5leHBvcnQgY29uc3QgVHJpYW5nbGVzRHJhd01vZGUgPSAwO1xyXG5leHBvcnQgY29uc3QgVHJpYW5nbGVTdHJpcERyYXdNb2RlID0gMTtcclxuZXhwb3J0IGNvbnN0IFRyaWFuZ2xlRmFuRHJhd01vZGUgPSAyO1xyXG5leHBvcnQgY29uc3QgQmFzaWNEZXB0aFBhY2tpbmcgPSAzMjAwO1xyXG5leHBvcnQgY29uc3QgUkdCQURlcHRoUGFja2luZyA9IDMyMDE7XHJcbmV4cG9ydCBjb25zdCBUYW5nZW50U3BhY2VOb3JtYWxNYXAgPSAwO1xyXG5leHBvcnQgY29uc3QgT2JqZWN0U3BhY2VOb3JtYWxNYXAgPSAxO1xyXG5cclxuLy8gQ29sb3Igc3BhY2Ugc3RyaW5nIGlkZW50aWZpZXJzLCBtYXRjaGluZyBDU1MgQ29sb3IgTW9kdWxlIExldmVsIDQgYW5kIFdlYkdQVSBuYW1lcyB3aGVyZSBhdmFpbGFibGUuXHJcbmV4cG9ydCBjb25zdCBOb0NvbG9yU3BhY2UgPSAnJztcclxuZXhwb3J0IGNvbnN0IFNSR0JDb2xvclNwYWNlID0gJ3NyZ2InO1xyXG5leHBvcnQgY29uc3QgTGluZWFyU1JHQkNvbG9yU3BhY2UgPSAnc3JnYi1saW5lYXInO1xyXG5leHBvcnQgY29uc3QgRGlzcGxheVAzQ29sb3JTcGFjZSA9ICdkaXNwbGF5LXAzJztcclxuZXhwb3J0IGNvbnN0IExpbmVhckRpc3BsYXlQM0NvbG9yU3BhY2UgPSAnZGlzcGxheS1wMy1saW5lYXInO1xyXG5cclxuZXhwb3J0IGNvbnN0IExpbmVhclRyYW5zZmVyID0gJ2xpbmVhcic7XHJcbmV4cG9ydCBjb25zdCBTUkdCVHJhbnNmZXIgPSAnc3JnYic7XHJcblxyXG5leHBvcnQgY29uc3QgUmVjNzA5UHJpbWFyaWVzID0gJ3JlYzcwOSc7XHJcbmV4cG9ydCBjb25zdCBQM1ByaW1hcmllcyA9ICdwMyc7XHJcblxyXG5leHBvcnQgY29uc3QgWmVyb1N0ZW5jaWxPcCA9IDA7XHJcbmV4cG9ydCBjb25zdCBLZWVwU3RlbmNpbE9wID0gNzY4MDtcclxuZXhwb3J0IGNvbnN0IFJlcGxhY2VTdGVuY2lsT3AgPSA3NjgxO1xyXG5leHBvcnQgY29uc3QgSW5jcmVtZW50U3RlbmNpbE9wID0gNzY4MjtcclxuZXhwb3J0IGNvbnN0IERlY3JlbWVudFN0ZW5jaWxPcCA9IDc2ODM7XHJcbmV4cG9ydCBjb25zdCBJbmNyZW1lbnRXcmFwU3RlbmNpbE9wID0gMzQwNTU7XHJcbmV4cG9ydCBjb25zdCBEZWNyZW1lbnRXcmFwU3RlbmNpbE9wID0gMzQwNTY7XHJcbmV4cG9ydCBjb25zdCBJbnZlcnRTdGVuY2lsT3AgPSA1Mzg2O1xyXG5cclxuZXhwb3J0IGNvbnN0IE5ldmVyU3RlbmNpbEZ1bmMgPSA1MTI7XHJcbmV4cG9ydCBjb25zdCBMZXNzU3RlbmNpbEZ1bmMgPSA1MTM7XHJcbmV4cG9ydCBjb25zdCBFcXVhbFN0ZW5jaWxGdW5jID0gNTE0O1xyXG5leHBvcnQgY29uc3QgTGVzc0VxdWFsU3RlbmNpbEZ1bmMgPSA1MTU7XHJcbmV4cG9ydCBjb25zdCBHcmVhdGVyU3RlbmNpbEZ1bmMgPSA1MTY7XHJcbmV4cG9ydCBjb25zdCBOb3RFcXVhbFN0ZW5jaWxGdW5jID0gNTE3O1xyXG5leHBvcnQgY29uc3QgR3JlYXRlckVxdWFsU3RlbmNpbEZ1bmMgPSA1MTg7XHJcbmV4cG9ydCBjb25zdCBBbHdheXNTdGVuY2lsRnVuYyA9IDUxOTtcclxuXHJcbmV4cG9ydCBjb25zdCBOZXZlckNvbXBhcmUgPSA1MTI7XHJcbmV4cG9ydCBjb25zdCBMZXNzQ29tcGFyZSA9IDUxMztcclxuZXhwb3J0IGNvbnN0IEVxdWFsQ29tcGFyZSA9IDUxNDtcclxuZXhwb3J0IGNvbnN0IExlc3NFcXVhbENvbXBhcmUgPSA1MTU7XHJcbmV4cG9ydCBjb25zdCBHcmVhdGVyQ29tcGFyZSA9IDUxNjtcclxuZXhwb3J0IGNvbnN0IE5vdEVxdWFsQ29tcGFyZSA9IDUxNztcclxuZXhwb3J0IGNvbnN0IEdyZWF0ZXJFcXVhbENvbXBhcmUgPSA1MTg7XHJcbmV4cG9ydCBjb25zdCBBbHdheXNDb21wYXJlID0gNTE5O1xyXG5cclxuZXhwb3J0IGNvbnN0IFN0YXRpY0RyYXdVc2FnZSA9IDM1MDQ0O1xyXG5leHBvcnQgY29uc3QgRHluYW1pY0RyYXdVc2FnZSA9IDM1MDQ4O1xyXG5leHBvcnQgY29uc3QgU3RyZWFtRHJhd1VzYWdlID0gMzUwNDA7XHJcbmV4cG9ydCBjb25zdCBTdGF0aWNSZWFkVXNhZ2UgPSAzNTA0NTtcclxuZXhwb3J0IGNvbnN0IER5bmFtaWNSZWFkVXNhZ2UgPSAzNTA0OTtcclxuZXhwb3J0IGNvbnN0IFN0cmVhbVJlYWRVc2FnZSA9IDM1MDQxO1xyXG5leHBvcnQgY29uc3QgU3RhdGljQ29weVVzYWdlID0gMzUwNDY7XHJcbmV4cG9ydCBjb25zdCBEeW5hbWljQ29weVVzYWdlID0gMzUwNTA7XHJcbmV4cG9ydCBjb25zdCBTdHJlYW1Db3B5VXNhZ2UgPSAzNTA0MjtcclxuXHJcbmV4cG9ydCBjb25zdCBHTFNMMSA9ICcxMDAnO1xyXG5leHBvcnQgY29uc3QgR0xTTDMgPSAnMzAwIGVzJztcclxuXHJcbmV4cG9ydCBjb25zdCBfU1JHQkFGb3JtYXQgPSAxMDM1OyAvLyBmYWxsYmFjayBmb3IgV2ViR0wgMVxyXG5cclxuZXhwb3J0IGNvbnN0IFdlYkdMQ29vcmRpbmF0ZVN5c3RlbSA9IDIwMDA7XHJcbmV4cG9ydCBjb25zdCBXZWJHUFVDb29yZGluYXRlU3lzdGVtID0gMjAwMTtcclxuIiwiLyoqXHJcbiAqIGh0dHBzOi8vZ2l0aHViLmNvbS9tcmRvb2IvZXZlbnRkaXNwYXRjaGVyLmpzL1xyXG4gKi9cclxuXHJcbmNsYXNzIEV2ZW50RGlzcGF0Y2hlciB7XHJcblxyXG5cdGFkZEV2ZW50TGlzdGVuZXIoIHR5cGUsIGxpc3RlbmVyICkge1xyXG5cclxuXHRcdGlmICggdGhpcy5fbGlzdGVuZXJzID09PSB1bmRlZmluZWQgKSB0aGlzLl9saXN0ZW5lcnMgPSB7fTtcclxuXHJcblx0XHRjb25zdCBsaXN0ZW5lcnMgPSB0aGlzLl9saXN0ZW5lcnM7XHJcblxyXG5cdFx0aWYgKCBsaXN0ZW5lcnNbIHR5cGUgXSA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0bGlzdGVuZXJzWyB0eXBlIF0gPSBbXTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBsaXN0ZW5lcnNbIHR5cGUgXS5pbmRleE9mKCBsaXN0ZW5lciApID09PSAtIDEgKSB7XHJcblxyXG5cdFx0XHRsaXN0ZW5lcnNbIHR5cGUgXS5wdXNoKCBsaXN0ZW5lciApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRoYXNFdmVudExpc3RlbmVyKCB0eXBlLCBsaXN0ZW5lciApIHtcclxuXHJcblx0XHRpZiAoIHRoaXMuX2xpc3RlbmVycyA9PT0gdW5kZWZpbmVkICkgcmV0dXJuIGZhbHNlO1xyXG5cclxuXHRcdGNvbnN0IGxpc3RlbmVycyA9IHRoaXMuX2xpc3RlbmVycztcclxuXHJcblx0XHRyZXR1cm4gbGlzdGVuZXJzWyB0eXBlIF0gIT09IHVuZGVmaW5lZCAmJiBsaXN0ZW5lcnNbIHR5cGUgXS5pbmRleE9mKCBsaXN0ZW5lciApICE9PSAtIDE7XHJcblxyXG5cdH1cclxuXHJcblx0cmVtb3ZlRXZlbnRMaXN0ZW5lciggdHlwZSwgbGlzdGVuZXIgKSB7XHJcblxyXG5cdFx0aWYgKCB0aGlzLl9saXN0ZW5lcnMgPT09IHVuZGVmaW5lZCApIHJldHVybjtcclxuXHJcblx0XHRjb25zdCBsaXN0ZW5lcnMgPSB0aGlzLl9saXN0ZW5lcnM7XHJcblx0XHRjb25zdCBsaXN0ZW5lckFycmF5ID0gbGlzdGVuZXJzWyB0eXBlIF07XHJcblxyXG5cdFx0aWYgKCBsaXN0ZW5lckFycmF5ICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBpbmRleCA9IGxpc3RlbmVyQXJyYXkuaW5kZXhPZiggbGlzdGVuZXIgKTtcclxuXHJcblx0XHRcdGlmICggaW5kZXggIT09IC0gMSApIHtcclxuXHJcblx0XHRcdFx0bGlzdGVuZXJBcnJheS5zcGxpY2UoIGluZGV4LCAxICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGRpc3BhdGNoRXZlbnQoIGV2ZW50ICkge1xyXG5cclxuXHRcdGlmICggdGhpcy5fbGlzdGVuZXJzID09PSB1bmRlZmluZWQgKSByZXR1cm47XHJcblxyXG5cdFx0Y29uc3QgbGlzdGVuZXJzID0gdGhpcy5fbGlzdGVuZXJzO1xyXG5cdFx0Y29uc3QgbGlzdGVuZXJBcnJheSA9IGxpc3RlbmVyc1sgZXZlbnQudHlwZSBdO1xyXG5cclxuXHRcdGlmICggbGlzdGVuZXJBcnJheSAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0ZXZlbnQudGFyZ2V0ID0gdGhpcztcclxuXHJcblx0XHRcdC8vIE1ha2UgYSBjb3B5LCBpbiBjYXNlIGxpc3RlbmVycyBhcmUgcmVtb3ZlZCB3aGlsZSBpdGVyYXRpbmcuXHJcblx0XHRcdGNvbnN0IGFycmF5ID0gbGlzdGVuZXJBcnJheS5zbGljZSggMCApO1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gYXJyYXkubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0YXJyYXlbIGkgXS5jYWxsKCB0aGlzLCBldmVudCApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0ZXZlbnQudGFyZ2V0ID0gbnVsbDtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcblxyXG5leHBvcnQgeyBFdmVudERpc3BhdGNoZXIgfTtcclxuIiwiY29uc3QgX2x1dCA9IFsgJzAwJywgJzAxJywgJzAyJywgJzAzJywgJzA0JywgJzA1JywgJzA2JywgJzA3JywgJzA4JywgJzA5JywgJzBhJywgJzBiJywgJzBjJywgJzBkJywgJzBlJywgJzBmJywgJzEwJywgJzExJywgJzEyJywgJzEzJywgJzE0JywgJzE1JywgJzE2JywgJzE3JywgJzE4JywgJzE5JywgJzFhJywgJzFiJywgJzFjJywgJzFkJywgJzFlJywgJzFmJywgJzIwJywgJzIxJywgJzIyJywgJzIzJywgJzI0JywgJzI1JywgJzI2JywgJzI3JywgJzI4JywgJzI5JywgJzJhJywgJzJiJywgJzJjJywgJzJkJywgJzJlJywgJzJmJywgJzMwJywgJzMxJywgJzMyJywgJzMzJywgJzM0JywgJzM1JywgJzM2JywgJzM3JywgJzM4JywgJzM5JywgJzNhJywgJzNiJywgJzNjJywgJzNkJywgJzNlJywgJzNmJywgJzQwJywgJzQxJywgJzQyJywgJzQzJywgJzQ0JywgJzQ1JywgJzQ2JywgJzQ3JywgJzQ4JywgJzQ5JywgJzRhJywgJzRiJywgJzRjJywgJzRkJywgJzRlJywgJzRmJywgJzUwJywgJzUxJywgJzUyJywgJzUzJywgJzU0JywgJzU1JywgJzU2JywgJzU3JywgJzU4JywgJzU5JywgJzVhJywgJzViJywgJzVjJywgJzVkJywgJzVlJywgJzVmJywgJzYwJywgJzYxJywgJzYyJywgJzYzJywgJzY0JywgJzY1JywgJzY2JywgJzY3JywgJzY4JywgJzY5JywgJzZhJywgJzZiJywgJzZjJywgJzZkJywgJzZlJywgJzZmJywgJzcwJywgJzcxJywgJzcyJywgJzczJywgJzc0JywgJzc1JywgJzc2JywgJzc3JywgJzc4JywgJzc5JywgJzdhJywgJzdiJywgJzdjJywgJzdkJywgJzdlJywgJzdmJywgJzgwJywgJzgxJywgJzgyJywgJzgzJywgJzg0JywgJzg1JywgJzg2JywgJzg3JywgJzg4JywgJzg5JywgJzhhJywgJzhiJywgJzhjJywgJzhkJywgJzhlJywgJzhmJywgJzkwJywgJzkxJywgJzkyJywgJzkzJywgJzk0JywgJzk1JywgJzk2JywgJzk3JywgJzk4JywgJzk5JywgJzlhJywgJzliJywgJzljJywgJzlkJywgJzllJywgJzlmJywgJ2EwJywgJ2ExJywgJ2EyJywgJ2EzJywgJ2E0JywgJ2E1JywgJ2E2JywgJ2E3JywgJ2E4JywgJ2E5JywgJ2FhJywgJ2FiJywgJ2FjJywgJ2FkJywgJ2FlJywgJ2FmJywgJ2IwJywgJ2IxJywgJ2IyJywgJ2IzJywgJ2I0JywgJ2I1JywgJ2I2JywgJ2I3JywgJ2I4JywgJ2I5JywgJ2JhJywgJ2JiJywgJ2JjJywgJ2JkJywgJ2JlJywgJ2JmJywgJ2MwJywgJ2MxJywgJ2MyJywgJ2MzJywgJ2M0JywgJ2M1JywgJ2M2JywgJ2M3JywgJ2M4JywgJ2M5JywgJ2NhJywgJ2NiJywgJ2NjJywgJ2NkJywgJ2NlJywgJ2NmJywgJ2QwJywgJ2QxJywgJ2QyJywgJ2QzJywgJ2Q0JywgJ2Q1JywgJ2Q2JywgJ2Q3JywgJ2Q4JywgJ2Q5JywgJ2RhJywgJ2RiJywgJ2RjJywgJ2RkJywgJ2RlJywgJ2RmJywgJ2UwJywgJ2UxJywgJ2UyJywgJ2UzJywgJ2U0JywgJ2U1JywgJ2U2JywgJ2U3JywgJ2U4JywgJ2U5JywgJ2VhJywgJ2ViJywgJ2VjJywgJ2VkJywgJ2VlJywgJ2VmJywgJ2YwJywgJ2YxJywgJ2YyJywgJ2YzJywgJ2Y0JywgJ2Y1JywgJ2Y2JywgJ2Y3JywgJ2Y4JywgJ2Y5JywgJ2ZhJywgJ2ZiJywgJ2ZjJywgJ2ZkJywgJ2ZlJywgJ2ZmJyBdO1xyXG5cclxubGV0IF9zZWVkID0gMTIzNDU2NztcclxuXHJcblxyXG5jb25zdCBERUcyUkFEID0gTWF0aC5QSSAvIDE4MDtcclxuY29uc3QgUkFEMkRFRyA9IDE4MCAvIE1hdGguUEk7XHJcblxyXG4vLyBodHRwOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzEwNTAzNC9ob3ctdG8tY3JlYXRlLWEtZ3VpZC11dWlkLWluLWphdmFzY3JpcHQvMjE5NjMxMzYjMjE5NjMxMzZcclxuZnVuY3Rpb24gZ2VuZXJhdGVVVUlEKCkge1xyXG5cclxuXHRjb25zdCBkMCA9IE1hdGgucmFuZG9tKCkgKiAweGZmZmZmZmZmIHwgMDtcclxuXHRjb25zdCBkMSA9IE1hdGgucmFuZG9tKCkgKiAweGZmZmZmZmZmIHwgMDtcclxuXHRjb25zdCBkMiA9IE1hdGgucmFuZG9tKCkgKiAweGZmZmZmZmZmIHwgMDtcclxuXHRjb25zdCBkMyA9IE1hdGgucmFuZG9tKCkgKiAweGZmZmZmZmZmIHwgMDtcclxuXHRjb25zdCB1dWlkID0gX2x1dFsgZDAgJiAweGZmIF0gKyBfbHV0WyBkMCA+PiA4ICYgMHhmZiBdICsgX2x1dFsgZDAgPj4gMTYgJiAweGZmIF0gKyBfbHV0WyBkMCA+PiAyNCAmIDB4ZmYgXSArICctJyArXHJcblx0XHRcdF9sdXRbIGQxICYgMHhmZiBdICsgX2x1dFsgZDEgPj4gOCAmIDB4ZmYgXSArICctJyArIF9sdXRbIGQxID4+IDE2ICYgMHgwZiB8IDB4NDAgXSArIF9sdXRbIGQxID4+IDI0ICYgMHhmZiBdICsgJy0nICtcclxuXHRcdFx0X2x1dFsgZDIgJiAweDNmIHwgMHg4MCBdICsgX2x1dFsgZDIgPj4gOCAmIDB4ZmYgXSArICctJyArIF9sdXRbIGQyID4+IDE2ICYgMHhmZiBdICsgX2x1dFsgZDIgPj4gMjQgJiAweGZmIF0gK1xyXG5cdFx0XHRfbHV0WyBkMyAmIDB4ZmYgXSArIF9sdXRbIGQzID4+IDggJiAweGZmIF0gKyBfbHV0WyBkMyA+PiAxNiAmIDB4ZmYgXSArIF9sdXRbIGQzID4+IDI0ICYgMHhmZiBdO1xyXG5cclxuXHQvLyAudG9Mb3dlckNhc2UoKSBoZXJlIGZsYXR0ZW5zIGNvbmNhdGVuYXRlZCBzdHJpbmdzIHRvIHNhdmUgaGVhcCBtZW1vcnkgc3BhY2UuXHJcblx0cmV0dXJuIHV1aWQudG9Mb3dlckNhc2UoKTtcclxuXHJcbn1cclxuXHJcbmZ1bmN0aW9uIGNsYW1wKCB2YWx1ZSwgbWluLCBtYXggKSB7XHJcblxyXG5cdHJldHVybiBNYXRoLm1heCggbWluLCBNYXRoLm1pbiggbWF4LCB2YWx1ZSApICk7XHJcblxyXG59XHJcblxyXG4vLyBjb21wdXRlIGV1Y2xpZGVhbiBtb2R1bG8gb2YgbSAlIG5cclxuLy8gaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvTW9kdWxvX29wZXJhdGlvblxyXG5mdW5jdGlvbiBldWNsaWRlYW5Nb2R1bG8oIG4sIG0gKSB7XHJcblxyXG5cdHJldHVybiAoICggbiAlIG0gKSArIG0gKSAlIG07XHJcblxyXG59XHJcblxyXG4vLyBMaW5lYXIgbWFwcGluZyBmcm9tIHJhbmdlIDxhMSwgYTI+IHRvIHJhbmdlIDxiMSwgYjI+XHJcbmZ1bmN0aW9uIG1hcExpbmVhciggeCwgYTEsIGEyLCBiMSwgYjIgKSB7XHJcblxyXG5cdHJldHVybiBiMSArICggeCAtIGExICkgKiAoIGIyIC0gYjEgKSAvICggYTIgLSBhMSApO1xyXG5cclxufVxyXG5cclxuLy8gaHR0cHM6Ly93d3cuZ2FtZWRldi5uZXQvdHV0b3JpYWxzL3Byb2dyYW1taW5nL2dlbmVyYWwtYW5kLWdhbWVwbGF5LXByb2dyYW1taW5nL2ludmVyc2UtbGVycC1hLXN1cGVyLXVzZWZ1bC15ZXQtb2Z0ZW4tb3Zlcmxvb2tlZC1mdW5jdGlvbi1yNTIzMC9cclxuZnVuY3Rpb24gaW52ZXJzZUxlcnAoIHgsIHksIHZhbHVlICkge1xyXG5cclxuXHRpZiAoIHggIT09IHkgKSB7XHJcblxyXG5cdFx0cmV0dXJuICggdmFsdWUgLSB4ICkgLyAoIHkgLSB4ICk7XHJcblxyXG5cdH0gZWxzZSB7XHJcblxyXG5cdFx0cmV0dXJuIDA7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbi8vIGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0xpbmVhcl9pbnRlcnBvbGF0aW9uXHJcbmZ1bmN0aW9uIGxlcnAoIHgsIHksIHQgKSB7XHJcblxyXG5cdHJldHVybiAoIDEgLSB0ICkgKiB4ICsgdCAqIHk7XHJcblxyXG59XHJcblxyXG4vLyBodHRwOi8vd3d3LnJvcnlkcmlzY29sbC5jb20vMjAxNi8wMy8wNy9mcmFtZS1yYXRlLWluZGVwZW5kZW50LWRhbXBpbmctdXNpbmctbGVycC9cclxuZnVuY3Rpb24gZGFtcCggeCwgeSwgbGFtYmRhLCBkdCApIHtcclxuXHJcblx0cmV0dXJuIGxlcnAoIHgsIHksIDEgLSBNYXRoLmV4cCggLSBsYW1iZGEgKiBkdCApICk7XHJcblxyXG59XHJcblxyXG4vLyBodHRwczovL3d3dy5kZXNtb3MuY29tL2NhbGN1bGF0b3IvdmNzam55ejd4NFxyXG5mdW5jdGlvbiBwaW5ncG9uZyggeCwgbGVuZ3RoID0gMSApIHtcclxuXHJcblx0cmV0dXJuIGxlbmd0aCAtIE1hdGguYWJzKCBldWNsaWRlYW5Nb2R1bG8oIHgsIGxlbmd0aCAqIDIgKSAtIGxlbmd0aCApO1xyXG5cclxufVxyXG5cclxuLy8gaHR0cDovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9TbW9vdGhzdGVwXHJcbmZ1bmN0aW9uIHNtb290aHN0ZXAoIHgsIG1pbiwgbWF4ICkge1xyXG5cclxuXHRpZiAoIHggPD0gbWluICkgcmV0dXJuIDA7XHJcblx0aWYgKCB4ID49IG1heCApIHJldHVybiAxO1xyXG5cclxuXHR4ID0gKCB4IC0gbWluICkgLyAoIG1heCAtIG1pbiApO1xyXG5cclxuXHRyZXR1cm4geCAqIHggKiAoIDMgLSAyICogeCApO1xyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gc21vb3RoZXJzdGVwKCB4LCBtaW4sIG1heCApIHtcclxuXHJcblx0aWYgKCB4IDw9IG1pbiApIHJldHVybiAwO1xyXG5cdGlmICggeCA+PSBtYXggKSByZXR1cm4gMTtcclxuXHJcblx0eCA9ICggeCAtIG1pbiApIC8gKCBtYXggLSBtaW4gKTtcclxuXHJcblx0cmV0dXJuIHggKiB4ICogeCAqICggeCAqICggeCAqIDYgLSAxNSApICsgMTAgKTtcclxuXHJcbn1cclxuXHJcbi8vIFJhbmRvbSBpbnRlZ2VyIGZyb20gPGxvdywgaGlnaD4gaW50ZXJ2YWxcclxuZnVuY3Rpb24gcmFuZEludCggbG93LCBoaWdoICkge1xyXG5cclxuXHRyZXR1cm4gbG93ICsgTWF0aC5mbG9vciggTWF0aC5yYW5kb20oKSAqICggaGlnaCAtIGxvdyArIDEgKSApO1xyXG5cclxufVxyXG5cclxuLy8gUmFuZG9tIGZsb2F0IGZyb20gPGxvdywgaGlnaD4gaW50ZXJ2YWxcclxuZnVuY3Rpb24gcmFuZEZsb2F0KCBsb3csIGhpZ2ggKSB7XHJcblxyXG5cdHJldHVybiBsb3cgKyBNYXRoLnJhbmRvbSgpICogKCBoaWdoIC0gbG93ICk7XHJcblxyXG59XHJcblxyXG4vLyBSYW5kb20gZmxvYXQgZnJvbSA8LXJhbmdlLzIsIHJhbmdlLzI+IGludGVydmFsXHJcbmZ1bmN0aW9uIHJhbmRGbG9hdFNwcmVhZCggcmFuZ2UgKSB7XHJcblxyXG5cdHJldHVybiByYW5nZSAqICggMC41IC0gTWF0aC5yYW5kb20oKSApO1xyXG5cclxufVxyXG5cclxuLy8gRGV0ZXJtaW5pc3RpYyBwc2V1ZG8tcmFuZG9tIGZsb2F0IGluIHRoZSBpbnRlcnZhbCBbIDAsIDEgXVxyXG5mdW5jdGlvbiBzZWVkZWRSYW5kb20oIHMgKSB7XHJcblxyXG5cdGlmICggcyAhPT0gdW5kZWZpbmVkICkgX3NlZWQgPSBzO1xyXG5cclxuXHQvLyBNdWxiZXJyeTMyIGdlbmVyYXRvclxyXG5cclxuXHRsZXQgdCA9IF9zZWVkICs9IDB4NkQyQjc5RjU7XHJcblxyXG5cdHQgPSBNYXRoLmltdWwoIHQgXiB0ID4+PiAxNSwgdCB8IDEgKTtcclxuXHJcblx0dCBePSB0ICsgTWF0aC5pbXVsKCB0IF4gdCA+Pj4gNywgdCB8IDYxICk7XHJcblxyXG5cdHJldHVybiAoICggdCBeIHQgPj4+IDE0ICkgPj4+IDAgKSAvIDQyOTQ5NjcyOTY7XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiBkZWdUb1JhZCggZGVncmVlcyApIHtcclxuXHJcblx0cmV0dXJuIGRlZ3JlZXMgKiBERUcyUkFEO1xyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gcmFkVG9EZWcoIHJhZGlhbnMgKSB7XHJcblxyXG5cdHJldHVybiByYWRpYW5zICogUkFEMkRFRztcclxuXHJcbn1cclxuXHJcbmZ1bmN0aW9uIGlzUG93ZXJPZlR3byggdmFsdWUgKSB7XHJcblxyXG5cdHJldHVybiAoIHZhbHVlICYgKCB2YWx1ZSAtIDEgKSApID09PSAwICYmIHZhbHVlICE9PSAwO1xyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gY2VpbFBvd2VyT2ZUd28oIHZhbHVlICkge1xyXG5cclxuXHRyZXR1cm4gTWF0aC5wb3coIDIsIE1hdGguY2VpbCggTWF0aC5sb2coIHZhbHVlICkgLyBNYXRoLkxOMiApICk7XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiBmbG9vclBvd2VyT2ZUd28oIHZhbHVlICkge1xyXG5cclxuXHRyZXR1cm4gTWF0aC5wb3coIDIsIE1hdGguZmxvb3IoIE1hdGgubG9nKCB2YWx1ZSApIC8gTWF0aC5MTjIgKSApO1xyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gc2V0UXVhdGVybmlvbkZyb21Qcm9wZXJFdWxlciggcSwgYSwgYiwgYywgb3JkZXIgKSB7XHJcblxyXG5cdC8vIEludHJpbnNpYyBQcm9wZXIgRXVsZXIgQW5nbGVzIC0gc2VlIGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0V1bGVyX2FuZ2xlc1xyXG5cclxuXHQvLyByb3RhdGlvbnMgYXJlIGFwcGxpZWQgdG8gdGhlIGF4ZXMgaW4gdGhlIG9yZGVyIHNwZWNpZmllZCBieSAnb3JkZXInXHJcblx0Ly8gcm90YXRpb24gYnkgYW5nbGUgJ2EnIGlzIGFwcGxpZWQgZmlyc3QsIHRoZW4gYnkgYW5nbGUgJ2InLCB0aGVuIGJ5IGFuZ2xlICdjJ1xyXG5cdC8vIGFuZ2xlcyBhcmUgaW4gcmFkaWFuc1xyXG5cclxuXHRjb25zdCBjb3MgPSBNYXRoLmNvcztcclxuXHRjb25zdCBzaW4gPSBNYXRoLnNpbjtcclxuXHJcblx0Y29uc3QgYzIgPSBjb3MoIGIgLyAyICk7XHJcblx0Y29uc3QgczIgPSBzaW4oIGIgLyAyICk7XHJcblxyXG5cdGNvbnN0IGMxMyA9IGNvcyggKCBhICsgYyApIC8gMiApO1xyXG5cdGNvbnN0IHMxMyA9IHNpbiggKCBhICsgYyApIC8gMiApO1xyXG5cclxuXHRjb25zdCBjMV8zID0gY29zKCAoIGEgLSBjICkgLyAyICk7XHJcblx0Y29uc3QgczFfMyA9IHNpbiggKCBhIC0gYyApIC8gMiApO1xyXG5cclxuXHRjb25zdCBjM18xID0gY29zKCAoIGMgLSBhICkgLyAyICk7XHJcblx0Y29uc3QgczNfMSA9IHNpbiggKCBjIC0gYSApIC8gMiApO1xyXG5cclxuXHRzd2l0Y2ggKCBvcmRlciApIHtcclxuXHJcblx0XHRjYXNlICdYWVgnOlxyXG5cdFx0XHRxLnNldCggYzIgKiBzMTMsIHMyICogYzFfMywgczIgKiBzMV8zLCBjMiAqIGMxMyApO1xyXG5cdFx0XHRicmVhaztcclxuXHJcblx0XHRjYXNlICdZWlknOlxyXG5cdFx0XHRxLnNldCggczIgKiBzMV8zLCBjMiAqIHMxMywgczIgKiBjMV8zLCBjMiAqIGMxMyApO1xyXG5cdFx0XHRicmVhaztcclxuXHJcblx0XHRjYXNlICdaWFonOlxyXG5cdFx0XHRxLnNldCggczIgKiBjMV8zLCBzMiAqIHMxXzMsIGMyICogczEzLCBjMiAqIGMxMyApO1xyXG5cdFx0XHRicmVhaztcclxuXHJcblx0XHRjYXNlICdYWlgnOlxyXG5cdFx0XHRxLnNldCggYzIgKiBzMTMsIHMyICogczNfMSwgczIgKiBjM18xLCBjMiAqIGMxMyApO1xyXG5cdFx0XHRicmVhaztcclxuXHJcblx0XHRjYXNlICdZWFknOlxyXG5cdFx0XHRxLnNldCggczIgKiBjM18xLCBjMiAqIHMxMywgczIgKiBzM18xLCBjMiAqIGMxMyApO1xyXG5cdFx0XHRicmVhaztcclxuXHJcblx0XHRjYXNlICdaWVonOlxyXG5cdFx0XHRxLnNldCggczIgKiBzM18xLCBzMiAqIGMzXzEsIGMyICogczEzLCBjMiAqIGMxMyApO1xyXG5cdFx0XHRicmVhaztcclxuXHJcblx0XHRkZWZhdWx0OlxyXG5cdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5NYXRoVXRpbHM6IC5zZXRRdWF0ZXJuaW9uRnJvbVByb3BlckV1bGVyKCkgZW5jb3VudGVyZWQgYW4gdW5rbm93biBvcmRlcjogJyArIG9yZGVyICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmZ1bmN0aW9uIGRlbm9ybWFsaXplKCB2YWx1ZSwgYXJyYXkgKSB7XHJcblxyXG5cdHN3aXRjaCAoIGFycmF5LmNvbnN0cnVjdG9yICkge1xyXG5cclxuXHRcdGNhc2UgRmxvYXQzMkFycmF5OlxyXG5cclxuXHRcdFx0cmV0dXJuIHZhbHVlO1xyXG5cclxuXHRcdGNhc2UgVWludDMyQXJyYXk6XHJcblxyXG5cdFx0XHRyZXR1cm4gdmFsdWUgLyA0Mjk0OTY3Mjk1LjA7XHJcblxyXG5cdFx0Y2FzZSBVaW50MTZBcnJheTpcclxuXHJcblx0XHRcdHJldHVybiB2YWx1ZSAvIDY1NTM1LjA7XHJcblxyXG5cdFx0Y2FzZSBVaW50OEFycmF5OlxyXG5cclxuXHRcdFx0cmV0dXJuIHZhbHVlIC8gMjU1LjA7XHJcblxyXG5cdFx0Y2FzZSBJbnQzMkFycmF5OlxyXG5cclxuXHRcdFx0cmV0dXJuIE1hdGgubWF4KCB2YWx1ZSAvIDIxNDc0ODM2NDcuMCwgLSAxLjAgKTtcclxuXHJcblx0XHRjYXNlIEludDE2QXJyYXk6XHJcblxyXG5cdFx0XHRyZXR1cm4gTWF0aC5tYXgoIHZhbHVlIC8gMzI3NjcuMCwgLSAxLjAgKTtcclxuXHJcblx0XHRjYXNlIEludDhBcnJheTpcclxuXHJcblx0XHRcdHJldHVybiBNYXRoLm1heCggdmFsdWUgLyAxMjcuMCwgLSAxLjAgKTtcclxuXHJcblx0XHRkZWZhdWx0OlxyXG5cclxuXHRcdFx0dGhyb3cgbmV3IEVycm9yKCAnSW52YWxpZCBjb21wb25lbnQgdHlwZS4nICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmZ1bmN0aW9uIG5vcm1hbGl6ZSggdmFsdWUsIGFycmF5ICkge1xyXG5cclxuXHRzd2l0Y2ggKCBhcnJheS5jb25zdHJ1Y3RvciApIHtcclxuXHJcblx0XHRjYXNlIEZsb2F0MzJBcnJheTpcclxuXHJcblx0XHRcdHJldHVybiB2YWx1ZTtcclxuXHJcblx0XHRjYXNlIFVpbnQzMkFycmF5OlxyXG5cclxuXHRcdFx0cmV0dXJuIE1hdGgucm91bmQoIHZhbHVlICogNDI5NDk2NzI5NS4wICk7XHJcblxyXG5cdFx0Y2FzZSBVaW50MTZBcnJheTpcclxuXHJcblx0XHRcdHJldHVybiBNYXRoLnJvdW5kKCB2YWx1ZSAqIDY1NTM1LjAgKTtcclxuXHJcblx0XHRjYXNlIFVpbnQ4QXJyYXk6XHJcblxyXG5cdFx0XHRyZXR1cm4gTWF0aC5yb3VuZCggdmFsdWUgKiAyNTUuMCApO1xyXG5cclxuXHRcdGNhc2UgSW50MzJBcnJheTpcclxuXHJcblx0XHRcdHJldHVybiBNYXRoLnJvdW5kKCB2YWx1ZSAqIDIxNDc0ODM2NDcuMCApO1xyXG5cclxuXHRcdGNhc2UgSW50MTZBcnJheTpcclxuXHJcblx0XHRcdHJldHVybiBNYXRoLnJvdW5kKCB2YWx1ZSAqIDMyNzY3LjAgKTtcclxuXHJcblx0XHRjYXNlIEludDhBcnJheTpcclxuXHJcblx0XHRcdHJldHVybiBNYXRoLnJvdW5kKCB2YWx1ZSAqIDEyNy4wICk7XHJcblxyXG5cdFx0ZGVmYXVsdDpcclxuXHJcblx0XHRcdHRocm93IG5ldyBFcnJvciggJ0ludmFsaWQgY29tcG9uZW50IHR5cGUuJyApO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5jb25zdCBNYXRoVXRpbHMgPSB7XHJcblx0REVHMlJBRDogREVHMlJBRCxcclxuXHRSQUQyREVHOiBSQUQyREVHLFxyXG5cdGdlbmVyYXRlVVVJRDogZ2VuZXJhdGVVVUlELFxyXG5cdGNsYW1wOiBjbGFtcCxcclxuXHRldWNsaWRlYW5Nb2R1bG86IGV1Y2xpZGVhbk1vZHVsbyxcclxuXHRtYXBMaW5lYXI6IG1hcExpbmVhcixcclxuXHRpbnZlcnNlTGVycDogaW52ZXJzZUxlcnAsXHJcblx0bGVycDogbGVycCxcclxuXHRkYW1wOiBkYW1wLFxyXG5cdHBpbmdwb25nOiBwaW5ncG9uZyxcclxuXHRzbW9vdGhzdGVwOiBzbW9vdGhzdGVwLFxyXG5cdHNtb290aGVyc3RlcDogc21vb3RoZXJzdGVwLFxyXG5cdHJhbmRJbnQ6IHJhbmRJbnQsXHJcblx0cmFuZEZsb2F0OiByYW5kRmxvYXQsXHJcblx0cmFuZEZsb2F0U3ByZWFkOiByYW5kRmxvYXRTcHJlYWQsXHJcblx0c2VlZGVkUmFuZG9tOiBzZWVkZWRSYW5kb20sXHJcblx0ZGVnVG9SYWQ6IGRlZ1RvUmFkLFxyXG5cdHJhZFRvRGVnOiByYWRUb0RlZyxcclxuXHRpc1Bvd2VyT2ZUd286IGlzUG93ZXJPZlR3byxcclxuXHRjZWlsUG93ZXJPZlR3bzogY2VpbFBvd2VyT2ZUd28sXHJcblx0Zmxvb3JQb3dlck9mVHdvOiBmbG9vclBvd2VyT2ZUd28sXHJcblx0c2V0UXVhdGVybmlvbkZyb21Qcm9wZXJFdWxlcjogc2V0UXVhdGVybmlvbkZyb21Qcm9wZXJFdWxlcixcclxuXHRub3JtYWxpemU6IG5vcm1hbGl6ZSxcclxuXHRkZW5vcm1hbGl6ZTogZGVub3JtYWxpemVcclxufTtcclxuXHJcbmV4cG9ydCB7XHJcblx0REVHMlJBRCxcclxuXHRSQUQyREVHLFxyXG5cdGdlbmVyYXRlVVVJRCxcclxuXHRjbGFtcCxcclxuXHRldWNsaWRlYW5Nb2R1bG8sXHJcblx0bWFwTGluZWFyLFxyXG5cdGludmVyc2VMZXJwLFxyXG5cdGxlcnAsXHJcblx0ZGFtcCxcclxuXHRwaW5ncG9uZyxcclxuXHRzbW9vdGhzdGVwLFxyXG5cdHNtb290aGVyc3RlcCxcclxuXHRyYW5kSW50LFxyXG5cdHJhbmRGbG9hdCxcclxuXHRyYW5kRmxvYXRTcHJlYWQsXHJcblx0c2VlZGVkUmFuZG9tLFxyXG5cdGRlZ1RvUmFkLFxyXG5cdHJhZFRvRGVnLFxyXG5cdGlzUG93ZXJPZlR3byxcclxuXHRjZWlsUG93ZXJPZlR3byxcclxuXHRmbG9vclBvd2VyT2ZUd28sXHJcblx0c2V0UXVhdGVybmlvbkZyb21Qcm9wZXJFdWxlcixcclxuXHRub3JtYWxpemUsXHJcblx0ZGVub3JtYWxpemUsXHJcblx0TWF0aFV0aWxzXHJcbn07XHJcbiIsImltcG9ydCAqIGFzIE1hdGhVdGlscyBmcm9tICcuL01hdGhVdGlscy5qcyc7XHJcblxyXG5jbGFzcyBWZWN0b3IyIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIHggPSAwLCB5ID0gMCApIHtcclxuXHJcblx0XHRWZWN0b3IyLnByb3RvdHlwZS5pc1ZlY3RvcjIgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMueCA9IHg7XHJcblx0XHR0aGlzLnkgPSB5O1xyXG5cclxuXHR9XHJcblxyXG5cdGdldCB3aWR0aCgpIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy54O1xyXG5cclxuXHR9XHJcblxyXG5cdHNldCB3aWR0aCggdmFsdWUgKSB7XHJcblxyXG5cdFx0dGhpcy54ID0gdmFsdWU7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0IGhlaWdodCgpIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy55O1xyXG5cclxuXHR9XHJcblxyXG5cdHNldCBoZWlnaHQoIHZhbHVlICkge1xyXG5cclxuXHRcdHRoaXMueSA9IHZhbHVlO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldCggeCwgeSApIHtcclxuXHJcblx0XHR0aGlzLnggPSB4O1xyXG5cdFx0dGhpcy55ID0geTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRTY2FsYXIoIHNjYWxhciApIHtcclxuXHJcblx0XHR0aGlzLnggPSBzY2FsYXI7XHJcblx0XHR0aGlzLnkgPSBzY2FsYXI7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0WCggeCApIHtcclxuXHJcblx0XHR0aGlzLnggPSB4O1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldFkoIHkgKSB7XHJcblxyXG5cdFx0dGhpcy55ID0geTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRDb21wb25lbnQoIGluZGV4LCB2YWx1ZSApIHtcclxuXHJcblx0XHRzd2l0Y2ggKCBpbmRleCApIHtcclxuXHJcblx0XHRcdGNhc2UgMDogdGhpcy54ID0gdmFsdWU7IGJyZWFrO1xyXG5cdFx0XHRjYXNlIDE6IHRoaXMueSA9IHZhbHVlOyBicmVhaztcclxuXHRcdFx0ZGVmYXVsdDogdGhyb3cgbmV3IEVycm9yKCAnaW5kZXggaXMgb3V0IG9mIHJhbmdlOiAnICsgaW5kZXggKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0Q29tcG9uZW50KCBpbmRleCApIHtcclxuXHJcblx0XHRzd2l0Y2ggKCBpbmRleCApIHtcclxuXHJcblx0XHRcdGNhc2UgMDogcmV0dXJuIHRoaXMueDtcclxuXHRcdFx0Y2FzZSAxOiByZXR1cm4gdGhpcy55O1xyXG5cdFx0XHRkZWZhdWx0OiB0aHJvdyBuZXcgRXJyb3IoICdpbmRleCBpcyBvdXQgb2YgcmFuZ2U6ICcgKyBpbmRleCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRjbG9uZSgpIHtcclxuXHJcblx0XHRyZXR1cm4gbmV3IHRoaXMuY29uc3RydWN0b3IoIHRoaXMueCwgdGhpcy55ICk7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggdiApIHtcclxuXHJcblx0XHR0aGlzLnggPSB2Lng7XHJcblx0XHR0aGlzLnkgPSB2Lnk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0YWRkKCB2ICkge1xyXG5cclxuXHRcdHRoaXMueCArPSB2Lng7XHJcblx0XHR0aGlzLnkgKz0gdi55O1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGFkZFNjYWxhciggcyApIHtcclxuXHJcblx0XHR0aGlzLnggKz0gcztcclxuXHRcdHRoaXMueSArPSBzO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGFkZFZlY3RvcnMoIGEsIGIgKSB7XHJcblxyXG5cdFx0dGhpcy54ID0gYS54ICsgYi54O1xyXG5cdFx0dGhpcy55ID0gYS55ICsgYi55O1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGFkZFNjYWxlZFZlY3RvciggdiwgcyApIHtcclxuXHJcblx0XHR0aGlzLnggKz0gdi54ICogcztcclxuXHRcdHRoaXMueSArPSB2LnkgKiBzO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHN1YiggdiApIHtcclxuXHJcblx0XHR0aGlzLnggLT0gdi54O1xyXG5cdFx0dGhpcy55IC09IHYueTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzdWJTY2FsYXIoIHMgKSB7XHJcblxyXG5cdFx0dGhpcy54IC09IHM7XHJcblx0XHR0aGlzLnkgLT0gcztcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzdWJWZWN0b3JzKCBhLCBiICkge1xyXG5cclxuXHRcdHRoaXMueCA9IGEueCAtIGIueDtcclxuXHRcdHRoaXMueSA9IGEueSAtIGIueTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRtdWx0aXBseSggdiApIHtcclxuXHJcblx0XHR0aGlzLnggKj0gdi54O1xyXG5cdFx0dGhpcy55ICo9IHYueTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRtdWx0aXBseVNjYWxhciggc2NhbGFyICkge1xyXG5cclxuXHRcdHRoaXMueCAqPSBzY2FsYXI7XHJcblx0XHR0aGlzLnkgKj0gc2NhbGFyO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGRpdmlkZSggdiApIHtcclxuXHJcblx0XHR0aGlzLnggLz0gdi54O1xyXG5cdFx0dGhpcy55IC89IHYueTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRkaXZpZGVTY2FsYXIoIHNjYWxhciApIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5tdWx0aXBseVNjYWxhciggMSAvIHNjYWxhciApO1xyXG5cclxuXHR9XHJcblxyXG5cdGFwcGx5TWF0cml4MyggbSApIHtcclxuXHJcblx0XHRjb25zdCB4ID0gdGhpcy54LCB5ID0gdGhpcy55O1xyXG5cdFx0Y29uc3QgZSA9IG0uZWxlbWVudHM7XHJcblxyXG5cdFx0dGhpcy54ID0gZVsgMCBdICogeCArIGVbIDMgXSAqIHkgKyBlWyA2IF07XHJcblx0XHR0aGlzLnkgPSBlWyAxIF0gKiB4ICsgZVsgNCBdICogeSArIGVbIDcgXTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRtaW4oIHYgKSB7XHJcblxyXG5cdFx0dGhpcy54ID0gTWF0aC5taW4oIHRoaXMueCwgdi54ICk7XHJcblx0XHR0aGlzLnkgPSBNYXRoLm1pbiggdGhpcy55LCB2LnkgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRtYXgoIHYgKSB7XHJcblxyXG5cdFx0dGhpcy54ID0gTWF0aC5tYXgoIHRoaXMueCwgdi54ICk7XHJcblx0XHR0aGlzLnkgPSBNYXRoLm1heCggdGhpcy55LCB2LnkgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRjbGFtcCggbWluLCBtYXggKSB7XHJcblxyXG5cdFx0Ly8gYXNzdW1lcyBtaW4gPCBtYXgsIGNvbXBvbmVudHdpc2VcclxuXHJcblx0XHR0aGlzLnggPSBNYXRoLm1heCggbWluLngsIE1hdGgubWluKCBtYXgueCwgdGhpcy54ICkgKTtcclxuXHRcdHRoaXMueSA9IE1hdGgubWF4KCBtaW4ueSwgTWF0aC5taW4oIG1heC55LCB0aGlzLnkgKSApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGNsYW1wU2NhbGFyKCBtaW5WYWwsIG1heFZhbCApIHtcclxuXHJcblx0XHR0aGlzLnggPSBNYXRoLm1heCggbWluVmFsLCBNYXRoLm1pbiggbWF4VmFsLCB0aGlzLnggKSApO1xyXG5cdFx0dGhpcy55ID0gTWF0aC5tYXgoIG1pblZhbCwgTWF0aC5taW4oIG1heFZhbCwgdGhpcy55ICkgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRjbGFtcExlbmd0aCggbWluLCBtYXggKSB7XHJcblxyXG5cdFx0Y29uc3QgbGVuZ3RoID0gdGhpcy5sZW5ndGgoKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5kaXZpZGVTY2FsYXIoIGxlbmd0aCB8fCAxICkubXVsdGlwbHlTY2FsYXIoIE1hdGgubWF4KCBtaW4sIE1hdGgubWluKCBtYXgsIGxlbmd0aCApICkgKTtcclxuXHJcblx0fVxyXG5cclxuXHRmbG9vcigpIHtcclxuXHJcblx0XHR0aGlzLnggPSBNYXRoLmZsb29yKCB0aGlzLnggKTtcclxuXHRcdHRoaXMueSA9IE1hdGguZmxvb3IoIHRoaXMueSApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGNlaWwoKSB7XHJcblxyXG5cdFx0dGhpcy54ID0gTWF0aC5jZWlsKCB0aGlzLnggKTtcclxuXHRcdHRoaXMueSA9IE1hdGguY2VpbCggdGhpcy55ICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0cm91bmQoKSB7XHJcblxyXG5cdFx0dGhpcy54ID0gTWF0aC5yb3VuZCggdGhpcy54ICk7XHJcblx0XHR0aGlzLnkgPSBNYXRoLnJvdW5kKCB0aGlzLnkgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRyb3VuZFRvWmVybygpIHtcclxuXHJcblx0XHR0aGlzLnggPSBNYXRoLnRydW5jKCB0aGlzLnggKTtcclxuXHRcdHRoaXMueSA9IE1hdGgudHJ1bmMoIHRoaXMueSApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdG5lZ2F0ZSgpIHtcclxuXHJcblx0XHR0aGlzLnggPSAtIHRoaXMueDtcclxuXHRcdHRoaXMueSA9IC0gdGhpcy55O1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGRvdCggdiApIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy54ICogdi54ICsgdGhpcy55ICogdi55O1xyXG5cclxuXHR9XHJcblxyXG5cdGNyb3NzKCB2ICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLnggKiB2LnkgLSB0aGlzLnkgKiB2Lng7XHJcblxyXG5cdH1cclxuXHJcblx0bGVuZ3RoU3EoKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMueCAqIHRoaXMueCArIHRoaXMueSAqIHRoaXMueTtcclxuXHJcblx0fVxyXG5cclxuXHRsZW5ndGgoKSB7XHJcblxyXG5cdFx0cmV0dXJuIE1hdGguc3FydCggdGhpcy54ICogdGhpcy54ICsgdGhpcy55ICogdGhpcy55ICk7XHJcblxyXG5cdH1cclxuXHJcblx0bWFuaGF0dGFuTGVuZ3RoKCkge1xyXG5cclxuXHRcdHJldHVybiBNYXRoLmFicyggdGhpcy54ICkgKyBNYXRoLmFicyggdGhpcy55ICk7XHJcblxyXG5cdH1cclxuXHJcblx0bm9ybWFsaXplKCkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLmRpdmlkZVNjYWxhciggdGhpcy5sZW5ndGgoKSB8fCAxICk7XHJcblxyXG5cdH1cclxuXHJcblx0YW5nbGUoKSB7XHJcblxyXG5cdFx0Ly8gY29tcHV0ZXMgdGhlIGFuZ2xlIGluIHJhZGlhbnMgd2l0aCByZXNwZWN0IHRvIHRoZSBwb3NpdGl2ZSB4LWF4aXNcclxuXHJcblx0XHRjb25zdCBhbmdsZSA9IE1hdGguYXRhbjIoIC0gdGhpcy55LCAtIHRoaXMueCApICsgTWF0aC5QSTtcclxuXHJcblx0XHRyZXR1cm4gYW5nbGU7XHJcblxyXG5cdH1cclxuXHJcblx0YW5nbGVUbyggdiApIHtcclxuXHJcblx0XHRjb25zdCBkZW5vbWluYXRvciA9IE1hdGguc3FydCggdGhpcy5sZW5ndGhTcSgpICogdi5sZW5ndGhTcSgpICk7XHJcblxyXG5cdFx0aWYgKCBkZW5vbWluYXRvciA9PT0gMCApIHJldHVybiBNYXRoLlBJIC8gMjtcclxuXHJcblx0XHRjb25zdCB0aGV0YSA9IHRoaXMuZG90KCB2ICkgLyBkZW5vbWluYXRvcjtcclxuXHJcblx0XHQvLyBjbGFtcCwgdG8gaGFuZGxlIG51bWVyaWNhbCBwcm9ibGVtc1xyXG5cclxuXHRcdHJldHVybiBNYXRoLmFjb3MoIE1hdGhVdGlscy5jbGFtcCggdGhldGEsIC0gMSwgMSApICk7XHJcblxyXG5cdH1cclxuXHJcblx0ZGlzdGFuY2VUbyggdiApIHtcclxuXHJcblx0XHRyZXR1cm4gTWF0aC5zcXJ0KCB0aGlzLmRpc3RhbmNlVG9TcXVhcmVkKCB2ICkgKTtcclxuXHJcblx0fVxyXG5cclxuXHRkaXN0YW5jZVRvU3F1YXJlZCggdiApIHtcclxuXHJcblx0XHRjb25zdCBkeCA9IHRoaXMueCAtIHYueCwgZHkgPSB0aGlzLnkgLSB2Lnk7XHJcblx0XHRyZXR1cm4gZHggKiBkeCArIGR5ICogZHk7XHJcblxyXG5cdH1cclxuXHJcblx0bWFuaGF0dGFuRGlzdGFuY2VUbyggdiApIHtcclxuXHJcblx0XHRyZXR1cm4gTWF0aC5hYnMoIHRoaXMueCAtIHYueCApICsgTWF0aC5hYnMoIHRoaXMueSAtIHYueSApO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldExlbmd0aCggbGVuZ3RoICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLm5vcm1hbGl6ZSgpLm11bHRpcGx5U2NhbGFyKCBsZW5ndGggKTtcclxuXHJcblx0fVxyXG5cclxuXHRsZXJwKCB2LCBhbHBoYSApIHtcclxuXHJcblx0XHR0aGlzLnggKz0gKCB2LnggLSB0aGlzLnggKSAqIGFscGhhO1xyXG5cdFx0dGhpcy55ICs9ICggdi55IC0gdGhpcy55ICkgKiBhbHBoYTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRsZXJwVmVjdG9ycyggdjEsIHYyLCBhbHBoYSApIHtcclxuXHJcblx0XHR0aGlzLnggPSB2MS54ICsgKCB2Mi54IC0gdjEueCApICogYWxwaGE7XHJcblx0XHR0aGlzLnkgPSB2MS55ICsgKCB2Mi55IC0gdjEueSApICogYWxwaGE7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0ZXF1YWxzKCB2ICkge1xyXG5cclxuXHRcdHJldHVybiAoICggdi54ID09PSB0aGlzLnggKSAmJiAoIHYueSA9PT0gdGhpcy55ICkgKTtcclxuXHJcblx0fVxyXG5cclxuXHRmcm9tQXJyYXkoIGFycmF5LCBvZmZzZXQgPSAwICkge1xyXG5cclxuXHRcdHRoaXMueCA9IGFycmF5WyBvZmZzZXQgXTtcclxuXHRcdHRoaXMueSA9IGFycmF5WyBvZmZzZXQgKyAxIF07XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0dG9BcnJheSggYXJyYXkgPSBbXSwgb2Zmc2V0ID0gMCApIHtcclxuXHJcblx0XHRhcnJheVsgb2Zmc2V0IF0gPSB0aGlzLng7XHJcblx0XHRhcnJheVsgb2Zmc2V0ICsgMSBdID0gdGhpcy55O1xyXG5cclxuXHRcdHJldHVybiBhcnJheTtcclxuXHJcblx0fVxyXG5cclxuXHRmcm9tQnVmZmVyQXR0cmlidXRlKCBhdHRyaWJ1dGUsIGluZGV4ICkge1xyXG5cclxuXHRcdHRoaXMueCA9IGF0dHJpYnV0ZS5nZXRYKCBpbmRleCApO1xyXG5cdFx0dGhpcy55ID0gYXR0cmlidXRlLmdldFkoIGluZGV4ICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0cm90YXRlQXJvdW5kKCBjZW50ZXIsIGFuZ2xlICkge1xyXG5cclxuXHRcdGNvbnN0IGMgPSBNYXRoLmNvcyggYW5nbGUgKSwgcyA9IE1hdGguc2luKCBhbmdsZSApO1xyXG5cclxuXHRcdGNvbnN0IHggPSB0aGlzLnggLSBjZW50ZXIueDtcclxuXHRcdGNvbnN0IHkgPSB0aGlzLnkgLSBjZW50ZXIueTtcclxuXHJcblx0XHR0aGlzLnggPSB4ICogYyAtIHkgKiBzICsgY2VudGVyLng7XHJcblx0XHR0aGlzLnkgPSB4ICogcyArIHkgKiBjICsgY2VudGVyLnk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0cmFuZG9tKCkge1xyXG5cclxuXHRcdHRoaXMueCA9IE1hdGgucmFuZG9tKCk7XHJcblx0XHR0aGlzLnkgPSBNYXRoLnJhbmRvbSgpO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdCpbIFN5bWJvbC5pdGVyYXRvciBdKCkge1xyXG5cclxuXHRcdHlpZWxkIHRoaXMueDtcclxuXHRcdHlpZWxkIHRoaXMueTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgVmVjdG9yMiB9O1xyXG4iLCJjbGFzcyBNYXRyaXgzIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIG4xMSwgbjEyLCBuMTMsIG4yMSwgbjIyLCBuMjMsIG4zMSwgbjMyLCBuMzMgKSB7XHJcblxyXG5cdFx0TWF0cml4My5wcm90b3R5cGUuaXNNYXRyaXgzID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLmVsZW1lbnRzID0gW1xyXG5cclxuXHRcdFx0MSwgMCwgMCxcclxuXHRcdFx0MCwgMSwgMCxcclxuXHRcdFx0MCwgMCwgMVxyXG5cclxuXHRcdF07XHJcblxyXG5cdFx0aWYgKCBuMTEgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdHRoaXMuc2V0KCBuMTEsIG4xMiwgbjEzLCBuMjEsIG4yMiwgbjIzLCBuMzEsIG4zMiwgbjMzICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdHNldCggbjExLCBuMTIsIG4xMywgbjIxLCBuMjIsIG4yMywgbjMxLCBuMzIsIG4zMyApIHtcclxuXHJcblx0XHRjb25zdCB0ZSA9IHRoaXMuZWxlbWVudHM7XHJcblxyXG5cdFx0dGVbIDAgXSA9IG4xMTsgdGVbIDEgXSA9IG4yMTsgdGVbIDIgXSA9IG4zMTtcclxuXHRcdHRlWyAzIF0gPSBuMTI7IHRlWyA0IF0gPSBuMjI7IHRlWyA1IF0gPSBuMzI7XHJcblx0XHR0ZVsgNiBdID0gbjEzOyB0ZVsgNyBdID0gbjIzOyB0ZVsgOCBdID0gbjMzO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGlkZW50aXR5KCkge1xyXG5cclxuXHRcdHRoaXMuc2V0KFxyXG5cclxuXHRcdFx0MSwgMCwgMCxcclxuXHRcdFx0MCwgMSwgMCxcclxuXHRcdFx0MCwgMCwgMVxyXG5cclxuXHRcdCk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggbSApIHtcclxuXHJcblx0XHRjb25zdCB0ZSA9IHRoaXMuZWxlbWVudHM7XHJcblx0XHRjb25zdCBtZSA9IG0uZWxlbWVudHM7XHJcblxyXG5cdFx0dGVbIDAgXSA9IG1lWyAwIF07IHRlWyAxIF0gPSBtZVsgMSBdOyB0ZVsgMiBdID0gbWVbIDIgXTtcclxuXHRcdHRlWyAzIF0gPSBtZVsgMyBdOyB0ZVsgNCBdID0gbWVbIDQgXTsgdGVbIDUgXSA9IG1lWyA1IF07XHJcblx0XHR0ZVsgNiBdID0gbWVbIDYgXTsgdGVbIDcgXSA9IG1lWyA3IF07IHRlWyA4IF0gPSBtZVsgOCBdO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGV4dHJhY3RCYXNpcyggeEF4aXMsIHlBeGlzLCB6QXhpcyApIHtcclxuXHJcblx0XHR4QXhpcy5zZXRGcm9tTWF0cml4M0NvbHVtbiggdGhpcywgMCApO1xyXG5cdFx0eUF4aXMuc2V0RnJvbU1hdHJpeDNDb2x1bW4oIHRoaXMsIDEgKTtcclxuXHRcdHpBeGlzLnNldEZyb21NYXRyaXgzQ29sdW1uKCB0aGlzLCAyICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0RnJvbU1hdHJpeDQoIG0gKSB7XHJcblxyXG5cdFx0Y29uc3QgbWUgPSBtLmVsZW1lbnRzO1xyXG5cclxuXHRcdHRoaXMuc2V0KFxyXG5cclxuXHRcdFx0bWVbIDAgXSwgbWVbIDQgXSwgbWVbIDggXSxcclxuXHRcdFx0bWVbIDEgXSwgbWVbIDUgXSwgbWVbIDkgXSxcclxuXHRcdFx0bWVbIDIgXSwgbWVbIDYgXSwgbWVbIDEwIF1cclxuXHJcblx0XHQpO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdG11bHRpcGx5KCBtICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLm11bHRpcGx5TWF0cmljZXMoIHRoaXMsIG0gKTtcclxuXHJcblx0fVxyXG5cclxuXHRwcmVtdWx0aXBseSggbSApIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5tdWx0aXBseU1hdHJpY2VzKCBtLCB0aGlzICk7XHJcblxyXG5cdH1cclxuXHJcblx0bXVsdGlwbHlNYXRyaWNlcyggYSwgYiApIHtcclxuXHJcblx0XHRjb25zdCBhZSA9IGEuZWxlbWVudHM7XHJcblx0XHRjb25zdCBiZSA9IGIuZWxlbWVudHM7XHJcblx0XHRjb25zdCB0ZSA9IHRoaXMuZWxlbWVudHM7XHJcblxyXG5cdFx0Y29uc3QgYTExID0gYWVbIDAgXSwgYTEyID0gYWVbIDMgXSwgYTEzID0gYWVbIDYgXTtcclxuXHRcdGNvbnN0IGEyMSA9IGFlWyAxIF0sIGEyMiA9IGFlWyA0IF0sIGEyMyA9IGFlWyA3IF07XHJcblx0XHRjb25zdCBhMzEgPSBhZVsgMiBdLCBhMzIgPSBhZVsgNSBdLCBhMzMgPSBhZVsgOCBdO1xyXG5cclxuXHRcdGNvbnN0IGIxMSA9IGJlWyAwIF0sIGIxMiA9IGJlWyAzIF0sIGIxMyA9IGJlWyA2IF07XHJcblx0XHRjb25zdCBiMjEgPSBiZVsgMSBdLCBiMjIgPSBiZVsgNCBdLCBiMjMgPSBiZVsgNyBdO1xyXG5cdFx0Y29uc3QgYjMxID0gYmVbIDIgXSwgYjMyID0gYmVbIDUgXSwgYjMzID0gYmVbIDggXTtcclxuXHJcblx0XHR0ZVsgMCBdID0gYTExICogYjExICsgYTEyICogYjIxICsgYTEzICogYjMxO1xyXG5cdFx0dGVbIDMgXSA9IGExMSAqIGIxMiArIGExMiAqIGIyMiArIGExMyAqIGIzMjtcclxuXHRcdHRlWyA2IF0gPSBhMTEgKiBiMTMgKyBhMTIgKiBiMjMgKyBhMTMgKiBiMzM7XHJcblxyXG5cdFx0dGVbIDEgXSA9IGEyMSAqIGIxMSArIGEyMiAqIGIyMSArIGEyMyAqIGIzMTtcclxuXHRcdHRlWyA0IF0gPSBhMjEgKiBiMTIgKyBhMjIgKiBiMjIgKyBhMjMgKiBiMzI7XHJcblx0XHR0ZVsgNyBdID0gYTIxICogYjEzICsgYTIyICogYjIzICsgYTIzICogYjMzO1xyXG5cclxuXHRcdHRlWyAyIF0gPSBhMzEgKiBiMTEgKyBhMzIgKiBiMjEgKyBhMzMgKiBiMzE7XHJcblx0XHR0ZVsgNSBdID0gYTMxICogYjEyICsgYTMyICogYjIyICsgYTMzICogYjMyO1xyXG5cdFx0dGVbIDggXSA9IGEzMSAqIGIxMyArIGEzMiAqIGIyMyArIGEzMyAqIGIzMztcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRtdWx0aXBseVNjYWxhciggcyApIHtcclxuXHJcblx0XHRjb25zdCB0ZSA9IHRoaXMuZWxlbWVudHM7XHJcblxyXG5cdFx0dGVbIDAgXSAqPSBzOyB0ZVsgMyBdICo9IHM7IHRlWyA2IF0gKj0gcztcclxuXHRcdHRlWyAxIF0gKj0gczsgdGVbIDQgXSAqPSBzOyB0ZVsgNyBdICo9IHM7XHJcblx0XHR0ZVsgMiBdICo9IHM7IHRlWyA1IF0gKj0gczsgdGVbIDggXSAqPSBzO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGRldGVybWluYW50KCkge1xyXG5cclxuXHRcdGNvbnN0IHRlID0gdGhpcy5lbGVtZW50cztcclxuXHJcblx0XHRjb25zdCBhID0gdGVbIDAgXSwgYiA9IHRlWyAxIF0sIGMgPSB0ZVsgMiBdLFxyXG5cdFx0XHRkID0gdGVbIDMgXSwgZSA9IHRlWyA0IF0sIGYgPSB0ZVsgNSBdLFxyXG5cdFx0XHRnID0gdGVbIDYgXSwgaCA9IHRlWyA3IF0sIGkgPSB0ZVsgOCBdO1xyXG5cclxuXHRcdHJldHVybiBhICogZSAqIGkgLSBhICogZiAqIGggLSBiICogZCAqIGkgKyBiICogZiAqIGcgKyBjICogZCAqIGggLSBjICogZSAqIGc7XHJcblxyXG5cdH1cclxuXHJcblx0aW52ZXJ0KCkge1xyXG5cclxuXHRcdGNvbnN0IHRlID0gdGhpcy5lbGVtZW50cyxcclxuXHJcblx0XHRcdG4xMSA9IHRlWyAwIF0sIG4yMSA9IHRlWyAxIF0sIG4zMSA9IHRlWyAyIF0sXHJcblx0XHRcdG4xMiA9IHRlWyAzIF0sIG4yMiA9IHRlWyA0IF0sIG4zMiA9IHRlWyA1IF0sXHJcblx0XHRcdG4xMyA9IHRlWyA2IF0sIG4yMyA9IHRlWyA3IF0sIG4zMyA9IHRlWyA4IF0sXHJcblxyXG5cdFx0XHR0MTEgPSBuMzMgKiBuMjIgLSBuMzIgKiBuMjMsXHJcblx0XHRcdHQxMiA9IG4zMiAqIG4xMyAtIG4zMyAqIG4xMixcclxuXHRcdFx0dDEzID0gbjIzICogbjEyIC0gbjIyICogbjEzLFxyXG5cclxuXHRcdFx0ZGV0ID0gbjExICogdDExICsgbjIxICogdDEyICsgbjMxICogdDEzO1xyXG5cclxuXHRcdGlmICggZGV0ID09PSAwICkgcmV0dXJuIHRoaXMuc2V0KCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwICk7XHJcblxyXG5cdFx0Y29uc3QgZGV0SW52ID0gMSAvIGRldDtcclxuXHJcblx0XHR0ZVsgMCBdID0gdDExICogZGV0SW52O1xyXG5cdFx0dGVbIDEgXSA9ICggbjMxICogbjIzIC0gbjMzICogbjIxICkgKiBkZXRJbnY7XHJcblx0XHR0ZVsgMiBdID0gKCBuMzIgKiBuMjEgLSBuMzEgKiBuMjIgKSAqIGRldEludjtcclxuXHJcblx0XHR0ZVsgMyBdID0gdDEyICogZGV0SW52O1xyXG5cdFx0dGVbIDQgXSA9ICggbjMzICogbjExIC0gbjMxICogbjEzICkgKiBkZXRJbnY7XHJcblx0XHR0ZVsgNSBdID0gKCBuMzEgKiBuMTIgLSBuMzIgKiBuMTEgKSAqIGRldEludjtcclxuXHJcblx0XHR0ZVsgNiBdID0gdDEzICogZGV0SW52O1xyXG5cdFx0dGVbIDcgXSA9ICggbjIxICogbjEzIC0gbjIzICogbjExICkgKiBkZXRJbnY7XHJcblx0XHR0ZVsgOCBdID0gKCBuMjIgKiBuMTEgLSBuMjEgKiBuMTIgKSAqIGRldEludjtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHR0cmFuc3Bvc2UoKSB7XHJcblxyXG5cdFx0bGV0IHRtcDtcclxuXHRcdGNvbnN0IG0gPSB0aGlzLmVsZW1lbnRzO1xyXG5cclxuXHRcdHRtcCA9IG1bIDEgXTsgbVsgMSBdID0gbVsgMyBdOyBtWyAzIF0gPSB0bXA7XHJcblx0XHR0bXAgPSBtWyAyIF07IG1bIDIgXSA9IG1bIDYgXTsgbVsgNiBdID0gdG1wO1xyXG5cdFx0dG1wID0gbVsgNSBdOyBtWyA1IF0gPSBtWyA3IF07IG1bIDcgXSA9IHRtcDtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRnZXROb3JtYWxNYXRyaXgoIG1hdHJpeDQgKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuc2V0RnJvbU1hdHJpeDQoIG1hdHJpeDQgKS5pbnZlcnQoKS50cmFuc3Bvc2UoKTtcclxuXHJcblx0fVxyXG5cclxuXHR0cmFuc3Bvc2VJbnRvQXJyYXkoIHIgKSB7XHJcblxyXG5cdFx0Y29uc3QgbSA9IHRoaXMuZWxlbWVudHM7XHJcblxyXG5cdFx0clsgMCBdID0gbVsgMCBdO1xyXG5cdFx0clsgMSBdID0gbVsgMyBdO1xyXG5cdFx0clsgMiBdID0gbVsgNiBdO1xyXG5cdFx0clsgMyBdID0gbVsgMSBdO1xyXG5cdFx0clsgNCBdID0gbVsgNCBdO1xyXG5cdFx0clsgNSBdID0gbVsgNyBdO1xyXG5cdFx0clsgNiBdID0gbVsgMiBdO1xyXG5cdFx0clsgNyBdID0gbVsgNSBdO1xyXG5cdFx0clsgOCBdID0gbVsgOCBdO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldFV2VHJhbnNmb3JtKCB0eCwgdHksIHN4LCBzeSwgcm90YXRpb24sIGN4LCBjeSApIHtcclxuXHJcblx0XHRjb25zdCBjID0gTWF0aC5jb3MoIHJvdGF0aW9uICk7XHJcblx0XHRjb25zdCBzID0gTWF0aC5zaW4oIHJvdGF0aW9uICk7XHJcblxyXG5cdFx0dGhpcy5zZXQoXHJcblx0XHRcdHN4ICogYywgc3ggKiBzLCAtIHN4ICogKCBjICogY3ggKyBzICogY3kgKSArIGN4ICsgdHgsXHJcblx0XHRcdC0gc3kgKiBzLCBzeSAqIGMsIC0gc3kgKiAoIC0gcyAqIGN4ICsgYyAqIGN5ICkgKyBjeSArIHR5LFxyXG5cdFx0XHQwLCAwLCAxXHJcblx0XHQpO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdC8vXHJcblxyXG5cdHNjYWxlKCBzeCwgc3kgKSB7XHJcblxyXG5cdFx0dGhpcy5wcmVtdWx0aXBseSggX20zLm1ha2VTY2FsZSggc3gsIHN5ICkgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRyb3RhdGUoIHRoZXRhICkge1xyXG5cclxuXHRcdHRoaXMucHJlbXVsdGlwbHkoIF9tMy5tYWtlUm90YXRpb24oIC0gdGhldGEgKSApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHRyYW5zbGF0ZSggdHgsIHR5ICkge1xyXG5cclxuXHRcdHRoaXMucHJlbXVsdGlwbHkoIF9tMy5tYWtlVHJhbnNsYXRpb24oIHR4LCB0eSApICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gZm9yIDJEIFRyYW5zZm9ybXNcclxuXHJcblx0bWFrZVRyYW5zbGF0aW9uKCB4LCB5ICkge1xyXG5cclxuXHRcdGlmICggeC5pc1ZlY3RvcjIgKSB7XHJcblxyXG5cdFx0XHR0aGlzLnNldChcclxuXHJcblx0XHRcdFx0MSwgMCwgeC54LFxyXG5cdFx0XHRcdDAsIDEsIHgueSxcclxuXHRcdFx0XHQwLCAwLCAxXHJcblxyXG5cdFx0XHQpO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHR0aGlzLnNldChcclxuXHJcblx0XHRcdFx0MSwgMCwgeCxcclxuXHRcdFx0XHQwLCAxLCB5LFxyXG5cdFx0XHRcdDAsIDAsIDFcclxuXHJcblx0XHRcdCk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdG1ha2VSb3RhdGlvbiggdGhldGEgKSB7XHJcblxyXG5cdFx0Ly8gY291bnRlcmNsb2Nrd2lzZVxyXG5cclxuXHRcdGNvbnN0IGMgPSBNYXRoLmNvcyggdGhldGEgKTtcclxuXHRcdGNvbnN0IHMgPSBNYXRoLnNpbiggdGhldGEgKTtcclxuXHJcblx0XHR0aGlzLnNldChcclxuXHJcblx0XHRcdGMsIC0gcywgMCxcclxuXHRcdFx0cywgYywgMCxcclxuXHRcdFx0MCwgMCwgMVxyXG5cclxuXHRcdCk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0bWFrZVNjYWxlKCB4LCB5ICkge1xyXG5cclxuXHRcdHRoaXMuc2V0KFxyXG5cclxuXHRcdFx0eCwgMCwgMCxcclxuXHRcdFx0MCwgeSwgMCxcclxuXHRcdFx0MCwgMCwgMVxyXG5cclxuXHRcdCk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Ly9cclxuXHJcblx0ZXF1YWxzKCBtYXRyaXggKSB7XHJcblxyXG5cdFx0Y29uc3QgdGUgPSB0aGlzLmVsZW1lbnRzO1xyXG5cdFx0Y29uc3QgbWUgPSBtYXRyaXguZWxlbWVudHM7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgOTsgaSArKyApIHtcclxuXHJcblx0XHRcdGlmICggdGVbIGkgXSAhPT0gbWVbIGkgXSApIHJldHVybiBmYWxzZTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRydWU7XHJcblxyXG5cdH1cclxuXHJcblx0ZnJvbUFycmF5KCBhcnJheSwgb2Zmc2V0ID0gMCApIHtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCA5OyBpICsrICkge1xyXG5cclxuXHRcdFx0dGhpcy5lbGVtZW50c1sgaSBdID0gYXJyYXlbIGkgKyBvZmZzZXQgXTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0dG9BcnJheSggYXJyYXkgPSBbXSwgb2Zmc2V0ID0gMCApIHtcclxuXHJcblx0XHRjb25zdCB0ZSA9IHRoaXMuZWxlbWVudHM7XHJcblxyXG5cdFx0YXJyYXlbIG9mZnNldCBdID0gdGVbIDAgXTtcclxuXHRcdGFycmF5WyBvZmZzZXQgKyAxIF0gPSB0ZVsgMSBdO1xyXG5cdFx0YXJyYXlbIG9mZnNldCArIDIgXSA9IHRlWyAyIF07XHJcblxyXG5cdFx0YXJyYXlbIG9mZnNldCArIDMgXSA9IHRlWyAzIF07XHJcblx0XHRhcnJheVsgb2Zmc2V0ICsgNCBdID0gdGVbIDQgXTtcclxuXHRcdGFycmF5WyBvZmZzZXQgKyA1IF0gPSB0ZVsgNSBdO1xyXG5cclxuXHRcdGFycmF5WyBvZmZzZXQgKyA2IF0gPSB0ZVsgNiBdO1xyXG5cdFx0YXJyYXlbIG9mZnNldCArIDcgXSA9IHRlWyA3IF07XHJcblx0XHRhcnJheVsgb2Zmc2V0ICsgOCBdID0gdGVbIDggXTtcclxuXHJcblx0XHRyZXR1cm4gYXJyYXk7XHJcblxyXG5cdH1cclxuXHJcblx0Y2xvbmUoKSB7XHJcblxyXG5cdFx0cmV0dXJuIG5ldyB0aGlzLmNvbnN0cnVjdG9yKCkuZnJvbUFycmF5KCB0aGlzLmVsZW1lbnRzICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmNvbnN0IF9tMyA9IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDMoKTtcclxuXHJcbmV4cG9ydCB7IE1hdHJpeDMgfTtcclxuIiwiZnVuY3Rpb24gYXJyYXlNaW4oIGFycmF5ICkge1xyXG5cclxuXHRpZiAoIGFycmF5Lmxlbmd0aCA9PT0gMCApIHJldHVybiBJbmZpbml0eTtcclxuXHJcblx0bGV0IG1pbiA9IGFycmF5WyAwIF07XHJcblxyXG5cdGZvciAoIGxldCBpID0gMSwgbCA9IGFycmF5Lmxlbmd0aDsgaSA8IGw7ICsrIGkgKSB7XHJcblxyXG5cdFx0aWYgKCBhcnJheVsgaSBdIDwgbWluICkgbWluID0gYXJyYXlbIGkgXTtcclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4gbWluO1xyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gYXJyYXlNYXgoIGFycmF5ICkge1xyXG5cclxuXHRpZiAoIGFycmF5Lmxlbmd0aCA9PT0gMCApIHJldHVybiAtIEluZmluaXR5O1xyXG5cclxuXHRsZXQgbWF4ID0gYXJyYXlbIDAgXTtcclxuXHJcblx0Zm9yICggbGV0IGkgPSAxLCBsID0gYXJyYXkubGVuZ3RoOyBpIDwgbDsgKysgaSApIHtcclxuXHJcblx0XHRpZiAoIGFycmF5WyBpIF0gPiBtYXggKSBtYXggPSBhcnJheVsgaSBdO1xyXG5cclxuXHR9XHJcblxyXG5cdHJldHVybiBtYXg7XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiBhcnJheU5lZWRzVWludDMyKCBhcnJheSApIHtcclxuXHJcblx0Ly8gYXNzdW1lcyBsYXJnZXIgdmFsdWVzIHVzdWFsbHkgb24gbGFzdFxyXG5cclxuXHRmb3IgKCBsZXQgaSA9IGFycmF5Lmxlbmd0aCAtIDE7IGkgPj0gMDsgLS0gaSApIHtcclxuXHJcblx0XHRpZiAoIGFycmF5WyBpIF0gPj0gNjU1MzUgKSByZXR1cm4gdHJ1ZTsgLy8gYWNjb3VudCBmb3IgUFJJTUlUSVZFX1JFU1RBUlRfRklYRURfSU5ERVgsICMyNDU2NVxyXG5cclxuXHR9XHJcblxyXG5cdHJldHVybiBmYWxzZTtcclxuXHJcbn1cclxuXHJcbmNvbnN0IFRZUEVEX0FSUkFZUyA9IHtcclxuXHRJbnQ4QXJyYXk6IEludDhBcnJheSxcclxuXHRVaW50OEFycmF5OiBVaW50OEFycmF5LFxyXG5cdFVpbnQ4Q2xhbXBlZEFycmF5OiBVaW50OENsYW1wZWRBcnJheSxcclxuXHRJbnQxNkFycmF5OiBJbnQxNkFycmF5LFxyXG5cdFVpbnQxNkFycmF5OiBVaW50MTZBcnJheSxcclxuXHRJbnQzMkFycmF5OiBJbnQzMkFycmF5LFxyXG5cdFVpbnQzMkFycmF5OiBVaW50MzJBcnJheSxcclxuXHRGbG9hdDMyQXJyYXk6IEZsb2F0MzJBcnJheSxcclxuXHRGbG9hdDY0QXJyYXk6IEZsb2F0NjRBcnJheVxyXG59O1xyXG5cclxuZnVuY3Rpb24gZ2V0VHlwZWRBcnJheSggdHlwZSwgYnVmZmVyICkge1xyXG5cclxuXHRyZXR1cm4gbmV3IFRZUEVEX0FSUkFZU1sgdHlwZSBdKCBidWZmZXIgKTtcclxuXHJcbn1cclxuXHJcbmZ1bmN0aW9uIGNyZWF0ZUVsZW1lbnROUyggbmFtZSApIHtcclxuXHJcblx0cmV0dXJuIGRvY3VtZW50LmNyZWF0ZUVsZW1lbnROUyggJ2h0dHA6Ly93d3cudzMub3JnLzE5OTkveGh0bWwnLCBuYW1lICk7XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiBjcmVhdGVDYW52YXNFbGVtZW50KCkge1xyXG5cclxuXHRjb25zdCBjYW52YXMgPSBjcmVhdGVFbGVtZW50TlMoICdjYW52YXMnICk7XHJcblx0Y2FudmFzLnN0eWxlLmRpc3BsYXkgPSAnYmxvY2snO1xyXG5cdHJldHVybiBjYW52YXM7XHJcblxyXG59XHJcblxyXG5jb25zdCBfY2FjaGUgPSB7fTtcclxuXHJcbmZ1bmN0aW9uIHdhcm5PbmNlKCBtZXNzYWdlICkge1xyXG5cclxuXHRpZiAoIG1lc3NhZ2UgaW4gX2NhY2hlICkgcmV0dXJuO1xyXG5cclxuXHRfY2FjaGVbIG1lc3NhZ2UgXSA9IHRydWU7XHJcblxyXG5cdGNvbnNvbGUud2FybiggbWVzc2FnZSApO1xyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgYXJyYXlNaW4sIGFycmF5TWF4LCBhcnJheU5lZWRzVWludDMyLCBnZXRUeXBlZEFycmF5LCBjcmVhdGVFbGVtZW50TlMsIGNyZWF0ZUNhbnZhc0VsZW1lbnQsIHdhcm5PbmNlIH07XHJcbiIsImltcG9ydCB7IFNSR0JDb2xvclNwYWNlLCBMaW5lYXJTUkdCQ29sb3JTcGFjZSwgRGlzcGxheVAzQ29sb3JTcGFjZSwgTGluZWFyRGlzcGxheVAzQ29sb3JTcGFjZSwgUmVjNzA5UHJpbWFyaWVzLCBQM1ByaW1hcmllcywgU1JHQlRyYW5zZmVyLCBMaW5lYXJUcmFuc2ZlciwgTm9Db2xvclNwYWNlLCB9IGZyb20gJy4uL2NvbnN0YW50cy5qcyc7XHJcbmltcG9ydCB7IE1hdHJpeDMgfSBmcm9tICcuL01hdHJpeDMuanMnO1xyXG5cclxuLyoqXHJcbiAqIE1hdHJpY2VzIGNvbnZlcnRpbmcgUDMgPC0+IFJlYy4gNzA5IHByaW1hcmllcywgd2l0aG91dCBnYW11dCBtYXBwaW5nXHJcbiAqIG9yIGNsaXBwaW5nLiBCYXNlZCBvbiBXM0Mgc3BlY2lmaWNhdGlvbnMgZm9yIHNSR0IgYW5kIERpc3BsYXkgUDMsXHJcbiAqIGFuZCBJQ0Mgc3BlY2lmaWNhdGlvbnMgZm9yIHRoZSBENTAgY29ubmVjdGlvbiBzcGFjZS4gVmFsdWVzIGluL291dFxyXG4gKiBhcmUgX2xpbmVhcl8gc1JHQiBhbmQgX2xpbmVhcl8gRGlzcGxheSBQMy5cclxuICpcclxuICogTm90ZSB0aGF0IGJvdGggc1JHQiBhbmQgRGlzcGxheSBQMyB1c2UgdGhlIHNSR0IgdHJhbnNmZXIgZnVuY3Rpb25zLlxyXG4gKlxyXG4gKiBSZWZlcmVuY2U6XHJcbiAqIC0gaHR0cDovL3d3dy5ydXNzZWxsY290dHJlbGwuY29tL3Bob3RvL21hdHJpeENhbGN1bGF0b3IuaHRtXHJcbiAqL1xyXG5cclxuY29uc3QgTElORUFSX1NSR0JfVE9fTElORUFSX0RJU1BMQVlfUDMgPSAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXgzKCkuc2V0KFxyXG5cdDAuODIyNDYyMSwgMC4xNzc1MzgsIDAuMCxcclxuXHQwLjAzMzE5NDEsIDAuOTY2ODA1OCwgMC4wLFxyXG5cdDAuMDE3MDgyNywgMC4wNzIzOTc0LCAwLjkxMDUxOTksXHJcbik7XHJcblxyXG5jb25zdCBMSU5FQVJfRElTUExBWV9QM19UT19MSU5FQVJfU1JHQiA9IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDMoKS5zZXQoXHJcblx0MS4yMjQ5NDAxLCAtIDAuMjI0OTQwNCwgMC4wLFxyXG5cdC0gMC4wNDIwNTY5LCAxLjA0MjA1NzEsIDAuMCxcclxuXHQtIDAuMDE5NjM3NiwgLSAwLjA3ODYzNjEsIDEuMDk4MjczNVxyXG4pO1xyXG5cclxuLyoqXHJcbiAqIERlZmluZXMgc3VwcG9ydGVkIGNvbG9yIHNwYWNlcyBieSB0cmFuc2ZlciBmdW5jdGlvbiBhbmQgcHJpbWFyaWVzLFxyXG4gKiBhbmQgcHJvdmlkZXMgY29udmVyc2lvbnMgdG8vZnJvbSB0aGUgTGluZWFyLXNSR0IgcmVmZXJlbmNlIHNwYWNlLlxyXG4gKi9cclxuY29uc3QgQ09MT1JfU1BBQ0VTID0ge1xyXG5cdFsgTGluZWFyU1JHQkNvbG9yU3BhY2UgXToge1xyXG5cdFx0dHJhbnNmZXI6IExpbmVhclRyYW5zZmVyLFxyXG5cdFx0cHJpbWFyaWVzOiBSZWM3MDlQcmltYXJpZXMsXHJcblx0XHR0b1JlZmVyZW5jZTogKCBjb2xvciApID0+IGNvbG9yLFxyXG5cdFx0ZnJvbVJlZmVyZW5jZTogKCBjb2xvciApID0+IGNvbG9yLFxyXG5cdH0sXHJcblx0WyBTUkdCQ29sb3JTcGFjZSBdOiB7XHJcblx0XHR0cmFuc2ZlcjogU1JHQlRyYW5zZmVyLFxyXG5cdFx0cHJpbWFyaWVzOiBSZWM3MDlQcmltYXJpZXMsXHJcblx0XHR0b1JlZmVyZW5jZTogKCBjb2xvciApID0+IGNvbG9yLmNvbnZlcnRTUkdCVG9MaW5lYXIoKSxcclxuXHRcdGZyb21SZWZlcmVuY2U6ICggY29sb3IgKSA9PiBjb2xvci5jb252ZXJ0TGluZWFyVG9TUkdCKCksXHJcblx0fSxcclxuXHRbIExpbmVhckRpc3BsYXlQM0NvbG9yU3BhY2UgXToge1xyXG5cdFx0dHJhbnNmZXI6IExpbmVhclRyYW5zZmVyLFxyXG5cdFx0cHJpbWFyaWVzOiBQM1ByaW1hcmllcyxcclxuXHRcdHRvUmVmZXJlbmNlOiAoIGNvbG9yICkgPT4gY29sb3IuYXBwbHlNYXRyaXgzKCBMSU5FQVJfRElTUExBWV9QM19UT19MSU5FQVJfU1JHQiApLFxyXG5cdFx0ZnJvbVJlZmVyZW5jZTogKCBjb2xvciApID0+IGNvbG9yLmFwcGx5TWF0cml4MyggTElORUFSX1NSR0JfVE9fTElORUFSX0RJU1BMQVlfUDMgKSxcclxuXHR9LFxyXG5cdFsgRGlzcGxheVAzQ29sb3JTcGFjZSBdOiB7XHJcblx0XHR0cmFuc2ZlcjogU1JHQlRyYW5zZmVyLFxyXG5cdFx0cHJpbWFyaWVzOiBQM1ByaW1hcmllcyxcclxuXHRcdHRvUmVmZXJlbmNlOiAoIGNvbG9yICkgPT4gY29sb3IuY29udmVydFNSR0JUb0xpbmVhcigpLmFwcGx5TWF0cml4MyggTElORUFSX0RJU1BMQVlfUDNfVE9fTElORUFSX1NSR0IgKSxcclxuXHRcdGZyb21SZWZlcmVuY2U6ICggY29sb3IgKSA9PiBjb2xvci5hcHBseU1hdHJpeDMoIExJTkVBUl9TUkdCX1RPX0xJTkVBUl9ESVNQTEFZX1AzICkuY29udmVydExpbmVhclRvU1JHQigpLFxyXG5cdH0sXHJcbn07XHJcblxyXG5jb25zdCBTVVBQT1JURURfV09SS0lOR19DT0xPUl9TUEFDRVMgPSBuZXcgU2V0KCBbIExpbmVhclNSR0JDb2xvclNwYWNlLCBMaW5lYXJEaXNwbGF5UDNDb2xvclNwYWNlIF0gKTtcclxuXHJcbmV4cG9ydCBjb25zdCBDb2xvck1hbmFnZW1lbnQgPSB7XHJcblxyXG5cdGVuYWJsZWQ6IHRydWUsXHJcblxyXG5cdF93b3JraW5nQ29sb3JTcGFjZTogTGluZWFyU1JHQkNvbG9yU3BhY2UsXHJcblxyXG5cdGdldCB3b3JraW5nQ29sb3JTcGFjZSgpIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5fd29ya2luZ0NvbG9yU3BhY2U7XHJcblxyXG5cdH0sXHJcblxyXG5cdHNldCB3b3JraW5nQ29sb3JTcGFjZSggY29sb3JTcGFjZSApIHtcclxuXHJcblx0XHRpZiAoICEgU1VQUE9SVEVEX1dPUktJTkdfQ09MT1JfU1BBQ0VTLmhhcyggY29sb3JTcGFjZSApICkge1xyXG5cclxuXHRcdFx0dGhyb3cgbmV3IEVycm9yKCBgVW5zdXBwb3J0ZWQgd29ya2luZyBjb2xvciBzcGFjZSwgXCIkeyBjb2xvclNwYWNlIH1cIi5gICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMuX3dvcmtpbmdDb2xvclNwYWNlID0gY29sb3JTcGFjZTtcclxuXHJcblx0fSxcclxuXHJcblx0Y29udmVydDogZnVuY3Rpb24gKCBjb2xvciwgc291cmNlQ29sb3JTcGFjZSwgdGFyZ2V0Q29sb3JTcGFjZSApIHtcclxuXHJcblx0XHRpZiAoIHRoaXMuZW5hYmxlZCA9PT0gZmFsc2UgfHwgc291cmNlQ29sb3JTcGFjZSA9PT0gdGFyZ2V0Q29sb3JTcGFjZSB8fCAhIHNvdXJjZUNvbG9yU3BhY2UgfHwgISB0YXJnZXRDb2xvclNwYWNlICkge1xyXG5cclxuXHRcdFx0cmV0dXJuIGNvbG9yO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCBzb3VyY2VUb1JlZmVyZW5jZSA9IENPTE9SX1NQQUNFU1sgc291cmNlQ29sb3JTcGFjZSBdLnRvUmVmZXJlbmNlO1xyXG5cdFx0Y29uc3QgdGFyZ2V0RnJvbVJlZmVyZW5jZSA9IENPTE9SX1NQQUNFU1sgdGFyZ2V0Q29sb3JTcGFjZSBdLmZyb21SZWZlcmVuY2U7XHJcblxyXG5cdFx0cmV0dXJuIHRhcmdldEZyb21SZWZlcmVuY2UoIHNvdXJjZVRvUmVmZXJlbmNlKCBjb2xvciApICk7XHJcblxyXG5cdH0sXHJcblxyXG5cdGZyb21Xb3JraW5nQ29sb3JTcGFjZTogZnVuY3Rpb24gKCBjb2xvciwgdGFyZ2V0Q29sb3JTcGFjZSApIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5jb252ZXJ0KCBjb2xvciwgdGhpcy5fd29ya2luZ0NvbG9yU3BhY2UsIHRhcmdldENvbG9yU3BhY2UgKTtcclxuXHJcblx0fSxcclxuXHJcblx0dG9Xb3JraW5nQ29sb3JTcGFjZTogZnVuY3Rpb24gKCBjb2xvciwgc291cmNlQ29sb3JTcGFjZSApIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5jb252ZXJ0KCBjb2xvciwgc291cmNlQ29sb3JTcGFjZSwgdGhpcy5fd29ya2luZ0NvbG9yU3BhY2UgKTtcclxuXHJcblx0fSxcclxuXHJcblx0Z2V0UHJpbWFyaWVzOiBmdW5jdGlvbiAoIGNvbG9yU3BhY2UgKSB7XHJcblxyXG5cdFx0cmV0dXJuIENPTE9SX1NQQUNFU1sgY29sb3JTcGFjZSBdLnByaW1hcmllcztcclxuXHJcblx0fSxcclxuXHJcblx0Z2V0VHJhbnNmZXI6IGZ1bmN0aW9uICggY29sb3JTcGFjZSApIHtcclxuXHJcblx0XHRpZiAoIGNvbG9yU3BhY2UgPT09IE5vQ29sb3JTcGFjZSApIHJldHVybiBMaW5lYXJUcmFuc2ZlcjtcclxuXHJcblx0XHRyZXR1cm4gQ09MT1JfU1BBQ0VTWyBjb2xvclNwYWNlIF0udHJhbnNmZXI7XHJcblxyXG5cdH0sXHJcblxyXG59O1xyXG5cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBTUkdCVG9MaW5lYXIoIGMgKSB7XHJcblxyXG5cdHJldHVybiAoIGMgPCAwLjA0MDQ1ICkgPyBjICogMC4wNzczOTkzODA4IDogTWF0aC5wb3coIGMgKiAwLjk0Nzg2NzI5ODYgKyAwLjA1MjEzMjcwMTQsIDIuNCApO1xyXG5cclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIExpbmVhclRvU1JHQiggYyApIHtcclxuXHJcblx0cmV0dXJuICggYyA8IDAuMDAzMTMwOCApID8gYyAqIDEyLjkyIDogMS4wNTUgKiAoIE1hdGgucG93KCBjLCAwLjQxNjY2ICkgKSAtIDAuMDU1O1xyXG5cclxufVxyXG4iLCJpbXBvcnQgeyBjcmVhdGVFbGVtZW50TlMgfSBmcm9tICcuLi91dGlscy5qcyc7XHJcbmltcG9ydCB7IFNSR0JUb0xpbmVhciB9IGZyb20gJy4uL21hdGgvQ29sb3JNYW5hZ2VtZW50LmpzJztcclxuXHJcbmxldCBfY2FudmFzO1xyXG5cclxuY2xhc3MgSW1hZ2VVdGlscyB7XHJcblxyXG5cdHN0YXRpYyBnZXREYXRhVVJMKCBpbWFnZSApIHtcclxuXHJcblx0XHRpZiAoIC9eZGF0YTovaS50ZXN0KCBpbWFnZS5zcmMgKSApIHtcclxuXHJcblx0XHRcdHJldHVybiBpbWFnZS5zcmM7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggdHlwZW9mIEhUTUxDYW52YXNFbGVtZW50ID09PSAndW5kZWZpbmVkJyApIHtcclxuXHJcblx0XHRcdHJldHVybiBpbWFnZS5zcmM7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGxldCBjYW52YXM7XHJcblxyXG5cdFx0aWYgKCBpbWFnZSBpbnN0YW5jZW9mIEhUTUxDYW52YXNFbGVtZW50ICkge1xyXG5cclxuXHRcdFx0Y2FudmFzID0gaW1hZ2U7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdGlmICggX2NhbnZhcyA9PT0gdW5kZWZpbmVkICkgX2NhbnZhcyA9IGNyZWF0ZUVsZW1lbnROUyggJ2NhbnZhcycgKTtcclxuXHJcblx0XHRcdF9jYW52YXMud2lkdGggPSBpbWFnZS53aWR0aDtcclxuXHRcdFx0X2NhbnZhcy5oZWlnaHQgPSBpbWFnZS5oZWlnaHQ7XHJcblxyXG5cdFx0XHRjb25zdCBjb250ZXh0ID0gX2NhbnZhcy5nZXRDb250ZXh0KCAnMmQnICk7XHJcblxyXG5cdFx0XHRpZiAoIGltYWdlIGluc3RhbmNlb2YgSW1hZ2VEYXRhICkge1xyXG5cclxuXHRcdFx0XHRjb250ZXh0LnB1dEltYWdlRGF0YSggaW1hZ2UsIDAsIDAgKTtcclxuXHJcblx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdGNvbnRleHQuZHJhd0ltYWdlKCBpbWFnZSwgMCwgMCwgaW1hZ2Uud2lkdGgsIGltYWdlLmhlaWdodCApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Y2FudmFzID0gX2NhbnZhcztcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBjYW52YXMud2lkdGggPiAyMDQ4IHx8IGNhbnZhcy5oZWlnaHQgPiAyMDQ4ICkge1xyXG5cclxuXHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuSW1hZ2VVdGlscy5nZXREYXRhVVJMOiBJbWFnZSBjb252ZXJ0ZWQgdG8ganBnIGZvciBwZXJmb3JtYW5jZSByZWFzb25zJywgaW1hZ2UgKTtcclxuXHJcblx0XHRcdHJldHVybiBjYW52YXMudG9EYXRhVVJMKCAnaW1hZ2UvanBlZycsIDAuNiApO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRyZXR1cm4gY2FudmFzLnRvRGF0YVVSTCggJ2ltYWdlL3BuZycgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0c3RhdGljIHNSR0JUb0xpbmVhciggaW1hZ2UgKSB7XHJcblxyXG5cdFx0aWYgKCAoIHR5cGVvZiBIVE1MSW1hZ2VFbGVtZW50ICE9PSAndW5kZWZpbmVkJyAmJiBpbWFnZSBpbnN0YW5jZW9mIEhUTUxJbWFnZUVsZW1lbnQgKSB8fFxyXG5cdFx0XHQoIHR5cGVvZiBIVE1MQ2FudmFzRWxlbWVudCAhPT0gJ3VuZGVmaW5lZCcgJiYgaW1hZ2UgaW5zdGFuY2VvZiBIVE1MQ2FudmFzRWxlbWVudCApIHx8XHJcblx0XHRcdCggdHlwZW9mIEltYWdlQml0bWFwICE9PSAndW5kZWZpbmVkJyAmJiBpbWFnZSBpbnN0YW5jZW9mIEltYWdlQml0bWFwICkgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBjYW52YXMgPSBjcmVhdGVFbGVtZW50TlMoICdjYW52YXMnICk7XHJcblxyXG5cdFx0XHRjYW52YXMud2lkdGggPSBpbWFnZS53aWR0aDtcclxuXHRcdFx0Y2FudmFzLmhlaWdodCA9IGltYWdlLmhlaWdodDtcclxuXHJcblx0XHRcdGNvbnN0IGNvbnRleHQgPSBjYW52YXMuZ2V0Q29udGV4dCggJzJkJyApO1xyXG5cdFx0XHRjb250ZXh0LmRyYXdJbWFnZSggaW1hZ2UsIDAsIDAsIGltYWdlLndpZHRoLCBpbWFnZS5oZWlnaHQgKTtcclxuXHJcblx0XHRcdGNvbnN0IGltYWdlRGF0YSA9IGNvbnRleHQuZ2V0SW1hZ2VEYXRhKCAwLCAwLCBpbWFnZS53aWR0aCwgaW1hZ2UuaGVpZ2h0ICk7XHJcblx0XHRcdGNvbnN0IGRhdGEgPSBpbWFnZURhdGEuZGF0YTtcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IGRhdGEubGVuZ3RoOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRkYXRhWyBpIF0gPSBTUkdCVG9MaW5lYXIoIGRhdGFbIGkgXSAvIDI1NSApICogMjU1O1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Y29udGV4dC5wdXRJbWFnZURhdGEoIGltYWdlRGF0YSwgMCwgMCApO1xyXG5cclxuXHRcdFx0cmV0dXJuIGNhbnZhcztcclxuXHJcblx0XHR9IGVsc2UgaWYgKCBpbWFnZS5kYXRhICkge1xyXG5cclxuXHRcdFx0Y29uc3QgZGF0YSA9IGltYWdlLmRhdGEuc2xpY2UoIDAgKTtcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IGRhdGEubGVuZ3RoOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRpZiAoIGRhdGEgaW5zdGFuY2VvZiBVaW50OEFycmF5IHx8IGRhdGEgaW5zdGFuY2VvZiBVaW50OENsYW1wZWRBcnJheSApIHtcclxuXHJcblx0XHRcdFx0XHRkYXRhWyBpIF0gPSBNYXRoLmZsb29yKCBTUkdCVG9MaW5lYXIoIGRhdGFbIGkgXSAvIDI1NSApICogMjU1ICk7XHJcblxyXG5cdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0Ly8gYXNzdW1pbmcgZmxvYXRcclxuXHJcblx0XHRcdFx0XHRkYXRhWyBpIF0gPSBTUkdCVG9MaW5lYXIoIGRhdGFbIGkgXSApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRyZXR1cm4ge1xyXG5cdFx0XHRcdGRhdGE6IGRhdGEsXHJcblx0XHRcdFx0d2lkdGg6IGltYWdlLndpZHRoLFxyXG5cdFx0XHRcdGhlaWdodDogaW1hZ2UuaGVpZ2h0XHJcblx0XHRcdH07XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLkltYWdlVXRpbHMuc1JHQlRvTGluZWFyKCk6IFVuc3VwcG9ydGVkIGltYWdlIHR5cGUuIE5vIGNvbG9yIHNwYWNlIGNvbnZlcnNpb24gYXBwbGllZC4nICk7XHJcblx0XHRcdHJldHVybiBpbWFnZTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IEltYWdlVXRpbHMgfTtcclxuIiwiaW1wb3J0IHsgSW1hZ2VVdGlscyB9IGZyb20gJy4uL2V4dHJhcy9JbWFnZVV0aWxzLmpzJztcclxuaW1wb3J0ICogYXMgTWF0aFV0aWxzIGZyb20gJy4uL21hdGgvTWF0aFV0aWxzLmpzJztcclxuXHJcbmxldCBfc291cmNlSWQgPSAwO1xyXG5cclxuY2xhc3MgU291cmNlIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIGRhdGEgPSBudWxsICkge1xyXG5cclxuXHRcdHRoaXMuaXNTb3VyY2UgPSB0cnVlO1xyXG5cclxuXHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eSggdGhpcywgJ2lkJywgeyB2YWx1ZTogX3NvdXJjZUlkICsrIH0gKTtcclxuXHJcblx0XHR0aGlzLnV1aWQgPSBNYXRoVXRpbHMuZ2VuZXJhdGVVVUlEKCk7XHJcblxyXG5cdFx0dGhpcy5kYXRhID0gZGF0YTtcclxuXHRcdHRoaXMuZGF0YVJlYWR5ID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLnZlcnNpb24gPSAwO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldCBuZWVkc1VwZGF0ZSggdmFsdWUgKSB7XHJcblxyXG5cdFx0aWYgKCB2YWx1ZSA9PT0gdHJ1ZSApIHRoaXMudmVyc2lvbiArKztcclxuXHJcblx0fVxyXG5cclxuXHR0b0pTT04oIG1ldGEgKSB7XHJcblxyXG5cdFx0Y29uc3QgaXNSb290T2JqZWN0ID0gKCBtZXRhID09PSB1bmRlZmluZWQgfHwgdHlwZW9mIG1ldGEgPT09ICdzdHJpbmcnICk7XHJcblxyXG5cdFx0aWYgKCAhIGlzUm9vdE9iamVjdCAmJiBtZXRhLmltYWdlc1sgdGhpcy51dWlkIF0gIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdHJldHVybiBtZXRhLmltYWdlc1sgdGhpcy51dWlkIF07XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGNvbnN0IG91dHB1dCA9IHtcclxuXHRcdFx0dXVpZDogdGhpcy51dWlkLFxyXG5cdFx0XHR1cmw6ICcnXHJcblx0XHR9O1xyXG5cclxuXHRcdGNvbnN0IGRhdGEgPSB0aGlzLmRhdGE7XHJcblxyXG5cdFx0aWYgKCBkYXRhICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0bGV0IHVybDtcclxuXHJcblx0XHRcdGlmICggQXJyYXkuaXNBcnJheSggZGF0YSApICkge1xyXG5cclxuXHRcdFx0XHQvLyBjdWJlIHRleHR1cmVcclxuXHJcblx0XHRcdFx0dXJsID0gW107XHJcblxyXG5cdFx0XHRcdGZvciAoIGxldCBpID0gMCwgbCA9IGRhdGEubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0XHRpZiAoIGRhdGFbIGkgXS5pc0RhdGFUZXh0dXJlICkge1xyXG5cclxuXHRcdFx0XHRcdFx0dXJsLnB1c2goIHNlcmlhbGl6ZUltYWdlKCBkYXRhWyBpIF0uaW1hZ2UgKSApO1xyXG5cclxuXHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHR1cmwucHVzaCggc2VyaWFsaXplSW1hZ2UoIGRhdGFbIGkgXSApICk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHQvLyB0ZXh0dXJlXHJcblxyXG5cdFx0XHRcdHVybCA9IHNlcmlhbGl6ZUltYWdlKCBkYXRhICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRvdXRwdXQudXJsID0gdXJsO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoICEgaXNSb290T2JqZWN0ICkge1xyXG5cclxuXHRcdFx0bWV0YS5pbWFnZXNbIHRoaXMudXVpZCBdID0gb3V0cHV0O1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gb3V0cHV0O1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiBzZXJpYWxpemVJbWFnZSggaW1hZ2UgKSB7XHJcblxyXG5cdGlmICggKCB0eXBlb2YgSFRNTEltYWdlRWxlbWVudCAhPT0gJ3VuZGVmaW5lZCcgJiYgaW1hZ2UgaW5zdGFuY2VvZiBIVE1MSW1hZ2VFbGVtZW50ICkgfHxcclxuXHRcdCggdHlwZW9mIEhUTUxDYW52YXNFbGVtZW50ICE9PSAndW5kZWZpbmVkJyAmJiBpbWFnZSBpbnN0YW5jZW9mIEhUTUxDYW52YXNFbGVtZW50ICkgfHxcclxuXHRcdCggdHlwZW9mIEltYWdlQml0bWFwICE9PSAndW5kZWZpbmVkJyAmJiBpbWFnZSBpbnN0YW5jZW9mIEltYWdlQml0bWFwICkgKSB7XHJcblxyXG5cdFx0Ly8gZGVmYXVsdCBpbWFnZXNcclxuXHJcblx0XHRyZXR1cm4gSW1hZ2VVdGlscy5nZXREYXRhVVJMKCBpbWFnZSApO1xyXG5cclxuXHR9IGVsc2Uge1xyXG5cclxuXHRcdGlmICggaW1hZ2UuZGF0YSApIHtcclxuXHJcblx0XHRcdC8vIGltYWdlcyBvZiBEYXRhVGV4dHVyZVxyXG5cclxuXHRcdFx0cmV0dXJuIHtcclxuXHRcdFx0XHRkYXRhOiBBcnJheS5mcm9tKCBpbWFnZS5kYXRhICksXHJcblx0XHRcdFx0d2lkdGg6IGltYWdlLndpZHRoLFxyXG5cdFx0XHRcdGhlaWdodDogaW1hZ2UuaGVpZ2h0LFxyXG5cdFx0XHRcdHR5cGU6IGltYWdlLmRhdGEuY29uc3RydWN0b3IubmFtZVxyXG5cdFx0XHR9O1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5UZXh0dXJlOiBVbmFibGUgdG8gc2VyaWFsaXplIFRleHR1cmUuJyApO1xyXG5cdFx0XHRyZXR1cm4ge307XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBTb3VyY2UgfTtcclxuIiwiaW1wb3J0IHsgRXZlbnREaXNwYXRjaGVyIH0gZnJvbSAnLi4vY29yZS9FdmVudERpc3BhdGNoZXIuanMnO1xyXG5pbXBvcnQge1xyXG5cdE1pcnJvcmVkUmVwZWF0V3JhcHBpbmcsXHJcblx0Q2xhbXBUb0VkZ2VXcmFwcGluZyxcclxuXHRSZXBlYXRXcmFwcGluZyxcclxuXHRVbnNpZ25lZEJ5dGVUeXBlLFxyXG5cdFJHQkFGb3JtYXQsXHJcblx0TGluZWFyTWlwbWFwTGluZWFyRmlsdGVyLFxyXG5cdExpbmVhckZpbHRlcixcclxuXHRVVk1hcHBpbmcsXHJcblx0Tm9Db2xvclNwYWNlLFxyXG59IGZyb20gJy4uL2NvbnN0YW50cy5qcyc7XHJcbmltcG9ydCAqIGFzIE1hdGhVdGlscyBmcm9tICcuLi9tYXRoL01hdGhVdGlscy5qcyc7XHJcbmltcG9ydCB7IFZlY3RvcjIgfSBmcm9tICcuLi9tYXRoL1ZlY3RvcjIuanMnO1xyXG5pbXBvcnQgeyBNYXRyaXgzIH0gZnJvbSAnLi4vbWF0aC9NYXRyaXgzLmpzJztcclxuaW1wb3J0IHsgU291cmNlIH0gZnJvbSAnLi9Tb3VyY2UuanMnO1xyXG5cclxubGV0IF90ZXh0dXJlSWQgPSAwO1xyXG5cclxuY2xhc3MgVGV4dHVyZSBleHRlbmRzIEV2ZW50RGlzcGF0Y2hlciB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBpbWFnZSA9IFRleHR1cmUuREVGQVVMVF9JTUFHRSwgbWFwcGluZyA9IFRleHR1cmUuREVGQVVMVF9NQVBQSU5HLCB3cmFwUyA9IENsYW1wVG9FZGdlV3JhcHBpbmcsIHdyYXBUID0gQ2xhbXBUb0VkZ2VXcmFwcGluZywgbWFnRmlsdGVyID0gTGluZWFyRmlsdGVyLCBtaW5GaWx0ZXIgPSBMaW5lYXJNaXBtYXBMaW5lYXJGaWx0ZXIsIGZvcm1hdCA9IFJHQkFGb3JtYXQsIHR5cGUgPSBVbnNpZ25lZEJ5dGVUeXBlLCBhbmlzb3Ryb3B5ID0gVGV4dHVyZS5ERUZBVUxUX0FOSVNPVFJPUFksIGNvbG9yU3BhY2UgPSBOb0NvbG9yU3BhY2UgKSB7XHJcblxyXG5cdFx0c3VwZXIoKTtcclxuXHJcblx0XHR0aGlzLmlzVGV4dHVyZSA9IHRydWU7XHJcblxyXG5cdFx0T2JqZWN0LmRlZmluZVByb3BlcnR5KCB0aGlzLCAnaWQnLCB7IHZhbHVlOiBfdGV4dHVyZUlkICsrIH0gKTtcclxuXHJcblx0XHR0aGlzLnV1aWQgPSBNYXRoVXRpbHMuZ2VuZXJhdGVVVUlEKCk7XHJcblxyXG5cdFx0dGhpcy5uYW1lID0gJyc7XHJcblxyXG5cdFx0dGhpcy5zb3VyY2UgPSBuZXcgU291cmNlKCBpbWFnZSApO1xyXG5cdFx0dGhpcy5taXBtYXBzID0gW107XHJcblxyXG5cdFx0dGhpcy5tYXBwaW5nID0gbWFwcGluZztcclxuXHRcdHRoaXMuY2hhbm5lbCA9IDA7XHJcblxyXG5cdFx0dGhpcy53cmFwUyA9IHdyYXBTO1xyXG5cdFx0dGhpcy53cmFwVCA9IHdyYXBUO1xyXG5cclxuXHRcdHRoaXMubWFnRmlsdGVyID0gbWFnRmlsdGVyO1xyXG5cdFx0dGhpcy5taW5GaWx0ZXIgPSBtaW5GaWx0ZXI7XHJcblxyXG5cdFx0dGhpcy5hbmlzb3Ryb3B5ID0gYW5pc290cm9weTtcclxuXHJcblx0XHR0aGlzLmZvcm1hdCA9IGZvcm1hdDtcclxuXHRcdHRoaXMuaW50ZXJuYWxGb3JtYXQgPSBudWxsO1xyXG5cdFx0dGhpcy50eXBlID0gdHlwZTtcclxuXHJcblx0XHR0aGlzLm9mZnNldCA9IG5ldyBWZWN0b3IyKCAwLCAwICk7XHJcblx0XHR0aGlzLnJlcGVhdCA9IG5ldyBWZWN0b3IyKCAxLCAxICk7XHJcblx0XHR0aGlzLmNlbnRlciA9IG5ldyBWZWN0b3IyKCAwLCAwICk7XHJcblx0XHR0aGlzLnJvdGF0aW9uID0gMDtcclxuXHJcblx0XHR0aGlzLm1hdHJpeEF1dG9VcGRhdGUgPSB0cnVlO1xyXG5cdFx0dGhpcy5tYXRyaXggPSBuZXcgTWF0cml4MygpO1xyXG5cclxuXHRcdHRoaXMuZ2VuZXJhdGVNaXBtYXBzID0gdHJ1ZTtcclxuXHRcdHRoaXMucHJlbXVsdGlwbHlBbHBoYSA9IGZhbHNlO1xyXG5cdFx0dGhpcy5mbGlwWSA9IHRydWU7XHJcblx0XHR0aGlzLnVucGFja0FsaWdubWVudCA9IDQ7XHQvLyB2YWxpZCB2YWx1ZXM6IDEsIDIsIDQsIDggKHNlZSBodHRwOi8vd3d3Lmtocm9ub3Mub3JnL29wZW5nbGVzL3Nkay9kb2NzL21hbi94aHRtbC9nbFBpeGVsU3RvcmVpLnhtbClcclxuXHJcblx0XHR0aGlzLmNvbG9yU3BhY2UgPSBjb2xvclNwYWNlO1xyXG5cclxuXHRcdHRoaXMudXNlckRhdGEgPSB7fTtcclxuXHJcblx0XHR0aGlzLnZlcnNpb24gPSAwO1xyXG5cdFx0dGhpcy5vblVwZGF0ZSA9IG51bGw7XHJcblxyXG5cdFx0dGhpcy5pc1JlbmRlclRhcmdldFRleHR1cmUgPSBmYWxzZTsgLy8gaW5kaWNhdGVzIHdoZXRoZXIgYSB0ZXh0dXJlIGJlbG9uZ3MgdG8gYSByZW5kZXIgdGFyZ2V0IG9yIG5vdFxyXG5cdFx0dGhpcy5uZWVkc1BNUkVNVXBkYXRlID0gZmFsc2U7IC8vIGluZGljYXRlcyB3aGV0aGVyIHRoaXMgdGV4dHVyZSBzaG91bGQgYmUgcHJvY2Vzc2VkIGJ5IFBNUkVNR2VuZXJhdG9yIG9yIG5vdCAob25seSByZWxldmFudCBmb3IgcmVuZGVyIHRhcmdldCB0ZXh0dXJlcylcclxuXHJcblx0fVxyXG5cclxuXHRnZXQgaW1hZ2UoKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuc291cmNlLmRhdGE7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0IGltYWdlKCB2YWx1ZSA9IG51bGwgKSB7XHJcblxyXG5cdFx0dGhpcy5zb3VyY2UuZGF0YSA9IHZhbHVlO1xyXG5cclxuXHR9XHJcblxyXG5cdHVwZGF0ZU1hdHJpeCgpIHtcclxuXHJcblx0XHR0aGlzLm1hdHJpeC5zZXRVdlRyYW5zZm9ybSggdGhpcy5vZmZzZXQueCwgdGhpcy5vZmZzZXQueSwgdGhpcy5yZXBlYXQueCwgdGhpcy5yZXBlYXQueSwgdGhpcy5yb3RhdGlvbiwgdGhpcy5jZW50ZXIueCwgdGhpcy5jZW50ZXIueSApO1xyXG5cclxuXHR9XHJcblxyXG5cdGNsb25lKCkge1xyXG5cclxuXHRcdHJldHVybiBuZXcgdGhpcy5jb25zdHJ1Y3RvcigpLmNvcHkoIHRoaXMgKTtcclxuXHJcblx0fVxyXG5cclxuXHRjb3B5KCBzb3VyY2UgKSB7XHJcblxyXG5cdFx0dGhpcy5uYW1lID0gc291cmNlLm5hbWU7XHJcblxyXG5cdFx0dGhpcy5zb3VyY2UgPSBzb3VyY2Uuc291cmNlO1xyXG5cdFx0dGhpcy5taXBtYXBzID0gc291cmNlLm1pcG1hcHMuc2xpY2UoIDAgKTtcclxuXHJcblx0XHR0aGlzLm1hcHBpbmcgPSBzb3VyY2UubWFwcGluZztcclxuXHRcdHRoaXMuY2hhbm5lbCA9IHNvdXJjZS5jaGFubmVsO1xyXG5cclxuXHRcdHRoaXMud3JhcFMgPSBzb3VyY2Uud3JhcFM7XHJcblx0XHR0aGlzLndyYXBUID0gc291cmNlLndyYXBUO1xyXG5cclxuXHRcdHRoaXMubWFnRmlsdGVyID0gc291cmNlLm1hZ0ZpbHRlcjtcclxuXHRcdHRoaXMubWluRmlsdGVyID0gc291cmNlLm1pbkZpbHRlcjtcclxuXHJcblx0XHR0aGlzLmFuaXNvdHJvcHkgPSBzb3VyY2UuYW5pc290cm9weTtcclxuXHJcblx0XHR0aGlzLmZvcm1hdCA9IHNvdXJjZS5mb3JtYXQ7XHJcblx0XHR0aGlzLmludGVybmFsRm9ybWF0ID0gc291cmNlLmludGVybmFsRm9ybWF0O1xyXG5cdFx0dGhpcy50eXBlID0gc291cmNlLnR5cGU7XHJcblxyXG5cdFx0dGhpcy5vZmZzZXQuY29weSggc291cmNlLm9mZnNldCApO1xyXG5cdFx0dGhpcy5yZXBlYXQuY29weSggc291cmNlLnJlcGVhdCApO1xyXG5cdFx0dGhpcy5jZW50ZXIuY29weSggc291cmNlLmNlbnRlciApO1xyXG5cdFx0dGhpcy5yb3RhdGlvbiA9IHNvdXJjZS5yb3RhdGlvbjtcclxuXHJcblx0XHR0aGlzLm1hdHJpeEF1dG9VcGRhdGUgPSBzb3VyY2UubWF0cml4QXV0b1VwZGF0ZTtcclxuXHRcdHRoaXMubWF0cml4LmNvcHkoIHNvdXJjZS5tYXRyaXggKTtcclxuXHJcblx0XHR0aGlzLmdlbmVyYXRlTWlwbWFwcyA9IHNvdXJjZS5nZW5lcmF0ZU1pcG1hcHM7XHJcblx0XHR0aGlzLnByZW11bHRpcGx5QWxwaGEgPSBzb3VyY2UucHJlbXVsdGlwbHlBbHBoYTtcclxuXHRcdHRoaXMuZmxpcFkgPSBzb3VyY2UuZmxpcFk7XHJcblx0XHR0aGlzLnVucGFja0FsaWdubWVudCA9IHNvdXJjZS51bnBhY2tBbGlnbm1lbnQ7XHJcblx0XHR0aGlzLmNvbG9yU3BhY2UgPSBzb3VyY2UuY29sb3JTcGFjZTtcclxuXHJcblx0XHR0aGlzLnVzZXJEYXRhID0gSlNPTi5wYXJzZSggSlNPTi5zdHJpbmdpZnkoIHNvdXJjZS51c2VyRGF0YSApICk7XHJcblxyXG5cdFx0dGhpcy5uZWVkc1VwZGF0ZSA9IHRydWU7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0dG9KU09OKCBtZXRhICkge1xyXG5cclxuXHRcdGNvbnN0IGlzUm9vdE9iamVjdCA9ICggbWV0YSA9PT0gdW5kZWZpbmVkIHx8IHR5cGVvZiBtZXRhID09PSAnc3RyaW5nJyApO1xyXG5cclxuXHRcdGlmICggISBpc1Jvb3RPYmplY3QgJiYgbWV0YS50ZXh0dXJlc1sgdGhpcy51dWlkIF0gIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdHJldHVybiBtZXRhLnRleHR1cmVzWyB0aGlzLnV1aWQgXTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Y29uc3Qgb3V0cHV0ID0ge1xyXG5cclxuXHRcdFx0bWV0YWRhdGE6IHtcclxuXHRcdFx0XHR2ZXJzaW9uOiA0LjYsXHJcblx0XHRcdFx0dHlwZTogJ1RleHR1cmUnLFxyXG5cdFx0XHRcdGdlbmVyYXRvcjogJ1RleHR1cmUudG9KU09OJ1xyXG5cdFx0XHR9LFxyXG5cclxuXHRcdFx0dXVpZDogdGhpcy51dWlkLFxyXG5cdFx0XHRuYW1lOiB0aGlzLm5hbWUsXHJcblxyXG5cdFx0XHRpbWFnZTogdGhpcy5zb3VyY2UudG9KU09OKCBtZXRhICkudXVpZCxcclxuXHJcblx0XHRcdG1hcHBpbmc6IHRoaXMubWFwcGluZyxcclxuXHRcdFx0Y2hhbm5lbDogdGhpcy5jaGFubmVsLFxyXG5cclxuXHRcdFx0cmVwZWF0OiBbIHRoaXMucmVwZWF0LngsIHRoaXMucmVwZWF0LnkgXSxcclxuXHRcdFx0b2Zmc2V0OiBbIHRoaXMub2Zmc2V0LngsIHRoaXMub2Zmc2V0LnkgXSxcclxuXHRcdFx0Y2VudGVyOiBbIHRoaXMuY2VudGVyLngsIHRoaXMuY2VudGVyLnkgXSxcclxuXHRcdFx0cm90YXRpb246IHRoaXMucm90YXRpb24sXHJcblxyXG5cdFx0XHR3cmFwOiBbIHRoaXMud3JhcFMsIHRoaXMud3JhcFQgXSxcclxuXHJcblx0XHRcdGZvcm1hdDogdGhpcy5mb3JtYXQsXHJcblx0XHRcdGludGVybmFsRm9ybWF0OiB0aGlzLmludGVybmFsRm9ybWF0LFxyXG5cdFx0XHR0eXBlOiB0aGlzLnR5cGUsXHJcblx0XHRcdGNvbG9yU3BhY2U6IHRoaXMuY29sb3JTcGFjZSxcclxuXHJcblx0XHRcdG1pbkZpbHRlcjogdGhpcy5taW5GaWx0ZXIsXHJcblx0XHRcdG1hZ0ZpbHRlcjogdGhpcy5tYWdGaWx0ZXIsXHJcblx0XHRcdGFuaXNvdHJvcHk6IHRoaXMuYW5pc290cm9weSxcclxuXHJcblx0XHRcdGZsaXBZOiB0aGlzLmZsaXBZLFxyXG5cclxuXHRcdFx0Z2VuZXJhdGVNaXBtYXBzOiB0aGlzLmdlbmVyYXRlTWlwbWFwcyxcclxuXHRcdFx0cHJlbXVsdGlwbHlBbHBoYTogdGhpcy5wcmVtdWx0aXBseUFscGhhLFxyXG5cdFx0XHR1bnBhY2tBbGlnbm1lbnQ6IHRoaXMudW5wYWNrQWxpZ25tZW50XHJcblxyXG5cdFx0fTtcclxuXHJcblx0XHRpZiAoIE9iamVjdC5rZXlzKCB0aGlzLnVzZXJEYXRhICkubGVuZ3RoID4gMCApIG91dHB1dC51c2VyRGF0YSA9IHRoaXMudXNlckRhdGE7XHJcblxyXG5cdFx0aWYgKCAhIGlzUm9vdE9iamVjdCApIHtcclxuXHJcblx0XHRcdG1ldGEudGV4dHVyZXNbIHRoaXMudXVpZCBdID0gb3V0cHV0O1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gb3V0cHV0O1xyXG5cclxuXHR9XHJcblxyXG5cdGRpc3Bvc2UoKSB7XHJcblxyXG5cdFx0dGhpcy5kaXNwYXRjaEV2ZW50KCB7IHR5cGU6ICdkaXNwb3NlJyB9ICk7XHJcblxyXG5cdH1cclxuXHJcblx0dHJhbnNmb3JtVXYoIHV2ICkge1xyXG5cclxuXHRcdGlmICggdGhpcy5tYXBwaW5nICE9PSBVVk1hcHBpbmcgKSByZXR1cm4gdXY7XHJcblxyXG5cdFx0dXYuYXBwbHlNYXRyaXgzKCB0aGlzLm1hdHJpeCApO1xyXG5cclxuXHRcdGlmICggdXYueCA8IDAgfHwgdXYueCA+IDEgKSB7XHJcblxyXG5cdFx0XHRzd2l0Y2ggKCB0aGlzLndyYXBTICkge1xyXG5cclxuXHRcdFx0XHRjYXNlIFJlcGVhdFdyYXBwaW5nOlxyXG5cclxuXHRcdFx0XHRcdHV2LnggPSB1di54IC0gTWF0aC5mbG9vciggdXYueCApO1xyXG5cdFx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRcdGNhc2UgQ2xhbXBUb0VkZ2VXcmFwcGluZzpcclxuXHJcblx0XHRcdFx0XHR1di54ID0gdXYueCA8IDAgPyAwIDogMTtcclxuXHRcdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0XHRjYXNlIE1pcnJvcmVkUmVwZWF0V3JhcHBpbmc6XHJcblxyXG5cdFx0XHRcdFx0aWYgKCBNYXRoLmFicyggTWF0aC5mbG9vciggdXYueCApICUgMiApID09PSAxICkge1xyXG5cclxuXHRcdFx0XHRcdFx0dXYueCA9IE1hdGguY2VpbCggdXYueCApIC0gdXYueDtcclxuXHJcblx0XHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdFx0dXYueCA9IHV2LnggLSBNYXRoLmZsb29yKCB1di54ICk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHV2LnkgPCAwIHx8IHV2LnkgPiAxICkge1xyXG5cclxuXHRcdFx0c3dpdGNoICggdGhpcy53cmFwVCApIHtcclxuXHJcblx0XHRcdFx0Y2FzZSBSZXBlYXRXcmFwcGluZzpcclxuXHJcblx0XHRcdFx0XHR1di55ID0gdXYueSAtIE1hdGguZmxvb3IoIHV2LnkgKTtcclxuXHRcdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0XHRjYXNlIENsYW1wVG9FZGdlV3JhcHBpbmc6XHJcblxyXG5cdFx0XHRcdFx0dXYueSA9IHV2LnkgPCAwID8gMCA6IDE7XHJcblx0XHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdFx0Y2FzZSBNaXJyb3JlZFJlcGVhdFdyYXBwaW5nOlxyXG5cclxuXHRcdFx0XHRcdGlmICggTWF0aC5hYnMoIE1hdGguZmxvb3IoIHV2LnkgKSAlIDIgKSA9PT0gMSApIHtcclxuXHJcblx0XHRcdFx0XHRcdHV2LnkgPSBNYXRoLmNlaWwoIHV2LnkgKSAtIHV2Lnk7XHJcblxyXG5cdFx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRcdHV2LnkgPSB1di55IC0gTWF0aC5mbG9vciggdXYueSApO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCB0aGlzLmZsaXBZICkge1xyXG5cclxuXHRcdFx0dXYueSA9IDEgLSB1di55O1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdXY7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0IG5lZWRzVXBkYXRlKCB2YWx1ZSApIHtcclxuXHJcblx0XHRpZiAoIHZhbHVlID09PSB0cnVlICkge1xyXG5cclxuXHRcdFx0dGhpcy52ZXJzaW9uICsrO1xyXG5cdFx0XHR0aGlzLnNvdXJjZS5uZWVkc1VwZGF0ZSA9IHRydWU7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5UZXh0dXJlLkRFRkFVTFRfSU1BR0UgPSBudWxsO1xyXG5UZXh0dXJlLkRFRkFVTFRfTUFQUElORyA9IFVWTWFwcGluZztcclxuVGV4dHVyZS5ERUZBVUxUX0FOSVNPVFJPUFkgPSAxO1xyXG5cclxuZXhwb3J0IHsgVGV4dHVyZSB9O1xyXG4iLCJjbGFzcyBWZWN0b3I0IHtcclxuXHJcblx0Y29uc3RydWN0b3IoIHggPSAwLCB5ID0gMCwgeiA9IDAsIHcgPSAxICkge1xyXG5cclxuXHRcdFZlY3RvcjQucHJvdG90eXBlLmlzVmVjdG9yNCA9IHRydWU7XHJcblxyXG5cdFx0dGhpcy54ID0geDtcclxuXHRcdHRoaXMueSA9IHk7XHJcblx0XHR0aGlzLnogPSB6O1xyXG5cdFx0dGhpcy53ID0gdztcclxuXHJcblx0fVxyXG5cclxuXHRnZXQgd2lkdGgoKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuejtcclxuXHJcblx0fVxyXG5cclxuXHRzZXQgd2lkdGgoIHZhbHVlICkge1xyXG5cclxuXHRcdHRoaXMueiA9IHZhbHVlO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldCBoZWlnaHQoKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMudztcclxuXHJcblx0fVxyXG5cclxuXHRzZXQgaGVpZ2h0KCB2YWx1ZSApIHtcclxuXHJcblx0XHR0aGlzLncgPSB2YWx1ZTtcclxuXHJcblx0fVxyXG5cclxuXHRzZXQoIHgsIHksIHosIHcgKSB7XHJcblxyXG5cdFx0dGhpcy54ID0geDtcclxuXHRcdHRoaXMueSA9IHk7XHJcblx0XHR0aGlzLnogPSB6O1xyXG5cdFx0dGhpcy53ID0gdztcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRTY2FsYXIoIHNjYWxhciApIHtcclxuXHJcblx0XHR0aGlzLnggPSBzY2FsYXI7XHJcblx0XHR0aGlzLnkgPSBzY2FsYXI7XHJcblx0XHR0aGlzLnogPSBzY2FsYXI7XHJcblx0XHR0aGlzLncgPSBzY2FsYXI7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0WCggeCApIHtcclxuXHJcblx0XHR0aGlzLnggPSB4O1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldFkoIHkgKSB7XHJcblxyXG5cdFx0dGhpcy55ID0geTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRaKCB6ICkge1xyXG5cclxuXHRcdHRoaXMueiA9IHo7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0VyggdyApIHtcclxuXHJcblx0XHR0aGlzLncgPSB3O1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldENvbXBvbmVudCggaW5kZXgsIHZhbHVlICkge1xyXG5cclxuXHRcdHN3aXRjaCAoIGluZGV4ICkge1xyXG5cclxuXHRcdFx0Y2FzZSAwOiB0aGlzLnggPSB2YWx1ZTsgYnJlYWs7XHJcblx0XHRcdGNhc2UgMTogdGhpcy55ID0gdmFsdWU7IGJyZWFrO1xyXG5cdFx0XHRjYXNlIDI6IHRoaXMueiA9IHZhbHVlOyBicmVhaztcclxuXHRcdFx0Y2FzZSAzOiB0aGlzLncgPSB2YWx1ZTsgYnJlYWs7XHJcblx0XHRcdGRlZmF1bHQ6IHRocm93IG5ldyBFcnJvciggJ2luZGV4IGlzIG91dCBvZiByYW5nZTogJyArIGluZGV4ICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldENvbXBvbmVudCggaW5kZXggKSB7XHJcblxyXG5cdFx0c3dpdGNoICggaW5kZXggKSB7XHJcblxyXG5cdFx0XHRjYXNlIDA6IHJldHVybiB0aGlzLng7XHJcblx0XHRcdGNhc2UgMTogcmV0dXJuIHRoaXMueTtcclxuXHRcdFx0Y2FzZSAyOiByZXR1cm4gdGhpcy56O1xyXG5cdFx0XHRjYXNlIDM6IHJldHVybiB0aGlzLnc7XHJcblx0XHRcdGRlZmF1bHQ6IHRocm93IG5ldyBFcnJvciggJ2luZGV4IGlzIG91dCBvZiByYW5nZTogJyArIGluZGV4ICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGNsb25lKCkge1xyXG5cclxuXHRcdHJldHVybiBuZXcgdGhpcy5jb25zdHJ1Y3RvciggdGhpcy54LCB0aGlzLnksIHRoaXMueiwgdGhpcy53ICk7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggdiApIHtcclxuXHJcblx0XHR0aGlzLnggPSB2Lng7XHJcblx0XHR0aGlzLnkgPSB2Lnk7XHJcblx0XHR0aGlzLnogPSB2Lno7XHJcblx0XHR0aGlzLncgPSAoIHYudyAhPT0gdW5kZWZpbmVkICkgPyB2LncgOiAxO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGFkZCggdiApIHtcclxuXHJcblx0XHR0aGlzLnggKz0gdi54O1xyXG5cdFx0dGhpcy55ICs9IHYueTtcclxuXHRcdHRoaXMueiArPSB2Lno7XHJcblx0XHR0aGlzLncgKz0gdi53O1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGFkZFNjYWxhciggcyApIHtcclxuXHJcblx0XHR0aGlzLnggKz0gcztcclxuXHRcdHRoaXMueSArPSBzO1xyXG5cdFx0dGhpcy56ICs9IHM7XHJcblx0XHR0aGlzLncgKz0gcztcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRhZGRWZWN0b3JzKCBhLCBiICkge1xyXG5cclxuXHRcdHRoaXMueCA9IGEueCArIGIueDtcclxuXHRcdHRoaXMueSA9IGEueSArIGIueTtcclxuXHRcdHRoaXMueiA9IGEueiArIGIuejtcclxuXHRcdHRoaXMudyA9IGEudyArIGIudztcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRhZGRTY2FsZWRWZWN0b3IoIHYsIHMgKSB7XHJcblxyXG5cdFx0dGhpcy54ICs9IHYueCAqIHM7XHJcblx0XHR0aGlzLnkgKz0gdi55ICogcztcclxuXHRcdHRoaXMueiArPSB2LnogKiBzO1xyXG5cdFx0dGhpcy53ICs9IHYudyAqIHM7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0c3ViKCB2ICkge1xyXG5cclxuXHRcdHRoaXMueCAtPSB2Lng7XHJcblx0XHR0aGlzLnkgLT0gdi55O1xyXG5cdFx0dGhpcy56IC09IHYuejtcclxuXHRcdHRoaXMudyAtPSB2Lnc7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0c3ViU2NhbGFyKCBzICkge1xyXG5cclxuXHRcdHRoaXMueCAtPSBzO1xyXG5cdFx0dGhpcy55IC09IHM7XHJcblx0XHR0aGlzLnogLT0gcztcclxuXHRcdHRoaXMudyAtPSBzO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHN1YlZlY3RvcnMoIGEsIGIgKSB7XHJcblxyXG5cdFx0dGhpcy54ID0gYS54IC0gYi54O1xyXG5cdFx0dGhpcy55ID0gYS55IC0gYi55O1xyXG5cdFx0dGhpcy56ID0gYS56IC0gYi56O1xyXG5cdFx0dGhpcy53ID0gYS53IC0gYi53O1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdG11bHRpcGx5KCB2ICkge1xyXG5cclxuXHRcdHRoaXMueCAqPSB2Lng7XHJcblx0XHR0aGlzLnkgKj0gdi55O1xyXG5cdFx0dGhpcy56ICo9IHYuejtcclxuXHRcdHRoaXMudyAqPSB2Lnc7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0bXVsdGlwbHlTY2FsYXIoIHNjYWxhciApIHtcclxuXHJcblx0XHR0aGlzLnggKj0gc2NhbGFyO1xyXG5cdFx0dGhpcy55ICo9IHNjYWxhcjtcclxuXHRcdHRoaXMueiAqPSBzY2FsYXI7XHJcblx0XHR0aGlzLncgKj0gc2NhbGFyO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGFwcGx5TWF0cml4NCggbSApIHtcclxuXHJcblx0XHRjb25zdCB4ID0gdGhpcy54LCB5ID0gdGhpcy55LCB6ID0gdGhpcy56LCB3ID0gdGhpcy53O1xyXG5cdFx0Y29uc3QgZSA9IG0uZWxlbWVudHM7XHJcblxyXG5cdFx0dGhpcy54ID0gZVsgMCBdICogeCArIGVbIDQgXSAqIHkgKyBlWyA4IF0gKiB6ICsgZVsgMTIgXSAqIHc7XHJcblx0XHR0aGlzLnkgPSBlWyAxIF0gKiB4ICsgZVsgNSBdICogeSArIGVbIDkgXSAqIHogKyBlWyAxMyBdICogdztcclxuXHRcdHRoaXMueiA9IGVbIDIgXSAqIHggKyBlWyA2IF0gKiB5ICsgZVsgMTAgXSAqIHogKyBlWyAxNCBdICogdztcclxuXHRcdHRoaXMudyA9IGVbIDMgXSAqIHggKyBlWyA3IF0gKiB5ICsgZVsgMTEgXSAqIHogKyBlWyAxNSBdICogdztcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRkaXZpZGVTY2FsYXIoIHNjYWxhciApIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5tdWx0aXBseVNjYWxhciggMSAvIHNjYWxhciApO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldEF4aXNBbmdsZUZyb21RdWF0ZXJuaW9uKCBxICkge1xyXG5cclxuXHRcdC8vIGh0dHA6Ly93d3cuZXVjbGlkZWFuc3BhY2UuY29tL21hdGhzL2dlb21ldHJ5L3JvdGF0aW9ucy9jb252ZXJzaW9ucy9xdWF0ZXJuaW9uVG9BbmdsZS9pbmRleC5odG1cclxuXHJcblx0XHQvLyBxIGlzIGFzc3VtZWQgdG8gYmUgbm9ybWFsaXplZFxyXG5cclxuXHRcdHRoaXMudyA9IDIgKiBNYXRoLmFjb3MoIHEudyApO1xyXG5cclxuXHRcdGNvbnN0IHMgPSBNYXRoLnNxcnQoIDEgLSBxLncgKiBxLncgKTtcclxuXHJcblx0XHRpZiAoIHMgPCAwLjAwMDEgKSB7XHJcblxyXG5cdFx0XHR0aGlzLnggPSAxO1xyXG5cdFx0XHR0aGlzLnkgPSAwO1xyXG5cdFx0XHR0aGlzLnogPSAwO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHR0aGlzLnggPSBxLnggLyBzO1xyXG5cdFx0XHR0aGlzLnkgPSBxLnkgLyBzO1xyXG5cdFx0XHR0aGlzLnogPSBxLnogLyBzO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRBeGlzQW5nbGVGcm9tUm90YXRpb25NYXRyaXgoIG0gKSB7XHJcblxyXG5cdFx0Ly8gaHR0cDovL3d3dy5ldWNsaWRlYW5zcGFjZS5jb20vbWF0aHMvZ2VvbWV0cnkvcm90YXRpb25zL2NvbnZlcnNpb25zL21hdHJpeFRvQW5nbGUvaW5kZXguaHRtXHJcblxyXG5cdFx0Ly8gYXNzdW1lcyB0aGUgdXBwZXIgM3gzIG9mIG0gaXMgYSBwdXJlIHJvdGF0aW9uIG1hdHJpeCAoaS5lLCB1bnNjYWxlZClcclxuXHJcblx0XHRsZXQgYW5nbGUsIHgsIHksIHo7IC8vIHZhcmlhYmxlcyBmb3IgcmVzdWx0XHJcblx0XHRjb25zdCBlcHNpbG9uID0gMC4wMSxcdFx0Ly8gbWFyZ2luIHRvIGFsbG93IGZvciByb3VuZGluZyBlcnJvcnNcclxuXHRcdFx0ZXBzaWxvbjIgPSAwLjEsXHRcdC8vIG1hcmdpbiB0byBkaXN0aW5ndWlzaCBiZXR3ZWVuIDAgYW5kIDE4MCBkZWdyZWVzXHJcblxyXG5cdFx0XHR0ZSA9IG0uZWxlbWVudHMsXHJcblxyXG5cdFx0XHRtMTEgPSB0ZVsgMCBdLCBtMTIgPSB0ZVsgNCBdLCBtMTMgPSB0ZVsgOCBdLFxyXG5cdFx0XHRtMjEgPSB0ZVsgMSBdLCBtMjIgPSB0ZVsgNSBdLCBtMjMgPSB0ZVsgOSBdLFxyXG5cdFx0XHRtMzEgPSB0ZVsgMiBdLCBtMzIgPSB0ZVsgNiBdLCBtMzMgPSB0ZVsgMTAgXTtcclxuXHJcblx0XHRpZiAoICggTWF0aC5hYnMoIG0xMiAtIG0yMSApIDwgZXBzaWxvbiApICYmXHJcblx0XHQgICAgICggTWF0aC5hYnMoIG0xMyAtIG0zMSApIDwgZXBzaWxvbiApICYmXHJcblx0XHQgICAgICggTWF0aC5hYnMoIG0yMyAtIG0zMiApIDwgZXBzaWxvbiApICkge1xyXG5cclxuXHRcdFx0Ly8gc2luZ3VsYXJpdHkgZm91bmRcclxuXHRcdFx0Ly8gZmlyc3QgY2hlY2sgZm9yIGlkZW50aXR5IG1hdHJpeCB3aGljaCBtdXN0IGhhdmUgKzEgZm9yIGFsbCB0ZXJtc1xyXG5cdFx0XHQvLyBpbiBsZWFkaW5nIGRpYWdvbmFsIGFuZCB6ZXJvIGluIG90aGVyIHRlcm1zXHJcblxyXG5cdFx0XHRpZiAoICggTWF0aC5hYnMoIG0xMiArIG0yMSApIDwgZXBzaWxvbjIgKSAmJlxyXG5cdFx0XHQgICAgICggTWF0aC5hYnMoIG0xMyArIG0zMSApIDwgZXBzaWxvbjIgKSAmJlxyXG5cdFx0XHQgICAgICggTWF0aC5hYnMoIG0yMyArIG0zMiApIDwgZXBzaWxvbjIgKSAmJlxyXG5cdFx0XHQgICAgICggTWF0aC5hYnMoIG0xMSArIG0yMiArIG0zMyAtIDMgKSA8IGVwc2lsb24yICkgKSB7XHJcblxyXG5cdFx0XHRcdC8vIHRoaXMgc2luZ3VsYXJpdHkgaXMgaWRlbnRpdHkgbWF0cml4IHNvIGFuZ2xlID0gMFxyXG5cclxuXHRcdFx0XHR0aGlzLnNldCggMSwgMCwgMCwgMCApO1xyXG5cclxuXHRcdFx0XHRyZXR1cm4gdGhpczsgLy8gemVybyBhbmdsZSwgYXJiaXRyYXJ5IGF4aXNcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdC8vIG90aGVyd2lzZSB0aGlzIHNpbmd1bGFyaXR5IGlzIGFuZ2xlID0gMTgwXHJcblxyXG5cdFx0XHRhbmdsZSA9IE1hdGguUEk7XHJcblxyXG5cdFx0XHRjb25zdCB4eCA9ICggbTExICsgMSApIC8gMjtcclxuXHRcdFx0Y29uc3QgeXkgPSAoIG0yMiArIDEgKSAvIDI7XHJcblx0XHRcdGNvbnN0IHp6ID0gKCBtMzMgKyAxICkgLyAyO1xyXG5cdFx0XHRjb25zdCB4eSA9ICggbTEyICsgbTIxICkgLyA0O1xyXG5cdFx0XHRjb25zdCB4eiA9ICggbTEzICsgbTMxICkgLyA0O1xyXG5cdFx0XHRjb25zdCB5eiA9ICggbTIzICsgbTMyICkgLyA0O1xyXG5cclxuXHRcdFx0aWYgKCAoIHh4ID4geXkgKSAmJiAoIHh4ID4genogKSApIHtcclxuXHJcblx0XHRcdFx0Ly8gbTExIGlzIHRoZSBsYXJnZXN0IGRpYWdvbmFsIHRlcm1cclxuXHJcblx0XHRcdFx0aWYgKCB4eCA8IGVwc2lsb24gKSB7XHJcblxyXG5cdFx0XHRcdFx0eCA9IDA7XHJcblx0XHRcdFx0XHR5ID0gMC43MDcxMDY3ODE7XHJcblx0XHRcdFx0XHR6ID0gMC43MDcxMDY3ODE7XHJcblxyXG5cdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0eCA9IE1hdGguc3FydCggeHggKTtcclxuXHRcdFx0XHRcdHkgPSB4eSAvIHg7XHJcblx0XHRcdFx0XHR6ID0geHogLyB4O1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9IGVsc2UgaWYgKCB5eSA+IHp6ICkge1xyXG5cclxuXHRcdFx0XHQvLyBtMjIgaXMgdGhlIGxhcmdlc3QgZGlhZ29uYWwgdGVybVxyXG5cclxuXHRcdFx0XHRpZiAoIHl5IDwgZXBzaWxvbiApIHtcclxuXHJcblx0XHRcdFx0XHR4ID0gMC43MDcxMDY3ODE7XHJcblx0XHRcdFx0XHR5ID0gMDtcclxuXHRcdFx0XHRcdHogPSAwLjcwNzEwNjc4MTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHR5ID0gTWF0aC5zcXJ0KCB5eSApO1xyXG5cdFx0XHRcdFx0eCA9IHh5IC8geTtcclxuXHRcdFx0XHRcdHogPSB5eiAvIHk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdC8vIG0zMyBpcyB0aGUgbGFyZ2VzdCBkaWFnb25hbCB0ZXJtIHNvIGJhc2UgcmVzdWx0IG9uIHRoaXNcclxuXHJcblx0XHRcdFx0aWYgKCB6eiA8IGVwc2lsb24gKSB7XHJcblxyXG5cdFx0XHRcdFx0eCA9IDAuNzA3MTA2NzgxO1xyXG5cdFx0XHRcdFx0eSA9IDAuNzA3MTA2NzgxO1xyXG5cdFx0XHRcdFx0eiA9IDA7XHJcblxyXG5cdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0eiA9IE1hdGguc3FydCggenogKTtcclxuXHRcdFx0XHRcdHggPSB4eiAvIHo7XHJcblx0XHRcdFx0XHR5ID0geXogLyB6O1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHR0aGlzLnNldCggeCwgeSwgeiwgYW5nbGUgKTtcclxuXHJcblx0XHRcdHJldHVybiB0aGlzOyAvLyByZXR1cm4gMTgwIGRlZyByb3RhdGlvblxyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvLyBhcyB3ZSBoYXZlIHJlYWNoZWQgaGVyZSB0aGVyZSBhcmUgbm8gc2luZ3VsYXJpdGllcyBzbyB3ZSBjYW4gaGFuZGxlIG5vcm1hbGx5XHJcblxyXG5cdFx0bGV0IHMgPSBNYXRoLnNxcnQoICggbTMyIC0gbTIzICkgKiAoIG0zMiAtIG0yMyApICtcclxuXHRcdFx0KCBtMTMgLSBtMzEgKSAqICggbTEzIC0gbTMxICkgK1xyXG5cdFx0XHQoIG0yMSAtIG0xMiApICogKCBtMjEgLSBtMTIgKSApOyAvLyB1c2VkIHRvIG5vcm1hbGl6ZVxyXG5cclxuXHRcdGlmICggTWF0aC5hYnMoIHMgKSA8IDAuMDAxICkgcyA9IDE7XHJcblxyXG5cdFx0Ly8gcHJldmVudCBkaXZpZGUgYnkgemVybywgc2hvdWxkIG5vdCBoYXBwZW4gaWYgbWF0cml4IGlzIG9ydGhvZ29uYWwgYW5kIHNob3VsZCBiZVxyXG5cdFx0Ly8gY2F1Z2h0IGJ5IHNpbmd1bGFyaXR5IHRlc3QgYWJvdmUsIGJ1dCBJJ3ZlIGxlZnQgaXQgaW4ganVzdCBpbiBjYXNlXHJcblxyXG5cdFx0dGhpcy54ID0gKCBtMzIgLSBtMjMgKSAvIHM7XHJcblx0XHR0aGlzLnkgPSAoIG0xMyAtIG0zMSApIC8gcztcclxuXHRcdHRoaXMueiA9ICggbTIxIC0gbTEyICkgLyBzO1xyXG5cdFx0dGhpcy53ID0gTWF0aC5hY29zKCAoIG0xMSArIG0yMiArIG0zMyAtIDEgKSAvIDIgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRtaW4oIHYgKSB7XHJcblxyXG5cdFx0dGhpcy54ID0gTWF0aC5taW4oIHRoaXMueCwgdi54ICk7XHJcblx0XHR0aGlzLnkgPSBNYXRoLm1pbiggdGhpcy55LCB2LnkgKTtcclxuXHRcdHRoaXMueiA9IE1hdGgubWluKCB0aGlzLnosIHYueiApO1xyXG5cdFx0dGhpcy53ID0gTWF0aC5taW4oIHRoaXMudywgdi53ICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0bWF4KCB2ICkge1xyXG5cclxuXHRcdHRoaXMueCA9IE1hdGgubWF4KCB0aGlzLngsIHYueCApO1xyXG5cdFx0dGhpcy55ID0gTWF0aC5tYXgoIHRoaXMueSwgdi55ICk7XHJcblx0XHR0aGlzLnogPSBNYXRoLm1heCggdGhpcy56LCB2LnogKTtcclxuXHRcdHRoaXMudyA9IE1hdGgubWF4KCB0aGlzLncsIHYudyApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGNsYW1wKCBtaW4sIG1heCApIHtcclxuXHJcblx0XHQvLyBhc3N1bWVzIG1pbiA8IG1heCwgY29tcG9uZW50d2lzZVxyXG5cclxuXHRcdHRoaXMueCA9IE1hdGgubWF4KCBtaW4ueCwgTWF0aC5taW4oIG1heC54LCB0aGlzLnggKSApO1xyXG5cdFx0dGhpcy55ID0gTWF0aC5tYXgoIG1pbi55LCBNYXRoLm1pbiggbWF4LnksIHRoaXMueSApICk7XHJcblx0XHR0aGlzLnogPSBNYXRoLm1heCggbWluLnosIE1hdGgubWluKCBtYXgueiwgdGhpcy56ICkgKTtcclxuXHRcdHRoaXMudyA9IE1hdGgubWF4KCBtaW4udywgTWF0aC5taW4oIG1heC53LCB0aGlzLncgKSApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGNsYW1wU2NhbGFyKCBtaW5WYWwsIG1heFZhbCApIHtcclxuXHJcblx0XHR0aGlzLnggPSBNYXRoLm1heCggbWluVmFsLCBNYXRoLm1pbiggbWF4VmFsLCB0aGlzLnggKSApO1xyXG5cdFx0dGhpcy55ID0gTWF0aC5tYXgoIG1pblZhbCwgTWF0aC5taW4oIG1heFZhbCwgdGhpcy55ICkgKTtcclxuXHRcdHRoaXMueiA9IE1hdGgubWF4KCBtaW5WYWwsIE1hdGgubWluKCBtYXhWYWwsIHRoaXMueiApICk7XHJcblx0XHR0aGlzLncgPSBNYXRoLm1heCggbWluVmFsLCBNYXRoLm1pbiggbWF4VmFsLCB0aGlzLncgKSApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGNsYW1wTGVuZ3RoKCBtaW4sIG1heCApIHtcclxuXHJcblx0XHRjb25zdCBsZW5ndGggPSB0aGlzLmxlbmd0aCgpO1xyXG5cclxuXHRcdHJldHVybiB0aGlzLmRpdmlkZVNjYWxhciggbGVuZ3RoIHx8IDEgKS5tdWx0aXBseVNjYWxhciggTWF0aC5tYXgoIG1pbiwgTWF0aC5taW4oIG1heCwgbGVuZ3RoICkgKSApO1xyXG5cclxuXHR9XHJcblxyXG5cdGZsb29yKCkge1xyXG5cclxuXHRcdHRoaXMueCA9IE1hdGguZmxvb3IoIHRoaXMueCApO1xyXG5cdFx0dGhpcy55ID0gTWF0aC5mbG9vciggdGhpcy55ICk7XHJcblx0XHR0aGlzLnogPSBNYXRoLmZsb29yKCB0aGlzLnogKTtcclxuXHRcdHRoaXMudyA9IE1hdGguZmxvb3IoIHRoaXMudyApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGNlaWwoKSB7XHJcblxyXG5cdFx0dGhpcy54ID0gTWF0aC5jZWlsKCB0aGlzLnggKTtcclxuXHRcdHRoaXMueSA9IE1hdGguY2VpbCggdGhpcy55ICk7XHJcblx0XHR0aGlzLnogPSBNYXRoLmNlaWwoIHRoaXMueiApO1xyXG5cdFx0dGhpcy53ID0gTWF0aC5jZWlsKCB0aGlzLncgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRyb3VuZCgpIHtcclxuXHJcblx0XHR0aGlzLnggPSBNYXRoLnJvdW5kKCB0aGlzLnggKTtcclxuXHRcdHRoaXMueSA9IE1hdGgucm91bmQoIHRoaXMueSApO1xyXG5cdFx0dGhpcy56ID0gTWF0aC5yb3VuZCggdGhpcy56ICk7XHJcblx0XHR0aGlzLncgPSBNYXRoLnJvdW5kKCB0aGlzLncgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRyb3VuZFRvWmVybygpIHtcclxuXHJcblx0XHR0aGlzLnggPSBNYXRoLnRydW5jKCB0aGlzLnggKTtcclxuXHRcdHRoaXMueSA9IE1hdGgudHJ1bmMoIHRoaXMueSApO1xyXG5cdFx0dGhpcy56ID0gTWF0aC50cnVuYyggdGhpcy56ICk7XHJcblx0XHR0aGlzLncgPSBNYXRoLnRydW5jKCB0aGlzLncgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRuZWdhdGUoKSB7XHJcblxyXG5cdFx0dGhpcy54ID0gLSB0aGlzLng7XHJcblx0XHR0aGlzLnkgPSAtIHRoaXMueTtcclxuXHRcdHRoaXMueiA9IC0gdGhpcy56O1xyXG5cdFx0dGhpcy53ID0gLSB0aGlzLnc7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0ZG90KCB2ICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLnggKiB2LnggKyB0aGlzLnkgKiB2LnkgKyB0aGlzLnogKiB2LnogKyB0aGlzLncgKiB2Lnc7XHJcblxyXG5cdH1cclxuXHJcblx0bGVuZ3RoU3EoKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMueCAqIHRoaXMueCArIHRoaXMueSAqIHRoaXMueSArIHRoaXMueiAqIHRoaXMueiArIHRoaXMudyAqIHRoaXMudztcclxuXHJcblx0fVxyXG5cclxuXHRsZW5ndGgoKSB7XHJcblxyXG5cdFx0cmV0dXJuIE1hdGguc3FydCggdGhpcy54ICogdGhpcy54ICsgdGhpcy55ICogdGhpcy55ICsgdGhpcy56ICogdGhpcy56ICsgdGhpcy53ICogdGhpcy53ICk7XHJcblxyXG5cdH1cclxuXHJcblx0bWFuaGF0dGFuTGVuZ3RoKCkge1xyXG5cclxuXHRcdHJldHVybiBNYXRoLmFicyggdGhpcy54ICkgKyBNYXRoLmFicyggdGhpcy55ICkgKyBNYXRoLmFicyggdGhpcy56ICkgKyBNYXRoLmFicyggdGhpcy53ICk7XHJcblxyXG5cdH1cclxuXHJcblx0bm9ybWFsaXplKCkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLmRpdmlkZVNjYWxhciggdGhpcy5sZW5ndGgoKSB8fCAxICk7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0TGVuZ3RoKCBsZW5ndGggKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMubm9ybWFsaXplKCkubXVsdGlwbHlTY2FsYXIoIGxlbmd0aCApO1xyXG5cclxuXHR9XHJcblxyXG5cdGxlcnAoIHYsIGFscGhhICkge1xyXG5cclxuXHRcdHRoaXMueCArPSAoIHYueCAtIHRoaXMueCApICogYWxwaGE7XHJcblx0XHR0aGlzLnkgKz0gKCB2LnkgLSB0aGlzLnkgKSAqIGFscGhhO1xyXG5cdFx0dGhpcy56ICs9ICggdi56IC0gdGhpcy56ICkgKiBhbHBoYTtcclxuXHRcdHRoaXMudyArPSAoIHYudyAtIHRoaXMudyApICogYWxwaGE7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0bGVycFZlY3RvcnMoIHYxLCB2MiwgYWxwaGEgKSB7XHJcblxyXG5cdFx0dGhpcy54ID0gdjEueCArICggdjIueCAtIHYxLnggKSAqIGFscGhhO1xyXG5cdFx0dGhpcy55ID0gdjEueSArICggdjIueSAtIHYxLnkgKSAqIGFscGhhO1xyXG5cdFx0dGhpcy56ID0gdjEueiArICggdjIueiAtIHYxLnogKSAqIGFscGhhO1xyXG5cdFx0dGhpcy53ID0gdjEudyArICggdjIudyAtIHYxLncgKSAqIGFscGhhO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGVxdWFscyggdiApIHtcclxuXHJcblx0XHRyZXR1cm4gKCAoIHYueCA9PT0gdGhpcy54ICkgJiYgKCB2LnkgPT09IHRoaXMueSApICYmICggdi56ID09PSB0aGlzLnogKSAmJiAoIHYudyA9PT0gdGhpcy53ICkgKTtcclxuXHJcblx0fVxyXG5cclxuXHRmcm9tQXJyYXkoIGFycmF5LCBvZmZzZXQgPSAwICkge1xyXG5cclxuXHRcdHRoaXMueCA9IGFycmF5WyBvZmZzZXQgXTtcclxuXHRcdHRoaXMueSA9IGFycmF5WyBvZmZzZXQgKyAxIF07XHJcblx0XHR0aGlzLnogPSBhcnJheVsgb2Zmc2V0ICsgMiBdO1xyXG5cdFx0dGhpcy53ID0gYXJyYXlbIG9mZnNldCArIDMgXTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHR0b0FycmF5KCBhcnJheSA9IFtdLCBvZmZzZXQgPSAwICkge1xyXG5cclxuXHRcdGFycmF5WyBvZmZzZXQgXSA9IHRoaXMueDtcclxuXHRcdGFycmF5WyBvZmZzZXQgKyAxIF0gPSB0aGlzLnk7XHJcblx0XHRhcnJheVsgb2Zmc2V0ICsgMiBdID0gdGhpcy56O1xyXG5cdFx0YXJyYXlbIG9mZnNldCArIDMgXSA9IHRoaXMudztcclxuXHJcblx0XHRyZXR1cm4gYXJyYXk7XHJcblxyXG5cdH1cclxuXHJcblx0ZnJvbUJ1ZmZlckF0dHJpYnV0ZSggYXR0cmlidXRlLCBpbmRleCApIHtcclxuXHJcblx0XHR0aGlzLnggPSBhdHRyaWJ1dGUuZ2V0WCggaW5kZXggKTtcclxuXHRcdHRoaXMueSA9IGF0dHJpYnV0ZS5nZXRZKCBpbmRleCApO1xyXG5cdFx0dGhpcy56ID0gYXR0cmlidXRlLmdldFooIGluZGV4ICk7XHJcblx0XHR0aGlzLncgPSBhdHRyaWJ1dGUuZ2V0VyggaW5kZXggKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRyYW5kb20oKSB7XHJcblxyXG5cdFx0dGhpcy54ID0gTWF0aC5yYW5kb20oKTtcclxuXHRcdHRoaXMueSA9IE1hdGgucmFuZG9tKCk7XHJcblx0XHR0aGlzLnogPSBNYXRoLnJhbmRvbSgpO1xyXG5cdFx0dGhpcy53ID0gTWF0aC5yYW5kb20oKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHQqWyBTeW1ib2wuaXRlcmF0b3IgXSgpIHtcclxuXHJcblx0XHR5aWVsZCB0aGlzLng7XHJcblx0XHR5aWVsZCB0aGlzLnk7XHJcblx0XHR5aWVsZCB0aGlzLno7XHJcblx0XHR5aWVsZCB0aGlzLnc7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IFZlY3RvcjQgfTtcclxuIiwiaW1wb3J0IHsgRXZlbnREaXNwYXRjaGVyIH0gZnJvbSAnLi9FdmVudERpc3BhdGNoZXIuanMnO1xyXG5pbXBvcnQgeyBUZXh0dXJlIH0gZnJvbSAnLi4vdGV4dHVyZXMvVGV4dHVyZS5qcyc7XHJcbmltcG9ydCB7IExpbmVhckZpbHRlciB9IGZyb20gJy4uL2NvbnN0YW50cy5qcyc7XHJcbmltcG9ydCB7IFZlY3RvcjQgfSBmcm9tICcuLi9tYXRoL1ZlY3RvcjQuanMnO1xyXG5pbXBvcnQgeyBTb3VyY2UgfSBmcm9tICcuLi90ZXh0dXJlcy9Tb3VyY2UuanMnO1xyXG5cclxuLypcclxuIEluIG9wdGlvbnMsIHdlIGNhbiBzcGVjaWZ5OlxyXG4gKiBUZXh0dXJlIHBhcmFtZXRlcnMgZm9yIGFuIGF1dG8tZ2VuZXJhdGVkIHRhcmdldCB0ZXh0dXJlXHJcbiAqIGRlcHRoQnVmZmVyL3N0ZW5jaWxCdWZmZXI6IEJvb2xlYW5zIHRvIGluZGljYXRlIGlmIHdlIHNob3VsZCBnZW5lcmF0ZSB0aGVzZSBidWZmZXJzXHJcbiovXHJcbmNsYXNzIFJlbmRlclRhcmdldCBleHRlbmRzIEV2ZW50RGlzcGF0Y2hlciB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCB3aWR0aCA9IDEsIGhlaWdodCA9IDEsIG9wdGlvbnMgPSB7fSApIHtcclxuXHJcblx0XHRzdXBlcigpO1xyXG5cclxuXHRcdHRoaXMuaXNSZW5kZXJUYXJnZXQgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMud2lkdGggPSB3aWR0aDtcclxuXHRcdHRoaXMuaGVpZ2h0ID0gaGVpZ2h0O1xyXG5cdFx0dGhpcy5kZXB0aCA9IDE7XHJcblxyXG5cdFx0dGhpcy5zY2lzc29yID0gbmV3IFZlY3RvcjQoIDAsIDAsIHdpZHRoLCBoZWlnaHQgKTtcclxuXHRcdHRoaXMuc2Npc3NvclRlc3QgPSBmYWxzZTtcclxuXHJcblx0XHR0aGlzLnZpZXdwb3J0ID0gbmV3IFZlY3RvcjQoIDAsIDAsIHdpZHRoLCBoZWlnaHQgKTtcclxuXHJcblx0XHRjb25zdCBpbWFnZSA9IHsgd2lkdGg6IHdpZHRoLCBoZWlnaHQ6IGhlaWdodCwgZGVwdGg6IDEgfTtcclxuXHJcblx0XHRvcHRpb25zID0gT2JqZWN0LmFzc2lnbigge1xyXG5cdFx0XHRnZW5lcmF0ZU1pcG1hcHM6IGZhbHNlLFxyXG5cdFx0XHRpbnRlcm5hbEZvcm1hdDogbnVsbCxcclxuXHRcdFx0bWluRmlsdGVyOiBMaW5lYXJGaWx0ZXIsXHJcblx0XHRcdGRlcHRoQnVmZmVyOiB0cnVlLFxyXG5cdFx0XHRzdGVuY2lsQnVmZmVyOiBmYWxzZSxcclxuXHRcdFx0ZGVwdGhUZXh0dXJlOiBudWxsLFxyXG5cdFx0XHRzYW1wbGVzOiAwXHJcblx0XHR9LCBvcHRpb25zICk7XHJcblxyXG5cdFx0dGhpcy50ZXh0dXJlID0gbmV3IFRleHR1cmUoIGltYWdlLCBvcHRpb25zLm1hcHBpbmcsIG9wdGlvbnMud3JhcFMsIG9wdGlvbnMud3JhcFQsIG9wdGlvbnMubWFnRmlsdGVyLCBvcHRpb25zLm1pbkZpbHRlciwgb3B0aW9ucy5mb3JtYXQsIG9wdGlvbnMudHlwZSwgb3B0aW9ucy5hbmlzb3Ryb3B5LCBvcHRpb25zLmNvbG9yU3BhY2UgKTtcclxuXHRcdHRoaXMudGV4dHVyZS5pc1JlbmRlclRhcmdldFRleHR1cmUgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMudGV4dHVyZS5mbGlwWSA9IGZhbHNlO1xyXG5cdFx0dGhpcy50ZXh0dXJlLmdlbmVyYXRlTWlwbWFwcyA9IG9wdGlvbnMuZ2VuZXJhdGVNaXBtYXBzO1xyXG5cdFx0dGhpcy50ZXh0dXJlLmludGVybmFsRm9ybWF0ID0gb3B0aW9ucy5pbnRlcm5hbEZvcm1hdDtcclxuXHJcblx0XHR0aGlzLmRlcHRoQnVmZmVyID0gb3B0aW9ucy5kZXB0aEJ1ZmZlcjtcclxuXHRcdHRoaXMuc3RlbmNpbEJ1ZmZlciA9IG9wdGlvbnMuc3RlbmNpbEJ1ZmZlcjtcclxuXHJcblx0XHR0aGlzLmRlcHRoVGV4dHVyZSA9IG9wdGlvbnMuZGVwdGhUZXh0dXJlO1xyXG5cclxuXHRcdHRoaXMuc2FtcGxlcyA9IG9wdGlvbnMuc2FtcGxlcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRTaXplKCB3aWR0aCwgaGVpZ2h0LCBkZXB0aCA9IDEgKSB7XHJcblxyXG5cdFx0aWYgKCB0aGlzLndpZHRoICE9PSB3aWR0aCB8fCB0aGlzLmhlaWdodCAhPT0gaGVpZ2h0IHx8IHRoaXMuZGVwdGggIT09IGRlcHRoICkge1xyXG5cclxuXHRcdFx0dGhpcy53aWR0aCA9IHdpZHRoO1xyXG5cdFx0XHR0aGlzLmhlaWdodCA9IGhlaWdodDtcclxuXHRcdFx0dGhpcy5kZXB0aCA9IGRlcHRoO1xyXG5cclxuXHRcdFx0dGhpcy50ZXh0dXJlLmltYWdlLndpZHRoID0gd2lkdGg7XHJcblx0XHRcdHRoaXMudGV4dHVyZS5pbWFnZS5oZWlnaHQgPSBoZWlnaHQ7XHJcblx0XHRcdHRoaXMudGV4dHVyZS5pbWFnZS5kZXB0aCA9IGRlcHRoO1xyXG5cclxuXHRcdFx0dGhpcy5kaXNwb3NlKCk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMudmlld3BvcnQuc2V0KCAwLCAwLCB3aWR0aCwgaGVpZ2h0ICk7XHJcblx0XHR0aGlzLnNjaXNzb3Iuc2V0KCAwLCAwLCB3aWR0aCwgaGVpZ2h0ICk7XHJcblxyXG5cdH1cclxuXHJcblx0Y2xvbmUoKSB7XHJcblxyXG5cdFx0cmV0dXJuIG5ldyB0aGlzLmNvbnN0cnVjdG9yKCkuY29weSggdGhpcyApO1xyXG5cclxuXHR9XHJcblxyXG5cdGNvcHkoIHNvdXJjZSApIHtcclxuXHJcblx0XHR0aGlzLndpZHRoID0gc291cmNlLndpZHRoO1xyXG5cdFx0dGhpcy5oZWlnaHQgPSBzb3VyY2UuaGVpZ2h0O1xyXG5cdFx0dGhpcy5kZXB0aCA9IHNvdXJjZS5kZXB0aDtcclxuXHJcblx0XHR0aGlzLnNjaXNzb3IuY29weSggc291cmNlLnNjaXNzb3IgKTtcclxuXHRcdHRoaXMuc2Npc3NvclRlc3QgPSBzb3VyY2Uuc2Npc3NvclRlc3Q7XHJcblxyXG5cdFx0dGhpcy52aWV3cG9ydC5jb3B5KCBzb3VyY2Uudmlld3BvcnQgKTtcclxuXHJcblx0XHR0aGlzLnRleHR1cmUgPSBzb3VyY2UudGV4dHVyZS5jbG9uZSgpO1xyXG5cdFx0dGhpcy50ZXh0dXJlLmlzUmVuZGVyVGFyZ2V0VGV4dHVyZSA9IHRydWU7XHJcblxyXG5cdFx0Ly8gZW5zdXJlIGltYWdlIG9iamVjdCBpcyBub3Qgc2hhcmVkLCBzZWUgIzIwMzI4XHJcblxyXG5cdFx0Y29uc3QgaW1hZ2UgPSBPYmplY3QuYXNzaWduKCB7fSwgc291cmNlLnRleHR1cmUuaW1hZ2UgKTtcclxuXHRcdHRoaXMudGV4dHVyZS5zb3VyY2UgPSBuZXcgU291cmNlKCBpbWFnZSApO1xyXG5cclxuXHRcdHRoaXMuZGVwdGhCdWZmZXIgPSBzb3VyY2UuZGVwdGhCdWZmZXI7XHJcblx0XHR0aGlzLnN0ZW5jaWxCdWZmZXIgPSBzb3VyY2Uuc3RlbmNpbEJ1ZmZlcjtcclxuXHJcblx0XHRpZiAoIHNvdXJjZS5kZXB0aFRleHR1cmUgIT09IG51bGwgKSB0aGlzLmRlcHRoVGV4dHVyZSA9IHNvdXJjZS5kZXB0aFRleHR1cmUuY2xvbmUoKTtcclxuXHJcblx0XHR0aGlzLnNhbXBsZXMgPSBzb3VyY2Uuc2FtcGxlcztcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRkaXNwb3NlKCkge1xyXG5cclxuXHRcdHRoaXMuZGlzcGF0Y2hFdmVudCggeyB0eXBlOiAnZGlzcG9zZScgfSApO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBSZW5kZXJUYXJnZXQgfTtcclxuIiwiaW1wb3J0IHsgUmVuZGVyVGFyZ2V0IH0gZnJvbSAnLi4vY29yZS9SZW5kZXJUYXJnZXQuanMnO1xyXG5cclxuY2xhc3MgV2ViR0xSZW5kZXJUYXJnZXQgZXh0ZW5kcyBSZW5kZXJUYXJnZXQge1xyXG5cclxuXHRjb25zdHJ1Y3Rvciggd2lkdGggPSAxLCBoZWlnaHQgPSAxLCBvcHRpb25zID0ge30gKSB7XHJcblxyXG5cdFx0c3VwZXIoIHdpZHRoLCBoZWlnaHQsIG9wdGlvbnMgKTtcclxuXHJcblx0XHR0aGlzLmlzV2ViR0xSZW5kZXJUYXJnZXQgPSB0cnVlO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBXZWJHTFJlbmRlclRhcmdldCB9O1xyXG4iLCJpbXBvcnQgeyBUZXh0dXJlIH0gZnJvbSAnLi9UZXh0dXJlLmpzJztcclxuaW1wb3J0IHsgQ2xhbXBUb0VkZ2VXcmFwcGluZywgTmVhcmVzdEZpbHRlciB9IGZyb20gJy4uL2NvbnN0YW50cy5qcyc7XHJcblxyXG5jbGFzcyBEYXRhQXJyYXlUZXh0dXJlIGV4dGVuZHMgVGV4dHVyZSB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBkYXRhID0gbnVsbCwgd2lkdGggPSAxLCBoZWlnaHQgPSAxLCBkZXB0aCA9IDEgKSB7XHJcblxyXG5cdFx0c3VwZXIoIG51bGwgKTtcclxuXHJcblx0XHR0aGlzLmlzRGF0YUFycmF5VGV4dHVyZSA9IHRydWU7XHJcblxyXG5cdFx0dGhpcy5pbWFnZSA9IHsgZGF0YSwgd2lkdGgsIGhlaWdodCwgZGVwdGggfTtcclxuXHJcblx0XHR0aGlzLm1hZ0ZpbHRlciA9IE5lYXJlc3RGaWx0ZXI7XHJcblx0XHR0aGlzLm1pbkZpbHRlciA9IE5lYXJlc3RGaWx0ZXI7XHJcblxyXG5cdFx0dGhpcy53cmFwUiA9IENsYW1wVG9FZGdlV3JhcHBpbmc7XHJcblxyXG5cdFx0dGhpcy5nZW5lcmF0ZU1pcG1hcHMgPSBmYWxzZTtcclxuXHRcdHRoaXMuZmxpcFkgPSBmYWxzZTtcclxuXHRcdHRoaXMudW5wYWNrQWxpZ25tZW50ID0gMTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgRGF0YUFycmF5VGV4dHVyZSB9O1xyXG4iLCJpbXBvcnQgeyBXZWJHTFJlbmRlclRhcmdldCB9IGZyb20gJy4vV2ViR0xSZW5kZXJUYXJnZXQuanMnO1xyXG5pbXBvcnQgeyBEYXRhQXJyYXlUZXh0dXJlIH0gZnJvbSAnLi4vdGV4dHVyZXMvRGF0YUFycmF5VGV4dHVyZS5qcyc7XHJcblxyXG5jbGFzcyBXZWJHTEFycmF5UmVuZGVyVGFyZ2V0IGV4dGVuZHMgV2ViR0xSZW5kZXJUYXJnZXQge1xyXG5cclxuXHRjb25zdHJ1Y3Rvciggd2lkdGggPSAxLCBoZWlnaHQgPSAxLCBkZXB0aCA9IDEsIG9wdGlvbnMgPSB7fSApIHtcclxuXHJcblx0XHRzdXBlciggd2lkdGgsIGhlaWdodCwgb3B0aW9ucyApO1xyXG5cclxuXHRcdHRoaXMuaXNXZWJHTEFycmF5UmVuZGVyVGFyZ2V0ID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLmRlcHRoID0gZGVwdGg7XHJcblxyXG5cdFx0dGhpcy50ZXh0dXJlID0gbmV3IERhdGFBcnJheVRleHR1cmUoIG51bGwsIHdpZHRoLCBoZWlnaHQsIGRlcHRoICk7XHJcblxyXG5cdFx0dGhpcy50ZXh0dXJlLmlzUmVuZGVyVGFyZ2V0VGV4dHVyZSA9IHRydWU7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IFdlYkdMQXJyYXlSZW5kZXJUYXJnZXQgfTtcclxuIiwiaW1wb3J0IHsgVGV4dHVyZSB9IGZyb20gJy4vVGV4dHVyZS5qcyc7XHJcbmltcG9ydCB7IENsYW1wVG9FZGdlV3JhcHBpbmcsIE5lYXJlc3RGaWx0ZXIgfSBmcm9tICcuLi9jb25zdGFudHMuanMnO1xyXG5cclxuY2xhc3MgRGF0YTNEVGV4dHVyZSBleHRlbmRzIFRleHR1cmUge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggZGF0YSA9IG51bGwsIHdpZHRoID0gMSwgaGVpZ2h0ID0gMSwgZGVwdGggPSAxICkge1xyXG5cclxuXHRcdC8vIFdlJ3JlIGdvaW5nIHRvIGFkZCAuc2V0WFhYKCkgbWV0aG9kcyBmb3Igc2V0dGluZyBwcm9wZXJ0aWVzIGxhdGVyLlxyXG5cdFx0Ly8gVXNlcnMgY2FuIHN0aWxsIHNldCBpbiBEYXRhVGV4dHVyZTNEIGRpcmVjdGx5LlxyXG5cdFx0Ly9cclxuXHRcdC8vXHRjb25zdCB0ZXh0dXJlID0gbmV3IFRIUkVFLkRhdGFUZXh0dXJlM0QoIGRhdGEsIHdpZHRoLCBoZWlnaHQsIGRlcHRoICk7XHJcblx0XHQvLyBcdHRleHR1cmUuYW5pc290cm9weSA9IDE2O1xyXG5cdFx0Ly9cclxuXHRcdC8vIFNlZSAjMTQ4MzlcclxuXHJcblx0XHRzdXBlciggbnVsbCApO1xyXG5cclxuXHRcdHRoaXMuaXNEYXRhM0RUZXh0dXJlID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLmltYWdlID0geyBkYXRhLCB3aWR0aCwgaGVpZ2h0LCBkZXB0aCB9O1xyXG5cclxuXHRcdHRoaXMubWFnRmlsdGVyID0gTmVhcmVzdEZpbHRlcjtcclxuXHRcdHRoaXMubWluRmlsdGVyID0gTmVhcmVzdEZpbHRlcjtcclxuXHJcblx0XHR0aGlzLndyYXBSID0gQ2xhbXBUb0VkZ2VXcmFwcGluZztcclxuXHJcblx0XHR0aGlzLmdlbmVyYXRlTWlwbWFwcyA9IGZhbHNlO1xyXG5cdFx0dGhpcy5mbGlwWSA9IGZhbHNlO1xyXG5cdFx0dGhpcy51bnBhY2tBbGlnbm1lbnQgPSAxO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBEYXRhM0RUZXh0dXJlIH07XHJcbiIsImltcG9ydCB7IFdlYkdMUmVuZGVyVGFyZ2V0IH0gZnJvbSAnLi9XZWJHTFJlbmRlclRhcmdldC5qcyc7XHJcbmltcG9ydCB7IERhdGEzRFRleHR1cmUgfSBmcm9tICcuLi90ZXh0dXJlcy9EYXRhM0RUZXh0dXJlLmpzJztcclxuXHJcbmNsYXNzIFdlYkdMM0RSZW5kZXJUYXJnZXQgZXh0ZW5kcyBXZWJHTFJlbmRlclRhcmdldCB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCB3aWR0aCA9IDEsIGhlaWdodCA9IDEsIGRlcHRoID0gMSwgb3B0aW9ucyA9IHt9ICkge1xyXG5cclxuXHRcdHN1cGVyKCB3aWR0aCwgaGVpZ2h0LCBvcHRpb25zICk7XHJcblxyXG5cdFx0dGhpcy5pc1dlYkdMM0RSZW5kZXJUYXJnZXQgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMuZGVwdGggPSBkZXB0aDtcclxuXHJcblx0XHR0aGlzLnRleHR1cmUgPSBuZXcgRGF0YTNEVGV4dHVyZSggbnVsbCwgd2lkdGgsIGhlaWdodCwgZGVwdGggKTtcclxuXHJcblx0XHR0aGlzLnRleHR1cmUuaXNSZW5kZXJUYXJnZXRUZXh0dXJlID0gdHJ1ZTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgV2ViR0wzRFJlbmRlclRhcmdldCB9O1xyXG4iLCJpbXBvcnQgeyBXZWJHTFJlbmRlclRhcmdldCB9IGZyb20gJy4vV2ViR0xSZW5kZXJUYXJnZXQuanMnO1xyXG5cclxuY2xhc3MgV2ViR0xNdWx0aXBsZVJlbmRlclRhcmdldHMgZXh0ZW5kcyBXZWJHTFJlbmRlclRhcmdldCB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCB3aWR0aCA9IDEsIGhlaWdodCA9IDEsIGNvdW50ID0gMSwgb3B0aW9ucyA9IHt9ICkge1xyXG5cclxuXHRcdHN1cGVyKCB3aWR0aCwgaGVpZ2h0LCBvcHRpb25zICk7XHJcblxyXG5cdFx0dGhpcy5pc1dlYkdMTXVsdGlwbGVSZW5kZXJUYXJnZXRzID0gdHJ1ZTtcclxuXHJcblx0XHRjb25zdCB0ZXh0dXJlID0gdGhpcy50ZXh0dXJlO1xyXG5cclxuXHRcdHRoaXMudGV4dHVyZSA9IFtdO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IGNvdW50OyBpICsrICkge1xyXG5cclxuXHRcdFx0dGhpcy50ZXh0dXJlWyBpIF0gPSB0ZXh0dXJlLmNsb25lKCk7XHJcblx0XHRcdHRoaXMudGV4dHVyZVsgaSBdLmlzUmVuZGVyVGFyZ2V0VGV4dHVyZSA9IHRydWU7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdHNldFNpemUoIHdpZHRoLCBoZWlnaHQsIGRlcHRoID0gMSApIHtcclxuXHJcblx0XHRpZiAoIHRoaXMud2lkdGggIT09IHdpZHRoIHx8IHRoaXMuaGVpZ2h0ICE9PSBoZWlnaHQgfHwgdGhpcy5kZXB0aCAhPT0gZGVwdGggKSB7XHJcblxyXG5cdFx0XHR0aGlzLndpZHRoID0gd2lkdGg7XHJcblx0XHRcdHRoaXMuaGVpZ2h0ID0gaGVpZ2h0O1xyXG5cdFx0XHR0aGlzLmRlcHRoID0gZGVwdGg7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gdGhpcy50ZXh0dXJlLmxlbmd0aDsgaSA8IGlsOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHR0aGlzLnRleHR1cmVbIGkgXS5pbWFnZS53aWR0aCA9IHdpZHRoO1xyXG5cdFx0XHRcdHRoaXMudGV4dHVyZVsgaSBdLmltYWdlLmhlaWdodCA9IGhlaWdodDtcclxuXHRcdFx0XHR0aGlzLnRleHR1cmVbIGkgXS5pbWFnZS5kZXB0aCA9IGRlcHRoO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0dGhpcy5kaXNwb3NlKCk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMudmlld3BvcnQuc2V0KCAwLCAwLCB3aWR0aCwgaGVpZ2h0ICk7XHJcblx0XHR0aGlzLnNjaXNzb3Iuc2V0KCAwLCAwLCB3aWR0aCwgaGVpZ2h0ICk7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHRoaXMuZGlzcG9zZSgpO1xyXG5cclxuXHRcdHRoaXMud2lkdGggPSBzb3VyY2Uud2lkdGg7XHJcblx0XHR0aGlzLmhlaWdodCA9IHNvdXJjZS5oZWlnaHQ7XHJcblx0XHR0aGlzLmRlcHRoID0gc291cmNlLmRlcHRoO1xyXG5cclxuXHRcdHRoaXMuc2Npc3Nvci5jb3B5KCBzb3VyY2Uuc2Npc3NvciApO1xyXG5cdFx0dGhpcy5zY2lzc29yVGVzdCA9IHNvdXJjZS5zY2lzc29yVGVzdDtcclxuXHJcblx0XHR0aGlzLnZpZXdwb3J0LmNvcHkoIHNvdXJjZS52aWV3cG9ydCApO1xyXG5cclxuXHRcdHRoaXMuZGVwdGhCdWZmZXIgPSBzb3VyY2UuZGVwdGhCdWZmZXI7XHJcblx0XHR0aGlzLnN0ZW5jaWxCdWZmZXIgPSBzb3VyY2Uuc3RlbmNpbEJ1ZmZlcjtcclxuXHJcblx0XHRpZiAoIHNvdXJjZS5kZXB0aFRleHR1cmUgIT09IG51bGwgKSB0aGlzLmRlcHRoVGV4dHVyZSA9IHNvdXJjZS5kZXB0aFRleHR1cmUuY2xvbmUoKTtcclxuXHJcblx0XHR0aGlzLnRleHR1cmUubGVuZ3RoID0gMDtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gc291cmNlLnRleHR1cmUubGVuZ3RoOyBpIDwgaWw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHR0aGlzLnRleHR1cmVbIGkgXSA9IHNvdXJjZS50ZXh0dXJlWyBpIF0uY2xvbmUoKTtcclxuXHRcdFx0dGhpcy50ZXh0dXJlWyBpIF0uaXNSZW5kZXJUYXJnZXRUZXh0dXJlID0gdHJ1ZTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IFdlYkdMTXVsdGlwbGVSZW5kZXJUYXJnZXRzIH07XHJcbiIsImltcG9ydCAqIGFzIE1hdGhVdGlscyBmcm9tICcuL01hdGhVdGlscy5qcyc7XHJcblxyXG5jbGFzcyBRdWF0ZXJuaW9uIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIHggPSAwLCB5ID0gMCwgeiA9IDAsIHcgPSAxICkge1xyXG5cclxuXHRcdHRoaXMuaXNRdWF0ZXJuaW9uID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLl94ID0geDtcclxuXHRcdHRoaXMuX3kgPSB5O1xyXG5cdFx0dGhpcy5feiA9IHo7XHJcblx0XHR0aGlzLl93ID0gdztcclxuXHJcblx0fVxyXG5cclxuXHRzdGF0aWMgc2xlcnBGbGF0KCBkc3QsIGRzdE9mZnNldCwgc3JjMCwgc3JjT2Zmc2V0MCwgc3JjMSwgc3JjT2Zmc2V0MSwgdCApIHtcclxuXHJcblx0XHQvLyBmdXp6LWZyZWUsIGFycmF5LWJhc2VkIFF1YXRlcm5pb24gU0xFUlAgb3BlcmF0aW9uXHJcblxyXG5cdFx0bGV0IHgwID0gc3JjMFsgc3JjT2Zmc2V0MCArIDAgXSxcclxuXHRcdFx0eTAgPSBzcmMwWyBzcmNPZmZzZXQwICsgMSBdLFxyXG5cdFx0XHR6MCA9IHNyYzBbIHNyY09mZnNldDAgKyAyIF0sXHJcblx0XHRcdHcwID0gc3JjMFsgc3JjT2Zmc2V0MCArIDMgXTtcclxuXHJcblx0XHRjb25zdCB4MSA9IHNyYzFbIHNyY09mZnNldDEgKyAwIF0sXHJcblx0XHRcdHkxID0gc3JjMVsgc3JjT2Zmc2V0MSArIDEgXSxcclxuXHRcdFx0ejEgPSBzcmMxWyBzcmNPZmZzZXQxICsgMiBdLFxyXG5cdFx0XHR3MSA9IHNyYzFbIHNyY09mZnNldDEgKyAzIF07XHJcblxyXG5cdFx0aWYgKCB0ID09PSAwICkge1xyXG5cclxuXHRcdFx0ZHN0WyBkc3RPZmZzZXQgKyAwIF0gPSB4MDtcclxuXHRcdFx0ZHN0WyBkc3RPZmZzZXQgKyAxIF0gPSB5MDtcclxuXHRcdFx0ZHN0WyBkc3RPZmZzZXQgKyAyIF0gPSB6MDtcclxuXHRcdFx0ZHN0WyBkc3RPZmZzZXQgKyAzIF0gPSB3MDtcclxuXHRcdFx0cmV0dXJuO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHQgPT09IDEgKSB7XHJcblxyXG5cdFx0XHRkc3RbIGRzdE9mZnNldCArIDAgXSA9IHgxO1xyXG5cdFx0XHRkc3RbIGRzdE9mZnNldCArIDEgXSA9IHkxO1xyXG5cdFx0XHRkc3RbIGRzdE9mZnNldCArIDIgXSA9IHoxO1xyXG5cdFx0XHRkc3RbIGRzdE9mZnNldCArIDMgXSA9IHcxO1xyXG5cdFx0XHRyZXR1cm47XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggdzAgIT09IHcxIHx8IHgwICE9PSB4MSB8fCB5MCAhPT0geTEgfHwgejAgIT09IHoxICkge1xyXG5cclxuXHRcdFx0bGV0IHMgPSAxIC0gdDtcclxuXHRcdFx0Y29uc3QgY29zID0geDAgKiB4MSArIHkwICogeTEgKyB6MCAqIHoxICsgdzAgKiB3MSxcclxuXHRcdFx0XHRkaXIgPSAoIGNvcyA+PSAwID8gMSA6IC0gMSApLFxyXG5cdFx0XHRcdHNxclNpbiA9IDEgLSBjb3MgKiBjb3M7XHJcblxyXG5cdFx0XHQvLyBTa2lwIHRoZSBTbGVycCBmb3IgdGlueSBzdGVwcyB0byBhdm9pZCBudW1lcmljIHByb2JsZW1zOlxyXG5cdFx0XHRpZiAoIHNxclNpbiA+IE51bWJlci5FUFNJTE9OICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBzaW4gPSBNYXRoLnNxcnQoIHNxclNpbiApLFxyXG5cdFx0XHRcdFx0bGVuID0gTWF0aC5hdGFuMiggc2luLCBjb3MgKiBkaXIgKTtcclxuXHJcblx0XHRcdFx0cyA9IE1hdGguc2luKCBzICogbGVuICkgLyBzaW47XHJcblx0XHRcdFx0dCA9IE1hdGguc2luKCB0ICogbGVuICkgLyBzaW47XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRjb25zdCB0RGlyID0gdCAqIGRpcjtcclxuXHJcblx0XHRcdHgwID0geDAgKiBzICsgeDEgKiB0RGlyO1xyXG5cdFx0XHR5MCA9IHkwICogcyArIHkxICogdERpcjtcclxuXHRcdFx0ejAgPSB6MCAqIHMgKyB6MSAqIHREaXI7XHJcblx0XHRcdHcwID0gdzAgKiBzICsgdzEgKiB0RGlyO1xyXG5cclxuXHRcdFx0Ly8gTm9ybWFsaXplIGluIGNhc2Ugd2UganVzdCBkaWQgYSBsZXJwOlxyXG5cdFx0XHRpZiAoIHMgPT09IDEgLSB0ICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBmID0gMSAvIE1hdGguc3FydCggeDAgKiB4MCArIHkwICogeTAgKyB6MCAqIHowICsgdzAgKiB3MCApO1xyXG5cclxuXHRcdFx0XHR4MCAqPSBmO1xyXG5cdFx0XHRcdHkwICo9IGY7XHJcblx0XHRcdFx0ejAgKj0gZjtcclxuXHRcdFx0XHR3MCAqPSBmO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRkc3RbIGRzdE9mZnNldCBdID0geDA7XHJcblx0XHRkc3RbIGRzdE9mZnNldCArIDEgXSA9IHkwO1xyXG5cdFx0ZHN0WyBkc3RPZmZzZXQgKyAyIF0gPSB6MDtcclxuXHRcdGRzdFsgZHN0T2Zmc2V0ICsgMyBdID0gdzA7XHJcblxyXG5cdH1cclxuXHJcblx0c3RhdGljIG11bHRpcGx5UXVhdGVybmlvbnNGbGF0KCBkc3QsIGRzdE9mZnNldCwgc3JjMCwgc3JjT2Zmc2V0MCwgc3JjMSwgc3JjT2Zmc2V0MSApIHtcclxuXHJcblx0XHRjb25zdCB4MCA9IHNyYzBbIHNyY09mZnNldDAgXTtcclxuXHRcdGNvbnN0IHkwID0gc3JjMFsgc3JjT2Zmc2V0MCArIDEgXTtcclxuXHRcdGNvbnN0IHowID0gc3JjMFsgc3JjT2Zmc2V0MCArIDIgXTtcclxuXHRcdGNvbnN0IHcwID0gc3JjMFsgc3JjT2Zmc2V0MCArIDMgXTtcclxuXHJcblx0XHRjb25zdCB4MSA9IHNyYzFbIHNyY09mZnNldDEgXTtcclxuXHRcdGNvbnN0IHkxID0gc3JjMVsgc3JjT2Zmc2V0MSArIDEgXTtcclxuXHRcdGNvbnN0IHoxID0gc3JjMVsgc3JjT2Zmc2V0MSArIDIgXTtcclxuXHRcdGNvbnN0IHcxID0gc3JjMVsgc3JjT2Zmc2V0MSArIDMgXTtcclxuXHJcblx0XHRkc3RbIGRzdE9mZnNldCBdID0geDAgKiB3MSArIHcwICogeDEgKyB5MCAqIHoxIC0gejAgKiB5MTtcclxuXHRcdGRzdFsgZHN0T2Zmc2V0ICsgMSBdID0geTAgKiB3MSArIHcwICogeTEgKyB6MCAqIHgxIC0geDAgKiB6MTtcclxuXHRcdGRzdFsgZHN0T2Zmc2V0ICsgMiBdID0gejAgKiB3MSArIHcwICogejEgKyB4MCAqIHkxIC0geTAgKiB4MTtcclxuXHRcdGRzdFsgZHN0T2Zmc2V0ICsgMyBdID0gdzAgKiB3MSAtIHgwICogeDEgLSB5MCAqIHkxIC0gejAgKiB6MTtcclxuXHJcblx0XHRyZXR1cm4gZHN0O1xyXG5cclxuXHR9XHJcblxyXG5cdGdldCB4KCkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLl94O1xyXG5cclxuXHR9XHJcblxyXG5cdHNldCB4KCB2YWx1ZSApIHtcclxuXHJcblx0XHR0aGlzLl94ID0gdmFsdWU7XHJcblx0XHR0aGlzLl9vbkNoYW5nZUNhbGxiYWNrKCk7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0IHkoKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuX3k7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0IHkoIHZhbHVlICkge1xyXG5cclxuXHRcdHRoaXMuX3kgPSB2YWx1ZTtcclxuXHRcdHRoaXMuX29uQ2hhbmdlQ2FsbGJhY2soKTtcclxuXHJcblx0fVxyXG5cclxuXHRnZXQgeigpIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5fejtcclxuXHJcblx0fVxyXG5cclxuXHRzZXQgeiggdmFsdWUgKSB7XHJcblxyXG5cdFx0dGhpcy5feiA9IHZhbHVlO1xyXG5cdFx0dGhpcy5fb25DaGFuZ2VDYWxsYmFjaygpO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldCB3KCkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLl93O1xyXG5cclxuXHR9XHJcblxyXG5cdHNldCB3KCB2YWx1ZSApIHtcclxuXHJcblx0XHR0aGlzLl93ID0gdmFsdWU7XHJcblx0XHR0aGlzLl9vbkNoYW5nZUNhbGxiYWNrKCk7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0KCB4LCB5LCB6LCB3ICkge1xyXG5cclxuXHRcdHRoaXMuX3ggPSB4O1xyXG5cdFx0dGhpcy5feSA9IHk7XHJcblx0XHR0aGlzLl96ID0gejtcclxuXHRcdHRoaXMuX3cgPSB3O1xyXG5cclxuXHRcdHRoaXMuX29uQ2hhbmdlQ2FsbGJhY2soKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRjbG9uZSgpIHtcclxuXHJcblx0XHRyZXR1cm4gbmV3IHRoaXMuY29uc3RydWN0b3IoIHRoaXMuX3gsIHRoaXMuX3ksIHRoaXMuX3osIHRoaXMuX3cgKTtcclxuXHJcblx0fVxyXG5cclxuXHRjb3B5KCBxdWF0ZXJuaW9uICkge1xyXG5cclxuXHRcdHRoaXMuX3ggPSBxdWF0ZXJuaW9uLng7XHJcblx0XHR0aGlzLl95ID0gcXVhdGVybmlvbi55O1xyXG5cdFx0dGhpcy5feiA9IHF1YXRlcm5pb24uejtcclxuXHRcdHRoaXMuX3cgPSBxdWF0ZXJuaW9uLnc7XHJcblxyXG5cdFx0dGhpcy5fb25DaGFuZ2VDYWxsYmFjaygpO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldEZyb21FdWxlciggZXVsZXIsIHVwZGF0ZSA9IHRydWUgKSB7XHJcblxyXG5cdFx0Y29uc3QgeCA9IGV1bGVyLl94LCB5ID0gZXVsZXIuX3ksIHogPSBldWxlci5feiwgb3JkZXIgPSBldWxlci5fb3JkZXI7XHJcblxyXG5cdFx0Ly8gaHR0cDovL3d3dy5tYXRod29ya3MuY29tL21hdGxhYmNlbnRyYWwvZmlsZWV4Y2hhbmdlL1xyXG5cdFx0Ly8gXHQyMDY5Ni1mdW5jdGlvbi10by1jb252ZXJ0LWJldHdlZW4tZGNtLWV1bGVyLWFuZ2xlcy1xdWF0ZXJuaW9ucy1hbmQtZXVsZXItdmVjdG9ycy9cclxuXHRcdC8vXHRjb250ZW50L1NwaW5DYWxjLm1cclxuXHJcblx0XHRjb25zdCBjb3MgPSBNYXRoLmNvcztcclxuXHRcdGNvbnN0IHNpbiA9IE1hdGguc2luO1xyXG5cclxuXHRcdGNvbnN0IGMxID0gY29zKCB4IC8gMiApO1xyXG5cdFx0Y29uc3QgYzIgPSBjb3MoIHkgLyAyICk7XHJcblx0XHRjb25zdCBjMyA9IGNvcyggeiAvIDIgKTtcclxuXHJcblx0XHRjb25zdCBzMSA9IHNpbiggeCAvIDIgKTtcclxuXHRcdGNvbnN0IHMyID0gc2luKCB5IC8gMiApO1xyXG5cdFx0Y29uc3QgczMgPSBzaW4oIHogLyAyICk7XHJcblxyXG5cdFx0c3dpdGNoICggb3JkZXIgKSB7XHJcblxyXG5cdFx0XHRjYXNlICdYWVonOlxyXG5cdFx0XHRcdHRoaXMuX3ggPSBzMSAqIGMyICogYzMgKyBjMSAqIHMyICogczM7XHJcblx0XHRcdFx0dGhpcy5feSA9IGMxICogczIgKiBjMyAtIHMxICogYzIgKiBzMztcclxuXHRcdFx0XHR0aGlzLl96ID0gYzEgKiBjMiAqIHMzICsgczEgKiBzMiAqIGMzO1xyXG5cdFx0XHRcdHRoaXMuX3cgPSBjMSAqIGMyICogYzMgLSBzMSAqIHMyICogczM7XHJcblx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRjYXNlICdZWFonOlxyXG5cdFx0XHRcdHRoaXMuX3ggPSBzMSAqIGMyICogYzMgKyBjMSAqIHMyICogczM7XHJcblx0XHRcdFx0dGhpcy5feSA9IGMxICogczIgKiBjMyAtIHMxICogYzIgKiBzMztcclxuXHRcdFx0XHR0aGlzLl96ID0gYzEgKiBjMiAqIHMzIC0gczEgKiBzMiAqIGMzO1xyXG5cdFx0XHRcdHRoaXMuX3cgPSBjMSAqIGMyICogYzMgKyBzMSAqIHMyICogczM7XHJcblx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRjYXNlICdaWFknOlxyXG5cdFx0XHRcdHRoaXMuX3ggPSBzMSAqIGMyICogYzMgLSBjMSAqIHMyICogczM7XHJcblx0XHRcdFx0dGhpcy5feSA9IGMxICogczIgKiBjMyArIHMxICogYzIgKiBzMztcclxuXHRcdFx0XHR0aGlzLl96ID0gYzEgKiBjMiAqIHMzICsgczEgKiBzMiAqIGMzO1xyXG5cdFx0XHRcdHRoaXMuX3cgPSBjMSAqIGMyICogYzMgLSBzMSAqIHMyICogczM7XHJcblx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRjYXNlICdaWVgnOlxyXG5cdFx0XHRcdHRoaXMuX3ggPSBzMSAqIGMyICogYzMgLSBjMSAqIHMyICogczM7XHJcblx0XHRcdFx0dGhpcy5feSA9IGMxICogczIgKiBjMyArIHMxICogYzIgKiBzMztcclxuXHRcdFx0XHR0aGlzLl96ID0gYzEgKiBjMiAqIHMzIC0gczEgKiBzMiAqIGMzO1xyXG5cdFx0XHRcdHRoaXMuX3cgPSBjMSAqIGMyICogYzMgKyBzMSAqIHMyICogczM7XHJcblx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRjYXNlICdZWlgnOlxyXG5cdFx0XHRcdHRoaXMuX3ggPSBzMSAqIGMyICogYzMgKyBjMSAqIHMyICogczM7XHJcblx0XHRcdFx0dGhpcy5feSA9IGMxICogczIgKiBjMyArIHMxICogYzIgKiBzMztcclxuXHRcdFx0XHR0aGlzLl96ID0gYzEgKiBjMiAqIHMzIC0gczEgKiBzMiAqIGMzO1xyXG5cdFx0XHRcdHRoaXMuX3cgPSBjMSAqIGMyICogYzMgLSBzMSAqIHMyICogczM7XHJcblx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRjYXNlICdYWlknOlxyXG5cdFx0XHRcdHRoaXMuX3ggPSBzMSAqIGMyICogYzMgLSBjMSAqIHMyICogczM7XHJcblx0XHRcdFx0dGhpcy5feSA9IGMxICogczIgKiBjMyAtIHMxICogYzIgKiBzMztcclxuXHRcdFx0XHR0aGlzLl96ID0gYzEgKiBjMiAqIHMzICsgczEgKiBzMiAqIGMzO1xyXG5cdFx0XHRcdHRoaXMuX3cgPSBjMSAqIGMyICogYzMgKyBzMSAqIHMyICogczM7XHJcblx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRkZWZhdWx0OlxyXG5cdFx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLlF1YXRlcm5pb246IC5zZXRGcm9tRXVsZXIoKSBlbmNvdW50ZXJlZCBhbiB1bmtub3duIG9yZGVyOiAnICsgb3JkZXIgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCB1cGRhdGUgPT09IHRydWUgKSB0aGlzLl9vbkNoYW5nZUNhbGxiYWNrKCk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0RnJvbUF4aXNBbmdsZSggYXhpcywgYW5nbGUgKSB7XHJcblxyXG5cdFx0Ly8gaHR0cDovL3d3dy5ldWNsaWRlYW5zcGFjZS5jb20vbWF0aHMvZ2VvbWV0cnkvcm90YXRpb25zL2NvbnZlcnNpb25zL2FuZ2xlVG9RdWF0ZXJuaW9uL2luZGV4Lmh0bVxyXG5cclxuXHRcdC8vIGFzc3VtZXMgYXhpcyBpcyBub3JtYWxpemVkXHJcblxyXG5cdFx0Y29uc3QgaGFsZkFuZ2xlID0gYW5nbGUgLyAyLCBzID0gTWF0aC5zaW4oIGhhbGZBbmdsZSApO1xyXG5cclxuXHRcdHRoaXMuX3ggPSBheGlzLnggKiBzO1xyXG5cdFx0dGhpcy5feSA9IGF4aXMueSAqIHM7XHJcblx0XHR0aGlzLl96ID0gYXhpcy56ICogcztcclxuXHRcdHRoaXMuX3cgPSBNYXRoLmNvcyggaGFsZkFuZ2xlICk7XHJcblxyXG5cdFx0dGhpcy5fb25DaGFuZ2VDYWxsYmFjaygpO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldEZyb21Sb3RhdGlvbk1hdHJpeCggbSApIHtcclxuXHJcblx0XHQvLyBodHRwOi8vd3d3LmV1Y2xpZGVhbnNwYWNlLmNvbS9tYXRocy9nZW9tZXRyeS9yb3RhdGlvbnMvY29udmVyc2lvbnMvbWF0cml4VG9RdWF0ZXJuaW9uL2luZGV4Lmh0bVxyXG5cclxuXHRcdC8vIGFzc3VtZXMgdGhlIHVwcGVyIDN4MyBvZiBtIGlzIGEgcHVyZSByb3RhdGlvbiBtYXRyaXggKGkuZSwgdW5zY2FsZWQpXHJcblxyXG5cdFx0Y29uc3QgdGUgPSBtLmVsZW1lbnRzLFxyXG5cclxuXHRcdFx0bTExID0gdGVbIDAgXSwgbTEyID0gdGVbIDQgXSwgbTEzID0gdGVbIDggXSxcclxuXHRcdFx0bTIxID0gdGVbIDEgXSwgbTIyID0gdGVbIDUgXSwgbTIzID0gdGVbIDkgXSxcclxuXHRcdFx0bTMxID0gdGVbIDIgXSwgbTMyID0gdGVbIDYgXSwgbTMzID0gdGVbIDEwIF0sXHJcblxyXG5cdFx0XHR0cmFjZSA9IG0xMSArIG0yMiArIG0zMztcclxuXHJcblx0XHRpZiAoIHRyYWNlID4gMCApIHtcclxuXHJcblx0XHRcdGNvbnN0IHMgPSAwLjUgLyBNYXRoLnNxcnQoIHRyYWNlICsgMS4wICk7XHJcblxyXG5cdFx0XHR0aGlzLl93ID0gMC4yNSAvIHM7XHJcblx0XHRcdHRoaXMuX3ggPSAoIG0zMiAtIG0yMyApICogcztcclxuXHRcdFx0dGhpcy5feSA9ICggbTEzIC0gbTMxICkgKiBzO1xyXG5cdFx0XHR0aGlzLl96ID0gKCBtMjEgLSBtMTIgKSAqIHM7XHJcblxyXG5cdFx0fSBlbHNlIGlmICggbTExID4gbTIyICYmIG0xMSA+IG0zMyApIHtcclxuXHJcblx0XHRcdGNvbnN0IHMgPSAyLjAgKiBNYXRoLnNxcnQoIDEuMCArIG0xMSAtIG0yMiAtIG0zMyApO1xyXG5cclxuXHRcdFx0dGhpcy5fdyA9ICggbTMyIC0gbTIzICkgLyBzO1xyXG5cdFx0XHR0aGlzLl94ID0gMC4yNSAqIHM7XHJcblx0XHRcdHRoaXMuX3kgPSAoIG0xMiArIG0yMSApIC8gcztcclxuXHRcdFx0dGhpcy5feiA9ICggbTEzICsgbTMxICkgLyBzO1xyXG5cclxuXHRcdH0gZWxzZSBpZiAoIG0yMiA+IG0zMyApIHtcclxuXHJcblx0XHRcdGNvbnN0IHMgPSAyLjAgKiBNYXRoLnNxcnQoIDEuMCArIG0yMiAtIG0xMSAtIG0zMyApO1xyXG5cclxuXHRcdFx0dGhpcy5fdyA9ICggbTEzIC0gbTMxICkgLyBzO1xyXG5cdFx0XHR0aGlzLl94ID0gKCBtMTIgKyBtMjEgKSAvIHM7XHJcblx0XHRcdHRoaXMuX3kgPSAwLjI1ICogcztcclxuXHRcdFx0dGhpcy5feiA9ICggbTIzICsgbTMyICkgLyBzO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRjb25zdCBzID0gMi4wICogTWF0aC5zcXJ0KCAxLjAgKyBtMzMgLSBtMTEgLSBtMjIgKTtcclxuXHJcblx0XHRcdHRoaXMuX3cgPSAoIG0yMSAtIG0xMiApIC8gcztcclxuXHRcdFx0dGhpcy5feCA9ICggbTEzICsgbTMxICkgLyBzO1xyXG5cdFx0XHR0aGlzLl95ID0gKCBtMjMgKyBtMzIgKSAvIHM7XHJcblx0XHRcdHRoaXMuX3ogPSAwLjI1ICogcztcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5fb25DaGFuZ2VDYWxsYmFjaygpO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldEZyb21Vbml0VmVjdG9ycyggdkZyb20sIHZUbyApIHtcclxuXHJcblx0XHQvLyBhc3N1bWVzIGRpcmVjdGlvbiB2ZWN0b3JzIHZGcm9tIGFuZCB2VG8gYXJlIG5vcm1hbGl6ZWRcclxuXHJcblx0XHRsZXQgciA9IHZGcm9tLmRvdCggdlRvICkgKyAxO1xyXG5cclxuXHRcdGlmICggciA8IE51bWJlci5FUFNJTE9OICkge1xyXG5cclxuXHRcdFx0Ly8gdkZyb20gYW5kIHZUbyBwb2ludCBpbiBvcHBvc2l0ZSBkaXJlY3Rpb25zXHJcblxyXG5cdFx0XHRyID0gMDtcclxuXHJcblx0XHRcdGlmICggTWF0aC5hYnMoIHZGcm9tLnggKSA+IE1hdGguYWJzKCB2RnJvbS56ICkgKSB7XHJcblxyXG5cdFx0XHRcdHRoaXMuX3ggPSAtIHZGcm9tLnk7XHJcblx0XHRcdFx0dGhpcy5feSA9IHZGcm9tLng7XHJcblx0XHRcdFx0dGhpcy5feiA9IDA7XHJcblx0XHRcdFx0dGhpcy5fdyA9IHI7XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHR0aGlzLl94ID0gMDtcclxuXHRcdFx0XHR0aGlzLl95ID0gLSB2RnJvbS56O1xyXG5cdFx0XHRcdHRoaXMuX3ogPSB2RnJvbS55O1xyXG5cdFx0XHRcdHRoaXMuX3cgPSByO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHQvLyBjcm9zc1ZlY3RvcnMoIHZGcm9tLCB2VG8gKTsgLy8gaW5saW5lZCB0byBhdm9pZCBjeWNsaWMgZGVwZW5kZW5jeSBvbiBWZWN0b3IzXHJcblxyXG5cdFx0XHR0aGlzLl94ID0gdkZyb20ueSAqIHZUby56IC0gdkZyb20ueiAqIHZUby55O1xyXG5cdFx0XHR0aGlzLl95ID0gdkZyb20ueiAqIHZUby54IC0gdkZyb20ueCAqIHZUby56O1xyXG5cdFx0XHR0aGlzLl96ID0gdkZyb20ueCAqIHZUby55IC0gdkZyb20ueSAqIHZUby54O1xyXG5cdFx0XHR0aGlzLl93ID0gcjtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMubm9ybWFsaXplKCk7XHJcblxyXG5cdH1cclxuXHJcblx0YW5nbGVUbyggcSApIHtcclxuXHJcblx0XHRyZXR1cm4gMiAqIE1hdGguYWNvcyggTWF0aC5hYnMoIE1hdGhVdGlscy5jbGFtcCggdGhpcy5kb3QoIHEgKSwgLSAxLCAxICkgKSApO1xyXG5cclxuXHR9XHJcblxyXG5cdHJvdGF0ZVRvd2FyZHMoIHEsIHN0ZXAgKSB7XHJcblxyXG5cdFx0Y29uc3QgYW5nbGUgPSB0aGlzLmFuZ2xlVG8oIHEgKTtcclxuXHJcblx0XHRpZiAoIGFuZ2xlID09PSAwICkgcmV0dXJuIHRoaXM7XHJcblxyXG5cdFx0Y29uc3QgdCA9IE1hdGgubWluKCAxLCBzdGVwIC8gYW5nbGUgKTtcclxuXHJcblx0XHR0aGlzLnNsZXJwKCBxLCB0ICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0aWRlbnRpdHkoKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuc2V0KCAwLCAwLCAwLCAxICk7XHJcblxyXG5cdH1cclxuXHJcblx0aW52ZXJ0KCkge1xyXG5cclxuXHRcdC8vIHF1YXRlcm5pb24gaXMgYXNzdW1lZCB0byBoYXZlIHVuaXQgbGVuZ3RoXHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuY29uanVnYXRlKCk7XHJcblxyXG5cdH1cclxuXHJcblx0Y29uanVnYXRlKCkge1xyXG5cclxuXHRcdHRoaXMuX3ggKj0gLSAxO1xyXG5cdFx0dGhpcy5feSAqPSAtIDE7XHJcblx0XHR0aGlzLl96ICo9IC0gMTtcclxuXHJcblx0XHR0aGlzLl9vbkNoYW5nZUNhbGxiYWNrKCk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0ZG90KCB2ICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLl94ICogdi5feCArIHRoaXMuX3kgKiB2Ll95ICsgdGhpcy5feiAqIHYuX3ogKyB0aGlzLl93ICogdi5fdztcclxuXHJcblx0fVxyXG5cclxuXHRsZW5ndGhTcSgpIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5feCAqIHRoaXMuX3ggKyB0aGlzLl95ICogdGhpcy5feSArIHRoaXMuX3ogKiB0aGlzLl96ICsgdGhpcy5fdyAqIHRoaXMuX3c7XHJcblxyXG5cdH1cclxuXHJcblx0bGVuZ3RoKCkge1xyXG5cclxuXHRcdHJldHVybiBNYXRoLnNxcnQoIHRoaXMuX3ggKiB0aGlzLl94ICsgdGhpcy5feSAqIHRoaXMuX3kgKyB0aGlzLl96ICogdGhpcy5feiArIHRoaXMuX3cgKiB0aGlzLl93ICk7XHJcblxyXG5cdH1cclxuXHJcblx0bm9ybWFsaXplKCkge1xyXG5cclxuXHRcdGxldCBsID0gdGhpcy5sZW5ndGgoKTtcclxuXHJcblx0XHRpZiAoIGwgPT09IDAgKSB7XHJcblxyXG5cdFx0XHR0aGlzLl94ID0gMDtcclxuXHRcdFx0dGhpcy5feSA9IDA7XHJcblx0XHRcdHRoaXMuX3ogPSAwO1xyXG5cdFx0XHR0aGlzLl93ID0gMTtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0bCA9IDEgLyBsO1xyXG5cclxuXHRcdFx0dGhpcy5feCA9IHRoaXMuX3ggKiBsO1xyXG5cdFx0XHR0aGlzLl95ID0gdGhpcy5feSAqIGw7XHJcblx0XHRcdHRoaXMuX3ogPSB0aGlzLl96ICogbDtcclxuXHRcdFx0dGhpcy5fdyA9IHRoaXMuX3cgKiBsO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLl9vbkNoYW5nZUNhbGxiYWNrKCk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0bXVsdGlwbHkoIHEgKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMubXVsdGlwbHlRdWF0ZXJuaW9ucyggdGhpcywgcSApO1xyXG5cclxuXHR9XHJcblxyXG5cdHByZW11bHRpcGx5KCBxICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLm11bHRpcGx5UXVhdGVybmlvbnMoIHEsIHRoaXMgKTtcclxuXHJcblx0fVxyXG5cclxuXHRtdWx0aXBseVF1YXRlcm5pb25zKCBhLCBiICkge1xyXG5cclxuXHRcdC8vIGZyb20gaHR0cDovL3d3dy5ldWNsaWRlYW5zcGFjZS5jb20vbWF0aHMvYWxnZWJyYS9yZWFsTm9ybWVkQWxnZWJyYS9xdWF0ZXJuaW9ucy9jb2RlL2luZGV4Lmh0bVxyXG5cclxuXHRcdGNvbnN0IHFheCA9IGEuX3gsIHFheSA9IGEuX3ksIHFheiA9IGEuX3osIHFhdyA9IGEuX3c7XHJcblx0XHRjb25zdCBxYnggPSBiLl94LCBxYnkgPSBiLl95LCBxYnogPSBiLl96LCBxYncgPSBiLl93O1xyXG5cclxuXHRcdHRoaXMuX3ggPSBxYXggKiBxYncgKyBxYXcgKiBxYnggKyBxYXkgKiBxYnogLSBxYXogKiBxYnk7XHJcblx0XHR0aGlzLl95ID0gcWF5ICogcWJ3ICsgcWF3ICogcWJ5ICsgcWF6ICogcWJ4IC0gcWF4ICogcWJ6O1xyXG5cdFx0dGhpcy5feiA9IHFheiAqIHFidyArIHFhdyAqIHFieiArIHFheCAqIHFieSAtIHFheSAqIHFieDtcclxuXHRcdHRoaXMuX3cgPSBxYXcgKiBxYncgLSBxYXggKiBxYnggLSBxYXkgKiBxYnkgLSBxYXogKiBxYno7XHJcblxyXG5cdFx0dGhpcy5fb25DaGFuZ2VDYWxsYmFjaygpO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNsZXJwKCBxYiwgdCApIHtcclxuXHJcblx0XHRpZiAoIHQgPT09IDAgKSByZXR1cm4gdGhpcztcclxuXHRcdGlmICggdCA9PT0gMSApIHJldHVybiB0aGlzLmNvcHkoIHFiICk7XHJcblxyXG5cdFx0Y29uc3QgeCA9IHRoaXMuX3gsIHkgPSB0aGlzLl95LCB6ID0gdGhpcy5feiwgdyA9IHRoaXMuX3c7XHJcblxyXG5cdFx0Ly8gaHR0cDovL3d3dy5ldWNsaWRlYW5zcGFjZS5jb20vbWF0aHMvYWxnZWJyYS9yZWFsTm9ybWVkQWxnZWJyYS9xdWF0ZXJuaW9ucy9zbGVycC9cclxuXHJcblx0XHRsZXQgY29zSGFsZlRoZXRhID0gdyAqIHFiLl93ICsgeCAqIHFiLl94ICsgeSAqIHFiLl95ICsgeiAqIHFiLl96O1xyXG5cclxuXHRcdGlmICggY29zSGFsZlRoZXRhIDwgMCApIHtcclxuXHJcblx0XHRcdHRoaXMuX3cgPSAtIHFiLl93O1xyXG5cdFx0XHR0aGlzLl94ID0gLSBxYi5feDtcclxuXHRcdFx0dGhpcy5feSA9IC0gcWIuX3k7XHJcblx0XHRcdHRoaXMuX3ogPSAtIHFiLl96O1xyXG5cclxuXHRcdFx0Y29zSGFsZlRoZXRhID0gLSBjb3NIYWxmVGhldGE7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdHRoaXMuY29weSggcWIgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBjb3NIYWxmVGhldGEgPj0gMS4wICkge1xyXG5cclxuXHRcdFx0dGhpcy5fdyA9IHc7XHJcblx0XHRcdHRoaXMuX3ggPSB4O1xyXG5cdFx0XHR0aGlzLl95ID0geTtcclxuXHRcdFx0dGhpcy5feiA9IHo7XHJcblxyXG5cdFx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Y29uc3Qgc3FyU2luSGFsZlRoZXRhID0gMS4wIC0gY29zSGFsZlRoZXRhICogY29zSGFsZlRoZXRhO1xyXG5cclxuXHRcdGlmICggc3FyU2luSGFsZlRoZXRhIDw9IE51bWJlci5FUFNJTE9OICkge1xyXG5cclxuXHRcdFx0Y29uc3QgcyA9IDEgLSB0O1xyXG5cdFx0XHR0aGlzLl93ID0gcyAqIHcgKyB0ICogdGhpcy5fdztcclxuXHRcdFx0dGhpcy5feCA9IHMgKiB4ICsgdCAqIHRoaXMuX3g7XHJcblx0XHRcdHRoaXMuX3kgPSBzICogeSArIHQgKiB0aGlzLl95O1xyXG5cdFx0XHR0aGlzLl96ID0gcyAqIHogKyB0ICogdGhpcy5fejtcclxuXHJcblx0XHRcdHRoaXMubm9ybWFsaXplKCk7IC8vIG5vcm1hbGl6ZSBjYWxscyBfb25DaGFuZ2VDYWxsYmFjaygpXHJcblxyXG5cdFx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Y29uc3Qgc2luSGFsZlRoZXRhID0gTWF0aC5zcXJ0KCBzcXJTaW5IYWxmVGhldGEgKTtcclxuXHRcdGNvbnN0IGhhbGZUaGV0YSA9IE1hdGguYXRhbjIoIHNpbkhhbGZUaGV0YSwgY29zSGFsZlRoZXRhICk7XHJcblx0XHRjb25zdCByYXRpb0EgPSBNYXRoLnNpbiggKCAxIC0gdCApICogaGFsZlRoZXRhICkgLyBzaW5IYWxmVGhldGEsXHJcblx0XHRcdHJhdGlvQiA9IE1hdGguc2luKCB0ICogaGFsZlRoZXRhICkgLyBzaW5IYWxmVGhldGE7XHJcblxyXG5cdFx0dGhpcy5fdyA9ICggdyAqIHJhdGlvQSArIHRoaXMuX3cgKiByYXRpb0IgKTtcclxuXHRcdHRoaXMuX3ggPSAoIHggKiByYXRpb0EgKyB0aGlzLl94ICogcmF0aW9CICk7XHJcblx0XHR0aGlzLl95ID0gKCB5ICogcmF0aW9BICsgdGhpcy5feSAqIHJhdGlvQiApO1xyXG5cdFx0dGhpcy5feiA9ICggeiAqIHJhdGlvQSArIHRoaXMuX3ogKiByYXRpb0IgKTtcclxuXHJcblx0XHR0aGlzLl9vbkNoYW5nZUNhbGxiYWNrKCk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0c2xlcnBRdWF0ZXJuaW9ucyggcWEsIHFiLCB0ICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLmNvcHkoIHFhICkuc2xlcnAoIHFiLCB0ICk7XHJcblxyXG5cdH1cclxuXHJcblx0cmFuZG9tKCkge1xyXG5cclxuXHRcdC8vIERlcml2ZWQgZnJvbSBodHRwOi8vcGxhbm5pbmcuY3MudWl1Yy5lZHUvbm9kZTE5OC5odG1sXHJcblx0XHQvLyBOb3RlLCB0aGlzIHNvdXJjZSB1c2VzIHcsIHgsIHksIHogb3JkZXJpbmcsXHJcblx0XHQvLyBzbyB3ZSBzd2FwIHRoZSBvcmRlciBiZWxvdy5cclxuXHJcblx0XHRjb25zdCB1MSA9IE1hdGgucmFuZG9tKCk7XHJcblx0XHRjb25zdCBzcXJ0MXUxID0gTWF0aC5zcXJ0KCAxIC0gdTEgKTtcclxuXHRcdGNvbnN0IHNxcnR1MSA9IE1hdGguc3FydCggdTEgKTtcclxuXHJcblx0XHRjb25zdCB1MiA9IDIgKiBNYXRoLlBJICogTWF0aC5yYW5kb20oKTtcclxuXHJcblx0XHRjb25zdCB1MyA9IDIgKiBNYXRoLlBJICogTWF0aC5yYW5kb20oKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5zZXQoXHJcblx0XHRcdHNxcnQxdTEgKiBNYXRoLmNvcyggdTIgKSxcclxuXHRcdFx0c3FydHUxICogTWF0aC5zaW4oIHUzICksXHJcblx0XHRcdHNxcnR1MSAqIE1hdGguY29zKCB1MyApLFxyXG5cdFx0XHRzcXJ0MXUxICogTWF0aC5zaW4oIHUyICksXHJcblx0XHQpO1xyXG5cclxuXHR9XHJcblxyXG5cdGVxdWFscyggcXVhdGVybmlvbiApIHtcclxuXHJcblx0XHRyZXR1cm4gKCBxdWF0ZXJuaW9uLl94ID09PSB0aGlzLl94ICkgJiYgKCBxdWF0ZXJuaW9uLl95ID09PSB0aGlzLl95ICkgJiYgKCBxdWF0ZXJuaW9uLl96ID09PSB0aGlzLl96ICkgJiYgKCBxdWF0ZXJuaW9uLl93ID09PSB0aGlzLl93ICk7XHJcblxyXG5cdH1cclxuXHJcblx0ZnJvbUFycmF5KCBhcnJheSwgb2Zmc2V0ID0gMCApIHtcclxuXHJcblx0XHR0aGlzLl94ID0gYXJyYXlbIG9mZnNldCBdO1xyXG5cdFx0dGhpcy5feSA9IGFycmF5WyBvZmZzZXQgKyAxIF07XHJcblx0XHR0aGlzLl96ID0gYXJyYXlbIG9mZnNldCArIDIgXTtcclxuXHRcdHRoaXMuX3cgPSBhcnJheVsgb2Zmc2V0ICsgMyBdO1xyXG5cclxuXHRcdHRoaXMuX29uQ2hhbmdlQ2FsbGJhY2soKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHR0b0FycmF5KCBhcnJheSA9IFtdLCBvZmZzZXQgPSAwICkge1xyXG5cclxuXHRcdGFycmF5WyBvZmZzZXQgXSA9IHRoaXMuX3g7XHJcblx0XHRhcnJheVsgb2Zmc2V0ICsgMSBdID0gdGhpcy5feTtcclxuXHRcdGFycmF5WyBvZmZzZXQgKyAyIF0gPSB0aGlzLl96O1xyXG5cdFx0YXJyYXlbIG9mZnNldCArIDMgXSA9IHRoaXMuX3c7XHJcblxyXG5cdFx0cmV0dXJuIGFycmF5O1xyXG5cclxuXHR9XHJcblxyXG5cdGZyb21CdWZmZXJBdHRyaWJ1dGUoIGF0dHJpYnV0ZSwgaW5kZXggKSB7XHJcblxyXG5cdFx0dGhpcy5feCA9IGF0dHJpYnV0ZS5nZXRYKCBpbmRleCApO1xyXG5cdFx0dGhpcy5feSA9IGF0dHJpYnV0ZS5nZXRZKCBpbmRleCApO1xyXG5cdFx0dGhpcy5feiA9IGF0dHJpYnV0ZS5nZXRaKCBpbmRleCApO1xyXG5cdFx0dGhpcy5fdyA9IGF0dHJpYnV0ZS5nZXRXKCBpbmRleCApO1xyXG5cclxuXHRcdHRoaXMuX29uQ2hhbmdlQ2FsbGJhY2soKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHR0b0pTT04oKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMudG9BcnJheSgpO1xyXG5cclxuXHR9XHJcblxyXG5cdF9vbkNoYW5nZSggY2FsbGJhY2sgKSB7XHJcblxyXG5cdFx0dGhpcy5fb25DaGFuZ2VDYWxsYmFjayA9IGNhbGxiYWNrO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdF9vbkNoYW5nZUNhbGxiYWNrKCkge31cclxuXHJcblx0KlsgU3ltYm9sLml0ZXJhdG9yIF0oKSB7XHJcblxyXG5cdFx0eWllbGQgdGhpcy5feDtcclxuXHRcdHlpZWxkIHRoaXMuX3k7XHJcblx0XHR5aWVsZCB0aGlzLl96O1xyXG5cdFx0eWllbGQgdGhpcy5fdztcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgUXVhdGVybmlvbiB9O1xyXG4iLCJpbXBvcnQgKiBhcyBNYXRoVXRpbHMgZnJvbSAnLi9NYXRoVXRpbHMuanMnO1xyXG5pbXBvcnQgeyBRdWF0ZXJuaW9uIH0gZnJvbSAnLi9RdWF0ZXJuaW9uLmpzJztcclxuXHJcbmNsYXNzIFZlY3RvcjMge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggeCA9IDAsIHkgPSAwLCB6ID0gMCApIHtcclxuXHJcblx0XHRWZWN0b3IzLnByb3RvdHlwZS5pc1ZlY3RvcjMgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMueCA9IHg7XHJcblx0XHR0aGlzLnkgPSB5O1xyXG5cdFx0dGhpcy56ID0gejtcclxuXHJcblx0fVxyXG5cclxuXHRzZXQoIHgsIHksIHogKSB7XHJcblxyXG5cdFx0aWYgKCB6ID09PSB1bmRlZmluZWQgKSB6ID0gdGhpcy56OyAvLyBzcHJpdGUuc2NhbGUuc2V0KHgseSlcclxuXHJcblx0XHR0aGlzLnggPSB4O1xyXG5cdFx0dGhpcy55ID0geTtcclxuXHRcdHRoaXMueiA9IHo7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0U2NhbGFyKCBzY2FsYXIgKSB7XHJcblxyXG5cdFx0dGhpcy54ID0gc2NhbGFyO1xyXG5cdFx0dGhpcy55ID0gc2NhbGFyO1xyXG5cdFx0dGhpcy56ID0gc2NhbGFyO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldFgoIHggKSB7XHJcblxyXG5cdFx0dGhpcy54ID0geDtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRZKCB5ICkge1xyXG5cclxuXHRcdHRoaXMueSA9IHk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0WiggeiApIHtcclxuXHJcblx0XHR0aGlzLnogPSB6O1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldENvbXBvbmVudCggaW5kZXgsIHZhbHVlICkge1xyXG5cclxuXHRcdHN3aXRjaCAoIGluZGV4ICkge1xyXG5cclxuXHRcdFx0Y2FzZSAwOiB0aGlzLnggPSB2YWx1ZTsgYnJlYWs7XHJcblx0XHRcdGNhc2UgMTogdGhpcy55ID0gdmFsdWU7IGJyZWFrO1xyXG5cdFx0XHRjYXNlIDI6IHRoaXMueiA9IHZhbHVlOyBicmVhaztcclxuXHRcdFx0ZGVmYXVsdDogdGhyb3cgbmV3IEVycm9yKCAnaW5kZXggaXMgb3V0IG9mIHJhbmdlOiAnICsgaW5kZXggKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0Q29tcG9uZW50KCBpbmRleCApIHtcclxuXHJcblx0XHRzd2l0Y2ggKCBpbmRleCApIHtcclxuXHJcblx0XHRcdGNhc2UgMDogcmV0dXJuIHRoaXMueDtcclxuXHRcdFx0Y2FzZSAxOiByZXR1cm4gdGhpcy55O1xyXG5cdFx0XHRjYXNlIDI6IHJldHVybiB0aGlzLno7XHJcblx0XHRcdGRlZmF1bHQ6IHRocm93IG5ldyBFcnJvciggJ2luZGV4IGlzIG91dCBvZiByYW5nZTogJyArIGluZGV4ICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGNsb25lKCkge1xyXG5cclxuXHRcdHJldHVybiBuZXcgdGhpcy5jb25zdHJ1Y3RvciggdGhpcy54LCB0aGlzLnksIHRoaXMueiApO1xyXG5cclxuXHR9XHJcblxyXG5cdGNvcHkoIHYgKSB7XHJcblxyXG5cdFx0dGhpcy54ID0gdi54O1xyXG5cdFx0dGhpcy55ID0gdi55O1xyXG5cdFx0dGhpcy56ID0gdi56O1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGFkZCggdiApIHtcclxuXHJcblx0XHR0aGlzLnggKz0gdi54O1xyXG5cdFx0dGhpcy55ICs9IHYueTtcclxuXHRcdHRoaXMueiArPSB2Lno7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0YWRkU2NhbGFyKCBzICkge1xyXG5cclxuXHRcdHRoaXMueCArPSBzO1xyXG5cdFx0dGhpcy55ICs9IHM7XHJcblx0XHR0aGlzLnogKz0gcztcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRhZGRWZWN0b3JzKCBhLCBiICkge1xyXG5cclxuXHRcdHRoaXMueCA9IGEueCArIGIueDtcclxuXHRcdHRoaXMueSA9IGEueSArIGIueTtcclxuXHRcdHRoaXMueiA9IGEueiArIGIuejtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRhZGRTY2FsZWRWZWN0b3IoIHYsIHMgKSB7XHJcblxyXG5cdFx0dGhpcy54ICs9IHYueCAqIHM7XHJcblx0XHR0aGlzLnkgKz0gdi55ICogcztcclxuXHRcdHRoaXMueiArPSB2LnogKiBzO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHN1YiggdiApIHtcclxuXHJcblx0XHR0aGlzLnggLT0gdi54O1xyXG5cdFx0dGhpcy55IC09IHYueTtcclxuXHRcdHRoaXMueiAtPSB2Lno7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0c3ViU2NhbGFyKCBzICkge1xyXG5cclxuXHRcdHRoaXMueCAtPSBzO1xyXG5cdFx0dGhpcy55IC09IHM7XHJcblx0XHR0aGlzLnogLT0gcztcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzdWJWZWN0b3JzKCBhLCBiICkge1xyXG5cclxuXHRcdHRoaXMueCA9IGEueCAtIGIueDtcclxuXHRcdHRoaXMueSA9IGEueSAtIGIueTtcclxuXHRcdHRoaXMueiA9IGEueiAtIGIuejtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRtdWx0aXBseSggdiApIHtcclxuXHJcblx0XHR0aGlzLnggKj0gdi54O1xyXG5cdFx0dGhpcy55ICo9IHYueTtcclxuXHRcdHRoaXMueiAqPSB2Lno7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0bXVsdGlwbHlTY2FsYXIoIHNjYWxhciApIHtcclxuXHJcblx0XHR0aGlzLnggKj0gc2NhbGFyO1xyXG5cdFx0dGhpcy55ICo9IHNjYWxhcjtcclxuXHRcdHRoaXMueiAqPSBzY2FsYXI7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0bXVsdGlwbHlWZWN0b3JzKCBhLCBiICkge1xyXG5cclxuXHRcdHRoaXMueCA9IGEueCAqIGIueDtcclxuXHRcdHRoaXMueSA9IGEueSAqIGIueTtcclxuXHRcdHRoaXMueiA9IGEueiAqIGIuejtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRhcHBseUV1bGVyKCBldWxlciApIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5hcHBseVF1YXRlcm5pb24oIF9xdWF0ZXJuaW9uLnNldEZyb21FdWxlciggZXVsZXIgKSApO1xyXG5cclxuXHR9XHJcblxyXG5cdGFwcGx5QXhpc0FuZ2xlKCBheGlzLCBhbmdsZSApIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5hcHBseVF1YXRlcm5pb24oIF9xdWF0ZXJuaW9uLnNldEZyb21BeGlzQW5nbGUoIGF4aXMsIGFuZ2xlICkgKTtcclxuXHJcblx0fVxyXG5cclxuXHRhcHBseU1hdHJpeDMoIG0gKSB7XHJcblxyXG5cdFx0Y29uc3QgeCA9IHRoaXMueCwgeSA9IHRoaXMueSwgeiA9IHRoaXMuejtcclxuXHRcdGNvbnN0IGUgPSBtLmVsZW1lbnRzO1xyXG5cclxuXHRcdHRoaXMueCA9IGVbIDAgXSAqIHggKyBlWyAzIF0gKiB5ICsgZVsgNiBdICogejtcclxuXHRcdHRoaXMueSA9IGVbIDEgXSAqIHggKyBlWyA0IF0gKiB5ICsgZVsgNyBdICogejtcclxuXHRcdHRoaXMueiA9IGVbIDIgXSAqIHggKyBlWyA1IF0gKiB5ICsgZVsgOCBdICogejtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRhcHBseU5vcm1hbE1hdHJpeCggbSApIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5hcHBseU1hdHJpeDMoIG0gKS5ub3JtYWxpemUoKTtcclxuXHJcblx0fVxyXG5cclxuXHRhcHBseU1hdHJpeDQoIG0gKSB7XHJcblxyXG5cdFx0Y29uc3QgeCA9IHRoaXMueCwgeSA9IHRoaXMueSwgeiA9IHRoaXMuejtcclxuXHRcdGNvbnN0IGUgPSBtLmVsZW1lbnRzO1xyXG5cclxuXHRcdGNvbnN0IHcgPSAxIC8gKCBlWyAzIF0gKiB4ICsgZVsgNyBdICogeSArIGVbIDExIF0gKiB6ICsgZVsgMTUgXSApO1xyXG5cclxuXHRcdHRoaXMueCA9ICggZVsgMCBdICogeCArIGVbIDQgXSAqIHkgKyBlWyA4IF0gKiB6ICsgZVsgMTIgXSApICogdztcclxuXHRcdHRoaXMueSA9ICggZVsgMSBdICogeCArIGVbIDUgXSAqIHkgKyBlWyA5IF0gKiB6ICsgZVsgMTMgXSApICogdztcclxuXHRcdHRoaXMueiA9ICggZVsgMiBdICogeCArIGVbIDYgXSAqIHkgKyBlWyAxMCBdICogeiArIGVbIDE0IF0gKSAqIHc7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0YXBwbHlRdWF0ZXJuaW9uKCBxICkge1xyXG5cclxuXHRcdC8vIHF1YXRlcm5pb24gcSBpcyBhc3N1bWVkIHRvIGhhdmUgdW5pdCBsZW5ndGhcclxuXHJcblx0XHRjb25zdCB2eCA9IHRoaXMueCwgdnkgPSB0aGlzLnksIHZ6ID0gdGhpcy56O1xyXG5cdFx0Y29uc3QgcXggPSBxLngsIHF5ID0gcS55LCBxeiA9IHEueiwgcXcgPSBxLnc7XHJcblxyXG5cdFx0Ly8gdCA9IDIgKiBjcm9zcyggcS54eXosIHYgKTtcclxuXHRcdGNvbnN0IHR4ID0gMiAqICggcXkgKiB2eiAtIHF6ICogdnkgKTtcclxuXHRcdGNvbnN0IHR5ID0gMiAqICggcXogKiB2eCAtIHF4ICogdnogKTtcclxuXHRcdGNvbnN0IHR6ID0gMiAqICggcXggKiB2eSAtIHF5ICogdnggKTtcclxuXHJcblx0XHQvLyB2ICsgcS53ICogdCArIGNyb3NzKCBxLnh5eiwgdCApO1xyXG5cdFx0dGhpcy54ID0gdnggKyBxdyAqIHR4ICsgcXkgKiB0eiAtIHF6ICogdHk7XHJcblx0XHR0aGlzLnkgPSB2eSArIHF3ICogdHkgKyBxeiAqIHR4IC0gcXggKiB0ejtcclxuXHRcdHRoaXMueiA9IHZ6ICsgcXcgKiB0eiArIHF4ICogdHkgLSBxeSAqIHR4O1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHByb2plY3QoIGNhbWVyYSApIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5hcHBseU1hdHJpeDQoIGNhbWVyYS5tYXRyaXhXb3JsZEludmVyc2UgKS5hcHBseU1hdHJpeDQoIGNhbWVyYS5wcm9qZWN0aW9uTWF0cml4ICk7XHJcblxyXG5cdH1cclxuXHJcblx0dW5wcm9qZWN0KCBjYW1lcmEgKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuYXBwbHlNYXRyaXg0KCBjYW1lcmEucHJvamVjdGlvbk1hdHJpeEludmVyc2UgKS5hcHBseU1hdHJpeDQoIGNhbWVyYS5tYXRyaXhXb3JsZCApO1xyXG5cclxuXHR9XHJcblxyXG5cdHRyYW5zZm9ybURpcmVjdGlvbiggbSApIHtcclxuXHJcblx0XHQvLyBpbnB1dDogVEhSRUUuTWF0cml4NCBhZmZpbmUgbWF0cml4XHJcblx0XHQvLyB2ZWN0b3IgaW50ZXJwcmV0ZWQgYXMgYSBkaXJlY3Rpb25cclxuXHJcblx0XHRjb25zdCB4ID0gdGhpcy54LCB5ID0gdGhpcy55LCB6ID0gdGhpcy56O1xyXG5cdFx0Y29uc3QgZSA9IG0uZWxlbWVudHM7XHJcblxyXG5cdFx0dGhpcy54ID0gZVsgMCBdICogeCArIGVbIDQgXSAqIHkgKyBlWyA4IF0gKiB6O1xyXG5cdFx0dGhpcy55ID0gZVsgMSBdICogeCArIGVbIDUgXSAqIHkgKyBlWyA5IF0gKiB6O1xyXG5cdFx0dGhpcy56ID0gZVsgMiBdICogeCArIGVbIDYgXSAqIHkgKyBlWyAxMCBdICogejtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5ub3JtYWxpemUoKTtcclxuXHJcblx0fVxyXG5cclxuXHRkaXZpZGUoIHYgKSB7XHJcblxyXG5cdFx0dGhpcy54IC89IHYueDtcclxuXHRcdHRoaXMueSAvPSB2Lnk7XHJcblx0XHR0aGlzLnogLz0gdi56O1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGRpdmlkZVNjYWxhciggc2NhbGFyICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLm11bHRpcGx5U2NhbGFyKCAxIC8gc2NhbGFyICk7XHJcblxyXG5cdH1cclxuXHJcblx0bWluKCB2ICkge1xyXG5cclxuXHRcdHRoaXMueCA9IE1hdGgubWluKCB0aGlzLngsIHYueCApO1xyXG5cdFx0dGhpcy55ID0gTWF0aC5taW4oIHRoaXMueSwgdi55ICk7XHJcblx0XHR0aGlzLnogPSBNYXRoLm1pbiggdGhpcy56LCB2LnogKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRtYXgoIHYgKSB7XHJcblxyXG5cdFx0dGhpcy54ID0gTWF0aC5tYXgoIHRoaXMueCwgdi54ICk7XHJcblx0XHR0aGlzLnkgPSBNYXRoLm1heCggdGhpcy55LCB2LnkgKTtcclxuXHRcdHRoaXMueiA9IE1hdGgubWF4KCB0aGlzLnosIHYueiApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGNsYW1wKCBtaW4sIG1heCApIHtcclxuXHJcblx0XHQvLyBhc3N1bWVzIG1pbiA8IG1heCwgY29tcG9uZW50d2lzZVxyXG5cclxuXHRcdHRoaXMueCA9IE1hdGgubWF4KCBtaW4ueCwgTWF0aC5taW4oIG1heC54LCB0aGlzLnggKSApO1xyXG5cdFx0dGhpcy55ID0gTWF0aC5tYXgoIG1pbi55LCBNYXRoLm1pbiggbWF4LnksIHRoaXMueSApICk7XHJcblx0XHR0aGlzLnogPSBNYXRoLm1heCggbWluLnosIE1hdGgubWluKCBtYXgueiwgdGhpcy56ICkgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRjbGFtcFNjYWxhciggbWluVmFsLCBtYXhWYWwgKSB7XHJcblxyXG5cdFx0dGhpcy54ID0gTWF0aC5tYXgoIG1pblZhbCwgTWF0aC5taW4oIG1heFZhbCwgdGhpcy54ICkgKTtcclxuXHRcdHRoaXMueSA9IE1hdGgubWF4KCBtaW5WYWwsIE1hdGgubWluKCBtYXhWYWwsIHRoaXMueSApICk7XHJcblx0XHR0aGlzLnogPSBNYXRoLm1heCggbWluVmFsLCBNYXRoLm1pbiggbWF4VmFsLCB0aGlzLnogKSApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGNsYW1wTGVuZ3RoKCBtaW4sIG1heCApIHtcclxuXHJcblx0XHRjb25zdCBsZW5ndGggPSB0aGlzLmxlbmd0aCgpO1xyXG5cclxuXHRcdHJldHVybiB0aGlzLmRpdmlkZVNjYWxhciggbGVuZ3RoIHx8IDEgKS5tdWx0aXBseVNjYWxhciggTWF0aC5tYXgoIG1pbiwgTWF0aC5taW4oIG1heCwgbGVuZ3RoICkgKSApO1xyXG5cclxuXHR9XHJcblxyXG5cdGZsb29yKCkge1xyXG5cclxuXHRcdHRoaXMueCA9IE1hdGguZmxvb3IoIHRoaXMueCApO1xyXG5cdFx0dGhpcy55ID0gTWF0aC5mbG9vciggdGhpcy55ICk7XHJcblx0XHR0aGlzLnogPSBNYXRoLmZsb29yKCB0aGlzLnogKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRjZWlsKCkge1xyXG5cclxuXHRcdHRoaXMueCA9IE1hdGguY2VpbCggdGhpcy54ICk7XHJcblx0XHR0aGlzLnkgPSBNYXRoLmNlaWwoIHRoaXMueSApO1xyXG5cdFx0dGhpcy56ID0gTWF0aC5jZWlsKCB0aGlzLnogKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRyb3VuZCgpIHtcclxuXHJcblx0XHR0aGlzLnggPSBNYXRoLnJvdW5kKCB0aGlzLnggKTtcclxuXHRcdHRoaXMueSA9IE1hdGgucm91bmQoIHRoaXMueSApO1xyXG5cdFx0dGhpcy56ID0gTWF0aC5yb3VuZCggdGhpcy56ICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0cm91bmRUb1plcm8oKSB7XHJcblxyXG5cdFx0dGhpcy54ID0gTWF0aC50cnVuYyggdGhpcy54ICk7XHJcblx0XHR0aGlzLnkgPSBNYXRoLnRydW5jKCB0aGlzLnkgKTtcclxuXHRcdHRoaXMueiA9IE1hdGgudHJ1bmMoIHRoaXMueiApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdG5lZ2F0ZSgpIHtcclxuXHJcblx0XHR0aGlzLnggPSAtIHRoaXMueDtcclxuXHRcdHRoaXMueSA9IC0gdGhpcy55O1xyXG5cdFx0dGhpcy56ID0gLSB0aGlzLno7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0ZG90KCB2ICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLnggKiB2LnggKyB0aGlzLnkgKiB2LnkgKyB0aGlzLnogKiB2Lno7XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gVE9ETyBsZW5ndGhTcXVhcmVkP1xyXG5cclxuXHRsZW5ndGhTcSgpIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy54ICogdGhpcy54ICsgdGhpcy55ICogdGhpcy55ICsgdGhpcy56ICogdGhpcy56O1xyXG5cclxuXHR9XHJcblxyXG5cdGxlbmd0aCgpIHtcclxuXHJcblx0XHRyZXR1cm4gTWF0aC5zcXJ0KCB0aGlzLnggKiB0aGlzLnggKyB0aGlzLnkgKiB0aGlzLnkgKyB0aGlzLnogKiB0aGlzLnogKTtcclxuXHJcblx0fVxyXG5cclxuXHRtYW5oYXR0YW5MZW5ndGgoKSB7XHJcblxyXG5cdFx0cmV0dXJuIE1hdGguYWJzKCB0aGlzLnggKSArIE1hdGguYWJzKCB0aGlzLnkgKSArIE1hdGguYWJzKCB0aGlzLnogKTtcclxuXHJcblx0fVxyXG5cclxuXHRub3JtYWxpemUoKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuZGl2aWRlU2NhbGFyKCB0aGlzLmxlbmd0aCgpIHx8IDEgKTtcclxuXHJcblx0fVxyXG5cclxuXHRzZXRMZW5ndGgoIGxlbmd0aCApIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5ub3JtYWxpemUoKS5tdWx0aXBseVNjYWxhciggbGVuZ3RoICk7XHJcblxyXG5cdH1cclxuXHJcblx0bGVycCggdiwgYWxwaGEgKSB7XHJcblxyXG5cdFx0dGhpcy54ICs9ICggdi54IC0gdGhpcy54ICkgKiBhbHBoYTtcclxuXHRcdHRoaXMueSArPSAoIHYueSAtIHRoaXMueSApICogYWxwaGE7XHJcblx0XHR0aGlzLnogKz0gKCB2LnogLSB0aGlzLnogKSAqIGFscGhhO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGxlcnBWZWN0b3JzKCB2MSwgdjIsIGFscGhhICkge1xyXG5cclxuXHRcdHRoaXMueCA9IHYxLnggKyAoIHYyLnggLSB2MS54ICkgKiBhbHBoYTtcclxuXHRcdHRoaXMueSA9IHYxLnkgKyAoIHYyLnkgLSB2MS55ICkgKiBhbHBoYTtcclxuXHRcdHRoaXMueiA9IHYxLnogKyAoIHYyLnogLSB2MS56ICkgKiBhbHBoYTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRjcm9zcyggdiApIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5jcm9zc1ZlY3RvcnMoIHRoaXMsIHYgKTtcclxuXHJcblx0fVxyXG5cclxuXHRjcm9zc1ZlY3RvcnMoIGEsIGIgKSB7XHJcblxyXG5cdFx0Y29uc3QgYXggPSBhLngsIGF5ID0gYS55LCBheiA9IGEuejtcclxuXHRcdGNvbnN0IGJ4ID0gYi54LCBieSA9IGIueSwgYnogPSBiLno7XHJcblxyXG5cdFx0dGhpcy54ID0gYXkgKiBieiAtIGF6ICogYnk7XHJcblx0XHR0aGlzLnkgPSBheiAqIGJ4IC0gYXggKiBiejtcclxuXHRcdHRoaXMueiA9IGF4ICogYnkgLSBheSAqIGJ4O1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHByb2plY3RPblZlY3RvciggdiApIHtcclxuXHJcblx0XHRjb25zdCBkZW5vbWluYXRvciA9IHYubGVuZ3RoU3EoKTtcclxuXHJcblx0XHRpZiAoIGRlbm9taW5hdG9yID09PSAwICkgcmV0dXJuIHRoaXMuc2V0KCAwLCAwLCAwICk7XHJcblxyXG5cdFx0Y29uc3Qgc2NhbGFyID0gdi5kb3QoIHRoaXMgKSAvIGRlbm9taW5hdG9yO1xyXG5cclxuXHRcdHJldHVybiB0aGlzLmNvcHkoIHYgKS5tdWx0aXBseVNjYWxhciggc2NhbGFyICk7XHJcblxyXG5cdH1cclxuXHJcblx0cHJvamVjdE9uUGxhbmUoIHBsYW5lTm9ybWFsICkge1xyXG5cclxuXHRcdF92ZWN0b3IuY29weSggdGhpcyApLnByb2plY3RPblZlY3RvciggcGxhbmVOb3JtYWwgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5zdWIoIF92ZWN0b3IgKTtcclxuXHJcblx0fVxyXG5cclxuXHRyZWZsZWN0KCBub3JtYWwgKSB7XHJcblxyXG5cdFx0Ly8gcmVmbGVjdCBpbmNpZGVudCB2ZWN0b3Igb2ZmIHBsYW5lIG9ydGhvZ29uYWwgdG8gbm9ybWFsXHJcblx0XHQvLyBub3JtYWwgaXMgYXNzdW1lZCB0byBoYXZlIHVuaXQgbGVuZ3RoXHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuc3ViKCBfdmVjdG9yLmNvcHkoIG5vcm1hbCApLm11bHRpcGx5U2NhbGFyKCAyICogdGhpcy5kb3QoIG5vcm1hbCApICkgKTtcclxuXHJcblx0fVxyXG5cclxuXHRhbmdsZVRvKCB2ICkge1xyXG5cclxuXHRcdGNvbnN0IGRlbm9taW5hdG9yID0gTWF0aC5zcXJ0KCB0aGlzLmxlbmd0aFNxKCkgKiB2Lmxlbmd0aFNxKCkgKTtcclxuXHJcblx0XHRpZiAoIGRlbm9taW5hdG9yID09PSAwICkgcmV0dXJuIE1hdGguUEkgLyAyO1xyXG5cclxuXHRcdGNvbnN0IHRoZXRhID0gdGhpcy5kb3QoIHYgKSAvIGRlbm9taW5hdG9yO1xyXG5cclxuXHRcdC8vIGNsYW1wLCB0byBoYW5kbGUgbnVtZXJpY2FsIHByb2JsZW1zXHJcblxyXG5cdFx0cmV0dXJuIE1hdGguYWNvcyggTWF0aFV0aWxzLmNsYW1wKCB0aGV0YSwgLSAxLCAxICkgKTtcclxuXHJcblx0fVxyXG5cclxuXHRkaXN0YW5jZVRvKCB2ICkge1xyXG5cclxuXHRcdHJldHVybiBNYXRoLnNxcnQoIHRoaXMuZGlzdGFuY2VUb1NxdWFyZWQoIHYgKSApO1xyXG5cclxuXHR9XHJcblxyXG5cdGRpc3RhbmNlVG9TcXVhcmVkKCB2ICkge1xyXG5cclxuXHRcdGNvbnN0IGR4ID0gdGhpcy54IC0gdi54LCBkeSA9IHRoaXMueSAtIHYueSwgZHogPSB0aGlzLnogLSB2Lno7XHJcblxyXG5cdFx0cmV0dXJuIGR4ICogZHggKyBkeSAqIGR5ICsgZHogKiBkejtcclxuXHJcblx0fVxyXG5cclxuXHRtYW5oYXR0YW5EaXN0YW5jZVRvKCB2ICkge1xyXG5cclxuXHRcdHJldHVybiBNYXRoLmFicyggdGhpcy54IC0gdi54ICkgKyBNYXRoLmFicyggdGhpcy55IC0gdi55ICkgKyBNYXRoLmFicyggdGhpcy56IC0gdi56ICk7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0RnJvbVNwaGVyaWNhbCggcyApIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5zZXRGcm9tU3BoZXJpY2FsQ29vcmRzKCBzLnJhZGl1cywgcy5waGksIHMudGhldGEgKTtcclxuXHJcblx0fVxyXG5cclxuXHRzZXRGcm9tU3BoZXJpY2FsQ29vcmRzKCByYWRpdXMsIHBoaSwgdGhldGEgKSB7XHJcblxyXG5cdFx0Y29uc3Qgc2luUGhpUmFkaXVzID0gTWF0aC5zaW4oIHBoaSApICogcmFkaXVzO1xyXG5cclxuXHRcdHRoaXMueCA9IHNpblBoaVJhZGl1cyAqIE1hdGguc2luKCB0aGV0YSApO1xyXG5cdFx0dGhpcy55ID0gTWF0aC5jb3MoIHBoaSApICogcmFkaXVzO1xyXG5cdFx0dGhpcy56ID0gc2luUGhpUmFkaXVzICogTWF0aC5jb3MoIHRoZXRhICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0RnJvbUN5bGluZHJpY2FsKCBjICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLnNldEZyb21DeWxpbmRyaWNhbENvb3JkcyggYy5yYWRpdXMsIGMudGhldGEsIGMueSApO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldEZyb21DeWxpbmRyaWNhbENvb3JkcyggcmFkaXVzLCB0aGV0YSwgeSApIHtcclxuXHJcblx0XHR0aGlzLnggPSByYWRpdXMgKiBNYXRoLnNpbiggdGhldGEgKTtcclxuXHRcdHRoaXMueSA9IHk7XHJcblx0XHR0aGlzLnogPSByYWRpdXMgKiBNYXRoLmNvcyggdGhldGEgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRGcm9tTWF0cml4UG9zaXRpb24oIG0gKSB7XHJcblxyXG5cdFx0Y29uc3QgZSA9IG0uZWxlbWVudHM7XHJcblxyXG5cdFx0dGhpcy54ID0gZVsgMTIgXTtcclxuXHRcdHRoaXMueSA9IGVbIDEzIF07XHJcblx0XHR0aGlzLnogPSBlWyAxNCBdO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldEZyb21NYXRyaXhTY2FsZSggbSApIHtcclxuXHJcblx0XHRjb25zdCBzeCA9IHRoaXMuc2V0RnJvbU1hdHJpeENvbHVtbiggbSwgMCApLmxlbmd0aCgpO1xyXG5cdFx0Y29uc3Qgc3kgPSB0aGlzLnNldEZyb21NYXRyaXhDb2x1bW4oIG0sIDEgKS5sZW5ndGgoKTtcclxuXHRcdGNvbnN0IHN6ID0gdGhpcy5zZXRGcm9tTWF0cml4Q29sdW1uKCBtLCAyICkubGVuZ3RoKCk7XHJcblxyXG5cdFx0dGhpcy54ID0gc3g7XHJcblx0XHR0aGlzLnkgPSBzeTtcclxuXHRcdHRoaXMueiA9IHN6O1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldEZyb21NYXRyaXhDb2x1bW4oIG0sIGluZGV4ICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLmZyb21BcnJheSggbS5lbGVtZW50cywgaW5kZXggKiA0ICk7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0RnJvbU1hdHJpeDNDb2x1bW4oIG0sIGluZGV4ICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLmZyb21BcnJheSggbS5lbGVtZW50cywgaW5kZXggKiAzICk7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0RnJvbUV1bGVyKCBlICkge1xyXG5cclxuXHRcdHRoaXMueCA9IGUuX3g7XHJcblx0XHR0aGlzLnkgPSBlLl95O1xyXG5cdFx0dGhpcy56ID0gZS5fejtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRGcm9tQ29sb3IoIGMgKSB7XHJcblxyXG5cdFx0dGhpcy54ID0gYy5yO1xyXG5cdFx0dGhpcy55ID0gYy5nO1xyXG5cdFx0dGhpcy56ID0gYy5iO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGVxdWFscyggdiApIHtcclxuXHJcblx0XHRyZXR1cm4gKCAoIHYueCA9PT0gdGhpcy54ICkgJiYgKCB2LnkgPT09IHRoaXMueSApICYmICggdi56ID09PSB0aGlzLnogKSApO1xyXG5cclxuXHR9XHJcblxyXG5cdGZyb21BcnJheSggYXJyYXksIG9mZnNldCA9IDAgKSB7XHJcblxyXG5cdFx0dGhpcy54ID0gYXJyYXlbIG9mZnNldCBdO1xyXG5cdFx0dGhpcy55ID0gYXJyYXlbIG9mZnNldCArIDEgXTtcclxuXHRcdHRoaXMueiA9IGFycmF5WyBvZmZzZXQgKyAyIF07XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0dG9BcnJheSggYXJyYXkgPSBbXSwgb2Zmc2V0ID0gMCApIHtcclxuXHJcblx0XHRhcnJheVsgb2Zmc2V0IF0gPSB0aGlzLng7XHJcblx0XHRhcnJheVsgb2Zmc2V0ICsgMSBdID0gdGhpcy55O1xyXG5cdFx0YXJyYXlbIG9mZnNldCArIDIgXSA9IHRoaXMuejtcclxuXHJcblx0XHRyZXR1cm4gYXJyYXk7XHJcblxyXG5cdH1cclxuXHJcblx0ZnJvbUJ1ZmZlckF0dHJpYnV0ZSggYXR0cmlidXRlLCBpbmRleCApIHtcclxuXHJcblx0XHR0aGlzLnggPSBhdHRyaWJ1dGUuZ2V0WCggaW5kZXggKTtcclxuXHRcdHRoaXMueSA9IGF0dHJpYnV0ZS5nZXRZKCBpbmRleCApO1xyXG5cdFx0dGhpcy56ID0gYXR0cmlidXRlLmdldFooIGluZGV4ICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0cmFuZG9tKCkge1xyXG5cclxuXHRcdHRoaXMueCA9IE1hdGgucmFuZG9tKCk7XHJcblx0XHR0aGlzLnkgPSBNYXRoLnJhbmRvbSgpO1xyXG5cdFx0dGhpcy56ID0gTWF0aC5yYW5kb20oKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRyYW5kb21EaXJlY3Rpb24oKSB7XHJcblxyXG5cdFx0Ly8gRGVyaXZlZCBmcm9tIGh0dHBzOi8vbWF0aHdvcmxkLndvbGZyYW0uY29tL1NwaGVyZVBvaW50UGlja2luZy5odG1sXHJcblxyXG5cdFx0Y29uc3QgdSA9ICggTWF0aC5yYW5kb20oKSAtIDAuNSApICogMjtcclxuXHRcdGNvbnN0IHQgPSBNYXRoLnJhbmRvbSgpICogTWF0aC5QSSAqIDI7XHJcblx0XHRjb25zdCBmID0gTWF0aC5zcXJ0KCAxIC0gdSAqKiAyICk7XHJcblxyXG5cdFx0dGhpcy54ID0gZiAqIE1hdGguY29zKCB0ICk7XHJcblx0XHR0aGlzLnkgPSBmICogTWF0aC5zaW4oIHQgKTtcclxuXHRcdHRoaXMueiA9IHU7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0KlsgU3ltYm9sLml0ZXJhdG9yIF0oKSB7XHJcblxyXG5cdFx0eWllbGQgdGhpcy54O1xyXG5cdFx0eWllbGQgdGhpcy55O1xyXG5cdFx0eWllbGQgdGhpcy56O1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5jb25zdCBfdmVjdG9yID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5jb25zdCBfcXVhdGVybmlvbiA9IC8qQF9fUFVSRV9fKi8gbmV3IFF1YXRlcm5pb24oKTtcclxuXHJcbmV4cG9ydCB7IFZlY3RvcjMgfTtcclxuIiwiaW1wb3J0IHsgVmVjdG9yMyB9IGZyb20gJy4vVmVjdG9yMy5qcyc7XHJcblxyXG5jbGFzcyBCb3gzIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIG1pbiA9IG5ldyBWZWN0b3IzKCArIEluZmluaXR5LCArIEluZmluaXR5LCArIEluZmluaXR5ICksIG1heCA9IG5ldyBWZWN0b3IzKCAtIEluZmluaXR5LCAtIEluZmluaXR5LCAtIEluZmluaXR5ICkgKSB7XHJcblxyXG5cdFx0dGhpcy5pc0JveDMgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMubWluID0gbWluO1xyXG5cdFx0dGhpcy5tYXggPSBtYXg7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0KCBtaW4sIG1heCApIHtcclxuXHJcblx0XHR0aGlzLm1pbi5jb3B5KCBtaW4gKTtcclxuXHRcdHRoaXMubWF4LmNvcHkoIG1heCApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldEZyb21BcnJheSggYXJyYXkgKSB7XHJcblxyXG5cdFx0dGhpcy5tYWtlRW1wdHkoKTtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gYXJyYXkubGVuZ3RoOyBpIDwgaWw7IGkgKz0gMyApIHtcclxuXHJcblx0XHRcdHRoaXMuZXhwYW5kQnlQb2ludCggX3ZlY3Rvci5mcm9tQXJyYXkoIGFycmF5LCBpICkgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0RnJvbUJ1ZmZlckF0dHJpYnV0ZSggYXR0cmlidXRlICkge1xyXG5cclxuXHRcdHRoaXMubWFrZUVtcHR5KCk7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBpbCA9IGF0dHJpYnV0ZS5jb3VudDsgaSA8IGlsOyBpICsrICkge1xyXG5cclxuXHRcdFx0dGhpcy5leHBhbmRCeVBvaW50KCBfdmVjdG9yLmZyb21CdWZmZXJBdHRyaWJ1dGUoIGF0dHJpYnV0ZSwgaSApICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldEZyb21Qb2ludHMoIHBvaW50cyApIHtcclxuXHJcblx0XHR0aGlzLm1ha2VFbXB0eSgpO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSBwb2ludHMubGVuZ3RoOyBpIDwgaWw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHR0aGlzLmV4cGFuZEJ5UG9pbnQoIHBvaW50c1sgaSBdICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldEZyb21DZW50ZXJBbmRTaXplKCBjZW50ZXIsIHNpemUgKSB7XHJcblxyXG5cdFx0Y29uc3QgaGFsZlNpemUgPSBfdmVjdG9yLmNvcHkoIHNpemUgKS5tdWx0aXBseVNjYWxhciggMC41ICk7XHJcblxyXG5cdFx0dGhpcy5taW4uY29weSggY2VudGVyICkuc3ViKCBoYWxmU2l6ZSApO1xyXG5cdFx0dGhpcy5tYXguY29weSggY2VudGVyICkuYWRkKCBoYWxmU2l6ZSApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldEZyb21PYmplY3QoIG9iamVjdCwgcHJlY2lzZSA9IGZhbHNlICkge1xyXG5cclxuXHRcdHRoaXMubWFrZUVtcHR5KCk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuZXhwYW5kQnlPYmplY3QoIG9iamVjdCwgcHJlY2lzZSApO1xyXG5cclxuXHR9XHJcblxyXG5cdGNsb25lKCkge1xyXG5cclxuXHRcdHJldHVybiBuZXcgdGhpcy5jb25zdHJ1Y3RvcigpLmNvcHkoIHRoaXMgKTtcclxuXHJcblx0fVxyXG5cclxuXHRjb3B5KCBib3ggKSB7XHJcblxyXG5cdFx0dGhpcy5taW4uY29weSggYm94Lm1pbiApO1xyXG5cdFx0dGhpcy5tYXguY29weSggYm94Lm1heCApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdG1ha2VFbXB0eSgpIHtcclxuXHJcblx0XHR0aGlzLm1pbi54ID0gdGhpcy5taW4ueSA9IHRoaXMubWluLnogPSArIEluZmluaXR5O1xyXG5cdFx0dGhpcy5tYXgueCA9IHRoaXMubWF4LnkgPSB0aGlzLm1heC56ID0gLSBJbmZpbml0eTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRpc0VtcHR5KCkge1xyXG5cclxuXHRcdC8vIHRoaXMgaXMgYSBtb3JlIHJvYnVzdCBjaGVjayBmb3IgZW1wdHkgdGhhbiAoIHZvbHVtZSA8PSAwICkgYmVjYXVzZSB2b2x1bWUgY2FuIGdldCBwb3NpdGl2ZSB3aXRoIHR3byBuZWdhdGl2ZSBheGVzXHJcblxyXG5cdFx0cmV0dXJuICggdGhpcy5tYXgueCA8IHRoaXMubWluLnggKSB8fCAoIHRoaXMubWF4LnkgPCB0aGlzLm1pbi55ICkgfHwgKCB0aGlzLm1heC56IDwgdGhpcy5taW4ueiApO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldENlbnRlciggdGFyZ2V0ICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLmlzRW1wdHkoKSA/IHRhcmdldC5zZXQoIDAsIDAsIDAgKSA6IHRhcmdldC5hZGRWZWN0b3JzKCB0aGlzLm1pbiwgdGhpcy5tYXggKS5tdWx0aXBseVNjYWxhciggMC41ICk7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0U2l6ZSggdGFyZ2V0ICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLmlzRW1wdHkoKSA/IHRhcmdldC5zZXQoIDAsIDAsIDAgKSA6IHRhcmdldC5zdWJWZWN0b3JzKCB0aGlzLm1heCwgdGhpcy5taW4gKTtcclxuXHJcblx0fVxyXG5cclxuXHRleHBhbmRCeVBvaW50KCBwb2ludCApIHtcclxuXHJcblx0XHR0aGlzLm1pbi5taW4oIHBvaW50ICk7XHJcblx0XHR0aGlzLm1heC5tYXgoIHBvaW50ICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0ZXhwYW5kQnlWZWN0b3IoIHZlY3RvciApIHtcclxuXHJcblx0XHR0aGlzLm1pbi5zdWIoIHZlY3RvciApO1xyXG5cdFx0dGhpcy5tYXguYWRkKCB2ZWN0b3IgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRleHBhbmRCeVNjYWxhciggc2NhbGFyICkge1xyXG5cclxuXHRcdHRoaXMubWluLmFkZFNjYWxhciggLSBzY2FsYXIgKTtcclxuXHRcdHRoaXMubWF4LmFkZFNjYWxhciggc2NhbGFyICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0ZXhwYW5kQnlPYmplY3QoIG9iamVjdCwgcHJlY2lzZSA9IGZhbHNlICkge1xyXG5cclxuXHRcdC8vIENvbXB1dGVzIHRoZSB3b3JsZC1heGlzLWFsaWduZWQgYm91bmRpbmcgYm94IG9mIGFuIG9iamVjdCAoaW5jbHVkaW5nIGl0cyBjaGlsZHJlbiksXHJcblx0XHQvLyBhY2NvdW50aW5nIGZvciBib3RoIHRoZSBvYmplY3QncywgYW5kIGNoaWxkcmVuJ3MsIHdvcmxkIHRyYW5zZm9ybXNcclxuXHJcblx0XHRvYmplY3QudXBkYXRlV29ybGRNYXRyaXgoIGZhbHNlLCBmYWxzZSApO1xyXG5cclxuXHRcdGNvbnN0IGdlb21ldHJ5ID0gb2JqZWN0Lmdlb21ldHJ5O1xyXG5cclxuXHRcdGlmICggZ2VvbWV0cnkgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdGNvbnN0IHBvc2l0aW9uQXR0cmlidXRlID0gZ2VvbWV0cnkuZ2V0QXR0cmlidXRlKCAncG9zaXRpb24nICk7XHJcblxyXG5cdFx0XHQvLyBwcmVjaXNlIEFBQkIgY29tcHV0YXRpb24gYmFzZWQgb24gdmVydGV4IGRhdGEgcmVxdWlyZXMgYXQgbGVhc3QgYSBwb3NpdGlvbiBhdHRyaWJ1dGUuXHJcblx0XHRcdC8vIGluc3RhbmNpbmcgaXNuJ3Qgc3VwcG9ydGVkIHNvIGZhciBhbmQgdXNlcyB0aGUgbm9ybWFsIChjb25zZXJ2YXRpdmUpIGNvZGUgcGF0aC5cclxuXHJcblx0XHRcdGlmICggcHJlY2lzZSA9PT0gdHJ1ZSAmJiBwb3NpdGlvbkF0dHJpYnV0ZSAhPT0gdW5kZWZpbmVkICYmIG9iamVjdC5pc0luc3RhbmNlZE1lc2ggIT09IHRydWUgKSB7XHJcblxyXG5cdFx0XHRcdGZvciAoIGxldCBpID0gMCwgbCA9IHBvc2l0aW9uQXR0cmlidXRlLmNvdW50OyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0XHRpZiAoIG9iamVjdC5pc01lc2ggPT09IHRydWUgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRvYmplY3QuZ2V0VmVydGV4UG9zaXRpb24oIGksIF92ZWN0b3IgKTtcclxuXHJcblx0XHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdFx0X3ZlY3Rvci5mcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbkF0dHJpYnV0ZSwgaSApO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRfdmVjdG9yLmFwcGx5TWF0cml4NCggb2JqZWN0Lm1hdHJpeFdvcmxkICk7XHJcblx0XHRcdFx0XHR0aGlzLmV4cGFuZEJ5UG9pbnQoIF92ZWN0b3IgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0aWYgKCBvYmplY3QuYm91bmRpbmdCb3ggIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0XHQvLyBvYmplY3QtbGV2ZWwgYm91bmRpbmcgYm94XHJcblxyXG5cdFx0XHRcdFx0aWYgKCBvYmplY3QuYm91bmRpbmdCb3ggPT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRvYmplY3QuY29tcHV0ZUJvdW5kaW5nQm94KCk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdF9ib3guY29weSggb2JqZWN0LmJvdW5kaW5nQm94ICk7XHJcblxyXG5cclxuXHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdC8vIGdlb21ldHJ5LWxldmVsIGJvdW5kaW5nIGJveFxyXG5cclxuXHRcdFx0XHRcdGlmICggZ2VvbWV0cnkuYm91bmRpbmdCb3ggPT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRnZW9tZXRyeS5jb21wdXRlQm91bmRpbmdCb3goKTtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0X2JveC5jb3B5KCBnZW9tZXRyeS5ib3VuZGluZ0JveCApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdF9ib3guYXBwbHlNYXRyaXg0KCBvYmplY3QubWF0cml4V29ybGQgKTtcclxuXHJcblx0XHRcdFx0dGhpcy51bmlvbiggX2JveCApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCBjaGlsZHJlbiA9IG9iamVjdC5jaGlsZHJlbjtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBjaGlsZHJlbi5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0dGhpcy5leHBhbmRCeU9iamVjdCggY2hpbGRyZW5bIGkgXSwgcHJlY2lzZSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRjb250YWluc1BvaW50KCBwb2ludCApIHtcclxuXHJcblx0XHRyZXR1cm4gcG9pbnQueCA8IHRoaXMubWluLnggfHwgcG9pbnQueCA+IHRoaXMubWF4LnggfHxcclxuXHRcdFx0cG9pbnQueSA8IHRoaXMubWluLnkgfHwgcG9pbnQueSA+IHRoaXMubWF4LnkgfHxcclxuXHRcdFx0cG9pbnQueiA8IHRoaXMubWluLnogfHwgcG9pbnQueiA+IHRoaXMubWF4LnogPyBmYWxzZSA6IHRydWU7XHJcblxyXG5cdH1cclxuXHJcblx0Y29udGFpbnNCb3goIGJveCApIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5taW4ueCA8PSBib3gubWluLnggJiYgYm94Lm1heC54IDw9IHRoaXMubWF4LnggJiZcclxuXHRcdFx0dGhpcy5taW4ueSA8PSBib3gubWluLnkgJiYgYm94Lm1heC55IDw9IHRoaXMubWF4LnkgJiZcclxuXHRcdFx0dGhpcy5taW4ueiA8PSBib3gubWluLnogJiYgYm94Lm1heC56IDw9IHRoaXMubWF4Lno7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0UGFyYW1ldGVyKCBwb2ludCwgdGFyZ2V0ICkge1xyXG5cclxuXHRcdC8vIFRoaXMgY2FuIHBvdGVudGlhbGx5IGhhdmUgYSBkaXZpZGUgYnkgemVybyBpZiB0aGUgYm94XHJcblx0XHQvLyBoYXMgYSBzaXplIGRpbWVuc2lvbiBvZiAwLlxyXG5cclxuXHRcdHJldHVybiB0YXJnZXQuc2V0KFxyXG5cdFx0XHQoIHBvaW50LnggLSB0aGlzLm1pbi54ICkgLyAoIHRoaXMubWF4LnggLSB0aGlzLm1pbi54ICksXHJcblx0XHRcdCggcG9pbnQueSAtIHRoaXMubWluLnkgKSAvICggdGhpcy5tYXgueSAtIHRoaXMubWluLnkgKSxcclxuXHRcdFx0KCBwb2ludC56IC0gdGhpcy5taW4ueiApIC8gKCB0aGlzLm1heC56IC0gdGhpcy5taW4ueiApXHJcblx0XHQpO1xyXG5cclxuXHR9XHJcblxyXG5cdGludGVyc2VjdHNCb3goIGJveCApIHtcclxuXHJcblx0XHQvLyB1c2luZyA2IHNwbGl0dGluZyBwbGFuZXMgdG8gcnVsZSBvdXQgaW50ZXJzZWN0aW9ucy5cclxuXHRcdHJldHVybiBib3gubWF4LnggPCB0aGlzLm1pbi54IHx8IGJveC5taW4ueCA+IHRoaXMubWF4LnggfHxcclxuXHRcdFx0Ym94Lm1heC55IDwgdGhpcy5taW4ueSB8fCBib3gubWluLnkgPiB0aGlzLm1heC55IHx8XHJcblx0XHRcdGJveC5tYXgueiA8IHRoaXMubWluLnogfHwgYm94Lm1pbi56ID4gdGhpcy5tYXgueiA/IGZhbHNlIDogdHJ1ZTtcclxuXHJcblx0fVxyXG5cclxuXHRpbnRlcnNlY3RzU3BoZXJlKCBzcGhlcmUgKSB7XHJcblxyXG5cdFx0Ly8gRmluZCB0aGUgcG9pbnQgb24gdGhlIEFBQkIgY2xvc2VzdCB0byB0aGUgc3BoZXJlIGNlbnRlci5cclxuXHRcdHRoaXMuY2xhbXBQb2ludCggc3BoZXJlLmNlbnRlciwgX3ZlY3RvciApO1xyXG5cclxuXHRcdC8vIElmIHRoYXQgcG9pbnQgaXMgaW5zaWRlIHRoZSBzcGhlcmUsIHRoZSBBQUJCIGFuZCBzcGhlcmUgaW50ZXJzZWN0LlxyXG5cdFx0cmV0dXJuIF92ZWN0b3IuZGlzdGFuY2VUb1NxdWFyZWQoIHNwaGVyZS5jZW50ZXIgKSA8PSAoIHNwaGVyZS5yYWRpdXMgKiBzcGhlcmUucmFkaXVzICk7XHJcblxyXG5cdH1cclxuXHJcblx0aW50ZXJzZWN0c1BsYW5lKCBwbGFuZSApIHtcclxuXHJcblx0XHQvLyBXZSBjb21wdXRlIHRoZSBtaW5pbXVtIGFuZCBtYXhpbXVtIGRvdCBwcm9kdWN0IHZhbHVlcy4gSWYgdGhvc2UgdmFsdWVzXHJcblx0XHQvLyBhcmUgb24gdGhlIHNhbWUgc2lkZSAoYmFjayBvciBmcm9udCkgb2YgdGhlIHBsYW5lLCB0aGVuIHRoZXJlIGlzIG5vIGludGVyc2VjdGlvbi5cclxuXHJcblx0XHRsZXQgbWluLCBtYXg7XHJcblxyXG5cdFx0aWYgKCBwbGFuZS5ub3JtYWwueCA+IDAgKSB7XHJcblxyXG5cdFx0XHRtaW4gPSBwbGFuZS5ub3JtYWwueCAqIHRoaXMubWluLng7XHJcblx0XHRcdG1heCA9IHBsYW5lLm5vcm1hbC54ICogdGhpcy5tYXgueDtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0bWluID0gcGxhbmUubm9ybWFsLnggKiB0aGlzLm1heC54O1xyXG5cdFx0XHRtYXggPSBwbGFuZS5ub3JtYWwueCAqIHRoaXMubWluLng7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggcGxhbmUubm9ybWFsLnkgPiAwICkge1xyXG5cclxuXHRcdFx0bWluICs9IHBsYW5lLm5vcm1hbC55ICogdGhpcy5taW4ueTtcclxuXHRcdFx0bWF4ICs9IHBsYW5lLm5vcm1hbC55ICogdGhpcy5tYXgueTtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0bWluICs9IHBsYW5lLm5vcm1hbC55ICogdGhpcy5tYXgueTtcclxuXHRcdFx0bWF4ICs9IHBsYW5lLm5vcm1hbC55ICogdGhpcy5taW4ueTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBwbGFuZS5ub3JtYWwueiA+IDAgKSB7XHJcblxyXG5cdFx0XHRtaW4gKz0gcGxhbmUubm9ybWFsLnogKiB0aGlzLm1pbi56O1xyXG5cdFx0XHRtYXggKz0gcGxhbmUubm9ybWFsLnogKiB0aGlzLm1heC56O1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRtaW4gKz0gcGxhbmUubm9ybWFsLnogKiB0aGlzLm1heC56O1xyXG5cdFx0XHRtYXggKz0gcGxhbmUubm9ybWFsLnogKiB0aGlzLm1pbi56O1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gKCBtaW4gPD0gLSBwbGFuZS5jb25zdGFudCAmJiBtYXggPj0gLSBwbGFuZS5jb25zdGFudCApO1xyXG5cclxuXHR9XHJcblxyXG5cdGludGVyc2VjdHNUcmlhbmdsZSggdHJpYW5nbGUgKSB7XHJcblxyXG5cdFx0aWYgKCB0aGlzLmlzRW1wdHkoKSApIHtcclxuXHJcblx0XHRcdHJldHVybiBmYWxzZTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gY29tcHV0ZSBib3ggY2VudGVyIGFuZCBleHRlbnRzXHJcblx0XHR0aGlzLmdldENlbnRlciggX2NlbnRlciApO1xyXG5cdFx0X2V4dGVudHMuc3ViVmVjdG9ycyggdGhpcy5tYXgsIF9jZW50ZXIgKTtcclxuXHJcblx0XHQvLyB0cmFuc2xhdGUgdHJpYW5nbGUgdG8gYWFiYiBvcmlnaW5cclxuXHRcdF92MC5zdWJWZWN0b3JzKCB0cmlhbmdsZS5hLCBfY2VudGVyICk7XHJcblx0XHRfdjEuc3ViVmVjdG9ycyggdHJpYW5nbGUuYiwgX2NlbnRlciApO1xyXG5cdFx0X3YyLnN1YlZlY3RvcnMoIHRyaWFuZ2xlLmMsIF9jZW50ZXIgKTtcclxuXHJcblx0XHQvLyBjb21wdXRlIGVkZ2UgdmVjdG9ycyBmb3IgdHJpYW5nbGVcclxuXHRcdF9mMC5zdWJWZWN0b3JzKCBfdjEsIF92MCApO1xyXG5cdFx0X2YxLnN1YlZlY3RvcnMoIF92MiwgX3YxICk7XHJcblx0XHRfZjIuc3ViVmVjdG9ycyggX3YwLCBfdjIgKTtcclxuXHJcblx0XHQvLyB0ZXN0IGFnYWluc3QgYXhlcyB0aGF0IGFyZSBnaXZlbiBieSBjcm9zcyBwcm9kdWN0IGNvbWJpbmF0aW9ucyBvZiB0aGUgZWRnZXMgb2YgdGhlIHRyaWFuZ2xlIGFuZCB0aGUgZWRnZXMgb2YgdGhlIGFhYmJcclxuXHRcdC8vIG1ha2UgYW4gYXhpcyB0ZXN0aW5nIG9mIGVhY2ggb2YgdGhlIDMgc2lkZXMgb2YgdGhlIGFhYmIgYWdhaW5zdCBlYWNoIG9mIHRoZSAzIHNpZGVzIG9mIHRoZSB0cmlhbmdsZSA9IDkgYXhpcyBvZiBzZXBhcmF0aW9uXHJcblx0XHQvLyBheGlzX2lqID0gdV9pIHggZl9qICh1MCwgdTEsIHUyID0gZmFjZSBub3JtYWxzIG9mIGFhYmIgPSB4LHkseiBheGVzIHZlY3RvcnMgc2luY2UgYWFiYiBpcyBheGlzIGFsaWduZWQpXHJcblx0XHRsZXQgYXhlcyA9IFtcclxuXHRcdFx0MCwgLSBfZjAueiwgX2YwLnksIDAsIC0gX2YxLnosIF9mMS55LCAwLCAtIF9mMi56LCBfZjIueSxcclxuXHRcdFx0X2YwLnosIDAsIC0gX2YwLngsIF9mMS56LCAwLCAtIF9mMS54LCBfZjIueiwgMCwgLSBfZjIueCxcclxuXHRcdFx0LSBfZjAueSwgX2YwLngsIDAsIC0gX2YxLnksIF9mMS54LCAwLCAtIF9mMi55LCBfZjIueCwgMFxyXG5cdFx0XTtcclxuXHRcdGlmICggISBzYXRGb3JBeGVzKCBheGVzLCBfdjAsIF92MSwgX3YyLCBfZXh0ZW50cyApICkge1xyXG5cclxuXHRcdFx0cmV0dXJuIGZhbHNlO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvLyB0ZXN0IDMgZmFjZSBub3JtYWxzIGZyb20gdGhlIGFhYmJcclxuXHRcdGF4ZXMgPSBbIDEsIDAsIDAsIDAsIDEsIDAsIDAsIDAsIDEgXTtcclxuXHRcdGlmICggISBzYXRGb3JBeGVzKCBheGVzLCBfdjAsIF92MSwgX3YyLCBfZXh0ZW50cyApICkge1xyXG5cclxuXHRcdFx0cmV0dXJuIGZhbHNlO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvLyBmaW5hbGx5IHRlc3RpbmcgdGhlIGZhY2Ugbm9ybWFsIG9mIHRoZSB0cmlhbmdsZVxyXG5cdFx0Ly8gdXNlIGFscmVhZHkgZXhpc3RpbmcgdHJpYW5nbGUgZWRnZSB2ZWN0b3JzIGhlcmVcclxuXHRcdF90cmlhbmdsZU5vcm1hbC5jcm9zc1ZlY3RvcnMoIF9mMCwgX2YxICk7XHJcblx0XHRheGVzID0gWyBfdHJpYW5nbGVOb3JtYWwueCwgX3RyaWFuZ2xlTm9ybWFsLnksIF90cmlhbmdsZU5vcm1hbC56IF07XHJcblxyXG5cdFx0cmV0dXJuIHNhdEZvckF4ZXMoIGF4ZXMsIF92MCwgX3YxLCBfdjIsIF9leHRlbnRzICk7XHJcblxyXG5cdH1cclxuXHJcblx0Y2xhbXBQb2ludCggcG9pbnQsIHRhcmdldCApIHtcclxuXHJcblx0XHRyZXR1cm4gdGFyZ2V0LmNvcHkoIHBvaW50ICkuY2xhbXAoIHRoaXMubWluLCB0aGlzLm1heCApO1xyXG5cclxuXHR9XHJcblxyXG5cdGRpc3RhbmNlVG9Qb2ludCggcG9pbnQgKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuY2xhbXBQb2ludCggcG9pbnQsIF92ZWN0b3IgKS5kaXN0YW5jZVRvKCBwb2ludCApO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldEJvdW5kaW5nU3BoZXJlKCB0YXJnZXQgKSB7XHJcblxyXG5cdFx0aWYgKCB0aGlzLmlzRW1wdHkoKSApIHtcclxuXHJcblx0XHRcdHRhcmdldC5tYWtlRW1wdHkoKTtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0dGhpcy5nZXRDZW50ZXIoIHRhcmdldC5jZW50ZXIgKTtcclxuXHJcblx0XHRcdHRhcmdldC5yYWRpdXMgPSB0aGlzLmdldFNpemUoIF92ZWN0b3IgKS5sZW5ndGgoKSAqIDAuNTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRhcmdldDtcclxuXHJcblx0fVxyXG5cclxuXHRpbnRlcnNlY3QoIGJveCApIHtcclxuXHJcblx0XHR0aGlzLm1pbi5tYXgoIGJveC5taW4gKTtcclxuXHRcdHRoaXMubWF4Lm1pbiggYm94Lm1heCApO1xyXG5cclxuXHRcdC8vIGVuc3VyZSB0aGF0IGlmIHRoZXJlIGlzIG5vIG92ZXJsYXAsIHRoZSByZXN1bHQgaXMgZnVsbHkgZW1wdHksIG5vdCBzbGlnaHRseSBlbXB0eSB3aXRoIG5vbi1pbmYvK2luZiB2YWx1ZXMgdGhhdCB3aWxsIGNhdXNlIHN1YnNlcXVlbmNlIGludGVyc2VjdHMgdG8gZXJyb25lb3VzbHkgcmV0dXJuIHZhbGlkIHZhbHVlcy5cclxuXHRcdGlmICggdGhpcy5pc0VtcHR5KCkgKSB0aGlzLm1ha2VFbXB0eSgpO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHVuaW9uKCBib3ggKSB7XHJcblxyXG5cdFx0dGhpcy5taW4ubWluKCBib3gubWluICk7XHJcblx0XHR0aGlzLm1heC5tYXgoIGJveC5tYXggKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRhcHBseU1hdHJpeDQoIG1hdHJpeCApIHtcclxuXHJcblx0XHQvLyB0cmFuc2Zvcm0gb2YgZW1wdHkgYm94IGlzIGFuIGVtcHR5IGJveC5cclxuXHRcdGlmICggdGhpcy5pc0VtcHR5KCkgKSByZXR1cm4gdGhpcztcclxuXHJcblx0XHQvLyBOT1RFOiBJIGFtIHVzaW5nIGEgYmluYXJ5IHBhdHRlcm4gdG8gc3BlY2lmeSBhbGwgMl4zIGNvbWJpbmF0aW9ucyBiZWxvd1xyXG5cdFx0X3BvaW50c1sgMCBdLnNldCggdGhpcy5taW4ueCwgdGhpcy5taW4ueSwgdGhpcy5taW4ueiApLmFwcGx5TWF0cml4NCggbWF0cml4ICk7IC8vIDAwMFxyXG5cdFx0X3BvaW50c1sgMSBdLnNldCggdGhpcy5taW4ueCwgdGhpcy5taW4ueSwgdGhpcy5tYXgueiApLmFwcGx5TWF0cml4NCggbWF0cml4ICk7IC8vIDAwMVxyXG5cdFx0X3BvaW50c1sgMiBdLnNldCggdGhpcy5taW4ueCwgdGhpcy5tYXgueSwgdGhpcy5taW4ueiApLmFwcGx5TWF0cml4NCggbWF0cml4ICk7IC8vIDAxMFxyXG5cdFx0X3BvaW50c1sgMyBdLnNldCggdGhpcy5taW4ueCwgdGhpcy5tYXgueSwgdGhpcy5tYXgueiApLmFwcGx5TWF0cml4NCggbWF0cml4ICk7IC8vIDAxMVxyXG5cdFx0X3BvaW50c1sgNCBdLnNldCggdGhpcy5tYXgueCwgdGhpcy5taW4ueSwgdGhpcy5taW4ueiApLmFwcGx5TWF0cml4NCggbWF0cml4ICk7IC8vIDEwMFxyXG5cdFx0X3BvaW50c1sgNSBdLnNldCggdGhpcy5tYXgueCwgdGhpcy5taW4ueSwgdGhpcy5tYXgueiApLmFwcGx5TWF0cml4NCggbWF0cml4ICk7IC8vIDEwMVxyXG5cdFx0X3BvaW50c1sgNiBdLnNldCggdGhpcy5tYXgueCwgdGhpcy5tYXgueSwgdGhpcy5taW4ueiApLmFwcGx5TWF0cml4NCggbWF0cml4ICk7IC8vIDExMFxyXG5cdFx0X3BvaW50c1sgNyBdLnNldCggdGhpcy5tYXgueCwgdGhpcy5tYXgueSwgdGhpcy5tYXgueiApLmFwcGx5TWF0cml4NCggbWF0cml4ICk7IC8vIDExMVxyXG5cclxuXHRcdHRoaXMuc2V0RnJvbVBvaW50cyggX3BvaW50cyApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHRyYW5zbGF0ZSggb2Zmc2V0ICkge1xyXG5cclxuXHRcdHRoaXMubWluLmFkZCggb2Zmc2V0ICk7XHJcblx0XHR0aGlzLm1heC5hZGQoIG9mZnNldCApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGVxdWFscyggYm94ICkge1xyXG5cclxuXHRcdHJldHVybiBib3gubWluLmVxdWFscyggdGhpcy5taW4gKSAmJiBib3gubWF4LmVxdWFscyggdGhpcy5tYXggKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuY29uc3QgX3BvaW50cyA9IFtcclxuXHQvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCksXHJcblx0LypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpLFxyXG5cdC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKSxcclxuXHQvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCksXHJcblx0LypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpLFxyXG5cdC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKSxcclxuXHQvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCksXHJcblx0LypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpXHJcbl07XHJcblxyXG5jb25zdCBfdmVjdG9yID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5cclxuY29uc3QgX2JveCA9IC8qQF9fUFVSRV9fKi8gbmV3IEJveDMoKTtcclxuXHJcbi8vIHRyaWFuZ2xlIGNlbnRlcmVkIHZlcnRpY2VzXHJcblxyXG5jb25zdCBfdjAgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XHJcbmNvbnN0IF92MSA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuY29uc3QgX3YyID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5cclxuLy8gdHJpYW5nbGUgZWRnZSB2ZWN0b3JzXHJcblxyXG5jb25zdCBfZjAgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XHJcbmNvbnN0IF9mMSA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuY29uc3QgX2YyID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5cclxuY29uc3QgX2NlbnRlciA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuY29uc3QgX2V4dGVudHMgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XHJcbmNvbnN0IF90cmlhbmdsZU5vcm1hbCA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuY29uc3QgX3Rlc3RBeGlzID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5cclxuZnVuY3Rpb24gc2F0Rm9yQXhlcyggYXhlcywgdjAsIHYxLCB2MiwgZXh0ZW50cyApIHtcclxuXHJcblx0Zm9yICggbGV0IGkgPSAwLCBqID0gYXhlcy5sZW5ndGggLSAzOyBpIDw9IGo7IGkgKz0gMyApIHtcclxuXHJcblx0XHRfdGVzdEF4aXMuZnJvbUFycmF5KCBheGVzLCBpICk7XHJcblx0XHQvLyBwcm9qZWN0IHRoZSBhYWJiIG9udG8gdGhlIHNlcGFyYXRpbmcgYXhpc1xyXG5cdFx0Y29uc3QgciA9IGV4dGVudHMueCAqIE1hdGguYWJzKCBfdGVzdEF4aXMueCApICsgZXh0ZW50cy55ICogTWF0aC5hYnMoIF90ZXN0QXhpcy55ICkgKyBleHRlbnRzLnogKiBNYXRoLmFicyggX3Rlc3RBeGlzLnogKTtcclxuXHRcdC8vIHByb2plY3QgYWxsIDMgdmVydGljZXMgb2YgdGhlIHRyaWFuZ2xlIG9udG8gdGhlIHNlcGFyYXRpbmcgYXhpc1xyXG5cdFx0Y29uc3QgcDAgPSB2MC5kb3QoIF90ZXN0QXhpcyApO1xyXG5cdFx0Y29uc3QgcDEgPSB2MS5kb3QoIF90ZXN0QXhpcyApO1xyXG5cdFx0Y29uc3QgcDIgPSB2Mi5kb3QoIF90ZXN0QXhpcyApO1xyXG5cdFx0Ly8gYWN0dWFsIHRlc3QsIGJhc2ljYWxseSBzZWUgaWYgZWl0aGVyIG9mIHRoZSBtb3N0IGV4dHJlbWUgb2YgdGhlIHRyaWFuZ2xlIHBvaW50cyBpbnRlcnNlY3RzIHJcclxuXHRcdGlmICggTWF0aC5tYXgoIC0gTWF0aC5tYXgoIHAwLCBwMSwgcDIgKSwgTWF0aC5taW4oIHAwLCBwMSwgcDIgKSApID4gciApIHtcclxuXHJcblx0XHRcdC8vIHBvaW50cyBvZiB0aGUgcHJvamVjdGVkIHRyaWFuZ2xlIGFyZSBvdXRzaWRlIHRoZSBwcm9qZWN0ZWQgaGFsZi1sZW5ndGggb2YgdGhlIGFhYmJcclxuXHRcdFx0Ly8gdGhlIGF4aXMgaXMgc2VwYXJhdGluZyBhbmQgd2UgY2FuIGV4aXRcclxuXHRcdFx0cmV0dXJuIGZhbHNlO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4gdHJ1ZTtcclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IEJveDMgfTtcclxuIiwiaW1wb3J0IHsgQm94MyB9IGZyb20gJy4vQm94My5qcyc7XHJcbmltcG9ydCB7IFZlY3RvcjMgfSBmcm9tICcuL1ZlY3RvcjMuanMnO1xyXG5cclxuY29uc3QgX2JveCA9IC8qQF9fUFVSRV9fKi8gbmV3IEJveDMoKTtcclxuY29uc3QgX3YxID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5jb25zdCBfdjIgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XHJcblxyXG5jbGFzcyBTcGhlcmUge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggY2VudGVyID0gbmV3IFZlY3RvcjMoKSwgcmFkaXVzID0gLSAxICkge1xyXG5cclxuXHRcdHRoaXMuaXNTcGhlcmUgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMuY2VudGVyID0gY2VudGVyO1xyXG5cdFx0dGhpcy5yYWRpdXMgPSByYWRpdXM7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0KCBjZW50ZXIsIHJhZGl1cyApIHtcclxuXHJcblx0XHR0aGlzLmNlbnRlci5jb3B5KCBjZW50ZXIgKTtcclxuXHRcdHRoaXMucmFkaXVzID0gcmFkaXVzO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldEZyb21Qb2ludHMoIHBvaW50cywgb3B0aW9uYWxDZW50ZXIgKSB7XHJcblxyXG5cdFx0Y29uc3QgY2VudGVyID0gdGhpcy5jZW50ZXI7XHJcblxyXG5cdFx0aWYgKCBvcHRpb25hbENlbnRlciAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0Y2VudGVyLmNvcHkoIG9wdGlvbmFsQ2VudGVyICk7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdF9ib3guc2V0RnJvbVBvaW50cyggcG9pbnRzICkuZ2V0Q2VudGVyKCBjZW50ZXIgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0bGV0IG1heFJhZGl1c1NxID0gMDtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gcG9pbnRzLmxlbmd0aDsgaSA8IGlsOyBpICsrICkge1xyXG5cclxuXHRcdFx0bWF4UmFkaXVzU3EgPSBNYXRoLm1heCggbWF4UmFkaXVzU3EsIGNlbnRlci5kaXN0YW5jZVRvU3F1YXJlZCggcG9pbnRzWyBpIF0gKSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLnJhZGl1cyA9IE1hdGguc3FydCggbWF4UmFkaXVzU3EgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRjb3B5KCBzcGhlcmUgKSB7XHJcblxyXG5cdFx0dGhpcy5jZW50ZXIuY29weSggc3BoZXJlLmNlbnRlciApO1xyXG5cdFx0dGhpcy5yYWRpdXMgPSBzcGhlcmUucmFkaXVzO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGlzRW1wdHkoKSB7XHJcblxyXG5cdFx0cmV0dXJuICggdGhpcy5yYWRpdXMgPCAwICk7XHJcblxyXG5cdH1cclxuXHJcblx0bWFrZUVtcHR5KCkge1xyXG5cclxuXHRcdHRoaXMuY2VudGVyLnNldCggMCwgMCwgMCApO1xyXG5cdFx0dGhpcy5yYWRpdXMgPSAtIDE7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Y29udGFpbnNQb2ludCggcG9pbnQgKSB7XHJcblxyXG5cdFx0cmV0dXJuICggcG9pbnQuZGlzdGFuY2VUb1NxdWFyZWQoIHRoaXMuY2VudGVyICkgPD0gKCB0aGlzLnJhZGl1cyAqIHRoaXMucmFkaXVzICkgKTtcclxuXHJcblx0fVxyXG5cclxuXHRkaXN0YW5jZVRvUG9pbnQoIHBvaW50ICkge1xyXG5cclxuXHRcdHJldHVybiAoIHBvaW50LmRpc3RhbmNlVG8oIHRoaXMuY2VudGVyICkgLSB0aGlzLnJhZGl1cyApO1xyXG5cclxuXHR9XHJcblxyXG5cdGludGVyc2VjdHNTcGhlcmUoIHNwaGVyZSApIHtcclxuXHJcblx0XHRjb25zdCByYWRpdXNTdW0gPSB0aGlzLnJhZGl1cyArIHNwaGVyZS5yYWRpdXM7XHJcblxyXG5cdFx0cmV0dXJuIHNwaGVyZS5jZW50ZXIuZGlzdGFuY2VUb1NxdWFyZWQoIHRoaXMuY2VudGVyICkgPD0gKCByYWRpdXNTdW0gKiByYWRpdXNTdW0gKTtcclxuXHJcblx0fVxyXG5cclxuXHRpbnRlcnNlY3RzQm94KCBib3ggKSB7XHJcblxyXG5cdFx0cmV0dXJuIGJveC5pbnRlcnNlY3RzU3BoZXJlKCB0aGlzICk7XHJcblxyXG5cdH1cclxuXHJcblx0aW50ZXJzZWN0c1BsYW5lKCBwbGFuZSApIHtcclxuXHJcblx0XHRyZXR1cm4gTWF0aC5hYnMoIHBsYW5lLmRpc3RhbmNlVG9Qb2ludCggdGhpcy5jZW50ZXIgKSApIDw9IHRoaXMucmFkaXVzO1xyXG5cclxuXHR9XHJcblxyXG5cdGNsYW1wUG9pbnQoIHBvaW50LCB0YXJnZXQgKSB7XHJcblxyXG5cdFx0Y29uc3QgZGVsdGFMZW5ndGhTcSA9IHRoaXMuY2VudGVyLmRpc3RhbmNlVG9TcXVhcmVkKCBwb2ludCApO1xyXG5cclxuXHRcdHRhcmdldC5jb3B5KCBwb2ludCApO1xyXG5cclxuXHRcdGlmICggZGVsdGFMZW5ndGhTcSA+ICggdGhpcy5yYWRpdXMgKiB0aGlzLnJhZGl1cyApICkge1xyXG5cclxuXHRcdFx0dGFyZ2V0LnN1YiggdGhpcy5jZW50ZXIgKS5ub3JtYWxpemUoKTtcclxuXHRcdFx0dGFyZ2V0Lm11bHRpcGx5U2NhbGFyKCB0aGlzLnJhZGl1cyApLmFkZCggdGhpcy5jZW50ZXIgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRhcmdldDtcclxuXHJcblx0fVxyXG5cclxuXHRnZXRCb3VuZGluZ0JveCggdGFyZ2V0ICkge1xyXG5cclxuXHRcdGlmICggdGhpcy5pc0VtcHR5KCkgKSB7XHJcblxyXG5cdFx0XHQvLyBFbXB0eSBzcGhlcmUgcHJvZHVjZXMgZW1wdHkgYm91bmRpbmcgYm94XHJcblx0XHRcdHRhcmdldC5tYWtlRW1wdHkoKTtcclxuXHRcdFx0cmV0dXJuIHRhcmdldDtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGFyZ2V0LnNldCggdGhpcy5jZW50ZXIsIHRoaXMuY2VudGVyICk7XHJcblx0XHR0YXJnZXQuZXhwYW5kQnlTY2FsYXIoIHRoaXMucmFkaXVzICk7XHJcblxyXG5cdFx0cmV0dXJuIHRhcmdldDtcclxuXHJcblx0fVxyXG5cclxuXHRhcHBseU1hdHJpeDQoIG1hdHJpeCApIHtcclxuXHJcblx0XHR0aGlzLmNlbnRlci5hcHBseU1hdHJpeDQoIG1hdHJpeCApO1xyXG5cdFx0dGhpcy5yYWRpdXMgPSB0aGlzLnJhZGl1cyAqIG1hdHJpeC5nZXRNYXhTY2FsZU9uQXhpcygpO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHRyYW5zbGF0ZSggb2Zmc2V0ICkge1xyXG5cclxuXHRcdHRoaXMuY2VudGVyLmFkZCggb2Zmc2V0ICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0ZXhwYW5kQnlQb2ludCggcG9pbnQgKSB7XHJcblxyXG5cdFx0aWYgKCB0aGlzLmlzRW1wdHkoKSApIHtcclxuXHJcblx0XHRcdHRoaXMuY2VudGVyLmNvcHkoIHBvaW50ICk7XHJcblxyXG5cdFx0XHR0aGlzLnJhZGl1cyA9IDA7XHJcblxyXG5cdFx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0X3YxLnN1YlZlY3RvcnMoIHBvaW50LCB0aGlzLmNlbnRlciApO1xyXG5cclxuXHRcdGNvbnN0IGxlbmd0aFNxID0gX3YxLmxlbmd0aFNxKCk7XHJcblxyXG5cdFx0aWYgKCBsZW5ndGhTcSA+ICggdGhpcy5yYWRpdXMgKiB0aGlzLnJhZGl1cyApICkge1xyXG5cclxuXHRcdFx0Ly8gY2FsY3VsYXRlIHRoZSBtaW5pbWFsIHNwaGVyZVxyXG5cclxuXHRcdFx0Y29uc3QgbGVuZ3RoID0gTWF0aC5zcXJ0KCBsZW5ndGhTcSApO1xyXG5cclxuXHRcdFx0Y29uc3QgZGVsdGEgPSAoIGxlbmd0aCAtIHRoaXMucmFkaXVzICkgKiAwLjU7XHJcblxyXG5cdFx0XHR0aGlzLmNlbnRlci5hZGRTY2FsZWRWZWN0b3IoIF92MSwgZGVsdGEgLyBsZW5ndGggKTtcclxuXHJcblx0XHRcdHRoaXMucmFkaXVzICs9IGRlbHRhO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHR1bmlvbiggc3BoZXJlICkge1xyXG5cclxuXHRcdGlmICggc3BoZXJlLmlzRW1wdHkoKSApIHtcclxuXHJcblx0XHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHRoaXMuaXNFbXB0eSgpICkge1xyXG5cclxuXHRcdFx0dGhpcy5jb3B5KCBzcGhlcmUgKTtcclxuXHJcblx0XHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHRoaXMuY2VudGVyLmVxdWFscyggc3BoZXJlLmNlbnRlciApID09PSB0cnVlICkge1xyXG5cclxuXHRcdFx0IHRoaXMucmFkaXVzID0gTWF0aC5tYXgoIHRoaXMucmFkaXVzLCBzcGhlcmUucmFkaXVzICk7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdF92Mi5zdWJWZWN0b3JzKCBzcGhlcmUuY2VudGVyLCB0aGlzLmNlbnRlciApLnNldExlbmd0aCggc3BoZXJlLnJhZGl1cyApO1xyXG5cclxuXHRcdFx0dGhpcy5leHBhbmRCeVBvaW50KCBfdjEuY29weSggc3BoZXJlLmNlbnRlciApLmFkZCggX3YyICkgKTtcclxuXHJcblx0XHRcdHRoaXMuZXhwYW5kQnlQb2ludCggX3YxLmNvcHkoIHNwaGVyZS5jZW50ZXIgKS5zdWIoIF92MiApICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGVxdWFscyggc3BoZXJlICkge1xyXG5cclxuXHRcdHJldHVybiBzcGhlcmUuY2VudGVyLmVxdWFscyggdGhpcy5jZW50ZXIgKSAmJiAoIHNwaGVyZS5yYWRpdXMgPT09IHRoaXMucmFkaXVzICk7XHJcblxyXG5cdH1cclxuXHJcblx0Y2xvbmUoKSB7XHJcblxyXG5cdFx0cmV0dXJuIG5ldyB0aGlzLmNvbnN0cnVjdG9yKCkuY29weSggdGhpcyApO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBTcGhlcmUgfTtcclxuIiwiaW1wb3J0IHsgVmVjdG9yMyB9IGZyb20gJy4vVmVjdG9yMy5qcyc7XHJcblxyXG5jb25zdCBfdmVjdG9yID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5jb25zdCBfc2VnQ2VudGVyID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5jb25zdCBfc2VnRGlyID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5jb25zdCBfZGlmZiA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuXHJcbmNvbnN0IF9lZGdlMSA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuY29uc3QgX2VkZ2UyID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5jb25zdCBfbm9ybWFsID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5cclxuY2xhc3MgUmF5IHtcclxuXHJcblx0Y29uc3RydWN0b3IoIG9yaWdpbiA9IG5ldyBWZWN0b3IzKCksIGRpcmVjdGlvbiA9IG5ldyBWZWN0b3IzKCAwLCAwLCAtIDEgKSApIHtcclxuXHJcblx0XHR0aGlzLm9yaWdpbiA9IG9yaWdpbjtcclxuXHRcdHRoaXMuZGlyZWN0aW9uID0gZGlyZWN0aW9uO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldCggb3JpZ2luLCBkaXJlY3Rpb24gKSB7XHJcblxyXG5cdFx0dGhpcy5vcmlnaW4uY29weSggb3JpZ2luICk7XHJcblx0XHR0aGlzLmRpcmVjdGlvbi5jb3B5KCBkaXJlY3Rpb24gKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRjb3B5KCByYXkgKSB7XHJcblxyXG5cdFx0dGhpcy5vcmlnaW4uY29weSggcmF5Lm9yaWdpbiApO1xyXG5cdFx0dGhpcy5kaXJlY3Rpb24uY29weSggcmF5LmRpcmVjdGlvbiApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGF0KCB0LCB0YXJnZXQgKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRhcmdldC5jb3B5KCB0aGlzLm9yaWdpbiApLmFkZFNjYWxlZFZlY3RvciggdGhpcy5kaXJlY3Rpb24sIHQgKTtcclxuXHJcblx0fVxyXG5cclxuXHRsb29rQXQoIHYgKSB7XHJcblxyXG5cdFx0dGhpcy5kaXJlY3Rpb24uY29weSggdiApLnN1YiggdGhpcy5vcmlnaW4gKS5ub3JtYWxpemUoKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRyZWNhc3QoIHQgKSB7XHJcblxyXG5cdFx0dGhpcy5vcmlnaW4uY29weSggdGhpcy5hdCggdCwgX3ZlY3RvciApICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Y2xvc2VzdFBvaW50VG9Qb2ludCggcG9pbnQsIHRhcmdldCApIHtcclxuXHJcblx0XHR0YXJnZXQuc3ViVmVjdG9ycyggcG9pbnQsIHRoaXMub3JpZ2luICk7XHJcblxyXG5cdFx0Y29uc3QgZGlyZWN0aW9uRGlzdGFuY2UgPSB0YXJnZXQuZG90KCB0aGlzLmRpcmVjdGlvbiApO1xyXG5cclxuXHRcdGlmICggZGlyZWN0aW9uRGlzdGFuY2UgPCAwICkge1xyXG5cclxuXHRcdFx0cmV0dXJuIHRhcmdldC5jb3B5KCB0aGlzLm9yaWdpbiApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGFyZ2V0LmNvcHkoIHRoaXMub3JpZ2luICkuYWRkU2NhbGVkVmVjdG9yKCB0aGlzLmRpcmVjdGlvbiwgZGlyZWN0aW9uRGlzdGFuY2UgKTtcclxuXHJcblx0fVxyXG5cclxuXHRkaXN0YW5jZVRvUG9pbnQoIHBvaW50ICkge1xyXG5cclxuXHRcdHJldHVybiBNYXRoLnNxcnQoIHRoaXMuZGlzdGFuY2VTcVRvUG9pbnQoIHBvaW50ICkgKTtcclxuXHJcblx0fVxyXG5cclxuXHRkaXN0YW5jZVNxVG9Qb2ludCggcG9pbnQgKSB7XHJcblxyXG5cdFx0Y29uc3QgZGlyZWN0aW9uRGlzdGFuY2UgPSBfdmVjdG9yLnN1YlZlY3RvcnMoIHBvaW50LCB0aGlzLm9yaWdpbiApLmRvdCggdGhpcy5kaXJlY3Rpb24gKTtcclxuXHJcblx0XHQvLyBwb2ludCBiZWhpbmQgdGhlIHJheVxyXG5cclxuXHRcdGlmICggZGlyZWN0aW9uRGlzdGFuY2UgPCAwICkge1xyXG5cclxuXHRcdFx0cmV0dXJuIHRoaXMub3JpZ2luLmRpc3RhbmNlVG9TcXVhcmVkKCBwb2ludCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRfdmVjdG9yLmNvcHkoIHRoaXMub3JpZ2luICkuYWRkU2NhbGVkVmVjdG9yKCB0aGlzLmRpcmVjdGlvbiwgZGlyZWN0aW9uRGlzdGFuY2UgKTtcclxuXHJcblx0XHRyZXR1cm4gX3ZlY3Rvci5kaXN0YW5jZVRvU3F1YXJlZCggcG9pbnQgKTtcclxuXHJcblx0fVxyXG5cclxuXHRkaXN0YW5jZVNxVG9TZWdtZW50KCB2MCwgdjEsIG9wdGlvbmFsUG9pbnRPblJheSwgb3B0aW9uYWxQb2ludE9uU2VnbWVudCApIHtcclxuXHJcblx0XHQvLyBmcm9tIGh0dHBzOi8vZ2l0aHViLmNvbS9wbWpvbmlhay9HZW9tZXRyaWNUb29scy9ibG9iL21hc3Rlci9HVEVuZ2luZS9JbmNsdWRlL01hdGhlbWF0aWNzL0d0ZURpc3RSYXlTZWdtZW50LmhcclxuXHRcdC8vIEl0IHJldHVybnMgdGhlIG1pbiBkaXN0YW5jZSBiZXR3ZWVuIHRoZSByYXkgYW5kIHRoZSBzZWdtZW50XHJcblx0XHQvLyBkZWZpbmVkIGJ5IHYwIGFuZCB2MVxyXG5cdFx0Ly8gSXQgY2FuIGFsc28gc2V0IHR3byBvcHRpb25hbCB0YXJnZXRzIDpcclxuXHRcdC8vIC0gVGhlIGNsb3Nlc3QgcG9pbnQgb24gdGhlIHJheVxyXG5cdFx0Ly8gLSBUaGUgY2xvc2VzdCBwb2ludCBvbiB0aGUgc2VnbWVudFxyXG5cclxuXHRcdF9zZWdDZW50ZXIuY29weSggdjAgKS5hZGQoIHYxICkubXVsdGlwbHlTY2FsYXIoIDAuNSApO1xyXG5cdFx0X3NlZ0Rpci5jb3B5KCB2MSApLnN1YiggdjAgKS5ub3JtYWxpemUoKTtcclxuXHRcdF9kaWZmLmNvcHkoIHRoaXMub3JpZ2luICkuc3ViKCBfc2VnQ2VudGVyICk7XHJcblxyXG5cdFx0Y29uc3Qgc2VnRXh0ZW50ID0gdjAuZGlzdGFuY2VUbyggdjEgKSAqIDAuNTtcclxuXHRcdGNvbnN0IGEwMSA9IC0gdGhpcy5kaXJlY3Rpb24uZG90KCBfc2VnRGlyICk7XHJcblx0XHRjb25zdCBiMCA9IF9kaWZmLmRvdCggdGhpcy5kaXJlY3Rpb24gKTtcclxuXHRcdGNvbnN0IGIxID0gLSBfZGlmZi5kb3QoIF9zZWdEaXIgKTtcclxuXHRcdGNvbnN0IGMgPSBfZGlmZi5sZW5ndGhTcSgpO1xyXG5cdFx0Y29uc3QgZGV0ID0gTWF0aC5hYnMoIDEgLSBhMDEgKiBhMDEgKTtcclxuXHRcdGxldCBzMCwgczEsIHNxckRpc3QsIGV4dERldDtcclxuXHJcblx0XHRpZiAoIGRldCA+IDAgKSB7XHJcblxyXG5cdFx0XHQvLyBUaGUgcmF5IGFuZCBzZWdtZW50IGFyZSBub3QgcGFyYWxsZWwuXHJcblxyXG5cdFx0XHRzMCA9IGEwMSAqIGIxIC0gYjA7XHJcblx0XHRcdHMxID0gYTAxICogYjAgLSBiMTtcclxuXHRcdFx0ZXh0RGV0ID0gc2VnRXh0ZW50ICogZGV0O1xyXG5cclxuXHRcdFx0aWYgKCBzMCA+PSAwICkge1xyXG5cclxuXHRcdFx0XHRpZiAoIHMxID49IC0gZXh0RGV0ICkge1xyXG5cclxuXHRcdFx0XHRcdGlmICggczEgPD0gZXh0RGV0ICkge1xyXG5cclxuXHRcdFx0XHRcdFx0Ly8gcmVnaW9uIDBcclxuXHRcdFx0XHRcdFx0Ly8gTWluaW11bSBhdCBpbnRlcmlvciBwb2ludHMgb2YgcmF5IGFuZCBzZWdtZW50LlxyXG5cclxuXHRcdFx0XHRcdFx0Y29uc3QgaW52RGV0ID0gMSAvIGRldDtcclxuXHRcdFx0XHRcdFx0czAgKj0gaW52RGV0O1xyXG5cdFx0XHRcdFx0XHRzMSAqPSBpbnZEZXQ7XHJcblx0XHRcdFx0XHRcdHNxckRpc3QgPSBzMCAqICggczAgKyBhMDEgKiBzMSArIDIgKiBiMCApICsgczEgKiAoIGEwMSAqIHMwICsgczEgKyAyICogYjEgKSArIGM7XHJcblxyXG5cdFx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRcdC8vIHJlZ2lvbiAxXHJcblxyXG5cdFx0XHRcdFx0XHRzMSA9IHNlZ0V4dGVudDtcclxuXHRcdFx0XHRcdFx0czAgPSBNYXRoLm1heCggMCwgLSAoIGEwMSAqIHMxICsgYjAgKSApO1xyXG5cdFx0XHRcdFx0XHRzcXJEaXN0ID0gLSBzMCAqIHMwICsgczEgKiAoIHMxICsgMiAqIGIxICkgKyBjO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHQvLyByZWdpb24gNVxyXG5cclxuXHRcdFx0XHRcdHMxID0gLSBzZWdFeHRlbnQ7XHJcblx0XHRcdFx0XHRzMCA9IE1hdGgubWF4KCAwLCAtICggYTAxICogczEgKyBiMCApICk7XHJcblx0XHRcdFx0XHRzcXJEaXN0ID0gLSBzMCAqIHMwICsgczEgKiAoIHMxICsgMiAqIGIxICkgKyBjO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRpZiAoIHMxIDw9IC0gZXh0RGV0ICkge1xyXG5cclxuXHRcdFx0XHRcdC8vIHJlZ2lvbiA0XHJcblxyXG5cdFx0XHRcdFx0czAgPSBNYXRoLm1heCggMCwgLSAoIC0gYTAxICogc2VnRXh0ZW50ICsgYjAgKSApO1xyXG5cdFx0XHRcdFx0czEgPSAoIHMwID4gMCApID8gLSBzZWdFeHRlbnQgOiBNYXRoLm1pbiggTWF0aC5tYXgoIC0gc2VnRXh0ZW50LCAtIGIxICksIHNlZ0V4dGVudCApO1xyXG5cdFx0XHRcdFx0c3FyRGlzdCA9IC0gczAgKiBzMCArIHMxICogKCBzMSArIDIgKiBiMSApICsgYztcclxuXHJcblx0XHRcdFx0fSBlbHNlIGlmICggczEgPD0gZXh0RGV0ICkge1xyXG5cclxuXHRcdFx0XHRcdC8vIHJlZ2lvbiAzXHJcblxyXG5cdFx0XHRcdFx0czAgPSAwO1xyXG5cdFx0XHRcdFx0czEgPSBNYXRoLm1pbiggTWF0aC5tYXgoIC0gc2VnRXh0ZW50LCAtIGIxICksIHNlZ0V4dGVudCApO1xyXG5cdFx0XHRcdFx0c3FyRGlzdCA9IHMxICogKCBzMSArIDIgKiBiMSApICsgYztcclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHQvLyByZWdpb24gMlxyXG5cclxuXHRcdFx0XHRcdHMwID0gTWF0aC5tYXgoIDAsIC0gKCBhMDEgKiBzZWdFeHRlbnQgKyBiMCApICk7XHJcblx0XHRcdFx0XHRzMSA9ICggczAgPiAwICkgPyBzZWdFeHRlbnQgOiBNYXRoLm1pbiggTWF0aC5tYXgoIC0gc2VnRXh0ZW50LCAtIGIxICksIHNlZ0V4dGVudCApO1xyXG5cdFx0XHRcdFx0c3FyRGlzdCA9IC0gczAgKiBzMCArIHMxICogKCBzMSArIDIgKiBiMSApICsgYztcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHQvLyBSYXkgYW5kIHNlZ21lbnQgYXJlIHBhcmFsbGVsLlxyXG5cclxuXHRcdFx0czEgPSAoIGEwMSA+IDAgKSA/IC0gc2VnRXh0ZW50IDogc2VnRXh0ZW50O1xyXG5cdFx0XHRzMCA9IE1hdGgubWF4KCAwLCAtICggYTAxICogczEgKyBiMCApICk7XHJcblx0XHRcdHNxckRpc3QgPSAtIHMwICogczAgKyBzMSAqICggczEgKyAyICogYjEgKSArIGM7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggb3B0aW9uYWxQb2ludE9uUmF5ICkge1xyXG5cclxuXHRcdFx0b3B0aW9uYWxQb2ludE9uUmF5LmNvcHkoIHRoaXMub3JpZ2luICkuYWRkU2NhbGVkVmVjdG9yKCB0aGlzLmRpcmVjdGlvbiwgczAgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBvcHRpb25hbFBvaW50T25TZWdtZW50ICkge1xyXG5cclxuXHRcdFx0b3B0aW9uYWxQb2ludE9uU2VnbWVudC5jb3B5KCBfc2VnQ2VudGVyICkuYWRkU2NhbGVkVmVjdG9yKCBfc2VnRGlyLCBzMSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gc3FyRGlzdDtcclxuXHJcblx0fVxyXG5cclxuXHRpbnRlcnNlY3RTcGhlcmUoIHNwaGVyZSwgdGFyZ2V0ICkge1xyXG5cclxuXHRcdF92ZWN0b3Iuc3ViVmVjdG9ycyggc3BoZXJlLmNlbnRlciwgdGhpcy5vcmlnaW4gKTtcclxuXHRcdGNvbnN0IHRjYSA9IF92ZWN0b3IuZG90KCB0aGlzLmRpcmVjdGlvbiApO1xyXG5cdFx0Y29uc3QgZDIgPSBfdmVjdG9yLmRvdCggX3ZlY3RvciApIC0gdGNhICogdGNhO1xyXG5cdFx0Y29uc3QgcmFkaXVzMiA9IHNwaGVyZS5yYWRpdXMgKiBzcGhlcmUucmFkaXVzO1xyXG5cclxuXHRcdGlmICggZDIgPiByYWRpdXMyICkgcmV0dXJuIG51bGw7XHJcblxyXG5cdFx0Y29uc3QgdGhjID0gTWF0aC5zcXJ0KCByYWRpdXMyIC0gZDIgKTtcclxuXHJcblx0XHQvLyB0MCA9IGZpcnN0IGludGVyc2VjdCBwb2ludCAtIGVudHJhbmNlIG9uIGZyb250IG9mIHNwaGVyZVxyXG5cdFx0Y29uc3QgdDAgPSB0Y2EgLSB0aGM7XHJcblxyXG5cdFx0Ly8gdDEgPSBzZWNvbmQgaW50ZXJzZWN0IHBvaW50IC0gZXhpdCBwb2ludCBvbiBiYWNrIG9mIHNwaGVyZVxyXG5cdFx0Y29uc3QgdDEgPSB0Y2EgKyB0aGM7XHJcblxyXG5cdFx0Ly8gdGVzdCB0byBzZWUgaWYgdDEgaXMgYmVoaW5kIHRoZSByYXkgLSBpZiBzbywgcmV0dXJuIG51bGxcclxuXHRcdGlmICggdDEgPCAwICkgcmV0dXJuIG51bGw7XHJcblxyXG5cdFx0Ly8gdGVzdCB0byBzZWUgaWYgdDAgaXMgYmVoaW5kIHRoZSByYXk6XHJcblx0XHQvLyBpZiBpdCBpcywgdGhlIHJheSBpcyBpbnNpZGUgdGhlIHNwaGVyZSwgc28gcmV0dXJuIHRoZSBzZWNvbmQgZXhpdCBwb2ludCBzY2FsZWQgYnkgdDEsXHJcblx0XHQvLyBpbiBvcmRlciB0byBhbHdheXMgcmV0dXJuIGFuIGludGVyc2VjdCBwb2ludCB0aGF0IGlzIGluIGZyb250IG9mIHRoZSByYXkuXHJcblx0XHRpZiAoIHQwIDwgMCApIHJldHVybiB0aGlzLmF0KCB0MSwgdGFyZ2V0ICk7XHJcblxyXG5cdFx0Ly8gZWxzZSB0MCBpcyBpbiBmcm9udCBvZiB0aGUgcmF5LCBzbyByZXR1cm4gdGhlIGZpcnN0IGNvbGxpc2lvbiBwb2ludCBzY2FsZWQgYnkgdDBcclxuXHRcdHJldHVybiB0aGlzLmF0KCB0MCwgdGFyZ2V0ICk7XHJcblxyXG5cdH1cclxuXHJcblx0aW50ZXJzZWN0c1NwaGVyZSggc3BoZXJlICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLmRpc3RhbmNlU3FUb1BvaW50KCBzcGhlcmUuY2VudGVyICkgPD0gKCBzcGhlcmUucmFkaXVzICogc3BoZXJlLnJhZGl1cyApO1xyXG5cclxuXHR9XHJcblxyXG5cdGRpc3RhbmNlVG9QbGFuZSggcGxhbmUgKSB7XHJcblxyXG5cdFx0Y29uc3QgZGVub21pbmF0b3IgPSBwbGFuZS5ub3JtYWwuZG90KCB0aGlzLmRpcmVjdGlvbiApO1xyXG5cclxuXHRcdGlmICggZGVub21pbmF0b3IgPT09IDAgKSB7XHJcblxyXG5cdFx0XHQvLyBsaW5lIGlzIGNvcGxhbmFyLCByZXR1cm4gb3JpZ2luXHJcblx0XHRcdGlmICggcGxhbmUuZGlzdGFuY2VUb1BvaW50KCB0aGlzLm9yaWdpbiApID09PSAwICkge1xyXG5cclxuXHRcdFx0XHRyZXR1cm4gMDtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdC8vIE51bGwgaXMgcHJlZmVyYWJsZSB0byB1bmRlZmluZWQgc2luY2UgdW5kZWZpbmVkIG1lYW5zLi4uLiBpdCBpcyB1bmRlZmluZWRcclxuXHJcblx0XHRcdHJldHVybiBudWxsO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCB0ID0gLSAoIHRoaXMub3JpZ2luLmRvdCggcGxhbmUubm9ybWFsICkgKyBwbGFuZS5jb25zdGFudCApIC8gZGVub21pbmF0b3I7XHJcblxyXG5cdFx0Ly8gUmV0dXJuIGlmIHRoZSByYXkgbmV2ZXIgaW50ZXJzZWN0cyB0aGUgcGxhbmVcclxuXHJcblx0XHRyZXR1cm4gdCA+PSAwID8gdCA6IG51bGw7XHJcblxyXG5cdH1cclxuXHJcblx0aW50ZXJzZWN0UGxhbmUoIHBsYW5lLCB0YXJnZXQgKSB7XHJcblxyXG5cdFx0Y29uc3QgdCA9IHRoaXMuZGlzdGFuY2VUb1BsYW5lKCBwbGFuZSApO1xyXG5cclxuXHRcdGlmICggdCA9PT0gbnVsbCApIHtcclxuXHJcblx0XHRcdHJldHVybiBudWxsO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcy5hdCggdCwgdGFyZ2V0ICk7XHJcblxyXG5cdH1cclxuXHJcblx0aW50ZXJzZWN0c1BsYW5lKCBwbGFuZSApIHtcclxuXHJcblx0XHQvLyBjaGVjayBpZiB0aGUgcmF5IGxpZXMgb24gdGhlIHBsYW5lIGZpcnN0XHJcblxyXG5cdFx0Y29uc3QgZGlzdFRvUG9pbnQgPSBwbGFuZS5kaXN0YW5jZVRvUG9pbnQoIHRoaXMub3JpZ2luICk7XHJcblxyXG5cdFx0aWYgKCBkaXN0VG9Qb2ludCA9PT0gMCApIHtcclxuXHJcblx0XHRcdHJldHVybiB0cnVlO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCBkZW5vbWluYXRvciA9IHBsYW5lLm5vcm1hbC5kb3QoIHRoaXMuZGlyZWN0aW9uICk7XHJcblxyXG5cdFx0aWYgKCBkZW5vbWluYXRvciAqIGRpc3RUb1BvaW50IDwgMCApIHtcclxuXHJcblx0XHRcdHJldHVybiB0cnVlO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvLyByYXkgb3JpZ2luIGlzIGJlaGluZCB0aGUgcGxhbmUgKGFuZCBpcyBwb2ludGluZyBiZWhpbmQgaXQpXHJcblxyXG5cdFx0cmV0dXJuIGZhbHNlO1xyXG5cclxuXHR9XHJcblxyXG5cdGludGVyc2VjdEJveCggYm94LCB0YXJnZXQgKSB7XHJcblxyXG5cdFx0bGV0IHRtaW4sIHRtYXgsIHR5bWluLCB0eW1heCwgdHptaW4sIHR6bWF4O1xyXG5cclxuXHRcdGNvbnN0IGludmRpcnggPSAxIC8gdGhpcy5kaXJlY3Rpb24ueCxcclxuXHRcdFx0aW52ZGlyeSA9IDEgLyB0aGlzLmRpcmVjdGlvbi55LFxyXG5cdFx0XHRpbnZkaXJ6ID0gMSAvIHRoaXMuZGlyZWN0aW9uLno7XHJcblxyXG5cdFx0Y29uc3Qgb3JpZ2luID0gdGhpcy5vcmlnaW47XHJcblxyXG5cdFx0aWYgKCBpbnZkaXJ4ID49IDAgKSB7XHJcblxyXG5cdFx0XHR0bWluID0gKCBib3gubWluLnggLSBvcmlnaW4ueCApICogaW52ZGlyeDtcclxuXHRcdFx0dG1heCA9ICggYm94Lm1heC54IC0gb3JpZ2luLnggKSAqIGludmRpcng7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdHRtaW4gPSAoIGJveC5tYXgueCAtIG9yaWdpbi54ICkgKiBpbnZkaXJ4O1xyXG5cdFx0XHR0bWF4ID0gKCBib3gubWluLnggLSBvcmlnaW4ueCApICogaW52ZGlyeDtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBpbnZkaXJ5ID49IDAgKSB7XHJcblxyXG5cdFx0XHR0eW1pbiA9ICggYm94Lm1pbi55IC0gb3JpZ2luLnkgKSAqIGludmRpcnk7XHJcblx0XHRcdHR5bWF4ID0gKCBib3gubWF4LnkgLSBvcmlnaW4ueSApICogaW52ZGlyeTtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0dHltaW4gPSAoIGJveC5tYXgueSAtIG9yaWdpbi55ICkgKiBpbnZkaXJ5O1xyXG5cdFx0XHR0eW1heCA9ICggYm94Lm1pbi55IC0gb3JpZ2luLnkgKSAqIGludmRpcnk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggKCB0bWluID4gdHltYXggKSB8fCAoIHR5bWluID4gdG1heCApICkgcmV0dXJuIG51bGw7XHJcblxyXG5cdFx0aWYgKCB0eW1pbiA+IHRtaW4gfHwgaXNOYU4oIHRtaW4gKSApIHRtaW4gPSB0eW1pbjtcclxuXHJcblx0XHRpZiAoIHR5bWF4IDwgdG1heCB8fCBpc05hTiggdG1heCApICkgdG1heCA9IHR5bWF4O1xyXG5cclxuXHRcdGlmICggaW52ZGlyeiA+PSAwICkge1xyXG5cclxuXHRcdFx0dHptaW4gPSAoIGJveC5taW4ueiAtIG9yaWdpbi56ICkgKiBpbnZkaXJ6O1xyXG5cdFx0XHR0em1heCA9ICggYm94Lm1heC56IC0gb3JpZ2luLnogKSAqIGludmRpcno7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdHR6bWluID0gKCBib3gubWF4LnogLSBvcmlnaW4ueiApICogaW52ZGlyejtcclxuXHRcdFx0dHptYXggPSAoIGJveC5taW4ueiAtIG9yaWdpbi56ICkgKiBpbnZkaXJ6O1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoICggdG1pbiA+IHR6bWF4ICkgfHwgKCB0em1pbiA+IHRtYXggKSApIHJldHVybiBudWxsO1xyXG5cclxuXHRcdGlmICggdHptaW4gPiB0bWluIHx8IHRtaW4gIT09IHRtaW4gKSB0bWluID0gdHptaW47XHJcblxyXG5cdFx0aWYgKCB0em1heCA8IHRtYXggfHwgdG1heCAhPT0gdG1heCApIHRtYXggPSB0em1heDtcclxuXHJcblx0XHQvL3JldHVybiBwb2ludCBjbG9zZXN0IHRvIHRoZSByYXkgKHBvc2l0aXZlIHNpZGUpXHJcblxyXG5cdFx0aWYgKCB0bWF4IDwgMCApIHJldHVybiBudWxsO1xyXG5cclxuXHRcdHJldHVybiB0aGlzLmF0KCB0bWluID49IDAgPyB0bWluIDogdG1heCwgdGFyZ2V0ICk7XHJcblxyXG5cdH1cclxuXHJcblx0aW50ZXJzZWN0c0JveCggYm94ICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLmludGVyc2VjdEJveCggYm94LCBfdmVjdG9yICkgIT09IG51bGw7XHJcblxyXG5cdH1cclxuXHJcblx0aW50ZXJzZWN0VHJpYW5nbGUoIGEsIGIsIGMsIGJhY2tmYWNlQ3VsbGluZywgdGFyZ2V0ICkge1xyXG5cclxuXHRcdC8vIENvbXB1dGUgdGhlIG9mZnNldCBvcmlnaW4sIGVkZ2VzLCBhbmQgbm9ybWFsLlxyXG5cclxuXHRcdC8vIGZyb20gaHR0cHM6Ly9naXRodWIuY29tL3Btam9uaWFrL0dlb21ldHJpY1Rvb2xzL2Jsb2IvbWFzdGVyL0dURW5naW5lL0luY2x1ZGUvTWF0aGVtYXRpY3MvR3RlSW50clJheTNUcmlhbmdsZTMuaFxyXG5cclxuXHRcdF9lZGdlMS5zdWJWZWN0b3JzKCBiLCBhICk7XHJcblx0XHRfZWRnZTIuc3ViVmVjdG9ycyggYywgYSApO1xyXG5cdFx0X25vcm1hbC5jcm9zc1ZlY3RvcnMoIF9lZGdlMSwgX2VkZ2UyICk7XHJcblxyXG5cdFx0Ly8gU29sdmUgUSArIHQqRCA9IGIxKkUxICsgYjIqRTIgKFEgPSBrRGlmZiwgRCA9IHJheSBkaXJlY3Rpb24sXHJcblx0XHQvLyBFMSA9IGtFZGdlMSwgRTIgPSBrRWRnZTIsIE4gPSBDcm9zcyhFMSxFMikpIGJ5XHJcblx0XHQvLyAgIHxEb3QoRCxOKXwqYjEgPSBzaWduKERvdChELE4pKSpEb3QoRCxDcm9zcyhRLEUyKSlcclxuXHRcdC8vICAgfERvdChELE4pfCpiMiA9IHNpZ24oRG90KEQsTikpKkRvdChELENyb3NzKEUxLFEpKVxyXG5cdFx0Ly8gICB8RG90KEQsTil8KnQgPSAtc2lnbihEb3QoRCxOKSkqRG90KFEsTilcclxuXHRcdGxldCBEZE4gPSB0aGlzLmRpcmVjdGlvbi5kb3QoIF9ub3JtYWwgKTtcclxuXHRcdGxldCBzaWduO1xyXG5cclxuXHRcdGlmICggRGROID4gMCApIHtcclxuXHJcblx0XHRcdGlmICggYmFja2ZhY2VDdWxsaW5nICkgcmV0dXJuIG51bGw7XHJcblx0XHRcdHNpZ24gPSAxO1xyXG5cclxuXHRcdH0gZWxzZSBpZiAoIERkTiA8IDAgKSB7XHJcblxyXG5cdFx0XHRzaWduID0gLSAxO1xyXG5cdFx0XHREZE4gPSAtIERkTjtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0cmV0dXJuIG51bGw7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdF9kaWZmLnN1YlZlY3RvcnMoIHRoaXMub3JpZ2luLCBhICk7XHJcblx0XHRjb25zdCBEZFF4RTIgPSBzaWduICogdGhpcy5kaXJlY3Rpb24uZG90KCBfZWRnZTIuY3Jvc3NWZWN0b3JzKCBfZGlmZiwgX2VkZ2UyICkgKTtcclxuXHJcblx0XHQvLyBiMSA8IDAsIG5vIGludGVyc2VjdGlvblxyXG5cdFx0aWYgKCBEZFF4RTIgPCAwICkge1xyXG5cclxuXHRcdFx0cmV0dXJuIG51bGw7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGNvbnN0IERkRTF4USA9IHNpZ24gKiB0aGlzLmRpcmVjdGlvbi5kb3QoIF9lZGdlMS5jcm9zcyggX2RpZmYgKSApO1xyXG5cclxuXHRcdC8vIGIyIDwgMCwgbm8gaW50ZXJzZWN0aW9uXHJcblx0XHRpZiAoIERkRTF4USA8IDAgKSB7XHJcblxyXG5cdFx0XHRyZXR1cm4gbnVsbDtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gYjErYjIgPiAxLCBubyBpbnRlcnNlY3Rpb25cclxuXHRcdGlmICggRGRReEUyICsgRGRFMXhRID4gRGROICkge1xyXG5cclxuXHRcdFx0cmV0dXJuIG51bGw7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIExpbmUgaW50ZXJzZWN0cyB0cmlhbmdsZSwgY2hlY2sgaWYgcmF5IGRvZXMuXHJcblx0XHRjb25zdCBRZE4gPSAtIHNpZ24gKiBfZGlmZi5kb3QoIF9ub3JtYWwgKTtcclxuXHJcblx0XHQvLyB0IDwgMCwgbm8gaW50ZXJzZWN0aW9uXHJcblx0XHRpZiAoIFFkTiA8IDAgKSB7XHJcblxyXG5cdFx0XHRyZXR1cm4gbnVsbDtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gUmF5IGludGVyc2VjdHMgdHJpYW5nbGUuXHJcblx0XHRyZXR1cm4gdGhpcy5hdCggUWROIC8gRGROLCB0YXJnZXQgKTtcclxuXHJcblx0fVxyXG5cclxuXHRhcHBseU1hdHJpeDQoIG1hdHJpeDQgKSB7XHJcblxyXG5cdFx0dGhpcy5vcmlnaW4uYXBwbHlNYXRyaXg0KCBtYXRyaXg0ICk7XHJcblx0XHR0aGlzLmRpcmVjdGlvbi50cmFuc2Zvcm1EaXJlY3Rpb24oIG1hdHJpeDQgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRlcXVhbHMoIHJheSApIHtcclxuXHJcblx0XHRyZXR1cm4gcmF5Lm9yaWdpbi5lcXVhbHMoIHRoaXMub3JpZ2luICkgJiYgcmF5LmRpcmVjdGlvbi5lcXVhbHMoIHRoaXMuZGlyZWN0aW9uICk7XHJcblxyXG5cdH1cclxuXHJcblx0Y2xvbmUoKSB7XHJcblxyXG5cdFx0cmV0dXJuIG5ldyB0aGlzLmNvbnN0cnVjdG9yKCkuY29weSggdGhpcyApO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBSYXkgfTtcclxuIiwiaW1wb3J0IHsgV2ViR0xDb29yZGluYXRlU3lzdGVtLCBXZWJHUFVDb29yZGluYXRlU3lzdGVtIH0gZnJvbSAnLi4vY29uc3RhbnRzLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yMyB9IGZyb20gJy4vVmVjdG9yMy5qcyc7XHJcblxyXG5jbGFzcyBNYXRyaXg0IHtcclxuXHJcblx0Y29uc3RydWN0b3IoIG4xMSwgbjEyLCBuMTMsIG4xNCwgbjIxLCBuMjIsIG4yMywgbjI0LCBuMzEsIG4zMiwgbjMzLCBuMzQsIG40MSwgbjQyLCBuNDMsIG40NCApIHtcclxuXHJcblx0XHRNYXRyaXg0LnByb3RvdHlwZS5pc01hdHJpeDQgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMuZWxlbWVudHMgPSBbXHJcblxyXG5cdFx0XHQxLCAwLCAwLCAwLFxyXG5cdFx0XHQwLCAxLCAwLCAwLFxyXG5cdFx0XHQwLCAwLCAxLCAwLFxyXG5cdFx0XHQwLCAwLCAwLCAxXHJcblxyXG5cdFx0XTtcclxuXHJcblx0XHRpZiAoIG4xMSAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0dGhpcy5zZXQoIG4xMSwgbjEyLCBuMTMsIG4xNCwgbjIxLCBuMjIsIG4yMywgbjI0LCBuMzEsIG4zMiwgbjMzLCBuMzQsIG40MSwgbjQyLCBuNDMsIG40NCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRzZXQoIG4xMSwgbjEyLCBuMTMsIG4xNCwgbjIxLCBuMjIsIG4yMywgbjI0LCBuMzEsIG4zMiwgbjMzLCBuMzQsIG40MSwgbjQyLCBuNDMsIG40NCApIHtcclxuXHJcblx0XHRjb25zdCB0ZSA9IHRoaXMuZWxlbWVudHM7XHJcblxyXG5cdFx0dGVbIDAgXSA9IG4xMTsgdGVbIDQgXSA9IG4xMjsgdGVbIDggXSA9IG4xMzsgdGVbIDEyIF0gPSBuMTQ7XHJcblx0XHR0ZVsgMSBdID0gbjIxOyB0ZVsgNSBdID0gbjIyOyB0ZVsgOSBdID0gbjIzOyB0ZVsgMTMgXSA9IG4yNDtcclxuXHRcdHRlWyAyIF0gPSBuMzE7IHRlWyA2IF0gPSBuMzI7IHRlWyAxMCBdID0gbjMzOyB0ZVsgMTQgXSA9IG4zNDtcclxuXHRcdHRlWyAzIF0gPSBuNDE7IHRlWyA3IF0gPSBuNDI7IHRlWyAxMSBdID0gbjQzOyB0ZVsgMTUgXSA9IG40NDtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRpZGVudGl0eSgpIHtcclxuXHJcblx0XHR0aGlzLnNldChcclxuXHJcblx0XHRcdDEsIDAsIDAsIDAsXHJcblx0XHRcdDAsIDEsIDAsIDAsXHJcblx0XHRcdDAsIDAsIDEsIDAsXHJcblx0XHRcdDAsIDAsIDAsIDFcclxuXHJcblx0XHQpO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGNsb25lKCkge1xyXG5cclxuXHRcdHJldHVybiBuZXcgTWF0cml4NCgpLmZyb21BcnJheSggdGhpcy5lbGVtZW50cyApO1xyXG5cclxuXHR9XHJcblxyXG5cdGNvcHkoIG0gKSB7XHJcblxyXG5cdFx0Y29uc3QgdGUgPSB0aGlzLmVsZW1lbnRzO1xyXG5cdFx0Y29uc3QgbWUgPSBtLmVsZW1lbnRzO1xyXG5cclxuXHRcdHRlWyAwIF0gPSBtZVsgMCBdOyB0ZVsgMSBdID0gbWVbIDEgXTsgdGVbIDIgXSA9IG1lWyAyIF07IHRlWyAzIF0gPSBtZVsgMyBdO1xyXG5cdFx0dGVbIDQgXSA9IG1lWyA0IF07IHRlWyA1IF0gPSBtZVsgNSBdOyB0ZVsgNiBdID0gbWVbIDYgXTsgdGVbIDcgXSA9IG1lWyA3IF07XHJcblx0XHR0ZVsgOCBdID0gbWVbIDggXTsgdGVbIDkgXSA9IG1lWyA5IF07IHRlWyAxMCBdID0gbWVbIDEwIF07IHRlWyAxMSBdID0gbWVbIDExIF07XHJcblx0XHR0ZVsgMTIgXSA9IG1lWyAxMiBdOyB0ZVsgMTMgXSA9IG1lWyAxMyBdOyB0ZVsgMTQgXSA9IG1lWyAxNCBdOyB0ZVsgMTUgXSA9IG1lWyAxNSBdO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGNvcHlQb3NpdGlvbiggbSApIHtcclxuXHJcblx0XHRjb25zdCB0ZSA9IHRoaXMuZWxlbWVudHMsIG1lID0gbS5lbGVtZW50cztcclxuXHJcblx0XHR0ZVsgMTIgXSA9IG1lWyAxMiBdO1xyXG5cdFx0dGVbIDEzIF0gPSBtZVsgMTMgXTtcclxuXHRcdHRlWyAxNCBdID0gbWVbIDE0IF07XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0RnJvbU1hdHJpeDMoIG0gKSB7XHJcblxyXG5cdFx0Y29uc3QgbWUgPSBtLmVsZW1lbnRzO1xyXG5cclxuXHRcdHRoaXMuc2V0KFxyXG5cclxuXHRcdFx0bWVbIDAgXSwgbWVbIDMgXSwgbWVbIDYgXSwgMCxcclxuXHRcdFx0bWVbIDEgXSwgbWVbIDQgXSwgbWVbIDcgXSwgMCxcclxuXHRcdFx0bWVbIDIgXSwgbWVbIDUgXSwgbWVbIDggXSwgMCxcclxuXHRcdFx0MCwgMCwgMCwgMVxyXG5cclxuXHRcdCk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0ZXh0cmFjdEJhc2lzKCB4QXhpcywgeUF4aXMsIHpBeGlzICkge1xyXG5cclxuXHRcdHhBeGlzLnNldEZyb21NYXRyaXhDb2x1bW4oIHRoaXMsIDAgKTtcclxuXHRcdHlBeGlzLnNldEZyb21NYXRyaXhDb2x1bW4oIHRoaXMsIDEgKTtcclxuXHRcdHpBeGlzLnNldEZyb21NYXRyaXhDb2x1bW4oIHRoaXMsIDIgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRtYWtlQmFzaXMoIHhBeGlzLCB5QXhpcywgekF4aXMgKSB7XHJcblxyXG5cdFx0dGhpcy5zZXQoXHJcblx0XHRcdHhBeGlzLngsIHlBeGlzLngsIHpBeGlzLngsIDAsXHJcblx0XHRcdHhBeGlzLnksIHlBeGlzLnksIHpBeGlzLnksIDAsXHJcblx0XHRcdHhBeGlzLnosIHlBeGlzLnosIHpBeGlzLnosIDAsXHJcblx0XHRcdDAsIDAsIDAsIDFcclxuXHRcdCk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0ZXh0cmFjdFJvdGF0aW9uKCBtICkge1xyXG5cclxuXHRcdC8vIHRoaXMgbWV0aG9kIGRvZXMgbm90IHN1cHBvcnQgcmVmbGVjdGlvbiBtYXRyaWNlc1xyXG5cclxuXHRcdGNvbnN0IHRlID0gdGhpcy5lbGVtZW50cztcclxuXHRcdGNvbnN0IG1lID0gbS5lbGVtZW50cztcclxuXHJcblx0XHRjb25zdCBzY2FsZVggPSAxIC8gX3YxLnNldEZyb21NYXRyaXhDb2x1bW4oIG0sIDAgKS5sZW5ndGgoKTtcclxuXHRcdGNvbnN0IHNjYWxlWSA9IDEgLyBfdjEuc2V0RnJvbU1hdHJpeENvbHVtbiggbSwgMSApLmxlbmd0aCgpO1xyXG5cdFx0Y29uc3Qgc2NhbGVaID0gMSAvIF92MS5zZXRGcm9tTWF0cml4Q29sdW1uKCBtLCAyICkubGVuZ3RoKCk7XHJcblxyXG5cdFx0dGVbIDAgXSA9IG1lWyAwIF0gKiBzY2FsZVg7XHJcblx0XHR0ZVsgMSBdID0gbWVbIDEgXSAqIHNjYWxlWDtcclxuXHRcdHRlWyAyIF0gPSBtZVsgMiBdICogc2NhbGVYO1xyXG5cdFx0dGVbIDMgXSA9IDA7XHJcblxyXG5cdFx0dGVbIDQgXSA9IG1lWyA0IF0gKiBzY2FsZVk7XHJcblx0XHR0ZVsgNSBdID0gbWVbIDUgXSAqIHNjYWxlWTtcclxuXHRcdHRlWyA2IF0gPSBtZVsgNiBdICogc2NhbGVZO1xyXG5cdFx0dGVbIDcgXSA9IDA7XHJcblxyXG5cdFx0dGVbIDggXSA9IG1lWyA4IF0gKiBzY2FsZVo7XHJcblx0XHR0ZVsgOSBdID0gbWVbIDkgXSAqIHNjYWxlWjtcclxuXHRcdHRlWyAxMCBdID0gbWVbIDEwIF0gKiBzY2FsZVo7XHJcblx0XHR0ZVsgMTEgXSA9IDA7XHJcblxyXG5cdFx0dGVbIDEyIF0gPSAwO1xyXG5cdFx0dGVbIDEzIF0gPSAwO1xyXG5cdFx0dGVbIDE0IF0gPSAwO1xyXG5cdFx0dGVbIDE1IF0gPSAxO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdG1ha2VSb3RhdGlvbkZyb21FdWxlciggZXVsZXIgKSB7XHJcblxyXG5cdFx0Y29uc3QgdGUgPSB0aGlzLmVsZW1lbnRzO1xyXG5cclxuXHRcdGNvbnN0IHggPSBldWxlci54LCB5ID0gZXVsZXIueSwgeiA9IGV1bGVyLno7XHJcblx0XHRjb25zdCBhID0gTWF0aC5jb3MoIHggKSwgYiA9IE1hdGguc2luKCB4ICk7XHJcblx0XHRjb25zdCBjID0gTWF0aC5jb3MoIHkgKSwgZCA9IE1hdGguc2luKCB5ICk7XHJcblx0XHRjb25zdCBlID0gTWF0aC5jb3MoIHogKSwgZiA9IE1hdGguc2luKCB6ICk7XHJcblxyXG5cdFx0aWYgKCBldWxlci5vcmRlciA9PT0gJ1hZWicgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBhZSA9IGEgKiBlLCBhZiA9IGEgKiBmLCBiZSA9IGIgKiBlLCBiZiA9IGIgKiBmO1xyXG5cclxuXHRcdFx0dGVbIDAgXSA9IGMgKiBlO1xyXG5cdFx0XHR0ZVsgNCBdID0gLSBjICogZjtcclxuXHRcdFx0dGVbIDggXSA9IGQ7XHJcblxyXG5cdFx0XHR0ZVsgMSBdID0gYWYgKyBiZSAqIGQ7XHJcblx0XHRcdHRlWyA1IF0gPSBhZSAtIGJmICogZDtcclxuXHRcdFx0dGVbIDkgXSA9IC0gYiAqIGM7XHJcblxyXG5cdFx0XHR0ZVsgMiBdID0gYmYgLSBhZSAqIGQ7XHJcblx0XHRcdHRlWyA2IF0gPSBiZSArIGFmICogZDtcclxuXHRcdFx0dGVbIDEwIF0gPSBhICogYztcclxuXHJcblx0XHR9IGVsc2UgaWYgKCBldWxlci5vcmRlciA9PT0gJ1lYWicgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBjZSA9IGMgKiBlLCBjZiA9IGMgKiBmLCBkZSA9IGQgKiBlLCBkZiA9IGQgKiBmO1xyXG5cclxuXHRcdFx0dGVbIDAgXSA9IGNlICsgZGYgKiBiO1xyXG5cdFx0XHR0ZVsgNCBdID0gZGUgKiBiIC0gY2Y7XHJcblx0XHRcdHRlWyA4IF0gPSBhICogZDtcclxuXHJcblx0XHRcdHRlWyAxIF0gPSBhICogZjtcclxuXHRcdFx0dGVbIDUgXSA9IGEgKiBlO1xyXG5cdFx0XHR0ZVsgOSBdID0gLSBiO1xyXG5cclxuXHRcdFx0dGVbIDIgXSA9IGNmICogYiAtIGRlO1xyXG5cdFx0XHR0ZVsgNiBdID0gZGYgKyBjZSAqIGI7XHJcblx0XHRcdHRlWyAxMCBdID0gYSAqIGM7XHJcblxyXG5cdFx0fSBlbHNlIGlmICggZXVsZXIub3JkZXIgPT09ICdaWFknICkge1xyXG5cclxuXHRcdFx0Y29uc3QgY2UgPSBjICogZSwgY2YgPSBjICogZiwgZGUgPSBkICogZSwgZGYgPSBkICogZjtcclxuXHJcblx0XHRcdHRlWyAwIF0gPSBjZSAtIGRmICogYjtcclxuXHRcdFx0dGVbIDQgXSA9IC0gYSAqIGY7XHJcblx0XHRcdHRlWyA4IF0gPSBkZSArIGNmICogYjtcclxuXHJcblx0XHRcdHRlWyAxIF0gPSBjZiArIGRlICogYjtcclxuXHRcdFx0dGVbIDUgXSA9IGEgKiBlO1xyXG5cdFx0XHR0ZVsgOSBdID0gZGYgLSBjZSAqIGI7XHJcblxyXG5cdFx0XHR0ZVsgMiBdID0gLSBhICogZDtcclxuXHRcdFx0dGVbIDYgXSA9IGI7XHJcblx0XHRcdHRlWyAxMCBdID0gYSAqIGM7XHJcblxyXG5cdFx0fSBlbHNlIGlmICggZXVsZXIub3JkZXIgPT09ICdaWVgnICkge1xyXG5cclxuXHRcdFx0Y29uc3QgYWUgPSBhICogZSwgYWYgPSBhICogZiwgYmUgPSBiICogZSwgYmYgPSBiICogZjtcclxuXHJcblx0XHRcdHRlWyAwIF0gPSBjICogZTtcclxuXHRcdFx0dGVbIDQgXSA9IGJlICogZCAtIGFmO1xyXG5cdFx0XHR0ZVsgOCBdID0gYWUgKiBkICsgYmY7XHJcblxyXG5cdFx0XHR0ZVsgMSBdID0gYyAqIGY7XHJcblx0XHRcdHRlWyA1IF0gPSBiZiAqIGQgKyBhZTtcclxuXHRcdFx0dGVbIDkgXSA9IGFmICogZCAtIGJlO1xyXG5cclxuXHRcdFx0dGVbIDIgXSA9IC0gZDtcclxuXHRcdFx0dGVbIDYgXSA9IGIgKiBjO1xyXG5cdFx0XHR0ZVsgMTAgXSA9IGEgKiBjO1xyXG5cclxuXHRcdH0gZWxzZSBpZiAoIGV1bGVyLm9yZGVyID09PSAnWVpYJyApIHtcclxuXHJcblx0XHRcdGNvbnN0IGFjID0gYSAqIGMsIGFkID0gYSAqIGQsIGJjID0gYiAqIGMsIGJkID0gYiAqIGQ7XHJcblxyXG5cdFx0XHR0ZVsgMCBdID0gYyAqIGU7XHJcblx0XHRcdHRlWyA0IF0gPSBiZCAtIGFjICogZjtcclxuXHRcdFx0dGVbIDggXSA9IGJjICogZiArIGFkO1xyXG5cclxuXHRcdFx0dGVbIDEgXSA9IGY7XHJcblx0XHRcdHRlWyA1IF0gPSBhICogZTtcclxuXHRcdFx0dGVbIDkgXSA9IC0gYiAqIGU7XHJcblxyXG5cdFx0XHR0ZVsgMiBdID0gLSBkICogZTtcclxuXHRcdFx0dGVbIDYgXSA9IGFkICogZiArIGJjO1xyXG5cdFx0XHR0ZVsgMTAgXSA9IGFjIC0gYmQgKiBmO1xyXG5cclxuXHRcdH0gZWxzZSBpZiAoIGV1bGVyLm9yZGVyID09PSAnWFpZJyApIHtcclxuXHJcblx0XHRcdGNvbnN0IGFjID0gYSAqIGMsIGFkID0gYSAqIGQsIGJjID0gYiAqIGMsIGJkID0gYiAqIGQ7XHJcblxyXG5cdFx0XHR0ZVsgMCBdID0gYyAqIGU7XHJcblx0XHRcdHRlWyA0IF0gPSAtIGY7XHJcblx0XHRcdHRlWyA4IF0gPSBkICogZTtcclxuXHJcblx0XHRcdHRlWyAxIF0gPSBhYyAqIGYgKyBiZDtcclxuXHRcdFx0dGVbIDUgXSA9IGEgKiBlO1xyXG5cdFx0XHR0ZVsgOSBdID0gYWQgKiBmIC0gYmM7XHJcblxyXG5cdFx0XHR0ZVsgMiBdID0gYmMgKiBmIC0gYWQ7XHJcblx0XHRcdHRlWyA2IF0gPSBiICogZTtcclxuXHRcdFx0dGVbIDEwIF0gPSBiZCAqIGYgKyBhYztcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gYm90dG9tIHJvd1xyXG5cdFx0dGVbIDMgXSA9IDA7XHJcblx0XHR0ZVsgNyBdID0gMDtcclxuXHRcdHRlWyAxMSBdID0gMDtcclxuXHJcblx0XHQvLyBsYXN0IGNvbHVtblxyXG5cdFx0dGVbIDEyIF0gPSAwO1xyXG5cdFx0dGVbIDEzIF0gPSAwO1xyXG5cdFx0dGVbIDE0IF0gPSAwO1xyXG5cdFx0dGVbIDE1IF0gPSAxO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdG1ha2VSb3RhdGlvbkZyb21RdWF0ZXJuaW9uKCBxICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLmNvbXBvc2UoIF96ZXJvLCBxLCBfb25lICk7XHJcblxyXG5cdH1cclxuXHJcblx0bG9va0F0KCBleWUsIHRhcmdldCwgdXAgKSB7XHJcblxyXG5cdFx0Y29uc3QgdGUgPSB0aGlzLmVsZW1lbnRzO1xyXG5cclxuXHRcdF96LnN1YlZlY3RvcnMoIGV5ZSwgdGFyZ2V0ICk7XHJcblxyXG5cdFx0aWYgKCBfei5sZW5ndGhTcSgpID09PSAwICkge1xyXG5cclxuXHRcdFx0Ly8gZXllIGFuZCB0YXJnZXQgYXJlIGluIHRoZSBzYW1lIHBvc2l0aW9uXHJcblxyXG5cdFx0XHRfei56ID0gMTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0X3oubm9ybWFsaXplKCk7XHJcblx0XHRfeC5jcm9zc1ZlY3RvcnMoIHVwLCBfeiApO1xyXG5cclxuXHRcdGlmICggX3gubGVuZ3RoU3EoKSA9PT0gMCApIHtcclxuXHJcblx0XHRcdC8vIHVwIGFuZCB6IGFyZSBwYXJhbGxlbFxyXG5cclxuXHRcdFx0aWYgKCBNYXRoLmFicyggdXAueiApID09PSAxICkge1xyXG5cclxuXHRcdFx0XHRfei54ICs9IDAuMDAwMTtcclxuXHJcblx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdF96LnogKz0gMC4wMDAxO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0X3oubm9ybWFsaXplKCk7XHJcblx0XHRcdF94LmNyb3NzVmVjdG9ycyggdXAsIF96ICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdF94Lm5vcm1hbGl6ZSgpO1xyXG5cdFx0X3kuY3Jvc3NWZWN0b3JzKCBfeiwgX3ggKTtcclxuXHJcblx0XHR0ZVsgMCBdID0gX3gueDsgdGVbIDQgXSA9IF95Lng7IHRlWyA4IF0gPSBfei54O1xyXG5cdFx0dGVbIDEgXSA9IF94Lnk7IHRlWyA1IF0gPSBfeS55OyB0ZVsgOSBdID0gX3oueTtcclxuXHRcdHRlWyAyIF0gPSBfeC56OyB0ZVsgNiBdID0gX3kuejsgdGVbIDEwIF0gPSBfei56O1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdG11bHRpcGx5KCBtICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLm11bHRpcGx5TWF0cmljZXMoIHRoaXMsIG0gKTtcclxuXHJcblx0fVxyXG5cclxuXHRwcmVtdWx0aXBseSggbSApIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5tdWx0aXBseU1hdHJpY2VzKCBtLCB0aGlzICk7XHJcblxyXG5cdH1cclxuXHJcblx0bXVsdGlwbHlNYXRyaWNlcyggYSwgYiApIHtcclxuXHJcblx0XHRjb25zdCBhZSA9IGEuZWxlbWVudHM7XHJcblx0XHRjb25zdCBiZSA9IGIuZWxlbWVudHM7XHJcblx0XHRjb25zdCB0ZSA9IHRoaXMuZWxlbWVudHM7XHJcblxyXG5cdFx0Y29uc3QgYTExID0gYWVbIDAgXSwgYTEyID0gYWVbIDQgXSwgYTEzID0gYWVbIDggXSwgYTE0ID0gYWVbIDEyIF07XHJcblx0XHRjb25zdCBhMjEgPSBhZVsgMSBdLCBhMjIgPSBhZVsgNSBdLCBhMjMgPSBhZVsgOSBdLCBhMjQgPSBhZVsgMTMgXTtcclxuXHRcdGNvbnN0IGEzMSA9IGFlWyAyIF0sIGEzMiA9IGFlWyA2IF0sIGEzMyA9IGFlWyAxMCBdLCBhMzQgPSBhZVsgMTQgXTtcclxuXHRcdGNvbnN0IGE0MSA9IGFlWyAzIF0sIGE0MiA9IGFlWyA3IF0sIGE0MyA9IGFlWyAxMSBdLCBhNDQgPSBhZVsgMTUgXTtcclxuXHJcblx0XHRjb25zdCBiMTEgPSBiZVsgMCBdLCBiMTIgPSBiZVsgNCBdLCBiMTMgPSBiZVsgOCBdLCBiMTQgPSBiZVsgMTIgXTtcclxuXHRcdGNvbnN0IGIyMSA9IGJlWyAxIF0sIGIyMiA9IGJlWyA1IF0sIGIyMyA9IGJlWyA5IF0sIGIyNCA9IGJlWyAxMyBdO1xyXG5cdFx0Y29uc3QgYjMxID0gYmVbIDIgXSwgYjMyID0gYmVbIDYgXSwgYjMzID0gYmVbIDEwIF0sIGIzNCA9IGJlWyAxNCBdO1xyXG5cdFx0Y29uc3QgYjQxID0gYmVbIDMgXSwgYjQyID0gYmVbIDcgXSwgYjQzID0gYmVbIDExIF0sIGI0NCA9IGJlWyAxNSBdO1xyXG5cclxuXHRcdHRlWyAwIF0gPSBhMTEgKiBiMTEgKyBhMTIgKiBiMjEgKyBhMTMgKiBiMzEgKyBhMTQgKiBiNDE7XHJcblx0XHR0ZVsgNCBdID0gYTExICogYjEyICsgYTEyICogYjIyICsgYTEzICogYjMyICsgYTE0ICogYjQyO1xyXG5cdFx0dGVbIDggXSA9IGExMSAqIGIxMyArIGExMiAqIGIyMyArIGExMyAqIGIzMyArIGExNCAqIGI0MztcclxuXHRcdHRlWyAxMiBdID0gYTExICogYjE0ICsgYTEyICogYjI0ICsgYTEzICogYjM0ICsgYTE0ICogYjQ0O1xyXG5cclxuXHRcdHRlWyAxIF0gPSBhMjEgKiBiMTEgKyBhMjIgKiBiMjEgKyBhMjMgKiBiMzEgKyBhMjQgKiBiNDE7XHJcblx0XHR0ZVsgNSBdID0gYTIxICogYjEyICsgYTIyICogYjIyICsgYTIzICogYjMyICsgYTI0ICogYjQyO1xyXG5cdFx0dGVbIDkgXSA9IGEyMSAqIGIxMyArIGEyMiAqIGIyMyArIGEyMyAqIGIzMyArIGEyNCAqIGI0MztcclxuXHRcdHRlWyAxMyBdID0gYTIxICogYjE0ICsgYTIyICogYjI0ICsgYTIzICogYjM0ICsgYTI0ICogYjQ0O1xyXG5cclxuXHRcdHRlWyAyIF0gPSBhMzEgKiBiMTEgKyBhMzIgKiBiMjEgKyBhMzMgKiBiMzEgKyBhMzQgKiBiNDE7XHJcblx0XHR0ZVsgNiBdID0gYTMxICogYjEyICsgYTMyICogYjIyICsgYTMzICogYjMyICsgYTM0ICogYjQyO1xyXG5cdFx0dGVbIDEwIF0gPSBhMzEgKiBiMTMgKyBhMzIgKiBiMjMgKyBhMzMgKiBiMzMgKyBhMzQgKiBiNDM7XHJcblx0XHR0ZVsgMTQgXSA9IGEzMSAqIGIxNCArIGEzMiAqIGIyNCArIGEzMyAqIGIzNCArIGEzNCAqIGI0NDtcclxuXHJcblx0XHR0ZVsgMyBdID0gYTQxICogYjExICsgYTQyICogYjIxICsgYTQzICogYjMxICsgYTQ0ICogYjQxO1xyXG5cdFx0dGVbIDcgXSA9IGE0MSAqIGIxMiArIGE0MiAqIGIyMiArIGE0MyAqIGIzMiArIGE0NCAqIGI0MjtcclxuXHRcdHRlWyAxMSBdID0gYTQxICogYjEzICsgYTQyICogYjIzICsgYTQzICogYjMzICsgYTQ0ICogYjQzO1xyXG5cdFx0dGVbIDE1IF0gPSBhNDEgKiBiMTQgKyBhNDIgKiBiMjQgKyBhNDMgKiBiMzQgKyBhNDQgKiBiNDQ7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0bXVsdGlwbHlTY2FsYXIoIHMgKSB7XHJcblxyXG5cdFx0Y29uc3QgdGUgPSB0aGlzLmVsZW1lbnRzO1xyXG5cclxuXHRcdHRlWyAwIF0gKj0gczsgdGVbIDQgXSAqPSBzOyB0ZVsgOCBdICo9IHM7IHRlWyAxMiBdICo9IHM7XHJcblx0XHR0ZVsgMSBdICo9IHM7IHRlWyA1IF0gKj0gczsgdGVbIDkgXSAqPSBzOyB0ZVsgMTMgXSAqPSBzO1xyXG5cdFx0dGVbIDIgXSAqPSBzOyB0ZVsgNiBdICo9IHM7IHRlWyAxMCBdICo9IHM7IHRlWyAxNCBdICo9IHM7XHJcblx0XHR0ZVsgMyBdICo9IHM7IHRlWyA3IF0gKj0gczsgdGVbIDExIF0gKj0gczsgdGVbIDE1IF0gKj0gcztcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRkZXRlcm1pbmFudCgpIHtcclxuXHJcblx0XHRjb25zdCB0ZSA9IHRoaXMuZWxlbWVudHM7XHJcblxyXG5cdFx0Y29uc3QgbjExID0gdGVbIDAgXSwgbjEyID0gdGVbIDQgXSwgbjEzID0gdGVbIDggXSwgbjE0ID0gdGVbIDEyIF07XHJcblx0XHRjb25zdCBuMjEgPSB0ZVsgMSBdLCBuMjIgPSB0ZVsgNSBdLCBuMjMgPSB0ZVsgOSBdLCBuMjQgPSB0ZVsgMTMgXTtcclxuXHRcdGNvbnN0IG4zMSA9IHRlWyAyIF0sIG4zMiA9IHRlWyA2IF0sIG4zMyA9IHRlWyAxMCBdLCBuMzQgPSB0ZVsgMTQgXTtcclxuXHRcdGNvbnN0IG40MSA9IHRlWyAzIF0sIG40MiA9IHRlWyA3IF0sIG40MyA9IHRlWyAxMSBdLCBuNDQgPSB0ZVsgMTUgXTtcclxuXHJcblx0XHQvL1RPRE86IG1ha2UgdGhpcyBtb3JlIGVmZmljaWVudFxyXG5cdFx0Ly8oIGJhc2VkIG9uIGh0dHA6Ly93d3cuZXVjbGlkZWFuc3BhY2UuY29tL21hdGhzL2FsZ2VicmEvbWF0cml4L2Z1bmN0aW9ucy9pbnZlcnNlL2ZvdXJEL2luZGV4Lmh0bSApXHJcblxyXG5cdFx0cmV0dXJuIChcclxuXHRcdFx0bjQxICogKFxyXG5cdFx0XHRcdCsgbjE0ICogbjIzICogbjMyXHJcblx0XHRcdFx0IC0gbjEzICogbjI0ICogbjMyXHJcblx0XHRcdFx0IC0gbjE0ICogbjIyICogbjMzXHJcblx0XHRcdFx0ICsgbjEyICogbjI0ICogbjMzXHJcblx0XHRcdFx0ICsgbjEzICogbjIyICogbjM0XHJcblx0XHRcdFx0IC0gbjEyICogbjIzICogbjM0XHJcblx0XHRcdCkgK1xyXG5cdFx0XHRuNDIgKiAoXHJcblx0XHRcdFx0KyBuMTEgKiBuMjMgKiBuMzRcclxuXHRcdFx0XHQgLSBuMTEgKiBuMjQgKiBuMzNcclxuXHRcdFx0XHQgKyBuMTQgKiBuMjEgKiBuMzNcclxuXHRcdFx0XHQgLSBuMTMgKiBuMjEgKiBuMzRcclxuXHRcdFx0XHQgKyBuMTMgKiBuMjQgKiBuMzFcclxuXHRcdFx0XHQgLSBuMTQgKiBuMjMgKiBuMzFcclxuXHRcdFx0KSArXHJcblx0XHRcdG40MyAqIChcclxuXHRcdFx0XHQrIG4xMSAqIG4yNCAqIG4zMlxyXG5cdFx0XHRcdCAtIG4xMSAqIG4yMiAqIG4zNFxyXG5cdFx0XHRcdCAtIG4xNCAqIG4yMSAqIG4zMlxyXG5cdFx0XHRcdCArIG4xMiAqIG4yMSAqIG4zNFxyXG5cdFx0XHRcdCArIG4xNCAqIG4yMiAqIG4zMVxyXG5cdFx0XHRcdCAtIG4xMiAqIG4yNCAqIG4zMVxyXG5cdFx0XHQpICtcclxuXHRcdFx0bjQ0ICogKFxyXG5cdFx0XHRcdC0gbjEzICogbjIyICogbjMxXHJcblx0XHRcdFx0IC0gbjExICogbjIzICogbjMyXHJcblx0XHRcdFx0ICsgbjExICogbjIyICogbjMzXHJcblx0XHRcdFx0ICsgbjEzICogbjIxICogbjMyXHJcblx0XHRcdFx0IC0gbjEyICogbjIxICogbjMzXHJcblx0XHRcdFx0ICsgbjEyICogbjIzICogbjMxXHJcblx0XHRcdClcclxuXHJcblx0XHQpO1xyXG5cclxuXHR9XHJcblxyXG5cdHRyYW5zcG9zZSgpIHtcclxuXHJcblx0XHRjb25zdCB0ZSA9IHRoaXMuZWxlbWVudHM7XHJcblx0XHRsZXQgdG1wO1xyXG5cclxuXHRcdHRtcCA9IHRlWyAxIF07IHRlWyAxIF0gPSB0ZVsgNCBdOyB0ZVsgNCBdID0gdG1wO1xyXG5cdFx0dG1wID0gdGVbIDIgXTsgdGVbIDIgXSA9IHRlWyA4IF07IHRlWyA4IF0gPSB0bXA7XHJcblx0XHR0bXAgPSB0ZVsgNiBdOyB0ZVsgNiBdID0gdGVbIDkgXTsgdGVbIDkgXSA9IHRtcDtcclxuXHJcblx0XHR0bXAgPSB0ZVsgMyBdOyB0ZVsgMyBdID0gdGVbIDEyIF07IHRlWyAxMiBdID0gdG1wO1xyXG5cdFx0dG1wID0gdGVbIDcgXTsgdGVbIDcgXSA9IHRlWyAxMyBdOyB0ZVsgMTMgXSA9IHRtcDtcclxuXHRcdHRtcCA9IHRlWyAxMSBdOyB0ZVsgMTEgXSA9IHRlWyAxNCBdOyB0ZVsgMTQgXSA9IHRtcDtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRQb3NpdGlvbiggeCwgeSwgeiApIHtcclxuXHJcblx0XHRjb25zdCB0ZSA9IHRoaXMuZWxlbWVudHM7XHJcblxyXG5cdFx0aWYgKCB4LmlzVmVjdG9yMyApIHtcclxuXHJcblx0XHRcdHRlWyAxMiBdID0geC54O1xyXG5cdFx0XHR0ZVsgMTMgXSA9IHgueTtcclxuXHRcdFx0dGVbIDE0IF0gPSB4Lno7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdHRlWyAxMiBdID0geDtcclxuXHRcdFx0dGVbIDEzIF0gPSB5O1xyXG5cdFx0XHR0ZVsgMTQgXSA9IHo7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGludmVydCgpIHtcclxuXHJcblx0XHQvLyBiYXNlZCBvbiBodHRwOi8vd3d3LmV1Y2xpZGVhbnNwYWNlLmNvbS9tYXRocy9hbGdlYnJhL21hdHJpeC9mdW5jdGlvbnMvaW52ZXJzZS9mb3VyRC9pbmRleC5odG1cclxuXHRcdGNvbnN0IHRlID0gdGhpcy5lbGVtZW50cyxcclxuXHJcblx0XHRcdG4xMSA9IHRlWyAwIF0sIG4yMSA9IHRlWyAxIF0sIG4zMSA9IHRlWyAyIF0sIG40MSA9IHRlWyAzIF0sXHJcblx0XHRcdG4xMiA9IHRlWyA0IF0sIG4yMiA9IHRlWyA1IF0sIG4zMiA9IHRlWyA2IF0sIG40MiA9IHRlWyA3IF0sXHJcblx0XHRcdG4xMyA9IHRlWyA4IF0sIG4yMyA9IHRlWyA5IF0sIG4zMyA9IHRlWyAxMCBdLCBuNDMgPSB0ZVsgMTEgXSxcclxuXHRcdFx0bjE0ID0gdGVbIDEyIF0sIG4yNCA9IHRlWyAxMyBdLCBuMzQgPSB0ZVsgMTQgXSwgbjQ0ID0gdGVbIDE1IF0sXHJcblxyXG5cdFx0XHR0MTEgPSBuMjMgKiBuMzQgKiBuNDIgLSBuMjQgKiBuMzMgKiBuNDIgKyBuMjQgKiBuMzIgKiBuNDMgLSBuMjIgKiBuMzQgKiBuNDMgLSBuMjMgKiBuMzIgKiBuNDQgKyBuMjIgKiBuMzMgKiBuNDQsXHJcblx0XHRcdHQxMiA9IG4xNCAqIG4zMyAqIG40MiAtIG4xMyAqIG4zNCAqIG40MiAtIG4xNCAqIG4zMiAqIG40MyArIG4xMiAqIG4zNCAqIG40MyArIG4xMyAqIG4zMiAqIG40NCAtIG4xMiAqIG4zMyAqIG40NCxcclxuXHRcdFx0dDEzID0gbjEzICogbjI0ICogbjQyIC0gbjE0ICogbjIzICogbjQyICsgbjE0ICogbjIyICogbjQzIC0gbjEyICogbjI0ICogbjQzIC0gbjEzICogbjIyICogbjQ0ICsgbjEyICogbjIzICogbjQ0LFxyXG5cdFx0XHR0MTQgPSBuMTQgKiBuMjMgKiBuMzIgLSBuMTMgKiBuMjQgKiBuMzIgLSBuMTQgKiBuMjIgKiBuMzMgKyBuMTIgKiBuMjQgKiBuMzMgKyBuMTMgKiBuMjIgKiBuMzQgLSBuMTIgKiBuMjMgKiBuMzQ7XHJcblxyXG5cdFx0Y29uc3QgZGV0ID0gbjExICogdDExICsgbjIxICogdDEyICsgbjMxICogdDEzICsgbjQxICogdDE0O1xyXG5cclxuXHRcdGlmICggZGV0ID09PSAwICkgcmV0dXJuIHRoaXMuc2V0KCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwICk7XHJcblxyXG5cdFx0Y29uc3QgZGV0SW52ID0gMSAvIGRldDtcclxuXHJcblx0XHR0ZVsgMCBdID0gdDExICogZGV0SW52O1xyXG5cdFx0dGVbIDEgXSA9ICggbjI0ICogbjMzICogbjQxIC0gbjIzICogbjM0ICogbjQxIC0gbjI0ICogbjMxICogbjQzICsgbjIxICogbjM0ICogbjQzICsgbjIzICogbjMxICogbjQ0IC0gbjIxICogbjMzICogbjQ0ICkgKiBkZXRJbnY7XHJcblx0XHR0ZVsgMiBdID0gKCBuMjIgKiBuMzQgKiBuNDEgLSBuMjQgKiBuMzIgKiBuNDEgKyBuMjQgKiBuMzEgKiBuNDIgLSBuMjEgKiBuMzQgKiBuNDIgLSBuMjIgKiBuMzEgKiBuNDQgKyBuMjEgKiBuMzIgKiBuNDQgKSAqIGRldEludjtcclxuXHRcdHRlWyAzIF0gPSAoIG4yMyAqIG4zMiAqIG40MSAtIG4yMiAqIG4zMyAqIG40MSAtIG4yMyAqIG4zMSAqIG40MiArIG4yMSAqIG4zMyAqIG40MiArIG4yMiAqIG4zMSAqIG40MyAtIG4yMSAqIG4zMiAqIG40MyApICogZGV0SW52O1xyXG5cclxuXHRcdHRlWyA0IF0gPSB0MTIgKiBkZXRJbnY7XHJcblx0XHR0ZVsgNSBdID0gKCBuMTMgKiBuMzQgKiBuNDEgLSBuMTQgKiBuMzMgKiBuNDEgKyBuMTQgKiBuMzEgKiBuNDMgLSBuMTEgKiBuMzQgKiBuNDMgLSBuMTMgKiBuMzEgKiBuNDQgKyBuMTEgKiBuMzMgKiBuNDQgKSAqIGRldEludjtcclxuXHRcdHRlWyA2IF0gPSAoIG4xNCAqIG4zMiAqIG40MSAtIG4xMiAqIG4zNCAqIG40MSAtIG4xNCAqIG4zMSAqIG40MiArIG4xMSAqIG4zNCAqIG40MiArIG4xMiAqIG4zMSAqIG40NCAtIG4xMSAqIG4zMiAqIG40NCApICogZGV0SW52O1xyXG5cdFx0dGVbIDcgXSA9ICggbjEyICogbjMzICogbjQxIC0gbjEzICogbjMyICogbjQxICsgbjEzICogbjMxICogbjQyIC0gbjExICogbjMzICogbjQyIC0gbjEyICogbjMxICogbjQzICsgbjExICogbjMyICogbjQzICkgKiBkZXRJbnY7XHJcblxyXG5cdFx0dGVbIDggXSA9IHQxMyAqIGRldEludjtcclxuXHRcdHRlWyA5IF0gPSAoIG4xNCAqIG4yMyAqIG40MSAtIG4xMyAqIG4yNCAqIG40MSAtIG4xNCAqIG4yMSAqIG40MyArIG4xMSAqIG4yNCAqIG40MyArIG4xMyAqIG4yMSAqIG40NCAtIG4xMSAqIG4yMyAqIG40NCApICogZGV0SW52O1xyXG5cdFx0dGVbIDEwIF0gPSAoIG4xMiAqIG4yNCAqIG40MSAtIG4xNCAqIG4yMiAqIG40MSArIG4xNCAqIG4yMSAqIG40MiAtIG4xMSAqIG4yNCAqIG40MiAtIG4xMiAqIG4yMSAqIG40NCArIG4xMSAqIG4yMiAqIG40NCApICogZGV0SW52O1xyXG5cdFx0dGVbIDExIF0gPSAoIG4xMyAqIG4yMiAqIG40MSAtIG4xMiAqIG4yMyAqIG40MSAtIG4xMyAqIG4yMSAqIG40MiArIG4xMSAqIG4yMyAqIG40MiArIG4xMiAqIG4yMSAqIG40MyAtIG4xMSAqIG4yMiAqIG40MyApICogZGV0SW52O1xyXG5cclxuXHRcdHRlWyAxMiBdID0gdDE0ICogZGV0SW52O1xyXG5cdFx0dGVbIDEzIF0gPSAoIG4xMyAqIG4yNCAqIG4zMSAtIG4xNCAqIG4yMyAqIG4zMSArIG4xNCAqIG4yMSAqIG4zMyAtIG4xMSAqIG4yNCAqIG4zMyAtIG4xMyAqIG4yMSAqIG4zNCArIG4xMSAqIG4yMyAqIG4zNCApICogZGV0SW52O1xyXG5cdFx0dGVbIDE0IF0gPSAoIG4xNCAqIG4yMiAqIG4zMSAtIG4xMiAqIG4yNCAqIG4zMSAtIG4xNCAqIG4yMSAqIG4zMiArIG4xMSAqIG4yNCAqIG4zMiArIG4xMiAqIG4yMSAqIG4zNCAtIG4xMSAqIG4yMiAqIG4zNCApICogZGV0SW52O1xyXG5cdFx0dGVbIDE1IF0gPSAoIG4xMiAqIG4yMyAqIG4zMSAtIG4xMyAqIG4yMiAqIG4zMSArIG4xMyAqIG4yMSAqIG4zMiAtIG4xMSAqIG4yMyAqIG4zMiAtIG4xMiAqIG4yMSAqIG4zMyArIG4xMSAqIG4yMiAqIG4zMyApICogZGV0SW52O1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNjYWxlKCB2ICkge1xyXG5cclxuXHRcdGNvbnN0IHRlID0gdGhpcy5lbGVtZW50cztcclxuXHRcdGNvbnN0IHggPSB2LngsIHkgPSB2LnksIHogPSB2Lno7XHJcblxyXG5cdFx0dGVbIDAgXSAqPSB4OyB0ZVsgNCBdICo9IHk7IHRlWyA4IF0gKj0gejtcclxuXHRcdHRlWyAxIF0gKj0geDsgdGVbIDUgXSAqPSB5OyB0ZVsgOSBdICo9IHo7XHJcblx0XHR0ZVsgMiBdICo9IHg7IHRlWyA2IF0gKj0geTsgdGVbIDEwIF0gKj0gejtcclxuXHRcdHRlWyAzIF0gKj0geDsgdGVbIDcgXSAqPSB5OyB0ZVsgMTEgXSAqPSB6O1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldE1heFNjYWxlT25BeGlzKCkge1xyXG5cclxuXHRcdGNvbnN0IHRlID0gdGhpcy5lbGVtZW50cztcclxuXHJcblx0XHRjb25zdCBzY2FsZVhTcSA9IHRlWyAwIF0gKiB0ZVsgMCBdICsgdGVbIDEgXSAqIHRlWyAxIF0gKyB0ZVsgMiBdICogdGVbIDIgXTtcclxuXHRcdGNvbnN0IHNjYWxlWVNxID0gdGVbIDQgXSAqIHRlWyA0IF0gKyB0ZVsgNSBdICogdGVbIDUgXSArIHRlWyA2IF0gKiB0ZVsgNiBdO1xyXG5cdFx0Y29uc3Qgc2NhbGVaU3EgPSB0ZVsgOCBdICogdGVbIDggXSArIHRlWyA5IF0gKiB0ZVsgOSBdICsgdGVbIDEwIF0gKiB0ZVsgMTAgXTtcclxuXHJcblx0XHRyZXR1cm4gTWF0aC5zcXJ0KCBNYXRoLm1heCggc2NhbGVYU3EsIHNjYWxlWVNxLCBzY2FsZVpTcSApICk7XHJcblxyXG5cdH1cclxuXHJcblx0bWFrZVRyYW5zbGF0aW9uKCB4LCB5LCB6ICkge1xyXG5cclxuXHRcdGlmICggeC5pc1ZlY3RvcjMgKSB7XHJcblxyXG5cdFx0XHR0aGlzLnNldChcclxuXHJcblx0XHRcdFx0MSwgMCwgMCwgeC54LFxyXG5cdFx0XHRcdDAsIDEsIDAsIHgueSxcclxuXHRcdFx0XHQwLCAwLCAxLCB4LnosXHJcblx0XHRcdFx0MCwgMCwgMCwgMVxyXG5cclxuXHRcdFx0KTtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0dGhpcy5zZXQoXHJcblxyXG5cdFx0XHRcdDEsIDAsIDAsIHgsXHJcblx0XHRcdFx0MCwgMSwgMCwgeSxcclxuXHRcdFx0XHQwLCAwLCAxLCB6LFxyXG5cdFx0XHRcdDAsIDAsIDAsIDFcclxuXHJcblx0XHRcdCk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdG1ha2VSb3RhdGlvblgoIHRoZXRhICkge1xyXG5cclxuXHRcdGNvbnN0IGMgPSBNYXRoLmNvcyggdGhldGEgKSwgcyA9IE1hdGguc2luKCB0aGV0YSApO1xyXG5cclxuXHRcdHRoaXMuc2V0KFxyXG5cclxuXHRcdFx0MSwgMCwgMCwgMCxcclxuXHRcdFx0MCwgYywgLSBzLCAwLFxyXG5cdFx0XHQwLCBzLCBjLCAwLFxyXG5cdFx0XHQwLCAwLCAwLCAxXHJcblxyXG5cdFx0KTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRtYWtlUm90YXRpb25ZKCB0aGV0YSApIHtcclxuXHJcblx0XHRjb25zdCBjID0gTWF0aC5jb3MoIHRoZXRhICksIHMgPSBNYXRoLnNpbiggdGhldGEgKTtcclxuXHJcblx0XHR0aGlzLnNldChcclxuXHJcblx0XHRcdCBjLCAwLCBzLCAwLFxyXG5cdFx0XHQgMCwgMSwgMCwgMCxcclxuXHRcdFx0LSBzLCAwLCBjLCAwLFxyXG5cdFx0XHQgMCwgMCwgMCwgMVxyXG5cclxuXHRcdCk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0bWFrZVJvdGF0aW9uWiggdGhldGEgKSB7XHJcblxyXG5cdFx0Y29uc3QgYyA9IE1hdGguY29zKCB0aGV0YSApLCBzID0gTWF0aC5zaW4oIHRoZXRhICk7XHJcblxyXG5cdFx0dGhpcy5zZXQoXHJcblxyXG5cdFx0XHRjLCAtIHMsIDAsIDAsXHJcblx0XHRcdHMsIGMsIDAsIDAsXHJcblx0XHRcdDAsIDAsIDEsIDAsXHJcblx0XHRcdDAsIDAsIDAsIDFcclxuXHJcblx0XHQpO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdG1ha2VSb3RhdGlvbkF4aXMoIGF4aXMsIGFuZ2xlICkge1xyXG5cclxuXHRcdC8vIEJhc2VkIG9uIGh0dHA6Ly93d3cuZ2FtZWRldi5uZXQvcmVmZXJlbmNlL2FydGljbGVzL2FydGljbGUxMTk5LmFzcFxyXG5cclxuXHRcdGNvbnN0IGMgPSBNYXRoLmNvcyggYW5nbGUgKTtcclxuXHRcdGNvbnN0IHMgPSBNYXRoLnNpbiggYW5nbGUgKTtcclxuXHRcdGNvbnN0IHQgPSAxIC0gYztcclxuXHRcdGNvbnN0IHggPSBheGlzLngsIHkgPSBheGlzLnksIHogPSBheGlzLno7XHJcblx0XHRjb25zdCB0eCA9IHQgKiB4LCB0eSA9IHQgKiB5O1xyXG5cclxuXHRcdHRoaXMuc2V0KFxyXG5cclxuXHRcdFx0dHggKiB4ICsgYywgdHggKiB5IC0gcyAqIHosIHR4ICogeiArIHMgKiB5LCAwLFxyXG5cdFx0XHR0eCAqIHkgKyBzICogeiwgdHkgKiB5ICsgYywgdHkgKiB6IC0gcyAqIHgsIDAsXHJcblx0XHRcdHR4ICogeiAtIHMgKiB5LCB0eSAqIHogKyBzICogeCwgdCAqIHogKiB6ICsgYywgMCxcclxuXHRcdFx0MCwgMCwgMCwgMVxyXG5cclxuXHRcdCk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0bWFrZVNjYWxlKCB4LCB5LCB6ICkge1xyXG5cclxuXHRcdHRoaXMuc2V0KFxyXG5cclxuXHRcdFx0eCwgMCwgMCwgMCxcclxuXHRcdFx0MCwgeSwgMCwgMCxcclxuXHRcdFx0MCwgMCwgeiwgMCxcclxuXHRcdFx0MCwgMCwgMCwgMVxyXG5cclxuXHRcdCk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0bWFrZVNoZWFyKCB4eSwgeHosIHl4LCB5eiwgengsIHp5ICkge1xyXG5cclxuXHRcdHRoaXMuc2V0KFxyXG5cclxuXHRcdFx0MSwgeXgsIHp4LCAwLFxyXG5cdFx0XHR4eSwgMSwgenksIDAsXHJcblx0XHRcdHh6LCB5eiwgMSwgMCxcclxuXHRcdFx0MCwgMCwgMCwgMVxyXG5cclxuXHRcdCk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Y29tcG9zZSggcG9zaXRpb24sIHF1YXRlcm5pb24sIHNjYWxlICkge1xyXG5cclxuXHRcdGNvbnN0IHRlID0gdGhpcy5lbGVtZW50cztcclxuXHJcblx0XHRjb25zdCB4ID0gcXVhdGVybmlvbi5feCwgeSA9IHF1YXRlcm5pb24uX3ksIHogPSBxdWF0ZXJuaW9uLl96LCB3ID0gcXVhdGVybmlvbi5fdztcclxuXHRcdGNvbnN0IHgyID0geCArIHgsXHR5MiA9IHkgKyB5LCB6MiA9IHogKyB6O1xyXG5cdFx0Y29uc3QgeHggPSB4ICogeDIsIHh5ID0geCAqIHkyLCB4eiA9IHggKiB6MjtcclxuXHRcdGNvbnN0IHl5ID0geSAqIHkyLCB5eiA9IHkgKiB6MiwgenogPSB6ICogejI7XHJcblx0XHRjb25zdCB3eCA9IHcgKiB4Miwgd3kgPSB3ICogeTIsIHd6ID0gdyAqIHoyO1xyXG5cclxuXHRcdGNvbnN0IHN4ID0gc2NhbGUueCwgc3kgPSBzY2FsZS55LCBzeiA9IHNjYWxlLno7XHJcblxyXG5cdFx0dGVbIDAgXSA9ICggMSAtICggeXkgKyB6eiApICkgKiBzeDtcclxuXHRcdHRlWyAxIF0gPSAoIHh5ICsgd3ogKSAqIHN4O1xyXG5cdFx0dGVbIDIgXSA9ICggeHogLSB3eSApICogc3g7XHJcblx0XHR0ZVsgMyBdID0gMDtcclxuXHJcblx0XHR0ZVsgNCBdID0gKCB4eSAtIHd6ICkgKiBzeTtcclxuXHRcdHRlWyA1IF0gPSAoIDEgLSAoIHh4ICsgenogKSApICogc3k7XHJcblx0XHR0ZVsgNiBdID0gKCB5eiArIHd4ICkgKiBzeTtcclxuXHRcdHRlWyA3IF0gPSAwO1xyXG5cclxuXHRcdHRlWyA4IF0gPSAoIHh6ICsgd3kgKSAqIHN6O1xyXG5cdFx0dGVbIDkgXSA9ICggeXogLSB3eCApICogc3o7XHJcblx0XHR0ZVsgMTAgXSA9ICggMSAtICggeHggKyB5eSApICkgKiBzejtcclxuXHRcdHRlWyAxMSBdID0gMDtcclxuXHJcblx0XHR0ZVsgMTIgXSA9IHBvc2l0aW9uLng7XHJcblx0XHR0ZVsgMTMgXSA9IHBvc2l0aW9uLnk7XHJcblx0XHR0ZVsgMTQgXSA9IHBvc2l0aW9uLno7XHJcblx0XHR0ZVsgMTUgXSA9IDE7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0ZGVjb21wb3NlKCBwb3NpdGlvbiwgcXVhdGVybmlvbiwgc2NhbGUgKSB7XHJcblxyXG5cdFx0Y29uc3QgdGUgPSB0aGlzLmVsZW1lbnRzO1xyXG5cclxuXHRcdGxldCBzeCA9IF92MS5zZXQoIHRlWyAwIF0sIHRlWyAxIF0sIHRlWyAyIF0gKS5sZW5ndGgoKTtcclxuXHRcdGNvbnN0IHN5ID0gX3YxLnNldCggdGVbIDQgXSwgdGVbIDUgXSwgdGVbIDYgXSApLmxlbmd0aCgpO1xyXG5cdFx0Y29uc3Qgc3ogPSBfdjEuc2V0KCB0ZVsgOCBdLCB0ZVsgOSBdLCB0ZVsgMTAgXSApLmxlbmd0aCgpO1xyXG5cclxuXHRcdC8vIGlmIGRldGVybWluZSBpcyBuZWdhdGl2ZSwgd2UgbmVlZCB0byBpbnZlcnQgb25lIHNjYWxlXHJcblx0XHRjb25zdCBkZXQgPSB0aGlzLmRldGVybWluYW50KCk7XHJcblx0XHRpZiAoIGRldCA8IDAgKSBzeCA9IC0gc3g7XHJcblxyXG5cdFx0cG9zaXRpb24ueCA9IHRlWyAxMiBdO1xyXG5cdFx0cG9zaXRpb24ueSA9IHRlWyAxMyBdO1xyXG5cdFx0cG9zaXRpb24ueiA9IHRlWyAxNCBdO1xyXG5cclxuXHRcdC8vIHNjYWxlIHRoZSByb3RhdGlvbiBwYXJ0XHJcblx0XHRfbTEuY29weSggdGhpcyApO1xyXG5cclxuXHRcdGNvbnN0IGludlNYID0gMSAvIHN4O1xyXG5cdFx0Y29uc3QgaW52U1kgPSAxIC8gc3k7XHJcblx0XHRjb25zdCBpbnZTWiA9IDEgLyBzejtcclxuXHJcblx0XHRfbTEuZWxlbWVudHNbIDAgXSAqPSBpbnZTWDtcclxuXHRcdF9tMS5lbGVtZW50c1sgMSBdICo9IGludlNYO1xyXG5cdFx0X20xLmVsZW1lbnRzWyAyIF0gKj0gaW52U1g7XHJcblxyXG5cdFx0X20xLmVsZW1lbnRzWyA0IF0gKj0gaW52U1k7XHJcblx0XHRfbTEuZWxlbWVudHNbIDUgXSAqPSBpbnZTWTtcclxuXHRcdF9tMS5lbGVtZW50c1sgNiBdICo9IGludlNZO1xyXG5cclxuXHRcdF9tMS5lbGVtZW50c1sgOCBdICo9IGludlNaO1xyXG5cdFx0X20xLmVsZW1lbnRzWyA5IF0gKj0gaW52U1o7XHJcblx0XHRfbTEuZWxlbWVudHNbIDEwIF0gKj0gaW52U1o7XHJcblxyXG5cdFx0cXVhdGVybmlvbi5zZXRGcm9tUm90YXRpb25NYXRyaXgoIF9tMSApO1xyXG5cclxuXHRcdHNjYWxlLnggPSBzeDtcclxuXHRcdHNjYWxlLnkgPSBzeTtcclxuXHRcdHNjYWxlLnogPSBzejtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRtYWtlUGVyc3BlY3RpdmUoIGxlZnQsIHJpZ2h0LCB0b3AsIGJvdHRvbSwgbmVhciwgZmFyLCBjb29yZGluYXRlU3lzdGVtID0gV2ViR0xDb29yZGluYXRlU3lzdGVtICkge1xyXG5cclxuXHRcdGNvbnN0IHRlID0gdGhpcy5lbGVtZW50cztcclxuXHRcdGNvbnN0IHggPSAyICogbmVhciAvICggcmlnaHQgLSBsZWZ0ICk7XHJcblx0XHRjb25zdCB5ID0gMiAqIG5lYXIgLyAoIHRvcCAtIGJvdHRvbSApO1xyXG5cclxuXHRcdGNvbnN0IGEgPSAoIHJpZ2h0ICsgbGVmdCApIC8gKCByaWdodCAtIGxlZnQgKTtcclxuXHRcdGNvbnN0IGIgPSAoIHRvcCArIGJvdHRvbSApIC8gKCB0b3AgLSBib3R0b20gKTtcclxuXHJcblx0XHRsZXQgYywgZDtcclxuXHJcblx0XHRpZiAoIGNvb3JkaW5hdGVTeXN0ZW0gPT09IFdlYkdMQ29vcmRpbmF0ZVN5c3RlbSApIHtcclxuXHJcblx0XHRcdGMgPSAtICggZmFyICsgbmVhciApIC8gKCBmYXIgLSBuZWFyICk7XHJcblx0XHRcdGQgPSAoIC0gMiAqIGZhciAqIG5lYXIgKSAvICggZmFyIC0gbmVhciApO1xyXG5cclxuXHRcdH0gZWxzZSBpZiAoIGNvb3JkaW5hdGVTeXN0ZW0gPT09IFdlYkdQVUNvb3JkaW5hdGVTeXN0ZW0gKSB7XHJcblxyXG5cdFx0XHRjID0gLSBmYXIgLyAoIGZhciAtIG5lYXIgKTtcclxuXHRcdFx0ZCA9ICggLSBmYXIgKiBuZWFyICkgLyAoIGZhciAtIG5lYXIgKTtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0dGhyb3cgbmV3IEVycm9yKCAnVEhSRUUuTWF0cml4NC5tYWtlUGVyc3BlY3RpdmUoKTogSW52YWxpZCBjb29yZGluYXRlIHN5c3RlbTogJyArIGNvb3JkaW5hdGVTeXN0ZW0gKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGVbIDAgXSA9IHg7XHR0ZVsgNCBdID0gMDtcdHRlWyA4IF0gPSBhOyBcdHRlWyAxMiBdID0gMDtcclxuXHRcdHRlWyAxIF0gPSAwO1x0dGVbIDUgXSA9IHk7XHR0ZVsgOSBdID0gYjsgXHR0ZVsgMTMgXSA9IDA7XHJcblx0XHR0ZVsgMiBdID0gMDtcdHRlWyA2IF0gPSAwO1x0dGVbIDEwIF0gPSBjOyBcdHRlWyAxNCBdID0gZDtcclxuXHRcdHRlWyAzIF0gPSAwO1x0dGVbIDcgXSA9IDA7XHR0ZVsgMTEgXSA9IC0gMTtcdHRlWyAxNSBdID0gMDtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRtYWtlT3J0aG9ncmFwaGljKCBsZWZ0LCByaWdodCwgdG9wLCBib3R0b20sIG5lYXIsIGZhciwgY29vcmRpbmF0ZVN5c3RlbSA9IFdlYkdMQ29vcmRpbmF0ZVN5c3RlbSApIHtcclxuXHJcblx0XHRjb25zdCB0ZSA9IHRoaXMuZWxlbWVudHM7XHJcblx0XHRjb25zdCB3ID0gMS4wIC8gKCByaWdodCAtIGxlZnQgKTtcclxuXHRcdGNvbnN0IGggPSAxLjAgLyAoIHRvcCAtIGJvdHRvbSApO1xyXG5cdFx0Y29uc3QgcCA9IDEuMCAvICggZmFyIC0gbmVhciApO1xyXG5cclxuXHRcdGNvbnN0IHggPSAoIHJpZ2h0ICsgbGVmdCApICogdztcclxuXHRcdGNvbnN0IHkgPSAoIHRvcCArIGJvdHRvbSApICogaDtcclxuXHJcblx0XHRsZXQgeiwgekludjtcclxuXHJcblx0XHRpZiAoIGNvb3JkaW5hdGVTeXN0ZW0gPT09IFdlYkdMQ29vcmRpbmF0ZVN5c3RlbSApIHtcclxuXHJcblx0XHRcdHogPSAoIGZhciArIG5lYXIgKSAqIHA7XHJcblx0XHRcdHpJbnYgPSAtIDIgKiBwO1xyXG5cclxuXHRcdH0gZWxzZSBpZiAoIGNvb3JkaW5hdGVTeXN0ZW0gPT09IFdlYkdQVUNvb3JkaW5hdGVTeXN0ZW0gKSB7XHJcblxyXG5cdFx0XHR6ID0gbmVhciAqIHA7XHJcblx0XHRcdHpJbnYgPSAtIDEgKiBwO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHR0aHJvdyBuZXcgRXJyb3IoICdUSFJFRS5NYXRyaXg0Lm1ha2VPcnRob2dyYXBoaWMoKTogSW52YWxpZCBjb29yZGluYXRlIHN5c3RlbTogJyArIGNvb3JkaW5hdGVTeXN0ZW0gKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGVbIDAgXSA9IDIgKiB3O1x0dGVbIDQgXSA9IDA7XHRcdHRlWyA4IF0gPSAwOyBcdFx0dGVbIDEyIF0gPSAtIHg7XHJcblx0XHR0ZVsgMSBdID0gMDsgXHRcdHRlWyA1IF0gPSAyICogaDtcdHRlWyA5IF0gPSAwOyBcdFx0dGVbIDEzIF0gPSAtIHk7XHJcblx0XHR0ZVsgMiBdID0gMDsgXHRcdHRlWyA2IF0gPSAwO1x0XHR0ZVsgMTAgXSA9IHpJbnY7XHR0ZVsgMTQgXSA9IC0gejtcclxuXHRcdHRlWyAzIF0gPSAwOyBcdFx0dGVbIDcgXSA9IDA7XHRcdHRlWyAxMSBdID0gMDtcdFx0dGVbIDE1IF0gPSAxO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGVxdWFscyggbWF0cml4ICkge1xyXG5cclxuXHRcdGNvbnN0IHRlID0gdGhpcy5lbGVtZW50cztcclxuXHRcdGNvbnN0IG1lID0gbWF0cml4LmVsZW1lbnRzO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IDE2OyBpICsrICkge1xyXG5cclxuXHRcdFx0aWYgKCB0ZVsgaSBdICE9PSBtZVsgaSBdICkgcmV0dXJuIGZhbHNlO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdHJ1ZTtcclxuXHJcblx0fVxyXG5cclxuXHRmcm9tQXJyYXkoIGFycmF5LCBvZmZzZXQgPSAwICkge1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IDE2OyBpICsrICkge1xyXG5cclxuXHRcdFx0dGhpcy5lbGVtZW50c1sgaSBdID0gYXJyYXlbIGkgKyBvZmZzZXQgXTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0dG9BcnJheSggYXJyYXkgPSBbXSwgb2Zmc2V0ID0gMCApIHtcclxuXHJcblx0XHRjb25zdCB0ZSA9IHRoaXMuZWxlbWVudHM7XHJcblxyXG5cdFx0YXJyYXlbIG9mZnNldCBdID0gdGVbIDAgXTtcclxuXHRcdGFycmF5WyBvZmZzZXQgKyAxIF0gPSB0ZVsgMSBdO1xyXG5cdFx0YXJyYXlbIG9mZnNldCArIDIgXSA9IHRlWyAyIF07XHJcblx0XHRhcnJheVsgb2Zmc2V0ICsgMyBdID0gdGVbIDMgXTtcclxuXHJcblx0XHRhcnJheVsgb2Zmc2V0ICsgNCBdID0gdGVbIDQgXTtcclxuXHRcdGFycmF5WyBvZmZzZXQgKyA1IF0gPSB0ZVsgNSBdO1xyXG5cdFx0YXJyYXlbIG9mZnNldCArIDYgXSA9IHRlWyA2IF07XHJcblx0XHRhcnJheVsgb2Zmc2V0ICsgNyBdID0gdGVbIDcgXTtcclxuXHJcblx0XHRhcnJheVsgb2Zmc2V0ICsgOCBdID0gdGVbIDggXTtcclxuXHRcdGFycmF5WyBvZmZzZXQgKyA5IF0gPSB0ZVsgOSBdO1xyXG5cdFx0YXJyYXlbIG9mZnNldCArIDEwIF0gPSB0ZVsgMTAgXTtcclxuXHRcdGFycmF5WyBvZmZzZXQgKyAxMSBdID0gdGVbIDExIF07XHJcblxyXG5cdFx0YXJyYXlbIG9mZnNldCArIDEyIF0gPSB0ZVsgMTIgXTtcclxuXHRcdGFycmF5WyBvZmZzZXQgKyAxMyBdID0gdGVbIDEzIF07XHJcblx0XHRhcnJheVsgb2Zmc2V0ICsgMTQgXSA9IHRlWyAxNCBdO1xyXG5cdFx0YXJyYXlbIG9mZnNldCArIDE1IF0gPSB0ZVsgMTUgXTtcclxuXHJcblx0XHRyZXR1cm4gYXJyYXk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmNvbnN0IF92MSA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuY29uc3QgX20xID0gLypAX19QVVJFX18qLyBuZXcgTWF0cml4NCgpO1xyXG5jb25zdCBfemVybyA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoIDAsIDAsIDAgKTtcclxuY29uc3QgX29uZSA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoIDEsIDEsIDEgKTtcclxuY29uc3QgX3ggPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XHJcbmNvbnN0IF95ID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5jb25zdCBfeiA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuXHJcbmV4cG9ydCB7IE1hdHJpeDQgfTtcclxuIiwiaW1wb3J0IHsgUXVhdGVybmlvbiB9IGZyb20gJy4vUXVhdGVybmlvbi5qcyc7XHJcbmltcG9ydCB7IE1hdHJpeDQgfSBmcm9tICcuL01hdHJpeDQuanMnO1xyXG5pbXBvcnQgeyBjbGFtcCB9IGZyb20gJy4vTWF0aFV0aWxzLmpzJztcclxuXHJcbmNvbnN0IF9tYXRyaXggPSAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXg0KCk7XHJcbmNvbnN0IF9xdWF0ZXJuaW9uID0gLypAX19QVVJFX18qLyBuZXcgUXVhdGVybmlvbigpO1xyXG5cclxuY2xhc3MgRXVsZXIge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggeCA9IDAsIHkgPSAwLCB6ID0gMCwgb3JkZXIgPSBFdWxlci5ERUZBVUxUX09SREVSICkge1xyXG5cclxuXHRcdHRoaXMuaXNFdWxlciA9IHRydWU7XHJcblxyXG5cdFx0dGhpcy5feCA9IHg7XHJcblx0XHR0aGlzLl95ID0geTtcclxuXHRcdHRoaXMuX3ogPSB6O1xyXG5cdFx0dGhpcy5fb3JkZXIgPSBvcmRlcjtcclxuXHJcblx0fVxyXG5cclxuXHRnZXQgeCgpIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5feDtcclxuXHJcblx0fVxyXG5cclxuXHRzZXQgeCggdmFsdWUgKSB7XHJcblxyXG5cdFx0dGhpcy5feCA9IHZhbHVlO1xyXG5cdFx0dGhpcy5fb25DaGFuZ2VDYWxsYmFjaygpO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldCB5KCkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLl95O1xyXG5cclxuXHR9XHJcblxyXG5cdHNldCB5KCB2YWx1ZSApIHtcclxuXHJcblx0XHR0aGlzLl95ID0gdmFsdWU7XHJcblx0XHR0aGlzLl9vbkNoYW5nZUNhbGxiYWNrKCk7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0IHooKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuX3o7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0IHooIHZhbHVlICkge1xyXG5cclxuXHRcdHRoaXMuX3ogPSB2YWx1ZTtcclxuXHRcdHRoaXMuX29uQ2hhbmdlQ2FsbGJhY2soKTtcclxuXHJcblx0fVxyXG5cclxuXHRnZXQgb3JkZXIoKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuX29yZGVyO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldCBvcmRlciggdmFsdWUgKSB7XHJcblxyXG5cdFx0dGhpcy5fb3JkZXIgPSB2YWx1ZTtcclxuXHRcdHRoaXMuX29uQ2hhbmdlQ2FsbGJhY2soKTtcclxuXHJcblx0fVxyXG5cclxuXHRzZXQoIHgsIHksIHosIG9yZGVyID0gdGhpcy5fb3JkZXIgKSB7XHJcblxyXG5cdFx0dGhpcy5feCA9IHg7XHJcblx0XHR0aGlzLl95ID0geTtcclxuXHRcdHRoaXMuX3ogPSB6O1xyXG5cdFx0dGhpcy5fb3JkZXIgPSBvcmRlcjtcclxuXHJcblx0XHR0aGlzLl9vbkNoYW5nZUNhbGxiYWNrKCk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Y2xvbmUoKSB7XHJcblxyXG5cdFx0cmV0dXJuIG5ldyB0aGlzLmNvbnN0cnVjdG9yKCB0aGlzLl94LCB0aGlzLl95LCB0aGlzLl96LCB0aGlzLl9vcmRlciApO1xyXG5cclxuXHR9XHJcblxyXG5cdGNvcHkoIGV1bGVyICkge1xyXG5cclxuXHRcdHRoaXMuX3ggPSBldWxlci5feDtcclxuXHRcdHRoaXMuX3kgPSBldWxlci5feTtcclxuXHRcdHRoaXMuX3ogPSBldWxlci5fejtcclxuXHRcdHRoaXMuX29yZGVyID0gZXVsZXIuX29yZGVyO1xyXG5cclxuXHRcdHRoaXMuX29uQ2hhbmdlQ2FsbGJhY2soKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRGcm9tUm90YXRpb25NYXRyaXgoIG0sIG9yZGVyID0gdGhpcy5fb3JkZXIsIHVwZGF0ZSA9IHRydWUgKSB7XHJcblxyXG5cdFx0Ly8gYXNzdW1lcyB0aGUgdXBwZXIgM3gzIG9mIG0gaXMgYSBwdXJlIHJvdGF0aW9uIG1hdHJpeCAoaS5lLCB1bnNjYWxlZClcclxuXHJcblx0XHRjb25zdCB0ZSA9IG0uZWxlbWVudHM7XHJcblx0XHRjb25zdCBtMTEgPSB0ZVsgMCBdLCBtMTIgPSB0ZVsgNCBdLCBtMTMgPSB0ZVsgOCBdO1xyXG5cdFx0Y29uc3QgbTIxID0gdGVbIDEgXSwgbTIyID0gdGVbIDUgXSwgbTIzID0gdGVbIDkgXTtcclxuXHRcdGNvbnN0IG0zMSA9IHRlWyAyIF0sIG0zMiA9IHRlWyA2IF0sIG0zMyA9IHRlWyAxMCBdO1xyXG5cclxuXHRcdHN3aXRjaCAoIG9yZGVyICkge1xyXG5cclxuXHRcdFx0Y2FzZSAnWFlaJzpcclxuXHJcblx0XHRcdFx0dGhpcy5feSA9IE1hdGguYXNpbiggY2xhbXAoIG0xMywgLSAxLCAxICkgKTtcclxuXHJcblx0XHRcdFx0aWYgKCBNYXRoLmFicyggbTEzICkgPCAwLjk5OTk5OTkgKSB7XHJcblxyXG5cdFx0XHRcdFx0dGhpcy5feCA9IE1hdGguYXRhbjIoIC0gbTIzLCBtMzMgKTtcclxuXHRcdFx0XHRcdHRoaXMuX3ogPSBNYXRoLmF0YW4yKCAtIG0xMiwgbTExICk7XHJcblxyXG5cdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0dGhpcy5feCA9IE1hdGguYXRhbjIoIG0zMiwgbTIyICk7XHJcblx0XHRcdFx0XHR0aGlzLl96ID0gMDtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdGNhc2UgJ1lYWic6XHJcblxyXG5cdFx0XHRcdHRoaXMuX3ggPSBNYXRoLmFzaW4oIC0gY2xhbXAoIG0yMywgLSAxLCAxICkgKTtcclxuXHJcblx0XHRcdFx0aWYgKCBNYXRoLmFicyggbTIzICkgPCAwLjk5OTk5OTkgKSB7XHJcblxyXG5cdFx0XHRcdFx0dGhpcy5feSA9IE1hdGguYXRhbjIoIG0xMywgbTMzICk7XHJcblx0XHRcdFx0XHR0aGlzLl96ID0gTWF0aC5hdGFuMiggbTIxLCBtMjIgKTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHR0aGlzLl95ID0gTWF0aC5hdGFuMiggLSBtMzEsIG0xMSApO1xyXG5cdFx0XHRcdFx0dGhpcy5feiA9IDA7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRjYXNlICdaWFknOlxyXG5cclxuXHRcdFx0XHR0aGlzLl94ID0gTWF0aC5hc2luKCBjbGFtcCggbTMyLCAtIDEsIDEgKSApO1xyXG5cclxuXHRcdFx0XHRpZiAoIE1hdGguYWJzKCBtMzIgKSA8IDAuOTk5OTk5OSApIHtcclxuXHJcblx0XHRcdFx0XHR0aGlzLl95ID0gTWF0aC5hdGFuMiggLSBtMzEsIG0zMyApO1xyXG5cdFx0XHRcdFx0dGhpcy5feiA9IE1hdGguYXRhbjIoIC0gbTEyLCBtMjIgKTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHR0aGlzLl95ID0gMDtcclxuXHRcdFx0XHRcdHRoaXMuX3ogPSBNYXRoLmF0YW4yKCBtMjEsIG0xMSApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0Y2FzZSAnWllYJzpcclxuXHJcblx0XHRcdFx0dGhpcy5feSA9IE1hdGguYXNpbiggLSBjbGFtcCggbTMxLCAtIDEsIDEgKSApO1xyXG5cclxuXHRcdFx0XHRpZiAoIE1hdGguYWJzKCBtMzEgKSA8IDAuOTk5OTk5OSApIHtcclxuXHJcblx0XHRcdFx0XHR0aGlzLl94ID0gTWF0aC5hdGFuMiggbTMyLCBtMzMgKTtcclxuXHRcdFx0XHRcdHRoaXMuX3ogPSBNYXRoLmF0YW4yKCBtMjEsIG0xMSApO1xyXG5cclxuXHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdHRoaXMuX3ggPSAwO1xyXG5cdFx0XHRcdFx0dGhpcy5feiA9IE1hdGguYXRhbjIoIC0gbTEyLCBtMjIgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdGNhc2UgJ1laWCc6XHJcblxyXG5cdFx0XHRcdHRoaXMuX3ogPSBNYXRoLmFzaW4oIGNsYW1wKCBtMjEsIC0gMSwgMSApICk7XHJcblxyXG5cdFx0XHRcdGlmICggTWF0aC5hYnMoIG0yMSApIDwgMC45OTk5OTk5ICkge1xyXG5cclxuXHRcdFx0XHRcdHRoaXMuX3ggPSBNYXRoLmF0YW4yKCAtIG0yMywgbTIyICk7XHJcblx0XHRcdFx0XHR0aGlzLl95ID0gTWF0aC5hdGFuMiggLSBtMzEsIG0xMSApO1xyXG5cclxuXHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdHRoaXMuX3ggPSAwO1xyXG5cdFx0XHRcdFx0dGhpcy5feSA9IE1hdGguYXRhbjIoIG0xMywgbTMzICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRjYXNlICdYWlknOlxyXG5cclxuXHRcdFx0XHR0aGlzLl96ID0gTWF0aC5hc2luKCAtIGNsYW1wKCBtMTIsIC0gMSwgMSApICk7XHJcblxyXG5cdFx0XHRcdGlmICggTWF0aC5hYnMoIG0xMiApIDwgMC45OTk5OTk5ICkge1xyXG5cclxuXHRcdFx0XHRcdHRoaXMuX3ggPSBNYXRoLmF0YW4yKCBtMzIsIG0yMiApO1xyXG5cdFx0XHRcdFx0dGhpcy5feSA9IE1hdGguYXRhbjIoIG0xMywgbTExICk7XHJcblxyXG5cdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0dGhpcy5feCA9IE1hdGguYXRhbjIoIC0gbTIzLCBtMzMgKTtcclxuXHRcdFx0XHRcdHRoaXMuX3kgPSAwO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0ZGVmYXVsdDpcclxuXHJcblx0XHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuRXVsZXI6IC5zZXRGcm9tUm90YXRpb25NYXRyaXgoKSBlbmNvdW50ZXJlZCBhbiB1bmtub3duIG9yZGVyOiAnICsgb3JkZXIgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5fb3JkZXIgPSBvcmRlcjtcclxuXHJcblx0XHRpZiAoIHVwZGF0ZSA9PT0gdHJ1ZSApIHRoaXMuX29uQ2hhbmdlQ2FsbGJhY2soKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRGcm9tUXVhdGVybmlvbiggcSwgb3JkZXIsIHVwZGF0ZSApIHtcclxuXHJcblx0XHRfbWF0cml4Lm1ha2VSb3RhdGlvbkZyb21RdWF0ZXJuaW9uKCBxICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuc2V0RnJvbVJvdGF0aW9uTWF0cml4KCBfbWF0cml4LCBvcmRlciwgdXBkYXRlICk7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0RnJvbVZlY3RvcjMoIHYsIG9yZGVyID0gdGhpcy5fb3JkZXIgKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuc2V0KCB2LngsIHYueSwgdi56LCBvcmRlciApO1xyXG5cclxuXHR9XHJcblxyXG5cdHJlb3JkZXIoIG5ld09yZGVyICkge1xyXG5cclxuXHRcdC8vIFdBUk5JTkc6IHRoaXMgZGlzY2FyZHMgcmV2b2x1dGlvbiBpbmZvcm1hdGlvbiAtYmhvdXN0b25cclxuXHJcblx0XHRfcXVhdGVybmlvbi5zZXRGcm9tRXVsZXIoIHRoaXMgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5zZXRGcm9tUXVhdGVybmlvbiggX3F1YXRlcm5pb24sIG5ld09yZGVyICk7XHJcblxyXG5cdH1cclxuXHJcblx0ZXF1YWxzKCBldWxlciApIHtcclxuXHJcblx0XHRyZXR1cm4gKCBldWxlci5feCA9PT0gdGhpcy5feCApICYmICggZXVsZXIuX3kgPT09IHRoaXMuX3kgKSAmJiAoIGV1bGVyLl96ID09PSB0aGlzLl96ICkgJiYgKCBldWxlci5fb3JkZXIgPT09IHRoaXMuX29yZGVyICk7XHJcblxyXG5cdH1cclxuXHJcblx0ZnJvbUFycmF5KCBhcnJheSApIHtcclxuXHJcblx0XHR0aGlzLl94ID0gYXJyYXlbIDAgXTtcclxuXHRcdHRoaXMuX3kgPSBhcnJheVsgMSBdO1xyXG5cdFx0dGhpcy5feiA9IGFycmF5WyAyIF07XHJcblx0XHRpZiAoIGFycmF5WyAzIF0gIT09IHVuZGVmaW5lZCApIHRoaXMuX29yZGVyID0gYXJyYXlbIDMgXTtcclxuXHJcblx0XHR0aGlzLl9vbkNoYW5nZUNhbGxiYWNrKCk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0dG9BcnJheSggYXJyYXkgPSBbXSwgb2Zmc2V0ID0gMCApIHtcclxuXHJcblx0XHRhcnJheVsgb2Zmc2V0IF0gPSB0aGlzLl94O1xyXG5cdFx0YXJyYXlbIG9mZnNldCArIDEgXSA9IHRoaXMuX3k7XHJcblx0XHRhcnJheVsgb2Zmc2V0ICsgMiBdID0gdGhpcy5fejtcclxuXHRcdGFycmF5WyBvZmZzZXQgKyAzIF0gPSB0aGlzLl9vcmRlcjtcclxuXHJcblx0XHRyZXR1cm4gYXJyYXk7XHJcblxyXG5cdH1cclxuXHJcblx0X29uQ2hhbmdlKCBjYWxsYmFjayApIHtcclxuXHJcblx0XHR0aGlzLl9vbkNoYW5nZUNhbGxiYWNrID0gY2FsbGJhY2s7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0X29uQ2hhbmdlQ2FsbGJhY2soKSB7fVxyXG5cclxuXHQqWyBTeW1ib2wuaXRlcmF0b3IgXSgpIHtcclxuXHJcblx0XHR5aWVsZCB0aGlzLl94O1xyXG5cdFx0eWllbGQgdGhpcy5feTtcclxuXHRcdHlpZWxkIHRoaXMuX3o7XHJcblx0XHR5aWVsZCB0aGlzLl9vcmRlcjtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuRXVsZXIuREVGQVVMVF9PUkRFUiA9ICdYWVonO1xyXG5cclxuZXhwb3J0IHsgRXVsZXIgfTtcclxuIiwiY2xhc3MgTGF5ZXJzIHtcclxuXHJcblx0Y29uc3RydWN0b3IoKSB7XHJcblxyXG5cdFx0dGhpcy5tYXNrID0gMSB8IDA7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0KCBjaGFubmVsICkge1xyXG5cclxuXHRcdHRoaXMubWFzayA9ICggMSA8PCBjaGFubmVsIHwgMCApID4+PiAwO1xyXG5cclxuXHR9XHJcblxyXG5cdGVuYWJsZSggY2hhbm5lbCApIHtcclxuXHJcblx0XHR0aGlzLm1hc2sgfD0gMSA8PCBjaGFubmVsIHwgMDtcclxuXHJcblx0fVxyXG5cclxuXHRlbmFibGVBbGwoKSB7XHJcblxyXG5cdFx0dGhpcy5tYXNrID0gMHhmZmZmZmZmZiB8IDA7XHJcblxyXG5cdH1cclxuXHJcblx0dG9nZ2xlKCBjaGFubmVsICkge1xyXG5cclxuXHRcdHRoaXMubWFzayBePSAxIDw8IGNoYW5uZWwgfCAwO1xyXG5cclxuXHR9XHJcblxyXG5cdGRpc2FibGUoIGNoYW5uZWwgKSB7XHJcblxyXG5cdFx0dGhpcy5tYXNrICY9IH4gKCAxIDw8IGNoYW5uZWwgfCAwICk7XHJcblxyXG5cdH1cclxuXHJcblx0ZGlzYWJsZUFsbCgpIHtcclxuXHJcblx0XHR0aGlzLm1hc2sgPSAwO1xyXG5cclxuXHR9XHJcblxyXG5cdHRlc3QoIGxheWVycyApIHtcclxuXHJcblx0XHRyZXR1cm4gKCB0aGlzLm1hc2sgJiBsYXllcnMubWFzayApICE9PSAwO1xyXG5cclxuXHR9XHJcblxyXG5cdGlzRW5hYmxlZCggY2hhbm5lbCApIHtcclxuXHJcblx0XHRyZXR1cm4gKCB0aGlzLm1hc2sgJiAoIDEgPDwgY2hhbm5lbCB8IDAgKSApICE9PSAwO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5cclxuZXhwb3J0IHsgTGF5ZXJzIH07XHJcbiIsImltcG9ydCB7IFF1YXRlcm5pb24gfSBmcm9tICcuLi9tYXRoL1F1YXRlcm5pb24uanMnO1xyXG5pbXBvcnQgeyBWZWN0b3IzIH0gZnJvbSAnLi4vbWF0aC9WZWN0b3IzLmpzJztcclxuaW1wb3J0IHsgTWF0cml4NCB9IGZyb20gJy4uL21hdGgvTWF0cml4NC5qcyc7XHJcbmltcG9ydCB7IEV2ZW50RGlzcGF0Y2hlciB9IGZyb20gJy4vRXZlbnREaXNwYXRjaGVyLmpzJztcclxuaW1wb3J0IHsgRXVsZXIgfSBmcm9tICcuLi9tYXRoL0V1bGVyLmpzJztcclxuaW1wb3J0IHsgTGF5ZXJzIH0gZnJvbSAnLi9MYXllcnMuanMnO1xyXG5pbXBvcnQgeyBNYXRyaXgzIH0gZnJvbSAnLi4vbWF0aC9NYXRyaXgzLmpzJztcclxuaW1wb3J0ICogYXMgTWF0aFV0aWxzIGZyb20gJy4uL21hdGgvTWF0aFV0aWxzLmpzJztcclxuXHJcbmxldCBfb2JqZWN0M0RJZCA9IDA7XHJcblxyXG5jb25zdCBfdjEgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XHJcbmNvbnN0IF9xMSA9IC8qQF9fUFVSRV9fKi8gbmV3IFF1YXRlcm5pb24oKTtcclxuY29uc3QgX20xID0gLypAX19QVVJFX18qLyBuZXcgTWF0cml4NCgpO1xyXG5jb25zdCBfdGFyZ2V0ID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5cclxuY29uc3QgX3Bvc2l0aW9uID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5jb25zdCBfc2NhbGUgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XHJcbmNvbnN0IF9xdWF0ZXJuaW9uID0gLypAX19QVVJFX18qLyBuZXcgUXVhdGVybmlvbigpO1xyXG5cclxuY29uc3QgX3hBeGlzID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMyggMSwgMCwgMCApO1xyXG5jb25zdCBfeUF4aXMgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCAwLCAxLCAwICk7XHJcbmNvbnN0IF96QXhpcyA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoIDAsIDAsIDEgKTtcclxuXHJcbmNvbnN0IF9hZGRlZEV2ZW50ID0geyB0eXBlOiAnYWRkZWQnIH07XHJcbmNvbnN0IF9yZW1vdmVkRXZlbnQgPSB7IHR5cGU6ICdyZW1vdmVkJyB9O1xyXG5cclxuY2xhc3MgT2JqZWN0M0QgZXh0ZW5kcyBFdmVudERpc3BhdGNoZXIge1xyXG5cclxuXHRjb25zdHJ1Y3RvcigpIHtcclxuXHJcblx0XHRzdXBlcigpO1xyXG5cclxuXHRcdHRoaXMuaXNPYmplY3QzRCA9IHRydWU7XHJcblxyXG5cdFx0T2JqZWN0LmRlZmluZVByb3BlcnR5KCB0aGlzLCAnaWQnLCB7IHZhbHVlOiBfb2JqZWN0M0RJZCArKyB9ICk7XHJcblxyXG5cdFx0dGhpcy51dWlkID0gTWF0aFV0aWxzLmdlbmVyYXRlVVVJRCgpO1xyXG5cclxuXHRcdHRoaXMubmFtZSA9ICcnO1xyXG5cdFx0dGhpcy50eXBlID0gJ09iamVjdDNEJztcclxuXHJcblx0XHR0aGlzLnBhcmVudCA9IG51bGw7XHJcblx0XHR0aGlzLmNoaWxkcmVuID0gW107XHJcblxyXG5cdFx0dGhpcy51cCA9IE9iamVjdDNELkRFRkFVTFRfVVAuY2xvbmUoKTtcclxuXHJcblx0XHRjb25zdCBwb3NpdGlvbiA9IG5ldyBWZWN0b3IzKCk7XHJcblx0XHRjb25zdCByb3RhdGlvbiA9IG5ldyBFdWxlcigpO1xyXG5cdFx0Y29uc3QgcXVhdGVybmlvbiA9IG5ldyBRdWF0ZXJuaW9uKCk7XHJcblx0XHRjb25zdCBzY2FsZSA9IG5ldyBWZWN0b3IzKCAxLCAxLCAxICk7XHJcblxyXG5cdFx0ZnVuY3Rpb24gb25Sb3RhdGlvbkNoYW5nZSgpIHtcclxuXHJcblx0XHRcdHF1YXRlcm5pb24uc2V0RnJvbUV1bGVyKCByb3RhdGlvbiwgZmFsc2UgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0ZnVuY3Rpb24gb25RdWF0ZXJuaW9uQ2hhbmdlKCkge1xyXG5cclxuXHRcdFx0cm90YXRpb24uc2V0RnJvbVF1YXRlcm5pb24oIHF1YXRlcm5pb24sIHVuZGVmaW5lZCwgZmFsc2UgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cm90YXRpb24uX29uQ2hhbmdlKCBvblJvdGF0aW9uQ2hhbmdlICk7XHJcblx0XHRxdWF0ZXJuaW9uLl9vbkNoYW5nZSggb25RdWF0ZXJuaW9uQ2hhbmdlICk7XHJcblxyXG5cdFx0T2JqZWN0LmRlZmluZVByb3BlcnRpZXMoIHRoaXMsIHtcclxuXHRcdFx0cG9zaXRpb246IHtcclxuXHRcdFx0XHRjb25maWd1cmFibGU6IHRydWUsXHJcblx0XHRcdFx0ZW51bWVyYWJsZTogdHJ1ZSxcclxuXHRcdFx0XHR2YWx1ZTogcG9zaXRpb25cclxuXHRcdFx0fSxcclxuXHRcdFx0cm90YXRpb246IHtcclxuXHRcdFx0XHRjb25maWd1cmFibGU6IHRydWUsXHJcblx0XHRcdFx0ZW51bWVyYWJsZTogdHJ1ZSxcclxuXHRcdFx0XHR2YWx1ZTogcm90YXRpb25cclxuXHRcdFx0fSxcclxuXHRcdFx0cXVhdGVybmlvbjoge1xyXG5cdFx0XHRcdGNvbmZpZ3VyYWJsZTogdHJ1ZSxcclxuXHRcdFx0XHRlbnVtZXJhYmxlOiB0cnVlLFxyXG5cdFx0XHRcdHZhbHVlOiBxdWF0ZXJuaW9uXHJcblx0XHRcdH0sXHJcblx0XHRcdHNjYWxlOiB7XHJcblx0XHRcdFx0Y29uZmlndXJhYmxlOiB0cnVlLFxyXG5cdFx0XHRcdGVudW1lcmFibGU6IHRydWUsXHJcblx0XHRcdFx0dmFsdWU6IHNjYWxlXHJcblx0XHRcdH0sXHJcblx0XHRcdG1vZGVsVmlld01hdHJpeDoge1xyXG5cdFx0XHRcdHZhbHVlOiBuZXcgTWF0cml4NCgpXHJcblx0XHRcdH0sXHJcblx0XHRcdG5vcm1hbE1hdHJpeDoge1xyXG5cdFx0XHRcdHZhbHVlOiBuZXcgTWF0cml4MygpXHJcblx0XHRcdH1cclxuXHRcdH0gKTtcclxuXHJcblx0XHR0aGlzLm1hdHJpeCA9IG5ldyBNYXRyaXg0KCk7XHJcblx0XHR0aGlzLm1hdHJpeFdvcmxkID0gbmV3IE1hdHJpeDQoKTtcclxuXHJcblx0XHR0aGlzLm1hdHJpeEF1dG9VcGRhdGUgPSBPYmplY3QzRC5ERUZBVUxUX01BVFJJWF9BVVRPX1VQREFURTtcclxuXHJcblx0XHR0aGlzLm1hdHJpeFdvcmxkQXV0b1VwZGF0ZSA9IE9iamVjdDNELkRFRkFVTFRfTUFUUklYX1dPUkxEX0FVVE9fVVBEQVRFOyAvLyBjaGVja2VkIGJ5IHRoZSByZW5kZXJlclxyXG5cdFx0dGhpcy5tYXRyaXhXb3JsZE5lZWRzVXBkYXRlID0gZmFsc2U7XHJcblxyXG5cdFx0dGhpcy5sYXllcnMgPSBuZXcgTGF5ZXJzKCk7XHJcblx0XHR0aGlzLnZpc2libGUgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMuY2FzdFNoYWRvdyA9IGZhbHNlO1xyXG5cdFx0dGhpcy5yZWNlaXZlU2hhZG93ID0gZmFsc2U7XHJcblxyXG5cdFx0dGhpcy5mcnVzdHVtQ3VsbGVkID0gdHJ1ZTtcclxuXHRcdHRoaXMucmVuZGVyT3JkZXIgPSAwO1xyXG5cclxuXHRcdHRoaXMuYW5pbWF0aW9ucyA9IFtdO1xyXG5cclxuXHRcdHRoaXMudXNlckRhdGEgPSB7fTtcclxuXHJcblx0fVxyXG5cclxuXHRvbkJlZm9yZVNoYWRvdyggLyogcmVuZGVyZXIsIG9iamVjdCwgY2FtZXJhLCBzaGFkb3dDYW1lcmEsIGdlb21ldHJ5LCBkZXB0aE1hdGVyaWFsLCBncm91cCAqLyApIHt9XHJcblxyXG5cdG9uQWZ0ZXJTaGFkb3coIC8qIHJlbmRlcmVyLCBvYmplY3QsIGNhbWVyYSwgc2hhZG93Q2FtZXJhLCBnZW9tZXRyeSwgZGVwdGhNYXRlcmlhbCwgZ3JvdXAgKi8gKSB7fVxyXG5cclxuXHRvbkJlZm9yZVJlbmRlciggLyogcmVuZGVyZXIsIHNjZW5lLCBjYW1lcmEsIGdlb21ldHJ5LCBtYXRlcmlhbCwgZ3JvdXAgKi8gKSB7fVxyXG5cclxuXHRvbkFmdGVyUmVuZGVyKCAvKiByZW5kZXJlciwgc2NlbmUsIGNhbWVyYSwgZ2VvbWV0cnksIG1hdGVyaWFsLCBncm91cCAqLyApIHt9XHJcblxyXG5cdGFwcGx5TWF0cml4NCggbWF0cml4ICkge1xyXG5cclxuXHRcdGlmICggdGhpcy5tYXRyaXhBdXRvVXBkYXRlICkgdGhpcy51cGRhdGVNYXRyaXgoKTtcclxuXHJcblx0XHR0aGlzLm1hdHJpeC5wcmVtdWx0aXBseSggbWF0cml4ICk7XHJcblxyXG5cdFx0dGhpcy5tYXRyaXguZGVjb21wb3NlKCB0aGlzLnBvc2l0aW9uLCB0aGlzLnF1YXRlcm5pb24sIHRoaXMuc2NhbGUgKTtcclxuXHJcblx0fVxyXG5cclxuXHRhcHBseVF1YXRlcm5pb24oIHEgKSB7XHJcblxyXG5cdFx0dGhpcy5xdWF0ZXJuaW9uLnByZW11bHRpcGx5KCBxICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0Um90YXRpb25Gcm9tQXhpc0FuZ2xlKCBheGlzLCBhbmdsZSApIHtcclxuXHJcblx0XHQvLyBhc3N1bWVzIGF4aXMgaXMgbm9ybWFsaXplZFxyXG5cclxuXHRcdHRoaXMucXVhdGVybmlvbi5zZXRGcm9tQXhpc0FuZ2xlKCBheGlzLCBhbmdsZSApO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldFJvdGF0aW9uRnJvbUV1bGVyKCBldWxlciApIHtcclxuXHJcblx0XHR0aGlzLnF1YXRlcm5pb24uc2V0RnJvbUV1bGVyKCBldWxlciwgdHJ1ZSApO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldFJvdGF0aW9uRnJvbU1hdHJpeCggbSApIHtcclxuXHJcblx0XHQvLyBhc3N1bWVzIHRoZSB1cHBlciAzeDMgb2YgbSBpcyBhIHB1cmUgcm90YXRpb24gbWF0cml4IChpLmUsIHVuc2NhbGVkKVxyXG5cclxuXHRcdHRoaXMucXVhdGVybmlvbi5zZXRGcm9tUm90YXRpb25NYXRyaXgoIG0gKTtcclxuXHJcblx0fVxyXG5cclxuXHRzZXRSb3RhdGlvbkZyb21RdWF0ZXJuaW9uKCBxICkge1xyXG5cclxuXHRcdC8vIGFzc3VtZXMgcSBpcyBub3JtYWxpemVkXHJcblxyXG5cdFx0dGhpcy5xdWF0ZXJuaW9uLmNvcHkoIHEgKTtcclxuXHJcblx0fVxyXG5cclxuXHRyb3RhdGVPbkF4aXMoIGF4aXMsIGFuZ2xlICkge1xyXG5cclxuXHRcdC8vIHJvdGF0ZSBvYmplY3Qgb24gYXhpcyBpbiBvYmplY3Qgc3BhY2VcclxuXHRcdC8vIGF4aXMgaXMgYXNzdW1lZCB0byBiZSBub3JtYWxpemVkXHJcblxyXG5cdFx0X3ExLnNldEZyb21BeGlzQW5nbGUoIGF4aXMsIGFuZ2xlICk7XHJcblxyXG5cdFx0dGhpcy5xdWF0ZXJuaW9uLm11bHRpcGx5KCBfcTEgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRyb3RhdGVPbldvcmxkQXhpcyggYXhpcywgYW5nbGUgKSB7XHJcblxyXG5cdFx0Ly8gcm90YXRlIG9iamVjdCBvbiBheGlzIGluIHdvcmxkIHNwYWNlXHJcblx0XHQvLyBheGlzIGlzIGFzc3VtZWQgdG8gYmUgbm9ybWFsaXplZFxyXG5cdFx0Ly8gbWV0aG9kIGFzc3VtZXMgbm8gcm90YXRlZCBwYXJlbnRcclxuXHJcblx0XHRfcTEuc2V0RnJvbUF4aXNBbmdsZSggYXhpcywgYW5nbGUgKTtcclxuXHJcblx0XHR0aGlzLnF1YXRlcm5pb24ucHJlbXVsdGlwbHkoIF9xMSApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHJvdGF0ZVgoIGFuZ2xlICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLnJvdGF0ZU9uQXhpcyggX3hBeGlzLCBhbmdsZSApO1xyXG5cclxuXHR9XHJcblxyXG5cdHJvdGF0ZVkoIGFuZ2xlICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLnJvdGF0ZU9uQXhpcyggX3lBeGlzLCBhbmdsZSApO1xyXG5cclxuXHR9XHJcblxyXG5cdHJvdGF0ZVooIGFuZ2xlICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLnJvdGF0ZU9uQXhpcyggX3pBeGlzLCBhbmdsZSApO1xyXG5cclxuXHR9XHJcblxyXG5cdHRyYW5zbGF0ZU9uQXhpcyggYXhpcywgZGlzdGFuY2UgKSB7XHJcblxyXG5cdFx0Ly8gdHJhbnNsYXRlIG9iamVjdCBieSBkaXN0YW5jZSBhbG9uZyBheGlzIGluIG9iamVjdCBzcGFjZVxyXG5cdFx0Ly8gYXhpcyBpcyBhc3N1bWVkIHRvIGJlIG5vcm1hbGl6ZWRcclxuXHJcblx0XHRfdjEuY29weSggYXhpcyApLmFwcGx5UXVhdGVybmlvbiggdGhpcy5xdWF0ZXJuaW9uICk7XHJcblxyXG5cdFx0dGhpcy5wb3NpdGlvbi5hZGQoIF92MS5tdWx0aXBseVNjYWxhciggZGlzdGFuY2UgKSApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHRyYW5zbGF0ZVgoIGRpc3RhbmNlICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLnRyYW5zbGF0ZU9uQXhpcyggX3hBeGlzLCBkaXN0YW5jZSApO1xyXG5cclxuXHR9XHJcblxyXG5cdHRyYW5zbGF0ZVkoIGRpc3RhbmNlICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLnRyYW5zbGF0ZU9uQXhpcyggX3lBeGlzLCBkaXN0YW5jZSApO1xyXG5cclxuXHR9XHJcblxyXG5cdHRyYW5zbGF0ZVooIGRpc3RhbmNlICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLnRyYW5zbGF0ZU9uQXhpcyggX3pBeGlzLCBkaXN0YW5jZSApO1xyXG5cclxuXHR9XHJcblxyXG5cdGxvY2FsVG9Xb3JsZCggdmVjdG9yICkge1xyXG5cclxuXHRcdHRoaXMudXBkYXRlV29ybGRNYXRyaXgoIHRydWUsIGZhbHNlICk7XHJcblxyXG5cdFx0cmV0dXJuIHZlY3Rvci5hcHBseU1hdHJpeDQoIHRoaXMubWF0cml4V29ybGQgKTtcclxuXHJcblx0fVxyXG5cclxuXHR3b3JsZFRvTG9jYWwoIHZlY3RvciApIHtcclxuXHJcblx0XHR0aGlzLnVwZGF0ZVdvcmxkTWF0cml4KCB0cnVlLCBmYWxzZSApO1xyXG5cclxuXHRcdHJldHVybiB2ZWN0b3IuYXBwbHlNYXRyaXg0KCBfbTEuY29weSggdGhpcy5tYXRyaXhXb3JsZCApLmludmVydCgpICk7XHJcblxyXG5cdH1cclxuXHJcblx0bG9va0F0KCB4LCB5LCB6ICkge1xyXG5cclxuXHRcdC8vIFRoaXMgbWV0aG9kIGRvZXMgbm90IHN1cHBvcnQgb2JqZWN0cyBoYXZpbmcgbm9uLXVuaWZvcm1seS1zY2FsZWQgcGFyZW50KHMpXHJcblxyXG5cdFx0aWYgKCB4LmlzVmVjdG9yMyApIHtcclxuXHJcblx0XHRcdF90YXJnZXQuY29weSggeCApO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRfdGFyZ2V0LnNldCggeCwgeSwgeiApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCBwYXJlbnQgPSB0aGlzLnBhcmVudDtcclxuXHJcblx0XHR0aGlzLnVwZGF0ZVdvcmxkTWF0cml4KCB0cnVlLCBmYWxzZSApO1xyXG5cclxuXHRcdF9wb3NpdGlvbi5zZXRGcm9tTWF0cml4UG9zaXRpb24oIHRoaXMubWF0cml4V29ybGQgKTtcclxuXHJcblx0XHRpZiAoIHRoaXMuaXNDYW1lcmEgfHwgdGhpcy5pc0xpZ2h0ICkge1xyXG5cclxuXHRcdFx0X20xLmxvb2tBdCggX3Bvc2l0aW9uLCBfdGFyZ2V0LCB0aGlzLnVwICk7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdF9tMS5sb29rQXQoIF90YXJnZXQsIF9wb3NpdGlvbiwgdGhpcy51cCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLnF1YXRlcm5pb24uc2V0RnJvbVJvdGF0aW9uTWF0cml4KCBfbTEgKTtcclxuXHJcblx0XHRpZiAoIHBhcmVudCApIHtcclxuXHJcblx0XHRcdF9tMS5leHRyYWN0Um90YXRpb24oIHBhcmVudC5tYXRyaXhXb3JsZCApO1xyXG5cdFx0XHRfcTEuc2V0RnJvbVJvdGF0aW9uTWF0cml4KCBfbTEgKTtcclxuXHRcdFx0dGhpcy5xdWF0ZXJuaW9uLnByZW11bHRpcGx5KCBfcTEuaW52ZXJ0KCkgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0YWRkKCBvYmplY3QgKSB7XHJcblxyXG5cdFx0aWYgKCBhcmd1bWVudHMubGVuZ3RoID4gMSApIHtcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IGFyZ3VtZW50cy5sZW5ndGg7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdHRoaXMuYWRkKCBhcmd1bWVudHNbIGkgXSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggb2JqZWN0ID09PSB0aGlzICkge1xyXG5cclxuXHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLk9iamVjdDNELmFkZDogb2JqZWN0IGNhblxcJ3QgYmUgYWRkZWQgYXMgYSBjaGlsZCBvZiBpdHNlbGYuJywgb2JqZWN0ICk7XHJcblx0XHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIG9iamVjdCAmJiBvYmplY3QuaXNPYmplY3QzRCApIHtcclxuXHJcblx0XHRcdGlmICggb2JqZWN0LnBhcmVudCAhPT0gbnVsbCApIHtcclxuXHJcblx0XHRcdFx0b2JqZWN0LnBhcmVudC5yZW1vdmUoIG9iamVjdCApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0b2JqZWN0LnBhcmVudCA9IHRoaXM7XHJcblx0XHRcdHRoaXMuY2hpbGRyZW4ucHVzaCggb2JqZWN0ICk7XHJcblxyXG5cdFx0XHRvYmplY3QuZGlzcGF0Y2hFdmVudCggX2FkZGVkRXZlbnQgKTtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLk9iamVjdDNELmFkZDogb2JqZWN0IG5vdCBhbiBpbnN0YW5jZSBvZiBUSFJFRS5PYmplY3QzRC4nLCBvYmplY3QgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0cmVtb3ZlKCBvYmplY3QgKSB7XHJcblxyXG5cdFx0aWYgKCBhcmd1bWVudHMubGVuZ3RoID4gMSApIHtcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IGFyZ3VtZW50cy5sZW5ndGg7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdHRoaXMucmVtb3ZlKCBhcmd1bWVudHNbIGkgXSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGNvbnN0IGluZGV4ID0gdGhpcy5jaGlsZHJlbi5pbmRleE9mKCBvYmplY3QgKTtcclxuXHJcblx0XHRpZiAoIGluZGV4ICE9PSAtIDEgKSB7XHJcblxyXG5cdFx0XHRvYmplY3QucGFyZW50ID0gbnVsbDtcclxuXHRcdFx0dGhpcy5jaGlsZHJlbi5zcGxpY2UoIGluZGV4LCAxICk7XHJcblxyXG5cdFx0XHRvYmplY3QuZGlzcGF0Y2hFdmVudCggX3JlbW92ZWRFdmVudCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRyZW1vdmVGcm9tUGFyZW50KCkge1xyXG5cclxuXHRcdGNvbnN0IHBhcmVudCA9IHRoaXMucGFyZW50O1xyXG5cclxuXHRcdGlmICggcGFyZW50ICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0cGFyZW50LnJlbW92ZSggdGhpcyApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRjbGVhcigpIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5yZW1vdmUoIC4uLiB0aGlzLmNoaWxkcmVuICk7XHJcblxyXG5cdH1cclxuXHJcblx0YXR0YWNoKCBvYmplY3QgKSB7XHJcblxyXG5cdFx0Ly8gYWRkcyBvYmplY3QgYXMgYSBjaGlsZCBvZiB0aGlzLCB3aGlsZSBtYWludGFpbmluZyB0aGUgb2JqZWN0J3Mgd29ybGQgdHJhbnNmb3JtXHJcblxyXG5cdFx0Ly8gTm90ZTogVGhpcyBtZXRob2QgZG9lcyBub3Qgc3VwcG9ydCBzY2VuZSBncmFwaHMgaGF2aW5nIG5vbi11bmlmb3JtbHktc2NhbGVkIG5vZGVzKHMpXHJcblxyXG5cdFx0dGhpcy51cGRhdGVXb3JsZE1hdHJpeCggdHJ1ZSwgZmFsc2UgKTtcclxuXHJcblx0XHRfbTEuY29weSggdGhpcy5tYXRyaXhXb3JsZCApLmludmVydCgpO1xyXG5cclxuXHRcdGlmICggb2JqZWN0LnBhcmVudCAhPT0gbnVsbCApIHtcclxuXHJcblx0XHRcdG9iamVjdC5wYXJlbnQudXBkYXRlV29ybGRNYXRyaXgoIHRydWUsIGZhbHNlICk7XHJcblxyXG5cdFx0XHRfbTEubXVsdGlwbHkoIG9iamVjdC5wYXJlbnQubWF0cml4V29ybGQgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0b2JqZWN0LmFwcGx5TWF0cml4NCggX20xICk7XHJcblxyXG5cdFx0dGhpcy5hZGQoIG9iamVjdCApO1xyXG5cclxuXHRcdG9iamVjdC51cGRhdGVXb3JsZE1hdHJpeCggZmFsc2UsIHRydWUgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRnZXRPYmplY3RCeUlkKCBpZCApIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5nZXRPYmplY3RCeVByb3BlcnR5KCAnaWQnLCBpZCApO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldE9iamVjdEJ5TmFtZSggbmFtZSApIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5nZXRPYmplY3RCeVByb3BlcnR5KCAnbmFtZScsIG5hbWUgKTtcclxuXHJcblx0fVxyXG5cclxuXHRnZXRPYmplY3RCeVByb3BlcnR5KCBuYW1lLCB2YWx1ZSApIHtcclxuXHJcblx0XHRpZiAoIHRoaXNbIG5hbWUgXSA9PT0gdmFsdWUgKSByZXR1cm4gdGhpcztcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSB0aGlzLmNoaWxkcmVuLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBjaGlsZCA9IHRoaXMuY2hpbGRyZW5bIGkgXTtcclxuXHRcdFx0Y29uc3Qgb2JqZWN0ID0gY2hpbGQuZ2V0T2JqZWN0QnlQcm9wZXJ0eSggbmFtZSwgdmFsdWUgKTtcclxuXHJcblx0XHRcdGlmICggb2JqZWN0ICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRcdHJldHVybiBvYmplY3Q7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB1bmRlZmluZWQ7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0T2JqZWN0c0J5UHJvcGVydHkoIG5hbWUsIHZhbHVlLCByZXN1bHQgPSBbXSApIHtcclxuXHJcblx0XHRpZiAoIHRoaXNbIG5hbWUgXSA9PT0gdmFsdWUgKSByZXN1bHQucHVzaCggdGhpcyApO1xyXG5cclxuXHRcdGNvbnN0IGNoaWxkcmVuID0gdGhpcy5jaGlsZHJlbjtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBjaGlsZHJlbi5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0Y2hpbGRyZW5bIGkgXS5nZXRPYmplY3RzQnlQcm9wZXJ0eSggbmFtZSwgdmFsdWUsIHJlc3VsdCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gcmVzdWx0O1xyXG5cclxuXHR9XHJcblxyXG5cdGdldFdvcmxkUG9zaXRpb24oIHRhcmdldCApIHtcclxuXHJcblx0XHR0aGlzLnVwZGF0ZVdvcmxkTWF0cml4KCB0cnVlLCBmYWxzZSApO1xyXG5cclxuXHRcdHJldHVybiB0YXJnZXQuc2V0RnJvbU1hdHJpeFBvc2l0aW9uKCB0aGlzLm1hdHJpeFdvcmxkICk7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0V29ybGRRdWF0ZXJuaW9uKCB0YXJnZXQgKSB7XHJcblxyXG5cdFx0dGhpcy51cGRhdGVXb3JsZE1hdHJpeCggdHJ1ZSwgZmFsc2UgKTtcclxuXHJcblx0XHR0aGlzLm1hdHJpeFdvcmxkLmRlY29tcG9zZSggX3Bvc2l0aW9uLCB0YXJnZXQsIF9zY2FsZSApO1xyXG5cclxuXHRcdHJldHVybiB0YXJnZXQ7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0V29ybGRTY2FsZSggdGFyZ2V0ICkge1xyXG5cclxuXHRcdHRoaXMudXBkYXRlV29ybGRNYXRyaXgoIHRydWUsIGZhbHNlICk7XHJcblxyXG5cdFx0dGhpcy5tYXRyaXhXb3JsZC5kZWNvbXBvc2UoIF9wb3NpdGlvbiwgX3F1YXRlcm5pb24sIHRhcmdldCApO1xyXG5cclxuXHRcdHJldHVybiB0YXJnZXQ7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0V29ybGREaXJlY3Rpb24oIHRhcmdldCApIHtcclxuXHJcblx0XHR0aGlzLnVwZGF0ZVdvcmxkTWF0cml4KCB0cnVlLCBmYWxzZSApO1xyXG5cclxuXHRcdGNvbnN0IGUgPSB0aGlzLm1hdHJpeFdvcmxkLmVsZW1lbnRzO1xyXG5cclxuXHRcdHJldHVybiB0YXJnZXQuc2V0KCBlWyA4IF0sIGVbIDkgXSwgZVsgMTAgXSApLm5vcm1hbGl6ZSgpO1xyXG5cclxuXHR9XHJcblxyXG5cdHJheWNhc3QoIC8qIHJheWNhc3RlciwgaW50ZXJzZWN0cyAqLyApIHt9XHJcblxyXG5cdHRyYXZlcnNlKCBjYWxsYmFjayApIHtcclxuXHJcblx0XHRjYWxsYmFjayggdGhpcyApO1xyXG5cclxuXHRcdGNvbnN0IGNoaWxkcmVuID0gdGhpcy5jaGlsZHJlbjtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBjaGlsZHJlbi5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0Y2hpbGRyZW5bIGkgXS50cmF2ZXJzZSggY2FsbGJhY2sgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0dHJhdmVyc2VWaXNpYmxlKCBjYWxsYmFjayApIHtcclxuXHJcblx0XHRpZiAoIHRoaXMudmlzaWJsZSA9PT0gZmFsc2UgKSByZXR1cm47XHJcblxyXG5cdFx0Y2FsbGJhY2soIHRoaXMgKTtcclxuXHJcblx0XHRjb25zdCBjaGlsZHJlbiA9IHRoaXMuY2hpbGRyZW47XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gY2hpbGRyZW4ubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdGNoaWxkcmVuWyBpIF0udHJhdmVyc2VWaXNpYmxlKCBjYWxsYmFjayApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHR0cmF2ZXJzZUFuY2VzdG9ycyggY2FsbGJhY2sgKSB7XHJcblxyXG5cdFx0Y29uc3QgcGFyZW50ID0gdGhpcy5wYXJlbnQ7XHJcblxyXG5cdFx0aWYgKCBwYXJlbnQgIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRjYWxsYmFjayggcGFyZW50ICk7XHJcblxyXG5cdFx0XHRwYXJlbnQudHJhdmVyc2VBbmNlc3RvcnMoIGNhbGxiYWNrICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdHVwZGF0ZU1hdHJpeCgpIHtcclxuXHJcblx0XHR0aGlzLm1hdHJpeC5jb21wb3NlKCB0aGlzLnBvc2l0aW9uLCB0aGlzLnF1YXRlcm5pb24sIHRoaXMuc2NhbGUgKTtcclxuXHJcblx0XHR0aGlzLm1hdHJpeFdvcmxkTmVlZHNVcGRhdGUgPSB0cnVlO1xyXG5cclxuXHR9XHJcblxyXG5cdHVwZGF0ZU1hdHJpeFdvcmxkKCBmb3JjZSApIHtcclxuXHJcblx0XHRpZiAoIHRoaXMubWF0cml4QXV0b1VwZGF0ZSApIHRoaXMudXBkYXRlTWF0cml4KCk7XHJcblxyXG5cdFx0aWYgKCB0aGlzLm1hdHJpeFdvcmxkTmVlZHNVcGRhdGUgfHwgZm9yY2UgKSB7XHJcblxyXG5cdFx0XHRpZiAoIHRoaXMucGFyZW50ID09PSBudWxsICkge1xyXG5cclxuXHRcdFx0XHR0aGlzLm1hdHJpeFdvcmxkLmNvcHkoIHRoaXMubWF0cml4ICk7XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHR0aGlzLm1hdHJpeFdvcmxkLm11bHRpcGx5TWF0cmljZXMoIHRoaXMucGFyZW50Lm1hdHJpeFdvcmxkLCB0aGlzLm1hdHJpeCApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0dGhpcy5tYXRyaXhXb3JsZE5lZWRzVXBkYXRlID0gZmFsc2U7XHJcblxyXG5cdFx0XHRmb3JjZSA9IHRydWU7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIHVwZGF0ZSBjaGlsZHJlblxyXG5cclxuXHRcdGNvbnN0IGNoaWxkcmVuID0gdGhpcy5jaGlsZHJlbjtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBjaGlsZHJlbi5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0Y29uc3QgY2hpbGQgPSBjaGlsZHJlblsgaSBdO1xyXG5cclxuXHRcdFx0aWYgKCBjaGlsZC5tYXRyaXhXb3JsZEF1dG9VcGRhdGUgPT09IHRydWUgfHwgZm9yY2UgPT09IHRydWUgKSB7XHJcblxyXG5cdFx0XHRcdGNoaWxkLnVwZGF0ZU1hdHJpeFdvcmxkKCBmb3JjZSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHR1cGRhdGVXb3JsZE1hdHJpeCggdXBkYXRlUGFyZW50cywgdXBkYXRlQ2hpbGRyZW4gKSB7XHJcblxyXG5cdFx0Y29uc3QgcGFyZW50ID0gdGhpcy5wYXJlbnQ7XHJcblxyXG5cdFx0aWYgKCB1cGRhdGVQYXJlbnRzID09PSB0cnVlICYmIHBhcmVudCAhPT0gbnVsbCAmJiBwYXJlbnQubWF0cml4V29ybGRBdXRvVXBkYXRlID09PSB0cnVlICkge1xyXG5cclxuXHRcdFx0cGFyZW50LnVwZGF0ZVdvcmxkTWF0cml4KCB0cnVlLCBmYWxzZSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHRoaXMubWF0cml4QXV0b1VwZGF0ZSApIHRoaXMudXBkYXRlTWF0cml4KCk7XHJcblxyXG5cdFx0aWYgKCB0aGlzLnBhcmVudCA9PT0gbnVsbCApIHtcclxuXHJcblx0XHRcdHRoaXMubWF0cml4V29ybGQuY29weSggdGhpcy5tYXRyaXggKTtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0dGhpcy5tYXRyaXhXb3JsZC5tdWx0aXBseU1hdHJpY2VzKCB0aGlzLnBhcmVudC5tYXRyaXhXb3JsZCwgdGhpcy5tYXRyaXggKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gdXBkYXRlIGNoaWxkcmVuXHJcblxyXG5cdFx0aWYgKCB1cGRhdGVDaGlsZHJlbiA9PT0gdHJ1ZSApIHtcclxuXHJcblx0XHRcdGNvbnN0IGNoaWxkcmVuID0gdGhpcy5jaGlsZHJlbjtcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMCwgbCA9IGNoaWxkcmVuLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IGNoaWxkID0gY2hpbGRyZW5bIGkgXTtcclxuXHJcblx0XHRcdFx0aWYgKCBjaGlsZC5tYXRyaXhXb3JsZEF1dG9VcGRhdGUgPT09IHRydWUgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y2hpbGQudXBkYXRlV29ybGRNYXRyaXgoIGZhbHNlLCB0cnVlICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0dG9KU09OKCBtZXRhICkge1xyXG5cclxuXHRcdC8vIG1ldGEgaXMgYSBzdHJpbmcgd2hlbiBjYWxsZWQgZnJvbSBKU09OLnN0cmluZ2lmeVxyXG5cdFx0Y29uc3QgaXNSb290T2JqZWN0ID0gKCBtZXRhID09PSB1bmRlZmluZWQgfHwgdHlwZW9mIG1ldGEgPT09ICdzdHJpbmcnICk7XHJcblxyXG5cdFx0Y29uc3Qgb3V0cHV0ID0ge307XHJcblxyXG5cdFx0Ly8gbWV0YSBpcyBhIGhhc2ggdXNlZCB0byBjb2xsZWN0IGdlb21ldHJpZXMsIG1hdGVyaWFscy5cclxuXHRcdC8vIG5vdCBwcm92aWRpbmcgaXQgaW1wbGllcyB0aGF0IHRoaXMgaXMgdGhlIHJvb3Qgb2JqZWN0XHJcblx0XHQvLyBiZWluZyBzZXJpYWxpemVkLlxyXG5cdFx0aWYgKCBpc1Jvb3RPYmplY3QgKSB7XHJcblxyXG5cdFx0XHQvLyBpbml0aWFsaXplIG1ldGEgb2JqXHJcblx0XHRcdG1ldGEgPSB7XHJcblx0XHRcdFx0Z2VvbWV0cmllczoge30sXHJcblx0XHRcdFx0bWF0ZXJpYWxzOiB7fSxcclxuXHRcdFx0XHR0ZXh0dXJlczoge30sXHJcblx0XHRcdFx0aW1hZ2VzOiB7fSxcclxuXHRcdFx0XHRzaGFwZXM6IHt9LFxyXG5cdFx0XHRcdHNrZWxldG9uczoge30sXHJcblx0XHRcdFx0YW5pbWF0aW9uczoge30sXHJcblx0XHRcdFx0bm9kZXM6IHt9XHJcblx0XHRcdH07XHJcblxyXG5cdFx0XHRvdXRwdXQubWV0YWRhdGEgPSB7XHJcblx0XHRcdFx0dmVyc2lvbjogNC42LFxyXG5cdFx0XHRcdHR5cGU6ICdPYmplY3QnLFxyXG5cdFx0XHRcdGdlbmVyYXRvcjogJ09iamVjdDNELnRvSlNPTidcclxuXHRcdFx0fTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gc3RhbmRhcmQgT2JqZWN0M0Qgc2VyaWFsaXphdGlvblxyXG5cclxuXHRcdGNvbnN0IG9iamVjdCA9IHt9O1xyXG5cclxuXHRcdG9iamVjdC51dWlkID0gdGhpcy51dWlkO1xyXG5cdFx0b2JqZWN0LnR5cGUgPSB0aGlzLnR5cGU7XHJcblxyXG5cdFx0aWYgKCB0aGlzLm5hbWUgIT09ICcnICkgb2JqZWN0Lm5hbWUgPSB0aGlzLm5hbWU7XHJcblx0XHRpZiAoIHRoaXMuY2FzdFNoYWRvdyA9PT0gdHJ1ZSApIG9iamVjdC5jYXN0U2hhZG93ID0gdHJ1ZTtcclxuXHRcdGlmICggdGhpcy5yZWNlaXZlU2hhZG93ID09PSB0cnVlICkgb2JqZWN0LnJlY2VpdmVTaGFkb3cgPSB0cnVlO1xyXG5cdFx0aWYgKCB0aGlzLnZpc2libGUgPT09IGZhbHNlICkgb2JqZWN0LnZpc2libGUgPSBmYWxzZTtcclxuXHRcdGlmICggdGhpcy5mcnVzdHVtQ3VsbGVkID09PSBmYWxzZSApIG9iamVjdC5mcnVzdHVtQ3VsbGVkID0gZmFsc2U7XHJcblx0XHRpZiAoIHRoaXMucmVuZGVyT3JkZXIgIT09IDAgKSBvYmplY3QucmVuZGVyT3JkZXIgPSB0aGlzLnJlbmRlck9yZGVyO1xyXG5cdFx0aWYgKCBPYmplY3Qua2V5cyggdGhpcy51c2VyRGF0YSApLmxlbmd0aCA+IDAgKSBvYmplY3QudXNlckRhdGEgPSB0aGlzLnVzZXJEYXRhO1xyXG5cclxuXHRcdG9iamVjdC5sYXllcnMgPSB0aGlzLmxheWVycy5tYXNrO1xyXG5cdFx0b2JqZWN0Lm1hdHJpeCA9IHRoaXMubWF0cml4LnRvQXJyYXkoKTtcclxuXHRcdG9iamVjdC51cCA9IHRoaXMudXAudG9BcnJheSgpO1xyXG5cclxuXHRcdGlmICggdGhpcy5tYXRyaXhBdXRvVXBkYXRlID09PSBmYWxzZSApIG9iamVjdC5tYXRyaXhBdXRvVXBkYXRlID0gZmFsc2U7XHJcblxyXG5cdFx0Ly8gb2JqZWN0IHNwZWNpZmljIHByb3BlcnRpZXNcclxuXHJcblx0XHRpZiAoIHRoaXMuaXNJbnN0YW5jZWRNZXNoICkge1xyXG5cclxuXHRcdFx0b2JqZWN0LnR5cGUgPSAnSW5zdGFuY2VkTWVzaCc7XHJcblx0XHRcdG9iamVjdC5jb3VudCA9IHRoaXMuY291bnQ7XHJcblx0XHRcdG9iamVjdC5pbnN0YW5jZU1hdHJpeCA9IHRoaXMuaW5zdGFuY2VNYXRyaXgudG9KU09OKCk7XHJcblx0XHRcdGlmICggdGhpcy5pbnN0YW5jZUNvbG9yICE9PSBudWxsICkgb2JqZWN0Lmluc3RhbmNlQ29sb3IgPSB0aGlzLmluc3RhbmNlQ29sb3IudG9KU09OKCk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggdGhpcy5pc0JhdGNoZWRNZXNoICkge1xyXG5cclxuXHRcdFx0b2JqZWN0LnR5cGUgPSAnQmF0Y2hlZE1lc2gnO1xyXG5cdFx0XHRvYmplY3QucGVyT2JqZWN0RnJ1c3R1bUN1bGxlZCA9IHRoaXMucGVyT2JqZWN0RnJ1c3R1bUN1bGxlZDtcclxuXHRcdFx0b2JqZWN0LnNvcnRPYmplY3RzID0gdGhpcy5zb3J0T2JqZWN0cztcclxuXHJcblx0XHRcdG9iamVjdC5kcmF3UmFuZ2VzID0gdGhpcy5fZHJhd1JhbmdlcztcclxuXHRcdFx0b2JqZWN0LnJlc2VydmVkUmFuZ2VzID0gdGhpcy5fcmVzZXJ2ZWRSYW5nZXM7XHJcblxyXG5cdFx0XHRvYmplY3QudmlzaWJpbGl0eSA9IHRoaXMuX3Zpc2liaWxpdHk7XHJcblx0XHRcdG9iamVjdC5hY3RpdmUgPSB0aGlzLl9hY3RpdmU7XHJcblx0XHRcdG9iamVjdC5ib3VuZHMgPSB0aGlzLl9ib3VuZHMubWFwKCBib3VuZCA9PiAoIHtcclxuXHRcdFx0XHRib3hJbml0aWFsaXplZDogYm91bmQuYm94SW5pdGlhbGl6ZWQsXHJcblx0XHRcdFx0Ym94TWluOiBib3VuZC5ib3gubWluLnRvQXJyYXkoKSxcclxuXHRcdFx0XHRib3hNYXg6IGJvdW5kLmJveC5tYXgudG9BcnJheSgpLFxyXG5cclxuXHRcdFx0XHRzcGhlcmVJbml0aWFsaXplZDogYm91bmQuc3BoZXJlSW5pdGlhbGl6ZWQsXHJcblx0XHRcdFx0c3BoZXJlUmFkaXVzOiBib3VuZC5zcGhlcmUucmFkaXVzLFxyXG5cdFx0XHRcdHNwaGVyZUNlbnRlcjogYm91bmQuc3BoZXJlLmNlbnRlci50b0FycmF5KClcclxuXHRcdFx0fSApICk7XHJcblxyXG5cdFx0XHRvYmplY3QubWF4R2VvbWV0cnlDb3VudCA9IHRoaXMuX21heEdlb21ldHJ5Q291bnQ7XHJcblx0XHRcdG9iamVjdC5tYXhWZXJ0ZXhDb3VudCA9IHRoaXMuX21heFZlcnRleENvdW50O1xyXG5cdFx0XHRvYmplY3QubWF4SW5kZXhDb3VudCA9IHRoaXMuX21heEluZGV4Q291bnQ7XHJcblxyXG5cdFx0XHRvYmplY3QuZ2VvbWV0cnlJbml0aWFsaXplZCA9IHRoaXMuX2dlb21ldHJ5SW5pdGlhbGl6ZWQ7XHJcblx0XHRcdG9iamVjdC5nZW9tZXRyeUNvdW50ID0gdGhpcy5fZ2VvbWV0cnlDb3VudDtcclxuXHJcblx0XHRcdG9iamVjdC5tYXRyaWNlc1RleHR1cmUgPSB0aGlzLl9tYXRyaWNlc1RleHR1cmUudG9KU09OKCBtZXRhICk7XHJcblxyXG5cdFx0XHRpZiAoIHRoaXMuYm91bmRpbmdTcGhlcmUgIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdG9iamVjdC5ib3VuZGluZ1NwaGVyZSA9IHtcclxuXHRcdFx0XHRcdGNlbnRlcjogb2JqZWN0LmJvdW5kaW5nU3BoZXJlLmNlbnRlci50b0FycmF5KCksXHJcblx0XHRcdFx0XHRyYWRpdXM6IG9iamVjdC5ib3VuZGluZ1NwaGVyZS5yYWRpdXNcclxuXHRcdFx0XHR9O1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0aWYgKCB0aGlzLmJvdW5kaW5nQm94ICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0XHRvYmplY3QuYm91bmRpbmdCb3ggPSB7XHJcblx0XHRcdFx0XHRtaW46IG9iamVjdC5ib3VuZGluZ0JveC5taW4udG9BcnJheSgpLFxyXG5cdFx0XHRcdFx0bWF4OiBvYmplY3QuYm91bmRpbmdCb3gubWF4LnRvQXJyYXkoKVxyXG5cdFx0XHRcdH07XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vXHJcblxyXG5cdFx0ZnVuY3Rpb24gc2VyaWFsaXplKCBsaWJyYXJ5LCBlbGVtZW50ICkge1xyXG5cclxuXHRcdFx0aWYgKCBsaWJyYXJ5WyBlbGVtZW50LnV1aWQgXSA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHRsaWJyYXJ5WyBlbGVtZW50LnV1aWQgXSA9IGVsZW1lbnQudG9KU09OKCBtZXRhICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRyZXR1cm4gZWxlbWVudC51dWlkO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHRoaXMuaXNTY2VuZSApIHtcclxuXHJcblx0XHRcdGlmICggdGhpcy5iYWNrZ3JvdW5kICkge1xyXG5cclxuXHRcdFx0XHRpZiAoIHRoaXMuYmFja2dyb3VuZC5pc0NvbG9yICkge1xyXG5cclxuXHRcdFx0XHRcdG9iamVjdC5iYWNrZ3JvdW5kID0gdGhpcy5iYWNrZ3JvdW5kLnRvSlNPTigpO1xyXG5cclxuXHRcdFx0XHR9IGVsc2UgaWYgKCB0aGlzLmJhY2tncm91bmQuaXNUZXh0dXJlICkge1xyXG5cclxuXHRcdFx0XHRcdG9iamVjdC5iYWNrZ3JvdW5kID0gdGhpcy5iYWNrZ3JvdW5kLnRvSlNPTiggbWV0YSApLnV1aWQ7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGlmICggdGhpcy5lbnZpcm9ubWVudCAmJiB0aGlzLmVudmlyb25tZW50LmlzVGV4dHVyZSAmJiB0aGlzLmVudmlyb25tZW50LmlzUmVuZGVyVGFyZ2V0VGV4dHVyZSAhPT0gdHJ1ZSApIHtcclxuXHJcblx0XHRcdFx0b2JqZWN0LmVudmlyb25tZW50ID0gdGhpcy5lbnZpcm9ubWVudC50b0pTT04oIG1ldGEgKS51dWlkO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH0gZWxzZSBpZiAoIHRoaXMuaXNNZXNoIHx8IHRoaXMuaXNMaW5lIHx8IHRoaXMuaXNQb2ludHMgKSB7XHJcblxyXG5cdFx0XHRvYmplY3QuZ2VvbWV0cnkgPSBzZXJpYWxpemUoIG1ldGEuZ2VvbWV0cmllcywgdGhpcy5nZW9tZXRyeSApO1xyXG5cclxuXHRcdFx0Y29uc3QgcGFyYW1ldGVycyA9IHRoaXMuZ2VvbWV0cnkucGFyYW1ldGVycztcclxuXHJcblx0XHRcdGlmICggcGFyYW1ldGVycyAhPT0gdW5kZWZpbmVkICYmIHBhcmFtZXRlcnMuc2hhcGVzICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IHNoYXBlcyA9IHBhcmFtZXRlcnMuc2hhcGVzO1xyXG5cclxuXHRcdFx0XHRpZiAoIEFycmF5LmlzQXJyYXkoIHNoYXBlcyApICkge1xyXG5cclxuXHRcdFx0XHRcdGZvciAoIGxldCBpID0gMCwgbCA9IHNoYXBlcy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRcdFx0Y29uc3Qgc2hhcGUgPSBzaGFwZXNbIGkgXTtcclxuXHJcblx0XHRcdFx0XHRcdHNlcmlhbGl6ZSggbWV0YS5zaGFwZXMsIHNoYXBlICk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdHNlcmlhbGl6ZSggbWV0YS5zaGFwZXMsIHNoYXBlcyApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggdGhpcy5pc1NraW5uZWRNZXNoICkge1xyXG5cclxuXHRcdFx0b2JqZWN0LmJpbmRNb2RlID0gdGhpcy5iaW5kTW9kZTtcclxuXHRcdFx0b2JqZWN0LmJpbmRNYXRyaXggPSB0aGlzLmJpbmRNYXRyaXgudG9BcnJheSgpO1xyXG5cclxuXHRcdFx0aWYgKCB0aGlzLnNrZWxldG9uICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRcdHNlcmlhbGl6ZSggbWV0YS5za2VsZXRvbnMsIHRoaXMuc2tlbGV0b24gKTtcclxuXHJcblx0XHRcdFx0b2JqZWN0LnNrZWxldG9uID0gdGhpcy5za2VsZXRvbi51dWlkO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHRoaXMubWF0ZXJpYWwgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdGlmICggQXJyYXkuaXNBcnJheSggdGhpcy5tYXRlcmlhbCApICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCB1dWlkcyA9IFtdO1xyXG5cclxuXHRcdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSB0aGlzLm1hdGVyaWFsLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0dXVpZHMucHVzaCggc2VyaWFsaXplKCBtZXRhLm1hdGVyaWFscywgdGhpcy5tYXRlcmlhbFsgaSBdICkgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRvYmplY3QubWF0ZXJpYWwgPSB1dWlkcztcclxuXHJcblx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdG9iamVjdC5tYXRlcmlhbCA9IHNlcmlhbGl6ZSggbWV0YS5tYXRlcmlhbHMsIHRoaXMubWF0ZXJpYWwgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly9cclxuXHJcblx0XHRpZiAoIHRoaXMuY2hpbGRyZW4ubGVuZ3RoID4gMCApIHtcclxuXHJcblx0XHRcdG9iamVjdC5jaGlsZHJlbiA9IFtdO1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgdGhpcy5jaGlsZHJlbi5sZW5ndGg7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdG9iamVjdC5jaGlsZHJlbi5wdXNoKCB0aGlzLmNoaWxkcmVuWyBpIF0udG9KU09OKCBtZXRhICkub2JqZWN0ICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vXHJcblxyXG5cdFx0aWYgKCB0aGlzLmFuaW1hdGlvbnMubGVuZ3RoID4gMCApIHtcclxuXHJcblx0XHRcdG9iamVjdC5hbmltYXRpb25zID0gW107XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCB0aGlzLmFuaW1hdGlvbnMubGVuZ3RoOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBhbmltYXRpb24gPSB0aGlzLmFuaW1hdGlvbnNbIGkgXTtcclxuXHJcblx0XHRcdFx0b2JqZWN0LmFuaW1hdGlvbnMucHVzaCggc2VyaWFsaXplKCBtZXRhLmFuaW1hdGlvbnMsIGFuaW1hdGlvbiApICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggaXNSb290T2JqZWN0ICkge1xyXG5cclxuXHRcdFx0Y29uc3QgZ2VvbWV0cmllcyA9IGV4dHJhY3RGcm9tQ2FjaGUoIG1ldGEuZ2VvbWV0cmllcyApO1xyXG5cdFx0XHRjb25zdCBtYXRlcmlhbHMgPSBleHRyYWN0RnJvbUNhY2hlKCBtZXRhLm1hdGVyaWFscyApO1xyXG5cdFx0XHRjb25zdCB0ZXh0dXJlcyA9IGV4dHJhY3RGcm9tQ2FjaGUoIG1ldGEudGV4dHVyZXMgKTtcclxuXHRcdFx0Y29uc3QgaW1hZ2VzID0gZXh0cmFjdEZyb21DYWNoZSggbWV0YS5pbWFnZXMgKTtcclxuXHRcdFx0Y29uc3Qgc2hhcGVzID0gZXh0cmFjdEZyb21DYWNoZSggbWV0YS5zaGFwZXMgKTtcclxuXHRcdFx0Y29uc3Qgc2tlbGV0b25zID0gZXh0cmFjdEZyb21DYWNoZSggbWV0YS5za2VsZXRvbnMgKTtcclxuXHRcdFx0Y29uc3QgYW5pbWF0aW9ucyA9IGV4dHJhY3RGcm9tQ2FjaGUoIG1ldGEuYW5pbWF0aW9ucyApO1xyXG5cdFx0XHRjb25zdCBub2RlcyA9IGV4dHJhY3RGcm9tQ2FjaGUoIG1ldGEubm9kZXMgKTtcclxuXHJcblx0XHRcdGlmICggZ2VvbWV0cmllcy5sZW5ndGggPiAwICkgb3V0cHV0Lmdlb21ldHJpZXMgPSBnZW9tZXRyaWVzO1xyXG5cdFx0XHRpZiAoIG1hdGVyaWFscy5sZW5ndGggPiAwICkgb3V0cHV0Lm1hdGVyaWFscyA9IG1hdGVyaWFscztcclxuXHRcdFx0aWYgKCB0ZXh0dXJlcy5sZW5ndGggPiAwICkgb3V0cHV0LnRleHR1cmVzID0gdGV4dHVyZXM7XHJcblx0XHRcdGlmICggaW1hZ2VzLmxlbmd0aCA+IDAgKSBvdXRwdXQuaW1hZ2VzID0gaW1hZ2VzO1xyXG5cdFx0XHRpZiAoIHNoYXBlcy5sZW5ndGggPiAwICkgb3V0cHV0LnNoYXBlcyA9IHNoYXBlcztcclxuXHRcdFx0aWYgKCBza2VsZXRvbnMubGVuZ3RoID4gMCApIG91dHB1dC5za2VsZXRvbnMgPSBza2VsZXRvbnM7XHJcblx0XHRcdGlmICggYW5pbWF0aW9ucy5sZW5ndGggPiAwICkgb3V0cHV0LmFuaW1hdGlvbnMgPSBhbmltYXRpb25zO1xyXG5cdFx0XHRpZiAoIG5vZGVzLmxlbmd0aCA+IDAgKSBvdXRwdXQubm9kZXMgPSBub2RlcztcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0b3V0cHV0Lm9iamVjdCA9IG9iamVjdDtcclxuXHJcblx0XHRyZXR1cm4gb3V0cHV0O1xyXG5cclxuXHRcdC8vIGV4dHJhY3QgZGF0YSBmcm9tIHRoZSBjYWNoZSBoYXNoXHJcblx0XHQvLyByZW1vdmUgbWV0YWRhdGEgb24gZWFjaCBpdGVtXHJcblx0XHQvLyBhbmQgcmV0dXJuIGFzIGFycmF5XHJcblx0XHRmdW5jdGlvbiBleHRyYWN0RnJvbUNhY2hlKCBjYWNoZSApIHtcclxuXHJcblx0XHRcdGNvbnN0IHZhbHVlcyA9IFtdO1xyXG5cdFx0XHRmb3IgKCBjb25zdCBrZXkgaW4gY2FjaGUgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IGRhdGEgPSBjYWNoZVsga2V5IF07XHJcblx0XHRcdFx0ZGVsZXRlIGRhdGEubWV0YWRhdGE7XHJcblx0XHRcdFx0dmFsdWVzLnB1c2goIGRhdGEgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHJldHVybiB2YWx1ZXM7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGNsb25lKCByZWN1cnNpdmUgKSB7XHJcblxyXG5cdFx0cmV0dXJuIG5ldyB0aGlzLmNvbnN0cnVjdG9yKCkuY29weSggdGhpcywgcmVjdXJzaXZlICk7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlLCByZWN1cnNpdmUgPSB0cnVlICkge1xyXG5cclxuXHRcdHRoaXMubmFtZSA9IHNvdXJjZS5uYW1lO1xyXG5cclxuXHRcdHRoaXMudXAuY29weSggc291cmNlLnVwICk7XHJcblxyXG5cdFx0dGhpcy5wb3NpdGlvbi5jb3B5KCBzb3VyY2UucG9zaXRpb24gKTtcclxuXHRcdHRoaXMucm90YXRpb24ub3JkZXIgPSBzb3VyY2Uucm90YXRpb24ub3JkZXI7XHJcblx0XHR0aGlzLnF1YXRlcm5pb24uY29weSggc291cmNlLnF1YXRlcm5pb24gKTtcclxuXHRcdHRoaXMuc2NhbGUuY29weSggc291cmNlLnNjYWxlICk7XHJcblxyXG5cdFx0dGhpcy5tYXRyaXguY29weSggc291cmNlLm1hdHJpeCApO1xyXG5cdFx0dGhpcy5tYXRyaXhXb3JsZC5jb3B5KCBzb3VyY2UubWF0cml4V29ybGQgKTtcclxuXHJcblx0XHR0aGlzLm1hdHJpeEF1dG9VcGRhdGUgPSBzb3VyY2UubWF0cml4QXV0b1VwZGF0ZTtcclxuXHJcblx0XHR0aGlzLm1hdHJpeFdvcmxkQXV0b1VwZGF0ZSA9IHNvdXJjZS5tYXRyaXhXb3JsZEF1dG9VcGRhdGU7XHJcblx0XHR0aGlzLm1hdHJpeFdvcmxkTmVlZHNVcGRhdGUgPSBzb3VyY2UubWF0cml4V29ybGROZWVkc1VwZGF0ZTtcclxuXHJcblx0XHR0aGlzLmxheWVycy5tYXNrID0gc291cmNlLmxheWVycy5tYXNrO1xyXG5cdFx0dGhpcy52aXNpYmxlID0gc291cmNlLnZpc2libGU7XHJcblxyXG5cdFx0dGhpcy5jYXN0U2hhZG93ID0gc291cmNlLmNhc3RTaGFkb3c7XHJcblx0XHR0aGlzLnJlY2VpdmVTaGFkb3cgPSBzb3VyY2UucmVjZWl2ZVNoYWRvdztcclxuXHJcblx0XHR0aGlzLmZydXN0dW1DdWxsZWQgPSBzb3VyY2UuZnJ1c3R1bUN1bGxlZDtcclxuXHRcdHRoaXMucmVuZGVyT3JkZXIgPSBzb3VyY2UucmVuZGVyT3JkZXI7XHJcblxyXG5cdFx0dGhpcy5hbmltYXRpb25zID0gc291cmNlLmFuaW1hdGlvbnMuc2xpY2UoKTtcclxuXHJcblx0XHR0aGlzLnVzZXJEYXRhID0gSlNPTi5wYXJzZSggSlNPTi5zdHJpbmdpZnkoIHNvdXJjZS51c2VyRGF0YSApICk7XHJcblxyXG5cdFx0aWYgKCByZWN1cnNpdmUgPT09IHRydWUgKSB7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBzb3VyY2UuY2hpbGRyZW4ubGVuZ3RoOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBjaGlsZCA9IHNvdXJjZS5jaGlsZHJlblsgaSBdO1xyXG5cdFx0XHRcdHRoaXMuYWRkKCBjaGlsZC5jbG9uZSgpICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5PYmplY3QzRC5ERUZBVUxUX1VQID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMyggMCwgMSwgMCApO1xyXG5PYmplY3QzRC5ERUZBVUxUX01BVFJJWF9BVVRPX1VQREFURSA9IHRydWU7XHJcbk9iamVjdDNELkRFRkFVTFRfTUFUUklYX1dPUkxEX0FVVE9fVVBEQVRFID0gdHJ1ZTtcclxuXHJcbmV4cG9ydCB7IE9iamVjdDNEIH07XHJcbiIsImltcG9ydCB7IFZlY3RvcjMgfSBmcm9tICcuL1ZlY3RvcjMuanMnO1xyXG5cclxuY29uc3QgX3YwID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5jb25zdCBfdjEgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XHJcbmNvbnN0IF92MiA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuY29uc3QgX3YzID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5cclxuY29uc3QgX3ZhYiA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuY29uc3QgX3ZhYyA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuY29uc3QgX3ZiYyA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuY29uc3QgX3ZhcCA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuY29uc3QgX3ZicCA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuY29uc3QgX3ZjcCA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuXHJcbmNsYXNzIFRyaWFuZ2xlIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIGEgPSBuZXcgVmVjdG9yMygpLCBiID0gbmV3IFZlY3RvcjMoKSwgYyA9IG5ldyBWZWN0b3IzKCkgKSB7XHJcblxyXG5cdFx0dGhpcy5hID0gYTtcclxuXHRcdHRoaXMuYiA9IGI7XHJcblx0XHR0aGlzLmMgPSBjO1xyXG5cclxuXHR9XHJcblxyXG5cdHN0YXRpYyBnZXROb3JtYWwoIGEsIGIsIGMsIHRhcmdldCApIHtcclxuXHJcblx0XHR0YXJnZXQuc3ViVmVjdG9ycyggYywgYiApO1xyXG5cdFx0X3YwLnN1YlZlY3RvcnMoIGEsIGIgKTtcclxuXHRcdHRhcmdldC5jcm9zcyggX3YwICk7XHJcblxyXG5cdFx0Y29uc3QgdGFyZ2V0TGVuZ3RoU3EgPSB0YXJnZXQubGVuZ3RoU3EoKTtcclxuXHRcdGlmICggdGFyZ2V0TGVuZ3RoU3EgPiAwICkge1xyXG5cclxuXHRcdFx0cmV0dXJuIHRhcmdldC5tdWx0aXBseVNjYWxhciggMSAvIE1hdGguc3FydCggdGFyZ2V0TGVuZ3RoU3EgKSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGFyZ2V0LnNldCggMCwgMCwgMCApO1xyXG5cclxuXHR9XHJcblxyXG5cdC8vIHN0YXRpYy9pbnN0YW5jZSBtZXRob2QgdG8gY2FsY3VsYXRlIGJhcnljZW50cmljIGNvb3JkaW5hdGVzXHJcblx0Ly8gYmFzZWQgb246IGh0dHA6Ly93d3cuYmxhY2twYXduLmNvbS90ZXh0cy9wb2ludGlucG9seS9kZWZhdWx0Lmh0bWxcclxuXHRzdGF0aWMgZ2V0QmFyeWNvb3JkKCBwb2ludCwgYSwgYiwgYywgdGFyZ2V0ICkge1xyXG5cclxuXHRcdF92MC5zdWJWZWN0b3JzKCBjLCBhICk7XHJcblx0XHRfdjEuc3ViVmVjdG9ycyggYiwgYSApO1xyXG5cdFx0X3YyLnN1YlZlY3RvcnMoIHBvaW50LCBhICk7XHJcblxyXG5cdFx0Y29uc3QgZG90MDAgPSBfdjAuZG90KCBfdjAgKTtcclxuXHRcdGNvbnN0IGRvdDAxID0gX3YwLmRvdCggX3YxICk7XHJcblx0XHRjb25zdCBkb3QwMiA9IF92MC5kb3QoIF92MiApO1xyXG5cdFx0Y29uc3QgZG90MTEgPSBfdjEuZG90KCBfdjEgKTtcclxuXHRcdGNvbnN0IGRvdDEyID0gX3YxLmRvdCggX3YyICk7XHJcblxyXG5cdFx0Y29uc3QgZGVub20gPSAoIGRvdDAwICogZG90MTEgLSBkb3QwMSAqIGRvdDAxICk7XHJcblxyXG5cdFx0Ly8gY29sbGluZWFyIG9yIHNpbmd1bGFyIHRyaWFuZ2xlXHJcblx0XHRpZiAoIGRlbm9tID09PSAwICkge1xyXG5cclxuXHRcdFx0dGFyZ2V0LnNldCggMCwgMCwgMCApO1xyXG5cdFx0XHRyZXR1cm4gbnVsbDtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Y29uc3QgaW52RGVub20gPSAxIC8gZGVub207XHJcblx0XHRjb25zdCB1ID0gKCBkb3QxMSAqIGRvdDAyIC0gZG90MDEgKiBkb3QxMiApICogaW52RGVub207XHJcblx0XHRjb25zdCB2ID0gKCBkb3QwMCAqIGRvdDEyIC0gZG90MDEgKiBkb3QwMiApICogaW52RGVub207XHJcblxyXG5cdFx0Ly8gYmFyeWNlbnRyaWMgY29vcmRpbmF0ZXMgbXVzdCBhbHdheXMgc3VtIHRvIDFcclxuXHRcdHJldHVybiB0YXJnZXQuc2V0KCAxIC0gdSAtIHYsIHYsIHUgKTtcclxuXHJcblx0fVxyXG5cclxuXHRzdGF0aWMgY29udGFpbnNQb2ludCggcG9pbnQsIGEsIGIsIGMgKSB7XHJcblxyXG5cdFx0Ly8gaWYgdGhlIHRyaWFuZ2xlIGlzIGRlZ2VuZXJhdGUgdGhlbiB3ZSBjYW4ndCBjb250YWluIGEgcG9pbnRcclxuXHRcdGlmICggdGhpcy5nZXRCYXJ5Y29vcmQoIHBvaW50LCBhLCBiLCBjLCBfdjMgKSA9PT0gbnVsbCApIHtcclxuXHJcblx0XHRcdHJldHVybiBmYWxzZTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuICggX3YzLnggPj0gMCApICYmICggX3YzLnkgPj0gMCApICYmICggKCBfdjMueCArIF92My55ICkgPD0gMSApO1xyXG5cclxuXHR9XHJcblxyXG5cdHN0YXRpYyBnZXRJbnRlcnBvbGF0aW9uKCBwb2ludCwgcDEsIHAyLCBwMywgdjEsIHYyLCB2MywgdGFyZ2V0ICkge1xyXG5cclxuXHRcdGlmICggdGhpcy5nZXRCYXJ5Y29vcmQoIHBvaW50LCBwMSwgcDIsIHAzLCBfdjMgKSA9PT0gbnVsbCApIHtcclxuXHJcblx0XHRcdHRhcmdldC54ID0gMDtcclxuXHRcdFx0dGFyZ2V0LnkgPSAwO1xyXG5cdFx0XHRpZiAoICd6JyBpbiB0YXJnZXQgKSB0YXJnZXQueiA9IDA7XHJcblx0XHRcdGlmICggJ3cnIGluIHRhcmdldCApIHRhcmdldC53ID0gMDtcclxuXHRcdFx0cmV0dXJuIG51bGw7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRhcmdldC5zZXRTY2FsYXIoIDAgKTtcclxuXHRcdHRhcmdldC5hZGRTY2FsZWRWZWN0b3IoIHYxLCBfdjMueCApO1xyXG5cdFx0dGFyZ2V0LmFkZFNjYWxlZFZlY3RvciggdjIsIF92My55ICk7XHJcblx0XHR0YXJnZXQuYWRkU2NhbGVkVmVjdG9yKCB2MywgX3YzLnogKTtcclxuXHJcblx0XHRyZXR1cm4gdGFyZ2V0O1xyXG5cclxuXHR9XHJcblxyXG5cdHN0YXRpYyBpc0Zyb250RmFjaW5nKCBhLCBiLCBjLCBkaXJlY3Rpb24gKSB7XHJcblxyXG5cdFx0X3YwLnN1YlZlY3RvcnMoIGMsIGIgKTtcclxuXHRcdF92MS5zdWJWZWN0b3JzKCBhLCBiICk7XHJcblxyXG5cdFx0Ly8gc3RyaWN0bHkgZnJvbnQgZmFjaW5nXHJcblx0XHRyZXR1cm4gKCBfdjAuY3Jvc3MoIF92MSApLmRvdCggZGlyZWN0aW9uICkgPCAwICkgPyB0cnVlIDogZmFsc2U7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0KCBhLCBiLCBjICkge1xyXG5cclxuXHRcdHRoaXMuYS5jb3B5KCBhICk7XHJcblx0XHR0aGlzLmIuY29weSggYiApO1xyXG5cdFx0dGhpcy5jLmNvcHkoIGMgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRGcm9tUG9pbnRzQW5kSW5kaWNlcyggcG9pbnRzLCBpMCwgaTEsIGkyICkge1xyXG5cclxuXHRcdHRoaXMuYS5jb3B5KCBwb2ludHNbIGkwIF0gKTtcclxuXHRcdHRoaXMuYi5jb3B5KCBwb2ludHNbIGkxIF0gKTtcclxuXHRcdHRoaXMuYy5jb3B5KCBwb2ludHNbIGkyIF0gKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRGcm9tQXR0cmlidXRlQW5kSW5kaWNlcyggYXR0cmlidXRlLCBpMCwgaTEsIGkyICkge1xyXG5cclxuXHRcdHRoaXMuYS5mcm9tQnVmZmVyQXR0cmlidXRlKCBhdHRyaWJ1dGUsIGkwICk7XHJcblx0XHR0aGlzLmIuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggYXR0cmlidXRlLCBpMSApO1xyXG5cdFx0dGhpcy5jLmZyb21CdWZmZXJBdHRyaWJ1dGUoIGF0dHJpYnV0ZSwgaTIgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRjbG9uZSgpIHtcclxuXHJcblx0XHRyZXR1cm4gbmV3IHRoaXMuY29uc3RydWN0b3IoKS5jb3B5KCB0aGlzICk7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggdHJpYW5nbGUgKSB7XHJcblxyXG5cdFx0dGhpcy5hLmNvcHkoIHRyaWFuZ2xlLmEgKTtcclxuXHRcdHRoaXMuYi5jb3B5KCB0cmlhbmdsZS5iICk7XHJcblx0XHR0aGlzLmMuY29weSggdHJpYW5nbGUuYyApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldEFyZWEoKSB7XHJcblxyXG5cdFx0X3YwLnN1YlZlY3RvcnMoIHRoaXMuYywgdGhpcy5iICk7XHJcblx0XHRfdjEuc3ViVmVjdG9ycyggdGhpcy5hLCB0aGlzLmIgKTtcclxuXHJcblx0XHRyZXR1cm4gX3YwLmNyb3NzKCBfdjEgKS5sZW5ndGgoKSAqIDAuNTtcclxuXHJcblx0fVxyXG5cclxuXHRnZXRNaWRwb2ludCggdGFyZ2V0ICkge1xyXG5cclxuXHRcdHJldHVybiB0YXJnZXQuYWRkVmVjdG9ycyggdGhpcy5hLCB0aGlzLmIgKS5hZGQoIHRoaXMuYyApLm11bHRpcGx5U2NhbGFyKCAxIC8gMyApO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldE5vcm1hbCggdGFyZ2V0ICkge1xyXG5cclxuXHRcdHJldHVybiBUcmlhbmdsZS5nZXROb3JtYWwoIHRoaXMuYSwgdGhpcy5iLCB0aGlzLmMsIHRhcmdldCApO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldFBsYW5lKCB0YXJnZXQgKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRhcmdldC5zZXRGcm9tQ29wbGFuYXJQb2ludHMoIHRoaXMuYSwgdGhpcy5iLCB0aGlzLmMgKTtcclxuXHJcblx0fVxyXG5cclxuXHRnZXRCYXJ5Y29vcmQoIHBvaW50LCB0YXJnZXQgKSB7XHJcblxyXG5cdFx0cmV0dXJuIFRyaWFuZ2xlLmdldEJhcnljb29yZCggcG9pbnQsIHRoaXMuYSwgdGhpcy5iLCB0aGlzLmMsIHRhcmdldCApO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldEludGVycG9sYXRpb24oIHBvaW50LCB2MSwgdjIsIHYzLCB0YXJnZXQgKSB7XHJcblxyXG5cdFx0cmV0dXJuIFRyaWFuZ2xlLmdldEludGVycG9sYXRpb24oIHBvaW50LCB0aGlzLmEsIHRoaXMuYiwgdGhpcy5jLCB2MSwgdjIsIHYzLCB0YXJnZXQgKTtcclxuXHJcblx0fVxyXG5cclxuXHRjb250YWluc1BvaW50KCBwb2ludCApIHtcclxuXHJcblx0XHRyZXR1cm4gVHJpYW5nbGUuY29udGFpbnNQb2ludCggcG9pbnQsIHRoaXMuYSwgdGhpcy5iLCB0aGlzLmMgKTtcclxuXHJcblx0fVxyXG5cclxuXHRpc0Zyb250RmFjaW5nKCBkaXJlY3Rpb24gKSB7XHJcblxyXG5cdFx0cmV0dXJuIFRyaWFuZ2xlLmlzRnJvbnRGYWNpbmcoIHRoaXMuYSwgdGhpcy5iLCB0aGlzLmMsIGRpcmVjdGlvbiApO1xyXG5cclxuXHR9XHJcblxyXG5cdGludGVyc2VjdHNCb3goIGJveCApIHtcclxuXHJcblx0XHRyZXR1cm4gYm94LmludGVyc2VjdHNUcmlhbmdsZSggdGhpcyApO1xyXG5cclxuXHR9XHJcblxyXG5cdGNsb3Nlc3RQb2ludFRvUG9pbnQoIHAsIHRhcmdldCApIHtcclxuXHJcblx0XHRjb25zdCBhID0gdGhpcy5hLCBiID0gdGhpcy5iLCBjID0gdGhpcy5jO1xyXG5cdFx0bGV0IHYsIHc7XHJcblxyXG5cdFx0Ly8gYWxnb3JpdGhtIHRoYW5rcyB0byBSZWFsLVRpbWUgQ29sbGlzaW9uIERldGVjdGlvbiBieSBDaHJpc3RlciBFcmljc29uLFxyXG5cdFx0Ly8gcHVibGlzaGVkIGJ5IE1vcmdhbiBLYXVmbWFubiBQdWJsaXNoZXJzLCAoYykgMjAwNSBFbHNldmllciBJbmMuLFxyXG5cdFx0Ly8gdW5kZXIgdGhlIGFjY29tcGFueWluZyBsaWNlbnNlOyBzZWUgY2hhcHRlciA1LjEuNSBmb3IgZGV0YWlsZWQgZXhwbGFuYXRpb24uXHJcblx0XHQvLyBiYXNpY2FsbHksIHdlJ3JlIGRpc3Rpbmd1aXNoaW5nIHdoaWNoIG9mIHRoZSB2b3Jvbm9pIHJlZ2lvbnMgb2YgdGhlIHRyaWFuZ2xlXHJcblx0XHQvLyB0aGUgcG9pbnQgbGllcyBpbiB3aXRoIHRoZSBtaW5pbXVtIGFtb3VudCBvZiByZWR1bmRhbnQgY29tcHV0YXRpb24uXHJcblxyXG5cdFx0X3ZhYi5zdWJWZWN0b3JzKCBiLCBhICk7XHJcblx0XHRfdmFjLnN1YlZlY3RvcnMoIGMsIGEgKTtcclxuXHRcdF92YXAuc3ViVmVjdG9ycyggcCwgYSApO1xyXG5cdFx0Y29uc3QgZDEgPSBfdmFiLmRvdCggX3ZhcCApO1xyXG5cdFx0Y29uc3QgZDIgPSBfdmFjLmRvdCggX3ZhcCApO1xyXG5cdFx0aWYgKCBkMSA8PSAwICYmIGQyIDw9IDAgKSB7XHJcblxyXG5cdFx0XHQvLyB2ZXJ0ZXggcmVnaW9uIG9mIEE7IGJhcnljZW50cmljIGNvb3JkcyAoMSwgMCwgMClcclxuXHRcdFx0cmV0dXJuIHRhcmdldC5jb3B5KCBhICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdF92YnAuc3ViVmVjdG9ycyggcCwgYiApO1xyXG5cdFx0Y29uc3QgZDMgPSBfdmFiLmRvdCggX3ZicCApO1xyXG5cdFx0Y29uc3QgZDQgPSBfdmFjLmRvdCggX3ZicCApO1xyXG5cdFx0aWYgKCBkMyA+PSAwICYmIGQ0IDw9IGQzICkge1xyXG5cclxuXHRcdFx0Ly8gdmVydGV4IHJlZ2lvbiBvZiBCOyBiYXJ5Y2VudHJpYyBjb29yZHMgKDAsIDEsIDApXHJcblx0XHRcdHJldHVybiB0YXJnZXQuY29weSggYiApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCB2YyA9IGQxICogZDQgLSBkMyAqIGQyO1xyXG5cdFx0aWYgKCB2YyA8PSAwICYmIGQxID49IDAgJiYgZDMgPD0gMCApIHtcclxuXHJcblx0XHRcdHYgPSBkMSAvICggZDEgLSBkMyApO1xyXG5cdFx0XHQvLyBlZGdlIHJlZ2lvbiBvZiBBQjsgYmFyeWNlbnRyaWMgY29vcmRzICgxLXYsIHYsIDApXHJcblx0XHRcdHJldHVybiB0YXJnZXQuY29weSggYSApLmFkZFNjYWxlZFZlY3RvciggX3ZhYiwgdiApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRfdmNwLnN1YlZlY3RvcnMoIHAsIGMgKTtcclxuXHRcdGNvbnN0IGQ1ID0gX3ZhYi5kb3QoIF92Y3AgKTtcclxuXHRcdGNvbnN0IGQ2ID0gX3ZhYy5kb3QoIF92Y3AgKTtcclxuXHRcdGlmICggZDYgPj0gMCAmJiBkNSA8PSBkNiApIHtcclxuXHJcblx0XHRcdC8vIHZlcnRleCByZWdpb24gb2YgQzsgYmFyeWNlbnRyaWMgY29vcmRzICgwLCAwLCAxKVxyXG5cdFx0XHRyZXR1cm4gdGFyZ2V0LmNvcHkoIGMgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Y29uc3QgdmIgPSBkNSAqIGQyIC0gZDEgKiBkNjtcclxuXHRcdGlmICggdmIgPD0gMCAmJiBkMiA+PSAwICYmIGQ2IDw9IDAgKSB7XHJcblxyXG5cdFx0XHR3ID0gZDIgLyAoIGQyIC0gZDYgKTtcclxuXHRcdFx0Ly8gZWRnZSByZWdpb24gb2YgQUM7IGJhcnljZW50cmljIGNvb3JkcyAoMS13LCAwLCB3KVxyXG5cdFx0XHRyZXR1cm4gdGFyZ2V0LmNvcHkoIGEgKS5hZGRTY2FsZWRWZWN0b3IoIF92YWMsIHcgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Y29uc3QgdmEgPSBkMyAqIGQ2IC0gZDUgKiBkNDtcclxuXHRcdGlmICggdmEgPD0gMCAmJiAoIGQ0IC0gZDMgKSA+PSAwICYmICggZDUgLSBkNiApID49IDAgKSB7XHJcblxyXG5cdFx0XHRfdmJjLnN1YlZlY3RvcnMoIGMsIGIgKTtcclxuXHRcdFx0dyA9ICggZDQgLSBkMyApIC8gKCAoIGQ0IC0gZDMgKSArICggZDUgLSBkNiApICk7XHJcblx0XHRcdC8vIGVkZ2UgcmVnaW9uIG9mIEJDOyBiYXJ5Y2VudHJpYyBjb29yZHMgKDAsIDEtdywgdylcclxuXHRcdFx0cmV0dXJuIHRhcmdldC5jb3B5KCBiICkuYWRkU2NhbGVkVmVjdG9yKCBfdmJjLCB3ICk7IC8vIGVkZ2UgcmVnaW9uIG9mIEJDXHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIGZhY2UgcmVnaW9uXHJcblx0XHRjb25zdCBkZW5vbSA9IDEgLyAoIHZhICsgdmIgKyB2YyApO1xyXG5cdFx0Ly8gdSA9IHZhICogZGVub21cclxuXHRcdHYgPSB2YiAqIGRlbm9tO1xyXG5cdFx0dyA9IHZjICogZGVub207XHJcblxyXG5cdFx0cmV0dXJuIHRhcmdldC5jb3B5KCBhICkuYWRkU2NhbGVkVmVjdG9yKCBfdmFiLCB2ICkuYWRkU2NhbGVkVmVjdG9yKCBfdmFjLCB3ICk7XHJcblxyXG5cdH1cclxuXHJcblx0ZXF1YWxzKCB0cmlhbmdsZSApIHtcclxuXHJcblx0XHRyZXR1cm4gdHJpYW5nbGUuYS5lcXVhbHMoIHRoaXMuYSApICYmIHRyaWFuZ2xlLmIuZXF1YWxzKCB0aGlzLmIgKSAmJiB0cmlhbmdsZS5jLmVxdWFscyggdGhpcy5jICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IFRyaWFuZ2xlIH07XHJcbiIsImltcG9ydCB7IGNsYW1wLCBldWNsaWRlYW5Nb2R1bG8sIGxlcnAgfSBmcm9tICcuL01hdGhVdGlscy5qcyc7XHJcbmltcG9ydCB7IENvbG9yTWFuYWdlbWVudCwgU1JHQlRvTGluZWFyLCBMaW5lYXJUb1NSR0IgfSBmcm9tICcuL0NvbG9yTWFuYWdlbWVudC5qcyc7XHJcbmltcG9ydCB7IFNSR0JDb2xvclNwYWNlIH0gZnJvbSAnLi4vY29uc3RhbnRzLmpzJztcclxuXHJcbmNvbnN0IF9jb2xvcktleXdvcmRzID0geyAnYWxpY2VibHVlJzogMHhGMEY4RkYsICdhbnRpcXVld2hpdGUnOiAweEZBRUJENywgJ2FxdWEnOiAweDAwRkZGRiwgJ2FxdWFtYXJpbmUnOiAweDdGRkZENCwgJ2F6dXJlJzogMHhGMEZGRkYsXHJcblx0J2JlaWdlJzogMHhGNUY1REMsICdiaXNxdWUnOiAweEZGRTRDNCwgJ2JsYWNrJzogMHgwMDAwMDAsICdibGFuY2hlZGFsbW9uZCc6IDB4RkZFQkNELCAnYmx1ZSc6IDB4MDAwMEZGLCAnYmx1ZXZpb2xldCc6IDB4OEEyQkUyLFxyXG5cdCdicm93bic6IDB4QTUyQTJBLCAnYnVybHl3b29kJzogMHhERUI4ODcsICdjYWRldGJsdWUnOiAweDVGOUVBMCwgJ2NoYXJ0cmV1c2UnOiAweDdGRkYwMCwgJ2Nob2NvbGF0ZSc6IDB4RDI2OTFFLCAnY29yYWwnOiAweEZGN0Y1MCxcclxuXHQnY29ybmZsb3dlcmJsdWUnOiAweDY0OTVFRCwgJ2Nvcm5zaWxrJzogMHhGRkY4REMsICdjcmltc29uJzogMHhEQzE0M0MsICdjeWFuJzogMHgwMEZGRkYsICdkYXJrYmx1ZSc6IDB4MDAwMDhCLCAnZGFya2N5YW4nOiAweDAwOEI4QixcclxuXHQnZGFya2dvbGRlbnJvZCc6IDB4Qjg4NjBCLCAnZGFya2dyYXknOiAweEE5QTlBOSwgJ2RhcmtncmVlbic6IDB4MDA2NDAwLCAnZGFya2dyZXknOiAweEE5QTlBOSwgJ2RhcmtraGFraSc6IDB4QkRCNzZCLCAnZGFya21hZ2VudGEnOiAweDhCMDA4QixcclxuXHQnZGFya29saXZlZ3JlZW4nOiAweDU1NkIyRiwgJ2RhcmtvcmFuZ2UnOiAweEZGOEMwMCwgJ2RhcmtvcmNoaWQnOiAweDk5MzJDQywgJ2RhcmtyZWQnOiAweDhCMDAwMCwgJ2RhcmtzYWxtb24nOiAweEU5OTY3QSwgJ2RhcmtzZWFncmVlbic6IDB4OEZCQzhGLFxyXG5cdCdkYXJrc2xhdGVibHVlJzogMHg0ODNEOEIsICdkYXJrc2xhdGVncmF5JzogMHgyRjRGNEYsICdkYXJrc2xhdGVncmV5JzogMHgyRjRGNEYsICdkYXJrdHVycXVvaXNlJzogMHgwMENFRDEsICdkYXJrdmlvbGV0JzogMHg5NDAwRDMsXHJcblx0J2RlZXBwaW5rJzogMHhGRjE0OTMsICdkZWVwc2t5Ymx1ZSc6IDB4MDBCRkZGLCAnZGltZ3JheSc6IDB4Njk2OTY5LCAnZGltZ3JleSc6IDB4Njk2OTY5LCAnZG9kZ2VyYmx1ZSc6IDB4MUU5MEZGLCAnZmlyZWJyaWNrJzogMHhCMjIyMjIsXHJcblx0J2Zsb3JhbHdoaXRlJzogMHhGRkZBRjAsICdmb3Jlc3RncmVlbic6IDB4MjI4QjIyLCAnZnVjaHNpYSc6IDB4RkYwMEZGLCAnZ2FpbnNib3JvJzogMHhEQ0RDREMsICdnaG9zdHdoaXRlJzogMHhGOEY4RkYsICdnb2xkJzogMHhGRkQ3MDAsXHJcblx0J2dvbGRlbnJvZCc6IDB4REFBNTIwLCAnZ3JheSc6IDB4ODA4MDgwLCAnZ3JlZW4nOiAweDAwODAwMCwgJ2dyZWVueWVsbG93JzogMHhBREZGMkYsICdncmV5JzogMHg4MDgwODAsICdob25leWRldyc6IDB4RjBGRkYwLCAnaG90cGluayc6IDB4RkY2OUI0LFxyXG5cdCdpbmRpYW5yZWQnOiAweENENUM1QywgJ2luZGlnbyc6IDB4NEIwMDgyLCAnaXZvcnknOiAweEZGRkZGMCwgJ2toYWtpJzogMHhGMEU2OEMsICdsYXZlbmRlcic6IDB4RTZFNkZBLCAnbGF2ZW5kZXJibHVzaCc6IDB4RkZGMEY1LCAnbGF3bmdyZWVuJzogMHg3Q0ZDMDAsXHJcblx0J2xlbW9uY2hpZmZvbic6IDB4RkZGQUNELCAnbGlnaHRibHVlJzogMHhBREQ4RTYsICdsaWdodGNvcmFsJzogMHhGMDgwODAsICdsaWdodGN5YW4nOiAweEUwRkZGRiwgJ2xpZ2h0Z29sZGVucm9keWVsbG93JzogMHhGQUZBRDIsICdsaWdodGdyYXknOiAweEQzRDNEMyxcclxuXHQnbGlnaHRncmVlbic6IDB4OTBFRTkwLCAnbGlnaHRncmV5JzogMHhEM0QzRDMsICdsaWdodHBpbmsnOiAweEZGQjZDMSwgJ2xpZ2h0c2FsbW9uJzogMHhGRkEwN0EsICdsaWdodHNlYWdyZWVuJzogMHgyMEIyQUEsICdsaWdodHNreWJsdWUnOiAweDg3Q0VGQSxcclxuXHQnbGlnaHRzbGF0ZWdyYXknOiAweDc3ODg5OSwgJ2xpZ2h0c2xhdGVncmV5JzogMHg3Nzg4OTksICdsaWdodHN0ZWVsYmx1ZSc6IDB4QjBDNERFLCAnbGlnaHR5ZWxsb3cnOiAweEZGRkZFMCwgJ2xpbWUnOiAweDAwRkYwMCwgJ2xpbWVncmVlbic6IDB4MzJDRDMyLFxyXG5cdCdsaW5lbic6IDB4RkFGMEU2LCAnbWFnZW50YSc6IDB4RkYwMEZGLCAnbWFyb29uJzogMHg4MDAwMDAsICdtZWRpdW1hcXVhbWFyaW5lJzogMHg2NkNEQUEsICdtZWRpdW1ibHVlJzogMHgwMDAwQ0QsICdtZWRpdW1vcmNoaWQnOiAweEJBNTVEMyxcclxuXHQnbWVkaXVtcHVycGxlJzogMHg5MzcwREIsICdtZWRpdW1zZWFncmVlbic6IDB4M0NCMzcxLCAnbWVkaXVtc2xhdGVibHVlJzogMHg3QjY4RUUsICdtZWRpdW1zcHJpbmdncmVlbic6IDB4MDBGQTlBLCAnbWVkaXVtdHVycXVvaXNlJzogMHg0OEQxQ0MsXHJcblx0J21lZGl1bXZpb2xldHJlZCc6IDB4QzcxNTg1LCAnbWlkbmlnaHRibHVlJzogMHgxOTE5NzAsICdtaW50Y3JlYW0nOiAweEY1RkZGQSwgJ21pc3R5cm9zZSc6IDB4RkZFNEUxLCAnbW9jY2FzaW4nOiAweEZGRTRCNSwgJ25hdmFqb3doaXRlJzogMHhGRkRFQUQsXHJcblx0J25hdnknOiAweDAwMDA4MCwgJ29sZGxhY2UnOiAweEZERjVFNiwgJ29saXZlJzogMHg4MDgwMDAsICdvbGl2ZWRyYWInOiAweDZCOEUyMywgJ29yYW5nZSc6IDB4RkZBNTAwLCAnb3JhbmdlcmVkJzogMHhGRjQ1MDAsICdvcmNoaWQnOiAweERBNzBENixcclxuXHQncGFsZWdvbGRlbnJvZCc6IDB4RUVFOEFBLCAncGFsZWdyZWVuJzogMHg5OEZCOTgsICdwYWxldHVycXVvaXNlJzogMHhBRkVFRUUsICdwYWxldmlvbGV0cmVkJzogMHhEQjcwOTMsICdwYXBheWF3aGlwJzogMHhGRkVGRDUsICdwZWFjaHB1ZmYnOiAweEZGREFCOSxcclxuXHQncGVydSc6IDB4Q0Q4NTNGLCAncGluayc6IDB4RkZDMENCLCAncGx1bSc6IDB4RERBMERELCAncG93ZGVyYmx1ZSc6IDB4QjBFMEU2LCAncHVycGxlJzogMHg4MDAwODAsICdyZWJlY2NhcHVycGxlJzogMHg2NjMzOTksICdyZWQnOiAweEZGMDAwMCwgJ3Jvc3licm93bic6IDB4QkM4RjhGLFxyXG5cdCdyb3lhbGJsdWUnOiAweDQxNjlFMSwgJ3NhZGRsZWJyb3duJzogMHg4QjQ1MTMsICdzYWxtb24nOiAweEZBODA3MiwgJ3NhbmR5YnJvd24nOiAweEY0QTQ2MCwgJ3NlYWdyZWVuJzogMHgyRThCNTcsICdzZWFzaGVsbCc6IDB4RkZGNUVFLFxyXG5cdCdzaWVubmEnOiAweEEwNTIyRCwgJ3NpbHZlcic6IDB4QzBDMEMwLCAnc2t5Ymx1ZSc6IDB4ODdDRUVCLCAnc2xhdGVibHVlJzogMHg2QTVBQ0QsICdzbGF0ZWdyYXknOiAweDcwODA5MCwgJ3NsYXRlZ3JleSc6IDB4NzA4MDkwLCAnc25vdyc6IDB4RkZGQUZBLFxyXG5cdCdzcHJpbmdncmVlbic6IDB4MDBGRjdGLCAnc3RlZWxibHVlJzogMHg0NjgyQjQsICd0YW4nOiAweEQyQjQ4QywgJ3RlYWwnOiAweDAwODA4MCwgJ3RoaXN0bGUnOiAweEQ4QkZEOCwgJ3RvbWF0byc6IDB4RkY2MzQ3LCAndHVycXVvaXNlJzogMHg0MEUwRDAsXHJcblx0J3Zpb2xldCc6IDB4RUU4MkVFLCAnd2hlYXQnOiAweEY1REVCMywgJ3doaXRlJzogMHhGRkZGRkYsICd3aGl0ZXNtb2tlJzogMHhGNUY1RjUsICd5ZWxsb3cnOiAweEZGRkYwMCwgJ3llbGxvd2dyZWVuJzogMHg5QUNEMzIgfTtcclxuXHJcbmNvbnN0IF9oc2xBID0geyBoOiAwLCBzOiAwLCBsOiAwIH07XHJcbmNvbnN0IF9oc2xCID0geyBoOiAwLCBzOiAwLCBsOiAwIH07XHJcblxyXG5mdW5jdGlvbiBodWUycmdiKCBwLCBxLCB0ICkge1xyXG5cclxuXHRpZiAoIHQgPCAwICkgdCArPSAxO1xyXG5cdGlmICggdCA+IDEgKSB0IC09IDE7XHJcblx0aWYgKCB0IDwgMSAvIDYgKSByZXR1cm4gcCArICggcSAtIHAgKSAqIDYgKiB0O1xyXG5cdGlmICggdCA8IDEgLyAyICkgcmV0dXJuIHE7XHJcblx0aWYgKCB0IDwgMiAvIDMgKSByZXR1cm4gcCArICggcSAtIHAgKSAqIDYgKiAoIDIgLyAzIC0gdCApO1xyXG5cdHJldHVybiBwO1xyXG5cclxufVxyXG5cclxuY2xhc3MgQ29sb3Ige1xyXG5cclxuXHRjb25zdHJ1Y3RvciggciwgZywgYiApIHtcclxuXHJcblx0XHR0aGlzLmlzQ29sb3IgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMuciA9IDE7XHJcblx0XHR0aGlzLmcgPSAxO1xyXG5cdFx0dGhpcy5iID0gMTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5zZXQoIHIsIGcsIGIgKTtcclxuXHJcblx0fVxyXG5cclxuXHRzZXQoIHIsIGcsIGIgKSB7XHJcblxyXG5cdFx0aWYgKCBnID09PSB1bmRlZmluZWQgJiYgYiA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0Ly8gciBpcyBUSFJFRS5Db2xvciwgaGV4IG9yIHN0cmluZ1xyXG5cclxuXHRcdFx0Y29uc3QgdmFsdWUgPSByO1xyXG5cclxuXHRcdFx0aWYgKCB2YWx1ZSAmJiB2YWx1ZS5pc0NvbG9yICkge1xyXG5cclxuXHRcdFx0XHR0aGlzLmNvcHkoIHZhbHVlICk7XHJcblxyXG5cdFx0XHR9IGVsc2UgaWYgKCB0eXBlb2YgdmFsdWUgPT09ICdudW1iZXInICkge1xyXG5cclxuXHRcdFx0XHR0aGlzLnNldEhleCggdmFsdWUgKTtcclxuXHJcblx0XHRcdH0gZWxzZSBpZiAoIHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZycgKSB7XHJcblxyXG5cdFx0XHRcdHRoaXMuc2V0U3R5bGUoIHZhbHVlICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdHRoaXMuc2V0UkdCKCByLCBnLCBiICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldFNjYWxhciggc2NhbGFyICkge1xyXG5cclxuXHRcdHRoaXMuciA9IHNjYWxhcjtcclxuXHRcdHRoaXMuZyA9IHNjYWxhcjtcclxuXHRcdHRoaXMuYiA9IHNjYWxhcjtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRIZXgoIGhleCwgY29sb3JTcGFjZSA9IFNSR0JDb2xvclNwYWNlICkge1xyXG5cclxuXHRcdGhleCA9IE1hdGguZmxvb3IoIGhleCApO1xyXG5cclxuXHRcdHRoaXMuciA9ICggaGV4ID4+IDE2ICYgMjU1ICkgLyAyNTU7XHJcblx0XHR0aGlzLmcgPSAoIGhleCA+PiA4ICYgMjU1ICkgLyAyNTU7XHJcblx0XHR0aGlzLmIgPSAoIGhleCAmIDI1NSApIC8gMjU1O1xyXG5cclxuXHRcdENvbG9yTWFuYWdlbWVudC50b1dvcmtpbmdDb2xvclNwYWNlKCB0aGlzLCBjb2xvclNwYWNlICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0UkdCKCByLCBnLCBiLCBjb2xvclNwYWNlID0gQ29sb3JNYW5hZ2VtZW50LndvcmtpbmdDb2xvclNwYWNlICkge1xyXG5cclxuXHRcdHRoaXMuciA9IHI7XHJcblx0XHR0aGlzLmcgPSBnO1xyXG5cdFx0dGhpcy5iID0gYjtcclxuXHJcblx0XHRDb2xvck1hbmFnZW1lbnQudG9Xb3JraW5nQ29sb3JTcGFjZSggdGhpcywgY29sb3JTcGFjZSApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldEhTTCggaCwgcywgbCwgY29sb3JTcGFjZSA9IENvbG9yTWFuYWdlbWVudC53b3JraW5nQ29sb3JTcGFjZSApIHtcclxuXHJcblx0XHQvLyBoLHMsbCByYW5nZXMgYXJlIGluIDAuMCAtIDEuMFxyXG5cdFx0aCA9IGV1Y2xpZGVhbk1vZHVsbyggaCwgMSApO1xyXG5cdFx0cyA9IGNsYW1wKCBzLCAwLCAxICk7XHJcblx0XHRsID0gY2xhbXAoIGwsIDAsIDEgKTtcclxuXHJcblx0XHRpZiAoIHMgPT09IDAgKSB7XHJcblxyXG5cdFx0XHR0aGlzLnIgPSB0aGlzLmcgPSB0aGlzLmIgPSBsO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRjb25zdCBwID0gbCA8PSAwLjUgPyBsICogKCAxICsgcyApIDogbCArIHMgLSAoIGwgKiBzICk7XHJcblx0XHRcdGNvbnN0IHEgPSAoIDIgKiBsICkgLSBwO1xyXG5cclxuXHRcdFx0dGhpcy5yID0gaHVlMnJnYiggcSwgcCwgaCArIDEgLyAzICk7XHJcblx0XHRcdHRoaXMuZyA9IGh1ZTJyZ2IoIHEsIHAsIGggKTtcclxuXHRcdFx0dGhpcy5iID0gaHVlMnJnYiggcSwgcCwgaCAtIDEgLyAzICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdENvbG9yTWFuYWdlbWVudC50b1dvcmtpbmdDb2xvclNwYWNlKCB0aGlzLCBjb2xvclNwYWNlICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0U3R5bGUoIHN0eWxlLCBjb2xvclNwYWNlID0gU1JHQkNvbG9yU3BhY2UgKSB7XHJcblxyXG5cdFx0ZnVuY3Rpb24gaGFuZGxlQWxwaGEoIHN0cmluZyApIHtcclxuXHJcblx0XHRcdGlmICggc3RyaW5nID09PSB1bmRlZmluZWQgKSByZXR1cm47XHJcblxyXG5cdFx0XHRpZiAoIHBhcnNlRmxvYXQoIHN0cmluZyApIDwgMSApIHtcclxuXHJcblx0XHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuQ29sb3I6IEFscGhhIGNvbXBvbmVudCBvZiAnICsgc3R5bGUgKyAnIHdpbGwgYmUgaWdub3JlZC4nICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHJcblx0XHRsZXQgbTtcclxuXHJcblx0XHRpZiAoIG0gPSAvXihcXHcrKVxcKChbXlxcKV0qKVxcKS8uZXhlYyggc3R5bGUgKSApIHtcclxuXHJcblx0XHRcdC8vIHJnYiAvIGhzbFxyXG5cclxuXHRcdFx0bGV0IGNvbG9yO1xyXG5cdFx0XHRjb25zdCBuYW1lID0gbVsgMSBdO1xyXG5cdFx0XHRjb25zdCBjb21wb25lbnRzID0gbVsgMiBdO1xyXG5cclxuXHRcdFx0c3dpdGNoICggbmFtZSApIHtcclxuXHJcblx0XHRcdFx0Y2FzZSAncmdiJzpcclxuXHRcdFx0XHRjYXNlICdyZ2JhJzpcclxuXHJcblx0XHRcdFx0XHRpZiAoIGNvbG9yID0gL15cXHMqKFxcZCspXFxzKixcXHMqKFxcZCspXFxzKixcXHMqKFxcZCspXFxzKig/OixcXHMqKFxcZCpcXC4/XFxkKylcXHMqKT8kLy5leGVjKCBjb21wb25lbnRzICkgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHQvLyByZ2IoMjU1LDAsMCkgcmdiYSgyNTUsMCwwLDAuNSlcclxuXHJcblx0XHRcdFx0XHRcdGhhbmRsZUFscGhhKCBjb2xvclsgNCBdICk7XHJcblxyXG5cdFx0XHRcdFx0XHRyZXR1cm4gdGhpcy5zZXRSR0IoXHJcblx0XHRcdFx0XHRcdFx0TWF0aC5taW4oIDI1NSwgcGFyc2VJbnQoIGNvbG9yWyAxIF0sIDEwICkgKSAvIDI1NSxcclxuXHRcdFx0XHRcdFx0XHRNYXRoLm1pbiggMjU1LCBwYXJzZUludCggY29sb3JbIDIgXSwgMTAgKSApIC8gMjU1LFxyXG5cdFx0XHRcdFx0XHRcdE1hdGgubWluKCAyNTUsIHBhcnNlSW50KCBjb2xvclsgMyBdLCAxMCApICkgLyAyNTUsXHJcblx0XHRcdFx0XHRcdFx0Y29sb3JTcGFjZVxyXG5cdFx0XHRcdFx0XHQpO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRpZiAoIGNvbG9yID0gL15cXHMqKFxcZCspXFwlXFxzKixcXHMqKFxcZCspXFwlXFxzKixcXHMqKFxcZCspXFwlXFxzKig/OixcXHMqKFxcZCpcXC4/XFxkKylcXHMqKT8kLy5leGVjKCBjb21wb25lbnRzICkgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHQvLyByZ2IoMTAwJSwwJSwwJSkgcmdiYSgxMDAlLDAlLDAlLDAuNSlcclxuXHJcblx0XHRcdFx0XHRcdGhhbmRsZUFscGhhKCBjb2xvclsgNCBdICk7XHJcblxyXG5cdFx0XHRcdFx0XHRyZXR1cm4gdGhpcy5zZXRSR0IoXHJcblx0XHRcdFx0XHRcdFx0TWF0aC5taW4oIDEwMCwgcGFyc2VJbnQoIGNvbG9yWyAxIF0sIDEwICkgKSAvIDEwMCxcclxuXHRcdFx0XHRcdFx0XHRNYXRoLm1pbiggMTAwLCBwYXJzZUludCggY29sb3JbIDIgXSwgMTAgKSApIC8gMTAwLFxyXG5cdFx0XHRcdFx0XHRcdE1hdGgubWluKCAxMDAsIHBhcnNlSW50KCBjb2xvclsgMyBdLCAxMCApICkgLyAxMDAsXHJcblx0XHRcdFx0XHRcdFx0Y29sb3JTcGFjZVxyXG5cdFx0XHRcdFx0XHQpO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdFx0Y2FzZSAnaHNsJzpcclxuXHRcdFx0XHRjYXNlICdoc2xhJzpcclxuXHJcblx0XHRcdFx0XHRpZiAoIGNvbG9yID0gL15cXHMqKFxcZCpcXC4/XFxkKylcXHMqLFxccyooXFxkKlxcLj9cXGQrKVxcJVxccyosXFxzKihcXGQqXFwuP1xcZCspXFwlXFxzKig/OixcXHMqKFxcZCpcXC4/XFxkKylcXHMqKT8kLy5leGVjKCBjb21wb25lbnRzICkgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHQvLyBoc2woMTIwLDUwJSw1MCUpIGhzbGEoMTIwLDUwJSw1MCUsMC41KVxyXG5cclxuXHRcdFx0XHRcdFx0aGFuZGxlQWxwaGEoIGNvbG9yWyA0IF0gKTtcclxuXHJcblx0XHRcdFx0XHRcdHJldHVybiB0aGlzLnNldEhTTChcclxuXHRcdFx0XHRcdFx0XHRwYXJzZUZsb2F0KCBjb2xvclsgMSBdICkgLyAzNjAsXHJcblx0XHRcdFx0XHRcdFx0cGFyc2VGbG9hdCggY29sb3JbIDIgXSApIC8gMTAwLFxyXG5cdFx0XHRcdFx0XHRcdHBhcnNlRmxvYXQoIGNvbG9yWyAzIF0gKSAvIDEwMCxcclxuXHRcdFx0XHRcdFx0XHRjb2xvclNwYWNlXHJcblx0XHRcdFx0XHRcdCk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0XHRkZWZhdWx0OlxyXG5cclxuXHRcdFx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLkNvbG9yOiBVbmtub3duIGNvbG9yIG1vZGVsICcgKyBzdHlsZSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH0gZWxzZSBpZiAoIG0gPSAvXlxcIyhbQS1GYS1mXFxkXSspJC8uZXhlYyggc3R5bGUgKSApIHtcclxuXHJcblx0XHRcdC8vIGhleCBjb2xvclxyXG5cclxuXHRcdFx0Y29uc3QgaGV4ID0gbVsgMSBdO1xyXG5cdFx0XHRjb25zdCBzaXplID0gaGV4Lmxlbmd0aDtcclxuXHJcblx0XHRcdGlmICggc2l6ZSA9PT0gMyApIHtcclxuXHJcblx0XHRcdFx0Ly8gI2ZmMFxyXG5cdFx0XHRcdHJldHVybiB0aGlzLnNldFJHQihcclxuXHRcdFx0XHRcdHBhcnNlSW50KCBoZXguY2hhckF0KCAwICksIDE2ICkgLyAxNSxcclxuXHRcdFx0XHRcdHBhcnNlSW50KCBoZXguY2hhckF0KCAxICksIDE2ICkgLyAxNSxcclxuXHRcdFx0XHRcdHBhcnNlSW50KCBoZXguY2hhckF0KCAyICksIDE2ICkgLyAxNSxcclxuXHRcdFx0XHRcdGNvbG9yU3BhY2VcclxuXHRcdFx0XHQpO1xyXG5cclxuXHRcdFx0fSBlbHNlIGlmICggc2l6ZSA9PT0gNiApIHtcclxuXHJcblx0XHRcdFx0Ly8gI2ZmMDAwMFxyXG5cdFx0XHRcdHJldHVybiB0aGlzLnNldEhleCggcGFyc2VJbnQoIGhleCwgMTYgKSwgY29sb3JTcGFjZSApO1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuQ29sb3I6IEludmFsaWQgaGV4IGNvbG9yICcgKyBzdHlsZSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH0gZWxzZSBpZiAoIHN0eWxlICYmIHN0eWxlLmxlbmd0aCA+IDAgKSB7XHJcblxyXG5cdFx0XHRyZXR1cm4gdGhpcy5zZXRDb2xvck5hbWUoIHN0eWxlLCBjb2xvclNwYWNlICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldENvbG9yTmFtZSggc3R5bGUsIGNvbG9yU3BhY2UgPSBTUkdCQ29sb3JTcGFjZSApIHtcclxuXHJcblx0XHQvLyBjb2xvciBrZXl3b3Jkc1xyXG5cdFx0Y29uc3QgaGV4ID0gX2NvbG9yS2V5d29yZHNbIHN0eWxlLnRvTG93ZXJDYXNlKCkgXTtcclxuXHJcblx0XHRpZiAoIGhleCAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0Ly8gcmVkXHJcblx0XHRcdHRoaXMuc2V0SGV4KCBoZXgsIGNvbG9yU3BhY2UgKTtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0Ly8gdW5rbm93biBjb2xvclxyXG5cdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5Db2xvcjogVW5rbm93biBjb2xvciAnICsgc3R5bGUgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Y2xvbmUoKSB7XHJcblxyXG5cdFx0cmV0dXJuIG5ldyB0aGlzLmNvbnN0cnVjdG9yKCB0aGlzLnIsIHRoaXMuZywgdGhpcy5iICk7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggY29sb3IgKSB7XHJcblxyXG5cdFx0dGhpcy5yID0gY29sb3IucjtcclxuXHRcdHRoaXMuZyA9IGNvbG9yLmc7XHJcblx0XHR0aGlzLmIgPSBjb2xvci5iO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGNvcHlTUkdCVG9MaW5lYXIoIGNvbG9yICkge1xyXG5cclxuXHRcdHRoaXMuciA9IFNSR0JUb0xpbmVhciggY29sb3IuciApO1xyXG5cdFx0dGhpcy5nID0gU1JHQlRvTGluZWFyKCBjb2xvci5nICk7XHJcblx0XHR0aGlzLmIgPSBTUkdCVG9MaW5lYXIoIGNvbG9yLmIgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRjb3B5TGluZWFyVG9TUkdCKCBjb2xvciApIHtcclxuXHJcblx0XHR0aGlzLnIgPSBMaW5lYXJUb1NSR0IoIGNvbG9yLnIgKTtcclxuXHRcdHRoaXMuZyA9IExpbmVhclRvU1JHQiggY29sb3IuZyApO1xyXG5cdFx0dGhpcy5iID0gTGluZWFyVG9TUkdCKCBjb2xvci5iICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Y29udmVydFNSR0JUb0xpbmVhcigpIHtcclxuXHJcblx0XHR0aGlzLmNvcHlTUkdCVG9MaW5lYXIoIHRoaXMgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRjb252ZXJ0TGluZWFyVG9TUkdCKCkge1xyXG5cclxuXHRcdHRoaXMuY29weUxpbmVhclRvU1JHQiggdGhpcyApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldEhleCggY29sb3JTcGFjZSA9IFNSR0JDb2xvclNwYWNlICkge1xyXG5cclxuXHRcdENvbG9yTWFuYWdlbWVudC5mcm9tV29ya2luZ0NvbG9yU3BhY2UoIF9jb2xvci5jb3B5KCB0aGlzICksIGNvbG9yU3BhY2UgKTtcclxuXHJcblx0XHRyZXR1cm4gTWF0aC5yb3VuZCggY2xhbXAoIF9jb2xvci5yICogMjU1LCAwLCAyNTUgKSApICogNjU1MzYgKyBNYXRoLnJvdW5kKCBjbGFtcCggX2NvbG9yLmcgKiAyNTUsIDAsIDI1NSApICkgKiAyNTYgKyBNYXRoLnJvdW5kKCBjbGFtcCggX2NvbG9yLmIgKiAyNTUsIDAsIDI1NSApICk7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0SGV4U3RyaW5nKCBjb2xvclNwYWNlID0gU1JHQkNvbG9yU3BhY2UgKSB7XHJcblxyXG5cdFx0cmV0dXJuICggJzAwMDAwMCcgKyB0aGlzLmdldEhleCggY29sb3JTcGFjZSApLnRvU3RyaW5nKCAxNiApICkuc2xpY2UoIC0gNiApO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldEhTTCggdGFyZ2V0LCBjb2xvclNwYWNlID0gQ29sb3JNYW5hZ2VtZW50LndvcmtpbmdDb2xvclNwYWNlICkge1xyXG5cclxuXHRcdC8vIGgscyxsIHJhbmdlcyBhcmUgaW4gMC4wIC0gMS4wXHJcblxyXG5cdFx0Q29sb3JNYW5hZ2VtZW50LmZyb21Xb3JraW5nQ29sb3JTcGFjZSggX2NvbG9yLmNvcHkoIHRoaXMgKSwgY29sb3JTcGFjZSApO1xyXG5cclxuXHRcdGNvbnN0IHIgPSBfY29sb3IuciwgZyA9IF9jb2xvci5nLCBiID0gX2NvbG9yLmI7XHJcblxyXG5cdFx0Y29uc3QgbWF4ID0gTWF0aC5tYXgoIHIsIGcsIGIgKTtcclxuXHRcdGNvbnN0IG1pbiA9IE1hdGgubWluKCByLCBnLCBiICk7XHJcblxyXG5cdFx0bGV0IGh1ZSwgc2F0dXJhdGlvbjtcclxuXHRcdGNvbnN0IGxpZ2h0bmVzcyA9ICggbWluICsgbWF4ICkgLyAyLjA7XHJcblxyXG5cdFx0aWYgKCBtaW4gPT09IG1heCApIHtcclxuXHJcblx0XHRcdGh1ZSA9IDA7XHJcblx0XHRcdHNhdHVyYXRpb24gPSAwO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRjb25zdCBkZWx0YSA9IG1heCAtIG1pbjtcclxuXHJcblx0XHRcdHNhdHVyYXRpb24gPSBsaWdodG5lc3MgPD0gMC41ID8gZGVsdGEgLyAoIG1heCArIG1pbiApIDogZGVsdGEgLyAoIDIgLSBtYXggLSBtaW4gKTtcclxuXHJcblx0XHRcdHN3aXRjaCAoIG1heCApIHtcclxuXHJcblx0XHRcdFx0Y2FzZSByOiBodWUgPSAoIGcgLSBiICkgLyBkZWx0YSArICggZyA8IGIgPyA2IDogMCApOyBicmVhaztcclxuXHRcdFx0XHRjYXNlIGc6IGh1ZSA9ICggYiAtIHIgKSAvIGRlbHRhICsgMjsgYnJlYWs7XHJcblx0XHRcdFx0Y2FzZSBiOiBodWUgPSAoIHIgLSBnICkgLyBkZWx0YSArIDQ7IGJyZWFrO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0aHVlIC89IDY7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRhcmdldC5oID0gaHVlO1xyXG5cdFx0dGFyZ2V0LnMgPSBzYXR1cmF0aW9uO1xyXG5cdFx0dGFyZ2V0LmwgPSBsaWdodG5lc3M7XHJcblxyXG5cdFx0cmV0dXJuIHRhcmdldDtcclxuXHJcblx0fVxyXG5cclxuXHRnZXRSR0IoIHRhcmdldCwgY29sb3JTcGFjZSA9IENvbG9yTWFuYWdlbWVudC53b3JraW5nQ29sb3JTcGFjZSApIHtcclxuXHJcblx0XHRDb2xvck1hbmFnZW1lbnQuZnJvbVdvcmtpbmdDb2xvclNwYWNlKCBfY29sb3IuY29weSggdGhpcyApLCBjb2xvclNwYWNlICk7XHJcblxyXG5cdFx0dGFyZ2V0LnIgPSBfY29sb3IucjtcclxuXHRcdHRhcmdldC5nID0gX2NvbG9yLmc7XHJcblx0XHR0YXJnZXQuYiA9IF9jb2xvci5iO1xyXG5cclxuXHRcdHJldHVybiB0YXJnZXQ7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0U3R5bGUoIGNvbG9yU3BhY2UgPSBTUkdCQ29sb3JTcGFjZSApIHtcclxuXHJcblx0XHRDb2xvck1hbmFnZW1lbnQuZnJvbVdvcmtpbmdDb2xvclNwYWNlKCBfY29sb3IuY29weSggdGhpcyApLCBjb2xvclNwYWNlICk7XHJcblxyXG5cdFx0Y29uc3QgciA9IF9jb2xvci5yLCBnID0gX2NvbG9yLmcsIGIgPSBfY29sb3IuYjtcclxuXHJcblx0XHRpZiAoIGNvbG9yU3BhY2UgIT09IFNSR0JDb2xvclNwYWNlICkge1xyXG5cclxuXHRcdFx0Ly8gUmVxdWlyZXMgQ1NTIENvbG9yIE1vZHVsZSBMZXZlbCA0IChodHRwczovL3d3dy53My5vcmcvVFIvY3NzLWNvbG9yLTQvKS5cclxuXHRcdFx0cmV0dXJuIGBjb2xvcigkeyBjb2xvclNwYWNlIH0gJHsgci50b0ZpeGVkKCAzICkgfSAkeyBnLnRvRml4ZWQoIDMgKSB9ICR7IGIudG9GaXhlZCggMyApIH0pYDtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIGByZ2IoJHsgTWF0aC5yb3VuZCggciAqIDI1NSApIH0sJHsgTWF0aC5yb3VuZCggZyAqIDI1NSApIH0sJHsgTWF0aC5yb3VuZCggYiAqIDI1NSApIH0pYDtcclxuXHJcblx0fVxyXG5cclxuXHRvZmZzZXRIU0woIGgsIHMsIGwgKSB7XHJcblxyXG5cdFx0dGhpcy5nZXRIU0woIF9oc2xBICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuc2V0SFNMKCBfaHNsQS5oICsgaCwgX2hzbEEucyArIHMsIF9oc2xBLmwgKyBsICk7XHJcblxyXG5cdH1cclxuXHJcblx0YWRkKCBjb2xvciApIHtcclxuXHJcblx0XHR0aGlzLnIgKz0gY29sb3IucjtcclxuXHRcdHRoaXMuZyArPSBjb2xvci5nO1xyXG5cdFx0dGhpcy5iICs9IGNvbG9yLmI7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0YWRkQ29sb3JzKCBjb2xvcjEsIGNvbG9yMiApIHtcclxuXHJcblx0XHR0aGlzLnIgPSBjb2xvcjEuciArIGNvbG9yMi5yO1xyXG5cdFx0dGhpcy5nID0gY29sb3IxLmcgKyBjb2xvcjIuZztcclxuXHRcdHRoaXMuYiA9IGNvbG9yMS5iICsgY29sb3IyLmI7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0YWRkU2NhbGFyKCBzICkge1xyXG5cclxuXHRcdHRoaXMuciArPSBzO1xyXG5cdFx0dGhpcy5nICs9IHM7XHJcblx0XHR0aGlzLmIgKz0gcztcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzdWIoIGNvbG9yICkge1xyXG5cclxuXHRcdHRoaXMuciA9IE1hdGgubWF4KCAwLCB0aGlzLnIgLSBjb2xvci5yICk7XHJcblx0XHR0aGlzLmcgPSBNYXRoLm1heCggMCwgdGhpcy5nIC0gY29sb3IuZyApO1xyXG5cdFx0dGhpcy5iID0gTWF0aC5tYXgoIDAsIHRoaXMuYiAtIGNvbG9yLmIgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRtdWx0aXBseSggY29sb3IgKSB7XHJcblxyXG5cdFx0dGhpcy5yICo9IGNvbG9yLnI7XHJcblx0XHR0aGlzLmcgKj0gY29sb3IuZztcclxuXHRcdHRoaXMuYiAqPSBjb2xvci5iO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdG11bHRpcGx5U2NhbGFyKCBzICkge1xyXG5cclxuXHRcdHRoaXMuciAqPSBzO1xyXG5cdFx0dGhpcy5nICo9IHM7XHJcblx0XHR0aGlzLmIgKj0gcztcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRsZXJwKCBjb2xvciwgYWxwaGEgKSB7XHJcblxyXG5cdFx0dGhpcy5yICs9ICggY29sb3IuciAtIHRoaXMuciApICogYWxwaGE7XHJcblx0XHR0aGlzLmcgKz0gKCBjb2xvci5nIC0gdGhpcy5nICkgKiBhbHBoYTtcclxuXHRcdHRoaXMuYiArPSAoIGNvbG9yLmIgLSB0aGlzLmIgKSAqIGFscGhhO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGxlcnBDb2xvcnMoIGNvbG9yMSwgY29sb3IyLCBhbHBoYSApIHtcclxuXHJcblx0XHR0aGlzLnIgPSBjb2xvcjEuciArICggY29sb3IyLnIgLSBjb2xvcjEuciApICogYWxwaGE7XHJcblx0XHR0aGlzLmcgPSBjb2xvcjEuZyArICggY29sb3IyLmcgLSBjb2xvcjEuZyApICogYWxwaGE7XHJcblx0XHR0aGlzLmIgPSBjb2xvcjEuYiArICggY29sb3IyLmIgLSBjb2xvcjEuYiApICogYWxwaGE7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0bGVycEhTTCggY29sb3IsIGFscGhhICkge1xyXG5cclxuXHRcdHRoaXMuZ2V0SFNMKCBfaHNsQSApO1xyXG5cdFx0Y29sb3IuZ2V0SFNMKCBfaHNsQiApO1xyXG5cclxuXHRcdGNvbnN0IGggPSBsZXJwKCBfaHNsQS5oLCBfaHNsQi5oLCBhbHBoYSApO1xyXG5cdFx0Y29uc3QgcyA9IGxlcnAoIF9oc2xBLnMsIF9oc2xCLnMsIGFscGhhICk7XHJcblx0XHRjb25zdCBsID0gbGVycCggX2hzbEEubCwgX2hzbEIubCwgYWxwaGEgKTtcclxuXHJcblx0XHR0aGlzLnNldEhTTCggaCwgcywgbCApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldEZyb21WZWN0b3IzKCB2ICkge1xyXG5cclxuXHRcdHRoaXMuciA9IHYueDtcclxuXHRcdHRoaXMuZyA9IHYueTtcclxuXHRcdHRoaXMuYiA9IHYuejtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRhcHBseU1hdHJpeDMoIG0gKSB7XHJcblxyXG5cdFx0Y29uc3QgciA9IHRoaXMuciwgZyA9IHRoaXMuZywgYiA9IHRoaXMuYjtcclxuXHRcdGNvbnN0IGUgPSBtLmVsZW1lbnRzO1xyXG5cclxuXHRcdHRoaXMuciA9IGVbIDAgXSAqIHIgKyBlWyAzIF0gKiBnICsgZVsgNiBdICogYjtcclxuXHRcdHRoaXMuZyA9IGVbIDEgXSAqIHIgKyBlWyA0IF0gKiBnICsgZVsgNyBdICogYjtcclxuXHRcdHRoaXMuYiA9IGVbIDIgXSAqIHIgKyBlWyA1IF0gKiBnICsgZVsgOCBdICogYjtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRlcXVhbHMoIGMgKSB7XHJcblxyXG5cdFx0cmV0dXJuICggYy5yID09PSB0aGlzLnIgKSAmJiAoIGMuZyA9PT0gdGhpcy5nICkgJiYgKCBjLmIgPT09IHRoaXMuYiApO1xyXG5cclxuXHR9XHJcblxyXG5cdGZyb21BcnJheSggYXJyYXksIG9mZnNldCA9IDAgKSB7XHJcblxyXG5cdFx0dGhpcy5yID0gYXJyYXlbIG9mZnNldCBdO1xyXG5cdFx0dGhpcy5nID0gYXJyYXlbIG9mZnNldCArIDEgXTtcclxuXHRcdHRoaXMuYiA9IGFycmF5WyBvZmZzZXQgKyAyIF07XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0dG9BcnJheSggYXJyYXkgPSBbXSwgb2Zmc2V0ID0gMCApIHtcclxuXHJcblx0XHRhcnJheVsgb2Zmc2V0IF0gPSB0aGlzLnI7XHJcblx0XHRhcnJheVsgb2Zmc2V0ICsgMSBdID0gdGhpcy5nO1xyXG5cdFx0YXJyYXlbIG9mZnNldCArIDIgXSA9IHRoaXMuYjtcclxuXHJcblx0XHRyZXR1cm4gYXJyYXk7XHJcblxyXG5cdH1cclxuXHJcblx0ZnJvbUJ1ZmZlckF0dHJpYnV0ZSggYXR0cmlidXRlLCBpbmRleCApIHtcclxuXHJcblx0XHR0aGlzLnIgPSBhdHRyaWJ1dGUuZ2V0WCggaW5kZXggKTtcclxuXHRcdHRoaXMuZyA9IGF0dHJpYnV0ZS5nZXRZKCBpbmRleCApO1xyXG5cdFx0dGhpcy5iID0gYXR0cmlidXRlLmdldFooIGluZGV4ICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0dG9KU09OKCkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLmdldEhleCgpO1xyXG5cclxuXHR9XHJcblxyXG5cdCpbIFN5bWJvbC5pdGVyYXRvciBdKCkge1xyXG5cclxuXHRcdHlpZWxkIHRoaXMucjtcclxuXHRcdHlpZWxkIHRoaXMuZztcclxuXHRcdHlpZWxkIHRoaXMuYjtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuY29uc3QgX2NvbG9yID0gLypAX19QVVJFX18qLyBuZXcgQ29sb3IoKTtcclxuXHJcbkNvbG9yLk5BTUVTID0gX2NvbG9yS2V5d29yZHM7XHJcblxyXG5leHBvcnQgeyBDb2xvciB9O1xyXG4iLCJpbXBvcnQgeyBDb2xvciB9IGZyb20gJy4uL21hdGgvQ29sb3IuanMnO1xyXG5pbXBvcnQgeyBFdmVudERpc3BhdGNoZXIgfSBmcm9tICcuLi9jb3JlL0V2ZW50RGlzcGF0Y2hlci5qcyc7XHJcbmltcG9ydCB7IEZyb250U2lkZSwgTm9ybWFsQmxlbmRpbmcsIExlc3NFcXVhbERlcHRoLCBBZGRFcXVhdGlvbiwgT25lTWludXNTcmNBbHBoYUZhY3RvciwgU3JjQWxwaGFGYWN0b3IsIEFsd2F5c1N0ZW5jaWxGdW5jLCBLZWVwU3RlbmNpbE9wIH0gZnJvbSAnLi4vY29uc3RhbnRzLmpzJztcclxuaW1wb3J0ICogYXMgTWF0aFV0aWxzIGZyb20gJy4uL21hdGgvTWF0aFV0aWxzLmpzJztcclxuXHJcbmxldCBfbWF0ZXJpYWxJZCA9IDA7XHJcblxyXG5jbGFzcyBNYXRlcmlhbCBleHRlbmRzIEV2ZW50RGlzcGF0Y2hlciB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCkge1xyXG5cclxuXHRcdHN1cGVyKCk7XHJcblxyXG5cdFx0dGhpcy5pc01hdGVyaWFsID0gdHJ1ZTtcclxuXHJcblx0XHRPYmplY3QuZGVmaW5lUHJvcGVydHkoIHRoaXMsICdpZCcsIHsgdmFsdWU6IF9tYXRlcmlhbElkICsrIH0gKTtcclxuXHJcblx0XHR0aGlzLnV1aWQgPSBNYXRoVXRpbHMuZ2VuZXJhdGVVVUlEKCk7XHJcblxyXG5cdFx0dGhpcy5uYW1lID0gJyc7XHJcblx0XHR0aGlzLnR5cGUgPSAnTWF0ZXJpYWwnO1xyXG5cclxuXHRcdHRoaXMuYmxlbmRpbmcgPSBOb3JtYWxCbGVuZGluZztcclxuXHRcdHRoaXMuc2lkZSA9IEZyb250U2lkZTtcclxuXHRcdHRoaXMudmVydGV4Q29sb3JzID0gZmFsc2U7XHJcblxyXG5cdFx0dGhpcy5vcGFjaXR5ID0gMTtcclxuXHRcdHRoaXMudHJhbnNwYXJlbnQgPSBmYWxzZTtcclxuXHRcdHRoaXMuYWxwaGFIYXNoID0gZmFsc2U7XHJcblxyXG5cdFx0dGhpcy5ibGVuZFNyYyA9IFNyY0FscGhhRmFjdG9yO1xyXG5cdFx0dGhpcy5ibGVuZERzdCA9IE9uZU1pbnVzU3JjQWxwaGFGYWN0b3I7XHJcblx0XHR0aGlzLmJsZW5kRXF1YXRpb24gPSBBZGRFcXVhdGlvbjtcclxuXHRcdHRoaXMuYmxlbmRTcmNBbHBoYSA9IG51bGw7XHJcblx0XHR0aGlzLmJsZW5kRHN0QWxwaGEgPSBudWxsO1xyXG5cdFx0dGhpcy5ibGVuZEVxdWF0aW9uQWxwaGEgPSBudWxsO1xyXG5cdFx0dGhpcy5ibGVuZENvbG9yID0gbmV3IENvbG9yKCAwLCAwLCAwICk7XHJcblx0XHR0aGlzLmJsZW5kQWxwaGEgPSAwO1xyXG5cclxuXHRcdHRoaXMuZGVwdGhGdW5jID0gTGVzc0VxdWFsRGVwdGg7XHJcblx0XHR0aGlzLmRlcHRoVGVzdCA9IHRydWU7XHJcblx0XHR0aGlzLmRlcHRoV3JpdGUgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMuc3RlbmNpbFdyaXRlTWFzayA9IDB4ZmY7XHJcblx0XHR0aGlzLnN0ZW5jaWxGdW5jID0gQWx3YXlzU3RlbmNpbEZ1bmM7XHJcblx0XHR0aGlzLnN0ZW5jaWxSZWYgPSAwO1xyXG5cdFx0dGhpcy5zdGVuY2lsRnVuY01hc2sgPSAweGZmO1xyXG5cdFx0dGhpcy5zdGVuY2lsRmFpbCA9IEtlZXBTdGVuY2lsT3A7XHJcblx0XHR0aGlzLnN0ZW5jaWxaRmFpbCA9IEtlZXBTdGVuY2lsT3A7XHJcblx0XHR0aGlzLnN0ZW5jaWxaUGFzcyA9IEtlZXBTdGVuY2lsT3A7XHJcblx0XHR0aGlzLnN0ZW5jaWxXcml0ZSA9IGZhbHNlO1xyXG5cclxuXHRcdHRoaXMuY2xpcHBpbmdQbGFuZXMgPSBudWxsO1xyXG5cdFx0dGhpcy5jbGlwSW50ZXJzZWN0aW9uID0gZmFsc2U7XHJcblx0XHR0aGlzLmNsaXBTaGFkb3dzID0gZmFsc2U7XHJcblxyXG5cdFx0dGhpcy5zaGFkb3dTaWRlID0gbnVsbDtcclxuXHJcblx0XHR0aGlzLmNvbG9yV3JpdGUgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMucHJlY2lzaW9uID0gbnVsbDsgLy8gb3ZlcnJpZGUgdGhlIHJlbmRlcmVyJ3MgZGVmYXVsdCBwcmVjaXNpb24gZm9yIHRoaXMgbWF0ZXJpYWxcclxuXHJcblx0XHR0aGlzLnBvbHlnb25PZmZzZXQgPSBmYWxzZTtcclxuXHRcdHRoaXMucG9seWdvbk9mZnNldEZhY3RvciA9IDA7XHJcblx0XHR0aGlzLnBvbHlnb25PZmZzZXRVbml0cyA9IDA7XHJcblxyXG5cdFx0dGhpcy5kaXRoZXJpbmcgPSBmYWxzZTtcclxuXHJcblx0XHR0aGlzLmFscGhhVG9Db3ZlcmFnZSA9IGZhbHNlO1xyXG5cdFx0dGhpcy5wcmVtdWx0aXBsaWVkQWxwaGEgPSBmYWxzZTtcclxuXHRcdHRoaXMuZm9yY2VTaW5nbGVQYXNzID0gZmFsc2U7XHJcblxyXG5cdFx0dGhpcy52aXNpYmxlID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLnRvbmVNYXBwZWQgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMudXNlckRhdGEgPSB7fTtcclxuXHJcblx0XHR0aGlzLnZlcnNpb24gPSAwO1xyXG5cclxuXHRcdHRoaXMuX2FscGhhVGVzdCA9IDA7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0IGFscGhhVGVzdCgpIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5fYWxwaGFUZXN0O1xyXG5cclxuXHR9XHJcblxyXG5cdHNldCBhbHBoYVRlc3QoIHZhbHVlICkge1xyXG5cclxuXHRcdGlmICggdGhpcy5fYWxwaGFUZXN0ID4gMCAhPT0gdmFsdWUgPiAwICkge1xyXG5cclxuXHRcdFx0dGhpcy52ZXJzaW9uICsrO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLl9hbHBoYVRlc3QgPSB2YWx1ZTtcclxuXHJcblx0fVxyXG5cclxuXHRvbkJ1aWxkKCAvKiBzaGFkZXJvYmplY3QsIHJlbmRlcmVyICovICkge31cclxuXHJcblx0b25CZWZvcmVSZW5kZXIoIC8qIHJlbmRlcmVyLCBzY2VuZSwgY2FtZXJhLCBnZW9tZXRyeSwgb2JqZWN0LCBncm91cCAqLyApIHt9XHJcblxyXG5cdG9uQmVmb3JlQ29tcGlsZSggLyogc2hhZGVyb2JqZWN0LCByZW5kZXJlciAqLyApIHt9XHJcblxyXG5cdGN1c3RvbVByb2dyYW1DYWNoZUtleSgpIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5vbkJlZm9yZUNvbXBpbGUudG9TdHJpbmcoKTtcclxuXHJcblx0fVxyXG5cclxuXHRzZXRWYWx1ZXMoIHZhbHVlcyApIHtcclxuXHJcblx0XHRpZiAoIHZhbHVlcyA9PT0gdW5kZWZpbmVkICkgcmV0dXJuO1xyXG5cclxuXHRcdGZvciAoIGNvbnN0IGtleSBpbiB2YWx1ZXMgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBuZXdWYWx1ZSA9IHZhbHVlc1sga2V5IF07XHJcblxyXG5cdFx0XHRpZiAoIG5ld1ZhbHVlID09PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnNvbGUud2FybiggYFRIUkVFLk1hdGVyaWFsOiBwYXJhbWV0ZXIgJyR7IGtleSB9JyBoYXMgdmFsdWUgb2YgdW5kZWZpbmVkLmAgKTtcclxuXHRcdFx0XHRjb250aW51ZTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGNvbnN0IGN1cnJlbnRWYWx1ZSA9IHRoaXNbIGtleSBdO1xyXG5cclxuXHRcdFx0aWYgKCBjdXJyZW50VmFsdWUgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0Y29uc29sZS53YXJuKCBgVEhSRUUuTWF0ZXJpYWw6ICckeyBrZXkgfScgaXMgbm90IGEgcHJvcGVydHkgb2YgVEhSRUUuJHsgdGhpcy50eXBlIH0uYCApO1xyXG5cdFx0XHRcdGNvbnRpbnVlO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0aWYgKCBjdXJyZW50VmFsdWUgJiYgY3VycmVudFZhbHVlLmlzQ29sb3IgKSB7XHJcblxyXG5cdFx0XHRcdGN1cnJlbnRWYWx1ZS5zZXQoIG5ld1ZhbHVlICk7XHJcblxyXG5cdFx0XHR9IGVsc2UgaWYgKCAoIGN1cnJlbnRWYWx1ZSAmJiBjdXJyZW50VmFsdWUuaXNWZWN0b3IzICkgJiYgKCBuZXdWYWx1ZSAmJiBuZXdWYWx1ZS5pc1ZlY3RvcjMgKSApIHtcclxuXHJcblx0XHRcdFx0Y3VycmVudFZhbHVlLmNvcHkoIG5ld1ZhbHVlICk7XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHR0aGlzWyBrZXkgXSA9IG5ld1ZhbHVlO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHR0b0pTT04oIG1ldGEgKSB7XHJcblxyXG5cdFx0Y29uc3QgaXNSb290T2JqZWN0ID0gKCBtZXRhID09PSB1bmRlZmluZWQgfHwgdHlwZW9mIG1ldGEgPT09ICdzdHJpbmcnICk7XHJcblxyXG5cdFx0aWYgKCBpc1Jvb3RPYmplY3QgKSB7XHJcblxyXG5cdFx0XHRtZXRhID0ge1xyXG5cdFx0XHRcdHRleHR1cmVzOiB7fSxcclxuXHRcdFx0XHRpbWFnZXM6IHt9XHJcblx0XHRcdH07XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGNvbnN0IGRhdGEgPSB7XHJcblx0XHRcdG1ldGFkYXRhOiB7XHJcblx0XHRcdFx0dmVyc2lvbjogNC42LFxyXG5cdFx0XHRcdHR5cGU6ICdNYXRlcmlhbCcsXHJcblx0XHRcdFx0Z2VuZXJhdG9yOiAnTWF0ZXJpYWwudG9KU09OJ1xyXG5cdFx0XHR9XHJcblx0XHR9O1xyXG5cclxuXHRcdC8vIHN0YW5kYXJkIE1hdGVyaWFsIHNlcmlhbGl6YXRpb25cclxuXHRcdGRhdGEudXVpZCA9IHRoaXMudXVpZDtcclxuXHRcdGRhdGEudHlwZSA9IHRoaXMudHlwZTtcclxuXHJcblx0XHRpZiAoIHRoaXMubmFtZSAhPT0gJycgKSBkYXRhLm5hbWUgPSB0aGlzLm5hbWU7XHJcblxyXG5cdFx0aWYgKCB0aGlzLmNvbG9yICYmIHRoaXMuY29sb3IuaXNDb2xvciApIGRhdGEuY29sb3IgPSB0aGlzLmNvbG9yLmdldEhleCgpO1xyXG5cclxuXHRcdGlmICggdGhpcy5yb3VnaG5lc3MgIT09IHVuZGVmaW5lZCApIGRhdGEucm91Z2huZXNzID0gdGhpcy5yb3VnaG5lc3M7XHJcblx0XHRpZiAoIHRoaXMubWV0YWxuZXNzICE9PSB1bmRlZmluZWQgKSBkYXRhLm1ldGFsbmVzcyA9IHRoaXMubWV0YWxuZXNzO1xyXG5cclxuXHRcdGlmICggdGhpcy5zaGVlbiAhPT0gdW5kZWZpbmVkICkgZGF0YS5zaGVlbiA9IHRoaXMuc2hlZW47XHJcblx0XHRpZiAoIHRoaXMuc2hlZW5Db2xvciAmJiB0aGlzLnNoZWVuQ29sb3IuaXNDb2xvciApIGRhdGEuc2hlZW5Db2xvciA9IHRoaXMuc2hlZW5Db2xvci5nZXRIZXgoKTtcclxuXHRcdGlmICggdGhpcy5zaGVlblJvdWdobmVzcyAhPT0gdW5kZWZpbmVkICkgZGF0YS5zaGVlblJvdWdobmVzcyA9IHRoaXMuc2hlZW5Sb3VnaG5lc3M7XHJcblx0XHRpZiAoIHRoaXMuZW1pc3NpdmUgJiYgdGhpcy5lbWlzc2l2ZS5pc0NvbG9yICkgZGF0YS5lbWlzc2l2ZSA9IHRoaXMuZW1pc3NpdmUuZ2V0SGV4KCk7XHJcblx0XHRpZiAoIHRoaXMuZW1pc3NpdmVJbnRlbnNpdHkgJiYgdGhpcy5lbWlzc2l2ZUludGVuc2l0eSAhPT0gMSApIGRhdGEuZW1pc3NpdmVJbnRlbnNpdHkgPSB0aGlzLmVtaXNzaXZlSW50ZW5zaXR5O1xyXG5cclxuXHRcdGlmICggdGhpcy5zcGVjdWxhciAmJiB0aGlzLnNwZWN1bGFyLmlzQ29sb3IgKSBkYXRhLnNwZWN1bGFyID0gdGhpcy5zcGVjdWxhci5nZXRIZXgoKTtcclxuXHRcdGlmICggdGhpcy5zcGVjdWxhckludGVuc2l0eSAhPT0gdW5kZWZpbmVkICkgZGF0YS5zcGVjdWxhckludGVuc2l0eSA9IHRoaXMuc3BlY3VsYXJJbnRlbnNpdHk7XHJcblx0XHRpZiAoIHRoaXMuc3BlY3VsYXJDb2xvciAmJiB0aGlzLnNwZWN1bGFyQ29sb3IuaXNDb2xvciApIGRhdGEuc3BlY3VsYXJDb2xvciA9IHRoaXMuc3BlY3VsYXJDb2xvci5nZXRIZXgoKTtcclxuXHRcdGlmICggdGhpcy5zaGluaW5lc3MgIT09IHVuZGVmaW5lZCApIGRhdGEuc2hpbmluZXNzID0gdGhpcy5zaGluaW5lc3M7XHJcblx0XHRpZiAoIHRoaXMuY2xlYXJjb2F0ICE9PSB1bmRlZmluZWQgKSBkYXRhLmNsZWFyY29hdCA9IHRoaXMuY2xlYXJjb2F0O1xyXG5cdFx0aWYgKCB0aGlzLmNsZWFyY29hdFJvdWdobmVzcyAhPT0gdW5kZWZpbmVkICkgZGF0YS5jbGVhcmNvYXRSb3VnaG5lc3MgPSB0aGlzLmNsZWFyY29hdFJvdWdobmVzcztcclxuXHJcblx0XHRpZiAoIHRoaXMuY2xlYXJjb2F0TWFwICYmIHRoaXMuY2xlYXJjb2F0TWFwLmlzVGV4dHVyZSApIHtcclxuXHJcblx0XHRcdGRhdGEuY2xlYXJjb2F0TWFwID0gdGhpcy5jbGVhcmNvYXRNYXAudG9KU09OKCBtZXRhICkudXVpZDtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCB0aGlzLmNsZWFyY29hdFJvdWdobmVzc01hcCAmJiB0aGlzLmNsZWFyY29hdFJvdWdobmVzc01hcC5pc1RleHR1cmUgKSB7XHJcblxyXG5cdFx0XHRkYXRhLmNsZWFyY29hdFJvdWdobmVzc01hcCA9IHRoaXMuY2xlYXJjb2F0Um91Z2huZXNzTWFwLnRvSlNPTiggbWV0YSApLnV1aWQ7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggdGhpcy5jbGVhcmNvYXROb3JtYWxNYXAgJiYgdGhpcy5jbGVhcmNvYXROb3JtYWxNYXAuaXNUZXh0dXJlICkge1xyXG5cclxuXHRcdFx0ZGF0YS5jbGVhcmNvYXROb3JtYWxNYXAgPSB0aGlzLmNsZWFyY29hdE5vcm1hbE1hcC50b0pTT04oIG1ldGEgKS51dWlkO1xyXG5cdFx0XHRkYXRhLmNsZWFyY29hdE5vcm1hbFNjYWxlID0gdGhpcy5jbGVhcmNvYXROb3JtYWxTY2FsZS50b0FycmF5KCk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggdGhpcy5pcmlkZXNjZW5jZSAhPT0gdW5kZWZpbmVkICkgZGF0YS5pcmlkZXNjZW5jZSA9IHRoaXMuaXJpZGVzY2VuY2U7XHJcblx0XHRpZiAoIHRoaXMuaXJpZGVzY2VuY2VJT1IgIT09IHVuZGVmaW5lZCApIGRhdGEuaXJpZGVzY2VuY2VJT1IgPSB0aGlzLmlyaWRlc2NlbmNlSU9SO1xyXG5cdFx0aWYgKCB0aGlzLmlyaWRlc2NlbmNlVGhpY2tuZXNzUmFuZ2UgIT09IHVuZGVmaW5lZCApIGRhdGEuaXJpZGVzY2VuY2VUaGlja25lc3NSYW5nZSA9IHRoaXMuaXJpZGVzY2VuY2VUaGlja25lc3NSYW5nZTtcclxuXHJcblx0XHRpZiAoIHRoaXMuaXJpZGVzY2VuY2VNYXAgJiYgdGhpcy5pcmlkZXNjZW5jZU1hcC5pc1RleHR1cmUgKSB7XHJcblxyXG5cdFx0XHRkYXRhLmlyaWRlc2NlbmNlTWFwID0gdGhpcy5pcmlkZXNjZW5jZU1hcC50b0pTT04oIG1ldGEgKS51dWlkO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHRoaXMuaXJpZGVzY2VuY2VUaGlja25lc3NNYXAgJiYgdGhpcy5pcmlkZXNjZW5jZVRoaWNrbmVzc01hcC5pc1RleHR1cmUgKSB7XHJcblxyXG5cdFx0XHRkYXRhLmlyaWRlc2NlbmNlVGhpY2tuZXNzTWFwID0gdGhpcy5pcmlkZXNjZW5jZVRoaWNrbmVzc01hcC50b0pTT04oIG1ldGEgKS51dWlkO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHRoaXMuYW5pc290cm9weSAhPT0gdW5kZWZpbmVkICkgZGF0YS5hbmlzb3Ryb3B5ID0gdGhpcy5hbmlzb3Ryb3B5O1xyXG5cdFx0aWYgKCB0aGlzLmFuaXNvdHJvcHlSb3RhdGlvbiAhPT0gdW5kZWZpbmVkICkgZGF0YS5hbmlzb3Ryb3B5Um90YXRpb24gPSB0aGlzLmFuaXNvdHJvcHlSb3RhdGlvbjtcclxuXHJcblx0XHRpZiAoIHRoaXMuYW5pc290cm9weU1hcCAmJiB0aGlzLmFuaXNvdHJvcHlNYXAuaXNUZXh0dXJlICkge1xyXG5cclxuXHRcdFx0ZGF0YS5hbmlzb3Ryb3B5TWFwID0gdGhpcy5hbmlzb3Ryb3B5TWFwLnRvSlNPTiggbWV0YSApLnV1aWQ7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggdGhpcy5tYXAgJiYgdGhpcy5tYXAuaXNUZXh0dXJlICkgZGF0YS5tYXAgPSB0aGlzLm1hcC50b0pTT04oIG1ldGEgKS51dWlkO1xyXG5cdFx0aWYgKCB0aGlzLm1hdGNhcCAmJiB0aGlzLm1hdGNhcC5pc1RleHR1cmUgKSBkYXRhLm1hdGNhcCA9IHRoaXMubWF0Y2FwLnRvSlNPTiggbWV0YSApLnV1aWQ7XHJcblx0XHRpZiAoIHRoaXMuYWxwaGFNYXAgJiYgdGhpcy5hbHBoYU1hcC5pc1RleHR1cmUgKSBkYXRhLmFscGhhTWFwID0gdGhpcy5hbHBoYU1hcC50b0pTT04oIG1ldGEgKS51dWlkO1xyXG5cclxuXHRcdGlmICggdGhpcy5saWdodE1hcCAmJiB0aGlzLmxpZ2h0TWFwLmlzVGV4dHVyZSApIHtcclxuXHJcblx0XHRcdGRhdGEubGlnaHRNYXAgPSB0aGlzLmxpZ2h0TWFwLnRvSlNPTiggbWV0YSApLnV1aWQ7XHJcblx0XHRcdGRhdGEubGlnaHRNYXBJbnRlbnNpdHkgPSB0aGlzLmxpZ2h0TWFwSW50ZW5zaXR5O1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHRoaXMuYW9NYXAgJiYgdGhpcy5hb01hcC5pc1RleHR1cmUgKSB7XHJcblxyXG5cdFx0XHRkYXRhLmFvTWFwID0gdGhpcy5hb01hcC50b0pTT04oIG1ldGEgKS51dWlkO1xyXG5cdFx0XHRkYXRhLmFvTWFwSW50ZW5zaXR5ID0gdGhpcy5hb01hcEludGVuc2l0eTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCB0aGlzLmJ1bXBNYXAgJiYgdGhpcy5idW1wTWFwLmlzVGV4dHVyZSApIHtcclxuXHJcblx0XHRcdGRhdGEuYnVtcE1hcCA9IHRoaXMuYnVtcE1hcC50b0pTT04oIG1ldGEgKS51dWlkO1xyXG5cdFx0XHRkYXRhLmJ1bXBTY2FsZSA9IHRoaXMuYnVtcFNjYWxlO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHRoaXMubm9ybWFsTWFwICYmIHRoaXMubm9ybWFsTWFwLmlzVGV4dHVyZSApIHtcclxuXHJcblx0XHRcdGRhdGEubm9ybWFsTWFwID0gdGhpcy5ub3JtYWxNYXAudG9KU09OKCBtZXRhICkudXVpZDtcclxuXHRcdFx0ZGF0YS5ub3JtYWxNYXBUeXBlID0gdGhpcy5ub3JtYWxNYXBUeXBlO1xyXG5cdFx0XHRkYXRhLm5vcm1hbFNjYWxlID0gdGhpcy5ub3JtYWxTY2FsZS50b0FycmF5KCk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggdGhpcy5kaXNwbGFjZW1lbnRNYXAgJiYgdGhpcy5kaXNwbGFjZW1lbnRNYXAuaXNUZXh0dXJlICkge1xyXG5cclxuXHRcdFx0ZGF0YS5kaXNwbGFjZW1lbnRNYXAgPSB0aGlzLmRpc3BsYWNlbWVudE1hcC50b0pTT04oIG1ldGEgKS51dWlkO1xyXG5cdFx0XHRkYXRhLmRpc3BsYWNlbWVudFNjYWxlID0gdGhpcy5kaXNwbGFjZW1lbnRTY2FsZTtcclxuXHRcdFx0ZGF0YS5kaXNwbGFjZW1lbnRCaWFzID0gdGhpcy5kaXNwbGFjZW1lbnRCaWFzO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHRoaXMucm91Z2huZXNzTWFwICYmIHRoaXMucm91Z2huZXNzTWFwLmlzVGV4dHVyZSApIGRhdGEucm91Z2huZXNzTWFwID0gdGhpcy5yb3VnaG5lc3NNYXAudG9KU09OKCBtZXRhICkudXVpZDtcclxuXHRcdGlmICggdGhpcy5tZXRhbG5lc3NNYXAgJiYgdGhpcy5tZXRhbG5lc3NNYXAuaXNUZXh0dXJlICkgZGF0YS5tZXRhbG5lc3NNYXAgPSB0aGlzLm1ldGFsbmVzc01hcC50b0pTT04oIG1ldGEgKS51dWlkO1xyXG5cclxuXHRcdGlmICggdGhpcy5lbWlzc2l2ZU1hcCAmJiB0aGlzLmVtaXNzaXZlTWFwLmlzVGV4dHVyZSApIGRhdGEuZW1pc3NpdmVNYXAgPSB0aGlzLmVtaXNzaXZlTWFwLnRvSlNPTiggbWV0YSApLnV1aWQ7XHJcblx0XHRpZiAoIHRoaXMuc3BlY3VsYXJNYXAgJiYgdGhpcy5zcGVjdWxhck1hcC5pc1RleHR1cmUgKSBkYXRhLnNwZWN1bGFyTWFwID0gdGhpcy5zcGVjdWxhck1hcC50b0pTT04oIG1ldGEgKS51dWlkO1xyXG5cdFx0aWYgKCB0aGlzLnNwZWN1bGFySW50ZW5zaXR5TWFwICYmIHRoaXMuc3BlY3VsYXJJbnRlbnNpdHlNYXAuaXNUZXh0dXJlICkgZGF0YS5zcGVjdWxhckludGVuc2l0eU1hcCA9IHRoaXMuc3BlY3VsYXJJbnRlbnNpdHlNYXAudG9KU09OKCBtZXRhICkudXVpZDtcclxuXHRcdGlmICggdGhpcy5zcGVjdWxhckNvbG9yTWFwICYmIHRoaXMuc3BlY3VsYXJDb2xvck1hcC5pc1RleHR1cmUgKSBkYXRhLnNwZWN1bGFyQ29sb3JNYXAgPSB0aGlzLnNwZWN1bGFyQ29sb3JNYXAudG9KU09OKCBtZXRhICkudXVpZDtcclxuXHJcblx0XHRpZiAoIHRoaXMuZW52TWFwICYmIHRoaXMuZW52TWFwLmlzVGV4dHVyZSApIHtcclxuXHJcblx0XHRcdGRhdGEuZW52TWFwID0gdGhpcy5lbnZNYXAudG9KU09OKCBtZXRhICkudXVpZDtcclxuXHJcblx0XHRcdGlmICggdGhpcy5jb21iaW5lICE9PSB1bmRlZmluZWQgKSBkYXRhLmNvbWJpbmUgPSB0aGlzLmNvbWJpbmU7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggdGhpcy5lbnZNYXBJbnRlbnNpdHkgIT09IHVuZGVmaW5lZCApIGRhdGEuZW52TWFwSW50ZW5zaXR5ID0gdGhpcy5lbnZNYXBJbnRlbnNpdHk7XHJcblx0XHRpZiAoIHRoaXMucmVmbGVjdGl2aXR5ICE9PSB1bmRlZmluZWQgKSBkYXRhLnJlZmxlY3Rpdml0eSA9IHRoaXMucmVmbGVjdGl2aXR5O1xyXG5cdFx0aWYgKCB0aGlzLnJlZnJhY3Rpb25SYXRpbyAhPT0gdW5kZWZpbmVkICkgZGF0YS5yZWZyYWN0aW9uUmF0aW8gPSB0aGlzLnJlZnJhY3Rpb25SYXRpbztcclxuXHJcblx0XHRpZiAoIHRoaXMuZ3JhZGllbnRNYXAgJiYgdGhpcy5ncmFkaWVudE1hcC5pc1RleHR1cmUgKSB7XHJcblxyXG5cdFx0XHRkYXRhLmdyYWRpZW50TWFwID0gdGhpcy5ncmFkaWVudE1hcC50b0pTT04oIG1ldGEgKS51dWlkO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHRoaXMudHJhbnNtaXNzaW9uICE9PSB1bmRlZmluZWQgKSBkYXRhLnRyYW5zbWlzc2lvbiA9IHRoaXMudHJhbnNtaXNzaW9uO1xyXG5cdFx0aWYgKCB0aGlzLnRyYW5zbWlzc2lvbk1hcCAmJiB0aGlzLnRyYW5zbWlzc2lvbk1hcC5pc1RleHR1cmUgKSBkYXRhLnRyYW5zbWlzc2lvbk1hcCA9IHRoaXMudHJhbnNtaXNzaW9uTWFwLnRvSlNPTiggbWV0YSApLnV1aWQ7XHJcblx0XHRpZiAoIHRoaXMudGhpY2tuZXNzICE9PSB1bmRlZmluZWQgKSBkYXRhLnRoaWNrbmVzcyA9IHRoaXMudGhpY2tuZXNzO1xyXG5cdFx0aWYgKCB0aGlzLnRoaWNrbmVzc01hcCAmJiB0aGlzLnRoaWNrbmVzc01hcC5pc1RleHR1cmUgKSBkYXRhLnRoaWNrbmVzc01hcCA9IHRoaXMudGhpY2tuZXNzTWFwLnRvSlNPTiggbWV0YSApLnV1aWQ7XHJcblx0XHRpZiAoIHRoaXMuYXR0ZW51YXRpb25EaXN0YW5jZSAhPT0gdW5kZWZpbmVkICYmIHRoaXMuYXR0ZW51YXRpb25EaXN0YW5jZSAhPT0gSW5maW5pdHkgKSBkYXRhLmF0dGVudWF0aW9uRGlzdGFuY2UgPSB0aGlzLmF0dGVudWF0aW9uRGlzdGFuY2U7XHJcblx0XHRpZiAoIHRoaXMuYXR0ZW51YXRpb25Db2xvciAhPT0gdW5kZWZpbmVkICkgZGF0YS5hdHRlbnVhdGlvbkNvbG9yID0gdGhpcy5hdHRlbnVhdGlvbkNvbG9yLmdldEhleCgpO1xyXG5cclxuXHRcdGlmICggdGhpcy5zaXplICE9PSB1bmRlZmluZWQgKSBkYXRhLnNpemUgPSB0aGlzLnNpemU7XHJcblx0XHRpZiAoIHRoaXMuc2hhZG93U2lkZSAhPT0gbnVsbCApIGRhdGEuc2hhZG93U2lkZSA9IHRoaXMuc2hhZG93U2lkZTtcclxuXHRcdGlmICggdGhpcy5zaXplQXR0ZW51YXRpb24gIT09IHVuZGVmaW5lZCApIGRhdGEuc2l6ZUF0dGVudWF0aW9uID0gdGhpcy5zaXplQXR0ZW51YXRpb247XHJcblxyXG5cdFx0aWYgKCB0aGlzLmJsZW5kaW5nICE9PSBOb3JtYWxCbGVuZGluZyApIGRhdGEuYmxlbmRpbmcgPSB0aGlzLmJsZW5kaW5nO1xyXG5cdFx0aWYgKCB0aGlzLnNpZGUgIT09IEZyb250U2lkZSApIGRhdGEuc2lkZSA9IHRoaXMuc2lkZTtcclxuXHRcdGlmICggdGhpcy52ZXJ0ZXhDb2xvcnMgPT09IHRydWUgKSBkYXRhLnZlcnRleENvbG9ycyA9IHRydWU7XHJcblxyXG5cdFx0aWYgKCB0aGlzLm9wYWNpdHkgPCAxICkgZGF0YS5vcGFjaXR5ID0gdGhpcy5vcGFjaXR5O1xyXG5cdFx0aWYgKCB0aGlzLnRyYW5zcGFyZW50ID09PSB0cnVlICkgZGF0YS50cmFuc3BhcmVudCA9IHRydWU7XHJcblxyXG5cdFx0aWYgKCB0aGlzLmJsZW5kU3JjICE9PSBTcmNBbHBoYUZhY3RvciApIGRhdGEuYmxlbmRTcmMgPSB0aGlzLmJsZW5kU3JjO1xyXG5cdFx0aWYgKCB0aGlzLmJsZW5kRHN0ICE9PSBPbmVNaW51c1NyY0FscGhhRmFjdG9yICkgZGF0YS5ibGVuZERzdCA9IHRoaXMuYmxlbmREc3Q7XHJcblx0XHRpZiAoIHRoaXMuYmxlbmRFcXVhdGlvbiAhPT0gQWRkRXF1YXRpb24gKSBkYXRhLmJsZW5kRXF1YXRpb24gPSB0aGlzLmJsZW5kRXF1YXRpb247XHJcblx0XHRpZiAoIHRoaXMuYmxlbmRTcmNBbHBoYSAhPT0gbnVsbCApIGRhdGEuYmxlbmRTcmNBbHBoYSA9IHRoaXMuYmxlbmRTcmNBbHBoYTtcclxuXHRcdGlmICggdGhpcy5ibGVuZERzdEFscGhhICE9PSBudWxsICkgZGF0YS5ibGVuZERzdEFscGhhID0gdGhpcy5ibGVuZERzdEFscGhhO1xyXG5cdFx0aWYgKCB0aGlzLmJsZW5kRXF1YXRpb25BbHBoYSAhPT0gbnVsbCApIGRhdGEuYmxlbmRFcXVhdGlvbkFscGhhID0gdGhpcy5ibGVuZEVxdWF0aW9uQWxwaGE7XHJcblx0XHRpZiAoIHRoaXMuYmxlbmRDb2xvciAmJiB0aGlzLmJsZW5kQ29sb3IuaXNDb2xvciApIGRhdGEuYmxlbmRDb2xvciA9IHRoaXMuYmxlbmRDb2xvci5nZXRIZXgoKTtcclxuXHRcdGlmICggdGhpcy5ibGVuZEFscGhhICE9PSAwICkgZGF0YS5ibGVuZEFscGhhID0gdGhpcy5ibGVuZEFscGhhO1xyXG5cclxuXHRcdGlmICggdGhpcy5kZXB0aEZ1bmMgIT09IExlc3NFcXVhbERlcHRoICkgZGF0YS5kZXB0aEZ1bmMgPSB0aGlzLmRlcHRoRnVuYztcclxuXHRcdGlmICggdGhpcy5kZXB0aFRlc3QgPT09IGZhbHNlICkgZGF0YS5kZXB0aFRlc3QgPSB0aGlzLmRlcHRoVGVzdDtcclxuXHRcdGlmICggdGhpcy5kZXB0aFdyaXRlID09PSBmYWxzZSApIGRhdGEuZGVwdGhXcml0ZSA9IHRoaXMuZGVwdGhXcml0ZTtcclxuXHRcdGlmICggdGhpcy5jb2xvcldyaXRlID09PSBmYWxzZSApIGRhdGEuY29sb3JXcml0ZSA9IHRoaXMuY29sb3JXcml0ZTtcclxuXHJcblx0XHRpZiAoIHRoaXMuc3RlbmNpbFdyaXRlTWFzayAhPT0gMHhmZiApIGRhdGEuc3RlbmNpbFdyaXRlTWFzayA9IHRoaXMuc3RlbmNpbFdyaXRlTWFzaztcclxuXHRcdGlmICggdGhpcy5zdGVuY2lsRnVuYyAhPT0gQWx3YXlzU3RlbmNpbEZ1bmMgKSBkYXRhLnN0ZW5jaWxGdW5jID0gdGhpcy5zdGVuY2lsRnVuYztcclxuXHRcdGlmICggdGhpcy5zdGVuY2lsUmVmICE9PSAwICkgZGF0YS5zdGVuY2lsUmVmID0gdGhpcy5zdGVuY2lsUmVmO1xyXG5cdFx0aWYgKCB0aGlzLnN0ZW5jaWxGdW5jTWFzayAhPT0gMHhmZiApIGRhdGEuc3RlbmNpbEZ1bmNNYXNrID0gdGhpcy5zdGVuY2lsRnVuY01hc2s7XHJcblx0XHRpZiAoIHRoaXMuc3RlbmNpbEZhaWwgIT09IEtlZXBTdGVuY2lsT3AgKSBkYXRhLnN0ZW5jaWxGYWlsID0gdGhpcy5zdGVuY2lsRmFpbDtcclxuXHRcdGlmICggdGhpcy5zdGVuY2lsWkZhaWwgIT09IEtlZXBTdGVuY2lsT3AgKSBkYXRhLnN0ZW5jaWxaRmFpbCA9IHRoaXMuc3RlbmNpbFpGYWlsO1xyXG5cdFx0aWYgKCB0aGlzLnN0ZW5jaWxaUGFzcyAhPT0gS2VlcFN0ZW5jaWxPcCApIGRhdGEuc3RlbmNpbFpQYXNzID0gdGhpcy5zdGVuY2lsWlBhc3M7XHJcblx0XHRpZiAoIHRoaXMuc3RlbmNpbFdyaXRlID09PSB0cnVlICkgZGF0YS5zdGVuY2lsV3JpdGUgPSB0aGlzLnN0ZW5jaWxXcml0ZTtcclxuXHJcblx0XHQvLyByb3RhdGlvbiAoU3ByaXRlTWF0ZXJpYWwpXHJcblx0XHRpZiAoIHRoaXMucm90YXRpb24gIT09IHVuZGVmaW5lZCAmJiB0aGlzLnJvdGF0aW9uICE9PSAwICkgZGF0YS5yb3RhdGlvbiA9IHRoaXMucm90YXRpb247XHJcblxyXG5cdFx0aWYgKCB0aGlzLnBvbHlnb25PZmZzZXQgPT09IHRydWUgKSBkYXRhLnBvbHlnb25PZmZzZXQgPSB0cnVlO1xyXG5cdFx0aWYgKCB0aGlzLnBvbHlnb25PZmZzZXRGYWN0b3IgIT09IDAgKSBkYXRhLnBvbHlnb25PZmZzZXRGYWN0b3IgPSB0aGlzLnBvbHlnb25PZmZzZXRGYWN0b3I7XHJcblx0XHRpZiAoIHRoaXMucG9seWdvbk9mZnNldFVuaXRzICE9PSAwICkgZGF0YS5wb2x5Z29uT2Zmc2V0VW5pdHMgPSB0aGlzLnBvbHlnb25PZmZzZXRVbml0cztcclxuXHJcblx0XHRpZiAoIHRoaXMubGluZXdpZHRoICE9PSB1bmRlZmluZWQgJiYgdGhpcy5saW5ld2lkdGggIT09IDEgKSBkYXRhLmxpbmV3aWR0aCA9IHRoaXMubGluZXdpZHRoO1xyXG5cdFx0aWYgKCB0aGlzLmRhc2hTaXplICE9PSB1bmRlZmluZWQgKSBkYXRhLmRhc2hTaXplID0gdGhpcy5kYXNoU2l6ZTtcclxuXHRcdGlmICggdGhpcy5nYXBTaXplICE9PSB1bmRlZmluZWQgKSBkYXRhLmdhcFNpemUgPSB0aGlzLmdhcFNpemU7XHJcblx0XHRpZiAoIHRoaXMuc2NhbGUgIT09IHVuZGVmaW5lZCApIGRhdGEuc2NhbGUgPSB0aGlzLnNjYWxlO1xyXG5cclxuXHRcdGlmICggdGhpcy5kaXRoZXJpbmcgPT09IHRydWUgKSBkYXRhLmRpdGhlcmluZyA9IHRydWU7XHJcblxyXG5cdFx0aWYgKCB0aGlzLmFscGhhVGVzdCA+IDAgKSBkYXRhLmFscGhhVGVzdCA9IHRoaXMuYWxwaGFUZXN0O1xyXG5cdFx0aWYgKCB0aGlzLmFscGhhSGFzaCA9PT0gdHJ1ZSApIGRhdGEuYWxwaGFIYXNoID0gdHJ1ZTtcclxuXHRcdGlmICggdGhpcy5hbHBoYVRvQ292ZXJhZ2UgPT09IHRydWUgKSBkYXRhLmFscGhhVG9Db3ZlcmFnZSA9IHRydWU7XHJcblx0XHRpZiAoIHRoaXMucHJlbXVsdGlwbGllZEFscGhhID09PSB0cnVlICkgZGF0YS5wcmVtdWx0aXBsaWVkQWxwaGEgPSB0cnVlO1xyXG5cdFx0aWYgKCB0aGlzLmZvcmNlU2luZ2xlUGFzcyA9PT0gdHJ1ZSApIGRhdGEuZm9yY2VTaW5nbGVQYXNzID0gdHJ1ZTtcclxuXHJcblx0XHRpZiAoIHRoaXMud2lyZWZyYW1lID09PSB0cnVlICkgZGF0YS53aXJlZnJhbWUgPSB0cnVlO1xyXG5cdFx0aWYgKCB0aGlzLndpcmVmcmFtZUxpbmV3aWR0aCA+IDEgKSBkYXRhLndpcmVmcmFtZUxpbmV3aWR0aCA9IHRoaXMud2lyZWZyYW1lTGluZXdpZHRoO1xyXG5cdFx0aWYgKCB0aGlzLndpcmVmcmFtZUxpbmVjYXAgIT09ICdyb3VuZCcgKSBkYXRhLndpcmVmcmFtZUxpbmVjYXAgPSB0aGlzLndpcmVmcmFtZUxpbmVjYXA7XHJcblx0XHRpZiAoIHRoaXMud2lyZWZyYW1lTGluZWpvaW4gIT09ICdyb3VuZCcgKSBkYXRhLndpcmVmcmFtZUxpbmVqb2luID0gdGhpcy53aXJlZnJhbWVMaW5lam9pbjtcclxuXHJcblx0XHRpZiAoIHRoaXMuZmxhdFNoYWRpbmcgPT09IHRydWUgKSBkYXRhLmZsYXRTaGFkaW5nID0gdHJ1ZTtcclxuXHJcblx0XHRpZiAoIHRoaXMudmlzaWJsZSA9PT0gZmFsc2UgKSBkYXRhLnZpc2libGUgPSBmYWxzZTtcclxuXHJcblx0XHRpZiAoIHRoaXMudG9uZU1hcHBlZCA9PT0gZmFsc2UgKSBkYXRhLnRvbmVNYXBwZWQgPSBmYWxzZTtcclxuXHJcblx0XHRpZiAoIHRoaXMuZm9nID09PSBmYWxzZSApIGRhdGEuZm9nID0gZmFsc2U7XHJcblxyXG5cdFx0aWYgKCBPYmplY3Qua2V5cyggdGhpcy51c2VyRGF0YSApLmxlbmd0aCA+IDAgKSBkYXRhLnVzZXJEYXRhID0gdGhpcy51c2VyRGF0YTtcclxuXHJcblx0XHQvLyBUT0RPOiBDb3BpZWQgZnJvbSBPYmplY3QzRC50b0pTT05cclxuXHJcblx0XHRmdW5jdGlvbiBleHRyYWN0RnJvbUNhY2hlKCBjYWNoZSApIHtcclxuXHJcblx0XHRcdGNvbnN0IHZhbHVlcyA9IFtdO1xyXG5cclxuXHRcdFx0Zm9yICggY29uc3Qga2V5IGluIGNhY2hlICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBkYXRhID0gY2FjaGVbIGtleSBdO1xyXG5cdFx0XHRcdGRlbGV0ZSBkYXRhLm1ldGFkYXRhO1xyXG5cdFx0XHRcdHZhbHVlcy5wdXNoKCBkYXRhICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRyZXR1cm4gdmFsdWVzO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIGlzUm9vdE9iamVjdCApIHtcclxuXHJcblx0XHRcdGNvbnN0IHRleHR1cmVzID0gZXh0cmFjdEZyb21DYWNoZSggbWV0YS50ZXh0dXJlcyApO1xyXG5cdFx0XHRjb25zdCBpbWFnZXMgPSBleHRyYWN0RnJvbUNhY2hlKCBtZXRhLmltYWdlcyApO1xyXG5cclxuXHRcdFx0aWYgKCB0ZXh0dXJlcy5sZW5ndGggPiAwICkgZGF0YS50ZXh0dXJlcyA9IHRleHR1cmVzO1xyXG5cdFx0XHRpZiAoIGltYWdlcy5sZW5ndGggPiAwICkgZGF0YS5pbWFnZXMgPSBpbWFnZXM7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiBkYXRhO1xyXG5cclxuXHR9XHJcblxyXG5cdGNsb25lKCkge1xyXG5cclxuXHRcdHJldHVybiBuZXcgdGhpcy5jb25zdHJ1Y3RvcigpLmNvcHkoIHRoaXMgKTtcclxuXHJcblx0fVxyXG5cclxuXHRjb3B5KCBzb3VyY2UgKSB7XHJcblxyXG5cdFx0dGhpcy5uYW1lID0gc291cmNlLm5hbWU7XHJcblxyXG5cdFx0dGhpcy5ibGVuZGluZyA9IHNvdXJjZS5ibGVuZGluZztcclxuXHRcdHRoaXMuc2lkZSA9IHNvdXJjZS5zaWRlO1xyXG5cdFx0dGhpcy52ZXJ0ZXhDb2xvcnMgPSBzb3VyY2UudmVydGV4Q29sb3JzO1xyXG5cclxuXHRcdHRoaXMub3BhY2l0eSA9IHNvdXJjZS5vcGFjaXR5O1xyXG5cdFx0dGhpcy50cmFuc3BhcmVudCA9IHNvdXJjZS50cmFuc3BhcmVudDtcclxuXHJcblx0XHR0aGlzLmJsZW5kU3JjID0gc291cmNlLmJsZW5kU3JjO1xyXG5cdFx0dGhpcy5ibGVuZERzdCA9IHNvdXJjZS5ibGVuZERzdDtcclxuXHRcdHRoaXMuYmxlbmRFcXVhdGlvbiA9IHNvdXJjZS5ibGVuZEVxdWF0aW9uO1xyXG5cdFx0dGhpcy5ibGVuZFNyY0FscGhhID0gc291cmNlLmJsZW5kU3JjQWxwaGE7XHJcblx0XHR0aGlzLmJsZW5kRHN0QWxwaGEgPSBzb3VyY2UuYmxlbmREc3RBbHBoYTtcclxuXHRcdHRoaXMuYmxlbmRFcXVhdGlvbkFscGhhID0gc291cmNlLmJsZW5kRXF1YXRpb25BbHBoYTtcclxuXHRcdHRoaXMuYmxlbmRDb2xvci5jb3B5KCBzb3VyY2UuYmxlbmRDb2xvciApO1xyXG5cdFx0dGhpcy5ibGVuZEFscGhhID0gc291cmNlLmJsZW5kQWxwaGE7XHJcblxyXG5cdFx0dGhpcy5kZXB0aEZ1bmMgPSBzb3VyY2UuZGVwdGhGdW5jO1xyXG5cdFx0dGhpcy5kZXB0aFRlc3QgPSBzb3VyY2UuZGVwdGhUZXN0O1xyXG5cdFx0dGhpcy5kZXB0aFdyaXRlID0gc291cmNlLmRlcHRoV3JpdGU7XHJcblxyXG5cdFx0dGhpcy5zdGVuY2lsV3JpdGVNYXNrID0gc291cmNlLnN0ZW5jaWxXcml0ZU1hc2s7XHJcblx0XHR0aGlzLnN0ZW5jaWxGdW5jID0gc291cmNlLnN0ZW5jaWxGdW5jO1xyXG5cdFx0dGhpcy5zdGVuY2lsUmVmID0gc291cmNlLnN0ZW5jaWxSZWY7XHJcblx0XHR0aGlzLnN0ZW5jaWxGdW5jTWFzayA9IHNvdXJjZS5zdGVuY2lsRnVuY01hc2s7XHJcblx0XHR0aGlzLnN0ZW5jaWxGYWlsID0gc291cmNlLnN0ZW5jaWxGYWlsO1xyXG5cdFx0dGhpcy5zdGVuY2lsWkZhaWwgPSBzb3VyY2Uuc3RlbmNpbFpGYWlsO1xyXG5cdFx0dGhpcy5zdGVuY2lsWlBhc3MgPSBzb3VyY2Uuc3RlbmNpbFpQYXNzO1xyXG5cdFx0dGhpcy5zdGVuY2lsV3JpdGUgPSBzb3VyY2Uuc3RlbmNpbFdyaXRlO1xyXG5cclxuXHRcdGNvbnN0IHNyY1BsYW5lcyA9IHNvdXJjZS5jbGlwcGluZ1BsYW5lcztcclxuXHRcdGxldCBkc3RQbGFuZXMgPSBudWxsO1xyXG5cclxuXHRcdGlmICggc3JjUGxhbmVzICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0Y29uc3QgbiA9IHNyY1BsYW5lcy5sZW5ndGg7XHJcblx0XHRcdGRzdFBsYW5lcyA9IG5ldyBBcnJheSggbiApO1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpICE9PSBuOyArKyBpICkge1xyXG5cclxuXHRcdFx0XHRkc3RQbGFuZXNbIGkgXSA9IHNyY1BsYW5lc1sgaSBdLmNsb25lKCk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMuY2xpcHBpbmdQbGFuZXMgPSBkc3RQbGFuZXM7XHJcblx0XHR0aGlzLmNsaXBJbnRlcnNlY3Rpb24gPSBzb3VyY2UuY2xpcEludGVyc2VjdGlvbjtcclxuXHRcdHRoaXMuY2xpcFNoYWRvd3MgPSBzb3VyY2UuY2xpcFNoYWRvd3M7XHJcblxyXG5cdFx0dGhpcy5zaGFkb3dTaWRlID0gc291cmNlLnNoYWRvd1NpZGU7XHJcblxyXG5cdFx0dGhpcy5jb2xvcldyaXRlID0gc291cmNlLmNvbG9yV3JpdGU7XHJcblxyXG5cdFx0dGhpcy5wcmVjaXNpb24gPSBzb3VyY2UucHJlY2lzaW9uO1xyXG5cclxuXHRcdHRoaXMucG9seWdvbk9mZnNldCA9IHNvdXJjZS5wb2x5Z29uT2Zmc2V0O1xyXG5cdFx0dGhpcy5wb2x5Z29uT2Zmc2V0RmFjdG9yID0gc291cmNlLnBvbHlnb25PZmZzZXRGYWN0b3I7XHJcblx0XHR0aGlzLnBvbHlnb25PZmZzZXRVbml0cyA9IHNvdXJjZS5wb2x5Z29uT2Zmc2V0VW5pdHM7XHJcblxyXG5cdFx0dGhpcy5kaXRoZXJpbmcgPSBzb3VyY2UuZGl0aGVyaW5nO1xyXG5cclxuXHRcdHRoaXMuYWxwaGFUZXN0ID0gc291cmNlLmFscGhhVGVzdDtcclxuXHRcdHRoaXMuYWxwaGFIYXNoID0gc291cmNlLmFscGhhSGFzaDtcclxuXHRcdHRoaXMuYWxwaGFUb0NvdmVyYWdlID0gc291cmNlLmFscGhhVG9Db3ZlcmFnZTtcclxuXHRcdHRoaXMucHJlbXVsdGlwbGllZEFscGhhID0gc291cmNlLnByZW11bHRpcGxpZWRBbHBoYTtcclxuXHRcdHRoaXMuZm9yY2VTaW5nbGVQYXNzID0gc291cmNlLmZvcmNlU2luZ2xlUGFzcztcclxuXHJcblx0XHR0aGlzLnZpc2libGUgPSBzb3VyY2UudmlzaWJsZTtcclxuXHJcblx0XHR0aGlzLnRvbmVNYXBwZWQgPSBzb3VyY2UudG9uZU1hcHBlZDtcclxuXHJcblx0XHR0aGlzLnVzZXJEYXRhID0gSlNPTi5wYXJzZSggSlNPTi5zdHJpbmdpZnkoIHNvdXJjZS51c2VyRGF0YSApICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0ZGlzcG9zZSgpIHtcclxuXHJcblx0XHR0aGlzLmRpc3BhdGNoRXZlbnQoIHsgdHlwZTogJ2Rpc3Bvc2UnIH0gKTtcclxuXHJcblx0fVxyXG5cclxuXHRzZXQgbmVlZHNVcGRhdGUoIHZhbHVlICkge1xyXG5cclxuXHRcdGlmICggdmFsdWUgPT09IHRydWUgKSB0aGlzLnZlcnNpb24gKys7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IE1hdGVyaWFsIH07XHJcbiIsImltcG9ydCB7IE1hdGVyaWFsIH0gZnJvbSAnLi9NYXRlcmlhbC5qcyc7XHJcbmltcG9ydCB7IE11bHRpcGx5T3BlcmF0aW9uIH0gZnJvbSAnLi4vY29uc3RhbnRzLmpzJztcclxuaW1wb3J0IHsgQ29sb3IgfSBmcm9tICcuLi9tYXRoL0NvbG9yLmpzJztcclxuXHJcbmNsYXNzIE1lc2hCYXNpY01hdGVyaWFsIGV4dGVuZHMgTWF0ZXJpYWwge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggcGFyYW1ldGVycyApIHtcclxuXHJcblx0XHRzdXBlcigpO1xyXG5cclxuXHRcdHRoaXMuaXNNZXNoQmFzaWNNYXRlcmlhbCA9IHRydWU7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ01lc2hCYXNpY01hdGVyaWFsJztcclxuXHJcblx0XHR0aGlzLmNvbG9yID0gbmV3IENvbG9yKCAweGZmZmZmZiApOyAvLyBlbWlzc2l2ZVxyXG5cclxuXHRcdHRoaXMubWFwID0gbnVsbDtcclxuXHJcblx0XHR0aGlzLmxpZ2h0TWFwID0gbnVsbDtcclxuXHRcdHRoaXMubGlnaHRNYXBJbnRlbnNpdHkgPSAxLjA7XHJcblxyXG5cdFx0dGhpcy5hb01hcCA9IG51bGw7XHJcblx0XHR0aGlzLmFvTWFwSW50ZW5zaXR5ID0gMS4wO1xyXG5cclxuXHRcdHRoaXMuc3BlY3VsYXJNYXAgPSBudWxsO1xyXG5cclxuXHRcdHRoaXMuYWxwaGFNYXAgPSBudWxsO1xyXG5cclxuXHRcdHRoaXMuZW52TWFwID0gbnVsbDtcclxuXHRcdHRoaXMuY29tYmluZSA9IE11bHRpcGx5T3BlcmF0aW9uO1xyXG5cdFx0dGhpcy5yZWZsZWN0aXZpdHkgPSAxO1xyXG5cdFx0dGhpcy5yZWZyYWN0aW9uUmF0aW8gPSAwLjk4O1xyXG5cclxuXHRcdHRoaXMud2lyZWZyYW1lID0gZmFsc2U7XHJcblx0XHR0aGlzLndpcmVmcmFtZUxpbmV3aWR0aCA9IDE7XHJcblx0XHR0aGlzLndpcmVmcmFtZUxpbmVjYXAgPSAncm91bmQnO1xyXG5cdFx0dGhpcy53aXJlZnJhbWVMaW5lam9pbiA9ICdyb3VuZCc7XHJcblxyXG5cdFx0dGhpcy5mb2cgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMuc2V0VmFsdWVzKCBwYXJhbWV0ZXJzICk7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xyXG5cclxuXHRcdHRoaXMuY29sb3IuY29weSggc291cmNlLmNvbG9yICk7XHJcblxyXG5cdFx0dGhpcy5tYXAgPSBzb3VyY2UubWFwO1xyXG5cclxuXHRcdHRoaXMubGlnaHRNYXAgPSBzb3VyY2UubGlnaHRNYXA7XHJcblx0XHR0aGlzLmxpZ2h0TWFwSW50ZW5zaXR5ID0gc291cmNlLmxpZ2h0TWFwSW50ZW5zaXR5O1xyXG5cclxuXHRcdHRoaXMuYW9NYXAgPSBzb3VyY2UuYW9NYXA7XHJcblx0XHR0aGlzLmFvTWFwSW50ZW5zaXR5ID0gc291cmNlLmFvTWFwSW50ZW5zaXR5O1xyXG5cclxuXHRcdHRoaXMuc3BlY3VsYXJNYXAgPSBzb3VyY2Uuc3BlY3VsYXJNYXA7XHJcblxyXG5cdFx0dGhpcy5hbHBoYU1hcCA9IHNvdXJjZS5hbHBoYU1hcDtcclxuXHJcblx0XHR0aGlzLmVudk1hcCA9IHNvdXJjZS5lbnZNYXA7XHJcblx0XHR0aGlzLmNvbWJpbmUgPSBzb3VyY2UuY29tYmluZTtcclxuXHRcdHRoaXMucmVmbGVjdGl2aXR5ID0gc291cmNlLnJlZmxlY3Rpdml0eTtcclxuXHRcdHRoaXMucmVmcmFjdGlvblJhdGlvID0gc291cmNlLnJlZnJhY3Rpb25SYXRpbztcclxuXHJcblx0XHR0aGlzLndpcmVmcmFtZSA9IHNvdXJjZS53aXJlZnJhbWU7XHJcblx0XHR0aGlzLndpcmVmcmFtZUxpbmV3aWR0aCA9IHNvdXJjZS53aXJlZnJhbWVMaW5ld2lkdGg7XHJcblx0XHR0aGlzLndpcmVmcmFtZUxpbmVjYXAgPSBzb3VyY2Uud2lyZWZyYW1lTGluZWNhcDtcclxuXHRcdHRoaXMud2lyZWZyYW1lTGluZWpvaW4gPSBzb3VyY2Uud2lyZWZyYW1lTGluZWpvaW47XHJcblxyXG5cdFx0dGhpcy5mb2cgPSBzb3VyY2UuZm9nO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBNZXNoQmFzaWNNYXRlcmlhbCB9O1xyXG4iLCJpbXBvcnQgeyBjbGFtcCB9IGZyb20gJy4uL21hdGgvTWF0aFV0aWxzLmpzJztcclxuXHJcbi8vIEZhc3QgSGFsZiBGbG9hdCBDb252ZXJzaW9ucywgaHR0cDovL3d3dy5mb3gtdG9vbGtpdC5vcmcvZnRwL2Zhc3RoYWxmZmxvYXRjb252ZXJzaW9uLnBkZlxyXG5cclxuY29uc3QgX3RhYmxlcyA9IC8qQF9fUFVSRV9fKi8gX2dlbmVyYXRlVGFibGVzKCk7XHJcblxyXG5mdW5jdGlvbiBfZ2VuZXJhdGVUYWJsZXMoKSB7XHJcblxyXG5cdC8vIGZsb2F0MzIgdG8gZmxvYXQxNiBoZWxwZXJzXHJcblxyXG5cdGNvbnN0IGJ1ZmZlciA9IG5ldyBBcnJheUJ1ZmZlciggNCApO1xyXG5cdGNvbnN0IGZsb2F0VmlldyA9IG5ldyBGbG9hdDMyQXJyYXkoIGJ1ZmZlciApO1xyXG5cdGNvbnN0IHVpbnQzMlZpZXcgPSBuZXcgVWludDMyQXJyYXkoIGJ1ZmZlciApO1xyXG5cclxuXHRjb25zdCBiYXNlVGFibGUgPSBuZXcgVWludDMyQXJyYXkoIDUxMiApO1xyXG5cdGNvbnN0IHNoaWZ0VGFibGUgPSBuZXcgVWludDMyQXJyYXkoIDUxMiApO1xyXG5cclxuXHRmb3IgKCBsZXQgaSA9IDA7IGkgPCAyNTY7ICsrIGkgKSB7XHJcblxyXG5cdFx0Y29uc3QgZSA9IGkgLSAxMjc7XHJcblxyXG5cdFx0Ly8gdmVyeSBzbWFsbCBudW1iZXIgKDAsIC0wKVxyXG5cclxuXHRcdGlmICggZSA8IC0gMjcgKSB7XHJcblxyXG5cdFx0XHRiYXNlVGFibGVbIGkgXSA9IDB4MDAwMDtcclxuXHRcdFx0YmFzZVRhYmxlWyBpIHwgMHgxMDAgXSA9IDB4ODAwMDtcclxuXHRcdFx0c2hpZnRUYWJsZVsgaSBdID0gMjQ7XHJcblx0XHRcdHNoaWZ0VGFibGVbIGkgfCAweDEwMCBdID0gMjQ7XHJcblxyXG5cdFx0XHQvLyBzbWFsbCBudW1iZXIgKGRlbm9ybSlcclxuXHJcblx0XHR9IGVsc2UgaWYgKCBlIDwgLSAxNCApIHtcclxuXHJcblx0XHRcdGJhc2VUYWJsZVsgaSBdID0gMHgwNDAwID4+ICggLSBlIC0gMTQgKTtcclxuXHRcdFx0YmFzZVRhYmxlWyBpIHwgMHgxMDAgXSA9ICggMHgwNDAwID4+ICggLSBlIC0gMTQgKSApIHwgMHg4MDAwO1xyXG5cdFx0XHRzaGlmdFRhYmxlWyBpIF0gPSAtIGUgLSAxO1xyXG5cdFx0XHRzaGlmdFRhYmxlWyBpIHwgMHgxMDAgXSA9IC0gZSAtIDE7XHJcblxyXG5cdFx0XHQvLyBub3JtYWwgbnVtYmVyXHJcblxyXG5cdFx0fSBlbHNlIGlmICggZSA8PSAxNSApIHtcclxuXHJcblx0XHRcdGJhc2VUYWJsZVsgaSBdID0gKCBlICsgMTUgKSA8PCAxMDtcclxuXHRcdFx0YmFzZVRhYmxlWyBpIHwgMHgxMDAgXSA9ICggKCBlICsgMTUgKSA8PCAxMCApIHwgMHg4MDAwO1xyXG5cdFx0XHRzaGlmdFRhYmxlWyBpIF0gPSAxMztcclxuXHRcdFx0c2hpZnRUYWJsZVsgaSB8IDB4MTAwIF0gPSAxMztcclxuXHJcblx0XHRcdC8vIGxhcmdlIG51bWJlciAoSW5maW5pdHksIC1JbmZpbml0eSlcclxuXHJcblx0XHR9IGVsc2UgaWYgKCBlIDwgMTI4ICkge1xyXG5cclxuXHRcdFx0YmFzZVRhYmxlWyBpIF0gPSAweDdjMDA7XHJcblx0XHRcdGJhc2VUYWJsZVsgaSB8IDB4MTAwIF0gPSAweGZjMDA7XHJcblx0XHRcdHNoaWZ0VGFibGVbIGkgXSA9IDI0O1xyXG5cdFx0XHRzaGlmdFRhYmxlWyBpIHwgMHgxMDAgXSA9IDI0O1xyXG5cclxuXHRcdFx0Ly8gc3RheSAoTmFOLCBJbmZpbml0eSwgLUluZmluaXR5KVxyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRiYXNlVGFibGVbIGkgXSA9IDB4N2MwMDtcclxuXHRcdFx0YmFzZVRhYmxlWyBpIHwgMHgxMDAgXSA9IDB4ZmMwMDtcclxuXHRcdFx0c2hpZnRUYWJsZVsgaSBdID0gMTM7XHJcblx0XHRcdHNoaWZ0VGFibGVbIGkgfCAweDEwMCBdID0gMTM7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdC8vIGZsb2F0MTYgdG8gZmxvYXQzMiBoZWxwZXJzXHJcblxyXG5cdGNvbnN0IG1hbnRpc3NhVGFibGUgPSBuZXcgVWludDMyQXJyYXkoIDIwNDggKTtcclxuXHRjb25zdCBleHBvbmVudFRhYmxlID0gbmV3IFVpbnQzMkFycmF5KCA2NCApO1xyXG5cdGNvbnN0IG9mZnNldFRhYmxlID0gbmV3IFVpbnQzMkFycmF5KCA2NCApO1xyXG5cclxuXHRmb3IgKCBsZXQgaSA9IDE7IGkgPCAxMDI0OyArKyBpICkge1xyXG5cclxuXHRcdGxldCBtID0gaSA8PCAxMzsgLy8gemVybyBwYWQgbWFudGlzc2EgYml0c1xyXG5cdFx0bGV0IGUgPSAwOyAvLyB6ZXJvIGV4cG9uZW50XHJcblxyXG5cdFx0Ly8gbm9ybWFsaXplZFxyXG5cdFx0d2hpbGUgKCAoIG0gJiAweDAwODAwMDAwICkgPT09IDAgKSB7XHJcblxyXG5cdFx0XHRtIDw8PSAxO1xyXG5cdFx0XHRlIC09IDB4MDA4MDAwMDA7IC8vIGRlY3JlbWVudCBleHBvbmVudFxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRtICY9IH4gMHgwMDgwMDAwMDsgLy8gY2xlYXIgbGVhZGluZyAxIGJpdFxyXG5cdFx0ZSArPSAweDM4ODAwMDAwOyAvLyBhZGp1c3QgYmlhc1xyXG5cclxuXHRcdG1hbnRpc3NhVGFibGVbIGkgXSA9IG0gfCBlO1xyXG5cclxuXHR9XHJcblxyXG5cdGZvciAoIGxldCBpID0gMTAyNDsgaSA8IDIwNDg7ICsrIGkgKSB7XHJcblxyXG5cdFx0bWFudGlzc2FUYWJsZVsgaSBdID0gMHgzODAwMDAwMCArICggKCBpIC0gMTAyNCApIDw8IDEzICk7XHJcblxyXG5cdH1cclxuXHJcblx0Zm9yICggbGV0IGkgPSAxOyBpIDwgMzE7ICsrIGkgKSB7XHJcblxyXG5cdFx0ZXhwb25lbnRUYWJsZVsgaSBdID0gaSA8PCAyMztcclxuXHJcblx0fVxyXG5cclxuXHRleHBvbmVudFRhYmxlWyAzMSBdID0gMHg0NzgwMDAwMDtcclxuXHRleHBvbmVudFRhYmxlWyAzMiBdID0gMHg4MDAwMDAwMDtcclxuXHJcblx0Zm9yICggbGV0IGkgPSAzMzsgaSA8IDYzOyArKyBpICkge1xyXG5cclxuXHRcdGV4cG9uZW50VGFibGVbIGkgXSA9IDB4ODAwMDAwMDAgKyAoICggaSAtIDMyICkgPDwgMjMgKTtcclxuXHJcblx0fVxyXG5cclxuXHRleHBvbmVudFRhYmxlWyA2MyBdID0gMHhjNzgwMDAwMDtcclxuXHJcblx0Zm9yICggbGV0IGkgPSAxOyBpIDwgNjQ7ICsrIGkgKSB7XHJcblxyXG5cdFx0aWYgKCBpICE9PSAzMiApIHtcclxuXHJcblx0XHRcdG9mZnNldFRhYmxlWyBpIF0gPSAxMDI0O1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4ge1xyXG5cdFx0ZmxvYXRWaWV3OiBmbG9hdFZpZXcsXHJcblx0XHR1aW50MzJWaWV3OiB1aW50MzJWaWV3LFxyXG5cdFx0YmFzZVRhYmxlOiBiYXNlVGFibGUsXHJcblx0XHRzaGlmdFRhYmxlOiBzaGlmdFRhYmxlLFxyXG5cdFx0bWFudGlzc2FUYWJsZTogbWFudGlzc2FUYWJsZSxcclxuXHRcdGV4cG9uZW50VGFibGU6IGV4cG9uZW50VGFibGUsXHJcblx0XHRvZmZzZXRUYWJsZTogb2Zmc2V0VGFibGVcclxuXHR9O1xyXG5cclxufVxyXG5cclxuLy8gZmxvYXQzMiB0byBmbG9hdDE2XHJcblxyXG5mdW5jdGlvbiB0b0hhbGZGbG9hdCggdmFsICkge1xyXG5cclxuXHRpZiAoIE1hdGguYWJzKCB2YWwgKSA+IDY1NTA0ICkgY29uc29sZS53YXJuKCAnVEhSRUUuRGF0YVV0aWxzLnRvSGFsZkZsb2F0KCk6IFZhbHVlIG91dCBvZiByYW5nZS4nICk7XHJcblxyXG5cdHZhbCA9IGNsYW1wKCB2YWwsIC0gNjU1MDQsIDY1NTA0ICk7XHJcblxyXG5cdF90YWJsZXMuZmxvYXRWaWV3WyAwIF0gPSB2YWw7XHJcblx0Y29uc3QgZiA9IF90YWJsZXMudWludDMyVmlld1sgMCBdO1xyXG5cdGNvbnN0IGUgPSAoIGYgPj4gMjMgKSAmIDB4MWZmO1xyXG5cdHJldHVybiBfdGFibGVzLmJhc2VUYWJsZVsgZSBdICsgKCAoIGYgJiAweDAwN2ZmZmZmICkgPj4gX3RhYmxlcy5zaGlmdFRhYmxlWyBlIF0gKTtcclxuXHJcbn1cclxuXHJcbi8vIGZsb2F0MTYgdG8gZmxvYXQzMlxyXG5cclxuZnVuY3Rpb24gZnJvbUhhbGZGbG9hdCggdmFsICkge1xyXG5cclxuXHRjb25zdCBtID0gdmFsID4+IDEwO1xyXG5cdF90YWJsZXMudWludDMyVmlld1sgMCBdID0gX3RhYmxlcy5tYW50aXNzYVRhYmxlWyBfdGFibGVzLm9mZnNldFRhYmxlWyBtIF0gKyAoIHZhbCAmIDB4M2ZmICkgXSArIF90YWJsZXMuZXhwb25lbnRUYWJsZVsgbSBdO1xyXG5cdHJldHVybiBfdGFibGVzLmZsb2F0Vmlld1sgMCBdO1xyXG5cclxufVxyXG5cclxuY29uc3QgRGF0YVV0aWxzID0ge1xyXG5cdHRvSGFsZkZsb2F0OiB0b0hhbGZGbG9hdCxcclxuXHRmcm9tSGFsZkZsb2F0OiBmcm9tSGFsZkZsb2F0LFxyXG59O1xyXG5cclxuZXhwb3J0IHtcclxuXHR0b0hhbGZGbG9hdCxcclxuXHRmcm9tSGFsZkZsb2F0LFxyXG5cdERhdGFVdGlsc1xyXG59O1xyXG4iLCJpbXBvcnQgeyBWZWN0b3IzIH0gZnJvbSAnLi4vbWF0aC9WZWN0b3IzLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yMiB9IGZyb20gJy4uL21hdGgvVmVjdG9yMi5qcyc7XHJcbmltcG9ydCB7IGRlbm9ybWFsaXplLCBub3JtYWxpemUgfSBmcm9tICcuLi9tYXRoL01hdGhVdGlscy5qcyc7XHJcbmltcG9ydCB7IFN0YXRpY0RyYXdVc2FnZSwgRmxvYXRUeXBlIH0gZnJvbSAnLi4vY29uc3RhbnRzLmpzJztcclxuaW1wb3J0IHsgZnJvbUhhbGZGbG9hdCwgdG9IYWxmRmxvYXQgfSBmcm9tICcuLi9leHRyYXMvRGF0YVV0aWxzLmpzJztcclxuaW1wb3J0IHsgd2Fybk9uY2UgfSBmcm9tICcuLi91dGlscy5qcyc7XHJcblxyXG5jb25zdCBfdmVjdG9yID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5jb25zdCBfdmVjdG9yMiA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjIoKTtcclxuXHJcbmNsYXNzIEJ1ZmZlckF0dHJpYnV0ZSB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBhcnJheSwgaXRlbVNpemUsIG5vcm1hbGl6ZWQgPSBmYWxzZSApIHtcclxuXHJcblx0XHRpZiAoIEFycmF5LmlzQXJyYXkoIGFycmF5ICkgKSB7XHJcblxyXG5cdFx0XHR0aHJvdyBuZXcgVHlwZUVycm9yKCAnVEhSRUUuQnVmZmVyQXR0cmlidXRlOiBhcnJheSBzaG91bGQgYmUgYSBUeXBlZCBBcnJheS4nICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMuaXNCdWZmZXJBdHRyaWJ1dGUgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMubmFtZSA9ICcnO1xyXG5cclxuXHRcdHRoaXMuYXJyYXkgPSBhcnJheTtcclxuXHRcdHRoaXMuaXRlbVNpemUgPSBpdGVtU2l6ZTtcclxuXHRcdHRoaXMuY291bnQgPSBhcnJheSAhPT0gdW5kZWZpbmVkID8gYXJyYXkubGVuZ3RoIC8gaXRlbVNpemUgOiAwO1xyXG5cdFx0dGhpcy5ub3JtYWxpemVkID0gbm9ybWFsaXplZDtcclxuXHJcblx0XHR0aGlzLnVzYWdlID0gU3RhdGljRHJhd1VzYWdlO1xyXG5cdFx0dGhpcy5fdXBkYXRlUmFuZ2UgPSB7IG9mZnNldDogMCwgY291bnQ6IC0gMSB9O1xyXG5cdFx0dGhpcy51cGRhdGVSYW5nZXMgPSBbXTtcclxuXHRcdHRoaXMuZ3B1VHlwZSA9IEZsb2F0VHlwZTtcclxuXHJcblx0XHR0aGlzLnZlcnNpb24gPSAwO1xyXG5cclxuXHR9XHJcblxyXG5cdG9uVXBsb2FkQ2FsbGJhY2soKSB7fVxyXG5cclxuXHRzZXQgbmVlZHNVcGRhdGUoIHZhbHVlICkge1xyXG5cclxuXHRcdGlmICggdmFsdWUgPT09IHRydWUgKSB0aGlzLnZlcnNpb24gKys7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0IHVwZGF0ZVJhbmdlKCkge1xyXG5cclxuXHRcdHdhcm5PbmNlKCAnVEhSRUUuQnVmZmVyQXR0cmlidXRlOiB1cGRhdGVSYW5nZSgpIGlzIGRlcHJlY2F0ZWQgYW5kIHdpbGwgYmUgcmVtb3ZlZCBpbiByMTY5LiBVc2UgYWRkVXBkYXRlUmFuZ2UoKSBpbnN0ZWFkLicgKTsgLy8gQGRlcHJlY2F0ZWQsIHIxNTlcclxuXHRcdHJldHVybiB0aGlzLl91cGRhdGVSYW5nZTtcclxuXHJcblx0fVxyXG5cclxuXHRzZXRVc2FnZSggdmFsdWUgKSB7XHJcblxyXG5cdFx0dGhpcy51c2FnZSA9IHZhbHVlO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGFkZFVwZGF0ZVJhbmdlKCBzdGFydCwgY291bnQgKSB7XHJcblxyXG5cdFx0dGhpcy51cGRhdGVSYW5nZXMucHVzaCggeyBzdGFydCwgY291bnQgfSApO1xyXG5cclxuXHR9XHJcblxyXG5cdGNsZWFyVXBkYXRlUmFuZ2VzKCkge1xyXG5cclxuXHRcdHRoaXMudXBkYXRlUmFuZ2VzLmxlbmd0aCA9IDA7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHRoaXMubmFtZSA9IHNvdXJjZS5uYW1lO1xyXG5cdFx0dGhpcy5hcnJheSA9IG5ldyBzb3VyY2UuYXJyYXkuY29uc3RydWN0b3IoIHNvdXJjZS5hcnJheSApO1xyXG5cdFx0dGhpcy5pdGVtU2l6ZSA9IHNvdXJjZS5pdGVtU2l6ZTtcclxuXHRcdHRoaXMuY291bnQgPSBzb3VyY2UuY291bnQ7XHJcblx0XHR0aGlzLm5vcm1hbGl6ZWQgPSBzb3VyY2Uubm9ybWFsaXplZDtcclxuXHJcblx0XHR0aGlzLnVzYWdlID0gc291cmNlLnVzYWdlO1xyXG5cdFx0dGhpcy5ncHVUeXBlID0gc291cmNlLmdwdVR5cGU7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weUF0KCBpbmRleDEsIGF0dHJpYnV0ZSwgaW5kZXgyICkge1xyXG5cclxuXHRcdGluZGV4MSAqPSB0aGlzLml0ZW1TaXplO1xyXG5cdFx0aW5kZXgyICo9IGF0dHJpYnV0ZS5pdGVtU2l6ZTtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSB0aGlzLml0ZW1TaXplOyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdHRoaXMuYXJyYXlbIGluZGV4MSArIGkgXSA9IGF0dHJpYnV0ZS5hcnJheVsgaW5kZXgyICsgaSBdO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRjb3B5QXJyYXkoIGFycmF5ICkge1xyXG5cclxuXHRcdHRoaXMuYXJyYXkuc2V0KCBhcnJheSApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGFwcGx5TWF0cml4MyggbSApIHtcclxuXHJcblx0XHRpZiAoIHRoaXMuaXRlbVNpemUgPT09IDIgKSB7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSB0aGlzLmNvdW50OyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0X3ZlY3RvcjIuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggdGhpcywgaSApO1xyXG5cdFx0XHRcdF92ZWN0b3IyLmFwcGx5TWF0cml4MyggbSApO1xyXG5cclxuXHRcdFx0XHR0aGlzLnNldFhZKCBpLCBfdmVjdG9yMi54LCBfdmVjdG9yMi55ICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fSBlbHNlIGlmICggdGhpcy5pdGVtU2l6ZSA9PT0gMyApIHtcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMCwgbCA9IHRoaXMuY291bnQ7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRfdmVjdG9yLmZyb21CdWZmZXJBdHRyaWJ1dGUoIHRoaXMsIGkgKTtcclxuXHRcdFx0XHRfdmVjdG9yLmFwcGx5TWF0cml4MyggbSApO1xyXG5cclxuXHRcdFx0XHR0aGlzLnNldFhZWiggaSwgX3ZlY3Rvci54LCBfdmVjdG9yLnksIF92ZWN0b3IueiApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRhcHBseU1hdHJpeDQoIG0gKSB7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gdGhpcy5jb3VudDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRfdmVjdG9yLmZyb21CdWZmZXJBdHRyaWJ1dGUoIHRoaXMsIGkgKTtcclxuXHJcblx0XHRcdF92ZWN0b3IuYXBwbHlNYXRyaXg0KCBtICk7XHJcblxyXG5cdFx0XHR0aGlzLnNldFhZWiggaSwgX3ZlY3Rvci54LCBfdmVjdG9yLnksIF92ZWN0b3IueiApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRhcHBseU5vcm1hbE1hdHJpeCggbSApIHtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSB0aGlzLmNvdW50OyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdF92ZWN0b3IuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggdGhpcywgaSApO1xyXG5cclxuXHRcdFx0X3ZlY3Rvci5hcHBseU5vcm1hbE1hdHJpeCggbSApO1xyXG5cclxuXHRcdFx0dGhpcy5zZXRYWVooIGksIF92ZWN0b3IueCwgX3ZlY3Rvci55LCBfdmVjdG9yLnogKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0dHJhbnNmb3JtRGlyZWN0aW9uKCBtICkge1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IHRoaXMuY291bnQ7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0X3ZlY3Rvci5mcm9tQnVmZmVyQXR0cmlidXRlKCB0aGlzLCBpICk7XHJcblxyXG5cdFx0XHRfdmVjdG9yLnRyYW5zZm9ybURpcmVjdGlvbiggbSApO1xyXG5cclxuXHRcdFx0dGhpcy5zZXRYWVooIGksIF92ZWN0b3IueCwgX3ZlY3Rvci55LCBfdmVjdG9yLnogKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0KCB2YWx1ZSwgb2Zmc2V0ID0gMCApIHtcclxuXHJcblx0XHQvLyBNYXRjaGluZyBCdWZmZXJBdHRyaWJ1dGUgY29uc3RydWN0b3IsIGRvIG5vdCBub3JtYWxpemUgdGhlIGFycmF5LlxyXG5cdFx0dGhpcy5hcnJheS5zZXQoIHZhbHVlLCBvZmZzZXQgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRnZXRDb21wb25lbnQoIGluZGV4LCBjb21wb25lbnQgKSB7XHJcblxyXG5cdFx0bGV0IHZhbHVlID0gdGhpcy5hcnJheVsgaW5kZXggKiB0aGlzLml0ZW1TaXplICsgY29tcG9uZW50IF07XHJcblxyXG5cdFx0aWYgKCB0aGlzLm5vcm1hbGl6ZWQgKSB2YWx1ZSA9IGRlbm9ybWFsaXplKCB2YWx1ZSwgdGhpcy5hcnJheSApO1xyXG5cclxuXHRcdHJldHVybiB2YWx1ZTtcclxuXHJcblx0fVxyXG5cclxuXHRzZXRDb21wb25lbnQoIGluZGV4LCBjb21wb25lbnQsIHZhbHVlICkge1xyXG5cclxuXHRcdGlmICggdGhpcy5ub3JtYWxpemVkICkgdmFsdWUgPSBub3JtYWxpemUoIHZhbHVlLCB0aGlzLmFycmF5ICk7XHJcblxyXG5cdFx0dGhpcy5hcnJheVsgaW5kZXggKiB0aGlzLml0ZW1TaXplICsgY29tcG9uZW50IF0gPSB2YWx1ZTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRnZXRYKCBpbmRleCApIHtcclxuXHJcblx0XHRsZXQgeCA9IHRoaXMuYXJyYXlbIGluZGV4ICogdGhpcy5pdGVtU2l6ZSBdO1xyXG5cclxuXHRcdGlmICggdGhpcy5ub3JtYWxpemVkICkgeCA9IGRlbm9ybWFsaXplKCB4LCB0aGlzLmFycmF5ICk7XHJcblxyXG5cdFx0cmV0dXJuIHg7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0WCggaW5kZXgsIHggKSB7XHJcblxyXG5cdFx0aWYgKCB0aGlzLm5vcm1hbGl6ZWQgKSB4ID0gbm9ybWFsaXplKCB4LCB0aGlzLmFycmF5ICk7XHJcblxyXG5cdFx0dGhpcy5hcnJheVsgaW5kZXggKiB0aGlzLml0ZW1TaXplIF0gPSB4O1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldFkoIGluZGV4ICkge1xyXG5cclxuXHRcdGxldCB5ID0gdGhpcy5hcnJheVsgaW5kZXggKiB0aGlzLml0ZW1TaXplICsgMSBdO1xyXG5cclxuXHRcdGlmICggdGhpcy5ub3JtYWxpemVkICkgeSA9IGRlbm9ybWFsaXplKCB5LCB0aGlzLmFycmF5ICk7XHJcblxyXG5cdFx0cmV0dXJuIHk7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0WSggaW5kZXgsIHkgKSB7XHJcblxyXG5cdFx0aWYgKCB0aGlzLm5vcm1hbGl6ZWQgKSB5ID0gbm9ybWFsaXplKCB5LCB0aGlzLmFycmF5ICk7XHJcblxyXG5cdFx0dGhpcy5hcnJheVsgaW5kZXggKiB0aGlzLml0ZW1TaXplICsgMSBdID0geTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRnZXRaKCBpbmRleCApIHtcclxuXHJcblx0XHRsZXQgeiA9IHRoaXMuYXJyYXlbIGluZGV4ICogdGhpcy5pdGVtU2l6ZSArIDIgXTtcclxuXHJcblx0XHRpZiAoIHRoaXMubm9ybWFsaXplZCApIHogPSBkZW5vcm1hbGl6ZSggeiwgdGhpcy5hcnJheSApO1xyXG5cclxuXHRcdHJldHVybiB6O1xyXG5cclxuXHR9XHJcblxyXG5cdHNldFooIGluZGV4LCB6ICkge1xyXG5cclxuXHRcdGlmICggdGhpcy5ub3JtYWxpemVkICkgeiA9IG5vcm1hbGl6ZSggeiwgdGhpcy5hcnJheSApO1xyXG5cclxuXHRcdHRoaXMuYXJyYXlbIGluZGV4ICogdGhpcy5pdGVtU2l6ZSArIDIgXSA9IHo7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0VyggaW5kZXggKSB7XHJcblxyXG5cdFx0bGV0IHcgPSB0aGlzLmFycmF5WyBpbmRleCAqIHRoaXMuaXRlbVNpemUgKyAzIF07XHJcblxyXG5cdFx0aWYgKCB0aGlzLm5vcm1hbGl6ZWQgKSB3ID0gZGVub3JtYWxpemUoIHcsIHRoaXMuYXJyYXkgKTtcclxuXHJcblx0XHRyZXR1cm4gdztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRXKCBpbmRleCwgdyApIHtcclxuXHJcblx0XHRpZiAoIHRoaXMubm9ybWFsaXplZCApIHcgPSBub3JtYWxpemUoIHcsIHRoaXMuYXJyYXkgKTtcclxuXHJcblx0XHR0aGlzLmFycmF5WyBpbmRleCAqIHRoaXMuaXRlbVNpemUgKyAzIF0gPSB3O1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldFhZKCBpbmRleCwgeCwgeSApIHtcclxuXHJcblx0XHRpbmRleCAqPSB0aGlzLml0ZW1TaXplO1xyXG5cclxuXHRcdGlmICggdGhpcy5ub3JtYWxpemVkICkge1xyXG5cclxuXHRcdFx0eCA9IG5vcm1hbGl6ZSggeCwgdGhpcy5hcnJheSApO1xyXG5cdFx0XHR5ID0gbm9ybWFsaXplKCB5LCB0aGlzLmFycmF5ICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMuYXJyYXlbIGluZGV4ICsgMCBdID0geDtcclxuXHRcdHRoaXMuYXJyYXlbIGluZGV4ICsgMSBdID0geTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRYWVooIGluZGV4LCB4LCB5LCB6ICkge1xyXG5cclxuXHRcdGluZGV4ICo9IHRoaXMuaXRlbVNpemU7XHJcblxyXG5cdFx0aWYgKCB0aGlzLm5vcm1hbGl6ZWQgKSB7XHJcblxyXG5cdFx0XHR4ID0gbm9ybWFsaXplKCB4LCB0aGlzLmFycmF5ICk7XHJcblx0XHRcdHkgPSBub3JtYWxpemUoIHksIHRoaXMuYXJyYXkgKTtcclxuXHRcdFx0eiA9IG5vcm1hbGl6ZSggeiwgdGhpcy5hcnJheSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLmFycmF5WyBpbmRleCArIDAgXSA9IHg7XHJcblx0XHR0aGlzLmFycmF5WyBpbmRleCArIDEgXSA9IHk7XHJcblx0XHR0aGlzLmFycmF5WyBpbmRleCArIDIgXSA9IHo7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0WFlaVyggaW5kZXgsIHgsIHksIHosIHcgKSB7XHJcblxyXG5cdFx0aW5kZXggKj0gdGhpcy5pdGVtU2l6ZTtcclxuXHJcblx0XHRpZiAoIHRoaXMubm9ybWFsaXplZCApIHtcclxuXHJcblx0XHRcdHggPSBub3JtYWxpemUoIHgsIHRoaXMuYXJyYXkgKTtcclxuXHRcdFx0eSA9IG5vcm1hbGl6ZSggeSwgdGhpcy5hcnJheSApO1xyXG5cdFx0XHR6ID0gbm9ybWFsaXplKCB6LCB0aGlzLmFycmF5ICk7XHJcblx0XHRcdHcgPSBub3JtYWxpemUoIHcsIHRoaXMuYXJyYXkgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5hcnJheVsgaW5kZXggKyAwIF0gPSB4O1xyXG5cdFx0dGhpcy5hcnJheVsgaW5kZXggKyAxIF0gPSB5O1xyXG5cdFx0dGhpcy5hcnJheVsgaW5kZXggKyAyIF0gPSB6O1xyXG5cdFx0dGhpcy5hcnJheVsgaW5kZXggKyAzIF0gPSB3O1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdG9uVXBsb2FkKCBjYWxsYmFjayApIHtcclxuXHJcblx0XHR0aGlzLm9uVXBsb2FkQ2FsbGJhY2sgPSBjYWxsYmFjaztcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRjbG9uZSgpIHtcclxuXHJcblx0XHRyZXR1cm4gbmV3IHRoaXMuY29uc3RydWN0b3IoIHRoaXMuYXJyYXksIHRoaXMuaXRlbVNpemUgKS5jb3B5KCB0aGlzICk7XHJcblxyXG5cdH1cclxuXHJcblx0dG9KU09OKCkge1xyXG5cclxuXHRcdGNvbnN0IGRhdGEgPSB7XHJcblx0XHRcdGl0ZW1TaXplOiB0aGlzLml0ZW1TaXplLFxyXG5cdFx0XHR0eXBlOiB0aGlzLmFycmF5LmNvbnN0cnVjdG9yLm5hbWUsXHJcblx0XHRcdGFycmF5OiBBcnJheS5mcm9tKCB0aGlzLmFycmF5ICksXHJcblx0XHRcdG5vcm1hbGl6ZWQ6IHRoaXMubm9ybWFsaXplZFxyXG5cdFx0fTtcclxuXHJcblx0XHRpZiAoIHRoaXMubmFtZSAhPT0gJycgKSBkYXRhLm5hbWUgPSB0aGlzLm5hbWU7XHJcblx0XHRpZiAoIHRoaXMudXNhZ2UgIT09IFN0YXRpY0RyYXdVc2FnZSApIGRhdGEudXNhZ2UgPSB0aGlzLnVzYWdlO1xyXG5cclxuXHRcdHJldHVybiBkYXRhO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG4vL1xyXG5cclxuY2xhc3MgSW50OEJ1ZmZlckF0dHJpYnV0ZSBleHRlbmRzIEJ1ZmZlckF0dHJpYnV0ZSB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBhcnJheSwgaXRlbVNpemUsIG5vcm1hbGl6ZWQgKSB7XHJcblxyXG5cdFx0c3VwZXIoIG5ldyBJbnQ4QXJyYXkoIGFycmF5ICksIGl0ZW1TaXplLCBub3JtYWxpemVkICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmNsYXNzIFVpbnQ4QnVmZmVyQXR0cmlidXRlIGV4dGVuZHMgQnVmZmVyQXR0cmlidXRlIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIGFycmF5LCBpdGVtU2l6ZSwgbm9ybWFsaXplZCApIHtcclxuXHJcblx0XHRzdXBlciggbmV3IFVpbnQ4QXJyYXkoIGFycmF5ICksIGl0ZW1TaXplLCBub3JtYWxpemVkICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmNsYXNzIFVpbnQ4Q2xhbXBlZEJ1ZmZlckF0dHJpYnV0ZSBleHRlbmRzIEJ1ZmZlckF0dHJpYnV0ZSB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBhcnJheSwgaXRlbVNpemUsIG5vcm1hbGl6ZWQgKSB7XHJcblxyXG5cdFx0c3VwZXIoIG5ldyBVaW50OENsYW1wZWRBcnJheSggYXJyYXkgKSwgaXRlbVNpemUsIG5vcm1hbGl6ZWQgKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuY2xhc3MgSW50MTZCdWZmZXJBdHRyaWJ1dGUgZXh0ZW5kcyBCdWZmZXJBdHRyaWJ1dGUge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggYXJyYXksIGl0ZW1TaXplLCBub3JtYWxpemVkICkge1xyXG5cclxuXHRcdHN1cGVyKCBuZXcgSW50MTZBcnJheSggYXJyYXkgKSwgaXRlbVNpemUsIG5vcm1hbGl6ZWQgKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuY2xhc3MgVWludDE2QnVmZmVyQXR0cmlidXRlIGV4dGVuZHMgQnVmZmVyQXR0cmlidXRlIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIGFycmF5LCBpdGVtU2l6ZSwgbm9ybWFsaXplZCApIHtcclxuXHJcblx0XHRzdXBlciggbmV3IFVpbnQxNkFycmF5KCBhcnJheSApLCBpdGVtU2l6ZSwgbm9ybWFsaXplZCApO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5jbGFzcyBJbnQzMkJ1ZmZlckF0dHJpYnV0ZSBleHRlbmRzIEJ1ZmZlckF0dHJpYnV0ZSB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBhcnJheSwgaXRlbVNpemUsIG5vcm1hbGl6ZWQgKSB7XHJcblxyXG5cdFx0c3VwZXIoIG5ldyBJbnQzMkFycmF5KCBhcnJheSApLCBpdGVtU2l6ZSwgbm9ybWFsaXplZCApO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5jbGFzcyBVaW50MzJCdWZmZXJBdHRyaWJ1dGUgZXh0ZW5kcyBCdWZmZXJBdHRyaWJ1dGUge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggYXJyYXksIGl0ZW1TaXplLCBub3JtYWxpemVkICkge1xyXG5cclxuXHRcdHN1cGVyKCBuZXcgVWludDMyQXJyYXkoIGFycmF5ICksIGl0ZW1TaXplLCBub3JtYWxpemVkICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmNsYXNzIEZsb2F0MTZCdWZmZXJBdHRyaWJ1dGUgZXh0ZW5kcyBCdWZmZXJBdHRyaWJ1dGUge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggYXJyYXksIGl0ZW1TaXplLCBub3JtYWxpemVkICkge1xyXG5cclxuXHRcdHN1cGVyKCBuZXcgVWludDE2QXJyYXkoIGFycmF5ICksIGl0ZW1TaXplLCBub3JtYWxpemVkICk7XHJcblxyXG5cdFx0dGhpcy5pc0Zsb2F0MTZCdWZmZXJBdHRyaWJ1dGUgPSB0cnVlO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldFgoIGluZGV4ICkge1xyXG5cclxuXHRcdGxldCB4ID0gZnJvbUhhbGZGbG9hdCggdGhpcy5hcnJheVsgaW5kZXggKiB0aGlzLml0ZW1TaXplIF0gKTtcclxuXHJcblx0XHRpZiAoIHRoaXMubm9ybWFsaXplZCApIHggPSBkZW5vcm1hbGl6ZSggeCwgdGhpcy5hcnJheSApO1xyXG5cclxuXHRcdHJldHVybiB4O1xyXG5cclxuXHR9XHJcblxyXG5cdHNldFgoIGluZGV4LCB4ICkge1xyXG5cclxuXHRcdGlmICggdGhpcy5ub3JtYWxpemVkICkgeCA9IG5vcm1hbGl6ZSggeCwgdGhpcy5hcnJheSApO1xyXG5cclxuXHRcdHRoaXMuYXJyYXlbIGluZGV4ICogdGhpcy5pdGVtU2l6ZSBdID0gdG9IYWxmRmxvYXQoIHggKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRnZXRZKCBpbmRleCApIHtcclxuXHJcblx0XHRsZXQgeSA9IGZyb21IYWxmRmxvYXQoIHRoaXMuYXJyYXlbIGluZGV4ICogdGhpcy5pdGVtU2l6ZSArIDEgXSApO1xyXG5cclxuXHRcdGlmICggdGhpcy5ub3JtYWxpemVkICkgeSA9IGRlbm9ybWFsaXplKCB5LCB0aGlzLmFycmF5ICk7XHJcblxyXG5cdFx0cmV0dXJuIHk7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0WSggaW5kZXgsIHkgKSB7XHJcblxyXG5cdFx0aWYgKCB0aGlzLm5vcm1hbGl6ZWQgKSB5ID0gbm9ybWFsaXplKCB5LCB0aGlzLmFycmF5ICk7XHJcblxyXG5cdFx0dGhpcy5hcnJheVsgaW5kZXggKiB0aGlzLml0ZW1TaXplICsgMSBdID0gdG9IYWxmRmxvYXQoIHkgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRnZXRaKCBpbmRleCApIHtcclxuXHJcblx0XHRsZXQgeiA9IGZyb21IYWxmRmxvYXQoIHRoaXMuYXJyYXlbIGluZGV4ICogdGhpcy5pdGVtU2l6ZSArIDIgXSApO1xyXG5cclxuXHRcdGlmICggdGhpcy5ub3JtYWxpemVkICkgeiA9IGRlbm9ybWFsaXplKCB6LCB0aGlzLmFycmF5ICk7XHJcblxyXG5cdFx0cmV0dXJuIHo7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0WiggaW5kZXgsIHogKSB7XHJcblxyXG5cdFx0aWYgKCB0aGlzLm5vcm1hbGl6ZWQgKSB6ID0gbm9ybWFsaXplKCB6LCB0aGlzLmFycmF5ICk7XHJcblxyXG5cdFx0dGhpcy5hcnJheVsgaW5kZXggKiB0aGlzLml0ZW1TaXplICsgMiBdID0gdG9IYWxmRmxvYXQoIHogKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRnZXRXKCBpbmRleCApIHtcclxuXHJcblx0XHRsZXQgdyA9IGZyb21IYWxmRmxvYXQoIHRoaXMuYXJyYXlbIGluZGV4ICogdGhpcy5pdGVtU2l6ZSArIDMgXSApO1xyXG5cclxuXHRcdGlmICggdGhpcy5ub3JtYWxpemVkICkgdyA9IGRlbm9ybWFsaXplKCB3LCB0aGlzLmFycmF5ICk7XHJcblxyXG5cdFx0cmV0dXJuIHc7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0VyggaW5kZXgsIHcgKSB7XHJcblxyXG5cdFx0aWYgKCB0aGlzLm5vcm1hbGl6ZWQgKSB3ID0gbm9ybWFsaXplKCB3LCB0aGlzLmFycmF5ICk7XHJcblxyXG5cdFx0dGhpcy5hcnJheVsgaW5kZXggKiB0aGlzLml0ZW1TaXplICsgMyBdID0gdG9IYWxmRmxvYXQoIHcgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRYWSggaW5kZXgsIHgsIHkgKSB7XHJcblxyXG5cdFx0aW5kZXggKj0gdGhpcy5pdGVtU2l6ZTtcclxuXHJcblx0XHRpZiAoIHRoaXMubm9ybWFsaXplZCApIHtcclxuXHJcblx0XHRcdHggPSBub3JtYWxpemUoIHgsIHRoaXMuYXJyYXkgKTtcclxuXHRcdFx0eSA9IG5vcm1hbGl6ZSggeSwgdGhpcy5hcnJheSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLmFycmF5WyBpbmRleCArIDAgXSA9IHRvSGFsZkZsb2F0KCB4ICk7XHJcblx0XHR0aGlzLmFycmF5WyBpbmRleCArIDEgXSA9IHRvSGFsZkZsb2F0KCB5ICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0WFlaKCBpbmRleCwgeCwgeSwgeiApIHtcclxuXHJcblx0XHRpbmRleCAqPSB0aGlzLml0ZW1TaXplO1xyXG5cclxuXHRcdGlmICggdGhpcy5ub3JtYWxpemVkICkge1xyXG5cclxuXHRcdFx0eCA9IG5vcm1hbGl6ZSggeCwgdGhpcy5hcnJheSApO1xyXG5cdFx0XHR5ID0gbm9ybWFsaXplKCB5LCB0aGlzLmFycmF5ICk7XHJcblx0XHRcdHogPSBub3JtYWxpemUoIHosIHRoaXMuYXJyYXkgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5hcnJheVsgaW5kZXggKyAwIF0gPSB0b0hhbGZGbG9hdCggeCApO1xyXG5cdFx0dGhpcy5hcnJheVsgaW5kZXggKyAxIF0gPSB0b0hhbGZGbG9hdCggeSApO1xyXG5cdFx0dGhpcy5hcnJheVsgaW5kZXggKyAyIF0gPSB0b0hhbGZGbG9hdCggeiApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldFhZWlcoIGluZGV4LCB4LCB5LCB6LCB3ICkge1xyXG5cclxuXHRcdGluZGV4ICo9IHRoaXMuaXRlbVNpemU7XHJcblxyXG5cdFx0aWYgKCB0aGlzLm5vcm1hbGl6ZWQgKSB7XHJcblxyXG5cdFx0XHR4ID0gbm9ybWFsaXplKCB4LCB0aGlzLmFycmF5ICk7XHJcblx0XHRcdHkgPSBub3JtYWxpemUoIHksIHRoaXMuYXJyYXkgKTtcclxuXHRcdFx0eiA9IG5vcm1hbGl6ZSggeiwgdGhpcy5hcnJheSApO1xyXG5cdFx0XHR3ID0gbm9ybWFsaXplKCB3LCB0aGlzLmFycmF5ICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMuYXJyYXlbIGluZGV4ICsgMCBdID0gdG9IYWxmRmxvYXQoIHggKTtcclxuXHRcdHRoaXMuYXJyYXlbIGluZGV4ICsgMSBdID0gdG9IYWxmRmxvYXQoIHkgKTtcclxuXHRcdHRoaXMuYXJyYXlbIGluZGV4ICsgMiBdID0gdG9IYWxmRmxvYXQoIHogKTtcclxuXHRcdHRoaXMuYXJyYXlbIGluZGV4ICsgMyBdID0gdG9IYWxmRmxvYXQoIHcgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuXHJcbmNsYXNzIEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUgZXh0ZW5kcyBCdWZmZXJBdHRyaWJ1dGUge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggYXJyYXksIGl0ZW1TaXplLCBub3JtYWxpemVkICkge1xyXG5cclxuXHRcdHN1cGVyKCBuZXcgRmxvYXQzMkFycmF5KCBhcnJheSApLCBpdGVtU2l6ZSwgbm9ybWFsaXplZCApO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5jbGFzcyBGbG9hdDY0QnVmZmVyQXR0cmlidXRlIGV4dGVuZHMgQnVmZmVyQXR0cmlidXRlIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIGFycmF5LCBpdGVtU2l6ZSwgbm9ybWFsaXplZCApIHtcclxuXHJcblx0XHRzdXBlciggbmV3IEZsb2F0NjRBcnJheSggYXJyYXkgKSwgaXRlbVNpemUsIG5vcm1hbGl6ZWQgKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuLy9cclxuXHJcbmV4cG9ydCB7XHJcblx0RmxvYXQ2NEJ1ZmZlckF0dHJpYnV0ZSxcclxuXHRGbG9hdDMyQnVmZmVyQXR0cmlidXRlLFxyXG5cdEZsb2F0MTZCdWZmZXJBdHRyaWJ1dGUsXHJcblx0VWludDMyQnVmZmVyQXR0cmlidXRlLFxyXG5cdEludDMyQnVmZmVyQXR0cmlidXRlLFxyXG5cdFVpbnQxNkJ1ZmZlckF0dHJpYnV0ZSxcclxuXHRJbnQxNkJ1ZmZlckF0dHJpYnV0ZSxcclxuXHRVaW50OENsYW1wZWRCdWZmZXJBdHRyaWJ1dGUsXHJcblx0VWludDhCdWZmZXJBdHRyaWJ1dGUsXHJcblx0SW50OEJ1ZmZlckF0dHJpYnV0ZSxcclxuXHRCdWZmZXJBdHRyaWJ1dGVcclxufTtcclxuIiwiaW1wb3J0IHsgVmVjdG9yMyB9IGZyb20gJy4uL21hdGgvVmVjdG9yMy5qcyc7XHJcbmltcG9ydCB7IFZlY3RvcjIgfSBmcm9tICcuLi9tYXRoL1ZlY3RvcjIuanMnO1xyXG5pbXBvcnQgeyBCb3gzIH0gZnJvbSAnLi4vbWF0aC9Cb3gzLmpzJztcclxuaW1wb3J0IHsgRXZlbnREaXNwYXRjaGVyIH0gZnJvbSAnLi9FdmVudERpc3BhdGNoZXIuanMnO1xyXG5pbXBvcnQgeyBCdWZmZXJBdHRyaWJ1dGUsIEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUsIFVpbnQxNkJ1ZmZlckF0dHJpYnV0ZSwgVWludDMyQnVmZmVyQXR0cmlidXRlIH0gZnJvbSAnLi9CdWZmZXJBdHRyaWJ1dGUuanMnO1xyXG5pbXBvcnQgeyBTcGhlcmUgfSBmcm9tICcuLi9tYXRoL1NwaGVyZS5qcyc7XHJcbmltcG9ydCB7IE9iamVjdDNEIH0gZnJvbSAnLi9PYmplY3QzRC5qcyc7XHJcbmltcG9ydCB7IE1hdHJpeDQgfSBmcm9tICcuLi9tYXRoL01hdHJpeDQuanMnO1xyXG5pbXBvcnQgeyBNYXRyaXgzIH0gZnJvbSAnLi4vbWF0aC9NYXRyaXgzLmpzJztcclxuaW1wb3J0ICogYXMgTWF0aFV0aWxzIGZyb20gJy4uL21hdGgvTWF0aFV0aWxzLmpzJztcclxuaW1wb3J0IHsgYXJyYXlOZWVkc1VpbnQzMiB9IGZyb20gJy4uL3V0aWxzLmpzJztcclxuXHJcbmxldCBfaWQgPSAwO1xyXG5cclxuY29uc3QgX20xID0gLypAX19QVVJFX18qLyBuZXcgTWF0cml4NCgpO1xyXG5jb25zdCBfb2JqID0gLypAX19QVVJFX18qLyBuZXcgT2JqZWN0M0QoKTtcclxuY29uc3QgX29mZnNldCA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuY29uc3QgX2JveCA9IC8qQF9fUFVSRV9fKi8gbmV3IEJveDMoKTtcclxuY29uc3QgX2JveE1vcnBoVGFyZ2V0cyA9IC8qQF9fUFVSRV9fKi8gbmV3IEJveDMoKTtcclxuY29uc3QgX3ZlY3RvciA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuXHJcbmNsYXNzIEJ1ZmZlckdlb21ldHJ5IGV4dGVuZHMgRXZlbnREaXNwYXRjaGVyIHtcclxuXHJcblx0Y29uc3RydWN0b3IoKSB7XHJcblxyXG5cdFx0c3VwZXIoKTtcclxuXHJcblx0XHR0aGlzLmlzQnVmZmVyR2VvbWV0cnkgPSB0cnVlO1xyXG5cclxuXHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eSggdGhpcywgJ2lkJywgeyB2YWx1ZTogX2lkICsrIH0gKTtcclxuXHJcblx0XHR0aGlzLnV1aWQgPSBNYXRoVXRpbHMuZ2VuZXJhdGVVVUlEKCk7XHJcblxyXG5cdFx0dGhpcy5uYW1lID0gJyc7XHJcblx0XHR0aGlzLnR5cGUgPSAnQnVmZmVyR2VvbWV0cnknO1xyXG5cclxuXHRcdHRoaXMuaW5kZXggPSBudWxsO1xyXG5cdFx0dGhpcy5hdHRyaWJ1dGVzID0ge307XHJcblxyXG5cdFx0dGhpcy5tb3JwaEF0dHJpYnV0ZXMgPSB7fTtcclxuXHRcdHRoaXMubW9ycGhUYXJnZXRzUmVsYXRpdmUgPSBmYWxzZTtcclxuXHJcblx0XHR0aGlzLmdyb3VwcyA9IFtdO1xyXG5cclxuXHRcdHRoaXMuYm91bmRpbmdCb3ggPSBudWxsO1xyXG5cdFx0dGhpcy5ib3VuZGluZ1NwaGVyZSA9IG51bGw7XHJcblxyXG5cdFx0dGhpcy5kcmF3UmFuZ2UgPSB7IHN0YXJ0OiAwLCBjb3VudDogSW5maW5pdHkgfTtcclxuXHJcblx0XHR0aGlzLnVzZXJEYXRhID0ge307XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0SW5kZXgoKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuaW5kZXg7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0SW5kZXgoIGluZGV4ICkge1xyXG5cclxuXHRcdGlmICggQXJyYXkuaXNBcnJheSggaW5kZXggKSApIHtcclxuXHJcblx0XHRcdHRoaXMuaW5kZXggPSBuZXcgKCBhcnJheU5lZWRzVWludDMyKCBpbmRleCApID8gVWludDMyQnVmZmVyQXR0cmlidXRlIDogVWludDE2QnVmZmVyQXR0cmlidXRlICkoIGluZGV4LCAxICk7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdHRoaXMuaW5kZXggPSBpbmRleDtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0QXR0cmlidXRlKCBuYW1lICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLmF0dHJpYnV0ZXNbIG5hbWUgXTtcclxuXHJcblx0fVxyXG5cclxuXHRzZXRBdHRyaWJ1dGUoIG5hbWUsIGF0dHJpYnV0ZSApIHtcclxuXHJcblx0XHR0aGlzLmF0dHJpYnV0ZXNbIG5hbWUgXSA9IGF0dHJpYnV0ZTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRkZWxldGVBdHRyaWJ1dGUoIG5hbWUgKSB7XHJcblxyXG5cdFx0ZGVsZXRlIHRoaXMuYXR0cmlidXRlc1sgbmFtZSBdO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGhhc0F0dHJpYnV0ZSggbmFtZSApIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5hdHRyaWJ1dGVzWyBuYW1lIF0gIT09IHVuZGVmaW5lZDtcclxuXHJcblx0fVxyXG5cclxuXHRhZGRHcm91cCggc3RhcnQsIGNvdW50LCBtYXRlcmlhbEluZGV4ID0gMCApIHtcclxuXHJcblx0XHR0aGlzLmdyb3Vwcy5wdXNoKCB7XHJcblxyXG5cdFx0XHRzdGFydDogc3RhcnQsXHJcblx0XHRcdGNvdW50OiBjb3VudCxcclxuXHRcdFx0bWF0ZXJpYWxJbmRleDogbWF0ZXJpYWxJbmRleFxyXG5cclxuXHRcdH0gKTtcclxuXHJcblx0fVxyXG5cclxuXHRjbGVhckdyb3VwcygpIHtcclxuXHJcblx0XHR0aGlzLmdyb3VwcyA9IFtdO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldERyYXdSYW5nZSggc3RhcnQsIGNvdW50ICkge1xyXG5cclxuXHRcdHRoaXMuZHJhd1JhbmdlLnN0YXJ0ID0gc3RhcnQ7XHJcblx0XHR0aGlzLmRyYXdSYW5nZS5jb3VudCA9IGNvdW50O1xyXG5cclxuXHR9XHJcblxyXG5cdGFwcGx5TWF0cml4NCggbWF0cml4ICkge1xyXG5cclxuXHRcdGNvbnN0IHBvc2l0aW9uID0gdGhpcy5hdHRyaWJ1dGVzLnBvc2l0aW9uO1xyXG5cclxuXHRcdGlmICggcG9zaXRpb24gIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdHBvc2l0aW9uLmFwcGx5TWF0cml4NCggbWF0cml4ICk7XHJcblxyXG5cdFx0XHRwb3NpdGlvbi5uZWVkc1VwZGF0ZSA9IHRydWU7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGNvbnN0IG5vcm1hbCA9IHRoaXMuYXR0cmlidXRlcy5ub3JtYWw7XHJcblxyXG5cdFx0aWYgKCBub3JtYWwgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdGNvbnN0IG5vcm1hbE1hdHJpeCA9IG5ldyBNYXRyaXgzKCkuZ2V0Tm9ybWFsTWF0cml4KCBtYXRyaXggKTtcclxuXHJcblx0XHRcdG5vcm1hbC5hcHBseU5vcm1hbE1hdHJpeCggbm9ybWFsTWF0cml4ICk7XHJcblxyXG5cdFx0XHRub3JtYWwubmVlZHNVcGRhdGUgPSB0cnVlO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCB0YW5nZW50ID0gdGhpcy5hdHRyaWJ1dGVzLnRhbmdlbnQ7XHJcblxyXG5cdFx0aWYgKCB0YW5nZW50ICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHR0YW5nZW50LnRyYW5zZm9ybURpcmVjdGlvbiggbWF0cml4ICk7XHJcblxyXG5cdFx0XHR0YW5nZW50Lm5lZWRzVXBkYXRlID0gdHJ1ZTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCB0aGlzLmJvdW5kaW5nQm94ICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0dGhpcy5jb21wdXRlQm91bmRpbmdCb3goKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCB0aGlzLmJvdW5kaW5nU3BoZXJlICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0dGhpcy5jb21wdXRlQm91bmRpbmdTcGhlcmUoKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0YXBwbHlRdWF0ZXJuaW9uKCBxICkge1xyXG5cclxuXHRcdF9tMS5tYWtlUm90YXRpb25Gcm9tUXVhdGVybmlvbiggcSApO1xyXG5cclxuXHRcdHRoaXMuYXBwbHlNYXRyaXg0KCBfbTEgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRyb3RhdGVYKCBhbmdsZSApIHtcclxuXHJcblx0XHQvLyByb3RhdGUgZ2VvbWV0cnkgYXJvdW5kIHdvcmxkIHgtYXhpc1xyXG5cclxuXHRcdF9tMS5tYWtlUm90YXRpb25YKCBhbmdsZSApO1xyXG5cclxuXHRcdHRoaXMuYXBwbHlNYXRyaXg0KCBfbTEgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRyb3RhdGVZKCBhbmdsZSApIHtcclxuXHJcblx0XHQvLyByb3RhdGUgZ2VvbWV0cnkgYXJvdW5kIHdvcmxkIHktYXhpc1xyXG5cclxuXHRcdF9tMS5tYWtlUm90YXRpb25ZKCBhbmdsZSApO1xyXG5cclxuXHRcdHRoaXMuYXBwbHlNYXRyaXg0KCBfbTEgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRyb3RhdGVaKCBhbmdsZSApIHtcclxuXHJcblx0XHQvLyByb3RhdGUgZ2VvbWV0cnkgYXJvdW5kIHdvcmxkIHotYXhpc1xyXG5cclxuXHRcdF9tMS5tYWtlUm90YXRpb25aKCBhbmdsZSApO1xyXG5cclxuXHRcdHRoaXMuYXBwbHlNYXRyaXg0KCBfbTEgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHR0cmFuc2xhdGUoIHgsIHksIHogKSB7XHJcblxyXG5cdFx0Ly8gdHJhbnNsYXRlIGdlb21ldHJ5XHJcblxyXG5cdFx0X20xLm1ha2VUcmFuc2xhdGlvbiggeCwgeSwgeiApO1xyXG5cclxuXHRcdHRoaXMuYXBwbHlNYXRyaXg0KCBfbTEgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzY2FsZSggeCwgeSwgeiApIHtcclxuXHJcblx0XHQvLyBzY2FsZSBnZW9tZXRyeVxyXG5cclxuXHRcdF9tMS5tYWtlU2NhbGUoIHgsIHksIHogKTtcclxuXHJcblx0XHR0aGlzLmFwcGx5TWF0cml4NCggX20xICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0bG9va0F0KCB2ZWN0b3IgKSB7XHJcblxyXG5cdFx0X29iai5sb29rQXQoIHZlY3RvciApO1xyXG5cclxuXHRcdF9vYmoudXBkYXRlTWF0cml4KCk7XHJcblxyXG5cdFx0dGhpcy5hcHBseU1hdHJpeDQoIF9vYmoubWF0cml4ICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Y2VudGVyKCkge1xyXG5cclxuXHRcdHRoaXMuY29tcHV0ZUJvdW5kaW5nQm94KCk7XHJcblxyXG5cdFx0dGhpcy5ib3VuZGluZ0JveC5nZXRDZW50ZXIoIF9vZmZzZXQgKS5uZWdhdGUoKTtcclxuXHJcblx0XHR0aGlzLnRyYW5zbGF0ZSggX29mZnNldC54LCBfb2Zmc2V0LnksIF9vZmZzZXQueiApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldEZyb21Qb2ludHMoIHBvaW50cyApIHtcclxuXHJcblx0XHRjb25zdCBwb3NpdGlvbiA9IFtdO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IHBvaW50cy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0Y29uc3QgcG9pbnQgPSBwb2ludHNbIGkgXTtcclxuXHRcdFx0cG9zaXRpb24ucHVzaCggcG9pbnQueCwgcG9pbnQueSwgcG9pbnQueiB8fCAwICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMuc2V0QXR0cmlidXRlKCAncG9zaXRpb24nLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggcG9zaXRpb24sIDMgKSApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGNvbXB1dGVCb3VuZGluZ0JveCgpIHtcclxuXHJcblx0XHRpZiAoIHRoaXMuYm91bmRpbmdCb3ggPT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHR0aGlzLmJvdW5kaW5nQm94ID0gbmV3IEJveDMoKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Y29uc3QgcG9zaXRpb24gPSB0aGlzLmF0dHJpYnV0ZXMucG9zaXRpb247XHJcblx0XHRjb25zdCBtb3JwaEF0dHJpYnV0ZXNQb3NpdGlvbiA9IHRoaXMubW9ycGhBdHRyaWJ1dGVzLnBvc2l0aW9uO1xyXG5cclxuXHRcdGlmICggcG9zaXRpb24gJiYgcG9zaXRpb24uaXNHTEJ1ZmZlckF0dHJpYnV0ZSApIHtcclxuXHJcblx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5CdWZmZXJHZW9tZXRyeS5jb21wdXRlQm91bmRpbmdCb3goKTogR0xCdWZmZXJBdHRyaWJ1dGUgcmVxdWlyZXMgYSBtYW51YWwgYm91bmRpbmcgYm94LiBBbHRlcm5hdGl2ZWx5IHNldCBcIm1lc2guZnJ1c3R1bUN1bGxlZFwiIHRvIFwiZmFsc2VcIi4nLCB0aGlzICk7XHJcblxyXG5cdFx0XHR0aGlzLmJvdW5kaW5nQm94LnNldChcclxuXHRcdFx0XHRuZXcgVmVjdG9yMyggLSBJbmZpbml0eSwgLSBJbmZpbml0eSwgLSBJbmZpbml0eSApLFxyXG5cdFx0XHRcdG5ldyBWZWN0b3IzKCArIEluZmluaXR5LCArIEluZmluaXR5LCArIEluZmluaXR5IClcclxuXHRcdFx0KTtcclxuXHJcblx0XHRcdHJldHVybjtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBwb3NpdGlvbiAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0dGhpcy5ib3VuZGluZ0JveC5zZXRGcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbiApO1xyXG5cclxuXHRcdFx0Ly8gcHJvY2VzcyBtb3JwaCBhdHRyaWJ1dGVzIGlmIHByZXNlbnRcclxuXHJcblx0XHRcdGlmICggbW9ycGhBdHRyaWJ1dGVzUG9zaXRpb24gKSB7XHJcblxyXG5cdFx0XHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSBtb3JwaEF0dHJpYnV0ZXNQb3NpdGlvbi5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0XHRjb25zdCBtb3JwaEF0dHJpYnV0ZSA9IG1vcnBoQXR0cmlidXRlc1Bvc2l0aW9uWyBpIF07XHJcblx0XHRcdFx0XHRfYm94LnNldEZyb21CdWZmZXJBdHRyaWJ1dGUoIG1vcnBoQXR0cmlidXRlICk7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCB0aGlzLm1vcnBoVGFyZ2V0c1JlbGF0aXZlICkge1xyXG5cclxuXHRcdFx0XHRcdFx0X3ZlY3Rvci5hZGRWZWN0b3JzKCB0aGlzLmJvdW5kaW5nQm94Lm1pbiwgX2JveC5taW4gKTtcclxuXHRcdFx0XHRcdFx0dGhpcy5ib3VuZGluZ0JveC5leHBhbmRCeVBvaW50KCBfdmVjdG9yICk7XHJcblxyXG5cdFx0XHRcdFx0XHRfdmVjdG9yLmFkZFZlY3RvcnMoIHRoaXMuYm91bmRpbmdCb3gubWF4LCBfYm94Lm1heCApO1xyXG5cdFx0XHRcdFx0XHR0aGlzLmJvdW5kaW5nQm94LmV4cGFuZEJ5UG9pbnQoIF92ZWN0b3IgKTtcclxuXHJcblx0XHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdFx0dGhpcy5ib3VuZGluZ0JveC5leHBhbmRCeVBvaW50KCBfYm94Lm1pbiApO1xyXG5cdFx0XHRcdFx0XHR0aGlzLmJvdW5kaW5nQm94LmV4cGFuZEJ5UG9pbnQoIF9ib3gubWF4ICk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdHRoaXMuYm91bmRpbmdCb3gubWFrZUVtcHR5KCk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggaXNOYU4oIHRoaXMuYm91bmRpbmdCb3gubWluLnggKSB8fCBpc05hTiggdGhpcy5ib3VuZGluZ0JveC5taW4ueSApIHx8IGlzTmFOKCB0aGlzLmJvdW5kaW5nQm94Lm1pbi56ICkgKSB7XHJcblxyXG5cdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuQnVmZmVyR2VvbWV0cnkuY29tcHV0ZUJvdW5kaW5nQm94KCk6IENvbXB1dGVkIG1pbi9tYXggaGF2ZSBOYU4gdmFsdWVzLiBUaGUgXCJwb3NpdGlvblwiIGF0dHJpYnV0ZSBpcyBsaWtlbHkgdG8gaGF2ZSBOYU4gdmFsdWVzLicsIHRoaXMgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0Y29tcHV0ZUJvdW5kaW5nU3BoZXJlKCkge1xyXG5cclxuXHRcdGlmICggdGhpcy5ib3VuZGluZ1NwaGVyZSA9PT0gbnVsbCApIHtcclxuXHJcblx0XHRcdHRoaXMuYm91bmRpbmdTcGhlcmUgPSBuZXcgU3BoZXJlKCk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGNvbnN0IHBvc2l0aW9uID0gdGhpcy5hdHRyaWJ1dGVzLnBvc2l0aW9uO1xyXG5cdFx0Y29uc3QgbW9ycGhBdHRyaWJ1dGVzUG9zaXRpb24gPSB0aGlzLm1vcnBoQXR0cmlidXRlcy5wb3NpdGlvbjtcclxuXHJcblx0XHRpZiAoIHBvc2l0aW9uICYmIHBvc2l0aW9uLmlzR0xCdWZmZXJBdHRyaWJ1dGUgKSB7XHJcblxyXG5cdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuQnVmZmVyR2VvbWV0cnkuY29tcHV0ZUJvdW5kaW5nU3BoZXJlKCk6IEdMQnVmZmVyQXR0cmlidXRlIHJlcXVpcmVzIGEgbWFudWFsIGJvdW5kaW5nIHNwaGVyZS4gQWx0ZXJuYXRpdmVseSBzZXQgXCJtZXNoLmZydXN0dW1DdWxsZWRcIiB0byBcImZhbHNlXCIuJywgdGhpcyApO1xyXG5cclxuXHRcdFx0dGhpcy5ib3VuZGluZ1NwaGVyZS5zZXQoIG5ldyBWZWN0b3IzKCksIEluZmluaXR5ICk7XHJcblxyXG5cdFx0XHRyZXR1cm47XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggcG9zaXRpb24gKSB7XHJcblxyXG5cdFx0XHQvLyBmaXJzdCwgZmluZCB0aGUgY2VudGVyIG9mIHRoZSBib3VuZGluZyBzcGhlcmVcclxuXHJcblx0XHRcdGNvbnN0IGNlbnRlciA9IHRoaXMuYm91bmRpbmdTcGhlcmUuY2VudGVyO1xyXG5cclxuXHRcdFx0X2JveC5zZXRGcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbiApO1xyXG5cclxuXHRcdFx0Ly8gcHJvY2VzcyBtb3JwaCBhdHRyaWJ1dGVzIGlmIHByZXNlbnRcclxuXHJcblx0XHRcdGlmICggbW9ycGhBdHRyaWJ1dGVzUG9zaXRpb24gKSB7XHJcblxyXG5cdFx0XHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSBtb3JwaEF0dHJpYnV0ZXNQb3NpdGlvbi5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0XHRjb25zdCBtb3JwaEF0dHJpYnV0ZSA9IG1vcnBoQXR0cmlidXRlc1Bvc2l0aW9uWyBpIF07XHJcblx0XHRcdFx0XHRfYm94TW9ycGhUYXJnZXRzLnNldEZyb21CdWZmZXJBdHRyaWJ1dGUoIG1vcnBoQXR0cmlidXRlICk7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCB0aGlzLm1vcnBoVGFyZ2V0c1JlbGF0aXZlICkge1xyXG5cclxuXHRcdFx0XHRcdFx0X3ZlY3Rvci5hZGRWZWN0b3JzKCBfYm94Lm1pbiwgX2JveE1vcnBoVGFyZ2V0cy5taW4gKTtcclxuXHRcdFx0XHRcdFx0X2JveC5leHBhbmRCeVBvaW50KCBfdmVjdG9yICk7XHJcblxyXG5cdFx0XHRcdFx0XHRfdmVjdG9yLmFkZFZlY3RvcnMoIF9ib3gubWF4LCBfYm94TW9ycGhUYXJnZXRzLm1heCApO1xyXG5cdFx0XHRcdFx0XHRfYm94LmV4cGFuZEJ5UG9pbnQoIF92ZWN0b3IgKTtcclxuXHJcblx0XHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdFx0X2JveC5leHBhbmRCeVBvaW50KCBfYm94TW9ycGhUYXJnZXRzLm1pbiApO1xyXG5cdFx0XHRcdFx0XHRfYm94LmV4cGFuZEJ5UG9pbnQoIF9ib3hNb3JwaFRhcmdldHMubWF4ICk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRfYm94LmdldENlbnRlciggY2VudGVyICk7XHJcblxyXG5cdFx0XHQvLyBzZWNvbmQsIHRyeSB0byBmaW5kIGEgYm91bmRpbmdTcGhlcmUgd2l0aCBhIHJhZGl1cyBzbWFsbGVyIHRoYW4gdGhlXHJcblx0XHRcdC8vIGJvdW5kaW5nU3BoZXJlIG9mIHRoZSBib3VuZGluZ0JveDogc3FydCgzKSBzbWFsbGVyIGluIHRoZSBiZXN0IGNhc2VcclxuXHJcblx0XHRcdGxldCBtYXhSYWRpdXNTcSA9IDA7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gcG9zaXRpb24uY291bnQ7IGkgPCBpbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0X3ZlY3Rvci5mcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbiwgaSApO1xyXG5cclxuXHRcdFx0XHRtYXhSYWRpdXNTcSA9IE1hdGgubWF4KCBtYXhSYWRpdXNTcSwgY2VudGVyLmRpc3RhbmNlVG9TcXVhcmVkKCBfdmVjdG9yICkgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdC8vIHByb2Nlc3MgbW9ycGggYXR0cmlidXRlcyBpZiBwcmVzZW50XHJcblxyXG5cdFx0XHRpZiAoIG1vcnBoQXR0cmlidXRlc1Bvc2l0aW9uICkge1xyXG5cclxuXHRcdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gbW9ycGhBdHRyaWJ1dGVzUG9zaXRpb24ubGVuZ3RoOyBpIDwgaWw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgbW9ycGhBdHRyaWJ1dGUgPSBtb3JwaEF0dHJpYnV0ZXNQb3NpdGlvblsgaSBdO1xyXG5cdFx0XHRcdFx0Y29uc3QgbW9ycGhUYXJnZXRzUmVsYXRpdmUgPSB0aGlzLm1vcnBoVGFyZ2V0c1JlbGF0aXZlO1xyXG5cclxuXHRcdFx0XHRcdGZvciAoIGxldCBqID0gMCwgamwgPSBtb3JwaEF0dHJpYnV0ZS5jb3VudDsgaiA8IGpsOyBqICsrICkge1xyXG5cclxuXHRcdFx0XHRcdFx0X3ZlY3Rvci5mcm9tQnVmZmVyQXR0cmlidXRlKCBtb3JwaEF0dHJpYnV0ZSwgaiApO1xyXG5cclxuXHRcdFx0XHRcdFx0aWYgKCBtb3JwaFRhcmdldHNSZWxhdGl2ZSApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0X29mZnNldC5mcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbiwgaiApO1xyXG5cdFx0XHRcdFx0XHRcdF92ZWN0b3IuYWRkKCBfb2Zmc2V0ICk7XHJcblxyXG5cdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0XHRtYXhSYWRpdXNTcSA9IE1hdGgubWF4KCBtYXhSYWRpdXNTcSwgY2VudGVyLmRpc3RhbmNlVG9TcXVhcmVkKCBfdmVjdG9yICkgKTtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHRoaXMuYm91bmRpbmdTcGhlcmUucmFkaXVzID0gTWF0aC5zcXJ0KCBtYXhSYWRpdXNTcSApO1xyXG5cclxuXHRcdFx0aWYgKCBpc05hTiggdGhpcy5ib3VuZGluZ1NwaGVyZS5yYWRpdXMgKSApIHtcclxuXHJcblx0XHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLkJ1ZmZlckdlb21ldHJ5LmNvbXB1dGVCb3VuZGluZ1NwaGVyZSgpOiBDb21wdXRlZCByYWRpdXMgaXMgTmFOLiBUaGUgXCJwb3NpdGlvblwiIGF0dHJpYnV0ZSBpcyBsaWtlbHkgdG8gaGF2ZSBOYU4gdmFsdWVzLicsIHRoaXMgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0Y29tcHV0ZVRhbmdlbnRzKCkge1xyXG5cclxuXHRcdGNvbnN0IGluZGV4ID0gdGhpcy5pbmRleDtcclxuXHRcdGNvbnN0IGF0dHJpYnV0ZXMgPSB0aGlzLmF0dHJpYnV0ZXM7XHJcblxyXG5cdFx0Ly8gYmFzZWQgb24gaHR0cDovL3d3dy50ZXJhdGhvbi5jb20vY29kZS90YW5nZW50Lmh0bWxcclxuXHRcdC8vIChwZXIgdmVydGV4IHRhbmdlbnRzKVxyXG5cclxuXHRcdGlmICggaW5kZXggPT09IG51bGwgfHxcclxuXHRcdFx0IGF0dHJpYnV0ZXMucG9zaXRpb24gPT09IHVuZGVmaW5lZCB8fFxyXG5cdFx0XHQgYXR0cmlidXRlcy5ub3JtYWwgPT09IHVuZGVmaW5lZCB8fFxyXG5cdFx0XHQgYXR0cmlidXRlcy51diA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLkJ1ZmZlckdlb21ldHJ5OiAuY29tcHV0ZVRhbmdlbnRzKCkgZmFpbGVkLiBNaXNzaW5nIHJlcXVpcmVkIGF0dHJpYnV0ZXMgKGluZGV4LCBwb3NpdGlvbiwgbm9ybWFsIG9yIHV2KScgKTtcclxuXHRcdFx0cmV0dXJuO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCBpbmRpY2VzID0gaW5kZXguYXJyYXk7XHJcblx0XHRjb25zdCBwb3NpdGlvbnMgPSBhdHRyaWJ1dGVzLnBvc2l0aW9uLmFycmF5O1xyXG5cdFx0Y29uc3Qgbm9ybWFscyA9IGF0dHJpYnV0ZXMubm9ybWFsLmFycmF5O1xyXG5cdFx0Y29uc3QgdXZzID0gYXR0cmlidXRlcy51di5hcnJheTtcclxuXHJcblx0XHRjb25zdCBuVmVydGljZXMgPSBwb3NpdGlvbnMubGVuZ3RoIC8gMztcclxuXHJcblx0XHRpZiAoIHRoaXMuaGFzQXR0cmlidXRlKCAndGFuZ2VudCcgKSA9PT0gZmFsc2UgKSB7XHJcblxyXG5cdFx0XHR0aGlzLnNldEF0dHJpYnV0ZSggJ3RhbmdlbnQnLCBuZXcgQnVmZmVyQXR0cmlidXRlKCBuZXcgRmxvYXQzMkFycmF5KCA0ICogblZlcnRpY2VzICksIDQgKSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCB0YW5nZW50cyA9IHRoaXMuZ2V0QXR0cmlidXRlKCAndGFuZ2VudCcgKS5hcnJheTtcclxuXHJcblx0XHRjb25zdCB0YW4xID0gW10sIHRhbjIgPSBbXTtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBuVmVydGljZXM7IGkgKysgKSB7XHJcblxyXG5cdFx0XHR0YW4xWyBpIF0gPSBuZXcgVmVjdG9yMygpO1xyXG5cdFx0XHR0YW4yWyBpIF0gPSBuZXcgVmVjdG9yMygpO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCB2QSA9IG5ldyBWZWN0b3IzKCksXHJcblx0XHRcdHZCID0gbmV3IFZlY3RvcjMoKSxcclxuXHRcdFx0dkMgPSBuZXcgVmVjdG9yMygpLFxyXG5cclxuXHRcdFx0dXZBID0gbmV3IFZlY3RvcjIoKSxcclxuXHRcdFx0dXZCID0gbmV3IFZlY3RvcjIoKSxcclxuXHRcdFx0dXZDID0gbmV3IFZlY3RvcjIoKSxcclxuXHJcblx0XHRcdHNkaXIgPSBuZXcgVmVjdG9yMygpLFxyXG5cdFx0XHR0ZGlyID0gbmV3IFZlY3RvcjMoKTtcclxuXHJcblx0XHRmdW5jdGlvbiBoYW5kbGVUcmlhbmdsZSggYSwgYiwgYyApIHtcclxuXHJcblx0XHRcdHZBLmZyb21BcnJheSggcG9zaXRpb25zLCBhICogMyApO1xyXG5cdFx0XHR2Qi5mcm9tQXJyYXkoIHBvc2l0aW9ucywgYiAqIDMgKTtcclxuXHRcdFx0dkMuZnJvbUFycmF5KCBwb3NpdGlvbnMsIGMgKiAzICk7XHJcblxyXG5cdFx0XHR1dkEuZnJvbUFycmF5KCB1dnMsIGEgKiAyICk7XHJcblx0XHRcdHV2Qi5mcm9tQXJyYXkoIHV2cywgYiAqIDIgKTtcclxuXHRcdFx0dXZDLmZyb21BcnJheSggdXZzLCBjICogMiApO1xyXG5cclxuXHRcdFx0dkIuc3ViKCB2QSApO1xyXG5cdFx0XHR2Qy5zdWIoIHZBICk7XHJcblxyXG5cdFx0XHR1dkIuc3ViKCB1dkEgKTtcclxuXHRcdFx0dXZDLnN1YiggdXZBICk7XHJcblxyXG5cdFx0XHRjb25zdCByID0gMS4wIC8gKCB1dkIueCAqIHV2Qy55IC0gdXZDLnggKiB1dkIueSApO1xyXG5cclxuXHRcdFx0Ly8gc2lsZW50bHkgaWdub3JlIGRlZ2VuZXJhdGUgdXYgdHJpYW5nbGVzIGhhdmluZyBjb2luY2lkZW50IG9yIGNvbGluZWFyIHZlcnRpY2VzXHJcblxyXG5cdFx0XHRpZiAoICEgaXNGaW5pdGUoIHIgKSApIHJldHVybjtcclxuXHJcblx0XHRcdHNkaXIuY29weSggdkIgKS5tdWx0aXBseVNjYWxhciggdXZDLnkgKS5hZGRTY2FsZWRWZWN0b3IoIHZDLCAtIHV2Qi55ICkubXVsdGlwbHlTY2FsYXIoIHIgKTtcclxuXHRcdFx0dGRpci5jb3B5KCB2QyApLm11bHRpcGx5U2NhbGFyKCB1dkIueCApLmFkZFNjYWxlZFZlY3RvciggdkIsIC0gdXZDLnggKS5tdWx0aXBseVNjYWxhciggciApO1xyXG5cclxuXHRcdFx0dGFuMVsgYSBdLmFkZCggc2RpciApO1xyXG5cdFx0XHR0YW4xWyBiIF0uYWRkKCBzZGlyICk7XHJcblx0XHRcdHRhbjFbIGMgXS5hZGQoIHNkaXIgKTtcclxuXHJcblx0XHRcdHRhbjJbIGEgXS5hZGQoIHRkaXIgKTtcclxuXHRcdFx0dGFuMlsgYiBdLmFkZCggdGRpciApO1xyXG5cdFx0XHR0YW4yWyBjIF0uYWRkKCB0ZGlyICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGxldCBncm91cHMgPSB0aGlzLmdyb3VwcztcclxuXHJcblx0XHRpZiAoIGdyb3Vwcy5sZW5ndGggPT09IDAgKSB7XHJcblxyXG5cdFx0XHRncm91cHMgPSBbIHtcclxuXHRcdFx0XHRzdGFydDogMCxcclxuXHRcdFx0XHRjb3VudDogaW5kaWNlcy5sZW5ndGhcclxuXHRcdFx0fSBdO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gZ3JvdXBzLmxlbmd0aDsgaSA8IGlsOyArKyBpICkge1xyXG5cclxuXHRcdFx0Y29uc3QgZ3JvdXAgPSBncm91cHNbIGkgXTtcclxuXHJcblx0XHRcdGNvbnN0IHN0YXJ0ID0gZ3JvdXAuc3RhcnQ7XHJcblx0XHRcdGNvbnN0IGNvdW50ID0gZ3JvdXAuY291bnQ7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaiA9IHN0YXJ0LCBqbCA9IHN0YXJ0ICsgY291bnQ7IGogPCBqbDsgaiArPSAzICkge1xyXG5cclxuXHRcdFx0XHRoYW5kbGVUcmlhbmdsZShcclxuXHRcdFx0XHRcdGluZGljZXNbIGogKyAwIF0sXHJcblx0XHRcdFx0XHRpbmRpY2VzWyBqICsgMSBdLFxyXG5cdFx0XHRcdFx0aW5kaWNlc1sgaiArIDIgXVxyXG5cdFx0XHRcdCk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGNvbnN0IHRtcCA9IG5ldyBWZWN0b3IzKCksIHRtcDIgPSBuZXcgVmVjdG9yMygpO1xyXG5cdFx0Y29uc3QgbiA9IG5ldyBWZWN0b3IzKCksIG4yID0gbmV3IFZlY3RvcjMoKTtcclxuXHJcblx0XHRmdW5jdGlvbiBoYW5kbGVWZXJ0ZXgoIHYgKSB7XHJcblxyXG5cdFx0XHRuLmZyb21BcnJheSggbm9ybWFscywgdiAqIDMgKTtcclxuXHRcdFx0bjIuY29weSggbiApO1xyXG5cclxuXHRcdFx0Y29uc3QgdCA9IHRhbjFbIHYgXTtcclxuXHJcblx0XHRcdC8vIEdyYW0tU2NobWlkdCBvcnRob2dvbmFsaXplXHJcblxyXG5cdFx0XHR0bXAuY29weSggdCApO1xyXG5cdFx0XHR0bXAuc3ViKCBuLm11bHRpcGx5U2NhbGFyKCBuLmRvdCggdCApICkgKS5ub3JtYWxpemUoKTtcclxuXHJcblx0XHRcdC8vIENhbGN1bGF0ZSBoYW5kZWRuZXNzXHJcblxyXG5cdFx0XHR0bXAyLmNyb3NzVmVjdG9ycyggbjIsIHQgKTtcclxuXHRcdFx0Y29uc3QgdGVzdCA9IHRtcDIuZG90KCB0YW4yWyB2IF0gKTtcclxuXHRcdFx0Y29uc3QgdyA9ICggdGVzdCA8IDAuMCApID8gLSAxLjAgOiAxLjA7XHJcblxyXG5cdFx0XHR0YW5nZW50c1sgdiAqIDQgXSA9IHRtcC54O1xyXG5cdFx0XHR0YW5nZW50c1sgdiAqIDQgKyAxIF0gPSB0bXAueTtcclxuXHRcdFx0dGFuZ2VudHNbIHYgKiA0ICsgMiBdID0gdG1wLno7XHJcblx0XHRcdHRhbmdlbnRzWyB2ICogNCArIDMgXSA9IHc7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSBncm91cHMubGVuZ3RoOyBpIDwgaWw7ICsrIGkgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBncm91cCA9IGdyb3Vwc1sgaSBdO1xyXG5cclxuXHRcdFx0Y29uc3Qgc3RhcnQgPSBncm91cC5zdGFydDtcclxuXHRcdFx0Y29uc3QgY291bnQgPSBncm91cC5jb3VudDtcclxuXHJcblx0XHRcdGZvciAoIGxldCBqID0gc3RhcnQsIGpsID0gc3RhcnQgKyBjb3VudDsgaiA8IGpsOyBqICs9IDMgKSB7XHJcblxyXG5cdFx0XHRcdGhhbmRsZVZlcnRleCggaW5kaWNlc1sgaiArIDAgXSApO1xyXG5cdFx0XHRcdGhhbmRsZVZlcnRleCggaW5kaWNlc1sgaiArIDEgXSApO1xyXG5cdFx0XHRcdGhhbmRsZVZlcnRleCggaW5kaWNlc1sgaiArIDIgXSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRjb21wdXRlVmVydGV4Tm9ybWFscygpIHtcclxuXHJcblx0XHRjb25zdCBpbmRleCA9IHRoaXMuaW5kZXg7XHJcblx0XHRjb25zdCBwb3NpdGlvbkF0dHJpYnV0ZSA9IHRoaXMuZ2V0QXR0cmlidXRlKCAncG9zaXRpb24nICk7XHJcblxyXG5cdFx0aWYgKCBwb3NpdGlvbkF0dHJpYnV0ZSAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0bGV0IG5vcm1hbEF0dHJpYnV0ZSA9IHRoaXMuZ2V0QXR0cmlidXRlKCAnbm9ybWFsJyApO1xyXG5cclxuXHRcdFx0aWYgKCBub3JtYWxBdHRyaWJ1dGUgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0bm9ybWFsQXR0cmlidXRlID0gbmV3IEJ1ZmZlckF0dHJpYnV0ZSggbmV3IEZsb2F0MzJBcnJheSggcG9zaXRpb25BdHRyaWJ1dGUuY291bnQgKiAzICksIDMgKTtcclxuXHRcdFx0XHR0aGlzLnNldEF0dHJpYnV0ZSggJ25vcm1hbCcsIG5vcm1hbEF0dHJpYnV0ZSApO1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0Ly8gcmVzZXQgZXhpc3Rpbmcgbm9ybWFscyB0byB6ZXJvXHJcblxyXG5cdFx0XHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSBub3JtYWxBdHRyaWJ1dGUuY291bnQ7IGkgPCBpbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0XHRub3JtYWxBdHRyaWJ1dGUuc2V0WFlaKCBpLCAwLCAwLCAwICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGNvbnN0IHBBID0gbmV3IFZlY3RvcjMoKSwgcEIgPSBuZXcgVmVjdG9yMygpLCBwQyA9IG5ldyBWZWN0b3IzKCk7XHJcblx0XHRcdGNvbnN0IG5BID0gbmV3IFZlY3RvcjMoKSwgbkIgPSBuZXcgVmVjdG9yMygpLCBuQyA9IG5ldyBWZWN0b3IzKCk7XHJcblx0XHRcdGNvbnN0IGNiID0gbmV3IFZlY3RvcjMoKSwgYWIgPSBuZXcgVmVjdG9yMygpO1xyXG5cclxuXHRcdFx0Ly8gaW5kZXhlZCBlbGVtZW50c1xyXG5cclxuXHRcdFx0aWYgKCBpbmRleCApIHtcclxuXHJcblx0XHRcdFx0Zm9yICggbGV0IGkgPSAwLCBpbCA9IGluZGV4LmNvdW50OyBpIDwgaWw7IGkgKz0gMyApIHtcclxuXHJcblx0XHRcdFx0XHRjb25zdCB2QSA9IGluZGV4LmdldFgoIGkgKyAwICk7XHJcblx0XHRcdFx0XHRjb25zdCB2QiA9IGluZGV4LmdldFgoIGkgKyAxICk7XHJcblx0XHRcdFx0XHRjb25zdCB2QyA9IGluZGV4LmdldFgoIGkgKyAyICk7XHJcblxyXG5cdFx0XHRcdFx0cEEuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggcG9zaXRpb25BdHRyaWJ1dGUsIHZBICk7XHJcblx0XHRcdFx0XHRwQi5mcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbkF0dHJpYnV0ZSwgdkIgKTtcclxuXHRcdFx0XHRcdHBDLmZyb21CdWZmZXJBdHRyaWJ1dGUoIHBvc2l0aW9uQXR0cmlidXRlLCB2QyApO1xyXG5cclxuXHRcdFx0XHRcdGNiLnN1YlZlY3RvcnMoIHBDLCBwQiApO1xyXG5cdFx0XHRcdFx0YWIuc3ViVmVjdG9ycyggcEEsIHBCICk7XHJcblx0XHRcdFx0XHRjYi5jcm9zcyggYWIgKTtcclxuXHJcblx0XHRcdFx0XHRuQS5mcm9tQnVmZmVyQXR0cmlidXRlKCBub3JtYWxBdHRyaWJ1dGUsIHZBICk7XHJcblx0XHRcdFx0XHRuQi5mcm9tQnVmZmVyQXR0cmlidXRlKCBub3JtYWxBdHRyaWJ1dGUsIHZCICk7XHJcblx0XHRcdFx0XHRuQy5mcm9tQnVmZmVyQXR0cmlidXRlKCBub3JtYWxBdHRyaWJ1dGUsIHZDICk7XHJcblxyXG5cdFx0XHRcdFx0bkEuYWRkKCBjYiApO1xyXG5cdFx0XHRcdFx0bkIuYWRkKCBjYiApO1xyXG5cdFx0XHRcdFx0bkMuYWRkKCBjYiApO1xyXG5cclxuXHRcdFx0XHRcdG5vcm1hbEF0dHJpYnV0ZS5zZXRYWVooIHZBLCBuQS54LCBuQS55LCBuQS56ICk7XHJcblx0XHRcdFx0XHRub3JtYWxBdHRyaWJ1dGUuc2V0WFlaKCB2QiwgbkIueCwgbkIueSwgbkIueiApO1xyXG5cdFx0XHRcdFx0bm9ybWFsQXR0cmlidXRlLnNldFhZWiggdkMsIG5DLngsIG5DLnksIG5DLnogKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0Ly8gbm9uLWluZGV4ZWQgZWxlbWVudHMgKHVuY29ubmVjdGVkIHRyaWFuZ2xlIHNvdXApXHJcblxyXG5cdFx0XHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSBwb3NpdGlvbkF0dHJpYnV0ZS5jb3VudDsgaSA8IGlsOyBpICs9IDMgKSB7XHJcblxyXG5cdFx0XHRcdFx0cEEuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggcG9zaXRpb25BdHRyaWJ1dGUsIGkgKyAwICk7XHJcblx0XHRcdFx0XHRwQi5mcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbkF0dHJpYnV0ZSwgaSArIDEgKTtcclxuXHRcdFx0XHRcdHBDLmZyb21CdWZmZXJBdHRyaWJ1dGUoIHBvc2l0aW9uQXR0cmlidXRlLCBpICsgMiApO1xyXG5cclxuXHRcdFx0XHRcdGNiLnN1YlZlY3RvcnMoIHBDLCBwQiApO1xyXG5cdFx0XHRcdFx0YWIuc3ViVmVjdG9ycyggcEEsIHBCICk7XHJcblx0XHRcdFx0XHRjYi5jcm9zcyggYWIgKTtcclxuXHJcblx0XHRcdFx0XHRub3JtYWxBdHRyaWJ1dGUuc2V0WFlaKCBpICsgMCwgY2IueCwgY2IueSwgY2IueiApO1xyXG5cdFx0XHRcdFx0bm9ybWFsQXR0cmlidXRlLnNldFhZWiggaSArIDEsIGNiLngsIGNiLnksIGNiLnogKTtcclxuXHRcdFx0XHRcdG5vcm1hbEF0dHJpYnV0ZS5zZXRYWVooIGkgKyAyLCBjYi54LCBjYi55LCBjYi56ICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHRoaXMubm9ybWFsaXplTm9ybWFscygpO1xyXG5cclxuXHRcdFx0bm9ybWFsQXR0cmlidXRlLm5lZWRzVXBkYXRlID0gdHJ1ZTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0bm9ybWFsaXplTm9ybWFscygpIHtcclxuXHJcblx0XHRjb25zdCBub3JtYWxzID0gdGhpcy5hdHRyaWJ1dGVzLm5vcm1hbDtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gbm9ybWFscy5jb3VudDsgaSA8IGlsOyBpICsrICkge1xyXG5cclxuXHRcdFx0X3ZlY3Rvci5mcm9tQnVmZmVyQXR0cmlidXRlKCBub3JtYWxzLCBpICk7XHJcblxyXG5cdFx0XHRfdmVjdG9yLm5vcm1hbGl6ZSgpO1xyXG5cclxuXHRcdFx0bm9ybWFscy5zZXRYWVooIGksIF92ZWN0b3IueCwgX3ZlY3Rvci55LCBfdmVjdG9yLnogKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0dG9Ob25JbmRleGVkKCkge1xyXG5cclxuXHRcdGZ1bmN0aW9uIGNvbnZlcnRCdWZmZXJBdHRyaWJ1dGUoIGF0dHJpYnV0ZSwgaW5kaWNlcyApIHtcclxuXHJcblx0XHRcdGNvbnN0IGFycmF5ID0gYXR0cmlidXRlLmFycmF5O1xyXG5cdFx0XHRjb25zdCBpdGVtU2l6ZSA9IGF0dHJpYnV0ZS5pdGVtU2l6ZTtcclxuXHRcdFx0Y29uc3Qgbm9ybWFsaXplZCA9IGF0dHJpYnV0ZS5ub3JtYWxpemVkO1xyXG5cclxuXHRcdFx0Y29uc3QgYXJyYXkyID0gbmV3IGFycmF5LmNvbnN0cnVjdG9yKCBpbmRpY2VzLmxlbmd0aCAqIGl0ZW1TaXplICk7XHJcblxyXG5cdFx0XHRsZXQgaW5kZXggPSAwLCBpbmRleDIgPSAwO1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gaW5kaWNlcy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRpZiAoIGF0dHJpYnV0ZS5pc0ludGVybGVhdmVkQnVmZmVyQXR0cmlidXRlICkge1xyXG5cclxuXHRcdFx0XHRcdGluZGV4ID0gaW5kaWNlc1sgaSBdICogYXR0cmlidXRlLmRhdGEuc3RyaWRlICsgYXR0cmlidXRlLm9mZnNldDtcclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRpbmRleCA9IGluZGljZXNbIGkgXSAqIGl0ZW1TaXplO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdGZvciAoIGxldCBqID0gMDsgaiA8IGl0ZW1TaXplOyBqICsrICkge1xyXG5cclxuXHRcdFx0XHRcdGFycmF5MlsgaW5kZXgyICsrIF0gPSBhcnJheVsgaW5kZXggKysgXTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0cmV0dXJuIG5ldyBCdWZmZXJBdHRyaWJ1dGUoIGFycmF5MiwgaXRlbVNpemUsIG5vcm1hbGl6ZWQgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly9cclxuXHJcblx0XHRpZiAoIHRoaXMuaW5kZXggPT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5CdWZmZXJHZW9tZXRyeS50b05vbkluZGV4ZWQoKTogQnVmZmVyR2VvbWV0cnkgaXMgYWxyZWFkeSBub24taW5kZXhlZC4nICk7XHJcblx0XHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCBnZW9tZXRyeTIgPSBuZXcgQnVmZmVyR2VvbWV0cnkoKTtcclxuXHJcblx0XHRjb25zdCBpbmRpY2VzID0gdGhpcy5pbmRleC5hcnJheTtcclxuXHRcdGNvbnN0IGF0dHJpYnV0ZXMgPSB0aGlzLmF0dHJpYnV0ZXM7XHJcblxyXG5cdFx0Ly8gYXR0cmlidXRlc1xyXG5cclxuXHRcdGZvciAoIGNvbnN0IG5hbWUgaW4gYXR0cmlidXRlcyApIHtcclxuXHJcblx0XHRcdGNvbnN0IGF0dHJpYnV0ZSA9IGF0dHJpYnV0ZXNbIG5hbWUgXTtcclxuXHJcblx0XHRcdGNvbnN0IG5ld0F0dHJpYnV0ZSA9IGNvbnZlcnRCdWZmZXJBdHRyaWJ1dGUoIGF0dHJpYnV0ZSwgaW5kaWNlcyApO1xyXG5cclxuXHRcdFx0Z2VvbWV0cnkyLnNldEF0dHJpYnV0ZSggbmFtZSwgbmV3QXR0cmlidXRlICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIG1vcnBoIGF0dHJpYnV0ZXNcclxuXHJcblx0XHRjb25zdCBtb3JwaEF0dHJpYnV0ZXMgPSB0aGlzLm1vcnBoQXR0cmlidXRlcztcclxuXHJcblx0XHRmb3IgKCBjb25zdCBuYW1lIGluIG1vcnBoQXR0cmlidXRlcyApIHtcclxuXHJcblx0XHRcdGNvbnN0IG1vcnBoQXJyYXkgPSBbXTtcclxuXHRcdFx0Y29uc3QgbW9ycGhBdHRyaWJ1dGUgPSBtb3JwaEF0dHJpYnV0ZXNbIG5hbWUgXTsgLy8gbW9ycGhBdHRyaWJ1dGU6IGFycmF5IG9mIEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGVzXHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gbW9ycGhBdHRyaWJ1dGUubGVuZ3RoOyBpIDwgaWw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IGF0dHJpYnV0ZSA9IG1vcnBoQXR0cmlidXRlWyBpIF07XHJcblxyXG5cdFx0XHRcdGNvbnN0IG5ld0F0dHJpYnV0ZSA9IGNvbnZlcnRCdWZmZXJBdHRyaWJ1dGUoIGF0dHJpYnV0ZSwgaW5kaWNlcyApO1xyXG5cclxuXHRcdFx0XHRtb3JwaEFycmF5LnB1c2goIG5ld0F0dHJpYnV0ZSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Z2VvbWV0cnkyLm1vcnBoQXR0cmlidXRlc1sgbmFtZSBdID0gbW9ycGhBcnJheTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Z2VvbWV0cnkyLm1vcnBoVGFyZ2V0c1JlbGF0aXZlID0gdGhpcy5tb3JwaFRhcmdldHNSZWxhdGl2ZTtcclxuXHJcblx0XHQvLyBncm91cHNcclxuXHJcblx0XHRjb25zdCBncm91cHMgPSB0aGlzLmdyb3VwcztcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBncm91cHMubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdGNvbnN0IGdyb3VwID0gZ3JvdXBzWyBpIF07XHJcblx0XHRcdGdlb21ldHJ5Mi5hZGRHcm91cCggZ3JvdXAuc3RhcnQsIGdyb3VwLmNvdW50LCBncm91cC5tYXRlcmlhbEluZGV4ICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiBnZW9tZXRyeTI7XHJcblxyXG5cdH1cclxuXHJcblx0dG9KU09OKCkge1xyXG5cclxuXHRcdGNvbnN0IGRhdGEgPSB7XHJcblx0XHRcdG1ldGFkYXRhOiB7XHJcblx0XHRcdFx0dmVyc2lvbjogNC42LFxyXG5cdFx0XHRcdHR5cGU6ICdCdWZmZXJHZW9tZXRyeScsXHJcblx0XHRcdFx0Z2VuZXJhdG9yOiAnQnVmZmVyR2VvbWV0cnkudG9KU09OJ1xyXG5cdFx0XHR9XHJcblx0XHR9O1xyXG5cclxuXHRcdC8vIHN0YW5kYXJkIEJ1ZmZlckdlb21ldHJ5IHNlcmlhbGl6YXRpb25cclxuXHJcblx0XHRkYXRhLnV1aWQgPSB0aGlzLnV1aWQ7XHJcblx0XHRkYXRhLnR5cGUgPSB0aGlzLnR5cGU7XHJcblx0XHRpZiAoIHRoaXMubmFtZSAhPT0gJycgKSBkYXRhLm5hbWUgPSB0aGlzLm5hbWU7XHJcblx0XHRpZiAoIE9iamVjdC5rZXlzKCB0aGlzLnVzZXJEYXRhICkubGVuZ3RoID4gMCApIGRhdGEudXNlckRhdGEgPSB0aGlzLnVzZXJEYXRhO1xyXG5cclxuXHRcdGlmICggdGhpcy5wYXJhbWV0ZXJzICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBwYXJhbWV0ZXJzID0gdGhpcy5wYXJhbWV0ZXJzO1xyXG5cclxuXHRcdFx0Zm9yICggY29uc3Qga2V5IGluIHBhcmFtZXRlcnMgKSB7XHJcblxyXG5cdFx0XHRcdGlmICggcGFyYW1ldGVyc1sga2V5IF0gIT09IHVuZGVmaW5lZCApIGRhdGFbIGtleSBdID0gcGFyYW1ldGVyc1sga2V5IF07XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRyZXR1cm4gZGF0YTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gZm9yIHNpbXBsaWNpdHkgdGhlIGNvZGUgYXNzdW1lcyBhdHRyaWJ1dGVzIGFyZSBub3Qgc2hhcmVkIGFjcm9zcyBnZW9tZXRyaWVzLCBzZWUgIzE1ODExXHJcblxyXG5cdFx0ZGF0YS5kYXRhID0geyBhdHRyaWJ1dGVzOiB7fSB9O1xyXG5cclxuXHRcdGNvbnN0IGluZGV4ID0gdGhpcy5pbmRleDtcclxuXHJcblx0XHRpZiAoIGluZGV4ICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0ZGF0YS5kYXRhLmluZGV4ID0ge1xyXG5cdFx0XHRcdHR5cGU6IGluZGV4LmFycmF5LmNvbnN0cnVjdG9yLm5hbWUsXHJcblx0XHRcdFx0YXJyYXk6IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKCBpbmRleC5hcnJheSApXHJcblx0XHRcdH07XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGNvbnN0IGF0dHJpYnV0ZXMgPSB0aGlzLmF0dHJpYnV0ZXM7XHJcblxyXG5cdFx0Zm9yICggY29uc3Qga2V5IGluIGF0dHJpYnV0ZXMgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBhdHRyaWJ1dGUgPSBhdHRyaWJ1dGVzWyBrZXkgXTtcclxuXHJcblx0XHRcdGRhdGEuZGF0YS5hdHRyaWJ1dGVzWyBrZXkgXSA9IGF0dHJpYnV0ZS50b0pTT04oIGRhdGEuZGF0YSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCBtb3JwaEF0dHJpYnV0ZXMgPSB7fTtcclxuXHRcdGxldCBoYXNNb3JwaEF0dHJpYnV0ZXMgPSBmYWxzZTtcclxuXHJcblx0XHRmb3IgKCBjb25zdCBrZXkgaW4gdGhpcy5tb3JwaEF0dHJpYnV0ZXMgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBhdHRyaWJ1dGVBcnJheSA9IHRoaXMubW9ycGhBdHRyaWJ1dGVzWyBrZXkgXTtcclxuXHJcblx0XHRcdGNvbnN0IGFycmF5ID0gW107XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gYXR0cmlidXRlQXJyYXkubGVuZ3RoOyBpIDwgaWw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IGF0dHJpYnV0ZSA9IGF0dHJpYnV0ZUFycmF5WyBpIF07XHJcblxyXG5cdFx0XHRcdGFycmF5LnB1c2goIGF0dHJpYnV0ZS50b0pTT04oIGRhdGEuZGF0YSApICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRpZiAoIGFycmF5Lmxlbmd0aCA+IDAgKSB7XHJcblxyXG5cdFx0XHRcdG1vcnBoQXR0cmlidXRlc1sga2V5IF0gPSBhcnJheTtcclxuXHJcblx0XHRcdFx0aGFzTW9ycGhBdHRyaWJ1dGVzID0gdHJ1ZTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBoYXNNb3JwaEF0dHJpYnV0ZXMgKSB7XHJcblxyXG5cdFx0XHRkYXRhLmRhdGEubW9ycGhBdHRyaWJ1dGVzID0gbW9ycGhBdHRyaWJ1dGVzO1xyXG5cdFx0XHRkYXRhLmRhdGEubW9ycGhUYXJnZXRzUmVsYXRpdmUgPSB0aGlzLm1vcnBoVGFyZ2V0c1JlbGF0aXZlO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCBncm91cHMgPSB0aGlzLmdyb3VwcztcclxuXHJcblx0XHRpZiAoIGdyb3Vwcy5sZW5ndGggPiAwICkge1xyXG5cclxuXHRcdFx0ZGF0YS5kYXRhLmdyb3VwcyA9IEpTT04ucGFyc2UoIEpTT04uc3RyaW5naWZ5KCBncm91cHMgKSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCBib3VuZGluZ1NwaGVyZSA9IHRoaXMuYm91bmRpbmdTcGhlcmU7XHJcblxyXG5cdFx0aWYgKCBib3VuZGluZ1NwaGVyZSAhPT0gbnVsbCApIHtcclxuXHJcblx0XHRcdGRhdGEuZGF0YS5ib3VuZGluZ1NwaGVyZSA9IHtcclxuXHRcdFx0XHRjZW50ZXI6IGJvdW5kaW5nU3BoZXJlLmNlbnRlci50b0FycmF5KCksXHJcblx0XHRcdFx0cmFkaXVzOiBib3VuZGluZ1NwaGVyZS5yYWRpdXNcclxuXHRcdFx0fTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIGRhdGE7XHJcblxyXG5cdH1cclxuXHJcblx0Y2xvbmUoKSB7XHJcblxyXG5cdFx0cmV0dXJuIG5ldyB0aGlzLmNvbnN0cnVjdG9yKCkuY29weSggdGhpcyApO1xyXG5cclxuXHR9XHJcblxyXG5cdGNvcHkoIHNvdXJjZSApIHtcclxuXHJcblx0XHQvLyByZXNldFxyXG5cclxuXHRcdHRoaXMuaW5kZXggPSBudWxsO1xyXG5cdFx0dGhpcy5hdHRyaWJ1dGVzID0ge307XHJcblx0XHR0aGlzLm1vcnBoQXR0cmlidXRlcyA9IHt9O1xyXG5cdFx0dGhpcy5ncm91cHMgPSBbXTtcclxuXHRcdHRoaXMuYm91bmRpbmdCb3ggPSBudWxsO1xyXG5cdFx0dGhpcy5ib3VuZGluZ1NwaGVyZSA9IG51bGw7XHJcblxyXG5cdFx0Ly8gdXNlZCBmb3Igc3RvcmluZyBjbG9uZWQsIHNoYXJlZCBkYXRhXHJcblxyXG5cdFx0Y29uc3QgZGF0YSA9IHt9O1xyXG5cclxuXHRcdC8vIG5hbWVcclxuXHJcblx0XHR0aGlzLm5hbWUgPSBzb3VyY2UubmFtZTtcclxuXHJcblx0XHQvLyBpbmRleFxyXG5cclxuXHRcdGNvbnN0IGluZGV4ID0gc291cmNlLmluZGV4O1xyXG5cclxuXHRcdGlmICggaW5kZXggIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHR0aGlzLnNldEluZGV4KCBpbmRleC5jbG9uZSggZGF0YSApICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIGF0dHJpYnV0ZXNcclxuXHJcblx0XHRjb25zdCBhdHRyaWJ1dGVzID0gc291cmNlLmF0dHJpYnV0ZXM7XHJcblxyXG5cdFx0Zm9yICggY29uc3QgbmFtZSBpbiBhdHRyaWJ1dGVzICkge1xyXG5cclxuXHRcdFx0Y29uc3QgYXR0cmlidXRlID0gYXR0cmlidXRlc1sgbmFtZSBdO1xyXG5cdFx0XHR0aGlzLnNldEF0dHJpYnV0ZSggbmFtZSwgYXR0cmlidXRlLmNsb25lKCBkYXRhICkgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gbW9ycGggYXR0cmlidXRlc1xyXG5cclxuXHRcdGNvbnN0IG1vcnBoQXR0cmlidXRlcyA9IHNvdXJjZS5tb3JwaEF0dHJpYnV0ZXM7XHJcblxyXG5cdFx0Zm9yICggY29uc3QgbmFtZSBpbiBtb3JwaEF0dHJpYnV0ZXMgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBhcnJheSA9IFtdO1xyXG5cdFx0XHRjb25zdCBtb3JwaEF0dHJpYnV0ZSA9IG1vcnBoQXR0cmlidXRlc1sgbmFtZSBdOyAvLyBtb3JwaEF0dHJpYnV0ZTogYXJyYXkgb2YgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZXNcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMCwgbCA9IG1vcnBoQXR0cmlidXRlLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdGFycmF5LnB1c2goIG1vcnBoQXR0cmlidXRlWyBpIF0uY2xvbmUoIGRhdGEgKSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0dGhpcy5tb3JwaEF0dHJpYnV0ZXNbIG5hbWUgXSA9IGFycmF5O1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLm1vcnBoVGFyZ2V0c1JlbGF0aXZlID0gc291cmNlLm1vcnBoVGFyZ2V0c1JlbGF0aXZlO1xyXG5cclxuXHRcdC8vIGdyb3Vwc1xyXG5cclxuXHRcdGNvbnN0IGdyb3VwcyA9IHNvdXJjZS5ncm91cHM7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gZ3JvdXBzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBncm91cCA9IGdyb3Vwc1sgaSBdO1xyXG5cdFx0XHR0aGlzLmFkZEdyb3VwKCBncm91cC5zdGFydCwgZ3JvdXAuY291bnQsIGdyb3VwLm1hdGVyaWFsSW5kZXggKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gYm91bmRpbmcgYm94XHJcblxyXG5cdFx0Y29uc3QgYm91bmRpbmdCb3ggPSBzb3VyY2UuYm91bmRpbmdCb3g7XHJcblxyXG5cdFx0aWYgKCBib3VuZGluZ0JveCAhPT0gbnVsbCApIHtcclxuXHJcblx0XHRcdHRoaXMuYm91bmRpbmdCb3ggPSBib3VuZGluZ0JveC5jbG9uZSgpO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvLyBib3VuZGluZyBzcGhlcmVcclxuXHJcblx0XHRjb25zdCBib3VuZGluZ1NwaGVyZSA9IHNvdXJjZS5ib3VuZGluZ1NwaGVyZTtcclxuXHJcblx0XHRpZiAoIGJvdW5kaW5nU3BoZXJlICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0dGhpcy5ib3VuZGluZ1NwaGVyZSA9IGJvdW5kaW5nU3BoZXJlLmNsb25lKCk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIGRyYXcgcmFuZ2VcclxuXHJcblx0XHR0aGlzLmRyYXdSYW5nZS5zdGFydCA9IHNvdXJjZS5kcmF3UmFuZ2Uuc3RhcnQ7XHJcblx0XHR0aGlzLmRyYXdSYW5nZS5jb3VudCA9IHNvdXJjZS5kcmF3UmFuZ2UuY291bnQ7XHJcblxyXG5cdFx0Ly8gdXNlciBkYXRhXHJcblxyXG5cdFx0dGhpcy51c2VyRGF0YSA9IHNvdXJjZS51c2VyRGF0YTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRkaXNwb3NlKCkge1xyXG5cclxuXHRcdHRoaXMuZGlzcGF0Y2hFdmVudCggeyB0eXBlOiAnZGlzcG9zZScgfSApO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBCdWZmZXJHZW9tZXRyeSB9O1xyXG4iLCJpbXBvcnQgeyBWZWN0b3IzIH0gZnJvbSAnLi4vbWF0aC9WZWN0b3IzLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yMiB9IGZyb20gJy4uL21hdGgvVmVjdG9yMi5qcyc7XHJcbmltcG9ydCB7IFNwaGVyZSB9IGZyb20gJy4uL21hdGgvU3BoZXJlLmpzJztcclxuaW1wb3J0IHsgUmF5IH0gZnJvbSAnLi4vbWF0aC9SYXkuanMnO1xyXG5pbXBvcnQgeyBNYXRyaXg0IH0gZnJvbSAnLi4vbWF0aC9NYXRyaXg0LmpzJztcclxuaW1wb3J0IHsgT2JqZWN0M0QgfSBmcm9tICcuLi9jb3JlL09iamVjdDNELmpzJztcclxuaW1wb3J0IHsgVHJpYW5nbGUgfSBmcm9tICcuLi9tYXRoL1RyaWFuZ2xlLmpzJztcclxuaW1wb3J0IHsgQmFja1NpZGUsIEZyb250U2lkZSB9IGZyb20gJy4uL2NvbnN0YW50cy5qcyc7XHJcbmltcG9ydCB7IE1lc2hCYXNpY01hdGVyaWFsIH0gZnJvbSAnLi4vbWF0ZXJpYWxzL01lc2hCYXNpY01hdGVyaWFsLmpzJztcclxuaW1wb3J0IHsgQnVmZmVyR2VvbWV0cnkgfSBmcm9tICcuLi9jb3JlL0J1ZmZlckdlb21ldHJ5LmpzJztcclxuXHJcbmNvbnN0IF9pbnZlcnNlTWF0cml4ID0gLypAX19QVVJFX18qLyBuZXcgTWF0cml4NCgpO1xyXG5jb25zdCBfcmF5ID0gLypAX19QVVJFX18qLyBuZXcgUmF5KCk7XHJcbmNvbnN0IF9zcGhlcmUgPSAvKkBfX1BVUkVfXyovIG5ldyBTcGhlcmUoKTtcclxuY29uc3QgX3NwaGVyZUhpdEF0ID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5cclxuY29uc3QgX3ZBID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5jb25zdCBfdkIgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XHJcbmNvbnN0IF92QyA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuXHJcbmNvbnN0IF90ZW1wQSA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuY29uc3QgX21vcnBoQSA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuXHJcbmNvbnN0IF91dkEgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IyKCk7XHJcbmNvbnN0IF91dkIgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IyKCk7XHJcbmNvbnN0IF91dkMgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IyKCk7XHJcblxyXG5jb25zdCBfbm9ybWFsQSA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuY29uc3QgX25vcm1hbEIgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XHJcbmNvbnN0IF9ub3JtYWxDID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5cclxuY29uc3QgX2ludGVyc2VjdGlvblBvaW50ID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5jb25zdCBfaW50ZXJzZWN0aW9uUG9pbnRXb3JsZCA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuXHJcbmNsYXNzIE1lc2ggZXh0ZW5kcyBPYmplY3QzRCB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBnZW9tZXRyeSA9IG5ldyBCdWZmZXJHZW9tZXRyeSgpLCBtYXRlcmlhbCA9IG5ldyBNZXNoQmFzaWNNYXRlcmlhbCgpICkge1xyXG5cclxuXHRcdHN1cGVyKCk7XHJcblxyXG5cdFx0dGhpcy5pc01lc2ggPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMudHlwZSA9ICdNZXNoJztcclxuXHJcblx0XHR0aGlzLmdlb21ldHJ5ID0gZ2VvbWV0cnk7XHJcblx0XHR0aGlzLm1hdGVyaWFsID0gbWF0ZXJpYWw7XHJcblxyXG5cdFx0dGhpcy51cGRhdGVNb3JwaFRhcmdldHMoKTtcclxuXHJcblx0fVxyXG5cclxuXHRjb3B5KCBzb3VyY2UsIHJlY3Vyc2l2ZSApIHtcclxuXHJcblx0XHRzdXBlci5jb3B5KCBzb3VyY2UsIHJlY3Vyc2l2ZSApO1xyXG5cclxuXHRcdGlmICggc291cmNlLm1vcnBoVGFyZ2V0SW5mbHVlbmNlcyAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0dGhpcy5tb3JwaFRhcmdldEluZmx1ZW5jZXMgPSBzb3VyY2UubW9ycGhUYXJnZXRJbmZsdWVuY2VzLnNsaWNlKCk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggc291cmNlLm1vcnBoVGFyZ2V0RGljdGlvbmFyeSAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0dGhpcy5tb3JwaFRhcmdldERpY3Rpb25hcnkgPSBPYmplY3QuYXNzaWduKCB7fSwgc291cmNlLm1vcnBoVGFyZ2V0RGljdGlvbmFyeSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLm1hdGVyaWFsID0gQXJyYXkuaXNBcnJheSggc291cmNlLm1hdGVyaWFsICkgPyBzb3VyY2UubWF0ZXJpYWwuc2xpY2UoKSA6IHNvdXJjZS5tYXRlcmlhbDtcclxuXHRcdHRoaXMuZ2VvbWV0cnkgPSBzb3VyY2UuZ2VvbWV0cnk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0dXBkYXRlTW9ycGhUYXJnZXRzKCkge1xyXG5cclxuXHRcdGNvbnN0IGdlb21ldHJ5ID0gdGhpcy5nZW9tZXRyeTtcclxuXHJcblx0XHRjb25zdCBtb3JwaEF0dHJpYnV0ZXMgPSBnZW9tZXRyeS5tb3JwaEF0dHJpYnV0ZXM7XHJcblx0XHRjb25zdCBrZXlzID0gT2JqZWN0LmtleXMoIG1vcnBoQXR0cmlidXRlcyApO1xyXG5cclxuXHRcdGlmICgga2V5cy5sZW5ndGggPiAwICkge1xyXG5cclxuXHRcdFx0Y29uc3QgbW9ycGhBdHRyaWJ1dGUgPSBtb3JwaEF0dHJpYnV0ZXNbIGtleXNbIDAgXSBdO1xyXG5cclxuXHRcdFx0aWYgKCBtb3JwaEF0dHJpYnV0ZSAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHR0aGlzLm1vcnBoVGFyZ2V0SW5mbHVlbmNlcyA9IFtdO1xyXG5cdFx0XHRcdHRoaXMubW9ycGhUYXJnZXREaWN0aW9uYXJ5ID0ge307XHJcblxyXG5cdFx0XHRcdGZvciAoIGxldCBtID0gMCwgbWwgPSBtb3JwaEF0dHJpYnV0ZS5sZW5ndGg7IG0gPCBtbDsgbSArKyApIHtcclxuXHJcblx0XHRcdFx0XHRjb25zdCBuYW1lID0gbW9ycGhBdHRyaWJ1dGVbIG0gXS5uYW1lIHx8IFN0cmluZyggbSApO1xyXG5cclxuXHRcdFx0XHRcdHRoaXMubW9ycGhUYXJnZXRJbmZsdWVuY2VzLnB1c2goIDAgKTtcclxuXHRcdFx0XHRcdHRoaXMubW9ycGhUYXJnZXREaWN0aW9uYXJ5WyBuYW1lIF0gPSBtO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGdldFZlcnRleFBvc2l0aW9uKCBpbmRleCwgdGFyZ2V0ICkge1xyXG5cclxuXHRcdGNvbnN0IGdlb21ldHJ5ID0gdGhpcy5nZW9tZXRyeTtcclxuXHRcdGNvbnN0IHBvc2l0aW9uID0gZ2VvbWV0cnkuYXR0cmlidXRlcy5wb3NpdGlvbjtcclxuXHRcdGNvbnN0IG1vcnBoUG9zaXRpb24gPSBnZW9tZXRyeS5tb3JwaEF0dHJpYnV0ZXMucG9zaXRpb247XHJcblx0XHRjb25zdCBtb3JwaFRhcmdldHNSZWxhdGl2ZSA9IGdlb21ldHJ5Lm1vcnBoVGFyZ2V0c1JlbGF0aXZlO1xyXG5cclxuXHRcdHRhcmdldC5mcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbiwgaW5kZXggKTtcclxuXHJcblx0XHRjb25zdCBtb3JwaEluZmx1ZW5jZXMgPSB0aGlzLm1vcnBoVGFyZ2V0SW5mbHVlbmNlcztcclxuXHJcblx0XHRpZiAoIG1vcnBoUG9zaXRpb24gJiYgbW9ycGhJbmZsdWVuY2VzICkge1xyXG5cclxuXHRcdFx0X21vcnBoQS5zZXQoIDAsIDAsIDAgKTtcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSBtb3JwaFBvc2l0aW9uLmxlbmd0aDsgaSA8IGlsOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBpbmZsdWVuY2UgPSBtb3JwaEluZmx1ZW5jZXNbIGkgXTtcclxuXHRcdFx0XHRjb25zdCBtb3JwaEF0dHJpYnV0ZSA9IG1vcnBoUG9zaXRpb25bIGkgXTtcclxuXHJcblx0XHRcdFx0aWYgKCBpbmZsdWVuY2UgPT09IDAgKSBjb250aW51ZTtcclxuXHJcblx0XHRcdFx0X3RlbXBBLmZyb21CdWZmZXJBdHRyaWJ1dGUoIG1vcnBoQXR0cmlidXRlLCBpbmRleCApO1xyXG5cclxuXHRcdFx0XHRpZiAoIG1vcnBoVGFyZ2V0c1JlbGF0aXZlICkge1xyXG5cclxuXHRcdFx0XHRcdF9tb3JwaEEuYWRkU2NhbGVkVmVjdG9yKCBfdGVtcEEsIGluZmx1ZW5jZSApO1xyXG5cclxuXHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdF9tb3JwaEEuYWRkU2NhbGVkVmVjdG9yKCBfdGVtcEEuc3ViKCB0YXJnZXQgKSwgaW5mbHVlbmNlICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHRhcmdldC5hZGQoIF9tb3JwaEEgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRhcmdldDtcclxuXHJcblx0fVxyXG5cclxuXHRyYXljYXN0KCByYXljYXN0ZXIsIGludGVyc2VjdHMgKSB7XHJcblxyXG5cdFx0Y29uc3QgZ2VvbWV0cnkgPSB0aGlzLmdlb21ldHJ5O1xyXG5cdFx0Y29uc3QgbWF0ZXJpYWwgPSB0aGlzLm1hdGVyaWFsO1xyXG5cdFx0Y29uc3QgbWF0cml4V29ybGQgPSB0aGlzLm1hdHJpeFdvcmxkO1xyXG5cclxuXHRcdGlmICggbWF0ZXJpYWwgPT09IHVuZGVmaW5lZCApIHJldHVybjtcclxuXHJcblx0XHQvLyB0ZXN0IHdpdGggYm91bmRpbmcgc3BoZXJlIGluIHdvcmxkIHNwYWNlXHJcblxyXG5cdFx0aWYgKCBnZW9tZXRyeS5ib3VuZGluZ1NwaGVyZSA9PT0gbnVsbCApIGdlb21ldHJ5LmNvbXB1dGVCb3VuZGluZ1NwaGVyZSgpO1xyXG5cclxuXHRcdF9zcGhlcmUuY29weSggZ2VvbWV0cnkuYm91bmRpbmdTcGhlcmUgKTtcclxuXHRcdF9zcGhlcmUuYXBwbHlNYXRyaXg0KCBtYXRyaXhXb3JsZCApO1xyXG5cclxuXHRcdC8vIGNoZWNrIGRpc3RhbmNlIGZyb20gcmF5IG9yaWdpbiB0byBib3VuZGluZyBzcGhlcmVcclxuXHJcblx0XHRfcmF5LmNvcHkoIHJheWNhc3Rlci5yYXkgKS5yZWNhc3QoIHJheWNhc3Rlci5uZWFyICk7XHJcblxyXG5cdFx0aWYgKCBfc3BoZXJlLmNvbnRhaW5zUG9pbnQoIF9yYXkub3JpZ2luICkgPT09IGZhbHNlICkge1xyXG5cclxuXHRcdFx0aWYgKCBfcmF5LmludGVyc2VjdFNwaGVyZSggX3NwaGVyZSwgX3NwaGVyZUhpdEF0ICkgPT09IG51bGwgKSByZXR1cm47XHJcblxyXG5cdFx0XHRpZiAoIF9yYXkub3JpZ2luLmRpc3RhbmNlVG9TcXVhcmVkKCBfc3BoZXJlSGl0QXQgKSA+ICggcmF5Y2FzdGVyLmZhciAtIHJheWNhc3Rlci5uZWFyICkgKiogMiApIHJldHVybjtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gY29udmVydCByYXkgdG8gbG9jYWwgc3BhY2Ugb2YgbWVzaFxyXG5cclxuXHRcdF9pbnZlcnNlTWF0cml4LmNvcHkoIG1hdHJpeFdvcmxkICkuaW52ZXJ0KCk7XHJcblx0XHRfcmF5LmNvcHkoIHJheWNhc3Rlci5yYXkgKS5hcHBseU1hdHJpeDQoIF9pbnZlcnNlTWF0cml4ICk7XHJcblxyXG5cdFx0Ly8gdGVzdCB3aXRoIGJvdW5kaW5nIGJveCBpbiBsb2NhbCBzcGFjZVxyXG5cclxuXHRcdGlmICggZ2VvbWV0cnkuYm91bmRpbmdCb3ggIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRpZiAoIF9yYXkuaW50ZXJzZWN0c0JveCggZ2VvbWV0cnkuYm91bmRpbmdCb3ggKSA9PT0gZmFsc2UgKSByZXR1cm47XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIHRlc3QgZm9yIGludGVyc2VjdGlvbnMgd2l0aCBnZW9tZXRyeVxyXG5cclxuXHRcdHRoaXMuX2NvbXB1dGVJbnRlcnNlY3Rpb25zKCByYXljYXN0ZXIsIGludGVyc2VjdHMsIF9yYXkgKTtcclxuXHJcblx0fVxyXG5cclxuXHRfY29tcHV0ZUludGVyc2VjdGlvbnMoIHJheWNhc3RlciwgaW50ZXJzZWN0cywgcmF5TG9jYWxTcGFjZSApIHtcclxuXHJcblx0XHRsZXQgaW50ZXJzZWN0aW9uO1xyXG5cclxuXHRcdGNvbnN0IGdlb21ldHJ5ID0gdGhpcy5nZW9tZXRyeTtcclxuXHRcdGNvbnN0IG1hdGVyaWFsID0gdGhpcy5tYXRlcmlhbDtcclxuXHJcblx0XHRjb25zdCBpbmRleCA9IGdlb21ldHJ5LmluZGV4O1xyXG5cdFx0Y29uc3QgcG9zaXRpb24gPSBnZW9tZXRyeS5hdHRyaWJ1dGVzLnBvc2l0aW9uO1xyXG5cdFx0Y29uc3QgdXYgPSBnZW9tZXRyeS5hdHRyaWJ1dGVzLnV2O1xyXG5cdFx0Y29uc3QgdXYxID0gZ2VvbWV0cnkuYXR0cmlidXRlcy51djE7XHJcblx0XHRjb25zdCBub3JtYWwgPSBnZW9tZXRyeS5hdHRyaWJ1dGVzLm5vcm1hbDtcclxuXHRcdGNvbnN0IGdyb3VwcyA9IGdlb21ldHJ5Lmdyb3VwcztcclxuXHRcdGNvbnN0IGRyYXdSYW5nZSA9IGdlb21ldHJ5LmRyYXdSYW5nZTtcclxuXHJcblx0XHRpZiAoIGluZGV4ICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0Ly8gaW5kZXhlZCBidWZmZXIgZ2VvbWV0cnlcclxuXHJcblx0XHRcdGlmICggQXJyYXkuaXNBcnJheSggbWF0ZXJpYWwgKSApIHtcclxuXHJcblx0XHRcdFx0Zm9yICggbGV0IGkgPSAwLCBpbCA9IGdyb3Vwcy5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0XHRjb25zdCBncm91cCA9IGdyb3Vwc1sgaSBdO1xyXG5cdFx0XHRcdFx0Y29uc3QgZ3JvdXBNYXRlcmlhbCA9IG1hdGVyaWFsWyBncm91cC5tYXRlcmlhbEluZGV4IF07XHJcblxyXG5cdFx0XHRcdFx0Y29uc3Qgc3RhcnQgPSBNYXRoLm1heCggZ3JvdXAuc3RhcnQsIGRyYXdSYW5nZS5zdGFydCApO1xyXG5cdFx0XHRcdFx0Y29uc3QgZW5kID0gTWF0aC5taW4oIGluZGV4LmNvdW50LCBNYXRoLm1pbiggKCBncm91cC5zdGFydCArIGdyb3VwLmNvdW50ICksICggZHJhd1JhbmdlLnN0YXJ0ICsgZHJhd1JhbmdlLmNvdW50ICkgKSApO1xyXG5cclxuXHRcdFx0XHRcdGZvciAoIGxldCBqID0gc3RhcnQsIGpsID0gZW5kOyBqIDwgamw7IGogKz0gMyApIHtcclxuXHJcblx0XHRcdFx0XHRcdGNvbnN0IGEgPSBpbmRleC5nZXRYKCBqICk7XHJcblx0XHRcdFx0XHRcdGNvbnN0IGIgPSBpbmRleC5nZXRYKCBqICsgMSApO1xyXG5cdFx0XHRcdFx0XHRjb25zdCBjID0gaW5kZXguZ2V0WCggaiArIDIgKTtcclxuXHJcblx0XHRcdFx0XHRcdGludGVyc2VjdGlvbiA9IGNoZWNrR2VvbWV0cnlJbnRlcnNlY3Rpb24oIHRoaXMsIGdyb3VwTWF0ZXJpYWwsIHJheWNhc3RlciwgcmF5TG9jYWxTcGFjZSwgdXYsIHV2MSwgbm9ybWFsLCBhLCBiLCBjICk7XHJcblxyXG5cdFx0XHRcdFx0XHRpZiAoIGludGVyc2VjdGlvbiApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0aW50ZXJzZWN0aW9uLmZhY2VJbmRleCA9IE1hdGguZmxvb3IoIGogLyAzICk7IC8vIHRyaWFuZ2xlIG51bWJlciBpbiBpbmRleGVkIGJ1ZmZlciBzZW1hbnRpY3NcclxuXHRcdFx0XHRcdFx0XHRpbnRlcnNlY3Rpb24uZmFjZS5tYXRlcmlhbEluZGV4ID0gZ3JvdXAubWF0ZXJpYWxJbmRleDtcclxuXHRcdFx0XHRcdFx0XHRpbnRlcnNlY3RzLnB1c2goIGludGVyc2VjdGlvbiApO1xyXG5cclxuXHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0Y29uc3Qgc3RhcnQgPSBNYXRoLm1heCggMCwgZHJhd1JhbmdlLnN0YXJ0ICk7XHJcblx0XHRcdFx0Y29uc3QgZW5kID0gTWF0aC5taW4oIGluZGV4LmNvdW50LCAoIGRyYXdSYW5nZS5zdGFydCArIGRyYXdSYW5nZS5jb3VudCApICk7XHJcblxyXG5cdFx0XHRcdGZvciAoIGxldCBpID0gc3RhcnQsIGlsID0gZW5kOyBpIDwgaWw7IGkgKz0gMyApIHtcclxuXHJcblx0XHRcdFx0XHRjb25zdCBhID0gaW5kZXguZ2V0WCggaSApO1xyXG5cdFx0XHRcdFx0Y29uc3QgYiA9IGluZGV4LmdldFgoIGkgKyAxICk7XHJcblx0XHRcdFx0XHRjb25zdCBjID0gaW5kZXguZ2V0WCggaSArIDIgKTtcclxuXHJcblx0XHRcdFx0XHRpbnRlcnNlY3Rpb24gPSBjaGVja0dlb21ldHJ5SW50ZXJzZWN0aW9uKCB0aGlzLCBtYXRlcmlhbCwgcmF5Y2FzdGVyLCByYXlMb2NhbFNwYWNlLCB1diwgdXYxLCBub3JtYWwsIGEsIGIsIGMgKTtcclxuXHJcblx0XHRcdFx0XHRpZiAoIGludGVyc2VjdGlvbiApIHtcclxuXHJcblx0XHRcdFx0XHRcdGludGVyc2VjdGlvbi5mYWNlSW5kZXggPSBNYXRoLmZsb29yKCBpIC8gMyApOyAvLyB0cmlhbmdsZSBudW1iZXIgaW4gaW5kZXhlZCBidWZmZXIgc2VtYW50aWNzXHJcblx0XHRcdFx0XHRcdGludGVyc2VjdHMucHVzaCggaW50ZXJzZWN0aW9uICk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fSBlbHNlIGlmICggcG9zaXRpb24gIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdC8vIG5vbi1pbmRleGVkIGJ1ZmZlciBnZW9tZXRyeVxyXG5cclxuXHRcdFx0aWYgKCBBcnJheS5pc0FycmF5KCBtYXRlcmlhbCApICkge1xyXG5cclxuXHRcdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gZ3JvdXBzLmxlbmd0aDsgaSA8IGlsOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRcdGNvbnN0IGdyb3VwID0gZ3JvdXBzWyBpIF07XHJcblx0XHRcdFx0XHRjb25zdCBncm91cE1hdGVyaWFsID0gbWF0ZXJpYWxbIGdyb3VwLm1hdGVyaWFsSW5kZXggXTtcclxuXHJcblx0XHRcdFx0XHRjb25zdCBzdGFydCA9IE1hdGgubWF4KCBncm91cC5zdGFydCwgZHJhd1JhbmdlLnN0YXJ0ICk7XHJcblx0XHRcdFx0XHRjb25zdCBlbmQgPSBNYXRoLm1pbiggcG9zaXRpb24uY291bnQsIE1hdGgubWluKCAoIGdyb3VwLnN0YXJ0ICsgZ3JvdXAuY291bnQgKSwgKCBkcmF3UmFuZ2Uuc3RhcnQgKyBkcmF3UmFuZ2UuY291bnQgKSApICk7XHJcblxyXG5cdFx0XHRcdFx0Zm9yICggbGV0IGogPSBzdGFydCwgamwgPSBlbmQ7IGogPCBqbDsgaiArPSAzICkge1xyXG5cclxuXHRcdFx0XHRcdFx0Y29uc3QgYSA9IGo7XHJcblx0XHRcdFx0XHRcdGNvbnN0IGIgPSBqICsgMTtcclxuXHRcdFx0XHRcdFx0Y29uc3QgYyA9IGogKyAyO1xyXG5cclxuXHRcdFx0XHRcdFx0aW50ZXJzZWN0aW9uID0gY2hlY2tHZW9tZXRyeUludGVyc2VjdGlvbiggdGhpcywgZ3JvdXBNYXRlcmlhbCwgcmF5Y2FzdGVyLCByYXlMb2NhbFNwYWNlLCB1diwgdXYxLCBub3JtYWwsIGEsIGIsIGMgKTtcclxuXHJcblx0XHRcdFx0XHRcdGlmICggaW50ZXJzZWN0aW9uICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRpbnRlcnNlY3Rpb24uZmFjZUluZGV4ID0gTWF0aC5mbG9vciggaiAvIDMgKTsgLy8gdHJpYW5nbGUgbnVtYmVyIGluIG5vbi1pbmRleGVkIGJ1ZmZlciBzZW1hbnRpY3NcclxuXHRcdFx0XHRcdFx0XHRpbnRlcnNlY3Rpb24uZmFjZS5tYXRlcmlhbEluZGV4ID0gZ3JvdXAubWF0ZXJpYWxJbmRleDtcclxuXHRcdFx0XHRcdFx0XHRpbnRlcnNlY3RzLnB1c2goIGludGVyc2VjdGlvbiApO1xyXG5cclxuXHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0Y29uc3Qgc3RhcnQgPSBNYXRoLm1heCggMCwgZHJhd1JhbmdlLnN0YXJ0ICk7XHJcblx0XHRcdFx0Y29uc3QgZW5kID0gTWF0aC5taW4oIHBvc2l0aW9uLmNvdW50LCAoIGRyYXdSYW5nZS5zdGFydCArIGRyYXdSYW5nZS5jb3VudCApICk7XHJcblxyXG5cdFx0XHRcdGZvciAoIGxldCBpID0gc3RhcnQsIGlsID0gZW5kOyBpIDwgaWw7IGkgKz0gMyApIHtcclxuXHJcblx0XHRcdFx0XHRjb25zdCBhID0gaTtcclxuXHRcdFx0XHRcdGNvbnN0IGIgPSBpICsgMTtcclxuXHRcdFx0XHRcdGNvbnN0IGMgPSBpICsgMjtcclxuXHJcblx0XHRcdFx0XHRpbnRlcnNlY3Rpb24gPSBjaGVja0dlb21ldHJ5SW50ZXJzZWN0aW9uKCB0aGlzLCBtYXRlcmlhbCwgcmF5Y2FzdGVyLCByYXlMb2NhbFNwYWNlLCB1diwgdXYxLCBub3JtYWwsIGEsIGIsIGMgKTtcclxuXHJcblx0XHRcdFx0XHRpZiAoIGludGVyc2VjdGlvbiApIHtcclxuXHJcblx0XHRcdFx0XHRcdGludGVyc2VjdGlvbi5mYWNlSW5kZXggPSBNYXRoLmZsb29yKCBpIC8gMyApOyAvLyB0cmlhbmdsZSBudW1iZXIgaW4gbm9uLWluZGV4ZWQgYnVmZmVyIHNlbWFudGljc1xyXG5cdFx0XHRcdFx0XHRpbnRlcnNlY3RzLnB1c2goIGludGVyc2VjdGlvbiApO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gY2hlY2tJbnRlcnNlY3Rpb24oIG9iamVjdCwgbWF0ZXJpYWwsIHJheWNhc3RlciwgcmF5LCBwQSwgcEIsIHBDLCBwb2ludCApIHtcclxuXHJcblx0bGV0IGludGVyc2VjdDtcclxuXHJcblx0aWYgKCBtYXRlcmlhbC5zaWRlID09PSBCYWNrU2lkZSApIHtcclxuXHJcblx0XHRpbnRlcnNlY3QgPSByYXkuaW50ZXJzZWN0VHJpYW5nbGUoIHBDLCBwQiwgcEEsIHRydWUsIHBvaW50ICk7XHJcblxyXG5cdH0gZWxzZSB7XHJcblxyXG5cdFx0aW50ZXJzZWN0ID0gcmF5LmludGVyc2VjdFRyaWFuZ2xlKCBwQSwgcEIsIHBDLCAoIG1hdGVyaWFsLnNpZGUgPT09IEZyb250U2lkZSApLCBwb2ludCApO1xyXG5cclxuXHR9XHJcblxyXG5cdGlmICggaW50ZXJzZWN0ID09PSBudWxsICkgcmV0dXJuIG51bGw7XHJcblxyXG5cdF9pbnRlcnNlY3Rpb25Qb2ludFdvcmxkLmNvcHkoIHBvaW50ICk7XHJcblx0X2ludGVyc2VjdGlvblBvaW50V29ybGQuYXBwbHlNYXRyaXg0KCBvYmplY3QubWF0cml4V29ybGQgKTtcclxuXHJcblx0Y29uc3QgZGlzdGFuY2UgPSByYXljYXN0ZXIucmF5Lm9yaWdpbi5kaXN0YW5jZVRvKCBfaW50ZXJzZWN0aW9uUG9pbnRXb3JsZCApO1xyXG5cclxuXHRpZiAoIGRpc3RhbmNlIDwgcmF5Y2FzdGVyLm5lYXIgfHwgZGlzdGFuY2UgPiByYXljYXN0ZXIuZmFyICkgcmV0dXJuIG51bGw7XHJcblxyXG5cdHJldHVybiB7XHJcblx0XHRkaXN0YW5jZTogZGlzdGFuY2UsXHJcblx0XHRwb2ludDogX2ludGVyc2VjdGlvblBvaW50V29ybGQuY2xvbmUoKSxcclxuXHRcdG9iamVjdDogb2JqZWN0XHJcblx0fTtcclxuXHJcbn1cclxuXHJcbmZ1bmN0aW9uIGNoZWNrR2VvbWV0cnlJbnRlcnNlY3Rpb24oIG9iamVjdCwgbWF0ZXJpYWwsIHJheWNhc3RlciwgcmF5LCB1diwgdXYxLCBub3JtYWwsIGEsIGIsIGMgKSB7XHJcblxyXG5cdG9iamVjdC5nZXRWZXJ0ZXhQb3NpdGlvbiggYSwgX3ZBICk7XHJcblx0b2JqZWN0LmdldFZlcnRleFBvc2l0aW9uKCBiLCBfdkIgKTtcclxuXHRvYmplY3QuZ2V0VmVydGV4UG9zaXRpb24oIGMsIF92QyApO1xyXG5cclxuXHRjb25zdCBpbnRlcnNlY3Rpb24gPSBjaGVja0ludGVyc2VjdGlvbiggb2JqZWN0LCBtYXRlcmlhbCwgcmF5Y2FzdGVyLCByYXksIF92QSwgX3ZCLCBfdkMsIF9pbnRlcnNlY3Rpb25Qb2ludCApO1xyXG5cclxuXHRpZiAoIGludGVyc2VjdGlvbiApIHtcclxuXHJcblx0XHRpZiAoIHV2ICkge1xyXG5cclxuXHRcdFx0X3V2QS5mcm9tQnVmZmVyQXR0cmlidXRlKCB1diwgYSApO1xyXG5cdFx0XHRfdXZCLmZyb21CdWZmZXJBdHRyaWJ1dGUoIHV2LCBiICk7XHJcblx0XHRcdF91dkMuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggdXYsIGMgKTtcclxuXHJcblx0XHRcdGludGVyc2VjdGlvbi51diA9IFRyaWFuZ2xlLmdldEludGVycG9sYXRpb24oIF9pbnRlcnNlY3Rpb25Qb2ludCwgX3ZBLCBfdkIsIF92QywgX3V2QSwgX3V2QiwgX3V2QywgbmV3IFZlY3RvcjIoKSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHV2MSApIHtcclxuXHJcblx0XHRcdF91dkEuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggdXYxLCBhICk7XHJcblx0XHRcdF91dkIuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggdXYxLCBiICk7XHJcblx0XHRcdF91dkMuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggdXYxLCBjICk7XHJcblxyXG5cdFx0XHRpbnRlcnNlY3Rpb24udXYxID0gVHJpYW5nbGUuZ2V0SW50ZXJwb2xhdGlvbiggX2ludGVyc2VjdGlvblBvaW50LCBfdkEsIF92QiwgX3ZDLCBfdXZBLCBfdXZCLCBfdXZDLCBuZXcgVmVjdG9yMigpICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggbm9ybWFsICkge1xyXG5cclxuXHRcdFx0X25vcm1hbEEuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggbm9ybWFsLCBhICk7XHJcblx0XHRcdF9ub3JtYWxCLmZyb21CdWZmZXJBdHRyaWJ1dGUoIG5vcm1hbCwgYiApO1xyXG5cdFx0XHRfbm9ybWFsQy5mcm9tQnVmZmVyQXR0cmlidXRlKCBub3JtYWwsIGMgKTtcclxuXHJcblx0XHRcdGludGVyc2VjdGlvbi5ub3JtYWwgPSBUcmlhbmdsZS5nZXRJbnRlcnBvbGF0aW9uKCBfaW50ZXJzZWN0aW9uUG9pbnQsIF92QSwgX3ZCLCBfdkMsIF9ub3JtYWxBLCBfbm9ybWFsQiwgX25vcm1hbEMsIG5ldyBWZWN0b3IzKCkgKTtcclxuXHJcblx0XHRcdGlmICggaW50ZXJzZWN0aW9uLm5vcm1hbC5kb3QoIHJheS5kaXJlY3Rpb24gKSA+IDAgKSB7XHJcblxyXG5cdFx0XHRcdGludGVyc2VjdGlvbi5ub3JtYWwubXVsdGlwbHlTY2FsYXIoIC0gMSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCBmYWNlID0ge1xyXG5cdFx0XHRhOiBhLFxyXG5cdFx0XHRiOiBiLFxyXG5cdFx0XHRjOiBjLFxyXG5cdFx0XHRub3JtYWw6IG5ldyBWZWN0b3IzKCksXHJcblx0XHRcdG1hdGVyaWFsSW5kZXg6IDBcclxuXHRcdH07XHJcblxyXG5cdFx0VHJpYW5nbGUuZ2V0Tm9ybWFsKCBfdkEsIF92QiwgX3ZDLCBmYWNlLm5vcm1hbCApO1xyXG5cclxuXHRcdGludGVyc2VjdGlvbi5mYWNlID0gZmFjZTtcclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4gaW50ZXJzZWN0aW9uO1xyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgTWVzaCB9O1xyXG4iLCJpbXBvcnQgeyBCdWZmZXJHZW9tZXRyeSB9IGZyb20gJy4uL2NvcmUvQnVmZmVyR2VvbWV0cnkuanMnO1xyXG5pbXBvcnQgeyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlIH0gZnJvbSAnLi4vY29yZS9CdWZmZXJBdHRyaWJ1dGUuanMnO1xyXG5pbXBvcnQgeyBWZWN0b3IzIH0gZnJvbSAnLi4vbWF0aC9WZWN0b3IzLmpzJztcclxuXHJcbmNsYXNzIEJveEdlb21ldHJ5IGV4dGVuZHMgQnVmZmVyR2VvbWV0cnkge1xyXG5cclxuXHRjb25zdHJ1Y3Rvciggd2lkdGggPSAxLCBoZWlnaHQgPSAxLCBkZXB0aCA9IDEsIHdpZHRoU2VnbWVudHMgPSAxLCBoZWlnaHRTZWdtZW50cyA9IDEsIGRlcHRoU2VnbWVudHMgPSAxICkge1xyXG5cclxuXHRcdHN1cGVyKCk7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ0JveEdlb21ldHJ5JztcclxuXHJcblx0XHR0aGlzLnBhcmFtZXRlcnMgPSB7XHJcblx0XHRcdHdpZHRoOiB3aWR0aCxcclxuXHRcdFx0aGVpZ2h0OiBoZWlnaHQsXHJcblx0XHRcdGRlcHRoOiBkZXB0aCxcclxuXHRcdFx0d2lkdGhTZWdtZW50czogd2lkdGhTZWdtZW50cyxcclxuXHRcdFx0aGVpZ2h0U2VnbWVudHM6IGhlaWdodFNlZ21lbnRzLFxyXG5cdFx0XHRkZXB0aFNlZ21lbnRzOiBkZXB0aFNlZ21lbnRzXHJcblx0XHR9O1xyXG5cclxuXHRcdGNvbnN0IHNjb3BlID0gdGhpcztcclxuXHJcblx0XHQvLyBzZWdtZW50c1xyXG5cclxuXHRcdHdpZHRoU2VnbWVudHMgPSBNYXRoLmZsb29yKCB3aWR0aFNlZ21lbnRzICk7XHJcblx0XHRoZWlnaHRTZWdtZW50cyA9IE1hdGguZmxvb3IoIGhlaWdodFNlZ21lbnRzICk7XHJcblx0XHRkZXB0aFNlZ21lbnRzID0gTWF0aC5mbG9vciggZGVwdGhTZWdtZW50cyApO1xyXG5cclxuXHRcdC8vIGJ1ZmZlcnNcclxuXHJcblx0XHRjb25zdCBpbmRpY2VzID0gW107XHJcblx0XHRjb25zdCB2ZXJ0aWNlcyA9IFtdO1xyXG5cdFx0Y29uc3Qgbm9ybWFscyA9IFtdO1xyXG5cdFx0Y29uc3QgdXZzID0gW107XHJcblxyXG5cdFx0Ly8gaGVscGVyIHZhcmlhYmxlc1xyXG5cclxuXHRcdGxldCBudW1iZXJPZlZlcnRpY2VzID0gMDtcclxuXHRcdGxldCBncm91cFN0YXJ0ID0gMDtcclxuXHJcblx0XHQvLyBidWlsZCBlYWNoIHNpZGUgb2YgdGhlIGJveCBnZW9tZXRyeVxyXG5cclxuXHRcdGJ1aWxkUGxhbmUoICd6JywgJ3knLCAneCcsIC0gMSwgLSAxLCBkZXB0aCwgaGVpZ2h0LCB3aWR0aCwgZGVwdGhTZWdtZW50cywgaGVpZ2h0U2VnbWVudHMsIDAgKTsgLy8gcHhcclxuXHRcdGJ1aWxkUGxhbmUoICd6JywgJ3knLCAneCcsIDEsIC0gMSwgZGVwdGgsIGhlaWdodCwgLSB3aWR0aCwgZGVwdGhTZWdtZW50cywgaGVpZ2h0U2VnbWVudHMsIDEgKTsgLy8gbnhcclxuXHRcdGJ1aWxkUGxhbmUoICd4JywgJ3onLCAneScsIDEsIDEsIHdpZHRoLCBkZXB0aCwgaGVpZ2h0LCB3aWR0aFNlZ21lbnRzLCBkZXB0aFNlZ21lbnRzLCAyICk7IC8vIHB5XHJcblx0XHRidWlsZFBsYW5lKCAneCcsICd6JywgJ3knLCAxLCAtIDEsIHdpZHRoLCBkZXB0aCwgLSBoZWlnaHQsIHdpZHRoU2VnbWVudHMsIGRlcHRoU2VnbWVudHMsIDMgKTsgLy8gbnlcclxuXHRcdGJ1aWxkUGxhbmUoICd4JywgJ3knLCAneicsIDEsIC0gMSwgd2lkdGgsIGhlaWdodCwgZGVwdGgsIHdpZHRoU2VnbWVudHMsIGhlaWdodFNlZ21lbnRzLCA0ICk7IC8vIHB6XHJcblx0XHRidWlsZFBsYW5lKCAneCcsICd5JywgJ3onLCAtIDEsIC0gMSwgd2lkdGgsIGhlaWdodCwgLSBkZXB0aCwgd2lkdGhTZWdtZW50cywgaGVpZ2h0U2VnbWVudHMsIDUgKTsgLy8gbnpcclxuXHJcblx0XHQvLyBidWlsZCBnZW9tZXRyeVxyXG5cclxuXHRcdHRoaXMuc2V0SW5kZXgoIGluZGljZXMgKTtcclxuXHRcdHRoaXMuc2V0QXR0cmlidXRlKCAncG9zaXRpb24nLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggdmVydGljZXMsIDMgKSApO1xyXG5cdFx0dGhpcy5zZXRBdHRyaWJ1dGUoICdub3JtYWwnLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggbm9ybWFscywgMyApICk7XHJcblx0XHR0aGlzLnNldEF0dHJpYnV0ZSggJ3V2JywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIHV2cywgMiApICk7XHJcblxyXG5cdFx0ZnVuY3Rpb24gYnVpbGRQbGFuZSggdSwgdiwgdywgdWRpciwgdmRpciwgd2lkdGgsIGhlaWdodCwgZGVwdGgsIGdyaWRYLCBncmlkWSwgbWF0ZXJpYWxJbmRleCApIHtcclxuXHJcblx0XHRcdGNvbnN0IHNlZ21lbnRXaWR0aCA9IHdpZHRoIC8gZ3JpZFg7XHJcblx0XHRcdGNvbnN0IHNlZ21lbnRIZWlnaHQgPSBoZWlnaHQgLyBncmlkWTtcclxuXHJcblx0XHRcdGNvbnN0IHdpZHRoSGFsZiA9IHdpZHRoIC8gMjtcclxuXHRcdFx0Y29uc3QgaGVpZ2h0SGFsZiA9IGhlaWdodCAvIDI7XHJcblx0XHRcdGNvbnN0IGRlcHRoSGFsZiA9IGRlcHRoIC8gMjtcclxuXHJcblx0XHRcdGNvbnN0IGdyaWRYMSA9IGdyaWRYICsgMTtcclxuXHRcdFx0Y29uc3QgZ3JpZFkxID0gZ3JpZFkgKyAxO1xyXG5cclxuXHRcdFx0bGV0IHZlcnRleENvdW50ZXIgPSAwO1xyXG5cdFx0XHRsZXQgZ3JvdXBDb3VudCA9IDA7XHJcblxyXG5cdFx0XHRjb25zdCB2ZWN0b3IgPSBuZXcgVmVjdG9yMygpO1xyXG5cclxuXHRcdFx0Ly8gZ2VuZXJhdGUgdmVydGljZXMsIG5vcm1hbHMgYW5kIHV2c1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGl5ID0gMDsgaXkgPCBncmlkWTE7IGl5ICsrICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCB5ID0gaXkgKiBzZWdtZW50SGVpZ2h0IC0gaGVpZ2h0SGFsZjtcclxuXHJcblx0XHRcdFx0Zm9yICggbGV0IGl4ID0gMDsgaXggPCBncmlkWDE7IGl4ICsrICkge1xyXG5cclxuXHRcdFx0XHRcdGNvbnN0IHggPSBpeCAqIHNlZ21lbnRXaWR0aCAtIHdpZHRoSGFsZjtcclxuXHJcblx0XHRcdFx0XHQvLyBzZXQgdmFsdWVzIHRvIGNvcnJlY3QgdmVjdG9yIGNvbXBvbmVudFxyXG5cclxuXHRcdFx0XHRcdHZlY3RvclsgdSBdID0geCAqIHVkaXI7XHJcblx0XHRcdFx0XHR2ZWN0b3JbIHYgXSA9IHkgKiB2ZGlyO1xyXG5cdFx0XHRcdFx0dmVjdG9yWyB3IF0gPSBkZXB0aEhhbGY7XHJcblxyXG5cdFx0XHRcdFx0Ly8gbm93IGFwcGx5IHZlY3RvciB0byB2ZXJ0ZXggYnVmZmVyXHJcblxyXG5cdFx0XHRcdFx0dmVydGljZXMucHVzaCggdmVjdG9yLngsIHZlY3Rvci55LCB2ZWN0b3IueiApO1xyXG5cclxuXHRcdFx0XHRcdC8vIHNldCB2YWx1ZXMgdG8gY29ycmVjdCB2ZWN0b3IgY29tcG9uZW50XHJcblxyXG5cdFx0XHRcdFx0dmVjdG9yWyB1IF0gPSAwO1xyXG5cdFx0XHRcdFx0dmVjdG9yWyB2IF0gPSAwO1xyXG5cdFx0XHRcdFx0dmVjdG9yWyB3IF0gPSBkZXB0aCA+IDAgPyAxIDogLSAxO1xyXG5cclxuXHRcdFx0XHRcdC8vIG5vdyBhcHBseSB2ZWN0b3IgdG8gbm9ybWFsIGJ1ZmZlclxyXG5cclxuXHRcdFx0XHRcdG5vcm1hbHMucHVzaCggdmVjdG9yLngsIHZlY3Rvci55LCB2ZWN0b3IueiApO1xyXG5cclxuXHRcdFx0XHRcdC8vIHV2c1xyXG5cclxuXHRcdFx0XHRcdHV2cy5wdXNoKCBpeCAvIGdyaWRYICk7XHJcblx0XHRcdFx0XHR1dnMucHVzaCggMSAtICggaXkgLyBncmlkWSApICk7XHJcblxyXG5cdFx0XHRcdFx0Ly8gY291bnRlcnNcclxuXHJcblx0XHRcdFx0XHR2ZXJ0ZXhDb3VudGVyICs9IDE7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdC8vIGluZGljZXNcclxuXHJcblx0XHRcdC8vIDEuIHlvdSBuZWVkIHRocmVlIGluZGljZXMgdG8gZHJhdyBhIHNpbmdsZSBmYWNlXHJcblx0XHRcdC8vIDIuIGEgc2luZ2xlIHNlZ21lbnQgY29uc2lzdHMgb2YgdHdvIGZhY2VzXHJcblx0XHRcdC8vIDMuIHNvIHdlIG5lZWQgdG8gZ2VuZXJhdGUgc2l4ICgyKjMpIGluZGljZXMgcGVyIHNlZ21lbnRcclxuXHJcblx0XHRcdGZvciAoIGxldCBpeSA9IDA7IGl5IDwgZ3JpZFk7IGl5ICsrICkge1xyXG5cclxuXHRcdFx0XHRmb3IgKCBsZXQgaXggPSAwOyBpeCA8IGdyaWRYOyBpeCArKyApIHtcclxuXHJcblx0XHRcdFx0XHRjb25zdCBhID0gbnVtYmVyT2ZWZXJ0aWNlcyArIGl4ICsgZ3JpZFgxICogaXk7XHJcblx0XHRcdFx0XHRjb25zdCBiID0gbnVtYmVyT2ZWZXJ0aWNlcyArIGl4ICsgZ3JpZFgxICogKCBpeSArIDEgKTtcclxuXHRcdFx0XHRcdGNvbnN0IGMgPSBudW1iZXJPZlZlcnRpY2VzICsgKCBpeCArIDEgKSArIGdyaWRYMSAqICggaXkgKyAxICk7XHJcblx0XHRcdFx0XHRjb25zdCBkID0gbnVtYmVyT2ZWZXJ0aWNlcyArICggaXggKyAxICkgKyBncmlkWDEgKiBpeTtcclxuXHJcblx0XHRcdFx0XHQvLyBmYWNlc1xyXG5cclxuXHRcdFx0XHRcdGluZGljZXMucHVzaCggYSwgYiwgZCApO1xyXG5cdFx0XHRcdFx0aW5kaWNlcy5wdXNoKCBiLCBjLCBkICk7XHJcblxyXG5cdFx0XHRcdFx0Ly8gaW5jcmVhc2UgY291bnRlclxyXG5cclxuXHRcdFx0XHRcdGdyb3VwQ291bnQgKz0gNjtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Ly8gYWRkIGEgZ3JvdXAgdG8gdGhlIGdlb21ldHJ5LiB0aGlzIHdpbGwgZW5zdXJlIG11bHRpIG1hdGVyaWFsIHN1cHBvcnRcclxuXHJcblx0XHRcdHNjb3BlLmFkZEdyb3VwKCBncm91cFN0YXJ0LCBncm91cENvdW50LCBtYXRlcmlhbEluZGV4ICk7XHJcblxyXG5cdFx0XHQvLyBjYWxjdWxhdGUgbmV3IHN0YXJ0IHZhbHVlIGZvciBncm91cHNcclxuXHJcblx0XHRcdGdyb3VwU3RhcnQgKz0gZ3JvdXBDb3VudDtcclxuXHJcblx0XHRcdC8vIHVwZGF0ZSB0b3RhbCBudW1iZXIgb2YgdmVydGljZXNcclxuXHJcblx0XHRcdG51bWJlck9mVmVydGljZXMgKz0gdmVydGV4Q291bnRlcjtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xyXG5cclxuXHRcdHRoaXMucGFyYW1ldGVycyA9IE9iamVjdC5hc3NpZ24oIHt9LCBzb3VyY2UucGFyYW1ldGVycyApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHN0YXRpYyBmcm9tSlNPTiggZGF0YSApIHtcclxuXHJcblx0XHRyZXR1cm4gbmV3IEJveEdlb21ldHJ5KCBkYXRhLndpZHRoLCBkYXRhLmhlaWdodCwgZGF0YS5kZXB0aCwgZGF0YS53aWR0aFNlZ21lbnRzLCBkYXRhLmhlaWdodFNlZ21lbnRzLCBkYXRhLmRlcHRoU2VnbWVudHMgKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgQm94R2VvbWV0cnkgfTtcclxuIiwiaW1wb3J0IHsgQ29sb3JNYW5hZ2VtZW50IH0gZnJvbSAnLi4vLi4vbWF0aC9Db2xvck1hbmFnZW1lbnQuanMnO1xyXG5cclxuLyoqXHJcbiAqIFVuaWZvcm0gVXRpbGl0aWVzXHJcbiAqL1xyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIGNsb25lVW5pZm9ybXMoIHNyYyApIHtcclxuXHJcblx0Y29uc3QgZHN0ID0ge307XHJcblxyXG5cdGZvciAoIGNvbnN0IHUgaW4gc3JjICkge1xyXG5cclxuXHRcdGRzdFsgdSBdID0ge307XHJcblxyXG5cdFx0Zm9yICggY29uc3QgcCBpbiBzcmNbIHUgXSApIHtcclxuXHJcblx0XHRcdGNvbnN0IHByb3BlcnR5ID0gc3JjWyB1IF1bIHAgXTtcclxuXHJcblx0XHRcdGlmICggcHJvcGVydHkgJiYgKCBwcm9wZXJ0eS5pc0NvbG9yIHx8XHJcblx0XHRcdFx0cHJvcGVydHkuaXNNYXRyaXgzIHx8IHByb3BlcnR5LmlzTWF0cml4NCB8fFxyXG5cdFx0XHRcdHByb3BlcnR5LmlzVmVjdG9yMiB8fCBwcm9wZXJ0eS5pc1ZlY3RvcjMgfHwgcHJvcGVydHkuaXNWZWN0b3I0IHx8XHJcblx0XHRcdFx0cHJvcGVydHkuaXNUZXh0dXJlIHx8IHByb3BlcnR5LmlzUXVhdGVybmlvbiApICkge1xyXG5cclxuXHRcdFx0XHRpZiAoIHByb3BlcnR5LmlzUmVuZGVyVGFyZ2V0VGV4dHVyZSApIHtcclxuXHJcblx0XHRcdFx0XHRjb25zb2xlLndhcm4oICdVbmlmb3Jtc1V0aWxzOiBUZXh0dXJlcyBvZiByZW5kZXIgdGFyZ2V0cyBjYW5ub3QgYmUgY2xvbmVkIHZpYSBjbG9uZVVuaWZvcm1zKCkgb3IgbWVyZ2VVbmlmb3JtcygpLicgKTtcclxuXHRcdFx0XHRcdGRzdFsgdSBdWyBwIF0gPSBudWxsO1xyXG5cclxuXHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdGRzdFsgdSBdWyBwIF0gPSBwcm9wZXJ0eS5jbG9uZSgpO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9IGVsc2UgaWYgKCBBcnJheS5pc0FycmF5KCBwcm9wZXJ0eSApICkge1xyXG5cclxuXHRcdFx0XHRkc3RbIHUgXVsgcCBdID0gcHJvcGVydHkuc2xpY2UoKTtcclxuXHJcblx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdGRzdFsgdSBdWyBwIF0gPSBwcm9wZXJ0eTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0cmV0dXJuIGRzdDtcclxuXHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBtZXJnZVVuaWZvcm1zKCB1bmlmb3JtcyApIHtcclxuXHJcblx0Y29uc3QgbWVyZ2VkID0ge307XHJcblxyXG5cdGZvciAoIGxldCB1ID0gMDsgdSA8IHVuaWZvcm1zLmxlbmd0aDsgdSArKyApIHtcclxuXHJcblx0XHRjb25zdCB0bXAgPSBjbG9uZVVuaWZvcm1zKCB1bmlmb3Jtc1sgdSBdICk7XHJcblxyXG5cdFx0Zm9yICggY29uc3QgcCBpbiB0bXAgKSB7XHJcblxyXG5cdFx0XHRtZXJnZWRbIHAgXSA9IHRtcFsgcCBdO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4gbWVyZ2VkO1xyXG5cclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIGNsb25lVW5pZm9ybXNHcm91cHMoIHNyYyApIHtcclxuXHJcblx0Y29uc3QgZHN0ID0gW107XHJcblxyXG5cdGZvciAoIGxldCB1ID0gMDsgdSA8IHNyYy5sZW5ndGg7IHUgKysgKSB7XHJcblxyXG5cdFx0ZHN0LnB1c2goIHNyY1sgdSBdLmNsb25lKCkgKTtcclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4gZHN0O1xyXG5cclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIGdldFVubGl0VW5pZm9ybUNvbG9yU3BhY2UoIHJlbmRlcmVyICkge1xyXG5cclxuXHRpZiAoIHJlbmRlcmVyLmdldFJlbmRlclRhcmdldCgpID09PSBudWxsICkge1xyXG5cclxuXHRcdC8vIGh0dHBzOi8vZ2l0aHViLmNvbS9tcmRvb2IvdGhyZWUuanMvcHVsbC8yMzkzNyNpc3N1ZWNvbW1lbnQtMTExMTA2NzM5OFxyXG5cdFx0cmV0dXJuIHJlbmRlcmVyLm91dHB1dENvbG9yU3BhY2U7XHJcblxyXG5cdH1cclxuXHJcblx0cmV0dXJuIENvbG9yTWFuYWdlbWVudC53b3JraW5nQ29sb3JTcGFjZTtcclxuXHJcbn1cclxuXHJcbi8vIExlZ2FjeVxyXG5cclxuY29uc3QgVW5pZm9ybXNVdGlscyA9IHsgY2xvbmU6IGNsb25lVW5pZm9ybXMsIG1lcmdlOiBtZXJnZVVuaWZvcm1zIH07XHJcblxyXG5leHBvcnQgeyBVbmlmb3Jtc1V0aWxzIH07XHJcbiIsImV4cG9ydCBkZWZhdWx0IC8qIGdsc2wgKi9gXHJcbnZvaWQgbWFpbigpIHtcclxuXHRnbF9Qb3NpdGlvbiA9IHByb2plY3Rpb25NYXRyaXggKiBtb2RlbFZpZXdNYXRyaXggKiB2ZWM0KCBwb3NpdGlvbiwgMS4wICk7XHJcbn1cclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2Bcclxudm9pZCBtYWluKCkge1xyXG5cdGdsX0ZyYWdDb2xvciA9IHZlYzQoIDEuMCwgMC4wLCAwLjAsIDEuMCApO1xyXG59XHJcbmA7XHJcbiIsImltcG9ydCB7IE1hdGVyaWFsIH0gZnJvbSAnLi9NYXRlcmlhbC5qcyc7XHJcbmltcG9ydCB7IGNsb25lVW5pZm9ybXMsIGNsb25lVW5pZm9ybXNHcm91cHMgfSBmcm9tICcuLi9yZW5kZXJlcnMvc2hhZGVycy9Vbmlmb3Jtc1V0aWxzLmpzJztcclxuXHJcbmltcG9ydCBkZWZhdWx0X3ZlcnRleCBmcm9tICcuLi9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9kZWZhdWx0X3ZlcnRleC5nbHNsLmpzJztcclxuaW1wb3J0IGRlZmF1bHRfZnJhZ21lbnQgZnJvbSAnLi4vcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvZGVmYXVsdF9mcmFnbWVudC5nbHNsLmpzJztcclxuXHJcbmNsYXNzIFNoYWRlck1hdGVyaWFsIGV4dGVuZHMgTWF0ZXJpYWwge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggcGFyYW1ldGVycyApIHtcclxuXHJcblx0XHRzdXBlcigpO1xyXG5cclxuXHRcdHRoaXMuaXNTaGFkZXJNYXRlcmlhbCA9IHRydWU7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ1NoYWRlck1hdGVyaWFsJztcclxuXHJcblx0XHR0aGlzLmRlZmluZXMgPSB7fTtcclxuXHRcdHRoaXMudW5pZm9ybXMgPSB7fTtcclxuXHRcdHRoaXMudW5pZm9ybXNHcm91cHMgPSBbXTtcclxuXHJcblx0XHR0aGlzLnZlcnRleFNoYWRlciA9IGRlZmF1bHRfdmVydGV4O1xyXG5cdFx0dGhpcy5mcmFnbWVudFNoYWRlciA9IGRlZmF1bHRfZnJhZ21lbnQ7XHJcblxyXG5cdFx0dGhpcy5saW5ld2lkdGggPSAxO1xyXG5cclxuXHRcdHRoaXMud2lyZWZyYW1lID0gZmFsc2U7XHJcblx0XHR0aGlzLndpcmVmcmFtZUxpbmV3aWR0aCA9IDE7XHJcblxyXG5cdFx0dGhpcy5mb2cgPSBmYWxzZTsgLy8gc2V0IHRvIHVzZSBzY2VuZSBmb2dcclxuXHRcdHRoaXMubGlnaHRzID0gZmFsc2U7IC8vIHNldCB0byB1c2Ugc2NlbmUgbGlnaHRzXHJcblx0XHR0aGlzLmNsaXBwaW5nID0gZmFsc2U7IC8vIHNldCB0byB1c2UgdXNlci1kZWZpbmVkIGNsaXBwaW5nIHBsYW5lc1xyXG5cclxuXHRcdHRoaXMuZm9yY2VTaW5nbGVQYXNzID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLmV4dGVuc2lvbnMgPSB7XHJcblx0XHRcdGRlcml2YXRpdmVzOiBmYWxzZSwgLy8gc2V0IHRvIHVzZSBkZXJpdmF0aXZlc1xyXG5cdFx0XHRmcmFnRGVwdGg6IGZhbHNlLCAvLyBzZXQgdG8gdXNlIGZyYWdtZW50IGRlcHRoIHZhbHVlc1xyXG5cdFx0XHRkcmF3QnVmZmVyczogZmFsc2UsIC8vIHNldCB0byB1c2UgZHJhdyBidWZmZXJzXHJcblx0XHRcdHNoYWRlclRleHR1cmVMT0Q6IGZhbHNlLCAvLyBzZXQgdG8gdXNlIHNoYWRlciB0ZXh0dXJlIExPRFxyXG5cdFx0XHRjbGlwQ3VsbERpc3RhbmNlOiBmYWxzZSwgLy8gc2V0IHRvIHVzZSB2ZXJ0ZXggc2hhZGVyIGNsaXBwaW5nXHJcblx0XHRcdG11bHRpRHJhdzogZmFsc2UgLy8gc2V0IHRvIHVzZSB2ZXJ0ZXggc2hhZGVyIG11bHRpX2RyYXcgLyBlbmFibGUgZ2xfRHJhd0lEXHJcblx0XHR9O1xyXG5cclxuXHRcdC8vIFdoZW4gcmVuZGVyZWQgZ2VvbWV0cnkgZG9lc24ndCBpbmNsdWRlIHRoZXNlIGF0dHJpYnV0ZXMgYnV0IHRoZSBtYXRlcmlhbCBkb2VzLFxyXG5cdFx0Ly8gdXNlIHRoZXNlIGRlZmF1bHQgdmFsdWVzIGluIFdlYkdMLiBUaGlzIGF2b2lkcyBlcnJvcnMgd2hlbiBidWZmZXIgZGF0YSBpcyBtaXNzaW5nLlxyXG5cdFx0dGhpcy5kZWZhdWx0QXR0cmlidXRlVmFsdWVzID0ge1xyXG5cdFx0XHQnY29sb3InOiBbIDEsIDEsIDEgXSxcclxuXHRcdFx0J3V2JzogWyAwLCAwIF0sXHJcblx0XHRcdCd1djEnOiBbIDAsIDAgXVxyXG5cdFx0fTtcclxuXHJcblx0XHR0aGlzLmluZGV4MEF0dHJpYnV0ZU5hbWUgPSB1bmRlZmluZWQ7XHJcblx0XHR0aGlzLnVuaWZvcm1zTmVlZFVwZGF0ZSA9IGZhbHNlO1xyXG5cclxuXHRcdHRoaXMuZ2xzbFZlcnNpb24gPSBudWxsO1xyXG5cclxuXHRcdGlmICggcGFyYW1ldGVycyAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0dGhpcy5zZXRWYWx1ZXMoIHBhcmFtZXRlcnMgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xyXG5cclxuXHRcdHRoaXMuZnJhZ21lbnRTaGFkZXIgPSBzb3VyY2UuZnJhZ21lbnRTaGFkZXI7XHJcblx0XHR0aGlzLnZlcnRleFNoYWRlciA9IHNvdXJjZS52ZXJ0ZXhTaGFkZXI7XHJcblxyXG5cdFx0dGhpcy51bmlmb3JtcyA9IGNsb25lVW5pZm9ybXMoIHNvdXJjZS51bmlmb3JtcyApO1xyXG5cdFx0dGhpcy51bmlmb3Jtc0dyb3VwcyA9IGNsb25lVW5pZm9ybXNHcm91cHMoIHNvdXJjZS51bmlmb3Jtc0dyb3VwcyApO1xyXG5cclxuXHRcdHRoaXMuZGVmaW5lcyA9IE9iamVjdC5hc3NpZ24oIHt9LCBzb3VyY2UuZGVmaW5lcyApO1xyXG5cclxuXHRcdHRoaXMud2lyZWZyYW1lID0gc291cmNlLndpcmVmcmFtZTtcclxuXHRcdHRoaXMud2lyZWZyYW1lTGluZXdpZHRoID0gc291cmNlLndpcmVmcmFtZUxpbmV3aWR0aDtcclxuXHJcblx0XHR0aGlzLmZvZyA9IHNvdXJjZS5mb2c7XHJcblx0XHR0aGlzLmxpZ2h0cyA9IHNvdXJjZS5saWdodHM7XHJcblx0XHR0aGlzLmNsaXBwaW5nID0gc291cmNlLmNsaXBwaW5nO1xyXG5cclxuXHRcdHRoaXMuZXh0ZW5zaW9ucyA9IE9iamVjdC5hc3NpZ24oIHt9LCBzb3VyY2UuZXh0ZW5zaW9ucyApO1xyXG5cclxuXHRcdHRoaXMuZ2xzbFZlcnNpb24gPSBzb3VyY2UuZ2xzbFZlcnNpb247XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0dG9KU09OKCBtZXRhICkge1xyXG5cclxuXHRcdGNvbnN0IGRhdGEgPSBzdXBlci50b0pTT04oIG1ldGEgKTtcclxuXHJcblx0XHRkYXRhLmdsc2xWZXJzaW9uID0gdGhpcy5nbHNsVmVyc2lvbjtcclxuXHRcdGRhdGEudW5pZm9ybXMgPSB7fTtcclxuXHJcblx0XHRmb3IgKCBjb25zdCBuYW1lIGluIHRoaXMudW5pZm9ybXMgKSB7XHJcblxyXG5cdFx0XHRjb25zdCB1bmlmb3JtID0gdGhpcy51bmlmb3Jtc1sgbmFtZSBdO1xyXG5cdFx0XHRjb25zdCB2YWx1ZSA9IHVuaWZvcm0udmFsdWU7XHJcblxyXG5cdFx0XHRpZiAoIHZhbHVlICYmIHZhbHVlLmlzVGV4dHVyZSApIHtcclxuXHJcblx0XHRcdFx0ZGF0YS51bmlmb3Jtc1sgbmFtZSBdID0ge1xyXG5cdFx0XHRcdFx0dHlwZTogJ3QnLFxyXG5cdFx0XHRcdFx0dmFsdWU6IHZhbHVlLnRvSlNPTiggbWV0YSApLnV1aWRcclxuXHRcdFx0XHR9O1xyXG5cclxuXHRcdFx0fSBlbHNlIGlmICggdmFsdWUgJiYgdmFsdWUuaXNDb2xvciApIHtcclxuXHJcblx0XHRcdFx0ZGF0YS51bmlmb3Jtc1sgbmFtZSBdID0ge1xyXG5cdFx0XHRcdFx0dHlwZTogJ2MnLFxyXG5cdFx0XHRcdFx0dmFsdWU6IHZhbHVlLmdldEhleCgpXHJcblx0XHRcdFx0fTtcclxuXHJcblx0XHRcdH0gZWxzZSBpZiAoIHZhbHVlICYmIHZhbHVlLmlzVmVjdG9yMiApIHtcclxuXHJcblx0XHRcdFx0ZGF0YS51bmlmb3Jtc1sgbmFtZSBdID0ge1xyXG5cdFx0XHRcdFx0dHlwZTogJ3YyJyxcclxuXHRcdFx0XHRcdHZhbHVlOiB2YWx1ZS50b0FycmF5KClcclxuXHRcdFx0XHR9O1xyXG5cclxuXHRcdFx0fSBlbHNlIGlmICggdmFsdWUgJiYgdmFsdWUuaXNWZWN0b3IzICkge1xyXG5cclxuXHRcdFx0XHRkYXRhLnVuaWZvcm1zWyBuYW1lIF0gPSB7XHJcblx0XHRcdFx0XHR0eXBlOiAndjMnLFxyXG5cdFx0XHRcdFx0dmFsdWU6IHZhbHVlLnRvQXJyYXkoKVxyXG5cdFx0XHRcdH07XHJcblxyXG5cdFx0XHR9IGVsc2UgaWYgKCB2YWx1ZSAmJiB2YWx1ZS5pc1ZlY3RvcjQgKSB7XHJcblxyXG5cdFx0XHRcdGRhdGEudW5pZm9ybXNbIG5hbWUgXSA9IHtcclxuXHRcdFx0XHRcdHR5cGU6ICd2NCcsXHJcblx0XHRcdFx0XHR2YWx1ZTogdmFsdWUudG9BcnJheSgpXHJcblx0XHRcdFx0fTtcclxuXHJcblx0XHRcdH0gZWxzZSBpZiAoIHZhbHVlICYmIHZhbHVlLmlzTWF0cml4MyApIHtcclxuXHJcblx0XHRcdFx0ZGF0YS51bmlmb3Jtc1sgbmFtZSBdID0ge1xyXG5cdFx0XHRcdFx0dHlwZTogJ20zJyxcclxuXHRcdFx0XHRcdHZhbHVlOiB2YWx1ZS50b0FycmF5KClcclxuXHRcdFx0XHR9O1xyXG5cclxuXHRcdFx0fSBlbHNlIGlmICggdmFsdWUgJiYgdmFsdWUuaXNNYXRyaXg0ICkge1xyXG5cclxuXHRcdFx0XHRkYXRhLnVuaWZvcm1zWyBuYW1lIF0gPSB7XHJcblx0XHRcdFx0XHR0eXBlOiAnbTQnLFxyXG5cdFx0XHRcdFx0dmFsdWU6IHZhbHVlLnRvQXJyYXkoKVxyXG5cdFx0XHRcdH07XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRkYXRhLnVuaWZvcm1zWyBuYW1lIF0gPSB7XHJcblx0XHRcdFx0XHR2YWx1ZTogdmFsdWVcclxuXHRcdFx0XHR9O1xyXG5cclxuXHRcdFx0XHQvLyBub3RlOiB0aGUgYXJyYXkgdmFyaWFudHMgdjJ2LCB2M3YsIHY0diwgbTR2IGFuZCB0diBhcmUgbm90IHN1cHBvcnRlZCBzbyBmYXJcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBPYmplY3Qua2V5cyggdGhpcy5kZWZpbmVzICkubGVuZ3RoID4gMCApIGRhdGEuZGVmaW5lcyA9IHRoaXMuZGVmaW5lcztcclxuXHJcblx0XHRkYXRhLnZlcnRleFNoYWRlciA9IHRoaXMudmVydGV4U2hhZGVyO1xyXG5cdFx0ZGF0YS5mcmFnbWVudFNoYWRlciA9IHRoaXMuZnJhZ21lbnRTaGFkZXI7XHJcblxyXG5cdFx0ZGF0YS5saWdodHMgPSB0aGlzLmxpZ2h0cztcclxuXHRcdGRhdGEuY2xpcHBpbmcgPSB0aGlzLmNsaXBwaW5nO1xyXG5cclxuXHRcdGNvbnN0IGV4dGVuc2lvbnMgPSB7fTtcclxuXHJcblx0XHRmb3IgKCBjb25zdCBrZXkgaW4gdGhpcy5leHRlbnNpb25zICkge1xyXG5cclxuXHRcdFx0aWYgKCB0aGlzLmV4dGVuc2lvbnNbIGtleSBdID09PSB0cnVlICkgZXh0ZW5zaW9uc1sga2V5IF0gPSB0cnVlO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIE9iamVjdC5rZXlzKCBleHRlbnNpb25zICkubGVuZ3RoID4gMCApIGRhdGEuZXh0ZW5zaW9ucyA9IGV4dGVuc2lvbnM7XHJcblxyXG5cdFx0cmV0dXJuIGRhdGE7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IFNoYWRlck1hdGVyaWFsIH07XHJcbiIsImltcG9ydCB7IFdlYkdMQ29vcmRpbmF0ZVN5c3RlbSB9IGZyb20gJy4uL2NvbnN0YW50cy5qcyc7XHJcbmltcG9ydCB7IE1hdHJpeDQgfSBmcm9tICcuLi9tYXRoL01hdHJpeDQuanMnO1xyXG5pbXBvcnQgeyBPYmplY3QzRCB9IGZyb20gJy4uL2NvcmUvT2JqZWN0M0QuanMnO1xyXG5cclxuY2xhc3MgQ2FtZXJhIGV4dGVuZHMgT2JqZWN0M0Qge1xyXG5cclxuXHRjb25zdHJ1Y3RvcigpIHtcclxuXHJcblx0XHRzdXBlcigpO1xyXG5cclxuXHRcdHRoaXMuaXNDYW1lcmEgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMudHlwZSA9ICdDYW1lcmEnO1xyXG5cclxuXHRcdHRoaXMubWF0cml4V29ybGRJbnZlcnNlID0gbmV3IE1hdHJpeDQoKTtcclxuXHJcblx0XHR0aGlzLnByb2plY3Rpb25NYXRyaXggPSBuZXcgTWF0cml4NCgpO1xyXG5cdFx0dGhpcy5wcm9qZWN0aW9uTWF0cml4SW52ZXJzZSA9IG5ldyBNYXRyaXg0KCk7XHJcblxyXG5cdFx0dGhpcy5jb29yZGluYXRlU3lzdGVtID0gV2ViR0xDb29yZGluYXRlU3lzdGVtO1xyXG5cclxuXHR9XHJcblxyXG5cdGNvcHkoIHNvdXJjZSwgcmVjdXJzaXZlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSwgcmVjdXJzaXZlICk7XHJcblxyXG5cdFx0dGhpcy5tYXRyaXhXb3JsZEludmVyc2UuY29weSggc291cmNlLm1hdHJpeFdvcmxkSW52ZXJzZSApO1xyXG5cclxuXHRcdHRoaXMucHJvamVjdGlvbk1hdHJpeC5jb3B5KCBzb3VyY2UucHJvamVjdGlvbk1hdHJpeCApO1xyXG5cdFx0dGhpcy5wcm9qZWN0aW9uTWF0cml4SW52ZXJzZS5jb3B5KCBzb3VyY2UucHJvamVjdGlvbk1hdHJpeEludmVyc2UgKTtcclxuXHJcblx0XHR0aGlzLmNvb3JkaW5hdGVTeXN0ZW0gPSBzb3VyY2UuY29vcmRpbmF0ZVN5c3RlbTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRnZXRXb3JsZERpcmVjdGlvbiggdGFyZ2V0ICkge1xyXG5cclxuXHRcdHJldHVybiBzdXBlci5nZXRXb3JsZERpcmVjdGlvbiggdGFyZ2V0ICkubmVnYXRlKCk7XHJcblxyXG5cdH1cclxuXHJcblx0dXBkYXRlTWF0cml4V29ybGQoIGZvcmNlICkge1xyXG5cclxuXHRcdHN1cGVyLnVwZGF0ZU1hdHJpeFdvcmxkKCBmb3JjZSApO1xyXG5cclxuXHRcdHRoaXMubWF0cml4V29ybGRJbnZlcnNlLmNvcHkoIHRoaXMubWF0cml4V29ybGQgKS5pbnZlcnQoKTtcclxuXHJcblx0fVxyXG5cclxuXHR1cGRhdGVXb3JsZE1hdHJpeCggdXBkYXRlUGFyZW50cywgdXBkYXRlQ2hpbGRyZW4gKSB7XHJcblxyXG5cdFx0c3VwZXIudXBkYXRlV29ybGRNYXRyaXgoIHVwZGF0ZVBhcmVudHMsIHVwZGF0ZUNoaWxkcmVuICk7XHJcblxyXG5cdFx0dGhpcy5tYXRyaXhXb3JsZEludmVyc2UuY29weSggdGhpcy5tYXRyaXhXb3JsZCApLmludmVydCgpO1xyXG5cclxuXHR9XHJcblxyXG5cdGNsb25lKCkge1xyXG5cclxuXHRcdHJldHVybiBuZXcgdGhpcy5jb25zdHJ1Y3RvcigpLmNvcHkoIHRoaXMgKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgQ2FtZXJhIH07XHJcbiIsImltcG9ydCB7IENhbWVyYSB9IGZyb20gJy4vQ2FtZXJhLmpzJztcclxuaW1wb3J0ICogYXMgTWF0aFV0aWxzIGZyb20gJy4uL21hdGgvTWF0aFV0aWxzLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yMiB9IGZyb20gJy4uL21hdGgvVmVjdG9yMi5qcyc7XHJcbmltcG9ydCB7IFZlY3RvcjMgfSBmcm9tICcuLi9tYXRoL1ZlY3RvcjMuanMnO1xyXG5cclxuY29uc3QgX3YzID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5jb25zdCBfbWluVGFyZ2V0ID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMigpO1xyXG5jb25zdCBfbWF4VGFyZ2V0ID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMigpO1xyXG5cclxuXHJcbmNsYXNzIFBlcnNwZWN0aXZlQ2FtZXJhIGV4dGVuZHMgQ2FtZXJhIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIGZvdiA9IDUwLCBhc3BlY3QgPSAxLCBuZWFyID0gMC4xLCBmYXIgPSAyMDAwICkge1xyXG5cclxuXHRcdHN1cGVyKCk7XHJcblxyXG5cdFx0dGhpcy5pc1BlcnNwZWN0aXZlQ2FtZXJhID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSAnUGVyc3BlY3RpdmVDYW1lcmEnO1xyXG5cclxuXHRcdHRoaXMuZm92ID0gZm92O1xyXG5cdFx0dGhpcy56b29tID0gMTtcclxuXHJcblx0XHR0aGlzLm5lYXIgPSBuZWFyO1xyXG5cdFx0dGhpcy5mYXIgPSBmYXI7XHJcblx0XHR0aGlzLmZvY3VzID0gMTA7XHJcblxyXG5cdFx0dGhpcy5hc3BlY3QgPSBhc3BlY3Q7XHJcblx0XHR0aGlzLnZpZXcgPSBudWxsO1xyXG5cclxuXHRcdHRoaXMuZmlsbUdhdWdlID0gMzU7XHQvLyB3aWR0aCBvZiB0aGUgZmlsbSAoZGVmYXVsdCBpbiBtaWxsaW1ldGVycylcclxuXHRcdHRoaXMuZmlsbU9mZnNldCA9IDA7XHQvLyBob3Jpem9udGFsIGZpbG0gb2Zmc2V0IChzYW1lIHVuaXQgYXMgZ2F1Z2UpXHJcblxyXG5cdFx0dGhpcy51cGRhdGVQcm9qZWN0aW9uTWF0cml4KCk7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlLCByZWN1cnNpdmUgKSB7XHJcblxyXG5cdFx0c3VwZXIuY29weSggc291cmNlLCByZWN1cnNpdmUgKTtcclxuXHJcblx0XHR0aGlzLmZvdiA9IHNvdXJjZS5mb3Y7XHJcblx0XHR0aGlzLnpvb20gPSBzb3VyY2Uuem9vbTtcclxuXHJcblx0XHR0aGlzLm5lYXIgPSBzb3VyY2UubmVhcjtcclxuXHRcdHRoaXMuZmFyID0gc291cmNlLmZhcjtcclxuXHRcdHRoaXMuZm9jdXMgPSBzb3VyY2UuZm9jdXM7XHJcblxyXG5cdFx0dGhpcy5hc3BlY3QgPSBzb3VyY2UuYXNwZWN0O1xyXG5cdFx0dGhpcy52aWV3ID0gc291cmNlLnZpZXcgPT09IG51bGwgPyBudWxsIDogT2JqZWN0LmFzc2lnbigge30sIHNvdXJjZS52aWV3ICk7XHJcblxyXG5cdFx0dGhpcy5maWxtR2F1Z2UgPSBzb3VyY2UuZmlsbUdhdWdlO1xyXG5cdFx0dGhpcy5maWxtT2Zmc2V0ID0gc291cmNlLmZpbG1PZmZzZXQ7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0LyoqXHJcblx0ICogU2V0cyB0aGUgRk9WIGJ5IGZvY2FsIGxlbmd0aCBpbiByZXNwZWN0IHRvIHRoZSBjdXJyZW50IC5maWxtR2F1Z2UuXHJcblx0ICpcclxuXHQgKiBUaGUgZGVmYXVsdCBmaWxtIGdhdWdlIGlzIDM1LCBzbyB0aGF0IHRoZSBmb2NhbCBsZW5ndGggY2FuIGJlIHNwZWNpZmllZCBmb3JcclxuXHQgKiBhIDM1bW0gKGZ1bGwgZnJhbWUpIGNhbWVyYS5cclxuXHQgKlxyXG5cdCAqIFZhbHVlcyBmb3IgZm9jYWwgbGVuZ3RoIGFuZCBmaWxtIGdhdWdlIG11c3QgaGF2ZSB0aGUgc2FtZSB1bml0LlxyXG5cdCAqL1xyXG5cdHNldEZvY2FsTGVuZ3RoKCBmb2NhbExlbmd0aCApIHtcclxuXHJcblx0XHQvKiogc2VlIHtAbGluayBodHRwOi8vd3d3LmJvYmF0a2lucy5jb20vcGhvdG9ncmFwaHkvdGVjaG5pY2FsL2ZpZWxkX29mX3ZpZXcuaHRtbH0gKi9cclxuXHRcdGNvbnN0IHZFeHRlbnRTbG9wZSA9IDAuNSAqIHRoaXMuZ2V0RmlsbUhlaWdodCgpIC8gZm9jYWxMZW5ndGg7XHJcblxyXG5cdFx0dGhpcy5mb3YgPSBNYXRoVXRpbHMuUkFEMkRFRyAqIDIgKiBNYXRoLmF0YW4oIHZFeHRlbnRTbG9wZSApO1xyXG5cdFx0dGhpcy51cGRhdGVQcm9qZWN0aW9uTWF0cml4KCk7XHJcblxyXG5cdH1cclxuXHJcblx0LyoqXHJcblx0ICogQ2FsY3VsYXRlcyB0aGUgZm9jYWwgbGVuZ3RoIGZyb20gdGhlIGN1cnJlbnQgLmZvdiBhbmQgLmZpbG1HYXVnZS5cclxuXHQgKi9cclxuXHRnZXRGb2NhbExlbmd0aCgpIHtcclxuXHJcblx0XHRjb25zdCB2RXh0ZW50U2xvcGUgPSBNYXRoLnRhbiggTWF0aFV0aWxzLkRFRzJSQUQgKiAwLjUgKiB0aGlzLmZvdiApO1xyXG5cclxuXHRcdHJldHVybiAwLjUgKiB0aGlzLmdldEZpbG1IZWlnaHQoKSAvIHZFeHRlbnRTbG9wZTtcclxuXHJcblx0fVxyXG5cclxuXHRnZXRFZmZlY3RpdmVGT1YoKSB7XHJcblxyXG5cdFx0cmV0dXJuIE1hdGhVdGlscy5SQUQyREVHICogMiAqIE1hdGguYXRhbihcclxuXHRcdFx0TWF0aC50YW4oIE1hdGhVdGlscy5ERUcyUkFEICogMC41ICogdGhpcy5mb3YgKSAvIHRoaXMuem9vbSApO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldEZpbG1XaWR0aCgpIHtcclxuXHJcblx0XHQvLyBmaWxtIG5vdCBjb21wbGV0ZWx5IGNvdmVyZWQgaW4gcG9ydHJhaXQgZm9ybWF0IChhc3BlY3QgPCAxKVxyXG5cdFx0cmV0dXJuIHRoaXMuZmlsbUdhdWdlICogTWF0aC5taW4oIHRoaXMuYXNwZWN0LCAxICk7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0RmlsbUhlaWdodCgpIHtcclxuXHJcblx0XHQvLyBmaWxtIG5vdCBjb21wbGV0ZWx5IGNvdmVyZWQgaW4gbGFuZHNjYXBlIGZvcm1hdCAoYXNwZWN0ID4gMSlcclxuXHRcdHJldHVybiB0aGlzLmZpbG1HYXVnZSAvIE1hdGgubWF4KCB0aGlzLmFzcGVjdCwgMSApO1xyXG5cclxuXHR9XHJcblxyXG5cdC8qKlxyXG5cdCAqIENvbXB1dGVzIHRoZSAyRCBib3VuZHMgb2YgdGhlIGNhbWVyYSdzIHZpZXdhYmxlIHJlY3RhbmdsZSBhdCBhIGdpdmVuIGRpc3RhbmNlIGFsb25nIHRoZSB2aWV3aW5nIGRpcmVjdGlvbi5cclxuXHQgKiBTZXRzIG1pblRhcmdldCBhbmQgbWF4VGFyZ2V0IHRvIHRoZSBjb29yZGluYXRlcyBvZiB0aGUgbG93ZXItbGVmdCBhbmQgdXBwZXItcmlnaHQgY29ybmVycyBvZiB0aGUgdmlldyByZWN0YW5nbGUuXHJcblx0ICovXHJcblx0Z2V0Vmlld0JvdW5kcyggZGlzdGFuY2UsIG1pblRhcmdldCwgbWF4VGFyZ2V0ICkge1xyXG5cclxuXHRcdF92My5zZXQoIC0gMSwgLSAxLCAwLjUgKS5hcHBseU1hdHJpeDQoIHRoaXMucHJvamVjdGlvbk1hdHJpeEludmVyc2UgKTtcclxuXHJcblx0XHRtaW5UYXJnZXQuc2V0KCBfdjMueCwgX3YzLnkgKS5tdWx0aXBseVNjYWxhciggLSBkaXN0YW5jZSAvIF92My56ICk7XHJcblxyXG5cdFx0X3YzLnNldCggMSwgMSwgMC41ICkuYXBwbHlNYXRyaXg0KCB0aGlzLnByb2plY3Rpb25NYXRyaXhJbnZlcnNlICk7XHJcblxyXG5cdFx0bWF4VGFyZ2V0LnNldCggX3YzLngsIF92My55ICkubXVsdGlwbHlTY2FsYXIoIC0gZGlzdGFuY2UgLyBfdjMueiApO1xyXG5cclxuXHR9XHJcblxyXG5cdC8qKlxyXG5cdCAqIENvbXB1dGVzIHRoZSB3aWR0aCBhbmQgaGVpZ2h0IG9mIHRoZSBjYW1lcmEncyB2aWV3YWJsZSByZWN0YW5nbGUgYXQgYSBnaXZlbiBkaXN0YW5jZSBhbG9uZyB0aGUgdmlld2luZyBkaXJlY3Rpb24uXHJcblx0ICogQ29waWVzIHRoZSByZXN1bHQgaW50byB0aGUgdGFyZ2V0IFZlY3RvcjIsIHdoZXJlIHggaXMgd2lkdGggYW5kIHkgaXMgaGVpZ2h0LlxyXG5cdCAqL1xyXG5cdGdldFZpZXdTaXplKCBkaXN0YW5jZSwgdGFyZ2V0ICkge1xyXG5cclxuXHRcdHRoaXMuZ2V0Vmlld0JvdW5kcyggZGlzdGFuY2UsIF9taW5UYXJnZXQsIF9tYXhUYXJnZXQgKTtcclxuXHJcblx0XHRyZXR1cm4gdGFyZ2V0LnN1YlZlY3RvcnMoIF9tYXhUYXJnZXQsIF9taW5UYXJnZXQgKTtcclxuXHJcblx0fVxyXG5cclxuXHQvKipcclxuXHQgKiBTZXRzIGFuIG9mZnNldCBpbiBhIGxhcmdlciBmcnVzdHVtLiBUaGlzIGlzIHVzZWZ1bCBmb3IgbXVsdGktd2luZG93IG9yXHJcblx0ICogbXVsdGktbW9uaXRvci9tdWx0aS1tYWNoaW5lIHNldHVwcy5cclxuXHQgKlxyXG5cdCAqIEZvciBleGFtcGxlLCBpZiB5b3UgaGF2ZSAzeDIgbW9uaXRvcnMgYW5kIGVhY2ggbW9uaXRvciBpcyAxOTIweDEwODAgYW5kXHJcblx0ICogdGhlIG1vbml0b3JzIGFyZSBpbiBncmlkIGxpa2UgdGhpc1xyXG5cdCAqXHJcblx0ICogICArLS0tKy0tLSstLS0rXHJcblx0ICogICB8IEEgfCBCIHwgQyB8XHJcblx0ICogICArLS0tKy0tLSstLS0rXHJcblx0ICogICB8IEQgfCBFIHwgRiB8XHJcblx0ICogICArLS0tKy0tLSstLS0rXHJcblx0ICpcclxuXHQgKiB0aGVuIGZvciBlYWNoIG1vbml0b3IgeW91IHdvdWxkIGNhbGwgaXQgbGlrZSB0aGlzXHJcblx0ICpcclxuXHQgKiAgIGNvbnN0IHcgPSAxOTIwO1xyXG5cdCAqICAgY29uc3QgaCA9IDEwODA7XHJcblx0ICogICBjb25zdCBmdWxsV2lkdGggPSB3ICogMztcclxuXHQgKiAgIGNvbnN0IGZ1bGxIZWlnaHQgPSBoICogMjtcclxuXHQgKlxyXG5cdCAqICAgLS1BLS1cclxuXHQgKiAgIGNhbWVyYS5zZXRWaWV3T2Zmc2V0KCBmdWxsV2lkdGgsIGZ1bGxIZWlnaHQsIHcgKiAwLCBoICogMCwgdywgaCApO1xyXG5cdCAqICAgLS1CLS1cclxuXHQgKiAgIGNhbWVyYS5zZXRWaWV3T2Zmc2V0KCBmdWxsV2lkdGgsIGZ1bGxIZWlnaHQsIHcgKiAxLCBoICogMCwgdywgaCApO1xyXG5cdCAqICAgLS1DLS1cclxuXHQgKiAgIGNhbWVyYS5zZXRWaWV3T2Zmc2V0KCBmdWxsV2lkdGgsIGZ1bGxIZWlnaHQsIHcgKiAyLCBoICogMCwgdywgaCApO1xyXG5cdCAqICAgLS1ELS1cclxuXHQgKiAgIGNhbWVyYS5zZXRWaWV3T2Zmc2V0KCBmdWxsV2lkdGgsIGZ1bGxIZWlnaHQsIHcgKiAwLCBoICogMSwgdywgaCApO1xyXG5cdCAqICAgLS1FLS1cclxuXHQgKiAgIGNhbWVyYS5zZXRWaWV3T2Zmc2V0KCBmdWxsV2lkdGgsIGZ1bGxIZWlnaHQsIHcgKiAxLCBoICogMSwgdywgaCApO1xyXG5cdCAqICAgLS1GLS1cclxuXHQgKiAgIGNhbWVyYS5zZXRWaWV3T2Zmc2V0KCBmdWxsV2lkdGgsIGZ1bGxIZWlnaHQsIHcgKiAyLCBoICogMSwgdywgaCApO1xyXG5cdCAqXHJcblx0ICogICBOb3RlIHRoZXJlIGlzIG5vIHJlYXNvbiBtb25pdG9ycyBoYXZlIHRvIGJlIHRoZSBzYW1lIHNpemUgb3IgaW4gYSBncmlkLlxyXG5cdCAqL1xyXG5cdHNldFZpZXdPZmZzZXQoIGZ1bGxXaWR0aCwgZnVsbEhlaWdodCwgeCwgeSwgd2lkdGgsIGhlaWdodCApIHtcclxuXHJcblx0XHR0aGlzLmFzcGVjdCA9IGZ1bGxXaWR0aCAvIGZ1bGxIZWlnaHQ7XHJcblxyXG5cdFx0aWYgKCB0aGlzLnZpZXcgPT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHR0aGlzLnZpZXcgPSB7XHJcblx0XHRcdFx0ZW5hYmxlZDogdHJ1ZSxcclxuXHRcdFx0XHRmdWxsV2lkdGg6IDEsXHJcblx0XHRcdFx0ZnVsbEhlaWdodDogMSxcclxuXHRcdFx0XHRvZmZzZXRYOiAwLFxyXG5cdFx0XHRcdG9mZnNldFk6IDAsXHJcblx0XHRcdFx0d2lkdGg6IDEsXHJcblx0XHRcdFx0aGVpZ2h0OiAxXHJcblx0XHRcdH07XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMudmlldy5lbmFibGVkID0gdHJ1ZTtcclxuXHRcdHRoaXMudmlldy5mdWxsV2lkdGggPSBmdWxsV2lkdGg7XHJcblx0XHR0aGlzLnZpZXcuZnVsbEhlaWdodCA9IGZ1bGxIZWlnaHQ7XHJcblx0XHR0aGlzLnZpZXcub2Zmc2V0WCA9IHg7XHJcblx0XHR0aGlzLnZpZXcub2Zmc2V0WSA9IHk7XHJcblx0XHR0aGlzLnZpZXcud2lkdGggPSB3aWR0aDtcclxuXHRcdHRoaXMudmlldy5oZWlnaHQgPSBoZWlnaHQ7XHJcblxyXG5cdFx0dGhpcy51cGRhdGVQcm9qZWN0aW9uTWF0cml4KCk7XHJcblxyXG5cdH1cclxuXHJcblx0Y2xlYXJWaWV3T2Zmc2V0KCkge1xyXG5cclxuXHRcdGlmICggdGhpcy52aWV3ICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0dGhpcy52aWV3LmVuYWJsZWQgPSBmYWxzZTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy51cGRhdGVQcm9qZWN0aW9uTWF0cml4KCk7XHJcblxyXG5cdH1cclxuXHJcblx0dXBkYXRlUHJvamVjdGlvbk1hdHJpeCgpIHtcclxuXHJcblx0XHRjb25zdCBuZWFyID0gdGhpcy5uZWFyO1xyXG5cdFx0bGV0IHRvcCA9IG5lYXIgKiBNYXRoLnRhbiggTWF0aFV0aWxzLkRFRzJSQUQgKiAwLjUgKiB0aGlzLmZvdiApIC8gdGhpcy56b29tO1xyXG5cdFx0bGV0IGhlaWdodCA9IDIgKiB0b3A7XHJcblx0XHRsZXQgd2lkdGggPSB0aGlzLmFzcGVjdCAqIGhlaWdodDtcclxuXHRcdGxldCBsZWZ0ID0gLSAwLjUgKiB3aWR0aDtcclxuXHRcdGNvbnN0IHZpZXcgPSB0aGlzLnZpZXc7XHJcblxyXG5cdFx0aWYgKCB0aGlzLnZpZXcgIT09IG51bGwgJiYgdGhpcy52aWV3LmVuYWJsZWQgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBmdWxsV2lkdGggPSB2aWV3LmZ1bGxXaWR0aCxcclxuXHRcdFx0XHRmdWxsSGVpZ2h0ID0gdmlldy5mdWxsSGVpZ2h0O1xyXG5cclxuXHRcdFx0bGVmdCArPSB2aWV3Lm9mZnNldFggKiB3aWR0aCAvIGZ1bGxXaWR0aDtcclxuXHRcdFx0dG9wIC09IHZpZXcub2Zmc2V0WSAqIGhlaWdodCAvIGZ1bGxIZWlnaHQ7XHJcblx0XHRcdHdpZHRoICo9IHZpZXcud2lkdGggLyBmdWxsV2lkdGg7XHJcblx0XHRcdGhlaWdodCAqPSB2aWV3LmhlaWdodCAvIGZ1bGxIZWlnaHQ7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGNvbnN0IHNrZXcgPSB0aGlzLmZpbG1PZmZzZXQ7XHJcblx0XHRpZiAoIHNrZXcgIT09IDAgKSBsZWZ0ICs9IG5lYXIgKiBza2V3IC8gdGhpcy5nZXRGaWxtV2lkdGgoKTtcclxuXHJcblx0XHR0aGlzLnByb2plY3Rpb25NYXRyaXgubWFrZVBlcnNwZWN0aXZlKCBsZWZ0LCBsZWZ0ICsgd2lkdGgsIHRvcCwgdG9wIC0gaGVpZ2h0LCBuZWFyLCB0aGlzLmZhciwgdGhpcy5jb29yZGluYXRlU3lzdGVtICk7XHJcblxyXG5cdFx0dGhpcy5wcm9qZWN0aW9uTWF0cml4SW52ZXJzZS5jb3B5KCB0aGlzLnByb2plY3Rpb25NYXRyaXggKS5pbnZlcnQoKTtcclxuXHJcblx0fVxyXG5cclxuXHR0b0pTT04oIG1ldGEgKSB7XHJcblxyXG5cdFx0Y29uc3QgZGF0YSA9IHN1cGVyLnRvSlNPTiggbWV0YSApO1xyXG5cclxuXHRcdGRhdGEub2JqZWN0LmZvdiA9IHRoaXMuZm92O1xyXG5cdFx0ZGF0YS5vYmplY3Quem9vbSA9IHRoaXMuem9vbTtcclxuXHJcblx0XHRkYXRhLm9iamVjdC5uZWFyID0gdGhpcy5uZWFyO1xyXG5cdFx0ZGF0YS5vYmplY3QuZmFyID0gdGhpcy5mYXI7XHJcblx0XHRkYXRhLm9iamVjdC5mb2N1cyA9IHRoaXMuZm9jdXM7XHJcblxyXG5cdFx0ZGF0YS5vYmplY3QuYXNwZWN0ID0gdGhpcy5hc3BlY3Q7XHJcblxyXG5cdFx0aWYgKCB0aGlzLnZpZXcgIT09IG51bGwgKSBkYXRhLm9iamVjdC52aWV3ID0gT2JqZWN0LmFzc2lnbigge30sIHRoaXMudmlldyApO1xyXG5cclxuXHRcdGRhdGEub2JqZWN0LmZpbG1HYXVnZSA9IHRoaXMuZmlsbUdhdWdlO1xyXG5cdFx0ZGF0YS5vYmplY3QuZmlsbU9mZnNldCA9IHRoaXMuZmlsbU9mZnNldDtcclxuXHJcblx0XHRyZXR1cm4gZGF0YTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgUGVyc3BlY3RpdmVDYW1lcmEgfTtcclxuIiwiaW1wb3J0IHsgV2ViR0xDb29yZGluYXRlU3lzdGVtLCBXZWJHUFVDb29yZGluYXRlU3lzdGVtIH0gZnJvbSAnLi4vY29uc3RhbnRzLmpzJztcclxuaW1wb3J0IHsgT2JqZWN0M0QgfSBmcm9tICcuLi9jb3JlL09iamVjdDNELmpzJztcclxuaW1wb3J0IHsgUGVyc3BlY3RpdmVDYW1lcmEgfSBmcm9tICcuL1BlcnNwZWN0aXZlQ2FtZXJhLmpzJztcclxuXHJcbmNvbnN0IGZvdiA9IC0gOTA7IC8vIG5lZ2F0aXZlIGZvdiBpcyBub3QgYW4gZXJyb3JcclxuY29uc3QgYXNwZWN0ID0gMTtcclxuXHJcbmNsYXNzIEN1YmVDYW1lcmEgZXh0ZW5kcyBPYmplY3QzRCB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBuZWFyLCBmYXIsIHJlbmRlclRhcmdldCApIHtcclxuXHJcblx0XHRzdXBlcigpO1xyXG5cclxuXHRcdHRoaXMudHlwZSA9ICdDdWJlQ2FtZXJhJztcclxuXHJcblx0XHR0aGlzLnJlbmRlclRhcmdldCA9IHJlbmRlclRhcmdldDtcclxuXHRcdHRoaXMuY29vcmRpbmF0ZVN5c3RlbSA9IG51bGw7XHJcblx0XHR0aGlzLmFjdGl2ZU1pcG1hcExldmVsID0gMDtcclxuXHJcblx0XHRjb25zdCBjYW1lcmFQWCA9IG5ldyBQZXJzcGVjdGl2ZUNhbWVyYSggZm92LCBhc3BlY3QsIG5lYXIsIGZhciApO1xyXG5cdFx0Y2FtZXJhUFgubGF5ZXJzID0gdGhpcy5sYXllcnM7XHJcblx0XHR0aGlzLmFkZCggY2FtZXJhUFggKTtcclxuXHJcblx0XHRjb25zdCBjYW1lcmFOWCA9IG5ldyBQZXJzcGVjdGl2ZUNhbWVyYSggZm92LCBhc3BlY3QsIG5lYXIsIGZhciApO1xyXG5cdFx0Y2FtZXJhTlgubGF5ZXJzID0gdGhpcy5sYXllcnM7XHJcblx0XHR0aGlzLmFkZCggY2FtZXJhTlggKTtcclxuXHJcblx0XHRjb25zdCBjYW1lcmFQWSA9IG5ldyBQZXJzcGVjdGl2ZUNhbWVyYSggZm92LCBhc3BlY3QsIG5lYXIsIGZhciApO1xyXG5cdFx0Y2FtZXJhUFkubGF5ZXJzID0gdGhpcy5sYXllcnM7XHJcblx0XHR0aGlzLmFkZCggY2FtZXJhUFkgKTtcclxuXHJcblx0XHRjb25zdCBjYW1lcmFOWSA9IG5ldyBQZXJzcGVjdGl2ZUNhbWVyYSggZm92LCBhc3BlY3QsIG5lYXIsIGZhciApO1xyXG5cdFx0Y2FtZXJhTlkubGF5ZXJzID0gdGhpcy5sYXllcnM7XHJcblx0XHR0aGlzLmFkZCggY2FtZXJhTlkgKTtcclxuXHJcblx0XHRjb25zdCBjYW1lcmFQWiA9IG5ldyBQZXJzcGVjdGl2ZUNhbWVyYSggZm92LCBhc3BlY3QsIG5lYXIsIGZhciApO1xyXG5cdFx0Y2FtZXJhUFoubGF5ZXJzID0gdGhpcy5sYXllcnM7XHJcblx0XHR0aGlzLmFkZCggY2FtZXJhUFogKTtcclxuXHJcblx0XHRjb25zdCBjYW1lcmFOWiA9IG5ldyBQZXJzcGVjdGl2ZUNhbWVyYSggZm92LCBhc3BlY3QsIG5lYXIsIGZhciApO1xyXG5cdFx0Y2FtZXJhTloubGF5ZXJzID0gdGhpcy5sYXllcnM7XHJcblx0XHR0aGlzLmFkZCggY2FtZXJhTlogKTtcclxuXHJcblx0fVxyXG5cclxuXHR1cGRhdGVDb29yZGluYXRlU3lzdGVtKCkge1xyXG5cclxuXHRcdGNvbnN0IGNvb3JkaW5hdGVTeXN0ZW0gPSB0aGlzLmNvb3JkaW5hdGVTeXN0ZW07XHJcblxyXG5cdFx0Y29uc3QgY2FtZXJhcyA9IHRoaXMuY2hpbGRyZW4uY29uY2F0KCk7XHJcblxyXG5cdFx0Y29uc3QgWyBjYW1lcmFQWCwgY2FtZXJhTlgsIGNhbWVyYVBZLCBjYW1lcmFOWSwgY2FtZXJhUFosIGNhbWVyYU5aIF0gPSBjYW1lcmFzO1xyXG5cclxuXHRcdGZvciAoIGNvbnN0IGNhbWVyYSBvZiBjYW1lcmFzICkgdGhpcy5yZW1vdmUoIGNhbWVyYSApO1xyXG5cclxuXHRcdGlmICggY29vcmRpbmF0ZVN5c3RlbSA9PT0gV2ViR0xDb29yZGluYXRlU3lzdGVtICkge1xyXG5cclxuXHRcdFx0Y2FtZXJhUFgudXAuc2V0KCAwLCAxLCAwICk7XHJcblx0XHRcdGNhbWVyYVBYLmxvb2tBdCggMSwgMCwgMCApO1xyXG5cclxuXHRcdFx0Y2FtZXJhTlgudXAuc2V0KCAwLCAxLCAwICk7XHJcblx0XHRcdGNhbWVyYU5YLmxvb2tBdCggLSAxLCAwLCAwICk7XHJcblxyXG5cdFx0XHRjYW1lcmFQWS51cC5zZXQoIDAsIDAsIC0gMSApO1xyXG5cdFx0XHRjYW1lcmFQWS5sb29rQXQoIDAsIDEsIDAgKTtcclxuXHJcblx0XHRcdGNhbWVyYU5ZLnVwLnNldCggMCwgMCwgMSApO1xyXG5cdFx0XHRjYW1lcmFOWS5sb29rQXQoIDAsIC0gMSwgMCApO1xyXG5cclxuXHRcdFx0Y2FtZXJhUFoudXAuc2V0KCAwLCAxLCAwICk7XHJcblx0XHRcdGNhbWVyYVBaLmxvb2tBdCggMCwgMCwgMSApO1xyXG5cclxuXHRcdFx0Y2FtZXJhTloudXAuc2V0KCAwLCAxLCAwICk7XHJcblx0XHRcdGNhbWVyYU5aLmxvb2tBdCggMCwgMCwgLSAxICk7XHJcblxyXG5cdFx0fSBlbHNlIGlmICggY29vcmRpbmF0ZVN5c3RlbSA9PT0gV2ViR1BVQ29vcmRpbmF0ZVN5c3RlbSApIHtcclxuXHJcblx0XHRcdGNhbWVyYVBYLnVwLnNldCggMCwgLSAxLCAwICk7XHJcblx0XHRcdGNhbWVyYVBYLmxvb2tBdCggLSAxLCAwLCAwICk7XHJcblxyXG5cdFx0XHRjYW1lcmFOWC51cC5zZXQoIDAsIC0gMSwgMCApO1xyXG5cdFx0XHRjYW1lcmFOWC5sb29rQXQoIDEsIDAsIDAgKTtcclxuXHJcblx0XHRcdGNhbWVyYVBZLnVwLnNldCggMCwgMCwgMSApO1xyXG5cdFx0XHRjYW1lcmFQWS5sb29rQXQoIDAsIDEsIDAgKTtcclxuXHJcblx0XHRcdGNhbWVyYU5ZLnVwLnNldCggMCwgMCwgLSAxICk7XHJcblx0XHRcdGNhbWVyYU5ZLmxvb2tBdCggMCwgLSAxLCAwICk7XHJcblxyXG5cdFx0XHRjYW1lcmFQWi51cC5zZXQoIDAsIC0gMSwgMCApO1xyXG5cdFx0XHRjYW1lcmFQWi5sb29rQXQoIDAsIDAsIDEgKTtcclxuXHJcblx0XHRcdGNhbWVyYU5aLnVwLnNldCggMCwgLSAxLCAwICk7XHJcblx0XHRcdGNhbWVyYU5aLmxvb2tBdCggMCwgMCwgLSAxICk7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdHRocm93IG5ldyBFcnJvciggJ1RIUkVFLkN1YmVDYW1lcmEudXBkYXRlQ29vcmRpbmF0ZVN5c3RlbSgpOiBJbnZhbGlkIGNvb3JkaW5hdGUgc3lzdGVtOiAnICsgY29vcmRpbmF0ZVN5c3RlbSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRmb3IgKCBjb25zdCBjYW1lcmEgb2YgY2FtZXJhcyApIHtcclxuXHJcblx0XHRcdHRoaXMuYWRkKCBjYW1lcmEgKTtcclxuXHJcblx0XHRcdGNhbWVyYS51cGRhdGVNYXRyaXhXb3JsZCgpO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHR1cGRhdGUoIHJlbmRlcmVyLCBzY2VuZSApIHtcclxuXHJcblx0XHRpZiAoIHRoaXMucGFyZW50ID09PSBudWxsICkgdGhpcy51cGRhdGVNYXRyaXhXb3JsZCgpO1xyXG5cclxuXHRcdGNvbnN0IHsgcmVuZGVyVGFyZ2V0LCBhY3RpdmVNaXBtYXBMZXZlbCB9ID0gdGhpcztcclxuXHJcblx0XHRpZiAoIHRoaXMuY29vcmRpbmF0ZVN5c3RlbSAhPT0gcmVuZGVyZXIuY29vcmRpbmF0ZVN5c3RlbSApIHtcclxuXHJcblx0XHRcdHRoaXMuY29vcmRpbmF0ZVN5c3RlbSA9IHJlbmRlcmVyLmNvb3JkaW5hdGVTeXN0ZW07XHJcblxyXG5cdFx0XHR0aGlzLnVwZGF0ZUNvb3JkaW5hdGVTeXN0ZW0oKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Y29uc3QgWyBjYW1lcmFQWCwgY2FtZXJhTlgsIGNhbWVyYVBZLCBjYW1lcmFOWSwgY2FtZXJhUFosIGNhbWVyYU5aIF0gPSB0aGlzLmNoaWxkcmVuO1xyXG5cclxuXHRcdGNvbnN0IGN1cnJlbnRSZW5kZXJUYXJnZXQgPSByZW5kZXJlci5nZXRSZW5kZXJUYXJnZXQoKTtcclxuXHRcdGNvbnN0IGN1cnJlbnRBY3RpdmVDdWJlRmFjZSA9IHJlbmRlcmVyLmdldEFjdGl2ZUN1YmVGYWNlKCk7XHJcblx0XHRjb25zdCBjdXJyZW50QWN0aXZlTWlwbWFwTGV2ZWwgPSByZW5kZXJlci5nZXRBY3RpdmVNaXBtYXBMZXZlbCgpO1xyXG5cclxuXHRcdGNvbnN0IGN1cnJlbnRYckVuYWJsZWQgPSByZW5kZXJlci54ci5lbmFibGVkO1xyXG5cclxuXHRcdHJlbmRlcmVyLnhyLmVuYWJsZWQgPSBmYWxzZTtcclxuXHJcblx0XHRjb25zdCBnZW5lcmF0ZU1pcG1hcHMgPSByZW5kZXJUYXJnZXQudGV4dHVyZS5nZW5lcmF0ZU1pcG1hcHM7XHJcblxyXG5cdFx0cmVuZGVyVGFyZ2V0LnRleHR1cmUuZ2VuZXJhdGVNaXBtYXBzID0gZmFsc2U7XHJcblxyXG5cdFx0cmVuZGVyZXIuc2V0UmVuZGVyVGFyZ2V0KCByZW5kZXJUYXJnZXQsIDAsIGFjdGl2ZU1pcG1hcExldmVsICk7XHJcblx0XHRyZW5kZXJlci5yZW5kZXIoIHNjZW5lLCBjYW1lcmFQWCApO1xyXG5cclxuXHRcdHJlbmRlcmVyLnNldFJlbmRlclRhcmdldCggcmVuZGVyVGFyZ2V0LCAxLCBhY3RpdmVNaXBtYXBMZXZlbCApO1xyXG5cdFx0cmVuZGVyZXIucmVuZGVyKCBzY2VuZSwgY2FtZXJhTlggKTtcclxuXHJcblx0XHRyZW5kZXJlci5zZXRSZW5kZXJUYXJnZXQoIHJlbmRlclRhcmdldCwgMiwgYWN0aXZlTWlwbWFwTGV2ZWwgKTtcclxuXHRcdHJlbmRlcmVyLnJlbmRlciggc2NlbmUsIGNhbWVyYVBZICk7XHJcblxyXG5cdFx0cmVuZGVyZXIuc2V0UmVuZGVyVGFyZ2V0KCByZW5kZXJUYXJnZXQsIDMsIGFjdGl2ZU1pcG1hcExldmVsICk7XHJcblx0XHRyZW5kZXJlci5yZW5kZXIoIHNjZW5lLCBjYW1lcmFOWSApO1xyXG5cclxuXHRcdHJlbmRlcmVyLnNldFJlbmRlclRhcmdldCggcmVuZGVyVGFyZ2V0LCA0LCBhY3RpdmVNaXBtYXBMZXZlbCApO1xyXG5cdFx0cmVuZGVyZXIucmVuZGVyKCBzY2VuZSwgY2FtZXJhUFogKTtcclxuXHJcblx0XHQvLyBtaXBtYXBzIGFyZSBnZW5lcmF0ZWQgZHVyaW5nIHRoZSBsYXN0IGNhbGwgb2YgcmVuZGVyKClcclxuXHRcdC8vIGF0IHRoaXMgcG9pbnQsIGFsbCBzaWRlcyBvZiB0aGUgY3ViZSByZW5kZXIgdGFyZ2V0IGFyZSBkZWZpbmVkXHJcblxyXG5cdFx0cmVuZGVyVGFyZ2V0LnRleHR1cmUuZ2VuZXJhdGVNaXBtYXBzID0gZ2VuZXJhdGVNaXBtYXBzO1xyXG5cclxuXHRcdHJlbmRlcmVyLnNldFJlbmRlclRhcmdldCggcmVuZGVyVGFyZ2V0LCA1LCBhY3RpdmVNaXBtYXBMZXZlbCApO1xyXG5cdFx0cmVuZGVyZXIucmVuZGVyKCBzY2VuZSwgY2FtZXJhTlogKTtcclxuXHJcblx0XHRyZW5kZXJlci5zZXRSZW5kZXJUYXJnZXQoIGN1cnJlbnRSZW5kZXJUYXJnZXQsIGN1cnJlbnRBY3RpdmVDdWJlRmFjZSwgY3VycmVudEFjdGl2ZU1pcG1hcExldmVsICk7XHJcblxyXG5cdFx0cmVuZGVyZXIueHIuZW5hYmxlZCA9IGN1cnJlbnRYckVuYWJsZWQ7XHJcblxyXG5cdFx0cmVuZGVyVGFyZ2V0LnRleHR1cmUubmVlZHNQTVJFTVVwZGF0ZSA9IHRydWU7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IEN1YmVDYW1lcmEgfTtcclxuIiwiaW1wb3J0IHsgVGV4dHVyZSB9IGZyb20gJy4vVGV4dHVyZS5qcyc7XHJcbmltcG9ydCB7IEN1YmVSZWZsZWN0aW9uTWFwcGluZyB9IGZyb20gJy4uL2NvbnN0YW50cy5qcyc7XHJcblxyXG5jbGFzcyBDdWJlVGV4dHVyZSBleHRlbmRzIFRleHR1cmUge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggaW1hZ2VzLCBtYXBwaW5nLCB3cmFwUywgd3JhcFQsIG1hZ0ZpbHRlciwgbWluRmlsdGVyLCBmb3JtYXQsIHR5cGUsIGFuaXNvdHJvcHksIGNvbG9yU3BhY2UgKSB7XHJcblxyXG5cdFx0aW1hZ2VzID0gaW1hZ2VzICE9PSB1bmRlZmluZWQgPyBpbWFnZXMgOiBbXTtcclxuXHRcdG1hcHBpbmcgPSBtYXBwaW5nICE9PSB1bmRlZmluZWQgPyBtYXBwaW5nIDogQ3ViZVJlZmxlY3Rpb25NYXBwaW5nO1xyXG5cclxuXHRcdHN1cGVyKCBpbWFnZXMsIG1hcHBpbmcsIHdyYXBTLCB3cmFwVCwgbWFnRmlsdGVyLCBtaW5GaWx0ZXIsIGZvcm1hdCwgdHlwZSwgYW5pc290cm9weSwgY29sb3JTcGFjZSApO1xyXG5cclxuXHRcdHRoaXMuaXNDdWJlVGV4dHVyZSA9IHRydWU7XHJcblxyXG5cdFx0dGhpcy5mbGlwWSA9IGZhbHNlO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldCBpbWFnZXMoKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuaW1hZ2U7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0IGltYWdlcyggdmFsdWUgKSB7XHJcblxyXG5cdFx0dGhpcy5pbWFnZSA9IHZhbHVlO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBDdWJlVGV4dHVyZSB9O1xyXG4iLCJpbXBvcnQgeyBCYWNrU2lkZSwgTGluZWFyRmlsdGVyLCBMaW5lYXJNaXBtYXBMaW5lYXJGaWx0ZXIsIE5vQmxlbmRpbmcgfSBmcm9tICcuLi9jb25zdGFudHMuanMnO1xyXG5pbXBvcnQgeyBNZXNoIH0gZnJvbSAnLi4vb2JqZWN0cy9NZXNoLmpzJztcclxuaW1wb3J0IHsgQm94R2VvbWV0cnkgfSBmcm9tICcuLi9nZW9tZXRyaWVzL0JveEdlb21ldHJ5LmpzJztcclxuaW1wb3J0IHsgU2hhZGVyTWF0ZXJpYWwgfSBmcm9tICcuLi9tYXRlcmlhbHMvU2hhZGVyTWF0ZXJpYWwuanMnO1xyXG5pbXBvcnQgeyBjbG9uZVVuaWZvcm1zIH0gZnJvbSAnLi9zaGFkZXJzL1VuaWZvcm1zVXRpbHMuanMnO1xyXG5pbXBvcnQgeyBXZWJHTFJlbmRlclRhcmdldCB9IGZyb20gJy4vV2ViR0xSZW5kZXJUYXJnZXQuanMnO1xyXG5pbXBvcnQgeyBDdWJlQ2FtZXJhIH0gZnJvbSAnLi4vY2FtZXJhcy9DdWJlQ2FtZXJhLmpzJztcclxuaW1wb3J0IHsgQ3ViZVRleHR1cmUgfSBmcm9tICcuLi90ZXh0dXJlcy9DdWJlVGV4dHVyZS5qcyc7XHJcblxyXG5jbGFzcyBXZWJHTEN1YmVSZW5kZXJUYXJnZXQgZXh0ZW5kcyBXZWJHTFJlbmRlclRhcmdldCB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBzaXplID0gMSwgb3B0aW9ucyA9IHt9ICkge1xyXG5cclxuXHRcdHN1cGVyKCBzaXplLCBzaXplLCBvcHRpb25zICk7XHJcblxyXG5cdFx0dGhpcy5pc1dlYkdMQ3ViZVJlbmRlclRhcmdldCA9IHRydWU7XHJcblxyXG5cdFx0Y29uc3QgaW1hZ2UgPSB7IHdpZHRoOiBzaXplLCBoZWlnaHQ6IHNpemUsIGRlcHRoOiAxIH07XHJcblx0XHRjb25zdCBpbWFnZXMgPSBbIGltYWdlLCBpbWFnZSwgaW1hZ2UsIGltYWdlLCBpbWFnZSwgaW1hZ2UgXTtcclxuXHJcblx0XHR0aGlzLnRleHR1cmUgPSBuZXcgQ3ViZVRleHR1cmUoIGltYWdlcywgb3B0aW9ucy5tYXBwaW5nLCBvcHRpb25zLndyYXBTLCBvcHRpb25zLndyYXBULCBvcHRpb25zLm1hZ0ZpbHRlciwgb3B0aW9ucy5taW5GaWx0ZXIsIG9wdGlvbnMuZm9ybWF0LCBvcHRpb25zLnR5cGUsIG9wdGlvbnMuYW5pc290cm9weSwgb3B0aW9ucy5jb2xvclNwYWNlICk7XHJcblxyXG5cdFx0Ly8gQnkgY29udmVudGlvbiAtLSBsaWtlbHkgYmFzZWQgb24gdGhlIFJlbmRlck1hbiBzcGVjIGZyb20gdGhlIDE5OTAncyAtLSBjdWJlIG1hcHMgYXJlIHNwZWNpZmllZCBieSBXZWJHTCAoYW5kIHRocmVlLmpzKVxyXG5cdFx0Ly8gaW4gYSBjb29yZGluYXRlIHN5c3RlbSBpbiB3aGljaCBwb3NpdGl2ZS14IGlzIHRvIHRoZSByaWdodCB3aGVuIGxvb2tpbmcgdXAgdGhlIHBvc2l0aXZlLXogYXhpcyAtLSBpbiBvdGhlciB3b3JkcyxcclxuXHRcdC8vIGluIGEgbGVmdC1oYW5kZWQgY29vcmRpbmF0ZSBzeXN0ZW0uIEJ5IGNvbnRpbnVpbmcgdGhpcyBjb252ZW50aW9uLCBwcmVleGlzdGluZyBjdWJlIG1hcHMgY29udGludWVkIHRvIHJlbmRlciBjb3JyZWN0bHkuXHJcblxyXG5cdFx0Ly8gdGhyZWUuanMgdXNlcyBhIHJpZ2h0LWhhbmRlZCBjb29yZGluYXRlIHN5c3RlbS4gU28gZW52aXJvbm1lbnQgbWFwcyB1c2VkIGluIHRocmVlLmpzIGFwcGVhciB0byBoYXZlIHB4IGFuZCBueCBzd2FwcGVkXHJcblx0XHQvLyBhbmQgdGhlIGZsYWcgaXNSZW5kZXJUYXJnZXRUZXh0dXJlIGNvbnRyb2xzIHRoaXMgY29udmVyc2lvbi4gVGhlIGZsaXAgaXMgbm90IHJlcXVpcmVkIHdoZW4gdXNpbmcgV2ViR0xDdWJlUmVuZGVyVGFyZ2V0LnRleHR1cmVcclxuXHRcdC8vIGFzIGEgY3ViZSB0ZXh0dXJlICh0aGlzIGlzIGRldGVjdGVkIHdoZW4gaXNSZW5kZXJUYXJnZXRUZXh0dXJlIGlzIHNldCB0byB0cnVlIGZvciBjdWJlIHRleHR1cmVzKS5cclxuXHJcblx0XHR0aGlzLnRleHR1cmUuaXNSZW5kZXJUYXJnZXRUZXh0dXJlID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLnRleHR1cmUuZ2VuZXJhdGVNaXBtYXBzID0gb3B0aW9ucy5nZW5lcmF0ZU1pcG1hcHMgIT09IHVuZGVmaW5lZCA/IG9wdGlvbnMuZ2VuZXJhdGVNaXBtYXBzIDogZmFsc2U7XHJcblx0XHR0aGlzLnRleHR1cmUubWluRmlsdGVyID0gb3B0aW9ucy5taW5GaWx0ZXIgIT09IHVuZGVmaW5lZCA/IG9wdGlvbnMubWluRmlsdGVyIDogTGluZWFyRmlsdGVyO1xyXG5cclxuXHR9XHJcblxyXG5cdGZyb21FcXVpcmVjdGFuZ3VsYXJUZXh0dXJlKCByZW5kZXJlciwgdGV4dHVyZSApIHtcclxuXHJcblx0XHR0aGlzLnRleHR1cmUudHlwZSA9IHRleHR1cmUudHlwZTtcclxuXHRcdHRoaXMudGV4dHVyZS5jb2xvclNwYWNlID0gdGV4dHVyZS5jb2xvclNwYWNlO1xyXG5cclxuXHRcdHRoaXMudGV4dHVyZS5nZW5lcmF0ZU1pcG1hcHMgPSB0ZXh0dXJlLmdlbmVyYXRlTWlwbWFwcztcclxuXHRcdHRoaXMudGV4dHVyZS5taW5GaWx0ZXIgPSB0ZXh0dXJlLm1pbkZpbHRlcjtcclxuXHRcdHRoaXMudGV4dHVyZS5tYWdGaWx0ZXIgPSB0ZXh0dXJlLm1hZ0ZpbHRlcjtcclxuXHJcblx0XHRjb25zdCBzaGFkZXIgPSB7XHJcblxyXG5cdFx0XHR1bmlmb3Jtczoge1xyXG5cdFx0XHRcdHRFcXVpcmVjdDogeyB2YWx1ZTogbnVsbCB9LFxyXG5cdFx0XHR9LFxyXG5cclxuXHRcdFx0dmVydGV4U2hhZGVyOiAvKiBnbHNsICovYFxyXG5cclxuXHRcdFx0XHR2YXJ5aW5nIHZlYzMgdldvcmxkRGlyZWN0aW9uO1xyXG5cclxuXHRcdFx0XHR2ZWMzIHRyYW5zZm9ybURpcmVjdGlvbiggaW4gdmVjMyBkaXIsIGluIG1hdDQgbWF0cml4ICkge1xyXG5cclxuXHRcdFx0XHRcdHJldHVybiBub3JtYWxpemUoICggbWF0cml4ICogdmVjNCggZGlyLCAwLjAgKSApLnh5eiApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdHZvaWQgbWFpbigpIHtcclxuXHJcblx0XHRcdFx0XHR2V29ybGREaXJlY3Rpb24gPSB0cmFuc2Zvcm1EaXJlY3Rpb24oIHBvc2l0aW9uLCBtb2RlbE1hdHJpeCApO1xyXG5cclxuXHRcdFx0XHRcdCNpbmNsdWRlIDxiZWdpbl92ZXJ0ZXg+XHJcblx0XHRcdFx0XHQjaW5jbHVkZSA8cHJvamVjdF92ZXJ0ZXg+XHJcblxyXG5cdFx0XHRcdH1cclxuXHRcdFx0YCxcclxuXHJcblx0XHRcdGZyYWdtZW50U2hhZGVyOiAvKiBnbHNsICovYFxyXG5cclxuXHRcdFx0XHR1bmlmb3JtIHNhbXBsZXIyRCB0RXF1aXJlY3Q7XHJcblxyXG5cdFx0XHRcdHZhcnlpbmcgdmVjMyB2V29ybGREaXJlY3Rpb247XHJcblxyXG5cdFx0XHRcdCNpbmNsdWRlIDxjb21tb24+XHJcblxyXG5cdFx0XHRcdHZvaWQgbWFpbigpIHtcclxuXHJcblx0XHRcdFx0XHR2ZWMzIGRpcmVjdGlvbiA9IG5vcm1hbGl6ZSggdldvcmxkRGlyZWN0aW9uICk7XHJcblxyXG5cdFx0XHRcdFx0dmVjMiBzYW1wbGVVViA9IGVxdWlyZWN0VXYoIGRpcmVjdGlvbiApO1xyXG5cclxuXHRcdFx0XHRcdGdsX0ZyYWdDb2xvciA9IHRleHR1cmUyRCggdEVxdWlyZWN0LCBzYW1wbGVVViApO1xyXG5cclxuXHRcdFx0XHR9XHJcblx0XHRcdGBcclxuXHRcdH07XHJcblxyXG5cdFx0Y29uc3QgZ2VvbWV0cnkgPSBuZXcgQm94R2VvbWV0cnkoIDUsIDUsIDUgKTtcclxuXHJcblx0XHRjb25zdCBtYXRlcmlhbCA9IG5ldyBTaGFkZXJNYXRlcmlhbCgge1xyXG5cclxuXHRcdFx0bmFtZTogJ0N1YmVtYXBGcm9tRXF1aXJlY3QnLFxyXG5cclxuXHRcdFx0dW5pZm9ybXM6IGNsb25lVW5pZm9ybXMoIHNoYWRlci51bmlmb3JtcyApLFxyXG5cdFx0XHR2ZXJ0ZXhTaGFkZXI6IHNoYWRlci52ZXJ0ZXhTaGFkZXIsXHJcblx0XHRcdGZyYWdtZW50U2hhZGVyOiBzaGFkZXIuZnJhZ21lbnRTaGFkZXIsXHJcblx0XHRcdHNpZGU6IEJhY2tTaWRlLFxyXG5cdFx0XHRibGVuZGluZzogTm9CbGVuZGluZ1xyXG5cclxuXHRcdH0gKTtcclxuXHJcblx0XHRtYXRlcmlhbC51bmlmb3Jtcy50RXF1aXJlY3QudmFsdWUgPSB0ZXh0dXJlO1xyXG5cclxuXHRcdGNvbnN0IG1lc2ggPSBuZXcgTWVzaCggZ2VvbWV0cnksIG1hdGVyaWFsICk7XHJcblxyXG5cdFx0Y29uc3QgY3VycmVudE1pbkZpbHRlciA9IHRleHR1cmUubWluRmlsdGVyO1xyXG5cclxuXHRcdC8vIEF2b2lkIGJsdXJyZWQgcG9sZXNcclxuXHRcdGlmICggdGV4dHVyZS5taW5GaWx0ZXIgPT09IExpbmVhck1pcG1hcExpbmVhckZpbHRlciApIHRleHR1cmUubWluRmlsdGVyID0gTGluZWFyRmlsdGVyO1xyXG5cclxuXHRcdGNvbnN0IGNhbWVyYSA9IG5ldyBDdWJlQ2FtZXJhKCAxLCAxMCwgdGhpcyApO1xyXG5cdFx0Y2FtZXJhLnVwZGF0ZSggcmVuZGVyZXIsIG1lc2ggKTtcclxuXHJcblx0XHR0ZXh0dXJlLm1pbkZpbHRlciA9IGN1cnJlbnRNaW5GaWx0ZXI7XHJcblxyXG5cdFx0bWVzaC5nZW9tZXRyeS5kaXNwb3NlKCk7XHJcblx0XHRtZXNoLm1hdGVyaWFsLmRpc3Bvc2UoKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRjbGVhciggcmVuZGVyZXIsIGNvbG9yLCBkZXB0aCwgc3RlbmNpbCApIHtcclxuXHJcblx0XHRjb25zdCBjdXJyZW50UmVuZGVyVGFyZ2V0ID0gcmVuZGVyZXIuZ2V0UmVuZGVyVGFyZ2V0KCk7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgNjsgaSArKyApIHtcclxuXHJcblx0XHRcdHJlbmRlcmVyLnNldFJlbmRlclRhcmdldCggdGhpcywgaSApO1xyXG5cclxuXHRcdFx0cmVuZGVyZXIuY2xlYXIoIGNvbG9yLCBkZXB0aCwgc3RlbmNpbCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZW5kZXJlci5zZXRSZW5kZXJUYXJnZXQoIGN1cnJlbnRSZW5kZXJUYXJnZXQgKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgV2ViR0xDdWJlUmVuZGVyVGFyZ2V0IH07XHJcbiIsImltcG9ydCB7IE1hdHJpeDMgfSBmcm9tICcuL01hdHJpeDMuanMnO1xyXG5pbXBvcnQgeyBWZWN0b3IzIH0gZnJvbSAnLi9WZWN0b3IzLmpzJztcclxuXHJcbmNvbnN0IF92ZWN0b3IxID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5jb25zdCBfdmVjdG9yMiA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuY29uc3QgX25vcm1hbE1hdHJpeCA9IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDMoKTtcclxuXHJcbmNsYXNzIFBsYW5lIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIG5vcm1hbCA9IG5ldyBWZWN0b3IzKCAxLCAwLCAwICksIGNvbnN0YW50ID0gMCApIHtcclxuXHJcblx0XHR0aGlzLmlzUGxhbmUgPSB0cnVlO1xyXG5cclxuXHRcdC8vIG5vcm1hbCBpcyBhc3N1bWVkIHRvIGJlIG5vcm1hbGl6ZWRcclxuXHJcblx0XHR0aGlzLm5vcm1hbCA9IG5vcm1hbDtcclxuXHRcdHRoaXMuY29uc3RhbnQgPSBjb25zdGFudDtcclxuXHJcblx0fVxyXG5cclxuXHRzZXQoIG5vcm1hbCwgY29uc3RhbnQgKSB7XHJcblxyXG5cdFx0dGhpcy5ub3JtYWwuY29weSggbm9ybWFsICk7XHJcblx0XHR0aGlzLmNvbnN0YW50ID0gY29uc3RhbnQ7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0Q29tcG9uZW50cyggeCwgeSwgeiwgdyApIHtcclxuXHJcblx0XHR0aGlzLm5vcm1hbC5zZXQoIHgsIHksIHogKTtcclxuXHRcdHRoaXMuY29uc3RhbnQgPSB3O1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldEZyb21Ob3JtYWxBbmRDb3BsYW5hclBvaW50KCBub3JtYWwsIHBvaW50ICkge1xyXG5cclxuXHRcdHRoaXMubm9ybWFsLmNvcHkoIG5vcm1hbCApO1xyXG5cdFx0dGhpcy5jb25zdGFudCA9IC0gcG9pbnQuZG90KCB0aGlzLm5vcm1hbCApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldEZyb21Db3BsYW5hclBvaW50cyggYSwgYiwgYyApIHtcclxuXHJcblx0XHRjb25zdCBub3JtYWwgPSBfdmVjdG9yMS5zdWJWZWN0b3JzKCBjLCBiICkuY3Jvc3MoIF92ZWN0b3IyLnN1YlZlY3RvcnMoIGEsIGIgKSApLm5vcm1hbGl6ZSgpO1xyXG5cclxuXHRcdC8vIFE6IHNob3VsZCBhbiBlcnJvciBiZSB0aHJvd24gaWYgbm9ybWFsIGlzIHplcm8gKGUuZy4gZGVnZW5lcmF0ZSBwbGFuZSk/XHJcblxyXG5cdFx0dGhpcy5zZXRGcm9tTm9ybWFsQW5kQ29wbGFuYXJQb2ludCggbm9ybWFsLCBhICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggcGxhbmUgKSB7XHJcblxyXG5cdFx0dGhpcy5ub3JtYWwuY29weSggcGxhbmUubm9ybWFsICk7XHJcblx0XHR0aGlzLmNvbnN0YW50ID0gcGxhbmUuY29uc3RhbnQ7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0bm9ybWFsaXplKCkge1xyXG5cclxuXHRcdC8vIE5vdGU6IHdpbGwgbGVhZCB0byBhIGRpdmlkZSBieSB6ZXJvIGlmIHRoZSBwbGFuZSBpcyBpbnZhbGlkLlxyXG5cclxuXHRcdGNvbnN0IGludmVyc2VOb3JtYWxMZW5ndGggPSAxLjAgLyB0aGlzLm5vcm1hbC5sZW5ndGgoKTtcclxuXHRcdHRoaXMubm9ybWFsLm11bHRpcGx5U2NhbGFyKCBpbnZlcnNlTm9ybWFsTGVuZ3RoICk7XHJcblx0XHR0aGlzLmNvbnN0YW50ICo9IGludmVyc2VOb3JtYWxMZW5ndGg7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0bmVnYXRlKCkge1xyXG5cclxuXHRcdHRoaXMuY29uc3RhbnQgKj0gLSAxO1xyXG5cdFx0dGhpcy5ub3JtYWwubmVnYXRlKCk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0ZGlzdGFuY2VUb1BvaW50KCBwb2ludCApIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5ub3JtYWwuZG90KCBwb2ludCApICsgdGhpcy5jb25zdGFudDtcclxuXHJcblx0fVxyXG5cclxuXHRkaXN0YW5jZVRvU3BoZXJlKCBzcGhlcmUgKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuZGlzdGFuY2VUb1BvaW50KCBzcGhlcmUuY2VudGVyICkgLSBzcGhlcmUucmFkaXVzO1xyXG5cclxuXHR9XHJcblxyXG5cdHByb2plY3RQb2ludCggcG9pbnQsIHRhcmdldCApIHtcclxuXHJcblx0XHRyZXR1cm4gdGFyZ2V0LmNvcHkoIHBvaW50ICkuYWRkU2NhbGVkVmVjdG9yKCB0aGlzLm5vcm1hbCwgLSB0aGlzLmRpc3RhbmNlVG9Qb2ludCggcG9pbnQgKSApO1xyXG5cclxuXHR9XHJcblxyXG5cdGludGVyc2VjdExpbmUoIGxpbmUsIHRhcmdldCApIHtcclxuXHJcblx0XHRjb25zdCBkaXJlY3Rpb24gPSBsaW5lLmRlbHRhKCBfdmVjdG9yMSApO1xyXG5cclxuXHRcdGNvbnN0IGRlbm9taW5hdG9yID0gdGhpcy5ub3JtYWwuZG90KCBkaXJlY3Rpb24gKTtcclxuXHJcblx0XHRpZiAoIGRlbm9taW5hdG9yID09PSAwICkge1xyXG5cclxuXHRcdFx0Ly8gbGluZSBpcyBjb3BsYW5hciwgcmV0dXJuIG9yaWdpblxyXG5cdFx0XHRpZiAoIHRoaXMuZGlzdGFuY2VUb1BvaW50KCBsaW5lLnN0YXJ0ICkgPT09IDAgKSB7XHJcblxyXG5cdFx0XHRcdHJldHVybiB0YXJnZXQuY29weSggbGluZS5zdGFydCApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Ly8gVW5zdXJlIGlmIHRoaXMgaXMgdGhlIGNvcnJlY3QgbWV0aG9kIHRvIGhhbmRsZSB0aGlzIGNhc2UuXHJcblx0XHRcdHJldHVybiBudWxsO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCB0ID0gLSAoIGxpbmUuc3RhcnQuZG90KCB0aGlzLm5vcm1hbCApICsgdGhpcy5jb25zdGFudCApIC8gZGVub21pbmF0b3I7XHJcblxyXG5cdFx0aWYgKCB0IDwgMCB8fCB0ID4gMSApIHtcclxuXHJcblx0XHRcdHJldHVybiBudWxsO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGFyZ2V0LmNvcHkoIGxpbmUuc3RhcnQgKS5hZGRTY2FsZWRWZWN0b3IoIGRpcmVjdGlvbiwgdCApO1xyXG5cclxuXHR9XHJcblxyXG5cdGludGVyc2VjdHNMaW5lKCBsaW5lICkge1xyXG5cclxuXHRcdC8vIE5vdGU6IHRoaXMgdGVzdHMgaWYgYSBsaW5lIGludGVyc2VjdHMgdGhlIHBsYW5lLCBub3Qgd2hldGhlciBpdCAob3IgaXRzIGVuZC1wb2ludHMpIGFyZSBjb3BsYW5hciB3aXRoIGl0LlxyXG5cclxuXHRcdGNvbnN0IHN0YXJ0U2lnbiA9IHRoaXMuZGlzdGFuY2VUb1BvaW50KCBsaW5lLnN0YXJ0ICk7XHJcblx0XHRjb25zdCBlbmRTaWduID0gdGhpcy5kaXN0YW5jZVRvUG9pbnQoIGxpbmUuZW5kICk7XHJcblxyXG5cdFx0cmV0dXJuICggc3RhcnRTaWduIDwgMCAmJiBlbmRTaWduID4gMCApIHx8ICggZW5kU2lnbiA8IDAgJiYgc3RhcnRTaWduID4gMCApO1xyXG5cclxuXHR9XHJcblxyXG5cdGludGVyc2VjdHNCb3goIGJveCApIHtcclxuXHJcblx0XHRyZXR1cm4gYm94LmludGVyc2VjdHNQbGFuZSggdGhpcyApO1xyXG5cclxuXHR9XHJcblxyXG5cdGludGVyc2VjdHNTcGhlcmUoIHNwaGVyZSApIHtcclxuXHJcblx0XHRyZXR1cm4gc3BoZXJlLmludGVyc2VjdHNQbGFuZSggdGhpcyApO1xyXG5cclxuXHR9XHJcblxyXG5cdGNvcGxhbmFyUG9pbnQoIHRhcmdldCApIHtcclxuXHJcblx0XHRyZXR1cm4gdGFyZ2V0LmNvcHkoIHRoaXMubm9ybWFsICkubXVsdGlwbHlTY2FsYXIoIC0gdGhpcy5jb25zdGFudCApO1xyXG5cclxuXHR9XHJcblxyXG5cdGFwcGx5TWF0cml4NCggbWF0cml4LCBvcHRpb25hbE5vcm1hbE1hdHJpeCApIHtcclxuXHJcblx0XHRjb25zdCBub3JtYWxNYXRyaXggPSBvcHRpb25hbE5vcm1hbE1hdHJpeCB8fCBfbm9ybWFsTWF0cml4LmdldE5vcm1hbE1hdHJpeCggbWF0cml4ICk7XHJcblxyXG5cdFx0Y29uc3QgcmVmZXJlbmNlUG9pbnQgPSB0aGlzLmNvcGxhbmFyUG9pbnQoIF92ZWN0b3IxICkuYXBwbHlNYXRyaXg0KCBtYXRyaXggKTtcclxuXHJcblx0XHRjb25zdCBub3JtYWwgPSB0aGlzLm5vcm1hbC5hcHBseU1hdHJpeDMoIG5vcm1hbE1hdHJpeCApLm5vcm1hbGl6ZSgpO1xyXG5cclxuXHRcdHRoaXMuY29uc3RhbnQgPSAtIHJlZmVyZW5jZVBvaW50LmRvdCggbm9ybWFsICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0dHJhbnNsYXRlKCBvZmZzZXQgKSB7XHJcblxyXG5cdFx0dGhpcy5jb25zdGFudCAtPSBvZmZzZXQuZG90KCB0aGlzLm5vcm1hbCApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGVxdWFscyggcGxhbmUgKSB7XHJcblxyXG5cdFx0cmV0dXJuIHBsYW5lLm5vcm1hbC5lcXVhbHMoIHRoaXMubm9ybWFsICkgJiYgKCBwbGFuZS5jb25zdGFudCA9PT0gdGhpcy5jb25zdGFudCApO1xyXG5cclxuXHR9XHJcblxyXG5cdGNsb25lKCkge1xyXG5cclxuXHRcdHJldHVybiBuZXcgdGhpcy5jb25zdHJ1Y3RvcigpLmNvcHkoIHRoaXMgKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgUGxhbmUgfTtcclxuIiwiaW1wb3J0IHsgV2ViR0xDb29yZGluYXRlU3lzdGVtLCBXZWJHUFVDb29yZGluYXRlU3lzdGVtIH0gZnJvbSAnLi4vY29uc3RhbnRzLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yMyB9IGZyb20gJy4vVmVjdG9yMy5qcyc7XHJcbmltcG9ydCB7IFNwaGVyZSB9IGZyb20gJy4vU3BoZXJlLmpzJztcclxuaW1wb3J0IHsgUGxhbmUgfSBmcm9tICcuL1BsYW5lLmpzJztcclxuXHJcbmNvbnN0IF9zcGhlcmUgPSAvKkBfX1BVUkVfXyovIG5ldyBTcGhlcmUoKTtcclxuY29uc3QgX3ZlY3RvciA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuXHJcbmNsYXNzIEZydXN0dW0ge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggcDAgPSBuZXcgUGxhbmUoKSwgcDEgPSBuZXcgUGxhbmUoKSwgcDIgPSBuZXcgUGxhbmUoKSwgcDMgPSBuZXcgUGxhbmUoKSwgcDQgPSBuZXcgUGxhbmUoKSwgcDUgPSBuZXcgUGxhbmUoKSApIHtcclxuXHJcblx0XHR0aGlzLnBsYW5lcyA9IFsgcDAsIHAxLCBwMiwgcDMsIHA0LCBwNSBdO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldCggcDAsIHAxLCBwMiwgcDMsIHA0LCBwNSApIHtcclxuXHJcblx0XHRjb25zdCBwbGFuZXMgPSB0aGlzLnBsYW5lcztcclxuXHJcblx0XHRwbGFuZXNbIDAgXS5jb3B5KCBwMCApO1xyXG5cdFx0cGxhbmVzWyAxIF0uY29weSggcDEgKTtcclxuXHRcdHBsYW5lc1sgMiBdLmNvcHkoIHAyICk7XHJcblx0XHRwbGFuZXNbIDMgXS5jb3B5KCBwMyApO1xyXG5cdFx0cGxhbmVzWyA0IF0uY29weSggcDQgKTtcclxuXHRcdHBsYW5lc1sgNSBdLmNvcHkoIHA1ICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggZnJ1c3R1bSApIHtcclxuXHJcblx0XHRjb25zdCBwbGFuZXMgPSB0aGlzLnBsYW5lcztcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCA2OyBpICsrICkge1xyXG5cclxuXHRcdFx0cGxhbmVzWyBpIF0uY29weSggZnJ1c3R1bS5wbGFuZXNbIGkgXSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRGcm9tUHJvamVjdGlvbk1hdHJpeCggbSwgY29vcmRpbmF0ZVN5c3RlbSA9IFdlYkdMQ29vcmRpbmF0ZVN5c3RlbSApIHtcclxuXHJcblx0XHRjb25zdCBwbGFuZXMgPSB0aGlzLnBsYW5lcztcclxuXHRcdGNvbnN0IG1lID0gbS5lbGVtZW50cztcclxuXHRcdGNvbnN0IG1lMCA9IG1lWyAwIF0sIG1lMSA9IG1lWyAxIF0sIG1lMiA9IG1lWyAyIF0sIG1lMyA9IG1lWyAzIF07XHJcblx0XHRjb25zdCBtZTQgPSBtZVsgNCBdLCBtZTUgPSBtZVsgNSBdLCBtZTYgPSBtZVsgNiBdLCBtZTcgPSBtZVsgNyBdO1xyXG5cdFx0Y29uc3QgbWU4ID0gbWVbIDggXSwgbWU5ID0gbWVbIDkgXSwgbWUxMCA9IG1lWyAxMCBdLCBtZTExID0gbWVbIDExIF07XHJcblx0XHRjb25zdCBtZTEyID0gbWVbIDEyIF0sIG1lMTMgPSBtZVsgMTMgXSwgbWUxNCA9IG1lWyAxNCBdLCBtZTE1ID0gbWVbIDE1IF07XHJcblxyXG5cdFx0cGxhbmVzWyAwIF0uc2V0Q29tcG9uZW50cyggbWUzIC0gbWUwLCBtZTcgLSBtZTQsIG1lMTEgLSBtZTgsIG1lMTUgLSBtZTEyICkubm9ybWFsaXplKCk7XHJcblx0XHRwbGFuZXNbIDEgXS5zZXRDb21wb25lbnRzKCBtZTMgKyBtZTAsIG1lNyArIG1lNCwgbWUxMSArIG1lOCwgbWUxNSArIG1lMTIgKS5ub3JtYWxpemUoKTtcclxuXHRcdHBsYW5lc1sgMiBdLnNldENvbXBvbmVudHMoIG1lMyArIG1lMSwgbWU3ICsgbWU1LCBtZTExICsgbWU5LCBtZTE1ICsgbWUxMyApLm5vcm1hbGl6ZSgpO1xyXG5cdFx0cGxhbmVzWyAzIF0uc2V0Q29tcG9uZW50cyggbWUzIC0gbWUxLCBtZTcgLSBtZTUsIG1lMTEgLSBtZTksIG1lMTUgLSBtZTEzICkubm9ybWFsaXplKCk7XHJcblx0XHRwbGFuZXNbIDQgXS5zZXRDb21wb25lbnRzKCBtZTMgLSBtZTIsIG1lNyAtIG1lNiwgbWUxMSAtIG1lMTAsIG1lMTUgLSBtZTE0ICkubm9ybWFsaXplKCk7XHJcblxyXG5cdFx0aWYgKCBjb29yZGluYXRlU3lzdGVtID09PSBXZWJHTENvb3JkaW5hdGVTeXN0ZW0gKSB7XHJcblxyXG5cdFx0XHRwbGFuZXNbIDUgXS5zZXRDb21wb25lbnRzKCBtZTMgKyBtZTIsIG1lNyArIG1lNiwgbWUxMSArIG1lMTAsIG1lMTUgKyBtZTE0ICkubm9ybWFsaXplKCk7XHJcblxyXG5cdFx0fSBlbHNlIGlmICggY29vcmRpbmF0ZVN5c3RlbSA9PT0gV2ViR1BVQ29vcmRpbmF0ZVN5c3RlbSApIHtcclxuXHJcblx0XHRcdHBsYW5lc1sgNSBdLnNldENvbXBvbmVudHMoIG1lMiwgbWU2LCBtZTEwLCBtZTE0ICkubm9ybWFsaXplKCk7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdHRocm93IG5ldyBFcnJvciggJ1RIUkVFLkZydXN0dW0uc2V0RnJvbVByb2plY3Rpb25NYXRyaXgoKTogSW52YWxpZCBjb29yZGluYXRlIHN5c3RlbTogJyArIGNvb3JkaW5hdGVTeXN0ZW0gKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0aW50ZXJzZWN0c09iamVjdCggb2JqZWN0ICkge1xyXG5cclxuXHRcdGlmICggb2JqZWN0LmJvdW5kaW5nU3BoZXJlICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRpZiAoIG9iamVjdC5ib3VuZGluZ1NwaGVyZSA9PT0gbnVsbCApIG9iamVjdC5jb21wdXRlQm91bmRpbmdTcGhlcmUoKTtcclxuXHJcblx0XHRcdF9zcGhlcmUuY29weSggb2JqZWN0LmJvdW5kaW5nU3BoZXJlICkuYXBwbHlNYXRyaXg0KCBvYmplY3QubWF0cml4V29ybGQgKTtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0Y29uc3QgZ2VvbWV0cnkgPSBvYmplY3QuZ2VvbWV0cnk7XHJcblxyXG5cdFx0XHRpZiAoIGdlb21ldHJ5LmJvdW5kaW5nU3BoZXJlID09PSBudWxsICkgZ2VvbWV0cnkuY29tcHV0ZUJvdW5kaW5nU3BoZXJlKCk7XHJcblxyXG5cdFx0XHRfc3BoZXJlLmNvcHkoIGdlb21ldHJ5LmJvdW5kaW5nU3BoZXJlICkuYXBwbHlNYXRyaXg0KCBvYmplY3QubWF0cml4V29ybGQgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuaW50ZXJzZWN0c1NwaGVyZSggX3NwaGVyZSApO1xyXG5cclxuXHR9XHJcblxyXG5cdGludGVyc2VjdHNTcHJpdGUoIHNwcml0ZSApIHtcclxuXHJcblx0XHRfc3BoZXJlLmNlbnRlci5zZXQoIDAsIDAsIDAgKTtcclxuXHRcdF9zcGhlcmUucmFkaXVzID0gMC43MDcxMDY3ODExODY1NDc2O1xyXG5cdFx0X3NwaGVyZS5hcHBseU1hdHJpeDQoIHNwcml0ZS5tYXRyaXhXb3JsZCApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzLmludGVyc2VjdHNTcGhlcmUoIF9zcGhlcmUgKTtcclxuXHJcblx0fVxyXG5cclxuXHRpbnRlcnNlY3RzU3BoZXJlKCBzcGhlcmUgKSB7XHJcblxyXG5cdFx0Y29uc3QgcGxhbmVzID0gdGhpcy5wbGFuZXM7XHJcblx0XHRjb25zdCBjZW50ZXIgPSBzcGhlcmUuY2VudGVyO1xyXG5cdFx0Y29uc3QgbmVnUmFkaXVzID0gLSBzcGhlcmUucmFkaXVzO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IDY7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBkaXN0YW5jZSA9IHBsYW5lc1sgaSBdLmRpc3RhbmNlVG9Qb2ludCggY2VudGVyICk7XHJcblxyXG5cdFx0XHRpZiAoIGRpc3RhbmNlIDwgbmVnUmFkaXVzICkge1xyXG5cclxuXHRcdFx0XHRyZXR1cm4gZmFsc2U7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0cnVlO1xyXG5cclxuXHR9XHJcblxyXG5cdGludGVyc2VjdHNCb3goIGJveCApIHtcclxuXHJcblx0XHRjb25zdCBwbGFuZXMgPSB0aGlzLnBsYW5lcztcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCA2OyBpICsrICkge1xyXG5cclxuXHRcdFx0Y29uc3QgcGxhbmUgPSBwbGFuZXNbIGkgXTtcclxuXHJcblx0XHRcdC8vIGNvcm5lciBhdCBtYXggZGlzdGFuY2VcclxuXHJcblx0XHRcdF92ZWN0b3IueCA9IHBsYW5lLm5vcm1hbC54ID4gMCA/IGJveC5tYXgueCA6IGJveC5taW4ueDtcclxuXHRcdFx0X3ZlY3Rvci55ID0gcGxhbmUubm9ybWFsLnkgPiAwID8gYm94Lm1heC55IDogYm94Lm1pbi55O1xyXG5cdFx0XHRfdmVjdG9yLnogPSBwbGFuZS5ub3JtYWwueiA+IDAgPyBib3gubWF4LnogOiBib3gubWluLno7XHJcblxyXG5cdFx0XHRpZiAoIHBsYW5lLmRpc3RhbmNlVG9Qb2ludCggX3ZlY3RvciApIDwgMCApIHtcclxuXHJcblx0XHRcdFx0cmV0dXJuIGZhbHNlO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdHJ1ZTtcclxuXHJcblx0fVxyXG5cclxuXHRjb250YWluc1BvaW50KCBwb2ludCApIHtcclxuXHJcblx0XHRjb25zdCBwbGFuZXMgPSB0aGlzLnBsYW5lcztcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCA2OyBpICsrICkge1xyXG5cclxuXHRcdFx0aWYgKCBwbGFuZXNbIGkgXS5kaXN0YW5jZVRvUG9pbnQoIHBvaW50ICkgPCAwICkge1xyXG5cclxuXHRcdFx0XHRyZXR1cm4gZmFsc2U7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0cnVlO1xyXG5cclxuXHR9XHJcblxyXG5cdGNsb25lKCkge1xyXG5cclxuXHRcdHJldHVybiBuZXcgdGhpcy5jb25zdHJ1Y3RvcigpLmNvcHkoIHRoaXMgKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuXHJcbmV4cG9ydCB7IEZydXN0dW0gfTtcclxuIiwiZnVuY3Rpb24gV2ViR0xBbmltYXRpb24oKSB7XHJcblxyXG5cdGxldCBjb250ZXh0ID0gbnVsbDtcclxuXHRsZXQgaXNBbmltYXRpbmcgPSBmYWxzZTtcclxuXHRsZXQgYW5pbWF0aW9uTG9vcCA9IG51bGw7XHJcblx0bGV0IHJlcXVlc3RJZCA9IG51bGw7XHJcblxyXG5cdGZ1bmN0aW9uIG9uQW5pbWF0aW9uRnJhbWUoIHRpbWUsIGZyYW1lICkge1xyXG5cclxuXHRcdGFuaW1hdGlvbkxvb3AoIHRpbWUsIGZyYW1lICk7XHJcblxyXG5cdFx0cmVxdWVzdElkID0gY29udGV4dC5yZXF1ZXN0QW5pbWF0aW9uRnJhbWUoIG9uQW5pbWF0aW9uRnJhbWUgKTtcclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4ge1xyXG5cclxuXHRcdHN0YXJ0OiBmdW5jdGlvbiAoKSB7XHJcblxyXG5cdFx0XHRpZiAoIGlzQW5pbWF0aW5nID09PSB0cnVlICkgcmV0dXJuO1xyXG5cdFx0XHRpZiAoIGFuaW1hdGlvbkxvb3AgPT09IG51bGwgKSByZXR1cm47XHJcblxyXG5cdFx0XHRyZXF1ZXN0SWQgPSBjb250ZXh0LnJlcXVlc3RBbmltYXRpb25GcmFtZSggb25BbmltYXRpb25GcmFtZSApO1xyXG5cclxuXHRcdFx0aXNBbmltYXRpbmcgPSB0cnVlO1xyXG5cclxuXHRcdH0sXHJcblxyXG5cdFx0c3RvcDogZnVuY3Rpb24gKCkge1xyXG5cclxuXHRcdFx0Y29udGV4dC5jYW5jZWxBbmltYXRpb25GcmFtZSggcmVxdWVzdElkICk7XHJcblxyXG5cdFx0XHRpc0FuaW1hdGluZyA9IGZhbHNlO1xyXG5cclxuXHRcdH0sXHJcblxyXG5cdFx0c2V0QW5pbWF0aW9uTG9vcDogZnVuY3Rpb24gKCBjYWxsYmFjayApIHtcclxuXHJcblx0XHRcdGFuaW1hdGlvbkxvb3AgPSBjYWxsYmFjaztcclxuXHJcblx0XHR9LFxyXG5cclxuXHRcdHNldENvbnRleHQ6IGZ1bmN0aW9uICggdmFsdWUgKSB7XHJcblxyXG5cdFx0XHRjb250ZXh0ID0gdmFsdWU7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9O1xyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgV2ViR0xBbmltYXRpb24gfTtcclxuIiwiZnVuY3Rpb24gV2ViR0xBdHRyaWJ1dGVzKCBnbCwgY2FwYWJpbGl0aWVzICkge1xyXG5cclxuXHRjb25zdCBpc1dlYkdMMiA9IGNhcGFiaWxpdGllcy5pc1dlYkdMMjtcclxuXHJcblx0Y29uc3QgYnVmZmVycyA9IG5ldyBXZWFrTWFwKCk7XHJcblxyXG5cdGZ1bmN0aW9uIGNyZWF0ZUJ1ZmZlciggYXR0cmlidXRlLCBidWZmZXJUeXBlICkge1xyXG5cclxuXHRcdGNvbnN0IGFycmF5ID0gYXR0cmlidXRlLmFycmF5O1xyXG5cdFx0Y29uc3QgdXNhZ2UgPSBhdHRyaWJ1dGUudXNhZ2U7XHJcblx0XHRjb25zdCBzaXplID0gYXJyYXkuYnl0ZUxlbmd0aDtcclxuXHJcblx0XHRjb25zdCBidWZmZXIgPSBnbC5jcmVhdGVCdWZmZXIoKTtcclxuXHJcblx0XHRnbC5iaW5kQnVmZmVyKCBidWZmZXJUeXBlLCBidWZmZXIgKTtcclxuXHRcdGdsLmJ1ZmZlckRhdGEoIGJ1ZmZlclR5cGUsIGFycmF5LCB1c2FnZSApO1xyXG5cclxuXHRcdGF0dHJpYnV0ZS5vblVwbG9hZENhbGxiYWNrKCk7XHJcblxyXG5cdFx0bGV0IHR5cGU7XHJcblxyXG5cdFx0aWYgKCBhcnJheSBpbnN0YW5jZW9mIEZsb2F0MzJBcnJheSApIHtcclxuXHJcblx0XHRcdHR5cGUgPSBnbC5GTE9BVDtcclxuXHJcblx0XHR9IGVsc2UgaWYgKCBhcnJheSBpbnN0YW5jZW9mIFVpbnQxNkFycmF5ICkge1xyXG5cclxuXHRcdFx0aWYgKCBhdHRyaWJ1dGUuaXNGbG9hdDE2QnVmZmVyQXR0cmlidXRlICkge1xyXG5cclxuXHRcdFx0XHRpZiAoIGlzV2ViR0wyICkge1xyXG5cclxuXHRcdFx0XHRcdHR5cGUgPSBnbC5IQUxGX0ZMT0FUO1xyXG5cclxuXHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdHRocm93IG5ldyBFcnJvciggJ1RIUkVFLldlYkdMQXR0cmlidXRlczogVXNhZ2Ugb2YgRmxvYXQxNkJ1ZmZlckF0dHJpYnV0ZSByZXF1aXJlcyBXZWJHTDIuJyApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHR0eXBlID0gZ2wuVU5TSUdORURfU0hPUlQ7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fSBlbHNlIGlmICggYXJyYXkgaW5zdGFuY2VvZiBJbnQxNkFycmF5ICkge1xyXG5cclxuXHRcdFx0dHlwZSA9IGdsLlNIT1JUO1xyXG5cclxuXHRcdH0gZWxzZSBpZiAoIGFycmF5IGluc3RhbmNlb2YgVWludDMyQXJyYXkgKSB7XHJcblxyXG5cdFx0XHR0eXBlID0gZ2wuVU5TSUdORURfSU5UO1xyXG5cclxuXHRcdH0gZWxzZSBpZiAoIGFycmF5IGluc3RhbmNlb2YgSW50MzJBcnJheSApIHtcclxuXHJcblx0XHRcdHR5cGUgPSBnbC5JTlQ7XHJcblxyXG5cdFx0fSBlbHNlIGlmICggYXJyYXkgaW5zdGFuY2VvZiBJbnQ4QXJyYXkgKSB7XHJcblxyXG5cdFx0XHR0eXBlID0gZ2wuQllURTtcclxuXHJcblx0XHR9IGVsc2UgaWYgKCBhcnJheSBpbnN0YW5jZW9mIFVpbnQ4QXJyYXkgKSB7XHJcblxyXG5cdFx0XHR0eXBlID0gZ2wuVU5TSUdORURfQllURTtcclxuXHJcblx0XHR9IGVsc2UgaWYgKCBhcnJheSBpbnN0YW5jZW9mIFVpbnQ4Q2xhbXBlZEFycmF5ICkge1xyXG5cclxuXHRcdFx0dHlwZSA9IGdsLlVOU0lHTkVEX0JZVEU7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdHRocm93IG5ldyBFcnJvciggJ1RIUkVFLldlYkdMQXR0cmlidXRlczogVW5zdXBwb3J0ZWQgYnVmZmVyIGRhdGEgZm9ybWF0OiAnICsgYXJyYXkgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHtcclxuXHRcdFx0YnVmZmVyOiBidWZmZXIsXHJcblx0XHRcdHR5cGU6IHR5cGUsXHJcblx0XHRcdGJ5dGVzUGVyRWxlbWVudDogYXJyYXkuQllURVNfUEVSX0VMRU1FTlQsXHJcblx0XHRcdHZlcnNpb246IGF0dHJpYnV0ZS52ZXJzaW9uLFxyXG5cdFx0XHRzaXplOiBzaXplXHJcblx0XHR9O1xyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHVwZGF0ZUJ1ZmZlciggYnVmZmVyLCBhdHRyaWJ1dGUsIGJ1ZmZlclR5cGUgKSB7XHJcblxyXG5cdFx0Y29uc3QgYXJyYXkgPSBhdHRyaWJ1dGUuYXJyYXk7XHJcblx0XHRjb25zdCB1cGRhdGVSYW5nZSA9IGF0dHJpYnV0ZS5fdXBkYXRlUmFuZ2U7IC8vIEBkZXByZWNhdGVkLCByMTU5XHJcblx0XHRjb25zdCB1cGRhdGVSYW5nZXMgPSBhdHRyaWJ1dGUudXBkYXRlUmFuZ2VzO1xyXG5cclxuXHRcdGdsLmJpbmRCdWZmZXIoIGJ1ZmZlclR5cGUsIGJ1ZmZlciApO1xyXG5cclxuXHRcdGlmICggdXBkYXRlUmFuZ2UuY291bnQgPT09IC0gMSAmJiB1cGRhdGVSYW5nZXMubGVuZ3RoID09PSAwICkge1xyXG5cclxuXHRcdFx0Ly8gTm90IHVzaW5nIHVwZGF0ZSByYW5nZXNcclxuXHRcdFx0Z2wuYnVmZmVyU3ViRGF0YSggYnVmZmVyVHlwZSwgMCwgYXJyYXkgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCB1cGRhdGVSYW5nZXMubGVuZ3RoICE9PSAwICkge1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gdXBkYXRlUmFuZ2VzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IHJhbmdlID0gdXBkYXRlUmFuZ2VzWyBpIF07XHJcblx0XHRcdFx0aWYgKCBpc1dlYkdMMiApIHtcclxuXHJcblx0XHRcdFx0XHRnbC5idWZmZXJTdWJEYXRhKCBidWZmZXJUeXBlLCByYW5nZS5zdGFydCAqIGFycmF5LkJZVEVTX1BFUl9FTEVNRU5ULFxyXG5cdFx0XHRcdFx0XHRhcnJheSwgcmFuZ2Uuc3RhcnQsIHJhbmdlLmNvdW50ICk7XHJcblxyXG5cdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0Z2wuYnVmZmVyU3ViRGF0YSggYnVmZmVyVHlwZSwgcmFuZ2Uuc3RhcnQgKiBhcnJheS5CWVRFU19QRVJfRUxFTUVOVCxcclxuXHRcdFx0XHRcdFx0YXJyYXkuc3ViYXJyYXkoIHJhbmdlLnN0YXJ0LCByYW5nZS5zdGFydCArIHJhbmdlLmNvdW50ICkgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0YXR0cmlidXRlLmNsZWFyVXBkYXRlUmFuZ2VzKCk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIEBkZXByZWNhdGVkLCByMTU5XHJcblx0XHRpZiAoIHVwZGF0ZVJhbmdlLmNvdW50ICE9PSAtIDEgKSB7XHJcblxyXG5cdFx0XHRpZiAoIGlzV2ViR0wyICkge1xyXG5cclxuXHRcdFx0XHRnbC5idWZmZXJTdWJEYXRhKCBidWZmZXJUeXBlLCB1cGRhdGVSYW5nZS5vZmZzZXQgKiBhcnJheS5CWVRFU19QRVJfRUxFTUVOVCxcclxuXHRcdFx0XHRcdGFycmF5LCB1cGRhdGVSYW5nZS5vZmZzZXQsIHVwZGF0ZVJhbmdlLmNvdW50ICk7XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRnbC5idWZmZXJTdWJEYXRhKCBidWZmZXJUeXBlLCB1cGRhdGVSYW5nZS5vZmZzZXQgKiBhcnJheS5CWVRFU19QRVJfRUxFTUVOVCxcclxuXHRcdFx0XHRcdGFycmF5LnN1YmFycmF5KCB1cGRhdGVSYW5nZS5vZmZzZXQsIHVwZGF0ZVJhbmdlLm9mZnNldCArIHVwZGF0ZVJhbmdlLmNvdW50ICkgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHVwZGF0ZVJhbmdlLmNvdW50ID0gLSAxOyAvLyByZXNldCByYW5nZVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRhdHRyaWJ1dGUub25VcGxvYWRDYWxsYmFjaygpO1xyXG5cclxuXHR9XHJcblxyXG5cdC8vXHJcblxyXG5cdGZ1bmN0aW9uIGdldCggYXR0cmlidXRlICkge1xyXG5cclxuXHRcdGlmICggYXR0cmlidXRlLmlzSW50ZXJsZWF2ZWRCdWZmZXJBdHRyaWJ1dGUgKSBhdHRyaWJ1dGUgPSBhdHRyaWJ1dGUuZGF0YTtcclxuXHJcblx0XHRyZXR1cm4gYnVmZmVycy5nZXQoIGF0dHJpYnV0ZSApO1xyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHJlbW92ZSggYXR0cmlidXRlICkge1xyXG5cclxuXHRcdGlmICggYXR0cmlidXRlLmlzSW50ZXJsZWF2ZWRCdWZmZXJBdHRyaWJ1dGUgKSBhdHRyaWJ1dGUgPSBhdHRyaWJ1dGUuZGF0YTtcclxuXHJcblx0XHRjb25zdCBkYXRhID0gYnVmZmVycy5nZXQoIGF0dHJpYnV0ZSApO1xyXG5cclxuXHRcdGlmICggZGF0YSApIHtcclxuXHJcblx0XHRcdGdsLmRlbGV0ZUJ1ZmZlciggZGF0YS5idWZmZXIgKTtcclxuXHJcblx0XHRcdGJ1ZmZlcnMuZGVsZXRlKCBhdHRyaWJ1dGUgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gdXBkYXRlKCBhdHRyaWJ1dGUsIGJ1ZmZlclR5cGUgKSB7XHJcblxyXG5cdFx0aWYgKCBhdHRyaWJ1dGUuaXNHTEJ1ZmZlckF0dHJpYnV0ZSApIHtcclxuXHJcblx0XHRcdGNvbnN0IGNhY2hlZCA9IGJ1ZmZlcnMuZ2V0KCBhdHRyaWJ1dGUgKTtcclxuXHJcblx0XHRcdGlmICggISBjYWNoZWQgfHwgY2FjaGVkLnZlcnNpb24gPCBhdHRyaWJ1dGUudmVyc2lvbiApIHtcclxuXHJcblx0XHRcdFx0YnVmZmVycy5zZXQoIGF0dHJpYnV0ZSwge1xyXG5cdFx0XHRcdFx0YnVmZmVyOiBhdHRyaWJ1dGUuYnVmZmVyLFxyXG5cdFx0XHRcdFx0dHlwZTogYXR0cmlidXRlLnR5cGUsXHJcblx0XHRcdFx0XHRieXRlc1BlckVsZW1lbnQ6IGF0dHJpYnV0ZS5lbGVtZW50U2l6ZSxcclxuXHRcdFx0XHRcdHZlcnNpb246IGF0dHJpYnV0ZS52ZXJzaW9uXHJcblx0XHRcdFx0fSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0cmV0dXJuO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIGF0dHJpYnV0ZS5pc0ludGVybGVhdmVkQnVmZmVyQXR0cmlidXRlICkgYXR0cmlidXRlID0gYXR0cmlidXRlLmRhdGE7XHJcblxyXG5cdFx0Y29uc3QgZGF0YSA9IGJ1ZmZlcnMuZ2V0KCBhdHRyaWJ1dGUgKTtcclxuXHJcblx0XHRpZiAoIGRhdGEgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdGJ1ZmZlcnMuc2V0KCBhdHRyaWJ1dGUsIGNyZWF0ZUJ1ZmZlciggYXR0cmlidXRlLCBidWZmZXJUeXBlICkgKTtcclxuXHJcblx0XHR9IGVsc2UgaWYgKCBkYXRhLnZlcnNpb24gPCBhdHRyaWJ1dGUudmVyc2lvbiApIHtcclxuXHJcblx0XHRcdGlmICggZGF0YS5zaXplICE9PSBhdHRyaWJ1dGUuYXJyYXkuYnl0ZUxlbmd0aCApIHtcclxuXHJcblx0XHRcdFx0dGhyb3cgbmV3IEVycm9yKCAnVEhSRUUuV2ViR0xBdHRyaWJ1dGVzOiBUaGUgc2l6ZSBvZiB0aGUgYnVmZmVyIGF0dHJpYnV0ZVxcJ3MgYXJyYXkgYnVmZmVyIGRvZXMgbm90IG1hdGNoIHRoZSBvcmlnaW5hbCBzaXplLiBSZXNpemluZyBidWZmZXIgYXR0cmlidXRlcyBpcyBub3Qgc3VwcG9ydGVkLicgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHVwZGF0ZUJ1ZmZlciggZGF0YS5idWZmZXIsIGF0dHJpYnV0ZSwgYnVmZmVyVHlwZSApO1xyXG5cclxuXHRcdFx0ZGF0YS52ZXJzaW9uID0gYXR0cmlidXRlLnZlcnNpb247XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdHJldHVybiB7XHJcblxyXG5cdFx0Z2V0OiBnZXQsXHJcblx0XHRyZW1vdmU6IHJlbW92ZSxcclxuXHRcdHVwZGF0ZTogdXBkYXRlXHJcblxyXG5cdH07XHJcblxyXG59XHJcblxyXG5cclxuZXhwb3J0IHsgV2ViR0xBdHRyaWJ1dGVzIH07XHJcbiIsImltcG9ydCB7IEJ1ZmZlckdlb21ldHJ5IH0gZnJvbSAnLi4vY29yZS9CdWZmZXJHZW9tZXRyeS5qcyc7XHJcbmltcG9ydCB7IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUgfSBmcm9tICcuLi9jb3JlL0J1ZmZlckF0dHJpYnV0ZS5qcyc7XHJcblxyXG5jbGFzcyBQbGFuZUdlb21ldHJ5IGV4dGVuZHMgQnVmZmVyR2VvbWV0cnkge1xyXG5cclxuXHRjb25zdHJ1Y3Rvciggd2lkdGggPSAxLCBoZWlnaHQgPSAxLCB3aWR0aFNlZ21lbnRzID0gMSwgaGVpZ2h0U2VnbWVudHMgPSAxICkge1xyXG5cclxuXHRcdHN1cGVyKCk7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ1BsYW5lR2VvbWV0cnknO1xyXG5cclxuXHRcdHRoaXMucGFyYW1ldGVycyA9IHtcclxuXHRcdFx0d2lkdGg6IHdpZHRoLFxyXG5cdFx0XHRoZWlnaHQ6IGhlaWdodCxcclxuXHRcdFx0d2lkdGhTZWdtZW50czogd2lkdGhTZWdtZW50cyxcclxuXHRcdFx0aGVpZ2h0U2VnbWVudHM6IGhlaWdodFNlZ21lbnRzXHJcblx0XHR9O1xyXG5cclxuXHRcdGNvbnN0IHdpZHRoX2hhbGYgPSB3aWR0aCAvIDI7XHJcblx0XHRjb25zdCBoZWlnaHRfaGFsZiA9IGhlaWdodCAvIDI7XHJcblxyXG5cdFx0Y29uc3QgZ3JpZFggPSBNYXRoLmZsb29yKCB3aWR0aFNlZ21lbnRzICk7XHJcblx0XHRjb25zdCBncmlkWSA9IE1hdGguZmxvb3IoIGhlaWdodFNlZ21lbnRzICk7XHJcblxyXG5cdFx0Y29uc3QgZ3JpZFgxID0gZ3JpZFggKyAxO1xyXG5cdFx0Y29uc3QgZ3JpZFkxID0gZ3JpZFkgKyAxO1xyXG5cclxuXHRcdGNvbnN0IHNlZ21lbnRfd2lkdGggPSB3aWR0aCAvIGdyaWRYO1xyXG5cdFx0Y29uc3Qgc2VnbWVudF9oZWlnaHQgPSBoZWlnaHQgLyBncmlkWTtcclxuXHJcblx0XHQvL1xyXG5cclxuXHRcdGNvbnN0IGluZGljZXMgPSBbXTtcclxuXHRcdGNvbnN0IHZlcnRpY2VzID0gW107XHJcblx0XHRjb25zdCBub3JtYWxzID0gW107XHJcblx0XHRjb25zdCB1dnMgPSBbXTtcclxuXHJcblx0XHRmb3IgKCBsZXQgaXkgPSAwOyBpeSA8IGdyaWRZMTsgaXkgKysgKSB7XHJcblxyXG5cdFx0XHRjb25zdCB5ID0gaXkgKiBzZWdtZW50X2hlaWdodCAtIGhlaWdodF9oYWxmO1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGl4ID0gMDsgaXggPCBncmlkWDE7IGl4ICsrICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCB4ID0gaXggKiBzZWdtZW50X3dpZHRoIC0gd2lkdGhfaGFsZjtcclxuXHJcblx0XHRcdFx0dmVydGljZXMucHVzaCggeCwgLSB5LCAwICk7XHJcblxyXG5cdFx0XHRcdG5vcm1hbHMucHVzaCggMCwgMCwgMSApO1xyXG5cclxuXHRcdFx0XHR1dnMucHVzaCggaXggLyBncmlkWCApO1xyXG5cdFx0XHRcdHV2cy5wdXNoKCAxIC0gKCBpeSAvIGdyaWRZICkgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Zm9yICggbGV0IGl5ID0gMDsgaXkgPCBncmlkWTsgaXkgKysgKSB7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaXggPSAwOyBpeCA8IGdyaWRYOyBpeCArKyApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgYSA9IGl4ICsgZ3JpZFgxICogaXk7XHJcblx0XHRcdFx0Y29uc3QgYiA9IGl4ICsgZ3JpZFgxICogKCBpeSArIDEgKTtcclxuXHRcdFx0XHRjb25zdCBjID0gKCBpeCArIDEgKSArIGdyaWRYMSAqICggaXkgKyAxICk7XHJcblx0XHRcdFx0Y29uc3QgZCA9ICggaXggKyAxICkgKyBncmlkWDEgKiBpeTtcclxuXHJcblx0XHRcdFx0aW5kaWNlcy5wdXNoKCBhLCBiLCBkICk7XHJcblx0XHRcdFx0aW5kaWNlcy5wdXNoKCBiLCBjLCBkICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMuc2V0SW5kZXgoIGluZGljZXMgKTtcclxuXHRcdHRoaXMuc2V0QXR0cmlidXRlKCAncG9zaXRpb24nLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggdmVydGljZXMsIDMgKSApO1xyXG5cdFx0dGhpcy5zZXRBdHRyaWJ1dGUoICdub3JtYWwnLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggbm9ybWFscywgMyApICk7XHJcblx0XHR0aGlzLnNldEF0dHJpYnV0ZSggJ3V2JywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIHV2cywgMiApICk7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xyXG5cclxuXHRcdHRoaXMucGFyYW1ldGVycyA9IE9iamVjdC5hc3NpZ24oIHt9LCBzb3VyY2UucGFyYW1ldGVycyApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHN0YXRpYyBmcm9tSlNPTiggZGF0YSApIHtcclxuXHJcblx0XHRyZXR1cm4gbmV3IFBsYW5lR2VvbWV0cnkoIGRhdGEud2lkdGgsIGRhdGEuaGVpZ2h0LCBkYXRhLndpZHRoU2VnbWVudHMsIGRhdGEuaGVpZ2h0U2VnbWVudHMgKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgUGxhbmVHZW9tZXRyeSB9O1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWZkZWYgVVNFX0FMUEhBSEFTSFxyXG5cclxuXHRpZiAoIGRpZmZ1c2VDb2xvci5hIDwgZ2V0QWxwaGFIYXNoVGhyZXNob2xkKCB2UG9zaXRpb24gKSApIGRpc2NhcmQ7XHJcblxyXG4jZW5kaWZcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuI2lmZGVmIFVTRV9BTFBIQUhBU0hcclxuXHJcblx0LyoqXHJcblx0ICogU2VlOiBodHRwczovL2Nhc3VhbC1lZmZlY3RzLmNvbS9yZXNlYXJjaC9XeW1hbjIwMTdIYXNoZWQvaW5kZXguaHRtbFxyXG5cdCAqL1xyXG5cclxuXHRjb25zdCBmbG9hdCBBTFBIQV9IQVNIX1NDQUxFID0gMC4wNTsgLy8gRGVyaXZlZCBmcm9tIHRyaWFscyBvbmx5LCBhbmQgbWF5IGJlIGNoYW5nZWQuXHJcblxyXG5cdGZsb2F0IGhhc2gyRCggdmVjMiB2YWx1ZSApIHtcclxuXHJcblx0XHRyZXR1cm4gZnJhY3QoIDEuMGU0ICogc2luKCAxNy4wICogdmFsdWUueCArIDAuMSAqIHZhbHVlLnkgKSAqICggMC4xICsgYWJzKCBzaW4oIDEzLjAgKiB2YWx1ZS55ICsgdmFsdWUueCApICkgKSApO1xyXG5cclxuXHR9XHJcblxyXG5cdGZsb2F0IGhhc2gzRCggdmVjMyB2YWx1ZSApIHtcclxuXHJcblx0XHRyZXR1cm4gaGFzaDJEKCB2ZWMyKCBoYXNoMkQoIHZhbHVlLnh5ICksIHZhbHVlLnogKSApO1xyXG5cclxuXHR9XHJcblxyXG5cdGZsb2F0IGdldEFscGhhSGFzaFRocmVzaG9sZCggdmVjMyBwb3NpdGlvbiApIHtcclxuXHJcblx0XHQvLyBGaW5kIHRoZSBkaXNjcmV0aXplZCBkZXJpdmF0aXZlcyBvZiBvdXIgY29vcmRpbmF0ZXNcclxuXHRcdGZsb2F0IG1heERlcml2ID0gbWF4KFxyXG5cdFx0XHRsZW5ndGgoIGRGZHgoIHBvc2l0aW9uLnh5eiApICksXHJcblx0XHRcdGxlbmd0aCggZEZkeSggcG9zaXRpb24ueHl6ICkgKVxyXG5cdFx0KTtcclxuXHRcdGZsb2F0IHBpeFNjYWxlID0gMS4wIC8gKCBBTFBIQV9IQVNIX1NDQUxFICogbWF4RGVyaXYgKTtcclxuXHJcblx0XHQvLyBGaW5kIHR3byBuZWFyZXN0IGxvZy1kaXNjcmV0aXplZCBub2lzZSBzY2FsZXNcclxuXHRcdHZlYzIgcGl4U2NhbGVzID0gdmVjMihcclxuXHRcdFx0ZXhwMiggZmxvb3IoIGxvZzIoIHBpeFNjYWxlICkgKSApLFxyXG5cdFx0XHRleHAyKCBjZWlsKCBsb2cyKCBwaXhTY2FsZSApICkgKVxyXG5cdFx0KTtcclxuXHJcblx0XHQvLyBDb21wdXRlIGFscGhhIHRocmVzaG9sZHMgYXQgb3VyIHR3byBub2lzZSBzY2FsZXNcclxuXHRcdHZlYzIgYWxwaGEgPSB2ZWMyKFxyXG5cdFx0XHRoYXNoM0QoIGZsb29yKCBwaXhTY2FsZXMueCAqIHBvc2l0aW9uLnh5eiApICksXHJcblx0XHRcdGhhc2gzRCggZmxvb3IoIHBpeFNjYWxlcy55ICogcG9zaXRpb24ueHl6ICkgKVxyXG5cdFx0KTtcclxuXHJcblx0XHQvLyBGYWN0b3IgdG8gaW50ZXJwb2xhdGUgbGVycCB3aXRoXHJcblx0XHRmbG9hdCBsZXJwRmFjdG9yID0gZnJhY3QoIGxvZzIoIHBpeFNjYWxlICkgKTtcclxuXHJcblx0XHQvLyBJbnRlcnBvbGF0ZSBhbHBoYSB0aHJlc2hvbGQgZnJvbSBub2lzZSBhdCB0d28gc2NhbGVzXHJcblx0XHRmbG9hdCB4ID0gKCAxLjAgLSBsZXJwRmFjdG9yICkgKiBhbHBoYS54ICsgbGVycEZhY3RvciAqIGFscGhhLnk7XHJcblxyXG5cdFx0Ly8gUGFzcyBpbnRvIENERiB0byBjb21wdXRlIHVuaWZvcm1seSBkaXN0cmliIHRocmVzaG9sZFxyXG5cdFx0ZmxvYXQgYSA9IG1pbiggbGVycEZhY3RvciwgMS4wIC0gbGVycEZhY3RvciApO1xyXG5cdFx0dmVjMyBjYXNlcyA9IHZlYzMoXHJcblx0XHRcdHggKiB4IC8gKCAyLjAgKiBhICogKCAxLjAgLSBhICkgKSxcclxuXHRcdFx0KCB4IC0gMC41ICogYSApIC8gKCAxLjAgLSBhICksXHJcblx0XHRcdDEuMCAtICggKCAxLjAgLSB4ICkgKiAoIDEuMCAtIHggKSAvICggMi4wICogYSAqICggMS4wIC0gYSApICkgKVxyXG5cdFx0KTtcclxuXHJcblx0XHQvLyBGaW5kIG91ciBmaW5hbCwgdW5pZm9ybWx5IGRpc3RyaWJ1dGVkIGFscGhhIHRocmVzaG9sZCAozrHPhClcclxuXHRcdGZsb2F0IHRocmVzaG9sZCA9ICggeCA8ICggMS4wIC0gYSApIClcclxuXHRcdFx0PyAoICggeCA8IGEgKSA/IGNhc2VzLnggOiBjYXNlcy55IClcclxuXHRcdFx0OiBjYXNlcy56O1xyXG5cclxuXHRcdC8vIEF2b2lkcyDOsc+EID09IDAuIENvdWxkIGFsc28gZG8gzrHPhCA9MS3Osc+EXHJcblx0XHRyZXR1cm4gY2xhbXAoIHRocmVzaG9sZCAsIDEuMGUtNiwgMS4wICk7XHJcblxyXG5cdH1cclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWZkZWYgVVNFX0FMUEhBTUFQXHJcblxyXG5cdGRpZmZ1c2VDb2xvci5hICo9IHRleHR1cmUyRCggYWxwaGFNYXAsIHZBbHBoYU1hcFV2ICkuZztcclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWZkZWYgVVNFX0FMUEhBTUFQXHJcblxyXG5cdHVuaWZvcm0gc2FtcGxlcjJEIGFscGhhTWFwO1xyXG5cclxuI2VuZGlmXHJcbmA7XHJcbiIsImV4cG9ydCBkZWZhdWx0IC8qIGdsc2wgKi9gXHJcbiNpZmRlZiBVU0VfQUxQSEFURVNUXHJcblxyXG5cdCNpZmRlZiBBTFBIQV9UT19DT1ZFUkFHRVxyXG5cclxuXHRkaWZmdXNlQ29sb3IuYSA9IHNtb290aHN0ZXAoIGFscGhhVGVzdCwgYWxwaGFUZXN0ICsgZndpZHRoKCBkaWZmdXNlQ29sb3IuYSApLCBkaWZmdXNlQ29sb3IuYSApO1xyXG5cdGlmICggZGlmZnVzZUNvbG9yLmEgPT0gMC4wICkgZGlzY2FyZDtcclxuXHJcblx0I2Vsc2VcclxuXHJcblx0aWYgKCBkaWZmdXNlQ29sb3IuYSA8IGFscGhhVGVzdCApIGRpc2NhcmQ7XHJcblxyXG5cdCNlbmRpZlxyXG5cclxuI2VuZGlmXHJcbmA7XHJcbiIsImV4cG9ydCBkZWZhdWx0IC8qIGdsc2wgKi9gXHJcbiNpZmRlZiBVU0VfQUxQSEFURVNUXHJcblx0dW5pZm9ybSBmbG9hdCBhbHBoYVRlc3Q7XHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWZkZWYgVVNFX0FPTUFQXHJcblxyXG5cdC8vIHJlYWRzIGNoYW5uZWwgUiwgY29tcGF0aWJsZSB3aXRoIGEgY29tYmluZWQgT2NjbHVzaW9uUm91Z2huZXNzTWV0YWxsaWMgKFJHQikgdGV4dHVyZVxyXG5cdGZsb2F0IGFtYmllbnRPY2NsdXNpb24gPSAoIHRleHR1cmUyRCggYW9NYXAsIHZBb01hcFV2ICkuciAtIDEuMCApICogYW9NYXBJbnRlbnNpdHkgKyAxLjA7XHJcblxyXG5cdHJlZmxlY3RlZExpZ2h0LmluZGlyZWN0RGlmZnVzZSAqPSBhbWJpZW50T2NjbHVzaW9uO1xyXG5cclxuXHQjaWYgZGVmaW5lZCggVVNFX0NMRUFSQ09BVCApIFxyXG5cdFx0Y2xlYXJjb2F0U3BlY3VsYXJJbmRpcmVjdCAqPSBhbWJpZW50T2NjbHVzaW9uO1xyXG5cdCNlbmRpZlxyXG5cclxuXHQjaWYgZGVmaW5lZCggVVNFX1NIRUVOICkgXHJcblx0XHRzaGVlblNwZWN1bGFySW5kaXJlY3QgKj0gYW1iaWVudE9jY2x1c2lvbjtcclxuXHQjZW5kaWZcclxuXHJcblx0I2lmIGRlZmluZWQoIFVTRV9FTlZNQVAgKSAmJiBkZWZpbmVkKCBTVEFOREFSRCApXHJcblxyXG5cdFx0ZmxvYXQgZG90TlYgPSBzYXR1cmF0ZSggZG90KCBnZW9tZXRyeU5vcm1hbCwgZ2VvbWV0cnlWaWV3RGlyICkgKTtcclxuXHJcblx0XHRyZWZsZWN0ZWRMaWdodC5pbmRpcmVjdFNwZWN1bGFyICo9IGNvbXB1dGVTcGVjdWxhck9jY2x1c2lvbiggZG90TlYsIGFtYmllbnRPY2NsdXNpb24sIG1hdGVyaWFsLnJvdWdobmVzcyApO1xyXG5cclxuXHQjZW5kaWZcclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWZkZWYgVVNFX0FPTUFQXHJcblxyXG5cdHVuaWZvcm0gc2FtcGxlcjJEIGFvTWFwO1xyXG5cdHVuaWZvcm0gZmxvYXQgYW9NYXBJbnRlbnNpdHk7XHJcblxyXG4jZW5kaWZcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuI2lmZGVmIFVTRV9CQVRDSElOR1xyXG5cdGF0dHJpYnV0ZSBmbG9hdCBiYXRjaElkO1xyXG5cdHVuaWZvcm0gaGlnaHAgc2FtcGxlcjJEIGJhdGNoaW5nVGV4dHVyZTtcclxuXHRtYXQ0IGdldEJhdGNoaW5nTWF0cml4KCBjb25zdCBpbiBmbG9hdCBpICkge1xyXG5cclxuXHRcdGludCBzaXplID0gdGV4dHVyZVNpemUoIGJhdGNoaW5nVGV4dHVyZSwgMCApLng7XHJcblx0XHRpbnQgaiA9IGludCggaSApICogNDtcclxuXHRcdGludCB4ID0gaiAlIHNpemU7XHJcblx0XHRpbnQgeSA9IGogLyBzaXplO1xyXG5cdFx0dmVjNCB2MSA9IHRleGVsRmV0Y2goIGJhdGNoaW5nVGV4dHVyZSwgaXZlYzIoIHgsIHkgKSwgMCApO1xyXG5cdFx0dmVjNCB2MiA9IHRleGVsRmV0Y2goIGJhdGNoaW5nVGV4dHVyZSwgaXZlYzIoIHggKyAxLCB5ICksIDAgKTtcclxuXHRcdHZlYzQgdjMgPSB0ZXhlbEZldGNoKCBiYXRjaGluZ1RleHR1cmUsIGl2ZWMyKCB4ICsgMiwgeSApLCAwICk7XHJcblx0XHR2ZWM0IHY0ID0gdGV4ZWxGZXRjaCggYmF0Y2hpbmdUZXh0dXJlLCBpdmVjMiggeCArIDMsIHkgKSwgMCApO1xyXG5cdFx0cmV0dXJuIG1hdDQoIHYxLCB2MiwgdjMsIHY0ICk7XHJcblxyXG5cdH1cclxuI2VuZGlmXHJcbmA7XHJcbiIsImV4cG9ydCBkZWZhdWx0IC8qIGdsc2wgKi9gXHJcbiNpZmRlZiBVU0VfQkFUQ0hJTkdcclxuXHRtYXQ0IGJhdGNoaW5nTWF0cml4ID0gZ2V0QmF0Y2hpbmdNYXRyaXgoIGJhdGNoSWQgKTtcclxuI2VuZGlmXHJcbmA7XHJcbiIsImV4cG9ydCBkZWZhdWx0IC8qIGdsc2wgKi9gXHJcbnZlYzMgdHJhbnNmb3JtZWQgPSB2ZWMzKCBwb3NpdGlvbiApO1xyXG5cclxuI2lmZGVmIFVTRV9BTFBIQUhBU0hcclxuXHJcblx0dlBvc2l0aW9uID0gdmVjMyggcG9zaXRpb24gKTtcclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG52ZWMzIG9iamVjdE5vcm1hbCA9IHZlYzMoIG5vcm1hbCApO1xyXG5cclxuI2lmZGVmIFVTRV9UQU5HRU5UXHJcblxyXG5cdHZlYzMgb2JqZWN0VGFuZ2VudCA9IHZlYzMoIHRhbmdlbnQueHl6ICk7XHJcblxyXG4jZW5kaWZcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuXHJcbmZsb2F0IEdfQmxpbm5QaG9uZ19JbXBsaWNpdCggLyogY29uc3QgaW4gZmxvYXQgZG90TkwsIGNvbnN0IGluIGZsb2F0IGRvdE5WICovICkge1xyXG5cclxuXHQvLyBnZW9tZXRyeSB0ZXJtIGlzIChuIGRvdCBsKShuIGRvdCB2KSAvIDQobiBkb3QgbCkobiBkb3QgdilcclxuXHRyZXR1cm4gMC4yNTtcclxuXHJcbn1cclxuXHJcbmZsb2F0IERfQmxpbm5QaG9uZyggY29uc3QgaW4gZmxvYXQgc2hpbmluZXNzLCBjb25zdCBpbiBmbG9hdCBkb3ROSCApIHtcclxuXHJcblx0cmV0dXJuIFJFQ0lQUk9DQUxfUEkgKiAoIHNoaW5pbmVzcyAqIDAuNSArIDEuMCApICogcG93KCBkb3ROSCwgc2hpbmluZXNzICk7XHJcblxyXG59XHJcblxyXG52ZWMzIEJSREZfQmxpbm5QaG9uZyggY29uc3QgaW4gdmVjMyBsaWdodERpciwgY29uc3QgaW4gdmVjMyB2aWV3RGlyLCBjb25zdCBpbiB2ZWMzIG5vcm1hbCwgY29uc3QgaW4gdmVjMyBzcGVjdWxhckNvbG9yLCBjb25zdCBpbiBmbG9hdCBzaGluaW5lc3MgKSB7XHJcblxyXG5cdHZlYzMgaGFsZkRpciA9IG5vcm1hbGl6ZSggbGlnaHREaXIgKyB2aWV3RGlyICk7XHJcblxyXG5cdGZsb2F0IGRvdE5IID0gc2F0dXJhdGUoIGRvdCggbm9ybWFsLCBoYWxmRGlyICkgKTtcclxuXHRmbG9hdCBkb3RWSCA9IHNhdHVyYXRlKCBkb3QoIHZpZXdEaXIsIGhhbGZEaXIgKSApO1xyXG5cclxuXHR2ZWMzIEYgPSBGX1NjaGxpY2soIHNwZWN1bGFyQ29sb3IsIDEuMCwgZG90VkggKTtcclxuXHJcblx0ZmxvYXQgRyA9IEdfQmxpbm5QaG9uZ19JbXBsaWNpdCggLyogZG90TkwsIGRvdE5WICovICk7XHJcblxyXG5cdGZsb2F0IEQgPSBEX0JsaW5uUGhvbmcoIHNoaW5pbmVzcywgZG90TkggKTtcclxuXHJcblx0cmV0dXJuIEYgKiAoIEcgKiBEICk7XHJcblxyXG59IC8vIHZhbGlkYXRlZFxyXG5cclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuXHJcbiNpZmRlZiBVU0VfSVJJREVTQ0VOQ0VcclxuXHJcblx0Ly8gWFlaIHRvIGxpbmVhci1zUkdCIGNvbG9yIHNwYWNlXHJcblx0Y29uc3QgbWF0MyBYWVpfVE9fUkVDNzA5ID0gbWF0MyhcclxuXHRcdCAzLjI0MDQ1NDIsIC0wLjk2OTI2NjAsICAwLjA1NTY0MzQsXHJcblx0XHQtMS41MzcxMzg1LCAgMS44NzYwMTA4LCAtMC4yMDQwMjU5LFxyXG5cdFx0LTAuNDk4NTMxNCwgIDAuMDQxNTU2MCwgIDEuMDU3MjI1MlxyXG5cdCk7XHJcblxyXG5cdC8vIEFzc3VtZSBhaXIgaW50ZXJmYWNlIGZvciB0b3BcclxuXHQvLyBOb3RlOiBXZSBkb24ndCBoYW5kbGUgdGhlIGNhc2UgZnJlc25lbDAgPT0gMVxyXG5cdHZlYzMgRnJlc25lbDBUb0lvciggdmVjMyBmcmVzbmVsMCApIHtcclxuXHJcblx0XHR2ZWMzIHNxcnRGMCA9IHNxcnQoIGZyZXNuZWwwICk7XHJcblx0XHRyZXR1cm4gKCB2ZWMzKCAxLjAgKSArIHNxcnRGMCApIC8gKCB2ZWMzKCAxLjAgKSAtIHNxcnRGMCApO1xyXG5cclxuXHR9XHJcblxyXG5cdC8vIENvbnZlcnNpb24gRk8vSU9SXHJcblx0dmVjMyBJb3JUb0ZyZXNuZWwwKCB2ZWMzIHRyYW5zbWl0dGVkSW9yLCBmbG9hdCBpbmNpZGVudElvciApIHtcclxuXHJcblx0XHRyZXR1cm4gcG93MiggKCB0cmFuc21pdHRlZElvciAtIHZlYzMoIGluY2lkZW50SW9yICkgKSAvICggdHJhbnNtaXR0ZWRJb3IgKyB2ZWMzKCBpbmNpZGVudElvciApICkgKTtcclxuXHJcblx0fVxyXG5cclxuXHQvLyBpb3IgaXMgYSB2YWx1ZSBiZXR3ZWVuIDEuMCBhbmQgMy4wLiAxLjAgaXMgYWlyIGludGVyZmFjZVxyXG5cdGZsb2F0IElvclRvRnJlc25lbDAoIGZsb2F0IHRyYW5zbWl0dGVkSW9yLCBmbG9hdCBpbmNpZGVudElvciApIHtcclxuXHJcblx0XHRyZXR1cm4gcG93MiggKCB0cmFuc21pdHRlZElvciAtIGluY2lkZW50SW9yICkgLyAoIHRyYW5zbWl0dGVkSW9yICsgaW5jaWRlbnRJb3IgKSk7XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gRnJlc25lbCBlcXVhdGlvbnMgZm9yIGRpZWxlY3RyaWMvZGllbGVjdHJpYyBpbnRlcmZhY2VzLlxyXG5cdC8vIFJlZjogaHR0cHM6Ly9iZWxjb3VyLmdpdGh1Yi5pby9ibG9nL3Jlc2VhcmNoLzIwMTcvMDUvMDEvYnJkZi10aGluLWZpbG0uaHRtbFxyXG5cdC8vIEV2YWx1YXRpb24gWFlaIHNlbnNpdGl2aXR5IGN1cnZlcyBpbiBGb3VyaWVyIHNwYWNlXHJcblx0dmVjMyBldmFsU2Vuc2l0aXZpdHkoIGZsb2F0IE9QRCwgdmVjMyBzaGlmdCApIHtcclxuXHJcblx0XHRmbG9hdCBwaGFzZSA9IDIuMCAqIFBJICogT1BEICogMS4wZS05O1xyXG5cdFx0dmVjMyB2YWwgPSB2ZWMzKCA1LjQ4NTZlLTEzLCA0LjQyMDFlLTEzLCA1LjI0ODFlLTEzICk7XHJcblx0XHR2ZWMzIHBvcyA9IHZlYzMoIDEuNjgxMGUrMDYsIDEuNzk1M2UrMDYsIDIuMjA4NGUrMDYgKTtcclxuXHRcdHZlYzMgdmFyID0gdmVjMyggNC4zMjc4ZSswOSwgOS4zMDQ2ZSswOSwgNi42MTIxZSswOSApO1xyXG5cclxuXHRcdHZlYzMgeHl6ID0gdmFsICogc3FydCggMi4wICogUEkgKiB2YXIgKSAqIGNvcyggcG9zICogcGhhc2UgKyBzaGlmdCApICogZXhwKCAtIHBvdzIoIHBoYXNlICkgKiB2YXIgKTtcclxuXHRcdHh5ei54ICs9IDkuNzQ3MGUtMTQgKiBzcXJ0KCAyLjAgKiBQSSAqIDQuNTI4MmUrMDkgKSAqIGNvcyggMi4yMzk5ZSswNiAqIHBoYXNlICsgc2hpZnRbIDAgXSApICogZXhwKCAtIDQuNTI4MmUrMDkgKiBwb3cyKCBwaGFzZSApICk7XHJcblx0XHR4eXogLz0gMS4wNjg1ZS03O1xyXG5cclxuXHRcdHZlYzMgcmdiID0gWFlaX1RPX1JFQzcwOSAqIHh5ejtcclxuXHRcdHJldHVybiByZ2I7XHJcblxyXG5cdH1cclxuXHJcblx0dmVjMyBldmFsSXJpZGVzY2VuY2UoIGZsb2F0IG91dHNpZGVJT1IsIGZsb2F0IGV0YTIsIGZsb2F0IGNvc1RoZXRhMSwgZmxvYXQgdGhpbkZpbG1UaGlja25lc3MsIHZlYzMgYmFzZUYwICkge1xyXG5cclxuXHRcdHZlYzMgSTtcclxuXHJcblx0XHQvLyBGb3JjZSBpcmlkZXNjZW5jZUlPUiAtPiBvdXRzaWRlSU9SIHdoZW4gdGhpbkZpbG1UaGlja25lc3MgLT4gMC4wXHJcblx0XHRmbG9hdCBpcmlkZXNjZW5jZUlPUiA9IG1peCggb3V0c2lkZUlPUiwgZXRhMiwgc21vb3Roc3RlcCggMC4wLCAwLjAzLCB0aGluRmlsbVRoaWNrbmVzcyApICk7XHJcblx0XHQvLyBFdmFsdWF0ZSB0aGUgY29zVGhldGEgb24gdGhlIGJhc2UgbGF5ZXIgKFNuZWxsIGxhdylcclxuXHRcdGZsb2F0IHNpblRoZXRhMlNxID0gcG93Miggb3V0c2lkZUlPUiAvIGlyaWRlc2NlbmNlSU9SICkgKiAoIDEuMCAtIHBvdzIoIGNvc1RoZXRhMSApICk7XHJcblxyXG5cdFx0Ly8gSGFuZGxlIFRJUjpcclxuXHRcdGZsb2F0IGNvc1RoZXRhMlNxID0gMS4wIC0gc2luVGhldGEyU3E7XHJcblx0XHRpZiAoIGNvc1RoZXRhMlNxIDwgMC4wICkge1xyXG5cclxuXHRcdFx0cmV0dXJuIHZlYzMoIDEuMCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRmbG9hdCBjb3NUaGV0YTIgPSBzcXJ0KCBjb3NUaGV0YTJTcSApO1xyXG5cclxuXHRcdC8vIEZpcnN0IGludGVyZmFjZVxyXG5cdFx0ZmxvYXQgUjAgPSBJb3JUb0ZyZXNuZWwwKCBpcmlkZXNjZW5jZUlPUiwgb3V0c2lkZUlPUiApO1xyXG5cdFx0ZmxvYXQgUjEyID0gRl9TY2hsaWNrKCBSMCwgMS4wLCBjb3NUaGV0YTEgKTtcclxuXHRcdGZsb2F0IFQxMjEgPSAxLjAgLSBSMTI7XHJcblx0XHRmbG9hdCBwaGkxMiA9IDAuMDtcclxuXHRcdGlmICggaXJpZGVzY2VuY2VJT1IgPCBvdXRzaWRlSU9SICkgcGhpMTIgPSBQSTtcclxuXHRcdGZsb2F0IHBoaTIxID0gUEkgLSBwaGkxMjtcclxuXHJcblx0XHQvLyBTZWNvbmQgaW50ZXJmYWNlXHJcblx0XHR2ZWMzIGJhc2VJT1IgPSBGcmVzbmVsMFRvSW9yKCBjbGFtcCggYmFzZUYwLCAwLjAsIDAuOTk5OSApICk7IC8vIGd1YXJkIGFnYWluc3QgMS4wXHJcblx0XHR2ZWMzIFIxID0gSW9yVG9GcmVzbmVsMCggYmFzZUlPUiwgaXJpZGVzY2VuY2VJT1IgKTtcclxuXHRcdHZlYzMgUjIzID0gRl9TY2hsaWNrKCBSMSwgMS4wLCBjb3NUaGV0YTIgKTtcclxuXHRcdHZlYzMgcGhpMjMgPSB2ZWMzKCAwLjAgKTtcclxuXHRcdGlmICggYmFzZUlPUlsgMCBdIDwgaXJpZGVzY2VuY2VJT1IgKSBwaGkyM1sgMCBdID0gUEk7XHJcblx0XHRpZiAoIGJhc2VJT1JbIDEgXSA8IGlyaWRlc2NlbmNlSU9SICkgcGhpMjNbIDEgXSA9IFBJO1xyXG5cdFx0aWYgKCBiYXNlSU9SWyAyIF0gPCBpcmlkZXNjZW5jZUlPUiApIHBoaTIzWyAyIF0gPSBQSTtcclxuXHJcblx0XHQvLyBQaGFzZSBzaGlmdFxyXG5cdFx0ZmxvYXQgT1BEID0gMi4wICogaXJpZGVzY2VuY2VJT1IgKiB0aGluRmlsbVRoaWNrbmVzcyAqIGNvc1RoZXRhMjtcclxuXHRcdHZlYzMgcGhpID0gdmVjMyggcGhpMjEgKSArIHBoaTIzO1xyXG5cclxuXHRcdC8vIENvbXBvdW5kIHRlcm1zXHJcblx0XHR2ZWMzIFIxMjMgPSBjbGFtcCggUjEyICogUjIzLCAxZS01LCAwLjk5OTkgKTtcclxuXHRcdHZlYzMgcjEyMyA9IHNxcnQoIFIxMjMgKTtcclxuXHRcdHZlYzMgUnMgPSBwb3cyKCBUMTIxICkgKiBSMjMgLyAoIHZlYzMoIDEuMCApIC0gUjEyMyApO1xyXG5cclxuXHRcdC8vIFJlZmxlY3RhbmNlIHRlcm0gZm9yIG0gPSAwIChEQyB0ZXJtIGFtcGxpdHVkZSlcclxuXHRcdHZlYzMgQzAgPSBSMTIgKyBScztcclxuXHRcdEkgPSBDMDtcclxuXHJcblx0XHQvLyBSZWZsZWN0YW5jZSB0ZXJtIGZvciBtID4gMCAocGFpcnMgb2YgZGlyYWNzKVxyXG5cdFx0dmVjMyBDbSA9IFJzIC0gVDEyMTtcclxuXHRcdGZvciAoIGludCBtID0gMTsgbSA8PSAyOyArKyBtICkge1xyXG5cclxuXHRcdFx0Q20gKj0gcjEyMztcclxuXHRcdFx0dmVjMyBTbSA9IDIuMCAqIGV2YWxTZW5zaXRpdml0eSggZmxvYXQoIG0gKSAqIE9QRCwgZmxvYXQoIG0gKSAqIHBoaSApO1xyXG5cdFx0XHRJICs9IENtICogU207XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIFNpbmNlIG91dCBvZiBnYW11dCBjb2xvcnMgbWlnaHQgYmUgcHJvZHVjZWQsIG5lZ2F0aXZlIGNvbG9yIHZhbHVlcyBhcmUgY2xhbXBlZCB0byAwLlxyXG5cdFx0cmV0dXJuIG1heCggSSwgdmVjMyggMC4wICkgKTtcclxuXHJcblx0fVxyXG5cclxuI2VuZGlmXHJcblxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWZkZWYgVVNFX0JVTVBNQVBcclxuXHJcblx0dW5pZm9ybSBzYW1wbGVyMkQgYnVtcE1hcDtcclxuXHR1bmlmb3JtIGZsb2F0IGJ1bXBTY2FsZTtcclxuXHJcblx0Ly8gQnVtcCBNYXBwaW5nIFVucGFyYW1ldHJpemVkIFN1cmZhY2VzIG9uIHRoZSBHUFUgYnkgTW9ydGVuIFMuIE1pa2tlbHNlblxyXG5cdC8vIGh0dHBzOi8vbW1pa2suZ2l0aHViLmlvL3BhcGVyczNkL21tX3NmZ3JhZF9idW1wLnBkZlxyXG5cclxuXHQvLyBFdmFsdWF0ZSB0aGUgZGVyaXZhdGl2ZSBvZiB0aGUgaGVpZ2h0IHcuci50LiBzY3JlZW4tc3BhY2UgdXNpbmcgZm9yd2FyZCBkaWZmZXJlbmNpbmcgKGxpc3RpbmcgMilcclxuXHJcblx0dmVjMiBkSGR4eV9md2QoKSB7XHJcblxyXG5cdFx0dmVjMiBkU1RkeCA9IGRGZHgoIHZCdW1wTWFwVXYgKTtcclxuXHRcdHZlYzIgZFNUZHkgPSBkRmR5KCB2QnVtcE1hcFV2ICk7XHJcblxyXG5cdFx0ZmxvYXQgSGxsID0gYnVtcFNjYWxlICogdGV4dHVyZTJEKCBidW1wTWFwLCB2QnVtcE1hcFV2ICkueDtcclxuXHRcdGZsb2F0IGRCeCA9IGJ1bXBTY2FsZSAqIHRleHR1cmUyRCggYnVtcE1hcCwgdkJ1bXBNYXBVdiArIGRTVGR4ICkueCAtIEhsbDtcclxuXHRcdGZsb2F0IGRCeSA9IGJ1bXBTY2FsZSAqIHRleHR1cmUyRCggYnVtcE1hcCwgdkJ1bXBNYXBVdiArIGRTVGR5ICkueCAtIEhsbDtcclxuXHJcblx0XHRyZXR1cm4gdmVjMiggZEJ4LCBkQnkgKTtcclxuXHJcblx0fVxyXG5cclxuXHR2ZWMzIHBlcnR1cmJOb3JtYWxBcmIoIHZlYzMgc3VyZl9wb3MsIHZlYzMgc3VyZl9ub3JtLCB2ZWMyIGRIZHh5LCBmbG9hdCBmYWNlRGlyZWN0aW9uICkge1xyXG5cclxuXHRcdC8vIG5vcm1hbGl6ZSBpcyBkb25lIHRvIGVuc3VyZSB0aGF0IHRoZSBidW1wIG1hcCBsb29rcyB0aGUgc2FtZSByZWdhcmRsZXNzIG9mIHRoZSB0ZXh0dXJlJ3Mgc2NhbGVcclxuXHRcdHZlYzMgdlNpZ21hWCA9IG5vcm1hbGl6ZSggZEZkeCggc3VyZl9wb3MueHl6ICkgKTtcclxuXHRcdHZlYzMgdlNpZ21hWSA9IG5vcm1hbGl6ZSggZEZkeSggc3VyZl9wb3MueHl6ICkgKTtcclxuXHRcdHZlYzMgdk4gPSBzdXJmX25vcm07IC8vIG5vcm1hbGl6ZWRcclxuXHJcblx0XHR2ZWMzIFIxID0gY3Jvc3MoIHZTaWdtYVksIHZOICk7XHJcblx0XHR2ZWMzIFIyID0gY3Jvc3MoIHZOLCB2U2lnbWFYICk7XHJcblxyXG5cdFx0ZmxvYXQgZkRldCA9IGRvdCggdlNpZ21hWCwgUjEgKSAqIGZhY2VEaXJlY3Rpb247XHJcblxyXG5cdFx0dmVjMyB2R3JhZCA9IHNpZ24oIGZEZXQgKSAqICggZEhkeHkueCAqIFIxICsgZEhkeHkueSAqIFIyICk7XHJcblx0XHRyZXR1cm4gbm9ybWFsaXplKCBhYnMoIGZEZXQgKSAqIHN1cmZfbm9ybSAtIHZHcmFkICk7XHJcblxyXG5cdH1cclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWYgTlVNX0NMSVBQSU5HX1BMQU5FUyA+IDBcclxuXHJcblx0dmVjNCBwbGFuZTtcclxuXHJcblx0I2lmZGVmIEFMUEhBX1RPX0NPVkVSQUdFXHJcblxyXG5cdFx0ZmxvYXQgZGlzdGFuY2VUb1BsYW5lLCBkaXN0YW5jZUdyYWRpZW50O1xyXG5cdFx0ZmxvYXQgY2xpcE9wYWNpdHkgPSAxLjA7XHJcblxyXG5cdFx0I3ByYWdtYSB1bnJvbGxfbG9vcF9zdGFydFxyXG5cdFx0Zm9yICggaW50IGkgPSAwOyBpIDwgVU5JT05fQ0xJUFBJTkdfUExBTkVTOyBpICsrICkge1xyXG5cclxuXHRcdFx0cGxhbmUgPSBjbGlwcGluZ1BsYW5lc1sgaSBdO1xyXG5cdFx0XHRkaXN0YW5jZVRvUGxhbmUgPSAtIGRvdCggdkNsaXBQb3NpdGlvbiwgcGxhbmUueHl6ICkgKyBwbGFuZS53O1xyXG5cdFx0XHRkaXN0YW5jZUdyYWRpZW50ID0gZndpZHRoKCBkaXN0YW5jZVRvUGxhbmUgKSAvIDIuMDtcclxuXHRcdFx0Y2xpcE9wYWNpdHkgKj0gc21vb3Roc3RlcCggLSBkaXN0YW5jZUdyYWRpZW50LCBkaXN0YW5jZUdyYWRpZW50LCBkaXN0YW5jZVRvUGxhbmUgKTtcclxuXHJcblx0XHRcdGlmICggY2xpcE9wYWNpdHkgPT0gMC4wICkgZGlzY2FyZDtcclxuXHJcblx0XHR9XHJcblx0XHQjcHJhZ21hIHVucm9sbF9sb29wX2VuZFxyXG5cclxuXHRcdCNpZiBVTklPTl9DTElQUElOR19QTEFORVMgPCBOVU1fQ0xJUFBJTkdfUExBTkVTXHJcblxyXG5cdFx0XHRmbG9hdCB1bmlvbkNsaXBPcGFjaXR5ID0gMS4wO1xyXG5cclxuXHRcdFx0I3ByYWdtYSB1bnJvbGxfbG9vcF9zdGFydFxyXG5cdFx0XHRmb3IgKCBpbnQgaSA9IFVOSU9OX0NMSVBQSU5HX1BMQU5FUzsgaSA8IE5VTV9DTElQUElOR19QTEFORVM7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdHBsYW5lID0gY2xpcHBpbmdQbGFuZXNbIGkgXTtcclxuXHRcdFx0XHRkaXN0YW5jZVRvUGxhbmUgPSAtIGRvdCggdkNsaXBQb3NpdGlvbiwgcGxhbmUueHl6ICkgKyBwbGFuZS53O1xyXG5cdFx0XHRcdGRpc3RhbmNlR3JhZGllbnQgPSBmd2lkdGgoIGRpc3RhbmNlVG9QbGFuZSApIC8gMi4wO1xyXG5cdFx0XHRcdHVuaW9uQ2xpcE9wYWNpdHkgKj0gMS4wIC0gc21vb3Roc3RlcCggLSBkaXN0YW5jZUdyYWRpZW50LCBkaXN0YW5jZUdyYWRpZW50LCBkaXN0YW5jZVRvUGxhbmUgKTtcclxuXHJcblx0XHRcdH1cclxuXHRcdFx0I3ByYWdtYSB1bnJvbGxfbG9vcF9lbmRcclxuXHJcblx0XHRcdGNsaXBPcGFjaXR5ICo9IDEuMCAtIHVuaW9uQ2xpcE9wYWNpdHk7XHJcblxyXG5cdFx0I2VuZGlmXHJcblxyXG5cdFx0ZGlmZnVzZUNvbG9yLmEgKj0gY2xpcE9wYWNpdHk7XHJcblxyXG5cdFx0aWYgKCBkaWZmdXNlQ29sb3IuYSA9PSAwLjAgKSBkaXNjYXJkO1xyXG5cclxuXHQjZWxzZVxyXG5cclxuXHRcdCNwcmFnbWEgdW5yb2xsX2xvb3Bfc3RhcnRcclxuXHRcdGZvciAoIGludCBpID0gMDsgaSA8IFVOSU9OX0NMSVBQSU5HX1BMQU5FUzsgaSArKyApIHtcclxuXHJcblx0XHRcdHBsYW5lID0gY2xpcHBpbmdQbGFuZXNbIGkgXTtcclxuXHRcdFx0aWYgKCBkb3QoIHZDbGlwUG9zaXRpb24sIHBsYW5lLnh5eiApID4gcGxhbmUudyApIGRpc2NhcmQ7XHJcblxyXG5cdFx0fVxyXG5cdFx0I3ByYWdtYSB1bnJvbGxfbG9vcF9lbmRcclxuXHJcblx0XHQjaWYgVU5JT05fQ0xJUFBJTkdfUExBTkVTIDwgTlVNX0NMSVBQSU5HX1BMQU5FU1xyXG5cclxuXHRcdFx0Ym9vbCBjbGlwcGVkID0gdHJ1ZTtcclxuXHJcblx0XHRcdCNwcmFnbWEgdW5yb2xsX2xvb3Bfc3RhcnRcclxuXHRcdFx0Zm9yICggaW50IGkgPSBVTklPTl9DTElQUElOR19QTEFORVM7IGkgPCBOVU1fQ0xJUFBJTkdfUExBTkVTOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRwbGFuZSA9IGNsaXBwaW5nUGxhbmVzWyBpIF07XHJcblx0XHRcdFx0Y2xpcHBlZCA9ICggZG90KCB2Q2xpcFBvc2l0aW9uLCBwbGFuZS54eXogKSA+IHBsYW5lLncgKSAmJiBjbGlwcGVkO1xyXG5cclxuXHRcdFx0fVxyXG5cdFx0XHQjcHJhZ21hIHVucm9sbF9sb29wX2VuZFxyXG5cclxuXHRcdFx0aWYgKCBjbGlwcGVkICkgZGlzY2FyZDtcclxuXHJcblx0XHQjZW5kaWZcclxuXHJcblx0I2VuZGlmXHJcblxyXG4jZW5kaWZcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuI2lmIE5VTV9DTElQUElOR19QTEFORVMgPiAwXHJcblxyXG5cdHZhcnlpbmcgdmVjMyB2Q2xpcFBvc2l0aW9uO1xyXG5cclxuXHR1bmlmb3JtIHZlYzQgY2xpcHBpbmdQbGFuZXNbIE5VTV9DTElQUElOR19QTEFORVMgXTtcclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWYgTlVNX0NMSVBQSU5HX1BMQU5FUyA+IDBcclxuXHJcblx0dmFyeWluZyB2ZWMzIHZDbGlwUG9zaXRpb247XHJcblxyXG4jZW5kaWZcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuI2lmIE5VTV9DTElQUElOR19QTEFORVMgPiAwXHJcblxyXG5cdHZDbGlwUG9zaXRpb24gPSAtIG12UG9zaXRpb24ueHl6O1xyXG5cclxuI2VuZGlmXHJcbmA7XHJcbiIsImV4cG9ydCBkZWZhdWx0IC8qIGdsc2wgKi9gXHJcbiNpZiBkZWZpbmVkKCBVU0VfQ09MT1JfQUxQSEEgKVxyXG5cclxuXHRkaWZmdXNlQ29sb3IgKj0gdkNvbG9yO1xyXG5cclxuI2VsaWYgZGVmaW5lZCggVVNFX0NPTE9SIClcclxuXHJcblx0ZGlmZnVzZUNvbG9yLnJnYiAqPSB2Q29sb3I7XHJcblxyXG4jZW5kaWZcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuI2lmIGRlZmluZWQoIFVTRV9DT0xPUl9BTFBIQSApXHJcblxyXG5cdHZhcnlpbmcgdmVjNCB2Q29sb3I7XHJcblxyXG4jZWxpZiBkZWZpbmVkKCBVU0VfQ09MT1IgKVxyXG5cclxuXHR2YXJ5aW5nIHZlYzMgdkNvbG9yO1xyXG5cclxuI2VuZGlmXHJcbmA7XHJcbiIsImV4cG9ydCBkZWZhdWx0IC8qIGdsc2wgKi9gXHJcbiNpZiBkZWZpbmVkKCBVU0VfQ09MT1JfQUxQSEEgKVxyXG5cclxuXHR2YXJ5aW5nIHZlYzQgdkNvbG9yO1xyXG5cclxuI2VsaWYgZGVmaW5lZCggVVNFX0NPTE9SICkgfHwgZGVmaW5lZCggVVNFX0lOU1RBTkNJTkdfQ09MT1IgKVxyXG5cclxuXHR2YXJ5aW5nIHZlYzMgdkNvbG9yO1xyXG5cclxuI2VuZGlmXHJcbmA7XHJcbiIsImV4cG9ydCBkZWZhdWx0IC8qIGdsc2wgKi9gXHJcbiNpZiBkZWZpbmVkKCBVU0VfQ09MT1JfQUxQSEEgKVxyXG5cclxuXHR2Q29sb3IgPSB2ZWM0KCAxLjAgKTtcclxuXHJcbiNlbGlmIGRlZmluZWQoIFVTRV9DT0xPUiApIHx8IGRlZmluZWQoIFVTRV9JTlNUQU5DSU5HX0NPTE9SIClcclxuXHJcblx0dkNvbG9yID0gdmVjMyggMS4wICk7XHJcblxyXG4jZW5kaWZcclxuXHJcbiNpZmRlZiBVU0VfQ09MT1JcclxuXHJcblx0dkNvbG9yICo9IGNvbG9yO1xyXG5cclxuI2VuZGlmXHJcblxyXG4jaWZkZWYgVVNFX0lOU1RBTkNJTkdfQ09MT1JcclxuXHJcblx0dkNvbG9yLnh5eiAqPSBpbnN0YW5jZUNvbG9yLnh5ejtcclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jZGVmaW5lIFBJIDMuMTQxNTkyNjUzNTg5NzkzXHJcbiNkZWZpbmUgUEkyIDYuMjgzMTg1MzA3MTc5NTg2XHJcbiNkZWZpbmUgUElfSEFMRiAxLjU3MDc5NjMyNjc5NDg5NjZcclxuI2RlZmluZSBSRUNJUFJPQ0FMX1BJIDAuMzE4MzA5ODg2MTgzNzkwN1xyXG4jZGVmaW5lIFJFQ0lQUk9DQUxfUEkyIDAuMTU5MTU0OTQzMDkxODk1MzVcclxuI2RlZmluZSBFUFNJTE9OIDFlLTZcclxuXHJcbiNpZm5kZWYgc2F0dXJhdGVcclxuLy8gPHRvbmVtYXBwaW5nX3BhcnNfZnJhZ21lbnQ+IG1heSBoYXZlIGRlZmluZWQgc2F0dXJhdGUoKSBhbHJlYWR5XHJcbiNkZWZpbmUgc2F0dXJhdGUoIGEgKSBjbGFtcCggYSwgMC4wLCAxLjAgKVxyXG4jZW5kaWZcclxuI2RlZmluZSB3aGl0ZUNvbXBsZW1lbnQoIGEgKSAoIDEuMCAtIHNhdHVyYXRlKCBhICkgKVxyXG5cclxuZmxvYXQgcG93MiggY29uc3QgaW4gZmxvYXQgeCApIHsgcmV0dXJuIHgqeDsgfVxyXG52ZWMzIHBvdzIoIGNvbnN0IGluIHZlYzMgeCApIHsgcmV0dXJuIHgqeDsgfVxyXG5mbG9hdCBwb3czKCBjb25zdCBpbiBmbG9hdCB4ICkgeyByZXR1cm4geCp4Kng7IH1cclxuZmxvYXQgcG93NCggY29uc3QgaW4gZmxvYXQgeCApIHsgZmxvYXQgeDIgPSB4Kng7IHJldHVybiB4Mip4MjsgfVxyXG5mbG9hdCBtYXgzKCBjb25zdCBpbiB2ZWMzIHYgKSB7IHJldHVybiBtYXgoIG1heCggdi54LCB2LnkgKSwgdi56ICk7IH1cclxuZmxvYXQgYXZlcmFnZSggY29uc3QgaW4gdmVjMyB2ICkgeyByZXR1cm4gZG90KCB2LCB2ZWMzKCAwLjMzMzMzMzMgKSApOyB9XHJcblxyXG4vLyBleHBlY3RzIHZhbHVlcyBpbiB0aGUgcmFuZ2Ugb2YgWzAsMV14WzAsMV0sIHJldHVybnMgdmFsdWVzIGluIHRoZSBbMCwxXSByYW5nZS5cclxuLy8gZG8gbm90IGNvbGxhcHNlIGludG8gYSBzaW5nbGUgZnVuY3Rpb24gcGVyOiBodHRwOi8vYnl0ZWJsYWNrc21pdGguY29tL2ltcHJvdmVtZW50cy10by10aGUtY2Fub25pY2FsLW9uZS1saW5lci1nbHNsLXJhbmQtZm9yLW9wZW5nbC1lcy0yLTAvXHJcbmhpZ2hwIGZsb2F0IHJhbmQoIGNvbnN0IGluIHZlYzIgdXYgKSB7XHJcblxyXG5cdGNvbnN0IGhpZ2hwIGZsb2F0IGEgPSAxMi45ODk4LCBiID0gNzguMjMzLCBjID0gNDM3NTguNTQ1MztcclxuXHRoaWdocCBmbG9hdCBkdCA9IGRvdCggdXYueHksIHZlYzIoIGEsYiApICksIHNuID0gbW9kKCBkdCwgUEkgKTtcclxuXHJcblx0cmV0dXJuIGZyYWN0KCBzaW4oIHNuICkgKiBjICk7XHJcblxyXG59XHJcblxyXG4jaWZkZWYgSElHSF9QUkVDSVNJT05cclxuXHRmbG9hdCBwcmVjaXNpb25TYWZlTGVuZ3RoKCB2ZWMzIHYgKSB7IHJldHVybiBsZW5ndGgoIHYgKTsgfVxyXG4jZWxzZVxyXG5cdGZsb2F0IHByZWNpc2lvblNhZmVMZW5ndGgoIHZlYzMgdiApIHtcclxuXHRcdGZsb2F0IG1heENvbXBvbmVudCA9IG1heDMoIGFicyggdiApICk7XHJcblx0XHRyZXR1cm4gbGVuZ3RoKCB2IC8gbWF4Q29tcG9uZW50ICkgKiBtYXhDb21wb25lbnQ7XHJcblx0fVxyXG4jZW5kaWZcclxuXHJcbnN0cnVjdCBJbmNpZGVudExpZ2h0IHtcclxuXHR2ZWMzIGNvbG9yO1xyXG5cdHZlYzMgZGlyZWN0aW9uO1xyXG5cdGJvb2wgdmlzaWJsZTtcclxufTtcclxuXHJcbnN0cnVjdCBSZWZsZWN0ZWRMaWdodCB7XHJcblx0dmVjMyBkaXJlY3REaWZmdXNlO1xyXG5cdHZlYzMgZGlyZWN0U3BlY3VsYXI7XHJcblx0dmVjMyBpbmRpcmVjdERpZmZ1c2U7XHJcblx0dmVjMyBpbmRpcmVjdFNwZWN1bGFyO1xyXG59O1xyXG5cclxuI2lmZGVmIFVTRV9BTFBIQUhBU0hcclxuXHJcblx0dmFyeWluZyB2ZWMzIHZQb3NpdGlvbjtcclxuXHJcbiNlbmRpZlxyXG5cclxudmVjMyB0cmFuc2Zvcm1EaXJlY3Rpb24oIGluIHZlYzMgZGlyLCBpbiBtYXQ0IG1hdHJpeCApIHtcclxuXHJcblx0cmV0dXJuIG5vcm1hbGl6ZSggKCBtYXRyaXggKiB2ZWM0KCBkaXIsIDAuMCApICkueHl6ICk7XHJcblxyXG59XHJcblxyXG52ZWMzIGludmVyc2VUcmFuc2Zvcm1EaXJlY3Rpb24oIGluIHZlYzMgZGlyLCBpbiBtYXQ0IG1hdHJpeCApIHtcclxuXHJcblx0Ly8gZGlyIGNhbiBiZSBlaXRoZXIgYSBkaXJlY3Rpb24gdmVjdG9yIG9yIGEgbm9ybWFsIHZlY3RvclxyXG5cdC8vIHVwcGVyLWxlZnQgM3gzIG9mIG1hdHJpeCBpcyBhc3N1bWVkIHRvIGJlIG9ydGhvZ29uYWxcclxuXHJcblx0cmV0dXJuIG5vcm1hbGl6ZSggKCB2ZWM0KCBkaXIsIDAuMCApICogbWF0cml4ICkueHl6ICk7XHJcblxyXG59XHJcblxyXG5tYXQzIHRyYW5zcG9zZU1hdDMoIGNvbnN0IGluIG1hdDMgbSApIHtcclxuXHJcblx0bWF0MyB0bXA7XHJcblxyXG5cdHRtcFsgMCBdID0gdmVjMyggbVsgMCBdLngsIG1bIDEgXS54LCBtWyAyIF0ueCApO1xyXG5cdHRtcFsgMSBdID0gdmVjMyggbVsgMCBdLnksIG1bIDEgXS55LCBtWyAyIF0ueSApO1xyXG5cdHRtcFsgMiBdID0gdmVjMyggbVsgMCBdLnosIG1bIDEgXS56LCBtWyAyIF0ueiApO1xyXG5cclxuXHRyZXR1cm4gdG1wO1xyXG5cclxufVxyXG5cclxuZmxvYXQgbHVtaW5hbmNlKCBjb25zdCBpbiB2ZWMzIHJnYiApIHtcclxuXHJcblx0Ly8gYXNzdW1lcyByZ2IgaXMgaW4gbGluZWFyIGNvbG9yIHNwYWNlIHdpdGggc1JHQiBwcmltYXJpZXMgYW5kIEQ2NSB3aGl0ZSBwb2ludFxyXG5cclxuXHRjb25zdCB2ZWMzIHdlaWdodHMgPSB2ZWMzKCAwLjIxMjY3MjksIDAuNzE1MTUyMiwgMC4wNzIxNzUwICk7XHJcblxyXG5cdHJldHVybiBkb3QoIHdlaWdodHMsIHJnYiApO1xyXG5cclxufVxyXG5cclxuYm9vbCBpc1BlcnNwZWN0aXZlTWF0cml4KCBtYXQ0IG0gKSB7XHJcblxyXG5cdHJldHVybiBtWyAyIF1bIDMgXSA9PSAtIDEuMDtcclxuXHJcbn1cclxuXHJcbnZlYzIgZXF1aXJlY3RVdiggaW4gdmVjMyBkaXIgKSB7XHJcblxyXG5cdC8vIGRpciBpcyBhc3N1bWVkIHRvIGJlIHVuaXQgbGVuZ3RoXHJcblxyXG5cdGZsb2F0IHUgPSBhdGFuKCBkaXIueiwgZGlyLnggKSAqIFJFQ0lQUk9DQUxfUEkyICsgMC41O1xyXG5cclxuXHRmbG9hdCB2ID0gYXNpbiggY2xhbXAoIGRpci55LCAtIDEuMCwgMS4wICkgKSAqIFJFQ0lQUk9DQUxfUEkgKyAwLjU7XHJcblxyXG5cdHJldHVybiB2ZWMyKCB1LCB2ICk7XHJcblxyXG59XHJcblxyXG52ZWMzIEJSREZfTGFtYmVydCggY29uc3QgaW4gdmVjMyBkaWZmdXNlQ29sb3IgKSB7XHJcblxyXG5cdHJldHVybiBSRUNJUFJPQ0FMX1BJICogZGlmZnVzZUNvbG9yO1xyXG5cclxufSAvLyB2YWxpZGF0ZWRcclxuXHJcbnZlYzMgRl9TY2hsaWNrKCBjb25zdCBpbiB2ZWMzIGYwLCBjb25zdCBpbiBmbG9hdCBmOTAsIGNvbnN0IGluIGZsb2F0IGRvdFZIICkge1xyXG5cclxuXHQvLyBPcmlnaW5hbCBhcHByb3hpbWF0aW9uIGJ5IENocmlzdG9waGUgU2NobGljayAnOTRcclxuXHQvLyBmbG9hdCBmcmVzbmVsID0gcG93KCAxLjAgLSBkb3RWSCwgNS4wICk7XHJcblxyXG5cdC8vIE9wdGltaXplZCB2YXJpYW50IChwcmVzZW50ZWQgYnkgRXBpYyBhdCBTSUdHUkFQSCAnMTMpXHJcblx0Ly8gaHR0cHM6Ly9jZG4yLnVucmVhbGVuZ2luZS5jb20vUmVzb3VyY2VzL2ZpbGVzLzIwMTNTaWdncmFwaFByZXNlbnRhdGlvbnNOb3Rlcy0yNjkxNTczOC5wZGZcclxuXHRmbG9hdCBmcmVzbmVsID0gZXhwMiggKCAtIDUuNTU0NzMgKiBkb3RWSCAtIDYuOTgzMTYgKSAqIGRvdFZIICk7XHJcblxyXG5cdHJldHVybiBmMCAqICggMS4wIC0gZnJlc25lbCApICsgKCBmOTAgKiBmcmVzbmVsICk7XHJcblxyXG59IC8vIHZhbGlkYXRlZFxyXG5cclxuZmxvYXQgRl9TY2hsaWNrKCBjb25zdCBpbiBmbG9hdCBmMCwgY29uc3QgaW4gZmxvYXQgZjkwLCBjb25zdCBpbiBmbG9hdCBkb3RWSCApIHtcclxuXHJcblx0Ly8gT3JpZ2luYWwgYXBwcm94aW1hdGlvbiBieSBDaHJpc3RvcGhlIFNjaGxpY2sgJzk0XHJcblx0Ly8gZmxvYXQgZnJlc25lbCA9IHBvdyggMS4wIC0gZG90VkgsIDUuMCApO1xyXG5cclxuXHQvLyBPcHRpbWl6ZWQgdmFyaWFudCAocHJlc2VudGVkIGJ5IEVwaWMgYXQgU0lHR1JBUEggJzEzKVxyXG5cdC8vIGh0dHBzOi8vY2RuMi51bnJlYWxlbmdpbmUuY29tL1Jlc291cmNlcy9maWxlcy8yMDEzU2lnZ3JhcGhQcmVzZW50YXRpb25zTm90ZXMtMjY5MTU3MzgucGRmXHJcblx0ZmxvYXQgZnJlc25lbCA9IGV4cDIoICggLSA1LjU1NDczICogZG90VkggLSA2Ljk4MzE2ICkgKiBkb3RWSCApO1xyXG5cclxuXHRyZXR1cm4gZjAgKiAoIDEuMCAtIGZyZXNuZWwgKSArICggZjkwICogZnJlc25lbCApO1xyXG5cclxufSAvLyB2YWxpZGF0ZWRcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuI2lmZGVmIEVOVk1BUF9UWVBFX0NVQkVfVVZcclxuXHJcblx0I2RlZmluZSBjdWJlVVZfbWluTWlwTGV2ZWwgNC4wXHJcblx0I2RlZmluZSBjdWJlVVZfbWluVGlsZVNpemUgMTYuMFxyXG5cclxuXHQvLyBUaGVzZSBzaGFkZXIgZnVuY3Rpb25zIGNvbnZlcnQgYmV0d2VlbiB0aGUgVVYgY29vcmRpbmF0ZXMgb2YgYSBzaW5nbGUgZmFjZSBvZlxyXG5cdC8vIGEgY3ViZW1hcCwgdGhlIDAtNSBpbnRlZ2VyIGluZGV4IG9mIGEgY3ViZSBmYWNlLCBhbmQgdGhlIGRpcmVjdGlvbiB2ZWN0b3IgZm9yXHJcblx0Ly8gc2FtcGxpbmcgYSB0ZXh0dXJlQ3ViZSAobm90IGdlbmVyYWxseSBub3JtYWxpemVkICkuXHJcblxyXG5cdGZsb2F0IGdldEZhY2UoIHZlYzMgZGlyZWN0aW9uICkge1xyXG5cclxuXHRcdHZlYzMgYWJzRGlyZWN0aW9uID0gYWJzKCBkaXJlY3Rpb24gKTtcclxuXHJcblx0XHRmbG9hdCBmYWNlID0gLSAxLjA7XHJcblxyXG5cdFx0aWYgKCBhYnNEaXJlY3Rpb24ueCA+IGFic0RpcmVjdGlvbi56ICkge1xyXG5cclxuXHRcdFx0aWYgKCBhYnNEaXJlY3Rpb24ueCA+IGFic0RpcmVjdGlvbi55IClcclxuXHJcblx0XHRcdFx0ZmFjZSA9IGRpcmVjdGlvbi54ID4gMC4wID8gMC4wIDogMy4wO1xyXG5cclxuXHRcdFx0ZWxzZVxyXG5cclxuXHRcdFx0XHRmYWNlID0gZGlyZWN0aW9uLnkgPiAwLjAgPyAxLjAgOiA0LjA7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdGlmICggYWJzRGlyZWN0aW9uLnogPiBhYnNEaXJlY3Rpb24ueSApXHJcblxyXG5cdFx0XHRcdGZhY2UgPSBkaXJlY3Rpb24ueiA+IDAuMCA/IDIuMCA6IDUuMDtcclxuXHJcblx0XHRcdGVsc2VcclxuXHJcblx0XHRcdFx0ZmFjZSA9IGRpcmVjdGlvbi55ID4gMC4wID8gMS4wIDogNC4wO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gZmFjZTtcclxuXHJcblx0fVxyXG5cclxuXHQvLyBSSCBjb29yZGluYXRlIHN5c3RlbTsgUE1SRU0gZmFjZS1pbmRleGluZyBjb252ZW50aW9uXHJcblx0dmVjMiBnZXRVViggdmVjMyBkaXJlY3Rpb24sIGZsb2F0IGZhY2UgKSB7XHJcblxyXG5cdFx0dmVjMiB1djtcclxuXHJcblx0XHRpZiAoIGZhY2UgPT0gMC4wICkge1xyXG5cclxuXHRcdFx0dXYgPSB2ZWMyKCBkaXJlY3Rpb24ueiwgZGlyZWN0aW9uLnkgKSAvIGFicyggZGlyZWN0aW9uLnggKTsgLy8gcG9zIHhcclxuXHJcblx0XHR9IGVsc2UgaWYgKCBmYWNlID09IDEuMCApIHtcclxuXHJcblx0XHRcdHV2ID0gdmVjMiggLSBkaXJlY3Rpb24ueCwgLSBkaXJlY3Rpb24ueiApIC8gYWJzKCBkaXJlY3Rpb24ueSApOyAvLyBwb3MgeVxyXG5cclxuXHRcdH0gZWxzZSBpZiAoIGZhY2UgPT0gMi4wICkge1xyXG5cclxuXHRcdFx0dXYgPSB2ZWMyKCAtIGRpcmVjdGlvbi54LCBkaXJlY3Rpb24ueSApIC8gYWJzKCBkaXJlY3Rpb24ueiApOyAvLyBwb3MgelxyXG5cclxuXHRcdH0gZWxzZSBpZiAoIGZhY2UgPT0gMy4wICkge1xyXG5cclxuXHRcdFx0dXYgPSB2ZWMyKCAtIGRpcmVjdGlvbi56LCBkaXJlY3Rpb24ueSApIC8gYWJzKCBkaXJlY3Rpb24ueCApOyAvLyBuZWcgeFxyXG5cclxuXHRcdH0gZWxzZSBpZiAoIGZhY2UgPT0gNC4wICkge1xyXG5cclxuXHRcdFx0dXYgPSB2ZWMyKCAtIGRpcmVjdGlvbi54LCBkaXJlY3Rpb24ueiApIC8gYWJzKCBkaXJlY3Rpb24ueSApOyAvLyBuZWcgeVxyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHR1diA9IHZlYzIoIGRpcmVjdGlvbi54LCBkaXJlY3Rpb24ueSApIC8gYWJzKCBkaXJlY3Rpb24ueiApOyAvLyBuZWcgelxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gMC41ICogKCB1diArIDEuMCApO1xyXG5cclxuXHR9XHJcblxyXG5cdHZlYzMgYmlsaW5lYXJDdWJlVVYoIHNhbXBsZXIyRCBlbnZNYXAsIHZlYzMgZGlyZWN0aW9uLCBmbG9hdCBtaXBJbnQgKSB7XHJcblxyXG5cdFx0ZmxvYXQgZmFjZSA9IGdldEZhY2UoIGRpcmVjdGlvbiApO1xyXG5cclxuXHRcdGZsb2F0IGZpbHRlckludCA9IG1heCggY3ViZVVWX21pbk1pcExldmVsIC0gbWlwSW50LCAwLjAgKTtcclxuXHJcblx0XHRtaXBJbnQgPSBtYXgoIG1pcEludCwgY3ViZVVWX21pbk1pcExldmVsICk7XHJcblxyXG5cdFx0ZmxvYXQgZmFjZVNpemUgPSBleHAyKCBtaXBJbnQgKTtcclxuXHJcblx0XHRoaWdocCB2ZWMyIHV2ID0gZ2V0VVYoIGRpcmVjdGlvbiwgZmFjZSApICogKCBmYWNlU2l6ZSAtIDIuMCApICsgMS4wOyAvLyAjMjUwNzFcclxuXHJcblx0XHRpZiAoIGZhY2UgPiAyLjAgKSB7XHJcblxyXG5cdFx0XHR1di55ICs9IGZhY2VTaXplO1xyXG5cclxuXHRcdFx0ZmFjZSAtPSAzLjA7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHV2LnggKz0gZmFjZSAqIGZhY2VTaXplO1xyXG5cclxuXHRcdHV2LnggKz0gZmlsdGVySW50ICogMy4wICogY3ViZVVWX21pblRpbGVTaXplO1xyXG5cclxuXHRcdHV2LnkgKz0gNC4wICogKCBleHAyKCBDVUJFVVZfTUFYX01JUCApIC0gZmFjZVNpemUgKTtcclxuXHJcblx0XHR1di54ICo9IENVQkVVVl9URVhFTF9XSURUSDtcclxuXHRcdHV2LnkgKj0gQ1VCRVVWX1RFWEVMX0hFSUdIVDtcclxuXHJcblx0XHQjaWZkZWYgdGV4dHVyZTJER3JhZEVYVFxyXG5cclxuXHRcdFx0cmV0dXJuIHRleHR1cmUyREdyYWRFWFQoIGVudk1hcCwgdXYsIHZlYzIoIDAuMCApLCB2ZWMyKCAwLjAgKSApLnJnYjsgLy8gZGlzYWJsZSBhbmlzb3Ryb3BpYyBmaWx0ZXJpbmdcclxuXHJcblx0XHQjZWxzZVxyXG5cclxuXHRcdFx0cmV0dXJuIHRleHR1cmUyRCggZW52TWFwLCB1diApLnJnYjtcclxuXHJcblx0XHQjZW5kaWZcclxuXHJcblx0fVxyXG5cclxuXHQvLyBUaGVzZSBkZWZpbmVzIG11c3QgbWF0Y2ggd2l0aCBQTVJFTUdlbmVyYXRvclxyXG5cclxuXHQjZGVmaW5lIGN1YmVVVl9yMCAxLjBcclxuXHQjZGVmaW5lIGN1YmVVVl9tMCAtIDIuMFxyXG5cdCNkZWZpbmUgY3ViZVVWX3IxIDAuOFxyXG5cdCNkZWZpbmUgY3ViZVVWX20xIC0gMS4wXHJcblx0I2RlZmluZSBjdWJlVVZfcjQgMC40XHJcblx0I2RlZmluZSBjdWJlVVZfbTQgMi4wXHJcblx0I2RlZmluZSBjdWJlVVZfcjUgMC4zMDVcclxuXHQjZGVmaW5lIGN1YmVVVl9tNSAzLjBcclxuXHQjZGVmaW5lIGN1YmVVVl9yNiAwLjIxXHJcblx0I2RlZmluZSBjdWJlVVZfbTYgNC4wXHJcblxyXG5cdGZsb2F0IHJvdWdobmVzc1RvTWlwKCBmbG9hdCByb3VnaG5lc3MgKSB7XHJcblxyXG5cdFx0ZmxvYXQgbWlwID0gMC4wO1xyXG5cclxuXHRcdGlmICggcm91Z2huZXNzID49IGN1YmVVVl9yMSApIHtcclxuXHJcblx0XHRcdG1pcCA9ICggY3ViZVVWX3IwIC0gcm91Z2huZXNzICkgKiAoIGN1YmVVVl9tMSAtIGN1YmVVVl9tMCApIC8gKCBjdWJlVVZfcjAgLSBjdWJlVVZfcjEgKSArIGN1YmVVVl9tMDtcclxuXHJcblx0XHR9IGVsc2UgaWYgKCByb3VnaG5lc3MgPj0gY3ViZVVWX3I0ICkge1xyXG5cclxuXHRcdFx0bWlwID0gKCBjdWJlVVZfcjEgLSByb3VnaG5lc3MgKSAqICggY3ViZVVWX200IC0gY3ViZVVWX20xICkgLyAoIGN1YmVVVl9yMSAtIGN1YmVVVl9yNCApICsgY3ViZVVWX20xO1xyXG5cclxuXHRcdH0gZWxzZSBpZiAoIHJvdWdobmVzcyA+PSBjdWJlVVZfcjUgKSB7XHJcblxyXG5cdFx0XHRtaXAgPSAoIGN1YmVVVl9yNCAtIHJvdWdobmVzcyApICogKCBjdWJlVVZfbTUgLSBjdWJlVVZfbTQgKSAvICggY3ViZVVWX3I0IC0gY3ViZVVWX3I1ICkgKyBjdWJlVVZfbTQ7XHJcblxyXG5cdFx0fSBlbHNlIGlmICggcm91Z2huZXNzID49IGN1YmVVVl9yNiApIHtcclxuXHJcblx0XHRcdG1pcCA9ICggY3ViZVVWX3I1IC0gcm91Z2huZXNzICkgKiAoIGN1YmVVVl9tNiAtIGN1YmVVVl9tNSApIC8gKCBjdWJlVVZfcjUgLSBjdWJlVVZfcjYgKSArIGN1YmVVVl9tNTtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0bWlwID0gLSAyLjAgKiBsb2cyKCAxLjE2ICogcm91Z2huZXNzICk7IC8vIDEuMTYgPSAxLjc5XjAuMjVcclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gbWlwO1xyXG5cclxuXHR9XHJcblxyXG5cdHZlYzQgdGV4dHVyZUN1YmVVViggc2FtcGxlcjJEIGVudk1hcCwgdmVjMyBzYW1wbGVEaXIsIGZsb2F0IHJvdWdobmVzcyApIHtcclxuXHJcblx0XHRmbG9hdCBtaXAgPSBjbGFtcCggcm91Z2huZXNzVG9NaXAoIHJvdWdobmVzcyApLCBjdWJlVVZfbTAsIENVQkVVVl9NQVhfTUlQICk7XHJcblxyXG5cdFx0ZmxvYXQgbWlwRiA9IGZyYWN0KCBtaXAgKTtcclxuXHJcblx0XHRmbG9hdCBtaXBJbnQgPSBmbG9vciggbWlwICk7XHJcblxyXG5cdFx0dmVjMyBjb2xvcjAgPSBiaWxpbmVhckN1YmVVViggZW52TWFwLCBzYW1wbGVEaXIsIG1pcEludCApO1xyXG5cclxuXHRcdGlmICggbWlwRiA9PSAwLjAgKSB7XHJcblxyXG5cdFx0XHRyZXR1cm4gdmVjNCggY29sb3IwLCAxLjAgKTtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0dmVjMyBjb2xvcjEgPSBiaWxpbmVhckN1YmVVViggZW52TWFwLCBzYW1wbGVEaXIsIG1pcEludCArIDEuMCApO1xyXG5cclxuXHRcdFx0cmV0dXJuIHZlYzQoIG1peCggY29sb3IwLCBjb2xvcjEsIG1pcEYgKSwgMS4wICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG4jZW5kaWZcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuXHJcbnZlYzMgdHJhbnNmb3JtZWROb3JtYWwgPSBvYmplY3ROb3JtYWw7XHJcbiNpZmRlZiBVU0VfVEFOR0VOVFxyXG5cclxuXHR2ZWMzIHRyYW5zZm9ybWVkVGFuZ2VudCA9IG9iamVjdFRhbmdlbnQ7XHJcblxyXG4jZW5kaWZcclxuXHJcbiNpZmRlZiBVU0VfQkFUQ0hJTkdcclxuXHJcblx0Ly8gdGhpcyBpcyBpbiBsaWV1IG9mIGEgcGVyLWluc3RhbmNlIG5vcm1hbC1tYXRyaXhcclxuXHQvLyBzaGVhciB0cmFuc2Zvcm1zIGluIHRoZSBpbnN0YW5jZSBtYXRyaXggYXJlIG5vdCBzdXBwb3J0ZWRcclxuXHJcblx0bWF0MyBibSA9IG1hdDMoIGJhdGNoaW5nTWF0cml4ICk7XHJcblx0dHJhbnNmb3JtZWROb3JtYWwgLz0gdmVjMyggZG90KCBibVsgMCBdLCBibVsgMCBdICksIGRvdCggYm1bIDEgXSwgYm1bIDEgXSApLCBkb3QoIGJtWyAyIF0sIGJtWyAyIF0gKSApO1xyXG5cdHRyYW5zZm9ybWVkTm9ybWFsID0gYm0gKiB0cmFuc2Zvcm1lZE5vcm1hbDtcclxuXHJcblx0I2lmZGVmIFVTRV9UQU5HRU5UXHJcblxyXG5cdFx0dHJhbnNmb3JtZWRUYW5nZW50ID0gYm0gKiB0cmFuc2Zvcm1lZFRhbmdlbnQ7XHJcblxyXG5cdCNlbmRpZlxyXG5cclxuI2VuZGlmXHJcblxyXG4jaWZkZWYgVVNFX0lOU1RBTkNJTkdcclxuXHJcblx0Ly8gdGhpcyBpcyBpbiBsaWV1IG9mIGEgcGVyLWluc3RhbmNlIG5vcm1hbC1tYXRyaXhcclxuXHQvLyBzaGVhciB0cmFuc2Zvcm1zIGluIHRoZSBpbnN0YW5jZSBtYXRyaXggYXJlIG5vdCBzdXBwb3J0ZWRcclxuXHJcblx0bWF0MyBpbSA9IG1hdDMoIGluc3RhbmNlTWF0cml4ICk7XHJcblx0dHJhbnNmb3JtZWROb3JtYWwgLz0gdmVjMyggZG90KCBpbVsgMCBdLCBpbVsgMCBdICksIGRvdCggaW1bIDEgXSwgaW1bIDEgXSApLCBkb3QoIGltWyAyIF0sIGltWyAyIF0gKSApO1xyXG5cdHRyYW5zZm9ybWVkTm9ybWFsID0gaW0gKiB0cmFuc2Zvcm1lZE5vcm1hbDtcclxuXHJcblx0I2lmZGVmIFVTRV9UQU5HRU5UXHJcblxyXG5cdFx0dHJhbnNmb3JtZWRUYW5nZW50ID0gaW0gKiB0cmFuc2Zvcm1lZFRhbmdlbnQ7XHJcblxyXG5cdCNlbmRpZlxyXG5cclxuI2VuZGlmXHJcblxyXG50cmFuc2Zvcm1lZE5vcm1hbCA9IG5vcm1hbE1hdHJpeCAqIHRyYW5zZm9ybWVkTm9ybWFsO1xyXG5cclxuI2lmZGVmIEZMSVBfU0lERURcclxuXHJcblx0dHJhbnNmb3JtZWROb3JtYWwgPSAtIHRyYW5zZm9ybWVkTm9ybWFsO1xyXG5cclxuI2VuZGlmXHJcblxyXG4jaWZkZWYgVVNFX1RBTkdFTlRcclxuXHJcblx0dHJhbnNmb3JtZWRUYW5nZW50ID0gKCBtb2RlbFZpZXdNYXRyaXggKiB2ZWM0KCB0cmFuc2Zvcm1lZFRhbmdlbnQsIDAuMCApICkueHl6O1xyXG5cclxuXHQjaWZkZWYgRkxJUF9TSURFRFxyXG5cclxuXHRcdHRyYW5zZm9ybWVkVGFuZ2VudCA9IC0gdHJhbnNmb3JtZWRUYW5nZW50O1xyXG5cclxuXHQjZW5kaWZcclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWZkZWYgVVNFX0RJU1BMQUNFTUVOVE1BUFxyXG5cclxuXHR1bmlmb3JtIHNhbXBsZXIyRCBkaXNwbGFjZW1lbnRNYXA7XHJcblx0dW5pZm9ybSBmbG9hdCBkaXNwbGFjZW1lbnRTY2FsZTtcclxuXHR1bmlmb3JtIGZsb2F0IGRpc3BsYWNlbWVudEJpYXM7XHJcblxyXG4jZW5kaWZcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuI2lmZGVmIFVTRV9ESVNQTEFDRU1FTlRNQVBcclxuXHJcblx0dHJhbnNmb3JtZWQgKz0gbm9ybWFsaXplKCBvYmplY3ROb3JtYWwgKSAqICggdGV4dHVyZTJEKCBkaXNwbGFjZW1lbnRNYXAsIHZEaXNwbGFjZW1lbnRNYXBVdiApLnggKiBkaXNwbGFjZW1lbnRTY2FsZSArIGRpc3BsYWNlbWVudEJpYXMgKTtcclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWZkZWYgVVNFX0VNSVNTSVZFTUFQXHJcblxyXG5cdHZlYzQgZW1pc3NpdmVDb2xvciA9IHRleHR1cmUyRCggZW1pc3NpdmVNYXAsIHZFbWlzc2l2ZU1hcFV2ICk7XHJcblxyXG5cdHRvdGFsRW1pc3NpdmVSYWRpYW5jZSAqPSBlbWlzc2l2ZUNvbG9yLnJnYjtcclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWZkZWYgVVNFX0VNSVNTSVZFTUFQXHJcblxyXG5cdHVuaWZvcm0gc2FtcGxlcjJEIGVtaXNzaXZlTWFwO1xyXG5cclxuI2VuZGlmXHJcbmA7XHJcbiIsImV4cG9ydCBkZWZhdWx0IC8qIGdsc2wgKi9gXHJcbmdsX0ZyYWdDb2xvciA9IGxpbmVhclRvT3V0cHV0VGV4ZWwoIGdsX0ZyYWdDb2xvciApO1xyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG5cclxuLy8gaHR0cDovL3d3dy5ydXNzZWxsY290dHJlbGwuY29tL3Bob3RvL21hdHJpeENhbGN1bGF0b3IuaHRtXHJcblxyXG4vLyBMaW5lYXIgc1JHQiA9PiBYWVogPT4gTGluZWFyIERpc3BsYXkgUDNcclxuY29uc3QgbWF0MyBMSU5FQVJfU1JHQl9UT19MSU5FQVJfRElTUExBWV9QMyA9IG1hdDMoXHJcblx0dmVjMyggMC44MjI0NjIxLCAwLjE3NzUzOCwgMC4wICksXHJcblx0dmVjMyggMC4wMzMxOTQxLCAwLjk2NjgwNTgsIDAuMCApLFxyXG5cdHZlYzMoIDAuMDE3MDgyNywgMC4wNzIzOTc0LCAwLjkxMDUxOTkgKVxyXG4pO1xyXG5cclxuLy8gTGluZWFyIERpc3BsYXkgUDMgPT4gWFlaID0+IExpbmVhciBzUkdCXHJcbmNvbnN0IG1hdDMgTElORUFSX0RJU1BMQVlfUDNfVE9fTElORUFSX1NSR0IgPSBtYXQzKFxyXG5cdHZlYzMoIDEuMjI0OTQwMSwgLSAwLjIyNDk0MDQsIDAuMCApLFxyXG5cdHZlYzMoIC0gMC4wNDIwNTY5LCAxLjA0MjA1NzEsIDAuMCApLFxyXG5cdHZlYzMoIC0gMC4wMTk2Mzc2LCAtIDAuMDc4NjM2MSwgMS4wOTgyNzM1IClcclxuKTtcclxuXHJcbnZlYzQgTGluZWFyU1JHQlRvTGluZWFyRGlzcGxheVAzKCBpbiB2ZWM0IHZhbHVlICkge1xyXG5cdHJldHVybiB2ZWM0KCB2YWx1ZS5yZ2IgKiBMSU5FQVJfU1JHQl9UT19MSU5FQVJfRElTUExBWV9QMywgdmFsdWUuYSApO1xyXG59XHJcblxyXG52ZWM0IExpbmVhckRpc3BsYXlQM1RvTGluZWFyU1JHQiggaW4gdmVjNCB2YWx1ZSApIHtcclxuXHRyZXR1cm4gdmVjNCggdmFsdWUucmdiICogTElORUFSX0RJU1BMQVlfUDNfVE9fTElORUFSX1NSR0IsIHZhbHVlLmEgKTtcclxufVxyXG5cclxudmVjNCBMaW5lYXJUcmFuc2Zlck9FVEYoIGluIHZlYzQgdmFsdWUgKSB7XHJcblx0cmV0dXJuIHZhbHVlO1xyXG59XHJcblxyXG52ZWM0IHNSR0JUcmFuc2Zlck9FVEYoIGluIHZlYzQgdmFsdWUgKSB7XHJcblx0cmV0dXJuIHZlYzQoIG1peCggcG93KCB2YWx1ZS5yZ2IsIHZlYzMoIDAuNDE2NjYgKSApICogMS4wNTUgLSB2ZWMzKCAwLjA1NSApLCB2YWx1ZS5yZ2IgKiAxMi45MiwgdmVjMyggbGVzc1RoYW5FcXVhbCggdmFsdWUucmdiLCB2ZWMzKCAwLjAwMzEzMDggKSApICkgKSwgdmFsdWUuYSApO1xyXG59XHJcblxyXG4vLyBAZGVwcmVjYXRlZCwgcjE1NlxyXG52ZWM0IExpbmVhclRvTGluZWFyKCBpbiB2ZWM0IHZhbHVlICkge1xyXG5cdHJldHVybiB2YWx1ZTtcclxufVxyXG5cclxuLy8gQGRlcHJlY2F0ZWQsIHIxNTZcclxudmVjNCBMaW5lYXJUb3NSR0IoIGluIHZlYzQgdmFsdWUgKSB7XHJcblx0cmV0dXJuIHNSR0JUcmFuc2Zlck9FVEYoIHZhbHVlICk7XHJcbn1cclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuI2lmZGVmIFVTRV9FTlZNQVBcclxuXHJcblx0I2lmZGVmIEVOVl9XT1JMRFBPU1xyXG5cclxuXHRcdHZlYzMgY2FtZXJhVG9GcmFnO1xyXG5cclxuXHRcdGlmICggaXNPcnRob2dyYXBoaWMgKSB7XHJcblxyXG5cdFx0XHRjYW1lcmFUb0ZyYWcgPSBub3JtYWxpemUoIHZlYzMoIC0gdmlld01hdHJpeFsgMCBdWyAyIF0sIC0gdmlld01hdHJpeFsgMSBdWyAyIF0sIC0gdmlld01hdHJpeFsgMiBdWyAyIF0gKSApO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRjYW1lcmFUb0ZyYWcgPSBub3JtYWxpemUoIHZXb3JsZFBvc2l0aW9uIC0gY2FtZXJhUG9zaXRpb24gKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gVHJhbnNmb3JtaW5nIE5vcm1hbCBWZWN0b3JzIHdpdGggdGhlIEludmVyc2UgVHJhbnNmb3JtYXRpb25cclxuXHRcdHZlYzMgd29ybGROb3JtYWwgPSBpbnZlcnNlVHJhbnNmb3JtRGlyZWN0aW9uKCBub3JtYWwsIHZpZXdNYXRyaXggKTtcclxuXHJcblx0XHQjaWZkZWYgRU5WTUFQX01PREVfUkVGTEVDVElPTlxyXG5cclxuXHRcdFx0dmVjMyByZWZsZWN0VmVjID0gcmVmbGVjdCggY2FtZXJhVG9GcmFnLCB3b3JsZE5vcm1hbCApO1xyXG5cclxuXHRcdCNlbHNlXHJcblxyXG5cdFx0XHR2ZWMzIHJlZmxlY3RWZWMgPSByZWZyYWN0KCBjYW1lcmFUb0ZyYWcsIHdvcmxkTm9ybWFsLCByZWZyYWN0aW9uUmF0aW8gKTtcclxuXHJcblx0XHQjZW5kaWZcclxuXHJcblx0I2Vsc2VcclxuXHJcblx0XHR2ZWMzIHJlZmxlY3RWZWMgPSB2UmVmbGVjdDtcclxuXHJcblx0I2VuZGlmXHJcblxyXG5cdCNpZmRlZiBFTlZNQVBfVFlQRV9DVUJFXHJcblxyXG5cdFx0dmVjNCBlbnZDb2xvciA9IHRleHR1cmVDdWJlKCBlbnZNYXAsIHZlYzMoIGZsaXBFbnZNYXAgKiByZWZsZWN0VmVjLngsIHJlZmxlY3RWZWMueXogKSApO1xyXG5cclxuXHQjZWxzZVxyXG5cclxuXHRcdHZlYzQgZW52Q29sb3IgPSB2ZWM0KCAwLjAgKTtcclxuXHJcblx0I2VuZGlmXHJcblxyXG5cdCNpZmRlZiBFTlZNQVBfQkxFTkRJTkdfTVVMVElQTFlcclxuXHJcblx0XHRvdXRnb2luZ0xpZ2h0ID0gbWl4KCBvdXRnb2luZ0xpZ2h0LCBvdXRnb2luZ0xpZ2h0ICogZW52Q29sb3IueHl6LCBzcGVjdWxhclN0cmVuZ3RoICogcmVmbGVjdGl2aXR5ICk7XHJcblxyXG5cdCNlbGlmIGRlZmluZWQoIEVOVk1BUF9CTEVORElOR19NSVggKVxyXG5cclxuXHRcdG91dGdvaW5nTGlnaHQgPSBtaXgoIG91dGdvaW5nTGlnaHQsIGVudkNvbG9yLnh5eiwgc3BlY3VsYXJTdHJlbmd0aCAqIHJlZmxlY3Rpdml0eSApO1xyXG5cclxuXHQjZWxpZiBkZWZpbmVkKCBFTlZNQVBfQkxFTkRJTkdfQUREIClcclxuXHJcblx0XHRvdXRnb2luZ0xpZ2h0ICs9IGVudkNvbG9yLnh5eiAqIHNwZWN1bGFyU3RyZW5ndGggKiByZWZsZWN0aXZpdHk7XHJcblxyXG5cdCNlbmRpZlxyXG5cclxuI2VuZGlmXHJcbmA7XHJcbiIsImV4cG9ydCBkZWZhdWx0IC8qIGdsc2wgKi9gXHJcbiNpZmRlZiBVU0VfRU5WTUFQXHJcblxyXG5cdHVuaWZvcm0gZmxvYXQgZW52TWFwSW50ZW5zaXR5O1xyXG5cdHVuaWZvcm0gZmxvYXQgZmxpcEVudk1hcDtcclxuXHJcblx0I2lmZGVmIEVOVk1BUF9UWVBFX0NVQkVcclxuXHRcdHVuaWZvcm0gc2FtcGxlckN1YmUgZW52TWFwO1xyXG5cdCNlbHNlXHJcblx0XHR1bmlmb3JtIHNhbXBsZXIyRCBlbnZNYXA7XHJcblx0I2VuZGlmXHJcblx0XHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWZkZWYgVVNFX0VOVk1BUFxyXG5cclxuXHR1bmlmb3JtIGZsb2F0IHJlZmxlY3Rpdml0eTtcclxuXHJcblx0I2lmIGRlZmluZWQoIFVTRV9CVU1QTUFQICkgfHwgZGVmaW5lZCggVVNFX05PUk1BTE1BUCApIHx8IGRlZmluZWQoIFBIT05HICkgfHwgZGVmaW5lZCggTEFNQkVSVCApXHJcblxyXG5cdFx0I2RlZmluZSBFTlZfV09STERQT1NcclxuXHJcblx0I2VuZGlmXHJcblxyXG5cdCNpZmRlZiBFTlZfV09STERQT1NcclxuXHJcblx0XHR2YXJ5aW5nIHZlYzMgdldvcmxkUG9zaXRpb247XHJcblx0XHR1bmlmb3JtIGZsb2F0IHJlZnJhY3Rpb25SYXRpbztcclxuXHQjZWxzZVxyXG5cdFx0dmFyeWluZyB2ZWMzIHZSZWZsZWN0O1xyXG5cdCNlbmRpZlxyXG5cclxuI2VuZGlmXHJcbmA7XHJcbiIsImV4cG9ydCBkZWZhdWx0IC8qIGdsc2wgKi9gXHJcbiNpZmRlZiBVU0VfRU5WTUFQXHJcblxyXG5cdCNpZiBkZWZpbmVkKCBVU0VfQlVNUE1BUCApIHx8IGRlZmluZWQoIFVTRV9OT1JNQUxNQVAgKSB8fCBkZWZpbmVkKCBQSE9ORyApIHx8IGRlZmluZWQoIExBTUJFUlQgKVxyXG5cclxuXHRcdCNkZWZpbmUgRU5WX1dPUkxEUE9TXHJcblxyXG5cdCNlbmRpZlxyXG5cclxuXHQjaWZkZWYgRU5WX1dPUkxEUE9TXHJcblx0XHRcclxuXHRcdHZhcnlpbmcgdmVjMyB2V29ybGRQb3NpdGlvbjtcclxuXHJcblx0I2Vsc2VcclxuXHJcblx0XHR2YXJ5aW5nIHZlYzMgdlJlZmxlY3Q7XHJcblx0XHR1bmlmb3JtIGZsb2F0IHJlZnJhY3Rpb25SYXRpbztcclxuXHJcblx0I2VuZGlmXHJcblxyXG4jZW5kaWZcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuI2lmZGVmIFVTRV9FTlZNQVBcclxuXHJcblx0I2lmZGVmIEVOVl9XT1JMRFBPU1xyXG5cclxuXHRcdHZXb3JsZFBvc2l0aW9uID0gd29ybGRQb3NpdGlvbi54eXo7XHJcblxyXG5cdCNlbHNlXHJcblxyXG5cdFx0dmVjMyBjYW1lcmFUb1ZlcnRleDtcclxuXHJcblx0XHRpZiAoIGlzT3J0aG9ncmFwaGljICkge1xyXG5cclxuXHRcdFx0Y2FtZXJhVG9WZXJ0ZXggPSBub3JtYWxpemUoIHZlYzMoIC0gdmlld01hdHJpeFsgMCBdWyAyIF0sIC0gdmlld01hdHJpeFsgMSBdWyAyIF0sIC0gdmlld01hdHJpeFsgMiBdWyAyIF0gKSApO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRjYW1lcmFUb1ZlcnRleCA9IG5vcm1hbGl6ZSggd29ybGRQb3NpdGlvbi54eXogLSBjYW1lcmFQb3NpdGlvbiApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHR2ZWMzIHdvcmxkTm9ybWFsID0gaW52ZXJzZVRyYW5zZm9ybURpcmVjdGlvbiggdHJhbnNmb3JtZWROb3JtYWwsIHZpZXdNYXRyaXggKTtcclxuXHJcblx0XHQjaWZkZWYgRU5WTUFQX01PREVfUkVGTEVDVElPTlxyXG5cclxuXHRcdFx0dlJlZmxlY3QgPSByZWZsZWN0KCBjYW1lcmFUb1ZlcnRleCwgd29ybGROb3JtYWwgKTtcclxuXHJcblx0XHQjZWxzZVxyXG5cclxuXHRcdFx0dlJlZmxlY3QgPSByZWZyYWN0KCBjYW1lcmFUb1ZlcnRleCwgd29ybGROb3JtYWwsIHJlZnJhY3Rpb25SYXRpbyApO1xyXG5cclxuXHRcdCNlbmRpZlxyXG5cclxuXHQjZW5kaWZcclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWZkZWYgVVNFX0ZPR1xyXG5cclxuXHR2Rm9nRGVwdGggPSAtIG12UG9zaXRpb24uejtcclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWZkZWYgVVNFX0ZPR1xyXG5cclxuXHR2YXJ5aW5nIGZsb2F0IHZGb2dEZXB0aDtcclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWZkZWYgVVNFX0ZPR1xyXG5cclxuXHQjaWZkZWYgRk9HX0VYUDJcclxuXHJcblx0XHRmbG9hdCBmb2dGYWN0b3IgPSAxLjAgLSBleHAoIC0gZm9nRGVuc2l0eSAqIGZvZ0RlbnNpdHkgKiB2Rm9nRGVwdGggKiB2Rm9nRGVwdGggKTtcclxuXHJcblx0I2Vsc2VcclxuXHJcblx0XHRmbG9hdCBmb2dGYWN0b3IgPSBzbW9vdGhzdGVwKCBmb2dOZWFyLCBmb2dGYXIsIHZGb2dEZXB0aCApO1xyXG5cclxuXHQjZW5kaWZcclxuXHJcblx0Z2xfRnJhZ0NvbG9yLnJnYiA9IG1peCggZ2xfRnJhZ0NvbG9yLnJnYiwgZm9nQ29sb3IsIGZvZ0ZhY3RvciApO1xyXG5cclxuI2VuZGlmXHJcbmA7XHJcbiIsImV4cG9ydCBkZWZhdWx0IC8qIGdsc2wgKi9gXHJcbiNpZmRlZiBVU0VfRk9HXHJcblxyXG5cdHVuaWZvcm0gdmVjMyBmb2dDb2xvcjtcclxuXHR2YXJ5aW5nIGZsb2F0IHZGb2dEZXB0aDtcclxuXHJcblx0I2lmZGVmIEZPR19FWFAyXHJcblxyXG5cdFx0dW5pZm9ybSBmbG9hdCBmb2dEZW5zaXR5O1xyXG5cclxuXHQjZWxzZVxyXG5cclxuXHRcdHVuaWZvcm0gZmxvYXQgZm9nTmVhcjtcclxuXHRcdHVuaWZvcm0gZmxvYXQgZm9nRmFyO1xyXG5cclxuXHQjZW5kaWZcclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG5cclxuI2lmZGVmIFVTRV9HUkFESUVOVE1BUFxyXG5cclxuXHR1bmlmb3JtIHNhbXBsZXIyRCBncmFkaWVudE1hcDtcclxuXHJcbiNlbmRpZlxyXG5cclxudmVjMyBnZXRHcmFkaWVudElycmFkaWFuY2UoIHZlYzMgbm9ybWFsLCB2ZWMzIGxpZ2h0RGlyZWN0aW9uICkge1xyXG5cclxuXHQvLyBkb3ROTCB3aWxsIGJlIGZyb20gLTEuMCB0byAxLjBcclxuXHRmbG9hdCBkb3ROTCA9IGRvdCggbm9ybWFsLCBsaWdodERpcmVjdGlvbiApO1xyXG5cdHZlYzIgY29vcmQgPSB2ZWMyKCBkb3ROTCAqIDAuNSArIDAuNSwgMC4wICk7XHJcblxyXG5cdCNpZmRlZiBVU0VfR1JBRElFTlRNQVBcclxuXHJcblx0XHRyZXR1cm4gdmVjMyggdGV4dHVyZTJEKCBncmFkaWVudE1hcCwgY29vcmQgKS5yICk7XHJcblxyXG5cdCNlbHNlXHJcblxyXG5cdFx0dmVjMiBmdyA9IGZ3aWR0aCggY29vcmQgKSAqIDAuNTtcclxuXHRcdHJldHVybiBtaXgoIHZlYzMoIDAuNyApLCB2ZWMzKCAxLjAgKSwgc21vb3Roc3RlcCggMC43IC0gZncueCwgMC43ICsgZncueCwgY29vcmQueCApICk7XHJcblxyXG5cdCNlbmRpZlxyXG5cclxufVxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWZkZWYgVVNFX0xJR0hUTUFQXHJcblxyXG5cdHZlYzQgbGlnaHRNYXBUZXhlbCA9IHRleHR1cmUyRCggbGlnaHRNYXAsIHZMaWdodE1hcFV2ICk7XHJcblx0dmVjMyBsaWdodE1hcElycmFkaWFuY2UgPSBsaWdodE1hcFRleGVsLnJnYiAqIGxpZ2h0TWFwSW50ZW5zaXR5O1xyXG5cclxuXHRyZWZsZWN0ZWRMaWdodC5pbmRpcmVjdERpZmZ1c2UgKz0gbGlnaHRNYXBJcnJhZGlhbmNlO1xyXG5cclxuI2VuZGlmXHJcbmA7XHJcbiIsImV4cG9ydCBkZWZhdWx0IC8qIGdsc2wgKi9gXHJcbiNpZmRlZiBVU0VfTElHSFRNQVBcclxuXHJcblx0dW5pZm9ybSBzYW1wbGVyMkQgbGlnaHRNYXA7XHJcblx0dW5pZm9ybSBmbG9hdCBsaWdodE1hcEludGVuc2l0eTtcclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG5MYW1iZXJ0TWF0ZXJpYWwgbWF0ZXJpYWw7XHJcbm1hdGVyaWFsLmRpZmZ1c2VDb2xvciA9IGRpZmZ1c2VDb2xvci5yZ2I7XHJcbm1hdGVyaWFsLnNwZWN1bGFyU3RyZW5ndGggPSBzcGVjdWxhclN0cmVuZ3RoO1xyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG52YXJ5aW5nIHZlYzMgdlZpZXdQb3NpdGlvbjtcclxuXHJcbnN0cnVjdCBMYW1iZXJ0TWF0ZXJpYWwge1xyXG5cclxuXHR2ZWMzIGRpZmZ1c2VDb2xvcjtcclxuXHRmbG9hdCBzcGVjdWxhclN0cmVuZ3RoO1xyXG5cclxufTtcclxuXHJcbnZvaWQgUkVfRGlyZWN0X0xhbWJlcnQoIGNvbnN0IGluIEluY2lkZW50TGlnaHQgZGlyZWN0TGlnaHQsIGNvbnN0IGluIHZlYzMgZ2VvbWV0cnlQb3NpdGlvbiwgY29uc3QgaW4gdmVjMyBnZW9tZXRyeU5vcm1hbCwgY29uc3QgaW4gdmVjMyBnZW9tZXRyeVZpZXdEaXIsIGNvbnN0IGluIHZlYzMgZ2VvbWV0cnlDbGVhcmNvYXROb3JtYWwsIGNvbnN0IGluIExhbWJlcnRNYXRlcmlhbCBtYXRlcmlhbCwgaW5vdXQgUmVmbGVjdGVkTGlnaHQgcmVmbGVjdGVkTGlnaHQgKSB7XHJcblxyXG5cdGZsb2F0IGRvdE5MID0gc2F0dXJhdGUoIGRvdCggZ2VvbWV0cnlOb3JtYWwsIGRpcmVjdExpZ2h0LmRpcmVjdGlvbiApICk7XHJcblx0dmVjMyBpcnJhZGlhbmNlID0gZG90TkwgKiBkaXJlY3RMaWdodC5jb2xvcjtcclxuXHJcblx0cmVmbGVjdGVkTGlnaHQuZGlyZWN0RGlmZnVzZSArPSBpcnJhZGlhbmNlICogQlJERl9MYW1iZXJ0KCBtYXRlcmlhbC5kaWZmdXNlQ29sb3IgKTtcclxuXHJcbn1cclxuXHJcbnZvaWQgUkVfSW5kaXJlY3REaWZmdXNlX0xhbWJlcnQoIGNvbnN0IGluIHZlYzMgaXJyYWRpYW5jZSwgY29uc3QgaW4gdmVjMyBnZW9tZXRyeVBvc2l0aW9uLCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5Tm9ybWFsLCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5Vmlld0RpciwgY29uc3QgaW4gdmVjMyBnZW9tZXRyeUNsZWFyY29hdE5vcm1hbCwgY29uc3QgaW4gTGFtYmVydE1hdGVyaWFsIG1hdGVyaWFsLCBpbm91dCBSZWZsZWN0ZWRMaWdodCByZWZsZWN0ZWRMaWdodCApIHtcclxuXHJcblx0cmVmbGVjdGVkTGlnaHQuaW5kaXJlY3REaWZmdXNlICs9IGlycmFkaWFuY2UgKiBCUkRGX0xhbWJlcnQoIG1hdGVyaWFsLmRpZmZ1c2VDb2xvciApO1xyXG5cclxufVxyXG5cclxuI2RlZmluZSBSRV9EaXJlY3RcdFx0XHRcdFJFX0RpcmVjdF9MYW1iZXJ0XHJcbiNkZWZpbmUgUkVfSW5kaXJlY3REaWZmdXNlXHRcdFJFX0luZGlyZWN0RGlmZnVzZV9MYW1iZXJ0XHJcbmA7XHJcbiIsImV4cG9ydCBkZWZhdWx0IC8qIGdsc2wgKi9gXHJcbnVuaWZvcm0gYm9vbCByZWNlaXZlU2hhZG93O1xyXG51bmlmb3JtIHZlYzMgYW1iaWVudExpZ2h0Q29sb3I7XHJcblxyXG4jaWYgZGVmaW5lZCggVVNFX0xJR0hUX1BST0JFUyApXHJcblxyXG5cdHVuaWZvcm0gdmVjMyBsaWdodFByb2JlWyA5IF07XHJcblxyXG4jZW5kaWZcclxuXHJcbi8vIGdldCB0aGUgaXJyYWRpYW5jZSAocmFkaWFuY2UgY29udm9sdmVkIHdpdGggY29zaW5lIGxvYmUpIGF0IHRoZSBwb2ludCAnbm9ybWFsJyBvbiB0aGUgdW5pdCBzcGhlcmVcclxuLy8gc291cmNlOiBodHRwczovL2dyYXBoaWNzLnN0YW5mb3JkLmVkdS9wYXBlcnMvZW52bWFwL2Vudm1hcC5wZGZcclxudmVjMyBzaEdldElycmFkaWFuY2VBdCggaW4gdmVjMyBub3JtYWwsIGluIHZlYzMgc2hDb2VmZmljaWVudHNbIDkgXSApIHtcclxuXHJcblx0Ly8gbm9ybWFsIGlzIGFzc3VtZWQgdG8gaGF2ZSB1bml0IGxlbmd0aFxyXG5cclxuXHRmbG9hdCB4ID0gbm9ybWFsLngsIHkgPSBub3JtYWwueSwgeiA9IG5vcm1hbC56O1xyXG5cclxuXHQvLyBiYW5kIDBcclxuXHR2ZWMzIHJlc3VsdCA9IHNoQ29lZmZpY2llbnRzWyAwIF0gKiAwLjg4NjIyNztcclxuXHJcblx0Ly8gYmFuZCAxXHJcblx0cmVzdWx0ICs9IHNoQ29lZmZpY2llbnRzWyAxIF0gKiAyLjAgKiAwLjUxMTY2NCAqIHk7XHJcblx0cmVzdWx0ICs9IHNoQ29lZmZpY2llbnRzWyAyIF0gKiAyLjAgKiAwLjUxMTY2NCAqIHo7XHJcblx0cmVzdWx0ICs9IHNoQ29lZmZpY2llbnRzWyAzIF0gKiAyLjAgKiAwLjUxMTY2NCAqIHg7XHJcblxyXG5cdC8vIGJhbmQgMlxyXG5cdHJlc3VsdCArPSBzaENvZWZmaWNpZW50c1sgNCBdICogMi4wICogMC40MjkwNDMgKiB4ICogeTtcclxuXHRyZXN1bHQgKz0gc2hDb2VmZmljaWVudHNbIDUgXSAqIDIuMCAqIDAuNDI5MDQzICogeSAqIHo7XHJcblx0cmVzdWx0ICs9IHNoQ29lZmZpY2llbnRzWyA2IF0gKiAoIDAuNzQzMTI1ICogeiAqIHogLSAwLjI0NzcwOCApO1xyXG5cdHJlc3VsdCArPSBzaENvZWZmaWNpZW50c1sgNyBdICogMi4wICogMC40MjkwNDMgKiB4ICogejtcclxuXHRyZXN1bHQgKz0gc2hDb2VmZmljaWVudHNbIDggXSAqIDAuNDI5MDQzICogKCB4ICogeCAtIHkgKiB5ICk7XHJcblxyXG5cdHJldHVybiByZXN1bHQ7XHJcblxyXG59XHJcblxyXG52ZWMzIGdldExpZ2h0UHJvYmVJcnJhZGlhbmNlKCBjb25zdCBpbiB2ZWMzIGxpZ2h0UHJvYmVbIDkgXSwgY29uc3QgaW4gdmVjMyBub3JtYWwgKSB7XHJcblxyXG5cdHZlYzMgd29ybGROb3JtYWwgPSBpbnZlcnNlVHJhbnNmb3JtRGlyZWN0aW9uKCBub3JtYWwsIHZpZXdNYXRyaXggKTtcclxuXHJcblx0dmVjMyBpcnJhZGlhbmNlID0gc2hHZXRJcnJhZGlhbmNlQXQoIHdvcmxkTm9ybWFsLCBsaWdodFByb2JlICk7XHJcblxyXG5cdHJldHVybiBpcnJhZGlhbmNlO1xyXG5cclxufVxyXG5cclxudmVjMyBnZXRBbWJpZW50TGlnaHRJcnJhZGlhbmNlKCBjb25zdCBpbiB2ZWMzIGFtYmllbnRMaWdodENvbG9yICkge1xyXG5cclxuXHR2ZWMzIGlycmFkaWFuY2UgPSBhbWJpZW50TGlnaHRDb2xvcjtcclxuXHJcblx0cmV0dXJuIGlycmFkaWFuY2U7XHJcblxyXG59XHJcblxyXG5mbG9hdCBnZXREaXN0YW5jZUF0dGVudWF0aW9uKCBjb25zdCBpbiBmbG9hdCBsaWdodERpc3RhbmNlLCBjb25zdCBpbiBmbG9hdCBjdXRvZmZEaXN0YW5jZSwgY29uc3QgaW4gZmxvYXQgZGVjYXlFeHBvbmVudCApIHtcclxuXHJcblx0I2lmIGRlZmluZWQgKCBMRUdBQ1lfTElHSFRTIClcclxuXHJcblx0XHRpZiAoIGN1dG9mZkRpc3RhbmNlID4gMC4wICYmIGRlY2F5RXhwb25lbnQgPiAwLjAgKSB7XHJcblxyXG5cdFx0XHRyZXR1cm4gcG93KCBzYXR1cmF0ZSggLSBsaWdodERpc3RhbmNlIC8gY3V0b2ZmRGlzdGFuY2UgKyAxLjAgKSwgZGVjYXlFeHBvbmVudCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gMS4wO1xyXG5cclxuXHQjZWxzZVxyXG5cclxuXHRcdC8vIGJhc2VkIHVwb24gRnJvc3RiaXRlIDMgTW92aW5nIHRvIFBoeXNpY2FsbHktYmFzZWQgUmVuZGVyaW5nXHJcblx0XHQvLyBwYWdlIDMyLCBlcXVhdGlvbiAyNjogRVt3aW5kb3cxXVxyXG5cdFx0Ly8gaHR0cHM6Ly9zZWJsYWdhcmRlLmZpbGVzLndvcmRwcmVzcy5jb20vMjAxNS8wNy9jb3Vyc2Vfbm90ZXNfbW92aW5nX2Zyb3N0Yml0ZV90b19wYnJfdjMyLnBkZlxyXG5cdFx0ZmxvYXQgZGlzdGFuY2VGYWxsb2ZmID0gMS4wIC8gbWF4KCBwb3coIGxpZ2h0RGlzdGFuY2UsIGRlY2F5RXhwb25lbnQgKSwgMC4wMSApO1xyXG5cclxuXHRcdGlmICggY3V0b2ZmRGlzdGFuY2UgPiAwLjAgKSB7XHJcblxyXG5cdFx0XHRkaXN0YW5jZUZhbGxvZmYgKj0gcG93Miggc2F0dXJhdGUoIDEuMCAtIHBvdzQoIGxpZ2h0RGlzdGFuY2UgLyBjdXRvZmZEaXN0YW5jZSApICkgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIGRpc3RhbmNlRmFsbG9mZjtcclxuXHJcblx0I2VuZGlmXHJcblxyXG59XHJcblxyXG5mbG9hdCBnZXRTcG90QXR0ZW51YXRpb24oIGNvbnN0IGluIGZsb2F0IGNvbmVDb3NpbmUsIGNvbnN0IGluIGZsb2F0IHBlbnVtYnJhQ29zaW5lLCBjb25zdCBpbiBmbG9hdCBhbmdsZUNvc2luZSApIHtcclxuXHJcblx0cmV0dXJuIHNtb290aHN0ZXAoIGNvbmVDb3NpbmUsIHBlbnVtYnJhQ29zaW5lLCBhbmdsZUNvc2luZSApO1xyXG5cclxufVxyXG5cclxuI2lmIE5VTV9ESVJfTElHSFRTID4gMFxyXG5cclxuXHRzdHJ1Y3QgRGlyZWN0aW9uYWxMaWdodCB7XHJcblx0XHR2ZWMzIGRpcmVjdGlvbjtcclxuXHRcdHZlYzMgY29sb3I7XHJcblx0fTtcclxuXHJcblx0dW5pZm9ybSBEaXJlY3Rpb25hbExpZ2h0IGRpcmVjdGlvbmFsTGlnaHRzWyBOVU1fRElSX0xJR0hUUyBdO1xyXG5cclxuXHR2b2lkIGdldERpcmVjdGlvbmFsTGlnaHRJbmZvKCBjb25zdCBpbiBEaXJlY3Rpb25hbExpZ2h0IGRpcmVjdGlvbmFsTGlnaHQsIG91dCBJbmNpZGVudExpZ2h0IGxpZ2h0ICkge1xyXG5cclxuXHRcdGxpZ2h0LmNvbG9yID0gZGlyZWN0aW9uYWxMaWdodC5jb2xvcjtcclxuXHRcdGxpZ2h0LmRpcmVjdGlvbiA9IGRpcmVjdGlvbmFsTGlnaHQuZGlyZWN0aW9uO1xyXG5cdFx0bGlnaHQudmlzaWJsZSA9IHRydWU7XHJcblxyXG5cdH1cclxuXHJcbiNlbmRpZlxyXG5cclxuXHJcbiNpZiBOVU1fUE9JTlRfTElHSFRTID4gMFxyXG5cclxuXHRzdHJ1Y3QgUG9pbnRMaWdodCB7XHJcblx0XHR2ZWMzIHBvc2l0aW9uO1xyXG5cdFx0dmVjMyBjb2xvcjtcclxuXHRcdGZsb2F0IGRpc3RhbmNlO1xyXG5cdFx0ZmxvYXQgZGVjYXk7XHJcblx0fTtcclxuXHJcblx0dW5pZm9ybSBQb2ludExpZ2h0IHBvaW50TGlnaHRzWyBOVU1fUE9JTlRfTElHSFRTIF07XHJcblxyXG5cdC8vIGxpZ2h0IGlzIGFuIG91dCBwYXJhbWV0ZXIgYXMgaGF2aW5nIGl0IGFzIGEgcmV0dXJuIHZhbHVlIGNhdXNlZCBjb21waWxlciBlcnJvcnMgb24gc29tZSBkZXZpY2VzXHJcblx0dm9pZCBnZXRQb2ludExpZ2h0SW5mbyggY29uc3QgaW4gUG9pbnRMaWdodCBwb2ludExpZ2h0LCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5UG9zaXRpb24sIG91dCBJbmNpZGVudExpZ2h0IGxpZ2h0ICkge1xyXG5cclxuXHRcdHZlYzMgbFZlY3RvciA9IHBvaW50TGlnaHQucG9zaXRpb24gLSBnZW9tZXRyeVBvc2l0aW9uO1xyXG5cclxuXHRcdGxpZ2h0LmRpcmVjdGlvbiA9IG5vcm1hbGl6ZSggbFZlY3RvciApO1xyXG5cclxuXHRcdGZsb2F0IGxpZ2h0RGlzdGFuY2UgPSBsZW5ndGgoIGxWZWN0b3IgKTtcclxuXHJcblx0XHRsaWdodC5jb2xvciA9IHBvaW50TGlnaHQuY29sb3I7XHJcblx0XHRsaWdodC5jb2xvciAqPSBnZXREaXN0YW5jZUF0dGVudWF0aW9uKCBsaWdodERpc3RhbmNlLCBwb2ludExpZ2h0LmRpc3RhbmNlLCBwb2ludExpZ2h0LmRlY2F5ICk7XHJcblx0XHRsaWdodC52aXNpYmxlID0gKCBsaWdodC5jb2xvciAhPSB2ZWMzKCAwLjAgKSApO1xyXG5cclxuXHR9XHJcblxyXG4jZW5kaWZcclxuXHJcblxyXG4jaWYgTlVNX1NQT1RfTElHSFRTID4gMFxyXG5cclxuXHRzdHJ1Y3QgU3BvdExpZ2h0IHtcclxuXHRcdHZlYzMgcG9zaXRpb247XHJcblx0XHR2ZWMzIGRpcmVjdGlvbjtcclxuXHRcdHZlYzMgY29sb3I7XHJcblx0XHRmbG9hdCBkaXN0YW5jZTtcclxuXHRcdGZsb2F0IGRlY2F5O1xyXG5cdFx0ZmxvYXQgY29uZUNvcztcclxuXHRcdGZsb2F0IHBlbnVtYnJhQ29zO1xyXG5cdH07XHJcblxyXG5cdHVuaWZvcm0gU3BvdExpZ2h0IHNwb3RMaWdodHNbIE5VTV9TUE9UX0xJR0hUUyBdO1xyXG5cclxuXHQvLyBsaWdodCBpcyBhbiBvdXQgcGFyYW1ldGVyIGFzIGhhdmluZyBpdCBhcyBhIHJldHVybiB2YWx1ZSBjYXVzZWQgY29tcGlsZXIgZXJyb3JzIG9uIHNvbWUgZGV2aWNlc1xyXG5cdHZvaWQgZ2V0U3BvdExpZ2h0SW5mbyggY29uc3QgaW4gU3BvdExpZ2h0IHNwb3RMaWdodCwgY29uc3QgaW4gdmVjMyBnZW9tZXRyeVBvc2l0aW9uLCBvdXQgSW5jaWRlbnRMaWdodCBsaWdodCApIHtcclxuXHJcblx0XHR2ZWMzIGxWZWN0b3IgPSBzcG90TGlnaHQucG9zaXRpb24gLSBnZW9tZXRyeVBvc2l0aW9uO1xyXG5cclxuXHRcdGxpZ2h0LmRpcmVjdGlvbiA9IG5vcm1hbGl6ZSggbFZlY3RvciApO1xyXG5cclxuXHRcdGZsb2F0IGFuZ2xlQ29zID0gZG90KCBsaWdodC5kaXJlY3Rpb24sIHNwb3RMaWdodC5kaXJlY3Rpb24gKTtcclxuXHJcblx0XHRmbG9hdCBzcG90QXR0ZW51YXRpb24gPSBnZXRTcG90QXR0ZW51YXRpb24oIHNwb3RMaWdodC5jb25lQ29zLCBzcG90TGlnaHQucGVudW1icmFDb3MsIGFuZ2xlQ29zICk7XHJcblxyXG5cdFx0aWYgKCBzcG90QXR0ZW51YXRpb24gPiAwLjAgKSB7XHJcblxyXG5cdFx0XHRmbG9hdCBsaWdodERpc3RhbmNlID0gbGVuZ3RoKCBsVmVjdG9yICk7XHJcblxyXG5cdFx0XHRsaWdodC5jb2xvciA9IHNwb3RMaWdodC5jb2xvciAqIHNwb3RBdHRlbnVhdGlvbjtcclxuXHRcdFx0bGlnaHQuY29sb3IgKj0gZ2V0RGlzdGFuY2VBdHRlbnVhdGlvbiggbGlnaHREaXN0YW5jZSwgc3BvdExpZ2h0LmRpc3RhbmNlLCBzcG90TGlnaHQuZGVjYXkgKTtcclxuXHRcdFx0bGlnaHQudmlzaWJsZSA9ICggbGlnaHQuY29sb3IgIT0gdmVjMyggMC4wICkgKTtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0bGlnaHQuY29sb3IgPSB2ZWMzKCAwLjAgKTtcclxuXHRcdFx0bGlnaHQudmlzaWJsZSA9IGZhbHNlO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuI2VuZGlmXHJcblxyXG5cclxuI2lmIE5VTV9SRUNUX0FSRUFfTElHSFRTID4gMFxyXG5cclxuXHRzdHJ1Y3QgUmVjdEFyZWFMaWdodCB7XHJcblx0XHR2ZWMzIGNvbG9yO1xyXG5cdFx0dmVjMyBwb3NpdGlvbjtcclxuXHRcdHZlYzMgaGFsZldpZHRoO1xyXG5cdFx0dmVjMyBoYWxmSGVpZ2h0O1xyXG5cdH07XHJcblxyXG5cdC8vIFByZS1jb21wdXRlZCB2YWx1ZXMgb2YgTGluZWFyVHJhbnNmb3JtZWRDb3NpbmUgYXBwcm94aW1hdGlvbiBvZiBCUkRGXHJcblx0Ly8gQlJERiBhcHByb3hpbWF0aW9uIFRleHR1cmUgaXMgNjR4NjRcclxuXHR1bmlmb3JtIHNhbXBsZXIyRCBsdGNfMTsgLy8gUkdCQSBGbG9hdFxyXG5cdHVuaWZvcm0gc2FtcGxlcjJEIGx0Y18yOyAvLyBSR0JBIEZsb2F0XHJcblxyXG5cdHVuaWZvcm0gUmVjdEFyZWFMaWdodCByZWN0QXJlYUxpZ2h0c1sgTlVNX1JFQ1RfQVJFQV9MSUdIVFMgXTtcclxuXHJcbiNlbmRpZlxyXG5cclxuXHJcbiNpZiBOVU1fSEVNSV9MSUdIVFMgPiAwXHJcblxyXG5cdHN0cnVjdCBIZW1pc3BoZXJlTGlnaHQge1xyXG5cdFx0dmVjMyBkaXJlY3Rpb247XHJcblx0XHR2ZWMzIHNreUNvbG9yO1xyXG5cdFx0dmVjMyBncm91bmRDb2xvcjtcclxuXHR9O1xyXG5cclxuXHR1bmlmb3JtIEhlbWlzcGhlcmVMaWdodCBoZW1pc3BoZXJlTGlnaHRzWyBOVU1fSEVNSV9MSUdIVFMgXTtcclxuXHJcblx0dmVjMyBnZXRIZW1pc3BoZXJlTGlnaHRJcnJhZGlhbmNlKCBjb25zdCBpbiBIZW1pc3BoZXJlTGlnaHQgaGVtaUxpZ2h0LCBjb25zdCBpbiB2ZWMzIG5vcm1hbCApIHtcclxuXHJcblx0XHRmbG9hdCBkb3ROTCA9IGRvdCggbm9ybWFsLCBoZW1pTGlnaHQuZGlyZWN0aW9uICk7XHJcblx0XHRmbG9hdCBoZW1pRGlmZnVzZVdlaWdodCA9IDAuNSAqIGRvdE5MICsgMC41O1xyXG5cclxuXHRcdHZlYzMgaXJyYWRpYW5jZSA9IG1peCggaGVtaUxpZ2h0Lmdyb3VuZENvbG9yLCBoZW1pTGlnaHQuc2t5Q29sb3IsIGhlbWlEaWZmdXNlV2VpZ2h0ICk7XHJcblxyXG5cdFx0cmV0dXJuIGlycmFkaWFuY2U7XHJcblxyXG5cdH1cclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWZkZWYgVVNFX0VOVk1BUFxyXG5cclxuXHR2ZWMzIGdldElCTElycmFkaWFuY2UoIGNvbnN0IGluIHZlYzMgbm9ybWFsICkge1xyXG5cclxuXHRcdCNpZmRlZiBFTlZNQVBfVFlQRV9DVUJFX1VWXHJcblxyXG5cdFx0XHR2ZWMzIHdvcmxkTm9ybWFsID0gaW52ZXJzZVRyYW5zZm9ybURpcmVjdGlvbiggbm9ybWFsLCB2aWV3TWF0cml4ICk7XHJcblxyXG5cdFx0XHR2ZWM0IGVudk1hcENvbG9yID0gdGV4dHVyZUN1YmVVViggZW52TWFwLCB3b3JsZE5vcm1hbCwgMS4wICk7XHJcblxyXG5cdFx0XHRyZXR1cm4gUEkgKiBlbnZNYXBDb2xvci5yZ2IgKiBlbnZNYXBJbnRlbnNpdHk7XHJcblxyXG5cdFx0I2Vsc2VcclxuXHJcblx0XHRcdHJldHVybiB2ZWMzKCAwLjAgKTtcclxuXHJcblx0XHQjZW5kaWZcclxuXHJcblx0fVxyXG5cclxuXHR2ZWMzIGdldElCTFJhZGlhbmNlKCBjb25zdCBpbiB2ZWMzIHZpZXdEaXIsIGNvbnN0IGluIHZlYzMgbm9ybWFsLCBjb25zdCBpbiBmbG9hdCByb3VnaG5lc3MgKSB7XHJcblxyXG5cdFx0I2lmZGVmIEVOVk1BUF9UWVBFX0NVQkVfVVZcclxuXHJcblx0XHRcdHZlYzMgcmVmbGVjdFZlYyA9IHJlZmxlY3QoIC0gdmlld0Rpciwgbm9ybWFsICk7XHJcblxyXG5cdFx0XHQvLyBNaXhpbmcgdGhlIHJlZmxlY3Rpb24gd2l0aCB0aGUgbm9ybWFsIGlzIG1vcmUgYWNjdXJhdGUgYW5kIGtlZXBzIHJvdWdoIG9iamVjdHMgZnJvbSBnYXRoZXJpbmcgbGlnaHQgZnJvbSBiZWhpbmQgdGhlaXIgdGFuZ2VudCBwbGFuZS5cclxuXHRcdFx0cmVmbGVjdFZlYyA9IG5vcm1hbGl6ZSggbWl4KCByZWZsZWN0VmVjLCBub3JtYWwsIHJvdWdobmVzcyAqIHJvdWdobmVzcykgKTtcclxuXHJcblx0XHRcdHJlZmxlY3RWZWMgPSBpbnZlcnNlVHJhbnNmb3JtRGlyZWN0aW9uKCByZWZsZWN0VmVjLCB2aWV3TWF0cml4ICk7XHJcblxyXG5cdFx0XHR2ZWM0IGVudk1hcENvbG9yID0gdGV4dHVyZUN1YmVVViggZW52TWFwLCByZWZsZWN0VmVjLCByb3VnaG5lc3MgKTtcclxuXHJcblx0XHRcdHJldHVybiBlbnZNYXBDb2xvci5yZ2IgKiBlbnZNYXBJbnRlbnNpdHk7XHJcblxyXG5cdFx0I2Vsc2VcclxuXHJcblx0XHRcdHJldHVybiB2ZWMzKCAwLjAgKTtcclxuXHJcblx0XHQjZW5kaWZcclxuXHJcblx0fVxyXG5cclxuXHQjaWZkZWYgVVNFX0FOSVNPVFJPUFlcclxuXHJcblx0XHR2ZWMzIGdldElCTEFuaXNvdHJvcHlSYWRpYW5jZSggY29uc3QgaW4gdmVjMyB2aWV3RGlyLCBjb25zdCBpbiB2ZWMzIG5vcm1hbCwgY29uc3QgaW4gZmxvYXQgcm91Z2huZXNzLCBjb25zdCBpbiB2ZWMzIGJpdGFuZ2VudCwgY29uc3QgaW4gZmxvYXQgYW5pc290cm9weSApIHtcclxuXHJcblx0XHRcdCNpZmRlZiBFTlZNQVBfVFlQRV9DVUJFX1VWXHJcblxyXG5cdFx0XHQgIC8vIGh0dHBzOi8vZ29vZ2xlLmdpdGh1Yi5pby9maWxhbWVudC9GaWxhbWVudC5tZC5odG1sI2xpZ2h0aW5nL2ltYWdlYmFzZWRsaWdodHMvYW5pc290cm9weVxyXG5cdFx0XHRcdHZlYzMgYmVudE5vcm1hbCA9IGNyb3NzKCBiaXRhbmdlbnQsIHZpZXdEaXIgKTtcclxuXHRcdFx0XHRiZW50Tm9ybWFsID0gbm9ybWFsaXplKCBjcm9zcyggYmVudE5vcm1hbCwgYml0YW5nZW50ICkgKTtcclxuXHRcdFx0XHRiZW50Tm9ybWFsID0gbm9ybWFsaXplKCBtaXgoIGJlbnROb3JtYWwsIG5vcm1hbCwgcG93MiggcG93MiggMS4wIC0gYW5pc290cm9weSAqICggMS4wIC0gcm91Z2huZXNzICkgKSApICkgKTtcclxuXHJcblx0XHRcdFx0cmV0dXJuIGdldElCTFJhZGlhbmNlKCB2aWV3RGlyLCBiZW50Tm9ybWFsLCByb3VnaG5lc3MgKTtcclxuXHJcblx0XHRcdCNlbHNlXHJcblxyXG5cdFx0XHRcdHJldHVybiB2ZWMzKCAwLjAgKTtcclxuXHJcblx0XHRcdCNlbmRpZlxyXG5cclxuXHRcdH1cclxuXHJcblx0I2VuZGlmXHJcblxyXG4jZW5kaWZcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuVG9vbk1hdGVyaWFsIG1hdGVyaWFsO1xyXG5tYXRlcmlhbC5kaWZmdXNlQ29sb3IgPSBkaWZmdXNlQ29sb3IucmdiO1xyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG52YXJ5aW5nIHZlYzMgdlZpZXdQb3NpdGlvbjtcclxuXHJcbnN0cnVjdCBUb29uTWF0ZXJpYWwge1xyXG5cclxuXHR2ZWMzIGRpZmZ1c2VDb2xvcjtcclxuXHJcbn07XHJcblxyXG52b2lkIFJFX0RpcmVjdF9Ub29uKCBjb25zdCBpbiBJbmNpZGVudExpZ2h0IGRpcmVjdExpZ2h0LCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5UG9zaXRpb24sIGNvbnN0IGluIHZlYzMgZ2VvbWV0cnlOb3JtYWwsIGNvbnN0IGluIHZlYzMgZ2VvbWV0cnlWaWV3RGlyLCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5Q2xlYXJjb2F0Tm9ybWFsLCBjb25zdCBpbiBUb29uTWF0ZXJpYWwgbWF0ZXJpYWwsIGlub3V0IFJlZmxlY3RlZExpZ2h0IHJlZmxlY3RlZExpZ2h0ICkge1xyXG5cclxuXHR2ZWMzIGlycmFkaWFuY2UgPSBnZXRHcmFkaWVudElycmFkaWFuY2UoIGdlb21ldHJ5Tm9ybWFsLCBkaXJlY3RMaWdodC5kaXJlY3Rpb24gKSAqIGRpcmVjdExpZ2h0LmNvbG9yO1xyXG5cclxuXHRyZWZsZWN0ZWRMaWdodC5kaXJlY3REaWZmdXNlICs9IGlycmFkaWFuY2UgKiBCUkRGX0xhbWJlcnQoIG1hdGVyaWFsLmRpZmZ1c2VDb2xvciApO1xyXG5cclxufVxyXG5cclxudm9pZCBSRV9JbmRpcmVjdERpZmZ1c2VfVG9vbiggY29uc3QgaW4gdmVjMyBpcnJhZGlhbmNlLCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5UG9zaXRpb24sIGNvbnN0IGluIHZlYzMgZ2VvbWV0cnlOb3JtYWwsIGNvbnN0IGluIHZlYzMgZ2VvbWV0cnlWaWV3RGlyLCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5Q2xlYXJjb2F0Tm9ybWFsLCBjb25zdCBpbiBUb29uTWF0ZXJpYWwgbWF0ZXJpYWwsIGlub3V0IFJlZmxlY3RlZExpZ2h0IHJlZmxlY3RlZExpZ2h0ICkge1xyXG5cclxuXHRyZWZsZWN0ZWRMaWdodC5pbmRpcmVjdERpZmZ1c2UgKz0gaXJyYWRpYW5jZSAqIEJSREZfTGFtYmVydCggbWF0ZXJpYWwuZGlmZnVzZUNvbG9yICk7XHJcblxyXG59XHJcblxyXG4jZGVmaW5lIFJFX0RpcmVjdFx0XHRcdFx0UkVfRGlyZWN0X1Rvb25cclxuI2RlZmluZSBSRV9JbmRpcmVjdERpZmZ1c2VcdFx0UkVfSW5kaXJlY3REaWZmdXNlX1Rvb25cclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuQmxpbm5QaG9uZ01hdGVyaWFsIG1hdGVyaWFsO1xyXG5tYXRlcmlhbC5kaWZmdXNlQ29sb3IgPSBkaWZmdXNlQ29sb3IucmdiO1xyXG5tYXRlcmlhbC5zcGVjdWxhckNvbG9yID0gc3BlY3VsYXI7XHJcbm1hdGVyaWFsLnNwZWN1bGFyU2hpbmluZXNzID0gc2hpbmluZXNzO1xyXG5tYXRlcmlhbC5zcGVjdWxhclN0cmVuZ3RoID0gc3BlY3VsYXJTdHJlbmd0aDtcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxudmFyeWluZyB2ZWMzIHZWaWV3UG9zaXRpb247XHJcblxyXG5zdHJ1Y3QgQmxpbm5QaG9uZ01hdGVyaWFsIHtcclxuXHJcblx0dmVjMyBkaWZmdXNlQ29sb3I7XHJcblx0dmVjMyBzcGVjdWxhckNvbG9yO1xyXG5cdGZsb2F0IHNwZWN1bGFyU2hpbmluZXNzO1xyXG5cdGZsb2F0IHNwZWN1bGFyU3RyZW5ndGg7XHJcblxyXG59O1xyXG5cclxudm9pZCBSRV9EaXJlY3RfQmxpbm5QaG9uZyggY29uc3QgaW4gSW5jaWRlbnRMaWdodCBkaXJlY3RMaWdodCwgY29uc3QgaW4gdmVjMyBnZW9tZXRyeVBvc2l0aW9uLCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5Tm9ybWFsLCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5Vmlld0RpciwgY29uc3QgaW4gdmVjMyBnZW9tZXRyeUNsZWFyY29hdE5vcm1hbCwgY29uc3QgaW4gQmxpbm5QaG9uZ01hdGVyaWFsIG1hdGVyaWFsLCBpbm91dCBSZWZsZWN0ZWRMaWdodCByZWZsZWN0ZWRMaWdodCApIHtcclxuXHJcblx0ZmxvYXQgZG90TkwgPSBzYXR1cmF0ZSggZG90KCBnZW9tZXRyeU5vcm1hbCwgZGlyZWN0TGlnaHQuZGlyZWN0aW9uICkgKTtcclxuXHR2ZWMzIGlycmFkaWFuY2UgPSBkb3ROTCAqIGRpcmVjdExpZ2h0LmNvbG9yO1xyXG5cclxuXHRyZWZsZWN0ZWRMaWdodC5kaXJlY3REaWZmdXNlICs9IGlycmFkaWFuY2UgKiBCUkRGX0xhbWJlcnQoIG1hdGVyaWFsLmRpZmZ1c2VDb2xvciApO1xyXG5cclxuXHRyZWZsZWN0ZWRMaWdodC5kaXJlY3RTcGVjdWxhciArPSBpcnJhZGlhbmNlICogQlJERl9CbGlublBob25nKCBkaXJlY3RMaWdodC5kaXJlY3Rpb24sIGdlb21ldHJ5Vmlld0RpciwgZ2VvbWV0cnlOb3JtYWwsIG1hdGVyaWFsLnNwZWN1bGFyQ29sb3IsIG1hdGVyaWFsLnNwZWN1bGFyU2hpbmluZXNzICkgKiBtYXRlcmlhbC5zcGVjdWxhclN0cmVuZ3RoO1xyXG5cclxufVxyXG5cclxudm9pZCBSRV9JbmRpcmVjdERpZmZ1c2VfQmxpbm5QaG9uZyggY29uc3QgaW4gdmVjMyBpcnJhZGlhbmNlLCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5UG9zaXRpb24sIGNvbnN0IGluIHZlYzMgZ2VvbWV0cnlOb3JtYWwsIGNvbnN0IGluIHZlYzMgZ2VvbWV0cnlWaWV3RGlyLCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5Q2xlYXJjb2F0Tm9ybWFsLCBjb25zdCBpbiBCbGlublBob25nTWF0ZXJpYWwgbWF0ZXJpYWwsIGlub3V0IFJlZmxlY3RlZExpZ2h0IHJlZmxlY3RlZExpZ2h0ICkge1xyXG5cclxuXHRyZWZsZWN0ZWRMaWdodC5pbmRpcmVjdERpZmZ1c2UgKz0gaXJyYWRpYW5jZSAqIEJSREZfTGFtYmVydCggbWF0ZXJpYWwuZGlmZnVzZUNvbG9yICk7XHJcblxyXG59XHJcblxyXG4jZGVmaW5lIFJFX0RpcmVjdFx0XHRcdFx0UkVfRGlyZWN0X0JsaW5uUGhvbmdcclxuI2RlZmluZSBSRV9JbmRpcmVjdERpZmZ1c2VcdFx0UkVfSW5kaXJlY3REaWZmdXNlX0JsaW5uUGhvbmdcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuUGh5c2ljYWxNYXRlcmlhbCBtYXRlcmlhbDtcclxubWF0ZXJpYWwuZGlmZnVzZUNvbG9yID0gZGlmZnVzZUNvbG9yLnJnYiAqICggMS4wIC0gbWV0YWxuZXNzRmFjdG9yICk7XHJcblxyXG52ZWMzIGR4eSA9IG1heCggYWJzKCBkRmR4KCBub25QZXJ0dXJiZWROb3JtYWwgKSApLCBhYnMoIGRGZHkoIG5vblBlcnR1cmJlZE5vcm1hbCApICkgKTtcclxuZmxvYXQgZ2VvbWV0cnlSb3VnaG5lc3MgPSBtYXgoIG1heCggZHh5LngsIGR4eS55ICksIGR4eS56ICk7XHJcblxyXG5tYXRlcmlhbC5yb3VnaG5lc3MgPSBtYXgoIHJvdWdobmVzc0ZhY3RvciwgMC4wNTI1ICk7Ly8gMC4wNTI1IGNvcnJlc3BvbmRzIHRvIHRoZSBiYXNlIG1pcCBvZiBhIDI1NiBjdWJlbWFwLlxyXG5tYXRlcmlhbC5yb3VnaG5lc3MgKz0gZ2VvbWV0cnlSb3VnaG5lc3M7XHJcbm1hdGVyaWFsLnJvdWdobmVzcyA9IG1pbiggbWF0ZXJpYWwucm91Z2huZXNzLCAxLjAgKTtcclxuXHJcbiNpZmRlZiBJT1JcclxuXHJcblx0bWF0ZXJpYWwuaW9yID0gaW9yO1xyXG5cclxuXHQjaWZkZWYgVVNFX1NQRUNVTEFSXHJcblxyXG5cdFx0ZmxvYXQgc3BlY3VsYXJJbnRlbnNpdHlGYWN0b3IgPSBzcGVjdWxhckludGVuc2l0eTtcclxuXHRcdHZlYzMgc3BlY3VsYXJDb2xvckZhY3RvciA9IHNwZWN1bGFyQ29sb3I7XHJcblxyXG5cdFx0I2lmZGVmIFVTRV9TUEVDVUxBUl9DT0xPUk1BUFxyXG5cclxuXHRcdFx0c3BlY3VsYXJDb2xvckZhY3RvciAqPSB0ZXh0dXJlMkQoIHNwZWN1bGFyQ29sb3JNYXAsIHZTcGVjdWxhckNvbG9yTWFwVXYgKS5yZ2I7XHJcblxyXG5cdFx0I2VuZGlmXHJcblxyXG5cdFx0I2lmZGVmIFVTRV9TUEVDVUxBUl9JTlRFTlNJVFlNQVBcclxuXHJcblx0XHRcdHNwZWN1bGFySW50ZW5zaXR5RmFjdG9yICo9IHRleHR1cmUyRCggc3BlY3VsYXJJbnRlbnNpdHlNYXAsIHZTcGVjdWxhckludGVuc2l0eU1hcFV2ICkuYTtcclxuXHJcblx0XHQjZW5kaWZcclxuXHJcblx0XHRtYXRlcmlhbC5zcGVjdWxhckY5MCA9IG1peCggc3BlY3VsYXJJbnRlbnNpdHlGYWN0b3IsIDEuMCwgbWV0YWxuZXNzRmFjdG9yICk7XHJcblxyXG5cdCNlbHNlXHJcblxyXG5cdFx0ZmxvYXQgc3BlY3VsYXJJbnRlbnNpdHlGYWN0b3IgPSAxLjA7XHJcblx0XHR2ZWMzIHNwZWN1bGFyQ29sb3JGYWN0b3IgPSB2ZWMzKCAxLjAgKTtcclxuXHRcdG1hdGVyaWFsLnNwZWN1bGFyRjkwID0gMS4wO1xyXG5cclxuXHQjZW5kaWZcclxuXHJcblx0bWF0ZXJpYWwuc3BlY3VsYXJDb2xvciA9IG1peCggbWluKCBwb3cyKCAoIG1hdGVyaWFsLmlvciAtIDEuMCApIC8gKCBtYXRlcmlhbC5pb3IgKyAxLjAgKSApICogc3BlY3VsYXJDb2xvckZhY3RvciwgdmVjMyggMS4wICkgKSAqIHNwZWN1bGFySW50ZW5zaXR5RmFjdG9yLCBkaWZmdXNlQ29sb3IucmdiLCBtZXRhbG5lc3NGYWN0b3IgKTtcclxuXHJcbiNlbHNlXHJcblxyXG5cdG1hdGVyaWFsLnNwZWN1bGFyQ29sb3IgPSBtaXgoIHZlYzMoIDAuMDQgKSwgZGlmZnVzZUNvbG9yLnJnYiwgbWV0YWxuZXNzRmFjdG9yICk7XHJcblx0bWF0ZXJpYWwuc3BlY3VsYXJGOTAgPSAxLjA7XHJcblxyXG4jZW5kaWZcclxuXHJcbiNpZmRlZiBVU0VfQ0xFQVJDT0FUXHJcblxyXG5cdG1hdGVyaWFsLmNsZWFyY29hdCA9IGNsZWFyY29hdDtcclxuXHRtYXRlcmlhbC5jbGVhcmNvYXRSb3VnaG5lc3MgPSBjbGVhcmNvYXRSb3VnaG5lc3M7XHJcblx0bWF0ZXJpYWwuY2xlYXJjb2F0RjAgPSB2ZWMzKCAwLjA0ICk7XHJcblx0bWF0ZXJpYWwuY2xlYXJjb2F0RjkwID0gMS4wO1xyXG5cclxuXHQjaWZkZWYgVVNFX0NMRUFSQ09BVE1BUFxyXG5cclxuXHRcdG1hdGVyaWFsLmNsZWFyY29hdCAqPSB0ZXh0dXJlMkQoIGNsZWFyY29hdE1hcCwgdkNsZWFyY29hdE1hcFV2ICkueDtcclxuXHJcblx0I2VuZGlmXHJcblxyXG5cdCNpZmRlZiBVU0VfQ0xFQVJDT0FUX1JPVUdITkVTU01BUFxyXG5cclxuXHRcdG1hdGVyaWFsLmNsZWFyY29hdFJvdWdobmVzcyAqPSB0ZXh0dXJlMkQoIGNsZWFyY29hdFJvdWdobmVzc01hcCwgdkNsZWFyY29hdFJvdWdobmVzc01hcFV2ICkueTtcclxuXHJcblx0I2VuZGlmXHJcblxyXG5cdG1hdGVyaWFsLmNsZWFyY29hdCA9IHNhdHVyYXRlKCBtYXRlcmlhbC5jbGVhcmNvYXQgKTsgLy8gQnVybGV5IGNsZWFyY29hdCBtb2RlbFxyXG5cdG1hdGVyaWFsLmNsZWFyY29hdFJvdWdobmVzcyA9IG1heCggbWF0ZXJpYWwuY2xlYXJjb2F0Um91Z2huZXNzLCAwLjA1MjUgKTtcclxuXHRtYXRlcmlhbC5jbGVhcmNvYXRSb3VnaG5lc3MgKz0gZ2VvbWV0cnlSb3VnaG5lc3M7XHJcblx0bWF0ZXJpYWwuY2xlYXJjb2F0Um91Z2huZXNzID0gbWluKCBtYXRlcmlhbC5jbGVhcmNvYXRSb3VnaG5lc3MsIDEuMCApO1xyXG5cclxuI2VuZGlmXHJcblxyXG4jaWZkZWYgVVNFX0lSSURFU0NFTkNFXHJcblxyXG5cdG1hdGVyaWFsLmlyaWRlc2NlbmNlID0gaXJpZGVzY2VuY2U7XHJcblx0bWF0ZXJpYWwuaXJpZGVzY2VuY2VJT1IgPSBpcmlkZXNjZW5jZUlPUjtcclxuXHJcblx0I2lmZGVmIFVTRV9JUklERVNDRU5DRU1BUFxyXG5cclxuXHRcdG1hdGVyaWFsLmlyaWRlc2NlbmNlICo9IHRleHR1cmUyRCggaXJpZGVzY2VuY2VNYXAsIHZJcmlkZXNjZW5jZU1hcFV2ICkucjtcclxuXHJcblx0I2VuZGlmXHJcblxyXG5cdCNpZmRlZiBVU0VfSVJJREVTQ0VOQ0VfVEhJQ0tORVNTTUFQXHJcblxyXG5cdFx0bWF0ZXJpYWwuaXJpZGVzY2VuY2VUaGlja25lc3MgPSAoaXJpZGVzY2VuY2VUaGlja25lc3NNYXhpbXVtIC0gaXJpZGVzY2VuY2VUaGlja25lc3NNaW5pbXVtKSAqIHRleHR1cmUyRCggaXJpZGVzY2VuY2VUaGlja25lc3NNYXAsIHZJcmlkZXNjZW5jZVRoaWNrbmVzc01hcFV2ICkuZyArIGlyaWRlc2NlbmNlVGhpY2tuZXNzTWluaW11bTtcclxuXHJcblx0I2Vsc2VcclxuXHJcblx0XHRtYXRlcmlhbC5pcmlkZXNjZW5jZVRoaWNrbmVzcyA9IGlyaWRlc2NlbmNlVGhpY2tuZXNzTWF4aW11bTtcclxuXHJcblx0I2VuZGlmXHJcblxyXG4jZW5kaWZcclxuXHJcbiNpZmRlZiBVU0VfU0hFRU5cclxuXHJcblx0bWF0ZXJpYWwuc2hlZW5Db2xvciA9IHNoZWVuQ29sb3I7XHJcblxyXG5cdCNpZmRlZiBVU0VfU0hFRU5fQ09MT1JNQVBcclxuXHJcblx0XHRtYXRlcmlhbC5zaGVlbkNvbG9yICo9IHRleHR1cmUyRCggc2hlZW5Db2xvck1hcCwgdlNoZWVuQ29sb3JNYXBVdiApLnJnYjtcclxuXHJcblx0I2VuZGlmXHJcblxyXG5cdG1hdGVyaWFsLnNoZWVuUm91Z2huZXNzID0gY2xhbXAoIHNoZWVuUm91Z2huZXNzLCAwLjA3LCAxLjAgKTtcclxuXHJcblx0I2lmZGVmIFVTRV9TSEVFTl9ST1VHSE5FU1NNQVBcclxuXHJcblx0XHRtYXRlcmlhbC5zaGVlblJvdWdobmVzcyAqPSB0ZXh0dXJlMkQoIHNoZWVuUm91Z2huZXNzTWFwLCB2U2hlZW5Sb3VnaG5lc3NNYXBVdiApLmE7XHJcblxyXG5cdCNlbmRpZlxyXG5cclxuI2VuZGlmXHJcblxyXG4jaWZkZWYgVVNFX0FOSVNPVFJPUFlcclxuXHJcblx0I2lmZGVmIFVTRV9BTklTT1RST1BZTUFQXHJcblxyXG5cdFx0bWF0MiBhbmlzb3Ryb3B5TWF0ID0gbWF0MiggYW5pc290cm9weVZlY3Rvci54LCBhbmlzb3Ryb3B5VmVjdG9yLnksIC0gYW5pc290cm9weVZlY3Rvci55LCBhbmlzb3Ryb3B5VmVjdG9yLnggKTtcclxuXHRcdHZlYzMgYW5pc290cm9weVBvbGFyID0gdGV4dHVyZTJEKCBhbmlzb3Ryb3B5TWFwLCB2QW5pc290cm9weU1hcFV2ICkucmdiO1xyXG5cdFx0dmVjMiBhbmlzb3Ryb3B5ViA9IGFuaXNvdHJvcHlNYXQgKiBub3JtYWxpemUoIDIuMCAqIGFuaXNvdHJvcHlQb2xhci5yZyAtIHZlYzIoIDEuMCApICkgKiBhbmlzb3Ryb3B5UG9sYXIuYjtcclxuXHJcblx0I2Vsc2VcclxuXHJcblx0XHR2ZWMyIGFuaXNvdHJvcHlWID0gYW5pc290cm9weVZlY3RvcjtcclxuXHJcblx0I2VuZGlmXHJcblxyXG5cdG1hdGVyaWFsLmFuaXNvdHJvcHkgPSBsZW5ndGgoIGFuaXNvdHJvcHlWICk7XHJcblxyXG5cdGlmKCBtYXRlcmlhbC5hbmlzb3Ryb3B5ID09IDAuMCApIHtcclxuXHRcdGFuaXNvdHJvcHlWID0gdmVjMiggMS4wLCAwLjAgKTtcclxuXHR9IGVsc2Uge1xyXG5cdFx0YW5pc290cm9weVYgLz0gbWF0ZXJpYWwuYW5pc290cm9weTtcclxuXHRcdG1hdGVyaWFsLmFuaXNvdHJvcHkgPSBzYXR1cmF0ZSggbWF0ZXJpYWwuYW5pc290cm9weSApO1xyXG5cdH1cclxuXHJcblx0Ly8gUm91Z2huZXNzIGFsb25nIHRoZSBhbmlzb3Ryb3B5IGJpdGFuZ2VudCBpcyB0aGUgbWF0ZXJpYWwgcm91Z2huZXNzLCB3aGlsZSB0aGUgdGFuZ2VudCByb3VnaG5lc3MgaW5jcmVhc2VzIHdpdGggYW5pc290cm9weS5cclxuXHRtYXRlcmlhbC5hbHBoYVQgPSBtaXgoIHBvdzIoIG1hdGVyaWFsLnJvdWdobmVzcyApLCAxLjAsIHBvdzIoIG1hdGVyaWFsLmFuaXNvdHJvcHkgKSApO1xyXG5cclxuXHRtYXRlcmlhbC5hbmlzb3Ryb3B5VCA9IHRiblsgMCBdICogYW5pc290cm9weVYueCArIHRiblsgMSBdICogYW5pc290cm9weVYueTtcclxuXHRtYXRlcmlhbC5hbmlzb3Ryb3B5QiA9IHRiblsgMSBdICogYW5pc290cm9weVYueCAtIHRiblsgMCBdICogYW5pc290cm9weVYueTtcclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG5cclxuc3RydWN0IFBoeXNpY2FsTWF0ZXJpYWwge1xyXG5cclxuXHR2ZWMzIGRpZmZ1c2VDb2xvcjtcclxuXHRmbG9hdCByb3VnaG5lc3M7XHJcblx0dmVjMyBzcGVjdWxhckNvbG9yO1xyXG5cdGZsb2F0IHNwZWN1bGFyRjkwO1xyXG5cclxuXHQjaWZkZWYgVVNFX0NMRUFSQ09BVFxyXG5cdFx0ZmxvYXQgY2xlYXJjb2F0O1xyXG5cdFx0ZmxvYXQgY2xlYXJjb2F0Um91Z2huZXNzO1xyXG5cdFx0dmVjMyBjbGVhcmNvYXRGMDtcclxuXHRcdGZsb2F0IGNsZWFyY29hdEY5MDtcclxuXHQjZW5kaWZcclxuXHJcblx0I2lmZGVmIFVTRV9JUklERVNDRU5DRVxyXG5cdFx0ZmxvYXQgaXJpZGVzY2VuY2U7XHJcblx0XHRmbG9hdCBpcmlkZXNjZW5jZUlPUjtcclxuXHRcdGZsb2F0IGlyaWRlc2NlbmNlVGhpY2tuZXNzO1xyXG5cdFx0dmVjMyBpcmlkZXNjZW5jZUZyZXNuZWw7XHJcblx0XHR2ZWMzIGlyaWRlc2NlbmNlRjA7XHJcblx0I2VuZGlmXHJcblxyXG5cdCNpZmRlZiBVU0VfU0hFRU5cclxuXHRcdHZlYzMgc2hlZW5Db2xvcjtcclxuXHRcdGZsb2F0IHNoZWVuUm91Z2huZXNzO1xyXG5cdCNlbmRpZlxyXG5cclxuXHQjaWZkZWYgSU9SXHJcblx0XHRmbG9hdCBpb3I7XHJcblx0I2VuZGlmXHJcblxyXG5cdCNpZmRlZiBVU0VfVFJBTlNNSVNTSU9OXHJcblx0XHRmbG9hdCB0cmFuc21pc3Npb247XHJcblx0XHRmbG9hdCB0cmFuc21pc3Npb25BbHBoYTtcclxuXHRcdGZsb2F0IHRoaWNrbmVzcztcclxuXHRcdGZsb2F0IGF0dGVudWF0aW9uRGlzdGFuY2U7XHJcblx0XHR2ZWMzIGF0dGVudWF0aW9uQ29sb3I7XHJcblx0I2VuZGlmXHJcblxyXG5cdCNpZmRlZiBVU0VfQU5JU09UUk9QWVxyXG5cdFx0ZmxvYXQgYW5pc290cm9weTtcclxuXHRcdGZsb2F0IGFscGhhVDtcclxuXHRcdHZlYzMgYW5pc290cm9weVQ7XHJcblx0XHR2ZWMzIGFuaXNvdHJvcHlCO1xyXG5cdCNlbmRpZlxyXG5cclxufTtcclxuXHJcbi8vIHRlbXBvcmFyeVxyXG52ZWMzIGNsZWFyY29hdFNwZWN1bGFyRGlyZWN0ID0gdmVjMyggMC4wICk7XHJcbnZlYzMgY2xlYXJjb2F0U3BlY3VsYXJJbmRpcmVjdCA9IHZlYzMoIDAuMCApO1xyXG52ZWMzIHNoZWVuU3BlY3VsYXJEaXJlY3QgPSB2ZWMzKCAwLjAgKTtcclxudmVjMyBzaGVlblNwZWN1bGFySW5kaXJlY3QgPSB2ZWMzKDAuMCApO1xyXG5cclxudmVjMyBTY2hsaWNrX3RvX0YwKCBjb25zdCBpbiB2ZWMzIGYsIGNvbnN0IGluIGZsb2F0IGY5MCwgY29uc3QgaW4gZmxvYXQgZG90VkggKSB7XHJcbiAgICBmbG9hdCB4ID0gY2xhbXAoIDEuMCAtIGRvdFZILCAwLjAsIDEuMCApO1xyXG4gICAgZmxvYXQgeDIgPSB4ICogeDtcclxuICAgIGZsb2F0IHg1ID0gY2xhbXAoIHggKiB4MiAqIHgyLCAwLjAsIDAuOTk5OSApO1xyXG5cclxuICAgIHJldHVybiAoIGYgLSB2ZWMzKCBmOTAgKSAqIHg1ICkgLyAoIDEuMCAtIHg1ICk7XHJcbn1cclxuXHJcbi8vIE1vdmluZyBGcm9zdGJpdGUgdG8gUGh5c2ljYWxseSBCYXNlZCBSZW5kZXJpbmcgMy4wIC0gcGFnZSAxMiwgbGlzdGluZyAyXHJcbi8vIGh0dHBzOi8vc2VibGFnYXJkZS5maWxlcy53b3JkcHJlc3MuY29tLzIwMTUvMDcvY291cnNlX25vdGVzX21vdmluZ19mcm9zdGJpdGVfdG9fcGJyX3YzMi5wZGZcclxuZmxvYXQgVl9HR1hfU21pdGhDb3JyZWxhdGVkKCBjb25zdCBpbiBmbG9hdCBhbHBoYSwgY29uc3QgaW4gZmxvYXQgZG90TkwsIGNvbnN0IGluIGZsb2F0IGRvdE5WICkge1xyXG5cclxuXHRmbG9hdCBhMiA9IHBvdzIoIGFscGhhICk7XHJcblxyXG5cdGZsb2F0IGd2ID0gZG90TkwgKiBzcXJ0KCBhMiArICggMS4wIC0gYTIgKSAqIHBvdzIoIGRvdE5WICkgKTtcclxuXHRmbG9hdCBnbCA9IGRvdE5WICogc3FydCggYTIgKyAoIDEuMCAtIGEyICkgKiBwb3cyKCBkb3ROTCApICk7XHJcblxyXG5cdHJldHVybiAwLjUgLyBtYXgoIGd2ICsgZ2wsIEVQU0lMT04gKTtcclxuXHJcbn1cclxuXHJcbi8vIE1pY3JvZmFjZXQgTW9kZWxzIGZvciBSZWZyYWN0aW9uIHRocm91Z2ggUm91Z2ggU3VyZmFjZXMgLSBlcXVhdGlvbiAoMzMpXHJcbi8vIGh0dHA6Ly9ncmFwaGljcmFudHMuYmxvZ3Nwb3QuY29tLzIwMTMvMDgvc3BlY3VsYXItYnJkZi1yZWZlcmVuY2UuaHRtbFxyXG4vLyBhbHBoYSBpcyBcInJvdWdobmVzcyBzcXVhcmVkXCIgaW4gRGlzbmV54oCZcyByZXBhcmFtZXRlcml6YXRpb25cclxuZmxvYXQgRF9HR1goIGNvbnN0IGluIGZsb2F0IGFscGhhLCBjb25zdCBpbiBmbG9hdCBkb3ROSCApIHtcclxuXHJcblx0ZmxvYXQgYTIgPSBwb3cyKCBhbHBoYSApO1xyXG5cclxuXHRmbG9hdCBkZW5vbSA9IHBvdzIoIGRvdE5IICkgKiAoIGEyIC0gMS4wICkgKyAxLjA7IC8vIGF2b2lkIGFscGhhID0gMCB3aXRoIGRvdE5IID0gMVxyXG5cclxuXHRyZXR1cm4gUkVDSVBST0NBTF9QSSAqIGEyIC8gcG93MiggZGVub20gKTtcclxuXHJcbn1cclxuXHJcbi8vIGh0dHBzOi8vZ29vZ2xlLmdpdGh1Yi5pby9maWxhbWVudC9GaWxhbWVudC5tZC5odG1sI21hdGVyaWFsc3lzdGVtL2FuaXNvdHJvcGljbW9kZWwvYW5pc290cm9waWNzcGVjdWxhcmJyZGZcclxuI2lmZGVmIFVTRV9BTklTT1RST1BZXHJcblxyXG5cdGZsb2F0IFZfR0dYX1NtaXRoQ29ycmVsYXRlZF9Bbmlzb3Ryb3BpYyggY29uc3QgaW4gZmxvYXQgYWxwaGFULCBjb25zdCBpbiBmbG9hdCBhbHBoYUIsIGNvbnN0IGluIGZsb2F0IGRvdFRWLCBjb25zdCBpbiBmbG9hdCBkb3RCViwgY29uc3QgaW4gZmxvYXQgZG90VEwsIGNvbnN0IGluIGZsb2F0IGRvdEJMLCBjb25zdCBpbiBmbG9hdCBkb3ROViwgY29uc3QgaW4gZmxvYXQgZG90TkwgKSB7XHJcblxyXG5cdFx0ZmxvYXQgZ3YgPSBkb3ROTCAqIGxlbmd0aCggdmVjMyggYWxwaGFUICogZG90VFYsIGFscGhhQiAqIGRvdEJWLCBkb3ROViApICk7XHJcblx0XHRmbG9hdCBnbCA9IGRvdE5WICogbGVuZ3RoKCB2ZWMzKCBhbHBoYVQgKiBkb3RUTCwgYWxwaGFCICogZG90QkwsIGRvdE5MICkgKTtcclxuXHRcdGZsb2F0IHYgPSAwLjUgLyAoIGd2ICsgZ2wgKTtcclxuXHJcblx0XHRyZXR1cm4gc2F0dXJhdGUodik7XHJcblxyXG5cdH1cclxuXHJcblx0ZmxvYXQgRF9HR1hfQW5pc290cm9waWMoIGNvbnN0IGluIGZsb2F0IGFscGhhVCwgY29uc3QgaW4gZmxvYXQgYWxwaGFCLCBjb25zdCBpbiBmbG9hdCBkb3ROSCwgY29uc3QgaW4gZmxvYXQgZG90VEgsIGNvbnN0IGluIGZsb2F0IGRvdEJIICkge1xyXG5cclxuXHRcdGZsb2F0IGEyID0gYWxwaGFUICogYWxwaGFCO1xyXG5cdFx0aGlnaHAgdmVjMyB2ID0gdmVjMyggYWxwaGFCICogZG90VEgsIGFscGhhVCAqIGRvdEJILCBhMiAqIGRvdE5IICk7XHJcblx0XHRoaWdocCBmbG9hdCB2MiA9IGRvdCggdiwgdiApO1xyXG5cdFx0ZmxvYXQgdzIgPSBhMiAvIHYyO1xyXG5cclxuXHRcdHJldHVybiBSRUNJUFJPQ0FMX1BJICogYTIgKiBwb3cyICggdzIgKTtcclxuXHJcblx0fVxyXG5cclxuI2VuZGlmXHJcblxyXG4jaWZkZWYgVVNFX0NMRUFSQ09BVFxyXG5cclxuXHQvLyBHR1ggRGlzdHJpYnV0aW9uLCBTY2hsaWNrIEZyZXNuZWwsIEdHWF9TbWl0aENvcnJlbGF0ZWQgVmlzaWJpbGl0eVxyXG5cdHZlYzMgQlJERl9HR1hfQ2xlYXJjb2F0KCBjb25zdCBpbiB2ZWMzIGxpZ2h0RGlyLCBjb25zdCBpbiB2ZWMzIHZpZXdEaXIsIGNvbnN0IGluIHZlYzMgbm9ybWFsLCBjb25zdCBpbiBQaHlzaWNhbE1hdGVyaWFsIG1hdGVyaWFsKSB7XHJcblxyXG5cdFx0dmVjMyBmMCA9IG1hdGVyaWFsLmNsZWFyY29hdEYwO1xyXG5cdFx0ZmxvYXQgZjkwID0gbWF0ZXJpYWwuY2xlYXJjb2F0RjkwO1xyXG5cdFx0ZmxvYXQgcm91Z2huZXNzID0gbWF0ZXJpYWwuY2xlYXJjb2F0Um91Z2huZXNzO1xyXG5cclxuXHRcdGZsb2F0IGFscGhhID0gcG93Miggcm91Z2huZXNzICk7IC8vIFVFNCdzIHJvdWdobmVzc1xyXG5cclxuXHRcdHZlYzMgaGFsZkRpciA9IG5vcm1hbGl6ZSggbGlnaHREaXIgKyB2aWV3RGlyICk7XHJcblxyXG5cdFx0ZmxvYXQgZG90TkwgPSBzYXR1cmF0ZSggZG90KCBub3JtYWwsIGxpZ2h0RGlyICkgKTtcclxuXHRcdGZsb2F0IGRvdE5WID0gc2F0dXJhdGUoIGRvdCggbm9ybWFsLCB2aWV3RGlyICkgKTtcclxuXHRcdGZsb2F0IGRvdE5IID0gc2F0dXJhdGUoIGRvdCggbm9ybWFsLCBoYWxmRGlyICkgKTtcclxuXHRcdGZsb2F0IGRvdFZIID0gc2F0dXJhdGUoIGRvdCggdmlld0RpciwgaGFsZkRpciApICk7XHJcblxyXG5cdFx0dmVjMyBGID0gRl9TY2hsaWNrKCBmMCwgZjkwLCBkb3RWSCApO1xyXG5cclxuXHRcdGZsb2F0IFYgPSBWX0dHWF9TbWl0aENvcnJlbGF0ZWQoIGFscGhhLCBkb3ROTCwgZG90TlYgKTtcclxuXHJcblx0XHRmbG9hdCBEID0gRF9HR1goIGFscGhhLCBkb3ROSCApO1xyXG5cclxuXHRcdHJldHVybiBGICogKCBWICogRCApO1xyXG5cclxuXHR9XHJcblxyXG4jZW5kaWZcclxuXHJcbnZlYzMgQlJERl9HR1goIGNvbnN0IGluIHZlYzMgbGlnaHREaXIsIGNvbnN0IGluIHZlYzMgdmlld0RpciwgY29uc3QgaW4gdmVjMyBub3JtYWwsIGNvbnN0IGluIFBoeXNpY2FsTWF0ZXJpYWwgbWF0ZXJpYWwgKSB7XHJcblxyXG5cdHZlYzMgZjAgPSBtYXRlcmlhbC5zcGVjdWxhckNvbG9yO1xyXG5cdGZsb2F0IGY5MCA9IG1hdGVyaWFsLnNwZWN1bGFyRjkwO1xyXG5cdGZsb2F0IHJvdWdobmVzcyA9IG1hdGVyaWFsLnJvdWdobmVzcztcclxuXHJcblx0ZmxvYXQgYWxwaGEgPSBwb3cyKCByb3VnaG5lc3MgKTsgLy8gVUU0J3Mgcm91Z2huZXNzXHJcblxyXG5cdHZlYzMgaGFsZkRpciA9IG5vcm1hbGl6ZSggbGlnaHREaXIgKyB2aWV3RGlyICk7XHJcblxyXG5cdGZsb2F0IGRvdE5MID0gc2F0dXJhdGUoIGRvdCggbm9ybWFsLCBsaWdodERpciApICk7XHJcblx0ZmxvYXQgZG90TlYgPSBzYXR1cmF0ZSggZG90KCBub3JtYWwsIHZpZXdEaXIgKSApO1xyXG5cdGZsb2F0IGRvdE5IID0gc2F0dXJhdGUoIGRvdCggbm9ybWFsLCBoYWxmRGlyICkgKTtcclxuXHRmbG9hdCBkb3RWSCA9IHNhdHVyYXRlKCBkb3QoIHZpZXdEaXIsIGhhbGZEaXIgKSApO1xyXG5cclxuXHR2ZWMzIEYgPSBGX1NjaGxpY2soIGYwLCBmOTAsIGRvdFZIICk7XHJcblxyXG5cdCNpZmRlZiBVU0VfSVJJREVTQ0VOQ0VcclxuXHJcblx0XHRGID0gbWl4KCBGLCBtYXRlcmlhbC5pcmlkZXNjZW5jZUZyZXNuZWwsIG1hdGVyaWFsLmlyaWRlc2NlbmNlICk7XHJcblxyXG5cdCNlbmRpZlxyXG5cclxuXHQjaWZkZWYgVVNFX0FOSVNPVFJPUFlcclxuXHJcblx0XHRmbG9hdCBkb3RUTCA9IGRvdCggbWF0ZXJpYWwuYW5pc290cm9weVQsIGxpZ2h0RGlyICk7XHJcblx0XHRmbG9hdCBkb3RUViA9IGRvdCggbWF0ZXJpYWwuYW5pc290cm9weVQsIHZpZXdEaXIgKTtcclxuXHRcdGZsb2F0IGRvdFRIID0gZG90KCBtYXRlcmlhbC5hbmlzb3Ryb3B5VCwgaGFsZkRpciApO1xyXG5cdFx0ZmxvYXQgZG90QkwgPSBkb3QoIG1hdGVyaWFsLmFuaXNvdHJvcHlCLCBsaWdodERpciApO1xyXG5cdFx0ZmxvYXQgZG90QlYgPSBkb3QoIG1hdGVyaWFsLmFuaXNvdHJvcHlCLCB2aWV3RGlyICk7XHJcblx0XHRmbG9hdCBkb3RCSCA9IGRvdCggbWF0ZXJpYWwuYW5pc290cm9weUIsIGhhbGZEaXIgKTtcclxuXHJcblx0XHRmbG9hdCBWID0gVl9HR1hfU21pdGhDb3JyZWxhdGVkX0FuaXNvdHJvcGljKCBtYXRlcmlhbC5hbHBoYVQsIGFscGhhLCBkb3RUViwgZG90QlYsIGRvdFRMLCBkb3RCTCwgZG90TlYsIGRvdE5MICk7XHJcblxyXG5cdFx0ZmxvYXQgRCA9IERfR0dYX0FuaXNvdHJvcGljKCBtYXRlcmlhbC5hbHBoYVQsIGFscGhhLCBkb3ROSCwgZG90VEgsIGRvdEJIICk7XHJcblxyXG5cdCNlbHNlXHJcblxyXG5cdFx0ZmxvYXQgViA9IFZfR0dYX1NtaXRoQ29ycmVsYXRlZCggYWxwaGEsIGRvdE5MLCBkb3ROViApO1xyXG5cclxuXHRcdGZsb2F0IEQgPSBEX0dHWCggYWxwaGEsIGRvdE5IICk7XHJcblxyXG5cdCNlbmRpZlxyXG5cclxuXHRyZXR1cm4gRiAqICggViAqIEQgKTtcclxuXHJcbn1cclxuXHJcbi8vIFJlY3QgQXJlYSBMaWdodFxyXG5cclxuLy8gUmVhbC1UaW1lIFBvbHlnb25hbC1MaWdodCBTaGFkaW5nIHdpdGggTGluZWFybHkgVHJhbnNmb3JtZWQgQ29zaW5lc1xyXG4vLyBieSBFcmljIEhlaXR6LCBKb25hdGhhbiBEdXB1eSwgU3RlcGhlbiBIaWxsIGFuZCBEYXZpZCBOZXViZWx0XHJcbi8vIGNvZGU6IGh0dHBzOi8vZ2l0aHViLmNvbS9zZWxmc2hhZG93L2x0Y19jb2RlL1xyXG5cclxudmVjMiBMVENfVXYoIGNvbnN0IGluIHZlYzMgTiwgY29uc3QgaW4gdmVjMyBWLCBjb25zdCBpbiBmbG9hdCByb3VnaG5lc3MgKSB7XHJcblxyXG5cdGNvbnN0IGZsb2F0IExVVF9TSVpFID0gNjQuMDtcclxuXHRjb25zdCBmbG9hdCBMVVRfU0NBTEUgPSAoIExVVF9TSVpFIC0gMS4wICkgLyBMVVRfU0laRTtcclxuXHRjb25zdCBmbG9hdCBMVVRfQklBUyA9IDAuNSAvIExVVF9TSVpFO1xyXG5cclxuXHRmbG9hdCBkb3ROViA9IHNhdHVyYXRlKCBkb3QoIE4sIFYgKSApO1xyXG5cclxuXHQvLyB0ZXh0dXJlIHBhcmFtZXRlcml6ZWQgYnkgc3FydCggR0dYIGFscGhhICkgYW5kIHNxcnQoIDEgLSBjb3MoIHRoZXRhICkgKVxyXG5cdHZlYzIgdXYgPSB2ZWMyKCByb3VnaG5lc3MsIHNxcnQoIDEuMCAtIGRvdE5WICkgKTtcclxuXHJcblx0dXYgPSB1diAqIExVVF9TQ0FMRSArIExVVF9CSUFTO1xyXG5cclxuXHRyZXR1cm4gdXY7XHJcblxyXG59XHJcblxyXG5mbG9hdCBMVENfQ2xpcHBlZFNwaGVyZUZvcm1GYWN0b3IoIGNvbnN0IGluIHZlYzMgZiApIHtcclxuXHJcblx0Ly8gUmVhbC1UaW1lIEFyZWEgTGlnaHRpbmc6IGEgSm91cm5leSBmcm9tIFJlc2VhcmNoIHRvIFByb2R1Y3Rpb24gKHAuMTAyKVxyXG5cdC8vIEFuIGFwcHJveGltYXRpb24gb2YgdGhlIGZvcm0gZmFjdG9yIG9mIGEgaG9yaXpvbi1jbGlwcGVkIHJlY3RhbmdsZS5cclxuXHJcblx0ZmxvYXQgbCA9IGxlbmd0aCggZiApO1xyXG5cclxuXHRyZXR1cm4gbWF4KCAoIGwgKiBsICsgZi56ICkgLyAoIGwgKyAxLjAgKSwgMC4wICk7XHJcblxyXG59XHJcblxyXG52ZWMzIExUQ19FZGdlVmVjdG9yRm9ybUZhY3RvciggY29uc3QgaW4gdmVjMyB2MSwgY29uc3QgaW4gdmVjMyB2MiApIHtcclxuXHJcblx0ZmxvYXQgeCA9IGRvdCggdjEsIHYyICk7XHJcblxyXG5cdGZsb2F0IHkgPSBhYnMoIHggKTtcclxuXHJcblx0Ly8gcmF0aW9uYWwgcG9seW5vbWlhbCBhcHByb3hpbWF0aW9uIHRvIHRoZXRhIC8gc2luKCB0aGV0YSApIC8gMlBJXHJcblx0ZmxvYXQgYSA9IDAuODU0Mzk4NSArICggMC40OTY1MTU1ICsgMC4wMTQ1MjA2ICogeSApICogeTtcclxuXHRmbG9hdCBiID0gMy40MTc1OTQwICsgKCA0LjE2MTY3MjQgKyB5ICkgKiB5O1xyXG5cdGZsb2F0IHYgPSBhIC8gYjtcclxuXHJcblx0ZmxvYXQgdGhldGFfc2ludGhldGEgPSAoIHggPiAwLjAgKSA/IHYgOiAwLjUgKiBpbnZlcnNlc3FydCggbWF4KCAxLjAgLSB4ICogeCwgMWUtNyApICkgLSB2O1xyXG5cclxuXHRyZXR1cm4gY3Jvc3MoIHYxLCB2MiApICogdGhldGFfc2ludGhldGE7XHJcblxyXG59XHJcblxyXG52ZWMzIExUQ19FdmFsdWF0ZSggY29uc3QgaW4gdmVjMyBOLCBjb25zdCBpbiB2ZWMzIFYsIGNvbnN0IGluIHZlYzMgUCwgY29uc3QgaW4gbWF0MyBtSW52LCBjb25zdCBpbiB2ZWMzIHJlY3RDb29yZHNbIDQgXSApIHtcclxuXHJcblx0Ly8gYmFpbCBpZiBwb2ludCBpcyBvbiBiYWNrIHNpZGUgb2YgcGxhbmUgb2YgbGlnaHRcclxuXHQvLyBhc3N1bWVzIGNjdyB3aW5kaW5nIG9yZGVyIG9mIGxpZ2h0IHZlcnRpY2VzXHJcblx0dmVjMyB2MSA9IHJlY3RDb29yZHNbIDEgXSAtIHJlY3RDb29yZHNbIDAgXTtcclxuXHR2ZWMzIHYyID0gcmVjdENvb3Jkc1sgMyBdIC0gcmVjdENvb3Jkc1sgMCBdO1xyXG5cdHZlYzMgbGlnaHROb3JtYWwgPSBjcm9zcyggdjEsIHYyICk7XHJcblxyXG5cdGlmKCBkb3QoIGxpZ2h0Tm9ybWFsLCBQIC0gcmVjdENvb3Jkc1sgMCBdICkgPCAwLjAgKSByZXR1cm4gdmVjMyggMC4wICk7XHJcblxyXG5cdC8vIGNvbnN0cnVjdCBvcnRob25vcm1hbCBiYXNpcyBhcm91bmQgTlxyXG5cdHZlYzMgVDEsIFQyO1xyXG5cdFQxID0gbm9ybWFsaXplKCBWIC0gTiAqIGRvdCggViwgTiApICk7XHJcblx0VDIgPSAtIGNyb3NzKCBOLCBUMSApOyAvLyBuZWdhdGVkIGZyb20gcGFwZXI7IHBvc3NpYmx5IGR1ZSB0byBhIGRpZmZlcmVudCBoYW5kZWRuZXNzIG9mIHdvcmxkIGNvb3JkaW5hdGUgc3lzdGVtXHJcblxyXG5cdC8vIGNvbXB1dGUgdHJhbnNmb3JtXHJcblx0bWF0MyBtYXQgPSBtSW52ICogdHJhbnNwb3NlTWF0MyggbWF0MyggVDEsIFQyLCBOICkgKTtcclxuXHJcblx0Ly8gdHJhbnNmb3JtIHJlY3RcclxuXHR2ZWMzIGNvb3Jkc1sgNCBdO1xyXG5cdGNvb3Jkc1sgMCBdID0gbWF0ICogKCByZWN0Q29vcmRzWyAwIF0gLSBQICk7XHJcblx0Y29vcmRzWyAxIF0gPSBtYXQgKiAoIHJlY3RDb29yZHNbIDEgXSAtIFAgKTtcclxuXHRjb29yZHNbIDIgXSA9IG1hdCAqICggcmVjdENvb3Jkc1sgMiBdIC0gUCApO1xyXG5cdGNvb3Jkc1sgMyBdID0gbWF0ICogKCByZWN0Q29vcmRzWyAzIF0gLSBQICk7XHJcblxyXG5cdC8vIHByb2plY3QgcmVjdCBvbnRvIHNwaGVyZVxyXG5cdGNvb3Jkc1sgMCBdID0gbm9ybWFsaXplKCBjb29yZHNbIDAgXSApO1xyXG5cdGNvb3Jkc1sgMSBdID0gbm9ybWFsaXplKCBjb29yZHNbIDEgXSApO1xyXG5cdGNvb3Jkc1sgMiBdID0gbm9ybWFsaXplKCBjb29yZHNbIDIgXSApO1xyXG5cdGNvb3Jkc1sgMyBdID0gbm9ybWFsaXplKCBjb29yZHNbIDMgXSApO1xyXG5cclxuXHQvLyBjYWxjdWxhdGUgdmVjdG9yIGZvcm0gZmFjdG9yXHJcblx0dmVjMyB2ZWN0b3JGb3JtRmFjdG9yID0gdmVjMyggMC4wICk7XHJcblx0dmVjdG9yRm9ybUZhY3RvciArPSBMVENfRWRnZVZlY3RvckZvcm1GYWN0b3IoIGNvb3Jkc1sgMCBdLCBjb29yZHNbIDEgXSApO1xyXG5cdHZlY3RvckZvcm1GYWN0b3IgKz0gTFRDX0VkZ2VWZWN0b3JGb3JtRmFjdG9yKCBjb29yZHNbIDEgXSwgY29vcmRzWyAyIF0gKTtcclxuXHR2ZWN0b3JGb3JtRmFjdG9yICs9IExUQ19FZGdlVmVjdG9yRm9ybUZhY3RvciggY29vcmRzWyAyIF0sIGNvb3Jkc1sgMyBdICk7XHJcblx0dmVjdG9yRm9ybUZhY3RvciArPSBMVENfRWRnZVZlY3RvckZvcm1GYWN0b3IoIGNvb3Jkc1sgMyBdLCBjb29yZHNbIDAgXSApO1xyXG5cclxuXHQvLyBhZGp1c3QgZm9yIGhvcml6b24gY2xpcHBpbmdcclxuXHRmbG9hdCByZXN1bHQgPSBMVENfQ2xpcHBlZFNwaGVyZUZvcm1GYWN0b3IoIHZlY3RvckZvcm1GYWN0b3IgKTtcclxuXHJcbi8qXHJcblx0Ly8gYWx0ZXJuYXRlIG1ldGhvZCBvZiBhZGp1c3RpbmcgZm9yIGhvcml6b24gY2xpcHBpbmcgKHNlZSByZWZlcmVjZSlcclxuXHQvLyByZWZhY3RvcmluZyByZXF1aXJlZFxyXG5cdGZsb2F0IGxlbiA9IGxlbmd0aCggdmVjdG9yRm9ybUZhY3RvciApO1xyXG5cdGZsb2F0IHogPSB2ZWN0b3JGb3JtRmFjdG9yLnogLyBsZW47XHJcblxyXG5cdGNvbnN0IGZsb2F0IExVVF9TSVpFID0gNjQuMDtcclxuXHRjb25zdCBmbG9hdCBMVVRfU0NBTEUgPSAoIExVVF9TSVpFIC0gMS4wICkgLyBMVVRfU0laRTtcclxuXHRjb25zdCBmbG9hdCBMVVRfQklBUyA9IDAuNSAvIExVVF9TSVpFO1xyXG5cclxuXHQvLyB0YWJ1bGF0ZWQgaG9yaXpvbi1jbGlwcGVkIHNwaGVyZSwgYXBwYXJlbnRseS4uLlxyXG5cdHZlYzIgdXYgPSB2ZWMyKCB6ICogMC41ICsgMC41LCBsZW4gKTtcclxuXHR1diA9IHV2ICogTFVUX1NDQUxFICsgTFVUX0JJQVM7XHJcblxyXG5cdGZsb2F0IHNjYWxlID0gdGV4dHVyZTJEKCBsdGNfMiwgdXYgKS53O1xyXG5cclxuXHRmbG9hdCByZXN1bHQgPSBsZW4gKiBzY2FsZTtcclxuKi9cclxuXHJcblx0cmV0dXJuIHZlYzMoIHJlc3VsdCApO1xyXG5cclxufVxyXG5cclxuLy8gRW5kIFJlY3QgQXJlYSBMaWdodFxyXG5cclxuI2lmIGRlZmluZWQoIFVTRV9TSEVFTiApXHJcblxyXG4vLyBodHRwczovL2dpdGh1Yi5jb20vZ29vZ2xlL2ZpbGFtZW50L2Jsb2IvbWFzdGVyL3NoYWRlcnMvc3JjL2JyZGYuZnNcclxuZmxvYXQgRF9DaGFybGllKCBmbG9hdCByb3VnaG5lc3MsIGZsb2F0IGRvdE5IICkge1xyXG5cclxuXHRmbG9hdCBhbHBoYSA9IHBvdzIoIHJvdWdobmVzcyApO1xyXG5cclxuXHQvLyBFc3RldmV6IGFuZCBLdWxsYSAyMDE3LCBcIlByb2R1Y3Rpb24gRnJpZW5kbHkgTWljcm9mYWNldCBTaGVlbiBCUkRGXCJcclxuXHRmbG9hdCBpbnZBbHBoYSA9IDEuMCAvIGFscGhhO1xyXG5cdGZsb2F0IGNvczJoID0gZG90TkggKiBkb3ROSDtcclxuXHRmbG9hdCBzaW4yaCA9IG1heCggMS4wIC0gY29zMmgsIDAuMDA3ODEyNSApOyAvLyAyXigtMTQvMiksIHNvIHNpbjJoXjIgPiAwIGluIGZwMTZcclxuXHJcblx0cmV0dXJuICggMi4wICsgaW52QWxwaGEgKSAqIHBvdyggc2luMmgsIGludkFscGhhICogMC41ICkgLyAoIDIuMCAqIFBJICk7XHJcblxyXG59XHJcblxyXG4vLyBodHRwczovL2dpdGh1Yi5jb20vZ29vZ2xlL2ZpbGFtZW50L2Jsb2IvbWFzdGVyL3NoYWRlcnMvc3JjL2JyZGYuZnNcclxuZmxvYXQgVl9OZXViZWx0KCBmbG9hdCBkb3ROViwgZmxvYXQgZG90TkwgKSB7XHJcblxyXG5cdC8vIE5ldWJlbHQgYW5kIFBldHRpbmVvIDIwMTMsIFwiQ3JhZnRpbmcgYSBOZXh0LWdlbiBNYXRlcmlhbCBQaXBlbGluZSBmb3IgVGhlIE9yZGVyOiAxODg2XCJcclxuXHRyZXR1cm4gc2F0dXJhdGUoIDEuMCAvICggNC4wICogKCBkb3ROTCArIGRvdE5WIC0gZG90TkwgKiBkb3ROViApICkgKTtcclxuXHJcbn1cclxuXHJcbnZlYzMgQlJERl9TaGVlbiggY29uc3QgaW4gdmVjMyBsaWdodERpciwgY29uc3QgaW4gdmVjMyB2aWV3RGlyLCBjb25zdCBpbiB2ZWMzIG5vcm1hbCwgdmVjMyBzaGVlbkNvbG9yLCBjb25zdCBpbiBmbG9hdCBzaGVlblJvdWdobmVzcyApIHtcclxuXHJcblx0dmVjMyBoYWxmRGlyID0gbm9ybWFsaXplKCBsaWdodERpciArIHZpZXdEaXIgKTtcclxuXHJcblx0ZmxvYXQgZG90TkwgPSBzYXR1cmF0ZSggZG90KCBub3JtYWwsIGxpZ2h0RGlyICkgKTtcclxuXHRmbG9hdCBkb3ROViA9IHNhdHVyYXRlKCBkb3QoIG5vcm1hbCwgdmlld0RpciApICk7XHJcblx0ZmxvYXQgZG90TkggPSBzYXR1cmF0ZSggZG90KCBub3JtYWwsIGhhbGZEaXIgKSApO1xyXG5cclxuXHRmbG9hdCBEID0gRF9DaGFybGllKCBzaGVlblJvdWdobmVzcywgZG90TkggKTtcclxuXHRmbG9hdCBWID0gVl9OZXViZWx0KCBkb3ROViwgZG90TkwgKTtcclxuXHJcblx0cmV0dXJuIHNoZWVuQ29sb3IgKiAoIEQgKiBWICk7XHJcblxyXG59XHJcblxyXG4jZW5kaWZcclxuXHJcbi8vIFRoaXMgaXMgYSBjdXJ2ZS1maXQgYXBwcm94bWF0aW9uIHRvIHRoZSBcIkNoYXJsaWUgc2hlZW5cIiBCUkRGIGludGVncmF0ZWQgb3ZlciB0aGUgaGVtaXNwaGVyZSBmcm9tIFxyXG4vLyBFc3RldmV6IGFuZCBLdWxsYSAyMDE3LCBcIlByb2R1Y3Rpb24gRnJpZW5kbHkgTWljcm9mYWNldCBTaGVlbiBCUkRGXCIuIFRoZSBhbmFseXNpcyBjYW4gYmUgZm91bmRcclxuLy8gaW4gdGhlIFNoZWVuIHNlY3Rpb24gb2YgaHR0cHM6Ly9kcml2ZS5nb29nbGUuY29tL2ZpbGUvZC8xVDBEMVZTeVI0QWxscUlKVFFBcmFFSXpqbGI1aDRGS0gvdmlldz91c3A9c2hhcmluZ1xyXG5mbG9hdCBJQkxTaGVlbkJSREYoIGNvbnN0IGluIHZlYzMgbm9ybWFsLCBjb25zdCBpbiB2ZWMzIHZpZXdEaXIsIGNvbnN0IGluIGZsb2F0IHJvdWdobmVzcyApIHtcclxuXHJcblx0ZmxvYXQgZG90TlYgPSBzYXR1cmF0ZSggZG90KCBub3JtYWwsIHZpZXdEaXIgKSApO1xyXG5cclxuXHRmbG9hdCByMiA9IHJvdWdobmVzcyAqIHJvdWdobmVzcztcclxuXHJcblx0ZmxvYXQgYSA9IHJvdWdobmVzcyA8IDAuMjUgPyAtMzM5LjIgKiByMiArIDE2MS40ICogcm91Z2huZXNzIC0gMjUuOSA6IC04LjQ4ICogcjIgKyAxNC4zICogcm91Z2huZXNzIC0gOS45NTtcclxuXHJcblx0ZmxvYXQgYiA9IHJvdWdobmVzcyA8IDAuMjUgPyA0NC4wICogcjIgLSAyMy43ICogcm91Z2huZXNzICsgMy4yNiA6IDEuOTcgKiByMiAtIDMuMjcgKiByb3VnaG5lc3MgKyAwLjcyO1xyXG5cclxuXHRmbG9hdCBERyA9IGV4cCggYSAqIGRvdE5WICsgYiApICsgKCByb3VnaG5lc3MgPCAwLjI1ID8gMC4wIDogMC4xICogKCByb3VnaG5lc3MgLSAwLjI1ICkgKTtcclxuXHJcblx0cmV0dXJuIHNhdHVyYXRlKCBERyAqIFJFQ0lQUk9DQUxfUEkgKTtcclxuXHJcbn1cclxuXHJcbi8vIEFuYWx5dGljYWwgYXBwcm94aW1hdGlvbiBvZiB0aGUgREZHIExVVCwgb25lIGhhbGYgb2YgdGhlXHJcbi8vIHNwbGl0LXN1bSBhcHByb3hpbWF0aW9uIHVzZWQgaW4gaW5kaXJlY3Qgc3BlY3VsYXIgbGlnaHRpbmcuXHJcbi8vIHZpYSAnZW52aXJvbm1lbnRCUkRGJyBmcm9tIFwiUGh5c2ljYWxseSBCYXNlZCBTaGFkaW5nIG9uIE1vYmlsZVwiXHJcbi8vIGh0dHBzOi8vd3d3LnVucmVhbGVuZ2luZS5jb20vYmxvZy9waHlzaWNhbGx5LWJhc2VkLXNoYWRpbmctb24tbW9iaWxlXHJcbnZlYzIgREZHQXBwcm94KCBjb25zdCBpbiB2ZWMzIG5vcm1hbCwgY29uc3QgaW4gdmVjMyB2aWV3RGlyLCBjb25zdCBpbiBmbG9hdCByb3VnaG5lc3MgKSB7XHJcblxyXG5cdGZsb2F0IGRvdE5WID0gc2F0dXJhdGUoIGRvdCggbm9ybWFsLCB2aWV3RGlyICkgKTtcclxuXHJcblx0Y29uc3QgdmVjNCBjMCA9IHZlYzQoIC0gMSwgLSAwLjAyNzUsIC0gMC41NzIsIDAuMDIyICk7XHJcblxyXG5cdGNvbnN0IHZlYzQgYzEgPSB2ZWM0KCAxLCAwLjA0MjUsIDEuMDQsIC0gMC4wNCApO1xyXG5cclxuXHR2ZWM0IHIgPSByb3VnaG5lc3MgKiBjMCArIGMxO1xyXG5cclxuXHRmbG9hdCBhMDA0ID0gbWluKCByLnggKiByLngsIGV4cDIoIC0gOS4yOCAqIGRvdE5WICkgKSAqIHIueCArIHIueTtcclxuXHJcblx0dmVjMiBmYWIgPSB2ZWMyKCAtIDEuMDQsIDEuMDQgKSAqIGEwMDQgKyByLnp3O1xyXG5cclxuXHRyZXR1cm4gZmFiO1xyXG5cclxufVxyXG5cclxudmVjMyBFbnZpcm9ubWVudEJSREYoIGNvbnN0IGluIHZlYzMgbm9ybWFsLCBjb25zdCBpbiB2ZWMzIHZpZXdEaXIsIGNvbnN0IGluIHZlYzMgc3BlY3VsYXJDb2xvciwgY29uc3QgaW4gZmxvYXQgc3BlY3VsYXJGOTAsIGNvbnN0IGluIGZsb2F0IHJvdWdobmVzcyApIHtcclxuXHJcblx0dmVjMiBmYWIgPSBERkdBcHByb3goIG5vcm1hbCwgdmlld0Rpciwgcm91Z2huZXNzICk7XHJcblxyXG5cdHJldHVybiBzcGVjdWxhckNvbG9yICogZmFiLnggKyBzcGVjdWxhckY5MCAqIGZhYi55O1xyXG5cclxufVxyXG5cclxuLy8gRmRlei1BZ8O8ZXJhJ3MgXCJNdWx0aXBsZS1TY2F0dGVyaW5nIE1pY3JvZmFjZXQgTW9kZWwgZm9yIFJlYWwtVGltZSBJbWFnZSBCYXNlZCBMaWdodGluZ1wiXHJcbi8vIEFwcHJveGltYXRlcyBtdWx0aXNjYXR0ZXJpbmcgaW4gb3JkZXIgdG8gcHJlc2VydmUgZW5lcmd5LlxyXG4vLyBodHRwOi8vd3d3LmpjZ3Qub3JnL3B1Ymxpc2hlZC8wMDA4LzAxLzAzL1xyXG4jaWZkZWYgVVNFX0lSSURFU0NFTkNFXHJcbnZvaWQgY29tcHV0ZU11bHRpc2NhdHRlcmluZ0lyaWRlc2NlbmNlKCBjb25zdCBpbiB2ZWMzIG5vcm1hbCwgY29uc3QgaW4gdmVjMyB2aWV3RGlyLCBjb25zdCBpbiB2ZWMzIHNwZWN1bGFyQ29sb3IsIGNvbnN0IGluIGZsb2F0IHNwZWN1bGFyRjkwLCBjb25zdCBpbiBmbG9hdCBpcmlkZXNjZW5jZSwgY29uc3QgaW4gdmVjMyBpcmlkZXNjZW5jZUYwLCBjb25zdCBpbiBmbG9hdCByb3VnaG5lc3MsIGlub3V0IHZlYzMgc2luZ2xlU2NhdHRlciwgaW5vdXQgdmVjMyBtdWx0aVNjYXR0ZXIgKSB7XHJcbiNlbHNlXHJcbnZvaWQgY29tcHV0ZU11bHRpc2NhdHRlcmluZyggY29uc3QgaW4gdmVjMyBub3JtYWwsIGNvbnN0IGluIHZlYzMgdmlld0RpciwgY29uc3QgaW4gdmVjMyBzcGVjdWxhckNvbG9yLCBjb25zdCBpbiBmbG9hdCBzcGVjdWxhckY5MCwgY29uc3QgaW4gZmxvYXQgcm91Z2huZXNzLCBpbm91dCB2ZWMzIHNpbmdsZVNjYXR0ZXIsIGlub3V0IHZlYzMgbXVsdGlTY2F0dGVyICkge1xyXG4jZW5kaWZcclxuXHJcblx0dmVjMiBmYWIgPSBERkdBcHByb3goIG5vcm1hbCwgdmlld0Rpciwgcm91Z2huZXNzICk7XHJcblxyXG5cdCNpZmRlZiBVU0VfSVJJREVTQ0VOQ0VcclxuXHJcblx0XHR2ZWMzIEZyID0gbWl4KCBzcGVjdWxhckNvbG9yLCBpcmlkZXNjZW5jZUYwLCBpcmlkZXNjZW5jZSApO1xyXG5cclxuXHQjZWxzZVxyXG5cclxuXHRcdHZlYzMgRnIgPSBzcGVjdWxhckNvbG9yO1xyXG5cclxuXHQjZW5kaWZcclxuXHJcblx0dmVjMyBGc3NFc3MgPSBGciAqIGZhYi54ICsgc3BlY3VsYXJGOTAgKiBmYWIueTtcclxuXHJcblx0ZmxvYXQgRXNzID0gZmFiLnggKyBmYWIueTtcclxuXHRmbG9hdCBFbXMgPSAxLjAgLSBFc3M7XHJcblxyXG5cdHZlYzMgRmF2ZyA9IEZyICsgKCAxLjAgLSBGciApICogMC4wNDc2MTk7IC8vIDEvMjFcclxuXHR2ZWMzIEZtcyA9IEZzc0VzcyAqIEZhdmcgLyAoIDEuMCAtIEVtcyAqIEZhdmcgKTtcclxuXHJcblx0c2luZ2xlU2NhdHRlciArPSBGc3NFc3M7XHJcblx0bXVsdGlTY2F0dGVyICs9IEZtcyAqIEVtcztcclxuXHJcbn1cclxuXHJcbiNpZiBOVU1fUkVDVF9BUkVBX0xJR0hUUyA+IDBcclxuXHJcblx0dm9pZCBSRV9EaXJlY3RfUmVjdEFyZWFfUGh5c2ljYWwoIGNvbnN0IGluIFJlY3RBcmVhTGlnaHQgcmVjdEFyZWFMaWdodCwgY29uc3QgaW4gdmVjMyBnZW9tZXRyeVBvc2l0aW9uLCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5Tm9ybWFsLCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5Vmlld0RpciwgY29uc3QgaW4gdmVjMyBnZW9tZXRyeUNsZWFyY29hdE5vcm1hbCwgY29uc3QgaW4gUGh5c2ljYWxNYXRlcmlhbCBtYXRlcmlhbCwgaW5vdXQgUmVmbGVjdGVkTGlnaHQgcmVmbGVjdGVkTGlnaHQgKSB7XHJcblxyXG5cdFx0dmVjMyBub3JtYWwgPSBnZW9tZXRyeU5vcm1hbDtcclxuXHRcdHZlYzMgdmlld0RpciA9IGdlb21ldHJ5Vmlld0RpcjtcclxuXHRcdHZlYzMgcG9zaXRpb24gPSBnZW9tZXRyeVBvc2l0aW9uO1xyXG5cdFx0dmVjMyBsaWdodFBvcyA9IHJlY3RBcmVhTGlnaHQucG9zaXRpb247XHJcblx0XHR2ZWMzIGhhbGZXaWR0aCA9IHJlY3RBcmVhTGlnaHQuaGFsZldpZHRoO1xyXG5cdFx0dmVjMyBoYWxmSGVpZ2h0ID0gcmVjdEFyZWFMaWdodC5oYWxmSGVpZ2h0O1xyXG5cdFx0dmVjMyBsaWdodENvbG9yID0gcmVjdEFyZWFMaWdodC5jb2xvcjtcclxuXHRcdGZsb2F0IHJvdWdobmVzcyA9IG1hdGVyaWFsLnJvdWdobmVzcztcclxuXHJcblx0XHR2ZWMzIHJlY3RDb29yZHNbIDQgXTtcclxuXHRcdHJlY3RDb29yZHNbIDAgXSA9IGxpZ2h0UG9zICsgaGFsZldpZHRoIC0gaGFsZkhlaWdodDsgLy8gY291bnRlcmNsb2Nrd2lzZTsgbGlnaHQgc2hpbmVzIGluIGxvY2FsIG5lZyB6IGRpcmVjdGlvblxyXG5cdFx0cmVjdENvb3Jkc1sgMSBdID0gbGlnaHRQb3MgLSBoYWxmV2lkdGggLSBoYWxmSGVpZ2h0O1xyXG5cdFx0cmVjdENvb3Jkc1sgMiBdID0gbGlnaHRQb3MgLSBoYWxmV2lkdGggKyBoYWxmSGVpZ2h0O1xyXG5cdFx0cmVjdENvb3Jkc1sgMyBdID0gbGlnaHRQb3MgKyBoYWxmV2lkdGggKyBoYWxmSGVpZ2h0O1xyXG5cclxuXHRcdHZlYzIgdXYgPSBMVENfVXYoIG5vcm1hbCwgdmlld0Rpciwgcm91Z2huZXNzICk7XHJcblxyXG5cdFx0dmVjNCB0MSA9IHRleHR1cmUyRCggbHRjXzEsIHV2ICk7XHJcblx0XHR2ZWM0IHQyID0gdGV4dHVyZTJEKCBsdGNfMiwgdXYgKTtcclxuXHJcblx0XHRtYXQzIG1JbnYgPSBtYXQzKFxyXG5cdFx0XHR2ZWMzKCB0MS54LCAwLCB0MS55ICksXHJcblx0XHRcdHZlYzMoICAgIDAsIDEsICAgIDAgKSxcclxuXHRcdFx0dmVjMyggdDEueiwgMCwgdDEudyApXHJcblx0XHQpO1xyXG5cclxuXHRcdC8vIExUQyBGcmVzbmVsIEFwcHJveGltYXRpb24gYnkgU3RlcGhlbiBIaWxsXHJcblx0XHQvLyBodHRwOi8vYmxvZy5zZWxmc2hhZG93LmNvbS9wdWJsaWNhdGlvbnMvczIwMTYtYWR2YW5jZXMvczIwMTZfbHRjX2ZyZXNuZWwucGRmXHJcblx0XHR2ZWMzIGZyZXNuZWwgPSAoIG1hdGVyaWFsLnNwZWN1bGFyQ29sb3IgKiB0Mi54ICsgKCB2ZWMzKCAxLjAgKSAtIG1hdGVyaWFsLnNwZWN1bGFyQ29sb3IgKSAqIHQyLnkgKTtcclxuXHJcblx0XHRyZWZsZWN0ZWRMaWdodC5kaXJlY3RTcGVjdWxhciArPSBsaWdodENvbG9yICogZnJlc25lbCAqIExUQ19FdmFsdWF0ZSggbm9ybWFsLCB2aWV3RGlyLCBwb3NpdGlvbiwgbUludiwgcmVjdENvb3JkcyApO1xyXG5cclxuXHRcdHJlZmxlY3RlZExpZ2h0LmRpcmVjdERpZmZ1c2UgKz0gbGlnaHRDb2xvciAqIG1hdGVyaWFsLmRpZmZ1c2VDb2xvciAqIExUQ19FdmFsdWF0ZSggbm9ybWFsLCB2aWV3RGlyLCBwb3NpdGlvbiwgbWF0MyggMS4wICksIHJlY3RDb29yZHMgKTtcclxuXHJcblx0fVxyXG5cclxuI2VuZGlmXHJcblxyXG52b2lkIFJFX0RpcmVjdF9QaHlzaWNhbCggY29uc3QgaW4gSW5jaWRlbnRMaWdodCBkaXJlY3RMaWdodCwgY29uc3QgaW4gdmVjMyBnZW9tZXRyeVBvc2l0aW9uLCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5Tm9ybWFsLCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5Vmlld0RpciwgY29uc3QgaW4gdmVjMyBnZW9tZXRyeUNsZWFyY29hdE5vcm1hbCwgY29uc3QgaW4gUGh5c2ljYWxNYXRlcmlhbCBtYXRlcmlhbCwgaW5vdXQgUmVmbGVjdGVkTGlnaHQgcmVmbGVjdGVkTGlnaHQgKSB7XHJcblxyXG5cdGZsb2F0IGRvdE5MID0gc2F0dXJhdGUoIGRvdCggZ2VvbWV0cnlOb3JtYWwsIGRpcmVjdExpZ2h0LmRpcmVjdGlvbiApICk7XHJcblxyXG5cdHZlYzMgaXJyYWRpYW5jZSA9IGRvdE5MICogZGlyZWN0TGlnaHQuY29sb3I7XHJcblxyXG5cdCNpZmRlZiBVU0VfQ0xFQVJDT0FUXHJcblxyXG5cdFx0ZmxvYXQgZG90TkxjYyA9IHNhdHVyYXRlKCBkb3QoIGdlb21ldHJ5Q2xlYXJjb2F0Tm9ybWFsLCBkaXJlY3RMaWdodC5kaXJlY3Rpb24gKSApO1xyXG5cclxuXHRcdHZlYzMgY2NJcnJhZGlhbmNlID0gZG90TkxjYyAqIGRpcmVjdExpZ2h0LmNvbG9yO1xyXG5cclxuXHRcdGNsZWFyY29hdFNwZWN1bGFyRGlyZWN0ICs9IGNjSXJyYWRpYW5jZSAqIEJSREZfR0dYX0NsZWFyY29hdCggZGlyZWN0TGlnaHQuZGlyZWN0aW9uLCBnZW9tZXRyeVZpZXdEaXIsIGdlb21ldHJ5Q2xlYXJjb2F0Tm9ybWFsLCBtYXRlcmlhbCApO1xyXG5cclxuXHQjZW5kaWZcclxuXHJcblx0I2lmZGVmIFVTRV9TSEVFTlxyXG5cclxuXHRcdHNoZWVuU3BlY3VsYXJEaXJlY3QgKz0gaXJyYWRpYW5jZSAqIEJSREZfU2hlZW4oIGRpcmVjdExpZ2h0LmRpcmVjdGlvbiwgZ2VvbWV0cnlWaWV3RGlyLCBnZW9tZXRyeU5vcm1hbCwgbWF0ZXJpYWwuc2hlZW5Db2xvciwgbWF0ZXJpYWwuc2hlZW5Sb3VnaG5lc3MgKTtcclxuXHJcblx0I2VuZGlmXHJcblxyXG5cdHJlZmxlY3RlZExpZ2h0LmRpcmVjdFNwZWN1bGFyICs9IGlycmFkaWFuY2UgKiBCUkRGX0dHWCggZGlyZWN0TGlnaHQuZGlyZWN0aW9uLCBnZW9tZXRyeVZpZXdEaXIsIGdlb21ldHJ5Tm9ybWFsLCBtYXRlcmlhbCApO1xyXG5cclxuXHRyZWZsZWN0ZWRMaWdodC5kaXJlY3REaWZmdXNlICs9IGlycmFkaWFuY2UgKiBCUkRGX0xhbWJlcnQoIG1hdGVyaWFsLmRpZmZ1c2VDb2xvciApO1xyXG59XHJcblxyXG52b2lkIFJFX0luZGlyZWN0RGlmZnVzZV9QaHlzaWNhbCggY29uc3QgaW4gdmVjMyBpcnJhZGlhbmNlLCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5UG9zaXRpb24sIGNvbnN0IGluIHZlYzMgZ2VvbWV0cnlOb3JtYWwsIGNvbnN0IGluIHZlYzMgZ2VvbWV0cnlWaWV3RGlyLCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5Q2xlYXJjb2F0Tm9ybWFsLCBjb25zdCBpbiBQaHlzaWNhbE1hdGVyaWFsIG1hdGVyaWFsLCBpbm91dCBSZWZsZWN0ZWRMaWdodCByZWZsZWN0ZWRMaWdodCApIHtcclxuXHJcblx0cmVmbGVjdGVkTGlnaHQuaW5kaXJlY3REaWZmdXNlICs9IGlycmFkaWFuY2UgKiBCUkRGX0xhbWJlcnQoIG1hdGVyaWFsLmRpZmZ1c2VDb2xvciApO1xyXG5cclxufVxyXG5cclxudm9pZCBSRV9JbmRpcmVjdFNwZWN1bGFyX1BoeXNpY2FsKCBjb25zdCBpbiB2ZWMzIHJhZGlhbmNlLCBjb25zdCBpbiB2ZWMzIGlycmFkaWFuY2UsIGNvbnN0IGluIHZlYzMgY2xlYXJjb2F0UmFkaWFuY2UsIGNvbnN0IGluIHZlYzMgZ2VvbWV0cnlQb3NpdGlvbiwgY29uc3QgaW4gdmVjMyBnZW9tZXRyeU5vcm1hbCwgY29uc3QgaW4gdmVjMyBnZW9tZXRyeVZpZXdEaXIsIGNvbnN0IGluIHZlYzMgZ2VvbWV0cnlDbGVhcmNvYXROb3JtYWwsIGNvbnN0IGluIFBoeXNpY2FsTWF0ZXJpYWwgbWF0ZXJpYWwsIGlub3V0IFJlZmxlY3RlZExpZ2h0IHJlZmxlY3RlZExpZ2h0KSB7XHJcblxyXG5cdCNpZmRlZiBVU0VfQ0xFQVJDT0FUXHJcblxyXG5cdFx0Y2xlYXJjb2F0U3BlY3VsYXJJbmRpcmVjdCArPSBjbGVhcmNvYXRSYWRpYW5jZSAqIEVudmlyb25tZW50QlJERiggZ2VvbWV0cnlDbGVhcmNvYXROb3JtYWwsIGdlb21ldHJ5Vmlld0RpciwgbWF0ZXJpYWwuY2xlYXJjb2F0RjAsIG1hdGVyaWFsLmNsZWFyY29hdEY5MCwgbWF0ZXJpYWwuY2xlYXJjb2F0Um91Z2huZXNzICk7XHJcblxyXG5cdCNlbmRpZlxyXG5cclxuXHQjaWZkZWYgVVNFX1NIRUVOXHJcblxyXG5cdFx0c2hlZW5TcGVjdWxhckluZGlyZWN0ICs9IGlycmFkaWFuY2UgKiBtYXRlcmlhbC5zaGVlbkNvbG9yICogSUJMU2hlZW5CUkRGKCBnZW9tZXRyeU5vcm1hbCwgZ2VvbWV0cnlWaWV3RGlyLCBtYXRlcmlhbC5zaGVlblJvdWdobmVzcyApO1xyXG5cclxuXHQjZW5kaWZcclxuXHJcblx0Ly8gQm90aCBpbmRpcmVjdCBzcGVjdWxhciBhbmQgaW5kaXJlY3QgZGlmZnVzZSBsaWdodCBhY2N1bXVsYXRlIGhlcmVcclxuXHJcblx0dmVjMyBzaW5nbGVTY2F0dGVyaW5nID0gdmVjMyggMC4wICk7XHJcblx0dmVjMyBtdWx0aVNjYXR0ZXJpbmcgPSB2ZWMzKCAwLjAgKTtcclxuXHR2ZWMzIGNvc2luZVdlaWdodGVkSXJyYWRpYW5jZSA9IGlycmFkaWFuY2UgKiBSRUNJUFJPQ0FMX1BJO1xyXG5cclxuXHQjaWZkZWYgVVNFX0lSSURFU0NFTkNFXHJcblxyXG5cdFx0Y29tcHV0ZU11bHRpc2NhdHRlcmluZ0lyaWRlc2NlbmNlKCBnZW9tZXRyeU5vcm1hbCwgZ2VvbWV0cnlWaWV3RGlyLCBtYXRlcmlhbC5zcGVjdWxhckNvbG9yLCBtYXRlcmlhbC5zcGVjdWxhckY5MCwgbWF0ZXJpYWwuaXJpZGVzY2VuY2UsIG1hdGVyaWFsLmlyaWRlc2NlbmNlRnJlc25lbCwgbWF0ZXJpYWwucm91Z2huZXNzLCBzaW5nbGVTY2F0dGVyaW5nLCBtdWx0aVNjYXR0ZXJpbmcgKTtcclxuXHJcblx0I2Vsc2VcclxuXHJcblx0XHRjb21wdXRlTXVsdGlzY2F0dGVyaW5nKCBnZW9tZXRyeU5vcm1hbCwgZ2VvbWV0cnlWaWV3RGlyLCBtYXRlcmlhbC5zcGVjdWxhckNvbG9yLCBtYXRlcmlhbC5zcGVjdWxhckY5MCwgbWF0ZXJpYWwucm91Z2huZXNzLCBzaW5nbGVTY2F0dGVyaW5nLCBtdWx0aVNjYXR0ZXJpbmcgKTtcclxuXHJcblx0I2VuZGlmXHJcblxyXG5cdHZlYzMgdG90YWxTY2F0dGVyaW5nID0gc2luZ2xlU2NhdHRlcmluZyArIG11bHRpU2NhdHRlcmluZztcclxuXHR2ZWMzIGRpZmZ1c2UgPSBtYXRlcmlhbC5kaWZmdXNlQ29sb3IgKiAoIDEuMCAtIG1heCggbWF4KCB0b3RhbFNjYXR0ZXJpbmcuciwgdG90YWxTY2F0dGVyaW5nLmcgKSwgdG90YWxTY2F0dGVyaW5nLmIgKSApO1xyXG5cclxuXHRyZWZsZWN0ZWRMaWdodC5pbmRpcmVjdFNwZWN1bGFyICs9IHJhZGlhbmNlICogc2luZ2xlU2NhdHRlcmluZztcclxuXHRyZWZsZWN0ZWRMaWdodC5pbmRpcmVjdFNwZWN1bGFyICs9IG11bHRpU2NhdHRlcmluZyAqIGNvc2luZVdlaWdodGVkSXJyYWRpYW5jZTtcclxuXHJcblx0cmVmbGVjdGVkTGlnaHQuaW5kaXJlY3REaWZmdXNlICs9IGRpZmZ1c2UgKiBjb3NpbmVXZWlnaHRlZElycmFkaWFuY2U7XHJcblxyXG59XHJcblxyXG4jZGVmaW5lIFJFX0RpcmVjdFx0XHRcdFx0UkVfRGlyZWN0X1BoeXNpY2FsXHJcbiNkZWZpbmUgUkVfRGlyZWN0X1JlY3RBcmVhXHRcdFJFX0RpcmVjdF9SZWN0QXJlYV9QaHlzaWNhbFxyXG4jZGVmaW5lIFJFX0luZGlyZWN0RGlmZnVzZVx0XHRSRV9JbmRpcmVjdERpZmZ1c2VfUGh5c2ljYWxcclxuI2RlZmluZSBSRV9JbmRpcmVjdFNwZWN1bGFyXHRcdFJFX0luZGlyZWN0U3BlY3VsYXJfUGh5c2ljYWxcclxuXHJcbi8vIHJlZjogaHR0cHM6Ly9zZWJsYWdhcmRlLmZpbGVzLndvcmRwcmVzcy5jb20vMjAxNS8wNy9jb3Vyc2Vfbm90ZXNfbW92aW5nX2Zyb3N0Yml0ZV90b19wYnJfdjMyLnBkZlxyXG5mbG9hdCBjb21wdXRlU3BlY3VsYXJPY2NsdXNpb24oIGNvbnN0IGluIGZsb2F0IGRvdE5WLCBjb25zdCBpbiBmbG9hdCBhbWJpZW50T2NjbHVzaW9uLCBjb25zdCBpbiBmbG9hdCByb3VnaG5lc3MgKSB7XHJcblxyXG5cdHJldHVybiBzYXR1cmF0ZSggcG93KCBkb3ROViArIGFtYmllbnRPY2NsdXNpb24sIGV4cDIoIC0gMTYuMCAqIHJvdWdobmVzcyAtIDEuMCApICkgLSAxLjAgKyBhbWJpZW50T2NjbHVzaW9uICk7XHJcblxyXG59XHJcbmA7XHJcbiIsImV4cG9ydCBkZWZhdWx0IC8qIGdsc2wgKi9gXHJcbi8qKlxyXG4gKiBUaGlzIGlzIGEgdGVtcGxhdGUgdGhhdCBjYW4gYmUgdXNlZCB0byBsaWdodCBhIG1hdGVyaWFsLCBpdCB1c2VzIHBsdWdnYWJsZVxyXG4gKiBSZW5kZXJFcXVhdGlvbnMgKFJFKWZvciBzcGVjaWZpYyBsaWdodGluZyBzY2VuYXJpb3MuXHJcbiAqXHJcbiAqIEluc3RydWN0aW9ucyBmb3IgdXNlOlxyXG4gKiAtIEVuc3VyZSB0aGF0IGJvdGggUkVfRGlyZWN0LCBSRV9JbmRpcmVjdERpZmZ1c2UgYW5kIFJFX0luZGlyZWN0U3BlY3VsYXIgYXJlIGRlZmluZWRcclxuICogLSBDcmVhdGUgYSBtYXRlcmlhbCBwYXJhbWV0ZXIgdGhhdCBpcyB0byBiZSBwYXNzZWQgYXMgdGhlIHRoaXJkIHBhcmFtZXRlciB0byB5b3VyIGxpZ2h0aW5nIGZ1bmN0aW9ucy5cclxuICpcclxuICogVE9ETzpcclxuICogLSBBZGQgYXJlYSBsaWdodCBzdXBwb3J0LlxyXG4gKiAtIEFkZCBzcGhlcmUgbGlnaHQgc3VwcG9ydC5cclxuICogLSBBZGQgZGlmZnVzZSBsaWdodCBwcm9iZSAoaXJyYWRpYW5jZSBjdWJlbWFwKSBzdXBwb3J0LlxyXG4gKi9cclxuXHJcbnZlYzMgZ2VvbWV0cnlQb3NpdGlvbiA9IC0gdlZpZXdQb3NpdGlvbjtcclxudmVjMyBnZW9tZXRyeU5vcm1hbCA9IG5vcm1hbDtcclxudmVjMyBnZW9tZXRyeVZpZXdEaXIgPSAoIGlzT3J0aG9ncmFwaGljICkgPyB2ZWMzKCAwLCAwLCAxICkgOiBub3JtYWxpemUoIHZWaWV3UG9zaXRpb24gKTtcclxuXHJcbnZlYzMgZ2VvbWV0cnlDbGVhcmNvYXROb3JtYWwgPSB2ZWMzKCAwLjAgKTtcclxuXHJcbiNpZmRlZiBVU0VfQ0xFQVJDT0FUXHJcblxyXG5cdGdlb21ldHJ5Q2xlYXJjb2F0Tm9ybWFsID0gY2xlYXJjb2F0Tm9ybWFsO1xyXG5cclxuI2VuZGlmXHJcblxyXG4jaWZkZWYgVVNFX0lSSURFU0NFTkNFXHJcblxyXG5cdGZsb2F0IGRvdE5WaSA9IHNhdHVyYXRlKCBkb3QoIG5vcm1hbCwgZ2VvbWV0cnlWaWV3RGlyICkgKTtcclxuXHJcblx0aWYgKCBtYXRlcmlhbC5pcmlkZXNjZW5jZVRoaWNrbmVzcyA9PSAwLjAgKSB7XHJcblxyXG5cdFx0bWF0ZXJpYWwuaXJpZGVzY2VuY2UgPSAwLjA7XHJcblxyXG5cdH0gZWxzZSB7XHJcblxyXG5cdFx0bWF0ZXJpYWwuaXJpZGVzY2VuY2UgPSBzYXR1cmF0ZSggbWF0ZXJpYWwuaXJpZGVzY2VuY2UgKTtcclxuXHJcblx0fVxyXG5cclxuXHRpZiAoIG1hdGVyaWFsLmlyaWRlc2NlbmNlID4gMC4wICkge1xyXG5cclxuXHRcdG1hdGVyaWFsLmlyaWRlc2NlbmNlRnJlc25lbCA9IGV2YWxJcmlkZXNjZW5jZSggMS4wLCBtYXRlcmlhbC5pcmlkZXNjZW5jZUlPUiwgZG90TlZpLCBtYXRlcmlhbC5pcmlkZXNjZW5jZVRoaWNrbmVzcywgbWF0ZXJpYWwuc3BlY3VsYXJDb2xvciApO1xyXG5cclxuXHRcdC8vIElyaWRlc2NlbmNlIEYwIGFwcHJveGltYXRpb25cclxuXHRcdG1hdGVyaWFsLmlyaWRlc2NlbmNlRjAgPSBTY2hsaWNrX3RvX0YwKCBtYXRlcmlhbC5pcmlkZXNjZW5jZUZyZXNuZWwsIDEuMCwgZG90TlZpICk7XHJcblxyXG5cdH1cclxuXHJcbiNlbmRpZlxyXG5cclxuSW5jaWRlbnRMaWdodCBkaXJlY3RMaWdodDtcclxuXHJcbiNpZiAoIE5VTV9QT0lOVF9MSUdIVFMgPiAwICkgJiYgZGVmaW5lZCggUkVfRGlyZWN0IClcclxuXHJcblx0UG9pbnRMaWdodCBwb2ludExpZ2h0O1xyXG5cdCNpZiBkZWZpbmVkKCBVU0VfU0hBRE9XTUFQICkgJiYgTlVNX1BPSU5UX0xJR0hUX1NIQURPV1MgPiAwXHJcblx0UG9pbnRMaWdodFNoYWRvdyBwb2ludExpZ2h0U2hhZG93O1xyXG5cdCNlbmRpZlxyXG5cclxuXHQjcHJhZ21hIHVucm9sbF9sb29wX3N0YXJ0XHJcblx0Zm9yICggaW50IGkgPSAwOyBpIDwgTlVNX1BPSU5UX0xJR0hUUzsgaSArKyApIHtcclxuXHJcblx0XHRwb2ludExpZ2h0ID0gcG9pbnRMaWdodHNbIGkgXTtcclxuXHJcblx0XHRnZXRQb2ludExpZ2h0SW5mbyggcG9pbnRMaWdodCwgZ2VvbWV0cnlQb3NpdGlvbiwgZGlyZWN0TGlnaHQgKTtcclxuXHJcblx0XHQjaWYgZGVmaW5lZCggVVNFX1NIQURPV01BUCApICYmICggVU5ST0xMRURfTE9PUF9JTkRFWCA8IE5VTV9QT0lOVF9MSUdIVF9TSEFET1dTIClcclxuXHRcdHBvaW50TGlnaHRTaGFkb3cgPSBwb2ludExpZ2h0U2hhZG93c1sgaSBdO1xyXG5cdFx0ZGlyZWN0TGlnaHQuY29sb3IgKj0gKCBkaXJlY3RMaWdodC52aXNpYmxlICYmIHJlY2VpdmVTaGFkb3cgKSA/IGdldFBvaW50U2hhZG93KCBwb2ludFNoYWRvd01hcFsgaSBdLCBwb2ludExpZ2h0U2hhZG93LnNoYWRvd01hcFNpemUsIHBvaW50TGlnaHRTaGFkb3cuc2hhZG93QmlhcywgcG9pbnRMaWdodFNoYWRvdy5zaGFkb3dSYWRpdXMsIHZQb2ludFNoYWRvd0Nvb3JkWyBpIF0sIHBvaW50TGlnaHRTaGFkb3cuc2hhZG93Q2FtZXJhTmVhciwgcG9pbnRMaWdodFNoYWRvdy5zaGFkb3dDYW1lcmFGYXIgKSA6IDEuMDtcclxuXHRcdCNlbmRpZlxyXG5cclxuXHRcdFJFX0RpcmVjdCggZGlyZWN0TGlnaHQsIGdlb21ldHJ5UG9zaXRpb24sIGdlb21ldHJ5Tm9ybWFsLCBnZW9tZXRyeVZpZXdEaXIsIGdlb21ldHJ5Q2xlYXJjb2F0Tm9ybWFsLCBtYXRlcmlhbCwgcmVmbGVjdGVkTGlnaHQgKTtcclxuXHJcblx0fVxyXG5cdCNwcmFnbWEgdW5yb2xsX2xvb3BfZW5kXHJcblxyXG4jZW5kaWZcclxuXHJcbiNpZiAoIE5VTV9TUE9UX0xJR0hUUyA+IDAgKSAmJiBkZWZpbmVkKCBSRV9EaXJlY3QgKVxyXG5cclxuXHRTcG90TGlnaHQgc3BvdExpZ2h0O1xyXG5cdHZlYzQgc3BvdENvbG9yO1xyXG5cdHZlYzMgc3BvdExpZ2h0Q29vcmQ7XHJcblx0Ym9vbCBpblNwb3RMaWdodE1hcDtcclxuXHJcblx0I2lmIGRlZmluZWQoIFVTRV9TSEFET1dNQVAgKSAmJiBOVU1fU1BPVF9MSUdIVF9TSEFET1dTID4gMFxyXG5cdFNwb3RMaWdodFNoYWRvdyBzcG90TGlnaHRTaGFkb3c7XHJcblx0I2VuZGlmXHJcblxyXG5cdCNwcmFnbWEgdW5yb2xsX2xvb3Bfc3RhcnRcclxuXHRmb3IgKCBpbnQgaSA9IDA7IGkgPCBOVU1fU1BPVF9MSUdIVFM7IGkgKysgKSB7XHJcblxyXG5cdFx0c3BvdExpZ2h0ID0gc3BvdExpZ2h0c1sgaSBdO1xyXG5cclxuXHRcdGdldFNwb3RMaWdodEluZm8oIHNwb3RMaWdodCwgZ2VvbWV0cnlQb3NpdGlvbiwgZGlyZWN0TGlnaHQgKTtcclxuXHJcblx0XHQvLyBzcG90IGxpZ2h0cyBhcmUgb3JkZXJlZCBbc2hhZG93cyB3aXRoIG1hcHMsIHNoYWRvd3Mgd2l0aG91dCBtYXBzLCBtYXBzIHdpdGhvdXQgc2hhZG93cywgbm9uZV1cclxuXHRcdCNpZiAoIFVOUk9MTEVEX0xPT1BfSU5ERVggPCBOVU1fU1BPVF9MSUdIVF9TSEFET1dTX1dJVEhfTUFQUyApXHJcblx0XHQjZGVmaW5lIFNQT1RfTElHSFRfTUFQX0lOREVYIFVOUk9MTEVEX0xPT1BfSU5ERVhcclxuXHRcdCNlbGlmICggVU5ST0xMRURfTE9PUF9JTkRFWCA8IE5VTV9TUE9UX0xJR0hUX1NIQURPV1MgKVxyXG5cdFx0I2RlZmluZSBTUE9UX0xJR0hUX01BUF9JTkRFWCBOVU1fU1BPVF9MSUdIVF9NQVBTXHJcblx0XHQjZWxzZVxyXG5cdFx0I2RlZmluZSBTUE9UX0xJR0hUX01BUF9JTkRFWCAoIFVOUk9MTEVEX0xPT1BfSU5ERVggLSBOVU1fU1BPVF9MSUdIVF9TSEFET1dTICsgTlVNX1NQT1RfTElHSFRfU0hBRE9XU19XSVRIX01BUFMgKVxyXG5cdFx0I2VuZGlmXHJcblxyXG5cdFx0I2lmICggU1BPVF9MSUdIVF9NQVBfSU5ERVggPCBOVU1fU1BPVF9MSUdIVF9NQVBTIClcclxuXHRcdFx0c3BvdExpZ2h0Q29vcmQgPSB2U3BvdExpZ2h0Q29vcmRbIGkgXS54eXogLyB2U3BvdExpZ2h0Q29vcmRbIGkgXS53O1xyXG5cdFx0XHRpblNwb3RMaWdodE1hcCA9IGFsbCggbGVzc1RoYW4oIGFicyggc3BvdExpZ2h0Q29vcmQgKiAyLiAtIDEuICksIHZlYzMoIDEuMCApICkgKTtcclxuXHRcdFx0c3BvdENvbG9yID0gdGV4dHVyZTJEKCBzcG90TGlnaHRNYXBbIFNQT1RfTElHSFRfTUFQX0lOREVYIF0sIHNwb3RMaWdodENvb3JkLnh5ICk7XHJcblx0XHRcdGRpcmVjdExpZ2h0LmNvbG9yID0gaW5TcG90TGlnaHRNYXAgPyBkaXJlY3RMaWdodC5jb2xvciAqIHNwb3RDb2xvci5yZ2IgOiBkaXJlY3RMaWdodC5jb2xvcjtcclxuXHRcdCNlbmRpZlxyXG5cclxuXHRcdCN1bmRlZiBTUE9UX0xJR0hUX01BUF9JTkRFWFxyXG5cclxuXHRcdCNpZiBkZWZpbmVkKCBVU0VfU0hBRE9XTUFQICkgJiYgKCBVTlJPTExFRF9MT09QX0lOREVYIDwgTlVNX1NQT1RfTElHSFRfU0hBRE9XUyApXHJcblx0XHRzcG90TGlnaHRTaGFkb3cgPSBzcG90TGlnaHRTaGFkb3dzWyBpIF07XHJcblx0XHRkaXJlY3RMaWdodC5jb2xvciAqPSAoIGRpcmVjdExpZ2h0LnZpc2libGUgJiYgcmVjZWl2ZVNoYWRvdyApID8gZ2V0U2hhZG93KCBzcG90U2hhZG93TWFwWyBpIF0sIHNwb3RMaWdodFNoYWRvdy5zaGFkb3dNYXBTaXplLCBzcG90TGlnaHRTaGFkb3cuc2hhZG93Qmlhcywgc3BvdExpZ2h0U2hhZG93LnNoYWRvd1JhZGl1cywgdlNwb3RMaWdodENvb3JkWyBpIF0gKSA6IDEuMDtcclxuXHRcdCNlbmRpZlxyXG5cclxuXHRcdFJFX0RpcmVjdCggZGlyZWN0TGlnaHQsIGdlb21ldHJ5UG9zaXRpb24sIGdlb21ldHJ5Tm9ybWFsLCBnZW9tZXRyeVZpZXdEaXIsIGdlb21ldHJ5Q2xlYXJjb2F0Tm9ybWFsLCBtYXRlcmlhbCwgcmVmbGVjdGVkTGlnaHQgKTtcclxuXHJcblx0fVxyXG5cdCNwcmFnbWEgdW5yb2xsX2xvb3BfZW5kXHJcblxyXG4jZW5kaWZcclxuXHJcbiNpZiAoIE5VTV9ESVJfTElHSFRTID4gMCApICYmIGRlZmluZWQoIFJFX0RpcmVjdCApXHJcblxyXG5cdERpcmVjdGlvbmFsTGlnaHQgZGlyZWN0aW9uYWxMaWdodDtcclxuXHQjaWYgZGVmaW5lZCggVVNFX1NIQURPV01BUCApICYmIE5VTV9ESVJfTElHSFRfU0hBRE9XUyA+IDBcclxuXHREaXJlY3Rpb25hbExpZ2h0U2hhZG93IGRpcmVjdGlvbmFsTGlnaHRTaGFkb3c7XHJcblx0I2VuZGlmXHJcblxyXG5cdCNwcmFnbWEgdW5yb2xsX2xvb3Bfc3RhcnRcclxuXHRmb3IgKCBpbnQgaSA9IDA7IGkgPCBOVU1fRElSX0xJR0hUUzsgaSArKyApIHtcclxuXHJcblx0XHRkaXJlY3Rpb25hbExpZ2h0ID0gZGlyZWN0aW9uYWxMaWdodHNbIGkgXTtcclxuXHJcblx0XHRnZXREaXJlY3Rpb25hbExpZ2h0SW5mbyggZGlyZWN0aW9uYWxMaWdodCwgZGlyZWN0TGlnaHQgKTtcclxuXHJcblx0XHQjaWYgZGVmaW5lZCggVVNFX1NIQURPV01BUCApICYmICggVU5ST0xMRURfTE9PUF9JTkRFWCA8IE5VTV9ESVJfTElHSFRfU0hBRE9XUyApXHJcblx0XHRkaXJlY3Rpb25hbExpZ2h0U2hhZG93ID0gZGlyZWN0aW9uYWxMaWdodFNoYWRvd3NbIGkgXTtcclxuXHRcdGRpcmVjdExpZ2h0LmNvbG9yICo9ICggZGlyZWN0TGlnaHQudmlzaWJsZSAmJiByZWNlaXZlU2hhZG93ICkgPyBnZXRTaGFkb3coIGRpcmVjdGlvbmFsU2hhZG93TWFwWyBpIF0sIGRpcmVjdGlvbmFsTGlnaHRTaGFkb3cuc2hhZG93TWFwU2l6ZSwgZGlyZWN0aW9uYWxMaWdodFNoYWRvdy5zaGFkb3dCaWFzLCBkaXJlY3Rpb25hbExpZ2h0U2hhZG93LnNoYWRvd1JhZGl1cywgdkRpcmVjdGlvbmFsU2hhZG93Q29vcmRbIGkgXSApIDogMS4wO1xyXG5cdFx0I2VuZGlmXHJcblxyXG5cdFx0UkVfRGlyZWN0KCBkaXJlY3RMaWdodCwgZ2VvbWV0cnlQb3NpdGlvbiwgZ2VvbWV0cnlOb3JtYWwsIGdlb21ldHJ5Vmlld0RpciwgZ2VvbWV0cnlDbGVhcmNvYXROb3JtYWwsIG1hdGVyaWFsLCByZWZsZWN0ZWRMaWdodCApO1xyXG5cclxuXHR9XHJcblx0I3ByYWdtYSB1bnJvbGxfbG9vcF9lbmRcclxuXHJcbiNlbmRpZlxyXG5cclxuI2lmICggTlVNX1JFQ1RfQVJFQV9MSUdIVFMgPiAwICkgJiYgZGVmaW5lZCggUkVfRGlyZWN0X1JlY3RBcmVhIClcclxuXHJcblx0UmVjdEFyZWFMaWdodCByZWN0QXJlYUxpZ2h0O1xyXG5cclxuXHQjcHJhZ21hIHVucm9sbF9sb29wX3N0YXJ0XHJcblx0Zm9yICggaW50IGkgPSAwOyBpIDwgTlVNX1JFQ1RfQVJFQV9MSUdIVFM7IGkgKysgKSB7XHJcblxyXG5cdFx0cmVjdEFyZWFMaWdodCA9IHJlY3RBcmVhTGlnaHRzWyBpIF07XHJcblx0XHRSRV9EaXJlY3RfUmVjdEFyZWEoIHJlY3RBcmVhTGlnaHQsIGdlb21ldHJ5UG9zaXRpb24sIGdlb21ldHJ5Tm9ybWFsLCBnZW9tZXRyeVZpZXdEaXIsIGdlb21ldHJ5Q2xlYXJjb2F0Tm9ybWFsLCBtYXRlcmlhbCwgcmVmbGVjdGVkTGlnaHQgKTtcclxuXHJcblx0fVxyXG5cdCNwcmFnbWEgdW5yb2xsX2xvb3BfZW5kXHJcblxyXG4jZW5kaWZcclxuXHJcbiNpZiBkZWZpbmVkKCBSRV9JbmRpcmVjdERpZmZ1c2UgKVxyXG5cclxuXHR2ZWMzIGlibElycmFkaWFuY2UgPSB2ZWMzKCAwLjAgKTtcclxuXHJcblx0dmVjMyBpcnJhZGlhbmNlID0gZ2V0QW1iaWVudExpZ2h0SXJyYWRpYW5jZSggYW1iaWVudExpZ2h0Q29sb3IgKTtcclxuXHJcblx0I2lmIGRlZmluZWQoIFVTRV9MSUdIVF9QUk9CRVMgKVxyXG5cclxuXHRcdGlycmFkaWFuY2UgKz0gZ2V0TGlnaHRQcm9iZUlycmFkaWFuY2UoIGxpZ2h0UHJvYmUsIGdlb21ldHJ5Tm9ybWFsICk7XHJcblxyXG5cdCNlbmRpZlxyXG5cclxuXHQjaWYgKCBOVU1fSEVNSV9MSUdIVFMgPiAwIClcclxuXHJcblx0XHQjcHJhZ21hIHVucm9sbF9sb29wX3N0YXJ0XHJcblx0XHRmb3IgKCBpbnQgaSA9IDA7IGkgPCBOVU1fSEVNSV9MSUdIVFM7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRpcnJhZGlhbmNlICs9IGdldEhlbWlzcGhlcmVMaWdodElycmFkaWFuY2UoIGhlbWlzcGhlcmVMaWdodHNbIGkgXSwgZ2VvbWV0cnlOb3JtYWwgKTtcclxuXHJcblx0XHR9XHJcblx0XHQjcHJhZ21hIHVucm9sbF9sb29wX2VuZFxyXG5cclxuXHQjZW5kaWZcclxuXHJcbiNlbmRpZlxyXG5cclxuI2lmIGRlZmluZWQoIFJFX0luZGlyZWN0U3BlY3VsYXIgKVxyXG5cclxuXHR2ZWMzIHJhZGlhbmNlID0gdmVjMyggMC4wICk7XHJcblx0dmVjMyBjbGVhcmNvYXRSYWRpYW5jZSA9IHZlYzMoIDAuMCApO1xyXG5cclxuI2VuZGlmXHJcbmA7XHJcbiIsImV4cG9ydCBkZWZhdWx0IC8qIGdsc2wgKi9gXHJcbiNpZiBkZWZpbmVkKCBSRV9JbmRpcmVjdERpZmZ1c2UgKVxyXG5cclxuXHQjaWZkZWYgVVNFX0xJR0hUTUFQXHJcblxyXG5cdFx0dmVjNCBsaWdodE1hcFRleGVsID0gdGV4dHVyZTJEKCBsaWdodE1hcCwgdkxpZ2h0TWFwVXYgKTtcclxuXHRcdHZlYzMgbGlnaHRNYXBJcnJhZGlhbmNlID0gbGlnaHRNYXBUZXhlbC5yZ2IgKiBsaWdodE1hcEludGVuc2l0eTtcclxuXHJcblx0XHRpcnJhZGlhbmNlICs9IGxpZ2h0TWFwSXJyYWRpYW5jZTtcclxuXHJcblx0I2VuZGlmXHJcblxyXG5cdCNpZiBkZWZpbmVkKCBVU0VfRU5WTUFQICkgJiYgZGVmaW5lZCggU1RBTkRBUkQgKSAmJiBkZWZpbmVkKCBFTlZNQVBfVFlQRV9DVUJFX1VWIClcclxuXHJcblx0XHRpYmxJcnJhZGlhbmNlICs9IGdldElCTElycmFkaWFuY2UoIGdlb21ldHJ5Tm9ybWFsICk7XHJcblxyXG5cdCNlbmRpZlxyXG5cclxuI2VuZGlmXHJcblxyXG4jaWYgZGVmaW5lZCggVVNFX0VOVk1BUCApICYmIGRlZmluZWQoIFJFX0luZGlyZWN0U3BlY3VsYXIgKVxyXG5cclxuXHQjaWZkZWYgVVNFX0FOSVNPVFJPUFlcclxuXHJcblx0XHRyYWRpYW5jZSArPSBnZXRJQkxBbmlzb3Ryb3B5UmFkaWFuY2UoIGdlb21ldHJ5Vmlld0RpciwgZ2VvbWV0cnlOb3JtYWwsIG1hdGVyaWFsLnJvdWdobmVzcywgbWF0ZXJpYWwuYW5pc290cm9weUIsIG1hdGVyaWFsLmFuaXNvdHJvcHkgKTtcclxuXHJcblx0I2Vsc2VcclxuXHJcblx0XHRyYWRpYW5jZSArPSBnZXRJQkxSYWRpYW5jZSggZ2VvbWV0cnlWaWV3RGlyLCBnZW9tZXRyeU5vcm1hbCwgbWF0ZXJpYWwucm91Z2huZXNzICk7XHJcblxyXG5cdCNlbmRpZlxyXG5cclxuXHQjaWZkZWYgVVNFX0NMRUFSQ09BVFxyXG5cclxuXHRcdGNsZWFyY29hdFJhZGlhbmNlICs9IGdldElCTFJhZGlhbmNlKCBnZW9tZXRyeVZpZXdEaXIsIGdlb21ldHJ5Q2xlYXJjb2F0Tm9ybWFsLCBtYXRlcmlhbC5jbGVhcmNvYXRSb3VnaG5lc3MgKTtcclxuXHJcblx0I2VuZGlmXHJcblxyXG4jZW5kaWZcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuI2lmIGRlZmluZWQoIFJFX0luZGlyZWN0RGlmZnVzZSApXHJcblxyXG5cdFJFX0luZGlyZWN0RGlmZnVzZSggaXJyYWRpYW5jZSwgZ2VvbWV0cnlQb3NpdGlvbiwgZ2VvbWV0cnlOb3JtYWwsIGdlb21ldHJ5Vmlld0RpciwgZ2VvbWV0cnlDbGVhcmNvYXROb3JtYWwsIG1hdGVyaWFsLCByZWZsZWN0ZWRMaWdodCApO1xyXG5cclxuI2VuZGlmXHJcblxyXG4jaWYgZGVmaW5lZCggUkVfSW5kaXJlY3RTcGVjdWxhciApXHJcblxyXG5cdFJFX0luZGlyZWN0U3BlY3VsYXIoIHJhZGlhbmNlLCBpYmxJcnJhZGlhbmNlLCBjbGVhcmNvYXRSYWRpYW5jZSwgZ2VvbWV0cnlQb3NpdGlvbiwgZ2VvbWV0cnlOb3JtYWwsIGdlb21ldHJ5Vmlld0RpciwgZ2VvbWV0cnlDbGVhcmNvYXROb3JtYWwsIG1hdGVyaWFsLCByZWZsZWN0ZWRMaWdodCApO1xyXG5cclxuI2VuZGlmXHJcbmA7XHJcbiIsImV4cG9ydCBkZWZhdWx0IC8qIGdsc2wgKi9gXHJcbiNpZiBkZWZpbmVkKCBVU0VfTE9HREVQVEhCVUYgKSAmJiBkZWZpbmVkKCBVU0VfTE9HREVQVEhCVUZfRVhUIClcclxuXHJcblx0Ly8gRG9pbmcgYSBzdHJpY3QgY29tcGFyaXNvbiB3aXRoID09IDEuMCBjYW4gY2F1c2Ugbm9pc2UgYXJ0aWZhY3RzXHJcblx0Ly8gb24gc29tZSBwbGF0Zm9ybXMuIFNlZSBpc3N1ZSAjMTc2MjMuXHJcblx0Z2xfRnJhZ0RlcHRoRVhUID0gdklzUGVyc3BlY3RpdmUgPT0gMC4wID8gZ2xfRnJhZ0Nvb3JkLnogOiBsb2cyKCB2RnJhZ0RlcHRoICkgKiBsb2dEZXB0aEJ1ZkZDICogMC41O1xyXG5cclxuI2VuZGlmXHJcbmA7XHJcbiIsImV4cG9ydCBkZWZhdWx0IC8qIGdsc2wgKi9gXHJcbiNpZiBkZWZpbmVkKCBVU0VfTE9HREVQVEhCVUYgKSAmJiBkZWZpbmVkKCBVU0VfTE9HREVQVEhCVUZfRVhUIClcclxuXHJcblx0dW5pZm9ybSBmbG9hdCBsb2dEZXB0aEJ1ZkZDO1xyXG5cdHZhcnlpbmcgZmxvYXQgdkZyYWdEZXB0aDtcclxuXHR2YXJ5aW5nIGZsb2F0IHZJc1BlcnNwZWN0aXZlO1xyXG5cclxuI2VuZGlmXHJcbmA7XHJcbiIsImV4cG9ydCBkZWZhdWx0IC8qIGdsc2wgKi9gXHJcbiNpZmRlZiBVU0VfTE9HREVQVEhCVUZcclxuXHJcblx0I2lmZGVmIFVTRV9MT0dERVBUSEJVRl9FWFRcclxuXHJcblx0XHR2YXJ5aW5nIGZsb2F0IHZGcmFnRGVwdGg7XHJcblx0XHR2YXJ5aW5nIGZsb2F0IHZJc1BlcnNwZWN0aXZlO1xyXG5cclxuXHQjZWxzZVxyXG5cclxuXHRcdHVuaWZvcm0gZmxvYXQgbG9nRGVwdGhCdWZGQztcclxuXHJcblx0I2VuZGlmXHJcblxyXG4jZW5kaWZcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuI2lmZGVmIFVTRV9MT0dERVBUSEJVRlxyXG5cclxuXHQjaWZkZWYgVVNFX0xPR0RFUFRIQlVGX0VYVFxyXG5cclxuXHRcdHZGcmFnRGVwdGggPSAxLjAgKyBnbF9Qb3NpdGlvbi53O1xyXG5cdFx0dklzUGVyc3BlY3RpdmUgPSBmbG9hdCggaXNQZXJzcGVjdGl2ZU1hdHJpeCggcHJvamVjdGlvbk1hdHJpeCApICk7XHJcblxyXG5cdCNlbHNlXHJcblxyXG5cdFx0aWYgKCBpc1BlcnNwZWN0aXZlTWF0cml4KCBwcm9qZWN0aW9uTWF0cml4ICkgKSB7XHJcblxyXG5cdFx0XHRnbF9Qb3NpdGlvbi56ID0gbG9nMiggbWF4KCBFUFNJTE9OLCBnbF9Qb3NpdGlvbi53ICsgMS4wICkgKSAqIGxvZ0RlcHRoQnVmRkMgLSAxLjA7XHJcblxyXG5cdFx0XHRnbF9Qb3NpdGlvbi56ICo9IGdsX1Bvc2l0aW9uLnc7XHJcblxyXG5cdFx0fVxyXG5cclxuXHQjZW5kaWZcclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWZkZWYgVVNFX01BUFxyXG5cclxuXHR2ZWM0IHNhbXBsZWREaWZmdXNlQ29sb3IgPSB0ZXh0dXJlMkQoIG1hcCwgdk1hcFV2ICk7XHJcblxyXG5cdCNpZmRlZiBERUNPREVfVklERU9fVEVYVFVSRVxyXG5cclxuXHRcdC8vIHVzZSBpbmxpbmUgc1JHQiBkZWNvZGUgdW50aWwgYnJvd3NlcnMgcHJvcGVybHkgc3VwcG9ydCBTUkdCOF9BUExIQTggd2l0aCB2aWRlbyB0ZXh0dXJlc1xyXG5cclxuXHRcdHNhbXBsZWREaWZmdXNlQ29sb3IgPSB2ZWM0KCBtaXgoIHBvdyggc2FtcGxlZERpZmZ1c2VDb2xvci5yZ2IgKiAwLjk0Nzg2NzI5ODYgKyB2ZWMzKCAwLjA1MjEzMjcwMTQgKSwgdmVjMyggMi40ICkgKSwgc2FtcGxlZERpZmZ1c2VDb2xvci5yZ2IgKiAwLjA3NzM5OTM4MDgsIHZlYzMoIGxlc3NUaGFuRXF1YWwoIHNhbXBsZWREaWZmdXNlQ29sb3IucmdiLCB2ZWMzKCAwLjA0MDQ1ICkgKSApICksIHNhbXBsZWREaWZmdXNlQ29sb3IudyApO1xyXG5cdFxyXG5cdCNlbmRpZlxyXG5cclxuXHRkaWZmdXNlQ29sb3IgKj0gc2FtcGxlZERpZmZ1c2VDb2xvcjtcclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWZkZWYgVVNFX01BUFxyXG5cclxuXHR1bmlmb3JtIHNhbXBsZXIyRCBtYXA7XHJcblxyXG4jZW5kaWZcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuI2lmIGRlZmluZWQoIFVTRV9NQVAgKSB8fCBkZWZpbmVkKCBVU0VfQUxQSEFNQVAgKVxyXG5cclxuXHQjaWYgZGVmaW5lZCggVVNFX1BPSU5UU19VViApXHJcblxyXG5cdFx0dmVjMiB1diA9IHZVdjtcclxuXHJcblx0I2Vsc2VcclxuXHJcblx0XHR2ZWMyIHV2ID0gKCB1dlRyYW5zZm9ybSAqIHZlYzMoIGdsX1BvaW50Q29vcmQueCwgMS4wIC0gZ2xfUG9pbnRDb29yZC55LCAxICkgKS54eTtcclxuXHJcblx0I2VuZGlmXHJcblxyXG4jZW5kaWZcclxuXHJcbiNpZmRlZiBVU0VfTUFQXHJcblxyXG5cdGRpZmZ1c2VDb2xvciAqPSB0ZXh0dXJlMkQoIG1hcCwgdXYgKTtcclxuXHJcbiNlbmRpZlxyXG5cclxuI2lmZGVmIFVTRV9BTFBIQU1BUFxyXG5cclxuXHRkaWZmdXNlQ29sb3IuYSAqPSB0ZXh0dXJlMkQoIGFscGhhTWFwLCB1diApLmc7XHJcblxyXG4jZW5kaWZcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuI2lmIGRlZmluZWQoIFVTRV9QT0lOVFNfVVYgKVxyXG5cclxuXHR2YXJ5aW5nIHZlYzIgdlV2O1xyXG5cclxuI2Vsc2VcclxuXHJcblx0I2lmIGRlZmluZWQoIFVTRV9NQVAgKSB8fCBkZWZpbmVkKCBVU0VfQUxQSEFNQVAgKVxyXG5cclxuXHRcdHVuaWZvcm0gbWF0MyB1dlRyYW5zZm9ybTtcclxuXHJcblx0I2VuZGlmXHJcblxyXG4jZW5kaWZcclxuXHJcbiNpZmRlZiBVU0VfTUFQXHJcblxyXG5cdHVuaWZvcm0gc2FtcGxlcjJEIG1hcDtcclxuXHJcbiNlbmRpZlxyXG5cclxuI2lmZGVmIFVTRV9BTFBIQU1BUFxyXG5cclxuXHR1bmlmb3JtIHNhbXBsZXIyRCBhbHBoYU1hcDtcclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG5mbG9hdCBtZXRhbG5lc3NGYWN0b3IgPSBtZXRhbG5lc3M7XHJcblxyXG4jaWZkZWYgVVNFX01FVEFMTkVTU01BUFxyXG5cclxuXHR2ZWM0IHRleGVsTWV0YWxuZXNzID0gdGV4dHVyZTJEKCBtZXRhbG5lc3NNYXAsIHZNZXRhbG5lc3NNYXBVdiApO1xyXG5cclxuXHQvLyByZWFkcyBjaGFubmVsIEIsIGNvbXBhdGlibGUgd2l0aCBhIGNvbWJpbmVkIE9jY2x1c2lvblJvdWdobmVzc01ldGFsbGljIChSR0IpIHRleHR1cmVcclxuXHRtZXRhbG5lc3NGYWN0b3IgKj0gdGV4ZWxNZXRhbG5lc3MuYjtcclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWZkZWYgVVNFX01FVEFMTkVTU01BUFxyXG5cclxuXHR1bmlmb3JtIHNhbXBsZXIyRCBtZXRhbG5lc3NNYXA7XHJcblxyXG4jZW5kaWZcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuI2lmIGRlZmluZWQoIFVTRV9NT1JQSENPTE9SUyApICYmIGRlZmluZWQoIE1PUlBIVEFSR0VUU19URVhUVVJFIClcclxuXHJcblx0Ly8gbW9ycGhUYXJnZXRCYXNlSW5mbHVlbmNlIGlzIHNldCBiYXNlZCBvbiBCdWZmZXJHZW9tZXRyeS5tb3JwaFRhcmdldHNSZWxhdGl2ZSB2YWx1ZTpcclxuXHQvLyBXaGVuIG1vcnBoVGFyZ2V0c1JlbGF0aXZlIGlzIGZhbHNlLCB0aGlzIGlzIHNldCB0byAxIC0gc3VtKGluZmx1ZW5jZXMpOyB0aGlzIHJlc3VsdHMgaW4gbm9ybWFsID0gc3VtKCh0YXJnZXQgLSBiYXNlKSAqIGluZmx1ZW5jZSlcclxuXHQvLyBXaGVuIG1vcnBoVGFyZ2V0c1JlbGF0aXZlIGlzIHRydWUsIHRoaXMgaXMgc2V0IHRvIDE7IGFzIGEgcmVzdWx0LCBhbGwgbW9ycGggdGFyZ2V0cyBhcmUgc2ltcGx5IGFkZGVkIHRvIHRoZSBiYXNlIGFmdGVyIHdlaWdodGluZ1xyXG5cdHZDb2xvciAqPSBtb3JwaFRhcmdldEJhc2VJbmZsdWVuY2U7XHJcblxyXG5cdGZvciAoIGludCBpID0gMDsgaSA8IE1PUlBIVEFSR0VUU19DT1VOVDsgaSArKyApIHtcclxuXHJcblx0XHQjaWYgZGVmaW5lZCggVVNFX0NPTE9SX0FMUEhBIClcclxuXHJcblx0XHRcdGlmICggbW9ycGhUYXJnZXRJbmZsdWVuY2VzWyBpIF0gIT0gMC4wICkgdkNvbG9yICs9IGdldE1vcnBoKCBnbF9WZXJ0ZXhJRCwgaSwgMiApICogbW9ycGhUYXJnZXRJbmZsdWVuY2VzWyBpIF07XHJcblxyXG5cdFx0I2VsaWYgZGVmaW5lZCggVVNFX0NPTE9SIClcclxuXHJcblx0XHRcdGlmICggbW9ycGhUYXJnZXRJbmZsdWVuY2VzWyBpIF0gIT0gMC4wICkgdkNvbG9yICs9IGdldE1vcnBoKCBnbF9WZXJ0ZXhJRCwgaSwgMiApLnJnYiAqIG1vcnBoVGFyZ2V0SW5mbHVlbmNlc1sgaSBdO1xyXG5cclxuXHRcdCNlbmRpZlxyXG5cclxuXHR9XHJcblxyXG4jZW5kaWZcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuI2lmZGVmIFVTRV9NT1JQSE5PUk1BTFNcclxuXHJcblx0Ly8gbW9ycGhUYXJnZXRCYXNlSW5mbHVlbmNlIGlzIHNldCBiYXNlZCBvbiBCdWZmZXJHZW9tZXRyeS5tb3JwaFRhcmdldHNSZWxhdGl2ZSB2YWx1ZTpcclxuXHQvLyBXaGVuIG1vcnBoVGFyZ2V0c1JlbGF0aXZlIGlzIGZhbHNlLCB0aGlzIGlzIHNldCB0byAxIC0gc3VtKGluZmx1ZW5jZXMpOyB0aGlzIHJlc3VsdHMgaW4gbm9ybWFsID0gc3VtKCh0YXJnZXQgLSBiYXNlKSAqIGluZmx1ZW5jZSlcclxuXHQvLyBXaGVuIG1vcnBoVGFyZ2V0c1JlbGF0aXZlIGlzIHRydWUsIHRoaXMgaXMgc2V0IHRvIDE7IGFzIGEgcmVzdWx0LCBhbGwgbW9ycGggdGFyZ2V0cyBhcmUgc2ltcGx5IGFkZGVkIHRvIHRoZSBiYXNlIGFmdGVyIHdlaWdodGluZ1xyXG5cdG9iamVjdE5vcm1hbCAqPSBtb3JwaFRhcmdldEJhc2VJbmZsdWVuY2U7XHJcblxyXG5cdCNpZmRlZiBNT1JQSFRBUkdFVFNfVEVYVFVSRVxyXG5cclxuXHRcdGZvciAoIGludCBpID0gMDsgaSA8IE1PUlBIVEFSR0VUU19DT1VOVDsgaSArKyApIHtcclxuXHJcblx0XHRcdGlmICggbW9ycGhUYXJnZXRJbmZsdWVuY2VzWyBpIF0gIT0gMC4wICkgb2JqZWN0Tm9ybWFsICs9IGdldE1vcnBoKCBnbF9WZXJ0ZXhJRCwgaSwgMSApLnh5eiAqIG1vcnBoVGFyZ2V0SW5mbHVlbmNlc1sgaSBdO1xyXG5cclxuXHRcdH1cclxuXHJcblx0I2Vsc2VcclxuXHJcblx0XHRvYmplY3ROb3JtYWwgKz0gbW9ycGhOb3JtYWwwICogbW9ycGhUYXJnZXRJbmZsdWVuY2VzWyAwIF07XHJcblx0XHRvYmplY3ROb3JtYWwgKz0gbW9ycGhOb3JtYWwxICogbW9ycGhUYXJnZXRJbmZsdWVuY2VzWyAxIF07XHJcblx0XHRvYmplY3ROb3JtYWwgKz0gbW9ycGhOb3JtYWwyICogbW9ycGhUYXJnZXRJbmZsdWVuY2VzWyAyIF07XHJcblx0XHRvYmplY3ROb3JtYWwgKz0gbW9ycGhOb3JtYWwzICogbW9ycGhUYXJnZXRJbmZsdWVuY2VzWyAzIF07XHJcblxyXG5cdCNlbmRpZlxyXG5cclxuI2VuZGlmXHJcbmA7XHJcbiIsImV4cG9ydCBkZWZhdWx0IC8qIGdsc2wgKi9gXHJcbiNpZmRlZiBVU0VfTU9SUEhUQVJHRVRTXHJcblxyXG5cdHVuaWZvcm0gZmxvYXQgbW9ycGhUYXJnZXRCYXNlSW5mbHVlbmNlO1xyXG5cclxuXHQjaWZkZWYgTU9SUEhUQVJHRVRTX1RFWFRVUkVcclxuXHJcblx0XHR1bmlmb3JtIGZsb2F0IG1vcnBoVGFyZ2V0SW5mbHVlbmNlc1sgTU9SUEhUQVJHRVRTX0NPVU5UIF07XHJcblx0XHR1bmlmb3JtIHNhbXBsZXIyREFycmF5IG1vcnBoVGFyZ2V0c1RleHR1cmU7XHJcblx0XHR1bmlmb3JtIGl2ZWMyIG1vcnBoVGFyZ2V0c1RleHR1cmVTaXplO1xyXG5cclxuXHRcdHZlYzQgZ2V0TW9ycGgoIGNvbnN0IGluIGludCB2ZXJ0ZXhJbmRleCwgY29uc3QgaW4gaW50IG1vcnBoVGFyZ2V0SW5kZXgsIGNvbnN0IGluIGludCBvZmZzZXQgKSB7XHJcblxyXG5cdFx0XHRpbnQgdGV4ZWxJbmRleCA9IHZlcnRleEluZGV4ICogTU9SUEhUQVJHRVRTX1RFWFRVUkVfU1RSSURFICsgb2Zmc2V0O1xyXG5cdFx0XHRpbnQgeSA9IHRleGVsSW5kZXggLyBtb3JwaFRhcmdldHNUZXh0dXJlU2l6ZS54O1xyXG5cdFx0XHRpbnQgeCA9IHRleGVsSW5kZXggLSB5ICogbW9ycGhUYXJnZXRzVGV4dHVyZVNpemUueDtcclxuXHJcblx0XHRcdGl2ZWMzIG1vcnBoVVYgPSBpdmVjMyggeCwgeSwgbW9ycGhUYXJnZXRJbmRleCApO1xyXG5cdFx0XHRyZXR1cm4gdGV4ZWxGZXRjaCggbW9ycGhUYXJnZXRzVGV4dHVyZSwgbW9ycGhVViwgMCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0I2Vsc2VcclxuXHJcblx0XHQjaWZuZGVmIFVTRV9NT1JQSE5PUk1BTFNcclxuXHJcblx0XHRcdHVuaWZvcm0gZmxvYXQgbW9ycGhUYXJnZXRJbmZsdWVuY2VzWyA4IF07XHJcblxyXG5cdFx0I2Vsc2VcclxuXHJcblx0XHRcdHVuaWZvcm0gZmxvYXQgbW9ycGhUYXJnZXRJbmZsdWVuY2VzWyA0IF07XHJcblxyXG5cdFx0I2VuZGlmXHJcblxyXG5cdCNlbmRpZlxyXG5cclxuI2VuZGlmXHJcbmA7XHJcbiIsImV4cG9ydCBkZWZhdWx0IC8qIGdsc2wgKi9gXHJcbiNpZmRlZiBVU0VfTU9SUEhUQVJHRVRTXHJcblxyXG5cdC8vIG1vcnBoVGFyZ2V0QmFzZUluZmx1ZW5jZSBpcyBzZXQgYmFzZWQgb24gQnVmZmVyR2VvbWV0cnkubW9ycGhUYXJnZXRzUmVsYXRpdmUgdmFsdWU6XHJcblx0Ly8gV2hlbiBtb3JwaFRhcmdldHNSZWxhdGl2ZSBpcyBmYWxzZSwgdGhpcyBpcyBzZXQgdG8gMSAtIHN1bShpbmZsdWVuY2VzKTsgdGhpcyByZXN1bHRzIGluIHBvc2l0aW9uID0gc3VtKCh0YXJnZXQgLSBiYXNlKSAqIGluZmx1ZW5jZSlcclxuXHQvLyBXaGVuIG1vcnBoVGFyZ2V0c1JlbGF0aXZlIGlzIHRydWUsIHRoaXMgaXMgc2V0IHRvIDE7IGFzIGEgcmVzdWx0LCBhbGwgbW9ycGggdGFyZ2V0cyBhcmUgc2ltcGx5IGFkZGVkIHRvIHRoZSBiYXNlIGFmdGVyIHdlaWdodGluZ1xyXG5cdHRyYW5zZm9ybWVkICo9IG1vcnBoVGFyZ2V0QmFzZUluZmx1ZW5jZTtcclxuXHJcblx0I2lmZGVmIE1PUlBIVEFSR0VUU19URVhUVVJFXHJcblxyXG5cdFx0Zm9yICggaW50IGkgPSAwOyBpIDwgTU9SUEhUQVJHRVRTX0NPVU5UOyBpICsrICkge1xyXG5cclxuXHRcdFx0aWYgKCBtb3JwaFRhcmdldEluZmx1ZW5jZXNbIGkgXSAhPSAwLjAgKSB0cmFuc2Zvcm1lZCArPSBnZXRNb3JwaCggZ2xfVmVydGV4SUQsIGksIDAgKS54eXogKiBtb3JwaFRhcmdldEluZmx1ZW5jZXNbIGkgXTtcclxuXHJcblx0XHR9XHJcblxyXG5cdCNlbHNlXHJcblxyXG5cdFx0dHJhbnNmb3JtZWQgKz0gbW9ycGhUYXJnZXQwICogbW9ycGhUYXJnZXRJbmZsdWVuY2VzWyAwIF07XHJcblx0XHR0cmFuc2Zvcm1lZCArPSBtb3JwaFRhcmdldDEgKiBtb3JwaFRhcmdldEluZmx1ZW5jZXNbIDEgXTtcclxuXHRcdHRyYW5zZm9ybWVkICs9IG1vcnBoVGFyZ2V0MiAqIG1vcnBoVGFyZ2V0SW5mbHVlbmNlc1sgMiBdO1xyXG5cdFx0dHJhbnNmb3JtZWQgKz0gbW9ycGhUYXJnZXQzICogbW9ycGhUYXJnZXRJbmZsdWVuY2VzWyAzIF07XHJcblxyXG5cdFx0I2lmbmRlZiBVU0VfTU9SUEhOT1JNQUxTXHJcblxyXG5cdFx0XHR0cmFuc2Zvcm1lZCArPSBtb3JwaFRhcmdldDQgKiBtb3JwaFRhcmdldEluZmx1ZW5jZXNbIDQgXTtcclxuXHRcdFx0dHJhbnNmb3JtZWQgKz0gbW9ycGhUYXJnZXQ1ICogbW9ycGhUYXJnZXRJbmZsdWVuY2VzWyA1IF07XHJcblx0XHRcdHRyYW5zZm9ybWVkICs9IG1vcnBoVGFyZ2V0NiAqIG1vcnBoVGFyZ2V0SW5mbHVlbmNlc1sgNiBdO1xyXG5cdFx0XHR0cmFuc2Zvcm1lZCArPSBtb3JwaFRhcmdldDcgKiBtb3JwaFRhcmdldEluZmx1ZW5jZXNbIDcgXTtcclxuXHJcblx0XHQjZW5kaWZcclxuXHJcblx0I2VuZGlmXHJcblxyXG4jZW5kaWZcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuZmxvYXQgZmFjZURpcmVjdGlvbiA9IGdsX0Zyb250RmFjaW5nID8gMS4wIDogLSAxLjA7XHJcblxyXG4jaWZkZWYgRkxBVF9TSEFERURcclxuXHJcblx0dmVjMyBmZHggPSBkRmR4KCB2Vmlld1Bvc2l0aW9uICk7XHJcblx0dmVjMyBmZHkgPSBkRmR5KCB2Vmlld1Bvc2l0aW9uICk7XHJcblx0dmVjMyBub3JtYWwgPSBub3JtYWxpemUoIGNyb3NzKCBmZHgsIGZkeSApICk7XHJcblxyXG4jZWxzZVxyXG5cclxuXHR2ZWMzIG5vcm1hbCA9IG5vcm1hbGl6ZSggdk5vcm1hbCApO1xyXG5cclxuXHQjaWZkZWYgRE9VQkxFX1NJREVEXHJcblxyXG5cdFx0bm9ybWFsICo9IGZhY2VEaXJlY3Rpb247XHJcblxyXG5cdCNlbmRpZlxyXG5cclxuI2VuZGlmXHJcblxyXG4jaWYgZGVmaW5lZCggVVNFX05PUk1BTE1BUF9UQU5HRU5UU1BBQ0UgKSB8fCBkZWZpbmVkKCBVU0VfQ0xFQVJDT0FUX05PUk1BTE1BUCApIHx8IGRlZmluZWQoIFVTRV9BTklTT1RST1BZIClcclxuXHJcblx0I2lmZGVmIFVTRV9UQU5HRU5UXHJcblxyXG5cdFx0bWF0MyB0Ym4gPSBtYXQzKCBub3JtYWxpemUoIHZUYW5nZW50ICksIG5vcm1hbGl6ZSggdkJpdGFuZ2VudCApLCBub3JtYWwgKTtcclxuXHJcblx0I2Vsc2VcclxuXHJcblx0XHRtYXQzIHRibiA9IGdldFRhbmdlbnRGcmFtZSggLSB2Vmlld1Bvc2l0aW9uLCBub3JtYWwsXHJcblx0XHQjaWYgZGVmaW5lZCggVVNFX05PUk1BTE1BUCApXHJcblx0XHRcdHZOb3JtYWxNYXBVdlxyXG5cdFx0I2VsaWYgZGVmaW5lZCggVVNFX0NMRUFSQ09BVF9OT1JNQUxNQVAgKVxyXG5cdFx0XHR2Q2xlYXJjb2F0Tm9ybWFsTWFwVXZcclxuXHRcdCNlbHNlXHJcblx0XHRcdHZVdlxyXG5cdFx0I2VuZGlmXHJcblx0XHQpO1xyXG5cclxuXHQjZW5kaWZcclxuXHJcblx0I2lmIGRlZmluZWQoIERPVUJMRV9TSURFRCApICYmICEgZGVmaW5lZCggRkxBVF9TSEFERUQgKVxyXG5cclxuXHRcdHRiblswXSAqPSBmYWNlRGlyZWN0aW9uO1xyXG5cdFx0dGJuWzFdICo9IGZhY2VEaXJlY3Rpb247XHJcblxyXG5cdCNlbmRpZlxyXG5cclxuI2VuZGlmXHJcblxyXG4jaWZkZWYgVVNFX0NMRUFSQ09BVF9OT1JNQUxNQVBcclxuXHJcblx0I2lmZGVmIFVTRV9UQU5HRU5UXHJcblxyXG5cdFx0bWF0MyB0Ym4yID0gbWF0Myggbm9ybWFsaXplKCB2VGFuZ2VudCApLCBub3JtYWxpemUoIHZCaXRhbmdlbnQgKSwgbm9ybWFsICk7XHJcblxyXG5cdCNlbHNlXHJcblxyXG5cdFx0bWF0MyB0Ym4yID0gZ2V0VGFuZ2VudEZyYW1lKCAtIHZWaWV3UG9zaXRpb24sIG5vcm1hbCwgdkNsZWFyY29hdE5vcm1hbE1hcFV2ICk7XHJcblxyXG5cdCNlbmRpZlxyXG5cclxuXHQjaWYgZGVmaW5lZCggRE9VQkxFX1NJREVEICkgJiYgISBkZWZpbmVkKCBGTEFUX1NIQURFRCApXHJcblxyXG5cdFx0dGJuMlswXSAqPSBmYWNlRGlyZWN0aW9uO1xyXG5cdFx0dGJuMlsxXSAqPSBmYWNlRGlyZWN0aW9uO1xyXG5cclxuXHQjZW5kaWZcclxuXHJcbiNlbmRpZlxyXG5cclxuLy8gbm9uIHBlcnR1cmJlZCBub3JtYWwgZm9yIGNsZWFyY29hdCBhbW9uZyBvdGhlcnNcclxuXHJcbnZlYzMgbm9uUGVydHVyYmVkTm9ybWFsID0gbm9ybWFsO1xyXG5cclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuXHJcbiNpZmRlZiBVU0VfTk9STUFMTUFQX09CSkVDVFNQQUNFXHJcblxyXG5cdG5vcm1hbCA9IHRleHR1cmUyRCggbm9ybWFsTWFwLCB2Tm9ybWFsTWFwVXYgKS54eXogKiAyLjAgLSAxLjA7IC8vIG92ZXJyaWRlcyBib3RoIGZsYXRTaGFkaW5nIGFuZCBhdHRyaWJ1dGUgbm9ybWFsc1xyXG5cclxuXHQjaWZkZWYgRkxJUF9TSURFRFxyXG5cclxuXHRcdG5vcm1hbCA9IC0gbm9ybWFsO1xyXG5cclxuXHQjZW5kaWZcclxuXHJcblx0I2lmZGVmIERPVUJMRV9TSURFRFxyXG5cclxuXHRcdG5vcm1hbCA9IG5vcm1hbCAqIGZhY2VEaXJlY3Rpb247XHJcblxyXG5cdCNlbmRpZlxyXG5cclxuXHRub3JtYWwgPSBub3JtYWxpemUoIG5vcm1hbE1hdHJpeCAqIG5vcm1hbCApO1xyXG5cclxuI2VsaWYgZGVmaW5lZCggVVNFX05PUk1BTE1BUF9UQU5HRU5UU1BBQ0UgKVxyXG5cclxuXHR2ZWMzIG1hcE4gPSB0ZXh0dXJlMkQoIG5vcm1hbE1hcCwgdk5vcm1hbE1hcFV2ICkueHl6ICogMi4wIC0gMS4wO1xyXG5cdG1hcE4ueHkgKj0gbm9ybWFsU2NhbGU7XHJcblxyXG5cdG5vcm1hbCA9IG5vcm1hbGl6ZSggdGJuICogbWFwTiApO1xyXG5cclxuI2VsaWYgZGVmaW5lZCggVVNFX0JVTVBNQVAgKVxyXG5cclxuXHRub3JtYWwgPSBwZXJ0dXJiTm9ybWFsQXJiKCAtIHZWaWV3UG9zaXRpb24sIG5vcm1hbCwgZEhkeHlfZndkKCksIGZhY2VEaXJlY3Rpb24gKTtcclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWZuZGVmIEZMQVRfU0hBREVEXHJcblxyXG5cdHZhcnlpbmcgdmVjMyB2Tm9ybWFsO1xyXG5cclxuXHQjaWZkZWYgVVNFX1RBTkdFTlRcclxuXHJcblx0XHR2YXJ5aW5nIHZlYzMgdlRhbmdlbnQ7XHJcblx0XHR2YXJ5aW5nIHZlYzMgdkJpdGFuZ2VudDtcclxuXHJcblx0I2VuZGlmXHJcblxyXG4jZW5kaWZcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuI2lmbmRlZiBGTEFUX1NIQURFRFxyXG5cclxuXHR2YXJ5aW5nIHZlYzMgdk5vcm1hbDtcclxuXHJcblx0I2lmZGVmIFVTRV9UQU5HRU5UXHJcblxyXG5cdFx0dmFyeWluZyB2ZWMzIHZUYW5nZW50O1xyXG5cdFx0dmFyeWluZyB2ZWMzIHZCaXRhbmdlbnQ7XHJcblxyXG5cdCNlbmRpZlxyXG5cclxuI2VuZGlmXHJcbmA7XHJcbiIsImV4cG9ydCBkZWZhdWx0IC8qIGdsc2wgKi9gXHJcbiNpZm5kZWYgRkxBVF9TSEFERUQgLy8gbm9ybWFsIGlzIGNvbXB1dGVkIHdpdGggZGVyaXZhdGl2ZXMgd2hlbiBGTEFUX1NIQURFRFxyXG5cclxuXHR2Tm9ybWFsID0gbm9ybWFsaXplKCB0cmFuc2Zvcm1lZE5vcm1hbCApO1xyXG5cclxuXHQjaWZkZWYgVVNFX1RBTkdFTlRcclxuXHJcblx0XHR2VGFuZ2VudCA9IG5vcm1hbGl6ZSggdHJhbnNmb3JtZWRUYW5nZW50ICk7XHJcblx0XHR2Qml0YW5nZW50ID0gbm9ybWFsaXplKCBjcm9zcyggdk5vcm1hbCwgdlRhbmdlbnQgKSAqIHRhbmdlbnQudyApO1xyXG5cclxuXHQjZW5kaWZcclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWZkZWYgVVNFX05PUk1BTE1BUFxyXG5cclxuXHR1bmlmb3JtIHNhbXBsZXIyRCBub3JtYWxNYXA7XHJcblx0dW5pZm9ybSB2ZWMyIG5vcm1hbFNjYWxlO1xyXG5cclxuI2VuZGlmXHJcblxyXG4jaWZkZWYgVVNFX05PUk1BTE1BUF9PQkpFQ1RTUEFDRVxyXG5cclxuXHR1bmlmb3JtIG1hdDMgbm9ybWFsTWF0cml4O1xyXG5cclxuI2VuZGlmXHJcblxyXG4jaWYgISBkZWZpbmVkICggVVNFX1RBTkdFTlQgKSAmJiAoIGRlZmluZWQgKCBVU0VfTk9STUFMTUFQX1RBTkdFTlRTUEFDRSApIHx8IGRlZmluZWQgKCBVU0VfQ0xFQVJDT0FUX05PUk1BTE1BUCApIHx8IGRlZmluZWQoIFVTRV9BTklTT1RST1BZICkgKVxyXG5cclxuXHQvLyBOb3JtYWwgTWFwcGluZyBXaXRob3V0IFByZWNvbXB1dGVkIFRhbmdlbnRzXHJcblx0Ly8gaHR0cDovL3d3dy50aGV0ZW50aHBsYW5ldC5kZS9hcmNoaXZlcy8xMTgwXHJcblxyXG5cdG1hdDMgZ2V0VGFuZ2VudEZyYW1lKCB2ZWMzIGV5ZV9wb3MsIHZlYzMgc3VyZl9ub3JtLCB2ZWMyIHV2ICkge1xyXG5cclxuXHRcdHZlYzMgcTAgPSBkRmR4KCBleWVfcG9zLnh5eiApO1xyXG5cdFx0dmVjMyBxMSA9IGRGZHkoIGV5ZV9wb3MueHl6ICk7XHJcblx0XHR2ZWMyIHN0MCA9IGRGZHgoIHV2LnN0ICk7XHJcblx0XHR2ZWMyIHN0MSA9IGRGZHkoIHV2LnN0ICk7XHJcblxyXG5cdFx0dmVjMyBOID0gc3VyZl9ub3JtOyAvLyBub3JtYWxpemVkXHJcblxyXG5cdFx0dmVjMyBxMXBlcnAgPSBjcm9zcyggcTEsIE4gKTtcclxuXHRcdHZlYzMgcTBwZXJwID0gY3Jvc3MoIE4sIHEwICk7XHJcblxyXG5cdFx0dmVjMyBUID0gcTFwZXJwICogc3QwLnggKyBxMHBlcnAgKiBzdDEueDtcclxuXHRcdHZlYzMgQiA9IHExcGVycCAqIHN0MC55ICsgcTBwZXJwICogc3QxLnk7XHJcblxyXG5cdFx0ZmxvYXQgZGV0ID0gbWF4KCBkb3QoIFQsIFQgKSwgZG90KCBCLCBCICkgKTtcclxuXHRcdGZsb2F0IHNjYWxlID0gKCBkZXQgPT0gMC4wICkgPyAwLjAgOiBpbnZlcnNlc3FydCggZGV0ICk7XHJcblxyXG5cdFx0cmV0dXJuIG1hdDMoIFQgKiBzY2FsZSwgQiAqIHNjYWxlLCBOICk7XHJcblxyXG5cdH1cclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWZkZWYgVVNFX0NMRUFSQ09BVFxyXG5cclxuXHR2ZWMzIGNsZWFyY29hdE5vcm1hbCA9IG5vblBlcnR1cmJlZE5vcm1hbDtcclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWZkZWYgVVNFX0NMRUFSQ09BVF9OT1JNQUxNQVBcclxuXHJcblx0dmVjMyBjbGVhcmNvYXRNYXBOID0gdGV4dHVyZTJEKCBjbGVhcmNvYXROb3JtYWxNYXAsIHZDbGVhcmNvYXROb3JtYWxNYXBVdiApLnh5eiAqIDIuMCAtIDEuMDtcclxuXHRjbGVhcmNvYXRNYXBOLnh5ICo9IGNsZWFyY29hdE5vcm1hbFNjYWxlO1xyXG5cclxuXHRjbGVhcmNvYXROb3JtYWwgPSBub3JtYWxpemUoIHRibjIgKiBjbGVhcmNvYXRNYXBOICk7XHJcblxyXG4jZW5kaWZcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuXHJcbiNpZmRlZiBVU0VfQ0xFQVJDT0FUTUFQXHJcblxyXG5cdHVuaWZvcm0gc2FtcGxlcjJEIGNsZWFyY29hdE1hcDtcclxuXHJcbiNlbmRpZlxyXG5cclxuI2lmZGVmIFVTRV9DTEVBUkNPQVRfTk9STUFMTUFQXHJcblxyXG5cdHVuaWZvcm0gc2FtcGxlcjJEIGNsZWFyY29hdE5vcm1hbE1hcDtcclxuXHR1bmlmb3JtIHZlYzIgY2xlYXJjb2F0Tm9ybWFsU2NhbGU7XHJcblxyXG4jZW5kaWZcclxuXHJcbiNpZmRlZiBVU0VfQ0xFQVJDT0FUX1JPVUdITkVTU01BUFxyXG5cclxuXHR1bmlmb3JtIHNhbXBsZXIyRCBjbGVhcmNvYXRSb3VnaG5lc3NNYXA7XHJcblxyXG4jZW5kaWZcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuXHJcbiNpZmRlZiBVU0VfSVJJREVTQ0VOQ0VNQVBcclxuXHJcblx0dW5pZm9ybSBzYW1wbGVyMkQgaXJpZGVzY2VuY2VNYXA7XHJcblxyXG4jZW5kaWZcclxuXHJcbiNpZmRlZiBVU0VfSVJJREVTQ0VOQ0VfVEhJQ0tORVNTTUFQXHJcblxyXG5cdHVuaWZvcm0gc2FtcGxlcjJEIGlyaWRlc2NlbmNlVGhpY2tuZXNzTWFwO1xyXG5cclxuI2VuZGlmXHJcbmA7XHJcbiIsImV4cG9ydCBkZWZhdWx0IC8qIGdsc2wgKi9gXHJcbiNpZmRlZiBPUEFRVUVcclxuZGlmZnVzZUNvbG9yLmEgPSAxLjA7XHJcbiNlbmRpZlxyXG5cclxuI2lmZGVmIFVTRV9UUkFOU01JU1NJT05cclxuZGlmZnVzZUNvbG9yLmEgKj0gbWF0ZXJpYWwudHJhbnNtaXNzaW9uQWxwaGE7XHJcbiNlbmRpZlxyXG5cclxuZ2xfRnJhZ0NvbG9yID0gdmVjNCggb3V0Z29pbmdMaWdodCwgZGlmZnVzZUNvbG9yLmEgKTtcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxudmVjMyBwYWNrTm9ybWFsVG9SR0IoIGNvbnN0IGluIHZlYzMgbm9ybWFsICkge1xyXG5cdHJldHVybiBub3JtYWxpemUoIG5vcm1hbCApICogMC41ICsgMC41O1xyXG59XHJcblxyXG52ZWMzIHVucGFja1JHQlRvTm9ybWFsKCBjb25zdCBpbiB2ZWMzIHJnYiApIHtcclxuXHRyZXR1cm4gMi4wICogcmdiLnh5eiAtIDEuMDtcclxufVxyXG5cclxuY29uc3QgZmxvYXQgUGFja1Vwc2NhbGUgPSAyNTYuIC8gMjU1LjsgLy8gZnJhY3Rpb24gLT4gMC4uMSAoaW5jbHVkaW5nIDEpXHJcbmNvbnN0IGZsb2F0IFVucGFja0Rvd25zY2FsZSA9IDI1NS4gLyAyNTYuOyAvLyAwLi4xIC0+IGZyYWN0aW9uIChleGNsdWRpbmcgMSlcclxuXHJcbmNvbnN0IHZlYzMgUGFja0ZhY3RvcnMgPSB2ZWMzKCAyNTYuICogMjU2LiAqIDI1Ni4sIDI1Ni4gKiAyNTYuLCAyNTYuICk7XHJcbmNvbnN0IHZlYzQgVW5wYWNrRmFjdG9ycyA9IFVucGFja0Rvd25zY2FsZSAvIHZlYzQoIFBhY2tGYWN0b3JzLCAxLiApO1xyXG5cclxuY29uc3QgZmxvYXQgU2hpZnRSaWdodDggPSAxLiAvIDI1Ni47XHJcblxyXG52ZWM0IHBhY2tEZXB0aFRvUkdCQSggY29uc3QgaW4gZmxvYXQgdiApIHtcclxuXHR2ZWM0IHIgPSB2ZWM0KCBmcmFjdCggdiAqIFBhY2tGYWN0b3JzICksIHYgKTtcclxuXHRyLnl6dyAtPSByLnh5eiAqIFNoaWZ0UmlnaHQ4OyAvLyB0aWR5IG92ZXJmbG93XHJcblx0cmV0dXJuIHIgKiBQYWNrVXBzY2FsZTtcclxufVxyXG5cclxuZmxvYXQgdW5wYWNrUkdCQVRvRGVwdGgoIGNvbnN0IGluIHZlYzQgdiApIHtcclxuXHRyZXR1cm4gZG90KCB2LCBVbnBhY2tGYWN0b3JzICk7XHJcbn1cclxuXHJcbnZlYzIgcGFja0RlcHRoVG9SRyggaW4gaGlnaHAgZmxvYXQgdiApIHtcclxuXHRyZXR1cm4gcGFja0RlcHRoVG9SR0JBKCB2ICkueXg7XHJcbn1cclxuXHJcbmZsb2F0IHVucGFja1JHVG9EZXB0aCggY29uc3QgaW4gaGlnaHAgdmVjMiB2ICkge1xyXG5cdHJldHVybiB1bnBhY2tSR0JBVG9EZXB0aCggdmVjNCggdi54eSwgMC4wLCAwLjAgKSApO1xyXG59XHJcblxyXG52ZWM0IHBhY2sySGFsZlRvUkdCQSggdmVjMiB2ICkge1xyXG5cdHZlYzQgciA9IHZlYzQoIHYueCwgZnJhY3QoIHYueCAqIDI1NS4wICksIHYueSwgZnJhY3QoIHYueSAqIDI1NS4wICkgKTtcclxuXHRyZXR1cm4gdmVjNCggci54IC0gci55IC8gMjU1LjAsIHIueSwgci56IC0gci53IC8gMjU1LjAsIHIudyApO1xyXG59XHJcblxyXG52ZWMyIHVucGFja1JHQkFUbzJIYWxmKCB2ZWM0IHYgKSB7XHJcblx0cmV0dXJuIHZlYzIoIHYueCArICggdi55IC8gMjU1LjAgKSwgdi56ICsgKCB2LncgLyAyNTUuMCApICk7XHJcbn1cclxuXHJcbi8vIE5PVEU6IHZpZXdaLCB0aGUgei1jb29yZGluYXRlIGluIGNhbWVyYSBzcGFjZSwgaXMgbmVnYXRpdmUgZm9yIHBvaW50cyBpbiBmcm9udCBvZiB0aGUgY2FtZXJhXHJcblxyXG5mbG9hdCB2aWV3WlRvT3J0aG9ncmFwaGljRGVwdGgoIGNvbnN0IGluIGZsb2F0IHZpZXdaLCBjb25zdCBpbiBmbG9hdCBuZWFyLCBjb25zdCBpbiBmbG9hdCBmYXIgKSB7XHJcblx0Ly8gLW5lYXIgbWFwcyB0byAwOyAtZmFyIG1hcHMgdG8gMVxyXG5cdHJldHVybiAoIHZpZXdaICsgbmVhciApIC8gKCBuZWFyIC0gZmFyICk7XHJcbn1cclxuXHJcbmZsb2F0IG9ydGhvZ3JhcGhpY0RlcHRoVG9WaWV3WiggY29uc3QgaW4gZmxvYXQgZGVwdGgsIGNvbnN0IGluIGZsb2F0IG5lYXIsIGNvbnN0IGluIGZsb2F0IGZhciApIHtcclxuXHQvLyBtYXBzIG9ydGhvZ3JhcGhpYyBkZXB0aCBpbiBbIDAsIDEgXSB0byB2aWV3WlxyXG5cdHJldHVybiBkZXB0aCAqICggbmVhciAtIGZhciApIC0gbmVhcjtcclxufVxyXG5cclxuLy8gTk9URTogaHR0cHM6Ly90d2l0dGVyLmNvbS9nb25uYXZpcy9zdGF0dXMvMTM3NzE4Mzc4Njk0OTk1OTY4MlxyXG5cclxuZmxvYXQgdmlld1pUb1BlcnNwZWN0aXZlRGVwdGgoIGNvbnN0IGluIGZsb2F0IHZpZXdaLCBjb25zdCBpbiBmbG9hdCBuZWFyLCBjb25zdCBpbiBmbG9hdCBmYXIgKSB7XHJcblx0Ly8gLW5lYXIgbWFwcyB0byAwOyAtZmFyIG1hcHMgdG8gMVxyXG5cdHJldHVybiAoICggbmVhciArIHZpZXdaICkgKiBmYXIgKSAvICggKCBmYXIgLSBuZWFyICkgKiB2aWV3WiApO1xyXG59XHJcblxyXG5mbG9hdCBwZXJzcGVjdGl2ZURlcHRoVG9WaWV3WiggY29uc3QgaW4gZmxvYXQgZGVwdGgsIGNvbnN0IGluIGZsb2F0IG5lYXIsIGNvbnN0IGluIGZsb2F0IGZhciApIHtcclxuXHQvLyBtYXBzIHBlcnNwZWN0aXZlIGRlcHRoIGluIFsgMCwgMSBdIHRvIHZpZXdaXHJcblx0cmV0dXJuICggbmVhciAqIGZhciApIC8gKCAoIGZhciAtIG5lYXIgKSAqIGRlcHRoIC0gZmFyICk7XHJcbn1cclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuI2lmZGVmIFBSRU1VTFRJUExJRURfQUxQSEFcclxuXHJcblx0Ly8gR2V0IGdldCBub3JtYWwgYmxlbmRpbmcgd2l0aCBwcmVtdWx0aXBsZWQsIHVzZSB3aXRoIEN1c3RvbUJsZW5kaW5nLCBPbmVGYWN0b3IsIE9uZU1pbnVzU3JjQWxwaGFGYWN0b3IsIEFkZEVxdWF0aW9uLlxyXG5cdGdsX0ZyYWdDb2xvci5yZ2IgKj0gZ2xfRnJhZ0NvbG9yLmE7XHJcblxyXG4jZW5kaWZcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxudmVjNCBtdlBvc2l0aW9uID0gdmVjNCggdHJhbnNmb3JtZWQsIDEuMCApO1xyXG5cclxuI2lmZGVmIFVTRV9CQVRDSElOR1xyXG5cclxuXHRtdlBvc2l0aW9uID0gYmF0Y2hpbmdNYXRyaXggKiBtdlBvc2l0aW9uO1xyXG5cclxuI2VuZGlmXHJcblxyXG4jaWZkZWYgVVNFX0lOU1RBTkNJTkdcclxuXHJcblx0bXZQb3NpdGlvbiA9IGluc3RhbmNlTWF0cml4ICogbXZQb3NpdGlvbjtcclxuXHJcbiNlbmRpZlxyXG5cclxubXZQb3NpdGlvbiA9IG1vZGVsVmlld01hdHJpeCAqIG12UG9zaXRpb247XHJcblxyXG5nbF9Qb3NpdGlvbiA9IHByb2plY3Rpb25NYXRyaXggKiBtdlBvc2l0aW9uO1xyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWZkZWYgRElUSEVSSU5HXHJcblxyXG5cdGdsX0ZyYWdDb2xvci5yZ2IgPSBkaXRoZXJpbmcoIGdsX0ZyYWdDb2xvci5yZ2IgKTtcclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWZkZWYgRElUSEVSSU5HXHJcblxyXG5cdC8vIGJhc2VkIG9uIGh0dHBzOi8vd3d3LnNoYWRlcnRveS5jb20vdmlldy9Nc2xHUjhcclxuXHR2ZWMzIGRpdGhlcmluZyggdmVjMyBjb2xvciApIHtcclxuXHRcdC8vQ2FsY3VsYXRlIGdyaWQgcG9zaXRpb25cclxuXHRcdGZsb2F0IGdyaWRfcG9zaXRpb24gPSByYW5kKCBnbF9GcmFnQ29vcmQueHkgKTtcclxuXHJcblx0XHQvL1NoaWZ0IHRoZSBpbmRpdmlkdWFsIGNvbG9ycyBkaWZmZXJlbnRseSwgdGh1cyBtYWtpbmcgaXQgZXZlbiBoYXJkZXIgdG8gc2VlIHRoZSBkaXRoZXJpbmcgcGF0dGVyblxyXG5cdFx0dmVjMyBkaXRoZXJfc2hpZnRfUkdCID0gdmVjMyggMC4yNSAvIDI1NS4wLCAtMC4yNSAvIDI1NS4wLCAwLjI1IC8gMjU1LjAgKTtcclxuXHJcblx0XHQvL21vZGlmeSBzaGlmdCBhY2NvcmRpbmcgdG8gZ3JpZCBwb3NpdGlvbi5cclxuXHRcdGRpdGhlcl9zaGlmdF9SR0IgPSBtaXgoIDIuMCAqIGRpdGhlcl9zaGlmdF9SR0IsIC0yLjAgKiBkaXRoZXJfc2hpZnRfUkdCLCBncmlkX3Bvc2l0aW9uICk7XHJcblxyXG5cdFx0Ly9zaGlmdCB0aGUgY29sb3IgYnkgZGl0aGVyX3NoaWZ0XHJcblx0XHRyZXR1cm4gY29sb3IgKyBkaXRoZXJfc2hpZnRfUkdCO1xyXG5cdH1cclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG5mbG9hdCByb3VnaG5lc3NGYWN0b3IgPSByb3VnaG5lc3M7XHJcblxyXG4jaWZkZWYgVVNFX1JPVUdITkVTU01BUFxyXG5cclxuXHR2ZWM0IHRleGVsUm91Z2huZXNzID0gdGV4dHVyZTJEKCByb3VnaG5lc3NNYXAsIHZSb3VnaG5lc3NNYXBVdiApO1xyXG5cclxuXHQvLyByZWFkcyBjaGFubmVsIEcsIGNvbXBhdGlibGUgd2l0aCBhIGNvbWJpbmVkIE9jY2x1c2lvblJvdWdobmVzc01ldGFsbGljIChSR0IpIHRleHR1cmVcclxuXHRyb3VnaG5lc3NGYWN0b3IgKj0gdGV4ZWxSb3VnaG5lc3MuZztcclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWZkZWYgVVNFX1JPVUdITkVTU01BUFxyXG5cclxuXHR1bmlmb3JtIHNhbXBsZXIyRCByb3VnaG5lc3NNYXA7XHJcblxyXG4jZW5kaWZcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuI2lmIE5VTV9TUE9UX0xJR0hUX0NPT1JEUyA+IDBcclxuXHJcblx0dmFyeWluZyB2ZWM0IHZTcG90TGlnaHRDb29yZFsgTlVNX1NQT1RfTElHSFRfQ09PUkRTIF07XHJcblxyXG4jZW5kaWZcclxuXHJcbiNpZiBOVU1fU1BPVF9MSUdIVF9NQVBTID4gMFxyXG5cclxuXHR1bmlmb3JtIHNhbXBsZXIyRCBzcG90TGlnaHRNYXBbIE5VTV9TUE9UX0xJR0hUX01BUFMgXTtcclxuXHJcbiNlbmRpZlxyXG5cclxuI2lmZGVmIFVTRV9TSEFET1dNQVBcclxuXHJcblx0I2lmIE5VTV9ESVJfTElHSFRfU0hBRE9XUyA+IDBcclxuXHJcblx0XHR1bmlmb3JtIHNhbXBsZXIyRCBkaXJlY3Rpb25hbFNoYWRvd01hcFsgTlVNX0RJUl9MSUdIVF9TSEFET1dTIF07XHJcblx0XHR2YXJ5aW5nIHZlYzQgdkRpcmVjdGlvbmFsU2hhZG93Q29vcmRbIE5VTV9ESVJfTElHSFRfU0hBRE9XUyBdO1xyXG5cclxuXHRcdHN0cnVjdCBEaXJlY3Rpb25hbExpZ2h0U2hhZG93IHtcclxuXHRcdFx0ZmxvYXQgc2hhZG93QmlhcztcclxuXHRcdFx0ZmxvYXQgc2hhZG93Tm9ybWFsQmlhcztcclxuXHRcdFx0ZmxvYXQgc2hhZG93UmFkaXVzO1xyXG5cdFx0XHR2ZWMyIHNoYWRvd01hcFNpemU7XHJcblx0XHR9O1xyXG5cclxuXHRcdHVuaWZvcm0gRGlyZWN0aW9uYWxMaWdodFNoYWRvdyBkaXJlY3Rpb25hbExpZ2h0U2hhZG93c1sgTlVNX0RJUl9MSUdIVF9TSEFET1dTIF07XHJcblxyXG5cdCNlbmRpZlxyXG5cclxuXHQjaWYgTlVNX1NQT1RfTElHSFRfU0hBRE9XUyA+IDBcclxuXHJcblx0XHR1bmlmb3JtIHNhbXBsZXIyRCBzcG90U2hhZG93TWFwWyBOVU1fU1BPVF9MSUdIVF9TSEFET1dTIF07XHJcblxyXG5cdFx0c3RydWN0IFNwb3RMaWdodFNoYWRvdyB7XHJcblx0XHRcdGZsb2F0IHNoYWRvd0JpYXM7XHJcblx0XHRcdGZsb2F0IHNoYWRvd05vcm1hbEJpYXM7XHJcblx0XHRcdGZsb2F0IHNoYWRvd1JhZGl1cztcclxuXHRcdFx0dmVjMiBzaGFkb3dNYXBTaXplO1xyXG5cdFx0fTtcclxuXHJcblx0XHR1bmlmb3JtIFNwb3RMaWdodFNoYWRvdyBzcG90TGlnaHRTaGFkb3dzWyBOVU1fU1BPVF9MSUdIVF9TSEFET1dTIF07XHJcblxyXG5cdCNlbmRpZlxyXG5cclxuXHQjaWYgTlVNX1BPSU5UX0xJR0hUX1NIQURPV1MgPiAwXHJcblxyXG5cdFx0dW5pZm9ybSBzYW1wbGVyMkQgcG9pbnRTaGFkb3dNYXBbIE5VTV9QT0lOVF9MSUdIVF9TSEFET1dTIF07XHJcblx0XHR2YXJ5aW5nIHZlYzQgdlBvaW50U2hhZG93Q29vcmRbIE5VTV9QT0lOVF9MSUdIVF9TSEFET1dTIF07XHJcblxyXG5cdFx0c3RydWN0IFBvaW50TGlnaHRTaGFkb3cge1xyXG5cdFx0XHRmbG9hdCBzaGFkb3dCaWFzO1xyXG5cdFx0XHRmbG9hdCBzaGFkb3dOb3JtYWxCaWFzO1xyXG5cdFx0XHRmbG9hdCBzaGFkb3dSYWRpdXM7XHJcblx0XHRcdHZlYzIgc2hhZG93TWFwU2l6ZTtcclxuXHRcdFx0ZmxvYXQgc2hhZG93Q2FtZXJhTmVhcjtcclxuXHRcdFx0ZmxvYXQgc2hhZG93Q2FtZXJhRmFyO1xyXG5cdFx0fTtcclxuXHJcblx0XHR1bmlmb3JtIFBvaW50TGlnaHRTaGFkb3cgcG9pbnRMaWdodFNoYWRvd3NbIE5VTV9QT0lOVF9MSUdIVF9TSEFET1dTIF07XHJcblxyXG5cdCNlbmRpZlxyXG5cclxuXHQvKlxyXG5cdCNpZiBOVU1fUkVDVF9BUkVBX0xJR0hUUyA+IDBcclxuXHJcblx0XHQvLyBUT0RPIChhYmVsbmF0aW9uKTogY3JlYXRlIHVuaWZvcm1zIGZvciBhcmVhIGxpZ2h0IHNoYWRvd3NcclxuXHJcblx0I2VuZGlmXHJcblx0Ki9cclxuXHJcblx0ZmxvYXQgdGV4dHVyZTJEQ29tcGFyZSggc2FtcGxlcjJEIGRlcHRocywgdmVjMiB1diwgZmxvYXQgY29tcGFyZSApIHtcclxuXHJcblx0XHRyZXR1cm4gc3RlcCggY29tcGFyZSwgdW5wYWNrUkdCQVRvRGVwdGgoIHRleHR1cmUyRCggZGVwdGhzLCB1diApICkgKTtcclxuXHJcblx0fVxyXG5cclxuXHR2ZWMyIHRleHR1cmUyRERpc3RyaWJ1dGlvbiggc2FtcGxlcjJEIHNoYWRvdywgdmVjMiB1diApIHtcclxuXHJcblx0XHRyZXR1cm4gdW5wYWNrUkdCQVRvMkhhbGYoIHRleHR1cmUyRCggc2hhZG93LCB1diApICk7XHJcblxyXG5cdH1cclxuXHJcblx0ZmxvYXQgVlNNU2hhZG93IChzYW1wbGVyMkQgc2hhZG93LCB2ZWMyIHV2LCBmbG9hdCBjb21wYXJlICl7XHJcblxyXG5cdFx0ZmxvYXQgb2NjbHVzaW9uID0gMS4wO1xyXG5cclxuXHRcdHZlYzIgZGlzdHJpYnV0aW9uID0gdGV4dHVyZTJERGlzdHJpYnV0aW9uKCBzaGFkb3csIHV2ICk7XHJcblxyXG5cdFx0ZmxvYXQgaGFyZF9zaGFkb3cgPSBzdGVwKCBjb21wYXJlICwgZGlzdHJpYnV0aW9uLnggKTsgLy8gSGFyZCBTaGFkb3dcclxuXHJcblx0XHRpZiAoaGFyZF9zaGFkb3cgIT0gMS4wICkge1xyXG5cclxuXHRcdFx0ZmxvYXQgZGlzdGFuY2UgPSBjb21wYXJlIC0gZGlzdHJpYnV0aW9uLnggO1xyXG5cdFx0XHRmbG9hdCB2YXJpYW5jZSA9IG1heCggMC4wMDAwMCwgZGlzdHJpYnV0aW9uLnkgKiBkaXN0cmlidXRpb24ueSApO1xyXG5cdFx0XHRmbG9hdCBzb2Z0bmVzc19wcm9iYWJpbGl0eSA9IHZhcmlhbmNlIC8gKHZhcmlhbmNlICsgZGlzdGFuY2UgKiBkaXN0YW5jZSApOyAvLyBDaGViZXlzaGV2cyBpbmVxdWFsaXR5XHJcblx0XHRcdHNvZnRuZXNzX3Byb2JhYmlsaXR5ID0gY2xhbXAoICggc29mdG5lc3NfcHJvYmFiaWxpdHkgLSAwLjMgKSAvICggMC45NSAtIDAuMyApLCAwLjAsIDEuMCApOyAvLyAwLjMgcmVkdWNlcyBsaWdodCBibGVlZFxyXG5cdFx0XHRvY2NsdXNpb24gPSBjbGFtcCggbWF4KCBoYXJkX3NoYWRvdywgc29mdG5lc3NfcHJvYmFiaWxpdHkgKSwgMC4wLCAxLjAgKTtcclxuXHJcblx0XHR9XHJcblx0XHRyZXR1cm4gb2NjbHVzaW9uO1xyXG5cclxuXHR9XHJcblxyXG5cdGZsb2F0IGdldFNoYWRvdyggc2FtcGxlcjJEIHNoYWRvd01hcCwgdmVjMiBzaGFkb3dNYXBTaXplLCBmbG9hdCBzaGFkb3dCaWFzLCBmbG9hdCBzaGFkb3dSYWRpdXMsIHZlYzQgc2hhZG93Q29vcmQgKSB7XHJcblxyXG5cdFx0ZmxvYXQgc2hhZG93ID0gMS4wO1xyXG5cclxuXHRcdHNoYWRvd0Nvb3JkLnh5eiAvPSBzaGFkb3dDb29yZC53O1xyXG5cdFx0c2hhZG93Q29vcmQueiArPSBzaGFkb3dCaWFzO1xyXG5cclxuXHRcdGJvb2wgaW5GcnVzdHVtID0gc2hhZG93Q29vcmQueCA+PSAwLjAgJiYgc2hhZG93Q29vcmQueCA8PSAxLjAgJiYgc2hhZG93Q29vcmQueSA+PSAwLjAgJiYgc2hhZG93Q29vcmQueSA8PSAxLjA7XHJcblx0XHRib29sIGZydXN0dW1UZXN0ID0gaW5GcnVzdHVtICYmIHNoYWRvd0Nvb3JkLnogPD0gMS4wO1xyXG5cclxuXHRcdGlmICggZnJ1c3R1bVRlc3QgKSB7XHJcblxyXG5cdFx0I2lmIGRlZmluZWQoIFNIQURPV01BUF9UWVBFX1BDRiApXHJcblxyXG5cdFx0XHR2ZWMyIHRleGVsU2l6ZSA9IHZlYzIoIDEuMCApIC8gc2hhZG93TWFwU2l6ZTtcclxuXHJcblx0XHRcdGZsb2F0IGR4MCA9IC0gdGV4ZWxTaXplLnggKiBzaGFkb3dSYWRpdXM7XHJcblx0XHRcdGZsb2F0IGR5MCA9IC0gdGV4ZWxTaXplLnkgKiBzaGFkb3dSYWRpdXM7XHJcblx0XHRcdGZsb2F0IGR4MSA9ICsgdGV4ZWxTaXplLnggKiBzaGFkb3dSYWRpdXM7XHJcblx0XHRcdGZsb2F0IGR5MSA9ICsgdGV4ZWxTaXplLnkgKiBzaGFkb3dSYWRpdXM7XHJcblx0XHRcdGZsb2F0IGR4MiA9IGR4MCAvIDIuMDtcclxuXHRcdFx0ZmxvYXQgZHkyID0gZHkwIC8gMi4wO1xyXG5cdFx0XHRmbG9hdCBkeDMgPSBkeDEgLyAyLjA7XHJcblx0XHRcdGZsb2F0IGR5MyA9IGR5MSAvIDIuMDtcclxuXHJcblx0XHRcdHNoYWRvdyA9IChcclxuXHRcdFx0XHR0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIHNoYWRvd0Nvb3JkLnh5ICsgdmVjMiggZHgwLCBkeTAgKSwgc2hhZG93Q29vcmQueiApICtcclxuXHRcdFx0XHR0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIHNoYWRvd0Nvb3JkLnh5ICsgdmVjMiggMC4wLCBkeTAgKSwgc2hhZG93Q29vcmQueiApICtcclxuXHRcdFx0XHR0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIHNoYWRvd0Nvb3JkLnh5ICsgdmVjMiggZHgxLCBkeTAgKSwgc2hhZG93Q29vcmQueiApICtcclxuXHRcdFx0XHR0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIHNoYWRvd0Nvb3JkLnh5ICsgdmVjMiggZHgyLCBkeTIgKSwgc2hhZG93Q29vcmQueiApICtcclxuXHRcdFx0XHR0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIHNoYWRvd0Nvb3JkLnh5ICsgdmVjMiggMC4wLCBkeTIgKSwgc2hhZG93Q29vcmQueiApICtcclxuXHRcdFx0XHR0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIHNoYWRvd0Nvb3JkLnh5ICsgdmVjMiggZHgzLCBkeTIgKSwgc2hhZG93Q29vcmQueiApICtcclxuXHRcdFx0XHR0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIHNoYWRvd0Nvb3JkLnh5ICsgdmVjMiggZHgwLCAwLjAgKSwgc2hhZG93Q29vcmQueiApICtcclxuXHRcdFx0XHR0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIHNoYWRvd0Nvb3JkLnh5ICsgdmVjMiggZHgyLCAwLjAgKSwgc2hhZG93Q29vcmQueiApICtcclxuXHRcdFx0XHR0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIHNoYWRvd0Nvb3JkLnh5LCBzaGFkb3dDb29yZC56ICkgK1xyXG5cdFx0XHRcdHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgc2hhZG93Q29vcmQueHkgKyB2ZWMyKCBkeDMsIDAuMCApLCBzaGFkb3dDb29yZC56ICkgK1xyXG5cdFx0XHRcdHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgc2hhZG93Q29vcmQueHkgKyB2ZWMyKCBkeDEsIDAuMCApLCBzaGFkb3dDb29yZC56ICkgK1xyXG5cdFx0XHRcdHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgc2hhZG93Q29vcmQueHkgKyB2ZWMyKCBkeDIsIGR5MyApLCBzaGFkb3dDb29yZC56ICkgK1xyXG5cdFx0XHRcdHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgc2hhZG93Q29vcmQueHkgKyB2ZWMyKCAwLjAsIGR5MyApLCBzaGFkb3dDb29yZC56ICkgK1xyXG5cdFx0XHRcdHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgc2hhZG93Q29vcmQueHkgKyB2ZWMyKCBkeDMsIGR5MyApLCBzaGFkb3dDb29yZC56ICkgK1xyXG5cdFx0XHRcdHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgc2hhZG93Q29vcmQueHkgKyB2ZWMyKCBkeDAsIGR5MSApLCBzaGFkb3dDb29yZC56ICkgK1xyXG5cdFx0XHRcdHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgc2hhZG93Q29vcmQueHkgKyB2ZWMyKCAwLjAsIGR5MSApLCBzaGFkb3dDb29yZC56ICkgK1xyXG5cdFx0XHRcdHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgc2hhZG93Q29vcmQueHkgKyB2ZWMyKCBkeDEsIGR5MSApLCBzaGFkb3dDb29yZC56IClcclxuXHRcdFx0KSAqICggMS4wIC8gMTcuMCApO1xyXG5cclxuXHRcdCNlbGlmIGRlZmluZWQoIFNIQURPV01BUF9UWVBFX1BDRl9TT0ZUIClcclxuXHJcblx0XHRcdHZlYzIgdGV4ZWxTaXplID0gdmVjMiggMS4wICkgLyBzaGFkb3dNYXBTaXplO1xyXG5cdFx0XHRmbG9hdCBkeCA9IHRleGVsU2l6ZS54O1xyXG5cdFx0XHRmbG9hdCBkeSA9IHRleGVsU2l6ZS55O1xyXG5cclxuXHRcdFx0dmVjMiB1diA9IHNoYWRvd0Nvb3JkLnh5O1xyXG5cdFx0XHR2ZWMyIGYgPSBmcmFjdCggdXYgKiBzaGFkb3dNYXBTaXplICsgMC41ICk7XHJcblx0XHRcdHV2IC09IGYgKiB0ZXhlbFNpemU7XHJcblxyXG5cdFx0XHRzaGFkb3cgPSAoXHJcblx0XHRcdFx0dGV4dHVyZTJEQ29tcGFyZSggc2hhZG93TWFwLCB1diwgc2hhZG93Q29vcmQueiApICtcclxuXHRcdFx0XHR0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIHV2ICsgdmVjMiggZHgsIDAuMCApLCBzaGFkb3dDb29yZC56ICkgK1xyXG5cdFx0XHRcdHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgdXYgKyB2ZWMyKCAwLjAsIGR5ICksIHNoYWRvd0Nvb3JkLnogKSArXHJcblx0XHRcdFx0dGV4dHVyZTJEQ29tcGFyZSggc2hhZG93TWFwLCB1diArIHRleGVsU2l6ZSwgc2hhZG93Q29vcmQueiApICtcclxuXHRcdFx0XHRtaXgoIHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgdXYgKyB2ZWMyKCAtZHgsIDAuMCApLCBzaGFkb3dDb29yZC56ICksXHJcblx0XHRcdFx0XHQgdGV4dHVyZTJEQ29tcGFyZSggc2hhZG93TWFwLCB1diArIHZlYzIoIDIuMCAqIGR4LCAwLjAgKSwgc2hhZG93Q29vcmQueiApLFxyXG5cdFx0XHRcdFx0IGYueCApICtcclxuXHRcdFx0XHRtaXgoIHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgdXYgKyB2ZWMyKCAtZHgsIGR5ICksIHNoYWRvd0Nvb3JkLnogKSxcclxuXHRcdFx0XHRcdCB0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIHV2ICsgdmVjMiggMi4wICogZHgsIGR5ICksIHNoYWRvd0Nvb3JkLnogKSxcclxuXHRcdFx0XHRcdCBmLnggKSArXHJcblx0XHRcdFx0bWl4KCB0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIHV2ICsgdmVjMiggMC4wLCAtZHkgKSwgc2hhZG93Q29vcmQueiApLFxyXG5cdFx0XHRcdFx0IHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgdXYgKyB2ZWMyKCAwLjAsIDIuMCAqIGR5ICksIHNoYWRvd0Nvb3JkLnogKSxcclxuXHRcdFx0XHRcdCBmLnkgKSArXHJcblx0XHRcdFx0bWl4KCB0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIHV2ICsgdmVjMiggZHgsIC1keSApLCBzaGFkb3dDb29yZC56ICksXHJcblx0XHRcdFx0XHQgdGV4dHVyZTJEQ29tcGFyZSggc2hhZG93TWFwLCB1diArIHZlYzIoIGR4LCAyLjAgKiBkeSApLCBzaGFkb3dDb29yZC56ICksXHJcblx0XHRcdFx0XHQgZi55ICkgK1xyXG5cdFx0XHRcdG1peCggbWl4KCB0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIHV2ICsgdmVjMiggLWR4LCAtZHkgKSwgc2hhZG93Q29vcmQueiApLFxyXG5cdFx0XHRcdFx0XHQgIHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgdXYgKyB2ZWMyKCAyLjAgKiBkeCwgLWR5ICksIHNoYWRvd0Nvb3JkLnogKSxcclxuXHRcdFx0XHRcdFx0ICBmLnggKSxcclxuXHRcdFx0XHRcdCBtaXgoIHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgdXYgKyB2ZWMyKCAtZHgsIDIuMCAqIGR5ICksIHNoYWRvd0Nvb3JkLnogKSxcclxuXHRcdFx0XHRcdFx0ICB0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIHV2ICsgdmVjMiggMi4wICogZHgsIDIuMCAqIGR5ICksIHNoYWRvd0Nvb3JkLnogKSxcclxuXHRcdFx0XHRcdFx0ICBmLnggKSxcclxuXHRcdFx0XHRcdCBmLnkgKVxyXG5cdFx0XHQpICogKCAxLjAgLyA5LjAgKTtcclxuXHJcblx0XHQjZWxpZiBkZWZpbmVkKCBTSEFET1dNQVBfVFlQRV9WU00gKVxyXG5cclxuXHRcdFx0c2hhZG93ID0gVlNNU2hhZG93KCBzaGFkb3dNYXAsIHNoYWRvd0Nvb3JkLnh5LCBzaGFkb3dDb29yZC56ICk7XHJcblxyXG5cdFx0I2Vsc2UgLy8gbm8gcGVyY2VudGFnZS1jbG9zZXIgZmlsdGVyaW5nOlxyXG5cclxuXHRcdFx0c2hhZG93ID0gdGV4dHVyZTJEQ29tcGFyZSggc2hhZG93TWFwLCBzaGFkb3dDb29yZC54eSwgc2hhZG93Q29vcmQueiApO1xyXG5cclxuXHRcdCNlbmRpZlxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gc2hhZG93O1xyXG5cclxuXHR9XHJcblxyXG5cdC8vIGN1YmVUb1VWKCkgbWFwcyBhIDNEIGRpcmVjdGlvbiB2ZWN0b3Igc3VpdGFibGUgZm9yIGN1YmUgdGV4dHVyZSBtYXBwaW5nIHRvIGEgMkRcclxuXHQvLyB2ZWN0b3Igc3VpdGFibGUgZm9yIDJEIHRleHR1cmUgbWFwcGluZy4gVGhpcyBjb2RlIHVzZXMgdGhlIGZvbGxvd2luZyBsYXlvdXQgZm9yIHRoZVxyXG5cdC8vIDJEIHRleHR1cmU6XHJcblx0Ly9cclxuXHQvLyB4elhaXHJcblx0Ly8gIHkgWVxyXG5cdC8vXHJcblx0Ly8gWSAtIFBvc2l0aXZlIHkgZGlyZWN0aW9uXHJcblx0Ly8geSAtIE5lZ2F0aXZlIHkgZGlyZWN0aW9uXHJcblx0Ly8gWCAtIFBvc2l0aXZlIHggZGlyZWN0aW9uXHJcblx0Ly8geCAtIE5lZ2F0aXZlIHggZGlyZWN0aW9uXHJcblx0Ly8gWiAtIFBvc2l0aXZlIHogZGlyZWN0aW9uXHJcblx0Ly8geiAtIE5lZ2F0aXZlIHogZGlyZWN0aW9uXHJcblx0Ly9cclxuXHQvLyBTb3VyY2UgYW5kIHRlc3QgYmVkOlxyXG5cdC8vIGh0dHBzOi8vZ2lzdC5naXRodWIuY29tL3RzY2h3L2RhMTBjNDNjNDY3Y2U4YWZkMGM0XHJcblxyXG5cdHZlYzIgY3ViZVRvVVYoIHZlYzMgdiwgZmxvYXQgdGV4ZWxTaXplWSApIHtcclxuXHJcblx0XHQvLyBOdW1iZXIgb2YgdGV4ZWxzIHRvIGF2b2lkIGF0IHRoZSBlZGdlIG9mIGVhY2ggc3F1YXJlXHJcblxyXG5cdFx0dmVjMyBhYnNWID0gYWJzKCB2ICk7XHJcblxyXG5cdFx0Ly8gSW50ZXJzZWN0IHVuaXQgY3ViZVxyXG5cclxuXHRcdGZsb2F0IHNjYWxlVG9DdWJlID0gMS4wIC8gbWF4KCBhYnNWLngsIG1heCggYWJzVi55LCBhYnNWLnogKSApO1xyXG5cdFx0YWJzViAqPSBzY2FsZVRvQ3ViZTtcclxuXHJcblx0XHQvLyBBcHBseSBzY2FsZSB0byBhdm9pZCBzZWFtc1xyXG5cclxuXHRcdC8vIHR3byB0ZXhlbHMgbGVzcyBwZXIgc3F1YXJlIChvbmUgdGV4ZWwgd2lsbCBkbyBmb3IgTkVBUkVTVClcclxuXHRcdHYgKj0gc2NhbGVUb0N1YmUgKiAoIDEuMCAtIDIuMCAqIHRleGVsU2l6ZVkgKTtcclxuXHJcblx0XHQvLyBVbndyYXBcclxuXHJcblx0XHQvLyBzcGFjZTogLTEgLi4uIDEgcmFuZ2UgZm9yIGVhY2ggc3F1YXJlXHJcblx0XHQvL1xyXG5cdFx0Ly8gI1gjI1x0XHRkaW0gICAgOj0gKCA0ICwgMiApXHJcblx0XHQvLyAgIyAjXHRcdGNlbnRlciA6PSAoIDEgLCAxIClcclxuXHJcblx0XHR2ZWMyIHBsYW5hciA9IHYueHk7XHJcblxyXG5cdFx0ZmxvYXQgYWxtb3N0QVRleGVsID0gMS41ICogdGV4ZWxTaXplWTtcclxuXHRcdGZsb2F0IGFsbW9zdE9uZSA9IDEuMCAtIGFsbW9zdEFUZXhlbDtcclxuXHJcblx0XHRpZiAoIGFic1YueiA+PSBhbG1vc3RPbmUgKSB7XHJcblxyXG5cdFx0XHRpZiAoIHYueiA+IDAuMCApXHJcblx0XHRcdFx0cGxhbmFyLnggPSA0LjAgLSB2Lng7XHJcblxyXG5cdFx0fSBlbHNlIGlmICggYWJzVi54ID49IGFsbW9zdE9uZSApIHtcclxuXHJcblx0XHRcdGZsb2F0IHNpZ25YID0gc2lnbiggdi54ICk7XHJcblx0XHRcdHBsYW5hci54ID0gdi56ICogc2lnblggKyAyLjAgKiBzaWduWDtcclxuXHJcblx0XHR9IGVsc2UgaWYgKCBhYnNWLnkgPj0gYWxtb3N0T25lICkge1xyXG5cclxuXHRcdFx0ZmxvYXQgc2lnblkgPSBzaWduKCB2LnkgKTtcclxuXHRcdFx0cGxhbmFyLnggPSB2LnggKyAyLjAgKiBzaWduWSArIDIuMDtcclxuXHRcdFx0cGxhbmFyLnkgPSB2LnogKiBzaWduWSAtIDIuMDtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gVHJhbnNmb3JtIHRvIFVWIHNwYWNlXHJcblxyXG5cdFx0Ly8gc2NhbGUgOj0gMC41IC8gZGltXHJcblx0XHQvLyB0cmFuc2xhdGUgOj0gKCBjZW50ZXIgKyAwLjUgKSAvIGRpbVxyXG5cdFx0cmV0dXJuIHZlYzIoIDAuMTI1LCAwLjI1ICkgKiBwbGFuYXIgKyB2ZWMyKCAwLjM3NSwgMC43NSApO1xyXG5cclxuXHR9XHJcblxyXG5cdGZsb2F0IGdldFBvaW50U2hhZG93KCBzYW1wbGVyMkQgc2hhZG93TWFwLCB2ZWMyIHNoYWRvd01hcFNpemUsIGZsb2F0IHNoYWRvd0JpYXMsIGZsb2F0IHNoYWRvd1JhZGl1cywgdmVjNCBzaGFkb3dDb29yZCwgZmxvYXQgc2hhZG93Q2FtZXJhTmVhciwgZmxvYXQgc2hhZG93Q2FtZXJhRmFyICkge1xyXG5cclxuXHRcdHZlYzIgdGV4ZWxTaXplID0gdmVjMiggMS4wICkgLyAoIHNoYWRvd01hcFNpemUgKiB2ZWMyKCA0LjAsIDIuMCApICk7XHJcblxyXG5cdFx0Ly8gZm9yIHBvaW50IGxpZ2h0cywgdGhlIHVuaWZvcm0gQHZTaGFkb3dDb29yZCBpcyByZS1wdXJwb3NlZCB0byBob2xkXHJcblx0XHQvLyB0aGUgdmVjdG9yIGZyb20gdGhlIGxpZ2h0IHRvIHRoZSB3b3JsZC1zcGFjZSBwb3NpdGlvbiBvZiB0aGUgZnJhZ21lbnQuXHJcblx0XHR2ZWMzIGxpZ2h0VG9Qb3NpdGlvbiA9IHNoYWRvd0Nvb3JkLnh5ejtcclxuXHJcblx0XHQvLyBkcCA9IG5vcm1hbGl6ZWQgZGlzdGFuY2UgZnJvbSBsaWdodCB0byBmcmFnbWVudCBwb3NpdGlvblxyXG5cdFx0ZmxvYXQgZHAgPSAoIGxlbmd0aCggbGlnaHRUb1Bvc2l0aW9uICkgLSBzaGFkb3dDYW1lcmFOZWFyICkgLyAoIHNoYWRvd0NhbWVyYUZhciAtIHNoYWRvd0NhbWVyYU5lYXIgKTsgLy8gbmVlZCB0byBjbGFtcD9cclxuXHRcdGRwICs9IHNoYWRvd0JpYXM7XHJcblxyXG5cdFx0Ly8gYmQzRCA9IGJhc2UgZGlyZWN0aW9uIDNEXHJcblx0XHR2ZWMzIGJkM0QgPSBub3JtYWxpemUoIGxpZ2h0VG9Qb3NpdGlvbiApO1xyXG5cclxuXHRcdCNpZiBkZWZpbmVkKCBTSEFET1dNQVBfVFlQRV9QQ0YgKSB8fCBkZWZpbmVkKCBTSEFET1dNQVBfVFlQRV9QQ0ZfU09GVCApIHx8IGRlZmluZWQoIFNIQURPV01BUF9UWVBFX1ZTTSApXHJcblxyXG5cdFx0XHR2ZWMyIG9mZnNldCA9IHZlYzIoIC0gMSwgMSApICogc2hhZG93UmFkaXVzICogdGV4ZWxTaXplLnk7XHJcblxyXG5cdFx0XHRyZXR1cm4gKFxyXG5cdFx0XHRcdHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgY3ViZVRvVVYoIGJkM0QgKyBvZmZzZXQueHl5LCB0ZXhlbFNpemUueSApLCBkcCApICtcclxuXHRcdFx0XHR0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIGN1YmVUb1VWKCBiZDNEICsgb2Zmc2V0Lnl5eSwgdGV4ZWxTaXplLnkgKSwgZHAgKSArXHJcblx0XHRcdFx0dGV4dHVyZTJEQ29tcGFyZSggc2hhZG93TWFwLCBjdWJlVG9VViggYmQzRCArIG9mZnNldC54eXgsIHRleGVsU2l6ZS55ICksIGRwICkgK1xyXG5cdFx0XHRcdHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgY3ViZVRvVVYoIGJkM0QgKyBvZmZzZXQueXl4LCB0ZXhlbFNpemUueSApLCBkcCApICtcclxuXHRcdFx0XHR0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIGN1YmVUb1VWKCBiZDNELCB0ZXhlbFNpemUueSApLCBkcCApICtcclxuXHRcdFx0XHR0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIGN1YmVUb1VWKCBiZDNEICsgb2Zmc2V0Lnh4eSwgdGV4ZWxTaXplLnkgKSwgZHAgKSArXHJcblx0XHRcdFx0dGV4dHVyZTJEQ29tcGFyZSggc2hhZG93TWFwLCBjdWJlVG9VViggYmQzRCArIG9mZnNldC55eHksIHRleGVsU2l6ZS55ICksIGRwICkgK1xyXG5cdFx0XHRcdHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgY3ViZVRvVVYoIGJkM0QgKyBvZmZzZXQueHh4LCB0ZXhlbFNpemUueSApLCBkcCApICtcclxuXHRcdFx0XHR0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIGN1YmVUb1VWKCBiZDNEICsgb2Zmc2V0Lnl4eCwgdGV4ZWxTaXplLnkgKSwgZHAgKVxyXG5cdFx0XHQpICogKCAxLjAgLyA5LjAgKTtcclxuXHJcblx0XHQjZWxzZSAvLyBubyBwZXJjZW50YWdlLWNsb3NlciBmaWx0ZXJpbmdcclxuXHJcblx0XHRcdHJldHVybiB0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIGN1YmVUb1VWKCBiZDNELCB0ZXhlbFNpemUueSApLCBkcCApO1xyXG5cclxuXHRcdCNlbmRpZlxyXG5cclxuXHR9XHJcblxyXG4jZW5kaWZcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuXHJcbiNpZiBOVU1fU1BPVF9MSUdIVF9DT09SRFMgPiAwXHJcblxyXG5cdHVuaWZvcm0gbWF0NCBzcG90TGlnaHRNYXRyaXhbIE5VTV9TUE9UX0xJR0hUX0NPT1JEUyBdO1xyXG5cdHZhcnlpbmcgdmVjNCB2U3BvdExpZ2h0Q29vcmRbIE5VTV9TUE9UX0xJR0hUX0NPT1JEUyBdO1xyXG5cclxuI2VuZGlmXHJcblxyXG4jaWZkZWYgVVNFX1NIQURPV01BUFxyXG5cclxuXHQjaWYgTlVNX0RJUl9MSUdIVF9TSEFET1dTID4gMFxyXG5cclxuXHRcdHVuaWZvcm0gbWF0NCBkaXJlY3Rpb25hbFNoYWRvd01hdHJpeFsgTlVNX0RJUl9MSUdIVF9TSEFET1dTIF07XHJcblx0XHR2YXJ5aW5nIHZlYzQgdkRpcmVjdGlvbmFsU2hhZG93Q29vcmRbIE5VTV9ESVJfTElHSFRfU0hBRE9XUyBdO1xyXG5cclxuXHRcdHN0cnVjdCBEaXJlY3Rpb25hbExpZ2h0U2hhZG93IHtcclxuXHRcdFx0ZmxvYXQgc2hhZG93QmlhcztcclxuXHRcdFx0ZmxvYXQgc2hhZG93Tm9ybWFsQmlhcztcclxuXHRcdFx0ZmxvYXQgc2hhZG93UmFkaXVzO1xyXG5cdFx0XHR2ZWMyIHNoYWRvd01hcFNpemU7XHJcblx0XHR9O1xyXG5cclxuXHRcdHVuaWZvcm0gRGlyZWN0aW9uYWxMaWdodFNoYWRvdyBkaXJlY3Rpb25hbExpZ2h0U2hhZG93c1sgTlVNX0RJUl9MSUdIVF9TSEFET1dTIF07XHJcblxyXG5cdCNlbmRpZlxyXG5cclxuXHQjaWYgTlVNX1NQT1RfTElHSFRfU0hBRE9XUyA+IDBcclxuXHJcblx0XHRzdHJ1Y3QgU3BvdExpZ2h0U2hhZG93IHtcclxuXHRcdFx0ZmxvYXQgc2hhZG93QmlhcztcclxuXHRcdFx0ZmxvYXQgc2hhZG93Tm9ybWFsQmlhcztcclxuXHRcdFx0ZmxvYXQgc2hhZG93UmFkaXVzO1xyXG5cdFx0XHR2ZWMyIHNoYWRvd01hcFNpemU7XHJcblx0XHR9O1xyXG5cclxuXHRcdHVuaWZvcm0gU3BvdExpZ2h0U2hhZG93IHNwb3RMaWdodFNoYWRvd3NbIE5VTV9TUE9UX0xJR0hUX1NIQURPV1MgXTtcclxuXHJcblx0I2VuZGlmXHJcblxyXG5cdCNpZiBOVU1fUE9JTlRfTElHSFRfU0hBRE9XUyA+IDBcclxuXHJcblx0XHR1bmlmb3JtIG1hdDQgcG9pbnRTaGFkb3dNYXRyaXhbIE5VTV9QT0lOVF9MSUdIVF9TSEFET1dTIF07XHJcblx0XHR2YXJ5aW5nIHZlYzQgdlBvaW50U2hhZG93Q29vcmRbIE5VTV9QT0lOVF9MSUdIVF9TSEFET1dTIF07XHJcblxyXG5cdFx0c3RydWN0IFBvaW50TGlnaHRTaGFkb3cge1xyXG5cdFx0XHRmbG9hdCBzaGFkb3dCaWFzO1xyXG5cdFx0XHRmbG9hdCBzaGFkb3dOb3JtYWxCaWFzO1xyXG5cdFx0XHRmbG9hdCBzaGFkb3dSYWRpdXM7XHJcblx0XHRcdHZlYzIgc2hhZG93TWFwU2l6ZTtcclxuXHRcdFx0ZmxvYXQgc2hhZG93Q2FtZXJhTmVhcjtcclxuXHRcdFx0ZmxvYXQgc2hhZG93Q2FtZXJhRmFyO1xyXG5cdFx0fTtcclxuXHJcblx0XHR1bmlmb3JtIFBvaW50TGlnaHRTaGFkb3cgcG9pbnRMaWdodFNoYWRvd3NbIE5VTV9QT0lOVF9MSUdIVF9TSEFET1dTIF07XHJcblxyXG5cdCNlbmRpZlxyXG5cclxuXHQvKlxyXG5cdCNpZiBOVU1fUkVDVF9BUkVBX0xJR0hUUyA+IDBcclxuXHJcblx0XHQvLyBUT0RPIChhYmVsbmF0aW9uKTogdW5pZm9ybXMgZm9yIGFyZWEgbGlnaHQgc2hhZG93c1xyXG5cclxuXHQjZW5kaWZcclxuXHQqL1xyXG5cclxuI2VuZGlmXHJcbmA7XHJcbiIsImV4cG9ydCBkZWZhdWx0IC8qIGdsc2wgKi9gXHJcblxyXG4jaWYgKCBkZWZpbmVkKCBVU0VfU0hBRE9XTUFQICkgJiYgKCBOVU1fRElSX0xJR0hUX1NIQURPV1MgPiAwIHx8IE5VTV9QT0lOVF9MSUdIVF9TSEFET1dTID4gMCApICkgfHwgKCBOVU1fU1BPVF9MSUdIVF9DT09SRFMgPiAwIClcclxuXHJcblx0Ly8gT2Zmc2V0dGluZyB0aGUgcG9zaXRpb24gdXNlZCBmb3IgcXVlcnlpbmcgb2NjbHVzaW9uIGFsb25nIHRoZSB3b3JsZCBub3JtYWwgY2FuIGJlIHVzZWQgdG8gcmVkdWNlIHNoYWRvdyBhY25lLlxyXG5cdHZlYzMgc2hhZG93V29ybGROb3JtYWwgPSBpbnZlcnNlVHJhbnNmb3JtRGlyZWN0aW9uKCB0cmFuc2Zvcm1lZE5vcm1hbCwgdmlld01hdHJpeCApO1xyXG5cdHZlYzQgc2hhZG93V29ybGRQb3NpdGlvbjtcclxuXHJcbiNlbmRpZlxyXG5cclxuI2lmIGRlZmluZWQoIFVTRV9TSEFET1dNQVAgKVxyXG5cclxuXHQjaWYgTlVNX0RJUl9MSUdIVF9TSEFET1dTID4gMFxyXG5cclxuXHRcdCNwcmFnbWEgdW5yb2xsX2xvb3Bfc3RhcnRcclxuXHRcdGZvciAoIGludCBpID0gMDsgaSA8IE5VTV9ESVJfTElHSFRfU0hBRE9XUzsgaSArKyApIHtcclxuXHJcblx0XHRcdHNoYWRvd1dvcmxkUG9zaXRpb24gPSB3b3JsZFBvc2l0aW9uICsgdmVjNCggc2hhZG93V29ybGROb3JtYWwgKiBkaXJlY3Rpb25hbExpZ2h0U2hhZG93c1sgaSBdLnNoYWRvd05vcm1hbEJpYXMsIDAgKTtcclxuXHRcdFx0dkRpcmVjdGlvbmFsU2hhZG93Q29vcmRbIGkgXSA9IGRpcmVjdGlvbmFsU2hhZG93TWF0cml4WyBpIF0gKiBzaGFkb3dXb3JsZFBvc2l0aW9uO1xyXG5cclxuXHRcdH1cclxuXHRcdCNwcmFnbWEgdW5yb2xsX2xvb3BfZW5kXHJcblxyXG5cdCNlbmRpZlxyXG5cclxuXHQjaWYgTlVNX1BPSU5UX0xJR0hUX1NIQURPV1MgPiAwXHJcblxyXG5cdFx0I3ByYWdtYSB1bnJvbGxfbG9vcF9zdGFydFxyXG5cdFx0Zm9yICggaW50IGkgPSAwOyBpIDwgTlVNX1BPSU5UX0xJR0hUX1NIQURPV1M7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRzaGFkb3dXb3JsZFBvc2l0aW9uID0gd29ybGRQb3NpdGlvbiArIHZlYzQoIHNoYWRvd1dvcmxkTm9ybWFsICogcG9pbnRMaWdodFNoYWRvd3NbIGkgXS5zaGFkb3dOb3JtYWxCaWFzLCAwICk7XHJcblx0XHRcdHZQb2ludFNoYWRvd0Nvb3JkWyBpIF0gPSBwb2ludFNoYWRvd01hdHJpeFsgaSBdICogc2hhZG93V29ybGRQb3NpdGlvbjtcclxuXHJcblx0XHR9XHJcblx0XHQjcHJhZ21hIHVucm9sbF9sb29wX2VuZFxyXG5cclxuXHQjZW5kaWZcclxuXHJcblx0LypcclxuXHQjaWYgTlVNX1JFQ1RfQVJFQV9MSUdIVFMgPiAwXHJcblxyXG5cdFx0Ly8gVE9ETyAoYWJlbG5hdGlvbik6IHVwZGF0ZSB2QXJlYVNoYWRvd0Nvb3JkIHdpdGggYXJlYSBsaWdodCBpbmZvXHJcblxyXG5cdCNlbmRpZlxyXG5cdCovXHJcblxyXG4jZW5kaWZcclxuXHJcbi8vIHNwb3QgbGlnaHRzIGNhbiBiZSBldmFsdWF0ZWQgd2l0aG91dCBhY3RpdmUgc2hhZG93IG1hcHBpbmcgKHdoZW4gU3BvdExpZ2h0Lm1hcCBpcyB1c2VkKVxyXG5cclxuI2lmIE5VTV9TUE9UX0xJR0hUX0NPT1JEUyA+IDBcclxuXHJcblx0I3ByYWdtYSB1bnJvbGxfbG9vcF9zdGFydFxyXG5cdGZvciAoIGludCBpID0gMDsgaSA8IE5VTV9TUE9UX0xJR0hUX0NPT1JEUzsgaSArKyApIHtcclxuXHJcblx0XHRzaGFkb3dXb3JsZFBvc2l0aW9uID0gd29ybGRQb3NpdGlvbjtcclxuXHRcdCNpZiAoIGRlZmluZWQoIFVTRV9TSEFET1dNQVAgKSAmJiBVTlJPTExFRF9MT09QX0lOREVYIDwgTlVNX1NQT1RfTElHSFRfU0hBRE9XUyApXHJcblx0XHRcdHNoYWRvd1dvcmxkUG9zaXRpb24ueHl6ICs9IHNoYWRvd1dvcmxkTm9ybWFsICogc3BvdExpZ2h0U2hhZG93c1sgaSBdLnNoYWRvd05vcm1hbEJpYXM7XHJcblx0XHQjZW5kaWZcclxuXHRcdHZTcG90TGlnaHRDb29yZFsgaSBdID0gc3BvdExpZ2h0TWF0cml4WyBpIF0gKiBzaGFkb3dXb3JsZFBvc2l0aW9uO1xyXG5cclxuXHR9XHJcblx0I3ByYWdtYSB1bnJvbGxfbG9vcF9lbmRcclxuXHJcbiNlbmRpZlxyXG5cclxuXHJcbmA7XHJcbiIsImV4cG9ydCBkZWZhdWx0IC8qIGdsc2wgKi9gXHJcbmZsb2F0IGdldFNoYWRvd01hc2soKSB7XHJcblxyXG5cdGZsb2F0IHNoYWRvdyA9IDEuMDtcclxuXHJcblx0I2lmZGVmIFVTRV9TSEFET1dNQVBcclxuXHJcblx0I2lmIE5VTV9ESVJfTElHSFRfU0hBRE9XUyA+IDBcclxuXHJcblx0RGlyZWN0aW9uYWxMaWdodFNoYWRvdyBkaXJlY3Rpb25hbExpZ2h0O1xyXG5cclxuXHQjcHJhZ21hIHVucm9sbF9sb29wX3N0YXJ0XHJcblx0Zm9yICggaW50IGkgPSAwOyBpIDwgTlVNX0RJUl9MSUdIVF9TSEFET1dTOyBpICsrICkge1xyXG5cclxuXHRcdGRpcmVjdGlvbmFsTGlnaHQgPSBkaXJlY3Rpb25hbExpZ2h0U2hhZG93c1sgaSBdO1xyXG5cdFx0c2hhZG93ICo9IHJlY2VpdmVTaGFkb3cgPyBnZXRTaGFkb3coIGRpcmVjdGlvbmFsU2hhZG93TWFwWyBpIF0sIGRpcmVjdGlvbmFsTGlnaHQuc2hhZG93TWFwU2l6ZSwgZGlyZWN0aW9uYWxMaWdodC5zaGFkb3dCaWFzLCBkaXJlY3Rpb25hbExpZ2h0LnNoYWRvd1JhZGl1cywgdkRpcmVjdGlvbmFsU2hhZG93Q29vcmRbIGkgXSApIDogMS4wO1xyXG5cclxuXHR9XHJcblx0I3ByYWdtYSB1bnJvbGxfbG9vcF9lbmRcclxuXHJcblx0I2VuZGlmXHJcblxyXG5cdCNpZiBOVU1fU1BPVF9MSUdIVF9TSEFET1dTID4gMFxyXG5cclxuXHRTcG90TGlnaHRTaGFkb3cgc3BvdExpZ2h0O1xyXG5cclxuXHQjcHJhZ21hIHVucm9sbF9sb29wX3N0YXJ0XHJcblx0Zm9yICggaW50IGkgPSAwOyBpIDwgTlVNX1NQT1RfTElHSFRfU0hBRE9XUzsgaSArKyApIHtcclxuXHJcblx0XHRzcG90TGlnaHQgPSBzcG90TGlnaHRTaGFkb3dzWyBpIF07XHJcblx0XHRzaGFkb3cgKj0gcmVjZWl2ZVNoYWRvdyA/IGdldFNoYWRvdyggc3BvdFNoYWRvd01hcFsgaSBdLCBzcG90TGlnaHQuc2hhZG93TWFwU2l6ZSwgc3BvdExpZ2h0LnNoYWRvd0JpYXMsIHNwb3RMaWdodC5zaGFkb3dSYWRpdXMsIHZTcG90TGlnaHRDb29yZFsgaSBdICkgOiAxLjA7XHJcblxyXG5cdH1cclxuXHQjcHJhZ21hIHVucm9sbF9sb29wX2VuZFxyXG5cclxuXHQjZW5kaWZcclxuXHJcblx0I2lmIE5VTV9QT0lOVF9MSUdIVF9TSEFET1dTID4gMFxyXG5cclxuXHRQb2ludExpZ2h0U2hhZG93IHBvaW50TGlnaHQ7XHJcblxyXG5cdCNwcmFnbWEgdW5yb2xsX2xvb3Bfc3RhcnRcclxuXHRmb3IgKCBpbnQgaSA9IDA7IGkgPCBOVU1fUE9JTlRfTElHSFRfU0hBRE9XUzsgaSArKyApIHtcclxuXHJcblx0XHRwb2ludExpZ2h0ID0gcG9pbnRMaWdodFNoYWRvd3NbIGkgXTtcclxuXHRcdHNoYWRvdyAqPSByZWNlaXZlU2hhZG93ID8gZ2V0UG9pbnRTaGFkb3coIHBvaW50U2hhZG93TWFwWyBpIF0sIHBvaW50TGlnaHQuc2hhZG93TWFwU2l6ZSwgcG9pbnRMaWdodC5zaGFkb3dCaWFzLCBwb2ludExpZ2h0LnNoYWRvd1JhZGl1cywgdlBvaW50U2hhZG93Q29vcmRbIGkgXSwgcG9pbnRMaWdodC5zaGFkb3dDYW1lcmFOZWFyLCBwb2ludExpZ2h0LnNoYWRvd0NhbWVyYUZhciApIDogMS4wO1xyXG5cclxuXHR9XHJcblx0I3ByYWdtYSB1bnJvbGxfbG9vcF9lbmRcclxuXHJcblx0I2VuZGlmXHJcblxyXG5cdC8qXHJcblx0I2lmIE5VTV9SRUNUX0FSRUFfTElHSFRTID4gMFxyXG5cclxuXHRcdC8vIFRPRE8gKGFiZWxuYXRpb24pOiB1cGRhdGUgc2hhZG93IGZvciBBcmVhIGxpZ2h0XHJcblxyXG5cdCNlbmRpZlxyXG5cdCovXHJcblxyXG5cdCNlbmRpZlxyXG5cclxuXHRyZXR1cm4gc2hhZG93O1xyXG5cclxufVxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWZkZWYgVVNFX1NLSU5OSU5HXHJcblxyXG5cdG1hdDQgYm9uZU1hdFggPSBnZXRCb25lTWF0cml4KCBza2luSW5kZXgueCApO1xyXG5cdG1hdDQgYm9uZU1hdFkgPSBnZXRCb25lTWF0cml4KCBza2luSW5kZXgueSApO1xyXG5cdG1hdDQgYm9uZU1hdFogPSBnZXRCb25lTWF0cml4KCBza2luSW5kZXgueiApO1xyXG5cdG1hdDQgYm9uZU1hdFcgPSBnZXRCb25lTWF0cml4KCBza2luSW5kZXgudyApO1xyXG5cclxuI2VuZGlmXHJcbmA7XHJcbiIsImV4cG9ydCBkZWZhdWx0IC8qIGdsc2wgKi9gXHJcbiNpZmRlZiBVU0VfU0tJTk5JTkdcclxuXHJcblx0dW5pZm9ybSBtYXQ0IGJpbmRNYXRyaXg7XHJcblx0dW5pZm9ybSBtYXQ0IGJpbmRNYXRyaXhJbnZlcnNlO1xyXG5cclxuXHR1bmlmb3JtIGhpZ2hwIHNhbXBsZXIyRCBib25lVGV4dHVyZTtcclxuXHJcblx0bWF0NCBnZXRCb25lTWF0cml4KCBjb25zdCBpbiBmbG9hdCBpICkge1xyXG5cclxuXHRcdGludCBzaXplID0gdGV4dHVyZVNpemUoIGJvbmVUZXh0dXJlLCAwICkueDtcclxuXHRcdGludCBqID0gaW50KCBpICkgKiA0O1xyXG5cdFx0aW50IHggPSBqICUgc2l6ZTtcclxuXHRcdGludCB5ID0gaiAvIHNpemU7XHJcblx0XHR2ZWM0IHYxID0gdGV4ZWxGZXRjaCggYm9uZVRleHR1cmUsIGl2ZWMyKCB4LCB5ICksIDAgKTtcclxuXHRcdHZlYzQgdjIgPSB0ZXhlbEZldGNoKCBib25lVGV4dHVyZSwgaXZlYzIoIHggKyAxLCB5ICksIDAgKTtcclxuXHRcdHZlYzQgdjMgPSB0ZXhlbEZldGNoKCBib25lVGV4dHVyZSwgaXZlYzIoIHggKyAyLCB5ICksIDAgKTtcclxuXHRcdHZlYzQgdjQgPSB0ZXhlbEZldGNoKCBib25lVGV4dHVyZSwgaXZlYzIoIHggKyAzLCB5ICksIDAgKTtcclxuXHJcblx0XHRyZXR1cm4gbWF0NCggdjEsIHYyLCB2MywgdjQgKTtcclxuXHJcblx0fVxyXG5cclxuI2VuZGlmXHJcbmA7XHJcbiIsImV4cG9ydCBkZWZhdWx0IC8qIGdsc2wgKi9gXHJcbiNpZmRlZiBVU0VfU0tJTk5JTkdcclxuXHJcblx0dmVjNCBza2luVmVydGV4ID0gYmluZE1hdHJpeCAqIHZlYzQoIHRyYW5zZm9ybWVkLCAxLjAgKTtcclxuXHJcblx0dmVjNCBza2lubmVkID0gdmVjNCggMC4wICk7XHJcblx0c2tpbm5lZCArPSBib25lTWF0WCAqIHNraW5WZXJ0ZXggKiBza2luV2VpZ2h0Lng7XHJcblx0c2tpbm5lZCArPSBib25lTWF0WSAqIHNraW5WZXJ0ZXggKiBza2luV2VpZ2h0Lnk7XHJcblx0c2tpbm5lZCArPSBib25lTWF0WiAqIHNraW5WZXJ0ZXggKiBza2luV2VpZ2h0Lno7XHJcblx0c2tpbm5lZCArPSBib25lTWF0VyAqIHNraW5WZXJ0ZXggKiBza2luV2VpZ2h0Lnc7XHJcblxyXG5cdHRyYW5zZm9ybWVkID0gKCBiaW5kTWF0cml4SW52ZXJzZSAqIHNraW5uZWQgKS54eXo7XHJcblxyXG4jZW5kaWZcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuI2lmZGVmIFVTRV9TS0lOTklOR1xyXG5cclxuXHRtYXQ0IHNraW5NYXRyaXggPSBtYXQ0KCAwLjAgKTtcclxuXHRza2luTWF0cml4ICs9IHNraW5XZWlnaHQueCAqIGJvbmVNYXRYO1xyXG5cdHNraW5NYXRyaXggKz0gc2tpbldlaWdodC55ICogYm9uZU1hdFk7XHJcblx0c2tpbk1hdHJpeCArPSBza2luV2VpZ2h0LnogKiBib25lTWF0WjtcclxuXHRza2luTWF0cml4ICs9IHNraW5XZWlnaHQudyAqIGJvbmVNYXRXO1xyXG5cdHNraW5NYXRyaXggPSBiaW5kTWF0cml4SW52ZXJzZSAqIHNraW5NYXRyaXggKiBiaW5kTWF0cml4O1xyXG5cclxuXHRvYmplY3ROb3JtYWwgPSB2ZWM0KCBza2luTWF0cml4ICogdmVjNCggb2JqZWN0Tm9ybWFsLCAwLjAgKSApLnh5ejtcclxuXHJcblx0I2lmZGVmIFVTRV9UQU5HRU5UXHJcblxyXG5cdFx0b2JqZWN0VGFuZ2VudCA9IHZlYzQoIHNraW5NYXRyaXggKiB2ZWM0KCBvYmplY3RUYW5nZW50LCAwLjAgKSApLnh5ejtcclxuXHJcblx0I2VuZGlmXHJcblxyXG4jZW5kaWZcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuZmxvYXQgc3BlY3VsYXJTdHJlbmd0aDtcclxuXHJcbiNpZmRlZiBVU0VfU1BFQ1VMQVJNQVBcclxuXHJcblx0dmVjNCB0ZXhlbFNwZWN1bGFyID0gdGV4dHVyZTJEKCBzcGVjdWxhck1hcCwgdlNwZWN1bGFyTWFwVXYgKTtcclxuXHRzcGVjdWxhclN0cmVuZ3RoID0gdGV4ZWxTcGVjdWxhci5yO1xyXG5cclxuI2Vsc2VcclxuXHJcblx0c3BlY3VsYXJTdHJlbmd0aCA9IDEuMDtcclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWZkZWYgVVNFX1NQRUNVTEFSTUFQXHJcblxyXG5cdHVuaWZvcm0gc2FtcGxlcjJEIHNwZWN1bGFyTWFwO1xyXG5cclxuI2VuZGlmXHJcbmA7XHJcbiIsImV4cG9ydCBkZWZhdWx0IC8qIGdsc2wgKi9gXHJcbiNpZiBkZWZpbmVkKCBUT05FX01BUFBJTkcgKVxyXG5cclxuXHRnbF9GcmFnQ29sb3IucmdiID0gdG9uZU1hcHBpbmcoIGdsX0ZyYWdDb2xvci5yZ2IgKTtcclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWZuZGVmIHNhdHVyYXRlXHJcbi8vIDxjb21tb24+IG1heSBoYXZlIGRlZmluZWQgc2F0dXJhdGUoKSBhbHJlYWR5XHJcbiNkZWZpbmUgc2F0dXJhdGUoIGEgKSBjbGFtcCggYSwgMC4wLCAxLjAgKVxyXG4jZW5kaWZcclxuXHJcbnVuaWZvcm0gZmxvYXQgdG9uZU1hcHBpbmdFeHBvc3VyZTtcclxuXHJcbi8vIGV4cG9zdXJlIG9ubHlcclxudmVjMyBMaW5lYXJUb25lTWFwcGluZyggdmVjMyBjb2xvciApIHtcclxuXHJcblx0cmV0dXJuIHNhdHVyYXRlKCB0b25lTWFwcGluZ0V4cG9zdXJlICogY29sb3IgKTtcclxuXHJcbn1cclxuXHJcbi8vIHNvdXJjZTogaHR0cHM6Ly93d3cuY3MudXRhaC5lZHUvZG9jcy90ZWNocmVwb3J0cy8yMDAyL3BkZi9VVUNTLTAyLTAwMS5wZGZcclxudmVjMyBSZWluaGFyZFRvbmVNYXBwaW5nKCB2ZWMzIGNvbG9yICkge1xyXG5cclxuXHRjb2xvciAqPSB0b25lTWFwcGluZ0V4cG9zdXJlO1xyXG5cdHJldHVybiBzYXR1cmF0ZSggY29sb3IgLyAoIHZlYzMoIDEuMCApICsgY29sb3IgKSApO1xyXG5cclxufVxyXG5cclxuLy8gc291cmNlOiBodHRwOi8vZmlsbWljd29ybGRzLmNvbS9ibG9nL2ZpbG1pYy10b25lbWFwcGluZy1vcGVyYXRvcnMvXHJcbnZlYzMgT3B0aW1pemVkQ2luZW9uVG9uZU1hcHBpbmcoIHZlYzMgY29sb3IgKSB7XHJcblxyXG5cdC8vIG9wdGltaXplZCBmaWxtaWMgb3BlcmF0b3IgYnkgSmltIEhlamwgYW5kIFJpY2hhcmQgQnVyZ2Vzcy1EYXdzb25cclxuXHRjb2xvciAqPSB0b25lTWFwcGluZ0V4cG9zdXJlO1xyXG5cdGNvbG9yID0gbWF4KCB2ZWMzKCAwLjAgKSwgY29sb3IgLSAwLjAwNCApO1xyXG5cdHJldHVybiBwb3coICggY29sb3IgKiAoIDYuMiAqIGNvbG9yICsgMC41ICkgKSAvICggY29sb3IgKiAoIDYuMiAqIGNvbG9yICsgMS43ICkgKyAwLjA2ICksIHZlYzMoIDIuMiApICk7XHJcblxyXG59XHJcblxyXG4vLyBzb3VyY2U6IGh0dHBzOi8vZ2l0aHViLmNvbS9zZWxmc2hhZG93L2x0Y19jb2RlL2Jsb2IvbWFzdGVyL3dlYmdsL3NoYWRlcnMvbHRjL2x0Y19ibGl0LmZzXHJcbnZlYzMgUlJUQW5kT0RURml0KCB2ZWMzIHYgKSB7XHJcblxyXG5cdHZlYzMgYSA9IHYgKiAoIHYgKyAwLjAyNDU3ODYgKSAtIDAuMDAwMDkwNTM3O1xyXG5cdHZlYzMgYiA9IHYgKiAoIDAuOTgzNzI5ICogdiArIDAuNDMyOTUxMCApICsgMC4yMzgwODE7XHJcblx0cmV0dXJuIGEgLyBiO1xyXG5cclxufVxyXG5cclxuLy8gdGhpcyBpbXBsZW1lbnRhdGlvbiBvZiBBQ0VTIGlzIG1vZGlmaWVkIHRvIGFjY29tbW9kYXRlIGEgYnJpZ2h0ZXIgdmlld2luZyBlbnZpcm9ubWVudC5cclxuLy8gdGhlIHNjYWxlIGZhY3RvciBvZiAxLzAuNiBpcyBzdWJqZWN0aXZlLiBzZWUgZGlzY3Vzc2lvbiBpbiAjMTk2MjEuXHJcblxyXG52ZWMzIEFDRVNGaWxtaWNUb25lTWFwcGluZyggdmVjMyBjb2xvciApIHtcclxuXHJcblx0Ly8gc1JHQiA9PiBYWVogPT4gRDY1XzJfRDYwID0+IEFQMSA9PiBSUlRfU0FUXHJcblx0Y29uc3QgbWF0MyBBQ0VTSW5wdXRNYXQgPSBtYXQzKFxyXG5cdFx0dmVjMyggMC41OTcxOSwgMC4wNzYwMCwgMC4wMjg0MCApLCAvLyB0cmFuc3Bvc2VkIGZyb20gc291cmNlXHJcblx0XHR2ZWMzKCAwLjM1NDU4LCAwLjkwODM0LCAwLjEzMzgzICksXHJcblx0XHR2ZWMzKCAwLjA0ODIzLCAwLjAxNTY2LCAwLjgzNzc3IClcclxuXHQpO1xyXG5cclxuXHQvLyBPRFRfU0FUID0+IFhZWiA9PiBENjBfMl9ENjUgPT4gc1JHQlxyXG5cdGNvbnN0IG1hdDMgQUNFU091dHB1dE1hdCA9IG1hdDMoXHJcblx0XHR2ZWMzKCAgMS42MDQ3NSwgLTAuMTAyMDgsIC0wLjAwMzI3ICksIC8vIHRyYW5zcG9zZWQgZnJvbSBzb3VyY2VcclxuXHRcdHZlYzMoIC0wLjUzMTA4LCAgMS4xMDgxMywgLTAuMDcyNzYgKSxcclxuXHRcdHZlYzMoIC0wLjA3MzY3LCAtMC4wMDYwNSwgIDEuMDc2MDIgKVxyXG5cdCk7XHJcblxyXG5cdGNvbG9yICo9IHRvbmVNYXBwaW5nRXhwb3N1cmUgLyAwLjY7XHJcblxyXG5cdGNvbG9yID0gQUNFU0lucHV0TWF0ICogY29sb3I7XHJcblxyXG5cdC8vIEFwcGx5IFJSVCBhbmQgT0RUXHJcblx0Y29sb3IgPSBSUlRBbmRPRFRGaXQoIGNvbG9yICk7XHJcblxyXG5cdGNvbG9yID0gQUNFU091dHB1dE1hdCAqIGNvbG9yO1xyXG5cclxuXHQvLyBDbGFtcCB0byBbMCwgMV1cclxuXHRyZXR1cm4gc2F0dXJhdGUoIGNvbG9yICk7XHJcblxyXG59XHJcblxyXG4vLyBNYXRyaWNlcyBmb3IgcmVjIDIwMjAgPD4gcmVjIDcwOSBjb2xvciBzcGFjZSBjb252ZXJzaW9uXHJcbi8vIG1hdHJpeCBwcm92aWRlZCBpbiByb3ctbWFqb3Igb3JkZXIgc28gaXQgaGFzIGJlZW4gdHJhbnNwb3NlZFxyXG4vLyBodHRwczovL3d3dy5pdHUuaW50L3B1Yi9SLVJFUC1CVC4yNDA3LTIwMTdcclxuY29uc3QgbWF0MyBMSU5FQVJfUkVDMjAyMF9UT19MSU5FQVJfU1JHQiA9IG1hdDMoXHJcblx0dmVjMyggMS42NjA1LCAtIDAuMTI0NiwgLSAwLjAxODIgKSxcclxuXHR2ZWMzKCAtIDAuNTg3NiwgMS4xMzI5LCAtIDAuMTAwNiApLFxyXG5cdHZlYzMoIC0gMC4wNzI4LCAtIDAuMDA4MywgMS4xMTg3IClcclxuKTtcclxuXHJcbmNvbnN0IG1hdDMgTElORUFSX1NSR0JfVE9fTElORUFSX1JFQzIwMjAgPSBtYXQzKFxyXG5cdHZlYzMoIDAuNjI3NCwgMC4wNjkxLCAwLjAxNjQgKSxcclxuXHR2ZWMzKCAwLjMyOTMsIDAuOTE5NSwgMC4wODgwICksXHJcblx0dmVjMyggMC4wNDMzLCAwLjAxMTMsIDAuODk1NiApXHJcbik7XHJcblxyXG4vLyBodHRwczovL2lvbGl0ZS1lbmdpbmUuY29tL2Jsb2dfcG9zdHMvbWluaW1hbF9hZ3hfaW1wbGVtZW50YXRpb25cclxuLy8gTWVhbiBlcnJvcl4yOiAzLjY3MDUxNDFlLTA2XHJcbnZlYzMgYWd4RGVmYXVsdENvbnRyYXN0QXBwcm94KCB2ZWMzIHggKSB7XHJcblxyXG5cdHZlYzMgeDIgPSB4ICogeDtcclxuXHR2ZWMzIHg0ID0geDIgKiB4MjtcclxuXHJcblx0cmV0dXJuICsgMTUuNSAqIHg0ICogeDJcclxuXHRcdC0gNDAuMTQgKiB4NCAqIHhcclxuXHRcdCsgMzEuOTYgKiB4NFxyXG5cdFx0LSA2Ljg2OCAqIHgyICogeFxyXG5cdFx0KyAwLjQyOTggKiB4MlxyXG5cdFx0KyAwLjExOTEgKiB4XHJcblx0XHQtIDAuMDAyMzI7XHJcblxyXG59XHJcblxyXG4vLyBBZ1ggVG9uZSBNYXBwaW5nIGltcGxlbWVudGF0aW9uIGJhc2VkIG9uIEZpbGFtZW50LCB3aGljaCBpbiB0dXJuIGlzIGJhc2VkXHJcbi8vIG9uIEJsZW5kZXIncyBpbXBsZW1lbnRhdGlvbiB1c2luZyByZWMgMjAyMCBwcmltYXJpZXNcclxuLy8gaHR0cHM6Ly9naXRodWIuY29tL2dvb2dsZS9maWxhbWVudC9wdWxsLzcyMzZcclxuLy8gSW5wdXRzIGFuZCBvdXRwdXRzIGFyZSBlbmNvZGVkIGFzIExpbmVhci1zUkdCLlxyXG5cclxudmVjMyBBZ1hUb25lTWFwcGluZyggdmVjMyBjb2xvciApIHtcclxuXHJcblx0Ly8gQWdYIGNvbnN0YW50c1xyXG5cdGNvbnN0IG1hdDMgQWdYSW5zZXRNYXRyaXggPSBtYXQzKFxyXG5cdFx0dmVjMyggMC44NTY2MjcxNTMzMTU5ODMsIDAuMTM3MzE4OTcyOTI5ODQ3LCAwLjExMTg5ODIxMjk5OTk1ICksXHJcblx0XHR2ZWMzKCAwLjA5NTEyMTI0MDUzODE1ODgsIDAuNzYxMjQxOTkwNjAyNTkxLCAwLjA3Njc5OTQxODYwMzE5MDMgKSxcclxuXHRcdHZlYzMoIDAuMDQ4MjUxNjA2MTQ1ODU4MywgMC4xMDE0MzkwMzY0Njc1NjIsIDAuODExMzAyMzY4Mzk2ODU5IClcclxuXHQpO1xyXG5cclxuXHQvLyBleHBsaWNpdCBBZ1hPdXRzZXRNYXRyaXggZ2VuZXJhdGVkIGZyb20gRmlsYW1lbnRzIEFnWE91dHNldE1hdHJpeEludlxyXG5cdGNvbnN0IG1hdDMgQWdYT3V0c2V0TWF0cml4ID0gbWF0MyhcclxuXHRcdHZlYzMoIDEuMTI3MTAwNTgxODE0NDM2OCwgLSAwLjE0MTMyOTc2MzQ5ODQzODMsIC0gMC4xNDEzMjk3NjM0OTg0MzgyNiApLFxyXG5cdFx0dmVjMyggLSAwLjExMDYwNjY0MzA5NjYwMzIzLCAxLjE1NzgyMzcwMjIxNjI3MiwgLSAwLjExMDYwNjY0MzA5NjYwMjk0ICksXHJcblx0XHR2ZWMzKCAtIDAuMDE2NDkzOTM4NzE3ODM0NTczLCAtIDAuMDE2NDkzOTM4NzE3ODM0MjU3LCAxLjI1MTkzNjQwNjU5NTA0MDUgKVxyXG5cdCk7XHJcblxyXG5cdC8vIExPRzJfTUlOICAgICAgPSAtMTAuMFxyXG5cdC8vIExPRzJfTUFYICAgICAgPSAgKzYuNVxyXG5cdC8vIE1JRERMRV9HUkFZICAgPSAgMC4xOFxyXG5cdGNvbnN0IGZsb2F0IEFneE1pbkV2ID0gLSAxMi40NzM5MzsgIC8vIGxvZzIoIHBvdyggMiwgTE9HMl9NSU4gKSAqIE1JRERMRV9HUkFZIClcclxuXHRjb25zdCBmbG9hdCBBZ3hNYXhFdiA9IDQuMDI2MDY5OyAgICAvLyBsb2cyKCBwb3coIDIsIExPRzJfTUFYICkgKiBNSURETEVfR1JBWSApXHJcblxyXG5cdGNvbG9yICo9IHRvbmVNYXBwaW5nRXhwb3N1cmU7XHJcblxyXG5cdGNvbG9yID0gTElORUFSX1NSR0JfVE9fTElORUFSX1JFQzIwMjAgKiBjb2xvcjtcclxuXHJcblx0Y29sb3IgPSBBZ1hJbnNldE1hdHJpeCAqIGNvbG9yO1xyXG5cclxuXHQvLyBMb2cyIGVuY29kaW5nXHJcblx0Y29sb3IgPSBtYXgoIGNvbG9yLCAxZS0xMCApOyAvLyBhdm9pZCAwIG9yIG5lZ2F0aXZlIG51bWJlcnMgZm9yIGxvZzJcclxuXHRjb2xvciA9IGxvZzIoIGNvbG9yICk7XHJcblx0Y29sb3IgPSAoIGNvbG9yIC0gQWd4TWluRXYgKSAvICggQWd4TWF4RXYgLSBBZ3hNaW5FdiApO1xyXG5cclxuXHRjb2xvciA9IGNsYW1wKCBjb2xvciwgMC4wLCAxLjAgKTtcclxuXHJcblx0Ly8gQXBwbHkgc2lnbW9pZFxyXG5cdGNvbG9yID0gYWd4RGVmYXVsdENvbnRyYXN0QXBwcm94KCBjb2xvciApO1xyXG5cclxuXHQvLyBBcHBseSBBZ1ggbG9va1xyXG5cdC8vIHYgPSBhZ3hMb29rKHYsIGxvb2spO1xyXG5cclxuXHRjb2xvciA9IEFnWE91dHNldE1hdHJpeCAqIGNvbG9yO1xyXG5cclxuXHQvLyBMaW5lYXJpemVcclxuXHRjb2xvciA9IHBvdyggbWF4KCB2ZWMzKCAwLjAgKSwgY29sb3IgKSwgdmVjMyggMi4yICkgKTtcclxuXHJcblx0Y29sb3IgPSBMSU5FQVJfUkVDMjAyMF9UT19MSU5FQVJfU1JHQiAqIGNvbG9yO1xyXG5cclxuXHQvLyBHYW11dCBtYXBwaW5nLiBTaW1wbGUgY2xhbXAgZm9yIG5vdy5cclxuXHRjb2xvciA9IGNsYW1wKCBjb2xvciwgMC4wLCAxLjAgKTtcclxuXHJcblx0cmV0dXJuIGNvbG9yO1xyXG5cclxufVxyXG5cclxudmVjMyBDdXN0b21Ub25lTWFwcGluZyggdmVjMyBjb2xvciApIHsgcmV0dXJuIGNvbG9yOyB9XHJcbmA7XHJcbiIsImV4cG9ydCBkZWZhdWx0IC8qIGdsc2wgKi9gXHJcbiNpZmRlZiBVU0VfVFJBTlNNSVNTSU9OXHJcblxyXG5cdG1hdGVyaWFsLnRyYW5zbWlzc2lvbiA9IHRyYW5zbWlzc2lvbjtcclxuXHRtYXRlcmlhbC50cmFuc21pc3Npb25BbHBoYSA9IDEuMDtcclxuXHRtYXRlcmlhbC50aGlja25lc3MgPSB0aGlja25lc3M7XHJcblx0bWF0ZXJpYWwuYXR0ZW51YXRpb25EaXN0YW5jZSA9IGF0dGVudWF0aW9uRGlzdGFuY2U7XHJcblx0bWF0ZXJpYWwuYXR0ZW51YXRpb25Db2xvciA9IGF0dGVudWF0aW9uQ29sb3I7XHJcblxyXG5cdCNpZmRlZiBVU0VfVFJBTlNNSVNTSU9OTUFQXHJcblxyXG5cdFx0bWF0ZXJpYWwudHJhbnNtaXNzaW9uICo9IHRleHR1cmUyRCggdHJhbnNtaXNzaW9uTWFwLCB2VHJhbnNtaXNzaW9uTWFwVXYgKS5yO1xyXG5cclxuXHQjZW5kaWZcclxuXHJcblx0I2lmZGVmIFVTRV9USElDS05FU1NNQVBcclxuXHJcblx0XHRtYXRlcmlhbC50aGlja25lc3MgKj0gdGV4dHVyZTJEKCB0aGlja25lc3NNYXAsIHZUaGlja25lc3NNYXBVdiApLmc7XHJcblxyXG5cdCNlbmRpZlxyXG5cclxuXHR2ZWMzIHBvcyA9IHZXb3JsZFBvc2l0aW9uO1xyXG5cdHZlYzMgdiA9IG5vcm1hbGl6ZSggY2FtZXJhUG9zaXRpb24gLSBwb3MgKTtcclxuXHR2ZWMzIG4gPSBpbnZlcnNlVHJhbnNmb3JtRGlyZWN0aW9uKCBub3JtYWwsIHZpZXdNYXRyaXggKTtcclxuXHJcblx0dmVjNCB0cmFuc21pdHRlZCA9IGdldElCTFZvbHVtZVJlZnJhY3Rpb24oXHJcblx0XHRuLCB2LCBtYXRlcmlhbC5yb3VnaG5lc3MsIG1hdGVyaWFsLmRpZmZ1c2VDb2xvciwgbWF0ZXJpYWwuc3BlY3VsYXJDb2xvciwgbWF0ZXJpYWwuc3BlY3VsYXJGOTAsXHJcblx0XHRwb3MsIG1vZGVsTWF0cml4LCB2aWV3TWF0cml4LCBwcm9qZWN0aW9uTWF0cml4LCBtYXRlcmlhbC5pb3IsIG1hdGVyaWFsLnRoaWNrbmVzcyxcclxuXHRcdG1hdGVyaWFsLmF0dGVudWF0aW9uQ29sb3IsIG1hdGVyaWFsLmF0dGVudWF0aW9uRGlzdGFuY2UgKTtcclxuXHJcblx0bWF0ZXJpYWwudHJhbnNtaXNzaW9uQWxwaGEgPSBtaXgoIG1hdGVyaWFsLnRyYW5zbWlzc2lvbkFscGhhLCB0cmFuc21pdHRlZC5hLCBtYXRlcmlhbC50cmFuc21pc3Npb24gKTtcclxuXHJcblx0dG90YWxEaWZmdXNlID0gbWl4KCB0b3RhbERpZmZ1c2UsIHRyYW5zbWl0dGVkLnJnYiwgbWF0ZXJpYWwudHJhbnNtaXNzaW9uICk7XHJcblxyXG4jZW5kaWZcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuI2lmZGVmIFVTRV9UUkFOU01JU1NJT05cclxuXHJcblx0Ly8gVHJhbnNtaXNzaW9uIGNvZGUgaXMgYmFzZWQgb24gZ2xURi1TYW1wbGVyLVZpZXdlclxyXG5cdC8vIGh0dHBzOi8vZ2l0aHViLmNvbS9LaHJvbm9zR3JvdXAvZ2xURi1TYW1wbGUtVmlld2VyXHJcblxyXG5cdHVuaWZvcm0gZmxvYXQgdHJhbnNtaXNzaW9uO1xyXG5cdHVuaWZvcm0gZmxvYXQgdGhpY2tuZXNzO1xyXG5cdHVuaWZvcm0gZmxvYXQgYXR0ZW51YXRpb25EaXN0YW5jZTtcclxuXHR1bmlmb3JtIHZlYzMgYXR0ZW51YXRpb25Db2xvcjtcclxuXHJcblx0I2lmZGVmIFVTRV9UUkFOU01JU1NJT05NQVBcclxuXHJcblx0XHR1bmlmb3JtIHNhbXBsZXIyRCB0cmFuc21pc3Npb25NYXA7XHJcblxyXG5cdCNlbmRpZlxyXG5cclxuXHQjaWZkZWYgVVNFX1RISUNLTkVTU01BUFxyXG5cclxuXHRcdHVuaWZvcm0gc2FtcGxlcjJEIHRoaWNrbmVzc01hcDtcclxuXHJcblx0I2VuZGlmXHJcblxyXG5cdHVuaWZvcm0gdmVjMiB0cmFuc21pc3Npb25TYW1wbGVyU2l6ZTtcclxuXHR1bmlmb3JtIHNhbXBsZXIyRCB0cmFuc21pc3Npb25TYW1wbGVyTWFwO1xyXG5cclxuXHR1bmlmb3JtIG1hdDQgbW9kZWxNYXRyaXg7XHJcblx0dW5pZm9ybSBtYXQ0IHByb2plY3Rpb25NYXRyaXg7XHJcblxyXG5cdHZhcnlpbmcgdmVjMyB2V29ybGRQb3NpdGlvbjtcclxuXHJcblx0Ly8gTWlwcGVkIEJpY3ViaWMgVGV4dHVyZSBGaWx0ZXJpbmcgYnkgTjhcclxuXHQvLyBodHRwczovL3d3dy5zaGFkZXJ0b3kuY29tL3ZpZXcvRGwyU0RXXHJcblxyXG5cdGZsb2F0IHcwKCBmbG9hdCBhICkge1xyXG5cclxuXHRcdHJldHVybiAoIDEuMCAvIDYuMCApICogKCBhICogKCBhICogKCAtIGEgKyAzLjAgKSAtIDMuMCApICsgMS4wICk7XHJcblxyXG5cdH1cclxuXHJcblx0ZmxvYXQgdzEoIGZsb2F0IGEgKSB7XHJcblxyXG5cdFx0cmV0dXJuICggMS4wIC8gNi4wICkgKiAoIGEgKiAgYSAqICggMy4wICogYSAtIDYuMCApICsgNC4wICk7XHJcblxyXG5cdH1cclxuXHJcblx0ZmxvYXQgdzIoIGZsb2F0IGEgKXtcclxuXHJcblx0XHRyZXR1cm4gKCAxLjAgLyA2LjAgKSAqICggYSAqICggYSAqICggLSAzLjAgKiBhICsgMy4wICkgKyAzLjAgKSArIDEuMCApO1xyXG5cclxuXHR9XHJcblxyXG5cdGZsb2F0IHczKCBmbG9hdCBhICkge1xyXG5cclxuXHRcdHJldHVybiAoIDEuMCAvIDYuMCApICogKCBhICogYSAqIGEgKTtcclxuXHJcblx0fVxyXG5cclxuXHQvLyBnMCBhbmQgZzEgYXJlIHRoZSB0d28gYW1wbGl0dWRlIGZ1bmN0aW9uc1xyXG5cdGZsb2F0IGcwKCBmbG9hdCBhICkge1xyXG5cclxuXHRcdHJldHVybiB3MCggYSApICsgdzEoIGEgKTtcclxuXHJcblx0fVxyXG5cclxuXHRmbG9hdCBnMSggZmxvYXQgYSApIHtcclxuXHJcblx0XHRyZXR1cm4gdzIoIGEgKSArIHczKCBhICk7XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gaDAgYW5kIGgxIGFyZSB0aGUgdHdvIG9mZnNldCBmdW5jdGlvbnNcclxuXHRmbG9hdCBoMCggZmxvYXQgYSApIHtcclxuXHJcblx0XHRyZXR1cm4gLSAxLjAgKyB3MSggYSApIC8gKCB3MCggYSApICsgdzEoIGEgKSApO1xyXG5cclxuXHR9XHJcblxyXG5cdGZsb2F0IGgxKCBmbG9hdCBhICkge1xyXG5cclxuXHRcdHJldHVybiAxLjAgKyB3MyggYSApIC8gKCB3MiggYSApICsgdzMoIGEgKSApO1xyXG5cclxuXHR9XHJcblxyXG5cdHZlYzQgYmljdWJpYyggc2FtcGxlcjJEIHRleCwgdmVjMiB1diwgdmVjNCB0ZXhlbFNpemUsIGZsb2F0IGxvZCApIHtcclxuXHJcblx0XHR1diA9IHV2ICogdGV4ZWxTaXplLnp3ICsgMC41O1xyXG5cclxuXHRcdHZlYzIgaXV2ID0gZmxvb3IoIHV2ICk7XHJcblx0XHR2ZWMyIGZ1diA9IGZyYWN0KCB1diApO1xyXG5cclxuXHRcdGZsb2F0IGcweCA9IGcwKCBmdXYueCApO1xyXG5cdFx0ZmxvYXQgZzF4ID0gZzEoIGZ1di54ICk7XHJcblx0XHRmbG9hdCBoMHggPSBoMCggZnV2LnggKTtcclxuXHRcdGZsb2F0IGgxeCA9IGgxKCBmdXYueCApO1xyXG5cdFx0ZmxvYXQgaDB5ID0gaDAoIGZ1di55ICk7XHJcblx0XHRmbG9hdCBoMXkgPSBoMSggZnV2LnkgKTtcclxuXHJcblx0XHR2ZWMyIHAwID0gKCB2ZWMyKCBpdXYueCArIGgweCwgaXV2LnkgKyBoMHkgKSAtIDAuNSApICogdGV4ZWxTaXplLnh5O1xyXG5cdFx0dmVjMiBwMSA9ICggdmVjMiggaXV2LnggKyBoMXgsIGl1di55ICsgaDB5ICkgLSAwLjUgKSAqIHRleGVsU2l6ZS54eTtcclxuXHRcdHZlYzIgcDIgPSAoIHZlYzIoIGl1di54ICsgaDB4LCBpdXYueSArIGgxeSApIC0gMC41ICkgKiB0ZXhlbFNpemUueHk7XHJcblx0XHR2ZWMyIHAzID0gKCB2ZWMyKCBpdXYueCArIGgxeCwgaXV2LnkgKyBoMXkgKSAtIDAuNSApICogdGV4ZWxTaXplLnh5O1xyXG5cclxuXHRcdHJldHVybiBnMCggZnV2LnkgKSAqICggZzB4ICogdGV4dHVyZUxvZCggdGV4LCBwMCwgbG9kICkgKyBnMXggKiB0ZXh0dXJlTG9kKCB0ZXgsIHAxLCBsb2QgKSApICtcclxuXHRcdFx0ZzEoIGZ1di55ICkgKiAoIGcweCAqIHRleHR1cmVMb2QoIHRleCwgcDIsIGxvZCApICsgZzF4ICogdGV4dHVyZUxvZCggdGV4LCBwMywgbG9kICkgKTtcclxuXHJcblx0fVxyXG5cclxuXHR2ZWM0IHRleHR1cmVCaWN1YmljKCBzYW1wbGVyMkQgc2FtcGxlciwgdmVjMiB1diwgZmxvYXQgbG9kICkge1xyXG5cclxuXHRcdHZlYzIgZkxvZFNpemUgPSB2ZWMyKCB0ZXh0dXJlU2l6ZSggc2FtcGxlciwgaW50KCBsb2QgKSApICk7XHJcblx0XHR2ZWMyIGNMb2RTaXplID0gdmVjMiggdGV4dHVyZVNpemUoIHNhbXBsZXIsIGludCggbG9kICsgMS4wICkgKSApO1xyXG5cdFx0dmVjMiBmTG9kU2l6ZUludiA9IDEuMCAvIGZMb2RTaXplO1xyXG5cdFx0dmVjMiBjTG9kU2l6ZUludiA9IDEuMCAvIGNMb2RTaXplO1xyXG5cdFx0dmVjNCBmU2FtcGxlID0gYmljdWJpYyggc2FtcGxlciwgdXYsIHZlYzQoIGZMb2RTaXplSW52LCBmTG9kU2l6ZSApLCBmbG9vciggbG9kICkgKTtcclxuXHRcdHZlYzQgY1NhbXBsZSA9IGJpY3ViaWMoIHNhbXBsZXIsIHV2LCB2ZWM0KCBjTG9kU2l6ZUludiwgY0xvZFNpemUgKSwgY2VpbCggbG9kICkgKTtcclxuXHRcdHJldHVybiBtaXgoIGZTYW1wbGUsIGNTYW1wbGUsIGZyYWN0KCBsb2QgKSApO1xyXG5cclxuXHR9XHJcblxyXG5cdHZlYzMgZ2V0Vm9sdW1lVHJhbnNtaXNzaW9uUmF5KCBjb25zdCBpbiB2ZWMzIG4sIGNvbnN0IGluIHZlYzMgdiwgY29uc3QgaW4gZmxvYXQgdGhpY2tuZXNzLCBjb25zdCBpbiBmbG9hdCBpb3IsIGNvbnN0IGluIG1hdDQgbW9kZWxNYXRyaXggKSB7XHJcblxyXG5cdFx0Ly8gRGlyZWN0aW9uIG9mIHJlZnJhY3RlZCBsaWdodC5cclxuXHRcdHZlYzMgcmVmcmFjdGlvblZlY3RvciA9IHJlZnJhY3QoIC0gdiwgbm9ybWFsaXplKCBuICksIDEuMCAvIGlvciApO1xyXG5cclxuXHRcdC8vIENvbXB1dGUgcm90YXRpb24taW5kZXBlbmRhbnQgc2NhbGluZyBvZiB0aGUgbW9kZWwgbWF0cml4LlxyXG5cdFx0dmVjMyBtb2RlbFNjYWxlO1xyXG5cdFx0bW9kZWxTY2FsZS54ID0gbGVuZ3RoKCB2ZWMzKCBtb2RlbE1hdHJpeFsgMCBdLnh5eiApICk7XHJcblx0XHRtb2RlbFNjYWxlLnkgPSBsZW5ndGgoIHZlYzMoIG1vZGVsTWF0cml4WyAxIF0ueHl6ICkgKTtcclxuXHRcdG1vZGVsU2NhbGUueiA9IGxlbmd0aCggdmVjMyggbW9kZWxNYXRyaXhbIDIgXS54eXogKSApO1xyXG5cclxuXHRcdC8vIFRoZSB0aGlja25lc3MgaXMgc3BlY2lmaWVkIGluIGxvY2FsIHNwYWNlLlxyXG5cdFx0cmV0dXJuIG5vcm1hbGl6ZSggcmVmcmFjdGlvblZlY3RvciApICogdGhpY2tuZXNzICogbW9kZWxTY2FsZTtcclxuXHJcblx0fVxyXG5cclxuXHRmbG9hdCBhcHBseUlvclRvUm91Z2huZXNzKCBjb25zdCBpbiBmbG9hdCByb3VnaG5lc3MsIGNvbnN0IGluIGZsb2F0IGlvciApIHtcclxuXHJcblx0XHQvLyBTY2FsZSByb3VnaG5lc3Mgd2l0aCBJT1Igc28gdGhhdCBhbiBJT1Igb2YgMS4wIHJlc3VsdHMgaW4gbm8gbWljcm9mYWNldCByZWZyYWN0aW9uIGFuZFxyXG5cdFx0Ly8gYW4gSU9SIG9mIDEuNSByZXN1bHRzIGluIHRoZSBkZWZhdWx0IGFtb3VudCBvZiBtaWNyb2ZhY2V0IHJlZnJhY3Rpb24uXHJcblx0XHRyZXR1cm4gcm91Z2huZXNzICogY2xhbXAoIGlvciAqIDIuMCAtIDIuMCwgMC4wLCAxLjAgKTtcclxuXHJcblx0fVxyXG5cclxuXHR2ZWM0IGdldFRyYW5zbWlzc2lvblNhbXBsZSggY29uc3QgaW4gdmVjMiBmcmFnQ29vcmQsIGNvbnN0IGluIGZsb2F0IHJvdWdobmVzcywgY29uc3QgaW4gZmxvYXQgaW9yICkge1xyXG5cclxuXHRcdGZsb2F0IGxvZCA9IGxvZzIoIHRyYW5zbWlzc2lvblNhbXBsZXJTaXplLnggKSAqIGFwcGx5SW9yVG9Sb3VnaG5lc3MoIHJvdWdobmVzcywgaW9yICk7XHJcblx0XHRyZXR1cm4gdGV4dHVyZUJpY3ViaWMoIHRyYW5zbWlzc2lvblNhbXBsZXJNYXAsIGZyYWdDb29yZC54eSwgbG9kICk7XHJcblxyXG5cdH1cclxuXHJcblx0dmVjMyB2b2x1bWVBdHRlbnVhdGlvbiggY29uc3QgaW4gZmxvYXQgdHJhbnNtaXNzaW9uRGlzdGFuY2UsIGNvbnN0IGluIHZlYzMgYXR0ZW51YXRpb25Db2xvciwgY29uc3QgaW4gZmxvYXQgYXR0ZW51YXRpb25EaXN0YW5jZSApIHtcclxuXHJcblx0XHRpZiAoIGlzaW5mKCBhdHRlbnVhdGlvbkRpc3RhbmNlICkgKSB7XHJcblxyXG5cdFx0XHQvLyBBdHRlbnVhdGlvbiBkaXN0YW5jZSBpcyAr4oieLCBpLmUuIHRoZSB0cmFuc21pdHRlZCBjb2xvciBpcyBub3QgYXR0ZW51YXRlZCBhdCBhbGwuXHJcblx0XHRcdHJldHVybiB2ZWMzKCAxLjAgKTtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0Ly8gQ29tcHV0ZSBsaWdodCBhdHRlbnVhdGlvbiB1c2luZyBCZWVyJ3MgbGF3LlxyXG5cdFx0XHR2ZWMzIGF0dGVudWF0aW9uQ29lZmZpY2llbnQgPSAtbG9nKCBhdHRlbnVhdGlvbkNvbG9yICkgLyBhdHRlbnVhdGlvbkRpc3RhbmNlO1xyXG5cdFx0XHR2ZWMzIHRyYW5zbWl0dGFuY2UgPSBleHAoIC0gYXR0ZW51YXRpb25Db2VmZmljaWVudCAqIHRyYW5zbWlzc2lvbkRpc3RhbmNlICk7IC8vIEJlZXIncyBsYXdcclxuXHRcdFx0cmV0dXJuIHRyYW5zbWl0dGFuY2U7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdHZlYzQgZ2V0SUJMVm9sdW1lUmVmcmFjdGlvbiggY29uc3QgaW4gdmVjMyBuLCBjb25zdCBpbiB2ZWMzIHYsIGNvbnN0IGluIGZsb2F0IHJvdWdobmVzcywgY29uc3QgaW4gdmVjMyBkaWZmdXNlQ29sb3IsXHJcblx0XHRjb25zdCBpbiB2ZWMzIHNwZWN1bGFyQ29sb3IsIGNvbnN0IGluIGZsb2F0IHNwZWN1bGFyRjkwLCBjb25zdCBpbiB2ZWMzIHBvc2l0aW9uLCBjb25zdCBpbiBtYXQ0IG1vZGVsTWF0cml4LFxyXG5cdFx0Y29uc3QgaW4gbWF0NCB2aWV3TWF0cml4LCBjb25zdCBpbiBtYXQ0IHByb2pNYXRyaXgsIGNvbnN0IGluIGZsb2F0IGlvciwgY29uc3QgaW4gZmxvYXQgdGhpY2tuZXNzLFxyXG5cdFx0Y29uc3QgaW4gdmVjMyBhdHRlbnVhdGlvbkNvbG9yLCBjb25zdCBpbiBmbG9hdCBhdHRlbnVhdGlvbkRpc3RhbmNlICkge1xyXG5cclxuXHRcdHZlYzMgdHJhbnNtaXNzaW9uUmF5ID0gZ2V0Vm9sdW1lVHJhbnNtaXNzaW9uUmF5KCBuLCB2LCB0aGlja25lc3MsIGlvciwgbW9kZWxNYXRyaXggKTtcclxuXHRcdHZlYzMgcmVmcmFjdGVkUmF5RXhpdCA9IHBvc2l0aW9uICsgdHJhbnNtaXNzaW9uUmF5O1xyXG5cclxuXHRcdC8vIFByb2plY3QgcmVmcmFjdGVkIHZlY3RvciBvbiB0aGUgZnJhbWVidWZmZXIsIHdoaWxlIG1hcHBpbmcgdG8gbm9ybWFsaXplZCBkZXZpY2UgY29vcmRpbmF0ZXMuXHJcblx0XHR2ZWM0IG5kY1BvcyA9IHByb2pNYXRyaXggKiB2aWV3TWF0cml4ICogdmVjNCggcmVmcmFjdGVkUmF5RXhpdCwgMS4wICk7XHJcblx0XHR2ZWMyIHJlZnJhY3Rpb25Db29yZHMgPSBuZGNQb3MueHkgLyBuZGNQb3MudztcclxuXHRcdHJlZnJhY3Rpb25Db29yZHMgKz0gMS4wO1xyXG5cdFx0cmVmcmFjdGlvbkNvb3JkcyAvPSAyLjA7XHJcblxyXG5cdFx0Ly8gU2FtcGxlIGZyYW1lYnVmZmVyIHRvIGdldCBwaXhlbCB0aGUgcmVmcmFjdGVkIHJheSBoaXRzLlxyXG5cdFx0dmVjNCB0cmFuc21pdHRlZExpZ2h0ID0gZ2V0VHJhbnNtaXNzaW9uU2FtcGxlKCByZWZyYWN0aW9uQ29vcmRzLCByb3VnaG5lc3MsIGlvciApO1xyXG5cclxuXHRcdHZlYzMgdHJhbnNtaXR0YW5jZSA9IGRpZmZ1c2VDb2xvciAqIHZvbHVtZUF0dGVudWF0aW9uKCBsZW5ndGgoIHRyYW5zbWlzc2lvblJheSApLCBhdHRlbnVhdGlvbkNvbG9yLCBhdHRlbnVhdGlvbkRpc3RhbmNlICk7XHJcblx0XHR2ZWMzIGF0dGVudWF0ZWRDb2xvciA9IHRyYW5zbWl0dGFuY2UgKiB0cmFuc21pdHRlZExpZ2h0LnJnYjtcclxuXHJcblx0XHQvLyBHZXQgdGhlIHNwZWN1bGFyIGNvbXBvbmVudC5cclxuXHRcdHZlYzMgRiA9IEVudmlyb25tZW50QlJERiggbiwgdiwgc3BlY3VsYXJDb2xvciwgc3BlY3VsYXJGOTAsIHJvdWdobmVzcyApO1xyXG5cclxuXHRcdC8vIEFzIGxlc3MgbGlnaHQgaXMgdHJhbnNtaXR0ZWQsIHRoZSBvcGFjaXR5IHNob3VsZCBiZSBpbmNyZWFzZWQuIFRoaXMgc2ltcGxlIGFwcHJveGltYXRpb24gZG9lcyBhIGRlY2VudCBqb2IgXHJcblx0XHQvLyBvZiBtb2R1bGF0aW5nIGEgQ1NTIGJhY2tncm91bmQsIGFuZCBoYXMgbm8gZWZmZWN0IHdoZW4gdGhlIGJ1ZmZlciBpcyBvcGFxdWUsIGR1ZSB0byBhIHNvbGlkIG9iamVjdCBvciBjbGVhciBjb2xvci5cclxuXHRcdGZsb2F0IHRyYW5zbWl0dGFuY2VGYWN0b3IgPSAoIHRyYW5zbWl0dGFuY2UuciArIHRyYW5zbWl0dGFuY2UuZyArIHRyYW5zbWl0dGFuY2UuYiApIC8gMy4wO1xyXG5cclxuXHRcdHJldHVybiB2ZWM0KCAoIDEuMCAtIEYgKSAqIGF0dGVudWF0ZWRDb2xvciwgMS4wIC0gKCAxLjAgLSB0cmFuc21pdHRlZExpZ2h0LmEgKSAqIHRyYW5zbWl0dGFuY2VGYWN0b3IgKTtcclxuXHJcblx0fVxyXG4jZW5kaWZcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuI2lmIGRlZmluZWQoIFVTRV9VViApIHx8IGRlZmluZWQoIFVTRV9BTklTT1RST1BZIClcclxuXHJcblx0dmFyeWluZyB2ZWMyIHZVdjtcclxuXHJcbiNlbmRpZlxyXG4jaWZkZWYgVVNFX01BUFxyXG5cclxuXHR2YXJ5aW5nIHZlYzIgdk1hcFV2O1xyXG5cclxuI2VuZGlmXHJcbiNpZmRlZiBVU0VfQUxQSEFNQVBcclxuXHJcblx0dmFyeWluZyB2ZWMyIHZBbHBoYU1hcFV2O1xyXG5cclxuI2VuZGlmXHJcbiNpZmRlZiBVU0VfTElHSFRNQVBcclxuXHJcblx0dmFyeWluZyB2ZWMyIHZMaWdodE1hcFV2O1xyXG5cclxuI2VuZGlmXHJcbiNpZmRlZiBVU0VfQU9NQVBcclxuXHJcblx0dmFyeWluZyB2ZWMyIHZBb01hcFV2O1xyXG5cclxuI2VuZGlmXHJcbiNpZmRlZiBVU0VfQlVNUE1BUFxyXG5cclxuXHR2YXJ5aW5nIHZlYzIgdkJ1bXBNYXBVdjtcclxuXHJcbiNlbmRpZlxyXG4jaWZkZWYgVVNFX05PUk1BTE1BUFxyXG5cclxuXHR2YXJ5aW5nIHZlYzIgdk5vcm1hbE1hcFV2O1xyXG5cclxuI2VuZGlmXHJcbiNpZmRlZiBVU0VfRU1JU1NJVkVNQVBcclxuXHJcblx0dmFyeWluZyB2ZWMyIHZFbWlzc2l2ZU1hcFV2O1xyXG5cclxuI2VuZGlmXHJcbiNpZmRlZiBVU0VfTUVUQUxORVNTTUFQXHJcblxyXG5cdHZhcnlpbmcgdmVjMiB2TWV0YWxuZXNzTWFwVXY7XHJcblxyXG4jZW5kaWZcclxuI2lmZGVmIFVTRV9ST1VHSE5FU1NNQVBcclxuXHJcblx0dmFyeWluZyB2ZWMyIHZSb3VnaG5lc3NNYXBVdjtcclxuXHJcbiNlbmRpZlxyXG4jaWZkZWYgVVNFX0FOSVNPVFJPUFlNQVBcclxuXHJcblx0dmFyeWluZyB2ZWMyIHZBbmlzb3Ryb3B5TWFwVXY7XHJcblxyXG4jZW5kaWZcclxuI2lmZGVmIFVTRV9DTEVBUkNPQVRNQVBcclxuXHJcblx0dmFyeWluZyB2ZWMyIHZDbGVhcmNvYXRNYXBVdjtcclxuXHJcbiNlbmRpZlxyXG4jaWZkZWYgVVNFX0NMRUFSQ09BVF9OT1JNQUxNQVBcclxuXHJcblx0dmFyeWluZyB2ZWMyIHZDbGVhcmNvYXROb3JtYWxNYXBVdjtcclxuXHJcbiNlbmRpZlxyXG4jaWZkZWYgVVNFX0NMRUFSQ09BVF9ST1VHSE5FU1NNQVBcclxuXHJcblx0dmFyeWluZyB2ZWMyIHZDbGVhcmNvYXRSb3VnaG5lc3NNYXBVdjtcclxuXHJcbiNlbmRpZlxyXG4jaWZkZWYgVVNFX0lSSURFU0NFTkNFTUFQXHJcblxyXG5cdHZhcnlpbmcgdmVjMiB2SXJpZGVzY2VuY2VNYXBVdjtcclxuXHJcbiNlbmRpZlxyXG4jaWZkZWYgVVNFX0lSSURFU0NFTkNFX1RISUNLTkVTU01BUFxyXG5cclxuXHR2YXJ5aW5nIHZlYzIgdklyaWRlc2NlbmNlVGhpY2tuZXNzTWFwVXY7XHJcblxyXG4jZW5kaWZcclxuI2lmZGVmIFVTRV9TSEVFTl9DT0xPUk1BUFxyXG5cclxuXHR2YXJ5aW5nIHZlYzIgdlNoZWVuQ29sb3JNYXBVdjtcclxuXHJcbiNlbmRpZlxyXG4jaWZkZWYgVVNFX1NIRUVOX1JPVUdITkVTU01BUFxyXG5cclxuXHR2YXJ5aW5nIHZlYzIgdlNoZWVuUm91Z2huZXNzTWFwVXY7XHJcblxyXG4jZW5kaWZcclxuI2lmZGVmIFVTRV9TUEVDVUxBUk1BUFxyXG5cclxuXHR2YXJ5aW5nIHZlYzIgdlNwZWN1bGFyTWFwVXY7XHJcblxyXG4jZW5kaWZcclxuI2lmZGVmIFVTRV9TUEVDVUxBUl9DT0xPUk1BUFxyXG5cclxuXHR2YXJ5aW5nIHZlYzIgdlNwZWN1bGFyQ29sb3JNYXBVdjtcclxuXHJcbiNlbmRpZlxyXG4jaWZkZWYgVVNFX1NQRUNVTEFSX0lOVEVOU0lUWU1BUFxyXG5cclxuXHR2YXJ5aW5nIHZlYzIgdlNwZWN1bGFySW50ZW5zaXR5TWFwVXY7XHJcblxyXG4jZW5kaWZcclxuI2lmZGVmIFVTRV9UUkFOU01JU1NJT05NQVBcclxuXHJcblx0dW5pZm9ybSBtYXQzIHRyYW5zbWlzc2lvbk1hcFRyYW5zZm9ybTtcclxuXHR2YXJ5aW5nIHZlYzIgdlRyYW5zbWlzc2lvbk1hcFV2O1xyXG5cclxuI2VuZGlmXHJcbiNpZmRlZiBVU0VfVEhJQ0tORVNTTUFQXHJcblxyXG5cdHVuaWZvcm0gbWF0MyB0aGlja25lc3NNYXBUcmFuc2Zvcm07XHJcblx0dmFyeWluZyB2ZWMyIHZUaGlja25lc3NNYXBVdjtcclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWYgZGVmaW5lZCggVVNFX1VWICkgfHwgZGVmaW5lZCggVVNFX0FOSVNPVFJPUFkgKVxyXG5cclxuXHR2YXJ5aW5nIHZlYzIgdlV2O1xyXG5cclxuI2VuZGlmXHJcbiNpZmRlZiBVU0VfTUFQXHJcblxyXG5cdHVuaWZvcm0gbWF0MyBtYXBUcmFuc2Zvcm07XHJcblx0dmFyeWluZyB2ZWMyIHZNYXBVdjtcclxuXHJcbiNlbmRpZlxyXG4jaWZkZWYgVVNFX0FMUEhBTUFQXHJcblxyXG5cdHVuaWZvcm0gbWF0MyBhbHBoYU1hcFRyYW5zZm9ybTtcclxuXHR2YXJ5aW5nIHZlYzIgdkFscGhhTWFwVXY7XHJcblxyXG4jZW5kaWZcclxuI2lmZGVmIFVTRV9MSUdIVE1BUFxyXG5cclxuXHR1bmlmb3JtIG1hdDMgbGlnaHRNYXBUcmFuc2Zvcm07XHJcblx0dmFyeWluZyB2ZWMyIHZMaWdodE1hcFV2O1xyXG5cclxuI2VuZGlmXHJcbiNpZmRlZiBVU0VfQU9NQVBcclxuXHJcblx0dW5pZm9ybSBtYXQzIGFvTWFwVHJhbnNmb3JtO1xyXG5cdHZhcnlpbmcgdmVjMiB2QW9NYXBVdjtcclxuXHJcbiNlbmRpZlxyXG4jaWZkZWYgVVNFX0JVTVBNQVBcclxuXHJcblx0dW5pZm9ybSBtYXQzIGJ1bXBNYXBUcmFuc2Zvcm07XHJcblx0dmFyeWluZyB2ZWMyIHZCdW1wTWFwVXY7XHJcblxyXG4jZW5kaWZcclxuI2lmZGVmIFVTRV9OT1JNQUxNQVBcclxuXHJcblx0dW5pZm9ybSBtYXQzIG5vcm1hbE1hcFRyYW5zZm9ybTtcclxuXHR2YXJ5aW5nIHZlYzIgdk5vcm1hbE1hcFV2O1xyXG5cclxuI2VuZGlmXHJcbiNpZmRlZiBVU0VfRElTUExBQ0VNRU5UTUFQXHJcblxyXG5cdHVuaWZvcm0gbWF0MyBkaXNwbGFjZW1lbnRNYXBUcmFuc2Zvcm07XHJcblx0dmFyeWluZyB2ZWMyIHZEaXNwbGFjZW1lbnRNYXBVdjtcclxuXHJcbiNlbmRpZlxyXG4jaWZkZWYgVVNFX0VNSVNTSVZFTUFQXHJcblxyXG5cdHVuaWZvcm0gbWF0MyBlbWlzc2l2ZU1hcFRyYW5zZm9ybTtcclxuXHR2YXJ5aW5nIHZlYzIgdkVtaXNzaXZlTWFwVXY7XHJcblxyXG4jZW5kaWZcclxuI2lmZGVmIFVTRV9NRVRBTE5FU1NNQVBcclxuXHJcblx0dW5pZm9ybSBtYXQzIG1ldGFsbmVzc01hcFRyYW5zZm9ybTtcclxuXHR2YXJ5aW5nIHZlYzIgdk1ldGFsbmVzc01hcFV2O1xyXG5cclxuI2VuZGlmXHJcbiNpZmRlZiBVU0VfUk9VR0hORVNTTUFQXHJcblxyXG5cdHVuaWZvcm0gbWF0MyByb3VnaG5lc3NNYXBUcmFuc2Zvcm07XHJcblx0dmFyeWluZyB2ZWMyIHZSb3VnaG5lc3NNYXBVdjtcclxuXHJcbiNlbmRpZlxyXG4jaWZkZWYgVVNFX0FOSVNPVFJPUFlNQVBcclxuXHJcblx0dW5pZm9ybSBtYXQzIGFuaXNvdHJvcHlNYXBUcmFuc2Zvcm07XHJcblx0dmFyeWluZyB2ZWMyIHZBbmlzb3Ryb3B5TWFwVXY7XHJcblxyXG4jZW5kaWZcclxuI2lmZGVmIFVTRV9DTEVBUkNPQVRNQVBcclxuXHJcblx0dW5pZm9ybSBtYXQzIGNsZWFyY29hdE1hcFRyYW5zZm9ybTtcclxuXHR2YXJ5aW5nIHZlYzIgdkNsZWFyY29hdE1hcFV2O1xyXG5cclxuI2VuZGlmXHJcbiNpZmRlZiBVU0VfQ0xFQVJDT0FUX05PUk1BTE1BUFxyXG5cclxuXHR1bmlmb3JtIG1hdDMgY2xlYXJjb2F0Tm9ybWFsTWFwVHJhbnNmb3JtO1xyXG5cdHZhcnlpbmcgdmVjMiB2Q2xlYXJjb2F0Tm9ybWFsTWFwVXY7XHJcblxyXG4jZW5kaWZcclxuI2lmZGVmIFVTRV9DTEVBUkNPQVRfUk9VR0hORVNTTUFQXHJcblxyXG5cdHVuaWZvcm0gbWF0MyBjbGVhcmNvYXRSb3VnaG5lc3NNYXBUcmFuc2Zvcm07XHJcblx0dmFyeWluZyB2ZWMyIHZDbGVhcmNvYXRSb3VnaG5lc3NNYXBVdjtcclxuXHJcbiNlbmRpZlxyXG4jaWZkZWYgVVNFX1NIRUVOX0NPTE9STUFQXHJcblxyXG5cdHVuaWZvcm0gbWF0MyBzaGVlbkNvbG9yTWFwVHJhbnNmb3JtO1xyXG5cdHZhcnlpbmcgdmVjMiB2U2hlZW5Db2xvck1hcFV2O1xyXG5cclxuI2VuZGlmXHJcbiNpZmRlZiBVU0VfU0hFRU5fUk9VR0hORVNTTUFQXHJcblxyXG5cdHVuaWZvcm0gbWF0MyBzaGVlblJvdWdobmVzc01hcFRyYW5zZm9ybTtcclxuXHR2YXJ5aW5nIHZlYzIgdlNoZWVuUm91Z2huZXNzTWFwVXY7XHJcblxyXG4jZW5kaWZcclxuI2lmZGVmIFVTRV9JUklERVNDRU5DRU1BUFxyXG5cclxuXHR1bmlmb3JtIG1hdDMgaXJpZGVzY2VuY2VNYXBUcmFuc2Zvcm07XHJcblx0dmFyeWluZyB2ZWMyIHZJcmlkZXNjZW5jZU1hcFV2O1xyXG5cclxuI2VuZGlmXHJcbiNpZmRlZiBVU0VfSVJJREVTQ0VOQ0VfVEhJQ0tORVNTTUFQXHJcblxyXG5cdHVuaWZvcm0gbWF0MyBpcmlkZXNjZW5jZVRoaWNrbmVzc01hcFRyYW5zZm9ybTtcclxuXHR2YXJ5aW5nIHZlYzIgdklyaWRlc2NlbmNlVGhpY2tuZXNzTWFwVXY7XHJcblxyXG4jZW5kaWZcclxuI2lmZGVmIFVTRV9TUEVDVUxBUk1BUFxyXG5cclxuXHR1bmlmb3JtIG1hdDMgc3BlY3VsYXJNYXBUcmFuc2Zvcm07XHJcblx0dmFyeWluZyB2ZWMyIHZTcGVjdWxhck1hcFV2O1xyXG5cclxuI2VuZGlmXHJcbiNpZmRlZiBVU0VfU1BFQ1VMQVJfQ09MT1JNQVBcclxuXHJcblx0dW5pZm9ybSBtYXQzIHNwZWN1bGFyQ29sb3JNYXBUcmFuc2Zvcm07XHJcblx0dmFyeWluZyB2ZWMyIHZTcGVjdWxhckNvbG9yTWFwVXY7XHJcblxyXG4jZW5kaWZcclxuI2lmZGVmIFVTRV9TUEVDVUxBUl9JTlRFTlNJVFlNQVBcclxuXHJcblx0dW5pZm9ybSBtYXQzIHNwZWN1bGFySW50ZW5zaXR5TWFwVHJhbnNmb3JtO1xyXG5cdHZhcnlpbmcgdmVjMiB2U3BlY3VsYXJJbnRlbnNpdHlNYXBVdjtcclxuXHJcbiNlbmRpZlxyXG4jaWZkZWYgVVNFX1RSQU5TTUlTU0lPTk1BUFxyXG5cclxuXHR1bmlmb3JtIG1hdDMgdHJhbnNtaXNzaW9uTWFwVHJhbnNmb3JtO1xyXG5cdHZhcnlpbmcgdmVjMiB2VHJhbnNtaXNzaW9uTWFwVXY7XHJcblxyXG4jZW5kaWZcclxuI2lmZGVmIFVTRV9USElDS05FU1NNQVBcclxuXHJcblx0dW5pZm9ybSBtYXQzIHRoaWNrbmVzc01hcFRyYW5zZm9ybTtcclxuXHR2YXJ5aW5nIHZlYzIgdlRoaWNrbmVzc01hcFV2O1xyXG5cclxuI2VuZGlmXHJcbmA7XHJcbiIsImV4cG9ydCBkZWZhdWx0IC8qIGdsc2wgKi9gXHJcbiNpZiBkZWZpbmVkKCBVU0VfVVYgKSB8fCBkZWZpbmVkKCBVU0VfQU5JU09UUk9QWSApXHJcblxyXG5cdHZVdiA9IHZlYzMoIHV2LCAxICkueHk7XHJcblxyXG4jZW5kaWZcclxuI2lmZGVmIFVTRV9NQVBcclxuXHJcblx0dk1hcFV2ID0gKCBtYXBUcmFuc2Zvcm0gKiB2ZWMzKCBNQVBfVVYsIDEgKSApLnh5O1xyXG5cclxuI2VuZGlmXHJcbiNpZmRlZiBVU0VfQUxQSEFNQVBcclxuXHJcblx0dkFscGhhTWFwVXYgPSAoIGFscGhhTWFwVHJhbnNmb3JtICogdmVjMyggQUxQSEFNQVBfVVYsIDEgKSApLnh5O1xyXG5cclxuI2VuZGlmXHJcbiNpZmRlZiBVU0VfTElHSFRNQVBcclxuXHJcblx0dkxpZ2h0TWFwVXYgPSAoIGxpZ2h0TWFwVHJhbnNmb3JtICogdmVjMyggTElHSFRNQVBfVVYsIDEgKSApLnh5O1xyXG5cclxuI2VuZGlmXHJcbiNpZmRlZiBVU0VfQU9NQVBcclxuXHJcblx0dkFvTWFwVXYgPSAoIGFvTWFwVHJhbnNmb3JtICogdmVjMyggQU9NQVBfVVYsIDEgKSApLnh5O1xyXG5cclxuI2VuZGlmXHJcbiNpZmRlZiBVU0VfQlVNUE1BUFxyXG5cclxuXHR2QnVtcE1hcFV2ID0gKCBidW1wTWFwVHJhbnNmb3JtICogdmVjMyggQlVNUE1BUF9VViwgMSApICkueHk7XHJcblxyXG4jZW5kaWZcclxuI2lmZGVmIFVTRV9OT1JNQUxNQVBcclxuXHJcblx0dk5vcm1hbE1hcFV2ID0gKCBub3JtYWxNYXBUcmFuc2Zvcm0gKiB2ZWMzKCBOT1JNQUxNQVBfVVYsIDEgKSApLnh5O1xyXG5cclxuI2VuZGlmXHJcbiNpZmRlZiBVU0VfRElTUExBQ0VNRU5UTUFQXHJcblxyXG5cdHZEaXNwbGFjZW1lbnRNYXBVdiA9ICggZGlzcGxhY2VtZW50TWFwVHJhbnNmb3JtICogdmVjMyggRElTUExBQ0VNRU5UTUFQX1VWLCAxICkgKS54eTtcclxuXHJcbiNlbmRpZlxyXG4jaWZkZWYgVVNFX0VNSVNTSVZFTUFQXHJcblxyXG5cdHZFbWlzc2l2ZU1hcFV2ID0gKCBlbWlzc2l2ZU1hcFRyYW5zZm9ybSAqIHZlYzMoIEVNSVNTSVZFTUFQX1VWLCAxICkgKS54eTtcclxuXHJcbiNlbmRpZlxyXG4jaWZkZWYgVVNFX01FVEFMTkVTU01BUFxyXG5cclxuXHR2TWV0YWxuZXNzTWFwVXYgPSAoIG1ldGFsbmVzc01hcFRyYW5zZm9ybSAqIHZlYzMoIE1FVEFMTkVTU01BUF9VViwgMSApICkueHk7XHJcblxyXG4jZW5kaWZcclxuI2lmZGVmIFVTRV9ST1VHSE5FU1NNQVBcclxuXHJcblx0dlJvdWdobmVzc01hcFV2ID0gKCByb3VnaG5lc3NNYXBUcmFuc2Zvcm0gKiB2ZWMzKCBST1VHSE5FU1NNQVBfVVYsIDEgKSApLnh5O1xyXG5cclxuI2VuZGlmXHJcbiNpZmRlZiBVU0VfQU5JU09UUk9QWU1BUFxyXG5cclxuXHR2QW5pc290cm9weU1hcFV2ID0gKCBhbmlzb3Ryb3B5TWFwVHJhbnNmb3JtICogdmVjMyggQU5JU09UUk9QWU1BUF9VViwgMSApICkueHk7XHJcblxyXG4jZW5kaWZcclxuI2lmZGVmIFVTRV9DTEVBUkNPQVRNQVBcclxuXHJcblx0dkNsZWFyY29hdE1hcFV2ID0gKCBjbGVhcmNvYXRNYXBUcmFuc2Zvcm0gKiB2ZWMzKCBDTEVBUkNPQVRNQVBfVVYsIDEgKSApLnh5O1xyXG5cclxuI2VuZGlmXHJcbiNpZmRlZiBVU0VfQ0xFQVJDT0FUX05PUk1BTE1BUFxyXG5cclxuXHR2Q2xlYXJjb2F0Tm9ybWFsTWFwVXYgPSAoIGNsZWFyY29hdE5vcm1hbE1hcFRyYW5zZm9ybSAqIHZlYzMoIENMRUFSQ09BVF9OT1JNQUxNQVBfVVYsIDEgKSApLnh5O1xyXG5cclxuI2VuZGlmXHJcbiNpZmRlZiBVU0VfQ0xFQVJDT0FUX1JPVUdITkVTU01BUFxyXG5cclxuXHR2Q2xlYXJjb2F0Um91Z2huZXNzTWFwVXYgPSAoIGNsZWFyY29hdFJvdWdobmVzc01hcFRyYW5zZm9ybSAqIHZlYzMoIENMRUFSQ09BVF9ST1VHSE5FU1NNQVBfVVYsIDEgKSApLnh5O1xyXG5cclxuI2VuZGlmXHJcbiNpZmRlZiBVU0VfSVJJREVTQ0VOQ0VNQVBcclxuXHJcblx0dklyaWRlc2NlbmNlTWFwVXYgPSAoIGlyaWRlc2NlbmNlTWFwVHJhbnNmb3JtICogdmVjMyggSVJJREVTQ0VOQ0VNQVBfVVYsIDEgKSApLnh5O1xyXG5cclxuI2VuZGlmXHJcbiNpZmRlZiBVU0VfSVJJREVTQ0VOQ0VfVEhJQ0tORVNTTUFQXHJcblxyXG5cdHZJcmlkZXNjZW5jZVRoaWNrbmVzc01hcFV2ID0gKCBpcmlkZXNjZW5jZVRoaWNrbmVzc01hcFRyYW5zZm9ybSAqIHZlYzMoIElSSURFU0NFTkNFX1RISUNLTkVTU01BUF9VViwgMSApICkueHk7XHJcblxyXG4jZW5kaWZcclxuI2lmZGVmIFVTRV9TSEVFTl9DT0xPUk1BUFxyXG5cclxuXHR2U2hlZW5Db2xvck1hcFV2ID0gKCBzaGVlbkNvbG9yTWFwVHJhbnNmb3JtICogdmVjMyggU0hFRU5fQ09MT1JNQVBfVVYsIDEgKSApLnh5O1xyXG5cclxuI2VuZGlmXHJcbiNpZmRlZiBVU0VfU0hFRU5fUk9VR0hORVNTTUFQXHJcblxyXG5cdHZTaGVlblJvdWdobmVzc01hcFV2ID0gKCBzaGVlblJvdWdobmVzc01hcFRyYW5zZm9ybSAqIHZlYzMoIFNIRUVOX1JPVUdITkVTU01BUF9VViwgMSApICkueHk7XHJcblxyXG4jZW5kaWZcclxuI2lmZGVmIFVTRV9TUEVDVUxBUk1BUFxyXG5cclxuXHR2U3BlY3VsYXJNYXBVdiA9ICggc3BlY3VsYXJNYXBUcmFuc2Zvcm0gKiB2ZWMzKCBTUEVDVUxBUk1BUF9VViwgMSApICkueHk7XHJcblxyXG4jZW5kaWZcclxuI2lmZGVmIFVTRV9TUEVDVUxBUl9DT0xPUk1BUFxyXG5cclxuXHR2U3BlY3VsYXJDb2xvck1hcFV2ID0gKCBzcGVjdWxhckNvbG9yTWFwVHJhbnNmb3JtICogdmVjMyggU1BFQ1VMQVJfQ09MT1JNQVBfVVYsIDEgKSApLnh5O1xyXG5cclxuI2VuZGlmXHJcbiNpZmRlZiBVU0VfU1BFQ1VMQVJfSU5URU5TSVRZTUFQXHJcblxyXG5cdHZTcGVjdWxhckludGVuc2l0eU1hcFV2ID0gKCBzcGVjdWxhckludGVuc2l0eU1hcFRyYW5zZm9ybSAqIHZlYzMoIFNQRUNVTEFSX0lOVEVOU0lUWU1BUF9VViwgMSApICkueHk7XHJcblxyXG4jZW5kaWZcclxuI2lmZGVmIFVTRV9UUkFOU01JU1NJT05NQVBcclxuXHJcblx0dlRyYW5zbWlzc2lvbk1hcFV2ID0gKCB0cmFuc21pc3Npb25NYXBUcmFuc2Zvcm0gKiB2ZWMzKCBUUkFOU01JU1NJT05NQVBfVVYsIDEgKSApLnh5O1xyXG5cclxuI2VuZGlmXHJcbiNpZmRlZiBVU0VfVEhJQ0tORVNTTUFQXHJcblxyXG5cdHZUaGlja25lc3NNYXBVdiA9ICggdGhpY2tuZXNzTWFwVHJhbnNmb3JtICogdmVjMyggVEhJQ0tORVNTTUFQX1VWLCAxICkgKS54eTtcclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWYgZGVmaW5lZCggVVNFX0VOVk1BUCApIHx8IGRlZmluZWQoIERJU1RBTkNFICkgfHwgZGVmaW5lZCAoIFVTRV9TSEFET1dNQVAgKSB8fCBkZWZpbmVkICggVVNFX1RSQU5TTUlTU0lPTiApIHx8IE5VTV9TUE9UX0xJR0hUX0NPT1JEUyA+IDBcclxuXHJcblx0dmVjNCB3b3JsZFBvc2l0aW9uID0gdmVjNCggdHJhbnNmb3JtZWQsIDEuMCApO1xyXG5cclxuXHQjaWZkZWYgVVNFX0JBVENISU5HXHJcblxyXG5cdFx0d29ybGRQb3NpdGlvbiA9IGJhdGNoaW5nTWF0cml4ICogd29ybGRQb3NpdGlvbjtcclxuXHJcblx0I2VuZGlmXHJcblxyXG5cdCNpZmRlZiBVU0VfSU5TVEFOQ0lOR1xyXG5cclxuXHRcdHdvcmxkUG9zaXRpb24gPSBpbnN0YW5jZU1hdHJpeCAqIHdvcmxkUG9zaXRpb247XHJcblxyXG5cdCNlbmRpZlxyXG5cclxuXHR3b3JsZFBvc2l0aW9uID0gbW9kZWxNYXRyaXggKiB3b3JsZFBvc2l0aW9uO1xyXG5cclxuI2VuZGlmXHJcbmA7XHJcbiIsImV4cG9ydCBjb25zdCB2ZXJ0ZXggPSAvKiBnbHNsICovYFxyXG52YXJ5aW5nIHZlYzIgdlV2O1xyXG51bmlmb3JtIG1hdDMgdXZUcmFuc2Zvcm07XHJcblxyXG52b2lkIG1haW4oKSB7XHJcblxyXG5cdHZVdiA9ICggdXZUcmFuc2Zvcm0gKiB2ZWMzKCB1diwgMSApICkueHk7XHJcblxyXG5cdGdsX1Bvc2l0aW9uID0gdmVjNCggcG9zaXRpb24ueHksIDEuMCwgMS4wICk7XHJcblxyXG59XHJcbmA7XHJcblxyXG5leHBvcnQgY29uc3QgZnJhZ21lbnQgPSAvKiBnbHNsICovYFxyXG51bmlmb3JtIHNhbXBsZXIyRCB0MkQ7XHJcbnVuaWZvcm0gZmxvYXQgYmFja2dyb3VuZEludGVuc2l0eTtcclxuXHJcbnZhcnlpbmcgdmVjMiB2VXY7XHJcblxyXG52b2lkIG1haW4oKSB7XHJcblxyXG5cdHZlYzQgdGV4Q29sb3IgPSB0ZXh0dXJlMkQoIHQyRCwgdlV2ICk7XHJcblxyXG5cdCNpZmRlZiBERUNPREVfVklERU9fVEVYVFVSRVxyXG5cclxuXHRcdC8vIHVzZSBpbmxpbmUgc1JHQiBkZWNvZGUgdW50aWwgYnJvd3NlcnMgcHJvcGVybHkgc3VwcG9ydCBTUkdCOF9BUExIQTggd2l0aCB2aWRlbyB0ZXh0dXJlc1xyXG5cclxuXHRcdHRleENvbG9yID0gdmVjNCggbWl4KCBwb3coIHRleENvbG9yLnJnYiAqIDAuOTQ3ODY3Mjk4NiArIHZlYzMoIDAuMDUyMTMyNzAxNCApLCB2ZWMzKCAyLjQgKSApLCB0ZXhDb2xvci5yZ2IgKiAwLjA3NzM5OTM4MDgsIHZlYzMoIGxlc3NUaGFuRXF1YWwoIHRleENvbG9yLnJnYiwgdmVjMyggMC4wNDA0NSApICkgKSApLCB0ZXhDb2xvci53ICk7XHJcblxyXG5cdCNlbmRpZlxyXG5cclxuXHR0ZXhDb2xvci5yZ2IgKj0gYmFja2dyb3VuZEludGVuc2l0eTtcclxuXHJcblx0Z2xfRnJhZ0NvbG9yID0gdGV4Q29sb3I7XHJcblxyXG5cdCNpbmNsdWRlIDx0b25lbWFwcGluZ19mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8Y29sb3JzcGFjZV9mcmFnbWVudD5cclxuXHJcbn1cclxuYDtcclxuIiwiZXhwb3J0IGNvbnN0IHZlcnRleCA9IC8qIGdsc2wgKi9gXHJcbnZhcnlpbmcgdmVjMyB2V29ybGREaXJlY3Rpb247XHJcblxyXG4jaW5jbHVkZSA8Y29tbW9uPlxyXG5cclxudm9pZCBtYWluKCkge1xyXG5cclxuXHR2V29ybGREaXJlY3Rpb24gPSB0cmFuc2Zvcm1EaXJlY3Rpb24oIHBvc2l0aW9uLCBtb2RlbE1hdHJpeCApO1xyXG5cclxuXHQjaW5jbHVkZSA8YmVnaW5fdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxwcm9qZWN0X3ZlcnRleD5cclxuXHJcblx0Z2xfUG9zaXRpb24ueiA9IGdsX1Bvc2l0aW9uLnc7IC8vIHNldCB6IHRvIGNhbWVyYS5mYXJcclxuXHJcbn1cclxuYDtcclxuXHJcbmV4cG9ydCBjb25zdCBmcmFnbWVudCA9IC8qIGdsc2wgKi9gXHJcblxyXG4jaWZkZWYgRU5WTUFQX1RZUEVfQ1VCRVxyXG5cclxuXHR1bmlmb3JtIHNhbXBsZXJDdWJlIGVudk1hcDtcclxuXHJcbiNlbGlmIGRlZmluZWQoIEVOVk1BUF9UWVBFX0NVQkVfVVYgKVxyXG5cclxuXHR1bmlmb3JtIHNhbXBsZXIyRCBlbnZNYXA7XHJcblxyXG4jZW5kaWZcclxuXHJcbnVuaWZvcm0gZmxvYXQgZmxpcEVudk1hcDtcclxudW5pZm9ybSBmbG9hdCBiYWNrZ3JvdW5kQmx1cnJpbmVzcztcclxudW5pZm9ybSBmbG9hdCBiYWNrZ3JvdW5kSW50ZW5zaXR5O1xyXG5cclxudmFyeWluZyB2ZWMzIHZXb3JsZERpcmVjdGlvbjtcclxuXHJcbiNpbmNsdWRlIDxjdWJlX3V2X3JlZmxlY3Rpb25fZnJhZ21lbnQ+XHJcblxyXG52b2lkIG1haW4oKSB7XHJcblxyXG5cdCNpZmRlZiBFTlZNQVBfVFlQRV9DVUJFXHJcblxyXG5cdFx0dmVjNCB0ZXhDb2xvciA9IHRleHR1cmVDdWJlKCBlbnZNYXAsIHZlYzMoIGZsaXBFbnZNYXAgKiB2V29ybGREaXJlY3Rpb24ueCwgdldvcmxkRGlyZWN0aW9uLnl6ICkgKTtcclxuXHJcblx0I2VsaWYgZGVmaW5lZCggRU5WTUFQX1RZUEVfQ1VCRV9VViApXHJcblxyXG5cdFx0dmVjNCB0ZXhDb2xvciA9IHRleHR1cmVDdWJlVVYoIGVudk1hcCwgdldvcmxkRGlyZWN0aW9uLCBiYWNrZ3JvdW5kQmx1cnJpbmVzcyApO1xyXG5cclxuXHQjZWxzZVxyXG5cclxuXHRcdHZlYzQgdGV4Q29sb3IgPSB2ZWM0KCAwLjAsIDAuMCwgMC4wLCAxLjAgKTtcclxuXHJcblx0I2VuZGlmXHJcblxyXG5cdHRleENvbG9yLnJnYiAqPSBiYWNrZ3JvdW5kSW50ZW5zaXR5O1xyXG5cclxuXHRnbF9GcmFnQ29sb3IgPSB0ZXhDb2xvcjtcclxuXHJcblx0I2luY2x1ZGUgPHRvbmVtYXBwaW5nX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxjb2xvcnNwYWNlX2ZyYWdtZW50PlxyXG5cclxufVxyXG5gO1xyXG4iLCJleHBvcnQgY29uc3QgdmVydGV4ID0gLyogZ2xzbCAqL2BcclxudmFyeWluZyB2ZWMzIHZXb3JsZERpcmVjdGlvbjtcclxuXHJcbiNpbmNsdWRlIDxjb21tb24+XHJcblxyXG52b2lkIG1haW4oKSB7XHJcblxyXG5cdHZXb3JsZERpcmVjdGlvbiA9IHRyYW5zZm9ybURpcmVjdGlvbiggcG9zaXRpb24sIG1vZGVsTWF0cml4ICk7XHJcblxyXG5cdCNpbmNsdWRlIDxiZWdpbl92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPHByb2plY3RfdmVydGV4PlxyXG5cclxuXHRnbF9Qb3NpdGlvbi56ID0gZ2xfUG9zaXRpb24udzsgLy8gc2V0IHogdG8gY2FtZXJhLmZhclxyXG5cclxufVxyXG5gO1xyXG5cclxuZXhwb3J0IGNvbnN0IGZyYWdtZW50ID0gLyogZ2xzbCAqL2BcclxudW5pZm9ybSBzYW1wbGVyQ3ViZSB0Q3ViZTtcclxudW5pZm9ybSBmbG9hdCB0RmxpcDtcclxudW5pZm9ybSBmbG9hdCBvcGFjaXR5O1xyXG5cclxudmFyeWluZyB2ZWMzIHZXb3JsZERpcmVjdGlvbjtcclxuXHJcbnZvaWQgbWFpbigpIHtcclxuXHJcblx0dmVjNCB0ZXhDb2xvciA9IHRleHR1cmVDdWJlKCB0Q3ViZSwgdmVjMyggdEZsaXAgKiB2V29ybGREaXJlY3Rpb24ueCwgdldvcmxkRGlyZWN0aW9uLnl6ICkgKTtcclxuXHJcblx0Z2xfRnJhZ0NvbG9yID0gdGV4Q29sb3I7XHJcblx0Z2xfRnJhZ0NvbG9yLmEgKj0gb3BhY2l0eTtcclxuXHJcblx0I2luY2x1ZGUgPHRvbmVtYXBwaW5nX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxjb2xvcnNwYWNlX2ZyYWdtZW50PlxyXG5cclxufVxyXG5gO1xyXG4iLCJleHBvcnQgY29uc3QgdmVydGV4ID0gLyogZ2xzbCAqL2BcclxuI2luY2x1ZGUgPGNvbW1vbj5cclxuI2luY2x1ZGUgPGJhdGNoaW5nX3BhcnNfdmVydGV4PlxyXG4jaW5jbHVkZSA8dXZfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxkaXNwbGFjZW1lbnRtYXBfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxtb3JwaHRhcmdldF9wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPHNraW5uaW5nX3BhcnNfdmVydGV4PlxyXG4jaW5jbHVkZSA8bG9nZGVwdGhidWZfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxjbGlwcGluZ19wbGFuZXNfcGFyc192ZXJ0ZXg+XHJcblxyXG4vLyBUaGlzIGlzIHVzZWQgZm9yIGNvbXB1dGluZyBhbiBlcXVpdmFsZW50IG9mIGdsX0ZyYWdDb29yZC56IHRoYXQgaXMgYXMgaGlnaCBwcmVjaXNpb24gYXMgcG9zc2libGUuXHJcbi8vIFNvbWUgcGxhdGZvcm1zIGNvbXB1dGUgZ2xfRnJhZ0Nvb3JkIGF0IGEgbG93ZXIgcHJlY2lzaW9uIHdoaWNoIG1ha2VzIHRoZSBtYW51YWxseSBjb21wdXRlZCB2YWx1ZSBiZXR0ZXIgZm9yXHJcbi8vIGRlcHRoLWJhc2VkIHBvc3Rwcm9jZXNzaW5nIGVmZmVjdHMuIFJlcHJvZHVjZWQgb24gaVBhZCB3aXRoIEExMCBwcm9jZXNzb3IgLyBpUGFkT1MgMTMuMy4xLlxyXG52YXJ5aW5nIHZlYzIgdkhpZ2hQcmVjaXNpb25aVztcclxuXHJcbnZvaWQgbWFpbigpIHtcclxuXHJcblx0I2luY2x1ZGUgPHV2X3ZlcnRleD5cclxuXHJcblx0I2luY2x1ZGUgPGJhdGNoaW5nX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8c2tpbmJhc2VfdmVydGV4PlxyXG5cclxuXHQjaWZkZWYgVVNFX0RJU1BMQUNFTUVOVE1BUFxyXG5cclxuXHRcdCNpbmNsdWRlIDxiZWdpbm5vcm1hbF92ZXJ0ZXg+XHJcblx0XHQjaW5jbHVkZSA8bW9ycGhub3JtYWxfdmVydGV4PlxyXG5cdFx0I2luY2x1ZGUgPHNraW5ub3JtYWxfdmVydGV4PlxyXG5cclxuXHQjZW5kaWZcclxuXHJcblx0I2luY2x1ZGUgPGJlZ2luX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8bW9ycGh0YXJnZXRfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxza2lubmluZ192ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPGRpc3BsYWNlbWVudG1hcF92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPHByb2plY3RfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc192ZXJ0ZXg+XHJcblxyXG5cdHZIaWdoUHJlY2lzaW9uWlcgPSBnbF9Qb3NpdGlvbi56dztcclxuXHJcbn1cclxuYDtcclxuXHJcbmV4cG9ydCBjb25zdCBmcmFnbWVudCA9IC8qIGdsc2wgKi9gXHJcbiNpZiBERVBUSF9QQUNLSU5HID09IDMyMDBcclxuXHJcblx0dW5pZm9ybSBmbG9hdCBvcGFjaXR5O1xyXG5cclxuI2VuZGlmXHJcblxyXG4jaW5jbHVkZSA8Y29tbW9uPlxyXG4jaW5jbHVkZSA8cGFja2luZz5cclxuI2luY2x1ZGUgPHV2X3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxtYXBfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGFscGhhbWFwX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxhbHBoYXRlc3RfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGFscGhhaGFzaF9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8bG9nZGVwdGhidWZfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc19wYXJzX2ZyYWdtZW50PlxyXG5cclxudmFyeWluZyB2ZWMyIHZIaWdoUHJlY2lzaW9uWlc7XHJcblxyXG52b2lkIG1haW4oKSB7XHJcblxyXG5cdHZlYzQgZGlmZnVzZUNvbG9yID0gdmVjNCggMS4wICk7XHJcblx0I2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc19mcmFnbWVudD5cclxuXHJcblx0I2lmIERFUFRIX1BBQ0tJTkcgPT0gMzIwMFxyXG5cclxuXHRcdGRpZmZ1c2VDb2xvci5hID0gb3BhY2l0eTtcclxuXHJcblx0I2VuZGlmXHJcblxyXG5cdCNpbmNsdWRlIDxtYXBfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPGFscGhhbWFwX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxhbHBoYXRlc3RfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPGFscGhhaGFzaF9mcmFnbWVudD5cclxuXHJcblx0I2luY2x1ZGUgPGxvZ2RlcHRoYnVmX2ZyYWdtZW50PlxyXG5cclxuXHQvLyBIaWdoZXIgcHJlY2lzaW9uIGVxdWl2YWxlbnQgb2YgZ2xfRnJhZ0Nvb3JkLnouIFRoaXMgYXNzdW1lcyBkZXB0aFJhbmdlIGhhcyBiZWVuIGxlZnQgdG8gaXRzIGRlZmF1bHQgdmFsdWVzLlxyXG5cdGZsb2F0IGZyYWdDb29yZFogPSAwLjUgKiB2SGlnaFByZWNpc2lvblpXWzBdIC8gdkhpZ2hQcmVjaXNpb25aV1sxXSArIDAuNTtcclxuXHJcblx0I2lmIERFUFRIX1BBQ0tJTkcgPT0gMzIwMFxyXG5cclxuXHRcdGdsX0ZyYWdDb2xvciA9IHZlYzQoIHZlYzMoIDEuMCAtIGZyYWdDb29yZFogKSwgb3BhY2l0eSApO1xyXG5cclxuXHQjZWxpZiBERVBUSF9QQUNLSU5HID09IDMyMDFcclxuXHJcblx0XHRnbF9GcmFnQ29sb3IgPSBwYWNrRGVwdGhUb1JHQkEoIGZyYWdDb29yZFogKTtcclxuXHJcblx0I2VuZGlmXHJcblxyXG59XHJcbmA7XHJcbiIsImV4cG9ydCBjb25zdCB2ZXJ0ZXggPSAvKiBnbHNsICovYFxyXG4jZGVmaW5lIERJU1RBTkNFXHJcblxyXG52YXJ5aW5nIHZlYzMgdldvcmxkUG9zaXRpb247XHJcblxyXG4jaW5jbHVkZSA8Y29tbW9uPlxyXG4jaW5jbHVkZSA8YmF0Y2hpbmdfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDx1dl9wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPGRpc3BsYWNlbWVudG1hcF9wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPG1vcnBodGFyZ2V0X3BhcnNfdmVydGV4PlxyXG4jaW5jbHVkZSA8c2tpbm5pbmdfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxjbGlwcGluZ19wbGFuZXNfcGFyc192ZXJ0ZXg+XHJcblxyXG52b2lkIG1haW4oKSB7XHJcblxyXG5cdCNpbmNsdWRlIDx1dl92ZXJ0ZXg+XHJcblxyXG5cdCNpbmNsdWRlIDxiYXRjaGluZ192ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPHNraW5iYXNlX3ZlcnRleD5cclxuXHJcblx0I2lmZGVmIFVTRV9ESVNQTEFDRU1FTlRNQVBcclxuXHJcblx0XHQjaW5jbHVkZSA8YmVnaW5ub3JtYWxfdmVydGV4PlxyXG5cdFx0I2luY2x1ZGUgPG1vcnBobm9ybWFsX3ZlcnRleD5cclxuXHRcdCNpbmNsdWRlIDxza2lubm9ybWFsX3ZlcnRleD5cclxuXHJcblx0I2VuZGlmXHJcblxyXG5cdCNpbmNsdWRlIDxiZWdpbl92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPG1vcnBodGFyZ2V0X3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8c2tpbm5pbmdfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxkaXNwbGFjZW1lbnRtYXBfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxwcm9qZWN0X3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8d29ybGRwb3NfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxjbGlwcGluZ19wbGFuZXNfdmVydGV4PlxyXG5cclxuXHR2V29ybGRQb3NpdGlvbiA9IHdvcmxkUG9zaXRpb24ueHl6O1xyXG5cclxufVxyXG5gO1xyXG5cclxuZXhwb3J0IGNvbnN0IGZyYWdtZW50ID0gLyogZ2xzbCAqL2BcclxuI2RlZmluZSBESVNUQU5DRVxyXG5cclxudW5pZm9ybSB2ZWMzIHJlZmVyZW5jZVBvc2l0aW9uO1xyXG51bmlmb3JtIGZsb2F0IG5lYXJEaXN0YW5jZTtcclxudW5pZm9ybSBmbG9hdCBmYXJEaXN0YW5jZTtcclxudmFyeWluZyB2ZWMzIHZXb3JsZFBvc2l0aW9uO1xyXG5cclxuI2luY2x1ZGUgPGNvbW1vbj5cclxuI2luY2x1ZGUgPHBhY2tpbmc+XHJcbiNpbmNsdWRlIDx1dl9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8bWFwX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxhbHBoYW1hcF9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8YWxwaGF0ZXN0X3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxhbHBoYWhhc2hfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc19wYXJzX2ZyYWdtZW50PlxyXG5cclxudm9pZCBtYWluICgpIHtcclxuXHJcblx0dmVjNCBkaWZmdXNlQ29sb3IgPSB2ZWM0KCAxLjAgKTtcclxuXHQjaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX2ZyYWdtZW50PlxyXG5cclxuXHQjaW5jbHVkZSA8bWFwX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxhbHBoYW1hcF9mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8YWxwaGF0ZXN0X2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxhbHBoYWhhc2hfZnJhZ21lbnQ+XHJcblxyXG5cdGZsb2F0IGRpc3QgPSBsZW5ndGgoIHZXb3JsZFBvc2l0aW9uIC0gcmVmZXJlbmNlUG9zaXRpb24gKTtcclxuXHRkaXN0ID0gKCBkaXN0IC0gbmVhckRpc3RhbmNlICkgLyAoIGZhckRpc3RhbmNlIC0gbmVhckRpc3RhbmNlICk7XHJcblx0ZGlzdCA9IHNhdHVyYXRlKCBkaXN0ICk7IC8vIGNsYW1wIHRvIFsgMCwgMSBdXHJcblxyXG5cdGdsX0ZyYWdDb2xvciA9IHBhY2tEZXB0aFRvUkdCQSggZGlzdCApO1xyXG5cclxufVxyXG5gO1xyXG4iLCJleHBvcnQgY29uc3QgdmVydGV4ID0gLyogZ2xzbCAqL2BcclxudmFyeWluZyB2ZWMzIHZXb3JsZERpcmVjdGlvbjtcclxuXHJcbiNpbmNsdWRlIDxjb21tb24+XHJcblxyXG52b2lkIG1haW4oKSB7XHJcblxyXG5cdHZXb3JsZERpcmVjdGlvbiA9IHRyYW5zZm9ybURpcmVjdGlvbiggcG9zaXRpb24sIG1vZGVsTWF0cml4ICk7XHJcblxyXG5cdCNpbmNsdWRlIDxiZWdpbl92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPHByb2plY3RfdmVydGV4PlxyXG5cclxufVxyXG5gO1xyXG5cclxuZXhwb3J0IGNvbnN0IGZyYWdtZW50ID0gLyogZ2xzbCAqL2BcclxudW5pZm9ybSBzYW1wbGVyMkQgdEVxdWlyZWN0O1xyXG5cclxudmFyeWluZyB2ZWMzIHZXb3JsZERpcmVjdGlvbjtcclxuXHJcbiNpbmNsdWRlIDxjb21tb24+XHJcblxyXG52b2lkIG1haW4oKSB7XHJcblxyXG5cdHZlYzMgZGlyZWN0aW9uID0gbm9ybWFsaXplKCB2V29ybGREaXJlY3Rpb24gKTtcclxuXHJcblx0dmVjMiBzYW1wbGVVViA9IGVxdWlyZWN0VXYoIGRpcmVjdGlvbiApO1xyXG5cclxuXHRnbF9GcmFnQ29sb3IgPSB0ZXh0dXJlMkQoIHRFcXVpcmVjdCwgc2FtcGxlVVYgKTtcclxuXHJcblx0I2luY2x1ZGUgPHRvbmVtYXBwaW5nX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxjb2xvcnNwYWNlX2ZyYWdtZW50PlxyXG5cclxufVxyXG5gO1xyXG4iLCJleHBvcnQgY29uc3QgdmVydGV4ID0gLyogZ2xzbCAqL2BcclxudW5pZm9ybSBmbG9hdCBzY2FsZTtcclxuYXR0cmlidXRlIGZsb2F0IGxpbmVEaXN0YW5jZTtcclxuXHJcbnZhcnlpbmcgZmxvYXQgdkxpbmVEaXN0YW5jZTtcclxuXHJcbiNpbmNsdWRlIDxjb21tb24+XHJcbiNpbmNsdWRlIDx1dl9wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPGNvbG9yX3BhcnNfdmVydGV4PlxyXG4jaW5jbHVkZSA8Zm9nX3BhcnNfdmVydGV4PlxyXG4jaW5jbHVkZSA8bW9ycGh0YXJnZXRfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl9wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc19wYXJzX3ZlcnRleD5cclxuXHJcbnZvaWQgbWFpbigpIHtcclxuXHJcblx0dkxpbmVEaXN0YW5jZSA9IHNjYWxlICogbGluZURpc3RhbmNlO1xyXG5cclxuXHQjaW5jbHVkZSA8dXZfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxjb2xvcl92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPG1vcnBoY29sb3JfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxiZWdpbl92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPG1vcnBodGFyZ2V0X3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8cHJvamVjdF92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPGxvZ2RlcHRoYnVmX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8Zm9nX3ZlcnRleD5cclxuXHJcbn1cclxuYDtcclxuXHJcbmV4cG9ydCBjb25zdCBmcmFnbWVudCA9IC8qIGdsc2wgKi9gXHJcbnVuaWZvcm0gdmVjMyBkaWZmdXNlO1xyXG51bmlmb3JtIGZsb2F0IG9wYWNpdHk7XHJcblxyXG51bmlmb3JtIGZsb2F0IGRhc2hTaXplO1xyXG51bmlmb3JtIGZsb2F0IHRvdGFsU2l6ZTtcclxuXHJcbnZhcnlpbmcgZmxvYXQgdkxpbmVEaXN0YW5jZTtcclxuXHJcbiNpbmNsdWRlIDxjb21tb24+XHJcbiNpbmNsdWRlIDxjb2xvcl9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8dXZfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPG1hcF9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8Zm9nX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX3BhcnNfZnJhZ21lbnQ+XHJcblxyXG52b2lkIG1haW4oKSB7XHJcblxyXG5cdHZlYzQgZGlmZnVzZUNvbG9yID0gdmVjNCggZGlmZnVzZSwgb3BhY2l0eSApO1xyXG5cdCNpbmNsdWRlIDxjbGlwcGluZ19wbGFuZXNfZnJhZ21lbnQ+XHJcblxyXG5cdGlmICggbW9kKCB2TGluZURpc3RhbmNlLCB0b3RhbFNpemUgKSA+IGRhc2hTaXplICkge1xyXG5cclxuXHRcdGRpc2NhcmQ7XHJcblxyXG5cdH1cclxuXHJcblx0dmVjMyBvdXRnb2luZ0xpZ2h0ID0gdmVjMyggMC4wICk7XHJcblxyXG5cdCNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl9mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8bWFwX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxjb2xvcl9mcmFnbWVudD5cclxuXHJcblx0b3V0Z29pbmdMaWdodCA9IGRpZmZ1c2VDb2xvci5yZ2I7IC8vIHNpbXBsZSBzaGFkZXJcclxuXHJcblx0I2luY2x1ZGUgPG9wYXF1ZV9mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8dG9uZW1hcHBpbmdfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPGNvbG9yc3BhY2VfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPGZvZ19mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8cHJlbXVsdGlwbGllZF9hbHBoYV9mcmFnbWVudD5cclxuXHJcbn1cclxuYDtcclxuIiwiZXhwb3J0IGNvbnN0IHZlcnRleCA9IC8qIGdsc2wgKi9gXHJcbiNpbmNsdWRlIDxjb21tb24+XHJcbiNpbmNsdWRlIDxiYXRjaGluZ19wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPHV2X3BhcnNfdmVydGV4PlxyXG4jaW5jbHVkZSA8ZW52bWFwX3BhcnNfdmVydGV4PlxyXG4jaW5jbHVkZSA8Y29sb3JfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxmb2dfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxtb3JwaHRhcmdldF9wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPHNraW5uaW5nX3BhcnNfdmVydGV4PlxyXG4jaW5jbHVkZSA8bG9nZGVwdGhidWZfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxjbGlwcGluZ19wbGFuZXNfcGFyc192ZXJ0ZXg+XHJcblxyXG52b2lkIG1haW4oKSB7XHJcblxyXG5cdCNpbmNsdWRlIDx1dl92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPGNvbG9yX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8bW9ycGhjb2xvcl92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPGJhdGNoaW5nX3ZlcnRleD5cclxuXHJcblx0I2lmIGRlZmluZWQgKCBVU0VfRU5WTUFQICkgfHwgZGVmaW5lZCAoIFVTRV9TS0lOTklORyApXHJcblxyXG5cdFx0I2luY2x1ZGUgPGJlZ2lubm9ybWFsX3ZlcnRleD5cclxuXHRcdCNpbmNsdWRlIDxtb3JwaG5vcm1hbF92ZXJ0ZXg+XHJcblx0XHQjaW5jbHVkZSA8c2tpbmJhc2VfdmVydGV4PlxyXG5cdFx0I2luY2x1ZGUgPHNraW5ub3JtYWxfdmVydGV4PlxyXG5cdFx0I2luY2x1ZGUgPGRlZmF1bHRub3JtYWxfdmVydGV4PlxyXG5cclxuXHQjZW5kaWZcclxuXHJcblx0I2luY2x1ZGUgPGJlZ2luX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8bW9ycGh0YXJnZXRfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxza2lubmluZ192ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPHByb2plY3RfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc192ZXJ0ZXg+XHJcblxyXG5cdCNpbmNsdWRlIDx3b3JsZHBvc192ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPGVudm1hcF92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPGZvZ192ZXJ0ZXg+XHJcblxyXG59XHJcbmA7XHJcblxyXG5leHBvcnQgY29uc3QgZnJhZ21lbnQgPSAvKiBnbHNsICovYFxyXG51bmlmb3JtIHZlYzMgZGlmZnVzZTtcclxudW5pZm9ybSBmbG9hdCBvcGFjaXR5O1xyXG5cclxuI2lmbmRlZiBGTEFUX1NIQURFRFxyXG5cclxuXHR2YXJ5aW5nIHZlYzMgdk5vcm1hbDtcclxuXHJcbiNlbmRpZlxyXG5cclxuI2luY2x1ZGUgPGNvbW1vbj5cclxuI2luY2x1ZGUgPGRpdGhlcmluZ19wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8Y29sb3JfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPHV2X3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxtYXBfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGFscGhhbWFwX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxhbHBoYXRlc3RfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGFscGhhaGFzaF9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8YW9tYXBfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGxpZ2h0bWFwX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxlbnZtYXBfY29tbW9uX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxlbnZtYXBfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGZvZ19wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8c3BlY3VsYXJtYXBfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGxvZ2RlcHRoYnVmX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxjbGlwcGluZ19wbGFuZXNfcGFyc19mcmFnbWVudD5cclxuXHJcbnZvaWQgbWFpbigpIHtcclxuXHJcblx0dmVjNCBkaWZmdXNlQ29sb3IgPSB2ZWM0KCBkaWZmdXNlLCBvcGFjaXR5ICk7XHJcblx0I2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc19mcmFnbWVudD5cclxuXHJcblx0I2luY2x1ZGUgPGxvZ2RlcHRoYnVmX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxtYXBfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPGNvbG9yX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxhbHBoYW1hcF9mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8YWxwaGF0ZXN0X2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxhbHBoYWhhc2hfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPHNwZWN1bGFybWFwX2ZyYWdtZW50PlxyXG5cclxuXHRSZWZsZWN0ZWRMaWdodCByZWZsZWN0ZWRMaWdodCA9IFJlZmxlY3RlZExpZ2h0KCB2ZWMzKCAwLjAgKSwgdmVjMyggMC4wICksIHZlYzMoIDAuMCApLCB2ZWMzKCAwLjAgKSApO1xyXG5cclxuXHQvLyBhY2N1bXVsYXRpb24gKGJha2VkIGluZGlyZWN0IGxpZ2h0aW5nIG9ubHkpXHJcblx0I2lmZGVmIFVTRV9MSUdIVE1BUFxyXG5cclxuXHRcdHZlYzQgbGlnaHRNYXBUZXhlbCA9IHRleHR1cmUyRCggbGlnaHRNYXAsIHZMaWdodE1hcFV2ICk7XHJcblx0XHRyZWZsZWN0ZWRMaWdodC5pbmRpcmVjdERpZmZ1c2UgKz0gbGlnaHRNYXBUZXhlbC5yZ2IgKiBsaWdodE1hcEludGVuc2l0eSAqIFJFQ0lQUk9DQUxfUEk7XHJcblxyXG5cdCNlbHNlXHJcblxyXG5cdFx0cmVmbGVjdGVkTGlnaHQuaW5kaXJlY3REaWZmdXNlICs9IHZlYzMoIDEuMCApO1xyXG5cclxuXHQjZW5kaWZcclxuXHJcblx0Ly8gbW9kdWxhdGlvblxyXG5cdCNpbmNsdWRlIDxhb21hcF9mcmFnbWVudD5cclxuXHJcblx0cmVmbGVjdGVkTGlnaHQuaW5kaXJlY3REaWZmdXNlICo9IGRpZmZ1c2VDb2xvci5yZ2I7XHJcblxyXG5cdHZlYzMgb3V0Z29pbmdMaWdodCA9IHJlZmxlY3RlZExpZ2h0LmluZGlyZWN0RGlmZnVzZTtcclxuXHJcblx0I2luY2x1ZGUgPGVudm1hcF9mcmFnbWVudD5cclxuXHJcblx0I2luY2x1ZGUgPG9wYXF1ZV9mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8dG9uZW1hcHBpbmdfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPGNvbG9yc3BhY2VfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPGZvZ19mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8cHJlbXVsdGlwbGllZF9hbHBoYV9mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8ZGl0aGVyaW5nX2ZyYWdtZW50PlxyXG5cclxufVxyXG5gO1xyXG4iLCJleHBvcnQgY29uc3QgdmVydGV4ID0gLyogZ2xzbCAqL2BcclxuI2RlZmluZSBMQU1CRVJUXHJcblxyXG52YXJ5aW5nIHZlYzMgdlZpZXdQb3NpdGlvbjtcclxuXHJcbiNpbmNsdWRlIDxjb21tb24+XHJcbiNpbmNsdWRlIDxiYXRjaGluZ19wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPHV2X3BhcnNfdmVydGV4PlxyXG4jaW5jbHVkZSA8ZGlzcGxhY2VtZW50bWFwX3BhcnNfdmVydGV4PlxyXG4jaW5jbHVkZSA8ZW52bWFwX3BhcnNfdmVydGV4PlxyXG4jaW5jbHVkZSA8Y29sb3JfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxmb2dfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxub3JtYWxfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxtb3JwaHRhcmdldF9wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPHNraW5uaW5nX3BhcnNfdmVydGV4PlxyXG4jaW5jbHVkZSA8c2hhZG93bWFwX3BhcnNfdmVydGV4PlxyXG4jaW5jbHVkZSA8bG9nZGVwdGhidWZfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxjbGlwcGluZ19wbGFuZXNfcGFyc192ZXJ0ZXg+XHJcblxyXG52b2lkIG1haW4oKSB7XHJcblxyXG5cdCNpbmNsdWRlIDx1dl92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPGNvbG9yX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8bW9ycGhjb2xvcl92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPGJhdGNoaW5nX3ZlcnRleD5cclxuXHJcblx0I2luY2x1ZGUgPGJlZ2lubm9ybWFsX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8bW9ycGhub3JtYWxfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxza2luYmFzZV92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPHNraW5ub3JtYWxfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxkZWZhdWx0bm9ybWFsX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8bm9ybWFsX3ZlcnRleD5cclxuXHJcblx0I2luY2x1ZGUgPGJlZ2luX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8bW9ycGh0YXJnZXRfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxza2lubmluZ192ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPGRpc3BsYWNlbWVudG1hcF92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPHByb2plY3RfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc192ZXJ0ZXg+XHJcblxyXG5cdHZWaWV3UG9zaXRpb24gPSAtIG12UG9zaXRpb24ueHl6O1xyXG5cclxuXHQjaW5jbHVkZSA8d29ybGRwb3NfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxlbnZtYXBfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxzaGFkb3dtYXBfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxmb2dfdmVydGV4PlxyXG5cclxufVxyXG5gO1xyXG5cclxuZXhwb3J0IGNvbnN0IGZyYWdtZW50ID0gLyogZ2xzbCAqL2BcclxuI2RlZmluZSBMQU1CRVJUXHJcblxyXG51bmlmb3JtIHZlYzMgZGlmZnVzZTtcclxudW5pZm9ybSB2ZWMzIGVtaXNzaXZlO1xyXG51bmlmb3JtIGZsb2F0IG9wYWNpdHk7XHJcblxyXG4jaW5jbHVkZSA8Y29tbW9uPlxyXG4jaW5jbHVkZSA8cGFja2luZz5cclxuI2luY2x1ZGUgPGRpdGhlcmluZ19wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8Y29sb3JfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPHV2X3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxtYXBfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGFscGhhbWFwX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxhbHBoYXRlc3RfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGFscGhhaGFzaF9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8YW9tYXBfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGxpZ2h0bWFwX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxlbWlzc2l2ZW1hcF9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8ZW52bWFwX2NvbW1vbl9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8ZW52bWFwX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxmb2dfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGJzZGZzPlxyXG4jaW5jbHVkZSA8bGlnaHRzX3BhcnNfYmVnaW4+XHJcbiNpbmNsdWRlIDxub3JtYWxfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGxpZ2h0c19sYW1iZXJ0X3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxzaGFkb3dtYXBfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGJ1bXBtYXBfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPG5vcm1hbG1hcF9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8c3BlY3VsYXJtYXBfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGxvZ2RlcHRoYnVmX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxjbGlwcGluZ19wbGFuZXNfcGFyc19mcmFnbWVudD5cclxuXHJcbnZvaWQgbWFpbigpIHtcclxuXHJcblx0dmVjNCBkaWZmdXNlQ29sb3IgPSB2ZWM0KCBkaWZmdXNlLCBvcGFjaXR5ICk7XHJcblx0I2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc19mcmFnbWVudD5cclxuXHJcblx0UmVmbGVjdGVkTGlnaHQgcmVmbGVjdGVkTGlnaHQgPSBSZWZsZWN0ZWRMaWdodCggdmVjMyggMC4wICksIHZlYzMoIDAuMCApLCB2ZWMzKCAwLjAgKSwgdmVjMyggMC4wICkgKTtcclxuXHR2ZWMzIHRvdGFsRW1pc3NpdmVSYWRpYW5jZSA9IGVtaXNzaXZlO1xyXG5cclxuXHQjaW5jbHVkZSA8bG9nZGVwdGhidWZfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPG1hcF9mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8Y29sb3JfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPGFscGhhbWFwX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxhbHBoYXRlc3RfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPGFscGhhaGFzaF9mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8c3BlY3VsYXJtYXBfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPG5vcm1hbF9mcmFnbWVudF9iZWdpbj5cclxuXHQjaW5jbHVkZSA8bm9ybWFsX2ZyYWdtZW50X21hcHM+XHJcblx0I2luY2x1ZGUgPGVtaXNzaXZlbWFwX2ZyYWdtZW50PlxyXG5cclxuXHQvLyBhY2N1bXVsYXRpb25cclxuXHQjaW5jbHVkZSA8bGlnaHRzX2xhbWJlcnRfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPGxpZ2h0c19mcmFnbWVudF9iZWdpbj5cclxuXHQjaW5jbHVkZSA8bGlnaHRzX2ZyYWdtZW50X21hcHM+XHJcblx0I2luY2x1ZGUgPGxpZ2h0c19mcmFnbWVudF9lbmQ+XHJcblxyXG5cdC8vIG1vZHVsYXRpb25cclxuXHQjaW5jbHVkZSA8YW9tYXBfZnJhZ21lbnQ+XHJcblxyXG5cdHZlYzMgb3V0Z29pbmdMaWdodCA9IHJlZmxlY3RlZExpZ2h0LmRpcmVjdERpZmZ1c2UgKyByZWZsZWN0ZWRMaWdodC5pbmRpcmVjdERpZmZ1c2UgKyB0b3RhbEVtaXNzaXZlUmFkaWFuY2U7XHJcblxyXG5cdCNpbmNsdWRlIDxlbnZtYXBfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPG9wYXF1ZV9mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8dG9uZW1hcHBpbmdfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPGNvbG9yc3BhY2VfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPGZvZ19mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8cHJlbXVsdGlwbGllZF9hbHBoYV9mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8ZGl0aGVyaW5nX2ZyYWdtZW50PlxyXG5cclxufVxyXG5gO1xyXG4iLCJleHBvcnQgY29uc3QgdmVydGV4ID0gLyogZ2xzbCAqL2BcclxuI2RlZmluZSBNQVRDQVBcclxuXHJcbnZhcnlpbmcgdmVjMyB2Vmlld1Bvc2l0aW9uO1xyXG5cclxuI2luY2x1ZGUgPGNvbW1vbj5cclxuI2luY2x1ZGUgPGJhdGNoaW5nX3BhcnNfdmVydGV4PlxyXG4jaW5jbHVkZSA8dXZfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxjb2xvcl9wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPGRpc3BsYWNlbWVudG1hcF9wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPGZvZ19wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPG5vcm1hbF9wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPG1vcnBodGFyZ2V0X3BhcnNfdmVydGV4PlxyXG4jaW5jbHVkZSA8c2tpbm5pbmdfcGFyc192ZXJ0ZXg+XHJcblxyXG4jaW5jbHVkZSA8bG9nZGVwdGhidWZfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxjbGlwcGluZ19wbGFuZXNfcGFyc192ZXJ0ZXg+XHJcblxyXG52b2lkIG1haW4oKSB7XHJcblxyXG5cdCNpbmNsdWRlIDx1dl92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPGNvbG9yX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8bW9ycGhjb2xvcl92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPGJhdGNoaW5nX3ZlcnRleD5cclxuXHJcblx0I2luY2x1ZGUgPGJlZ2lubm9ybWFsX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8bW9ycGhub3JtYWxfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxza2luYmFzZV92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPHNraW5ub3JtYWxfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxkZWZhdWx0bm9ybWFsX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8bm9ybWFsX3ZlcnRleD5cclxuXHJcblx0I2luY2x1ZGUgPGJlZ2luX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8bW9ycGh0YXJnZXRfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxza2lubmluZ192ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPGRpc3BsYWNlbWVudG1hcF92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPHByb2plY3RfdmVydGV4PlxyXG5cclxuXHQjaW5jbHVkZSA8bG9nZGVwdGhidWZfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxjbGlwcGluZ19wbGFuZXNfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxmb2dfdmVydGV4PlxyXG5cclxuXHR2Vmlld1Bvc2l0aW9uID0gLSBtdlBvc2l0aW9uLnh5ejtcclxuXHJcbn1cclxuYDtcclxuXHJcbmV4cG9ydCBjb25zdCBmcmFnbWVudCA9IC8qIGdsc2wgKi9gXHJcbiNkZWZpbmUgTUFUQ0FQXHJcblxyXG51bmlmb3JtIHZlYzMgZGlmZnVzZTtcclxudW5pZm9ybSBmbG9hdCBvcGFjaXR5O1xyXG51bmlmb3JtIHNhbXBsZXIyRCBtYXRjYXA7XHJcblxyXG52YXJ5aW5nIHZlYzMgdlZpZXdQb3NpdGlvbjtcclxuXHJcbiNpbmNsdWRlIDxjb21tb24+XHJcbiNpbmNsdWRlIDxkaXRoZXJpbmdfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGNvbG9yX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDx1dl9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8bWFwX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxhbHBoYW1hcF9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8YWxwaGF0ZXN0X3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxhbHBoYWhhc2hfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGZvZ19wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8bm9ybWFsX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxidW1wbWFwX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxub3JtYWxtYXBfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGxvZ2RlcHRoYnVmX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxjbGlwcGluZ19wbGFuZXNfcGFyc19mcmFnbWVudD5cclxuXHJcbnZvaWQgbWFpbigpIHtcclxuXHJcblx0dmVjNCBkaWZmdXNlQ29sb3IgPSB2ZWM0KCBkaWZmdXNlLCBvcGFjaXR5ICk7XHJcblx0I2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc19mcmFnbWVudD5cclxuXHJcblx0I2luY2x1ZGUgPGxvZ2RlcHRoYnVmX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxtYXBfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPGNvbG9yX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxhbHBoYW1hcF9mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8YWxwaGF0ZXN0X2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxhbHBoYWhhc2hfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPG5vcm1hbF9mcmFnbWVudF9iZWdpbj5cclxuXHQjaW5jbHVkZSA8bm9ybWFsX2ZyYWdtZW50X21hcHM+XHJcblxyXG5cdHZlYzMgdmlld0RpciA9IG5vcm1hbGl6ZSggdlZpZXdQb3NpdGlvbiApO1xyXG5cdHZlYzMgeCA9IG5vcm1hbGl6ZSggdmVjMyggdmlld0Rpci56LCAwLjAsIC0gdmlld0Rpci54ICkgKTtcclxuXHR2ZWMzIHkgPSBjcm9zcyggdmlld0RpciwgeCApO1xyXG5cdHZlYzIgdXYgPSB2ZWMyKCBkb3QoIHgsIG5vcm1hbCApLCBkb3QoIHksIG5vcm1hbCApICkgKiAwLjQ5NSArIDAuNTsgLy8gMC40OTUgdG8gcmVtb3ZlIGFydGlmYWN0cyBjYXVzZWQgYnkgdW5kZXJzaXplZCBtYXRjYXAgZGlza3NcclxuXHJcblx0I2lmZGVmIFVTRV9NQVRDQVBcclxuXHJcblx0XHR2ZWM0IG1hdGNhcENvbG9yID0gdGV4dHVyZTJEKCBtYXRjYXAsIHV2ICk7XHJcblxyXG5cdCNlbHNlXHJcblxyXG5cdFx0dmVjNCBtYXRjYXBDb2xvciA9IHZlYzQoIHZlYzMoIG1peCggMC4yLCAwLjgsIHV2LnkgKSApLCAxLjAgKTsgLy8gZGVmYXVsdCBpZiBtYXRjYXAgaXMgbWlzc2luZ1xyXG5cclxuXHQjZW5kaWZcclxuXHJcblx0dmVjMyBvdXRnb2luZ0xpZ2h0ID0gZGlmZnVzZUNvbG9yLnJnYiAqIG1hdGNhcENvbG9yLnJnYjtcclxuXHJcblx0I2luY2x1ZGUgPG9wYXF1ZV9mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8dG9uZW1hcHBpbmdfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPGNvbG9yc3BhY2VfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPGZvZ19mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8cHJlbXVsdGlwbGllZF9hbHBoYV9mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8ZGl0aGVyaW5nX2ZyYWdtZW50PlxyXG5cclxufVxyXG5gO1xyXG4iLCJleHBvcnQgY29uc3QgdmVydGV4ID0gLyogZ2xzbCAqL2BcclxuI2RlZmluZSBOT1JNQUxcclxuXHJcbiNpZiBkZWZpbmVkKCBGTEFUX1NIQURFRCApIHx8IGRlZmluZWQoIFVTRV9CVU1QTUFQICkgfHwgZGVmaW5lZCggVVNFX05PUk1BTE1BUF9UQU5HRU5UU1BBQ0UgKVxyXG5cclxuXHR2YXJ5aW5nIHZlYzMgdlZpZXdQb3NpdGlvbjtcclxuXHJcbiNlbmRpZlxyXG5cclxuI2luY2x1ZGUgPGNvbW1vbj5cclxuI2luY2x1ZGUgPGJhdGNoaW5nX3BhcnNfdmVydGV4PlxyXG4jaW5jbHVkZSA8dXZfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxkaXNwbGFjZW1lbnRtYXBfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxub3JtYWxfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxtb3JwaHRhcmdldF9wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPHNraW5uaW5nX3BhcnNfdmVydGV4PlxyXG4jaW5jbHVkZSA8bG9nZGVwdGhidWZfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxjbGlwcGluZ19wbGFuZXNfcGFyc192ZXJ0ZXg+XHJcblxyXG52b2lkIG1haW4oKSB7XHJcblxyXG5cdCNpbmNsdWRlIDx1dl92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPGJhdGNoaW5nX3ZlcnRleD5cclxuXHJcblx0I2luY2x1ZGUgPGJlZ2lubm9ybWFsX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8bW9ycGhub3JtYWxfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxza2luYmFzZV92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPHNraW5ub3JtYWxfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxkZWZhdWx0bm9ybWFsX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8bm9ybWFsX3ZlcnRleD5cclxuXHJcblx0I2luY2x1ZGUgPGJlZ2luX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8bW9ycGh0YXJnZXRfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxza2lubmluZ192ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPGRpc3BsYWNlbWVudG1hcF92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPHByb2plY3RfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc192ZXJ0ZXg+XHJcblxyXG4jaWYgZGVmaW5lZCggRkxBVF9TSEFERUQgKSB8fCBkZWZpbmVkKCBVU0VfQlVNUE1BUCApIHx8IGRlZmluZWQoIFVTRV9OT1JNQUxNQVBfVEFOR0VOVFNQQUNFIClcclxuXHJcblx0dlZpZXdQb3NpdGlvbiA9IC0gbXZQb3NpdGlvbi54eXo7XHJcblxyXG4jZW5kaWZcclxuXHJcbn1cclxuYDtcclxuXHJcbmV4cG9ydCBjb25zdCBmcmFnbWVudCA9IC8qIGdsc2wgKi9gXHJcbiNkZWZpbmUgTk9STUFMXHJcblxyXG51bmlmb3JtIGZsb2F0IG9wYWNpdHk7XHJcblxyXG4jaWYgZGVmaW5lZCggRkxBVF9TSEFERUQgKSB8fCBkZWZpbmVkKCBVU0VfQlVNUE1BUCApIHx8IGRlZmluZWQoIFVTRV9OT1JNQUxNQVBfVEFOR0VOVFNQQUNFIClcclxuXHJcblx0dmFyeWluZyB2ZWMzIHZWaWV3UG9zaXRpb247XHJcblxyXG4jZW5kaWZcclxuXHJcbiNpbmNsdWRlIDxwYWNraW5nPlxyXG4jaW5jbHVkZSA8dXZfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPG5vcm1hbF9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8YnVtcG1hcF9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8bm9ybWFsbWFwX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX3BhcnNfZnJhZ21lbnQ+XHJcblxyXG52b2lkIG1haW4oKSB7XHJcblxyXG5cdHZlYzQgZGlmZnVzZUNvbG9yID0gdmVjNCggMC4wLCAwLjAsIDAuMCwgb3BhY2l0eSApO1xyXG5cclxuXHQjaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl9mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8bm9ybWFsX2ZyYWdtZW50X2JlZ2luPlxyXG5cdCNpbmNsdWRlIDxub3JtYWxfZnJhZ21lbnRfbWFwcz5cclxuXHJcblx0Z2xfRnJhZ0NvbG9yID0gdmVjNCggcGFja05vcm1hbFRvUkdCKCBub3JtYWwgKSwgZGlmZnVzZUNvbG9yLmEgKTtcclxuXHJcblx0I2lmZGVmIE9QQVFVRVxyXG5cclxuXHRcdGdsX0ZyYWdDb2xvci5hID0gMS4wO1xyXG5cclxuXHQjZW5kaWZcclxuXHJcbn1cclxuYDtcclxuIiwiZXhwb3J0IGNvbnN0IHZlcnRleCA9IC8qIGdsc2wgKi9gXHJcbiNkZWZpbmUgUEhPTkdcclxuXHJcbnZhcnlpbmcgdmVjMyB2Vmlld1Bvc2l0aW9uO1xyXG5cclxuI2luY2x1ZGUgPGNvbW1vbj5cclxuI2luY2x1ZGUgPGJhdGNoaW5nX3BhcnNfdmVydGV4PlxyXG4jaW5jbHVkZSA8dXZfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxkaXNwbGFjZW1lbnRtYXBfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxlbnZtYXBfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxjb2xvcl9wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPGZvZ19wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPG5vcm1hbF9wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPG1vcnBodGFyZ2V0X3BhcnNfdmVydGV4PlxyXG4jaW5jbHVkZSA8c2tpbm5pbmdfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxzaGFkb3dtYXBfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl9wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc19wYXJzX3ZlcnRleD5cclxuXHJcbnZvaWQgbWFpbigpIHtcclxuXHJcblx0I2luY2x1ZGUgPHV2X3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8Y29sb3JfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxtb3JwaGNvbG9yX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8YmF0Y2hpbmdfdmVydGV4PlxyXG5cclxuXHQjaW5jbHVkZSA8YmVnaW5ub3JtYWxfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxtb3JwaG5vcm1hbF92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPHNraW5iYXNlX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8c2tpbm5vcm1hbF92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPGRlZmF1bHRub3JtYWxfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxub3JtYWxfdmVydGV4PlxyXG5cclxuXHQjaW5jbHVkZSA8YmVnaW5fdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxtb3JwaHRhcmdldF92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPHNraW5uaW5nX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8ZGlzcGxhY2VtZW50bWFwX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8cHJvamVjdF92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPGxvZ2RlcHRoYnVmX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX3ZlcnRleD5cclxuXHJcblx0dlZpZXdQb3NpdGlvbiA9IC0gbXZQb3NpdGlvbi54eXo7XHJcblxyXG5cdCNpbmNsdWRlIDx3b3JsZHBvc192ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPGVudm1hcF92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPHNoYWRvd21hcF92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPGZvZ192ZXJ0ZXg+XHJcblxyXG59XHJcbmA7XHJcblxyXG5leHBvcnQgY29uc3QgZnJhZ21lbnQgPSAvKiBnbHNsICovYFxyXG4jZGVmaW5lIFBIT05HXHJcblxyXG51bmlmb3JtIHZlYzMgZGlmZnVzZTtcclxudW5pZm9ybSB2ZWMzIGVtaXNzaXZlO1xyXG51bmlmb3JtIHZlYzMgc3BlY3VsYXI7XHJcbnVuaWZvcm0gZmxvYXQgc2hpbmluZXNzO1xyXG51bmlmb3JtIGZsb2F0IG9wYWNpdHk7XHJcblxyXG4jaW5jbHVkZSA8Y29tbW9uPlxyXG4jaW5jbHVkZSA8cGFja2luZz5cclxuI2luY2x1ZGUgPGRpdGhlcmluZ19wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8Y29sb3JfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPHV2X3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxtYXBfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGFscGhhbWFwX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxhbHBoYXRlc3RfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGFscGhhaGFzaF9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8YW9tYXBfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGxpZ2h0bWFwX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxlbWlzc2l2ZW1hcF9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8ZW52bWFwX2NvbW1vbl9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8ZW52bWFwX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxmb2dfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGJzZGZzPlxyXG4jaW5jbHVkZSA8bGlnaHRzX3BhcnNfYmVnaW4+XHJcbiNpbmNsdWRlIDxub3JtYWxfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGxpZ2h0c19waG9uZ19wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8c2hhZG93bWFwX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxidW1wbWFwX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxub3JtYWxtYXBfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPHNwZWN1bGFybWFwX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX3BhcnNfZnJhZ21lbnQ+XHJcblxyXG52b2lkIG1haW4oKSB7XHJcblxyXG5cdHZlYzQgZGlmZnVzZUNvbG9yID0gdmVjNCggZGlmZnVzZSwgb3BhY2l0eSApO1xyXG5cdCNpbmNsdWRlIDxjbGlwcGluZ19wbGFuZXNfZnJhZ21lbnQ+XHJcblxyXG5cdFJlZmxlY3RlZExpZ2h0IHJlZmxlY3RlZExpZ2h0ID0gUmVmbGVjdGVkTGlnaHQoIHZlYzMoIDAuMCApLCB2ZWMzKCAwLjAgKSwgdmVjMyggMC4wICksIHZlYzMoIDAuMCApICk7XHJcblx0dmVjMyB0b3RhbEVtaXNzaXZlUmFkaWFuY2UgPSBlbWlzc2l2ZTtcclxuXHJcblx0I2luY2x1ZGUgPGxvZ2RlcHRoYnVmX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxtYXBfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPGNvbG9yX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxhbHBoYW1hcF9mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8YWxwaGF0ZXN0X2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxhbHBoYWhhc2hfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPHNwZWN1bGFybWFwX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxub3JtYWxfZnJhZ21lbnRfYmVnaW4+XHJcblx0I2luY2x1ZGUgPG5vcm1hbF9mcmFnbWVudF9tYXBzPlxyXG5cdCNpbmNsdWRlIDxlbWlzc2l2ZW1hcF9mcmFnbWVudD5cclxuXHJcblx0Ly8gYWNjdW11bGF0aW9uXHJcblx0I2luY2x1ZGUgPGxpZ2h0c19waG9uZ19mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8bGlnaHRzX2ZyYWdtZW50X2JlZ2luPlxyXG5cdCNpbmNsdWRlIDxsaWdodHNfZnJhZ21lbnRfbWFwcz5cclxuXHQjaW5jbHVkZSA8bGlnaHRzX2ZyYWdtZW50X2VuZD5cclxuXHJcblx0Ly8gbW9kdWxhdGlvblxyXG5cdCNpbmNsdWRlIDxhb21hcF9mcmFnbWVudD5cclxuXHJcblx0dmVjMyBvdXRnb2luZ0xpZ2h0ID0gcmVmbGVjdGVkTGlnaHQuZGlyZWN0RGlmZnVzZSArIHJlZmxlY3RlZExpZ2h0LmluZGlyZWN0RGlmZnVzZSArIHJlZmxlY3RlZExpZ2h0LmRpcmVjdFNwZWN1bGFyICsgcmVmbGVjdGVkTGlnaHQuaW5kaXJlY3RTcGVjdWxhciArIHRvdGFsRW1pc3NpdmVSYWRpYW5jZTtcclxuXHJcblx0I2luY2x1ZGUgPGVudm1hcF9mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8b3BhcXVlX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDx0b25lbWFwcGluZ19mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8Y29sb3JzcGFjZV9mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8Zm9nX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxwcmVtdWx0aXBsaWVkX2FscGhhX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxkaXRoZXJpbmdfZnJhZ21lbnQ+XHJcblxyXG59XHJcbmA7XHJcbiIsImV4cG9ydCBjb25zdCB2ZXJ0ZXggPSAvKiBnbHNsICovYFxyXG4jZGVmaW5lIFNUQU5EQVJEXHJcblxyXG52YXJ5aW5nIHZlYzMgdlZpZXdQb3NpdGlvbjtcclxuXHJcbiNpZmRlZiBVU0VfVFJBTlNNSVNTSU9OXHJcblxyXG5cdHZhcnlpbmcgdmVjMyB2V29ybGRQb3NpdGlvbjtcclxuXHJcbiNlbmRpZlxyXG5cclxuI2luY2x1ZGUgPGNvbW1vbj5cclxuI2luY2x1ZGUgPGJhdGNoaW5nX3BhcnNfdmVydGV4PlxyXG4jaW5jbHVkZSA8dXZfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxkaXNwbGFjZW1lbnRtYXBfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxjb2xvcl9wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPGZvZ19wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPG5vcm1hbF9wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPG1vcnBodGFyZ2V0X3BhcnNfdmVydGV4PlxyXG4jaW5jbHVkZSA8c2tpbm5pbmdfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxzaGFkb3dtYXBfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl9wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc19wYXJzX3ZlcnRleD5cclxuXHJcbnZvaWQgbWFpbigpIHtcclxuXHJcblx0I2luY2x1ZGUgPHV2X3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8Y29sb3JfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxtb3JwaGNvbG9yX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8YmF0Y2hpbmdfdmVydGV4PlxyXG5cclxuXHQjaW5jbHVkZSA8YmVnaW5ub3JtYWxfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxtb3JwaG5vcm1hbF92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPHNraW5iYXNlX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8c2tpbm5vcm1hbF92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPGRlZmF1bHRub3JtYWxfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxub3JtYWxfdmVydGV4PlxyXG5cclxuXHQjaW5jbHVkZSA8YmVnaW5fdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxtb3JwaHRhcmdldF92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPHNraW5uaW5nX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8ZGlzcGxhY2VtZW50bWFwX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8cHJvamVjdF92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPGxvZ2RlcHRoYnVmX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX3ZlcnRleD5cclxuXHJcblx0dlZpZXdQb3NpdGlvbiA9IC0gbXZQb3NpdGlvbi54eXo7XHJcblxyXG5cdCNpbmNsdWRlIDx3b3JsZHBvc192ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPHNoYWRvd21hcF92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPGZvZ192ZXJ0ZXg+XHJcblxyXG4jaWZkZWYgVVNFX1RSQU5TTUlTU0lPTlxyXG5cclxuXHR2V29ybGRQb3NpdGlvbiA9IHdvcmxkUG9zaXRpb24ueHl6O1xyXG5cclxuI2VuZGlmXHJcbn1cclxuYDtcclxuXHJcbmV4cG9ydCBjb25zdCBmcmFnbWVudCA9IC8qIGdsc2wgKi9gXHJcbiNkZWZpbmUgU1RBTkRBUkRcclxuXHJcbiNpZmRlZiBQSFlTSUNBTFxyXG5cdCNkZWZpbmUgSU9SXHJcblx0I2RlZmluZSBVU0VfU1BFQ1VMQVJcclxuI2VuZGlmXHJcblxyXG51bmlmb3JtIHZlYzMgZGlmZnVzZTtcclxudW5pZm9ybSB2ZWMzIGVtaXNzaXZlO1xyXG51bmlmb3JtIGZsb2F0IHJvdWdobmVzcztcclxudW5pZm9ybSBmbG9hdCBtZXRhbG5lc3M7XHJcbnVuaWZvcm0gZmxvYXQgb3BhY2l0eTtcclxuXHJcbiNpZmRlZiBJT1JcclxuXHR1bmlmb3JtIGZsb2F0IGlvcjtcclxuI2VuZGlmXHJcblxyXG4jaWZkZWYgVVNFX1NQRUNVTEFSXHJcblx0dW5pZm9ybSBmbG9hdCBzcGVjdWxhckludGVuc2l0eTtcclxuXHR1bmlmb3JtIHZlYzMgc3BlY3VsYXJDb2xvcjtcclxuXHJcblx0I2lmZGVmIFVTRV9TUEVDVUxBUl9DT0xPUk1BUFxyXG5cdFx0dW5pZm9ybSBzYW1wbGVyMkQgc3BlY3VsYXJDb2xvck1hcDtcclxuXHQjZW5kaWZcclxuXHJcblx0I2lmZGVmIFVTRV9TUEVDVUxBUl9JTlRFTlNJVFlNQVBcclxuXHRcdHVuaWZvcm0gc2FtcGxlcjJEIHNwZWN1bGFySW50ZW5zaXR5TWFwO1xyXG5cdCNlbmRpZlxyXG4jZW5kaWZcclxuXHJcbiNpZmRlZiBVU0VfQ0xFQVJDT0FUXHJcblx0dW5pZm9ybSBmbG9hdCBjbGVhcmNvYXQ7XHJcblx0dW5pZm9ybSBmbG9hdCBjbGVhcmNvYXRSb3VnaG5lc3M7XHJcbiNlbmRpZlxyXG5cclxuI2lmZGVmIFVTRV9JUklERVNDRU5DRVxyXG5cdHVuaWZvcm0gZmxvYXQgaXJpZGVzY2VuY2U7XHJcblx0dW5pZm9ybSBmbG9hdCBpcmlkZXNjZW5jZUlPUjtcclxuXHR1bmlmb3JtIGZsb2F0IGlyaWRlc2NlbmNlVGhpY2tuZXNzTWluaW11bTtcclxuXHR1bmlmb3JtIGZsb2F0IGlyaWRlc2NlbmNlVGhpY2tuZXNzTWF4aW11bTtcclxuI2VuZGlmXHJcblxyXG4jaWZkZWYgVVNFX1NIRUVOXHJcblx0dW5pZm9ybSB2ZWMzIHNoZWVuQ29sb3I7XHJcblx0dW5pZm9ybSBmbG9hdCBzaGVlblJvdWdobmVzcztcclxuXHJcblx0I2lmZGVmIFVTRV9TSEVFTl9DT0xPUk1BUFxyXG5cdFx0dW5pZm9ybSBzYW1wbGVyMkQgc2hlZW5Db2xvck1hcDtcclxuXHQjZW5kaWZcclxuXHJcblx0I2lmZGVmIFVTRV9TSEVFTl9ST1VHSE5FU1NNQVBcclxuXHRcdHVuaWZvcm0gc2FtcGxlcjJEIHNoZWVuUm91Z2huZXNzTWFwO1xyXG5cdCNlbmRpZlxyXG4jZW5kaWZcclxuXHJcbiNpZmRlZiBVU0VfQU5JU09UUk9QWVxyXG5cdHVuaWZvcm0gdmVjMiBhbmlzb3Ryb3B5VmVjdG9yO1xyXG5cclxuXHQjaWZkZWYgVVNFX0FOSVNPVFJPUFlNQVBcclxuXHRcdHVuaWZvcm0gc2FtcGxlcjJEIGFuaXNvdHJvcHlNYXA7XHJcblx0I2VuZGlmXHJcbiNlbmRpZlxyXG5cclxudmFyeWluZyB2ZWMzIHZWaWV3UG9zaXRpb247XHJcblxyXG4jaW5jbHVkZSA8Y29tbW9uPlxyXG4jaW5jbHVkZSA8cGFja2luZz5cclxuI2luY2x1ZGUgPGRpdGhlcmluZ19wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8Y29sb3JfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPHV2X3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxtYXBfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGFscGhhbWFwX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxhbHBoYXRlc3RfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGFscGhhaGFzaF9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8YW9tYXBfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGxpZ2h0bWFwX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxlbWlzc2l2ZW1hcF9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8aXJpZGVzY2VuY2VfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxjdWJlX3V2X3JlZmxlY3Rpb25fZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxlbnZtYXBfY29tbW9uX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxlbnZtYXBfcGh5c2ljYWxfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGZvZ19wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8bGlnaHRzX3BhcnNfYmVnaW4+XHJcbiNpbmNsdWRlIDxub3JtYWxfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGxpZ2h0c19waHlzaWNhbF9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8dHJhbnNtaXNzaW9uX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxzaGFkb3dtYXBfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGJ1bXBtYXBfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPG5vcm1hbG1hcF9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8Y2xlYXJjb2F0X3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxpcmlkZXNjZW5jZV9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8cm91Z2huZXNzbWFwX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxtZXRhbG5lc3NtYXBfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGxvZ2RlcHRoYnVmX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxjbGlwcGluZ19wbGFuZXNfcGFyc19mcmFnbWVudD5cclxuXHJcbnZvaWQgbWFpbigpIHtcclxuXHJcblx0dmVjNCBkaWZmdXNlQ29sb3IgPSB2ZWM0KCBkaWZmdXNlLCBvcGFjaXR5ICk7XHJcblx0I2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc19mcmFnbWVudD5cclxuXHJcblx0UmVmbGVjdGVkTGlnaHQgcmVmbGVjdGVkTGlnaHQgPSBSZWZsZWN0ZWRMaWdodCggdmVjMyggMC4wICksIHZlYzMoIDAuMCApLCB2ZWMzKCAwLjAgKSwgdmVjMyggMC4wICkgKTtcclxuXHR2ZWMzIHRvdGFsRW1pc3NpdmVSYWRpYW5jZSA9IGVtaXNzaXZlO1xyXG5cclxuXHQjaW5jbHVkZSA8bG9nZGVwdGhidWZfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPG1hcF9mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8Y29sb3JfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPGFscGhhbWFwX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxhbHBoYXRlc3RfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPGFscGhhaGFzaF9mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8cm91Z2huZXNzbWFwX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxtZXRhbG5lc3NtYXBfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPG5vcm1hbF9mcmFnbWVudF9iZWdpbj5cclxuXHQjaW5jbHVkZSA8bm9ybWFsX2ZyYWdtZW50X21hcHM+XHJcblx0I2luY2x1ZGUgPGNsZWFyY29hdF9ub3JtYWxfZnJhZ21lbnRfYmVnaW4+XHJcblx0I2luY2x1ZGUgPGNsZWFyY29hdF9ub3JtYWxfZnJhZ21lbnRfbWFwcz5cclxuXHQjaW5jbHVkZSA8ZW1pc3NpdmVtYXBfZnJhZ21lbnQ+XHJcblxyXG5cdC8vIGFjY3VtdWxhdGlvblxyXG5cdCNpbmNsdWRlIDxsaWdodHNfcGh5c2ljYWxfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPGxpZ2h0c19mcmFnbWVudF9iZWdpbj5cclxuXHQjaW5jbHVkZSA8bGlnaHRzX2ZyYWdtZW50X21hcHM+XHJcblx0I2luY2x1ZGUgPGxpZ2h0c19mcmFnbWVudF9lbmQ+XHJcblxyXG5cdC8vIG1vZHVsYXRpb25cclxuXHQjaW5jbHVkZSA8YW9tYXBfZnJhZ21lbnQ+XHJcblxyXG5cdHZlYzMgdG90YWxEaWZmdXNlID0gcmVmbGVjdGVkTGlnaHQuZGlyZWN0RGlmZnVzZSArIHJlZmxlY3RlZExpZ2h0LmluZGlyZWN0RGlmZnVzZTtcclxuXHR2ZWMzIHRvdGFsU3BlY3VsYXIgPSByZWZsZWN0ZWRMaWdodC5kaXJlY3RTcGVjdWxhciArIHJlZmxlY3RlZExpZ2h0LmluZGlyZWN0U3BlY3VsYXI7XHJcblxyXG5cdCNpbmNsdWRlIDx0cmFuc21pc3Npb25fZnJhZ21lbnQ+XHJcblxyXG5cdHZlYzMgb3V0Z29pbmdMaWdodCA9IHRvdGFsRGlmZnVzZSArIHRvdGFsU3BlY3VsYXIgKyB0b3RhbEVtaXNzaXZlUmFkaWFuY2U7XHJcblxyXG5cdCNpZmRlZiBVU0VfU0hFRU5cclxuXHJcblx0XHQvLyBTaGVlbiBlbmVyZ3kgY29tcGVuc2F0aW9uIGFwcHJveGltYXRpb24gY2FsY3VsYXRpb24gY2FuIGJlIGZvdW5kIGF0IHRoZSBlbmQgb2ZcclxuXHRcdC8vIGh0dHBzOi8vZHJpdmUuZ29vZ2xlLmNvbS9maWxlL2QvMVQwRDFWU3lSNEFsbHFJSlRRQXJhRUl6amxiNWg0RktIL3ZpZXc/dXNwPXNoYXJpbmdcclxuXHRcdGZsb2F0IHNoZWVuRW5lcmd5Q29tcCA9IDEuMCAtIDAuMTU3ICogbWF4MyggbWF0ZXJpYWwuc2hlZW5Db2xvciApO1xyXG5cclxuXHRcdG91dGdvaW5nTGlnaHQgPSBvdXRnb2luZ0xpZ2h0ICogc2hlZW5FbmVyZ3lDb21wICsgc2hlZW5TcGVjdWxhckRpcmVjdCArIHNoZWVuU3BlY3VsYXJJbmRpcmVjdDtcclxuXHJcblx0I2VuZGlmXHJcblxyXG5cdCNpZmRlZiBVU0VfQ0xFQVJDT0FUXHJcblxyXG5cdFx0ZmxvYXQgZG90TlZjYyA9IHNhdHVyYXRlKCBkb3QoIGdlb21ldHJ5Q2xlYXJjb2F0Tm9ybWFsLCBnZW9tZXRyeVZpZXdEaXIgKSApO1xyXG5cclxuXHRcdHZlYzMgRmNjID0gRl9TY2hsaWNrKCBtYXRlcmlhbC5jbGVhcmNvYXRGMCwgbWF0ZXJpYWwuY2xlYXJjb2F0RjkwLCBkb3ROVmNjICk7XHJcblxyXG5cdFx0b3V0Z29pbmdMaWdodCA9IG91dGdvaW5nTGlnaHQgKiAoIDEuMCAtIG1hdGVyaWFsLmNsZWFyY29hdCAqIEZjYyApICsgKCBjbGVhcmNvYXRTcGVjdWxhckRpcmVjdCArIGNsZWFyY29hdFNwZWN1bGFySW5kaXJlY3QgKSAqIG1hdGVyaWFsLmNsZWFyY29hdDtcclxuXHJcblx0I2VuZGlmXHJcblxyXG5cdCNpbmNsdWRlIDxvcGFxdWVfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPHRvbmVtYXBwaW5nX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxjb2xvcnNwYWNlX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxmb2dfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPHByZW11bHRpcGxpZWRfYWxwaGFfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPGRpdGhlcmluZ19mcmFnbWVudD5cclxuXHJcbn1cclxuYDtcclxuIiwiZXhwb3J0IGNvbnN0IHZlcnRleCA9IC8qIGdsc2wgKi9gXHJcbiNkZWZpbmUgVE9PTlxyXG5cclxudmFyeWluZyB2ZWMzIHZWaWV3UG9zaXRpb247XHJcblxyXG4jaW5jbHVkZSA8Y29tbW9uPlxyXG4jaW5jbHVkZSA8YmF0Y2hpbmdfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDx1dl9wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPGRpc3BsYWNlbWVudG1hcF9wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPGNvbG9yX3BhcnNfdmVydGV4PlxyXG4jaW5jbHVkZSA8Zm9nX3BhcnNfdmVydGV4PlxyXG4jaW5jbHVkZSA8bm9ybWFsX3BhcnNfdmVydGV4PlxyXG4jaW5jbHVkZSA8bW9ycGh0YXJnZXRfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxza2lubmluZ19wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPHNoYWRvd21hcF9wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPGxvZ2RlcHRoYnVmX3BhcnNfdmVydGV4PlxyXG4jaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX3BhcnNfdmVydGV4PlxyXG5cclxudm9pZCBtYWluKCkge1xyXG5cclxuXHQjaW5jbHVkZSA8dXZfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxjb2xvcl92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPG1vcnBoY29sb3JfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxiYXRjaGluZ192ZXJ0ZXg+XHJcblxyXG5cdCNpbmNsdWRlIDxiZWdpbm5vcm1hbF92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPG1vcnBobm9ybWFsX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8c2tpbmJhc2VfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxza2lubm9ybWFsX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8ZGVmYXVsdG5vcm1hbF92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPG5vcm1hbF92ZXJ0ZXg+XHJcblxyXG5cdCNpbmNsdWRlIDxiZWdpbl92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPG1vcnBodGFyZ2V0X3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8c2tpbm5pbmdfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxkaXNwbGFjZW1lbnRtYXBfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxwcm9qZWN0X3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8bG9nZGVwdGhidWZfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxjbGlwcGluZ19wbGFuZXNfdmVydGV4PlxyXG5cclxuXHR2Vmlld1Bvc2l0aW9uID0gLSBtdlBvc2l0aW9uLnh5ejtcclxuXHJcblx0I2luY2x1ZGUgPHdvcmxkcG9zX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8c2hhZG93bWFwX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8Zm9nX3ZlcnRleD5cclxuXHJcbn1cclxuYDtcclxuXHJcbmV4cG9ydCBjb25zdCBmcmFnbWVudCA9IC8qIGdsc2wgKi9gXHJcbiNkZWZpbmUgVE9PTlxyXG5cclxudW5pZm9ybSB2ZWMzIGRpZmZ1c2U7XHJcbnVuaWZvcm0gdmVjMyBlbWlzc2l2ZTtcclxudW5pZm9ybSBmbG9hdCBvcGFjaXR5O1xyXG5cclxuI2luY2x1ZGUgPGNvbW1vbj5cclxuI2luY2x1ZGUgPHBhY2tpbmc+XHJcbiNpbmNsdWRlIDxkaXRoZXJpbmdfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGNvbG9yX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDx1dl9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8bWFwX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxhbHBoYW1hcF9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8YWxwaGF0ZXN0X3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxhbHBoYWhhc2hfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGFvbWFwX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxsaWdodG1hcF9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8ZW1pc3NpdmVtYXBfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGdyYWRpZW50bWFwX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxmb2dfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGJzZGZzPlxyXG4jaW5jbHVkZSA8bGlnaHRzX3BhcnNfYmVnaW4+XHJcbiNpbmNsdWRlIDxub3JtYWxfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGxpZ2h0c190b29uX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxzaGFkb3dtYXBfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGJ1bXBtYXBfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPG5vcm1hbG1hcF9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8bG9nZGVwdGhidWZfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc19wYXJzX2ZyYWdtZW50PlxyXG5cclxudm9pZCBtYWluKCkge1xyXG5cclxuXHR2ZWM0IGRpZmZ1c2VDb2xvciA9IHZlYzQoIGRpZmZ1c2UsIG9wYWNpdHkgKTtcclxuXHQjaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX2ZyYWdtZW50PlxyXG5cclxuXHRSZWZsZWN0ZWRMaWdodCByZWZsZWN0ZWRMaWdodCA9IFJlZmxlY3RlZExpZ2h0KCB2ZWMzKCAwLjAgKSwgdmVjMyggMC4wICksIHZlYzMoIDAuMCApLCB2ZWMzKCAwLjAgKSApO1xyXG5cdHZlYzMgdG90YWxFbWlzc2l2ZVJhZGlhbmNlID0gZW1pc3NpdmU7XHJcblxyXG5cdCNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl9mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8bWFwX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxjb2xvcl9mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8YWxwaGFtYXBfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPGFscGhhdGVzdF9mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8YWxwaGFoYXNoX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxub3JtYWxfZnJhZ21lbnRfYmVnaW4+XHJcblx0I2luY2x1ZGUgPG5vcm1hbF9mcmFnbWVudF9tYXBzPlxyXG5cdCNpbmNsdWRlIDxlbWlzc2l2ZW1hcF9mcmFnbWVudD5cclxuXHJcblx0Ly8gYWNjdW11bGF0aW9uXHJcblx0I2luY2x1ZGUgPGxpZ2h0c190b29uX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxsaWdodHNfZnJhZ21lbnRfYmVnaW4+XHJcblx0I2luY2x1ZGUgPGxpZ2h0c19mcmFnbWVudF9tYXBzPlxyXG5cdCNpbmNsdWRlIDxsaWdodHNfZnJhZ21lbnRfZW5kPlxyXG5cclxuXHQvLyBtb2R1bGF0aW9uXHJcblx0I2luY2x1ZGUgPGFvbWFwX2ZyYWdtZW50PlxyXG5cclxuXHR2ZWMzIG91dGdvaW5nTGlnaHQgPSByZWZsZWN0ZWRMaWdodC5kaXJlY3REaWZmdXNlICsgcmVmbGVjdGVkTGlnaHQuaW5kaXJlY3REaWZmdXNlICsgdG90YWxFbWlzc2l2ZVJhZGlhbmNlO1xyXG5cclxuXHQjaW5jbHVkZSA8b3BhcXVlX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDx0b25lbWFwcGluZ19mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8Y29sb3JzcGFjZV9mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8Zm9nX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxwcmVtdWx0aXBsaWVkX2FscGhhX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxkaXRoZXJpbmdfZnJhZ21lbnQ+XHJcblxyXG59XHJcbmA7XHJcbiIsImV4cG9ydCBjb25zdCB2ZXJ0ZXggPSAvKiBnbHNsICovYFxyXG51bmlmb3JtIGZsb2F0IHNpemU7XHJcbnVuaWZvcm0gZmxvYXQgc2NhbGU7XHJcblxyXG4jaW5jbHVkZSA8Y29tbW9uPlxyXG4jaW5jbHVkZSA8Y29sb3JfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxmb2dfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxtb3JwaHRhcmdldF9wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPGxvZ2RlcHRoYnVmX3BhcnNfdmVydGV4PlxyXG4jaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX3BhcnNfdmVydGV4PlxyXG5cclxuI2lmZGVmIFVTRV9QT0lOVFNfVVZcclxuXHJcblx0dmFyeWluZyB2ZWMyIHZVdjtcclxuXHR1bmlmb3JtIG1hdDMgdXZUcmFuc2Zvcm07XHJcblxyXG4jZW5kaWZcclxuXHJcbnZvaWQgbWFpbigpIHtcclxuXHJcblx0I2lmZGVmIFVTRV9QT0lOVFNfVVZcclxuXHJcblx0XHR2VXYgPSAoIHV2VHJhbnNmb3JtICogdmVjMyggdXYsIDEgKSApLnh5O1xyXG5cclxuXHQjZW5kaWZcclxuXHJcblx0I2luY2x1ZGUgPGNvbG9yX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8bW9ycGhjb2xvcl92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPGJlZ2luX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8bW9ycGh0YXJnZXRfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxwcm9qZWN0X3ZlcnRleD5cclxuXHJcblx0Z2xfUG9pbnRTaXplID0gc2l6ZTtcclxuXHJcblx0I2lmZGVmIFVTRV9TSVpFQVRURU5VQVRJT05cclxuXHJcblx0XHRib29sIGlzUGVyc3BlY3RpdmUgPSBpc1BlcnNwZWN0aXZlTWF0cml4KCBwcm9qZWN0aW9uTWF0cml4ICk7XHJcblxyXG5cdFx0aWYgKCBpc1BlcnNwZWN0aXZlICkgZ2xfUG9pbnRTaXplICo9ICggc2NhbGUgLyAtIG12UG9zaXRpb24ueiApO1xyXG5cclxuXHQjZW5kaWZcclxuXHJcblx0I2luY2x1ZGUgPGxvZ2RlcHRoYnVmX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8d29ybGRwb3NfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxmb2dfdmVydGV4PlxyXG5cclxufVxyXG5gO1xyXG5cclxuZXhwb3J0IGNvbnN0IGZyYWdtZW50ID0gLyogZ2xzbCAqL2BcclxudW5pZm9ybSB2ZWMzIGRpZmZ1c2U7XHJcbnVuaWZvcm0gZmxvYXQgb3BhY2l0eTtcclxuXHJcbiNpbmNsdWRlIDxjb21tb24+XHJcbiNpbmNsdWRlIDxjb2xvcl9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8bWFwX3BhcnRpY2xlX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxhbHBoYXRlc3RfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGFscGhhaGFzaF9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8Zm9nX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX3BhcnNfZnJhZ21lbnQ+XHJcblxyXG52b2lkIG1haW4oKSB7XHJcblxyXG5cdHZlYzQgZGlmZnVzZUNvbG9yID0gdmVjNCggZGlmZnVzZSwgb3BhY2l0eSApO1xyXG5cdCNpbmNsdWRlIDxjbGlwcGluZ19wbGFuZXNfZnJhZ21lbnQ+XHJcblxyXG5cdHZlYzMgb3V0Z29pbmdMaWdodCA9IHZlYzMoIDAuMCApO1xyXG5cclxuXHQjaW5jbHVkZSA8bG9nZGVwdGhidWZfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPG1hcF9wYXJ0aWNsZV9mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8Y29sb3JfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPGFscGhhdGVzdF9mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8YWxwaGFoYXNoX2ZyYWdtZW50PlxyXG5cclxuXHRvdXRnb2luZ0xpZ2h0ID0gZGlmZnVzZUNvbG9yLnJnYjtcclxuXHJcblx0I2luY2x1ZGUgPG9wYXF1ZV9mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8dG9uZW1hcHBpbmdfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPGNvbG9yc3BhY2VfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPGZvZ19mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8cHJlbXVsdGlwbGllZF9hbHBoYV9mcmFnbWVudD5cclxuXHJcbn1cclxuYDtcclxuIiwiZXhwb3J0IGNvbnN0IHZlcnRleCA9IC8qIGdsc2wgKi9gXHJcbiNpbmNsdWRlIDxjb21tb24+XHJcbiNpbmNsdWRlIDxiYXRjaGluZ19wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPGZvZ19wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPG1vcnBodGFyZ2V0X3BhcnNfdmVydGV4PlxyXG4jaW5jbHVkZSA8c2tpbm5pbmdfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl9wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPHNoYWRvd21hcF9wYXJzX3ZlcnRleD5cclxuXHJcbnZvaWQgbWFpbigpIHtcclxuXHJcblx0I2luY2x1ZGUgPGJhdGNoaW5nX3ZlcnRleD5cclxuXHJcblx0I2luY2x1ZGUgPGJlZ2lubm9ybWFsX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8bW9ycGhub3JtYWxfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxza2luYmFzZV92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPHNraW5ub3JtYWxfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxkZWZhdWx0bm9ybWFsX3ZlcnRleD5cclxuXHJcblx0I2luY2x1ZGUgPGJlZ2luX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8bW9ycGh0YXJnZXRfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxza2lubmluZ192ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPHByb2plY3RfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl92ZXJ0ZXg+XHJcblxyXG5cdCNpbmNsdWRlIDx3b3JsZHBvc192ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPHNoYWRvd21hcF92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPGZvZ192ZXJ0ZXg+XHJcblxyXG59XHJcbmA7XHJcblxyXG5leHBvcnQgY29uc3QgZnJhZ21lbnQgPSAvKiBnbHNsICovYFxyXG51bmlmb3JtIHZlYzMgY29sb3I7XHJcbnVuaWZvcm0gZmxvYXQgb3BhY2l0eTtcclxuXHJcbiNpbmNsdWRlIDxjb21tb24+XHJcbiNpbmNsdWRlIDxwYWNraW5nPlxyXG4jaW5jbHVkZSA8Zm9nX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxic2Rmcz5cclxuI2luY2x1ZGUgPGxpZ2h0c19wYXJzX2JlZ2luPlxyXG4jaW5jbHVkZSA8bG9nZGVwdGhidWZfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPHNoYWRvd21hcF9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8c2hhZG93bWFza19wYXJzX2ZyYWdtZW50PlxyXG5cclxudm9pZCBtYWluKCkge1xyXG5cclxuXHQjaW5jbHVkZSA8bG9nZGVwdGhidWZfZnJhZ21lbnQ+XHJcblxyXG5cdGdsX0ZyYWdDb2xvciA9IHZlYzQoIGNvbG9yLCBvcGFjaXR5ICogKCAxLjAgLSBnZXRTaGFkb3dNYXNrKCkgKSApO1xyXG5cclxuXHQjaW5jbHVkZSA8dG9uZW1hcHBpbmdfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPGNvbG9yc3BhY2VfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPGZvZ19mcmFnbWVudD5cclxuXHJcbn1cclxuYDtcclxuIiwiZXhwb3J0IGNvbnN0IHZlcnRleCA9IC8qIGdsc2wgKi9gXHJcbnVuaWZvcm0gZmxvYXQgcm90YXRpb247XHJcbnVuaWZvcm0gdmVjMiBjZW50ZXI7XHJcblxyXG4jaW5jbHVkZSA8Y29tbW9uPlxyXG4jaW5jbHVkZSA8dXZfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxmb2dfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl9wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc19wYXJzX3ZlcnRleD5cclxuXHJcbnZvaWQgbWFpbigpIHtcclxuXHJcblx0I2luY2x1ZGUgPHV2X3ZlcnRleD5cclxuXHJcblx0dmVjNCBtdlBvc2l0aW9uID0gbW9kZWxWaWV3TWF0cml4ICogdmVjNCggMC4wLCAwLjAsIDAuMCwgMS4wICk7XHJcblxyXG5cdHZlYzIgc2NhbGU7XHJcblx0c2NhbGUueCA9IGxlbmd0aCggdmVjMyggbW9kZWxNYXRyaXhbIDAgXS54LCBtb2RlbE1hdHJpeFsgMCBdLnksIG1vZGVsTWF0cml4WyAwIF0ueiApICk7XHJcblx0c2NhbGUueSA9IGxlbmd0aCggdmVjMyggbW9kZWxNYXRyaXhbIDEgXS54LCBtb2RlbE1hdHJpeFsgMSBdLnksIG1vZGVsTWF0cml4WyAxIF0ueiApICk7XHJcblxyXG5cdCNpZm5kZWYgVVNFX1NJWkVBVFRFTlVBVElPTlxyXG5cclxuXHRcdGJvb2wgaXNQZXJzcGVjdGl2ZSA9IGlzUGVyc3BlY3RpdmVNYXRyaXgoIHByb2plY3Rpb25NYXRyaXggKTtcclxuXHJcblx0XHRpZiAoIGlzUGVyc3BlY3RpdmUgKSBzY2FsZSAqPSAtIG12UG9zaXRpb24uejtcclxuXHJcblx0I2VuZGlmXHJcblxyXG5cdHZlYzIgYWxpZ25lZFBvc2l0aW9uID0gKCBwb3NpdGlvbi54eSAtICggY2VudGVyIC0gdmVjMiggMC41ICkgKSApICogc2NhbGU7XHJcblxyXG5cdHZlYzIgcm90YXRlZFBvc2l0aW9uO1xyXG5cdHJvdGF0ZWRQb3NpdGlvbi54ID0gY29zKCByb3RhdGlvbiApICogYWxpZ25lZFBvc2l0aW9uLnggLSBzaW4oIHJvdGF0aW9uICkgKiBhbGlnbmVkUG9zaXRpb24ueTtcclxuXHRyb3RhdGVkUG9zaXRpb24ueSA9IHNpbiggcm90YXRpb24gKSAqIGFsaWduZWRQb3NpdGlvbi54ICsgY29zKCByb3RhdGlvbiApICogYWxpZ25lZFBvc2l0aW9uLnk7XHJcblxyXG5cdG12UG9zaXRpb24ueHkgKz0gcm90YXRlZFBvc2l0aW9uO1xyXG5cclxuXHRnbF9Qb3NpdGlvbiA9IHByb2plY3Rpb25NYXRyaXggKiBtdlBvc2l0aW9uO1xyXG5cclxuXHQjaW5jbHVkZSA8bG9nZGVwdGhidWZfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxjbGlwcGluZ19wbGFuZXNfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxmb2dfdmVydGV4PlxyXG5cclxufVxyXG5gO1xyXG5cclxuZXhwb3J0IGNvbnN0IGZyYWdtZW50ID0gLyogZ2xzbCAqL2BcclxudW5pZm9ybSB2ZWMzIGRpZmZ1c2U7XHJcbnVuaWZvcm0gZmxvYXQgb3BhY2l0eTtcclxuXHJcbiNpbmNsdWRlIDxjb21tb24+XHJcbiNpbmNsdWRlIDx1dl9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8bWFwX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxhbHBoYW1hcF9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8YWxwaGF0ZXN0X3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxhbHBoYWhhc2hfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGZvZ19wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8bG9nZGVwdGhidWZfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc19wYXJzX2ZyYWdtZW50PlxyXG5cclxudm9pZCBtYWluKCkge1xyXG5cclxuXHR2ZWM0IGRpZmZ1c2VDb2xvciA9IHZlYzQoIGRpZmZ1c2UsIG9wYWNpdHkgKTtcclxuXHQjaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX2ZyYWdtZW50PlxyXG5cclxuXHR2ZWMzIG91dGdvaW5nTGlnaHQgPSB2ZWMzKCAwLjAgKTtcclxuXHJcblx0I2luY2x1ZGUgPGxvZ2RlcHRoYnVmX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxtYXBfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPGFscGhhbWFwX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxhbHBoYXRlc3RfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPGFscGhhaGFzaF9mcmFnbWVudD5cclxuXHJcblx0b3V0Z29pbmdMaWdodCA9IGRpZmZ1c2VDb2xvci5yZ2I7XHJcblxyXG5cdCNpbmNsdWRlIDxvcGFxdWVfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPHRvbmVtYXBwaW5nX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxjb2xvcnNwYWNlX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxmb2dfZnJhZ21lbnQ+XHJcblxyXG59XHJcbmA7XHJcbiIsImltcG9ydCBhbHBoYWhhc2hfZnJhZ21lbnQgZnJvbSAnLi9TaGFkZXJDaHVuay9hbHBoYWhhc2hfZnJhZ21lbnQuZ2xzbC5qcyc7XHJcbmltcG9ydCBhbHBoYWhhc2hfcGFyc19mcmFnbWVudCBmcm9tICcuL1NoYWRlckNodW5rL2FscGhhaGFzaF9wYXJzX2ZyYWdtZW50Lmdsc2wuanMnO1xyXG5pbXBvcnQgYWxwaGFtYXBfZnJhZ21lbnQgZnJvbSAnLi9TaGFkZXJDaHVuay9hbHBoYW1hcF9mcmFnbWVudC5nbHNsLmpzJztcclxuaW1wb3J0IGFscGhhbWFwX3BhcnNfZnJhZ21lbnQgZnJvbSAnLi9TaGFkZXJDaHVuay9hbHBoYW1hcF9wYXJzX2ZyYWdtZW50Lmdsc2wuanMnO1xyXG5pbXBvcnQgYWxwaGF0ZXN0X2ZyYWdtZW50IGZyb20gJy4vU2hhZGVyQ2h1bmsvYWxwaGF0ZXN0X2ZyYWdtZW50Lmdsc2wuanMnO1xyXG5pbXBvcnQgYWxwaGF0ZXN0X3BhcnNfZnJhZ21lbnQgZnJvbSAnLi9TaGFkZXJDaHVuay9hbHBoYXRlc3RfcGFyc19mcmFnbWVudC5nbHNsLmpzJztcclxuaW1wb3J0IGFvbWFwX2ZyYWdtZW50IGZyb20gJy4vU2hhZGVyQ2h1bmsvYW9tYXBfZnJhZ21lbnQuZ2xzbC5qcyc7XHJcbmltcG9ydCBhb21hcF9wYXJzX2ZyYWdtZW50IGZyb20gJy4vU2hhZGVyQ2h1bmsvYW9tYXBfcGFyc19mcmFnbWVudC5nbHNsLmpzJztcclxuaW1wb3J0IGJhdGNoaW5nX3BhcnNfdmVydGV4IGZyb20gJy4vU2hhZGVyQ2h1bmsvYmF0Y2hpbmdfcGFyc192ZXJ0ZXguZ2xzbC5qcyc7XHJcbmltcG9ydCBiYXRjaGluZ192ZXJ0ZXggZnJvbSAnLi9TaGFkZXJDaHVuay9iYXRjaGluZ192ZXJ0ZXguZ2xzbC5qcyc7XHJcbmltcG9ydCBiZWdpbl92ZXJ0ZXggZnJvbSAnLi9TaGFkZXJDaHVuay9iZWdpbl92ZXJ0ZXguZ2xzbC5qcyc7XHJcbmltcG9ydCBiZWdpbm5vcm1hbF92ZXJ0ZXggZnJvbSAnLi9TaGFkZXJDaHVuay9iZWdpbm5vcm1hbF92ZXJ0ZXguZ2xzbC5qcyc7XHJcbmltcG9ydCBic2RmcyBmcm9tICcuL1NoYWRlckNodW5rL2JzZGZzLmdsc2wuanMnO1xyXG5pbXBvcnQgaXJpZGVzY2VuY2VfZnJhZ21lbnQgZnJvbSAnLi9TaGFkZXJDaHVuay9pcmlkZXNjZW5jZV9mcmFnbWVudC5nbHNsLmpzJztcclxuaW1wb3J0IGJ1bXBtYXBfcGFyc19mcmFnbWVudCBmcm9tICcuL1NoYWRlckNodW5rL2J1bXBtYXBfcGFyc19mcmFnbWVudC5nbHNsLmpzJztcclxuaW1wb3J0IGNsaXBwaW5nX3BsYW5lc19mcmFnbWVudCBmcm9tICcuL1NoYWRlckNodW5rL2NsaXBwaW5nX3BsYW5lc19mcmFnbWVudC5nbHNsLmpzJztcclxuaW1wb3J0IGNsaXBwaW5nX3BsYW5lc19wYXJzX2ZyYWdtZW50IGZyb20gJy4vU2hhZGVyQ2h1bmsvY2xpcHBpbmdfcGxhbmVzX3BhcnNfZnJhZ21lbnQuZ2xzbC5qcyc7XHJcbmltcG9ydCBjbGlwcGluZ19wbGFuZXNfcGFyc192ZXJ0ZXggZnJvbSAnLi9TaGFkZXJDaHVuay9jbGlwcGluZ19wbGFuZXNfcGFyc192ZXJ0ZXguZ2xzbC5qcyc7XHJcbmltcG9ydCBjbGlwcGluZ19wbGFuZXNfdmVydGV4IGZyb20gJy4vU2hhZGVyQ2h1bmsvY2xpcHBpbmdfcGxhbmVzX3ZlcnRleC5nbHNsLmpzJztcclxuaW1wb3J0IGNvbG9yX2ZyYWdtZW50IGZyb20gJy4vU2hhZGVyQ2h1bmsvY29sb3JfZnJhZ21lbnQuZ2xzbC5qcyc7XHJcbmltcG9ydCBjb2xvcl9wYXJzX2ZyYWdtZW50IGZyb20gJy4vU2hhZGVyQ2h1bmsvY29sb3JfcGFyc19mcmFnbWVudC5nbHNsLmpzJztcclxuaW1wb3J0IGNvbG9yX3BhcnNfdmVydGV4IGZyb20gJy4vU2hhZGVyQ2h1bmsvY29sb3JfcGFyc192ZXJ0ZXguZ2xzbC5qcyc7XHJcbmltcG9ydCBjb2xvcl92ZXJ0ZXggZnJvbSAnLi9TaGFkZXJDaHVuay9jb2xvcl92ZXJ0ZXguZ2xzbC5qcyc7XHJcbmltcG9ydCBjb21tb24gZnJvbSAnLi9TaGFkZXJDaHVuay9jb21tb24uZ2xzbC5qcyc7XHJcbmltcG9ydCBjdWJlX3V2X3JlZmxlY3Rpb25fZnJhZ21lbnQgZnJvbSAnLi9TaGFkZXJDaHVuay9jdWJlX3V2X3JlZmxlY3Rpb25fZnJhZ21lbnQuZ2xzbC5qcyc7XHJcbmltcG9ydCBkZWZhdWx0bm9ybWFsX3ZlcnRleCBmcm9tICcuL1NoYWRlckNodW5rL2RlZmF1bHRub3JtYWxfdmVydGV4Lmdsc2wuanMnO1xyXG5pbXBvcnQgZGlzcGxhY2VtZW50bWFwX3BhcnNfdmVydGV4IGZyb20gJy4vU2hhZGVyQ2h1bmsvZGlzcGxhY2VtZW50bWFwX3BhcnNfdmVydGV4Lmdsc2wuanMnO1xyXG5pbXBvcnQgZGlzcGxhY2VtZW50bWFwX3ZlcnRleCBmcm9tICcuL1NoYWRlckNodW5rL2Rpc3BsYWNlbWVudG1hcF92ZXJ0ZXguZ2xzbC5qcyc7XHJcbmltcG9ydCBlbWlzc2l2ZW1hcF9mcmFnbWVudCBmcm9tICcuL1NoYWRlckNodW5rL2VtaXNzaXZlbWFwX2ZyYWdtZW50Lmdsc2wuanMnO1xyXG5pbXBvcnQgZW1pc3NpdmVtYXBfcGFyc19mcmFnbWVudCBmcm9tICcuL1NoYWRlckNodW5rL2VtaXNzaXZlbWFwX3BhcnNfZnJhZ21lbnQuZ2xzbC5qcyc7XHJcbmltcG9ydCBjb2xvcnNwYWNlX2ZyYWdtZW50IGZyb20gJy4vU2hhZGVyQ2h1bmsvY29sb3JzcGFjZV9mcmFnbWVudC5nbHNsLmpzJztcclxuaW1wb3J0IGNvbG9yc3BhY2VfcGFyc19mcmFnbWVudCBmcm9tICcuL1NoYWRlckNodW5rL2NvbG9yc3BhY2VfcGFyc19mcmFnbWVudC5nbHNsLmpzJztcclxuaW1wb3J0IGVudm1hcF9mcmFnbWVudCBmcm9tICcuL1NoYWRlckNodW5rL2Vudm1hcF9mcmFnbWVudC5nbHNsLmpzJztcclxuaW1wb3J0IGVudm1hcF9jb21tb25fcGFyc19mcmFnbWVudCBmcm9tICcuL1NoYWRlckNodW5rL2Vudm1hcF9jb21tb25fcGFyc19mcmFnbWVudC5nbHNsLmpzJztcclxuaW1wb3J0IGVudm1hcF9wYXJzX2ZyYWdtZW50IGZyb20gJy4vU2hhZGVyQ2h1bmsvZW52bWFwX3BhcnNfZnJhZ21lbnQuZ2xzbC5qcyc7XHJcbmltcG9ydCBlbnZtYXBfcGFyc192ZXJ0ZXggZnJvbSAnLi9TaGFkZXJDaHVuay9lbnZtYXBfcGFyc192ZXJ0ZXguZ2xzbC5qcyc7XHJcbmltcG9ydCBlbnZtYXBfdmVydGV4IGZyb20gJy4vU2hhZGVyQ2h1bmsvZW52bWFwX3ZlcnRleC5nbHNsLmpzJztcclxuaW1wb3J0IGZvZ192ZXJ0ZXggZnJvbSAnLi9TaGFkZXJDaHVuay9mb2dfdmVydGV4Lmdsc2wuanMnO1xyXG5pbXBvcnQgZm9nX3BhcnNfdmVydGV4IGZyb20gJy4vU2hhZGVyQ2h1bmsvZm9nX3BhcnNfdmVydGV4Lmdsc2wuanMnO1xyXG5pbXBvcnQgZm9nX2ZyYWdtZW50IGZyb20gJy4vU2hhZGVyQ2h1bmsvZm9nX2ZyYWdtZW50Lmdsc2wuanMnO1xyXG5pbXBvcnQgZm9nX3BhcnNfZnJhZ21lbnQgZnJvbSAnLi9TaGFkZXJDaHVuay9mb2dfcGFyc19mcmFnbWVudC5nbHNsLmpzJztcclxuaW1wb3J0IGdyYWRpZW50bWFwX3BhcnNfZnJhZ21lbnQgZnJvbSAnLi9TaGFkZXJDaHVuay9ncmFkaWVudG1hcF9wYXJzX2ZyYWdtZW50Lmdsc2wuanMnO1xyXG5pbXBvcnQgbGlnaHRtYXBfZnJhZ21lbnQgZnJvbSAnLi9TaGFkZXJDaHVuay9saWdodG1hcF9mcmFnbWVudC5nbHNsLmpzJztcclxuaW1wb3J0IGxpZ2h0bWFwX3BhcnNfZnJhZ21lbnQgZnJvbSAnLi9TaGFkZXJDaHVuay9saWdodG1hcF9wYXJzX2ZyYWdtZW50Lmdsc2wuanMnO1xyXG5pbXBvcnQgbGlnaHRzX2xhbWJlcnRfZnJhZ21lbnQgZnJvbSAnLi9TaGFkZXJDaHVuay9saWdodHNfbGFtYmVydF9mcmFnbWVudC5nbHNsLmpzJztcclxuaW1wb3J0IGxpZ2h0c19sYW1iZXJ0X3BhcnNfZnJhZ21lbnQgZnJvbSAnLi9TaGFkZXJDaHVuay9saWdodHNfbGFtYmVydF9wYXJzX2ZyYWdtZW50Lmdsc2wuanMnO1xyXG5pbXBvcnQgbGlnaHRzX3BhcnNfYmVnaW4gZnJvbSAnLi9TaGFkZXJDaHVuay9saWdodHNfcGFyc19iZWdpbi5nbHNsLmpzJztcclxuaW1wb3J0IGVudm1hcF9waHlzaWNhbF9wYXJzX2ZyYWdtZW50IGZyb20gJy4vU2hhZGVyQ2h1bmsvZW52bWFwX3BoeXNpY2FsX3BhcnNfZnJhZ21lbnQuZ2xzbC5qcyc7XHJcbmltcG9ydCBsaWdodHNfdG9vbl9mcmFnbWVudCBmcm9tICcuL1NoYWRlckNodW5rL2xpZ2h0c190b29uX2ZyYWdtZW50Lmdsc2wuanMnO1xyXG5pbXBvcnQgbGlnaHRzX3Rvb25fcGFyc19mcmFnbWVudCBmcm9tICcuL1NoYWRlckNodW5rL2xpZ2h0c190b29uX3BhcnNfZnJhZ21lbnQuZ2xzbC5qcyc7XHJcbmltcG9ydCBsaWdodHNfcGhvbmdfZnJhZ21lbnQgZnJvbSAnLi9TaGFkZXJDaHVuay9saWdodHNfcGhvbmdfZnJhZ21lbnQuZ2xzbC5qcyc7XHJcbmltcG9ydCBsaWdodHNfcGhvbmdfcGFyc19mcmFnbWVudCBmcm9tICcuL1NoYWRlckNodW5rL2xpZ2h0c19waG9uZ19wYXJzX2ZyYWdtZW50Lmdsc2wuanMnO1xyXG5pbXBvcnQgbGlnaHRzX3BoeXNpY2FsX2ZyYWdtZW50IGZyb20gJy4vU2hhZGVyQ2h1bmsvbGlnaHRzX3BoeXNpY2FsX2ZyYWdtZW50Lmdsc2wuanMnO1xyXG5pbXBvcnQgbGlnaHRzX3BoeXNpY2FsX3BhcnNfZnJhZ21lbnQgZnJvbSAnLi9TaGFkZXJDaHVuay9saWdodHNfcGh5c2ljYWxfcGFyc19mcmFnbWVudC5nbHNsLmpzJztcclxuaW1wb3J0IGxpZ2h0c19mcmFnbWVudF9iZWdpbiBmcm9tICcuL1NoYWRlckNodW5rL2xpZ2h0c19mcmFnbWVudF9iZWdpbi5nbHNsLmpzJztcclxuaW1wb3J0IGxpZ2h0c19mcmFnbWVudF9tYXBzIGZyb20gJy4vU2hhZGVyQ2h1bmsvbGlnaHRzX2ZyYWdtZW50X21hcHMuZ2xzbC5qcyc7XHJcbmltcG9ydCBsaWdodHNfZnJhZ21lbnRfZW5kIGZyb20gJy4vU2hhZGVyQ2h1bmsvbGlnaHRzX2ZyYWdtZW50X2VuZC5nbHNsLmpzJztcclxuaW1wb3J0IGxvZ2RlcHRoYnVmX2ZyYWdtZW50IGZyb20gJy4vU2hhZGVyQ2h1bmsvbG9nZGVwdGhidWZfZnJhZ21lbnQuZ2xzbC5qcyc7XHJcbmltcG9ydCBsb2dkZXB0aGJ1Zl9wYXJzX2ZyYWdtZW50IGZyb20gJy4vU2hhZGVyQ2h1bmsvbG9nZGVwdGhidWZfcGFyc19mcmFnbWVudC5nbHNsLmpzJztcclxuaW1wb3J0IGxvZ2RlcHRoYnVmX3BhcnNfdmVydGV4IGZyb20gJy4vU2hhZGVyQ2h1bmsvbG9nZGVwdGhidWZfcGFyc192ZXJ0ZXguZ2xzbC5qcyc7XHJcbmltcG9ydCBsb2dkZXB0aGJ1Zl92ZXJ0ZXggZnJvbSAnLi9TaGFkZXJDaHVuay9sb2dkZXB0aGJ1Zl92ZXJ0ZXguZ2xzbC5qcyc7XHJcbmltcG9ydCBtYXBfZnJhZ21lbnQgZnJvbSAnLi9TaGFkZXJDaHVuay9tYXBfZnJhZ21lbnQuZ2xzbC5qcyc7XHJcbmltcG9ydCBtYXBfcGFyc19mcmFnbWVudCBmcm9tICcuL1NoYWRlckNodW5rL21hcF9wYXJzX2ZyYWdtZW50Lmdsc2wuanMnO1xyXG5pbXBvcnQgbWFwX3BhcnRpY2xlX2ZyYWdtZW50IGZyb20gJy4vU2hhZGVyQ2h1bmsvbWFwX3BhcnRpY2xlX2ZyYWdtZW50Lmdsc2wuanMnO1xyXG5pbXBvcnQgbWFwX3BhcnRpY2xlX3BhcnNfZnJhZ21lbnQgZnJvbSAnLi9TaGFkZXJDaHVuay9tYXBfcGFydGljbGVfcGFyc19mcmFnbWVudC5nbHNsLmpzJztcclxuaW1wb3J0IG1ldGFsbmVzc21hcF9mcmFnbWVudCBmcm9tICcuL1NoYWRlckNodW5rL21ldGFsbmVzc21hcF9mcmFnbWVudC5nbHNsLmpzJztcclxuaW1wb3J0IG1ldGFsbmVzc21hcF9wYXJzX2ZyYWdtZW50IGZyb20gJy4vU2hhZGVyQ2h1bmsvbWV0YWxuZXNzbWFwX3BhcnNfZnJhZ21lbnQuZ2xzbC5qcyc7XHJcbmltcG9ydCBtb3JwaGNvbG9yX3ZlcnRleCBmcm9tICcuL1NoYWRlckNodW5rL21vcnBoY29sb3JfdmVydGV4Lmdsc2wuanMnO1xyXG5pbXBvcnQgbW9ycGhub3JtYWxfdmVydGV4IGZyb20gJy4vU2hhZGVyQ2h1bmsvbW9ycGhub3JtYWxfdmVydGV4Lmdsc2wuanMnO1xyXG5pbXBvcnQgbW9ycGh0YXJnZXRfcGFyc192ZXJ0ZXggZnJvbSAnLi9TaGFkZXJDaHVuay9tb3JwaHRhcmdldF9wYXJzX3ZlcnRleC5nbHNsLmpzJztcclxuaW1wb3J0IG1vcnBodGFyZ2V0X3ZlcnRleCBmcm9tICcuL1NoYWRlckNodW5rL21vcnBodGFyZ2V0X3ZlcnRleC5nbHNsLmpzJztcclxuaW1wb3J0IG5vcm1hbF9mcmFnbWVudF9iZWdpbiBmcm9tICcuL1NoYWRlckNodW5rL25vcm1hbF9mcmFnbWVudF9iZWdpbi5nbHNsLmpzJztcclxuaW1wb3J0IG5vcm1hbF9mcmFnbWVudF9tYXBzIGZyb20gJy4vU2hhZGVyQ2h1bmsvbm9ybWFsX2ZyYWdtZW50X21hcHMuZ2xzbC5qcyc7XHJcbmltcG9ydCBub3JtYWxfcGFyc19mcmFnbWVudCBmcm9tICcuL1NoYWRlckNodW5rL25vcm1hbF9wYXJzX2ZyYWdtZW50Lmdsc2wuanMnO1xyXG5pbXBvcnQgbm9ybWFsX3BhcnNfdmVydGV4IGZyb20gJy4vU2hhZGVyQ2h1bmsvbm9ybWFsX3BhcnNfdmVydGV4Lmdsc2wuanMnO1xyXG5pbXBvcnQgbm9ybWFsX3ZlcnRleCBmcm9tICcuL1NoYWRlckNodW5rL25vcm1hbF92ZXJ0ZXguZ2xzbC5qcyc7XHJcbmltcG9ydCBub3JtYWxtYXBfcGFyc19mcmFnbWVudCBmcm9tICcuL1NoYWRlckNodW5rL25vcm1hbG1hcF9wYXJzX2ZyYWdtZW50Lmdsc2wuanMnO1xyXG5pbXBvcnQgY2xlYXJjb2F0X25vcm1hbF9mcmFnbWVudF9iZWdpbiBmcm9tICcuL1NoYWRlckNodW5rL2NsZWFyY29hdF9ub3JtYWxfZnJhZ21lbnRfYmVnaW4uZ2xzbC5qcyc7XHJcbmltcG9ydCBjbGVhcmNvYXRfbm9ybWFsX2ZyYWdtZW50X21hcHMgZnJvbSAnLi9TaGFkZXJDaHVuay9jbGVhcmNvYXRfbm9ybWFsX2ZyYWdtZW50X21hcHMuZ2xzbC5qcyc7XHJcbmltcG9ydCBjbGVhcmNvYXRfcGFyc19mcmFnbWVudCBmcm9tICcuL1NoYWRlckNodW5rL2NsZWFyY29hdF9wYXJzX2ZyYWdtZW50Lmdsc2wuanMnO1xyXG5pbXBvcnQgaXJpZGVzY2VuY2VfcGFyc19mcmFnbWVudCBmcm9tICcuL1NoYWRlckNodW5rL2lyaWRlc2NlbmNlX3BhcnNfZnJhZ21lbnQuZ2xzbC5qcyc7XHJcbmltcG9ydCBvcGFxdWVfZnJhZ21lbnQgZnJvbSAnLi9TaGFkZXJDaHVuay9vcGFxdWVfZnJhZ21lbnQuZ2xzbC5qcyc7XHJcbmltcG9ydCBwYWNraW5nIGZyb20gJy4vU2hhZGVyQ2h1bmsvcGFja2luZy5nbHNsLmpzJztcclxuaW1wb3J0IHByZW11bHRpcGxpZWRfYWxwaGFfZnJhZ21lbnQgZnJvbSAnLi9TaGFkZXJDaHVuay9wcmVtdWx0aXBsaWVkX2FscGhhX2ZyYWdtZW50Lmdsc2wuanMnO1xyXG5pbXBvcnQgcHJvamVjdF92ZXJ0ZXggZnJvbSAnLi9TaGFkZXJDaHVuay9wcm9qZWN0X3ZlcnRleC5nbHNsLmpzJztcclxuaW1wb3J0IGRpdGhlcmluZ19mcmFnbWVudCBmcm9tICcuL1NoYWRlckNodW5rL2RpdGhlcmluZ19mcmFnbWVudC5nbHNsLmpzJztcclxuaW1wb3J0IGRpdGhlcmluZ19wYXJzX2ZyYWdtZW50IGZyb20gJy4vU2hhZGVyQ2h1bmsvZGl0aGVyaW5nX3BhcnNfZnJhZ21lbnQuZ2xzbC5qcyc7XHJcbmltcG9ydCByb3VnaG5lc3NtYXBfZnJhZ21lbnQgZnJvbSAnLi9TaGFkZXJDaHVuay9yb3VnaG5lc3NtYXBfZnJhZ21lbnQuZ2xzbC5qcyc7XHJcbmltcG9ydCByb3VnaG5lc3NtYXBfcGFyc19mcmFnbWVudCBmcm9tICcuL1NoYWRlckNodW5rL3JvdWdobmVzc21hcF9wYXJzX2ZyYWdtZW50Lmdsc2wuanMnO1xyXG5pbXBvcnQgc2hhZG93bWFwX3BhcnNfZnJhZ21lbnQgZnJvbSAnLi9TaGFkZXJDaHVuay9zaGFkb3dtYXBfcGFyc19mcmFnbWVudC5nbHNsLmpzJztcclxuaW1wb3J0IHNoYWRvd21hcF9wYXJzX3ZlcnRleCBmcm9tICcuL1NoYWRlckNodW5rL3NoYWRvd21hcF9wYXJzX3ZlcnRleC5nbHNsLmpzJztcclxuaW1wb3J0IHNoYWRvd21hcF92ZXJ0ZXggZnJvbSAnLi9TaGFkZXJDaHVuay9zaGFkb3dtYXBfdmVydGV4Lmdsc2wuanMnO1xyXG5pbXBvcnQgc2hhZG93bWFza19wYXJzX2ZyYWdtZW50IGZyb20gJy4vU2hhZGVyQ2h1bmsvc2hhZG93bWFza19wYXJzX2ZyYWdtZW50Lmdsc2wuanMnO1xyXG5pbXBvcnQgc2tpbmJhc2VfdmVydGV4IGZyb20gJy4vU2hhZGVyQ2h1bmsvc2tpbmJhc2VfdmVydGV4Lmdsc2wuanMnO1xyXG5pbXBvcnQgc2tpbm5pbmdfcGFyc192ZXJ0ZXggZnJvbSAnLi9TaGFkZXJDaHVuay9za2lubmluZ19wYXJzX3ZlcnRleC5nbHNsLmpzJztcclxuaW1wb3J0IHNraW5uaW5nX3ZlcnRleCBmcm9tICcuL1NoYWRlckNodW5rL3NraW5uaW5nX3ZlcnRleC5nbHNsLmpzJztcclxuaW1wb3J0IHNraW5ub3JtYWxfdmVydGV4IGZyb20gJy4vU2hhZGVyQ2h1bmsvc2tpbm5vcm1hbF92ZXJ0ZXguZ2xzbC5qcyc7XHJcbmltcG9ydCBzcGVjdWxhcm1hcF9mcmFnbWVudCBmcm9tICcuL1NoYWRlckNodW5rL3NwZWN1bGFybWFwX2ZyYWdtZW50Lmdsc2wuanMnO1xyXG5pbXBvcnQgc3BlY3VsYXJtYXBfcGFyc19mcmFnbWVudCBmcm9tICcuL1NoYWRlckNodW5rL3NwZWN1bGFybWFwX3BhcnNfZnJhZ21lbnQuZ2xzbC5qcyc7XHJcbmltcG9ydCB0b25lbWFwcGluZ19mcmFnbWVudCBmcm9tICcuL1NoYWRlckNodW5rL3RvbmVtYXBwaW5nX2ZyYWdtZW50Lmdsc2wuanMnO1xyXG5pbXBvcnQgdG9uZW1hcHBpbmdfcGFyc19mcmFnbWVudCBmcm9tICcuL1NoYWRlckNodW5rL3RvbmVtYXBwaW5nX3BhcnNfZnJhZ21lbnQuZ2xzbC5qcyc7XHJcbmltcG9ydCB0cmFuc21pc3Npb25fZnJhZ21lbnQgZnJvbSAnLi9TaGFkZXJDaHVuay90cmFuc21pc3Npb25fZnJhZ21lbnQuZ2xzbC5qcyc7XHJcbmltcG9ydCB0cmFuc21pc3Npb25fcGFyc19mcmFnbWVudCBmcm9tICcuL1NoYWRlckNodW5rL3RyYW5zbWlzc2lvbl9wYXJzX2ZyYWdtZW50Lmdsc2wuanMnO1xyXG5pbXBvcnQgdXZfcGFyc19mcmFnbWVudCBmcm9tICcuL1NoYWRlckNodW5rL3V2X3BhcnNfZnJhZ21lbnQuZ2xzbC5qcyc7XHJcbmltcG9ydCB1dl9wYXJzX3ZlcnRleCBmcm9tICcuL1NoYWRlckNodW5rL3V2X3BhcnNfdmVydGV4Lmdsc2wuanMnO1xyXG5pbXBvcnQgdXZfdmVydGV4IGZyb20gJy4vU2hhZGVyQ2h1bmsvdXZfdmVydGV4Lmdsc2wuanMnO1xyXG5pbXBvcnQgd29ybGRwb3NfdmVydGV4IGZyb20gJy4vU2hhZGVyQ2h1bmsvd29ybGRwb3NfdmVydGV4Lmdsc2wuanMnO1xyXG5cclxuaW1wb3J0ICogYXMgYmFja2dyb3VuZCBmcm9tICcuL1NoYWRlckxpYi9iYWNrZ3JvdW5kLmdsc2wuanMnO1xyXG5pbXBvcnQgKiBhcyBiYWNrZ3JvdW5kQ3ViZSBmcm9tICcuL1NoYWRlckxpYi9iYWNrZ3JvdW5kQ3ViZS5nbHNsLmpzJztcclxuaW1wb3J0ICogYXMgY3ViZSBmcm9tICcuL1NoYWRlckxpYi9jdWJlLmdsc2wuanMnO1xyXG5pbXBvcnQgKiBhcyBkZXB0aCBmcm9tICcuL1NoYWRlckxpYi9kZXB0aC5nbHNsLmpzJztcclxuaW1wb3J0ICogYXMgZGlzdGFuY2VSR0JBIGZyb20gJy4vU2hhZGVyTGliL2Rpc3RhbmNlUkdCQS5nbHNsLmpzJztcclxuaW1wb3J0ICogYXMgZXF1aXJlY3QgZnJvbSAnLi9TaGFkZXJMaWIvZXF1aXJlY3QuZ2xzbC5qcyc7XHJcbmltcG9ydCAqIGFzIGxpbmVkYXNoZWQgZnJvbSAnLi9TaGFkZXJMaWIvbGluZWRhc2hlZC5nbHNsLmpzJztcclxuaW1wb3J0ICogYXMgbWVzaGJhc2ljIGZyb20gJy4vU2hhZGVyTGliL21lc2hiYXNpYy5nbHNsLmpzJztcclxuaW1wb3J0ICogYXMgbWVzaGxhbWJlcnQgZnJvbSAnLi9TaGFkZXJMaWIvbWVzaGxhbWJlcnQuZ2xzbC5qcyc7XHJcbmltcG9ydCAqIGFzIG1lc2htYXRjYXAgZnJvbSAnLi9TaGFkZXJMaWIvbWVzaG1hdGNhcC5nbHNsLmpzJztcclxuaW1wb3J0ICogYXMgbWVzaG5vcm1hbCBmcm9tICcuL1NoYWRlckxpYi9tZXNobm9ybWFsLmdsc2wuanMnO1xyXG5pbXBvcnQgKiBhcyBtZXNocGhvbmcgZnJvbSAnLi9TaGFkZXJMaWIvbWVzaHBob25nLmdsc2wuanMnO1xyXG5pbXBvcnQgKiBhcyBtZXNocGh5c2ljYWwgZnJvbSAnLi9TaGFkZXJMaWIvbWVzaHBoeXNpY2FsLmdsc2wuanMnO1xyXG5pbXBvcnQgKiBhcyBtZXNodG9vbiBmcm9tICcuL1NoYWRlckxpYi9tZXNodG9vbi5nbHNsLmpzJztcclxuaW1wb3J0ICogYXMgcG9pbnRzIGZyb20gJy4vU2hhZGVyTGliL3BvaW50cy5nbHNsLmpzJztcclxuaW1wb3J0ICogYXMgc2hhZG93IGZyb20gJy4vU2hhZGVyTGliL3NoYWRvdy5nbHNsLmpzJztcclxuaW1wb3J0ICogYXMgc3ByaXRlIGZyb20gJy4vU2hhZGVyTGliL3Nwcml0ZS5nbHNsLmpzJztcclxuXHJcbmV4cG9ydCBjb25zdCBTaGFkZXJDaHVuayA9IHtcclxuXHRhbHBoYWhhc2hfZnJhZ21lbnQ6IGFscGhhaGFzaF9mcmFnbWVudCxcclxuXHRhbHBoYWhhc2hfcGFyc19mcmFnbWVudDogYWxwaGFoYXNoX3BhcnNfZnJhZ21lbnQsXHJcblx0YWxwaGFtYXBfZnJhZ21lbnQ6IGFscGhhbWFwX2ZyYWdtZW50LFxyXG5cdGFscGhhbWFwX3BhcnNfZnJhZ21lbnQ6IGFscGhhbWFwX3BhcnNfZnJhZ21lbnQsXHJcblx0YWxwaGF0ZXN0X2ZyYWdtZW50OiBhbHBoYXRlc3RfZnJhZ21lbnQsXHJcblx0YWxwaGF0ZXN0X3BhcnNfZnJhZ21lbnQ6IGFscGhhdGVzdF9wYXJzX2ZyYWdtZW50LFxyXG5cdGFvbWFwX2ZyYWdtZW50OiBhb21hcF9mcmFnbWVudCxcclxuXHRhb21hcF9wYXJzX2ZyYWdtZW50OiBhb21hcF9wYXJzX2ZyYWdtZW50LFxyXG5cdGJhdGNoaW5nX3BhcnNfdmVydGV4OiBiYXRjaGluZ19wYXJzX3ZlcnRleCxcclxuXHRiYXRjaGluZ192ZXJ0ZXg6IGJhdGNoaW5nX3ZlcnRleCxcclxuXHRiZWdpbl92ZXJ0ZXg6IGJlZ2luX3ZlcnRleCxcclxuXHRiZWdpbm5vcm1hbF92ZXJ0ZXg6IGJlZ2lubm9ybWFsX3ZlcnRleCxcclxuXHRic2RmczogYnNkZnMsXHJcblx0aXJpZGVzY2VuY2VfZnJhZ21lbnQ6IGlyaWRlc2NlbmNlX2ZyYWdtZW50LFxyXG5cdGJ1bXBtYXBfcGFyc19mcmFnbWVudDogYnVtcG1hcF9wYXJzX2ZyYWdtZW50LFxyXG5cdGNsaXBwaW5nX3BsYW5lc19mcmFnbWVudDogY2xpcHBpbmdfcGxhbmVzX2ZyYWdtZW50LFxyXG5cdGNsaXBwaW5nX3BsYW5lc19wYXJzX2ZyYWdtZW50OiBjbGlwcGluZ19wbGFuZXNfcGFyc19mcmFnbWVudCxcclxuXHRjbGlwcGluZ19wbGFuZXNfcGFyc192ZXJ0ZXg6IGNsaXBwaW5nX3BsYW5lc19wYXJzX3ZlcnRleCxcclxuXHRjbGlwcGluZ19wbGFuZXNfdmVydGV4OiBjbGlwcGluZ19wbGFuZXNfdmVydGV4LFxyXG5cdGNvbG9yX2ZyYWdtZW50OiBjb2xvcl9mcmFnbWVudCxcclxuXHRjb2xvcl9wYXJzX2ZyYWdtZW50OiBjb2xvcl9wYXJzX2ZyYWdtZW50LFxyXG5cdGNvbG9yX3BhcnNfdmVydGV4OiBjb2xvcl9wYXJzX3ZlcnRleCxcclxuXHRjb2xvcl92ZXJ0ZXg6IGNvbG9yX3ZlcnRleCxcclxuXHRjb21tb246IGNvbW1vbixcclxuXHRjdWJlX3V2X3JlZmxlY3Rpb25fZnJhZ21lbnQ6IGN1YmVfdXZfcmVmbGVjdGlvbl9mcmFnbWVudCxcclxuXHRkZWZhdWx0bm9ybWFsX3ZlcnRleDogZGVmYXVsdG5vcm1hbF92ZXJ0ZXgsXHJcblx0ZGlzcGxhY2VtZW50bWFwX3BhcnNfdmVydGV4OiBkaXNwbGFjZW1lbnRtYXBfcGFyc192ZXJ0ZXgsXHJcblx0ZGlzcGxhY2VtZW50bWFwX3ZlcnRleDogZGlzcGxhY2VtZW50bWFwX3ZlcnRleCxcclxuXHRlbWlzc2l2ZW1hcF9mcmFnbWVudDogZW1pc3NpdmVtYXBfZnJhZ21lbnQsXHJcblx0ZW1pc3NpdmVtYXBfcGFyc19mcmFnbWVudDogZW1pc3NpdmVtYXBfcGFyc19mcmFnbWVudCxcclxuXHRjb2xvcnNwYWNlX2ZyYWdtZW50OiBjb2xvcnNwYWNlX2ZyYWdtZW50LFxyXG5cdGNvbG9yc3BhY2VfcGFyc19mcmFnbWVudDogY29sb3JzcGFjZV9wYXJzX2ZyYWdtZW50LFxyXG5cdGVudm1hcF9mcmFnbWVudDogZW52bWFwX2ZyYWdtZW50LFxyXG5cdGVudm1hcF9jb21tb25fcGFyc19mcmFnbWVudDogZW52bWFwX2NvbW1vbl9wYXJzX2ZyYWdtZW50LFxyXG5cdGVudm1hcF9wYXJzX2ZyYWdtZW50OiBlbnZtYXBfcGFyc19mcmFnbWVudCxcclxuXHRlbnZtYXBfcGFyc192ZXJ0ZXg6IGVudm1hcF9wYXJzX3ZlcnRleCxcclxuXHRlbnZtYXBfcGh5c2ljYWxfcGFyc19mcmFnbWVudDogZW52bWFwX3BoeXNpY2FsX3BhcnNfZnJhZ21lbnQsXHJcblx0ZW52bWFwX3ZlcnRleDogZW52bWFwX3ZlcnRleCxcclxuXHRmb2dfdmVydGV4OiBmb2dfdmVydGV4LFxyXG5cdGZvZ19wYXJzX3ZlcnRleDogZm9nX3BhcnNfdmVydGV4LFxyXG5cdGZvZ19mcmFnbWVudDogZm9nX2ZyYWdtZW50LFxyXG5cdGZvZ19wYXJzX2ZyYWdtZW50OiBmb2dfcGFyc19mcmFnbWVudCxcclxuXHRncmFkaWVudG1hcF9wYXJzX2ZyYWdtZW50OiBncmFkaWVudG1hcF9wYXJzX2ZyYWdtZW50LFxyXG5cdGxpZ2h0bWFwX2ZyYWdtZW50OiBsaWdodG1hcF9mcmFnbWVudCxcclxuXHRsaWdodG1hcF9wYXJzX2ZyYWdtZW50OiBsaWdodG1hcF9wYXJzX2ZyYWdtZW50LFxyXG5cdGxpZ2h0c19sYW1iZXJ0X2ZyYWdtZW50OiBsaWdodHNfbGFtYmVydF9mcmFnbWVudCxcclxuXHRsaWdodHNfbGFtYmVydF9wYXJzX2ZyYWdtZW50OiBsaWdodHNfbGFtYmVydF9wYXJzX2ZyYWdtZW50LFxyXG5cdGxpZ2h0c19wYXJzX2JlZ2luOiBsaWdodHNfcGFyc19iZWdpbixcclxuXHRsaWdodHNfdG9vbl9mcmFnbWVudDogbGlnaHRzX3Rvb25fZnJhZ21lbnQsXHJcblx0bGlnaHRzX3Rvb25fcGFyc19mcmFnbWVudDogbGlnaHRzX3Rvb25fcGFyc19mcmFnbWVudCxcclxuXHRsaWdodHNfcGhvbmdfZnJhZ21lbnQ6IGxpZ2h0c19waG9uZ19mcmFnbWVudCxcclxuXHRsaWdodHNfcGhvbmdfcGFyc19mcmFnbWVudDogbGlnaHRzX3Bob25nX3BhcnNfZnJhZ21lbnQsXHJcblx0bGlnaHRzX3BoeXNpY2FsX2ZyYWdtZW50OiBsaWdodHNfcGh5c2ljYWxfZnJhZ21lbnQsXHJcblx0bGlnaHRzX3BoeXNpY2FsX3BhcnNfZnJhZ21lbnQ6IGxpZ2h0c19waHlzaWNhbF9wYXJzX2ZyYWdtZW50LFxyXG5cdGxpZ2h0c19mcmFnbWVudF9iZWdpbjogbGlnaHRzX2ZyYWdtZW50X2JlZ2luLFxyXG5cdGxpZ2h0c19mcmFnbWVudF9tYXBzOiBsaWdodHNfZnJhZ21lbnRfbWFwcyxcclxuXHRsaWdodHNfZnJhZ21lbnRfZW5kOiBsaWdodHNfZnJhZ21lbnRfZW5kLFxyXG5cdGxvZ2RlcHRoYnVmX2ZyYWdtZW50OiBsb2dkZXB0aGJ1Zl9mcmFnbWVudCxcclxuXHRsb2dkZXB0aGJ1Zl9wYXJzX2ZyYWdtZW50OiBsb2dkZXB0aGJ1Zl9wYXJzX2ZyYWdtZW50LFxyXG5cdGxvZ2RlcHRoYnVmX3BhcnNfdmVydGV4OiBsb2dkZXB0aGJ1Zl9wYXJzX3ZlcnRleCxcclxuXHRsb2dkZXB0aGJ1Zl92ZXJ0ZXg6IGxvZ2RlcHRoYnVmX3ZlcnRleCxcclxuXHRtYXBfZnJhZ21lbnQ6IG1hcF9mcmFnbWVudCxcclxuXHRtYXBfcGFyc19mcmFnbWVudDogbWFwX3BhcnNfZnJhZ21lbnQsXHJcblx0bWFwX3BhcnRpY2xlX2ZyYWdtZW50OiBtYXBfcGFydGljbGVfZnJhZ21lbnQsXHJcblx0bWFwX3BhcnRpY2xlX3BhcnNfZnJhZ21lbnQ6IG1hcF9wYXJ0aWNsZV9wYXJzX2ZyYWdtZW50LFxyXG5cdG1ldGFsbmVzc21hcF9mcmFnbWVudDogbWV0YWxuZXNzbWFwX2ZyYWdtZW50LFxyXG5cdG1ldGFsbmVzc21hcF9wYXJzX2ZyYWdtZW50OiBtZXRhbG5lc3NtYXBfcGFyc19mcmFnbWVudCxcclxuXHRtb3JwaGNvbG9yX3ZlcnRleDogbW9ycGhjb2xvcl92ZXJ0ZXgsXHJcblx0bW9ycGhub3JtYWxfdmVydGV4OiBtb3JwaG5vcm1hbF92ZXJ0ZXgsXHJcblx0bW9ycGh0YXJnZXRfcGFyc192ZXJ0ZXg6IG1vcnBodGFyZ2V0X3BhcnNfdmVydGV4LFxyXG5cdG1vcnBodGFyZ2V0X3ZlcnRleDogbW9ycGh0YXJnZXRfdmVydGV4LFxyXG5cdG5vcm1hbF9mcmFnbWVudF9iZWdpbjogbm9ybWFsX2ZyYWdtZW50X2JlZ2luLFxyXG5cdG5vcm1hbF9mcmFnbWVudF9tYXBzOiBub3JtYWxfZnJhZ21lbnRfbWFwcyxcclxuXHRub3JtYWxfcGFyc19mcmFnbWVudDogbm9ybWFsX3BhcnNfZnJhZ21lbnQsXHJcblx0bm9ybWFsX3BhcnNfdmVydGV4OiBub3JtYWxfcGFyc192ZXJ0ZXgsXHJcblx0bm9ybWFsX3ZlcnRleDogbm9ybWFsX3ZlcnRleCxcclxuXHRub3JtYWxtYXBfcGFyc19mcmFnbWVudDogbm9ybWFsbWFwX3BhcnNfZnJhZ21lbnQsXHJcblx0Y2xlYXJjb2F0X25vcm1hbF9mcmFnbWVudF9iZWdpbjogY2xlYXJjb2F0X25vcm1hbF9mcmFnbWVudF9iZWdpbixcclxuXHRjbGVhcmNvYXRfbm9ybWFsX2ZyYWdtZW50X21hcHM6IGNsZWFyY29hdF9ub3JtYWxfZnJhZ21lbnRfbWFwcyxcclxuXHRjbGVhcmNvYXRfcGFyc19mcmFnbWVudDogY2xlYXJjb2F0X3BhcnNfZnJhZ21lbnQsXHJcblx0aXJpZGVzY2VuY2VfcGFyc19mcmFnbWVudDogaXJpZGVzY2VuY2VfcGFyc19mcmFnbWVudCxcclxuXHRvcGFxdWVfZnJhZ21lbnQ6IG9wYXF1ZV9mcmFnbWVudCxcclxuXHRwYWNraW5nOiBwYWNraW5nLFxyXG5cdHByZW11bHRpcGxpZWRfYWxwaGFfZnJhZ21lbnQ6IHByZW11bHRpcGxpZWRfYWxwaGFfZnJhZ21lbnQsXHJcblx0cHJvamVjdF92ZXJ0ZXg6IHByb2plY3RfdmVydGV4LFxyXG5cdGRpdGhlcmluZ19mcmFnbWVudDogZGl0aGVyaW5nX2ZyYWdtZW50LFxyXG5cdGRpdGhlcmluZ19wYXJzX2ZyYWdtZW50OiBkaXRoZXJpbmdfcGFyc19mcmFnbWVudCxcclxuXHRyb3VnaG5lc3NtYXBfZnJhZ21lbnQ6IHJvdWdobmVzc21hcF9mcmFnbWVudCxcclxuXHRyb3VnaG5lc3NtYXBfcGFyc19mcmFnbWVudDogcm91Z2huZXNzbWFwX3BhcnNfZnJhZ21lbnQsXHJcblx0c2hhZG93bWFwX3BhcnNfZnJhZ21lbnQ6IHNoYWRvd21hcF9wYXJzX2ZyYWdtZW50LFxyXG5cdHNoYWRvd21hcF9wYXJzX3ZlcnRleDogc2hhZG93bWFwX3BhcnNfdmVydGV4LFxyXG5cdHNoYWRvd21hcF92ZXJ0ZXg6IHNoYWRvd21hcF92ZXJ0ZXgsXHJcblx0c2hhZG93bWFza19wYXJzX2ZyYWdtZW50OiBzaGFkb3dtYXNrX3BhcnNfZnJhZ21lbnQsXHJcblx0c2tpbmJhc2VfdmVydGV4OiBza2luYmFzZV92ZXJ0ZXgsXHJcblx0c2tpbm5pbmdfcGFyc192ZXJ0ZXg6IHNraW5uaW5nX3BhcnNfdmVydGV4LFxyXG5cdHNraW5uaW5nX3ZlcnRleDogc2tpbm5pbmdfdmVydGV4LFxyXG5cdHNraW5ub3JtYWxfdmVydGV4OiBza2lubm9ybWFsX3ZlcnRleCxcclxuXHRzcGVjdWxhcm1hcF9mcmFnbWVudDogc3BlY3VsYXJtYXBfZnJhZ21lbnQsXHJcblx0c3BlY3VsYXJtYXBfcGFyc19mcmFnbWVudDogc3BlY3VsYXJtYXBfcGFyc19mcmFnbWVudCxcclxuXHR0b25lbWFwcGluZ19mcmFnbWVudDogdG9uZW1hcHBpbmdfZnJhZ21lbnQsXHJcblx0dG9uZW1hcHBpbmdfcGFyc19mcmFnbWVudDogdG9uZW1hcHBpbmdfcGFyc19mcmFnbWVudCxcclxuXHR0cmFuc21pc3Npb25fZnJhZ21lbnQ6IHRyYW5zbWlzc2lvbl9mcmFnbWVudCxcclxuXHR0cmFuc21pc3Npb25fcGFyc19mcmFnbWVudDogdHJhbnNtaXNzaW9uX3BhcnNfZnJhZ21lbnQsXHJcblx0dXZfcGFyc19mcmFnbWVudDogdXZfcGFyc19mcmFnbWVudCxcclxuXHR1dl9wYXJzX3ZlcnRleDogdXZfcGFyc192ZXJ0ZXgsXHJcblx0dXZfdmVydGV4OiB1dl92ZXJ0ZXgsXHJcblx0d29ybGRwb3NfdmVydGV4OiB3b3JsZHBvc192ZXJ0ZXgsXHJcblxyXG5cdGJhY2tncm91bmRfdmVydDogYmFja2dyb3VuZC52ZXJ0ZXgsXHJcblx0YmFja2dyb3VuZF9mcmFnOiBiYWNrZ3JvdW5kLmZyYWdtZW50LFxyXG5cdGJhY2tncm91bmRDdWJlX3ZlcnQ6IGJhY2tncm91bmRDdWJlLnZlcnRleCxcclxuXHRiYWNrZ3JvdW5kQ3ViZV9mcmFnOiBiYWNrZ3JvdW5kQ3ViZS5mcmFnbWVudCxcclxuXHRjdWJlX3ZlcnQ6IGN1YmUudmVydGV4LFxyXG5cdGN1YmVfZnJhZzogY3ViZS5mcmFnbWVudCxcclxuXHRkZXB0aF92ZXJ0OiBkZXB0aC52ZXJ0ZXgsXHJcblx0ZGVwdGhfZnJhZzogZGVwdGguZnJhZ21lbnQsXHJcblx0ZGlzdGFuY2VSR0JBX3ZlcnQ6IGRpc3RhbmNlUkdCQS52ZXJ0ZXgsXHJcblx0ZGlzdGFuY2VSR0JBX2ZyYWc6IGRpc3RhbmNlUkdCQS5mcmFnbWVudCxcclxuXHRlcXVpcmVjdF92ZXJ0OiBlcXVpcmVjdC52ZXJ0ZXgsXHJcblx0ZXF1aXJlY3RfZnJhZzogZXF1aXJlY3QuZnJhZ21lbnQsXHJcblx0bGluZWRhc2hlZF92ZXJ0OiBsaW5lZGFzaGVkLnZlcnRleCxcclxuXHRsaW5lZGFzaGVkX2ZyYWc6IGxpbmVkYXNoZWQuZnJhZ21lbnQsXHJcblx0bWVzaGJhc2ljX3ZlcnQ6IG1lc2hiYXNpYy52ZXJ0ZXgsXHJcblx0bWVzaGJhc2ljX2ZyYWc6IG1lc2hiYXNpYy5mcmFnbWVudCxcclxuXHRtZXNobGFtYmVydF92ZXJ0OiBtZXNobGFtYmVydC52ZXJ0ZXgsXHJcblx0bWVzaGxhbWJlcnRfZnJhZzogbWVzaGxhbWJlcnQuZnJhZ21lbnQsXHJcblx0bWVzaG1hdGNhcF92ZXJ0OiBtZXNobWF0Y2FwLnZlcnRleCxcclxuXHRtZXNobWF0Y2FwX2ZyYWc6IG1lc2htYXRjYXAuZnJhZ21lbnQsXHJcblx0bWVzaG5vcm1hbF92ZXJ0OiBtZXNobm9ybWFsLnZlcnRleCxcclxuXHRtZXNobm9ybWFsX2ZyYWc6IG1lc2hub3JtYWwuZnJhZ21lbnQsXHJcblx0bWVzaHBob25nX3ZlcnQ6IG1lc2hwaG9uZy52ZXJ0ZXgsXHJcblx0bWVzaHBob25nX2ZyYWc6IG1lc2hwaG9uZy5mcmFnbWVudCxcclxuXHRtZXNocGh5c2ljYWxfdmVydDogbWVzaHBoeXNpY2FsLnZlcnRleCxcclxuXHRtZXNocGh5c2ljYWxfZnJhZzogbWVzaHBoeXNpY2FsLmZyYWdtZW50LFxyXG5cdG1lc2h0b29uX3ZlcnQ6IG1lc2h0b29uLnZlcnRleCxcclxuXHRtZXNodG9vbl9mcmFnOiBtZXNodG9vbi5mcmFnbWVudCxcclxuXHRwb2ludHNfdmVydDogcG9pbnRzLnZlcnRleCxcclxuXHRwb2ludHNfZnJhZzogcG9pbnRzLmZyYWdtZW50LFxyXG5cdHNoYWRvd192ZXJ0OiBzaGFkb3cudmVydGV4LFxyXG5cdHNoYWRvd19mcmFnOiBzaGFkb3cuZnJhZ21lbnQsXHJcblx0c3ByaXRlX3ZlcnQ6IHNwcml0ZS52ZXJ0ZXgsXHJcblx0c3ByaXRlX2ZyYWc6IHNwcml0ZS5mcmFnbWVudFxyXG59O1xyXG4iLCJpbXBvcnQgeyBDb2xvciB9IGZyb20gJy4uLy4uL21hdGgvQ29sb3IuanMnO1xyXG5pbXBvcnQgeyBWZWN0b3IyIH0gZnJvbSAnLi4vLi4vbWF0aC9WZWN0b3IyLmpzJztcclxuaW1wb3J0IHsgTWF0cml4MyB9IGZyb20gJy4uLy4uL21hdGgvTWF0cml4My5qcyc7XHJcblxyXG4vKipcclxuICogVW5pZm9ybXMgbGlicmFyeSBmb3Igc2hhcmVkIHdlYmdsIHNoYWRlcnNcclxuICovXHJcblxyXG5jb25zdCBVbmlmb3Jtc0xpYiA9IHtcclxuXHJcblx0Y29tbW9uOiB7XHJcblxyXG5cdFx0ZGlmZnVzZTogeyB2YWx1ZTogLypAX19QVVJFX18qLyBuZXcgQ29sb3IoIDB4ZmZmZmZmICkgfSxcclxuXHRcdG9wYWNpdHk6IHsgdmFsdWU6IDEuMCB9LFxyXG5cclxuXHRcdG1hcDogeyB2YWx1ZTogbnVsbCB9LFxyXG5cdFx0bWFwVHJhbnNmb3JtOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXgzKCkgfSxcclxuXHJcblx0XHRhbHBoYU1hcDogeyB2YWx1ZTogbnVsbCB9LFxyXG5cdFx0YWxwaGFNYXBUcmFuc2Zvcm06IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDMoKSB9LFxyXG5cclxuXHRcdGFscGhhVGVzdDogeyB2YWx1ZTogMCB9XHJcblxyXG5cdH0sXHJcblxyXG5cdHNwZWN1bGFybWFwOiB7XHJcblxyXG5cdFx0c3BlY3VsYXJNYXA6IHsgdmFsdWU6IG51bGwgfSxcclxuXHRcdHNwZWN1bGFyTWFwVHJhbnNmb3JtOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXgzKCkgfVxyXG5cclxuXHR9LFxyXG5cclxuXHRlbnZtYXA6IHtcclxuXHJcblx0XHRlbnZNYXA6IHsgdmFsdWU6IG51bGwgfSxcclxuXHRcdGZsaXBFbnZNYXA6IHsgdmFsdWU6IC0gMSB9LFxyXG5cdFx0cmVmbGVjdGl2aXR5OiB7IHZhbHVlOiAxLjAgfSwgLy8gYmFzaWMsIGxhbWJlcnQsIHBob25nXHJcblx0XHRpb3I6IHsgdmFsdWU6IDEuNSB9LCAvLyBwaHlzaWNhbFxyXG5cdFx0cmVmcmFjdGlvblJhdGlvOiB7IHZhbHVlOiAwLjk4IH0sIC8vIGJhc2ljLCBsYW1iZXJ0LCBwaG9uZ1xyXG5cclxuXHR9LFxyXG5cclxuXHRhb21hcDoge1xyXG5cclxuXHRcdGFvTWFwOiB7IHZhbHVlOiBudWxsIH0sXHJcblx0XHRhb01hcEludGVuc2l0eTogeyB2YWx1ZTogMSB9LFxyXG5cdFx0YW9NYXBUcmFuc2Zvcm06IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDMoKSB9XHJcblxyXG5cdH0sXHJcblxyXG5cdGxpZ2h0bWFwOiB7XHJcblxyXG5cdFx0bGlnaHRNYXA6IHsgdmFsdWU6IG51bGwgfSxcclxuXHRcdGxpZ2h0TWFwSW50ZW5zaXR5OiB7IHZhbHVlOiAxIH0sXHJcblx0XHRsaWdodE1hcFRyYW5zZm9ybTogeyB2YWx1ZTogLypAX19QVVJFX18qLyBuZXcgTWF0cml4MygpIH1cclxuXHJcblx0fSxcclxuXHJcblx0YnVtcG1hcDoge1xyXG5cclxuXHRcdGJ1bXBNYXA6IHsgdmFsdWU6IG51bGwgfSxcclxuXHRcdGJ1bXBNYXBUcmFuc2Zvcm06IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDMoKSB9LFxyXG5cdFx0YnVtcFNjYWxlOiB7IHZhbHVlOiAxIH1cclxuXHJcblx0fSxcclxuXHJcblx0bm9ybWFsbWFwOiB7XHJcblxyXG5cdFx0bm9ybWFsTWFwOiB7IHZhbHVlOiBudWxsIH0sXHJcblx0XHRub3JtYWxNYXBUcmFuc2Zvcm06IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDMoKSB9LFxyXG5cdFx0bm9ybWFsU2NhbGU6IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjIoIDEsIDEgKSB9XHJcblxyXG5cdH0sXHJcblxyXG5cdGRpc3BsYWNlbWVudG1hcDoge1xyXG5cclxuXHRcdGRpc3BsYWNlbWVudE1hcDogeyB2YWx1ZTogbnVsbCB9LFxyXG5cdFx0ZGlzcGxhY2VtZW50TWFwVHJhbnNmb3JtOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXgzKCkgfSxcclxuXHRcdGRpc3BsYWNlbWVudFNjYWxlOiB7IHZhbHVlOiAxIH0sXHJcblx0XHRkaXNwbGFjZW1lbnRCaWFzOiB7IHZhbHVlOiAwIH1cclxuXHJcblx0fSxcclxuXHJcblx0ZW1pc3NpdmVtYXA6IHtcclxuXHJcblx0XHRlbWlzc2l2ZU1hcDogeyB2YWx1ZTogbnVsbCB9LFxyXG5cdFx0ZW1pc3NpdmVNYXBUcmFuc2Zvcm06IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDMoKSB9XHJcblxyXG5cdH0sXHJcblxyXG5cdG1ldGFsbmVzc21hcDoge1xyXG5cclxuXHRcdG1ldGFsbmVzc01hcDogeyB2YWx1ZTogbnVsbCB9LFxyXG5cdFx0bWV0YWxuZXNzTWFwVHJhbnNmb3JtOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXgzKCkgfVxyXG5cclxuXHR9LFxyXG5cclxuXHRyb3VnaG5lc3NtYXA6IHtcclxuXHJcblx0XHRyb3VnaG5lc3NNYXA6IHsgdmFsdWU6IG51bGwgfSxcclxuXHRcdHJvdWdobmVzc01hcFRyYW5zZm9ybTogeyB2YWx1ZTogLypAX19QVVJFX18qLyBuZXcgTWF0cml4MygpIH1cclxuXHJcblx0fSxcclxuXHJcblx0Z3JhZGllbnRtYXA6IHtcclxuXHJcblx0XHRncmFkaWVudE1hcDogeyB2YWx1ZTogbnVsbCB9XHJcblxyXG5cdH0sXHJcblxyXG5cdGZvZzoge1xyXG5cclxuXHRcdGZvZ0RlbnNpdHk6IHsgdmFsdWU6IDAuMDAwMjUgfSxcclxuXHRcdGZvZ05lYXI6IHsgdmFsdWU6IDEgfSxcclxuXHRcdGZvZ0ZhcjogeyB2YWx1ZTogMjAwMCB9LFxyXG5cdFx0Zm9nQ29sb3I6IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IENvbG9yKCAweGZmZmZmZiApIH1cclxuXHJcblx0fSxcclxuXHJcblx0bGlnaHRzOiB7XHJcblxyXG5cdFx0YW1iaWVudExpZ2h0Q29sb3I6IHsgdmFsdWU6IFtdIH0sXHJcblxyXG5cdFx0bGlnaHRQcm9iZTogeyB2YWx1ZTogW10gfSxcclxuXHJcblx0XHRkaXJlY3Rpb25hbExpZ2h0czogeyB2YWx1ZTogW10sIHByb3BlcnRpZXM6IHtcclxuXHRcdFx0ZGlyZWN0aW9uOiB7fSxcclxuXHRcdFx0Y29sb3I6IHt9XHJcblx0XHR9IH0sXHJcblxyXG5cdFx0ZGlyZWN0aW9uYWxMaWdodFNoYWRvd3M6IHsgdmFsdWU6IFtdLCBwcm9wZXJ0aWVzOiB7XHJcblx0XHRcdHNoYWRvd0JpYXM6IHt9LFxyXG5cdFx0XHRzaGFkb3dOb3JtYWxCaWFzOiB7fSxcclxuXHRcdFx0c2hhZG93UmFkaXVzOiB7fSxcclxuXHRcdFx0c2hhZG93TWFwU2l6ZToge31cclxuXHRcdH0gfSxcclxuXHJcblx0XHRkaXJlY3Rpb25hbFNoYWRvd01hcDogeyB2YWx1ZTogW10gfSxcclxuXHRcdGRpcmVjdGlvbmFsU2hhZG93TWF0cml4OiB7IHZhbHVlOiBbXSB9LFxyXG5cclxuXHRcdHNwb3RMaWdodHM6IHsgdmFsdWU6IFtdLCBwcm9wZXJ0aWVzOiB7XHJcblx0XHRcdGNvbG9yOiB7fSxcclxuXHRcdFx0cG9zaXRpb246IHt9LFxyXG5cdFx0XHRkaXJlY3Rpb246IHt9LFxyXG5cdFx0XHRkaXN0YW5jZToge30sXHJcblx0XHRcdGNvbmVDb3M6IHt9LFxyXG5cdFx0XHRwZW51bWJyYUNvczoge30sXHJcblx0XHRcdGRlY2F5OiB7fVxyXG5cdFx0fSB9LFxyXG5cclxuXHRcdHNwb3RMaWdodFNoYWRvd3M6IHsgdmFsdWU6IFtdLCBwcm9wZXJ0aWVzOiB7XHJcblx0XHRcdHNoYWRvd0JpYXM6IHt9LFxyXG5cdFx0XHRzaGFkb3dOb3JtYWxCaWFzOiB7fSxcclxuXHRcdFx0c2hhZG93UmFkaXVzOiB7fSxcclxuXHRcdFx0c2hhZG93TWFwU2l6ZToge31cclxuXHRcdH0gfSxcclxuXHJcblx0XHRzcG90TGlnaHRNYXA6IHsgdmFsdWU6IFtdIH0sXHJcblx0XHRzcG90U2hhZG93TWFwOiB7IHZhbHVlOiBbXSB9LFxyXG5cdFx0c3BvdExpZ2h0TWF0cml4OiB7IHZhbHVlOiBbXSB9LFxyXG5cclxuXHRcdHBvaW50TGlnaHRzOiB7IHZhbHVlOiBbXSwgcHJvcGVydGllczoge1xyXG5cdFx0XHRjb2xvcjoge30sXHJcblx0XHRcdHBvc2l0aW9uOiB7fSxcclxuXHRcdFx0ZGVjYXk6IHt9LFxyXG5cdFx0XHRkaXN0YW5jZToge31cclxuXHRcdH0gfSxcclxuXHJcblx0XHRwb2ludExpZ2h0U2hhZG93czogeyB2YWx1ZTogW10sIHByb3BlcnRpZXM6IHtcclxuXHRcdFx0c2hhZG93Qmlhczoge30sXHJcblx0XHRcdHNoYWRvd05vcm1hbEJpYXM6IHt9LFxyXG5cdFx0XHRzaGFkb3dSYWRpdXM6IHt9LFxyXG5cdFx0XHRzaGFkb3dNYXBTaXplOiB7fSxcclxuXHRcdFx0c2hhZG93Q2FtZXJhTmVhcjoge30sXHJcblx0XHRcdHNoYWRvd0NhbWVyYUZhcjoge31cclxuXHRcdH0gfSxcclxuXHJcblx0XHRwb2ludFNoYWRvd01hcDogeyB2YWx1ZTogW10gfSxcclxuXHRcdHBvaW50U2hhZG93TWF0cml4OiB7IHZhbHVlOiBbXSB9LFxyXG5cclxuXHRcdGhlbWlzcGhlcmVMaWdodHM6IHsgdmFsdWU6IFtdLCBwcm9wZXJ0aWVzOiB7XHJcblx0XHRcdGRpcmVjdGlvbjoge30sXHJcblx0XHRcdHNreUNvbG9yOiB7fSxcclxuXHRcdFx0Z3JvdW5kQ29sb3I6IHt9XHJcblx0XHR9IH0sXHJcblxyXG5cdFx0Ly8gVE9ETyAoYWJlbG5hdGlvbik6IFJlY3RBcmVhTGlnaHQgQlJERiBkYXRhIG5lZWRzIHRvIGJlIG1vdmVkIGZyb20gZXhhbXBsZSB0byBtYWluIHNyY1xyXG5cdFx0cmVjdEFyZWFMaWdodHM6IHsgdmFsdWU6IFtdLCBwcm9wZXJ0aWVzOiB7XHJcblx0XHRcdGNvbG9yOiB7fSxcclxuXHRcdFx0cG9zaXRpb246IHt9LFxyXG5cdFx0XHR3aWR0aDoge30sXHJcblx0XHRcdGhlaWdodDoge31cclxuXHRcdH0gfSxcclxuXHJcblx0XHRsdGNfMTogeyB2YWx1ZTogbnVsbCB9LFxyXG5cdFx0bHRjXzI6IHsgdmFsdWU6IG51bGwgfVxyXG5cclxuXHR9LFxyXG5cclxuXHRwb2ludHM6IHtcclxuXHJcblx0XHRkaWZmdXNlOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBDb2xvciggMHhmZmZmZmYgKSB9LFxyXG5cdFx0b3BhY2l0eTogeyB2YWx1ZTogMS4wIH0sXHJcblx0XHRzaXplOiB7IHZhbHVlOiAxLjAgfSxcclxuXHRcdHNjYWxlOiB7IHZhbHVlOiAxLjAgfSxcclxuXHRcdG1hcDogeyB2YWx1ZTogbnVsbCB9LFxyXG5cdFx0YWxwaGFNYXA6IHsgdmFsdWU6IG51bGwgfSxcclxuXHRcdGFscGhhTWFwVHJhbnNmb3JtOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXgzKCkgfSxcclxuXHRcdGFscGhhVGVzdDogeyB2YWx1ZTogMCB9LFxyXG5cdFx0dXZUcmFuc2Zvcm06IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDMoKSB9XHJcblxyXG5cdH0sXHJcblxyXG5cdHNwcml0ZToge1xyXG5cclxuXHRcdGRpZmZ1c2U6IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IENvbG9yKCAweGZmZmZmZiApIH0sXHJcblx0XHRvcGFjaXR5OiB7IHZhbHVlOiAxLjAgfSxcclxuXHRcdGNlbnRlcjogeyB2YWx1ZTogLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMiggMC41LCAwLjUgKSB9LFxyXG5cdFx0cm90YXRpb246IHsgdmFsdWU6IDAuMCB9LFxyXG5cdFx0bWFwOiB7IHZhbHVlOiBudWxsIH0sXHJcblx0XHRtYXBUcmFuc2Zvcm06IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDMoKSB9LFxyXG5cdFx0YWxwaGFNYXA6IHsgdmFsdWU6IG51bGwgfSxcclxuXHRcdGFscGhhTWFwVHJhbnNmb3JtOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXgzKCkgfSxcclxuXHRcdGFscGhhVGVzdDogeyB2YWx1ZTogMCB9XHJcblxyXG5cdH1cclxuXHJcbn07XHJcblxyXG5leHBvcnQgeyBVbmlmb3Jtc0xpYiB9O1xyXG4iLCJpbXBvcnQgeyBTaGFkZXJDaHVuayB9IGZyb20gJy4vU2hhZGVyQ2h1bmsuanMnO1xyXG5pbXBvcnQgeyBtZXJnZVVuaWZvcm1zIH0gZnJvbSAnLi9Vbmlmb3Jtc1V0aWxzLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yMiB9IGZyb20gJy4uLy4uL21hdGgvVmVjdG9yMi5qcyc7XHJcbmltcG9ydCB7IFZlY3RvcjMgfSBmcm9tICcuLi8uLi9tYXRoL1ZlY3RvcjMuanMnO1xyXG5pbXBvcnQgeyBVbmlmb3Jtc0xpYiB9IGZyb20gJy4vVW5pZm9ybXNMaWIuanMnO1xyXG5pbXBvcnQgeyBDb2xvciB9IGZyb20gJy4uLy4uL21hdGgvQ29sb3IuanMnO1xyXG5pbXBvcnQgeyBNYXRyaXgzIH0gZnJvbSAnLi4vLi4vbWF0aC9NYXRyaXgzLmpzJztcclxuXHJcbmNvbnN0IFNoYWRlckxpYiA9IHtcclxuXHJcblx0YmFzaWM6IHtcclxuXHJcblx0XHR1bmlmb3JtczogLypAX19QVVJFX18qLyBtZXJnZVVuaWZvcm1zKCBbXHJcblx0XHRcdFVuaWZvcm1zTGliLmNvbW1vbixcclxuXHRcdFx0VW5pZm9ybXNMaWIuc3BlY3VsYXJtYXAsXHJcblx0XHRcdFVuaWZvcm1zTGliLmVudm1hcCxcclxuXHRcdFx0VW5pZm9ybXNMaWIuYW9tYXAsXHJcblx0XHRcdFVuaWZvcm1zTGliLmxpZ2h0bWFwLFxyXG5cdFx0XHRVbmlmb3Jtc0xpYi5mb2dcclxuXHRcdF0gKSxcclxuXHJcblx0XHR2ZXJ0ZXhTaGFkZXI6IFNoYWRlckNodW5rLm1lc2hiYXNpY192ZXJ0LFxyXG5cdFx0ZnJhZ21lbnRTaGFkZXI6IFNoYWRlckNodW5rLm1lc2hiYXNpY19mcmFnXHJcblxyXG5cdH0sXHJcblxyXG5cdGxhbWJlcnQ6IHtcclxuXHJcblx0XHR1bmlmb3JtczogLypAX19QVVJFX18qLyBtZXJnZVVuaWZvcm1zKCBbXHJcblx0XHRcdFVuaWZvcm1zTGliLmNvbW1vbixcclxuXHRcdFx0VW5pZm9ybXNMaWIuc3BlY3VsYXJtYXAsXHJcblx0XHRcdFVuaWZvcm1zTGliLmVudm1hcCxcclxuXHRcdFx0VW5pZm9ybXNMaWIuYW9tYXAsXHJcblx0XHRcdFVuaWZvcm1zTGliLmxpZ2h0bWFwLFxyXG5cdFx0XHRVbmlmb3Jtc0xpYi5lbWlzc2l2ZW1hcCxcclxuXHRcdFx0VW5pZm9ybXNMaWIuYnVtcG1hcCxcclxuXHRcdFx0VW5pZm9ybXNMaWIubm9ybWFsbWFwLFxyXG5cdFx0XHRVbmlmb3Jtc0xpYi5kaXNwbGFjZW1lbnRtYXAsXHJcblx0XHRcdFVuaWZvcm1zTGliLmZvZyxcclxuXHRcdFx0VW5pZm9ybXNMaWIubGlnaHRzLFxyXG5cdFx0XHR7XHJcblx0XHRcdFx0ZW1pc3NpdmU6IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IENvbG9yKCAweDAwMDAwMCApIH1cclxuXHRcdFx0fVxyXG5cdFx0XSApLFxyXG5cclxuXHRcdHZlcnRleFNoYWRlcjogU2hhZGVyQ2h1bmsubWVzaGxhbWJlcnRfdmVydCxcclxuXHRcdGZyYWdtZW50U2hhZGVyOiBTaGFkZXJDaHVuay5tZXNobGFtYmVydF9mcmFnXHJcblxyXG5cdH0sXHJcblxyXG5cdHBob25nOiB7XHJcblxyXG5cdFx0dW5pZm9ybXM6IC8qQF9fUFVSRV9fKi8gbWVyZ2VVbmlmb3JtcyggW1xyXG5cdFx0XHRVbmlmb3Jtc0xpYi5jb21tb24sXHJcblx0XHRcdFVuaWZvcm1zTGliLnNwZWN1bGFybWFwLFxyXG5cdFx0XHRVbmlmb3Jtc0xpYi5lbnZtYXAsXHJcblx0XHRcdFVuaWZvcm1zTGliLmFvbWFwLFxyXG5cdFx0XHRVbmlmb3Jtc0xpYi5saWdodG1hcCxcclxuXHRcdFx0VW5pZm9ybXNMaWIuZW1pc3NpdmVtYXAsXHJcblx0XHRcdFVuaWZvcm1zTGliLmJ1bXBtYXAsXHJcblx0XHRcdFVuaWZvcm1zTGliLm5vcm1hbG1hcCxcclxuXHRcdFx0VW5pZm9ybXNMaWIuZGlzcGxhY2VtZW50bWFwLFxyXG5cdFx0XHRVbmlmb3Jtc0xpYi5mb2csXHJcblx0XHRcdFVuaWZvcm1zTGliLmxpZ2h0cyxcclxuXHRcdFx0e1xyXG5cdFx0XHRcdGVtaXNzaXZlOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBDb2xvciggMHgwMDAwMDAgKSB9LFxyXG5cdFx0XHRcdHNwZWN1bGFyOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBDb2xvciggMHgxMTExMTEgKSB9LFxyXG5cdFx0XHRcdHNoaW5pbmVzczogeyB2YWx1ZTogMzAgfVxyXG5cdFx0XHR9XHJcblx0XHRdICksXHJcblxyXG5cdFx0dmVydGV4U2hhZGVyOiBTaGFkZXJDaHVuay5tZXNocGhvbmdfdmVydCxcclxuXHRcdGZyYWdtZW50U2hhZGVyOiBTaGFkZXJDaHVuay5tZXNocGhvbmdfZnJhZ1xyXG5cclxuXHR9LFxyXG5cclxuXHRzdGFuZGFyZDoge1xyXG5cclxuXHRcdHVuaWZvcm1zOiAvKkBfX1BVUkVfXyovIG1lcmdlVW5pZm9ybXMoIFtcclxuXHRcdFx0VW5pZm9ybXNMaWIuY29tbW9uLFxyXG5cdFx0XHRVbmlmb3Jtc0xpYi5lbnZtYXAsXHJcblx0XHRcdFVuaWZvcm1zTGliLmFvbWFwLFxyXG5cdFx0XHRVbmlmb3Jtc0xpYi5saWdodG1hcCxcclxuXHRcdFx0VW5pZm9ybXNMaWIuZW1pc3NpdmVtYXAsXHJcblx0XHRcdFVuaWZvcm1zTGliLmJ1bXBtYXAsXHJcblx0XHRcdFVuaWZvcm1zTGliLm5vcm1hbG1hcCxcclxuXHRcdFx0VW5pZm9ybXNMaWIuZGlzcGxhY2VtZW50bWFwLFxyXG5cdFx0XHRVbmlmb3Jtc0xpYi5yb3VnaG5lc3NtYXAsXHJcblx0XHRcdFVuaWZvcm1zTGliLm1ldGFsbmVzc21hcCxcclxuXHRcdFx0VW5pZm9ybXNMaWIuZm9nLFxyXG5cdFx0XHRVbmlmb3Jtc0xpYi5saWdodHMsXHJcblx0XHRcdHtcclxuXHRcdFx0XHRlbWlzc2l2ZTogeyB2YWx1ZTogLypAX19QVVJFX18qLyBuZXcgQ29sb3IoIDB4MDAwMDAwICkgfSxcclxuXHRcdFx0XHRyb3VnaG5lc3M6IHsgdmFsdWU6IDEuMCB9LFxyXG5cdFx0XHRcdG1ldGFsbmVzczogeyB2YWx1ZTogMC4wIH0sXHJcblx0XHRcdFx0ZW52TWFwSW50ZW5zaXR5OiB7IHZhbHVlOiAxIH0gLy8gdGVtcG9yYXJ5XHJcblx0XHRcdH1cclxuXHRcdF0gKSxcclxuXHJcblx0XHR2ZXJ0ZXhTaGFkZXI6IFNoYWRlckNodW5rLm1lc2hwaHlzaWNhbF92ZXJ0LFxyXG5cdFx0ZnJhZ21lbnRTaGFkZXI6IFNoYWRlckNodW5rLm1lc2hwaHlzaWNhbF9mcmFnXHJcblxyXG5cdH0sXHJcblxyXG5cdHRvb246IHtcclxuXHJcblx0XHR1bmlmb3JtczogLypAX19QVVJFX18qLyBtZXJnZVVuaWZvcm1zKCBbXHJcblx0XHRcdFVuaWZvcm1zTGliLmNvbW1vbixcclxuXHRcdFx0VW5pZm9ybXNMaWIuYW9tYXAsXHJcblx0XHRcdFVuaWZvcm1zTGliLmxpZ2h0bWFwLFxyXG5cdFx0XHRVbmlmb3Jtc0xpYi5lbWlzc2l2ZW1hcCxcclxuXHRcdFx0VW5pZm9ybXNMaWIuYnVtcG1hcCxcclxuXHRcdFx0VW5pZm9ybXNMaWIubm9ybWFsbWFwLFxyXG5cdFx0XHRVbmlmb3Jtc0xpYi5kaXNwbGFjZW1lbnRtYXAsXHJcblx0XHRcdFVuaWZvcm1zTGliLmdyYWRpZW50bWFwLFxyXG5cdFx0XHRVbmlmb3Jtc0xpYi5mb2csXHJcblx0XHRcdFVuaWZvcm1zTGliLmxpZ2h0cyxcclxuXHRcdFx0e1xyXG5cdFx0XHRcdGVtaXNzaXZlOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBDb2xvciggMHgwMDAwMDAgKSB9XHJcblx0XHRcdH1cclxuXHRcdF0gKSxcclxuXHJcblx0XHR2ZXJ0ZXhTaGFkZXI6IFNoYWRlckNodW5rLm1lc2h0b29uX3ZlcnQsXHJcblx0XHRmcmFnbWVudFNoYWRlcjogU2hhZGVyQ2h1bmsubWVzaHRvb25fZnJhZ1xyXG5cclxuXHR9LFxyXG5cclxuXHRtYXRjYXA6IHtcclxuXHJcblx0XHR1bmlmb3JtczogLypAX19QVVJFX18qLyBtZXJnZVVuaWZvcm1zKCBbXHJcblx0XHRcdFVuaWZvcm1zTGliLmNvbW1vbixcclxuXHRcdFx0VW5pZm9ybXNMaWIuYnVtcG1hcCxcclxuXHRcdFx0VW5pZm9ybXNMaWIubm9ybWFsbWFwLFxyXG5cdFx0XHRVbmlmb3Jtc0xpYi5kaXNwbGFjZW1lbnRtYXAsXHJcblx0XHRcdFVuaWZvcm1zTGliLmZvZyxcclxuXHRcdFx0e1xyXG5cdFx0XHRcdG1hdGNhcDogeyB2YWx1ZTogbnVsbCB9XHJcblx0XHRcdH1cclxuXHRcdF0gKSxcclxuXHJcblx0XHR2ZXJ0ZXhTaGFkZXI6IFNoYWRlckNodW5rLm1lc2htYXRjYXBfdmVydCxcclxuXHRcdGZyYWdtZW50U2hhZGVyOiBTaGFkZXJDaHVuay5tZXNobWF0Y2FwX2ZyYWdcclxuXHJcblx0fSxcclxuXHJcblx0cG9pbnRzOiB7XHJcblxyXG5cdFx0dW5pZm9ybXM6IC8qQF9fUFVSRV9fKi8gbWVyZ2VVbmlmb3JtcyggW1xyXG5cdFx0XHRVbmlmb3Jtc0xpYi5wb2ludHMsXHJcblx0XHRcdFVuaWZvcm1zTGliLmZvZ1xyXG5cdFx0XSApLFxyXG5cclxuXHRcdHZlcnRleFNoYWRlcjogU2hhZGVyQ2h1bmsucG9pbnRzX3ZlcnQsXHJcblx0XHRmcmFnbWVudFNoYWRlcjogU2hhZGVyQ2h1bmsucG9pbnRzX2ZyYWdcclxuXHJcblx0fSxcclxuXHJcblx0ZGFzaGVkOiB7XHJcblxyXG5cdFx0dW5pZm9ybXM6IC8qQF9fUFVSRV9fKi8gbWVyZ2VVbmlmb3JtcyggW1xyXG5cdFx0XHRVbmlmb3Jtc0xpYi5jb21tb24sXHJcblx0XHRcdFVuaWZvcm1zTGliLmZvZyxcclxuXHRcdFx0e1xyXG5cdFx0XHRcdHNjYWxlOiB7IHZhbHVlOiAxIH0sXHJcblx0XHRcdFx0ZGFzaFNpemU6IHsgdmFsdWU6IDEgfSxcclxuXHRcdFx0XHR0b3RhbFNpemU6IHsgdmFsdWU6IDIgfVxyXG5cdFx0XHR9XHJcblx0XHRdICksXHJcblxyXG5cdFx0dmVydGV4U2hhZGVyOiBTaGFkZXJDaHVuay5saW5lZGFzaGVkX3ZlcnQsXHJcblx0XHRmcmFnbWVudFNoYWRlcjogU2hhZGVyQ2h1bmsubGluZWRhc2hlZF9mcmFnXHJcblxyXG5cdH0sXHJcblxyXG5cdGRlcHRoOiB7XHJcblxyXG5cdFx0dW5pZm9ybXM6IC8qQF9fUFVSRV9fKi8gbWVyZ2VVbmlmb3JtcyggW1xyXG5cdFx0XHRVbmlmb3Jtc0xpYi5jb21tb24sXHJcblx0XHRcdFVuaWZvcm1zTGliLmRpc3BsYWNlbWVudG1hcFxyXG5cdFx0XSApLFxyXG5cclxuXHRcdHZlcnRleFNoYWRlcjogU2hhZGVyQ2h1bmsuZGVwdGhfdmVydCxcclxuXHRcdGZyYWdtZW50U2hhZGVyOiBTaGFkZXJDaHVuay5kZXB0aF9mcmFnXHJcblxyXG5cdH0sXHJcblxyXG5cdG5vcm1hbDoge1xyXG5cclxuXHRcdHVuaWZvcm1zOiAvKkBfX1BVUkVfXyovIG1lcmdlVW5pZm9ybXMoIFtcclxuXHRcdFx0VW5pZm9ybXNMaWIuY29tbW9uLFxyXG5cdFx0XHRVbmlmb3Jtc0xpYi5idW1wbWFwLFxyXG5cdFx0XHRVbmlmb3Jtc0xpYi5ub3JtYWxtYXAsXHJcblx0XHRcdFVuaWZvcm1zTGliLmRpc3BsYWNlbWVudG1hcCxcclxuXHRcdFx0e1xyXG5cdFx0XHRcdG9wYWNpdHk6IHsgdmFsdWU6IDEuMCB9XHJcblx0XHRcdH1cclxuXHRcdF0gKSxcclxuXHJcblx0XHR2ZXJ0ZXhTaGFkZXI6IFNoYWRlckNodW5rLm1lc2hub3JtYWxfdmVydCxcclxuXHRcdGZyYWdtZW50U2hhZGVyOiBTaGFkZXJDaHVuay5tZXNobm9ybWFsX2ZyYWdcclxuXHJcblx0fSxcclxuXHJcblx0c3ByaXRlOiB7XHJcblxyXG5cdFx0dW5pZm9ybXM6IC8qQF9fUFVSRV9fKi8gbWVyZ2VVbmlmb3JtcyggW1xyXG5cdFx0XHRVbmlmb3Jtc0xpYi5zcHJpdGUsXHJcblx0XHRcdFVuaWZvcm1zTGliLmZvZ1xyXG5cdFx0XSApLFxyXG5cclxuXHRcdHZlcnRleFNoYWRlcjogU2hhZGVyQ2h1bmsuc3ByaXRlX3ZlcnQsXHJcblx0XHRmcmFnbWVudFNoYWRlcjogU2hhZGVyQ2h1bmsuc3ByaXRlX2ZyYWdcclxuXHJcblx0fSxcclxuXHJcblx0YmFja2dyb3VuZDoge1xyXG5cclxuXHRcdHVuaWZvcm1zOiB7XHJcblx0XHRcdHV2VHJhbnNmb3JtOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXgzKCkgfSxcclxuXHRcdFx0dDJEOiB7IHZhbHVlOiBudWxsIH0sXHJcblx0XHRcdGJhY2tncm91bmRJbnRlbnNpdHk6IHsgdmFsdWU6IDEgfVxyXG5cdFx0fSxcclxuXHJcblx0XHR2ZXJ0ZXhTaGFkZXI6IFNoYWRlckNodW5rLmJhY2tncm91bmRfdmVydCxcclxuXHRcdGZyYWdtZW50U2hhZGVyOiBTaGFkZXJDaHVuay5iYWNrZ3JvdW5kX2ZyYWdcclxuXHJcblx0fSxcclxuXHJcblx0YmFja2dyb3VuZEN1YmU6IHtcclxuXHJcblx0XHR1bmlmb3Jtczoge1xyXG5cdFx0XHRlbnZNYXA6IHsgdmFsdWU6IG51bGwgfSxcclxuXHRcdFx0ZmxpcEVudk1hcDogeyB2YWx1ZTogLSAxIH0sXHJcblx0XHRcdGJhY2tncm91bmRCbHVycmluZXNzOiB7IHZhbHVlOiAwIH0sXHJcblx0XHRcdGJhY2tncm91bmRJbnRlbnNpdHk6IHsgdmFsdWU6IDEgfVxyXG5cdFx0fSxcclxuXHJcblx0XHR2ZXJ0ZXhTaGFkZXI6IFNoYWRlckNodW5rLmJhY2tncm91bmRDdWJlX3ZlcnQsXHJcblx0XHRmcmFnbWVudFNoYWRlcjogU2hhZGVyQ2h1bmsuYmFja2dyb3VuZEN1YmVfZnJhZ1xyXG5cclxuXHR9LFxyXG5cclxuXHRjdWJlOiB7XHJcblxyXG5cdFx0dW5pZm9ybXM6IHtcclxuXHRcdFx0dEN1YmU6IHsgdmFsdWU6IG51bGwgfSxcclxuXHRcdFx0dEZsaXA6IHsgdmFsdWU6IC0gMSB9LFxyXG5cdFx0XHRvcGFjaXR5OiB7IHZhbHVlOiAxLjAgfVxyXG5cdFx0fSxcclxuXHJcblx0XHR2ZXJ0ZXhTaGFkZXI6IFNoYWRlckNodW5rLmN1YmVfdmVydCxcclxuXHRcdGZyYWdtZW50U2hhZGVyOiBTaGFkZXJDaHVuay5jdWJlX2ZyYWdcclxuXHJcblx0fSxcclxuXHJcblx0ZXF1aXJlY3Q6IHtcclxuXHJcblx0XHR1bmlmb3Jtczoge1xyXG5cdFx0XHR0RXF1aXJlY3Q6IHsgdmFsdWU6IG51bGwgfSxcclxuXHRcdH0sXHJcblxyXG5cdFx0dmVydGV4U2hhZGVyOiBTaGFkZXJDaHVuay5lcXVpcmVjdF92ZXJ0LFxyXG5cdFx0ZnJhZ21lbnRTaGFkZXI6IFNoYWRlckNodW5rLmVxdWlyZWN0X2ZyYWdcclxuXHJcblx0fSxcclxuXHJcblx0ZGlzdGFuY2VSR0JBOiB7XHJcblxyXG5cdFx0dW5pZm9ybXM6IC8qQF9fUFVSRV9fKi8gbWVyZ2VVbmlmb3JtcyggW1xyXG5cdFx0XHRVbmlmb3Jtc0xpYi5jb21tb24sXHJcblx0XHRcdFVuaWZvcm1zTGliLmRpc3BsYWNlbWVudG1hcCxcclxuXHRcdFx0e1xyXG5cdFx0XHRcdHJlZmVyZW5jZVBvc2l0aW9uOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCkgfSxcclxuXHRcdFx0XHRuZWFyRGlzdGFuY2U6IHsgdmFsdWU6IDEgfSxcclxuXHRcdFx0XHRmYXJEaXN0YW5jZTogeyB2YWx1ZTogMTAwMCB9XHJcblx0XHRcdH1cclxuXHRcdF0gKSxcclxuXHJcblx0XHR2ZXJ0ZXhTaGFkZXI6IFNoYWRlckNodW5rLmRpc3RhbmNlUkdCQV92ZXJ0LFxyXG5cdFx0ZnJhZ21lbnRTaGFkZXI6IFNoYWRlckNodW5rLmRpc3RhbmNlUkdCQV9mcmFnXHJcblxyXG5cdH0sXHJcblxyXG5cdHNoYWRvdzoge1xyXG5cclxuXHRcdHVuaWZvcm1zOiAvKkBfX1BVUkVfXyovIG1lcmdlVW5pZm9ybXMoIFtcclxuXHRcdFx0VW5pZm9ybXNMaWIubGlnaHRzLFxyXG5cdFx0XHRVbmlmb3Jtc0xpYi5mb2csXHJcblx0XHRcdHtcclxuXHRcdFx0XHRjb2xvcjogeyB2YWx1ZTogLypAX19QVVJFX18qLyBuZXcgQ29sb3IoIDB4MDAwMDAgKSB9LFxyXG5cdFx0XHRcdG9wYWNpdHk6IHsgdmFsdWU6IDEuMCB9XHJcblx0XHRcdH0sXHJcblx0XHRdICksXHJcblxyXG5cdFx0dmVydGV4U2hhZGVyOiBTaGFkZXJDaHVuay5zaGFkb3dfdmVydCxcclxuXHRcdGZyYWdtZW50U2hhZGVyOiBTaGFkZXJDaHVuay5zaGFkb3dfZnJhZ1xyXG5cclxuXHR9XHJcblxyXG59O1xyXG5cclxuU2hhZGVyTGliLnBoeXNpY2FsID0ge1xyXG5cclxuXHR1bmlmb3JtczogLypAX19QVVJFX18qLyBtZXJnZVVuaWZvcm1zKCBbXHJcblx0XHRTaGFkZXJMaWIuc3RhbmRhcmQudW5pZm9ybXMsXHJcblx0XHR7XHJcblx0XHRcdGNsZWFyY29hdDogeyB2YWx1ZTogMCB9LFxyXG5cdFx0XHRjbGVhcmNvYXRNYXA6IHsgdmFsdWU6IG51bGwgfSxcclxuXHRcdFx0Y2xlYXJjb2F0TWFwVHJhbnNmb3JtOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXgzKCkgfSxcclxuXHRcdFx0Y2xlYXJjb2F0Tm9ybWFsTWFwOiB7IHZhbHVlOiBudWxsIH0sXHJcblx0XHRcdGNsZWFyY29hdE5vcm1hbE1hcFRyYW5zZm9ybTogeyB2YWx1ZTogLypAX19QVVJFX18qLyBuZXcgTWF0cml4MygpIH0sXHJcblx0XHRcdGNsZWFyY29hdE5vcm1hbFNjYWxlOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IyKCAxLCAxICkgfSxcclxuXHRcdFx0Y2xlYXJjb2F0Um91Z2huZXNzOiB7IHZhbHVlOiAwIH0sXHJcblx0XHRcdGNsZWFyY29hdFJvdWdobmVzc01hcDogeyB2YWx1ZTogbnVsbCB9LFxyXG5cdFx0XHRjbGVhcmNvYXRSb3VnaG5lc3NNYXBUcmFuc2Zvcm06IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDMoKSB9LFxyXG5cdFx0XHRpcmlkZXNjZW5jZTogeyB2YWx1ZTogMCB9LFxyXG5cdFx0XHRpcmlkZXNjZW5jZU1hcDogeyB2YWx1ZTogbnVsbCB9LFxyXG5cdFx0XHRpcmlkZXNjZW5jZU1hcFRyYW5zZm9ybTogeyB2YWx1ZTogLypAX19QVVJFX18qLyBuZXcgTWF0cml4MygpIH0sXHJcblx0XHRcdGlyaWRlc2NlbmNlSU9SOiB7IHZhbHVlOiAxLjMgfSxcclxuXHRcdFx0aXJpZGVzY2VuY2VUaGlja25lc3NNaW5pbXVtOiB7IHZhbHVlOiAxMDAgfSxcclxuXHRcdFx0aXJpZGVzY2VuY2VUaGlja25lc3NNYXhpbXVtOiB7IHZhbHVlOiA0MDAgfSxcclxuXHRcdFx0aXJpZGVzY2VuY2VUaGlja25lc3NNYXA6IHsgdmFsdWU6IG51bGwgfSxcclxuXHRcdFx0aXJpZGVzY2VuY2VUaGlja25lc3NNYXBUcmFuc2Zvcm06IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDMoKSB9LFxyXG5cdFx0XHRzaGVlbjogeyB2YWx1ZTogMCB9LFxyXG5cdFx0XHRzaGVlbkNvbG9yOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBDb2xvciggMHgwMDAwMDAgKSB9LFxyXG5cdFx0XHRzaGVlbkNvbG9yTWFwOiB7IHZhbHVlOiBudWxsIH0sXHJcblx0XHRcdHNoZWVuQ29sb3JNYXBUcmFuc2Zvcm06IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDMoKSB9LFxyXG5cdFx0XHRzaGVlblJvdWdobmVzczogeyB2YWx1ZTogMSB9LFxyXG5cdFx0XHRzaGVlblJvdWdobmVzc01hcDogeyB2YWx1ZTogbnVsbCB9LFxyXG5cdFx0XHRzaGVlblJvdWdobmVzc01hcFRyYW5zZm9ybTogeyB2YWx1ZTogLypAX19QVVJFX18qLyBuZXcgTWF0cml4MygpIH0sXHJcblx0XHRcdHRyYW5zbWlzc2lvbjogeyB2YWx1ZTogMCB9LFxyXG5cdFx0XHR0cmFuc21pc3Npb25NYXA6IHsgdmFsdWU6IG51bGwgfSxcclxuXHRcdFx0dHJhbnNtaXNzaW9uTWFwVHJhbnNmb3JtOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXgzKCkgfSxcclxuXHRcdFx0dHJhbnNtaXNzaW9uU2FtcGxlclNpemU6IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjIoKSB9LFxyXG5cdFx0XHR0cmFuc21pc3Npb25TYW1wbGVyTWFwOiB7IHZhbHVlOiBudWxsIH0sXHJcblx0XHRcdHRoaWNrbmVzczogeyB2YWx1ZTogMCB9LFxyXG5cdFx0XHR0aGlja25lc3NNYXA6IHsgdmFsdWU6IG51bGwgfSxcclxuXHRcdFx0dGhpY2tuZXNzTWFwVHJhbnNmb3JtOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXgzKCkgfSxcclxuXHRcdFx0YXR0ZW51YXRpb25EaXN0YW5jZTogeyB2YWx1ZTogMCB9LFxyXG5cdFx0XHRhdHRlbnVhdGlvbkNvbG9yOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBDb2xvciggMHgwMDAwMDAgKSB9LFxyXG5cdFx0XHRzcGVjdWxhckNvbG9yOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBDb2xvciggMSwgMSwgMSApIH0sXHJcblx0XHRcdHNwZWN1bGFyQ29sb3JNYXA6IHsgdmFsdWU6IG51bGwgfSxcclxuXHRcdFx0c3BlY3VsYXJDb2xvck1hcFRyYW5zZm9ybTogeyB2YWx1ZTogLypAX19QVVJFX18qLyBuZXcgTWF0cml4MygpIH0sXHJcblx0XHRcdHNwZWN1bGFySW50ZW5zaXR5OiB7IHZhbHVlOiAxIH0sXHJcblx0XHRcdHNwZWN1bGFySW50ZW5zaXR5TWFwOiB7IHZhbHVlOiBudWxsIH0sXHJcblx0XHRcdHNwZWN1bGFySW50ZW5zaXR5TWFwVHJhbnNmb3JtOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXgzKCkgfSxcclxuXHRcdFx0YW5pc290cm9weVZlY3RvcjogeyB2YWx1ZTogLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMigpIH0sXHJcblx0XHRcdGFuaXNvdHJvcHlNYXA6IHsgdmFsdWU6IG51bGwgfSxcclxuXHRcdFx0YW5pc290cm9weU1hcFRyYW5zZm9ybTogeyB2YWx1ZTogLypAX19QVVJFX18qLyBuZXcgTWF0cml4MygpIH0sXHJcblx0XHR9XHJcblx0XSApLFxyXG5cclxuXHR2ZXJ0ZXhTaGFkZXI6IFNoYWRlckNodW5rLm1lc2hwaHlzaWNhbF92ZXJ0LFxyXG5cdGZyYWdtZW50U2hhZGVyOiBTaGFkZXJDaHVuay5tZXNocGh5c2ljYWxfZnJhZ1xyXG5cclxufTtcclxuXHJcblxyXG5leHBvcnQgeyBTaGFkZXJMaWIgfTtcclxuIiwiaW1wb3J0IHsgQmFja1NpZGUsIEZyb250U2lkZSwgQ3ViZVVWUmVmbGVjdGlvbk1hcHBpbmcsIFNSR0JUcmFuc2ZlciB9IGZyb20gJy4uLy4uL2NvbnN0YW50cy5qcyc7XHJcbmltcG9ydCB7IEJveEdlb21ldHJ5IH0gZnJvbSAnLi4vLi4vZ2VvbWV0cmllcy9Cb3hHZW9tZXRyeS5qcyc7XHJcbmltcG9ydCB7IFBsYW5lR2VvbWV0cnkgfSBmcm9tICcuLi8uLi9nZW9tZXRyaWVzL1BsYW5lR2VvbWV0cnkuanMnO1xyXG5pbXBvcnQgeyBTaGFkZXJNYXRlcmlhbCB9IGZyb20gJy4uLy4uL21hdGVyaWFscy9TaGFkZXJNYXRlcmlhbC5qcyc7XHJcbmltcG9ydCB7IENvbG9yIH0gZnJvbSAnLi4vLi4vbWF0aC9Db2xvci5qcyc7XHJcbmltcG9ydCB7IENvbG9yTWFuYWdlbWVudCB9IGZyb20gJy4uLy4uL21hdGgvQ29sb3JNYW5hZ2VtZW50LmpzJztcclxuaW1wb3J0IHsgTWVzaCB9IGZyb20gJy4uLy4uL29iamVjdHMvTWVzaC5qcyc7XHJcbmltcG9ydCB7IFNoYWRlckxpYiB9IGZyb20gJy4uL3NoYWRlcnMvU2hhZGVyTGliLmpzJztcclxuaW1wb3J0IHsgY2xvbmVVbmlmb3JtcywgZ2V0VW5saXRVbmlmb3JtQ29sb3JTcGFjZSB9IGZyb20gJy4uL3NoYWRlcnMvVW5pZm9ybXNVdGlscy5qcyc7XHJcblxyXG5jb25zdCBfcmdiID0geyByOiAwLCBiOiAwLCBnOiAwIH07XHJcblxyXG5mdW5jdGlvbiBXZWJHTEJhY2tncm91bmQoIHJlbmRlcmVyLCBjdWJlbWFwcywgY3ViZXV2bWFwcywgc3RhdGUsIG9iamVjdHMsIGFscGhhLCBwcmVtdWx0aXBsaWVkQWxwaGEgKSB7XHJcblxyXG5cdGNvbnN0IGNsZWFyQ29sb3IgPSBuZXcgQ29sb3IoIDB4MDAwMDAwICk7XHJcblx0bGV0IGNsZWFyQWxwaGEgPSBhbHBoYSA9PT0gdHJ1ZSA/IDAgOiAxO1xyXG5cclxuXHRsZXQgcGxhbmVNZXNoO1xyXG5cdGxldCBib3hNZXNoO1xyXG5cclxuXHRsZXQgY3VycmVudEJhY2tncm91bmQgPSBudWxsO1xyXG5cdGxldCBjdXJyZW50QmFja2dyb3VuZFZlcnNpb24gPSAwO1xyXG5cdGxldCBjdXJyZW50VG9uZW1hcHBpbmcgPSBudWxsO1xyXG5cclxuXHRmdW5jdGlvbiByZW5kZXIoIHJlbmRlckxpc3QsIHNjZW5lICkge1xyXG5cclxuXHRcdGxldCBmb3JjZUNsZWFyID0gZmFsc2U7XHJcblx0XHRsZXQgYmFja2dyb3VuZCA9IHNjZW5lLmlzU2NlbmUgPT09IHRydWUgPyBzY2VuZS5iYWNrZ3JvdW5kIDogbnVsbDtcclxuXHJcblx0XHRpZiAoIGJhY2tncm91bmQgJiYgYmFja2dyb3VuZC5pc1RleHR1cmUgKSB7XHJcblxyXG5cdFx0XHRjb25zdCB1c2VQTVJFTSA9IHNjZW5lLmJhY2tncm91bmRCbHVycmluZXNzID4gMDsgLy8gdXNlIFBNUkVNIGlmIHRoZSB1c2VyIHdhbnRzIHRvIGJsdXIgdGhlIGJhY2tncm91bmRcclxuXHRcdFx0YmFja2dyb3VuZCA9ICggdXNlUE1SRU0gPyBjdWJldXZtYXBzIDogY3ViZW1hcHMgKS5nZXQoIGJhY2tncm91bmQgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBiYWNrZ3JvdW5kID09PSBudWxsICkge1xyXG5cclxuXHRcdFx0c2V0Q2xlYXIoIGNsZWFyQ29sb3IsIGNsZWFyQWxwaGEgKTtcclxuXHJcblx0XHR9IGVsc2UgaWYgKCBiYWNrZ3JvdW5kICYmIGJhY2tncm91bmQuaXNDb2xvciApIHtcclxuXHJcblx0XHRcdHNldENsZWFyKCBiYWNrZ3JvdW5kLCAxICk7XHJcblx0XHRcdGZvcmNlQ2xlYXIgPSB0cnVlO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCBlbnZpcm9ubWVudEJsZW5kTW9kZSA9IHJlbmRlcmVyLnhyLmdldEVudmlyb25tZW50QmxlbmRNb2RlKCk7XHJcblxyXG5cdFx0aWYgKCBlbnZpcm9ubWVudEJsZW5kTW9kZSA9PT0gJ2FkZGl0aXZlJyApIHtcclxuXHJcblx0XHRcdHN0YXRlLmJ1ZmZlcnMuY29sb3Iuc2V0Q2xlYXIoIDAsIDAsIDAsIDEsIHByZW11bHRpcGxpZWRBbHBoYSApO1xyXG5cclxuXHRcdH0gZWxzZSBpZiAoIGVudmlyb25tZW50QmxlbmRNb2RlID09PSAnYWxwaGEtYmxlbmQnICkge1xyXG5cclxuXHRcdFx0c3RhdGUuYnVmZmVycy5jb2xvci5zZXRDbGVhciggMCwgMCwgMCwgMCwgcHJlbXVsdGlwbGllZEFscGhhICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggcmVuZGVyZXIuYXV0b0NsZWFyIHx8IGZvcmNlQ2xlYXIgKSB7XHJcblxyXG5cdFx0XHRyZW5kZXJlci5jbGVhciggcmVuZGVyZXIuYXV0b0NsZWFyQ29sb3IsIHJlbmRlcmVyLmF1dG9DbGVhckRlcHRoLCByZW5kZXJlci5hdXRvQ2xlYXJTdGVuY2lsICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggYmFja2dyb3VuZCAmJiAoIGJhY2tncm91bmQuaXNDdWJlVGV4dHVyZSB8fCBiYWNrZ3JvdW5kLm1hcHBpbmcgPT09IEN1YmVVVlJlZmxlY3Rpb25NYXBwaW5nICkgKSB7XHJcblxyXG5cdFx0XHRpZiAoIGJveE1lc2ggPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0Ym94TWVzaCA9IG5ldyBNZXNoKFxyXG5cdFx0XHRcdFx0bmV3IEJveEdlb21ldHJ5KCAxLCAxLCAxICksXHJcblx0XHRcdFx0XHRuZXcgU2hhZGVyTWF0ZXJpYWwoIHtcclxuXHRcdFx0XHRcdFx0bmFtZTogJ0JhY2tncm91bmRDdWJlTWF0ZXJpYWwnLFxyXG5cdFx0XHRcdFx0XHR1bmlmb3JtczogY2xvbmVVbmlmb3JtcyggU2hhZGVyTGliLmJhY2tncm91bmRDdWJlLnVuaWZvcm1zICksXHJcblx0XHRcdFx0XHRcdHZlcnRleFNoYWRlcjogU2hhZGVyTGliLmJhY2tncm91bmRDdWJlLnZlcnRleFNoYWRlcixcclxuXHRcdFx0XHRcdFx0ZnJhZ21lbnRTaGFkZXI6IFNoYWRlckxpYi5iYWNrZ3JvdW5kQ3ViZS5mcmFnbWVudFNoYWRlcixcclxuXHRcdFx0XHRcdFx0c2lkZTogQmFja1NpZGUsXHJcblx0XHRcdFx0XHRcdGRlcHRoVGVzdDogZmFsc2UsXHJcblx0XHRcdFx0XHRcdGRlcHRoV3JpdGU6IGZhbHNlLFxyXG5cdFx0XHRcdFx0XHRmb2c6IGZhbHNlXHJcblx0XHRcdFx0XHR9IClcclxuXHRcdFx0XHQpO1xyXG5cclxuXHRcdFx0XHRib3hNZXNoLmdlb21ldHJ5LmRlbGV0ZUF0dHJpYnV0ZSggJ25vcm1hbCcgKTtcclxuXHRcdFx0XHRib3hNZXNoLmdlb21ldHJ5LmRlbGV0ZUF0dHJpYnV0ZSggJ3V2JyApO1xyXG5cclxuXHRcdFx0XHRib3hNZXNoLm9uQmVmb3JlUmVuZGVyID0gZnVuY3Rpb24gKCByZW5kZXJlciwgc2NlbmUsIGNhbWVyYSApIHtcclxuXHJcblx0XHRcdFx0XHR0aGlzLm1hdHJpeFdvcmxkLmNvcHlQb3NpdGlvbiggY2FtZXJhLm1hdHJpeFdvcmxkICk7XHJcblxyXG5cdFx0XHRcdH07XHJcblxyXG5cdFx0XHRcdC8vIGFkZCBcImVudk1hcFwiIG1hdGVyaWFsIHByb3BlcnR5IHNvIHRoZSByZW5kZXJlciBjYW4gZXZhbHVhdGUgaXQgbGlrZSBmb3IgYnVpbHQtaW4gbWF0ZXJpYWxzXHJcblx0XHRcdFx0T2JqZWN0LmRlZmluZVByb3BlcnR5KCBib3hNZXNoLm1hdGVyaWFsLCAnZW52TWFwJywge1xyXG5cclxuXHRcdFx0XHRcdGdldDogZnVuY3Rpb24gKCkge1xyXG5cclxuXHRcdFx0XHRcdFx0cmV0dXJuIHRoaXMudW5pZm9ybXMuZW52TWFwLnZhbHVlO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fSApO1xyXG5cclxuXHRcdFx0XHRvYmplY3RzLnVwZGF0ZSggYm94TWVzaCApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Ym94TWVzaC5tYXRlcmlhbC51bmlmb3Jtcy5lbnZNYXAudmFsdWUgPSBiYWNrZ3JvdW5kO1xyXG5cdFx0XHRib3hNZXNoLm1hdGVyaWFsLnVuaWZvcm1zLmZsaXBFbnZNYXAudmFsdWUgPSAoIGJhY2tncm91bmQuaXNDdWJlVGV4dHVyZSAmJiBiYWNrZ3JvdW5kLmlzUmVuZGVyVGFyZ2V0VGV4dHVyZSA9PT0gZmFsc2UgKSA/IC0gMSA6IDE7XHJcblx0XHRcdGJveE1lc2gubWF0ZXJpYWwudW5pZm9ybXMuYmFja2dyb3VuZEJsdXJyaW5lc3MudmFsdWUgPSBzY2VuZS5iYWNrZ3JvdW5kQmx1cnJpbmVzcztcclxuXHRcdFx0Ym94TWVzaC5tYXRlcmlhbC51bmlmb3Jtcy5iYWNrZ3JvdW5kSW50ZW5zaXR5LnZhbHVlID0gc2NlbmUuYmFja2dyb3VuZEludGVuc2l0eTtcclxuXHRcdFx0Ym94TWVzaC5tYXRlcmlhbC50b25lTWFwcGVkID0gQ29sb3JNYW5hZ2VtZW50LmdldFRyYW5zZmVyKCBiYWNrZ3JvdW5kLmNvbG9yU3BhY2UgKSAhPT0gU1JHQlRyYW5zZmVyO1xyXG5cclxuXHRcdFx0aWYgKCBjdXJyZW50QmFja2dyb3VuZCAhPT0gYmFja2dyb3VuZCB8fFxyXG5cdFx0XHRcdGN1cnJlbnRCYWNrZ3JvdW5kVmVyc2lvbiAhPT0gYmFja2dyb3VuZC52ZXJzaW9uIHx8XHJcblx0XHRcdFx0Y3VycmVudFRvbmVtYXBwaW5nICE9PSByZW5kZXJlci50b25lTWFwcGluZyApIHtcclxuXHJcblx0XHRcdFx0Ym94TWVzaC5tYXRlcmlhbC5uZWVkc1VwZGF0ZSA9IHRydWU7XHJcblxyXG5cdFx0XHRcdGN1cnJlbnRCYWNrZ3JvdW5kID0gYmFja2dyb3VuZDtcclxuXHRcdFx0XHRjdXJyZW50QmFja2dyb3VuZFZlcnNpb24gPSBiYWNrZ3JvdW5kLnZlcnNpb247XHJcblx0XHRcdFx0Y3VycmVudFRvbmVtYXBwaW5nID0gcmVuZGVyZXIudG9uZU1hcHBpbmc7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRib3hNZXNoLmxheWVycy5lbmFibGVBbGwoKTtcclxuXHJcblx0XHRcdC8vIHB1c2ggdG8gdGhlIHByZS1zb3J0ZWQgb3BhcXVlIHJlbmRlciBsaXN0XHJcblx0XHRcdHJlbmRlckxpc3QudW5zaGlmdCggYm94TWVzaCwgYm94TWVzaC5nZW9tZXRyeSwgYm94TWVzaC5tYXRlcmlhbCwgMCwgMCwgbnVsbCApO1xyXG5cclxuXHRcdH0gZWxzZSBpZiAoIGJhY2tncm91bmQgJiYgYmFja2dyb3VuZC5pc1RleHR1cmUgKSB7XHJcblxyXG5cdFx0XHRpZiAoIHBsYW5lTWVzaCA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHRwbGFuZU1lc2ggPSBuZXcgTWVzaChcclxuXHRcdFx0XHRcdG5ldyBQbGFuZUdlb21ldHJ5KCAyLCAyICksXHJcblx0XHRcdFx0XHRuZXcgU2hhZGVyTWF0ZXJpYWwoIHtcclxuXHRcdFx0XHRcdFx0bmFtZTogJ0JhY2tncm91bmRNYXRlcmlhbCcsXHJcblx0XHRcdFx0XHRcdHVuaWZvcm1zOiBjbG9uZVVuaWZvcm1zKCBTaGFkZXJMaWIuYmFja2dyb3VuZC51bmlmb3JtcyApLFxyXG5cdFx0XHRcdFx0XHR2ZXJ0ZXhTaGFkZXI6IFNoYWRlckxpYi5iYWNrZ3JvdW5kLnZlcnRleFNoYWRlcixcclxuXHRcdFx0XHRcdFx0ZnJhZ21lbnRTaGFkZXI6IFNoYWRlckxpYi5iYWNrZ3JvdW5kLmZyYWdtZW50U2hhZGVyLFxyXG5cdFx0XHRcdFx0XHRzaWRlOiBGcm9udFNpZGUsXHJcblx0XHRcdFx0XHRcdGRlcHRoVGVzdDogZmFsc2UsXHJcblx0XHRcdFx0XHRcdGRlcHRoV3JpdGU6IGZhbHNlLFxyXG5cdFx0XHRcdFx0XHRmb2c6IGZhbHNlXHJcblx0XHRcdFx0XHR9IClcclxuXHRcdFx0XHQpO1xyXG5cclxuXHRcdFx0XHRwbGFuZU1lc2guZ2VvbWV0cnkuZGVsZXRlQXR0cmlidXRlKCAnbm9ybWFsJyApO1xyXG5cclxuXHRcdFx0XHQvLyBhZGQgXCJtYXBcIiBtYXRlcmlhbCBwcm9wZXJ0eSBzbyB0aGUgcmVuZGVyZXIgY2FuIGV2YWx1YXRlIGl0IGxpa2UgZm9yIGJ1aWx0LWluIG1hdGVyaWFsc1xyXG5cdFx0XHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eSggcGxhbmVNZXNoLm1hdGVyaWFsLCAnbWFwJywge1xyXG5cclxuXHRcdFx0XHRcdGdldDogZnVuY3Rpb24gKCkge1xyXG5cclxuXHRcdFx0XHRcdFx0cmV0dXJuIHRoaXMudW5pZm9ybXMudDJELnZhbHVlO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fSApO1xyXG5cclxuXHRcdFx0XHRvYmplY3RzLnVwZGF0ZSggcGxhbmVNZXNoICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRwbGFuZU1lc2gubWF0ZXJpYWwudW5pZm9ybXMudDJELnZhbHVlID0gYmFja2dyb3VuZDtcclxuXHRcdFx0cGxhbmVNZXNoLm1hdGVyaWFsLnVuaWZvcm1zLmJhY2tncm91bmRJbnRlbnNpdHkudmFsdWUgPSBzY2VuZS5iYWNrZ3JvdW5kSW50ZW5zaXR5O1xyXG5cdFx0XHRwbGFuZU1lc2gubWF0ZXJpYWwudG9uZU1hcHBlZCA9IENvbG9yTWFuYWdlbWVudC5nZXRUcmFuc2ZlciggYmFja2dyb3VuZC5jb2xvclNwYWNlICkgIT09IFNSR0JUcmFuc2ZlcjtcclxuXHJcblx0XHRcdGlmICggYmFja2dyb3VuZC5tYXRyaXhBdXRvVXBkYXRlID09PSB0cnVlICkge1xyXG5cclxuXHRcdFx0XHRiYWNrZ3JvdW5kLnVwZGF0ZU1hdHJpeCgpO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0cGxhbmVNZXNoLm1hdGVyaWFsLnVuaWZvcm1zLnV2VHJhbnNmb3JtLnZhbHVlLmNvcHkoIGJhY2tncm91bmQubWF0cml4ICk7XHJcblxyXG5cdFx0XHRpZiAoIGN1cnJlbnRCYWNrZ3JvdW5kICE9PSBiYWNrZ3JvdW5kIHx8XHJcblx0XHRcdFx0Y3VycmVudEJhY2tncm91bmRWZXJzaW9uICE9PSBiYWNrZ3JvdW5kLnZlcnNpb24gfHxcclxuXHRcdFx0XHRjdXJyZW50VG9uZW1hcHBpbmcgIT09IHJlbmRlcmVyLnRvbmVNYXBwaW5nICkge1xyXG5cclxuXHRcdFx0XHRwbGFuZU1lc2gubWF0ZXJpYWwubmVlZHNVcGRhdGUgPSB0cnVlO1xyXG5cclxuXHRcdFx0XHRjdXJyZW50QmFja2dyb3VuZCA9IGJhY2tncm91bmQ7XHJcblx0XHRcdFx0Y3VycmVudEJhY2tncm91bmRWZXJzaW9uID0gYmFja2dyb3VuZC52ZXJzaW9uO1xyXG5cdFx0XHRcdGN1cnJlbnRUb25lbWFwcGluZyA9IHJlbmRlcmVyLnRvbmVNYXBwaW5nO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0cGxhbmVNZXNoLmxheWVycy5lbmFibGVBbGwoKTtcclxuXHJcblx0XHRcdC8vIHB1c2ggdG8gdGhlIHByZS1zb3J0ZWQgb3BhcXVlIHJlbmRlciBsaXN0XHJcblx0XHRcdHJlbmRlckxpc3QudW5zaGlmdCggcGxhbmVNZXNoLCBwbGFuZU1lc2guZ2VvbWV0cnksIHBsYW5lTWVzaC5tYXRlcmlhbCwgMCwgMCwgbnVsbCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBzZXRDbGVhciggY29sb3IsIGFscGhhICkge1xyXG5cclxuXHRcdGNvbG9yLmdldFJHQiggX3JnYiwgZ2V0VW5saXRVbmlmb3JtQ29sb3JTcGFjZSggcmVuZGVyZXIgKSApO1xyXG5cclxuXHRcdHN0YXRlLmJ1ZmZlcnMuY29sb3Iuc2V0Q2xlYXIoIF9yZ2IuciwgX3JnYi5nLCBfcmdiLmIsIGFscGhhLCBwcmVtdWx0aXBsaWVkQWxwaGEgKTtcclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4ge1xyXG5cclxuXHRcdGdldENsZWFyQ29sb3I6IGZ1bmN0aW9uICgpIHtcclxuXHJcblx0XHRcdHJldHVybiBjbGVhckNvbG9yO1xyXG5cclxuXHRcdH0sXHJcblx0XHRzZXRDbGVhckNvbG9yOiBmdW5jdGlvbiAoIGNvbG9yLCBhbHBoYSA9IDEgKSB7XHJcblxyXG5cdFx0XHRjbGVhckNvbG9yLnNldCggY29sb3IgKTtcclxuXHRcdFx0Y2xlYXJBbHBoYSA9IGFscGhhO1xyXG5cdFx0XHRzZXRDbGVhciggY2xlYXJDb2xvciwgY2xlYXJBbHBoYSApO1xyXG5cclxuXHRcdH0sXHJcblx0XHRnZXRDbGVhckFscGhhOiBmdW5jdGlvbiAoKSB7XHJcblxyXG5cdFx0XHRyZXR1cm4gY2xlYXJBbHBoYTtcclxuXHJcblx0XHR9LFxyXG5cdFx0c2V0Q2xlYXJBbHBoYTogZnVuY3Rpb24gKCBhbHBoYSApIHtcclxuXHJcblx0XHRcdGNsZWFyQWxwaGEgPSBhbHBoYTtcclxuXHRcdFx0c2V0Q2xlYXIoIGNsZWFyQ29sb3IsIGNsZWFyQWxwaGEgKTtcclxuXHJcblx0XHR9LFxyXG5cdFx0cmVuZGVyOiByZW5kZXJcclxuXHJcblx0fTtcclxuXHJcbn1cclxuXHJcblxyXG5leHBvcnQgeyBXZWJHTEJhY2tncm91bmQgfTtcclxuIiwiaW1wb3J0IHsgSW50VHlwZSB9IGZyb20gJy4uLy4uL2NvbnN0YW50cy5qcyc7XHJcblxyXG5mdW5jdGlvbiBXZWJHTEJpbmRpbmdTdGF0ZXMoIGdsLCBleHRlbnNpb25zLCBhdHRyaWJ1dGVzLCBjYXBhYmlsaXRpZXMgKSB7XHJcblxyXG5cdGNvbnN0IG1heFZlcnRleEF0dHJpYnV0ZXMgPSBnbC5nZXRQYXJhbWV0ZXIoIGdsLk1BWF9WRVJURVhfQVRUUklCUyApO1xyXG5cclxuXHRjb25zdCBleHRlbnNpb24gPSBjYXBhYmlsaXRpZXMuaXNXZWJHTDIgPyBudWxsIDogZXh0ZW5zaW9ucy5nZXQoICdPRVNfdmVydGV4X2FycmF5X29iamVjdCcgKTtcclxuXHRjb25zdCB2YW9BdmFpbGFibGUgPSBjYXBhYmlsaXRpZXMuaXNXZWJHTDIgfHwgZXh0ZW5zaW9uICE9PSBudWxsO1xyXG5cclxuXHRjb25zdCBiaW5kaW5nU3RhdGVzID0ge307XHJcblxyXG5cdGNvbnN0IGRlZmF1bHRTdGF0ZSA9IGNyZWF0ZUJpbmRpbmdTdGF0ZSggbnVsbCApO1xyXG5cdGxldCBjdXJyZW50U3RhdGUgPSBkZWZhdWx0U3RhdGU7XHJcblx0bGV0IGZvcmNlVXBkYXRlID0gZmFsc2U7XHJcblxyXG5cdGZ1bmN0aW9uIHNldHVwKCBvYmplY3QsIG1hdGVyaWFsLCBwcm9ncmFtLCBnZW9tZXRyeSwgaW5kZXggKSB7XHJcblxyXG5cdFx0bGV0IHVwZGF0ZUJ1ZmZlcnMgPSBmYWxzZTtcclxuXHJcblx0XHRpZiAoIHZhb0F2YWlsYWJsZSApIHtcclxuXHJcblx0XHRcdGNvbnN0IHN0YXRlID0gZ2V0QmluZGluZ1N0YXRlKCBnZW9tZXRyeSwgcHJvZ3JhbSwgbWF0ZXJpYWwgKTtcclxuXHJcblx0XHRcdGlmICggY3VycmVudFN0YXRlICE9PSBzdGF0ZSApIHtcclxuXHJcblx0XHRcdFx0Y3VycmVudFN0YXRlID0gc3RhdGU7XHJcblx0XHRcdFx0YmluZFZlcnRleEFycmF5T2JqZWN0KCBjdXJyZW50U3RhdGUub2JqZWN0ICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHR1cGRhdGVCdWZmZXJzID0gbmVlZHNVcGRhdGUoIG9iamVjdCwgZ2VvbWV0cnksIHByb2dyYW0sIGluZGV4ICk7XHJcblxyXG5cdFx0XHRpZiAoIHVwZGF0ZUJ1ZmZlcnMgKSBzYXZlQ2FjaGUoIG9iamVjdCwgZ2VvbWV0cnksIHByb2dyYW0sIGluZGV4ICk7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdGNvbnN0IHdpcmVmcmFtZSA9ICggbWF0ZXJpYWwud2lyZWZyYW1lID09PSB0cnVlICk7XHJcblxyXG5cdFx0XHRpZiAoIGN1cnJlbnRTdGF0ZS5nZW9tZXRyeSAhPT0gZ2VvbWV0cnkuaWQgfHxcclxuXHRcdFx0XHRjdXJyZW50U3RhdGUucHJvZ3JhbSAhPT0gcHJvZ3JhbS5pZCB8fFxyXG5cdFx0XHRcdGN1cnJlbnRTdGF0ZS53aXJlZnJhbWUgIT09IHdpcmVmcmFtZSApIHtcclxuXHJcblx0XHRcdFx0Y3VycmVudFN0YXRlLmdlb21ldHJ5ID0gZ2VvbWV0cnkuaWQ7XHJcblx0XHRcdFx0Y3VycmVudFN0YXRlLnByb2dyYW0gPSBwcm9ncmFtLmlkO1xyXG5cdFx0XHRcdGN1cnJlbnRTdGF0ZS53aXJlZnJhbWUgPSB3aXJlZnJhbWU7XHJcblxyXG5cdFx0XHRcdHVwZGF0ZUJ1ZmZlcnMgPSB0cnVlO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIGluZGV4ICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0YXR0cmlidXRlcy51cGRhdGUoIGluZGV4LCBnbC5FTEVNRU5UX0FSUkFZX0JVRkZFUiApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHVwZGF0ZUJ1ZmZlcnMgfHwgZm9yY2VVcGRhdGUgKSB7XHJcblxyXG5cdFx0XHRmb3JjZVVwZGF0ZSA9IGZhbHNlO1xyXG5cclxuXHRcdFx0c2V0dXBWZXJ0ZXhBdHRyaWJ1dGVzKCBvYmplY3QsIG1hdGVyaWFsLCBwcm9ncmFtLCBnZW9tZXRyeSApO1xyXG5cclxuXHRcdFx0aWYgKCBpbmRleCAhPT0gbnVsbCApIHtcclxuXHJcblx0XHRcdFx0Z2wuYmluZEJ1ZmZlciggZ2wuRUxFTUVOVF9BUlJBWV9CVUZGRVIsIGF0dHJpYnV0ZXMuZ2V0KCBpbmRleCApLmJ1ZmZlciApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBjcmVhdGVWZXJ0ZXhBcnJheU9iamVjdCgpIHtcclxuXHJcblx0XHRpZiAoIGNhcGFiaWxpdGllcy5pc1dlYkdMMiApIHJldHVybiBnbC5jcmVhdGVWZXJ0ZXhBcnJheSgpO1xyXG5cclxuXHRcdHJldHVybiBleHRlbnNpb24uY3JlYXRlVmVydGV4QXJyYXlPRVMoKTtcclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBiaW5kVmVydGV4QXJyYXlPYmplY3QoIHZhbyApIHtcclxuXHJcblx0XHRpZiAoIGNhcGFiaWxpdGllcy5pc1dlYkdMMiApIHJldHVybiBnbC5iaW5kVmVydGV4QXJyYXkoIHZhbyApO1xyXG5cclxuXHRcdHJldHVybiBleHRlbnNpb24uYmluZFZlcnRleEFycmF5T0VTKCB2YW8gKTtcclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBkZWxldGVWZXJ0ZXhBcnJheU9iamVjdCggdmFvICkge1xyXG5cclxuXHRcdGlmICggY2FwYWJpbGl0aWVzLmlzV2ViR0wyICkgcmV0dXJuIGdsLmRlbGV0ZVZlcnRleEFycmF5KCB2YW8gKTtcclxuXHJcblx0XHRyZXR1cm4gZXh0ZW5zaW9uLmRlbGV0ZVZlcnRleEFycmF5T0VTKCB2YW8gKTtcclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBnZXRCaW5kaW5nU3RhdGUoIGdlb21ldHJ5LCBwcm9ncmFtLCBtYXRlcmlhbCApIHtcclxuXHJcblx0XHRjb25zdCB3aXJlZnJhbWUgPSAoIG1hdGVyaWFsLndpcmVmcmFtZSA9PT0gdHJ1ZSApO1xyXG5cclxuXHRcdGxldCBwcm9ncmFtTWFwID0gYmluZGluZ1N0YXRlc1sgZ2VvbWV0cnkuaWQgXTtcclxuXHJcblx0XHRpZiAoIHByb2dyYW1NYXAgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdHByb2dyYW1NYXAgPSB7fTtcclxuXHRcdFx0YmluZGluZ1N0YXRlc1sgZ2VvbWV0cnkuaWQgXSA9IHByb2dyYW1NYXA7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGxldCBzdGF0ZU1hcCA9IHByb2dyYW1NYXBbIHByb2dyYW0uaWQgXTtcclxuXHJcblx0XHRpZiAoIHN0YXRlTWFwID09PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRzdGF0ZU1hcCA9IHt9O1xyXG5cdFx0XHRwcm9ncmFtTWFwWyBwcm9ncmFtLmlkIF0gPSBzdGF0ZU1hcDtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0bGV0IHN0YXRlID0gc3RhdGVNYXBbIHdpcmVmcmFtZSBdO1xyXG5cclxuXHRcdGlmICggc3RhdGUgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdHN0YXRlID0gY3JlYXRlQmluZGluZ1N0YXRlKCBjcmVhdGVWZXJ0ZXhBcnJheU9iamVjdCgpICk7XHJcblx0XHRcdHN0YXRlTWFwWyB3aXJlZnJhbWUgXSA9IHN0YXRlO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gc3RhdGU7XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gY3JlYXRlQmluZGluZ1N0YXRlKCB2YW8gKSB7XHJcblxyXG5cdFx0Y29uc3QgbmV3QXR0cmlidXRlcyA9IFtdO1xyXG5cdFx0Y29uc3QgZW5hYmxlZEF0dHJpYnV0ZXMgPSBbXTtcclxuXHRcdGNvbnN0IGF0dHJpYnV0ZURpdmlzb3JzID0gW107XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgbWF4VmVydGV4QXR0cmlidXRlczsgaSArKyApIHtcclxuXHJcblx0XHRcdG5ld0F0dHJpYnV0ZXNbIGkgXSA9IDA7XHJcblx0XHRcdGVuYWJsZWRBdHRyaWJ1dGVzWyBpIF0gPSAwO1xyXG5cdFx0XHRhdHRyaWJ1dGVEaXZpc29yc1sgaSBdID0gMDtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHtcclxuXHJcblx0XHRcdC8vIGZvciBiYWNrd2FyZCBjb21wYXRpYmlsaXR5IG9uIG5vbi1WQU8gc3VwcG9ydCBicm93c2VyXHJcblx0XHRcdGdlb21ldHJ5OiBudWxsLFxyXG5cdFx0XHRwcm9ncmFtOiBudWxsLFxyXG5cdFx0XHR3aXJlZnJhbWU6IGZhbHNlLFxyXG5cclxuXHRcdFx0bmV3QXR0cmlidXRlczogbmV3QXR0cmlidXRlcyxcclxuXHRcdFx0ZW5hYmxlZEF0dHJpYnV0ZXM6IGVuYWJsZWRBdHRyaWJ1dGVzLFxyXG5cdFx0XHRhdHRyaWJ1dGVEaXZpc29yczogYXR0cmlidXRlRGl2aXNvcnMsXHJcblx0XHRcdG9iamVjdDogdmFvLFxyXG5cdFx0XHRhdHRyaWJ1dGVzOiB7fSxcclxuXHRcdFx0aW5kZXg6IG51bGxcclxuXHJcblx0XHR9O1xyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIG5lZWRzVXBkYXRlKCBvYmplY3QsIGdlb21ldHJ5LCBwcm9ncmFtLCBpbmRleCApIHtcclxuXHJcblx0XHRjb25zdCBjYWNoZWRBdHRyaWJ1dGVzID0gY3VycmVudFN0YXRlLmF0dHJpYnV0ZXM7XHJcblx0XHRjb25zdCBnZW9tZXRyeUF0dHJpYnV0ZXMgPSBnZW9tZXRyeS5hdHRyaWJ1dGVzO1xyXG5cclxuXHRcdGxldCBhdHRyaWJ1dGVzTnVtID0gMDtcclxuXHJcblx0XHRjb25zdCBwcm9ncmFtQXR0cmlidXRlcyA9IHByb2dyYW0uZ2V0QXR0cmlidXRlcygpO1xyXG5cclxuXHRcdGZvciAoIGNvbnN0IG5hbWUgaW4gcHJvZ3JhbUF0dHJpYnV0ZXMgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBwcm9ncmFtQXR0cmlidXRlID0gcHJvZ3JhbUF0dHJpYnV0ZXNbIG5hbWUgXTtcclxuXHJcblx0XHRcdGlmICggcHJvZ3JhbUF0dHJpYnV0ZS5sb2NhdGlvbiA+PSAwICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBjYWNoZWRBdHRyaWJ1dGUgPSBjYWNoZWRBdHRyaWJ1dGVzWyBuYW1lIF07XHJcblx0XHRcdFx0bGV0IGdlb21ldHJ5QXR0cmlidXRlID0gZ2VvbWV0cnlBdHRyaWJ1dGVzWyBuYW1lIF07XHJcblxyXG5cdFx0XHRcdGlmICggZ2VvbWV0cnlBdHRyaWJ1dGUgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0XHRpZiAoIG5hbWUgPT09ICdpbnN0YW5jZU1hdHJpeCcgJiYgb2JqZWN0Lmluc3RhbmNlTWF0cml4ICkgZ2VvbWV0cnlBdHRyaWJ1dGUgPSBvYmplY3QuaW5zdGFuY2VNYXRyaXg7XHJcblx0XHRcdFx0XHRpZiAoIG5hbWUgPT09ICdpbnN0YW5jZUNvbG9yJyAmJiBvYmplY3QuaW5zdGFuY2VDb2xvciApIGdlb21ldHJ5QXR0cmlidXRlID0gb2JqZWN0Lmluc3RhbmNlQ29sb3I7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0aWYgKCBjYWNoZWRBdHRyaWJ1dGUgPT09IHVuZGVmaW5lZCApIHJldHVybiB0cnVlO1xyXG5cclxuXHRcdFx0XHRpZiAoIGNhY2hlZEF0dHJpYnV0ZS5hdHRyaWJ1dGUgIT09IGdlb21ldHJ5QXR0cmlidXRlICkgcmV0dXJuIHRydWU7XHJcblxyXG5cdFx0XHRcdGlmICggZ2VvbWV0cnlBdHRyaWJ1dGUgJiYgY2FjaGVkQXR0cmlidXRlLmRhdGEgIT09IGdlb21ldHJ5QXR0cmlidXRlLmRhdGEgKSByZXR1cm4gdHJ1ZTtcclxuXHJcblx0XHRcdFx0YXR0cmlidXRlc051bSArKztcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBjdXJyZW50U3RhdGUuYXR0cmlidXRlc051bSAhPT0gYXR0cmlidXRlc051bSApIHJldHVybiB0cnVlO1xyXG5cclxuXHRcdGlmICggY3VycmVudFN0YXRlLmluZGV4ICE9PSBpbmRleCApIHJldHVybiB0cnVlO1xyXG5cclxuXHRcdHJldHVybiBmYWxzZTtcclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBzYXZlQ2FjaGUoIG9iamVjdCwgZ2VvbWV0cnksIHByb2dyYW0sIGluZGV4ICkge1xyXG5cclxuXHRcdGNvbnN0IGNhY2hlID0ge307XHJcblx0XHRjb25zdCBhdHRyaWJ1dGVzID0gZ2VvbWV0cnkuYXR0cmlidXRlcztcclxuXHRcdGxldCBhdHRyaWJ1dGVzTnVtID0gMDtcclxuXHJcblx0XHRjb25zdCBwcm9ncmFtQXR0cmlidXRlcyA9IHByb2dyYW0uZ2V0QXR0cmlidXRlcygpO1xyXG5cclxuXHRcdGZvciAoIGNvbnN0IG5hbWUgaW4gcHJvZ3JhbUF0dHJpYnV0ZXMgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBwcm9ncmFtQXR0cmlidXRlID0gcHJvZ3JhbUF0dHJpYnV0ZXNbIG5hbWUgXTtcclxuXHJcblx0XHRcdGlmICggcHJvZ3JhbUF0dHJpYnV0ZS5sb2NhdGlvbiA+PSAwICkge1xyXG5cclxuXHRcdFx0XHRsZXQgYXR0cmlidXRlID0gYXR0cmlidXRlc1sgbmFtZSBdO1xyXG5cclxuXHRcdFx0XHRpZiAoIGF0dHJpYnV0ZSA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHRcdGlmICggbmFtZSA9PT0gJ2luc3RhbmNlTWF0cml4JyAmJiBvYmplY3QuaW5zdGFuY2VNYXRyaXggKSBhdHRyaWJ1dGUgPSBvYmplY3QuaW5zdGFuY2VNYXRyaXg7XHJcblx0XHRcdFx0XHRpZiAoIG5hbWUgPT09ICdpbnN0YW5jZUNvbG9yJyAmJiBvYmplY3QuaW5zdGFuY2VDb2xvciApIGF0dHJpYnV0ZSA9IG9iamVjdC5pbnN0YW5jZUNvbG9yO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdGNvbnN0IGRhdGEgPSB7fTtcclxuXHRcdFx0XHRkYXRhLmF0dHJpYnV0ZSA9IGF0dHJpYnV0ZTtcclxuXHJcblx0XHRcdFx0aWYgKCBhdHRyaWJ1dGUgJiYgYXR0cmlidXRlLmRhdGEgKSB7XHJcblxyXG5cdFx0XHRcdFx0ZGF0YS5kYXRhID0gYXR0cmlidXRlLmRhdGE7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0Y2FjaGVbIG5hbWUgXSA9IGRhdGE7XHJcblxyXG5cdFx0XHRcdGF0dHJpYnV0ZXNOdW0gKys7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGN1cnJlbnRTdGF0ZS5hdHRyaWJ1dGVzID0gY2FjaGU7XHJcblx0XHRjdXJyZW50U3RhdGUuYXR0cmlidXRlc051bSA9IGF0dHJpYnV0ZXNOdW07XHJcblxyXG5cdFx0Y3VycmVudFN0YXRlLmluZGV4ID0gaW5kZXg7XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gaW5pdEF0dHJpYnV0ZXMoKSB7XHJcblxyXG5cdFx0Y29uc3QgbmV3QXR0cmlidXRlcyA9IGN1cnJlbnRTdGF0ZS5uZXdBdHRyaWJ1dGVzO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSBuZXdBdHRyaWJ1dGVzLmxlbmd0aDsgaSA8IGlsOyBpICsrICkge1xyXG5cclxuXHRcdFx0bmV3QXR0cmlidXRlc1sgaSBdID0gMDtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gZW5hYmxlQXR0cmlidXRlKCBhdHRyaWJ1dGUgKSB7XHJcblxyXG5cdFx0ZW5hYmxlQXR0cmlidXRlQW5kRGl2aXNvciggYXR0cmlidXRlLCAwICk7XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gZW5hYmxlQXR0cmlidXRlQW5kRGl2aXNvciggYXR0cmlidXRlLCBtZXNoUGVyQXR0cmlidXRlICkge1xyXG5cclxuXHRcdGNvbnN0IG5ld0F0dHJpYnV0ZXMgPSBjdXJyZW50U3RhdGUubmV3QXR0cmlidXRlcztcclxuXHRcdGNvbnN0IGVuYWJsZWRBdHRyaWJ1dGVzID0gY3VycmVudFN0YXRlLmVuYWJsZWRBdHRyaWJ1dGVzO1xyXG5cdFx0Y29uc3QgYXR0cmlidXRlRGl2aXNvcnMgPSBjdXJyZW50U3RhdGUuYXR0cmlidXRlRGl2aXNvcnM7XHJcblxyXG5cdFx0bmV3QXR0cmlidXRlc1sgYXR0cmlidXRlIF0gPSAxO1xyXG5cclxuXHRcdGlmICggZW5hYmxlZEF0dHJpYnV0ZXNbIGF0dHJpYnV0ZSBdID09PSAwICkge1xyXG5cclxuXHRcdFx0Z2wuZW5hYmxlVmVydGV4QXR0cmliQXJyYXkoIGF0dHJpYnV0ZSApO1xyXG5cdFx0XHRlbmFibGVkQXR0cmlidXRlc1sgYXR0cmlidXRlIF0gPSAxO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIGF0dHJpYnV0ZURpdmlzb3JzWyBhdHRyaWJ1dGUgXSAhPT0gbWVzaFBlckF0dHJpYnV0ZSApIHtcclxuXHJcblx0XHRcdGNvbnN0IGV4dGVuc2lvbiA9IGNhcGFiaWxpdGllcy5pc1dlYkdMMiA/IGdsIDogZXh0ZW5zaW9ucy5nZXQoICdBTkdMRV9pbnN0YW5jZWRfYXJyYXlzJyApO1xyXG5cclxuXHRcdFx0ZXh0ZW5zaW9uWyBjYXBhYmlsaXRpZXMuaXNXZWJHTDIgPyAndmVydGV4QXR0cmliRGl2aXNvcicgOiAndmVydGV4QXR0cmliRGl2aXNvckFOR0xFJyBdKCBhdHRyaWJ1dGUsIG1lc2hQZXJBdHRyaWJ1dGUgKTtcclxuXHRcdFx0YXR0cmlidXRlRGl2aXNvcnNbIGF0dHJpYnV0ZSBdID0gbWVzaFBlckF0dHJpYnV0ZTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gZGlzYWJsZVVudXNlZEF0dHJpYnV0ZXMoKSB7XHJcblxyXG5cdFx0Y29uc3QgbmV3QXR0cmlidXRlcyA9IGN1cnJlbnRTdGF0ZS5uZXdBdHRyaWJ1dGVzO1xyXG5cdFx0Y29uc3QgZW5hYmxlZEF0dHJpYnV0ZXMgPSBjdXJyZW50U3RhdGUuZW5hYmxlZEF0dHJpYnV0ZXM7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBpbCA9IGVuYWJsZWRBdHRyaWJ1dGVzLmxlbmd0aDsgaSA8IGlsOyBpICsrICkge1xyXG5cclxuXHRcdFx0aWYgKCBlbmFibGVkQXR0cmlidXRlc1sgaSBdICE9PSBuZXdBdHRyaWJ1dGVzWyBpIF0gKSB7XHJcblxyXG5cdFx0XHRcdGdsLmRpc2FibGVWZXJ0ZXhBdHRyaWJBcnJheSggaSApO1xyXG5cdFx0XHRcdGVuYWJsZWRBdHRyaWJ1dGVzWyBpIF0gPSAwO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiB2ZXJ0ZXhBdHRyaWJQb2ludGVyKCBpbmRleCwgc2l6ZSwgdHlwZSwgbm9ybWFsaXplZCwgc3RyaWRlLCBvZmZzZXQsIGludGVnZXIgKSB7XHJcblxyXG5cdFx0aWYgKCBpbnRlZ2VyID09PSB0cnVlICkge1xyXG5cclxuXHRcdFx0Z2wudmVydGV4QXR0cmliSVBvaW50ZXIoIGluZGV4LCBzaXplLCB0eXBlLCBzdHJpZGUsIG9mZnNldCApO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRnbC52ZXJ0ZXhBdHRyaWJQb2ludGVyKCBpbmRleCwgc2l6ZSwgdHlwZSwgbm9ybWFsaXplZCwgc3RyaWRlLCBvZmZzZXQgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gc2V0dXBWZXJ0ZXhBdHRyaWJ1dGVzKCBvYmplY3QsIG1hdGVyaWFsLCBwcm9ncmFtLCBnZW9tZXRyeSApIHtcclxuXHJcblx0XHRpZiAoIGNhcGFiaWxpdGllcy5pc1dlYkdMMiA9PT0gZmFsc2UgJiYgKCBvYmplY3QuaXNJbnN0YW5jZWRNZXNoIHx8IGdlb21ldHJ5LmlzSW5zdGFuY2VkQnVmZmVyR2VvbWV0cnkgKSApIHtcclxuXHJcblx0XHRcdGlmICggZXh0ZW5zaW9ucy5nZXQoICdBTkdMRV9pbnN0YW5jZWRfYXJyYXlzJyApID09PSBudWxsICkgcmV0dXJuO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpbml0QXR0cmlidXRlcygpO1xyXG5cclxuXHRcdGNvbnN0IGdlb21ldHJ5QXR0cmlidXRlcyA9IGdlb21ldHJ5LmF0dHJpYnV0ZXM7XHJcblxyXG5cdFx0Y29uc3QgcHJvZ3JhbUF0dHJpYnV0ZXMgPSBwcm9ncmFtLmdldEF0dHJpYnV0ZXMoKTtcclxuXHJcblx0XHRjb25zdCBtYXRlcmlhbERlZmF1bHRBdHRyaWJ1dGVWYWx1ZXMgPSBtYXRlcmlhbC5kZWZhdWx0QXR0cmlidXRlVmFsdWVzO1xyXG5cclxuXHRcdGZvciAoIGNvbnN0IG5hbWUgaW4gcHJvZ3JhbUF0dHJpYnV0ZXMgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBwcm9ncmFtQXR0cmlidXRlID0gcHJvZ3JhbUF0dHJpYnV0ZXNbIG5hbWUgXTtcclxuXHJcblx0XHRcdGlmICggcHJvZ3JhbUF0dHJpYnV0ZS5sb2NhdGlvbiA+PSAwICkge1xyXG5cclxuXHRcdFx0XHRsZXQgZ2VvbWV0cnlBdHRyaWJ1dGUgPSBnZW9tZXRyeUF0dHJpYnV0ZXNbIG5hbWUgXTtcclxuXHJcblx0XHRcdFx0aWYgKCBnZW9tZXRyeUF0dHJpYnV0ZSA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHRcdGlmICggbmFtZSA9PT0gJ2luc3RhbmNlTWF0cml4JyAmJiBvYmplY3QuaW5zdGFuY2VNYXRyaXggKSBnZW9tZXRyeUF0dHJpYnV0ZSA9IG9iamVjdC5pbnN0YW5jZU1hdHJpeDtcclxuXHRcdFx0XHRcdGlmICggbmFtZSA9PT0gJ2luc3RhbmNlQ29sb3InICYmIG9iamVjdC5pbnN0YW5jZUNvbG9yICkgZ2VvbWV0cnlBdHRyaWJ1dGUgPSBvYmplY3QuaW5zdGFuY2VDb2xvcjtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRpZiAoIGdlb21ldHJ5QXR0cmlidXRlICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y29uc3Qgbm9ybWFsaXplZCA9IGdlb21ldHJ5QXR0cmlidXRlLm5vcm1hbGl6ZWQ7XHJcblx0XHRcdFx0XHRjb25zdCBzaXplID0gZ2VvbWV0cnlBdHRyaWJ1dGUuaXRlbVNpemU7XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgYXR0cmlidXRlID0gYXR0cmlidXRlcy5nZXQoIGdlb21ldHJ5QXR0cmlidXRlICk7XHJcblxyXG5cdFx0XHRcdFx0Ly8gVE9ETyBBdHRyaWJ1dGUgbWF5IG5vdCBiZSBhdmFpbGFibGUgb24gY29udGV4dCByZXN0b3JlXHJcblxyXG5cdFx0XHRcdFx0aWYgKCBhdHRyaWJ1dGUgPT09IHVuZGVmaW5lZCApIGNvbnRpbnVlO1xyXG5cclxuXHRcdFx0XHRcdGNvbnN0IGJ1ZmZlciA9IGF0dHJpYnV0ZS5idWZmZXI7XHJcblx0XHRcdFx0XHRjb25zdCB0eXBlID0gYXR0cmlidXRlLnR5cGU7XHJcblx0XHRcdFx0XHRjb25zdCBieXRlc1BlckVsZW1lbnQgPSBhdHRyaWJ1dGUuYnl0ZXNQZXJFbGVtZW50O1xyXG5cclxuXHRcdFx0XHRcdC8vIGNoZWNrIGZvciBpbnRlZ2VyIGF0dHJpYnV0ZXMgKFdlYkdMIDIgb25seSlcclxuXHJcblx0XHRcdFx0XHRjb25zdCBpbnRlZ2VyID0gKCBjYXBhYmlsaXRpZXMuaXNXZWJHTDIgPT09IHRydWUgJiYgKCB0eXBlID09PSBnbC5JTlQgfHwgdHlwZSA9PT0gZ2wuVU5TSUdORURfSU5UIHx8IGdlb21ldHJ5QXR0cmlidXRlLmdwdVR5cGUgPT09IEludFR5cGUgKSApO1xyXG5cclxuXHRcdFx0XHRcdGlmICggZ2VvbWV0cnlBdHRyaWJ1dGUuaXNJbnRlcmxlYXZlZEJ1ZmZlckF0dHJpYnV0ZSApIHtcclxuXHJcblx0XHRcdFx0XHRcdGNvbnN0IGRhdGEgPSBnZW9tZXRyeUF0dHJpYnV0ZS5kYXRhO1xyXG5cdFx0XHRcdFx0XHRjb25zdCBzdHJpZGUgPSBkYXRhLnN0cmlkZTtcclxuXHRcdFx0XHRcdFx0Y29uc3Qgb2Zmc2V0ID0gZ2VvbWV0cnlBdHRyaWJ1dGUub2Zmc2V0O1xyXG5cclxuXHRcdFx0XHRcdFx0aWYgKCBkYXRhLmlzSW5zdGFuY2VkSW50ZXJsZWF2ZWRCdWZmZXIgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHByb2dyYW1BdHRyaWJ1dGUubG9jYXRpb25TaXplOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRcdGVuYWJsZUF0dHJpYnV0ZUFuZERpdmlzb3IoIHByb2dyYW1BdHRyaWJ1dGUubG9jYXRpb24gKyBpLCBkYXRhLm1lc2hQZXJBdHRyaWJ1dGUgKTtcclxuXHJcblx0XHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdFx0XHRpZiAoIG9iamVjdC5pc0luc3RhbmNlZE1lc2ggIT09IHRydWUgJiYgZ2VvbWV0cnkuX21heEluc3RhbmNlQ291bnQgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHRnZW9tZXRyeS5fbWF4SW5zdGFuY2VDb3VudCA9IGRhdGEubWVzaFBlckF0dHJpYnV0ZSAqIGRhdGEuY291bnQ7XHJcblxyXG5cdFx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHByb2dyYW1BdHRyaWJ1dGUubG9jYXRpb25TaXplOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRcdGVuYWJsZUF0dHJpYnV0ZSggcHJvZ3JhbUF0dHJpYnV0ZS5sb2NhdGlvbiArIGkgKTtcclxuXHJcblx0XHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdFx0Z2wuYmluZEJ1ZmZlciggZ2wuQVJSQVlfQlVGRkVSLCBidWZmZXIgKTtcclxuXHJcblx0XHRcdFx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHByb2dyYW1BdHRyaWJ1dGUubG9jYXRpb25TaXplOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHR2ZXJ0ZXhBdHRyaWJQb2ludGVyKFxyXG5cdFx0XHRcdFx0XHRcdFx0cHJvZ3JhbUF0dHJpYnV0ZS5sb2NhdGlvbiArIGksXHJcblx0XHRcdFx0XHRcdFx0XHRzaXplIC8gcHJvZ3JhbUF0dHJpYnV0ZS5sb2NhdGlvblNpemUsXHJcblx0XHRcdFx0XHRcdFx0XHR0eXBlLFxyXG5cdFx0XHRcdFx0XHRcdFx0bm9ybWFsaXplZCxcclxuXHRcdFx0XHRcdFx0XHRcdHN0cmlkZSAqIGJ5dGVzUGVyRWxlbWVudCxcclxuXHRcdFx0XHRcdFx0XHRcdCggb2Zmc2V0ICsgKCBzaXplIC8gcHJvZ3JhbUF0dHJpYnV0ZS5sb2NhdGlvblNpemUgKSAqIGkgKSAqIGJ5dGVzUGVyRWxlbWVudCxcclxuXHRcdFx0XHRcdFx0XHRcdGludGVnZXJcclxuXHRcdFx0XHRcdFx0XHQpO1xyXG5cclxuXHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHRpZiAoIGdlb21ldHJ5QXR0cmlidXRlLmlzSW5zdGFuY2VkQnVmZmVyQXR0cmlidXRlICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBwcm9ncmFtQXR0cmlidXRlLmxvY2F0aW9uU2l6ZTsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHRlbmFibGVBdHRyaWJ1dGVBbmREaXZpc29yKCBwcm9ncmFtQXR0cmlidXRlLmxvY2F0aW9uICsgaSwgZ2VvbWV0cnlBdHRyaWJ1dGUubWVzaFBlckF0dHJpYnV0ZSApO1xyXG5cclxuXHRcdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0XHRcdGlmICggb2JqZWN0LmlzSW5zdGFuY2VkTWVzaCAhPT0gdHJ1ZSAmJiBnZW9tZXRyeS5fbWF4SW5zdGFuY2VDb3VudCA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRcdGdlb21ldHJ5Ll9tYXhJbnN0YW5jZUNvdW50ID0gZ2VvbWV0cnlBdHRyaWJ1dGUubWVzaFBlckF0dHJpYnV0ZSAqIGdlb21ldHJ5QXR0cmlidXRlLmNvdW50O1xyXG5cclxuXHRcdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBwcm9ncmFtQXR0cmlidXRlLmxvY2F0aW9uU2l6ZTsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHRlbmFibGVBdHRyaWJ1dGUoIHByb2dyYW1BdHRyaWJ1dGUubG9jYXRpb24gKyBpICk7XHJcblxyXG5cdFx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRcdGdsLmJpbmRCdWZmZXIoIGdsLkFSUkFZX0JVRkZFUiwgYnVmZmVyICk7XHJcblxyXG5cdFx0XHRcdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBwcm9ncmFtQXR0cmlidXRlLmxvY2F0aW9uU2l6ZTsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0dmVydGV4QXR0cmliUG9pbnRlcihcclxuXHRcdFx0XHRcdFx0XHRcdHByb2dyYW1BdHRyaWJ1dGUubG9jYXRpb24gKyBpLFxyXG5cdFx0XHRcdFx0XHRcdFx0c2l6ZSAvIHByb2dyYW1BdHRyaWJ1dGUubG9jYXRpb25TaXplLFxyXG5cdFx0XHRcdFx0XHRcdFx0dHlwZSxcclxuXHRcdFx0XHRcdFx0XHRcdG5vcm1hbGl6ZWQsXHJcblx0XHRcdFx0XHRcdFx0XHRzaXplICogYnl0ZXNQZXJFbGVtZW50LFxyXG5cdFx0XHRcdFx0XHRcdFx0KCBzaXplIC8gcHJvZ3JhbUF0dHJpYnV0ZS5sb2NhdGlvblNpemUgKSAqIGkgKiBieXRlc1BlckVsZW1lbnQsXHJcblx0XHRcdFx0XHRcdFx0XHRpbnRlZ2VyXHJcblx0XHRcdFx0XHRcdFx0KTtcclxuXHJcblx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH0gZWxzZSBpZiAoIG1hdGVyaWFsRGVmYXVsdEF0dHJpYnV0ZVZhbHVlcyAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHRcdGNvbnN0IHZhbHVlID0gbWF0ZXJpYWxEZWZhdWx0QXR0cmlidXRlVmFsdWVzWyBuYW1lIF07XHJcblxyXG5cdFx0XHRcdFx0aWYgKCB2YWx1ZSAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHRcdFx0c3dpdGNoICggdmFsdWUubGVuZ3RoICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRjYXNlIDI6XHJcblx0XHRcdFx0XHRcdFx0XHRnbC52ZXJ0ZXhBdHRyaWIyZnYoIHByb2dyYW1BdHRyaWJ1dGUubG9jYXRpb24sIHZhbHVlICk7XHJcblx0XHRcdFx0XHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdFx0XHRcdFx0Y2FzZSAzOlxyXG5cdFx0XHRcdFx0XHRcdFx0Z2wudmVydGV4QXR0cmliM2Z2KCBwcm9ncmFtQXR0cmlidXRlLmxvY2F0aW9uLCB2YWx1ZSApO1xyXG5cdFx0XHRcdFx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRcdFx0XHRcdGNhc2UgNDpcclxuXHRcdFx0XHRcdFx0XHRcdGdsLnZlcnRleEF0dHJpYjRmdiggcHJvZ3JhbUF0dHJpYnV0ZS5sb2NhdGlvbiwgdmFsdWUgKTtcclxuXHRcdFx0XHRcdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0XHRcdFx0XHRkZWZhdWx0OlxyXG5cdFx0XHRcdFx0XHRcdFx0Z2wudmVydGV4QXR0cmliMWZ2KCBwcm9ncmFtQXR0cmlidXRlLmxvY2F0aW9uLCB2YWx1ZSApO1xyXG5cclxuXHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRkaXNhYmxlVW51c2VkQXR0cmlidXRlcygpO1xyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIGRpc3Bvc2UoKSB7XHJcblxyXG5cdFx0cmVzZXQoKTtcclxuXHJcblx0XHRmb3IgKCBjb25zdCBnZW9tZXRyeUlkIGluIGJpbmRpbmdTdGF0ZXMgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBwcm9ncmFtTWFwID0gYmluZGluZ1N0YXRlc1sgZ2VvbWV0cnlJZCBdO1xyXG5cclxuXHRcdFx0Zm9yICggY29uc3QgcHJvZ3JhbUlkIGluIHByb2dyYW1NYXAgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IHN0YXRlTWFwID0gcHJvZ3JhbU1hcFsgcHJvZ3JhbUlkIF07XHJcblxyXG5cdFx0XHRcdGZvciAoIGNvbnN0IHdpcmVmcmFtZSBpbiBzdGF0ZU1hcCApIHtcclxuXHJcblx0XHRcdFx0XHRkZWxldGVWZXJ0ZXhBcnJheU9iamVjdCggc3RhdGVNYXBbIHdpcmVmcmFtZSBdLm9iamVjdCApO1xyXG5cclxuXHRcdFx0XHRcdGRlbGV0ZSBzdGF0ZU1hcFsgd2lyZWZyYW1lIF07XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0ZGVsZXRlIHByb2dyYW1NYXBbIHByb2dyYW1JZCBdO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0ZGVsZXRlIGJpbmRpbmdTdGF0ZXNbIGdlb21ldHJ5SWQgXTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gcmVsZWFzZVN0YXRlc09mR2VvbWV0cnkoIGdlb21ldHJ5ICkge1xyXG5cclxuXHRcdGlmICggYmluZGluZ1N0YXRlc1sgZ2VvbWV0cnkuaWQgXSA9PT0gdW5kZWZpbmVkICkgcmV0dXJuO1xyXG5cclxuXHRcdGNvbnN0IHByb2dyYW1NYXAgPSBiaW5kaW5nU3RhdGVzWyBnZW9tZXRyeS5pZCBdO1xyXG5cclxuXHRcdGZvciAoIGNvbnN0IHByb2dyYW1JZCBpbiBwcm9ncmFtTWFwICkge1xyXG5cclxuXHRcdFx0Y29uc3Qgc3RhdGVNYXAgPSBwcm9ncmFtTWFwWyBwcm9ncmFtSWQgXTtcclxuXHJcblx0XHRcdGZvciAoIGNvbnN0IHdpcmVmcmFtZSBpbiBzdGF0ZU1hcCApIHtcclxuXHJcblx0XHRcdFx0ZGVsZXRlVmVydGV4QXJyYXlPYmplY3QoIHN0YXRlTWFwWyB3aXJlZnJhbWUgXS5vYmplY3QgKTtcclxuXHJcblx0XHRcdFx0ZGVsZXRlIHN0YXRlTWFwWyB3aXJlZnJhbWUgXTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGRlbGV0ZSBwcm9ncmFtTWFwWyBwcm9ncmFtSWQgXTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0ZGVsZXRlIGJpbmRpbmdTdGF0ZXNbIGdlb21ldHJ5LmlkIF07XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gcmVsZWFzZVN0YXRlc09mUHJvZ3JhbSggcHJvZ3JhbSApIHtcclxuXHJcblx0XHRmb3IgKCBjb25zdCBnZW9tZXRyeUlkIGluIGJpbmRpbmdTdGF0ZXMgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBwcm9ncmFtTWFwID0gYmluZGluZ1N0YXRlc1sgZ2VvbWV0cnlJZCBdO1xyXG5cclxuXHRcdFx0aWYgKCBwcm9ncmFtTWFwWyBwcm9ncmFtLmlkIF0gPT09IHVuZGVmaW5lZCApIGNvbnRpbnVlO1xyXG5cclxuXHRcdFx0Y29uc3Qgc3RhdGVNYXAgPSBwcm9ncmFtTWFwWyBwcm9ncmFtLmlkIF07XHJcblxyXG5cdFx0XHRmb3IgKCBjb25zdCB3aXJlZnJhbWUgaW4gc3RhdGVNYXAgKSB7XHJcblxyXG5cdFx0XHRcdGRlbGV0ZVZlcnRleEFycmF5T2JqZWN0KCBzdGF0ZU1hcFsgd2lyZWZyYW1lIF0ub2JqZWN0ICk7XHJcblxyXG5cdFx0XHRcdGRlbGV0ZSBzdGF0ZU1hcFsgd2lyZWZyYW1lIF07XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRkZWxldGUgcHJvZ3JhbU1hcFsgcHJvZ3JhbS5pZCBdO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiByZXNldCgpIHtcclxuXHJcblx0XHRyZXNldERlZmF1bHRTdGF0ZSgpO1xyXG5cdFx0Zm9yY2VVcGRhdGUgPSB0cnVlO1xyXG5cclxuXHRcdGlmICggY3VycmVudFN0YXRlID09PSBkZWZhdWx0U3RhdGUgKSByZXR1cm47XHJcblxyXG5cdFx0Y3VycmVudFN0YXRlID0gZGVmYXVsdFN0YXRlO1xyXG5cdFx0YmluZFZlcnRleEFycmF5T2JqZWN0KCBjdXJyZW50U3RhdGUub2JqZWN0ICk7XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gZm9yIGJhY2t3YXJkLWNvbXBhdGliaWxpdHlcclxuXHJcblx0ZnVuY3Rpb24gcmVzZXREZWZhdWx0U3RhdGUoKSB7XHJcblxyXG5cdFx0ZGVmYXVsdFN0YXRlLmdlb21ldHJ5ID0gbnVsbDtcclxuXHRcdGRlZmF1bHRTdGF0ZS5wcm9ncmFtID0gbnVsbDtcclxuXHRcdGRlZmF1bHRTdGF0ZS53aXJlZnJhbWUgPSBmYWxzZTtcclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4ge1xyXG5cclxuXHRcdHNldHVwOiBzZXR1cCxcclxuXHRcdHJlc2V0OiByZXNldCxcclxuXHRcdHJlc2V0RGVmYXVsdFN0YXRlOiByZXNldERlZmF1bHRTdGF0ZSxcclxuXHRcdGRpc3Bvc2U6IGRpc3Bvc2UsXHJcblx0XHRyZWxlYXNlU3RhdGVzT2ZHZW9tZXRyeTogcmVsZWFzZVN0YXRlc09mR2VvbWV0cnksXHJcblx0XHRyZWxlYXNlU3RhdGVzT2ZQcm9ncmFtOiByZWxlYXNlU3RhdGVzT2ZQcm9ncmFtLFxyXG5cclxuXHRcdGluaXRBdHRyaWJ1dGVzOiBpbml0QXR0cmlidXRlcyxcclxuXHRcdGVuYWJsZUF0dHJpYnV0ZTogZW5hYmxlQXR0cmlidXRlLFxyXG5cdFx0ZGlzYWJsZVVudXNlZEF0dHJpYnV0ZXM6IGRpc2FibGVVbnVzZWRBdHRyaWJ1dGVzXHJcblxyXG5cdH07XHJcblxyXG59XHJcblxyXG5cclxuZXhwb3J0IHsgV2ViR0xCaW5kaW5nU3RhdGVzIH07XHJcbiIsImZ1bmN0aW9uIFdlYkdMQnVmZmVyUmVuZGVyZXIoIGdsLCBleHRlbnNpb25zLCBpbmZvLCBjYXBhYmlsaXRpZXMgKSB7XHJcblxyXG5cdGNvbnN0IGlzV2ViR0wyID0gY2FwYWJpbGl0aWVzLmlzV2ViR0wyO1xyXG5cclxuXHRsZXQgbW9kZTtcclxuXHJcblx0ZnVuY3Rpb24gc2V0TW9kZSggdmFsdWUgKSB7XHJcblxyXG5cdFx0bW9kZSA9IHZhbHVlO1xyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHJlbmRlciggc3RhcnQsIGNvdW50ICkge1xyXG5cclxuXHRcdGdsLmRyYXdBcnJheXMoIG1vZGUsIHN0YXJ0LCBjb3VudCApO1xyXG5cclxuXHRcdGluZm8udXBkYXRlKCBjb3VudCwgbW9kZSwgMSApO1xyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHJlbmRlckluc3RhbmNlcyggc3RhcnQsIGNvdW50LCBwcmltY291bnQgKSB7XHJcblxyXG5cdFx0aWYgKCBwcmltY291bnQgPT09IDAgKSByZXR1cm47XHJcblxyXG5cdFx0bGV0IGV4dGVuc2lvbiwgbWV0aG9kTmFtZTtcclxuXHJcblx0XHRpZiAoIGlzV2ViR0wyICkge1xyXG5cclxuXHRcdFx0ZXh0ZW5zaW9uID0gZ2w7XHJcblx0XHRcdG1ldGhvZE5hbWUgPSAnZHJhd0FycmF5c0luc3RhbmNlZCc7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdGV4dGVuc2lvbiA9IGV4dGVuc2lvbnMuZ2V0KCAnQU5HTEVfaW5zdGFuY2VkX2FycmF5cycgKTtcclxuXHRcdFx0bWV0aG9kTmFtZSA9ICdkcmF3QXJyYXlzSW5zdGFuY2VkQU5HTEUnO1xyXG5cclxuXHRcdFx0aWYgKCBleHRlbnNpb24gPT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5XZWJHTEJ1ZmZlclJlbmRlcmVyOiB1c2luZyBUSFJFRS5JbnN0YW5jZWRCdWZmZXJHZW9tZXRyeSBidXQgaGFyZHdhcmUgZG9lcyBub3Qgc3VwcG9ydCBleHRlbnNpb24gQU5HTEVfaW5zdGFuY2VkX2FycmF5cy4nICk7XHJcblx0XHRcdFx0cmV0dXJuO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRleHRlbnNpb25bIG1ldGhvZE5hbWUgXSggbW9kZSwgc3RhcnQsIGNvdW50LCBwcmltY291bnQgKTtcclxuXHJcblx0XHRpbmZvLnVwZGF0ZSggY291bnQsIG1vZGUsIHByaW1jb3VudCApO1xyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHJlbmRlck11bHRpRHJhdyggc3RhcnRzLCBjb3VudHMsIGRyYXdDb3VudCApIHtcclxuXHJcblx0XHRpZiAoIGRyYXdDb3VudCA9PT0gMCApIHJldHVybjtcclxuXHJcblx0XHRjb25zdCBleHRlbnNpb24gPSBleHRlbnNpb25zLmdldCggJ1dFQkdMX211bHRpX2RyYXcnICk7XHJcblx0XHRpZiAoIGV4dGVuc2lvbiA9PT0gbnVsbCApIHtcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IGRyYXdDb3VudDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0dGhpcy5yZW5kZXIoIHN0YXJ0c1sgaSBdLCBjb3VudHNbIGkgXSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRleHRlbnNpb24ubXVsdGlEcmF3QXJyYXlzV0VCR0woIG1vZGUsIHN0YXJ0cywgMCwgY291bnRzLCAwLCBkcmF3Q291bnQgKTtcclxuXHJcblx0XHRcdGxldCBlbGVtZW50Q291bnQgPSAwO1xyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBkcmF3Q291bnQ7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdGVsZW1lbnRDb3VudCArPSBjb3VudHNbIGkgXTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGluZm8udXBkYXRlKCBlbGVtZW50Q291bnQsIG1vZGUsIDEgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0Ly9cclxuXHJcblx0dGhpcy5zZXRNb2RlID0gc2V0TW9kZTtcclxuXHR0aGlzLnJlbmRlciA9IHJlbmRlcjtcclxuXHR0aGlzLnJlbmRlckluc3RhbmNlcyA9IHJlbmRlckluc3RhbmNlcztcclxuXHR0aGlzLnJlbmRlck11bHRpRHJhdyA9IHJlbmRlck11bHRpRHJhdztcclxuXHJcbn1cclxuXHJcblxyXG5leHBvcnQgeyBXZWJHTEJ1ZmZlclJlbmRlcmVyIH07XHJcbiIsImZ1bmN0aW9uIFdlYkdMQ2FwYWJpbGl0aWVzKCBnbCwgZXh0ZW5zaW9ucywgcGFyYW1ldGVycyApIHtcclxuXHJcblx0bGV0IG1heEFuaXNvdHJvcHk7XHJcblxyXG5cdGZ1bmN0aW9uIGdldE1heEFuaXNvdHJvcHkoKSB7XHJcblxyXG5cdFx0aWYgKCBtYXhBbmlzb3Ryb3B5ICE9PSB1bmRlZmluZWQgKSByZXR1cm4gbWF4QW5pc290cm9weTtcclxuXHJcblx0XHRpZiAoIGV4dGVuc2lvbnMuaGFzKCAnRVhUX3RleHR1cmVfZmlsdGVyX2FuaXNvdHJvcGljJyApID09PSB0cnVlICkge1xyXG5cclxuXHRcdFx0Y29uc3QgZXh0ZW5zaW9uID0gZXh0ZW5zaW9ucy5nZXQoICdFWFRfdGV4dHVyZV9maWx0ZXJfYW5pc290cm9waWMnICk7XHJcblxyXG5cdFx0XHRtYXhBbmlzb3Ryb3B5ID0gZ2wuZ2V0UGFyYW1ldGVyKCBleHRlbnNpb24uTUFYX1RFWFRVUkVfTUFYX0FOSVNPVFJPUFlfRVhUICk7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdG1heEFuaXNvdHJvcHkgPSAwO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gbWF4QW5pc290cm9weTtcclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBnZXRNYXhQcmVjaXNpb24oIHByZWNpc2lvbiApIHtcclxuXHJcblx0XHRpZiAoIHByZWNpc2lvbiA9PT0gJ2hpZ2hwJyApIHtcclxuXHJcblx0XHRcdGlmICggZ2wuZ2V0U2hhZGVyUHJlY2lzaW9uRm9ybWF0KCBnbC5WRVJURVhfU0hBREVSLCBnbC5ISUdIX0ZMT0FUICkucHJlY2lzaW9uID4gMCAmJlxyXG5cdFx0XHRcdGdsLmdldFNoYWRlclByZWNpc2lvbkZvcm1hdCggZ2wuRlJBR01FTlRfU0hBREVSLCBnbC5ISUdIX0ZMT0FUICkucHJlY2lzaW9uID4gMCApIHtcclxuXHJcblx0XHRcdFx0cmV0dXJuICdoaWdocCc7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRwcmVjaXNpb24gPSAnbWVkaXVtcCc7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggcHJlY2lzaW9uID09PSAnbWVkaXVtcCcgKSB7XHJcblxyXG5cdFx0XHRpZiAoIGdsLmdldFNoYWRlclByZWNpc2lvbkZvcm1hdCggZ2wuVkVSVEVYX1NIQURFUiwgZ2wuTUVESVVNX0ZMT0FUICkucHJlY2lzaW9uID4gMCAmJlxyXG5cdFx0XHRcdGdsLmdldFNoYWRlclByZWNpc2lvbkZvcm1hdCggZ2wuRlJBR01FTlRfU0hBREVSLCBnbC5NRURJVU1fRkxPQVQgKS5wcmVjaXNpb24gPiAwICkge1xyXG5cclxuXHRcdFx0XHRyZXR1cm4gJ21lZGl1bXAnO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gJ2xvd3AnO1xyXG5cclxuXHR9XHJcblxyXG5cdGNvbnN0IGlzV2ViR0wyID0gdHlwZW9mIFdlYkdMMlJlbmRlcmluZ0NvbnRleHQgIT09ICd1bmRlZmluZWQnICYmIGdsLmNvbnN0cnVjdG9yLm5hbWUgPT09ICdXZWJHTDJSZW5kZXJpbmdDb250ZXh0JztcclxuXHJcblx0bGV0IHByZWNpc2lvbiA9IHBhcmFtZXRlcnMucHJlY2lzaW9uICE9PSB1bmRlZmluZWQgPyBwYXJhbWV0ZXJzLnByZWNpc2lvbiA6ICdoaWdocCc7XHJcblx0Y29uc3QgbWF4UHJlY2lzaW9uID0gZ2V0TWF4UHJlY2lzaW9uKCBwcmVjaXNpb24gKTtcclxuXHJcblx0aWYgKCBtYXhQcmVjaXNpb24gIT09IHByZWNpc2lvbiApIHtcclxuXHJcblx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5XZWJHTFJlbmRlcmVyOicsIHByZWNpc2lvbiwgJ25vdCBzdXBwb3J0ZWQsIHVzaW5nJywgbWF4UHJlY2lzaW9uLCAnaW5zdGVhZC4nICk7XHJcblx0XHRwcmVjaXNpb24gPSBtYXhQcmVjaXNpb247XHJcblxyXG5cdH1cclxuXHJcblx0Y29uc3QgZHJhd0J1ZmZlcnMgPSBpc1dlYkdMMiB8fCBleHRlbnNpb25zLmhhcyggJ1dFQkdMX2RyYXdfYnVmZmVycycgKTtcclxuXHJcblx0Y29uc3QgbG9nYXJpdGhtaWNEZXB0aEJ1ZmZlciA9IHBhcmFtZXRlcnMubG9nYXJpdGhtaWNEZXB0aEJ1ZmZlciA9PT0gdHJ1ZTtcclxuXHJcblx0Y29uc3QgbWF4VGV4dHVyZXMgPSBnbC5nZXRQYXJhbWV0ZXIoIGdsLk1BWF9URVhUVVJFX0lNQUdFX1VOSVRTICk7XHJcblx0Y29uc3QgbWF4VmVydGV4VGV4dHVyZXMgPSBnbC5nZXRQYXJhbWV0ZXIoIGdsLk1BWF9WRVJURVhfVEVYVFVSRV9JTUFHRV9VTklUUyApO1xyXG5cdGNvbnN0IG1heFRleHR1cmVTaXplID0gZ2wuZ2V0UGFyYW1ldGVyKCBnbC5NQVhfVEVYVFVSRV9TSVpFICk7XHJcblx0Y29uc3QgbWF4Q3ViZW1hcFNpemUgPSBnbC5nZXRQYXJhbWV0ZXIoIGdsLk1BWF9DVUJFX01BUF9URVhUVVJFX1NJWkUgKTtcclxuXHJcblx0Y29uc3QgbWF4QXR0cmlidXRlcyA9IGdsLmdldFBhcmFtZXRlciggZ2wuTUFYX1ZFUlRFWF9BVFRSSUJTICk7XHJcblx0Y29uc3QgbWF4VmVydGV4VW5pZm9ybXMgPSBnbC5nZXRQYXJhbWV0ZXIoIGdsLk1BWF9WRVJURVhfVU5JRk9STV9WRUNUT1JTICk7XHJcblx0Y29uc3QgbWF4VmFyeWluZ3MgPSBnbC5nZXRQYXJhbWV0ZXIoIGdsLk1BWF9WQVJZSU5HX1ZFQ1RPUlMgKTtcclxuXHRjb25zdCBtYXhGcmFnbWVudFVuaWZvcm1zID0gZ2wuZ2V0UGFyYW1ldGVyKCBnbC5NQVhfRlJBR01FTlRfVU5JRk9STV9WRUNUT1JTICk7XHJcblxyXG5cdGNvbnN0IHZlcnRleFRleHR1cmVzID0gbWF4VmVydGV4VGV4dHVyZXMgPiAwO1xyXG5cdGNvbnN0IGZsb2F0RnJhZ21lbnRUZXh0dXJlcyA9IGlzV2ViR0wyIHx8IGV4dGVuc2lvbnMuaGFzKCAnT0VTX3RleHR1cmVfZmxvYXQnICk7XHJcblx0Y29uc3QgZmxvYXRWZXJ0ZXhUZXh0dXJlcyA9IHZlcnRleFRleHR1cmVzICYmIGZsb2F0RnJhZ21lbnRUZXh0dXJlcztcclxuXHJcblx0Y29uc3QgbWF4U2FtcGxlcyA9IGlzV2ViR0wyID8gZ2wuZ2V0UGFyYW1ldGVyKCBnbC5NQVhfU0FNUExFUyApIDogMDtcclxuXHJcblx0cmV0dXJuIHtcclxuXHJcblx0XHRpc1dlYkdMMjogaXNXZWJHTDIsXHJcblxyXG5cdFx0ZHJhd0J1ZmZlcnM6IGRyYXdCdWZmZXJzLFxyXG5cclxuXHRcdGdldE1heEFuaXNvdHJvcHk6IGdldE1heEFuaXNvdHJvcHksXHJcblx0XHRnZXRNYXhQcmVjaXNpb246IGdldE1heFByZWNpc2lvbixcclxuXHJcblx0XHRwcmVjaXNpb246IHByZWNpc2lvbixcclxuXHRcdGxvZ2FyaXRobWljRGVwdGhCdWZmZXI6IGxvZ2FyaXRobWljRGVwdGhCdWZmZXIsXHJcblxyXG5cdFx0bWF4VGV4dHVyZXM6IG1heFRleHR1cmVzLFxyXG5cdFx0bWF4VmVydGV4VGV4dHVyZXM6IG1heFZlcnRleFRleHR1cmVzLFxyXG5cdFx0bWF4VGV4dHVyZVNpemU6IG1heFRleHR1cmVTaXplLFxyXG5cdFx0bWF4Q3ViZW1hcFNpemU6IG1heEN1YmVtYXBTaXplLFxyXG5cclxuXHRcdG1heEF0dHJpYnV0ZXM6IG1heEF0dHJpYnV0ZXMsXHJcblx0XHRtYXhWZXJ0ZXhVbmlmb3JtczogbWF4VmVydGV4VW5pZm9ybXMsXHJcblx0XHRtYXhWYXJ5aW5nczogbWF4VmFyeWluZ3MsXHJcblx0XHRtYXhGcmFnbWVudFVuaWZvcm1zOiBtYXhGcmFnbWVudFVuaWZvcm1zLFxyXG5cclxuXHRcdHZlcnRleFRleHR1cmVzOiB2ZXJ0ZXhUZXh0dXJlcyxcclxuXHRcdGZsb2F0RnJhZ21lbnRUZXh0dXJlczogZmxvYXRGcmFnbWVudFRleHR1cmVzLFxyXG5cdFx0ZmxvYXRWZXJ0ZXhUZXh0dXJlczogZmxvYXRWZXJ0ZXhUZXh0dXJlcyxcclxuXHJcblx0XHRtYXhTYW1wbGVzOiBtYXhTYW1wbGVzXHJcblxyXG5cdH07XHJcblxyXG59XHJcblxyXG5cclxuZXhwb3J0IHsgV2ViR0xDYXBhYmlsaXRpZXMgfTtcclxuIiwiaW1wb3J0IHsgTWF0cml4MyB9IGZyb20gJy4uLy4uL21hdGgvTWF0cml4My5qcyc7XHJcbmltcG9ydCB7IFBsYW5lIH0gZnJvbSAnLi4vLi4vbWF0aC9QbGFuZS5qcyc7XHJcblxyXG5mdW5jdGlvbiBXZWJHTENsaXBwaW5nKCBwcm9wZXJ0aWVzICkge1xyXG5cclxuXHRjb25zdCBzY29wZSA9IHRoaXM7XHJcblxyXG5cdGxldCBnbG9iYWxTdGF0ZSA9IG51bGwsXHJcblx0XHRudW1HbG9iYWxQbGFuZXMgPSAwLFxyXG5cdFx0bG9jYWxDbGlwcGluZ0VuYWJsZWQgPSBmYWxzZSxcclxuXHRcdHJlbmRlcmluZ1NoYWRvd3MgPSBmYWxzZTtcclxuXHJcblx0Y29uc3QgcGxhbmUgPSBuZXcgUGxhbmUoKSxcclxuXHRcdHZpZXdOb3JtYWxNYXRyaXggPSBuZXcgTWF0cml4MygpLFxyXG5cclxuXHRcdHVuaWZvcm0gPSB7IHZhbHVlOiBudWxsLCBuZWVkc1VwZGF0ZTogZmFsc2UgfTtcclxuXHJcblx0dGhpcy51bmlmb3JtID0gdW5pZm9ybTtcclxuXHR0aGlzLm51bVBsYW5lcyA9IDA7XHJcblx0dGhpcy5udW1JbnRlcnNlY3Rpb24gPSAwO1xyXG5cclxuXHR0aGlzLmluaXQgPSBmdW5jdGlvbiAoIHBsYW5lcywgZW5hYmxlTG9jYWxDbGlwcGluZyApIHtcclxuXHJcblx0XHRjb25zdCBlbmFibGVkID1cclxuXHRcdFx0cGxhbmVzLmxlbmd0aCAhPT0gMCB8fFxyXG5cdFx0XHRlbmFibGVMb2NhbENsaXBwaW5nIHx8XHJcblx0XHRcdC8vIGVuYWJsZSBzdGF0ZSBvZiBwcmV2aW91cyBmcmFtZSAtIHRoZSBjbGlwcGluZyBjb2RlIGhhcyB0b1xyXG5cdFx0XHQvLyBydW4gYW5vdGhlciBmcmFtZSBpbiBvcmRlciB0byByZXNldCB0aGUgc3RhdGU6XHJcblx0XHRcdG51bUdsb2JhbFBsYW5lcyAhPT0gMCB8fFxyXG5cdFx0XHRsb2NhbENsaXBwaW5nRW5hYmxlZDtcclxuXHJcblx0XHRsb2NhbENsaXBwaW5nRW5hYmxlZCA9IGVuYWJsZUxvY2FsQ2xpcHBpbmc7XHJcblxyXG5cdFx0bnVtR2xvYmFsUGxhbmVzID0gcGxhbmVzLmxlbmd0aDtcclxuXHJcblx0XHRyZXR1cm4gZW5hYmxlZDtcclxuXHJcblx0fTtcclxuXHJcblx0dGhpcy5iZWdpblNoYWRvd3MgPSBmdW5jdGlvbiAoKSB7XHJcblxyXG5cdFx0cmVuZGVyaW5nU2hhZG93cyA9IHRydWU7XHJcblx0XHRwcm9qZWN0UGxhbmVzKCBudWxsICk7XHJcblxyXG5cdH07XHJcblxyXG5cdHRoaXMuZW5kU2hhZG93cyA9IGZ1bmN0aW9uICgpIHtcclxuXHJcblx0XHRyZW5kZXJpbmdTaGFkb3dzID0gZmFsc2U7XHJcblxyXG5cdH07XHJcblxyXG5cdHRoaXMuc2V0R2xvYmFsU3RhdGUgPSBmdW5jdGlvbiAoIHBsYW5lcywgY2FtZXJhICkge1xyXG5cclxuXHRcdGdsb2JhbFN0YXRlID0gcHJvamVjdFBsYW5lcyggcGxhbmVzLCBjYW1lcmEsIDAgKTtcclxuXHJcblx0fTtcclxuXHJcblx0dGhpcy5zZXRTdGF0ZSA9IGZ1bmN0aW9uICggbWF0ZXJpYWwsIGNhbWVyYSwgdXNlQ2FjaGUgKSB7XHJcblxyXG5cdFx0Y29uc3QgcGxhbmVzID0gbWF0ZXJpYWwuY2xpcHBpbmdQbGFuZXMsXHJcblx0XHRcdGNsaXBJbnRlcnNlY3Rpb24gPSBtYXRlcmlhbC5jbGlwSW50ZXJzZWN0aW9uLFxyXG5cdFx0XHRjbGlwU2hhZG93cyA9IG1hdGVyaWFsLmNsaXBTaGFkb3dzO1xyXG5cclxuXHRcdGNvbnN0IG1hdGVyaWFsUHJvcGVydGllcyA9IHByb3BlcnRpZXMuZ2V0KCBtYXRlcmlhbCApO1xyXG5cclxuXHRcdGlmICggISBsb2NhbENsaXBwaW5nRW5hYmxlZCB8fCBwbGFuZXMgPT09IG51bGwgfHwgcGxhbmVzLmxlbmd0aCA9PT0gMCB8fCByZW5kZXJpbmdTaGFkb3dzICYmICEgY2xpcFNoYWRvd3MgKSB7XHJcblxyXG5cdFx0XHQvLyB0aGVyZSdzIG5vIGxvY2FsIGNsaXBwaW5nXHJcblxyXG5cdFx0XHRpZiAoIHJlbmRlcmluZ1NoYWRvd3MgKSB7XHJcblxyXG5cdFx0XHRcdC8vIHRoZXJlJ3Mgbm8gZ2xvYmFsIGNsaXBwaW5nXHJcblxyXG5cdFx0XHRcdHByb2plY3RQbGFuZXMoIG51bGwgKTtcclxuXHJcblx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdHJlc2V0R2xvYmFsU3RhdGUoKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0Y29uc3Qgbkdsb2JhbCA9IHJlbmRlcmluZ1NoYWRvd3MgPyAwIDogbnVtR2xvYmFsUGxhbmVzLFxyXG5cdFx0XHRcdGxHbG9iYWwgPSBuR2xvYmFsICogNDtcclxuXHJcblx0XHRcdGxldCBkc3RBcnJheSA9IG1hdGVyaWFsUHJvcGVydGllcy5jbGlwcGluZ1N0YXRlIHx8IG51bGw7XHJcblxyXG5cdFx0XHR1bmlmb3JtLnZhbHVlID0gZHN0QXJyYXk7IC8vIGVuc3VyZSB1bmlxdWUgc3RhdGVcclxuXHJcblx0XHRcdGRzdEFycmF5ID0gcHJvamVjdFBsYW5lcyggcGxhbmVzLCBjYW1lcmEsIGxHbG9iYWwsIHVzZUNhY2hlICk7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgIT09IGxHbG9iYWw7ICsrIGkgKSB7XHJcblxyXG5cdFx0XHRcdGRzdEFycmF5WyBpIF0gPSBnbG9iYWxTdGF0ZVsgaSBdO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0bWF0ZXJpYWxQcm9wZXJ0aWVzLmNsaXBwaW5nU3RhdGUgPSBkc3RBcnJheTtcclxuXHRcdFx0dGhpcy5udW1JbnRlcnNlY3Rpb24gPSBjbGlwSW50ZXJzZWN0aW9uID8gdGhpcy5udW1QbGFuZXMgOiAwO1xyXG5cdFx0XHR0aGlzLm51bVBsYW5lcyArPSBuR2xvYmFsO1xyXG5cclxuXHRcdH1cclxuXHJcblxyXG5cdH07XHJcblxyXG5cdGZ1bmN0aW9uIHJlc2V0R2xvYmFsU3RhdGUoKSB7XHJcblxyXG5cdFx0aWYgKCB1bmlmb3JtLnZhbHVlICE9PSBnbG9iYWxTdGF0ZSApIHtcclxuXHJcblx0XHRcdHVuaWZvcm0udmFsdWUgPSBnbG9iYWxTdGF0ZTtcclxuXHRcdFx0dW5pZm9ybS5uZWVkc1VwZGF0ZSA9IG51bUdsb2JhbFBsYW5lcyA+IDA7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHNjb3BlLm51bVBsYW5lcyA9IG51bUdsb2JhbFBsYW5lcztcclxuXHRcdHNjb3BlLm51bUludGVyc2VjdGlvbiA9IDA7XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gcHJvamVjdFBsYW5lcyggcGxhbmVzLCBjYW1lcmEsIGRzdE9mZnNldCwgc2tpcFRyYW5zZm9ybSApIHtcclxuXHJcblx0XHRjb25zdCBuUGxhbmVzID0gcGxhbmVzICE9PSBudWxsID8gcGxhbmVzLmxlbmd0aCA6IDA7XHJcblx0XHRsZXQgZHN0QXJyYXkgPSBudWxsO1xyXG5cclxuXHRcdGlmICggblBsYW5lcyAhPT0gMCApIHtcclxuXHJcblx0XHRcdGRzdEFycmF5ID0gdW5pZm9ybS52YWx1ZTtcclxuXHJcblx0XHRcdGlmICggc2tpcFRyYW5zZm9ybSAhPT0gdHJ1ZSB8fCBkc3RBcnJheSA9PT0gbnVsbCApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgZmxhdFNpemUgPSBkc3RPZmZzZXQgKyBuUGxhbmVzICogNCxcclxuXHRcdFx0XHRcdHZpZXdNYXRyaXggPSBjYW1lcmEubWF0cml4V29ybGRJbnZlcnNlO1xyXG5cclxuXHRcdFx0XHR2aWV3Tm9ybWFsTWF0cml4LmdldE5vcm1hbE1hdHJpeCggdmlld01hdHJpeCApO1xyXG5cclxuXHRcdFx0XHRpZiAoIGRzdEFycmF5ID09PSBudWxsIHx8IGRzdEFycmF5Lmxlbmd0aCA8IGZsYXRTaXplICkge1xyXG5cclxuXHRcdFx0XHRcdGRzdEFycmF5ID0gbmV3IEZsb2F0MzJBcnJheSggZmxhdFNpemUgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGk0ID0gZHN0T2Zmc2V0OyBpICE9PSBuUGxhbmVzOyArKyBpLCBpNCArPSA0ICkge1xyXG5cclxuXHRcdFx0XHRcdHBsYW5lLmNvcHkoIHBsYW5lc1sgaSBdICkuYXBwbHlNYXRyaXg0KCB2aWV3TWF0cml4LCB2aWV3Tm9ybWFsTWF0cml4ICk7XHJcblxyXG5cdFx0XHRcdFx0cGxhbmUubm9ybWFsLnRvQXJyYXkoIGRzdEFycmF5LCBpNCApO1xyXG5cdFx0XHRcdFx0ZHN0QXJyYXlbIGk0ICsgMyBdID0gcGxhbmUuY29uc3RhbnQ7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHVuaWZvcm0udmFsdWUgPSBkc3RBcnJheTtcclxuXHRcdFx0dW5pZm9ybS5uZWVkc1VwZGF0ZSA9IHRydWU7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHNjb3BlLm51bVBsYW5lcyA9IG5QbGFuZXM7XHJcblx0XHRzY29wZS5udW1JbnRlcnNlY3Rpb24gPSAwO1xyXG5cclxuXHRcdHJldHVybiBkc3RBcnJheTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuXHJcbmV4cG9ydCB7IFdlYkdMQ2xpcHBpbmcgfTtcclxuIiwiaW1wb3J0IHsgQ3ViZVJlZmxlY3Rpb25NYXBwaW5nLCBDdWJlUmVmcmFjdGlvbk1hcHBpbmcsIEVxdWlyZWN0YW5ndWxhclJlZmxlY3Rpb25NYXBwaW5nLCBFcXVpcmVjdGFuZ3VsYXJSZWZyYWN0aW9uTWFwcGluZyB9IGZyb20gJy4uLy4uL2NvbnN0YW50cy5qcyc7XHJcbmltcG9ydCB7IFdlYkdMQ3ViZVJlbmRlclRhcmdldCB9IGZyb20gJy4uL1dlYkdMQ3ViZVJlbmRlclRhcmdldC5qcyc7XHJcblxyXG5mdW5jdGlvbiBXZWJHTEN1YmVNYXBzKCByZW5kZXJlciApIHtcclxuXHJcblx0bGV0IGN1YmVtYXBzID0gbmV3IFdlYWtNYXAoKTtcclxuXHJcblx0ZnVuY3Rpb24gbWFwVGV4dHVyZU1hcHBpbmcoIHRleHR1cmUsIG1hcHBpbmcgKSB7XHJcblxyXG5cdFx0aWYgKCBtYXBwaW5nID09PSBFcXVpcmVjdGFuZ3VsYXJSZWZsZWN0aW9uTWFwcGluZyApIHtcclxuXHJcblx0XHRcdHRleHR1cmUubWFwcGluZyA9IEN1YmVSZWZsZWN0aW9uTWFwcGluZztcclxuXHJcblx0XHR9IGVsc2UgaWYgKCBtYXBwaW5nID09PSBFcXVpcmVjdGFuZ3VsYXJSZWZyYWN0aW9uTWFwcGluZyApIHtcclxuXHJcblx0XHRcdHRleHR1cmUubWFwcGluZyA9IEN1YmVSZWZyYWN0aW9uTWFwcGluZztcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRleHR1cmU7XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gZ2V0KCB0ZXh0dXJlICkge1xyXG5cclxuXHRcdGlmICggdGV4dHVyZSAmJiB0ZXh0dXJlLmlzVGV4dHVyZSApIHtcclxuXHJcblx0XHRcdGNvbnN0IG1hcHBpbmcgPSB0ZXh0dXJlLm1hcHBpbmc7XHJcblxyXG5cdFx0XHRpZiAoIG1hcHBpbmcgPT09IEVxdWlyZWN0YW5ndWxhclJlZmxlY3Rpb25NYXBwaW5nIHx8IG1hcHBpbmcgPT09IEVxdWlyZWN0YW5ndWxhclJlZnJhY3Rpb25NYXBwaW5nICkge1xyXG5cclxuXHRcdFx0XHRpZiAoIGN1YmVtYXBzLmhhcyggdGV4dHVyZSApICkge1xyXG5cclxuXHRcdFx0XHRcdGNvbnN0IGN1YmVtYXAgPSBjdWJlbWFwcy5nZXQoIHRleHR1cmUgKS50ZXh0dXJlO1xyXG5cdFx0XHRcdFx0cmV0dXJuIG1hcFRleHR1cmVNYXBwaW5nKCBjdWJlbWFwLCB0ZXh0dXJlLm1hcHBpbmcgKTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRjb25zdCBpbWFnZSA9IHRleHR1cmUuaW1hZ2U7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCBpbWFnZSAmJiBpbWFnZS5oZWlnaHQgPiAwICkge1xyXG5cclxuXHRcdFx0XHRcdFx0Y29uc3QgcmVuZGVyVGFyZ2V0ID0gbmV3IFdlYkdMQ3ViZVJlbmRlclRhcmdldCggaW1hZ2UuaGVpZ2h0ICk7XHJcblx0XHRcdFx0XHRcdHJlbmRlclRhcmdldC5mcm9tRXF1aXJlY3Rhbmd1bGFyVGV4dHVyZSggcmVuZGVyZXIsIHRleHR1cmUgKTtcclxuXHRcdFx0XHRcdFx0Y3ViZW1hcHMuc2V0KCB0ZXh0dXJlLCByZW5kZXJUYXJnZXQgKTtcclxuXHJcblx0XHRcdFx0XHRcdHRleHR1cmUuYWRkRXZlbnRMaXN0ZW5lciggJ2Rpc3Bvc2UnLCBvblRleHR1cmVEaXNwb3NlICk7XHJcblxyXG5cdFx0XHRcdFx0XHRyZXR1cm4gbWFwVGV4dHVyZU1hcHBpbmcoIHJlbmRlclRhcmdldC50ZXh0dXJlLCB0ZXh0dXJlLm1hcHBpbmcgKTtcclxuXHJcblx0XHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdFx0Ly8gaW1hZ2Ugbm90IHlldCByZWFkeS4gdHJ5IHRoZSBjb252ZXJzaW9uIG5leHQgZnJhbWVcclxuXHJcblx0XHRcdFx0XHRcdHJldHVybiBudWxsO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGV4dHVyZTtcclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBvblRleHR1cmVEaXNwb3NlKCBldmVudCApIHtcclxuXHJcblx0XHRjb25zdCB0ZXh0dXJlID0gZXZlbnQudGFyZ2V0O1xyXG5cclxuXHRcdHRleHR1cmUucmVtb3ZlRXZlbnRMaXN0ZW5lciggJ2Rpc3Bvc2UnLCBvblRleHR1cmVEaXNwb3NlICk7XHJcblxyXG5cdFx0Y29uc3QgY3ViZW1hcCA9IGN1YmVtYXBzLmdldCggdGV4dHVyZSApO1xyXG5cclxuXHRcdGlmICggY3ViZW1hcCAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0Y3ViZW1hcHMuZGVsZXRlKCB0ZXh0dXJlICk7XHJcblx0XHRcdGN1YmVtYXAuZGlzcG9zZSgpO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBkaXNwb3NlKCkge1xyXG5cclxuXHRcdGN1YmVtYXBzID0gbmV3IFdlYWtNYXAoKTtcclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4ge1xyXG5cdFx0Z2V0OiBnZXQsXHJcblx0XHRkaXNwb3NlOiBkaXNwb3NlXHJcblx0fTtcclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IFdlYkdMQ3ViZU1hcHMgfTtcclxuIiwiaW1wb3J0IHsgQ2FtZXJhIH0gZnJvbSAnLi9DYW1lcmEuanMnO1xyXG5cclxuY2xhc3MgT3J0aG9ncmFwaGljQ2FtZXJhIGV4dGVuZHMgQ2FtZXJhIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIGxlZnQgPSAtIDEsIHJpZ2h0ID0gMSwgdG9wID0gMSwgYm90dG9tID0gLSAxLCBuZWFyID0gMC4xLCBmYXIgPSAyMDAwICkge1xyXG5cclxuXHRcdHN1cGVyKCk7XHJcblxyXG5cdFx0dGhpcy5pc09ydGhvZ3JhcGhpY0NhbWVyYSA9IHRydWU7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ09ydGhvZ3JhcGhpY0NhbWVyYSc7XHJcblxyXG5cdFx0dGhpcy56b29tID0gMTtcclxuXHRcdHRoaXMudmlldyA9IG51bGw7XHJcblxyXG5cdFx0dGhpcy5sZWZ0ID0gbGVmdDtcclxuXHRcdHRoaXMucmlnaHQgPSByaWdodDtcclxuXHRcdHRoaXMudG9wID0gdG9wO1xyXG5cdFx0dGhpcy5ib3R0b20gPSBib3R0b207XHJcblxyXG5cdFx0dGhpcy5uZWFyID0gbmVhcjtcclxuXHRcdHRoaXMuZmFyID0gZmFyO1xyXG5cclxuXHRcdHRoaXMudXBkYXRlUHJvamVjdGlvbk1hdHJpeCgpO1xyXG5cclxuXHR9XHJcblxyXG5cdGNvcHkoIHNvdXJjZSwgcmVjdXJzaXZlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSwgcmVjdXJzaXZlICk7XHJcblxyXG5cdFx0dGhpcy5sZWZ0ID0gc291cmNlLmxlZnQ7XHJcblx0XHR0aGlzLnJpZ2h0ID0gc291cmNlLnJpZ2h0O1xyXG5cdFx0dGhpcy50b3AgPSBzb3VyY2UudG9wO1xyXG5cdFx0dGhpcy5ib3R0b20gPSBzb3VyY2UuYm90dG9tO1xyXG5cdFx0dGhpcy5uZWFyID0gc291cmNlLm5lYXI7XHJcblx0XHR0aGlzLmZhciA9IHNvdXJjZS5mYXI7XHJcblxyXG5cdFx0dGhpcy56b29tID0gc291cmNlLnpvb207XHJcblx0XHR0aGlzLnZpZXcgPSBzb3VyY2UudmlldyA9PT0gbnVsbCA/IG51bGwgOiBPYmplY3QuYXNzaWduKCB7fSwgc291cmNlLnZpZXcgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRWaWV3T2Zmc2V0KCBmdWxsV2lkdGgsIGZ1bGxIZWlnaHQsIHgsIHksIHdpZHRoLCBoZWlnaHQgKSB7XHJcblxyXG5cdFx0aWYgKCB0aGlzLnZpZXcgPT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHR0aGlzLnZpZXcgPSB7XHJcblx0XHRcdFx0ZW5hYmxlZDogdHJ1ZSxcclxuXHRcdFx0XHRmdWxsV2lkdGg6IDEsXHJcblx0XHRcdFx0ZnVsbEhlaWdodDogMSxcclxuXHRcdFx0XHRvZmZzZXRYOiAwLFxyXG5cdFx0XHRcdG9mZnNldFk6IDAsXHJcblx0XHRcdFx0d2lkdGg6IDEsXHJcblx0XHRcdFx0aGVpZ2h0OiAxXHJcblx0XHRcdH07XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMudmlldy5lbmFibGVkID0gdHJ1ZTtcclxuXHRcdHRoaXMudmlldy5mdWxsV2lkdGggPSBmdWxsV2lkdGg7XHJcblx0XHR0aGlzLnZpZXcuZnVsbEhlaWdodCA9IGZ1bGxIZWlnaHQ7XHJcblx0XHR0aGlzLnZpZXcub2Zmc2V0WCA9IHg7XHJcblx0XHR0aGlzLnZpZXcub2Zmc2V0WSA9IHk7XHJcblx0XHR0aGlzLnZpZXcud2lkdGggPSB3aWR0aDtcclxuXHRcdHRoaXMudmlldy5oZWlnaHQgPSBoZWlnaHQ7XHJcblxyXG5cdFx0dGhpcy51cGRhdGVQcm9qZWN0aW9uTWF0cml4KCk7XHJcblxyXG5cdH1cclxuXHJcblx0Y2xlYXJWaWV3T2Zmc2V0KCkge1xyXG5cclxuXHRcdGlmICggdGhpcy52aWV3ICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0dGhpcy52aWV3LmVuYWJsZWQgPSBmYWxzZTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy51cGRhdGVQcm9qZWN0aW9uTWF0cml4KCk7XHJcblxyXG5cdH1cclxuXHJcblx0dXBkYXRlUHJvamVjdGlvbk1hdHJpeCgpIHtcclxuXHJcblx0XHRjb25zdCBkeCA9ICggdGhpcy5yaWdodCAtIHRoaXMubGVmdCApIC8gKCAyICogdGhpcy56b29tICk7XHJcblx0XHRjb25zdCBkeSA9ICggdGhpcy50b3AgLSB0aGlzLmJvdHRvbSApIC8gKCAyICogdGhpcy56b29tICk7XHJcblx0XHRjb25zdCBjeCA9ICggdGhpcy5yaWdodCArIHRoaXMubGVmdCApIC8gMjtcclxuXHRcdGNvbnN0IGN5ID0gKCB0aGlzLnRvcCArIHRoaXMuYm90dG9tICkgLyAyO1xyXG5cclxuXHRcdGxldCBsZWZ0ID0gY3ggLSBkeDtcclxuXHRcdGxldCByaWdodCA9IGN4ICsgZHg7XHJcblx0XHRsZXQgdG9wID0gY3kgKyBkeTtcclxuXHRcdGxldCBib3R0b20gPSBjeSAtIGR5O1xyXG5cclxuXHRcdGlmICggdGhpcy52aWV3ICE9PSBudWxsICYmIHRoaXMudmlldy5lbmFibGVkICkge1xyXG5cclxuXHRcdFx0Y29uc3Qgc2NhbGVXID0gKCB0aGlzLnJpZ2h0IC0gdGhpcy5sZWZ0ICkgLyB0aGlzLnZpZXcuZnVsbFdpZHRoIC8gdGhpcy56b29tO1xyXG5cdFx0XHRjb25zdCBzY2FsZUggPSAoIHRoaXMudG9wIC0gdGhpcy5ib3R0b20gKSAvIHRoaXMudmlldy5mdWxsSGVpZ2h0IC8gdGhpcy56b29tO1xyXG5cclxuXHRcdFx0bGVmdCArPSBzY2FsZVcgKiB0aGlzLnZpZXcub2Zmc2V0WDtcclxuXHRcdFx0cmlnaHQgPSBsZWZ0ICsgc2NhbGVXICogdGhpcy52aWV3LndpZHRoO1xyXG5cdFx0XHR0b3AgLT0gc2NhbGVIICogdGhpcy52aWV3Lm9mZnNldFk7XHJcblx0XHRcdGJvdHRvbSA9IHRvcCAtIHNjYWxlSCAqIHRoaXMudmlldy5oZWlnaHQ7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMucHJvamVjdGlvbk1hdHJpeC5tYWtlT3J0aG9ncmFwaGljKCBsZWZ0LCByaWdodCwgdG9wLCBib3R0b20sIHRoaXMubmVhciwgdGhpcy5mYXIsIHRoaXMuY29vcmRpbmF0ZVN5c3RlbSApO1xyXG5cclxuXHRcdHRoaXMucHJvamVjdGlvbk1hdHJpeEludmVyc2UuY29weSggdGhpcy5wcm9qZWN0aW9uTWF0cml4ICkuaW52ZXJ0KCk7XHJcblxyXG5cdH1cclxuXHJcblx0dG9KU09OKCBtZXRhICkge1xyXG5cclxuXHRcdGNvbnN0IGRhdGEgPSBzdXBlci50b0pTT04oIG1ldGEgKTtcclxuXHJcblx0XHRkYXRhLm9iamVjdC56b29tID0gdGhpcy56b29tO1xyXG5cdFx0ZGF0YS5vYmplY3QubGVmdCA9IHRoaXMubGVmdDtcclxuXHRcdGRhdGEub2JqZWN0LnJpZ2h0ID0gdGhpcy5yaWdodDtcclxuXHRcdGRhdGEub2JqZWN0LnRvcCA9IHRoaXMudG9wO1xyXG5cdFx0ZGF0YS5vYmplY3QuYm90dG9tID0gdGhpcy5ib3R0b207XHJcblx0XHRkYXRhLm9iamVjdC5uZWFyID0gdGhpcy5uZWFyO1xyXG5cdFx0ZGF0YS5vYmplY3QuZmFyID0gdGhpcy5mYXI7XHJcblxyXG5cdFx0aWYgKCB0aGlzLnZpZXcgIT09IG51bGwgKSBkYXRhLm9iamVjdC52aWV3ID0gT2JqZWN0LmFzc2lnbigge30sIHRoaXMudmlldyApO1xyXG5cclxuXHRcdHJldHVybiBkYXRhO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBPcnRob2dyYXBoaWNDYW1lcmEgfTtcclxuIiwiaW1wb3J0IHtcclxuXHRDdWJlUmVmbGVjdGlvbk1hcHBpbmcsXHJcblx0Q3ViZVJlZnJhY3Rpb25NYXBwaW5nLFxyXG5cdEN1YmVVVlJlZmxlY3Rpb25NYXBwaW5nLFxyXG5cdExpbmVhckZpbHRlcixcclxuXHROb1RvbmVNYXBwaW5nLFxyXG5cdE5vQmxlbmRpbmcsXHJcblx0UkdCQUZvcm1hdCxcclxuXHRIYWxmRmxvYXRUeXBlLFxyXG5cdEJhY2tTaWRlLFxyXG5cdExpbmVhclNSR0JDb2xvclNwYWNlXHJcbn0gZnJvbSAnLi4vY29uc3RhbnRzLmpzJztcclxuXHJcbmltcG9ydCB7IEJ1ZmZlckF0dHJpYnV0ZSB9IGZyb20gJy4uL2NvcmUvQnVmZmVyQXR0cmlidXRlLmpzJztcclxuaW1wb3J0IHsgQnVmZmVyR2VvbWV0cnkgfSBmcm9tICcuLi9jb3JlL0J1ZmZlckdlb21ldHJ5LmpzJztcclxuaW1wb3J0IHsgTWVzaCB9IGZyb20gJy4uL29iamVjdHMvTWVzaC5qcyc7XHJcbmltcG9ydCB7IE9ydGhvZ3JhcGhpY0NhbWVyYSB9IGZyb20gJy4uL2NhbWVyYXMvT3J0aG9ncmFwaGljQ2FtZXJhLmpzJztcclxuaW1wb3J0IHsgUGVyc3BlY3RpdmVDYW1lcmEgfSBmcm9tICcuLi9jYW1lcmFzL1BlcnNwZWN0aXZlQ2FtZXJhLmpzJztcclxuaW1wb3J0IHsgU2hhZGVyTWF0ZXJpYWwgfSBmcm9tICcuLi9tYXRlcmlhbHMvU2hhZGVyTWF0ZXJpYWwuanMnO1xyXG5pbXBvcnQgeyBWZWN0b3IzIH0gZnJvbSAnLi4vbWF0aC9WZWN0b3IzLmpzJztcclxuaW1wb3J0IHsgQ29sb3IgfSBmcm9tICcuLi9tYXRoL0NvbG9yLmpzJztcclxuaW1wb3J0IHsgV2ViR0xSZW5kZXJUYXJnZXQgfSBmcm9tICcuLi9yZW5kZXJlcnMvV2ViR0xSZW5kZXJUYXJnZXQuanMnO1xyXG5pbXBvcnQgeyBNZXNoQmFzaWNNYXRlcmlhbCB9IGZyb20gJy4uL21hdGVyaWFscy9NZXNoQmFzaWNNYXRlcmlhbC5qcyc7XHJcbmltcG9ydCB7IEJveEdlb21ldHJ5IH0gZnJvbSAnLi4vZ2VvbWV0cmllcy9Cb3hHZW9tZXRyeS5qcyc7XHJcblxyXG5jb25zdCBMT0RfTUlOID0gNDtcclxuXHJcbi8vIFRoZSBzdGFuZGFyZCBkZXZpYXRpb25zIChyYWRpYW5zKSBhc3NvY2lhdGVkIHdpdGggdGhlIGV4dHJhIG1pcHMuIFRoZXNlIGFyZVxyXG4vLyBjaG9zZW4gdG8gYXBwcm94aW1hdGUgYSBUcm93YnJpZGdlLVJlaXR6IGRpc3RyaWJ1dGlvbiBmdW5jdGlvbiB0aW1lcyB0aGVcclxuLy8gZ2VvbWV0cmljIHNoYWRvd2luZyBmdW5jdGlvbi4gVGhlc2Ugc2lnbWEgdmFsdWVzIHNxdWFyZWQgbXVzdCBtYXRjaCB0aGVcclxuLy8gdmFyaWFuY2UgI2RlZmluZXMgaW4gY3ViZV91dl9yZWZsZWN0aW9uX2ZyYWdtZW50Lmdsc2wuanMuXHJcbmNvbnN0IEVYVFJBX0xPRF9TSUdNQSA9IFsgMC4xMjUsIDAuMjE1LCAwLjM1LCAwLjQ0NiwgMC41MjYsIDAuNTgyIF07XHJcblxyXG4vLyBUaGUgbWF4aW11bSBsZW5ndGggb2YgdGhlIGJsdXIgZm9yIGxvb3AuIFNtYWxsZXIgc2lnbWFzIHdpbGwgdXNlIGZld2VyXHJcbi8vIHNhbXBsZXMgYW5kIGV4aXQgZWFybHksIGJ1dCBub3QgcmVjb21waWxlIHRoZSBzaGFkZXIuXHJcbmNvbnN0IE1BWF9TQU1QTEVTID0gMjA7XHJcblxyXG5jb25zdCBfZmxhdENhbWVyYSA9IC8qQF9fUFVSRV9fKi8gbmV3IE9ydGhvZ3JhcGhpY0NhbWVyYSgpO1xyXG5jb25zdCBfY2xlYXJDb2xvciA9IC8qQF9fUFVSRV9fKi8gbmV3IENvbG9yKCk7XHJcbmxldCBfb2xkVGFyZ2V0ID0gbnVsbDtcclxubGV0IF9vbGRBY3RpdmVDdWJlRmFjZSA9IDA7XHJcbmxldCBfb2xkQWN0aXZlTWlwbWFwTGV2ZWwgPSAwO1xyXG5cclxuLy8gR29sZGVuIFJhdGlvXHJcbmNvbnN0IFBISSA9ICggMSArIE1hdGguc3FydCggNSApICkgLyAyO1xyXG5jb25zdCBJTlZfUEhJID0gMSAvIFBISTtcclxuXHJcbi8vIFZlcnRpY2VzIG9mIGEgZG9kZWNhaGVkcm9uIChleGNlcHQgdGhlIG9wcG9zaXRlcywgd2hpY2ggcmVwcmVzZW50IHRoZVxyXG4vLyBzYW1lIGF4aXMpLCB1c2VkIGFzIGF4aXMgZGlyZWN0aW9ucyBldmVubHkgc3ByZWFkIG9uIGEgc3BoZXJlLlxyXG5jb25zdCBfYXhpc0RpcmVjdGlvbnMgPSBbXHJcblx0LypAX19QVVJFX18qLyBuZXcgVmVjdG9yMyggMSwgMSwgMSApLFxyXG5cdC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoIC0gMSwgMSwgMSApLFxyXG5cdC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoIDEsIDEsIC0gMSApLFxyXG5cdC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoIC0gMSwgMSwgLSAxICksXHJcblx0LypAX19QVVJFX18qLyBuZXcgVmVjdG9yMyggMCwgUEhJLCBJTlZfUEhJICksXHJcblx0LypAX19QVVJFX18qLyBuZXcgVmVjdG9yMyggMCwgUEhJLCAtIElOVl9QSEkgKSxcclxuXHQvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCBJTlZfUEhJLCAwLCBQSEkgKSxcclxuXHQvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCAtIElOVl9QSEksIDAsIFBISSApLFxyXG5cdC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoIFBISSwgSU5WX1BISSwgMCApLFxyXG5cdC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoIC0gUEhJLCBJTlZfUEhJLCAwICkgXTtcclxuXHJcbi8qKlxyXG4gKiBUaGlzIGNsYXNzIGdlbmVyYXRlcyBhIFByZWZpbHRlcmVkLCBNaXBtYXBwZWQgUmFkaWFuY2UgRW52aXJvbm1lbnQgTWFwXHJcbiAqIChQTVJFTSkgZnJvbSBhIGN1YmVNYXAgZW52aXJvbm1lbnQgdGV4dHVyZS4gVGhpcyBhbGxvd3MgZGlmZmVyZW50IGxldmVscyBvZlxyXG4gKiBibHVyIHRvIGJlIHF1aWNrbHkgYWNjZXNzZWQgYmFzZWQgb24gbWF0ZXJpYWwgcm91Z2huZXNzLiBJdCBpcyBwYWNrZWQgaW50byBhXHJcbiAqIHNwZWNpYWwgQ3ViZVVWIGZvcm1hdCB0aGF0IGFsbG93cyB1cyB0byBwZXJmb3JtIGN1c3RvbSBpbnRlcnBvbGF0aW9uIHNvIHRoYXRcclxuICogd2UgY2FuIHN1cHBvcnQgbm9ubGluZWFyIGZvcm1hdHMgc3VjaCBhcyBSR0JFLiBVbmxpa2UgYSB0cmFkaXRpb25hbCBtaXBtYXBcclxuICogY2hhaW4sIGl0IG9ubHkgZ29lcyBkb3duIHRvIHRoZSBMT0RfTUlOIGxldmVsIChhYm92ZSksIGFuZCB0aGVuIGNyZWF0ZXMgZXh0cmFcclxuICogZXZlbiBtb3JlIGZpbHRlcmVkICdtaXBzJyBhdCB0aGUgc2FtZSBMT0RfTUlOIHJlc29sdXRpb24sIGFzc29jaWF0ZWQgd2l0aFxyXG4gKiBoaWdoZXIgcm91Z2huZXNzIGxldmVscy4gSW4gdGhpcyB3YXkgd2UgbWFpbnRhaW4gcmVzb2x1dGlvbiB0byBzbW9vdGhseVxyXG4gKiBpbnRlcnBvbGF0ZSBkaWZmdXNlIGxpZ2h0aW5nIHdoaWxlIGxpbWl0aW5nIHNhbXBsaW5nIGNvbXB1dGF0aW9uLlxyXG4gKlxyXG4gKiBQYXBlcjogRmFzdCwgQWNjdXJhdGUgSW1hZ2UtQmFzZWQgTGlnaHRpbmdcclxuICogaHR0cHM6Ly9kcml2ZS5nb29nbGUuY29tL2ZpbGUvZC8xNXk4cl9VcEtsVTlTdlY0SUxiMEMzcUNQZWNTOHB2THovdmlld1xyXG4qL1xyXG5cclxuY2xhc3MgUE1SRU1HZW5lcmF0b3Ige1xyXG5cclxuXHRjb25zdHJ1Y3RvciggcmVuZGVyZXIgKSB7XHJcblxyXG5cdFx0dGhpcy5fcmVuZGVyZXIgPSByZW5kZXJlcjtcclxuXHRcdHRoaXMuX3BpbmdQb25nUmVuZGVyVGFyZ2V0ID0gbnVsbDtcclxuXHJcblx0XHR0aGlzLl9sb2RNYXggPSAwO1xyXG5cdFx0dGhpcy5fY3ViZVNpemUgPSAwO1xyXG5cdFx0dGhpcy5fbG9kUGxhbmVzID0gW107XHJcblx0XHR0aGlzLl9zaXplTG9kcyA9IFtdO1xyXG5cdFx0dGhpcy5fc2lnbWFzID0gW107XHJcblxyXG5cdFx0dGhpcy5fYmx1ck1hdGVyaWFsID0gbnVsbDtcclxuXHRcdHRoaXMuX2N1YmVtYXBNYXRlcmlhbCA9IG51bGw7XHJcblx0XHR0aGlzLl9lcXVpcmVjdE1hdGVyaWFsID0gbnVsbDtcclxuXHJcblx0XHR0aGlzLl9jb21waWxlTWF0ZXJpYWwoIHRoaXMuX2JsdXJNYXRlcmlhbCApO1xyXG5cclxuXHR9XHJcblxyXG5cdC8qKlxyXG5cdCAqIEdlbmVyYXRlcyBhIFBNUkVNIGZyb20gYSBzdXBwbGllZCBTY2VuZSwgd2hpY2ggY2FuIGJlIGZhc3RlciB0aGFuIHVzaW5nIGFuXHJcblx0ICogaW1hZ2UgaWYgbmV0d29ya2luZyBiYW5kd2lkdGggaXMgbG93LiBPcHRpb25hbCBzaWdtYSBzcGVjaWZpZXMgYSBibHVyIHJhZGl1c1xyXG5cdCAqIGluIHJhZGlhbnMgdG8gYmUgYXBwbGllZCB0byB0aGUgc2NlbmUgYmVmb3JlIFBNUkVNIGdlbmVyYXRpb24uIE9wdGlvbmFsIG5lYXJcclxuXHQgKiBhbmQgZmFyIHBsYW5lcyBlbnN1cmUgdGhlIHNjZW5lIGlzIHJlbmRlcmVkIGluIGl0cyBlbnRpcmV0eSAodGhlIGN1YmVDYW1lcmFcclxuXHQgKiBpcyBwbGFjZWQgYXQgdGhlIG9yaWdpbikuXHJcblx0ICovXHJcblx0ZnJvbVNjZW5lKCBzY2VuZSwgc2lnbWEgPSAwLCBuZWFyID0gMC4xLCBmYXIgPSAxMDAgKSB7XHJcblxyXG5cdFx0X29sZFRhcmdldCA9IHRoaXMuX3JlbmRlcmVyLmdldFJlbmRlclRhcmdldCgpO1xyXG5cdFx0X29sZEFjdGl2ZUN1YmVGYWNlID0gdGhpcy5fcmVuZGVyZXIuZ2V0QWN0aXZlQ3ViZUZhY2UoKTtcclxuXHRcdF9vbGRBY3RpdmVNaXBtYXBMZXZlbCA9IHRoaXMuX3JlbmRlcmVyLmdldEFjdGl2ZU1pcG1hcExldmVsKCk7XHJcblxyXG5cdFx0dGhpcy5fc2V0U2l6ZSggMjU2ICk7XHJcblxyXG5cdFx0Y29uc3QgY3ViZVVWUmVuZGVyVGFyZ2V0ID0gdGhpcy5fYWxsb2NhdGVUYXJnZXRzKCk7XHJcblx0XHRjdWJlVVZSZW5kZXJUYXJnZXQuZGVwdGhCdWZmZXIgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMuX3NjZW5lVG9DdWJlVVYoIHNjZW5lLCBuZWFyLCBmYXIsIGN1YmVVVlJlbmRlclRhcmdldCApO1xyXG5cclxuXHRcdGlmICggc2lnbWEgPiAwICkge1xyXG5cclxuXHRcdFx0dGhpcy5fYmx1ciggY3ViZVVWUmVuZGVyVGFyZ2V0LCAwLCAwLCBzaWdtYSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLl9hcHBseVBNUkVNKCBjdWJlVVZSZW5kZXJUYXJnZXQgKTtcclxuXHRcdHRoaXMuX2NsZWFudXAoIGN1YmVVVlJlbmRlclRhcmdldCApO1xyXG5cclxuXHRcdHJldHVybiBjdWJlVVZSZW5kZXJUYXJnZXQ7XHJcblxyXG5cdH1cclxuXHJcblx0LyoqXHJcblx0ICogR2VuZXJhdGVzIGEgUE1SRU0gZnJvbSBhbiBlcXVpcmVjdGFuZ3VsYXIgdGV4dHVyZSwgd2hpY2ggY2FuIGJlIGVpdGhlciBMRFJcclxuXHQgKiBvciBIRFIuIFRoZSBpZGVhbCBpbnB1dCBpbWFnZSBzaXplIGlzIDFrICgxMDI0IHggNTEyKSxcclxuXHQgKiBhcyB0aGlzIG1hdGNoZXMgYmVzdCB3aXRoIHRoZSAyNTYgeCAyNTYgY3ViZW1hcCBvdXRwdXQuXHJcblx0ICovXHJcblx0ZnJvbUVxdWlyZWN0YW5ndWxhciggZXF1aXJlY3Rhbmd1bGFyLCByZW5kZXJUYXJnZXQgPSBudWxsICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLl9mcm9tVGV4dHVyZSggZXF1aXJlY3Rhbmd1bGFyLCByZW5kZXJUYXJnZXQgKTtcclxuXHJcblx0fVxyXG5cclxuXHQvKipcclxuXHQgKiBHZW5lcmF0ZXMgYSBQTVJFTSBmcm9tIGFuIGN1YmVtYXAgdGV4dHVyZSwgd2hpY2ggY2FuIGJlIGVpdGhlciBMRFJcclxuXHQgKiBvciBIRFIuIFRoZSBpZGVhbCBpbnB1dCBjdWJlIHNpemUgaXMgMjU2IHggMjU2LFxyXG5cdCAqIGFzIHRoaXMgbWF0Y2hlcyBiZXN0IHdpdGggdGhlIDI1NiB4IDI1NiBjdWJlbWFwIG91dHB1dC5cclxuXHQgKi9cclxuXHRmcm9tQ3ViZW1hcCggY3ViZW1hcCwgcmVuZGVyVGFyZ2V0ID0gbnVsbCApIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5fZnJvbVRleHR1cmUoIGN1YmVtYXAsIHJlbmRlclRhcmdldCApO1xyXG5cclxuXHR9XHJcblxyXG5cdC8qKlxyXG5cdCAqIFByZS1jb21waWxlcyB0aGUgY3ViZW1hcCBzaGFkZXIuIFlvdSBjYW4gZ2V0IGZhc3RlciBzdGFydC11cCBieSBpbnZva2luZyB0aGlzIG1ldGhvZCBkdXJpbmdcclxuXHQgKiB5b3VyIHRleHR1cmUncyBuZXR3b3JrIGZldGNoIGZvciBpbmNyZWFzZWQgY29uY3VycmVuY3kuXHJcblx0ICovXHJcblx0Y29tcGlsZUN1YmVtYXBTaGFkZXIoKSB7XHJcblxyXG5cdFx0aWYgKCB0aGlzLl9jdWJlbWFwTWF0ZXJpYWwgPT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHR0aGlzLl9jdWJlbWFwTWF0ZXJpYWwgPSBfZ2V0Q3ViZW1hcE1hdGVyaWFsKCk7XHJcblx0XHRcdHRoaXMuX2NvbXBpbGVNYXRlcmlhbCggdGhpcy5fY3ViZW1hcE1hdGVyaWFsICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdC8qKlxyXG5cdCAqIFByZS1jb21waWxlcyB0aGUgZXF1aXJlY3Rhbmd1bGFyIHNoYWRlci4gWW91IGNhbiBnZXQgZmFzdGVyIHN0YXJ0LXVwIGJ5IGludm9raW5nIHRoaXMgbWV0aG9kIGR1cmluZ1xyXG5cdCAqIHlvdXIgdGV4dHVyZSdzIG5ldHdvcmsgZmV0Y2ggZm9yIGluY3JlYXNlZCBjb25jdXJyZW5jeS5cclxuXHQgKi9cclxuXHRjb21waWxlRXF1aXJlY3Rhbmd1bGFyU2hhZGVyKCkge1xyXG5cclxuXHRcdGlmICggdGhpcy5fZXF1aXJlY3RNYXRlcmlhbCA9PT0gbnVsbCApIHtcclxuXHJcblx0XHRcdHRoaXMuX2VxdWlyZWN0TWF0ZXJpYWwgPSBfZ2V0RXF1aXJlY3RNYXRlcmlhbCgpO1xyXG5cdFx0XHR0aGlzLl9jb21waWxlTWF0ZXJpYWwoIHRoaXMuX2VxdWlyZWN0TWF0ZXJpYWwgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0LyoqXHJcblx0ICogRGlzcG9zZXMgb2YgdGhlIFBNUkVNR2VuZXJhdG9yJ3MgaW50ZXJuYWwgbWVtb3J5LiBOb3RlIHRoYXQgUE1SRU1HZW5lcmF0b3IgaXMgYSBzdGF0aWMgY2xhc3MsXHJcblx0ICogc28geW91IHNob3VsZCBub3QgbmVlZCBtb3JlIHRoYW4gb25lIFBNUkVNR2VuZXJhdG9yIG9iamVjdC4gSWYgeW91IGRvLCBjYWxsaW5nIGRpc3Bvc2UoKSBvblxyXG5cdCAqIG9uZSBvZiB0aGVtIHdpbGwgY2F1c2UgYW55IG90aGVycyB0byBhbHNvIGJlY29tZSB1bnVzYWJsZS5cclxuXHQgKi9cclxuXHRkaXNwb3NlKCkge1xyXG5cclxuXHRcdHRoaXMuX2Rpc3Bvc2UoKTtcclxuXHJcblx0XHRpZiAoIHRoaXMuX2N1YmVtYXBNYXRlcmlhbCAhPT0gbnVsbCApIHRoaXMuX2N1YmVtYXBNYXRlcmlhbC5kaXNwb3NlKCk7XHJcblx0XHRpZiAoIHRoaXMuX2VxdWlyZWN0TWF0ZXJpYWwgIT09IG51bGwgKSB0aGlzLl9lcXVpcmVjdE1hdGVyaWFsLmRpc3Bvc2UoKTtcclxuXHJcblx0fVxyXG5cclxuXHQvLyBwcml2YXRlIGludGVyZmFjZVxyXG5cclxuXHRfc2V0U2l6ZSggY3ViZVNpemUgKSB7XHJcblxyXG5cdFx0dGhpcy5fbG9kTWF4ID0gTWF0aC5mbG9vciggTWF0aC5sb2cyKCBjdWJlU2l6ZSApICk7XHJcblx0XHR0aGlzLl9jdWJlU2l6ZSA9IE1hdGgucG93KCAyLCB0aGlzLl9sb2RNYXggKTtcclxuXHJcblx0fVxyXG5cclxuXHRfZGlzcG9zZSgpIHtcclxuXHJcblx0XHRpZiAoIHRoaXMuX2JsdXJNYXRlcmlhbCAhPT0gbnVsbCApIHRoaXMuX2JsdXJNYXRlcmlhbC5kaXNwb3NlKCk7XHJcblxyXG5cdFx0aWYgKCB0aGlzLl9waW5nUG9uZ1JlbmRlclRhcmdldCAhPT0gbnVsbCApIHRoaXMuX3BpbmdQb25nUmVuZGVyVGFyZ2V0LmRpc3Bvc2UoKTtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCB0aGlzLl9sb2RQbGFuZXMubGVuZ3RoOyBpICsrICkge1xyXG5cclxuXHRcdFx0dGhpcy5fbG9kUGxhbmVzWyBpIF0uZGlzcG9zZSgpO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRfY2xlYW51cCggb3V0cHV0VGFyZ2V0ICkge1xyXG5cclxuXHRcdHRoaXMuX3JlbmRlcmVyLnNldFJlbmRlclRhcmdldCggX29sZFRhcmdldCwgX29sZEFjdGl2ZUN1YmVGYWNlLCBfb2xkQWN0aXZlTWlwbWFwTGV2ZWwgKTtcclxuXHRcdG91dHB1dFRhcmdldC5zY2lzc29yVGVzdCA9IGZhbHNlO1xyXG5cdFx0X3NldFZpZXdwb3J0KCBvdXRwdXRUYXJnZXQsIDAsIDAsIG91dHB1dFRhcmdldC53aWR0aCwgb3V0cHV0VGFyZ2V0LmhlaWdodCApO1xyXG5cclxuXHR9XHJcblxyXG5cdF9mcm9tVGV4dHVyZSggdGV4dHVyZSwgcmVuZGVyVGFyZ2V0ICkge1xyXG5cclxuXHRcdGlmICggdGV4dHVyZS5tYXBwaW5nID09PSBDdWJlUmVmbGVjdGlvbk1hcHBpbmcgfHwgdGV4dHVyZS5tYXBwaW5nID09PSBDdWJlUmVmcmFjdGlvbk1hcHBpbmcgKSB7XHJcblxyXG5cdFx0XHR0aGlzLl9zZXRTaXplKCB0ZXh0dXJlLmltYWdlLmxlbmd0aCA9PT0gMCA/IDE2IDogKCB0ZXh0dXJlLmltYWdlWyAwIF0ud2lkdGggfHwgdGV4dHVyZS5pbWFnZVsgMCBdLmltYWdlLndpZHRoICkgKTtcclxuXHJcblx0XHR9IGVsc2UgeyAvLyBFcXVpcmVjdGFuZ3VsYXJcclxuXHJcblx0XHRcdHRoaXMuX3NldFNpemUoIHRleHR1cmUuaW1hZ2Uud2lkdGggLyA0ICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdF9vbGRUYXJnZXQgPSB0aGlzLl9yZW5kZXJlci5nZXRSZW5kZXJUYXJnZXQoKTtcclxuXHRcdF9vbGRBY3RpdmVDdWJlRmFjZSA9IHRoaXMuX3JlbmRlcmVyLmdldEFjdGl2ZUN1YmVGYWNlKCk7XHJcblx0XHRfb2xkQWN0aXZlTWlwbWFwTGV2ZWwgPSB0aGlzLl9yZW5kZXJlci5nZXRBY3RpdmVNaXBtYXBMZXZlbCgpO1xyXG5cclxuXHRcdGNvbnN0IGN1YmVVVlJlbmRlclRhcmdldCA9IHJlbmRlclRhcmdldCB8fCB0aGlzLl9hbGxvY2F0ZVRhcmdldHMoKTtcclxuXHRcdHRoaXMuX3RleHR1cmVUb0N1YmVVViggdGV4dHVyZSwgY3ViZVVWUmVuZGVyVGFyZ2V0ICk7XHJcblx0XHR0aGlzLl9hcHBseVBNUkVNKCBjdWJlVVZSZW5kZXJUYXJnZXQgKTtcclxuXHRcdHRoaXMuX2NsZWFudXAoIGN1YmVVVlJlbmRlclRhcmdldCApO1xyXG5cclxuXHRcdHJldHVybiBjdWJlVVZSZW5kZXJUYXJnZXQ7XHJcblxyXG5cdH1cclxuXHJcblx0X2FsbG9jYXRlVGFyZ2V0cygpIHtcclxuXHJcblx0XHRjb25zdCB3aWR0aCA9IDMgKiBNYXRoLm1heCggdGhpcy5fY3ViZVNpemUsIDE2ICogNyApO1xyXG5cdFx0Y29uc3QgaGVpZ2h0ID0gNCAqIHRoaXMuX2N1YmVTaXplO1xyXG5cclxuXHRcdGNvbnN0IHBhcmFtcyA9IHtcclxuXHRcdFx0bWFnRmlsdGVyOiBMaW5lYXJGaWx0ZXIsXHJcblx0XHRcdG1pbkZpbHRlcjogTGluZWFyRmlsdGVyLFxyXG5cdFx0XHRnZW5lcmF0ZU1pcG1hcHM6IGZhbHNlLFxyXG5cdFx0XHR0eXBlOiBIYWxmRmxvYXRUeXBlLFxyXG5cdFx0XHRmb3JtYXQ6IFJHQkFGb3JtYXQsXHJcblx0XHRcdGNvbG9yU3BhY2U6IExpbmVhclNSR0JDb2xvclNwYWNlLFxyXG5cdFx0XHRkZXB0aEJ1ZmZlcjogZmFsc2VcclxuXHRcdH07XHJcblxyXG5cdFx0Y29uc3QgY3ViZVVWUmVuZGVyVGFyZ2V0ID0gX2NyZWF0ZVJlbmRlclRhcmdldCggd2lkdGgsIGhlaWdodCwgcGFyYW1zICk7XHJcblxyXG5cdFx0aWYgKCB0aGlzLl9waW5nUG9uZ1JlbmRlclRhcmdldCA9PT0gbnVsbCB8fCB0aGlzLl9waW5nUG9uZ1JlbmRlclRhcmdldC53aWR0aCAhPT0gd2lkdGggfHwgdGhpcy5fcGluZ1BvbmdSZW5kZXJUYXJnZXQuaGVpZ2h0ICE9PSBoZWlnaHQgKSB7XHJcblxyXG5cdFx0XHRpZiAoIHRoaXMuX3BpbmdQb25nUmVuZGVyVGFyZ2V0ICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0XHR0aGlzLl9kaXNwb3NlKCk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHR0aGlzLl9waW5nUG9uZ1JlbmRlclRhcmdldCA9IF9jcmVhdGVSZW5kZXJUYXJnZXQoIHdpZHRoLCBoZWlnaHQsIHBhcmFtcyApO1xyXG5cclxuXHRcdFx0Y29uc3QgeyBfbG9kTWF4IH0gPSB0aGlzO1xyXG5cdFx0XHQoIHsgc2l6ZUxvZHM6IHRoaXMuX3NpemVMb2RzLCBsb2RQbGFuZXM6IHRoaXMuX2xvZFBsYW5lcywgc2lnbWFzOiB0aGlzLl9zaWdtYXMgfSA9IF9jcmVhdGVQbGFuZXMoIF9sb2RNYXggKSApO1xyXG5cclxuXHRcdFx0dGhpcy5fYmx1ck1hdGVyaWFsID0gX2dldEJsdXJTaGFkZXIoIF9sb2RNYXgsIHdpZHRoLCBoZWlnaHQgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIGN1YmVVVlJlbmRlclRhcmdldDtcclxuXHJcblx0fVxyXG5cclxuXHRfY29tcGlsZU1hdGVyaWFsKCBtYXRlcmlhbCApIHtcclxuXHJcblx0XHRjb25zdCB0bXBNZXNoID0gbmV3IE1lc2goIHRoaXMuX2xvZFBsYW5lc1sgMCBdLCBtYXRlcmlhbCApO1xyXG5cdFx0dGhpcy5fcmVuZGVyZXIuY29tcGlsZSggdG1wTWVzaCwgX2ZsYXRDYW1lcmEgKTtcclxuXHJcblx0fVxyXG5cclxuXHRfc2NlbmVUb0N1YmVVViggc2NlbmUsIG5lYXIsIGZhciwgY3ViZVVWUmVuZGVyVGFyZ2V0ICkge1xyXG5cclxuXHRcdGNvbnN0IGZvdiA9IDkwO1xyXG5cdFx0Y29uc3QgYXNwZWN0ID0gMTtcclxuXHRcdGNvbnN0IGN1YmVDYW1lcmEgPSBuZXcgUGVyc3BlY3RpdmVDYW1lcmEoIGZvdiwgYXNwZWN0LCBuZWFyLCBmYXIgKTtcclxuXHRcdGNvbnN0IHVwU2lnbiA9IFsgMSwgLSAxLCAxLCAxLCAxLCAxIF07XHJcblx0XHRjb25zdCBmb3J3YXJkU2lnbiA9IFsgMSwgMSwgMSwgLSAxLCAtIDEsIC0gMSBdO1xyXG5cdFx0Y29uc3QgcmVuZGVyZXIgPSB0aGlzLl9yZW5kZXJlcjtcclxuXHJcblx0XHRjb25zdCBvcmlnaW5hbEF1dG9DbGVhciA9IHJlbmRlcmVyLmF1dG9DbGVhcjtcclxuXHRcdGNvbnN0IHRvbmVNYXBwaW5nID0gcmVuZGVyZXIudG9uZU1hcHBpbmc7XHJcblx0XHRyZW5kZXJlci5nZXRDbGVhckNvbG9yKCBfY2xlYXJDb2xvciApO1xyXG5cclxuXHRcdHJlbmRlcmVyLnRvbmVNYXBwaW5nID0gTm9Ub25lTWFwcGluZztcclxuXHRcdHJlbmRlcmVyLmF1dG9DbGVhciA9IGZhbHNlO1xyXG5cclxuXHRcdGNvbnN0IGJhY2tncm91bmRNYXRlcmlhbCA9IG5ldyBNZXNoQmFzaWNNYXRlcmlhbCgge1xyXG5cdFx0XHRuYW1lOiAnUE1SRU0uQmFja2dyb3VuZCcsXHJcblx0XHRcdHNpZGU6IEJhY2tTaWRlLFxyXG5cdFx0XHRkZXB0aFdyaXRlOiBmYWxzZSxcclxuXHRcdFx0ZGVwdGhUZXN0OiBmYWxzZSxcclxuXHRcdH0gKTtcclxuXHJcblx0XHRjb25zdCBiYWNrZ3JvdW5kQm94ID0gbmV3IE1lc2goIG5ldyBCb3hHZW9tZXRyeSgpLCBiYWNrZ3JvdW5kTWF0ZXJpYWwgKTtcclxuXHJcblx0XHRsZXQgdXNlU29saWRDb2xvciA9IGZhbHNlO1xyXG5cdFx0Y29uc3QgYmFja2dyb3VuZCA9IHNjZW5lLmJhY2tncm91bmQ7XHJcblxyXG5cdFx0aWYgKCBiYWNrZ3JvdW5kICkge1xyXG5cclxuXHRcdFx0aWYgKCBiYWNrZ3JvdW5kLmlzQ29sb3IgKSB7XHJcblxyXG5cdFx0XHRcdGJhY2tncm91bmRNYXRlcmlhbC5jb2xvci5jb3B5KCBiYWNrZ3JvdW5kICk7XHJcblx0XHRcdFx0c2NlbmUuYmFja2dyb3VuZCA9IG51bGw7XHJcblx0XHRcdFx0dXNlU29saWRDb2xvciA9IHRydWU7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdGJhY2tncm91bmRNYXRlcmlhbC5jb2xvci5jb3B5KCBfY2xlYXJDb2xvciApO1xyXG5cdFx0XHR1c2VTb2xpZENvbG9yID0gdHJ1ZTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgNjsgaSArKyApIHtcclxuXHJcblx0XHRcdGNvbnN0IGNvbCA9IGkgJSAzO1xyXG5cclxuXHRcdFx0aWYgKCBjb2wgPT09IDAgKSB7XHJcblxyXG5cdFx0XHRcdGN1YmVDYW1lcmEudXAuc2V0KCAwLCB1cFNpZ25bIGkgXSwgMCApO1xyXG5cdFx0XHRcdGN1YmVDYW1lcmEubG9va0F0KCBmb3J3YXJkU2lnblsgaSBdLCAwLCAwICk7XHJcblxyXG5cdFx0XHR9IGVsc2UgaWYgKCBjb2wgPT09IDEgKSB7XHJcblxyXG5cdFx0XHRcdGN1YmVDYW1lcmEudXAuc2V0KCAwLCAwLCB1cFNpZ25bIGkgXSApO1xyXG5cdFx0XHRcdGN1YmVDYW1lcmEubG9va0F0KCAwLCBmb3J3YXJkU2lnblsgaSBdLCAwICk7XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRjdWJlQ2FtZXJhLnVwLnNldCggMCwgdXBTaWduWyBpIF0sIDAgKTtcclxuXHRcdFx0XHRjdWJlQ2FtZXJhLmxvb2tBdCggMCwgMCwgZm9yd2FyZFNpZ25bIGkgXSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Y29uc3Qgc2l6ZSA9IHRoaXMuX2N1YmVTaXplO1xyXG5cclxuXHRcdFx0X3NldFZpZXdwb3J0KCBjdWJlVVZSZW5kZXJUYXJnZXQsIGNvbCAqIHNpemUsIGkgPiAyID8gc2l6ZSA6IDAsIHNpemUsIHNpemUgKTtcclxuXHJcblx0XHRcdHJlbmRlcmVyLnNldFJlbmRlclRhcmdldCggY3ViZVVWUmVuZGVyVGFyZ2V0ICk7XHJcblxyXG5cdFx0XHRpZiAoIHVzZVNvbGlkQ29sb3IgKSB7XHJcblxyXG5cdFx0XHRcdHJlbmRlcmVyLnJlbmRlciggYmFja2dyb3VuZEJveCwgY3ViZUNhbWVyYSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0cmVuZGVyZXIucmVuZGVyKCBzY2VuZSwgY3ViZUNhbWVyYSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRiYWNrZ3JvdW5kQm94Lmdlb21ldHJ5LmRpc3Bvc2UoKTtcclxuXHRcdGJhY2tncm91bmRCb3gubWF0ZXJpYWwuZGlzcG9zZSgpO1xyXG5cclxuXHRcdHJlbmRlcmVyLnRvbmVNYXBwaW5nID0gdG9uZU1hcHBpbmc7XHJcblx0XHRyZW5kZXJlci5hdXRvQ2xlYXIgPSBvcmlnaW5hbEF1dG9DbGVhcjtcclxuXHRcdHNjZW5lLmJhY2tncm91bmQgPSBiYWNrZ3JvdW5kO1xyXG5cclxuXHR9XHJcblxyXG5cdF90ZXh0dXJlVG9DdWJlVVYoIHRleHR1cmUsIGN1YmVVVlJlbmRlclRhcmdldCApIHtcclxuXHJcblx0XHRjb25zdCByZW5kZXJlciA9IHRoaXMuX3JlbmRlcmVyO1xyXG5cclxuXHRcdGNvbnN0IGlzQ3ViZVRleHR1cmUgPSAoIHRleHR1cmUubWFwcGluZyA9PT0gQ3ViZVJlZmxlY3Rpb25NYXBwaW5nIHx8IHRleHR1cmUubWFwcGluZyA9PT0gQ3ViZVJlZnJhY3Rpb25NYXBwaW5nICk7XHJcblxyXG5cdFx0aWYgKCBpc0N1YmVUZXh0dXJlICkge1xyXG5cclxuXHRcdFx0aWYgKCB0aGlzLl9jdWJlbWFwTWF0ZXJpYWwgPT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdHRoaXMuX2N1YmVtYXBNYXRlcmlhbCA9IF9nZXRDdWJlbWFwTWF0ZXJpYWwoKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHRoaXMuX2N1YmVtYXBNYXRlcmlhbC51bmlmb3Jtcy5mbGlwRW52TWFwLnZhbHVlID0gKCB0ZXh0dXJlLmlzUmVuZGVyVGFyZ2V0VGV4dHVyZSA9PT0gZmFsc2UgKSA/IC0gMSA6IDE7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdGlmICggdGhpcy5fZXF1aXJlY3RNYXRlcmlhbCA9PT0gbnVsbCApIHtcclxuXHJcblx0XHRcdFx0dGhpcy5fZXF1aXJlY3RNYXRlcmlhbCA9IF9nZXRFcXVpcmVjdE1hdGVyaWFsKCk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGNvbnN0IG1hdGVyaWFsID0gaXNDdWJlVGV4dHVyZSA/IHRoaXMuX2N1YmVtYXBNYXRlcmlhbCA6IHRoaXMuX2VxdWlyZWN0TWF0ZXJpYWw7XHJcblx0XHRjb25zdCBtZXNoID0gbmV3IE1lc2goIHRoaXMuX2xvZFBsYW5lc1sgMCBdLCBtYXRlcmlhbCApO1xyXG5cclxuXHRcdGNvbnN0IHVuaWZvcm1zID0gbWF0ZXJpYWwudW5pZm9ybXM7XHJcblxyXG5cdFx0dW5pZm9ybXNbICdlbnZNYXAnIF0udmFsdWUgPSB0ZXh0dXJlO1xyXG5cclxuXHRcdGNvbnN0IHNpemUgPSB0aGlzLl9jdWJlU2l6ZTtcclxuXHJcblx0XHRfc2V0Vmlld3BvcnQoIGN1YmVVVlJlbmRlclRhcmdldCwgMCwgMCwgMyAqIHNpemUsIDIgKiBzaXplICk7XHJcblxyXG5cdFx0cmVuZGVyZXIuc2V0UmVuZGVyVGFyZ2V0KCBjdWJlVVZSZW5kZXJUYXJnZXQgKTtcclxuXHRcdHJlbmRlcmVyLnJlbmRlciggbWVzaCwgX2ZsYXRDYW1lcmEgKTtcclxuXHJcblx0fVxyXG5cclxuXHRfYXBwbHlQTVJFTSggY3ViZVVWUmVuZGVyVGFyZ2V0ICkge1xyXG5cclxuXHRcdGNvbnN0IHJlbmRlcmVyID0gdGhpcy5fcmVuZGVyZXI7XHJcblx0XHRjb25zdCBhdXRvQ2xlYXIgPSByZW5kZXJlci5hdXRvQ2xlYXI7XHJcblx0XHRyZW5kZXJlci5hdXRvQ2xlYXIgPSBmYWxzZTtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDE7IGkgPCB0aGlzLl9sb2RQbGFuZXMubGVuZ3RoOyBpICsrICkge1xyXG5cclxuXHRcdFx0Y29uc3Qgc2lnbWEgPSBNYXRoLnNxcnQoIHRoaXMuX3NpZ21hc1sgaSBdICogdGhpcy5fc2lnbWFzWyBpIF0gLSB0aGlzLl9zaWdtYXNbIGkgLSAxIF0gKiB0aGlzLl9zaWdtYXNbIGkgLSAxIF0gKTtcclxuXHJcblx0XHRcdGNvbnN0IHBvbGVBeGlzID0gX2F4aXNEaXJlY3Rpb25zWyAoIGkgLSAxICkgJSBfYXhpc0RpcmVjdGlvbnMubGVuZ3RoIF07XHJcblxyXG5cdFx0XHR0aGlzLl9ibHVyKCBjdWJlVVZSZW5kZXJUYXJnZXQsIGkgLSAxLCBpLCBzaWdtYSwgcG9sZUF4aXMgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmVuZGVyZXIuYXV0b0NsZWFyID0gYXV0b0NsZWFyO1xyXG5cclxuXHR9XHJcblxyXG5cdC8qKlxyXG5cdCAqIFRoaXMgaXMgYSB0d28tcGFzcyBHYXVzc2lhbiBibHVyIGZvciBhIGN1YmVtYXAuIE5vcm1hbGx5IHRoaXMgaXMgZG9uZVxyXG5cdCAqIHZlcnRpY2FsbHkgYW5kIGhvcml6b250YWxseSwgYnV0IHRoaXMgYnJlYWtzIGRvd24gb24gYSBjdWJlLiBIZXJlIHdlIGFwcGx5XHJcblx0ICogdGhlIGJsdXIgbGF0aXR1ZGluYWxseSAoYXJvdW5kIHRoZSBwb2xlcyksIGFuZCB0aGVuIGxvbmdpdHVkaW5hbGx5ICh0b3dhcmRzXHJcblx0ICogdGhlIHBvbGVzKSB0byBhcHByb3hpbWF0ZSB0aGUgb3J0aG9nb25hbGx5LXNlcGFyYWJsZSBibHVyLiBJdCBpcyBsZWFzdFxyXG5cdCAqIGFjY3VyYXRlIGF0IHRoZSBwb2xlcywgYnV0IHN0aWxsIGRvZXMgYSBkZWNlbnQgam9iLlxyXG5cdCAqL1xyXG5cdF9ibHVyKCBjdWJlVVZSZW5kZXJUYXJnZXQsIGxvZEluLCBsb2RPdXQsIHNpZ21hLCBwb2xlQXhpcyApIHtcclxuXHJcblx0XHRjb25zdCBwaW5nUG9uZ1JlbmRlclRhcmdldCA9IHRoaXMuX3BpbmdQb25nUmVuZGVyVGFyZ2V0O1xyXG5cclxuXHRcdHRoaXMuX2hhbGZCbHVyKFxyXG5cdFx0XHRjdWJlVVZSZW5kZXJUYXJnZXQsXHJcblx0XHRcdHBpbmdQb25nUmVuZGVyVGFyZ2V0LFxyXG5cdFx0XHRsb2RJbixcclxuXHRcdFx0bG9kT3V0LFxyXG5cdFx0XHRzaWdtYSxcclxuXHRcdFx0J2xhdGl0dWRpbmFsJyxcclxuXHRcdFx0cG9sZUF4aXMgKTtcclxuXHJcblx0XHR0aGlzLl9oYWxmQmx1cihcclxuXHRcdFx0cGluZ1BvbmdSZW5kZXJUYXJnZXQsXHJcblx0XHRcdGN1YmVVVlJlbmRlclRhcmdldCxcclxuXHRcdFx0bG9kT3V0LFxyXG5cdFx0XHRsb2RPdXQsXHJcblx0XHRcdHNpZ21hLFxyXG5cdFx0XHQnbG9uZ2l0dWRpbmFsJyxcclxuXHRcdFx0cG9sZUF4aXMgKTtcclxuXHJcblx0fVxyXG5cclxuXHRfaGFsZkJsdXIoIHRhcmdldEluLCB0YXJnZXRPdXQsIGxvZEluLCBsb2RPdXQsIHNpZ21hUmFkaWFucywgZGlyZWN0aW9uLCBwb2xlQXhpcyApIHtcclxuXHJcblx0XHRjb25zdCByZW5kZXJlciA9IHRoaXMuX3JlbmRlcmVyO1xyXG5cdFx0Y29uc3QgYmx1ck1hdGVyaWFsID0gdGhpcy5fYmx1ck1hdGVyaWFsO1xyXG5cclxuXHRcdGlmICggZGlyZWN0aW9uICE9PSAnbGF0aXR1ZGluYWwnICYmIGRpcmVjdGlvbiAhPT0gJ2xvbmdpdHVkaW5hbCcgKSB7XHJcblxyXG5cdFx0XHRjb25zb2xlLmVycm9yKFxyXG5cdFx0XHRcdCdibHVyIGRpcmVjdGlvbiBtdXN0IGJlIGVpdGhlciBsYXRpdHVkaW5hbCBvciBsb25naXR1ZGluYWwhJyApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvLyBOdW1iZXIgb2Ygc3RhbmRhcmQgZGV2aWF0aW9ucyBhdCB3aGljaCB0byBjdXQgb2ZmIHRoZSBkaXNjcmV0ZSBhcHByb3hpbWF0aW9uLlxyXG5cdFx0Y29uc3QgU1RBTkRBUkRfREVWSUFUSU9OUyA9IDM7XHJcblxyXG5cdFx0Y29uc3QgYmx1ck1lc2ggPSBuZXcgTWVzaCggdGhpcy5fbG9kUGxhbmVzWyBsb2RPdXQgXSwgYmx1ck1hdGVyaWFsICk7XHJcblx0XHRjb25zdCBibHVyVW5pZm9ybXMgPSBibHVyTWF0ZXJpYWwudW5pZm9ybXM7XHJcblxyXG5cdFx0Y29uc3QgcGl4ZWxzID0gdGhpcy5fc2l6ZUxvZHNbIGxvZEluIF0gLSAxO1xyXG5cdFx0Y29uc3QgcmFkaWFuc1BlclBpeGVsID0gaXNGaW5pdGUoIHNpZ21hUmFkaWFucyApID8gTWF0aC5QSSAvICggMiAqIHBpeGVscyApIDogMiAqIE1hdGguUEkgLyAoIDIgKiBNQVhfU0FNUExFUyAtIDEgKTtcclxuXHRcdGNvbnN0IHNpZ21hUGl4ZWxzID0gc2lnbWFSYWRpYW5zIC8gcmFkaWFuc1BlclBpeGVsO1xyXG5cdFx0Y29uc3Qgc2FtcGxlcyA9IGlzRmluaXRlKCBzaWdtYVJhZGlhbnMgKSA/IDEgKyBNYXRoLmZsb29yKCBTVEFOREFSRF9ERVZJQVRJT05TICogc2lnbWFQaXhlbHMgKSA6IE1BWF9TQU1QTEVTO1xyXG5cclxuXHRcdGlmICggc2FtcGxlcyA+IE1BWF9TQU1QTEVTICkge1xyXG5cclxuXHRcdFx0Y29uc29sZS53YXJuKCBgc2lnbWFSYWRpYW5zLCAke1xyXG5cdFx0XHRcdHNpZ21hUmFkaWFuc30sIGlzIHRvbyBsYXJnZSBhbmQgd2lsbCBjbGlwLCBhcyBpdCByZXF1ZXN0ZWQgJHtcclxuXHRcdFx0XHRzYW1wbGVzfSBzYW1wbGVzIHdoZW4gdGhlIG1heGltdW0gaXMgc2V0IHRvICR7TUFYX1NBTVBMRVN9YCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCB3ZWlnaHRzID0gW107XHJcblx0XHRsZXQgc3VtID0gMDtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBNQVhfU0FNUExFUzsgKysgaSApIHtcclxuXHJcblx0XHRcdGNvbnN0IHggPSBpIC8gc2lnbWFQaXhlbHM7XHJcblx0XHRcdGNvbnN0IHdlaWdodCA9IE1hdGguZXhwKCAtIHggKiB4IC8gMiApO1xyXG5cdFx0XHR3ZWlnaHRzLnB1c2goIHdlaWdodCApO1xyXG5cclxuXHRcdFx0aWYgKCBpID09PSAwICkge1xyXG5cclxuXHRcdFx0XHRzdW0gKz0gd2VpZ2h0O1xyXG5cclxuXHRcdFx0fSBlbHNlIGlmICggaSA8IHNhbXBsZXMgKSB7XHJcblxyXG5cdFx0XHRcdHN1bSArPSAyICogd2VpZ2h0O1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCB3ZWlnaHRzLmxlbmd0aDsgaSArKyApIHtcclxuXHJcblx0XHRcdHdlaWdodHNbIGkgXSA9IHdlaWdodHNbIGkgXSAvIHN1bTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ymx1clVuaWZvcm1zWyAnZW52TWFwJyBdLnZhbHVlID0gdGFyZ2V0SW4udGV4dHVyZTtcclxuXHRcdGJsdXJVbmlmb3Jtc1sgJ3NhbXBsZXMnIF0udmFsdWUgPSBzYW1wbGVzO1xyXG5cdFx0Ymx1clVuaWZvcm1zWyAnd2VpZ2h0cycgXS52YWx1ZSA9IHdlaWdodHM7XHJcblx0XHRibHVyVW5pZm9ybXNbICdsYXRpdHVkaW5hbCcgXS52YWx1ZSA9IGRpcmVjdGlvbiA9PT0gJ2xhdGl0dWRpbmFsJztcclxuXHJcblx0XHRpZiAoIHBvbGVBeGlzICkge1xyXG5cclxuXHRcdFx0Ymx1clVuaWZvcm1zWyAncG9sZUF4aXMnIF0udmFsdWUgPSBwb2xlQXhpcztcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Y29uc3QgeyBfbG9kTWF4IH0gPSB0aGlzO1xyXG5cdFx0Ymx1clVuaWZvcm1zWyAnZFRoZXRhJyBdLnZhbHVlID0gcmFkaWFuc1BlclBpeGVsO1xyXG5cdFx0Ymx1clVuaWZvcm1zWyAnbWlwSW50JyBdLnZhbHVlID0gX2xvZE1heCAtIGxvZEluO1xyXG5cclxuXHRcdGNvbnN0IG91dHB1dFNpemUgPSB0aGlzLl9zaXplTG9kc1sgbG9kT3V0IF07XHJcblx0XHRjb25zdCB4ID0gMyAqIG91dHB1dFNpemUgKiAoIGxvZE91dCA+IF9sb2RNYXggLSBMT0RfTUlOID8gbG9kT3V0IC0gX2xvZE1heCArIExPRF9NSU4gOiAwICk7XHJcblx0XHRjb25zdCB5ID0gNCAqICggdGhpcy5fY3ViZVNpemUgLSBvdXRwdXRTaXplICk7XHJcblxyXG5cdFx0X3NldFZpZXdwb3J0KCB0YXJnZXRPdXQsIHgsIHksIDMgKiBvdXRwdXRTaXplLCAyICogb3V0cHV0U2l6ZSApO1xyXG5cdFx0cmVuZGVyZXIuc2V0UmVuZGVyVGFyZ2V0KCB0YXJnZXRPdXQgKTtcclxuXHRcdHJlbmRlcmVyLnJlbmRlciggYmx1ck1lc2gsIF9mbGF0Q2FtZXJhICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcblxyXG5cclxuZnVuY3Rpb24gX2NyZWF0ZVBsYW5lcyggbG9kTWF4ICkge1xyXG5cclxuXHRjb25zdCBsb2RQbGFuZXMgPSBbXTtcclxuXHRjb25zdCBzaXplTG9kcyA9IFtdO1xyXG5cdGNvbnN0IHNpZ21hcyA9IFtdO1xyXG5cclxuXHRsZXQgbG9kID0gbG9kTWF4O1xyXG5cclxuXHRjb25zdCB0b3RhbExvZHMgPSBsb2RNYXggLSBMT0RfTUlOICsgMSArIEVYVFJBX0xPRF9TSUdNQS5sZW5ndGg7XHJcblxyXG5cdGZvciAoIGxldCBpID0gMDsgaSA8IHRvdGFsTG9kczsgaSArKyApIHtcclxuXHJcblx0XHRjb25zdCBzaXplTG9kID0gTWF0aC5wb3coIDIsIGxvZCApO1xyXG5cdFx0c2l6ZUxvZHMucHVzaCggc2l6ZUxvZCApO1xyXG5cdFx0bGV0IHNpZ21hID0gMS4wIC8gc2l6ZUxvZDtcclxuXHJcblx0XHRpZiAoIGkgPiBsb2RNYXggLSBMT0RfTUlOICkge1xyXG5cclxuXHRcdFx0c2lnbWEgPSBFWFRSQV9MT0RfU0lHTUFbIGkgLSBsb2RNYXggKyBMT0RfTUlOIC0gMSBdO1xyXG5cclxuXHRcdH0gZWxzZSBpZiAoIGkgPT09IDAgKSB7XHJcblxyXG5cdFx0XHRzaWdtYSA9IDA7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHNpZ21hcy5wdXNoKCBzaWdtYSApO1xyXG5cclxuXHRcdGNvbnN0IHRleGVsU2l6ZSA9IDEuMCAvICggc2l6ZUxvZCAtIDIgKTtcclxuXHRcdGNvbnN0IG1pbiA9IC0gdGV4ZWxTaXplO1xyXG5cdFx0Y29uc3QgbWF4ID0gMSArIHRleGVsU2l6ZTtcclxuXHRcdGNvbnN0IHV2MSA9IFsgbWluLCBtaW4sIG1heCwgbWluLCBtYXgsIG1heCwgbWluLCBtaW4sIG1heCwgbWF4LCBtaW4sIG1heCBdO1xyXG5cclxuXHRcdGNvbnN0IGN1YmVGYWNlcyA9IDY7XHJcblx0XHRjb25zdCB2ZXJ0aWNlcyA9IDY7XHJcblx0XHRjb25zdCBwb3NpdGlvblNpemUgPSAzO1xyXG5cdFx0Y29uc3QgdXZTaXplID0gMjtcclxuXHRcdGNvbnN0IGZhY2VJbmRleFNpemUgPSAxO1xyXG5cclxuXHRcdGNvbnN0IHBvc2l0aW9uID0gbmV3IEZsb2F0MzJBcnJheSggcG9zaXRpb25TaXplICogdmVydGljZXMgKiBjdWJlRmFjZXMgKTtcclxuXHRcdGNvbnN0IHV2ID0gbmV3IEZsb2F0MzJBcnJheSggdXZTaXplICogdmVydGljZXMgKiBjdWJlRmFjZXMgKTtcclxuXHRcdGNvbnN0IGZhY2VJbmRleCA9IG5ldyBGbG9hdDMyQXJyYXkoIGZhY2VJbmRleFNpemUgKiB2ZXJ0aWNlcyAqIGN1YmVGYWNlcyApO1xyXG5cclxuXHRcdGZvciAoIGxldCBmYWNlID0gMDsgZmFjZSA8IGN1YmVGYWNlczsgZmFjZSArKyApIHtcclxuXHJcblx0XHRcdGNvbnN0IHggPSAoIGZhY2UgJSAzICkgKiAyIC8gMyAtIDE7XHJcblx0XHRcdGNvbnN0IHkgPSBmYWNlID4gMiA/IDAgOiAtIDE7XHJcblx0XHRcdGNvbnN0IGNvb3JkaW5hdGVzID0gW1xyXG5cdFx0XHRcdHgsIHksIDAsXHJcblx0XHRcdFx0eCArIDIgLyAzLCB5LCAwLFxyXG5cdFx0XHRcdHggKyAyIC8gMywgeSArIDEsIDAsXHJcblx0XHRcdFx0eCwgeSwgMCxcclxuXHRcdFx0XHR4ICsgMiAvIDMsIHkgKyAxLCAwLFxyXG5cdFx0XHRcdHgsIHkgKyAxLCAwXHJcblx0XHRcdF07XHJcblx0XHRcdHBvc2l0aW9uLnNldCggY29vcmRpbmF0ZXMsIHBvc2l0aW9uU2l6ZSAqIHZlcnRpY2VzICogZmFjZSApO1xyXG5cdFx0XHR1di5zZXQoIHV2MSwgdXZTaXplICogdmVydGljZXMgKiBmYWNlICk7XHJcblx0XHRcdGNvbnN0IGZpbGwgPSBbIGZhY2UsIGZhY2UsIGZhY2UsIGZhY2UsIGZhY2UsIGZhY2UgXTtcclxuXHRcdFx0ZmFjZUluZGV4LnNldCggZmlsbCwgZmFjZUluZGV4U2l6ZSAqIHZlcnRpY2VzICogZmFjZSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCBwbGFuZXMgPSBuZXcgQnVmZmVyR2VvbWV0cnkoKTtcclxuXHRcdHBsYW5lcy5zZXRBdHRyaWJ1dGUoICdwb3NpdGlvbicsIG5ldyBCdWZmZXJBdHRyaWJ1dGUoIHBvc2l0aW9uLCBwb3NpdGlvblNpemUgKSApO1xyXG5cdFx0cGxhbmVzLnNldEF0dHJpYnV0ZSggJ3V2JywgbmV3IEJ1ZmZlckF0dHJpYnV0ZSggdXYsIHV2U2l6ZSApICk7XHJcblx0XHRwbGFuZXMuc2V0QXR0cmlidXRlKCAnZmFjZUluZGV4JywgbmV3IEJ1ZmZlckF0dHJpYnV0ZSggZmFjZUluZGV4LCBmYWNlSW5kZXhTaXplICkgKTtcclxuXHRcdGxvZFBsYW5lcy5wdXNoKCBwbGFuZXMgKTtcclxuXHJcblx0XHRpZiAoIGxvZCA+IExPRF9NSU4gKSB7XHJcblxyXG5cdFx0XHRsb2QgLS07XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdHJldHVybiB7IGxvZFBsYW5lcywgc2l6ZUxvZHMsIHNpZ21hcyB9O1xyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gX2NyZWF0ZVJlbmRlclRhcmdldCggd2lkdGgsIGhlaWdodCwgcGFyYW1zICkge1xyXG5cclxuXHRjb25zdCBjdWJlVVZSZW5kZXJUYXJnZXQgPSBuZXcgV2ViR0xSZW5kZXJUYXJnZXQoIHdpZHRoLCBoZWlnaHQsIHBhcmFtcyApO1xyXG5cdGN1YmVVVlJlbmRlclRhcmdldC50ZXh0dXJlLm1hcHBpbmcgPSBDdWJlVVZSZWZsZWN0aW9uTWFwcGluZztcclxuXHRjdWJlVVZSZW5kZXJUYXJnZXQudGV4dHVyZS5uYW1lID0gJ1BNUkVNLmN1YmVVdic7XHJcblx0Y3ViZVVWUmVuZGVyVGFyZ2V0LnNjaXNzb3JUZXN0ID0gdHJ1ZTtcclxuXHRyZXR1cm4gY3ViZVVWUmVuZGVyVGFyZ2V0O1xyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gX3NldFZpZXdwb3J0KCB0YXJnZXQsIHgsIHksIHdpZHRoLCBoZWlnaHQgKSB7XHJcblxyXG5cdHRhcmdldC52aWV3cG9ydC5zZXQoIHgsIHksIHdpZHRoLCBoZWlnaHQgKTtcclxuXHR0YXJnZXQuc2Npc3Nvci5zZXQoIHgsIHksIHdpZHRoLCBoZWlnaHQgKTtcclxuXHJcbn1cclxuXHJcbmZ1bmN0aW9uIF9nZXRCbHVyU2hhZGVyKCBsb2RNYXgsIHdpZHRoLCBoZWlnaHQgKSB7XHJcblxyXG5cdGNvbnN0IHdlaWdodHMgPSBuZXcgRmxvYXQzMkFycmF5KCBNQVhfU0FNUExFUyApO1xyXG5cdGNvbnN0IHBvbGVBeGlzID0gbmV3IFZlY3RvcjMoIDAsIDEsIDAgKTtcclxuXHRjb25zdCBzaGFkZXJNYXRlcmlhbCA9IG5ldyBTaGFkZXJNYXRlcmlhbCgge1xyXG5cclxuXHRcdG5hbWU6ICdTcGhlcmljYWxHYXVzc2lhbkJsdXInLFxyXG5cclxuXHRcdGRlZmluZXM6IHtcclxuXHRcdFx0J24nOiBNQVhfU0FNUExFUyxcclxuXHRcdFx0J0NVQkVVVl9URVhFTF9XSURUSCc6IDEuMCAvIHdpZHRoLFxyXG5cdFx0XHQnQ1VCRVVWX1RFWEVMX0hFSUdIVCc6IDEuMCAvIGhlaWdodCxcclxuXHRcdFx0J0NVQkVVVl9NQVhfTUlQJzogYCR7bG9kTWF4fS4wYCxcclxuXHRcdH0sXHJcblxyXG5cdFx0dW5pZm9ybXM6IHtcclxuXHRcdFx0J2Vudk1hcCc6IHsgdmFsdWU6IG51bGwgfSxcclxuXHRcdFx0J3NhbXBsZXMnOiB7IHZhbHVlOiAxIH0sXHJcblx0XHRcdCd3ZWlnaHRzJzogeyB2YWx1ZTogd2VpZ2h0cyB9LFxyXG5cdFx0XHQnbGF0aXR1ZGluYWwnOiB7IHZhbHVlOiBmYWxzZSB9LFxyXG5cdFx0XHQnZFRoZXRhJzogeyB2YWx1ZTogMCB9LFxyXG5cdFx0XHQnbWlwSW50JzogeyB2YWx1ZTogMCB9LFxyXG5cdFx0XHQncG9sZUF4aXMnOiB7IHZhbHVlOiBwb2xlQXhpcyB9XHJcblx0XHR9LFxyXG5cclxuXHRcdHZlcnRleFNoYWRlcjogX2dldENvbW1vblZlcnRleFNoYWRlcigpLFxyXG5cclxuXHRcdGZyYWdtZW50U2hhZGVyOiAvKiBnbHNsICovYFxyXG5cclxuXHRcdFx0cHJlY2lzaW9uIG1lZGl1bXAgZmxvYXQ7XHJcblx0XHRcdHByZWNpc2lvbiBtZWRpdW1wIGludDtcclxuXHJcblx0XHRcdHZhcnlpbmcgdmVjMyB2T3V0cHV0RGlyZWN0aW9uO1xyXG5cclxuXHRcdFx0dW5pZm9ybSBzYW1wbGVyMkQgZW52TWFwO1xyXG5cdFx0XHR1bmlmb3JtIGludCBzYW1wbGVzO1xyXG5cdFx0XHR1bmlmb3JtIGZsb2F0IHdlaWdodHNbIG4gXTtcclxuXHRcdFx0dW5pZm9ybSBib29sIGxhdGl0dWRpbmFsO1xyXG5cdFx0XHR1bmlmb3JtIGZsb2F0IGRUaGV0YTtcclxuXHRcdFx0dW5pZm9ybSBmbG9hdCBtaXBJbnQ7XHJcblx0XHRcdHVuaWZvcm0gdmVjMyBwb2xlQXhpcztcclxuXHJcblx0XHRcdCNkZWZpbmUgRU5WTUFQX1RZUEVfQ1VCRV9VVlxyXG5cdFx0XHQjaW5jbHVkZSA8Y3ViZV91dl9yZWZsZWN0aW9uX2ZyYWdtZW50PlxyXG5cclxuXHRcdFx0dmVjMyBnZXRTYW1wbGUoIGZsb2F0IHRoZXRhLCB2ZWMzIGF4aXMgKSB7XHJcblxyXG5cdFx0XHRcdGZsb2F0IGNvc1RoZXRhID0gY29zKCB0aGV0YSApO1xyXG5cdFx0XHRcdC8vIFJvZHJpZ3VlcycgYXhpcy1hbmdsZSByb3RhdGlvblxyXG5cdFx0XHRcdHZlYzMgc2FtcGxlRGlyZWN0aW9uID0gdk91dHB1dERpcmVjdGlvbiAqIGNvc1RoZXRhXHJcblx0XHRcdFx0XHQrIGNyb3NzKCBheGlzLCB2T3V0cHV0RGlyZWN0aW9uICkgKiBzaW4oIHRoZXRhIClcclxuXHRcdFx0XHRcdCsgYXhpcyAqIGRvdCggYXhpcywgdk91dHB1dERpcmVjdGlvbiApICogKCAxLjAgLSBjb3NUaGV0YSApO1xyXG5cclxuXHRcdFx0XHRyZXR1cm4gYmlsaW5lYXJDdWJlVVYoIGVudk1hcCwgc2FtcGxlRGlyZWN0aW9uLCBtaXBJbnQgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHZvaWQgbWFpbigpIHtcclxuXHJcblx0XHRcdFx0dmVjMyBheGlzID0gbGF0aXR1ZGluYWwgPyBwb2xlQXhpcyA6IGNyb3NzKCBwb2xlQXhpcywgdk91dHB1dERpcmVjdGlvbiApO1xyXG5cclxuXHRcdFx0XHRpZiAoIGFsbCggZXF1YWwoIGF4aXMsIHZlYzMoIDAuMCApICkgKSApIHtcclxuXHJcblx0XHRcdFx0XHRheGlzID0gdmVjMyggdk91dHB1dERpcmVjdGlvbi56LCAwLjAsIC0gdk91dHB1dERpcmVjdGlvbi54ICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0YXhpcyA9IG5vcm1hbGl6ZSggYXhpcyApO1xyXG5cclxuXHRcdFx0XHRnbF9GcmFnQ29sb3IgPSB2ZWM0KCAwLjAsIDAuMCwgMC4wLCAxLjAgKTtcclxuXHRcdFx0XHRnbF9GcmFnQ29sb3IucmdiICs9IHdlaWdodHNbIDAgXSAqIGdldFNhbXBsZSggMC4wLCBheGlzICk7XHJcblxyXG5cdFx0XHRcdGZvciAoIGludCBpID0gMTsgaSA8IG47IGkrKyApIHtcclxuXHJcblx0XHRcdFx0XHRpZiAoIGkgPj0gc2FtcGxlcyApIHtcclxuXHJcblx0XHRcdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRmbG9hdCB0aGV0YSA9IGRUaGV0YSAqIGZsb2F0KCBpICk7XHJcblx0XHRcdFx0XHRnbF9GcmFnQ29sb3IucmdiICs9IHdlaWdodHNbIGkgXSAqIGdldFNhbXBsZSggLTEuMCAqIHRoZXRhLCBheGlzICk7XHJcblx0XHRcdFx0XHRnbF9GcmFnQ29sb3IucmdiICs9IHdlaWdodHNbIGkgXSAqIGdldFNhbXBsZSggdGhldGEsIGF4aXMgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cdFx0YCxcclxuXHJcblx0XHRibGVuZGluZzogTm9CbGVuZGluZyxcclxuXHRcdGRlcHRoVGVzdDogZmFsc2UsXHJcblx0XHRkZXB0aFdyaXRlOiBmYWxzZVxyXG5cclxuXHR9ICk7XHJcblxyXG5cdHJldHVybiBzaGFkZXJNYXRlcmlhbDtcclxuXHJcbn1cclxuXHJcbmZ1bmN0aW9uIF9nZXRFcXVpcmVjdE1hdGVyaWFsKCkge1xyXG5cclxuXHRyZXR1cm4gbmV3IFNoYWRlck1hdGVyaWFsKCB7XHJcblxyXG5cdFx0bmFtZTogJ0VxdWlyZWN0YW5ndWxhclRvQ3ViZVVWJyxcclxuXHJcblx0XHR1bmlmb3Jtczoge1xyXG5cdFx0XHQnZW52TWFwJzogeyB2YWx1ZTogbnVsbCB9XHJcblx0XHR9LFxyXG5cclxuXHRcdHZlcnRleFNoYWRlcjogX2dldENvbW1vblZlcnRleFNoYWRlcigpLFxyXG5cclxuXHRcdGZyYWdtZW50U2hhZGVyOiAvKiBnbHNsICovYFxyXG5cclxuXHRcdFx0cHJlY2lzaW9uIG1lZGl1bXAgZmxvYXQ7XHJcblx0XHRcdHByZWNpc2lvbiBtZWRpdW1wIGludDtcclxuXHJcblx0XHRcdHZhcnlpbmcgdmVjMyB2T3V0cHV0RGlyZWN0aW9uO1xyXG5cclxuXHRcdFx0dW5pZm9ybSBzYW1wbGVyMkQgZW52TWFwO1xyXG5cclxuXHRcdFx0I2luY2x1ZGUgPGNvbW1vbj5cclxuXHJcblx0XHRcdHZvaWQgbWFpbigpIHtcclxuXHJcblx0XHRcdFx0dmVjMyBvdXRwdXREaXJlY3Rpb24gPSBub3JtYWxpemUoIHZPdXRwdXREaXJlY3Rpb24gKTtcclxuXHRcdFx0XHR2ZWMyIHV2ID0gZXF1aXJlY3RVdiggb3V0cHV0RGlyZWN0aW9uICk7XHJcblxyXG5cdFx0XHRcdGdsX0ZyYWdDb2xvciA9IHZlYzQoIHRleHR1cmUyRCAoIGVudk1hcCwgdXYgKS5yZ2IsIDEuMCApO1xyXG5cclxuXHRcdFx0fVxyXG5cdFx0YCxcclxuXHJcblx0XHRibGVuZGluZzogTm9CbGVuZGluZyxcclxuXHRcdGRlcHRoVGVzdDogZmFsc2UsXHJcblx0XHRkZXB0aFdyaXRlOiBmYWxzZVxyXG5cclxuXHR9ICk7XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiBfZ2V0Q3ViZW1hcE1hdGVyaWFsKCkge1xyXG5cclxuXHRyZXR1cm4gbmV3IFNoYWRlck1hdGVyaWFsKCB7XHJcblxyXG5cdFx0bmFtZTogJ0N1YmVtYXBUb0N1YmVVVicsXHJcblxyXG5cdFx0dW5pZm9ybXM6IHtcclxuXHRcdFx0J2Vudk1hcCc6IHsgdmFsdWU6IG51bGwgfSxcclxuXHRcdFx0J2ZsaXBFbnZNYXAnOiB7IHZhbHVlOiAtIDEgfVxyXG5cdFx0fSxcclxuXHJcblx0XHR2ZXJ0ZXhTaGFkZXI6IF9nZXRDb21tb25WZXJ0ZXhTaGFkZXIoKSxcclxuXHJcblx0XHRmcmFnbWVudFNoYWRlcjogLyogZ2xzbCAqL2BcclxuXHJcblx0XHRcdHByZWNpc2lvbiBtZWRpdW1wIGZsb2F0O1xyXG5cdFx0XHRwcmVjaXNpb24gbWVkaXVtcCBpbnQ7XHJcblxyXG5cdFx0XHR1bmlmb3JtIGZsb2F0IGZsaXBFbnZNYXA7XHJcblxyXG5cdFx0XHR2YXJ5aW5nIHZlYzMgdk91dHB1dERpcmVjdGlvbjtcclxuXHJcblx0XHRcdHVuaWZvcm0gc2FtcGxlckN1YmUgZW52TWFwO1xyXG5cclxuXHRcdFx0dm9pZCBtYWluKCkge1xyXG5cclxuXHRcdFx0XHRnbF9GcmFnQ29sb3IgPSB0ZXh0dXJlQ3ViZSggZW52TWFwLCB2ZWMzKCBmbGlwRW52TWFwICogdk91dHB1dERpcmVjdGlvbi54LCB2T3V0cHV0RGlyZWN0aW9uLnl6ICkgKTtcclxuXHJcblx0XHRcdH1cclxuXHRcdGAsXHJcblxyXG5cdFx0YmxlbmRpbmc6IE5vQmxlbmRpbmcsXHJcblx0XHRkZXB0aFRlc3Q6IGZhbHNlLFxyXG5cdFx0ZGVwdGhXcml0ZTogZmFsc2VcclxuXHJcblx0fSApO1xyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gX2dldENvbW1vblZlcnRleFNoYWRlcigpIHtcclxuXHJcblx0cmV0dXJuIC8qIGdsc2wgKi9gXHJcblxyXG5cdFx0cHJlY2lzaW9uIG1lZGl1bXAgZmxvYXQ7XHJcblx0XHRwcmVjaXNpb24gbWVkaXVtcCBpbnQ7XHJcblxyXG5cdFx0YXR0cmlidXRlIGZsb2F0IGZhY2VJbmRleDtcclxuXHJcblx0XHR2YXJ5aW5nIHZlYzMgdk91dHB1dERpcmVjdGlvbjtcclxuXHJcblx0XHQvLyBSSCBjb29yZGluYXRlIHN5c3RlbTsgUE1SRU0gZmFjZS1pbmRleGluZyBjb252ZW50aW9uXHJcblx0XHR2ZWMzIGdldERpcmVjdGlvbiggdmVjMiB1diwgZmxvYXQgZmFjZSApIHtcclxuXHJcblx0XHRcdHV2ID0gMi4wICogdXYgLSAxLjA7XHJcblxyXG5cdFx0XHR2ZWMzIGRpcmVjdGlvbiA9IHZlYzMoIHV2LCAxLjAgKTtcclxuXHJcblx0XHRcdGlmICggZmFjZSA9PSAwLjAgKSB7XHJcblxyXG5cdFx0XHRcdGRpcmVjdGlvbiA9IGRpcmVjdGlvbi56eXg7IC8vICggMSwgdiwgdSApIHBvcyB4XHJcblxyXG5cdFx0XHR9IGVsc2UgaWYgKCBmYWNlID09IDEuMCApIHtcclxuXHJcblx0XHRcdFx0ZGlyZWN0aW9uID0gZGlyZWN0aW9uLnh6eTtcclxuXHRcdFx0XHRkaXJlY3Rpb24ueHogKj0gLTEuMDsgLy8gKCAtdSwgMSwgLXYgKSBwb3MgeVxyXG5cclxuXHRcdFx0fSBlbHNlIGlmICggZmFjZSA9PSAyLjAgKSB7XHJcblxyXG5cdFx0XHRcdGRpcmVjdGlvbi54ICo9IC0xLjA7IC8vICggLXUsIHYsIDEgKSBwb3MgelxyXG5cclxuXHRcdFx0fSBlbHNlIGlmICggZmFjZSA9PSAzLjAgKSB7XHJcblxyXG5cdFx0XHRcdGRpcmVjdGlvbiA9IGRpcmVjdGlvbi56eXg7XHJcblx0XHRcdFx0ZGlyZWN0aW9uLnh6ICo9IC0xLjA7IC8vICggLTEsIHYsIC11ICkgbmVnIHhcclxuXHJcblx0XHRcdH0gZWxzZSBpZiAoIGZhY2UgPT0gNC4wICkge1xyXG5cclxuXHRcdFx0XHRkaXJlY3Rpb24gPSBkaXJlY3Rpb24ueHp5O1xyXG5cdFx0XHRcdGRpcmVjdGlvbi54eSAqPSAtMS4wOyAvLyAoIC11LCAtMSwgdiApIG5lZyB5XHJcblxyXG5cdFx0XHR9IGVsc2UgaWYgKCBmYWNlID09IDUuMCApIHtcclxuXHJcblx0XHRcdFx0ZGlyZWN0aW9uLnogKj0gLTEuMDsgLy8gKCB1LCB2LCAtMSApIG5lZyB6XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRyZXR1cm4gZGlyZWN0aW9uO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHR2b2lkIG1haW4oKSB7XHJcblxyXG5cdFx0XHR2T3V0cHV0RGlyZWN0aW9uID0gZ2V0RGlyZWN0aW9uKCB1diwgZmFjZUluZGV4ICk7XHJcblx0XHRcdGdsX1Bvc2l0aW9uID0gdmVjNCggcG9zaXRpb24sIDEuMCApO1xyXG5cclxuXHRcdH1cclxuXHRgO1xyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgUE1SRU1HZW5lcmF0b3IgfTtcclxuIiwiaW1wb3J0IHsgQ3ViZVJlZmxlY3Rpb25NYXBwaW5nLCBDdWJlUmVmcmFjdGlvbk1hcHBpbmcsIEVxdWlyZWN0YW5ndWxhclJlZmxlY3Rpb25NYXBwaW5nLCBFcXVpcmVjdGFuZ3VsYXJSZWZyYWN0aW9uTWFwcGluZyB9IGZyb20gJy4uLy4uL2NvbnN0YW50cy5qcyc7XHJcbmltcG9ydCB7IFBNUkVNR2VuZXJhdG9yIH0gZnJvbSAnLi4vLi4vZXh0cmFzL1BNUkVNR2VuZXJhdG9yLmpzJztcclxuXHJcbmZ1bmN0aW9uIFdlYkdMQ3ViZVVWTWFwcyggcmVuZGVyZXIgKSB7XHJcblxyXG5cdGxldCBjdWJlVVZtYXBzID0gbmV3IFdlYWtNYXAoKTtcclxuXHJcblx0bGV0IHBtcmVtR2VuZXJhdG9yID0gbnVsbDtcclxuXHJcblx0ZnVuY3Rpb24gZ2V0KCB0ZXh0dXJlICkge1xyXG5cclxuXHRcdGlmICggdGV4dHVyZSAmJiB0ZXh0dXJlLmlzVGV4dHVyZSApIHtcclxuXHJcblx0XHRcdGNvbnN0IG1hcHBpbmcgPSB0ZXh0dXJlLm1hcHBpbmc7XHJcblxyXG5cdFx0XHRjb25zdCBpc0VxdWlyZWN0TWFwID0gKCBtYXBwaW5nID09PSBFcXVpcmVjdGFuZ3VsYXJSZWZsZWN0aW9uTWFwcGluZyB8fCBtYXBwaW5nID09PSBFcXVpcmVjdGFuZ3VsYXJSZWZyYWN0aW9uTWFwcGluZyApO1xyXG5cdFx0XHRjb25zdCBpc0N1YmVNYXAgPSAoIG1hcHBpbmcgPT09IEN1YmVSZWZsZWN0aW9uTWFwcGluZyB8fCBtYXBwaW5nID09PSBDdWJlUmVmcmFjdGlvbk1hcHBpbmcgKTtcclxuXHJcblx0XHRcdC8vIGVxdWlyZWN0L2N1YmUgbWFwIHRvIGN1YmVVViBjb252ZXJzaW9uXHJcblxyXG5cdFx0XHRpZiAoIGlzRXF1aXJlY3RNYXAgfHwgaXNDdWJlTWFwICkge1xyXG5cclxuXHRcdFx0XHRpZiAoIHRleHR1cmUuaXNSZW5kZXJUYXJnZXRUZXh0dXJlICYmIHRleHR1cmUubmVlZHNQTVJFTVVwZGF0ZSA9PT0gdHJ1ZSApIHtcclxuXHJcblx0XHRcdFx0XHR0ZXh0dXJlLm5lZWRzUE1SRU1VcGRhdGUgPSBmYWxzZTtcclxuXHJcblx0XHRcdFx0XHRsZXQgcmVuZGVyVGFyZ2V0ID0gY3ViZVVWbWFwcy5nZXQoIHRleHR1cmUgKTtcclxuXHJcblx0XHRcdFx0XHRpZiAoIHBtcmVtR2VuZXJhdG9yID09PSBudWxsICkgcG1yZW1HZW5lcmF0b3IgPSBuZXcgUE1SRU1HZW5lcmF0b3IoIHJlbmRlcmVyICk7XHJcblxyXG5cdFx0XHRcdFx0cmVuZGVyVGFyZ2V0ID0gaXNFcXVpcmVjdE1hcCA/IHBtcmVtR2VuZXJhdG9yLmZyb21FcXVpcmVjdGFuZ3VsYXIoIHRleHR1cmUsIHJlbmRlclRhcmdldCApIDogcG1yZW1HZW5lcmF0b3IuZnJvbUN1YmVtYXAoIHRleHR1cmUsIHJlbmRlclRhcmdldCApO1xyXG5cdFx0XHRcdFx0Y3ViZVVWbWFwcy5zZXQoIHRleHR1cmUsIHJlbmRlclRhcmdldCApO1xyXG5cclxuXHRcdFx0XHRcdHJldHVybiByZW5kZXJUYXJnZXQudGV4dHVyZTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRpZiAoIGN1YmVVVm1hcHMuaGFzKCB0ZXh0dXJlICkgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRyZXR1cm4gY3ViZVVWbWFwcy5nZXQoIHRleHR1cmUgKS50ZXh0dXJlO1xyXG5cclxuXHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHRjb25zdCBpbWFnZSA9IHRleHR1cmUuaW1hZ2U7XHJcblxyXG5cdFx0XHRcdFx0XHRpZiAoICggaXNFcXVpcmVjdE1hcCAmJiBpbWFnZSAmJiBpbWFnZS5oZWlnaHQgPiAwICkgfHwgKCBpc0N1YmVNYXAgJiYgaW1hZ2UgJiYgaXNDdWJlVGV4dHVyZUNvbXBsZXRlKCBpbWFnZSApICkgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdGlmICggcG1yZW1HZW5lcmF0b3IgPT09IG51bGwgKSBwbXJlbUdlbmVyYXRvciA9IG5ldyBQTVJFTUdlbmVyYXRvciggcmVuZGVyZXIgKTtcclxuXHJcblx0XHRcdFx0XHRcdFx0Y29uc3QgcmVuZGVyVGFyZ2V0ID0gaXNFcXVpcmVjdE1hcCA/IHBtcmVtR2VuZXJhdG9yLmZyb21FcXVpcmVjdGFuZ3VsYXIoIHRleHR1cmUgKSA6IHBtcmVtR2VuZXJhdG9yLmZyb21DdWJlbWFwKCB0ZXh0dXJlICk7XHJcblx0XHRcdFx0XHRcdFx0Y3ViZVVWbWFwcy5zZXQoIHRleHR1cmUsIHJlbmRlclRhcmdldCApO1xyXG5cclxuXHRcdFx0XHRcdFx0XHR0ZXh0dXJlLmFkZEV2ZW50TGlzdGVuZXIoICdkaXNwb3NlJywgb25UZXh0dXJlRGlzcG9zZSApO1xyXG5cclxuXHRcdFx0XHRcdFx0XHRyZXR1cm4gcmVuZGVyVGFyZ2V0LnRleHR1cmU7XHJcblxyXG5cdFx0XHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdFx0XHQvLyBpbWFnZSBub3QgeWV0IHJlYWR5LiB0cnkgdGhlIGNvbnZlcnNpb24gbmV4dCBmcmFtZVxyXG5cclxuXHRcdFx0XHRcdFx0XHRyZXR1cm4gbnVsbDtcclxuXHJcblx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRleHR1cmU7XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gaXNDdWJlVGV4dHVyZUNvbXBsZXRlKCBpbWFnZSApIHtcclxuXHJcblx0XHRsZXQgY291bnQgPSAwO1xyXG5cdFx0Y29uc3QgbGVuZ3RoID0gNjtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBsZW5ndGg7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRpZiAoIGltYWdlWyBpIF0gIT09IHVuZGVmaW5lZCApIGNvdW50ICsrO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gY291bnQgPT09IGxlbmd0aDtcclxuXHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gb25UZXh0dXJlRGlzcG9zZSggZXZlbnQgKSB7XHJcblxyXG5cdFx0Y29uc3QgdGV4dHVyZSA9IGV2ZW50LnRhcmdldDtcclxuXHJcblx0XHR0ZXh0dXJlLnJlbW92ZUV2ZW50TGlzdGVuZXIoICdkaXNwb3NlJywgb25UZXh0dXJlRGlzcG9zZSApO1xyXG5cclxuXHRcdGNvbnN0IGN1YmVtYXBVViA9IGN1YmVVVm1hcHMuZ2V0KCB0ZXh0dXJlICk7XHJcblxyXG5cdFx0aWYgKCBjdWJlbWFwVVYgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdGN1YmVVVm1hcHMuZGVsZXRlKCB0ZXh0dXJlICk7XHJcblx0XHRcdGN1YmVtYXBVVi5kaXNwb3NlKCk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIGRpc3Bvc2UoKSB7XHJcblxyXG5cdFx0Y3ViZVVWbWFwcyA9IG5ldyBXZWFrTWFwKCk7XHJcblxyXG5cdFx0aWYgKCBwbXJlbUdlbmVyYXRvciAhPT0gbnVsbCApIHtcclxuXHJcblx0XHRcdHBtcmVtR2VuZXJhdG9yLmRpc3Bvc2UoKTtcclxuXHRcdFx0cG1yZW1HZW5lcmF0b3IgPSBudWxsO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4ge1xyXG5cdFx0Z2V0OiBnZXQsXHJcblx0XHRkaXNwb3NlOiBkaXNwb3NlXHJcblx0fTtcclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IFdlYkdMQ3ViZVVWTWFwcyB9O1xyXG4iLCJmdW5jdGlvbiBXZWJHTEV4dGVuc2lvbnMoIGdsICkge1xyXG5cclxuXHRjb25zdCBleHRlbnNpb25zID0ge307XHJcblxyXG5cdGZ1bmN0aW9uIGdldEV4dGVuc2lvbiggbmFtZSApIHtcclxuXHJcblx0XHRpZiAoIGV4dGVuc2lvbnNbIG5hbWUgXSAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0cmV0dXJuIGV4dGVuc2lvbnNbIG5hbWUgXTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0bGV0IGV4dGVuc2lvbjtcclxuXHJcblx0XHRzd2l0Y2ggKCBuYW1lICkge1xyXG5cclxuXHRcdFx0Y2FzZSAnV0VCR0xfZGVwdGhfdGV4dHVyZSc6XHJcblx0XHRcdFx0ZXh0ZW5zaW9uID0gZ2wuZ2V0RXh0ZW5zaW9uKCAnV0VCR0xfZGVwdGhfdGV4dHVyZScgKSB8fCBnbC5nZXRFeHRlbnNpb24oICdNT1pfV0VCR0xfZGVwdGhfdGV4dHVyZScgKSB8fCBnbC5nZXRFeHRlbnNpb24oICdXRUJLSVRfV0VCR0xfZGVwdGhfdGV4dHVyZScgKTtcclxuXHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdGNhc2UgJ0VYVF90ZXh0dXJlX2ZpbHRlcl9hbmlzb3Ryb3BpYyc6XHJcblx0XHRcdFx0ZXh0ZW5zaW9uID0gZ2wuZ2V0RXh0ZW5zaW9uKCAnRVhUX3RleHR1cmVfZmlsdGVyX2FuaXNvdHJvcGljJyApIHx8IGdsLmdldEV4dGVuc2lvbiggJ01PWl9FWFRfdGV4dHVyZV9maWx0ZXJfYW5pc290cm9waWMnICkgfHwgZ2wuZ2V0RXh0ZW5zaW9uKCAnV0VCS0lUX0VYVF90ZXh0dXJlX2ZpbHRlcl9hbmlzb3Ryb3BpYycgKTtcclxuXHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdGNhc2UgJ1dFQkdMX2NvbXByZXNzZWRfdGV4dHVyZV9zM3RjJzpcclxuXHRcdFx0XHRleHRlbnNpb24gPSBnbC5nZXRFeHRlbnNpb24oICdXRUJHTF9jb21wcmVzc2VkX3RleHR1cmVfczN0YycgKSB8fCBnbC5nZXRFeHRlbnNpb24oICdNT1pfV0VCR0xfY29tcHJlc3NlZF90ZXh0dXJlX3MzdGMnICkgfHwgZ2wuZ2V0RXh0ZW5zaW9uKCAnV0VCS0lUX1dFQkdMX2NvbXByZXNzZWRfdGV4dHVyZV9zM3RjJyApO1xyXG5cdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0Y2FzZSAnV0VCR0xfY29tcHJlc3NlZF90ZXh0dXJlX3B2cnRjJzpcclxuXHRcdFx0XHRleHRlbnNpb24gPSBnbC5nZXRFeHRlbnNpb24oICdXRUJHTF9jb21wcmVzc2VkX3RleHR1cmVfcHZydGMnICkgfHwgZ2wuZ2V0RXh0ZW5zaW9uKCAnV0VCS0lUX1dFQkdMX2NvbXByZXNzZWRfdGV4dHVyZV9wdnJ0YycgKTtcclxuXHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdGRlZmF1bHQ6XHJcblx0XHRcdFx0ZXh0ZW5zaW9uID0gZ2wuZ2V0RXh0ZW5zaW9uKCBuYW1lICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGV4dGVuc2lvbnNbIG5hbWUgXSA9IGV4dGVuc2lvbjtcclxuXHJcblx0XHRyZXR1cm4gZXh0ZW5zaW9uO1xyXG5cclxuXHR9XHJcblxyXG5cdHJldHVybiB7XHJcblxyXG5cdFx0aGFzOiBmdW5jdGlvbiAoIG5hbWUgKSB7XHJcblxyXG5cdFx0XHRyZXR1cm4gZ2V0RXh0ZW5zaW9uKCBuYW1lICkgIT09IG51bGw7XHJcblxyXG5cdFx0fSxcclxuXHJcblx0XHRpbml0OiBmdW5jdGlvbiAoIGNhcGFiaWxpdGllcyApIHtcclxuXHJcblx0XHRcdGlmICggY2FwYWJpbGl0aWVzLmlzV2ViR0wyICkge1xyXG5cclxuXHRcdFx0XHRnZXRFeHRlbnNpb24oICdFWFRfY29sb3JfYnVmZmVyX2Zsb2F0JyApO1xyXG5cdFx0XHRcdGdldEV4dGVuc2lvbiggJ1dFQkdMX2NsaXBfY3VsbF9kaXN0YW5jZScgKTtcclxuXHJcblx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdGdldEV4dGVuc2lvbiggJ1dFQkdMX2RlcHRoX3RleHR1cmUnICk7XHJcblx0XHRcdFx0Z2V0RXh0ZW5zaW9uKCAnT0VTX3RleHR1cmVfZmxvYXQnICk7XHJcblx0XHRcdFx0Z2V0RXh0ZW5zaW9uKCAnT0VTX3RleHR1cmVfaGFsZl9mbG9hdCcgKTtcclxuXHRcdFx0XHRnZXRFeHRlbnNpb24oICdPRVNfdGV4dHVyZV9oYWxmX2Zsb2F0X2xpbmVhcicgKTtcclxuXHRcdFx0XHRnZXRFeHRlbnNpb24oICdPRVNfc3RhbmRhcmRfZGVyaXZhdGl2ZXMnICk7XHJcblx0XHRcdFx0Z2V0RXh0ZW5zaW9uKCAnT0VTX2VsZW1lbnRfaW5kZXhfdWludCcgKTtcclxuXHRcdFx0XHRnZXRFeHRlbnNpb24oICdPRVNfdmVydGV4X2FycmF5X29iamVjdCcgKTtcclxuXHRcdFx0XHRnZXRFeHRlbnNpb24oICdBTkdMRV9pbnN0YW5jZWRfYXJyYXlzJyApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Z2V0RXh0ZW5zaW9uKCAnT0VTX3RleHR1cmVfZmxvYXRfbGluZWFyJyApO1xyXG5cdFx0XHRnZXRFeHRlbnNpb24oICdFWFRfY29sb3JfYnVmZmVyX2hhbGZfZmxvYXQnICk7XHJcblx0XHRcdGdldEV4dGVuc2lvbiggJ1dFQkdMX211bHRpc2FtcGxlZF9yZW5kZXJfdG9fdGV4dHVyZScgKTtcclxuXHJcblx0XHR9LFxyXG5cclxuXHRcdGdldDogZnVuY3Rpb24gKCBuYW1lICkge1xyXG5cclxuXHRcdFx0Y29uc3QgZXh0ZW5zaW9uID0gZ2V0RXh0ZW5zaW9uKCBuYW1lICk7XHJcblxyXG5cdFx0XHRpZiAoIGV4dGVuc2lvbiA9PT0gbnVsbCApIHtcclxuXHJcblx0XHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuV2ViR0xSZW5kZXJlcjogJyArIG5hbWUgKyAnIGV4dGVuc2lvbiBub3Qgc3VwcG9ydGVkLicgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHJldHVybiBleHRlbnNpb247XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9O1xyXG5cclxufVxyXG5cclxuXHJcbmV4cG9ydCB7IFdlYkdMRXh0ZW5zaW9ucyB9O1xyXG4iLCJpbXBvcnQgeyBVaW50MTZCdWZmZXJBdHRyaWJ1dGUsIFVpbnQzMkJ1ZmZlckF0dHJpYnV0ZSB9IGZyb20gJy4uLy4uL2NvcmUvQnVmZmVyQXR0cmlidXRlLmpzJztcclxuaW1wb3J0IHsgYXJyYXlOZWVkc1VpbnQzMiB9IGZyb20gJy4uLy4uL3V0aWxzLmpzJztcclxuXHJcbmZ1bmN0aW9uIFdlYkdMR2VvbWV0cmllcyggZ2wsIGF0dHJpYnV0ZXMsIGluZm8sIGJpbmRpbmdTdGF0ZXMgKSB7XHJcblxyXG5cdGNvbnN0IGdlb21ldHJpZXMgPSB7fTtcclxuXHRjb25zdCB3aXJlZnJhbWVBdHRyaWJ1dGVzID0gbmV3IFdlYWtNYXAoKTtcclxuXHJcblx0ZnVuY3Rpb24gb25HZW9tZXRyeURpc3Bvc2UoIGV2ZW50ICkge1xyXG5cclxuXHRcdGNvbnN0IGdlb21ldHJ5ID0gZXZlbnQudGFyZ2V0O1xyXG5cclxuXHRcdGlmICggZ2VvbWV0cnkuaW5kZXggIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRhdHRyaWJ1dGVzLnJlbW92ZSggZ2VvbWV0cnkuaW5kZXggKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Zm9yICggY29uc3QgbmFtZSBpbiBnZW9tZXRyeS5hdHRyaWJ1dGVzICkge1xyXG5cclxuXHRcdFx0YXR0cmlidXRlcy5yZW1vdmUoIGdlb21ldHJ5LmF0dHJpYnV0ZXNbIG5hbWUgXSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRmb3IgKCBjb25zdCBuYW1lIGluIGdlb21ldHJ5Lm1vcnBoQXR0cmlidXRlcyApIHtcclxuXHJcblx0XHRcdGNvbnN0IGFycmF5ID0gZ2VvbWV0cnkubW9ycGhBdHRyaWJ1dGVzWyBuYW1lIF07XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBhcnJheS5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRhdHRyaWJ1dGVzLnJlbW92ZSggYXJyYXlbIGkgXSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRnZW9tZXRyeS5yZW1vdmVFdmVudExpc3RlbmVyKCAnZGlzcG9zZScsIG9uR2VvbWV0cnlEaXNwb3NlICk7XHJcblxyXG5cdFx0ZGVsZXRlIGdlb21ldHJpZXNbIGdlb21ldHJ5LmlkIF07XHJcblxyXG5cdFx0Y29uc3QgYXR0cmlidXRlID0gd2lyZWZyYW1lQXR0cmlidXRlcy5nZXQoIGdlb21ldHJ5ICk7XHJcblxyXG5cdFx0aWYgKCBhdHRyaWJ1dGUgKSB7XHJcblxyXG5cdFx0XHRhdHRyaWJ1dGVzLnJlbW92ZSggYXR0cmlidXRlICk7XHJcblx0XHRcdHdpcmVmcmFtZUF0dHJpYnV0ZXMuZGVsZXRlKCBnZW9tZXRyeSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRiaW5kaW5nU3RhdGVzLnJlbGVhc2VTdGF0ZXNPZkdlb21ldHJ5KCBnZW9tZXRyeSApO1xyXG5cclxuXHRcdGlmICggZ2VvbWV0cnkuaXNJbnN0YW5jZWRCdWZmZXJHZW9tZXRyeSA9PT0gdHJ1ZSApIHtcclxuXHJcblx0XHRcdGRlbGV0ZSBnZW9tZXRyeS5fbWF4SW5zdGFuY2VDb3VudDtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly9cclxuXHJcblx0XHRpbmZvLm1lbW9yeS5nZW9tZXRyaWVzIC0tO1xyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIGdldCggb2JqZWN0LCBnZW9tZXRyeSApIHtcclxuXHJcblx0XHRpZiAoIGdlb21ldHJpZXNbIGdlb21ldHJ5LmlkIF0gPT09IHRydWUgKSByZXR1cm4gZ2VvbWV0cnk7XHJcblxyXG5cdFx0Z2VvbWV0cnkuYWRkRXZlbnRMaXN0ZW5lciggJ2Rpc3Bvc2UnLCBvbkdlb21ldHJ5RGlzcG9zZSApO1xyXG5cclxuXHRcdGdlb21ldHJpZXNbIGdlb21ldHJ5LmlkIF0gPSB0cnVlO1xyXG5cclxuXHRcdGluZm8ubWVtb3J5Lmdlb21ldHJpZXMgKys7XHJcblxyXG5cdFx0cmV0dXJuIGdlb21ldHJ5O1xyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHVwZGF0ZSggZ2VvbWV0cnkgKSB7XHJcblxyXG5cdFx0Y29uc3QgZ2VvbWV0cnlBdHRyaWJ1dGVzID0gZ2VvbWV0cnkuYXR0cmlidXRlcztcclxuXHJcblx0XHQvLyBVcGRhdGluZyBpbmRleCBidWZmZXIgaW4gVkFPIG5vdy4gU2VlIFdlYkdMQmluZGluZ1N0YXRlcy5cclxuXHJcblx0XHRmb3IgKCBjb25zdCBuYW1lIGluIGdlb21ldHJ5QXR0cmlidXRlcyApIHtcclxuXHJcblx0XHRcdGF0dHJpYnV0ZXMudXBkYXRlKCBnZW9tZXRyeUF0dHJpYnV0ZXNbIG5hbWUgXSwgZ2wuQVJSQVlfQlVGRkVSICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIG1vcnBoIHRhcmdldHNcclxuXHJcblx0XHRjb25zdCBtb3JwaEF0dHJpYnV0ZXMgPSBnZW9tZXRyeS5tb3JwaEF0dHJpYnV0ZXM7XHJcblxyXG5cdFx0Zm9yICggY29uc3QgbmFtZSBpbiBtb3JwaEF0dHJpYnV0ZXMgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBhcnJheSA9IG1vcnBoQXR0cmlidXRlc1sgbmFtZSBdO1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gYXJyYXkubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0YXR0cmlidXRlcy51cGRhdGUoIGFycmF5WyBpIF0sIGdsLkFSUkFZX0JVRkZFUiApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiB1cGRhdGVXaXJlZnJhbWVBdHRyaWJ1dGUoIGdlb21ldHJ5ICkge1xyXG5cclxuXHRcdGNvbnN0IGluZGljZXMgPSBbXTtcclxuXHJcblx0XHRjb25zdCBnZW9tZXRyeUluZGV4ID0gZ2VvbWV0cnkuaW5kZXg7XHJcblx0XHRjb25zdCBnZW9tZXRyeVBvc2l0aW9uID0gZ2VvbWV0cnkuYXR0cmlidXRlcy5wb3NpdGlvbjtcclxuXHRcdGxldCB2ZXJzaW9uID0gMDtcclxuXHJcblx0XHRpZiAoIGdlb21ldHJ5SW5kZXggIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBhcnJheSA9IGdlb21ldHJ5SW5kZXguYXJyYXk7XHJcblx0XHRcdHZlcnNpb24gPSBnZW9tZXRyeUluZGV4LnZlcnNpb247XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBhcnJheS5sZW5ndGg7IGkgPCBsOyBpICs9IDMgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IGEgPSBhcnJheVsgaSArIDAgXTtcclxuXHRcdFx0XHRjb25zdCBiID0gYXJyYXlbIGkgKyAxIF07XHJcblx0XHRcdFx0Y29uc3QgYyA9IGFycmF5WyBpICsgMiBdO1xyXG5cclxuXHRcdFx0XHRpbmRpY2VzLnB1c2goIGEsIGIsIGIsIGMsIGMsIGEgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9IGVsc2UgaWYgKCBnZW9tZXRyeVBvc2l0aW9uICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBhcnJheSA9IGdlb21ldHJ5UG9zaXRpb24uYXJyYXk7XHJcblx0XHRcdHZlcnNpb24gPSBnZW9tZXRyeVBvc2l0aW9uLnZlcnNpb247XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSAoIGFycmF5Lmxlbmd0aCAvIDMgKSAtIDE7IGkgPCBsOyBpICs9IDMgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IGEgPSBpICsgMDtcclxuXHRcdFx0XHRjb25zdCBiID0gaSArIDE7XHJcblx0XHRcdFx0Y29uc3QgYyA9IGkgKyAyO1xyXG5cclxuXHRcdFx0XHRpbmRpY2VzLnB1c2goIGEsIGIsIGIsIGMsIGMsIGEgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0cmV0dXJuO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCBhdHRyaWJ1dGUgPSBuZXcgKCBhcnJheU5lZWRzVWludDMyKCBpbmRpY2VzICkgPyBVaW50MzJCdWZmZXJBdHRyaWJ1dGUgOiBVaW50MTZCdWZmZXJBdHRyaWJ1dGUgKSggaW5kaWNlcywgMSApO1xyXG5cdFx0YXR0cmlidXRlLnZlcnNpb24gPSB2ZXJzaW9uO1xyXG5cclxuXHRcdC8vIFVwZGF0aW5nIGluZGV4IGJ1ZmZlciBpbiBWQU8gbm93LiBTZWUgV2ViR0xCaW5kaW5nU3RhdGVzXHJcblxyXG5cdFx0Ly9cclxuXHJcblx0XHRjb25zdCBwcmV2aW91c0F0dHJpYnV0ZSA9IHdpcmVmcmFtZUF0dHJpYnV0ZXMuZ2V0KCBnZW9tZXRyeSApO1xyXG5cclxuXHRcdGlmICggcHJldmlvdXNBdHRyaWJ1dGUgKSBhdHRyaWJ1dGVzLnJlbW92ZSggcHJldmlvdXNBdHRyaWJ1dGUgKTtcclxuXHJcblx0XHQvL1xyXG5cclxuXHRcdHdpcmVmcmFtZUF0dHJpYnV0ZXMuc2V0KCBnZW9tZXRyeSwgYXR0cmlidXRlICk7XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gZ2V0V2lyZWZyYW1lQXR0cmlidXRlKCBnZW9tZXRyeSApIHtcclxuXHJcblx0XHRjb25zdCBjdXJyZW50QXR0cmlidXRlID0gd2lyZWZyYW1lQXR0cmlidXRlcy5nZXQoIGdlb21ldHJ5ICk7XHJcblxyXG5cdFx0aWYgKCBjdXJyZW50QXR0cmlidXRlICkge1xyXG5cclxuXHRcdFx0Y29uc3QgZ2VvbWV0cnlJbmRleCA9IGdlb21ldHJ5LmluZGV4O1xyXG5cclxuXHRcdFx0aWYgKCBnZW9tZXRyeUluZGV4ICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0XHQvLyBpZiB0aGUgYXR0cmlidXRlIGlzIG9ic29sZXRlLCBjcmVhdGUgYSBuZXcgb25lXHJcblxyXG5cdFx0XHRcdGlmICggY3VycmVudEF0dHJpYnV0ZS52ZXJzaW9uIDwgZ2VvbWV0cnlJbmRleC52ZXJzaW9uICkge1xyXG5cclxuXHRcdFx0XHRcdHVwZGF0ZVdpcmVmcmFtZUF0dHJpYnV0ZSggZ2VvbWV0cnkgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHR1cGRhdGVXaXJlZnJhbWVBdHRyaWJ1dGUoIGdlb21ldHJ5ICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB3aXJlZnJhbWVBdHRyaWJ1dGVzLmdldCggZ2VvbWV0cnkgKTtcclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4ge1xyXG5cclxuXHRcdGdldDogZ2V0LFxyXG5cdFx0dXBkYXRlOiB1cGRhdGUsXHJcblxyXG5cdFx0Z2V0V2lyZWZyYW1lQXR0cmlidXRlOiBnZXRXaXJlZnJhbWVBdHRyaWJ1dGVcclxuXHJcblx0fTtcclxuXHJcbn1cclxuXHJcblxyXG5leHBvcnQgeyBXZWJHTEdlb21ldHJpZXMgfTtcclxuIiwiZnVuY3Rpb24gV2ViR0xJbmRleGVkQnVmZmVyUmVuZGVyZXIoIGdsLCBleHRlbnNpb25zLCBpbmZvLCBjYXBhYmlsaXRpZXMgKSB7XHJcblxyXG5cdGNvbnN0IGlzV2ViR0wyID0gY2FwYWJpbGl0aWVzLmlzV2ViR0wyO1xyXG5cclxuXHRsZXQgbW9kZTtcclxuXHJcblx0ZnVuY3Rpb24gc2V0TW9kZSggdmFsdWUgKSB7XHJcblxyXG5cdFx0bW9kZSA9IHZhbHVlO1xyXG5cclxuXHR9XHJcblxyXG5cdGxldCB0eXBlLCBieXRlc1BlckVsZW1lbnQ7XHJcblxyXG5cdGZ1bmN0aW9uIHNldEluZGV4KCB2YWx1ZSApIHtcclxuXHJcblx0XHR0eXBlID0gdmFsdWUudHlwZTtcclxuXHRcdGJ5dGVzUGVyRWxlbWVudCA9IHZhbHVlLmJ5dGVzUGVyRWxlbWVudDtcclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiByZW5kZXIoIHN0YXJ0LCBjb3VudCApIHtcclxuXHJcblx0XHRnbC5kcmF3RWxlbWVudHMoIG1vZGUsIGNvdW50LCB0eXBlLCBzdGFydCAqIGJ5dGVzUGVyRWxlbWVudCApO1xyXG5cclxuXHRcdGluZm8udXBkYXRlKCBjb3VudCwgbW9kZSwgMSApO1xyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHJlbmRlckluc3RhbmNlcyggc3RhcnQsIGNvdW50LCBwcmltY291bnQgKSB7XHJcblxyXG5cdFx0aWYgKCBwcmltY291bnQgPT09IDAgKSByZXR1cm47XHJcblxyXG5cdFx0bGV0IGV4dGVuc2lvbiwgbWV0aG9kTmFtZTtcclxuXHJcblx0XHRpZiAoIGlzV2ViR0wyICkge1xyXG5cclxuXHRcdFx0ZXh0ZW5zaW9uID0gZ2w7XHJcblx0XHRcdG1ldGhvZE5hbWUgPSAnZHJhd0VsZW1lbnRzSW5zdGFuY2VkJztcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0ZXh0ZW5zaW9uID0gZXh0ZW5zaW9ucy5nZXQoICdBTkdMRV9pbnN0YW5jZWRfYXJyYXlzJyApO1xyXG5cdFx0XHRtZXRob2ROYW1lID0gJ2RyYXdFbGVtZW50c0luc3RhbmNlZEFOR0xFJztcclxuXHJcblx0XHRcdGlmICggZXh0ZW5zaW9uID09PSBudWxsICkge1xyXG5cclxuXHRcdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuV2ViR0xJbmRleGVkQnVmZmVyUmVuZGVyZXI6IHVzaW5nIFRIUkVFLkluc3RhbmNlZEJ1ZmZlckdlb21ldHJ5IGJ1dCBoYXJkd2FyZSBkb2VzIG5vdCBzdXBwb3J0IGV4dGVuc2lvbiBBTkdMRV9pbnN0YW5jZWRfYXJyYXlzLicgKTtcclxuXHRcdFx0XHRyZXR1cm47XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGV4dGVuc2lvblsgbWV0aG9kTmFtZSBdKCBtb2RlLCBjb3VudCwgdHlwZSwgc3RhcnQgKiBieXRlc1BlckVsZW1lbnQsIHByaW1jb3VudCApO1xyXG5cclxuXHRcdGluZm8udXBkYXRlKCBjb3VudCwgbW9kZSwgcHJpbWNvdW50ICk7XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gcmVuZGVyTXVsdGlEcmF3KCBzdGFydHMsIGNvdW50cywgZHJhd0NvdW50ICkge1xyXG5cclxuXHRcdGlmICggZHJhd0NvdW50ID09PSAwICkgcmV0dXJuO1xyXG5cclxuXHRcdGNvbnN0IGV4dGVuc2lvbiA9IGV4dGVuc2lvbnMuZ2V0KCAnV0VCR0xfbXVsdGlfZHJhdycgKTtcclxuXHRcdGlmICggZXh0ZW5zaW9uID09PSBudWxsICkge1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgZHJhd0NvdW50OyBpICsrICkge1xyXG5cclxuXHRcdFx0XHR0aGlzLnJlbmRlciggc3RhcnRzWyBpIF0gLyBieXRlc1BlckVsZW1lbnQsIGNvdW50c1sgaSBdICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdGV4dGVuc2lvbi5tdWx0aURyYXdFbGVtZW50c1dFQkdMKCBtb2RlLCBjb3VudHMsIDAsIHR5cGUsIHN0YXJ0cywgMCwgZHJhd0NvdW50ICk7XHJcblxyXG5cdFx0XHRsZXQgZWxlbWVudENvdW50ID0gMDtcclxuXHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgZHJhd0NvdW50OyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRlbGVtZW50Q291bnQgKz0gY291bnRzWyBpIF07XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRpbmZvLnVwZGF0ZSggZWxlbWVudENvdW50LCBtb2RlLCAxICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdC8vXHJcblxyXG5cdHRoaXMuc2V0TW9kZSA9IHNldE1vZGU7XHJcblx0dGhpcy5zZXRJbmRleCA9IHNldEluZGV4O1xyXG5cdHRoaXMucmVuZGVyID0gcmVuZGVyO1xyXG5cdHRoaXMucmVuZGVySW5zdGFuY2VzID0gcmVuZGVySW5zdGFuY2VzO1xyXG5cdHRoaXMucmVuZGVyTXVsdGlEcmF3ID0gcmVuZGVyTXVsdGlEcmF3O1xyXG5cclxufVxyXG5cclxuXHJcbmV4cG9ydCB7IFdlYkdMSW5kZXhlZEJ1ZmZlclJlbmRlcmVyIH07XHJcbiIsImZ1bmN0aW9uIFdlYkdMSW5mbyggZ2wgKSB7XHJcblxyXG5cdGNvbnN0IG1lbW9yeSA9IHtcclxuXHRcdGdlb21ldHJpZXM6IDAsXHJcblx0XHR0ZXh0dXJlczogMFxyXG5cdH07XHJcblxyXG5cdGNvbnN0IHJlbmRlciA9IHtcclxuXHRcdGZyYW1lOiAwLFxyXG5cdFx0Y2FsbHM6IDAsXHJcblx0XHR0cmlhbmdsZXM6IDAsXHJcblx0XHRwb2ludHM6IDAsXHJcblx0XHRsaW5lczogMFxyXG5cdH07XHJcblxyXG5cdGZ1bmN0aW9uIHVwZGF0ZSggY291bnQsIG1vZGUsIGluc3RhbmNlQ291bnQgKSB7XHJcblxyXG5cdFx0cmVuZGVyLmNhbGxzICsrO1xyXG5cclxuXHRcdHN3aXRjaCAoIG1vZGUgKSB7XHJcblxyXG5cdFx0XHRjYXNlIGdsLlRSSUFOR0xFUzpcclxuXHRcdFx0XHRyZW5kZXIudHJpYW5nbGVzICs9IGluc3RhbmNlQ291bnQgKiAoIGNvdW50IC8gMyApO1xyXG5cdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0Y2FzZSBnbC5MSU5FUzpcclxuXHRcdFx0XHRyZW5kZXIubGluZXMgKz0gaW5zdGFuY2VDb3VudCAqICggY291bnQgLyAyICk7XHJcblx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRjYXNlIGdsLkxJTkVfU1RSSVA6XHJcblx0XHRcdFx0cmVuZGVyLmxpbmVzICs9IGluc3RhbmNlQ291bnQgKiAoIGNvdW50IC0gMSApO1xyXG5cdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0Y2FzZSBnbC5MSU5FX0xPT1A6XHJcblx0XHRcdFx0cmVuZGVyLmxpbmVzICs9IGluc3RhbmNlQ291bnQgKiBjb3VudDtcclxuXHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdGNhc2UgZ2wuUE9JTlRTOlxyXG5cdFx0XHRcdHJlbmRlci5wb2ludHMgKz0gaW5zdGFuY2VDb3VudCAqIGNvdW50O1xyXG5cdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0ZGVmYXVsdDpcclxuXHRcdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuV2ViR0xJbmZvOiBVbmtub3duIGRyYXcgbW9kZTonLCBtb2RlICk7XHJcblx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHJlc2V0KCkge1xyXG5cclxuXHRcdHJlbmRlci5jYWxscyA9IDA7XHJcblx0XHRyZW5kZXIudHJpYW5nbGVzID0gMDtcclxuXHRcdHJlbmRlci5wb2ludHMgPSAwO1xyXG5cdFx0cmVuZGVyLmxpbmVzID0gMDtcclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4ge1xyXG5cdFx0bWVtb3J5OiBtZW1vcnksXHJcblx0XHRyZW5kZXI6IHJlbmRlcixcclxuXHRcdHByb2dyYW1zOiBudWxsLFxyXG5cdFx0YXV0b1Jlc2V0OiB0cnVlLFxyXG5cdFx0cmVzZXQ6IHJlc2V0LFxyXG5cdFx0dXBkYXRlOiB1cGRhdGVcclxuXHR9O1xyXG5cclxufVxyXG5cclxuXHJcbmV4cG9ydCB7IFdlYkdMSW5mbyB9O1xyXG4iLCJpbXBvcnQgeyBGbG9hdFR5cGUgfSBmcm9tICcuLi8uLi9jb25zdGFudHMuanMnO1xyXG5pbXBvcnQgeyBEYXRhQXJyYXlUZXh0dXJlIH0gZnJvbSAnLi4vLi4vdGV4dHVyZXMvRGF0YUFycmF5VGV4dHVyZS5qcyc7XHJcbmltcG9ydCB7IFZlY3RvcjQgfSBmcm9tICcuLi8uLi9tYXRoL1ZlY3RvcjQuanMnO1xyXG5pbXBvcnQgeyBWZWN0b3IyIH0gZnJvbSAnLi4vLi4vbWF0aC9WZWN0b3IyLmpzJztcclxuXHJcbmZ1bmN0aW9uIG51bWVyaWNhbFNvcnQoIGEsIGIgKSB7XHJcblxyXG5cdHJldHVybiBhWyAwIF0gLSBiWyAwIF07XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiBhYnNOdW1lcmljYWxTb3J0KCBhLCBiICkge1xyXG5cclxuXHRyZXR1cm4gTWF0aC5hYnMoIGJbIDEgXSApIC0gTWF0aC5hYnMoIGFbIDEgXSApO1xyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gV2ViR0xNb3JwaHRhcmdldHMoIGdsLCBjYXBhYmlsaXRpZXMsIHRleHR1cmVzICkge1xyXG5cclxuXHRjb25zdCBpbmZsdWVuY2VzTGlzdCA9IHt9O1xyXG5cdGNvbnN0IG1vcnBoSW5mbHVlbmNlcyA9IG5ldyBGbG9hdDMyQXJyYXkoIDggKTtcclxuXHRjb25zdCBtb3JwaFRleHR1cmVzID0gbmV3IFdlYWtNYXAoKTtcclxuXHRjb25zdCBtb3JwaCA9IG5ldyBWZWN0b3I0KCk7XHJcblxyXG5cdGNvbnN0IHdvcmtJbmZsdWVuY2VzID0gW107XHJcblxyXG5cdGZvciAoIGxldCBpID0gMDsgaSA8IDg7IGkgKysgKSB7XHJcblxyXG5cdFx0d29ya0luZmx1ZW5jZXNbIGkgXSA9IFsgaSwgMCBdO1xyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHVwZGF0ZSggb2JqZWN0LCBnZW9tZXRyeSwgcHJvZ3JhbSApIHtcclxuXHJcblx0XHRjb25zdCBvYmplY3RJbmZsdWVuY2VzID0gb2JqZWN0Lm1vcnBoVGFyZ2V0SW5mbHVlbmNlcztcclxuXHJcblx0XHRpZiAoIGNhcGFiaWxpdGllcy5pc1dlYkdMMiA9PT0gdHJ1ZSApIHtcclxuXHJcblx0XHRcdC8vIGluc3RlYWQgb2YgdXNpbmcgYXR0cmlidXRlcywgdGhlIFdlYkdMIDIgY29kZSBwYXRoIGVuY29kZXMgbW9ycGggdGFyZ2V0c1xyXG5cdFx0XHQvLyBpbnRvIGFuIGFycmF5IG9mIGRhdGEgdGV4dHVyZXMuIEVhY2ggbGF5ZXIgcmVwcmVzZW50cyBhIHNpbmdsZSBtb3JwaCB0YXJnZXQuXHJcblxyXG5cdFx0XHRjb25zdCBtb3JwaEF0dHJpYnV0ZSA9IGdlb21ldHJ5Lm1vcnBoQXR0cmlidXRlcy5wb3NpdGlvbiB8fCBnZW9tZXRyeS5tb3JwaEF0dHJpYnV0ZXMubm9ybWFsIHx8IGdlb21ldHJ5Lm1vcnBoQXR0cmlidXRlcy5jb2xvcjtcclxuXHRcdFx0Y29uc3QgbW9ycGhUYXJnZXRzQ291bnQgPSAoIG1vcnBoQXR0cmlidXRlICE9PSB1bmRlZmluZWQgKSA/IG1vcnBoQXR0cmlidXRlLmxlbmd0aCA6IDA7XHJcblxyXG5cdFx0XHRsZXQgZW50cnkgPSBtb3JwaFRleHR1cmVzLmdldCggZ2VvbWV0cnkgKTtcclxuXHJcblx0XHRcdGlmICggZW50cnkgPT09IHVuZGVmaW5lZCB8fCBlbnRyeS5jb3VudCAhPT0gbW9ycGhUYXJnZXRzQ291bnQgKSB7XHJcblxyXG5cdFx0XHRcdGlmICggZW50cnkgIT09IHVuZGVmaW5lZCApIGVudHJ5LnRleHR1cmUuZGlzcG9zZSgpO1xyXG5cclxuXHRcdFx0XHRjb25zdCBoYXNNb3JwaFBvc2l0aW9uID0gZ2VvbWV0cnkubW9ycGhBdHRyaWJ1dGVzLnBvc2l0aW9uICE9PSB1bmRlZmluZWQ7XHJcblx0XHRcdFx0Y29uc3QgaGFzTW9ycGhOb3JtYWxzID0gZ2VvbWV0cnkubW9ycGhBdHRyaWJ1dGVzLm5vcm1hbCAhPT0gdW5kZWZpbmVkO1xyXG5cdFx0XHRcdGNvbnN0IGhhc01vcnBoQ29sb3JzID0gZ2VvbWV0cnkubW9ycGhBdHRyaWJ1dGVzLmNvbG9yICE9PSB1bmRlZmluZWQ7XHJcblxyXG5cdFx0XHRcdGNvbnN0IG1vcnBoVGFyZ2V0cyA9IGdlb21ldHJ5Lm1vcnBoQXR0cmlidXRlcy5wb3NpdGlvbiB8fCBbXTtcclxuXHRcdFx0XHRjb25zdCBtb3JwaE5vcm1hbHMgPSBnZW9tZXRyeS5tb3JwaEF0dHJpYnV0ZXMubm9ybWFsIHx8IFtdO1xyXG5cdFx0XHRcdGNvbnN0IG1vcnBoQ29sb3JzID0gZ2VvbWV0cnkubW9ycGhBdHRyaWJ1dGVzLmNvbG9yIHx8IFtdO1xyXG5cclxuXHRcdFx0XHRsZXQgdmVydGV4RGF0YUNvdW50ID0gMDtcclxuXHJcblx0XHRcdFx0aWYgKCBoYXNNb3JwaFBvc2l0aW9uID09PSB0cnVlICkgdmVydGV4RGF0YUNvdW50ID0gMTtcclxuXHRcdFx0XHRpZiAoIGhhc01vcnBoTm9ybWFscyA9PT0gdHJ1ZSApIHZlcnRleERhdGFDb3VudCA9IDI7XHJcblx0XHRcdFx0aWYgKCBoYXNNb3JwaENvbG9ycyA9PT0gdHJ1ZSApIHZlcnRleERhdGFDb3VudCA9IDM7XHJcblxyXG5cdFx0XHRcdGxldCB3aWR0aCA9IGdlb21ldHJ5LmF0dHJpYnV0ZXMucG9zaXRpb24uY291bnQgKiB2ZXJ0ZXhEYXRhQ291bnQ7XHJcblx0XHRcdFx0bGV0IGhlaWdodCA9IDE7XHJcblxyXG5cdFx0XHRcdGlmICggd2lkdGggPiBjYXBhYmlsaXRpZXMubWF4VGV4dHVyZVNpemUgKSB7XHJcblxyXG5cdFx0XHRcdFx0aGVpZ2h0ID0gTWF0aC5jZWlsKCB3aWR0aCAvIGNhcGFiaWxpdGllcy5tYXhUZXh0dXJlU2l6ZSApO1xyXG5cdFx0XHRcdFx0d2lkdGggPSBjYXBhYmlsaXRpZXMubWF4VGV4dHVyZVNpemU7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0Y29uc3QgYnVmZmVyID0gbmV3IEZsb2F0MzJBcnJheSggd2lkdGggKiBoZWlnaHQgKiA0ICogbW9ycGhUYXJnZXRzQ291bnQgKTtcclxuXHJcblx0XHRcdFx0Y29uc3QgdGV4dHVyZSA9IG5ldyBEYXRhQXJyYXlUZXh0dXJlKCBidWZmZXIsIHdpZHRoLCBoZWlnaHQsIG1vcnBoVGFyZ2V0c0NvdW50ICk7XHJcblx0XHRcdFx0dGV4dHVyZS50eXBlID0gRmxvYXRUeXBlO1xyXG5cdFx0XHRcdHRleHR1cmUubmVlZHNVcGRhdGUgPSB0cnVlO1xyXG5cclxuXHRcdFx0XHQvLyBmaWxsIGJ1ZmZlclxyXG5cclxuXHRcdFx0XHRjb25zdCB2ZXJ0ZXhEYXRhU3RyaWRlID0gdmVydGV4RGF0YUNvdW50ICogNDtcclxuXHJcblx0XHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgbW9ycGhUYXJnZXRzQ291bnQ7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgbW9ycGhUYXJnZXQgPSBtb3JwaFRhcmdldHNbIGkgXTtcclxuXHRcdFx0XHRcdGNvbnN0IG1vcnBoTm9ybWFsID0gbW9ycGhOb3JtYWxzWyBpIF07XHJcblx0XHRcdFx0XHRjb25zdCBtb3JwaENvbG9yID0gbW9ycGhDb2xvcnNbIGkgXTtcclxuXHJcblx0XHRcdFx0XHRjb25zdCBvZmZzZXQgPSB3aWR0aCAqIGhlaWdodCAqIDQgKiBpO1xyXG5cclxuXHRcdFx0XHRcdGZvciAoIGxldCBqID0gMDsgaiA8IG1vcnBoVGFyZ2V0LmNvdW50OyBqICsrICkge1xyXG5cclxuXHRcdFx0XHRcdFx0Y29uc3Qgc3RyaWRlID0gaiAqIHZlcnRleERhdGFTdHJpZGU7XHJcblxyXG5cdFx0XHRcdFx0XHRpZiAoIGhhc01vcnBoUG9zaXRpb24gPT09IHRydWUgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdG1vcnBoLmZyb21CdWZmZXJBdHRyaWJ1dGUoIG1vcnBoVGFyZ2V0LCBqICk7XHJcblxyXG5cdFx0XHRcdFx0XHRcdGJ1ZmZlclsgb2Zmc2V0ICsgc3RyaWRlICsgMCBdID0gbW9ycGgueDtcclxuXHRcdFx0XHRcdFx0XHRidWZmZXJbIG9mZnNldCArIHN0cmlkZSArIDEgXSA9IG1vcnBoLnk7XHJcblx0XHRcdFx0XHRcdFx0YnVmZmVyWyBvZmZzZXQgKyBzdHJpZGUgKyAyIF0gPSBtb3JwaC56O1xyXG5cdFx0XHRcdFx0XHRcdGJ1ZmZlclsgb2Zmc2V0ICsgc3RyaWRlICsgMyBdID0gMDtcclxuXHJcblx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRcdGlmICggaGFzTW9ycGhOb3JtYWxzID09PSB0cnVlICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRtb3JwaC5mcm9tQnVmZmVyQXR0cmlidXRlKCBtb3JwaE5vcm1hbCwgaiApO1xyXG5cclxuXHRcdFx0XHRcdFx0XHRidWZmZXJbIG9mZnNldCArIHN0cmlkZSArIDQgXSA9IG1vcnBoLng7XHJcblx0XHRcdFx0XHRcdFx0YnVmZmVyWyBvZmZzZXQgKyBzdHJpZGUgKyA1IF0gPSBtb3JwaC55O1xyXG5cdFx0XHRcdFx0XHRcdGJ1ZmZlclsgb2Zmc2V0ICsgc3RyaWRlICsgNiBdID0gbW9ycGguejtcclxuXHRcdFx0XHRcdFx0XHRidWZmZXJbIG9mZnNldCArIHN0cmlkZSArIDcgXSA9IDA7XHJcblxyXG5cdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0XHRpZiAoIGhhc01vcnBoQ29sb3JzID09PSB0cnVlICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRtb3JwaC5mcm9tQnVmZmVyQXR0cmlidXRlKCBtb3JwaENvbG9yLCBqICk7XHJcblxyXG5cdFx0XHRcdFx0XHRcdGJ1ZmZlclsgb2Zmc2V0ICsgc3RyaWRlICsgOCBdID0gbW9ycGgueDtcclxuXHRcdFx0XHRcdFx0XHRidWZmZXJbIG9mZnNldCArIHN0cmlkZSArIDkgXSA9IG1vcnBoLnk7XHJcblx0XHRcdFx0XHRcdFx0YnVmZmVyWyBvZmZzZXQgKyBzdHJpZGUgKyAxMCBdID0gbW9ycGguejtcclxuXHRcdFx0XHRcdFx0XHRidWZmZXJbIG9mZnNldCArIHN0cmlkZSArIDExIF0gPSAoIG1vcnBoQ29sb3IuaXRlbVNpemUgPT09IDQgKSA/IG1vcnBoLncgOiAxO1xyXG5cclxuXHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRlbnRyeSA9IHtcclxuXHRcdFx0XHRcdGNvdW50OiBtb3JwaFRhcmdldHNDb3VudCxcclxuXHRcdFx0XHRcdHRleHR1cmU6IHRleHR1cmUsXHJcblx0XHRcdFx0XHRzaXplOiBuZXcgVmVjdG9yMiggd2lkdGgsIGhlaWdodCApXHJcblx0XHRcdFx0fTtcclxuXHJcblx0XHRcdFx0bW9ycGhUZXh0dXJlcy5zZXQoIGdlb21ldHJ5LCBlbnRyeSApO1xyXG5cclxuXHRcdFx0XHRmdW5jdGlvbiBkaXNwb3NlVGV4dHVyZSgpIHtcclxuXHJcblx0XHRcdFx0XHR0ZXh0dXJlLmRpc3Bvc2UoKTtcclxuXHJcblx0XHRcdFx0XHRtb3JwaFRleHR1cmVzLmRlbGV0ZSggZ2VvbWV0cnkgKTtcclxuXHJcblx0XHRcdFx0XHRnZW9tZXRyeS5yZW1vdmVFdmVudExpc3RlbmVyKCAnZGlzcG9zZScsIGRpc3Bvc2VUZXh0dXJlICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0Z2VvbWV0cnkuYWRkRXZlbnRMaXN0ZW5lciggJ2Rpc3Bvc2UnLCBkaXNwb3NlVGV4dHVyZSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Ly9cclxuXHJcblx0XHRcdGxldCBtb3JwaEluZmx1ZW5jZXNTdW0gPSAwO1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgb2JqZWN0SW5mbHVlbmNlcy5sZW5ndGg7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdG1vcnBoSW5mbHVlbmNlc1N1bSArPSBvYmplY3RJbmZsdWVuY2VzWyBpIF07XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRjb25zdCBtb3JwaEJhc2VJbmZsdWVuY2UgPSBnZW9tZXRyeS5tb3JwaFRhcmdldHNSZWxhdGl2ZSA/IDEgOiAxIC0gbW9ycGhJbmZsdWVuY2VzU3VtO1xyXG5cclxuXHRcdFx0cHJvZ3JhbS5nZXRVbmlmb3JtcygpLnNldFZhbHVlKCBnbCwgJ21vcnBoVGFyZ2V0QmFzZUluZmx1ZW5jZScsIG1vcnBoQmFzZUluZmx1ZW5jZSApO1xyXG5cdFx0XHRwcm9ncmFtLmdldFVuaWZvcm1zKCkuc2V0VmFsdWUoIGdsLCAnbW9ycGhUYXJnZXRJbmZsdWVuY2VzJywgb2JqZWN0SW5mbHVlbmNlcyApO1xyXG5cclxuXHRcdFx0cHJvZ3JhbS5nZXRVbmlmb3JtcygpLnNldFZhbHVlKCBnbCwgJ21vcnBoVGFyZ2V0c1RleHR1cmUnLCBlbnRyeS50ZXh0dXJlLCB0ZXh0dXJlcyApO1xyXG5cdFx0XHRwcm9ncmFtLmdldFVuaWZvcm1zKCkuc2V0VmFsdWUoIGdsLCAnbW9ycGhUYXJnZXRzVGV4dHVyZVNpemUnLCBlbnRyeS5zaXplICk7XHJcblxyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHQvLyBXaGVuIG9iamVjdCBkb2Vzbid0IGhhdmUgbW9ycGggdGFyZ2V0IGluZmx1ZW5jZXMgZGVmaW5lZCwgd2UgdHJlYXQgaXQgYXMgYSAwLWxlbmd0aCBhcnJheVxyXG5cdFx0XHQvLyBUaGlzIGlzIGltcG9ydGFudCB0byBtYWtlIHN1cmUgd2Ugc2V0IHVwIG1vcnBoVGFyZ2V0QmFzZUluZmx1ZW5jZSAvIG1vcnBoVGFyZ2V0SW5mbHVlbmNlc1xyXG5cclxuXHRcdFx0Y29uc3QgbGVuZ3RoID0gb2JqZWN0SW5mbHVlbmNlcyA9PT0gdW5kZWZpbmVkID8gMCA6IG9iamVjdEluZmx1ZW5jZXMubGVuZ3RoO1xyXG5cclxuXHRcdFx0bGV0IGluZmx1ZW5jZXMgPSBpbmZsdWVuY2VzTGlzdFsgZ2VvbWV0cnkuaWQgXTtcclxuXHJcblx0XHRcdGlmICggaW5mbHVlbmNlcyA9PT0gdW5kZWZpbmVkIHx8IGluZmx1ZW5jZXMubGVuZ3RoICE9PSBsZW5ndGggKSB7XHJcblxyXG5cdFx0XHRcdC8vIGluaXRpYWxpc2UgbGlzdFxyXG5cclxuXHRcdFx0XHRpbmZsdWVuY2VzID0gW107XHJcblxyXG5cdFx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IGxlbmd0aDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0XHRpbmZsdWVuY2VzWyBpIF0gPSBbIGksIDAgXTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRpbmZsdWVuY2VzTGlzdFsgZ2VvbWV0cnkuaWQgXSA9IGluZmx1ZW5jZXM7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyBDb2xsZWN0IGluZmx1ZW5jZXNcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IGxlbmd0aDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgaW5mbHVlbmNlID0gaW5mbHVlbmNlc1sgaSBdO1xyXG5cclxuXHRcdFx0XHRpbmZsdWVuY2VbIDAgXSA9IGk7XHJcblx0XHRcdFx0aW5mbHVlbmNlWyAxIF0gPSBvYmplY3RJbmZsdWVuY2VzWyBpIF07XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRpbmZsdWVuY2VzLnNvcnQoIGFic051bWVyaWNhbFNvcnQgKTtcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IDg7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdGlmICggaSA8IGxlbmd0aCAmJiBpbmZsdWVuY2VzWyBpIF1bIDEgXSApIHtcclxuXHJcblx0XHRcdFx0XHR3b3JrSW5mbHVlbmNlc1sgaSBdWyAwIF0gPSBpbmZsdWVuY2VzWyBpIF1bIDAgXTtcclxuXHRcdFx0XHRcdHdvcmtJbmZsdWVuY2VzWyBpIF1bIDEgXSA9IGluZmx1ZW5jZXNbIGkgXVsgMSBdO1xyXG5cclxuXHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdHdvcmtJbmZsdWVuY2VzWyBpIF1bIDAgXSA9IE51bWJlci5NQVhfU0FGRV9JTlRFR0VSO1xyXG5cdFx0XHRcdFx0d29ya0luZmx1ZW5jZXNbIGkgXVsgMSBdID0gMDtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0d29ya0luZmx1ZW5jZXMuc29ydCggbnVtZXJpY2FsU29ydCApO1xyXG5cclxuXHRcdFx0Y29uc3QgbW9ycGhUYXJnZXRzID0gZ2VvbWV0cnkubW9ycGhBdHRyaWJ1dGVzLnBvc2l0aW9uO1xyXG5cdFx0XHRjb25zdCBtb3JwaE5vcm1hbHMgPSBnZW9tZXRyeS5tb3JwaEF0dHJpYnV0ZXMubm9ybWFsO1xyXG5cclxuXHRcdFx0bGV0IG1vcnBoSW5mbHVlbmNlc1N1bSA9IDA7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCA4OyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBpbmZsdWVuY2UgPSB3b3JrSW5mbHVlbmNlc1sgaSBdO1xyXG5cdFx0XHRcdGNvbnN0IGluZGV4ID0gaW5mbHVlbmNlWyAwIF07XHJcblx0XHRcdFx0Y29uc3QgdmFsdWUgPSBpbmZsdWVuY2VbIDEgXTtcclxuXHJcblx0XHRcdFx0aWYgKCBpbmRleCAhPT0gTnVtYmVyLk1BWF9TQUZFX0lOVEVHRVIgJiYgdmFsdWUgKSB7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCBtb3JwaFRhcmdldHMgJiYgZ2VvbWV0cnkuZ2V0QXR0cmlidXRlKCAnbW9ycGhUYXJnZXQnICsgaSApICE9PSBtb3JwaFRhcmdldHNbIGluZGV4IF0gKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRnZW9tZXRyeS5zZXRBdHRyaWJ1dGUoICdtb3JwaFRhcmdldCcgKyBpLCBtb3JwaFRhcmdldHNbIGluZGV4IF0gKTtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0aWYgKCBtb3JwaE5vcm1hbHMgJiYgZ2VvbWV0cnkuZ2V0QXR0cmlidXRlKCAnbW9ycGhOb3JtYWwnICsgaSApICE9PSBtb3JwaE5vcm1hbHNbIGluZGV4IF0gKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRnZW9tZXRyeS5zZXRBdHRyaWJ1dGUoICdtb3JwaE5vcm1hbCcgKyBpLCBtb3JwaE5vcm1hbHNbIGluZGV4IF0gKTtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0bW9ycGhJbmZsdWVuY2VzWyBpIF0gPSB2YWx1ZTtcclxuXHRcdFx0XHRcdG1vcnBoSW5mbHVlbmNlc1N1bSArPSB2YWx1ZTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRpZiAoIG1vcnBoVGFyZ2V0cyAmJiBnZW9tZXRyeS5oYXNBdHRyaWJ1dGUoICdtb3JwaFRhcmdldCcgKyBpICkgPT09IHRydWUgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRnZW9tZXRyeS5kZWxldGVBdHRyaWJ1dGUoICdtb3JwaFRhcmdldCcgKyBpICk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdGlmICggbW9ycGhOb3JtYWxzICYmIGdlb21ldHJ5Lmhhc0F0dHJpYnV0ZSggJ21vcnBoTm9ybWFsJyArIGkgKSA9PT0gdHJ1ZSApIHtcclxuXHJcblx0XHRcdFx0XHRcdGdlb21ldHJ5LmRlbGV0ZUF0dHJpYnV0ZSggJ21vcnBoTm9ybWFsJyArIGkgKTtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0bW9ycGhJbmZsdWVuY2VzWyBpIF0gPSAwO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyBHTFNMIHNoYWRlciB1c2VzIGZvcm11bGEgYmFzZWluZmx1ZW5jZSAqIGJhc2UgKyBzdW0odGFyZ2V0ICogaW5mbHVlbmNlKVxyXG5cdFx0XHQvLyBUaGlzIGFsbG93cyB1cyB0byBzd2l0Y2ggYmV0d2VlbiBhYnNvbHV0ZSBtb3JwaHMgYW5kIHJlbGF0aXZlIG1vcnBocyB3aXRob3V0IGNoYW5naW5nIHNoYWRlciBjb2RlXHJcblx0XHRcdC8vIFdoZW4gYmFzZWluZmx1ZW5jZSA9IDEgLSBzdW0oaW5mbHVlbmNlKSwgdGhlIGFib3ZlIGlzIGVxdWl2YWxlbnQgdG8gc3VtKCh0YXJnZXQgLSBiYXNlKSAqIGluZmx1ZW5jZSlcclxuXHRcdFx0Y29uc3QgbW9ycGhCYXNlSW5mbHVlbmNlID0gZ2VvbWV0cnkubW9ycGhUYXJnZXRzUmVsYXRpdmUgPyAxIDogMSAtIG1vcnBoSW5mbHVlbmNlc1N1bTtcclxuXHJcblx0XHRcdHByb2dyYW0uZ2V0VW5pZm9ybXMoKS5zZXRWYWx1ZSggZ2wsICdtb3JwaFRhcmdldEJhc2VJbmZsdWVuY2UnLCBtb3JwaEJhc2VJbmZsdWVuY2UgKTtcclxuXHRcdFx0cHJvZ3JhbS5nZXRVbmlmb3JtcygpLnNldFZhbHVlKCBnbCwgJ21vcnBoVGFyZ2V0SW5mbHVlbmNlcycsIG1vcnBoSW5mbHVlbmNlcyApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4ge1xyXG5cclxuXHRcdHVwZGF0ZTogdXBkYXRlXHJcblxyXG5cdH07XHJcblxyXG59XHJcblxyXG5cclxuZXhwb3J0IHsgV2ViR0xNb3JwaHRhcmdldHMgfTtcclxuIiwiZnVuY3Rpb24gV2ViR0xPYmplY3RzKCBnbCwgZ2VvbWV0cmllcywgYXR0cmlidXRlcywgaW5mbyApIHtcclxuXHJcblx0bGV0IHVwZGF0ZU1hcCA9IG5ldyBXZWFrTWFwKCk7XHJcblxyXG5cdGZ1bmN0aW9uIHVwZGF0ZSggb2JqZWN0ICkge1xyXG5cclxuXHRcdGNvbnN0IGZyYW1lID0gaW5mby5yZW5kZXIuZnJhbWU7XHJcblxyXG5cdFx0Y29uc3QgZ2VvbWV0cnkgPSBvYmplY3QuZ2VvbWV0cnk7XHJcblx0XHRjb25zdCBidWZmZXJnZW9tZXRyeSA9IGdlb21ldHJpZXMuZ2V0KCBvYmplY3QsIGdlb21ldHJ5ICk7XHJcblxyXG5cdFx0Ly8gVXBkYXRlIG9uY2UgcGVyIGZyYW1lXHJcblxyXG5cdFx0aWYgKCB1cGRhdGVNYXAuZ2V0KCBidWZmZXJnZW9tZXRyeSApICE9PSBmcmFtZSApIHtcclxuXHJcblx0XHRcdGdlb21ldHJpZXMudXBkYXRlKCBidWZmZXJnZW9tZXRyeSApO1xyXG5cclxuXHRcdFx0dXBkYXRlTWFwLnNldCggYnVmZmVyZ2VvbWV0cnksIGZyYW1lICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggb2JqZWN0LmlzSW5zdGFuY2VkTWVzaCApIHtcclxuXHJcblx0XHRcdGlmICggb2JqZWN0Lmhhc0V2ZW50TGlzdGVuZXIoICdkaXNwb3NlJywgb25JbnN0YW5jZWRNZXNoRGlzcG9zZSApID09PSBmYWxzZSApIHtcclxuXHJcblx0XHRcdFx0b2JqZWN0LmFkZEV2ZW50TGlzdGVuZXIoICdkaXNwb3NlJywgb25JbnN0YW5jZWRNZXNoRGlzcG9zZSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0aWYgKCB1cGRhdGVNYXAuZ2V0KCBvYmplY3QgKSAhPT0gZnJhbWUgKSB7XHJcblxyXG5cdFx0XHRcdGF0dHJpYnV0ZXMudXBkYXRlKCBvYmplY3QuaW5zdGFuY2VNYXRyaXgsIGdsLkFSUkFZX0JVRkZFUiApO1xyXG5cclxuXHRcdFx0XHRpZiAoIG9iamVjdC5pbnN0YW5jZUNvbG9yICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0XHRcdGF0dHJpYnV0ZXMudXBkYXRlKCBvYmplY3QuaW5zdGFuY2VDb2xvciwgZ2wuQVJSQVlfQlVGRkVSICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0dXBkYXRlTWFwLnNldCggb2JqZWN0LCBmcmFtZSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIG9iamVjdC5pc1NraW5uZWRNZXNoICkge1xyXG5cclxuXHRcdFx0Y29uc3Qgc2tlbGV0b24gPSBvYmplY3Quc2tlbGV0b247XHJcblxyXG5cdFx0XHRpZiAoIHVwZGF0ZU1hcC5nZXQoIHNrZWxldG9uICkgIT09IGZyYW1lICkge1xyXG5cclxuXHRcdFx0XHRza2VsZXRvbi51cGRhdGUoKTtcclxuXHJcblx0XHRcdFx0dXBkYXRlTWFwLnNldCggc2tlbGV0b24sIGZyYW1lICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiBidWZmZXJnZW9tZXRyeTtcclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBkaXNwb3NlKCkge1xyXG5cclxuXHRcdHVwZGF0ZU1hcCA9IG5ldyBXZWFrTWFwKCk7XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gb25JbnN0YW5jZWRNZXNoRGlzcG9zZSggZXZlbnQgKSB7XHJcblxyXG5cdFx0Y29uc3QgaW5zdGFuY2VkTWVzaCA9IGV2ZW50LnRhcmdldDtcclxuXHJcblx0XHRpbnN0YW5jZWRNZXNoLnJlbW92ZUV2ZW50TGlzdGVuZXIoICdkaXNwb3NlJywgb25JbnN0YW5jZWRNZXNoRGlzcG9zZSApO1xyXG5cclxuXHRcdGF0dHJpYnV0ZXMucmVtb3ZlKCBpbnN0YW5jZWRNZXNoLmluc3RhbmNlTWF0cml4ICk7XHJcblxyXG5cdFx0aWYgKCBpbnN0YW5jZWRNZXNoLmluc3RhbmNlQ29sb3IgIT09IG51bGwgKSBhdHRyaWJ1dGVzLnJlbW92ZSggaW5zdGFuY2VkTWVzaC5pbnN0YW5jZUNvbG9yICk7XHJcblxyXG5cdH1cclxuXHJcblx0cmV0dXJuIHtcclxuXHJcblx0XHR1cGRhdGU6IHVwZGF0ZSxcclxuXHRcdGRpc3Bvc2U6IGRpc3Bvc2VcclxuXHJcblx0fTtcclxuXHJcbn1cclxuXHJcblxyXG5leHBvcnQgeyBXZWJHTE9iamVjdHMgfTtcclxuIiwiaW1wb3J0IHsgVGV4dHVyZSB9IGZyb20gJy4vVGV4dHVyZS5qcyc7XHJcbmltcG9ydCB7IE5lYXJlc3RGaWx0ZXIsIFVuc2lnbmVkSW50VHlwZSwgVW5zaWduZWRJbnQyNDhUeXBlLCBEZXB0aEZvcm1hdCwgRGVwdGhTdGVuY2lsRm9ybWF0IH0gZnJvbSAnLi4vY29uc3RhbnRzLmpzJztcclxuXHJcbmNsYXNzIERlcHRoVGV4dHVyZSBleHRlbmRzIFRleHR1cmUge1xyXG5cclxuXHRjb25zdHJ1Y3Rvciggd2lkdGgsIGhlaWdodCwgdHlwZSwgbWFwcGluZywgd3JhcFMsIHdyYXBULCBtYWdGaWx0ZXIsIG1pbkZpbHRlciwgYW5pc290cm9weSwgZm9ybWF0ICkge1xyXG5cclxuXHRcdGZvcm1hdCA9IGZvcm1hdCAhPT0gdW5kZWZpbmVkID8gZm9ybWF0IDogRGVwdGhGb3JtYXQ7XHJcblxyXG5cdFx0aWYgKCBmb3JtYXQgIT09IERlcHRoRm9ybWF0ICYmIGZvcm1hdCAhPT0gRGVwdGhTdGVuY2lsRm9ybWF0ICkge1xyXG5cclxuXHRcdFx0dGhyb3cgbmV3IEVycm9yKCAnRGVwdGhUZXh0dXJlIGZvcm1hdCBtdXN0IGJlIGVpdGhlciBUSFJFRS5EZXB0aEZvcm1hdCBvciBUSFJFRS5EZXB0aFN0ZW5jaWxGb3JtYXQnICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggdHlwZSA9PT0gdW5kZWZpbmVkICYmIGZvcm1hdCA9PT0gRGVwdGhGb3JtYXQgKSB0eXBlID0gVW5zaWduZWRJbnRUeXBlO1xyXG5cdFx0aWYgKCB0eXBlID09PSB1bmRlZmluZWQgJiYgZm9ybWF0ID09PSBEZXB0aFN0ZW5jaWxGb3JtYXQgKSB0eXBlID0gVW5zaWduZWRJbnQyNDhUeXBlO1xyXG5cclxuXHRcdHN1cGVyKCBudWxsLCBtYXBwaW5nLCB3cmFwUywgd3JhcFQsIG1hZ0ZpbHRlciwgbWluRmlsdGVyLCBmb3JtYXQsIHR5cGUsIGFuaXNvdHJvcHkgKTtcclxuXHJcblx0XHR0aGlzLmlzRGVwdGhUZXh0dXJlID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLmltYWdlID0geyB3aWR0aDogd2lkdGgsIGhlaWdodDogaGVpZ2h0IH07XHJcblxyXG5cdFx0dGhpcy5tYWdGaWx0ZXIgPSBtYWdGaWx0ZXIgIT09IHVuZGVmaW5lZCA/IG1hZ0ZpbHRlciA6IE5lYXJlc3RGaWx0ZXI7XHJcblx0XHR0aGlzLm1pbkZpbHRlciA9IG1pbkZpbHRlciAhPT0gdW5kZWZpbmVkID8gbWluRmlsdGVyIDogTmVhcmVzdEZpbHRlcjtcclxuXHJcblx0XHR0aGlzLmZsaXBZID0gZmFsc2U7XHJcblx0XHR0aGlzLmdlbmVyYXRlTWlwbWFwcyA9IGZhbHNlO1xyXG5cclxuXHRcdHRoaXMuY29tcGFyZUZ1bmN0aW9uID0gbnVsbDtcclxuXHJcblx0fVxyXG5cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xyXG5cclxuXHRcdHRoaXMuY29tcGFyZUZ1bmN0aW9uID0gc291cmNlLmNvbXBhcmVGdW5jdGlvbjtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHR0b0pTT04oIG1ldGEgKSB7XHJcblxyXG5cdFx0Y29uc3QgZGF0YSA9IHN1cGVyLnRvSlNPTiggbWV0YSApO1xyXG5cclxuXHRcdGlmICggdGhpcy5jb21wYXJlRnVuY3Rpb24gIT09IG51bGwgKSBkYXRhLmNvbXBhcmVGdW5jdGlvbiA9IHRoaXMuY29tcGFyZUZ1bmN0aW9uO1xyXG5cclxuXHRcdHJldHVybiBkYXRhO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBEZXB0aFRleHR1cmUgfTtcclxuIiwiLyoqXHJcbiAqIFVuaWZvcm1zIG9mIGEgcHJvZ3JhbS5cclxuICogVGhvc2UgZm9ybSBhIHRyZWUgc3RydWN0dXJlIHdpdGggYSBzcGVjaWFsIHRvcC1sZXZlbCBjb250YWluZXIgZm9yIHRoZSByb290LFxyXG4gKiB3aGljaCB5b3UgZ2V0IGJ5IGNhbGxpbmcgJ25ldyBXZWJHTFVuaWZvcm1zKCBnbCwgcHJvZ3JhbSApJy5cclxuICpcclxuICpcclxuICogUHJvcGVydGllcyBvZiBpbm5lciBub2RlcyBpbmNsdWRpbmcgdGhlIHRvcC1sZXZlbCBjb250YWluZXI6XHJcbiAqXHJcbiAqIC5zZXEgLSBhcnJheSBvZiBuZXN0ZWQgdW5pZm9ybXNcclxuICogLm1hcCAtIG5lc3RlZCB1bmlmb3JtcyBieSBuYW1lXHJcbiAqXHJcbiAqXHJcbiAqIE1ldGhvZHMgb2YgYWxsIG5vZGVzIGV4Y2VwdCB0aGUgdG9wLWxldmVsIGNvbnRhaW5lcjpcclxuICpcclxuICogLnNldFZhbHVlKCBnbCwgdmFsdWUsIFt0ZXh0dXJlc10gKVxyXG4gKlxyXG4gKiBcdFx0dXBsb2FkcyBhIHVuaWZvcm0gdmFsdWUocylcclxuICogIFx0dGhlICd0ZXh0dXJlcycgcGFyYW1ldGVyIGlzIG5lZWRlZCBmb3Igc2FtcGxlciB1bmlmb3Jtc1xyXG4gKlxyXG4gKlxyXG4gKiBTdGF0aWMgbWV0aG9kcyBvZiB0aGUgdG9wLWxldmVsIGNvbnRhaW5lciAodGV4dHVyZXMgZmFjdG9yaXphdGlvbnMpOlxyXG4gKlxyXG4gKiAudXBsb2FkKCBnbCwgc2VxLCB2YWx1ZXMsIHRleHR1cmVzIClcclxuICpcclxuICogXHRcdHNldHMgdW5pZm9ybXMgaW4gJ3NlcScgdG8gJ3ZhbHVlc1tpZF0udmFsdWUnXHJcbiAqXHJcbiAqIC5zZXFXaXRoVmFsdWUoIHNlcSwgdmFsdWVzICkgOiBmaWx0ZXJlZFNlcVxyXG4gKlxyXG4gKiBcdFx0ZmlsdGVycyAnc2VxJyBlbnRyaWVzIHdpdGggY29ycmVzcG9uZGluZyBlbnRyeSBpbiB2YWx1ZXNcclxuICpcclxuICpcclxuICogTWV0aG9kcyBvZiB0aGUgdG9wLWxldmVsIGNvbnRhaW5lciAodGV4dHVyZXMgZmFjdG9yaXphdGlvbnMpOlxyXG4gKlxyXG4gKiAuc2V0VmFsdWUoIGdsLCBuYW1lLCB2YWx1ZSwgdGV4dHVyZXMgKVxyXG4gKlxyXG4gKiBcdFx0c2V0cyB1bmlmb3JtIHdpdGggIG5hbWUgJ25hbWUnIHRvICd2YWx1ZSdcclxuICpcclxuICogLnNldE9wdGlvbmFsKCBnbCwgb2JqLCBwcm9wIClcclxuICpcclxuICogXHRcdGxpa2UgLnNldCBmb3IgYW4gb3B0aW9uYWwgcHJvcGVydHkgb2YgdGhlIG9iamVjdFxyXG4gKlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IEN1YmVUZXh0dXJlIH0gZnJvbSAnLi4vLi4vdGV4dHVyZXMvQ3ViZVRleHR1cmUuanMnO1xyXG5pbXBvcnQgeyBUZXh0dXJlIH0gZnJvbSAnLi4vLi4vdGV4dHVyZXMvVGV4dHVyZS5qcyc7XHJcbmltcG9ydCB7IERhdGFBcnJheVRleHR1cmUgfSBmcm9tICcuLi8uLi90ZXh0dXJlcy9EYXRhQXJyYXlUZXh0dXJlLmpzJztcclxuaW1wb3J0IHsgRGF0YTNEVGV4dHVyZSB9IGZyb20gJy4uLy4uL3RleHR1cmVzL0RhdGEzRFRleHR1cmUuanMnO1xyXG5pbXBvcnQgeyBEZXB0aFRleHR1cmUgfSBmcm9tICcuLi8uLi90ZXh0dXJlcy9EZXB0aFRleHR1cmUuanMnO1xyXG5pbXBvcnQgeyBMZXNzRXF1YWxDb21wYXJlIH0gZnJvbSAnLi4vLi4vY29uc3RhbnRzLmpzJztcclxuXHJcbmNvbnN0IGVtcHR5VGV4dHVyZSA9IC8qQF9fUFVSRV9fKi8gbmV3IFRleHR1cmUoKTtcclxuXHJcbmNvbnN0IGVtcHR5U2hhZG93VGV4dHVyZSA9IC8qQF9fUFVSRV9fKi8gbmV3IERlcHRoVGV4dHVyZSggMSwgMSApO1xyXG5lbXB0eVNoYWRvd1RleHR1cmUuY29tcGFyZUZ1bmN0aW9uID0gTGVzc0VxdWFsQ29tcGFyZTtcclxuXHJcbmNvbnN0IGVtcHR5QXJyYXlUZXh0dXJlID0gLypAX19QVVJFX18qLyBuZXcgRGF0YUFycmF5VGV4dHVyZSgpO1xyXG5jb25zdCBlbXB0eTNkVGV4dHVyZSA9IC8qQF9fUFVSRV9fKi8gbmV3IERhdGEzRFRleHR1cmUoKTtcclxuY29uc3QgZW1wdHlDdWJlVGV4dHVyZSA9IC8qQF9fUFVSRV9fKi8gbmV3IEN1YmVUZXh0dXJlKCk7XHJcblxyXG4vLyAtLS0gVXRpbGl0aWVzIC0tLVxyXG5cclxuLy8gQXJyYXkgQ2FjaGVzIChwcm92aWRlIHR5cGVkIGFycmF5cyBmb3IgdGVtcG9yYXJ5IGJ5IHNpemUpXHJcblxyXG5jb25zdCBhcnJheUNhY2hlRjMyID0gW107XHJcbmNvbnN0IGFycmF5Q2FjaGVJMzIgPSBbXTtcclxuXHJcbi8vIEZsb2F0MzJBcnJheSBjYWNoZXMgdXNlZCBmb3IgdXBsb2FkaW5nIE1hdHJpeCB1bmlmb3Jtc1xyXG5cclxuY29uc3QgbWF0NGFycmF5ID0gbmV3IEZsb2F0MzJBcnJheSggMTYgKTtcclxuY29uc3QgbWF0M2FycmF5ID0gbmV3IEZsb2F0MzJBcnJheSggOSApO1xyXG5jb25zdCBtYXQyYXJyYXkgPSBuZXcgRmxvYXQzMkFycmF5KCA0ICk7XHJcblxyXG4vLyBGbGF0dGVuaW5nIGZvciBhcnJheXMgb2YgdmVjdG9ycyBhbmQgbWF0cmljZXNcclxuXHJcbmZ1bmN0aW9uIGZsYXR0ZW4oIGFycmF5LCBuQmxvY2tzLCBibG9ja1NpemUgKSB7XHJcblxyXG5cdGNvbnN0IGZpcnN0RWxlbSA9IGFycmF5WyAwIF07XHJcblxyXG5cdGlmICggZmlyc3RFbGVtIDw9IDAgfHwgZmlyc3RFbGVtID4gMCApIHJldHVybiBhcnJheTtcclxuXHQvLyB1bm9wdGltaXplZDogISBpc05hTiggZmlyc3RFbGVtIClcclxuXHQvLyBzZWUgaHR0cDovL2phY2tzb25kdW5zdGFuLmNvbS9hcnRpY2xlcy85ODNcclxuXHJcblx0Y29uc3QgbiA9IG5CbG9ja3MgKiBibG9ja1NpemU7XHJcblx0bGV0IHIgPSBhcnJheUNhY2hlRjMyWyBuIF07XHJcblxyXG5cdGlmICggciA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdHIgPSBuZXcgRmxvYXQzMkFycmF5KCBuICk7XHJcblx0XHRhcnJheUNhY2hlRjMyWyBuIF0gPSByO1xyXG5cclxuXHR9XHJcblxyXG5cdGlmICggbkJsb2NrcyAhPT0gMCApIHtcclxuXHJcblx0XHRmaXJzdEVsZW0udG9BcnJheSggciwgMCApO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMSwgb2Zmc2V0ID0gMDsgaSAhPT0gbkJsb2NrczsgKysgaSApIHtcclxuXHJcblx0XHRcdG9mZnNldCArPSBibG9ja1NpemU7XHJcblx0XHRcdGFycmF5WyBpIF0udG9BcnJheSggciwgb2Zmc2V0ICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdHJldHVybiByO1xyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gYXJyYXlzRXF1YWwoIGEsIGIgKSB7XHJcblxyXG5cdGlmICggYS5sZW5ndGggIT09IGIubGVuZ3RoICkgcmV0dXJuIGZhbHNlO1xyXG5cclxuXHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBhLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0aWYgKCBhWyBpIF0gIT09IGJbIGkgXSApIHJldHVybiBmYWxzZTtcclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4gdHJ1ZTtcclxuXHJcbn1cclxuXHJcbmZ1bmN0aW9uIGNvcHlBcnJheSggYSwgYiApIHtcclxuXHJcblx0Zm9yICggbGV0IGkgPSAwLCBsID0gYi5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdGFbIGkgXSA9IGJbIGkgXTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuLy8gVGV4dHVyZSB1bml0IGFsbG9jYXRpb25cclxuXHJcbmZ1bmN0aW9uIGFsbG9jVGV4VW5pdHMoIHRleHR1cmVzLCBuICkge1xyXG5cclxuXHRsZXQgciA9IGFycmF5Q2FjaGVJMzJbIG4gXTtcclxuXHJcblx0aWYgKCByID09PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0ciA9IG5ldyBJbnQzMkFycmF5KCBuICk7XHJcblx0XHRhcnJheUNhY2hlSTMyWyBuIF0gPSByO1xyXG5cclxuXHR9XHJcblxyXG5cdGZvciAoIGxldCBpID0gMDsgaSAhPT0gbjsgKysgaSApIHtcclxuXHJcblx0XHRyWyBpIF0gPSB0ZXh0dXJlcy5hbGxvY2F0ZVRleHR1cmVVbml0KCk7XHJcblxyXG5cdH1cclxuXHJcblx0cmV0dXJuIHI7XHJcblxyXG59XHJcblxyXG4vLyAtLS0gU2V0dGVycyAtLS1cclxuXHJcbi8vIE5vdGU6IERlZmluaW5nIHRoZXNlIG1ldGhvZHMgZXh0ZXJuYWxseSwgYmVjYXVzZSB0aGV5IGNvbWUgaW4gYSBidW5jaFxyXG4vLyBhbmQgdGhpcyB3YXkgdGhlaXIgbmFtZXMgbWluaWZ5LlxyXG5cclxuLy8gU2luZ2xlIHNjYWxhclxyXG5cclxuZnVuY3Rpb24gc2V0VmFsdWVWMWYoIGdsLCB2ICkge1xyXG5cclxuXHRjb25zdCBjYWNoZSA9IHRoaXMuY2FjaGU7XHJcblxyXG5cdGlmICggY2FjaGVbIDAgXSA9PT0gdiApIHJldHVybjtcclxuXHJcblx0Z2wudW5pZm9ybTFmKCB0aGlzLmFkZHIsIHYgKTtcclxuXHJcblx0Y2FjaGVbIDAgXSA9IHY7XHJcblxyXG59XHJcblxyXG4vLyBTaW5nbGUgZmxvYXQgdmVjdG9yIChmcm9tIGZsYXQgYXJyYXkgb3IgVEhSRUUuVmVjdG9yTilcclxuXHJcbmZ1bmN0aW9uIHNldFZhbHVlVjJmKCBnbCwgdiApIHtcclxuXHJcblx0Y29uc3QgY2FjaGUgPSB0aGlzLmNhY2hlO1xyXG5cclxuXHRpZiAoIHYueCAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdGlmICggY2FjaGVbIDAgXSAhPT0gdi54IHx8IGNhY2hlWyAxIF0gIT09IHYueSApIHtcclxuXHJcblx0XHRcdGdsLnVuaWZvcm0yZiggdGhpcy5hZGRyLCB2LngsIHYueSApO1xyXG5cclxuXHRcdFx0Y2FjaGVbIDAgXSA9IHYueDtcclxuXHRcdFx0Y2FjaGVbIDEgXSA9IHYueTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH0gZWxzZSB7XHJcblxyXG5cdFx0aWYgKCBhcnJheXNFcXVhbCggY2FjaGUsIHYgKSApIHJldHVybjtcclxuXHJcblx0XHRnbC51bmlmb3JtMmZ2KCB0aGlzLmFkZHIsIHYgKTtcclxuXHJcblx0XHRjb3B5QXJyYXkoIGNhY2hlLCB2ICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmZ1bmN0aW9uIHNldFZhbHVlVjNmKCBnbCwgdiApIHtcclxuXHJcblx0Y29uc3QgY2FjaGUgPSB0aGlzLmNhY2hlO1xyXG5cclxuXHRpZiAoIHYueCAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdGlmICggY2FjaGVbIDAgXSAhPT0gdi54IHx8IGNhY2hlWyAxIF0gIT09IHYueSB8fCBjYWNoZVsgMiBdICE9PSB2LnogKSB7XHJcblxyXG5cdFx0XHRnbC51bmlmb3JtM2YoIHRoaXMuYWRkciwgdi54LCB2LnksIHYueiApO1xyXG5cclxuXHRcdFx0Y2FjaGVbIDAgXSA9IHYueDtcclxuXHRcdFx0Y2FjaGVbIDEgXSA9IHYueTtcclxuXHRcdFx0Y2FjaGVbIDIgXSA9IHYuejtcclxuXHJcblx0XHR9XHJcblxyXG5cdH0gZWxzZSBpZiAoIHYuciAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdGlmICggY2FjaGVbIDAgXSAhPT0gdi5yIHx8IGNhY2hlWyAxIF0gIT09IHYuZyB8fCBjYWNoZVsgMiBdICE9PSB2LmIgKSB7XHJcblxyXG5cdFx0XHRnbC51bmlmb3JtM2YoIHRoaXMuYWRkciwgdi5yLCB2LmcsIHYuYiApO1xyXG5cclxuXHRcdFx0Y2FjaGVbIDAgXSA9IHYucjtcclxuXHRcdFx0Y2FjaGVbIDEgXSA9IHYuZztcclxuXHRcdFx0Y2FjaGVbIDIgXSA9IHYuYjtcclxuXHJcblx0XHR9XHJcblxyXG5cdH0gZWxzZSB7XHJcblxyXG5cdFx0aWYgKCBhcnJheXNFcXVhbCggY2FjaGUsIHYgKSApIHJldHVybjtcclxuXHJcblx0XHRnbC51bmlmb3JtM2Z2KCB0aGlzLmFkZHIsIHYgKTtcclxuXHJcblx0XHRjb3B5QXJyYXkoIGNhY2hlLCB2ICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmZ1bmN0aW9uIHNldFZhbHVlVjRmKCBnbCwgdiApIHtcclxuXHJcblx0Y29uc3QgY2FjaGUgPSB0aGlzLmNhY2hlO1xyXG5cclxuXHRpZiAoIHYueCAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdGlmICggY2FjaGVbIDAgXSAhPT0gdi54IHx8IGNhY2hlWyAxIF0gIT09IHYueSB8fCBjYWNoZVsgMiBdICE9PSB2LnogfHwgY2FjaGVbIDMgXSAhPT0gdi53ICkge1xyXG5cclxuXHRcdFx0Z2wudW5pZm9ybTRmKCB0aGlzLmFkZHIsIHYueCwgdi55LCB2LnosIHYudyApO1xyXG5cclxuXHRcdFx0Y2FjaGVbIDAgXSA9IHYueDtcclxuXHRcdFx0Y2FjaGVbIDEgXSA9IHYueTtcclxuXHRcdFx0Y2FjaGVbIDIgXSA9IHYuejtcclxuXHRcdFx0Y2FjaGVbIDMgXSA9IHYudztcclxuXHJcblx0XHR9XHJcblxyXG5cdH0gZWxzZSB7XHJcblxyXG5cdFx0aWYgKCBhcnJheXNFcXVhbCggY2FjaGUsIHYgKSApIHJldHVybjtcclxuXHJcblx0XHRnbC51bmlmb3JtNGZ2KCB0aGlzLmFkZHIsIHYgKTtcclxuXHJcblx0XHRjb3B5QXJyYXkoIGNhY2hlLCB2ICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbi8vIFNpbmdsZSBtYXRyaXggKGZyb20gZmxhdCBhcnJheSBvciBUSFJFRS5NYXRyaXhOKVxyXG5cclxuZnVuY3Rpb24gc2V0VmFsdWVNMiggZ2wsIHYgKSB7XHJcblxyXG5cdGNvbnN0IGNhY2hlID0gdGhpcy5jYWNoZTtcclxuXHRjb25zdCBlbGVtZW50cyA9IHYuZWxlbWVudHM7XHJcblxyXG5cdGlmICggZWxlbWVudHMgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRpZiAoIGFycmF5c0VxdWFsKCBjYWNoZSwgdiApICkgcmV0dXJuO1xyXG5cclxuXHRcdGdsLnVuaWZvcm1NYXRyaXgyZnYoIHRoaXMuYWRkciwgZmFsc2UsIHYgKTtcclxuXHJcblx0XHRjb3B5QXJyYXkoIGNhY2hlLCB2ICk7XHJcblxyXG5cdH0gZWxzZSB7XHJcblxyXG5cdFx0aWYgKCBhcnJheXNFcXVhbCggY2FjaGUsIGVsZW1lbnRzICkgKSByZXR1cm47XHJcblxyXG5cdFx0bWF0MmFycmF5LnNldCggZWxlbWVudHMgKTtcclxuXHJcblx0XHRnbC51bmlmb3JtTWF0cml4MmZ2KCB0aGlzLmFkZHIsIGZhbHNlLCBtYXQyYXJyYXkgKTtcclxuXHJcblx0XHRjb3B5QXJyYXkoIGNhY2hlLCBlbGVtZW50cyApO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiBzZXRWYWx1ZU0zKCBnbCwgdiApIHtcclxuXHJcblx0Y29uc3QgY2FjaGUgPSB0aGlzLmNhY2hlO1xyXG5cdGNvbnN0IGVsZW1lbnRzID0gdi5lbGVtZW50cztcclxuXHJcblx0aWYgKCBlbGVtZW50cyA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdGlmICggYXJyYXlzRXF1YWwoIGNhY2hlLCB2ICkgKSByZXR1cm47XHJcblxyXG5cdFx0Z2wudW5pZm9ybU1hdHJpeDNmdiggdGhpcy5hZGRyLCBmYWxzZSwgdiApO1xyXG5cclxuXHRcdGNvcHlBcnJheSggY2FjaGUsIHYgKTtcclxuXHJcblx0fSBlbHNlIHtcclxuXHJcblx0XHRpZiAoIGFycmF5c0VxdWFsKCBjYWNoZSwgZWxlbWVudHMgKSApIHJldHVybjtcclxuXHJcblx0XHRtYXQzYXJyYXkuc2V0KCBlbGVtZW50cyApO1xyXG5cclxuXHRcdGdsLnVuaWZvcm1NYXRyaXgzZnYoIHRoaXMuYWRkciwgZmFsc2UsIG1hdDNhcnJheSApO1xyXG5cclxuXHRcdGNvcHlBcnJheSggY2FjaGUsIGVsZW1lbnRzICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmZ1bmN0aW9uIHNldFZhbHVlTTQoIGdsLCB2ICkge1xyXG5cclxuXHRjb25zdCBjYWNoZSA9IHRoaXMuY2FjaGU7XHJcblx0Y29uc3QgZWxlbWVudHMgPSB2LmVsZW1lbnRzO1xyXG5cclxuXHRpZiAoIGVsZW1lbnRzID09PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0aWYgKCBhcnJheXNFcXVhbCggY2FjaGUsIHYgKSApIHJldHVybjtcclxuXHJcblx0XHRnbC51bmlmb3JtTWF0cml4NGZ2KCB0aGlzLmFkZHIsIGZhbHNlLCB2ICk7XHJcblxyXG5cdFx0Y29weUFycmF5KCBjYWNoZSwgdiApO1xyXG5cclxuXHR9IGVsc2Uge1xyXG5cclxuXHRcdGlmICggYXJyYXlzRXF1YWwoIGNhY2hlLCBlbGVtZW50cyApICkgcmV0dXJuO1xyXG5cclxuXHRcdG1hdDRhcnJheS5zZXQoIGVsZW1lbnRzICk7XHJcblxyXG5cdFx0Z2wudW5pZm9ybU1hdHJpeDRmdiggdGhpcy5hZGRyLCBmYWxzZSwgbWF0NGFycmF5ICk7XHJcblxyXG5cdFx0Y29weUFycmF5KCBjYWNoZSwgZWxlbWVudHMgKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuLy8gU2luZ2xlIGludGVnZXIgLyBib29sZWFuXHJcblxyXG5mdW5jdGlvbiBzZXRWYWx1ZVYxaSggZ2wsIHYgKSB7XHJcblxyXG5cdGNvbnN0IGNhY2hlID0gdGhpcy5jYWNoZTtcclxuXHJcblx0aWYgKCBjYWNoZVsgMCBdID09PSB2ICkgcmV0dXJuO1xyXG5cclxuXHRnbC51bmlmb3JtMWkoIHRoaXMuYWRkciwgdiApO1xyXG5cclxuXHRjYWNoZVsgMCBdID0gdjtcclxuXHJcbn1cclxuXHJcbi8vIFNpbmdsZSBpbnRlZ2VyIC8gYm9vbGVhbiB2ZWN0b3IgKGZyb20gZmxhdCBhcnJheSBvciBUSFJFRS5WZWN0b3JOKVxyXG5cclxuZnVuY3Rpb24gc2V0VmFsdWVWMmkoIGdsLCB2ICkge1xyXG5cclxuXHRjb25zdCBjYWNoZSA9IHRoaXMuY2FjaGU7XHJcblxyXG5cdGlmICggdi54ICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0aWYgKCBjYWNoZVsgMCBdICE9PSB2LnggfHwgY2FjaGVbIDEgXSAhPT0gdi55ICkge1xyXG5cclxuXHRcdFx0Z2wudW5pZm9ybTJpKCB0aGlzLmFkZHIsIHYueCwgdi55ICk7XHJcblxyXG5cdFx0XHRjYWNoZVsgMCBdID0gdi54O1xyXG5cdFx0XHRjYWNoZVsgMSBdID0gdi55O1xyXG5cclxuXHRcdH1cclxuXHJcblx0fSBlbHNlIHtcclxuXHJcblx0XHRpZiAoIGFycmF5c0VxdWFsKCBjYWNoZSwgdiApICkgcmV0dXJuO1xyXG5cclxuXHRcdGdsLnVuaWZvcm0yaXYoIHRoaXMuYWRkciwgdiApO1xyXG5cclxuXHRcdGNvcHlBcnJheSggY2FjaGUsIHYgKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gc2V0VmFsdWVWM2koIGdsLCB2ICkge1xyXG5cclxuXHRjb25zdCBjYWNoZSA9IHRoaXMuY2FjaGU7XHJcblxyXG5cdGlmICggdi54ICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0aWYgKCBjYWNoZVsgMCBdICE9PSB2LnggfHwgY2FjaGVbIDEgXSAhPT0gdi55IHx8IGNhY2hlWyAyIF0gIT09IHYueiApIHtcclxuXHJcblx0XHRcdGdsLnVuaWZvcm0zaSggdGhpcy5hZGRyLCB2LngsIHYueSwgdi56ICk7XHJcblxyXG5cdFx0XHRjYWNoZVsgMCBdID0gdi54O1xyXG5cdFx0XHRjYWNoZVsgMSBdID0gdi55O1xyXG5cdFx0XHRjYWNoZVsgMiBdID0gdi56O1xyXG5cclxuXHRcdH1cclxuXHJcblx0fSBlbHNlIHtcclxuXHJcblx0XHRpZiAoIGFycmF5c0VxdWFsKCBjYWNoZSwgdiApICkgcmV0dXJuO1xyXG5cclxuXHRcdGdsLnVuaWZvcm0zaXYoIHRoaXMuYWRkciwgdiApO1xyXG5cclxuXHRcdGNvcHlBcnJheSggY2FjaGUsIHYgKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gc2V0VmFsdWVWNGkoIGdsLCB2ICkge1xyXG5cclxuXHRjb25zdCBjYWNoZSA9IHRoaXMuY2FjaGU7XHJcblxyXG5cdGlmICggdi54ICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0aWYgKCBjYWNoZVsgMCBdICE9PSB2LnggfHwgY2FjaGVbIDEgXSAhPT0gdi55IHx8IGNhY2hlWyAyIF0gIT09IHYueiB8fCBjYWNoZVsgMyBdICE9PSB2LncgKSB7XHJcblxyXG5cdFx0XHRnbC51bmlmb3JtNGkoIHRoaXMuYWRkciwgdi54LCB2LnksIHYueiwgdi53ICk7XHJcblxyXG5cdFx0XHRjYWNoZVsgMCBdID0gdi54O1xyXG5cdFx0XHRjYWNoZVsgMSBdID0gdi55O1xyXG5cdFx0XHRjYWNoZVsgMiBdID0gdi56O1xyXG5cdFx0XHRjYWNoZVsgMyBdID0gdi53O1xyXG5cclxuXHRcdH1cclxuXHJcblx0fSBlbHNlIHtcclxuXHJcblx0XHRpZiAoIGFycmF5c0VxdWFsKCBjYWNoZSwgdiApICkgcmV0dXJuO1xyXG5cclxuXHRcdGdsLnVuaWZvcm00aXYoIHRoaXMuYWRkciwgdiApO1xyXG5cclxuXHRcdGNvcHlBcnJheSggY2FjaGUsIHYgKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuLy8gU2luZ2xlIHVuc2lnbmVkIGludGVnZXJcclxuXHJcbmZ1bmN0aW9uIHNldFZhbHVlVjF1aSggZ2wsIHYgKSB7XHJcblxyXG5cdGNvbnN0IGNhY2hlID0gdGhpcy5jYWNoZTtcclxuXHJcblx0aWYgKCBjYWNoZVsgMCBdID09PSB2ICkgcmV0dXJuO1xyXG5cclxuXHRnbC51bmlmb3JtMXVpKCB0aGlzLmFkZHIsIHYgKTtcclxuXHJcblx0Y2FjaGVbIDAgXSA9IHY7XHJcblxyXG59XHJcblxyXG4vLyBTaW5nbGUgdW5zaWduZWQgaW50ZWdlciB2ZWN0b3IgKGZyb20gZmxhdCBhcnJheSBvciBUSFJFRS5WZWN0b3JOKVxyXG5cclxuZnVuY3Rpb24gc2V0VmFsdWVWMnVpKCBnbCwgdiApIHtcclxuXHJcblx0Y29uc3QgY2FjaGUgPSB0aGlzLmNhY2hlO1xyXG5cclxuXHRpZiAoIHYueCAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdGlmICggY2FjaGVbIDAgXSAhPT0gdi54IHx8IGNhY2hlWyAxIF0gIT09IHYueSApIHtcclxuXHJcblx0XHRcdGdsLnVuaWZvcm0ydWkoIHRoaXMuYWRkciwgdi54LCB2LnkgKTtcclxuXHJcblx0XHRcdGNhY2hlWyAwIF0gPSB2Lng7XHJcblx0XHRcdGNhY2hlWyAxIF0gPSB2Lnk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9IGVsc2Uge1xyXG5cclxuXHRcdGlmICggYXJyYXlzRXF1YWwoIGNhY2hlLCB2ICkgKSByZXR1cm47XHJcblxyXG5cdFx0Z2wudW5pZm9ybTJ1aXYoIHRoaXMuYWRkciwgdiApO1xyXG5cclxuXHRcdGNvcHlBcnJheSggY2FjaGUsIHYgKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gc2V0VmFsdWVWM3VpKCBnbCwgdiApIHtcclxuXHJcblx0Y29uc3QgY2FjaGUgPSB0aGlzLmNhY2hlO1xyXG5cclxuXHRpZiAoIHYueCAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdGlmICggY2FjaGVbIDAgXSAhPT0gdi54IHx8IGNhY2hlWyAxIF0gIT09IHYueSB8fCBjYWNoZVsgMiBdICE9PSB2LnogKSB7XHJcblxyXG5cdFx0XHRnbC51bmlmb3JtM3VpKCB0aGlzLmFkZHIsIHYueCwgdi55LCB2LnogKTtcclxuXHJcblx0XHRcdGNhY2hlWyAwIF0gPSB2Lng7XHJcblx0XHRcdGNhY2hlWyAxIF0gPSB2Lnk7XHJcblx0XHRcdGNhY2hlWyAyIF0gPSB2Lno7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9IGVsc2Uge1xyXG5cclxuXHRcdGlmICggYXJyYXlzRXF1YWwoIGNhY2hlLCB2ICkgKSByZXR1cm47XHJcblxyXG5cdFx0Z2wudW5pZm9ybTN1aXYoIHRoaXMuYWRkciwgdiApO1xyXG5cclxuXHRcdGNvcHlBcnJheSggY2FjaGUsIHYgKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gc2V0VmFsdWVWNHVpKCBnbCwgdiApIHtcclxuXHJcblx0Y29uc3QgY2FjaGUgPSB0aGlzLmNhY2hlO1xyXG5cclxuXHRpZiAoIHYueCAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdGlmICggY2FjaGVbIDAgXSAhPT0gdi54IHx8IGNhY2hlWyAxIF0gIT09IHYueSB8fCBjYWNoZVsgMiBdICE9PSB2LnogfHwgY2FjaGVbIDMgXSAhPT0gdi53ICkge1xyXG5cclxuXHRcdFx0Z2wudW5pZm9ybTR1aSggdGhpcy5hZGRyLCB2LngsIHYueSwgdi56LCB2LncgKTtcclxuXHJcblx0XHRcdGNhY2hlWyAwIF0gPSB2Lng7XHJcblx0XHRcdGNhY2hlWyAxIF0gPSB2Lnk7XHJcblx0XHRcdGNhY2hlWyAyIF0gPSB2Lno7XHJcblx0XHRcdGNhY2hlWyAzIF0gPSB2Lnc7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9IGVsc2Uge1xyXG5cclxuXHRcdGlmICggYXJyYXlzRXF1YWwoIGNhY2hlLCB2ICkgKSByZXR1cm47XHJcblxyXG5cdFx0Z2wudW5pZm9ybTR1aXYoIHRoaXMuYWRkciwgdiApO1xyXG5cclxuXHRcdGNvcHlBcnJheSggY2FjaGUsIHYgKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuXHJcbi8vIFNpbmdsZSB0ZXh0dXJlICgyRCAvIEN1YmUpXHJcblxyXG5mdW5jdGlvbiBzZXRWYWx1ZVQxKCBnbCwgdiwgdGV4dHVyZXMgKSB7XHJcblxyXG5cdGNvbnN0IGNhY2hlID0gdGhpcy5jYWNoZTtcclxuXHRjb25zdCB1bml0ID0gdGV4dHVyZXMuYWxsb2NhdGVUZXh0dXJlVW5pdCgpO1xyXG5cclxuXHRpZiAoIGNhY2hlWyAwIF0gIT09IHVuaXQgKSB7XHJcblxyXG5cdFx0Z2wudW5pZm9ybTFpKCB0aGlzLmFkZHIsIHVuaXQgKTtcclxuXHRcdGNhY2hlWyAwIF0gPSB1bml0O1xyXG5cclxuXHR9XHJcblxyXG5cdGNvbnN0IGVtcHR5VGV4dHVyZTJEID0gKCB0aGlzLnR5cGUgPT09IGdsLlNBTVBMRVJfMkRfU0hBRE9XICkgPyBlbXB0eVNoYWRvd1RleHR1cmUgOiBlbXB0eVRleHR1cmU7XHJcblxyXG5cdHRleHR1cmVzLnNldFRleHR1cmUyRCggdiB8fCBlbXB0eVRleHR1cmUyRCwgdW5pdCApO1xyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gc2V0VmFsdWVUM0QxKCBnbCwgdiwgdGV4dHVyZXMgKSB7XHJcblxyXG5cdGNvbnN0IGNhY2hlID0gdGhpcy5jYWNoZTtcclxuXHRjb25zdCB1bml0ID0gdGV4dHVyZXMuYWxsb2NhdGVUZXh0dXJlVW5pdCgpO1xyXG5cclxuXHRpZiAoIGNhY2hlWyAwIF0gIT09IHVuaXQgKSB7XHJcblxyXG5cdFx0Z2wudW5pZm9ybTFpKCB0aGlzLmFkZHIsIHVuaXQgKTtcclxuXHRcdGNhY2hlWyAwIF0gPSB1bml0O1xyXG5cclxuXHR9XHJcblxyXG5cdHRleHR1cmVzLnNldFRleHR1cmUzRCggdiB8fCBlbXB0eTNkVGV4dHVyZSwgdW5pdCApO1xyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gc2V0VmFsdWVUNiggZ2wsIHYsIHRleHR1cmVzICkge1xyXG5cclxuXHRjb25zdCBjYWNoZSA9IHRoaXMuY2FjaGU7XHJcblx0Y29uc3QgdW5pdCA9IHRleHR1cmVzLmFsbG9jYXRlVGV4dHVyZVVuaXQoKTtcclxuXHJcblx0aWYgKCBjYWNoZVsgMCBdICE9PSB1bml0ICkge1xyXG5cclxuXHRcdGdsLnVuaWZvcm0xaSggdGhpcy5hZGRyLCB1bml0ICk7XHJcblx0XHRjYWNoZVsgMCBdID0gdW5pdDtcclxuXHJcblx0fVxyXG5cclxuXHR0ZXh0dXJlcy5zZXRUZXh0dXJlQ3ViZSggdiB8fCBlbXB0eUN1YmVUZXh0dXJlLCB1bml0ICk7XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiBzZXRWYWx1ZVQyREFycmF5MSggZ2wsIHYsIHRleHR1cmVzICkge1xyXG5cclxuXHRjb25zdCBjYWNoZSA9IHRoaXMuY2FjaGU7XHJcblx0Y29uc3QgdW5pdCA9IHRleHR1cmVzLmFsbG9jYXRlVGV4dHVyZVVuaXQoKTtcclxuXHJcblx0aWYgKCBjYWNoZVsgMCBdICE9PSB1bml0ICkge1xyXG5cclxuXHRcdGdsLnVuaWZvcm0xaSggdGhpcy5hZGRyLCB1bml0ICk7XHJcblx0XHRjYWNoZVsgMCBdID0gdW5pdDtcclxuXHJcblx0fVxyXG5cclxuXHR0ZXh0dXJlcy5zZXRUZXh0dXJlMkRBcnJheSggdiB8fCBlbXB0eUFycmF5VGV4dHVyZSwgdW5pdCApO1xyXG5cclxufVxyXG5cclxuLy8gSGVscGVyIHRvIHBpY2sgdGhlIHJpZ2h0IHNldHRlciBmb3IgdGhlIHNpbmd1bGFyIGNhc2VcclxuXHJcbmZ1bmN0aW9uIGdldFNpbmd1bGFyU2V0dGVyKCB0eXBlICkge1xyXG5cclxuXHRzd2l0Y2ggKCB0eXBlICkge1xyXG5cclxuXHRcdGNhc2UgMHgxNDA2OiByZXR1cm4gc2V0VmFsdWVWMWY7IC8vIEZMT0FUXHJcblx0XHRjYXNlIDB4OGI1MDogcmV0dXJuIHNldFZhbHVlVjJmOyAvLyBfVkVDMlxyXG5cdFx0Y2FzZSAweDhiNTE6IHJldHVybiBzZXRWYWx1ZVYzZjsgLy8gX1ZFQzNcclxuXHRcdGNhc2UgMHg4YjUyOiByZXR1cm4gc2V0VmFsdWVWNGY7IC8vIF9WRUM0XHJcblxyXG5cdFx0Y2FzZSAweDhiNWE6IHJldHVybiBzZXRWYWx1ZU0yOyAvLyBfTUFUMlxyXG5cdFx0Y2FzZSAweDhiNWI6IHJldHVybiBzZXRWYWx1ZU0zOyAvLyBfTUFUM1xyXG5cdFx0Y2FzZSAweDhiNWM6IHJldHVybiBzZXRWYWx1ZU00OyAvLyBfTUFUNFxyXG5cclxuXHRcdGNhc2UgMHgxNDA0OiBjYXNlIDB4OGI1NjogcmV0dXJuIHNldFZhbHVlVjFpOyAvLyBJTlQsIEJPT0xcclxuXHRcdGNhc2UgMHg4YjUzOiBjYXNlIDB4OGI1NzogcmV0dXJuIHNldFZhbHVlVjJpOyAvLyBfVkVDMlxyXG5cdFx0Y2FzZSAweDhiNTQ6IGNhc2UgMHg4YjU4OiByZXR1cm4gc2V0VmFsdWVWM2k7IC8vIF9WRUMzXHJcblx0XHRjYXNlIDB4OGI1NTogY2FzZSAweDhiNTk6IHJldHVybiBzZXRWYWx1ZVY0aTsgLy8gX1ZFQzRcclxuXHJcblx0XHRjYXNlIDB4MTQwNTogcmV0dXJuIHNldFZhbHVlVjF1aTsgLy8gVUlOVFxyXG5cdFx0Y2FzZSAweDhkYzY6IHJldHVybiBzZXRWYWx1ZVYydWk7IC8vIF9WRUMyXHJcblx0XHRjYXNlIDB4OGRjNzogcmV0dXJuIHNldFZhbHVlVjN1aTsgLy8gX1ZFQzNcclxuXHRcdGNhc2UgMHg4ZGM4OiByZXR1cm4gc2V0VmFsdWVWNHVpOyAvLyBfVkVDNFxyXG5cclxuXHRcdGNhc2UgMHg4YjVlOiAvLyBTQU1QTEVSXzJEXHJcblx0XHRjYXNlIDB4OGQ2NjogLy8gU0FNUExFUl9FWFRFUk5BTF9PRVNcclxuXHRcdGNhc2UgMHg4ZGNhOiAvLyBJTlRfU0FNUExFUl8yRFxyXG5cdFx0Y2FzZSAweDhkZDI6IC8vIFVOU0lHTkVEX0lOVF9TQU1QTEVSXzJEXHJcblx0XHRjYXNlIDB4OGI2MjogLy8gU0FNUExFUl8yRF9TSEFET1dcclxuXHRcdFx0cmV0dXJuIHNldFZhbHVlVDE7XHJcblxyXG5cdFx0Y2FzZSAweDhiNWY6IC8vIFNBTVBMRVJfM0RcclxuXHRcdGNhc2UgMHg4ZGNiOiAvLyBJTlRfU0FNUExFUl8zRFxyXG5cdFx0Y2FzZSAweDhkZDM6IC8vIFVOU0lHTkVEX0lOVF9TQU1QTEVSXzNEXHJcblx0XHRcdHJldHVybiBzZXRWYWx1ZVQzRDE7XHJcblxyXG5cdFx0Y2FzZSAweDhiNjA6IC8vIFNBTVBMRVJfQ1VCRVxyXG5cdFx0Y2FzZSAweDhkY2M6IC8vIElOVF9TQU1QTEVSX0NVQkVcclxuXHRcdGNhc2UgMHg4ZGQ0OiAvLyBVTlNJR05FRF9JTlRfU0FNUExFUl9DVUJFXHJcblx0XHRjYXNlIDB4OGRjNTogLy8gU0FNUExFUl9DVUJFX1NIQURPV1xyXG5cdFx0XHRyZXR1cm4gc2V0VmFsdWVUNjtcclxuXHJcblx0XHRjYXNlIDB4OGRjMTogLy8gU0FNUExFUl8yRF9BUlJBWVxyXG5cdFx0Y2FzZSAweDhkY2Y6IC8vIElOVF9TQU1QTEVSXzJEX0FSUkFZXHJcblx0XHRjYXNlIDB4OGRkNzogLy8gVU5TSUdORURfSU5UX1NBTVBMRVJfMkRfQVJSQVlcclxuXHRcdGNhc2UgMHg4ZGM0OiAvLyBTQU1QTEVSXzJEX0FSUkFZX1NIQURPV1xyXG5cdFx0XHRyZXR1cm4gc2V0VmFsdWVUMkRBcnJheTE7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcblxyXG4vLyBBcnJheSBvZiBzY2FsYXJzXHJcblxyXG5mdW5jdGlvbiBzZXRWYWx1ZVYxZkFycmF5KCBnbCwgdiApIHtcclxuXHJcblx0Z2wudW5pZm9ybTFmdiggdGhpcy5hZGRyLCB2ICk7XHJcblxyXG59XHJcblxyXG4vLyBBcnJheSBvZiB2ZWN0b3JzIChmcm9tIGZsYXQgYXJyYXkgb3IgYXJyYXkgb2YgVEhSRUUuVmVjdG9yTilcclxuXHJcbmZ1bmN0aW9uIHNldFZhbHVlVjJmQXJyYXkoIGdsLCB2ICkge1xyXG5cclxuXHRjb25zdCBkYXRhID0gZmxhdHRlbiggdiwgdGhpcy5zaXplLCAyICk7XHJcblxyXG5cdGdsLnVuaWZvcm0yZnYoIHRoaXMuYWRkciwgZGF0YSApO1xyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gc2V0VmFsdWVWM2ZBcnJheSggZ2wsIHYgKSB7XHJcblxyXG5cdGNvbnN0IGRhdGEgPSBmbGF0dGVuKCB2LCB0aGlzLnNpemUsIDMgKTtcclxuXHJcblx0Z2wudW5pZm9ybTNmdiggdGhpcy5hZGRyLCBkYXRhICk7XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiBzZXRWYWx1ZVY0ZkFycmF5KCBnbCwgdiApIHtcclxuXHJcblx0Y29uc3QgZGF0YSA9IGZsYXR0ZW4oIHYsIHRoaXMuc2l6ZSwgNCApO1xyXG5cclxuXHRnbC51bmlmb3JtNGZ2KCB0aGlzLmFkZHIsIGRhdGEgKTtcclxuXHJcbn1cclxuXHJcbi8vIEFycmF5IG9mIG1hdHJpY2VzIChmcm9tIGZsYXQgYXJyYXkgb3IgYXJyYXkgb2YgVEhSRUUuTWF0cml4TilcclxuXHJcbmZ1bmN0aW9uIHNldFZhbHVlTTJBcnJheSggZ2wsIHYgKSB7XHJcblxyXG5cdGNvbnN0IGRhdGEgPSBmbGF0dGVuKCB2LCB0aGlzLnNpemUsIDQgKTtcclxuXHJcblx0Z2wudW5pZm9ybU1hdHJpeDJmdiggdGhpcy5hZGRyLCBmYWxzZSwgZGF0YSApO1xyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gc2V0VmFsdWVNM0FycmF5KCBnbCwgdiApIHtcclxuXHJcblx0Y29uc3QgZGF0YSA9IGZsYXR0ZW4oIHYsIHRoaXMuc2l6ZSwgOSApO1xyXG5cclxuXHRnbC51bmlmb3JtTWF0cml4M2Z2KCB0aGlzLmFkZHIsIGZhbHNlLCBkYXRhICk7XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiBzZXRWYWx1ZU00QXJyYXkoIGdsLCB2ICkge1xyXG5cclxuXHRjb25zdCBkYXRhID0gZmxhdHRlbiggdiwgdGhpcy5zaXplLCAxNiApO1xyXG5cclxuXHRnbC51bmlmb3JtTWF0cml4NGZ2KCB0aGlzLmFkZHIsIGZhbHNlLCBkYXRhICk7XHJcblxyXG59XHJcblxyXG4vLyBBcnJheSBvZiBpbnRlZ2VyIC8gYm9vbGVhblxyXG5cclxuZnVuY3Rpb24gc2V0VmFsdWVWMWlBcnJheSggZ2wsIHYgKSB7XHJcblxyXG5cdGdsLnVuaWZvcm0xaXYoIHRoaXMuYWRkciwgdiApO1xyXG5cclxufVxyXG5cclxuLy8gQXJyYXkgb2YgaW50ZWdlciAvIGJvb2xlYW4gdmVjdG9ycyAoZnJvbSBmbGF0IGFycmF5KVxyXG5cclxuZnVuY3Rpb24gc2V0VmFsdWVWMmlBcnJheSggZ2wsIHYgKSB7XHJcblxyXG5cdGdsLnVuaWZvcm0yaXYoIHRoaXMuYWRkciwgdiApO1xyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gc2V0VmFsdWVWM2lBcnJheSggZ2wsIHYgKSB7XHJcblxyXG5cdGdsLnVuaWZvcm0zaXYoIHRoaXMuYWRkciwgdiApO1xyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gc2V0VmFsdWVWNGlBcnJheSggZ2wsIHYgKSB7XHJcblxyXG5cdGdsLnVuaWZvcm00aXYoIHRoaXMuYWRkciwgdiApO1xyXG5cclxufVxyXG5cclxuLy8gQXJyYXkgb2YgdW5zaWduZWQgaW50ZWdlclxyXG5cclxuZnVuY3Rpb24gc2V0VmFsdWVWMXVpQXJyYXkoIGdsLCB2ICkge1xyXG5cclxuXHRnbC51bmlmb3JtMXVpdiggdGhpcy5hZGRyLCB2ICk7XHJcblxyXG59XHJcblxyXG4vLyBBcnJheSBvZiB1bnNpZ25lZCBpbnRlZ2VyIHZlY3RvcnMgKGZyb20gZmxhdCBhcnJheSlcclxuXHJcbmZ1bmN0aW9uIHNldFZhbHVlVjJ1aUFycmF5KCBnbCwgdiApIHtcclxuXHJcblx0Z2wudW5pZm9ybTJ1aXYoIHRoaXMuYWRkciwgdiApO1xyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gc2V0VmFsdWVWM3VpQXJyYXkoIGdsLCB2ICkge1xyXG5cclxuXHRnbC51bmlmb3JtM3VpdiggdGhpcy5hZGRyLCB2ICk7XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiBzZXRWYWx1ZVY0dWlBcnJheSggZ2wsIHYgKSB7XHJcblxyXG5cdGdsLnVuaWZvcm00dWl2KCB0aGlzLmFkZHIsIHYgKTtcclxuXHJcbn1cclxuXHJcblxyXG4vLyBBcnJheSBvZiB0ZXh0dXJlcyAoMkQgLyAzRCAvIEN1YmUgLyAyREFycmF5KVxyXG5cclxuZnVuY3Rpb24gc2V0VmFsdWVUMUFycmF5KCBnbCwgdiwgdGV4dHVyZXMgKSB7XHJcblxyXG5cdGNvbnN0IGNhY2hlID0gdGhpcy5jYWNoZTtcclxuXHJcblx0Y29uc3QgbiA9IHYubGVuZ3RoO1xyXG5cclxuXHRjb25zdCB1bml0cyA9IGFsbG9jVGV4VW5pdHMoIHRleHR1cmVzLCBuICk7XHJcblxyXG5cdGlmICggISBhcnJheXNFcXVhbCggY2FjaGUsIHVuaXRzICkgKSB7XHJcblxyXG5cdFx0Z2wudW5pZm9ybTFpdiggdGhpcy5hZGRyLCB1bml0cyApO1xyXG5cclxuXHRcdGNvcHlBcnJheSggY2FjaGUsIHVuaXRzICk7XHJcblxyXG5cdH1cclxuXHJcblx0Zm9yICggbGV0IGkgPSAwOyBpICE9PSBuOyArKyBpICkge1xyXG5cclxuXHRcdHRleHR1cmVzLnNldFRleHR1cmUyRCggdlsgaSBdIHx8IGVtcHR5VGV4dHVyZSwgdW5pdHNbIGkgXSApO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiBzZXRWYWx1ZVQzREFycmF5KCBnbCwgdiwgdGV4dHVyZXMgKSB7XHJcblxyXG5cdGNvbnN0IGNhY2hlID0gdGhpcy5jYWNoZTtcclxuXHJcblx0Y29uc3QgbiA9IHYubGVuZ3RoO1xyXG5cclxuXHRjb25zdCB1bml0cyA9IGFsbG9jVGV4VW5pdHMoIHRleHR1cmVzLCBuICk7XHJcblxyXG5cdGlmICggISBhcnJheXNFcXVhbCggY2FjaGUsIHVuaXRzICkgKSB7XHJcblxyXG5cdFx0Z2wudW5pZm9ybTFpdiggdGhpcy5hZGRyLCB1bml0cyApO1xyXG5cclxuXHRcdGNvcHlBcnJheSggY2FjaGUsIHVuaXRzICk7XHJcblxyXG5cdH1cclxuXHJcblx0Zm9yICggbGV0IGkgPSAwOyBpICE9PSBuOyArKyBpICkge1xyXG5cclxuXHRcdHRleHR1cmVzLnNldFRleHR1cmUzRCggdlsgaSBdIHx8IGVtcHR5M2RUZXh0dXJlLCB1bml0c1sgaSBdICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmZ1bmN0aW9uIHNldFZhbHVlVDZBcnJheSggZ2wsIHYsIHRleHR1cmVzICkge1xyXG5cclxuXHRjb25zdCBjYWNoZSA9IHRoaXMuY2FjaGU7XHJcblxyXG5cdGNvbnN0IG4gPSB2Lmxlbmd0aDtcclxuXHJcblx0Y29uc3QgdW5pdHMgPSBhbGxvY1RleFVuaXRzKCB0ZXh0dXJlcywgbiApO1xyXG5cclxuXHRpZiAoICEgYXJyYXlzRXF1YWwoIGNhY2hlLCB1bml0cyApICkge1xyXG5cclxuXHRcdGdsLnVuaWZvcm0xaXYoIHRoaXMuYWRkciwgdW5pdHMgKTtcclxuXHJcblx0XHRjb3B5QXJyYXkoIGNhY2hlLCB1bml0cyApO1xyXG5cclxuXHR9XHJcblxyXG5cdGZvciAoIGxldCBpID0gMDsgaSAhPT0gbjsgKysgaSApIHtcclxuXHJcblx0XHR0ZXh0dXJlcy5zZXRUZXh0dXJlQ3ViZSggdlsgaSBdIHx8IGVtcHR5Q3ViZVRleHR1cmUsIHVuaXRzWyBpIF0gKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gc2V0VmFsdWVUMkRBcnJheUFycmF5KCBnbCwgdiwgdGV4dHVyZXMgKSB7XHJcblxyXG5cdGNvbnN0IGNhY2hlID0gdGhpcy5jYWNoZTtcclxuXHJcblx0Y29uc3QgbiA9IHYubGVuZ3RoO1xyXG5cclxuXHRjb25zdCB1bml0cyA9IGFsbG9jVGV4VW5pdHMoIHRleHR1cmVzLCBuICk7XHJcblxyXG5cdGlmICggISBhcnJheXNFcXVhbCggY2FjaGUsIHVuaXRzICkgKSB7XHJcblxyXG5cdFx0Z2wudW5pZm9ybTFpdiggdGhpcy5hZGRyLCB1bml0cyApO1xyXG5cclxuXHRcdGNvcHlBcnJheSggY2FjaGUsIHVuaXRzICk7XHJcblxyXG5cdH1cclxuXHJcblx0Zm9yICggbGV0IGkgPSAwOyBpICE9PSBuOyArKyBpICkge1xyXG5cclxuXHRcdHRleHR1cmVzLnNldFRleHR1cmUyREFycmF5KCB2WyBpIF0gfHwgZW1wdHlBcnJheVRleHR1cmUsIHVuaXRzWyBpIF0gKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuXHJcbi8vIEhlbHBlciB0byBwaWNrIHRoZSByaWdodCBzZXR0ZXIgZm9yIGEgcHVyZSAoYm90dG9tLWxldmVsKSBhcnJheVxyXG5cclxuZnVuY3Rpb24gZ2V0UHVyZUFycmF5U2V0dGVyKCB0eXBlICkge1xyXG5cclxuXHRzd2l0Y2ggKCB0eXBlICkge1xyXG5cclxuXHRcdGNhc2UgMHgxNDA2OiByZXR1cm4gc2V0VmFsdWVWMWZBcnJheTsgLy8gRkxPQVRcclxuXHRcdGNhc2UgMHg4YjUwOiByZXR1cm4gc2V0VmFsdWVWMmZBcnJheTsgLy8gX1ZFQzJcclxuXHRcdGNhc2UgMHg4YjUxOiByZXR1cm4gc2V0VmFsdWVWM2ZBcnJheTsgLy8gX1ZFQzNcclxuXHRcdGNhc2UgMHg4YjUyOiByZXR1cm4gc2V0VmFsdWVWNGZBcnJheTsgLy8gX1ZFQzRcclxuXHJcblx0XHRjYXNlIDB4OGI1YTogcmV0dXJuIHNldFZhbHVlTTJBcnJheTsgLy8gX01BVDJcclxuXHRcdGNhc2UgMHg4YjViOiByZXR1cm4gc2V0VmFsdWVNM0FycmF5OyAvLyBfTUFUM1xyXG5cdFx0Y2FzZSAweDhiNWM6IHJldHVybiBzZXRWYWx1ZU00QXJyYXk7IC8vIF9NQVQ0XHJcblxyXG5cdFx0Y2FzZSAweDE0MDQ6IGNhc2UgMHg4YjU2OiByZXR1cm4gc2V0VmFsdWVWMWlBcnJheTsgLy8gSU5ULCBCT09MXHJcblx0XHRjYXNlIDB4OGI1MzogY2FzZSAweDhiNTc6IHJldHVybiBzZXRWYWx1ZVYyaUFycmF5OyAvLyBfVkVDMlxyXG5cdFx0Y2FzZSAweDhiNTQ6IGNhc2UgMHg4YjU4OiByZXR1cm4gc2V0VmFsdWVWM2lBcnJheTsgLy8gX1ZFQzNcclxuXHRcdGNhc2UgMHg4YjU1OiBjYXNlIDB4OGI1OTogcmV0dXJuIHNldFZhbHVlVjRpQXJyYXk7IC8vIF9WRUM0XHJcblxyXG5cdFx0Y2FzZSAweDE0MDU6IHJldHVybiBzZXRWYWx1ZVYxdWlBcnJheTsgLy8gVUlOVFxyXG5cdFx0Y2FzZSAweDhkYzY6IHJldHVybiBzZXRWYWx1ZVYydWlBcnJheTsgLy8gX1ZFQzJcclxuXHRcdGNhc2UgMHg4ZGM3OiByZXR1cm4gc2V0VmFsdWVWM3VpQXJyYXk7IC8vIF9WRUMzXHJcblx0XHRjYXNlIDB4OGRjODogcmV0dXJuIHNldFZhbHVlVjR1aUFycmF5OyAvLyBfVkVDNFxyXG5cclxuXHRcdGNhc2UgMHg4YjVlOiAvLyBTQU1QTEVSXzJEXHJcblx0XHRjYXNlIDB4OGQ2NjogLy8gU0FNUExFUl9FWFRFUk5BTF9PRVNcclxuXHRcdGNhc2UgMHg4ZGNhOiAvLyBJTlRfU0FNUExFUl8yRFxyXG5cdFx0Y2FzZSAweDhkZDI6IC8vIFVOU0lHTkVEX0lOVF9TQU1QTEVSXzJEXHJcblx0XHRjYXNlIDB4OGI2MjogLy8gU0FNUExFUl8yRF9TSEFET1dcclxuXHRcdFx0cmV0dXJuIHNldFZhbHVlVDFBcnJheTtcclxuXHJcblx0XHRjYXNlIDB4OGI1ZjogLy8gU0FNUExFUl8zRFxyXG5cdFx0Y2FzZSAweDhkY2I6IC8vIElOVF9TQU1QTEVSXzNEXHJcblx0XHRjYXNlIDB4OGRkMzogLy8gVU5TSUdORURfSU5UX1NBTVBMRVJfM0RcclxuXHRcdFx0cmV0dXJuIHNldFZhbHVlVDNEQXJyYXk7XHJcblxyXG5cdFx0Y2FzZSAweDhiNjA6IC8vIFNBTVBMRVJfQ1VCRVxyXG5cdFx0Y2FzZSAweDhkY2M6IC8vIElOVF9TQU1QTEVSX0NVQkVcclxuXHRcdGNhc2UgMHg4ZGQ0OiAvLyBVTlNJR05FRF9JTlRfU0FNUExFUl9DVUJFXHJcblx0XHRjYXNlIDB4OGRjNTogLy8gU0FNUExFUl9DVUJFX1NIQURPV1xyXG5cdFx0XHRyZXR1cm4gc2V0VmFsdWVUNkFycmF5O1xyXG5cclxuXHRcdGNhc2UgMHg4ZGMxOiAvLyBTQU1QTEVSXzJEX0FSUkFZXHJcblx0XHRjYXNlIDB4OGRjZjogLy8gSU5UX1NBTVBMRVJfMkRfQVJSQVlcclxuXHRcdGNhc2UgMHg4ZGQ3OiAvLyBVTlNJR05FRF9JTlRfU0FNUExFUl8yRF9BUlJBWVxyXG5cdFx0Y2FzZSAweDhkYzQ6IC8vIFNBTVBMRVJfMkRfQVJSQVlfU0hBRE9XXHJcblx0XHRcdHJldHVybiBzZXRWYWx1ZVQyREFycmF5QXJyYXk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbi8vIC0tLSBVbmlmb3JtIENsYXNzZXMgLS0tXHJcblxyXG5jbGFzcyBTaW5nbGVVbmlmb3JtIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIGlkLCBhY3RpdmVJbmZvLCBhZGRyICkge1xyXG5cclxuXHRcdHRoaXMuaWQgPSBpZDtcclxuXHRcdHRoaXMuYWRkciA9IGFkZHI7XHJcblx0XHR0aGlzLmNhY2hlID0gW107XHJcblx0XHR0aGlzLnR5cGUgPSBhY3RpdmVJbmZvLnR5cGU7XHJcblx0XHR0aGlzLnNldFZhbHVlID0gZ2V0U2luZ3VsYXJTZXR0ZXIoIGFjdGl2ZUluZm8udHlwZSApO1xyXG5cclxuXHRcdC8vIHRoaXMucGF0aCA9IGFjdGl2ZUluZm8ubmFtZTsgLy8gREVCVUdcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuY2xhc3MgUHVyZUFycmF5VW5pZm9ybSB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBpZCwgYWN0aXZlSW5mbywgYWRkciApIHtcclxuXHJcblx0XHR0aGlzLmlkID0gaWQ7XHJcblx0XHR0aGlzLmFkZHIgPSBhZGRyO1xyXG5cdFx0dGhpcy5jYWNoZSA9IFtdO1xyXG5cdFx0dGhpcy50eXBlID0gYWN0aXZlSW5mby50eXBlO1xyXG5cdFx0dGhpcy5zaXplID0gYWN0aXZlSW5mby5zaXplO1xyXG5cdFx0dGhpcy5zZXRWYWx1ZSA9IGdldFB1cmVBcnJheVNldHRlciggYWN0aXZlSW5mby50eXBlICk7XHJcblxyXG5cdFx0Ly8gdGhpcy5wYXRoID0gYWN0aXZlSW5mby5uYW1lOyAvLyBERUJVR1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5jbGFzcyBTdHJ1Y3R1cmVkVW5pZm9ybSB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBpZCApIHtcclxuXHJcblx0XHR0aGlzLmlkID0gaWQ7XHJcblxyXG5cdFx0dGhpcy5zZXEgPSBbXTtcclxuXHRcdHRoaXMubWFwID0ge307XHJcblxyXG5cdH1cclxuXHJcblx0c2V0VmFsdWUoIGdsLCB2YWx1ZSwgdGV4dHVyZXMgKSB7XHJcblxyXG5cdFx0Y29uc3Qgc2VxID0gdGhpcy5zZXE7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBuID0gc2VxLmxlbmd0aDsgaSAhPT0gbjsgKysgaSApIHtcclxuXHJcblx0XHRcdGNvbnN0IHUgPSBzZXFbIGkgXTtcclxuXHRcdFx0dS5zZXRWYWx1ZSggZ2wsIHZhbHVlWyB1LmlkIF0sIHRleHR1cmVzICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG4vLyAtLS0gVG9wLWxldmVsIC0tLVxyXG5cclxuLy8gUGFyc2VyIC0gYnVpbGRzIHVwIHRoZSBwcm9wZXJ0eSB0cmVlIGZyb20gdGhlIHBhdGggc3RyaW5nc1xyXG5cclxuY29uc3QgUmVQYXRoUGFydCA9IC8oXFx3KykoXFxdKT8oXFxbfFxcLik/L2c7XHJcblxyXG4vLyBleHRyYWN0c1xyXG4vLyBcdC0gdGhlIGlkZW50aWZpZXIgKG1lbWJlciBuYW1lIG9yIGFycmF5IGluZGV4KVxyXG4vLyAgLSBmb2xsb3dlZCBieSBhbiBvcHRpb25hbCByaWdodCBicmFja2V0IChmb3VuZCB3aGVuIGFycmF5IGluZGV4KVxyXG4vLyAgLSBmb2xsb3dlZCBieSBhbiBvcHRpb25hbCBsZWZ0IGJyYWNrZXQgb3IgZG90ICh0eXBlIG9mIHN1YnNjcmlwdClcclxuLy9cclxuLy8gTm90ZTogVGhlc2UgcG9ydGlvbnMgY2FuIGJlIHJlYWQgaW4gYSBub24tb3ZlcmxhcHBpbmcgZmFzaGlvbiBhbmRcclxuLy8gYWxsb3cgc3RyYWlnaHRmb3J3YXJkIHBhcnNpbmcgb2YgdGhlIGhpZXJhcmNoeSB0aGF0IFdlYkdMIGVuY29kZXNcclxuLy8gaW4gdGhlIHVuaWZvcm0gbmFtZXMuXHJcblxyXG5mdW5jdGlvbiBhZGRVbmlmb3JtKCBjb250YWluZXIsIHVuaWZvcm1PYmplY3QgKSB7XHJcblxyXG5cdGNvbnRhaW5lci5zZXEucHVzaCggdW5pZm9ybU9iamVjdCApO1xyXG5cdGNvbnRhaW5lci5tYXBbIHVuaWZvcm1PYmplY3QuaWQgXSA9IHVuaWZvcm1PYmplY3Q7XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiBwYXJzZVVuaWZvcm0oIGFjdGl2ZUluZm8sIGFkZHIsIGNvbnRhaW5lciApIHtcclxuXHJcblx0Y29uc3QgcGF0aCA9IGFjdGl2ZUluZm8ubmFtZSxcclxuXHRcdHBhdGhMZW5ndGggPSBwYXRoLmxlbmd0aDtcclxuXHJcblx0Ly8gcmVzZXQgUmVnRXhwIG9iamVjdCwgYmVjYXVzZSBvZiB0aGUgZWFybHkgZXhpdCBvZiBhIHByZXZpb3VzIHJ1blxyXG5cdFJlUGF0aFBhcnQubGFzdEluZGV4ID0gMDtcclxuXHJcblx0d2hpbGUgKCB0cnVlICkge1xyXG5cclxuXHRcdGNvbnN0IG1hdGNoID0gUmVQYXRoUGFydC5leGVjKCBwYXRoICksXHJcblx0XHRcdG1hdGNoRW5kID0gUmVQYXRoUGFydC5sYXN0SW5kZXg7XHJcblxyXG5cdFx0bGV0IGlkID0gbWF0Y2hbIDEgXTtcclxuXHRcdGNvbnN0IGlkSXNJbmRleCA9IG1hdGNoWyAyIF0gPT09ICddJyxcclxuXHRcdFx0c3Vic2NyaXB0ID0gbWF0Y2hbIDMgXTtcclxuXHJcblx0XHRpZiAoIGlkSXNJbmRleCApIGlkID0gaWQgfCAwOyAvLyBjb252ZXJ0IHRvIGludGVnZXJcclxuXHJcblx0XHRpZiAoIHN1YnNjcmlwdCA9PT0gdW5kZWZpbmVkIHx8IHN1YnNjcmlwdCA9PT0gJ1snICYmIG1hdGNoRW5kICsgMiA9PT0gcGF0aExlbmd0aCApIHtcclxuXHJcblx0XHRcdC8vIGJhcmUgbmFtZSBvciBcInB1cmVcIiBib3R0b20tbGV2ZWwgYXJyYXkgXCJbMF1cIiBzdWZmaXhcclxuXHJcblx0XHRcdGFkZFVuaWZvcm0oIGNvbnRhaW5lciwgc3Vic2NyaXB0ID09PSB1bmRlZmluZWQgP1xyXG5cdFx0XHRcdG5ldyBTaW5nbGVVbmlmb3JtKCBpZCwgYWN0aXZlSW5mbywgYWRkciApIDpcclxuXHRcdFx0XHRuZXcgUHVyZUFycmF5VW5pZm9ybSggaWQsIGFjdGl2ZUluZm8sIGFkZHIgKSApO1xyXG5cclxuXHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdC8vIHN0ZXAgaW50byBpbm5lciBub2RlIC8gY3JlYXRlIGl0IGluIGNhc2UgaXQgZG9lc24ndCBleGlzdFxyXG5cclxuXHRcdFx0Y29uc3QgbWFwID0gY29udGFpbmVyLm1hcDtcclxuXHRcdFx0bGV0IG5leHQgPSBtYXBbIGlkIF07XHJcblxyXG5cdFx0XHRpZiAoIG5leHQgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0bmV4dCA9IG5ldyBTdHJ1Y3R1cmVkVW5pZm9ybSggaWQgKTtcclxuXHRcdFx0XHRhZGRVbmlmb3JtKCBjb250YWluZXIsIG5leHQgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGNvbnRhaW5lciA9IG5leHQ7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG4vLyBSb290IENvbnRhaW5lclxyXG5cclxuY2xhc3MgV2ViR0xVbmlmb3JtcyB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBnbCwgcHJvZ3JhbSApIHtcclxuXHJcblx0XHR0aGlzLnNlcSA9IFtdO1xyXG5cdFx0dGhpcy5tYXAgPSB7fTtcclxuXHJcblx0XHRjb25zdCBuID0gZ2wuZ2V0UHJvZ3JhbVBhcmFtZXRlciggcHJvZ3JhbSwgZ2wuQUNUSVZFX1VOSUZPUk1TICk7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgbjsgKysgaSApIHtcclxuXHJcblx0XHRcdGNvbnN0IGluZm8gPSBnbC5nZXRBY3RpdmVVbmlmb3JtKCBwcm9ncmFtLCBpICksXHJcblx0XHRcdFx0YWRkciA9IGdsLmdldFVuaWZvcm1Mb2NhdGlvbiggcHJvZ3JhbSwgaW5mby5uYW1lICk7XHJcblxyXG5cdFx0XHRwYXJzZVVuaWZvcm0oIGluZm8sIGFkZHIsIHRoaXMgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0c2V0VmFsdWUoIGdsLCBuYW1lLCB2YWx1ZSwgdGV4dHVyZXMgKSB7XHJcblxyXG5cdFx0Y29uc3QgdSA9IHRoaXMubWFwWyBuYW1lIF07XHJcblxyXG5cdFx0aWYgKCB1ICE9PSB1bmRlZmluZWQgKSB1LnNldFZhbHVlKCBnbCwgdmFsdWUsIHRleHR1cmVzICk7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0T3B0aW9uYWwoIGdsLCBvYmplY3QsIG5hbWUgKSB7XHJcblxyXG5cdFx0Y29uc3QgdiA9IG9iamVjdFsgbmFtZSBdO1xyXG5cclxuXHRcdGlmICggdiAhPT0gdW5kZWZpbmVkICkgdGhpcy5zZXRWYWx1ZSggZ2wsIG5hbWUsIHYgKTtcclxuXHJcblx0fVxyXG5cclxuXHRzdGF0aWMgdXBsb2FkKCBnbCwgc2VxLCB2YWx1ZXMsIHRleHR1cmVzICkge1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMCwgbiA9IHNlcS5sZW5ndGg7IGkgIT09IG47ICsrIGkgKSB7XHJcblxyXG5cdFx0XHRjb25zdCB1ID0gc2VxWyBpIF0sXHJcblx0XHRcdFx0diA9IHZhbHVlc1sgdS5pZCBdO1xyXG5cclxuXHRcdFx0aWYgKCB2Lm5lZWRzVXBkYXRlICE9PSBmYWxzZSApIHtcclxuXHJcblx0XHRcdFx0Ly8gbm90ZTogYWx3YXlzIHVwZGF0aW5nIHdoZW4gLm5lZWRzVXBkYXRlIGlzIHVuZGVmaW5lZFxyXG5cdFx0XHRcdHUuc2V0VmFsdWUoIGdsLCB2LnZhbHVlLCB0ZXh0dXJlcyApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRzdGF0aWMgc2VxV2l0aFZhbHVlKCBzZXEsIHZhbHVlcyApIHtcclxuXHJcblx0XHRjb25zdCByID0gW107XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBuID0gc2VxLmxlbmd0aDsgaSAhPT0gbjsgKysgaSApIHtcclxuXHJcblx0XHRcdGNvbnN0IHUgPSBzZXFbIGkgXTtcclxuXHRcdFx0aWYgKCB1LmlkIGluIHZhbHVlcyApIHIucHVzaCggdSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gcjtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgV2ViR0xVbmlmb3JtcyB9O1xyXG4iLCJmdW5jdGlvbiBXZWJHTFNoYWRlciggZ2wsIHR5cGUsIHN0cmluZyApIHtcclxuXHJcblx0Y29uc3Qgc2hhZGVyID0gZ2wuY3JlYXRlU2hhZGVyKCB0eXBlICk7XHJcblxyXG5cdGdsLnNoYWRlclNvdXJjZSggc2hhZGVyLCBzdHJpbmcgKTtcclxuXHRnbC5jb21waWxlU2hhZGVyKCBzaGFkZXIgKTtcclxuXHJcblx0cmV0dXJuIHNoYWRlcjtcclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IFdlYkdMU2hhZGVyIH07XHJcbiIsImltcG9ydCB7IFdlYkdMVW5pZm9ybXMgfSBmcm9tICcuL1dlYkdMVW5pZm9ybXMuanMnO1xyXG5pbXBvcnQgeyBXZWJHTFNoYWRlciB9IGZyb20gJy4vV2ViR0xTaGFkZXIuanMnO1xyXG5pbXBvcnQgeyBTaGFkZXJDaHVuayB9IGZyb20gJy4uL3NoYWRlcnMvU2hhZGVyQ2h1bmsuanMnO1xyXG5pbXBvcnQgeyBOb1RvbmVNYXBwaW5nLCBBZGRPcGVyYXRpb24sIE1peE9wZXJhdGlvbiwgTXVsdGlwbHlPcGVyYXRpb24sIEN1YmVSZWZyYWN0aW9uTWFwcGluZywgQ3ViZVVWUmVmbGVjdGlvbk1hcHBpbmcsIEN1YmVSZWZsZWN0aW9uTWFwcGluZywgUENGU29mdFNoYWRvd01hcCwgUENGU2hhZG93TWFwLCBWU01TaGFkb3dNYXAsIEFnWFRvbmVNYXBwaW5nLCBBQ0VTRmlsbWljVG9uZU1hcHBpbmcsIENpbmVvblRvbmVNYXBwaW5nLCBDdXN0b21Ub25lTWFwcGluZywgUmVpbmhhcmRUb25lTWFwcGluZywgTGluZWFyVG9uZU1hcHBpbmcsIEdMU0wzLCBMaW5lYXJTUkdCQ29sb3JTcGFjZSwgU1JHQkNvbG9yU3BhY2UsIExpbmVhckRpc3BsYXlQM0NvbG9yU3BhY2UsIERpc3BsYXlQM0NvbG9yU3BhY2UsIFAzUHJpbWFyaWVzLCBSZWM3MDlQcmltYXJpZXMgfSBmcm9tICcuLi8uLi9jb25zdGFudHMuanMnO1xyXG5pbXBvcnQgeyBDb2xvck1hbmFnZW1lbnQgfSBmcm9tICcuLi8uLi9tYXRoL0NvbG9yTWFuYWdlbWVudC5qcyc7XHJcblxyXG4vLyBGcm9tIGh0dHBzOi8vd3d3Lmtocm9ub3Mub3JnL3JlZ2lzdHJ5L3dlYmdsL2V4dGVuc2lvbnMvS0hSX3BhcmFsbGVsX3NoYWRlcl9jb21waWxlL1xyXG5jb25zdCBDT01QTEVUSU9OX1NUQVRVU19LSFIgPSAweDkxQjE7XHJcblxyXG5sZXQgcHJvZ3JhbUlkQ291bnQgPSAwO1xyXG5cclxuZnVuY3Rpb24gaGFuZGxlU291cmNlKCBzdHJpbmcsIGVycm9yTGluZSApIHtcclxuXHJcblx0Y29uc3QgbGluZXMgPSBzdHJpbmcuc3BsaXQoICdcXG4nICk7XHJcblx0Y29uc3QgbGluZXMyID0gW107XHJcblxyXG5cdGNvbnN0IGZyb20gPSBNYXRoLm1heCggZXJyb3JMaW5lIC0gNiwgMCApO1xyXG5cdGNvbnN0IHRvID0gTWF0aC5taW4oIGVycm9yTGluZSArIDYsIGxpbmVzLmxlbmd0aCApO1xyXG5cclxuXHRmb3IgKCBsZXQgaSA9IGZyb207IGkgPCB0bzsgaSArKyApIHtcclxuXHJcblx0XHRjb25zdCBsaW5lID0gaSArIDE7XHJcblx0XHRsaW5lczIucHVzaCggYCR7bGluZSA9PT0gZXJyb3JMaW5lID8gJz4nIDogJyAnfSAke2xpbmV9OiAke2xpbmVzWyBpIF19YCApO1xyXG5cclxuXHR9XHJcblxyXG5cdHJldHVybiBsaW5lczIuam9pbiggJ1xcbicgKTtcclxuXHJcbn1cclxuXHJcbmZ1bmN0aW9uIGdldEVuY29kaW5nQ29tcG9uZW50cyggY29sb3JTcGFjZSApIHtcclxuXHJcblx0Y29uc3Qgd29ya2luZ1ByaW1hcmllcyA9IENvbG9yTWFuYWdlbWVudC5nZXRQcmltYXJpZXMoIENvbG9yTWFuYWdlbWVudC53b3JraW5nQ29sb3JTcGFjZSApO1xyXG5cdGNvbnN0IGVuY29kaW5nUHJpbWFyaWVzID0gQ29sb3JNYW5hZ2VtZW50LmdldFByaW1hcmllcyggY29sb3JTcGFjZSApO1xyXG5cclxuXHRsZXQgZ2FtdXRNYXBwaW5nO1xyXG5cclxuXHRpZiAoIHdvcmtpbmdQcmltYXJpZXMgPT09IGVuY29kaW5nUHJpbWFyaWVzICkge1xyXG5cclxuXHRcdGdhbXV0TWFwcGluZyA9ICcnO1xyXG5cclxuXHR9IGVsc2UgaWYgKCB3b3JraW5nUHJpbWFyaWVzID09PSBQM1ByaW1hcmllcyAmJiBlbmNvZGluZ1ByaW1hcmllcyA9PT0gUmVjNzA5UHJpbWFyaWVzICkge1xyXG5cclxuXHRcdGdhbXV0TWFwcGluZyA9ICdMaW5lYXJEaXNwbGF5UDNUb0xpbmVhclNSR0InO1xyXG5cclxuXHR9IGVsc2UgaWYgKCB3b3JraW5nUHJpbWFyaWVzID09PSBSZWM3MDlQcmltYXJpZXMgJiYgZW5jb2RpbmdQcmltYXJpZXMgPT09IFAzUHJpbWFyaWVzICkge1xyXG5cclxuXHRcdGdhbXV0TWFwcGluZyA9ICdMaW5lYXJTUkdCVG9MaW5lYXJEaXNwbGF5UDMnO1xyXG5cclxuXHR9XHJcblxyXG5cdHN3aXRjaCAoIGNvbG9yU3BhY2UgKSB7XHJcblxyXG5cdFx0Y2FzZSBMaW5lYXJTUkdCQ29sb3JTcGFjZTpcclxuXHRcdGNhc2UgTGluZWFyRGlzcGxheVAzQ29sb3JTcGFjZTpcclxuXHRcdFx0cmV0dXJuIFsgZ2FtdXRNYXBwaW5nLCAnTGluZWFyVHJhbnNmZXJPRVRGJyBdO1xyXG5cclxuXHRcdGNhc2UgU1JHQkNvbG9yU3BhY2U6XHJcblx0XHRjYXNlIERpc3BsYXlQM0NvbG9yU3BhY2U6XHJcblx0XHRcdHJldHVybiBbIGdhbXV0TWFwcGluZywgJ3NSR0JUcmFuc2Zlck9FVEYnIF07XHJcblxyXG5cdFx0ZGVmYXVsdDpcclxuXHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuV2ViR0xQcm9ncmFtOiBVbnN1cHBvcnRlZCBjb2xvciBzcGFjZTonLCBjb2xvclNwYWNlICk7XHJcblx0XHRcdHJldHVybiBbIGdhbXV0TWFwcGluZywgJ0xpbmVhclRyYW5zZmVyT0VURicgXTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gZ2V0U2hhZGVyRXJyb3JzKCBnbCwgc2hhZGVyLCB0eXBlICkge1xyXG5cclxuXHRjb25zdCBzdGF0dXMgPSBnbC5nZXRTaGFkZXJQYXJhbWV0ZXIoIHNoYWRlciwgZ2wuQ09NUElMRV9TVEFUVVMgKTtcclxuXHRjb25zdCBlcnJvcnMgPSBnbC5nZXRTaGFkZXJJbmZvTG9nKCBzaGFkZXIgKS50cmltKCk7XHJcblxyXG5cdGlmICggc3RhdHVzICYmIGVycm9ycyA9PT0gJycgKSByZXR1cm4gJyc7XHJcblxyXG5cdGNvbnN0IGVycm9yTWF0Y2hlcyA9IC9FUlJPUjogMDooXFxkKykvLmV4ZWMoIGVycm9ycyApO1xyXG5cdGlmICggZXJyb3JNYXRjaGVzICkge1xyXG5cclxuXHRcdC8vIC0tZW5hYmxlLXByaXZpbGVnZWQtd2ViZ2wtZXh0ZW5zaW9uXHJcblx0XHQvLyBjb25zb2xlLmxvZyggJyoqJyArIHR5cGUgKyAnKionLCBnbC5nZXRFeHRlbnNpb24oICdXRUJHTF9kZWJ1Z19zaGFkZXJzJyApLmdldFRyYW5zbGF0ZWRTaGFkZXJTb3VyY2UoIHNoYWRlciApICk7XHJcblxyXG5cdFx0Y29uc3QgZXJyb3JMaW5lID0gcGFyc2VJbnQoIGVycm9yTWF0Y2hlc1sgMSBdICk7XHJcblx0XHRyZXR1cm4gdHlwZS50b1VwcGVyQ2FzZSgpICsgJ1xcblxcbicgKyBlcnJvcnMgKyAnXFxuXFxuJyArIGhhbmRsZVNvdXJjZSggZ2wuZ2V0U2hhZGVyU291cmNlKCBzaGFkZXIgKSwgZXJyb3JMaW5lICk7XHJcblxyXG5cdH0gZWxzZSB7XHJcblxyXG5cdFx0cmV0dXJuIGVycm9ycztcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gZ2V0VGV4ZWxFbmNvZGluZ0Z1bmN0aW9uKCBmdW5jdGlvbk5hbWUsIGNvbG9yU3BhY2UgKSB7XHJcblxyXG5cdGNvbnN0IGNvbXBvbmVudHMgPSBnZXRFbmNvZGluZ0NvbXBvbmVudHMoIGNvbG9yU3BhY2UgKTtcclxuXHRyZXR1cm4gYHZlYzQgJHtmdW5jdGlvbk5hbWV9KCB2ZWM0IHZhbHVlICkgeyByZXR1cm4gJHtjb21wb25lbnRzWyAwIF19KCAke2NvbXBvbmVudHNbIDEgXX0oIHZhbHVlICkgKTsgfWA7XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiBnZXRUb25lTWFwcGluZ0Z1bmN0aW9uKCBmdW5jdGlvbk5hbWUsIHRvbmVNYXBwaW5nICkge1xyXG5cclxuXHRsZXQgdG9uZU1hcHBpbmdOYW1lO1xyXG5cclxuXHRzd2l0Y2ggKCB0b25lTWFwcGluZyApIHtcclxuXHJcblx0XHRjYXNlIExpbmVhclRvbmVNYXBwaW5nOlxyXG5cdFx0XHR0b25lTWFwcGluZ05hbWUgPSAnTGluZWFyJztcclxuXHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0Y2FzZSBSZWluaGFyZFRvbmVNYXBwaW5nOlxyXG5cdFx0XHR0b25lTWFwcGluZ05hbWUgPSAnUmVpbmhhcmQnO1xyXG5cdFx0XHRicmVhaztcclxuXHJcblx0XHRjYXNlIENpbmVvblRvbmVNYXBwaW5nOlxyXG5cdFx0XHR0b25lTWFwcGluZ05hbWUgPSAnT3B0aW1pemVkQ2luZW9uJztcclxuXHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0Y2FzZSBBQ0VTRmlsbWljVG9uZU1hcHBpbmc6XHJcblx0XHRcdHRvbmVNYXBwaW5nTmFtZSA9ICdBQ0VTRmlsbWljJztcclxuXHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0Y2FzZSBBZ1hUb25lTWFwcGluZzpcclxuXHRcdFx0dG9uZU1hcHBpbmdOYW1lID0gJ0FnWCc7XHJcblx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdGNhc2UgQ3VzdG9tVG9uZU1hcHBpbmc6XHJcblx0XHRcdHRvbmVNYXBwaW5nTmFtZSA9ICdDdXN0b20nO1xyXG5cdFx0XHRicmVhaztcclxuXHJcblx0XHRkZWZhdWx0OlxyXG5cdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5XZWJHTFByb2dyYW06IFVuc3VwcG9ydGVkIHRvbmVNYXBwaW5nOicsIHRvbmVNYXBwaW5nICk7XHJcblx0XHRcdHRvbmVNYXBwaW5nTmFtZSA9ICdMaW5lYXInO1xyXG5cclxuXHR9XHJcblxyXG5cdHJldHVybiAndmVjMyAnICsgZnVuY3Rpb25OYW1lICsgJyggdmVjMyBjb2xvciApIHsgcmV0dXJuICcgKyB0b25lTWFwcGluZ05hbWUgKyAnVG9uZU1hcHBpbmcoIGNvbG9yICk7IH0nO1xyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gZ2VuZXJhdGVFeHRlbnNpb25zKCBwYXJhbWV0ZXJzICkge1xyXG5cclxuXHRjb25zdCBjaHVua3MgPSBbXHJcblx0XHQoIHBhcmFtZXRlcnMuZXh0ZW5zaW9uRGVyaXZhdGl2ZXMgfHwgISEgcGFyYW1ldGVycy5lbnZNYXBDdWJlVVZIZWlnaHQgfHwgcGFyYW1ldGVycy5idW1wTWFwIHx8IHBhcmFtZXRlcnMubm9ybWFsTWFwVGFuZ2VudFNwYWNlIHx8IHBhcmFtZXRlcnMuY2xlYXJjb2F0Tm9ybWFsTWFwIHx8IHBhcmFtZXRlcnMuZmxhdFNoYWRpbmcgfHwgcGFyYW1ldGVycy5hbHBoYVRvQ292ZXJhZ2UgfHwgcGFyYW1ldGVycy5zaGFkZXJJRCA9PT0gJ3BoeXNpY2FsJyApID8gJyNleHRlbnNpb24gR0xfT0VTX3N0YW5kYXJkX2Rlcml2YXRpdmVzIDogZW5hYmxlJyA6ICcnLFxyXG5cdFx0KCBwYXJhbWV0ZXJzLmV4dGVuc2lvbkZyYWdEZXB0aCB8fCBwYXJhbWV0ZXJzLmxvZ2FyaXRobWljRGVwdGhCdWZmZXIgKSAmJiBwYXJhbWV0ZXJzLnJlbmRlcmVyRXh0ZW5zaW9uRnJhZ0RlcHRoID8gJyNleHRlbnNpb24gR0xfRVhUX2ZyYWdfZGVwdGggOiBlbmFibGUnIDogJycsXHJcblx0XHQoIHBhcmFtZXRlcnMuZXh0ZW5zaW9uRHJhd0J1ZmZlcnMgJiYgcGFyYW1ldGVycy5yZW5kZXJlckV4dGVuc2lvbkRyYXdCdWZmZXJzICkgPyAnI2V4dGVuc2lvbiBHTF9FWFRfZHJhd19idWZmZXJzIDogcmVxdWlyZScgOiAnJyxcclxuXHRcdCggcGFyYW1ldGVycy5leHRlbnNpb25TaGFkZXJUZXh0dXJlTE9EIHx8IHBhcmFtZXRlcnMuZW52TWFwIHx8IHBhcmFtZXRlcnMudHJhbnNtaXNzaW9uICkgJiYgcGFyYW1ldGVycy5yZW5kZXJlckV4dGVuc2lvblNoYWRlclRleHR1cmVMb2QgPyAnI2V4dGVuc2lvbiBHTF9FWFRfc2hhZGVyX3RleHR1cmVfbG9kIDogZW5hYmxlJyA6ICcnXHJcblx0XTtcclxuXHJcblx0cmV0dXJuIGNodW5rcy5maWx0ZXIoIGZpbHRlckVtcHR5TGluZSApLmpvaW4oICdcXG4nICk7XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiBnZW5lcmF0ZVZlcnRleEV4dGVuc2lvbnMoIHBhcmFtZXRlcnMgKSB7XHJcblxyXG5cdGNvbnN0IGNodW5rcyA9IFtcclxuXHRcdHBhcmFtZXRlcnMuZXh0ZW5zaW9uQ2xpcEN1bGxEaXN0YW5jZSA/ICcjZXh0ZW5zaW9uIEdMX0FOR0xFX2NsaXBfY3VsbF9kaXN0YW5jZSA6IHJlcXVpcmUnIDogJycsXHJcblx0XHRwYXJhbWV0ZXJzLmV4dGVuc2lvbk11bHRpRHJhdyA/ICcjZXh0ZW5zaW9uIEdMX0FOR0xFX211bHRpX2RyYXcgOiByZXF1aXJlJyA6ICcnLFxyXG5cdF07XHJcblxyXG5cdHJldHVybiBjaHVua3MuZmlsdGVyKCBmaWx0ZXJFbXB0eUxpbmUgKS5qb2luKCAnXFxuJyApO1xyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gZ2VuZXJhdGVEZWZpbmVzKCBkZWZpbmVzICkge1xyXG5cclxuXHRjb25zdCBjaHVua3MgPSBbXTtcclxuXHJcblx0Zm9yICggY29uc3QgbmFtZSBpbiBkZWZpbmVzICkge1xyXG5cclxuXHRcdGNvbnN0IHZhbHVlID0gZGVmaW5lc1sgbmFtZSBdO1xyXG5cclxuXHRcdGlmICggdmFsdWUgPT09IGZhbHNlICkgY29udGludWU7XHJcblxyXG5cdFx0Y2h1bmtzLnB1c2goICcjZGVmaW5lICcgKyBuYW1lICsgJyAnICsgdmFsdWUgKTtcclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4gY2h1bmtzLmpvaW4oICdcXG4nICk7XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiBmZXRjaEF0dHJpYnV0ZUxvY2F0aW9ucyggZ2wsIHByb2dyYW0gKSB7XHJcblxyXG5cdGNvbnN0IGF0dHJpYnV0ZXMgPSB7fTtcclxuXHJcblx0Y29uc3QgbiA9IGdsLmdldFByb2dyYW1QYXJhbWV0ZXIoIHByb2dyYW0sIGdsLkFDVElWRV9BVFRSSUJVVEVTICk7XHJcblxyXG5cdGZvciAoIGxldCBpID0gMDsgaSA8IG47IGkgKysgKSB7XHJcblxyXG5cdFx0Y29uc3QgaW5mbyA9IGdsLmdldEFjdGl2ZUF0dHJpYiggcHJvZ3JhbSwgaSApO1xyXG5cdFx0Y29uc3QgbmFtZSA9IGluZm8ubmFtZTtcclxuXHJcblx0XHRsZXQgbG9jYXRpb25TaXplID0gMTtcclxuXHRcdGlmICggaW5mby50eXBlID09PSBnbC5GTE9BVF9NQVQyICkgbG9jYXRpb25TaXplID0gMjtcclxuXHRcdGlmICggaW5mby50eXBlID09PSBnbC5GTE9BVF9NQVQzICkgbG9jYXRpb25TaXplID0gMztcclxuXHRcdGlmICggaW5mby50eXBlID09PSBnbC5GTE9BVF9NQVQ0ICkgbG9jYXRpb25TaXplID0gNDtcclxuXHJcblx0XHQvLyBjb25zb2xlLmxvZyggJ1RIUkVFLldlYkdMUHJvZ3JhbTogQUNUSVZFIFZFUlRFWCBBVFRSSUJVVEU6JywgbmFtZSwgaSApO1xyXG5cclxuXHRcdGF0dHJpYnV0ZXNbIG5hbWUgXSA9IHtcclxuXHRcdFx0dHlwZTogaW5mby50eXBlLFxyXG5cdFx0XHRsb2NhdGlvbjogZ2wuZ2V0QXR0cmliTG9jYXRpb24oIHByb2dyYW0sIG5hbWUgKSxcclxuXHRcdFx0bG9jYXRpb25TaXplOiBsb2NhdGlvblNpemVcclxuXHRcdH07XHJcblxyXG5cdH1cclxuXHJcblx0cmV0dXJuIGF0dHJpYnV0ZXM7XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiBmaWx0ZXJFbXB0eUxpbmUoIHN0cmluZyApIHtcclxuXHJcblx0cmV0dXJuIHN0cmluZyAhPT0gJyc7XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiByZXBsYWNlTGlnaHROdW1zKCBzdHJpbmcsIHBhcmFtZXRlcnMgKSB7XHJcblxyXG5cdGNvbnN0IG51bVNwb3RMaWdodENvb3JkcyA9IHBhcmFtZXRlcnMubnVtU3BvdExpZ2h0U2hhZG93cyArIHBhcmFtZXRlcnMubnVtU3BvdExpZ2h0TWFwcyAtIHBhcmFtZXRlcnMubnVtU3BvdExpZ2h0U2hhZG93c1dpdGhNYXBzO1xyXG5cclxuXHRyZXR1cm4gc3RyaW5nXHJcblx0XHQucmVwbGFjZSggL05VTV9ESVJfTElHSFRTL2csIHBhcmFtZXRlcnMubnVtRGlyTGlnaHRzIClcclxuXHRcdC5yZXBsYWNlKCAvTlVNX1NQT1RfTElHSFRTL2csIHBhcmFtZXRlcnMubnVtU3BvdExpZ2h0cyApXHJcblx0XHQucmVwbGFjZSggL05VTV9TUE9UX0xJR0hUX01BUFMvZywgcGFyYW1ldGVycy5udW1TcG90TGlnaHRNYXBzIClcclxuXHRcdC5yZXBsYWNlKCAvTlVNX1NQT1RfTElHSFRfQ09PUkRTL2csIG51bVNwb3RMaWdodENvb3JkcyApXHJcblx0XHQucmVwbGFjZSggL05VTV9SRUNUX0FSRUFfTElHSFRTL2csIHBhcmFtZXRlcnMubnVtUmVjdEFyZWFMaWdodHMgKVxyXG5cdFx0LnJlcGxhY2UoIC9OVU1fUE9JTlRfTElHSFRTL2csIHBhcmFtZXRlcnMubnVtUG9pbnRMaWdodHMgKVxyXG5cdFx0LnJlcGxhY2UoIC9OVU1fSEVNSV9MSUdIVFMvZywgcGFyYW1ldGVycy5udW1IZW1pTGlnaHRzIClcclxuXHRcdC5yZXBsYWNlKCAvTlVNX0RJUl9MSUdIVF9TSEFET1dTL2csIHBhcmFtZXRlcnMubnVtRGlyTGlnaHRTaGFkb3dzIClcclxuXHRcdC5yZXBsYWNlKCAvTlVNX1NQT1RfTElHSFRfU0hBRE9XU19XSVRIX01BUFMvZywgcGFyYW1ldGVycy5udW1TcG90TGlnaHRTaGFkb3dzV2l0aE1hcHMgKVxyXG5cdFx0LnJlcGxhY2UoIC9OVU1fU1BPVF9MSUdIVF9TSEFET1dTL2csIHBhcmFtZXRlcnMubnVtU3BvdExpZ2h0U2hhZG93cyApXHJcblx0XHQucmVwbGFjZSggL05VTV9QT0lOVF9MSUdIVF9TSEFET1dTL2csIHBhcmFtZXRlcnMubnVtUG9pbnRMaWdodFNoYWRvd3MgKTtcclxuXHJcbn1cclxuXHJcbmZ1bmN0aW9uIHJlcGxhY2VDbGlwcGluZ1BsYW5lTnVtcyggc3RyaW5nLCBwYXJhbWV0ZXJzICkge1xyXG5cclxuXHRyZXR1cm4gc3RyaW5nXHJcblx0XHQucmVwbGFjZSggL05VTV9DTElQUElOR19QTEFORVMvZywgcGFyYW1ldGVycy5udW1DbGlwcGluZ1BsYW5lcyApXHJcblx0XHQucmVwbGFjZSggL1VOSU9OX0NMSVBQSU5HX1BMQU5FUy9nLCAoIHBhcmFtZXRlcnMubnVtQ2xpcHBpbmdQbGFuZXMgLSBwYXJhbWV0ZXJzLm51bUNsaXBJbnRlcnNlY3Rpb24gKSApO1xyXG5cclxufVxyXG5cclxuLy8gUmVzb2x2ZSBJbmNsdWRlc1xyXG5cclxuY29uc3QgaW5jbHVkZVBhdHRlcm4gPSAvXlsgXFx0XSojaW5jbHVkZSArPChbXFx3XFxkLi9dKyk+L2dtO1xyXG5cclxuZnVuY3Rpb24gcmVzb2x2ZUluY2x1ZGVzKCBzdHJpbmcgKSB7XHJcblxyXG5cdHJldHVybiBzdHJpbmcucmVwbGFjZSggaW5jbHVkZVBhdHRlcm4sIGluY2x1ZGVSZXBsYWNlciApO1xyXG5cclxufVxyXG5cclxuY29uc3Qgc2hhZGVyQ2h1bmtNYXAgPSBuZXcgTWFwKCBbXHJcblx0WyAnZW5jb2RpbmdzX2ZyYWdtZW50JywgJ2NvbG9yc3BhY2VfZnJhZ21lbnQnIF0sIC8vIEBkZXByZWNhdGVkLCByMTU0XHJcblx0WyAnZW5jb2RpbmdzX3BhcnNfZnJhZ21lbnQnLCAnY29sb3JzcGFjZV9wYXJzX2ZyYWdtZW50JyBdLCAvLyBAZGVwcmVjYXRlZCwgcjE1NFxyXG5cdFsgJ291dHB1dF9mcmFnbWVudCcsICdvcGFxdWVfZnJhZ21lbnQnIF0sIC8vIEBkZXByZWNhdGVkLCByMTU0XHJcbl0gKTtcclxuXHJcbmZ1bmN0aW9uIGluY2x1ZGVSZXBsYWNlciggbWF0Y2gsIGluY2x1ZGUgKSB7XHJcblxyXG5cdGxldCBzdHJpbmcgPSBTaGFkZXJDaHVua1sgaW5jbHVkZSBdO1xyXG5cclxuXHRpZiAoIHN0cmluZyA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdGNvbnN0IG5ld0luY2x1ZGUgPSBzaGFkZXJDaHVua01hcC5nZXQoIGluY2x1ZGUgKTtcclxuXHJcblx0XHRpZiAoIG5ld0luY2x1ZGUgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdHN0cmluZyA9IFNoYWRlckNodW5rWyBuZXdJbmNsdWRlIF07XHJcblx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLldlYkdMUmVuZGVyZXI6IFNoYWRlciBjaHVuayBcIiVzXCIgaGFzIGJlZW4gZGVwcmVjYXRlZC4gVXNlIFwiJXNcIiBpbnN0ZWFkLicsIGluY2x1ZGUsIG5ld0luY2x1ZGUgKTtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0dGhyb3cgbmV3IEVycm9yKCAnQ2FuIG5vdCByZXNvbHZlICNpbmNsdWRlIDwnICsgaW5jbHVkZSArICc+JyApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4gcmVzb2x2ZUluY2x1ZGVzKCBzdHJpbmcgKTtcclxuXHJcbn1cclxuXHJcbi8vIFVucm9sbCBMb29wc1xyXG5cclxuY29uc3QgdW5yb2xsTG9vcFBhdHRlcm4gPSAvI3ByYWdtYSB1bnJvbGxfbG9vcF9zdGFydFxccytmb3JcXHMqXFwoXFxzKmludFxccytpXFxzKj1cXHMqKFxcZCspXFxzKjtcXHMqaVxccyo8XFxzKihcXGQrKVxccyo7XFxzKmlcXHMqXFwrXFwrXFxzKlxcKVxccyp7KFtcXHNcXFNdKz8pfVxccysjcHJhZ21hIHVucm9sbF9sb29wX2VuZC9nO1xyXG5cclxuZnVuY3Rpb24gdW5yb2xsTG9vcHMoIHN0cmluZyApIHtcclxuXHJcblx0cmV0dXJuIHN0cmluZy5yZXBsYWNlKCB1bnJvbGxMb29wUGF0dGVybiwgbG9vcFJlcGxhY2VyICk7XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiBsb29wUmVwbGFjZXIoIG1hdGNoLCBzdGFydCwgZW5kLCBzbmlwcGV0ICkge1xyXG5cclxuXHRsZXQgc3RyaW5nID0gJyc7XHJcblxyXG5cdGZvciAoIGxldCBpID0gcGFyc2VJbnQoIHN0YXJ0ICk7IGkgPCBwYXJzZUludCggZW5kICk7IGkgKysgKSB7XHJcblxyXG5cdFx0c3RyaW5nICs9IHNuaXBwZXRcclxuXHRcdFx0LnJlcGxhY2UoIC9cXFtcXHMqaVxccypcXF0vZywgJ1sgJyArIGkgKyAnIF0nIClcclxuXHRcdFx0LnJlcGxhY2UoIC9VTlJPTExFRF9MT09QX0lOREVYL2csIGkgKTtcclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4gc3RyaW5nO1xyXG5cclxufVxyXG5cclxuLy9cclxuXHJcbmZ1bmN0aW9uIGdlbmVyYXRlUHJlY2lzaW9uKCBwYXJhbWV0ZXJzICkge1xyXG5cclxuXHRsZXQgcHJlY2lzaW9uc3RyaW5nID0gYHByZWNpc2lvbiAke3BhcmFtZXRlcnMucHJlY2lzaW9ufSBmbG9hdDtcclxuXHRwcmVjaXNpb24gJHtwYXJhbWV0ZXJzLnByZWNpc2lvbn0gaW50O1xyXG5cdHByZWNpc2lvbiAke3BhcmFtZXRlcnMucHJlY2lzaW9ufSBzYW1wbGVyMkQ7XHJcblx0cHJlY2lzaW9uICR7cGFyYW1ldGVycy5wcmVjaXNpb259IHNhbXBsZXJDdWJlO1xyXG5cdGA7XHJcblxyXG5cdGlmICggcGFyYW1ldGVycy5pc1dlYkdMMiApIHtcclxuXHJcblx0XHRwcmVjaXNpb25zdHJpbmcgKz0gYHByZWNpc2lvbiAke3BhcmFtZXRlcnMucHJlY2lzaW9ufSBzYW1wbGVyM0Q7XHJcblx0XHRwcmVjaXNpb24gJHtwYXJhbWV0ZXJzLnByZWNpc2lvbn0gc2FtcGxlcjJEQXJyYXk7XHJcblx0XHRwcmVjaXNpb24gJHtwYXJhbWV0ZXJzLnByZWNpc2lvbn0gc2FtcGxlcjJEU2hhZG93O1xyXG5cdFx0cHJlY2lzaW9uICR7cGFyYW1ldGVycy5wcmVjaXNpb259IHNhbXBsZXJDdWJlU2hhZG93O1xyXG5cdFx0cHJlY2lzaW9uICR7cGFyYW1ldGVycy5wcmVjaXNpb259IHNhbXBsZXIyREFycmF5U2hhZG93O1xyXG5cdFx0cHJlY2lzaW9uICR7cGFyYW1ldGVycy5wcmVjaXNpb259IGlzYW1wbGVyMkQ7XHJcblx0XHRwcmVjaXNpb24gJHtwYXJhbWV0ZXJzLnByZWNpc2lvbn0gaXNhbXBsZXIzRDtcclxuXHRcdHByZWNpc2lvbiAke3BhcmFtZXRlcnMucHJlY2lzaW9ufSBpc2FtcGxlckN1YmU7XHJcblx0XHRwcmVjaXNpb24gJHtwYXJhbWV0ZXJzLnByZWNpc2lvbn0gaXNhbXBsZXIyREFycmF5O1xyXG5cdFx0cHJlY2lzaW9uICR7cGFyYW1ldGVycy5wcmVjaXNpb259IHVzYW1wbGVyMkQ7XHJcblx0XHRwcmVjaXNpb24gJHtwYXJhbWV0ZXJzLnByZWNpc2lvbn0gdXNhbXBsZXIzRDtcclxuXHRcdHByZWNpc2lvbiAke3BhcmFtZXRlcnMucHJlY2lzaW9ufSB1c2FtcGxlckN1YmU7XHJcblx0XHRwcmVjaXNpb24gJHtwYXJhbWV0ZXJzLnByZWNpc2lvbn0gdXNhbXBsZXIyREFycmF5O1xyXG5cdFx0YDtcclxuXHJcblx0fVxyXG5cclxuXHRpZiAoIHBhcmFtZXRlcnMucHJlY2lzaW9uID09PSAnaGlnaHAnICkge1xyXG5cclxuXHRcdHByZWNpc2lvbnN0cmluZyArPSAnXFxuI2RlZmluZSBISUdIX1BSRUNJU0lPTic7XHJcblxyXG5cdH0gZWxzZSBpZiAoIHBhcmFtZXRlcnMucHJlY2lzaW9uID09PSAnbWVkaXVtcCcgKSB7XHJcblxyXG5cdFx0cHJlY2lzaW9uc3RyaW5nICs9ICdcXG4jZGVmaW5lIE1FRElVTV9QUkVDSVNJT04nO1xyXG5cclxuXHR9IGVsc2UgaWYgKCBwYXJhbWV0ZXJzLnByZWNpc2lvbiA9PT0gJ2xvd3AnICkge1xyXG5cclxuXHRcdHByZWNpc2lvbnN0cmluZyArPSAnXFxuI2RlZmluZSBMT1dfUFJFQ0lTSU9OJztcclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4gcHJlY2lzaW9uc3RyaW5nO1xyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gZ2VuZXJhdGVTaGFkb3dNYXBUeXBlRGVmaW5lKCBwYXJhbWV0ZXJzICkge1xyXG5cclxuXHRsZXQgc2hhZG93TWFwVHlwZURlZmluZSA9ICdTSEFET1dNQVBfVFlQRV9CQVNJQyc7XHJcblxyXG5cdGlmICggcGFyYW1ldGVycy5zaGFkb3dNYXBUeXBlID09PSBQQ0ZTaGFkb3dNYXAgKSB7XHJcblxyXG5cdFx0c2hhZG93TWFwVHlwZURlZmluZSA9ICdTSEFET1dNQVBfVFlQRV9QQ0YnO1xyXG5cclxuXHR9IGVsc2UgaWYgKCBwYXJhbWV0ZXJzLnNoYWRvd01hcFR5cGUgPT09IFBDRlNvZnRTaGFkb3dNYXAgKSB7XHJcblxyXG5cdFx0c2hhZG93TWFwVHlwZURlZmluZSA9ICdTSEFET1dNQVBfVFlQRV9QQ0ZfU09GVCc7XHJcblxyXG5cdH0gZWxzZSBpZiAoIHBhcmFtZXRlcnMuc2hhZG93TWFwVHlwZSA9PT0gVlNNU2hhZG93TWFwICkge1xyXG5cclxuXHRcdHNoYWRvd01hcFR5cGVEZWZpbmUgPSAnU0hBRE9XTUFQX1RZUEVfVlNNJztcclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4gc2hhZG93TWFwVHlwZURlZmluZTtcclxuXHJcbn1cclxuXHJcbmZ1bmN0aW9uIGdlbmVyYXRlRW52TWFwVHlwZURlZmluZSggcGFyYW1ldGVycyApIHtcclxuXHJcblx0bGV0IGVudk1hcFR5cGVEZWZpbmUgPSAnRU5WTUFQX1RZUEVfQ1VCRSc7XHJcblxyXG5cdGlmICggcGFyYW1ldGVycy5lbnZNYXAgKSB7XHJcblxyXG5cdFx0c3dpdGNoICggcGFyYW1ldGVycy5lbnZNYXBNb2RlICkge1xyXG5cclxuXHRcdFx0Y2FzZSBDdWJlUmVmbGVjdGlvbk1hcHBpbmc6XHJcblx0XHRcdGNhc2UgQ3ViZVJlZnJhY3Rpb25NYXBwaW5nOlxyXG5cdFx0XHRcdGVudk1hcFR5cGVEZWZpbmUgPSAnRU5WTUFQX1RZUEVfQ1VCRSc7XHJcblx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRjYXNlIEN1YmVVVlJlZmxlY3Rpb25NYXBwaW5nOlxyXG5cdFx0XHRcdGVudk1hcFR5cGVEZWZpbmUgPSAnRU5WTUFQX1RZUEVfQ1VCRV9VVic7XHJcblx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdHJldHVybiBlbnZNYXBUeXBlRGVmaW5lO1xyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gZ2VuZXJhdGVFbnZNYXBNb2RlRGVmaW5lKCBwYXJhbWV0ZXJzICkge1xyXG5cclxuXHRsZXQgZW52TWFwTW9kZURlZmluZSA9ICdFTlZNQVBfTU9ERV9SRUZMRUNUSU9OJztcclxuXHJcblx0aWYgKCBwYXJhbWV0ZXJzLmVudk1hcCApIHtcclxuXHJcblx0XHRzd2l0Y2ggKCBwYXJhbWV0ZXJzLmVudk1hcE1vZGUgKSB7XHJcblxyXG5cdFx0XHRjYXNlIEN1YmVSZWZyYWN0aW9uTWFwcGluZzpcclxuXHJcblx0XHRcdFx0ZW52TWFwTW9kZURlZmluZSA9ICdFTlZNQVBfTU9ERV9SRUZSQUNUSU9OJztcclxuXHRcdFx0XHRicmVhaztcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0cmV0dXJuIGVudk1hcE1vZGVEZWZpbmU7XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiBnZW5lcmF0ZUVudk1hcEJsZW5kaW5nRGVmaW5lKCBwYXJhbWV0ZXJzICkge1xyXG5cclxuXHRsZXQgZW52TWFwQmxlbmRpbmdEZWZpbmUgPSAnRU5WTUFQX0JMRU5ESU5HX05PTkUnO1xyXG5cclxuXHRpZiAoIHBhcmFtZXRlcnMuZW52TWFwICkge1xyXG5cclxuXHRcdHN3aXRjaCAoIHBhcmFtZXRlcnMuY29tYmluZSApIHtcclxuXHJcblx0XHRcdGNhc2UgTXVsdGlwbHlPcGVyYXRpb246XHJcblx0XHRcdFx0ZW52TWFwQmxlbmRpbmdEZWZpbmUgPSAnRU5WTUFQX0JMRU5ESU5HX01VTFRJUExZJztcclxuXHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdGNhc2UgTWl4T3BlcmF0aW9uOlxyXG5cdFx0XHRcdGVudk1hcEJsZW5kaW5nRGVmaW5lID0gJ0VOVk1BUF9CTEVORElOR19NSVgnO1xyXG5cdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0Y2FzZSBBZGRPcGVyYXRpb246XHJcblx0XHRcdFx0ZW52TWFwQmxlbmRpbmdEZWZpbmUgPSAnRU5WTUFQX0JMRU5ESU5HX0FERCc7XHJcblx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdHJldHVybiBlbnZNYXBCbGVuZGluZ0RlZmluZTtcclxuXHJcbn1cclxuXHJcbmZ1bmN0aW9uIGdlbmVyYXRlQ3ViZVVWU2l6ZSggcGFyYW1ldGVycyApIHtcclxuXHJcblx0Y29uc3QgaW1hZ2VIZWlnaHQgPSBwYXJhbWV0ZXJzLmVudk1hcEN1YmVVVkhlaWdodDtcclxuXHJcblx0aWYgKCBpbWFnZUhlaWdodCA9PT0gbnVsbCApIHJldHVybiBudWxsO1xyXG5cclxuXHRjb25zdCBtYXhNaXAgPSBNYXRoLmxvZzIoIGltYWdlSGVpZ2h0ICkgLSAyO1xyXG5cclxuXHRjb25zdCB0ZXhlbEhlaWdodCA9IDEuMCAvIGltYWdlSGVpZ2h0O1xyXG5cclxuXHRjb25zdCB0ZXhlbFdpZHRoID0gMS4wIC8gKCAzICogTWF0aC5tYXgoIE1hdGgucG93KCAyLCBtYXhNaXAgKSwgNyAqIDE2ICkgKTtcclxuXHJcblx0cmV0dXJuIHsgdGV4ZWxXaWR0aCwgdGV4ZWxIZWlnaHQsIG1heE1pcCB9O1xyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gV2ViR0xQcm9ncmFtKCByZW5kZXJlciwgY2FjaGVLZXksIHBhcmFtZXRlcnMsIGJpbmRpbmdTdGF0ZXMgKSB7XHJcblxyXG5cdC8vIFRPRE8gU2VuZCB0aGlzIGV2ZW50IHRvIFRocmVlLmpzIERldlRvb2xzXHJcblx0Ly8gY29uc29sZS5sb2coICdXZWJHTFByb2dyYW0nLCBjYWNoZUtleSApO1xyXG5cclxuXHRjb25zdCBnbCA9IHJlbmRlcmVyLmdldENvbnRleHQoKTtcclxuXHJcblx0Y29uc3QgZGVmaW5lcyA9IHBhcmFtZXRlcnMuZGVmaW5lcztcclxuXHJcblx0bGV0IHZlcnRleFNoYWRlciA9IHBhcmFtZXRlcnMudmVydGV4U2hhZGVyO1xyXG5cdGxldCBmcmFnbWVudFNoYWRlciA9IHBhcmFtZXRlcnMuZnJhZ21lbnRTaGFkZXI7XHJcblxyXG5cdGNvbnN0IHNoYWRvd01hcFR5cGVEZWZpbmUgPSBnZW5lcmF0ZVNoYWRvd01hcFR5cGVEZWZpbmUoIHBhcmFtZXRlcnMgKTtcclxuXHRjb25zdCBlbnZNYXBUeXBlRGVmaW5lID0gZ2VuZXJhdGVFbnZNYXBUeXBlRGVmaW5lKCBwYXJhbWV0ZXJzICk7XHJcblx0Y29uc3QgZW52TWFwTW9kZURlZmluZSA9IGdlbmVyYXRlRW52TWFwTW9kZURlZmluZSggcGFyYW1ldGVycyApO1xyXG5cdGNvbnN0IGVudk1hcEJsZW5kaW5nRGVmaW5lID0gZ2VuZXJhdGVFbnZNYXBCbGVuZGluZ0RlZmluZSggcGFyYW1ldGVycyApO1xyXG5cdGNvbnN0IGVudk1hcEN1YmVVVlNpemUgPSBnZW5lcmF0ZUN1YmVVVlNpemUoIHBhcmFtZXRlcnMgKTtcclxuXHJcblx0Y29uc3QgY3VzdG9tRXh0ZW5zaW9ucyA9IHBhcmFtZXRlcnMuaXNXZWJHTDIgPyAnJyA6IGdlbmVyYXRlRXh0ZW5zaW9ucyggcGFyYW1ldGVycyApO1xyXG5cclxuXHRjb25zdCBjdXN0b21WZXJ0ZXhFeHRlbnNpb25zID0gZ2VuZXJhdGVWZXJ0ZXhFeHRlbnNpb25zKCBwYXJhbWV0ZXJzICk7XHJcblxyXG5cdGNvbnN0IGN1c3RvbURlZmluZXMgPSBnZW5lcmF0ZURlZmluZXMoIGRlZmluZXMgKTtcclxuXHJcblx0Y29uc3QgcHJvZ3JhbSA9IGdsLmNyZWF0ZVByb2dyYW0oKTtcclxuXHJcblx0bGV0IHByZWZpeFZlcnRleCwgcHJlZml4RnJhZ21lbnQ7XHJcblx0bGV0IHZlcnNpb25TdHJpbmcgPSBwYXJhbWV0ZXJzLmdsc2xWZXJzaW9uID8gJyN2ZXJzaW9uICcgKyBwYXJhbWV0ZXJzLmdsc2xWZXJzaW9uICsgJ1xcbicgOiAnJztcclxuXHJcblx0aWYgKCBwYXJhbWV0ZXJzLmlzUmF3U2hhZGVyTWF0ZXJpYWwgKSB7XHJcblxyXG5cdFx0cHJlZml4VmVydGV4ID0gW1xyXG5cclxuXHRcdFx0JyNkZWZpbmUgU0hBREVSX1RZUEUgJyArIHBhcmFtZXRlcnMuc2hhZGVyVHlwZSxcclxuXHRcdFx0JyNkZWZpbmUgU0hBREVSX05BTUUgJyArIHBhcmFtZXRlcnMuc2hhZGVyTmFtZSxcclxuXHJcblx0XHRcdGN1c3RvbURlZmluZXNcclxuXHJcblx0XHRdLmZpbHRlciggZmlsdGVyRW1wdHlMaW5lICkuam9pbiggJ1xcbicgKTtcclxuXHJcblx0XHRpZiAoIHByZWZpeFZlcnRleC5sZW5ndGggPiAwICkge1xyXG5cclxuXHRcdFx0cHJlZml4VmVydGV4ICs9ICdcXG4nO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRwcmVmaXhGcmFnbWVudCA9IFtcclxuXHJcblx0XHRcdGN1c3RvbUV4dGVuc2lvbnMsXHJcblxyXG5cdFx0XHQnI2RlZmluZSBTSEFERVJfVFlQRSAnICsgcGFyYW1ldGVycy5zaGFkZXJUeXBlLFxyXG5cdFx0XHQnI2RlZmluZSBTSEFERVJfTkFNRSAnICsgcGFyYW1ldGVycy5zaGFkZXJOYW1lLFxyXG5cclxuXHRcdFx0Y3VzdG9tRGVmaW5lc1xyXG5cclxuXHRcdF0uZmlsdGVyKCBmaWx0ZXJFbXB0eUxpbmUgKS5qb2luKCAnXFxuJyApO1xyXG5cclxuXHRcdGlmICggcHJlZml4RnJhZ21lbnQubGVuZ3RoID4gMCApIHtcclxuXHJcblx0XHRcdHByZWZpeEZyYWdtZW50ICs9ICdcXG4nO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fSBlbHNlIHtcclxuXHJcblx0XHRwcmVmaXhWZXJ0ZXggPSBbXHJcblxyXG5cdFx0XHRnZW5lcmF0ZVByZWNpc2lvbiggcGFyYW1ldGVycyApLFxyXG5cclxuXHRcdFx0JyNkZWZpbmUgU0hBREVSX1RZUEUgJyArIHBhcmFtZXRlcnMuc2hhZGVyVHlwZSxcclxuXHRcdFx0JyNkZWZpbmUgU0hBREVSX05BTUUgJyArIHBhcmFtZXRlcnMuc2hhZGVyTmFtZSxcclxuXHJcblx0XHRcdGN1c3RvbURlZmluZXMsXHJcblxyXG5cdFx0XHRwYXJhbWV0ZXJzLmV4dGVuc2lvbkNsaXBDdWxsRGlzdGFuY2UgPyAnI2RlZmluZSBVU0VfQ0xJUF9ESVNUQU5DRScgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy5iYXRjaGluZyA/ICcjZGVmaW5lIFVTRV9CQVRDSElORycgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy5pbnN0YW5jaW5nID8gJyNkZWZpbmUgVVNFX0lOU1RBTkNJTkcnIDogJycsXHJcblx0XHRcdHBhcmFtZXRlcnMuaW5zdGFuY2luZ0NvbG9yID8gJyNkZWZpbmUgVVNFX0lOU1RBTkNJTkdfQ09MT1InIDogJycsXHJcblxyXG5cdFx0XHRwYXJhbWV0ZXJzLnVzZUZvZyAmJiBwYXJhbWV0ZXJzLmZvZyA/ICcjZGVmaW5lIFVTRV9GT0cnIDogJycsXHJcblx0XHRcdHBhcmFtZXRlcnMudXNlRm9nICYmIHBhcmFtZXRlcnMuZm9nRXhwMiA/ICcjZGVmaW5lIEZPR19FWFAyJyA6ICcnLFxyXG5cclxuXHRcdFx0cGFyYW1ldGVycy5tYXAgPyAnI2RlZmluZSBVU0VfTUFQJyA6ICcnLFxyXG5cdFx0XHRwYXJhbWV0ZXJzLmVudk1hcCA/ICcjZGVmaW5lIFVTRV9FTlZNQVAnIDogJycsXHJcblx0XHRcdHBhcmFtZXRlcnMuZW52TWFwID8gJyNkZWZpbmUgJyArIGVudk1hcE1vZGVEZWZpbmUgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy5saWdodE1hcCA/ICcjZGVmaW5lIFVTRV9MSUdIVE1BUCcgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy5hb01hcCA/ICcjZGVmaW5lIFVTRV9BT01BUCcgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy5idW1wTWFwID8gJyNkZWZpbmUgVVNFX0JVTVBNQVAnIDogJycsXHJcblx0XHRcdHBhcmFtZXRlcnMubm9ybWFsTWFwID8gJyNkZWZpbmUgVVNFX05PUk1BTE1BUCcgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy5ub3JtYWxNYXBPYmplY3RTcGFjZSA/ICcjZGVmaW5lIFVTRV9OT1JNQUxNQVBfT0JKRUNUU1BBQ0UnIDogJycsXHJcblx0XHRcdHBhcmFtZXRlcnMubm9ybWFsTWFwVGFuZ2VudFNwYWNlID8gJyNkZWZpbmUgVVNFX05PUk1BTE1BUF9UQU5HRU5UU1BBQ0UnIDogJycsXHJcblx0XHRcdHBhcmFtZXRlcnMuZGlzcGxhY2VtZW50TWFwID8gJyNkZWZpbmUgVVNFX0RJU1BMQUNFTUVOVE1BUCcgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy5lbWlzc2l2ZU1hcCA/ICcjZGVmaW5lIFVTRV9FTUlTU0lWRU1BUCcgOiAnJyxcclxuXHJcblx0XHRcdHBhcmFtZXRlcnMuYW5pc290cm9weSA/ICcjZGVmaW5lIFVTRV9BTklTT1RST1BZJyA6ICcnLFxyXG5cdFx0XHRwYXJhbWV0ZXJzLmFuaXNvdHJvcHlNYXAgPyAnI2RlZmluZSBVU0VfQU5JU09UUk9QWU1BUCcgOiAnJyxcclxuXHJcblx0XHRcdHBhcmFtZXRlcnMuY2xlYXJjb2F0TWFwID8gJyNkZWZpbmUgVVNFX0NMRUFSQ09BVE1BUCcgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy5jbGVhcmNvYXRSb3VnaG5lc3NNYXAgPyAnI2RlZmluZSBVU0VfQ0xFQVJDT0FUX1JPVUdITkVTU01BUCcgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy5jbGVhcmNvYXROb3JtYWxNYXAgPyAnI2RlZmluZSBVU0VfQ0xFQVJDT0FUX05PUk1BTE1BUCcgOiAnJyxcclxuXHJcblx0XHRcdHBhcmFtZXRlcnMuaXJpZGVzY2VuY2VNYXAgPyAnI2RlZmluZSBVU0VfSVJJREVTQ0VOQ0VNQVAnIDogJycsXHJcblx0XHRcdHBhcmFtZXRlcnMuaXJpZGVzY2VuY2VUaGlja25lc3NNYXAgPyAnI2RlZmluZSBVU0VfSVJJREVTQ0VOQ0VfVEhJQ0tORVNTTUFQJyA6ICcnLFxyXG5cclxuXHRcdFx0cGFyYW1ldGVycy5zcGVjdWxhck1hcCA/ICcjZGVmaW5lIFVTRV9TUEVDVUxBUk1BUCcgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy5zcGVjdWxhckNvbG9yTWFwID8gJyNkZWZpbmUgVVNFX1NQRUNVTEFSX0NPTE9STUFQJyA6ICcnLFxyXG5cdFx0XHRwYXJhbWV0ZXJzLnNwZWN1bGFySW50ZW5zaXR5TWFwID8gJyNkZWZpbmUgVVNFX1NQRUNVTEFSX0lOVEVOU0lUWU1BUCcgOiAnJyxcclxuXHJcblx0XHRcdHBhcmFtZXRlcnMucm91Z2huZXNzTWFwID8gJyNkZWZpbmUgVVNFX1JPVUdITkVTU01BUCcgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy5tZXRhbG5lc3NNYXAgPyAnI2RlZmluZSBVU0VfTUVUQUxORVNTTUFQJyA6ICcnLFxyXG5cdFx0XHRwYXJhbWV0ZXJzLmFscGhhTWFwID8gJyNkZWZpbmUgVVNFX0FMUEhBTUFQJyA6ICcnLFxyXG5cdFx0XHRwYXJhbWV0ZXJzLmFscGhhSGFzaCA/ICcjZGVmaW5lIFVTRV9BTFBIQUhBU0gnIDogJycsXHJcblxyXG5cdFx0XHRwYXJhbWV0ZXJzLnRyYW5zbWlzc2lvbiA/ICcjZGVmaW5lIFVTRV9UUkFOU01JU1NJT04nIDogJycsXHJcblx0XHRcdHBhcmFtZXRlcnMudHJhbnNtaXNzaW9uTWFwID8gJyNkZWZpbmUgVVNFX1RSQU5TTUlTU0lPTk1BUCcgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy50aGlja25lc3NNYXAgPyAnI2RlZmluZSBVU0VfVEhJQ0tORVNTTUFQJyA6ICcnLFxyXG5cclxuXHRcdFx0cGFyYW1ldGVycy5zaGVlbkNvbG9yTWFwID8gJyNkZWZpbmUgVVNFX1NIRUVOX0NPTE9STUFQJyA6ICcnLFxyXG5cdFx0XHRwYXJhbWV0ZXJzLnNoZWVuUm91Z2huZXNzTWFwID8gJyNkZWZpbmUgVVNFX1NIRUVOX1JPVUdITkVTU01BUCcgOiAnJyxcclxuXHJcblx0XHRcdC8vXHJcblxyXG5cdFx0XHRwYXJhbWV0ZXJzLm1hcFV2ID8gJyNkZWZpbmUgTUFQX1VWICcgKyBwYXJhbWV0ZXJzLm1hcFV2IDogJycsXHJcblx0XHRcdHBhcmFtZXRlcnMuYWxwaGFNYXBVdiA/ICcjZGVmaW5lIEFMUEhBTUFQX1VWICcgKyBwYXJhbWV0ZXJzLmFscGhhTWFwVXYgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy5saWdodE1hcFV2ID8gJyNkZWZpbmUgTElHSFRNQVBfVVYgJyArIHBhcmFtZXRlcnMubGlnaHRNYXBVdiA6ICcnLFxyXG5cdFx0XHRwYXJhbWV0ZXJzLmFvTWFwVXYgPyAnI2RlZmluZSBBT01BUF9VViAnICsgcGFyYW1ldGVycy5hb01hcFV2IDogJycsXHJcblx0XHRcdHBhcmFtZXRlcnMuZW1pc3NpdmVNYXBVdiA/ICcjZGVmaW5lIEVNSVNTSVZFTUFQX1VWICcgKyBwYXJhbWV0ZXJzLmVtaXNzaXZlTWFwVXYgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy5idW1wTWFwVXYgPyAnI2RlZmluZSBCVU1QTUFQX1VWICcgKyBwYXJhbWV0ZXJzLmJ1bXBNYXBVdiA6ICcnLFxyXG5cdFx0XHRwYXJhbWV0ZXJzLm5vcm1hbE1hcFV2ID8gJyNkZWZpbmUgTk9STUFMTUFQX1VWICcgKyBwYXJhbWV0ZXJzLm5vcm1hbE1hcFV2IDogJycsXHJcblx0XHRcdHBhcmFtZXRlcnMuZGlzcGxhY2VtZW50TWFwVXYgPyAnI2RlZmluZSBESVNQTEFDRU1FTlRNQVBfVVYgJyArIHBhcmFtZXRlcnMuZGlzcGxhY2VtZW50TWFwVXYgOiAnJyxcclxuXHJcblx0XHRcdHBhcmFtZXRlcnMubWV0YWxuZXNzTWFwVXYgPyAnI2RlZmluZSBNRVRBTE5FU1NNQVBfVVYgJyArIHBhcmFtZXRlcnMubWV0YWxuZXNzTWFwVXYgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy5yb3VnaG5lc3NNYXBVdiA/ICcjZGVmaW5lIFJPVUdITkVTU01BUF9VViAnICsgcGFyYW1ldGVycy5yb3VnaG5lc3NNYXBVdiA6ICcnLFxyXG5cclxuXHRcdFx0cGFyYW1ldGVycy5hbmlzb3Ryb3B5TWFwVXYgPyAnI2RlZmluZSBBTklTT1RST1BZTUFQX1VWICcgKyBwYXJhbWV0ZXJzLmFuaXNvdHJvcHlNYXBVdiA6ICcnLFxyXG5cclxuXHRcdFx0cGFyYW1ldGVycy5jbGVhcmNvYXRNYXBVdiA/ICcjZGVmaW5lIENMRUFSQ09BVE1BUF9VViAnICsgcGFyYW1ldGVycy5jbGVhcmNvYXRNYXBVdiA6ICcnLFxyXG5cdFx0XHRwYXJhbWV0ZXJzLmNsZWFyY29hdE5vcm1hbE1hcFV2ID8gJyNkZWZpbmUgQ0xFQVJDT0FUX05PUk1BTE1BUF9VViAnICsgcGFyYW1ldGVycy5jbGVhcmNvYXROb3JtYWxNYXBVdiA6ICcnLFxyXG5cdFx0XHRwYXJhbWV0ZXJzLmNsZWFyY29hdFJvdWdobmVzc01hcFV2ID8gJyNkZWZpbmUgQ0xFQVJDT0FUX1JPVUdITkVTU01BUF9VViAnICsgcGFyYW1ldGVycy5jbGVhcmNvYXRSb3VnaG5lc3NNYXBVdiA6ICcnLFxyXG5cclxuXHRcdFx0cGFyYW1ldGVycy5pcmlkZXNjZW5jZU1hcFV2ID8gJyNkZWZpbmUgSVJJREVTQ0VOQ0VNQVBfVVYgJyArIHBhcmFtZXRlcnMuaXJpZGVzY2VuY2VNYXBVdiA6ICcnLFxyXG5cdFx0XHRwYXJhbWV0ZXJzLmlyaWRlc2NlbmNlVGhpY2tuZXNzTWFwVXYgPyAnI2RlZmluZSBJUklERVNDRU5DRV9USElDS05FU1NNQVBfVVYgJyArIHBhcmFtZXRlcnMuaXJpZGVzY2VuY2VUaGlja25lc3NNYXBVdiA6ICcnLFxyXG5cclxuXHRcdFx0cGFyYW1ldGVycy5zaGVlbkNvbG9yTWFwVXYgPyAnI2RlZmluZSBTSEVFTl9DT0xPUk1BUF9VViAnICsgcGFyYW1ldGVycy5zaGVlbkNvbG9yTWFwVXYgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy5zaGVlblJvdWdobmVzc01hcFV2ID8gJyNkZWZpbmUgU0hFRU5fUk9VR0hORVNTTUFQX1VWICcgKyBwYXJhbWV0ZXJzLnNoZWVuUm91Z2huZXNzTWFwVXYgOiAnJyxcclxuXHJcblx0XHRcdHBhcmFtZXRlcnMuc3BlY3VsYXJNYXBVdiA/ICcjZGVmaW5lIFNQRUNVTEFSTUFQX1VWICcgKyBwYXJhbWV0ZXJzLnNwZWN1bGFyTWFwVXYgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy5zcGVjdWxhckNvbG9yTWFwVXYgPyAnI2RlZmluZSBTUEVDVUxBUl9DT0xPUk1BUF9VViAnICsgcGFyYW1ldGVycy5zcGVjdWxhckNvbG9yTWFwVXYgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy5zcGVjdWxhckludGVuc2l0eU1hcFV2ID8gJyNkZWZpbmUgU1BFQ1VMQVJfSU5URU5TSVRZTUFQX1VWICcgKyBwYXJhbWV0ZXJzLnNwZWN1bGFySW50ZW5zaXR5TWFwVXYgOiAnJyxcclxuXHJcblx0XHRcdHBhcmFtZXRlcnMudHJhbnNtaXNzaW9uTWFwVXYgPyAnI2RlZmluZSBUUkFOU01JU1NJT05NQVBfVVYgJyArIHBhcmFtZXRlcnMudHJhbnNtaXNzaW9uTWFwVXYgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy50aGlja25lc3NNYXBVdiA/ICcjZGVmaW5lIFRISUNLTkVTU01BUF9VViAnICsgcGFyYW1ldGVycy50aGlja25lc3NNYXBVdiA6ICcnLFxyXG5cclxuXHRcdFx0Ly9cclxuXHJcblx0XHRcdHBhcmFtZXRlcnMudmVydGV4VGFuZ2VudHMgJiYgcGFyYW1ldGVycy5mbGF0U2hhZGluZyA9PT0gZmFsc2UgPyAnI2RlZmluZSBVU0VfVEFOR0VOVCcgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy52ZXJ0ZXhDb2xvcnMgPyAnI2RlZmluZSBVU0VfQ09MT1InIDogJycsXHJcblx0XHRcdHBhcmFtZXRlcnMudmVydGV4QWxwaGFzID8gJyNkZWZpbmUgVVNFX0NPTE9SX0FMUEhBJyA6ICcnLFxyXG5cdFx0XHRwYXJhbWV0ZXJzLnZlcnRleFV2MXMgPyAnI2RlZmluZSBVU0VfVVYxJyA6ICcnLFxyXG5cdFx0XHRwYXJhbWV0ZXJzLnZlcnRleFV2MnMgPyAnI2RlZmluZSBVU0VfVVYyJyA6ICcnLFxyXG5cdFx0XHRwYXJhbWV0ZXJzLnZlcnRleFV2M3MgPyAnI2RlZmluZSBVU0VfVVYzJyA6ICcnLFxyXG5cclxuXHRcdFx0cGFyYW1ldGVycy5wb2ludHNVdnMgPyAnI2RlZmluZSBVU0VfUE9JTlRTX1VWJyA6ICcnLFxyXG5cclxuXHRcdFx0cGFyYW1ldGVycy5mbGF0U2hhZGluZyA/ICcjZGVmaW5lIEZMQVRfU0hBREVEJyA6ICcnLFxyXG5cclxuXHRcdFx0cGFyYW1ldGVycy5za2lubmluZyA/ICcjZGVmaW5lIFVTRV9TS0lOTklORycgOiAnJyxcclxuXHJcblx0XHRcdHBhcmFtZXRlcnMubW9ycGhUYXJnZXRzID8gJyNkZWZpbmUgVVNFX01PUlBIVEFSR0VUUycgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy5tb3JwaE5vcm1hbHMgJiYgcGFyYW1ldGVycy5mbGF0U2hhZGluZyA9PT0gZmFsc2UgPyAnI2RlZmluZSBVU0VfTU9SUEhOT1JNQUxTJyA6ICcnLFxyXG5cdFx0XHQoIHBhcmFtZXRlcnMubW9ycGhDb2xvcnMgJiYgcGFyYW1ldGVycy5pc1dlYkdMMiApID8gJyNkZWZpbmUgVVNFX01PUlBIQ09MT1JTJyA6ICcnLFxyXG5cdFx0XHQoIHBhcmFtZXRlcnMubW9ycGhUYXJnZXRzQ291bnQgPiAwICYmIHBhcmFtZXRlcnMuaXNXZWJHTDIgKSA/ICcjZGVmaW5lIE1PUlBIVEFSR0VUU19URVhUVVJFJyA6ICcnLFxyXG5cdFx0XHQoIHBhcmFtZXRlcnMubW9ycGhUYXJnZXRzQ291bnQgPiAwICYmIHBhcmFtZXRlcnMuaXNXZWJHTDIgKSA/ICcjZGVmaW5lIE1PUlBIVEFSR0VUU19URVhUVVJFX1NUUklERSAnICsgcGFyYW1ldGVycy5tb3JwaFRleHR1cmVTdHJpZGUgOiAnJyxcclxuXHRcdFx0KCBwYXJhbWV0ZXJzLm1vcnBoVGFyZ2V0c0NvdW50ID4gMCAmJiBwYXJhbWV0ZXJzLmlzV2ViR0wyICkgPyAnI2RlZmluZSBNT1JQSFRBUkdFVFNfQ09VTlQgJyArIHBhcmFtZXRlcnMubW9ycGhUYXJnZXRzQ291bnQgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy5kb3VibGVTaWRlZCA/ICcjZGVmaW5lIERPVUJMRV9TSURFRCcgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy5mbGlwU2lkZWQgPyAnI2RlZmluZSBGTElQX1NJREVEJyA6ICcnLFxyXG5cclxuXHRcdFx0cGFyYW1ldGVycy5zaGFkb3dNYXBFbmFibGVkID8gJyNkZWZpbmUgVVNFX1NIQURPV01BUCcgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy5zaGFkb3dNYXBFbmFibGVkID8gJyNkZWZpbmUgJyArIHNoYWRvd01hcFR5cGVEZWZpbmUgOiAnJyxcclxuXHJcblx0XHRcdHBhcmFtZXRlcnMuc2l6ZUF0dGVudWF0aW9uID8gJyNkZWZpbmUgVVNFX1NJWkVBVFRFTlVBVElPTicgOiAnJyxcclxuXHJcblx0XHRcdHBhcmFtZXRlcnMubnVtTGlnaHRQcm9iZXMgPiAwID8gJyNkZWZpbmUgVVNFX0xJR0hUX1BST0JFUycgOiAnJyxcclxuXHJcblx0XHRcdHBhcmFtZXRlcnMudXNlTGVnYWN5TGlnaHRzID8gJyNkZWZpbmUgTEVHQUNZX0xJR0hUUycgOiAnJyxcclxuXHJcblx0XHRcdHBhcmFtZXRlcnMubG9nYXJpdGhtaWNEZXB0aEJ1ZmZlciA/ICcjZGVmaW5lIFVTRV9MT0dERVBUSEJVRicgOiAnJyxcclxuXHRcdFx0KCBwYXJhbWV0ZXJzLmxvZ2FyaXRobWljRGVwdGhCdWZmZXIgJiYgcGFyYW1ldGVycy5yZW5kZXJlckV4dGVuc2lvbkZyYWdEZXB0aCApID8gJyNkZWZpbmUgVVNFX0xPR0RFUFRIQlVGX0VYVCcgOiAnJyxcclxuXHJcblx0XHRcdCd1bmlmb3JtIG1hdDQgbW9kZWxNYXRyaXg7JyxcclxuXHRcdFx0J3VuaWZvcm0gbWF0NCBtb2RlbFZpZXdNYXRyaXg7JyxcclxuXHRcdFx0J3VuaWZvcm0gbWF0NCBwcm9qZWN0aW9uTWF0cml4OycsXHJcblx0XHRcdCd1bmlmb3JtIG1hdDQgdmlld01hdHJpeDsnLFxyXG5cdFx0XHQndW5pZm9ybSBtYXQzIG5vcm1hbE1hdHJpeDsnLFxyXG5cdFx0XHQndW5pZm9ybSB2ZWMzIGNhbWVyYVBvc2l0aW9uOycsXHJcblx0XHRcdCd1bmlmb3JtIGJvb2wgaXNPcnRob2dyYXBoaWM7JyxcclxuXHJcblx0XHRcdCcjaWZkZWYgVVNFX0lOU1RBTkNJTkcnLFxyXG5cclxuXHRcdFx0J1x0YXR0cmlidXRlIG1hdDQgaW5zdGFuY2VNYXRyaXg7JyxcclxuXHJcblx0XHRcdCcjZW5kaWYnLFxyXG5cclxuXHRcdFx0JyNpZmRlZiBVU0VfSU5TVEFOQ0lOR19DT0xPUicsXHJcblxyXG5cdFx0XHQnXHRhdHRyaWJ1dGUgdmVjMyBpbnN0YW5jZUNvbG9yOycsXHJcblxyXG5cdFx0XHQnI2VuZGlmJyxcclxuXHJcblx0XHRcdCdhdHRyaWJ1dGUgdmVjMyBwb3NpdGlvbjsnLFxyXG5cdFx0XHQnYXR0cmlidXRlIHZlYzMgbm9ybWFsOycsXHJcblx0XHRcdCdhdHRyaWJ1dGUgdmVjMiB1djsnLFxyXG5cclxuXHRcdFx0JyNpZmRlZiBVU0VfVVYxJyxcclxuXHJcblx0XHRcdCdcdGF0dHJpYnV0ZSB2ZWMyIHV2MTsnLFxyXG5cclxuXHRcdFx0JyNlbmRpZicsXHJcblxyXG5cdFx0XHQnI2lmZGVmIFVTRV9VVjInLFxyXG5cclxuXHRcdFx0J1x0YXR0cmlidXRlIHZlYzIgdXYyOycsXHJcblxyXG5cdFx0XHQnI2VuZGlmJyxcclxuXHJcblx0XHRcdCcjaWZkZWYgVVNFX1VWMycsXHJcblxyXG5cdFx0XHQnXHRhdHRyaWJ1dGUgdmVjMiB1djM7JyxcclxuXHJcblx0XHRcdCcjZW5kaWYnLFxyXG5cclxuXHRcdFx0JyNpZmRlZiBVU0VfVEFOR0VOVCcsXHJcblxyXG5cdFx0XHQnXHRhdHRyaWJ1dGUgdmVjNCB0YW5nZW50OycsXHJcblxyXG5cdFx0XHQnI2VuZGlmJyxcclxuXHJcblx0XHRcdCcjaWYgZGVmaW5lZCggVVNFX0NPTE9SX0FMUEhBICknLFxyXG5cclxuXHRcdFx0J1x0YXR0cmlidXRlIHZlYzQgY29sb3I7JyxcclxuXHJcblx0XHRcdCcjZWxpZiBkZWZpbmVkKCBVU0VfQ09MT1IgKScsXHJcblxyXG5cdFx0XHQnXHRhdHRyaWJ1dGUgdmVjMyBjb2xvcjsnLFxyXG5cclxuXHRcdFx0JyNlbmRpZicsXHJcblxyXG5cdFx0XHQnI2lmICggZGVmaW5lZCggVVNFX01PUlBIVEFSR0VUUyApICYmICEgZGVmaW5lZCggTU9SUEhUQVJHRVRTX1RFWFRVUkUgKSApJyxcclxuXHJcblx0XHRcdCdcdGF0dHJpYnV0ZSB2ZWMzIG1vcnBoVGFyZ2V0MDsnLFxyXG5cdFx0XHQnXHRhdHRyaWJ1dGUgdmVjMyBtb3JwaFRhcmdldDE7JyxcclxuXHRcdFx0J1x0YXR0cmlidXRlIHZlYzMgbW9ycGhUYXJnZXQyOycsXHJcblx0XHRcdCdcdGF0dHJpYnV0ZSB2ZWMzIG1vcnBoVGFyZ2V0MzsnLFxyXG5cclxuXHRcdFx0J1x0I2lmZGVmIFVTRV9NT1JQSE5PUk1BTFMnLFxyXG5cclxuXHRcdFx0J1x0XHRhdHRyaWJ1dGUgdmVjMyBtb3JwaE5vcm1hbDA7JyxcclxuXHRcdFx0J1x0XHRhdHRyaWJ1dGUgdmVjMyBtb3JwaE5vcm1hbDE7JyxcclxuXHRcdFx0J1x0XHRhdHRyaWJ1dGUgdmVjMyBtb3JwaE5vcm1hbDI7JyxcclxuXHRcdFx0J1x0XHRhdHRyaWJ1dGUgdmVjMyBtb3JwaE5vcm1hbDM7JyxcclxuXHJcblx0XHRcdCdcdCNlbHNlJyxcclxuXHJcblx0XHRcdCdcdFx0YXR0cmlidXRlIHZlYzMgbW9ycGhUYXJnZXQ0OycsXHJcblx0XHRcdCdcdFx0YXR0cmlidXRlIHZlYzMgbW9ycGhUYXJnZXQ1OycsXHJcblx0XHRcdCdcdFx0YXR0cmlidXRlIHZlYzMgbW9ycGhUYXJnZXQ2OycsXHJcblx0XHRcdCdcdFx0YXR0cmlidXRlIHZlYzMgbW9ycGhUYXJnZXQ3OycsXHJcblxyXG5cdFx0XHQnXHQjZW5kaWYnLFxyXG5cclxuXHRcdFx0JyNlbmRpZicsXHJcblxyXG5cdFx0XHQnI2lmZGVmIFVTRV9TS0lOTklORycsXHJcblxyXG5cdFx0XHQnXHRhdHRyaWJ1dGUgdmVjNCBza2luSW5kZXg7JyxcclxuXHRcdFx0J1x0YXR0cmlidXRlIHZlYzQgc2tpbldlaWdodDsnLFxyXG5cclxuXHRcdFx0JyNlbmRpZicsXHJcblxyXG5cdFx0XHQnXFxuJ1xyXG5cclxuXHRcdF0uZmlsdGVyKCBmaWx0ZXJFbXB0eUxpbmUgKS5qb2luKCAnXFxuJyApO1xyXG5cclxuXHRcdHByZWZpeEZyYWdtZW50ID0gW1xyXG5cclxuXHRcdFx0Y3VzdG9tRXh0ZW5zaW9ucyxcclxuXHJcblx0XHRcdGdlbmVyYXRlUHJlY2lzaW9uKCBwYXJhbWV0ZXJzICksXHJcblxyXG5cdFx0XHQnI2RlZmluZSBTSEFERVJfVFlQRSAnICsgcGFyYW1ldGVycy5zaGFkZXJUeXBlLFxyXG5cdFx0XHQnI2RlZmluZSBTSEFERVJfTkFNRSAnICsgcGFyYW1ldGVycy5zaGFkZXJOYW1lLFxyXG5cclxuXHRcdFx0Y3VzdG9tRGVmaW5lcyxcclxuXHJcblx0XHRcdHBhcmFtZXRlcnMudXNlRm9nICYmIHBhcmFtZXRlcnMuZm9nID8gJyNkZWZpbmUgVVNFX0ZPRycgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy51c2VGb2cgJiYgcGFyYW1ldGVycy5mb2dFeHAyID8gJyNkZWZpbmUgRk9HX0VYUDInIDogJycsXHJcblxyXG5cdFx0XHRwYXJhbWV0ZXJzLmFscGhhVG9Db3ZlcmFnZSA/ICcjZGVmaW5lIEFMUEhBX1RPX0NPVkVSQUdFJyA6ICcnLFxyXG5cdFx0XHRwYXJhbWV0ZXJzLm1hcCA/ICcjZGVmaW5lIFVTRV9NQVAnIDogJycsXHJcblx0XHRcdHBhcmFtZXRlcnMubWF0Y2FwID8gJyNkZWZpbmUgVVNFX01BVENBUCcgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy5lbnZNYXAgPyAnI2RlZmluZSBVU0VfRU5WTUFQJyA6ICcnLFxyXG5cdFx0XHRwYXJhbWV0ZXJzLmVudk1hcCA/ICcjZGVmaW5lICcgKyBlbnZNYXBUeXBlRGVmaW5lIDogJycsXHJcblx0XHRcdHBhcmFtZXRlcnMuZW52TWFwID8gJyNkZWZpbmUgJyArIGVudk1hcE1vZGVEZWZpbmUgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy5lbnZNYXAgPyAnI2RlZmluZSAnICsgZW52TWFwQmxlbmRpbmdEZWZpbmUgOiAnJyxcclxuXHRcdFx0ZW52TWFwQ3ViZVVWU2l6ZSA/ICcjZGVmaW5lIENVQkVVVl9URVhFTF9XSURUSCAnICsgZW52TWFwQ3ViZVVWU2l6ZS50ZXhlbFdpZHRoIDogJycsXHJcblx0XHRcdGVudk1hcEN1YmVVVlNpemUgPyAnI2RlZmluZSBDVUJFVVZfVEVYRUxfSEVJR0hUICcgKyBlbnZNYXBDdWJlVVZTaXplLnRleGVsSGVpZ2h0IDogJycsXHJcblx0XHRcdGVudk1hcEN1YmVVVlNpemUgPyAnI2RlZmluZSBDVUJFVVZfTUFYX01JUCAnICsgZW52TWFwQ3ViZVVWU2l6ZS5tYXhNaXAgKyAnLjAnIDogJycsXHJcblx0XHRcdHBhcmFtZXRlcnMubGlnaHRNYXAgPyAnI2RlZmluZSBVU0VfTElHSFRNQVAnIDogJycsXHJcblx0XHRcdHBhcmFtZXRlcnMuYW9NYXAgPyAnI2RlZmluZSBVU0VfQU9NQVAnIDogJycsXHJcblx0XHRcdHBhcmFtZXRlcnMuYnVtcE1hcCA/ICcjZGVmaW5lIFVTRV9CVU1QTUFQJyA6ICcnLFxyXG5cdFx0XHRwYXJhbWV0ZXJzLm5vcm1hbE1hcCA/ICcjZGVmaW5lIFVTRV9OT1JNQUxNQVAnIDogJycsXHJcblx0XHRcdHBhcmFtZXRlcnMubm9ybWFsTWFwT2JqZWN0U3BhY2UgPyAnI2RlZmluZSBVU0VfTk9STUFMTUFQX09CSkVDVFNQQUNFJyA6ICcnLFxyXG5cdFx0XHRwYXJhbWV0ZXJzLm5vcm1hbE1hcFRhbmdlbnRTcGFjZSA/ICcjZGVmaW5lIFVTRV9OT1JNQUxNQVBfVEFOR0VOVFNQQUNFJyA6ICcnLFxyXG5cdFx0XHRwYXJhbWV0ZXJzLmVtaXNzaXZlTWFwID8gJyNkZWZpbmUgVVNFX0VNSVNTSVZFTUFQJyA6ICcnLFxyXG5cclxuXHRcdFx0cGFyYW1ldGVycy5hbmlzb3Ryb3B5ID8gJyNkZWZpbmUgVVNFX0FOSVNPVFJPUFknIDogJycsXHJcblx0XHRcdHBhcmFtZXRlcnMuYW5pc290cm9weU1hcCA/ICcjZGVmaW5lIFVTRV9BTklTT1RST1BZTUFQJyA6ICcnLFxyXG5cclxuXHRcdFx0cGFyYW1ldGVycy5jbGVhcmNvYXQgPyAnI2RlZmluZSBVU0VfQ0xFQVJDT0FUJyA6ICcnLFxyXG5cdFx0XHRwYXJhbWV0ZXJzLmNsZWFyY29hdE1hcCA/ICcjZGVmaW5lIFVTRV9DTEVBUkNPQVRNQVAnIDogJycsXHJcblx0XHRcdHBhcmFtZXRlcnMuY2xlYXJjb2F0Um91Z2huZXNzTWFwID8gJyNkZWZpbmUgVVNFX0NMRUFSQ09BVF9ST1VHSE5FU1NNQVAnIDogJycsXHJcblx0XHRcdHBhcmFtZXRlcnMuY2xlYXJjb2F0Tm9ybWFsTWFwID8gJyNkZWZpbmUgVVNFX0NMRUFSQ09BVF9OT1JNQUxNQVAnIDogJycsXHJcblxyXG5cdFx0XHRwYXJhbWV0ZXJzLmlyaWRlc2NlbmNlID8gJyNkZWZpbmUgVVNFX0lSSURFU0NFTkNFJyA6ICcnLFxyXG5cdFx0XHRwYXJhbWV0ZXJzLmlyaWRlc2NlbmNlTWFwID8gJyNkZWZpbmUgVVNFX0lSSURFU0NFTkNFTUFQJyA6ICcnLFxyXG5cdFx0XHRwYXJhbWV0ZXJzLmlyaWRlc2NlbmNlVGhpY2tuZXNzTWFwID8gJyNkZWZpbmUgVVNFX0lSSURFU0NFTkNFX1RISUNLTkVTU01BUCcgOiAnJyxcclxuXHJcblx0XHRcdHBhcmFtZXRlcnMuc3BlY3VsYXJNYXAgPyAnI2RlZmluZSBVU0VfU1BFQ1VMQVJNQVAnIDogJycsXHJcblx0XHRcdHBhcmFtZXRlcnMuc3BlY3VsYXJDb2xvck1hcCA/ICcjZGVmaW5lIFVTRV9TUEVDVUxBUl9DT0xPUk1BUCcgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy5zcGVjdWxhckludGVuc2l0eU1hcCA/ICcjZGVmaW5lIFVTRV9TUEVDVUxBUl9JTlRFTlNJVFlNQVAnIDogJycsXHJcblxyXG5cdFx0XHRwYXJhbWV0ZXJzLnJvdWdobmVzc01hcCA/ICcjZGVmaW5lIFVTRV9ST1VHSE5FU1NNQVAnIDogJycsXHJcblx0XHRcdHBhcmFtZXRlcnMubWV0YWxuZXNzTWFwID8gJyNkZWZpbmUgVVNFX01FVEFMTkVTU01BUCcgOiAnJyxcclxuXHJcblx0XHRcdHBhcmFtZXRlcnMuYWxwaGFNYXAgPyAnI2RlZmluZSBVU0VfQUxQSEFNQVAnIDogJycsXHJcblx0XHRcdHBhcmFtZXRlcnMuYWxwaGFUZXN0ID8gJyNkZWZpbmUgVVNFX0FMUEhBVEVTVCcgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy5hbHBoYUhhc2ggPyAnI2RlZmluZSBVU0VfQUxQSEFIQVNIJyA6ICcnLFxyXG5cclxuXHRcdFx0cGFyYW1ldGVycy5zaGVlbiA/ICcjZGVmaW5lIFVTRV9TSEVFTicgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy5zaGVlbkNvbG9yTWFwID8gJyNkZWZpbmUgVVNFX1NIRUVOX0NPTE9STUFQJyA6ICcnLFxyXG5cdFx0XHRwYXJhbWV0ZXJzLnNoZWVuUm91Z2huZXNzTWFwID8gJyNkZWZpbmUgVVNFX1NIRUVOX1JPVUdITkVTU01BUCcgOiAnJyxcclxuXHJcblx0XHRcdHBhcmFtZXRlcnMudHJhbnNtaXNzaW9uID8gJyNkZWZpbmUgVVNFX1RSQU5TTUlTU0lPTicgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy50cmFuc21pc3Npb25NYXAgPyAnI2RlZmluZSBVU0VfVFJBTlNNSVNTSU9OTUFQJyA6ICcnLFxyXG5cdFx0XHRwYXJhbWV0ZXJzLnRoaWNrbmVzc01hcCA/ICcjZGVmaW5lIFVTRV9USElDS05FU1NNQVAnIDogJycsXHJcblxyXG5cdFx0XHRwYXJhbWV0ZXJzLnZlcnRleFRhbmdlbnRzICYmIHBhcmFtZXRlcnMuZmxhdFNoYWRpbmcgPT09IGZhbHNlID8gJyNkZWZpbmUgVVNFX1RBTkdFTlQnIDogJycsXHJcblx0XHRcdHBhcmFtZXRlcnMudmVydGV4Q29sb3JzIHx8IHBhcmFtZXRlcnMuaW5zdGFuY2luZ0NvbG9yID8gJyNkZWZpbmUgVVNFX0NPTE9SJyA6ICcnLFxyXG5cdFx0XHRwYXJhbWV0ZXJzLnZlcnRleEFscGhhcyA/ICcjZGVmaW5lIFVTRV9DT0xPUl9BTFBIQScgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy52ZXJ0ZXhVdjFzID8gJyNkZWZpbmUgVVNFX1VWMScgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy52ZXJ0ZXhVdjJzID8gJyNkZWZpbmUgVVNFX1VWMicgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy52ZXJ0ZXhVdjNzID8gJyNkZWZpbmUgVVNFX1VWMycgOiAnJyxcclxuXHJcblx0XHRcdHBhcmFtZXRlcnMucG9pbnRzVXZzID8gJyNkZWZpbmUgVVNFX1BPSU5UU19VVicgOiAnJyxcclxuXHJcblx0XHRcdHBhcmFtZXRlcnMuZ3JhZGllbnRNYXAgPyAnI2RlZmluZSBVU0VfR1JBRElFTlRNQVAnIDogJycsXHJcblxyXG5cdFx0XHRwYXJhbWV0ZXJzLmZsYXRTaGFkaW5nID8gJyNkZWZpbmUgRkxBVF9TSEFERUQnIDogJycsXHJcblxyXG5cdFx0XHRwYXJhbWV0ZXJzLmRvdWJsZVNpZGVkID8gJyNkZWZpbmUgRE9VQkxFX1NJREVEJyA6ICcnLFxyXG5cdFx0XHRwYXJhbWV0ZXJzLmZsaXBTaWRlZCA/ICcjZGVmaW5lIEZMSVBfU0lERUQnIDogJycsXHJcblxyXG5cdFx0XHRwYXJhbWV0ZXJzLnNoYWRvd01hcEVuYWJsZWQgPyAnI2RlZmluZSBVU0VfU0hBRE9XTUFQJyA6ICcnLFxyXG5cdFx0XHRwYXJhbWV0ZXJzLnNoYWRvd01hcEVuYWJsZWQgPyAnI2RlZmluZSAnICsgc2hhZG93TWFwVHlwZURlZmluZSA6ICcnLFxyXG5cclxuXHRcdFx0cGFyYW1ldGVycy5wcmVtdWx0aXBsaWVkQWxwaGEgPyAnI2RlZmluZSBQUkVNVUxUSVBMSUVEX0FMUEhBJyA6ICcnLFxyXG5cclxuXHRcdFx0cGFyYW1ldGVycy5udW1MaWdodFByb2JlcyA+IDAgPyAnI2RlZmluZSBVU0VfTElHSFRfUFJPQkVTJyA6ICcnLFxyXG5cclxuXHRcdFx0cGFyYW1ldGVycy51c2VMZWdhY3lMaWdodHMgPyAnI2RlZmluZSBMRUdBQ1lfTElHSFRTJyA6ICcnLFxyXG5cclxuXHRcdFx0cGFyYW1ldGVycy5kZWNvZGVWaWRlb1RleHR1cmUgPyAnI2RlZmluZSBERUNPREVfVklERU9fVEVYVFVSRScgOiAnJyxcclxuXHJcblx0XHRcdHBhcmFtZXRlcnMubG9nYXJpdGhtaWNEZXB0aEJ1ZmZlciA/ICcjZGVmaW5lIFVTRV9MT0dERVBUSEJVRicgOiAnJyxcclxuXHRcdFx0KCBwYXJhbWV0ZXJzLmxvZ2FyaXRobWljRGVwdGhCdWZmZXIgJiYgcGFyYW1ldGVycy5yZW5kZXJlckV4dGVuc2lvbkZyYWdEZXB0aCApID8gJyNkZWZpbmUgVVNFX0xPR0RFUFRIQlVGX0VYVCcgOiAnJyxcclxuXHJcblx0XHRcdCd1bmlmb3JtIG1hdDQgdmlld01hdHJpeDsnLFxyXG5cdFx0XHQndW5pZm9ybSB2ZWMzIGNhbWVyYVBvc2l0aW9uOycsXHJcblx0XHRcdCd1bmlmb3JtIGJvb2wgaXNPcnRob2dyYXBoaWM7JyxcclxuXHJcblx0XHRcdCggcGFyYW1ldGVycy50b25lTWFwcGluZyAhPT0gTm9Ub25lTWFwcGluZyApID8gJyNkZWZpbmUgVE9ORV9NQVBQSU5HJyA6ICcnLFxyXG5cdFx0XHQoIHBhcmFtZXRlcnMudG9uZU1hcHBpbmcgIT09IE5vVG9uZU1hcHBpbmcgKSA/IFNoYWRlckNodW5rWyAndG9uZW1hcHBpbmdfcGFyc19mcmFnbWVudCcgXSA6ICcnLCAvLyB0aGlzIGNvZGUgaXMgcmVxdWlyZWQgaGVyZSBiZWNhdXNlIGl0IGlzIHVzZWQgYnkgdGhlIHRvbmVNYXBwaW5nKCkgZnVuY3Rpb24gZGVmaW5lZCBiZWxvd1xyXG5cdFx0XHQoIHBhcmFtZXRlcnMudG9uZU1hcHBpbmcgIT09IE5vVG9uZU1hcHBpbmcgKSA/IGdldFRvbmVNYXBwaW5nRnVuY3Rpb24oICd0b25lTWFwcGluZycsIHBhcmFtZXRlcnMudG9uZU1hcHBpbmcgKSA6ICcnLFxyXG5cclxuXHRcdFx0cGFyYW1ldGVycy5kaXRoZXJpbmcgPyAnI2RlZmluZSBESVRIRVJJTkcnIDogJycsXHJcblx0XHRcdHBhcmFtZXRlcnMub3BhcXVlID8gJyNkZWZpbmUgT1BBUVVFJyA6ICcnLFxyXG5cclxuXHRcdFx0U2hhZGVyQ2h1bmtbICdjb2xvcnNwYWNlX3BhcnNfZnJhZ21lbnQnIF0sIC8vIHRoaXMgY29kZSBpcyByZXF1aXJlZCBoZXJlIGJlY2F1c2UgaXQgaXMgdXNlZCBieSB0aGUgdmFyaW91cyBlbmNvZGluZy9kZWNvZGluZyBmdW5jdGlvbiBkZWZpbmVkIGJlbG93XHJcblx0XHRcdGdldFRleGVsRW5jb2RpbmdGdW5jdGlvbiggJ2xpbmVhclRvT3V0cHV0VGV4ZWwnLCBwYXJhbWV0ZXJzLm91dHB1dENvbG9yU3BhY2UgKSxcclxuXHJcblx0XHRcdHBhcmFtZXRlcnMudXNlRGVwdGhQYWNraW5nID8gJyNkZWZpbmUgREVQVEhfUEFDS0lORyAnICsgcGFyYW1ldGVycy5kZXB0aFBhY2tpbmcgOiAnJyxcclxuXHJcblx0XHRcdCdcXG4nXHJcblxyXG5cdFx0XS5maWx0ZXIoIGZpbHRlckVtcHR5TGluZSApLmpvaW4oICdcXG4nICk7XHJcblxyXG5cdH1cclxuXHJcblx0dmVydGV4U2hhZGVyID0gcmVzb2x2ZUluY2x1ZGVzKCB2ZXJ0ZXhTaGFkZXIgKTtcclxuXHR2ZXJ0ZXhTaGFkZXIgPSByZXBsYWNlTGlnaHROdW1zKCB2ZXJ0ZXhTaGFkZXIsIHBhcmFtZXRlcnMgKTtcclxuXHR2ZXJ0ZXhTaGFkZXIgPSByZXBsYWNlQ2xpcHBpbmdQbGFuZU51bXMoIHZlcnRleFNoYWRlciwgcGFyYW1ldGVycyApO1xyXG5cclxuXHRmcmFnbWVudFNoYWRlciA9IHJlc29sdmVJbmNsdWRlcyggZnJhZ21lbnRTaGFkZXIgKTtcclxuXHRmcmFnbWVudFNoYWRlciA9IHJlcGxhY2VMaWdodE51bXMoIGZyYWdtZW50U2hhZGVyLCBwYXJhbWV0ZXJzICk7XHJcblx0ZnJhZ21lbnRTaGFkZXIgPSByZXBsYWNlQ2xpcHBpbmdQbGFuZU51bXMoIGZyYWdtZW50U2hhZGVyLCBwYXJhbWV0ZXJzICk7XHJcblxyXG5cdHZlcnRleFNoYWRlciA9IHVucm9sbExvb3BzKCB2ZXJ0ZXhTaGFkZXIgKTtcclxuXHRmcmFnbWVudFNoYWRlciA9IHVucm9sbExvb3BzKCBmcmFnbWVudFNoYWRlciApO1xyXG5cclxuXHRpZiAoIHBhcmFtZXRlcnMuaXNXZWJHTDIgJiYgcGFyYW1ldGVycy5pc1Jhd1NoYWRlck1hdGVyaWFsICE9PSB0cnVlICkge1xyXG5cclxuXHRcdC8vIEdMU0wgMy4wIGNvbnZlcnNpb24gZm9yIGJ1aWx0LWluIG1hdGVyaWFscyBhbmQgU2hhZGVyTWF0ZXJpYWxcclxuXHJcblx0XHR2ZXJzaW9uU3RyaW5nID0gJyN2ZXJzaW9uIDMwMCBlc1xcbic7XHJcblxyXG5cdFx0cHJlZml4VmVydGV4ID0gW1xyXG5cdFx0XHRjdXN0b21WZXJ0ZXhFeHRlbnNpb25zLFxyXG5cdFx0XHQncHJlY2lzaW9uIG1lZGl1bXAgc2FtcGxlcjJEQXJyYXk7JyxcclxuXHRcdFx0JyNkZWZpbmUgYXR0cmlidXRlIGluJyxcclxuXHRcdFx0JyNkZWZpbmUgdmFyeWluZyBvdXQnLFxyXG5cdFx0XHQnI2RlZmluZSB0ZXh0dXJlMkQgdGV4dHVyZSdcclxuXHRcdF0uam9pbiggJ1xcbicgKSArICdcXG4nICsgcHJlZml4VmVydGV4O1xyXG5cclxuXHRcdHByZWZpeEZyYWdtZW50ID0gW1xyXG5cdFx0XHQncHJlY2lzaW9uIG1lZGl1bXAgc2FtcGxlcjJEQXJyYXk7JyxcclxuXHRcdFx0JyNkZWZpbmUgdmFyeWluZyBpbicsXHJcblx0XHRcdCggcGFyYW1ldGVycy5nbHNsVmVyc2lvbiA9PT0gR0xTTDMgKSA/ICcnIDogJ2xheW91dChsb2NhdGlvbiA9IDApIG91dCBoaWdocCB2ZWM0IHBjX2ZyYWdDb2xvcjsnLFxyXG5cdFx0XHQoIHBhcmFtZXRlcnMuZ2xzbFZlcnNpb24gPT09IEdMU0wzICkgPyAnJyA6ICcjZGVmaW5lIGdsX0ZyYWdDb2xvciBwY19mcmFnQ29sb3InLFxyXG5cdFx0XHQnI2RlZmluZSBnbF9GcmFnRGVwdGhFWFQgZ2xfRnJhZ0RlcHRoJyxcclxuXHRcdFx0JyNkZWZpbmUgdGV4dHVyZTJEIHRleHR1cmUnLFxyXG5cdFx0XHQnI2RlZmluZSB0ZXh0dXJlQ3ViZSB0ZXh0dXJlJyxcclxuXHRcdFx0JyNkZWZpbmUgdGV4dHVyZTJEUHJvaiB0ZXh0dXJlUHJvaicsXHJcblx0XHRcdCcjZGVmaW5lIHRleHR1cmUyRExvZEVYVCB0ZXh0dXJlTG9kJyxcclxuXHRcdFx0JyNkZWZpbmUgdGV4dHVyZTJEUHJvakxvZEVYVCB0ZXh0dXJlUHJvakxvZCcsXHJcblx0XHRcdCcjZGVmaW5lIHRleHR1cmVDdWJlTG9kRVhUIHRleHR1cmVMb2QnLFxyXG5cdFx0XHQnI2RlZmluZSB0ZXh0dXJlMkRHcmFkRVhUIHRleHR1cmVHcmFkJyxcclxuXHRcdFx0JyNkZWZpbmUgdGV4dHVyZTJEUHJvakdyYWRFWFQgdGV4dHVyZVByb2pHcmFkJyxcclxuXHRcdFx0JyNkZWZpbmUgdGV4dHVyZUN1YmVHcmFkRVhUIHRleHR1cmVHcmFkJ1xyXG5cdFx0XS5qb2luKCAnXFxuJyApICsgJ1xcbicgKyBwcmVmaXhGcmFnbWVudDtcclxuXHJcblx0fVxyXG5cclxuXHRjb25zdCB2ZXJ0ZXhHbHNsID0gdmVyc2lvblN0cmluZyArIHByZWZpeFZlcnRleCArIHZlcnRleFNoYWRlcjtcclxuXHRjb25zdCBmcmFnbWVudEdsc2wgPSB2ZXJzaW9uU3RyaW5nICsgcHJlZml4RnJhZ21lbnQgKyBmcmFnbWVudFNoYWRlcjtcclxuXHJcblx0Ly8gY29uc29sZS5sb2coICcqVkVSVEVYKicsIHZlcnRleEdsc2wgKTtcclxuXHQvLyBjb25zb2xlLmxvZyggJypGUkFHTUVOVConLCBmcmFnbWVudEdsc2wgKTtcclxuXHJcblx0Y29uc3QgZ2xWZXJ0ZXhTaGFkZXIgPSBXZWJHTFNoYWRlciggZ2wsIGdsLlZFUlRFWF9TSEFERVIsIHZlcnRleEdsc2wgKTtcclxuXHRjb25zdCBnbEZyYWdtZW50U2hhZGVyID0gV2ViR0xTaGFkZXIoIGdsLCBnbC5GUkFHTUVOVF9TSEFERVIsIGZyYWdtZW50R2xzbCApO1xyXG5cclxuXHRnbC5hdHRhY2hTaGFkZXIoIHByb2dyYW0sIGdsVmVydGV4U2hhZGVyICk7XHJcblx0Z2wuYXR0YWNoU2hhZGVyKCBwcm9ncmFtLCBnbEZyYWdtZW50U2hhZGVyICk7XHJcblxyXG5cdC8vIEZvcmNlIGEgcGFydGljdWxhciBhdHRyaWJ1dGUgdG8gaW5kZXggMC5cclxuXHJcblx0aWYgKCBwYXJhbWV0ZXJzLmluZGV4MEF0dHJpYnV0ZU5hbWUgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRnbC5iaW5kQXR0cmliTG9jYXRpb24oIHByb2dyYW0sIDAsIHBhcmFtZXRlcnMuaW5kZXgwQXR0cmlidXRlTmFtZSApO1xyXG5cclxuXHR9IGVsc2UgaWYgKCBwYXJhbWV0ZXJzLm1vcnBoVGFyZ2V0cyA9PT0gdHJ1ZSApIHtcclxuXHJcblx0XHQvLyBwcm9ncmFtcyB3aXRoIG1vcnBoVGFyZ2V0cyBkaXNwbGFjZSBwb3NpdGlvbiBvdXQgb2YgYXR0cmlidXRlIDBcclxuXHRcdGdsLmJpbmRBdHRyaWJMb2NhdGlvbiggcHJvZ3JhbSwgMCwgJ3Bvc2l0aW9uJyApO1xyXG5cclxuXHR9XHJcblxyXG5cdGdsLmxpbmtQcm9ncmFtKCBwcm9ncmFtICk7XHJcblxyXG5cdGZ1bmN0aW9uIG9uRmlyc3RVc2UoIHNlbGYgKSB7XHJcblxyXG5cdFx0Ly8gY2hlY2sgZm9yIGxpbmsgZXJyb3JzXHJcblx0XHRpZiAoIHJlbmRlcmVyLmRlYnVnLmNoZWNrU2hhZGVyRXJyb3JzICkge1xyXG5cclxuXHRcdFx0Y29uc3QgcHJvZ3JhbUxvZyA9IGdsLmdldFByb2dyYW1JbmZvTG9nKCBwcm9ncmFtICkudHJpbSgpO1xyXG5cdFx0XHRjb25zdCB2ZXJ0ZXhMb2cgPSBnbC5nZXRTaGFkZXJJbmZvTG9nKCBnbFZlcnRleFNoYWRlciApLnRyaW0oKTtcclxuXHRcdFx0Y29uc3QgZnJhZ21lbnRMb2cgPSBnbC5nZXRTaGFkZXJJbmZvTG9nKCBnbEZyYWdtZW50U2hhZGVyICkudHJpbSgpO1xyXG5cclxuXHRcdFx0bGV0IHJ1bm5hYmxlID0gdHJ1ZTtcclxuXHRcdFx0bGV0IGhhdmVEaWFnbm9zdGljcyA9IHRydWU7XHJcblxyXG5cdFx0XHRpZiAoIGdsLmdldFByb2dyYW1QYXJhbWV0ZXIoIHByb2dyYW0sIGdsLkxJTktfU1RBVFVTICkgPT09IGZhbHNlICkge1xyXG5cclxuXHRcdFx0XHRydW5uYWJsZSA9IGZhbHNlO1xyXG5cclxuXHRcdFx0XHRpZiAoIHR5cGVvZiByZW5kZXJlci5kZWJ1Zy5vblNoYWRlckVycm9yID09PSAnZnVuY3Rpb24nICkge1xyXG5cclxuXHRcdFx0XHRcdHJlbmRlcmVyLmRlYnVnLm9uU2hhZGVyRXJyb3IoIGdsLCBwcm9ncmFtLCBnbFZlcnRleFNoYWRlciwgZ2xGcmFnbWVudFNoYWRlciApO1xyXG5cclxuXHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdC8vIGRlZmF1bHQgZXJyb3IgcmVwb3J0aW5nXHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgdmVydGV4RXJyb3JzID0gZ2V0U2hhZGVyRXJyb3JzKCBnbCwgZ2xWZXJ0ZXhTaGFkZXIsICd2ZXJ0ZXgnICk7XHJcblx0XHRcdFx0XHRjb25zdCBmcmFnbWVudEVycm9ycyA9IGdldFNoYWRlckVycm9ycyggZ2wsIGdsRnJhZ21lbnRTaGFkZXIsICdmcmFnbWVudCcgKTtcclxuXHJcblx0XHRcdFx0XHRjb25zb2xlLmVycm9yKFxyXG5cdFx0XHRcdFx0XHQnVEhSRUUuV2ViR0xQcm9ncmFtOiBTaGFkZXIgRXJyb3IgJyArIGdsLmdldEVycm9yKCkgKyAnIC0gJyArXHJcblx0XHRcdFx0XHRcdCdWQUxJREFURV9TVEFUVVMgJyArIGdsLmdldFByb2dyYW1QYXJhbWV0ZXIoIHByb2dyYW0sIGdsLlZBTElEQVRFX1NUQVRVUyApICsgJ1xcblxcbicgK1xyXG5cdFx0XHRcdFx0XHQnTWF0ZXJpYWwgTmFtZTogJyArIHNlbGYubmFtZSArICdcXG4nICtcclxuXHRcdFx0XHRcdFx0J01hdGVyaWFsIFR5cGU6ICcgKyBzZWxmLnR5cGUgKyAnXFxuXFxuJyArXHJcblx0XHRcdFx0XHRcdCdQcm9ncmFtIEluZm8gTG9nOiAnICsgcHJvZ3JhbUxvZyArICdcXG4nICtcclxuXHRcdFx0XHRcdFx0dmVydGV4RXJyb3JzICsgJ1xcbicgK1xyXG5cdFx0XHRcdFx0XHRmcmFnbWVudEVycm9yc1xyXG5cdFx0XHRcdFx0KTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fSBlbHNlIGlmICggcHJvZ3JhbUxvZyAhPT0gJycgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLldlYkdMUHJvZ3JhbTogUHJvZ3JhbSBJbmZvIExvZzonLCBwcm9ncmFtTG9nICk7XHJcblxyXG5cdFx0XHR9IGVsc2UgaWYgKCB2ZXJ0ZXhMb2cgPT09ICcnIHx8IGZyYWdtZW50TG9nID09PSAnJyApIHtcclxuXHJcblx0XHRcdFx0aGF2ZURpYWdub3N0aWNzID0gZmFsc2U7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRpZiAoIGhhdmVEaWFnbm9zdGljcyApIHtcclxuXHJcblx0XHRcdFx0c2VsZi5kaWFnbm9zdGljcyA9IHtcclxuXHJcblx0XHRcdFx0XHRydW5uYWJsZTogcnVubmFibGUsXHJcblxyXG5cdFx0XHRcdFx0cHJvZ3JhbUxvZzogcHJvZ3JhbUxvZyxcclxuXHJcblx0XHRcdFx0XHR2ZXJ0ZXhTaGFkZXI6IHtcclxuXHJcblx0XHRcdFx0XHRcdGxvZzogdmVydGV4TG9nLFxyXG5cdFx0XHRcdFx0XHRwcmVmaXg6IHByZWZpeFZlcnRleFxyXG5cclxuXHRcdFx0XHRcdH0sXHJcblxyXG5cdFx0XHRcdFx0ZnJhZ21lbnRTaGFkZXI6IHtcclxuXHJcblx0XHRcdFx0XHRcdGxvZzogZnJhZ21lbnRMb2csXHJcblx0XHRcdFx0XHRcdHByZWZpeDogcHJlZml4RnJhZ21lbnRcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH07XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIENsZWFuIHVwXHJcblxyXG5cdFx0Ly8gQ3Jhc2hlcyBpbiBpT1M5IGFuZCBpT1MxMC4gIzE4NDAyXHJcblx0XHQvLyBnbC5kZXRhY2hTaGFkZXIoIHByb2dyYW0sIGdsVmVydGV4U2hhZGVyICk7XHJcblx0XHQvLyBnbC5kZXRhY2hTaGFkZXIoIHByb2dyYW0sIGdsRnJhZ21lbnRTaGFkZXIgKTtcclxuXHJcblx0XHRnbC5kZWxldGVTaGFkZXIoIGdsVmVydGV4U2hhZGVyICk7XHJcblx0XHRnbC5kZWxldGVTaGFkZXIoIGdsRnJhZ21lbnRTaGFkZXIgKTtcclxuXHJcblx0XHRjYWNoZWRVbmlmb3JtcyA9IG5ldyBXZWJHTFVuaWZvcm1zKCBnbCwgcHJvZ3JhbSApO1xyXG5cdFx0Y2FjaGVkQXR0cmlidXRlcyA9IGZldGNoQXR0cmlidXRlTG9jYXRpb25zKCBnbCwgcHJvZ3JhbSApO1xyXG5cclxuXHR9XHJcblxyXG5cdC8vIHNldCB1cCBjYWNoaW5nIGZvciB1bmlmb3JtIGxvY2F0aW9uc1xyXG5cclxuXHRsZXQgY2FjaGVkVW5pZm9ybXM7XHJcblxyXG5cdHRoaXMuZ2V0VW5pZm9ybXMgPSBmdW5jdGlvbiAoKSB7XHJcblxyXG5cdFx0aWYgKCBjYWNoZWRVbmlmb3JtcyA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0Ly8gUG9wdWxhdGVzIGNhY2hlZFVuaWZvcm1zIGFuZCBjYWNoZWRBdHRyaWJ1dGVzXHJcblx0XHRcdG9uRmlyc3RVc2UoIHRoaXMgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIGNhY2hlZFVuaWZvcm1zO1xyXG5cclxuXHR9O1xyXG5cclxuXHQvLyBzZXQgdXAgY2FjaGluZyBmb3IgYXR0cmlidXRlIGxvY2F0aW9uc1xyXG5cclxuXHRsZXQgY2FjaGVkQXR0cmlidXRlcztcclxuXHJcblx0dGhpcy5nZXRBdHRyaWJ1dGVzID0gZnVuY3Rpb24gKCkge1xyXG5cclxuXHRcdGlmICggY2FjaGVkQXR0cmlidXRlcyA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0Ly8gUG9wdWxhdGVzIGNhY2hlZEF0dHJpYnV0ZXMgYW5kIGNhY2hlZFVuaWZvcm1zXHJcblx0XHRcdG9uRmlyc3RVc2UoIHRoaXMgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIGNhY2hlZEF0dHJpYnV0ZXM7XHJcblxyXG5cdH07XHJcblxyXG5cdC8vIGluZGljYXRlIHdoZW4gdGhlIHByb2dyYW0gaXMgcmVhZHkgdG8gYmUgdXNlZC4gaWYgdGhlIEtIUl9wYXJhbGxlbF9zaGFkZXJfY29tcGlsZSBleHRlbnNpb24gaXNuJ3Qgc3VwcG9ydGVkLFxyXG5cdC8vIGZsYWcgdGhlIHByb2dyYW0gYXMgcmVhZHkgaW1tZWRpYXRlbHkuIEl0IG1heSBjYXVzZSBhIHN0YWxsIHdoZW4gaXQncyBmaXJzdCB1c2VkLlxyXG5cclxuXHRsZXQgcHJvZ3JhbVJlYWR5ID0gKCBwYXJhbWV0ZXJzLnJlbmRlcmVyRXh0ZW5zaW9uUGFyYWxsZWxTaGFkZXJDb21waWxlID09PSBmYWxzZSApO1xyXG5cclxuXHR0aGlzLmlzUmVhZHkgPSBmdW5jdGlvbiAoKSB7XHJcblxyXG5cdFx0aWYgKCBwcm9ncmFtUmVhZHkgPT09IGZhbHNlICkge1xyXG5cclxuXHRcdFx0cHJvZ3JhbVJlYWR5ID0gZ2wuZ2V0UHJvZ3JhbVBhcmFtZXRlciggcHJvZ3JhbSwgQ09NUExFVElPTl9TVEFUVVNfS0hSICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiBwcm9ncmFtUmVhZHk7XHJcblxyXG5cdH07XHJcblxyXG5cdC8vIGZyZWUgcmVzb3VyY2VcclxuXHJcblx0dGhpcy5kZXN0cm95ID0gZnVuY3Rpb24gKCkge1xyXG5cclxuXHRcdGJpbmRpbmdTdGF0ZXMucmVsZWFzZVN0YXRlc09mUHJvZ3JhbSggdGhpcyApO1xyXG5cclxuXHRcdGdsLmRlbGV0ZVByb2dyYW0oIHByb2dyYW0gKTtcclxuXHRcdHRoaXMucHJvZ3JhbSA9IHVuZGVmaW5lZDtcclxuXHJcblx0fTtcclxuXHJcblx0Ly9cclxuXHJcblx0dGhpcy50eXBlID0gcGFyYW1ldGVycy5zaGFkZXJUeXBlO1xyXG5cdHRoaXMubmFtZSA9IHBhcmFtZXRlcnMuc2hhZGVyTmFtZTtcclxuXHR0aGlzLmlkID0gcHJvZ3JhbUlkQ291bnQgKys7XHJcblx0dGhpcy5jYWNoZUtleSA9IGNhY2hlS2V5O1xyXG5cdHRoaXMudXNlZFRpbWVzID0gMTtcclxuXHR0aGlzLnByb2dyYW0gPSBwcm9ncmFtO1xyXG5cdHRoaXMudmVydGV4U2hhZGVyID0gZ2xWZXJ0ZXhTaGFkZXI7XHJcblx0dGhpcy5mcmFnbWVudFNoYWRlciA9IGdsRnJhZ21lbnRTaGFkZXI7XHJcblxyXG5cdHJldHVybiB0aGlzO1xyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgV2ViR0xQcm9ncmFtIH07XHJcbiIsImxldCBfaWQgPSAwO1xyXG5cclxuY2xhc3MgV2ViR0xTaGFkZXJDYWNoZSB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCkge1xyXG5cclxuXHRcdHRoaXMuc2hhZGVyQ2FjaGUgPSBuZXcgTWFwKCk7XHJcblx0XHR0aGlzLm1hdGVyaWFsQ2FjaGUgPSBuZXcgTWFwKCk7XHJcblxyXG5cdH1cclxuXHJcblx0dXBkYXRlKCBtYXRlcmlhbCApIHtcclxuXHJcblx0XHRjb25zdCB2ZXJ0ZXhTaGFkZXIgPSBtYXRlcmlhbC52ZXJ0ZXhTaGFkZXI7XHJcblx0XHRjb25zdCBmcmFnbWVudFNoYWRlciA9IG1hdGVyaWFsLmZyYWdtZW50U2hhZGVyO1xyXG5cclxuXHRcdGNvbnN0IHZlcnRleFNoYWRlclN0YWdlID0gdGhpcy5fZ2V0U2hhZGVyU3RhZ2UoIHZlcnRleFNoYWRlciApO1xyXG5cdFx0Y29uc3QgZnJhZ21lbnRTaGFkZXJTdGFnZSA9IHRoaXMuX2dldFNoYWRlclN0YWdlKCBmcmFnbWVudFNoYWRlciApO1xyXG5cclxuXHRcdGNvbnN0IG1hdGVyaWFsU2hhZGVycyA9IHRoaXMuX2dldFNoYWRlckNhY2hlRm9yTWF0ZXJpYWwoIG1hdGVyaWFsICk7XHJcblxyXG5cdFx0aWYgKCBtYXRlcmlhbFNoYWRlcnMuaGFzKCB2ZXJ0ZXhTaGFkZXJTdGFnZSApID09PSBmYWxzZSApIHtcclxuXHJcblx0XHRcdG1hdGVyaWFsU2hhZGVycy5hZGQoIHZlcnRleFNoYWRlclN0YWdlICk7XHJcblx0XHRcdHZlcnRleFNoYWRlclN0YWdlLnVzZWRUaW1lcyArKztcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBtYXRlcmlhbFNoYWRlcnMuaGFzKCBmcmFnbWVudFNoYWRlclN0YWdlICkgPT09IGZhbHNlICkge1xyXG5cclxuXHRcdFx0bWF0ZXJpYWxTaGFkZXJzLmFkZCggZnJhZ21lbnRTaGFkZXJTdGFnZSApO1xyXG5cdFx0XHRmcmFnbWVudFNoYWRlclN0YWdlLnVzZWRUaW1lcyArKztcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0cmVtb3ZlKCBtYXRlcmlhbCApIHtcclxuXHJcblx0XHRjb25zdCBtYXRlcmlhbFNoYWRlcnMgPSB0aGlzLm1hdGVyaWFsQ2FjaGUuZ2V0KCBtYXRlcmlhbCApO1xyXG5cclxuXHRcdGZvciAoIGNvbnN0IHNoYWRlclN0YWdlIG9mIG1hdGVyaWFsU2hhZGVycyApIHtcclxuXHJcblx0XHRcdHNoYWRlclN0YWdlLnVzZWRUaW1lcyAtLTtcclxuXHJcblx0XHRcdGlmICggc2hhZGVyU3RhZ2UudXNlZFRpbWVzID09PSAwICkgdGhpcy5zaGFkZXJDYWNoZS5kZWxldGUoIHNoYWRlclN0YWdlLmNvZGUgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5tYXRlcmlhbENhY2hlLmRlbGV0ZSggbWF0ZXJpYWwgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRnZXRWZXJ0ZXhTaGFkZXJJRCggbWF0ZXJpYWwgKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuX2dldFNoYWRlclN0YWdlKCBtYXRlcmlhbC52ZXJ0ZXhTaGFkZXIgKS5pZDtcclxuXHJcblx0fVxyXG5cclxuXHRnZXRGcmFnbWVudFNoYWRlcklEKCBtYXRlcmlhbCApIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5fZ2V0U2hhZGVyU3RhZ2UoIG1hdGVyaWFsLmZyYWdtZW50U2hhZGVyICkuaWQ7XHJcblxyXG5cdH1cclxuXHJcblx0ZGlzcG9zZSgpIHtcclxuXHJcblx0XHR0aGlzLnNoYWRlckNhY2hlLmNsZWFyKCk7XHJcblx0XHR0aGlzLm1hdGVyaWFsQ2FjaGUuY2xlYXIoKTtcclxuXHJcblx0fVxyXG5cclxuXHRfZ2V0U2hhZGVyQ2FjaGVGb3JNYXRlcmlhbCggbWF0ZXJpYWwgKSB7XHJcblxyXG5cdFx0Y29uc3QgY2FjaGUgPSB0aGlzLm1hdGVyaWFsQ2FjaGU7XHJcblx0XHRsZXQgc2V0ID0gY2FjaGUuZ2V0KCBtYXRlcmlhbCApO1xyXG5cclxuXHRcdGlmICggc2V0ID09PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRzZXQgPSBuZXcgU2V0KCk7XHJcblx0XHRcdGNhY2hlLnNldCggbWF0ZXJpYWwsIHNldCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gc2V0O1xyXG5cclxuXHR9XHJcblxyXG5cdF9nZXRTaGFkZXJTdGFnZSggY29kZSApIHtcclxuXHJcblx0XHRjb25zdCBjYWNoZSA9IHRoaXMuc2hhZGVyQ2FjaGU7XHJcblx0XHRsZXQgc3RhZ2UgPSBjYWNoZS5nZXQoIGNvZGUgKTtcclxuXHJcblx0XHRpZiAoIHN0YWdlID09PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRzdGFnZSA9IG5ldyBXZWJHTFNoYWRlclN0YWdlKCBjb2RlICk7XHJcblx0XHRcdGNhY2hlLnNldCggY29kZSwgc3RhZ2UgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHN0YWdlO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5jbGFzcyBXZWJHTFNoYWRlclN0YWdlIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIGNvZGUgKSB7XHJcblxyXG5cdFx0dGhpcy5pZCA9IF9pZCArKztcclxuXHJcblx0XHR0aGlzLmNvZGUgPSBjb2RlO1xyXG5cdFx0dGhpcy51c2VkVGltZXMgPSAwO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBXZWJHTFNoYWRlckNhY2hlIH07XHJcbiIsImltcG9ydCB7IEJhY2tTaWRlLCBEb3VibGVTaWRlLCBDdWJlVVZSZWZsZWN0aW9uTWFwcGluZywgT2JqZWN0U3BhY2VOb3JtYWxNYXAsIFRhbmdlbnRTcGFjZU5vcm1hbE1hcCwgTm9Ub25lTWFwcGluZywgTm9ybWFsQmxlbmRpbmcsIExpbmVhclNSR0JDb2xvclNwYWNlLCBTUkdCVHJhbnNmZXIgfSBmcm9tICcuLi8uLi9jb25zdGFudHMuanMnO1xyXG5pbXBvcnQgeyBMYXllcnMgfSBmcm9tICcuLi8uLi9jb3JlL0xheWVycy5qcyc7XHJcbmltcG9ydCB7IFdlYkdMUHJvZ3JhbSB9IGZyb20gJy4vV2ViR0xQcm9ncmFtLmpzJztcclxuaW1wb3J0IHsgV2ViR0xTaGFkZXJDYWNoZSB9IGZyb20gJy4vV2ViR0xTaGFkZXJDYWNoZS5qcyc7XHJcbmltcG9ydCB7IFNoYWRlckxpYiB9IGZyb20gJy4uL3NoYWRlcnMvU2hhZGVyTGliLmpzJztcclxuaW1wb3J0IHsgVW5pZm9ybXNVdGlscyB9IGZyb20gJy4uL3NoYWRlcnMvVW5pZm9ybXNVdGlscy5qcyc7XHJcbmltcG9ydCB7IENvbG9yTWFuYWdlbWVudCB9IGZyb20gJy4uLy4uL21hdGgvQ29sb3JNYW5hZ2VtZW50LmpzJztcclxuXHJcbmZ1bmN0aW9uIFdlYkdMUHJvZ3JhbXMoIHJlbmRlcmVyLCBjdWJlbWFwcywgY3ViZXV2bWFwcywgZXh0ZW5zaW9ucywgY2FwYWJpbGl0aWVzLCBiaW5kaW5nU3RhdGVzLCBjbGlwcGluZyApIHtcclxuXHJcblx0Y29uc3QgX3Byb2dyYW1MYXllcnMgPSBuZXcgTGF5ZXJzKCk7XHJcblx0Y29uc3QgX2N1c3RvbVNoYWRlcnMgPSBuZXcgV2ViR0xTaGFkZXJDYWNoZSgpO1xyXG5cdGNvbnN0IF9hY3RpdmVDaGFubmVscyA9IG5ldyBTZXQoKTtcclxuXHRjb25zdCBwcm9ncmFtcyA9IFtdO1xyXG5cclxuXHRjb25zdCBJU19XRUJHTDIgPSBjYXBhYmlsaXRpZXMuaXNXZWJHTDI7XHJcblx0Y29uc3QgbG9nYXJpdGhtaWNEZXB0aEJ1ZmZlciA9IGNhcGFiaWxpdGllcy5sb2dhcml0aG1pY0RlcHRoQnVmZmVyO1xyXG5cdGNvbnN0IFNVUFBPUlRTX1ZFUlRFWF9URVhUVVJFUyA9IGNhcGFiaWxpdGllcy52ZXJ0ZXhUZXh0dXJlcztcclxuXHJcblx0bGV0IHByZWNpc2lvbiA9IGNhcGFiaWxpdGllcy5wcmVjaXNpb247XHJcblxyXG5cdGNvbnN0IHNoYWRlcklEcyA9IHtcclxuXHRcdE1lc2hEZXB0aE1hdGVyaWFsOiAnZGVwdGgnLFxyXG5cdFx0TWVzaERpc3RhbmNlTWF0ZXJpYWw6ICdkaXN0YW5jZVJHQkEnLFxyXG5cdFx0TWVzaE5vcm1hbE1hdGVyaWFsOiAnbm9ybWFsJyxcclxuXHRcdE1lc2hCYXNpY01hdGVyaWFsOiAnYmFzaWMnLFxyXG5cdFx0TWVzaExhbWJlcnRNYXRlcmlhbDogJ2xhbWJlcnQnLFxyXG5cdFx0TWVzaFBob25nTWF0ZXJpYWw6ICdwaG9uZycsXHJcblx0XHRNZXNoVG9vbk1hdGVyaWFsOiAndG9vbicsXHJcblx0XHRNZXNoU3RhbmRhcmRNYXRlcmlhbDogJ3BoeXNpY2FsJyxcclxuXHRcdE1lc2hQaHlzaWNhbE1hdGVyaWFsOiAncGh5c2ljYWwnLFxyXG5cdFx0TWVzaE1hdGNhcE1hdGVyaWFsOiAnbWF0Y2FwJyxcclxuXHRcdExpbmVCYXNpY01hdGVyaWFsOiAnYmFzaWMnLFxyXG5cdFx0TGluZURhc2hlZE1hdGVyaWFsOiAnZGFzaGVkJyxcclxuXHRcdFBvaW50c01hdGVyaWFsOiAncG9pbnRzJyxcclxuXHRcdFNoYWRvd01hdGVyaWFsOiAnc2hhZG93JyxcclxuXHRcdFNwcml0ZU1hdGVyaWFsOiAnc3ByaXRlJ1xyXG5cdH07XHJcblxyXG5cdGZ1bmN0aW9uIGdldENoYW5uZWwoIHZhbHVlICkge1xyXG5cclxuXHRcdF9hY3RpdmVDaGFubmVscy5hZGQoIHZhbHVlICk7XHJcblxyXG5cdFx0aWYgKCB2YWx1ZSA9PT0gMCApIHJldHVybiAndXYnO1xyXG5cclxuXHRcdHJldHVybiBgdXYkeyB2YWx1ZSB9YDtcclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBnZXRQYXJhbWV0ZXJzKCBtYXRlcmlhbCwgbGlnaHRzLCBzaGFkb3dzLCBzY2VuZSwgb2JqZWN0ICkge1xyXG5cclxuXHRcdGNvbnN0IGZvZyA9IHNjZW5lLmZvZztcclxuXHRcdGNvbnN0IGdlb21ldHJ5ID0gb2JqZWN0Lmdlb21ldHJ5O1xyXG5cdFx0Y29uc3QgZW52aXJvbm1lbnQgPSBtYXRlcmlhbC5pc01lc2hTdGFuZGFyZE1hdGVyaWFsID8gc2NlbmUuZW52aXJvbm1lbnQgOiBudWxsO1xyXG5cclxuXHRcdGNvbnN0IGVudk1hcCA9ICggbWF0ZXJpYWwuaXNNZXNoU3RhbmRhcmRNYXRlcmlhbCA/IGN1YmV1dm1hcHMgOiBjdWJlbWFwcyApLmdldCggbWF0ZXJpYWwuZW52TWFwIHx8IGVudmlyb25tZW50ICk7XHJcblx0XHRjb25zdCBlbnZNYXBDdWJlVVZIZWlnaHQgPSAoICEhIGVudk1hcCApICYmICggZW52TWFwLm1hcHBpbmcgPT09IEN1YmVVVlJlZmxlY3Rpb25NYXBwaW5nICkgPyBlbnZNYXAuaW1hZ2UuaGVpZ2h0IDogbnVsbDtcclxuXHJcblx0XHRjb25zdCBzaGFkZXJJRCA9IHNoYWRlcklEc1sgbWF0ZXJpYWwudHlwZSBdO1xyXG5cclxuXHRcdC8vIGhldXJpc3RpY3MgdG8gY3JlYXRlIHNoYWRlciBwYXJhbWV0ZXJzIGFjY29yZGluZyB0byBsaWdodHMgaW4gdGhlIHNjZW5lXHJcblx0XHQvLyAobm90IHRvIGJsb3cgb3ZlciBtYXhMaWdodHMgYnVkZ2V0KVxyXG5cclxuXHRcdGlmICggbWF0ZXJpYWwucHJlY2lzaW9uICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0cHJlY2lzaW9uID0gY2FwYWJpbGl0aWVzLmdldE1heFByZWNpc2lvbiggbWF0ZXJpYWwucHJlY2lzaW9uICk7XHJcblxyXG5cdFx0XHRpZiAoIHByZWNpc2lvbiAhPT0gbWF0ZXJpYWwucHJlY2lzaW9uICkge1xyXG5cclxuXHRcdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5XZWJHTFByb2dyYW0uZ2V0UGFyYW1ldGVyczonLCBtYXRlcmlhbC5wcmVjaXNpb24sICdub3Qgc3VwcG9ydGVkLCB1c2luZycsIHByZWNpc2lvbiwgJ2luc3RlYWQuJyApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvL1xyXG5cclxuXHRcdGNvbnN0IG1vcnBoQXR0cmlidXRlID0gZ2VvbWV0cnkubW9ycGhBdHRyaWJ1dGVzLnBvc2l0aW9uIHx8IGdlb21ldHJ5Lm1vcnBoQXR0cmlidXRlcy5ub3JtYWwgfHwgZ2VvbWV0cnkubW9ycGhBdHRyaWJ1dGVzLmNvbG9yO1xyXG5cdFx0Y29uc3QgbW9ycGhUYXJnZXRzQ291bnQgPSAoIG1vcnBoQXR0cmlidXRlICE9PSB1bmRlZmluZWQgKSA/IG1vcnBoQXR0cmlidXRlLmxlbmd0aCA6IDA7XHJcblxyXG5cdFx0bGV0IG1vcnBoVGV4dHVyZVN0cmlkZSA9IDA7XHJcblxyXG5cdFx0aWYgKCBnZW9tZXRyeS5tb3JwaEF0dHJpYnV0ZXMucG9zaXRpb24gIT09IHVuZGVmaW5lZCApIG1vcnBoVGV4dHVyZVN0cmlkZSA9IDE7XHJcblx0XHRpZiAoIGdlb21ldHJ5Lm1vcnBoQXR0cmlidXRlcy5ub3JtYWwgIT09IHVuZGVmaW5lZCApIG1vcnBoVGV4dHVyZVN0cmlkZSA9IDI7XHJcblx0XHRpZiAoIGdlb21ldHJ5Lm1vcnBoQXR0cmlidXRlcy5jb2xvciAhPT0gdW5kZWZpbmVkICkgbW9ycGhUZXh0dXJlU3RyaWRlID0gMztcclxuXHJcblx0XHQvL1xyXG5cclxuXHRcdGxldCB2ZXJ0ZXhTaGFkZXIsIGZyYWdtZW50U2hhZGVyO1xyXG5cdFx0bGV0IGN1c3RvbVZlcnRleFNoYWRlcklELCBjdXN0b21GcmFnbWVudFNoYWRlcklEO1xyXG5cclxuXHRcdGlmICggc2hhZGVySUQgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBzaGFkZXIgPSBTaGFkZXJMaWJbIHNoYWRlcklEIF07XHJcblxyXG5cdFx0XHR2ZXJ0ZXhTaGFkZXIgPSBzaGFkZXIudmVydGV4U2hhZGVyO1xyXG5cdFx0XHRmcmFnbWVudFNoYWRlciA9IHNoYWRlci5mcmFnbWVudFNoYWRlcjtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0dmVydGV4U2hhZGVyID0gbWF0ZXJpYWwudmVydGV4U2hhZGVyO1xyXG5cdFx0XHRmcmFnbWVudFNoYWRlciA9IG1hdGVyaWFsLmZyYWdtZW50U2hhZGVyO1xyXG5cclxuXHRcdFx0X2N1c3RvbVNoYWRlcnMudXBkYXRlKCBtYXRlcmlhbCApO1xyXG5cclxuXHRcdFx0Y3VzdG9tVmVydGV4U2hhZGVySUQgPSBfY3VzdG9tU2hhZGVycy5nZXRWZXJ0ZXhTaGFkZXJJRCggbWF0ZXJpYWwgKTtcclxuXHRcdFx0Y3VzdG9tRnJhZ21lbnRTaGFkZXJJRCA9IF9jdXN0b21TaGFkZXJzLmdldEZyYWdtZW50U2hhZGVySUQoIG1hdGVyaWFsICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGNvbnN0IGN1cnJlbnRSZW5kZXJUYXJnZXQgPSByZW5kZXJlci5nZXRSZW5kZXJUYXJnZXQoKTtcclxuXHJcblx0XHRjb25zdCBJU19JTlNUQU5DRURNRVNIID0gb2JqZWN0LmlzSW5zdGFuY2VkTWVzaCA9PT0gdHJ1ZTtcclxuXHRcdGNvbnN0IElTX0JBVENIRURNRVNIID0gb2JqZWN0LmlzQmF0Y2hlZE1lc2ggPT09IHRydWU7XHJcblxyXG5cdFx0Y29uc3QgSEFTX01BUCA9ICEhIG1hdGVyaWFsLm1hcDtcclxuXHRcdGNvbnN0IEhBU19NQVRDQVAgPSAhISBtYXRlcmlhbC5tYXRjYXA7XHJcblx0XHRjb25zdCBIQVNfRU5WTUFQID0gISEgZW52TWFwO1xyXG5cdFx0Y29uc3QgSEFTX0FPTUFQID0gISEgbWF0ZXJpYWwuYW9NYXA7XHJcblx0XHRjb25zdCBIQVNfTElHSFRNQVAgPSAhISBtYXRlcmlhbC5saWdodE1hcDtcclxuXHRcdGNvbnN0IEhBU19CVU1QTUFQID0gISEgbWF0ZXJpYWwuYnVtcE1hcDtcclxuXHRcdGNvbnN0IEhBU19OT1JNQUxNQVAgPSAhISBtYXRlcmlhbC5ub3JtYWxNYXA7XHJcblx0XHRjb25zdCBIQVNfRElTUExBQ0VNRU5UTUFQID0gISEgbWF0ZXJpYWwuZGlzcGxhY2VtZW50TWFwO1xyXG5cdFx0Y29uc3QgSEFTX0VNSVNTSVZFTUFQID0gISEgbWF0ZXJpYWwuZW1pc3NpdmVNYXA7XHJcblxyXG5cdFx0Y29uc3QgSEFTX01FVEFMTkVTU01BUCA9ICEhIG1hdGVyaWFsLm1ldGFsbmVzc01hcDtcclxuXHRcdGNvbnN0IEhBU19ST1VHSE5FU1NNQVAgPSAhISBtYXRlcmlhbC5yb3VnaG5lc3NNYXA7XHJcblxyXG5cdFx0Y29uc3QgSEFTX0FOSVNPVFJPUFkgPSBtYXRlcmlhbC5hbmlzb3Ryb3B5ID4gMDtcclxuXHRcdGNvbnN0IEhBU19DTEVBUkNPQVQgPSBtYXRlcmlhbC5jbGVhcmNvYXQgPiAwO1xyXG5cdFx0Y29uc3QgSEFTX0lSSURFU0NFTkNFID0gbWF0ZXJpYWwuaXJpZGVzY2VuY2UgPiAwO1xyXG5cdFx0Y29uc3QgSEFTX1NIRUVOID0gbWF0ZXJpYWwuc2hlZW4gPiAwO1xyXG5cdFx0Y29uc3QgSEFTX1RSQU5TTUlTU0lPTiA9IG1hdGVyaWFsLnRyYW5zbWlzc2lvbiA+IDA7XHJcblxyXG5cdFx0Y29uc3QgSEFTX0FOSVNPVFJPUFlNQVAgPSBIQVNfQU5JU09UUk9QWSAmJiAhISBtYXRlcmlhbC5hbmlzb3Ryb3B5TWFwO1xyXG5cclxuXHRcdGNvbnN0IEhBU19DTEVBUkNPQVRNQVAgPSBIQVNfQ0xFQVJDT0FUICYmICEhIG1hdGVyaWFsLmNsZWFyY29hdE1hcDtcclxuXHRcdGNvbnN0IEhBU19DTEVBUkNPQVRfTk9STUFMTUFQID0gSEFTX0NMRUFSQ09BVCAmJiAhISBtYXRlcmlhbC5jbGVhcmNvYXROb3JtYWxNYXA7XHJcblx0XHRjb25zdCBIQVNfQ0xFQVJDT0FUX1JPVUdITkVTU01BUCA9IEhBU19DTEVBUkNPQVQgJiYgISEgbWF0ZXJpYWwuY2xlYXJjb2F0Um91Z2huZXNzTWFwO1xyXG5cclxuXHRcdGNvbnN0IEhBU19JUklERVNDRU5DRU1BUCA9IEhBU19JUklERVNDRU5DRSAmJiAhISBtYXRlcmlhbC5pcmlkZXNjZW5jZU1hcDtcclxuXHRcdGNvbnN0IEhBU19JUklERVNDRU5DRV9USElDS05FU1NNQVAgPSBIQVNfSVJJREVTQ0VOQ0UgJiYgISEgbWF0ZXJpYWwuaXJpZGVzY2VuY2VUaGlja25lc3NNYXA7XHJcblxyXG5cdFx0Y29uc3QgSEFTX1NIRUVOX0NPTE9STUFQID0gSEFTX1NIRUVOICYmICEhIG1hdGVyaWFsLnNoZWVuQ29sb3JNYXA7XHJcblx0XHRjb25zdCBIQVNfU0hFRU5fUk9VR0hORVNTTUFQID0gSEFTX1NIRUVOICYmICEhIG1hdGVyaWFsLnNoZWVuUm91Z2huZXNzTWFwO1xyXG5cclxuXHRcdGNvbnN0IEhBU19TUEVDVUxBUk1BUCA9ICEhIG1hdGVyaWFsLnNwZWN1bGFyTWFwO1xyXG5cdFx0Y29uc3QgSEFTX1NQRUNVTEFSX0NPTE9STUFQID0gISEgbWF0ZXJpYWwuc3BlY3VsYXJDb2xvck1hcDtcclxuXHRcdGNvbnN0IEhBU19TUEVDVUxBUl9JTlRFTlNJVFlNQVAgPSAhISBtYXRlcmlhbC5zcGVjdWxhckludGVuc2l0eU1hcDtcclxuXHJcblx0XHRjb25zdCBIQVNfVFJBTlNNSVNTSU9OTUFQID0gSEFTX1RSQU5TTUlTU0lPTiAmJiAhISBtYXRlcmlhbC50cmFuc21pc3Npb25NYXA7XHJcblx0XHRjb25zdCBIQVNfVEhJQ0tORVNTTUFQID0gSEFTX1RSQU5TTUlTU0lPTiAmJiAhISBtYXRlcmlhbC50aGlja25lc3NNYXA7XHJcblxyXG5cdFx0Y29uc3QgSEFTX0dSQURJRU5UTUFQID0gISEgbWF0ZXJpYWwuZ3JhZGllbnRNYXA7XHJcblxyXG5cdFx0Y29uc3QgSEFTX0FMUEhBTUFQID0gISEgbWF0ZXJpYWwuYWxwaGFNYXA7XHJcblxyXG5cdFx0Y29uc3QgSEFTX0FMUEhBVEVTVCA9IG1hdGVyaWFsLmFscGhhVGVzdCA+IDA7XHJcblxyXG5cdFx0Y29uc3QgSEFTX0FMUEhBSEFTSCA9ICEhIG1hdGVyaWFsLmFscGhhSGFzaDtcclxuXHJcblx0XHRjb25zdCBIQVNfRVhURU5TSU9OUyA9ICEhIG1hdGVyaWFsLmV4dGVuc2lvbnM7XHJcblxyXG5cdFx0bGV0IHRvbmVNYXBwaW5nID0gTm9Ub25lTWFwcGluZztcclxuXHJcblx0XHRpZiAoIG1hdGVyaWFsLnRvbmVNYXBwZWQgKSB7XHJcblxyXG5cdFx0XHRpZiAoIGN1cnJlbnRSZW5kZXJUYXJnZXQgPT09IG51bGwgfHwgY3VycmVudFJlbmRlclRhcmdldC5pc1hSUmVuZGVyVGFyZ2V0ID09PSB0cnVlICkge1xyXG5cclxuXHRcdFx0XHR0b25lTWFwcGluZyA9IHJlbmRlcmVyLnRvbmVNYXBwaW5nO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCBwYXJhbWV0ZXJzID0ge1xyXG5cclxuXHRcdFx0aXNXZWJHTDI6IElTX1dFQkdMMixcclxuXHJcblx0XHRcdHNoYWRlcklEOiBzaGFkZXJJRCxcclxuXHRcdFx0c2hhZGVyVHlwZTogbWF0ZXJpYWwudHlwZSxcclxuXHRcdFx0c2hhZGVyTmFtZTogbWF0ZXJpYWwubmFtZSxcclxuXHJcblx0XHRcdHZlcnRleFNoYWRlcjogdmVydGV4U2hhZGVyLFxyXG5cdFx0XHRmcmFnbWVudFNoYWRlcjogZnJhZ21lbnRTaGFkZXIsXHJcblx0XHRcdGRlZmluZXM6IG1hdGVyaWFsLmRlZmluZXMsXHJcblxyXG5cdFx0XHRjdXN0b21WZXJ0ZXhTaGFkZXJJRDogY3VzdG9tVmVydGV4U2hhZGVySUQsXHJcblx0XHRcdGN1c3RvbUZyYWdtZW50U2hhZGVySUQ6IGN1c3RvbUZyYWdtZW50U2hhZGVySUQsXHJcblxyXG5cdFx0XHRpc1Jhd1NoYWRlck1hdGVyaWFsOiBtYXRlcmlhbC5pc1Jhd1NoYWRlck1hdGVyaWFsID09PSB0cnVlLFxyXG5cdFx0XHRnbHNsVmVyc2lvbjogbWF0ZXJpYWwuZ2xzbFZlcnNpb24sXHJcblxyXG5cdFx0XHRwcmVjaXNpb246IHByZWNpc2lvbixcclxuXHJcblx0XHRcdGJhdGNoaW5nOiBJU19CQVRDSEVETUVTSCxcclxuXHRcdFx0aW5zdGFuY2luZzogSVNfSU5TVEFOQ0VETUVTSCxcclxuXHRcdFx0aW5zdGFuY2luZ0NvbG9yOiBJU19JTlNUQU5DRURNRVNIICYmIG9iamVjdC5pbnN0YW5jZUNvbG9yICE9PSBudWxsLFxyXG5cclxuXHRcdFx0c3VwcG9ydHNWZXJ0ZXhUZXh0dXJlczogU1VQUE9SVFNfVkVSVEVYX1RFWFRVUkVTLFxyXG5cdFx0XHRvdXRwdXRDb2xvclNwYWNlOiAoIGN1cnJlbnRSZW5kZXJUYXJnZXQgPT09IG51bGwgKSA/IHJlbmRlcmVyLm91dHB1dENvbG9yU3BhY2UgOiAoIGN1cnJlbnRSZW5kZXJUYXJnZXQuaXNYUlJlbmRlclRhcmdldCA9PT0gdHJ1ZSA/IGN1cnJlbnRSZW5kZXJUYXJnZXQudGV4dHVyZS5jb2xvclNwYWNlIDogTGluZWFyU1JHQkNvbG9yU3BhY2UgKSxcclxuXHRcdFx0YWxwaGFUb0NvdmVyYWdlOiAhISBtYXRlcmlhbC5hbHBoYVRvQ292ZXJhZ2UsXHJcblxyXG5cdFx0XHRtYXA6IEhBU19NQVAsXHJcblx0XHRcdG1hdGNhcDogSEFTX01BVENBUCxcclxuXHRcdFx0ZW52TWFwOiBIQVNfRU5WTUFQLFxyXG5cdFx0XHRlbnZNYXBNb2RlOiBIQVNfRU5WTUFQICYmIGVudk1hcC5tYXBwaW5nLFxyXG5cdFx0XHRlbnZNYXBDdWJlVVZIZWlnaHQ6IGVudk1hcEN1YmVVVkhlaWdodCxcclxuXHRcdFx0YW9NYXA6IEhBU19BT01BUCxcclxuXHRcdFx0bGlnaHRNYXA6IEhBU19MSUdIVE1BUCxcclxuXHRcdFx0YnVtcE1hcDogSEFTX0JVTVBNQVAsXHJcblx0XHRcdG5vcm1hbE1hcDogSEFTX05PUk1BTE1BUCxcclxuXHRcdFx0ZGlzcGxhY2VtZW50TWFwOiBTVVBQT1JUU19WRVJURVhfVEVYVFVSRVMgJiYgSEFTX0RJU1BMQUNFTUVOVE1BUCxcclxuXHRcdFx0ZW1pc3NpdmVNYXA6IEhBU19FTUlTU0lWRU1BUCxcclxuXHJcblx0XHRcdG5vcm1hbE1hcE9iamVjdFNwYWNlOiBIQVNfTk9STUFMTUFQICYmIG1hdGVyaWFsLm5vcm1hbE1hcFR5cGUgPT09IE9iamVjdFNwYWNlTm9ybWFsTWFwLFxyXG5cdFx0XHRub3JtYWxNYXBUYW5nZW50U3BhY2U6IEhBU19OT1JNQUxNQVAgJiYgbWF0ZXJpYWwubm9ybWFsTWFwVHlwZSA9PT0gVGFuZ2VudFNwYWNlTm9ybWFsTWFwLFxyXG5cclxuXHRcdFx0bWV0YWxuZXNzTWFwOiBIQVNfTUVUQUxORVNTTUFQLFxyXG5cdFx0XHRyb3VnaG5lc3NNYXA6IEhBU19ST1VHSE5FU1NNQVAsXHJcblxyXG5cdFx0XHRhbmlzb3Ryb3B5OiBIQVNfQU5JU09UUk9QWSxcclxuXHRcdFx0YW5pc290cm9weU1hcDogSEFTX0FOSVNPVFJPUFlNQVAsXHJcblxyXG5cdFx0XHRjbGVhcmNvYXQ6IEhBU19DTEVBUkNPQVQsXHJcblx0XHRcdGNsZWFyY29hdE1hcDogSEFTX0NMRUFSQ09BVE1BUCxcclxuXHRcdFx0Y2xlYXJjb2F0Tm9ybWFsTWFwOiBIQVNfQ0xFQVJDT0FUX05PUk1BTE1BUCxcclxuXHRcdFx0Y2xlYXJjb2F0Um91Z2huZXNzTWFwOiBIQVNfQ0xFQVJDT0FUX1JPVUdITkVTU01BUCxcclxuXHJcblx0XHRcdGlyaWRlc2NlbmNlOiBIQVNfSVJJREVTQ0VOQ0UsXHJcblx0XHRcdGlyaWRlc2NlbmNlTWFwOiBIQVNfSVJJREVTQ0VOQ0VNQVAsXHJcblx0XHRcdGlyaWRlc2NlbmNlVGhpY2tuZXNzTWFwOiBIQVNfSVJJREVTQ0VOQ0VfVEhJQ0tORVNTTUFQLFxyXG5cclxuXHRcdFx0c2hlZW46IEhBU19TSEVFTixcclxuXHRcdFx0c2hlZW5Db2xvck1hcDogSEFTX1NIRUVOX0NPTE9STUFQLFxyXG5cdFx0XHRzaGVlblJvdWdobmVzc01hcDogSEFTX1NIRUVOX1JPVUdITkVTU01BUCxcclxuXHJcblx0XHRcdHNwZWN1bGFyTWFwOiBIQVNfU1BFQ1VMQVJNQVAsXHJcblx0XHRcdHNwZWN1bGFyQ29sb3JNYXA6IEhBU19TUEVDVUxBUl9DT0xPUk1BUCxcclxuXHRcdFx0c3BlY3VsYXJJbnRlbnNpdHlNYXA6IEhBU19TUEVDVUxBUl9JTlRFTlNJVFlNQVAsXHJcblxyXG5cdFx0XHR0cmFuc21pc3Npb246IEhBU19UUkFOU01JU1NJT04sXHJcblx0XHRcdHRyYW5zbWlzc2lvbk1hcDogSEFTX1RSQU5TTUlTU0lPTk1BUCxcclxuXHRcdFx0dGhpY2tuZXNzTWFwOiBIQVNfVEhJQ0tORVNTTUFQLFxyXG5cclxuXHRcdFx0Z3JhZGllbnRNYXA6IEhBU19HUkFESUVOVE1BUCxcclxuXHJcblx0XHRcdG9wYXF1ZTogbWF0ZXJpYWwudHJhbnNwYXJlbnQgPT09IGZhbHNlICYmIG1hdGVyaWFsLmJsZW5kaW5nID09PSBOb3JtYWxCbGVuZGluZyAmJiBtYXRlcmlhbC5hbHBoYVRvQ292ZXJhZ2UgPT09IGZhbHNlLFxyXG5cclxuXHRcdFx0YWxwaGFNYXA6IEhBU19BTFBIQU1BUCxcclxuXHRcdFx0YWxwaGFUZXN0OiBIQVNfQUxQSEFURVNULFxyXG5cdFx0XHRhbHBoYUhhc2g6IEhBU19BTFBIQUhBU0gsXHJcblxyXG5cdFx0XHRjb21iaW5lOiBtYXRlcmlhbC5jb21iaW5lLFxyXG5cclxuXHRcdFx0Ly9cclxuXHJcblx0XHRcdG1hcFV2OiBIQVNfTUFQICYmIGdldENoYW5uZWwoIG1hdGVyaWFsLm1hcC5jaGFubmVsICksXHJcblx0XHRcdGFvTWFwVXY6IEhBU19BT01BUCAmJiBnZXRDaGFubmVsKCBtYXRlcmlhbC5hb01hcC5jaGFubmVsICksXHJcblx0XHRcdGxpZ2h0TWFwVXY6IEhBU19MSUdIVE1BUCAmJiBnZXRDaGFubmVsKCBtYXRlcmlhbC5saWdodE1hcC5jaGFubmVsICksXHJcblx0XHRcdGJ1bXBNYXBVdjogSEFTX0JVTVBNQVAgJiYgZ2V0Q2hhbm5lbCggbWF0ZXJpYWwuYnVtcE1hcC5jaGFubmVsICksXHJcblx0XHRcdG5vcm1hbE1hcFV2OiBIQVNfTk9STUFMTUFQICYmIGdldENoYW5uZWwoIG1hdGVyaWFsLm5vcm1hbE1hcC5jaGFubmVsICksXHJcblx0XHRcdGRpc3BsYWNlbWVudE1hcFV2OiBIQVNfRElTUExBQ0VNRU5UTUFQICYmIGdldENoYW5uZWwoIG1hdGVyaWFsLmRpc3BsYWNlbWVudE1hcC5jaGFubmVsICksXHJcblx0XHRcdGVtaXNzaXZlTWFwVXY6IEhBU19FTUlTU0lWRU1BUCAmJiBnZXRDaGFubmVsKCBtYXRlcmlhbC5lbWlzc2l2ZU1hcC5jaGFubmVsICksXHJcblxyXG5cdFx0XHRtZXRhbG5lc3NNYXBVdjogSEFTX01FVEFMTkVTU01BUCAmJiBnZXRDaGFubmVsKCBtYXRlcmlhbC5tZXRhbG5lc3NNYXAuY2hhbm5lbCApLFxyXG5cdFx0XHRyb3VnaG5lc3NNYXBVdjogSEFTX1JPVUdITkVTU01BUCAmJiBnZXRDaGFubmVsKCBtYXRlcmlhbC5yb3VnaG5lc3NNYXAuY2hhbm5lbCApLFxyXG5cclxuXHRcdFx0YW5pc290cm9weU1hcFV2OiBIQVNfQU5JU09UUk9QWU1BUCAmJiBnZXRDaGFubmVsKCBtYXRlcmlhbC5hbmlzb3Ryb3B5TWFwLmNoYW5uZWwgKSxcclxuXHJcblx0XHRcdGNsZWFyY29hdE1hcFV2OiBIQVNfQ0xFQVJDT0FUTUFQICYmIGdldENoYW5uZWwoIG1hdGVyaWFsLmNsZWFyY29hdE1hcC5jaGFubmVsICksXHJcblx0XHRcdGNsZWFyY29hdE5vcm1hbE1hcFV2OiBIQVNfQ0xFQVJDT0FUX05PUk1BTE1BUCAmJiBnZXRDaGFubmVsKCBtYXRlcmlhbC5jbGVhcmNvYXROb3JtYWxNYXAuY2hhbm5lbCApLFxyXG5cdFx0XHRjbGVhcmNvYXRSb3VnaG5lc3NNYXBVdjogSEFTX0NMRUFSQ09BVF9ST1VHSE5FU1NNQVAgJiYgZ2V0Q2hhbm5lbCggbWF0ZXJpYWwuY2xlYXJjb2F0Um91Z2huZXNzTWFwLmNoYW5uZWwgKSxcclxuXHJcblx0XHRcdGlyaWRlc2NlbmNlTWFwVXY6IEhBU19JUklERVNDRU5DRU1BUCAmJiBnZXRDaGFubmVsKCBtYXRlcmlhbC5pcmlkZXNjZW5jZU1hcC5jaGFubmVsICksXHJcblx0XHRcdGlyaWRlc2NlbmNlVGhpY2tuZXNzTWFwVXY6IEhBU19JUklERVNDRU5DRV9USElDS05FU1NNQVAgJiYgZ2V0Q2hhbm5lbCggbWF0ZXJpYWwuaXJpZGVzY2VuY2VUaGlja25lc3NNYXAuY2hhbm5lbCApLFxyXG5cclxuXHRcdFx0c2hlZW5Db2xvck1hcFV2OiBIQVNfU0hFRU5fQ09MT1JNQVAgJiYgZ2V0Q2hhbm5lbCggbWF0ZXJpYWwuc2hlZW5Db2xvck1hcC5jaGFubmVsICksXHJcblx0XHRcdHNoZWVuUm91Z2huZXNzTWFwVXY6IEhBU19TSEVFTl9ST1VHSE5FU1NNQVAgJiYgZ2V0Q2hhbm5lbCggbWF0ZXJpYWwuc2hlZW5Sb3VnaG5lc3NNYXAuY2hhbm5lbCApLFxyXG5cclxuXHRcdFx0c3BlY3VsYXJNYXBVdjogSEFTX1NQRUNVTEFSTUFQICYmIGdldENoYW5uZWwoIG1hdGVyaWFsLnNwZWN1bGFyTWFwLmNoYW5uZWwgKSxcclxuXHRcdFx0c3BlY3VsYXJDb2xvck1hcFV2OiBIQVNfU1BFQ1VMQVJfQ09MT1JNQVAgJiYgZ2V0Q2hhbm5lbCggbWF0ZXJpYWwuc3BlY3VsYXJDb2xvck1hcC5jaGFubmVsICksXHJcblx0XHRcdHNwZWN1bGFySW50ZW5zaXR5TWFwVXY6IEhBU19TUEVDVUxBUl9JTlRFTlNJVFlNQVAgJiYgZ2V0Q2hhbm5lbCggbWF0ZXJpYWwuc3BlY3VsYXJJbnRlbnNpdHlNYXAuY2hhbm5lbCApLFxyXG5cclxuXHRcdFx0dHJhbnNtaXNzaW9uTWFwVXY6IEhBU19UUkFOU01JU1NJT05NQVAgJiYgZ2V0Q2hhbm5lbCggbWF0ZXJpYWwudHJhbnNtaXNzaW9uTWFwLmNoYW5uZWwgKSxcclxuXHRcdFx0dGhpY2tuZXNzTWFwVXY6IEhBU19USElDS05FU1NNQVAgJiYgZ2V0Q2hhbm5lbCggbWF0ZXJpYWwudGhpY2tuZXNzTWFwLmNoYW5uZWwgKSxcclxuXHJcblx0XHRcdGFscGhhTWFwVXY6IEhBU19BTFBIQU1BUCAmJiBnZXRDaGFubmVsKCBtYXRlcmlhbC5hbHBoYU1hcC5jaGFubmVsICksXHJcblxyXG5cdFx0XHQvL1xyXG5cclxuXHRcdFx0dmVydGV4VGFuZ2VudHM6ICEhIGdlb21ldHJ5LmF0dHJpYnV0ZXMudGFuZ2VudCAmJiAoIEhBU19OT1JNQUxNQVAgfHwgSEFTX0FOSVNPVFJPUFkgKSxcclxuXHRcdFx0dmVydGV4Q29sb3JzOiBtYXRlcmlhbC52ZXJ0ZXhDb2xvcnMsXHJcblx0XHRcdHZlcnRleEFscGhhczogbWF0ZXJpYWwudmVydGV4Q29sb3JzID09PSB0cnVlICYmICEhIGdlb21ldHJ5LmF0dHJpYnV0ZXMuY29sb3IgJiYgZ2VvbWV0cnkuYXR0cmlidXRlcy5jb2xvci5pdGVtU2l6ZSA9PT0gNCxcclxuXHJcblx0XHRcdHBvaW50c1V2czogb2JqZWN0LmlzUG9pbnRzID09PSB0cnVlICYmICEhIGdlb21ldHJ5LmF0dHJpYnV0ZXMudXYgJiYgKCBIQVNfTUFQIHx8IEhBU19BTFBIQU1BUCApLFxyXG5cclxuXHRcdFx0Zm9nOiAhISBmb2csXHJcblx0XHRcdHVzZUZvZzogbWF0ZXJpYWwuZm9nID09PSB0cnVlLFxyXG5cdFx0XHRmb2dFeHAyOiAoICEhIGZvZyAmJiBmb2cuaXNGb2dFeHAyICksXHJcblxyXG5cdFx0XHRmbGF0U2hhZGluZzogbWF0ZXJpYWwuZmxhdFNoYWRpbmcgPT09IHRydWUsXHJcblxyXG5cdFx0XHRzaXplQXR0ZW51YXRpb246IG1hdGVyaWFsLnNpemVBdHRlbnVhdGlvbiA9PT0gdHJ1ZSxcclxuXHRcdFx0bG9nYXJpdGhtaWNEZXB0aEJ1ZmZlcjogbG9nYXJpdGhtaWNEZXB0aEJ1ZmZlcixcclxuXHJcblx0XHRcdHNraW5uaW5nOiBvYmplY3QuaXNTa2lubmVkTWVzaCA9PT0gdHJ1ZSxcclxuXHJcblx0XHRcdG1vcnBoVGFyZ2V0czogZ2VvbWV0cnkubW9ycGhBdHRyaWJ1dGVzLnBvc2l0aW9uICE9PSB1bmRlZmluZWQsXHJcblx0XHRcdG1vcnBoTm9ybWFsczogZ2VvbWV0cnkubW9ycGhBdHRyaWJ1dGVzLm5vcm1hbCAhPT0gdW5kZWZpbmVkLFxyXG5cdFx0XHRtb3JwaENvbG9yczogZ2VvbWV0cnkubW9ycGhBdHRyaWJ1dGVzLmNvbG9yICE9PSB1bmRlZmluZWQsXHJcblx0XHRcdG1vcnBoVGFyZ2V0c0NvdW50OiBtb3JwaFRhcmdldHNDb3VudCxcclxuXHRcdFx0bW9ycGhUZXh0dXJlU3RyaWRlOiBtb3JwaFRleHR1cmVTdHJpZGUsXHJcblxyXG5cdFx0XHRudW1EaXJMaWdodHM6IGxpZ2h0cy5kaXJlY3Rpb25hbC5sZW5ndGgsXHJcblx0XHRcdG51bVBvaW50TGlnaHRzOiBsaWdodHMucG9pbnQubGVuZ3RoLFxyXG5cdFx0XHRudW1TcG90TGlnaHRzOiBsaWdodHMuc3BvdC5sZW5ndGgsXHJcblx0XHRcdG51bVNwb3RMaWdodE1hcHM6IGxpZ2h0cy5zcG90TGlnaHRNYXAubGVuZ3RoLFxyXG5cdFx0XHRudW1SZWN0QXJlYUxpZ2h0czogbGlnaHRzLnJlY3RBcmVhLmxlbmd0aCxcclxuXHRcdFx0bnVtSGVtaUxpZ2h0czogbGlnaHRzLmhlbWkubGVuZ3RoLFxyXG5cclxuXHRcdFx0bnVtRGlyTGlnaHRTaGFkb3dzOiBsaWdodHMuZGlyZWN0aW9uYWxTaGFkb3dNYXAubGVuZ3RoLFxyXG5cdFx0XHRudW1Qb2ludExpZ2h0U2hhZG93czogbGlnaHRzLnBvaW50U2hhZG93TWFwLmxlbmd0aCxcclxuXHRcdFx0bnVtU3BvdExpZ2h0U2hhZG93czogbGlnaHRzLnNwb3RTaGFkb3dNYXAubGVuZ3RoLFxyXG5cdFx0XHRudW1TcG90TGlnaHRTaGFkb3dzV2l0aE1hcHM6IGxpZ2h0cy5udW1TcG90TGlnaHRTaGFkb3dzV2l0aE1hcHMsXHJcblxyXG5cdFx0XHRudW1MaWdodFByb2JlczogbGlnaHRzLm51bUxpZ2h0UHJvYmVzLFxyXG5cclxuXHRcdFx0bnVtQ2xpcHBpbmdQbGFuZXM6IGNsaXBwaW5nLm51bVBsYW5lcyxcclxuXHRcdFx0bnVtQ2xpcEludGVyc2VjdGlvbjogY2xpcHBpbmcubnVtSW50ZXJzZWN0aW9uLFxyXG5cclxuXHRcdFx0ZGl0aGVyaW5nOiBtYXRlcmlhbC5kaXRoZXJpbmcsXHJcblxyXG5cdFx0XHRzaGFkb3dNYXBFbmFibGVkOiByZW5kZXJlci5zaGFkb3dNYXAuZW5hYmxlZCAmJiBzaGFkb3dzLmxlbmd0aCA+IDAsXHJcblx0XHRcdHNoYWRvd01hcFR5cGU6IHJlbmRlcmVyLnNoYWRvd01hcC50eXBlLFxyXG5cclxuXHRcdFx0dG9uZU1hcHBpbmc6IHRvbmVNYXBwaW5nLFxyXG5cdFx0XHR1c2VMZWdhY3lMaWdodHM6IHJlbmRlcmVyLl91c2VMZWdhY3lMaWdodHMsXHJcblxyXG5cdFx0XHRkZWNvZGVWaWRlb1RleHR1cmU6IEhBU19NQVAgJiYgKCBtYXRlcmlhbC5tYXAuaXNWaWRlb1RleHR1cmUgPT09IHRydWUgKSAmJiAoIENvbG9yTWFuYWdlbWVudC5nZXRUcmFuc2ZlciggbWF0ZXJpYWwubWFwLmNvbG9yU3BhY2UgKSA9PT0gU1JHQlRyYW5zZmVyICksXHJcblxyXG5cdFx0XHRwcmVtdWx0aXBsaWVkQWxwaGE6IG1hdGVyaWFsLnByZW11bHRpcGxpZWRBbHBoYSxcclxuXHJcblx0XHRcdGRvdWJsZVNpZGVkOiBtYXRlcmlhbC5zaWRlID09PSBEb3VibGVTaWRlLFxyXG5cdFx0XHRmbGlwU2lkZWQ6IG1hdGVyaWFsLnNpZGUgPT09IEJhY2tTaWRlLFxyXG5cclxuXHRcdFx0dXNlRGVwdGhQYWNraW5nOiBtYXRlcmlhbC5kZXB0aFBhY2tpbmcgPj0gMCxcclxuXHRcdFx0ZGVwdGhQYWNraW5nOiBtYXRlcmlhbC5kZXB0aFBhY2tpbmcgfHwgMCxcclxuXHJcblx0XHRcdGluZGV4MEF0dHJpYnV0ZU5hbWU6IG1hdGVyaWFsLmluZGV4MEF0dHJpYnV0ZU5hbWUsXHJcblxyXG5cdFx0XHRleHRlbnNpb25EZXJpdmF0aXZlczogSEFTX0VYVEVOU0lPTlMgJiYgbWF0ZXJpYWwuZXh0ZW5zaW9ucy5kZXJpdmF0aXZlcyA9PT0gdHJ1ZSxcclxuXHRcdFx0ZXh0ZW5zaW9uRnJhZ0RlcHRoOiBIQVNfRVhURU5TSU9OUyAmJiBtYXRlcmlhbC5leHRlbnNpb25zLmZyYWdEZXB0aCA9PT0gdHJ1ZSxcclxuXHRcdFx0ZXh0ZW5zaW9uRHJhd0J1ZmZlcnM6IEhBU19FWFRFTlNJT05TICYmIG1hdGVyaWFsLmV4dGVuc2lvbnMuZHJhd0J1ZmZlcnMgPT09IHRydWUsXHJcblx0XHRcdGV4dGVuc2lvblNoYWRlclRleHR1cmVMT0Q6IEhBU19FWFRFTlNJT05TICYmIG1hdGVyaWFsLmV4dGVuc2lvbnMuc2hhZGVyVGV4dHVyZUxPRCA9PT0gdHJ1ZSxcclxuXHRcdFx0ZXh0ZW5zaW9uQ2xpcEN1bGxEaXN0YW5jZTogSEFTX0VYVEVOU0lPTlMgJiYgbWF0ZXJpYWwuZXh0ZW5zaW9ucy5jbGlwQ3VsbERpc3RhbmNlID09PSB0cnVlICYmIGV4dGVuc2lvbnMuaGFzKCAnV0VCR0xfY2xpcF9jdWxsX2Rpc3RhbmNlJyApLFxyXG5cdFx0XHRleHRlbnNpb25NdWx0aURyYXc6IEhBU19FWFRFTlNJT05TICYmIG1hdGVyaWFsLmV4dGVuc2lvbnMubXVsdGlEcmF3ID09PSB0cnVlICYmIGV4dGVuc2lvbnMuaGFzKCAnV0VCR0xfbXVsdGlfZHJhdycgKSxcclxuXHJcblx0XHRcdHJlbmRlcmVyRXh0ZW5zaW9uRnJhZ0RlcHRoOiBJU19XRUJHTDIgfHwgZXh0ZW5zaW9ucy5oYXMoICdFWFRfZnJhZ19kZXB0aCcgKSxcclxuXHRcdFx0cmVuZGVyZXJFeHRlbnNpb25EcmF3QnVmZmVyczogSVNfV0VCR0wyIHx8IGV4dGVuc2lvbnMuaGFzKCAnV0VCR0xfZHJhd19idWZmZXJzJyApLFxyXG5cdFx0XHRyZW5kZXJlckV4dGVuc2lvblNoYWRlclRleHR1cmVMb2Q6IElTX1dFQkdMMiB8fCBleHRlbnNpb25zLmhhcyggJ0VYVF9zaGFkZXJfdGV4dHVyZV9sb2QnICksXHJcblx0XHRcdHJlbmRlcmVyRXh0ZW5zaW9uUGFyYWxsZWxTaGFkZXJDb21waWxlOiBleHRlbnNpb25zLmhhcyggJ0tIUl9wYXJhbGxlbF9zaGFkZXJfY29tcGlsZScgKSxcclxuXHJcblx0XHRcdGN1c3RvbVByb2dyYW1DYWNoZUtleTogbWF0ZXJpYWwuY3VzdG9tUHJvZ3JhbUNhY2hlS2V5KClcclxuXHJcblx0XHR9O1xyXG5cclxuXHRcdC8vIHRoZSB1c2FnZSBvZiBnZXRDaGFubmVsKCkgZGV0ZXJtaW5lcyB0aGUgYWN0aXZlIHRleHR1cmUgY2hhbm5lbHMgZm9yIHRoaXMgc2hhZGVyXHJcblxyXG5cdFx0cGFyYW1ldGVycy52ZXJ0ZXhVdjFzID0gX2FjdGl2ZUNoYW5uZWxzLmhhcyggMSApO1xyXG5cdFx0cGFyYW1ldGVycy52ZXJ0ZXhVdjJzID0gX2FjdGl2ZUNoYW5uZWxzLmhhcyggMiApO1xyXG5cdFx0cGFyYW1ldGVycy52ZXJ0ZXhVdjNzID0gX2FjdGl2ZUNoYW5uZWxzLmhhcyggMyApO1xyXG5cclxuXHRcdF9hY3RpdmVDaGFubmVscy5jbGVhcigpO1xyXG5cclxuXHRcdHJldHVybiBwYXJhbWV0ZXJzO1xyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIGdldFByb2dyYW1DYWNoZUtleSggcGFyYW1ldGVycyApIHtcclxuXHJcblx0XHRjb25zdCBhcnJheSA9IFtdO1xyXG5cclxuXHRcdGlmICggcGFyYW1ldGVycy5zaGFkZXJJRCApIHtcclxuXHJcblx0XHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMuc2hhZGVySUQgKTtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0YXJyYXkucHVzaCggcGFyYW1ldGVycy5jdXN0b21WZXJ0ZXhTaGFkZXJJRCApO1xyXG5cdFx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLmN1c3RvbUZyYWdtZW50U2hhZGVySUQgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBwYXJhbWV0ZXJzLmRlZmluZXMgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdGZvciAoIGNvbnN0IG5hbWUgaW4gcGFyYW1ldGVycy5kZWZpbmVzICkge1xyXG5cclxuXHRcdFx0XHRhcnJheS5wdXNoKCBuYW1lICk7XHJcblx0XHRcdFx0YXJyYXkucHVzaCggcGFyYW1ldGVycy5kZWZpbmVzWyBuYW1lIF0gKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBwYXJhbWV0ZXJzLmlzUmF3U2hhZGVyTWF0ZXJpYWwgPT09IGZhbHNlICkge1xyXG5cclxuXHRcdFx0Z2V0UHJvZ3JhbUNhY2hlS2V5UGFyYW1ldGVycyggYXJyYXksIHBhcmFtZXRlcnMgKTtcclxuXHRcdFx0Z2V0UHJvZ3JhbUNhY2hlS2V5Qm9vbGVhbnMoIGFycmF5LCBwYXJhbWV0ZXJzICk7XHJcblx0XHRcdGFycmF5LnB1c2goIHJlbmRlcmVyLm91dHB1dENvbG9yU3BhY2UgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0YXJyYXkucHVzaCggcGFyYW1ldGVycy5jdXN0b21Qcm9ncmFtQ2FjaGVLZXkgKTtcclxuXHJcblx0XHRyZXR1cm4gYXJyYXkuam9pbigpO1xyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIGdldFByb2dyYW1DYWNoZUtleVBhcmFtZXRlcnMoIGFycmF5LCBwYXJhbWV0ZXJzICkge1xyXG5cclxuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMucHJlY2lzaW9uICk7XHJcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLm91dHB1dENvbG9yU3BhY2UgKTtcclxuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMuZW52TWFwTW9kZSApO1xyXG5cdFx0YXJyYXkucHVzaCggcGFyYW1ldGVycy5lbnZNYXBDdWJlVVZIZWlnaHQgKTtcclxuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMubWFwVXYgKTtcclxuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMuYWxwaGFNYXBVdiApO1xyXG5cdFx0YXJyYXkucHVzaCggcGFyYW1ldGVycy5saWdodE1hcFV2ICk7XHJcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLmFvTWFwVXYgKTtcclxuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMuYnVtcE1hcFV2ICk7XHJcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLm5vcm1hbE1hcFV2ICk7XHJcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLmRpc3BsYWNlbWVudE1hcFV2ICk7XHJcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLmVtaXNzaXZlTWFwVXYgKTtcclxuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMubWV0YWxuZXNzTWFwVXYgKTtcclxuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMucm91Z2huZXNzTWFwVXYgKTtcclxuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMuYW5pc290cm9weU1hcFV2ICk7XHJcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLmNsZWFyY29hdE1hcFV2ICk7XHJcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLmNsZWFyY29hdE5vcm1hbE1hcFV2ICk7XHJcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLmNsZWFyY29hdFJvdWdobmVzc01hcFV2ICk7XHJcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLmlyaWRlc2NlbmNlTWFwVXYgKTtcclxuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMuaXJpZGVzY2VuY2VUaGlja25lc3NNYXBVdiApO1xyXG5cdFx0YXJyYXkucHVzaCggcGFyYW1ldGVycy5zaGVlbkNvbG9yTWFwVXYgKTtcclxuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMuc2hlZW5Sb3VnaG5lc3NNYXBVdiApO1xyXG5cdFx0YXJyYXkucHVzaCggcGFyYW1ldGVycy5zcGVjdWxhck1hcFV2ICk7XHJcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLnNwZWN1bGFyQ29sb3JNYXBVdiApO1xyXG5cdFx0YXJyYXkucHVzaCggcGFyYW1ldGVycy5zcGVjdWxhckludGVuc2l0eU1hcFV2ICk7XHJcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLnRyYW5zbWlzc2lvbk1hcFV2ICk7XHJcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLnRoaWNrbmVzc01hcFV2ICk7XHJcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLmNvbWJpbmUgKTtcclxuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMuZm9nRXhwMiApO1xyXG5cdFx0YXJyYXkucHVzaCggcGFyYW1ldGVycy5zaXplQXR0ZW51YXRpb24gKTtcclxuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMubW9ycGhUYXJnZXRzQ291bnQgKTtcclxuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMubW9ycGhBdHRyaWJ1dGVDb3VudCApO1xyXG5cdFx0YXJyYXkucHVzaCggcGFyYW1ldGVycy5udW1EaXJMaWdodHMgKTtcclxuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMubnVtUG9pbnRMaWdodHMgKTtcclxuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMubnVtU3BvdExpZ2h0cyApO1xyXG5cdFx0YXJyYXkucHVzaCggcGFyYW1ldGVycy5udW1TcG90TGlnaHRNYXBzICk7XHJcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLm51bUhlbWlMaWdodHMgKTtcclxuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMubnVtUmVjdEFyZWFMaWdodHMgKTtcclxuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMubnVtRGlyTGlnaHRTaGFkb3dzICk7XHJcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLm51bVBvaW50TGlnaHRTaGFkb3dzICk7XHJcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLm51bVNwb3RMaWdodFNoYWRvd3MgKTtcclxuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMubnVtU3BvdExpZ2h0U2hhZG93c1dpdGhNYXBzICk7XHJcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLm51bUxpZ2h0UHJvYmVzICk7XHJcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLnNoYWRvd01hcFR5cGUgKTtcclxuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMudG9uZU1hcHBpbmcgKTtcclxuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMubnVtQ2xpcHBpbmdQbGFuZXMgKTtcclxuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMubnVtQ2xpcEludGVyc2VjdGlvbiApO1xyXG5cdFx0YXJyYXkucHVzaCggcGFyYW1ldGVycy5kZXB0aFBhY2tpbmcgKTtcclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBnZXRQcm9ncmFtQ2FjaGVLZXlCb29sZWFucyggYXJyYXksIHBhcmFtZXRlcnMgKSB7XHJcblxyXG5cdFx0X3Byb2dyYW1MYXllcnMuZGlzYWJsZUFsbCgpO1xyXG5cclxuXHRcdGlmICggcGFyYW1ldGVycy5pc1dlYkdMMiApXHJcblx0XHRcdF9wcm9ncmFtTGF5ZXJzLmVuYWJsZSggMCApO1xyXG5cdFx0aWYgKCBwYXJhbWV0ZXJzLnN1cHBvcnRzVmVydGV4VGV4dHVyZXMgKVxyXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDEgKTtcclxuXHRcdGlmICggcGFyYW1ldGVycy5pbnN0YW5jaW5nIClcclxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCAyICk7XHJcblx0XHRpZiAoIHBhcmFtZXRlcnMuaW5zdGFuY2luZ0NvbG9yIClcclxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCAzICk7XHJcblx0XHRpZiAoIHBhcmFtZXRlcnMubWF0Y2FwIClcclxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCA0ICk7XHJcblx0XHRpZiAoIHBhcmFtZXRlcnMuZW52TWFwIClcclxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCA1ICk7XHJcblx0XHRpZiAoIHBhcmFtZXRlcnMubm9ybWFsTWFwT2JqZWN0U3BhY2UgKVxyXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDYgKTtcclxuXHRcdGlmICggcGFyYW1ldGVycy5ub3JtYWxNYXBUYW5nZW50U3BhY2UgKVxyXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDcgKTtcclxuXHRcdGlmICggcGFyYW1ldGVycy5jbGVhcmNvYXQgKVxyXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDggKTtcclxuXHRcdGlmICggcGFyYW1ldGVycy5pcmlkZXNjZW5jZSApXHJcblx0XHRcdF9wcm9ncmFtTGF5ZXJzLmVuYWJsZSggOSApO1xyXG5cdFx0aWYgKCBwYXJhbWV0ZXJzLmFscGhhVGVzdCApXHJcblx0XHRcdF9wcm9ncmFtTGF5ZXJzLmVuYWJsZSggMTAgKTtcclxuXHRcdGlmICggcGFyYW1ldGVycy52ZXJ0ZXhDb2xvcnMgKVxyXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDExICk7XHJcblx0XHRpZiAoIHBhcmFtZXRlcnMudmVydGV4QWxwaGFzIClcclxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCAxMiApO1xyXG5cdFx0aWYgKCBwYXJhbWV0ZXJzLnZlcnRleFV2MXMgKVxyXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDEzICk7XHJcblx0XHRpZiAoIHBhcmFtZXRlcnMudmVydGV4VXYycyApXHJcblx0XHRcdF9wcm9ncmFtTGF5ZXJzLmVuYWJsZSggMTQgKTtcclxuXHRcdGlmICggcGFyYW1ldGVycy52ZXJ0ZXhVdjNzIClcclxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCAxNSApO1xyXG5cdFx0aWYgKCBwYXJhbWV0ZXJzLnZlcnRleFRhbmdlbnRzIClcclxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCAxNiApO1xyXG5cdFx0aWYgKCBwYXJhbWV0ZXJzLmFuaXNvdHJvcHkgKVxyXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDE3ICk7XHJcblx0XHRpZiAoIHBhcmFtZXRlcnMuYWxwaGFIYXNoIClcclxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCAxOCApO1xyXG5cdFx0aWYgKCBwYXJhbWV0ZXJzLmJhdGNoaW5nIClcclxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCAxOSApO1xyXG5cclxuXHRcdGFycmF5LnB1c2goIF9wcm9ncmFtTGF5ZXJzLm1hc2sgKTtcclxuXHRcdF9wcm9ncmFtTGF5ZXJzLmRpc2FibGVBbGwoKTtcclxuXHJcblx0XHRpZiAoIHBhcmFtZXRlcnMuZm9nIClcclxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCAwICk7XHJcblx0XHRpZiAoIHBhcmFtZXRlcnMudXNlRm9nIClcclxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCAxICk7XHJcblx0XHRpZiAoIHBhcmFtZXRlcnMuZmxhdFNoYWRpbmcgKVxyXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDIgKTtcclxuXHRcdGlmICggcGFyYW1ldGVycy5sb2dhcml0aG1pY0RlcHRoQnVmZmVyIClcclxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCAzICk7XHJcblx0XHRpZiAoIHBhcmFtZXRlcnMuc2tpbm5pbmcgKVxyXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDQgKTtcclxuXHRcdGlmICggcGFyYW1ldGVycy5tb3JwaFRhcmdldHMgKVxyXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDUgKTtcclxuXHRcdGlmICggcGFyYW1ldGVycy5tb3JwaE5vcm1hbHMgKVxyXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDYgKTtcclxuXHRcdGlmICggcGFyYW1ldGVycy5tb3JwaENvbG9ycyApXHJcblx0XHRcdF9wcm9ncmFtTGF5ZXJzLmVuYWJsZSggNyApO1xyXG5cdFx0aWYgKCBwYXJhbWV0ZXJzLnByZW11bHRpcGxpZWRBbHBoYSApXHJcblx0XHRcdF9wcm9ncmFtTGF5ZXJzLmVuYWJsZSggOCApO1xyXG5cdFx0aWYgKCBwYXJhbWV0ZXJzLnNoYWRvd01hcEVuYWJsZWQgKVxyXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDkgKTtcclxuXHRcdGlmICggcGFyYW1ldGVycy51c2VMZWdhY3lMaWdodHMgKVxyXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDEwICk7XHJcblx0XHRpZiAoIHBhcmFtZXRlcnMuZG91YmxlU2lkZWQgKVxyXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDExICk7XHJcblx0XHRpZiAoIHBhcmFtZXRlcnMuZmxpcFNpZGVkIClcclxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCAxMiApO1xyXG5cdFx0aWYgKCBwYXJhbWV0ZXJzLnVzZURlcHRoUGFja2luZyApXHJcblx0XHRcdF9wcm9ncmFtTGF5ZXJzLmVuYWJsZSggMTMgKTtcclxuXHRcdGlmICggcGFyYW1ldGVycy5kaXRoZXJpbmcgKVxyXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDE0ICk7XHJcblx0XHRpZiAoIHBhcmFtZXRlcnMudHJhbnNtaXNzaW9uIClcclxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCAxNSApO1xyXG5cdFx0aWYgKCBwYXJhbWV0ZXJzLnNoZWVuIClcclxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCAxNiApO1xyXG5cdFx0aWYgKCBwYXJhbWV0ZXJzLm9wYXF1ZSApXHJcblx0XHRcdF9wcm9ncmFtTGF5ZXJzLmVuYWJsZSggMTcgKTtcclxuXHRcdGlmICggcGFyYW1ldGVycy5wb2ludHNVdnMgKVxyXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDE4ICk7XHJcblx0XHRpZiAoIHBhcmFtZXRlcnMuZGVjb2RlVmlkZW9UZXh0dXJlIClcclxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCAxOSApO1xyXG5cdFx0aWYgKCBwYXJhbWV0ZXJzLmFscGhhVG9Db3ZlcmFnZSApXHJcblx0XHRcdF9wcm9ncmFtTGF5ZXJzLmVuYWJsZSggMjAgKTtcclxuXHJcblx0XHRhcnJheS5wdXNoKCBfcHJvZ3JhbUxheWVycy5tYXNrICk7XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gZ2V0VW5pZm9ybXMoIG1hdGVyaWFsICkge1xyXG5cclxuXHRcdGNvbnN0IHNoYWRlcklEID0gc2hhZGVySURzWyBtYXRlcmlhbC50eXBlIF07XHJcblx0XHRsZXQgdW5pZm9ybXM7XHJcblxyXG5cdFx0aWYgKCBzaGFkZXJJRCApIHtcclxuXHJcblx0XHRcdGNvbnN0IHNoYWRlciA9IFNoYWRlckxpYlsgc2hhZGVySUQgXTtcclxuXHRcdFx0dW5pZm9ybXMgPSBVbmlmb3Jtc1V0aWxzLmNsb25lKCBzaGFkZXIudW5pZm9ybXMgKTtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0dW5pZm9ybXMgPSBtYXRlcmlhbC51bmlmb3JtcztcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHVuaWZvcm1zO1xyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIGFjcXVpcmVQcm9ncmFtKCBwYXJhbWV0ZXJzLCBjYWNoZUtleSApIHtcclxuXHJcblx0XHRsZXQgcHJvZ3JhbTtcclxuXHJcblx0XHQvLyBDaGVjayBpZiBjb2RlIGhhcyBiZWVuIGFscmVhZHkgY29tcGlsZWRcclxuXHRcdGZvciAoIGxldCBwID0gMCwgcGwgPSBwcm9ncmFtcy5sZW5ndGg7IHAgPCBwbDsgcCArKyApIHtcclxuXHJcblx0XHRcdGNvbnN0IHByZWV4aXN0aW5nUHJvZ3JhbSA9IHByb2dyYW1zWyBwIF07XHJcblxyXG5cdFx0XHRpZiAoIHByZWV4aXN0aW5nUHJvZ3JhbS5jYWNoZUtleSA9PT0gY2FjaGVLZXkgKSB7XHJcblxyXG5cdFx0XHRcdHByb2dyYW0gPSBwcmVleGlzdGluZ1Byb2dyYW07XHJcblx0XHRcdFx0KysgcHJvZ3JhbS51c2VkVGltZXM7XHJcblxyXG5cdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHByb2dyYW0gPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdHByb2dyYW0gPSBuZXcgV2ViR0xQcm9ncmFtKCByZW5kZXJlciwgY2FjaGVLZXksIHBhcmFtZXRlcnMsIGJpbmRpbmdTdGF0ZXMgKTtcclxuXHRcdFx0cHJvZ3JhbXMucHVzaCggcHJvZ3JhbSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gcHJvZ3JhbTtcclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiByZWxlYXNlUHJvZ3JhbSggcHJvZ3JhbSApIHtcclxuXHJcblx0XHRpZiAoIC0tIHByb2dyYW0udXNlZFRpbWVzID09PSAwICkge1xyXG5cclxuXHRcdFx0Ly8gUmVtb3ZlIGZyb20gdW5vcmRlcmVkIHNldFxyXG5cdFx0XHRjb25zdCBpID0gcHJvZ3JhbXMuaW5kZXhPZiggcHJvZ3JhbSApO1xyXG5cdFx0XHRwcm9ncmFtc1sgaSBdID0gcHJvZ3JhbXNbIHByb2dyYW1zLmxlbmd0aCAtIDEgXTtcclxuXHRcdFx0cHJvZ3JhbXMucG9wKCk7XHJcblxyXG5cdFx0XHQvLyBGcmVlIFdlYkdMIHJlc291cmNlc1xyXG5cdFx0XHRwcm9ncmFtLmRlc3Ryb3koKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gcmVsZWFzZVNoYWRlckNhY2hlKCBtYXRlcmlhbCApIHtcclxuXHJcblx0XHRfY3VzdG9tU2hhZGVycy5yZW1vdmUoIG1hdGVyaWFsICk7XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gZGlzcG9zZSgpIHtcclxuXHJcblx0XHRfY3VzdG9tU2hhZGVycy5kaXNwb3NlKCk7XHJcblxyXG5cdH1cclxuXHJcblx0cmV0dXJuIHtcclxuXHRcdGdldFBhcmFtZXRlcnM6IGdldFBhcmFtZXRlcnMsXHJcblx0XHRnZXRQcm9ncmFtQ2FjaGVLZXk6IGdldFByb2dyYW1DYWNoZUtleSxcclxuXHRcdGdldFVuaWZvcm1zOiBnZXRVbmlmb3JtcyxcclxuXHRcdGFjcXVpcmVQcm9ncmFtOiBhY3F1aXJlUHJvZ3JhbSxcclxuXHRcdHJlbGVhc2VQcm9ncmFtOiByZWxlYXNlUHJvZ3JhbSxcclxuXHRcdHJlbGVhc2VTaGFkZXJDYWNoZTogcmVsZWFzZVNoYWRlckNhY2hlLFxyXG5cdFx0Ly8gRXhwb3NlZCBmb3IgcmVzb3VyY2UgbW9uaXRvcmluZyAmIGVycm9yIGZlZWRiYWNrIHZpYSByZW5kZXJlci5pbmZvOlxyXG5cdFx0cHJvZ3JhbXM6IHByb2dyYW1zLFxyXG5cdFx0ZGlzcG9zZTogZGlzcG9zZVxyXG5cdH07XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBXZWJHTFByb2dyYW1zIH07XHJcbiIsImZ1bmN0aW9uIFdlYkdMUHJvcGVydGllcygpIHtcclxuXHJcblx0bGV0IHByb3BlcnRpZXMgPSBuZXcgV2Vha01hcCgpO1xyXG5cclxuXHRmdW5jdGlvbiBnZXQoIG9iamVjdCApIHtcclxuXHJcblx0XHRsZXQgbWFwID0gcHJvcGVydGllcy5nZXQoIG9iamVjdCApO1xyXG5cclxuXHRcdGlmICggbWFwID09PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRtYXAgPSB7fTtcclxuXHRcdFx0cHJvcGVydGllcy5zZXQoIG9iamVjdCwgbWFwICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiBtYXA7XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gcmVtb3ZlKCBvYmplY3QgKSB7XHJcblxyXG5cdFx0cHJvcGVydGllcy5kZWxldGUoIG9iamVjdCApO1xyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHVwZGF0ZSggb2JqZWN0LCBrZXksIHZhbHVlICkge1xyXG5cclxuXHRcdHByb3BlcnRpZXMuZ2V0KCBvYmplY3QgKVsga2V5IF0gPSB2YWx1ZTtcclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBkaXNwb3NlKCkge1xyXG5cclxuXHRcdHByb3BlcnRpZXMgPSBuZXcgV2Vha01hcCgpO1xyXG5cclxuXHR9XHJcblxyXG5cdHJldHVybiB7XHJcblx0XHRnZXQ6IGdldCxcclxuXHRcdHJlbW92ZTogcmVtb3ZlLFxyXG5cdFx0dXBkYXRlOiB1cGRhdGUsXHJcblx0XHRkaXNwb3NlOiBkaXNwb3NlXHJcblx0fTtcclxuXHJcbn1cclxuXHJcblxyXG5leHBvcnQgeyBXZWJHTFByb3BlcnRpZXMgfTtcclxuIiwiZnVuY3Rpb24gcGFpbnRlclNvcnRTdGFibGUoIGEsIGIgKSB7XHJcblxyXG5cdGlmICggYS5ncm91cE9yZGVyICE9PSBiLmdyb3VwT3JkZXIgKSB7XHJcblxyXG5cdFx0cmV0dXJuIGEuZ3JvdXBPcmRlciAtIGIuZ3JvdXBPcmRlcjtcclxuXHJcblx0fSBlbHNlIGlmICggYS5yZW5kZXJPcmRlciAhPT0gYi5yZW5kZXJPcmRlciApIHtcclxuXHJcblx0XHRyZXR1cm4gYS5yZW5kZXJPcmRlciAtIGIucmVuZGVyT3JkZXI7XHJcblxyXG5cdH0gZWxzZSBpZiAoIGEubWF0ZXJpYWwuaWQgIT09IGIubWF0ZXJpYWwuaWQgKSB7XHJcblxyXG5cdFx0cmV0dXJuIGEubWF0ZXJpYWwuaWQgLSBiLm1hdGVyaWFsLmlkO1xyXG5cclxuXHR9IGVsc2UgaWYgKCBhLnogIT09IGIueiApIHtcclxuXHJcblx0XHRyZXR1cm4gYS56IC0gYi56O1xyXG5cclxuXHR9IGVsc2Uge1xyXG5cclxuXHRcdHJldHVybiBhLmlkIC0gYi5pZDtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gcmV2ZXJzZVBhaW50ZXJTb3J0U3RhYmxlKCBhLCBiICkge1xyXG5cclxuXHRpZiAoIGEuZ3JvdXBPcmRlciAhPT0gYi5ncm91cE9yZGVyICkge1xyXG5cclxuXHRcdHJldHVybiBhLmdyb3VwT3JkZXIgLSBiLmdyb3VwT3JkZXI7XHJcblxyXG5cdH0gZWxzZSBpZiAoIGEucmVuZGVyT3JkZXIgIT09IGIucmVuZGVyT3JkZXIgKSB7XHJcblxyXG5cdFx0cmV0dXJuIGEucmVuZGVyT3JkZXIgLSBiLnJlbmRlck9yZGVyO1xyXG5cclxuXHR9IGVsc2UgaWYgKCBhLnogIT09IGIueiApIHtcclxuXHJcblx0XHRyZXR1cm4gYi56IC0gYS56O1xyXG5cclxuXHR9IGVsc2Uge1xyXG5cclxuXHRcdHJldHVybiBhLmlkIC0gYi5pZDtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuXHJcbmZ1bmN0aW9uIFdlYkdMUmVuZGVyTGlzdCgpIHtcclxuXHJcblx0Y29uc3QgcmVuZGVySXRlbXMgPSBbXTtcclxuXHRsZXQgcmVuZGVySXRlbXNJbmRleCA9IDA7XHJcblxyXG5cdGNvbnN0IG9wYXF1ZSA9IFtdO1xyXG5cdGNvbnN0IHRyYW5zbWlzc2l2ZSA9IFtdO1xyXG5cdGNvbnN0IHRyYW5zcGFyZW50ID0gW107XHJcblxyXG5cdGZ1bmN0aW9uIGluaXQoKSB7XHJcblxyXG5cdFx0cmVuZGVySXRlbXNJbmRleCA9IDA7XHJcblxyXG5cdFx0b3BhcXVlLmxlbmd0aCA9IDA7XHJcblx0XHR0cmFuc21pc3NpdmUubGVuZ3RoID0gMDtcclxuXHRcdHRyYW5zcGFyZW50Lmxlbmd0aCA9IDA7XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gZ2V0TmV4dFJlbmRlckl0ZW0oIG9iamVjdCwgZ2VvbWV0cnksIG1hdGVyaWFsLCBncm91cE9yZGVyLCB6LCBncm91cCApIHtcclxuXHJcblx0XHRsZXQgcmVuZGVySXRlbSA9IHJlbmRlckl0ZW1zWyByZW5kZXJJdGVtc0luZGV4IF07XHJcblxyXG5cdFx0aWYgKCByZW5kZXJJdGVtID09PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRyZW5kZXJJdGVtID0ge1xyXG5cdFx0XHRcdGlkOiBvYmplY3QuaWQsXHJcblx0XHRcdFx0b2JqZWN0OiBvYmplY3QsXHJcblx0XHRcdFx0Z2VvbWV0cnk6IGdlb21ldHJ5LFxyXG5cdFx0XHRcdG1hdGVyaWFsOiBtYXRlcmlhbCxcclxuXHRcdFx0XHRncm91cE9yZGVyOiBncm91cE9yZGVyLFxyXG5cdFx0XHRcdHJlbmRlck9yZGVyOiBvYmplY3QucmVuZGVyT3JkZXIsXHJcblx0XHRcdFx0ejogeixcclxuXHRcdFx0XHRncm91cDogZ3JvdXBcclxuXHRcdFx0fTtcclxuXHJcblx0XHRcdHJlbmRlckl0ZW1zWyByZW5kZXJJdGVtc0luZGV4IF0gPSByZW5kZXJJdGVtO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRyZW5kZXJJdGVtLmlkID0gb2JqZWN0LmlkO1xyXG5cdFx0XHRyZW5kZXJJdGVtLm9iamVjdCA9IG9iamVjdDtcclxuXHRcdFx0cmVuZGVySXRlbS5nZW9tZXRyeSA9IGdlb21ldHJ5O1xyXG5cdFx0XHRyZW5kZXJJdGVtLm1hdGVyaWFsID0gbWF0ZXJpYWw7XHJcblx0XHRcdHJlbmRlckl0ZW0uZ3JvdXBPcmRlciA9IGdyb3VwT3JkZXI7XHJcblx0XHRcdHJlbmRlckl0ZW0ucmVuZGVyT3JkZXIgPSBvYmplY3QucmVuZGVyT3JkZXI7XHJcblx0XHRcdHJlbmRlckl0ZW0ueiA9IHo7XHJcblx0XHRcdHJlbmRlckl0ZW0uZ3JvdXAgPSBncm91cDtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmVuZGVySXRlbXNJbmRleCArKztcclxuXHJcblx0XHRyZXR1cm4gcmVuZGVySXRlbTtcclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBwdXNoKCBvYmplY3QsIGdlb21ldHJ5LCBtYXRlcmlhbCwgZ3JvdXBPcmRlciwgeiwgZ3JvdXAgKSB7XHJcblxyXG5cdFx0Y29uc3QgcmVuZGVySXRlbSA9IGdldE5leHRSZW5kZXJJdGVtKCBvYmplY3QsIGdlb21ldHJ5LCBtYXRlcmlhbCwgZ3JvdXBPcmRlciwgeiwgZ3JvdXAgKTtcclxuXHJcblx0XHRpZiAoIG1hdGVyaWFsLnRyYW5zbWlzc2lvbiA+IDAuMCApIHtcclxuXHJcblx0XHRcdHRyYW5zbWlzc2l2ZS5wdXNoKCByZW5kZXJJdGVtICk7XHJcblxyXG5cdFx0fSBlbHNlIGlmICggbWF0ZXJpYWwudHJhbnNwYXJlbnQgPT09IHRydWUgKSB7XHJcblxyXG5cdFx0XHR0cmFuc3BhcmVudC5wdXNoKCByZW5kZXJJdGVtICk7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdG9wYXF1ZS5wdXNoKCByZW5kZXJJdGVtICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHVuc2hpZnQoIG9iamVjdCwgZ2VvbWV0cnksIG1hdGVyaWFsLCBncm91cE9yZGVyLCB6LCBncm91cCApIHtcclxuXHJcblx0XHRjb25zdCByZW5kZXJJdGVtID0gZ2V0TmV4dFJlbmRlckl0ZW0oIG9iamVjdCwgZ2VvbWV0cnksIG1hdGVyaWFsLCBncm91cE9yZGVyLCB6LCBncm91cCApO1xyXG5cclxuXHRcdGlmICggbWF0ZXJpYWwudHJhbnNtaXNzaW9uID4gMC4wICkge1xyXG5cclxuXHRcdFx0dHJhbnNtaXNzaXZlLnVuc2hpZnQoIHJlbmRlckl0ZW0gKTtcclxuXHJcblx0XHR9IGVsc2UgaWYgKCBtYXRlcmlhbC50cmFuc3BhcmVudCA9PT0gdHJ1ZSApIHtcclxuXHJcblx0XHRcdHRyYW5zcGFyZW50LnVuc2hpZnQoIHJlbmRlckl0ZW0gKTtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0b3BhcXVlLnVuc2hpZnQoIHJlbmRlckl0ZW0gKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gc29ydCggY3VzdG9tT3BhcXVlU29ydCwgY3VzdG9tVHJhbnNwYXJlbnRTb3J0ICkge1xyXG5cclxuXHRcdGlmICggb3BhcXVlLmxlbmd0aCA+IDEgKSBvcGFxdWUuc29ydCggY3VzdG9tT3BhcXVlU29ydCB8fCBwYWludGVyU29ydFN0YWJsZSApO1xyXG5cdFx0aWYgKCB0cmFuc21pc3NpdmUubGVuZ3RoID4gMSApIHRyYW5zbWlzc2l2ZS5zb3J0KCBjdXN0b21UcmFuc3BhcmVudFNvcnQgfHwgcmV2ZXJzZVBhaW50ZXJTb3J0U3RhYmxlICk7XHJcblx0XHRpZiAoIHRyYW5zcGFyZW50Lmxlbmd0aCA+IDEgKSB0cmFuc3BhcmVudC5zb3J0KCBjdXN0b21UcmFuc3BhcmVudFNvcnQgfHwgcmV2ZXJzZVBhaW50ZXJTb3J0U3RhYmxlICk7XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gZmluaXNoKCkge1xyXG5cclxuXHRcdC8vIENsZWFyIHJlZmVyZW5jZXMgZnJvbSBpbmFjdGl2ZSByZW5kZXJJdGVtcyBpbiB0aGUgbGlzdFxyXG5cclxuXHRcdGZvciAoIGxldCBpID0gcmVuZGVySXRlbXNJbmRleCwgaWwgPSByZW5kZXJJdGVtcy5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcclxuXHJcblx0XHRcdGNvbnN0IHJlbmRlckl0ZW0gPSByZW5kZXJJdGVtc1sgaSBdO1xyXG5cclxuXHRcdFx0aWYgKCByZW5kZXJJdGVtLmlkID09PSBudWxsICkgYnJlYWs7XHJcblxyXG5cdFx0XHRyZW5kZXJJdGVtLmlkID0gbnVsbDtcclxuXHRcdFx0cmVuZGVySXRlbS5vYmplY3QgPSBudWxsO1xyXG5cdFx0XHRyZW5kZXJJdGVtLmdlb21ldHJ5ID0gbnVsbDtcclxuXHRcdFx0cmVuZGVySXRlbS5tYXRlcmlhbCA9IG51bGw7XHJcblx0XHRcdHJlbmRlckl0ZW0uZ3JvdXAgPSBudWxsO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4ge1xyXG5cclxuXHRcdG9wYXF1ZTogb3BhcXVlLFxyXG5cdFx0dHJhbnNtaXNzaXZlOiB0cmFuc21pc3NpdmUsXHJcblx0XHR0cmFuc3BhcmVudDogdHJhbnNwYXJlbnQsXHJcblxyXG5cdFx0aW5pdDogaW5pdCxcclxuXHRcdHB1c2g6IHB1c2gsXHJcblx0XHR1bnNoaWZ0OiB1bnNoaWZ0LFxyXG5cdFx0ZmluaXNoOiBmaW5pc2gsXHJcblxyXG5cdFx0c29ydDogc29ydFxyXG5cdH07XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiBXZWJHTFJlbmRlckxpc3RzKCkge1xyXG5cclxuXHRsZXQgbGlzdHMgPSBuZXcgV2Vha01hcCgpO1xyXG5cclxuXHRmdW5jdGlvbiBnZXQoIHNjZW5lLCByZW5kZXJDYWxsRGVwdGggKSB7XHJcblxyXG5cdFx0Y29uc3QgbGlzdEFycmF5ID0gbGlzdHMuZ2V0KCBzY2VuZSApO1xyXG5cdFx0bGV0IGxpc3Q7XHJcblxyXG5cdFx0aWYgKCBsaXN0QXJyYXkgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdGxpc3QgPSBuZXcgV2ViR0xSZW5kZXJMaXN0KCk7XHJcblx0XHRcdGxpc3RzLnNldCggc2NlbmUsIFsgbGlzdCBdICk7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdGlmICggcmVuZGVyQ2FsbERlcHRoID49IGxpc3RBcnJheS5sZW5ndGggKSB7XHJcblxyXG5cdFx0XHRcdGxpc3QgPSBuZXcgV2ViR0xSZW5kZXJMaXN0KCk7XHJcblx0XHRcdFx0bGlzdEFycmF5LnB1c2goIGxpc3QgKTtcclxuXHJcblx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdGxpc3QgPSBsaXN0QXJyYXlbIHJlbmRlckNhbGxEZXB0aCBdO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gbGlzdDtcclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBkaXNwb3NlKCkge1xyXG5cclxuXHRcdGxpc3RzID0gbmV3IFdlYWtNYXAoKTtcclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4ge1xyXG5cdFx0Z2V0OiBnZXQsXHJcblx0XHRkaXNwb3NlOiBkaXNwb3NlXHJcblx0fTtcclxuXHJcbn1cclxuXHJcblxyXG5leHBvcnQgeyBXZWJHTFJlbmRlckxpc3RzLCBXZWJHTFJlbmRlckxpc3QgfTtcclxuIiwiaW1wb3J0IHsgQ29sb3IgfSBmcm9tICcuLi8uLi9tYXRoL0NvbG9yLmpzJztcclxuaW1wb3J0IHsgTWF0cml4NCB9IGZyb20gJy4uLy4uL21hdGgvTWF0cml4NC5qcyc7XHJcbmltcG9ydCB7IFZlY3RvcjIgfSBmcm9tICcuLi8uLi9tYXRoL1ZlY3RvcjIuanMnO1xyXG5pbXBvcnQgeyBWZWN0b3IzIH0gZnJvbSAnLi4vLi4vbWF0aC9WZWN0b3IzLmpzJztcclxuaW1wb3J0IHsgVW5pZm9ybXNMaWIgfSBmcm9tICcuLi9zaGFkZXJzL1VuaWZvcm1zTGliLmpzJztcclxuXHJcbmZ1bmN0aW9uIFVuaWZvcm1zQ2FjaGUoKSB7XHJcblxyXG5cdGNvbnN0IGxpZ2h0cyA9IHt9O1xyXG5cclxuXHRyZXR1cm4ge1xyXG5cclxuXHRcdGdldDogZnVuY3Rpb24gKCBsaWdodCApIHtcclxuXHJcblx0XHRcdGlmICggbGlnaHRzWyBsaWdodC5pZCBdICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRcdHJldHVybiBsaWdodHNbIGxpZ2h0LmlkIF07XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRsZXQgdW5pZm9ybXM7XHJcblxyXG5cdFx0XHRzd2l0Y2ggKCBsaWdodC50eXBlICkge1xyXG5cclxuXHRcdFx0XHRjYXNlICdEaXJlY3Rpb25hbExpZ2h0JzpcclxuXHRcdFx0XHRcdHVuaWZvcm1zID0ge1xyXG5cdFx0XHRcdFx0XHRkaXJlY3Rpb246IG5ldyBWZWN0b3IzKCksXHJcblx0XHRcdFx0XHRcdGNvbG9yOiBuZXcgQ29sb3IoKVxyXG5cdFx0XHRcdFx0fTtcclxuXHRcdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0XHRjYXNlICdTcG90TGlnaHQnOlxyXG5cdFx0XHRcdFx0dW5pZm9ybXMgPSB7XHJcblx0XHRcdFx0XHRcdHBvc2l0aW9uOiBuZXcgVmVjdG9yMygpLFxyXG5cdFx0XHRcdFx0XHRkaXJlY3Rpb246IG5ldyBWZWN0b3IzKCksXHJcblx0XHRcdFx0XHRcdGNvbG9yOiBuZXcgQ29sb3IoKSxcclxuXHRcdFx0XHRcdFx0ZGlzdGFuY2U6IDAsXHJcblx0XHRcdFx0XHRcdGNvbmVDb3M6IDAsXHJcblx0XHRcdFx0XHRcdHBlbnVtYnJhQ29zOiAwLFxyXG5cdFx0XHRcdFx0XHRkZWNheTogMFxyXG5cdFx0XHRcdFx0fTtcclxuXHRcdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0XHRjYXNlICdQb2ludExpZ2h0JzpcclxuXHRcdFx0XHRcdHVuaWZvcm1zID0ge1xyXG5cdFx0XHRcdFx0XHRwb3NpdGlvbjogbmV3IFZlY3RvcjMoKSxcclxuXHRcdFx0XHRcdFx0Y29sb3I6IG5ldyBDb2xvcigpLFxyXG5cdFx0XHRcdFx0XHRkaXN0YW5jZTogMCxcclxuXHRcdFx0XHRcdFx0ZGVjYXk6IDBcclxuXHRcdFx0XHRcdH07XHJcblx0XHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdFx0Y2FzZSAnSGVtaXNwaGVyZUxpZ2h0JzpcclxuXHRcdFx0XHRcdHVuaWZvcm1zID0ge1xyXG5cdFx0XHRcdFx0XHRkaXJlY3Rpb246IG5ldyBWZWN0b3IzKCksXHJcblx0XHRcdFx0XHRcdHNreUNvbG9yOiBuZXcgQ29sb3IoKSxcclxuXHRcdFx0XHRcdFx0Z3JvdW5kQ29sb3I6IG5ldyBDb2xvcigpXHJcblx0XHRcdFx0XHR9O1xyXG5cdFx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRcdGNhc2UgJ1JlY3RBcmVhTGlnaHQnOlxyXG5cdFx0XHRcdFx0dW5pZm9ybXMgPSB7XHJcblx0XHRcdFx0XHRcdGNvbG9yOiBuZXcgQ29sb3IoKSxcclxuXHRcdFx0XHRcdFx0cG9zaXRpb246IG5ldyBWZWN0b3IzKCksXHJcblx0XHRcdFx0XHRcdGhhbGZXaWR0aDogbmV3IFZlY3RvcjMoKSxcclxuXHRcdFx0XHRcdFx0aGFsZkhlaWdodDogbmV3IFZlY3RvcjMoKVxyXG5cdFx0XHRcdFx0fTtcclxuXHRcdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0bGlnaHRzWyBsaWdodC5pZCBdID0gdW5pZm9ybXM7XHJcblxyXG5cdFx0XHRyZXR1cm4gdW5pZm9ybXM7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9O1xyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gU2hhZG93VW5pZm9ybXNDYWNoZSgpIHtcclxuXHJcblx0Y29uc3QgbGlnaHRzID0ge307XHJcblxyXG5cdHJldHVybiB7XHJcblxyXG5cdFx0Z2V0OiBmdW5jdGlvbiAoIGxpZ2h0ICkge1xyXG5cclxuXHRcdFx0aWYgKCBsaWdodHNbIGxpZ2h0LmlkIF0gIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0cmV0dXJuIGxpZ2h0c1sgbGlnaHQuaWQgXTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGxldCB1bmlmb3JtcztcclxuXHJcblx0XHRcdHN3aXRjaCAoIGxpZ2h0LnR5cGUgKSB7XHJcblxyXG5cdFx0XHRcdGNhc2UgJ0RpcmVjdGlvbmFsTGlnaHQnOlxyXG5cdFx0XHRcdFx0dW5pZm9ybXMgPSB7XHJcblx0XHRcdFx0XHRcdHNoYWRvd0JpYXM6IDAsXHJcblx0XHRcdFx0XHRcdHNoYWRvd05vcm1hbEJpYXM6IDAsXHJcblx0XHRcdFx0XHRcdHNoYWRvd1JhZGl1czogMSxcclxuXHRcdFx0XHRcdFx0c2hhZG93TWFwU2l6ZTogbmV3IFZlY3RvcjIoKVxyXG5cdFx0XHRcdFx0fTtcclxuXHRcdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0XHRjYXNlICdTcG90TGlnaHQnOlxyXG5cdFx0XHRcdFx0dW5pZm9ybXMgPSB7XHJcblx0XHRcdFx0XHRcdHNoYWRvd0JpYXM6IDAsXHJcblx0XHRcdFx0XHRcdHNoYWRvd05vcm1hbEJpYXM6IDAsXHJcblx0XHRcdFx0XHRcdHNoYWRvd1JhZGl1czogMSxcclxuXHRcdFx0XHRcdFx0c2hhZG93TWFwU2l6ZTogbmV3IFZlY3RvcjIoKVxyXG5cdFx0XHRcdFx0fTtcclxuXHRcdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0XHRjYXNlICdQb2ludExpZ2h0JzpcclxuXHRcdFx0XHRcdHVuaWZvcm1zID0ge1xyXG5cdFx0XHRcdFx0XHRzaGFkb3dCaWFzOiAwLFxyXG5cdFx0XHRcdFx0XHRzaGFkb3dOb3JtYWxCaWFzOiAwLFxyXG5cdFx0XHRcdFx0XHRzaGFkb3dSYWRpdXM6IDEsXHJcblx0XHRcdFx0XHRcdHNoYWRvd01hcFNpemU6IG5ldyBWZWN0b3IyKCksXHJcblx0XHRcdFx0XHRcdHNoYWRvd0NhbWVyYU5lYXI6IDEsXHJcblx0XHRcdFx0XHRcdHNoYWRvd0NhbWVyYUZhcjogMTAwMFxyXG5cdFx0XHRcdFx0fTtcclxuXHRcdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0XHQvLyBUT0RPIChhYmVsbmF0aW9uKTogc2V0IFJlY3RBcmVhTGlnaHQgc2hhZG93IHVuaWZvcm1zXHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRsaWdodHNbIGxpZ2h0LmlkIF0gPSB1bmlmb3JtcztcclxuXHJcblx0XHRcdHJldHVybiB1bmlmb3JtcztcclxuXHJcblx0XHR9XHJcblxyXG5cdH07XHJcblxyXG59XHJcblxyXG5cclxuXHJcbmxldCBuZXh0VmVyc2lvbiA9IDA7XHJcblxyXG5mdW5jdGlvbiBzaGFkb3dDYXN0aW5nQW5kVGV4dHVyaW5nTGlnaHRzRmlyc3QoIGxpZ2h0QSwgbGlnaHRCICkge1xyXG5cclxuXHRyZXR1cm4gKCBsaWdodEIuY2FzdFNoYWRvdyA/IDIgOiAwICkgLSAoIGxpZ2h0QS5jYXN0U2hhZG93ID8gMiA6IDAgKSArICggbGlnaHRCLm1hcCA/IDEgOiAwICkgLSAoIGxpZ2h0QS5tYXAgPyAxIDogMCApO1xyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gV2ViR0xMaWdodHMoIGV4dGVuc2lvbnMsIGNhcGFiaWxpdGllcyApIHtcclxuXHJcblx0Y29uc3QgY2FjaGUgPSBuZXcgVW5pZm9ybXNDYWNoZSgpO1xyXG5cclxuXHRjb25zdCBzaGFkb3dDYWNoZSA9IFNoYWRvd1VuaWZvcm1zQ2FjaGUoKTtcclxuXHJcblx0Y29uc3Qgc3RhdGUgPSB7XHJcblxyXG5cdFx0dmVyc2lvbjogMCxcclxuXHJcblx0XHRoYXNoOiB7XHJcblx0XHRcdGRpcmVjdGlvbmFsTGVuZ3RoOiAtIDEsXHJcblx0XHRcdHBvaW50TGVuZ3RoOiAtIDEsXHJcblx0XHRcdHNwb3RMZW5ndGg6IC0gMSxcclxuXHRcdFx0cmVjdEFyZWFMZW5ndGg6IC0gMSxcclxuXHRcdFx0aGVtaUxlbmd0aDogLSAxLFxyXG5cclxuXHRcdFx0bnVtRGlyZWN0aW9uYWxTaGFkb3dzOiAtIDEsXHJcblx0XHRcdG51bVBvaW50U2hhZG93czogLSAxLFxyXG5cdFx0XHRudW1TcG90U2hhZG93czogLSAxLFxyXG5cdFx0XHRudW1TcG90TWFwczogLSAxLFxyXG5cclxuXHRcdFx0bnVtTGlnaHRQcm9iZXM6IC0gMVxyXG5cdFx0fSxcclxuXHJcblx0XHRhbWJpZW50OiBbIDAsIDAsIDAgXSxcclxuXHRcdHByb2JlOiBbXSxcclxuXHRcdGRpcmVjdGlvbmFsOiBbXSxcclxuXHRcdGRpcmVjdGlvbmFsU2hhZG93OiBbXSxcclxuXHRcdGRpcmVjdGlvbmFsU2hhZG93TWFwOiBbXSxcclxuXHRcdGRpcmVjdGlvbmFsU2hhZG93TWF0cml4OiBbXSxcclxuXHRcdHNwb3Q6IFtdLFxyXG5cdFx0c3BvdExpZ2h0TWFwOiBbXSxcclxuXHRcdHNwb3RTaGFkb3c6IFtdLFxyXG5cdFx0c3BvdFNoYWRvd01hcDogW10sXHJcblx0XHRzcG90TGlnaHRNYXRyaXg6IFtdLFxyXG5cdFx0cmVjdEFyZWE6IFtdLFxyXG5cdFx0cmVjdEFyZWFMVEMxOiBudWxsLFxyXG5cdFx0cmVjdEFyZWFMVEMyOiBudWxsLFxyXG5cdFx0cG9pbnQ6IFtdLFxyXG5cdFx0cG9pbnRTaGFkb3c6IFtdLFxyXG5cdFx0cG9pbnRTaGFkb3dNYXA6IFtdLFxyXG5cdFx0cG9pbnRTaGFkb3dNYXRyaXg6IFtdLFxyXG5cdFx0aGVtaTogW10sXHJcblx0XHRudW1TcG90TGlnaHRTaGFkb3dzV2l0aE1hcHM6IDAsXHJcblx0XHRudW1MaWdodFByb2JlczogMFxyXG5cclxuXHR9O1xyXG5cclxuXHRmb3IgKCBsZXQgaSA9IDA7IGkgPCA5OyBpICsrICkgc3RhdGUucHJvYmUucHVzaCggbmV3IFZlY3RvcjMoKSApO1xyXG5cclxuXHRjb25zdCB2ZWN0b3IzID0gbmV3IFZlY3RvcjMoKTtcclxuXHRjb25zdCBtYXRyaXg0ID0gbmV3IE1hdHJpeDQoKTtcclxuXHRjb25zdCBtYXRyaXg0MiA9IG5ldyBNYXRyaXg0KCk7XHJcblxyXG5cdGZ1bmN0aW9uIHNldHVwKCBsaWdodHMsIHVzZUxlZ2FjeUxpZ2h0cyApIHtcclxuXHJcblx0XHRsZXQgciA9IDAsIGcgPSAwLCBiID0gMDtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCA5OyBpICsrICkgc3RhdGUucHJvYmVbIGkgXS5zZXQoIDAsIDAsIDAgKTtcclxuXHJcblx0XHRsZXQgZGlyZWN0aW9uYWxMZW5ndGggPSAwO1xyXG5cdFx0bGV0IHBvaW50TGVuZ3RoID0gMDtcclxuXHRcdGxldCBzcG90TGVuZ3RoID0gMDtcclxuXHRcdGxldCByZWN0QXJlYUxlbmd0aCA9IDA7XHJcblx0XHRsZXQgaGVtaUxlbmd0aCA9IDA7XHJcblxyXG5cdFx0bGV0IG51bURpcmVjdGlvbmFsU2hhZG93cyA9IDA7XHJcblx0XHRsZXQgbnVtUG9pbnRTaGFkb3dzID0gMDtcclxuXHRcdGxldCBudW1TcG90U2hhZG93cyA9IDA7XHJcblx0XHRsZXQgbnVtU3BvdE1hcHMgPSAwO1xyXG5cdFx0bGV0IG51bVNwb3RTaGFkb3dzV2l0aE1hcHMgPSAwO1xyXG5cclxuXHRcdGxldCBudW1MaWdodFByb2JlcyA9IDA7XHJcblxyXG5cdFx0Ly8gb3JkZXJpbmcgOiBbc2hhZG93IGNhc3RpbmcgKyBtYXAgdGV4dHVyaW5nLCBtYXAgdGV4dHVyaW5nLCBzaGFkb3cgY2FzdGluZywgbm9uZSBdXHJcblx0XHRsaWdodHMuc29ydCggc2hhZG93Q2FzdGluZ0FuZFRleHR1cmluZ0xpZ2h0c0ZpcnN0ICk7XHJcblxyXG5cdFx0Ly8gYXJ0aXN0LWZyaWVuZGx5IGxpZ2h0IGludGVuc2l0eSBzY2FsaW5nIGZhY3RvclxyXG5cdFx0Y29uc3Qgc2NhbGVGYWN0b3IgPSAoIHVzZUxlZ2FjeUxpZ2h0cyA9PT0gdHJ1ZSApID8gTWF0aC5QSSA6IDE7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gbGlnaHRzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBsaWdodCA9IGxpZ2h0c1sgaSBdO1xyXG5cclxuXHRcdFx0Y29uc3QgY29sb3IgPSBsaWdodC5jb2xvcjtcclxuXHRcdFx0Y29uc3QgaW50ZW5zaXR5ID0gbGlnaHQuaW50ZW5zaXR5O1xyXG5cdFx0XHRjb25zdCBkaXN0YW5jZSA9IGxpZ2h0LmRpc3RhbmNlO1xyXG5cclxuXHRcdFx0Y29uc3Qgc2hhZG93TWFwID0gKCBsaWdodC5zaGFkb3cgJiYgbGlnaHQuc2hhZG93Lm1hcCApID8gbGlnaHQuc2hhZG93Lm1hcC50ZXh0dXJlIDogbnVsbDtcclxuXHJcblx0XHRcdGlmICggbGlnaHQuaXNBbWJpZW50TGlnaHQgKSB7XHJcblxyXG5cdFx0XHRcdHIgKz0gY29sb3IuciAqIGludGVuc2l0eSAqIHNjYWxlRmFjdG9yO1xyXG5cdFx0XHRcdGcgKz0gY29sb3IuZyAqIGludGVuc2l0eSAqIHNjYWxlRmFjdG9yO1xyXG5cdFx0XHRcdGIgKz0gY29sb3IuYiAqIGludGVuc2l0eSAqIHNjYWxlRmFjdG9yO1xyXG5cclxuXHRcdFx0fSBlbHNlIGlmICggbGlnaHQuaXNMaWdodFByb2JlICkge1xyXG5cclxuXHRcdFx0XHRmb3IgKCBsZXQgaiA9IDA7IGogPCA5OyBqICsrICkge1xyXG5cclxuXHRcdFx0XHRcdHN0YXRlLnByb2JlWyBqIF0uYWRkU2NhbGVkVmVjdG9yKCBsaWdodC5zaC5jb2VmZmljaWVudHNbIGogXSwgaW50ZW5zaXR5ICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0bnVtTGlnaHRQcm9iZXMgKys7XHJcblxyXG5cdFx0XHR9IGVsc2UgaWYgKCBsaWdodC5pc0RpcmVjdGlvbmFsTGlnaHQgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IHVuaWZvcm1zID0gY2FjaGUuZ2V0KCBsaWdodCApO1xyXG5cclxuXHRcdFx0XHR1bmlmb3Jtcy5jb2xvci5jb3B5KCBsaWdodC5jb2xvciApLm11bHRpcGx5U2NhbGFyKCBsaWdodC5pbnRlbnNpdHkgKiBzY2FsZUZhY3RvciApO1xyXG5cclxuXHRcdFx0XHRpZiAoIGxpZ2h0LmNhc3RTaGFkb3cgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y29uc3Qgc2hhZG93ID0gbGlnaHQuc2hhZG93O1xyXG5cclxuXHRcdFx0XHRcdGNvbnN0IHNoYWRvd1VuaWZvcm1zID0gc2hhZG93Q2FjaGUuZ2V0KCBsaWdodCApO1xyXG5cclxuXHRcdFx0XHRcdHNoYWRvd1VuaWZvcm1zLnNoYWRvd0JpYXMgPSBzaGFkb3cuYmlhcztcclxuXHRcdFx0XHRcdHNoYWRvd1VuaWZvcm1zLnNoYWRvd05vcm1hbEJpYXMgPSBzaGFkb3cubm9ybWFsQmlhcztcclxuXHRcdFx0XHRcdHNoYWRvd1VuaWZvcm1zLnNoYWRvd1JhZGl1cyA9IHNoYWRvdy5yYWRpdXM7XHJcblx0XHRcdFx0XHRzaGFkb3dVbmlmb3Jtcy5zaGFkb3dNYXBTaXplID0gc2hhZG93Lm1hcFNpemU7XHJcblxyXG5cdFx0XHRcdFx0c3RhdGUuZGlyZWN0aW9uYWxTaGFkb3dbIGRpcmVjdGlvbmFsTGVuZ3RoIF0gPSBzaGFkb3dVbmlmb3JtcztcclxuXHRcdFx0XHRcdHN0YXRlLmRpcmVjdGlvbmFsU2hhZG93TWFwWyBkaXJlY3Rpb25hbExlbmd0aCBdID0gc2hhZG93TWFwO1xyXG5cdFx0XHRcdFx0c3RhdGUuZGlyZWN0aW9uYWxTaGFkb3dNYXRyaXhbIGRpcmVjdGlvbmFsTGVuZ3RoIF0gPSBsaWdodC5zaGFkb3cubWF0cml4O1xyXG5cclxuXHRcdFx0XHRcdG51bURpcmVjdGlvbmFsU2hhZG93cyArKztcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRzdGF0ZS5kaXJlY3Rpb25hbFsgZGlyZWN0aW9uYWxMZW5ndGggXSA9IHVuaWZvcm1zO1xyXG5cclxuXHRcdFx0XHRkaXJlY3Rpb25hbExlbmd0aCArKztcclxuXHJcblx0XHRcdH0gZWxzZSBpZiAoIGxpZ2h0LmlzU3BvdExpZ2h0ICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCB1bmlmb3JtcyA9IGNhY2hlLmdldCggbGlnaHQgKTtcclxuXHJcblx0XHRcdFx0dW5pZm9ybXMucG9zaXRpb24uc2V0RnJvbU1hdHJpeFBvc2l0aW9uKCBsaWdodC5tYXRyaXhXb3JsZCApO1xyXG5cclxuXHRcdFx0XHR1bmlmb3Jtcy5jb2xvci5jb3B5KCBjb2xvciApLm11bHRpcGx5U2NhbGFyKCBpbnRlbnNpdHkgKiBzY2FsZUZhY3RvciApO1xyXG5cdFx0XHRcdHVuaWZvcm1zLmRpc3RhbmNlID0gZGlzdGFuY2U7XHJcblxyXG5cdFx0XHRcdHVuaWZvcm1zLmNvbmVDb3MgPSBNYXRoLmNvcyggbGlnaHQuYW5nbGUgKTtcclxuXHRcdFx0XHR1bmlmb3Jtcy5wZW51bWJyYUNvcyA9IE1hdGguY29zKCBsaWdodC5hbmdsZSAqICggMSAtIGxpZ2h0LnBlbnVtYnJhICkgKTtcclxuXHRcdFx0XHR1bmlmb3Jtcy5kZWNheSA9IGxpZ2h0LmRlY2F5O1xyXG5cclxuXHRcdFx0XHRzdGF0ZS5zcG90WyBzcG90TGVuZ3RoIF0gPSB1bmlmb3JtcztcclxuXHJcblx0XHRcdFx0Y29uc3Qgc2hhZG93ID0gbGlnaHQuc2hhZG93O1xyXG5cclxuXHRcdFx0XHRpZiAoIGxpZ2h0Lm1hcCApIHtcclxuXHJcblx0XHRcdFx0XHRzdGF0ZS5zcG90TGlnaHRNYXBbIG51bVNwb3RNYXBzIF0gPSBsaWdodC5tYXA7XHJcblx0XHRcdFx0XHRudW1TcG90TWFwcyArKztcclxuXHJcblx0XHRcdFx0XHQvLyBtYWtlIHN1cmUgdGhlIGxpZ2h0TWF0cml4IGlzIHVwIHRvIGRhdGVcclxuXHRcdFx0XHRcdC8vIFRPRE8gOiBkbyBpdCBpZiByZXF1aXJlZCBvbmx5XHJcblx0XHRcdFx0XHRzaGFkb3cudXBkYXRlTWF0cmljZXMoIGxpZ2h0ICk7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCBsaWdodC5jYXN0U2hhZG93ICkgbnVtU3BvdFNoYWRvd3NXaXRoTWFwcyArKztcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRzdGF0ZS5zcG90TGlnaHRNYXRyaXhbIHNwb3RMZW5ndGggXSA9IHNoYWRvdy5tYXRyaXg7XHJcblxyXG5cdFx0XHRcdGlmICggbGlnaHQuY2FzdFNoYWRvdyApIHtcclxuXHJcblx0XHRcdFx0XHRjb25zdCBzaGFkb3dVbmlmb3JtcyA9IHNoYWRvd0NhY2hlLmdldCggbGlnaHQgKTtcclxuXHJcblx0XHRcdFx0XHRzaGFkb3dVbmlmb3Jtcy5zaGFkb3dCaWFzID0gc2hhZG93LmJpYXM7XHJcblx0XHRcdFx0XHRzaGFkb3dVbmlmb3Jtcy5zaGFkb3dOb3JtYWxCaWFzID0gc2hhZG93Lm5vcm1hbEJpYXM7XHJcblx0XHRcdFx0XHRzaGFkb3dVbmlmb3Jtcy5zaGFkb3dSYWRpdXMgPSBzaGFkb3cucmFkaXVzO1xyXG5cdFx0XHRcdFx0c2hhZG93VW5pZm9ybXMuc2hhZG93TWFwU2l6ZSA9IHNoYWRvdy5tYXBTaXplO1xyXG5cclxuXHRcdFx0XHRcdHN0YXRlLnNwb3RTaGFkb3dbIHNwb3RMZW5ndGggXSA9IHNoYWRvd1VuaWZvcm1zO1xyXG5cdFx0XHRcdFx0c3RhdGUuc3BvdFNoYWRvd01hcFsgc3BvdExlbmd0aCBdID0gc2hhZG93TWFwO1xyXG5cclxuXHRcdFx0XHRcdG51bVNwb3RTaGFkb3dzICsrO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdHNwb3RMZW5ndGggKys7XHJcblxyXG5cdFx0XHR9IGVsc2UgaWYgKCBsaWdodC5pc1JlY3RBcmVhTGlnaHQgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IHVuaWZvcm1zID0gY2FjaGUuZ2V0KCBsaWdodCApO1xyXG5cclxuXHRcdFx0XHR1bmlmb3Jtcy5jb2xvci5jb3B5KCBjb2xvciApLm11bHRpcGx5U2NhbGFyKCBpbnRlbnNpdHkgKTtcclxuXHJcblx0XHRcdFx0dW5pZm9ybXMuaGFsZldpZHRoLnNldCggbGlnaHQud2lkdGggKiAwLjUsIDAuMCwgMC4wICk7XHJcblx0XHRcdFx0dW5pZm9ybXMuaGFsZkhlaWdodC5zZXQoIDAuMCwgbGlnaHQuaGVpZ2h0ICogMC41LCAwLjAgKTtcclxuXHJcblx0XHRcdFx0c3RhdGUucmVjdEFyZWFbIHJlY3RBcmVhTGVuZ3RoIF0gPSB1bmlmb3JtcztcclxuXHJcblx0XHRcdFx0cmVjdEFyZWFMZW5ndGggKys7XHJcblxyXG5cdFx0XHR9IGVsc2UgaWYgKCBsaWdodC5pc1BvaW50TGlnaHQgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IHVuaWZvcm1zID0gY2FjaGUuZ2V0KCBsaWdodCApO1xyXG5cclxuXHRcdFx0XHR1bmlmb3Jtcy5jb2xvci5jb3B5KCBsaWdodC5jb2xvciApLm11bHRpcGx5U2NhbGFyKCBsaWdodC5pbnRlbnNpdHkgKiBzY2FsZUZhY3RvciApO1xyXG5cdFx0XHRcdHVuaWZvcm1zLmRpc3RhbmNlID0gbGlnaHQuZGlzdGFuY2U7XHJcblx0XHRcdFx0dW5pZm9ybXMuZGVjYXkgPSBsaWdodC5kZWNheTtcclxuXHJcblx0XHRcdFx0aWYgKCBsaWdodC5jYXN0U2hhZG93ICkge1xyXG5cclxuXHRcdFx0XHRcdGNvbnN0IHNoYWRvdyA9IGxpZ2h0LnNoYWRvdztcclxuXHJcblx0XHRcdFx0XHRjb25zdCBzaGFkb3dVbmlmb3JtcyA9IHNoYWRvd0NhY2hlLmdldCggbGlnaHQgKTtcclxuXHJcblx0XHRcdFx0XHRzaGFkb3dVbmlmb3Jtcy5zaGFkb3dCaWFzID0gc2hhZG93LmJpYXM7XHJcblx0XHRcdFx0XHRzaGFkb3dVbmlmb3Jtcy5zaGFkb3dOb3JtYWxCaWFzID0gc2hhZG93Lm5vcm1hbEJpYXM7XHJcblx0XHRcdFx0XHRzaGFkb3dVbmlmb3Jtcy5zaGFkb3dSYWRpdXMgPSBzaGFkb3cucmFkaXVzO1xyXG5cdFx0XHRcdFx0c2hhZG93VW5pZm9ybXMuc2hhZG93TWFwU2l6ZSA9IHNoYWRvdy5tYXBTaXplO1xyXG5cdFx0XHRcdFx0c2hhZG93VW5pZm9ybXMuc2hhZG93Q2FtZXJhTmVhciA9IHNoYWRvdy5jYW1lcmEubmVhcjtcclxuXHRcdFx0XHRcdHNoYWRvd1VuaWZvcm1zLnNoYWRvd0NhbWVyYUZhciA9IHNoYWRvdy5jYW1lcmEuZmFyO1xyXG5cclxuXHRcdFx0XHRcdHN0YXRlLnBvaW50U2hhZG93WyBwb2ludExlbmd0aCBdID0gc2hhZG93VW5pZm9ybXM7XHJcblx0XHRcdFx0XHRzdGF0ZS5wb2ludFNoYWRvd01hcFsgcG9pbnRMZW5ndGggXSA9IHNoYWRvd01hcDtcclxuXHRcdFx0XHRcdHN0YXRlLnBvaW50U2hhZG93TWF0cml4WyBwb2ludExlbmd0aCBdID0gbGlnaHQuc2hhZG93Lm1hdHJpeDtcclxuXHJcblx0XHRcdFx0XHRudW1Qb2ludFNoYWRvd3MgKys7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0c3RhdGUucG9pbnRbIHBvaW50TGVuZ3RoIF0gPSB1bmlmb3JtcztcclxuXHJcblx0XHRcdFx0cG9pbnRMZW5ndGggKys7XHJcblxyXG5cdFx0XHR9IGVsc2UgaWYgKCBsaWdodC5pc0hlbWlzcGhlcmVMaWdodCApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgdW5pZm9ybXMgPSBjYWNoZS5nZXQoIGxpZ2h0ICk7XHJcblxyXG5cdFx0XHRcdHVuaWZvcm1zLnNreUNvbG9yLmNvcHkoIGxpZ2h0LmNvbG9yICkubXVsdGlwbHlTY2FsYXIoIGludGVuc2l0eSAqIHNjYWxlRmFjdG9yICk7XHJcblx0XHRcdFx0dW5pZm9ybXMuZ3JvdW5kQ29sb3IuY29weSggbGlnaHQuZ3JvdW5kQ29sb3IgKS5tdWx0aXBseVNjYWxhciggaW50ZW5zaXR5ICogc2NhbGVGYWN0b3IgKTtcclxuXHJcblx0XHRcdFx0c3RhdGUuaGVtaVsgaGVtaUxlbmd0aCBdID0gdW5pZm9ybXM7XHJcblxyXG5cdFx0XHRcdGhlbWlMZW5ndGggKys7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggcmVjdEFyZWFMZW5ndGggPiAwICkge1xyXG5cclxuXHRcdFx0aWYgKCBjYXBhYmlsaXRpZXMuaXNXZWJHTDIgKSB7XHJcblxyXG5cdFx0XHRcdC8vIFdlYkdMIDJcclxuXHJcblx0XHRcdFx0aWYgKCBleHRlbnNpb25zLmhhcyggJ09FU190ZXh0dXJlX2Zsb2F0X2xpbmVhcicgKSA9PT0gdHJ1ZSApIHtcclxuXHJcblx0XHRcdFx0XHRzdGF0ZS5yZWN0QXJlYUxUQzEgPSBVbmlmb3Jtc0xpYi5MVENfRkxPQVRfMTtcclxuXHRcdFx0XHRcdHN0YXRlLnJlY3RBcmVhTFRDMiA9IFVuaWZvcm1zTGliLkxUQ19GTE9BVF8yO1xyXG5cclxuXHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdHN0YXRlLnJlY3RBcmVhTFRDMSA9IFVuaWZvcm1zTGliLkxUQ19IQUxGXzE7XHJcblx0XHRcdFx0XHRzdGF0ZS5yZWN0QXJlYUxUQzIgPSBVbmlmb3Jtc0xpYi5MVENfSEFMRl8yO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHQvLyBXZWJHTCAxXHJcblxyXG5cdFx0XHRcdGlmICggZXh0ZW5zaW9ucy5oYXMoICdPRVNfdGV4dHVyZV9mbG9hdF9saW5lYXInICkgPT09IHRydWUgKSB7XHJcblxyXG5cdFx0XHRcdFx0c3RhdGUucmVjdEFyZWFMVEMxID0gVW5pZm9ybXNMaWIuTFRDX0ZMT0FUXzE7XHJcblx0XHRcdFx0XHRzdGF0ZS5yZWN0QXJlYUxUQzIgPSBVbmlmb3Jtc0xpYi5MVENfRkxPQVRfMjtcclxuXHJcblx0XHRcdFx0fSBlbHNlIGlmICggZXh0ZW5zaW9ucy5oYXMoICdPRVNfdGV4dHVyZV9oYWxmX2Zsb2F0X2xpbmVhcicgKSA9PT0gdHJ1ZSApIHtcclxuXHJcblx0XHRcdFx0XHRzdGF0ZS5yZWN0QXJlYUxUQzEgPSBVbmlmb3Jtc0xpYi5MVENfSEFMRl8xO1xyXG5cdFx0XHRcdFx0c3RhdGUucmVjdEFyZWFMVEMyID0gVW5pZm9ybXNMaWIuTFRDX0hBTEZfMjtcclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuV2ViR0xSZW5kZXJlcjogVW5hYmxlIHRvIHVzZSBSZWN0QXJlYUxpZ2h0LiBNaXNzaW5nIFdlYkdMIGV4dGVuc2lvbnMuJyApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHN0YXRlLmFtYmllbnRbIDAgXSA9IHI7XHJcblx0XHRzdGF0ZS5hbWJpZW50WyAxIF0gPSBnO1xyXG5cdFx0c3RhdGUuYW1iaWVudFsgMiBdID0gYjtcclxuXHJcblx0XHRjb25zdCBoYXNoID0gc3RhdGUuaGFzaDtcclxuXHJcblx0XHRpZiAoIGhhc2guZGlyZWN0aW9uYWxMZW5ndGggIT09IGRpcmVjdGlvbmFsTGVuZ3RoIHx8XHJcblx0XHRcdGhhc2gucG9pbnRMZW5ndGggIT09IHBvaW50TGVuZ3RoIHx8XHJcblx0XHRcdGhhc2guc3BvdExlbmd0aCAhPT0gc3BvdExlbmd0aCB8fFxyXG5cdFx0XHRoYXNoLnJlY3RBcmVhTGVuZ3RoICE9PSByZWN0QXJlYUxlbmd0aCB8fFxyXG5cdFx0XHRoYXNoLmhlbWlMZW5ndGggIT09IGhlbWlMZW5ndGggfHxcclxuXHRcdFx0aGFzaC5udW1EaXJlY3Rpb25hbFNoYWRvd3MgIT09IG51bURpcmVjdGlvbmFsU2hhZG93cyB8fFxyXG5cdFx0XHRoYXNoLm51bVBvaW50U2hhZG93cyAhPT0gbnVtUG9pbnRTaGFkb3dzIHx8XHJcblx0XHRcdGhhc2gubnVtU3BvdFNoYWRvd3MgIT09IG51bVNwb3RTaGFkb3dzIHx8XHJcblx0XHRcdGhhc2gubnVtU3BvdE1hcHMgIT09IG51bVNwb3RNYXBzIHx8XHJcblx0XHRcdGhhc2gubnVtTGlnaHRQcm9iZXMgIT09IG51bUxpZ2h0UHJvYmVzICkge1xyXG5cclxuXHRcdFx0c3RhdGUuZGlyZWN0aW9uYWwubGVuZ3RoID0gZGlyZWN0aW9uYWxMZW5ndGg7XHJcblx0XHRcdHN0YXRlLnNwb3QubGVuZ3RoID0gc3BvdExlbmd0aDtcclxuXHRcdFx0c3RhdGUucmVjdEFyZWEubGVuZ3RoID0gcmVjdEFyZWFMZW5ndGg7XHJcblx0XHRcdHN0YXRlLnBvaW50Lmxlbmd0aCA9IHBvaW50TGVuZ3RoO1xyXG5cdFx0XHRzdGF0ZS5oZW1pLmxlbmd0aCA9IGhlbWlMZW5ndGg7XHJcblxyXG5cdFx0XHRzdGF0ZS5kaXJlY3Rpb25hbFNoYWRvdy5sZW5ndGggPSBudW1EaXJlY3Rpb25hbFNoYWRvd3M7XHJcblx0XHRcdHN0YXRlLmRpcmVjdGlvbmFsU2hhZG93TWFwLmxlbmd0aCA9IG51bURpcmVjdGlvbmFsU2hhZG93cztcclxuXHRcdFx0c3RhdGUucG9pbnRTaGFkb3cubGVuZ3RoID0gbnVtUG9pbnRTaGFkb3dzO1xyXG5cdFx0XHRzdGF0ZS5wb2ludFNoYWRvd01hcC5sZW5ndGggPSBudW1Qb2ludFNoYWRvd3M7XHJcblx0XHRcdHN0YXRlLnNwb3RTaGFkb3cubGVuZ3RoID0gbnVtU3BvdFNoYWRvd3M7XHJcblx0XHRcdHN0YXRlLnNwb3RTaGFkb3dNYXAubGVuZ3RoID0gbnVtU3BvdFNoYWRvd3M7XHJcblx0XHRcdHN0YXRlLmRpcmVjdGlvbmFsU2hhZG93TWF0cml4Lmxlbmd0aCA9IG51bURpcmVjdGlvbmFsU2hhZG93cztcclxuXHRcdFx0c3RhdGUucG9pbnRTaGFkb3dNYXRyaXgubGVuZ3RoID0gbnVtUG9pbnRTaGFkb3dzO1xyXG5cdFx0XHRzdGF0ZS5zcG90TGlnaHRNYXRyaXgubGVuZ3RoID0gbnVtU3BvdFNoYWRvd3MgKyBudW1TcG90TWFwcyAtIG51bVNwb3RTaGFkb3dzV2l0aE1hcHM7XHJcblx0XHRcdHN0YXRlLnNwb3RMaWdodE1hcC5sZW5ndGggPSBudW1TcG90TWFwcztcclxuXHRcdFx0c3RhdGUubnVtU3BvdExpZ2h0U2hhZG93c1dpdGhNYXBzID0gbnVtU3BvdFNoYWRvd3NXaXRoTWFwcztcclxuXHRcdFx0c3RhdGUubnVtTGlnaHRQcm9iZXMgPSBudW1MaWdodFByb2JlcztcclxuXHJcblx0XHRcdGhhc2guZGlyZWN0aW9uYWxMZW5ndGggPSBkaXJlY3Rpb25hbExlbmd0aDtcclxuXHRcdFx0aGFzaC5wb2ludExlbmd0aCA9IHBvaW50TGVuZ3RoO1xyXG5cdFx0XHRoYXNoLnNwb3RMZW5ndGggPSBzcG90TGVuZ3RoO1xyXG5cdFx0XHRoYXNoLnJlY3RBcmVhTGVuZ3RoID0gcmVjdEFyZWFMZW5ndGg7XHJcblx0XHRcdGhhc2guaGVtaUxlbmd0aCA9IGhlbWlMZW5ndGg7XHJcblxyXG5cdFx0XHRoYXNoLm51bURpcmVjdGlvbmFsU2hhZG93cyA9IG51bURpcmVjdGlvbmFsU2hhZG93cztcclxuXHRcdFx0aGFzaC5udW1Qb2ludFNoYWRvd3MgPSBudW1Qb2ludFNoYWRvd3M7XHJcblx0XHRcdGhhc2gubnVtU3BvdFNoYWRvd3MgPSBudW1TcG90U2hhZG93cztcclxuXHRcdFx0aGFzaC5udW1TcG90TWFwcyA9IG51bVNwb3RNYXBzO1xyXG5cclxuXHRcdFx0aGFzaC5udW1MaWdodFByb2JlcyA9IG51bUxpZ2h0UHJvYmVzO1xyXG5cclxuXHRcdFx0c3RhdGUudmVyc2lvbiA9IG5leHRWZXJzaW9uICsrO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBzZXR1cFZpZXcoIGxpZ2h0cywgY2FtZXJhICkge1xyXG5cclxuXHRcdGxldCBkaXJlY3Rpb25hbExlbmd0aCA9IDA7XHJcblx0XHRsZXQgcG9pbnRMZW5ndGggPSAwO1xyXG5cdFx0bGV0IHNwb3RMZW5ndGggPSAwO1xyXG5cdFx0bGV0IHJlY3RBcmVhTGVuZ3RoID0gMDtcclxuXHRcdGxldCBoZW1pTGVuZ3RoID0gMDtcclxuXHJcblx0XHRjb25zdCB2aWV3TWF0cml4ID0gY2FtZXJhLm1hdHJpeFdvcmxkSW52ZXJzZTtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBsaWdodHMubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdGNvbnN0IGxpZ2h0ID0gbGlnaHRzWyBpIF07XHJcblxyXG5cdFx0XHRpZiAoIGxpZ2h0LmlzRGlyZWN0aW9uYWxMaWdodCApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgdW5pZm9ybXMgPSBzdGF0ZS5kaXJlY3Rpb25hbFsgZGlyZWN0aW9uYWxMZW5ndGggXTtcclxuXHJcblx0XHRcdFx0dW5pZm9ybXMuZGlyZWN0aW9uLnNldEZyb21NYXRyaXhQb3NpdGlvbiggbGlnaHQubWF0cml4V29ybGQgKTtcclxuXHRcdFx0XHR2ZWN0b3IzLnNldEZyb21NYXRyaXhQb3NpdGlvbiggbGlnaHQudGFyZ2V0Lm1hdHJpeFdvcmxkICk7XHJcblx0XHRcdFx0dW5pZm9ybXMuZGlyZWN0aW9uLnN1YiggdmVjdG9yMyApO1xyXG5cdFx0XHRcdHVuaWZvcm1zLmRpcmVjdGlvbi50cmFuc2Zvcm1EaXJlY3Rpb24oIHZpZXdNYXRyaXggKTtcclxuXHJcblx0XHRcdFx0ZGlyZWN0aW9uYWxMZW5ndGggKys7XHJcblxyXG5cdFx0XHR9IGVsc2UgaWYgKCBsaWdodC5pc1Nwb3RMaWdodCApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgdW5pZm9ybXMgPSBzdGF0ZS5zcG90WyBzcG90TGVuZ3RoIF07XHJcblxyXG5cdFx0XHRcdHVuaWZvcm1zLnBvc2l0aW9uLnNldEZyb21NYXRyaXhQb3NpdGlvbiggbGlnaHQubWF0cml4V29ybGQgKTtcclxuXHRcdFx0XHR1bmlmb3Jtcy5wb3NpdGlvbi5hcHBseU1hdHJpeDQoIHZpZXdNYXRyaXggKTtcclxuXHJcblx0XHRcdFx0dW5pZm9ybXMuZGlyZWN0aW9uLnNldEZyb21NYXRyaXhQb3NpdGlvbiggbGlnaHQubWF0cml4V29ybGQgKTtcclxuXHRcdFx0XHR2ZWN0b3IzLnNldEZyb21NYXRyaXhQb3NpdGlvbiggbGlnaHQudGFyZ2V0Lm1hdHJpeFdvcmxkICk7XHJcblx0XHRcdFx0dW5pZm9ybXMuZGlyZWN0aW9uLnN1YiggdmVjdG9yMyApO1xyXG5cdFx0XHRcdHVuaWZvcm1zLmRpcmVjdGlvbi50cmFuc2Zvcm1EaXJlY3Rpb24oIHZpZXdNYXRyaXggKTtcclxuXHJcblx0XHRcdFx0c3BvdExlbmd0aCArKztcclxuXHJcblx0XHRcdH0gZWxzZSBpZiAoIGxpZ2h0LmlzUmVjdEFyZWFMaWdodCApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgdW5pZm9ybXMgPSBzdGF0ZS5yZWN0QXJlYVsgcmVjdEFyZWFMZW5ndGggXTtcclxuXHJcblx0XHRcdFx0dW5pZm9ybXMucG9zaXRpb24uc2V0RnJvbU1hdHJpeFBvc2l0aW9uKCBsaWdodC5tYXRyaXhXb3JsZCApO1xyXG5cdFx0XHRcdHVuaWZvcm1zLnBvc2l0aW9uLmFwcGx5TWF0cml4NCggdmlld01hdHJpeCApO1xyXG5cclxuXHRcdFx0XHQvLyBleHRyYWN0IGxvY2FsIHJvdGF0aW9uIG9mIGxpZ2h0IHRvIGRlcml2ZSB3aWR0aC9oZWlnaHQgaGFsZiB2ZWN0b3JzXHJcblx0XHRcdFx0bWF0cml4NDIuaWRlbnRpdHkoKTtcclxuXHRcdFx0XHRtYXRyaXg0LmNvcHkoIGxpZ2h0Lm1hdHJpeFdvcmxkICk7XHJcblx0XHRcdFx0bWF0cml4NC5wcmVtdWx0aXBseSggdmlld01hdHJpeCApO1xyXG5cdFx0XHRcdG1hdHJpeDQyLmV4dHJhY3RSb3RhdGlvbiggbWF0cml4NCApO1xyXG5cclxuXHRcdFx0XHR1bmlmb3Jtcy5oYWxmV2lkdGguc2V0KCBsaWdodC53aWR0aCAqIDAuNSwgMC4wLCAwLjAgKTtcclxuXHRcdFx0XHR1bmlmb3Jtcy5oYWxmSGVpZ2h0LnNldCggMC4wLCBsaWdodC5oZWlnaHQgKiAwLjUsIDAuMCApO1xyXG5cclxuXHRcdFx0XHR1bmlmb3Jtcy5oYWxmV2lkdGguYXBwbHlNYXRyaXg0KCBtYXRyaXg0MiApO1xyXG5cdFx0XHRcdHVuaWZvcm1zLmhhbGZIZWlnaHQuYXBwbHlNYXRyaXg0KCBtYXRyaXg0MiApO1xyXG5cclxuXHRcdFx0XHRyZWN0QXJlYUxlbmd0aCArKztcclxuXHJcblx0XHRcdH0gZWxzZSBpZiAoIGxpZ2h0LmlzUG9pbnRMaWdodCApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgdW5pZm9ybXMgPSBzdGF0ZS5wb2ludFsgcG9pbnRMZW5ndGggXTtcclxuXHJcblx0XHRcdFx0dW5pZm9ybXMucG9zaXRpb24uc2V0RnJvbU1hdHJpeFBvc2l0aW9uKCBsaWdodC5tYXRyaXhXb3JsZCApO1xyXG5cdFx0XHRcdHVuaWZvcm1zLnBvc2l0aW9uLmFwcGx5TWF0cml4NCggdmlld01hdHJpeCApO1xyXG5cclxuXHRcdFx0XHRwb2ludExlbmd0aCArKztcclxuXHJcblx0XHRcdH0gZWxzZSBpZiAoIGxpZ2h0LmlzSGVtaXNwaGVyZUxpZ2h0ICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCB1bmlmb3JtcyA9IHN0YXRlLmhlbWlbIGhlbWlMZW5ndGggXTtcclxuXHJcblx0XHRcdFx0dW5pZm9ybXMuZGlyZWN0aW9uLnNldEZyb21NYXRyaXhQb3NpdGlvbiggbGlnaHQubWF0cml4V29ybGQgKTtcclxuXHRcdFx0XHR1bmlmb3Jtcy5kaXJlY3Rpb24udHJhbnNmb3JtRGlyZWN0aW9uKCB2aWV3TWF0cml4ICk7XHJcblxyXG5cdFx0XHRcdGhlbWlMZW5ndGggKys7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdHJldHVybiB7XHJcblx0XHRzZXR1cDogc2V0dXAsXHJcblx0XHRzZXR1cFZpZXc6IHNldHVwVmlldyxcclxuXHRcdHN0YXRlOiBzdGF0ZVxyXG5cdH07XHJcblxyXG59XHJcblxyXG5cclxuZXhwb3J0IHsgV2ViR0xMaWdodHMgfTtcclxuIiwiaW1wb3J0IHsgV2ViR0xMaWdodHMgfSBmcm9tICcuL1dlYkdMTGlnaHRzLmpzJztcclxuXHJcbmZ1bmN0aW9uIFdlYkdMUmVuZGVyU3RhdGUoIGV4dGVuc2lvbnMsIGNhcGFiaWxpdGllcyApIHtcclxuXHJcblx0Y29uc3QgbGlnaHRzID0gbmV3IFdlYkdMTGlnaHRzKCBleHRlbnNpb25zLCBjYXBhYmlsaXRpZXMgKTtcclxuXHJcblx0Y29uc3QgbGlnaHRzQXJyYXkgPSBbXTtcclxuXHRjb25zdCBzaGFkb3dzQXJyYXkgPSBbXTtcclxuXHJcblx0ZnVuY3Rpb24gaW5pdCgpIHtcclxuXHJcblx0XHRsaWdodHNBcnJheS5sZW5ndGggPSAwO1xyXG5cdFx0c2hhZG93c0FycmF5Lmxlbmd0aCA9IDA7XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gcHVzaExpZ2h0KCBsaWdodCApIHtcclxuXHJcblx0XHRsaWdodHNBcnJheS5wdXNoKCBsaWdodCApO1xyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHB1c2hTaGFkb3coIHNoYWRvd0xpZ2h0ICkge1xyXG5cclxuXHRcdHNoYWRvd3NBcnJheS5wdXNoKCBzaGFkb3dMaWdodCApO1xyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHNldHVwTGlnaHRzKCB1c2VMZWdhY3lMaWdodHMgKSB7XHJcblxyXG5cdFx0bGlnaHRzLnNldHVwKCBsaWdodHNBcnJheSwgdXNlTGVnYWN5TGlnaHRzICk7XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gc2V0dXBMaWdodHNWaWV3KCBjYW1lcmEgKSB7XHJcblxyXG5cdFx0bGlnaHRzLnNldHVwVmlldyggbGlnaHRzQXJyYXksIGNhbWVyYSApO1xyXG5cclxuXHR9XHJcblxyXG5cdGNvbnN0IHN0YXRlID0ge1xyXG5cdFx0bGlnaHRzQXJyYXk6IGxpZ2h0c0FycmF5LFxyXG5cdFx0c2hhZG93c0FycmF5OiBzaGFkb3dzQXJyYXksXHJcblxyXG5cdFx0bGlnaHRzOiBsaWdodHNcclxuXHR9O1xyXG5cclxuXHRyZXR1cm4ge1xyXG5cdFx0aW5pdDogaW5pdCxcclxuXHRcdHN0YXRlOiBzdGF0ZSxcclxuXHRcdHNldHVwTGlnaHRzOiBzZXR1cExpZ2h0cyxcclxuXHRcdHNldHVwTGlnaHRzVmlldzogc2V0dXBMaWdodHNWaWV3LFxyXG5cclxuXHRcdHB1c2hMaWdodDogcHVzaExpZ2h0LFxyXG5cdFx0cHVzaFNoYWRvdzogcHVzaFNoYWRvd1xyXG5cdH07XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiBXZWJHTFJlbmRlclN0YXRlcyggZXh0ZW5zaW9ucywgY2FwYWJpbGl0aWVzICkge1xyXG5cclxuXHRsZXQgcmVuZGVyU3RhdGVzID0gbmV3IFdlYWtNYXAoKTtcclxuXHJcblx0ZnVuY3Rpb24gZ2V0KCBzY2VuZSwgcmVuZGVyQ2FsbERlcHRoID0gMCApIHtcclxuXHJcblx0XHRjb25zdCByZW5kZXJTdGF0ZUFycmF5ID0gcmVuZGVyU3RhdGVzLmdldCggc2NlbmUgKTtcclxuXHRcdGxldCByZW5kZXJTdGF0ZTtcclxuXHJcblx0XHRpZiAoIHJlbmRlclN0YXRlQXJyYXkgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdHJlbmRlclN0YXRlID0gbmV3IFdlYkdMUmVuZGVyU3RhdGUoIGV4dGVuc2lvbnMsIGNhcGFiaWxpdGllcyApO1xyXG5cdFx0XHRyZW5kZXJTdGF0ZXMuc2V0KCBzY2VuZSwgWyByZW5kZXJTdGF0ZSBdICk7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdGlmICggcmVuZGVyQ2FsbERlcHRoID49IHJlbmRlclN0YXRlQXJyYXkubGVuZ3RoICkge1xyXG5cclxuXHRcdFx0XHRyZW5kZXJTdGF0ZSA9IG5ldyBXZWJHTFJlbmRlclN0YXRlKCBleHRlbnNpb25zLCBjYXBhYmlsaXRpZXMgKTtcclxuXHRcdFx0XHRyZW5kZXJTdGF0ZUFycmF5LnB1c2goIHJlbmRlclN0YXRlICk7XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRyZW5kZXJTdGF0ZSA9IHJlbmRlclN0YXRlQXJyYXlbIHJlbmRlckNhbGxEZXB0aCBdO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gcmVuZGVyU3RhdGU7XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gZGlzcG9zZSgpIHtcclxuXHJcblx0XHRyZW5kZXJTdGF0ZXMgPSBuZXcgV2Vha01hcCgpO1xyXG5cclxuXHR9XHJcblxyXG5cdHJldHVybiB7XHJcblx0XHRnZXQ6IGdldCxcclxuXHRcdGRpc3Bvc2U6IGRpc3Bvc2VcclxuXHR9O1xyXG5cclxufVxyXG5cclxuXHJcbmV4cG9ydCB7IFdlYkdMUmVuZGVyU3RhdGVzIH07XHJcbiIsImltcG9ydCB7IE1hdGVyaWFsIH0gZnJvbSAnLi9NYXRlcmlhbC5qcyc7XHJcbmltcG9ydCB7IEJhc2ljRGVwdGhQYWNraW5nIH0gZnJvbSAnLi4vY29uc3RhbnRzLmpzJztcclxuXHJcbmNsYXNzIE1lc2hEZXB0aE1hdGVyaWFsIGV4dGVuZHMgTWF0ZXJpYWwge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggcGFyYW1ldGVycyApIHtcclxuXHJcblx0XHRzdXBlcigpO1xyXG5cclxuXHRcdHRoaXMuaXNNZXNoRGVwdGhNYXRlcmlhbCA9IHRydWU7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ01lc2hEZXB0aE1hdGVyaWFsJztcclxuXHJcblx0XHR0aGlzLmRlcHRoUGFja2luZyA9IEJhc2ljRGVwdGhQYWNraW5nO1xyXG5cclxuXHRcdHRoaXMubWFwID0gbnVsbDtcclxuXHJcblx0XHR0aGlzLmFscGhhTWFwID0gbnVsbDtcclxuXHJcblx0XHR0aGlzLmRpc3BsYWNlbWVudE1hcCA9IG51bGw7XHJcblx0XHR0aGlzLmRpc3BsYWNlbWVudFNjYWxlID0gMTtcclxuXHRcdHRoaXMuZGlzcGxhY2VtZW50QmlhcyA9IDA7XHJcblxyXG5cdFx0dGhpcy53aXJlZnJhbWUgPSBmYWxzZTtcclxuXHRcdHRoaXMud2lyZWZyYW1lTGluZXdpZHRoID0gMTtcclxuXHJcblx0XHR0aGlzLnNldFZhbHVlcyggcGFyYW1ldGVycyApO1xyXG5cclxuXHR9XHJcblxyXG5cdGNvcHkoIHNvdXJjZSApIHtcclxuXHJcblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcclxuXHJcblx0XHR0aGlzLmRlcHRoUGFja2luZyA9IHNvdXJjZS5kZXB0aFBhY2tpbmc7XHJcblxyXG5cdFx0dGhpcy5tYXAgPSBzb3VyY2UubWFwO1xyXG5cclxuXHRcdHRoaXMuYWxwaGFNYXAgPSBzb3VyY2UuYWxwaGFNYXA7XHJcblxyXG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRNYXAgPSBzb3VyY2UuZGlzcGxhY2VtZW50TWFwO1xyXG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRTY2FsZSA9IHNvdXJjZS5kaXNwbGFjZW1lbnRTY2FsZTtcclxuXHRcdHRoaXMuZGlzcGxhY2VtZW50QmlhcyA9IHNvdXJjZS5kaXNwbGFjZW1lbnRCaWFzO1xyXG5cclxuXHRcdHRoaXMud2lyZWZyYW1lID0gc291cmNlLndpcmVmcmFtZTtcclxuXHRcdHRoaXMud2lyZWZyYW1lTGluZXdpZHRoID0gc291cmNlLndpcmVmcmFtZUxpbmV3aWR0aDtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgTWVzaERlcHRoTWF0ZXJpYWwgfTtcclxuIiwiaW1wb3J0IHsgTWF0ZXJpYWwgfSBmcm9tICcuL01hdGVyaWFsLmpzJztcclxuXHJcbmNsYXNzIE1lc2hEaXN0YW5jZU1hdGVyaWFsIGV4dGVuZHMgTWF0ZXJpYWwge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggcGFyYW1ldGVycyApIHtcclxuXHJcblx0XHRzdXBlcigpO1xyXG5cclxuXHRcdHRoaXMuaXNNZXNoRGlzdGFuY2VNYXRlcmlhbCA9IHRydWU7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ01lc2hEaXN0YW5jZU1hdGVyaWFsJztcclxuXHJcblx0XHR0aGlzLm1hcCA9IG51bGw7XHJcblxyXG5cdFx0dGhpcy5hbHBoYU1hcCA9IG51bGw7XHJcblxyXG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRNYXAgPSBudWxsO1xyXG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRTY2FsZSA9IDE7XHJcblx0XHR0aGlzLmRpc3BsYWNlbWVudEJpYXMgPSAwO1xyXG5cclxuXHRcdHRoaXMuc2V0VmFsdWVzKCBwYXJhbWV0ZXJzICk7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xyXG5cclxuXHRcdHRoaXMubWFwID0gc291cmNlLm1hcDtcclxuXHJcblx0XHR0aGlzLmFscGhhTWFwID0gc291cmNlLmFscGhhTWFwO1xyXG5cclxuXHRcdHRoaXMuZGlzcGxhY2VtZW50TWFwID0gc291cmNlLmRpc3BsYWNlbWVudE1hcDtcclxuXHRcdHRoaXMuZGlzcGxhY2VtZW50U2NhbGUgPSBzb3VyY2UuZGlzcGxhY2VtZW50U2NhbGU7XHJcblx0XHR0aGlzLmRpc3BsYWNlbWVudEJpYXMgPSBzb3VyY2UuZGlzcGxhY2VtZW50QmlhcztcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgTWVzaERpc3RhbmNlTWF0ZXJpYWwgfTtcclxuIiwiZXhwb3J0IGNvbnN0IHZlcnRleCA9IC8qIGdsc2wgKi9gXHJcbnZvaWQgbWFpbigpIHtcclxuXHJcblx0Z2xfUG9zaXRpb24gPSB2ZWM0KCBwb3NpdGlvbiwgMS4wICk7XHJcblxyXG59XHJcbmA7XHJcblxyXG5leHBvcnQgY29uc3QgZnJhZ21lbnQgPSAvKiBnbHNsICovYFxyXG51bmlmb3JtIHNhbXBsZXIyRCBzaGFkb3dfcGFzcztcclxudW5pZm9ybSB2ZWMyIHJlc29sdXRpb247XHJcbnVuaWZvcm0gZmxvYXQgcmFkaXVzO1xyXG5cclxuI2luY2x1ZGUgPHBhY2tpbmc+XHJcblxyXG52b2lkIG1haW4oKSB7XHJcblxyXG5cdGNvbnN0IGZsb2F0IHNhbXBsZXMgPSBmbG9hdCggVlNNX1NBTVBMRVMgKTtcclxuXHJcblx0ZmxvYXQgbWVhbiA9IDAuMDtcclxuXHRmbG9hdCBzcXVhcmVkX21lYW4gPSAwLjA7XHJcblxyXG5cdGZsb2F0IHV2U3RyaWRlID0gc2FtcGxlcyA8PSAxLjAgPyAwLjAgOiAyLjAgLyAoIHNhbXBsZXMgLSAxLjAgKTtcclxuXHRmbG9hdCB1dlN0YXJ0ID0gc2FtcGxlcyA8PSAxLjAgPyAwLjAgOiAtIDEuMDtcclxuXHRmb3IgKCBmbG9hdCBpID0gMC4wOyBpIDwgc2FtcGxlczsgaSArKyApIHtcclxuXHJcblx0XHRmbG9hdCB1dk9mZnNldCA9IHV2U3RhcnQgKyBpICogdXZTdHJpZGU7XHJcblxyXG5cdFx0I2lmZGVmIEhPUklaT05UQUxfUEFTU1xyXG5cclxuXHRcdFx0dmVjMiBkaXN0cmlidXRpb24gPSB1bnBhY2tSR0JBVG8ySGFsZiggdGV4dHVyZTJEKCBzaGFkb3dfcGFzcywgKCBnbF9GcmFnQ29vcmQueHkgKyB2ZWMyKCB1dk9mZnNldCwgMC4wICkgKiByYWRpdXMgKSAvIHJlc29sdXRpb24gKSApO1xyXG5cdFx0XHRtZWFuICs9IGRpc3RyaWJ1dGlvbi54O1xyXG5cdFx0XHRzcXVhcmVkX21lYW4gKz0gZGlzdHJpYnV0aW9uLnkgKiBkaXN0cmlidXRpb24ueSArIGRpc3RyaWJ1dGlvbi54ICogZGlzdHJpYnV0aW9uLng7XHJcblxyXG5cdFx0I2Vsc2VcclxuXHJcblx0XHRcdGZsb2F0IGRlcHRoID0gdW5wYWNrUkdCQVRvRGVwdGgoIHRleHR1cmUyRCggc2hhZG93X3Bhc3MsICggZ2xfRnJhZ0Nvb3JkLnh5ICsgdmVjMiggMC4wLCB1dk9mZnNldCApICogcmFkaXVzICkgLyByZXNvbHV0aW9uICkgKTtcclxuXHRcdFx0bWVhbiArPSBkZXB0aDtcclxuXHRcdFx0c3F1YXJlZF9tZWFuICs9IGRlcHRoICogZGVwdGg7XHJcblxyXG5cdFx0I2VuZGlmXHJcblxyXG5cdH1cclxuXHJcblx0bWVhbiA9IG1lYW4gLyBzYW1wbGVzO1xyXG5cdHNxdWFyZWRfbWVhbiA9IHNxdWFyZWRfbWVhbiAvIHNhbXBsZXM7XHJcblxyXG5cdGZsb2F0IHN0ZF9kZXYgPSBzcXJ0KCBzcXVhcmVkX21lYW4gLSBtZWFuICogbWVhbiApO1xyXG5cclxuXHRnbF9GcmFnQ29sb3IgPSBwYWNrMkhhbGZUb1JHQkEoIHZlYzIoIG1lYW4sIHN0ZF9kZXYgKSApO1xyXG5cclxufVxyXG5gO1xyXG4iLCJpbXBvcnQgeyBGcm9udFNpZGUsIEJhY2tTaWRlLCBEb3VibGVTaWRlLCBOZWFyZXN0RmlsdGVyLCBQQ0ZTaGFkb3dNYXAsIFZTTVNoYWRvd01hcCwgUkdCQURlcHRoUGFja2luZywgTm9CbGVuZGluZyB9IGZyb20gJy4uLy4uL2NvbnN0YW50cy5qcyc7XHJcbmltcG9ydCB7IFdlYkdMUmVuZGVyVGFyZ2V0IH0gZnJvbSAnLi4vV2ViR0xSZW5kZXJUYXJnZXQuanMnO1xyXG5pbXBvcnQgeyBNZXNoRGVwdGhNYXRlcmlhbCB9IGZyb20gJy4uLy4uL21hdGVyaWFscy9NZXNoRGVwdGhNYXRlcmlhbC5qcyc7XHJcbmltcG9ydCB7IE1lc2hEaXN0YW5jZU1hdGVyaWFsIH0gZnJvbSAnLi4vLi4vbWF0ZXJpYWxzL01lc2hEaXN0YW5jZU1hdGVyaWFsLmpzJztcclxuaW1wb3J0IHsgU2hhZGVyTWF0ZXJpYWwgfSBmcm9tICcuLi8uLi9tYXRlcmlhbHMvU2hhZGVyTWF0ZXJpYWwuanMnO1xyXG5pbXBvcnQgeyBCdWZmZXJBdHRyaWJ1dGUgfSBmcm9tICcuLi8uLi9jb3JlL0J1ZmZlckF0dHJpYnV0ZS5qcyc7XHJcbmltcG9ydCB7IEJ1ZmZlckdlb21ldHJ5IH0gZnJvbSAnLi4vLi4vY29yZS9CdWZmZXJHZW9tZXRyeS5qcyc7XHJcbmltcG9ydCB7IE1lc2ggfSBmcm9tICcuLi8uLi9vYmplY3RzL01lc2guanMnO1xyXG5pbXBvcnQgeyBWZWN0b3I0IH0gZnJvbSAnLi4vLi4vbWF0aC9WZWN0b3I0LmpzJztcclxuaW1wb3J0IHsgVmVjdG9yMiB9IGZyb20gJy4uLy4uL21hdGgvVmVjdG9yMi5qcyc7XHJcbmltcG9ydCB7IEZydXN0dW0gfSBmcm9tICcuLi8uLi9tYXRoL0ZydXN0dW0uanMnO1xyXG5cclxuaW1wb3J0ICogYXMgdnNtIGZyb20gJy4uL3NoYWRlcnMvU2hhZGVyTGliL3ZzbS5nbHNsLmpzJztcclxuXHJcbmZ1bmN0aW9uIFdlYkdMU2hhZG93TWFwKCBfcmVuZGVyZXIsIF9vYmplY3RzLCBfY2FwYWJpbGl0aWVzICkge1xyXG5cclxuXHRsZXQgX2ZydXN0dW0gPSBuZXcgRnJ1c3R1bSgpO1xyXG5cclxuXHRjb25zdCBfc2hhZG93TWFwU2l6ZSA9IG5ldyBWZWN0b3IyKCksXHJcblx0XHRfdmlld3BvcnRTaXplID0gbmV3IFZlY3RvcjIoKSxcclxuXHJcblx0XHRfdmlld3BvcnQgPSBuZXcgVmVjdG9yNCgpLFxyXG5cclxuXHRcdF9kZXB0aE1hdGVyaWFsID0gbmV3IE1lc2hEZXB0aE1hdGVyaWFsKCB7IGRlcHRoUGFja2luZzogUkdCQURlcHRoUGFja2luZyB9ICksXHJcblx0XHRfZGlzdGFuY2VNYXRlcmlhbCA9IG5ldyBNZXNoRGlzdGFuY2VNYXRlcmlhbCgpLFxyXG5cclxuXHRcdF9tYXRlcmlhbENhY2hlID0ge30sXHJcblxyXG5cdFx0X21heFRleHR1cmVTaXplID0gX2NhcGFiaWxpdGllcy5tYXhUZXh0dXJlU2l6ZTtcclxuXHJcblx0Y29uc3Qgc2hhZG93U2lkZSA9IHsgWyBGcm9udFNpZGUgXTogQmFja1NpZGUsIFsgQmFja1NpZGUgXTogRnJvbnRTaWRlLCBbIERvdWJsZVNpZGUgXTogRG91YmxlU2lkZSB9O1xyXG5cclxuXHRjb25zdCBzaGFkb3dNYXRlcmlhbFZlcnRpY2FsID0gbmV3IFNoYWRlck1hdGVyaWFsKCB7XHJcblx0XHRkZWZpbmVzOiB7XHJcblx0XHRcdFZTTV9TQU1QTEVTOiA4XHJcblx0XHR9LFxyXG5cdFx0dW5pZm9ybXM6IHtcclxuXHRcdFx0c2hhZG93X3Bhc3M6IHsgdmFsdWU6IG51bGwgfSxcclxuXHRcdFx0cmVzb2x1dGlvbjogeyB2YWx1ZTogbmV3IFZlY3RvcjIoKSB9LFxyXG5cdFx0XHRyYWRpdXM6IHsgdmFsdWU6IDQuMCB9XHJcblx0XHR9LFxyXG5cclxuXHRcdHZlcnRleFNoYWRlcjogdnNtLnZlcnRleCxcclxuXHRcdGZyYWdtZW50U2hhZGVyOiB2c20uZnJhZ21lbnRcclxuXHJcblx0fSApO1xyXG5cclxuXHRjb25zdCBzaGFkb3dNYXRlcmlhbEhvcml6b250YWwgPSBzaGFkb3dNYXRlcmlhbFZlcnRpY2FsLmNsb25lKCk7XHJcblx0c2hhZG93TWF0ZXJpYWxIb3Jpem9udGFsLmRlZmluZXMuSE9SSVpPTlRBTF9QQVNTID0gMTtcclxuXHJcblx0Y29uc3QgZnVsbFNjcmVlblRyaSA9IG5ldyBCdWZmZXJHZW9tZXRyeSgpO1xyXG5cdGZ1bGxTY3JlZW5Ucmkuc2V0QXR0cmlidXRlKFxyXG5cdFx0J3Bvc2l0aW9uJyxcclxuXHRcdG5ldyBCdWZmZXJBdHRyaWJ1dGUoXHJcblx0XHRcdG5ldyBGbG9hdDMyQXJyYXkoIFsgLSAxLCAtIDEsIDAuNSwgMywgLSAxLCAwLjUsIC0gMSwgMywgMC41IF0gKSxcclxuXHRcdFx0M1xyXG5cdFx0KVxyXG5cdCk7XHJcblxyXG5cdGNvbnN0IGZ1bGxTY3JlZW5NZXNoID0gbmV3IE1lc2goIGZ1bGxTY3JlZW5UcmksIHNoYWRvd01hdGVyaWFsVmVydGljYWwgKTtcclxuXHJcblx0Y29uc3Qgc2NvcGUgPSB0aGlzO1xyXG5cclxuXHR0aGlzLmVuYWJsZWQgPSBmYWxzZTtcclxuXHJcblx0dGhpcy5hdXRvVXBkYXRlID0gdHJ1ZTtcclxuXHR0aGlzLm5lZWRzVXBkYXRlID0gZmFsc2U7XHJcblxyXG5cdHRoaXMudHlwZSA9IFBDRlNoYWRvd01hcDtcclxuXHRsZXQgX3ByZXZpb3VzVHlwZSA9IHRoaXMudHlwZTtcclxuXHJcblx0dGhpcy5yZW5kZXIgPSBmdW5jdGlvbiAoIGxpZ2h0cywgc2NlbmUsIGNhbWVyYSApIHtcclxuXHJcblx0XHRpZiAoIHNjb3BlLmVuYWJsZWQgPT09IGZhbHNlICkgcmV0dXJuO1xyXG5cdFx0aWYgKCBzY29wZS5hdXRvVXBkYXRlID09PSBmYWxzZSAmJiBzY29wZS5uZWVkc1VwZGF0ZSA9PT0gZmFsc2UgKSByZXR1cm47XHJcblxyXG5cdFx0aWYgKCBsaWdodHMubGVuZ3RoID09PSAwICkgcmV0dXJuO1xyXG5cclxuXHRcdGNvbnN0IGN1cnJlbnRSZW5kZXJUYXJnZXQgPSBfcmVuZGVyZXIuZ2V0UmVuZGVyVGFyZ2V0KCk7XHJcblx0XHRjb25zdCBhY3RpdmVDdWJlRmFjZSA9IF9yZW5kZXJlci5nZXRBY3RpdmVDdWJlRmFjZSgpO1xyXG5cdFx0Y29uc3QgYWN0aXZlTWlwbWFwTGV2ZWwgPSBfcmVuZGVyZXIuZ2V0QWN0aXZlTWlwbWFwTGV2ZWwoKTtcclxuXHJcblx0XHRjb25zdCBfc3RhdGUgPSBfcmVuZGVyZXIuc3RhdGU7XHJcblxyXG5cdFx0Ly8gU2V0IEdMIHN0YXRlIGZvciBkZXB0aCBtYXAuXHJcblx0XHRfc3RhdGUuc2V0QmxlbmRpbmcoIE5vQmxlbmRpbmcgKTtcclxuXHRcdF9zdGF0ZS5idWZmZXJzLmNvbG9yLnNldENsZWFyKCAxLCAxLCAxLCAxICk7XHJcblx0XHRfc3RhdGUuYnVmZmVycy5kZXB0aC5zZXRUZXN0KCB0cnVlICk7XHJcblx0XHRfc3RhdGUuc2V0U2Npc3NvclRlc3QoIGZhbHNlICk7XHJcblxyXG5cdFx0Ly8gY2hlY2sgZm9yIHNoYWRvdyBtYXAgdHlwZSBjaGFuZ2VzXHJcblxyXG5cdFx0Y29uc3QgdG9WU00gPSAoIF9wcmV2aW91c1R5cGUgIT09IFZTTVNoYWRvd01hcCAmJiB0aGlzLnR5cGUgPT09IFZTTVNoYWRvd01hcCApO1xyXG5cdFx0Y29uc3QgZnJvbVZTTSA9ICggX3ByZXZpb3VzVHlwZSA9PT0gVlNNU2hhZG93TWFwICYmIHRoaXMudHlwZSAhPT0gVlNNU2hhZG93TWFwICk7XHJcblxyXG5cdFx0Ly8gcmVuZGVyIGRlcHRoIG1hcFxyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSBsaWdodHMubGVuZ3RoOyBpIDwgaWw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBsaWdodCA9IGxpZ2h0c1sgaSBdO1xyXG5cdFx0XHRjb25zdCBzaGFkb3cgPSBsaWdodC5zaGFkb3c7XHJcblxyXG5cdFx0XHRpZiAoIHNoYWRvdyA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5XZWJHTFNoYWRvd01hcDonLCBsaWdodCwgJ2hhcyBubyBzaGFkb3cuJyApO1xyXG5cdFx0XHRcdGNvbnRpbnVlO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0aWYgKCBzaGFkb3cuYXV0b1VwZGF0ZSA9PT0gZmFsc2UgJiYgc2hhZG93Lm5lZWRzVXBkYXRlID09PSBmYWxzZSApIGNvbnRpbnVlO1xyXG5cclxuXHRcdFx0X3NoYWRvd01hcFNpemUuY29weSggc2hhZG93Lm1hcFNpemUgKTtcclxuXHJcblx0XHRcdGNvbnN0IHNoYWRvd0ZyYW1lRXh0ZW50cyA9IHNoYWRvdy5nZXRGcmFtZUV4dGVudHMoKTtcclxuXHJcblx0XHRcdF9zaGFkb3dNYXBTaXplLm11bHRpcGx5KCBzaGFkb3dGcmFtZUV4dGVudHMgKTtcclxuXHJcblx0XHRcdF92aWV3cG9ydFNpemUuY29weSggc2hhZG93Lm1hcFNpemUgKTtcclxuXHJcblx0XHRcdGlmICggX3NoYWRvd01hcFNpemUueCA+IF9tYXhUZXh0dXJlU2l6ZSB8fCBfc2hhZG93TWFwU2l6ZS55ID4gX21heFRleHR1cmVTaXplICkge1xyXG5cclxuXHRcdFx0XHRpZiAoIF9zaGFkb3dNYXBTaXplLnggPiBfbWF4VGV4dHVyZVNpemUgKSB7XHJcblxyXG5cdFx0XHRcdFx0X3ZpZXdwb3J0U2l6ZS54ID0gTWF0aC5mbG9vciggX21heFRleHR1cmVTaXplIC8gc2hhZG93RnJhbWVFeHRlbnRzLnggKTtcclxuXHRcdFx0XHRcdF9zaGFkb3dNYXBTaXplLnggPSBfdmlld3BvcnRTaXplLnggKiBzaGFkb3dGcmFtZUV4dGVudHMueDtcclxuXHRcdFx0XHRcdHNoYWRvdy5tYXBTaXplLnggPSBfdmlld3BvcnRTaXplLng7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0aWYgKCBfc2hhZG93TWFwU2l6ZS55ID4gX21heFRleHR1cmVTaXplICkge1xyXG5cclxuXHRcdFx0XHRcdF92aWV3cG9ydFNpemUueSA9IE1hdGguZmxvb3IoIF9tYXhUZXh0dXJlU2l6ZSAvIHNoYWRvd0ZyYW1lRXh0ZW50cy55ICk7XHJcblx0XHRcdFx0XHRfc2hhZG93TWFwU2l6ZS55ID0gX3ZpZXdwb3J0U2l6ZS55ICogc2hhZG93RnJhbWVFeHRlbnRzLnk7XHJcblx0XHRcdFx0XHRzaGFkb3cubWFwU2l6ZS55ID0gX3ZpZXdwb3J0U2l6ZS55O1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRpZiAoIHNoYWRvdy5tYXAgPT09IG51bGwgfHwgdG9WU00gPT09IHRydWUgfHwgZnJvbVZTTSA9PT0gdHJ1ZSApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgcGFycyA9ICggdGhpcy50eXBlICE9PSBWU01TaGFkb3dNYXAgKSA/IHsgbWluRmlsdGVyOiBOZWFyZXN0RmlsdGVyLCBtYWdGaWx0ZXI6IE5lYXJlc3RGaWx0ZXIgfSA6IHt9O1xyXG5cclxuXHRcdFx0XHRpZiAoIHNoYWRvdy5tYXAgIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdFx0c2hhZG93Lm1hcC5kaXNwb3NlKCk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0c2hhZG93Lm1hcCA9IG5ldyBXZWJHTFJlbmRlclRhcmdldCggX3NoYWRvd01hcFNpemUueCwgX3NoYWRvd01hcFNpemUueSwgcGFycyApO1xyXG5cdFx0XHRcdHNoYWRvdy5tYXAudGV4dHVyZS5uYW1lID0gbGlnaHQubmFtZSArICcuc2hhZG93TWFwJztcclxuXHJcblx0XHRcdFx0c2hhZG93LmNhbWVyYS51cGRhdGVQcm9qZWN0aW9uTWF0cml4KCk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRfcmVuZGVyZXIuc2V0UmVuZGVyVGFyZ2V0KCBzaGFkb3cubWFwICk7XHJcblx0XHRcdF9yZW5kZXJlci5jbGVhcigpO1xyXG5cclxuXHRcdFx0Y29uc3Qgdmlld3BvcnRDb3VudCA9IHNoYWRvdy5nZXRWaWV3cG9ydENvdW50KCk7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgdnAgPSAwOyB2cCA8IHZpZXdwb3J0Q291bnQ7IHZwICsrICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCB2aWV3cG9ydCA9IHNoYWRvdy5nZXRWaWV3cG9ydCggdnAgKTtcclxuXHJcblx0XHRcdFx0X3ZpZXdwb3J0LnNldChcclxuXHRcdFx0XHRcdF92aWV3cG9ydFNpemUueCAqIHZpZXdwb3J0LngsXHJcblx0XHRcdFx0XHRfdmlld3BvcnRTaXplLnkgKiB2aWV3cG9ydC55LFxyXG5cdFx0XHRcdFx0X3ZpZXdwb3J0U2l6ZS54ICogdmlld3BvcnQueixcclxuXHRcdFx0XHRcdF92aWV3cG9ydFNpemUueSAqIHZpZXdwb3J0LndcclxuXHRcdFx0XHQpO1xyXG5cclxuXHRcdFx0XHRfc3RhdGUudmlld3BvcnQoIF92aWV3cG9ydCApO1xyXG5cclxuXHRcdFx0XHRzaGFkb3cudXBkYXRlTWF0cmljZXMoIGxpZ2h0LCB2cCApO1xyXG5cclxuXHRcdFx0XHRfZnJ1c3R1bSA9IHNoYWRvdy5nZXRGcnVzdHVtKCk7XHJcblxyXG5cdFx0XHRcdHJlbmRlck9iamVjdCggc2NlbmUsIGNhbWVyYSwgc2hhZG93LmNhbWVyYSwgbGlnaHQsIHRoaXMudHlwZSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Ly8gZG8gYmx1ciBwYXNzIGZvciBWU01cclxuXHJcblx0XHRcdGlmICggc2hhZG93LmlzUG9pbnRMaWdodFNoYWRvdyAhPT0gdHJ1ZSAmJiB0aGlzLnR5cGUgPT09IFZTTVNoYWRvd01hcCApIHtcclxuXHJcblx0XHRcdFx0VlNNUGFzcyggc2hhZG93LCBjYW1lcmEgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHNoYWRvdy5uZWVkc1VwZGF0ZSA9IGZhbHNlO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRfcHJldmlvdXNUeXBlID0gdGhpcy50eXBlO1xyXG5cclxuXHRcdHNjb3BlLm5lZWRzVXBkYXRlID0gZmFsc2U7XHJcblxyXG5cdFx0X3JlbmRlcmVyLnNldFJlbmRlclRhcmdldCggY3VycmVudFJlbmRlclRhcmdldCwgYWN0aXZlQ3ViZUZhY2UsIGFjdGl2ZU1pcG1hcExldmVsICk7XHJcblxyXG5cdH07XHJcblxyXG5cdGZ1bmN0aW9uIFZTTVBhc3MoIHNoYWRvdywgY2FtZXJhICkge1xyXG5cclxuXHRcdGNvbnN0IGdlb21ldHJ5ID0gX29iamVjdHMudXBkYXRlKCBmdWxsU2NyZWVuTWVzaCApO1xyXG5cclxuXHRcdGlmICggc2hhZG93TWF0ZXJpYWxWZXJ0aWNhbC5kZWZpbmVzLlZTTV9TQU1QTEVTICE9PSBzaGFkb3cuYmx1clNhbXBsZXMgKSB7XHJcblxyXG5cdFx0XHRzaGFkb3dNYXRlcmlhbFZlcnRpY2FsLmRlZmluZXMuVlNNX1NBTVBMRVMgPSBzaGFkb3cuYmx1clNhbXBsZXM7XHJcblx0XHRcdHNoYWRvd01hdGVyaWFsSG9yaXpvbnRhbC5kZWZpbmVzLlZTTV9TQU1QTEVTID0gc2hhZG93LmJsdXJTYW1wbGVzO1xyXG5cclxuXHRcdFx0c2hhZG93TWF0ZXJpYWxWZXJ0aWNhbC5uZWVkc1VwZGF0ZSA9IHRydWU7XHJcblx0XHRcdHNoYWRvd01hdGVyaWFsSG9yaXpvbnRhbC5uZWVkc1VwZGF0ZSA9IHRydWU7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggc2hhZG93Lm1hcFBhc3MgPT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRzaGFkb3cubWFwUGFzcyA9IG5ldyBXZWJHTFJlbmRlclRhcmdldCggX3NoYWRvd01hcFNpemUueCwgX3NoYWRvd01hcFNpemUueSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvLyB2ZXJ0aWNhbCBwYXNzXHJcblxyXG5cdFx0c2hhZG93TWF0ZXJpYWxWZXJ0aWNhbC51bmlmb3Jtcy5zaGFkb3dfcGFzcy52YWx1ZSA9IHNoYWRvdy5tYXAudGV4dHVyZTtcclxuXHRcdHNoYWRvd01hdGVyaWFsVmVydGljYWwudW5pZm9ybXMucmVzb2x1dGlvbi52YWx1ZSA9IHNoYWRvdy5tYXBTaXplO1xyXG5cdFx0c2hhZG93TWF0ZXJpYWxWZXJ0aWNhbC51bmlmb3Jtcy5yYWRpdXMudmFsdWUgPSBzaGFkb3cucmFkaXVzO1xyXG5cdFx0X3JlbmRlcmVyLnNldFJlbmRlclRhcmdldCggc2hhZG93Lm1hcFBhc3MgKTtcclxuXHRcdF9yZW5kZXJlci5jbGVhcigpO1xyXG5cdFx0X3JlbmRlcmVyLnJlbmRlckJ1ZmZlckRpcmVjdCggY2FtZXJhLCBudWxsLCBnZW9tZXRyeSwgc2hhZG93TWF0ZXJpYWxWZXJ0aWNhbCwgZnVsbFNjcmVlbk1lc2gsIG51bGwgKTtcclxuXHJcblx0XHQvLyBob3Jpem9udGFsIHBhc3NcclxuXHJcblx0XHRzaGFkb3dNYXRlcmlhbEhvcml6b250YWwudW5pZm9ybXMuc2hhZG93X3Bhc3MudmFsdWUgPSBzaGFkb3cubWFwUGFzcy50ZXh0dXJlO1xyXG5cdFx0c2hhZG93TWF0ZXJpYWxIb3Jpem9udGFsLnVuaWZvcm1zLnJlc29sdXRpb24udmFsdWUgPSBzaGFkb3cubWFwU2l6ZTtcclxuXHRcdHNoYWRvd01hdGVyaWFsSG9yaXpvbnRhbC51bmlmb3Jtcy5yYWRpdXMudmFsdWUgPSBzaGFkb3cucmFkaXVzO1xyXG5cdFx0X3JlbmRlcmVyLnNldFJlbmRlclRhcmdldCggc2hhZG93Lm1hcCApO1xyXG5cdFx0X3JlbmRlcmVyLmNsZWFyKCk7XHJcblx0XHRfcmVuZGVyZXIucmVuZGVyQnVmZmVyRGlyZWN0KCBjYW1lcmEsIG51bGwsIGdlb21ldHJ5LCBzaGFkb3dNYXRlcmlhbEhvcml6b250YWwsIGZ1bGxTY3JlZW5NZXNoLCBudWxsICk7XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gZ2V0RGVwdGhNYXRlcmlhbCggb2JqZWN0LCBtYXRlcmlhbCwgbGlnaHQsIHR5cGUgKSB7XHJcblxyXG5cdFx0bGV0IHJlc3VsdCA9IG51bGw7XHJcblxyXG5cdFx0Y29uc3QgY3VzdG9tTWF0ZXJpYWwgPSAoIGxpZ2h0LmlzUG9pbnRMaWdodCA9PT0gdHJ1ZSApID8gb2JqZWN0LmN1c3RvbURpc3RhbmNlTWF0ZXJpYWwgOiBvYmplY3QuY3VzdG9tRGVwdGhNYXRlcmlhbDtcclxuXHJcblx0XHRpZiAoIGN1c3RvbU1hdGVyaWFsICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRyZXN1bHQgPSBjdXN0b21NYXRlcmlhbDtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0cmVzdWx0ID0gKCBsaWdodC5pc1BvaW50TGlnaHQgPT09IHRydWUgKSA/IF9kaXN0YW5jZU1hdGVyaWFsIDogX2RlcHRoTWF0ZXJpYWw7XHJcblxyXG5cdFx0XHRpZiAoICggX3JlbmRlcmVyLmxvY2FsQ2xpcHBpbmdFbmFibGVkICYmIG1hdGVyaWFsLmNsaXBTaGFkb3dzID09PSB0cnVlICYmIEFycmF5LmlzQXJyYXkoIG1hdGVyaWFsLmNsaXBwaW5nUGxhbmVzICkgJiYgbWF0ZXJpYWwuY2xpcHBpbmdQbGFuZXMubGVuZ3RoICE9PSAwICkgfHxcclxuXHRcdFx0XHQoIG1hdGVyaWFsLmRpc3BsYWNlbWVudE1hcCAmJiBtYXRlcmlhbC5kaXNwbGFjZW1lbnRTY2FsZSAhPT0gMCApIHx8XHJcblx0XHRcdFx0KCBtYXRlcmlhbC5hbHBoYU1hcCAmJiBtYXRlcmlhbC5hbHBoYVRlc3QgPiAwICkgfHxcclxuXHRcdFx0XHQoIG1hdGVyaWFsLm1hcCAmJiBtYXRlcmlhbC5hbHBoYVRlc3QgPiAwICkgKSB7XHJcblxyXG5cdFx0XHRcdC8vIGluIHRoaXMgY2FzZSB3ZSBuZWVkIGEgdW5pcXVlIG1hdGVyaWFsIGluc3RhbmNlIHJlZmxlY3RpbmcgdGhlXHJcblx0XHRcdFx0Ly8gYXBwcm9wcmlhdGUgc3RhdGVcclxuXHJcblx0XHRcdFx0Y29uc3Qga2V5QSA9IHJlc3VsdC51dWlkLCBrZXlCID0gbWF0ZXJpYWwudXVpZDtcclxuXHJcblx0XHRcdFx0bGV0IG1hdGVyaWFsc0ZvclZhcmlhbnQgPSBfbWF0ZXJpYWxDYWNoZVsga2V5QSBdO1xyXG5cclxuXHRcdFx0XHRpZiAoIG1hdGVyaWFsc0ZvclZhcmlhbnQgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0XHRtYXRlcmlhbHNGb3JWYXJpYW50ID0ge307XHJcblx0XHRcdFx0XHRfbWF0ZXJpYWxDYWNoZVsga2V5QSBdID0gbWF0ZXJpYWxzRm9yVmFyaWFudDtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRsZXQgY2FjaGVkTWF0ZXJpYWwgPSBtYXRlcmlhbHNGb3JWYXJpYW50WyBrZXlCIF07XHJcblxyXG5cdFx0XHRcdGlmICggY2FjaGVkTWF0ZXJpYWwgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0XHRjYWNoZWRNYXRlcmlhbCA9IHJlc3VsdC5jbG9uZSgpO1xyXG5cdFx0XHRcdFx0bWF0ZXJpYWxzRm9yVmFyaWFudFsga2V5QiBdID0gY2FjaGVkTWF0ZXJpYWw7XHJcblx0XHRcdFx0XHRtYXRlcmlhbC5hZGRFdmVudExpc3RlbmVyKCAnZGlzcG9zZScsIG9uTWF0ZXJpYWxEaXNwb3NlICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0cmVzdWx0ID0gY2FjaGVkTWF0ZXJpYWw7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJlc3VsdC52aXNpYmxlID0gbWF0ZXJpYWwudmlzaWJsZTtcclxuXHRcdHJlc3VsdC53aXJlZnJhbWUgPSBtYXRlcmlhbC53aXJlZnJhbWU7XHJcblxyXG5cdFx0aWYgKCB0eXBlID09PSBWU01TaGFkb3dNYXAgKSB7XHJcblxyXG5cdFx0XHRyZXN1bHQuc2lkZSA9ICggbWF0ZXJpYWwuc2hhZG93U2lkZSAhPT0gbnVsbCApID8gbWF0ZXJpYWwuc2hhZG93U2lkZSA6IG1hdGVyaWFsLnNpZGU7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdHJlc3VsdC5zaWRlID0gKCBtYXRlcmlhbC5zaGFkb3dTaWRlICE9PSBudWxsICkgPyBtYXRlcmlhbC5zaGFkb3dTaWRlIDogc2hhZG93U2lkZVsgbWF0ZXJpYWwuc2lkZSBdO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXN1bHQuYWxwaGFNYXAgPSBtYXRlcmlhbC5hbHBoYU1hcDtcclxuXHRcdHJlc3VsdC5hbHBoYVRlc3QgPSBtYXRlcmlhbC5hbHBoYVRlc3Q7XHJcblx0XHRyZXN1bHQubWFwID0gbWF0ZXJpYWwubWFwO1xyXG5cclxuXHRcdHJlc3VsdC5jbGlwU2hhZG93cyA9IG1hdGVyaWFsLmNsaXBTaGFkb3dzO1xyXG5cdFx0cmVzdWx0LmNsaXBwaW5nUGxhbmVzID0gbWF0ZXJpYWwuY2xpcHBpbmdQbGFuZXM7XHJcblx0XHRyZXN1bHQuY2xpcEludGVyc2VjdGlvbiA9IG1hdGVyaWFsLmNsaXBJbnRlcnNlY3Rpb247XHJcblxyXG5cdFx0cmVzdWx0LmRpc3BsYWNlbWVudE1hcCA9IG1hdGVyaWFsLmRpc3BsYWNlbWVudE1hcDtcclxuXHRcdHJlc3VsdC5kaXNwbGFjZW1lbnRTY2FsZSA9IG1hdGVyaWFsLmRpc3BsYWNlbWVudFNjYWxlO1xyXG5cdFx0cmVzdWx0LmRpc3BsYWNlbWVudEJpYXMgPSBtYXRlcmlhbC5kaXNwbGFjZW1lbnRCaWFzO1xyXG5cclxuXHRcdHJlc3VsdC53aXJlZnJhbWVMaW5ld2lkdGggPSBtYXRlcmlhbC53aXJlZnJhbWVMaW5ld2lkdGg7XHJcblx0XHRyZXN1bHQubGluZXdpZHRoID0gbWF0ZXJpYWwubGluZXdpZHRoO1xyXG5cclxuXHRcdGlmICggbGlnaHQuaXNQb2ludExpZ2h0ID09PSB0cnVlICYmIHJlc3VsdC5pc01lc2hEaXN0YW5jZU1hdGVyaWFsID09PSB0cnVlICkge1xyXG5cclxuXHRcdFx0Y29uc3QgbWF0ZXJpYWxQcm9wZXJ0aWVzID0gX3JlbmRlcmVyLnByb3BlcnRpZXMuZ2V0KCByZXN1bHQgKTtcclxuXHRcdFx0bWF0ZXJpYWxQcm9wZXJ0aWVzLmxpZ2h0ID0gbGlnaHQ7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiByZXN1bHQ7XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gcmVuZGVyT2JqZWN0KCBvYmplY3QsIGNhbWVyYSwgc2hhZG93Q2FtZXJhLCBsaWdodCwgdHlwZSApIHtcclxuXHJcblx0XHRpZiAoIG9iamVjdC52aXNpYmxlID09PSBmYWxzZSApIHJldHVybjtcclxuXHJcblx0XHRjb25zdCB2aXNpYmxlID0gb2JqZWN0LmxheWVycy50ZXN0KCBjYW1lcmEubGF5ZXJzICk7XHJcblxyXG5cdFx0aWYgKCB2aXNpYmxlICYmICggb2JqZWN0LmlzTWVzaCB8fCBvYmplY3QuaXNMaW5lIHx8IG9iamVjdC5pc1BvaW50cyApICkge1xyXG5cclxuXHRcdFx0aWYgKCAoIG9iamVjdC5jYXN0U2hhZG93IHx8ICggb2JqZWN0LnJlY2VpdmVTaGFkb3cgJiYgdHlwZSA9PT0gVlNNU2hhZG93TWFwICkgKSAmJiAoICEgb2JqZWN0LmZydXN0dW1DdWxsZWQgfHwgX2ZydXN0dW0uaW50ZXJzZWN0c09iamVjdCggb2JqZWN0ICkgKSApIHtcclxuXHJcblx0XHRcdFx0b2JqZWN0Lm1vZGVsVmlld01hdHJpeC5tdWx0aXBseU1hdHJpY2VzKCBzaGFkb3dDYW1lcmEubWF0cml4V29ybGRJbnZlcnNlLCBvYmplY3QubWF0cml4V29ybGQgKTtcclxuXHJcblx0XHRcdFx0Y29uc3QgZ2VvbWV0cnkgPSBfb2JqZWN0cy51cGRhdGUoIG9iamVjdCApO1xyXG5cdFx0XHRcdGNvbnN0IG1hdGVyaWFsID0gb2JqZWN0Lm1hdGVyaWFsO1xyXG5cclxuXHRcdFx0XHRpZiAoIEFycmF5LmlzQXJyYXkoIG1hdGVyaWFsICkgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgZ3JvdXBzID0gZ2VvbWV0cnkuZ3JvdXBzO1xyXG5cclxuXHRcdFx0XHRcdGZvciAoIGxldCBrID0gMCwga2wgPSBncm91cHMubGVuZ3RoOyBrIDwga2w7IGsgKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRjb25zdCBncm91cCA9IGdyb3Vwc1sgayBdO1xyXG5cdFx0XHRcdFx0XHRjb25zdCBncm91cE1hdGVyaWFsID0gbWF0ZXJpYWxbIGdyb3VwLm1hdGVyaWFsSW5kZXggXTtcclxuXHJcblx0XHRcdFx0XHRcdGlmICggZ3JvdXBNYXRlcmlhbCAmJiBncm91cE1hdGVyaWFsLnZpc2libGUgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdGNvbnN0IGRlcHRoTWF0ZXJpYWwgPSBnZXREZXB0aE1hdGVyaWFsKCBvYmplY3QsIGdyb3VwTWF0ZXJpYWwsIGxpZ2h0LCB0eXBlICk7XHJcblxyXG5cdFx0XHRcdFx0XHRcdG9iamVjdC5vbkJlZm9yZVNoYWRvdyggX3JlbmRlcmVyLCBvYmplY3QsIGNhbWVyYSwgc2hhZG93Q2FtZXJhLCBnZW9tZXRyeSwgZGVwdGhNYXRlcmlhbCwgZ3JvdXAgKTtcclxuXHJcblx0XHRcdFx0XHRcdFx0X3JlbmRlcmVyLnJlbmRlckJ1ZmZlckRpcmVjdCggc2hhZG93Q2FtZXJhLCBudWxsLCBnZW9tZXRyeSwgZGVwdGhNYXRlcmlhbCwgb2JqZWN0LCBncm91cCApO1xyXG5cclxuXHRcdFx0XHRcdFx0XHRvYmplY3Qub25BZnRlclNoYWRvdyggX3JlbmRlcmVyLCBvYmplY3QsIGNhbWVyYSwgc2hhZG93Q2FtZXJhLCBnZW9tZXRyeSwgZGVwdGhNYXRlcmlhbCwgZ3JvdXAgKTtcclxuXHJcblx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH0gZWxzZSBpZiAoIG1hdGVyaWFsLnZpc2libGUgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgZGVwdGhNYXRlcmlhbCA9IGdldERlcHRoTWF0ZXJpYWwoIG9iamVjdCwgbWF0ZXJpYWwsIGxpZ2h0LCB0eXBlICk7XHJcblxyXG5cdFx0XHRcdFx0b2JqZWN0Lm9uQmVmb3JlU2hhZG93KCBfcmVuZGVyZXIsIG9iamVjdCwgY2FtZXJhLCBzaGFkb3dDYW1lcmEsIGdlb21ldHJ5LCBkZXB0aE1hdGVyaWFsLCBudWxsICk7XHJcblxyXG5cdFx0XHRcdFx0X3JlbmRlcmVyLnJlbmRlckJ1ZmZlckRpcmVjdCggc2hhZG93Q2FtZXJhLCBudWxsLCBnZW9tZXRyeSwgZGVwdGhNYXRlcmlhbCwgb2JqZWN0LCBudWxsICk7XHJcblxyXG5cdFx0XHRcdFx0b2JqZWN0Lm9uQWZ0ZXJTaGFkb3coIF9yZW5kZXJlciwgb2JqZWN0LCBjYW1lcmEsIHNoYWRvd0NhbWVyYSwgZ2VvbWV0cnksIGRlcHRoTWF0ZXJpYWwsIG51bGwgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCBjaGlsZHJlbiA9IG9iamVjdC5jaGlsZHJlbjtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBjaGlsZHJlbi5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0cmVuZGVyT2JqZWN0KCBjaGlsZHJlblsgaSBdLCBjYW1lcmEsIHNoYWRvd0NhbWVyYSwgbGlnaHQsIHR5cGUgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gb25NYXRlcmlhbERpc3Bvc2UoIGV2ZW50ICkge1xyXG5cclxuXHRcdGNvbnN0IG1hdGVyaWFsID0gZXZlbnQudGFyZ2V0O1xyXG5cclxuXHRcdG1hdGVyaWFsLnJlbW92ZUV2ZW50TGlzdGVuZXIoICdkaXNwb3NlJywgb25NYXRlcmlhbERpc3Bvc2UgKTtcclxuXHJcblx0XHQvLyBtYWtlIHN1cmUgdG8gcmVtb3ZlIHRoZSB1bmlxdWUgZGlzdGFuY2UvZGVwdGggbWF0ZXJpYWxzIHVzZWQgZm9yIHNoYWRvdyBtYXAgcmVuZGVyaW5nXHJcblxyXG5cdFx0Zm9yICggY29uc3QgaWQgaW4gX21hdGVyaWFsQ2FjaGUgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBjYWNoZSA9IF9tYXRlcmlhbENhY2hlWyBpZCBdO1xyXG5cclxuXHRcdFx0Y29uc3QgdXVpZCA9IGV2ZW50LnRhcmdldC51dWlkO1xyXG5cclxuXHRcdFx0aWYgKCB1dWlkIGluIGNhY2hlICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBzaGFkb3dNYXRlcmlhbCA9IGNhY2hlWyB1dWlkIF07XHJcblx0XHRcdFx0c2hhZG93TWF0ZXJpYWwuZGlzcG9zZSgpO1xyXG5cdFx0XHRcdGRlbGV0ZSBjYWNoZVsgdXVpZCBdO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuXHJcbmV4cG9ydCB7IFdlYkdMU2hhZG93TWFwIH07XHJcbiIsImltcG9ydCB7IE5vdEVxdWFsRGVwdGgsIEdyZWF0ZXJEZXB0aCwgR3JlYXRlckVxdWFsRGVwdGgsIEVxdWFsRGVwdGgsIExlc3NFcXVhbERlcHRoLCBMZXNzRGVwdGgsIEFsd2F5c0RlcHRoLCBOZXZlckRlcHRoLCBDdWxsRmFjZUZyb250LCBDdWxsRmFjZUJhY2ssIEN1bGxGYWNlTm9uZSwgRG91YmxlU2lkZSwgQmFja1NpZGUsIEN1c3RvbUJsZW5kaW5nLCBNdWx0aXBseUJsZW5kaW5nLCBTdWJ0cmFjdGl2ZUJsZW5kaW5nLCBBZGRpdGl2ZUJsZW5kaW5nLCBOb0JsZW5kaW5nLCBOb3JtYWxCbGVuZGluZywgQWRkRXF1YXRpb24sIFN1YnRyYWN0RXF1YXRpb24sIFJldmVyc2VTdWJ0cmFjdEVxdWF0aW9uLCBNaW5FcXVhdGlvbiwgTWF4RXF1YXRpb24sIFplcm9GYWN0b3IsIE9uZUZhY3RvciwgU3JjQ29sb3JGYWN0b3IsIFNyY0FscGhhRmFjdG9yLCBTcmNBbHBoYVNhdHVyYXRlRmFjdG9yLCBEc3RDb2xvckZhY3RvciwgRHN0QWxwaGFGYWN0b3IsIE9uZU1pbnVzU3JjQ29sb3JGYWN0b3IsIE9uZU1pbnVzU3JjQWxwaGFGYWN0b3IsIE9uZU1pbnVzRHN0Q29sb3JGYWN0b3IsIE9uZU1pbnVzRHN0QWxwaGFGYWN0b3IsIENvbnN0YW50Q29sb3JGYWN0b3IsIE9uZU1pbnVzQ29uc3RhbnRDb2xvckZhY3RvciwgQ29uc3RhbnRBbHBoYUZhY3RvciwgT25lTWludXNDb25zdGFudEFscGhhRmFjdG9yIH0gZnJvbSAnLi4vLi4vY29uc3RhbnRzLmpzJztcclxuaW1wb3J0IHsgQ29sb3IgfSBmcm9tICcuLi8uLi9tYXRoL0NvbG9yLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yNCB9IGZyb20gJy4uLy4uL21hdGgvVmVjdG9yNC5qcyc7XHJcblxyXG5mdW5jdGlvbiBXZWJHTFN0YXRlKCBnbCwgZXh0ZW5zaW9ucywgY2FwYWJpbGl0aWVzICkge1xyXG5cclxuXHRjb25zdCBpc1dlYkdMMiA9IGNhcGFiaWxpdGllcy5pc1dlYkdMMjtcclxuXHJcblx0ZnVuY3Rpb24gQ29sb3JCdWZmZXIoKSB7XHJcblxyXG5cdFx0bGV0IGxvY2tlZCA9IGZhbHNlO1xyXG5cclxuXHRcdGNvbnN0IGNvbG9yID0gbmV3IFZlY3RvcjQoKTtcclxuXHRcdGxldCBjdXJyZW50Q29sb3JNYXNrID0gbnVsbDtcclxuXHRcdGNvbnN0IGN1cnJlbnRDb2xvckNsZWFyID0gbmV3IFZlY3RvcjQoIDAsIDAsIDAsIDAgKTtcclxuXHJcblx0XHRyZXR1cm4ge1xyXG5cclxuXHRcdFx0c2V0TWFzazogZnVuY3Rpb24gKCBjb2xvck1hc2sgKSB7XHJcblxyXG5cdFx0XHRcdGlmICggY3VycmVudENvbG9yTWFzayAhPT0gY29sb3JNYXNrICYmICEgbG9ja2VkICkge1xyXG5cclxuXHRcdFx0XHRcdGdsLmNvbG9yTWFzayggY29sb3JNYXNrLCBjb2xvck1hc2ssIGNvbG9yTWFzaywgY29sb3JNYXNrICk7XHJcblx0XHRcdFx0XHRjdXJyZW50Q29sb3JNYXNrID0gY29sb3JNYXNrO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9LFxyXG5cclxuXHRcdFx0c2V0TG9ja2VkOiBmdW5jdGlvbiAoIGxvY2sgKSB7XHJcblxyXG5cdFx0XHRcdGxvY2tlZCA9IGxvY2s7XHJcblxyXG5cdFx0XHR9LFxyXG5cclxuXHRcdFx0c2V0Q2xlYXI6IGZ1bmN0aW9uICggciwgZywgYiwgYSwgcHJlbXVsdGlwbGllZEFscGhhICkge1xyXG5cclxuXHRcdFx0XHRpZiAoIHByZW11bHRpcGxpZWRBbHBoYSA9PT0gdHJ1ZSApIHtcclxuXHJcblx0XHRcdFx0XHRyICo9IGE7IGcgKj0gYTsgYiAqPSBhO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdGNvbG9yLnNldCggciwgZywgYiwgYSApO1xyXG5cclxuXHRcdFx0XHRpZiAoIGN1cnJlbnRDb2xvckNsZWFyLmVxdWFscyggY29sb3IgKSA9PT0gZmFsc2UgKSB7XHJcblxyXG5cdFx0XHRcdFx0Z2wuY2xlYXJDb2xvciggciwgZywgYiwgYSApO1xyXG5cdFx0XHRcdFx0Y3VycmVudENvbG9yQ2xlYXIuY29weSggY29sb3IgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fSxcclxuXHJcblx0XHRcdHJlc2V0OiBmdW5jdGlvbiAoKSB7XHJcblxyXG5cdFx0XHRcdGxvY2tlZCA9IGZhbHNlO1xyXG5cclxuXHRcdFx0XHRjdXJyZW50Q29sb3JNYXNrID0gbnVsbDtcclxuXHRcdFx0XHRjdXJyZW50Q29sb3JDbGVhci5zZXQoIC0gMSwgMCwgMCwgMCApOyAvLyBzZXQgdG8gaW52YWxpZCBzdGF0ZVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH07XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gRGVwdGhCdWZmZXIoKSB7XHJcblxyXG5cdFx0bGV0IGxvY2tlZCA9IGZhbHNlO1xyXG5cclxuXHRcdGxldCBjdXJyZW50RGVwdGhNYXNrID0gbnVsbDtcclxuXHRcdGxldCBjdXJyZW50RGVwdGhGdW5jID0gbnVsbDtcclxuXHRcdGxldCBjdXJyZW50RGVwdGhDbGVhciA9IG51bGw7XHJcblxyXG5cdFx0cmV0dXJuIHtcclxuXHJcblx0XHRcdHNldFRlc3Q6IGZ1bmN0aW9uICggZGVwdGhUZXN0ICkge1xyXG5cclxuXHRcdFx0XHRpZiAoIGRlcHRoVGVzdCApIHtcclxuXHJcblx0XHRcdFx0XHRlbmFibGUoIGdsLkRFUFRIX1RFU1QgKTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRkaXNhYmxlKCBnbC5ERVBUSF9URVNUICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH0sXHJcblxyXG5cdFx0XHRzZXRNYXNrOiBmdW5jdGlvbiAoIGRlcHRoTWFzayApIHtcclxuXHJcblx0XHRcdFx0aWYgKCBjdXJyZW50RGVwdGhNYXNrICE9PSBkZXB0aE1hc2sgJiYgISBsb2NrZWQgKSB7XHJcblxyXG5cdFx0XHRcdFx0Z2wuZGVwdGhNYXNrKCBkZXB0aE1hc2sgKTtcclxuXHRcdFx0XHRcdGN1cnJlbnREZXB0aE1hc2sgPSBkZXB0aE1hc2s7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH0sXHJcblxyXG5cdFx0XHRzZXRGdW5jOiBmdW5jdGlvbiAoIGRlcHRoRnVuYyApIHtcclxuXHJcblx0XHRcdFx0aWYgKCBjdXJyZW50RGVwdGhGdW5jICE9PSBkZXB0aEZ1bmMgKSB7XHJcblxyXG5cdFx0XHRcdFx0c3dpdGNoICggZGVwdGhGdW5jICkge1xyXG5cclxuXHRcdFx0XHRcdFx0Y2FzZSBOZXZlckRlcHRoOlxyXG5cclxuXHRcdFx0XHRcdFx0XHRnbC5kZXB0aEZ1bmMoIGdsLk5FVkVSICk7XHJcblx0XHRcdFx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRcdFx0XHRjYXNlIEFsd2F5c0RlcHRoOlxyXG5cclxuXHRcdFx0XHRcdFx0XHRnbC5kZXB0aEZ1bmMoIGdsLkFMV0FZUyApO1xyXG5cdFx0XHRcdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0XHRcdFx0Y2FzZSBMZXNzRGVwdGg6XHJcblxyXG5cdFx0XHRcdFx0XHRcdGdsLmRlcHRoRnVuYyggZ2wuTEVTUyApO1xyXG5cdFx0XHRcdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0XHRcdFx0Y2FzZSBMZXNzRXF1YWxEZXB0aDpcclxuXHJcblx0XHRcdFx0XHRcdFx0Z2wuZGVwdGhGdW5jKCBnbC5MRVFVQUwgKTtcclxuXHRcdFx0XHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdFx0XHRcdGNhc2UgRXF1YWxEZXB0aDpcclxuXHJcblx0XHRcdFx0XHRcdFx0Z2wuZGVwdGhGdW5jKCBnbC5FUVVBTCApO1xyXG5cdFx0XHRcdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0XHRcdFx0Y2FzZSBHcmVhdGVyRXF1YWxEZXB0aDpcclxuXHJcblx0XHRcdFx0XHRcdFx0Z2wuZGVwdGhGdW5jKCBnbC5HRVFVQUwgKTtcclxuXHRcdFx0XHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdFx0XHRcdGNhc2UgR3JlYXRlckRlcHRoOlxyXG5cclxuXHRcdFx0XHRcdFx0XHRnbC5kZXB0aEZ1bmMoIGdsLkdSRUFURVIgKTtcclxuXHRcdFx0XHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdFx0XHRcdGNhc2UgTm90RXF1YWxEZXB0aDpcclxuXHJcblx0XHRcdFx0XHRcdFx0Z2wuZGVwdGhGdW5jKCBnbC5OT1RFUVVBTCApO1xyXG5cdFx0XHRcdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0XHRcdFx0ZGVmYXVsdDpcclxuXHJcblx0XHRcdFx0XHRcdFx0Z2wuZGVwdGhGdW5jKCBnbC5MRVFVQUwgKTtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0Y3VycmVudERlcHRoRnVuYyA9IGRlcHRoRnVuYztcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fSxcclxuXHJcblx0XHRcdHNldExvY2tlZDogZnVuY3Rpb24gKCBsb2NrICkge1xyXG5cclxuXHRcdFx0XHRsb2NrZWQgPSBsb2NrO1xyXG5cclxuXHRcdFx0fSxcclxuXHJcblx0XHRcdHNldENsZWFyOiBmdW5jdGlvbiAoIGRlcHRoICkge1xyXG5cclxuXHRcdFx0XHRpZiAoIGN1cnJlbnREZXB0aENsZWFyICE9PSBkZXB0aCApIHtcclxuXHJcblx0XHRcdFx0XHRnbC5jbGVhckRlcHRoKCBkZXB0aCApO1xyXG5cdFx0XHRcdFx0Y3VycmVudERlcHRoQ2xlYXIgPSBkZXB0aDtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fSxcclxuXHJcblx0XHRcdHJlc2V0OiBmdW5jdGlvbiAoKSB7XHJcblxyXG5cdFx0XHRcdGxvY2tlZCA9IGZhbHNlO1xyXG5cclxuXHRcdFx0XHRjdXJyZW50RGVwdGhNYXNrID0gbnVsbDtcclxuXHRcdFx0XHRjdXJyZW50RGVwdGhGdW5jID0gbnVsbDtcclxuXHRcdFx0XHRjdXJyZW50RGVwdGhDbGVhciA9IG51bGw7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fTtcclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBTdGVuY2lsQnVmZmVyKCkge1xyXG5cclxuXHRcdGxldCBsb2NrZWQgPSBmYWxzZTtcclxuXHJcblx0XHRsZXQgY3VycmVudFN0ZW5jaWxNYXNrID0gbnVsbDtcclxuXHRcdGxldCBjdXJyZW50U3RlbmNpbEZ1bmMgPSBudWxsO1xyXG5cdFx0bGV0IGN1cnJlbnRTdGVuY2lsUmVmID0gbnVsbDtcclxuXHRcdGxldCBjdXJyZW50U3RlbmNpbEZ1bmNNYXNrID0gbnVsbDtcclxuXHRcdGxldCBjdXJyZW50U3RlbmNpbEZhaWwgPSBudWxsO1xyXG5cdFx0bGV0IGN1cnJlbnRTdGVuY2lsWkZhaWwgPSBudWxsO1xyXG5cdFx0bGV0IGN1cnJlbnRTdGVuY2lsWlBhc3MgPSBudWxsO1xyXG5cdFx0bGV0IGN1cnJlbnRTdGVuY2lsQ2xlYXIgPSBudWxsO1xyXG5cclxuXHRcdHJldHVybiB7XHJcblxyXG5cdFx0XHRzZXRUZXN0OiBmdW5jdGlvbiAoIHN0ZW5jaWxUZXN0ICkge1xyXG5cclxuXHRcdFx0XHRpZiAoICEgbG9ja2VkICkge1xyXG5cclxuXHRcdFx0XHRcdGlmICggc3RlbmNpbFRlc3QgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRlbmFibGUoIGdsLlNURU5DSUxfVEVTVCApO1xyXG5cclxuXHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHRkaXNhYmxlKCBnbC5TVEVOQ0lMX1RFU1QgKTtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH0sXHJcblxyXG5cdFx0XHRzZXRNYXNrOiBmdW5jdGlvbiAoIHN0ZW5jaWxNYXNrICkge1xyXG5cclxuXHRcdFx0XHRpZiAoIGN1cnJlbnRTdGVuY2lsTWFzayAhPT0gc3RlbmNpbE1hc2sgJiYgISBsb2NrZWQgKSB7XHJcblxyXG5cdFx0XHRcdFx0Z2wuc3RlbmNpbE1hc2soIHN0ZW5jaWxNYXNrICk7XHJcblx0XHRcdFx0XHRjdXJyZW50U3RlbmNpbE1hc2sgPSBzdGVuY2lsTWFzaztcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fSxcclxuXHJcblx0XHRcdHNldEZ1bmM6IGZ1bmN0aW9uICggc3RlbmNpbEZ1bmMsIHN0ZW5jaWxSZWYsIHN0ZW5jaWxNYXNrICkge1xyXG5cclxuXHRcdFx0XHRpZiAoIGN1cnJlbnRTdGVuY2lsRnVuYyAhPT0gc3RlbmNpbEZ1bmMgfHxcclxuXHRcdFx0XHQgICAgIGN1cnJlbnRTdGVuY2lsUmVmICE9PSBzdGVuY2lsUmVmIHx8XHJcblx0XHRcdFx0ICAgICBjdXJyZW50U3RlbmNpbEZ1bmNNYXNrICE9PSBzdGVuY2lsTWFzayApIHtcclxuXHJcblx0XHRcdFx0XHRnbC5zdGVuY2lsRnVuYyggc3RlbmNpbEZ1bmMsIHN0ZW5jaWxSZWYsIHN0ZW5jaWxNYXNrICk7XHJcblxyXG5cdFx0XHRcdFx0Y3VycmVudFN0ZW5jaWxGdW5jID0gc3RlbmNpbEZ1bmM7XHJcblx0XHRcdFx0XHRjdXJyZW50U3RlbmNpbFJlZiA9IHN0ZW5jaWxSZWY7XHJcblx0XHRcdFx0XHRjdXJyZW50U3RlbmNpbEZ1bmNNYXNrID0gc3RlbmNpbE1hc2s7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH0sXHJcblxyXG5cdFx0XHRzZXRPcDogZnVuY3Rpb24gKCBzdGVuY2lsRmFpbCwgc3RlbmNpbFpGYWlsLCBzdGVuY2lsWlBhc3MgKSB7XHJcblxyXG5cdFx0XHRcdGlmICggY3VycmVudFN0ZW5jaWxGYWlsICE9PSBzdGVuY2lsRmFpbCB8fFxyXG5cdFx0XHRcdCAgICAgY3VycmVudFN0ZW5jaWxaRmFpbCAhPT0gc3RlbmNpbFpGYWlsIHx8XHJcblx0XHRcdFx0ICAgICBjdXJyZW50U3RlbmNpbFpQYXNzICE9PSBzdGVuY2lsWlBhc3MgKSB7XHJcblxyXG5cdFx0XHRcdFx0Z2wuc3RlbmNpbE9wKCBzdGVuY2lsRmFpbCwgc3RlbmNpbFpGYWlsLCBzdGVuY2lsWlBhc3MgKTtcclxuXHJcblx0XHRcdFx0XHRjdXJyZW50U3RlbmNpbEZhaWwgPSBzdGVuY2lsRmFpbDtcclxuXHRcdFx0XHRcdGN1cnJlbnRTdGVuY2lsWkZhaWwgPSBzdGVuY2lsWkZhaWw7XHJcblx0XHRcdFx0XHRjdXJyZW50U3RlbmNpbFpQYXNzID0gc3RlbmNpbFpQYXNzO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9LFxyXG5cclxuXHRcdFx0c2V0TG9ja2VkOiBmdW5jdGlvbiAoIGxvY2sgKSB7XHJcblxyXG5cdFx0XHRcdGxvY2tlZCA9IGxvY2s7XHJcblxyXG5cdFx0XHR9LFxyXG5cclxuXHRcdFx0c2V0Q2xlYXI6IGZ1bmN0aW9uICggc3RlbmNpbCApIHtcclxuXHJcblx0XHRcdFx0aWYgKCBjdXJyZW50U3RlbmNpbENsZWFyICE9PSBzdGVuY2lsICkge1xyXG5cclxuXHRcdFx0XHRcdGdsLmNsZWFyU3RlbmNpbCggc3RlbmNpbCApO1xyXG5cdFx0XHRcdFx0Y3VycmVudFN0ZW5jaWxDbGVhciA9IHN0ZW5jaWw7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH0sXHJcblxyXG5cdFx0XHRyZXNldDogZnVuY3Rpb24gKCkge1xyXG5cclxuXHRcdFx0XHRsb2NrZWQgPSBmYWxzZTtcclxuXHJcblx0XHRcdFx0Y3VycmVudFN0ZW5jaWxNYXNrID0gbnVsbDtcclxuXHRcdFx0XHRjdXJyZW50U3RlbmNpbEZ1bmMgPSBudWxsO1xyXG5cdFx0XHRcdGN1cnJlbnRTdGVuY2lsUmVmID0gbnVsbDtcclxuXHRcdFx0XHRjdXJyZW50U3RlbmNpbEZ1bmNNYXNrID0gbnVsbDtcclxuXHRcdFx0XHRjdXJyZW50U3RlbmNpbEZhaWwgPSBudWxsO1xyXG5cdFx0XHRcdGN1cnJlbnRTdGVuY2lsWkZhaWwgPSBudWxsO1xyXG5cdFx0XHRcdGN1cnJlbnRTdGVuY2lsWlBhc3MgPSBudWxsO1xyXG5cdFx0XHRcdGN1cnJlbnRTdGVuY2lsQ2xlYXIgPSBudWxsO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH07XHJcblxyXG5cdH1cclxuXHJcblx0Ly9cclxuXHJcblx0Y29uc3QgY29sb3JCdWZmZXIgPSBuZXcgQ29sb3JCdWZmZXIoKTtcclxuXHRjb25zdCBkZXB0aEJ1ZmZlciA9IG5ldyBEZXB0aEJ1ZmZlcigpO1xyXG5cdGNvbnN0IHN0ZW5jaWxCdWZmZXIgPSBuZXcgU3RlbmNpbEJ1ZmZlcigpO1xyXG5cclxuXHRjb25zdCB1Ym9CaW5kaW5ncyA9IG5ldyBXZWFrTWFwKCk7XHJcblx0Y29uc3QgdWJvUHJvZ3JhbU1hcCA9IG5ldyBXZWFrTWFwKCk7XHJcblxyXG5cdGxldCBlbmFibGVkQ2FwYWJpbGl0aWVzID0ge307XHJcblxyXG5cdGxldCBjdXJyZW50Qm91bmRGcmFtZWJ1ZmZlcnMgPSB7fTtcclxuXHRsZXQgY3VycmVudERyYXdidWZmZXJzID0gbmV3IFdlYWtNYXAoKTtcclxuXHRsZXQgZGVmYXVsdERyYXdidWZmZXJzID0gW107XHJcblxyXG5cdGxldCBjdXJyZW50UHJvZ3JhbSA9IG51bGw7XHJcblxyXG5cdGxldCBjdXJyZW50QmxlbmRpbmdFbmFibGVkID0gZmFsc2U7XHJcblx0bGV0IGN1cnJlbnRCbGVuZGluZyA9IG51bGw7XHJcblx0bGV0IGN1cnJlbnRCbGVuZEVxdWF0aW9uID0gbnVsbDtcclxuXHRsZXQgY3VycmVudEJsZW5kU3JjID0gbnVsbDtcclxuXHRsZXQgY3VycmVudEJsZW5kRHN0ID0gbnVsbDtcclxuXHRsZXQgY3VycmVudEJsZW5kRXF1YXRpb25BbHBoYSA9IG51bGw7XHJcblx0bGV0IGN1cnJlbnRCbGVuZFNyY0FscGhhID0gbnVsbDtcclxuXHRsZXQgY3VycmVudEJsZW5kRHN0QWxwaGEgPSBudWxsO1xyXG5cdGxldCBjdXJyZW50QmxlbmRDb2xvciA9IG5ldyBDb2xvciggMCwgMCwgMCApO1xyXG5cdGxldCBjdXJyZW50QmxlbmRBbHBoYSA9IDA7XHJcblx0bGV0IGN1cnJlbnRQcmVtdWx0aXBsZWRBbHBoYSA9IGZhbHNlO1xyXG5cclxuXHRsZXQgY3VycmVudEZsaXBTaWRlZCA9IG51bGw7XHJcblx0bGV0IGN1cnJlbnRDdWxsRmFjZSA9IG51bGw7XHJcblxyXG5cdGxldCBjdXJyZW50TGluZVdpZHRoID0gbnVsbDtcclxuXHJcblx0bGV0IGN1cnJlbnRQb2x5Z29uT2Zmc2V0RmFjdG9yID0gbnVsbDtcclxuXHRsZXQgY3VycmVudFBvbHlnb25PZmZzZXRVbml0cyA9IG51bGw7XHJcblxyXG5cdGNvbnN0IG1heFRleHR1cmVzID0gZ2wuZ2V0UGFyYW1ldGVyKCBnbC5NQVhfQ09NQklORURfVEVYVFVSRV9JTUFHRV9VTklUUyApO1xyXG5cclxuXHRsZXQgbGluZVdpZHRoQXZhaWxhYmxlID0gZmFsc2U7XHJcblx0bGV0IHZlcnNpb24gPSAwO1xyXG5cdGNvbnN0IGdsVmVyc2lvbiA9IGdsLmdldFBhcmFtZXRlciggZ2wuVkVSU0lPTiApO1xyXG5cclxuXHRpZiAoIGdsVmVyc2lvbi5pbmRleE9mKCAnV2ViR0wnICkgIT09IC0gMSApIHtcclxuXHJcblx0XHR2ZXJzaW9uID0gcGFyc2VGbG9hdCggL15XZWJHTCAoXFxkKS8uZXhlYyggZ2xWZXJzaW9uIClbIDEgXSApO1xyXG5cdFx0bGluZVdpZHRoQXZhaWxhYmxlID0gKCB2ZXJzaW9uID49IDEuMCApO1xyXG5cclxuXHR9IGVsc2UgaWYgKCBnbFZlcnNpb24uaW5kZXhPZiggJ09wZW5HTCBFUycgKSAhPT0gLSAxICkge1xyXG5cclxuXHRcdHZlcnNpb24gPSBwYXJzZUZsb2F0KCAvXk9wZW5HTCBFUyAoXFxkKS8uZXhlYyggZ2xWZXJzaW9uIClbIDEgXSApO1xyXG5cdFx0bGluZVdpZHRoQXZhaWxhYmxlID0gKCB2ZXJzaW9uID49IDIuMCApO1xyXG5cclxuXHR9XHJcblxyXG5cdGxldCBjdXJyZW50VGV4dHVyZVNsb3QgPSBudWxsO1xyXG5cdGxldCBjdXJyZW50Qm91bmRUZXh0dXJlcyA9IHt9O1xyXG5cclxuXHRjb25zdCBzY2lzc29yUGFyYW0gPSBnbC5nZXRQYXJhbWV0ZXIoIGdsLlNDSVNTT1JfQk9YICk7XHJcblx0Y29uc3Qgdmlld3BvcnRQYXJhbSA9IGdsLmdldFBhcmFtZXRlciggZ2wuVklFV1BPUlQgKTtcclxuXHJcblx0Y29uc3QgY3VycmVudFNjaXNzb3IgPSBuZXcgVmVjdG9yNCgpLmZyb21BcnJheSggc2Npc3NvclBhcmFtICk7XHJcblx0Y29uc3QgY3VycmVudFZpZXdwb3J0ID0gbmV3IFZlY3RvcjQoKS5mcm9tQXJyYXkoIHZpZXdwb3J0UGFyYW0gKTtcclxuXHJcblx0ZnVuY3Rpb24gY3JlYXRlVGV4dHVyZSggdHlwZSwgdGFyZ2V0LCBjb3VudCwgZGltZW5zaW9ucyApIHtcclxuXHJcblx0XHRjb25zdCBkYXRhID0gbmV3IFVpbnQ4QXJyYXkoIDQgKTsgLy8gNCBpcyByZXF1aXJlZCB0byBtYXRjaCBkZWZhdWx0IHVucGFjayBhbGlnbm1lbnQgb2YgNC5cclxuXHRcdGNvbnN0IHRleHR1cmUgPSBnbC5jcmVhdGVUZXh0dXJlKCk7XHJcblxyXG5cdFx0Z2wuYmluZFRleHR1cmUoIHR5cGUsIHRleHR1cmUgKTtcclxuXHRcdGdsLnRleFBhcmFtZXRlcmkoIHR5cGUsIGdsLlRFWFRVUkVfTUlOX0ZJTFRFUiwgZ2wuTkVBUkVTVCApO1xyXG5cdFx0Z2wudGV4UGFyYW1ldGVyaSggdHlwZSwgZ2wuVEVYVFVSRV9NQUdfRklMVEVSLCBnbC5ORUFSRVNUICk7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgY291bnQ7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRpZiAoIGlzV2ViR0wyICYmICggdHlwZSA9PT0gZ2wuVEVYVFVSRV8zRCB8fCB0eXBlID09PSBnbC5URVhUVVJFXzJEX0FSUkFZICkgKSB7XHJcblxyXG5cdFx0XHRcdGdsLnRleEltYWdlM0QoIHRhcmdldCwgMCwgZ2wuUkdCQSwgMSwgMSwgZGltZW5zaW9ucywgMCwgZ2wuUkdCQSwgZ2wuVU5TSUdORURfQllURSwgZGF0YSApO1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0Z2wudGV4SW1hZ2UyRCggdGFyZ2V0ICsgaSwgMCwgZ2wuUkdCQSwgMSwgMSwgMCwgZ2wuUkdCQSwgZ2wuVU5TSUdORURfQllURSwgZGF0YSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGV4dHVyZTtcclxuXHJcblx0fVxyXG5cclxuXHRjb25zdCBlbXB0eVRleHR1cmVzID0ge307XHJcblx0ZW1wdHlUZXh0dXJlc1sgZ2wuVEVYVFVSRV8yRCBdID0gY3JlYXRlVGV4dHVyZSggZ2wuVEVYVFVSRV8yRCwgZ2wuVEVYVFVSRV8yRCwgMSApO1xyXG5cdGVtcHR5VGV4dHVyZXNbIGdsLlRFWFRVUkVfQ1VCRV9NQVAgXSA9IGNyZWF0ZVRleHR1cmUoIGdsLlRFWFRVUkVfQ1VCRV9NQVAsIGdsLlRFWFRVUkVfQ1VCRV9NQVBfUE9TSVRJVkVfWCwgNiApO1xyXG5cclxuXHRpZiAoIGlzV2ViR0wyICkge1xyXG5cclxuXHRcdGVtcHR5VGV4dHVyZXNbIGdsLlRFWFRVUkVfMkRfQVJSQVkgXSA9IGNyZWF0ZVRleHR1cmUoIGdsLlRFWFRVUkVfMkRfQVJSQVksIGdsLlRFWFRVUkVfMkRfQVJSQVksIDEsIDEgKTtcclxuXHRcdGVtcHR5VGV4dHVyZXNbIGdsLlRFWFRVUkVfM0QgXSA9IGNyZWF0ZVRleHR1cmUoIGdsLlRFWFRVUkVfM0QsIGdsLlRFWFRVUkVfM0QsIDEsIDEgKTtcclxuXHJcblx0fVxyXG5cclxuXHQvLyBpbml0XHJcblxyXG5cdGNvbG9yQnVmZmVyLnNldENsZWFyKCAwLCAwLCAwLCAxICk7XHJcblx0ZGVwdGhCdWZmZXIuc2V0Q2xlYXIoIDEgKTtcclxuXHRzdGVuY2lsQnVmZmVyLnNldENsZWFyKCAwICk7XHJcblxyXG5cdGVuYWJsZSggZ2wuREVQVEhfVEVTVCApO1xyXG5cdGRlcHRoQnVmZmVyLnNldEZ1bmMoIExlc3NFcXVhbERlcHRoICk7XHJcblxyXG5cdHNldEZsaXBTaWRlZCggZmFsc2UgKTtcclxuXHRzZXRDdWxsRmFjZSggQ3VsbEZhY2VCYWNrICk7XHJcblx0ZW5hYmxlKCBnbC5DVUxMX0ZBQ0UgKTtcclxuXHJcblx0c2V0QmxlbmRpbmcoIE5vQmxlbmRpbmcgKTtcclxuXHJcblx0Ly9cclxuXHJcblx0ZnVuY3Rpb24gZW5hYmxlKCBpZCApIHtcclxuXHJcblx0XHRpZiAoIGVuYWJsZWRDYXBhYmlsaXRpZXNbIGlkIF0gIT09IHRydWUgKSB7XHJcblxyXG5cdFx0XHRnbC5lbmFibGUoIGlkICk7XHJcblx0XHRcdGVuYWJsZWRDYXBhYmlsaXRpZXNbIGlkIF0gPSB0cnVlO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBkaXNhYmxlKCBpZCApIHtcclxuXHJcblx0XHRpZiAoIGVuYWJsZWRDYXBhYmlsaXRpZXNbIGlkIF0gIT09IGZhbHNlICkge1xyXG5cclxuXHRcdFx0Z2wuZGlzYWJsZSggaWQgKTtcclxuXHRcdFx0ZW5hYmxlZENhcGFiaWxpdGllc1sgaWQgXSA9IGZhbHNlO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBiaW5kRnJhbWVidWZmZXIoIHRhcmdldCwgZnJhbWVidWZmZXIgKSB7XHJcblxyXG5cdFx0aWYgKCBjdXJyZW50Qm91bmRGcmFtZWJ1ZmZlcnNbIHRhcmdldCBdICE9PSBmcmFtZWJ1ZmZlciApIHtcclxuXHJcblx0XHRcdGdsLmJpbmRGcmFtZWJ1ZmZlciggdGFyZ2V0LCBmcmFtZWJ1ZmZlciApO1xyXG5cclxuXHRcdFx0Y3VycmVudEJvdW5kRnJhbWVidWZmZXJzWyB0YXJnZXQgXSA9IGZyYW1lYnVmZmVyO1xyXG5cclxuXHRcdFx0aWYgKCBpc1dlYkdMMiApIHtcclxuXHJcblx0XHRcdFx0Ly8gZ2wuRFJBV19GUkFNRUJVRkZFUiBpcyBlcXVpdmFsZW50IHRvIGdsLkZSQU1FQlVGRkVSXHJcblxyXG5cdFx0XHRcdGlmICggdGFyZ2V0ID09PSBnbC5EUkFXX0ZSQU1FQlVGRkVSICkge1xyXG5cclxuXHRcdFx0XHRcdGN1cnJlbnRCb3VuZEZyYW1lYnVmZmVyc1sgZ2wuRlJBTUVCVUZGRVIgXSA9IGZyYW1lYnVmZmVyO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdGlmICggdGFyZ2V0ID09PSBnbC5GUkFNRUJVRkZFUiApIHtcclxuXHJcblx0XHRcdFx0XHRjdXJyZW50Qm91bmRGcmFtZWJ1ZmZlcnNbIGdsLkRSQVdfRlJBTUVCVUZGRVIgXSA9IGZyYW1lYnVmZmVyO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRyZXR1cm4gdHJ1ZTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIGZhbHNlO1xyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIGRyYXdCdWZmZXJzKCByZW5kZXJUYXJnZXQsIGZyYW1lYnVmZmVyICkge1xyXG5cclxuXHRcdGxldCBkcmF3QnVmZmVycyA9IGRlZmF1bHREcmF3YnVmZmVycztcclxuXHJcblx0XHRsZXQgbmVlZHNVcGRhdGUgPSBmYWxzZTtcclxuXHJcblx0XHRpZiAoIHJlbmRlclRhcmdldCApIHtcclxuXHJcblx0XHRcdGRyYXdCdWZmZXJzID0gY3VycmVudERyYXdidWZmZXJzLmdldCggZnJhbWVidWZmZXIgKTtcclxuXHJcblx0XHRcdGlmICggZHJhd0J1ZmZlcnMgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0ZHJhd0J1ZmZlcnMgPSBbXTtcclxuXHRcdFx0XHRjdXJyZW50RHJhd2J1ZmZlcnMuc2V0KCBmcmFtZWJ1ZmZlciwgZHJhd0J1ZmZlcnMgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGlmICggcmVuZGVyVGFyZ2V0LmlzV2ViR0xNdWx0aXBsZVJlbmRlclRhcmdldHMgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IHRleHR1cmVzID0gcmVuZGVyVGFyZ2V0LnRleHR1cmU7XHJcblxyXG5cdFx0XHRcdGlmICggZHJhd0J1ZmZlcnMubGVuZ3RoICE9PSB0ZXh0dXJlcy5sZW5ndGggfHwgZHJhd0J1ZmZlcnNbIDAgXSAhPT0gZ2wuQ09MT1JfQVRUQUNITUVOVDAgKSB7XHJcblxyXG5cdFx0XHRcdFx0Zm9yICggbGV0IGkgPSAwLCBpbCA9IHRleHR1cmVzLmxlbmd0aDsgaSA8IGlsOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRcdFx0ZHJhd0J1ZmZlcnNbIGkgXSA9IGdsLkNPTE9SX0FUVEFDSE1FTlQwICsgaTtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0ZHJhd0J1ZmZlcnMubGVuZ3RoID0gdGV4dHVyZXMubGVuZ3RoO1xyXG5cclxuXHRcdFx0XHRcdG5lZWRzVXBkYXRlID0gdHJ1ZTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0aWYgKCBkcmF3QnVmZmVyc1sgMCBdICE9PSBnbC5DT0xPUl9BVFRBQ0hNRU5UMCApIHtcclxuXHJcblx0XHRcdFx0XHRkcmF3QnVmZmVyc1sgMCBdID0gZ2wuQ09MT1JfQVRUQUNITUVOVDA7XHJcblxyXG5cdFx0XHRcdFx0bmVlZHNVcGRhdGUgPSB0cnVlO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdGlmICggZHJhd0J1ZmZlcnNbIDAgXSAhPT0gZ2wuQkFDSyApIHtcclxuXHJcblx0XHRcdFx0ZHJhd0J1ZmZlcnNbIDAgXSA9IGdsLkJBQ0s7XHJcblxyXG5cdFx0XHRcdG5lZWRzVXBkYXRlID0gdHJ1ZTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBuZWVkc1VwZGF0ZSApIHtcclxuXHJcblx0XHRcdGlmICggY2FwYWJpbGl0aWVzLmlzV2ViR0wyICkge1xyXG5cclxuXHRcdFx0XHRnbC5kcmF3QnVmZmVycyggZHJhd0J1ZmZlcnMgKTtcclxuXHJcblx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdGV4dGVuc2lvbnMuZ2V0KCAnV0VCR0xfZHJhd19idWZmZXJzJyApLmRyYXdCdWZmZXJzV0VCR0woIGRyYXdCdWZmZXJzICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiB1c2VQcm9ncmFtKCBwcm9ncmFtICkge1xyXG5cclxuXHRcdGlmICggY3VycmVudFByb2dyYW0gIT09IHByb2dyYW0gKSB7XHJcblxyXG5cdFx0XHRnbC51c2VQcm9ncmFtKCBwcm9ncmFtICk7XHJcblxyXG5cdFx0XHRjdXJyZW50UHJvZ3JhbSA9IHByb2dyYW07XHJcblxyXG5cdFx0XHRyZXR1cm4gdHJ1ZTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIGZhbHNlO1xyXG5cclxuXHR9XHJcblxyXG5cdGNvbnN0IGVxdWF0aW9uVG9HTCA9IHtcclxuXHRcdFsgQWRkRXF1YXRpb24gXTogZ2wuRlVOQ19BREQsXHJcblx0XHRbIFN1YnRyYWN0RXF1YXRpb24gXTogZ2wuRlVOQ19TVUJUUkFDVCxcclxuXHRcdFsgUmV2ZXJzZVN1YnRyYWN0RXF1YXRpb24gXTogZ2wuRlVOQ19SRVZFUlNFX1NVQlRSQUNUXHJcblx0fTtcclxuXHJcblx0aWYgKCBpc1dlYkdMMiApIHtcclxuXHJcblx0XHRlcXVhdGlvblRvR0xbIE1pbkVxdWF0aW9uIF0gPSBnbC5NSU47XHJcblx0XHRlcXVhdGlvblRvR0xbIE1heEVxdWF0aW9uIF0gPSBnbC5NQVg7XHJcblxyXG5cdH0gZWxzZSB7XHJcblxyXG5cdFx0Y29uc3QgZXh0ZW5zaW9uID0gZXh0ZW5zaW9ucy5nZXQoICdFWFRfYmxlbmRfbWlubWF4JyApO1xyXG5cclxuXHRcdGlmICggZXh0ZW5zaW9uICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0ZXF1YXRpb25Ub0dMWyBNaW5FcXVhdGlvbiBdID0gZXh0ZW5zaW9uLk1JTl9FWFQ7XHJcblx0XHRcdGVxdWF0aW9uVG9HTFsgTWF4RXF1YXRpb24gXSA9IGV4dGVuc2lvbi5NQVhfRVhUO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRjb25zdCBmYWN0b3JUb0dMID0ge1xyXG5cdFx0WyBaZXJvRmFjdG9yIF06IGdsLlpFUk8sXHJcblx0XHRbIE9uZUZhY3RvciBdOiBnbC5PTkUsXHJcblx0XHRbIFNyY0NvbG9yRmFjdG9yIF06IGdsLlNSQ19DT0xPUixcclxuXHRcdFsgU3JjQWxwaGFGYWN0b3IgXTogZ2wuU1JDX0FMUEhBLFxyXG5cdFx0WyBTcmNBbHBoYVNhdHVyYXRlRmFjdG9yIF06IGdsLlNSQ19BTFBIQV9TQVRVUkFURSxcclxuXHRcdFsgRHN0Q29sb3JGYWN0b3IgXTogZ2wuRFNUX0NPTE9SLFxyXG5cdFx0WyBEc3RBbHBoYUZhY3RvciBdOiBnbC5EU1RfQUxQSEEsXHJcblx0XHRbIE9uZU1pbnVzU3JjQ29sb3JGYWN0b3IgXTogZ2wuT05FX01JTlVTX1NSQ19DT0xPUixcclxuXHRcdFsgT25lTWludXNTcmNBbHBoYUZhY3RvciBdOiBnbC5PTkVfTUlOVVNfU1JDX0FMUEhBLFxyXG5cdFx0WyBPbmVNaW51c0RzdENvbG9yRmFjdG9yIF06IGdsLk9ORV9NSU5VU19EU1RfQ09MT1IsXHJcblx0XHRbIE9uZU1pbnVzRHN0QWxwaGFGYWN0b3IgXTogZ2wuT05FX01JTlVTX0RTVF9BTFBIQSxcclxuXHRcdFsgQ29uc3RhbnRDb2xvckZhY3RvciBdOiBnbC5DT05TVEFOVF9DT0xPUixcclxuXHRcdFsgT25lTWludXNDb25zdGFudENvbG9yRmFjdG9yIF06IGdsLk9ORV9NSU5VU19DT05TVEFOVF9DT0xPUixcclxuXHRcdFsgQ29uc3RhbnRBbHBoYUZhY3RvciBdOiBnbC5DT05TVEFOVF9BTFBIQSxcclxuXHRcdFsgT25lTWludXNDb25zdGFudEFscGhhRmFjdG9yIF06IGdsLk9ORV9NSU5VU19DT05TVEFOVF9BTFBIQVxyXG5cdH07XHJcblxyXG5cdGZ1bmN0aW9uIHNldEJsZW5kaW5nKCBibGVuZGluZywgYmxlbmRFcXVhdGlvbiwgYmxlbmRTcmMsIGJsZW5kRHN0LCBibGVuZEVxdWF0aW9uQWxwaGEsIGJsZW5kU3JjQWxwaGEsIGJsZW5kRHN0QWxwaGEsIGJsZW5kQ29sb3IsIGJsZW5kQWxwaGEsIHByZW11bHRpcGxpZWRBbHBoYSApIHtcclxuXHJcblx0XHRpZiAoIGJsZW5kaW5nID09PSBOb0JsZW5kaW5nICkge1xyXG5cclxuXHRcdFx0aWYgKCBjdXJyZW50QmxlbmRpbmdFbmFibGVkID09PSB0cnVlICkge1xyXG5cclxuXHRcdFx0XHRkaXNhYmxlKCBnbC5CTEVORCApO1xyXG5cdFx0XHRcdGN1cnJlbnRCbGVuZGluZ0VuYWJsZWQgPSBmYWxzZTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHJldHVybjtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBjdXJyZW50QmxlbmRpbmdFbmFibGVkID09PSBmYWxzZSApIHtcclxuXHJcblx0XHRcdGVuYWJsZSggZ2wuQkxFTkQgKTtcclxuXHRcdFx0Y3VycmVudEJsZW5kaW5nRW5hYmxlZCA9IHRydWU7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggYmxlbmRpbmcgIT09IEN1c3RvbUJsZW5kaW5nICkge1xyXG5cclxuXHRcdFx0aWYgKCBibGVuZGluZyAhPT0gY3VycmVudEJsZW5kaW5nIHx8IHByZW11bHRpcGxpZWRBbHBoYSAhPT0gY3VycmVudFByZW11bHRpcGxlZEFscGhhICkge1xyXG5cclxuXHRcdFx0XHRpZiAoIGN1cnJlbnRCbGVuZEVxdWF0aW9uICE9PSBBZGRFcXVhdGlvbiB8fCBjdXJyZW50QmxlbmRFcXVhdGlvbkFscGhhICE9PSBBZGRFcXVhdGlvbiApIHtcclxuXHJcblx0XHRcdFx0XHRnbC5ibGVuZEVxdWF0aW9uKCBnbC5GVU5DX0FERCApO1xyXG5cclxuXHRcdFx0XHRcdGN1cnJlbnRCbGVuZEVxdWF0aW9uID0gQWRkRXF1YXRpb247XHJcblx0XHRcdFx0XHRjdXJyZW50QmxlbmRFcXVhdGlvbkFscGhhID0gQWRkRXF1YXRpb247XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0aWYgKCBwcmVtdWx0aXBsaWVkQWxwaGEgKSB7XHJcblxyXG5cdFx0XHRcdFx0c3dpdGNoICggYmxlbmRpbmcgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRjYXNlIE5vcm1hbEJsZW5kaW5nOlxyXG5cdFx0XHRcdFx0XHRcdGdsLmJsZW5kRnVuY1NlcGFyYXRlKCBnbC5PTkUsIGdsLk9ORV9NSU5VU19TUkNfQUxQSEEsIGdsLk9ORSwgZ2wuT05FX01JTlVTX1NSQ19BTFBIQSApO1xyXG5cdFx0XHRcdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0XHRcdFx0Y2FzZSBBZGRpdGl2ZUJsZW5kaW5nOlxyXG5cdFx0XHRcdFx0XHRcdGdsLmJsZW5kRnVuYyggZ2wuT05FLCBnbC5PTkUgKTtcclxuXHRcdFx0XHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdFx0XHRcdGNhc2UgU3VidHJhY3RpdmVCbGVuZGluZzpcclxuXHRcdFx0XHRcdFx0XHRnbC5ibGVuZEZ1bmNTZXBhcmF0ZSggZ2wuWkVSTywgZ2wuT05FX01JTlVTX1NSQ19DT0xPUiwgZ2wuWkVSTywgZ2wuT05FICk7XHJcblx0XHRcdFx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRcdFx0XHRjYXNlIE11bHRpcGx5QmxlbmRpbmc6XHJcblx0XHRcdFx0XHRcdFx0Z2wuYmxlbmRGdW5jU2VwYXJhdGUoIGdsLlpFUk8sIGdsLlNSQ19DT0xPUiwgZ2wuWkVSTywgZ2wuU1JDX0FMUEhBICk7XHJcblx0XHRcdFx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRcdFx0XHRkZWZhdWx0OlxyXG5cdFx0XHRcdFx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5XZWJHTFN0YXRlOiBJbnZhbGlkIGJsZW5kaW5nOiAnLCBibGVuZGluZyApO1xyXG5cdFx0XHRcdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRzd2l0Y2ggKCBibGVuZGluZyApIHtcclxuXHJcblx0XHRcdFx0XHRcdGNhc2UgTm9ybWFsQmxlbmRpbmc6XHJcblx0XHRcdFx0XHRcdFx0Z2wuYmxlbmRGdW5jU2VwYXJhdGUoIGdsLlNSQ19BTFBIQSwgZ2wuT05FX01JTlVTX1NSQ19BTFBIQSwgZ2wuT05FLCBnbC5PTkVfTUlOVVNfU1JDX0FMUEhBICk7XHJcblx0XHRcdFx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRcdFx0XHRjYXNlIEFkZGl0aXZlQmxlbmRpbmc6XHJcblx0XHRcdFx0XHRcdFx0Z2wuYmxlbmRGdW5jKCBnbC5TUkNfQUxQSEEsIGdsLk9ORSApO1xyXG5cdFx0XHRcdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0XHRcdFx0Y2FzZSBTdWJ0cmFjdGl2ZUJsZW5kaW5nOlxyXG5cdFx0XHRcdFx0XHRcdGdsLmJsZW5kRnVuY1NlcGFyYXRlKCBnbC5aRVJPLCBnbC5PTkVfTUlOVVNfU1JDX0NPTE9SLCBnbC5aRVJPLCBnbC5PTkUgKTtcclxuXHRcdFx0XHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdFx0XHRcdGNhc2UgTXVsdGlwbHlCbGVuZGluZzpcclxuXHRcdFx0XHRcdFx0XHRnbC5ibGVuZEZ1bmMoIGdsLlpFUk8sIGdsLlNSQ19DT0xPUiApO1xyXG5cdFx0XHRcdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0XHRcdFx0ZGVmYXVsdDpcclxuXHRcdFx0XHRcdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuV2ViR0xTdGF0ZTogSW52YWxpZCBibGVuZGluZzogJywgYmxlbmRpbmcgKTtcclxuXHRcdFx0XHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0Y3VycmVudEJsZW5kU3JjID0gbnVsbDtcclxuXHRcdFx0XHRjdXJyZW50QmxlbmREc3QgPSBudWxsO1xyXG5cdFx0XHRcdGN1cnJlbnRCbGVuZFNyY0FscGhhID0gbnVsbDtcclxuXHRcdFx0XHRjdXJyZW50QmxlbmREc3RBbHBoYSA9IG51bGw7XHJcblx0XHRcdFx0Y3VycmVudEJsZW5kQ29sb3Iuc2V0KCAwLCAwLCAwICk7XHJcblx0XHRcdFx0Y3VycmVudEJsZW5kQWxwaGEgPSAwO1xyXG5cclxuXHRcdFx0XHRjdXJyZW50QmxlbmRpbmcgPSBibGVuZGluZztcclxuXHRcdFx0XHRjdXJyZW50UHJlbXVsdGlwbGVkQWxwaGEgPSBwcmVtdWx0aXBsaWVkQWxwaGE7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRyZXR1cm47XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIGN1c3RvbSBibGVuZGluZ1xyXG5cclxuXHRcdGJsZW5kRXF1YXRpb25BbHBoYSA9IGJsZW5kRXF1YXRpb25BbHBoYSB8fCBibGVuZEVxdWF0aW9uO1xyXG5cdFx0YmxlbmRTcmNBbHBoYSA9IGJsZW5kU3JjQWxwaGEgfHwgYmxlbmRTcmM7XHJcblx0XHRibGVuZERzdEFscGhhID0gYmxlbmREc3RBbHBoYSB8fCBibGVuZERzdDtcclxuXHJcblx0XHRpZiAoIGJsZW5kRXF1YXRpb24gIT09IGN1cnJlbnRCbGVuZEVxdWF0aW9uIHx8IGJsZW5kRXF1YXRpb25BbHBoYSAhPT0gY3VycmVudEJsZW5kRXF1YXRpb25BbHBoYSApIHtcclxuXHJcblx0XHRcdGdsLmJsZW5kRXF1YXRpb25TZXBhcmF0ZSggZXF1YXRpb25Ub0dMWyBibGVuZEVxdWF0aW9uIF0sIGVxdWF0aW9uVG9HTFsgYmxlbmRFcXVhdGlvbkFscGhhIF0gKTtcclxuXHJcblx0XHRcdGN1cnJlbnRCbGVuZEVxdWF0aW9uID0gYmxlbmRFcXVhdGlvbjtcclxuXHRcdFx0Y3VycmVudEJsZW5kRXF1YXRpb25BbHBoYSA9IGJsZW5kRXF1YXRpb25BbHBoYTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBibGVuZFNyYyAhPT0gY3VycmVudEJsZW5kU3JjIHx8IGJsZW5kRHN0ICE9PSBjdXJyZW50QmxlbmREc3QgfHwgYmxlbmRTcmNBbHBoYSAhPT0gY3VycmVudEJsZW5kU3JjQWxwaGEgfHwgYmxlbmREc3RBbHBoYSAhPT0gY3VycmVudEJsZW5kRHN0QWxwaGEgKSB7XHJcblxyXG5cdFx0XHRnbC5ibGVuZEZ1bmNTZXBhcmF0ZSggZmFjdG9yVG9HTFsgYmxlbmRTcmMgXSwgZmFjdG9yVG9HTFsgYmxlbmREc3QgXSwgZmFjdG9yVG9HTFsgYmxlbmRTcmNBbHBoYSBdLCBmYWN0b3JUb0dMWyBibGVuZERzdEFscGhhIF0gKTtcclxuXHJcblx0XHRcdGN1cnJlbnRCbGVuZFNyYyA9IGJsZW5kU3JjO1xyXG5cdFx0XHRjdXJyZW50QmxlbmREc3QgPSBibGVuZERzdDtcclxuXHRcdFx0Y3VycmVudEJsZW5kU3JjQWxwaGEgPSBibGVuZFNyY0FscGhhO1xyXG5cdFx0XHRjdXJyZW50QmxlbmREc3RBbHBoYSA9IGJsZW5kRHN0QWxwaGE7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggYmxlbmRDb2xvci5lcXVhbHMoIGN1cnJlbnRCbGVuZENvbG9yICkgPT09IGZhbHNlIHx8IGJsZW5kQWxwaGEgIT09IGN1cnJlbnRCbGVuZEFscGhhICkge1xyXG5cclxuXHRcdFx0Z2wuYmxlbmRDb2xvciggYmxlbmRDb2xvci5yLCBibGVuZENvbG9yLmcsIGJsZW5kQ29sb3IuYiwgYmxlbmRBbHBoYSApO1xyXG5cclxuXHRcdFx0Y3VycmVudEJsZW5kQ29sb3IuY29weSggYmxlbmRDb2xvciApO1xyXG5cdFx0XHRjdXJyZW50QmxlbmRBbHBoYSA9IGJsZW5kQWxwaGE7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGN1cnJlbnRCbGVuZGluZyA9IGJsZW5kaW5nO1xyXG5cdFx0Y3VycmVudFByZW11bHRpcGxlZEFscGhhID0gZmFsc2U7XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gc2V0TWF0ZXJpYWwoIG1hdGVyaWFsLCBmcm9udEZhY2VDVyApIHtcclxuXHJcblx0XHRtYXRlcmlhbC5zaWRlID09PSBEb3VibGVTaWRlXHJcblx0XHRcdD8gZGlzYWJsZSggZ2wuQ1VMTF9GQUNFIClcclxuXHRcdFx0OiBlbmFibGUoIGdsLkNVTExfRkFDRSApO1xyXG5cclxuXHRcdGxldCBmbGlwU2lkZWQgPSAoIG1hdGVyaWFsLnNpZGUgPT09IEJhY2tTaWRlICk7XHJcblx0XHRpZiAoIGZyb250RmFjZUNXICkgZmxpcFNpZGVkID0gISBmbGlwU2lkZWQ7XHJcblxyXG5cdFx0c2V0RmxpcFNpZGVkKCBmbGlwU2lkZWQgKTtcclxuXHJcblx0XHQoIG1hdGVyaWFsLmJsZW5kaW5nID09PSBOb3JtYWxCbGVuZGluZyAmJiBtYXRlcmlhbC50cmFuc3BhcmVudCA9PT0gZmFsc2UgKVxyXG5cdFx0XHQ/IHNldEJsZW5kaW5nKCBOb0JsZW5kaW5nIClcclxuXHRcdFx0OiBzZXRCbGVuZGluZyggbWF0ZXJpYWwuYmxlbmRpbmcsIG1hdGVyaWFsLmJsZW5kRXF1YXRpb24sIG1hdGVyaWFsLmJsZW5kU3JjLCBtYXRlcmlhbC5ibGVuZERzdCwgbWF0ZXJpYWwuYmxlbmRFcXVhdGlvbkFscGhhLCBtYXRlcmlhbC5ibGVuZFNyY0FscGhhLCBtYXRlcmlhbC5ibGVuZERzdEFscGhhLCBtYXRlcmlhbC5ibGVuZENvbG9yLCBtYXRlcmlhbC5ibGVuZEFscGhhLCBtYXRlcmlhbC5wcmVtdWx0aXBsaWVkQWxwaGEgKTtcclxuXHJcblx0XHRkZXB0aEJ1ZmZlci5zZXRGdW5jKCBtYXRlcmlhbC5kZXB0aEZ1bmMgKTtcclxuXHRcdGRlcHRoQnVmZmVyLnNldFRlc3QoIG1hdGVyaWFsLmRlcHRoVGVzdCApO1xyXG5cdFx0ZGVwdGhCdWZmZXIuc2V0TWFzayggbWF0ZXJpYWwuZGVwdGhXcml0ZSApO1xyXG5cdFx0Y29sb3JCdWZmZXIuc2V0TWFzayggbWF0ZXJpYWwuY29sb3JXcml0ZSApO1xyXG5cclxuXHRcdGNvbnN0IHN0ZW5jaWxXcml0ZSA9IG1hdGVyaWFsLnN0ZW5jaWxXcml0ZTtcclxuXHRcdHN0ZW5jaWxCdWZmZXIuc2V0VGVzdCggc3RlbmNpbFdyaXRlICk7XHJcblx0XHRpZiAoIHN0ZW5jaWxXcml0ZSApIHtcclxuXHJcblx0XHRcdHN0ZW5jaWxCdWZmZXIuc2V0TWFzayggbWF0ZXJpYWwuc3RlbmNpbFdyaXRlTWFzayApO1xyXG5cdFx0XHRzdGVuY2lsQnVmZmVyLnNldEZ1bmMoIG1hdGVyaWFsLnN0ZW5jaWxGdW5jLCBtYXRlcmlhbC5zdGVuY2lsUmVmLCBtYXRlcmlhbC5zdGVuY2lsRnVuY01hc2sgKTtcclxuXHRcdFx0c3RlbmNpbEJ1ZmZlci5zZXRPcCggbWF0ZXJpYWwuc3RlbmNpbEZhaWwsIG1hdGVyaWFsLnN0ZW5jaWxaRmFpbCwgbWF0ZXJpYWwuc3RlbmNpbFpQYXNzICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHNldFBvbHlnb25PZmZzZXQoIG1hdGVyaWFsLnBvbHlnb25PZmZzZXQsIG1hdGVyaWFsLnBvbHlnb25PZmZzZXRGYWN0b3IsIG1hdGVyaWFsLnBvbHlnb25PZmZzZXRVbml0cyApO1xyXG5cclxuXHRcdG1hdGVyaWFsLmFscGhhVG9Db3ZlcmFnZSA9PT0gdHJ1ZVxyXG5cdFx0XHQ/IGVuYWJsZSggZ2wuU0FNUExFX0FMUEhBX1RPX0NPVkVSQUdFIClcclxuXHRcdFx0OiBkaXNhYmxlKCBnbC5TQU1QTEVfQUxQSEFfVE9fQ09WRVJBR0UgKTtcclxuXHJcblx0fVxyXG5cclxuXHQvL1xyXG5cclxuXHRmdW5jdGlvbiBzZXRGbGlwU2lkZWQoIGZsaXBTaWRlZCApIHtcclxuXHJcblx0XHRpZiAoIGN1cnJlbnRGbGlwU2lkZWQgIT09IGZsaXBTaWRlZCApIHtcclxuXHJcblx0XHRcdGlmICggZmxpcFNpZGVkICkge1xyXG5cclxuXHRcdFx0XHRnbC5mcm9udEZhY2UoIGdsLkNXICk7XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRnbC5mcm9udEZhY2UoIGdsLkNDVyApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Y3VycmVudEZsaXBTaWRlZCA9IGZsaXBTaWRlZDtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gc2V0Q3VsbEZhY2UoIGN1bGxGYWNlICkge1xyXG5cclxuXHRcdGlmICggY3VsbEZhY2UgIT09IEN1bGxGYWNlTm9uZSApIHtcclxuXHJcblx0XHRcdGVuYWJsZSggZ2wuQ1VMTF9GQUNFICk7XHJcblxyXG5cdFx0XHRpZiAoIGN1bGxGYWNlICE9PSBjdXJyZW50Q3VsbEZhY2UgKSB7XHJcblxyXG5cdFx0XHRcdGlmICggY3VsbEZhY2UgPT09IEN1bGxGYWNlQmFjayApIHtcclxuXHJcblx0XHRcdFx0XHRnbC5jdWxsRmFjZSggZ2wuQkFDSyApO1xyXG5cclxuXHRcdFx0XHR9IGVsc2UgaWYgKCBjdWxsRmFjZSA9PT0gQ3VsbEZhY2VGcm9udCApIHtcclxuXHJcblx0XHRcdFx0XHRnbC5jdWxsRmFjZSggZ2wuRlJPTlQgKTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRnbC5jdWxsRmFjZSggZ2wuRlJPTlRfQU5EX0JBQ0sgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRkaXNhYmxlKCBnbC5DVUxMX0ZBQ0UgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Y3VycmVudEN1bGxGYWNlID0gY3VsbEZhY2U7XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gc2V0TGluZVdpZHRoKCB3aWR0aCApIHtcclxuXHJcblx0XHRpZiAoIHdpZHRoICE9PSBjdXJyZW50TGluZVdpZHRoICkge1xyXG5cclxuXHRcdFx0aWYgKCBsaW5lV2lkdGhBdmFpbGFibGUgKSBnbC5saW5lV2lkdGgoIHdpZHRoICk7XHJcblxyXG5cdFx0XHRjdXJyZW50TGluZVdpZHRoID0gd2lkdGg7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHNldFBvbHlnb25PZmZzZXQoIHBvbHlnb25PZmZzZXQsIGZhY3RvciwgdW5pdHMgKSB7XHJcblxyXG5cdFx0aWYgKCBwb2x5Z29uT2Zmc2V0ICkge1xyXG5cclxuXHRcdFx0ZW5hYmxlKCBnbC5QT0xZR09OX09GRlNFVF9GSUxMICk7XHJcblxyXG5cdFx0XHRpZiAoIGN1cnJlbnRQb2x5Z29uT2Zmc2V0RmFjdG9yICE9PSBmYWN0b3IgfHwgY3VycmVudFBvbHlnb25PZmZzZXRVbml0cyAhPT0gdW5pdHMgKSB7XHJcblxyXG5cdFx0XHRcdGdsLnBvbHlnb25PZmZzZXQoIGZhY3RvciwgdW5pdHMgKTtcclxuXHJcblx0XHRcdFx0Y3VycmVudFBvbHlnb25PZmZzZXRGYWN0b3IgPSBmYWN0b3I7XHJcblx0XHRcdFx0Y3VycmVudFBvbHlnb25PZmZzZXRVbml0cyA9IHVuaXRzO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRkaXNhYmxlKCBnbC5QT0xZR09OX09GRlNFVF9GSUxMICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHNldFNjaXNzb3JUZXN0KCBzY2lzc29yVGVzdCApIHtcclxuXHJcblx0XHRpZiAoIHNjaXNzb3JUZXN0ICkge1xyXG5cclxuXHRcdFx0ZW5hYmxlKCBnbC5TQ0lTU09SX1RFU1QgKTtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0ZGlzYWJsZSggZ2wuU0NJU1NPUl9URVNUICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdC8vIHRleHR1cmVcclxuXHJcblx0ZnVuY3Rpb24gYWN0aXZlVGV4dHVyZSggd2ViZ2xTbG90ICkge1xyXG5cclxuXHRcdGlmICggd2ViZ2xTbG90ID09PSB1bmRlZmluZWQgKSB3ZWJnbFNsb3QgPSBnbC5URVhUVVJFMCArIG1heFRleHR1cmVzIC0gMTtcclxuXHJcblx0XHRpZiAoIGN1cnJlbnRUZXh0dXJlU2xvdCAhPT0gd2ViZ2xTbG90ICkge1xyXG5cclxuXHRcdFx0Z2wuYWN0aXZlVGV4dHVyZSggd2ViZ2xTbG90ICk7XHJcblx0XHRcdGN1cnJlbnRUZXh0dXJlU2xvdCA9IHdlYmdsU2xvdDtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gYmluZFRleHR1cmUoIHdlYmdsVHlwZSwgd2ViZ2xUZXh0dXJlLCB3ZWJnbFNsb3QgKSB7XHJcblxyXG5cdFx0aWYgKCB3ZWJnbFNsb3QgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdGlmICggY3VycmVudFRleHR1cmVTbG90ID09PSBudWxsICkge1xyXG5cclxuXHRcdFx0XHR3ZWJnbFNsb3QgPSBnbC5URVhUVVJFMCArIG1heFRleHR1cmVzIC0gMTtcclxuXHJcblx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdHdlYmdsU2xvdCA9IGN1cnJlbnRUZXh0dXJlU2xvdDtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0bGV0IGJvdW5kVGV4dHVyZSA9IGN1cnJlbnRCb3VuZFRleHR1cmVzWyB3ZWJnbFNsb3QgXTtcclxuXHJcblx0XHRpZiAoIGJvdW5kVGV4dHVyZSA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0Ym91bmRUZXh0dXJlID0geyB0eXBlOiB1bmRlZmluZWQsIHRleHR1cmU6IHVuZGVmaW5lZCB9O1xyXG5cdFx0XHRjdXJyZW50Qm91bmRUZXh0dXJlc1sgd2ViZ2xTbG90IF0gPSBib3VuZFRleHR1cmU7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggYm91bmRUZXh0dXJlLnR5cGUgIT09IHdlYmdsVHlwZSB8fCBib3VuZFRleHR1cmUudGV4dHVyZSAhPT0gd2ViZ2xUZXh0dXJlICkge1xyXG5cclxuXHRcdFx0aWYgKCBjdXJyZW50VGV4dHVyZVNsb3QgIT09IHdlYmdsU2xvdCApIHtcclxuXHJcblx0XHRcdFx0Z2wuYWN0aXZlVGV4dHVyZSggd2ViZ2xTbG90ICk7XHJcblx0XHRcdFx0Y3VycmVudFRleHR1cmVTbG90ID0gd2ViZ2xTbG90O1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Z2wuYmluZFRleHR1cmUoIHdlYmdsVHlwZSwgd2ViZ2xUZXh0dXJlIHx8IGVtcHR5VGV4dHVyZXNbIHdlYmdsVHlwZSBdICk7XHJcblxyXG5cdFx0XHRib3VuZFRleHR1cmUudHlwZSA9IHdlYmdsVHlwZTtcclxuXHRcdFx0Ym91bmRUZXh0dXJlLnRleHR1cmUgPSB3ZWJnbFRleHR1cmU7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHVuYmluZFRleHR1cmUoKSB7XHJcblxyXG5cdFx0Y29uc3QgYm91bmRUZXh0dXJlID0gY3VycmVudEJvdW5kVGV4dHVyZXNbIGN1cnJlbnRUZXh0dXJlU2xvdCBdO1xyXG5cclxuXHRcdGlmICggYm91bmRUZXh0dXJlICE9PSB1bmRlZmluZWQgJiYgYm91bmRUZXh0dXJlLnR5cGUgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdGdsLmJpbmRUZXh0dXJlKCBib3VuZFRleHR1cmUudHlwZSwgbnVsbCApO1xyXG5cclxuXHRcdFx0Ym91bmRUZXh0dXJlLnR5cGUgPSB1bmRlZmluZWQ7XHJcblx0XHRcdGJvdW5kVGV4dHVyZS50ZXh0dXJlID0gdW5kZWZpbmVkO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBjb21wcmVzc2VkVGV4SW1hZ2UyRCgpIHtcclxuXHJcblx0XHR0cnkge1xyXG5cclxuXHRcdFx0Z2wuY29tcHJlc3NlZFRleEltYWdlMkQuYXBwbHkoIGdsLCBhcmd1bWVudHMgKTtcclxuXHJcblx0XHR9IGNhdGNoICggZXJyb3IgKSB7XHJcblxyXG5cdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuV2ViR0xTdGF0ZTonLCBlcnJvciApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBjb21wcmVzc2VkVGV4SW1hZ2UzRCgpIHtcclxuXHJcblx0XHR0cnkge1xyXG5cclxuXHRcdFx0Z2wuY29tcHJlc3NlZFRleEltYWdlM0QuYXBwbHkoIGdsLCBhcmd1bWVudHMgKTtcclxuXHJcblx0XHR9IGNhdGNoICggZXJyb3IgKSB7XHJcblxyXG5cdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuV2ViR0xTdGF0ZTonLCBlcnJvciApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiB0ZXhTdWJJbWFnZTJEKCkge1xyXG5cclxuXHRcdHRyeSB7XHJcblxyXG5cdFx0XHRnbC50ZXhTdWJJbWFnZTJELmFwcGx5KCBnbCwgYXJndW1lbnRzICk7XHJcblxyXG5cdFx0fSBjYXRjaCAoIGVycm9yICkge1xyXG5cclxuXHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLldlYkdMU3RhdGU6JywgZXJyb3IgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gdGV4U3ViSW1hZ2UzRCgpIHtcclxuXHJcblx0XHR0cnkge1xyXG5cclxuXHRcdFx0Z2wudGV4U3ViSW1hZ2UzRC5hcHBseSggZ2wsIGFyZ3VtZW50cyApO1xyXG5cclxuXHRcdH0gY2F0Y2ggKCBlcnJvciApIHtcclxuXHJcblx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5XZWJHTFN0YXRlOicsIGVycm9yICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIGNvbXByZXNzZWRUZXhTdWJJbWFnZTJEKCkge1xyXG5cclxuXHRcdHRyeSB7XHJcblxyXG5cdFx0XHRnbC5jb21wcmVzc2VkVGV4U3ViSW1hZ2UyRC5hcHBseSggZ2wsIGFyZ3VtZW50cyApO1xyXG5cclxuXHRcdH0gY2F0Y2ggKCBlcnJvciApIHtcclxuXHJcblx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5XZWJHTFN0YXRlOicsIGVycm9yICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIGNvbXByZXNzZWRUZXhTdWJJbWFnZTNEKCkge1xyXG5cclxuXHRcdHRyeSB7XHJcblxyXG5cdFx0XHRnbC5jb21wcmVzc2VkVGV4U3ViSW1hZ2UzRC5hcHBseSggZ2wsIGFyZ3VtZW50cyApO1xyXG5cclxuXHRcdH0gY2F0Y2ggKCBlcnJvciApIHtcclxuXHJcblx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5XZWJHTFN0YXRlOicsIGVycm9yICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHRleFN0b3JhZ2UyRCgpIHtcclxuXHJcblx0XHR0cnkge1xyXG5cclxuXHRcdFx0Z2wudGV4U3RvcmFnZTJELmFwcGx5KCBnbCwgYXJndW1lbnRzICk7XHJcblxyXG5cdFx0fSBjYXRjaCAoIGVycm9yICkge1xyXG5cclxuXHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLldlYkdMU3RhdGU6JywgZXJyb3IgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gdGV4U3RvcmFnZTNEKCkge1xyXG5cclxuXHRcdHRyeSB7XHJcblxyXG5cdFx0XHRnbC50ZXhTdG9yYWdlM0QuYXBwbHkoIGdsLCBhcmd1bWVudHMgKTtcclxuXHJcblx0XHR9IGNhdGNoICggZXJyb3IgKSB7XHJcblxyXG5cdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuV2ViR0xTdGF0ZTonLCBlcnJvciApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiB0ZXhJbWFnZTJEKCkge1xyXG5cclxuXHRcdHRyeSB7XHJcblxyXG5cdFx0XHRnbC50ZXhJbWFnZTJELmFwcGx5KCBnbCwgYXJndW1lbnRzICk7XHJcblxyXG5cdFx0fSBjYXRjaCAoIGVycm9yICkge1xyXG5cclxuXHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLldlYkdMU3RhdGU6JywgZXJyb3IgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gdGV4SW1hZ2UzRCgpIHtcclxuXHJcblx0XHR0cnkge1xyXG5cclxuXHRcdFx0Z2wudGV4SW1hZ2UzRC5hcHBseSggZ2wsIGFyZ3VtZW50cyApO1xyXG5cclxuXHRcdH0gY2F0Y2ggKCBlcnJvciApIHtcclxuXHJcblx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5XZWJHTFN0YXRlOicsIGVycm9yICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdC8vXHJcblxyXG5cdGZ1bmN0aW9uIHNjaXNzb3IoIHNjaXNzb3IgKSB7XHJcblxyXG5cdFx0aWYgKCBjdXJyZW50U2Npc3Nvci5lcXVhbHMoIHNjaXNzb3IgKSA9PT0gZmFsc2UgKSB7XHJcblxyXG5cdFx0XHRnbC5zY2lzc29yKCBzY2lzc29yLngsIHNjaXNzb3IueSwgc2Npc3Nvci56LCBzY2lzc29yLncgKTtcclxuXHRcdFx0Y3VycmVudFNjaXNzb3IuY29weSggc2Npc3NvciApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiB2aWV3cG9ydCggdmlld3BvcnQgKSB7XHJcblxyXG5cdFx0aWYgKCBjdXJyZW50Vmlld3BvcnQuZXF1YWxzKCB2aWV3cG9ydCApID09PSBmYWxzZSApIHtcclxuXHJcblx0XHRcdGdsLnZpZXdwb3J0KCB2aWV3cG9ydC54LCB2aWV3cG9ydC55LCB2aWV3cG9ydC56LCB2aWV3cG9ydC53ICk7XHJcblx0XHRcdGN1cnJlbnRWaWV3cG9ydC5jb3B5KCB2aWV3cG9ydCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiB1cGRhdGVVQk9NYXBwaW5nKCB1bmlmb3Jtc0dyb3VwLCBwcm9ncmFtICkge1xyXG5cclxuXHRcdGxldCBtYXBwaW5nID0gdWJvUHJvZ3JhbU1hcC5nZXQoIHByb2dyYW0gKTtcclxuXHJcblx0XHRpZiAoIG1hcHBpbmcgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdG1hcHBpbmcgPSBuZXcgV2Vha01hcCgpO1xyXG5cclxuXHRcdFx0dWJvUHJvZ3JhbU1hcC5zZXQoIHByb2dyYW0sIG1hcHBpbmcgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0bGV0IGJsb2NrSW5kZXggPSBtYXBwaW5nLmdldCggdW5pZm9ybXNHcm91cCApO1xyXG5cclxuXHRcdGlmICggYmxvY2tJbmRleCA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0YmxvY2tJbmRleCA9IGdsLmdldFVuaWZvcm1CbG9ja0luZGV4KCBwcm9ncmFtLCB1bmlmb3Jtc0dyb3VwLm5hbWUgKTtcclxuXHJcblx0XHRcdG1hcHBpbmcuc2V0KCB1bmlmb3Jtc0dyb3VwLCBibG9ja0luZGV4ICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHVuaWZvcm1CbG9ja0JpbmRpbmcoIHVuaWZvcm1zR3JvdXAsIHByb2dyYW0gKSB7XHJcblxyXG5cdFx0Y29uc3QgbWFwcGluZyA9IHVib1Byb2dyYW1NYXAuZ2V0KCBwcm9ncmFtICk7XHJcblx0XHRjb25zdCBibG9ja0luZGV4ID0gbWFwcGluZy5nZXQoIHVuaWZvcm1zR3JvdXAgKTtcclxuXHJcblx0XHRpZiAoIHVib0JpbmRpbmdzLmdldCggcHJvZ3JhbSApICE9PSBibG9ja0luZGV4ICkge1xyXG5cclxuXHRcdFx0Ly8gYmluZCBzaGFkZXIgc3BlY2lmaWMgYmxvY2sgaW5kZXggdG8gZ2xvYmFsIGJsb2NrIHBvaW50XHJcblx0XHRcdGdsLnVuaWZvcm1CbG9ja0JpbmRpbmcoIHByb2dyYW0sIGJsb2NrSW5kZXgsIHVuaWZvcm1zR3JvdXAuX19iaW5kaW5nUG9pbnRJbmRleCApO1xyXG5cclxuXHRcdFx0dWJvQmluZGluZ3Muc2V0KCBwcm9ncmFtLCBibG9ja0luZGV4ICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdC8vXHJcblxyXG5cdGZ1bmN0aW9uIHJlc2V0KCkge1xyXG5cclxuXHRcdC8vIHJlc2V0IHN0YXRlXHJcblxyXG5cdFx0Z2wuZGlzYWJsZSggZ2wuQkxFTkQgKTtcclxuXHRcdGdsLmRpc2FibGUoIGdsLkNVTExfRkFDRSApO1xyXG5cdFx0Z2wuZGlzYWJsZSggZ2wuREVQVEhfVEVTVCApO1xyXG5cdFx0Z2wuZGlzYWJsZSggZ2wuUE9MWUdPTl9PRkZTRVRfRklMTCApO1xyXG5cdFx0Z2wuZGlzYWJsZSggZ2wuU0NJU1NPUl9URVNUICk7XHJcblx0XHRnbC5kaXNhYmxlKCBnbC5TVEVOQ0lMX1RFU1QgKTtcclxuXHRcdGdsLmRpc2FibGUoIGdsLlNBTVBMRV9BTFBIQV9UT19DT1ZFUkFHRSApO1xyXG5cclxuXHRcdGdsLmJsZW5kRXF1YXRpb24oIGdsLkZVTkNfQUREICk7XHJcblx0XHRnbC5ibGVuZEZ1bmMoIGdsLk9ORSwgZ2wuWkVSTyApO1xyXG5cdFx0Z2wuYmxlbmRGdW5jU2VwYXJhdGUoIGdsLk9ORSwgZ2wuWkVSTywgZ2wuT05FLCBnbC5aRVJPICk7XHJcblx0XHRnbC5ibGVuZENvbG9yKCAwLCAwLCAwLCAwICk7XHJcblxyXG5cdFx0Z2wuY29sb3JNYXNrKCB0cnVlLCB0cnVlLCB0cnVlLCB0cnVlICk7XHJcblx0XHRnbC5jbGVhckNvbG9yKCAwLCAwLCAwLCAwICk7XHJcblxyXG5cdFx0Z2wuZGVwdGhNYXNrKCB0cnVlICk7XHJcblx0XHRnbC5kZXB0aEZ1bmMoIGdsLkxFU1MgKTtcclxuXHRcdGdsLmNsZWFyRGVwdGgoIDEgKTtcclxuXHJcblx0XHRnbC5zdGVuY2lsTWFzayggMHhmZmZmZmZmZiApO1xyXG5cdFx0Z2wuc3RlbmNpbEZ1bmMoIGdsLkFMV0FZUywgMCwgMHhmZmZmZmZmZiApO1xyXG5cdFx0Z2wuc3RlbmNpbE9wKCBnbC5LRUVQLCBnbC5LRUVQLCBnbC5LRUVQICk7XHJcblx0XHRnbC5jbGVhclN0ZW5jaWwoIDAgKTtcclxuXHJcblx0XHRnbC5jdWxsRmFjZSggZ2wuQkFDSyApO1xyXG5cdFx0Z2wuZnJvbnRGYWNlKCBnbC5DQ1cgKTtcclxuXHJcblx0XHRnbC5wb2x5Z29uT2Zmc2V0KCAwLCAwICk7XHJcblxyXG5cdFx0Z2wuYWN0aXZlVGV4dHVyZSggZ2wuVEVYVFVSRTAgKTtcclxuXHJcblx0XHRnbC5iaW5kRnJhbWVidWZmZXIoIGdsLkZSQU1FQlVGRkVSLCBudWxsICk7XHJcblxyXG5cdFx0aWYgKCBpc1dlYkdMMiA9PT0gdHJ1ZSApIHtcclxuXHJcblx0XHRcdGdsLmJpbmRGcmFtZWJ1ZmZlciggZ2wuRFJBV19GUkFNRUJVRkZFUiwgbnVsbCApO1xyXG5cdFx0XHRnbC5iaW5kRnJhbWVidWZmZXIoIGdsLlJFQURfRlJBTUVCVUZGRVIsIG51bGwgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Z2wudXNlUHJvZ3JhbSggbnVsbCApO1xyXG5cclxuXHRcdGdsLmxpbmVXaWR0aCggMSApO1xyXG5cclxuXHRcdGdsLnNjaXNzb3IoIDAsIDAsIGdsLmNhbnZhcy53aWR0aCwgZ2wuY2FudmFzLmhlaWdodCApO1xyXG5cdFx0Z2wudmlld3BvcnQoIDAsIDAsIGdsLmNhbnZhcy53aWR0aCwgZ2wuY2FudmFzLmhlaWdodCApO1xyXG5cclxuXHRcdC8vIHJlc2V0IGludGVybmFsc1xyXG5cclxuXHRcdGVuYWJsZWRDYXBhYmlsaXRpZXMgPSB7fTtcclxuXHJcblx0XHRjdXJyZW50VGV4dHVyZVNsb3QgPSBudWxsO1xyXG5cdFx0Y3VycmVudEJvdW5kVGV4dHVyZXMgPSB7fTtcclxuXHJcblx0XHRjdXJyZW50Qm91bmRGcmFtZWJ1ZmZlcnMgPSB7fTtcclxuXHRcdGN1cnJlbnREcmF3YnVmZmVycyA9IG5ldyBXZWFrTWFwKCk7XHJcblx0XHRkZWZhdWx0RHJhd2J1ZmZlcnMgPSBbXTtcclxuXHJcblx0XHRjdXJyZW50UHJvZ3JhbSA9IG51bGw7XHJcblxyXG5cdFx0Y3VycmVudEJsZW5kaW5nRW5hYmxlZCA9IGZhbHNlO1xyXG5cdFx0Y3VycmVudEJsZW5kaW5nID0gbnVsbDtcclxuXHRcdGN1cnJlbnRCbGVuZEVxdWF0aW9uID0gbnVsbDtcclxuXHRcdGN1cnJlbnRCbGVuZFNyYyA9IG51bGw7XHJcblx0XHRjdXJyZW50QmxlbmREc3QgPSBudWxsO1xyXG5cdFx0Y3VycmVudEJsZW5kRXF1YXRpb25BbHBoYSA9IG51bGw7XHJcblx0XHRjdXJyZW50QmxlbmRTcmNBbHBoYSA9IG51bGw7XHJcblx0XHRjdXJyZW50QmxlbmREc3RBbHBoYSA9IG51bGw7XHJcblx0XHRjdXJyZW50QmxlbmRDb2xvciA9IG5ldyBDb2xvciggMCwgMCwgMCApO1xyXG5cdFx0Y3VycmVudEJsZW5kQWxwaGEgPSAwO1xyXG5cdFx0Y3VycmVudFByZW11bHRpcGxlZEFscGhhID0gZmFsc2U7XHJcblxyXG5cdFx0Y3VycmVudEZsaXBTaWRlZCA9IG51bGw7XHJcblx0XHRjdXJyZW50Q3VsbEZhY2UgPSBudWxsO1xyXG5cclxuXHRcdGN1cnJlbnRMaW5lV2lkdGggPSBudWxsO1xyXG5cclxuXHRcdGN1cnJlbnRQb2x5Z29uT2Zmc2V0RmFjdG9yID0gbnVsbDtcclxuXHRcdGN1cnJlbnRQb2x5Z29uT2Zmc2V0VW5pdHMgPSBudWxsO1xyXG5cclxuXHRcdGN1cnJlbnRTY2lzc29yLnNldCggMCwgMCwgZ2wuY2FudmFzLndpZHRoLCBnbC5jYW52YXMuaGVpZ2h0ICk7XHJcblx0XHRjdXJyZW50Vmlld3BvcnQuc2V0KCAwLCAwLCBnbC5jYW52YXMud2lkdGgsIGdsLmNhbnZhcy5oZWlnaHQgKTtcclxuXHJcblx0XHRjb2xvckJ1ZmZlci5yZXNldCgpO1xyXG5cdFx0ZGVwdGhCdWZmZXIucmVzZXQoKTtcclxuXHRcdHN0ZW5jaWxCdWZmZXIucmVzZXQoKTtcclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4ge1xyXG5cclxuXHRcdGJ1ZmZlcnM6IHtcclxuXHRcdFx0Y29sb3I6IGNvbG9yQnVmZmVyLFxyXG5cdFx0XHRkZXB0aDogZGVwdGhCdWZmZXIsXHJcblx0XHRcdHN0ZW5jaWw6IHN0ZW5jaWxCdWZmZXJcclxuXHRcdH0sXHJcblxyXG5cdFx0ZW5hYmxlOiBlbmFibGUsXHJcblx0XHRkaXNhYmxlOiBkaXNhYmxlLFxyXG5cclxuXHRcdGJpbmRGcmFtZWJ1ZmZlcjogYmluZEZyYW1lYnVmZmVyLFxyXG5cdFx0ZHJhd0J1ZmZlcnM6IGRyYXdCdWZmZXJzLFxyXG5cclxuXHRcdHVzZVByb2dyYW06IHVzZVByb2dyYW0sXHJcblxyXG5cdFx0c2V0QmxlbmRpbmc6IHNldEJsZW5kaW5nLFxyXG5cdFx0c2V0TWF0ZXJpYWw6IHNldE1hdGVyaWFsLFxyXG5cclxuXHRcdHNldEZsaXBTaWRlZDogc2V0RmxpcFNpZGVkLFxyXG5cdFx0c2V0Q3VsbEZhY2U6IHNldEN1bGxGYWNlLFxyXG5cclxuXHRcdHNldExpbmVXaWR0aDogc2V0TGluZVdpZHRoLFxyXG5cdFx0c2V0UG9seWdvbk9mZnNldDogc2V0UG9seWdvbk9mZnNldCxcclxuXHJcblx0XHRzZXRTY2lzc29yVGVzdDogc2V0U2Npc3NvclRlc3QsXHJcblxyXG5cdFx0YWN0aXZlVGV4dHVyZTogYWN0aXZlVGV4dHVyZSxcclxuXHRcdGJpbmRUZXh0dXJlOiBiaW5kVGV4dHVyZSxcclxuXHRcdHVuYmluZFRleHR1cmU6IHVuYmluZFRleHR1cmUsXHJcblx0XHRjb21wcmVzc2VkVGV4SW1hZ2UyRDogY29tcHJlc3NlZFRleEltYWdlMkQsXHJcblx0XHRjb21wcmVzc2VkVGV4SW1hZ2UzRDogY29tcHJlc3NlZFRleEltYWdlM0QsXHJcblx0XHR0ZXhJbWFnZTJEOiB0ZXhJbWFnZTJELFxyXG5cdFx0dGV4SW1hZ2UzRDogdGV4SW1hZ2UzRCxcclxuXHJcblx0XHR1cGRhdGVVQk9NYXBwaW5nOiB1cGRhdGVVQk9NYXBwaW5nLFxyXG5cdFx0dW5pZm9ybUJsb2NrQmluZGluZzogdW5pZm9ybUJsb2NrQmluZGluZyxcclxuXHJcblx0XHR0ZXhTdG9yYWdlMkQ6IHRleFN0b3JhZ2UyRCxcclxuXHRcdHRleFN0b3JhZ2UzRDogdGV4U3RvcmFnZTNELFxyXG5cdFx0dGV4U3ViSW1hZ2UyRDogdGV4U3ViSW1hZ2UyRCxcclxuXHRcdHRleFN1YkltYWdlM0Q6IHRleFN1YkltYWdlM0QsXHJcblx0XHRjb21wcmVzc2VkVGV4U3ViSW1hZ2UyRDogY29tcHJlc3NlZFRleFN1YkltYWdlMkQsXHJcblx0XHRjb21wcmVzc2VkVGV4U3ViSW1hZ2UzRDogY29tcHJlc3NlZFRleFN1YkltYWdlM0QsXHJcblxyXG5cdFx0c2Npc3Nvcjogc2Npc3NvcixcclxuXHRcdHZpZXdwb3J0OiB2aWV3cG9ydCxcclxuXHJcblx0XHRyZXNldDogcmVzZXRcclxuXHJcblx0fTtcclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IFdlYkdMU3RhdGUgfTtcclxuIiwiaW1wb3J0IHsgTGluZWFyRmlsdGVyLCBMaW5lYXJNaXBtYXBMaW5lYXJGaWx0ZXIsIExpbmVhck1pcG1hcE5lYXJlc3RGaWx0ZXIsIE5lYXJlc3RGaWx0ZXIsIE5lYXJlc3RNaXBtYXBMaW5lYXJGaWx0ZXIsIE5lYXJlc3RNaXBtYXBOZWFyZXN0RmlsdGVyLCBSR0JBRm9ybWF0LCBSR0JfRVRDMV9Gb3JtYXQsIERlcHRoRm9ybWF0LCBEZXB0aFN0ZW5jaWxGb3JtYXQsIFVuc2lnbmVkU2hvcnRUeXBlLCBVbnNpZ25lZEludFR5cGUsIFVuc2lnbmVkSW50MjQ4VHlwZSwgRmxvYXRUeXBlLCBIYWxmRmxvYXRUeXBlLCBNaXJyb3JlZFJlcGVhdFdyYXBwaW5nLCBDbGFtcFRvRWRnZVdyYXBwaW5nLCBSZXBlYXRXcmFwcGluZywgVW5zaWduZWRCeXRlVHlwZSwgX1NSR0JBRm9ybWF0LCBOb0NvbG9yU3BhY2UsIExpbmVhclNSR0JDb2xvclNwYWNlLCBOZXZlckNvbXBhcmUsIEFsd2F5c0NvbXBhcmUsIExlc3NDb21wYXJlLCBMZXNzRXF1YWxDb21wYXJlLCBFcXVhbENvbXBhcmUsIEdyZWF0ZXJFcXVhbENvbXBhcmUsIEdyZWF0ZXJDb21wYXJlLCBOb3RFcXVhbENvbXBhcmUsIFNSR0JUcmFuc2ZlciwgTGluZWFyVHJhbnNmZXIgfSBmcm9tICcuLi8uLi9jb25zdGFudHMuanMnO1xyXG5pbXBvcnQgKiBhcyBNYXRoVXRpbHMgZnJvbSAnLi4vLi4vbWF0aC9NYXRoVXRpbHMuanMnO1xyXG5pbXBvcnQgeyBJbWFnZVV0aWxzIH0gZnJvbSAnLi4vLi4vZXh0cmFzL0ltYWdlVXRpbHMuanMnO1xyXG5pbXBvcnQgeyBjcmVhdGVFbGVtZW50TlMgfSBmcm9tICcuLi8uLi91dGlscy5qcyc7XHJcbmltcG9ydCB7IENvbG9yTWFuYWdlbWVudCB9IGZyb20gJy4uLy4uL21hdGgvQ29sb3JNYW5hZ2VtZW50LmpzJztcclxuXHJcbmZ1bmN0aW9uIFdlYkdMVGV4dHVyZXMoIF9nbCwgZXh0ZW5zaW9ucywgc3RhdGUsIHByb3BlcnRpZXMsIGNhcGFiaWxpdGllcywgdXRpbHMsIGluZm8gKSB7XHJcblxyXG5cdGNvbnN0IGlzV2ViR0wyID0gY2FwYWJpbGl0aWVzLmlzV2ViR0wyO1xyXG5cdGNvbnN0IG11bHRpc2FtcGxlZFJUVEV4dCA9IGV4dGVuc2lvbnMuaGFzKCAnV0VCR0xfbXVsdGlzYW1wbGVkX3JlbmRlcl90b190ZXh0dXJlJyApID8gZXh0ZW5zaW9ucy5nZXQoICdXRUJHTF9tdWx0aXNhbXBsZWRfcmVuZGVyX3RvX3RleHR1cmUnICkgOiBudWxsO1xyXG5cdGNvbnN0IHN1cHBvcnRzSW52YWxpZGF0ZUZyYW1lYnVmZmVyID0gdHlwZW9mIG5hdmlnYXRvciA9PT0gJ3VuZGVmaW5lZCcgPyBmYWxzZSA6IC9PY3VsdXNCcm93c2VyL2cudGVzdCggbmF2aWdhdG9yLnVzZXJBZ2VudCApO1xyXG5cclxuXHRjb25zdCBfdmlkZW9UZXh0dXJlcyA9IG5ldyBXZWFrTWFwKCk7XHJcblx0bGV0IF9jYW52YXM7XHJcblxyXG5cdGNvbnN0IF9zb3VyY2VzID0gbmV3IFdlYWtNYXAoKTsgLy8gbWFwcyBXZWJnbFRleHR1cmUgb2JqZWN0cyB0byBpbnN0YW5jZXMgb2YgU291cmNlXHJcblxyXG5cdC8vIGNvcmRvdmEgaU9TIChhcyBvZiA1LjApIHN0aWxsIHVzZXMgVUlXZWJWaWV3LCB3aGljaCBwcm92aWRlcyBPZmZzY3JlZW5DYW52YXMsXHJcblx0Ly8gYWxzbyBPZmZzY3JlZW5DYW52YXMuZ2V0Q29udGV4dChcIndlYmdsXCIpLCBidXQgbm90IE9mZnNjcmVlbkNhbnZhcy5nZXRDb250ZXh0KFwiMmRcIikhXHJcblx0Ly8gU29tZSBpbXBsZW1lbnRhdGlvbnMgbWF5IG9ubHkgaW1wbGVtZW50IE9mZnNjcmVlbkNhbnZhcyBwYXJ0aWFsbHkgKGUuZy4gbGFja2luZyAyZCkuXHJcblxyXG5cdGxldCB1c2VPZmZzY3JlZW5DYW52YXMgPSBmYWxzZTtcclxuXHJcblx0dHJ5IHtcclxuXHJcblx0XHR1c2VPZmZzY3JlZW5DYW52YXMgPSB0eXBlb2YgT2Zmc2NyZWVuQ2FudmFzICE9PSAndW5kZWZpbmVkJ1xyXG5cdFx0XHQvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgY29tcGF0L2NvbXBhdFxyXG5cdFx0XHQmJiAoIG5ldyBPZmZzY3JlZW5DYW52YXMoIDEsIDEgKS5nZXRDb250ZXh0KCAnMmQnICkgKSAhPT0gbnVsbDtcclxuXHJcblx0fSBjYXRjaCAoIGVyciApIHtcclxuXHJcblx0XHQvLyBJZ25vcmUgYW55IGVycm9yc1xyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIGNyZWF0ZUNhbnZhcyggd2lkdGgsIGhlaWdodCApIHtcclxuXHJcblx0XHQvLyBVc2UgT2Zmc2NyZWVuQ2FudmFzIHdoZW4gYXZhaWxhYmxlLiBTcGVjaWFsbHkgbmVlZGVkIGluIHdlYiB3b3JrZXJzXHJcblxyXG5cdFx0cmV0dXJuIHVzZU9mZnNjcmVlbkNhbnZhcyA/XHJcblx0XHRcdC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBjb21wYXQvY29tcGF0XHJcblx0XHRcdG5ldyBPZmZzY3JlZW5DYW52YXMoIHdpZHRoLCBoZWlnaHQgKSA6IGNyZWF0ZUVsZW1lbnROUyggJ2NhbnZhcycgKTtcclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiByZXNpemVJbWFnZSggaW1hZ2UsIG5lZWRzUG93ZXJPZlR3bywgbmVlZHNOZXdDYW52YXMsIG1heFNpemUgKSB7XHJcblxyXG5cdFx0bGV0IHNjYWxlID0gMTtcclxuXHJcblx0XHQvLyBoYW5kbGUgY2FzZSBpZiB0ZXh0dXJlIGV4Y2VlZHMgbWF4IHNpemVcclxuXHJcblx0XHRpZiAoIGltYWdlLndpZHRoID4gbWF4U2l6ZSB8fCBpbWFnZS5oZWlnaHQgPiBtYXhTaXplICkge1xyXG5cclxuXHRcdFx0c2NhbGUgPSBtYXhTaXplIC8gTWF0aC5tYXgoIGltYWdlLndpZHRoLCBpbWFnZS5oZWlnaHQgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gb25seSBwZXJmb3JtIHJlc2l6ZSBpZiBuZWNlc3NhcnlcclxuXHJcblx0XHRpZiAoIHNjYWxlIDwgMSB8fCBuZWVkc1Bvd2VyT2ZUd28gPT09IHRydWUgKSB7XHJcblxyXG5cdFx0XHQvLyBvbmx5IHBlcmZvcm0gcmVzaXplIGZvciBjZXJ0YWluIGltYWdlIHR5cGVzXHJcblxyXG5cdFx0XHRpZiAoICggdHlwZW9mIEhUTUxJbWFnZUVsZW1lbnQgIT09ICd1bmRlZmluZWQnICYmIGltYWdlIGluc3RhbmNlb2YgSFRNTEltYWdlRWxlbWVudCApIHx8XHJcblx0XHRcdFx0KCB0eXBlb2YgSFRNTENhbnZhc0VsZW1lbnQgIT09ICd1bmRlZmluZWQnICYmIGltYWdlIGluc3RhbmNlb2YgSFRNTENhbnZhc0VsZW1lbnQgKSB8fFxyXG5cdFx0XHRcdCggdHlwZW9mIEltYWdlQml0bWFwICE9PSAndW5kZWZpbmVkJyAmJiBpbWFnZSBpbnN0YW5jZW9mIEltYWdlQml0bWFwICkgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IGZsb29yID0gbmVlZHNQb3dlck9mVHdvID8gTWF0aFV0aWxzLmZsb29yUG93ZXJPZlR3byA6IE1hdGguZmxvb3I7XHJcblxyXG5cdFx0XHRcdGNvbnN0IHdpZHRoID0gZmxvb3IoIHNjYWxlICogaW1hZ2Uud2lkdGggKTtcclxuXHRcdFx0XHRjb25zdCBoZWlnaHQgPSBmbG9vciggc2NhbGUgKiBpbWFnZS5oZWlnaHQgKTtcclxuXHJcblx0XHRcdFx0aWYgKCBfY2FudmFzID09PSB1bmRlZmluZWQgKSBfY2FudmFzID0gY3JlYXRlQ2FudmFzKCB3aWR0aCwgaGVpZ2h0ICk7XHJcblxyXG5cdFx0XHRcdC8vIGN1YmUgdGV4dHVyZXMgY2FuJ3QgcmV1c2UgdGhlIHNhbWUgY2FudmFzXHJcblxyXG5cdFx0XHRcdGNvbnN0IGNhbnZhcyA9IG5lZWRzTmV3Q2FudmFzID8gY3JlYXRlQ2FudmFzKCB3aWR0aCwgaGVpZ2h0ICkgOiBfY2FudmFzO1xyXG5cclxuXHRcdFx0XHRjYW52YXMud2lkdGggPSB3aWR0aDtcclxuXHRcdFx0XHRjYW52YXMuaGVpZ2h0ID0gaGVpZ2h0O1xyXG5cclxuXHRcdFx0XHRjb25zdCBjb250ZXh0ID0gY2FudmFzLmdldENvbnRleHQoICcyZCcgKTtcclxuXHRcdFx0XHRjb250ZXh0LmRyYXdJbWFnZSggaW1hZ2UsIDAsIDAsIHdpZHRoLCBoZWlnaHQgKTtcclxuXHJcblx0XHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuV2ViR0xSZW5kZXJlcjogVGV4dHVyZSBoYXMgYmVlbiByZXNpemVkIGZyb20gKCcgKyBpbWFnZS53aWR0aCArICd4JyArIGltYWdlLmhlaWdodCArICcpIHRvICgnICsgd2lkdGggKyAneCcgKyBoZWlnaHQgKyAnKS4nICk7XHJcblxyXG5cdFx0XHRcdHJldHVybiBjYW52YXM7XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRpZiAoICdkYXRhJyBpbiBpbWFnZSApIHtcclxuXHJcblx0XHRcdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5XZWJHTFJlbmRlcmVyOiBJbWFnZSBpbiBEYXRhVGV4dHVyZSBpcyB0b28gYmlnICgnICsgaW1hZ2Uud2lkdGggKyAneCcgKyBpbWFnZS5oZWlnaHQgKyAnKS4nICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0cmV0dXJuIGltYWdlO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gaW1hZ2U7XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gaXNQb3dlck9mVHdvKCBpbWFnZSApIHtcclxuXHJcblx0XHRyZXR1cm4gTWF0aFV0aWxzLmlzUG93ZXJPZlR3byggaW1hZ2Uud2lkdGggKSAmJiBNYXRoVXRpbHMuaXNQb3dlck9mVHdvKCBpbWFnZS5oZWlnaHQgKTtcclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiB0ZXh0dXJlTmVlZHNQb3dlck9mVHdvKCB0ZXh0dXJlICkge1xyXG5cclxuXHRcdGlmICggaXNXZWJHTDIgKSByZXR1cm4gZmFsc2U7XHJcblxyXG5cdFx0cmV0dXJuICggdGV4dHVyZS53cmFwUyAhPT0gQ2xhbXBUb0VkZ2VXcmFwcGluZyB8fCB0ZXh0dXJlLndyYXBUICE9PSBDbGFtcFRvRWRnZVdyYXBwaW5nICkgfHxcclxuXHRcdFx0KCB0ZXh0dXJlLm1pbkZpbHRlciAhPT0gTmVhcmVzdEZpbHRlciAmJiB0ZXh0dXJlLm1pbkZpbHRlciAhPT0gTGluZWFyRmlsdGVyICk7XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gdGV4dHVyZU5lZWRzR2VuZXJhdGVNaXBtYXBzKCB0ZXh0dXJlLCBzdXBwb3J0c01pcHMgKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRleHR1cmUuZ2VuZXJhdGVNaXBtYXBzICYmIHN1cHBvcnRzTWlwcyAmJlxyXG5cdFx0XHR0ZXh0dXJlLm1pbkZpbHRlciAhPT0gTmVhcmVzdEZpbHRlciAmJiB0ZXh0dXJlLm1pbkZpbHRlciAhPT0gTGluZWFyRmlsdGVyO1xyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIGdlbmVyYXRlTWlwbWFwKCB0YXJnZXQgKSB7XHJcblxyXG5cdFx0X2dsLmdlbmVyYXRlTWlwbWFwKCB0YXJnZXQgKTtcclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBnZXRJbnRlcm5hbEZvcm1hdCggaW50ZXJuYWxGb3JtYXROYW1lLCBnbEZvcm1hdCwgZ2xUeXBlLCBjb2xvclNwYWNlLCBmb3JjZUxpbmVhclRyYW5zZmVyID0gZmFsc2UgKSB7XHJcblxyXG5cdFx0aWYgKCBpc1dlYkdMMiA9PT0gZmFsc2UgKSByZXR1cm4gZ2xGb3JtYXQ7XHJcblxyXG5cdFx0aWYgKCBpbnRlcm5hbEZvcm1hdE5hbWUgIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRpZiAoIF9nbFsgaW50ZXJuYWxGb3JtYXROYW1lIF0gIT09IHVuZGVmaW5lZCApIHJldHVybiBfZ2xbIGludGVybmFsRm9ybWF0TmFtZSBdO1xyXG5cclxuXHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuV2ViR0xSZW5kZXJlcjogQXR0ZW1wdCB0byB1c2Ugbm9uLWV4aXN0aW5nIFdlYkdMIGludGVybmFsIGZvcm1hdCBcXCcnICsgaW50ZXJuYWxGb3JtYXROYW1lICsgJ1xcJycgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0bGV0IGludGVybmFsRm9ybWF0ID0gZ2xGb3JtYXQ7XHJcblxyXG5cdFx0aWYgKCBnbEZvcm1hdCA9PT0gX2dsLlJFRCApIHtcclxuXHJcblx0XHRcdGlmICggZ2xUeXBlID09PSBfZ2wuRkxPQVQgKSBpbnRlcm5hbEZvcm1hdCA9IF9nbC5SMzJGO1xyXG5cdFx0XHRpZiAoIGdsVHlwZSA9PT0gX2dsLkhBTEZfRkxPQVQgKSBpbnRlcm5hbEZvcm1hdCA9IF9nbC5SMTZGO1xyXG5cdFx0XHRpZiAoIGdsVHlwZSA9PT0gX2dsLlVOU0lHTkVEX0JZVEUgKSBpbnRlcm5hbEZvcm1hdCA9IF9nbC5SODtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBnbEZvcm1hdCA9PT0gX2dsLlJFRF9JTlRFR0VSICkge1xyXG5cclxuXHRcdFx0aWYgKCBnbFR5cGUgPT09IF9nbC5VTlNJR05FRF9CWVRFICkgaW50ZXJuYWxGb3JtYXQgPSBfZ2wuUjhVSTtcclxuXHRcdFx0aWYgKCBnbFR5cGUgPT09IF9nbC5VTlNJR05FRF9TSE9SVCApIGludGVybmFsRm9ybWF0ID0gX2dsLlIxNlVJO1xyXG5cdFx0XHRpZiAoIGdsVHlwZSA9PT0gX2dsLlVOU0lHTkVEX0lOVCApIGludGVybmFsRm9ybWF0ID0gX2dsLlIzMlVJO1xyXG5cdFx0XHRpZiAoIGdsVHlwZSA9PT0gX2dsLkJZVEUgKSBpbnRlcm5hbEZvcm1hdCA9IF9nbC5SOEk7XHJcblx0XHRcdGlmICggZ2xUeXBlID09PSBfZ2wuU0hPUlQgKSBpbnRlcm5hbEZvcm1hdCA9IF9nbC5SMTZJO1xyXG5cdFx0XHRpZiAoIGdsVHlwZSA9PT0gX2dsLklOVCApIGludGVybmFsRm9ybWF0ID0gX2dsLlIzMkk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggZ2xGb3JtYXQgPT09IF9nbC5SRyApIHtcclxuXHJcblx0XHRcdGlmICggZ2xUeXBlID09PSBfZ2wuRkxPQVQgKSBpbnRlcm5hbEZvcm1hdCA9IF9nbC5SRzMyRjtcclxuXHRcdFx0aWYgKCBnbFR5cGUgPT09IF9nbC5IQUxGX0ZMT0FUICkgaW50ZXJuYWxGb3JtYXQgPSBfZ2wuUkcxNkY7XHJcblx0XHRcdGlmICggZ2xUeXBlID09PSBfZ2wuVU5TSUdORURfQllURSApIGludGVybmFsRm9ybWF0ID0gX2dsLlJHODtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBnbEZvcm1hdCA9PT0gX2dsLlJHQkEgKSB7XHJcblxyXG5cdFx0XHRjb25zdCB0cmFuc2ZlciA9IGZvcmNlTGluZWFyVHJhbnNmZXIgPyBMaW5lYXJUcmFuc2ZlciA6IENvbG9yTWFuYWdlbWVudC5nZXRUcmFuc2ZlciggY29sb3JTcGFjZSApO1xyXG5cclxuXHRcdFx0aWYgKCBnbFR5cGUgPT09IF9nbC5GTE9BVCApIGludGVybmFsRm9ybWF0ID0gX2dsLlJHQkEzMkY7XHJcblx0XHRcdGlmICggZ2xUeXBlID09PSBfZ2wuSEFMRl9GTE9BVCApIGludGVybmFsRm9ybWF0ID0gX2dsLlJHQkExNkY7XHJcblx0XHRcdGlmICggZ2xUeXBlID09PSBfZ2wuVU5TSUdORURfQllURSApIGludGVybmFsRm9ybWF0ID0gKCB0cmFuc2ZlciA9PT0gU1JHQlRyYW5zZmVyICkgPyBfZ2wuU1JHQjhfQUxQSEE4IDogX2dsLlJHQkE4O1xyXG5cdFx0XHRpZiAoIGdsVHlwZSA9PT0gX2dsLlVOU0lHTkVEX1NIT1JUXzRfNF80XzQgKSBpbnRlcm5hbEZvcm1hdCA9IF9nbC5SR0JBNDtcclxuXHRcdFx0aWYgKCBnbFR5cGUgPT09IF9nbC5VTlNJR05FRF9TSE9SVF81XzVfNV8xICkgaW50ZXJuYWxGb3JtYXQgPSBfZ2wuUkdCNV9BMTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBpbnRlcm5hbEZvcm1hdCA9PT0gX2dsLlIxNkYgfHwgaW50ZXJuYWxGb3JtYXQgPT09IF9nbC5SMzJGIHx8XHJcblx0XHRcdGludGVybmFsRm9ybWF0ID09PSBfZ2wuUkcxNkYgfHwgaW50ZXJuYWxGb3JtYXQgPT09IF9nbC5SRzMyRiB8fFxyXG5cdFx0XHRpbnRlcm5hbEZvcm1hdCA9PT0gX2dsLlJHQkExNkYgfHwgaW50ZXJuYWxGb3JtYXQgPT09IF9nbC5SR0JBMzJGICkge1xyXG5cclxuXHRcdFx0ZXh0ZW5zaW9ucy5nZXQoICdFWFRfY29sb3JfYnVmZmVyX2Zsb2F0JyApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gaW50ZXJuYWxGb3JtYXQ7XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gZ2V0TWlwTGV2ZWxzKCB0ZXh0dXJlLCBpbWFnZSwgc3VwcG9ydHNNaXBzICkge1xyXG5cclxuXHRcdGlmICggdGV4dHVyZU5lZWRzR2VuZXJhdGVNaXBtYXBzKCB0ZXh0dXJlLCBzdXBwb3J0c01pcHMgKSA9PT0gdHJ1ZSB8fCAoIHRleHR1cmUuaXNGcmFtZWJ1ZmZlclRleHR1cmUgJiYgdGV4dHVyZS5taW5GaWx0ZXIgIT09IE5lYXJlc3RGaWx0ZXIgJiYgdGV4dHVyZS5taW5GaWx0ZXIgIT09IExpbmVhckZpbHRlciApICkge1xyXG5cclxuXHRcdFx0cmV0dXJuIE1hdGgubG9nMiggTWF0aC5tYXgoIGltYWdlLndpZHRoLCBpbWFnZS5oZWlnaHQgKSApICsgMTtcclxuXHJcblx0XHR9IGVsc2UgaWYgKCB0ZXh0dXJlLm1pcG1hcHMgIT09IHVuZGVmaW5lZCAmJiB0ZXh0dXJlLm1pcG1hcHMubGVuZ3RoID4gMCApIHtcclxuXHJcblx0XHRcdC8vIHVzZXItZGVmaW5lZCBtaXBtYXBzXHJcblxyXG5cdFx0XHRyZXR1cm4gdGV4dHVyZS5taXBtYXBzLmxlbmd0aDtcclxuXHJcblx0XHR9IGVsc2UgaWYgKCB0ZXh0dXJlLmlzQ29tcHJlc3NlZFRleHR1cmUgJiYgQXJyYXkuaXNBcnJheSggdGV4dHVyZS5pbWFnZSApICkge1xyXG5cclxuXHRcdFx0cmV0dXJuIGltYWdlLm1pcG1hcHMubGVuZ3RoO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHQvLyB0ZXh0dXJlIHdpdGhvdXQgbWlwbWFwcyAob25seSBiYXNlIGxldmVsKVxyXG5cclxuXHRcdFx0cmV0dXJuIDE7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdC8vIEZhbGxiYWNrIGZpbHRlcnMgZm9yIG5vbi1wb3dlci1vZi0yIHRleHR1cmVzXHJcblxyXG5cdGZ1bmN0aW9uIGZpbHRlckZhbGxiYWNrKCBmICkge1xyXG5cclxuXHRcdGlmICggZiA9PT0gTmVhcmVzdEZpbHRlciB8fCBmID09PSBOZWFyZXN0TWlwbWFwTmVhcmVzdEZpbHRlciB8fCBmID09PSBOZWFyZXN0TWlwbWFwTGluZWFyRmlsdGVyICkge1xyXG5cclxuXHRcdFx0cmV0dXJuIF9nbC5ORUFSRVNUO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gX2dsLkxJTkVBUjtcclxuXHJcblx0fVxyXG5cclxuXHQvL1xyXG5cclxuXHRmdW5jdGlvbiBvblRleHR1cmVEaXNwb3NlKCBldmVudCApIHtcclxuXHJcblx0XHRjb25zdCB0ZXh0dXJlID0gZXZlbnQudGFyZ2V0O1xyXG5cclxuXHRcdHRleHR1cmUucmVtb3ZlRXZlbnRMaXN0ZW5lciggJ2Rpc3Bvc2UnLCBvblRleHR1cmVEaXNwb3NlICk7XHJcblxyXG5cdFx0ZGVhbGxvY2F0ZVRleHR1cmUoIHRleHR1cmUgKTtcclxuXHJcblx0XHRpZiAoIHRleHR1cmUuaXNWaWRlb1RleHR1cmUgKSB7XHJcblxyXG5cdFx0XHRfdmlkZW9UZXh0dXJlcy5kZWxldGUoIHRleHR1cmUgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gb25SZW5kZXJUYXJnZXREaXNwb3NlKCBldmVudCApIHtcclxuXHJcblx0XHRjb25zdCByZW5kZXJUYXJnZXQgPSBldmVudC50YXJnZXQ7XHJcblxyXG5cdFx0cmVuZGVyVGFyZ2V0LnJlbW92ZUV2ZW50TGlzdGVuZXIoICdkaXNwb3NlJywgb25SZW5kZXJUYXJnZXREaXNwb3NlICk7XHJcblxyXG5cdFx0ZGVhbGxvY2F0ZVJlbmRlclRhcmdldCggcmVuZGVyVGFyZ2V0ICk7XHJcblxyXG5cdH1cclxuXHJcblx0Ly9cclxuXHJcblx0ZnVuY3Rpb24gZGVhbGxvY2F0ZVRleHR1cmUoIHRleHR1cmUgKSB7XHJcblxyXG5cdFx0Y29uc3QgdGV4dHVyZVByb3BlcnRpZXMgPSBwcm9wZXJ0aWVzLmdldCggdGV4dHVyZSApO1xyXG5cclxuXHRcdGlmICggdGV4dHVyZVByb3BlcnRpZXMuX193ZWJnbEluaXQgPT09IHVuZGVmaW5lZCApIHJldHVybjtcclxuXHJcblx0XHQvLyBjaGVjayBpZiBpdCdzIG5lY2Vzc2FyeSB0byByZW1vdmUgdGhlIFdlYkdMVGV4dHVyZSBvYmplY3RcclxuXHJcblx0XHRjb25zdCBzb3VyY2UgPSB0ZXh0dXJlLnNvdXJjZTtcclxuXHRcdGNvbnN0IHdlYmdsVGV4dHVyZXMgPSBfc291cmNlcy5nZXQoIHNvdXJjZSApO1xyXG5cclxuXHRcdGlmICggd2ViZ2xUZXh0dXJlcyApIHtcclxuXHJcblx0XHRcdGNvbnN0IHdlYmdsVGV4dHVyZSA9IHdlYmdsVGV4dHVyZXNbIHRleHR1cmVQcm9wZXJ0aWVzLl9fY2FjaGVLZXkgXTtcclxuXHRcdFx0d2ViZ2xUZXh0dXJlLnVzZWRUaW1lcyAtLTtcclxuXHJcblx0XHRcdC8vIHRoZSBXZWJHTFRleHR1cmUgb2JqZWN0IGlzIG5vdCB1c2VkIGFueW1vcmUsIHJlbW92ZSBpdFxyXG5cclxuXHRcdFx0aWYgKCB3ZWJnbFRleHR1cmUudXNlZFRpbWVzID09PSAwICkge1xyXG5cclxuXHRcdFx0XHRkZWxldGVUZXh0dXJlKCB0ZXh0dXJlICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyByZW1vdmUgdGhlIHdlYWsgbWFwIGVudHJ5IGlmIG5vIFdlYkdMVGV4dHVyZSB1c2VzIHRoZSBzb3VyY2UgYW55bW9yZVxyXG5cclxuXHRcdFx0aWYgKCBPYmplY3Qua2V5cyggd2ViZ2xUZXh0dXJlcyApLmxlbmd0aCA9PT0gMCApIHtcclxuXHJcblx0XHRcdFx0X3NvdXJjZXMuZGVsZXRlKCBzb3VyY2UgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cHJvcGVydGllcy5yZW1vdmUoIHRleHR1cmUgKTtcclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBkZWxldGVUZXh0dXJlKCB0ZXh0dXJlICkge1xyXG5cclxuXHRcdGNvbnN0IHRleHR1cmVQcm9wZXJ0aWVzID0gcHJvcGVydGllcy5nZXQoIHRleHR1cmUgKTtcclxuXHRcdF9nbC5kZWxldGVUZXh0dXJlKCB0ZXh0dXJlUHJvcGVydGllcy5fX3dlYmdsVGV4dHVyZSApO1xyXG5cclxuXHRcdGNvbnN0IHNvdXJjZSA9IHRleHR1cmUuc291cmNlO1xyXG5cdFx0Y29uc3Qgd2ViZ2xUZXh0dXJlcyA9IF9zb3VyY2VzLmdldCggc291cmNlICk7XHJcblx0XHRkZWxldGUgd2ViZ2xUZXh0dXJlc1sgdGV4dHVyZVByb3BlcnRpZXMuX19jYWNoZUtleSBdO1xyXG5cclxuXHRcdGluZm8ubWVtb3J5LnRleHR1cmVzIC0tO1xyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIGRlYWxsb2NhdGVSZW5kZXJUYXJnZXQoIHJlbmRlclRhcmdldCApIHtcclxuXHJcblx0XHRjb25zdCB0ZXh0dXJlID0gcmVuZGVyVGFyZ2V0LnRleHR1cmU7XHJcblxyXG5cdFx0Y29uc3QgcmVuZGVyVGFyZ2V0UHJvcGVydGllcyA9IHByb3BlcnRpZXMuZ2V0KCByZW5kZXJUYXJnZXQgKTtcclxuXHRcdGNvbnN0IHRleHR1cmVQcm9wZXJ0aWVzID0gcHJvcGVydGllcy5nZXQoIHRleHR1cmUgKTtcclxuXHJcblx0XHRpZiAoIHRleHR1cmVQcm9wZXJ0aWVzLl9fd2ViZ2xUZXh0dXJlICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRfZ2wuZGVsZXRlVGV4dHVyZSggdGV4dHVyZVByb3BlcnRpZXMuX193ZWJnbFRleHR1cmUgKTtcclxuXHJcblx0XHRcdGluZm8ubWVtb3J5LnRleHR1cmVzIC0tO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHJlbmRlclRhcmdldC5kZXB0aFRleHR1cmUgKSB7XHJcblxyXG5cdFx0XHRyZW5kZXJUYXJnZXQuZGVwdGhUZXh0dXJlLmRpc3Bvc2UoKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCByZW5kZXJUYXJnZXQuaXNXZWJHTEN1YmVSZW5kZXJUYXJnZXQgKSB7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCA2OyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRpZiAoIEFycmF5LmlzQXJyYXkoIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbEZyYW1lYnVmZmVyWyBpIF0gKSApIHtcclxuXHJcblx0XHRcdFx0XHRmb3IgKCBsZXQgbGV2ZWwgPSAwOyBsZXZlbCA8IHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbEZyYW1lYnVmZmVyWyBpIF0ubGVuZ3RoOyBsZXZlbCArKyApIF9nbC5kZWxldGVGcmFtZWJ1ZmZlciggcmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX3dlYmdsRnJhbWVidWZmZXJbIGkgXVsgbGV2ZWwgXSApO1xyXG5cclxuXHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdF9nbC5kZWxldGVGcmFtZWJ1ZmZlciggcmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX3dlYmdsRnJhbWVidWZmZXJbIGkgXSApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdGlmICggcmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX3dlYmdsRGVwdGhidWZmZXIgKSBfZ2wuZGVsZXRlUmVuZGVyYnVmZmVyKCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xEZXB0aGJ1ZmZlclsgaSBdICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdGlmICggQXJyYXkuaXNBcnJheSggcmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX3dlYmdsRnJhbWVidWZmZXIgKSApIHtcclxuXHJcblx0XHRcdFx0Zm9yICggbGV0IGxldmVsID0gMDsgbGV2ZWwgPCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xGcmFtZWJ1ZmZlci5sZW5ndGg7IGxldmVsICsrICkgX2dsLmRlbGV0ZUZyYW1lYnVmZmVyKCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xGcmFtZWJ1ZmZlclsgbGV2ZWwgXSApO1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0X2dsLmRlbGV0ZUZyYW1lYnVmZmVyKCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xGcmFtZWJ1ZmZlciApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0aWYgKCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xEZXB0aGJ1ZmZlciApIF9nbC5kZWxldGVSZW5kZXJidWZmZXIoIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbERlcHRoYnVmZmVyICk7XHJcblx0XHRcdGlmICggcmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX3dlYmdsTXVsdGlzYW1wbGVkRnJhbWVidWZmZXIgKSBfZ2wuZGVsZXRlRnJhbWVidWZmZXIoIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbE11bHRpc2FtcGxlZEZyYW1lYnVmZmVyICk7XHJcblxyXG5cdFx0XHRpZiAoIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbENvbG9yUmVuZGVyYnVmZmVyICkge1xyXG5cclxuXHRcdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xDb2xvclJlbmRlcmJ1ZmZlci5sZW5ndGg7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xDb2xvclJlbmRlcmJ1ZmZlclsgaSBdICkgX2dsLmRlbGV0ZVJlbmRlcmJ1ZmZlciggcmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX3dlYmdsQ29sb3JSZW5kZXJidWZmZXJbIGkgXSApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRpZiAoIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbERlcHRoUmVuZGVyYnVmZmVyICkgX2dsLmRlbGV0ZVJlbmRlcmJ1ZmZlciggcmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX3dlYmdsRGVwdGhSZW5kZXJidWZmZXIgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCByZW5kZXJUYXJnZXQuaXNXZWJHTE11bHRpcGxlUmVuZGVyVGFyZ2V0cyApIHtcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSB0ZXh0dXJlLmxlbmd0aDsgaSA8IGlsOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBhdHRhY2htZW50UHJvcGVydGllcyA9IHByb3BlcnRpZXMuZ2V0KCB0ZXh0dXJlWyBpIF0gKTtcclxuXHJcblx0XHRcdFx0aWYgKCBhdHRhY2htZW50UHJvcGVydGllcy5fX3dlYmdsVGV4dHVyZSApIHtcclxuXHJcblx0XHRcdFx0XHRfZ2wuZGVsZXRlVGV4dHVyZSggYXR0YWNobWVudFByb3BlcnRpZXMuX193ZWJnbFRleHR1cmUgKTtcclxuXHJcblx0XHRcdFx0XHRpbmZvLm1lbW9yeS50ZXh0dXJlcyAtLTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRwcm9wZXJ0aWVzLnJlbW92ZSggdGV4dHVyZVsgaSBdICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHByb3BlcnRpZXMucmVtb3ZlKCB0ZXh0dXJlICk7XHJcblx0XHRwcm9wZXJ0aWVzLnJlbW92ZSggcmVuZGVyVGFyZ2V0ICk7XHJcblxyXG5cdH1cclxuXHJcblx0Ly9cclxuXHJcblx0bGV0IHRleHR1cmVVbml0cyA9IDA7XHJcblxyXG5cdGZ1bmN0aW9uIHJlc2V0VGV4dHVyZVVuaXRzKCkge1xyXG5cclxuXHRcdHRleHR1cmVVbml0cyA9IDA7XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gYWxsb2NhdGVUZXh0dXJlVW5pdCgpIHtcclxuXHJcblx0XHRjb25zdCB0ZXh0dXJlVW5pdCA9IHRleHR1cmVVbml0cztcclxuXHJcblx0XHRpZiAoIHRleHR1cmVVbml0ID49IGNhcGFiaWxpdGllcy5tYXhUZXh0dXJlcyApIHtcclxuXHJcblx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLldlYkdMVGV4dHVyZXM6IFRyeWluZyB0byB1c2UgJyArIHRleHR1cmVVbml0ICsgJyB0ZXh0dXJlIHVuaXRzIHdoaWxlIHRoaXMgR1BVIHN1cHBvcnRzIG9ubHkgJyArIGNhcGFiaWxpdGllcy5tYXhUZXh0dXJlcyApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHR0ZXh0dXJlVW5pdHMgKz0gMTtcclxuXHJcblx0XHRyZXR1cm4gdGV4dHVyZVVuaXQ7XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gZ2V0VGV4dHVyZUNhY2hlS2V5KCB0ZXh0dXJlICkge1xyXG5cclxuXHRcdGNvbnN0IGFycmF5ID0gW107XHJcblxyXG5cdFx0YXJyYXkucHVzaCggdGV4dHVyZS53cmFwUyApO1xyXG5cdFx0YXJyYXkucHVzaCggdGV4dHVyZS53cmFwVCApO1xyXG5cdFx0YXJyYXkucHVzaCggdGV4dHVyZS53cmFwUiB8fCAwICk7XHJcblx0XHRhcnJheS5wdXNoKCB0ZXh0dXJlLm1hZ0ZpbHRlciApO1xyXG5cdFx0YXJyYXkucHVzaCggdGV4dHVyZS5taW5GaWx0ZXIgKTtcclxuXHRcdGFycmF5LnB1c2goIHRleHR1cmUuYW5pc290cm9weSApO1xyXG5cdFx0YXJyYXkucHVzaCggdGV4dHVyZS5pbnRlcm5hbEZvcm1hdCApO1xyXG5cdFx0YXJyYXkucHVzaCggdGV4dHVyZS5mb3JtYXQgKTtcclxuXHRcdGFycmF5LnB1c2goIHRleHR1cmUudHlwZSApO1xyXG5cdFx0YXJyYXkucHVzaCggdGV4dHVyZS5nZW5lcmF0ZU1pcG1hcHMgKTtcclxuXHRcdGFycmF5LnB1c2goIHRleHR1cmUucHJlbXVsdGlwbHlBbHBoYSApO1xyXG5cdFx0YXJyYXkucHVzaCggdGV4dHVyZS5mbGlwWSApO1xyXG5cdFx0YXJyYXkucHVzaCggdGV4dHVyZS51bnBhY2tBbGlnbm1lbnQgKTtcclxuXHRcdGFycmF5LnB1c2goIHRleHR1cmUuY29sb3JTcGFjZSApO1xyXG5cclxuXHRcdHJldHVybiBhcnJheS5qb2luKCk7XHJcblxyXG5cdH1cclxuXHJcblx0Ly9cclxuXHJcblx0ZnVuY3Rpb24gc2V0VGV4dHVyZTJEKCB0ZXh0dXJlLCBzbG90ICkge1xyXG5cclxuXHRcdGNvbnN0IHRleHR1cmVQcm9wZXJ0aWVzID0gcHJvcGVydGllcy5nZXQoIHRleHR1cmUgKTtcclxuXHJcblx0XHRpZiAoIHRleHR1cmUuaXNWaWRlb1RleHR1cmUgKSB1cGRhdGVWaWRlb1RleHR1cmUoIHRleHR1cmUgKTtcclxuXHJcblx0XHRpZiAoIHRleHR1cmUuaXNSZW5kZXJUYXJnZXRUZXh0dXJlID09PSBmYWxzZSAmJiB0ZXh0dXJlLnZlcnNpb24gPiAwICYmIHRleHR1cmVQcm9wZXJ0aWVzLl9fdmVyc2lvbiAhPT0gdGV4dHVyZS52ZXJzaW9uICkge1xyXG5cclxuXHRcdFx0Y29uc3QgaW1hZ2UgPSB0ZXh0dXJlLmltYWdlO1xyXG5cclxuXHRcdFx0aWYgKCBpbWFnZSA9PT0gbnVsbCApIHtcclxuXHJcblx0XHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuV2ViR0xSZW5kZXJlcjogVGV4dHVyZSBtYXJrZWQgZm9yIHVwZGF0ZSBidXQgbm8gaW1hZ2UgZGF0YSBmb3VuZC4nICk7XHJcblxyXG5cdFx0XHR9IGVsc2UgaWYgKCBpbWFnZS5jb21wbGV0ZSA9PT0gZmFsc2UgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLldlYkdMUmVuZGVyZXI6IFRleHR1cmUgbWFya2VkIGZvciB1cGRhdGUgYnV0IGltYWdlIGlzIGluY29tcGxldGUnICk7XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHR1cGxvYWRUZXh0dXJlKCB0ZXh0dXJlUHJvcGVydGllcywgdGV4dHVyZSwgc2xvdCApO1xyXG5cdFx0XHRcdHJldHVybjtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0c3RhdGUuYmluZFRleHR1cmUoIF9nbC5URVhUVVJFXzJELCB0ZXh0dXJlUHJvcGVydGllcy5fX3dlYmdsVGV4dHVyZSwgX2dsLlRFWFRVUkUwICsgc2xvdCApO1xyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHNldFRleHR1cmUyREFycmF5KCB0ZXh0dXJlLCBzbG90ICkge1xyXG5cclxuXHRcdGNvbnN0IHRleHR1cmVQcm9wZXJ0aWVzID0gcHJvcGVydGllcy5nZXQoIHRleHR1cmUgKTtcclxuXHJcblx0XHRpZiAoIHRleHR1cmUudmVyc2lvbiA+IDAgJiYgdGV4dHVyZVByb3BlcnRpZXMuX192ZXJzaW9uICE9PSB0ZXh0dXJlLnZlcnNpb24gKSB7XHJcblxyXG5cdFx0XHR1cGxvYWRUZXh0dXJlKCB0ZXh0dXJlUHJvcGVydGllcywgdGV4dHVyZSwgc2xvdCApO1xyXG5cdFx0XHRyZXR1cm47XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHN0YXRlLmJpbmRUZXh0dXJlKCBfZ2wuVEVYVFVSRV8yRF9BUlJBWSwgdGV4dHVyZVByb3BlcnRpZXMuX193ZWJnbFRleHR1cmUsIF9nbC5URVhUVVJFMCArIHNsb3QgKTtcclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBzZXRUZXh0dXJlM0QoIHRleHR1cmUsIHNsb3QgKSB7XHJcblxyXG5cdFx0Y29uc3QgdGV4dHVyZVByb3BlcnRpZXMgPSBwcm9wZXJ0aWVzLmdldCggdGV4dHVyZSApO1xyXG5cclxuXHRcdGlmICggdGV4dHVyZS52ZXJzaW9uID4gMCAmJiB0ZXh0dXJlUHJvcGVydGllcy5fX3ZlcnNpb24gIT09IHRleHR1cmUudmVyc2lvbiApIHtcclxuXHJcblx0XHRcdHVwbG9hZFRleHR1cmUoIHRleHR1cmVQcm9wZXJ0aWVzLCB0ZXh0dXJlLCBzbG90ICk7XHJcblx0XHRcdHJldHVybjtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0c3RhdGUuYmluZFRleHR1cmUoIF9nbC5URVhUVVJFXzNELCB0ZXh0dXJlUHJvcGVydGllcy5fX3dlYmdsVGV4dHVyZSwgX2dsLlRFWFRVUkUwICsgc2xvdCApO1xyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHNldFRleHR1cmVDdWJlKCB0ZXh0dXJlLCBzbG90ICkge1xyXG5cclxuXHRcdGNvbnN0IHRleHR1cmVQcm9wZXJ0aWVzID0gcHJvcGVydGllcy5nZXQoIHRleHR1cmUgKTtcclxuXHJcblx0XHRpZiAoIHRleHR1cmUudmVyc2lvbiA+IDAgJiYgdGV4dHVyZVByb3BlcnRpZXMuX192ZXJzaW9uICE9PSB0ZXh0dXJlLnZlcnNpb24gKSB7XHJcblxyXG5cdFx0XHR1cGxvYWRDdWJlVGV4dHVyZSggdGV4dHVyZVByb3BlcnRpZXMsIHRleHR1cmUsIHNsb3QgKTtcclxuXHRcdFx0cmV0dXJuO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRzdGF0ZS5iaW5kVGV4dHVyZSggX2dsLlRFWFRVUkVfQ1VCRV9NQVAsIHRleHR1cmVQcm9wZXJ0aWVzLl9fd2ViZ2xUZXh0dXJlLCBfZ2wuVEVYVFVSRTAgKyBzbG90ICk7XHJcblxyXG5cdH1cclxuXHJcblx0Y29uc3Qgd3JhcHBpbmdUb0dMID0ge1xyXG5cdFx0WyBSZXBlYXRXcmFwcGluZyBdOiBfZ2wuUkVQRUFULFxyXG5cdFx0WyBDbGFtcFRvRWRnZVdyYXBwaW5nIF06IF9nbC5DTEFNUF9UT19FREdFLFxyXG5cdFx0WyBNaXJyb3JlZFJlcGVhdFdyYXBwaW5nIF06IF9nbC5NSVJST1JFRF9SRVBFQVRcclxuXHR9O1xyXG5cclxuXHRjb25zdCBmaWx0ZXJUb0dMID0ge1xyXG5cdFx0WyBOZWFyZXN0RmlsdGVyIF06IF9nbC5ORUFSRVNULFxyXG5cdFx0WyBOZWFyZXN0TWlwbWFwTmVhcmVzdEZpbHRlciBdOiBfZ2wuTkVBUkVTVF9NSVBNQVBfTkVBUkVTVCxcclxuXHRcdFsgTmVhcmVzdE1pcG1hcExpbmVhckZpbHRlciBdOiBfZ2wuTkVBUkVTVF9NSVBNQVBfTElORUFSLFxyXG5cclxuXHRcdFsgTGluZWFyRmlsdGVyIF06IF9nbC5MSU5FQVIsXHJcblx0XHRbIExpbmVhck1pcG1hcE5lYXJlc3RGaWx0ZXIgXTogX2dsLkxJTkVBUl9NSVBNQVBfTkVBUkVTVCxcclxuXHRcdFsgTGluZWFyTWlwbWFwTGluZWFyRmlsdGVyIF06IF9nbC5MSU5FQVJfTUlQTUFQX0xJTkVBUlxyXG5cdH07XHJcblxyXG5cdGNvbnN0IGNvbXBhcmVUb0dMID0ge1xyXG5cdFx0WyBOZXZlckNvbXBhcmUgXTogX2dsLk5FVkVSLFxyXG5cdFx0WyBBbHdheXNDb21wYXJlIF06IF9nbC5BTFdBWVMsXHJcblx0XHRbIExlc3NDb21wYXJlIF06IF9nbC5MRVNTLFxyXG5cdFx0WyBMZXNzRXF1YWxDb21wYXJlIF06IF9nbC5MRVFVQUwsXHJcblx0XHRbIEVxdWFsQ29tcGFyZSBdOiBfZ2wuRVFVQUwsXHJcblx0XHRbIEdyZWF0ZXJFcXVhbENvbXBhcmUgXTogX2dsLkdFUVVBTCxcclxuXHRcdFsgR3JlYXRlckNvbXBhcmUgXTogX2dsLkdSRUFURVIsXHJcblx0XHRbIE5vdEVxdWFsQ29tcGFyZSBdOiBfZ2wuTk9URVFVQUxcclxuXHR9O1xyXG5cclxuXHRmdW5jdGlvbiBzZXRUZXh0dXJlUGFyYW1ldGVycyggdGV4dHVyZVR5cGUsIHRleHR1cmUsIHN1cHBvcnRzTWlwcyApIHtcclxuXHJcblx0XHRpZiAoIHRleHR1cmUudHlwZSA9PT0gRmxvYXRUeXBlICYmIGV4dGVuc2lvbnMuaGFzKCAnT0VTX3RleHR1cmVfZmxvYXRfbGluZWFyJyApID09PSBmYWxzZSAmJlxyXG5cdFx0XHQoIHRleHR1cmUubWFnRmlsdGVyID09PSBMaW5lYXJGaWx0ZXIgfHwgdGV4dHVyZS5tYWdGaWx0ZXIgPT09IExpbmVhck1pcG1hcE5lYXJlc3RGaWx0ZXIgfHwgdGV4dHVyZS5tYWdGaWx0ZXIgPT09IE5lYXJlc3RNaXBtYXBMaW5lYXJGaWx0ZXIgfHwgdGV4dHVyZS5tYWdGaWx0ZXIgPT09IExpbmVhck1pcG1hcExpbmVhckZpbHRlciB8fFxyXG5cdFx0XHR0ZXh0dXJlLm1pbkZpbHRlciA9PT0gTGluZWFyRmlsdGVyIHx8IHRleHR1cmUubWluRmlsdGVyID09PSBMaW5lYXJNaXBtYXBOZWFyZXN0RmlsdGVyIHx8IHRleHR1cmUubWluRmlsdGVyID09PSBOZWFyZXN0TWlwbWFwTGluZWFyRmlsdGVyIHx8IHRleHR1cmUubWluRmlsdGVyID09PSBMaW5lYXJNaXBtYXBMaW5lYXJGaWx0ZXIgKSApIHtcclxuXHJcblx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLldlYkdMUmVuZGVyZXI6IFVuYWJsZSB0byB1c2UgbGluZWFyIGZpbHRlcmluZyB3aXRoIGZsb2F0aW5nIHBvaW50IHRleHR1cmVzLiBPRVNfdGV4dHVyZV9mbG9hdF9saW5lYXIgbm90IHN1cHBvcnRlZCBvbiB0aGlzIGRldmljZS4nICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggc3VwcG9ydHNNaXBzICkge1xyXG5cclxuXHRcdFx0X2dsLnRleFBhcmFtZXRlcmkoIHRleHR1cmVUeXBlLCBfZ2wuVEVYVFVSRV9XUkFQX1MsIHdyYXBwaW5nVG9HTFsgdGV4dHVyZS53cmFwUyBdICk7XHJcblx0XHRcdF9nbC50ZXhQYXJhbWV0ZXJpKCB0ZXh0dXJlVHlwZSwgX2dsLlRFWFRVUkVfV1JBUF9ULCB3cmFwcGluZ1RvR0xbIHRleHR1cmUud3JhcFQgXSApO1xyXG5cclxuXHRcdFx0aWYgKCB0ZXh0dXJlVHlwZSA9PT0gX2dsLlRFWFRVUkVfM0QgfHwgdGV4dHVyZVR5cGUgPT09IF9nbC5URVhUVVJFXzJEX0FSUkFZICkge1xyXG5cclxuXHRcdFx0XHRfZ2wudGV4UGFyYW1ldGVyaSggdGV4dHVyZVR5cGUsIF9nbC5URVhUVVJFX1dSQVBfUiwgd3JhcHBpbmdUb0dMWyB0ZXh0dXJlLndyYXBSIF0gKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdF9nbC50ZXhQYXJhbWV0ZXJpKCB0ZXh0dXJlVHlwZSwgX2dsLlRFWFRVUkVfTUFHX0ZJTFRFUiwgZmlsdGVyVG9HTFsgdGV4dHVyZS5tYWdGaWx0ZXIgXSApO1xyXG5cdFx0XHRfZ2wudGV4UGFyYW1ldGVyaSggdGV4dHVyZVR5cGUsIF9nbC5URVhUVVJFX01JTl9GSUxURVIsIGZpbHRlclRvR0xbIHRleHR1cmUubWluRmlsdGVyIF0gKTtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0X2dsLnRleFBhcmFtZXRlcmkoIHRleHR1cmVUeXBlLCBfZ2wuVEVYVFVSRV9XUkFQX1MsIF9nbC5DTEFNUF9UT19FREdFICk7XHJcblx0XHRcdF9nbC50ZXhQYXJhbWV0ZXJpKCB0ZXh0dXJlVHlwZSwgX2dsLlRFWFRVUkVfV1JBUF9ULCBfZ2wuQ0xBTVBfVE9fRURHRSApO1xyXG5cclxuXHRcdFx0aWYgKCB0ZXh0dXJlVHlwZSA9PT0gX2dsLlRFWFRVUkVfM0QgfHwgdGV4dHVyZVR5cGUgPT09IF9nbC5URVhUVVJFXzJEX0FSUkFZICkge1xyXG5cclxuXHRcdFx0XHRfZ2wudGV4UGFyYW1ldGVyaSggdGV4dHVyZVR5cGUsIF9nbC5URVhUVVJFX1dSQVBfUiwgX2dsLkNMQU1QX1RPX0VER0UgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGlmICggdGV4dHVyZS53cmFwUyAhPT0gQ2xhbXBUb0VkZ2VXcmFwcGluZyB8fCB0ZXh0dXJlLndyYXBUICE9PSBDbGFtcFRvRWRnZVdyYXBwaW5nICkge1xyXG5cclxuXHRcdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5XZWJHTFJlbmRlcmVyOiBUZXh0dXJlIGlzIG5vdCBwb3dlciBvZiB0d28uIFRleHR1cmUud3JhcFMgYW5kIFRleHR1cmUud3JhcFQgc2hvdWxkIGJlIHNldCB0byBUSFJFRS5DbGFtcFRvRWRnZVdyYXBwaW5nLicgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdF9nbC50ZXhQYXJhbWV0ZXJpKCB0ZXh0dXJlVHlwZSwgX2dsLlRFWFRVUkVfTUFHX0ZJTFRFUiwgZmlsdGVyRmFsbGJhY2soIHRleHR1cmUubWFnRmlsdGVyICkgKTtcclxuXHRcdFx0X2dsLnRleFBhcmFtZXRlcmkoIHRleHR1cmVUeXBlLCBfZ2wuVEVYVFVSRV9NSU5fRklMVEVSLCBmaWx0ZXJGYWxsYmFjayggdGV4dHVyZS5taW5GaWx0ZXIgKSApO1xyXG5cclxuXHRcdFx0aWYgKCB0ZXh0dXJlLm1pbkZpbHRlciAhPT0gTmVhcmVzdEZpbHRlciAmJiB0ZXh0dXJlLm1pbkZpbHRlciAhPT0gTGluZWFyRmlsdGVyICkge1xyXG5cclxuXHRcdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5XZWJHTFJlbmRlcmVyOiBUZXh0dXJlIGlzIG5vdCBwb3dlciBvZiB0d28uIFRleHR1cmUubWluRmlsdGVyIHNob3VsZCBiZSBzZXQgdG8gVEhSRUUuTmVhcmVzdEZpbHRlciBvciBUSFJFRS5MaW5lYXJGaWx0ZXIuJyApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHRleHR1cmUuY29tcGFyZUZ1bmN0aW9uICkge1xyXG5cclxuXHRcdFx0X2dsLnRleFBhcmFtZXRlcmkoIHRleHR1cmVUeXBlLCBfZ2wuVEVYVFVSRV9DT01QQVJFX01PREUsIF9nbC5DT01QQVJFX1JFRl9UT19URVhUVVJFICk7XHJcblx0XHRcdF9nbC50ZXhQYXJhbWV0ZXJpKCB0ZXh0dXJlVHlwZSwgX2dsLlRFWFRVUkVfQ09NUEFSRV9GVU5DLCBjb21wYXJlVG9HTFsgdGV4dHVyZS5jb21wYXJlRnVuY3Rpb24gXSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIGV4dGVuc2lvbnMuaGFzKCAnRVhUX3RleHR1cmVfZmlsdGVyX2FuaXNvdHJvcGljJyApID09PSB0cnVlICkge1xyXG5cclxuXHRcdFx0Y29uc3QgZXh0ZW5zaW9uID0gZXh0ZW5zaW9ucy5nZXQoICdFWFRfdGV4dHVyZV9maWx0ZXJfYW5pc290cm9waWMnICk7XHJcblxyXG5cdFx0XHRpZiAoIHRleHR1cmUubWFnRmlsdGVyID09PSBOZWFyZXN0RmlsdGVyICkgcmV0dXJuO1xyXG5cdFx0XHRpZiAoIHRleHR1cmUubWluRmlsdGVyICE9PSBOZWFyZXN0TWlwbWFwTGluZWFyRmlsdGVyICYmIHRleHR1cmUubWluRmlsdGVyICE9PSBMaW5lYXJNaXBtYXBMaW5lYXJGaWx0ZXIgKSByZXR1cm47XHJcblx0XHRcdGlmICggdGV4dHVyZS50eXBlID09PSBGbG9hdFR5cGUgJiYgZXh0ZW5zaW9ucy5oYXMoICdPRVNfdGV4dHVyZV9mbG9hdF9saW5lYXInICkgPT09IGZhbHNlICkgcmV0dXJuOyAvLyB2ZXJpZnkgZXh0ZW5zaW9uIGZvciBXZWJHTCAxIGFuZCBXZWJHTCAyXHJcblx0XHRcdGlmICggaXNXZWJHTDIgPT09IGZhbHNlICYmICggdGV4dHVyZS50eXBlID09PSBIYWxmRmxvYXRUeXBlICYmIGV4dGVuc2lvbnMuaGFzKCAnT0VTX3RleHR1cmVfaGFsZl9mbG9hdF9saW5lYXInICkgPT09IGZhbHNlICkgKSByZXR1cm47IC8vIHZlcmlmeSBleHRlbnNpb24gZm9yIFdlYkdMIDEgb25seVxyXG5cclxuXHRcdFx0aWYgKCB0ZXh0dXJlLmFuaXNvdHJvcHkgPiAxIHx8IHByb3BlcnRpZXMuZ2V0KCB0ZXh0dXJlICkuX19jdXJyZW50QW5pc290cm9weSApIHtcclxuXHJcblx0XHRcdFx0X2dsLnRleFBhcmFtZXRlcmYoIHRleHR1cmVUeXBlLCBleHRlbnNpb24uVEVYVFVSRV9NQVhfQU5JU09UUk9QWV9FWFQsIE1hdGgubWluKCB0ZXh0dXJlLmFuaXNvdHJvcHksIGNhcGFiaWxpdGllcy5nZXRNYXhBbmlzb3Ryb3B5KCkgKSApO1xyXG5cdFx0XHRcdHByb3BlcnRpZXMuZ2V0KCB0ZXh0dXJlICkuX19jdXJyZW50QW5pc290cm9weSA9IHRleHR1cmUuYW5pc290cm9weTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gaW5pdFRleHR1cmUoIHRleHR1cmVQcm9wZXJ0aWVzLCB0ZXh0dXJlICkge1xyXG5cclxuXHRcdGxldCBmb3JjZVVwbG9hZCA9IGZhbHNlO1xyXG5cclxuXHRcdGlmICggdGV4dHVyZVByb3BlcnRpZXMuX193ZWJnbEluaXQgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdHRleHR1cmVQcm9wZXJ0aWVzLl9fd2ViZ2xJbml0ID0gdHJ1ZTtcclxuXHJcblx0XHRcdHRleHR1cmUuYWRkRXZlbnRMaXN0ZW5lciggJ2Rpc3Bvc2UnLCBvblRleHR1cmVEaXNwb3NlICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIGNyZWF0ZSBTb3VyY2UgPC0+IFdlYkdMVGV4dHVyZXMgbWFwcGluZyBpZiBuZWNlc3NhcnlcclxuXHJcblx0XHRjb25zdCBzb3VyY2UgPSB0ZXh0dXJlLnNvdXJjZTtcclxuXHRcdGxldCB3ZWJnbFRleHR1cmVzID0gX3NvdXJjZXMuZ2V0KCBzb3VyY2UgKTtcclxuXHJcblx0XHRpZiAoIHdlYmdsVGV4dHVyZXMgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdHdlYmdsVGV4dHVyZXMgPSB7fTtcclxuXHRcdFx0X3NvdXJjZXMuc2V0KCBzb3VyY2UsIHdlYmdsVGV4dHVyZXMgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gY2hlY2sgaWYgdGhlcmUgaXMgYWxyZWFkeSBhIFdlYkdMVGV4dHVyZSBvYmplY3QgZm9yIHRoZSBnaXZlbiB0ZXh0dXJlIHBhcmFtZXRlcnNcclxuXHJcblx0XHRjb25zdCB0ZXh0dXJlQ2FjaGVLZXkgPSBnZXRUZXh0dXJlQ2FjaGVLZXkoIHRleHR1cmUgKTtcclxuXHJcblx0XHRpZiAoIHRleHR1cmVDYWNoZUtleSAhPT0gdGV4dHVyZVByb3BlcnRpZXMuX19jYWNoZUtleSApIHtcclxuXHJcblx0XHRcdC8vIGlmIG5vdCwgY3JlYXRlIGEgbmV3IGluc3RhbmNlIG9mIFdlYkdMVGV4dHVyZVxyXG5cclxuXHRcdFx0aWYgKCB3ZWJnbFRleHR1cmVzWyB0ZXh0dXJlQ2FjaGVLZXkgXSA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHQvLyBjcmVhdGUgbmV3IGVudHJ5XHJcblxyXG5cdFx0XHRcdHdlYmdsVGV4dHVyZXNbIHRleHR1cmVDYWNoZUtleSBdID0ge1xyXG5cdFx0XHRcdFx0dGV4dHVyZTogX2dsLmNyZWF0ZVRleHR1cmUoKSxcclxuXHRcdFx0XHRcdHVzZWRUaW1lczogMFxyXG5cdFx0XHRcdH07XHJcblxyXG5cdFx0XHRcdGluZm8ubWVtb3J5LnRleHR1cmVzICsrO1xyXG5cclxuXHRcdFx0XHQvLyB3aGVuIGEgbmV3IGluc3RhbmNlIG9mIFdlYkdMVGV4dHVyZSB3YXMgY3JlYXRlZCwgYSB0ZXh0dXJlIHVwbG9hZCBpcyByZXF1aXJlZFxyXG5cdFx0XHRcdC8vIGV2ZW4gaWYgdGhlIGltYWdlIGNvbnRlbnRzIGFyZSBpZGVudGljYWxcclxuXHJcblx0XHRcdFx0Zm9yY2VVcGxvYWQgPSB0cnVlO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0d2ViZ2xUZXh0dXJlc1sgdGV4dHVyZUNhY2hlS2V5IF0udXNlZFRpbWVzICsrO1xyXG5cclxuXHRcdFx0Ly8gZXZlcnkgdGltZSB0aGUgdGV4dHVyZSBjYWNoZSBrZXkgY2hhbmdlcywgaXQncyBuZWNlc3NhcnkgdG8gY2hlY2sgaWYgYW4gaW5zdGFuY2Ugb2ZcclxuXHRcdFx0Ly8gV2ViR0xUZXh0dXJlIGNhbiBiZSBkZWxldGVkIGluIG9yZGVyIHRvIGF2b2lkIGEgbWVtb3J5IGxlYWsuXHJcblxyXG5cdFx0XHRjb25zdCB3ZWJnbFRleHR1cmUgPSB3ZWJnbFRleHR1cmVzWyB0ZXh0dXJlUHJvcGVydGllcy5fX2NhY2hlS2V5IF07XHJcblxyXG5cdFx0XHRpZiAoIHdlYmdsVGV4dHVyZSAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHR3ZWJnbFRleHR1cmVzWyB0ZXh0dXJlUHJvcGVydGllcy5fX2NhY2hlS2V5IF0udXNlZFRpbWVzIC0tO1xyXG5cclxuXHRcdFx0XHRpZiAoIHdlYmdsVGV4dHVyZS51c2VkVGltZXMgPT09IDAgKSB7XHJcblxyXG5cdFx0XHRcdFx0ZGVsZXRlVGV4dHVyZSggdGV4dHVyZSApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyBzdG9yZSByZWZlcmVuY2VzIHRvIGNhY2hlIGtleSBhbmQgV2ViR0xUZXh0dXJlIG9iamVjdFxyXG5cclxuXHRcdFx0dGV4dHVyZVByb3BlcnRpZXMuX19jYWNoZUtleSA9IHRleHR1cmVDYWNoZUtleTtcclxuXHRcdFx0dGV4dHVyZVByb3BlcnRpZXMuX193ZWJnbFRleHR1cmUgPSB3ZWJnbFRleHR1cmVzWyB0ZXh0dXJlQ2FjaGVLZXkgXS50ZXh0dXJlO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gZm9yY2VVcGxvYWQ7XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gdXBsb2FkVGV4dHVyZSggdGV4dHVyZVByb3BlcnRpZXMsIHRleHR1cmUsIHNsb3QgKSB7XHJcblxyXG5cdFx0bGV0IHRleHR1cmVUeXBlID0gX2dsLlRFWFRVUkVfMkQ7XHJcblxyXG5cdFx0aWYgKCB0ZXh0dXJlLmlzRGF0YUFycmF5VGV4dHVyZSB8fCB0ZXh0dXJlLmlzQ29tcHJlc3NlZEFycmF5VGV4dHVyZSApIHRleHR1cmVUeXBlID0gX2dsLlRFWFRVUkVfMkRfQVJSQVk7XHJcblx0XHRpZiAoIHRleHR1cmUuaXNEYXRhM0RUZXh0dXJlICkgdGV4dHVyZVR5cGUgPSBfZ2wuVEVYVFVSRV8zRDtcclxuXHJcblx0XHRjb25zdCBmb3JjZVVwbG9hZCA9IGluaXRUZXh0dXJlKCB0ZXh0dXJlUHJvcGVydGllcywgdGV4dHVyZSApO1xyXG5cdFx0Y29uc3Qgc291cmNlID0gdGV4dHVyZS5zb3VyY2U7XHJcblxyXG5cdFx0c3RhdGUuYmluZFRleHR1cmUoIHRleHR1cmVUeXBlLCB0ZXh0dXJlUHJvcGVydGllcy5fX3dlYmdsVGV4dHVyZSwgX2dsLlRFWFRVUkUwICsgc2xvdCApO1xyXG5cclxuXHRcdGNvbnN0IHNvdXJjZVByb3BlcnRpZXMgPSBwcm9wZXJ0aWVzLmdldCggc291cmNlICk7XHJcblxyXG5cdFx0aWYgKCBzb3VyY2UudmVyc2lvbiAhPT0gc291cmNlUHJvcGVydGllcy5fX3ZlcnNpb24gfHwgZm9yY2VVcGxvYWQgPT09IHRydWUgKSB7XHJcblxyXG5cdFx0XHRzdGF0ZS5hY3RpdmVUZXh0dXJlKCBfZ2wuVEVYVFVSRTAgKyBzbG90ICk7XHJcblxyXG5cdFx0XHRjb25zdCB3b3JraW5nUHJpbWFyaWVzID0gQ29sb3JNYW5hZ2VtZW50LmdldFByaW1hcmllcyggQ29sb3JNYW5hZ2VtZW50LndvcmtpbmdDb2xvclNwYWNlICk7XHJcblx0XHRcdGNvbnN0IHRleHR1cmVQcmltYXJpZXMgPSB0ZXh0dXJlLmNvbG9yU3BhY2UgPT09IE5vQ29sb3JTcGFjZSA/IG51bGwgOiBDb2xvck1hbmFnZW1lbnQuZ2V0UHJpbWFyaWVzKCB0ZXh0dXJlLmNvbG9yU3BhY2UgKTtcclxuXHRcdFx0Y29uc3QgdW5wYWNrQ29udmVyc2lvbiA9IHRleHR1cmUuY29sb3JTcGFjZSA9PT0gTm9Db2xvclNwYWNlIHx8IHdvcmtpbmdQcmltYXJpZXMgPT09IHRleHR1cmVQcmltYXJpZXMgPyBfZ2wuTk9ORSA6IF9nbC5CUk9XU0VSX0RFRkFVTFRfV0VCR0w7XHJcblxyXG5cdFx0XHRfZ2wucGl4ZWxTdG9yZWkoIF9nbC5VTlBBQ0tfRkxJUF9ZX1dFQkdMLCB0ZXh0dXJlLmZsaXBZICk7XHJcblx0XHRcdF9nbC5waXhlbFN0b3JlaSggX2dsLlVOUEFDS19QUkVNVUxUSVBMWV9BTFBIQV9XRUJHTCwgdGV4dHVyZS5wcmVtdWx0aXBseUFscGhhICk7XHJcblx0XHRcdF9nbC5waXhlbFN0b3JlaSggX2dsLlVOUEFDS19BTElHTk1FTlQsIHRleHR1cmUudW5wYWNrQWxpZ25tZW50ICk7XHJcblx0XHRcdF9nbC5waXhlbFN0b3JlaSggX2dsLlVOUEFDS19DT0xPUlNQQUNFX0NPTlZFUlNJT05fV0VCR0wsIHVucGFja0NvbnZlcnNpb24gKTtcclxuXHJcblx0XHRcdGNvbnN0IG5lZWRzUG93ZXJPZlR3byA9IHRleHR1cmVOZWVkc1Bvd2VyT2ZUd28oIHRleHR1cmUgKSAmJiBpc1Bvd2VyT2ZUd28oIHRleHR1cmUuaW1hZ2UgKSA9PT0gZmFsc2U7XHJcblx0XHRcdGxldCBpbWFnZSA9IHJlc2l6ZUltYWdlKCB0ZXh0dXJlLmltYWdlLCBuZWVkc1Bvd2VyT2ZUd28sIGZhbHNlLCBjYXBhYmlsaXRpZXMubWF4VGV4dHVyZVNpemUgKTtcclxuXHRcdFx0aW1hZ2UgPSB2ZXJpZnlDb2xvclNwYWNlKCB0ZXh0dXJlLCBpbWFnZSApO1xyXG5cclxuXHRcdFx0Y29uc3Qgc3VwcG9ydHNNaXBzID0gaXNQb3dlck9mVHdvKCBpbWFnZSApIHx8IGlzV2ViR0wyLFxyXG5cdFx0XHRcdGdsRm9ybWF0ID0gdXRpbHMuY29udmVydCggdGV4dHVyZS5mb3JtYXQsIHRleHR1cmUuY29sb3JTcGFjZSApO1xyXG5cclxuXHRcdFx0bGV0IGdsVHlwZSA9IHV0aWxzLmNvbnZlcnQoIHRleHR1cmUudHlwZSApLFxyXG5cdFx0XHRcdGdsSW50ZXJuYWxGb3JtYXQgPSBnZXRJbnRlcm5hbEZvcm1hdCggdGV4dHVyZS5pbnRlcm5hbEZvcm1hdCwgZ2xGb3JtYXQsIGdsVHlwZSwgdGV4dHVyZS5jb2xvclNwYWNlLCB0ZXh0dXJlLmlzVmlkZW9UZXh0dXJlICk7XHJcblxyXG5cdFx0XHRzZXRUZXh0dXJlUGFyYW1ldGVycyggdGV4dHVyZVR5cGUsIHRleHR1cmUsIHN1cHBvcnRzTWlwcyApO1xyXG5cclxuXHRcdFx0bGV0IG1pcG1hcDtcclxuXHRcdFx0Y29uc3QgbWlwbWFwcyA9IHRleHR1cmUubWlwbWFwcztcclxuXHJcblx0XHRcdGNvbnN0IHVzZVRleFN0b3JhZ2UgPSAoIGlzV2ViR0wyICYmIHRleHR1cmUuaXNWaWRlb1RleHR1cmUgIT09IHRydWUgJiYgZ2xJbnRlcm5hbEZvcm1hdCAhPT0gUkdCX0VUQzFfRm9ybWF0ICk7XHJcblx0XHRcdGNvbnN0IGFsbG9jYXRlTWVtb3J5ID0gKCBzb3VyY2VQcm9wZXJ0aWVzLl9fdmVyc2lvbiA9PT0gdW5kZWZpbmVkICkgfHwgKCBmb3JjZVVwbG9hZCA9PT0gdHJ1ZSApO1xyXG5cdFx0XHRjb25zdCBkYXRhUmVhZHkgPSBzb3VyY2UuZGF0YVJlYWR5O1xyXG5cdFx0XHRjb25zdCBsZXZlbHMgPSBnZXRNaXBMZXZlbHMoIHRleHR1cmUsIGltYWdlLCBzdXBwb3J0c01pcHMgKTtcclxuXHJcblx0XHRcdGlmICggdGV4dHVyZS5pc0RlcHRoVGV4dHVyZSApIHtcclxuXHJcblx0XHRcdFx0Ly8gcG9wdWxhdGUgZGVwdGggdGV4dHVyZSB3aXRoIGR1bW15IGRhdGFcclxuXHJcblx0XHRcdFx0Z2xJbnRlcm5hbEZvcm1hdCA9IF9nbC5ERVBUSF9DT01QT05FTlQ7XHJcblxyXG5cdFx0XHRcdGlmICggaXNXZWJHTDIgKSB7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCB0ZXh0dXJlLnR5cGUgPT09IEZsb2F0VHlwZSApIHtcclxuXHJcblx0XHRcdFx0XHRcdGdsSW50ZXJuYWxGb3JtYXQgPSBfZ2wuREVQVEhfQ09NUE9ORU5UMzJGO1xyXG5cclxuXHRcdFx0XHRcdH0gZWxzZSBpZiAoIHRleHR1cmUudHlwZSA9PT0gVW5zaWduZWRJbnRUeXBlICkge1xyXG5cclxuXHRcdFx0XHRcdFx0Z2xJbnRlcm5hbEZvcm1hdCA9IF9nbC5ERVBUSF9DT01QT05FTlQyNDtcclxuXHJcblx0XHRcdFx0XHR9IGVsc2UgaWYgKCB0ZXh0dXJlLnR5cGUgPT09IFVuc2lnbmVkSW50MjQ4VHlwZSApIHtcclxuXHJcblx0XHRcdFx0XHRcdGdsSW50ZXJuYWxGb3JtYXQgPSBfZ2wuREVQVEgyNF9TVEVOQ0lMODtcclxuXHJcblx0XHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdFx0Z2xJbnRlcm5hbEZvcm1hdCA9IF9nbC5ERVBUSF9DT01QT05FTlQxNjsgLy8gV2ViR0wyIHJlcXVpcmVzIHNpemVkIGludGVybmFsZm9ybWF0IGZvciBnbFRleEltYWdlMkRcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCB0ZXh0dXJlLnR5cGUgPT09IEZsb2F0VHlwZSApIHtcclxuXHJcblx0XHRcdFx0XHRcdGNvbnNvbGUuZXJyb3IoICdXZWJHTFJlbmRlcmVyOiBGbG9hdGluZyBwb2ludCBkZXB0aCB0ZXh0dXJlIHJlcXVpcmVzIFdlYkdMMi4nICk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdC8vIHZhbGlkYXRpb24gY2hlY2tzIGZvciBXZWJHTCAxXHJcblxyXG5cdFx0XHRcdGlmICggdGV4dHVyZS5mb3JtYXQgPT09IERlcHRoRm9ybWF0ICYmIGdsSW50ZXJuYWxGb3JtYXQgPT09IF9nbC5ERVBUSF9DT01QT05FTlQgKSB7XHJcblxyXG5cdFx0XHRcdFx0Ly8gVGhlIGVycm9yIElOVkFMSURfT1BFUkFUSU9OIGlzIGdlbmVyYXRlZCBieSB0ZXhJbWFnZTJEIGlmIGZvcm1hdCBhbmQgaW50ZXJuYWxmb3JtYXQgYXJlXHJcblx0XHRcdFx0XHQvLyBERVBUSF9DT01QT05FTlQgYW5kIHR5cGUgaXMgbm90IFVOU0lHTkVEX1NIT1JUIG9yIFVOU0lHTkVEX0lOVFxyXG5cdFx0XHRcdFx0Ly8gKGh0dHBzOi8vd3d3Lmtocm9ub3Mub3JnL3JlZ2lzdHJ5L3dlYmdsL2V4dGVuc2lvbnMvV0VCR0xfZGVwdGhfdGV4dHVyZS8pXHJcblx0XHRcdFx0XHRpZiAoIHRleHR1cmUudHlwZSAhPT0gVW5zaWduZWRTaG9ydFR5cGUgJiYgdGV4dHVyZS50eXBlICE9PSBVbnNpZ25lZEludFR5cGUgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5XZWJHTFJlbmRlcmVyOiBVc2UgVW5zaWduZWRTaG9ydFR5cGUgb3IgVW5zaWduZWRJbnRUeXBlIGZvciBEZXB0aEZvcm1hdCBEZXB0aFRleHR1cmUuJyApO1xyXG5cclxuXHRcdFx0XHRcdFx0dGV4dHVyZS50eXBlID0gVW5zaWduZWRJbnRUeXBlO1xyXG5cdFx0XHRcdFx0XHRnbFR5cGUgPSB1dGlscy5jb252ZXJ0KCB0ZXh0dXJlLnR5cGUgKTtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0aWYgKCB0ZXh0dXJlLmZvcm1hdCA9PT0gRGVwdGhTdGVuY2lsRm9ybWF0ICYmIGdsSW50ZXJuYWxGb3JtYXQgPT09IF9nbC5ERVBUSF9DT01QT05FTlQgKSB7XHJcblxyXG5cdFx0XHRcdFx0Ly8gRGVwdGggc3RlbmNpbCB0ZXh0dXJlcyBuZWVkIHRoZSBERVBUSF9TVEVOQ0lMIGludGVybmFsIGZvcm1hdFxyXG5cdFx0XHRcdFx0Ly8gKGh0dHBzOi8vd3d3Lmtocm9ub3Mub3JnL3JlZ2lzdHJ5L3dlYmdsL2V4dGVuc2lvbnMvV0VCR0xfZGVwdGhfdGV4dHVyZS8pXHJcblx0XHRcdFx0XHRnbEludGVybmFsRm9ybWF0ID0gX2dsLkRFUFRIX1NURU5DSUw7XHJcblxyXG5cdFx0XHRcdFx0Ly8gVGhlIGVycm9yIElOVkFMSURfT1BFUkFUSU9OIGlzIGdlbmVyYXRlZCBieSB0ZXhJbWFnZTJEIGlmIGZvcm1hdCBhbmQgaW50ZXJuYWxmb3JtYXQgYXJlXHJcblx0XHRcdFx0XHQvLyBERVBUSF9TVEVOQ0lMIGFuZCB0eXBlIGlzIG5vdCBVTlNJR05FRF9JTlRfMjRfOF9XRUJHTC5cclxuXHRcdFx0XHRcdC8vIChodHRwczovL3d3dy5raHJvbm9zLm9yZy9yZWdpc3RyeS93ZWJnbC9leHRlbnNpb25zL1dFQkdMX2RlcHRoX3RleHR1cmUvKVxyXG5cdFx0XHRcdFx0aWYgKCB0ZXh0dXJlLnR5cGUgIT09IFVuc2lnbmVkSW50MjQ4VHlwZSApIHtcclxuXHJcblx0XHRcdFx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLldlYkdMUmVuZGVyZXI6IFVzZSBVbnNpZ25lZEludDI0OFR5cGUgZm9yIERlcHRoU3RlbmNpbEZvcm1hdCBEZXB0aFRleHR1cmUuJyApO1xyXG5cclxuXHRcdFx0XHRcdFx0dGV4dHVyZS50eXBlID0gVW5zaWduZWRJbnQyNDhUeXBlO1xyXG5cdFx0XHRcdFx0XHRnbFR5cGUgPSB1dGlscy5jb252ZXJ0KCB0ZXh0dXJlLnR5cGUgKTtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0Ly9cclxuXHJcblx0XHRcdFx0aWYgKCBhbGxvY2F0ZU1lbW9yeSApIHtcclxuXHJcblx0XHRcdFx0XHRpZiAoIHVzZVRleFN0b3JhZ2UgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRzdGF0ZS50ZXhTdG9yYWdlMkQoIF9nbC5URVhUVVJFXzJELCAxLCBnbEludGVybmFsRm9ybWF0LCBpbWFnZS53aWR0aCwgaW1hZ2UuaGVpZ2h0ICk7XHJcblxyXG5cdFx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRcdHN0YXRlLnRleEltYWdlMkQoIF9nbC5URVhUVVJFXzJELCAwLCBnbEludGVybmFsRm9ybWF0LCBpbWFnZS53aWR0aCwgaW1hZ2UuaGVpZ2h0LCAwLCBnbEZvcm1hdCwgZ2xUeXBlLCBudWxsICk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9IGVsc2UgaWYgKCB0ZXh0dXJlLmlzRGF0YVRleHR1cmUgKSB7XHJcblxyXG5cdFx0XHRcdC8vIHVzZSBtYW51YWxseSBjcmVhdGVkIG1pcG1hcHMgaWYgYXZhaWxhYmxlXHJcblx0XHRcdFx0Ly8gaWYgdGhlcmUgYXJlIG5vIG1hbnVhbCBtaXBtYXBzXHJcblx0XHRcdFx0Ly8gc2V0IDAgbGV2ZWwgbWlwbWFwIGFuZCB0aGVuIHVzZSBHTCB0byBnZW5lcmF0ZSBvdGhlciBtaXBtYXAgbGV2ZWxzXHJcblxyXG5cdFx0XHRcdGlmICggbWlwbWFwcy5sZW5ndGggPiAwICYmIHN1cHBvcnRzTWlwcyApIHtcclxuXHJcblx0XHRcdFx0XHRpZiAoIHVzZVRleFN0b3JhZ2UgJiYgYWxsb2NhdGVNZW1vcnkgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRzdGF0ZS50ZXhTdG9yYWdlMkQoIF9nbC5URVhUVVJFXzJELCBsZXZlbHMsIGdsSW50ZXJuYWxGb3JtYXQsIG1pcG1hcHNbIDAgXS53aWR0aCwgbWlwbWFwc1sgMCBdLmhlaWdodCApO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gbWlwbWFwcy5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0XHRcdG1pcG1hcCA9IG1pcG1hcHNbIGkgXTtcclxuXHJcblx0XHRcdFx0XHRcdGlmICggdXNlVGV4U3RvcmFnZSApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0aWYgKCBkYXRhUmVhZHkgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0c3RhdGUudGV4U3ViSW1hZ2UyRCggX2dsLlRFWFRVUkVfMkQsIGksIDAsIDAsIG1pcG1hcC53aWR0aCwgbWlwbWFwLmhlaWdodCwgZ2xGb3JtYXQsIGdsVHlwZSwgbWlwbWFwLmRhdGEgKTtcclxuXHJcblx0XHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0c3RhdGUudGV4SW1hZ2UyRCggX2dsLlRFWFRVUkVfMkQsIGksIGdsSW50ZXJuYWxGb3JtYXQsIG1pcG1hcC53aWR0aCwgbWlwbWFwLmhlaWdodCwgMCwgZ2xGb3JtYXQsIGdsVHlwZSwgbWlwbWFwLmRhdGEgKTtcclxuXHJcblx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0dGV4dHVyZS5nZW5lcmF0ZU1pcG1hcHMgPSBmYWxzZTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRpZiAoIHVzZVRleFN0b3JhZ2UgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRpZiAoIGFsbG9jYXRlTWVtb3J5ICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRzdGF0ZS50ZXhTdG9yYWdlMkQoIF9nbC5URVhUVVJFXzJELCBsZXZlbHMsIGdsSW50ZXJuYWxGb3JtYXQsIGltYWdlLndpZHRoLCBpbWFnZS5oZWlnaHQgKTtcclxuXHJcblx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRcdGlmICggZGF0YVJlYWR5ICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRzdGF0ZS50ZXhTdWJJbWFnZTJEKCBfZ2wuVEVYVFVSRV8yRCwgMCwgMCwgMCwgaW1hZ2Uud2lkdGgsIGltYWdlLmhlaWdodCwgZ2xGb3JtYXQsIGdsVHlwZSwgaW1hZ2UuZGF0YSApO1xyXG5cclxuXHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHRzdGF0ZS50ZXhJbWFnZTJEKCBfZ2wuVEVYVFVSRV8yRCwgMCwgZ2xJbnRlcm5hbEZvcm1hdCwgaW1hZ2Uud2lkdGgsIGltYWdlLmhlaWdodCwgMCwgZ2xGb3JtYXQsIGdsVHlwZSwgaW1hZ2UuZGF0YSApO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fSBlbHNlIGlmICggdGV4dHVyZS5pc0NvbXByZXNzZWRUZXh0dXJlICkge1xyXG5cclxuXHRcdFx0XHRpZiAoIHRleHR1cmUuaXNDb21wcmVzc2VkQXJyYXlUZXh0dXJlICkge1xyXG5cclxuXHRcdFx0XHRcdGlmICggdXNlVGV4U3RvcmFnZSAmJiBhbGxvY2F0ZU1lbW9yeSApIHtcclxuXHJcblx0XHRcdFx0XHRcdHN0YXRlLnRleFN0b3JhZ2UzRCggX2dsLlRFWFRVUkVfMkRfQVJSQVksIGxldmVscywgZ2xJbnRlcm5hbEZvcm1hdCwgbWlwbWFwc1sgMCBdLndpZHRoLCBtaXBtYXBzWyAwIF0uaGVpZ2h0LCBpbWFnZS5kZXB0aCApO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gbWlwbWFwcy5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0XHRcdG1pcG1hcCA9IG1pcG1hcHNbIGkgXTtcclxuXHJcblx0XHRcdFx0XHRcdGlmICggdGV4dHVyZS5mb3JtYXQgIT09IFJHQkFGb3JtYXQgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdGlmICggZ2xGb3JtYXQgIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0aWYgKCB1c2VUZXhTdG9yYWdlICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRcdFx0aWYgKCBkYXRhUmVhZHkgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdHN0YXRlLmNvbXByZXNzZWRUZXhTdWJJbWFnZTNEKCBfZ2wuVEVYVFVSRV8yRF9BUlJBWSwgaSwgMCwgMCwgMCwgbWlwbWFwLndpZHRoLCBtaXBtYXAuaGVpZ2h0LCBpbWFnZS5kZXB0aCwgZ2xGb3JtYXQsIG1pcG1hcC5kYXRhLCAwLCAwICk7XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHRcdHN0YXRlLmNvbXByZXNzZWRUZXhJbWFnZTNEKCBfZ2wuVEVYVFVSRV8yRF9BUlJBWSwgaSwgZ2xJbnRlcm5hbEZvcm1hdCwgbWlwbWFwLndpZHRoLCBtaXBtYXAuaGVpZ2h0LCBpbWFnZS5kZXB0aCwgMCwgbWlwbWFwLmRhdGEsIDAsIDAgKTtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuV2ViR0xSZW5kZXJlcjogQXR0ZW1wdCB0byBsb2FkIHVuc3VwcG9ydGVkIGNvbXByZXNzZWQgdGV4dHVyZSBmb3JtYXQgaW4gLnVwbG9hZFRleHR1cmUoKScgKTtcclxuXHJcblx0XHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0aWYgKCB1c2VUZXhTdG9yYWdlICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRcdGlmICggZGF0YVJlYWR5ICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRcdFx0c3RhdGUudGV4U3ViSW1hZ2UzRCggX2dsLlRFWFRVUkVfMkRfQVJSQVksIGksIDAsIDAsIDAsIG1pcG1hcC53aWR0aCwgbWlwbWFwLmhlaWdodCwgaW1hZ2UuZGVwdGgsIGdsRm9ybWF0LCBnbFR5cGUsIG1pcG1hcC5kYXRhICk7XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRcdHN0YXRlLnRleEltYWdlM0QoIF9nbC5URVhUVVJFXzJEX0FSUkFZLCBpLCBnbEludGVybmFsRm9ybWF0LCBtaXBtYXAud2lkdGgsIG1pcG1hcC5oZWlnaHQsIGltYWdlLmRlcHRoLCAwLCBnbEZvcm1hdCwgZ2xUeXBlLCBtaXBtYXAuZGF0YSApO1xyXG5cclxuXHRcdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdGlmICggdXNlVGV4U3RvcmFnZSAmJiBhbGxvY2F0ZU1lbW9yeSApIHtcclxuXHJcblx0XHRcdFx0XHRcdHN0YXRlLnRleFN0b3JhZ2UyRCggX2dsLlRFWFRVUkVfMkQsIGxldmVscywgZ2xJbnRlcm5hbEZvcm1hdCwgbWlwbWFwc1sgMCBdLndpZHRoLCBtaXBtYXBzWyAwIF0uaGVpZ2h0ICk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSBtaXBtYXBzLmxlbmd0aDsgaSA8IGlsOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRcdFx0bWlwbWFwID0gbWlwbWFwc1sgaSBdO1xyXG5cclxuXHRcdFx0XHRcdFx0aWYgKCB0ZXh0dXJlLmZvcm1hdCAhPT0gUkdCQUZvcm1hdCApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0aWYgKCBnbEZvcm1hdCAhPT0gbnVsbCApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHRpZiAoIHVzZVRleFN0b3JhZ2UgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0XHRpZiAoIGRhdGFSZWFkeSApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0c3RhdGUuY29tcHJlc3NlZFRleFN1YkltYWdlMkQoIF9nbC5URVhUVVJFXzJELCBpLCAwLCAwLCBtaXBtYXAud2lkdGgsIG1pcG1hcC5oZWlnaHQsIGdsRm9ybWF0LCBtaXBtYXAuZGF0YSApO1xyXG5cclxuXHRcdFx0XHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0XHRzdGF0ZS5jb21wcmVzc2VkVGV4SW1hZ2UyRCggX2dsLlRFWFRVUkVfMkQsIGksIGdsSW50ZXJuYWxGb3JtYXQsIG1pcG1hcC53aWR0aCwgbWlwbWFwLmhlaWdodCwgMCwgbWlwbWFwLmRhdGEgKTtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuV2ViR0xSZW5kZXJlcjogQXR0ZW1wdCB0byBsb2FkIHVuc3VwcG9ydGVkIGNvbXByZXNzZWQgdGV4dHVyZSBmb3JtYXQgaW4gLnVwbG9hZFRleHR1cmUoKScgKTtcclxuXHJcblx0XHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0aWYgKCB1c2VUZXhTdG9yYWdlICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRcdGlmICggZGF0YVJlYWR5ICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRcdFx0c3RhdGUudGV4U3ViSW1hZ2UyRCggX2dsLlRFWFRVUkVfMkQsIGksIDAsIDAsIG1pcG1hcC53aWR0aCwgbWlwbWFwLmhlaWdodCwgZ2xGb3JtYXQsIGdsVHlwZSwgbWlwbWFwLmRhdGEgKTtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0c3RhdGUudGV4SW1hZ2UyRCggX2dsLlRFWFRVUkVfMkQsIGksIGdsSW50ZXJuYWxGb3JtYXQsIG1pcG1hcC53aWR0aCwgbWlwbWFwLmhlaWdodCwgMCwgZ2xGb3JtYXQsIGdsVHlwZSwgbWlwbWFwLmRhdGEgKTtcclxuXHJcblx0XHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fSBlbHNlIGlmICggdGV4dHVyZS5pc0RhdGFBcnJheVRleHR1cmUgKSB7XHJcblxyXG5cdFx0XHRcdGlmICggdXNlVGV4U3RvcmFnZSApIHtcclxuXHJcblx0XHRcdFx0XHRpZiAoIGFsbG9jYXRlTWVtb3J5ICkge1xyXG5cclxuXHRcdFx0XHRcdFx0c3RhdGUudGV4U3RvcmFnZTNEKCBfZ2wuVEVYVFVSRV8yRF9BUlJBWSwgbGV2ZWxzLCBnbEludGVybmFsRm9ybWF0LCBpbWFnZS53aWR0aCwgaW1hZ2UuaGVpZ2h0LCBpbWFnZS5kZXB0aCApO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRpZiAoIGRhdGFSZWFkeSApIHtcclxuXHJcblx0XHRcdFx0XHRcdHN0YXRlLnRleFN1YkltYWdlM0QoIF9nbC5URVhUVVJFXzJEX0FSUkFZLCAwLCAwLCAwLCAwLCBpbWFnZS53aWR0aCwgaW1hZ2UuaGVpZ2h0LCBpbWFnZS5kZXB0aCwgZ2xGb3JtYXQsIGdsVHlwZSwgaW1hZ2UuZGF0YSApO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRzdGF0ZS50ZXhJbWFnZTNEKCBfZ2wuVEVYVFVSRV8yRF9BUlJBWSwgMCwgZ2xJbnRlcm5hbEZvcm1hdCwgaW1hZ2Uud2lkdGgsIGltYWdlLmhlaWdodCwgaW1hZ2UuZGVwdGgsIDAsIGdsRm9ybWF0LCBnbFR5cGUsIGltYWdlLmRhdGEgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fSBlbHNlIGlmICggdGV4dHVyZS5pc0RhdGEzRFRleHR1cmUgKSB7XHJcblxyXG5cdFx0XHRcdGlmICggdXNlVGV4U3RvcmFnZSApIHtcclxuXHJcblx0XHRcdFx0XHRpZiAoIGFsbG9jYXRlTWVtb3J5ICkge1xyXG5cclxuXHRcdFx0XHRcdFx0c3RhdGUudGV4U3RvcmFnZTNEKCBfZ2wuVEVYVFVSRV8zRCwgbGV2ZWxzLCBnbEludGVybmFsRm9ybWF0LCBpbWFnZS53aWR0aCwgaW1hZ2UuaGVpZ2h0LCBpbWFnZS5kZXB0aCApO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRpZiAoIGRhdGFSZWFkeSApIHtcclxuXHJcblx0XHRcdFx0XHRcdHN0YXRlLnRleFN1YkltYWdlM0QoIF9nbC5URVhUVVJFXzNELCAwLCAwLCAwLCAwLCBpbWFnZS53aWR0aCwgaW1hZ2UuaGVpZ2h0LCBpbWFnZS5kZXB0aCwgZ2xGb3JtYXQsIGdsVHlwZSwgaW1hZ2UuZGF0YSApO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRzdGF0ZS50ZXhJbWFnZTNEKCBfZ2wuVEVYVFVSRV8zRCwgMCwgZ2xJbnRlcm5hbEZvcm1hdCwgaW1hZ2Uud2lkdGgsIGltYWdlLmhlaWdodCwgaW1hZ2UuZGVwdGgsIDAsIGdsRm9ybWF0LCBnbFR5cGUsIGltYWdlLmRhdGEgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fSBlbHNlIGlmICggdGV4dHVyZS5pc0ZyYW1lYnVmZmVyVGV4dHVyZSApIHtcclxuXHJcblx0XHRcdFx0aWYgKCBhbGxvY2F0ZU1lbW9yeSApIHtcclxuXHJcblx0XHRcdFx0XHRpZiAoIHVzZVRleFN0b3JhZ2UgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRzdGF0ZS50ZXhTdG9yYWdlMkQoIF9nbC5URVhUVVJFXzJELCBsZXZlbHMsIGdsSW50ZXJuYWxGb3JtYXQsIGltYWdlLndpZHRoLCBpbWFnZS5oZWlnaHQgKTtcclxuXHJcblx0XHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdFx0bGV0IHdpZHRoID0gaW1hZ2Uud2lkdGgsIGhlaWdodCA9IGltYWdlLmhlaWdodDtcclxuXHJcblx0XHRcdFx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IGxldmVsczsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0c3RhdGUudGV4SW1hZ2UyRCggX2dsLlRFWFRVUkVfMkQsIGksIGdsSW50ZXJuYWxGb3JtYXQsIHdpZHRoLCBoZWlnaHQsIDAsIGdsRm9ybWF0LCBnbFR5cGUsIG51bGwgKTtcclxuXHJcblx0XHRcdFx0XHRcdFx0d2lkdGggPj49IDE7XHJcblx0XHRcdFx0XHRcdFx0aGVpZ2h0ID4+PSAxO1xyXG5cclxuXHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0Ly8gcmVndWxhciBUZXh0dXJlIChpbWFnZSwgdmlkZW8sIGNhbnZhcylcclxuXHJcblx0XHRcdFx0Ly8gdXNlIG1hbnVhbGx5IGNyZWF0ZWQgbWlwbWFwcyBpZiBhdmFpbGFibGVcclxuXHRcdFx0XHQvLyBpZiB0aGVyZSBhcmUgbm8gbWFudWFsIG1pcG1hcHNcclxuXHRcdFx0XHQvLyBzZXQgMCBsZXZlbCBtaXBtYXAgYW5kIHRoZW4gdXNlIEdMIHRvIGdlbmVyYXRlIG90aGVyIG1pcG1hcCBsZXZlbHNcclxuXHJcblx0XHRcdFx0aWYgKCBtaXBtYXBzLmxlbmd0aCA+IDAgJiYgc3VwcG9ydHNNaXBzICkge1xyXG5cclxuXHRcdFx0XHRcdGlmICggdXNlVGV4U3RvcmFnZSAmJiBhbGxvY2F0ZU1lbW9yeSApIHtcclxuXHJcblx0XHRcdFx0XHRcdHN0YXRlLnRleFN0b3JhZ2UyRCggX2dsLlRFWFRVUkVfMkQsIGxldmVscywgZ2xJbnRlcm5hbEZvcm1hdCwgbWlwbWFwc1sgMCBdLndpZHRoLCBtaXBtYXBzWyAwIF0uaGVpZ2h0ICk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSBtaXBtYXBzLmxlbmd0aDsgaSA8IGlsOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRcdFx0bWlwbWFwID0gbWlwbWFwc1sgaSBdO1xyXG5cclxuXHRcdFx0XHRcdFx0aWYgKCB1c2VUZXhTdG9yYWdlICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRpZiAoIGRhdGFSZWFkeSApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHRzdGF0ZS50ZXhTdWJJbWFnZTJEKCBfZ2wuVEVYVFVSRV8yRCwgaSwgMCwgMCwgZ2xGb3JtYXQsIGdsVHlwZSwgbWlwbWFwICk7XHJcblxyXG5cdFx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdHN0YXRlLnRleEltYWdlMkQoIF9nbC5URVhUVVJFXzJELCBpLCBnbEludGVybmFsRm9ybWF0LCBnbEZvcm1hdCwgZ2xUeXBlLCBtaXBtYXAgKTtcclxuXHJcblx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0dGV4dHVyZS5nZW5lcmF0ZU1pcG1hcHMgPSBmYWxzZTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRpZiAoIHVzZVRleFN0b3JhZ2UgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRpZiAoIGFsbG9jYXRlTWVtb3J5ICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRzdGF0ZS50ZXhTdG9yYWdlMkQoIF9nbC5URVhUVVJFXzJELCBsZXZlbHMsIGdsSW50ZXJuYWxGb3JtYXQsIGltYWdlLndpZHRoLCBpbWFnZS5oZWlnaHQgKTtcclxuXHJcblx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRcdGlmICggZGF0YVJlYWR5ICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRzdGF0ZS50ZXhTdWJJbWFnZTJEKCBfZ2wuVEVYVFVSRV8yRCwgMCwgMCwgMCwgZ2xGb3JtYXQsIGdsVHlwZSwgaW1hZ2UgKTtcclxuXHJcblx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdFx0c3RhdGUudGV4SW1hZ2UyRCggX2dsLlRFWFRVUkVfMkQsIDAsIGdsSW50ZXJuYWxGb3JtYXQsIGdsRm9ybWF0LCBnbFR5cGUsIGltYWdlICk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRpZiAoIHRleHR1cmVOZWVkc0dlbmVyYXRlTWlwbWFwcyggdGV4dHVyZSwgc3VwcG9ydHNNaXBzICkgKSB7XHJcblxyXG5cdFx0XHRcdGdlbmVyYXRlTWlwbWFwKCB0ZXh0dXJlVHlwZSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0c291cmNlUHJvcGVydGllcy5fX3ZlcnNpb24gPSBzb3VyY2UudmVyc2lvbjtcclxuXHJcblx0XHRcdGlmICggdGV4dHVyZS5vblVwZGF0ZSApIHRleHR1cmUub25VcGRhdGUoIHRleHR1cmUgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGV4dHVyZVByb3BlcnRpZXMuX192ZXJzaW9uID0gdGV4dHVyZS52ZXJzaW9uO1xyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHVwbG9hZEN1YmVUZXh0dXJlKCB0ZXh0dXJlUHJvcGVydGllcywgdGV4dHVyZSwgc2xvdCApIHtcclxuXHJcblx0XHRpZiAoIHRleHR1cmUuaW1hZ2UubGVuZ3RoICE9PSA2ICkgcmV0dXJuO1xyXG5cclxuXHRcdGNvbnN0IGZvcmNlVXBsb2FkID0gaW5pdFRleHR1cmUoIHRleHR1cmVQcm9wZXJ0aWVzLCB0ZXh0dXJlICk7XHJcblx0XHRjb25zdCBzb3VyY2UgPSB0ZXh0dXJlLnNvdXJjZTtcclxuXHJcblx0XHRzdGF0ZS5iaW5kVGV4dHVyZSggX2dsLlRFWFRVUkVfQ1VCRV9NQVAsIHRleHR1cmVQcm9wZXJ0aWVzLl9fd2ViZ2xUZXh0dXJlLCBfZ2wuVEVYVFVSRTAgKyBzbG90ICk7XHJcblxyXG5cdFx0Y29uc3Qgc291cmNlUHJvcGVydGllcyA9IHByb3BlcnRpZXMuZ2V0KCBzb3VyY2UgKTtcclxuXHJcblx0XHRpZiAoIHNvdXJjZS52ZXJzaW9uICE9PSBzb3VyY2VQcm9wZXJ0aWVzLl9fdmVyc2lvbiB8fCBmb3JjZVVwbG9hZCA9PT0gdHJ1ZSApIHtcclxuXHJcblx0XHRcdHN0YXRlLmFjdGl2ZVRleHR1cmUoIF9nbC5URVhUVVJFMCArIHNsb3QgKTtcclxuXHJcblx0XHRcdGNvbnN0IHdvcmtpbmdQcmltYXJpZXMgPSBDb2xvck1hbmFnZW1lbnQuZ2V0UHJpbWFyaWVzKCBDb2xvck1hbmFnZW1lbnQud29ya2luZ0NvbG9yU3BhY2UgKTtcclxuXHRcdFx0Y29uc3QgdGV4dHVyZVByaW1hcmllcyA9IHRleHR1cmUuY29sb3JTcGFjZSA9PT0gTm9Db2xvclNwYWNlID8gbnVsbCA6IENvbG9yTWFuYWdlbWVudC5nZXRQcmltYXJpZXMoIHRleHR1cmUuY29sb3JTcGFjZSApO1xyXG5cdFx0XHRjb25zdCB1bnBhY2tDb252ZXJzaW9uID0gdGV4dHVyZS5jb2xvclNwYWNlID09PSBOb0NvbG9yU3BhY2UgfHwgd29ya2luZ1ByaW1hcmllcyA9PT0gdGV4dHVyZVByaW1hcmllcyA/IF9nbC5OT05FIDogX2dsLkJST1dTRVJfREVGQVVMVF9XRUJHTDtcclxuXHJcblx0XHRcdF9nbC5waXhlbFN0b3JlaSggX2dsLlVOUEFDS19GTElQX1lfV0VCR0wsIHRleHR1cmUuZmxpcFkgKTtcclxuXHRcdFx0X2dsLnBpeGVsU3RvcmVpKCBfZ2wuVU5QQUNLX1BSRU1VTFRJUExZX0FMUEhBX1dFQkdMLCB0ZXh0dXJlLnByZW11bHRpcGx5QWxwaGEgKTtcclxuXHRcdFx0X2dsLnBpeGVsU3RvcmVpKCBfZ2wuVU5QQUNLX0FMSUdOTUVOVCwgdGV4dHVyZS51bnBhY2tBbGlnbm1lbnQgKTtcclxuXHRcdFx0X2dsLnBpeGVsU3RvcmVpKCBfZ2wuVU5QQUNLX0NPTE9SU1BBQ0VfQ09OVkVSU0lPTl9XRUJHTCwgdW5wYWNrQ29udmVyc2lvbiApO1xyXG5cclxuXHRcdFx0Y29uc3QgaXNDb21wcmVzc2VkID0gKCB0ZXh0dXJlLmlzQ29tcHJlc3NlZFRleHR1cmUgfHwgdGV4dHVyZS5pbWFnZVsgMCBdLmlzQ29tcHJlc3NlZFRleHR1cmUgKTtcclxuXHRcdFx0Y29uc3QgaXNEYXRhVGV4dHVyZSA9ICggdGV4dHVyZS5pbWFnZVsgMCBdICYmIHRleHR1cmUuaW1hZ2VbIDAgXS5pc0RhdGFUZXh0dXJlICk7XHJcblxyXG5cdFx0XHRjb25zdCBjdWJlSW1hZ2UgPSBbXTtcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IDY7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdGlmICggISBpc0NvbXByZXNzZWQgJiYgISBpc0RhdGFUZXh0dXJlICkge1xyXG5cclxuXHRcdFx0XHRcdGN1YmVJbWFnZVsgaSBdID0gcmVzaXplSW1hZ2UoIHRleHR1cmUuaW1hZ2VbIGkgXSwgZmFsc2UsIHRydWUsIGNhcGFiaWxpdGllcy5tYXhDdWJlbWFwU2l6ZSApO1xyXG5cclxuXHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdGN1YmVJbWFnZVsgaSBdID0gaXNEYXRhVGV4dHVyZSA/IHRleHR1cmUuaW1hZ2VbIGkgXS5pbWFnZSA6IHRleHR1cmUuaW1hZ2VbIGkgXTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRjdWJlSW1hZ2VbIGkgXSA9IHZlcmlmeUNvbG9yU3BhY2UoIHRleHR1cmUsIGN1YmVJbWFnZVsgaSBdICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRjb25zdCBpbWFnZSA9IGN1YmVJbWFnZVsgMCBdLFxyXG5cdFx0XHRcdHN1cHBvcnRzTWlwcyA9IGlzUG93ZXJPZlR3byggaW1hZ2UgKSB8fCBpc1dlYkdMMixcclxuXHRcdFx0XHRnbEZvcm1hdCA9IHV0aWxzLmNvbnZlcnQoIHRleHR1cmUuZm9ybWF0LCB0ZXh0dXJlLmNvbG9yU3BhY2UgKSxcclxuXHRcdFx0XHRnbFR5cGUgPSB1dGlscy5jb252ZXJ0KCB0ZXh0dXJlLnR5cGUgKSxcclxuXHRcdFx0XHRnbEludGVybmFsRm9ybWF0ID0gZ2V0SW50ZXJuYWxGb3JtYXQoIHRleHR1cmUuaW50ZXJuYWxGb3JtYXQsIGdsRm9ybWF0LCBnbFR5cGUsIHRleHR1cmUuY29sb3JTcGFjZSApO1xyXG5cclxuXHRcdFx0Y29uc3QgdXNlVGV4U3RvcmFnZSA9ICggaXNXZWJHTDIgJiYgdGV4dHVyZS5pc1ZpZGVvVGV4dHVyZSAhPT0gdHJ1ZSApO1xyXG5cdFx0XHRjb25zdCBhbGxvY2F0ZU1lbW9yeSA9ICggc291cmNlUHJvcGVydGllcy5fX3ZlcnNpb24gPT09IHVuZGVmaW5lZCApIHx8ICggZm9yY2VVcGxvYWQgPT09IHRydWUgKTtcclxuXHRcdFx0Y29uc3QgZGF0YVJlYWR5ID0gc291cmNlLmRhdGFSZWFkeTtcclxuXHRcdFx0bGV0IGxldmVscyA9IGdldE1pcExldmVscyggdGV4dHVyZSwgaW1hZ2UsIHN1cHBvcnRzTWlwcyApO1xyXG5cclxuXHRcdFx0c2V0VGV4dHVyZVBhcmFtZXRlcnMoIF9nbC5URVhUVVJFX0NVQkVfTUFQLCB0ZXh0dXJlLCBzdXBwb3J0c01pcHMgKTtcclxuXHJcblx0XHRcdGxldCBtaXBtYXBzO1xyXG5cclxuXHRcdFx0aWYgKCBpc0NvbXByZXNzZWQgKSB7XHJcblxyXG5cdFx0XHRcdGlmICggdXNlVGV4U3RvcmFnZSAmJiBhbGxvY2F0ZU1lbW9yeSApIHtcclxuXHJcblx0XHRcdFx0XHRzdGF0ZS50ZXhTdG9yYWdlMkQoIF9nbC5URVhUVVJFX0NVQkVfTUFQLCBsZXZlbHMsIGdsSW50ZXJuYWxGb3JtYXQsIGltYWdlLndpZHRoLCBpbWFnZS5oZWlnaHQgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCA2OyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRcdG1pcG1hcHMgPSBjdWJlSW1hZ2VbIGkgXS5taXBtYXBzO1xyXG5cclxuXHRcdFx0XHRcdGZvciAoIGxldCBqID0gMDsgaiA8IG1pcG1hcHMubGVuZ3RoOyBqICsrICkge1xyXG5cclxuXHRcdFx0XHRcdFx0Y29uc3QgbWlwbWFwID0gbWlwbWFwc1sgaiBdO1xyXG5cclxuXHRcdFx0XHRcdFx0aWYgKCB0ZXh0dXJlLmZvcm1hdCAhPT0gUkdCQUZvcm1hdCApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0aWYgKCBnbEZvcm1hdCAhPT0gbnVsbCApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHRpZiAoIHVzZVRleFN0b3JhZ2UgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0XHRpZiAoIGRhdGFSZWFkeSApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0c3RhdGUuY29tcHJlc3NlZFRleFN1YkltYWdlMkQoIF9nbC5URVhUVVJFX0NVQkVfTUFQX1BPU0lUSVZFX1ggKyBpLCBqLCAwLCAwLCBtaXBtYXAud2lkdGgsIG1pcG1hcC5oZWlnaHQsIGdsRm9ybWF0LCBtaXBtYXAuZGF0YSApO1xyXG5cclxuXHRcdFx0XHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0XHRzdGF0ZS5jb21wcmVzc2VkVGV4SW1hZ2UyRCggX2dsLlRFWFRVUkVfQ1VCRV9NQVBfUE9TSVRJVkVfWCArIGksIGosIGdsSW50ZXJuYWxGb3JtYXQsIG1pcG1hcC53aWR0aCwgbWlwbWFwLmhlaWdodCwgMCwgbWlwbWFwLmRhdGEgKTtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuV2ViR0xSZW5kZXJlcjogQXR0ZW1wdCB0byBsb2FkIHVuc3VwcG9ydGVkIGNvbXByZXNzZWQgdGV4dHVyZSBmb3JtYXQgaW4gLnNldFRleHR1cmVDdWJlKCknICk7XHJcblxyXG5cdFx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdGlmICggdXNlVGV4U3RvcmFnZSApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHRpZiAoIGRhdGFSZWFkeSApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHRcdHN0YXRlLnRleFN1YkltYWdlMkQoIF9nbC5URVhUVVJFX0NVQkVfTUFQX1BPU0lUSVZFX1ggKyBpLCBqLCAwLCAwLCBtaXBtYXAud2lkdGgsIG1pcG1hcC5oZWlnaHQsIGdsRm9ybWF0LCBnbFR5cGUsIG1pcG1hcC5kYXRhICk7XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRcdHN0YXRlLnRleEltYWdlMkQoIF9nbC5URVhUVVJFX0NVQkVfTUFQX1BPU0lUSVZFX1ggKyBpLCBqLCBnbEludGVybmFsRm9ybWF0LCBtaXBtYXAud2lkdGgsIG1pcG1hcC5oZWlnaHQsIDAsIGdsRm9ybWF0LCBnbFR5cGUsIG1pcG1hcC5kYXRhICk7XHJcblxyXG5cdFx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdG1pcG1hcHMgPSB0ZXh0dXJlLm1pcG1hcHM7XHJcblxyXG5cdFx0XHRcdGlmICggdXNlVGV4U3RvcmFnZSAmJiBhbGxvY2F0ZU1lbW9yeSApIHtcclxuXHJcblx0XHRcdFx0XHQvLyBUT0RPOiBVbmlmb3JtbHkgaGFuZGxlIG1pcG1hcCBkZWZpbml0aW9uc1xyXG5cdFx0XHRcdFx0Ly8gTm9ybWFsIHRleHR1cmVzIGFuZCBjb21wcmVzc2VkIGN1YmUgdGV4dHVyZXMgZGVmaW5lIGJhc2UgbGV2ZWwgKyBtaXBzIHdpdGggdGhlaXIgbWlwbWFwIGFycmF5XHJcblx0XHRcdFx0XHQvLyBVbmNvbXByZXNzZWQgY3ViZSB0ZXh0dXJlcyB1c2UgdGhlaXIgbWlwbWFwIGFycmF5IG9ubHkgZm9yIG1pcHMgKG5vIGJhc2UgbGV2ZWwpXHJcblxyXG5cdFx0XHRcdFx0aWYgKCBtaXBtYXBzLmxlbmd0aCA+IDAgKSBsZXZlbHMgKys7XHJcblxyXG5cdFx0XHRcdFx0c3RhdGUudGV4U3RvcmFnZTJEKCBfZ2wuVEVYVFVSRV9DVUJFX01BUCwgbGV2ZWxzLCBnbEludGVybmFsRm9ybWF0LCBjdWJlSW1hZ2VbIDAgXS53aWR0aCwgY3ViZUltYWdlWyAwIF0uaGVpZ2h0ICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgNjsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0XHRpZiAoIGlzRGF0YVRleHR1cmUgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRpZiAoIHVzZVRleFN0b3JhZ2UgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdGlmICggZGF0YVJlYWR5ICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRcdHN0YXRlLnRleFN1YkltYWdlMkQoIF9nbC5URVhUVVJFX0NVQkVfTUFQX1BPU0lUSVZFX1ggKyBpLCAwLCAwLCAwLCBjdWJlSW1hZ2VbIGkgXS53aWR0aCwgY3ViZUltYWdlWyBpIF0uaGVpZ2h0LCBnbEZvcm1hdCwgZ2xUeXBlLCBjdWJlSW1hZ2VbIGkgXS5kYXRhICk7XHJcblxyXG5cdFx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdHN0YXRlLnRleEltYWdlMkQoIF9nbC5URVhUVVJFX0NVQkVfTUFQX1BPU0lUSVZFX1ggKyBpLCAwLCBnbEludGVybmFsRm9ybWF0LCBjdWJlSW1hZ2VbIGkgXS53aWR0aCwgY3ViZUltYWdlWyBpIF0uaGVpZ2h0LCAwLCBnbEZvcm1hdCwgZ2xUeXBlLCBjdWJlSW1hZ2VbIGkgXS5kYXRhICk7XHJcblxyXG5cdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0XHRmb3IgKCBsZXQgaiA9IDA7IGogPCBtaXBtYXBzLmxlbmd0aDsgaiArKyApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0Y29uc3QgbWlwbWFwID0gbWlwbWFwc1sgaiBdO1xyXG5cdFx0XHRcdFx0XHRcdGNvbnN0IG1pcG1hcEltYWdlID0gbWlwbWFwLmltYWdlWyBpIF0uaW1hZ2U7XHJcblxyXG5cdFx0XHRcdFx0XHRcdGlmICggdXNlVGV4U3RvcmFnZSApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHRpZiAoIGRhdGFSZWFkeSApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHRcdHN0YXRlLnRleFN1YkltYWdlMkQoIF9nbC5URVhUVVJFX0NVQkVfTUFQX1BPU0lUSVZFX1ggKyBpLCBqICsgMSwgMCwgMCwgbWlwbWFwSW1hZ2Uud2lkdGgsIG1pcG1hcEltYWdlLmhlaWdodCwgZ2xGb3JtYXQsIGdsVHlwZSwgbWlwbWFwSW1hZ2UuZGF0YSApO1xyXG5cclxuXHRcdFx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHRzdGF0ZS50ZXhJbWFnZTJEKCBfZ2wuVEVYVFVSRV9DVUJFX01BUF9QT1NJVElWRV9YICsgaSwgaiArIDEsIGdsSW50ZXJuYWxGb3JtYXQsIG1pcG1hcEltYWdlLndpZHRoLCBtaXBtYXBJbWFnZS5oZWlnaHQsIDAsIGdsRm9ybWF0LCBnbFR5cGUsIG1pcG1hcEltYWdlLmRhdGEgKTtcclxuXHJcblx0XHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHRpZiAoIHVzZVRleFN0b3JhZ2UgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdGlmICggZGF0YVJlYWR5ICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRcdHN0YXRlLnRleFN1YkltYWdlMkQoIF9nbC5URVhUVVJFX0NVQkVfTUFQX1BPU0lUSVZFX1ggKyBpLCAwLCAwLCAwLCBnbEZvcm1hdCwgZ2xUeXBlLCBjdWJlSW1hZ2VbIGkgXSApO1xyXG5cclxuXHRcdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRzdGF0ZS50ZXhJbWFnZTJEKCBfZ2wuVEVYVFVSRV9DVUJFX01BUF9QT1NJVElWRV9YICsgaSwgMCwgZ2xJbnRlcm5hbEZvcm1hdCwgZ2xGb3JtYXQsIGdsVHlwZSwgY3ViZUltYWdlWyBpIF0gKTtcclxuXHJcblx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRcdGZvciAoIGxldCBqID0gMDsgaiA8IG1pcG1hcHMubGVuZ3RoOyBqICsrICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRjb25zdCBtaXBtYXAgPSBtaXBtYXBzWyBqIF07XHJcblxyXG5cdFx0XHRcdFx0XHRcdGlmICggdXNlVGV4U3RvcmFnZSApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHRpZiAoIGRhdGFSZWFkeSApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHRcdHN0YXRlLnRleFN1YkltYWdlMkQoIF9nbC5URVhUVVJFX0NVQkVfTUFQX1BPU0lUSVZFX1ggKyBpLCBqICsgMSwgMCwgMCwgZ2xGb3JtYXQsIGdsVHlwZSwgbWlwbWFwLmltYWdlWyBpIF0gKTtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0c3RhdGUudGV4SW1hZ2UyRCggX2dsLlRFWFRVUkVfQ1VCRV9NQVBfUE9TSVRJVkVfWCArIGksIGogKyAxLCBnbEludGVybmFsRm9ybWF0LCBnbEZvcm1hdCwgZ2xUeXBlLCBtaXBtYXAuaW1hZ2VbIGkgXSApO1xyXG5cclxuXHRcdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRpZiAoIHRleHR1cmVOZWVkc0dlbmVyYXRlTWlwbWFwcyggdGV4dHVyZSwgc3VwcG9ydHNNaXBzICkgKSB7XHJcblxyXG5cdFx0XHRcdC8vIFdlIGFzc3VtZSBpbWFnZXMgZm9yIGN1YmUgbWFwIGhhdmUgdGhlIHNhbWUgc2l6ZS5cclxuXHRcdFx0XHRnZW5lcmF0ZU1pcG1hcCggX2dsLlRFWFRVUkVfQ1VCRV9NQVAgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHNvdXJjZVByb3BlcnRpZXMuX192ZXJzaW9uID0gc291cmNlLnZlcnNpb247XHJcblxyXG5cdFx0XHRpZiAoIHRleHR1cmUub25VcGRhdGUgKSB0ZXh0dXJlLm9uVXBkYXRlKCB0ZXh0dXJlICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRleHR1cmVQcm9wZXJ0aWVzLl9fdmVyc2lvbiA9IHRleHR1cmUudmVyc2lvbjtcclxuXHJcblx0fVxyXG5cclxuXHQvLyBSZW5kZXIgdGFyZ2V0c1xyXG5cclxuXHQvLyBTZXR1cCBzdG9yYWdlIGZvciB0YXJnZXQgdGV4dHVyZSBhbmQgYmluZCBpdCB0byBjb3JyZWN0IGZyYW1lYnVmZmVyXHJcblx0ZnVuY3Rpb24gc2V0dXBGcmFtZUJ1ZmZlclRleHR1cmUoIGZyYW1lYnVmZmVyLCByZW5kZXJUYXJnZXQsIHRleHR1cmUsIGF0dGFjaG1lbnQsIHRleHR1cmVUYXJnZXQsIGxldmVsICkge1xyXG5cclxuXHRcdGNvbnN0IGdsRm9ybWF0ID0gdXRpbHMuY29udmVydCggdGV4dHVyZS5mb3JtYXQsIHRleHR1cmUuY29sb3JTcGFjZSApO1xyXG5cdFx0Y29uc3QgZ2xUeXBlID0gdXRpbHMuY29udmVydCggdGV4dHVyZS50eXBlICk7XHJcblx0XHRjb25zdCBnbEludGVybmFsRm9ybWF0ID0gZ2V0SW50ZXJuYWxGb3JtYXQoIHRleHR1cmUuaW50ZXJuYWxGb3JtYXQsIGdsRm9ybWF0LCBnbFR5cGUsIHRleHR1cmUuY29sb3JTcGFjZSApO1xyXG5cdFx0Y29uc3QgcmVuZGVyVGFyZ2V0UHJvcGVydGllcyA9IHByb3BlcnRpZXMuZ2V0KCByZW5kZXJUYXJnZXQgKTtcclxuXHJcblx0XHRpZiAoICEgcmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX2hhc0V4dGVybmFsVGV4dHVyZXMgKSB7XHJcblxyXG5cdFx0XHRjb25zdCB3aWR0aCA9IE1hdGgubWF4KCAxLCByZW5kZXJUYXJnZXQud2lkdGggPj4gbGV2ZWwgKTtcclxuXHRcdFx0Y29uc3QgaGVpZ2h0ID0gTWF0aC5tYXgoIDEsIHJlbmRlclRhcmdldC5oZWlnaHQgPj4gbGV2ZWwgKTtcclxuXHJcblx0XHRcdGlmICggdGV4dHVyZVRhcmdldCA9PT0gX2dsLlRFWFRVUkVfM0QgfHwgdGV4dHVyZVRhcmdldCA9PT0gX2dsLlRFWFRVUkVfMkRfQVJSQVkgKSB7XHJcblxyXG5cdFx0XHRcdHN0YXRlLnRleEltYWdlM0QoIHRleHR1cmVUYXJnZXQsIGxldmVsLCBnbEludGVybmFsRm9ybWF0LCB3aWR0aCwgaGVpZ2h0LCByZW5kZXJUYXJnZXQuZGVwdGgsIDAsIGdsRm9ybWF0LCBnbFR5cGUsIG51bGwgKTtcclxuXHJcblx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdHN0YXRlLnRleEltYWdlMkQoIHRleHR1cmVUYXJnZXQsIGxldmVsLCBnbEludGVybmFsRm9ybWF0LCB3aWR0aCwgaGVpZ2h0LCAwLCBnbEZvcm1hdCwgZ2xUeXBlLCBudWxsICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHN0YXRlLmJpbmRGcmFtZWJ1ZmZlciggX2dsLkZSQU1FQlVGRkVSLCBmcmFtZWJ1ZmZlciApO1xyXG5cclxuXHRcdGlmICggdXNlTXVsdGlzYW1wbGVkUlRUKCByZW5kZXJUYXJnZXQgKSApIHtcclxuXHJcblx0XHRcdG11bHRpc2FtcGxlZFJUVEV4dC5mcmFtZWJ1ZmZlclRleHR1cmUyRE11bHRpc2FtcGxlRVhUKCBfZ2wuRlJBTUVCVUZGRVIsIGF0dGFjaG1lbnQsIHRleHR1cmVUYXJnZXQsIHByb3BlcnRpZXMuZ2V0KCB0ZXh0dXJlICkuX193ZWJnbFRleHR1cmUsIDAsIGdldFJlbmRlclRhcmdldFNhbXBsZXMoIHJlbmRlclRhcmdldCApICk7XHJcblxyXG5cdFx0fSBlbHNlIGlmICggdGV4dHVyZVRhcmdldCA9PT0gX2dsLlRFWFRVUkVfMkQgfHwgKCB0ZXh0dXJlVGFyZ2V0ID49IF9nbC5URVhUVVJFX0NVQkVfTUFQX1BPU0lUSVZFX1ggJiYgdGV4dHVyZVRhcmdldCA8PSBfZ2wuVEVYVFVSRV9DVUJFX01BUF9ORUdBVElWRV9aICkgKSB7IC8vIHNlZSAjMjQ3NTNcclxuXHJcblx0XHRcdF9nbC5mcmFtZWJ1ZmZlclRleHR1cmUyRCggX2dsLkZSQU1FQlVGRkVSLCBhdHRhY2htZW50LCB0ZXh0dXJlVGFyZ2V0LCBwcm9wZXJ0aWVzLmdldCggdGV4dHVyZSApLl9fd2ViZ2xUZXh0dXJlLCBsZXZlbCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRzdGF0ZS5iaW5kRnJhbWVidWZmZXIoIF9nbC5GUkFNRUJVRkZFUiwgbnVsbCApO1xyXG5cclxuXHR9XHJcblxyXG5cclxuXHQvLyBTZXR1cCBzdG9yYWdlIGZvciBpbnRlcm5hbCBkZXB0aC9zdGVuY2lsIGJ1ZmZlcnMgYW5kIGJpbmQgdG8gY29ycmVjdCBmcmFtZWJ1ZmZlclxyXG5cdGZ1bmN0aW9uIHNldHVwUmVuZGVyQnVmZmVyU3RvcmFnZSggcmVuZGVyYnVmZmVyLCByZW5kZXJUYXJnZXQsIGlzTXVsdGlzYW1wbGUgKSB7XHJcblxyXG5cdFx0X2dsLmJpbmRSZW5kZXJidWZmZXIoIF9nbC5SRU5ERVJCVUZGRVIsIHJlbmRlcmJ1ZmZlciApO1xyXG5cclxuXHRcdGlmICggcmVuZGVyVGFyZ2V0LmRlcHRoQnVmZmVyICYmICEgcmVuZGVyVGFyZ2V0LnN0ZW5jaWxCdWZmZXIgKSB7XHJcblxyXG5cdFx0XHRsZXQgZ2xJbnRlcm5hbEZvcm1hdCA9ICggaXNXZWJHTDIgPT09IHRydWUgKSA/IF9nbC5ERVBUSF9DT01QT05FTlQyNCA6IF9nbC5ERVBUSF9DT01QT05FTlQxNjtcclxuXHJcblx0XHRcdGlmICggaXNNdWx0aXNhbXBsZSB8fCB1c2VNdWx0aXNhbXBsZWRSVFQoIHJlbmRlclRhcmdldCApICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBkZXB0aFRleHR1cmUgPSByZW5kZXJUYXJnZXQuZGVwdGhUZXh0dXJlO1xyXG5cclxuXHRcdFx0XHRpZiAoIGRlcHRoVGV4dHVyZSAmJiBkZXB0aFRleHR1cmUuaXNEZXB0aFRleHR1cmUgKSB7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCBkZXB0aFRleHR1cmUudHlwZSA9PT0gRmxvYXRUeXBlICkge1xyXG5cclxuXHRcdFx0XHRcdFx0Z2xJbnRlcm5hbEZvcm1hdCA9IF9nbC5ERVBUSF9DT01QT05FTlQzMkY7XHJcblxyXG5cdFx0XHRcdFx0fSBlbHNlIGlmICggZGVwdGhUZXh0dXJlLnR5cGUgPT09IFVuc2lnbmVkSW50VHlwZSApIHtcclxuXHJcblx0XHRcdFx0XHRcdGdsSW50ZXJuYWxGb3JtYXQgPSBfZ2wuREVQVEhfQ09NUE9ORU5UMjQ7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdGNvbnN0IHNhbXBsZXMgPSBnZXRSZW5kZXJUYXJnZXRTYW1wbGVzKCByZW5kZXJUYXJnZXQgKTtcclxuXHJcblx0XHRcdFx0aWYgKCB1c2VNdWx0aXNhbXBsZWRSVFQoIHJlbmRlclRhcmdldCApICkge1xyXG5cclxuXHRcdFx0XHRcdG11bHRpc2FtcGxlZFJUVEV4dC5yZW5kZXJidWZmZXJTdG9yYWdlTXVsdGlzYW1wbGVFWFQoIF9nbC5SRU5ERVJCVUZGRVIsIHNhbXBsZXMsIGdsSW50ZXJuYWxGb3JtYXQsIHJlbmRlclRhcmdldC53aWR0aCwgcmVuZGVyVGFyZ2V0LmhlaWdodCApO1xyXG5cclxuXHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdF9nbC5yZW5kZXJidWZmZXJTdG9yYWdlTXVsdGlzYW1wbGUoIF9nbC5SRU5ERVJCVUZGRVIsIHNhbXBsZXMsIGdsSW50ZXJuYWxGb3JtYXQsIHJlbmRlclRhcmdldC53aWR0aCwgcmVuZGVyVGFyZ2V0LmhlaWdodCApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRfZ2wucmVuZGVyYnVmZmVyU3RvcmFnZSggX2dsLlJFTkRFUkJVRkZFUiwgZ2xJbnRlcm5hbEZvcm1hdCwgcmVuZGVyVGFyZ2V0LndpZHRoLCByZW5kZXJUYXJnZXQuaGVpZ2h0ICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRfZ2wuZnJhbWVidWZmZXJSZW5kZXJidWZmZXIoIF9nbC5GUkFNRUJVRkZFUiwgX2dsLkRFUFRIX0FUVEFDSE1FTlQsIF9nbC5SRU5ERVJCVUZGRVIsIHJlbmRlcmJ1ZmZlciApO1xyXG5cclxuXHRcdH0gZWxzZSBpZiAoIHJlbmRlclRhcmdldC5kZXB0aEJ1ZmZlciAmJiByZW5kZXJUYXJnZXQuc3RlbmNpbEJ1ZmZlciApIHtcclxuXHJcblx0XHRcdGNvbnN0IHNhbXBsZXMgPSBnZXRSZW5kZXJUYXJnZXRTYW1wbGVzKCByZW5kZXJUYXJnZXQgKTtcclxuXHJcblx0XHRcdGlmICggaXNNdWx0aXNhbXBsZSAmJiB1c2VNdWx0aXNhbXBsZWRSVFQoIHJlbmRlclRhcmdldCApID09PSBmYWxzZSApIHtcclxuXHJcblx0XHRcdFx0X2dsLnJlbmRlcmJ1ZmZlclN0b3JhZ2VNdWx0aXNhbXBsZSggX2dsLlJFTkRFUkJVRkZFUiwgc2FtcGxlcywgX2dsLkRFUFRIMjRfU1RFTkNJTDgsIHJlbmRlclRhcmdldC53aWR0aCwgcmVuZGVyVGFyZ2V0LmhlaWdodCApO1xyXG5cclxuXHRcdFx0fSBlbHNlIGlmICggdXNlTXVsdGlzYW1wbGVkUlRUKCByZW5kZXJUYXJnZXQgKSApIHtcclxuXHJcblx0XHRcdFx0bXVsdGlzYW1wbGVkUlRURXh0LnJlbmRlcmJ1ZmZlclN0b3JhZ2VNdWx0aXNhbXBsZUVYVCggX2dsLlJFTkRFUkJVRkZFUiwgc2FtcGxlcywgX2dsLkRFUFRIMjRfU1RFTkNJTDgsIHJlbmRlclRhcmdldC53aWR0aCwgcmVuZGVyVGFyZ2V0LmhlaWdodCApO1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0X2dsLnJlbmRlcmJ1ZmZlclN0b3JhZ2UoIF9nbC5SRU5ERVJCVUZGRVIsIF9nbC5ERVBUSF9TVEVOQ0lMLCByZW5kZXJUYXJnZXQud2lkdGgsIHJlbmRlclRhcmdldC5oZWlnaHQgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblxyXG5cdFx0XHRfZ2wuZnJhbWVidWZmZXJSZW5kZXJidWZmZXIoIF9nbC5GUkFNRUJVRkZFUiwgX2dsLkRFUFRIX1NURU5DSUxfQVRUQUNITUVOVCwgX2dsLlJFTkRFUkJVRkZFUiwgcmVuZGVyYnVmZmVyICk7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdGNvbnN0IHRleHR1cmVzID0gcmVuZGVyVGFyZ2V0LmlzV2ViR0xNdWx0aXBsZVJlbmRlclRhcmdldHMgPT09IHRydWUgPyByZW5kZXJUYXJnZXQudGV4dHVyZSA6IFsgcmVuZGVyVGFyZ2V0LnRleHR1cmUgXTtcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHRleHR1cmVzLmxlbmd0aDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgdGV4dHVyZSA9IHRleHR1cmVzWyBpIF07XHJcblxyXG5cdFx0XHRcdGNvbnN0IGdsRm9ybWF0ID0gdXRpbHMuY29udmVydCggdGV4dHVyZS5mb3JtYXQsIHRleHR1cmUuY29sb3JTcGFjZSApO1xyXG5cdFx0XHRcdGNvbnN0IGdsVHlwZSA9IHV0aWxzLmNvbnZlcnQoIHRleHR1cmUudHlwZSApO1xyXG5cdFx0XHRcdGNvbnN0IGdsSW50ZXJuYWxGb3JtYXQgPSBnZXRJbnRlcm5hbEZvcm1hdCggdGV4dHVyZS5pbnRlcm5hbEZvcm1hdCwgZ2xGb3JtYXQsIGdsVHlwZSwgdGV4dHVyZS5jb2xvclNwYWNlICk7XHJcblx0XHRcdFx0Y29uc3Qgc2FtcGxlcyA9IGdldFJlbmRlclRhcmdldFNhbXBsZXMoIHJlbmRlclRhcmdldCApO1xyXG5cclxuXHRcdFx0XHRpZiAoIGlzTXVsdGlzYW1wbGUgJiYgdXNlTXVsdGlzYW1wbGVkUlRUKCByZW5kZXJUYXJnZXQgKSA9PT0gZmFsc2UgKSB7XHJcblxyXG5cdFx0XHRcdFx0X2dsLnJlbmRlcmJ1ZmZlclN0b3JhZ2VNdWx0aXNhbXBsZSggX2dsLlJFTkRFUkJVRkZFUiwgc2FtcGxlcywgZ2xJbnRlcm5hbEZvcm1hdCwgcmVuZGVyVGFyZ2V0LndpZHRoLCByZW5kZXJUYXJnZXQuaGVpZ2h0ICk7XHJcblxyXG5cdFx0XHRcdH0gZWxzZSBpZiAoIHVzZU11bHRpc2FtcGxlZFJUVCggcmVuZGVyVGFyZ2V0ICkgKSB7XHJcblxyXG5cdFx0XHRcdFx0bXVsdGlzYW1wbGVkUlRURXh0LnJlbmRlcmJ1ZmZlclN0b3JhZ2VNdWx0aXNhbXBsZUVYVCggX2dsLlJFTkRFUkJVRkZFUiwgc2FtcGxlcywgZ2xJbnRlcm5hbEZvcm1hdCwgcmVuZGVyVGFyZ2V0LndpZHRoLCByZW5kZXJUYXJnZXQuaGVpZ2h0ICk7XHJcblxyXG5cdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0X2dsLnJlbmRlcmJ1ZmZlclN0b3JhZ2UoIF9nbC5SRU5ERVJCVUZGRVIsIGdsSW50ZXJuYWxGb3JtYXQsIHJlbmRlclRhcmdldC53aWR0aCwgcmVuZGVyVGFyZ2V0LmhlaWdodCApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdF9nbC5iaW5kUmVuZGVyYnVmZmVyKCBfZ2wuUkVOREVSQlVGRkVSLCBudWxsICk7XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gU2V0dXAgcmVzb3VyY2VzIGZvciBhIERlcHRoIFRleHR1cmUgZm9yIGEgRkJPIChuZWVkcyBhbiBleHRlbnNpb24pXHJcblx0ZnVuY3Rpb24gc2V0dXBEZXB0aFRleHR1cmUoIGZyYW1lYnVmZmVyLCByZW5kZXJUYXJnZXQgKSB7XHJcblxyXG5cdFx0Y29uc3QgaXNDdWJlID0gKCByZW5kZXJUYXJnZXQgJiYgcmVuZGVyVGFyZ2V0LmlzV2ViR0xDdWJlUmVuZGVyVGFyZ2V0ICk7XHJcblx0XHRpZiAoIGlzQ3ViZSApIHRocm93IG5ldyBFcnJvciggJ0RlcHRoIFRleHR1cmUgd2l0aCBjdWJlIHJlbmRlciB0YXJnZXRzIGlzIG5vdCBzdXBwb3J0ZWQnICk7XHJcblxyXG5cdFx0c3RhdGUuYmluZEZyYW1lYnVmZmVyKCBfZ2wuRlJBTUVCVUZGRVIsIGZyYW1lYnVmZmVyICk7XHJcblxyXG5cdFx0aWYgKCAhICggcmVuZGVyVGFyZ2V0LmRlcHRoVGV4dHVyZSAmJiByZW5kZXJUYXJnZXQuZGVwdGhUZXh0dXJlLmlzRGVwdGhUZXh0dXJlICkgKSB7XHJcblxyXG5cdFx0XHR0aHJvdyBuZXcgRXJyb3IoICdyZW5kZXJUYXJnZXQuZGVwdGhUZXh0dXJlIG11c3QgYmUgYW4gaW5zdGFuY2Ugb2YgVEhSRUUuRGVwdGhUZXh0dXJlJyApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvLyB1cGxvYWQgYW4gZW1wdHkgZGVwdGggdGV4dHVyZSB3aXRoIGZyYW1lYnVmZmVyIHNpemVcclxuXHRcdGlmICggISBwcm9wZXJ0aWVzLmdldCggcmVuZGVyVGFyZ2V0LmRlcHRoVGV4dHVyZSApLl9fd2ViZ2xUZXh0dXJlIHx8XHJcblx0XHRcdFx0cmVuZGVyVGFyZ2V0LmRlcHRoVGV4dHVyZS5pbWFnZS53aWR0aCAhPT0gcmVuZGVyVGFyZ2V0LndpZHRoIHx8XHJcblx0XHRcdFx0cmVuZGVyVGFyZ2V0LmRlcHRoVGV4dHVyZS5pbWFnZS5oZWlnaHQgIT09IHJlbmRlclRhcmdldC5oZWlnaHQgKSB7XHJcblxyXG5cdFx0XHRyZW5kZXJUYXJnZXQuZGVwdGhUZXh0dXJlLmltYWdlLndpZHRoID0gcmVuZGVyVGFyZ2V0LndpZHRoO1xyXG5cdFx0XHRyZW5kZXJUYXJnZXQuZGVwdGhUZXh0dXJlLmltYWdlLmhlaWdodCA9IHJlbmRlclRhcmdldC5oZWlnaHQ7XHJcblx0XHRcdHJlbmRlclRhcmdldC5kZXB0aFRleHR1cmUubmVlZHNVcGRhdGUgPSB0cnVlO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRzZXRUZXh0dXJlMkQoIHJlbmRlclRhcmdldC5kZXB0aFRleHR1cmUsIDAgKTtcclxuXHJcblx0XHRjb25zdCB3ZWJnbERlcHRoVGV4dHVyZSA9IHByb3BlcnRpZXMuZ2V0KCByZW5kZXJUYXJnZXQuZGVwdGhUZXh0dXJlICkuX193ZWJnbFRleHR1cmU7XHJcblx0XHRjb25zdCBzYW1wbGVzID0gZ2V0UmVuZGVyVGFyZ2V0U2FtcGxlcyggcmVuZGVyVGFyZ2V0ICk7XHJcblxyXG5cdFx0aWYgKCByZW5kZXJUYXJnZXQuZGVwdGhUZXh0dXJlLmZvcm1hdCA9PT0gRGVwdGhGb3JtYXQgKSB7XHJcblxyXG5cdFx0XHRpZiAoIHVzZU11bHRpc2FtcGxlZFJUVCggcmVuZGVyVGFyZ2V0ICkgKSB7XHJcblxyXG5cdFx0XHRcdG11bHRpc2FtcGxlZFJUVEV4dC5mcmFtZWJ1ZmZlclRleHR1cmUyRE11bHRpc2FtcGxlRVhUKCBfZ2wuRlJBTUVCVUZGRVIsIF9nbC5ERVBUSF9BVFRBQ0hNRU5ULCBfZ2wuVEVYVFVSRV8yRCwgd2ViZ2xEZXB0aFRleHR1cmUsIDAsIHNhbXBsZXMgKTtcclxuXHJcblx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdF9nbC5mcmFtZWJ1ZmZlclRleHR1cmUyRCggX2dsLkZSQU1FQlVGRkVSLCBfZ2wuREVQVEhfQVRUQUNITUVOVCwgX2dsLlRFWFRVUkVfMkQsIHdlYmdsRGVwdGhUZXh0dXJlLCAwICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fSBlbHNlIGlmICggcmVuZGVyVGFyZ2V0LmRlcHRoVGV4dHVyZS5mb3JtYXQgPT09IERlcHRoU3RlbmNpbEZvcm1hdCApIHtcclxuXHJcblx0XHRcdGlmICggdXNlTXVsdGlzYW1wbGVkUlRUKCByZW5kZXJUYXJnZXQgKSApIHtcclxuXHJcblx0XHRcdFx0bXVsdGlzYW1wbGVkUlRURXh0LmZyYW1lYnVmZmVyVGV4dHVyZTJETXVsdGlzYW1wbGVFWFQoIF9nbC5GUkFNRUJVRkZFUiwgX2dsLkRFUFRIX1NURU5DSUxfQVRUQUNITUVOVCwgX2dsLlRFWFRVUkVfMkQsIHdlYmdsRGVwdGhUZXh0dXJlLCAwLCBzYW1wbGVzICk7XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRfZ2wuZnJhbWVidWZmZXJUZXh0dXJlMkQoIF9nbC5GUkFNRUJVRkZFUiwgX2dsLkRFUFRIX1NURU5DSUxfQVRUQUNITUVOVCwgX2dsLlRFWFRVUkVfMkQsIHdlYmdsRGVwdGhUZXh0dXJlLCAwICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdHRocm93IG5ldyBFcnJvciggJ1Vua25vd24gZGVwdGhUZXh0dXJlIGZvcm1hdCcgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gU2V0dXAgR0wgcmVzb3VyY2VzIGZvciBhIG5vbi10ZXh0dXJlIGRlcHRoIGJ1ZmZlclxyXG5cdGZ1bmN0aW9uIHNldHVwRGVwdGhSZW5kZXJidWZmZXIoIHJlbmRlclRhcmdldCApIHtcclxuXHJcblx0XHRjb25zdCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzID0gcHJvcGVydGllcy5nZXQoIHJlbmRlclRhcmdldCApO1xyXG5cdFx0Y29uc3QgaXNDdWJlID0gKCByZW5kZXJUYXJnZXQuaXNXZWJHTEN1YmVSZW5kZXJUYXJnZXQgPT09IHRydWUgKTtcclxuXHJcblx0XHRpZiAoIHJlbmRlclRhcmdldC5kZXB0aFRleHR1cmUgJiYgISByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fYXV0b0FsbG9jYXRlRGVwdGhCdWZmZXIgKSB7XHJcblxyXG5cdFx0XHRpZiAoIGlzQ3ViZSApIHRocm93IG5ldyBFcnJvciggJ3RhcmdldC5kZXB0aFRleHR1cmUgbm90IHN1cHBvcnRlZCBpbiBDdWJlIHJlbmRlciB0YXJnZXRzJyApO1xyXG5cclxuXHRcdFx0c2V0dXBEZXB0aFRleHR1cmUoIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbEZyYW1lYnVmZmVyLCByZW5kZXJUYXJnZXQgKTtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0aWYgKCBpc0N1YmUgKSB7XHJcblxyXG5cdFx0XHRcdHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbERlcHRoYnVmZmVyID0gW107XHJcblxyXG5cdFx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IDY7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0c3RhdGUuYmluZEZyYW1lYnVmZmVyKCBfZ2wuRlJBTUVCVUZGRVIsIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbEZyYW1lYnVmZmVyWyBpIF0gKTtcclxuXHRcdFx0XHRcdHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbERlcHRoYnVmZmVyWyBpIF0gPSBfZ2wuY3JlYXRlUmVuZGVyYnVmZmVyKCk7XHJcblx0XHRcdFx0XHRzZXR1cFJlbmRlckJ1ZmZlclN0b3JhZ2UoIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbERlcHRoYnVmZmVyWyBpIF0sIHJlbmRlclRhcmdldCwgZmFsc2UgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0c3RhdGUuYmluZEZyYW1lYnVmZmVyKCBfZ2wuRlJBTUVCVUZGRVIsIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbEZyYW1lYnVmZmVyICk7XHJcblx0XHRcdFx0cmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX3dlYmdsRGVwdGhidWZmZXIgPSBfZ2wuY3JlYXRlUmVuZGVyYnVmZmVyKCk7XHJcblx0XHRcdFx0c2V0dXBSZW5kZXJCdWZmZXJTdG9yYWdlKCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xEZXB0aGJ1ZmZlciwgcmVuZGVyVGFyZ2V0LCBmYWxzZSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRzdGF0ZS5iaW5kRnJhbWVidWZmZXIoIF9nbC5GUkFNRUJVRkZFUiwgbnVsbCApO1xyXG5cclxuXHR9XHJcblxyXG5cdC8vIHJlYmluZCBmcmFtZWJ1ZmZlciB3aXRoIGV4dGVybmFsIHRleHR1cmVzXHJcblx0ZnVuY3Rpb24gcmViaW5kVGV4dHVyZXMoIHJlbmRlclRhcmdldCwgY29sb3JUZXh0dXJlLCBkZXB0aFRleHR1cmUgKSB7XHJcblxyXG5cdFx0Y29uc3QgcmVuZGVyVGFyZ2V0UHJvcGVydGllcyA9IHByb3BlcnRpZXMuZ2V0KCByZW5kZXJUYXJnZXQgKTtcclxuXHJcblx0XHRpZiAoIGNvbG9yVGV4dHVyZSAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0c2V0dXBGcmFtZUJ1ZmZlclRleHR1cmUoIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbEZyYW1lYnVmZmVyLCByZW5kZXJUYXJnZXQsIHJlbmRlclRhcmdldC50ZXh0dXJlLCBfZ2wuQ09MT1JfQVRUQUNITUVOVDAsIF9nbC5URVhUVVJFXzJELCAwICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggZGVwdGhUZXh0dXJlICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRzZXR1cERlcHRoUmVuZGVyYnVmZmVyKCByZW5kZXJUYXJnZXQgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gU2V0IHVwIEdMIHJlc291cmNlcyBmb3IgdGhlIHJlbmRlciB0YXJnZXRcclxuXHRmdW5jdGlvbiBzZXR1cFJlbmRlclRhcmdldCggcmVuZGVyVGFyZ2V0ICkge1xyXG5cclxuXHRcdGNvbnN0IHRleHR1cmUgPSByZW5kZXJUYXJnZXQudGV4dHVyZTtcclxuXHJcblx0XHRjb25zdCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzID0gcHJvcGVydGllcy5nZXQoIHJlbmRlclRhcmdldCApO1xyXG5cdFx0Y29uc3QgdGV4dHVyZVByb3BlcnRpZXMgPSBwcm9wZXJ0aWVzLmdldCggdGV4dHVyZSApO1xyXG5cclxuXHRcdHJlbmRlclRhcmdldC5hZGRFdmVudExpc3RlbmVyKCAnZGlzcG9zZScsIG9uUmVuZGVyVGFyZ2V0RGlzcG9zZSApO1xyXG5cclxuXHRcdGlmICggcmVuZGVyVGFyZ2V0LmlzV2ViR0xNdWx0aXBsZVJlbmRlclRhcmdldHMgIT09IHRydWUgKSB7XHJcblxyXG5cdFx0XHRpZiAoIHRleHR1cmVQcm9wZXJ0aWVzLl9fd2ViZ2xUZXh0dXJlID09PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRcdHRleHR1cmVQcm9wZXJ0aWVzLl9fd2ViZ2xUZXh0dXJlID0gX2dsLmNyZWF0ZVRleHR1cmUoKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHRleHR1cmVQcm9wZXJ0aWVzLl9fdmVyc2lvbiA9IHRleHR1cmUudmVyc2lvbjtcclxuXHRcdFx0aW5mby5tZW1vcnkudGV4dHVyZXMgKys7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGNvbnN0IGlzQ3ViZSA9ICggcmVuZGVyVGFyZ2V0LmlzV2ViR0xDdWJlUmVuZGVyVGFyZ2V0ID09PSB0cnVlICk7XHJcblx0XHRjb25zdCBpc011bHRpcGxlUmVuZGVyVGFyZ2V0cyA9ICggcmVuZGVyVGFyZ2V0LmlzV2ViR0xNdWx0aXBsZVJlbmRlclRhcmdldHMgPT09IHRydWUgKTtcclxuXHRcdGNvbnN0IHN1cHBvcnRzTWlwcyA9IGlzUG93ZXJPZlR3byggcmVuZGVyVGFyZ2V0ICkgfHwgaXNXZWJHTDI7XHJcblxyXG5cdFx0Ly8gU2V0dXAgZnJhbWVidWZmZXJcclxuXHJcblx0XHRpZiAoIGlzQ3ViZSApIHtcclxuXHJcblx0XHRcdHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbEZyYW1lYnVmZmVyID0gW107XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCA2OyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRpZiAoIGlzV2ViR0wyICYmIHRleHR1cmUubWlwbWFwcyAmJiB0ZXh0dXJlLm1pcG1hcHMubGVuZ3RoID4gMCApIHtcclxuXHJcblx0XHRcdFx0XHRyZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xGcmFtZWJ1ZmZlclsgaSBdID0gW107XHJcblxyXG5cdFx0XHRcdFx0Zm9yICggbGV0IGxldmVsID0gMDsgbGV2ZWwgPCB0ZXh0dXJlLm1pcG1hcHMubGVuZ3RoOyBsZXZlbCArKyApIHtcclxuXHJcblx0XHRcdFx0XHRcdHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbEZyYW1lYnVmZmVyWyBpIF1bIGxldmVsIF0gPSBfZ2wuY3JlYXRlRnJhbWVidWZmZXIoKTtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0cmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX3dlYmdsRnJhbWVidWZmZXJbIGkgXSA9IF9nbC5jcmVhdGVGcmFtZWJ1ZmZlcigpO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdGlmICggaXNXZWJHTDIgJiYgdGV4dHVyZS5taXBtYXBzICYmIHRleHR1cmUubWlwbWFwcy5sZW5ndGggPiAwICkge1xyXG5cclxuXHRcdFx0XHRyZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xGcmFtZWJ1ZmZlciA9IFtdO1xyXG5cclxuXHRcdFx0XHRmb3IgKCBsZXQgbGV2ZWwgPSAwOyBsZXZlbCA8IHRleHR1cmUubWlwbWFwcy5sZW5ndGg7IGxldmVsICsrICkge1xyXG5cclxuXHRcdFx0XHRcdHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbEZyYW1lYnVmZmVyWyBsZXZlbCBdID0gX2dsLmNyZWF0ZUZyYW1lYnVmZmVyKCk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbEZyYW1lYnVmZmVyID0gX2dsLmNyZWF0ZUZyYW1lYnVmZmVyKCk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRpZiAoIGlzTXVsdGlwbGVSZW5kZXJUYXJnZXRzICkge1xyXG5cclxuXHRcdFx0XHRpZiAoIGNhcGFiaWxpdGllcy5kcmF3QnVmZmVycyApIHtcclxuXHJcblx0XHRcdFx0XHRjb25zdCB0ZXh0dXJlcyA9IHJlbmRlclRhcmdldC50ZXh0dXJlO1xyXG5cclxuXHRcdFx0XHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSB0ZXh0dXJlcy5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0XHRcdGNvbnN0IGF0dGFjaG1lbnRQcm9wZXJ0aWVzID0gcHJvcGVydGllcy5nZXQoIHRleHR1cmVzWyBpIF0gKTtcclxuXHJcblx0XHRcdFx0XHRcdGlmICggYXR0YWNobWVudFByb3BlcnRpZXMuX193ZWJnbFRleHR1cmUgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0YXR0YWNobWVudFByb3BlcnRpZXMuX193ZWJnbFRleHR1cmUgPSBfZ2wuY3JlYXRlVGV4dHVyZSgpO1xyXG5cclxuXHRcdFx0XHRcdFx0XHRpbmZvLm1lbW9yeS50ZXh0dXJlcyArKztcclxuXHJcblx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuV2ViR0xSZW5kZXJlcjogV2ViR0xNdWx0aXBsZVJlbmRlclRhcmdldHMgY2FuIG9ubHkgYmUgdXNlZCB3aXRoIFdlYkdMMiBvciBXRUJHTF9kcmF3X2J1ZmZlcnMgZXh0ZW5zaW9uLicgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0aWYgKCAoIGlzV2ViR0wyICYmIHJlbmRlclRhcmdldC5zYW1wbGVzID4gMCApICYmIHVzZU11bHRpc2FtcGxlZFJUVCggcmVuZGVyVGFyZ2V0ICkgPT09IGZhbHNlICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCB0ZXh0dXJlcyA9IGlzTXVsdGlwbGVSZW5kZXJUYXJnZXRzID8gdGV4dHVyZSA6IFsgdGV4dHVyZSBdO1xyXG5cclxuXHRcdFx0XHRyZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xNdWx0aXNhbXBsZWRGcmFtZWJ1ZmZlciA9IF9nbC5jcmVhdGVGcmFtZWJ1ZmZlcigpO1xyXG5cdFx0XHRcdHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbENvbG9yUmVuZGVyYnVmZmVyID0gW107XHJcblxyXG5cdFx0XHRcdHN0YXRlLmJpbmRGcmFtZWJ1ZmZlciggX2dsLkZSQU1FQlVGRkVSLCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xNdWx0aXNhbXBsZWRGcmFtZWJ1ZmZlciApO1xyXG5cclxuXHRcdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCB0ZXh0dXJlcy5sZW5ndGg7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgdGV4dHVyZSA9IHRleHR1cmVzWyBpIF07XHJcblx0XHRcdFx0XHRyZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xDb2xvclJlbmRlcmJ1ZmZlclsgaSBdID0gX2dsLmNyZWF0ZVJlbmRlcmJ1ZmZlcigpO1xyXG5cclxuXHRcdFx0XHRcdF9nbC5iaW5kUmVuZGVyYnVmZmVyKCBfZ2wuUkVOREVSQlVGRkVSLCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xDb2xvclJlbmRlcmJ1ZmZlclsgaSBdICk7XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgZ2xGb3JtYXQgPSB1dGlscy5jb252ZXJ0KCB0ZXh0dXJlLmZvcm1hdCwgdGV4dHVyZS5jb2xvclNwYWNlICk7XHJcblx0XHRcdFx0XHRjb25zdCBnbFR5cGUgPSB1dGlscy5jb252ZXJ0KCB0ZXh0dXJlLnR5cGUgKTtcclxuXHRcdFx0XHRcdGNvbnN0IGdsSW50ZXJuYWxGb3JtYXQgPSBnZXRJbnRlcm5hbEZvcm1hdCggdGV4dHVyZS5pbnRlcm5hbEZvcm1hdCwgZ2xGb3JtYXQsIGdsVHlwZSwgdGV4dHVyZS5jb2xvclNwYWNlLCByZW5kZXJUYXJnZXQuaXNYUlJlbmRlclRhcmdldCA9PT0gdHJ1ZSApO1xyXG5cdFx0XHRcdFx0Y29uc3Qgc2FtcGxlcyA9IGdldFJlbmRlclRhcmdldFNhbXBsZXMoIHJlbmRlclRhcmdldCApO1xyXG5cdFx0XHRcdFx0X2dsLnJlbmRlcmJ1ZmZlclN0b3JhZ2VNdWx0aXNhbXBsZSggX2dsLlJFTkRFUkJVRkZFUiwgc2FtcGxlcywgZ2xJbnRlcm5hbEZvcm1hdCwgcmVuZGVyVGFyZ2V0LndpZHRoLCByZW5kZXJUYXJnZXQuaGVpZ2h0ICk7XHJcblxyXG5cdFx0XHRcdFx0X2dsLmZyYW1lYnVmZmVyUmVuZGVyYnVmZmVyKCBfZ2wuRlJBTUVCVUZGRVIsIF9nbC5DT0xPUl9BVFRBQ0hNRU5UMCArIGksIF9nbC5SRU5ERVJCVUZGRVIsIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbENvbG9yUmVuZGVyYnVmZmVyWyBpIF0gKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRfZ2wuYmluZFJlbmRlcmJ1ZmZlciggX2dsLlJFTkRFUkJVRkZFUiwgbnVsbCApO1xyXG5cclxuXHRcdFx0XHRpZiAoIHJlbmRlclRhcmdldC5kZXB0aEJ1ZmZlciApIHtcclxuXHJcblx0XHRcdFx0XHRyZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xEZXB0aFJlbmRlcmJ1ZmZlciA9IF9nbC5jcmVhdGVSZW5kZXJidWZmZXIoKTtcclxuXHRcdFx0XHRcdHNldHVwUmVuZGVyQnVmZmVyU3RvcmFnZSggcmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX3dlYmdsRGVwdGhSZW5kZXJidWZmZXIsIHJlbmRlclRhcmdldCwgdHJ1ZSApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdHN0YXRlLmJpbmRGcmFtZWJ1ZmZlciggX2dsLkZSQU1FQlVGRkVSLCBudWxsICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIFNldHVwIGNvbG9yIGJ1ZmZlclxyXG5cclxuXHRcdGlmICggaXNDdWJlICkge1xyXG5cclxuXHRcdFx0c3RhdGUuYmluZFRleHR1cmUoIF9nbC5URVhUVVJFX0NVQkVfTUFQLCB0ZXh0dXJlUHJvcGVydGllcy5fX3dlYmdsVGV4dHVyZSApO1xyXG5cdFx0XHRzZXRUZXh0dXJlUGFyYW1ldGVycyggX2dsLlRFWFRVUkVfQ1VCRV9NQVAsIHRleHR1cmUsIHN1cHBvcnRzTWlwcyApO1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgNjsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0aWYgKCBpc1dlYkdMMiAmJiB0ZXh0dXJlLm1pcG1hcHMgJiYgdGV4dHVyZS5taXBtYXBzLmxlbmd0aCA+IDAgKSB7XHJcblxyXG5cdFx0XHRcdFx0Zm9yICggbGV0IGxldmVsID0gMDsgbGV2ZWwgPCB0ZXh0dXJlLm1pcG1hcHMubGVuZ3RoOyBsZXZlbCArKyApIHtcclxuXHJcblx0XHRcdFx0XHRcdHNldHVwRnJhbWVCdWZmZXJUZXh0dXJlKCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xGcmFtZWJ1ZmZlclsgaSBdWyBsZXZlbCBdLCByZW5kZXJUYXJnZXQsIHRleHR1cmUsIF9nbC5DT0xPUl9BVFRBQ0hNRU5UMCwgX2dsLlRFWFRVUkVfQ1VCRV9NQVBfUE9TSVRJVkVfWCArIGksIGxldmVsICk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdHNldHVwRnJhbWVCdWZmZXJUZXh0dXJlKCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xGcmFtZWJ1ZmZlclsgaSBdLCByZW5kZXJUYXJnZXQsIHRleHR1cmUsIF9nbC5DT0xPUl9BVFRBQ0hNRU5UMCwgX2dsLlRFWFRVUkVfQ1VCRV9NQVBfUE9TSVRJVkVfWCArIGksIDAgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0aWYgKCB0ZXh0dXJlTmVlZHNHZW5lcmF0ZU1pcG1hcHMoIHRleHR1cmUsIHN1cHBvcnRzTWlwcyApICkge1xyXG5cclxuXHRcdFx0XHRnZW5lcmF0ZU1pcG1hcCggX2dsLlRFWFRVUkVfQ1VCRV9NQVAgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHN0YXRlLnVuYmluZFRleHR1cmUoKTtcclxuXHJcblx0XHR9IGVsc2UgaWYgKCBpc011bHRpcGxlUmVuZGVyVGFyZ2V0cyApIHtcclxuXHJcblx0XHRcdGNvbnN0IHRleHR1cmVzID0gcmVuZGVyVGFyZ2V0LnRleHR1cmU7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gdGV4dHVyZXMubGVuZ3RoOyBpIDwgaWw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IGF0dGFjaG1lbnQgPSB0ZXh0dXJlc1sgaSBdO1xyXG5cdFx0XHRcdGNvbnN0IGF0dGFjaG1lbnRQcm9wZXJ0aWVzID0gcHJvcGVydGllcy5nZXQoIGF0dGFjaG1lbnQgKTtcclxuXHJcblx0XHRcdFx0c3RhdGUuYmluZFRleHR1cmUoIF9nbC5URVhUVVJFXzJELCBhdHRhY2htZW50UHJvcGVydGllcy5fX3dlYmdsVGV4dHVyZSApO1xyXG5cdFx0XHRcdHNldFRleHR1cmVQYXJhbWV0ZXJzKCBfZ2wuVEVYVFVSRV8yRCwgYXR0YWNobWVudCwgc3VwcG9ydHNNaXBzICk7XHJcblx0XHRcdFx0c2V0dXBGcmFtZUJ1ZmZlclRleHR1cmUoIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbEZyYW1lYnVmZmVyLCByZW5kZXJUYXJnZXQsIGF0dGFjaG1lbnQsIF9nbC5DT0xPUl9BVFRBQ0hNRU5UMCArIGksIF9nbC5URVhUVVJFXzJELCAwICk7XHJcblxyXG5cdFx0XHRcdGlmICggdGV4dHVyZU5lZWRzR2VuZXJhdGVNaXBtYXBzKCBhdHRhY2htZW50LCBzdXBwb3J0c01pcHMgKSApIHtcclxuXHJcblx0XHRcdFx0XHRnZW5lcmF0ZU1pcG1hcCggX2dsLlRFWFRVUkVfMkQgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0c3RhdGUudW5iaW5kVGV4dHVyZSgpO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRsZXQgZ2xUZXh0dXJlVHlwZSA9IF9nbC5URVhUVVJFXzJEO1xyXG5cclxuXHRcdFx0aWYgKCByZW5kZXJUYXJnZXQuaXNXZWJHTDNEUmVuZGVyVGFyZ2V0IHx8IHJlbmRlclRhcmdldC5pc1dlYkdMQXJyYXlSZW5kZXJUYXJnZXQgKSB7XHJcblxyXG5cdFx0XHRcdGlmICggaXNXZWJHTDIgKSB7XHJcblxyXG5cdFx0XHRcdFx0Z2xUZXh0dXJlVHlwZSA9IHJlbmRlclRhcmdldC5pc1dlYkdMM0RSZW5kZXJUYXJnZXQgPyBfZ2wuVEVYVFVSRV8zRCA6IF9nbC5URVhUVVJFXzJEX0FSUkFZO1xyXG5cclxuXHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5XZWJHTFRleHR1cmVzOiBUSFJFRS5EYXRhM0RUZXh0dXJlIGFuZCBUSFJFRS5EYXRhQXJyYXlUZXh0dXJlIG9ubHkgc3VwcG9ydGVkIHdpdGggV2ViR0wyLicgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0c3RhdGUuYmluZFRleHR1cmUoIGdsVGV4dHVyZVR5cGUsIHRleHR1cmVQcm9wZXJ0aWVzLl9fd2ViZ2xUZXh0dXJlICk7XHJcblx0XHRcdHNldFRleHR1cmVQYXJhbWV0ZXJzKCBnbFRleHR1cmVUeXBlLCB0ZXh0dXJlLCBzdXBwb3J0c01pcHMgKTtcclxuXHJcblx0XHRcdGlmICggaXNXZWJHTDIgJiYgdGV4dHVyZS5taXBtYXBzICYmIHRleHR1cmUubWlwbWFwcy5sZW5ndGggPiAwICkge1xyXG5cclxuXHRcdFx0XHRmb3IgKCBsZXQgbGV2ZWwgPSAwOyBsZXZlbCA8IHRleHR1cmUubWlwbWFwcy5sZW5ndGg7IGxldmVsICsrICkge1xyXG5cclxuXHRcdFx0XHRcdHNldHVwRnJhbWVCdWZmZXJUZXh0dXJlKCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xGcmFtZWJ1ZmZlclsgbGV2ZWwgXSwgcmVuZGVyVGFyZ2V0LCB0ZXh0dXJlLCBfZ2wuQ09MT1JfQVRUQUNITUVOVDAsIGdsVGV4dHVyZVR5cGUsIGxldmVsICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdHNldHVwRnJhbWVCdWZmZXJUZXh0dXJlKCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xGcmFtZWJ1ZmZlciwgcmVuZGVyVGFyZ2V0LCB0ZXh0dXJlLCBfZ2wuQ09MT1JfQVRUQUNITUVOVDAsIGdsVGV4dHVyZVR5cGUsIDAgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGlmICggdGV4dHVyZU5lZWRzR2VuZXJhdGVNaXBtYXBzKCB0ZXh0dXJlLCBzdXBwb3J0c01pcHMgKSApIHtcclxuXHJcblx0XHRcdFx0Z2VuZXJhdGVNaXBtYXAoIGdsVGV4dHVyZVR5cGUgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHN0YXRlLnVuYmluZFRleHR1cmUoKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gU2V0dXAgZGVwdGggYW5kIHN0ZW5jaWwgYnVmZmVyc1xyXG5cclxuXHRcdGlmICggcmVuZGVyVGFyZ2V0LmRlcHRoQnVmZmVyICkge1xyXG5cclxuXHRcdFx0c2V0dXBEZXB0aFJlbmRlcmJ1ZmZlciggcmVuZGVyVGFyZ2V0ICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHVwZGF0ZVJlbmRlclRhcmdldE1pcG1hcCggcmVuZGVyVGFyZ2V0ICkge1xyXG5cclxuXHRcdGNvbnN0IHN1cHBvcnRzTWlwcyA9IGlzUG93ZXJPZlR3byggcmVuZGVyVGFyZ2V0ICkgfHwgaXNXZWJHTDI7XHJcblxyXG5cdFx0Y29uc3QgdGV4dHVyZXMgPSByZW5kZXJUYXJnZXQuaXNXZWJHTE11bHRpcGxlUmVuZGVyVGFyZ2V0cyA9PT0gdHJ1ZSA/IHJlbmRlclRhcmdldC50ZXh0dXJlIDogWyByZW5kZXJUYXJnZXQudGV4dHVyZSBdO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSB0ZXh0dXJlcy5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcclxuXHJcblx0XHRcdGNvbnN0IHRleHR1cmUgPSB0ZXh0dXJlc1sgaSBdO1xyXG5cclxuXHRcdFx0aWYgKCB0ZXh0dXJlTmVlZHNHZW5lcmF0ZU1pcG1hcHMoIHRleHR1cmUsIHN1cHBvcnRzTWlwcyApICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCB0YXJnZXQgPSByZW5kZXJUYXJnZXQuaXNXZWJHTEN1YmVSZW5kZXJUYXJnZXQgPyBfZ2wuVEVYVFVSRV9DVUJFX01BUCA6IF9nbC5URVhUVVJFXzJEO1xyXG5cdFx0XHRcdGNvbnN0IHdlYmdsVGV4dHVyZSA9IHByb3BlcnRpZXMuZ2V0KCB0ZXh0dXJlICkuX193ZWJnbFRleHR1cmU7XHJcblxyXG5cdFx0XHRcdHN0YXRlLmJpbmRUZXh0dXJlKCB0YXJnZXQsIHdlYmdsVGV4dHVyZSApO1xyXG5cdFx0XHRcdGdlbmVyYXRlTWlwbWFwKCB0YXJnZXQgKTtcclxuXHRcdFx0XHRzdGF0ZS51bmJpbmRUZXh0dXJlKCk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHVwZGF0ZU11bHRpc2FtcGxlUmVuZGVyVGFyZ2V0KCByZW5kZXJUYXJnZXQgKSB7XHJcblxyXG5cdFx0aWYgKCAoIGlzV2ViR0wyICYmIHJlbmRlclRhcmdldC5zYW1wbGVzID4gMCApICYmIHVzZU11bHRpc2FtcGxlZFJUVCggcmVuZGVyVGFyZ2V0ICkgPT09IGZhbHNlICkge1xyXG5cclxuXHRcdFx0Y29uc3QgdGV4dHVyZXMgPSByZW5kZXJUYXJnZXQuaXNXZWJHTE11bHRpcGxlUmVuZGVyVGFyZ2V0cyA/IHJlbmRlclRhcmdldC50ZXh0dXJlIDogWyByZW5kZXJUYXJnZXQudGV4dHVyZSBdO1xyXG5cdFx0XHRjb25zdCB3aWR0aCA9IHJlbmRlclRhcmdldC53aWR0aDtcclxuXHRcdFx0Y29uc3QgaGVpZ2h0ID0gcmVuZGVyVGFyZ2V0LmhlaWdodDtcclxuXHRcdFx0bGV0IG1hc2sgPSBfZ2wuQ09MT1JfQlVGRkVSX0JJVDtcclxuXHRcdFx0Y29uc3QgaW52YWxpZGF0aW9uQXJyYXkgPSBbXTtcclxuXHRcdFx0Y29uc3QgZGVwdGhTdHlsZSA9IHJlbmRlclRhcmdldC5zdGVuY2lsQnVmZmVyID8gX2dsLkRFUFRIX1NURU5DSUxfQVRUQUNITUVOVCA6IF9nbC5ERVBUSF9BVFRBQ0hNRU5UO1xyXG5cdFx0XHRjb25zdCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzID0gcHJvcGVydGllcy5nZXQoIHJlbmRlclRhcmdldCApO1xyXG5cdFx0XHRjb25zdCBpc011bHRpcGxlUmVuZGVyVGFyZ2V0cyA9ICggcmVuZGVyVGFyZ2V0LmlzV2ViR0xNdWx0aXBsZVJlbmRlclRhcmdldHMgPT09IHRydWUgKTtcclxuXHJcblx0XHRcdC8vIElmIE1SVCB3ZSBuZWVkIHRvIHJlbW92ZSBGQk8gYXR0YWNobWVudHNcclxuXHRcdFx0aWYgKCBpc011bHRpcGxlUmVuZGVyVGFyZ2V0cyApIHtcclxuXHJcblx0XHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgdGV4dHVyZXMubGVuZ3RoOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRcdHN0YXRlLmJpbmRGcmFtZWJ1ZmZlciggX2dsLkZSQU1FQlVGRkVSLCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xNdWx0aXNhbXBsZWRGcmFtZWJ1ZmZlciApO1xyXG5cdFx0XHRcdFx0X2dsLmZyYW1lYnVmZmVyUmVuZGVyYnVmZmVyKCBfZ2wuRlJBTUVCVUZGRVIsIF9nbC5DT0xPUl9BVFRBQ0hNRU5UMCArIGksIF9nbC5SRU5ERVJCVUZGRVIsIG51bGwgKTtcclxuXHJcblx0XHRcdFx0XHRzdGF0ZS5iaW5kRnJhbWVidWZmZXIoIF9nbC5GUkFNRUJVRkZFUiwgcmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX3dlYmdsRnJhbWVidWZmZXIgKTtcclxuXHRcdFx0XHRcdF9nbC5mcmFtZWJ1ZmZlclRleHR1cmUyRCggX2dsLkRSQVdfRlJBTUVCVUZGRVIsIF9nbC5DT0xPUl9BVFRBQ0hNRU5UMCArIGksIF9nbC5URVhUVVJFXzJELCBudWxsLCAwICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHN0YXRlLmJpbmRGcmFtZWJ1ZmZlciggX2dsLlJFQURfRlJBTUVCVUZGRVIsIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbE11bHRpc2FtcGxlZEZyYW1lYnVmZmVyICk7XHJcblx0XHRcdHN0YXRlLmJpbmRGcmFtZWJ1ZmZlciggX2dsLkRSQVdfRlJBTUVCVUZGRVIsIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbEZyYW1lYnVmZmVyICk7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCB0ZXh0dXJlcy5sZW5ndGg7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdGludmFsaWRhdGlvbkFycmF5LnB1c2goIF9nbC5DT0xPUl9BVFRBQ0hNRU5UMCArIGkgKTtcclxuXHJcblx0XHRcdFx0aWYgKCByZW5kZXJUYXJnZXQuZGVwdGhCdWZmZXIgKSB7XHJcblxyXG5cdFx0XHRcdFx0aW52YWxpZGF0aW9uQXJyYXkucHVzaCggZGVwdGhTdHlsZSApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdGNvbnN0IGlnbm9yZURlcHRoVmFsdWVzID0gKCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9faWdub3JlRGVwdGhWYWx1ZXMgIT09IHVuZGVmaW5lZCApID8gcmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX2lnbm9yZURlcHRoVmFsdWVzIDogZmFsc2U7XHJcblxyXG5cdFx0XHRcdGlmICggaWdub3JlRGVwdGhWYWx1ZXMgPT09IGZhbHNlICkge1xyXG5cclxuXHRcdFx0XHRcdGlmICggcmVuZGVyVGFyZ2V0LmRlcHRoQnVmZmVyICkgbWFzayB8PSBfZ2wuREVQVEhfQlVGRkVSX0JJVDtcclxuXHRcdFx0XHRcdGlmICggcmVuZGVyVGFyZ2V0LnN0ZW5jaWxCdWZmZXIgKSBtYXNrIHw9IF9nbC5TVEVOQ0lMX0JVRkZFUl9CSVQ7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0aWYgKCBpc011bHRpcGxlUmVuZGVyVGFyZ2V0cyApIHtcclxuXHJcblx0XHRcdFx0XHRfZ2wuZnJhbWVidWZmZXJSZW5kZXJidWZmZXIoIF9nbC5SRUFEX0ZSQU1FQlVGRkVSLCBfZ2wuQ09MT1JfQVRUQUNITUVOVDAsIF9nbC5SRU5ERVJCVUZGRVIsIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbENvbG9yUmVuZGVyYnVmZmVyWyBpIF0gKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRpZiAoIGlnbm9yZURlcHRoVmFsdWVzID09PSB0cnVlICkge1xyXG5cclxuXHRcdFx0XHRcdF9nbC5pbnZhbGlkYXRlRnJhbWVidWZmZXIoIF9nbC5SRUFEX0ZSQU1FQlVGRkVSLCBbIGRlcHRoU3R5bGUgXSApO1xyXG5cdFx0XHRcdFx0X2dsLmludmFsaWRhdGVGcmFtZWJ1ZmZlciggX2dsLkRSQVdfRlJBTUVCVUZGRVIsIFsgZGVwdGhTdHlsZSBdICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0aWYgKCBpc011bHRpcGxlUmVuZGVyVGFyZ2V0cyApIHtcclxuXHJcblx0XHRcdFx0XHRjb25zdCB3ZWJnbFRleHR1cmUgPSBwcm9wZXJ0aWVzLmdldCggdGV4dHVyZXNbIGkgXSApLl9fd2ViZ2xUZXh0dXJlO1xyXG5cdFx0XHRcdFx0X2dsLmZyYW1lYnVmZmVyVGV4dHVyZTJEKCBfZ2wuRFJBV19GUkFNRUJVRkZFUiwgX2dsLkNPTE9SX0FUVEFDSE1FTlQwLCBfZ2wuVEVYVFVSRV8yRCwgd2ViZ2xUZXh0dXJlLCAwICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0X2dsLmJsaXRGcmFtZWJ1ZmZlciggMCwgMCwgd2lkdGgsIGhlaWdodCwgMCwgMCwgd2lkdGgsIGhlaWdodCwgbWFzaywgX2dsLk5FQVJFU1QgKTtcclxuXHJcblx0XHRcdFx0aWYgKCBzdXBwb3J0c0ludmFsaWRhdGVGcmFtZWJ1ZmZlciApIHtcclxuXHJcblx0XHRcdFx0XHRfZ2wuaW52YWxpZGF0ZUZyYW1lYnVmZmVyKCBfZ2wuUkVBRF9GUkFNRUJVRkZFUiwgaW52YWxpZGF0aW9uQXJyYXkgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHN0YXRlLmJpbmRGcmFtZWJ1ZmZlciggX2dsLlJFQURfRlJBTUVCVUZGRVIsIG51bGwgKTtcclxuXHRcdFx0c3RhdGUuYmluZEZyYW1lYnVmZmVyKCBfZ2wuRFJBV19GUkFNRUJVRkZFUiwgbnVsbCApO1xyXG5cclxuXHRcdFx0Ly8gSWYgTVJUIHNpbmNlIHByZS1ibGl0IHdlIHJlbW92ZWQgdGhlIEZCTyB3ZSBuZWVkIHRvIHJlY29uc3RydWN0IHRoZSBhdHRhY2htZW50c1xyXG5cdFx0XHRpZiAoIGlzTXVsdGlwbGVSZW5kZXJUYXJnZXRzICkge1xyXG5cclxuXHRcdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCB0ZXh0dXJlcy5sZW5ndGg7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0c3RhdGUuYmluZEZyYW1lYnVmZmVyKCBfZ2wuRlJBTUVCVUZGRVIsIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbE11bHRpc2FtcGxlZEZyYW1lYnVmZmVyICk7XHJcblx0XHRcdFx0XHRfZ2wuZnJhbWVidWZmZXJSZW5kZXJidWZmZXIoIF9nbC5GUkFNRUJVRkZFUiwgX2dsLkNPTE9SX0FUVEFDSE1FTlQwICsgaSwgX2dsLlJFTkRFUkJVRkZFUiwgcmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX3dlYmdsQ29sb3JSZW5kZXJidWZmZXJbIGkgXSApO1xyXG5cclxuXHRcdFx0XHRcdGNvbnN0IHdlYmdsVGV4dHVyZSA9IHByb3BlcnRpZXMuZ2V0KCB0ZXh0dXJlc1sgaSBdICkuX193ZWJnbFRleHR1cmU7XHJcblxyXG5cdFx0XHRcdFx0c3RhdGUuYmluZEZyYW1lYnVmZmVyKCBfZ2wuRlJBTUVCVUZGRVIsIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbEZyYW1lYnVmZmVyICk7XHJcblx0XHRcdFx0XHRfZ2wuZnJhbWVidWZmZXJUZXh0dXJlMkQoIF9nbC5EUkFXX0ZSQU1FQlVGRkVSLCBfZ2wuQ09MT1JfQVRUQUNITUVOVDAgKyBpLCBfZ2wuVEVYVFVSRV8yRCwgd2ViZ2xUZXh0dXJlLCAwICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHN0YXRlLmJpbmRGcmFtZWJ1ZmZlciggX2dsLkRSQVdfRlJBTUVCVUZGRVIsIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbE11bHRpc2FtcGxlZEZyYW1lYnVmZmVyICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIGdldFJlbmRlclRhcmdldFNhbXBsZXMoIHJlbmRlclRhcmdldCApIHtcclxuXHJcblx0XHRyZXR1cm4gTWF0aC5taW4oIGNhcGFiaWxpdGllcy5tYXhTYW1wbGVzLCByZW5kZXJUYXJnZXQuc2FtcGxlcyApO1xyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHVzZU11bHRpc2FtcGxlZFJUVCggcmVuZGVyVGFyZ2V0ICkge1xyXG5cclxuXHRcdGNvbnN0IHJlbmRlclRhcmdldFByb3BlcnRpZXMgPSBwcm9wZXJ0aWVzLmdldCggcmVuZGVyVGFyZ2V0ICk7XHJcblxyXG5cdFx0cmV0dXJuIGlzV2ViR0wyICYmIHJlbmRlclRhcmdldC5zYW1wbGVzID4gMCAmJiBleHRlbnNpb25zLmhhcyggJ1dFQkdMX211bHRpc2FtcGxlZF9yZW5kZXJfdG9fdGV4dHVyZScgKSA9PT0gdHJ1ZSAmJiByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fdXNlUmVuZGVyVG9UZXh0dXJlICE9PSBmYWxzZTtcclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiB1cGRhdGVWaWRlb1RleHR1cmUoIHRleHR1cmUgKSB7XHJcblxyXG5cdFx0Y29uc3QgZnJhbWUgPSBpbmZvLnJlbmRlci5mcmFtZTtcclxuXHJcblx0XHQvLyBDaGVjayB0aGUgbGFzdCBmcmFtZSB3ZSB1cGRhdGVkIHRoZSBWaWRlb1RleHR1cmVcclxuXHJcblx0XHRpZiAoIF92aWRlb1RleHR1cmVzLmdldCggdGV4dHVyZSApICE9PSBmcmFtZSApIHtcclxuXHJcblx0XHRcdF92aWRlb1RleHR1cmVzLnNldCggdGV4dHVyZSwgZnJhbWUgKTtcclxuXHRcdFx0dGV4dHVyZS51cGRhdGUoKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gdmVyaWZ5Q29sb3JTcGFjZSggdGV4dHVyZSwgaW1hZ2UgKSB7XHJcblxyXG5cdFx0Y29uc3QgY29sb3JTcGFjZSA9IHRleHR1cmUuY29sb3JTcGFjZTtcclxuXHRcdGNvbnN0IGZvcm1hdCA9IHRleHR1cmUuZm9ybWF0O1xyXG5cdFx0Y29uc3QgdHlwZSA9IHRleHR1cmUudHlwZTtcclxuXHJcblx0XHRpZiAoIHRleHR1cmUuaXNDb21wcmVzc2VkVGV4dHVyZSA9PT0gdHJ1ZSB8fCB0ZXh0dXJlLmlzVmlkZW9UZXh0dXJlID09PSB0cnVlIHx8IHRleHR1cmUuZm9ybWF0ID09PSBfU1JHQkFGb3JtYXQgKSByZXR1cm4gaW1hZ2U7XHJcblxyXG5cdFx0aWYgKCBjb2xvclNwYWNlICE9PSBMaW5lYXJTUkdCQ29sb3JTcGFjZSAmJiBjb2xvclNwYWNlICE9PSBOb0NvbG9yU3BhY2UgKSB7XHJcblxyXG5cdFx0XHQvLyBzUkdCXHJcblxyXG5cdFx0XHRpZiAoIENvbG9yTWFuYWdlbWVudC5nZXRUcmFuc2ZlciggY29sb3JTcGFjZSApID09PSBTUkdCVHJhbnNmZXIgKSB7XHJcblxyXG5cdFx0XHRcdGlmICggaXNXZWJHTDIgPT09IGZhbHNlICkge1xyXG5cclxuXHRcdFx0XHRcdC8vIGluIFdlYkdMIDEsIHRyeSB0byB1c2UgRVhUX3NSR0IgZXh0ZW5zaW9uIGFuZCB1bnNpemVkIGZvcm1hdHNcclxuXHJcblx0XHRcdFx0XHRpZiAoIGV4dGVuc2lvbnMuaGFzKCAnRVhUX3NSR0InICkgPT09IHRydWUgJiYgZm9ybWF0ID09PSBSR0JBRm9ybWF0ICkge1xyXG5cclxuXHRcdFx0XHRcdFx0dGV4dHVyZS5mb3JtYXQgPSBfU1JHQkFGb3JtYXQ7XHJcblxyXG5cdFx0XHRcdFx0XHQvLyBpdCdzIG5vdCBwb3NzaWJsZSB0byBnZW5lcmF0ZSBtaXBzIGluIFdlYkdMIDEgd2l0aCB0aGlzIGV4dGVuc2lvblxyXG5cclxuXHRcdFx0XHRcdFx0dGV4dHVyZS5taW5GaWx0ZXIgPSBMaW5lYXJGaWx0ZXI7XHJcblx0XHRcdFx0XHRcdHRleHR1cmUuZ2VuZXJhdGVNaXBtYXBzID0gZmFsc2U7XHJcblxyXG5cdFx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRcdC8vIHNsb3cgZmFsbGJhY2sgKENQVSBkZWNvZGUpXHJcblxyXG5cdFx0XHRcdFx0XHRpbWFnZSA9IEltYWdlVXRpbHMuc1JHQlRvTGluZWFyKCBpbWFnZSApO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHQvLyBpbiBXZWJHTCAyIHVuY29tcHJlc3NlZCB0ZXh0dXJlcyBjYW4gb25seSBiZSBzUkdCIGVuY29kZWQgaWYgdGhleSBoYXZlIHRoZSBSR0JBOCBmb3JtYXRcclxuXHJcblx0XHRcdFx0XHRpZiAoIGZvcm1hdCAhPT0gUkdCQUZvcm1hdCB8fCB0eXBlICE9PSBVbnNpZ25lZEJ5dGVUeXBlICkge1xyXG5cclxuXHRcdFx0XHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuV2ViR0xUZXh0dXJlczogc1JHQiBlbmNvZGVkIHRleHR1cmVzIGhhdmUgdG8gdXNlIFJHQkFGb3JtYXQgYW5kIFVuc2lnbmVkQnl0ZVR5cGUuJyApO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLldlYkdMVGV4dHVyZXM6IFVuc3VwcG9ydGVkIHRleHR1cmUgY29sb3Igc3BhY2U6JywgY29sb3JTcGFjZSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gaW1hZ2U7XHJcblxyXG5cdH1cclxuXHJcblx0Ly9cclxuXHJcblx0dGhpcy5hbGxvY2F0ZVRleHR1cmVVbml0ID0gYWxsb2NhdGVUZXh0dXJlVW5pdDtcclxuXHR0aGlzLnJlc2V0VGV4dHVyZVVuaXRzID0gcmVzZXRUZXh0dXJlVW5pdHM7XHJcblxyXG5cdHRoaXMuc2V0VGV4dHVyZTJEID0gc2V0VGV4dHVyZTJEO1xyXG5cdHRoaXMuc2V0VGV4dHVyZTJEQXJyYXkgPSBzZXRUZXh0dXJlMkRBcnJheTtcclxuXHR0aGlzLnNldFRleHR1cmUzRCA9IHNldFRleHR1cmUzRDtcclxuXHR0aGlzLnNldFRleHR1cmVDdWJlID0gc2V0VGV4dHVyZUN1YmU7XHJcblx0dGhpcy5yZWJpbmRUZXh0dXJlcyA9IHJlYmluZFRleHR1cmVzO1xyXG5cdHRoaXMuc2V0dXBSZW5kZXJUYXJnZXQgPSBzZXR1cFJlbmRlclRhcmdldDtcclxuXHR0aGlzLnVwZGF0ZVJlbmRlclRhcmdldE1pcG1hcCA9IHVwZGF0ZVJlbmRlclRhcmdldE1pcG1hcDtcclxuXHR0aGlzLnVwZGF0ZU11bHRpc2FtcGxlUmVuZGVyVGFyZ2V0ID0gdXBkYXRlTXVsdGlzYW1wbGVSZW5kZXJUYXJnZXQ7XHJcblx0dGhpcy5zZXR1cERlcHRoUmVuZGVyYnVmZmVyID0gc2V0dXBEZXB0aFJlbmRlcmJ1ZmZlcjtcclxuXHR0aGlzLnNldHVwRnJhbWVCdWZmZXJUZXh0dXJlID0gc2V0dXBGcmFtZUJ1ZmZlclRleHR1cmU7XHJcblx0dGhpcy51c2VNdWx0aXNhbXBsZWRSVFQgPSB1c2VNdWx0aXNhbXBsZWRSVFQ7XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBXZWJHTFRleHR1cmVzIH07XHJcbiIsImltcG9ydCB7IFJHQkFfQVNUQ180eDRfRm9ybWF0LCBSR0JBX0FTVENfNXg0X0Zvcm1hdCwgUkdCQV9BU1RDXzV4NV9Gb3JtYXQsIFJHQkFfQVNUQ182eDVfRm9ybWF0LCBSR0JBX0FTVENfNng2X0Zvcm1hdCwgUkdCQV9BU1RDXzh4NV9Gb3JtYXQsIFJHQkFfQVNUQ184eDZfRm9ybWF0LCBSR0JBX0FTVENfOHg4X0Zvcm1hdCwgUkdCQV9BU1RDXzEweDVfRm9ybWF0LCBSR0JBX0FTVENfMTB4Nl9Gb3JtYXQsIFJHQkFfQVNUQ18xMHg4X0Zvcm1hdCwgUkdCQV9BU1RDXzEweDEwX0Zvcm1hdCwgUkdCQV9BU1RDXzEyeDEwX0Zvcm1hdCwgUkdCQV9BU1RDXzEyeDEyX0Zvcm1hdCwgUkdCX0VUQzFfRm9ybWF0LCBSR0JfRVRDMl9Gb3JtYXQsIFJHQkFfRVRDMl9FQUNfRm9ybWF0LCBSR0JBX1BWUlRDXzJCUFBWMV9Gb3JtYXQsIFJHQkFfUFZSVENfNEJQUFYxX0Zvcm1hdCwgUkdCX1BWUlRDXzJCUFBWMV9Gb3JtYXQsIFJHQl9QVlJUQ180QlBQVjFfRm9ybWF0LCBSR0JBX1MzVENfRFhUNV9Gb3JtYXQsIFJHQkFfUzNUQ19EWFQzX0Zvcm1hdCwgUkdCQV9TM1RDX0RYVDFfRm9ybWF0LCBSR0JfUzNUQ19EWFQxX0Zvcm1hdCwgRGVwdGhGb3JtYXQsIERlcHRoU3RlbmNpbEZvcm1hdCwgTHVtaW5hbmNlQWxwaGFGb3JtYXQsIEx1bWluYW5jZUZvcm1hdCwgUmVkRm9ybWF0LCBSR0JBRm9ybWF0LCBBbHBoYUZvcm1hdCwgUmVkSW50ZWdlckZvcm1hdCwgUkdGb3JtYXQsIFJHSW50ZWdlckZvcm1hdCwgUkdCQUludGVnZXJGb3JtYXQsIEhhbGZGbG9hdFR5cGUsIEZsb2F0VHlwZSwgVW5zaWduZWRJbnRUeXBlLCBJbnRUeXBlLCBVbnNpZ25lZFNob3J0VHlwZSwgU2hvcnRUeXBlLCBCeXRlVHlwZSwgVW5zaWduZWRJbnQyNDhUeXBlLCBVbnNpZ25lZFNob3J0NTU1MVR5cGUsIFVuc2lnbmVkU2hvcnQ0NDQ0VHlwZSwgVW5zaWduZWRCeXRlVHlwZSwgUkdCQV9CUFRDX0Zvcm1hdCwgUkdCX0JQVENfU0lHTkVEX0Zvcm1hdCwgUkdCX0JQVENfVU5TSUdORURfRm9ybWF0LCBfU1JHQkFGb3JtYXQsIFJFRF9SR1RDMV9Gb3JtYXQsIFNJR05FRF9SRURfUkdUQzFfRm9ybWF0LCBSRURfR1JFRU5fUkdUQzJfRm9ybWF0LCBTSUdORURfUkVEX0dSRUVOX1JHVEMyX0Zvcm1hdCwgTm9Db2xvclNwYWNlLCBTUkdCVHJhbnNmZXIgfSBmcm9tICcuLi8uLi9jb25zdGFudHMuanMnO1xyXG5pbXBvcnQgeyBDb2xvck1hbmFnZW1lbnQgfSBmcm9tICcuLi8uLi9tYXRoL0NvbG9yTWFuYWdlbWVudC5qcyc7XHJcblxyXG5mdW5jdGlvbiBXZWJHTFV0aWxzKCBnbCwgZXh0ZW5zaW9ucywgY2FwYWJpbGl0aWVzICkge1xyXG5cclxuXHRjb25zdCBpc1dlYkdMMiA9IGNhcGFiaWxpdGllcy5pc1dlYkdMMjtcclxuXHJcblx0ZnVuY3Rpb24gY29udmVydCggcCwgY29sb3JTcGFjZSA9IE5vQ29sb3JTcGFjZSApIHtcclxuXHJcblx0XHRsZXQgZXh0ZW5zaW9uO1xyXG5cclxuXHRcdGNvbnN0IHRyYW5zZmVyID0gQ29sb3JNYW5hZ2VtZW50LmdldFRyYW5zZmVyKCBjb2xvclNwYWNlICk7XHJcblxyXG5cdFx0aWYgKCBwID09PSBVbnNpZ25lZEJ5dGVUeXBlICkgcmV0dXJuIGdsLlVOU0lHTkVEX0JZVEU7XHJcblx0XHRpZiAoIHAgPT09IFVuc2lnbmVkU2hvcnQ0NDQ0VHlwZSApIHJldHVybiBnbC5VTlNJR05FRF9TSE9SVF80XzRfNF80O1xyXG5cdFx0aWYgKCBwID09PSBVbnNpZ25lZFNob3J0NTU1MVR5cGUgKSByZXR1cm4gZ2wuVU5TSUdORURfU0hPUlRfNV81XzVfMTtcclxuXHJcblx0XHRpZiAoIHAgPT09IEJ5dGVUeXBlICkgcmV0dXJuIGdsLkJZVEU7XHJcblx0XHRpZiAoIHAgPT09IFNob3J0VHlwZSApIHJldHVybiBnbC5TSE9SVDtcclxuXHRcdGlmICggcCA9PT0gVW5zaWduZWRTaG9ydFR5cGUgKSByZXR1cm4gZ2wuVU5TSUdORURfU0hPUlQ7XHJcblx0XHRpZiAoIHAgPT09IEludFR5cGUgKSByZXR1cm4gZ2wuSU5UO1xyXG5cdFx0aWYgKCBwID09PSBVbnNpZ25lZEludFR5cGUgKSByZXR1cm4gZ2wuVU5TSUdORURfSU5UO1xyXG5cdFx0aWYgKCBwID09PSBGbG9hdFR5cGUgKSByZXR1cm4gZ2wuRkxPQVQ7XHJcblxyXG5cdFx0aWYgKCBwID09PSBIYWxmRmxvYXRUeXBlICkge1xyXG5cclxuXHRcdFx0aWYgKCBpc1dlYkdMMiApIHJldHVybiBnbC5IQUxGX0ZMT0FUO1xyXG5cclxuXHRcdFx0ZXh0ZW5zaW9uID0gZXh0ZW5zaW9ucy5nZXQoICdPRVNfdGV4dHVyZV9oYWxmX2Zsb2F0JyApO1xyXG5cclxuXHRcdFx0aWYgKCBleHRlbnNpb24gIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdHJldHVybiBleHRlbnNpb24uSEFMRl9GTE9BVF9PRVM7XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRyZXR1cm4gbnVsbDtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBwID09PSBBbHBoYUZvcm1hdCApIHJldHVybiBnbC5BTFBIQTtcclxuXHRcdGlmICggcCA9PT0gUkdCQUZvcm1hdCApIHJldHVybiBnbC5SR0JBO1xyXG5cdFx0aWYgKCBwID09PSBMdW1pbmFuY2VGb3JtYXQgKSByZXR1cm4gZ2wuTFVNSU5BTkNFO1xyXG5cdFx0aWYgKCBwID09PSBMdW1pbmFuY2VBbHBoYUZvcm1hdCApIHJldHVybiBnbC5MVU1JTkFOQ0VfQUxQSEE7XHJcblx0XHRpZiAoIHAgPT09IERlcHRoRm9ybWF0ICkgcmV0dXJuIGdsLkRFUFRIX0NPTVBPTkVOVDtcclxuXHRcdGlmICggcCA9PT0gRGVwdGhTdGVuY2lsRm9ybWF0ICkgcmV0dXJuIGdsLkRFUFRIX1NURU5DSUw7XHJcblxyXG5cdFx0Ly8gV2ViR0wgMSBzUkdCIGZhbGxiYWNrXHJcblxyXG5cdFx0aWYgKCBwID09PSBfU1JHQkFGb3JtYXQgKSB7XHJcblxyXG5cdFx0XHRleHRlbnNpb24gPSBleHRlbnNpb25zLmdldCggJ0VYVF9zUkdCJyApO1xyXG5cclxuXHRcdFx0aWYgKCBleHRlbnNpb24gIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdHJldHVybiBleHRlbnNpb24uU1JHQl9BTFBIQV9FWFQ7XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRyZXR1cm4gbnVsbDtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gV2ViR0wyIGZvcm1hdHMuXHJcblxyXG5cdFx0aWYgKCBwID09PSBSZWRGb3JtYXQgKSByZXR1cm4gZ2wuUkVEO1xyXG5cdFx0aWYgKCBwID09PSBSZWRJbnRlZ2VyRm9ybWF0ICkgcmV0dXJuIGdsLlJFRF9JTlRFR0VSO1xyXG5cdFx0aWYgKCBwID09PSBSR0Zvcm1hdCApIHJldHVybiBnbC5SRztcclxuXHRcdGlmICggcCA9PT0gUkdJbnRlZ2VyRm9ybWF0ICkgcmV0dXJuIGdsLlJHX0lOVEVHRVI7XHJcblx0XHRpZiAoIHAgPT09IFJHQkFJbnRlZ2VyRm9ybWF0ICkgcmV0dXJuIGdsLlJHQkFfSU5URUdFUjtcclxuXHJcblx0XHQvLyBTM1RDXHJcblxyXG5cdFx0aWYgKCBwID09PSBSR0JfUzNUQ19EWFQxX0Zvcm1hdCB8fCBwID09PSBSR0JBX1MzVENfRFhUMV9Gb3JtYXQgfHwgcCA9PT0gUkdCQV9TM1RDX0RYVDNfRm9ybWF0IHx8IHAgPT09IFJHQkFfUzNUQ19EWFQ1X0Zvcm1hdCApIHtcclxuXHJcblx0XHRcdGlmICggdHJhbnNmZXIgPT09IFNSR0JUcmFuc2ZlciApIHtcclxuXHJcblx0XHRcdFx0ZXh0ZW5zaW9uID0gZXh0ZW5zaW9ucy5nZXQoICdXRUJHTF9jb21wcmVzc2VkX3RleHR1cmVfczN0Y19zcmdiJyApO1xyXG5cclxuXHRcdFx0XHRpZiAoIGV4dGVuc2lvbiAhPT0gbnVsbCApIHtcclxuXHJcblx0XHRcdFx0XHRpZiAoIHAgPT09IFJHQl9TM1RDX0RYVDFfRm9ybWF0ICkgcmV0dXJuIGV4dGVuc2lvbi5DT01QUkVTU0VEX1NSR0JfUzNUQ19EWFQxX0VYVDtcclxuXHRcdFx0XHRcdGlmICggcCA9PT0gUkdCQV9TM1RDX0RYVDFfRm9ybWF0ICkgcmV0dXJuIGV4dGVuc2lvbi5DT01QUkVTU0VEX1NSR0JfQUxQSEFfUzNUQ19EWFQxX0VYVDtcclxuXHRcdFx0XHRcdGlmICggcCA9PT0gUkdCQV9TM1RDX0RYVDNfRm9ybWF0ICkgcmV0dXJuIGV4dGVuc2lvbi5DT01QUkVTU0VEX1NSR0JfQUxQSEFfUzNUQ19EWFQzX0VYVDtcclxuXHRcdFx0XHRcdGlmICggcCA9PT0gUkdCQV9TM1RDX0RYVDVfRm9ybWF0ICkgcmV0dXJuIGV4dGVuc2lvbi5DT01QUkVTU0VEX1NSR0JfQUxQSEFfUzNUQ19EWFQ1X0VYVDtcclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRyZXR1cm4gbnVsbDtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0ZXh0ZW5zaW9uID0gZXh0ZW5zaW9ucy5nZXQoICdXRUJHTF9jb21wcmVzc2VkX3RleHR1cmVfczN0YycgKTtcclxuXHJcblx0XHRcdFx0aWYgKCBleHRlbnNpb24gIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCBwID09PSBSR0JfUzNUQ19EWFQxX0Zvcm1hdCApIHJldHVybiBleHRlbnNpb24uQ09NUFJFU1NFRF9SR0JfUzNUQ19EWFQxX0VYVDtcclxuXHRcdFx0XHRcdGlmICggcCA9PT0gUkdCQV9TM1RDX0RYVDFfRm9ybWF0ICkgcmV0dXJuIGV4dGVuc2lvbi5DT01QUkVTU0VEX1JHQkFfUzNUQ19EWFQxX0VYVDtcclxuXHRcdFx0XHRcdGlmICggcCA9PT0gUkdCQV9TM1RDX0RYVDNfRm9ybWF0ICkgcmV0dXJuIGV4dGVuc2lvbi5DT01QUkVTU0VEX1JHQkFfUzNUQ19EWFQzX0VYVDtcclxuXHRcdFx0XHRcdGlmICggcCA9PT0gUkdCQV9TM1RDX0RYVDVfRm9ybWF0ICkgcmV0dXJuIGV4dGVuc2lvbi5DT01QUkVTU0VEX1JHQkFfUzNUQ19EWFQ1X0VYVDtcclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRyZXR1cm4gbnVsbDtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvLyBQVlJUQ1xyXG5cclxuXHRcdGlmICggcCA9PT0gUkdCX1BWUlRDXzRCUFBWMV9Gb3JtYXQgfHwgcCA9PT0gUkdCX1BWUlRDXzJCUFBWMV9Gb3JtYXQgfHwgcCA9PT0gUkdCQV9QVlJUQ180QlBQVjFfRm9ybWF0IHx8IHAgPT09IFJHQkFfUFZSVENfMkJQUFYxX0Zvcm1hdCApIHtcclxuXHJcblx0XHRcdGV4dGVuc2lvbiA9IGV4dGVuc2lvbnMuZ2V0KCAnV0VCR0xfY29tcHJlc3NlZF90ZXh0dXJlX3B2cnRjJyApO1xyXG5cclxuXHRcdFx0aWYgKCBleHRlbnNpb24gIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdGlmICggcCA9PT0gUkdCX1BWUlRDXzRCUFBWMV9Gb3JtYXQgKSByZXR1cm4gZXh0ZW5zaW9uLkNPTVBSRVNTRURfUkdCX1BWUlRDXzRCUFBWMV9JTUc7XHJcblx0XHRcdFx0aWYgKCBwID09PSBSR0JfUFZSVENfMkJQUFYxX0Zvcm1hdCApIHJldHVybiBleHRlbnNpb24uQ09NUFJFU1NFRF9SR0JfUFZSVENfMkJQUFYxX0lNRztcclxuXHRcdFx0XHRpZiAoIHAgPT09IFJHQkFfUFZSVENfNEJQUFYxX0Zvcm1hdCApIHJldHVybiBleHRlbnNpb24uQ09NUFJFU1NFRF9SR0JBX1BWUlRDXzRCUFBWMV9JTUc7XHJcblx0XHRcdFx0aWYgKCBwID09PSBSR0JBX1BWUlRDXzJCUFBWMV9Gb3JtYXQgKSByZXR1cm4gZXh0ZW5zaW9uLkNPTVBSRVNTRURfUkdCQV9QVlJUQ18yQlBQVjFfSU1HO1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0cmV0dXJuIG51bGw7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIEVUQzFcclxuXHJcblx0XHRpZiAoIHAgPT09IFJHQl9FVEMxX0Zvcm1hdCApIHtcclxuXHJcblx0XHRcdGV4dGVuc2lvbiA9IGV4dGVuc2lvbnMuZ2V0KCAnV0VCR0xfY29tcHJlc3NlZF90ZXh0dXJlX2V0YzEnICk7XHJcblxyXG5cdFx0XHRpZiAoIGV4dGVuc2lvbiAhPT0gbnVsbCApIHtcclxuXHJcblx0XHRcdFx0cmV0dXJuIGV4dGVuc2lvbi5DT01QUkVTU0VEX1JHQl9FVEMxX1dFQkdMO1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0cmV0dXJuIG51bGw7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIEVUQzJcclxuXHJcblx0XHRpZiAoIHAgPT09IFJHQl9FVEMyX0Zvcm1hdCB8fCBwID09PSBSR0JBX0VUQzJfRUFDX0Zvcm1hdCApIHtcclxuXHJcblx0XHRcdGV4dGVuc2lvbiA9IGV4dGVuc2lvbnMuZ2V0KCAnV0VCR0xfY29tcHJlc3NlZF90ZXh0dXJlX2V0YycgKTtcclxuXHJcblx0XHRcdGlmICggZXh0ZW5zaW9uICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0XHRpZiAoIHAgPT09IFJHQl9FVEMyX0Zvcm1hdCApIHJldHVybiAoIHRyYW5zZmVyID09PSBTUkdCVHJhbnNmZXIgKSA/IGV4dGVuc2lvbi5DT01QUkVTU0VEX1NSR0I4X0VUQzIgOiBleHRlbnNpb24uQ09NUFJFU1NFRF9SR0I4X0VUQzI7XHJcblx0XHRcdFx0aWYgKCBwID09PSBSR0JBX0VUQzJfRUFDX0Zvcm1hdCApIHJldHVybiAoIHRyYW5zZmVyID09PSBTUkdCVHJhbnNmZXIgKSA/IGV4dGVuc2lvbi5DT01QUkVTU0VEX1NSR0I4X0FMUEhBOF9FVEMyX0VBQyA6IGV4dGVuc2lvbi5DT01QUkVTU0VEX1JHQkE4X0VUQzJfRUFDO1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0cmV0dXJuIG51bGw7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIEFTVENcclxuXHJcblx0XHRpZiAoIHAgPT09IFJHQkFfQVNUQ180eDRfRm9ybWF0IHx8IHAgPT09IFJHQkFfQVNUQ181eDRfRm9ybWF0IHx8IHAgPT09IFJHQkFfQVNUQ181eDVfRm9ybWF0IHx8XHJcblx0XHRcdHAgPT09IFJHQkFfQVNUQ182eDVfRm9ybWF0IHx8IHAgPT09IFJHQkFfQVNUQ182eDZfRm9ybWF0IHx8IHAgPT09IFJHQkFfQVNUQ184eDVfRm9ybWF0IHx8XHJcblx0XHRcdHAgPT09IFJHQkFfQVNUQ184eDZfRm9ybWF0IHx8IHAgPT09IFJHQkFfQVNUQ184eDhfRm9ybWF0IHx8IHAgPT09IFJHQkFfQVNUQ18xMHg1X0Zvcm1hdCB8fFxyXG5cdFx0XHRwID09PSBSR0JBX0FTVENfMTB4Nl9Gb3JtYXQgfHwgcCA9PT0gUkdCQV9BU1RDXzEweDhfRm9ybWF0IHx8IHAgPT09IFJHQkFfQVNUQ18xMHgxMF9Gb3JtYXQgfHxcclxuXHRcdFx0cCA9PT0gUkdCQV9BU1RDXzEyeDEwX0Zvcm1hdCB8fCBwID09PSBSR0JBX0FTVENfMTJ4MTJfRm9ybWF0ICkge1xyXG5cclxuXHRcdFx0ZXh0ZW5zaW9uID0gZXh0ZW5zaW9ucy5nZXQoICdXRUJHTF9jb21wcmVzc2VkX3RleHR1cmVfYXN0YycgKTtcclxuXHJcblx0XHRcdGlmICggZXh0ZW5zaW9uICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0XHRpZiAoIHAgPT09IFJHQkFfQVNUQ180eDRfRm9ybWF0ICkgcmV0dXJuICggdHJhbnNmZXIgPT09IFNSR0JUcmFuc2ZlciApID8gZXh0ZW5zaW9uLkNPTVBSRVNTRURfU1JHQjhfQUxQSEE4X0FTVENfNHg0X0tIUiA6IGV4dGVuc2lvbi5DT01QUkVTU0VEX1JHQkFfQVNUQ180eDRfS0hSO1xyXG5cdFx0XHRcdGlmICggcCA9PT0gUkdCQV9BU1RDXzV4NF9Gb3JtYXQgKSByZXR1cm4gKCB0cmFuc2ZlciA9PT0gU1JHQlRyYW5zZmVyICkgPyBleHRlbnNpb24uQ09NUFJFU1NFRF9TUkdCOF9BTFBIQThfQVNUQ181eDRfS0hSIDogZXh0ZW5zaW9uLkNPTVBSRVNTRURfUkdCQV9BU1RDXzV4NF9LSFI7XHJcblx0XHRcdFx0aWYgKCBwID09PSBSR0JBX0FTVENfNXg1X0Zvcm1hdCApIHJldHVybiAoIHRyYW5zZmVyID09PSBTUkdCVHJhbnNmZXIgKSA/IGV4dGVuc2lvbi5DT01QUkVTU0VEX1NSR0I4X0FMUEhBOF9BU1RDXzV4NV9LSFIgOiBleHRlbnNpb24uQ09NUFJFU1NFRF9SR0JBX0FTVENfNXg1X0tIUjtcclxuXHRcdFx0XHRpZiAoIHAgPT09IFJHQkFfQVNUQ182eDVfRm9ybWF0ICkgcmV0dXJuICggdHJhbnNmZXIgPT09IFNSR0JUcmFuc2ZlciApID8gZXh0ZW5zaW9uLkNPTVBSRVNTRURfU1JHQjhfQUxQSEE4X0FTVENfNng1X0tIUiA6IGV4dGVuc2lvbi5DT01QUkVTU0VEX1JHQkFfQVNUQ182eDVfS0hSO1xyXG5cdFx0XHRcdGlmICggcCA9PT0gUkdCQV9BU1RDXzZ4Nl9Gb3JtYXQgKSByZXR1cm4gKCB0cmFuc2ZlciA9PT0gU1JHQlRyYW5zZmVyICkgPyBleHRlbnNpb24uQ09NUFJFU1NFRF9TUkdCOF9BTFBIQThfQVNUQ182eDZfS0hSIDogZXh0ZW5zaW9uLkNPTVBSRVNTRURfUkdCQV9BU1RDXzZ4Nl9LSFI7XHJcblx0XHRcdFx0aWYgKCBwID09PSBSR0JBX0FTVENfOHg1X0Zvcm1hdCApIHJldHVybiAoIHRyYW5zZmVyID09PSBTUkdCVHJhbnNmZXIgKSA/IGV4dGVuc2lvbi5DT01QUkVTU0VEX1NSR0I4X0FMUEhBOF9BU1RDXzh4NV9LSFIgOiBleHRlbnNpb24uQ09NUFJFU1NFRF9SR0JBX0FTVENfOHg1X0tIUjtcclxuXHRcdFx0XHRpZiAoIHAgPT09IFJHQkFfQVNUQ184eDZfRm9ybWF0ICkgcmV0dXJuICggdHJhbnNmZXIgPT09IFNSR0JUcmFuc2ZlciApID8gZXh0ZW5zaW9uLkNPTVBSRVNTRURfU1JHQjhfQUxQSEE4X0FTVENfOHg2X0tIUiA6IGV4dGVuc2lvbi5DT01QUkVTU0VEX1JHQkFfQVNUQ184eDZfS0hSO1xyXG5cdFx0XHRcdGlmICggcCA9PT0gUkdCQV9BU1RDXzh4OF9Gb3JtYXQgKSByZXR1cm4gKCB0cmFuc2ZlciA9PT0gU1JHQlRyYW5zZmVyICkgPyBleHRlbnNpb24uQ09NUFJFU1NFRF9TUkdCOF9BTFBIQThfQVNUQ184eDhfS0hSIDogZXh0ZW5zaW9uLkNPTVBSRVNTRURfUkdCQV9BU1RDXzh4OF9LSFI7XHJcblx0XHRcdFx0aWYgKCBwID09PSBSR0JBX0FTVENfMTB4NV9Gb3JtYXQgKSByZXR1cm4gKCB0cmFuc2ZlciA9PT0gU1JHQlRyYW5zZmVyICkgPyBleHRlbnNpb24uQ09NUFJFU1NFRF9TUkdCOF9BTFBIQThfQVNUQ18xMHg1X0tIUiA6IGV4dGVuc2lvbi5DT01QUkVTU0VEX1JHQkFfQVNUQ18xMHg1X0tIUjtcclxuXHRcdFx0XHRpZiAoIHAgPT09IFJHQkFfQVNUQ18xMHg2X0Zvcm1hdCApIHJldHVybiAoIHRyYW5zZmVyID09PSBTUkdCVHJhbnNmZXIgKSA/IGV4dGVuc2lvbi5DT01QUkVTU0VEX1NSR0I4X0FMUEhBOF9BU1RDXzEweDZfS0hSIDogZXh0ZW5zaW9uLkNPTVBSRVNTRURfUkdCQV9BU1RDXzEweDZfS0hSO1xyXG5cdFx0XHRcdGlmICggcCA9PT0gUkdCQV9BU1RDXzEweDhfRm9ybWF0ICkgcmV0dXJuICggdHJhbnNmZXIgPT09IFNSR0JUcmFuc2ZlciApID8gZXh0ZW5zaW9uLkNPTVBSRVNTRURfU1JHQjhfQUxQSEE4X0FTVENfMTB4OF9LSFIgOiBleHRlbnNpb24uQ09NUFJFU1NFRF9SR0JBX0FTVENfMTB4OF9LSFI7XHJcblx0XHRcdFx0aWYgKCBwID09PSBSR0JBX0FTVENfMTB4MTBfRm9ybWF0ICkgcmV0dXJuICggdHJhbnNmZXIgPT09IFNSR0JUcmFuc2ZlciApID8gZXh0ZW5zaW9uLkNPTVBSRVNTRURfU1JHQjhfQUxQSEE4X0FTVENfMTB4MTBfS0hSIDogZXh0ZW5zaW9uLkNPTVBSRVNTRURfUkdCQV9BU1RDXzEweDEwX0tIUjtcclxuXHRcdFx0XHRpZiAoIHAgPT09IFJHQkFfQVNUQ18xMngxMF9Gb3JtYXQgKSByZXR1cm4gKCB0cmFuc2ZlciA9PT0gU1JHQlRyYW5zZmVyICkgPyBleHRlbnNpb24uQ09NUFJFU1NFRF9TUkdCOF9BTFBIQThfQVNUQ18xMngxMF9LSFIgOiBleHRlbnNpb24uQ09NUFJFU1NFRF9SR0JBX0FTVENfMTJ4MTBfS0hSO1xyXG5cdFx0XHRcdGlmICggcCA9PT0gUkdCQV9BU1RDXzEyeDEyX0Zvcm1hdCApIHJldHVybiAoIHRyYW5zZmVyID09PSBTUkdCVHJhbnNmZXIgKSA/IGV4dGVuc2lvbi5DT01QUkVTU0VEX1NSR0I4X0FMUEhBOF9BU1RDXzEyeDEyX0tIUiA6IGV4dGVuc2lvbi5DT01QUkVTU0VEX1JHQkFfQVNUQ18xMngxMl9LSFI7XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRyZXR1cm4gbnVsbDtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gQlBUQ1xyXG5cclxuXHRcdGlmICggcCA9PT0gUkdCQV9CUFRDX0Zvcm1hdCB8fCBwID09PSBSR0JfQlBUQ19TSUdORURfRm9ybWF0IHx8IHAgPT09IFJHQl9CUFRDX1VOU0lHTkVEX0Zvcm1hdCApIHtcclxuXHJcblx0XHRcdGV4dGVuc2lvbiA9IGV4dGVuc2lvbnMuZ2V0KCAnRVhUX3RleHR1cmVfY29tcHJlc3Npb25fYnB0YycgKTtcclxuXHJcblx0XHRcdGlmICggZXh0ZW5zaW9uICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0XHRpZiAoIHAgPT09IFJHQkFfQlBUQ19Gb3JtYXQgKSByZXR1cm4gKCB0cmFuc2ZlciA9PT0gU1JHQlRyYW5zZmVyICkgPyBleHRlbnNpb24uQ09NUFJFU1NFRF9TUkdCX0FMUEhBX0JQVENfVU5PUk1fRVhUIDogZXh0ZW5zaW9uLkNPTVBSRVNTRURfUkdCQV9CUFRDX1VOT1JNX0VYVDtcclxuXHRcdFx0XHRpZiAoIHAgPT09IFJHQl9CUFRDX1NJR05FRF9Gb3JtYXQgKSByZXR1cm4gZXh0ZW5zaW9uLkNPTVBSRVNTRURfUkdCX0JQVENfU0lHTkVEX0ZMT0FUX0VYVDtcclxuXHRcdFx0XHRpZiAoIHAgPT09IFJHQl9CUFRDX1VOU0lHTkVEX0Zvcm1hdCApIHJldHVybiBleHRlbnNpb24uQ09NUFJFU1NFRF9SR0JfQlBUQ19VTlNJR05FRF9GTE9BVF9FWFQ7XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRyZXR1cm4gbnVsbDtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gUkdUQ1xyXG5cclxuXHRcdGlmICggcCA9PT0gUkVEX1JHVEMxX0Zvcm1hdCB8fCBwID09PSBTSUdORURfUkVEX1JHVEMxX0Zvcm1hdCB8fCBwID09PSBSRURfR1JFRU5fUkdUQzJfRm9ybWF0IHx8IHAgPT09IFNJR05FRF9SRURfR1JFRU5fUkdUQzJfRm9ybWF0ICkge1xyXG5cclxuXHRcdFx0ZXh0ZW5zaW9uID0gZXh0ZW5zaW9ucy5nZXQoICdFWFRfdGV4dHVyZV9jb21wcmVzc2lvbl9yZ3RjJyApO1xyXG5cclxuXHRcdFx0aWYgKCBleHRlbnNpb24gIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdGlmICggcCA9PT0gUkdCQV9CUFRDX0Zvcm1hdCApIHJldHVybiBleHRlbnNpb24uQ09NUFJFU1NFRF9SRURfUkdUQzFfRVhUO1xyXG5cdFx0XHRcdGlmICggcCA9PT0gU0lHTkVEX1JFRF9SR1RDMV9Gb3JtYXQgKSByZXR1cm4gZXh0ZW5zaW9uLkNPTVBSRVNTRURfU0lHTkVEX1JFRF9SR1RDMV9FWFQ7XHJcblx0XHRcdFx0aWYgKCBwID09PSBSRURfR1JFRU5fUkdUQzJfRm9ybWF0ICkgcmV0dXJuIGV4dGVuc2lvbi5DT01QUkVTU0VEX1JFRF9HUkVFTl9SR1RDMl9FWFQ7XHJcblx0XHRcdFx0aWYgKCBwID09PSBTSUdORURfUkVEX0dSRUVOX1JHVEMyX0Zvcm1hdCApIHJldHVybiBleHRlbnNpb24uQ09NUFJFU1NFRF9TSUdORURfUkVEX0dSRUVOX1JHVEMyX0VYVDtcclxuXHJcblx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdHJldHVybiBudWxsO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvL1xyXG5cclxuXHRcdGlmICggcCA9PT0gVW5zaWduZWRJbnQyNDhUeXBlICkge1xyXG5cclxuXHRcdFx0aWYgKCBpc1dlYkdMMiApIHJldHVybiBnbC5VTlNJR05FRF9JTlRfMjRfODtcclxuXHJcblx0XHRcdGV4dGVuc2lvbiA9IGV4dGVuc2lvbnMuZ2V0KCAnV0VCR0xfZGVwdGhfdGV4dHVyZScgKTtcclxuXHJcblx0XHRcdGlmICggZXh0ZW5zaW9uICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0XHRyZXR1cm4gZXh0ZW5zaW9uLlVOU0lHTkVEX0lOVF8yNF84X1dFQkdMO1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0cmV0dXJuIG51bGw7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIGlmIFwicFwiIGNhbid0IGJlIHJlc29sdmVkLCBhc3N1bWUgdGhlIHVzZXIgZGVmaW5lcyBhIFdlYkdMIGNvbnN0YW50IGFzIGEgc3RyaW5nIChmYWxsYmFjay93b3JrYXJvdW5kIGZvciBwYWNrZWQgUkdCIGZvcm1hdHMpXHJcblxyXG5cdFx0cmV0dXJuICggZ2xbIHAgXSAhPT0gdW5kZWZpbmVkICkgPyBnbFsgcCBdIDogbnVsbDtcclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4geyBjb252ZXJ0OiBjb252ZXJ0IH07XHJcblxyXG59XHJcblxyXG5cclxuZXhwb3J0IHsgV2ViR0xVdGlscyB9O1xyXG4iLCJpbXBvcnQgeyBQZXJzcGVjdGl2ZUNhbWVyYSB9IGZyb20gJy4vUGVyc3BlY3RpdmVDYW1lcmEuanMnO1xyXG5cclxuY2xhc3MgQXJyYXlDYW1lcmEgZXh0ZW5kcyBQZXJzcGVjdGl2ZUNhbWVyYSB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBhcnJheSA9IFtdICkge1xyXG5cclxuXHRcdHN1cGVyKCk7XHJcblxyXG5cdFx0dGhpcy5pc0FycmF5Q2FtZXJhID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLmNhbWVyYXMgPSBhcnJheTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgQXJyYXlDYW1lcmEgfTtcclxuIiwiaW1wb3J0IHsgT2JqZWN0M0QgfSBmcm9tICcuLi9jb3JlL09iamVjdDNELmpzJztcclxuXHJcbmNsYXNzIEdyb3VwIGV4dGVuZHMgT2JqZWN0M0Qge1xyXG5cclxuXHRjb25zdHJ1Y3RvcigpIHtcclxuXHJcblx0XHRzdXBlcigpO1xyXG5cclxuXHRcdHRoaXMuaXNHcm91cCA9IHRydWU7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ0dyb3VwJztcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgR3JvdXAgfTtcclxuIiwiaW1wb3J0IHsgVmVjdG9yMyB9IGZyb20gJy4uLy4uL21hdGgvVmVjdG9yMy5qcyc7XHJcbmltcG9ydCB7IEdyb3VwIH0gZnJvbSAnLi4vLi4vb2JqZWN0cy9Hcm91cC5qcyc7XHJcblxyXG5jb25zdCBfbW92ZUV2ZW50ID0geyB0eXBlOiAnbW92ZScgfTtcclxuXHJcbmNsYXNzIFdlYlhSQ29udHJvbGxlciB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCkge1xyXG5cclxuXHRcdHRoaXMuX3RhcmdldFJheSA9IG51bGw7XHJcblx0XHR0aGlzLl9ncmlwID0gbnVsbDtcclxuXHRcdHRoaXMuX2hhbmQgPSBudWxsO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldEhhbmRTcGFjZSgpIHtcclxuXHJcblx0XHRpZiAoIHRoaXMuX2hhbmQgPT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHR0aGlzLl9oYW5kID0gbmV3IEdyb3VwKCk7XHJcblx0XHRcdHRoaXMuX2hhbmQubWF0cml4QXV0b1VwZGF0ZSA9IGZhbHNlO1xyXG5cdFx0XHR0aGlzLl9oYW5kLnZpc2libGUgPSBmYWxzZTtcclxuXHJcblx0XHRcdHRoaXMuX2hhbmQuam9pbnRzID0ge307XHJcblx0XHRcdHRoaXMuX2hhbmQuaW5wdXRTdGF0ZSA9IHsgcGluY2hpbmc6IGZhbHNlIH07XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzLl9oYW5kO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldFRhcmdldFJheVNwYWNlKCkge1xyXG5cclxuXHRcdGlmICggdGhpcy5fdGFyZ2V0UmF5ID09PSBudWxsICkge1xyXG5cclxuXHRcdFx0dGhpcy5fdGFyZ2V0UmF5ID0gbmV3IEdyb3VwKCk7XHJcblx0XHRcdHRoaXMuX3RhcmdldFJheS5tYXRyaXhBdXRvVXBkYXRlID0gZmFsc2U7XHJcblx0XHRcdHRoaXMuX3RhcmdldFJheS52aXNpYmxlID0gZmFsc2U7XHJcblx0XHRcdHRoaXMuX3RhcmdldFJheS5oYXNMaW5lYXJWZWxvY2l0eSA9IGZhbHNlO1xyXG5cdFx0XHR0aGlzLl90YXJnZXRSYXkubGluZWFyVmVsb2NpdHkgPSBuZXcgVmVjdG9yMygpO1xyXG5cdFx0XHR0aGlzLl90YXJnZXRSYXkuaGFzQW5ndWxhclZlbG9jaXR5ID0gZmFsc2U7XHJcblx0XHRcdHRoaXMuX3RhcmdldFJheS5hbmd1bGFyVmVsb2NpdHkgPSBuZXcgVmVjdG9yMygpO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcy5fdGFyZ2V0UmF5O1xyXG5cclxuXHR9XHJcblxyXG5cdGdldEdyaXBTcGFjZSgpIHtcclxuXHJcblx0XHRpZiAoIHRoaXMuX2dyaXAgPT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHR0aGlzLl9ncmlwID0gbmV3IEdyb3VwKCk7XHJcblx0XHRcdHRoaXMuX2dyaXAubWF0cml4QXV0b1VwZGF0ZSA9IGZhbHNlO1xyXG5cdFx0XHR0aGlzLl9ncmlwLnZpc2libGUgPSBmYWxzZTtcclxuXHRcdFx0dGhpcy5fZ3JpcC5oYXNMaW5lYXJWZWxvY2l0eSA9IGZhbHNlO1xyXG5cdFx0XHR0aGlzLl9ncmlwLmxpbmVhclZlbG9jaXR5ID0gbmV3IFZlY3RvcjMoKTtcclxuXHRcdFx0dGhpcy5fZ3JpcC5oYXNBbmd1bGFyVmVsb2NpdHkgPSBmYWxzZTtcclxuXHRcdFx0dGhpcy5fZ3JpcC5hbmd1bGFyVmVsb2NpdHkgPSBuZXcgVmVjdG9yMygpO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcy5fZ3JpcDtcclxuXHJcblx0fVxyXG5cclxuXHRkaXNwYXRjaEV2ZW50KCBldmVudCApIHtcclxuXHJcblx0XHRpZiAoIHRoaXMuX3RhcmdldFJheSAhPT0gbnVsbCApIHtcclxuXHJcblx0XHRcdHRoaXMuX3RhcmdldFJheS5kaXNwYXRjaEV2ZW50KCBldmVudCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHRoaXMuX2dyaXAgIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHR0aGlzLl9ncmlwLmRpc3BhdGNoRXZlbnQoIGV2ZW50ICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggdGhpcy5faGFuZCAhPT0gbnVsbCApIHtcclxuXHJcblx0XHRcdHRoaXMuX2hhbmQuZGlzcGF0Y2hFdmVudCggZXZlbnQgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Y29ubmVjdCggaW5wdXRTb3VyY2UgKSB7XHJcblxyXG5cdFx0aWYgKCBpbnB1dFNvdXJjZSAmJiBpbnB1dFNvdXJjZS5oYW5kICkge1xyXG5cclxuXHRcdFx0Y29uc3QgaGFuZCA9IHRoaXMuX2hhbmQ7XHJcblxyXG5cdFx0XHRpZiAoIGhhbmQgKSB7XHJcblxyXG5cdFx0XHRcdGZvciAoIGNvbnN0IGlucHV0am9pbnQgb2YgaW5wdXRTb3VyY2UuaGFuZC52YWx1ZXMoKSApIHtcclxuXHJcblx0XHRcdFx0XHQvLyBJbml0aWFsaXplIGhhbmQgd2l0aCBqb2ludHMgd2hlbiBjb25uZWN0ZWRcclxuXHRcdFx0XHRcdHRoaXMuX2dldEhhbmRKb2ludCggaGFuZCwgaW5wdXRqb2ludCApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMuZGlzcGF0Y2hFdmVudCggeyB0eXBlOiAnY29ubmVjdGVkJywgZGF0YTogaW5wdXRTb3VyY2UgfSApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGRpc2Nvbm5lY3QoIGlucHV0U291cmNlICkge1xyXG5cclxuXHRcdHRoaXMuZGlzcGF0Y2hFdmVudCggeyB0eXBlOiAnZGlzY29ubmVjdGVkJywgZGF0YTogaW5wdXRTb3VyY2UgfSApO1xyXG5cclxuXHRcdGlmICggdGhpcy5fdGFyZ2V0UmF5ICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0dGhpcy5fdGFyZ2V0UmF5LnZpc2libGUgPSBmYWxzZTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCB0aGlzLl9ncmlwICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0dGhpcy5fZ3JpcC52aXNpYmxlID0gZmFsc2U7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggdGhpcy5faGFuZCAhPT0gbnVsbCApIHtcclxuXHJcblx0XHRcdHRoaXMuX2hhbmQudmlzaWJsZSA9IGZhbHNlO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHR1cGRhdGUoIGlucHV0U291cmNlLCBmcmFtZSwgcmVmZXJlbmNlU3BhY2UgKSB7XHJcblxyXG5cdFx0bGV0IGlucHV0UG9zZSA9IG51bGw7XHJcblx0XHRsZXQgZ3JpcFBvc2UgPSBudWxsO1xyXG5cdFx0bGV0IGhhbmRQb3NlID0gbnVsbDtcclxuXHJcblx0XHRjb25zdCB0YXJnZXRSYXkgPSB0aGlzLl90YXJnZXRSYXk7XHJcblx0XHRjb25zdCBncmlwID0gdGhpcy5fZ3JpcDtcclxuXHRcdGNvbnN0IGhhbmQgPSB0aGlzLl9oYW5kO1xyXG5cclxuXHRcdGlmICggaW5wdXRTb3VyY2UgJiYgZnJhbWUuc2Vzc2lvbi52aXNpYmlsaXR5U3RhdGUgIT09ICd2aXNpYmxlLWJsdXJyZWQnICkge1xyXG5cclxuXHRcdFx0aWYgKCBoYW5kICYmIGlucHV0U291cmNlLmhhbmQgKSB7XHJcblxyXG5cdFx0XHRcdGhhbmRQb3NlID0gdHJ1ZTtcclxuXHJcblx0XHRcdFx0Zm9yICggY29uc3QgaW5wdXRqb2ludCBvZiBpbnB1dFNvdXJjZS5oYW5kLnZhbHVlcygpICkge1xyXG5cclxuXHRcdFx0XHRcdC8vIFVwZGF0ZSB0aGUgam9pbnRzIGdyb3VwcyB3aXRoIHRoZSBYUkpvaW50IHBvc2VzXHJcblx0XHRcdFx0XHRjb25zdCBqb2ludFBvc2UgPSBmcmFtZS5nZXRKb2ludFBvc2UoIGlucHV0am9pbnQsIHJlZmVyZW5jZVNwYWNlICk7XHJcblxyXG5cdFx0XHRcdFx0Ly8gVGhlIHRyYW5zZm9ybSBvZiB0aGlzIGpvaW50IHdpbGwgYmUgdXBkYXRlZCB3aXRoIHRoZSBqb2ludCBwb3NlIG9uIGVhY2ggZnJhbWVcclxuXHRcdFx0XHRcdGNvbnN0IGpvaW50ID0gdGhpcy5fZ2V0SGFuZEpvaW50KCBoYW5kLCBpbnB1dGpvaW50ICk7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCBqb2ludFBvc2UgIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRqb2ludC5tYXRyaXguZnJvbUFycmF5KCBqb2ludFBvc2UudHJhbnNmb3JtLm1hdHJpeCApO1xyXG5cdFx0XHRcdFx0XHRqb2ludC5tYXRyaXguZGVjb21wb3NlKCBqb2ludC5wb3NpdGlvbiwgam9pbnQucm90YXRpb24sIGpvaW50LnNjYWxlICk7XHJcblx0XHRcdFx0XHRcdGpvaW50Lm1hdHJpeFdvcmxkTmVlZHNVcGRhdGUgPSB0cnVlO1xyXG5cdFx0XHRcdFx0XHRqb2ludC5qb2ludFJhZGl1cyA9IGpvaW50UG9zZS5yYWRpdXM7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdGpvaW50LnZpc2libGUgPSBqb2ludFBvc2UgIT09IG51bGw7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0Ly8gQ3VzdG9tIGV2ZW50c1xyXG5cclxuXHRcdFx0XHQvLyBDaGVjayBwaW5jaHpcclxuXHRcdFx0XHRjb25zdCBpbmRleFRpcCA9IGhhbmQuam9pbnRzWyAnaW5kZXgtZmluZ2VyLXRpcCcgXTtcclxuXHRcdFx0XHRjb25zdCB0aHVtYlRpcCA9IGhhbmQuam9pbnRzWyAndGh1bWItdGlwJyBdO1xyXG5cdFx0XHRcdGNvbnN0IGRpc3RhbmNlID0gaW5kZXhUaXAucG9zaXRpb24uZGlzdGFuY2VUbyggdGh1bWJUaXAucG9zaXRpb24gKTtcclxuXHJcblx0XHRcdFx0Y29uc3QgZGlzdGFuY2VUb1BpbmNoID0gMC4wMjtcclxuXHRcdFx0XHRjb25zdCB0aHJlc2hvbGQgPSAwLjAwNTtcclxuXHJcblx0XHRcdFx0aWYgKCBoYW5kLmlucHV0U3RhdGUucGluY2hpbmcgJiYgZGlzdGFuY2UgPiBkaXN0YW5jZVRvUGluY2ggKyB0aHJlc2hvbGQgKSB7XHJcblxyXG5cdFx0XHRcdFx0aGFuZC5pbnB1dFN0YXRlLnBpbmNoaW5nID0gZmFsc2U7XHJcblx0XHRcdFx0XHR0aGlzLmRpc3BhdGNoRXZlbnQoIHtcclxuXHRcdFx0XHRcdFx0dHlwZTogJ3BpbmNoZW5kJyxcclxuXHRcdFx0XHRcdFx0aGFuZGVkbmVzczogaW5wdXRTb3VyY2UuaGFuZGVkbmVzcyxcclxuXHRcdFx0XHRcdFx0dGFyZ2V0OiB0aGlzXHJcblx0XHRcdFx0XHR9ICk7XHJcblxyXG5cdFx0XHRcdH0gZWxzZSBpZiAoICEgaGFuZC5pbnB1dFN0YXRlLnBpbmNoaW5nICYmIGRpc3RhbmNlIDw9IGRpc3RhbmNlVG9QaW5jaCAtIHRocmVzaG9sZCApIHtcclxuXHJcblx0XHRcdFx0XHRoYW5kLmlucHV0U3RhdGUucGluY2hpbmcgPSB0cnVlO1xyXG5cdFx0XHRcdFx0dGhpcy5kaXNwYXRjaEV2ZW50KCB7XHJcblx0XHRcdFx0XHRcdHR5cGU6ICdwaW5jaHN0YXJ0JyxcclxuXHRcdFx0XHRcdFx0aGFuZGVkbmVzczogaW5wdXRTb3VyY2UuaGFuZGVkbmVzcyxcclxuXHRcdFx0XHRcdFx0dGFyZ2V0OiB0aGlzXHJcblx0XHRcdFx0XHR9ICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdGlmICggZ3JpcCAhPT0gbnVsbCAmJiBpbnB1dFNvdXJjZS5ncmlwU3BhY2UgKSB7XHJcblxyXG5cdFx0XHRcdFx0Z3JpcFBvc2UgPSBmcmFtZS5nZXRQb3NlKCBpbnB1dFNvdXJjZS5ncmlwU3BhY2UsIHJlZmVyZW5jZVNwYWNlICk7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCBncmlwUG9zZSAhPT0gbnVsbCApIHtcclxuXHJcblx0XHRcdFx0XHRcdGdyaXAubWF0cml4LmZyb21BcnJheSggZ3JpcFBvc2UudHJhbnNmb3JtLm1hdHJpeCApO1xyXG5cdFx0XHRcdFx0XHRncmlwLm1hdHJpeC5kZWNvbXBvc2UoIGdyaXAucG9zaXRpb24sIGdyaXAucm90YXRpb24sIGdyaXAuc2NhbGUgKTtcclxuXHRcdFx0XHRcdFx0Z3JpcC5tYXRyaXhXb3JsZE5lZWRzVXBkYXRlID0gdHJ1ZTtcclxuXHJcblx0XHRcdFx0XHRcdGlmICggZ3JpcFBvc2UubGluZWFyVmVsb2NpdHkgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdGdyaXAuaGFzTGluZWFyVmVsb2NpdHkgPSB0cnVlO1xyXG5cdFx0XHRcdFx0XHRcdGdyaXAubGluZWFyVmVsb2NpdHkuY29weSggZ3JpcFBvc2UubGluZWFyVmVsb2NpdHkgKTtcclxuXHJcblx0XHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdGdyaXAuaGFzTGluZWFyVmVsb2NpdHkgPSBmYWxzZTtcclxuXHJcblx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRcdGlmICggZ3JpcFBvc2UuYW5ndWxhclZlbG9jaXR5ICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRncmlwLmhhc0FuZ3VsYXJWZWxvY2l0eSA9IHRydWU7XHJcblx0XHRcdFx0XHRcdFx0Z3JpcC5hbmd1bGFyVmVsb2NpdHkuY29weSggZ3JpcFBvc2UuYW5ndWxhclZlbG9jaXR5ICk7XHJcblxyXG5cdFx0XHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRncmlwLmhhc0FuZ3VsYXJWZWxvY2l0eSA9IGZhbHNlO1xyXG5cclxuXHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0aWYgKCB0YXJnZXRSYXkgIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdGlucHV0UG9zZSA9IGZyYW1lLmdldFBvc2UoIGlucHV0U291cmNlLnRhcmdldFJheVNwYWNlLCByZWZlcmVuY2VTcGFjZSApO1xyXG5cclxuXHRcdFx0XHQvLyBTb21lIHJ1bnRpbWVzIChuYW1lbHkgVml2ZSBDb3Ntb3Mgd2l0aCBWaXZlIE9wZW5YUiBSdW50aW1lKSBoYXZlIG9ubHkgZ3JpcCBzcGFjZSBhbmQgcmF5IHNwYWNlIGlzIGVxdWFsIHRvIGl0XHJcblx0XHRcdFx0aWYgKCBpbnB1dFBvc2UgPT09IG51bGwgJiYgZ3JpcFBvc2UgIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdFx0aW5wdXRQb3NlID0gZ3JpcFBvc2U7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0aWYgKCBpbnB1dFBvc2UgIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdFx0dGFyZ2V0UmF5Lm1hdHJpeC5mcm9tQXJyYXkoIGlucHV0UG9zZS50cmFuc2Zvcm0ubWF0cml4ICk7XHJcblx0XHRcdFx0XHR0YXJnZXRSYXkubWF0cml4LmRlY29tcG9zZSggdGFyZ2V0UmF5LnBvc2l0aW9uLCB0YXJnZXRSYXkucm90YXRpb24sIHRhcmdldFJheS5zY2FsZSApO1xyXG5cdFx0XHRcdFx0dGFyZ2V0UmF5Lm1hdHJpeFdvcmxkTmVlZHNVcGRhdGUgPSB0cnVlO1xyXG5cclxuXHRcdFx0XHRcdGlmICggaW5wdXRQb3NlLmxpbmVhclZlbG9jaXR5ICkge1xyXG5cclxuXHRcdFx0XHRcdFx0dGFyZ2V0UmF5Lmhhc0xpbmVhclZlbG9jaXR5ID0gdHJ1ZTtcclxuXHRcdFx0XHRcdFx0dGFyZ2V0UmF5LmxpbmVhclZlbG9jaXR5LmNvcHkoIGlucHV0UG9zZS5saW5lYXJWZWxvY2l0eSApO1xyXG5cclxuXHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHR0YXJnZXRSYXkuaGFzTGluZWFyVmVsb2NpdHkgPSBmYWxzZTtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0aWYgKCBpbnB1dFBvc2UuYW5ndWxhclZlbG9jaXR5ICkge1xyXG5cclxuXHRcdFx0XHRcdFx0dGFyZ2V0UmF5Lmhhc0FuZ3VsYXJWZWxvY2l0eSA9IHRydWU7XHJcblx0XHRcdFx0XHRcdHRhcmdldFJheS5hbmd1bGFyVmVsb2NpdHkuY29weSggaW5wdXRQb3NlLmFuZ3VsYXJWZWxvY2l0eSApO1xyXG5cclxuXHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHR0YXJnZXRSYXkuaGFzQW5ndWxhclZlbG9jaXR5ID0gZmFsc2U7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdHRoaXMuZGlzcGF0Y2hFdmVudCggX21vdmVFdmVudCApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHRhcmdldFJheSAhPT0gbnVsbCApIHtcclxuXHJcblx0XHRcdHRhcmdldFJheS52aXNpYmxlID0gKCBpbnB1dFBvc2UgIT09IG51bGwgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBncmlwICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0Z3JpcC52aXNpYmxlID0gKCBncmlwUG9zZSAhPT0gbnVsbCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIGhhbmQgIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRoYW5kLnZpc2libGUgPSAoIGhhbmRQb3NlICE9PSBudWxsICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdC8vIHByaXZhdGUgbWV0aG9kXHJcblxyXG5cdF9nZXRIYW5kSm9pbnQoIGhhbmQsIGlucHV0am9pbnQgKSB7XHJcblxyXG5cdFx0aWYgKCBoYW5kLmpvaW50c1sgaW5wdXRqb2ludC5qb2ludE5hbWUgXSA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0Y29uc3Qgam9pbnQgPSBuZXcgR3JvdXAoKTtcclxuXHRcdFx0am9pbnQubWF0cml4QXV0b1VwZGF0ZSA9IGZhbHNlO1xyXG5cdFx0XHRqb2ludC52aXNpYmxlID0gZmFsc2U7XHJcblx0XHRcdGhhbmQuam9pbnRzWyBpbnB1dGpvaW50LmpvaW50TmFtZSBdID0gam9pbnQ7XHJcblxyXG5cdFx0XHRoYW5kLmFkZCggam9pbnQgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIGhhbmQuam9pbnRzWyBpbnB1dGpvaW50LmpvaW50TmFtZSBdO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5cclxuZXhwb3J0IHsgV2ViWFJDb250cm9sbGVyIH07XHJcbiIsImltcG9ydCB7IFBsYW5lR2VvbWV0cnkgfSBmcm9tICcuLi8uLi9nZW9tZXRyaWVzL1BsYW5lR2VvbWV0cnkuanMnO1xyXG5pbXBvcnQgeyBTaGFkZXJNYXRlcmlhbCB9IGZyb20gJy4uLy4uL21hdGVyaWFscy9TaGFkZXJNYXRlcmlhbC5qcyc7XHJcbmltcG9ydCB7IE1lc2ggfSBmcm9tICcuLi8uLi9vYmplY3RzL01lc2guanMnO1xyXG5pbXBvcnQgeyBUZXh0dXJlIH0gZnJvbSAnLi4vLi4vdGV4dHVyZXMvVGV4dHVyZS5qcyc7XHJcblxyXG5jb25zdCBfb2NjbHVzaW9uX3ZlcnRleCA9IGBcclxudm9pZCBtYWluKCkge1xyXG5cclxuXHRnbF9Qb3NpdGlvbiA9IHZlYzQoIHBvc2l0aW9uLCAxLjAgKTtcclxuXHJcbn1gO1xyXG5cclxuY29uc3QgX29jY2x1c2lvbl9mcmFnbWVudCA9IGBcclxudW5pZm9ybSBzYW1wbGVyMkRBcnJheSBkZXB0aENvbG9yO1xyXG51bmlmb3JtIGZsb2F0IGRlcHRoV2lkdGg7XHJcbnVuaWZvcm0gZmxvYXQgZGVwdGhIZWlnaHQ7XHJcblxyXG52b2lkIG1haW4oKSB7XHJcblxyXG5cdHZlYzIgY29vcmQgPSB2ZWMyKCBnbF9GcmFnQ29vcmQueCAvIGRlcHRoV2lkdGgsIGdsX0ZyYWdDb29yZC55IC8gZGVwdGhIZWlnaHQgKTtcclxuXHJcblx0aWYgKCBjb29yZC54ID49IDEuMCApIHtcclxuXHJcblx0XHRnbF9GcmFnRGVwdGhFWFQgPSB0ZXh0dXJlKCBkZXB0aENvbG9yLCB2ZWMzKCBjb29yZC54IC0gMS4wLCBjb29yZC55LCAxICkgKS5yO1xyXG5cclxuXHR9IGVsc2Uge1xyXG5cclxuXHRcdGdsX0ZyYWdEZXB0aEVYVCA9IHRleHR1cmUoIGRlcHRoQ29sb3IsIHZlYzMoIGNvb3JkLngsIGNvb3JkLnksIDAgKSApLnI7XHJcblxyXG5cdH1cclxuXHJcbn1gO1xyXG5cclxuY2xhc3MgV2ViWFJEZXB0aFNlbnNpbmcge1xyXG5cclxuXHRjb25zdHJ1Y3RvcigpIHtcclxuXHJcblx0XHR0aGlzLnRleHR1cmUgPSBudWxsO1xyXG5cdFx0dGhpcy5tZXNoID0gbnVsbDtcclxuXHJcblx0XHR0aGlzLmRlcHRoTmVhciA9IDA7XHJcblx0XHR0aGlzLmRlcHRoRmFyID0gMDtcclxuXHJcblx0fVxyXG5cclxuXHRpbml0KCByZW5kZXJlciwgZGVwdGhEYXRhLCByZW5kZXJTdGF0ZSApIHtcclxuXHJcblx0XHRpZiAoIHRoaXMudGV4dHVyZSA9PT0gbnVsbCApIHtcclxuXHJcblx0XHRcdGNvbnN0IHRleHR1cmUgPSBuZXcgVGV4dHVyZSgpO1xyXG5cclxuXHRcdFx0Y29uc3QgdGV4UHJvcHMgPSByZW5kZXJlci5wcm9wZXJ0aWVzLmdldCggdGV4dHVyZSApO1xyXG5cdFx0XHR0ZXhQcm9wcy5fX3dlYmdsVGV4dHVyZSA9IGRlcHRoRGF0YS50ZXh0dXJlO1xyXG5cclxuXHRcdFx0aWYgKCAoIGRlcHRoRGF0YS5kZXB0aE5lYXIgIT0gcmVuZGVyU3RhdGUuZGVwdGhOZWFyICkgfHwgKCBkZXB0aERhdGEuZGVwdGhGYXIgIT0gcmVuZGVyU3RhdGUuZGVwdGhGYXIgKSApIHtcclxuXHJcblx0XHRcdFx0dGhpcy5kZXB0aE5lYXIgPSBkZXB0aERhdGEuZGVwdGhOZWFyO1xyXG5cdFx0XHRcdHRoaXMuZGVwdGhGYXIgPSBkZXB0aERhdGEuZGVwdGhGYXI7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHR0aGlzLnRleHR1cmUgPSB0ZXh0dXJlO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRyZW5kZXIoIHJlbmRlcmVyLCBjYW1lcmFYUiApIHtcclxuXHJcblx0XHRpZiAoIHRoaXMudGV4dHVyZSAhPT0gbnVsbCApIHtcclxuXHJcblx0XHRcdGlmICggdGhpcy5tZXNoID09PSBudWxsICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCB2aWV3cG9ydCA9IGNhbWVyYVhSLmNhbWVyYXNbIDAgXS52aWV3cG9ydDtcclxuXHRcdFx0XHRjb25zdCBtYXRlcmlhbCA9IG5ldyBTaGFkZXJNYXRlcmlhbCgge1xyXG5cdFx0XHRcdFx0ZXh0ZW5zaW9uczogeyBmcmFnRGVwdGg6IHRydWUgfSxcclxuXHRcdFx0XHRcdHZlcnRleFNoYWRlcjogX29jY2x1c2lvbl92ZXJ0ZXgsXHJcblx0XHRcdFx0XHRmcmFnbWVudFNoYWRlcjogX29jY2x1c2lvbl9mcmFnbWVudCxcclxuXHRcdFx0XHRcdHVuaWZvcm1zOiB7XHJcblx0XHRcdFx0XHRcdGRlcHRoQ29sb3I6IHsgdmFsdWU6IHRoaXMudGV4dHVyZSB9LFxyXG5cdFx0XHRcdFx0XHRkZXB0aFdpZHRoOiB7IHZhbHVlOiB2aWV3cG9ydC56IH0sXHJcblx0XHRcdFx0XHRcdGRlcHRoSGVpZ2h0OiB7IHZhbHVlOiB2aWV3cG9ydC53IH1cclxuXHRcdFx0XHRcdH1cclxuXHRcdFx0XHR9ICk7XHJcblxyXG5cdFx0XHRcdHRoaXMubWVzaCA9IG5ldyBNZXNoKCBuZXcgUGxhbmVHZW9tZXRyeSggMjAsIDIwICksIG1hdGVyaWFsICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRyZW5kZXJlci5yZW5kZXIoIHRoaXMubWVzaCwgY2FtZXJhWFIgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0cmVzZXQoKSB7XHJcblxyXG5cdFx0dGhpcy50ZXh0dXJlID0gbnVsbDtcclxuXHRcdHRoaXMubWVzaCA9IG51bGw7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IFdlYlhSRGVwdGhTZW5zaW5nIH07XHJcbiIsImltcG9ydCB7IEFycmF5Q2FtZXJhIH0gZnJvbSAnLi4vLi4vY2FtZXJhcy9BcnJheUNhbWVyYS5qcyc7XHJcbmltcG9ydCB7IEV2ZW50RGlzcGF0Y2hlciB9IGZyb20gJy4uLy4uL2NvcmUvRXZlbnREaXNwYXRjaGVyLmpzJztcclxuaW1wb3J0IHsgUGVyc3BlY3RpdmVDYW1lcmEgfSBmcm9tICcuLi8uLi9jYW1lcmFzL1BlcnNwZWN0aXZlQ2FtZXJhLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yMiB9IGZyb20gJy4uLy4uL21hdGgvVmVjdG9yMi5qcyc7XHJcbmltcG9ydCB7IFZlY3RvcjMgfSBmcm9tICcuLi8uLi9tYXRoL1ZlY3RvcjMuanMnO1xyXG5pbXBvcnQgeyBWZWN0b3I0IH0gZnJvbSAnLi4vLi4vbWF0aC9WZWN0b3I0LmpzJztcclxuaW1wb3J0IHsgUkFEMkRFRyB9IGZyb20gJy4uLy4uL21hdGgvTWF0aFV0aWxzLmpzJztcclxuaW1wb3J0IHsgV2ViR0xBbmltYXRpb24gfSBmcm9tICcuLi93ZWJnbC9XZWJHTEFuaW1hdGlvbi5qcyc7XHJcbmltcG9ydCB7IFdlYkdMUmVuZGVyVGFyZ2V0IH0gZnJvbSAnLi4vV2ViR0xSZW5kZXJUYXJnZXQuanMnO1xyXG5pbXBvcnQgeyBXZWJYUkNvbnRyb2xsZXIgfSBmcm9tICcuL1dlYlhSQ29udHJvbGxlci5qcyc7XHJcbmltcG9ydCB7IERlcHRoVGV4dHVyZSB9IGZyb20gJy4uLy4uL3RleHR1cmVzL0RlcHRoVGV4dHVyZS5qcyc7XHJcbmltcG9ydCB7IERlcHRoRm9ybWF0LCBEZXB0aFN0ZW5jaWxGb3JtYXQsIFJHQkFGb3JtYXQsIFVuc2lnbmVkQnl0ZVR5cGUsIFVuc2lnbmVkSW50VHlwZSwgVW5zaWduZWRJbnQyNDhUeXBlIH0gZnJvbSAnLi4vLi4vY29uc3RhbnRzLmpzJztcclxuaW1wb3J0IHsgV2ViWFJEZXB0aFNlbnNpbmcgfSBmcm9tICcuL1dlYlhSRGVwdGhTZW5zaW5nLmpzJztcclxuXHJcbmNsYXNzIFdlYlhSTWFuYWdlciBleHRlbmRzIEV2ZW50RGlzcGF0Y2hlciB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCByZW5kZXJlciwgZ2wgKSB7XHJcblxyXG5cdFx0c3VwZXIoKTtcclxuXHJcblx0XHRjb25zdCBzY29wZSA9IHRoaXM7XHJcblxyXG5cdFx0bGV0IHNlc3Npb24gPSBudWxsO1xyXG5cclxuXHRcdGxldCBmcmFtZWJ1ZmZlclNjYWxlRmFjdG9yID0gMS4wO1xyXG5cclxuXHRcdGxldCByZWZlcmVuY2VTcGFjZSA9IG51bGw7XHJcblx0XHRsZXQgcmVmZXJlbmNlU3BhY2VUeXBlID0gJ2xvY2FsLWZsb29yJztcclxuXHRcdC8vIFNldCBkZWZhdWx0IGZvdmVhdGlvbiB0byBtYXhpbXVtLlxyXG5cdFx0bGV0IGZvdmVhdGlvbiA9IDEuMDtcclxuXHRcdGxldCBjdXN0b21SZWZlcmVuY2VTcGFjZSA9IG51bGw7XHJcblxyXG5cdFx0bGV0IHBvc2UgPSBudWxsO1xyXG5cdFx0bGV0IGdsQmluZGluZyA9IG51bGw7XHJcblx0XHRsZXQgZ2xQcm9qTGF5ZXIgPSBudWxsO1xyXG5cdFx0bGV0IGdsQmFzZUxheWVyID0gbnVsbDtcclxuXHRcdGxldCB4ckZyYW1lID0gbnVsbDtcclxuXHJcblx0XHRjb25zdCBkZXB0aFNlbnNpbmcgPSBuZXcgV2ViWFJEZXB0aFNlbnNpbmcoKTtcclxuXHRcdGNvbnN0IGF0dHJpYnV0ZXMgPSBnbC5nZXRDb250ZXh0QXR0cmlidXRlcygpO1xyXG5cclxuXHRcdGxldCBpbml0aWFsUmVuZGVyVGFyZ2V0ID0gbnVsbDtcclxuXHRcdGxldCBuZXdSZW5kZXJUYXJnZXQgPSBudWxsO1xyXG5cclxuXHRcdGNvbnN0IGNvbnRyb2xsZXJzID0gW107XHJcblx0XHRjb25zdCBjb250cm9sbGVySW5wdXRTb3VyY2VzID0gW107XHJcblxyXG5cdFx0Y29uc3QgY3VycmVudFNpemUgPSBuZXcgVmVjdG9yMigpO1xyXG5cdFx0bGV0IGN1cnJlbnRQaXhlbFJhdGlvID0gbnVsbDtcclxuXHJcblx0XHQvL1xyXG5cclxuXHRcdGNvbnN0IGNhbWVyYUwgPSBuZXcgUGVyc3BlY3RpdmVDYW1lcmEoKTtcclxuXHRcdGNhbWVyYUwubGF5ZXJzLmVuYWJsZSggMSApO1xyXG5cdFx0Y2FtZXJhTC52aWV3cG9ydCA9IG5ldyBWZWN0b3I0KCk7XHJcblxyXG5cdFx0Y29uc3QgY2FtZXJhUiA9IG5ldyBQZXJzcGVjdGl2ZUNhbWVyYSgpO1xyXG5cdFx0Y2FtZXJhUi5sYXllcnMuZW5hYmxlKCAyICk7XHJcblx0XHRjYW1lcmFSLnZpZXdwb3J0ID0gbmV3IFZlY3RvcjQoKTtcclxuXHJcblx0XHRjb25zdCBjYW1lcmFzID0gWyBjYW1lcmFMLCBjYW1lcmFSIF07XHJcblxyXG5cdFx0Y29uc3QgY2FtZXJhWFIgPSBuZXcgQXJyYXlDYW1lcmEoKTtcclxuXHRcdGNhbWVyYVhSLmxheWVycy5lbmFibGUoIDEgKTtcclxuXHRcdGNhbWVyYVhSLmxheWVycy5lbmFibGUoIDIgKTtcclxuXHJcblx0XHRsZXQgX2N1cnJlbnREZXB0aE5lYXIgPSBudWxsO1xyXG5cdFx0bGV0IF9jdXJyZW50RGVwdGhGYXIgPSBudWxsO1xyXG5cclxuXHRcdC8vXHJcblxyXG5cdFx0dGhpcy5jYW1lcmFBdXRvVXBkYXRlID0gdHJ1ZTtcclxuXHRcdHRoaXMuZW5hYmxlZCA9IGZhbHNlO1xyXG5cclxuXHRcdHRoaXMuaXNQcmVzZW50aW5nID0gZmFsc2U7XHJcblxyXG5cdFx0dGhpcy5nZXRDb250cm9sbGVyID0gZnVuY3Rpb24gKCBpbmRleCApIHtcclxuXHJcblx0XHRcdGxldCBjb250cm9sbGVyID0gY29udHJvbGxlcnNbIGluZGV4IF07XHJcblxyXG5cdFx0XHRpZiAoIGNvbnRyb2xsZXIgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0Y29udHJvbGxlciA9IG5ldyBXZWJYUkNvbnRyb2xsZXIoKTtcclxuXHRcdFx0XHRjb250cm9sbGVyc1sgaW5kZXggXSA9IGNvbnRyb2xsZXI7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRyZXR1cm4gY29udHJvbGxlci5nZXRUYXJnZXRSYXlTcGFjZSgpO1xyXG5cclxuXHRcdH07XHJcblxyXG5cdFx0dGhpcy5nZXRDb250cm9sbGVyR3JpcCA9IGZ1bmN0aW9uICggaW5kZXggKSB7XHJcblxyXG5cdFx0XHRsZXQgY29udHJvbGxlciA9IGNvbnRyb2xsZXJzWyBpbmRleCBdO1xyXG5cclxuXHRcdFx0aWYgKCBjb250cm9sbGVyID09PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnRyb2xsZXIgPSBuZXcgV2ViWFJDb250cm9sbGVyKCk7XHJcblx0XHRcdFx0Y29udHJvbGxlcnNbIGluZGV4IF0gPSBjb250cm9sbGVyO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0cmV0dXJuIGNvbnRyb2xsZXIuZ2V0R3JpcFNwYWNlKCk7XHJcblxyXG5cdFx0fTtcclxuXHJcblx0XHR0aGlzLmdldEhhbmQgPSBmdW5jdGlvbiAoIGluZGV4ICkge1xyXG5cclxuXHRcdFx0bGV0IGNvbnRyb2xsZXIgPSBjb250cm9sbGVyc1sgaW5kZXggXTtcclxuXHJcblx0XHRcdGlmICggY29udHJvbGxlciA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHRjb250cm9sbGVyID0gbmV3IFdlYlhSQ29udHJvbGxlcigpO1xyXG5cdFx0XHRcdGNvbnRyb2xsZXJzWyBpbmRleCBdID0gY29udHJvbGxlcjtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHJldHVybiBjb250cm9sbGVyLmdldEhhbmRTcGFjZSgpO1xyXG5cclxuXHRcdH07XHJcblxyXG5cdFx0Ly9cclxuXHJcblx0XHRmdW5jdGlvbiBvblNlc3Npb25FdmVudCggZXZlbnQgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBjb250cm9sbGVySW5kZXggPSBjb250cm9sbGVySW5wdXRTb3VyY2VzLmluZGV4T2YoIGV2ZW50LmlucHV0U291cmNlICk7XHJcblxyXG5cdFx0XHRpZiAoIGNvbnRyb2xsZXJJbmRleCA9PT0gLSAxICkge1xyXG5cclxuXHRcdFx0XHRyZXR1cm47XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRjb25zdCBjb250cm9sbGVyID0gY29udHJvbGxlcnNbIGNvbnRyb2xsZXJJbmRleCBdO1xyXG5cclxuXHRcdFx0aWYgKCBjb250cm9sbGVyICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnRyb2xsZXIudXBkYXRlKCBldmVudC5pbnB1dFNvdXJjZSwgZXZlbnQuZnJhbWUsIGN1c3RvbVJlZmVyZW5jZVNwYWNlIHx8IHJlZmVyZW5jZVNwYWNlICk7XHJcblx0XHRcdFx0Y29udHJvbGxlci5kaXNwYXRjaEV2ZW50KCB7IHR5cGU6IGV2ZW50LnR5cGUsIGRhdGE6IGV2ZW50LmlucHV0U291cmNlIH0gKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0ZnVuY3Rpb24gb25TZXNzaW9uRW5kKCkge1xyXG5cclxuXHRcdFx0c2Vzc2lvbi5yZW1vdmVFdmVudExpc3RlbmVyKCAnc2VsZWN0Jywgb25TZXNzaW9uRXZlbnQgKTtcclxuXHRcdFx0c2Vzc2lvbi5yZW1vdmVFdmVudExpc3RlbmVyKCAnc2VsZWN0c3RhcnQnLCBvblNlc3Npb25FdmVudCApO1xyXG5cdFx0XHRzZXNzaW9uLnJlbW92ZUV2ZW50TGlzdGVuZXIoICdzZWxlY3RlbmQnLCBvblNlc3Npb25FdmVudCApO1xyXG5cdFx0XHRzZXNzaW9uLnJlbW92ZUV2ZW50TGlzdGVuZXIoICdzcXVlZXplJywgb25TZXNzaW9uRXZlbnQgKTtcclxuXHRcdFx0c2Vzc2lvbi5yZW1vdmVFdmVudExpc3RlbmVyKCAnc3F1ZWV6ZXN0YXJ0Jywgb25TZXNzaW9uRXZlbnQgKTtcclxuXHRcdFx0c2Vzc2lvbi5yZW1vdmVFdmVudExpc3RlbmVyKCAnc3F1ZWV6ZWVuZCcsIG9uU2Vzc2lvbkV2ZW50ICk7XHJcblx0XHRcdHNlc3Npb24ucmVtb3ZlRXZlbnRMaXN0ZW5lciggJ2VuZCcsIG9uU2Vzc2lvbkVuZCApO1xyXG5cdFx0XHRzZXNzaW9uLnJlbW92ZUV2ZW50TGlzdGVuZXIoICdpbnB1dHNvdXJjZXNjaGFuZ2UnLCBvbklucHV0U291cmNlc0NoYW5nZSApO1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgY29udHJvbGxlcnMubGVuZ3RoOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBpbnB1dFNvdXJjZSA9IGNvbnRyb2xsZXJJbnB1dFNvdXJjZXNbIGkgXTtcclxuXHJcblx0XHRcdFx0aWYgKCBpbnB1dFNvdXJjZSA9PT0gbnVsbCApIGNvbnRpbnVlO1xyXG5cclxuXHRcdFx0XHRjb250cm9sbGVySW5wdXRTb3VyY2VzWyBpIF0gPSBudWxsO1xyXG5cclxuXHRcdFx0XHRjb250cm9sbGVyc1sgaSBdLmRpc2Nvbm5lY3QoIGlucHV0U291cmNlICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRfY3VycmVudERlcHRoTmVhciA9IG51bGw7XHJcblx0XHRcdF9jdXJyZW50RGVwdGhGYXIgPSBudWxsO1xyXG5cclxuXHRcdFx0ZGVwdGhTZW5zaW5nLnJlc2V0KCk7XHJcblxyXG5cdFx0XHQvLyByZXN0b3JlIGZyYW1lYnVmZmVyL3JlbmRlcmluZyBzdGF0ZVxyXG5cclxuXHRcdFx0cmVuZGVyZXIuc2V0UmVuZGVyVGFyZ2V0KCBpbml0aWFsUmVuZGVyVGFyZ2V0ICk7XHJcblxyXG5cdFx0XHRnbEJhc2VMYXllciA9IG51bGw7XHJcblx0XHRcdGdsUHJvakxheWVyID0gbnVsbDtcclxuXHRcdFx0Z2xCaW5kaW5nID0gbnVsbDtcclxuXHRcdFx0c2Vzc2lvbiA9IG51bGw7XHJcblx0XHRcdG5ld1JlbmRlclRhcmdldCA9IG51bGw7XHJcblxyXG5cdFx0XHQvL1xyXG5cclxuXHRcdFx0YW5pbWF0aW9uLnN0b3AoKTtcclxuXHJcblx0XHRcdHNjb3BlLmlzUHJlc2VudGluZyA9IGZhbHNlO1xyXG5cclxuXHRcdFx0cmVuZGVyZXIuc2V0UGl4ZWxSYXRpbyggY3VycmVudFBpeGVsUmF0aW8gKTtcclxuXHRcdFx0cmVuZGVyZXIuc2V0U2l6ZSggY3VycmVudFNpemUud2lkdGgsIGN1cnJlbnRTaXplLmhlaWdodCwgZmFsc2UgKTtcclxuXHJcblx0XHRcdHNjb3BlLmRpc3BhdGNoRXZlbnQoIHsgdHlwZTogJ3Nlc3Npb25lbmQnIH0gKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5zZXRGcmFtZWJ1ZmZlclNjYWxlRmFjdG9yID0gZnVuY3Rpb24gKCB2YWx1ZSApIHtcclxuXHJcblx0XHRcdGZyYW1lYnVmZmVyU2NhbGVGYWN0b3IgPSB2YWx1ZTtcclxuXHJcblx0XHRcdGlmICggc2NvcGUuaXNQcmVzZW50aW5nID09PSB0cnVlICkge1xyXG5cclxuXHRcdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5XZWJYUk1hbmFnZXI6IENhbm5vdCBjaGFuZ2UgZnJhbWVidWZmZXIgc2NhbGUgd2hpbGUgcHJlc2VudGluZy4nICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fTtcclxuXHJcblx0XHR0aGlzLnNldFJlZmVyZW5jZVNwYWNlVHlwZSA9IGZ1bmN0aW9uICggdmFsdWUgKSB7XHJcblxyXG5cdFx0XHRyZWZlcmVuY2VTcGFjZVR5cGUgPSB2YWx1ZTtcclxuXHJcblx0XHRcdGlmICggc2NvcGUuaXNQcmVzZW50aW5nID09PSB0cnVlICkge1xyXG5cclxuXHRcdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5XZWJYUk1hbmFnZXI6IENhbm5vdCBjaGFuZ2UgcmVmZXJlbmNlIHNwYWNlIHR5cGUgd2hpbGUgcHJlc2VudGluZy4nICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fTtcclxuXHJcblx0XHR0aGlzLmdldFJlZmVyZW5jZVNwYWNlID0gZnVuY3Rpb24gKCkge1xyXG5cclxuXHRcdFx0cmV0dXJuIGN1c3RvbVJlZmVyZW5jZVNwYWNlIHx8IHJlZmVyZW5jZVNwYWNlO1xyXG5cclxuXHRcdH07XHJcblxyXG5cdFx0dGhpcy5zZXRSZWZlcmVuY2VTcGFjZSA9IGZ1bmN0aW9uICggc3BhY2UgKSB7XHJcblxyXG5cdFx0XHRjdXN0b21SZWZlcmVuY2VTcGFjZSA9IHNwYWNlO1xyXG5cclxuXHRcdH07XHJcblxyXG5cdFx0dGhpcy5nZXRCYXNlTGF5ZXIgPSBmdW5jdGlvbiAoKSB7XHJcblxyXG5cdFx0XHRyZXR1cm4gZ2xQcm9qTGF5ZXIgIT09IG51bGwgPyBnbFByb2pMYXllciA6IGdsQmFzZUxheWVyO1xyXG5cclxuXHRcdH07XHJcblxyXG5cdFx0dGhpcy5nZXRCaW5kaW5nID0gZnVuY3Rpb24gKCkge1xyXG5cclxuXHRcdFx0cmV0dXJuIGdsQmluZGluZztcclxuXHJcblx0XHR9O1xyXG5cclxuXHRcdHRoaXMuZ2V0RnJhbWUgPSBmdW5jdGlvbiAoKSB7XHJcblxyXG5cdFx0XHRyZXR1cm4geHJGcmFtZTtcclxuXHJcblx0XHR9O1xyXG5cclxuXHRcdHRoaXMuZ2V0U2Vzc2lvbiA9IGZ1bmN0aW9uICgpIHtcclxuXHJcblx0XHRcdHJldHVybiBzZXNzaW9uO1xyXG5cclxuXHRcdH07XHJcblxyXG5cdFx0dGhpcy5zZXRTZXNzaW9uID0gYXN5bmMgZnVuY3Rpb24gKCB2YWx1ZSApIHtcclxuXHJcblx0XHRcdHNlc3Npb24gPSB2YWx1ZTtcclxuXHJcblx0XHRcdGlmICggc2Vzc2lvbiAhPT0gbnVsbCApIHtcclxuXHJcblx0XHRcdFx0aW5pdGlhbFJlbmRlclRhcmdldCA9IHJlbmRlcmVyLmdldFJlbmRlclRhcmdldCgpO1xyXG5cclxuXHRcdFx0XHRzZXNzaW9uLmFkZEV2ZW50TGlzdGVuZXIoICdzZWxlY3QnLCBvblNlc3Npb25FdmVudCApO1xyXG5cdFx0XHRcdHNlc3Npb24uYWRkRXZlbnRMaXN0ZW5lciggJ3NlbGVjdHN0YXJ0Jywgb25TZXNzaW9uRXZlbnQgKTtcclxuXHRcdFx0XHRzZXNzaW9uLmFkZEV2ZW50TGlzdGVuZXIoICdzZWxlY3RlbmQnLCBvblNlc3Npb25FdmVudCApO1xyXG5cdFx0XHRcdHNlc3Npb24uYWRkRXZlbnRMaXN0ZW5lciggJ3NxdWVlemUnLCBvblNlc3Npb25FdmVudCApO1xyXG5cdFx0XHRcdHNlc3Npb24uYWRkRXZlbnRMaXN0ZW5lciggJ3NxdWVlemVzdGFydCcsIG9uU2Vzc2lvbkV2ZW50ICk7XHJcblx0XHRcdFx0c2Vzc2lvbi5hZGRFdmVudExpc3RlbmVyKCAnc3F1ZWV6ZWVuZCcsIG9uU2Vzc2lvbkV2ZW50ICk7XHJcblx0XHRcdFx0c2Vzc2lvbi5hZGRFdmVudExpc3RlbmVyKCAnZW5kJywgb25TZXNzaW9uRW5kICk7XHJcblx0XHRcdFx0c2Vzc2lvbi5hZGRFdmVudExpc3RlbmVyKCAnaW5wdXRzb3VyY2VzY2hhbmdlJywgb25JbnB1dFNvdXJjZXNDaGFuZ2UgKTtcclxuXHJcblx0XHRcdFx0aWYgKCBhdHRyaWJ1dGVzLnhyQ29tcGF0aWJsZSAhPT0gdHJ1ZSApIHtcclxuXHJcblx0XHRcdFx0XHRhd2FpdCBnbC5tYWtlWFJDb21wYXRpYmxlKCk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0Y3VycmVudFBpeGVsUmF0aW8gPSByZW5kZXJlci5nZXRQaXhlbFJhdGlvKCk7XHJcblx0XHRcdFx0cmVuZGVyZXIuZ2V0U2l6ZSggY3VycmVudFNpemUgKTtcclxuXHJcblx0XHRcdFx0aWYgKCAoIHNlc3Npb24ucmVuZGVyU3RhdGUubGF5ZXJzID09PSB1bmRlZmluZWQgKSB8fCAoIHJlbmRlcmVyLmNhcGFiaWxpdGllcy5pc1dlYkdMMiA9PT0gZmFsc2UgKSApIHtcclxuXHJcblx0XHRcdFx0XHRjb25zdCBsYXllckluaXQgPSB7XHJcblx0XHRcdFx0XHRcdGFudGlhbGlhczogKCBzZXNzaW9uLnJlbmRlclN0YXRlLmxheWVycyA9PT0gdW5kZWZpbmVkICkgPyBhdHRyaWJ1dGVzLmFudGlhbGlhcyA6IHRydWUsXHJcblx0XHRcdFx0XHRcdGFscGhhOiB0cnVlLFxyXG5cdFx0XHRcdFx0XHRkZXB0aDogYXR0cmlidXRlcy5kZXB0aCxcclxuXHRcdFx0XHRcdFx0c3RlbmNpbDogYXR0cmlidXRlcy5zdGVuY2lsLFxyXG5cdFx0XHRcdFx0XHRmcmFtZWJ1ZmZlclNjYWxlRmFjdG9yOiBmcmFtZWJ1ZmZlclNjYWxlRmFjdG9yXHJcblx0XHRcdFx0XHR9O1xyXG5cclxuXHRcdFx0XHRcdGdsQmFzZUxheWVyID0gbmV3IFhSV2ViR0xMYXllciggc2Vzc2lvbiwgZ2wsIGxheWVySW5pdCApO1xyXG5cclxuXHRcdFx0XHRcdHNlc3Npb24udXBkYXRlUmVuZGVyU3RhdGUoIHsgYmFzZUxheWVyOiBnbEJhc2VMYXllciB9ICk7XHJcblxyXG5cdFx0XHRcdFx0cmVuZGVyZXIuc2V0UGl4ZWxSYXRpbyggMSApO1xyXG5cdFx0XHRcdFx0cmVuZGVyZXIuc2V0U2l6ZSggZ2xCYXNlTGF5ZXIuZnJhbWVidWZmZXJXaWR0aCwgZ2xCYXNlTGF5ZXIuZnJhbWVidWZmZXJIZWlnaHQsIGZhbHNlICk7XHJcblxyXG5cdFx0XHRcdFx0bmV3UmVuZGVyVGFyZ2V0ID0gbmV3IFdlYkdMUmVuZGVyVGFyZ2V0KFxyXG5cdFx0XHRcdFx0XHRnbEJhc2VMYXllci5mcmFtZWJ1ZmZlcldpZHRoLFxyXG5cdFx0XHRcdFx0XHRnbEJhc2VMYXllci5mcmFtZWJ1ZmZlckhlaWdodCxcclxuXHRcdFx0XHRcdFx0e1xyXG5cdFx0XHRcdFx0XHRcdGZvcm1hdDogUkdCQUZvcm1hdCxcclxuXHRcdFx0XHRcdFx0XHR0eXBlOiBVbnNpZ25lZEJ5dGVUeXBlLFxyXG5cdFx0XHRcdFx0XHRcdGNvbG9yU3BhY2U6IHJlbmRlcmVyLm91dHB1dENvbG9yU3BhY2UsXHJcblx0XHRcdFx0XHRcdFx0c3RlbmNpbEJ1ZmZlcjogYXR0cmlidXRlcy5zdGVuY2lsXHJcblx0XHRcdFx0XHRcdH1cclxuXHRcdFx0XHRcdCk7XHJcblxyXG5cdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0bGV0IGRlcHRoRm9ybWF0ID0gbnVsbDtcclxuXHRcdFx0XHRcdGxldCBkZXB0aFR5cGUgPSBudWxsO1xyXG5cdFx0XHRcdFx0bGV0IGdsRGVwdGhGb3JtYXQgPSBudWxsO1xyXG5cclxuXHRcdFx0XHRcdGlmICggYXR0cmlidXRlcy5kZXB0aCApIHtcclxuXHJcblx0XHRcdFx0XHRcdGdsRGVwdGhGb3JtYXQgPSBhdHRyaWJ1dGVzLnN0ZW5jaWwgPyBnbC5ERVBUSDI0X1NURU5DSUw4IDogZ2wuREVQVEhfQ09NUE9ORU5UMjQ7XHJcblx0XHRcdFx0XHRcdGRlcHRoRm9ybWF0ID0gYXR0cmlidXRlcy5zdGVuY2lsID8gRGVwdGhTdGVuY2lsRm9ybWF0IDogRGVwdGhGb3JtYXQ7XHJcblx0XHRcdFx0XHRcdGRlcHRoVHlwZSA9IGF0dHJpYnV0ZXMuc3RlbmNpbCA/IFVuc2lnbmVkSW50MjQ4VHlwZSA6IFVuc2lnbmVkSW50VHlwZTtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgcHJvamVjdGlvbmxheWVySW5pdCA9IHtcclxuXHRcdFx0XHRcdFx0Y29sb3JGb3JtYXQ6IGdsLlJHQkE4LFxyXG5cdFx0XHRcdFx0XHRkZXB0aEZvcm1hdDogZ2xEZXB0aEZvcm1hdCxcclxuXHRcdFx0XHRcdFx0c2NhbGVGYWN0b3I6IGZyYW1lYnVmZmVyU2NhbGVGYWN0b3JcclxuXHRcdFx0XHRcdH07XHJcblxyXG5cdFx0XHRcdFx0Z2xCaW5kaW5nID0gbmV3IFhSV2ViR0xCaW5kaW5nKCBzZXNzaW9uLCBnbCApO1xyXG5cclxuXHRcdFx0XHRcdGdsUHJvakxheWVyID0gZ2xCaW5kaW5nLmNyZWF0ZVByb2plY3Rpb25MYXllciggcHJvamVjdGlvbmxheWVySW5pdCApO1xyXG5cclxuXHRcdFx0XHRcdHNlc3Npb24udXBkYXRlUmVuZGVyU3RhdGUoIHsgbGF5ZXJzOiBbIGdsUHJvakxheWVyIF0gfSApO1xyXG5cclxuXHRcdFx0XHRcdHJlbmRlcmVyLnNldFBpeGVsUmF0aW8oIDEgKTtcclxuXHRcdFx0XHRcdHJlbmRlcmVyLnNldFNpemUoIGdsUHJvakxheWVyLnRleHR1cmVXaWR0aCwgZ2xQcm9qTGF5ZXIudGV4dHVyZUhlaWdodCwgZmFsc2UgKTtcclxuXHJcblx0XHRcdFx0XHRuZXdSZW5kZXJUYXJnZXQgPSBuZXcgV2ViR0xSZW5kZXJUYXJnZXQoXHJcblx0XHRcdFx0XHRcdGdsUHJvakxheWVyLnRleHR1cmVXaWR0aCxcclxuXHRcdFx0XHRcdFx0Z2xQcm9qTGF5ZXIudGV4dHVyZUhlaWdodCxcclxuXHRcdFx0XHRcdFx0e1xyXG5cdFx0XHRcdFx0XHRcdGZvcm1hdDogUkdCQUZvcm1hdCxcclxuXHRcdFx0XHRcdFx0XHR0eXBlOiBVbnNpZ25lZEJ5dGVUeXBlLFxyXG5cdFx0XHRcdFx0XHRcdGRlcHRoVGV4dHVyZTogbmV3IERlcHRoVGV4dHVyZSggZ2xQcm9qTGF5ZXIudGV4dHVyZVdpZHRoLCBnbFByb2pMYXllci50ZXh0dXJlSGVpZ2h0LCBkZXB0aFR5cGUsIHVuZGVmaW5lZCwgdW5kZWZpbmVkLCB1bmRlZmluZWQsIHVuZGVmaW5lZCwgdW5kZWZpbmVkLCB1bmRlZmluZWQsIGRlcHRoRm9ybWF0ICksXHJcblx0XHRcdFx0XHRcdFx0c3RlbmNpbEJ1ZmZlcjogYXR0cmlidXRlcy5zdGVuY2lsLFxyXG5cdFx0XHRcdFx0XHRcdGNvbG9yU3BhY2U6IHJlbmRlcmVyLm91dHB1dENvbG9yU3BhY2UsXHJcblx0XHRcdFx0XHRcdFx0c2FtcGxlczogYXR0cmlidXRlcy5hbnRpYWxpYXMgPyA0IDogMFxyXG5cdFx0XHRcdFx0XHR9ICk7XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgcmVuZGVyVGFyZ2V0UHJvcGVydGllcyA9IHJlbmRlcmVyLnByb3BlcnRpZXMuZ2V0KCBuZXdSZW5kZXJUYXJnZXQgKTtcclxuXHRcdFx0XHRcdHJlbmRlclRhcmdldFByb3BlcnRpZXMuX19pZ25vcmVEZXB0aFZhbHVlcyA9IGdsUHJvakxheWVyLmlnbm9yZURlcHRoVmFsdWVzO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdG5ld1JlbmRlclRhcmdldC5pc1hSUmVuZGVyVGFyZ2V0ID0gdHJ1ZTsgLy8gVE9ETyBSZW1vdmUgdGhpcyB3aGVuIHBvc3NpYmxlLCBzZWUgIzIzMjc4XHJcblxyXG5cdFx0XHRcdHRoaXMuc2V0Rm92ZWF0aW9uKCBmb3ZlYXRpb24gKTtcclxuXHJcblx0XHRcdFx0Y3VzdG9tUmVmZXJlbmNlU3BhY2UgPSBudWxsO1xyXG5cdFx0XHRcdHJlZmVyZW5jZVNwYWNlID0gYXdhaXQgc2Vzc2lvbi5yZXF1ZXN0UmVmZXJlbmNlU3BhY2UoIHJlZmVyZW5jZVNwYWNlVHlwZSApO1xyXG5cclxuXHRcdFx0XHRhbmltYXRpb24uc2V0Q29udGV4dCggc2Vzc2lvbiApO1xyXG5cdFx0XHRcdGFuaW1hdGlvbi5zdGFydCgpO1xyXG5cclxuXHRcdFx0XHRzY29wZS5pc1ByZXNlbnRpbmcgPSB0cnVlO1xyXG5cclxuXHRcdFx0XHRzY29wZS5kaXNwYXRjaEV2ZW50KCB7IHR5cGU6ICdzZXNzaW9uc3RhcnQnIH0gKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9O1xyXG5cclxuXHRcdHRoaXMuZ2V0RW52aXJvbm1lbnRCbGVuZE1vZGUgPSBmdW5jdGlvbiAoKSB7XHJcblxyXG5cdFx0XHRpZiAoIHNlc3Npb24gIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdHJldHVybiBzZXNzaW9uLmVudmlyb25tZW50QmxlbmRNb2RlO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH07XHJcblxyXG5cdFx0ZnVuY3Rpb24gb25JbnB1dFNvdXJjZXNDaGFuZ2UoIGV2ZW50ICkge1xyXG5cclxuXHRcdFx0Ly8gTm90aWZ5IGRpc2Nvbm5lY3RlZFxyXG5cclxuXHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgZXZlbnQucmVtb3ZlZC5sZW5ndGg7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IGlucHV0U291cmNlID0gZXZlbnQucmVtb3ZlZFsgaSBdO1xyXG5cdFx0XHRcdGNvbnN0IGluZGV4ID0gY29udHJvbGxlcklucHV0U291cmNlcy5pbmRleE9mKCBpbnB1dFNvdXJjZSApO1xyXG5cclxuXHRcdFx0XHRpZiAoIGluZGV4ID49IDAgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y29udHJvbGxlcklucHV0U291cmNlc1sgaW5kZXggXSA9IG51bGw7XHJcblx0XHRcdFx0XHRjb250cm9sbGVyc1sgaW5kZXggXS5kaXNjb25uZWN0KCBpbnB1dFNvdXJjZSApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyBOb3RpZnkgY29ubmVjdGVkXHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBldmVudC5hZGRlZC5sZW5ndGg7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IGlucHV0U291cmNlID0gZXZlbnQuYWRkZWRbIGkgXTtcclxuXHJcblx0XHRcdFx0bGV0IGNvbnRyb2xsZXJJbmRleCA9IGNvbnRyb2xsZXJJbnB1dFNvdXJjZXMuaW5kZXhPZiggaW5wdXRTb3VyY2UgKTtcclxuXHJcblx0XHRcdFx0aWYgKCBjb250cm9sbGVySW5kZXggPT09IC0gMSApIHtcclxuXHJcblx0XHRcdFx0XHQvLyBBc3NpZ24gaW5wdXQgc291cmNlIGEgY29udHJvbGxlciB0aGF0IGN1cnJlbnRseSBoYXMgbm8gaW5wdXQgc291cmNlXHJcblxyXG5cdFx0XHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgY29udHJvbGxlcnMubGVuZ3RoOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRcdFx0aWYgKCBpID49IGNvbnRyb2xsZXJJbnB1dFNvdXJjZXMubGVuZ3RoICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRjb250cm9sbGVySW5wdXRTb3VyY2VzLnB1c2goIGlucHV0U291cmNlICk7XHJcblx0XHRcdFx0XHRcdFx0Y29udHJvbGxlckluZGV4ID0gaTtcclxuXHRcdFx0XHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdFx0XHRcdH0gZWxzZSBpZiAoIGNvbnRyb2xsZXJJbnB1dFNvdXJjZXNbIGkgXSA9PT0gbnVsbCApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0Y29udHJvbGxlcklucHV0U291cmNlc1sgaSBdID0gaW5wdXRTb3VyY2U7XHJcblx0XHRcdFx0XHRcdFx0Y29udHJvbGxlckluZGV4ID0gaTtcclxuXHRcdFx0XHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0Ly8gSWYgYWxsIGNvbnRyb2xsZXJzIGRvIGN1cnJlbnRseSByZWNlaXZlIGlucHV0IHdlIGlnbm9yZSBuZXcgb25lc1xyXG5cclxuXHRcdFx0XHRcdGlmICggY29udHJvbGxlckluZGV4ID09PSAtIDEgKSBicmVhaztcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRjb25zdCBjb250cm9sbGVyID0gY29udHJvbGxlcnNbIGNvbnRyb2xsZXJJbmRleCBdO1xyXG5cclxuXHRcdFx0XHRpZiAoIGNvbnRyb2xsZXIgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y29udHJvbGxlci5jb25uZWN0KCBpbnB1dFNvdXJjZSApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vXHJcblxyXG5cdFx0Y29uc3QgY2FtZXJhTFBvcyA9IG5ldyBWZWN0b3IzKCk7XHJcblx0XHRjb25zdCBjYW1lcmFSUG9zID0gbmV3IFZlY3RvcjMoKTtcclxuXHJcblx0XHQvKipcclxuXHRcdCAqIEFzc3VtZXMgMiBjYW1lcmFzIHRoYXQgYXJlIHBhcmFsbGVsIGFuZCBzaGFyZSBhbiBYLWF4aXMsIGFuZCB0aGF0XHJcblx0XHQgKiB0aGUgY2FtZXJhcycgcHJvamVjdGlvbiBhbmQgd29ybGQgbWF0cmljZXMgaGF2ZSBhbHJlYWR5IGJlZW4gc2V0LlxyXG5cdFx0ICogQW5kIHRoYXQgbmVhciBhbmQgZmFyIHBsYW5lcyBhcmUgaWRlbnRpY2FsIGZvciBib3RoIGNhbWVyYXMuXHJcblx0XHQgKiBWaXN1YWxpemF0aW9uIG9mIHRoaXMgdGVjaG5pcXVlOiBodHRwczovL2NvbXB1dGVyZ3JhcGhpY3Muc3RhY2tleGNoYW5nZS5jb20vYS80NzY1XHJcblx0XHQgKi9cclxuXHRcdGZ1bmN0aW9uIHNldFByb2plY3Rpb25Gcm9tVW5pb24oIGNhbWVyYSwgY2FtZXJhTCwgY2FtZXJhUiApIHtcclxuXHJcblx0XHRcdGNhbWVyYUxQb3Muc2V0RnJvbU1hdHJpeFBvc2l0aW9uKCBjYW1lcmFMLm1hdHJpeFdvcmxkICk7XHJcblx0XHRcdGNhbWVyYVJQb3Muc2V0RnJvbU1hdHJpeFBvc2l0aW9uKCBjYW1lcmFSLm1hdHJpeFdvcmxkICk7XHJcblxyXG5cdFx0XHRjb25zdCBpcGQgPSBjYW1lcmFMUG9zLmRpc3RhbmNlVG8oIGNhbWVyYVJQb3MgKTtcclxuXHJcblx0XHRcdGNvbnN0IHByb2pMID0gY2FtZXJhTC5wcm9qZWN0aW9uTWF0cml4LmVsZW1lbnRzO1xyXG5cdFx0XHRjb25zdCBwcm9qUiA9IGNhbWVyYVIucHJvamVjdGlvbk1hdHJpeC5lbGVtZW50cztcclxuXHJcblx0XHRcdC8vIFZSIHN5c3RlbXMgd2lsbCBoYXZlIGlkZW50aWNhbCBmYXIgYW5kIG5lYXIgcGxhbmVzLCBhbmRcclxuXHRcdFx0Ly8gbW9zdCBsaWtlbHkgaWRlbnRpY2FsIHRvcCBhbmQgYm90dG9tIGZydXN0dW0gZXh0ZW50cy5cclxuXHRcdFx0Ly8gVXNlIHRoZSBsZWZ0IGNhbWVyYSBmb3IgdGhlc2UgdmFsdWVzLlxyXG5cdFx0XHRjb25zdCBuZWFyID0gcHJvakxbIDE0IF0gLyAoIHByb2pMWyAxMCBdIC0gMSApO1xyXG5cdFx0XHRjb25zdCBmYXIgPSBwcm9qTFsgMTQgXSAvICggcHJvakxbIDEwIF0gKyAxICk7XHJcblx0XHRcdGNvbnN0IHRvcEZvdiA9ICggcHJvakxbIDkgXSArIDEgKSAvIHByb2pMWyA1IF07XHJcblx0XHRcdGNvbnN0IGJvdHRvbUZvdiA9ICggcHJvakxbIDkgXSAtIDEgKSAvIHByb2pMWyA1IF07XHJcblxyXG5cdFx0XHRjb25zdCBsZWZ0Rm92ID0gKCBwcm9qTFsgOCBdIC0gMSApIC8gcHJvakxbIDAgXTtcclxuXHRcdFx0Y29uc3QgcmlnaHRGb3YgPSAoIHByb2pSWyA4IF0gKyAxICkgLyBwcm9qUlsgMCBdO1xyXG5cdFx0XHRjb25zdCBsZWZ0ID0gbmVhciAqIGxlZnRGb3Y7XHJcblx0XHRcdGNvbnN0IHJpZ2h0ID0gbmVhciAqIHJpZ2h0Rm92O1xyXG5cclxuXHRcdFx0Ly8gQ2FsY3VsYXRlIHRoZSBuZXcgY2FtZXJhJ3MgcG9zaXRpb24gb2Zmc2V0IGZyb20gdGhlXHJcblx0XHRcdC8vIGxlZnQgY2FtZXJhLiB4T2Zmc2V0IHNob3VsZCBiZSByb3VnaGx5IGhhbGYgYGlwZGAuXHJcblx0XHRcdGNvbnN0IHpPZmZzZXQgPSBpcGQgLyAoIC0gbGVmdEZvdiArIHJpZ2h0Rm92ICk7XHJcblx0XHRcdGNvbnN0IHhPZmZzZXQgPSB6T2Zmc2V0ICogLSBsZWZ0Rm92O1xyXG5cclxuXHRcdFx0Ly8gVE9ETzogQmV0dGVyIHdheSB0byBhcHBseSB0aGlzIG9mZnNldD9cclxuXHRcdFx0Y2FtZXJhTC5tYXRyaXhXb3JsZC5kZWNvbXBvc2UoIGNhbWVyYS5wb3NpdGlvbiwgY2FtZXJhLnF1YXRlcm5pb24sIGNhbWVyYS5zY2FsZSApO1xyXG5cdFx0XHRjYW1lcmEudHJhbnNsYXRlWCggeE9mZnNldCApO1xyXG5cdFx0XHRjYW1lcmEudHJhbnNsYXRlWiggek9mZnNldCApO1xyXG5cdFx0XHRjYW1lcmEubWF0cml4V29ybGQuY29tcG9zZSggY2FtZXJhLnBvc2l0aW9uLCBjYW1lcmEucXVhdGVybmlvbiwgY2FtZXJhLnNjYWxlICk7XHJcblx0XHRcdGNhbWVyYS5tYXRyaXhXb3JsZEludmVyc2UuY29weSggY2FtZXJhLm1hdHJpeFdvcmxkICkuaW52ZXJ0KCk7XHJcblxyXG5cdFx0XHQvLyBGaW5kIHRoZSB1bmlvbiBvZiB0aGUgZnJ1c3R1bSB2YWx1ZXMgb2YgdGhlIGNhbWVyYXMgYW5kIHNjYWxlXHJcblx0XHRcdC8vIHRoZSB2YWx1ZXMgc28gdGhhdCB0aGUgbmVhciBwbGFuZSdzIHBvc2l0aW9uIGRvZXMgbm90IGNoYW5nZSBpbiB3b3JsZCBzcGFjZSxcclxuXHRcdFx0Ly8gYWx0aG91Z2ggbXVzdCBub3cgYmUgcmVsYXRpdmUgdG8gdGhlIG5ldyB1bmlvbiBjYW1lcmEuXHJcblx0XHRcdGNvbnN0IG5lYXIyID0gbmVhciArIHpPZmZzZXQ7XHJcblx0XHRcdGNvbnN0IGZhcjIgPSBmYXIgKyB6T2Zmc2V0O1xyXG5cdFx0XHRjb25zdCBsZWZ0MiA9IGxlZnQgLSB4T2Zmc2V0O1xyXG5cdFx0XHRjb25zdCByaWdodDIgPSByaWdodCArICggaXBkIC0geE9mZnNldCApO1xyXG5cdFx0XHRjb25zdCB0b3AyID0gdG9wRm92ICogZmFyIC8gZmFyMiAqIG5lYXIyO1xyXG5cdFx0XHRjb25zdCBib3R0b20yID0gYm90dG9tRm92ICogZmFyIC8gZmFyMiAqIG5lYXIyO1xyXG5cclxuXHRcdFx0Y2FtZXJhLnByb2plY3Rpb25NYXRyaXgubWFrZVBlcnNwZWN0aXZlKCBsZWZ0MiwgcmlnaHQyLCB0b3AyLCBib3R0b20yLCBuZWFyMiwgZmFyMiApO1xyXG5cdFx0XHRjYW1lcmEucHJvamVjdGlvbk1hdHJpeEludmVyc2UuY29weSggY2FtZXJhLnByb2plY3Rpb25NYXRyaXggKS5pbnZlcnQoKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0ZnVuY3Rpb24gdXBkYXRlQ2FtZXJhKCBjYW1lcmEsIHBhcmVudCApIHtcclxuXHJcblx0XHRcdGlmICggcGFyZW50ID09PSBudWxsICkge1xyXG5cclxuXHRcdFx0XHRjYW1lcmEubWF0cml4V29ybGQuY29weSggY2FtZXJhLm1hdHJpeCApO1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0Y2FtZXJhLm1hdHJpeFdvcmxkLm11bHRpcGx5TWF0cmljZXMoIHBhcmVudC5tYXRyaXhXb3JsZCwgY2FtZXJhLm1hdHJpeCApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Y2FtZXJhLm1hdHJpeFdvcmxkSW52ZXJzZS5jb3B5KCBjYW1lcmEubWF0cml4V29ybGQgKS5pbnZlcnQoKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy51cGRhdGVDYW1lcmEgPSBmdW5jdGlvbiAoIGNhbWVyYSApIHtcclxuXHJcblx0XHRcdGlmICggc2Vzc2lvbiA9PT0gbnVsbCApIHJldHVybjtcclxuXHJcblx0XHRcdGlmICggZGVwdGhTZW5zaW5nLnRleHR1cmUgIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdGNhbWVyYS5uZWFyID0gZGVwdGhTZW5zaW5nLmRlcHRoTmVhcjtcclxuXHRcdFx0XHRjYW1lcmEuZmFyID0gZGVwdGhTZW5zaW5nLmRlcHRoRmFyO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Y2FtZXJhWFIubmVhciA9IGNhbWVyYVIubmVhciA9IGNhbWVyYUwubmVhciA9IGNhbWVyYS5uZWFyO1xyXG5cdFx0XHRjYW1lcmFYUi5mYXIgPSBjYW1lcmFSLmZhciA9IGNhbWVyYUwuZmFyID0gY2FtZXJhLmZhcjtcclxuXHJcblx0XHRcdGlmICggX2N1cnJlbnREZXB0aE5lYXIgIT09IGNhbWVyYVhSLm5lYXIgfHwgX2N1cnJlbnREZXB0aEZhciAhPT0gY2FtZXJhWFIuZmFyICkge1xyXG5cclxuXHRcdFx0XHQvLyBOb3RlIHRoYXQgdGhlIG5ldyByZW5kZXJTdGF0ZSB3b24ndCBhcHBseSB1bnRpbCB0aGUgbmV4dCBmcmFtZS4gU2VlICMxODMyMFxyXG5cclxuXHRcdFx0XHRzZXNzaW9uLnVwZGF0ZVJlbmRlclN0YXRlKCB7XHJcblx0XHRcdFx0XHRkZXB0aE5lYXI6IGNhbWVyYVhSLm5lYXIsXHJcblx0XHRcdFx0XHRkZXB0aEZhcjogY2FtZXJhWFIuZmFyXHJcblx0XHRcdFx0fSApO1xyXG5cclxuXHRcdFx0XHRfY3VycmVudERlcHRoTmVhciA9IGNhbWVyYVhSLm5lYXI7XHJcblx0XHRcdFx0X2N1cnJlbnREZXB0aEZhciA9IGNhbWVyYVhSLmZhcjtcclxuXHJcblx0XHRcdFx0Y2FtZXJhTC5uZWFyID0gX2N1cnJlbnREZXB0aE5lYXI7XHJcblx0XHRcdFx0Y2FtZXJhTC5mYXIgPSBfY3VycmVudERlcHRoRmFyO1xyXG5cdFx0XHRcdGNhbWVyYVIubmVhciA9IF9jdXJyZW50RGVwdGhOZWFyO1xyXG5cdFx0XHRcdGNhbWVyYVIuZmFyID0gX2N1cnJlbnREZXB0aEZhcjtcclxuXHJcblx0XHRcdFx0Y2FtZXJhTC51cGRhdGVQcm9qZWN0aW9uTWF0cml4KCk7XHJcblx0XHRcdFx0Y2FtZXJhUi51cGRhdGVQcm9qZWN0aW9uTWF0cml4KCk7XHJcblx0XHRcdFx0Y2FtZXJhLnVwZGF0ZVByb2plY3Rpb25NYXRyaXgoKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGNvbnN0IHBhcmVudCA9IGNhbWVyYS5wYXJlbnQ7XHJcblx0XHRcdGNvbnN0IGNhbWVyYXMgPSBjYW1lcmFYUi5jYW1lcmFzO1xyXG5cclxuXHRcdFx0dXBkYXRlQ2FtZXJhKCBjYW1lcmFYUiwgcGFyZW50ICk7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBjYW1lcmFzLmxlbmd0aDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0dXBkYXRlQ2FtZXJhKCBjYW1lcmFzWyBpIF0sIHBhcmVudCApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Ly8gdXBkYXRlIHByb2plY3Rpb24gbWF0cml4IGZvciBwcm9wZXIgdmlldyBmcnVzdHVtIGN1bGxpbmdcclxuXHJcblx0XHRcdGlmICggY2FtZXJhcy5sZW5ndGggPT09IDIgKSB7XHJcblxyXG5cdFx0XHRcdHNldFByb2plY3Rpb25Gcm9tVW5pb24oIGNhbWVyYVhSLCBjYW1lcmFMLCBjYW1lcmFSICk7XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHQvLyBhc3N1bWUgc2luZ2xlIGNhbWVyYSBzZXR1cCAoQVIpXHJcblxyXG5cdFx0XHRcdGNhbWVyYVhSLnByb2plY3Rpb25NYXRyaXguY29weSggY2FtZXJhTC5wcm9qZWN0aW9uTWF0cml4ICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyB1cGRhdGUgdXNlciBjYW1lcmEgYW5kIGl0cyBjaGlsZHJlblxyXG5cclxuXHRcdFx0dXBkYXRlVXNlckNhbWVyYSggY2FtZXJhLCBjYW1lcmFYUiwgcGFyZW50ICk7XHJcblxyXG5cdFx0fTtcclxuXHJcblx0XHRmdW5jdGlvbiB1cGRhdGVVc2VyQ2FtZXJhKCBjYW1lcmEsIGNhbWVyYVhSLCBwYXJlbnQgKSB7XHJcblxyXG5cdFx0XHRpZiAoIHBhcmVudCA9PT0gbnVsbCApIHtcclxuXHJcblx0XHRcdFx0Y2FtZXJhLm1hdHJpeC5jb3B5KCBjYW1lcmFYUi5tYXRyaXhXb3JsZCApO1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0Y2FtZXJhLm1hdHJpeC5jb3B5KCBwYXJlbnQubWF0cml4V29ybGQgKTtcclxuXHRcdFx0XHRjYW1lcmEubWF0cml4LmludmVydCgpO1xyXG5cdFx0XHRcdGNhbWVyYS5tYXRyaXgubXVsdGlwbHkoIGNhbWVyYVhSLm1hdHJpeFdvcmxkICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRjYW1lcmEubWF0cml4LmRlY29tcG9zZSggY2FtZXJhLnBvc2l0aW9uLCBjYW1lcmEucXVhdGVybmlvbiwgY2FtZXJhLnNjYWxlICk7XHJcblx0XHRcdGNhbWVyYS51cGRhdGVNYXRyaXhXb3JsZCggdHJ1ZSApO1xyXG5cclxuXHRcdFx0Y2FtZXJhLnByb2plY3Rpb25NYXRyaXguY29weSggY2FtZXJhWFIucHJvamVjdGlvbk1hdHJpeCApO1xyXG5cdFx0XHRjYW1lcmEucHJvamVjdGlvbk1hdHJpeEludmVyc2UuY29weSggY2FtZXJhWFIucHJvamVjdGlvbk1hdHJpeEludmVyc2UgKTtcclxuXHJcblx0XHRcdGlmICggY2FtZXJhLmlzUGVyc3BlY3RpdmVDYW1lcmEgKSB7XHJcblxyXG5cdFx0XHRcdGNhbWVyYS5mb3YgPSBSQUQyREVHICogMiAqIE1hdGguYXRhbiggMSAvIGNhbWVyYS5wcm9qZWN0aW9uTWF0cml4LmVsZW1lbnRzWyA1IF0gKTtcclxuXHRcdFx0XHRjYW1lcmEuem9vbSA9IDE7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMuZ2V0Q2FtZXJhID0gZnVuY3Rpb24gKCkge1xyXG5cclxuXHRcdFx0cmV0dXJuIGNhbWVyYVhSO1xyXG5cclxuXHRcdH07XHJcblxyXG5cdFx0dGhpcy5nZXRGb3ZlYXRpb24gPSBmdW5jdGlvbiAoKSB7XHJcblxyXG5cdFx0XHRpZiAoIGdsUHJvakxheWVyID09PSBudWxsICYmIGdsQmFzZUxheWVyID09PSBudWxsICkge1xyXG5cclxuXHRcdFx0XHRyZXR1cm4gdW5kZWZpbmVkO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0cmV0dXJuIGZvdmVhdGlvbjtcclxuXHJcblx0XHR9O1xyXG5cclxuXHRcdHRoaXMuc2V0Rm92ZWF0aW9uID0gZnVuY3Rpb24gKCB2YWx1ZSApIHtcclxuXHJcblx0XHRcdC8vIDAgPSBubyBmb3ZlYXRpb24gPSBmdWxsIHJlc29sdXRpb25cclxuXHRcdFx0Ly8gMSA9IG1heGltdW0gZm92ZWF0aW9uID0gdGhlIGVkZ2VzIHJlbmRlciBhdCBsb3dlciByZXNvbHV0aW9uXHJcblxyXG5cdFx0XHRmb3ZlYXRpb24gPSB2YWx1ZTtcclxuXHJcblx0XHRcdGlmICggZ2xQcm9qTGF5ZXIgIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdGdsUHJvakxheWVyLmZpeGVkRm92ZWF0aW9uID0gdmFsdWU7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRpZiAoIGdsQmFzZUxheWVyICE9PSBudWxsICYmIGdsQmFzZUxheWVyLmZpeGVkRm92ZWF0aW9uICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRcdGdsQmFzZUxheWVyLmZpeGVkRm92ZWF0aW9uID0gdmFsdWU7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fTtcclxuXHJcblx0XHR0aGlzLmhhc0RlcHRoU2Vuc2luZyA9IGZ1bmN0aW9uICgpIHtcclxuXHJcblx0XHRcdHJldHVybiBkZXB0aFNlbnNpbmcudGV4dHVyZSAhPT0gbnVsbDtcclxuXHJcblx0XHR9O1xyXG5cclxuXHRcdC8vIEFuaW1hdGlvbiBMb29wXHJcblxyXG5cdFx0bGV0IG9uQW5pbWF0aW9uRnJhbWVDYWxsYmFjayA9IG51bGw7XHJcblxyXG5cdFx0ZnVuY3Rpb24gb25BbmltYXRpb25GcmFtZSggdGltZSwgZnJhbWUgKSB7XHJcblxyXG5cdFx0XHRwb3NlID0gZnJhbWUuZ2V0Vmlld2VyUG9zZSggY3VzdG9tUmVmZXJlbmNlU3BhY2UgfHwgcmVmZXJlbmNlU3BhY2UgKTtcclxuXHRcdFx0eHJGcmFtZSA9IGZyYW1lO1xyXG5cclxuXHRcdFx0aWYgKCBwb3NlICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCB2aWV3cyA9IHBvc2Uudmlld3M7XHJcblxyXG5cdFx0XHRcdGlmICggZ2xCYXNlTGF5ZXIgIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdFx0cmVuZGVyZXIuc2V0UmVuZGVyVGFyZ2V0RnJhbWVidWZmZXIoIG5ld1JlbmRlclRhcmdldCwgZ2xCYXNlTGF5ZXIuZnJhbWVidWZmZXIgKTtcclxuXHRcdFx0XHRcdHJlbmRlcmVyLnNldFJlbmRlclRhcmdldCggbmV3UmVuZGVyVGFyZ2V0ICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0bGV0IGNhbWVyYVhSTmVlZHNVcGRhdGUgPSBmYWxzZTtcclxuXHJcblx0XHRcdFx0Ly8gY2hlY2sgaWYgaXQncyBuZWNlc3NhcnkgdG8gcmVidWlsZCBjYW1lcmFYUidzIGNhbWVyYSBsaXN0XHJcblxyXG5cdFx0XHRcdGlmICggdmlld3MubGVuZ3RoICE9PSBjYW1lcmFYUi5jYW1lcmFzLmxlbmd0aCApIHtcclxuXHJcblx0XHRcdFx0XHRjYW1lcmFYUi5jYW1lcmFzLmxlbmd0aCA9IDA7XHJcblx0XHRcdFx0XHRjYW1lcmFYUk5lZWRzVXBkYXRlID0gdHJ1ZTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCB2aWV3cy5sZW5ndGg7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgdmlldyA9IHZpZXdzWyBpIF07XHJcblxyXG5cdFx0XHRcdFx0bGV0IHZpZXdwb3J0ID0gbnVsbDtcclxuXHJcblx0XHRcdFx0XHRpZiAoIGdsQmFzZUxheWVyICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0XHRcdFx0dmlld3BvcnQgPSBnbEJhc2VMYXllci5nZXRWaWV3cG9ydCggdmlldyApO1xyXG5cclxuXHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHRjb25zdCBnbFN1YkltYWdlID0gZ2xCaW5kaW5nLmdldFZpZXdTdWJJbWFnZSggZ2xQcm9qTGF5ZXIsIHZpZXcgKTtcclxuXHRcdFx0XHRcdFx0dmlld3BvcnQgPSBnbFN1YkltYWdlLnZpZXdwb3J0O1xyXG5cclxuXHRcdFx0XHRcdFx0Ly8gRm9yIHNpZGUtYnktc2lkZSBwcm9qZWN0aW9uLCB3ZSBvbmx5IHByb2R1Y2UgYSBzaW5nbGUgdGV4dHVyZSBmb3IgYm90aCBleWVzLlxyXG5cdFx0XHRcdFx0XHRpZiAoIGkgPT09IDAgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdHJlbmRlcmVyLnNldFJlbmRlclRhcmdldFRleHR1cmVzKFxyXG5cdFx0XHRcdFx0XHRcdFx0bmV3UmVuZGVyVGFyZ2V0LFxyXG5cdFx0XHRcdFx0XHRcdFx0Z2xTdWJJbWFnZS5jb2xvclRleHR1cmUsXHJcblx0XHRcdFx0XHRcdFx0XHRnbFByb2pMYXllci5pZ25vcmVEZXB0aFZhbHVlcyA/IHVuZGVmaW5lZCA6IGdsU3ViSW1hZ2UuZGVwdGhTdGVuY2lsVGV4dHVyZSApO1xyXG5cclxuXHRcdFx0XHRcdFx0XHRyZW5kZXJlci5zZXRSZW5kZXJUYXJnZXQoIG5ld1JlbmRlclRhcmdldCApO1xyXG5cclxuXHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRsZXQgY2FtZXJhID0gY2FtZXJhc1sgaSBdO1xyXG5cclxuXHRcdFx0XHRcdGlmICggY2FtZXJhID09PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRjYW1lcmEgPSBuZXcgUGVyc3BlY3RpdmVDYW1lcmEoKTtcclxuXHRcdFx0XHRcdFx0Y2FtZXJhLmxheWVycy5lbmFibGUoIGkgKTtcclxuXHRcdFx0XHRcdFx0Y2FtZXJhLnZpZXdwb3J0ID0gbmV3IFZlY3RvcjQoKTtcclxuXHRcdFx0XHRcdFx0Y2FtZXJhc1sgaSBdID0gY2FtZXJhO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRjYW1lcmEubWF0cml4LmZyb21BcnJheSggdmlldy50cmFuc2Zvcm0ubWF0cml4ICk7XHJcblx0XHRcdFx0XHRjYW1lcmEubWF0cml4LmRlY29tcG9zZSggY2FtZXJhLnBvc2l0aW9uLCBjYW1lcmEucXVhdGVybmlvbiwgY2FtZXJhLnNjYWxlICk7XHJcblx0XHRcdFx0XHRjYW1lcmEucHJvamVjdGlvbk1hdHJpeC5mcm9tQXJyYXkoIHZpZXcucHJvamVjdGlvbk1hdHJpeCApO1xyXG5cdFx0XHRcdFx0Y2FtZXJhLnByb2plY3Rpb25NYXRyaXhJbnZlcnNlLmNvcHkoIGNhbWVyYS5wcm9qZWN0aW9uTWF0cml4ICkuaW52ZXJ0KCk7XHJcblx0XHRcdFx0XHRjYW1lcmEudmlld3BvcnQuc2V0KCB2aWV3cG9ydC54LCB2aWV3cG9ydC55LCB2aWV3cG9ydC53aWR0aCwgdmlld3BvcnQuaGVpZ2h0ICk7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCBpID09PSAwICkge1xyXG5cclxuXHRcdFx0XHRcdFx0Y2FtZXJhWFIubWF0cml4LmNvcHkoIGNhbWVyYS5tYXRyaXggKTtcclxuXHRcdFx0XHRcdFx0Y2FtZXJhWFIubWF0cml4LmRlY29tcG9zZSggY2FtZXJhWFIucG9zaXRpb24sIGNhbWVyYVhSLnF1YXRlcm5pb24sIGNhbWVyYVhSLnNjYWxlICk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdGlmICggY2FtZXJhWFJOZWVkc1VwZGF0ZSA9PT0gdHJ1ZSApIHtcclxuXHJcblx0XHRcdFx0XHRcdGNhbWVyYVhSLmNhbWVyYXMucHVzaCggY2FtZXJhICk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdC8vXHJcblxyXG5cdFx0XHRcdGNvbnN0IGVuYWJsZWRGZWF0dXJlcyA9IHNlc3Npb24uZW5hYmxlZEZlYXR1cmVzO1xyXG5cclxuXHRcdFx0XHRpZiAoIGVuYWJsZWRGZWF0dXJlcyAmJiBlbmFibGVkRmVhdHVyZXMuaW5jbHVkZXMoICdkZXB0aC1zZW5zaW5nJyApICkge1xyXG5cclxuXHRcdFx0XHRcdGNvbnN0IGRlcHRoRGF0YSA9IGdsQmluZGluZy5nZXREZXB0aEluZm9ybWF0aW9uKCB2aWV3c1sgMCBdICk7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCBkZXB0aERhdGEgJiYgZGVwdGhEYXRhLmlzVmFsaWQgJiYgZGVwdGhEYXRhLnRleHR1cmUgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRkZXB0aFNlbnNpbmcuaW5pdCggcmVuZGVyZXIsIGRlcHRoRGF0YSwgc2Vzc2lvbi5yZW5kZXJTdGF0ZSApO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Ly9cclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IGNvbnRyb2xsZXJzLmxlbmd0aDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgaW5wdXRTb3VyY2UgPSBjb250cm9sbGVySW5wdXRTb3VyY2VzWyBpIF07XHJcblx0XHRcdFx0Y29uc3QgY29udHJvbGxlciA9IGNvbnRyb2xsZXJzWyBpIF07XHJcblxyXG5cdFx0XHRcdGlmICggaW5wdXRTb3VyY2UgIT09IG51bGwgJiYgY29udHJvbGxlciAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHRcdGNvbnRyb2xsZXIudXBkYXRlKCBpbnB1dFNvdXJjZSwgZnJhbWUsIGN1c3RvbVJlZmVyZW5jZVNwYWNlIHx8IHJlZmVyZW5jZVNwYWNlICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGRlcHRoU2Vuc2luZy5yZW5kZXIoIHJlbmRlcmVyLCBjYW1lcmFYUiApO1xyXG5cclxuXHRcdFx0aWYgKCBvbkFuaW1hdGlvbkZyYW1lQ2FsbGJhY2sgKSBvbkFuaW1hdGlvbkZyYW1lQ2FsbGJhY2soIHRpbWUsIGZyYW1lICk7XHJcblxyXG5cdFx0XHRpZiAoIGZyYW1lLmRldGVjdGVkUGxhbmVzICkge1xyXG5cclxuXHRcdFx0XHRzY29wZS5kaXNwYXRjaEV2ZW50KCB7IHR5cGU6ICdwbGFuZXNkZXRlY3RlZCcsIGRhdGE6IGZyYW1lIH0gKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHhyRnJhbWUgPSBudWxsO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCBhbmltYXRpb24gPSBuZXcgV2ViR0xBbmltYXRpb24oKTtcclxuXHJcblx0XHRhbmltYXRpb24uc2V0QW5pbWF0aW9uTG9vcCggb25BbmltYXRpb25GcmFtZSApO1xyXG5cclxuXHRcdHRoaXMuc2V0QW5pbWF0aW9uTG9vcCA9IGZ1bmN0aW9uICggY2FsbGJhY2sgKSB7XHJcblxyXG5cdFx0XHRvbkFuaW1hdGlvbkZyYW1lQ2FsbGJhY2sgPSBjYWxsYmFjaztcclxuXHJcblx0XHR9O1xyXG5cclxuXHRcdHRoaXMuZGlzcG9zZSA9IGZ1bmN0aW9uICgpIHt9O1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBXZWJYUk1hbmFnZXIgfTtcclxuIiwiaW1wb3J0IHsgQmFja1NpZGUgfSBmcm9tICcuLi8uLi9jb25zdGFudHMuanMnO1xyXG5pbXBvcnQgeyBnZXRVbmxpdFVuaWZvcm1Db2xvclNwYWNlIH0gZnJvbSAnLi4vc2hhZGVycy9Vbmlmb3Jtc1V0aWxzLmpzJztcclxuXHJcbmZ1bmN0aW9uIFdlYkdMTWF0ZXJpYWxzKCByZW5kZXJlciwgcHJvcGVydGllcyApIHtcclxuXHJcblx0ZnVuY3Rpb24gcmVmcmVzaFRyYW5zZm9ybVVuaWZvcm0oIG1hcCwgdW5pZm9ybSApIHtcclxuXHJcblx0XHRpZiAoIG1hcC5tYXRyaXhBdXRvVXBkYXRlID09PSB0cnVlICkge1xyXG5cclxuXHRcdFx0bWFwLnVwZGF0ZU1hdHJpeCgpO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHR1bmlmb3JtLnZhbHVlLmNvcHkoIG1hcC5tYXRyaXggKTtcclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiByZWZyZXNoRm9nVW5pZm9ybXMoIHVuaWZvcm1zLCBmb2cgKSB7XHJcblxyXG5cdFx0Zm9nLmNvbG9yLmdldFJHQiggdW5pZm9ybXMuZm9nQ29sb3IudmFsdWUsIGdldFVubGl0VW5pZm9ybUNvbG9yU3BhY2UoIHJlbmRlcmVyICkgKTtcclxuXHJcblx0XHRpZiAoIGZvZy5pc0ZvZyApIHtcclxuXHJcblx0XHRcdHVuaWZvcm1zLmZvZ05lYXIudmFsdWUgPSBmb2cubmVhcjtcclxuXHRcdFx0dW5pZm9ybXMuZm9nRmFyLnZhbHVlID0gZm9nLmZhcjtcclxuXHJcblx0XHR9IGVsc2UgaWYgKCBmb2cuaXNGb2dFeHAyICkge1xyXG5cclxuXHRcdFx0dW5pZm9ybXMuZm9nRGVuc2l0eS52YWx1ZSA9IGZvZy5kZW5zaXR5O1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiByZWZyZXNoTWF0ZXJpYWxVbmlmb3JtcyggdW5pZm9ybXMsIG1hdGVyaWFsLCBwaXhlbFJhdGlvLCBoZWlnaHQsIHRyYW5zbWlzc2lvblJlbmRlclRhcmdldCApIHtcclxuXHJcblx0XHRpZiAoIG1hdGVyaWFsLmlzTWVzaEJhc2ljTWF0ZXJpYWwgKSB7XHJcblxyXG5cdFx0XHRyZWZyZXNoVW5pZm9ybXNDb21tb24oIHVuaWZvcm1zLCBtYXRlcmlhbCApO1xyXG5cclxuXHRcdH0gZWxzZSBpZiAoIG1hdGVyaWFsLmlzTWVzaExhbWJlcnRNYXRlcmlhbCApIHtcclxuXHJcblx0XHRcdHJlZnJlc2hVbmlmb3Jtc0NvbW1vbiggdW5pZm9ybXMsIG1hdGVyaWFsICk7XHJcblxyXG5cdFx0fSBlbHNlIGlmICggbWF0ZXJpYWwuaXNNZXNoVG9vbk1hdGVyaWFsICkge1xyXG5cclxuXHRcdFx0cmVmcmVzaFVuaWZvcm1zQ29tbW9uKCB1bmlmb3JtcywgbWF0ZXJpYWwgKTtcclxuXHRcdFx0cmVmcmVzaFVuaWZvcm1zVG9vbiggdW5pZm9ybXMsIG1hdGVyaWFsICk7XHJcblxyXG5cdFx0fSBlbHNlIGlmICggbWF0ZXJpYWwuaXNNZXNoUGhvbmdNYXRlcmlhbCApIHtcclxuXHJcblx0XHRcdHJlZnJlc2hVbmlmb3Jtc0NvbW1vbiggdW5pZm9ybXMsIG1hdGVyaWFsICk7XHJcblx0XHRcdHJlZnJlc2hVbmlmb3Jtc1Bob25nKCB1bmlmb3JtcywgbWF0ZXJpYWwgKTtcclxuXHJcblx0XHR9IGVsc2UgaWYgKCBtYXRlcmlhbC5pc01lc2hTdGFuZGFyZE1hdGVyaWFsICkge1xyXG5cclxuXHRcdFx0cmVmcmVzaFVuaWZvcm1zQ29tbW9uKCB1bmlmb3JtcywgbWF0ZXJpYWwgKTtcclxuXHRcdFx0cmVmcmVzaFVuaWZvcm1zU3RhbmRhcmQoIHVuaWZvcm1zLCBtYXRlcmlhbCApO1xyXG5cclxuXHRcdFx0aWYgKCBtYXRlcmlhbC5pc01lc2hQaHlzaWNhbE1hdGVyaWFsICkge1xyXG5cclxuXHRcdFx0XHRyZWZyZXNoVW5pZm9ybXNQaHlzaWNhbCggdW5pZm9ybXMsIG1hdGVyaWFsLCB0cmFuc21pc3Npb25SZW5kZXJUYXJnZXQgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9IGVsc2UgaWYgKCBtYXRlcmlhbC5pc01lc2hNYXRjYXBNYXRlcmlhbCApIHtcclxuXHJcblx0XHRcdHJlZnJlc2hVbmlmb3Jtc0NvbW1vbiggdW5pZm9ybXMsIG1hdGVyaWFsICk7XHJcblx0XHRcdHJlZnJlc2hVbmlmb3Jtc01hdGNhcCggdW5pZm9ybXMsIG1hdGVyaWFsICk7XHJcblxyXG5cdFx0fSBlbHNlIGlmICggbWF0ZXJpYWwuaXNNZXNoRGVwdGhNYXRlcmlhbCApIHtcclxuXHJcblx0XHRcdHJlZnJlc2hVbmlmb3Jtc0NvbW1vbiggdW5pZm9ybXMsIG1hdGVyaWFsICk7XHJcblxyXG5cdFx0fSBlbHNlIGlmICggbWF0ZXJpYWwuaXNNZXNoRGlzdGFuY2VNYXRlcmlhbCApIHtcclxuXHJcblx0XHRcdHJlZnJlc2hVbmlmb3Jtc0NvbW1vbiggdW5pZm9ybXMsIG1hdGVyaWFsICk7XHJcblx0XHRcdHJlZnJlc2hVbmlmb3Jtc0Rpc3RhbmNlKCB1bmlmb3JtcywgbWF0ZXJpYWwgKTtcclxuXHJcblx0XHR9IGVsc2UgaWYgKCBtYXRlcmlhbC5pc01lc2hOb3JtYWxNYXRlcmlhbCApIHtcclxuXHJcblx0XHRcdHJlZnJlc2hVbmlmb3Jtc0NvbW1vbiggdW5pZm9ybXMsIG1hdGVyaWFsICk7XHJcblxyXG5cdFx0fSBlbHNlIGlmICggbWF0ZXJpYWwuaXNMaW5lQmFzaWNNYXRlcmlhbCApIHtcclxuXHJcblx0XHRcdHJlZnJlc2hVbmlmb3Jtc0xpbmUoIHVuaWZvcm1zLCBtYXRlcmlhbCApO1xyXG5cclxuXHRcdFx0aWYgKCBtYXRlcmlhbC5pc0xpbmVEYXNoZWRNYXRlcmlhbCApIHtcclxuXHJcblx0XHRcdFx0cmVmcmVzaFVuaWZvcm1zRGFzaCggdW5pZm9ybXMsIG1hdGVyaWFsICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fSBlbHNlIGlmICggbWF0ZXJpYWwuaXNQb2ludHNNYXRlcmlhbCApIHtcclxuXHJcblx0XHRcdHJlZnJlc2hVbmlmb3Jtc1BvaW50cyggdW5pZm9ybXMsIG1hdGVyaWFsLCBwaXhlbFJhdGlvLCBoZWlnaHQgKTtcclxuXHJcblx0XHR9IGVsc2UgaWYgKCBtYXRlcmlhbC5pc1Nwcml0ZU1hdGVyaWFsICkge1xyXG5cclxuXHRcdFx0cmVmcmVzaFVuaWZvcm1zU3ByaXRlcyggdW5pZm9ybXMsIG1hdGVyaWFsICk7XHJcblxyXG5cdFx0fSBlbHNlIGlmICggbWF0ZXJpYWwuaXNTaGFkb3dNYXRlcmlhbCApIHtcclxuXHJcblx0XHRcdHVuaWZvcm1zLmNvbG9yLnZhbHVlLmNvcHkoIG1hdGVyaWFsLmNvbG9yICk7XHJcblx0XHRcdHVuaWZvcm1zLm9wYWNpdHkudmFsdWUgPSBtYXRlcmlhbC5vcGFjaXR5O1xyXG5cclxuXHRcdH0gZWxzZSBpZiAoIG1hdGVyaWFsLmlzU2hhZGVyTWF0ZXJpYWwgKSB7XHJcblxyXG5cdFx0XHRtYXRlcmlhbC51bmlmb3Jtc05lZWRVcGRhdGUgPSBmYWxzZTsgLy8gIzE1NTgxXHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHJlZnJlc2hVbmlmb3Jtc0NvbW1vbiggdW5pZm9ybXMsIG1hdGVyaWFsICkge1xyXG5cclxuXHRcdHVuaWZvcm1zLm9wYWNpdHkudmFsdWUgPSBtYXRlcmlhbC5vcGFjaXR5O1xyXG5cclxuXHRcdGlmICggbWF0ZXJpYWwuY29sb3IgKSB7XHJcblxyXG5cdFx0XHR1bmlmb3Jtcy5kaWZmdXNlLnZhbHVlLmNvcHkoIG1hdGVyaWFsLmNvbG9yICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggbWF0ZXJpYWwuZW1pc3NpdmUgKSB7XHJcblxyXG5cdFx0XHR1bmlmb3Jtcy5lbWlzc2l2ZS52YWx1ZS5jb3B5KCBtYXRlcmlhbC5lbWlzc2l2ZSApLm11bHRpcGx5U2NhbGFyKCBtYXRlcmlhbC5lbWlzc2l2ZUludGVuc2l0eSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIG1hdGVyaWFsLm1hcCApIHtcclxuXHJcblx0XHRcdHVuaWZvcm1zLm1hcC52YWx1ZSA9IG1hdGVyaWFsLm1hcDtcclxuXHJcblx0XHRcdHJlZnJlc2hUcmFuc2Zvcm1Vbmlmb3JtKCBtYXRlcmlhbC5tYXAsIHVuaWZvcm1zLm1hcFRyYW5zZm9ybSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIG1hdGVyaWFsLmFscGhhTWFwICkge1xyXG5cclxuXHRcdFx0dW5pZm9ybXMuYWxwaGFNYXAudmFsdWUgPSBtYXRlcmlhbC5hbHBoYU1hcDtcclxuXHJcblx0XHRcdHJlZnJlc2hUcmFuc2Zvcm1Vbmlmb3JtKCBtYXRlcmlhbC5hbHBoYU1hcCwgdW5pZm9ybXMuYWxwaGFNYXBUcmFuc2Zvcm0gKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBtYXRlcmlhbC5idW1wTWFwICkge1xyXG5cclxuXHRcdFx0dW5pZm9ybXMuYnVtcE1hcC52YWx1ZSA9IG1hdGVyaWFsLmJ1bXBNYXA7XHJcblxyXG5cdFx0XHRyZWZyZXNoVHJhbnNmb3JtVW5pZm9ybSggbWF0ZXJpYWwuYnVtcE1hcCwgdW5pZm9ybXMuYnVtcE1hcFRyYW5zZm9ybSApO1xyXG5cclxuXHRcdFx0dW5pZm9ybXMuYnVtcFNjYWxlLnZhbHVlID0gbWF0ZXJpYWwuYnVtcFNjYWxlO1xyXG5cclxuXHRcdFx0aWYgKCBtYXRlcmlhbC5zaWRlID09PSBCYWNrU2lkZSApIHtcclxuXHJcblx0XHRcdFx0dW5pZm9ybXMuYnVtcFNjYWxlLnZhbHVlICo9IC0gMTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBtYXRlcmlhbC5ub3JtYWxNYXAgKSB7XHJcblxyXG5cdFx0XHR1bmlmb3Jtcy5ub3JtYWxNYXAudmFsdWUgPSBtYXRlcmlhbC5ub3JtYWxNYXA7XHJcblxyXG5cdFx0XHRyZWZyZXNoVHJhbnNmb3JtVW5pZm9ybSggbWF0ZXJpYWwubm9ybWFsTWFwLCB1bmlmb3Jtcy5ub3JtYWxNYXBUcmFuc2Zvcm0gKTtcclxuXHJcblx0XHRcdHVuaWZvcm1zLm5vcm1hbFNjYWxlLnZhbHVlLmNvcHkoIG1hdGVyaWFsLm5vcm1hbFNjYWxlICk7XHJcblxyXG5cdFx0XHRpZiAoIG1hdGVyaWFsLnNpZGUgPT09IEJhY2tTaWRlICkge1xyXG5cclxuXHRcdFx0XHR1bmlmb3Jtcy5ub3JtYWxTY2FsZS52YWx1ZS5uZWdhdGUoKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBtYXRlcmlhbC5kaXNwbGFjZW1lbnRNYXAgKSB7XHJcblxyXG5cdFx0XHR1bmlmb3Jtcy5kaXNwbGFjZW1lbnRNYXAudmFsdWUgPSBtYXRlcmlhbC5kaXNwbGFjZW1lbnRNYXA7XHJcblxyXG5cdFx0XHRyZWZyZXNoVHJhbnNmb3JtVW5pZm9ybSggbWF0ZXJpYWwuZGlzcGxhY2VtZW50TWFwLCB1bmlmb3Jtcy5kaXNwbGFjZW1lbnRNYXBUcmFuc2Zvcm0gKTtcclxuXHJcblx0XHRcdHVuaWZvcm1zLmRpc3BsYWNlbWVudFNjYWxlLnZhbHVlID0gbWF0ZXJpYWwuZGlzcGxhY2VtZW50U2NhbGU7XHJcblx0XHRcdHVuaWZvcm1zLmRpc3BsYWNlbWVudEJpYXMudmFsdWUgPSBtYXRlcmlhbC5kaXNwbGFjZW1lbnRCaWFzO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIG1hdGVyaWFsLmVtaXNzaXZlTWFwICkge1xyXG5cclxuXHRcdFx0dW5pZm9ybXMuZW1pc3NpdmVNYXAudmFsdWUgPSBtYXRlcmlhbC5lbWlzc2l2ZU1hcDtcclxuXHJcblx0XHRcdHJlZnJlc2hUcmFuc2Zvcm1Vbmlmb3JtKCBtYXRlcmlhbC5lbWlzc2l2ZU1hcCwgdW5pZm9ybXMuZW1pc3NpdmVNYXBUcmFuc2Zvcm0gKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBtYXRlcmlhbC5zcGVjdWxhck1hcCApIHtcclxuXHJcblx0XHRcdHVuaWZvcm1zLnNwZWN1bGFyTWFwLnZhbHVlID0gbWF0ZXJpYWwuc3BlY3VsYXJNYXA7XHJcblxyXG5cdFx0XHRyZWZyZXNoVHJhbnNmb3JtVW5pZm9ybSggbWF0ZXJpYWwuc3BlY3VsYXJNYXAsIHVuaWZvcm1zLnNwZWN1bGFyTWFwVHJhbnNmb3JtICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggbWF0ZXJpYWwuYWxwaGFUZXN0ID4gMCApIHtcclxuXHJcblx0XHRcdHVuaWZvcm1zLmFscGhhVGVzdC52YWx1ZSA9IG1hdGVyaWFsLmFscGhhVGVzdDtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Y29uc3QgZW52TWFwID0gcHJvcGVydGllcy5nZXQoIG1hdGVyaWFsICkuZW52TWFwO1xyXG5cclxuXHRcdGlmICggZW52TWFwICkge1xyXG5cclxuXHRcdFx0dW5pZm9ybXMuZW52TWFwLnZhbHVlID0gZW52TWFwO1xyXG5cclxuXHRcdFx0dW5pZm9ybXMuZmxpcEVudk1hcC52YWx1ZSA9ICggZW52TWFwLmlzQ3ViZVRleHR1cmUgJiYgZW52TWFwLmlzUmVuZGVyVGFyZ2V0VGV4dHVyZSA9PT0gZmFsc2UgKSA/IC0gMSA6IDE7XHJcblxyXG5cdFx0XHR1bmlmb3Jtcy5yZWZsZWN0aXZpdHkudmFsdWUgPSBtYXRlcmlhbC5yZWZsZWN0aXZpdHk7XHJcblx0XHRcdHVuaWZvcm1zLmlvci52YWx1ZSA9IG1hdGVyaWFsLmlvcjtcclxuXHRcdFx0dW5pZm9ybXMucmVmcmFjdGlvblJhdGlvLnZhbHVlID0gbWF0ZXJpYWwucmVmcmFjdGlvblJhdGlvO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIG1hdGVyaWFsLmxpZ2h0TWFwICkge1xyXG5cclxuXHRcdFx0dW5pZm9ybXMubGlnaHRNYXAudmFsdWUgPSBtYXRlcmlhbC5saWdodE1hcDtcclxuXHJcblx0XHRcdC8vIGFydGlzdC1mcmllbmRseSBsaWdodCBpbnRlbnNpdHkgc2NhbGluZyBmYWN0b3JcclxuXHRcdFx0Y29uc3Qgc2NhbGVGYWN0b3IgPSAoIHJlbmRlcmVyLl91c2VMZWdhY3lMaWdodHMgPT09IHRydWUgKSA/IE1hdGguUEkgOiAxO1xyXG5cclxuXHRcdFx0dW5pZm9ybXMubGlnaHRNYXBJbnRlbnNpdHkudmFsdWUgPSBtYXRlcmlhbC5saWdodE1hcEludGVuc2l0eSAqIHNjYWxlRmFjdG9yO1xyXG5cclxuXHRcdFx0cmVmcmVzaFRyYW5zZm9ybVVuaWZvcm0oIG1hdGVyaWFsLmxpZ2h0TWFwLCB1bmlmb3Jtcy5saWdodE1hcFRyYW5zZm9ybSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIG1hdGVyaWFsLmFvTWFwICkge1xyXG5cclxuXHRcdFx0dW5pZm9ybXMuYW9NYXAudmFsdWUgPSBtYXRlcmlhbC5hb01hcDtcclxuXHRcdFx0dW5pZm9ybXMuYW9NYXBJbnRlbnNpdHkudmFsdWUgPSBtYXRlcmlhbC5hb01hcEludGVuc2l0eTtcclxuXHJcblx0XHRcdHJlZnJlc2hUcmFuc2Zvcm1Vbmlmb3JtKCBtYXRlcmlhbC5hb01hcCwgdW5pZm9ybXMuYW9NYXBUcmFuc2Zvcm0gKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gcmVmcmVzaFVuaWZvcm1zTGluZSggdW5pZm9ybXMsIG1hdGVyaWFsICkge1xyXG5cclxuXHRcdHVuaWZvcm1zLmRpZmZ1c2UudmFsdWUuY29weSggbWF0ZXJpYWwuY29sb3IgKTtcclxuXHRcdHVuaWZvcm1zLm9wYWNpdHkudmFsdWUgPSBtYXRlcmlhbC5vcGFjaXR5O1xyXG5cclxuXHRcdGlmICggbWF0ZXJpYWwubWFwICkge1xyXG5cclxuXHRcdFx0dW5pZm9ybXMubWFwLnZhbHVlID0gbWF0ZXJpYWwubWFwO1xyXG5cclxuXHRcdFx0cmVmcmVzaFRyYW5zZm9ybVVuaWZvcm0oIG1hdGVyaWFsLm1hcCwgdW5pZm9ybXMubWFwVHJhbnNmb3JtICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHJlZnJlc2hVbmlmb3Jtc0Rhc2goIHVuaWZvcm1zLCBtYXRlcmlhbCApIHtcclxuXHJcblx0XHR1bmlmb3Jtcy5kYXNoU2l6ZS52YWx1ZSA9IG1hdGVyaWFsLmRhc2hTaXplO1xyXG5cdFx0dW5pZm9ybXMudG90YWxTaXplLnZhbHVlID0gbWF0ZXJpYWwuZGFzaFNpemUgKyBtYXRlcmlhbC5nYXBTaXplO1xyXG5cdFx0dW5pZm9ybXMuc2NhbGUudmFsdWUgPSBtYXRlcmlhbC5zY2FsZTtcclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiByZWZyZXNoVW5pZm9ybXNQb2ludHMoIHVuaWZvcm1zLCBtYXRlcmlhbCwgcGl4ZWxSYXRpbywgaGVpZ2h0ICkge1xyXG5cclxuXHRcdHVuaWZvcm1zLmRpZmZ1c2UudmFsdWUuY29weSggbWF0ZXJpYWwuY29sb3IgKTtcclxuXHRcdHVuaWZvcm1zLm9wYWNpdHkudmFsdWUgPSBtYXRlcmlhbC5vcGFjaXR5O1xyXG5cdFx0dW5pZm9ybXMuc2l6ZS52YWx1ZSA9IG1hdGVyaWFsLnNpemUgKiBwaXhlbFJhdGlvO1xyXG5cdFx0dW5pZm9ybXMuc2NhbGUudmFsdWUgPSBoZWlnaHQgKiAwLjU7XHJcblxyXG5cdFx0aWYgKCBtYXRlcmlhbC5tYXAgKSB7XHJcblxyXG5cdFx0XHR1bmlmb3Jtcy5tYXAudmFsdWUgPSBtYXRlcmlhbC5tYXA7XHJcblxyXG5cdFx0XHRyZWZyZXNoVHJhbnNmb3JtVW5pZm9ybSggbWF0ZXJpYWwubWFwLCB1bmlmb3Jtcy51dlRyYW5zZm9ybSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIG1hdGVyaWFsLmFscGhhTWFwICkge1xyXG5cclxuXHRcdFx0dW5pZm9ybXMuYWxwaGFNYXAudmFsdWUgPSBtYXRlcmlhbC5hbHBoYU1hcDtcclxuXHJcblx0XHRcdHJlZnJlc2hUcmFuc2Zvcm1Vbmlmb3JtKCBtYXRlcmlhbC5hbHBoYU1hcCwgdW5pZm9ybXMuYWxwaGFNYXBUcmFuc2Zvcm0gKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBtYXRlcmlhbC5hbHBoYVRlc3QgPiAwICkge1xyXG5cclxuXHRcdFx0dW5pZm9ybXMuYWxwaGFUZXN0LnZhbHVlID0gbWF0ZXJpYWwuYWxwaGFUZXN0O1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiByZWZyZXNoVW5pZm9ybXNTcHJpdGVzKCB1bmlmb3JtcywgbWF0ZXJpYWwgKSB7XHJcblxyXG5cdFx0dW5pZm9ybXMuZGlmZnVzZS52YWx1ZS5jb3B5KCBtYXRlcmlhbC5jb2xvciApO1xyXG5cdFx0dW5pZm9ybXMub3BhY2l0eS52YWx1ZSA9IG1hdGVyaWFsLm9wYWNpdHk7XHJcblx0XHR1bmlmb3Jtcy5yb3RhdGlvbi52YWx1ZSA9IG1hdGVyaWFsLnJvdGF0aW9uO1xyXG5cclxuXHRcdGlmICggbWF0ZXJpYWwubWFwICkge1xyXG5cclxuXHRcdFx0dW5pZm9ybXMubWFwLnZhbHVlID0gbWF0ZXJpYWwubWFwO1xyXG5cclxuXHRcdFx0cmVmcmVzaFRyYW5zZm9ybVVuaWZvcm0oIG1hdGVyaWFsLm1hcCwgdW5pZm9ybXMubWFwVHJhbnNmb3JtICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggbWF0ZXJpYWwuYWxwaGFNYXAgKSB7XHJcblxyXG5cdFx0XHR1bmlmb3Jtcy5hbHBoYU1hcC52YWx1ZSA9IG1hdGVyaWFsLmFscGhhTWFwO1xyXG5cclxuXHRcdFx0cmVmcmVzaFRyYW5zZm9ybVVuaWZvcm0oIG1hdGVyaWFsLmFscGhhTWFwLCB1bmlmb3Jtcy5hbHBoYU1hcFRyYW5zZm9ybSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIG1hdGVyaWFsLmFscGhhVGVzdCA+IDAgKSB7XHJcblxyXG5cdFx0XHR1bmlmb3Jtcy5hbHBoYVRlc3QudmFsdWUgPSBtYXRlcmlhbC5hbHBoYVRlc3Q7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHJlZnJlc2hVbmlmb3Jtc1Bob25nKCB1bmlmb3JtcywgbWF0ZXJpYWwgKSB7XHJcblxyXG5cdFx0dW5pZm9ybXMuc3BlY3VsYXIudmFsdWUuY29weSggbWF0ZXJpYWwuc3BlY3VsYXIgKTtcclxuXHRcdHVuaWZvcm1zLnNoaW5pbmVzcy52YWx1ZSA9IE1hdGgubWF4KCBtYXRlcmlhbC5zaGluaW5lc3MsIDFlLTQgKTsgLy8gdG8gcHJldmVudCBwb3coIDAuMCwgMC4wIClcclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiByZWZyZXNoVW5pZm9ybXNUb29uKCB1bmlmb3JtcywgbWF0ZXJpYWwgKSB7XHJcblxyXG5cdFx0aWYgKCBtYXRlcmlhbC5ncmFkaWVudE1hcCApIHtcclxuXHJcblx0XHRcdHVuaWZvcm1zLmdyYWRpZW50TWFwLnZhbHVlID0gbWF0ZXJpYWwuZ3JhZGllbnRNYXA7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHJlZnJlc2hVbmlmb3Jtc1N0YW5kYXJkKCB1bmlmb3JtcywgbWF0ZXJpYWwgKSB7XHJcblxyXG5cdFx0dW5pZm9ybXMubWV0YWxuZXNzLnZhbHVlID0gbWF0ZXJpYWwubWV0YWxuZXNzO1xyXG5cclxuXHRcdGlmICggbWF0ZXJpYWwubWV0YWxuZXNzTWFwICkge1xyXG5cclxuXHRcdFx0dW5pZm9ybXMubWV0YWxuZXNzTWFwLnZhbHVlID0gbWF0ZXJpYWwubWV0YWxuZXNzTWFwO1xyXG5cclxuXHRcdFx0cmVmcmVzaFRyYW5zZm9ybVVuaWZvcm0oIG1hdGVyaWFsLm1ldGFsbmVzc01hcCwgdW5pZm9ybXMubWV0YWxuZXNzTWFwVHJhbnNmb3JtICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHVuaWZvcm1zLnJvdWdobmVzcy52YWx1ZSA9IG1hdGVyaWFsLnJvdWdobmVzcztcclxuXHJcblx0XHRpZiAoIG1hdGVyaWFsLnJvdWdobmVzc01hcCApIHtcclxuXHJcblx0XHRcdHVuaWZvcm1zLnJvdWdobmVzc01hcC52YWx1ZSA9IG1hdGVyaWFsLnJvdWdobmVzc01hcDtcclxuXHJcblx0XHRcdHJlZnJlc2hUcmFuc2Zvcm1Vbmlmb3JtKCBtYXRlcmlhbC5yb3VnaG5lc3NNYXAsIHVuaWZvcm1zLnJvdWdobmVzc01hcFRyYW5zZm9ybSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCBlbnZNYXAgPSBwcm9wZXJ0aWVzLmdldCggbWF0ZXJpYWwgKS5lbnZNYXA7XHJcblxyXG5cdFx0aWYgKCBlbnZNYXAgKSB7XHJcblxyXG5cdFx0XHQvL3VuaWZvcm1zLmVudk1hcC52YWx1ZSA9IG1hdGVyaWFsLmVudk1hcDsgLy8gcGFydCBvZiB1bmlmb3JtcyBjb21tb25cclxuXHRcdFx0dW5pZm9ybXMuZW52TWFwSW50ZW5zaXR5LnZhbHVlID0gbWF0ZXJpYWwuZW52TWFwSW50ZW5zaXR5O1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiByZWZyZXNoVW5pZm9ybXNQaHlzaWNhbCggdW5pZm9ybXMsIG1hdGVyaWFsLCB0cmFuc21pc3Npb25SZW5kZXJUYXJnZXQgKSB7XHJcblxyXG5cdFx0dW5pZm9ybXMuaW9yLnZhbHVlID0gbWF0ZXJpYWwuaW9yOyAvLyBhbHNvIHBhcnQgb2YgdW5pZm9ybXMgY29tbW9uXHJcblxyXG5cdFx0aWYgKCBtYXRlcmlhbC5zaGVlbiA+IDAgKSB7XHJcblxyXG5cdFx0XHR1bmlmb3Jtcy5zaGVlbkNvbG9yLnZhbHVlLmNvcHkoIG1hdGVyaWFsLnNoZWVuQ29sb3IgKS5tdWx0aXBseVNjYWxhciggbWF0ZXJpYWwuc2hlZW4gKTtcclxuXHJcblx0XHRcdHVuaWZvcm1zLnNoZWVuUm91Z2huZXNzLnZhbHVlID0gbWF0ZXJpYWwuc2hlZW5Sb3VnaG5lc3M7XHJcblxyXG5cdFx0XHRpZiAoIG1hdGVyaWFsLnNoZWVuQ29sb3JNYXAgKSB7XHJcblxyXG5cdFx0XHRcdHVuaWZvcm1zLnNoZWVuQ29sb3JNYXAudmFsdWUgPSBtYXRlcmlhbC5zaGVlbkNvbG9yTWFwO1xyXG5cclxuXHRcdFx0XHRyZWZyZXNoVHJhbnNmb3JtVW5pZm9ybSggbWF0ZXJpYWwuc2hlZW5Db2xvck1hcCwgdW5pZm9ybXMuc2hlZW5Db2xvck1hcFRyYW5zZm9ybSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0aWYgKCBtYXRlcmlhbC5zaGVlblJvdWdobmVzc01hcCApIHtcclxuXHJcblx0XHRcdFx0dW5pZm9ybXMuc2hlZW5Sb3VnaG5lc3NNYXAudmFsdWUgPSBtYXRlcmlhbC5zaGVlblJvdWdobmVzc01hcDtcclxuXHJcblx0XHRcdFx0cmVmcmVzaFRyYW5zZm9ybVVuaWZvcm0oIG1hdGVyaWFsLnNoZWVuUm91Z2huZXNzTWFwLCB1bmlmb3Jtcy5zaGVlblJvdWdobmVzc01hcFRyYW5zZm9ybSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIG1hdGVyaWFsLmNsZWFyY29hdCA+IDAgKSB7XHJcblxyXG5cdFx0XHR1bmlmb3Jtcy5jbGVhcmNvYXQudmFsdWUgPSBtYXRlcmlhbC5jbGVhcmNvYXQ7XHJcblx0XHRcdHVuaWZvcm1zLmNsZWFyY29hdFJvdWdobmVzcy52YWx1ZSA9IG1hdGVyaWFsLmNsZWFyY29hdFJvdWdobmVzcztcclxuXHJcblx0XHRcdGlmICggbWF0ZXJpYWwuY2xlYXJjb2F0TWFwICkge1xyXG5cclxuXHRcdFx0XHR1bmlmb3Jtcy5jbGVhcmNvYXRNYXAudmFsdWUgPSBtYXRlcmlhbC5jbGVhcmNvYXRNYXA7XHJcblxyXG5cdFx0XHRcdHJlZnJlc2hUcmFuc2Zvcm1Vbmlmb3JtKCBtYXRlcmlhbC5jbGVhcmNvYXRNYXAsIHVuaWZvcm1zLmNsZWFyY29hdE1hcFRyYW5zZm9ybSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0aWYgKCBtYXRlcmlhbC5jbGVhcmNvYXRSb3VnaG5lc3NNYXAgKSB7XHJcblxyXG5cdFx0XHRcdHVuaWZvcm1zLmNsZWFyY29hdFJvdWdobmVzc01hcC52YWx1ZSA9IG1hdGVyaWFsLmNsZWFyY29hdFJvdWdobmVzc01hcDtcclxuXHJcblx0XHRcdFx0cmVmcmVzaFRyYW5zZm9ybVVuaWZvcm0oIG1hdGVyaWFsLmNsZWFyY29hdFJvdWdobmVzc01hcCwgdW5pZm9ybXMuY2xlYXJjb2F0Um91Z2huZXNzTWFwVHJhbnNmb3JtICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRpZiAoIG1hdGVyaWFsLmNsZWFyY29hdE5vcm1hbE1hcCApIHtcclxuXHJcblx0XHRcdFx0dW5pZm9ybXMuY2xlYXJjb2F0Tm9ybWFsTWFwLnZhbHVlID0gbWF0ZXJpYWwuY2xlYXJjb2F0Tm9ybWFsTWFwO1xyXG5cclxuXHRcdFx0XHRyZWZyZXNoVHJhbnNmb3JtVW5pZm9ybSggbWF0ZXJpYWwuY2xlYXJjb2F0Tm9ybWFsTWFwLCB1bmlmb3Jtcy5jbGVhcmNvYXROb3JtYWxNYXBUcmFuc2Zvcm0gKTtcclxuXHJcblx0XHRcdFx0dW5pZm9ybXMuY2xlYXJjb2F0Tm9ybWFsU2NhbGUudmFsdWUuY29weSggbWF0ZXJpYWwuY2xlYXJjb2F0Tm9ybWFsU2NhbGUgKTtcclxuXHJcblx0XHRcdFx0aWYgKCBtYXRlcmlhbC5zaWRlID09PSBCYWNrU2lkZSApIHtcclxuXHJcblx0XHRcdFx0XHR1bmlmb3Jtcy5jbGVhcmNvYXROb3JtYWxTY2FsZS52YWx1ZS5uZWdhdGUoKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIG1hdGVyaWFsLmlyaWRlc2NlbmNlID4gMCApIHtcclxuXHJcblx0XHRcdHVuaWZvcm1zLmlyaWRlc2NlbmNlLnZhbHVlID0gbWF0ZXJpYWwuaXJpZGVzY2VuY2U7XHJcblx0XHRcdHVuaWZvcm1zLmlyaWRlc2NlbmNlSU9SLnZhbHVlID0gbWF0ZXJpYWwuaXJpZGVzY2VuY2VJT1I7XHJcblx0XHRcdHVuaWZvcm1zLmlyaWRlc2NlbmNlVGhpY2tuZXNzTWluaW11bS52YWx1ZSA9IG1hdGVyaWFsLmlyaWRlc2NlbmNlVGhpY2tuZXNzUmFuZ2VbIDAgXTtcclxuXHRcdFx0dW5pZm9ybXMuaXJpZGVzY2VuY2VUaGlja25lc3NNYXhpbXVtLnZhbHVlID0gbWF0ZXJpYWwuaXJpZGVzY2VuY2VUaGlja25lc3NSYW5nZVsgMSBdO1xyXG5cclxuXHRcdFx0aWYgKCBtYXRlcmlhbC5pcmlkZXNjZW5jZU1hcCApIHtcclxuXHJcblx0XHRcdFx0dW5pZm9ybXMuaXJpZGVzY2VuY2VNYXAudmFsdWUgPSBtYXRlcmlhbC5pcmlkZXNjZW5jZU1hcDtcclxuXHJcblx0XHRcdFx0cmVmcmVzaFRyYW5zZm9ybVVuaWZvcm0oIG1hdGVyaWFsLmlyaWRlc2NlbmNlTWFwLCB1bmlmb3Jtcy5pcmlkZXNjZW5jZU1hcFRyYW5zZm9ybSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0aWYgKCBtYXRlcmlhbC5pcmlkZXNjZW5jZVRoaWNrbmVzc01hcCApIHtcclxuXHJcblx0XHRcdFx0dW5pZm9ybXMuaXJpZGVzY2VuY2VUaGlja25lc3NNYXAudmFsdWUgPSBtYXRlcmlhbC5pcmlkZXNjZW5jZVRoaWNrbmVzc01hcDtcclxuXHJcblx0XHRcdFx0cmVmcmVzaFRyYW5zZm9ybVVuaWZvcm0oIG1hdGVyaWFsLmlyaWRlc2NlbmNlVGhpY2tuZXNzTWFwLCB1bmlmb3Jtcy5pcmlkZXNjZW5jZVRoaWNrbmVzc01hcFRyYW5zZm9ybSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIG1hdGVyaWFsLnRyYW5zbWlzc2lvbiA+IDAgKSB7XHJcblxyXG5cdFx0XHR1bmlmb3Jtcy50cmFuc21pc3Npb24udmFsdWUgPSBtYXRlcmlhbC50cmFuc21pc3Npb247XHJcblx0XHRcdHVuaWZvcm1zLnRyYW5zbWlzc2lvblNhbXBsZXJNYXAudmFsdWUgPSB0cmFuc21pc3Npb25SZW5kZXJUYXJnZXQudGV4dHVyZTtcclxuXHRcdFx0dW5pZm9ybXMudHJhbnNtaXNzaW9uU2FtcGxlclNpemUudmFsdWUuc2V0KCB0cmFuc21pc3Npb25SZW5kZXJUYXJnZXQud2lkdGgsIHRyYW5zbWlzc2lvblJlbmRlclRhcmdldC5oZWlnaHQgKTtcclxuXHJcblx0XHRcdGlmICggbWF0ZXJpYWwudHJhbnNtaXNzaW9uTWFwICkge1xyXG5cclxuXHRcdFx0XHR1bmlmb3Jtcy50cmFuc21pc3Npb25NYXAudmFsdWUgPSBtYXRlcmlhbC50cmFuc21pc3Npb25NYXA7XHJcblxyXG5cdFx0XHRcdHJlZnJlc2hUcmFuc2Zvcm1Vbmlmb3JtKCBtYXRlcmlhbC50cmFuc21pc3Npb25NYXAsIHVuaWZvcm1zLnRyYW5zbWlzc2lvbk1hcFRyYW5zZm9ybSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0dW5pZm9ybXMudGhpY2tuZXNzLnZhbHVlID0gbWF0ZXJpYWwudGhpY2tuZXNzO1xyXG5cclxuXHRcdFx0aWYgKCBtYXRlcmlhbC50aGlja25lc3NNYXAgKSB7XHJcblxyXG5cdFx0XHRcdHVuaWZvcm1zLnRoaWNrbmVzc01hcC52YWx1ZSA9IG1hdGVyaWFsLnRoaWNrbmVzc01hcDtcclxuXHJcblx0XHRcdFx0cmVmcmVzaFRyYW5zZm9ybVVuaWZvcm0oIG1hdGVyaWFsLnRoaWNrbmVzc01hcCwgdW5pZm9ybXMudGhpY2tuZXNzTWFwVHJhbnNmb3JtICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHR1bmlmb3Jtcy5hdHRlbnVhdGlvbkRpc3RhbmNlLnZhbHVlID0gbWF0ZXJpYWwuYXR0ZW51YXRpb25EaXN0YW5jZTtcclxuXHRcdFx0dW5pZm9ybXMuYXR0ZW51YXRpb25Db2xvci52YWx1ZS5jb3B5KCBtYXRlcmlhbC5hdHRlbnVhdGlvbkNvbG9yICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggbWF0ZXJpYWwuYW5pc290cm9weSA+IDAgKSB7XHJcblxyXG5cdFx0XHR1bmlmb3Jtcy5hbmlzb3Ryb3B5VmVjdG9yLnZhbHVlLnNldCggbWF0ZXJpYWwuYW5pc290cm9weSAqIE1hdGguY29zKCBtYXRlcmlhbC5hbmlzb3Ryb3B5Um90YXRpb24gKSwgbWF0ZXJpYWwuYW5pc290cm9weSAqIE1hdGguc2luKCBtYXRlcmlhbC5hbmlzb3Ryb3B5Um90YXRpb24gKSApO1xyXG5cclxuXHRcdFx0aWYgKCBtYXRlcmlhbC5hbmlzb3Ryb3B5TWFwICkge1xyXG5cclxuXHRcdFx0XHR1bmlmb3Jtcy5hbmlzb3Ryb3B5TWFwLnZhbHVlID0gbWF0ZXJpYWwuYW5pc290cm9weU1hcDtcclxuXHJcblx0XHRcdFx0cmVmcmVzaFRyYW5zZm9ybVVuaWZvcm0oIG1hdGVyaWFsLmFuaXNvdHJvcHlNYXAsIHVuaWZvcm1zLmFuaXNvdHJvcHlNYXBUcmFuc2Zvcm0gKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dW5pZm9ybXMuc3BlY3VsYXJJbnRlbnNpdHkudmFsdWUgPSBtYXRlcmlhbC5zcGVjdWxhckludGVuc2l0eTtcclxuXHRcdHVuaWZvcm1zLnNwZWN1bGFyQ29sb3IudmFsdWUuY29weSggbWF0ZXJpYWwuc3BlY3VsYXJDb2xvciApO1xyXG5cclxuXHRcdGlmICggbWF0ZXJpYWwuc3BlY3VsYXJDb2xvck1hcCApIHtcclxuXHJcblx0XHRcdHVuaWZvcm1zLnNwZWN1bGFyQ29sb3JNYXAudmFsdWUgPSBtYXRlcmlhbC5zcGVjdWxhckNvbG9yTWFwO1xyXG5cclxuXHRcdFx0cmVmcmVzaFRyYW5zZm9ybVVuaWZvcm0oIG1hdGVyaWFsLnNwZWN1bGFyQ29sb3JNYXAsIHVuaWZvcm1zLnNwZWN1bGFyQ29sb3JNYXBUcmFuc2Zvcm0gKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBtYXRlcmlhbC5zcGVjdWxhckludGVuc2l0eU1hcCApIHtcclxuXHJcblx0XHRcdHVuaWZvcm1zLnNwZWN1bGFySW50ZW5zaXR5TWFwLnZhbHVlID0gbWF0ZXJpYWwuc3BlY3VsYXJJbnRlbnNpdHlNYXA7XHJcblxyXG5cdFx0XHRyZWZyZXNoVHJhbnNmb3JtVW5pZm9ybSggbWF0ZXJpYWwuc3BlY3VsYXJJbnRlbnNpdHlNYXAsIHVuaWZvcm1zLnNwZWN1bGFySW50ZW5zaXR5TWFwVHJhbnNmb3JtICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHJlZnJlc2hVbmlmb3Jtc01hdGNhcCggdW5pZm9ybXMsIG1hdGVyaWFsICkge1xyXG5cclxuXHRcdGlmICggbWF0ZXJpYWwubWF0Y2FwICkge1xyXG5cclxuXHRcdFx0dW5pZm9ybXMubWF0Y2FwLnZhbHVlID0gbWF0ZXJpYWwubWF0Y2FwO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiByZWZyZXNoVW5pZm9ybXNEaXN0YW5jZSggdW5pZm9ybXMsIG1hdGVyaWFsICkge1xyXG5cclxuXHRcdGNvbnN0IGxpZ2h0ID0gcHJvcGVydGllcy5nZXQoIG1hdGVyaWFsICkubGlnaHQ7XHJcblxyXG5cdFx0dW5pZm9ybXMucmVmZXJlbmNlUG9zaXRpb24udmFsdWUuc2V0RnJvbU1hdHJpeFBvc2l0aW9uKCBsaWdodC5tYXRyaXhXb3JsZCApO1xyXG5cdFx0dW5pZm9ybXMubmVhckRpc3RhbmNlLnZhbHVlID0gbGlnaHQuc2hhZG93LmNhbWVyYS5uZWFyO1xyXG5cdFx0dW5pZm9ybXMuZmFyRGlzdGFuY2UudmFsdWUgPSBsaWdodC5zaGFkb3cuY2FtZXJhLmZhcjtcclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4ge1xyXG5cdFx0cmVmcmVzaEZvZ1VuaWZvcm1zOiByZWZyZXNoRm9nVW5pZm9ybXMsXHJcblx0XHRyZWZyZXNoTWF0ZXJpYWxVbmlmb3JtczogcmVmcmVzaE1hdGVyaWFsVW5pZm9ybXNcclxuXHR9O1xyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgV2ViR0xNYXRlcmlhbHMgfTtcclxuIiwiZnVuY3Rpb24gV2ViR0xVbmlmb3Jtc0dyb3VwcyggZ2wsIGluZm8sIGNhcGFiaWxpdGllcywgc3RhdGUgKSB7XHJcblxyXG5cdGxldCBidWZmZXJzID0ge307XHJcblx0bGV0IHVwZGF0ZUxpc3QgPSB7fTtcclxuXHRsZXQgYWxsb2NhdGVkQmluZGluZ1BvaW50cyA9IFtdO1xyXG5cclxuXHRjb25zdCBtYXhCaW5kaW5nUG9pbnRzID0gKCBjYXBhYmlsaXRpZXMuaXNXZWJHTDIgKSA/IGdsLmdldFBhcmFtZXRlciggZ2wuTUFYX1VOSUZPUk1fQlVGRkVSX0JJTkRJTkdTICkgOiAwOyAvLyBiaW5kaW5nIHBvaW50cyBhcmUgZ2xvYmFsIHdoZXJlYXMgYmxvY2sgaW5kaWNlcyBhcmUgcGVyIHNoYWRlciBwcm9ncmFtXHJcblxyXG5cdGZ1bmN0aW9uIGJpbmQoIHVuaWZvcm1zR3JvdXAsIHByb2dyYW0gKSB7XHJcblxyXG5cdFx0Y29uc3Qgd2ViZ2xQcm9ncmFtID0gcHJvZ3JhbS5wcm9ncmFtO1xyXG5cdFx0c3RhdGUudW5pZm9ybUJsb2NrQmluZGluZyggdW5pZm9ybXNHcm91cCwgd2ViZ2xQcm9ncmFtICk7XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gdXBkYXRlKCB1bmlmb3Jtc0dyb3VwLCBwcm9ncmFtICkge1xyXG5cclxuXHRcdGxldCBidWZmZXIgPSBidWZmZXJzWyB1bmlmb3Jtc0dyb3VwLmlkIF07XHJcblxyXG5cdFx0aWYgKCBidWZmZXIgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdHByZXBhcmVVbmlmb3Jtc0dyb3VwKCB1bmlmb3Jtc0dyb3VwICk7XHJcblxyXG5cdFx0XHRidWZmZXIgPSBjcmVhdGVCdWZmZXIoIHVuaWZvcm1zR3JvdXAgKTtcclxuXHRcdFx0YnVmZmVyc1sgdW5pZm9ybXNHcm91cC5pZCBdID0gYnVmZmVyO1xyXG5cclxuXHRcdFx0dW5pZm9ybXNHcm91cC5hZGRFdmVudExpc3RlbmVyKCAnZGlzcG9zZScsIG9uVW5pZm9ybXNHcm91cHNEaXNwb3NlICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIGVuc3VyZSB0byB1cGRhdGUgdGhlIGJpbmRpbmcgcG9pbnRzL2Jsb2NrIGluZGljZXMgbWFwcGluZyBmb3IgdGhpcyBwcm9ncmFtXHJcblxyXG5cdFx0Y29uc3Qgd2ViZ2xQcm9ncmFtID0gcHJvZ3JhbS5wcm9ncmFtO1xyXG5cdFx0c3RhdGUudXBkYXRlVUJPTWFwcGluZyggdW5pZm9ybXNHcm91cCwgd2ViZ2xQcm9ncmFtICk7XHJcblxyXG5cdFx0Ly8gdXBkYXRlIFVCTyBvbmNlIHBlciBmcmFtZVxyXG5cclxuXHRcdGNvbnN0IGZyYW1lID0gaW5mby5yZW5kZXIuZnJhbWU7XHJcblxyXG5cdFx0aWYgKCB1cGRhdGVMaXN0WyB1bmlmb3Jtc0dyb3VwLmlkIF0gIT09IGZyYW1lICkge1xyXG5cclxuXHRcdFx0dXBkYXRlQnVmZmVyRGF0YSggdW5pZm9ybXNHcm91cCApO1xyXG5cclxuXHRcdFx0dXBkYXRlTGlzdFsgdW5pZm9ybXNHcm91cC5pZCBdID0gZnJhbWU7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIGNyZWF0ZUJ1ZmZlciggdW5pZm9ybXNHcm91cCApIHtcclxuXHJcblx0XHQvLyB0aGUgc2V0dXAgb2YgYW4gVUJPIGlzIGluZGVwZW5kZW50IG9mIGEgcGFydGljdWxhciBzaGFkZXIgcHJvZ3JhbSBidXQgZ2xvYmFsXHJcblxyXG5cdFx0Y29uc3QgYmluZGluZ1BvaW50SW5kZXggPSBhbGxvY2F0ZUJpbmRpbmdQb2ludEluZGV4KCk7XHJcblx0XHR1bmlmb3Jtc0dyb3VwLl9fYmluZGluZ1BvaW50SW5kZXggPSBiaW5kaW5nUG9pbnRJbmRleDtcclxuXHJcblx0XHRjb25zdCBidWZmZXIgPSBnbC5jcmVhdGVCdWZmZXIoKTtcclxuXHRcdGNvbnN0IHNpemUgPSB1bmlmb3Jtc0dyb3VwLl9fc2l6ZTtcclxuXHRcdGNvbnN0IHVzYWdlID0gdW5pZm9ybXNHcm91cC51c2FnZTtcclxuXHJcblx0XHRnbC5iaW5kQnVmZmVyKCBnbC5VTklGT1JNX0JVRkZFUiwgYnVmZmVyICk7XHJcblx0XHRnbC5idWZmZXJEYXRhKCBnbC5VTklGT1JNX0JVRkZFUiwgc2l6ZSwgdXNhZ2UgKTtcclxuXHRcdGdsLmJpbmRCdWZmZXIoIGdsLlVOSUZPUk1fQlVGRkVSLCBudWxsICk7XHJcblx0XHRnbC5iaW5kQnVmZmVyQmFzZSggZ2wuVU5JRk9STV9CVUZGRVIsIGJpbmRpbmdQb2ludEluZGV4LCBidWZmZXIgKTtcclxuXHJcblx0XHRyZXR1cm4gYnVmZmVyO1xyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIGFsbG9jYXRlQmluZGluZ1BvaW50SW5kZXgoKSB7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgbWF4QmluZGluZ1BvaW50czsgaSArKyApIHtcclxuXHJcblx0XHRcdGlmICggYWxsb2NhdGVkQmluZGluZ1BvaW50cy5pbmRleE9mKCBpICkgPT09IC0gMSApIHtcclxuXHJcblx0XHRcdFx0YWxsb2NhdGVkQmluZGluZ1BvaW50cy5wdXNoKCBpICk7XHJcblx0XHRcdFx0cmV0dXJuIGk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5XZWJHTFJlbmRlcmVyOiBNYXhpbXVtIG51bWJlciBvZiBzaW11bHRhbmVvdXNseSB1c2FibGUgdW5pZm9ybXMgZ3JvdXBzIHJlYWNoZWQuJyApO1xyXG5cclxuXHRcdHJldHVybiAwO1xyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHVwZGF0ZUJ1ZmZlckRhdGEoIHVuaWZvcm1zR3JvdXAgKSB7XHJcblxyXG5cdFx0Y29uc3QgYnVmZmVyID0gYnVmZmVyc1sgdW5pZm9ybXNHcm91cC5pZCBdO1xyXG5cdFx0Y29uc3QgdW5pZm9ybXMgPSB1bmlmb3Jtc0dyb3VwLnVuaWZvcm1zO1xyXG5cdFx0Y29uc3QgY2FjaGUgPSB1bmlmb3Jtc0dyb3VwLl9fY2FjaGU7XHJcblxyXG5cdFx0Z2wuYmluZEJ1ZmZlciggZ2wuVU5JRk9STV9CVUZGRVIsIGJ1ZmZlciApO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSB1bmlmb3Jtcy5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcclxuXHJcblx0XHRcdGNvbnN0IHVuaWZvcm1BcnJheSA9IEFycmF5LmlzQXJyYXkoIHVuaWZvcm1zWyBpIF0gKSA/IHVuaWZvcm1zWyBpIF0gOiBbIHVuaWZvcm1zWyBpIF0gXTtcclxuXHJcblx0XHRcdGZvciAoIGxldCBqID0gMCwgamwgPSB1bmlmb3JtQXJyYXkubGVuZ3RoOyBqIDwgamw7IGogKysgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IHVuaWZvcm0gPSB1bmlmb3JtQXJyYXlbIGogXTtcclxuXHJcblx0XHRcdFx0aWYgKCBoYXNVbmlmb3JtQ2hhbmdlZCggdW5pZm9ybSwgaSwgaiwgY2FjaGUgKSA9PT0gdHJ1ZSApIHtcclxuXHJcblx0XHRcdFx0XHRjb25zdCBvZmZzZXQgPSB1bmlmb3JtLl9fb2Zmc2V0O1xyXG5cclxuXHRcdFx0XHRcdGNvbnN0IHZhbHVlcyA9IEFycmF5LmlzQXJyYXkoIHVuaWZvcm0udmFsdWUgKSA/IHVuaWZvcm0udmFsdWUgOiBbIHVuaWZvcm0udmFsdWUgXTtcclxuXHJcblx0XHRcdFx0XHRsZXQgYXJyYXlPZmZzZXQgPSAwO1xyXG5cclxuXHRcdFx0XHRcdGZvciAoIGxldCBrID0gMDsgayA8IHZhbHVlcy5sZW5ndGg7IGsgKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRjb25zdCB2YWx1ZSA9IHZhbHVlc1sgayBdO1xyXG5cclxuXHRcdFx0XHRcdFx0Y29uc3QgaW5mbyA9IGdldFVuaWZvcm1TaXplKCB2YWx1ZSApO1xyXG5cclxuXHRcdFx0XHRcdFx0Ly8gVE9ETyBhZGQgaW50ZWdlciBhbmQgc3RydWN0IHN1cHBvcnRcclxuXHRcdFx0XHRcdFx0aWYgKCB0eXBlb2YgdmFsdWUgPT09ICdudW1iZXInIHx8IHR5cGVvZiB2YWx1ZSA9PT0gJ2Jvb2xlYW4nICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHR1bmlmb3JtLl9fZGF0YVsgMCBdID0gdmFsdWU7XHJcblx0XHRcdFx0XHRcdFx0Z2wuYnVmZmVyU3ViRGF0YSggZ2wuVU5JRk9STV9CVUZGRVIsIG9mZnNldCArIGFycmF5T2Zmc2V0LCB1bmlmb3JtLl9fZGF0YSApO1xyXG5cclxuXHRcdFx0XHRcdFx0fSBlbHNlIGlmICggdmFsdWUuaXNNYXRyaXgzICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHQvLyBtYW51YWxseSBjb252ZXJ0aW5nIDN4MyB0byAzeDRcclxuXHJcblx0XHRcdFx0XHRcdFx0dW5pZm9ybS5fX2RhdGFbIDAgXSA9IHZhbHVlLmVsZW1lbnRzWyAwIF07XHJcblx0XHRcdFx0XHRcdFx0dW5pZm9ybS5fX2RhdGFbIDEgXSA9IHZhbHVlLmVsZW1lbnRzWyAxIF07XHJcblx0XHRcdFx0XHRcdFx0dW5pZm9ybS5fX2RhdGFbIDIgXSA9IHZhbHVlLmVsZW1lbnRzWyAyIF07XHJcblx0XHRcdFx0XHRcdFx0dW5pZm9ybS5fX2RhdGFbIDMgXSA9IDA7XHJcblx0XHRcdFx0XHRcdFx0dW5pZm9ybS5fX2RhdGFbIDQgXSA9IHZhbHVlLmVsZW1lbnRzWyAzIF07XHJcblx0XHRcdFx0XHRcdFx0dW5pZm9ybS5fX2RhdGFbIDUgXSA9IHZhbHVlLmVsZW1lbnRzWyA0IF07XHJcblx0XHRcdFx0XHRcdFx0dW5pZm9ybS5fX2RhdGFbIDYgXSA9IHZhbHVlLmVsZW1lbnRzWyA1IF07XHJcblx0XHRcdFx0XHRcdFx0dW5pZm9ybS5fX2RhdGFbIDcgXSA9IDA7XHJcblx0XHRcdFx0XHRcdFx0dW5pZm9ybS5fX2RhdGFbIDggXSA9IHZhbHVlLmVsZW1lbnRzWyA2IF07XHJcblx0XHRcdFx0XHRcdFx0dW5pZm9ybS5fX2RhdGFbIDkgXSA9IHZhbHVlLmVsZW1lbnRzWyA3IF07XHJcblx0XHRcdFx0XHRcdFx0dW5pZm9ybS5fX2RhdGFbIDEwIF0gPSB2YWx1ZS5lbGVtZW50c1sgOCBdO1xyXG5cdFx0XHRcdFx0XHRcdHVuaWZvcm0uX19kYXRhWyAxMSBdID0gMDtcclxuXHJcblx0XHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdHZhbHVlLnRvQXJyYXkoIHVuaWZvcm0uX19kYXRhLCBhcnJheU9mZnNldCApO1xyXG5cclxuXHRcdFx0XHRcdFx0XHRhcnJheU9mZnNldCArPSBpbmZvLnN0b3JhZ2UgLyBGbG9hdDMyQXJyYXkuQllURVNfUEVSX0VMRU1FTlQ7XHJcblxyXG5cdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdGdsLmJ1ZmZlclN1YkRhdGEoIGdsLlVOSUZPUk1fQlVGRkVSLCBvZmZzZXQsIHVuaWZvcm0uX19kYXRhICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Z2wuYmluZEJ1ZmZlciggZ2wuVU5JRk9STV9CVUZGRVIsIG51bGwgKTtcclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBoYXNVbmlmb3JtQ2hhbmdlZCggdW5pZm9ybSwgaW5kZXgsIGluZGV4QXJyYXksIGNhY2hlICkge1xyXG5cclxuXHRcdGNvbnN0IHZhbHVlID0gdW5pZm9ybS52YWx1ZTtcclxuXHRcdGNvbnN0IGluZGV4U3RyaW5nID0gaW5kZXggKyAnXycgKyBpbmRleEFycmF5O1xyXG5cclxuXHRcdGlmICggY2FjaGVbIGluZGV4U3RyaW5nIF0gPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdC8vIGNhY2hlIGVudHJ5IGRvZXMgbm90IGV4aXN0IHNvIGZhclxyXG5cclxuXHRcdFx0aWYgKCB0eXBlb2YgdmFsdWUgPT09ICdudW1iZXInIHx8IHR5cGVvZiB2YWx1ZSA9PT0gJ2Jvb2xlYW4nICkge1xyXG5cclxuXHRcdFx0XHRjYWNoZVsgaW5kZXhTdHJpbmcgXSA9IHZhbHVlO1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0Y2FjaGVbIGluZGV4U3RyaW5nIF0gPSB2YWx1ZS5jbG9uZSgpO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0cmV0dXJuIHRydWU7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdGNvbnN0IGNhY2hlZE9iamVjdCA9IGNhY2hlWyBpbmRleFN0cmluZyBdO1xyXG5cclxuXHRcdFx0Ly8gY29tcGFyZSBjdXJyZW50IHZhbHVlIHdpdGggY2FjaGVkIGVudHJ5XHJcblxyXG5cdFx0XHRpZiAoIHR5cGVvZiB2YWx1ZSA9PT0gJ251bWJlcicgfHwgdHlwZW9mIHZhbHVlID09PSAnYm9vbGVhbicgKSB7XHJcblxyXG5cdFx0XHRcdGlmICggY2FjaGVkT2JqZWN0ICE9PSB2YWx1ZSApIHtcclxuXHJcblx0XHRcdFx0XHRjYWNoZVsgaW5kZXhTdHJpbmcgXSA9IHZhbHVlO1xyXG5cdFx0XHRcdFx0cmV0dXJuIHRydWU7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdGlmICggY2FjaGVkT2JqZWN0LmVxdWFscyggdmFsdWUgKSA9PT0gZmFsc2UgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y2FjaGVkT2JqZWN0LmNvcHkoIHZhbHVlICk7XHJcblx0XHRcdFx0XHRyZXR1cm4gdHJ1ZTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gZmFsc2U7XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gcHJlcGFyZVVuaWZvcm1zR3JvdXAoIHVuaWZvcm1zR3JvdXAgKSB7XHJcblxyXG5cdFx0Ly8gZGV0ZXJtaW5lIHRvdGFsIGJ1ZmZlciBzaXplIGFjY29yZGluZyB0byB0aGUgU1REMTQwIGxheW91dFxyXG5cdFx0Ly8gSGludDogU1REMTQwIGlzIHRoZSBvbmx5IHN1cHBvcnRlZCBsYXlvdXQgaW4gV2ViR0wgMlxyXG5cclxuXHRcdGNvbnN0IHVuaWZvcm1zID0gdW5pZm9ybXNHcm91cC51bmlmb3JtcztcclxuXHJcblx0XHRsZXQgb2Zmc2V0ID0gMDsgLy8gZ2xvYmFsIGJ1ZmZlciBvZmZzZXQgaW4gYnl0ZXNcclxuXHRcdGNvbnN0IGNodW5rU2l6ZSA9IDE2OyAvLyBzaXplIG9mIGEgY2h1bmsgaW4gYnl0ZXNcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSB1bmlmb3Jtcy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0Y29uc3QgdW5pZm9ybUFycmF5ID0gQXJyYXkuaXNBcnJheSggdW5pZm9ybXNbIGkgXSApID8gdW5pZm9ybXNbIGkgXSA6IFsgdW5pZm9ybXNbIGkgXSBdO1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGogPSAwLCBqbCA9IHVuaWZvcm1BcnJheS5sZW5ndGg7IGogPCBqbDsgaiArKyApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgdW5pZm9ybSA9IHVuaWZvcm1BcnJheVsgaiBdO1xyXG5cclxuXHRcdFx0XHRjb25zdCB2YWx1ZXMgPSBBcnJheS5pc0FycmF5KCB1bmlmb3JtLnZhbHVlICkgPyB1bmlmb3JtLnZhbHVlIDogWyB1bmlmb3JtLnZhbHVlIF07XHJcblxyXG5cdFx0XHRcdGZvciAoIGxldCBrID0gMCwga2wgPSB2YWx1ZXMubGVuZ3RoOyBrIDwga2w7IGsgKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgdmFsdWUgPSB2YWx1ZXNbIGsgXTtcclxuXHJcblx0XHRcdFx0XHRjb25zdCBpbmZvID0gZ2V0VW5pZm9ybVNpemUoIHZhbHVlICk7XHJcblxyXG5cdFx0XHRcdFx0Ly8gQ2FsY3VsYXRlIHRoZSBjaHVuayBvZmZzZXRcclxuXHRcdFx0XHRcdGNvbnN0IGNodW5rT2Zmc2V0VW5pZm9ybSA9IG9mZnNldCAlIGNodW5rU2l6ZTtcclxuXHJcblx0XHRcdFx0XHQvLyBDaGVjayBmb3IgY2h1bmsgb3ZlcmZsb3dcclxuXHRcdFx0XHRcdGlmICggY2h1bmtPZmZzZXRVbmlmb3JtICE9PSAwICYmICggY2h1bmtTaXplIC0gY2h1bmtPZmZzZXRVbmlmb3JtICkgPCBpbmZvLmJvdW5kYXJ5ICkge1xyXG5cclxuXHRcdFx0XHRcdFx0Ly8gQWRkIHBhZGRpbmcgYW5kIGFkanVzdCBvZmZzZXRcclxuXHRcdFx0XHRcdFx0b2Zmc2V0ICs9ICggY2h1bmtTaXplIC0gY2h1bmtPZmZzZXRVbmlmb3JtICk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdC8vIHRoZSBmb2xsb3dpbmcgdHdvIHByb3BlcnRpZXMgd2lsbCBiZSB1c2VkIGZvciBwYXJ0aWFsIGJ1ZmZlciB1cGRhdGVzXHJcblxyXG5cdFx0XHRcdFx0dW5pZm9ybS5fX2RhdGEgPSBuZXcgRmxvYXQzMkFycmF5KCBpbmZvLnN0b3JhZ2UgLyBGbG9hdDMyQXJyYXkuQllURVNfUEVSX0VMRU1FTlQgKTtcclxuXHRcdFx0XHRcdHVuaWZvcm0uX19vZmZzZXQgPSBvZmZzZXQ7XHJcblxyXG5cclxuXHRcdFx0XHRcdC8vIFVwZGF0ZSB0aGUgZ2xvYmFsIG9mZnNldFxyXG5cdFx0XHRcdFx0b2Zmc2V0ICs9IGluZm8uc3RvcmFnZTtcclxuXHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gZW5zdXJlIGNvcnJlY3QgZmluYWwgcGFkZGluZ1xyXG5cclxuXHRcdGNvbnN0IGNodW5rT2Zmc2V0ID0gb2Zmc2V0ICUgY2h1bmtTaXplO1xyXG5cclxuXHRcdGlmICggY2h1bmtPZmZzZXQgPiAwICkgb2Zmc2V0ICs9ICggY2h1bmtTaXplIC0gY2h1bmtPZmZzZXQgKTtcclxuXHJcblx0XHQvL1xyXG5cclxuXHRcdHVuaWZvcm1zR3JvdXAuX19zaXplID0gb2Zmc2V0O1xyXG5cdFx0dW5pZm9ybXNHcm91cC5fX2NhY2hlID0ge307XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gZ2V0VW5pZm9ybVNpemUoIHZhbHVlICkge1xyXG5cclxuXHRcdGNvbnN0IGluZm8gPSB7XHJcblx0XHRcdGJvdW5kYXJ5OiAwLCAvLyBieXRlc1xyXG5cdFx0XHRzdG9yYWdlOiAwIC8vIGJ5dGVzXHJcblx0XHR9O1xyXG5cclxuXHRcdC8vIGRldGVybWluZSBzaXplcyBhY2NvcmRpbmcgdG8gU1REMTQwXHJcblxyXG5cdFx0aWYgKCB0eXBlb2YgdmFsdWUgPT09ICdudW1iZXInIHx8IHR5cGVvZiB2YWx1ZSA9PT0gJ2Jvb2xlYW4nICkge1xyXG5cclxuXHRcdFx0Ly8gZmxvYXQvaW50L2Jvb2xcclxuXHJcblx0XHRcdGluZm8uYm91bmRhcnkgPSA0O1xyXG5cdFx0XHRpbmZvLnN0b3JhZ2UgPSA0O1xyXG5cclxuXHRcdH0gZWxzZSBpZiAoIHZhbHVlLmlzVmVjdG9yMiApIHtcclxuXHJcblx0XHRcdC8vIHZlYzJcclxuXHJcblx0XHRcdGluZm8uYm91bmRhcnkgPSA4O1xyXG5cdFx0XHRpbmZvLnN0b3JhZ2UgPSA4O1xyXG5cclxuXHRcdH0gZWxzZSBpZiAoIHZhbHVlLmlzVmVjdG9yMyB8fCB2YWx1ZS5pc0NvbG9yICkge1xyXG5cclxuXHRcdFx0Ly8gdmVjM1xyXG5cclxuXHRcdFx0aW5mby5ib3VuZGFyeSA9IDE2O1xyXG5cdFx0XHRpbmZvLnN0b3JhZ2UgPSAxMjsgLy8gZXZpbDogdmVjMyBtdXN0IHN0YXJ0IG9uIGEgMTYtYnl0ZSBib3VuZGFyeSBidXQgaXQgb25seSBjb25zdW1lcyAxMiBieXRlc1xyXG5cclxuXHRcdH0gZWxzZSBpZiAoIHZhbHVlLmlzVmVjdG9yNCApIHtcclxuXHJcblx0XHRcdC8vIHZlYzRcclxuXHJcblx0XHRcdGluZm8uYm91bmRhcnkgPSAxNjtcclxuXHRcdFx0aW5mby5zdG9yYWdlID0gMTY7XHJcblxyXG5cdFx0fSBlbHNlIGlmICggdmFsdWUuaXNNYXRyaXgzICkge1xyXG5cclxuXHRcdFx0Ly8gbWF0MyAoaW4gU1REMTQwIGEgM3gzIG1hdHJpeCBpcyByZXByZXNlbnRlZCBhcyAzeDQpXHJcblxyXG5cdFx0XHRpbmZvLmJvdW5kYXJ5ID0gNDg7XHJcblx0XHRcdGluZm8uc3RvcmFnZSA9IDQ4O1xyXG5cclxuXHRcdH0gZWxzZSBpZiAoIHZhbHVlLmlzTWF0cml4NCApIHtcclxuXHJcblx0XHRcdC8vIG1hdDRcclxuXHJcblx0XHRcdGluZm8uYm91bmRhcnkgPSA2NDtcclxuXHRcdFx0aW5mby5zdG9yYWdlID0gNjQ7XHJcblxyXG5cdFx0fSBlbHNlIGlmICggdmFsdWUuaXNUZXh0dXJlICkge1xyXG5cclxuXHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuV2ViR0xSZW5kZXJlcjogVGV4dHVyZSBzYW1wbGVycyBjYW4gbm90IGJlIHBhcnQgb2YgYW4gdW5pZm9ybXMgZ3JvdXAuJyApO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5XZWJHTFJlbmRlcmVyOiBVbnN1cHBvcnRlZCB1bmlmb3JtIHZhbHVlIHR5cGUuJywgdmFsdWUgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIGluZm87XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gb25Vbmlmb3Jtc0dyb3Vwc0Rpc3Bvc2UoIGV2ZW50ICkge1xyXG5cclxuXHRcdGNvbnN0IHVuaWZvcm1zR3JvdXAgPSBldmVudC50YXJnZXQ7XHJcblxyXG5cdFx0dW5pZm9ybXNHcm91cC5yZW1vdmVFdmVudExpc3RlbmVyKCAnZGlzcG9zZScsIG9uVW5pZm9ybXNHcm91cHNEaXNwb3NlICk7XHJcblxyXG5cdFx0Y29uc3QgaW5kZXggPSBhbGxvY2F0ZWRCaW5kaW5nUG9pbnRzLmluZGV4T2YoIHVuaWZvcm1zR3JvdXAuX19iaW5kaW5nUG9pbnRJbmRleCApO1xyXG5cdFx0YWxsb2NhdGVkQmluZGluZ1BvaW50cy5zcGxpY2UoIGluZGV4LCAxICk7XHJcblxyXG5cdFx0Z2wuZGVsZXRlQnVmZmVyKCBidWZmZXJzWyB1bmlmb3Jtc0dyb3VwLmlkIF0gKTtcclxuXHJcblx0XHRkZWxldGUgYnVmZmVyc1sgdW5pZm9ybXNHcm91cC5pZCBdO1xyXG5cdFx0ZGVsZXRlIHVwZGF0ZUxpc3RbIHVuaWZvcm1zR3JvdXAuaWQgXTtcclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBkaXNwb3NlKCkge1xyXG5cclxuXHRcdGZvciAoIGNvbnN0IGlkIGluIGJ1ZmZlcnMgKSB7XHJcblxyXG5cdFx0XHRnbC5kZWxldGVCdWZmZXIoIGJ1ZmZlcnNbIGlkIF0gKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0YWxsb2NhdGVkQmluZGluZ1BvaW50cyA9IFtdO1xyXG5cdFx0YnVmZmVycyA9IHt9O1xyXG5cdFx0dXBkYXRlTGlzdCA9IHt9O1xyXG5cclxuXHR9XHJcblxyXG5cdHJldHVybiB7XHJcblxyXG5cdFx0YmluZDogYmluZCxcclxuXHRcdHVwZGF0ZTogdXBkYXRlLFxyXG5cclxuXHRcdGRpc3Bvc2U6IGRpc3Bvc2VcclxuXHJcblx0fTtcclxuXHJcbn1cclxuXHJcblxyXG5leHBvcnQgeyBXZWJHTFVuaWZvcm1zR3JvdXBzIH07XHJcbiIsImltcG9ydCB7XHJcblx0UkVWSVNJT04sXHJcblx0QmFja1NpZGUsXHJcblx0RnJvbnRTaWRlLFxyXG5cdERvdWJsZVNpZGUsXHJcblx0UkdCQUZvcm1hdCxcclxuXHRIYWxmRmxvYXRUeXBlLFxyXG5cdEZsb2F0VHlwZSxcclxuXHRVbnNpZ25lZEJ5dGVUeXBlLFxyXG5cdE5vVG9uZU1hcHBpbmcsXHJcblx0TGluZWFyTWlwbWFwTGluZWFyRmlsdGVyLFxyXG5cdFNSR0JDb2xvclNwYWNlLFxyXG5cdExpbmVhclNSR0JDb2xvclNwYWNlLFxyXG5cdFJHQkFJbnRlZ2VyRm9ybWF0LFxyXG5cdFJHSW50ZWdlckZvcm1hdCxcclxuXHRSZWRJbnRlZ2VyRm9ybWF0LFxyXG5cdFVuc2lnbmVkSW50VHlwZSxcclxuXHRVbnNpZ25lZFNob3J0VHlwZSxcclxuXHRVbnNpZ25lZEludDI0OFR5cGUsXHJcblx0VW5zaWduZWRTaG9ydDQ0NDRUeXBlLFxyXG5cdFVuc2lnbmVkU2hvcnQ1NTUxVHlwZSxcclxuXHRXZWJHTENvb3JkaW5hdGVTeXN0ZW0sXHJcblx0RGlzcGxheVAzQ29sb3JTcGFjZSxcclxuXHRMaW5lYXJEaXNwbGF5UDNDb2xvclNwYWNlXHJcbn0gZnJvbSAnLi4vY29uc3RhbnRzLmpzJztcclxuaW1wb3J0IHsgQ29sb3IgfSBmcm9tICcuLi9tYXRoL0NvbG9yLmpzJztcclxuaW1wb3J0IHsgRnJ1c3R1bSB9IGZyb20gJy4uL21hdGgvRnJ1c3R1bS5qcyc7XHJcbmltcG9ydCB7IE1hdHJpeDQgfSBmcm9tICcuLi9tYXRoL01hdHJpeDQuanMnO1xyXG5pbXBvcnQgeyBWZWN0b3IyIH0gZnJvbSAnLi4vbWF0aC9WZWN0b3IyLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yMyB9IGZyb20gJy4uL21hdGgvVmVjdG9yMy5qcyc7XHJcbmltcG9ydCB7IFZlY3RvcjQgfSBmcm9tICcuLi9tYXRoL1ZlY3RvcjQuanMnO1xyXG5pbXBvcnQgeyBmbG9vclBvd2VyT2ZUd28gfSBmcm9tICcuLi9tYXRoL01hdGhVdGlscy5qcyc7XHJcbmltcG9ydCB7IFdlYkdMQW5pbWF0aW9uIH0gZnJvbSAnLi93ZWJnbC9XZWJHTEFuaW1hdGlvbi5qcyc7XHJcbmltcG9ydCB7IFdlYkdMQXR0cmlidXRlcyB9IGZyb20gJy4vd2ViZ2wvV2ViR0xBdHRyaWJ1dGVzLmpzJztcclxuaW1wb3J0IHsgV2ViR0xCYWNrZ3JvdW5kIH0gZnJvbSAnLi93ZWJnbC9XZWJHTEJhY2tncm91bmQuanMnO1xyXG5pbXBvcnQgeyBXZWJHTEJpbmRpbmdTdGF0ZXMgfSBmcm9tICcuL3dlYmdsL1dlYkdMQmluZGluZ1N0YXRlcy5qcyc7XHJcbmltcG9ydCB7IFdlYkdMQnVmZmVyUmVuZGVyZXIgfSBmcm9tICcuL3dlYmdsL1dlYkdMQnVmZmVyUmVuZGVyZXIuanMnO1xyXG5pbXBvcnQgeyBXZWJHTENhcGFiaWxpdGllcyB9IGZyb20gJy4vd2ViZ2wvV2ViR0xDYXBhYmlsaXRpZXMuanMnO1xyXG5pbXBvcnQgeyBXZWJHTENsaXBwaW5nIH0gZnJvbSAnLi93ZWJnbC9XZWJHTENsaXBwaW5nLmpzJztcclxuaW1wb3J0IHsgV2ViR0xDdWJlTWFwcyB9IGZyb20gJy4vd2ViZ2wvV2ViR0xDdWJlTWFwcy5qcyc7XHJcbmltcG9ydCB7IFdlYkdMQ3ViZVVWTWFwcyB9IGZyb20gJy4vd2ViZ2wvV2ViR0xDdWJlVVZNYXBzLmpzJztcclxuaW1wb3J0IHsgV2ViR0xFeHRlbnNpb25zIH0gZnJvbSAnLi93ZWJnbC9XZWJHTEV4dGVuc2lvbnMuanMnO1xyXG5pbXBvcnQgeyBXZWJHTEdlb21ldHJpZXMgfSBmcm9tICcuL3dlYmdsL1dlYkdMR2VvbWV0cmllcy5qcyc7XHJcbmltcG9ydCB7IFdlYkdMSW5kZXhlZEJ1ZmZlclJlbmRlcmVyIH0gZnJvbSAnLi93ZWJnbC9XZWJHTEluZGV4ZWRCdWZmZXJSZW5kZXJlci5qcyc7XHJcbmltcG9ydCB7IFdlYkdMSW5mbyB9IGZyb20gJy4vd2ViZ2wvV2ViR0xJbmZvLmpzJztcclxuaW1wb3J0IHsgV2ViR0xNb3JwaHRhcmdldHMgfSBmcm9tICcuL3dlYmdsL1dlYkdMTW9ycGh0YXJnZXRzLmpzJztcclxuaW1wb3J0IHsgV2ViR0xPYmplY3RzIH0gZnJvbSAnLi93ZWJnbC9XZWJHTE9iamVjdHMuanMnO1xyXG5pbXBvcnQgeyBXZWJHTFByb2dyYW1zIH0gZnJvbSAnLi93ZWJnbC9XZWJHTFByb2dyYW1zLmpzJztcclxuaW1wb3J0IHsgV2ViR0xQcm9wZXJ0aWVzIH0gZnJvbSAnLi93ZWJnbC9XZWJHTFByb3BlcnRpZXMuanMnO1xyXG5pbXBvcnQgeyBXZWJHTFJlbmRlckxpc3RzIH0gZnJvbSAnLi93ZWJnbC9XZWJHTFJlbmRlckxpc3RzLmpzJztcclxuaW1wb3J0IHsgV2ViR0xSZW5kZXJTdGF0ZXMgfSBmcm9tICcuL3dlYmdsL1dlYkdMUmVuZGVyU3RhdGVzLmpzJztcclxuaW1wb3J0IHsgV2ViR0xSZW5kZXJUYXJnZXQgfSBmcm9tICcuL1dlYkdMUmVuZGVyVGFyZ2V0LmpzJztcclxuaW1wb3J0IHsgV2ViR0xTaGFkb3dNYXAgfSBmcm9tICcuL3dlYmdsL1dlYkdMU2hhZG93TWFwLmpzJztcclxuaW1wb3J0IHsgV2ViR0xTdGF0ZSB9IGZyb20gJy4vd2ViZ2wvV2ViR0xTdGF0ZS5qcyc7XHJcbmltcG9ydCB7IFdlYkdMVGV4dHVyZXMgfSBmcm9tICcuL3dlYmdsL1dlYkdMVGV4dHVyZXMuanMnO1xyXG5pbXBvcnQgeyBXZWJHTFVuaWZvcm1zIH0gZnJvbSAnLi93ZWJnbC9XZWJHTFVuaWZvcm1zLmpzJztcclxuaW1wb3J0IHsgV2ViR0xVdGlscyB9IGZyb20gJy4vd2ViZ2wvV2ViR0xVdGlscy5qcyc7XHJcbmltcG9ydCB7IFdlYlhSTWFuYWdlciB9IGZyb20gJy4vd2VieHIvV2ViWFJNYW5hZ2VyLmpzJztcclxuaW1wb3J0IHsgV2ViR0xNYXRlcmlhbHMgfSBmcm9tICcuL3dlYmdsL1dlYkdMTWF0ZXJpYWxzLmpzJztcclxuaW1wb3J0IHsgV2ViR0xVbmlmb3Jtc0dyb3VwcyB9IGZyb20gJy4vd2ViZ2wvV2ViR0xVbmlmb3Jtc0dyb3Vwcy5qcyc7XHJcbmltcG9ydCB7IGNyZWF0ZUNhbnZhc0VsZW1lbnQgfSBmcm9tICcuLi91dGlscy5qcyc7XHJcbmltcG9ydCB7IENvbG9yTWFuYWdlbWVudCB9IGZyb20gJy4uL21hdGgvQ29sb3JNYW5hZ2VtZW50LmpzJztcclxuXHJcbmNsYXNzIFdlYkdMUmVuZGVyZXIge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggcGFyYW1ldGVycyA9IHt9ICkge1xyXG5cclxuXHRcdGNvbnN0IHtcclxuXHRcdFx0Y2FudmFzID0gY3JlYXRlQ2FudmFzRWxlbWVudCgpLFxyXG5cdFx0XHRjb250ZXh0ID0gbnVsbCxcclxuXHRcdFx0ZGVwdGggPSB0cnVlLFxyXG5cdFx0XHRzdGVuY2lsID0gdHJ1ZSxcclxuXHRcdFx0YWxwaGEgPSBmYWxzZSxcclxuXHRcdFx0YW50aWFsaWFzID0gZmFsc2UsXHJcblx0XHRcdHByZW11bHRpcGxpZWRBbHBoYSA9IHRydWUsXHJcblx0XHRcdHByZXNlcnZlRHJhd2luZ0J1ZmZlciA9IGZhbHNlLFxyXG5cdFx0XHRwb3dlclByZWZlcmVuY2UgPSAnZGVmYXVsdCcsXHJcblx0XHRcdGZhaWxJZk1ham9yUGVyZm9ybWFuY2VDYXZlYXQgPSBmYWxzZSxcclxuXHRcdH0gPSBwYXJhbWV0ZXJzO1xyXG5cclxuXHRcdHRoaXMuaXNXZWJHTFJlbmRlcmVyID0gdHJ1ZTtcclxuXHJcblx0XHRsZXQgX2FscGhhO1xyXG5cclxuXHRcdGlmICggY29udGV4dCAhPT0gbnVsbCApIHtcclxuXHJcblx0XHRcdF9hbHBoYSA9IGNvbnRleHQuZ2V0Q29udGV4dEF0dHJpYnV0ZXMoKS5hbHBoYTtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0X2FscGhhID0gYWxwaGE7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGNvbnN0IHVpbnRDbGVhckNvbG9yID0gbmV3IFVpbnQzMkFycmF5KCA0ICk7XHJcblx0XHRjb25zdCBpbnRDbGVhckNvbG9yID0gbmV3IEludDMyQXJyYXkoIDQgKTtcclxuXHJcblx0XHRsZXQgY3VycmVudFJlbmRlckxpc3QgPSBudWxsO1xyXG5cdFx0bGV0IGN1cnJlbnRSZW5kZXJTdGF0ZSA9IG51bGw7XHJcblxyXG5cdFx0Ly8gcmVuZGVyKCkgY2FuIGJlIGNhbGxlZCBmcm9tIHdpdGhpbiBhIGNhbGxiYWNrIHRyaWdnZXJlZCBieSBhbm90aGVyIHJlbmRlci5cclxuXHRcdC8vIFdlIHRyYWNrIHRoaXMgc28gdGhhdCB0aGUgbmVzdGVkIHJlbmRlciBjYWxsIGdldHMgaXRzIGxpc3QgYW5kIHN0YXRlIGlzb2xhdGVkIGZyb20gdGhlIHBhcmVudCByZW5kZXIgY2FsbC5cclxuXHJcblx0XHRjb25zdCByZW5kZXJMaXN0U3RhY2sgPSBbXTtcclxuXHRcdGNvbnN0IHJlbmRlclN0YXRlU3RhY2sgPSBbXTtcclxuXHJcblx0XHQvLyBwdWJsaWMgcHJvcGVydGllc1xyXG5cclxuXHRcdHRoaXMuZG9tRWxlbWVudCA9IGNhbnZhcztcclxuXHJcblx0XHQvLyBEZWJ1ZyBjb25maWd1cmF0aW9uIGNvbnRhaW5lclxyXG5cdFx0dGhpcy5kZWJ1ZyA9IHtcclxuXHJcblx0XHRcdC8qKlxyXG5cdFx0XHQgKiBFbmFibGVzIGVycm9yIGNoZWNraW5nIGFuZCByZXBvcnRpbmcgd2hlbiBzaGFkZXIgcHJvZ3JhbXMgYXJlIGJlaW5nIGNvbXBpbGVkXHJcblx0XHRcdCAqIEB0eXBlIHtib29sZWFufVxyXG5cdFx0XHQgKi9cclxuXHRcdFx0Y2hlY2tTaGFkZXJFcnJvcnM6IHRydWUsXHJcblx0XHRcdC8qKlxyXG5cdFx0XHQgKiBDYWxsYmFjayBmb3IgY3VzdG9tIGVycm9yIHJlcG9ydGluZy5cclxuXHRcdFx0ICogQHR5cGUgez9GdW5jdGlvbn1cclxuXHRcdFx0ICovXHJcblx0XHRcdG9uU2hhZGVyRXJyb3I6IG51bGxcclxuXHRcdH07XHJcblxyXG5cdFx0Ly8gY2xlYXJpbmdcclxuXHJcblx0XHR0aGlzLmF1dG9DbGVhciA9IHRydWU7XHJcblx0XHR0aGlzLmF1dG9DbGVhckNvbG9yID0gdHJ1ZTtcclxuXHRcdHRoaXMuYXV0b0NsZWFyRGVwdGggPSB0cnVlO1xyXG5cdFx0dGhpcy5hdXRvQ2xlYXJTdGVuY2lsID0gdHJ1ZTtcclxuXHJcblx0XHQvLyBzY2VuZSBncmFwaFxyXG5cclxuXHRcdHRoaXMuc29ydE9iamVjdHMgPSB0cnVlO1xyXG5cclxuXHRcdC8vIHVzZXItZGVmaW5lZCBjbGlwcGluZ1xyXG5cclxuXHRcdHRoaXMuY2xpcHBpbmdQbGFuZXMgPSBbXTtcclxuXHRcdHRoaXMubG9jYWxDbGlwcGluZ0VuYWJsZWQgPSBmYWxzZTtcclxuXHJcblx0XHQvLyBwaHlzaWNhbGx5IGJhc2VkIHNoYWRpbmdcclxuXHJcblx0XHR0aGlzLl9vdXRwdXRDb2xvclNwYWNlID0gU1JHQkNvbG9yU3BhY2U7XHJcblxyXG5cdFx0Ly8gcGh5c2ljYWwgbGlnaHRzXHJcblxyXG5cdFx0dGhpcy5fdXNlTGVnYWN5TGlnaHRzID0gZmFsc2U7XHJcblxyXG5cdFx0Ly8gdG9uZSBtYXBwaW5nXHJcblxyXG5cdFx0dGhpcy50b25lTWFwcGluZyA9IE5vVG9uZU1hcHBpbmc7XHJcblx0XHR0aGlzLnRvbmVNYXBwaW5nRXhwb3N1cmUgPSAxLjA7XHJcblxyXG5cdFx0Ly8gaW50ZXJuYWwgcHJvcGVydGllc1xyXG5cclxuXHRcdGNvbnN0IF90aGlzID0gdGhpcztcclxuXHJcblx0XHRsZXQgX2lzQ29udGV4dExvc3QgPSBmYWxzZTtcclxuXHJcblx0XHQvLyBpbnRlcm5hbCBzdGF0ZSBjYWNoZVxyXG5cclxuXHRcdGxldCBfY3VycmVudEFjdGl2ZUN1YmVGYWNlID0gMDtcclxuXHRcdGxldCBfY3VycmVudEFjdGl2ZU1pcG1hcExldmVsID0gMDtcclxuXHRcdGxldCBfY3VycmVudFJlbmRlclRhcmdldCA9IG51bGw7XHJcblx0XHRsZXQgX2N1cnJlbnRNYXRlcmlhbElkID0gLSAxO1xyXG5cclxuXHRcdGxldCBfY3VycmVudENhbWVyYSA9IG51bGw7XHJcblxyXG5cdFx0Y29uc3QgX2N1cnJlbnRWaWV3cG9ydCA9IG5ldyBWZWN0b3I0KCk7XHJcblx0XHRjb25zdCBfY3VycmVudFNjaXNzb3IgPSBuZXcgVmVjdG9yNCgpO1xyXG5cdFx0bGV0IF9jdXJyZW50U2Npc3NvclRlc3QgPSBudWxsO1xyXG5cclxuXHRcdGNvbnN0IF9jdXJyZW50Q2xlYXJDb2xvciA9IG5ldyBDb2xvciggMHgwMDAwMDAgKTtcclxuXHRcdGxldCBfY3VycmVudENsZWFyQWxwaGEgPSAwO1xyXG5cclxuXHRcdC8vXHJcblxyXG5cdFx0bGV0IF93aWR0aCA9IGNhbnZhcy53aWR0aDtcclxuXHRcdGxldCBfaGVpZ2h0ID0gY2FudmFzLmhlaWdodDtcclxuXHJcblx0XHRsZXQgX3BpeGVsUmF0aW8gPSAxO1xyXG5cdFx0bGV0IF9vcGFxdWVTb3J0ID0gbnVsbDtcclxuXHRcdGxldCBfdHJhbnNwYXJlbnRTb3J0ID0gbnVsbDtcclxuXHJcblx0XHRjb25zdCBfdmlld3BvcnQgPSBuZXcgVmVjdG9yNCggMCwgMCwgX3dpZHRoLCBfaGVpZ2h0ICk7XHJcblx0XHRjb25zdCBfc2Npc3NvciA9IG5ldyBWZWN0b3I0KCAwLCAwLCBfd2lkdGgsIF9oZWlnaHQgKTtcclxuXHRcdGxldCBfc2Npc3NvclRlc3QgPSBmYWxzZTtcclxuXHJcblx0XHQvLyBmcnVzdHVtXHJcblxyXG5cdFx0Y29uc3QgX2ZydXN0dW0gPSBuZXcgRnJ1c3R1bSgpO1xyXG5cclxuXHRcdC8vIGNsaXBwaW5nXHJcblxyXG5cdFx0bGV0IF9jbGlwcGluZ0VuYWJsZWQgPSBmYWxzZTtcclxuXHRcdGxldCBfbG9jYWxDbGlwcGluZ0VuYWJsZWQgPSBmYWxzZTtcclxuXHJcblx0XHQvLyB0cmFuc21pc3Npb25cclxuXHJcblx0XHRsZXQgX3RyYW5zbWlzc2lvblJlbmRlclRhcmdldCA9IG51bGw7XHJcblxyXG5cdFx0Ly8gY2FtZXJhIG1hdHJpY2VzIGNhY2hlXHJcblxyXG5cdFx0Y29uc3QgX3Byb2pTY3JlZW5NYXRyaXggPSBuZXcgTWF0cml4NCgpO1xyXG5cclxuXHRcdGNvbnN0IF92ZWN0b3IyID0gbmV3IFZlY3RvcjIoKTtcclxuXHRcdGNvbnN0IF92ZWN0b3IzID0gbmV3IFZlY3RvcjMoKTtcclxuXHJcblx0XHRjb25zdCBfZW1wdHlTY2VuZSA9IHsgYmFja2dyb3VuZDogbnVsbCwgZm9nOiBudWxsLCBlbnZpcm9ubWVudDogbnVsbCwgb3ZlcnJpZGVNYXRlcmlhbDogbnVsbCwgaXNTY2VuZTogdHJ1ZSB9O1xyXG5cclxuXHRcdGZ1bmN0aW9uIGdldFRhcmdldFBpeGVsUmF0aW8oKSB7XHJcblxyXG5cdFx0XHRyZXR1cm4gX2N1cnJlbnRSZW5kZXJUYXJnZXQgPT09IG51bGwgPyBfcGl4ZWxSYXRpbyA6IDE7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIGluaXRpYWxpemVcclxuXHJcblx0XHRsZXQgX2dsID0gY29udGV4dDtcclxuXHJcblx0XHRmdW5jdGlvbiBnZXRDb250ZXh0KCBjb250ZXh0TmFtZXMsIGNvbnRleHRBdHRyaWJ1dGVzICkge1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgY29udGV4dE5hbWVzLmxlbmd0aDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgY29udGV4dE5hbWUgPSBjb250ZXh0TmFtZXNbIGkgXTtcclxuXHRcdFx0XHRjb25zdCBjb250ZXh0ID0gY2FudmFzLmdldENvbnRleHQoIGNvbnRleHROYW1lLCBjb250ZXh0QXR0cmlidXRlcyApO1xyXG5cdFx0XHRcdGlmICggY29udGV4dCAhPT0gbnVsbCApIHJldHVybiBjb250ZXh0O1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0cmV0dXJuIG51bGw7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRyeSB7XHJcblxyXG5cdFx0XHRjb25zdCBjb250ZXh0QXR0cmlidXRlcyA9IHtcclxuXHRcdFx0XHRhbHBoYTogdHJ1ZSxcclxuXHRcdFx0XHRkZXB0aCxcclxuXHRcdFx0XHRzdGVuY2lsLFxyXG5cdFx0XHRcdGFudGlhbGlhcyxcclxuXHRcdFx0XHRwcmVtdWx0aXBsaWVkQWxwaGEsXHJcblx0XHRcdFx0cHJlc2VydmVEcmF3aW5nQnVmZmVyLFxyXG5cdFx0XHRcdHBvd2VyUHJlZmVyZW5jZSxcclxuXHRcdFx0XHRmYWlsSWZNYWpvclBlcmZvcm1hbmNlQ2F2ZWF0LFxyXG5cdFx0XHR9O1xyXG5cclxuXHRcdFx0Ly8gT2Zmc2NyZWVuQ2FudmFzIGRvZXMgbm90IGhhdmUgc2V0QXR0cmlidXRlLCBzZWUgIzIyODExXHJcblx0XHRcdGlmICggJ3NldEF0dHJpYnV0ZScgaW4gY2FudmFzICkgY2FudmFzLnNldEF0dHJpYnV0ZSggJ2RhdGEtZW5naW5lJywgYHRocmVlLmpzIHIke1JFVklTSU9OfWAgKTtcclxuXHJcblx0XHRcdC8vIGV2ZW50IGxpc3RlbmVycyBtdXN0IGJlIHJlZ2lzdGVyZWQgYmVmb3JlIFdlYkdMIGNvbnRleHQgaXMgY3JlYXRlZCwgc2VlICMxMjc1M1xyXG5cdFx0XHRjYW52YXMuYWRkRXZlbnRMaXN0ZW5lciggJ3dlYmdsY29udGV4dGxvc3QnLCBvbkNvbnRleHRMb3N0LCBmYWxzZSApO1xyXG5cdFx0XHRjYW52YXMuYWRkRXZlbnRMaXN0ZW5lciggJ3dlYmdsY29udGV4dHJlc3RvcmVkJywgb25Db250ZXh0UmVzdG9yZSwgZmFsc2UgKTtcclxuXHRcdFx0Y2FudmFzLmFkZEV2ZW50TGlzdGVuZXIoICd3ZWJnbGNvbnRleHRjcmVhdGlvbmVycm9yJywgb25Db250ZXh0Q3JlYXRpb25FcnJvciwgZmFsc2UgKTtcclxuXHJcblx0XHRcdGlmICggX2dsID09PSBudWxsICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBjb250ZXh0TmFtZXMgPSBbICd3ZWJnbDInLCAnd2ViZ2wnLCAnZXhwZXJpbWVudGFsLXdlYmdsJyBdO1xyXG5cclxuXHRcdFx0XHRpZiAoIF90aGlzLmlzV2ViR0wxUmVuZGVyZXIgPT09IHRydWUgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y29udGV4dE5hbWVzLnNoaWZ0KCk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0X2dsID0gZ2V0Q29udGV4dCggY29udGV4dE5hbWVzLCBjb250ZXh0QXR0cmlidXRlcyApO1xyXG5cclxuXHRcdFx0XHRpZiAoIF9nbCA9PT0gbnVsbCApIHtcclxuXHJcblx0XHRcdFx0XHRpZiAoIGdldENvbnRleHQoIGNvbnRleHROYW1lcyApICkge1xyXG5cclxuXHRcdFx0XHRcdFx0dGhyb3cgbmV3IEVycm9yKCAnRXJyb3IgY3JlYXRpbmcgV2ViR0wgY29udGV4dCB3aXRoIHlvdXIgc2VsZWN0ZWQgYXR0cmlidXRlcy4nICk7XHJcblxyXG5cdFx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRcdHRocm93IG5ldyBFcnJvciggJ0Vycm9yIGNyZWF0aW5nIFdlYkdMIGNvbnRleHQuJyApO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0aWYgKCB0eXBlb2YgV2ViR0xSZW5kZXJpbmdDb250ZXh0ICE9PSAndW5kZWZpbmVkJyAmJiBfZ2wgaW5zdGFuY2VvZiBXZWJHTFJlbmRlcmluZ0NvbnRleHQgKSB7IC8vIEBkZXByZWNhdGVkLCByMTUzXHJcblxyXG5cdFx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLldlYkdMUmVuZGVyZXI6IFdlYkdMIDEgc3VwcG9ydCB3YXMgZGVwcmVjYXRlZCBpbiByMTUzIGFuZCB3aWxsIGJlIHJlbW92ZWQgaW4gcjE2My4nICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyBTb21lIGV4cGVyaW1lbnRhbC13ZWJnbCBpbXBsZW1lbnRhdGlvbnMgZG8gbm90IGhhdmUgZ2V0U2hhZGVyUHJlY2lzaW9uRm9ybWF0XHJcblxyXG5cdFx0XHRpZiAoIF9nbC5nZXRTaGFkZXJQcmVjaXNpb25Gb3JtYXQgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0X2dsLmdldFNoYWRlclByZWNpc2lvbkZvcm1hdCA9IGZ1bmN0aW9uICgpIHtcclxuXHJcblx0XHRcdFx0XHRyZXR1cm4geyAncmFuZ2VNaW4nOiAxLCAncmFuZ2VNYXgnOiAxLCAncHJlY2lzaW9uJzogMSB9O1xyXG5cclxuXHRcdFx0XHR9O1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH0gY2F0Y2ggKCBlcnJvciApIHtcclxuXHJcblx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5XZWJHTFJlbmRlcmVyOiAnICsgZXJyb3IubWVzc2FnZSApO1xyXG5cdFx0XHR0aHJvdyBlcnJvcjtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0bGV0IGV4dGVuc2lvbnMsIGNhcGFiaWxpdGllcywgc3RhdGUsIGluZm87XHJcblx0XHRsZXQgcHJvcGVydGllcywgdGV4dHVyZXMsIGN1YmVtYXBzLCBjdWJldXZtYXBzLCBhdHRyaWJ1dGVzLCBnZW9tZXRyaWVzLCBvYmplY3RzO1xyXG5cdFx0bGV0IHByb2dyYW1DYWNoZSwgbWF0ZXJpYWxzLCByZW5kZXJMaXN0cywgcmVuZGVyU3RhdGVzLCBjbGlwcGluZywgc2hhZG93TWFwO1xyXG5cclxuXHRcdGxldCBiYWNrZ3JvdW5kLCBtb3JwaHRhcmdldHMsIGJ1ZmZlclJlbmRlcmVyLCBpbmRleGVkQnVmZmVyUmVuZGVyZXI7XHJcblxyXG5cdFx0bGV0IHV0aWxzLCBiaW5kaW5nU3RhdGVzLCB1bmlmb3Jtc0dyb3VwcztcclxuXHJcblx0XHRmdW5jdGlvbiBpbml0R0xDb250ZXh0KCkge1xyXG5cclxuXHRcdFx0ZXh0ZW5zaW9ucyA9IG5ldyBXZWJHTEV4dGVuc2lvbnMoIF9nbCApO1xyXG5cclxuXHRcdFx0Y2FwYWJpbGl0aWVzID0gbmV3IFdlYkdMQ2FwYWJpbGl0aWVzKCBfZ2wsIGV4dGVuc2lvbnMsIHBhcmFtZXRlcnMgKTtcclxuXHJcblx0XHRcdGV4dGVuc2lvbnMuaW5pdCggY2FwYWJpbGl0aWVzICk7XHJcblxyXG5cdFx0XHR1dGlscyA9IG5ldyBXZWJHTFV0aWxzKCBfZ2wsIGV4dGVuc2lvbnMsIGNhcGFiaWxpdGllcyApO1xyXG5cclxuXHRcdFx0c3RhdGUgPSBuZXcgV2ViR0xTdGF0ZSggX2dsLCBleHRlbnNpb25zLCBjYXBhYmlsaXRpZXMgKTtcclxuXHJcblx0XHRcdGluZm8gPSBuZXcgV2ViR0xJbmZvKCBfZ2wgKTtcclxuXHRcdFx0cHJvcGVydGllcyA9IG5ldyBXZWJHTFByb3BlcnRpZXMoKTtcclxuXHRcdFx0dGV4dHVyZXMgPSBuZXcgV2ViR0xUZXh0dXJlcyggX2dsLCBleHRlbnNpb25zLCBzdGF0ZSwgcHJvcGVydGllcywgY2FwYWJpbGl0aWVzLCB1dGlscywgaW5mbyApO1xyXG5cdFx0XHRjdWJlbWFwcyA9IG5ldyBXZWJHTEN1YmVNYXBzKCBfdGhpcyApO1xyXG5cdFx0XHRjdWJldXZtYXBzID0gbmV3IFdlYkdMQ3ViZVVWTWFwcyggX3RoaXMgKTtcclxuXHRcdFx0YXR0cmlidXRlcyA9IG5ldyBXZWJHTEF0dHJpYnV0ZXMoIF9nbCwgY2FwYWJpbGl0aWVzICk7XHJcblx0XHRcdGJpbmRpbmdTdGF0ZXMgPSBuZXcgV2ViR0xCaW5kaW5nU3RhdGVzKCBfZ2wsIGV4dGVuc2lvbnMsIGF0dHJpYnV0ZXMsIGNhcGFiaWxpdGllcyApO1xyXG5cdFx0XHRnZW9tZXRyaWVzID0gbmV3IFdlYkdMR2VvbWV0cmllcyggX2dsLCBhdHRyaWJ1dGVzLCBpbmZvLCBiaW5kaW5nU3RhdGVzICk7XHJcblx0XHRcdG9iamVjdHMgPSBuZXcgV2ViR0xPYmplY3RzKCBfZ2wsIGdlb21ldHJpZXMsIGF0dHJpYnV0ZXMsIGluZm8gKTtcclxuXHRcdFx0bW9ycGh0YXJnZXRzID0gbmV3IFdlYkdMTW9ycGh0YXJnZXRzKCBfZ2wsIGNhcGFiaWxpdGllcywgdGV4dHVyZXMgKTtcclxuXHRcdFx0Y2xpcHBpbmcgPSBuZXcgV2ViR0xDbGlwcGluZyggcHJvcGVydGllcyApO1xyXG5cdFx0XHRwcm9ncmFtQ2FjaGUgPSBuZXcgV2ViR0xQcm9ncmFtcyggX3RoaXMsIGN1YmVtYXBzLCBjdWJldXZtYXBzLCBleHRlbnNpb25zLCBjYXBhYmlsaXRpZXMsIGJpbmRpbmdTdGF0ZXMsIGNsaXBwaW5nICk7XHJcblx0XHRcdG1hdGVyaWFscyA9IG5ldyBXZWJHTE1hdGVyaWFscyggX3RoaXMsIHByb3BlcnRpZXMgKTtcclxuXHRcdFx0cmVuZGVyTGlzdHMgPSBuZXcgV2ViR0xSZW5kZXJMaXN0cygpO1xyXG5cdFx0XHRyZW5kZXJTdGF0ZXMgPSBuZXcgV2ViR0xSZW5kZXJTdGF0ZXMoIGV4dGVuc2lvbnMsIGNhcGFiaWxpdGllcyApO1xyXG5cdFx0XHRiYWNrZ3JvdW5kID0gbmV3IFdlYkdMQmFja2dyb3VuZCggX3RoaXMsIGN1YmVtYXBzLCBjdWJldXZtYXBzLCBzdGF0ZSwgb2JqZWN0cywgX2FscGhhLCBwcmVtdWx0aXBsaWVkQWxwaGEgKTtcclxuXHRcdFx0c2hhZG93TWFwID0gbmV3IFdlYkdMU2hhZG93TWFwKCBfdGhpcywgb2JqZWN0cywgY2FwYWJpbGl0aWVzICk7XHJcblx0XHRcdHVuaWZvcm1zR3JvdXBzID0gbmV3IFdlYkdMVW5pZm9ybXNHcm91cHMoIF9nbCwgaW5mbywgY2FwYWJpbGl0aWVzLCBzdGF0ZSApO1xyXG5cclxuXHRcdFx0YnVmZmVyUmVuZGVyZXIgPSBuZXcgV2ViR0xCdWZmZXJSZW5kZXJlciggX2dsLCBleHRlbnNpb25zLCBpbmZvLCBjYXBhYmlsaXRpZXMgKTtcclxuXHRcdFx0aW5kZXhlZEJ1ZmZlclJlbmRlcmVyID0gbmV3IFdlYkdMSW5kZXhlZEJ1ZmZlclJlbmRlcmVyKCBfZ2wsIGV4dGVuc2lvbnMsIGluZm8sIGNhcGFiaWxpdGllcyApO1xyXG5cclxuXHRcdFx0aW5mby5wcm9ncmFtcyA9IHByb2dyYW1DYWNoZS5wcm9ncmFtcztcclxuXHJcblx0XHRcdF90aGlzLmNhcGFiaWxpdGllcyA9IGNhcGFiaWxpdGllcztcclxuXHRcdFx0X3RoaXMuZXh0ZW5zaW9ucyA9IGV4dGVuc2lvbnM7XHJcblx0XHRcdF90aGlzLnByb3BlcnRpZXMgPSBwcm9wZXJ0aWVzO1xyXG5cdFx0XHRfdGhpcy5yZW5kZXJMaXN0cyA9IHJlbmRlckxpc3RzO1xyXG5cdFx0XHRfdGhpcy5zaGFkb3dNYXAgPSBzaGFkb3dNYXA7XHJcblx0XHRcdF90aGlzLnN0YXRlID0gc3RhdGU7XHJcblx0XHRcdF90aGlzLmluZm8gPSBpbmZvO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpbml0R0xDb250ZXh0KCk7XHJcblxyXG5cdFx0Ly8geHJcclxuXHJcblx0XHRjb25zdCB4ciA9IG5ldyBXZWJYUk1hbmFnZXIoIF90aGlzLCBfZ2wgKTtcclxuXHJcblx0XHR0aGlzLnhyID0geHI7XHJcblxyXG5cdFx0Ly8gQVBJXHJcblxyXG5cdFx0dGhpcy5nZXRDb250ZXh0ID0gZnVuY3Rpb24gKCkge1xyXG5cclxuXHRcdFx0cmV0dXJuIF9nbDtcclxuXHJcblx0XHR9O1xyXG5cclxuXHRcdHRoaXMuZ2V0Q29udGV4dEF0dHJpYnV0ZXMgPSBmdW5jdGlvbiAoKSB7XHJcblxyXG5cdFx0XHRyZXR1cm4gX2dsLmdldENvbnRleHRBdHRyaWJ1dGVzKCk7XHJcblxyXG5cdFx0fTtcclxuXHJcblx0XHR0aGlzLmZvcmNlQ29udGV4dExvc3MgPSBmdW5jdGlvbiAoKSB7XHJcblxyXG5cdFx0XHRjb25zdCBleHRlbnNpb24gPSBleHRlbnNpb25zLmdldCggJ1dFQkdMX2xvc2VfY29udGV4dCcgKTtcclxuXHRcdFx0aWYgKCBleHRlbnNpb24gKSBleHRlbnNpb24ubG9zZUNvbnRleHQoKTtcclxuXHJcblx0XHR9O1xyXG5cclxuXHRcdHRoaXMuZm9yY2VDb250ZXh0UmVzdG9yZSA9IGZ1bmN0aW9uICgpIHtcclxuXHJcblx0XHRcdGNvbnN0IGV4dGVuc2lvbiA9IGV4dGVuc2lvbnMuZ2V0KCAnV0VCR0xfbG9zZV9jb250ZXh0JyApO1xyXG5cdFx0XHRpZiAoIGV4dGVuc2lvbiApIGV4dGVuc2lvbi5yZXN0b3JlQ29udGV4dCgpO1xyXG5cclxuXHRcdH07XHJcblxyXG5cdFx0dGhpcy5nZXRQaXhlbFJhdGlvID0gZnVuY3Rpb24gKCkge1xyXG5cclxuXHRcdFx0cmV0dXJuIF9waXhlbFJhdGlvO1xyXG5cclxuXHRcdH07XHJcblxyXG5cdFx0dGhpcy5zZXRQaXhlbFJhdGlvID0gZnVuY3Rpb24gKCB2YWx1ZSApIHtcclxuXHJcblx0XHRcdGlmICggdmFsdWUgPT09IHVuZGVmaW5lZCApIHJldHVybjtcclxuXHJcblx0XHRcdF9waXhlbFJhdGlvID0gdmFsdWU7XHJcblxyXG5cdFx0XHR0aGlzLnNldFNpemUoIF93aWR0aCwgX2hlaWdodCwgZmFsc2UgKTtcclxuXHJcblx0XHR9O1xyXG5cclxuXHRcdHRoaXMuZ2V0U2l6ZSA9IGZ1bmN0aW9uICggdGFyZ2V0ICkge1xyXG5cclxuXHRcdFx0cmV0dXJuIHRhcmdldC5zZXQoIF93aWR0aCwgX2hlaWdodCApO1xyXG5cclxuXHRcdH07XHJcblxyXG5cdFx0dGhpcy5zZXRTaXplID0gZnVuY3Rpb24gKCB3aWR0aCwgaGVpZ2h0LCB1cGRhdGVTdHlsZSA9IHRydWUgKSB7XHJcblxyXG5cdFx0XHRpZiAoIHhyLmlzUHJlc2VudGluZyApIHtcclxuXHJcblx0XHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuV2ViR0xSZW5kZXJlcjogQ2FuXFwndCBjaGFuZ2Ugc2l6ZSB3aGlsZSBWUiBkZXZpY2UgaXMgcHJlc2VudGluZy4nICk7XHJcblx0XHRcdFx0cmV0dXJuO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0X3dpZHRoID0gd2lkdGg7XHJcblx0XHRcdF9oZWlnaHQgPSBoZWlnaHQ7XHJcblxyXG5cdFx0XHRjYW52YXMud2lkdGggPSBNYXRoLmZsb29yKCB3aWR0aCAqIF9waXhlbFJhdGlvICk7XHJcblx0XHRcdGNhbnZhcy5oZWlnaHQgPSBNYXRoLmZsb29yKCBoZWlnaHQgKiBfcGl4ZWxSYXRpbyApO1xyXG5cclxuXHRcdFx0aWYgKCB1cGRhdGVTdHlsZSA9PT0gdHJ1ZSApIHtcclxuXHJcblx0XHRcdFx0Y2FudmFzLnN0eWxlLndpZHRoID0gd2lkdGggKyAncHgnO1xyXG5cdFx0XHRcdGNhbnZhcy5zdHlsZS5oZWlnaHQgPSBoZWlnaHQgKyAncHgnO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0dGhpcy5zZXRWaWV3cG9ydCggMCwgMCwgd2lkdGgsIGhlaWdodCApO1xyXG5cclxuXHRcdH07XHJcblxyXG5cdFx0dGhpcy5nZXREcmF3aW5nQnVmZmVyU2l6ZSA9IGZ1bmN0aW9uICggdGFyZ2V0ICkge1xyXG5cclxuXHRcdFx0cmV0dXJuIHRhcmdldC5zZXQoIF93aWR0aCAqIF9waXhlbFJhdGlvLCBfaGVpZ2h0ICogX3BpeGVsUmF0aW8gKS5mbG9vcigpO1xyXG5cclxuXHRcdH07XHJcblxyXG5cdFx0dGhpcy5zZXREcmF3aW5nQnVmZmVyU2l6ZSA9IGZ1bmN0aW9uICggd2lkdGgsIGhlaWdodCwgcGl4ZWxSYXRpbyApIHtcclxuXHJcblx0XHRcdF93aWR0aCA9IHdpZHRoO1xyXG5cdFx0XHRfaGVpZ2h0ID0gaGVpZ2h0O1xyXG5cclxuXHRcdFx0X3BpeGVsUmF0aW8gPSBwaXhlbFJhdGlvO1xyXG5cclxuXHRcdFx0Y2FudmFzLndpZHRoID0gTWF0aC5mbG9vciggd2lkdGggKiBwaXhlbFJhdGlvICk7XHJcblx0XHRcdGNhbnZhcy5oZWlnaHQgPSBNYXRoLmZsb29yKCBoZWlnaHQgKiBwaXhlbFJhdGlvICk7XHJcblxyXG5cdFx0XHR0aGlzLnNldFZpZXdwb3J0KCAwLCAwLCB3aWR0aCwgaGVpZ2h0ICk7XHJcblxyXG5cdFx0fTtcclxuXHJcblx0XHR0aGlzLmdldEN1cnJlbnRWaWV3cG9ydCA9IGZ1bmN0aW9uICggdGFyZ2V0ICkge1xyXG5cclxuXHRcdFx0cmV0dXJuIHRhcmdldC5jb3B5KCBfY3VycmVudFZpZXdwb3J0ICk7XHJcblxyXG5cdFx0fTtcclxuXHJcblx0XHR0aGlzLmdldFZpZXdwb3J0ID0gZnVuY3Rpb24gKCB0YXJnZXQgKSB7XHJcblxyXG5cdFx0XHRyZXR1cm4gdGFyZ2V0LmNvcHkoIF92aWV3cG9ydCApO1xyXG5cclxuXHRcdH07XHJcblxyXG5cdFx0dGhpcy5zZXRWaWV3cG9ydCA9IGZ1bmN0aW9uICggeCwgeSwgd2lkdGgsIGhlaWdodCApIHtcclxuXHJcblx0XHRcdGlmICggeC5pc1ZlY3RvcjQgKSB7XHJcblxyXG5cdFx0XHRcdF92aWV3cG9ydC5zZXQoIHgueCwgeC55LCB4LnosIHgudyApO1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0X3ZpZXdwb3J0LnNldCggeCwgeSwgd2lkdGgsIGhlaWdodCApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0c3RhdGUudmlld3BvcnQoIF9jdXJyZW50Vmlld3BvcnQuY29weSggX3ZpZXdwb3J0ICkubXVsdGlwbHlTY2FsYXIoIF9waXhlbFJhdGlvICkuZmxvb3IoKSApO1xyXG5cclxuXHRcdH07XHJcblxyXG5cdFx0dGhpcy5nZXRTY2lzc29yID0gZnVuY3Rpb24gKCB0YXJnZXQgKSB7XHJcblxyXG5cdFx0XHRyZXR1cm4gdGFyZ2V0LmNvcHkoIF9zY2lzc29yICk7XHJcblxyXG5cdFx0fTtcclxuXHJcblx0XHR0aGlzLnNldFNjaXNzb3IgPSBmdW5jdGlvbiAoIHgsIHksIHdpZHRoLCBoZWlnaHQgKSB7XHJcblxyXG5cdFx0XHRpZiAoIHguaXNWZWN0b3I0ICkge1xyXG5cclxuXHRcdFx0XHRfc2Npc3Nvci5zZXQoIHgueCwgeC55LCB4LnosIHgudyApO1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0X3NjaXNzb3Iuc2V0KCB4LCB5LCB3aWR0aCwgaGVpZ2h0ICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRzdGF0ZS5zY2lzc29yKCBfY3VycmVudFNjaXNzb3IuY29weSggX3NjaXNzb3IgKS5tdWx0aXBseVNjYWxhciggX3BpeGVsUmF0aW8gKS5mbG9vcigpICk7XHJcblxyXG5cdFx0fTtcclxuXHJcblx0XHR0aGlzLmdldFNjaXNzb3JUZXN0ID0gZnVuY3Rpb24gKCkge1xyXG5cclxuXHRcdFx0cmV0dXJuIF9zY2lzc29yVGVzdDtcclxuXHJcblx0XHR9O1xyXG5cclxuXHRcdHRoaXMuc2V0U2Npc3NvclRlc3QgPSBmdW5jdGlvbiAoIGJvb2xlYW4gKSB7XHJcblxyXG5cdFx0XHRzdGF0ZS5zZXRTY2lzc29yVGVzdCggX3NjaXNzb3JUZXN0ID0gYm9vbGVhbiApO1xyXG5cclxuXHRcdH07XHJcblxyXG5cdFx0dGhpcy5zZXRPcGFxdWVTb3J0ID0gZnVuY3Rpb24gKCBtZXRob2QgKSB7XHJcblxyXG5cdFx0XHRfb3BhcXVlU29ydCA9IG1ldGhvZDtcclxuXHJcblx0XHR9O1xyXG5cclxuXHRcdHRoaXMuc2V0VHJhbnNwYXJlbnRTb3J0ID0gZnVuY3Rpb24gKCBtZXRob2QgKSB7XHJcblxyXG5cdFx0XHRfdHJhbnNwYXJlbnRTb3J0ID0gbWV0aG9kO1xyXG5cclxuXHRcdH07XHJcblxyXG5cdFx0Ly8gQ2xlYXJpbmdcclxuXHJcblx0XHR0aGlzLmdldENsZWFyQ29sb3IgPSBmdW5jdGlvbiAoIHRhcmdldCApIHtcclxuXHJcblx0XHRcdHJldHVybiB0YXJnZXQuY29weSggYmFja2dyb3VuZC5nZXRDbGVhckNvbG9yKCkgKTtcclxuXHJcblx0XHR9O1xyXG5cclxuXHRcdHRoaXMuc2V0Q2xlYXJDb2xvciA9IGZ1bmN0aW9uICgpIHtcclxuXHJcblx0XHRcdGJhY2tncm91bmQuc2V0Q2xlYXJDb2xvci5hcHBseSggYmFja2dyb3VuZCwgYXJndW1lbnRzICk7XHJcblxyXG5cdFx0fTtcclxuXHJcblx0XHR0aGlzLmdldENsZWFyQWxwaGEgPSBmdW5jdGlvbiAoKSB7XHJcblxyXG5cdFx0XHRyZXR1cm4gYmFja2dyb3VuZC5nZXRDbGVhckFscGhhKCk7XHJcblxyXG5cdFx0fTtcclxuXHJcblx0XHR0aGlzLnNldENsZWFyQWxwaGEgPSBmdW5jdGlvbiAoKSB7XHJcblxyXG5cdFx0XHRiYWNrZ3JvdW5kLnNldENsZWFyQWxwaGEuYXBwbHkoIGJhY2tncm91bmQsIGFyZ3VtZW50cyApO1xyXG5cclxuXHRcdH07XHJcblxyXG5cdFx0dGhpcy5jbGVhciA9IGZ1bmN0aW9uICggY29sb3IgPSB0cnVlLCBkZXB0aCA9IHRydWUsIHN0ZW5jaWwgPSB0cnVlICkge1xyXG5cclxuXHRcdFx0bGV0IGJpdHMgPSAwO1xyXG5cclxuXHRcdFx0aWYgKCBjb2xvciApIHtcclxuXHJcblx0XHRcdFx0Ly8gY2hlY2sgaWYgd2UncmUgdHJ5aW5nIHRvIGNsZWFyIGFuIGludGVnZXIgdGFyZ2V0XHJcblx0XHRcdFx0bGV0IGlzSW50ZWdlckZvcm1hdCA9IGZhbHNlO1xyXG5cdFx0XHRcdGlmICggX2N1cnJlbnRSZW5kZXJUYXJnZXQgIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgdGFyZ2V0Rm9ybWF0ID0gX2N1cnJlbnRSZW5kZXJUYXJnZXQudGV4dHVyZS5mb3JtYXQ7XHJcblx0XHRcdFx0XHRpc0ludGVnZXJGb3JtYXQgPSB0YXJnZXRGb3JtYXQgPT09IFJHQkFJbnRlZ2VyRm9ybWF0IHx8XHJcblx0XHRcdFx0XHRcdHRhcmdldEZvcm1hdCA9PT0gUkdJbnRlZ2VyRm9ybWF0IHx8XHJcblx0XHRcdFx0XHRcdHRhcmdldEZvcm1hdCA9PT0gUmVkSW50ZWdlckZvcm1hdDtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHQvLyB1c2UgdGhlIGFwcHJvcHJpYXRlIGNsZWFyIGZ1bmN0aW9ucyB0byBjbGVhciB0aGUgdGFyZ2V0IGlmIGl0J3MgYSBzaWduZWRcclxuXHRcdFx0XHQvLyBvciB1bnNpZ25lZCBpbnRlZ2VyIHRhcmdldFxyXG5cdFx0XHRcdGlmICggaXNJbnRlZ2VyRm9ybWF0ICkge1xyXG5cclxuXHRcdFx0XHRcdGNvbnN0IHRhcmdldFR5cGUgPSBfY3VycmVudFJlbmRlclRhcmdldC50ZXh0dXJlLnR5cGU7XHJcblx0XHRcdFx0XHRjb25zdCBpc1Vuc2lnbmVkVHlwZSA9IHRhcmdldFR5cGUgPT09IFVuc2lnbmVkQnl0ZVR5cGUgfHxcclxuXHRcdFx0XHRcdFx0dGFyZ2V0VHlwZSA9PT0gVW5zaWduZWRJbnRUeXBlIHx8XHJcblx0XHRcdFx0XHRcdHRhcmdldFR5cGUgPT09IFVuc2lnbmVkU2hvcnRUeXBlIHx8XHJcblx0XHRcdFx0XHRcdHRhcmdldFR5cGUgPT09IFVuc2lnbmVkSW50MjQ4VHlwZSB8fFxyXG5cdFx0XHRcdFx0XHR0YXJnZXRUeXBlID09PSBVbnNpZ25lZFNob3J0NDQ0NFR5cGUgfHxcclxuXHRcdFx0XHRcdFx0dGFyZ2V0VHlwZSA9PT0gVW5zaWduZWRTaG9ydDU1NTFUeXBlO1xyXG5cclxuXHRcdFx0XHRcdGNvbnN0IGNsZWFyQ29sb3IgPSBiYWNrZ3JvdW5kLmdldENsZWFyQ29sb3IoKTtcclxuXHRcdFx0XHRcdGNvbnN0IGEgPSBiYWNrZ3JvdW5kLmdldENsZWFyQWxwaGEoKTtcclxuXHRcdFx0XHRcdGNvbnN0IHIgPSBjbGVhckNvbG9yLnI7XHJcblx0XHRcdFx0XHRjb25zdCBnID0gY2xlYXJDb2xvci5nO1xyXG5cdFx0XHRcdFx0Y29uc3QgYiA9IGNsZWFyQ29sb3IuYjtcclxuXHJcblx0XHRcdFx0XHRpZiAoIGlzVW5zaWduZWRUeXBlICkge1xyXG5cclxuXHRcdFx0XHRcdFx0dWludENsZWFyQ29sb3JbIDAgXSA9IHI7XHJcblx0XHRcdFx0XHRcdHVpbnRDbGVhckNvbG9yWyAxIF0gPSBnO1xyXG5cdFx0XHRcdFx0XHR1aW50Q2xlYXJDb2xvclsgMiBdID0gYjtcclxuXHRcdFx0XHRcdFx0dWludENsZWFyQ29sb3JbIDMgXSA9IGE7XHJcblx0XHRcdFx0XHRcdF9nbC5jbGVhckJ1ZmZlcnVpdiggX2dsLkNPTE9SLCAwLCB1aW50Q2xlYXJDb2xvciApO1xyXG5cclxuXHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHRpbnRDbGVhckNvbG9yWyAwIF0gPSByO1xyXG5cdFx0XHRcdFx0XHRpbnRDbGVhckNvbG9yWyAxIF0gPSBnO1xyXG5cdFx0XHRcdFx0XHRpbnRDbGVhckNvbG9yWyAyIF0gPSBiO1xyXG5cdFx0XHRcdFx0XHRpbnRDbGVhckNvbG9yWyAzIF0gPSBhO1xyXG5cdFx0XHRcdFx0XHRfZ2wuY2xlYXJCdWZmZXJpdiggX2dsLkNPTE9SLCAwLCBpbnRDbGVhckNvbG9yICk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdGJpdHMgfD0gX2dsLkNPTE9SX0JVRkZFUl9CSVQ7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGlmICggZGVwdGggKSBiaXRzIHw9IF9nbC5ERVBUSF9CVUZGRVJfQklUO1xyXG5cdFx0XHRpZiAoIHN0ZW5jaWwgKSB7XHJcblxyXG5cdFx0XHRcdGJpdHMgfD0gX2dsLlNURU5DSUxfQlVGRkVSX0JJVDtcclxuXHRcdFx0XHR0aGlzLnN0YXRlLmJ1ZmZlcnMuc3RlbmNpbC5zZXRNYXNrKCAweGZmZmZmZmZmICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRfZ2wuY2xlYXIoIGJpdHMgKTtcclxuXHJcblx0XHR9O1xyXG5cclxuXHRcdHRoaXMuY2xlYXJDb2xvciA9IGZ1bmN0aW9uICgpIHtcclxuXHJcblx0XHRcdHRoaXMuY2xlYXIoIHRydWUsIGZhbHNlLCBmYWxzZSApO1xyXG5cclxuXHRcdH07XHJcblxyXG5cdFx0dGhpcy5jbGVhckRlcHRoID0gZnVuY3Rpb24gKCkge1xyXG5cclxuXHRcdFx0dGhpcy5jbGVhciggZmFsc2UsIHRydWUsIGZhbHNlICk7XHJcblxyXG5cdFx0fTtcclxuXHJcblx0XHR0aGlzLmNsZWFyU3RlbmNpbCA9IGZ1bmN0aW9uICgpIHtcclxuXHJcblx0XHRcdHRoaXMuY2xlYXIoIGZhbHNlLCBmYWxzZSwgdHJ1ZSApO1xyXG5cclxuXHRcdH07XHJcblxyXG5cdFx0Ly9cclxuXHJcblx0XHR0aGlzLmRpc3Bvc2UgPSBmdW5jdGlvbiAoKSB7XHJcblxyXG5cdFx0XHRjYW52YXMucmVtb3ZlRXZlbnRMaXN0ZW5lciggJ3dlYmdsY29udGV4dGxvc3QnLCBvbkNvbnRleHRMb3N0LCBmYWxzZSApO1xyXG5cdFx0XHRjYW52YXMucmVtb3ZlRXZlbnRMaXN0ZW5lciggJ3dlYmdsY29udGV4dHJlc3RvcmVkJywgb25Db250ZXh0UmVzdG9yZSwgZmFsc2UgKTtcclxuXHRcdFx0Y2FudmFzLnJlbW92ZUV2ZW50TGlzdGVuZXIoICd3ZWJnbGNvbnRleHRjcmVhdGlvbmVycm9yJywgb25Db250ZXh0Q3JlYXRpb25FcnJvciwgZmFsc2UgKTtcclxuXHJcblx0XHRcdHJlbmRlckxpc3RzLmRpc3Bvc2UoKTtcclxuXHRcdFx0cmVuZGVyU3RhdGVzLmRpc3Bvc2UoKTtcclxuXHRcdFx0cHJvcGVydGllcy5kaXNwb3NlKCk7XHJcblx0XHRcdGN1YmVtYXBzLmRpc3Bvc2UoKTtcclxuXHRcdFx0Y3ViZXV2bWFwcy5kaXNwb3NlKCk7XHJcblx0XHRcdG9iamVjdHMuZGlzcG9zZSgpO1xyXG5cdFx0XHRiaW5kaW5nU3RhdGVzLmRpc3Bvc2UoKTtcclxuXHRcdFx0dW5pZm9ybXNHcm91cHMuZGlzcG9zZSgpO1xyXG5cdFx0XHRwcm9ncmFtQ2FjaGUuZGlzcG9zZSgpO1xyXG5cclxuXHRcdFx0eHIuZGlzcG9zZSgpO1xyXG5cclxuXHRcdFx0eHIucmVtb3ZlRXZlbnRMaXN0ZW5lciggJ3Nlc3Npb25zdGFydCcsIG9uWFJTZXNzaW9uU3RhcnQgKTtcclxuXHRcdFx0eHIucmVtb3ZlRXZlbnRMaXN0ZW5lciggJ3Nlc3Npb25lbmQnLCBvblhSU2Vzc2lvbkVuZCApO1xyXG5cclxuXHRcdFx0aWYgKCBfdHJhbnNtaXNzaW9uUmVuZGVyVGFyZ2V0ICkge1xyXG5cclxuXHRcdFx0XHRfdHJhbnNtaXNzaW9uUmVuZGVyVGFyZ2V0LmRpc3Bvc2UoKTtcclxuXHRcdFx0XHRfdHJhbnNtaXNzaW9uUmVuZGVyVGFyZ2V0ID0gbnVsbDtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGFuaW1hdGlvbi5zdG9wKCk7XHJcblxyXG5cdFx0fTtcclxuXHJcblx0XHQvLyBFdmVudHNcclxuXHJcblx0XHRmdW5jdGlvbiBvbkNvbnRleHRMb3N0KCBldmVudCApIHtcclxuXHJcblx0XHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XHJcblxyXG5cdFx0XHRjb25zb2xlLmxvZyggJ1RIUkVFLldlYkdMUmVuZGVyZXI6IENvbnRleHQgTG9zdC4nICk7XHJcblxyXG5cdFx0XHRfaXNDb250ZXh0TG9zdCA9IHRydWU7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGZ1bmN0aW9uIG9uQ29udGV4dFJlc3RvcmUoIC8qIGV2ZW50ICovICkge1xyXG5cclxuXHRcdFx0Y29uc29sZS5sb2coICdUSFJFRS5XZWJHTFJlbmRlcmVyOiBDb250ZXh0IFJlc3RvcmVkLicgKTtcclxuXHJcblx0XHRcdF9pc0NvbnRleHRMb3N0ID0gZmFsc2U7XHJcblxyXG5cdFx0XHRjb25zdCBpbmZvQXV0b1Jlc2V0ID0gaW5mby5hdXRvUmVzZXQ7XHJcblx0XHRcdGNvbnN0IHNoYWRvd01hcEVuYWJsZWQgPSBzaGFkb3dNYXAuZW5hYmxlZDtcclxuXHRcdFx0Y29uc3Qgc2hhZG93TWFwQXV0b1VwZGF0ZSA9IHNoYWRvd01hcC5hdXRvVXBkYXRlO1xyXG5cdFx0XHRjb25zdCBzaGFkb3dNYXBOZWVkc1VwZGF0ZSA9IHNoYWRvd01hcC5uZWVkc1VwZGF0ZTtcclxuXHRcdFx0Y29uc3Qgc2hhZG93TWFwVHlwZSA9IHNoYWRvd01hcC50eXBlO1xyXG5cclxuXHRcdFx0aW5pdEdMQ29udGV4dCgpO1xyXG5cclxuXHRcdFx0aW5mby5hdXRvUmVzZXQgPSBpbmZvQXV0b1Jlc2V0O1xyXG5cdFx0XHRzaGFkb3dNYXAuZW5hYmxlZCA9IHNoYWRvd01hcEVuYWJsZWQ7XHJcblx0XHRcdHNoYWRvd01hcC5hdXRvVXBkYXRlID0gc2hhZG93TWFwQXV0b1VwZGF0ZTtcclxuXHRcdFx0c2hhZG93TWFwLm5lZWRzVXBkYXRlID0gc2hhZG93TWFwTmVlZHNVcGRhdGU7XHJcblx0XHRcdHNoYWRvd01hcC50eXBlID0gc2hhZG93TWFwVHlwZTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0ZnVuY3Rpb24gb25Db250ZXh0Q3JlYXRpb25FcnJvciggZXZlbnQgKSB7XHJcblxyXG5cdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuV2ViR0xSZW5kZXJlcjogQSBXZWJHTCBjb250ZXh0IGNvdWxkIG5vdCBiZSBjcmVhdGVkLiBSZWFzb246ICcsIGV2ZW50LnN0YXR1c01lc3NhZ2UgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0ZnVuY3Rpb24gb25NYXRlcmlhbERpc3Bvc2UoIGV2ZW50ICkge1xyXG5cclxuXHRcdFx0Y29uc3QgbWF0ZXJpYWwgPSBldmVudC50YXJnZXQ7XHJcblxyXG5cdFx0XHRtYXRlcmlhbC5yZW1vdmVFdmVudExpc3RlbmVyKCAnZGlzcG9zZScsIG9uTWF0ZXJpYWxEaXNwb3NlICk7XHJcblxyXG5cdFx0XHRkZWFsbG9jYXRlTWF0ZXJpYWwoIG1hdGVyaWFsICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIEJ1ZmZlciBkZWFsbG9jYXRpb25cclxuXHJcblx0XHRmdW5jdGlvbiBkZWFsbG9jYXRlTWF0ZXJpYWwoIG1hdGVyaWFsICkge1xyXG5cclxuXHRcdFx0cmVsZWFzZU1hdGVyaWFsUHJvZ3JhbVJlZmVyZW5jZXMoIG1hdGVyaWFsICk7XHJcblxyXG5cdFx0XHRwcm9wZXJ0aWVzLnJlbW92ZSggbWF0ZXJpYWwgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cclxuXHRcdGZ1bmN0aW9uIHJlbGVhc2VNYXRlcmlhbFByb2dyYW1SZWZlcmVuY2VzKCBtYXRlcmlhbCApIHtcclxuXHJcblx0XHRcdGNvbnN0IHByb2dyYW1zID0gcHJvcGVydGllcy5nZXQoIG1hdGVyaWFsICkucHJvZ3JhbXM7XHJcblxyXG5cdFx0XHRpZiAoIHByb2dyYW1zICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRcdHByb2dyYW1zLmZvckVhY2goIGZ1bmN0aW9uICggcHJvZ3JhbSApIHtcclxuXHJcblx0XHRcdFx0XHRwcm9ncmFtQ2FjaGUucmVsZWFzZVByb2dyYW0oIHByb2dyYW0gKTtcclxuXHJcblx0XHRcdFx0fSApO1xyXG5cclxuXHRcdFx0XHRpZiAoIG1hdGVyaWFsLmlzU2hhZGVyTWF0ZXJpYWwgKSB7XHJcblxyXG5cdFx0XHRcdFx0cHJvZ3JhbUNhY2hlLnJlbGVhc2VTaGFkZXJDYWNoZSggbWF0ZXJpYWwgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvLyBCdWZmZXIgcmVuZGVyaW5nXHJcblxyXG5cdFx0dGhpcy5yZW5kZXJCdWZmZXJEaXJlY3QgPSBmdW5jdGlvbiAoIGNhbWVyYSwgc2NlbmUsIGdlb21ldHJ5LCBtYXRlcmlhbCwgb2JqZWN0LCBncm91cCApIHtcclxuXHJcblx0XHRcdGlmICggc2NlbmUgPT09IG51bGwgKSBzY2VuZSA9IF9lbXB0eVNjZW5lOyAvLyByZW5kZXJCdWZmZXJEaXJlY3Qgc2Vjb25kIHBhcmFtZXRlciB1c2VkIHRvIGJlIGZvZyAoY291bGQgYmUgbnVsbClcclxuXHJcblx0XHRcdGNvbnN0IGZyb250RmFjZUNXID0gKCBvYmplY3QuaXNNZXNoICYmIG9iamVjdC5tYXRyaXhXb3JsZC5kZXRlcm1pbmFudCgpIDwgMCApO1xyXG5cclxuXHRcdFx0Y29uc3QgcHJvZ3JhbSA9IHNldFByb2dyYW0oIGNhbWVyYSwgc2NlbmUsIGdlb21ldHJ5LCBtYXRlcmlhbCwgb2JqZWN0ICk7XHJcblxyXG5cdFx0XHRzdGF0ZS5zZXRNYXRlcmlhbCggbWF0ZXJpYWwsIGZyb250RmFjZUNXICk7XHJcblxyXG5cdFx0XHQvL1xyXG5cclxuXHRcdFx0bGV0IGluZGV4ID0gZ2VvbWV0cnkuaW5kZXg7XHJcblx0XHRcdGxldCByYW5nZUZhY3RvciA9IDE7XHJcblxyXG5cdFx0XHRpZiAoIG1hdGVyaWFsLndpcmVmcmFtZSA9PT0gdHJ1ZSApIHtcclxuXHJcblx0XHRcdFx0aW5kZXggPSBnZW9tZXRyaWVzLmdldFdpcmVmcmFtZUF0dHJpYnV0ZSggZ2VvbWV0cnkgKTtcclxuXHJcblx0XHRcdFx0aWYgKCBpbmRleCA9PT0gdW5kZWZpbmVkICkgcmV0dXJuO1xyXG5cclxuXHRcdFx0XHRyYW5nZUZhY3RvciA9IDI7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvL1xyXG5cclxuXHRcdFx0Y29uc3QgZHJhd1JhbmdlID0gZ2VvbWV0cnkuZHJhd1JhbmdlO1xyXG5cdFx0XHRjb25zdCBwb3NpdGlvbiA9IGdlb21ldHJ5LmF0dHJpYnV0ZXMucG9zaXRpb247XHJcblxyXG5cdFx0XHRsZXQgZHJhd1N0YXJ0ID0gZHJhd1JhbmdlLnN0YXJ0ICogcmFuZ2VGYWN0b3I7XHJcblx0XHRcdGxldCBkcmF3RW5kID0gKCBkcmF3UmFuZ2Uuc3RhcnQgKyBkcmF3UmFuZ2UuY291bnQgKSAqIHJhbmdlRmFjdG9yO1xyXG5cclxuXHRcdFx0aWYgKCBncm91cCAhPT0gbnVsbCApIHtcclxuXHJcblx0XHRcdFx0ZHJhd1N0YXJ0ID0gTWF0aC5tYXgoIGRyYXdTdGFydCwgZ3JvdXAuc3RhcnQgKiByYW5nZUZhY3RvciApO1xyXG5cdFx0XHRcdGRyYXdFbmQgPSBNYXRoLm1pbiggZHJhd0VuZCwgKCBncm91cC5zdGFydCArIGdyb3VwLmNvdW50ICkgKiByYW5nZUZhY3RvciApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0aWYgKCBpbmRleCAhPT0gbnVsbCApIHtcclxuXHJcblx0XHRcdFx0ZHJhd1N0YXJ0ID0gTWF0aC5tYXgoIGRyYXdTdGFydCwgMCApO1xyXG5cdFx0XHRcdGRyYXdFbmQgPSBNYXRoLm1pbiggZHJhd0VuZCwgaW5kZXguY291bnQgKTtcclxuXHJcblx0XHRcdH0gZWxzZSBpZiAoIHBvc2l0aW9uICE9PSB1bmRlZmluZWQgJiYgcG9zaXRpb24gIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdGRyYXdTdGFydCA9IE1hdGgubWF4KCBkcmF3U3RhcnQsIDAgKTtcclxuXHRcdFx0XHRkcmF3RW5kID0gTWF0aC5taW4oIGRyYXdFbmQsIHBvc2l0aW9uLmNvdW50ICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRjb25zdCBkcmF3Q291bnQgPSBkcmF3RW5kIC0gZHJhd1N0YXJ0O1xyXG5cclxuXHRcdFx0aWYgKCBkcmF3Q291bnQgPCAwIHx8IGRyYXdDb3VudCA9PT0gSW5maW5pdHkgKSByZXR1cm47XHJcblxyXG5cdFx0XHQvL1xyXG5cclxuXHRcdFx0YmluZGluZ1N0YXRlcy5zZXR1cCggb2JqZWN0LCBtYXRlcmlhbCwgcHJvZ3JhbSwgZ2VvbWV0cnksIGluZGV4ICk7XHJcblxyXG5cdFx0XHRsZXQgYXR0cmlidXRlO1xyXG5cdFx0XHRsZXQgcmVuZGVyZXIgPSBidWZmZXJSZW5kZXJlcjtcclxuXHJcblx0XHRcdGlmICggaW5kZXggIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdGF0dHJpYnV0ZSA9IGF0dHJpYnV0ZXMuZ2V0KCBpbmRleCApO1xyXG5cclxuXHRcdFx0XHRyZW5kZXJlciA9IGluZGV4ZWRCdWZmZXJSZW5kZXJlcjtcclxuXHRcdFx0XHRyZW5kZXJlci5zZXRJbmRleCggYXR0cmlidXRlICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvL1xyXG5cclxuXHRcdFx0aWYgKCBvYmplY3QuaXNNZXNoICkge1xyXG5cclxuXHRcdFx0XHRpZiAoIG1hdGVyaWFsLndpcmVmcmFtZSA9PT0gdHJ1ZSApIHtcclxuXHJcblx0XHRcdFx0XHRzdGF0ZS5zZXRMaW5lV2lkdGgoIG1hdGVyaWFsLndpcmVmcmFtZUxpbmV3aWR0aCAqIGdldFRhcmdldFBpeGVsUmF0aW8oKSApO1xyXG5cdFx0XHRcdFx0cmVuZGVyZXIuc2V0TW9kZSggX2dsLkxJTkVTICk7XHJcblxyXG5cdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0cmVuZGVyZXIuc2V0TW9kZSggX2dsLlRSSUFOR0xFUyApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9IGVsc2UgaWYgKCBvYmplY3QuaXNMaW5lICkge1xyXG5cclxuXHRcdFx0XHRsZXQgbGluZVdpZHRoID0gbWF0ZXJpYWwubGluZXdpZHRoO1xyXG5cclxuXHRcdFx0XHRpZiAoIGxpbmVXaWR0aCA9PT0gdW5kZWZpbmVkICkgbGluZVdpZHRoID0gMTsgLy8gTm90IHVzaW5nIExpbmUqTWF0ZXJpYWxcclxuXHJcblx0XHRcdFx0c3RhdGUuc2V0TGluZVdpZHRoKCBsaW5lV2lkdGggKiBnZXRUYXJnZXRQaXhlbFJhdGlvKCkgKTtcclxuXHJcblx0XHRcdFx0aWYgKCBvYmplY3QuaXNMaW5lU2VnbWVudHMgKSB7XHJcblxyXG5cdFx0XHRcdFx0cmVuZGVyZXIuc2V0TW9kZSggX2dsLkxJTkVTICk7XHJcblxyXG5cdFx0XHRcdH0gZWxzZSBpZiAoIG9iamVjdC5pc0xpbmVMb29wICkge1xyXG5cclxuXHRcdFx0XHRcdHJlbmRlcmVyLnNldE1vZGUoIF9nbC5MSU5FX0xPT1AgKTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRyZW5kZXJlci5zZXRNb2RlKCBfZ2wuTElORV9TVFJJUCApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9IGVsc2UgaWYgKCBvYmplY3QuaXNQb2ludHMgKSB7XHJcblxyXG5cdFx0XHRcdHJlbmRlcmVyLnNldE1vZGUoIF9nbC5QT0lOVFMgKTtcclxuXHJcblx0XHRcdH0gZWxzZSBpZiAoIG9iamVjdC5pc1Nwcml0ZSApIHtcclxuXHJcblx0XHRcdFx0cmVuZGVyZXIuc2V0TW9kZSggX2dsLlRSSUFOR0xFUyApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0aWYgKCBvYmplY3QuaXNCYXRjaGVkTWVzaCApIHtcclxuXHJcblx0XHRcdFx0cmVuZGVyZXIucmVuZGVyTXVsdGlEcmF3KCBvYmplY3QuX211bHRpRHJhd1N0YXJ0cywgb2JqZWN0Ll9tdWx0aURyYXdDb3VudHMsIG9iamVjdC5fbXVsdGlEcmF3Q291bnQgKTtcclxuXHJcblx0XHRcdH0gZWxzZSBpZiAoIG9iamVjdC5pc0luc3RhbmNlZE1lc2ggKSB7XHJcblxyXG5cdFx0XHRcdHJlbmRlcmVyLnJlbmRlckluc3RhbmNlcyggZHJhd1N0YXJ0LCBkcmF3Q291bnQsIG9iamVjdC5jb3VudCApO1xyXG5cclxuXHRcdFx0fSBlbHNlIGlmICggZ2VvbWV0cnkuaXNJbnN0YW5jZWRCdWZmZXJHZW9tZXRyeSApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgbWF4SW5zdGFuY2VDb3VudCA9IGdlb21ldHJ5Ll9tYXhJbnN0YW5jZUNvdW50ICE9PSB1bmRlZmluZWQgPyBnZW9tZXRyeS5fbWF4SW5zdGFuY2VDb3VudCA6IEluZmluaXR5O1xyXG5cdFx0XHRcdGNvbnN0IGluc3RhbmNlQ291bnQgPSBNYXRoLm1pbiggZ2VvbWV0cnkuaW5zdGFuY2VDb3VudCwgbWF4SW5zdGFuY2VDb3VudCApO1xyXG5cclxuXHRcdFx0XHRyZW5kZXJlci5yZW5kZXJJbnN0YW5jZXMoIGRyYXdTdGFydCwgZHJhd0NvdW50LCBpbnN0YW5jZUNvdW50ICk7XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRyZW5kZXJlci5yZW5kZXIoIGRyYXdTdGFydCwgZHJhd0NvdW50ICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fTtcclxuXHJcblx0XHQvLyBDb21waWxlXHJcblxyXG5cdFx0ZnVuY3Rpb24gcHJlcGFyZU1hdGVyaWFsKCBtYXRlcmlhbCwgc2NlbmUsIG9iamVjdCApIHtcclxuXHJcblx0XHRcdGlmICggbWF0ZXJpYWwudHJhbnNwYXJlbnQgPT09IHRydWUgJiYgbWF0ZXJpYWwuc2lkZSA9PT0gRG91YmxlU2lkZSAmJiBtYXRlcmlhbC5mb3JjZVNpbmdsZVBhc3MgPT09IGZhbHNlICkge1xyXG5cclxuXHRcdFx0XHRtYXRlcmlhbC5zaWRlID0gQmFja1NpZGU7XHJcblx0XHRcdFx0bWF0ZXJpYWwubmVlZHNVcGRhdGUgPSB0cnVlO1xyXG5cdFx0XHRcdGdldFByb2dyYW0oIG1hdGVyaWFsLCBzY2VuZSwgb2JqZWN0ICk7XHJcblxyXG5cdFx0XHRcdG1hdGVyaWFsLnNpZGUgPSBGcm9udFNpZGU7XHJcblx0XHRcdFx0bWF0ZXJpYWwubmVlZHNVcGRhdGUgPSB0cnVlO1xyXG5cdFx0XHRcdGdldFByb2dyYW0oIG1hdGVyaWFsLCBzY2VuZSwgb2JqZWN0ICk7XHJcblxyXG5cdFx0XHRcdG1hdGVyaWFsLnNpZGUgPSBEb3VibGVTaWRlO1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0Z2V0UHJvZ3JhbSggbWF0ZXJpYWwsIHNjZW5lLCBvYmplY3QgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5jb21waWxlID0gZnVuY3Rpb24gKCBzY2VuZSwgY2FtZXJhLCB0YXJnZXRTY2VuZSA9IG51bGwgKSB7XHJcblxyXG5cdFx0XHRpZiAoIHRhcmdldFNjZW5lID09PSBudWxsICkgdGFyZ2V0U2NlbmUgPSBzY2VuZTtcclxuXHJcblx0XHRcdGN1cnJlbnRSZW5kZXJTdGF0ZSA9IHJlbmRlclN0YXRlcy5nZXQoIHRhcmdldFNjZW5lICk7XHJcblx0XHRcdGN1cnJlbnRSZW5kZXJTdGF0ZS5pbml0KCk7XHJcblxyXG5cdFx0XHRyZW5kZXJTdGF0ZVN0YWNrLnB1c2goIGN1cnJlbnRSZW5kZXJTdGF0ZSApO1xyXG5cclxuXHRcdFx0Ly8gZ2F0aGVyIGxpZ2h0cyBmcm9tIGJvdGggdGhlIHRhcmdldCBzY2VuZSBhbmQgdGhlIG5ldyBvYmplY3QgdGhhdCB3aWxsIGJlIGFkZGVkIHRvIHRoZSBzY2VuZS5cclxuXHJcblx0XHRcdHRhcmdldFNjZW5lLnRyYXZlcnNlVmlzaWJsZSggZnVuY3Rpb24gKCBvYmplY3QgKSB7XHJcblxyXG5cdFx0XHRcdGlmICggb2JqZWN0LmlzTGlnaHQgJiYgb2JqZWN0LmxheWVycy50ZXN0KCBjYW1lcmEubGF5ZXJzICkgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y3VycmVudFJlbmRlclN0YXRlLnB1c2hMaWdodCggb2JqZWN0ICk7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCBvYmplY3QuY2FzdFNoYWRvdyApIHtcclxuXHJcblx0XHRcdFx0XHRcdGN1cnJlbnRSZW5kZXJTdGF0ZS5wdXNoU2hhZG93KCBvYmplY3QgKTtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH0gKTtcclxuXHJcblx0XHRcdGlmICggc2NlbmUgIT09IHRhcmdldFNjZW5lICkge1xyXG5cclxuXHRcdFx0XHRzY2VuZS50cmF2ZXJzZVZpc2libGUoIGZ1bmN0aW9uICggb2JqZWN0ICkge1xyXG5cclxuXHRcdFx0XHRcdGlmICggb2JqZWN0LmlzTGlnaHQgJiYgb2JqZWN0LmxheWVycy50ZXN0KCBjYW1lcmEubGF5ZXJzICkgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRjdXJyZW50UmVuZGVyU3RhdGUucHVzaExpZ2h0KCBvYmplY3QgKTtcclxuXHJcblx0XHRcdFx0XHRcdGlmICggb2JqZWN0LmNhc3RTaGFkb3cgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdGN1cnJlbnRSZW5kZXJTdGF0ZS5wdXNoU2hhZG93KCBvYmplY3QgKTtcclxuXHJcblx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH0gKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGN1cnJlbnRSZW5kZXJTdGF0ZS5zZXR1cExpZ2h0cyggX3RoaXMuX3VzZUxlZ2FjeUxpZ2h0cyApO1xyXG5cclxuXHRcdFx0Ly8gT25seSBpbml0aWFsaXplIG1hdGVyaWFscyBpbiB0aGUgbmV3IHNjZW5lLCBub3QgdGhlIHRhcmdldFNjZW5lLlxyXG5cclxuXHRcdFx0Y29uc3QgbWF0ZXJpYWxzID0gbmV3IFNldCgpO1xyXG5cclxuXHRcdFx0c2NlbmUudHJhdmVyc2UoIGZ1bmN0aW9uICggb2JqZWN0ICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBtYXRlcmlhbCA9IG9iamVjdC5tYXRlcmlhbDtcclxuXHJcblx0XHRcdFx0aWYgKCBtYXRlcmlhbCApIHtcclxuXHJcblx0XHRcdFx0XHRpZiAoIEFycmF5LmlzQXJyYXkoIG1hdGVyaWFsICkgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBtYXRlcmlhbC5sZW5ndGg7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdGNvbnN0IG1hdGVyaWFsMiA9IG1hdGVyaWFsWyBpIF07XHJcblxyXG5cdFx0XHRcdFx0XHRcdHByZXBhcmVNYXRlcmlhbCggbWF0ZXJpYWwyLCB0YXJnZXRTY2VuZSwgb2JqZWN0ICk7XHJcblx0XHRcdFx0XHRcdFx0bWF0ZXJpYWxzLmFkZCggbWF0ZXJpYWwyICk7XHJcblxyXG5cdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRcdHByZXBhcmVNYXRlcmlhbCggbWF0ZXJpYWwsIHRhcmdldFNjZW5lLCBvYmplY3QgKTtcclxuXHRcdFx0XHRcdFx0bWF0ZXJpYWxzLmFkZCggbWF0ZXJpYWwgKTtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH0gKTtcclxuXHJcblx0XHRcdHJlbmRlclN0YXRlU3RhY2sucG9wKCk7XHJcblx0XHRcdGN1cnJlbnRSZW5kZXJTdGF0ZSA9IG51bGw7XHJcblxyXG5cdFx0XHRyZXR1cm4gbWF0ZXJpYWxzO1xyXG5cclxuXHRcdH07XHJcblxyXG5cdFx0Ly8gY29tcGlsZUFzeW5jXHJcblxyXG5cdFx0dGhpcy5jb21waWxlQXN5bmMgPSBmdW5jdGlvbiAoIHNjZW5lLCBjYW1lcmEsIHRhcmdldFNjZW5lID0gbnVsbCApIHtcclxuXHJcblx0XHRcdGNvbnN0IG1hdGVyaWFscyA9IHRoaXMuY29tcGlsZSggc2NlbmUsIGNhbWVyYSwgdGFyZ2V0U2NlbmUgKTtcclxuXHJcblx0XHRcdC8vIFdhaXQgZm9yIGFsbCB0aGUgbWF0ZXJpYWxzIGluIHRoZSBuZXcgb2JqZWN0IHRvIGluZGljYXRlIHRoYXQgdGhleSdyZVxyXG5cdFx0XHQvLyByZWFkeSB0byBiZSB1c2VkIGJlZm9yZSByZXNvbHZpbmcgdGhlIHByb21pc2UuXHJcblxyXG5cdFx0XHRyZXR1cm4gbmV3IFByb21pc2UoICggcmVzb2x2ZSApID0+IHtcclxuXHJcblx0XHRcdFx0ZnVuY3Rpb24gY2hlY2tNYXRlcmlhbHNSZWFkeSgpIHtcclxuXHJcblx0XHRcdFx0XHRtYXRlcmlhbHMuZm9yRWFjaCggZnVuY3Rpb24gKCBtYXRlcmlhbCApIHtcclxuXHJcblx0XHRcdFx0XHRcdGNvbnN0IG1hdGVyaWFsUHJvcGVydGllcyA9IHByb3BlcnRpZXMuZ2V0KCBtYXRlcmlhbCApO1xyXG5cdFx0XHRcdFx0XHRjb25zdCBwcm9ncmFtID0gbWF0ZXJpYWxQcm9wZXJ0aWVzLmN1cnJlbnRQcm9ncmFtO1xyXG5cclxuXHRcdFx0XHRcdFx0aWYgKCBwcm9ncmFtLmlzUmVhZHkoKSApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0Ly8gcmVtb3ZlIGFueSBwcm9ncmFtcyB0aGF0IHJlcG9ydCB0aGV5J3JlIHJlYWR5IHRvIHVzZSBmcm9tIHRoZSBsaXN0XHJcblx0XHRcdFx0XHRcdFx0bWF0ZXJpYWxzLmRlbGV0ZSggbWF0ZXJpYWwgKTtcclxuXHJcblx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHR9ICk7XHJcblxyXG5cdFx0XHRcdFx0Ly8gb25jZSB0aGUgbGlzdCBvZiBjb21waWxpbmcgbWF0ZXJpYWxzIGlzIGVtcHR5LCBjYWxsIHRoZSBjYWxsYmFja1xyXG5cclxuXHRcdFx0XHRcdGlmICggbWF0ZXJpYWxzLnNpemUgPT09IDAgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRyZXNvbHZlKCBzY2VuZSApO1xyXG5cdFx0XHRcdFx0XHRyZXR1cm47XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdC8vIGlmIHNvbWUgbWF0ZXJpYWxzIGFyZSBzdGlsbCBub3QgcmVhZHksIHdhaXQgYSBiaXQgYW5kIGNoZWNrIGFnYWluXHJcblxyXG5cdFx0XHRcdFx0c2V0VGltZW91dCggY2hlY2tNYXRlcmlhbHNSZWFkeSwgMTAgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRpZiAoIGV4dGVuc2lvbnMuZ2V0KCAnS0hSX3BhcmFsbGVsX3NoYWRlcl9jb21waWxlJyApICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0XHRcdC8vIElmIHdlIGNhbiBjaGVjayB0aGUgY29tcGlsYXRpb24gc3RhdHVzIG9mIHRoZSBtYXRlcmlhbHMgd2l0aG91dFxyXG5cdFx0XHRcdFx0Ly8gYmxvY2tpbmcgdGhlbiBkbyBzbyByaWdodCBhd2F5LlxyXG5cclxuXHRcdFx0XHRcdGNoZWNrTWF0ZXJpYWxzUmVhZHkoKTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHQvLyBPdGhlcndpc2Ugc3RhcnQgYnkgd2FpdGluZyBhIGJpdCB0byBnaXZlIHRoZSBtYXRlcmlhbHMgd2UganVzdFxyXG5cdFx0XHRcdFx0Ly8gaW5pdGlhbGl6ZWQgYSBjaGFuY2UgdG8gZmluaXNoLlxyXG5cclxuXHRcdFx0XHRcdHNldFRpbWVvdXQoIGNoZWNrTWF0ZXJpYWxzUmVhZHksIDEwICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH0gKTtcclxuXHJcblx0XHR9O1xyXG5cclxuXHRcdC8vIEFuaW1hdGlvbiBMb29wXHJcblxyXG5cdFx0bGV0IG9uQW5pbWF0aW9uRnJhbWVDYWxsYmFjayA9IG51bGw7XHJcblxyXG5cdFx0ZnVuY3Rpb24gb25BbmltYXRpb25GcmFtZSggdGltZSApIHtcclxuXHJcblx0XHRcdGlmICggb25BbmltYXRpb25GcmFtZUNhbGxiYWNrICkgb25BbmltYXRpb25GcmFtZUNhbGxiYWNrKCB0aW1lICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGZ1bmN0aW9uIG9uWFJTZXNzaW9uU3RhcnQoKSB7XHJcblxyXG5cdFx0XHRhbmltYXRpb24uc3RvcCgpO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRmdW5jdGlvbiBvblhSU2Vzc2lvbkVuZCgpIHtcclxuXHJcblx0XHRcdGFuaW1hdGlvbi5zdGFydCgpO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCBhbmltYXRpb24gPSBuZXcgV2ViR0xBbmltYXRpb24oKTtcclxuXHRcdGFuaW1hdGlvbi5zZXRBbmltYXRpb25Mb29wKCBvbkFuaW1hdGlvbkZyYW1lICk7XHJcblxyXG5cdFx0aWYgKCB0eXBlb2Ygc2VsZiAhPT0gJ3VuZGVmaW5lZCcgKSBhbmltYXRpb24uc2V0Q29udGV4dCggc2VsZiApO1xyXG5cclxuXHRcdHRoaXMuc2V0QW5pbWF0aW9uTG9vcCA9IGZ1bmN0aW9uICggY2FsbGJhY2sgKSB7XHJcblxyXG5cdFx0XHRvbkFuaW1hdGlvbkZyYW1lQ2FsbGJhY2sgPSBjYWxsYmFjaztcclxuXHRcdFx0eHIuc2V0QW5pbWF0aW9uTG9vcCggY2FsbGJhY2sgKTtcclxuXHJcblx0XHRcdCggY2FsbGJhY2sgPT09IG51bGwgKSA/IGFuaW1hdGlvbi5zdG9wKCkgOiBhbmltYXRpb24uc3RhcnQoKTtcclxuXHJcblx0XHR9O1xyXG5cclxuXHRcdHhyLmFkZEV2ZW50TGlzdGVuZXIoICdzZXNzaW9uc3RhcnQnLCBvblhSU2Vzc2lvblN0YXJ0ICk7XHJcblx0XHR4ci5hZGRFdmVudExpc3RlbmVyKCAnc2Vzc2lvbmVuZCcsIG9uWFJTZXNzaW9uRW5kICk7XHJcblxyXG5cdFx0Ly8gUmVuZGVyaW5nXHJcblxyXG5cdFx0dGhpcy5yZW5kZXIgPSBmdW5jdGlvbiAoIHNjZW5lLCBjYW1lcmEgKSB7XHJcblxyXG5cdFx0XHRpZiAoIGNhbWVyYSAhPT0gdW5kZWZpbmVkICYmIGNhbWVyYS5pc0NhbWVyYSAhPT0gdHJ1ZSApIHtcclxuXHJcblx0XHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLldlYkdMUmVuZGVyZXIucmVuZGVyOiBjYW1lcmEgaXMgbm90IGFuIGluc3RhbmNlIG9mIFRIUkVFLkNhbWVyYS4nICk7XHJcblx0XHRcdFx0cmV0dXJuO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0aWYgKCBfaXNDb250ZXh0TG9zdCA9PT0gdHJ1ZSApIHJldHVybjtcclxuXHJcblx0XHRcdC8vIHVwZGF0ZSBzY2VuZSBncmFwaFxyXG5cclxuXHRcdFx0aWYgKCBzY2VuZS5tYXRyaXhXb3JsZEF1dG9VcGRhdGUgPT09IHRydWUgKSBzY2VuZS51cGRhdGVNYXRyaXhXb3JsZCgpO1xyXG5cclxuXHRcdFx0Ly8gdXBkYXRlIGNhbWVyYSBtYXRyaWNlcyBhbmQgZnJ1c3R1bVxyXG5cclxuXHRcdFx0aWYgKCBjYW1lcmEucGFyZW50ID09PSBudWxsICYmIGNhbWVyYS5tYXRyaXhXb3JsZEF1dG9VcGRhdGUgPT09IHRydWUgKSBjYW1lcmEudXBkYXRlTWF0cml4V29ybGQoKTtcclxuXHJcblx0XHRcdGlmICggeHIuZW5hYmxlZCA9PT0gdHJ1ZSAmJiB4ci5pc1ByZXNlbnRpbmcgPT09IHRydWUgKSB7XHJcblxyXG5cdFx0XHRcdGlmICggeHIuY2FtZXJhQXV0b1VwZGF0ZSA9PT0gdHJ1ZSApIHhyLnVwZGF0ZUNhbWVyYSggY2FtZXJhICk7XHJcblxyXG5cdFx0XHRcdGNhbWVyYSA9IHhyLmdldENhbWVyYSgpOyAvLyB1c2UgWFIgY2FtZXJhIGZvciByZW5kZXJpbmdcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdC8vXHJcblx0XHRcdGlmICggc2NlbmUuaXNTY2VuZSA9PT0gdHJ1ZSApIHNjZW5lLm9uQmVmb3JlUmVuZGVyKCBfdGhpcywgc2NlbmUsIGNhbWVyYSwgX2N1cnJlbnRSZW5kZXJUYXJnZXQgKTtcclxuXHJcblx0XHRcdGN1cnJlbnRSZW5kZXJTdGF0ZSA9IHJlbmRlclN0YXRlcy5nZXQoIHNjZW5lLCByZW5kZXJTdGF0ZVN0YWNrLmxlbmd0aCApO1xyXG5cdFx0XHRjdXJyZW50UmVuZGVyU3RhdGUuaW5pdCgpO1xyXG5cclxuXHRcdFx0cmVuZGVyU3RhdGVTdGFjay5wdXNoKCBjdXJyZW50UmVuZGVyU3RhdGUgKTtcclxuXHJcblx0XHRcdF9wcm9qU2NyZWVuTWF0cml4Lm11bHRpcGx5TWF0cmljZXMoIGNhbWVyYS5wcm9qZWN0aW9uTWF0cml4LCBjYW1lcmEubWF0cml4V29ybGRJbnZlcnNlICk7XHJcblx0XHRcdF9mcnVzdHVtLnNldEZyb21Qcm9qZWN0aW9uTWF0cml4KCBfcHJvalNjcmVlbk1hdHJpeCApO1xyXG5cclxuXHRcdFx0X2xvY2FsQ2xpcHBpbmdFbmFibGVkID0gdGhpcy5sb2NhbENsaXBwaW5nRW5hYmxlZDtcclxuXHRcdFx0X2NsaXBwaW5nRW5hYmxlZCA9IGNsaXBwaW5nLmluaXQoIHRoaXMuY2xpcHBpbmdQbGFuZXMsIF9sb2NhbENsaXBwaW5nRW5hYmxlZCApO1xyXG5cclxuXHRcdFx0Y3VycmVudFJlbmRlckxpc3QgPSByZW5kZXJMaXN0cy5nZXQoIHNjZW5lLCByZW5kZXJMaXN0U3RhY2subGVuZ3RoICk7XHJcblx0XHRcdGN1cnJlbnRSZW5kZXJMaXN0LmluaXQoKTtcclxuXHJcblx0XHRcdHJlbmRlckxpc3RTdGFjay5wdXNoKCBjdXJyZW50UmVuZGVyTGlzdCApO1xyXG5cclxuXHRcdFx0cHJvamVjdE9iamVjdCggc2NlbmUsIGNhbWVyYSwgMCwgX3RoaXMuc29ydE9iamVjdHMgKTtcclxuXHJcblx0XHRcdGN1cnJlbnRSZW5kZXJMaXN0LmZpbmlzaCgpO1xyXG5cclxuXHRcdFx0aWYgKCBfdGhpcy5zb3J0T2JqZWN0cyA9PT0gdHJ1ZSApIHtcclxuXHJcblx0XHRcdFx0Y3VycmVudFJlbmRlckxpc3Quc29ydCggX29wYXF1ZVNvcnQsIF90cmFuc3BhcmVudFNvcnQgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdC8vXHJcblxyXG5cdFx0XHR0aGlzLmluZm8ucmVuZGVyLmZyYW1lICsrO1xyXG5cclxuXHRcdFx0aWYgKCBfY2xpcHBpbmdFbmFibGVkID09PSB0cnVlICkgY2xpcHBpbmcuYmVnaW5TaGFkb3dzKCk7XHJcblxyXG5cdFx0XHRjb25zdCBzaGFkb3dzQXJyYXkgPSBjdXJyZW50UmVuZGVyU3RhdGUuc3RhdGUuc2hhZG93c0FycmF5O1xyXG5cclxuXHRcdFx0c2hhZG93TWFwLnJlbmRlciggc2hhZG93c0FycmF5LCBzY2VuZSwgY2FtZXJhICk7XHJcblxyXG5cdFx0XHRpZiAoIF9jbGlwcGluZ0VuYWJsZWQgPT09IHRydWUgKSBjbGlwcGluZy5lbmRTaGFkb3dzKCk7XHJcblxyXG5cdFx0XHQvL1xyXG5cclxuXHRcdFx0aWYgKCB0aGlzLmluZm8uYXV0b1Jlc2V0ID09PSB0cnVlICkgdGhpcy5pbmZvLnJlc2V0KCk7XHJcblxyXG5cclxuXHRcdFx0Ly9cclxuXHJcblx0XHRcdGlmICggeHIuZW5hYmxlZCA9PT0gZmFsc2UgfHwgeHIuaXNQcmVzZW50aW5nID09PSBmYWxzZSB8fCB4ci5oYXNEZXB0aFNlbnNpbmcoKSA9PT0gZmFsc2UgKSB7XHJcblxyXG5cdFx0XHRcdGJhY2tncm91bmQucmVuZGVyKCBjdXJyZW50UmVuZGVyTGlzdCwgc2NlbmUgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdC8vIHJlbmRlciBzY2VuZVxyXG5cclxuXHRcdFx0Y3VycmVudFJlbmRlclN0YXRlLnNldHVwTGlnaHRzKCBfdGhpcy5fdXNlTGVnYWN5TGlnaHRzICk7XHJcblxyXG5cdFx0XHRpZiAoIGNhbWVyYS5pc0FycmF5Q2FtZXJhICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBjYW1lcmFzID0gY2FtZXJhLmNhbWVyYXM7XHJcblxyXG5cdFx0XHRcdGZvciAoIGxldCBpID0gMCwgbCA9IGNhbWVyYXMubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0XHRjb25zdCBjYW1lcmEyID0gY2FtZXJhc1sgaSBdO1xyXG5cclxuXHRcdFx0XHRcdHJlbmRlclNjZW5lKCBjdXJyZW50UmVuZGVyTGlzdCwgc2NlbmUsIGNhbWVyYTIsIGNhbWVyYTIudmlld3BvcnQgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0cmVuZGVyU2NlbmUoIGN1cnJlbnRSZW5kZXJMaXN0LCBzY2VuZSwgY2FtZXJhICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvL1xyXG5cclxuXHRcdFx0aWYgKCBfY3VycmVudFJlbmRlclRhcmdldCAhPT0gbnVsbCApIHtcclxuXHJcblx0XHRcdFx0Ly8gcmVzb2x2ZSBtdWx0aXNhbXBsZSByZW5kZXJidWZmZXJzIHRvIGEgc2luZ2xlLXNhbXBsZSB0ZXh0dXJlIGlmIG5lY2Vzc2FyeVxyXG5cclxuXHRcdFx0XHR0ZXh0dXJlcy51cGRhdGVNdWx0aXNhbXBsZVJlbmRlclRhcmdldCggX2N1cnJlbnRSZW5kZXJUYXJnZXQgKTtcclxuXHJcblx0XHRcdFx0Ly8gR2VuZXJhdGUgbWlwbWFwIGlmIHdlJ3JlIHVzaW5nIGFueSBraW5kIG9mIG1pcG1hcCBmaWx0ZXJpbmdcclxuXHJcblx0XHRcdFx0dGV4dHVyZXMudXBkYXRlUmVuZGVyVGFyZ2V0TWlwbWFwKCBfY3VycmVudFJlbmRlclRhcmdldCApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Ly9cclxuXHJcblx0XHRcdGlmICggc2NlbmUuaXNTY2VuZSA9PT0gdHJ1ZSApIHNjZW5lLm9uQWZ0ZXJSZW5kZXIoIF90aGlzLCBzY2VuZSwgY2FtZXJhICk7XHJcblxyXG5cdFx0XHQvLyBfZ2wuZmluaXNoKCk7XHJcblxyXG5cdFx0XHRiaW5kaW5nU3RhdGVzLnJlc2V0RGVmYXVsdFN0YXRlKCk7XHJcblx0XHRcdF9jdXJyZW50TWF0ZXJpYWxJZCA9IC0gMTtcclxuXHRcdFx0X2N1cnJlbnRDYW1lcmEgPSBudWxsO1xyXG5cclxuXHRcdFx0cmVuZGVyU3RhdGVTdGFjay5wb3AoKTtcclxuXHJcblx0XHRcdGlmICggcmVuZGVyU3RhdGVTdGFjay5sZW5ndGggPiAwICkge1xyXG5cclxuXHRcdFx0XHRjdXJyZW50UmVuZGVyU3RhdGUgPSByZW5kZXJTdGF0ZVN0YWNrWyByZW5kZXJTdGF0ZVN0YWNrLmxlbmd0aCAtIDEgXTtcclxuXHJcblx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdGN1cnJlbnRSZW5kZXJTdGF0ZSA9IG51bGw7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRyZW5kZXJMaXN0U3RhY2sucG9wKCk7XHJcblxyXG5cdFx0XHRpZiAoIHJlbmRlckxpc3RTdGFjay5sZW5ndGggPiAwICkge1xyXG5cclxuXHRcdFx0XHRjdXJyZW50UmVuZGVyTGlzdCA9IHJlbmRlckxpc3RTdGFja1sgcmVuZGVyTGlzdFN0YWNrLmxlbmd0aCAtIDEgXTtcclxuXHJcblx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdGN1cnJlbnRSZW5kZXJMaXN0ID0gbnVsbDtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9O1xyXG5cclxuXHRcdGZ1bmN0aW9uIHByb2plY3RPYmplY3QoIG9iamVjdCwgY2FtZXJhLCBncm91cE9yZGVyLCBzb3J0T2JqZWN0cyApIHtcclxuXHJcblx0XHRcdGlmICggb2JqZWN0LnZpc2libGUgPT09IGZhbHNlICkgcmV0dXJuO1xyXG5cclxuXHRcdFx0Y29uc3QgdmlzaWJsZSA9IG9iamVjdC5sYXllcnMudGVzdCggY2FtZXJhLmxheWVycyApO1xyXG5cclxuXHRcdFx0aWYgKCB2aXNpYmxlICkge1xyXG5cclxuXHRcdFx0XHRpZiAoIG9iamVjdC5pc0dyb3VwICkge1xyXG5cclxuXHRcdFx0XHRcdGdyb3VwT3JkZXIgPSBvYmplY3QucmVuZGVyT3JkZXI7XHJcblxyXG5cdFx0XHRcdH0gZWxzZSBpZiAoIG9iamVjdC5pc0xPRCApIHtcclxuXHJcblx0XHRcdFx0XHRpZiAoIG9iamVjdC5hdXRvVXBkYXRlID09PSB0cnVlICkgb2JqZWN0LnVwZGF0ZSggY2FtZXJhICk7XHJcblxyXG5cdFx0XHRcdH0gZWxzZSBpZiAoIG9iamVjdC5pc0xpZ2h0ICkge1xyXG5cclxuXHRcdFx0XHRcdGN1cnJlbnRSZW5kZXJTdGF0ZS5wdXNoTGlnaHQoIG9iamVjdCApO1xyXG5cclxuXHRcdFx0XHRcdGlmICggb2JqZWN0LmNhc3RTaGFkb3cgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRjdXJyZW50UmVuZGVyU3RhdGUucHVzaFNoYWRvdyggb2JqZWN0ICk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR9IGVsc2UgaWYgKCBvYmplY3QuaXNTcHJpdGUgKSB7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCAhIG9iamVjdC5mcnVzdHVtQ3VsbGVkIHx8IF9mcnVzdHVtLmludGVyc2VjdHNTcHJpdGUoIG9iamVjdCApICkge1xyXG5cclxuXHRcdFx0XHRcdFx0aWYgKCBzb3J0T2JqZWN0cyApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0X3ZlY3RvcjMuc2V0RnJvbU1hdHJpeFBvc2l0aW9uKCBvYmplY3QubWF0cml4V29ybGQgKVxyXG5cdFx0XHRcdFx0XHRcdFx0LmFwcGx5TWF0cml4NCggX3Byb2pTY3JlZW5NYXRyaXggKTtcclxuXHJcblx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRcdGNvbnN0IGdlb21ldHJ5ID0gb2JqZWN0cy51cGRhdGUoIG9iamVjdCApO1xyXG5cdFx0XHRcdFx0XHRjb25zdCBtYXRlcmlhbCA9IG9iamVjdC5tYXRlcmlhbDtcclxuXHJcblx0XHRcdFx0XHRcdGlmICggbWF0ZXJpYWwudmlzaWJsZSApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0Y3VycmVudFJlbmRlckxpc3QucHVzaCggb2JqZWN0LCBnZW9tZXRyeSwgbWF0ZXJpYWwsIGdyb3VwT3JkZXIsIF92ZWN0b3IzLnosIG51bGwgKTtcclxuXHJcblx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH0gZWxzZSBpZiAoIG9iamVjdC5pc01lc2ggfHwgb2JqZWN0LmlzTGluZSB8fCBvYmplY3QuaXNQb2ludHMgKSB7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCAhIG9iamVjdC5mcnVzdHVtQ3VsbGVkIHx8IF9mcnVzdHVtLmludGVyc2VjdHNPYmplY3QoIG9iamVjdCApICkge1xyXG5cclxuXHRcdFx0XHRcdFx0Y29uc3QgZ2VvbWV0cnkgPSBvYmplY3RzLnVwZGF0ZSggb2JqZWN0ICk7XHJcblx0XHRcdFx0XHRcdGNvbnN0IG1hdGVyaWFsID0gb2JqZWN0Lm1hdGVyaWFsO1xyXG5cclxuXHRcdFx0XHRcdFx0aWYgKCBzb3J0T2JqZWN0cyApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0aWYgKCBvYmplY3QuYm91bmRpbmdTcGhlcmUgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHRpZiAoIG9iamVjdC5ib3VuZGluZ1NwaGVyZSA9PT0gbnVsbCApIG9iamVjdC5jb21wdXRlQm91bmRpbmdTcGhlcmUoKTtcclxuXHRcdFx0XHRcdFx0XHRcdF92ZWN0b3IzLmNvcHkoIG9iamVjdC5ib3VuZGluZ1NwaGVyZS5jZW50ZXIgKTtcclxuXHJcblx0XHRcdFx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHRpZiAoIGdlb21ldHJ5LmJvdW5kaW5nU3BoZXJlID09PSBudWxsICkgZ2VvbWV0cnkuY29tcHV0ZUJvdW5kaW5nU3BoZXJlKCk7XHJcblx0XHRcdFx0XHRcdFx0XHRfdmVjdG9yMy5jb3B5KCBnZW9tZXRyeS5ib3VuZGluZ1NwaGVyZS5jZW50ZXIgKTtcclxuXHJcblx0XHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdFx0XHRfdmVjdG9yM1xyXG5cdFx0XHRcdFx0XHRcdFx0LmFwcGx5TWF0cml4NCggb2JqZWN0Lm1hdHJpeFdvcmxkIClcclxuXHRcdFx0XHRcdFx0XHRcdC5hcHBseU1hdHJpeDQoIF9wcm9qU2NyZWVuTWF0cml4ICk7XHJcblxyXG5cdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0XHRpZiAoIEFycmF5LmlzQXJyYXkoIG1hdGVyaWFsICkgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdGNvbnN0IGdyb3VwcyA9IGdlb21ldHJ5Lmdyb3VwcztcclxuXHJcblx0XHRcdFx0XHRcdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gZ3JvdXBzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0Y29uc3QgZ3JvdXAgPSBncm91cHNbIGkgXTtcclxuXHRcdFx0XHRcdFx0XHRcdGNvbnN0IGdyb3VwTWF0ZXJpYWwgPSBtYXRlcmlhbFsgZ3JvdXAubWF0ZXJpYWxJbmRleCBdO1xyXG5cclxuXHRcdFx0XHRcdFx0XHRcdGlmICggZ3JvdXBNYXRlcmlhbCAmJiBncm91cE1hdGVyaWFsLnZpc2libGUgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0XHRjdXJyZW50UmVuZGVyTGlzdC5wdXNoKCBvYmplY3QsIGdlb21ldHJ5LCBncm91cE1hdGVyaWFsLCBncm91cE9yZGVyLCBfdmVjdG9yMy56LCBncm91cCApO1xyXG5cclxuXHRcdFx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdFx0fSBlbHNlIGlmICggbWF0ZXJpYWwudmlzaWJsZSApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0Y3VycmVudFJlbmRlckxpc3QucHVzaCggb2JqZWN0LCBnZW9tZXRyeSwgbWF0ZXJpYWwsIGdyb3VwT3JkZXIsIF92ZWN0b3IzLnosIG51bGwgKTtcclxuXHJcblx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGNvbnN0IGNoaWxkcmVuID0gb2JqZWN0LmNoaWxkcmVuO1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gY2hpbGRyZW4ubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0cHJvamVjdE9iamVjdCggY2hpbGRyZW5bIGkgXSwgY2FtZXJhLCBncm91cE9yZGVyLCBzb3J0T2JqZWN0cyApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRmdW5jdGlvbiByZW5kZXJTY2VuZSggY3VycmVudFJlbmRlckxpc3QsIHNjZW5lLCBjYW1lcmEsIHZpZXdwb3J0ICkge1xyXG5cclxuXHRcdFx0Y29uc3Qgb3BhcXVlT2JqZWN0cyA9IGN1cnJlbnRSZW5kZXJMaXN0Lm9wYXF1ZTtcclxuXHRcdFx0Y29uc3QgdHJhbnNtaXNzaXZlT2JqZWN0cyA9IGN1cnJlbnRSZW5kZXJMaXN0LnRyYW5zbWlzc2l2ZTtcclxuXHRcdFx0Y29uc3QgdHJhbnNwYXJlbnRPYmplY3RzID0gY3VycmVudFJlbmRlckxpc3QudHJhbnNwYXJlbnQ7XHJcblxyXG5cdFx0XHRjdXJyZW50UmVuZGVyU3RhdGUuc2V0dXBMaWdodHNWaWV3KCBjYW1lcmEgKTtcclxuXHJcblx0XHRcdGlmICggX2NsaXBwaW5nRW5hYmxlZCA9PT0gdHJ1ZSApIGNsaXBwaW5nLnNldEdsb2JhbFN0YXRlKCBfdGhpcy5jbGlwcGluZ1BsYW5lcywgY2FtZXJhICk7XHJcblxyXG5cdFx0XHRpZiAoIHRyYW5zbWlzc2l2ZU9iamVjdHMubGVuZ3RoID4gMCApIHJlbmRlclRyYW5zbWlzc2lvblBhc3MoIG9wYXF1ZU9iamVjdHMsIHRyYW5zbWlzc2l2ZU9iamVjdHMsIHNjZW5lLCBjYW1lcmEgKTtcclxuXHJcblx0XHRcdGlmICggdmlld3BvcnQgKSBzdGF0ZS52aWV3cG9ydCggX2N1cnJlbnRWaWV3cG9ydC5jb3B5KCB2aWV3cG9ydCApICk7XHJcblxyXG5cdFx0XHRpZiAoIG9wYXF1ZU9iamVjdHMubGVuZ3RoID4gMCApIHJlbmRlck9iamVjdHMoIG9wYXF1ZU9iamVjdHMsIHNjZW5lLCBjYW1lcmEgKTtcclxuXHRcdFx0aWYgKCB0cmFuc21pc3NpdmVPYmplY3RzLmxlbmd0aCA+IDAgKSByZW5kZXJPYmplY3RzKCB0cmFuc21pc3NpdmVPYmplY3RzLCBzY2VuZSwgY2FtZXJhICk7XHJcblx0XHRcdGlmICggdHJhbnNwYXJlbnRPYmplY3RzLmxlbmd0aCA+IDAgKSByZW5kZXJPYmplY3RzKCB0cmFuc3BhcmVudE9iamVjdHMsIHNjZW5lLCBjYW1lcmEgKTtcclxuXHJcblx0XHRcdC8vIEVuc3VyZSBkZXB0aCBidWZmZXIgd3JpdGluZyBpcyBlbmFibGVkIHNvIGl0IGNhbiBiZSBjbGVhcmVkIG9uIG5leHQgcmVuZGVyXHJcblxyXG5cdFx0XHRzdGF0ZS5idWZmZXJzLmRlcHRoLnNldFRlc3QoIHRydWUgKTtcclxuXHRcdFx0c3RhdGUuYnVmZmVycy5kZXB0aC5zZXRNYXNrKCB0cnVlICk7XHJcblx0XHRcdHN0YXRlLmJ1ZmZlcnMuY29sb3Iuc2V0TWFzayggdHJ1ZSApO1xyXG5cclxuXHRcdFx0c3RhdGUuc2V0UG9seWdvbk9mZnNldCggZmFsc2UgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0ZnVuY3Rpb24gcmVuZGVyVHJhbnNtaXNzaW9uUGFzcyggb3BhcXVlT2JqZWN0cywgdHJhbnNtaXNzaXZlT2JqZWN0cywgc2NlbmUsIGNhbWVyYSApIHtcclxuXHJcblx0XHRcdGNvbnN0IG92ZXJyaWRlTWF0ZXJpYWwgPSBzY2VuZS5pc1NjZW5lID09PSB0cnVlID8gc2NlbmUub3ZlcnJpZGVNYXRlcmlhbCA6IG51bGw7XHJcblxyXG5cdFx0XHRpZiAoIG92ZXJyaWRlTWF0ZXJpYWwgIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdHJldHVybjtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGNvbnN0IGlzV2ViR0wyID0gY2FwYWJpbGl0aWVzLmlzV2ViR0wyO1xyXG5cclxuXHRcdFx0aWYgKCBfdHJhbnNtaXNzaW9uUmVuZGVyVGFyZ2V0ID09PSBudWxsICkge1xyXG5cclxuXHRcdFx0XHRfdHJhbnNtaXNzaW9uUmVuZGVyVGFyZ2V0ID0gbmV3IFdlYkdMUmVuZGVyVGFyZ2V0KCAxLCAxLCB7XHJcblx0XHRcdFx0XHRnZW5lcmF0ZU1pcG1hcHM6IHRydWUsXHJcblx0XHRcdFx0XHR0eXBlOiBleHRlbnNpb25zLmhhcyggJ0VYVF9jb2xvcl9idWZmZXJfaGFsZl9mbG9hdCcgKSA/IEhhbGZGbG9hdFR5cGUgOiBVbnNpZ25lZEJ5dGVUeXBlLFxyXG5cdFx0XHRcdFx0bWluRmlsdGVyOiBMaW5lYXJNaXBtYXBMaW5lYXJGaWx0ZXIsXHJcblx0XHRcdFx0XHRzYW1wbGVzOiAoIGlzV2ViR0wyICkgPyA0IDogMFxyXG5cdFx0XHRcdH0gKTtcclxuXHJcblx0XHRcdFx0Ly8gZGVidWdcclxuXHJcblx0XHRcdFx0LypcclxuXHRcdFx0XHRjb25zdCBnZW9tZXRyeSA9IG5ldyBQbGFuZUdlb21ldHJ5KCk7XHJcblx0XHRcdFx0Y29uc3QgbWF0ZXJpYWwgPSBuZXcgTWVzaEJhc2ljTWF0ZXJpYWwoIHsgbWFwOiBfdHJhbnNtaXNzaW9uUmVuZGVyVGFyZ2V0LnRleHR1cmUgfSApO1xyXG5cclxuXHRcdFx0XHRjb25zdCBtZXNoID0gbmV3IE1lc2goIGdlb21ldHJ5LCBtYXRlcmlhbCApO1xyXG5cdFx0XHRcdHNjZW5lLmFkZCggbWVzaCApO1xyXG5cdFx0XHRcdCovXHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRfdGhpcy5nZXREcmF3aW5nQnVmZmVyU2l6ZSggX3ZlY3RvcjIgKTtcclxuXHJcblx0XHRcdGlmICggaXNXZWJHTDIgKSB7XHJcblxyXG5cdFx0XHRcdF90cmFuc21pc3Npb25SZW5kZXJUYXJnZXQuc2V0U2l6ZSggX3ZlY3RvcjIueCwgX3ZlY3RvcjIueSApO1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0X3RyYW5zbWlzc2lvblJlbmRlclRhcmdldC5zZXRTaXplKCBmbG9vclBvd2VyT2ZUd28oIF92ZWN0b3IyLnggKSwgZmxvb3JQb3dlck9mVHdvKCBfdmVjdG9yMi55ICkgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdC8vXHJcblxyXG5cdFx0XHRjb25zdCBjdXJyZW50UmVuZGVyVGFyZ2V0ID0gX3RoaXMuZ2V0UmVuZGVyVGFyZ2V0KCk7XHJcblx0XHRcdF90aGlzLnNldFJlbmRlclRhcmdldCggX3RyYW5zbWlzc2lvblJlbmRlclRhcmdldCApO1xyXG5cclxuXHRcdFx0X3RoaXMuZ2V0Q2xlYXJDb2xvciggX2N1cnJlbnRDbGVhckNvbG9yICk7XHJcblx0XHRcdF9jdXJyZW50Q2xlYXJBbHBoYSA9IF90aGlzLmdldENsZWFyQWxwaGEoKTtcclxuXHRcdFx0aWYgKCBfY3VycmVudENsZWFyQWxwaGEgPCAxICkgX3RoaXMuc2V0Q2xlYXJDb2xvciggMHhmZmZmZmYsIDAuNSApO1xyXG5cclxuXHRcdFx0X3RoaXMuY2xlYXIoKTtcclxuXHJcblx0XHRcdC8vIFR1cm4gb2ZmIHRoZSBmZWF0dXJlcyB3aGljaCBjYW4gYWZmZWN0IHRoZSBmcmFnIGNvbG9yIGZvciBvcGFxdWUgb2JqZWN0cyBwYXNzLlxyXG5cdFx0XHQvLyBPdGhlcndpc2UgdGhleSBhcmUgYXBwbGllZCB0d2ljZSBpbiBvcGFxdWUgb2JqZWN0cyBwYXNzIGFuZCB0cmFuc21pc3Npb24gb2JqZWN0cyBwYXNzLlxyXG5cdFx0XHRjb25zdCBjdXJyZW50VG9uZU1hcHBpbmcgPSBfdGhpcy50b25lTWFwcGluZztcclxuXHRcdFx0X3RoaXMudG9uZU1hcHBpbmcgPSBOb1RvbmVNYXBwaW5nO1xyXG5cclxuXHRcdFx0cmVuZGVyT2JqZWN0cyggb3BhcXVlT2JqZWN0cywgc2NlbmUsIGNhbWVyYSApO1xyXG5cclxuXHRcdFx0dGV4dHVyZXMudXBkYXRlTXVsdGlzYW1wbGVSZW5kZXJUYXJnZXQoIF90cmFuc21pc3Npb25SZW5kZXJUYXJnZXQgKTtcclxuXHRcdFx0dGV4dHVyZXMudXBkYXRlUmVuZGVyVGFyZ2V0TWlwbWFwKCBfdHJhbnNtaXNzaW9uUmVuZGVyVGFyZ2V0ICk7XHJcblxyXG5cdFx0XHRsZXQgcmVuZGVyVGFyZ2V0TmVlZHNVcGRhdGUgPSBmYWxzZTtcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMCwgbCA9IHRyYW5zbWlzc2l2ZU9iamVjdHMubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgcmVuZGVySXRlbSA9IHRyYW5zbWlzc2l2ZU9iamVjdHNbIGkgXTtcclxuXHJcblx0XHRcdFx0Y29uc3Qgb2JqZWN0ID0gcmVuZGVySXRlbS5vYmplY3Q7XHJcblx0XHRcdFx0Y29uc3QgZ2VvbWV0cnkgPSByZW5kZXJJdGVtLmdlb21ldHJ5O1xyXG5cdFx0XHRcdGNvbnN0IG1hdGVyaWFsID0gcmVuZGVySXRlbS5tYXRlcmlhbDtcclxuXHRcdFx0XHRjb25zdCBncm91cCA9IHJlbmRlckl0ZW0uZ3JvdXA7XHJcblxyXG5cdFx0XHRcdGlmICggbWF0ZXJpYWwuc2lkZSA9PT0gRG91YmxlU2lkZSAmJiBvYmplY3QubGF5ZXJzLnRlc3QoIGNhbWVyYS5sYXllcnMgKSApIHtcclxuXHJcblx0XHRcdFx0XHRjb25zdCBjdXJyZW50U2lkZSA9IG1hdGVyaWFsLnNpZGU7XHJcblxyXG5cdFx0XHRcdFx0bWF0ZXJpYWwuc2lkZSA9IEJhY2tTaWRlO1xyXG5cdFx0XHRcdFx0bWF0ZXJpYWwubmVlZHNVcGRhdGUgPSB0cnVlO1xyXG5cclxuXHRcdFx0XHRcdHJlbmRlck9iamVjdCggb2JqZWN0LCBzY2VuZSwgY2FtZXJhLCBnZW9tZXRyeSwgbWF0ZXJpYWwsIGdyb3VwICk7XHJcblxyXG5cdFx0XHRcdFx0bWF0ZXJpYWwuc2lkZSA9IGN1cnJlbnRTaWRlO1xyXG5cdFx0XHRcdFx0bWF0ZXJpYWwubmVlZHNVcGRhdGUgPSB0cnVlO1xyXG5cclxuXHRcdFx0XHRcdHJlbmRlclRhcmdldE5lZWRzVXBkYXRlID0gdHJ1ZTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0aWYgKCByZW5kZXJUYXJnZXROZWVkc1VwZGF0ZSA9PT0gdHJ1ZSApIHtcclxuXHJcblx0XHRcdFx0dGV4dHVyZXMudXBkYXRlTXVsdGlzYW1wbGVSZW5kZXJUYXJnZXQoIF90cmFuc21pc3Npb25SZW5kZXJUYXJnZXQgKTtcclxuXHRcdFx0XHR0ZXh0dXJlcy51cGRhdGVSZW5kZXJUYXJnZXRNaXBtYXAoIF90cmFuc21pc3Npb25SZW5kZXJUYXJnZXQgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdF90aGlzLnNldFJlbmRlclRhcmdldCggY3VycmVudFJlbmRlclRhcmdldCApO1xyXG5cclxuXHRcdFx0X3RoaXMuc2V0Q2xlYXJDb2xvciggX2N1cnJlbnRDbGVhckNvbG9yLCBfY3VycmVudENsZWFyQWxwaGEgKTtcclxuXHJcblx0XHRcdF90aGlzLnRvbmVNYXBwaW5nID0gY3VycmVudFRvbmVNYXBwaW5nO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRmdW5jdGlvbiByZW5kZXJPYmplY3RzKCByZW5kZXJMaXN0LCBzY2VuZSwgY2FtZXJhICkge1xyXG5cclxuXHRcdFx0Y29uc3Qgb3ZlcnJpZGVNYXRlcmlhbCA9IHNjZW5lLmlzU2NlbmUgPT09IHRydWUgPyBzY2VuZS5vdmVycmlkZU1hdGVyaWFsIDogbnVsbDtcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMCwgbCA9IHJlbmRlckxpc3QubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgcmVuZGVySXRlbSA9IHJlbmRlckxpc3RbIGkgXTtcclxuXHJcblx0XHRcdFx0Y29uc3Qgb2JqZWN0ID0gcmVuZGVySXRlbS5vYmplY3Q7XHJcblx0XHRcdFx0Y29uc3QgZ2VvbWV0cnkgPSByZW5kZXJJdGVtLmdlb21ldHJ5O1xyXG5cdFx0XHRcdGNvbnN0IG1hdGVyaWFsID0gb3ZlcnJpZGVNYXRlcmlhbCA9PT0gbnVsbCA/IHJlbmRlckl0ZW0ubWF0ZXJpYWwgOiBvdmVycmlkZU1hdGVyaWFsO1xyXG5cdFx0XHRcdGNvbnN0IGdyb3VwID0gcmVuZGVySXRlbS5ncm91cDtcclxuXHJcblx0XHRcdFx0aWYgKCBvYmplY3QubGF5ZXJzLnRlc3QoIGNhbWVyYS5sYXllcnMgKSApIHtcclxuXHJcblx0XHRcdFx0XHRyZW5kZXJPYmplY3QoIG9iamVjdCwgc2NlbmUsIGNhbWVyYSwgZ2VvbWV0cnksIG1hdGVyaWFsLCBncm91cCApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGZ1bmN0aW9uIHJlbmRlck9iamVjdCggb2JqZWN0LCBzY2VuZSwgY2FtZXJhLCBnZW9tZXRyeSwgbWF0ZXJpYWwsIGdyb3VwICkge1xyXG5cclxuXHRcdFx0b2JqZWN0Lm9uQmVmb3JlUmVuZGVyKCBfdGhpcywgc2NlbmUsIGNhbWVyYSwgZ2VvbWV0cnksIG1hdGVyaWFsLCBncm91cCApO1xyXG5cclxuXHRcdFx0b2JqZWN0Lm1vZGVsVmlld01hdHJpeC5tdWx0aXBseU1hdHJpY2VzKCBjYW1lcmEubWF0cml4V29ybGRJbnZlcnNlLCBvYmplY3QubWF0cml4V29ybGQgKTtcclxuXHRcdFx0b2JqZWN0Lm5vcm1hbE1hdHJpeC5nZXROb3JtYWxNYXRyaXgoIG9iamVjdC5tb2RlbFZpZXdNYXRyaXggKTtcclxuXHJcblx0XHRcdG1hdGVyaWFsLm9uQmVmb3JlUmVuZGVyKCBfdGhpcywgc2NlbmUsIGNhbWVyYSwgZ2VvbWV0cnksIG9iamVjdCwgZ3JvdXAgKTtcclxuXHJcblx0XHRcdGlmICggbWF0ZXJpYWwudHJhbnNwYXJlbnQgPT09IHRydWUgJiYgbWF0ZXJpYWwuc2lkZSA9PT0gRG91YmxlU2lkZSAmJiBtYXRlcmlhbC5mb3JjZVNpbmdsZVBhc3MgPT09IGZhbHNlICkge1xyXG5cclxuXHRcdFx0XHRtYXRlcmlhbC5zaWRlID0gQmFja1NpZGU7XHJcblx0XHRcdFx0bWF0ZXJpYWwubmVlZHNVcGRhdGUgPSB0cnVlO1xyXG5cdFx0XHRcdF90aGlzLnJlbmRlckJ1ZmZlckRpcmVjdCggY2FtZXJhLCBzY2VuZSwgZ2VvbWV0cnksIG1hdGVyaWFsLCBvYmplY3QsIGdyb3VwICk7XHJcblxyXG5cdFx0XHRcdG1hdGVyaWFsLnNpZGUgPSBGcm9udFNpZGU7XHJcblx0XHRcdFx0bWF0ZXJpYWwubmVlZHNVcGRhdGUgPSB0cnVlO1xyXG5cdFx0XHRcdF90aGlzLnJlbmRlckJ1ZmZlckRpcmVjdCggY2FtZXJhLCBzY2VuZSwgZ2VvbWV0cnksIG1hdGVyaWFsLCBvYmplY3QsIGdyb3VwICk7XHJcblxyXG5cdFx0XHRcdG1hdGVyaWFsLnNpZGUgPSBEb3VibGVTaWRlO1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0X3RoaXMucmVuZGVyQnVmZmVyRGlyZWN0KCBjYW1lcmEsIHNjZW5lLCBnZW9tZXRyeSwgbWF0ZXJpYWwsIG9iamVjdCwgZ3JvdXAgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdG9iamVjdC5vbkFmdGVyUmVuZGVyKCBfdGhpcywgc2NlbmUsIGNhbWVyYSwgZ2VvbWV0cnksIG1hdGVyaWFsLCBncm91cCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRmdW5jdGlvbiBnZXRQcm9ncmFtKCBtYXRlcmlhbCwgc2NlbmUsIG9iamVjdCApIHtcclxuXHJcblx0XHRcdGlmICggc2NlbmUuaXNTY2VuZSAhPT0gdHJ1ZSApIHNjZW5lID0gX2VtcHR5U2NlbmU7IC8vIHNjZW5lIGNvdWxkIGJlIGEgTWVzaCwgTGluZSwgUG9pbnRzLCAuLi5cclxuXHJcblx0XHRcdGNvbnN0IG1hdGVyaWFsUHJvcGVydGllcyA9IHByb3BlcnRpZXMuZ2V0KCBtYXRlcmlhbCApO1xyXG5cclxuXHRcdFx0Y29uc3QgbGlnaHRzID0gY3VycmVudFJlbmRlclN0YXRlLnN0YXRlLmxpZ2h0cztcclxuXHRcdFx0Y29uc3Qgc2hhZG93c0FycmF5ID0gY3VycmVudFJlbmRlclN0YXRlLnN0YXRlLnNoYWRvd3NBcnJheTtcclxuXHJcblx0XHRcdGNvbnN0IGxpZ2h0c1N0YXRlVmVyc2lvbiA9IGxpZ2h0cy5zdGF0ZS52ZXJzaW9uO1xyXG5cclxuXHRcdFx0Y29uc3QgcGFyYW1ldGVycyA9IHByb2dyYW1DYWNoZS5nZXRQYXJhbWV0ZXJzKCBtYXRlcmlhbCwgbGlnaHRzLnN0YXRlLCBzaGFkb3dzQXJyYXksIHNjZW5lLCBvYmplY3QgKTtcclxuXHRcdFx0Y29uc3QgcHJvZ3JhbUNhY2hlS2V5ID0gcHJvZ3JhbUNhY2hlLmdldFByb2dyYW1DYWNoZUtleSggcGFyYW1ldGVycyApO1xyXG5cclxuXHRcdFx0bGV0IHByb2dyYW1zID0gbWF0ZXJpYWxQcm9wZXJ0aWVzLnByb2dyYW1zO1xyXG5cclxuXHRcdFx0Ly8gYWx3YXlzIHVwZGF0ZSBlbnZpcm9ubWVudCBhbmQgZm9nIC0gY2hhbmdpbmcgdGhlc2UgdHJpZ2dlciBhbiBnZXRQcm9ncmFtIGNhbGwsIGJ1dCBpdCdzIHBvc3NpYmxlIHRoYXQgdGhlIHByb2dyYW0gZG9lc24ndCBjaGFuZ2VcclxuXHJcblx0XHRcdG1hdGVyaWFsUHJvcGVydGllcy5lbnZpcm9ubWVudCA9IG1hdGVyaWFsLmlzTWVzaFN0YW5kYXJkTWF0ZXJpYWwgPyBzY2VuZS5lbnZpcm9ubWVudCA6IG51bGw7XHJcblx0XHRcdG1hdGVyaWFsUHJvcGVydGllcy5mb2cgPSBzY2VuZS5mb2c7XHJcblx0XHRcdG1hdGVyaWFsUHJvcGVydGllcy5lbnZNYXAgPSAoIG1hdGVyaWFsLmlzTWVzaFN0YW5kYXJkTWF0ZXJpYWwgPyBjdWJldXZtYXBzIDogY3ViZW1hcHMgKS5nZXQoIG1hdGVyaWFsLmVudk1hcCB8fCBtYXRlcmlhbFByb3BlcnRpZXMuZW52aXJvbm1lbnQgKTtcclxuXHJcblx0XHRcdGlmICggcHJvZ3JhbXMgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0Ly8gbmV3IG1hdGVyaWFsXHJcblxyXG5cdFx0XHRcdG1hdGVyaWFsLmFkZEV2ZW50TGlzdGVuZXIoICdkaXNwb3NlJywgb25NYXRlcmlhbERpc3Bvc2UgKTtcclxuXHJcblx0XHRcdFx0cHJvZ3JhbXMgPSBuZXcgTWFwKCk7XHJcblx0XHRcdFx0bWF0ZXJpYWxQcm9wZXJ0aWVzLnByb2dyYW1zID0gcHJvZ3JhbXM7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRsZXQgcHJvZ3JhbSA9IHByb2dyYW1zLmdldCggcHJvZ3JhbUNhY2hlS2V5ICk7XHJcblxyXG5cdFx0XHRpZiAoIHByb2dyYW0gIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0Ly8gZWFybHkgb3V0IGlmIHByb2dyYW0gYW5kIGxpZ2h0IHN0YXRlIGlzIGlkZW50aWNhbFxyXG5cclxuXHRcdFx0XHRpZiAoIG1hdGVyaWFsUHJvcGVydGllcy5jdXJyZW50UHJvZ3JhbSA9PT0gcHJvZ3JhbSAmJiBtYXRlcmlhbFByb3BlcnRpZXMubGlnaHRzU3RhdGVWZXJzaW9uID09PSBsaWdodHNTdGF0ZVZlcnNpb24gKSB7XHJcblxyXG5cdFx0XHRcdFx0dXBkYXRlQ29tbW9uTWF0ZXJpYWxQcm9wZXJ0aWVzKCBtYXRlcmlhbCwgcGFyYW1ldGVycyApO1xyXG5cclxuXHRcdFx0XHRcdHJldHVybiBwcm9ncmFtO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRwYXJhbWV0ZXJzLnVuaWZvcm1zID0gcHJvZ3JhbUNhY2hlLmdldFVuaWZvcm1zKCBtYXRlcmlhbCApO1xyXG5cclxuXHRcdFx0XHRtYXRlcmlhbC5vbkJ1aWxkKCBvYmplY3QsIHBhcmFtZXRlcnMsIF90aGlzICk7XHJcblxyXG5cdFx0XHRcdG1hdGVyaWFsLm9uQmVmb3JlQ29tcGlsZSggcGFyYW1ldGVycywgX3RoaXMgKTtcclxuXHJcblx0XHRcdFx0cHJvZ3JhbSA9IHByb2dyYW1DYWNoZS5hY3F1aXJlUHJvZ3JhbSggcGFyYW1ldGVycywgcHJvZ3JhbUNhY2hlS2V5ICk7XHJcblx0XHRcdFx0cHJvZ3JhbXMuc2V0KCBwcm9ncmFtQ2FjaGVLZXksIHByb2dyYW0gKTtcclxuXHJcblx0XHRcdFx0bWF0ZXJpYWxQcm9wZXJ0aWVzLnVuaWZvcm1zID0gcGFyYW1ldGVycy51bmlmb3JtcztcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGNvbnN0IHVuaWZvcm1zID0gbWF0ZXJpYWxQcm9wZXJ0aWVzLnVuaWZvcm1zO1xyXG5cclxuXHRcdFx0aWYgKCAoICEgbWF0ZXJpYWwuaXNTaGFkZXJNYXRlcmlhbCAmJiAhIG1hdGVyaWFsLmlzUmF3U2hhZGVyTWF0ZXJpYWwgKSB8fCBtYXRlcmlhbC5jbGlwcGluZyA9PT0gdHJ1ZSApIHtcclxuXHJcblx0XHRcdFx0dW5pZm9ybXMuY2xpcHBpbmdQbGFuZXMgPSBjbGlwcGluZy51bmlmb3JtO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0dXBkYXRlQ29tbW9uTWF0ZXJpYWxQcm9wZXJ0aWVzKCBtYXRlcmlhbCwgcGFyYW1ldGVycyApO1xyXG5cclxuXHRcdFx0Ly8gc3RvcmUgdGhlIGxpZ2h0IHNldHVwIGl0IHdhcyBjcmVhdGVkIGZvclxyXG5cclxuXHRcdFx0bWF0ZXJpYWxQcm9wZXJ0aWVzLm5lZWRzTGlnaHRzID0gbWF0ZXJpYWxOZWVkc0xpZ2h0cyggbWF0ZXJpYWwgKTtcclxuXHRcdFx0bWF0ZXJpYWxQcm9wZXJ0aWVzLmxpZ2h0c1N0YXRlVmVyc2lvbiA9IGxpZ2h0c1N0YXRlVmVyc2lvbjtcclxuXHJcblx0XHRcdGlmICggbWF0ZXJpYWxQcm9wZXJ0aWVzLm5lZWRzTGlnaHRzICkge1xyXG5cclxuXHRcdFx0XHQvLyB3aXJlIHVwIHRoZSBtYXRlcmlhbCB0byB0aGlzIHJlbmRlcmVyJ3MgbGlnaHRpbmcgc3RhdGVcclxuXHJcblx0XHRcdFx0dW5pZm9ybXMuYW1iaWVudExpZ2h0Q29sb3IudmFsdWUgPSBsaWdodHMuc3RhdGUuYW1iaWVudDtcclxuXHRcdFx0XHR1bmlmb3Jtcy5saWdodFByb2JlLnZhbHVlID0gbGlnaHRzLnN0YXRlLnByb2JlO1xyXG5cdFx0XHRcdHVuaWZvcm1zLmRpcmVjdGlvbmFsTGlnaHRzLnZhbHVlID0gbGlnaHRzLnN0YXRlLmRpcmVjdGlvbmFsO1xyXG5cdFx0XHRcdHVuaWZvcm1zLmRpcmVjdGlvbmFsTGlnaHRTaGFkb3dzLnZhbHVlID0gbGlnaHRzLnN0YXRlLmRpcmVjdGlvbmFsU2hhZG93O1xyXG5cdFx0XHRcdHVuaWZvcm1zLnNwb3RMaWdodHMudmFsdWUgPSBsaWdodHMuc3RhdGUuc3BvdDtcclxuXHRcdFx0XHR1bmlmb3Jtcy5zcG90TGlnaHRTaGFkb3dzLnZhbHVlID0gbGlnaHRzLnN0YXRlLnNwb3RTaGFkb3c7XHJcblx0XHRcdFx0dW5pZm9ybXMucmVjdEFyZWFMaWdodHMudmFsdWUgPSBsaWdodHMuc3RhdGUucmVjdEFyZWE7XHJcblx0XHRcdFx0dW5pZm9ybXMubHRjXzEudmFsdWUgPSBsaWdodHMuc3RhdGUucmVjdEFyZWFMVEMxO1xyXG5cdFx0XHRcdHVuaWZvcm1zLmx0Y18yLnZhbHVlID0gbGlnaHRzLnN0YXRlLnJlY3RBcmVhTFRDMjtcclxuXHRcdFx0XHR1bmlmb3Jtcy5wb2ludExpZ2h0cy52YWx1ZSA9IGxpZ2h0cy5zdGF0ZS5wb2ludDtcclxuXHRcdFx0XHR1bmlmb3Jtcy5wb2ludExpZ2h0U2hhZG93cy52YWx1ZSA9IGxpZ2h0cy5zdGF0ZS5wb2ludFNoYWRvdztcclxuXHRcdFx0XHR1bmlmb3Jtcy5oZW1pc3BoZXJlTGlnaHRzLnZhbHVlID0gbGlnaHRzLnN0YXRlLmhlbWk7XHJcblxyXG5cdFx0XHRcdHVuaWZvcm1zLmRpcmVjdGlvbmFsU2hhZG93TWFwLnZhbHVlID0gbGlnaHRzLnN0YXRlLmRpcmVjdGlvbmFsU2hhZG93TWFwO1xyXG5cdFx0XHRcdHVuaWZvcm1zLmRpcmVjdGlvbmFsU2hhZG93TWF0cml4LnZhbHVlID0gbGlnaHRzLnN0YXRlLmRpcmVjdGlvbmFsU2hhZG93TWF0cml4O1xyXG5cdFx0XHRcdHVuaWZvcm1zLnNwb3RTaGFkb3dNYXAudmFsdWUgPSBsaWdodHMuc3RhdGUuc3BvdFNoYWRvd01hcDtcclxuXHRcdFx0XHR1bmlmb3Jtcy5zcG90TGlnaHRNYXRyaXgudmFsdWUgPSBsaWdodHMuc3RhdGUuc3BvdExpZ2h0TWF0cml4O1xyXG5cdFx0XHRcdHVuaWZvcm1zLnNwb3RMaWdodE1hcC52YWx1ZSA9IGxpZ2h0cy5zdGF0ZS5zcG90TGlnaHRNYXA7XHJcblx0XHRcdFx0dW5pZm9ybXMucG9pbnRTaGFkb3dNYXAudmFsdWUgPSBsaWdodHMuc3RhdGUucG9pbnRTaGFkb3dNYXA7XHJcblx0XHRcdFx0dW5pZm9ybXMucG9pbnRTaGFkb3dNYXRyaXgudmFsdWUgPSBsaWdodHMuc3RhdGUucG9pbnRTaGFkb3dNYXRyaXg7XHJcblx0XHRcdFx0Ly8gVE9ETyAoYWJlbG5hdGlvbik6IGFkZCBhcmVhIGxpZ2h0cyBzaGFkb3cgaW5mbyB0byB1bmlmb3Jtc1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0bWF0ZXJpYWxQcm9wZXJ0aWVzLmN1cnJlbnRQcm9ncmFtID0gcHJvZ3JhbTtcclxuXHRcdFx0bWF0ZXJpYWxQcm9wZXJ0aWVzLnVuaWZvcm1zTGlzdCA9IG51bGw7XHJcblxyXG5cdFx0XHRyZXR1cm4gcHJvZ3JhbTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0ZnVuY3Rpb24gZ2V0VW5pZm9ybUxpc3QoIG1hdGVyaWFsUHJvcGVydGllcyApIHtcclxuXHJcblx0XHRcdGlmICggbWF0ZXJpYWxQcm9wZXJ0aWVzLnVuaWZvcm1zTGlzdCA9PT0gbnVsbCApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgcHJvZ1VuaWZvcm1zID0gbWF0ZXJpYWxQcm9wZXJ0aWVzLmN1cnJlbnRQcm9ncmFtLmdldFVuaWZvcm1zKCk7XHJcblx0XHRcdFx0bWF0ZXJpYWxQcm9wZXJ0aWVzLnVuaWZvcm1zTGlzdCA9IFdlYkdMVW5pZm9ybXMuc2VxV2l0aFZhbHVlKCBwcm9nVW5pZm9ybXMuc2VxLCBtYXRlcmlhbFByb3BlcnRpZXMudW5pZm9ybXMgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHJldHVybiBtYXRlcmlhbFByb3BlcnRpZXMudW5pZm9ybXNMaXN0O1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRmdW5jdGlvbiB1cGRhdGVDb21tb25NYXRlcmlhbFByb3BlcnRpZXMoIG1hdGVyaWFsLCBwYXJhbWV0ZXJzICkge1xyXG5cclxuXHRcdFx0Y29uc3QgbWF0ZXJpYWxQcm9wZXJ0aWVzID0gcHJvcGVydGllcy5nZXQoIG1hdGVyaWFsICk7XHJcblxyXG5cdFx0XHRtYXRlcmlhbFByb3BlcnRpZXMub3V0cHV0Q29sb3JTcGFjZSA9IHBhcmFtZXRlcnMub3V0cHV0Q29sb3JTcGFjZTtcclxuXHRcdFx0bWF0ZXJpYWxQcm9wZXJ0aWVzLmJhdGNoaW5nID0gcGFyYW1ldGVycy5iYXRjaGluZztcclxuXHRcdFx0bWF0ZXJpYWxQcm9wZXJ0aWVzLmluc3RhbmNpbmcgPSBwYXJhbWV0ZXJzLmluc3RhbmNpbmc7XHJcblx0XHRcdG1hdGVyaWFsUHJvcGVydGllcy5pbnN0YW5jaW5nQ29sb3IgPSBwYXJhbWV0ZXJzLmluc3RhbmNpbmdDb2xvcjtcclxuXHRcdFx0bWF0ZXJpYWxQcm9wZXJ0aWVzLnNraW5uaW5nID0gcGFyYW1ldGVycy5za2lubmluZztcclxuXHRcdFx0bWF0ZXJpYWxQcm9wZXJ0aWVzLm1vcnBoVGFyZ2V0cyA9IHBhcmFtZXRlcnMubW9ycGhUYXJnZXRzO1xyXG5cdFx0XHRtYXRlcmlhbFByb3BlcnRpZXMubW9ycGhOb3JtYWxzID0gcGFyYW1ldGVycy5tb3JwaE5vcm1hbHM7XHJcblx0XHRcdG1hdGVyaWFsUHJvcGVydGllcy5tb3JwaENvbG9ycyA9IHBhcmFtZXRlcnMubW9ycGhDb2xvcnM7XHJcblx0XHRcdG1hdGVyaWFsUHJvcGVydGllcy5tb3JwaFRhcmdldHNDb3VudCA9IHBhcmFtZXRlcnMubW9ycGhUYXJnZXRzQ291bnQ7XHJcblx0XHRcdG1hdGVyaWFsUHJvcGVydGllcy5udW1DbGlwcGluZ1BsYW5lcyA9IHBhcmFtZXRlcnMubnVtQ2xpcHBpbmdQbGFuZXM7XHJcblx0XHRcdG1hdGVyaWFsUHJvcGVydGllcy5udW1JbnRlcnNlY3Rpb24gPSBwYXJhbWV0ZXJzLm51bUNsaXBJbnRlcnNlY3Rpb247XHJcblx0XHRcdG1hdGVyaWFsUHJvcGVydGllcy52ZXJ0ZXhBbHBoYXMgPSBwYXJhbWV0ZXJzLnZlcnRleEFscGhhcztcclxuXHRcdFx0bWF0ZXJpYWxQcm9wZXJ0aWVzLnZlcnRleFRhbmdlbnRzID0gcGFyYW1ldGVycy52ZXJ0ZXhUYW5nZW50cztcclxuXHRcdFx0bWF0ZXJpYWxQcm9wZXJ0aWVzLnRvbmVNYXBwaW5nID0gcGFyYW1ldGVycy50b25lTWFwcGluZztcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0ZnVuY3Rpb24gc2V0UHJvZ3JhbSggY2FtZXJhLCBzY2VuZSwgZ2VvbWV0cnksIG1hdGVyaWFsLCBvYmplY3QgKSB7XHJcblxyXG5cdFx0XHRpZiAoIHNjZW5lLmlzU2NlbmUgIT09IHRydWUgKSBzY2VuZSA9IF9lbXB0eVNjZW5lOyAvLyBzY2VuZSBjb3VsZCBiZSBhIE1lc2gsIExpbmUsIFBvaW50cywgLi4uXHJcblxyXG5cdFx0XHR0ZXh0dXJlcy5yZXNldFRleHR1cmVVbml0cygpO1xyXG5cclxuXHRcdFx0Y29uc3QgZm9nID0gc2NlbmUuZm9nO1xyXG5cdFx0XHRjb25zdCBlbnZpcm9ubWVudCA9IG1hdGVyaWFsLmlzTWVzaFN0YW5kYXJkTWF0ZXJpYWwgPyBzY2VuZS5lbnZpcm9ubWVudCA6IG51bGw7XHJcblx0XHRcdGNvbnN0IGNvbG9yU3BhY2UgPSAoIF9jdXJyZW50UmVuZGVyVGFyZ2V0ID09PSBudWxsICkgPyBfdGhpcy5vdXRwdXRDb2xvclNwYWNlIDogKCBfY3VycmVudFJlbmRlclRhcmdldC5pc1hSUmVuZGVyVGFyZ2V0ID09PSB0cnVlID8gX2N1cnJlbnRSZW5kZXJUYXJnZXQudGV4dHVyZS5jb2xvclNwYWNlIDogTGluZWFyU1JHQkNvbG9yU3BhY2UgKTtcclxuXHRcdFx0Y29uc3QgZW52TWFwID0gKCBtYXRlcmlhbC5pc01lc2hTdGFuZGFyZE1hdGVyaWFsID8gY3ViZXV2bWFwcyA6IGN1YmVtYXBzICkuZ2V0KCBtYXRlcmlhbC5lbnZNYXAgfHwgZW52aXJvbm1lbnQgKTtcclxuXHRcdFx0Y29uc3QgdmVydGV4QWxwaGFzID0gbWF0ZXJpYWwudmVydGV4Q29sb3JzID09PSB0cnVlICYmICEhIGdlb21ldHJ5LmF0dHJpYnV0ZXMuY29sb3IgJiYgZ2VvbWV0cnkuYXR0cmlidXRlcy5jb2xvci5pdGVtU2l6ZSA9PT0gNDtcclxuXHRcdFx0Y29uc3QgdmVydGV4VGFuZ2VudHMgPSAhISBnZW9tZXRyeS5hdHRyaWJ1dGVzLnRhbmdlbnQgJiYgKCAhISBtYXRlcmlhbC5ub3JtYWxNYXAgfHwgbWF0ZXJpYWwuYW5pc290cm9weSA+IDAgKTtcclxuXHRcdFx0Y29uc3QgbW9ycGhUYXJnZXRzID0gISEgZ2VvbWV0cnkubW9ycGhBdHRyaWJ1dGVzLnBvc2l0aW9uO1xyXG5cdFx0XHRjb25zdCBtb3JwaE5vcm1hbHMgPSAhISBnZW9tZXRyeS5tb3JwaEF0dHJpYnV0ZXMubm9ybWFsO1xyXG5cdFx0XHRjb25zdCBtb3JwaENvbG9ycyA9ICEhIGdlb21ldHJ5Lm1vcnBoQXR0cmlidXRlcy5jb2xvcjtcclxuXHJcblx0XHRcdGxldCB0b25lTWFwcGluZyA9IE5vVG9uZU1hcHBpbmc7XHJcblxyXG5cdFx0XHRpZiAoIG1hdGVyaWFsLnRvbmVNYXBwZWQgKSB7XHJcblxyXG5cdFx0XHRcdGlmICggX2N1cnJlbnRSZW5kZXJUYXJnZXQgPT09IG51bGwgfHwgX2N1cnJlbnRSZW5kZXJUYXJnZXQuaXNYUlJlbmRlclRhcmdldCA9PT0gdHJ1ZSApIHtcclxuXHJcblx0XHRcdFx0XHR0b25lTWFwcGluZyA9IF90aGlzLnRvbmVNYXBwaW5nO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRjb25zdCBtb3JwaEF0dHJpYnV0ZSA9IGdlb21ldHJ5Lm1vcnBoQXR0cmlidXRlcy5wb3NpdGlvbiB8fCBnZW9tZXRyeS5tb3JwaEF0dHJpYnV0ZXMubm9ybWFsIHx8IGdlb21ldHJ5Lm1vcnBoQXR0cmlidXRlcy5jb2xvcjtcclxuXHRcdFx0Y29uc3QgbW9ycGhUYXJnZXRzQ291bnQgPSAoIG1vcnBoQXR0cmlidXRlICE9PSB1bmRlZmluZWQgKSA/IG1vcnBoQXR0cmlidXRlLmxlbmd0aCA6IDA7XHJcblxyXG5cdFx0XHRjb25zdCBtYXRlcmlhbFByb3BlcnRpZXMgPSBwcm9wZXJ0aWVzLmdldCggbWF0ZXJpYWwgKTtcclxuXHRcdFx0Y29uc3QgbGlnaHRzID0gY3VycmVudFJlbmRlclN0YXRlLnN0YXRlLmxpZ2h0cztcclxuXHJcblx0XHRcdGlmICggX2NsaXBwaW5nRW5hYmxlZCA9PT0gdHJ1ZSApIHtcclxuXHJcblx0XHRcdFx0aWYgKCBfbG9jYWxDbGlwcGluZ0VuYWJsZWQgPT09IHRydWUgfHwgY2FtZXJhICE9PSBfY3VycmVudENhbWVyYSApIHtcclxuXHJcblx0XHRcdFx0XHRjb25zdCB1c2VDYWNoZSA9XHJcblx0XHRcdFx0XHRcdGNhbWVyYSA9PT0gX2N1cnJlbnRDYW1lcmEgJiZcclxuXHRcdFx0XHRcdFx0bWF0ZXJpYWwuaWQgPT09IF9jdXJyZW50TWF0ZXJpYWxJZDtcclxuXHJcblx0XHRcdFx0XHQvLyB3ZSBtaWdodCB3YW50IHRvIGNhbGwgdGhpcyBmdW5jdGlvbiB3aXRoIHNvbWUgQ2xpcHBpbmdHcm91cFxyXG5cdFx0XHRcdFx0Ly8gb2JqZWN0IGluc3RlYWQgb2YgdGhlIG1hdGVyaWFsLCBvbmNlIGl0IGJlY29tZXMgZmVhc2libGVcclxuXHRcdFx0XHRcdC8vICgjODQ2NSwgIzgzNzkpXHJcblx0XHRcdFx0XHRjbGlwcGluZy5zZXRTdGF0ZSggbWF0ZXJpYWwsIGNhbWVyYSwgdXNlQ2FjaGUgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Ly9cclxuXHJcblx0XHRcdGxldCBuZWVkc1Byb2dyYW1DaGFuZ2UgPSBmYWxzZTtcclxuXHJcblx0XHRcdGlmICggbWF0ZXJpYWwudmVyc2lvbiA9PT0gbWF0ZXJpYWxQcm9wZXJ0aWVzLl9fdmVyc2lvbiApIHtcclxuXHJcblx0XHRcdFx0aWYgKCBtYXRlcmlhbFByb3BlcnRpZXMubmVlZHNMaWdodHMgJiYgKCBtYXRlcmlhbFByb3BlcnRpZXMubGlnaHRzU3RhdGVWZXJzaW9uICE9PSBsaWdodHMuc3RhdGUudmVyc2lvbiApICkge1xyXG5cclxuXHRcdFx0XHRcdG5lZWRzUHJvZ3JhbUNoYW5nZSA9IHRydWU7XHJcblxyXG5cdFx0XHRcdH0gZWxzZSBpZiAoIG1hdGVyaWFsUHJvcGVydGllcy5vdXRwdXRDb2xvclNwYWNlICE9PSBjb2xvclNwYWNlICkge1xyXG5cclxuXHRcdFx0XHRcdG5lZWRzUHJvZ3JhbUNoYW5nZSA9IHRydWU7XHJcblxyXG5cdFx0XHRcdH0gZWxzZSBpZiAoIG9iamVjdC5pc0JhdGNoZWRNZXNoICYmIG1hdGVyaWFsUHJvcGVydGllcy5iYXRjaGluZyA9PT0gZmFsc2UgKSB7XHJcblxyXG5cdFx0XHRcdFx0bmVlZHNQcm9ncmFtQ2hhbmdlID0gdHJ1ZTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIGlmICggISBvYmplY3QuaXNCYXRjaGVkTWVzaCAmJiBtYXRlcmlhbFByb3BlcnRpZXMuYmF0Y2hpbmcgPT09IHRydWUgKSB7XHJcblxyXG5cdFx0XHRcdFx0bmVlZHNQcm9ncmFtQ2hhbmdlID0gdHJ1ZTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIGlmICggb2JqZWN0LmlzSW5zdGFuY2VkTWVzaCAmJiBtYXRlcmlhbFByb3BlcnRpZXMuaW5zdGFuY2luZyA9PT0gZmFsc2UgKSB7XHJcblxyXG5cdFx0XHRcdFx0bmVlZHNQcm9ncmFtQ2hhbmdlID0gdHJ1ZTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIGlmICggISBvYmplY3QuaXNJbnN0YW5jZWRNZXNoICYmIG1hdGVyaWFsUHJvcGVydGllcy5pbnN0YW5jaW5nID09PSB0cnVlICkge1xyXG5cclxuXHRcdFx0XHRcdG5lZWRzUHJvZ3JhbUNoYW5nZSA9IHRydWU7XHJcblxyXG5cdFx0XHRcdH0gZWxzZSBpZiAoIG9iamVjdC5pc1NraW5uZWRNZXNoICYmIG1hdGVyaWFsUHJvcGVydGllcy5za2lubmluZyA9PT0gZmFsc2UgKSB7XHJcblxyXG5cdFx0XHRcdFx0bmVlZHNQcm9ncmFtQ2hhbmdlID0gdHJ1ZTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIGlmICggISBvYmplY3QuaXNTa2lubmVkTWVzaCAmJiBtYXRlcmlhbFByb3BlcnRpZXMuc2tpbm5pbmcgPT09IHRydWUgKSB7XHJcblxyXG5cdFx0XHRcdFx0bmVlZHNQcm9ncmFtQ2hhbmdlID0gdHJ1ZTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIGlmICggb2JqZWN0LmlzSW5zdGFuY2VkTWVzaCAmJiBtYXRlcmlhbFByb3BlcnRpZXMuaW5zdGFuY2luZ0NvbG9yID09PSB0cnVlICYmIG9iamVjdC5pbnN0YW5jZUNvbG9yID09PSBudWxsICkge1xyXG5cclxuXHRcdFx0XHRcdG5lZWRzUHJvZ3JhbUNoYW5nZSA9IHRydWU7XHJcblxyXG5cdFx0XHRcdH0gZWxzZSBpZiAoIG9iamVjdC5pc0luc3RhbmNlZE1lc2ggJiYgbWF0ZXJpYWxQcm9wZXJ0aWVzLmluc3RhbmNpbmdDb2xvciA9PT0gZmFsc2UgJiYgb2JqZWN0Lmluc3RhbmNlQ29sb3IgIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdFx0bmVlZHNQcm9ncmFtQ2hhbmdlID0gdHJ1ZTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIGlmICggbWF0ZXJpYWxQcm9wZXJ0aWVzLmVudk1hcCAhPT0gZW52TWFwICkge1xyXG5cclxuXHRcdFx0XHRcdG5lZWRzUHJvZ3JhbUNoYW5nZSA9IHRydWU7XHJcblxyXG5cdFx0XHRcdH0gZWxzZSBpZiAoIG1hdGVyaWFsLmZvZyA9PT0gdHJ1ZSAmJiBtYXRlcmlhbFByb3BlcnRpZXMuZm9nICE9PSBmb2cgKSB7XHJcblxyXG5cdFx0XHRcdFx0bmVlZHNQcm9ncmFtQ2hhbmdlID0gdHJ1ZTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIGlmICggbWF0ZXJpYWxQcm9wZXJ0aWVzLm51bUNsaXBwaW5nUGxhbmVzICE9PSB1bmRlZmluZWQgJiZcclxuXHRcdFx0XHRcdCggbWF0ZXJpYWxQcm9wZXJ0aWVzLm51bUNsaXBwaW5nUGxhbmVzICE9PSBjbGlwcGluZy5udW1QbGFuZXMgfHxcclxuXHRcdFx0XHRcdG1hdGVyaWFsUHJvcGVydGllcy5udW1JbnRlcnNlY3Rpb24gIT09IGNsaXBwaW5nLm51bUludGVyc2VjdGlvbiApICkge1xyXG5cclxuXHRcdFx0XHRcdG5lZWRzUHJvZ3JhbUNoYW5nZSA9IHRydWU7XHJcblxyXG5cdFx0XHRcdH0gZWxzZSBpZiAoIG1hdGVyaWFsUHJvcGVydGllcy52ZXJ0ZXhBbHBoYXMgIT09IHZlcnRleEFscGhhcyApIHtcclxuXHJcblx0XHRcdFx0XHRuZWVkc1Byb2dyYW1DaGFuZ2UgPSB0cnVlO1xyXG5cclxuXHRcdFx0XHR9IGVsc2UgaWYgKCBtYXRlcmlhbFByb3BlcnRpZXMudmVydGV4VGFuZ2VudHMgIT09IHZlcnRleFRhbmdlbnRzICkge1xyXG5cclxuXHRcdFx0XHRcdG5lZWRzUHJvZ3JhbUNoYW5nZSA9IHRydWU7XHJcblxyXG5cdFx0XHRcdH0gZWxzZSBpZiAoIG1hdGVyaWFsUHJvcGVydGllcy5tb3JwaFRhcmdldHMgIT09IG1vcnBoVGFyZ2V0cyApIHtcclxuXHJcblx0XHRcdFx0XHRuZWVkc1Byb2dyYW1DaGFuZ2UgPSB0cnVlO1xyXG5cclxuXHRcdFx0XHR9IGVsc2UgaWYgKCBtYXRlcmlhbFByb3BlcnRpZXMubW9ycGhOb3JtYWxzICE9PSBtb3JwaE5vcm1hbHMgKSB7XHJcblxyXG5cdFx0XHRcdFx0bmVlZHNQcm9ncmFtQ2hhbmdlID0gdHJ1ZTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIGlmICggbWF0ZXJpYWxQcm9wZXJ0aWVzLm1vcnBoQ29sb3JzICE9PSBtb3JwaENvbG9ycyApIHtcclxuXHJcblx0XHRcdFx0XHRuZWVkc1Byb2dyYW1DaGFuZ2UgPSB0cnVlO1xyXG5cclxuXHRcdFx0XHR9IGVsc2UgaWYgKCBtYXRlcmlhbFByb3BlcnRpZXMudG9uZU1hcHBpbmcgIT09IHRvbmVNYXBwaW5nICkge1xyXG5cclxuXHRcdFx0XHRcdG5lZWRzUHJvZ3JhbUNoYW5nZSA9IHRydWU7XHJcblxyXG5cdFx0XHRcdH0gZWxzZSBpZiAoIGNhcGFiaWxpdGllcy5pc1dlYkdMMiA9PT0gdHJ1ZSAmJiBtYXRlcmlhbFByb3BlcnRpZXMubW9ycGhUYXJnZXRzQ291bnQgIT09IG1vcnBoVGFyZ2V0c0NvdW50ICkge1xyXG5cclxuXHRcdFx0XHRcdG5lZWRzUHJvZ3JhbUNoYW5nZSA9IHRydWU7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdG5lZWRzUHJvZ3JhbUNoYW5nZSA9IHRydWU7XHJcblx0XHRcdFx0bWF0ZXJpYWxQcm9wZXJ0aWVzLl9fdmVyc2lvbiA9IG1hdGVyaWFsLnZlcnNpb247XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvL1xyXG5cclxuXHRcdFx0bGV0IHByb2dyYW0gPSBtYXRlcmlhbFByb3BlcnRpZXMuY3VycmVudFByb2dyYW07XHJcblxyXG5cdFx0XHRpZiAoIG5lZWRzUHJvZ3JhbUNoYW5nZSA9PT0gdHJ1ZSApIHtcclxuXHJcblx0XHRcdFx0cHJvZ3JhbSA9IGdldFByb2dyYW0oIG1hdGVyaWFsLCBzY2VuZSwgb2JqZWN0ICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRsZXQgcmVmcmVzaFByb2dyYW0gPSBmYWxzZTtcclxuXHRcdFx0bGV0IHJlZnJlc2hNYXRlcmlhbCA9IGZhbHNlO1xyXG5cdFx0XHRsZXQgcmVmcmVzaExpZ2h0cyA9IGZhbHNlO1xyXG5cclxuXHRcdFx0Y29uc3QgcF91bmlmb3JtcyA9IHByb2dyYW0uZ2V0VW5pZm9ybXMoKSxcclxuXHRcdFx0XHRtX3VuaWZvcm1zID0gbWF0ZXJpYWxQcm9wZXJ0aWVzLnVuaWZvcm1zO1xyXG5cclxuXHRcdFx0aWYgKCBzdGF0ZS51c2VQcm9ncmFtKCBwcm9ncmFtLnByb2dyYW0gKSApIHtcclxuXHJcblx0XHRcdFx0cmVmcmVzaFByb2dyYW0gPSB0cnVlO1xyXG5cdFx0XHRcdHJlZnJlc2hNYXRlcmlhbCA9IHRydWU7XHJcblx0XHRcdFx0cmVmcmVzaExpZ2h0cyA9IHRydWU7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRpZiAoIG1hdGVyaWFsLmlkICE9PSBfY3VycmVudE1hdGVyaWFsSWQgKSB7XHJcblxyXG5cdFx0XHRcdF9jdXJyZW50TWF0ZXJpYWxJZCA9IG1hdGVyaWFsLmlkO1xyXG5cclxuXHRcdFx0XHRyZWZyZXNoTWF0ZXJpYWwgPSB0cnVlO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0aWYgKCByZWZyZXNoUHJvZ3JhbSB8fCBfY3VycmVudENhbWVyYSAhPT0gY2FtZXJhICkge1xyXG5cclxuXHRcdFx0XHQvLyBjb21tb24gY2FtZXJhIHVuaWZvcm1zXHJcblxyXG5cdFx0XHRcdHBfdW5pZm9ybXMuc2V0VmFsdWUoIF9nbCwgJ3Byb2plY3Rpb25NYXRyaXgnLCBjYW1lcmEucHJvamVjdGlvbk1hdHJpeCApO1xyXG5cdFx0XHRcdHBfdW5pZm9ybXMuc2V0VmFsdWUoIF9nbCwgJ3ZpZXdNYXRyaXgnLCBjYW1lcmEubWF0cml4V29ybGRJbnZlcnNlICk7XHJcblxyXG5cdFx0XHRcdGNvbnN0IHVDYW1Qb3MgPSBwX3VuaWZvcm1zLm1hcC5jYW1lcmFQb3NpdGlvbjtcclxuXHJcblx0XHRcdFx0aWYgKCB1Q2FtUG9zICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRcdFx0dUNhbVBvcy5zZXRWYWx1ZSggX2dsLCBfdmVjdG9yMy5zZXRGcm9tTWF0cml4UG9zaXRpb24oIGNhbWVyYS5tYXRyaXhXb3JsZCApICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0aWYgKCBjYXBhYmlsaXRpZXMubG9nYXJpdGhtaWNEZXB0aEJ1ZmZlciApIHtcclxuXHJcblx0XHRcdFx0XHRwX3VuaWZvcm1zLnNldFZhbHVlKCBfZ2wsICdsb2dEZXB0aEJ1ZkZDJyxcclxuXHRcdFx0XHRcdFx0Mi4wIC8gKCBNYXRoLmxvZyggY2FtZXJhLmZhciArIDEuMCApIC8gTWF0aC5MTjIgKSApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdC8vIGNvbnNpZGVyIG1vdmluZyBpc09ydGhvZ3JhcGhpYyB0byBVbmlmb3JtTGliIGFuZCBXZWJHTE1hdGVyaWFscywgc2VlIGh0dHBzOi8vZ2l0aHViLmNvbS9tcmRvb2IvdGhyZWUuanMvcHVsbC8yNjQ2NyNpc3N1ZWNvbW1lbnQtMTY0NTE4NTA2N1xyXG5cclxuXHRcdFx0XHRpZiAoIG1hdGVyaWFsLmlzTWVzaFBob25nTWF0ZXJpYWwgfHxcclxuXHRcdFx0XHRcdG1hdGVyaWFsLmlzTWVzaFRvb25NYXRlcmlhbCB8fFxyXG5cdFx0XHRcdFx0bWF0ZXJpYWwuaXNNZXNoTGFtYmVydE1hdGVyaWFsIHx8XHJcblx0XHRcdFx0XHRtYXRlcmlhbC5pc01lc2hCYXNpY01hdGVyaWFsIHx8XHJcblx0XHRcdFx0XHRtYXRlcmlhbC5pc01lc2hTdGFuZGFyZE1hdGVyaWFsIHx8XHJcblx0XHRcdFx0XHRtYXRlcmlhbC5pc1NoYWRlck1hdGVyaWFsICkge1xyXG5cclxuXHRcdFx0XHRcdHBfdW5pZm9ybXMuc2V0VmFsdWUoIF9nbCwgJ2lzT3J0aG9ncmFwaGljJywgY2FtZXJhLmlzT3J0aG9ncmFwaGljQ2FtZXJhID09PSB0cnVlICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0aWYgKCBfY3VycmVudENhbWVyYSAhPT0gY2FtZXJhICkge1xyXG5cclxuXHRcdFx0XHRcdF9jdXJyZW50Q2FtZXJhID0gY2FtZXJhO1xyXG5cclxuXHRcdFx0XHRcdC8vIGxpZ2h0aW5nIHVuaWZvcm1zIGRlcGVuZCBvbiB0aGUgY2FtZXJhIHNvIGVuZm9yY2UgYW4gdXBkYXRlXHJcblx0XHRcdFx0XHQvLyBub3csIGluIGNhc2UgdGhpcyBtYXRlcmlhbCBzdXBwb3J0cyBsaWdodHMgLSBvciBsYXRlciwgd2hlblxyXG5cdFx0XHRcdFx0Ly8gdGhlIG5leHQgbWF0ZXJpYWwgdGhhdCBkb2VzIGdldHMgYWN0aXZhdGVkOlxyXG5cclxuXHRcdFx0XHRcdHJlZnJlc2hNYXRlcmlhbCA9IHRydWU7XHRcdC8vIHNldCB0byB0cnVlIG9uIG1hdGVyaWFsIGNoYW5nZVxyXG5cdFx0XHRcdFx0cmVmcmVzaExpZ2h0cyA9IHRydWU7XHRcdC8vIHJlbWFpbnMgc2V0IHVudGlsIHVwZGF0ZSBkb25lXHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdC8vIHNraW5uaW5nIGFuZCBtb3JwaCB0YXJnZXQgdW5pZm9ybXMgbXVzdCBiZSBzZXQgZXZlbiBpZiBtYXRlcmlhbCBkaWRuJ3QgY2hhbmdlXHJcblx0XHRcdC8vIGF1dG8tc2V0dGluZyBvZiB0ZXh0dXJlIHVuaXQgZm9yIGJvbmUgYW5kIG1vcnBoIHRleHR1cmUgbXVzdCBnbyBiZWZvcmUgb3RoZXIgdGV4dHVyZXNcclxuXHRcdFx0Ly8gb3RoZXJ3aXNlIHRleHR1cmVzIHVzZWQgZm9yIHNraW5uaW5nIGFuZCBtb3JwaGluZyBjYW4gdGFrZSBvdmVyIHRleHR1cmUgdW5pdHMgcmVzZXJ2ZWQgZm9yIG90aGVyIG1hdGVyaWFsIHRleHR1cmVzXHJcblxyXG5cdFx0XHRpZiAoIG9iamVjdC5pc1NraW5uZWRNZXNoICkge1xyXG5cclxuXHRcdFx0XHRwX3VuaWZvcm1zLnNldE9wdGlvbmFsKCBfZ2wsIG9iamVjdCwgJ2JpbmRNYXRyaXgnICk7XHJcblx0XHRcdFx0cF91bmlmb3Jtcy5zZXRPcHRpb25hbCggX2dsLCBvYmplY3QsICdiaW5kTWF0cml4SW52ZXJzZScgKTtcclxuXHJcblx0XHRcdFx0Y29uc3Qgc2tlbGV0b24gPSBvYmplY3Quc2tlbGV0b247XHJcblxyXG5cdFx0XHRcdGlmICggc2tlbGV0b24gKSB7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCBjYXBhYmlsaXRpZXMuZmxvYXRWZXJ0ZXhUZXh0dXJlcyApIHtcclxuXHJcblx0XHRcdFx0XHRcdGlmICggc2tlbGV0b24uYm9uZVRleHR1cmUgPT09IG51bGwgKSBza2VsZXRvbi5jb21wdXRlQm9uZVRleHR1cmUoKTtcclxuXHJcblx0XHRcdFx0XHRcdHBfdW5pZm9ybXMuc2V0VmFsdWUoIF9nbCwgJ2JvbmVUZXh0dXJlJywgc2tlbGV0b24uYm9uZVRleHR1cmUsIHRleHR1cmVzICk7XHJcblxyXG5cdFx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLldlYkdMUmVuZGVyZXI6IFNraW5uZWRNZXNoIGNhbiBvbmx5IGJlIHVzZWQgd2l0aCBXZWJHTCAyLiBXaXRoIFdlYkdMIDEgT0VTX3RleHR1cmVfZmxvYXQgYW5kIHZlcnRleCB0ZXh0dXJlcyBzdXBwb3J0IGlzIHJlcXVpcmVkLicgKTtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGlmICggb2JqZWN0LmlzQmF0Y2hlZE1lc2ggKSB7XHJcblxyXG5cdFx0XHRcdHBfdW5pZm9ybXMuc2V0T3B0aW9uYWwoIF9nbCwgb2JqZWN0LCAnYmF0Y2hpbmdUZXh0dXJlJyApO1xyXG5cdFx0XHRcdHBfdW5pZm9ybXMuc2V0VmFsdWUoIF9nbCwgJ2JhdGNoaW5nVGV4dHVyZScsIG9iamVjdC5fbWF0cmljZXNUZXh0dXJlLCB0ZXh0dXJlcyApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Y29uc3QgbW9ycGhBdHRyaWJ1dGVzID0gZ2VvbWV0cnkubW9ycGhBdHRyaWJ1dGVzO1xyXG5cclxuXHRcdFx0aWYgKCBtb3JwaEF0dHJpYnV0ZXMucG9zaXRpb24gIT09IHVuZGVmaW5lZCB8fCBtb3JwaEF0dHJpYnV0ZXMubm9ybWFsICE9PSB1bmRlZmluZWQgfHwgKCBtb3JwaEF0dHJpYnV0ZXMuY29sb3IgIT09IHVuZGVmaW5lZCAmJiBjYXBhYmlsaXRpZXMuaXNXZWJHTDIgPT09IHRydWUgKSApIHtcclxuXHJcblx0XHRcdFx0bW9ycGh0YXJnZXRzLnVwZGF0ZSggb2JqZWN0LCBnZW9tZXRyeSwgcHJvZ3JhbSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0aWYgKCByZWZyZXNoTWF0ZXJpYWwgfHwgbWF0ZXJpYWxQcm9wZXJ0aWVzLnJlY2VpdmVTaGFkb3cgIT09IG9iamVjdC5yZWNlaXZlU2hhZG93ICkge1xyXG5cclxuXHRcdFx0XHRtYXRlcmlhbFByb3BlcnRpZXMucmVjZWl2ZVNoYWRvdyA9IG9iamVjdC5yZWNlaXZlU2hhZG93O1xyXG5cdFx0XHRcdHBfdW5pZm9ybXMuc2V0VmFsdWUoIF9nbCwgJ3JlY2VpdmVTaGFkb3cnLCBvYmplY3QucmVjZWl2ZVNoYWRvdyApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Ly8gaHR0cHM6Ly9naXRodWIuY29tL21yZG9vYi90aHJlZS5qcy9wdWxsLzI0NDY3I2lzc3VlY29tbWVudC0xMjA5MDMxNTEyXHJcblxyXG5cdFx0XHRpZiAoIG1hdGVyaWFsLmlzTWVzaEdvdXJhdWRNYXRlcmlhbCAmJiBtYXRlcmlhbC5lbnZNYXAgIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdG1fdW5pZm9ybXMuZW52TWFwLnZhbHVlID0gZW52TWFwO1xyXG5cclxuXHRcdFx0XHRtX3VuaWZvcm1zLmZsaXBFbnZNYXAudmFsdWUgPSAoIGVudk1hcC5pc0N1YmVUZXh0dXJlICYmIGVudk1hcC5pc1JlbmRlclRhcmdldFRleHR1cmUgPT09IGZhbHNlICkgPyAtIDEgOiAxO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0aWYgKCByZWZyZXNoTWF0ZXJpYWwgKSB7XHJcblxyXG5cdFx0XHRcdHBfdW5pZm9ybXMuc2V0VmFsdWUoIF9nbCwgJ3RvbmVNYXBwaW5nRXhwb3N1cmUnLCBfdGhpcy50b25lTWFwcGluZ0V4cG9zdXJlICk7XHJcblxyXG5cdFx0XHRcdGlmICggbWF0ZXJpYWxQcm9wZXJ0aWVzLm5lZWRzTGlnaHRzICkge1xyXG5cclxuXHRcdFx0XHRcdC8vIHRoZSBjdXJyZW50IG1hdGVyaWFsIHJlcXVpcmVzIGxpZ2h0aW5nIGluZm9cclxuXHJcblx0XHRcdFx0XHQvLyBub3RlOiBhbGwgbGlnaHRpbmcgdW5pZm9ybXMgYXJlIGFsd2F5cyBzZXQgY29ycmVjdGx5XHJcblx0XHRcdFx0XHQvLyB0aGV5IHNpbXBseSByZWZlcmVuY2UgdGhlIHJlbmRlcmVyJ3Mgc3RhdGUgZm9yIHRoZWlyXHJcblx0XHRcdFx0XHQvLyB2YWx1ZXNcclxuXHRcdFx0XHRcdC8vXHJcblx0XHRcdFx0XHQvLyB1c2UgdGhlIGN1cnJlbnQgbWF0ZXJpYWwncyAubmVlZHNVcGRhdGUgZmxhZ3MgdG8gc2V0XHJcblx0XHRcdFx0XHQvLyB0aGUgR0wgc3RhdGUgd2hlbiByZXF1aXJlZFxyXG5cclxuXHRcdFx0XHRcdG1hcmtVbmlmb3Jtc0xpZ2h0c05lZWRzVXBkYXRlKCBtX3VuaWZvcm1zLCByZWZyZXNoTGlnaHRzICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0Ly8gcmVmcmVzaCB1bmlmb3JtcyBjb21tb24gdG8gc2V2ZXJhbCBtYXRlcmlhbHNcclxuXHJcblx0XHRcdFx0aWYgKCBmb2cgJiYgbWF0ZXJpYWwuZm9nID09PSB0cnVlICkge1xyXG5cclxuXHRcdFx0XHRcdG1hdGVyaWFscy5yZWZyZXNoRm9nVW5pZm9ybXMoIG1fdW5pZm9ybXMsIGZvZyApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdG1hdGVyaWFscy5yZWZyZXNoTWF0ZXJpYWxVbmlmb3JtcyggbV91bmlmb3JtcywgbWF0ZXJpYWwsIF9waXhlbFJhdGlvLCBfaGVpZ2h0LCBfdHJhbnNtaXNzaW9uUmVuZGVyVGFyZ2V0ICk7XHJcblxyXG5cdFx0XHRcdFdlYkdMVW5pZm9ybXMudXBsb2FkKCBfZ2wsIGdldFVuaWZvcm1MaXN0KCBtYXRlcmlhbFByb3BlcnRpZXMgKSwgbV91bmlmb3JtcywgdGV4dHVyZXMgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGlmICggbWF0ZXJpYWwuaXNTaGFkZXJNYXRlcmlhbCAmJiBtYXRlcmlhbC51bmlmb3Jtc05lZWRVcGRhdGUgPT09IHRydWUgKSB7XHJcblxyXG5cdFx0XHRcdFdlYkdMVW5pZm9ybXMudXBsb2FkKCBfZ2wsIGdldFVuaWZvcm1MaXN0KCBtYXRlcmlhbFByb3BlcnRpZXMgKSwgbV91bmlmb3JtcywgdGV4dHVyZXMgKTtcclxuXHRcdFx0XHRtYXRlcmlhbC51bmlmb3Jtc05lZWRVcGRhdGUgPSBmYWxzZTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGlmICggbWF0ZXJpYWwuaXNTcHJpdGVNYXRlcmlhbCApIHtcclxuXHJcblx0XHRcdFx0cF91bmlmb3Jtcy5zZXRWYWx1ZSggX2dsLCAnY2VudGVyJywgb2JqZWN0LmNlbnRlciApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Ly8gY29tbW9uIG1hdHJpY2VzXHJcblxyXG5cdFx0XHRwX3VuaWZvcm1zLnNldFZhbHVlKCBfZ2wsICdtb2RlbFZpZXdNYXRyaXgnLCBvYmplY3QubW9kZWxWaWV3TWF0cml4ICk7XHJcblx0XHRcdHBfdW5pZm9ybXMuc2V0VmFsdWUoIF9nbCwgJ25vcm1hbE1hdHJpeCcsIG9iamVjdC5ub3JtYWxNYXRyaXggKTtcclxuXHRcdFx0cF91bmlmb3Jtcy5zZXRWYWx1ZSggX2dsLCAnbW9kZWxNYXRyaXgnLCBvYmplY3QubWF0cml4V29ybGQgKTtcclxuXHJcblx0XHRcdC8vIFVCT3NcclxuXHJcblx0XHRcdGlmICggbWF0ZXJpYWwuaXNTaGFkZXJNYXRlcmlhbCB8fCBtYXRlcmlhbC5pc1Jhd1NoYWRlck1hdGVyaWFsICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBncm91cHMgPSBtYXRlcmlhbC51bmlmb3Jtc0dyb3VwcztcclxuXHJcblx0XHRcdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gZ3JvdXBzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCBjYXBhYmlsaXRpZXMuaXNXZWJHTDIgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRjb25zdCBncm91cCA9IGdyb3Vwc1sgaSBdO1xyXG5cclxuXHRcdFx0XHRcdFx0dW5pZm9ybXNHcm91cHMudXBkYXRlKCBncm91cCwgcHJvZ3JhbSApO1xyXG5cdFx0XHRcdFx0XHR1bmlmb3Jtc0dyb3Vwcy5iaW5kKCBncm91cCwgcHJvZ3JhbSApO1xyXG5cclxuXHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5XZWJHTFJlbmRlcmVyOiBVbmlmb3JtIEJ1ZmZlciBPYmplY3RzIGNhbiBvbmx5IGJlIHVzZWQgd2l0aCBXZWJHTCAyLicgKTtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHJldHVybiBwcm9ncmFtO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvLyBJZiB1bmlmb3JtcyBhcmUgbWFya2VkIGFzIGNsZWFuLCB0aGV5IGRvbid0IG5lZWQgdG8gYmUgbG9hZGVkIHRvIHRoZSBHUFUuXHJcblxyXG5cdFx0ZnVuY3Rpb24gbWFya1VuaWZvcm1zTGlnaHRzTmVlZHNVcGRhdGUoIHVuaWZvcm1zLCB2YWx1ZSApIHtcclxuXHJcblx0XHRcdHVuaWZvcm1zLmFtYmllbnRMaWdodENvbG9yLm5lZWRzVXBkYXRlID0gdmFsdWU7XHJcblx0XHRcdHVuaWZvcm1zLmxpZ2h0UHJvYmUubmVlZHNVcGRhdGUgPSB2YWx1ZTtcclxuXHJcblx0XHRcdHVuaWZvcm1zLmRpcmVjdGlvbmFsTGlnaHRzLm5lZWRzVXBkYXRlID0gdmFsdWU7XHJcblx0XHRcdHVuaWZvcm1zLmRpcmVjdGlvbmFsTGlnaHRTaGFkb3dzLm5lZWRzVXBkYXRlID0gdmFsdWU7XHJcblx0XHRcdHVuaWZvcm1zLnBvaW50TGlnaHRzLm5lZWRzVXBkYXRlID0gdmFsdWU7XHJcblx0XHRcdHVuaWZvcm1zLnBvaW50TGlnaHRTaGFkb3dzLm5lZWRzVXBkYXRlID0gdmFsdWU7XHJcblx0XHRcdHVuaWZvcm1zLnNwb3RMaWdodHMubmVlZHNVcGRhdGUgPSB2YWx1ZTtcclxuXHRcdFx0dW5pZm9ybXMuc3BvdExpZ2h0U2hhZG93cy5uZWVkc1VwZGF0ZSA9IHZhbHVlO1xyXG5cdFx0XHR1bmlmb3Jtcy5yZWN0QXJlYUxpZ2h0cy5uZWVkc1VwZGF0ZSA9IHZhbHVlO1xyXG5cdFx0XHR1bmlmb3Jtcy5oZW1pc3BoZXJlTGlnaHRzLm5lZWRzVXBkYXRlID0gdmFsdWU7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGZ1bmN0aW9uIG1hdGVyaWFsTmVlZHNMaWdodHMoIG1hdGVyaWFsICkge1xyXG5cclxuXHRcdFx0cmV0dXJuIG1hdGVyaWFsLmlzTWVzaExhbWJlcnRNYXRlcmlhbCB8fCBtYXRlcmlhbC5pc01lc2hUb29uTWF0ZXJpYWwgfHwgbWF0ZXJpYWwuaXNNZXNoUGhvbmdNYXRlcmlhbCB8fFxyXG5cdFx0XHRcdG1hdGVyaWFsLmlzTWVzaFN0YW5kYXJkTWF0ZXJpYWwgfHwgbWF0ZXJpYWwuaXNTaGFkb3dNYXRlcmlhbCB8fFxyXG5cdFx0XHRcdCggbWF0ZXJpYWwuaXNTaGFkZXJNYXRlcmlhbCAmJiBtYXRlcmlhbC5saWdodHMgPT09IHRydWUgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5nZXRBY3RpdmVDdWJlRmFjZSA9IGZ1bmN0aW9uICgpIHtcclxuXHJcblx0XHRcdHJldHVybiBfY3VycmVudEFjdGl2ZUN1YmVGYWNlO1xyXG5cclxuXHRcdH07XHJcblxyXG5cdFx0dGhpcy5nZXRBY3RpdmVNaXBtYXBMZXZlbCA9IGZ1bmN0aW9uICgpIHtcclxuXHJcblx0XHRcdHJldHVybiBfY3VycmVudEFjdGl2ZU1pcG1hcExldmVsO1xyXG5cclxuXHRcdH07XHJcblxyXG5cdFx0dGhpcy5nZXRSZW5kZXJUYXJnZXQgPSBmdW5jdGlvbiAoKSB7XHJcblxyXG5cdFx0XHRyZXR1cm4gX2N1cnJlbnRSZW5kZXJUYXJnZXQ7XHJcblxyXG5cdFx0fTtcclxuXHJcblx0XHR0aGlzLnNldFJlbmRlclRhcmdldFRleHR1cmVzID0gZnVuY3Rpb24gKCByZW5kZXJUYXJnZXQsIGNvbG9yVGV4dHVyZSwgZGVwdGhUZXh0dXJlICkge1xyXG5cclxuXHRcdFx0cHJvcGVydGllcy5nZXQoIHJlbmRlclRhcmdldC50ZXh0dXJlICkuX193ZWJnbFRleHR1cmUgPSBjb2xvclRleHR1cmU7XHJcblx0XHRcdHByb3BlcnRpZXMuZ2V0KCByZW5kZXJUYXJnZXQuZGVwdGhUZXh0dXJlICkuX193ZWJnbFRleHR1cmUgPSBkZXB0aFRleHR1cmU7XHJcblxyXG5cdFx0XHRjb25zdCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzID0gcHJvcGVydGllcy5nZXQoIHJlbmRlclRhcmdldCApO1xyXG5cdFx0XHRyZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9faGFzRXh0ZXJuYWxUZXh0dXJlcyA9IHRydWU7XHJcblxyXG5cdFx0XHRpZiAoIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX19oYXNFeHRlcm5hbFRleHR1cmVzICkge1xyXG5cclxuXHRcdFx0XHRyZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fYXV0b0FsbG9jYXRlRGVwdGhCdWZmZXIgPSBkZXB0aFRleHR1cmUgPT09IHVuZGVmaW5lZDtcclxuXHJcblx0XHRcdFx0aWYgKCAhIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX19hdXRvQWxsb2NhdGVEZXB0aEJ1ZmZlciApIHtcclxuXHJcblx0XHRcdFx0XHQvLyBUaGUgbXVsdGlzYW1wbGVfcmVuZGVyX3RvX3RleHR1cmUgZXh0ZW5zaW9uIGRvZXNuJ3Qgd29yayBwcm9wZXJseSBpZiB0aGVyZVxyXG5cdFx0XHRcdFx0Ly8gYXJlIG1pZGZyYW1lIGZsdXNoZXMgYW5kIGFuIGV4dGVybmFsIGRlcHRoIGJ1ZmZlci4gRGlzYWJsZSB1c2Ugb2YgdGhlIGV4dGVuc2lvbi5cclxuXHRcdFx0XHRcdGlmICggZXh0ZW5zaW9ucy5oYXMoICdXRUJHTF9tdWx0aXNhbXBsZWRfcmVuZGVyX3RvX3RleHR1cmUnICkgPT09IHRydWUgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5XZWJHTFJlbmRlcmVyOiBSZW5kZXItdG8tdGV4dHVyZSBleHRlbnNpb24gd2FzIGRpc2FibGVkIGJlY2F1c2UgYW4gZXh0ZXJuYWwgdGV4dHVyZSB3YXMgcHJvdmlkZWQnICk7XHJcblx0XHRcdFx0XHRcdHJlbmRlclRhcmdldFByb3BlcnRpZXMuX191c2VSZW5kZXJUb1RleHR1cmUgPSBmYWxzZTtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9O1xyXG5cclxuXHRcdHRoaXMuc2V0UmVuZGVyVGFyZ2V0RnJhbWVidWZmZXIgPSBmdW5jdGlvbiAoIHJlbmRlclRhcmdldCwgZGVmYXVsdEZyYW1lYnVmZmVyICkge1xyXG5cclxuXHRcdFx0Y29uc3QgcmVuZGVyVGFyZ2V0UHJvcGVydGllcyA9IHByb3BlcnRpZXMuZ2V0KCByZW5kZXJUYXJnZXQgKTtcclxuXHRcdFx0cmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX3dlYmdsRnJhbWVidWZmZXIgPSBkZWZhdWx0RnJhbWVidWZmZXI7XHJcblx0XHRcdHJlbmRlclRhcmdldFByb3BlcnRpZXMuX191c2VEZWZhdWx0RnJhbWVidWZmZXIgPSBkZWZhdWx0RnJhbWVidWZmZXIgPT09IHVuZGVmaW5lZDtcclxuXHJcblx0XHR9O1xyXG5cclxuXHRcdHRoaXMuc2V0UmVuZGVyVGFyZ2V0ID0gZnVuY3Rpb24gKCByZW5kZXJUYXJnZXQsIGFjdGl2ZUN1YmVGYWNlID0gMCwgYWN0aXZlTWlwbWFwTGV2ZWwgPSAwICkge1xyXG5cclxuXHRcdFx0X2N1cnJlbnRSZW5kZXJUYXJnZXQgPSByZW5kZXJUYXJnZXQ7XHJcblx0XHRcdF9jdXJyZW50QWN0aXZlQ3ViZUZhY2UgPSBhY3RpdmVDdWJlRmFjZTtcclxuXHRcdFx0X2N1cnJlbnRBY3RpdmVNaXBtYXBMZXZlbCA9IGFjdGl2ZU1pcG1hcExldmVsO1xyXG5cclxuXHRcdFx0bGV0IHVzZURlZmF1bHRGcmFtZWJ1ZmZlciA9IHRydWU7XHJcblx0XHRcdGxldCBmcmFtZWJ1ZmZlciA9IG51bGw7XHJcblx0XHRcdGxldCBpc0N1YmUgPSBmYWxzZTtcclxuXHRcdFx0bGV0IGlzUmVuZGVyVGFyZ2V0M0QgPSBmYWxzZTtcclxuXHJcblx0XHRcdGlmICggcmVuZGVyVGFyZ2V0ICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzID0gcHJvcGVydGllcy5nZXQoIHJlbmRlclRhcmdldCApO1xyXG5cclxuXHRcdFx0XHRpZiAoIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX191c2VEZWZhdWx0RnJhbWVidWZmZXIgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0XHQvLyBXZSBuZWVkIHRvIG1ha2Ugc3VyZSB0byByZWJpbmQgdGhlIGZyYW1lYnVmZmVyLlxyXG5cdFx0XHRcdFx0c3RhdGUuYmluZEZyYW1lYnVmZmVyKCBfZ2wuRlJBTUVCVUZGRVIsIG51bGwgKTtcclxuXHRcdFx0XHRcdHVzZURlZmF1bHRGcmFtZWJ1ZmZlciA9IGZhbHNlO1xyXG5cclxuXHRcdFx0XHR9IGVsc2UgaWYgKCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xGcmFtZWJ1ZmZlciA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHRcdHRleHR1cmVzLnNldHVwUmVuZGVyVGFyZ2V0KCByZW5kZXJUYXJnZXQgKTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIGlmICggcmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX2hhc0V4dGVybmFsVGV4dHVyZXMgKSB7XHJcblxyXG5cdFx0XHRcdFx0Ly8gQ29sb3IgYW5kIGRlcHRoIHRleHR1cmUgbXVzdCBiZSByZWJvdW5kIGluIG9yZGVyIGZvciB0aGUgc3dhcGNoYWluIHRvIHVwZGF0ZS5cclxuXHRcdFx0XHRcdHRleHR1cmVzLnJlYmluZFRleHR1cmVzKCByZW5kZXJUYXJnZXQsIHByb3BlcnRpZXMuZ2V0KCByZW5kZXJUYXJnZXQudGV4dHVyZSApLl9fd2ViZ2xUZXh0dXJlLCBwcm9wZXJ0aWVzLmdldCggcmVuZGVyVGFyZ2V0LmRlcHRoVGV4dHVyZSApLl9fd2ViZ2xUZXh0dXJlICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0Y29uc3QgdGV4dHVyZSA9IHJlbmRlclRhcmdldC50ZXh0dXJlO1xyXG5cclxuXHRcdFx0XHRpZiAoIHRleHR1cmUuaXNEYXRhM0RUZXh0dXJlIHx8IHRleHR1cmUuaXNEYXRhQXJyYXlUZXh0dXJlIHx8IHRleHR1cmUuaXNDb21wcmVzc2VkQXJyYXlUZXh0dXJlICkge1xyXG5cclxuXHRcdFx0XHRcdGlzUmVuZGVyVGFyZ2V0M0QgPSB0cnVlO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdGNvbnN0IF9fd2ViZ2xGcmFtZWJ1ZmZlciA9IHByb3BlcnRpZXMuZ2V0KCByZW5kZXJUYXJnZXQgKS5fX3dlYmdsRnJhbWVidWZmZXI7XHJcblxyXG5cdFx0XHRcdGlmICggcmVuZGVyVGFyZ2V0LmlzV2ViR0xDdWJlUmVuZGVyVGFyZ2V0ICkge1xyXG5cclxuXHRcdFx0XHRcdGlmICggQXJyYXkuaXNBcnJheSggX193ZWJnbEZyYW1lYnVmZmVyWyBhY3RpdmVDdWJlRmFjZSBdICkgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRmcmFtZWJ1ZmZlciA9IF9fd2ViZ2xGcmFtZWJ1ZmZlclsgYWN0aXZlQ3ViZUZhY2UgXVsgYWN0aXZlTWlwbWFwTGV2ZWwgXTtcclxuXHJcblx0XHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdFx0ZnJhbWVidWZmZXIgPSBfX3dlYmdsRnJhbWVidWZmZXJbIGFjdGl2ZUN1YmVGYWNlIF07XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdGlzQ3ViZSA9IHRydWU7XHJcblxyXG5cdFx0XHRcdH0gZWxzZSBpZiAoICggY2FwYWJpbGl0aWVzLmlzV2ViR0wyICYmIHJlbmRlclRhcmdldC5zYW1wbGVzID4gMCApICYmIHRleHR1cmVzLnVzZU11bHRpc2FtcGxlZFJUVCggcmVuZGVyVGFyZ2V0ICkgPT09IGZhbHNlICkge1xyXG5cclxuXHRcdFx0XHRcdGZyYW1lYnVmZmVyID0gcHJvcGVydGllcy5nZXQoIHJlbmRlclRhcmdldCApLl9fd2ViZ2xNdWx0aXNhbXBsZWRGcmFtZWJ1ZmZlcjtcclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRpZiAoIEFycmF5LmlzQXJyYXkoIF9fd2ViZ2xGcmFtZWJ1ZmZlciApICkge1xyXG5cclxuXHRcdFx0XHRcdFx0ZnJhbWVidWZmZXIgPSBfX3dlYmdsRnJhbWVidWZmZXJbIGFjdGl2ZU1pcG1hcExldmVsIF07XHJcblxyXG5cdFx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRcdGZyYW1lYnVmZmVyID0gX193ZWJnbEZyYW1lYnVmZmVyO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRfY3VycmVudFZpZXdwb3J0LmNvcHkoIHJlbmRlclRhcmdldC52aWV3cG9ydCApO1xyXG5cdFx0XHRcdF9jdXJyZW50U2Npc3Nvci5jb3B5KCByZW5kZXJUYXJnZXQuc2Npc3NvciApO1xyXG5cdFx0XHRcdF9jdXJyZW50U2Npc3NvclRlc3QgPSByZW5kZXJUYXJnZXQuc2Npc3NvclRlc3Q7XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRfY3VycmVudFZpZXdwb3J0LmNvcHkoIF92aWV3cG9ydCApLm11bHRpcGx5U2NhbGFyKCBfcGl4ZWxSYXRpbyApLmZsb29yKCk7XHJcblx0XHRcdFx0X2N1cnJlbnRTY2lzc29yLmNvcHkoIF9zY2lzc29yICkubXVsdGlwbHlTY2FsYXIoIF9waXhlbFJhdGlvICkuZmxvb3IoKTtcclxuXHRcdFx0XHRfY3VycmVudFNjaXNzb3JUZXN0ID0gX3NjaXNzb3JUZXN0O1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Y29uc3QgZnJhbWVidWZmZXJCb3VuZCA9IHN0YXRlLmJpbmRGcmFtZWJ1ZmZlciggX2dsLkZSQU1FQlVGRkVSLCBmcmFtZWJ1ZmZlciApO1xyXG5cclxuXHRcdFx0aWYgKCBmcmFtZWJ1ZmZlckJvdW5kICYmIGNhcGFiaWxpdGllcy5kcmF3QnVmZmVycyAmJiB1c2VEZWZhdWx0RnJhbWVidWZmZXIgKSB7XHJcblxyXG5cdFx0XHRcdHN0YXRlLmRyYXdCdWZmZXJzKCByZW5kZXJUYXJnZXQsIGZyYW1lYnVmZmVyICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRzdGF0ZS52aWV3cG9ydCggX2N1cnJlbnRWaWV3cG9ydCApO1xyXG5cdFx0XHRzdGF0ZS5zY2lzc29yKCBfY3VycmVudFNjaXNzb3IgKTtcclxuXHRcdFx0c3RhdGUuc2V0U2Npc3NvclRlc3QoIF9jdXJyZW50U2Npc3NvclRlc3QgKTtcclxuXHJcblx0XHRcdGlmICggaXNDdWJlICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCB0ZXh0dXJlUHJvcGVydGllcyA9IHByb3BlcnRpZXMuZ2V0KCByZW5kZXJUYXJnZXQudGV4dHVyZSApO1xyXG5cdFx0XHRcdF9nbC5mcmFtZWJ1ZmZlclRleHR1cmUyRCggX2dsLkZSQU1FQlVGRkVSLCBfZ2wuQ09MT1JfQVRUQUNITUVOVDAsIF9nbC5URVhUVVJFX0NVQkVfTUFQX1BPU0lUSVZFX1ggKyBhY3RpdmVDdWJlRmFjZSwgdGV4dHVyZVByb3BlcnRpZXMuX193ZWJnbFRleHR1cmUsIGFjdGl2ZU1pcG1hcExldmVsICk7XHJcblxyXG5cdFx0XHR9IGVsc2UgaWYgKCBpc1JlbmRlclRhcmdldDNEICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCB0ZXh0dXJlUHJvcGVydGllcyA9IHByb3BlcnRpZXMuZ2V0KCByZW5kZXJUYXJnZXQudGV4dHVyZSApO1xyXG5cdFx0XHRcdGNvbnN0IGxheWVyID0gYWN0aXZlQ3ViZUZhY2UgfHwgMDtcclxuXHRcdFx0XHRfZ2wuZnJhbWVidWZmZXJUZXh0dXJlTGF5ZXIoIF9nbC5GUkFNRUJVRkZFUiwgX2dsLkNPTE9SX0FUVEFDSE1FTlQwLCB0ZXh0dXJlUHJvcGVydGllcy5fX3dlYmdsVGV4dHVyZSwgYWN0aXZlTWlwbWFwTGV2ZWwgfHwgMCwgbGF5ZXIgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdF9jdXJyZW50TWF0ZXJpYWxJZCA9IC0gMTsgLy8gcmVzZXQgY3VycmVudCBtYXRlcmlhbCB0byBlbnN1cmUgY29ycmVjdCB1bmlmb3JtIGJpbmRpbmdzXHJcblxyXG5cdFx0fTtcclxuXHJcblx0XHR0aGlzLnJlYWRSZW5kZXJUYXJnZXRQaXhlbHMgPSBmdW5jdGlvbiAoIHJlbmRlclRhcmdldCwgeCwgeSwgd2lkdGgsIGhlaWdodCwgYnVmZmVyLCBhY3RpdmVDdWJlRmFjZUluZGV4ICkge1xyXG5cclxuXHRcdFx0aWYgKCAhICggcmVuZGVyVGFyZ2V0ICYmIHJlbmRlclRhcmdldC5pc1dlYkdMUmVuZGVyVGFyZ2V0ICkgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5XZWJHTFJlbmRlcmVyLnJlYWRSZW5kZXJUYXJnZXRQaXhlbHM6IHJlbmRlclRhcmdldCBpcyBub3QgVEhSRUUuV2ViR0xSZW5kZXJUYXJnZXQuJyApO1xyXG5cdFx0XHRcdHJldHVybjtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGxldCBmcmFtZWJ1ZmZlciA9IHByb3BlcnRpZXMuZ2V0KCByZW5kZXJUYXJnZXQgKS5fX3dlYmdsRnJhbWVidWZmZXI7XHJcblxyXG5cdFx0XHRpZiAoIHJlbmRlclRhcmdldC5pc1dlYkdMQ3ViZVJlbmRlclRhcmdldCAmJiBhY3RpdmVDdWJlRmFjZUluZGV4ICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRcdGZyYW1lYnVmZmVyID0gZnJhbWVidWZmZXJbIGFjdGl2ZUN1YmVGYWNlSW5kZXggXTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGlmICggZnJhbWVidWZmZXIgKSB7XHJcblxyXG5cdFx0XHRcdHN0YXRlLmJpbmRGcmFtZWJ1ZmZlciggX2dsLkZSQU1FQlVGRkVSLCBmcmFtZWJ1ZmZlciApO1xyXG5cclxuXHRcdFx0XHR0cnkge1xyXG5cclxuXHRcdFx0XHRcdGNvbnN0IHRleHR1cmUgPSByZW5kZXJUYXJnZXQudGV4dHVyZTtcclxuXHRcdFx0XHRcdGNvbnN0IHRleHR1cmVGb3JtYXQgPSB0ZXh0dXJlLmZvcm1hdDtcclxuXHRcdFx0XHRcdGNvbnN0IHRleHR1cmVUeXBlID0gdGV4dHVyZS50eXBlO1xyXG5cclxuXHRcdFx0XHRcdGlmICggdGV4dHVyZUZvcm1hdCAhPT0gUkdCQUZvcm1hdCAmJiB1dGlscy5jb252ZXJ0KCB0ZXh0dXJlRm9ybWF0ICkgIT09IF9nbC5nZXRQYXJhbWV0ZXIoIF9nbC5JTVBMRU1FTlRBVElPTl9DT0xPUl9SRUFEX0ZPUk1BVCApICkge1xyXG5cclxuXHRcdFx0XHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLldlYkdMUmVuZGVyZXIucmVhZFJlbmRlclRhcmdldFBpeGVsczogcmVuZGVyVGFyZ2V0IGlzIG5vdCBpbiBSR0JBIG9yIGltcGxlbWVudGF0aW9uIGRlZmluZWQgZm9ybWF0LicgKTtcclxuXHRcdFx0XHRcdFx0cmV0dXJuO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRjb25zdCBoYWxmRmxvYXRTdXBwb3J0ZWRCeUV4dCA9ICggdGV4dHVyZVR5cGUgPT09IEhhbGZGbG9hdFR5cGUgKSAmJiAoIGV4dGVuc2lvbnMuaGFzKCAnRVhUX2NvbG9yX2J1ZmZlcl9oYWxmX2Zsb2F0JyApIHx8ICggY2FwYWJpbGl0aWVzLmlzV2ViR0wyICYmIGV4dGVuc2lvbnMuaGFzKCAnRVhUX2NvbG9yX2J1ZmZlcl9mbG9hdCcgKSApICk7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCB0ZXh0dXJlVHlwZSAhPT0gVW5zaWduZWRCeXRlVHlwZSAmJiB1dGlscy5jb252ZXJ0KCB0ZXh0dXJlVHlwZSApICE9PSBfZ2wuZ2V0UGFyYW1ldGVyKCBfZ2wuSU1QTEVNRU5UQVRJT05fQ09MT1JfUkVBRF9UWVBFICkgJiYgLy8gRWRnZSBhbmQgQ2hyb21lIE1hYyA8IDUyICgjOTUxMylcclxuXHRcdFx0XHRcdFx0ISAoIHRleHR1cmVUeXBlID09PSBGbG9hdFR5cGUgJiYgKCBjYXBhYmlsaXRpZXMuaXNXZWJHTDIgfHwgZXh0ZW5zaW9ucy5oYXMoICdPRVNfdGV4dHVyZV9mbG9hdCcgKSB8fCBleHRlbnNpb25zLmhhcyggJ1dFQkdMX2NvbG9yX2J1ZmZlcl9mbG9hdCcgKSApICkgJiYgLy8gQ2hyb21lIE1hYyA+PSA1MiBhbmQgRmlyZWZveFxyXG5cdFx0XHRcdFx0XHQhIGhhbGZGbG9hdFN1cHBvcnRlZEJ5RXh0ICkge1xyXG5cclxuXHRcdFx0XHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLldlYkdMUmVuZGVyZXIucmVhZFJlbmRlclRhcmdldFBpeGVsczogcmVuZGVyVGFyZ2V0IGlzIG5vdCBpbiBVbnNpZ25lZEJ5dGVUeXBlIG9yIGltcGxlbWVudGF0aW9uIGRlZmluZWQgdHlwZS4nICk7XHJcblx0XHRcdFx0XHRcdHJldHVybjtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0Ly8gdGhlIGZvbGxvd2luZyBpZiBzdGF0ZW1lbnQgZW5zdXJlcyB2YWxpZCByZWFkIHJlcXVlc3RzIChubyBvdXQtb2YtYm91bmRzIHBpeGVscywgc2VlICM4NjA0KVxyXG5cclxuXHRcdFx0XHRcdGlmICggKCB4ID49IDAgJiYgeCA8PSAoIHJlbmRlclRhcmdldC53aWR0aCAtIHdpZHRoICkgKSAmJiAoIHkgPj0gMCAmJiB5IDw9ICggcmVuZGVyVGFyZ2V0LmhlaWdodCAtIGhlaWdodCApICkgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRfZ2wucmVhZFBpeGVscyggeCwgeSwgd2lkdGgsIGhlaWdodCwgdXRpbHMuY29udmVydCggdGV4dHVyZUZvcm1hdCApLCB1dGlscy5jb252ZXJ0KCB0ZXh0dXJlVHlwZSApLCBidWZmZXIgKTtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH0gZmluYWxseSB7XHJcblxyXG5cdFx0XHRcdFx0Ly8gcmVzdG9yZSBmcmFtZWJ1ZmZlciBvZiBjdXJyZW50IHJlbmRlciB0YXJnZXQgaWYgbmVjZXNzYXJ5XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgZnJhbWVidWZmZXIgPSAoIF9jdXJyZW50UmVuZGVyVGFyZ2V0ICE9PSBudWxsICkgPyBwcm9wZXJ0aWVzLmdldCggX2N1cnJlbnRSZW5kZXJUYXJnZXQgKS5fX3dlYmdsRnJhbWVidWZmZXIgOiBudWxsO1xyXG5cdFx0XHRcdFx0c3RhdGUuYmluZEZyYW1lYnVmZmVyKCBfZ2wuRlJBTUVCVUZGRVIsIGZyYW1lYnVmZmVyICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9O1xyXG5cclxuXHRcdHRoaXMuY29weUZyYW1lYnVmZmVyVG9UZXh0dXJlID0gZnVuY3Rpb24gKCBwb3NpdGlvbiwgdGV4dHVyZSwgbGV2ZWwgPSAwICkge1xyXG5cclxuXHRcdFx0Y29uc3QgbGV2ZWxTY2FsZSA9IE1hdGgucG93KCAyLCAtIGxldmVsICk7XHJcblx0XHRcdGNvbnN0IHdpZHRoID0gTWF0aC5mbG9vciggdGV4dHVyZS5pbWFnZS53aWR0aCAqIGxldmVsU2NhbGUgKTtcclxuXHRcdFx0Y29uc3QgaGVpZ2h0ID0gTWF0aC5mbG9vciggdGV4dHVyZS5pbWFnZS5oZWlnaHQgKiBsZXZlbFNjYWxlICk7XHJcblxyXG5cdFx0XHR0ZXh0dXJlcy5zZXRUZXh0dXJlMkQoIHRleHR1cmUsIDAgKTtcclxuXHJcblx0XHRcdF9nbC5jb3B5VGV4U3ViSW1hZ2UyRCggX2dsLlRFWFRVUkVfMkQsIGxldmVsLCAwLCAwLCBwb3NpdGlvbi54LCBwb3NpdGlvbi55LCB3aWR0aCwgaGVpZ2h0ICk7XHJcblxyXG5cdFx0XHRzdGF0ZS51bmJpbmRUZXh0dXJlKCk7XHJcblxyXG5cdFx0fTtcclxuXHJcblx0XHR0aGlzLmNvcHlUZXh0dXJlVG9UZXh0dXJlID0gZnVuY3Rpb24gKCBwb3NpdGlvbiwgc3JjVGV4dHVyZSwgZHN0VGV4dHVyZSwgbGV2ZWwgPSAwICkge1xyXG5cclxuXHRcdFx0Y29uc3Qgd2lkdGggPSBzcmNUZXh0dXJlLmltYWdlLndpZHRoO1xyXG5cdFx0XHRjb25zdCBoZWlnaHQgPSBzcmNUZXh0dXJlLmltYWdlLmhlaWdodDtcclxuXHRcdFx0Y29uc3QgZ2xGb3JtYXQgPSB1dGlscy5jb252ZXJ0KCBkc3RUZXh0dXJlLmZvcm1hdCApO1xyXG5cdFx0XHRjb25zdCBnbFR5cGUgPSB1dGlscy5jb252ZXJ0KCBkc3RUZXh0dXJlLnR5cGUgKTtcclxuXHJcblx0XHRcdHRleHR1cmVzLnNldFRleHR1cmUyRCggZHN0VGV4dHVyZSwgMCApO1xyXG5cclxuXHRcdFx0Ly8gQXMgYW5vdGhlciB0ZXh0dXJlIHVwbG9hZCBtYXkgaGF2ZSBjaGFuZ2VkIHBpeGVsU3RvcmVpXHJcblx0XHRcdC8vIHBhcmFtZXRlcnMsIG1ha2Ugc3VyZSB0aGV5IGFyZSBjb3JyZWN0IGZvciB0aGUgZHN0VGV4dHVyZVxyXG5cdFx0XHRfZ2wucGl4ZWxTdG9yZWkoIF9nbC5VTlBBQ0tfRkxJUF9ZX1dFQkdMLCBkc3RUZXh0dXJlLmZsaXBZICk7XHJcblx0XHRcdF9nbC5waXhlbFN0b3JlaSggX2dsLlVOUEFDS19QUkVNVUxUSVBMWV9BTFBIQV9XRUJHTCwgZHN0VGV4dHVyZS5wcmVtdWx0aXBseUFscGhhICk7XHJcblx0XHRcdF9nbC5waXhlbFN0b3JlaSggX2dsLlVOUEFDS19BTElHTk1FTlQsIGRzdFRleHR1cmUudW5wYWNrQWxpZ25tZW50ICk7XHJcblxyXG5cdFx0XHRpZiAoIHNyY1RleHR1cmUuaXNEYXRhVGV4dHVyZSApIHtcclxuXHJcblx0XHRcdFx0X2dsLnRleFN1YkltYWdlMkQoIF9nbC5URVhUVVJFXzJELCBsZXZlbCwgcG9zaXRpb24ueCwgcG9zaXRpb24ueSwgd2lkdGgsIGhlaWdodCwgZ2xGb3JtYXQsIGdsVHlwZSwgc3JjVGV4dHVyZS5pbWFnZS5kYXRhICk7XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRpZiAoIHNyY1RleHR1cmUuaXNDb21wcmVzc2VkVGV4dHVyZSApIHtcclxuXHJcblx0XHRcdFx0XHRfZ2wuY29tcHJlc3NlZFRleFN1YkltYWdlMkQoIF9nbC5URVhUVVJFXzJELCBsZXZlbCwgcG9zaXRpb24ueCwgcG9zaXRpb24ueSwgc3JjVGV4dHVyZS5taXBtYXBzWyAwIF0ud2lkdGgsIHNyY1RleHR1cmUubWlwbWFwc1sgMCBdLmhlaWdodCwgZ2xGb3JtYXQsIHNyY1RleHR1cmUubWlwbWFwc1sgMCBdLmRhdGEgKTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRfZ2wudGV4U3ViSW1hZ2UyRCggX2dsLlRFWFRVUkVfMkQsIGxldmVsLCBwb3NpdGlvbi54LCBwb3NpdGlvbi55LCBnbEZvcm1hdCwgZ2xUeXBlLCBzcmNUZXh0dXJlLmltYWdlICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdC8vIEdlbmVyYXRlIG1pcG1hcHMgb25seSB3aGVuIGNvcHlpbmcgbGV2ZWwgMFxyXG5cdFx0XHRpZiAoIGxldmVsID09PSAwICYmIGRzdFRleHR1cmUuZ2VuZXJhdGVNaXBtYXBzICkgX2dsLmdlbmVyYXRlTWlwbWFwKCBfZ2wuVEVYVFVSRV8yRCApO1xyXG5cclxuXHRcdFx0c3RhdGUudW5iaW5kVGV4dHVyZSgpO1xyXG5cclxuXHRcdH07XHJcblxyXG5cdFx0dGhpcy5jb3B5VGV4dHVyZVRvVGV4dHVyZTNEID0gZnVuY3Rpb24gKCBzb3VyY2VCb3gsIHBvc2l0aW9uLCBzcmNUZXh0dXJlLCBkc3RUZXh0dXJlLCBsZXZlbCA9IDAgKSB7XHJcblxyXG5cdFx0XHRpZiAoIF90aGlzLmlzV2ViR0wxUmVuZGVyZXIgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLldlYkdMUmVuZGVyZXIuY29weVRleHR1cmVUb1RleHR1cmUzRDogY2FuIG9ubHkgYmUgdXNlZCB3aXRoIFdlYkdMMi4nICk7XHJcblx0XHRcdFx0cmV0dXJuO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Y29uc3Qgd2lkdGggPSBzb3VyY2VCb3gubWF4LnggLSBzb3VyY2VCb3gubWluLnggKyAxO1xyXG5cdFx0XHRjb25zdCBoZWlnaHQgPSBzb3VyY2VCb3gubWF4LnkgLSBzb3VyY2VCb3gubWluLnkgKyAxO1xyXG5cdFx0XHRjb25zdCBkZXB0aCA9IHNvdXJjZUJveC5tYXgueiAtIHNvdXJjZUJveC5taW4ueiArIDE7XHJcblx0XHRcdGNvbnN0IGdsRm9ybWF0ID0gdXRpbHMuY29udmVydCggZHN0VGV4dHVyZS5mb3JtYXQgKTtcclxuXHRcdFx0Y29uc3QgZ2xUeXBlID0gdXRpbHMuY29udmVydCggZHN0VGV4dHVyZS50eXBlICk7XHJcblx0XHRcdGxldCBnbFRhcmdldDtcclxuXHJcblx0XHRcdGlmICggZHN0VGV4dHVyZS5pc0RhdGEzRFRleHR1cmUgKSB7XHJcblxyXG5cdFx0XHRcdHRleHR1cmVzLnNldFRleHR1cmUzRCggZHN0VGV4dHVyZSwgMCApO1xyXG5cdFx0XHRcdGdsVGFyZ2V0ID0gX2dsLlRFWFRVUkVfM0Q7XHJcblxyXG5cdFx0XHR9IGVsc2UgaWYgKCBkc3RUZXh0dXJlLmlzRGF0YUFycmF5VGV4dHVyZSB8fCBkc3RUZXh0dXJlLmlzQ29tcHJlc3NlZEFycmF5VGV4dHVyZSApIHtcclxuXHJcblx0XHRcdFx0dGV4dHVyZXMuc2V0VGV4dHVyZTJEQXJyYXkoIGRzdFRleHR1cmUsIDAgKTtcclxuXHRcdFx0XHRnbFRhcmdldCA9IF9nbC5URVhUVVJFXzJEX0FSUkFZO1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuV2ViR0xSZW5kZXJlci5jb3B5VGV4dHVyZVRvVGV4dHVyZTNEOiBvbmx5IHN1cHBvcnRzIFRIUkVFLkRhdGFUZXh0dXJlM0QgYW5kIFRIUkVFLkRhdGFUZXh0dXJlMkRBcnJheS4nICk7XHJcblx0XHRcdFx0cmV0dXJuO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0X2dsLnBpeGVsU3RvcmVpKCBfZ2wuVU5QQUNLX0ZMSVBfWV9XRUJHTCwgZHN0VGV4dHVyZS5mbGlwWSApO1xyXG5cdFx0XHRfZ2wucGl4ZWxTdG9yZWkoIF9nbC5VTlBBQ0tfUFJFTVVMVElQTFlfQUxQSEFfV0VCR0wsIGRzdFRleHR1cmUucHJlbXVsdGlwbHlBbHBoYSApO1xyXG5cdFx0XHRfZ2wucGl4ZWxTdG9yZWkoIF9nbC5VTlBBQ0tfQUxJR05NRU5ULCBkc3RUZXh0dXJlLnVucGFja0FsaWdubWVudCApO1xyXG5cclxuXHRcdFx0Y29uc3QgdW5wYWNrUm93TGVuID0gX2dsLmdldFBhcmFtZXRlciggX2dsLlVOUEFDS19ST1dfTEVOR1RIICk7XHJcblx0XHRcdGNvbnN0IHVucGFja0ltYWdlSGVpZ2h0ID0gX2dsLmdldFBhcmFtZXRlciggX2dsLlVOUEFDS19JTUFHRV9IRUlHSFQgKTtcclxuXHRcdFx0Y29uc3QgdW5wYWNrU2tpcFBpeGVscyA9IF9nbC5nZXRQYXJhbWV0ZXIoIF9nbC5VTlBBQ0tfU0tJUF9QSVhFTFMgKTtcclxuXHRcdFx0Y29uc3QgdW5wYWNrU2tpcFJvd3MgPSBfZ2wuZ2V0UGFyYW1ldGVyKCBfZ2wuVU5QQUNLX1NLSVBfUk9XUyApO1xyXG5cdFx0XHRjb25zdCB1bnBhY2tTa2lwSW1hZ2VzID0gX2dsLmdldFBhcmFtZXRlciggX2dsLlVOUEFDS19TS0lQX0lNQUdFUyApO1xyXG5cclxuXHRcdFx0Y29uc3QgaW1hZ2UgPSBzcmNUZXh0dXJlLmlzQ29tcHJlc3NlZFRleHR1cmUgPyBzcmNUZXh0dXJlLm1pcG1hcHNbIGxldmVsIF0gOiBzcmNUZXh0dXJlLmltYWdlO1xyXG5cclxuXHRcdFx0X2dsLnBpeGVsU3RvcmVpKCBfZ2wuVU5QQUNLX1JPV19MRU5HVEgsIGltYWdlLndpZHRoICk7XHJcblx0XHRcdF9nbC5waXhlbFN0b3JlaSggX2dsLlVOUEFDS19JTUFHRV9IRUlHSFQsIGltYWdlLmhlaWdodCApO1xyXG5cdFx0XHRfZ2wucGl4ZWxTdG9yZWkoIF9nbC5VTlBBQ0tfU0tJUF9QSVhFTFMsIHNvdXJjZUJveC5taW4ueCApO1xyXG5cdFx0XHRfZ2wucGl4ZWxTdG9yZWkoIF9nbC5VTlBBQ0tfU0tJUF9ST1dTLCBzb3VyY2VCb3gubWluLnkgKTtcclxuXHRcdFx0X2dsLnBpeGVsU3RvcmVpKCBfZ2wuVU5QQUNLX1NLSVBfSU1BR0VTLCBzb3VyY2VCb3gubWluLnogKTtcclxuXHJcblx0XHRcdGlmICggc3JjVGV4dHVyZS5pc0RhdGFUZXh0dXJlIHx8IHNyY1RleHR1cmUuaXNEYXRhM0RUZXh0dXJlICkge1xyXG5cclxuXHRcdFx0XHRfZ2wudGV4U3ViSW1hZ2UzRCggZ2xUYXJnZXQsIGxldmVsLCBwb3NpdGlvbi54LCBwb3NpdGlvbi55LCBwb3NpdGlvbi56LCB3aWR0aCwgaGVpZ2h0LCBkZXB0aCwgZ2xGb3JtYXQsIGdsVHlwZSwgaW1hZ2UuZGF0YSApO1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0aWYgKCBzcmNUZXh0dXJlLmlzQ29tcHJlc3NlZEFycmF5VGV4dHVyZSApIHtcclxuXHJcblx0XHRcdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5XZWJHTFJlbmRlcmVyLmNvcHlUZXh0dXJlVG9UZXh0dXJlM0Q6IHVudGVzdGVkIHN1cHBvcnQgZm9yIGNvbXByZXNzZWQgc3JjVGV4dHVyZS4nICk7XHJcblx0XHRcdFx0XHRfZ2wuY29tcHJlc3NlZFRleFN1YkltYWdlM0QoIGdsVGFyZ2V0LCBsZXZlbCwgcG9zaXRpb24ueCwgcG9zaXRpb24ueSwgcG9zaXRpb24ueiwgd2lkdGgsIGhlaWdodCwgZGVwdGgsIGdsRm9ybWF0LCBpbWFnZS5kYXRhICk7XHJcblxyXG5cdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0X2dsLnRleFN1YkltYWdlM0QoIGdsVGFyZ2V0LCBsZXZlbCwgcG9zaXRpb24ueCwgcG9zaXRpb24ueSwgcG9zaXRpb24ueiwgd2lkdGgsIGhlaWdodCwgZGVwdGgsIGdsRm9ybWF0LCBnbFR5cGUsIGltYWdlICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdF9nbC5waXhlbFN0b3JlaSggX2dsLlVOUEFDS19ST1dfTEVOR1RILCB1bnBhY2tSb3dMZW4gKTtcclxuXHRcdFx0X2dsLnBpeGVsU3RvcmVpKCBfZ2wuVU5QQUNLX0lNQUdFX0hFSUdIVCwgdW5wYWNrSW1hZ2VIZWlnaHQgKTtcclxuXHRcdFx0X2dsLnBpeGVsU3RvcmVpKCBfZ2wuVU5QQUNLX1NLSVBfUElYRUxTLCB1bnBhY2tTa2lwUGl4ZWxzICk7XHJcblx0XHRcdF9nbC5waXhlbFN0b3JlaSggX2dsLlVOUEFDS19TS0lQX1JPV1MsIHVucGFja1NraXBSb3dzICk7XHJcblx0XHRcdF9nbC5waXhlbFN0b3JlaSggX2dsLlVOUEFDS19TS0lQX0lNQUdFUywgdW5wYWNrU2tpcEltYWdlcyApO1xyXG5cclxuXHRcdFx0Ly8gR2VuZXJhdGUgbWlwbWFwcyBvbmx5IHdoZW4gY29weWluZyBsZXZlbCAwXHJcblx0XHRcdGlmICggbGV2ZWwgPT09IDAgJiYgZHN0VGV4dHVyZS5nZW5lcmF0ZU1pcG1hcHMgKSBfZ2wuZ2VuZXJhdGVNaXBtYXAoIGdsVGFyZ2V0ICk7XHJcblxyXG5cdFx0XHRzdGF0ZS51bmJpbmRUZXh0dXJlKCk7XHJcblxyXG5cdFx0fTtcclxuXHJcblx0XHR0aGlzLmluaXRUZXh0dXJlID0gZnVuY3Rpb24gKCB0ZXh0dXJlICkge1xyXG5cclxuXHRcdFx0aWYgKCB0ZXh0dXJlLmlzQ3ViZVRleHR1cmUgKSB7XHJcblxyXG5cdFx0XHRcdHRleHR1cmVzLnNldFRleHR1cmVDdWJlKCB0ZXh0dXJlLCAwICk7XHJcblxyXG5cdFx0XHR9IGVsc2UgaWYgKCB0ZXh0dXJlLmlzRGF0YTNEVGV4dHVyZSApIHtcclxuXHJcblx0XHRcdFx0dGV4dHVyZXMuc2V0VGV4dHVyZTNEKCB0ZXh0dXJlLCAwICk7XHJcblxyXG5cdFx0XHR9IGVsc2UgaWYgKCB0ZXh0dXJlLmlzRGF0YUFycmF5VGV4dHVyZSB8fCB0ZXh0dXJlLmlzQ29tcHJlc3NlZEFycmF5VGV4dHVyZSApIHtcclxuXHJcblx0XHRcdFx0dGV4dHVyZXMuc2V0VGV4dHVyZTJEQXJyYXkoIHRleHR1cmUsIDAgKTtcclxuXHJcblx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdHRleHR1cmVzLnNldFRleHR1cmUyRCggdGV4dHVyZSwgMCApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0c3RhdGUudW5iaW5kVGV4dHVyZSgpO1xyXG5cclxuXHRcdH07XHJcblxyXG5cdFx0dGhpcy5yZXNldFN0YXRlID0gZnVuY3Rpb24gKCkge1xyXG5cclxuXHRcdFx0X2N1cnJlbnRBY3RpdmVDdWJlRmFjZSA9IDA7XHJcblx0XHRcdF9jdXJyZW50QWN0aXZlTWlwbWFwTGV2ZWwgPSAwO1xyXG5cdFx0XHRfY3VycmVudFJlbmRlclRhcmdldCA9IG51bGw7XHJcblxyXG5cdFx0XHRzdGF0ZS5yZXNldCgpO1xyXG5cdFx0XHRiaW5kaW5nU3RhdGVzLnJlc2V0KCk7XHJcblxyXG5cdFx0fTtcclxuXHJcblx0XHRpZiAoIHR5cGVvZiBfX1RIUkVFX0RFVlRPT0xTX18gIT09ICd1bmRlZmluZWQnICkge1xyXG5cclxuXHRcdFx0X19USFJFRV9ERVZUT09MU19fLmRpc3BhdGNoRXZlbnQoIG5ldyBDdXN0b21FdmVudCggJ29ic2VydmUnLCB7IGRldGFpbDogdGhpcyB9ICkgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0IGNvb3JkaW5hdGVTeXN0ZW0oKSB7XHJcblxyXG5cdFx0cmV0dXJuIFdlYkdMQ29vcmRpbmF0ZVN5c3RlbTtcclxuXHJcblx0fVxyXG5cclxuXHRnZXQgb3V0cHV0Q29sb3JTcGFjZSgpIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5fb3V0cHV0Q29sb3JTcGFjZTtcclxuXHJcblx0fVxyXG5cclxuXHRzZXQgb3V0cHV0Q29sb3JTcGFjZSggY29sb3JTcGFjZSApIHtcclxuXHJcblx0XHR0aGlzLl9vdXRwdXRDb2xvclNwYWNlID0gY29sb3JTcGFjZTtcclxuXHJcblx0XHRjb25zdCBnbCA9IHRoaXMuZ2V0Q29udGV4dCgpO1xyXG5cdFx0Z2wuZHJhd2luZ0J1ZmZlckNvbG9yU3BhY2UgPSBjb2xvclNwYWNlID09PSBEaXNwbGF5UDNDb2xvclNwYWNlID8gJ2Rpc3BsYXktcDMnIDogJ3NyZ2InO1xyXG5cdFx0Z2wudW5wYWNrQ29sb3JTcGFjZSA9IENvbG9yTWFuYWdlbWVudC53b3JraW5nQ29sb3JTcGFjZSA9PT0gTGluZWFyRGlzcGxheVAzQ29sb3JTcGFjZSA/ICdkaXNwbGF5LXAzJyA6ICdzcmdiJztcclxuXHJcblx0fVxyXG5cclxuXHRnZXQgdXNlTGVnYWN5TGlnaHRzKCkgeyAvLyBAZGVwcmVjYXRlZCwgcjE1NVxyXG5cclxuXHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLldlYkdMUmVuZGVyZXI6IFRoZSBwcm9wZXJ0eSAudXNlTGVnYWN5TGlnaHRzIGhhcyBiZWVuIGRlcHJlY2F0ZWQuIE1pZ3JhdGUgeW91ciBsaWdodGluZyBhY2NvcmRpbmcgdG8gdGhlIGZvbGxvd2luZyBndWlkZTogaHR0cHM6Ly9kaXNjb3Vyc2UudGhyZWVqcy5vcmcvdC91cGRhdGVzLXRvLWxpZ2h0aW5nLWluLXRocmVlLWpzLXIxNTUvNTM3MzMuJyApO1xyXG5cdFx0cmV0dXJuIHRoaXMuX3VzZUxlZ2FjeUxpZ2h0cztcclxuXHJcblx0fVxyXG5cclxuXHRzZXQgdXNlTGVnYWN5TGlnaHRzKCB2YWx1ZSApIHsgLy8gQGRlcHJlY2F0ZWQsIHIxNTVcclxuXHJcblx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5XZWJHTFJlbmRlcmVyOiBUaGUgcHJvcGVydHkgLnVzZUxlZ2FjeUxpZ2h0cyBoYXMgYmVlbiBkZXByZWNhdGVkLiBNaWdyYXRlIHlvdXIgbGlnaHRpbmcgYWNjb3JkaW5nIHRvIHRoZSBmb2xsb3dpbmcgZ3VpZGU6IGh0dHBzOi8vZGlzY291cnNlLnRocmVlanMub3JnL3QvdXBkYXRlcy10by1saWdodGluZy1pbi10aHJlZS1qcy1yMTU1LzUzNzMzLicgKTtcclxuXHRcdHRoaXMuX3VzZUxlZ2FjeUxpZ2h0cyA9IHZhbHVlO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5cclxuZXhwb3J0IHsgV2ViR0xSZW5kZXJlciB9O1xyXG4iLCJpbXBvcnQgeyBXZWJHTFJlbmRlcmVyIH0gZnJvbSAnLi9XZWJHTFJlbmRlcmVyLmpzJztcclxuXHJcbmNsYXNzIFdlYkdMMVJlbmRlcmVyIGV4dGVuZHMgV2ViR0xSZW5kZXJlciB7fVxyXG5cclxuV2ViR0wxUmVuZGVyZXIucHJvdG90eXBlLmlzV2ViR0wxUmVuZGVyZXIgPSB0cnVlO1xyXG5cclxuZXhwb3J0IHsgV2ViR0wxUmVuZGVyZXIgfTtcclxuIiwiaW1wb3J0IHsgQ29sb3IgfSBmcm9tICcuLi9tYXRoL0NvbG9yLmpzJztcclxuXHJcbmNsYXNzIEZvZ0V4cDIge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggY29sb3IsIGRlbnNpdHkgPSAwLjAwMDI1ICkge1xyXG5cclxuXHRcdHRoaXMuaXNGb2dFeHAyID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLm5hbWUgPSAnJztcclxuXHJcblx0XHR0aGlzLmNvbG9yID0gbmV3IENvbG9yKCBjb2xvciApO1xyXG5cdFx0dGhpcy5kZW5zaXR5ID0gZGVuc2l0eTtcclxuXHJcblx0fVxyXG5cclxuXHRjbG9uZSgpIHtcclxuXHJcblx0XHRyZXR1cm4gbmV3IEZvZ0V4cDIoIHRoaXMuY29sb3IsIHRoaXMuZGVuc2l0eSApO1xyXG5cclxuXHR9XHJcblxyXG5cdHRvSlNPTiggLyogbWV0YSAqLyApIHtcclxuXHJcblx0XHRyZXR1cm4ge1xyXG5cdFx0XHR0eXBlOiAnRm9nRXhwMicsXHJcblx0XHRcdG5hbWU6IHRoaXMubmFtZSxcclxuXHRcdFx0Y29sb3I6IHRoaXMuY29sb3IuZ2V0SGV4KCksXHJcblx0XHRcdGRlbnNpdHk6IHRoaXMuZGVuc2l0eVxyXG5cdFx0fTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgRm9nRXhwMiB9O1xyXG4iLCJpbXBvcnQgeyBDb2xvciB9IGZyb20gJy4uL21hdGgvQ29sb3IuanMnO1xyXG5cclxuY2xhc3MgRm9nIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIGNvbG9yLCBuZWFyID0gMSwgZmFyID0gMTAwMCApIHtcclxuXHJcblx0XHR0aGlzLmlzRm9nID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLm5hbWUgPSAnJztcclxuXHJcblx0XHR0aGlzLmNvbG9yID0gbmV3IENvbG9yKCBjb2xvciApO1xyXG5cclxuXHRcdHRoaXMubmVhciA9IG5lYXI7XHJcblx0XHR0aGlzLmZhciA9IGZhcjtcclxuXHJcblx0fVxyXG5cclxuXHRjbG9uZSgpIHtcclxuXHJcblx0XHRyZXR1cm4gbmV3IEZvZyggdGhpcy5jb2xvciwgdGhpcy5uZWFyLCB0aGlzLmZhciApO1xyXG5cclxuXHR9XHJcblxyXG5cdHRvSlNPTiggLyogbWV0YSAqLyApIHtcclxuXHJcblx0XHRyZXR1cm4ge1xyXG5cdFx0XHR0eXBlOiAnRm9nJyxcclxuXHRcdFx0bmFtZTogdGhpcy5uYW1lLFxyXG5cdFx0XHRjb2xvcjogdGhpcy5jb2xvci5nZXRIZXgoKSxcclxuXHRcdFx0bmVhcjogdGhpcy5uZWFyLFxyXG5cdFx0XHRmYXI6IHRoaXMuZmFyXHJcblx0XHR9O1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBGb2cgfTtcclxuIiwiaW1wb3J0IHsgT2JqZWN0M0QgfSBmcm9tICcuLi9jb3JlL09iamVjdDNELmpzJztcclxuXHJcbmNsYXNzIFNjZW5lIGV4dGVuZHMgT2JqZWN0M0Qge1xyXG5cclxuXHRjb25zdHJ1Y3RvcigpIHtcclxuXHJcblx0XHRzdXBlcigpO1xyXG5cclxuXHRcdHRoaXMuaXNTY2VuZSA9IHRydWU7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ1NjZW5lJztcclxuXHJcblx0XHR0aGlzLmJhY2tncm91bmQgPSBudWxsO1xyXG5cdFx0dGhpcy5lbnZpcm9ubWVudCA9IG51bGw7XHJcblx0XHR0aGlzLmZvZyA9IG51bGw7XHJcblxyXG5cdFx0dGhpcy5iYWNrZ3JvdW5kQmx1cnJpbmVzcyA9IDA7XHJcblx0XHR0aGlzLmJhY2tncm91bmRJbnRlbnNpdHkgPSAxO1xyXG5cclxuXHRcdHRoaXMub3ZlcnJpZGVNYXRlcmlhbCA9IG51bGw7XHJcblxyXG5cdFx0aWYgKCB0eXBlb2YgX19USFJFRV9ERVZUT09MU19fICE9PSAndW5kZWZpbmVkJyApIHtcclxuXHJcblx0XHRcdF9fVEhSRUVfREVWVE9PTFNfXy5kaXNwYXRjaEV2ZW50KCBuZXcgQ3VzdG9tRXZlbnQoICdvYnNlcnZlJywgeyBkZXRhaWw6IHRoaXMgfSApICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGNvcHkoIHNvdXJjZSwgcmVjdXJzaXZlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSwgcmVjdXJzaXZlICk7XHJcblxyXG5cdFx0aWYgKCBzb3VyY2UuYmFja2dyb3VuZCAhPT0gbnVsbCApIHRoaXMuYmFja2dyb3VuZCA9IHNvdXJjZS5iYWNrZ3JvdW5kLmNsb25lKCk7XHJcblx0XHRpZiAoIHNvdXJjZS5lbnZpcm9ubWVudCAhPT0gbnVsbCApIHRoaXMuZW52aXJvbm1lbnQgPSBzb3VyY2UuZW52aXJvbm1lbnQuY2xvbmUoKTtcclxuXHRcdGlmICggc291cmNlLmZvZyAhPT0gbnVsbCApIHRoaXMuZm9nID0gc291cmNlLmZvZy5jbG9uZSgpO1xyXG5cclxuXHRcdHRoaXMuYmFja2dyb3VuZEJsdXJyaW5lc3MgPSBzb3VyY2UuYmFja2dyb3VuZEJsdXJyaW5lc3M7XHJcblx0XHR0aGlzLmJhY2tncm91bmRJbnRlbnNpdHkgPSBzb3VyY2UuYmFja2dyb3VuZEludGVuc2l0eTtcclxuXHJcblx0XHRpZiAoIHNvdXJjZS5vdmVycmlkZU1hdGVyaWFsICE9PSBudWxsICkgdGhpcy5vdmVycmlkZU1hdGVyaWFsID0gc291cmNlLm92ZXJyaWRlTWF0ZXJpYWwuY2xvbmUoKTtcclxuXHJcblx0XHR0aGlzLm1hdHJpeEF1dG9VcGRhdGUgPSBzb3VyY2UubWF0cml4QXV0b1VwZGF0ZTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHR0b0pTT04oIG1ldGEgKSB7XHJcblxyXG5cdFx0Y29uc3QgZGF0YSA9IHN1cGVyLnRvSlNPTiggbWV0YSApO1xyXG5cclxuXHRcdGlmICggdGhpcy5mb2cgIT09IG51bGwgKSBkYXRhLm9iamVjdC5mb2cgPSB0aGlzLmZvZy50b0pTT04oKTtcclxuXHRcdGlmICggdGhpcy5iYWNrZ3JvdW5kQmx1cnJpbmVzcyA+IDAgKSBkYXRhLm9iamVjdC5iYWNrZ3JvdW5kQmx1cnJpbmVzcyA9IHRoaXMuYmFja2dyb3VuZEJsdXJyaW5lc3M7XHJcblx0XHRpZiAoIHRoaXMuYmFja2dyb3VuZEludGVuc2l0eSAhPT0gMSApIGRhdGEub2JqZWN0LmJhY2tncm91bmRJbnRlbnNpdHkgPSB0aGlzLmJhY2tncm91bmRJbnRlbnNpdHk7XHJcblxyXG5cdFx0cmV0dXJuIGRhdGE7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IFNjZW5lIH07XHJcbiIsImltcG9ydCAqIGFzIE1hdGhVdGlscyBmcm9tICcuLi9tYXRoL01hdGhVdGlscy5qcyc7XHJcbmltcG9ydCB7IFN0YXRpY0RyYXdVc2FnZSB9IGZyb20gJy4uL2NvbnN0YW50cy5qcyc7XHJcbmltcG9ydCB7IHdhcm5PbmNlIH0gZnJvbSAnLi4vdXRpbHMuanMnO1xyXG5cclxuY2xhc3MgSW50ZXJsZWF2ZWRCdWZmZXIge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggYXJyYXksIHN0cmlkZSApIHtcclxuXHJcblx0XHR0aGlzLmlzSW50ZXJsZWF2ZWRCdWZmZXIgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMuYXJyYXkgPSBhcnJheTtcclxuXHRcdHRoaXMuc3RyaWRlID0gc3RyaWRlO1xyXG5cdFx0dGhpcy5jb3VudCA9IGFycmF5ICE9PSB1bmRlZmluZWQgPyBhcnJheS5sZW5ndGggLyBzdHJpZGUgOiAwO1xyXG5cclxuXHRcdHRoaXMudXNhZ2UgPSBTdGF0aWNEcmF3VXNhZ2U7XHJcblx0XHR0aGlzLl91cGRhdGVSYW5nZSA9IHsgb2Zmc2V0OiAwLCBjb3VudDogLSAxIH07XHJcblx0XHR0aGlzLnVwZGF0ZVJhbmdlcyA9IFtdO1xyXG5cclxuXHRcdHRoaXMudmVyc2lvbiA9IDA7XHJcblxyXG5cdFx0dGhpcy51dWlkID0gTWF0aFV0aWxzLmdlbmVyYXRlVVVJRCgpO1xyXG5cclxuXHR9XHJcblxyXG5cdG9uVXBsb2FkQ2FsbGJhY2soKSB7fVxyXG5cclxuXHRzZXQgbmVlZHNVcGRhdGUoIHZhbHVlICkge1xyXG5cclxuXHRcdGlmICggdmFsdWUgPT09IHRydWUgKSB0aGlzLnZlcnNpb24gKys7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0IHVwZGF0ZVJhbmdlKCkge1xyXG5cclxuXHRcdHdhcm5PbmNlKCAnVEhSRUUuSW50ZXJsZWF2ZWRCdWZmZXI6IHVwZGF0ZVJhbmdlKCkgaXMgZGVwcmVjYXRlZCBhbmQgd2lsbCBiZSByZW1vdmVkIGluIHIxNjkuIFVzZSBhZGRVcGRhdGVSYW5nZSgpIGluc3RlYWQuJyApOyAvLyBAZGVwcmVjYXRlZCwgcjE1OVxyXG5cdFx0cmV0dXJuIHRoaXMuX3VwZGF0ZVJhbmdlO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldFVzYWdlKCB2YWx1ZSApIHtcclxuXHJcblx0XHR0aGlzLnVzYWdlID0gdmFsdWU7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0YWRkVXBkYXRlUmFuZ2UoIHN0YXJ0LCBjb3VudCApIHtcclxuXHJcblx0XHR0aGlzLnVwZGF0ZVJhbmdlcy5wdXNoKCB7IHN0YXJ0LCBjb3VudCB9ICk7XHJcblxyXG5cdH1cclxuXHJcblx0Y2xlYXJVcGRhdGVSYW5nZXMoKSB7XHJcblxyXG5cdFx0dGhpcy51cGRhdGVSYW5nZXMubGVuZ3RoID0gMDtcclxuXHJcblx0fVxyXG5cclxuXHRjb3B5KCBzb3VyY2UgKSB7XHJcblxyXG5cdFx0dGhpcy5hcnJheSA9IG5ldyBzb3VyY2UuYXJyYXkuY29uc3RydWN0b3IoIHNvdXJjZS5hcnJheSApO1xyXG5cdFx0dGhpcy5jb3VudCA9IHNvdXJjZS5jb3VudDtcclxuXHRcdHRoaXMuc3RyaWRlID0gc291cmNlLnN0cmlkZTtcclxuXHRcdHRoaXMudXNhZ2UgPSBzb3VyY2UudXNhZ2U7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weUF0KCBpbmRleDEsIGF0dHJpYnV0ZSwgaW5kZXgyICkge1xyXG5cclxuXHRcdGluZGV4MSAqPSB0aGlzLnN0cmlkZTtcclxuXHRcdGluZGV4MiAqPSBhdHRyaWJ1dGUuc3RyaWRlO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IHRoaXMuc3RyaWRlOyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdHRoaXMuYXJyYXlbIGluZGV4MSArIGkgXSA9IGF0dHJpYnV0ZS5hcnJheVsgaW5kZXgyICsgaSBdO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXQoIHZhbHVlLCBvZmZzZXQgPSAwICkge1xyXG5cclxuXHRcdHRoaXMuYXJyYXkuc2V0KCB2YWx1ZSwgb2Zmc2V0ICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Y2xvbmUoIGRhdGEgKSB7XHJcblxyXG5cdFx0aWYgKCBkYXRhLmFycmF5QnVmZmVycyA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0ZGF0YS5hcnJheUJ1ZmZlcnMgPSB7fTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCB0aGlzLmFycmF5LmJ1ZmZlci5fdXVpZCA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0dGhpcy5hcnJheS5idWZmZXIuX3V1aWQgPSBNYXRoVXRpbHMuZ2VuZXJhdGVVVUlEKCk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggZGF0YS5hcnJheUJ1ZmZlcnNbIHRoaXMuYXJyYXkuYnVmZmVyLl91dWlkIF0gPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdGRhdGEuYXJyYXlCdWZmZXJzWyB0aGlzLmFycmF5LmJ1ZmZlci5fdXVpZCBdID0gdGhpcy5hcnJheS5zbGljZSggMCApLmJ1ZmZlcjtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Y29uc3QgYXJyYXkgPSBuZXcgdGhpcy5hcnJheS5jb25zdHJ1Y3RvciggZGF0YS5hcnJheUJ1ZmZlcnNbIHRoaXMuYXJyYXkuYnVmZmVyLl91dWlkIF0gKTtcclxuXHJcblx0XHRjb25zdCBpYiA9IG5ldyB0aGlzLmNvbnN0cnVjdG9yKCBhcnJheSwgdGhpcy5zdHJpZGUgKTtcclxuXHRcdGliLnNldFVzYWdlKCB0aGlzLnVzYWdlICk7XHJcblxyXG5cdFx0cmV0dXJuIGliO1xyXG5cclxuXHR9XHJcblxyXG5cdG9uVXBsb2FkKCBjYWxsYmFjayApIHtcclxuXHJcblx0XHR0aGlzLm9uVXBsb2FkQ2FsbGJhY2sgPSBjYWxsYmFjaztcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHR0b0pTT04oIGRhdGEgKSB7XHJcblxyXG5cdFx0aWYgKCBkYXRhLmFycmF5QnVmZmVycyA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0ZGF0YS5hcnJheUJ1ZmZlcnMgPSB7fTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gZ2VuZXJhdGUgVVVJRCBmb3IgYXJyYXkgYnVmZmVyIGlmIG5lY2Vzc2FyeVxyXG5cclxuXHRcdGlmICggdGhpcy5hcnJheS5idWZmZXIuX3V1aWQgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdHRoaXMuYXJyYXkuYnVmZmVyLl91dWlkID0gTWF0aFV0aWxzLmdlbmVyYXRlVVVJRCgpO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIGRhdGEuYXJyYXlCdWZmZXJzWyB0aGlzLmFycmF5LmJ1ZmZlci5fdXVpZCBdID09PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRkYXRhLmFycmF5QnVmZmVyc1sgdGhpcy5hcnJheS5idWZmZXIuX3V1aWQgXSA9IEFycmF5LmZyb20oIG5ldyBVaW50MzJBcnJheSggdGhpcy5hcnJheS5idWZmZXIgKSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvL1xyXG5cclxuXHRcdHJldHVybiB7XHJcblx0XHRcdHV1aWQ6IHRoaXMudXVpZCxcclxuXHRcdFx0YnVmZmVyOiB0aGlzLmFycmF5LmJ1ZmZlci5fdXVpZCxcclxuXHRcdFx0dHlwZTogdGhpcy5hcnJheS5jb25zdHJ1Y3Rvci5uYW1lLFxyXG5cdFx0XHRzdHJpZGU6IHRoaXMuc3RyaWRlXHJcblx0XHR9O1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBJbnRlcmxlYXZlZEJ1ZmZlciB9O1xyXG4iLCJpbXBvcnQgeyBWZWN0b3IzIH0gZnJvbSAnLi4vbWF0aC9WZWN0b3IzLmpzJztcclxuaW1wb3J0IHsgQnVmZmVyQXR0cmlidXRlIH0gZnJvbSAnLi9CdWZmZXJBdHRyaWJ1dGUuanMnO1xyXG5pbXBvcnQgeyBkZW5vcm1hbGl6ZSwgbm9ybWFsaXplIH0gZnJvbSAnLi4vbWF0aC9NYXRoVXRpbHMuanMnO1xyXG5cclxuY29uc3QgX3ZlY3RvciA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuXHJcbmNsYXNzIEludGVybGVhdmVkQnVmZmVyQXR0cmlidXRlIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIGludGVybGVhdmVkQnVmZmVyLCBpdGVtU2l6ZSwgb2Zmc2V0LCBub3JtYWxpemVkID0gZmFsc2UgKSB7XHJcblxyXG5cdFx0dGhpcy5pc0ludGVybGVhdmVkQnVmZmVyQXR0cmlidXRlID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLm5hbWUgPSAnJztcclxuXHJcblx0XHR0aGlzLmRhdGEgPSBpbnRlcmxlYXZlZEJ1ZmZlcjtcclxuXHRcdHRoaXMuaXRlbVNpemUgPSBpdGVtU2l6ZTtcclxuXHRcdHRoaXMub2Zmc2V0ID0gb2Zmc2V0O1xyXG5cclxuXHRcdHRoaXMubm9ybWFsaXplZCA9IG5vcm1hbGl6ZWQ7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0IGNvdW50KCkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLmRhdGEuY291bnQ7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0IGFycmF5KCkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLmRhdGEuYXJyYXk7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0IG5lZWRzVXBkYXRlKCB2YWx1ZSApIHtcclxuXHJcblx0XHR0aGlzLmRhdGEubmVlZHNVcGRhdGUgPSB2YWx1ZTtcclxuXHJcblx0fVxyXG5cclxuXHRhcHBseU1hdHJpeDQoIG0gKSB7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gdGhpcy5kYXRhLmNvdW50OyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdF92ZWN0b3IuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggdGhpcywgaSApO1xyXG5cclxuXHRcdFx0X3ZlY3Rvci5hcHBseU1hdHJpeDQoIG0gKTtcclxuXHJcblx0XHRcdHRoaXMuc2V0WFlaKCBpLCBfdmVjdG9yLngsIF92ZWN0b3IueSwgX3ZlY3Rvci56ICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGFwcGx5Tm9ybWFsTWF0cml4KCBtICkge1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IHRoaXMuY291bnQ7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0X3ZlY3Rvci5mcm9tQnVmZmVyQXR0cmlidXRlKCB0aGlzLCBpICk7XHJcblxyXG5cdFx0XHRfdmVjdG9yLmFwcGx5Tm9ybWFsTWF0cml4KCBtICk7XHJcblxyXG5cdFx0XHR0aGlzLnNldFhZWiggaSwgX3ZlY3Rvci54LCBfdmVjdG9yLnksIF92ZWN0b3IueiApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHR0cmFuc2Zvcm1EaXJlY3Rpb24oIG0gKSB7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gdGhpcy5jb3VudDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRfdmVjdG9yLmZyb21CdWZmZXJBdHRyaWJ1dGUoIHRoaXMsIGkgKTtcclxuXHJcblx0XHRcdF92ZWN0b3IudHJhbnNmb3JtRGlyZWN0aW9uKCBtICk7XHJcblxyXG5cdFx0XHR0aGlzLnNldFhZWiggaSwgX3ZlY3Rvci54LCBfdmVjdG9yLnksIF92ZWN0b3IueiApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRnZXRDb21wb25lbnQoIGluZGV4LCBjb21wb25lbnQgKSB7XHJcblxyXG5cdFx0bGV0IHZhbHVlID0gdGhpcy5hcnJheVsgaW5kZXggKiB0aGlzLmRhdGEuc3RyaWRlICsgdGhpcy5vZmZzZXQgKyBjb21wb25lbnQgXTtcclxuXHJcblx0XHRpZiAoIHRoaXMubm9ybWFsaXplZCApIHZhbHVlID0gZGVub3JtYWxpemUoIHZhbHVlLCB0aGlzLmFycmF5ICk7XHJcblxyXG5cdFx0cmV0dXJuIHZhbHVlO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldENvbXBvbmVudCggaW5kZXgsIGNvbXBvbmVudCwgdmFsdWUgKSB7XHJcblxyXG5cdFx0aWYgKCB0aGlzLm5vcm1hbGl6ZWQgKSB2YWx1ZSA9IG5vcm1hbGl6ZSggdmFsdWUsIHRoaXMuYXJyYXkgKTtcclxuXHJcblx0XHR0aGlzLmRhdGEuYXJyYXlbIGluZGV4ICogdGhpcy5kYXRhLnN0cmlkZSArIHRoaXMub2Zmc2V0ICsgY29tcG9uZW50IF0gPSB2YWx1ZTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRYKCBpbmRleCwgeCApIHtcclxuXHJcblx0XHRpZiAoIHRoaXMubm9ybWFsaXplZCApIHggPSBub3JtYWxpemUoIHgsIHRoaXMuYXJyYXkgKTtcclxuXHJcblx0XHR0aGlzLmRhdGEuYXJyYXlbIGluZGV4ICogdGhpcy5kYXRhLnN0cmlkZSArIHRoaXMub2Zmc2V0IF0gPSB4O1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldFkoIGluZGV4LCB5ICkge1xyXG5cclxuXHRcdGlmICggdGhpcy5ub3JtYWxpemVkICkgeSA9IG5vcm1hbGl6ZSggeSwgdGhpcy5hcnJheSApO1xyXG5cclxuXHRcdHRoaXMuZGF0YS5hcnJheVsgaW5kZXggKiB0aGlzLmRhdGEuc3RyaWRlICsgdGhpcy5vZmZzZXQgKyAxIF0gPSB5O1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldFooIGluZGV4LCB6ICkge1xyXG5cclxuXHRcdGlmICggdGhpcy5ub3JtYWxpemVkICkgeiA9IG5vcm1hbGl6ZSggeiwgdGhpcy5hcnJheSApO1xyXG5cclxuXHRcdHRoaXMuZGF0YS5hcnJheVsgaW5kZXggKiB0aGlzLmRhdGEuc3RyaWRlICsgdGhpcy5vZmZzZXQgKyAyIF0gPSB6O1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldFcoIGluZGV4LCB3ICkge1xyXG5cclxuXHRcdGlmICggdGhpcy5ub3JtYWxpemVkICkgdyA9IG5vcm1hbGl6ZSggdywgdGhpcy5hcnJheSApO1xyXG5cclxuXHRcdHRoaXMuZGF0YS5hcnJheVsgaW5kZXggKiB0aGlzLmRhdGEuc3RyaWRlICsgdGhpcy5vZmZzZXQgKyAzIF0gPSB3O1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldFgoIGluZGV4ICkge1xyXG5cclxuXHRcdGxldCB4ID0gdGhpcy5kYXRhLmFycmF5WyBpbmRleCAqIHRoaXMuZGF0YS5zdHJpZGUgKyB0aGlzLm9mZnNldCBdO1xyXG5cclxuXHRcdGlmICggdGhpcy5ub3JtYWxpemVkICkgeCA9IGRlbm9ybWFsaXplKCB4LCB0aGlzLmFycmF5ICk7XHJcblxyXG5cdFx0cmV0dXJuIHg7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0WSggaW5kZXggKSB7XHJcblxyXG5cdFx0bGV0IHkgPSB0aGlzLmRhdGEuYXJyYXlbIGluZGV4ICogdGhpcy5kYXRhLnN0cmlkZSArIHRoaXMub2Zmc2V0ICsgMSBdO1xyXG5cclxuXHRcdGlmICggdGhpcy5ub3JtYWxpemVkICkgeSA9IGRlbm9ybWFsaXplKCB5LCB0aGlzLmFycmF5ICk7XHJcblxyXG5cdFx0cmV0dXJuIHk7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0WiggaW5kZXggKSB7XHJcblxyXG5cdFx0bGV0IHogPSB0aGlzLmRhdGEuYXJyYXlbIGluZGV4ICogdGhpcy5kYXRhLnN0cmlkZSArIHRoaXMub2Zmc2V0ICsgMiBdO1xyXG5cclxuXHRcdGlmICggdGhpcy5ub3JtYWxpemVkICkgeiA9IGRlbm9ybWFsaXplKCB6LCB0aGlzLmFycmF5ICk7XHJcblxyXG5cdFx0cmV0dXJuIHo7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0VyggaW5kZXggKSB7XHJcblxyXG5cdFx0bGV0IHcgPSB0aGlzLmRhdGEuYXJyYXlbIGluZGV4ICogdGhpcy5kYXRhLnN0cmlkZSArIHRoaXMub2Zmc2V0ICsgMyBdO1xyXG5cclxuXHRcdGlmICggdGhpcy5ub3JtYWxpemVkICkgdyA9IGRlbm9ybWFsaXplKCB3LCB0aGlzLmFycmF5ICk7XHJcblxyXG5cdFx0cmV0dXJuIHc7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0WFkoIGluZGV4LCB4LCB5ICkge1xyXG5cclxuXHRcdGluZGV4ID0gaW5kZXggKiB0aGlzLmRhdGEuc3RyaWRlICsgdGhpcy5vZmZzZXQ7XHJcblxyXG5cdFx0aWYgKCB0aGlzLm5vcm1hbGl6ZWQgKSB7XHJcblxyXG5cdFx0XHR4ID0gbm9ybWFsaXplKCB4LCB0aGlzLmFycmF5ICk7XHJcblx0XHRcdHkgPSBub3JtYWxpemUoIHksIHRoaXMuYXJyYXkgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5kYXRhLmFycmF5WyBpbmRleCArIDAgXSA9IHg7XHJcblx0XHR0aGlzLmRhdGEuYXJyYXlbIGluZGV4ICsgMSBdID0geTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRYWVooIGluZGV4LCB4LCB5LCB6ICkge1xyXG5cclxuXHRcdGluZGV4ID0gaW5kZXggKiB0aGlzLmRhdGEuc3RyaWRlICsgdGhpcy5vZmZzZXQ7XHJcblxyXG5cdFx0aWYgKCB0aGlzLm5vcm1hbGl6ZWQgKSB7XHJcblxyXG5cdFx0XHR4ID0gbm9ybWFsaXplKCB4LCB0aGlzLmFycmF5ICk7XHJcblx0XHRcdHkgPSBub3JtYWxpemUoIHksIHRoaXMuYXJyYXkgKTtcclxuXHRcdFx0eiA9IG5vcm1hbGl6ZSggeiwgdGhpcy5hcnJheSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLmRhdGEuYXJyYXlbIGluZGV4ICsgMCBdID0geDtcclxuXHRcdHRoaXMuZGF0YS5hcnJheVsgaW5kZXggKyAxIF0gPSB5O1xyXG5cdFx0dGhpcy5kYXRhLmFycmF5WyBpbmRleCArIDIgXSA9IHo7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0WFlaVyggaW5kZXgsIHgsIHksIHosIHcgKSB7XHJcblxyXG5cdFx0aW5kZXggPSBpbmRleCAqIHRoaXMuZGF0YS5zdHJpZGUgKyB0aGlzLm9mZnNldDtcclxuXHJcblx0XHRpZiAoIHRoaXMubm9ybWFsaXplZCApIHtcclxuXHJcblx0XHRcdHggPSBub3JtYWxpemUoIHgsIHRoaXMuYXJyYXkgKTtcclxuXHRcdFx0eSA9IG5vcm1hbGl6ZSggeSwgdGhpcy5hcnJheSApO1xyXG5cdFx0XHR6ID0gbm9ybWFsaXplKCB6LCB0aGlzLmFycmF5ICk7XHJcblx0XHRcdHcgPSBub3JtYWxpemUoIHcsIHRoaXMuYXJyYXkgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5kYXRhLmFycmF5WyBpbmRleCArIDAgXSA9IHg7XHJcblx0XHR0aGlzLmRhdGEuYXJyYXlbIGluZGV4ICsgMSBdID0geTtcclxuXHRcdHRoaXMuZGF0YS5hcnJheVsgaW5kZXggKyAyIF0gPSB6O1xyXG5cdFx0dGhpcy5kYXRhLmFycmF5WyBpbmRleCArIDMgXSA9IHc7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Y2xvbmUoIGRhdGEgKSB7XHJcblxyXG5cdFx0aWYgKCBkYXRhID09PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRjb25zb2xlLmxvZyggJ1RIUkVFLkludGVybGVhdmVkQnVmZmVyQXR0cmlidXRlLmNsb25lKCk6IENsb25pbmcgYW4gaW50ZXJsZWF2ZWQgYnVmZmVyIGF0dHJpYnV0ZSB3aWxsIGRlLWludGVybGVhdmUgYnVmZmVyIGRhdGEuJyApO1xyXG5cclxuXHRcdFx0Y29uc3QgYXJyYXkgPSBbXTtcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHRoaXMuY291bnQ7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IGluZGV4ID0gaSAqIHRoaXMuZGF0YS5zdHJpZGUgKyB0aGlzLm9mZnNldDtcclxuXHJcblx0XHRcdFx0Zm9yICggbGV0IGogPSAwOyBqIDwgdGhpcy5pdGVtU2l6ZTsgaiArKyApIHtcclxuXHJcblx0XHRcdFx0XHRhcnJheS5wdXNoKCB0aGlzLmRhdGEuYXJyYXlbIGluZGV4ICsgaiBdICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHJldHVybiBuZXcgQnVmZmVyQXR0cmlidXRlKCBuZXcgdGhpcy5hcnJheS5jb25zdHJ1Y3RvciggYXJyYXkgKSwgdGhpcy5pdGVtU2l6ZSwgdGhpcy5ub3JtYWxpemVkICk7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdGlmICggZGF0YS5pbnRlcmxlYXZlZEJ1ZmZlcnMgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0ZGF0YS5pbnRlcmxlYXZlZEJ1ZmZlcnMgPSB7fTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGlmICggZGF0YS5pbnRlcmxlYXZlZEJ1ZmZlcnNbIHRoaXMuZGF0YS51dWlkIF0gPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0ZGF0YS5pbnRlcmxlYXZlZEJ1ZmZlcnNbIHRoaXMuZGF0YS51dWlkIF0gPSB0aGlzLmRhdGEuY2xvbmUoIGRhdGEgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHJldHVybiBuZXcgSW50ZXJsZWF2ZWRCdWZmZXJBdHRyaWJ1dGUoIGRhdGEuaW50ZXJsZWF2ZWRCdWZmZXJzWyB0aGlzLmRhdGEudXVpZCBdLCB0aGlzLml0ZW1TaXplLCB0aGlzLm9mZnNldCwgdGhpcy5ub3JtYWxpemVkICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdHRvSlNPTiggZGF0YSApIHtcclxuXHJcblx0XHRpZiAoIGRhdGEgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdGNvbnNvbGUubG9nKCAnVEhSRUUuSW50ZXJsZWF2ZWRCdWZmZXJBdHRyaWJ1dGUudG9KU09OKCk6IFNlcmlhbGl6aW5nIGFuIGludGVybGVhdmVkIGJ1ZmZlciBhdHRyaWJ1dGUgd2lsbCBkZS1pbnRlcmxlYXZlIGJ1ZmZlciBkYXRhLicgKTtcclxuXHJcblx0XHRcdGNvbnN0IGFycmF5ID0gW107XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCB0aGlzLmNvdW50OyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBpbmRleCA9IGkgKiB0aGlzLmRhdGEuc3RyaWRlICsgdGhpcy5vZmZzZXQ7XHJcblxyXG5cdFx0XHRcdGZvciAoIGxldCBqID0gMDsgaiA8IHRoaXMuaXRlbVNpemU7IGogKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0YXJyYXkucHVzaCggdGhpcy5kYXRhLmFycmF5WyBpbmRleCArIGogXSApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyBkZS1pbnRlcmxlYXZlIGRhdGEgYW5kIHNhdmUgaXQgYXMgYW4gb3JkaW5hcnkgYnVmZmVyIGF0dHJpYnV0ZSBmb3Igbm93XHJcblxyXG5cdFx0XHRyZXR1cm4ge1xyXG5cdFx0XHRcdGl0ZW1TaXplOiB0aGlzLml0ZW1TaXplLFxyXG5cdFx0XHRcdHR5cGU6IHRoaXMuYXJyYXkuY29uc3RydWN0b3IubmFtZSxcclxuXHRcdFx0XHRhcnJheTogYXJyYXksXHJcblx0XHRcdFx0bm9ybWFsaXplZDogdGhpcy5ub3JtYWxpemVkXHJcblx0XHRcdH07XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdC8vIHNhdmUgYXMgdHJ1ZSBpbnRlcmxlYXZlZCBhdHRyaWJ1dGVcclxuXHJcblx0XHRcdGlmICggZGF0YS5pbnRlcmxlYXZlZEJ1ZmZlcnMgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0ZGF0YS5pbnRlcmxlYXZlZEJ1ZmZlcnMgPSB7fTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGlmICggZGF0YS5pbnRlcmxlYXZlZEJ1ZmZlcnNbIHRoaXMuZGF0YS51dWlkIF0gPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0ZGF0YS5pbnRlcmxlYXZlZEJ1ZmZlcnNbIHRoaXMuZGF0YS51dWlkIF0gPSB0aGlzLmRhdGEudG9KU09OKCBkYXRhICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRyZXR1cm4ge1xyXG5cdFx0XHRcdGlzSW50ZXJsZWF2ZWRCdWZmZXJBdHRyaWJ1dGU6IHRydWUsXHJcblx0XHRcdFx0aXRlbVNpemU6IHRoaXMuaXRlbVNpemUsXHJcblx0XHRcdFx0ZGF0YTogdGhpcy5kYXRhLnV1aWQsXHJcblx0XHRcdFx0b2Zmc2V0OiB0aGlzLm9mZnNldCxcclxuXHRcdFx0XHRub3JtYWxpemVkOiB0aGlzLm5vcm1hbGl6ZWRcclxuXHRcdFx0fTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcblxyXG5leHBvcnQgeyBJbnRlcmxlYXZlZEJ1ZmZlckF0dHJpYnV0ZSB9O1xyXG4iLCJpbXBvcnQgeyBNYXRlcmlhbCB9IGZyb20gJy4vTWF0ZXJpYWwuanMnO1xyXG5pbXBvcnQgeyBDb2xvciB9IGZyb20gJy4uL21hdGgvQ29sb3IuanMnO1xyXG5cclxuY2xhc3MgU3ByaXRlTWF0ZXJpYWwgZXh0ZW5kcyBNYXRlcmlhbCB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBwYXJhbWV0ZXJzICkge1xyXG5cclxuXHRcdHN1cGVyKCk7XHJcblxyXG5cdFx0dGhpcy5pc1Nwcml0ZU1hdGVyaWFsID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSAnU3ByaXRlTWF0ZXJpYWwnO1xyXG5cclxuXHRcdHRoaXMuY29sb3IgPSBuZXcgQ29sb3IoIDB4ZmZmZmZmICk7XHJcblxyXG5cdFx0dGhpcy5tYXAgPSBudWxsO1xyXG5cclxuXHRcdHRoaXMuYWxwaGFNYXAgPSBudWxsO1xyXG5cclxuXHRcdHRoaXMucm90YXRpb24gPSAwO1xyXG5cclxuXHRcdHRoaXMuc2l6ZUF0dGVudWF0aW9uID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLnRyYW5zcGFyZW50ID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLmZvZyA9IHRydWU7XHJcblxyXG5cdFx0dGhpcy5zZXRWYWx1ZXMoIHBhcmFtZXRlcnMgKTtcclxuXHJcblx0fVxyXG5cclxuXHRjb3B5KCBzb3VyY2UgKSB7XHJcblxyXG5cdFx0c3VwZXIuY29weSggc291cmNlICk7XHJcblxyXG5cdFx0dGhpcy5jb2xvci5jb3B5KCBzb3VyY2UuY29sb3IgKTtcclxuXHJcblx0XHR0aGlzLm1hcCA9IHNvdXJjZS5tYXA7XHJcblxyXG5cdFx0dGhpcy5hbHBoYU1hcCA9IHNvdXJjZS5hbHBoYU1hcDtcclxuXHJcblx0XHR0aGlzLnJvdGF0aW9uID0gc291cmNlLnJvdGF0aW9uO1xyXG5cclxuXHRcdHRoaXMuc2l6ZUF0dGVudWF0aW9uID0gc291cmNlLnNpemVBdHRlbnVhdGlvbjtcclxuXHJcblx0XHR0aGlzLmZvZyA9IHNvdXJjZS5mb2c7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IFNwcml0ZU1hdGVyaWFsIH07XHJcbiIsImltcG9ydCB7IFZlY3RvcjIgfSBmcm9tICcuLi9tYXRoL1ZlY3RvcjIuanMnO1xyXG5pbXBvcnQgeyBWZWN0b3IzIH0gZnJvbSAnLi4vbWF0aC9WZWN0b3IzLmpzJztcclxuaW1wb3J0IHsgTWF0cml4NCB9IGZyb20gJy4uL21hdGgvTWF0cml4NC5qcyc7XHJcbmltcG9ydCB7IFRyaWFuZ2xlIH0gZnJvbSAnLi4vbWF0aC9UcmlhbmdsZS5qcyc7XHJcbmltcG9ydCB7IE9iamVjdDNEIH0gZnJvbSAnLi4vY29yZS9PYmplY3QzRC5qcyc7XHJcbmltcG9ydCB7IEJ1ZmZlckdlb21ldHJ5IH0gZnJvbSAnLi4vY29yZS9CdWZmZXJHZW9tZXRyeS5qcyc7XHJcbmltcG9ydCB7IEludGVybGVhdmVkQnVmZmVyIH0gZnJvbSAnLi4vY29yZS9JbnRlcmxlYXZlZEJ1ZmZlci5qcyc7XHJcbmltcG9ydCB7IEludGVybGVhdmVkQnVmZmVyQXR0cmlidXRlIH0gZnJvbSAnLi4vY29yZS9JbnRlcmxlYXZlZEJ1ZmZlckF0dHJpYnV0ZS5qcyc7XHJcbmltcG9ydCB7IFNwcml0ZU1hdGVyaWFsIH0gZnJvbSAnLi4vbWF0ZXJpYWxzL1Nwcml0ZU1hdGVyaWFsLmpzJztcclxuXHJcbmxldCBfZ2VvbWV0cnk7XHJcblxyXG5jb25zdCBfaW50ZXJzZWN0UG9pbnQgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XHJcbmNvbnN0IF93b3JsZFNjYWxlID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5jb25zdCBfbXZQb3NpdGlvbiA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuXHJcbmNvbnN0IF9hbGlnbmVkUG9zaXRpb24gPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IyKCk7XHJcbmNvbnN0IF9yb3RhdGVkUG9zaXRpb24gPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IyKCk7XHJcbmNvbnN0IF92aWV3V29ybGRNYXRyaXggPSAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXg0KCk7XHJcblxyXG5jb25zdCBfdkEgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XHJcbmNvbnN0IF92QiA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuY29uc3QgX3ZDID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5cclxuY29uc3QgX3V2QSA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjIoKTtcclxuY29uc3QgX3V2QiA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjIoKTtcclxuY29uc3QgX3V2QyA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjIoKTtcclxuXHJcbmNsYXNzIFNwcml0ZSBleHRlbmRzIE9iamVjdDNEIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIG1hdGVyaWFsID0gbmV3IFNwcml0ZU1hdGVyaWFsKCkgKSB7XHJcblxyXG5cdFx0c3VwZXIoKTtcclxuXHJcblx0XHR0aGlzLmlzU3ByaXRlID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSAnU3ByaXRlJztcclxuXHJcblx0XHRpZiAoIF9nZW9tZXRyeSA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0X2dlb21ldHJ5ID0gbmV3IEJ1ZmZlckdlb21ldHJ5KCk7XHJcblxyXG5cdFx0XHRjb25zdCBmbG9hdDMyQXJyYXkgPSBuZXcgRmxvYXQzMkFycmF5KCBbXHJcblx0XHRcdFx0LSAwLjUsIC0gMC41LCAwLCAwLCAwLFxyXG5cdFx0XHRcdDAuNSwgLSAwLjUsIDAsIDEsIDAsXHJcblx0XHRcdFx0MC41LCAwLjUsIDAsIDEsIDEsXHJcblx0XHRcdFx0LSAwLjUsIDAuNSwgMCwgMCwgMVxyXG5cdFx0XHRdICk7XHJcblxyXG5cdFx0XHRjb25zdCBpbnRlcmxlYXZlZEJ1ZmZlciA9IG5ldyBJbnRlcmxlYXZlZEJ1ZmZlciggZmxvYXQzMkFycmF5LCA1ICk7XHJcblxyXG5cdFx0XHRfZ2VvbWV0cnkuc2V0SW5kZXgoIFsgMCwgMSwgMixcdDAsIDIsIDMgXSApO1xyXG5cdFx0XHRfZ2VvbWV0cnkuc2V0QXR0cmlidXRlKCAncG9zaXRpb24nLCBuZXcgSW50ZXJsZWF2ZWRCdWZmZXJBdHRyaWJ1dGUoIGludGVybGVhdmVkQnVmZmVyLCAzLCAwLCBmYWxzZSApICk7XHJcblx0XHRcdF9nZW9tZXRyeS5zZXRBdHRyaWJ1dGUoICd1dicsIG5ldyBJbnRlcmxlYXZlZEJ1ZmZlckF0dHJpYnV0ZSggaW50ZXJsZWF2ZWRCdWZmZXIsIDIsIDMsIGZhbHNlICkgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5nZW9tZXRyeSA9IF9nZW9tZXRyeTtcclxuXHRcdHRoaXMubWF0ZXJpYWwgPSBtYXRlcmlhbDtcclxuXHJcblx0XHR0aGlzLmNlbnRlciA9IG5ldyBWZWN0b3IyKCAwLjUsIDAuNSApO1xyXG5cclxuXHR9XHJcblxyXG5cdHJheWNhc3QoIHJheWNhc3RlciwgaW50ZXJzZWN0cyApIHtcclxuXHJcblx0XHRpZiAoIHJheWNhc3Rlci5jYW1lcmEgPT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuU3ByaXRlOiBcIlJheWNhc3Rlci5jYW1lcmFcIiBuZWVkcyB0byBiZSBzZXQgaW4gb3JkZXIgdG8gcmF5Y2FzdCBhZ2FpbnN0IHNwcml0ZXMuJyApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRfd29ybGRTY2FsZS5zZXRGcm9tTWF0cml4U2NhbGUoIHRoaXMubWF0cml4V29ybGQgKTtcclxuXHJcblx0XHRfdmlld1dvcmxkTWF0cml4LmNvcHkoIHJheWNhc3Rlci5jYW1lcmEubWF0cml4V29ybGQgKTtcclxuXHRcdHRoaXMubW9kZWxWaWV3TWF0cml4Lm11bHRpcGx5TWF0cmljZXMoIHJheWNhc3Rlci5jYW1lcmEubWF0cml4V29ybGRJbnZlcnNlLCB0aGlzLm1hdHJpeFdvcmxkICk7XHJcblxyXG5cdFx0X212UG9zaXRpb24uc2V0RnJvbU1hdHJpeFBvc2l0aW9uKCB0aGlzLm1vZGVsVmlld01hdHJpeCApO1xyXG5cclxuXHRcdGlmICggcmF5Y2FzdGVyLmNhbWVyYS5pc1BlcnNwZWN0aXZlQ2FtZXJhICYmIHRoaXMubWF0ZXJpYWwuc2l6ZUF0dGVudWF0aW9uID09PSBmYWxzZSApIHtcclxuXHJcblx0XHRcdF93b3JsZFNjYWxlLm11bHRpcGx5U2NhbGFyKCAtIF9tdlBvc2l0aW9uLnogKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Y29uc3Qgcm90YXRpb24gPSB0aGlzLm1hdGVyaWFsLnJvdGF0aW9uO1xyXG5cdFx0bGV0IHNpbiwgY29zO1xyXG5cclxuXHRcdGlmICggcm90YXRpb24gIT09IDAgKSB7XHJcblxyXG5cdFx0XHRjb3MgPSBNYXRoLmNvcyggcm90YXRpb24gKTtcclxuXHRcdFx0c2luID0gTWF0aC5zaW4oIHJvdGF0aW9uICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGNvbnN0IGNlbnRlciA9IHRoaXMuY2VudGVyO1xyXG5cclxuXHRcdHRyYW5zZm9ybVZlcnRleCggX3ZBLnNldCggLSAwLjUsIC0gMC41LCAwICksIF9tdlBvc2l0aW9uLCBjZW50ZXIsIF93b3JsZFNjYWxlLCBzaW4sIGNvcyApO1xyXG5cdFx0dHJhbnNmb3JtVmVydGV4KCBfdkIuc2V0KCAwLjUsIC0gMC41LCAwICksIF9tdlBvc2l0aW9uLCBjZW50ZXIsIF93b3JsZFNjYWxlLCBzaW4sIGNvcyApO1xyXG5cdFx0dHJhbnNmb3JtVmVydGV4KCBfdkMuc2V0KCAwLjUsIDAuNSwgMCApLCBfbXZQb3NpdGlvbiwgY2VudGVyLCBfd29ybGRTY2FsZSwgc2luLCBjb3MgKTtcclxuXHJcblx0XHRfdXZBLnNldCggMCwgMCApO1xyXG5cdFx0X3V2Qi5zZXQoIDEsIDAgKTtcclxuXHRcdF91dkMuc2V0KCAxLCAxICk7XHJcblxyXG5cdFx0Ly8gY2hlY2sgZmlyc3QgdHJpYW5nbGVcclxuXHRcdGxldCBpbnRlcnNlY3QgPSByYXljYXN0ZXIucmF5LmludGVyc2VjdFRyaWFuZ2xlKCBfdkEsIF92QiwgX3ZDLCBmYWxzZSwgX2ludGVyc2VjdFBvaW50ICk7XHJcblxyXG5cdFx0aWYgKCBpbnRlcnNlY3QgPT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHQvLyBjaGVjayBzZWNvbmQgdHJpYW5nbGVcclxuXHRcdFx0dHJhbnNmb3JtVmVydGV4KCBfdkIuc2V0KCAtIDAuNSwgMC41LCAwICksIF9tdlBvc2l0aW9uLCBjZW50ZXIsIF93b3JsZFNjYWxlLCBzaW4sIGNvcyApO1xyXG5cdFx0XHRfdXZCLnNldCggMCwgMSApO1xyXG5cclxuXHRcdFx0aW50ZXJzZWN0ID0gcmF5Y2FzdGVyLnJheS5pbnRlcnNlY3RUcmlhbmdsZSggX3ZBLCBfdkMsIF92QiwgZmFsc2UsIF9pbnRlcnNlY3RQb2ludCApO1xyXG5cdFx0XHRpZiAoIGludGVyc2VjdCA9PT0gbnVsbCApIHtcclxuXHJcblx0XHRcdFx0cmV0dXJuO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCBkaXN0YW5jZSA9IHJheWNhc3Rlci5yYXkub3JpZ2luLmRpc3RhbmNlVG8oIF9pbnRlcnNlY3RQb2ludCApO1xyXG5cclxuXHRcdGlmICggZGlzdGFuY2UgPCByYXljYXN0ZXIubmVhciB8fCBkaXN0YW5jZSA+IHJheWNhc3Rlci5mYXIgKSByZXR1cm47XHJcblxyXG5cdFx0aW50ZXJzZWN0cy5wdXNoKCB7XHJcblxyXG5cdFx0XHRkaXN0YW5jZTogZGlzdGFuY2UsXHJcblx0XHRcdHBvaW50OiBfaW50ZXJzZWN0UG9pbnQuY2xvbmUoKSxcclxuXHRcdFx0dXY6IFRyaWFuZ2xlLmdldEludGVycG9sYXRpb24oIF9pbnRlcnNlY3RQb2ludCwgX3ZBLCBfdkIsIF92QywgX3V2QSwgX3V2QiwgX3V2QywgbmV3IFZlY3RvcjIoKSApLFxyXG5cdFx0XHRmYWNlOiBudWxsLFxyXG5cdFx0XHRvYmplY3Q6IHRoaXNcclxuXHJcblx0XHR9ICk7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlLCByZWN1cnNpdmUgKSB7XHJcblxyXG5cdFx0c3VwZXIuY29weSggc291cmNlLCByZWN1cnNpdmUgKTtcclxuXHJcblx0XHRpZiAoIHNvdXJjZS5jZW50ZXIgIT09IHVuZGVmaW5lZCApIHRoaXMuY2VudGVyLmNvcHkoIHNvdXJjZS5jZW50ZXIgKTtcclxuXHJcblx0XHR0aGlzLm1hdGVyaWFsID0gc291cmNlLm1hdGVyaWFsO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiB0cmFuc2Zvcm1WZXJ0ZXgoIHZlcnRleFBvc2l0aW9uLCBtdlBvc2l0aW9uLCBjZW50ZXIsIHNjYWxlLCBzaW4sIGNvcyApIHtcclxuXHJcblx0Ly8gY29tcHV0ZSBwb3NpdGlvbiBpbiBjYW1lcmEgc3BhY2VcclxuXHRfYWxpZ25lZFBvc2l0aW9uLnN1YlZlY3RvcnMoIHZlcnRleFBvc2l0aW9uLCBjZW50ZXIgKS5hZGRTY2FsYXIoIDAuNSApLm11bHRpcGx5KCBzY2FsZSApO1xyXG5cclxuXHQvLyB0byBjaGVjayBpZiByb3RhdGlvbiBpcyBub3QgemVyb1xyXG5cdGlmICggc2luICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0X3JvdGF0ZWRQb3NpdGlvbi54ID0gKCBjb3MgKiBfYWxpZ25lZFBvc2l0aW9uLnggKSAtICggc2luICogX2FsaWduZWRQb3NpdGlvbi55ICk7XHJcblx0XHRfcm90YXRlZFBvc2l0aW9uLnkgPSAoIHNpbiAqIF9hbGlnbmVkUG9zaXRpb24ueCApICsgKCBjb3MgKiBfYWxpZ25lZFBvc2l0aW9uLnkgKTtcclxuXHJcblx0fSBlbHNlIHtcclxuXHJcblx0XHRfcm90YXRlZFBvc2l0aW9uLmNvcHkoIF9hbGlnbmVkUG9zaXRpb24gKTtcclxuXHJcblx0fVxyXG5cclxuXHJcblx0dmVydGV4UG9zaXRpb24uY29weSggbXZQb3NpdGlvbiApO1xyXG5cdHZlcnRleFBvc2l0aW9uLnggKz0gX3JvdGF0ZWRQb3NpdGlvbi54O1xyXG5cdHZlcnRleFBvc2l0aW9uLnkgKz0gX3JvdGF0ZWRQb3NpdGlvbi55O1xyXG5cclxuXHQvLyB0cmFuc2Zvcm0gdG8gd29ybGQgc3BhY2VcclxuXHR2ZXJ0ZXhQb3NpdGlvbi5hcHBseU1hdHJpeDQoIF92aWV3V29ybGRNYXRyaXggKTtcclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IFNwcml0ZSB9O1xyXG4iLCJpbXBvcnQgeyBWZWN0b3IzIH0gZnJvbSAnLi4vbWF0aC9WZWN0b3IzLmpzJztcclxuaW1wb3J0IHsgT2JqZWN0M0QgfSBmcm9tICcuLi9jb3JlL09iamVjdDNELmpzJztcclxuXHJcbmNvbnN0IF92MSA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuY29uc3QgX3YyID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5cclxuY2xhc3MgTE9EIGV4dGVuZHMgT2JqZWN0M0Qge1xyXG5cclxuXHRjb25zdHJ1Y3RvcigpIHtcclxuXHJcblx0XHRzdXBlcigpO1xyXG5cclxuXHRcdHRoaXMuX2N1cnJlbnRMZXZlbCA9IDA7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ0xPRCc7XHJcblxyXG5cdFx0T2JqZWN0LmRlZmluZVByb3BlcnRpZXMoIHRoaXMsIHtcclxuXHRcdFx0bGV2ZWxzOiB7XHJcblx0XHRcdFx0ZW51bWVyYWJsZTogdHJ1ZSxcclxuXHRcdFx0XHR2YWx1ZTogW11cclxuXHRcdFx0fSxcclxuXHRcdFx0aXNMT0Q6IHtcclxuXHRcdFx0XHR2YWx1ZTogdHJ1ZSxcclxuXHRcdFx0fVxyXG5cdFx0fSApO1xyXG5cclxuXHRcdHRoaXMuYXV0b1VwZGF0ZSA9IHRydWU7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSwgZmFsc2UgKTtcclxuXHJcblx0XHRjb25zdCBsZXZlbHMgPSBzb3VyY2UubGV2ZWxzO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IGxldmVscy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0Y29uc3QgbGV2ZWwgPSBsZXZlbHNbIGkgXTtcclxuXHJcblx0XHRcdHRoaXMuYWRkTGV2ZWwoIGxldmVsLm9iamVjdC5jbG9uZSgpLCBsZXZlbC5kaXN0YW5jZSwgbGV2ZWwuaHlzdGVyZXNpcyApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLmF1dG9VcGRhdGUgPSBzb3VyY2UuYXV0b1VwZGF0ZTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRhZGRMZXZlbCggb2JqZWN0LCBkaXN0YW5jZSA9IDAsIGh5c3RlcmVzaXMgPSAwICkge1xyXG5cclxuXHRcdGRpc3RhbmNlID0gTWF0aC5hYnMoIGRpc3RhbmNlICk7XHJcblxyXG5cdFx0Y29uc3QgbGV2ZWxzID0gdGhpcy5sZXZlbHM7XHJcblxyXG5cdFx0bGV0IGw7XHJcblxyXG5cdFx0Zm9yICggbCA9IDA7IGwgPCBsZXZlbHMubGVuZ3RoOyBsICsrICkge1xyXG5cclxuXHRcdFx0aWYgKCBkaXN0YW5jZSA8IGxldmVsc1sgbCBdLmRpc3RhbmNlICkge1xyXG5cclxuXHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0bGV2ZWxzLnNwbGljZSggbCwgMCwgeyBkaXN0YW5jZTogZGlzdGFuY2UsIGh5c3RlcmVzaXM6IGh5c3RlcmVzaXMsIG9iamVjdDogb2JqZWN0IH0gKTtcclxuXHJcblx0XHR0aGlzLmFkZCggb2JqZWN0ICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0Q3VycmVudExldmVsKCkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLl9jdXJyZW50TGV2ZWw7XHJcblxyXG5cdH1cclxuXHJcblxyXG5cclxuXHRnZXRPYmplY3RGb3JEaXN0YW5jZSggZGlzdGFuY2UgKSB7XHJcblxyXG5cdFx0Y29uc3QgbGV2ZWxzID0gdGhpcy5sZXZlbHM7XHJcblxyXG5cdFx0aWYgKCBsZXZlbHMubGVuZ3RoID4gMCApIHtcclxuXHJcblx0XHRcdGxldCBpLCBsO1xyXG5cclxuXHRcdFx0Zm9yICggaSA9IDEsIGwgPSBsZXZlbHMubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0bGV0IGxldmVsRGlzdGFuY2UgPSBsZXZlbHNbIGkgXS5kaXN0YW5jZTtcclxuXHJcblx0XHRcdFx0aWYgKCBsZXZlbHNbIGkgXS5vYmplY3QudmlzaWJsZSApIHtcclxuXHJcblx0XHRcdFx0XHRsZXZlbERpc3RhbmNlIC09IGxldmVsRGlzdGFuY2UgKiBsZXZlbHNbIGkgXS5oeXN0ZXJlc2lzO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdGlmICggZGlzdGFuY2UgPCBsZXZlbERpc3RhbmNlICkge1xyXG5cclxuXHRcdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRyZXR1cm4gbGV2ZWxzWyBpIC0gMSBdLm9iamVjdDtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIG51bGw7XHJcblxyXG5cdH1cclxuXHJcblx0cmF5Y2FzdCggcmF5Y2FzdGVyLCBpbnRlcnNlY3RzICkge1xyXG5cclxuXHRcdGNvbnN0IGxldmVscyA9IHRoaXMubGV2ZWxzO1xyXG5cclxuXHRcdGlmICggbGV2ZWxzLmxlbmd0aCA+IDAgKSB7XHJcblxyXG5cdFx0XHRfdjEuc2V0RnJvbU1hdHJpeFBvc2l0aW9uKCB0aGlzLm1hdHJpeFdvcmxkICk7XHJcblxyXG5cdFx0XHRjb25zdCBkaXN0YW5jZSA9IHJheWNhc3Rlci5yYXkub3JpZ2luLmRpc3RhbmNlVG8oIF92MSApO1xyXG5cclxuXHRcdFx0dGhpcy5nZXRPYmplY3RGb3JEaXN0YW5jZSggZGlzdGFuY2UgKS5yYXljYXN0KCByYXljYXN0ZXIsIGludGVyc2VjdHMgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0dXBkYXRlKCBjYW1lcmEgKSB7XHJcblxyXG5cdFx0Y29uc3QgbGV2ZWxzID0gdGhpcy5sZXZlbHM7XHJcblxyXG5cdFx0aWYgKCBsZXZlbHMubGVuZ3RoID4gMSApIHtcclxuXHJcblx0XHRcdF92MS5zZXRGcm9tTWF0cml4UG9zaXRpb24oIGNhbWVyYS5tYXRyaXhXb3JsZCApO1xyXG5cdFx0XHRfdjIuc2V0RnJvbU1hdHJpeFBvc2l0aW9uKCB0aGlzLm1hdHJpeFdvcmxkICk7XHJcblxyXG5cdFx0XHRjb25zdCBkaXN0YW5jZSA9IF92MS5kaXN0YW5jZVRvKCBfdjIgKSAvIGNhbWVyYS56b29tO1xyXG5cclxuXHRcdFx0bGV2ZWxzWyAwIF0ub2JqZWN0LnZpc2libGUgPSB0cnVlO1xyXG5cclxuXHRcdFx0bGV0IGksIGw7XHJcblxyXG5cdFx0XHRmb3IgKCBpID0gMSwgbCA9IGxldmVscy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRsZXQgbGV2ZWxEaXN0YW5jZSA9IGxldmVsc1sgaSBdLmRpc3RhbmNlO1xyXG5cclxuXHRcdFx0XHRpZiAoIGxldmVsc1sgaSBdLm9iamVjdC52aXNpYmxlICkge1xyXG5cclxuXHRcdFx0XHRcdGxldmVsRGlzdGFuY2UgLT0gbGV2ZWxEaXN0YW5jZSAqIGxldmVsc1sgaSBdLmh5c3RlcmVzaXM7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0aWYgKCBkaXN0YW5jZSA+PSBsZXZlbERpc3RhbmNlICkge1xyXG5cclxuXHRcdFx0XHRcdGxldmVsc1sgaSAtIDEgXS5vYmplY3QudmlzaWJsZSA9IGZhbHNlO1xyXG5cdFx0XHRcdFx0bGV2ZWxzWyBpIF0ub2JqZWN0LnZpc2libGUgPSB0cnVlO1xyXG5cclxuXHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHR0aGlzLl9jdXJyZW50TGV2ZWwgPSBpIC0gMTtcclxuXHJcblx0XHRcdGZvciAoIDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdGxldmVsc1sgaSBdLm9iamVjdC52aXNpYmxlID0gZmFsc2U7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdHRvSlNPTiggbWV0YSApIHtcclxuXHJcblx0XHRjb25zdCBkYXRhID0gc3VwZXIudG9KU09OKCBtZXRhICk7XHJcblxyXG5cdFx0aWYgKCB0aGlzLmF1dG9VcGRhdGUgPT09IGZhbHNlICkgZGF0YS5vYmplY3QuYXV0b1VwZGF0ZSA9IGZhbHNlO1xyXG5cclxuXHRcdGRhdGEub2JqZWN0LmxldmVscyA9IFtdO1xyXG5cclxuXHRcdGNvbnN0IGxldmVscyA9IHRoaXMubGV2ZWxzO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IGxldmVscy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0Y29uc3QgbGV2ZWwgPSBsZXZlbHNbIGkgXTtcclxuXHJcblx0XHRcdGRhdGEub2JqZWN0LmxldmVscy5wdXNoKCB7XHJcblx0XHRcdFx0b2JqZWN0OiBsZXZlbC5vYmplY3QudXVpZCxcclxuXHRcdFx0XHRkaXN0YW5jZTogbGV2ZWwuZGlzdGFuY2UsXHJcblx0XHRcdFx0aHlzdGVyZXNpczogbGV2ZWwuaHlzdGVyZXNpc1xyXG5cdFx0XHR9ICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiBkYXRhO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5cclxuZXhwb3J0IHsgTE9EIH07XHJcbiIsImltcG9ydCB7IE1lc2ggfSBmcm9tICcuL01lc2guanMnO1xyXG5pbXBvcnQgeyBCb3gzIH0gZnJvbSAnLi4vbWF0aC9Cb3gzLmpzJztcclxuaW1wb3J0IHsgTWF0cml4NCB9IGZyb20gJy4uL21hdGgvTWF0cml4NC5qcyc7XHJcbmltcG9ydCB7IFNwaGVyZSB9IGZyb20gJy4uL21hdGgvU3BoZXJlLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yMyB9IGZyb20gJy4uL21hdGgvVmVjdG9yMy5qcyc7XHJcbmltcG9ydCB7IFZlY3RvcjQgfSBmcm9tICcuLi9tYXRoL1ZlY3RvcjQuanMnO1xyXG5pbXBvcnQgeyBSYXkgfSBmcm9tICcuLi9tYXRoL1JheS5qcyc7XHJcbmltcG9ydCB7IEF0dGFjaGVkQmluZE1vZGUsIERldGFjaGVkQmluZE1vZGUgfSBmcm9tICcuLi9jb25zdGFudHMuanMnO1xyXG5cclxuY29uc3QgX2Jhc2VQb3NpdGlvbiA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuXHJcbmNvbnN0IF9za2luSW5kZXggPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3I0KCk7XHJcbmNvbnN0IF9za2luV2VpZ2h0ID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yNCgpO1xyXG5cclxuY29uc3QgX3ZlY3RvcjMgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XHJcbmNvbnN0IF9tYXRyaXg0ID0gLypAX19QVVJFX18qLyBuZXcgTWF0cml4NCgpO1xyXG5jb25zdCBfdmVydGV4ID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5cclxuY29uc3QgX3NwaGVyZSA9IC8qQF9fUFVSRV9fKi8gbmV3IFNwaGVyZSgpO1xyXG5jb25zdCBfaW52ZXJzZU1hdHJpeCA9IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDQoKTtcclxuY29uc3QgX3JheSA9IC8qQF9fUFVSRV9fKi8gbmV3IFJheSgpO1xyXG5cclxuY2xhc3MgU2tpbm5lZE1lc2ggZXh0ZW5kcyBNZXNoIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIGdlb21ldHJ5LCBtYXRlcmlhbCApIHtcclxuXHJcblx0XHRzdXBlciggZ2VvbWV0cnksIG1hdGVyaWFsICk7XHJcblxyXG5cdFx0dGhpcy5pc1NraW5uZWRNZXNoID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSAnU2tpbm5lZE1lc2gnO1xyXG5cclxuXHRcdHRoaXMuYmluZE1vZGUgPSBBdHRhY2hlZEJpbmRNb2RlO1xyXG5cdFx0dGhpcy5iaW5kTWF0cml4ID0gbmV3IE1hdHJpeDQoKTtcclxuXHRcdHRoaXMuYmluZE1hdHJpeEludmVyc2UgPSBuZXcgTWF0cml4NCgpO1xyXG5cclxuXHRcdHRoaXMuYm91bmRpbmdCb3ggPSBudWxsO1xyXG5cdFx0dGhpcy5ib3VuZGluZ1NwaGVyZSA9IG51bGw7XHJcblxyXG5cdH1cclxuXHJcblx0Y29tcHV0ZUJvdW5kaW5nQm94KCkge1xyXG5cclxuXHRcdGNvbnN0IGdlb21ldHJ5ID0gdGhpcy5nZW9tZXRyeTtcclxuXHJcblx0XHRpZiAoIHRoaXMuYm91bmRpbmdCb3ggPT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHR0aGlzLmJvdW5kaW5nQm94ID0gbmV3IEJveDMoKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5ib3VuZGluZ0JveC5tYWtlRW1wdHkoKTtcclxuXHJcblx0XHRjb25zdCBwb3NpdGlvbkF0dHJpYnV0ZSA9IGdlb21ldHJ5LmdldEF0dHJpYnV0ZSggJ3Bvc2l0aW9uJyApO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHBvc2l0aW9uQXR0cmlidXRlLmNvdW50OyBpICsrICkge1xyXG5cclxuXHRcdFx0dGhpcy5nZXRWZXJ0ZXhQb3NpdGlvbiggaSwgX3ZlcnRleCApO1xyXG5cdFx0XHR0aGlzLmJvdW5kaW5nQm94LmV4cGFuZEJ5UG9pbnQoIF92ZXJ0ZXggKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0Y29tcHV0ZUJvdW5kaW5nU3BoZXJlKCkge1xyXG5cclxuXHRcdGNvbnN0IGdlb21ldHJ5ID0gdGhpcy5nZW9tZXRyeTtcclxuXHJcblx0XHRpZiAoIHRoaXMuYm91bmRpbmdTcGhlcmUgPT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHR0aGlzLmJvdW5kaW5nU3BoZXJlID0gbmV3IFNwaGVyZSgpO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLmJvdW5kaW5nU3BoZXJlLm1ha2VFbXB0eSgpO1xyXG5cclxuXHRcdGNvbnN0IHBvc2l0aW9uQXR0cmlidXRlID0gZ2VvbWV0cnkuZ2V0QXR0cmlidXRlKCAncG9zaXRpb24nICk7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgcG9zaXRpb25BdHRyaWJ1dGUuY291bnQ7IGkgKysgKSB7XHJcblxyXG5cdFx0XHR0aGlzLmdldFZlcnRleFBvc2l0aW9uKCBpLCBfdmVydGV4ICk7XHJcblx0XHRcdHRoaXMuYm91bmRpbmdTcGhlcmUuZXhwYW5kQnlQb2ludCggX3ZlcnRleCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRjb3B5KCBzb3VyY2UsIHJlY3Vyc2l2ZSApIHtcclxuXHJcblx0XHRzdXBlci5jb3B5KCBzb3VyY2UsIHJlY3Vyc2l2ZSApO1xyXG5cclxuXHRcdHRoaXMuYmluZE1vZGUgPSBzb3VyY2UuYmluZE1vZGU7XHJcblx0XHR0aGlzLmJpbmRNYXRyaXguY29weSggc291cmNlLmJpbmRNYXRyaXggKTtcclxuXHRcdHRoaXMuYmluZE1hdHJpeEludmVyc2UuY29weSggc291cmNlLmJpbmRNYXRyaXhJbnZlcnNlICk7XHJcblxyXG5cdFx0dGhpcy5za2VsZXRvbiA9IHNvdXJjZS5za2VsZXRvbjtcclxuXHJcblx0XHRpZiAoIHNvdXJjZS5ib3VuZGluZ0JveCAhPT0gbnVsbCApIHRoaXMuYm91bmRpbmdCb3ggPSBzb3VyY2UuYm91bmRpbmdCb3guY2xvbmUoKTtcclxuXHRcdGlmICggc291cmNlLmJvdW5kaW5nU3BoZXJlICE9PSBudWxsICkgdGhpcy5ib3VuZGluZ1NwaGVyZSA9IHNvdXJjZS5ib3VuZGluZ1NwaGVyZS5jbG9uZSgpO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHJheWNhc3QoIHJheWNhc3RlciwgaW50ZXJzZWN0cyApIHtcclxuXHJcblx0XHRjb25zdCBtYXRlcmlhbCA9IHRoaXMubWF0ZXJpYWw7XHJcblx0XHRjb25zdCBtYXRyaXhXb3JsZCA9IHRoaXMubWF0cml4V29ybGQ7XHJcblxyXG5cdFx0aWYgKCBtYXRlcmlhbCA9PT0gdW5kZWZpbmVkICkgcmV0dXJuO1xyXG5cclxuXHRcdC8vIHRlc3Qgd2l0aCBib3VuZGluZyBzcGhlcmUgaW4gd29ybGQgc3BhY2VcclxuXHJcblx0XHRpZiAoIHRoaXMuYm91bmRpbmdTcGhlcmUgPT09IG51bGwgKSB0aGlzLmNvbXB1dGVCb3VuZGluZ1NwaGVyZSgpO1xyXG5cclxuXHRcdF9zcGhlcmUuY29weSggdGhpcy5ib3VuZGluZ1NwaGVyZSApO1xyXG5cdFx0X3NwaGVyZS5hcHBseU1hdHJpeDQoIG1hdHJpeFdvcmxkICk7XHJcblxyXG5cdFx0aWYgKCByYXljYXN0ZXIucmF5LmludGVyc2VjdHNTcGhlcmUoIF9zcGhlcmUgKSA9PT0gZmFsc2UgKSByZXR1cm47XHJcblxyXG5cdFx0Ly8gY29udmVydCByYXkgdG8gbG9jYWwgc3BhY2Ugb2Ygc2tpbm5lZCBtZXNoXHJcblxyXG5cdFx0X2ludmVyc2VNYXRyaXguY29weSggbWF0cml4V29ybGQgKS5pbnZlcnQoKTtcclxuXHRcdF9yYXkuY29weSggcmF5Y2FzdGVyLnJheSApLmFwcGx5TWF0cml4NCggX2ludmVyc2VNYXRyaXggKTtcclxuXHJcblx0XHQvLyB0ZXN0IHdpdGggYm91bmRpbmcgYm94IGluIGxvY2FsIHNwYWNlXHJcblxyXG5cdFx0aWYgKCB0aGlzLmJvdW5kaW5nQm94ICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0aWYgKCBfcmF5LmludGVyc2VjdHNCb3goIHRoaXMuYm91bmRpbmdCb3ggKSA9PT0gZmFsc2UgKSByZXR1cm47XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIHRlc3QgZm9yIGludGVyc2VjdGlvbnMgd2l0aCBnZW9tZXRyeVxyXG5cclxuXHRcdHRoaXMuX2NvbXB1dGVJbnRlcnNlY3Rpb25zKCByYXljYXN0ZXIsIGludGVyc2VjdHMsIF9yYXkgKTtcclxuXHJcblx0fVxyXG5cclxuXHRnZXRWZXJ0ZXhQb3NpdGlvbiggaW5kZXgsIHRhcmdldCApIHtcclxuXHJcblx0XHRzdXBlci5nZXRWZXJ0ZXhQb3NpdGlvbiggaW5kZXgsIHRhcmdldCApO1xyXG5cclxuXHRcdHRoaXMuYXBwbHlCb25lVHJhbnNmb3JtKCBpbmRleCwgdGFyZ2V0ICk7XHJcblxyXG5cdFx0cmV0dXJuIHRhcmdldDtcclxuXHJcblx0fVxyXG5cclxuXHRiaW5kKCBza2VsZXRvbiwgYmluZE1hdHJpeCApIHtcclxuXHJcblx0XHR0aGlzLnNrZWxldG9uID0gc2tlbGV0b247XHJcblxyXG5cdFx0aWYgKCBiaW5kTWF0cml4ID09PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHR0aGlzLnVwZGF0ZU1hdHJpeFdvcmxkKCB0cnVlICk7XHJcblxyXG5cdFx0XHR0aGlzLnNrZWxldG9uLmNhbGN1bGF0ZUludmVyc2VzKCk7XHJcblxyXG5cdFx0XHRiaW5kTWF0cml4ID0gdGhpcy5tYXRyaXhXb3JsZDtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5iaW5kTWF0cml4LmNvcHkoIGJpbmRNYXRyaXggKTtcclxuXHRcdHRoaXMuYmluZE1hdHJpeEludmVyc2UuY29weSggYmluZE1hdHJpeCApLmludmVydCgpO1xyXG5cclxuXHR9XHJcblxyXG5cdHBvc2UoKSB7XHJcblxyXG5cdFx0dGhpcy5za2VsZXRvbi5wb3NlKCk7XHJcblxyXG5cdH1cclxuXHJcblx0bm9ybWFsaXplU2tpbldlaWdodHMoKSB7XHJcblxyXG5cdFx0Y29uc3QgdmVjdG9yID0gbmV3IFZlY3RvcjQoKTtcclxuXHJcblx0XHRjb25zdCBza2luV2VpZ2h0ID0gdGhpcy5nZW9tZXRyeS5hdHRyaWJ1dGVzLnNraW5XZWlnaHQ7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gc2tpbldlaWdodC5jb3VudDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHR2ZWN0b3IuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggc2tpbldlaWdodCwgaSApO1xyXG5cclxuXHRcdFx0Y29uc3Qgc2NhbGUgPSAxLjAgLyB2ZWN0b3IubWFuaGF0dGFuTGVuZ3RoKCk7XHJcblxyXG5cdFx0XHRpZiAoIHNjYWxlICE9PSBJbmZpbml0eSApIHtcclxuXHJcblx0XHRcdFx0dmVjdG9yLm11bHRpcGx5U2NhbGFyKCBzY2FsZSApO1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0dmVjdG9yLnNldCggMSwgMCwgMCwgMCApOyAvLyBkbyBzb21ldGhpbmcgcmVhc29uYWJsZVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0c2tpbldlaWdodC5zZXRYWVpXKCBpLCB2ZWN0b3IueCwgdmVjdG9yLnksIHZlY3Rvci56LCB2ZWN0b3IudyApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHR1cGRhdGVNYXRyaXhXb3JsZCggZm9yY2UgKSB7XHJcblxyXG5cdFx0c3VwZXIudXBkYXRlTWF0cml4V29ybGQoIGZvcmNlICk7XHJcblxyXG5cdFx0aWYgKCB0aGlzLmJpbmRNb2RlID09PSBBdHRhY2hlZEJpbmRNb2RlICkge1xyXG5cclxuXHRcdFx0dGhpcy5iaW5kTWF0cml4SW52ZXJzZS5jb3B5KCB0aGlzLm1hdHJpeFdvcmxkICkuaW52ZXJ0KCk7XHJcblxyXG5cdFx0fSBlbHNlIGlmICggdGhpcy5iaW5kTW9kZSA9PT0gRGV0YWNoZWRCaW5kTW9kZSApIHtcclxuXHJcblx0XHRcdHRoaXMuYmluZE1hdHJpeEludmVyc2UuY29weSggdGhpcy5iaW5kTWF0cml4ICkuaW52ZXJ0KCk7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLlNraW5uZWRNZXNoOiBVbnJlY29nbml6ZWQgYmluZE1vZGU6ICcgKyB0aGlzLmJpbmRNb2RlICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGFwcGx5Qm9uZVRyYW5zZm9ybSggaW5kZXgsIHZlY3RvciApIHtcclxuXHJcblx0XHRjb25zdCBza2VsZXRvbiA9IHRoaXMuc2tlbGV0b247XHJcblx0XHRjb25zdCBnZW9tZXRyeSA9IHRoaXMuZ2VvbWV0cnk7XHJcblxyXG5cdFx0X3NraW5JbmRleC5mcm9tQnVmZmVyQXR0cmlidXRlKCBnZW9tZXRyeS5hdHRyaWJ1dGVzLnNraW5JbmRleCwgaW5kZXggKTtcclxuXHRcdF9za2luV2VpZ2h0LmZyb21CdWZmZXJBdHRyaWJ1dGUoIGdlb21ldHJ5LmF0dHJpYnV0ZXMuc2tpbldlaWdodCwgaW5kZXggKTtcclxuXHJcblx0XHRfYmFzZVBvc2l0aW9uLmNvcHkoIHZlY3RvciApLmFwcGx5TWF0cml4NCggdGhpcy5iaW5kTWF0cml4ICk7XHJcblxyXG5cdFx0dmVjdG9yLnNldCggMCwgMCwgMCApO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IDQ7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRjb25zdCB3ZWlnaHQgPSBfc2tpbldlaWdodC5nZXRDb21wb25lbnQoIGkgKTtcclxuXHJcblx0XHRcdGlmICggd2VpZ2h0ICE9PSAwICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBib25lSW5kZXggPSBfc2tpbkluZGV4LmdldENvbXBvbmVudCggaSApO1xyXG5cclxuXHRcdFx0XHRfbWF0cml4NC5tdWx0aXBseU1hdHJpY2VzKCBza2VsZXRvbi5ib25lc1sgYm9uZUluZGV4IF0ubWF0cml4V29ybGQsIHNrZWxldG9uLmJvbmVJbnZlcnNlc1sgYm9uZUluZGV4IF0gKTtcclxuXHJcblx0XHRcdFx0dmVjdG9yLmFkZFNjYWxlZFZlY3RvciggX3ZlY3RvcjMuY29weSggX2Jhc2VQb3NpdGlvbiApLmFwcGx5TWF0cml4NCggX21hdHJpeDQgKSwgd2VpZ2h0ICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB2ZWN0b3IuYXBwbHlNYXRyaXg0KCB0aGlzLmJpbmRNYXRyaXhJbnZlcnNlICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IFNraW5uZWRNZXNoIH07XHJcbiIsImltcG9ydCB7IE9iamVjdDNEIH0gZnJvbSAnLi4vY29yZS9PYmplY3QzRC5qcyc7XHJcblxyXG5jbGFzcyBCb25lIGV4dGVuZHMgT2JqZWN0M0Qge1xyXG5cclxuXHRjb25zdHJ1Y3RvcigpIHtcclxuXHJcblx0XHRzdXBlcigpO1xyXG5cclxuXHRcdHRoaXMuaXNCb25lID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSAnQm9uZSc7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IEJvbmUgfTtcclxuIiwiaW1wb3J0IHsgVGV4dHVyZSB9IGZyb20gJy4vVGV4dHVyZS5qcyc7XHJcbmltcG9ydCB7IE5lYXJlc3RGaWx0ZXIgfSBmcm9tICcuLi9jb25zdGFudHMuanMnO1xyXG5cclxuY2xhc3MgRGF0YVRleHR1cmUgZXh0ZW5kcyBUZXh0dXJlIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIGRhdGEgPSBudWxsLCB3aWR0aCA9IDEsIGhlaWdodCA9IDEsIGZvcm1hdCwgdHlwZSwgbWFwcGluZywgd3JhcFMsIHdyYXBULCBtYWdGaWx0ZXIgPSBOZWFyZXN0RmlsdGVyLCBtaW5GaWx0ZXIgPSBOZWFyZXN0RmlsdGVyLCBhbmlzb3Ryb3B5LCBjb2xvclNwYWNlICkge1xyXG5cclxuXHRcdHN1cGVyKCBudWxsLCBtYXBwaW5nLCB3cmFwUywgd3JhcFQsIG1hZ0ZpbHRlciwgbWluRmlsdGVyLCBmb3JtYXQsIHR5cGUsIGFuaXNvdHJvcHksIGNvbG9yU3BhY2UgKTtcclxuXHJcblx0XHR0aGlzLmlzRGF0YVRleHR1cmUgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMuaW1hZ2UgPSB7IGRhdGE6IGRhdGEsIHdpZHRoOiB3aWR0aCwgaGVpZ2h0OiBoZWlnaHQgfTtcclxuXHJcblx0XHR0aGlzLmdlbmVyYXRlTWlwbWFwcyA9IGZhbHNlO1xyXG5cdFx0dGhpcy5mbGlwWSA9IGZhbHNlO1xyXG5cdFx0dGhpcy51bnBhY2tBbGlnbm1lbnQgPSAxO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBEYXRhVGV4dHVyZSB9O1xyXG4iLCJpbXBvcnQge1xyXG5cdFJHQkFGb3JtYXQsXHJcblx0RmxvYXRUeXBlXHJcbn0gZnJvbSAnLi4vY29uc3RhbnRzLmpzJztcclxuaW1wb3J0IHsgQm9uZSB9IGZyb20gJy4vQm9uZS5qcyc7XHJcbmltcG9ydCB7IE1hdHJpeDQgfSBmcm9tICcuLi9tYXRoL01hdHJpeDQuanMnO1xyXG5pbXBvcnQgeyBEYXRhVGV4dHVyZSB9IGZyb20gJy4uL3RleHR1cmVzL0RhdGFUZXh0dXJlLmpzJztcclxuaW1wb3J0ICogYXMgTWF0aFV0aWxzIGZyb20gJy4uL21hdGgvTWF0aFV0aWxzLmpzJztcclxuXHJcbmNvbnN0IF9vZmZzZXRNYXRyaXggPSAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXg0KCk7XHJcbmNvbnN0IF9pZGVudGl0eU1hdHJpeCA9IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDQoKTtcclxuXHJcbmNsYXNzIFNrZWxldG9uIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIGJvbmVzID0gW10sIGJvbmVJbnZlcnNlcyA9IFtdICkge1xyXG5cclxuXHRcdHRoaXMudXVpZCA9IE1hdGhVdGlscy5nZW5lcmF0ZVVVSUQoKTtcclxuXHJcblx0XHR0aGlzLmJvbmVzID0gYm9uZXMuc2xpY2UoIDAgKTtcclxuXHRcdHRoaXMuYm9uZUludmVyc2VzID0gYm9uZUludmVyc2VzO1xyXG5cdFx0dGhpcy5ib25lTWF0cmljZXMgPSBudWxsO1xyXG5cclxuXHRcdHRoaXMuYm9uZVRleHR1cmUgPSBudWxsO1xyXG5cclxuXHRcdHRoaXMuaW5pdCgpO1xyXG5cclxuXHR9XHJcblxyXG5cdGluaXQoKSB7XHJcblxyXG5cdFx0Y29uc3QgYm9uZXMgPSB0aGlzLmJvbmVzO1xyXG5cdFx0Y29uc3QgYm9uZUludmVyc2VzID0gdGhpcy5ib25lSW52ZXJzZXM7XHJcblxyXG5cdFx0dGhpcy5ib25lTWF0cmljZXMgPSBuZXcgRmxvYXQzMkFycmF5KCBib25lcy5sZW5ndGggKiAxNiApO1xyXG5cclxuXHRcdC8vIGNhbGN1bGF0ZSBpbnZlcnNlIGJvbmUgbWF0cmljZXMgaWYgbmVjZXNzYXJ5XHJcblxyXG5cdFx0aWYgKCBib25lSW52ZXJzZXMubGVuZ3RoID09PSAwICkge1xyXG5cclxuXHRcdFx0dGhpcy5jYWxjdWxhdGVJbnZlcnNlcygpO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHQvLyBoYW5kbGUgc3BlY2lhbCBjYXNlXHJcblxyXG5cdFx0XHRpZiAoIGJvbmVzLmxlbmd0aCAhPT0gYm9uZUludmVyc2VzLmxlbmd0aCApIHtcclxuXHJcblx0XHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuU2tlbGV0b246IE51bWJlciBvZiBpbnZlcnNlIGJvbmUgbWF0cmljZXMgZG9lcyBub3QgbWF0Y2ggYW1vdW50IG9mIGJvbmVzLicgKTtcclxuXHJcblx0XHRcdFx0dGhpcy5ib25lSW52ZXJzZXMgPSBbXTtcclxuXHJcblx0XHRcdFx0Zm9yICggbGV0IGkgPSAwLCBpbCA9IHRoaXMuYm9uZXMubGVuZ3RoOyBpIDwgaWw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0dGhpcy5ib25lSW52ZXJzZXMucHVzaCggbmV3IE1hdHJpeDQoKSApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGNhbGN1bGF0ZUludmVyc2VzKCkge1xyXG5cclxuXHRcdHRoaXMuYm9uZUludmVyc2VzLmxlbmd0aCA9IDA7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBpbCA9IHRoaXMuYm9uZXMubGVuZ3RoOyBpIDwgaWw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBpbnZlcnNlID0gbmV3IE1hdHJpeDQoKTtcclxuXHJcblx0XHRcdGlmICggdGhpcy5ib25lc1sgaSBdICkge1xyXG5cclxuXHRcdFx0XHRpbnZlcnNlLmNvcHkoIHRoaXMuYm9uZXNbIGkgXS5tYXRyaXhXb3JsZCApLmludmVydCgpO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0dGhpcy5ib25lSW52ZXJzZXMucHVzaCggaW52ZXJzZSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRwb3NlKCkge1xyXG5cclxuXHRcdC8vIHJlY292ZXIgdGhlIGJpbmQtdGltZSB3b3JsZCBtYXRyaWNlc1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSB0aGlzLmJvbmVzLmxlbmd0aDsgaSA8IGlsOyBpICsrICkge1xyXG5cclxuXHRcdFx0Y29uc3QgYm9uZSA9IHRoaXMuYm9uZXNbIGkgXTtcclxuXHJcblx0XHRcdGlmICggYm9uZSApIHtcclxuXHJcblx0XHRcdFx0Ym9uZS5tYXRyaXhXb3JsZC5jb3B5KCB0aGlzLmJvbmVJbnZlcnNlc1sgaSBdICkuaW52ZXJ0KCk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIGNvbXB1dGUgdGhlIGxvY2FsIG1hdHJpY2VzLCBwb3NpdGlvbnMsIHJvdGF0aW9ucyBhbmQgc2NhbGVzXHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBpbCA9IHRoaXMuYm9uZXMubGVuZ3RoOyBpIDwgaWw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBib25lID0gdGhpcy5ib25lc1sgaSBdO1xyXG5cclxuXHRcdFx0aWYgKCBib25lICkge1xyXG5cclxuXHRcdFx0XHRpZiAoIGJvbmUucGFyZW50ICYmIGJvbmUucGFyZW50LmlzQm9uZSApIHtcclxuXHJcblx0XHRcdFx0XHRib25lLm1hdHJpeC5jb3B5KCBib25lLnBhcmVudC5tYXRyaXhXb3JsZCApLmludmVydCgpO1xyXG5cdFx0XHRcdFx0Ym9uZS5tYXRyaXgubXVsdGlwbHkoIGJvbmUubWF0cml4V29ybGQgKTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRib25lLm1hdHJpeC5jb3B5KCBib25lLm1hdHJpeFdvcmxkICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0Ym9uZS5tYXRyaXguZGVjb21wb3NlKCBib25lLnBvc2l0aW9uLCBib25lLnF1YXRlcm5pb24sIGJvbmUuc2NhbGUgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0dXBkYXRlKCkge1xyXG5cclxuXHRcdGNvbnN0IGJvbmVzID0gdGhpcy5ib25lcztcclxuXHRcdGNvbnN0IGJvbmVJbnZlcnNlcyA9IHRoaXMuYm9uZUludmVyc2VzO1xyXG5cdFx0Y29uc3QgYm9uZU1hdHJpY2VzID0gdGhpcy5ib25lTWF0cmljZXM7XHJcblx0XHRjb25zdCBib25lVGV4dHVyZSA9IHRoaXMuYm9uZVRleHR1cmU7XHJcblxyXG5cdFx0Ly8gZmxhdHRlbiBib25lIG1hdHJpY2VzIHRvIGFycmF5XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBpbCA9IGJvbmVzLmxlbmd0aDsgaSA8IGlsOyBpICsrICkge1xyXG5cclxuXHRcdFx0Ly8gY29tcHV0ZSB0aGUgb2Zmc2V0IGJldHdlZW4gdGhlIGN1cnJlbnQgYW5kIHRoZSBvcmlnaW5hbCB0cmFuc2Zvcm1cclxuXHJcblx0XHRcdGNvbnN0IG1hdHJpeCA9IGJvbmVzWyBpIF0gPyBib25lc1sgaSBdLm1hdHJpeFdvcmxkIDogX2lkZW50aXR5TWF0cml4O1xyXG5cclxuXHRcdFx0X29mZnNldE1hdHJpeC5tdWx0aXBseU1hdHJpY2VzKCBtYXRyaXgsIGJvbmVJbnZlcnNlc1sgaSBdICk7XHJcblx0XHRcdF9vZmZzZXRNYXRyaXgudG9BcnJheSggYm9uZU1hdHJpY2VzLCBpICogMTYgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBib25lVGV4dHVyZSAhPT0gbnVsbCApIHtcclxuXHJcblx0XHRcdGJvbmVUZXh0dXJlLm5lZWRzVXBkYXRlID0gdHJ1ZTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0Y2xvbmUoKSB7XHJcblxyXG5cdFx0cmV0dXJuIG5ldyBTa2VsZXRvbiggdGhpcy5ib25lcywgdGhpcy5ib25lSW52ZXJzZXMgKTtcclxuXHJcblx0fVxyXG5cclxuXHRjb21wdXRlQm9uZVRleHR1cmUoKSB7XHJcblxyXG5cdFx0Ly8gbGF5b3V0ICgxIG1hdHJpeCA9IDQgcGl4ZWxzKVxyXG5cdFx0Ly8gICAgICBSR0JBIFJHQkEgUkdCQSBSR0JBICg9PiBjb2x1bW4xLCBjb2x1bW4yLCBjb2x1bW4zLCBjb2x1bW40KVxyXG5cdFx0Ly8gIHdpdGggIDh4OCAgcGl4ZWwgdGV4dHVyZSBtYXggICAxNiBib25lcyAqIDQgcGl4ZWxzID0gICg4ICogOClcclxuXHRcdC8vICAgICAgIDE2eDE2IHBpeGVsIHRleHR1cmUgbWF4ICAgNjQgYm9uZXMgKiA0IHBpeGVscyA9ICgxNiAqIDE2KVxyXG5cdFx0Ly8gICAgICAgMzJ4MzIgcGl4ZWwgdGV4dHVyZSBtYXggIDI1NiBib25lcyAqIDQgcGl4ZWxzID0gKDMyICogMzIpXHJcblx0XHQvLyAgICAgICA2NHg2NCBwaXhlbCB0ZXh0dXJlIG1heCAxMDI0IGJvbmVzICogNCBwaXhlbHMgPSAoNjQgKiA2NClcclxuXHJcblx0XHRsZXQgc2l6ZSA9IE1hdGguc3FydCggdGhpcy5ib25lcy5sZW5ndGggKiA0ICk7IC8vIDQgcGl4ZWxzIG5lZWRlZCBmb3IgMSBtYXRyaXhcclxuXHRcdHNpemUgPSBNYXRoLmNlaWwoIHNpemUgLyA0ICkgKiA0O1xyXG5cdFx0c2l6ZSA9IE1hdGgubWF4KCBzaXplLCA0ICk7XHJcblxyXG5cdFx0Y29uc3QgYm9uZU1hdHJpY2VzID0gbmV3IEZsb2F0MzJBcnJheSggc2l6ZSAqIHNpemUgKiA0ICk7IC8vIDQgZmxvYXRzIHBlciBSR0JBIHBpeGVsXHJcblx0XHRib25lTWF0cmljZXMuc2V0KCB0aGlzLmJvbmVNYXRyaWNlcyApOyAvLyBjb3B5IGN1cnJlbnQgdmFsdWVzXHJcblxyXG5cdFx0Y29uc3QgYm9uZVRleHR1cmUgPSBuZXcgRGF0YVRleHR1cmUoIGJvbmVNYXRyaWNlcywgc2l6ZSwgc2l6ZSwgUkdCQUZvcm1hdCwgRmxvYXRUeXBlICk7XHJcblx0XHRib25lVGV4dHVyZS5uZWVkc1VwZGF0ZSA9IHRydWU7XHJcblxyXG5cdFx0dGhpcy5ib25lTWF0cmljZXMgPSBib25lTWF0cmljZXM7XHJcblx0XHR0aGlzLmJvbmVUZXh0dXJlID0gYm9uZVRleHR1cmU7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0Qm9uZUJ5TmFtZSggbmFtZSApIHtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gdGhpcy5ib25lcy5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcclxuXHJcblx0XHRcdGNvbnN0IGJvbmUgPSB0aGlzLmJvbmVzWyBpIF07XHJcblxyXG5cdFx0XHRpZiAoIGJvbmUubmFtZSA9PT0gbmFtZSApIHtcclxuXHJcblx0XHRcdFx0cmV0dXJuIGJvbmU7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB1bmRlZmluZWQ7XHJcblxyXG5cdH1cclxuXHJcblx0ZGlzcG9zZSggKSB7XHJcblxyXG5cdFx0aWYgKCB0aGlzLmJvbmVUZXh0dXJlICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0dGhpcy5ib25lVGV4dHVyZS5kaXNwb3NlKCk7XHJcblxyXG5cdFx0XHR0aGlzLmJvbmVUZXh0dXJlID0gbnVsbDtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0ZnJvbUpTT04oIGpzb24sIGJvbmVzICkge1xyXG5cclxuXHRcdHRoaXMudXVpZCA9IGpzb24udXVpZDtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBqc29uLmJvbmVzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRjb25zdCB1dWlkID0ganNvbi5ib25lc1sgaSBdO1xyXG5cdFx0XHRsZXQgYm9uZSA9IGJvbmVzWyB1dWlkIF07XHJcblxyXG5cdFx0XHRpZiAoIGJvbmUgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuU2tlbGV0b246IE5vIGJvbmUgZm91bmQgd2l0aCBVVUlEOicsIHV1aWQgKTtcclxuXHRcdFx0XHRib25lID0gbmV3IEJvbmUoKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHRoaXMuYm9uZXMucHVzaCggYm9uZSApO1xyXG5cdFx0XHR0aGlzLmJvbmVJbnZlcnNlcy5wdXNoKCBuZXcgTWF0cml4NCgpLmZyb21BcnJheSgganNvbi5ib25lSW52ZXJzZXNbIGkgXSApICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMuaW5pdCgpO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHRvSlNPTigpIHtcclxuXHJcblx0XHRjb25zdCBkYXRhID0ge1xyXG5cdFx0XHRtZXRhZGF0YToge1xyXG5cdFx0XHRcdHZlcnNpb246IDQuNixcclxuXHRcdFx0XHR0eXBlOiAnU2tlbGV0b24nLFxyXG5cdFx0XHRcdGdlbmVyYXRvcjogJ1NrZWxldG9uLnRvSlNPTidcclxuXHRcdFx0fSxcclxuXHRcdFx0Ym9uZXM6IFtdLFxyXG5cdFx0XHRib25lSW52ZXJzZXM6IFtdXHJcblx0XHR9O1xyXG5cclxuXHRcdGRhdGEudXVpZCA9IHRoaXMudXVpZDtcclxuXHJcblx0XHRjb25zdCBib25lcyA9IHRoaXMuYm9uZXM7XHJcblx0XHRjb25zdCBib25lSW52ZXJzZXMgPSB0aGlzLmJvbmVJbnZlcnNlcztcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBib25lcy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0Y29uc3QgYm9uZSA9IGJvbmVzWyBpIF07XHJcblx0XHRcdGRhdGEuYm9uZXMucHVzaCggYm9uZS51dWlkICk7XHJcblxyXG5cdFx0XHRjb25zdCBib25lSW52ZXJzZSA9IGJvbmVJbnZlcnNlc1sgaSBdO1xyXG5cdFx0XHRkYXRhLmJvbmVJbnZlcnNlcy5wdXNoKCBib25lSW52ZXJzZS50b0FycmF5KCkgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIGRhdGE7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IFNrZWxldG9uIH07XHJcbiIsImltcG9ydCB7IEJ1ZmZlckF0dHJpYnV0ZSB9IGZyb20gJy4vQnVmZmVyQXR0cmlidXRlLmpzJztcclxuXHJcbmNsYXNzIEluc3RhbmNlZEJ1ZmZlckF0dHJpYnV0ZSBleHRlbmRzIEJ1ZmZlckF0dHJpYnV0ZSB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBhcnJheSwgaXRlbVNpemUsIG5vcm1hbGl6ZWQsIG1lc2hQZXJBdHRyaWJ1dGUgPSAxICkge1xyXG5cclxuXHRcdHN1cGVyKCBhcnJheSwgaXRlbVNpemUsIG5vcm1hbGl6ZWQgKTtcclxuXHJcblx0XHR0aGlzLmlzSW5zdGFuY2VkQnVmZmVyQXR0cmlidXRlID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLm1lc2hQZXJBdHRyaWJ1dGUgPSBtZXNoUGVyQXR0cmlidXRlO1xyXG5cclxuXHR9XHJcblxyXG5cdGNvcHkoIHNvdXJjZSApIHtcclxuXHJcblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcclxuXHJcblx0XHR0aGlzLm1lc2hQZXJBdHRyaWJ1dGUgPSBzb3VyY2UubWVzaFBlckF0dHJpYnV0ZTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHR0b0pTT04oKSB7XHJcblxyXG5cdFx0Y29uc3QgZGF0YSA9IHN1cGVyLnRvSlNPTigpO1xyXG5cclxuXHRcdGRhdGEubWVzaFBlckF0dHJpYnV0ZSA9IHRoaXMubWVzaFBlckF0dHJpYnV0ZTtcclxuXHJcblx0XHRkYXRhLmlzSW5zdGFuY2VkQnVmZmVyQXR0cmlidXRlID0gdHJ1ZTtcclxuXHJcblx0XHRyZXR1cm4gZGF0YTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgSW5zdGFuY2VkQnVmZmVyQXR0cmlidXRlIH07XHJcbiIsImltcG9ydCB7IEluc3RhbmNlZEJ1ZmZlckF0dHJpYnV0ZSB9IGZyb20gJy4uL2NvcmUvSW5zdGFuY2VkQnVmZmVyQXR0cmlidXRlLmpzJztcclxuaW1wb3J0IHsgTWVzaCB9IGZyb20gJy4vTWVzaC5qcyc7XHJcbmltcG9ydCB7IEJveDMgfSBmcm9tICcuLi9tYXRoL0JveDMuanMnO1xyXG5pbXBvcnQgeyBNYXRyaXg0IH0gZnJvbSAnLi4vbWF0aC9NYXRyaXg0LmpzJztcclxuaW1wb3J0IHsgU3BoZXJlIH0gZnJvbSAnLi4vbWF0aC9TcGhlcmUuanMnO1xyXG5cclxuY29uc3QgX2luc3RhbmNlTG9jYWxNYXRyaXggPSAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXg0KCk7XHJcbmNvbnN0IF9pbnN0YW5jZVdvcmxkTWF0cml4ID0gLypAX19QVVJFX18qLyBuZXcgTWF0cml4NCgpO1xyXG5cclxuY29uc3QgX2luc3RhbmNlSW50ZXJzZWN0cyA9IFtdO1xyXG5cclxuY29uc3QgX2JveDMgPSAvKkBfX1BVUkVfXyovIG5ldyBCb3gzKCk7XHJcbmNvbnN0IF9pZGVudGl0eSA9IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDQoKTtcclxuY29uc3QgX21lc2ggPSAvKkBfX1BVUkVfXyovIG5ldyBNZXNoKCk7XHJcbmNvbnN0IF9zcGhlcmUgPSAvKkBfX1BVUkVfXyovIG5ldyBTcGhlcmUoKTtcclxuXHJcbmNsYXNzIEluc3RhbmNlZE1lc2ggZXh0ZW5kcyBNZXNoIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIGdlb21ldHJ5LCBtYXRlcmlhbCwgY291bnQgKSB7XHJcblxyXG5cdFx0c3VwZXIoIGdlb21ldHJ5LCBtYXRlcmlhbCApO1xyXG5cclxuXHRcdHRoaXMuaXNJbnN0YW5jZWRNZXNoID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLmluc3RhbmNlTWF0cml4ID0gbmV3IEluc3RhbmNlZEJ1ZmZlckF0dHJpYnV0ZSggbmV3IEZsb2F0MzJBcnJheSggY291bnQgKiAxNiApLCAxNiApO1xyXG5cdFx0dGhpcy5pbnN0YW5jZUNvbG9yID0gbnVsbDtcclxuXHJcblx0XHR0aGlzLmNvdW50ID0gY291bnQ7XHJcblxyXG5cdFx0dGhpcy5ib3VuZGluZ0JveCA9IG51bGw7XHJcblx0XHR0aGlzLmJvdW5kaW5nU3BoZXJlID0gbnVsbDtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBjb3VudDsgaSArKyApIHtcclxuXHJcblx0XHRcdHRoaXMuc2V0TWF0cml4QXQoIGksIF9pZGVudGl0eSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRjb21wdXRlQm91bmRpbmdCb3goKSB7XHJcblxyXG5cdFx0Y29uc3QgZ2VvbWV0cnkgPSB0aGlzLmdlb21ldHJ5O1xyXG5cdFx0Y29uc3QgY291bnQgPSB0aGlzLmNvdW50O1xyXG5cclxuXHRcdGlmICggdGhpcy5ib3VuZGluZ0JveCA9PT0gbnVsbCApIHtcclxuXHJcblx0XHRcdHRoaXMuYm91bmRpbmdCb3ggPSBuZXcgQm94MygpO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIGdlb21ldHJ5LmJvdW5kaW5nQm94ID09PSBudWxsICkge1xyXG5cclxuXHRcdFx0Z2VvbWV0cnkuY29tcHV0ZUJvdW5kaW5nQm94KCk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMuYm91bmRpbmdCb3gubWFrZUVtcHR5KCk7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgY291bnQ7IGkgKysgKSB7XHJcblxyXG5cdFx0XHR0aGlzLmdldE1hdHJpeEF0KCBpLCBfaW5zdGFuY2VMb2NhbE1hdHJpeCApO1xyXG5cclxuXHRcdFx0X2JveDMuY29weSggZ2VvbWV0cnkuYm91bmRpbmdCb3ggKS5hcHBseU1hdHJpeDQoIF9pbnN0YW5jZUxvY2FsTWF0cml4ICk7XHJcblxyXG5cdFx0XHR0aGlzLmJvdW5kaW5nQm94LnVuaW9uKCBfYm94MyApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRjb21wdXRlQm91bmRpbmdTcGhlcmUoKSB7XHJcblxyXG5cdFx0Y29uc3QgZ2VvbWV0cnkgPSB0aGlzLmdlb21ldHJ5O1xyXG5cdFx0Y29uc3QgY291bnQgPSB0aGlzLmNvdW50O1xyXG5cclxuXHRcdGlmICggdGhpcy5ib3VuZGluZ1NwaGVyZSA9PT0gbnVsbCApIHtcclxuXHJcblx0XHRcdHRoaXMuYm91bmRpbmdTcGhlcmUgPSBuZXcgU3BoZXJlKCk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggZ2VvbWV0cnkuYm91bmRpbmdTcGhlcmUgPT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRnZW9tZXRyeS5jb21wdXRlQm91bmRpbmdTcGhlcmUoKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5ib3VuZGluZ1NwaGVyZS5tYWtlRW1wdHkoKTtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBjb3VudDsgaSArKyApIHtcclxuXHJcblx0XHRcdHRoaXMuZ2V0TWF0cml4QXQoIGksIF9pbnN0YW5jZUxvY2FsTWF0cml4ICk7XHJcblxyXG5cdFx0XHRfc3BoZXJlLmNvcHkoIGdlb21ldHJ5LmJvdW5kaW5nU3BoZXJlICkuYXBwbHlNYXRyaXg0KCBfaW5zdGFuY2VMb2NhbE1hdHJpeCApO1xyXG5cclxuXHRcdFx0dGhpcy5ib3VuZGluZ1NwaGVyZS51bmlvbiggX3NwaGVyZSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRjb3B5KCBzb3VyY2UsIHJlY3Vyc2l2ZSApIHtcclxuXHJcblx0XHRzdXBlci5jb3B5KCBzb3VyY2UsIHJlY3Vyc2l2ZSApO1xyXG5cclxuXHRcdHRoaXMuaW5zdGFuY2VNYXRyaXguY29weSggc291cmNlLmluc3RhbmNlTWF0cml4ICk7XHJcblxyXG5cdFx0aWYgKCBzb3VyY2UuaW5zdGFuY2VDb2xvciAhPT0gbnVsbCApIHRoaXMuaW5zdGFuY2VDb2xvciA9IHNvdXJjZS5pbnN0YW5jZUNvbG9yLmNsb25lKCk7XHJcblxyXG5cdFx0dGhpcy5jb3VudCA9IHNvdXJjZS5jb3VudDtcclxuXHJcblx0XHRpZiAoIHNvdXJjZS5ib3VuZGluZ0JveCAhPT0gbnVsbCApIHRoaXMuYm91bmRpbmdCb3ggPSBzb3VyY2UuYm91bmRpbmdCb3guY2xvbmUoKTtcclxuXHRcdGlmICggc291cmNlLmJvdW5kaW5nU3BoZXJlICE9PSBudWxsICkgdGhpcy5ib3VuZGluZ1NwaGVyZSA9IHNvdXJjZS5ib3VuZGluZ1NwaGVyZS5jbG9uZSgpO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldENvbG9yQXQoIGluZGV4LCBjb2xvciApIHtcclxuXHJcblx0XHRjb2xvci5mcm9tQXJyYXkoIHRoaXMuaW5zdGFuY2VDb2xvci5hcnJheSwgaW5kZXggKiAzICk7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0TWF0cml4QXQoIGluZGV4LCBtYXRyaXggKSB7XHJcblxyXG5cdFx0bWF0cml4LmZyb21BcnJheSggdGhpcy5pbnN0YW5jZU1hdHJpeC5hcnJheSwgaW5kZXggKiAxNiApO1xyXG5cclxuXHR9XHJcblxyXG5cdHJheWNhc3QoIHJheWNhc3RlciwgaW50ZXJzZWN0cyApIHtcclxuXHJcblx0XHRjb25zdCBtYXRyaXhXb3JsZCA9IHRoaXMubWF0cml4V29ybGQ7XHJcblx0XHRjb25zdCByYXljYXN0VGltZXMgPSB0aGlzLmNvdW50O1xyXG5cclxuXHRcdF9tZXNoLmdlb21ldHJ5ID0gdGhpcy5nZW9tZXRyeTtcclxuXHRcdF9tZXNoLm1hdGVyaWFsID0gdGhpcy5tYXRlcmlhbDtcclxuXHJcblx0XHRpZiAoIF9tZXNoLm1hdGVyaWFsID09PSB1bmRlZmluZWQgKSByZXR1cm47XHJcblxyXG5cdFx0Ly8gdGVzdCB3aXRoIGJvdW5kaW5nIHNwaGVyZSBmaXJzdFxyXG5cclxuXHRcdGlmICggdGhpcy5ib3VuZGluZ1NwaGVyZSA9PT0gbnVsbCApIHRoaXMuY29tcHV0ZUJvdW5kaW5nU3BoZXJlKCk7XHJcblxyXG5cdFx0X3NwaGVyZS5jb3B5KCB0aGlzLmJvdW5kaW5nU3BoZXJlICk7XHJcblx0XHRfc3BoZXJlLmFwcGx5TWF0cml4NCggbWF0cml4V29ybGQgKTtcclxuXHJcblx0XHRpZiAoIHJheWNhc3Rlci5yYXkuaW50ZXJzZWN0c1NwaGVyZSggX3NwaGVyZSApID09PSBmYWxzZSApIHJldHVybjtcclxuXHJcblx0XHQvLyBub3cgdGVzdCBlYWNoIGluc3RhbmNlXHJcblxyXG5cdFx0Zm9yICggbGV0IGluc3RhbmNlSWQgPSAwOyBpbnN0YW5jZUlkIDwgcmF5Y2FzdFRpbWVzOyBpbnN0YW5jZUlkICsrICkge1xyXG5cclxuXHRcdFx0Ly8gY2FsY3VsYXRlIHRoZSB3b3JsZCBtYXRyaXggZm9yIGVhY2ggaW5zdGFuY2VcclxuXHJcblx0XHRcdHRoaXMuZ2V0TWF0cml4QXQoIGluc3RhbmNlSWQsIF9pbnN0YW5jZUxvY2FsTWF0cml4ICk7XHJcblxyXG5cdFx0XHRfaW5zdGFuY2VXb3JsZE1hdHJpeC5tdWx0aXBseU1hdHJpY2VzKCBtYXRyaXhXb3JsZCwgX2luc3RhbmNlTG9jYWxNYXRyaXggKTtcclxuXHJcblx0XHRcdC8vIHRoZSBtZXNoIHJlcHJlc2VudHMgdGhpcyBzaW5nbGUgaW5zdGFuY2VcclxuXHJcblx0XHRcdF9tZXNoLm1hdHJpeFdvcmxkID0gX2luc3RhbmNlV29ybGRNYXRyaXg7XHJcblxyXG5cdFx0XHRfbWVzaC5yYXljYXN0KCByYXljYXN0ZXIsIF9pbnN0YW5jZUludGVyc2VjdHMgKTtcclxuXHJcblx0XHRcdC8vIHByb2Nlc3MgdGhlIHJlc3VsdCBvZiByYXljYXN0XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBfaW5zdGFuY2VJbnRlcnNlY3RzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IGludGVyc2VjdCA9IF9pbnN0YW5jZUludGVyc2VjdHNbIGkgXTtcclxuXHRcdFx0XHRpbnRlcnNlY3QuaW5zdGFuY2VJZCA9IGluc3RhbmNlSWQ7XHJcblx0XHRcdFx0aW50ZXJzZWN0Lm9iamVjdCA9IHRoaXM7XHJcblx0XHRcdFx0aW50ZXJzZWN0cy5wdXNoKCBpbnRlcnNlY3QgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdF9pbnN0YW5jZUludGVyc2VjdHMubGVuZ3RoID0gMDtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0c2V0Q29sb3JBdCggaW5kZXgsIGNvbG9yICkge1xyXG5cclxuXHRcdGlmICggdGhpcy5pbnN0YW5jZUNvbG9yID09PSBudWxsICkge1xyXG5cclxuXHRcdFx0dGhpcy5pbnN0YW5jZUNvbG9yID0gbmV3IEluc3RhbmNlZEJ1ZmZlckF0dHJpYnV0ZSggbmV3IEZsb2F0MzJBcnJheSggdGhpcy5pbnN0YW5jZU1hdHJpeC5jb3VudCAqIDMgKSwgMyApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb2xvci50b0FycmF5KCB0aGlzLmluc3RhbmNlQ29sb3IuYXJyYXksIGluZGV4ICogMyApO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldE1hdHJpeEF0KCBpbmRleCwgbWF0cml4ICkge1xyXG5cclxuXHRcdG1hdHJpeC50b0FycmF5KCB0aGlzLmluc3RhbmNlTWF0cml4LmFycmF5LCBpbmRleCAqIDE2ICk7XHJcblxyXG5cdH1cclxuXHJcblx0dXBkYXRlTW9ycGhUYXJnZXRzKCkge1xyXG5cclxuXHR9XHJcblxyXG5cdGRpc3Bvc2UoKSB7XHJcblxyXG5cdFx0dGhpcy5kaXNwYXRjaEV2ZW50KCB7IHR5cGU6ICdkaXNwb3NlJyB9ICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IEluc3RhbmNlZE1lc2ggfTtcclxuIiwiaW1wb3J0IHsgQnVmZmVyQXR0cmlidXRlIH0gZnJvbSAnLi4vY29yZS9CdWZmZXJBdHRyaWJ1dGUuanMnO1xyXG5pbXBvcnQgeyBCdWZmZXJHZW9tZXRyeSB9IGZyb20gJy4uL2NvcmUvQnVmZmVyR2VvbWV0cnkuanMnO1xyXG5pbXBvcnQgeyBEYXRhVGV4dHVyZSB9IGZyb20gJy4uL3RleHR1cmVzL0RhdGFUZXh0dXJlLmpzJztcclxuaW1wb3J0IHsgRmxvYXRUeXBlIH0gZnJvbSAnLi4vY29uc3RhbnRzLmpzJztcclxuaW1wb3J0IHsgTWF0cml4NCB9IGZyb20gJy4uL21hdGgvTWF0cml4NC5qcyc7XHJcbmltcG9ydCB7IE1lc2ggfSBmcm9tICcuL01lc2guanMnO1xyXG5pbXBvcnQgeyBSR0JBRm9ybWF0IH0gZnJvbSAnLi4vY29uc3RhbnRzLmpzJztcclxuaW1wb3J0IHsgQm94MyB9IGZyb20gJy4uL21hdGgvQm94My5qcyc7XHJcbmltcG9ydCB7IFNwaGVyZSB9IGZyb20gJy4uL21hdGgvU3BoZXJlLmpzJztcclxuaW1wb3J0IHsgRnJ1c3R1bSB9IGZyb20gJy4uL21hdGgvRnJ1c3R1bS5qcyc7XHJcbmltcG9ydCB7IFZlY3RvcjMgfSBmcm9tICcuLi9tYXRoL1ZlY3RvcjMuanMnO1xyXG5cclxuZnVuY3Rpb24gc29ydE9wYXF1ZSggYSwgYiApIHtcclxuXHJcblx0cmV0dXJuIGEueiAtIGIuejtcclxuXHJcbn1cclxuXHJcbmZ1bmN0aW9uIHNvcnRUcmFuc3BhcmVudCggYSwgYiApIHtcclxuXHJcblx0cmV0dXJuIGIueiAtIGEuejtcclxuXHJcbn1cclxuXHJcbmNsYXNzIE11bHRpRHJhd1JlbmRlckxpc3Qge1xyXG5cclxuXHRjb25zdHJ1Y3RvcigpIHtcclxuXHJcblx0XHR0aGlzLmluZGV4ID0gMDtcclxuXHRcdHRoaXMucG9vbCA9IFtdO1xyXG5cdFx0dGhpcy5saXN0ID0gW107XHJcblxyXG5cdH1cclxuXHJcblx0cHVzaCggZHJhd1JhbmdlLCB6ICkge1xyXG5cclxuXHRcdGNvbnN0IHBvb2wgPSB0aGlzLnBvb2w7XHJcblx0XHRjb25zdCBsaXN0ID0gdGhpcy5saXN0O1xyXG5cdFx0aWYgKCB0aGlzLmluZGV4ID49IHBvb2wubGVuZ3RoICkge1xyXG5cclxuXHRcdFx0cG9vbC5wdXNoKCB7XHJcblxyXG5cdFx0XHRcdHN0YXJ0OiAtIDEsXHJcblx0XHRcdFx0Y291bnQ6IC0gMSxcclxuXHRcdFx0XHR6OiAtIDEsXHJcblxyXG5cdFx0XHR9ICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGNvbnN0IGl0ZW0gPSBwb29sWyB0aGlzLmluZGV4IF07XHJcblx0XHRsaXN0LnB1c2goIGl0ZW0gKTtcclxuXHRcdHRoaXMuaW5kZXggKys7XHJcblxyXG5cdFx0aXRlbS5zdGFydCA9IGRyYXdSYW5nZS5zdGFydDtcclxuXHRcdGl0ZW0uY291bnQgPSBkcmF3UmFuZ2UuY291bnQ7XHJcblx0XHRpdGVtLnogPSB6O1xyXG5cclxuXHR9XHJcblxyXG5cdHJlc2V0KCkge1xyXG5cclxuXHRcdHRoaXMubGlzdC5sZW5ndGggPSAwO1xyXG5cdFx0dGhpcy5pbmRleCA9IDA7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmNvbnN0IElEX0FUVFJfTkFNRSA9ICdiYXRjaElkJztcclxuY29uc3QgX21hdHJpeCA9IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDQoKTtcclxuY29uc3QgX2ludk1hdHJpeFdvcmxkID0gLypAX19QVVJFX18qLyBuZXcgTWF0cml4NCgpO1xyXG5jb25zdCBfaWRlbnRpdHlNYXRyaXggPSAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXg0KCk7XHJcbmNvbnN0IF9wcm9qU2NyZWVuTWF0cml4ID0gLypAX19QVVJFX18qLyBuZXcgTWF0cml4NCgpO1xyXG5jb25zdCBfZnJ1c3R1bSA9IC8qQF9fUFVSRV9fKi8gbmV3IEZydXN0dW0oKTtcclxuY29uc3QgX2JveCA9IC8qQF9fUFVSRV9fKi8gbmV3IEJveDMoKTtcclxuY29uc3QgX3NwaGVyZSA9IC8qQF9fUFVSRV9fKi8gbmV3IFNwaGVyZSgpO1xyXG5jb25zdCBfdmVjdG9yID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5jb25zdCBfcmVuZGVyTGlzdCA9IC8qQF9fUFVSRV9fKi8gbmV3IE11bHRpRHJhd1JlbmRlckxpc3QoKTtcclxuY29uc3QgX21lc2ggPSAvKkBfX1BVUkVfXyovIG5ldyBNZXNoKCk7XHJcbmNvbnN0IF9iYXRjaEludGVyc2VjdHMgPSBbXTtcclxuXHJcbi8vIEBUT0RPOiBTa2lubmVkTWVzaCBzdXBwb3J0P1xyXG4vLyBAVE9ETzogZ2VvbWV0cnkuZ3JvdXBzIHN1cHBvcnQ/XHJcbi8vIEBUT0RPOiBnZW9tZXRyeS5kcmF3UmFuZ2Ugc3VwcG9ydD9cclxuLy8gQFRPRE86IGdlb21ldHJ5Lm1vcnBoQXR0cmlidXRlcyBzdXBwb3J0P1xyXG4vLyBAVE9ETzogU3VwcG9ydCB1bmlmb3JtIHBhcmFtZXRlciBwZXIgZ2VvbWV0cnlcclxuLy8gQFRPRE86IEFkZCBhbiBcIm9wdGltaXplXCIgZnVuY3Rpb24gdG8gcGFjayBnZW9tZXRyeSBhbmQgcmVtb3ZlIGRhdGEgZ2Fwc1xyXG5cclxuLy8gY29waWVzIGRhdGEgZnJvbSBhdHRyaWJ1dGUgXCJzcmNcIiBpbnRvIFwidGFyZ2V0XCIgc3RhcnRpbmcgYXQgXCJ0YXJnZXRPZmZzZXRcIlxyXG5mdW5jdGlvbiBjb3B5QXR0cmlidXRlRGF0YSggc3JjLCB0YXJnZXQsIHRhcmdldE9mZnNldCA9IDAgKSB7XHJcblxyXG5cdGNvbnN0IGl0ZW1TaXplID0gdGFyZ2V0Lml0ZW1TaXplO1xyXG5cdGlmICggc3JjLmlzSW50ZXJsZWF2ZWRCdWZmZXJBdHRyaWJ1dGUgfHwgc3JjLmFycmF5LmNvbnN0cnVjdG9yICE9PSB0YXJnZXQuYXJyYXkuY29uc3RydWN0b3IgKSB7XHJcblxyXG5cdFx0Ly8gdXNlIHRoZSBjb21wb25lbnQgZ2V0dGVycyBhbmQgc2V0dGVycyBpZiB0aGUgYXJyYXkgZGF0YSBjYW5ub3RcclxuXHRcdC8vIGJlIGNvcGllZCBkaXJlY3RseVxyXG5cdFx0Y29uc3QgdmVydGV4Q291bnQgPSBzcmMuY291bnQ7XHJcblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCB2ZXJ0ZXhDb3VudDsgaSArKyApIHtcclxuXHJcblx0XHRcdGZvciAoIGxldCBjID0gMDsgYyA8IGl0ZW1TaXplOyBjICsrICkge1xyXG5cclxuXHRcdFx0XHR0YXJnZXQuc2V0Q29tcG9uZW50KCBpICsgdGFyZ2V0T2Zmc2V0LCBjLCBzcmMuZ2V0Q29tcG9uZW50KCBpLCBjICkgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdH0gZWxzZSB7XHJcblxyXG5cdFx0Ly8gZmFzdGVyIGNvcHkgYXBwcm9hY2ggdXNpbmcgdHlwZWQgYXJyYXkgc2V0IGZ1bmN0aW9uXHJcblx0XHR0YXJnZXQuYXJyYXkuc2V0KCBzcmMuYXJyYXksIHRhcmdldE9mZnNldCAqIGl0ZW1TaXplICk7XHJcblxyXG5cdH1cclxuXHJcblx0dGFyZ2V0Lm5lZWRzVXBkYXRlID0gdHJ1ZTtcclxuXHJcbn1cclxuXHJcbmNsYXNzIEJhdGNoZWRNZXNoIGV4dGVuZHMgTWVzaCB7XHJcblxyXG5cdGdldCBtYXhHZW9tZXRyeUNvdW50KCkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLl9tYXhHZW9tZXRyeUNvdW50O1xyXG5cclxuXHR9XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBtYXhHZW9tZXRyeUNvdW50LCBtYXhWZXJ0ZXhDb3VudCwgbWF4SW5kZXhDb3VudCA9IG1heFZlcnRleENvdW50ICogMiwgbWF0ZXJpYWwgKSB7XHJcblxyXG5cdFx0c3VwZXIoIG5ldyBCdWZmZXJHZW9tZXRyeSgpLCBtYXRlcmlhbCApO1xyXG5cclxuXHRcdHRoaXMuaXNCYXRjaGVkTWVzaCA9IHRydWU7XHJcblx0XHR0aGlzLnBlck9iamVjdEZydXN0dW1DdWxsZWQgPSB0cnVlO1xyXG5cdFx0dGhpcy5zb3J0T2JqZWN0cyA9IHRydWU7XHJcblx0XHR0aGlzLmJvdW5kaW5nQm94ID0gbnVsbDtcclxuXHRcdHRoaXMuYm91bmRpbmdTcGhlcmUgPSBudWxsO1xyXG5cdFx0dGhpcy5jdXN0b21Tb3J0ID0gbnVsbDtcclxuXHJcblx0XHR0aGlzLl9kcmF3UmFuZ2VzID0gW107XHJcblx0XHR0aGlzLl9yZXNlcnZlZFJhbmdlcyA9IFtdO1xyXG5cclxuXHRcdHRoaXMuX3Zpc2liaWxpdHkgPSBbXTtcclxuXHRcdHRoaXMuX2FjdGl2ZSA9IFtdO1xyXG5cdFx0dGhpcy5fYm91bmRzID0gW107XHJcblxyXG5cdFx0dGhpcy5fbWF4R2VvbWV0cnlDb3VudCA9IG1heEdlb21ldHJ5Q291bnQ7XHJcblx0XHR0aGlzLl9tYXhWZXJ0ZXhDb3VudCA9IG1heFZlcnRleENvdW50O1xyXG5cdFx0dGhpcy5fbWF4SW5kZXhDb3VudCA9IG1heEluZGV4Q291bnQ7XHJcblxyXG5cdFx0dGhpcy5fZ2VvbWV0cnlJbml0aWFsaXplZCA9IGZhbHNlO1xyXG5cdFx0dGhpcy5fZ2VvbWV0cnlDb3VudCA9IDA7XHJcblx0XHR0aGlzLl9tdWx0aURyYXdDb3VudHMgPSBuZXcgSW50MzJBcnJheSggbWF4R2VvbWV0cnlDb3VudCApO1xyXG5cdFx0dGhpcy5fbXVsdGlEcmF3U3RhcnRzID0gbmV3IEludDMyQXJyYXkoIG1heEdlb21ldHJ5Q291bnQgKTtcclxuXHRcdHRoaXMuX211bHRpRHJhd0NvdW50ID0gMDtcclxuXHRcdHRoaXMuX3Zpc2liaWxpdHlDaGFuZ2VkID0gdHJ1ZTtcclxuXHJcblx0XHQvLyBMb2NhbCBtYXRyaXggcGVyIGdlb21ldHJ5IGJ5IHVzaW5nIGRhdGEgdGV4dHVyZVxyXG5cdFx0dGhpcy5fbWF0cmljZXNUZXh0dXJlID0gbnVsbDtcclxuXHJcblx0XHR0aGlzLl9pbml0TWF0cmljZXNUZXh0dXJlKCk7XHJcblxyXG5cdH1cclxuXHJcblx0X2luaXRNYXRyaWNlc1RleHR1cmUoKSB7XHJcblxyXG5cdFx0Ly8gbGF5b3V0ICgxIG1hdHJpeCA9IDQgcGl4ZWxzKVxyXG5cdFx0Ly8gICAgICBSR0JBIFJHQkEgUkdCQSBSR0JBICg9PiBjb2x1bW4xLCBjb2x1bW4yLCBjb2x1bW4zLCBjb2x1bW40KVxyXG5cdFx0Ly8gIHdpdGggIDh4OCAgcGl4ZWwgdGV4dHVyZSBtYXggICAxNiBtYXRyaWNlcyAqIDQgcGl4ZWxzID0gICg4ICogOClcclxuXHRcdC8vICAgICAgIDE2eDE2IHBpeGVsIHRleHR1cmUgbWF4ICAgNjQgbWF0cmljZXMgKiA0IHBpeGVscyA9ICgxNiAqIDE2KVxyXG5cdFx0Ly8gICAgICAgMzJ4MzIgcGl4ZWwgdGV4dHVyZSBtYXggIDI1NiBtYXRyaWNlcyAqIDQgcGl4ZWxzID0gKDMyICogMzIpXHJcblx0XHQvLyAgICAgICA2NHg2NCBwaXhlbCB0ZXh0dXJlIG1heCAxMDI0IG1hdHJpY2VzICogNCBwaXhlbHMgPSAoNjQgKiA2NClcclxuXHJcblx0XHRsZXQgc2l6ZSA9IE1hdGguc3FydCggdGhpcy5fbWF4R2VvbWV0cnlDb3VudCAqIDQgKTsgLy8gNCBwaXhlbHMgbmVlZGVkIGZvciAxIG1hdHJpeFxyXG5cdFx0c2l6ZSA9IE1hdGguY2VpbCggc2l6ZSAvIDQgKSAqIDQ7XHJcblx0XHRzaXplID0gTWF0aC5tYXgoIHNpemUsIDQgKTtcclxuXHJcblx0XHRjb25zdCBtYXRyaWNlc0FycmF5ID0gbmV3IEZsb2F0MzJBcnJheSggc2l6ZSAqIHNpemUgKiA0ICk7IC8vIDQgZmxvYXRzIHBlciBSR0JBIHBpeGVsXHJcblx0XHRjb25zdCBtYXRyaWNlc1RleHR1cmUgPSBuZXcgRGF0YVRleHR1cmUoIG1hdHJpY2VzQXJyYXksIHNpemUsIHNpemUsIFJHQkFGb3JtYXQsIEZsb2F0VHlwZSApO1xyXG5cclxuXHRcdHRoaXMuX21hdHJpY2VzVGV4dHVyZSA9IG1hdHJpY2VzVGV4dHVyZTtcclxuXHJcblx0fVxyXG5cclxuXHRfaW5pdGlhbGl6ZUdlb21ldHJ5KCByZWZlcmVuY2UgKSB7XHJcblxyXG5cdFx0Y29uc3QgZ2VvbWV0cnkgPSB0aGlzLmdlb21ldHJ5O1xyXG5cdFx0Y29uc3QgbWF4VmVydGV4Q291bnQgPSB0aGlzLl9tYXhWZXJ0ZXhDb3VudDtcclxuXHRcdGNvbnN0IG1heEdlb21ldHJ5Q291bnQgPSB0aGlzLl9tYXhHZW9tZXRyeUNvdW50O1xyXG5cdFx0Y29uc3QgbWF4SW5kZXhDb3VudCA9IHRoaXMuX21heEluZGV4Q291bnQ7XHJcblx0XHRpZiAoIHRoaXMuX2dlb21ldHJ5SW5pdGlhbGl6ZWQgPT09IGZhbHNlICkge1xyXG5cclxuXHRcdFx0Zm9yICggY29uc3QgYXR0cmlidXRlTmFtZSBpbiByZWZlcmVuY2UuYXR0cmlidXRlcyApIHtcclxuXHJcblx0XHRcdFx0Y29uc3Qgc3JjQXR0cmlidXRlID0gcmVmZXJlbmNlLmdldEF0dHJpYnV0ZSggYXR0cmlidXRlTmFtZSApO1xyXG5cdFx0XHRcdGNvbnN0IHsgYXJyYXksIGl0ZW1TaXplLCBub3JtYWxpemVkIH0gPSBzcmNBdHRyaWJ1dGU7XHJcblxyXG5cdFx0XHRcdGNvbnN0IGRzdEFycmF5ID0gbmV3IGFycmF5LmNvbnN0cnVjdG9yKCBtYXhWZXJ0ZXhDb3VudCAqIGl0ZW1TaXplICk7XHJcblx0XHRcdFx0Y29uc3QgZHN0QXR0cmlidXRlID0gbmV3IHNyY0F0dHJpYnV0ZS5jb25zdHJ1Y3RvciggZHN0QXJyYXksIGl0ZW1TaXplLCBub3JtYWxpemVkICk7XHJcblx0XHRcdFx0ZHN0QXR0cmlidXRlLnNldFVzYWdlKCBzcmNBdHRyaWJ1dGUudXNhZ2UgKTtcclxuXHJcblx0XHRcdFx0Z2VvbWV0cnkuc2V0QXR0cmlidXRlKCBhdHRyaWJ1dGVOYW1lLCBkc3RBdHRyaWJ1dGUgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGlmICggcmVmZXJlbmNlLmdldEluZGV4KCkgIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IGluZGV4QXJyYXkgPSBtYXhWZXJ0ZXhDb3VudCA+IDY1NTM2XHJcblx0XHRcdFx0XHQ/IG5ldyBVaW50MzJBcnJheSggbWF4SW5kZXhDb3VudCApXHJcblx0XHRcdFx0XHQ6IG5ldyBVaW50MTZBcnJheSggbWF4SW5kZXhDb3VudCApO1xyXG5cclxuXHRcdFx0XHRnZW9tZXRyeS5zZXRJbmRleCggbmV3IEJ1ZmZlckF0dHJpYnV0ZSggaW5kZXhBcnJheSwgMSApICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRjb25zdCBpZEFycmF5ID0gbWF4R2VvbWV0cnlDb3VudCA+IDY1NTM2XHJcblx0XHRcdFx0PyBuZXcgVWludDMyQXJyYXkoIG1heFZlcnRleENvdW50IClcclxuXHRcdFx0XHQ6IG5ldyBVaW50MTZBcnJheSggbWF4VmVydGV4Q291bnQgKTtcclxuXHRcdFx0Z2VvbWV0cnkuc2V0QXR0cmlidXRlKCBJRF9BVFRSX05BTUUsIG5ldyBCdWZmZXJBdHRyaWJ1dGUoIGlkQXJyYXksIDEgKSApO1xyXG5cclxuXHRcdFx0dGhpcy5fZ2VvbWV0cnlJbml0aWFsaXplZCA9IHRydWU7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdC8vIE1ha2Ugc3VyZSB0aGUgZ2VvbWV0cnkgaXMgY29tcGF0aWJsZSB3aXRoIHRoZSBleGlzdGluZyBjb21iaW5lZCBnZW9tZXRyeSBhdHJpYnV0ZXNcclxuXHRfdmFsaWRhdGVHZW9tZXRyeSggZ2VvbWV0cnkgKSB7XHJcblxyXG5cdFx0Ly8gY2hlY2sgdGhhdCB0aGUgZ2VvbWV0cnkgZG9lc24ndCBoYXZlIGEgdmVyc2lvbiBvZiBvdXIgcmVzZXJ2ZWQgaWQgYXR0cmlidXRlXHJcblx0XHRpZiAoIGdlb21ldHJ5LmdldEF0dHJpYnV0ZSggSURfQVRUUl9OQU1FICkgKSB7XHJcblxyXG5cdFx0XHR0aHJvdyBuZXcgRXJyb3IoIGBCYXRjaGVkTWVzaDogR2VvbWV0cnkgY2Fubm90IHVzZSBhdHRyaWJ1dGUgXCIkeyBJRF9BVFRSX05BTUUgfVwiYCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvLyBjaGVjayB0byBlbnN1cmUgdGhlIGdlb21ldHJpZXMgYXJlIHVzaW5nIGNvbnNpc3RlbnQgYXR0cmlidXRlcyBhbmQgaW5kaWNlc1xyXG5cdFx0Y29uc3QgYmF0Y2hHZW9tZXRyeSA9IHRoaXMuZ2VvbWV0cnk7XHJcblx0XHRpZiAoIEJvb2xlYW4oIGdlb21ldHJ5LmdldEluZGV4KCkgKSAhPT0gQm9vbGVhbiggYmF0Y2hHZW9tZXRyeS5nZXRJbmRleCgpICkgKSB7XHJcblxyXG5cdFx0XHR0aHJvdyBuZXcgRXJyb3IoICdCYXRjaGVkTWVzaDogQWxsIGdlb21ldHJpZXMgbXVzdCBjb25zaXN0ZW50bHkgaGF2ZSBcImluZGV4XCIuJyApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRmb3IgKCBjb25zdCBhdHRyaWJ1dGVOYW1lIGluIGJhdGNoR2VvbWV0cnkuYXR0cmlidXRlcyApIHtcclxuXHJcblx0XHRcdGlmICggYXR0cmlidXRlTmFtZSA9PT0gSURfQVRUUl9OQU1FICkge1xyXG5cclxuXHRcdFx0XHRjb250aW51ZTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGlmICggISBnZW9tZXRyeS5oYXNBdHRyaWJ1dGUoIGF0dHJpYnV0ZU5hbWUgKSApIHtcclxuXHJcblx0XHRcdFx0dGhyb3cgbmV3IEVycm9yKCBgQmF0Y2hlZE1lc2g6IEFkZGVkIGdlb21ldHJ5IG1pc3NpbmcgXCIkeyBhdHRyaWJ1dGVOYW1lIH1cIi4gQWxsIGdlb21ldHJpZXMgbXVzdCBoYXZlIGNvbnNpc3RlbnQgYXR0cmlidXRlcy5gICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRjb25zdCBzcmNBdHRyaWJ1dGUgPSBnZW9tZXRyeS5nZXRBdHRyaWJ1dGUoIGF0dHJpYnV0ZU5hbWUgKTtcclxuXHRcdFx0Y29uc3QgZHN0QXR0cmlidXRlID0gYmF0Y2hHZW9tZXRyeS5nZXRBdHRyaWJ1dGUoIGF0dHJpYnV0ZU5hbWUgKTtcclxuXHRcdFx0aWYgKCBzcmNBdHRyaWJ1dGUuaXRlbVNpemUgIT09IGRzdEF0dHJpYnV0ZS5pdGVtU2l6ZSB8fCBzcmNBdHRyaWJ1dGUubm9ybWFsaXplZCAhPT0gZHN0QXR0cmlidXRlLm5vcm1hbGl6ZWQgKSB7XHJcblxyXG5cdFx0XHRcdHRocm93IG5ldyBFcnJvciggJ0JhdGNoZWRNZXNoOiBBbGwgYXR0cmlidXRlcyBtdXN0IGhhdmUgYSBjb25zaXN0ZW50IGl0ZW1TaXplIGFuZCBub3JtYWxpemVkIHZhbHVlLicgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0c2V0Q3VzdG9tU29ydCggZnVuYyApIHtcclxuXHJcblx0XHR0aGlzLmN1c3RvbVNvcnQgPSBmdW5jO1xyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Y29tcHV0ZUJvdW5kaW5nQm94KCkge1xyXG5cclxuXHRcdGlmICggdGhpcy5ib3VuZGluZ0JveCA9PT0gbnVsbCApIHtcclxuXHJcblx0XHRcdHRoaXMuYm91bmRpbmdCb3ggPSBuZXcgQm94MygpO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCBnZW9tZXRyeUNvdW50ID0gdGhpcy5fZ2VvbWV0cnlDb3VudDtcclxuXHRcdGNvbnN0IGJvdW5kaW5nQm94ID0gdGhpcy5ib3VuZGluZ0JveDtcclxuXHRcdGNvbnN0IGFjdGl2ZSA9IHRoaXMuX2FjdGl2ZTtcclxuXHJcblx0XHRib3VuZGluZ0JveC5tYWtlRW1wdHkoKTtcclxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IGdlb21ldHJ5Q291bnQ7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRpZiAoIGFjdGl2ZVsgaSBdID09PSBmYWxzZSApIGNvbnRpbnVlO1xyXG5cclxuXHRcdFx0dGhpcy5nZXRNYXRyaXhBdCggaSwgX21hdHJpeCApO1xyXG5cdFx0XHR0aGlzLmdldEJvdW5kaW5nQm94QXQoIGksIF9ib3ggKS5hcHBseU1hdHJpeDQoIF9tYXRyaXggKTtcclxuXHRcdFx0Ym91bmRpbmdCb3gudW5pb24oIF9ib3ggKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0Y29tcHV0ZUJvdW5kaW5nU3BoZXJlKCkge1xyXG5cclxuXHRcdGlmICggdGhpcy5ib3VuZGluZ1NwaGVyZSA9PT0gbnVsbCApIHtcclxuXHJcblx0XHRcdHRoaXMuYm91bmRpbmdTcGhlcmUgPSBuZXcgU3BoZXJlKCk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGNvbnN0IGdlb21ldHJ5Q291bnQgPSB0aGlzLl9nZW9tZXRyeUNvdW50O1xyXG5cdFx0Y29uc3QgYm91bmRpbmdTcGhlcmUgPSB0aGlzLmJvdW5kaW5nU3BoZXJlO1xyXG5cdFx0Y29uc3QgYWN0aXZlID0gdGhpcy5fYWN0aXZlO1xyXG5cclxuXHRcdGJvdW5kaW5nU3BoZXJlLm1ha2VFbXB0eSgpO1xyXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgZ2VvbWV0cnlDb3VudDsgaSArKyApIHtcclxuXHJcblx0XHRcdGlmICggYWN0aXZlWyBpIF0gPT09IGZhbHNlICkgY29udGludWU7XHJcblxyXG5cdFx0XHR0aGlzLmdldE1hdHJpeEF0KCBpLCBfbWF0cml4ICk7XHJcblx0XHRcdHRoaXMuZ2V0Qm91bmRpbmdTcGhlcmVBdCggaSwgX3NwaGVyZSApLmFwcGx5TWF0cml4NCggX21hdHJpeCApO1xyXG5cdFx0XHRib3VuZGluZ1NwaGVyZS51bmlvbiggX3NwaGVyZSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRhZGRHZW9tZXRyeSggZ2VvbWV0cnksIHZlcnRleENvdW50ID0gLSAxLCBpbmRleENvdW50ID0gLSAxICkge1xyXG5cclxuXHRcdHRoaXMuX2luaXRpYWxpemVHZW9tZXRyeSggZ2VvbWV0cnkgKTtcclxuXHJcblx0XHR0aGlzLl92YWxpZGF0ZUdlb21ldHJ5KCBnZW9tZXRyeSApO1xyXG5cclxuXHRcdC8vIGVuc3VyZSB3ZSdyZSBub3Qgb3ZlciBnZW9tZXRyeVxyXG5cdFx0aWYgKCB0aGlzLl9nZW9tZXRyeUNvdW50ID49IHRoaXMuX21heEdlb21ldHJ5Q291bnQgKSB7XHJcblxyXG5cdFx0XHR0aHJvdyBuZXcgRXJyb3IoICdCYXRjaGVkTWVzaDogTWF4aW11bSBnZW9tZXRyeSBjb3VudCByZWFjaGVkLicgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gZ2V0IHRoZSBuZWNlc3NhcnkgcmFuZ2UgZm8gdGhlIGdlb21ldHJ5XHJcblx0XHRjb25zdCByZXNlcnZlZFJhbmdlID0ge1xyXG5cdFx0XHR2ZXJ0ZXhTdGFydDogLSAxLFxyXG5cdFx0XHR2ZXJ0ZXhDb3VudDogLSAxLFxyXG5cdFx0XHRpbmRleFN0YXJ0OiAtIDEsXHJcblx0XHRcdGluZGV4Q291bnQ6IC0gMSxcclxuXHRcdH07XHJcblxyXG5cdFx0bGV0IGxhc3RSYW5nZSA9IG51bGw7XHJcblx0XHRjb25zdCByZXNlcnZlZFJhbmdlcyA9IHRoaXMuX3Jlc2VydmVkUmFuZ2VzO1xyXG5cdFx0Y29uc3QgZHJhd1JhbmdlcyA9IHRoaXMuX2RyYXdSYW5nZXM7XHJcblx0XHRjb25zdCBib3VuZHMgPSB0aGlzLl9ib3VuZHM7XHJcblx0XHRpZiAoIHRoaXMuX2dlb21ldHJ5Q291bnQgIT09IDAgKSB7XHJcblxyXG5cdFx0XHRsYXN0UmFuZ2UgPSByZXNlcnZlZFJhbmdlc1sgcmVzZXJ2ZWRSYW5nZXMubGVuZ3RoIC0gMSBdO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHZlcnRleENvdW50ID09PSAtIDEgKSB7XHJcblxyXG5cdFx0XHRyZXNlcnZlZFJhbmdlLnZlcnRleENvdW50ID0gZ2VvbWV0cnkuZ2V0QXR0cmlidXRlKCAncG9zaXRpb24nICkuY291bnQ7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdHJlc2VydmVkUmFuZ2UudmVydGV4Q291bnQgPSB2ZXJ0ZXhDb3VudDtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBsYXN0UmFuZ2UgPT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRyZXNlcnZlZFJhbmdlLnZlcnRleFN0YXJ0ID0gMDtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0cmVzZXJ2ZWRSYW5nZS52ZXJ0ZXhTdGFydCA9IGxhc3RSYW5nZS52ZXJ0ZXhTdGFydCArIGxhc3RSYW5nZS52ZXJ0ZXhDb3VudDtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Y29uc3QgaW5kZXggPSBnZW9tZXRyeS5nZXRJbmRleCgpO1xyXG5cdFx0Y29uc3QgaGFzSW5kZXggPSBpbmRleCAhPT0gbnVsbDtcclxuXHRcdGlmICggaGFzSW5kZXggKSB7XHJcblxyXG5cdFx0XHRpZiAoIGluZGV4Q291bnRcdD09PSAtIDEgKSB7XHJcblxyXG5cdFx0XHRcdHJlc2VydmVkUmFuZ2UuaW5kZXhDb3VudCA9IGluZGV4LmNvdW50O1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0cmVzZXJ2ZWRSYW5nZS5pbmRleENvdW50ID0gaW5kZXhDb3VudDtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGlmICggbGFzdFJhbmdlID09PSBudWxsICkge1xyXG5cclxuXHRcdFx0XHRyZXNlcnZlZFJhbmdlLmluZGV4U3RhcnQgPSAwO1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0cmVzZXJ2ZWRSYW5nZS5pbmRleFN0YXJ0ID0gbGFzdFJhbmdlLmluZGV4U3RhcnQgKyBsYXN0UmFuZ2UuaW5kZXhDb3VudDtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKFxyXG5cdFx0XHRyZXNlcnZlZFJhbmdlLmluZGV4U3RhcnQgIT09IC0gMSAmJlxyXG5cdFx0XHRyZXNlcnZlZFJhbmdlLmluZGV4U3RhcnQgKyByZXNlcnZlZFJhbmdlLmluZGV4Q291bnQgPiB0aGlzLl9tYXhJbmRleENvdW50IHx8XHJcblx0XHRcdHJlc2VydmVkUmFuZ2UudmVydGV4U3RhcnQgKyByZXNlcnZlZFJhbmdlLnZlcnRleENvdW50ID4gdGhpcy5fbWF4VmVydGV4Q291bnRcclxuXHRcdCkge1xyXG5cclxuXHRcdFx0dGhyb3cgbmV3IEVycm9yKCAnQmF0Y2hlZE1lc2g6IFJlc2VydmVkIHNwYWNlIHJlcXVlc3QgZXhjZWVkcyB0aGUgbWF4aW11bSBidWZmZXIgc2l6ZS4nICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGNvbnN0IHZpc2liaWxpdHkgPSB0aGlzLl92aXNpYmlsaXR5O1xyXG5cdFx0Y29uc3QgYWN0aXZlID0gdGhpcy5fYWN0aXZlO1xyXG5cdFx0Y29uc3QgbWF0cmljZXNUZXh0dXJlID0gdGhpcy5fbWF0cmljZXNUZXh0dXJlO1xyXG5cdFx0Y29uc3QgbWF0cmljZXNBcnJheSA9IHRoaXMuX21hdHJpY2VzVGV4dHVyZS5pbWFnZS5kYXRhO1xyXG5cclxuXHRcdC8vIHB1c2ggbmV3IHZpc2liaWxpdHkgc3RhdGVzXHJcblx0XHR2aXNpYmlsaXR5LnB1c2goIHRydWUgKTtcclxuXHRcdGFjdGl2ZS5wdXNoKCB0cnVlICk7XHJcblxyXG5cdFx0Ly8gdXBkYXRlIGlkXHJcblx0XHRjb25zdCBnZW9tZXRyeUlkID0gdGhpcy5fZ2VvbWV0cnlDb3VudDtcclxuXHRcdHRoaXMuX2dlb21ldHJ5Q291bnQgKys7XHJcblxyXG5cdFx0Ly8gaW5pdGlhbGl6ZSBtYXRyaXggaW5mb3JtYXRpb25cclxuXHRcdF9pZGVudGl0eU1hdHJpeC50b0FycmF5KCBtYXRyaWNlc0FycmF5LCBnZW9tZXRyeUlkICogMTYgKTtcclxuXHRcdG1hdHJpY2VzVGV4dHVyZS5uZWVkc1VwZGF0ZSA9IHRydWU7XHJcblxyXG5cdFx0Ly8gYWRkIHRoZSByZXNlcnZlZCByYW5nZSBhbmQgZHJhdyByYW5nZSBvYmplY3RzXHJcblx0XHRyZXNlcnZlZFJhbmdlcy5wdXNoKCByZXNlcnZlZFJhbmdlICk7XHJcblx0XHRkcmF3UmFuZ2VzLnB1c2goIHtcclxuXHRcdFx0c3RhcnQ6IGhhc0luZGV4ID8gcmVzZXJ2ZWRSYW5nZS5pbmRleFN0YXJ0IDogcmVzZXJ2ZWRSYW5nZS52ZXJ0ZXhTdGFydCxcclxuXHRcdFx0Y291bnQ6IC0gMVxyXG5cdFx0fSApO1xyXG5cdFx0Ym91bmRzLnB1c2goIHtcclxuXHRcdFx0Ym94SW5pdGlhbGl6ZWQ6IGZhbHNlLFxyXG5cdFx0XHRib3g6IG5ldyBCb3gzKCksXHJcblxyXG5cdFx0XHRzcGhlcmVJbml0aWFsaXplZDogZmFsc2UsXHJcblx0XHRcdHNwaGVyZTogbmV3IFNwaGVyZSgpXHJcblx0XHR9ICk7XHJcblxyXG5cdFx0Ly8gc2V0IHRoZSBpZCBmb3IgdGhlIGdlb21ldHJ5XHJcblx0XHRjb25zdCBpZEF0dHJpYnV0ZSA9IHRoaXMuZ2VvbWV0cnkuZ2V0QXR0cmlidXRlKCBJRF9BVFRSX05BTUUgKTtcclxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHJlc2VydmVkUmFuZ2UudmVydGV4Q291bnQ7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRpZEF0dHJpYnV0ZS5zZXRYKCByZXNlcnZlZFJhbmdlLnZlcnRleFN0YXJ0ICsgaSwgZ2VvbWV0cnlJZCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZEF0dHJpYnV0ZS5uZWVkc1VwZGF0ZSA9IHRydWU7XHJcblxyXG5cdFx0Ly8gdXBkYXRlIHRoZSBnZW9tZXRyeVxyXG5cdFx0dGhpcy5zZXRHZW9tZXRyeUF0KCBnZW9tZXRyeUlkLCBnZW9tZXRyeSApO1xyXG5cclxuXHRcdHJldHVybiBnZW9tZXRyeUlkO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldEdlb21ldHJ5QXQoIGlkLCBnZW9tZXRyeSApIHtcclxuXHJcblx0XHRpZiAoIGlkID49IHRoaXMuX2dlb21ldHJ5Q291bnQgKSB7XHJcblxyXG5cdFx0XHR0aHJvdyBuZXcgRXJyb3IoICdCYXRjaGVkTWVzaDogTWF4aW11bSBnZW9tZXRyeSBjb3VudCByZWFjaGVkLicgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5fdmFsaWRhdGVHZW9tZXRyeSggZ2VvbWV0cnkgKTtcclxuXHJcblx0XHRjb25zdCBiYXRjaEdlb21ldHJ5ID0gdGhpcy5nZW9tZXRyeTtcclxuXHRcdGNvbnN0IGhhc0luZGV4ID0gYmF0Y2hHZW9tZXRyeS5nZXRJbmRleCgpICE9PSBudWxsO1xyXG5cdFx0Y29uc3QgZHN0SW5kZXggPSBiYXRjaEdlb21ldHJ5LmdldEluZGV4KCk7XHJcblx0XHRjb25zdCBzcmNJbmRleCA9IGdlb21ldHJ5LmdldEluZGV4KCk7XHJcblx0XHRjb25zdCByZXNlcnZlZFJhbmdlID0gdGhpcy5fcmVzZXJ2ZWRSYW5nZXNbIGlkIF07XHJcblx0XHRpZiAoXHJcblx0XHRcdGhhc0luZGV4ICYmXHJcblx0XHRcdHNyY0luZGV4LmNvdW50ID4gcmVzZXJ2ZWRSYW5nZS5pbmRleENvdW50IHx8XHJcblx0XHRcdGdlb21ldHJ5LmF0dHJpYnV0ZXMucG9zaXRpb24uY291bnQgPiByZXNlcnZlZFJhbmdlLnZlcnRleENvdW50XHJcblx0XHQpIHtcclxuXHJcblx0XHRcdHRocm93IG5ldyBFcnJvciggJ0JhdGNoZWRNZXNoOiBSZXNlcnZlZCBzcGFjZSBub3QgbGFyZ2UgZW5vdWdoIGZvciBwcm92aWRlZCBnZW9tZXRyeS4nICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIGNvcHkgZ2VvbWV0cnkgb3ZlclxyXG5cdFx0Y29uc3QgdmVydGV4U3RhcnQgPSByZXNlcnZlZFJhbmdlLnZlcnRleFN0YXJ0O1xyXG5cdFx0Y29uc3QgdmVydGV4Q291bnQgPSByZXNlcnZlZFJhbmdlLnZlcnRleENvdW50O1xyXG5cdFx0Zm9yICggY29uc3QgYXR0cmlidXRlTmFtZSBpbiBiYXRjaEdlb21ldHJ5LmF0dHJpYnV0ZXMgKSB7XHJcblxyXG5cdFx0XHRpZiAoIGF0dHJpYnV0ZU5hbWUgPT09IElEX0FUVFJfTkFNRSApIHtcclxuXHJcblx0XHRcdFx0Y29udGludWU7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyBjb3B5IGF0dHJpYnV0ZSBkYXRhXHJcblx0XHRcdGNvbnN0IHNyY0F0dHJpYnV0ZSA9IGdlb21ldHJ5LmdldEF0dHJpYnV0ZSggYXR0cmlidXRlTmFtZSApO1xyXG5cdFx0XHRjb25zdCBkc3RBdHRyaWJ1dGUgPSBiYXRjaEdlb21ldHJ5LmdldEF0dHJpYnV0ZSggYXR0cmlidXRlTmFtZSApO1xyXG5cdFx0XHRjb3B5QXR0cmlidXRlRGF0YSggc3JjQXR0cmlidXRlLCBkc3RBdHRyaWJ1dGUsIHZlcnRleFN0YXJ0ICk7XHJcblxyXG5cdFx0XHQvLyBmaWxsIHRoZSByZXN0IGluIHdpdGggemVyb2VzXHJcblx0XHRcdGNvbnN0IGl0ZW1TaXplID0gc3JjQXR0cmlidXRlLml0ZW1TaXplO1xyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IHNyY0F0dHJpYnV0ZS5jb3VudCwgbCA9IHZlcnRleENvdW50OyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgaW5kZXggPSB2ZXJ0ZXhTdGFydCArIGk7XHJcblx0XHRcdFx0Zm9yICggbGV0IGMgPSAwOyBjIDwgaXRlbVNpemU7IGMgKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0ZHN0QXR0cmlidXRlLnNldENvbXBvbmVudCggaW5kZXgsIGMsIDAgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0ZHN0QXR0cmlidXRlLm5lZWRzVXBkYXRlID0gdHJ1ZTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gY29weSBpbmRleFxyXG5cdFx0aWYgKCBoYXNJbmRleCApIHtcclxuXHJcblx0XHRcdGNvbnN0IGluZGV4U3RhcnQgPSByZXNlcnZlZFJhbmdlLmluZGV4U3RhcnQ7XHJcblxyXG5cdFx0XHQvLyBjb3B5IGluZGV4IGRhdGEgb3ZlclxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBzcmNJbmRleC5jb3VudDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0ZHN0SW5kZXguc2V0WCggaW5kZXhTdGFydCArIGksIHZlcnRleFN0YXJ0ICsgc3JjSW5kZXguZ2V0WCggaSApICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyBmaWxsIHRoZSByZXN0IGluIHdpdGggemVyb2VzXHJcblx0XHRcdGZvciAoIGxldCBpID0gc3JjSW5kZXguY291bnQsIGwgPSByZXNlcnZlZFJhbmdlLmluZGV4Q291bnQ7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRkc3RJbmRleC5zZXRYKCBpbmRleFN0YXJ0ICsgaSwgdmVydGV4U3RhcnQgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGRzdEluZGV4Lm5lZWRzVXBkYXRlID0gdHJ1ZTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gc3RvcmUgdGhlIGJvdW5kaW5nIGJveGVzXHJcblx0XHRjb25zdCBib3VuZCA9IHRoaXMuX2JvdW5kc1sgaWQgXTtcclxuXHRcdGlmICggZ2VvbWV0cnkuYm91bmRpbmdCb3ggIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRib3VuZC5ib3guY29weSggZ2VvbWV0cnkuYm91bmRpbmdCb3ggKTtcclxuXHRcdFx0Ym91bmQuYm94SW5pdGlhbGl6ZWQgPSB0cnVlO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRib3VuZC5ib3hJbml0aWFsaXplZCA9IGZhbHNlO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIGdlb21ldHJ5LmJvdW5kaW5nU3BoZXJlICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0Ym91bmQuc3BoZXJlLmNvcHkoIGdlb21ldHJ5LmJvdW5kaW5nU3BoZXJlICk7XHJcblx0XHRcdGJvdW5kLnNwaGVyZUluaXRpYWxpemVkID0gdHJ1ZTtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0Ym91bmQuc3BoZXJlSW5pdGlhbGl6ZWQgPSBmYWxzZTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gc2V0IGRyYXdSYW5nZSBjb3VudFxyXG5cdFx0Y29uc3QgZHJhd1JhbmdlID0gdGhpcy5fZHJhd1Jhbmdlc1sgaWQgXTtcclxuXHRcdGNvbnN0IHBvc0F0dHIgPSBnZW9tZXRyeS5nZXRBdHRyaWJ1dGUoICdwb3NpdGlvbicgKTtcclxuXHRcdGRyYXdSYW5nZS5jb3VudCA9IGhhc0luZGV4ID8gc3JjSW5kZXguY291bnQgOiBwb3NBdHRyLmNvdW50O1xyXG5cdFx0dGhpcy5fdmlzaWJpbGl0eUNoYW5nZWQgPSB0cnVlO1xyXG5cclxuXHRcdHJldHVybiBpZDtcclxuXHJcblx0fVxyXG5cclxuXHRkZWxldGVHZW9tZXRyeSggZ2VvbWV0cnlJZCApIHtcclxuXHJcblx0XHQvLyBOb3RlOiBVc2VyIG5lZWRzIHRvIGNhbGwgb3B0aW1pemUoKSBhZnRlcndhcmQgdG8gcGFjayB0aGUgZGF0YS5cclxuXHJcblx0XHRjb25zdCBhY3RpdmUgPSB0aGlzLl9hY3RpdmU7XHJcblx0XHRpZiAoIGdlb21ldHJ5SWQgPj0gYWN0aXZlLmxlbmd0aCB8fCBhY3RpdmVbIGdlb21ldHJ5SWQgXSA9PT0gZmFsc2UgKSB7XHJcblxyXG5cdFx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0YWN0aXZlWyBnZW9tZXRyeUlkIF0gPSBmYWxzZTtcclxuXHRcdHRoaXMuX3Zpc2liaWxpdHlDaGFuZ2VkID0gdHJ1ZTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHQvLyBnZXQgYm91bmRpbmcgYm94IGFuZCBjb21wdXRlIGl0IGlmIGl0IGRvZXNuJ3QgZXhpc3RcclxuXHRnZXRCb3VuZGluZ0JveEF0KCBpZCwgdGFyZ2V0ICkge1xyXG5cclxuXHRcdGNvbnN0IGFjdGl2ZSA9IHRoaXMuX2FjdGl2ZTtcclxuXHRcdGlmICggYWN0aXZlWyBpZCBdID09PSBmYWxzZSApIHtcclxuXHJcblx0XHRcdHJldHVybiBudWxsO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvLyBjb21wdXRlIGJvdW5kaW5nIGJveFxyXG5cdFx0Y29uc3QgYm91bmQgPSB0aGlzLl9ib3VuZHNbIGlkIF07XHJcblx0XHRjb25zdCBib3ggPSBib3VuZC5ib3g7XHJcblx0XHRjb25zdCBnZW9tZXRyeSA9IHRoaXMuZ2VvbWV0cnk7XHJcblx0XHRpZiAoIGJvdW5kLmJveEluaXRpYWxpemVkID09PSBmYWxzZSApIHtcclxuXHJcblx0XHRcdGJveC5tYWtlRW1wdHkoKTtcclxuXHJcblx0XHRcdGNvbnN0IGluZGV4ID0gZ2VvbWV0cnkuaW5kZXg7XHJcblx0XHRcdGNvbnN0IHBvc2l0aW9uID0gZ2VvbWV0cnkuYXR0cmlidXRlcy5wb3NpdGlvbjtcclxuXHRcdFx0Y29uc3QgZHJhd1JhbmdlID0gdGhpcy5fZHJhd1Jhbmdlc1sgaWQgXTtcclxuXHRcdFx0Zm9yICggbGV0IGkgPSBkcmF3UmFuZ2Uuc3RhcnQsIGwgPSBkcmF3UmFuZ2Uuc3RhcnQgKyBkcmF3UmFuZ2UuY291bnQ7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRsZXQgaXYgPSBpO1xyXG5cdFx0XHRcdGlmICggaW5kZXggKSB7XHJcblxyXG5cdFx0XHRcdFx0aXYgPSBpbmRleC5nZXRYKCBpdiApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdGJveC5leHBhbmRCeVBvaW50KCBfdmVjdG9yLmZyb21CdWZmZXJBdHRyaWJ1dGUoIHBvc2l0aW9uLCBpdiApICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRib3VuZC5ib3hJbml0aWFsaXplZCA9IHRydWU7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRhcmdldC5jb3B5KCBib3ggKTtcclxuXHRcdHJldHVybiB0YXJnZXQ7XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gZ2V0IGJvdW5kaW5nIHNwaGVyZSBhbmQgY29tcHV0ZSBpdCBpZiBpdCBkb2Vzbid0IGV4aXN0XHJcblx0Z2V0Qm91bmRpbmdTcGhlcmVBdCggaWQsIHRhcmdldCApIHtcclxuXHJcblx0XHRjb25zdCBhY3RpdmUgPSB0aGlzLl9hY3RpdmU7XHJcblx0XHRpZiAoIGFjdGl2ZVsgaWQgXSA9PT0gZmFsc2UgKSB7XHJcblxyXG5cdFx0XHRyZXR1cm4gbnVsbDtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gY29tcHV0ZSBib3VuZGluZyBzcGhlcmVcclxuXHRcdGNvbnN0IGJvdW5kID0gdGhpcy5fYm91bmRzWyBpZCBdO1xyXG5cdFx0Y29uc3Qgc3BoZXJlID0gYm91bmQuc3BoZXJlO1xyXG5cdFx0Y29uc3QgZ2VvbWV0cnkgPSB0aGlzLmdlb21ldHJ5O1xyXG5cdFx0aWYgKCBib3VuZC5zcGhlcmVJbml0aWFsaXplZCA9PT0gZmFsc2UgKSB7XHJcblxyXG5cdFx0XHRzcGhlcmUubWFrZUVtcHR5KCk7XHJcblxyXG5cdFx0XHR0aGlzLmdldEJvdW5kaW5nQm94QXQoIGlkLCBfYm94ICk7XHJcblx0XHRcdF9ib3guZ2V0Q2VudGVyKCBzcGhlcmUuY2VudGVyICk7XHJcblxyXG5cdFx0XHRjb25zdCBpbmRleCA9IGdlb21ldHJ5LmluZGV4O1xyXG5cdFx0XHRjb25zdCBwb3NpdGlvbiA9IGdlb21ldHJ5LmF0dHJpYnV0ZXMucG9zaXRpb247XHJcblx0XHRcdGNvbnN0IGRyYXdSYW5nZSA9IHRoaXMuX2RyYXdSYW5nZXNbIGlkIF07XHJcblxyXG5cdFx0XHRsZXQgbWF4UmFkaXVzU3EgPSAwO1xyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IGRyYXdSYW5nZS5zdGFydCwgbCA9IGRyYXdSYW5nZS5zdGFydCArIGRyYXdSYW5nZS5jb3VudDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdGxldCBpdiA9IGk7XHJcblx0XHRcdFx0aWYgKCBpbmRleCApIHtcclxuXHJcblx0XHRcdFx0XHRpdiA9IGluZGV4LmdldFgoIGl2ICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0X3ZlY3Rvci5mcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbiwgaXYgKTtcclxuXHRcdFx0XHRtYXhSYWRpdXNTcSA9IE1hdGgubWF4KCBtYXhSYWRpdXNTcSwgc3BoZXJlLmNlbnRlci5kaXN0YW5jZVRvU3F1YXJlZCggX3ZlY3RvciApICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRzcGhlcmUucmFkaXVzID0gTWF0aC5zcXJ0KCBtYXhSYWRpdXNTcSApO1xyXG5cdFx0XHRib3VuZC5zcGhlcmVJbml0aWFsaXplZCA9IHRydWU7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRhcmdldC5jb3B5KCBzcGhlcmUgKTtcclxuXHRcdHJldHVybiB0YXJnZXQ7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0TWF0cml4QXQoIGdlb21ldHJ5SWQsIG1hdHJpeCApIHtcclxuXHJcblx0XHQvLyBAVE9ETzogTWFwIGdlb21ldHJ5SWQgdG8gaW5kZXggb2YgdGhlIGFycmF5cyBiZWNhdXNlXHJcblx0XHQvLyAgICAgICAgb3B0aW1pemUoKSBjYW4gbWFrZSBnZW9tZXRyeUlkIG1pc21hdGNoIHRoZSBpbmRleFxyXG5cclxuXHRcdGNvbnN0IGFjdGl2ZSA9IHRoaXMuX2FjdGl2ZTtcclxuXHRcdGNvbnN0IG1hdHJpY2VzVGV4dHVyZSA9IHRoaXMuX21hdHJpY2VzVGV4dHVyZTtcclxuXHRcdGNvbnN0IG1hdHJpY2VzQXJyYXkgPSB0aGlzLl9tYXRyaWNlc1RleHR1cmUuaW1hZ2UuZGF0YTtcclxuXHRcdGNvbnN0IGdlb21ldHJ5Q291bnQgPSB0aGlzLl9nZW9tZXRyeUNvdW50O1xyXG5cdFx0aWYgKCBnZW9tZXRyeUlkID49IGdlb21ldHJ5Q291bnQgfHwgYWN0aXZlWyBnZW9tZXRyeUlkIF0gPT09IGZhbHNlICkge1xyXG5cclxuXHRcdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdG1hdHJpeC50b0FycmF5KCBtYXRyaWNlc0FycmF5LCBnZW9tZXRyeUlkICogMTYgKTtcclxuXHRcdG1hdHJpY2VzVGV4dHVyZS5uZWVkc1VwZGF0ZSA9IHRydWU7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0TWF0cml4QXQoIGdlb21ldHJ5SWQsIG1hdHJpeCApIHtcclxuXHJcblx0XHRjb25zdCBhY3RpdmUgPSB0aGlzLl9hY3RpdmU7XHJcblx0XHRjb25zdCBtYXRyaWNlc0FycmF5ID0gdGhpcy5fbWF0cmljZXNUZXh0dXJlLmltYWdlLmRhdGE7XHJcblx0XHRjb25zdCBnZW9tZXRyeUNvdW50ID0gdGhpcy5fZ2VvbWV0cnlDb3VudDtcclxuXHRcdGlmICggZ2VvbWV0cnlJZCA+PSBnZW9tZXRyeUNvdW50IHx8IGFjdGl2ZVsgZ2VvbWV0cnlJZCBdID09PSBmYWxzZSApIHtcclxuXHJcblx0XHRcdHJldHVybiBudWxsO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gbWF0cml4LmZyb21BcnJheSggbWF0cmljZXNBcnJheSwgZ2VvbWV0cnlJZCAqIDE2ICk7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0VmlzaWJsZUF0KCBnZW9tZXRyeUlkLCB2YWx1ZSApIHtcclxuXHJcblx0XHRjb25zdCB2aXNpYmlsaXR5ID0gdGhpcy5fdmlzaWJpbGl0eTtcclxuXHRcdGNvbnN0IGFjdGl2ZSA9IHRoaXMuX2FjdGl2ZTtcclxuXHRcdGNvbnN0IGdlb21ldHJ5Q291bnQgPSB0aGlzLl9nZW9tZXRyeUNvdW50O1xyXG5cclxuXHRcdC8vIGlmIHRoZSBnZW9tZXRyeSBpcyBvdXQgb2YgcmFuZ2UsIG5vdCBhY3RpdmUsIG9yIHZpc2liaWxpdHkgc3RhdGVcclxuXHRcdC8vIGRvZXMgbm90IGNoYW5nZSB0aGVuIHJldHVybiBlYXJseVxyXG5cdFx0aWYgKFxyXG5cdFx0XHRnZW9tZXRyeUlkID49IGdlb21ldHJ5Q291bnQgfHxcclxuXHRcdFx0YWN0aXZlWyBnZW9tZXRyeUlkIF0gPT09IGZhbHNlIHx8XHJcblx0XHRcdHZpc2liaWxpdHlbIGdlb21ldHJ5SWQgXSA9PT0gdmFsdWVcclxuXHRcdCkge1xyXG5cclxuXHRcdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHZpc2liaWxpdHlbIGdlb21ldHJ5SWQgXSA9IHZhbHVlO1xyXG5cdFx0dGhpcy5fdmlzaWJpbGl0eUNoYW5nZWQgPSB0cnVlO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldFZpc2libGVBdCggZ2VvbWV0cnlJZCApIHtcclxuXHJcblx0XHRjb25zdCB2aXNpYmlsaXR5ID0gdGhpcy5fdmlzaWJpbGl0eTtcclxuXHRcdGNvbnN0IGFjdGl2ZSA9IHRoaXMuX2FjdGl2ZTtcclxuXHRcdGNvbnN0IGdlb21ldHJ5Q291bnQgPSB0aGlzLl9nZW9tZXRyeUNvdW50O1xyXG5cclxuXHRcdC8vIHJldHVybiBlYXJseSBpZiB0aGUgZ2VvbWV0cnkgaXMgb3V0IG9mIHJhbmdlIG9yIG5vdCBhY3RpdmVcclxuXHRcdGlmICggZ2VvbWV0cnlJZCA+PSBnZW9tZXRyeUNvdW50IHx8IGFjdGl2ZVsgZ2VvbWV0cnlJZCBdID09PSBmYWxzZSApIHtcclxuXHJcblx0XHRcdHJldHVybiBmYWxzZTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHZpc2liaWxpdHlbIGdlb21ldHJ5SWQgXTtcclxuXHJcblx0fVxyXG5cclxuXHRyYXljYXN0KCByYXljYXN0ZXIsIGludGVyc2VjdHMgKSB7XHJcblxyXG5cdFx0Y29uc3QgdmlzaWJpbGl0eSA9IHRoaXMuX3Zpc2liaWxpdHk7XHJcblx0XHRjb25zdCBhY3RpdmUgPSB0aGlzLl9hY3RpdmU7XHJcblx0XHRjb25zdCBkcmF3UmFuZ2VzID0gdGhpcy5fZHJhd1JhbmdlcztcclxuXHRcdGNvbnN0IGdlb21ldHJ5Q291bnQgPSB0aGlzLl9nZW9tZXRyeUNvdW50O1xyXG5cdFx0Y29uc3QgbWF0cml4V29ybGQgPSB0aGlzLm1hdHJpeFdvcmxkO1xyXG5cdFx0Y29uc3QgYmF0Y2hHZW9tZXRyeSA9IHRoaXMuZ2VvbWV0cnk7XHJcblxyXG5cdFx0Ly8gaXRlcmF0ZSBvdmVyIGVhY2ggZ2VvbWV0cnlcclxuXHRcdF9tZXNoLm1hdGVyaWFsID0gdGhpcy5tYXRlcmlhbDtcclxuXHRcdF9tZXNoLmdlb21ldHJ5LmluZGV4ID0gYmF0Y2hHZW9tZXRyeS5pbmRleDtcclxuXHRcdF9tZXNoLmdlb21ldHJ5LmF0dHJpYnV0ZXMgPSBiYXRjaEdlb21ldHJ5LmF0dHJpYnV0ZXM7XHJcblx0XHRpZiAoIF9tZXNoLmdlb21ldHJ5LmJvdW5kaW5nQm94ID09PSBudWxsICkge1xyXG5cclxuXHRcdFx0X21lc2guZ2VvbWV0cnkuYm91bmRpbmdCb3ggPSBuZXcgQm94MygpO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIF9tZXNoLmdlb21ldHJ5LmJvdW5kaW5nU3BoZXJlID09PSBudWxsICkge1xyXG5cclxuXHRcdFx0X21lc2guZ2VvbWV0cnkuYm91bmRpbmdTcGhlcmUgPSBuZXcgU3BoZXJlKCk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IGdlb21ldHJ5Q291bnQ7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRpZiAoICEgdmlzaWJpbGl0eVsgaSBdIHx8ICEgYWN0aXZlWyBpIF0gKSB7XHJcblxyXG5cdFx0XHRcdGNvbnRpbnVlO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Y29uc3QgZHJhd1JhbmdlID0gZHJhd1Jhbmdlc1sgaSBdO1xyXG5cdFx0XHRfbWVzaC5nZW9tZXRyeS5zZXREcmF3UmFuZ2UoIGRyYXdSYW5nZS5zdGFydCwgZHJhd1JhbmdlLmNvdW50ICk7XHJcblxyXG5cdFx0XHQvLyBnZSB0aGUgaW50ZXJzZWN0c1xyXG5cdFx0XHR0aGlzLmdldE1hdHJpeEF0KCBpLCBfbWVzaC5tYXRyaXhXb3JsZCApLnByZW11bHRpcGx5KCBtYXRyaXhXb3JsZCApO1xyXG5cdFx0XHR0aGlzLmdldEJvdW5kaW5nQm94QXQoIGksIF9tZXNoLmdlb21ldHJ5LmJvdW5kaW5nQm94ICk7XHJcblx0XHRcdHRoaXMuZ2V0Qm91bmRpbmdTcGhlcmVBdCggaSwgX21lc2guZ2VvbWV0cnkuYm91bmRpbmdTcGhlcmUgKTtcclxuXHRcdFx0X21lc2gucmF5Y2FzdCggcmF5Y2FzdGVyLCBfYmF0Y2hJbnRlcnNlY3RzICk7XHJcblxyXG5cdFx0XHQvLyBhZGQgYmF0Y2ggaWQgdG8gdGhlIGludGVyc2VjdHNcclxuXHRcdFx0Zm9yICggbGV0IGogPSAwLCBsID0gX2JhdGNoSW50ZXJzZWN0cy5sZW5ndGg7IGogPCBsOyBqICsrICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBpbnRlcnNlY3QgPSBfYmF0Y2hJbnRlcnNlY3RzWyBqIF07XHJcblx0XHRcdFx0aW50ZXJzZWN0Lm9iamVjdCA9IHRoaXM7XHJcblx0XHRcdFx0aW50ZXJzZWN0LmJhdGNoSWQgPSBpO1xyXG5cdFx0XHRcdGludGVyc2VjdHMucHVzaCggaW50ZXJzZWN0ICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRfYmF0Y2hJbnRlcnNlY3RzLmxlbmd0aCA9IDA7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdF9tZXNoLm1hdGVyaWFsID0gbnVsbDtcclxuXHRcdF9tZXNoLmdlb21ldHJ5LmluZGV4ID0gbnVsbDtcclxuXHRcdF9tZXNoLmdlb21ldHJ5LmF0dHJpYnV0ZXMgPSB7fTtcclxuXHRcdF9tZXNoLmdlb21ldHJ5LnNldERyYXdSYW5nZSggMCwgSW5maW5pdHkgKTtcclxuXHJcblx0fVxyXG5cclxuXHRjb3B5KCBzb3VyY2UgKSB7XHJcblxyXG5cdFx0c3VwZXIuY29weSggc291cmNlICk7XHJcblxyXG5cdFx0dGhpcy5nZW9tZXRyeSA9IHNvdXJjZS5nZW9tZXRyeS5jbG9uZSgpO1xyXG5cdFx0dGhpcy5wZXJPYmplY3RGcnVzdHVtQ3VsbGVkID0gc291cmNlLnBlck9iamVjdEZydXN0dW1DdWxsZWQ7XHJcblx0XHR0aGlzLnNvcnRPYmplY3RzID0gc291cmNlLnNvcnRPYmplY3RzO1xyXG5cdFx0dGhpcy5ib3VuZGluZ0JveCA9IHNvdXJjZS5ib3VuZGluZ0JveCAhPT0gbnVsbCA/IHNvdXJjZS5ib3VuZGluZ0JveC5jbG9uZSgpIDogbnVsbDtcclxuXHRcdHRoaXMuYm91bmRpbmdTcGhlcmUgPSBzb3VyY2UuYm91bmRpbmdTcGhlcmUgIT09IG51bGwgPyBzb3VyY2UuYm91bmRpbmdTcGhlcmUuY2xvbmUoKSA6IG51bGw7XHJcblxyXG5cdFx0dGhpcy5fZHJhd1JhbmdlcyA9IHNvdXJjZS5fZHJhd1Jhbmdlcy5tYXAoIHJhbmdlID0+ICggeyAuLi5yYW5nZSB9ICkgKTtcclxuXHRcdHRoaXMuX3Jlc2VydmVkUmFuZ2VzID0gc291cmNlLl9yZXNlcnZlZFJhbmdlcy5tYXAoIHJhbmdlID0+ICggeyAuLi5yYW5nZSB9ICkgKTtcclxuXHJcblx0XHR0aGlzLl92aXNpYmlsaXR5ID0gc291cmNlLl92aXNpYmlsaXR5LnNsaWNlKCk7XHJcblx0XHR0aGlzLl9hY3RpdmUgPSBzb3VyY2UuX2FjdGl2ZS5zbGljZSgpO1xyXG5cdFx0dGhpcy5fYm91bmRzID0gc291cmNlLl9ib3VuZHMubWFwKCBib3VuZCA9PiAoIHtcclxuXHRcdFx0Ym94SW5pdGlhbGl6ZWQ6IGJvdW5kLmJveEluaXRpYWxpemVkLFxyXG5cdFx0XHRib3g6IGJvdW5kLmJveC5jbG9uZSgpLFxyXG5cclxuXHRcdFx0c3BoZXJlSW5pdGlhbGl6ZWQ6IGJvdW5kLnNwaGVyZUluaXRpYWxpemVkLFxyXG5cdFx0XHRzcGhlcmU6IGJvdW5kLnNwaGVyZS5jbG9uZSgpXHJcblx0XHR9ICkgKTtcclxuXHJcblx0XHR0aGlzLl9tYXhHZW9tZXRyeUNvdW50ID0gc291cmNlLl9tYXhHZW9tZXRyeUNvdW50O1xyXG5cdFx0dGhpcy5fbWF4VmVydGV4Q291bnQgPSBzb3VyY2UuX21heFZlcnRleENvdW50O1xyXG5cdFx0dGhpcy5fbWF4SW5kZXhDb3VudCA9IHNvdXJjZS5fbWF4SW5kZXhDb3VudDtcclxuXHJcblx0XHR0aGlzLl9nZW9tZXRyeUluaXRpYWxpemVkID0gc291cmNlLl9nZW9tZXRyeUluaXRpYWxpemVkO1xyXG5cdFx0dGhpcy5fZ2VvbWV0cnlDb3VudCA9IHNvdXJjZS5fZ2VvbWV0cnlDb3VudDtcclxuXHRcdHRoaXMuX211bHRpRHJhd0NvdW50cyA9IHNvdXJjZS5fbXVsdGlEcmF3Q291bnRzLnNsaWNlKCk7XHJcblx0XHR0aGlzLl9tdWx0aURyYXdTdGFydHMgPSBzb3VyY2UuX211bHRpRHJhd1N0YXJ0cy5zbGljZSgpO1xyXG5cclxuXHRcdHRoaXMuX21hdHJpY2VzVGV4dHVyZSA9IHNvdXJjZS5fbWF0cmljZXNUZXh0dXJlLmNsb25lKCk7XHJcblx0XHR0aGlzLl9tYXRyaWNlc1RleHR1cmUuaW1hZ2UuZGF0YSA9IHRoaXMuX21hdHJpY2VzVGV4dHVyZS5pbWFnZS5zbGljZSgpO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGRpc3Bvc2UoKSB7XHJcblxyXG5cdFx0Ly8gQXNzdW1pbmcgdGhlIGdlb21ldHJ5IGlzIG5vdCBzaGFyZWQgd2l0aCBvdGhlciBtZXNoZXNcclxuXHRcdHRoaXMuZ2VvbWV0cnkuZGlzcG9zZSgpO1xyXG5cclxuXHRcdHRoaXMuX21hdHJpY2VzVGV4dHVyZS5kaXNwb3NlKCk7XHJcblx0XHR0aGlzLl9tYXRyaWNlc1RleHR1cmUgPSBudWxsO1xyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0b25CZWZvcmVSZW5kZXIoIHJlbmRlcmVyLCBzY2VuZSwgY2FtZXJhLCBnZW9tZXRyeSwgbWF0ZXJpYWwvKiwgX2dyb3VwKi8gKSB7XHJcblxyXG5cdFx0Ly8gaWYgdmlzaWJpbGl0eSBoYXMgbm90IGNoYW5nZWQgYW5kIGZydXN0dW0gY3VsbGluZyBhbmQgb2JqZWN0IHNvcnRpbmcgaXMgbm90IHJlcXVpcmVkXHJcblx0XHQvLyB0aGVuIHNraXAgaXRlcmF0aW5nIG92ZXIgYWxsIGl0ZW1zXHJcblx0XHRpZiAoICEgdGhpcy5fdmlzaWJpbGl0eUNoYW5nZWQgJiYgISB0aGlzLnBlck9iamVjdEZydXN0dW1DdWxsZWQgJiYgISB0aGlzLnNvcnRPYmplY3RzICkge1xyXG5cclxuXHRcdFx0cmV0dXJuO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvLyB0aGUgaW5kZXhlZCB2ZXJzaW9uIG9mIHRoZSBtdWx0aSBkcmF3IGZ1bmN0aW9uIHJlcXVpcmVzIHNwZWNpZnlpbmcgdGhlIHN0YXJ0XHJcblx0XHQvLyBvZmZzZXQgaW4gYnl0ZXMuXHJcblx0XHRjb25zdCBpbmRleCA9IGdlb21ldHJ5LmdldEluZGV4KCk7XHJcblx0XHRjb25zdCBieXRlc1BlckVsZW1lbnQgPSBpbmRleCA9PT0gbnVsbCA/IDEgOiBpbmRleC5hcnJheS5CWVRFU19QRVJfRUxFTUVOVDtcclxuXHJcblx0XHRjb25zdCBhY3RpdmUgPSB0aGlzLl9hY3RpdmU7XHJcblx0XHRjb25zdCB2aXNpYmlsaXR5ID0gdGhpcy5fdmlzaWJpbGl0eTtcclxuXHRcdGNvbnN0IG11bHRpRHJhd1N0YXJ0cyA9IHRoaXMuX211bHRpRHJhd1N0YXJ0cztcclxuXHRcdGNvbnN0IG11bHRpRHJhd0NvdW50cyA9IHRoaXMuX211bHRpRHJhd0NvdW50cztcclxuXHRcdGNvbnN0IGRyYXdSYW5nZXMgPSB0aGlzLl9kcmF3UmFuZ2VzO1xyXG5cdFx0Y29uc3QgcGVyT2JqZWN0RnJ1c3R1bUN1bGxlZCA9IHRoaXMucGVyT2JqZWN0RnJ1c3R1bUN1bGxlZDtcclxuXHJcblx0XHQvLyBwcmVwYXJlIHRoZSBmcnVzdHVtIGluIHRoZSBsb2NhbCBmcmFtZVxyXG5cdFx0aWYgKCBwZXJPYmplY3RGcnVzdHVtQ3VsbGVkICkge1xyXG5cclxuXHRcdFx0X3Byb2pTY3JlZW5NYXRyaXhcclxuXHRcdFx0XHQubXVsdGlwbHlNYXRyaWNlcyggY2FtZXJhLnByb2plY3Rpb25NYXRyaXgsIGNhbWVyYS5tYXRyaXhXb3JsZEludmVyc2UgKVxyXG5cdFx0XHRcdC5tdWx0aXBseSggdGhpcy5tYXRyaXhXb3JsZCApO1xyXG5cdFx0XHRfZnJ1c3R1bS5zZXRGcm9tUHJvamVjdGlvbk1hdHJpeChcclxuXHRcdFx0XHRfcHJvalNjcmVlbk1hdHJpeCxcclxuXHRcdFx0XHRyZW5kZXJlci5jb29yZGluYXRlU3lzdGVtXHJcblx0XHRcdCk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGxldCBjb3VudCA9IDA7XHJcblx0XHRpZiAoIHRoaXMuc29ydE9iamVjdHMgKSB7XHJcblxyXG5cdFx0XHQvLyBnZXQgdGhlIGNhbWVyYSBwb3NpdGlvbiBpbiB0aGUgbG9jYWwgZnJhbWVcclxuXHRcdFx0X2ludk1hdHJpeFdvcmxkLmNvcHkoIHRoaXMubWF0cml4V29ybGQgKS5pbnZlcnQoKTtcclxuXHRcdFx0X3ZlY3Rvci5zZXRGcm9tTWF0cml4UG9zaXRpb24oIGNhbWVyYS5tYXRyaXhXb3JsZCApLmFwcGx5TWF0cml4NCggX2ludk1hdHJpeFdvcmxkICk7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSB2aXNpYmlsaXR5Lmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdGlmICggdmlzaWJpbGl0eVsgaSBdICYmIGFjdGl2ZVsgaSBdICkge1xyXG5cclxuXHRcdFx0XHRcdC8vIGdldCB0aGUgYm91bmRzIGluIHdvcmxkIHNwYWNlXHJcblx0XHRcdFx0XHR0aGlzLmdldE1hdHJpeEF0KCBpLCBfbWF0cml4ICk7XHJcblx0XHRcdFx0XHR0aGlzLmdldEJvdW5kaW5nU3BoZXJlQXQoIGksIF9zcGhlcmUgKS5hcHBseU1hdHJpeDQoIF9tYXRyaXggKTtcclxuXHJcblx0XHRcdFx0XHQvLyBkZXRlcm1pbmUgd2hldGhlciB0aGUgYmF0Y2hlZCBnZW9tZXRyeSBpcyB3aXRoaW4gdGhlIGZydXN0dW1cclxuXHRcdFx0XHRcdGxldCBjdWxsZWQgPSBmYWxzZTtcclxuXHRcdFx0XHRcdGlmICggcGVyT2JqZWN0RnJ1c3R1bUN1bGxlZCApIHtcclxuXHJcblx0XHRcdFx0XHRcdGN1bGxlZCA9ICEgX2ZydXN0dW0uaW50ZXJzZWN0c1NwaGVyZSggX3NwaGVyZSApO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRpZiAoICEgY3VsbGVkICkge1xyXG5cclxuXHRcdFx0XHRcdFx0Ly8gZ2V0IHRoZSBkaXN0YW5jZSBmcm9tIGNhbWVyYSB1c2VkIGZvciBzb3J0aW5nXHJcblx0XHRcdFx0XHRcdGNvbnN0IHogPSBfdmVjdG9yLmRpc3RhbmNlVG8oIF9zcGhlcmUuY2VudGVyICk7XHJcblx0XHRcdFx0XHRcdF9yZW5kZXJMaXN0LnB1c2goIGRyYXdSYW5nZXNbIGkgXSwgeiApO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Ly8gU29ydCB0aGUgZHJhdyByYW5nZXMgYW5kIHByZXAgZm9yIHJlbmRlcmluZ1xyXG5cdFx0XHRjb25zdCBsaXN0ID0gX3JlbmRlckxpc3QubGlzdDtcclxuXHRcdFx0Y29uc3QgY3VzdG9tU29ydCA9IHRoaXMuY3VzdG9tU29ydDtcclxuXHRcdFx0aWYgKCBjdXN0b21Tb3J0ID09PSBudWxsICkge1xyXG5cclxuXHRcdFx0XHRsaXN0LnNvcnQoIG1hdGVyaWFsLnRyYW5zcGFyZW50ID8gc29ydFRyYW5zcGFyZW50IDogc29ydE9wYXF1ZSApO1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0Y3VzdG9tU29ydC5jYWxsKCB0aGlzLCBsaXN0LCBjYW1lcmEgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMCwgbCA9IGxpc3QubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgaXRlbSA9IGxpc3RbIGkgXTtcclxuXHRcdFx0XHRtdWx0aURyYXdTdGFydHNbIGNvdW50IF0gPSBpdGVtLnN0YXJ0ICogYnl0ZXNQZXJFbGVtZW50O1xyXG5cdFx0XHRcdG11bHRpRHJhd0NvdW50c1sgY291bnQgXSA9IGl0ZW0uY291bnQ7XHJcblx0XHRcdFx0Y291bnQgKys7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRfcmVuZGVyTGlzdC5yZXNldCgpO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSB2aXNpYmlsaXR5Lmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdGlmICggdmlzaWJpbGl0eVsgaSBdICYmIGFjdGl2ZVsgaSBdICkge1xyXG5cclxuXHRcdFx0XHRcdC8vIGRldGVybWluZSB3aGV0aGVyIHRoZSBiYXRjaGVkIGdlb21ldHJ5IGlzIHdpdGhpbiB0aGUgZnJ1c3R1bVxyXG5cdFx0XHRcdFx0bGV0IGN1bGxlZCA9IGZhbHNlO1xyXG5cdFx0XHRcdFx0aWYgKCBwZXJPYmplY3RGcnVzdHVtQ3VsbGVkICkge1xyXG5cclxuXHRcdFx0XHRcdFx0Ly8gZ2V0IHRoZSBib3VuZHMgaW4gd29ybGQgc3BhY2VcclxuXHRcdFx0XHRcdFx0dGhpcy5nZXRNYXRyaXhBdCggaSwgX21hdHJpeCApO1xyXG5cdFx0XHRcdFx0XHR0aGlzLmdldEJvdW5kaW5nU3BoZXJlQXQoIGksIF9zcGhlcmUgKS5hcHBseU1hdHJpeDQoIF9tYXRyaXggKTtcclxuXHRcdFx0XHRcdFx0Y3VsbGVkID0gISBfZnJ1c3R1bS5pbnRlcnNlY3RzU3BoZXJlKCBfc3BoZXJlICk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdGlmICggISBjdWxsZWQgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRjb25zdCByYW5nZSA9IGRyYXdSYW5nZXNbIGkgXTtcclxuXHRcdFx0XHRcdFx0bXVsdGlEcmF3U3RhcnRzWyBjb3VudCBdID0gcmFuZ2Uuc3RhcnQgKiBieXRlc1BlckVsZW1lbnQ7XHJcblx0XHRcdFx0XHRcdG11bHRpRHJhd0NvdW50c1sgY291bnQgXSA9IHJhbmdlLmNvdW50O1xyXG5cdFx0XHRcdFx0XHRjb3VudCArKztcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5fbXVsdGlEcmF3Q291bnQgPSBjb3VudDtcclxuXHRcdHRoaXMuX3Zpc2liaWxpdHlDaGFuZ2VkID0gZmFsc2U7XHJcblxyXG5cdH1cclxuXHJcblx0b25CZWZvcmVTaGFkb3coIHJlbmRlcmVyLCBvYmplY3QsIGNhbWVyYSwgc2hhZG93Q2FtZXJhLCBnZW9tZXRyeSwgZGVwdGhNYXRlcmlhbC8qICwgZ3JvdXAgKi8gKSB7XHJcblxyXG5cdFx0dGhpcy5vbkJlZm9yZVJlbmRlciggcmVuZGVyZXIsIG51bGwsIHNoYWRvd0NhbWVyYSwgZ2VvbWV0cnksIGRlcHRoTWF0ZXJpYWwgKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgQmF0Y2hlZE1lc2ggfTtcclxuIiwiaW1wb3J0IHsgTWF0ZXJpYWwgfSBmcm9tICcuL01hdGVyaWFsLmpzJztcclxuaW1wb3J0IHsgQ29sb3IgfSBmcm9tICcuLi9tYXRoL0NvbG9yLmpzJztcclxuXHJcbmNsYXNzIExpbmVCYXNpY01hdGVyaWFsIGV4dGVuZHMgTWF0ZXJpYWwge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggcGFyYW1ldGVycyApIHtcclxuXHJcblx0XHRzdXBlcigpO1xyXG5cclxuXHRcdHRoaXMuaXNMaW5lQmFzaWNNYXRlcmlhbCA9IHRydWU7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ0xpbmVCYXNpY01hdGVyaWFsJztcclxuXHJcblx0XHR0aGlzLmNvbG9yID0gbmV3IENvbG9yKCAweGZmZmZmZiApO1xyXG5cclxuXHRcdHRoaXMubWFwID0gbnVsbDtcclxuXHJcblx0XHR0aGlzLmxpbmV3aWR0aCA9IDE7XHJcblx0XHR0aGlzLmxpbmVjYXAgPSAncm91bmQnO1xyXG5cdFx0dGhpcy5saW5lam9pbiA9ICdyb3VuZCc7XHJcblxyXG5cdFx0dGhpcy5mb2cgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMuc2V0VmFsdWVzKCBwYXJhbWV0ZXJzICk7XHJcblxyXG5cdH1cclxuXHJcblxyXG5cdGNvcHkoIHNvdXJjZSApIHtcclxuXHJcblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcclxuXHJcblx0XHR0aGlzLmNvbG9yLmNvcHkoIHNvdXJjZS5jb2xvciApO1xyXG5cclxuXHRcdHRoaXMubWFwID0gc291cmNlLm1hcDtcclxuXHJcblx0XHR0aGlzLmxpbmV3aWR0aCA9IHNvdXJjZS5saW5ld2lkdGg7XHJcblx0XHR0aGlzLmxpbmVjYXAgPSBzb3VyY2UubGluZWNhcDtcclxuXHRcdHRoaXMubGluZWpvaW4gPSBzb3VyY2UubGluZWpvaW47XHJcblxyXG5cdFx0dGhpcy5mb2cgPSBzb3VyY2UuZm9nO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBMaW5lQmFzaWNNYXRlcmlhbCB9O1xyXG4iLCJpbXBvcnQgeyBTcGhlcmUgfSBmcm9tICcuLi9tYXRoL1NwaGVyZS5qcyc7XHJcbmltcG9ydCB7IFJheSB9IGZyb20gJy4uL21hdGgvUmF5LmpzJztcclxuaW1wb3J0IHsgTWF0cml4NCB9IGZyb20gJy4uL21hdGgvTWF0cml4NC5qcyc7XHJcbmltcG9ydCB7IE9iamVjdDNEIH0gZnJvbSAnLi4vY29yZS9PYmplY3QzRC5qcyc7XHJcbmltcG9ydCB7IFZlY3RvcjMgfSBmcm9tICcuLi9tYXRoL1ZlY3RvcjMuanMnO1xyXG5pbXBvcnQgeyBMaW5lQmFzaWNNYXRlcmlhbCB9IGZyb20gJy4uL21hdGVyaWFscy9MaW5lQmFzaWNNYXRlcmlhbC5qcyc7XHJcbmltcG9ydCB7IEJ1ZmZlckdlb21ldHJ5IH0gZnJvbSAnLi4vY29yZS9CdWZmZXJHZW9tZXRyeS5qcyc7XHJcbmltcG9ydCB7IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUgfSBmcm9tICcuLi9jb3JlL0J1ZmZlckF0dHJpYnV0ZS5qcyc7XHJcblxyXG5jb25zdCBfc3RhcnQgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XHJcbmNvbnN0IF9lbmQgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XHJcbmNvbnN0IF9pbnZlcnNlTWF0cml4ID0gLypAX19QVVJFX18qLyBuZXcgTWF0cml4NCgpO1xyXG5jb25zdCBfcmF5ID0gLypAX19QVVJFX18qLyBuZXcgUmF5KCk7XHJcbmNvbnN0IF9zcGhlcmUgPSAvKkBfX1BVUkVfXyovIG5ldyBTcGhlcmUoKTtcclxuXHJcbmNsYXNzIExpbmUgZXh0ZW5kcyBPYmplY3QzRCB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBnZW9tZXRyeSA9IG5ldyBCdWZmZXJHZW9tZXRyeSgpLCBtYXRlcmlhbCA9IG5ldyBMaW5lQmFzaWNNYXRlcmlhbCgpICkge1xyXG5cclxuXHRcdHN1cGVyKCk7XHJcblxyXG5cdFx0dGhpcy5pc0xpbmUgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMudHlwZSA9ICdMaW5lJztcclxuXHJcblx0XHR0aGlzLmdlb21ldHJ5ID0gZ2VvbWV0cnk7XHJcblx0XHR0aGlzLm1hdGVyaWFsID0gbWF0ZXJpYWw7XHJcblxyXG5cdFx0dGhpcy51cGRhdGVNb3JwaFRhcmdldHMoKTtcclxuXHJcblx0fVxyXG5cclxuXHRjb3B5KCBzb3VyY2UsIHJlY3Vyc2l2ZSApIHtcclxuXHJcblx0XHRzdXBlci5jb3B5KCBzb3VyY2UsIHJlY3Vyc2l2ZSApO1xyXG5cclxuXHRcdHRoaXMubWF0ZXJpYWwgPSBBcnJheS5pc0FycmF5KCBzb3VyY2UubWF0ZXJpYWwgKSA/IHNvdXJjZS5tYXRlcmlhbC5zbGljZSgpIDogc291cmNlLm1hdGVyaWFsO1xyXG5cdFx0dGhpcy5nZW9tZXRyeSA9IHNvdXJjZS5nZW9tZXRyeTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRjb21wdXRlTGluZURpc3RhbmNlcygpIHtcclxuXHJcblx0XHRjb25zdCBnZW9tZXRyeSA9IHRoaXMuZ2VvbWV0cnk7XHJcblxyXG5cdFx0Ly8gd2UgYXNzdW1lIG5vbi1pbmRleGVkIGdlb21ldHJ5XHJcblxyXG5cdFx0aWYgKCBnZW9tZXRyeS5pbmRleCA9PT0gbnVsbCApIHtcclxuXHJcblx0XHRcdGNvbnN0IHBvc2l0aW9uQXR0cmlidXRlID0gZ2VvbWV0cnkuYXR0cmlidXRlcy5wb3NpdGlvbjtcclxuXHRcdFx0Y29uc3QgbGluZURpc3RhbmNlcyA9IFsgMCBdO1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGkgPSAxLCBsID0gcG9zaXRpb25BdHRyaWJ1dGUuY291bnQ7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRfc3RhcnQuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggcG9zaXRpb25BdHRyaWJ1dGUsIGkgLSAxICk7XHJcblx0XHRcdFx0X2VuZC5mcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbkF0dHJpYnV0ZSwgaSApO1xyXG5cclxuXHRcdFx0XHRsaW5lRGlzdGFuY2VzWyBpIF0gPSBsaW5lRGlzdGFuY2VzWyBpIC0gMSBdO1xyXG5cdFx0XHRcdGxpbmVEaXN0YW5jZXNbIGkgXSArPSBfc3RhcnQuZGlzdGFuY2VUbyggX2VuZCApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Z2VvbWV0cnkuc2V0QXR0cmlidXRlKCAnbGluZURpc3RhbmNlJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIGxpbmVEaXN0YW5jZXMsIDEgKSApO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5MaW5lLmNvbXB1dGVMaW5lRGlzdGFuY2VzKCk6IENvbXB1dGF0aW9uIG9ubHkgcG9zc2libGUgd2l0aCBub24taW5kZXhlZCBCdWZmZXJHZW9tZXRyeS4nICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHJheWNhc3QoIHJheWNhc3RlciwgaW50ZXJzZWN0cyApIHtcclxuXHJcblx0XHRjb25zdCBnZW9tZXRyeSA9IHRoaXMuZ2VvbWV0cnk7XHJcblx0XHRjb25zdCBtYXRyaXhXb3JsZCA9IHRoaXMubWF0cml4V29ybGQ7XHJcblx0XHRjb25zdCB0aHJlc2hvbGQgPSByYXljYXN0ZXIucGFyYW1zLkxpbmUudGhyZXNob2xkO1xyXG5cdFx0Y29uc3QgZHJhd1JhbmdlID0gZ2VvbWV0cnkuZHJhd1JhbmdlO1xyXG5cclxuXHRcdC8vIENoZWNraW5nIGJvdW5kaW5nU3BoZXJlIGRpc3RhbmNlIHRvIHJheVxyXG5cclxuXHRcdGlmICggZ2VvbWV0cnkuYm91bmRpbmdTcGhlcmUgPT09IG51bGwgKSBnZW9tZXRyeS5jb21wdXRlQm91bmRpbmdTcGhlcmUoKTtcclxuXHJcblx0XHRfc3BoZXJlLmNvcHkoIGdlb21ldHJ5LmJvdW5kaW5nU3BoZXJlICk7XHJcblx0XHRfc3BoZXJlLmFwcGx5TWF0cml4NCggbWF0cml4V29ybGQgKTtcclxuXHRcdF9zcGhlcmUucmFkaXVzICs9IHRocmVzaG9sZDtcclxuXHJcblx0XHRpZiAoIHJheWNhc3Rlci5yYXkuaW50ZXJzZWN0c1NwaGVyZSggX3NwaGVyZSApID09PSBmYWxzZSApIHJldHVybjtcclxuXHJcblx0XHQvL1xyXG5cclxuXHRcdF9pbnZlcnNlTWF0cml4LmNvcHkoIG1hdHJpeFdvcmxkICkuaW52ZXJ0KCk7XHJcblx0XHRfcmF5LmNvcHkoIHJheWNhc3Rlci5yYXkgKS5hcHBseU1hdHJpeDQoIF9pbnZlcnNlTWF0cml4ICk7XHJcblxyXG5cdFx0Y29uc3QgbG9jYWxUaHJlc2hvbGQgPSB0aHJlc2hvbGQgLyAoICggdGhpcy5zY2FsZS54ICsgdGhpcy5zY2FsZS55ICsgdGhpcy5zY2FsZS56ICkgLyAzICk7XHJcblx0XHRjb25zdCBsb2NhbFRocmVzaG9sZFNxID0gbG9jYWxUaHJlc2hvbGQgKiBsb2NhbFRocmVzaG9sZDtcclxuXHJcblx0XHRjb25zdCB2U3RhcnQgPSBuZXcgVmVjdG9yMygpO1xyXG5cdFx0Y29uc3QgdkVuZCA9IG5ldyBWZWN0b3IzKCk7XHJcblx0XHRjb25zdCBpbnRlclNlZ21lbnQgPSBuZXcgVmVjdG9yMygpO1xyXG5cdFx0Y29uc3QgaW50ZXJSYXkgPSBuZXcgVmVjdG9yMygpO1xyXG5cdFx0Y29uc3Qgc3RlcCA9IHRoaXMuaXNMaW5lU2VnbWVudHMgPyAyIDogMTtcclxuXHJcblx0XHRjb25zdCBpbmRleCA9IGdlb21ldHJ5LmluZGV4O1xyXG5cdFx0Y29uc3QgYXR0cmlidXRlcyA9IGdlb21ldHJ5LmF0dHJpYnV0ZXM7XHJcblx0XHRjb25zdCBwb3NpdGlvbkF0dHJpYnV0ZSA9IGF0dHJpYnV0ZXMucG9zaXRpb247XHJcblxyXG5cdFx0aWYgKCBpbmRleCAhPT0gbnVsbCApIHtcclxuXHJcblx0XHRcdGNvbnN0IHN0YXJ0ID0gTWF0aC5tYXgoIDAsIGRyYXdSYW5nZS5zdGFydCApO1xyXG5cdFx0XHRjb25zdCBlbmQgPSBNYXRoLm1pbiggaW5kZXguY291bnQsICggZHJhd1JhbmdlLnN0YXJ0ICsgZHJhd1JhbmdlLmNvdW50ICkgKTtcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gc3RhcnQsIGwgPSBlbmQgLSAxOyBpIDwgbDsgaSArPSBzdGVwICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBhID0gaW5kZXguZ2V0WCggaSApO1xyXG5cdFx0XHRcdGNvbnN0IGIgPSBpbmRleC5nZXRYKCBpICsgMSApO1xyXG5cclxuXHRcdFx0XHR2U3RhcnQuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggcG9zaXRpb25BdHRyaWJ1dGUsIGEgKTtcclxuXHRcdFx0XHR2RW5kLmZyb21CdWZmZXJBdHRyaWJ1dGUoIHBvc2l0aW9uQXR0cmlidXRlLCBiICk7XHJcblxyXG5cdFx0XHRcdGNvbnN0IGRpc3RTcSA9IF9yYXkuZGlzdGFuY2VTcVRvU2VnbWVudCggdlN0YXJ0LCB2RW5kLCBpbnRlclJheSwgaW50ZXJTZWdtZW50ICk7XHJcblxyXG5cdFx0XHRcdGlmICggZGlzdFNxID4gbG9jYWxUaHJlc2hvbGRTcSApIGNvbnRpbnVlO1xyXG5cclxuXHRcdFx0XHRpbnRlclJheS5hcHBseU1hdHJpeDQoIHRoaXMubWF0cml4V29ybGQgKTsgLy9Nb3ZlIGJhY2sgdG8gd29ybGQgc3BhY2UgZm9yIGRpc3RhbmNlIGNhbGN1bGF0aW9uXHJcblxyXG5cdFx0XHRcdGNvbnN0IGRpc3RhbmNlID0gcmF5Y2FzdGVyLnJheS5vcmlnaW4uZGlzdGFuY2VUbyggaW50ZXJSYXkgKTtcclxuXHJcblx0XHRcdFx0aWYgKCBkaXN0YW5jZSA8IHJheWNhc3Rlci5uZWFyIHx8IGRpc3RhbmNlID4gcmF5Y2FzdGVyLmZhciApIGNvbnRpbnVlO1xyXG5cclxuXHRcdFx0XHRpbnRlcnNlY3RzLnB1c2goIHtcclxuXHJcblx0XHRcdFx0XHRkaXN0YW5jZTogZGlzdGFuY2UsXHJcblx0XHRcdFx0XHQvLyBXaGF0IGRvIHdlIHdhbnQ/IGludGVyc2VjdGlvbiBwb2ludCBvbiB0aGUgcmF5IG9yIG9uIHRoZSBzZWdtZW50Pz9cclxuXHRcdFx0XHRcdC8vIHBvaW50OiByYXljYXN0ZXIucmF5LmF0KCBkaXN0YW5jZSApLFxyXG5cdFx0XHRcdFx0cG9pbnQ6IGludGVyU2VnbWVudC5jbG9uZSgpLmFwcGx5TWF0cml4NCggdGhpcy5tYXRyaXhXb3JsZCApLFxyXG5cdFx0XHRcdFx0aW5kZXg6IGksXHJcblx0XHRcdFx0XHRmYWNlOiBudWxsLFxyXG5cdFx0XHRcdFx0ZmFjZUluZGV4OiBudWxsLFxyXG5cdFx0XHRcdFx0b2JqZWN0OiB0aGlzXHJcblxyXG5cdFx0XHRcdH0gKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0Y29uc3Qgc3RhcnQgPSBNYXRoLm1heCggMCwgZHJhd1JhbmdlLnN0YXJ0ICk7XHJcblx0XHRcdGNvbnN0IGVuZCA9IE1hdGgubWluKCBwb3NpdGlvbkF0dHJpYnV0ZS5jb3VudCwgKCBkcmF3UmFuZ2Uuc3RhcnQgKyBkcmF3UmFuZ2UuY291bnQgKSApO1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGkgPSBzdGFydCwgbCA9IGVuZCAtIDE7IGkgPCBsOyBpICs9IHN0ZXAgKSB7XHJcblxyXG5cdFx0XHRcdHZTdGFydC5mcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbkF0dHJpYnV0ZSwgaSApO1xyXG5cdFx0XHRcdHZFbmQuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggcG9zaXRpb25BdHRyaWJ1dGUsIGkgKyAxICk7XHJcblxyXG5cdFx0XHRcdGNvbnN0IGRpc3RTcSA9IF9yYXkuZGlzdGFuY2VTcVRvU2VnbWVudCggdlN0YXJ0LCB2RW5kLCBpbnRlclJheSwgaW50ZXJTZWdtZW50ICk7XHJcblxyXG5cdFx0XHRcdGlmICggZGlzdFNxID4gbG9jYWxUaHJlc2hvbGRTcSApIGNvbnRpbnVlO1xyXG5cclxuXHRcdFx0XHRpbnRlclJheS5hcHBseU1hdHJpeDQoIHRoaXMubWF0cml4V29ybGQgKTsgLy9Nb3ZlIGJhY2sgdG8gd29ybGQgc3BhY2UgZm9yIGRpc3RhbmNlIGNhbGN1bGF0aW9uXHJcblxyXG5cdFx0XHRcdGNvbnN0IGRpc3RhbmNlID0gcmF5Y2FzdGVyLnJheS5vcmlnaW4uZGlzdGFuY2VUbyggaW50ZXJSYXkgKTtcclxuXHJcblx0XHRcdFx0aWYgKCBkaXN0YW5jZSA8IHJheWNhc3Rlci5uZWFyIHx8IGRpc3RhbmNlID4gcmF5Y2FzdGVyLmZhciApIGNvbnRpbnVlO1xyXG5cclxuXHRcdFx0XHRpbnRlcnNlY3RzLnB1c2goIHtcclxuXHJcblx0XHRcdFx0XHRkaXN0YW5jZTogZGlzdGFuY2UsXHJcblx0XHRcdFx0XHQvLyBXaGF0IGRvIHdlIHdhbnQ/IGludGVyc2VjdGlvbiBwb2ludCBvbiB0aGUgcmF5IG9yIG9uIHRoZSBzZWdtZW50Pz9cclxuXHRcdFx0XHRcdC8vIHBvaW50OiByYXljYXN0ZXIucmF5LmF0KCBkaXN0YW5jZSApLFxyXG5cdFx0XHRcdFx0cG9pbnQ6IGludGVyU2VnbWVudC5jbG9uZSgpLmFwcGx5TWF0cml4NCggdGhpcy5tYXRyaXhXb3JsZCApLFxyXG5cdFx0XHRcdFx0aW5kZXg6IGksXHJcblx0XHRcdFx0XHRmYWNlOiBudWxsLFxyXG5cdFx0XHRcdFx0ZmFjZUluZGV4OiBudWxsLFxyXG5cdFx0XHRcdFx0b2JqZWN0OiB0aGlzXHJcblxyXG5cdFx0XHRcdH0gKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0dXBkYXRlTW9ycGhUYXJnZXRzKCkge1xyXG5cclxuXHRcdGNvbnN0IGdlb21ldHJ5ID0gdGhpcy5nZW9tZXRyeTtcclxuXHJcblx0XHRjb25zdCBtb3JwaEF0dHJpYnV0ZXMgPSBnZW9tZXRyeS5tb3JwaEF0dHJpYnV0ZXM7XHJcblx0XHRjb25zdCBrZXlzID0gT2JqZWN0LmtleXMoIG1vcnBoQXR0cmlidXRlcyApO1xyXG5cclxuXHRcdGlmICgga2V5cy5sZW5ndGggPiAwICkge1xyXG5cclxuXHRcdFx0Y29uc3QgbW9ycGhBdHRyaWJ1dGUgPSBtb3JwaEF0dHJpYnV0ZXNbIGtleXNbIDAgXSBdO1xyXG5cclxuXHRcdFx0aWYgKCBtb3JwaEF0dHJpYnV0ZSAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHR0aGlzLm1vcnBoVGFyZ2V0SW5mbHVlbmNlcyA9IFtdO1xyXG5cdFx0XHRcdHRoaXMubW9ycGhUYXJnZXREaWN0aW9uYXJ5ID0ge307XHJcblxyXG5cdFx0XHRcdGZvciAoIGxldCBtID0gMCwgbWwgPSBtb3JwaEF0dHJpYnV0ZS5sZW5ndGg7IG0gPCBtbDsgbSArKyApIHtcclxuXHJcblx0XHRcdFx0XHRjb25zdCBuYW1lID0gbW9ycGhBdHRyaWJ1dGVbIG0gXS5uYW1lIHx8IFN0cmluZyggbSApO1xyXG5cclxuXHRcdFx0XHRcdHRoaXMubW9ycGhUYXJnZXRJbmZsdWVuY2VzLnB1c2goIDAgKTtcclxuXHRcdFx0XHRcdHRoaXMubW9ycGhUYXJnZXREaWN0aW9uYXJ5WyBuYW1lIF0gPSBtO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBMaW5lIH07XHJcbiIsImltcG9ydCB7IExpbmUgfSBmcm9tICcuL0xpbmUuanMnO1xyXG5pbXBvcnQgeyBWZWN0b3IzIH0gZnJvbSAnLi4vbWF0aC9WZWN0b3IzLmpzJztcclxuaW1wb3J0IHsgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSB9IGZyb20gJy4uL2NvcmUvQnVmZmVyQXR0cmlidXRlLmpzJztcclxuXHJcbmNvbnN0IF9zdGFydCA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuY29uc3QgX2VuZCA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuXHJcbmNsYXNzIExpbmVTZWdtZW50cyBleHRlbmRzIExpbmUge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggZ2VvbWV0cnksIG1hdGVyaWFsICkge1xyXG5cclxuXHRcdHN1cGVyKCBnZW9tZXRyeSwgbWF0ZXJpYWwgKTtcclxuXHJcblx0XHR0aGlzLmlzTGluZVNlZ21lbnRzID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSAnTGluZVNlZ21lbnRzJztcclxuXHJcblx0fVxyXG5cclxuXHRjb21wdXRlTGluZURpc3RhbmNlcygpIHtcclxuXHJcblx0XHRjb25zdCBnZW9tZXRyeSA9IHRoaXMuZ2VvbWV0cnk7XHJcblxyXG5cdFx0Ly8gd2UgYXNzdW1lIG5vbi1pbmRleGVkIGdlb21ldHJ5XHJcblxyXG5cdFx0aWYgKCBnZW9tZXRyeS5pbmRleCA9PT0gbnVsbCApIHtcclxuXHJcblx0XHRcdGNvbnN0IHBvc2l0aW9uQXR0cmlidXRlID0gZ2VvbWV0cnkuYXR0cmlidXRlcy5wb3NpdGlvbjtcclxuXHRcdFx0Y29uc3QgbGluZURpc3RhbmNlcyA9IFtdO1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gcG9zaXRpb25BdHRyaWJ1dGUuY291bnQ7IGkgPCBsOyBpICs9IDIgKSB7XHJcblxyXG5cdFx0XHRcdF9zdGFydC5mcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbkF0dHJpYnV0ZSwgaSApO1xyXG5cdFx0XHRcdF9lbmQuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggcG9zaXRpb25BdHRyaWJ1dGUsIGkgKyAxICk7XHJcblxyXG5cdFx0XHRcdGxpbmVEaXN0YW5jZXNbIGkgXSA9ICggaSA9PT0gMCApID8gMCA6IGxpbmVEaXN0YW5jZXNbIGkgLSAxIF07XHJcblx0XHRcdFx0bGluZURpc3RhbmNlc1sgaSArIDEgXSA9IGxpbmVEaXN0YW5jZXNbIGkgXSArIF9zdGFydC5kaXN0YW5jZVRvKCBfZW5kICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRnZW9tZXRyeS5zZXRBdHRyaWJ1dGUoICdsaW5lRGlzdGFuY2UnLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggbGluZURpc3RhbmNlcywgMSApICk7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLkxpbmVTZWdtZW50cy5jb21wdXRlTGluZURpc3RhbmNlcygpOiBDb21wdXRhdGlvbiBvbmx5IHBvc3NpYmxlIHdpdGggbm9uLWluZGV4ZWQgQnVmZmVyR2VvbWV0cnkuJyApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgTGluZVNlZ21lbnRzIH07XHJcbiIsImltcG9ydCB7IExpbmUgfSBmcm9tICcuL0xpbmUuanMnO1xyXG5cclxuY2xhc3MgTGluZUxvb3AgZXh0ZW5kcyBMaW5lIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIGdlb21ldHJ5LCBtYXRlcmlhbCApIHtcclxuXHJcblx0XHRzdXBlciggZ2VvbWV0cnksIG1hdGVyaWFsICk7XHJcblxyXG5cdFx0dGhpcy5pc0xpbmVMb29wID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSAnTGluZUxvb3AnO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBMaW5lTG9vcCB9O1xyXG4iLCJpbXBvcnQgeyBNYXRlcmlhbCB9IGZyb20gJy4vTWF0ZXJpYWwuanMnO1xyXG5pbXBvcnQgeyBDb2xvciB9IGZyb20gJy4uL21hdGgvQ29sb3IuanMnO1xyXG5cclxuY2xhc3MgUG9pbnRzTWF0ZXJpYWwgZXh0ZW5kcyBNYXRlcmlhbCB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBwYXJhbWV0ZXJzICkge1xyXG5cclxuXHRcdHN1cGVyKCk7XHJcblxyXG5cdFx0dGhpcy5pc1BvaW50c01hdGVyaWFsID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSAnUG9pbnRzTWF0ZXJpYWwnO1xyXG5cclxuXHRcdHRoaXMuY29sb3IgPSBuZXcgQ29sb3IoIDB4ZmZmZmZmICk7XHJcblxyXG5cdFx0dGhpcy5tYXAgPSBudWxsO1xyXG5cclxuXHRcdHRoaXMuYWxwaGFNYXAgPSBudWxsO1xyXG5cclxuXHRcdHRoaXMuc2l6ZSA9IDE7XHJcblx0XHR0aGlzLnNpemVBdHRlbnVhdGlvbiA9IHRydWU7XHJcblxyXG5cdFx0dGhpcy5mb2cgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMuc2V0VmFsdWVzKCBwYXJhbWV0ZXJzICk7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xyXG5cclxuXHRcdHRoaXMuY29sb3IuY29weSggc291cmNlLmNvbG9yICk7XHJcblxyXG5cdFx0dGhpcy5tYXAgPSBzb3VyY2UubWFwO1xyXG5cclxuXHRcdHRoaXMuYWxwaGFNYXAgPSBzb3VyY2UuYWxwaGFNYXA7XHJcblxyXG5cdFx0dGhpcy5zaXplID0gc291cmNlLnNpemU7XHJcblx0XHR0aGlzLnNpemVBdHRlbnVhdGlvbiA9IHNvdXJjZS5zaXplQXR0ZW51YXRpb247XHJcblxyXG5cdFx0dGhpcy5mb2cgPSBzb3VyY2UuZm9nO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBQb2ludHNNYXRlcmlhbCB9O1xyXG4iLCJpbXBvcnQgeyBTcGhlcmUgfSBmcm9tICcuLi9tYXRoL1NwaGVyZS5qcyc7XHJcbmltcG9ydCB7IFJheSB9IGZyb20gJy4uL21hdGgvUmF5LmpzJztcclxuaW1wb3J0IHsgTWF0cml4NCB9IGZyb20gJy4uL21hdGgvTWF0cml4NC5qcyc7XHJcbmltcG9ydCB7IE9iamVjdDNEIH0gZnJvbSAnLi4vY29yZS9PYmplY3QzRC5qcyc7XHJcbmltcG9ydCB7IFZlY3RvcjMgfSBmcm9tICcuLi9tYXRoL1ZlY3RvcjMuanMnO1xyXG5pbXBvcnQgeyBQb2ludHNNYXRlcmlhbCB9IGZyb20gJy4uL21hdGVyaWFscy9Qb2ludHNNYXRlcmlhbC5qcyc7XHJcbmltcG9ydCB7IEJ1ZmZlckdlb21ldHJ5IH0gZnJvbSAnLi4vY29yZS9CdWZmZXJHZW9tZXRyeS5qcyc7XHJcblxyXG5jb25zdCBfaW52ZXJzZU1hdHJpeCA9IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDQoKTtcclxuY29uc3QgX3JheSA9IC8qQF9fUFVSRV9fKi8gbmV3IFJheSgpO1xyXG5jb25zdCBfc3BoZXJlID0gLypAX19QVVJFX18qLyBuZXcgU3BoZXJlKCk7XHJcbmNvbnN0IF9wb3NpdGlvbiA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuXHJcbmNsYXNzIFBvaW50cyBleHRlbmRzIE9iamVjdDNEIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIGdlb21ldHJ5ID0gbmV3IEJ1ZmZlckdlb21ldHJ5KCksIG1hdGVyaWFsID0gbmV3IFBvaW50c01hdGVyaWFsKCkgKSB7XHJcblxyXG5cdFx0c3VwZXIoKTtcclxuXHJcblx0XHR0aGlzLmlzUG9pbnRzID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSAnUG9pbnRzJztcclxuXHJcblx0XHR0aGlzLmdlb21ldHJ5ID0gZ2VvbWV0cnk7XHJcblx0XHR0aGlzLm1hdGVyaWFsID0gbWF0ZXJpYWw7XHJcblxyXG5cdFx0dGhpcy51cGRhdGVNb3JwaFRhcmdldHMoKTtcclxuXHJcblx0fVxyXG5cclxuXHRjb3B5KCBzb3VyY2UsIHJlY3Vyc2l2ZSApIHtcclxuXHJcblx0XHRzdXBlci5jb3B5KCBzb3VyY2UsIHJlY3Vyc2l2ZSApO1xyXG5cclxuXHRcdHRoaXMubWF0ZXJpYWwgPSBBcnJheS5pc0FycmF5KCBzb3VyY2UubWF0ZXJpYWwgKSA/IHNvdXJjZS5tYXRlcmlhbC5zbGljZSgpIDogc291cmNlLm1hdGVyaWFsO1xyXG5cdFx0dGhpcy5nZW9tZXRyeSA9IHNvdXJjZS5nZW9tZXRyeTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRyYXljYXN0KCByYXljYXN0ZXIsIGludGVyc2VjdHMgKSB7XHJcblxyXG5cdFx0Y29uc3QgZ2VvbWV0cnkgPSB0aGlzLmdlb21ldHJ5O1xyXG5cdFx0Y29uc3QgbWF0cml4V29ybGQgPSB0aGlzLm1hdHJpeFdvcmxkO1xyXG5cdFx0Y29uc3QgdGhyZXNob2xkID0gcmF5Y2FzdGVyLnBhcmFtcy5Qb2ludHMudGhyZXNob2xkO1xyXG5cdFx0Y29uc3QgZHJhd1JhbmdlID0gZ2VvbWV0cnkuZHJhd1JhbmdlO1xyXG5cclxuXHRcdC8vIENoZWNraW5nIGJvdW5kaW5nU3BoZXJlIGRpc3RhbmNlIHRvIHJheVxyXG5cclxuXHRcdGlmICggZ2VvbWV0cnkuYm91bmRpbmdTcGhlcmUgPT09IG51bGwgKSBnZW9tZXRyeS5jb21wdXRlQm91bmRpbmdTcGhlcmUoKTtcclxuXHJcblx0XHRfc3BoZXJlLmNvcHkoIGdlb21ldHJ5LmJvdW5kaW5nU3BoZXJlICk7XHJcblx0XHRfc3BoZXJlLmFwcGx5TWF0cml4NCggbWF0cml4V29ybGQgKTtcclxuXHRcdF9zcGhlcmUucmFkaXVzICs9IHRocmVzaG9sZDtcclxuXHJcblx0XHRpZiAoIHJheWNhc3Rlci5yYXkuaW50ZXJzZWN0c1NwaGVyZSggX3NwaGVyZSApID09PSBmYWxzZSApIHJldHVybjtcclxuXHJcblx0XHQvL1xyXG5cclxuXHRcdF9pbnZlcnNlTWF0cml4LmNvcHkoIG1hdHJpeFdvcmxkICkuaW52ZXJ0KCk7XHJcblx0XHRfcmF5LmNvcHkoIHJheWNhc3Rlci5yYXkgKS5hcHBseU1hdHJpeDQoIF9pbnZlcnNlTWF0cml4ICk7XHJcblxyXG5cdFx0Y29uc3QgbG9jYWxUaHJlc2hvbGQgPSB0aHJlc2hvbGQgLyAoICggdGhpcy5zY2FsZS54ICsgdGhpcy5zY2FsZS55ICsgdGhpcy5zY2FsZS56ICkgLyAzICk7XHJcblx0XHRjb25zdCBsb2NhbFRocmVzaG9sZFNxID0gbG9jYWxUaHJlc2hvbGQgKiBsb2NhbFRocmVzaG9sZDtcclxuXHJcblx0XHRjb25zdCBpbmRleCA9IGdlb21ldHJ5LmluZGV4O1xyXG5cdFx0Y29uc3QgYXR0cmlidXRlcyA9IGdlb21ldHJ5LmF0dHJpYnV0ZXM7XHJcblx0XHRjb25zdCBwb3NpdGlvbkF0dHJpYnV0ZSA9IGF0dHJpYnV0ZXMucG9zaXRpb247XHJcblxyXG5cdFx0aWYgKCBpbmRleCAhPT0gbnVsbCApIHtcclxuXHJcblx0XHRcdGNvbnN0IHN0YXJ0ID0gTWF0aC5tYXgoIDAsIGRyYXdSYW5nZS5zdGFydCApO1xyXG5cdFx0XHRjb25zdCBlbmQgPSBNYXRoLm1pbiggaW5kZXguY291bnQsICggZHJhd1JhbmdlLnN0YXJ0ICsgZHJhd1JhbmdlLmNvdW50ICkgKTtcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gc3RhcnQsIGlsID0gZW5kOyBpIDwgaWw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IGEgPSBpbmRleC5nZXRYKCBpICk7XHJcblxyXG5cdFx0XHRcdF9wb3NpdGlvbi5mcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbkF0dHJpYnV0ZSwgYSApO1xyXG5cclxuXHRcdFx0XHR0ZXN0UG9pbnQoIF9wb3NpdGlvbiwgYSwgbG9jYWxUaHJlc2hvbGRTcSwgbWF0cml4V29ybGQsIHJheWNhc3RlciwgaW50ZXJzZWN0cywgdGhpcyApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRjb25zdCBzdGFydCA9IE1hdGgubWF4KCAwLCBkcmF3UmFuZ2Uuc3RhcnQgKTtcclxuXHRcdFx0Y29uc3QgZW5kID0gTWF0aC5taW4oIHBvc2l0aW9uQXR0cmlidXRlLmNvdW50LCAoIGRyYXdSYW5nZS5zdGFydCArIGRyYXdSYW5nZS5jb3VudCApICk7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IHN0YXJ0LCBsID0gZW5kOyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0X3Bvc2l0aW9uLmZyb21CdWZmZXJBdHRyaWJ1dGUoIHBvc2l0aW9uQXR0cmlidXRlLCBpICk7XHJcblxyXG5cdFx0XHRcdHRlc3RQb2ludCggX3Bvc2l0aW9uLCBpLCBsb2NhbFRocmVzaG9sZFNxLCBtYXRyaXhXb3JsZCwgcmF5Y2FzdGVyLCBpbnRlcnNlY3RzLCB0aGlzICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdHVwZGF0ZU1vcnBoVGFyZ2V0cygpIHtcclxuXHJcblx0XHRjb25zdCBnZW9tZXRyeSA9IHRoaXMuZ2VvbWV0cnk7XHJcblxyXG5cdFx0Y29uc3QgbW9ycGhBdHRyaWJ1dGVzID0gZ2VvbWV0cnkubW9ycGhBdHRyaWJ1dGVzO1xyXG5cdFx0Y29uc3Qga2V5cyA9IE9iamVjdC5rZXlzKCBtb3JwaEF0dHJpYnV0ZXMgKTtcclxuXHJcblx0XHRpZiAoIGtleXMubGVuZ3RoID4gMCApIHtcclxuXHJcblx0XHRcdGNvbnN0IG1vcnBoQXR0cmlidXRlID0gbW9ycGhBdHRyaWJ1dGVzWyBrZXlzWyAwIF0gXTtcclxuXHJcblx0XHRcdGlmICggbW9ycGhBdHRyaWJ1dGUgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0dGhpcy5tb3JwaFRhcmdldEluZmx1ZW5jZXMgPSBbXTtcclxuXHRcdFx0XHR0aGlzLm1vcnBoVGFyZ2V0RGljdGlvbmFyeSA9IHt9O1xyXG5cclxuXHRcdFx0XHRmb3IgKCBsZXQgbSA9IDAsIG1sID0gbW9ycGhBdHRyaWJ1dGUubGVuZ3RoOyBtIDwgbWw7IG0gKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgbmFtZSA9IG1vcnBoQXR0cmlidXRlWyBtIF0ubmFtZSB8fCBTdHJpbmcoIG0gKTtcclxuXHJcblx0XHRcdFx0XHR0aGlzLm1vcnBoVGFyZ2V0SW5mbHVlbmNlcy5wdXNoKCAwICk7XHJcblx0XHRcdFx0XHR0aGlzLm1vcnBoVGFyZ2V0RGljdGlvbmFyeVsgbmFtZSBdID0gbTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gdGVzdFBvaW50KCBwb2ludCwgaW5kZXgsIGxvY2FsVGhyZXNob2xkU3EsIG1hdHJpeFdvcmxkLCByYXljYXN0ZXIsIGludGVyc2VjdHMsIG9iamVjdCApIHtcclxuXHJcblx0Y29uc3QgcmF5UG9pbnREaXN0YW5jZVNxID0gX3JheS5kaXN0YW5jZVNxVG9Qb2ludCggcG9pbnQgKTtcclxuXHJcblx0aWYgKCByYXlQb2ludERpc3RhbmNlU3EgPCBsb2NhbFRocmVzaG9sZFNxICkge1xyXG5cclxuXHRcdGNvbnN0IGludGVyc2VjdFBvaW50ID0gbmV3IFZlY3RvcjMoKTtcclxuXHJcblx0XHRfcmF5LmNsb3Nlc3RQb2ludFRvUG9pbnQoIHBvaW50LCBpbnRlcnNlY3RQb2ludCApO1xyXG5cdFx0aW50ZXJzZWN0UG9pbnQuYXBwbHlNYXRyaXg0KCBtYXRyaXhXb3JsZCApO1xyXG5cclxuXHRcdGNvbnN0IGRpc3RhbmNlID0gcmF5Y2FzdGVyLnJheS5vcmlnaW4uZGlzdGFuY2VUbyggaW50ZXJzZWN0UG9pbnQgKTtcclxuXHJcblx0XHRpZiAoIGRpc3RhbmNlIDwgcmF5Y2FzdGVyLm5lYXIgfHwgZGlzdGFuY2UgPiByYXljYXN0ZXIuZmFyICkgcmV0dXJuO1xyXG5cclxuXHRcdGludGVyc2VjdHMucHVzaCgge1xyXG5cclxuXHRcdFx0ZGlzdGFuY2U6IGRpc3RhbmNlLFxyXG5cdFx0XHRkaXN0YW5jZVRvUmF5OiBNYXRoLnNxcnQoIHJheVBvaW50RGlzdGFuY2VTcSApLFxyXG5cdFx0XHRwb2ludDogaW50ZXJzZWN0UG9pbnQsXHJcblx0XHRcdGluZGV4OiBpbmRleCxcclxuXHRcdFx0ZmFjZTogbnVsbCxcclxuXHRcdFx0b2JqZWN0OiBvYmplY3RcclxuXHJcblx0XHR9ICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IFBvaW50cyB9O1xyXG4iLCJpbXBvcnQgeyBMaW5lYXJGaWx0ZXIgfSBmcm9tICcuLi9jb25zdGFudHMuanMnO1xyXG5pbXBvcnQgeyBUZXh0dXJlIH0gZnJvbSAnLi9UZXh0dXJlLmpzJztcclxuXHJcbmNsYXNzIFZpZGVvVGV4dHVyZSBleHRlbmRzIFRleHR1cmUge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggdmlkZW8sIG1hcHBpbmcsIHdyYXBTLCB3cmFwVCwgbWFnRmlsdGVyLCBtaW5GaWx0ZXIsIGZvcm1hdCwgdHlwZSwgYW5pc290cm9weSApIHtcclxuXHJcblx0XHRzdXBlciggdmlkZW8sIG1hcHBpbmcsIHdyYXBTLCB3cmFwVCwgbWFnRmlsdGVyLCBtaW5GaWx0ZXIsIGZvcm1hdCwgdHlwZSwgYW5pc290cm9weSApO1xyXG5cclxuXHRcdHRoaXMuaXNWaWRlb1RleHR1cmUgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMubWluRmlsdGVyID0gbWluRmlsdGVyICE9PSB1bmRlZmluZWQgPyBtaW5GaWx0ZXIgOiBMaW5lYXJGaWx0ZXI7XHJcblx0XHR0aGlzLm1hZ0ZpbHRlciA9IG1hZ0ZpbHRlciAhPT0gdW5kZWZpbmVkID8gbWFnRmlsdGVyIDogTGluZWFyRmlsdGVyO1xyXG5cclxuXHRcdHRoaXMuZ2VuZXJhdGVNaXBtYXBzID0gZmFsc2U7XHJcblxyXG5cdFx0Y29uc3Qgc2NvcGUgPSB0aGlzO1xyXG5cclxuXHRcdGZ1bmN0aW9uIHVwZGF0ZVZpZGVvKCkge1xyXG5cclxuXHRcdFx0c2NvcGUubmVlZHNVcGRhdGUgPSB0cnVlO1xyXG5cdFx0XHR2aWRlby5yZXF1ZXN0VmlkZW9GcmFtZUNhbGxiYWNrKCB1cGRhdGVWaWRlbyApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoICdyZXF1ZXN0VmlkZW9GcmFtZUNhbGxiYWNrJyBpbiB2aWRlbyApIHtcclxuXHJcblx0XHRcdHZpZGVvLnJlcXVlc3RWaWRlb0ZyYW1lQ2FsbGJhY2soIHVwZGF0ZVZpZGVvICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGNsb25lKCkge1xyXG5cclxuXHRcdHJldHVybiBuZXcgdGhpcy5jb25zdHJ1Y3RvciggdGhpcy5pbWFnZSApLmNvcHkoIHRoaXMgKTtcclxuXHJcblx0fVxyXG5cclxuXHR1cGRhdGUoKSB7XHJcblxyXG5cdFx0Y29uc3QgdmlkZW8gPSB0aGlzLmltYWdlO1xyXG5cdFx0Y29uc3QgaGFzVmlkZW9GcmFtZUNhbGxiYWNrID0gJ3JlcXVlc3RWaWRlb0ZyYW1lQ2FsbGJhY2snIGluIHZpZGVvO1xyXG5cclxuXHRcdGlmICggaGFzVmlkZW9GcmFtZUNhbGxiYWNrID09PSBmYWxzZSAmJiB2aWRlby5yZWFkeVN0YXRlID49IHZpZGVvLkhBVkVfQ1VSUkVOVF9EQVRBICkge1xyXG5cclxuXHRcdFx0dGhpcy5uZWVkc1VwZGF0ZSA9IHRydWU7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBWaWRlb1RleHR1cmUgfTtcclxuIiwiaW1wb3J0IHsgVGV4dHVyZSB9IGZyb20gJy4vVGV4dHVyZS5qcyc7XHJcbmltcG9ydCB7IE5lYXJlc3RGaWx0ZXIgfSBmcm9tICcuLi9jb25zdGFudHMuanMnO1xyXG5cclxuY2xhc3MgRnJhbWVidWZmZXJUZXh0dXJlIGV4dGVuZHMgVGV4dHVyZSB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCB3aWR0aCwgaGVpZ2h0ICkge1xyXG5cclxuXHRcdHN1cGVyKCB7IHdpZHRoLCBoZWlnaHQgfSApO1xyXG5cclxuXHRcdHRoaXMuaXNGcmFtZWJ1ZmZlclRleHR1cmUgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMubWFnRmlsdGVyID0gTmVhcmVzdEZpbHRlcjtcclxuXHRcdHRoaXMubWluRmlsdGVyID0gTmVhcmVzdEZpbHRlcjtcclxuXHJcblx0XHR0aGlzLmdlbmVyYXRlTWlwbWFwcyA9IGZhbHNlO1xyXG5cclxuXHRcdHRoaXMubmVlZHNVcGRhdGUgPSB0cnVlO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBGcmFtZWJ1ZmZlclRleHR1cmUgfTtcclxuIiwiaW1wb3J0IHsgVGV4dHVyZSB9IGZyb20gJy4vVGV4dHVyZS5qcyc7XHJcblxyXG5jbGFzcyBDb21wcmVzc2VkVGV4dHVyZSBleHRlbmRzIFRleHR1cmUge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggbWlwbWFwcywgd2lkdGgsIGhlaWdodCwgZm9ybWF0LCB0eXBlLCBtYXBwaW5nLCB3cmFwUywgd3JhcFQsIG1hZ0ZpbHRlciwgbWluRmlsdGVyLCBhbmlzb3Ryb3B5LCBjb2xvclNwYWNlICkge1xyXG5cclxuXHRcdHN1cGVyKCBudWxsLCBtYXBwaW5nLCB3cmFwUywgd3JhcFQsIG1hZ0ZpbHRlciwgbWluRmlsdGVyLCBmb3JtYXQsIHR5cGUsIGFuaXNvdHJvcHksIGNvbG9yU3BhY2UgKTtcclxuXHJcblx0XHR0aGlzLmlzQ29tcHJlc3NlZFRleHR1cmUgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMuaW1hZ2UgPSB7IHdpZHRoOiB3aWR0aCwgaGVpZ2h0OiBoZWlnaHQgfTtcclxuXHRcdHRoaXMubWlwbWFwcyA9IG1pcG1hcHM7XHJcblxyXG5cdFx0Ly8gbm8gZmxpcHBpbmcgZm9yIGN1YmUgdGV4dHVyZXNcclxuXHRcdC8vIChhbHNvIGZsaXBwaW5nIGRvZXNuJ3Qgd29yayBmb3IgY29tcHJlc3NlZCB0ZXh0dXJlcyApXHJcblxyXG5cdFx0dGhpcy5mbGlwWSA9IGZhbHNlO1xyXG5cclxuXHRcdC8vIGNhbid0IGdlbmVyYXRlIG1pcG1hcHMgZm9yIGNvbXByZXNzZWQgdGV4dHVyZXNcclxuXHRcdC8vIG1pcHMgbXVzdCBiZSBlbWJlZGRlZCBpbiBERFMgZmlsZXNcclxuXHJcblx0XHR0aGlzLmdlbmVyYXRlTWlwbWFwcyA9IGZhbHNlO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBDb21wcmVzc2VkVGV4dHVyZSB9O1xyXG4iLCJpbXBvcnQgeyBDbGFtcFRvRWRnZVdyYXBwaW5nIH0gZnJvbSAnLi4vY29uc3RhbnRzLmpzJztcclxuaW1wb3J0IHsgQ29tcHJlc3NlZFRleHR1cmUgfSBmcm9tICcuL0NvbXByZXNzZWRUZXh0dXJlLmpzJztcclxuXHJcbmNsYXNzIENvbXByZXNzZWRBcnJheVRleHR1cmUgZXh0ZW5kcyBDb21wcmVzc2VkVGV4dHVyZSB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBtaXBtYXBzLCB3aWR0aCwgaGVpZ2h0LCBkZXB0aCwgZm9ybWF0LCB0eXBlICkge1xyXG5cclxuXHRcdHN1cGVyKCBtaXBtYXBzLCB3aWR0aCwgaGVpZ2h0LCBmb3JtYXQsIHR5cGUgKTtcclxuXHJcblx0XHR0aGlzLmlzQ29tcHJlc3NlZEFycmF5VGV4dHVyZSA9IHRydWU7XHJcblx0XHR0aGlzLmltYWdlLmRlcHRoID0gZGVwdGg7XHJcblx0XHR0aGlzLndyYXBSID0gQ2xhbXBUb0VkZ2VXcmFwcGluZztcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgQ29tcHJlc3NlZEFycmF5VGV4dHVyZSB9O1xyXG4iLCJpbXBvcnQgeyBDdWJlUmVmbGVjdGlvbk1hcHBpbmcgfSBmcm9tICcuLi9jb25zdGFudHMuanMnO1xyXG5pbXBvcnQgeyBDb21wcmVzc2VkVGV4dHVyZSB9IGZyb20gJy4vQ29tcHJlc3NlZFRleHR1cmUuanMnO1xyXG5cclxuY2xhc3MgQ29tcHJlc3NlZEN1YmVUZXh0dXJlIGV4dGVuZHMgQ29tcHJlc3NlZFRleHR1cmUge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggaW1hZ2VzLCBmb3JtYXQsIHR5cGUgKSB7XHJcblxyXG5cdFx0c3VwZXIoIHVuZGVmaW5lZCwgaW1hZ2VzWyAwIF0ud2lkdGgsIGltYWdlc1sgMCBdLmhlaWdodCwgZm9ybWF0LCB0eXBlLCBDdWJlUmVmbGVjdGlvbk1hcHBpbmcgKTtcclxuXHJcblx0XHR0aGlzLmlzQ29tcHJlc3NlZEN1YmVUZXh0dXJlID0gdHJ1ZTtcclxuXHRcdHRoaXMuaXNDdWJlVGV4dHVyZSA9IHRydWU7XHJcblxyXG5cdFx0dGhpcy5pbWFnZSA9IGltYWdlcztcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgQ29tcHJlc3NlZEN1YmVUZXh0dXJlIH07XHJcbiIsImltcG9ydCB7IFRleHR1cmUgfSBmcm9tICcuL1RleHR1cmUuanMnO1xyXG5cclxuY2xhc3MgQ2FudmFzVGV4dHVyZSBleHRlbmRzIFRleHR1cmUge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggY2FudmFzLCBtYXBwaW5nLCB3cmFwUywgd3JhcFQsIG1hZ0ZpbHRlciwgbWluRmlsdGVyLCBmb3JtYXQsIHR5cGUsIGFuaXNvdHJvcHkgKSB7XHJcblxyXG5cdFx0c3VwZXIoIGNhbnZhcywgbWFwcGluZywgd3JhcFMsIHdyYXBULCBtYWdGaWx0ZXIsIG1pbkZpbHRlciwgZm9ybWF0LCB0eXBlLCBhbmlzb3Ryb3B5ICk7XHJcblxyXG5cdFx0dGhpcy5pc0NhbnZhc1RleHR1cmUgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMubmVlZHNVcGRhdGUgPSB0cnVlO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBDYW52YXNUZXh0dXJlIH07XHJcbiIsImltcG9ydCAqIGFzIE1hdGhVdGlscyBmcm9tICcuLi8uLi9tYXRoL01hdGhVdGlscy5qcyc7XHJcbmltcG9ydCB7IFZlY3RvcjIgfSBmcm9tICcuLi8uLi9tYXRoL1ZlY3RvcjIuanMnO1xyXG5pbXBvcnQgeyBWZWN0b3IzIH0gZnJvbSAnLi4vLi4vbWF0aC9WZWN0b3IzLmpzJztcclxuaW1wb3J0IHsgTWF0cml4NCB9IGZyb20gJy4uLy4uL21hdGgvTWF0cml4NC5qcyc7XHJcblxyXG4vKipcclxuICogRXh0ZW5zaWJsZSBjdXJ2ZSBvYmplY3QuXHJcbiAqXHJcbiAqIFNvbWUgY29tbW9uIG9mIGN1cnZlIG1ldGhvZHM6XHJcbiAqIC5nZXRQb2ludCggdCwgb3B0aW9uYWxUYXJnZXQgKSwgLmdldFRhbmdlbnQoIHQsIG9wdGlvbmFsVGFyZ2V0IClcclxuICogLmdldFBvaW50QXQoIHUsIG9wdGlvbmFsVGFyZ2V0ICksIC5nZXRUYW5nZW50QXQoIHUsIG9wdGlvbmFsVGFyZ2V0IClcclxuICogLmdldFBvaW50cygpLCAuZ2V0U3BhY2VkUG9pbnRzKClcclxuICogLmdldExlbmd0aCgpXHJcbiAqIC51cGRhdGVBcmNMZW5ndGhzKClcclxuICpcclxuICogVGhpcyBmb2xsb3dpbmcgY3VydmVzIGluaGVyaXQgZnJvbSBUSFJFRS5DdXJ2ZTpcclxuICpcclxuICogLS0gMkQgY3VydmVzIC0tXHJcbiAqIFRIUkVFLkFyY0N1cnZlXHJcbiAqIFRIUkVFLkN1YmljQmV6aWVyQ3VydmVcclxuICogVEhSRUUuRWxsaXBzZUN1cnZlXHJcbiAqIFRIUkVFLkxpbmVDdXJ2ZVxyXG4gKiBUSFJFRS5RdWFkcmF0aWNCZXppZXJDdXJ2ZVxyXG4gKiBUSFJFRS5TcGxpbmVDdXJ2ZVxyXG4gKlxyXG4gKiAtLSAzRCBjdXJ2ZXMgLS1cclxuICogVEhSRUUuQ2F0bXVsbFJvbUN1cnZlM1xyXG4gKiBUSFJFRS5DdWJpY0JlemllckN1cnZlM1xyXG4gKiBUSFJFRS5MaW5lQ3VydmUzXHJcbiAqIFRIUkVFLlF1YWRyYXRpY0JlemllckN1cnZlM1xyXG4gKlxyXG4gKiBBIHNlcmllcyBvZiBjdXJ2ZXMgY2FuIGJlIHJlcHJlc2VudGVkIGFzIGEgVEhSRUUuQ3VydmVQYXRoLlxyXG4gKlxyXG4gKiovXHJcblxyXG5jbGFzcyBDdXJ2ZSB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCkge1xyXG5cclxuXHRcdHRoaXMudHlwZSA9ICdDdXJ2ZSc7XHJcblxyXG5cdFx0dGhpcy5hcmNMZW5ndGhEaXZpc2lvbnMgPSAyMDA7XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gVmlydHVhbCBiYXNlIGNsYXNzIG1ldGhvZCB0byBvdmVyd3JpdGUgYW5kIGltcGxlbWVudCBpbiBzdWJjbGFzc2VzXHJcblx0Ly9cdC0gdCBbMCAuLiAxXVxyXG5cclxuXHRnZXRQb2ludCggLyogdCwgb3B0aW9uYWxUYXJnZXQgKi8gKSB7XHJcblxyXG5cdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuQ3VydmU6IC5nZXRQb2ludCgpIG5vdCBpbXBsZW1lbnRlZC4nICk7XHJcblx0XHRyZXR1cm4gbnVsbDtcclxuXHJcblx0fVxyXG5cclxuXHQvLyBHZXQgcG9pbnQgYXQgcmVsYXRpdmUgcG9zaXRpb24gaW4gY3VydmUgYWNjb3JkaW5nIHRvIGFyYyBsZW5ndGhcclxuXHQvLyAtIHUgWzAgLi4gMV1cclxuXHJcblx0Z2V0UG9pbnRBdCggdSwgb3B0aW9uYWxUYXJnZXQgKSB7XHJcblxyXG5cdFx0Y29uc3QgdCA9IHRoaXMuZ2V0VXRvVG1hcHBpbmcoIHUgKTtcclxuXHRcdHJldHVybiB0aGlzLmdldFBvaW50KCB0LCBvcHRpb25hbFRhcmdldCApO1xyXG5cclxuXHR9XHJcblxyXG5cdC8vIEdldCBzZXF1ZW5jZSBvZiBwb2ludHMgdXNpbmcgZ2V0UG9pbnQoIHQgKVxyXG5cclxuXHRnZXRQb2ludHMoIGRpdmlzaW9ucyA9IDUgKSB7XHJcblxyXG5cdFx0Y29uc3QgcG9pbnRzID0gW107XHJcblxyXG5cdFx0Zm9yICggbGV0IGQgPSAwOyBkIDw9IGRpdmlzaW9uczsgZCArKyApIHtcclxuXHJcblx0XHRcdHBvaW50cy5wdXNoKCB0aGlzLmdldFBvaW50KCBkIC8gZGl2aXNpb25zICkgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHBvaW50cztcclxuXHJcblx0fVxyXG5cclxuXHQvLyBHZXQgc2VxdWVuY2Ugb2YgcG9pbnRzIHVzaW5nIGdldFBvaW50QXQoIHUgKVxyXG5cclxuXHRnZXRTcGFjZWRQb2ludHMoIGRpdmlzaW9ucyA9IDUgKSB7XHJcblxyXG5cdFx0Y29uc3QgcG9pbnRzID0gW107XHJcblxyXG5cdFx0Zm9yICggbGV0IGQgPSAwOyBkIDw9IGRpdmlzaW9uczsgZCArKyApIHtcclxuXHJcblx0XHRcdHBvaW50cy5wdXNoKCB0aGlzLmdldFBvaW50QXQoIGQgLyBkaXZpc2lvbnMgKSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gcG9pbnRzO1xyXG5cclxuXHR9XHJcblxyXG5cdC8vIEdldCB0b3RhbCBjdXJ2ZSBhcmMgbGVuZ3RoXHJcblxyXG5cdGdldExlbmd0aCgpIHtcclxuXHJcblx0XHRjb25zdCBsZW5ndGhzID0gdGhpcy5nZXRMZW5ndGhzKCk7XHJcblx0XHRyZXR1cm4gbGVuZ3Roc1sgbGVuZ3Rocy5sZW5ndGggLSAxIF07XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gR2V0IGxpc3Qgb2YgY3VtdWxhdGl2ZSBzZWdtZW50IGxlbmd0aHNcclxuXHJcblx0Z2V0TGVuZ3RocyggZGl2aXNpb25zID0gdGhpcy5hcmNMZW5ndGhEaXZpc2lvbnMgKSB7XHJcblxyXG5cdFx0aWYgKCB0aGlzLmNhY2hlQXJjTGVuZ3RocyAmJlxyXG5cdFx0XHQoIHRoaXMuY2FjaGVBcmNMZW5ndGhzLmxlbmd0aCA9PT0gZGl2aXNpb25zICsgMSApICYmXHJcblx0XHRcdCEgdGhpcy5uZWVkc1VwZGF0ZSApIHtcclxuXHJcblx0XHRcdHJldHVybiB0aGlzLmNhY2hlQXJjTGVuZ3RocztcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5uZWVkc1VwZGF0ZSA9IGZhbHNlO1xyXG5cclxuXHRcdGNvbnN0IGNhY2hlID0gW107XHJcblx0XHRsZXQgY3VycmVudCwgbGFzdCA9IHRoaXMuZ2V0UG9pbnQoIDAgKTtcclxuXHRcdGxldCBzdW0gPSAwO1xyXG5cclxuXHRcdGNhY2hlLnB1c2goIDAgKTtcclxuXHJcblx0XHRmb3IgKCBsZXQgcCA9IDE7IHAgPD0gZGl2aXNpb25zOyBwICsrICkge1xyXG5cclxuXHRcdFx0Y3VycmVudCA9IHRoaXMuZ2V0UG9pbnQoIHAgLyBkaXZpc2lvbnMgKTtcclxuXHRcdFx0c3VtICs9IGN1cnJlbnQuZGlzdGFuY2VUbyggbGFzdCApO1xyXG5cdFx0XHRjYWNoZS5wdXNoKCBzdW0gKTtcclxuXHRcdFx0bGFzdCA9IGN1cnJlbnQ7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMuY2FjaGVBcmNMZW5ndGhzID0gY2FjaGU7XHJcblxyXG5cdFx0cmV0dXJuIGNhY2hlOyAvLyB7IHN1bXM6IGNhY2hlLCBzdW06IHN1bSB9OyBTdW0gaXMgaW4gdGhlIGxhc3QgZWxlbWVudC5cclxuXHJcblx0fVxyXG5cclxuXHR1cGRhdGVBcmNMZW5ndGhzKCkge1xyXG5cclxuXHRcdHRoaXMubmVlZHNVcGRhdGUgPSB0cnVlO1xyXG5cdFx0dGhpcy5nZXRMZW5ndGhzKCk7XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gR2l2ZW4gdSAoIDAgLi4gMSApLCBnZXQgYSB0IHRvIGZpbmQgcC4gVGhpcyBnaXZlcyB5b3UgcG9pbnRzIHdoaWNoIGFyZSBlcXVpZGlzdGFudFxyXG5cclxuXHRnZXRVdG9UbWFwcGluZyggdSwgZGlzdGFuY2UgKSB7XHJcblxyXG5cdFx0Y29uc3QgYXJjTGVuZ3RocyA9IHRoaXMuZ2V0TGVuZ3RocygpO1xyXG5cclxuXHRcdGxldCBpID0gMDtcclxuXHRcdGNvbnN0IGlsID0gYXJjTGVuZ3Rocy5sZW5ndGg7XHJcblxyXG5cdFx0bGV0IHRhcmdldEFyY0xlbmd0aDsgLy8gVGhlIHRhcmdldGVkIHUgZGlzdGFuY2UgdmFsdWUgdG8gZ2V0XHJcblxyXG5cdFx0aWYgKCBkaXN0YW5jZSApIHtcclxuXHJcblx0XHRcdHRhcmdldEFyY0xlbmd0aCA9IGRpc3RhbmNlO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHR0YXJnZXRBcmNMZW5ndGggPSB1ICogYXJjTGVuZ3Roc1sgaWwgLSAxIF07XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIGJpbmFyeSBzZWFyY2ggZm9yIHRoZSBpbmRleCB3aXRoIGxhcmdlc3QgdmFsdWUgc21hbGxlciB0aGFuIHRhcmdldCB1IGRpc3RhbmNlXHJcblxyXG5cdFx0bGV0IGxvdyA9IDAsIGhpZ2ggPSBpbCAtIDEsIGNvbXBhcmlzb247XHJcblxyXG5cdFx0d2hpbGUgKCBsb3cgPD0gaGlnaCApIHtcclxuXHJcblx0XHRcdGkgPSBNYXRoLmZsb29yKCBsb3cgKyAoIGhpZ2ggLSBsb3cgKSAvIDIgKTsgLy8gbGVzcyBsaWtlbHkgdG8gb3ZlcmZsb3csIHRob3VnaCBwcm9iYWJseSBub3QgaXNzdWUgaGVyZSwgSlMgZG9lc24ndCByZWFsbHkgaGF2ZSBpbnRlZ2VycywgYWxsIG51bWJlcnMgYXJlIGZsb2F0c1xyXG5cclxuXHRcdFx0Y29tcGFyaXNvbiA9IGFyY0xlbmd0aHNbIGkgXSAtIHRhcmdldEFyY0xlbmd0aDtcclxuXHJcblx0XHRcdGlmICggY29tcGFyaXNvbiA8IDAgKSB7XHJcblxyXG5cdFx0XHRcdGxvdyA9IGkgKyAxO1xyXG5cclxuXHRcdFx0fSBlbHNlIGlmICggY29tcGFyaXNvbiA+IDAgKSB7XHJcblxyXG5cdFx0XHRcdGhpZ2ggPSBpIC0gMTtcclxuXHJcblx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdGhpZ2ggPSBpO1xyXG5cdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0XHQvLyBET05FXHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGkgPSBoaWdoO1xyXG5cclxuXHRcdGlmICggYXJjTGVuZ3Roc1sgaSBdID09PSB0YXJnZXRBcmNMZW5ndGggKSB7XHJcblxyXG5cdFx0XHRyZXR1cm4gaSAvICggaWwgLSAxICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIHdlIGNvdWxkIGdldCBmaW5lciBncmFpbiBhdCBsZW5ndGhzLCBvciB1c2Ugc2ltcGxlIGludGVycG9sYXRpb24gYmV0d2VlbiB0d28gcG9pbnRzXHJcblxyXG5cdFx0Y29uc3QgbGVuZ3RoQmVmb3JlID0gYXJjTGVuZ3Roc1sgaSBdO1xyXG5cdFx0Y29uc3QgbGVuZ3RoQWZ0ZXIgPSBhcmNMZW5ndGhzWyBpICsgMSBdO1xyXG5cclxuXHRcdGNvbnN0IHNlZ21lbnRMZW5ndGggPSBsZW5ndGhBZnRlciAtIGxlbmd0aEJlZm9yZTtcclxuXHJcblx0XHQvLyBkZXRlcm1pbmUgd2hlcmUgd2UgYXJlIGJldHdlZW4gdGhlICdiZWZvcmUnIGFuZCAnYWZ0ZXInIHBvaW50c1xyXG5cclxuXHRcdGNvbnN0IHNlZ21lbnRGcmFjdGlvbiA9ICggdGFyZ2V0QXJjTGVuZ3RoIC0gbGVuZ3RoQmVmb3JlICkgLyBzZWdtZW50TGVuZ3RoO1xyXG5cclxuXHRcdC8vIGFkZCB0aGF0IGZyYWN0aW9uYWwgYW1vdW50IHRvIHRcclxuXHJcblx0XHRjb25zdCB0ID0gKCBpICsgc2VnbWVudEZyYWN0aW9uICkgLyAoIGlsIC0gMSApO1xyXG5cclxuXHRcdHJldHVybiB0O1xyXG5cclxuXHR9XHJcblxyXG5cdC8vIFJldHVybnMgYSB1bml0IHZlY3RvciB0YW5nZW50IGF0IHRcclxuXHQvLyBJbiBjYXNlIGFueSBzdWIgY3VydmUgZG9lcyBub3QgaW1wbGVtZW50IGl0cyB0YW5nZW50IGRlcml2YXRpb24sXHJcblx0Ly8gMiBwb2ludHMgYSBzbWFsbCBkZWx0YSBhcGFydCB3aWxsIGJlIHVzZWQgdG8gZmluZCBpdHMgZ3JhZGllbnRcclxuXHQvLyB3aGljaCBzZWVtcyB0byBnaXZlIGEgcmVhc29uYWJsZSBhcHByb3hpbWF0aW9uXHJcblxyXG5cdGdldFRhbmdlbnQoIHQsIG9wdGlvbmFsVGFyZ2V0ICkge1xyXG5cclxuXHRcdGNvbnN0IGRlbHRhID0gMC4wMDAxO1xyXG5cdFx0bGV0IHQxID0gdCAtIGRlbHRhO1xyXG5cdFx0bGV0IHQyID0gdCArIGRlbHRhO1xyXG5cclxuXHRcdC8vIENhcHBpbmcgaW4gY2FzZSBvZiBkYW5nZXJcclxuXHJcblx0XHRpZiAoIHQxIDwgMCApIHQxID0gMDtcclxuXHRcdGlmICggdDIgPiAxICkgdDIgPSAxO1xyXG5cclxuXHRcdGNvbnN0IHB0MSA9IHRoaXMuZ2V0UG9pbnQoIHQxICk7XHJcblx0XHRjb25zdCBwdDIgPSB0aGlzLmdldFBvaW50KCB0MiApO1xyXG5cclxuXHRcdGNvbnN0IHRhbmdlbnQgPSBvcHRpb25hbFRhcmdldCB8fCAoICggcHQxLmlzVmVjdG9yMiApID8gbmV3IFZlY3RvcjIoKSA6IG5ldyBWZWN0b3IzKCkgKTtcclxuXHJcblx0XHR0YW5nZW50LmNvcHkoIHB0MiApLnN1YiggcHQxICkubm9ybWFsaXplKCk7XHJcblxyXG5cdFx0cmV0dXJuIHRhbmdlbnQ7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0VGFuZ2VudEF0KCB1LCBvcHRpb25hbFRhcmdldCApIHtcclxuXHJcblx0XHRjb25zdCB0ID0gdGhpcy5nZXRVdG9UbWFwcGluZyggdSApO1xyXG5cdFx0cmV0dXJuIHRoaXMuZ2V0VGFuZ2VudCggdCwgb3B0aW9uYWxUYXJnZXQgKTtcclxuXHJcblx0fVxyXG5cclxuXHRjb21wdXRlRnJlbmV0RnJhbWVzKCBzZWdtZW50cywgY2xvc2VkICkge1xyXG5cclxuXHRcdC8vIHNlZSBodHRwOi8vd3d3LmNzLmluZGlhbmEuZWR1L3B1Yi90ZWNocmVwb3J0cy9UUjQyNS5wZGZcclxuXHJcblx0XHRjb25zdCBub3JtYWwgPSBuZXcgVmVjdG9yMygpO1xyXG5cclxuXHRcdGNvbnN0IHRhbmdlbnRzID0gW107XHJcblx0XHRjb25zdCBub3JtYWxzID0gW107XHJcblx0XHRjb25zdCBiaW5vcm1hbHMgPSBbXTtcclxuXHJcblx0XHRjb25zdCB2ZWMgPSBuZXcgVmVjdG9yMygpO1xyXG5cdFx0Y29uc3QgbWF0ID0gbmV3IE1hdHJpeDQoKTtcclxuXHJcblx0XHQvLyBjb21wdXRlIHRoZSB0YW5nZW50IHZlY3RvcnMgZm9yIGVhY2ggc2VnbWVudCBvbiB0aGUgY3VydmVcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPD0gc2VnbWVudHM7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRjb25zdCB1ID0gaSAvIHNlZ21lbnRzO1xyXG5cclxuXHRcdFx0dGFuZ2VudHNbIGkgXSA9IHRoaXMuZ2V0VGFuZ2VudEF0KCB1LCBuZXcgVmVjdG9yMygpICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIHNlbGVjdCBhbiBpbml0aWFsIG5vcm1hbCB2ZWN0b3IgcGVycGVuZGljdWxhciB0byB0aGUgZmlyc3QgdGFuZ2VudCB2ZWN0b3IsXHJcblx0XHQvLyBhbmQgaW4gdGhlIGRpcmVjdGlvbiBvZiB0aGUgbWluaW11bSB0YW5nZW50IHh5eiBjb21wb25lbnRcclxuXHJcblx0XHRub3JtYWxzWyAwIF0gPSBuZXcgVmVjdG9yMygpO1xyXG5cdFx0Ymlub3JtYWxzWyAwIF0gPSBuZXcgVmVjdG9yMygpO1xyXG5cdFx0bGV0IG1pbiA9IE51bWJlci5NQVhfVkFMVUU7XHJcblx0XHRjb25zdCB0eCA9IE1hdGguYWJzKCB0YW5nZW50c1sgMCBdLnggKTtcclxuXHRcdGNvbnN0IHR5ID0gTWF0aC5hYnMoIHRhbmdlbnRzWyAwIF0ueSApO1xyXG5cdFx0Y29uc3QgdHogPSBNYXRoLmFicyggdGFuZ2VudHNbIDAgXS56ICk7XHJcblxyXG5cdFx0aWYgKCB0eCA8PSBtaW4gKSB7XHJcblxyXG5cdFx0XHRtaW4gPSB0eDtcclxuXHRcdFx0bm9ybWFsLnNldCggMSwgMCwgMCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHR5IDw9IG1pbiApIHtcclxuXHJcblx0XHRcdG1pbiA9IHR5O1xyXG5cdFx0XHRub3JtYWwuc2V0KCAwLCAxLCAwICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggdHogPD0gbWluICkge1xyXG5cclxuXHRcdFx0bm9ybWFsLnNldCggMCwgMCwgMSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHR2ZWMuY3Jvc3NWZWN0b3JzKCB0YW5nZW50c1sgMCBdLCBub3JtYWwgKS5ub3JtYWxpemUoKTtcclxuXHJcblx0XHRub3JtYWxzWyAwIF0uY3Jvc3NWZWN0b3JzKCB0YW5nZW50c1sgMCBdLCB2ZWMgKTtcclxuXHRcdGJpbm9ybWFsc1sgMCBdLmNyb3NzVmVjdG9ycyggdGFuZ2VudHNbIDAgXSwgbm9ybWFsc1sgMCBdICk7XHJcblxyXG5cclxuXHRcdC8vIGNvbXB1dGUgdGhlIHNsb3dseS12YXJ5aW5nIG5vcm1hbCBhbmQgYmlub3JtYWwgdmVjdG9ycyBmb3IgZWFjaCBzZWdtZW50IG9uIHRoZSBjdXJ2ZVxyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMTsgaSA8PSBzZWdtZW50czsgaSArKyApIHtcclxuXHJcblx0XHRcdG5vcm1hbHNbIGkgXSA9IG5vcm1hbHNbIGkgLSAxIF0uY2xvbmUoKTtcclxuXHJcblx0XHRcdGJpbm9ybWFsc1sgaSBdID0gYmlub3JtYWxzWyBpIC0gMSBdLmNsb25lKCk7XHJcblxyXG5cdFx0XHR2ZWMuY3Jvc3NWZWN0b3JzKCB0YW5nZW50c1sgaSAtIDEgXSwgdGFuZ2VudHNbIGkgXSApO1xyXG5cclxuXHRcdFx0aWYgKCB2ZWMubGVuZ3RoKCkgPiBOdW1iZXIuRVBTSUxPTiApIHtcclxuXHJcblx0XHRcdFx0dmVjLm5vcm1hbGl6ZSgpO1xyXG5cclxuXHRcdFx0XHRjb25zdCB0aGV0YSA9IE1hdGguYWNvcyggTWF0aFV0aWxzLmNsYW1wKCB0YW5nZW50c1sgaSAtIDEgXS5kb3QoIHRhbmdlbnRzWyBpIF0gKSwgLSAxLCAxICkgKTsgLy8gY2xhbXAgZm9yIGZsb2F0aW5nIHB0IGVycm9yc1xyXG5cclxuXHRcdFx0XHRub3JtYWxzWyBpIF0uYXBwbHlNYXRyaXg0KCBtYXQubWFrZVJvdGF0aW9uQXhpcyggdmVjLCB0aGV0YSApICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRiaW5vcm1hbHNbIGkgXS5jcm9zc1ZlY3RvcnMoIHRhbmdlbnRzWyBpIF0sIG5vcm1hbHNbIGkgXSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvLyBpZiB0aGUgY3VydmUgaXMgY2xvc2VkLCBwb3N0cHJvY2VzcyB0aGUgdmVjdG9ycyBzbyB0aGUgZmlyc3QgYW5kIGxhc3Qgbm9ybWFsIHZlY3RvcnMgYXJlIHRoZSBzYW1lXHJcblxyXG5cdFx0aWYgKCBjbG9zZWQgPT09IHRydWUgKSB7XHJcblxyXG5cdFx0XHRsZXQgdGhldGEgPSBNYXRoLmFjb3MoIE1hdGhVdGlscy5jbGFtcCggbm9ybWFsc1sgMCBdLmRvdCggbm9ybWFsc1sgc2VnbWVudHMgXSApLCAtIDEsIDEgKSApO1xyXG5cdFx0XHR0aGV0YSAvPSBzZWdtZW50cztcclxuXHJcblx0XHRcdGlmICggdGFuZ2VudHNbIDAgXS5kb3QoIHZlYy5jcm9zc1ZlY3RvcnMoIG5vcm1hbHNbIDAgXSwgbm9ybWFsc1sgc2VnbWVudHMgXSApICkgPiAwICkge1xyXG5cclxuXHRcdFx0XHR0aGV0YSA9IC0gdGhldGE7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDE7IGkgPD0gc2VnbWVudHM7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdC8vIHR3aXN0IGEgbGl0dGxlLi4uXHJcblx0XHRcdFx0bm9ybWFsc1sgaSBdLmFwcGx5TWF0cml4NCggbWF0Lm1ha2VSb3RhdGlvbkF4aXMoIHRhbmdlbnRzWyBpIF0sIHRoZXRhICogaSApICk7XHJcblx0XHRcdFx0Ymlub3JtYWxzWyBpIF0uY3Jvc3NWZWN0b3JzKCB0YW5nZW50c1sgaSBdLCBub3JtYWxzWyBpIF0gKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHtcclxuXHRcdFx0dGFuZ2VudHM6IHRhbmdlbnRzLFxyXG5cdFx0XHRub3JtYWxzOiBub3JtYWxzLFxyXG5cdFx0XHRiaW5vcm1hbHM6IGJpbm9ybWFsc1xyXG5cdFx0fTtcclxuXHJcblx0fVxyXG5cclxuXHRjbG9uZSgpIHtcclxuXHJcblx0XHRyZXR1cm4gbmV3IHRoaXMuY29uc3RydWN0b3IoKS5jb3B5KCB0aGlzICk7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHRoaXMuYXJjTGVuZ3RoRGl2aXNpb25zID0gc291cmNlLmFyY0xlbmd0aERpdmlzaW9ucztcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHR0b0pTT04oKSB7XHJcblxyXG5cdFx0Y29uc3QgZGF0YSA9IHtcclxuXHRcdFx0bWV0YWRhdGE6IHtcclxuXHRcdFx0XHR2ZXJzaW9uOiA0LjYsXHJcblx0XHRcdFx0dHlwZTogJ0N1cnZlJyxcclxuXHRcdFx0XHRnZW5lcmF0b3I6ICdDdXJ2ZS50b0pTT04nXHJcblx0XHRcdH1cclxuXHRcdH07XHJcblxyXG5cdFx0ZGF0YS5hcmNMZW5ndGhEaXZpc2lvbnMgPSB0aGlzLmFyY0xlbmd0aERpdmlzaW9ucztcclxuXHRcdGRhdGEudHlwZSA9IHRoaXMudHlwZTtcclxuXHJcblx0XHRyZXR1cm4gZGF0YTtcclxuXHJcblx0fVxyXG5cclxuXHRmcm9tSlNPTigganNvbiApIHtcclxuXHJcblx0XHR0aGlzLmFyY0xlbmd0aERpdmlzaW9ucyA9IGpzb24uYXJjTGVuZ3RoRGl2aXNpb25zO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5cclxuZXhwb3J0IHsgQ3VydmUgfTtcclxuIiwiaW1wb3J0IHsgQ3VydmUgfSBmcm9tICcuLi9jb3JlL0N1cnZlLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yMiB9IGZyb20gJy4uLy4uL21hdGgvVmVjdG9yMi5qcyc7XHJcblxyXG5jbGFzcyBFbGxpcHNlQ3VydmUgZXh0ZW5kcyBDdXJ2ZSB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBhWCA9IDAsIGFZID0gMCwgeFJhZGl1cyA9IDEsIHlSYWRpdXMgPSAxLCBhU3RhcnRBbmdsZSA9IDAsIGFFbmRBbmdsZSA9IE1hdGguUEkgKiAyLCBhQ2xvY2t3aXNlID0gZmFsc2UsIGFSb3RhdGlvbiA9IDAgKSB7XHJcblxyXG5cdFx0c3VwZXIoKTtcclxuXHJcblx0XHR0aGlzLmlzRWxsaXBzZUN1cnZlID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSAnRWxsaXBzZUN1cnZlJztcclxuXHJcblx0XHR0aGlzLmFYID0gYVg7XHJcblx0XHR0aGlzLmFZID0gYVk7XHJcblxyXG5cdFx0dGhpcy54UmFkaXVzID0geFJhZGl1cztcclxuXHRcdHRoaXMueVJhZGl1cyA9IHlSYWRpdXM7XHJcblxyXG5cdFx0dGhpcy5hU3RhcnRBbmdsZSA9IGFTdGFydEFuZ2xlO1xyXG5cdFx0dGhpcy5hRW5kQW5nbGUgPSBhRW5kQW5nbGU7XHJcblxyXG5cdFx0dGhpcy5hQ2xvY2t3aXNlID0gYUNsb2Nrd2lzZTtcclxuXHJcblx0XHR0aGlzLmFSb3RhdGlvbiA9IGFSb3RhdGlvbjtcclxuXHJcblx0fVxyXG5cclxuXHRnZXRQb2ludCggdCwgb3B0aW9uYWxUYXJnZXQgKSB7XHJcblxyXG5cdFx0Y29uc3QgcG9pbnQgPSBvcHRpb25hbFRhcmdldCB8fCBuZXcgVmVjdG9yMigpO1xyXG5cclxuXHRcdGNvbnN0IHR3b1BpID0gTWF0aC5QSSAqIDI7XHJcblx0XHRsZXQgZGVsdGFBbmdsZSA9IHRoaXMuYUVuZEFuZ2xlIC0gdGhpcy5hU3RhcnRBbmdsZTtcclxuXHRcdGNvbnN0IHNhbWVQb2ludHMgPSBNYXRoLmFicyggZGVsdGFBbmdsZSApIDwgTnVtYmVyLkVQU0lMT047XHJcblxyXG5cdFx0Ly8gZW5zdXJlcyB0aGF0IGRlbHRhQW5nbGUgaXMgMCAuLiAyIFBJXHJcblx0XHR3aGlsZSAoIGRlbHRhQW5nbGUgPCAwICkgZGVsdGFBbmdsZSArPSB0d29QaTtcclxuXHRcdHdoaWxlICggZGVsdGFBbmdsZSA+IHR3b1BpICkgZGVsdGFBbmdsZSAtPSB0d29QaTtcclxuXHJcblx0XHRpZiAoIGRlbHRhQW5nbGUgPCBOdW1iZXIuRVBTSUxPTiApIHtcclxuXHJcblx0XHRcdGlmICggc2FtZVBvaW50cyApIHtcclxuXHJcblx0XHRcdFx0ZGVsdGFBbmdsZSA9IDA7XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRkZWx0YUFuZ2xlID0gdHdvUGk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggdGhpcy5hQ2xvY2t3aXNlID09PSB0cnVlICYmICEgc2FtZVBvaW50cyApIHtcclxuXHJcblx0XHRcdGlmICggZGVsdGFBbmdsZSA9PT0gdHdvUGkgKSB7XHJcblxyXG5cdFx0XHRcdGRlbHRhQW5nbGUgPSAtIHR3b1BpO1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0ZGVsdGFBbmdsZSA9IGRlbHRhQW5nbGUgLSB0d29QaTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Y29uc3QgYW5nbGUgPSB0aGlzLmFTdGFydEFuZ2xlICsgdCAqIGRlbHRhQW5nbGU7XHJcblx0XHRsZXQgeCA9IHRoaXMuYVggKyB0aGlzLnhSYWRpdXMgKiBNYXRoLmNvcyggYW5nbGUgKTtcclxuXHRcdGxldCB5ID0gdGhpcy5hWSArIHRoaXMueVJhZGl1cyAqIE1hdGguc2luKCBhbmdsZSApO1xyXG5cclxuXHRcdGlmICggdGhpcy5hUm90YXRpb24gIT09IDAgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBjb3MgPSBNYXRoLmNvcyggdGhpcy5hUm90YXRpb24gKTtcclxuXHRcdFx0Y29uc3Qgc2luID0gTWF0aC5zaW4oIHRoaXMuYVJvdGF0aW9uICk7XHJcblxyXG5cdFx0XHRjb25zdCB0eCA9IHggLSB0aGlzLmFYO1xyXG5cdFx0XHRjb25zdCB0eSA9IHkgLSB0aGlzLmFZO1xyXG5cclxuXHRcdFx0Ly8gUm90YXRlIHRoZSBwb2ludCBhYm91dCB0aGUgY2VudGVyIG9mIHRoZSBlbGxpcHNlLlxyXG5cdFx0XHR4ID0gdHggKiBjb3MgLSB0eSAqIHNpbiArIHRoaXMuYVg7XHJcblx0XHRcdHkgPSB0eCAqIHNpbiArIHR5ICogY29zICsgdGhpcy5hWTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHBvaW50LnNldCggeCwgeSApO1xyXG5cclxuXHR9XHJcblxyXG5cdGNvcHkoIHNvdXJjZSApIHtcclxuXHJcblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcclxuXHJcblx0XHR0aGlzLmFYID0gc291cmNlLmFYO1xyXG5cdFx0dGhpcy5hWSA9IHNvdXJjZS5hWTtcclxuXHJcblx0XHR0aGlzLnhSYWRpdXMgPSBzb3VyY2UueFJhZGl1cztcclxuXHRcdHRoaXMueVJhZGl1cyA9IHNvdXJjZS55UmFkaXVzO1xyXG5cclxuXHRcdHRoaXMuYVN0YXJ0QW5nbGUgPSBzb3VyY2UuYVN0YXJ0QW5nbGU7XHJcblx0XHR0aGlzLmFFbmRBbmdsZSA9IHNvdXJjZS5hRW5kQW5nbGU7XHJcblxyXG5cdFx0dGhpcy5hQ2xvY2t3aXNlID0gc291cmNlLmFDbG9ja3dpc2U7XHJcblxyXG5cdFx0dGhpcy5hUm90YXRpb24gPSBzb3VyY2UuYVJvdGF0aW9uO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHRvSlNPTigpIHtcclxuXHJcblx0XHRjb25zdCBkYXRhID0gc3VwZXIudG9KU09OKCk7XHJcblxyXG5cdFx0ZGF0YS5hWCA9IHRoaXMuYVg7XHJcblx0XHRkYXRhLmFZID0gdGhpcy5hWTtcclxuXHJcblx0XHRkYXRhLnhSYWRpdXMgPSB0aGlzLnhSYWRpdXM7XHJcblx0XHRkYXRhLnlSYWRpdXMgPSB0aGlzLnlSYWRpdXM7XHJcblxyXG5cdFx0ZGF0YS5hU3RhcnRBbmdsZSA9IHRoaXMuYVN0YXJ0QW5nbGU7XHJcblx0XHRkYXRhLmFFbmRBbmdsZSA9IHRoaXMuYUVuZEFuZ2xlO1xyXG5cclxuXHRcdGRhdGEuYUNsb2Nrd2lzZSA9IHRoaXMuYUNsb2Nrd2lzZTtcclxuXHJcblx0XHRkYXRhLmFSb3RhdGlvbiA9IHRoaXMuYVJvdGF0aW9uO1xyXG5cclxuXHRcdHJldHVybiBkYXRhO1xyXG5cclxuXHR9XHJcblxyXG5cdGZyb21KU09OKCBqc29uICkge1xyXG5cclxuXHRcdHN1cGVyLmZyb21KU09OKCBqc29uICk7XHJcblxyXG5cdFx0dGhpcy5hWCA9IGpzb24uYVg7XHJcblx0XHR0aGlzLmFZID0ganNvbi5hWTtcclxuXHJcblx0XHR0aGlzLnhSYWRpdXMgPSBqc29uLnhSYWRpdXM7XHJcblx0XHR0aGlzLnlSYWRpdXMgPSBqc29uLnlSYWRpdXM7XHJcblxyXG5cdFx0dGhpcy5hU3RhcnRBbmdsZSA9IGpzb24uYVN0YXJ0QW5nbGU7XHJcblx0XHR0aGlzLmFFbmRBbmdsZSA9IGpzb24uYUVuZEFuZ2xlO1xyXG5cclxuXHRcdHRoaXMuYUNsb2Nrd2lzZSA9IGpzb24uYUNsb2Nrd2lzZTtcclxuXHJcblx0XHR0aGlzLmFSb3RhdGlvbiA9IGpzb24uYVJvdGF0aW9uO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBFbGxpcHNlQ3VydmUgfTtcclxuIiwiaW1wb3J0IHsgRWxsaXBzZUN1cnZlIH0gZnJvbSAnLi9FbGxpcHNlQ3VydmUuanMnO1xyXG5cclxuY2xhc3MgQXJjQ3VydmUgZXh0ZW5kcyBFbGxpcHNlQ3VydmUge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggYVgsIGFZLCBhUmFkaXVzLCBhU3RhcnRBbmdsZSwgYUVuZEFuZ2xlLCBhQ2xvY2t3aXNlICkge1xyXG5cclxuXHRcdHN1cGVyKCBhWCwgYVksIGFSYWRpdXMsIGFSYWRpdXMsIGFTdGFydEFuZ2xlLCBhRW5kQW5nbGUsIGFDbG9ja3dpc2UgKTtcclxuXHJcblx0XHR0aGlzLmlzQXJjQ3VydmUgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMudHlwZSA9ICdBcmNDdXJ2ZSc7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IEFyY0N1cnZlIH07XHJcbiIsImltcG9ydCB7IFZlY3RvcjMgfSBmcm9tICcuLi8uLi9tYXRoL1ZlY3RvcjMuanMnO1xyXG5pbXBvcnQgeyBDdXJ2ZSB9IGZyb20gJy4uL2NvcmUvQ3VydmUuanMnO1xyXG5cclxuLyoqXHJcbiAqIENlbnRyaXBldGFsIENhdG11bGxSb20gQ3VydmUgLSB3aGljaCBpcyB1c2VmdWwgZm9yIGF2b2lkaW5nXHJcbiAqIGN1c3BzIGFuZCBzZWxmLWludGVyc2VjdGlvbnMgaW4gbm9uLXVuaWZvcm0gY2F0bXVsbCByb20gY3VydmVzLlxyXG4gKiBodHRwOi8vd3d3LmNlbXl1a3NlbC5jb20vcmVzZWFyY2gvY2F0bXVsbHJvbV9wYXJhbS9jYXRtdWxscm9tLnBkZlxyXG4gKlxyXG4gKiBjdXJ2ZS50eXBlIGFjY2VwdHMgY2VudHJpcGV0YWwoZGVmYXVsdCksIGNob3JkYWwgYW5kIGNhdG11bGxyb21cclxuICogY3VydmUudGVuc2lvbiBpcyB1c2VkIGZvciBjYXRtdWxscm9tIHdoaWNoIGRlZmF1bHRzIHRvIDAuNVxyXG4gKi9cclxuXHJcblxyXG4vKlxyXG5CYXNlZCBvbiBhbiBvcHRpbWl6ZWQgYysrIHNvbHV0aW9uIGluXHJcbiAtIGh0dHA6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvOTQ4OTczNi9jYXRtdWxsLXJvbS1jdXJ2ZS13aXRoLW5vLWN1c3BzLWFuZC1uby1zZWxmLWludGVyc2VjdGlvbnMvXHJcbiAtIGh0dHA6Ly9pZGVvbmUuY29tL05vRWJWTVxyXG5cclxuVGhpcyBDdWJpY1BvbHkgY2xhc3MgY291bGQgYmUgdXNlZCBmb3IgcmV1c2luZyBzb21lIHZhcmlhYmxlcyBhbmQgY2FsY3VsYXRpb25zLFxyXG5idXQgZm9yIHRocmVlLmpzIGN1cnZlIHVzZSwgaXQgY291bGQgYmUgcG9zc2libGUgaW5saW5lZCBhbmQgZmxhdHRlbiBpbnRvIGEgc2luZ2xlIGZ1bmN0aW9uIGNhbGxcclxud2hpY2ggY2FuIGJlIHBsYWNlZCBpbiBDdXJ2ZVV0aWxzLlxyXG4qL1xyXG5cclxuZnVuY3Rpb24gQ3ViaWNQb2x5KCkge1xyXG5cclxuXHRsZXQgYzAgPSAwLCBjMSA9IDAsIGMyID0gMCwgYzMgPSAwO1xyXG5cclxuXHQvKlxyXG5cdCAqIENvbXB1dGUgY29lZmZpY2llbnRzIGZvciBhIGN1YmljIHBvbHlub21pYWxcclxuXHQgKiAgIHAocykgPSBjMCArIGMxKnMgKyBjMipzXjIgKyBjMypzXjNcclxuXHQgKiBzdWNoIHRoYXRcclxuXHQgKiAgIHAoMCkgPSB4MCwgcCgxKSA9IHgxXHJcblx0ICogIGFuZFxyXG5cdCAqICAgcCcoMCkgPSB0MCwgcCcoMSkgPSB0MS5cclxuXHQgKi9cclxuXHRmdW5jdGlvbiBpbml0KCB4MCwgeDEsIHQwLCB0MSApIHtcclxuXHJcblx0XHRjMCA9IHgwO1xyXG5cdFx0YzEgPSB0MDtcclxuXHRcdGMyID0gLSAzICogeDAgKyAzICogeDEgLSAyICogdDAgLSB0MTtcclxuXHRcdGMzID0gMiAqIHgwIC0gMiAqIHgxICsgdDAgKyB0MTtcclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4ge1xyXG5cclxuXHRcdGluaXRDYXRtdWxsUm9tOiBmdW5jdGlvbiAoIHgwLCB4MSwgeDIsIHgzLCB0ZW5zaW9uICkge1xyXG5cclxuXHRcdFx0aW5pdCggeDEsIHgyLCB0ZW5zaW9uICogKCB4MiAtIHgwICksIHRlbnNpb24gKiAoIHgzIC0geDEgKSApO1xyXG5cclxuXHRcdH0sXHJcblxyXG5cdFx0aW5pdE5vbnVuaWZvcm1DYXRtdWxsUm9tOiBmdW5jdGlvbiAoIHgwLCB4MSwgeDIsIHgzLCBkdDAsIGR0MSwgZHQyICkge1xyXG5cclxuXHRcdFx0Ly8gY29tcHV0ZSB0YW5nZW50cyB3aGVuIHBhcmFtZXRlcml6ZWQgaW4gW3QxLHQyXVxyXG5cdFx0XHRsZXQgdDEgPSAoIHgxIC0geDAgKSAvIGR0MCAtICggeDIgLSB4MCApIC8gKCBkdDAgKyBkdDEgKSArICggeDIgLSB4MSApIC8gZHQxO1xyXG5cdFx0XHRsZXQgdDIgPSAoIHgyIC0geDEgKSAvIGR0MSAtICggeDMgLSB4MSApIC8gKCBkdDEgKyBkdDIgKSArICggeDMgLSB4MiApIC8gZHQyO1xyXG5cclxuXHRcdFx0Ly8gcmVzY2FsZSB0YW5nZW50cyBmb3IgcGFyYW1ldHJpemF0aW9uIGluIFswLDFdXHJcblx0XHRcdHQxICo9IGR0MTtcclxuXHRcdFx0dDIgKj0gZHQxO1xyXG5cclxuXHRcdFx0aW5pdCggeDEsIHgyLCB0MSwgdDIgKTtcclxuXHJcblx0XHR9LFxyXG5cclxuXHRcdGNhbGM6IGZ1bmN0aW9uICggdCApIHtcclxuXHJcblx0XHRcdGNvbnN0IHQyID0gdCAqIHQ7XHJcblx0XHRcdGNvbnN0IHQzID0gdDIgKiB0O1xyXG5cdFx0XHRyZXR1cm4gYzAgKyBjMSAqIHQgKyBjMiAqIHQyICsgYzMgKiB0MztcclxuXHJcblx0XHR9XHJcblxyXG5cdH07XHJcblxyXG59XHJcblxyXG4vL1xyXG5cclxuY29uc3QgdG1wID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5jb25zdCBweCA9IC8qQF9fUFVSRV9fKi8gbmV3IEN1YmljUG9seSgpO1xyXG5jb25zdCBweSA9IC8qQF9fUFVSRV9fKi8gbmV3IEN1YmljUG9seSgpO1xyXG5jb25zdCBweiA9IC8qQF9fUFVSRV9fKi8gbmV3IEN1YmljUG9seSgpO1xyXG5cclxuY2xhc3MgQ2F0bXVsbFJvbUN1cnZlMyBleHRlbmRzIEN1cnZlIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIHBvaW50cyA9IFtdLCBjbG9zZWQgPSBmYWxzZSwgY3VydmVUeXBlID0gJ2NlbnRyaXBldGFsJywgdGVuc2lvbiA9IDAuNSApIHtcclxuXHJcblx0XHRzdXBlcigpO1xyXG5cclxuXHRcdHRoaXMuaXNDYXRtdWxsUm9tQ3VydmUzID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSAnQ2F0bXVsbFJvbUN1cnZlMyc7XHJcblxyXG5cdFx0dGhpcy5wb2ludHMgPSBwb2ludHM7XHJcblx0XHR0aGlzLmNsb3NlZCA9IGNsb3NlZDtcclxuXHRcdHRoaXMuY3VydmVUeXBlID0gY3VydmVUeXBlO1xyXG5cdFx0dGhpcy50ZW5zaW9uID0gdGVuc2lvbjtcclxuXHJcblx0fVxyXG5cclxuXHRnZXRQb2ludCggdCwgb3B0aW9uYWxUYXJnZXQgPSBuZXcgVmVjdG9yMygpICkge1xyXG5cclxuXHRcdGNvbnN0IHBvaW50ID0gb3B0aW9uYWxUYXJnZXQ7XHJcblxyXG5cdFx0Y29uc3QgcG9pbnRzID0gdGhpcy5wb2ludHM7XHJcblx0XHRjb25zdCBsID0gcG9pbnRzLmxlbmd0aDtcclxuXHJcblx0XHRjb25zdCBwID0gKCBsIC0gKCB0aGlzLmNsb3NlZCA/IDAgOiAxICkgKSAqIHQ7XHJcblx0XHRsZXQgaW50UG9pbnQgPSBNYXRoLmZsb29yKCBwICk7XHJcblx0XHRsZXQgd2VpZ2h0ID0gcCAtIGludFBvaW50O1xyXG5cclxuXHRcdGlmICggdGhpcy5jbG9zZWQgKSB7XHJcblxyXG5cdFx0XHRpbnRQb2ludCArPSBpbnRQb2ludCA+IDAgPyAwIDogKCBNYXRoLmZsb29yKCBNYXRoLmFicyggaW50UG9pbnQgKSAvIGwgKSArIDEgKSAqIGw7XHJcblxyXG5cdFx0fSBlbHNlIGlmICggd2VpZ2h0ID09PSAwICYmIGludFBvaW50ID09PSBsIC0gMSApIHtcclxuXHJcblx0XHRcdGludFBvaW50ID0gbCAtIDI7XHJcblx0XHRcdHdlaWdodCA9IDE7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGxldCBwMCwgcDM7IC8vIDQgcG9pbnRzIChwMSAmIHAyIGRlZmluZWQgYmVsb3cpXHJcblxyXG5cdFx0aWYgKCB0aGlzLmNsb3NlZCB8fCBpbnRQb2ludCA+IDAgKSB7XHJcblxyXG5cdFx0XHRwMCA9IHBvaW50c1sgKCBpbnRQb2ludCAtIDEgKSAlIGwgXTtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0Ly8gZXh0cmFwb2xhdGUgZmlyc3QgcG9pbnRcclxuXHRcdFx0dG1wLnN1YlZlY3RvcnMoIHBvaW50c1sgMCBdLCBwb2ludHNbIDEgXSApLmFkZCggcG9pbnRzWyAwIF0gKTtcclxuXHRcdFx0cDAgPSB0bXA7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGNvbnN0IHAxID0gcG9pbnRzWyBpbnRQb2ludCAlIGwgXTtcclxuXHRcdGNvbnN0IHAyID0gcG9pbnRzWyAoIGludFBvaW50ICsgMSApICUgbCBdO1xyXG5cclxuXHRcdGlmICggdGhpcy5jbG9zZWQgfHwgaW50UG9pbnQgKyAyIDwgbCApIHtcclxuXHJcblx0XHRcdHAzID0gcG9pbnRzWyAoIGludFBvaW50ICsgMiApICUgbCBdO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHQvLyBleHRyYXBvbGF0ZSBsYXN0IHBvaW50XHJcblx0XHRcdHRtcC5zdWJWZWN0b3JzKCBwb2ludHNbIGwgLSAxIF0sIHBvaW50c1sgbCAtIDIgXSApLmFkZCggcG9pbnRzWyBsIC0gMSBdICk7XHJcblx0XHRcdHAzID0gdG1wO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHRoaXMuY3VydmVUeXBlID09PSAnY2VudHJpcGV0YWwnIHx8IHRoaXMuY3VydmVUeXBlID09PSAnY2hvcmRhbCcgKSB7XHJcblxyXG5cdFx0XHQvLyBpbml0IENlbnRyaXBldGFsIC8gQ2hvcmRhbCBDYXRtdWxsLVJvbVxyXG5cdFx0XHRjb25zdCBwb3cgPSB0aGlzLmN1cnZlVHlwZSA9PT0gJ2Nob3JkYWwnID8gMC41IDogMC4yNTtcclxuXHRcdFx0bGV0IGR0MCA9IE1hdGgucG93KCBwMC5kaXN0YW5jZVRvU3F1YXJlZCggcDEgKSwgcG93ICk7XHJcblx0XHRcdGxldCBkdDEgPSBNYXRoLnBvdyggcDEuZGlzdGFuY2VUb1NxdWFyZWQoIHAyICksIHBvdyApO1xyXG5cdFx0XHRsZXQgZHQyID0gTWF0aC5wb3coIHAyLmRpc3RhbmNlVG9TcXVhcmVkKCBwMyApLCBwb3cgKTtcclxuXHJcblx0XHRcdC8vIHNhZmV0eSBjaGVjayBmb3IgcmVwZWF0ZWQgcG9pbnRzXHJcblx0XHRcdGlmICggZHQxIDwgMWUtNCApIGR0MSA9IDEuMDtcclxuXHRcdFx0aWYgKCBkdDAgPCAxZS00ICkgZHQwID0gZHQxO1xyXG5cdFx0XHRpZiAoIGR0MiA8IDFlLTQgKSBkdDIgPSBkdDE7XHJcblxyXG5cdFx0XHRweC5pbml0Tm9udW5pZm9ybUNhdG11bGxSb20oIHAwLngsIHAxLngsIHAyLngsIHAzLngsIGR0MCwgZHQxLCBkdDIgKTtcclxuXHRcdFx0cHkuaW5pdE5vbnVuaWZvcm1DYXRtdWxsUm9tKCBwMC55LCBwMS55LCBwMi55LCBwMy55LCBkdDAsIGR0MSwgZHQyICk7XHJcblx0XHRcdHB6LmluaXROb251bmlmb3JtQ2F0bXVsbFJvbSggcDAueiwgcDEueiwgcDIueiwgcDMueiwgZHQwLCBkdDEsIGR0MiApO1xyXG5cclxuXHRcdH0gZWxzZSBpZiAoIHRoaXMuY3VydmVUeXBlID09PSAnY2F0bXVsbHJvbScgKSB7XHJcblxyXG5cdFx0XHRweC5pbml0Q2F0bXVsbFJvbSggcDAueCwgcDEueCwgcDIueCwgcDMueCwgdGhpcy50ZW5zaW9uICk7XHJcblx0XHRcdHB5LmluaXRDYXRtdWxsUm9tKCBwMC55LCBwMS55LCBwMi55LCBwMy55LCB0aGlzLnRlbnNpb24gKTtcclxuXHRcdFx0cHouaW5pdENhdG11bGxSb20oIHAwLnosIHAxLnosIHAyLnosIHAzLnosIHRoaXMudGVuc2lvbiApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRwb2ludC5zZXQoXHJcblx0XHRcdHB4LmNhbGMoIHdlaWdodCApLFxyXG5cdFx0XHRweS5jYWxjKCB3ZWlnaHQgKSxcclxuXHRcdFx0cHouY2FsYyggd2VpZ2h0IClcclxuXHRcdCk7XHJcblxyXG5cdFx0cmV0dXJuIHBvaW50O1xyXG5cclxuXHR9XHJcblxyXG5cdGNvcHkoIHNvdXJjZSApIHtcclxuXHJcblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcclxuXHJcblx0XHR0aGlzLnBvaW50cyA9IFtdO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IHNvdXJjZS5wb2ludHMubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdGNvbnN0IHBvaW50ID0gc291cmNlLnBvaW50c1sgaSBdO1xyXG5cclxuXHRcdFx0dGhpcy5wb2ludHMucHVzaCggcG9pbnQuY2xvbmUoKSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLmNsb3NlZCA9IHNvdXJjZS5jbG9zZWQ7XHJcblx0XHR0aGlzLmN1cnZlVHlwZSA9IHNvdXJjZS5jdXJ2ZVR5cGU7XHJcblx0XHR0aGlzLnRlbnNpb24gPSBzb3VyY2UudGVuc2lvbjtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHR0b0pTT04oKSB7XHJcblxyXG5cdFx0Y29uc3QgZGF0YSA9IHN1cGVyLnRvSlNPTigpO1xyXG5cclxuXHRcdGRhdGEucG9pbnRzID0gW107XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gdGhpcy5wb2ludHMubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdGNvbnN0IHBvaW50ID0gdGhpcy5wb2ludHNbIGkgXTtcclxuXHRcdFx0ZGF0YS5wb2ludHMucHVzaCggcG9pbnQudG9BcnJheSgpICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGRhdGEuY2xvc2VkID0gdGhpcy5jbG9zZWQ7XHJcblx0XHRkYXRhLmN1cnZlVHlwZSA9IHRoaXMuY3VydmVUeXBlO1xyXG5cdFx0ZGF0YS50ZW5zaW9uID0gdGhpcy50ZW5zaW9uO1xyXG5cclxuXHRcdHJldHVybiBkYXRhO1xyXG5cclxuXHR9XHJcblxyXG5cdGZyb21KU09OKCBqc29uICkge1xyXG5cclxuXHRcdHN1cGVyLmZyb21KU09OKCBqc29uICk7XHJcblxyXG5cdFx0dGhpcy5wb2ludHMgPSBbXTtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBqc29uLnBvaW50cy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0Y29uc3QgcG9pbnQgPSBqc29uLnBvaW50c1sgaSBdO1xyXG5cdFx0XHR0aGlzLnBvaW50cy5wdXNoKCBuZXcgVmVjdG9yMygpLmZyb21BcnJheSggcG9pbnQgKSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLmNsb3NlZCA9IGpzb24uY2xvc2VkO1xyXG5cdFx0dGhpcy5jdXJ2ZVR5cGUgPSBqc29uLmN1cnZlVHlwZTtcclxuXHRcdHRoaXMudGVuc2lvbiA9IGpzb24udGVuc2lvbjtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgQ2F0bXVsbFJvbUN1cnZlMyB9O1xyXG4iLCIvKipcclxuICogQmV6aWVyIEN1cnZlcyBmb3JtdWxhcyBvYnRhaW5lZCBmcm9tXHJcbiAqIGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0IlQzMlQTl6aWVyX2N1cnZlXHJcbiAqL1xyXG5cclxuZnVuY3Rpb24gQ2F0bXVsbFJvbSggdCwgcDAsIHAxLCBwMiwgcDMgKSB7XHJcblxyXG5cdGNvbnN0IHYwID0gKCBwMiAtIHAwICkgKiAwLjU7XHJcblx0Y29uc3QgdjEgPSAoIHAzIC0gcDEgKSAqIDAuNTtcclxuXHRjb25zdCB0MiA9IHQgKiB0O1xyXG5cdGNvbnN0IHQzID0gdCAqIHQyO1xyXG5cdHJldHVybiAoIDIgKiBwMSAtIDIgKiBwMiArIHYwICsgdjEgKSAqIHQzICsgKCAtIDMgKiBwMSArIDMgKiBwMiAtIDIgKiB2MCAtIHYxICkgKiB0MiArIHYwICogdCArIHAxO1xyXG5cclxufVxyXG5cclxuLy9cclxuXHJcbmZ1bmN0aW9uIFF1YWRyYXRpY0JlemllclAwKCB0LCBwICkge1xyXG5cclxuXHRjb25zdCBrID0gMSAtIHQ7XHJcblx0cmV0dXJuIGsgKiBrICogcDtcclxuXHJcbn1cclxuXHJcbmZ1bmN0aW9uIFF1YWRyYXRpY0JlemllclAxKCB0LCBwICkge1xyXG5cclxuXHRyZXR1cm4gMiAqICggMSAtIHQgKSAqIHQgKiBwO1xyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gUXVhZHJhdGljQmV6aWVyUDIoIHQsIHAgKSB7XHJcblxyXG5cdHJldHVybiB0ICogdCAqIHA7XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiBRdWFkcmF0aWNCZXppZXIoIHQsIHAwLCBwMSwgcDIgKSB7XHJcblxyXG5cdHJldHVybiBRdWFkcmF0aWNCZXppZXJQMCggdCwgcDAgKSArIFF1YWRyYXRpY0JlemllclAxKCB0LCBwMSApICtcclxuXHRcdFF1YWRyYXRpY0JlemllclAyKCB0LCBwMiApO1xyXG5cclxufVxyXG5cclxuLy9cclxuXHJcbmZ1bmN0aW9uIEN1YmljQmV6aWVyUDAoIHQsIHAgKSB7XHJcblxyXG5cdGNvbnN0IGsgPSAxIC0gdDtcclxuXHRyZXR1cm4gayAqIGsgKiBrICogcDtcclxuXHJcbn1cclxuXHJcbmZ1bmN0aW9uIEN1YmljQmV6aWVyUDEoIHQsIHAgKSB7XHJcblxyXG5cdGNvbnN0IGsgPSAxIC0gdDtcclxuXHRyZXR1cm4gMyAqIGsgKiBrICogdCAqIHA7XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiBDdWJpY0JlemllclAyKCB0LCBwICkge1xyXG5cclxuXHRyZXR1cm4gMyAqICggMSAtIHQgKSAqIHQgKiB0ICogcDtcclxuXHJcbn1cclxuXHJcbmZ1bmN0aW9uIEN1YmljQmV6aWVyUDMoIHQsIHAgKSB7XHJcblxyXG5cdHJldHVybiB0ICogdCAqIHQgKiBwO1xyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gQ3ViaWNCZXppZXIoIHQsIHAwLCBwMSwgcDIsIHAzICkge1xyXG5cclxuXHRyZXR1cm4gQ3ViaWNCZXppZXJQMCggdCwgcDAgKSArIEN1YmljQmV6aWVyUDEoIHQsIHAxICkgKyBDdWJpY0JlemllclAyKCB0LCBwMiApICtcclxuXHRcdEN1YmljQmV6aWVyUDMoIHQsIHAzICk7XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBDYXRtdWxsUm9tLCBRdWFkcmF0aWNCZXppZXIsIEN1YmljQmV6aWVyIH07XHJcbiIsImltcG9ydCB7IEN1cnZlIH0gZnJvbSAnLi4vY29yZS9DdXJ2ZS5qcyc7XHJcbmltcG9ydCB7IEN1YmljQmV6aWVyIH0gZnJvbSAnLi4vY29yZS9JbnRlcnBvbGF0aW9ucy5qcyc7XHJcbmltcG9ydCB7IFZlY3RvcjIgfSBmcm9tICcuLi8uLi9tYXRoL1ZlY3RvcjIuanMnO1xyXG5cclxuY2xhc3MgQ3ViaWNCZXppZXJDdXJ2ZSBleHRlbmRzIEN1cnZlIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIHYwID0gbmV3IFZlY3RvcjIoKSwgdjEgPSBuZXcgVmVjdG9yMigpLCB2MiA9IG5ldyBWZWN0b3IyKCksIHYzID0gbmV3IFZlY3RvcjIoKSApIHtcclxuXHJcblx0XHRzdXBlcigpO1xyXG5cclxuXHRcdHRoaXMuaXNDdWJpY0JlemllckN1cnZlID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSAnQ3ViaWNCZXppZXJDdXJ2ZSc7XHJcblxyXG5cdFx0dGhpcy52MCA9IHYwO1xyXG5cdFx0dGhpcy52MSA9IHYxO1xyXG5cdFx0dGhpcy52MiA9IHYyO1xyXG5cdFx0dGhpcy52MyA9IHYzO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldFBvaW50KCB0LCBvcHRpb25hbFRhcmdldCA9IG5ldyBWZWN0b3IyKCkgKSB7XHJcblxyXG5cdFx0Y29uc3QgcG9pbnQgPSBvcHRpb25hbFRhcmdldDtcclxuXHJcblx0XHRjb25zdCB2MCA9IHRoaXMudjAsIHYxID0gdGhpcy52MSwgdjIgPSB0aGlzLnYyLCB2MyA9IHRoaXMudjM7XHJcblxyXG5cdFx0cG9pbnQuc2V0KFxyXG5cdFx0XHRDdWJpY0JlemllciggdCwgdjAueCwgdjEueCwgdjIueCwgdjMueCApLFxyXG5cdFx0XHRDdWJpY0JlemllciggdCwgdjAueSwgdjEueSwgdjIueSwgdjMueSApXHJcblx0XHQpO1xyXG5cclxuXHRcdHJldHVybiBwb2ludDtcclxuXHJcblx0fVxyXG5cclxuXHRjb3B5KCBzb3VyY2UgKSB7XHJcblxyXG5cdFx0c3VwZXIuY29weSggc291cmNlICk7XHJcblxyXG5cdFx0dGhpcy52MC5jb3B5KCBzb3VyY2UudjAgKTtcclxuXHRcdHRoaXMudjEuY29weSggc291cmNlLnYxICk7XHJcblx0XHR0aGlzLnYyLmNvcHkoIHNvdXJjZS52MiApO1xyXG5cdFx0dGhpcy52My5jb3B5KCBzb3VyY2UudjMgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHR0b0pTT04oKSB7XHJcblxyXG5cdFx0Y29uc3QgZGF0YSA9IHN1cGVyLnRvSlNPTigpO1xyXG5cclxuXHRcdGRhdGEudjAgPSB0aGlzLnYwLnRvQXJyYXkoKTtcclxuXHRcdGRhdGEudjEgPSB0aGlzLnYxLnRvQXJyYXkoKTtcclxuXHRcdGRhdGEudjIgPSB0aGlzLnYyLnRvQXJyYXkoKTtcclxuXHRcdGRhdGEudjMgPSB0aGlzLnYzLnRvQXJyYXkoKTtcclxuXHJcblx0XHRyZXR1cm4gZGF0YTtcclxuXHJcblx0fVxyXG5cclxuXHRmcm9tSlNPTigganNvbiApIHtcclxuXHJcblx0XHRzdXBlci5mcm9tSlNPTigganNvbiApO1xyXG5cclxuXHRcdHRoaXMudjAuZnJvbUFycmF5KCBqc29uLnYwICk7XHJcblx0XHR0aGlzLnYxLmZyb21BcnJheSgganNvbi52MSApO1xyXG5cdFx0dGhpcy52Mi5mcm9tQXJyYXkoIGpzb24udjIgKTtcclxuXHRcdHRoaXMudjMuZnJvbUFycmF5KCBqc29uLnYzICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IEN1YmljQmV6aWVyQ3VydmUgfTtcclxuIiwiaW1wb3J0IHsgQ3VydmUgfSBmcm9tICcuLi9jb3JlL0N1cnZlLmpzJztcclxuaW1wb3J0IHsgQ3ViaWNCZXppZXIgfSBmcm9tICcuLi9jb3JlL0ludGVycG9sYXRpb25zLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yMyB9IGZyb20gJy4uLy4uL21hdGgvVmVjdG9yMy5qcyc7XHJcblxyXG5jbGFzcyBDdWJpY0JlemllckN1cnZlMyBleHRlbmRzIEN1cnZlIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIHYwID0gbmV3IFZlY3RvcjMoKSwgdjEgPSBuZXcgVmVjdG9yMygpLCB2MiA9IG5ldyBWZWN0b3IzKCksIHYzID0gbmV3IFZlY3RvcjMoKSApIHtcclxuXHJcblx0XHRzdXBlcigpO1xyXG5cclxuXHRcdHRoaXMuaXNDdWJpY0JlemllckN1cnZlMyA9IHRydWU7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ0N1YmljQmV6aWVyQ3VydmUzJztcclxuXHJcblx0XHR0aGlzLnYwID0gdjA7XHJcblx0XHR0aGlzLnYxID0gdjE7XHJcblx0XHR0aGlzLnYyID0gdjI7XHJcblx0XHR0aGlzLnYzID0gdjM7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0UG9pbnQoIHQsIG9wdGlvbmFsVGFyZ2V0ID0gbmV3IFZlY3RvcjMoKSApIHtcclxuXHJcblx0XHRjb25zdCBwb2ludCA9IG9wdGlvbmFsVGFyZ2V0O1xyXG5cclxuXHRcdGNvbnN0IHYwID0gdGhpcy52MCwgdjEgPSB0aGlzLnYxLCB2MiA9IHRoaXMudjIsIHYzID0gdGhpcy52MztcclxuXHJcblx0XHRwb2ludC5zZXQoXHJcblx0XHRcdEN1YmljQmV6aWVyKCB0LCB2MC54LCB2MS54LCB2Mi54LCB2My54ICksXHJcblx0XHRcdEN1YmljQmV6aWVyKCB0LCB2MC55LCB2MS55LCB2Mi55LCB2My55ICksXHJcblx0XHRcdEN1YmljQmV6aWVyKCB0LCB2MC56LCB2MS56LCB2Mi56LCB2My56IClcclxuXHRcdCk7XHJcblxyXG5cdFx0cmV0dXJuIHBvaW50O1xyXG5cclxuXHR9XHJcblxyXG5cdGNvcHkoIHNvdXJjZSApIHtcclxuXHJcblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcclxuXHJcblx0XHR0aGlzLnYwLmNvcHkoIHNvdXJjZS52MCApO1xyXG5cdFx0dGhpcy52MS5jb3B5KCBzb3VyY2UudjEgKTtcclxuXHRcdHRoaXMudjIuY29weSggc291cmNlLnYyICk7XHJcblx0XHR0aGlzLnYzLmNvcHkoIHNvdXJjZS52MyApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHRvSlNPTigpIHtcclxuXHJcblx0XHRjb25zdCBkYXRhID0gc3VwZXIudG9KU09OKCk7XHJcblxyXG5cdFx0ZGF0YS52MCA9IHRoaXMudjAudG9BcnJheSgpO1xyXG5cdFx0ZGF0YS52MSA9IHRoaXMudjEudG9BcnJheSgpO1xyXG5cdFx0ZGF0YS52MiA9IHRoaXMudjIudG9BcnJheSgpO1xyXG5cdFx0ZGF0YS52MyA9IHRoaXMudjMudG9BcnJheSgpO1xyXG5cclxuXHRcdHJldHVybiBkYXRhO1xyXG5cclxuXHR9XHJcblxyXG5cdGZyb21KU09OKCBqc29uICkge1xyXG5cclxuXHRcdHN1cGVyLmZyb21KU09OKCBqc29uICk7XHJcblxyXG5cdFx0dGhpcy52MC5mcm9tQXJyYXkoIGpzb24udjAgKTtcclxuXHRcdHRoaXMudjEuZnJvbUFycmF5KCBqc29uLnYxICk7XHJcblx0XHR0aGlzLnYyLmZyb21BcnJheSgganNvbi52MiApO1xyXG5cdFx0dGhpcy52My5mcm9tQXJyYXkoIGpzb24udjMgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgQ3ViaWNCZXppZXJDdXJ2ZTMgfTtcclxuIiwiaW1wb3J0IHsgVmVjdG9yMiB9IGZyb20gJy4uLy4uL21hdGgvVmVjdG9yMi5qcyc7XHJcbmltcG9ydCB7IEN1cnZlIH0gZnJvbSAnLi4vY29yZS9DdXJ2ZS5qcyc7XHJcblxyXG5jbGFzcyBMaW5lQ3VydmUgZXh0ZW5kcyBDdXJ2ZSB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCB2MSA9IG5ldyBWZWN0b3IyKCksIHYyID0gbmV3IFZlY3RvcjIoKSApIHtcclxuXHJcblx0XHRzdXBlcigpO1xyXG5cclxuXHRcdHRoaXMuaXNMaW5lQ3VydmUgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMudHlwZSA9ICdMaW5lQ3VydmUnO1xyXG5cclxuXHRcdHRoaXMudjEgPSB2MTtcclxuXHRcdHRoaXMudjIgPSB2MjtcclxuXHJcblx0fVxyXG5cclxuXHRnZXRQb2ludCggdCwgb3B0aW9uYWxUYXJnZXQgPSBuZXcgVmVjdG9yMigpICkge1xyXG5cclxuXHRcdGNvbnN0IHBvaW50ID0gb3B0aW9uYWxUYXJnZXQ7XHJcblxyXG5cdFx0aWYgKCB0ID09PSAxICkge1xyXG5cclxuXHRcdFx0cG9pbnQuY29weSggdGhpcy52MiApO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRwb2ludC5jb3B5KCB0aGlzLnYyICkuc3ViKCB0aGlzLnYxICk7XHJcblx0XHRcdHBvaW50Lm11bHRpcGx5U2NhbGFyKCB0ICkuYWRkKCB0aGlzLnYxICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiBwb2ludDtcclxuXHJcblx0fVxyXG5cclxuXHQvLyBMaW5lIGN1cnZlIGlzIGxpbmVhciwgc28gd2UgY2FuIG92ZXJ3cml0ZSBkZWZhdWx0IGdldFBvaW50QXRcclxuXHRnZXRQb2ludEF0KCB1LCBvcHRpb25hbFRhcmdldCApIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5nZXRQb2ludCggdSwgb3B0aW9uYWxUYXJnZXQgKTtcclxuXHJcblx0fVxyXG5cclxuXHRnZXRUYW5nZW50KCB0LCBvcHRpb25hbFRhcmdldCA9IG5ldyBWZWN0b3IyKCkgKSB7XHJcblxyXG5cdFx0cmV0dXJuIG9wdGlvbmFsVGFyZ2V0LnN1YlZlY3RvcnMoIHRoaXMudjIsIHRoaXMudjEgKS5ub3JtYWxpemUoKTtcclxuXHJcblx0fVxyXG5cclxuXHRnZXRUYW5nZW50QXQoIHUsIG9wdGlvbmFsVGFyZ2V0ICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLmdldFRhbmdlbnQoIHUsIG9wdGlvbmFsVGFyZ2V0ICk7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xyXG5cclxuXHRcdHRoaXMudjEuY29weSggc291cmNlLnYxICk7XHJcblx0XHR0aGlzLnYyLmNvcHkoIHNvdXJjZS52MiApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHRvSlNPTigpIHtcclxuXHJcblx0XHRjb25zdCBkYXRhID0gc3VwZXIudG9KU09OKCk7XHJcblxyXG5cdFx0ZGF0YS52MSA9IHRoaXMudjEudG9BcnJheSgpO1xyXG5cdFx0ZGF0YS52MiA9IHRoaXMudjIudG9BcnJheSgpO1xyXG5cclxuXHRcdHJldHVybiBkYXRhO1xyXG5cclxuXHR9XHJcblxyXG5cdGZyb21KU09OKCBqc29uICkge1xyXG5cclxuXHRcdHN1cGVyLmZyb21KU09OKCBqc29uICk7XHJcblxyXG5cdFx0dGhpcy52MS5mcm9tQXJyYXkoIGpzb24udjEgKTtcclxuXHRcdHRoaXMudjIuZnJvbUFycmF5KCBqc29uLnYyICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IExpbmVDdXJ2ZSB9O1xyXG4iLCJpbXBvcnQgeyBWZWN0b3IzIH0gZnJvbSAnLi4vLi4vbWF0aC9WZWN0b3IzLmpzJztcclxuaW1wb3J0IHsgQ3VydmUgfSBmcm9tICcuLi9jb3JlL0N1cnZlLmpzJztcclxuXHJcbmNsYXNzIExpbmVDdXJ2ZTMgZXh0ZW5kcyBDdXJ2ZSB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCB2MSA9IG5ldyBWZWN0b3IzKCksIHYyID0gbmV3IFZlY3RvcjMoKSApIHtcclxuXHJcblx0XHRzdXBlcigpO1xyXG5cclxuXHRcdHRoaXMuaXNMaW5lQ3VydmUzID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSAnTGluZUN1cnZlMyc7XHJcblxyXG5cdFx0dGhpcy52MSA9IHYxO1xyXG5cdFx0dGhpcy52MiA9IHYyO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldFBvaW50KCB0LCBvcHRpb25hbFRhcmdldCA9IG5ldyBWZWN0b3IzKCkgKSB7XHJcblxyXG5cdFx0Y29uc3QgcG9pbnQgPSBvcHRpb25hbFRhcmdldDtcclxuXHJcblx0XHRpZiAoIHQgPT09IDEgKSB7XHJcblxyXG5cdFx0XHRwb2ludC5jb3B5KCB0aGlzLnYyICk7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdHBvaW50LmNvcHkoIHRoaXMudjIgKS5zdWIoIHRoaXMudjEgKTtcclxuXHRcdFx0cG9pbnQubXVsdGlwbHlTY2FsYXIoIHQgKS5hZGQoIHRoaXMudjEgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHBvaW50O1xyXG5cclxuXHR9XHJcblxyXG5cdC8vIExpbmUgY3VydmUgaXMgbGluZWFyLCBzbyB3ZSBjYW4gb3ZlcndyaXRlIGRlZmF1bHQgZ2V0UG9pbnRBdFxyXG5cdGdldFBvaW50QXQoIHUsIG9wdGlvbmFsVGFyZ2V0ICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLmdldFBvaW50KCB1LCBvcHRpb25hbFRhcmdldCApO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldFRhbmdlbnQoIHQsIG9wdGlvbmFsVGFyZ2V0ID0gbmV3IFZlY3RvcjMoKSApIHtcclxuXHJcblx0XHRyZXR1cm4gb3B0aW9uYWxUYXJnZXQuc3ViVmVjdG9ycyggdGhpcy52MiwgdGhpcy52MSApLm5vcm1hbGl6ZSgpO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldFRhbmdlbnRBdCggdSwgb3B0aW9uYWxUYXJnZXQgKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuZ2V0VGFuZ2VudCggdSwgb3B0aW9uYWxUYXJnZXQgKTtcclxuXHJcblx0fVxyXG5cclxuXHRjb3B5KCBzb3VyY2UgKSB7XHJcblxyXG5cdFx0c3VwZXIuY29weSggc291cmNlICk7XHJcblxyXG5cdFx0dGhpcy52MS5jb3B5KCBzb3VyY2UudjEgKTtcclxuXHRcdHRoaXMudjIuY29weSggc291cmNlLnYyICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0dG9KU09OKCkge1xyXG5cclxuXHRcdGNvbnN0IGRhdGEgPSBzdXBlci50b0pTT04oKTtcclxuXHJcblx0XHRkYXRhLnYxID0gdGhpcy52MS50b0FycmF5KCk7XHJcblx0XHRkYXRhLnYyID0gdGhpcy52Mi50b0FycmF5KCk7XHJcblxyXG5cdFx0cmV0dXJuIGRhdGE7XHJcblxyXG5cdH1cclxuXHJcblx0ZnJvbUpTT04oIGpzb24gKSB7XHJcblxyXG5cdFx0c3VwZXIuZnJvbUpTT04oIGpzb24gKTtcclxuXHJcblx0XHR0aGlzLnYxLmZyb21BcnJheSgganNvbi52MSApO1xyXG5cdFx0dGhpcy52Mi5mcm9tQXJyYXkoIGpzb24udjIgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgTGluZUN1cnZlMyB9O1xyXG4iLCJpbXBvcnQgeyBDdXJ2ZSB9IGZyb20gJy4uL2NvcmUvQ3VydmUuanMnO1xyXG5pbXBvcnQgeyBRdWFkcmF0aWNCZXppZXIgfSBmcm9tICcuLi9jb3JlL0ludGVycG9sYXRpb25zLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yMiB9IGZyb20gJy4uLy4uL21hdGgvVmVjdG9yMi5qcyc7XHJcblxyXG5jbGFzcyBRdWFkcmF0aWNCZXppZXJDdXJ2ZSBleHRlbmRzIEN1cnZlIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIHYwID0gbmV3IFZlY3RvcjIoKSwgdjEgPSBuZXcgVmVjdG9yMigpLCB2MiA9IG5ldyBWZWN0b3IyKCkgKSB7XHJcblxyXG5cdFx0c3VwZXIoKTtcclxuXHJcblx0XHR0aGlzLmlzUXVhZHJhdGljQmV6aWVyQ3VydmUgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMudHlwZSA9ICdRdWFkcmF0aWNCZXppZXJDdXJ2ZSc7XHJcblxyXG5cdFx0dGhpcy52MCA9IHYwO1xyXG5cdFx0dGhpcy52MSA9IHYxO1xyXG5cdFx0dGhpcy52MiA9IHYyO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldFBvaW50KCB0LCBvcHRpb25hbFRhcmdldCA9IG5ldyBWZWN0b3IyKCkgKSB7XHJcblxyXG5cdFx0Y29uc3QgcG9pbnQgPSBvcHRpb25hbFRhcmdldDtcclxuXHJcblx0XHRjb25zdCB2MCA9IHRoaXMudjAsIHYxID0gdGhpcy52MSwgdjIgPSB0aGlzLnYyO1xyXG5cclxuXHRcdHBvaW50LnNldChcclxuXHRcdFx0UXVhZHJhdGljQmV6aWVyKCB0LCB2MC54LCB2MS54LCB2Mi54ICksXHJcblx0XHRcdFF1YWRyYXRpY0JlemllciggdCwgdjAueSwgdjEueSwgdjIueSApXHJcblx0XHQpO1xyXG5cclxuXHRcdHJldHVybiBwb2ludDtcclxuXHJcblx0fVxyXG5cclxuXHRjb3B5KCBzb3VyY2UgKSB7XHJcblxyXG5cdFx0c3VwZXIuY29weSggc291cmNlICk7XHJcblxyXG5cdFx0dGhpcy52MC5jb3B5KCBzb3VyY2UudjAgKTtcclxuXHRcdHRoaXMudjEuY29weSggc291cmNlLnYxICk7XHJcblx0XHR0aGlzLnYyLmNvcHkoIHNvdXJjZS52MiApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHRvSlNPTigpIHtcclxuXHJcblx0XHRjb25zdCBkYXRhID0gc3VwZXIudG9KU09OKCk7XHJcblxyXG5cdFx0ZGF0YS52MCA9IHRoaXMudjAudG9BcnJheSgpO1xyXG5cdFx0ZGF0YS52MSA9IHRoaXMudjEudG9BcnJheSgpO1xyXG5cdFx0ZGF0YS52MiA9IHRoaXMudjIudG9BcnJheSgpO1xyXG5cclxuXHRcdHJldHVybiBkYXRhO1xyXG5cclxuXHR9XHJcblxyXG5cdGZyb21KU09OKCBqc29uICkge1xyXG5cclxuXHRcdHN1cGVyLmZyb21KU09OKCBqc29uICk7XHJcblxyXG5cdFx0dGhpcy52MC5mcm9tQXJyYXkoIGpzb24udjAgKTtcclxuXHRcdHRoaXMudjEuZnJvbUFycmF5KCBqc29uLnYxICk7XHJcblx0XHR0aGlzLnYyLmZyb21BcnJheSgganNvbi52MiApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBRdWFkcmF0aWNCZXppZXJDdXJ2ZSB9O1xyXG4iLCJpbXBvcnQgeyBDdXJ2ZSB9IGZyb20gJy4uL2NvcmUvQ3VydmUuanMnO1xyXG5pbXBvcnQgeyBRdWFkcmF0aWNCZXppZXIgfSBmcm9tICcuLi9jb3JlL0ludGVycG9sYXRpb25zLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yMyB9IGZyb20gJy4uLy4uL21hdGgvVmVjdG9yMy5qcyc7XHJcblxyXG5jbGFzcyBRdWFkcmF0aWNCZXppZXJDdXJ2ZTMgZXh0ZW5kcyBDdXJ2ZSB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCB2MCA9IG5ldyBWZWN0b3IzKCksIHYxID0gbmV3IFZlY3RvcjMoKSwgdjIgPSBuZXcgVmVjdG9yMygpICkge1xyXG5cclxuXHRcdHN1cGVyKCk7XHJcblxyXG5cdFx0dGhpcy5pc1F1YWRyYXRpY0JlemllckN1cnZlMyA9IHRydWU7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ1F1YWRyYXRpY0JlemllckN1cnZlMyc7XHJcblxyXG5cdFx0dGhpcy52MCA9IHYwO1xyXG5cdFx0dGhpcy52MSA9IHYxO1xyXG5cdFx0dGhpcy52MiA9IHYyO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldFBvaW50KCB0LCBvcHRpb25hbFRhcmdldCA9IG5ldyBWZWN0b3IzKCkgKSB7XHJcblxyXG5cdFx0Y29uc3QgcG9pbnQgPSBvcHRpb25hbFRhcmdldDtcclxuXHJcblx0XHRjb25zdCB2MCA9IHRoaXMudjAsIHYxID0gdGhpcy52MSwgdjIgPSB0aGlzLnYyO1xyXG5cclxuXHRcdHBvaW50LnNldChcclxuXHRcdFx0UXVhZHJhdGljQmV6aWVyKCB0LCB2MC54LCB2MS54LCB2Mi54ICksXHJcblx0XHRcdFF1YWRyYXRpY0JlemllciggdCwgdjAueSwgdjEueSwgdjIueSApLFxyXG5cdFx0XHRRdWFkcmF0aWNCZXppZXIoIHQsIHYwLnosIHYxLnosIHYyLnogKVxyXG5cdFx0KTtcclxuXHJcblx0XHRyZXR1cm4gcG9pbnQ7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xyXG5cclxuXHRcdHRoaXMudjAuY29weSggc291cmNlLnYwICk7XHJcblx0XHR0aGlzLnYxLmNvcHkoIHNvdXJjZS52MSApO1xyXG5cdFx0dGhpcy52Mi5jb3B5KCBzb3VyY2UudjIgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHR0b0pTT04oKSB7XHJcblxyXG5cdFx0Y29uc3QgZGF0YSA9IHN1cGVyLnRvSlNPTigpO1xyXG5cclxuXHRcdGRhdGEudjAgPSB0aGlzLnYwLnRvQXJyYXkoKTtcclxuXHRcdGRhdGEudjEgPSB0aGlzLnYxLnRvQXJyYXkoKTtcclxuXHRcdGRhdGEudjIgPSB0aGlzLnYyLnRvQXJyYXkoKTtcclxuXHJcblx0XHRyZXR1cm4gZGF0YTtcclxuXHJcblx0fVxyXG5cclxuXHRmcm9tSlNPTigganNvbiApIHtcclxuXHJcblx0XHRzdXBlci5mcm9tSlNPTigganNvbiApO1xyXG5cclxuXHRcdHRoaXMudjAuZnJvbUFycmF5KCBqc29uLnYwICk7XHJcblx0XHR0aGlzLnYxLmZyb21BcnJheSgganNvbi52MSApO1xyXG5cdFx0dGhpcy52Mi5mcm9tQXJyYXkoIGpzb24udjIgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgUXVhZHJhdGljQmV6aWVyQ3VydmUzIH07XHJcbiIsImltcG9ydCB7IEN1cnZlIH0gZnJvbSAnLi4vY29yZS9DdXJ2ZS5qcyc7XHJcbmltcG9ydCB7IENhdG11bGxSb20gfSBmcm9tICcuLi9jb3JlL0ludGVycG9sYXRpb25zLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yMiB9IGZyb20gJy4uLy4uL21hdGgvVmVjdG9yMi5qcyc7XHJcblxyXG5jbGFzcyBTcGxpbmVDdXJ2ZSBleHRlbmRzIEN1cnZlIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIHBvaW50cyA9IFtdICkge1xyXG5cclxuXHRcdHN1cGVyKCk7XHJcblxyXG5cdFx0dGhpcy5pc1NwbGluZUN1cnZlID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSAnU3BsaW5lQ3VydmUnO1xyXG5cclxuXHRcdHRoaXMucG9pbnRzID0gcG9pbnRzO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldFBvaW50KCB0LCBvcHRpb25hbFRhcmdldCA9IG5ldyBWZWN0b3IyKCkgKSB7XHJcblxyXG5cdFx0Y29uc3QgcG9pbnQgPSBvcHRpb25hbFRhcmdldDtcclxuXHJcblx0XHRjb25zdCBwb2ludHMgPSB0aGlzLnBvaW50cztcclxuXHRcdGNvbnN0IHAgPSAoIHBvaW50cy5sZW5ndGggLSAxICkgKiB0O1xyXG5cclxuXHRcdGNvbnN0IGludFBvaW50ID0gTWF0aC5mbG9vciggcCApO1xyXG5cdFx0Y29uc3Qgd2VpZ2h0ID0gcCAtIGludFBvaW50O1xyXG5cclxuXHRcdGNvbnN0IHAwID0gcG9pbnRzWyBpbnRQb2ludCA9PT0gMCA/IGludFBvaW50IDogaW50UG9pbnQgLSAxIF07XHJcblx0XHRjb25zdCBwMSA9IHBvaW50c1sgaW50UG9pbnQgXTtcclxuXHRcdGNvbnN0IHAyID0gcG9pbnRzWyBpbnRQb2ludCA+IHBvaW50cy5sZW5ndGggLSAyID8gcG9pbnRzLmxlbmd0aCAtIDEgOiBpbnRQb2ludCArIDEgXTtcclxuXHRcdGNvbnN0IHAzID0gcG9pbnRzWyBpbnRQb2ludCA+IHBvaW50cy5sZW5ndGggLSAzID8gcG9pbnRzLmxlbmd0aCAtIDEgOiBpbnRQb2ludCArIDIgXTtcclxuXHJcblx0XHRwb2ludC5zZXQoXHJcblx0XHRcdENhdG11bGxSb20oIHdlaWdodCwgcDAueCwgcDEueCwgcDIueCwgcDMueCApLFxyXG5cdFx0XHRDYXRtdWxsUm9tKCB3ZWlnaHQsIHAwLnksIHAxLnksIHAyLnksIHAzLnkgKVxyXG5cdFx0KTtcclxuXHJcblx0XHRyZXR1cm4gcG9pbnQ7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xyXG5cclxuXHRcdHRoaXMucG9pbnRzID0gW107XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gc291cmNlLnBvaW50cy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0Y29uc3QgcG9pbnQgPSBzb3VyY2UucG9pbnRzWyBpIF07XHJcblxyXG5cdFx0XHR0aGlzLnBvaW50cy5wdXNoKCBwb2ludC5jbG9uZSgpICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHRvSlNPTigpIHtcclxuXHJcblx0XHRjb25zdCBkYXRhID0gc3VwZXIudG9KU09OKCk7XHJcblxyXG5cdFx0ZGF0YS5wb2ludHMgPSBbXTtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSB0aGlzLnBvaW50cy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0Y29uc3QgcG9pbnQgPSB0aGlzLnBvaW50c1sgaSBdO1xyXG5cdFx0XHRkYXRhLnBvaW50cy5wdXNoKCBwb2ludC50b0FycmF5KCkgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIGRhdGE7XHJcblxyXG5cdH1cclxuXHJcblx0ZnJvbUpTT04oIGpzb24gKSB7XHJcblxyXG5cdFx0c3VwZXIuZnJvbUpTT04oIGpzb24gKTtcclxuXHJcblx0XHR0aGlzLnBvaW50cyA9IFtdO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IGpzb24ucG9pbnRzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBwb2ludCA9IGpzb24ucG9pbnRzWyBpIF07XHJcblx0XHRcdHRoaXMucG9pbnRzLnB1c2goIG5ldyBWZWN0b3IyKCkuZnJvbUFycmF5KCBwb2ludCApICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBTcGxpbmVDdXJ2ZSB9O1xyXG4iLCJpbXBvcnQgeyBDdXJ2ZSB9IGZyb20gJy4vQ3VydmUuanMnO1xyXG5pbXBvcnQgKiBhcyBDdXJ2ZXMgZnJvbSAnLi4vY3VydmVzL0N1cnZlcy5qcyc7XHJcblxyXG4vKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuICpcdEN1cnZlZCBQYXRoIC0gYSBjdXJ2ZSBwYXRoIGlzIHNpbXBseSBhIGFycmF5IG9mIGNvbm5lY3RlZFxyXG4gKiAgY3VydmVzLCBidXQgcmV0YWlucyB0aGUgYXBpIG9mIGEgY3VydmVcclxuICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuY2xhc3MgQ3VydmVQYXRoIGV4dGVuZHMgQ3VydmUge1xyXG5cclxuXHRjb25zdHJ1Y3RvcigpIHtcclxuXHJcblx0XHRzdXBlcigpO1xyXG5cclxuXHRcdHRoaXMudHlwZSA9ICdDdXJ2ZVBhdGgnO1xyXG5cclxuXHRcdHRoaXMuY3VydmVzID0gW107XHJcblx0XHR0aGlzLmF1dG9DbG9zZSA9IGZhbHNlOyAvLyBBdXRvbWF0aWNhbGx5IGNsb3NlcyB0aGUgcGF0aFxyXG5cclxuXHR9XHJcblxyXG5cdGFkZCggY3VydmUgKSB7XHJcblxyXG5cdFx0dGhpcy5jdXJ2ZXMucHVzaCggY3VydmUgKTtcclxuXHJcblx0fVxyXG5cclxuXHRjbG9zZVBhdGgoKSB7XHJcblxyXG5cdFx0Ly8gQWRkIGEgbGluZSBjdXJ2ZSBpZiBzdGFydCBhbmQgZW5kIG9mIGxpbmVzIGFyZSBub3QgY29ubmVjdGVkXHJcblx0XHRjb25zdCBzdGFydFBvaW50ID0gdGhpcy5jdXJ2ZXNbIDAgXS5nZXRQb2ludCggMCApO1xyXG5cdFx0Y29uc3QgZW5kUG9pbnQgPSB0aGlzLmN1cnZlc1sgdGhpcy5jdXJ2ZXMubGVuZ3RoIC0gMSBdLmdldFBvaW50KCAxICk7XHJcblxyXG5cdFx0aWYgKCAhIHN0YXJ0UG9pbnQuZXF1YWxzKCBlbmRQb2ludCApICkge1xyXG5cclxuXHRcdFx0Y29uc3QgbGluZVR5cGUgPSAoIHN0YXJ0UG9pbnQuaXNWZWN0b3IyID09PSB0cnVlICkgPyAnTGluZUN1cnZlJyA6ICdMaW5lQ3VydmUzJztcclxuXHRcdFx0dGhpcy5jdXJ2ZXMucHVzaCggbmV3IEN1cnZlc1sgbGluZVR5cGUgXSggZW5kUG9pbnQsIHN0YXJ0UG9pbnQgKSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHQvLyBUbyBnZXQgYWNjdXJhdGUgcG9pbnQgd2l0aCByZWZlcmVuY2UgdG9cclxuXHQvLyBlbnRpcmUgcGF0aCBkaXN0YW5jZSBhdCB0aW1lIHQsXHJcblx0Ly8gZm9sbG93aW5nIGhhcyB0byBiZSBkb25lOlxyXG5cclxuXHQvLyAxLiBMZW5ndGggb2YgZWFjaCBzdWIgcGF0aCBoYXZlIHRvIGJlIGtub3duXHJcblx0Ly8gMi4gTG9jYXRlIGFuZCBpZGVudGlmeSB0eXBlIG9mIGN1cnZlXHJcblx0Ly8gMy4gR2V0IHQgZm9yIHRoZSBjdXJ2ZVxyXG5cdC8vIDQuIFJldHVybiBjdXJ2ZS5nZXRQb2ludEF0KHQnKVxyXG5cclxuXHRnZXRQb2ludCggdCwgb3B0aW9uYWxUYXJnZXQgKSB7XHJcblxyXG5cdFx0Y29uc3QgZCA9IHQgKiB0aGlzLmdldExlbmd0aCgpO1xyXG5cdFx0Y29uc3QgY3VydmVMZW5ndGhzID0gdGhpcy5nZXRDdXJ2ZUxlbmd0aHMoKTtcclxuXHRcdGxldCBpID0gMDtcclxuXHJcblx0XHQvLyBUbyB0aGluayBhYm91dCBib3VuZGFyaWVzIHBvaW50cy5cclxuXHJcblx0XHR3aGlsZSAoIGkgPCBjdXJ2ZUxlbmd0aHMubGVuZ3RoICkge1xyXG5cclxuXHRcdFx0aWYgKCBjdXJ2ZUxlbmd0aHNbIGkgXSA+PSBkICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBkaWZmID0gY3VydmVMZW5ndGhzWyBpIF0gLSBkO1xyXG5cdFx0XHRcdGNvbnN0IGN1cnZlID0gdGhpcy5jdXJ2ZXNbIGkgXTtcclxuXHJcblx0XHRcdFx0Y29uc3Qgc2VnbWVudExlbmd0aCA9IGN1cnZlLmdldExlbmd0aCgpO1xyXG5cdFx0XHRcdGNvbnN0IHUgPSBzZWdtZW50TGVuZ3RoID09PSAwID8gMCA6IDEgLSBkaWZmIC8gc2VnbWVudExlbmd0aDtcclxuXHJcblx0XHRcdFx0cmV0dXJuIGN1cnZlLmdldFBvaW50QXQoIHUsIG9wdGlvbmFsVGFyZ2V0ICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRpICsrO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gbnVsbDtcclxuXHJcblx0XHQvLyBsb29wIHdoZXJlIHN1bSAhPSAwLCBzdW0gPiBkICwgc3VtKzEgPGRcclxuXHJcblx0fVxyXG5cclxuXHQvLyBXZSBjYW5ub3QgdXNlIHRoZSBkZWZhdWx0IFRIUkVFLkN1cnZlIGdldFBvaW50KCkgd2l0aCBnZXRMZW5ndGgoKSBiZWNhdXNlIGluXHJcblx0Ly8gVEhSRUUuQ3VydmUsIGdldExlbmd0aCgpIGRlcGVuZHMgb24gZ2V0UG9pbnQoKSBidXQgaW4gVEhSRUUuQ3VydmVQYXRoXHJcblx0Ly8gZ2V0UG9pbnQoKSBkZXBlbmRzIG9uIGdldExlbmd0aFxyXG5cclxuXHRnZXRMZW5ndGgoKSB7XHJcblxyXG5cdFx0Y29uc3QgbGVucyA9IHRoaXMuZ2V0Q3VydmVMZW5ndGhzKCk7XHJcblx0XHRyZXR1cm4gbGVuc1sgbGVucy5sZW5ndGggLSAxIF07XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gY2FjaGVMZW5ndGhzIG11c3QgYmUgcmVjYWxjdWxhdGVkLlxyXG5cdHVwZGF0ZUFyY0xlbmd0aHMoKSB7XHJcblxyXG5cdFx0dGhpcy5uZWVkc1VwZGF0ZSA9IHRydWU7XHJcblx0XHR0aGlzLmNhY2hlTGVuZ3RocyA9IG51bGw7XHJcblx0XHR0aGlzLmdldEN1cnZlTGVuZ3RocygpO1xyXG5cclxuXHR9XHJcblxyXG5cdC8vIENvbXB1dGUgbGVuZ3RocyBhbmQgY2FjaGUgdGhlbVxyXG5cdC8vIFdlIGNhbm5vdCBvdmVyd3JpdGUgZ2V0TGVuZ3RocygpIGJlY2F1c2UgVXRvVCBtYXBwaW5nIHVzZXMgaXQuXHJcblxyXG5cdGdldEN1cnZlTGVuZ3RocygpIHtcclxuXHJcblx0XHQvLyBXZSB1c2UgY2FjaGUgdmFsdWVzIGlmIGN1cnZlcyBhbmQgY2FjaGUgYXJyYXkgYXJlIHNhbWUgbGVuZ3RoXHJcblxyXG5cdFx0aWYgKCB0aGlzLmNhY2hlTGVuZ3RocyAmJiB0aGlzLmNhY2hlTGVuZ3Rocy5sZW5ndGggPT09IHRoaXMuY3VydmVzLmxlbmd0aCApIHtcclxuXHJcblx0XHRcdHJldHVybiB0aGlzLmNhY2hlTGVuZ3RocztcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gR2V0IGxlbmd0aCBvZiBzdWItY3VydmVcclxuXHRcdC8vIFB1c2ggc3VtcyBpbnRvIGNhY2hlZCBhcnJheVxyXG5cclxuXHRcdGNvbnN0IGxlbmd0aHMgPSBbXTtcclxuXHRcdGxldCBzdW1zID0gMDtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSB0aGlzLmN1cnZlcy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0c3VtcyArPSB0aGlzLmN1cnZlc1sgaSBdLmdldExlbmd0aCgpO1xyXG5cdFx0XHRsZW5ndGhzLnB1c2goIHN1bXMgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5jYWNoZUxlbmd0aHMgPSBsZW5ndGhzO1xyXG5cclxuXHRcdHJldHVybiBsZW5ndGhzO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldFNwYWNlZFBvaW50cyggZGl2aXNpb25zID0gNDAgKSB7XHJcblxyXG5cdFx0Y29uc3QgcG9pbnRzID0gW107XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDw9IGRpdmlzaW9uczsgaSArKyApIHtcclxuXHJcblx0XHRcdHBvaW50cy5wdXNoKCB0aGlzLmdldFBvaW50KCBpIC8gZGl2aXNpb25zICkgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCB0aGlzLmF1dG9DbG9zZSApIHtcclxuXHJcblx0XHRcdHBvaW50cy5wdXNoKCBwb2ludHNbIDAgXSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gcG9pbnRzO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldFBvaW50cyggZGl2aXNpb25zID0gMTIgKSB7XHJcblxyXG5cdFx0Y29uc3QgcG9pbnRzID0gW107XHJcblx0XHRsZXQgbGFzdDtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGN1cnZlcyA9IHRoaXMuY3VydmVzOyBpIDwgY3VydmVzLmxlbmd0aDsgaSArKyApIHtcclxuXHJcblx0XHRcdGNvbnN0IGN1cnZlID0gY3VydmVzWyBpIF07XHJcblx0XHRcdGNvbnN0IHJlc29sdXRpb24gPSBjdXJ2ZS5pc0VsbGlwc2VDdXJ2ZSA/IGRpdmlzaW9ucyAqIDJcclxuXHRcdFx0XHQ6ICggY3VydmUuaXNMaW5lQ3VydmUgfHwgY3VydmUuaXNMaW5lQ3VydmUzICkgPyAxXHJcblx0XHRcdFx0XHQ6IGN1cnZlLmlzU3BsaW5lQ3VydmUgPyBkaXZpc2lvbnMgKiBjdXJ2ZS5wb2ludHMubGVuZ3RoXHJcblx0XHRcdFx0XHRcdDogZGl2aXNpb25zO1xyXG5cclxuXHRcdFx0Y29uc3QgcHRzID0gY3VydmUuZ2V0UG9pbnRzKCByZXNvbHV0aW9uICk7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaiA9IDA7IGogPCBwdHMubGVuZ3RoOyBqICsrICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBwb2ludCA9IHB0c1sgaiBdO1xyXG5cclxuXHRcdFx0XHRpZiAoIGxhc3QgJiYgbGFzdC5lcXVhbHMoIHBvaW50ICkgKSBjb250aW51ZTsgLy8gZW5zdXJlcyBubyBjb25zZWN1dGl2ZSBwb2ludHMgYXJlIGR1cGxpY2F0ZXNcclxuXHJcblx0XHRcdFx0cG9pbnRzLnB1c2goIHBvaW50ICk7XHJcblx0XHRcdFx0bGFzdCA9IHBvaW50O1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHRoaXMuYXV0b0Nsb3NlICYmIHBvaW50cy5sZW5ndGggPiAxICYmICEgcG9pbnRzWyBwb2ludHMubGVuZ3RoIC0gMSBdLmVxdWFscyggcG9pbnRzWyAwIF0gKSApIHtcclxuXHJcblx0XHRcdHBvaW50cy5wdXNoKCBwb2ludHNbIDAgXSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gcG9pbnRzO1xyXG5cclxuXHR9XHJcblxyXG5cdGNvcHkoIHNvdXJjZSApIHtcclxuXHJcblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcclxuXHJcblx0XHR0aGlzLmN1cnZlcyA9IFtdO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IHNvdXJjZS5jdXJ2ZXMubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdGNvbnN0IGN1cnZlID0gc291cmNlLmN1cnZlc1sgaSBdO1xyXG5cclxuXHRcdFx0dGhpcy5jdXJ2ZXMucHVzaCggY3VydmUuY2xvbmUoKSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLmF1dG9DbG9zZSA9IHNvdXJjZS5hdXRvQ2xvc2U7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0dG9KU09OKCkge1xyXG5cclxuXHRcdGNvbnN0IGRhdGEgPSBzdXBlci50b0pTT04oKTtcclxuXHJcblx0XHRkYXRhLmF1dG9DbG9zZSA9IHRoaXMuYXV0b0Nsb3NlO1xyXG5cdFx0ZGF0YS5jdXJ2ZXMgPSBbXTtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSB0aGlzLmN1cnZlcy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0Y29uc3QgY3VydmUgPSB0aGlzLmN1cnZlc1sgaSBdO1xyXG5cdFx0XHRkYXRhLmN1cnZlcy5wdXNoKCBjdXJ2ZS50b0pTT04oKSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gZGF0YTtcclxuXHJcblx0fVxyXG5cclxuXHRmcm9tSlNPTigganNvbiApIHtcclxuXHJcblx0XHRzdXBlci5mcm9tSlNPTigganNvbiApO1xyXG5cclxuXHRcdHRoaXMuYXV0b0Nsb3NlID0ganNvbi5hdXRvQ2xvc2U7XHJcblx0XHR0aGlzLmN1cnZlcyA9IFtdO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IGpzb24uY3VydmVzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBjdXJ2ZSA9IGpzb24uY3VydmVzWyBpIF07XHJcblx0XHRcdHRoaXMuY3VydmVzLnB1c2goIG5ldyBDdXJ2ZXNbIGN1cnZlLnR5cGUgXSgpLmZyb21KU09OKCBjdXJ2ZSApICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5cclxuZXhwb3J0IHsgQ3VydmVQYXRoIH07XHJcbiIsImltcG9ydCB7IFZlY3RvcjIgfSBmcm9tICcuLi8uLi9tYXRoL1ZlY3RvcjIuanMnO1xyXG5pbXBvcnQgeyBDdXJ2ZVBhdGggfSBmcm9tICcuL0N1cnZlUGF0aC5qcyc7XHJcbmltcG9ydCB7IEVsbGlwc2VDdXJ2ZSB9IGZyb20gJy4uL2N1cnZlcy9FbGxpcHNlQ3VydmUuanMnO1xyXG5pbXBvcnQgeyBTcGxpbmVDdXJ2ZSB9IGZyb20gJy4uL2N1cnZlcy9TcGxpbmVDdXJ2ZS5qcyc7XHJcbmltcG9ydCB7IEN1YmljQmV6aWVyQ3VydmUgfSBmcm9tICcuLi9jdXJ2ZXMvQ3ViaWNCZXppZXJDdXJ2ZS5qcyc7XHJcbmltcG9ydCB7IFF1YWRyYXRpY0JlemllckN1cnZlIH0gZnJvbSAnLi4vY3VydmVzL1F1YWRyYXRpY0JlemllckN1cnZlLmpzJztcclxuaW1wb3J0IHsgTGluZUN1cnZlIH0gZnJvbSAnLi4vY3VydmVzL0xpbmVDdXJ2ZS5qcyc7XHJcblxyXG5jbGFzcyBQYXRoIGV4dGVuZHMgQ3VydmVQYXRoIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIHBvaW50cyApIHtcclxuXHJcblx0XHRzdXBlcigpO1xyXG5cclxuXHRcdHRoaXMudHlwZSA9ICdQYXRoJztcclxuXHJcblx0XHR0aGlzLmN1cnJlbnRQb2ludCA9IG5ldyBWZWN0b3IyKCk7XHJcblxyXG5cdFx0aWYgKCBwb2ludHMgKSB7XHJcblxyXG5cdFx0XHR0aGlzLnNldEZyb21Qb2ludHMoIHBvaW50cyApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRzZXRGcm9tUG9pbnRzKCBwb2ludHMgKSB7XHJcblxyXG5cdFx0dGhpcy5tb3ZlVG8oIHBvaW50c1sgMCBdLngsIHBvaW50c1sgMCBdLnkgKTtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDEsIGwgPSBwb2ludHMubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdHRoaXMubGluZVRvKCBwb2ludHNbIGkgXS54LCBwb2ludHNbIGkgXS55ICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdG1vdmVUbyggeCwgeSApIHtcclxuXHJcblx0XHR0aGlzLmN1cnJlbnRQb2ludC5zZXQoIHgsIHkgKTsgLy8gVE9ETyBjb25zaWRlciByZWZlcmVuY2luZyB2ZWN0b3JzIGluc3RlYWQgb2YgY29weWluZz9cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRsaW5lVG8oIHgsIHkgKSB7XHJcblxyXG5cdFx0Y29uc3QgY3VydmUgPSBuZXcgTGluZUN1cnZlKCB0aGlzLmN1cnJlbnRQb2ludC5jbG9uZSgpLCBuZXcgVmVjdG9yMiggeCwgeSApICk7XHJcblx0XHR0aGlzLmN1cnZlcy5wdXNoKCBjdXJ2ZSApO1xyXG5cclxuXHRcdHRoaXMuY3VycmVudFBvaW50LnNldCggeCwgeSApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHF1YWRyYXRpY0N1cnZlVG8oIGFDUHgsIGFDUHksIGFYLCBhWSApIHtcclxuXHJcblx0XHRjb25zdCBjdXJ2ZSA9IG5ldyBRdWFkcmF0aWNCZXppZXJDdXJ2ZShcclxuXHRcdFx0dGhpcy5jdXJyZW50UG9pbnQuY2xvbmUoKSxcclxuXHRcdFx0bmV3IFZlY3RvcjIoIGFDUHgsIGFDUHkgKSxcclxuXHRcdFx0bmV3IFZlY3RvcjIoIGFYLCBhWSApXHJcblx0XHQpO1xyXG5cclxuXHRcdHRoaXMuY3VydmVzLnB1c2goIGN1cnZlICk7XHJcblxyXG5cdFx0dGhpcy5jdXJyZW50UG9pbnQuc2V0KCBhWCwgYVkgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRiZXppZXJDdXJ2ZVRvKCBhQ1AxeCwgYUNQMXksIGFDUDJ4LCBhQ1AyeSwgYVgsIGFZICkge1xyXG5cclxuXHRcdGNvbnN0IGN1cnZlID0gbmV3IEN1YmljQmV6aWVyQ3VydmUoXHJcblx0XHRcdHRoaXMuY3VycmVudFBvaW50LmNsb25lKCksXHJcblx0XHRcdG5ldyBWZWN0b3IyKCBhQ1AxeCwgYUNQMXkgKSxcclxuXHRcdFx0bmV3IFZlY3RvcjIoIGFDUDJ4LCBhQ1AyeSApLFxyXG5cdFx0XHRuZXcgVmVjdG9yMiggYVgsIGFZIClcclxuXHRcdCk7XHJcblxyXG5cdFx0dGhpcy5jdXJ2ZXMucHVzaCggY3VydmUgKTtcclxuXHJcblx0XHR0aGlzLmN1cnJlbnRQb2ludC5zZXQoIGFYLCBhWSApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNwbGluZVRocnUoIHB0cyAvKkFycmF5IG9mIFZlY3RvciovICkge1xyXG5cclxuXHRcdGNvbnN0IG5wdHMgPSBbIHRoaXMuY3VycmVudFBvaW50LmNsb25lKCkgXS5jb25jYXQoIHB0cyApO1xyXG5cclxuXHRcdGNvbnN0IGN1cnZlID0gbmV3IFNwbGluZUN1cnZlKCBucHRzICk7XHJcblx0XHR0aGlzLmN1cnZlcy5wdXNoKCBjdXJ2ZSApO1xyXG5cclxuXHRcdHRoaXMuY3VycmVudFBvaW50LmNvcHkoIHB0c1sgcHRzLmxlbmd0aCAtIDEgXSApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGFyYyggYVgsIGFZLCBhUmFkaXVzLCBhU3RhcnRBbmdsZSwgYUVuZEFuZ2xlLCBhQ2xvY2t3aXNlICkge1xyXG5cclxuXHRcdGNvbnN0IHgwID0gdGhpcy5jdXJyZW50UG9pbnQueDtcclxuXHRcdGNvbnN0IHkwID0gdGhpcy5jdXJyZW50UG9pbnQueTtcclxuXHJcblx0XHR0aGlzLmFic2FyYyggYVggKyB4MCwgYVkgKyB5MCwgYVJhZGl1cyxcclxuXHRcdFx0YVN0YXJ0QW5nbGUsIGFFbmRBbmdsZSwgYUNsb2Nrd2lzZSApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGFic2FyYyggYVgsIGFZLCBhUmFkaXVzLCBhU3RhcnRBbmdsZSwgYUVuZEFuZ2xlLCBhQ2xvY2t3aXNlICkge1xyXG5cclxuXHRcdHRoaXMuYWJzZWxsaXBzZSggYVgsIGFZLCBhUmFkaXVzLCBhUmFkaXVzLCBhU3RhcnRBbmdsZSwgYUVuZEFuZ2xlLCBhQ2xvY2t3aXNlICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0ZWxsaXBzZSggYVgsIGFZLCB4UmFkaXVzLCB5UmFkaXVzLCBhU3RhcnRBbmdsZSwgYUVuZEFuZ2xlLCBhQ2xvY2t3aXNlLCBhUm90YXRpb24gKSB7XHJcblxyXG5cdFx0Y29uc3QgeDAgPSB0aGlzLmN1cnJlbnRQb2ludC54O1xyXG5cdFx0Y29uc3QgeTAgPSB0aGlzLmN1cnJlbnRQb2ludC55O1xyXG5cclxuXHRcdHRoaXMuYWJzZWxsaXBzZSggYVggKyB4MCwgYVkgKyB5MCwgeFJhZGl1cywgeVJhZGl1cywgYVN0YXJ0QW5nbGUsIGFFbmRBbmdsZSwgYUNsb2Nrd2lzZSwgYVJvdGF0aW9uICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0YWJzZWxsaXBzZSggYVgsIGFZLCB4UmFkaXVzLCB5UmFkaXVzLCBhU3RhcnRBbmdsZSwgYUVuZEFuZ2xlLCBhQ2xvY2t3aXNlLCBhUm90YXRpb24gKSB7XHJcblxyXG5cdFx0Y29uc3QgY3VydmUgPSBuZXcgRWxsaXBzZUN1cnZlKCBhWCwgYVksIHhSYWRpdXMsIHlSYWRpdXMsIGFTdGFydEFuZ2xlLCBhRW5kQW5nbGUsIGFDbG9ja3dpc2UsIGFSb3RhdGlvbiApO1xyXG5cclxuXHRcdGlmICggdGhpcy5jdXJ2ZXMubGVuZ3RoID4gMCApIHtcclxuXHJcblx0XHRcdC8vIGlmIGEgcHJldmlvdXMgY3VydmUgaXMgcHJlc2VudCwgYXR0ZW1wdCB0byBqb2luXHJcblx0XHRcdGNvbnN0IGZpcnN0UG9pbnQgPSBjdXJ2ZS5nZXRQb2ludCggMCApO1xyXG5cclxuXHRcdFx0aWYgKCAhIGZpcnN0UG9pbnQuZXF1YWxzKCB0aGlzLmN1cnJlbnRQb2ludCApICkge1xyXG5cclxuXHRcdFx0XHR0aGlzLmxpbmVUbyggZmlyc3RQb2ludC54LCBmaXJzdFBvaW50LnkgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5jdXJ2ZXMucHVzaCggY3VydmUgKTtcclxuXHJcblx0XHRjb25zdCBsYXN0UG9pbnQgPSBjdXJ2ZS5nZXRQb2ludCggMSApO1xyXG5cdFx0dGhpcy5jdXJyZW50UG9pbnQuY29weSggbGFzdFBvaW50ICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xyXG5cclxuXHRcdHRoaXMuY3VycmVudFBvaW50LmNvcHkoIHNvdXJjZS5jdXJyZW50UG9pbnQgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHR0b0pTT04oKSB7XHJcblxyXG5cdFx0Y29uc3QgZGF0YSA9IHN1cGVyLnRvSlNPTigpO1xyXG5cclxuXHRcdGRhdGEuY3VycmVudFBvaW50ID0gdGhpcy5jdXJyZW50UG9pbnQudG9BcnJheSgpO1xyXG5cclxuXHRcdHJldHVybiBkYXRhO1xyXG5cclxuXHR9XHJcblxyXG5cdGZyb21KU09OKCBqc29uICkge1xyXG5cclxuXHRcdHN1cGVyLmZyb21KU09OKCBqc29uICk7XHJcblxyXG5cdFx0dGhpcy5jdXJyZW50UG9pbnQuZnJvbUFycmF5KCBqc29uLmN1cnJlbnRQb2ludCApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5cclxuZXhwb3J0IHsgUGF0aCB9O1xyXG4iLCJpbXBvcnQgeyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlIH0gZnJvbSAnLi4vY29yZS9CdWZmZXJBdHRyaWJ1dGUuanMnO1xyXG5pbXBvcnQgeyBCdWZmZXJHZW9tZXRyeSB9IGZyb20gJy4uL2NvcmUvQnVmZmVyR2VvbWV0cnkuanMnO1xyXG5pbXBvcnQgeyBWZWN0b3IzIH0gZnJvbSAnLi4vbWF0aC9WZWN0b3IzLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yMiB9IGZyb20gJy4uL21hdGgvVmVjdG9yMi5qcyc7XHJcbmltcG9ydCAqIGFzIE1hdGhVdGlscyBmcm9tICcuLi9tYXRoL01hdGhVdGlscy5qcyc7XHJcblxyXG5jbGFzcyBMYXRoZUdlb21ldHJ5IGV4dGVuZHMgQnVmZmVyR2VvbWV0cnkge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggcG9pbnRzID0gWyBuZXcgVmVjdG9yMiggMCwgLSAwLjUgKSwgbmV3IFZlY3RvcjIoIDAuNSwgMCApLCBuZXcgVmVjdG9yMiggMCwgMC41ICkgXSwgc2VnbWVudHMgPSAxMiwgcGhpU3RhcnQgPSAwLCBwaGlMZW5ndGggPSBNYXRoLlBJICogMiApIHtcclxuXHJcblx0XHRzdXBlcigpO1xyXG5cclxuXHRcdHRoaXMudHlwZSA9ICdMYXRoZUdlb21ldHJ5JztcclxuXHJcblx0XHR0aGlzLnBhcmFtZXRlcnMgPSB7XHJcblx0XHRcdHBvaW50czogcG9pbnRzLFxyXG5cdFx0XHRzZWdtZW50czogc2VnbWVudHMsXHJcblx0XHRcdHBoaVN0YXJ0OiBwaGlTdGFydCxcclxuXHRcdFx0cGhpTGVuZ3RoOiBwaGlMZW5ndGhcclxuXHRcdH07XHJcblxyXG5cdFx0c2VnbWVudHMgPSBNYXRoLmZsb29yKCBzZWdtZW50cyApO1xyXG5cclxuXHRcdC8vIGNsYW1wIHBoaUxlbmd0aCBzbyBpdCdzIGluIHJhbmdlIG9mIFsgMCwgMlBJIF1cclxuXHJcblx0XHRwaGlMZW5ndGggPSBNYXRoVXRpbHMuY2xhbXAoIHBoaUxlbmd0aCwgMCwgTWF0aC5QSSAqIDIgKTtcclxuXHJcblx0XHQvLyBidWZmZXJzXHJcblxyXG5cdFx0Y29uc3QgaW5kaWNlcyA9IFtdO1xyXG5cdFx0Y29uc3QgdmVydGljZXMgPSBbXTtcclxuXHRcdGNvbnN0IHV2cyA9IFtdO1xyXG5cdFx0Y29uc3QgaW5pdE5vcm1hbHMgPSBbXTtcclxuXHRcdGNvbnN0IG5vcm1hbHMgPSBbXTtcclxuXHJcblx0XHQvLyBoZWxwZXIgdmFyaWFibGVzXHJcblxyXG5cdFx0Y29uc3QgaW52ZXJzZVNlZ21lbnRzID0gMS4wIC8gc2VnbWVudHM7XHJcblx0XHRjb25zdCB2ZXJ0ZXggPSBuZXcgVmVjdG9yMygpO1xyXG5cdFx0Y29uc3QgdXYgPSBuZXcgVmVjdG9yMigpO1xyXG5cdFx0Y29uc3Qgbm9ybWFsID0gbmV3IFZlY3RvcjMoKTtcclxuXHRcdGNvbnN0IGN1ck5vcm1hbCA9IG5ldyBWZWN0b3IzKCk7XHJcblx0XHRjb25zdCBwcmV2Tm9ybWFsID0gbmV3IFZlY3RvcjMoKTtcclxuXHRcdGxldCBkeCA9IDA7XHJcblx0XHRsZXQgZHkgPSAwO1xyXG5cclxuXHRcdC8vIHByZS1jb21wdXRlIG5vcm1hbHMgZm9yIGluaXRpYWwgXCJtZXJpZGlhblwiXHJcblxyXG5cdFx0Zm9yICggbGV0IGogPSAwOyBqIDw9ICggcG9pbnRzLmxlbmd0aCAtIDEgKTsgaiArKyApIHtcclxuXHJcblx0XHRcdHN3aXRjaCAoIGogKSB7XHJcblxyXG5cdFx0XHRcdGNhc2UgMDpcdFx0XHRcdC8vIHNwZWNpYWwgaGFuZGxpbmcgZm9yIDFzdCB2ZXJ0ZXggb24gcGF0aFxyXG5cclxuXHRcdFx0XHRcdGR4ID0gcG9pbnRzWyBqICsgMSBdLnggLSBwb2ludHNbIGogXS54O1xyXG5cdFx0XHRcdFx0ZHkgPSBwb2ludHNbIGogKyAxIF0ueSAtIHBvaW50c1sgaiBdLnk7XHJcblxyXG5cdFx0XHRcdFx0bm9ybWFsLnggPSBkeSAqIDEuMDtcclxuXHRcdFx0XHRcdG5vcm1hbC55ID0gLSBkeDtcclxuXHRcdFx0XHRcdG5vcm1hbC56ID0gZHkgKiAwLjA7XHJcblxyXG5cdFx0XHRcdFx0cHJldk5vcm1hbC5jb3B5KCBub3JtYWwgKTtcclxuXHJcblx0XHRcdFx0XHRub3JtYWwubm9ybWFsaXplKCk7XHJcblxyXG5cdFx0XHRcdFx0aW5pdE5vcm1hbHMucHVzaCggbm9ybWFsLngsIG5vcm1hbC55LCBub3JtYWwueiApO1xyXG5cclxuXHRcdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0XHRjYXNlICggcG9pbnRzLmxlbmd0aCAtIDEgKTpcdC8vIHNwZWNpYWwgaGFuZGxpbmcgZm9yIGxhc3QgVmVydGV4IG9uIHBhdGhcclxuXHJcblx0XHRcdFx0XHRpbml0Tm9ybWFscy5wdXNoKCBwcmV2Tm9ybWFsLngsIHByZXZOb3JtYWwueSwgcHJldk5vcm1hbC56ICk7XHJcblxyXG5cdFx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRcdGRlZmF1bHQ6XHRcdFx0Ly8gZGVmYXVsdCBoYW5kbGluZyBmb3IgYWxsIHZlcnRpY2VzIGluIGJldHdlZW5cclxuXHJcblx0XHRcdFx0XHRkeCA9IHBvaW50c1sgaiArIDEgXS54IC0gcG9pbnRzWyBqIF0ueDtcclxuXHRcdFx0XHRcdGR5ID0gcG9pbnRzWyBqICsgMSBdLnkgLSBwb2ludHNbIGogXS55O1xyXG5cclxuXHRcdFx0XHRcdG5vcm1hbC54ID0gZHkgKiAxLjA7XHJcblx0XHRcdFx0XHRub3JtYWwueSA9IC0gZHg7XHJcblx0XHRcdFx0XHRub3JtYWwueiA9IGR5ICogMC4wO1xyXG5cclxuXHRcdFx0XHRcdGN1ck5vcm1hbC5jb3B5KCBub3JtYWwgKTtcclxuXHJcblx0XHRcdFx0XHRub3JtYWwueCArPSBwcmV2Tm9ybWFsLng7XHJcblx0XHRcdFx0XHRub3JtYWwueSArPSBwcmV2Tm9ybWFsLnk7XHJcblx0XHRcdFx0XHRub3JtYWwueiArPSBwcmV2Tm9ybWFsLno7XHJcblxyXG5cdFx0XHRcdFx0bm9ybWFsLm5vcm1hbGl6ZSgpO1xyXG5cclxuXHRcdFx0XHRcdGluaXROb3JtYWxzLnB1c2goIG5vcm1hbC54LCBub3JtYWwueSwgbm9ybWFsLnogKTtcclxuXHJcblx0XHRcdFx0XHRwcmV2Tm9ybWFsLmNvcHkoIGN1ck5vcm1hbCApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvLyBnZW5lcmF0ZSB2ZXJ0aWNlcywgdXZzIGFuZCBub3JtYWxzXHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDw9IHNlZ21lbnRzOyBpICsrICkge1xyXG5cclxuXHRcdFx0Y29uc3QgcGhpID0gcGhpU3RhcnQgKyBpICogaW52ZXJzZVNlZ21lbnRzICogcGhpTGVuZ3RoO1xyXG5cclxuXHRcdFx0Y29uc3Qgc2luID0gTWF0aC5zaW4oIHBoaSApO1xyXG5cdFx0XHRjb25zdCBjb3MgPSBNYXRoLmNvcyggcGhpICk7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaiA9IDA7IGogPD0gKCBwb2ludHMubGVuZ3RoIC0gMSApOyBqICsrICkge1xyXG5cclxuXHRcdFx0XHQvLyB2ZXJ0ZXhcclxuXHJcblx0XHRcdFx0dmVydGV4LnggPSBwb2ludHNbIGogXS54ICogc2luO1xyXG5cdFx0XHRcdHZlcnRleC55ID0gcG9pbnRzWyBqIF0ueTtcclxuXHRcdFx0XHR2ZXJ0ZXgueiA9IHBvaW50c1sgaiBdLnggKiBjb3M7XHJcblxyXG5cdFx0XHRcdHZlcnRpY2VzLnB1c2goIHZlcnRleC54LCB2ZXJ0ZXgueSwgdmVydGV4LnogKTtcclxuXHJcblx0XHRcdFx0Ly8gdXZcclxuXHJcblx0XHRcdFx0dXYueCA9IGkgLyBzZWdtZW50cztcclxuXHRcdFx0XHR1di55ID0gaiAvICggcG9pbnRzLmxlbmd0aCAtIDEgKTtcclxuXHJcblx0XHRcdFx0dXZzLnB1c2goIHV2LngsIHV2LnkgKTtcclxuXHJcblx0XHRcdFx0Ly8gbm9ybWFsXHJcblxyXG5cdFx0XHRcdGNvbnN0IHggPSBpbml0Tm9ybWFsc1sgMyAqIGogKyAwIF0gKiBzaW47XHJcblx0XHRcdFx0Y29uc3QgeSA9IGluaXROb3JtYWxzWyAzICogaiArIDEgXTtcclxuXHRcdFx0XHRjb25zdCB6ID0gaW5pdE5vcm1hbHNbIDMgKiBqICsgMCBdICogY29zO1xyXG5cclxuXHRcdFx0XHRub3JtYWxzLnB1c2goIHgsIHksIHogKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gaW5kaWNlc1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHNlZ21lbnRzOyBpICsrICkge1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGogPSAwOyBqIDwgKCBwb2ludHMubGVuZ3RoIC0gMSApOyBqICsrICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBiYXNlID0gaiArIGkgKiBwb2ludHMubGVuZ3RoO1xyXG5cclxuXHRcdFx0XHRjb25zdCBhID0gYmFzZTtcclxuXHRcdFx0XHRjb25zdCBiID0gYmFzZSArIHBvaW50cy5sZW5ndGg7XHJcblx0XHRcdFx0Y29uc3QgYyA9IGJhc2UgKyBwb2ludHMubGVuZ3RoICsgMTtcclxuXHRcdFx0XHRjb25zdCBkID0gYmFzZSArIDE7XHJcblxyXG5cdFx0XHRcdC8vIGZhY2VzXHJcblxyXG5cdFx0XHRcdGluZGljZXMucHVzaCggYSwgYiwgZCApO1xyXG5cdFx0XHRcdGluZGljZXMucHVzaCggYywgZCwgYiApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvLyBidWlsZCBnZW9tZXRyeVxyXG5cclxuXHRcdHRoaXMuc2V0SW5kZXgoIGluZGljZXMgKTtcclxuXHRcdHRoaXMuc2V0QXR0cmlidXRlKCAncG9zaXRpb24nLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggdmVydGljZXMsIDMgKSApO1xyXG5cdFx0dGhpcy5zZXRBdHRyaWJ1dGUoICd1dicsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCB1dnMsIDIgKSApO1xyXG5cdFx0dGhpcy5zZXRBdHRyaWJ1dGUoICdub3JtYWwnLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggbm9ybWFscywgMyApICk7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xyXG5cclxuXHRcdHRoaXMucGFyYW1ldGVycyA9IE9iamVjdC5hc3NpZ24oIHt9LCBzb3VyY2UucGFyYW1ldGVycyApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHN0YXRpYyBmcm9tSlNPTiggZGF0YSApIHtcclxuXHJcblx0XHRyZXR1cm4gbmV3IExhdGhlR2VvbWV0cnkoIGRhdGEucG9pbnRzLCBkYXRhLnNlZ21lbnRzLCBkYXRhLnBoaVN0YXJ0LCBkYXRhLnBoaUxlbmd0aCApO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5cclxuZXhwb3J0IHsgTGF0aGVHZW9tZXRyeSB9O1xyXG4iLCJpbXBvcnQgeyBQYXRoIH0gZnJvbSAnLi4vZXh0cmFzL2NvcmUvUGF0aC5qcyc7XHJcbmltcG9ydCB7IExhdGhlR2VvbWV0cnkgfSBmcm9tICcuL0xhdGhlR2VvbWV0cnkuanMnO1xyXG5cclxuY2xhc3MgQ2Fwc3VsZUdlb21ldHJ5IGV4dGVuZHMgTGF0aGVHZW9tZXRyeSB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCByYWRpdXMgPSAxLCBsZW5ndGggPSAxLCBjYXBTZWdtZW50cyA9IDQsIHJhZGlhbFNlZ21lbnRzID0gOCApIHtcclxuXHJcblx0XHRjb25zdCBwYXRoID0gbmV3IFBhdGgoKTtcclxuXHRcdHBhdGguYWJzYXJjKCAwLCAtIGxlbmd0aCAvIDIsIHJhZGl1cywgTWF0aC5QSSAqIDEuNSwgMCApO1xyXG5cdFx0cGF0aC5hYnNhcmMoIDAsIGxlbmd0aCAvIDIsIHJhZGl1cywgMCwgTWF0aC5QSSAqIDAuNSApO1xyXG5cclxuXHRcdHN1cGVyKCBwYXRoLmdldFBvaW50cyggY2FwU2VnbWVudHMgKSwgcmFkaWFsU2VnbWVudHMgKTtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSAnQ2Fwc3VsZUdlb21ldHJ5JztcclxuXHJcblx0XHR0aGlzLnBhcmFtZXRlcnMgPSB7XHJcblx0XHRcdHJhZGl1czogcmFkaXVzLFxyXG5cdFx0XHRsZW5ndGg6IGxlbmd0aCxcclxuXHRcdFx0Y2FwU2VnbWVudHM6IGNhcFNlZ21lbnRzLFxyXG5cdFx0XHRyYWRpYWxTZWdtZW50czogcmFkaWFsU2VnbWVudHMsXHJcblx0XHR9O1xyXG5cclxuXHR9XHJcblxyXG5cdHN0YXRpYyBmcm9tSlNPTiggZGF0YSApIHtcclxuXHJcblx0XHRyZXR1cm4gbmV3IENhcHN1bGVHZW9tZXRyeSggZGF0YS5yYWRpdXMsIGRhdGEubGVuZ3RoLCBkYXRhLmNhcFNlZ21lbnRzLCBkYXRhLnJhZGlhbFNlZ21lbnRzICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IENhcHN1bGVHZW9tZXRyeSB9O1xyXG4iLCJpbXBvcnQgeyBCdWZmZXJHZW9tZXRyeSB9IGZyb20gJy4uL2NvcmUvQnVmZmVyR2VvbWV0cnkuanMnO1xyXG5pbXBvcnQgeyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlIH0gZnJvbSAnLi4vY29yZS9CdWZmZXJBdHRyaWJ1dGUuanMnO1xyXG5pbXBvcnQgeyBWZWN0b3IzIH0gZnJvbSAnLi4vbWF0aC9WZWN0b3IzLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yMiB9IGZyb20gJy4uL21hdGgvVmVjdG9yMi5qcyc7XHJcblxyXG5jbGFzcyBDaXJjbGVHZW9tZXRyeSBleHRlbmRzIEJ1ZmZlckdlb21ldHJ5IHtcclxuXHJcblx0Y29uc3RydWN0b3IoIHJhZGl1cyA9IDEsIHNlZ21lbnRzID0gMzIsIHRoZXRhU3RhcnQgPSAwLCB0aGV0YUxlbmd0aCA9IE1hdGguUEkgKiAyICkge1xyXG5cclxuXHRcdHN1cGVyKCk7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ0NpcmNsZUdlb21ldHJ5JztcclxuXHJcblx0XHR0aGlzLnBhcmFtZXRlcnMgPSB7XHJcblx0XHRcdHJhZGl1czogcmFkaXVzLFxyXG5cdFx0XHRzZWdtZW50czogc2VnbWVudHMsXHJcblx0XHRcdHRoZXRhU3RhcnQ6IHRoZXRhU3RhcnQsXHJcblx0XHRcdHRoZXRhTGVuZ3RoOiB0aGV0YUxlbmd0aFxyXG5cdFx0fTtcclxuXHJcblx0XHRzZWdtZW50cyA9IE1hdGgubWF4KCAzLCBzZWdtZW50cyApO1xyXG5cclxuXHRcdC8vIGJ1ZmZlcnNcclxuXHJcblx0XHRjb25zdCBpbmRpY2VzID0gW107XHJcblx0XHRjb25zdCB2ZXJ0aWNlcyA9IFtdO1xyXG5cdFx0Y29uc3Qgbm9ybWFscyA9IFtdO1xyXG5cdFx0Y29uc3QgdXZzID0gW107XHJcblxyXG5cdFx0Ly8gaGVscGVyIHZhcmlhYmxlc1xyXG5cclxuXHRcdGNvbnN0IHZlcnRleCA9IG5ldyBWZWN0b3IzKCk7XHJcblx0XHRjb25zdCB1diA9IG5ldyBWZWN0b3IyKCk7XHJcblxyXG5cdFx0Ly8gY2VudGVyIHBvaW50XHJcblxyXG5cdFx0dmVydGljZXMucHVzaCggMCwgMCwgMCApO1xyXG5cdFx0bm9ybWFscy5wdXNoKCAwLCAwLCAxICk7XHJcblx0XHR1dnMucHVzaCggMC41LCAwLjUgKTtcclxuXHJcblx0XHRmb3IgKCBsZXQgcyA9IDAsIGkgPSAzOyBzIDw9IHNlZ21lbnRzOyBzICsrLCBpICs9IDMgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBzZWdtZW50ID0gdGhldGFTdGFydCArIHMgLyBzZWdtZW50cyAqIHRoZXRhTGVuZ3RoO1xyXG5cclxuXHRcdFx0Ly8gdmVydGV4XHJcblxyXG5cdFx0XHR2ZXJ0ZXgueCA9IHJhZGl1cyAqIE1hdGguY29zKCBzZWdtZW50ICk7XHJcblx0XHRcdHZlcnRleC55ID0gcmFkaXVzICogTWF0aC5zaW4oIHNlZ21lbnQgKTtcclxuXHJcblx0XHRcdHZlcnRpY2VzLnB1c2goIHZlcnRleC54LCB2ZXJ0ZXgueSwgdmVydGV4LnogKTtcclxuXHJcblx0XHRcdC8vIG5vcm1hbFxyXG5cclxuXHRcdFx0bm9ybWFscy5wdXNoKCAwLCAwLCAxICk7XHJcblxyXG5cdFx0XHQvLyB1dnNcclxuXHJcblx0XHRcdHV2LnggPSAoIHZlcnRpY2VzWyBpIF0gLyByYWRpdXMgKyAxICkgLyAyO1xyXG5cdFx0XHR1di55ID0gKCB2ZXJ0aWNlc1sgaSArIDEgXSAvIHJhZGl1cyArIDEgKSAvIDI7XHJcblxyXG5cdFx0XHR1dnMucHVzaCggdXYueCwgdXYueSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvLyBpbmRpY2VzXHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAxOyBpIDw9IHNlZ21lbnRzOyBpICsrICkge1xyXG5cclxuXHRcdFx0aW5kaWNlcy5wdXNoKCBpLCBpICsgMSwgMCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvLyBidWlsZCBnZW9tZXRyeVxyXG5cclxuXHRcdHRoaXMuc2V0SW5kZXgoIGluZGljZXMgKTtcclxuXHRcdHRoaXMuc2V0QXR0cmlidXRlKCAncG9zaXRpb24nLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggdmVydGljZXMsIDMgKSApO1xyXG5cdFx0dGhpcy5zZXRBdHRyaWJ1dGUoICdub3JtYWwnLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggbm9ybWFscywgMyApICk7XHJcblx0XHR0aGlzLnNldEF0dHJpYnV0ZSggJ3V2JywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIHV2cywgMiApICk7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xyXG5cclxuXHRcdHRoaXMucGFyYW1ldGVycyA9IE9iamVjdC5hc3NpZ24oIHt9LCBzb3VyY2UucGFyYW1ldGVycyApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHN0YXRpYyBmcm9tSlNPTiggZGF0YSApIHtcclxuXHJcblx0XHRyZXR1cm4gbmV3IENpcmNsZUdlb21ldHJ5KCBkYXRhLnJhZGl1cywgZGF0YS5zZWdtZW50cywgZGF0YS50aGV0YVN0YXJ0LCBkYXRhLnRoZXRhTGVuZ3RoICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcblxyXG5leHBvcnQgeyBDaXJjbGVHZW9tZXRyeSB9O1xyXG4iLCJpbXBvcnQgeyBCdWZmZXJHZW9tZXRyeSB9IGZyb20gJy4uL2NvcmUvQnVmZmVyR2VvbWV0cnkuanMnO1xyXG5pbXBvcnQgeyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlIH0gZnJvbSAnLi4vY29yZS9CdWZmZXJBdHRyaWJ1dGUuanMnO1xyXG5pbXBvcnQgeyBWZWN0b3IzIH0gZnJvbSAnLi4vbWF0aC9WZWN0b3IzLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yMiB9IGZyb20gJy4uL21hdGgvVmVjdG9yMi5qcyc7XHJcblxyXG5jbGFzcyBDeWxpbmRlckdlb21ldHJ5IGV4dGVuZHMgQnVmZmVyR2VvbWV0cnkge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggcmFkaXVzVG9wID0gMSwgcmFkaXVzQm90dG9tID0gMSwgaGVpZ2h0ID0gMSwgcmFkaWFsU2VnbWVudHMgPSAzMiwgaGVpZ2h0U2VnbWVudHMgPSAxLCBvcGVuRW5kZWQgPSBmYWxzZSwgdGhldGFTdGFydCA9IDAsIHRoZXRhTGVuZ3RoID0gTWF0aC5QSSAqIDIgKSB7XHJcblxyXG5cdFx0c3VwZXIoKTtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSAnQ3lsaW5kZXJHZW9tZXRyeSc7XHJcblxyXG5cdFx0dGhpcy5wYXJhbWV0ZXJzID0ge1xyXG5cdFx0XHRyYWRpdXNUb3A6IHJhZGl1c1RvcCxcclxuXHRcdFx0cmFkaXVzQm90dG9tOiByYWRpdXNCb3R0b20sXHJcblx0XHRcdGhlaWdodDogaGVpZ2h0LFxyXG5cdFx0XHRyYWRpYWxTZWdtZW50czogcmFkaWFsU2VnbWVudHMsXHJcblx0XHRcdGhlaWdodFNlZ21lbnRzOiBoZWlnaHRTZWdtZW50cyxcclxuXHRcdFx0b3BlbkVuZGVkOiBvcGVuRW5kZWQsXHJcblx0XHRcdHRoZXRhU3RhcnQ6IHRoZXRhU3RhcnQsXHJcblx0XHRcdHRoZXRhTGVuZ3RoOiB0aGV0YUxlbmd0aFxyXG5cdFx0fTtcclxuXHJcblx0XHRjb25zdCBzY29wZSA9IHRoaXM7XHJcblxyXG5cdFx0cmFkaWFsU2VnbWVudHMgPSBNYXRoLmZsb29yKCByYWRpYWxTZWdtZW50cyApO1xyXG5cdFx0aGVpZ2h0U2VnbWVudHMgPSBNYXRoLmZsb29yKCBoZWlnaHRTZWdtZW50cyApO1xyXG5cclxuXHRcdC8vIGJ1ZmZlcnNcclxuXHJcblx0XHRjb25zdCBpbmRpY2VzID0gW107XHJcblx0XHRjb25zdCB2ZXJ0aWNlcyA9IFtdO1xyXG5cdFx0Y29uc3Qgbm9ybWFscyA9IFtdO1xyXG5cdFx0Y29uc3QgdXZzID0gW107XHJcblxyXG5cdFx0Ly8gaGVscGVyIHZhcmlhYmxlc1xyXG5cclxuXHRcdGxldCBpbmRleCA9IDA7XHJcblx0XHRjb25zdCBpbmRleEFycmF5ID0gW107XHJcblx0XHRjb25zdCBoYWxmSGVpZ2h0ID0gaGVpZ2h0IC8gMjtcclxuXHRcdGxldCBncm91cFN0YXJ0ID0gMDtcclxuXHJcblx0XHQvLyBnZW5lcmF0ZSBnZW9tZXRyeVxyXG5cclxuXHRcdGdlbmVyYXRlVG9yc28oKTtcclxuXHJcblx0XHRpZiAoIG9wZW5FbmRlZCA9PT0gZmFsc2UgKSB7XHJcblxyXG5cdFx0XHRpZiAoIHJhZGl1c1RvcCA+IDAgKSBnZW5lcmF0ZUNhcCggdHJ1ZSApO1xyXG5cdFx0XHRpZiAoIHJhZGl1c0JvdHRvbSA+IDAgKSBnZW5lcmF0ZUNhcCggZmFsc2UgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gYnVpbGQgZ2VvbWV0cnlcclxuXHJcblx0XHR0aGlzLnNldEluZGV4KCBpbmRpY2VzICk7XHJcblx0XHR0aGlzLnNldEF0dHJpYnV0ZSggJ3Bvc2l0aW9uJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIHZlcnRpY2VzLCAzICkgKTtcclxuXHRcdHRoaXMuc2V0QXR0cmlidXRlKCAnbm9ybWFsJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIG5vcm1hbHMsIDMgKSApO1xyXG5cdFx0dGhpcy5zZXRBdHRyaWJ1dGUoICd1dicsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCB1dnMsIDIgKSApO1xyXG5cclxuXHRcdGZ1bmN0aW9uIGdlbmVyYXRlVG9yc28oKSB7XHJcblxyXG5cdFx0XHRjb25zdCBub3JtYWwgPSBuZXcgVmVjdG9yMygpO1xyXG5cdFx0XHRjb25zdCB2ZXJ0ZXggPSBuZXcgVmVjdG9yMygpO1xyXG5cclxuXHRcdFx0bGV0IGdyb3VwQ291bnQgPSAwO1xyXG5cclxuXHRcdFx0Ly8gdGhpcyB3aWxsIGJlIHVzZWQgdG8gY2FsY3VsYXRlIHRoZSBub3JtYWxcclxuXHRcdFx0Y29uc3Qgc2xvcGUgPSAoIHJhZGl1c0JvdHRvbSAtIHJhZGl1c1RvcCApIC8gaGVpZ2h0O1xyXG5cclxuXHRcdFx0Ly8gZ2VuZXJhdGUgdmVydGljZXMsIG5vcm1hbHMgYW5kIHV2c1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IHkgPSAwOyB5IDw9IGhlaWdodFNlZ21lbnRzOyB5ICsrICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBpbmRleFJvdyA9IFtdO1xyXG5cclxuXHRcdFx0XHRjb25zdCB2ID0geSAvIGhlaWdodFNlZ21lbnRzO1xyXG5cclxuXHRcdFx0XHQvLyBjYWxjdWxhdGUgdGhlIHJhZGl1cyBvZiB0aGUgY3VycmVudCByb3dcclxuXHJcblx0XHRcdFx0Y29uc3QgcmFkaXVzID0gdiAqICggcmFkaXVzQm90dG9tIC0gcmFkaXVzVG9wICkgKyByYWRpdXNUb3A7XHJcblxyXG5cdFx0XHRcdGZvciAoIGxldCB4ID0gMDsgeCA8PSByYWRpYWxTZWdtZW50czsgeCArKyApIHtcclxuXHJcblx0XHRcdFx0XHRjb25zdCB1ID0geCAvIHJhZGlhbFNlZ21lbnRzO1xyXG5cclxuXHRcdFx0XHRcdGNvbnN0IHRoZXRhID0gdSAqIHRoZXRhTGVuZ3RoICsgdGhldGFTdGFydDtcclxuXHJcblx0XHRcdFx0XHRjb25zdCBzaW5UaGV0YSA9IE1hdGguc2luKCB0aGV0YSApO1xyXG5cdFx0XHRcdFx0Y29uc3QgY29zVGhldGEgPSBNYXRoLmNvcyggdGhldGEgKTtcclxuXHJcblx0XHRcdFx0XHQvLyB2ZXJ0ZXhcclxuXHJcblx0XHRcdFx0XHR2ZXJ0ZXgueCA9IHJhZGl1cyAqIHNpblRoZXRhO1xyXG5cdFx0XHRcdFx0dmVydGV4LnkgPSAtIHYgKiBoZWlnaHQgKyBoYWxmSGVpZ2h0O1xyXG5cdFx0XHRcdFx0dmVydGV4LnogPSByYWRpdXMgKiBjb3NUaGV0YTtcclxuXHRcdFx0XHRcdHZlcnRpY2VzLnB1c2goIHZlcnRleC54LCB2ZXJ0ZXgueSwgdmVydGV4LnogKTtcclxuXHJcblx0XHRcdFx0XHQvLyBub3JtYWxcclxuXHJcblx0XHRcdFx0XHRub3JtYWwuc2V0KCBzaW5UaGV0YSwgc2xvcGUsIGNvc1RoZXRhICkubm9ybWFsaXplKCk7XHJcblx0XHRcdFx0XHRub3JtYWxzLnB1c2goIG5vcm1hbC54LCBub3JtYWwueSwgbm9ybWFsLnogKTtcclxuXHJcblx0XHRcdFx0XHQvLyB1dlxyXG5cclxuXHRcdFx0XHRcdHV2cy5wdXNoKCB1LCAxIC0gdiApO1xyXG5cclxuXHRcdFx0XHRcdC8vIHNhdmUgaW5kZXggb2YgdmVydGV4IGluIHJlc3BlY3RpdmUgcm93XHJcblxyXG5cdFx0XHRcdFx0aW5kZXhSb3cucHVzaCggaW5kZXggKysgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHQvLyBub3cgc2F2ZSB2ZXJ0aWNlcyBvZiB0aGUgcm93IGluIG91ciBpbmRleCBhcnJheVxyXG5cclxuXHRcdFx0XHRpbmRleEFycmF5LnB1c2goIGluZGV4Um93ICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyBnZW5lcmF0ZSBpbmRpY2VzXHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgeCA9IDA7IHggPCByYWRpYWxTZWdtZW50czsgeCArKyApIHtcclxuXHJcblx0XHRcdFx0Zm9yICggbGV0IHkgPSAwOyB5IDwgaGVpZ2h0U2VnbWVudHM7IHkgKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0Ly8gd2UgdXNlIHRoZSBpbmRleCBhcnJheSB0byBhY2Nlc3MgdGhlIGNvcnJlY3QgaW5kaWNlc1xyXG5cclxuXHRcdFx0XHRcdGNvbnN0IGEgPSBpbmRleEFycmF5WyB5IF1bIHggXTtcclxuXHRcdFx0XHRcdGNvbnN0IGIgPSBpbmRleEFycmF5WyB5ICsgMSBdWyB4IF07XHJcblx0XHRcdFx0XHRjb25zdCBjID0gaW5kZXhBcnJheVsgeSArIDEgXVsgeCArIDEgXTtcclxuXHRcdFx0XHRcdGNvbnN0IGQgPSBpbmRleEFycmF5WyB5IF1bIHggKyAxIF07XHJcblxyXG5cdFx0XHRcdFx0Ly8gZmFjZXNcclxuXHJcblx0XHRcdFx0XHRpbmRpY2VzLnB1c2goIGEsIGIsIGQgKTtcclxuXHRcdFx0XHRcdGluZGljZXMucHVzaCggYiwgYywgZCApO1xyXG5cclxuXHRcdFx0XHRcdC8vIHVwZGF0ZSBncm91cCBjb3VudGVyXHJcblxyXG5cdFx0XHRcdFx0Z3JvdXBDb3VudCArPSA2O1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyBhZGQgYSBncm91cCB0byB0aGUgZ2VvbWV0cnkuIHRoaXMgd2lsbCBlbnN1cmUgbXVsdGkgbWF0ZXJpYWwgc3VwcG9ydFxyXG5cclxuXHRcdFx0c2NvcGUuYWRkR3JvdXAoIGdyb3VwU3RhcnQsIGdyb3VwQ291bnQsIDAgKTtcclxuXHJcblx0XHRcdC8vIGNhbGN1bGF0ZSBuZXcgc3RhcnQgdmFsdWUgZm9yIGdyb3Vwc1xyXG5cclxuXHRcdFx0Z3JvdXBTdGFydCArPSBncm91cENvdW50O1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRmdW5jdGlvbiBnZW5lcmF0ZUNhcCggdG9wICkge1xyXG5cclxuXHRcdFx0Ly8gc2F2ZSB0aGUgaW5kZXggb2YgdGhlIGZpcnN0IGNlbnRlciB2ZXJ0ZXhcclxuXHRcdFx0Y29uc3QgY2VudGVySW5kZXhTdGFydCA9IGluZGV4O1xyXG5cclxuXHRcdFx0Y29uc3QgdXYgPSBuZXcgVmVjdG9yMigpO1xyXG5cdFx0XHRjb25zdCB2ZXJ0ZXggPSBuZXcgVmVjdG9yMygpO1xyXG5cclxuXHRcdFx0bGV0IGdyb3VwQ291bnQgPSAwO1xyXG5cclxuXHRcdFx0Y29uc3QgcmFkaXVzID0gKCB0b3AgPT09IHRydWUgKSA/IHJhZGl1c1RvcCA6IHJhZGl1c0JvdHRvbTtcclxuXHRcdFx0Y29uc3Qgc2lnbiA9ICggdG9wID09PSB0cnVlICkgPyAxIDogLSAxO1xyXG5cclxuXHRcdFx0Ly8gZmlyc3Qgd2UgZ2VuZXJhdGUgdGhlIGNlbnRlciB2ZXJ0ZXggZGF0YSBvZiB0aGUgY2FwLlxyXG5cdFx0XHQvLyBiZWNhdXNlIHRoZSBnZW9tZXRyeSBuZWVkcyBvbmUgc2V0IG9mIHV2cyBwZXIgZmFjZSxcclxuXHRcdFx0Ly8gd2UgbXVzdCBnZW5lcmF0ZSBhIGNlbnRlciB2ZXJ0ZXggcGVyIGZhY2Uvc2VnbWVudFxyXG5cclxuXHRcdFx0Zm9yICggbGV0IHggPSAxOyB4IDw9IHJhZGlhbFNlZ21lbnRzOyB4ICsrICkge1xyXG5cclxuXHRcdFx0XHQvLyB2ZXJ0ZXhcclxuXHJcblx0XHRcdFx0dmVydGljZXMucHVzaCggMCwgaGFsZkhlaWdodCAqIHNpZ24sIDAgKTtcclxuXHJcblx0XHRcdFx0Ly8gbm9ybWFsXHJcblxyXG5cdFx0XHRcdG5vcm1hbHMucHVzaCggMCwgc2lnbiwgMCApO1xyXG5cclxuXHRcdFx0XHQvLyB1dlxyXG5cclxuXHRcdFx0XHR1dnMucHVzaCggMC41LCAwLjUgKTtcclxuXHJcblx0XHRcdFx0Ly8gaW5jcmVhc2UgaW5kZXhcclxuXHJcblx0XHRcdFx0aW5kZXggKys7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyBzYXZlIHRoZSBpbmRleCBvZiB0aGUgbGFzdCBjZW50ZXIgdmVydGV4XHJcblx0XHRcdGNvbnN0IGNlbnRlckluZGV4RW5kID0gaW5kZXg7XHJcblxyXG5cdFx0XHQvLyBub3cgd2UgZ2VuZXJhdGUgdGhlIHN1cnJvdW5kaW5nIHZlcnRpY2VzLCBub3JtYWxzIGFuZCB1dnNcclxuXHJcblx0XHRcdGZvciAoIGxldCB4ID0gMDsgeCA8PSByYWRpYWxTZWdtZW50czsgeCArKyApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgdSA9IHggLyByYWRpYWxTZWdtZW50cztcclxuXHRcdFx0XHRjb25zdCB0aGV0YSA9IHUgKiB0aGV0YUxlbmd0aCArIHRoZXRhU3RhcnQ7XHJcblxyXG5cdFx0XHRcdGNvbnN0IGNvc1RoZXRhID0gTWF0aC5jb3MoIHRoZXRhICk7XHJcblx0XHRcdFx0Y29uc3Qgc2luVGhldGEgPSBNYXRoLnNpbiggdGhldGEgKTtcclxuXHJcblx0XHRcdFx0Ly8gdmVydGV4XHJcblxyXG5cdFx0XHRcdHZlcnRleC54ID0gcmFkaXVzICogc2luVGhldGE7XHJcblx0XHRcdFx0dmVydGV4LnkgPSBoYWxmSGVpZ2h0ICogc2lnbjtcclxuXHRcdFx0XHR2ZXJ0ZXgueiA9IHJhZGl1cyAqIGNvc1RoZXRhO1xyXG5cdFx0XHRcdHZlcnRpY2VzLnB1c2goIHZlcnRleC54LCB2ZXJ0ZXgueSwgdmVydGV4LnogKTtcclxuXHJcblx0XHRcdFx0Ly8gbm9ybWFsXHJcblxyXG5cdFx0XHRcdG5vcm1hbHMucHVzaCggMCwgc2lnbiwgMCApO1xyXG5cclxuXHRcdFx0XHQvLyB1dlxyXG5cclxuXHRcdFx0XHR1di54ID0gKCBjb3NUaGV0YSAqIDAuNSApICsgMC41O1xyXG5cdFx0XHRcdHV2LnkgPSAoIHNpblRoZXRhICogMC41ICogc2lnbiApICsgMC41O1xyXG5cdFx0XHRcdHV2cy5wdXNoKCB1di54LCB1di55ICk7XHJcblxyXG5cdFx0XHRcdC8vIGluY3JlYXNlIGluZGV4XHJcblxyXG5cdFx0XHRcdGluZGV4ICsrO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Ly8gZ2VuZXJhdGUgaW5kaWNlc1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IHggPSAwOyB4IDwgcmFkaWFsU2VnbWVudHM7IHggKysgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IGMgPSBjZW50ZXJJbmRleFN0YXJ0ICsgeDtcclxuXHRcdFx0XHRjb25zdCBpID0gY2VudGVySW5kZXhFbmQgKyB4O1xyXG5cclxuXHRcdFx0XHRpZiAoIHRvcCA9PT0gdHJ1ZSApIHtcclxuXHJcblx0XHRcdFx0XHQvLyBmYWNlIHRvcFxyXG5cclxuXHRcdFx0XHRcdGluZGljZXMucHVzaCggaSwgaSArIDEsIGMgKTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHQvLyBmYWNlIGJvdHRvbVxyXG5cclxuXHRcdFx0XHRcdGluZGljZXMucHVzaCggaSArIDEsIGksIGMgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRncm91cENvdW50ICs9IDM7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyBhZGQgYSBncm91cCB0byB0aGUgZ2VvbWV0cnkuIHRoaXMgd2lsbCBlbnN1cmUgbXVsdGkgbWF0ZXJpYWwgc3VwcG9ydFxyXG5cclxuXHRcdFx0c2NvcGUuYWRkR3JvdXAoIGdyb3VwU3RhcnQsIGdyb3VwQ291bnQsIHRvcCA9PT0gdHJ1ZSA/IDEgOiAyICk7XHJcblxyXG5cdFx0XHQvLyBjYWxjdWxhdGUgbmV3IHN0YXJ0IHZhbHVlIGZvciBncm91cHNcclxuXHJcblx0XHRcdGdyb3VwU3RhcnQgKz0gZ3JvdXBDb3VudDtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xyXG5cclxuXHRcdHRoaXMucGFyYW1ldGVycyA9IE9iamVjdC5hc3NpZ24oIHt9LCBzb3VyY2UucGFyYW1ldGVycyApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHN0YXRpYyBmcm9tSlNPTiggZGF0YSApIHtcclxuXHJcblx0XHRyZXR1cm4gbmV3IEN5bGluZGVyR2VvbWV0cnkoIGRhdGEucmFkaXVzVG9wLCBkYXRhLnJhZGl1c0JvdHRvbSwgZGF0YS5oZWlnaHQsIGRhdGEucmFkaWFsU2VnbWVudHMsIGRhdGEuaGVpZ2h0U2VnbWVudHMsIGRhdGEub3BlbkVuZGVkLCBkYXRhLnRoZXRhU3RhcnQsIGRhdGEudGhldGFMZW5ndGggKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuXHJcbmV4cG9ydCB7IEN5bGluZGVyR2VvbWV0cnkgfTtcclxuIiwiaW1wb3J0IHsgQ3lsaW5kZXJHZW9tZXRyeSB9IGZyb20gJy4vQ3lsaW5kZXJHZW9tZXRyeS5qcyc7XHJcblxyXG5jbGFzcyBDb25lR2VvbWV0cnkgZXh0ZW5kcyBDeWxpbmRlckdlb21ldHJ5IHtcclxuXHJcblx0Y29uc3RydWN0b3IoIHJhZGl1cyA9IDEsIGhlaWdodCA9IDEsIHJhZGlhbFNlZ21lbnRzID0gMzIsIGhlaWdodFNlZ21lbnRzID0gMSwgb3BlbkVuZGVkID0gZmFsc2UsIHRoZXRhU3RhcnQgPSAwLCB0aGV0YUxlbmd0aCA9IE1hdGguUEkgKiAyICkge1xyXG5cclxuXHRcdHN1cGVyKCAwLCByYWRpdXMsIGhlaWdodCwgcmFkaWFsU2VnbWVudHMsIGhlaWdodFNlZ21lbnRzLCBvcGVuRW5kZWQsIHRoZXRhU3RhcnQsIHRoZXRhTGVuZ3RoICk7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ0NvbmVHZW9tZXRyeSc7XHJcblxyXG5cdFx0dGhpcy5wYXJhbWV0ZXJzID0ge1xyXG5cdFx0XHRyYWRpdXM6IHJhZGl1cyxcclxuXHRcdFx0aGVpZ2h0OiBoZWlnaHQsXHJcblx0XHRcdHJhZGlhbFNlZ21lbnRzOiByYWRpYWxTZWdtZW50cyxcclxuXHRcdFx0aGVpZ2h0U2VnbWVudHM6IGhlaWdodFNlZ21lbnRzLFxyXG5cdFx0XHRvcGVuRW5kZWQ6IG9wZW5FbmRlZCxcclxuXHRcdFx0dGhldGFTdGFydDogdGhldGFTdGFydCxcclxuXHRcdFx0dGhldGFMZW5ndGg6IHRoZXRhTGVuZ3RoXHJcblx0XHR9O1xyXG5cclxuXHR9XHJcblxyXG5cdHN0YXRpYyBmcm9tSlNPTiggZGF0YSApIHtcclxuXHJcblx0XHRyZXR1cm4gbmV3IENvbmVHZW9tZXRyeSggZGF0YS5yYWRpdXMsIGRhdGEuaGVpZ2h0LCBkYXRhLnJhZGlhbFNlZ21lbnRzLCBkYXRhLmhlaWdodFNlZ21lbnRzLCBkYXRhLm9wZW5FbmRlZCwgZGF0YS50aGV0YVN0YXJ0LCBkYXRhLnRoZXRhTGVuZ3RoICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IENvbmVHZW9tZXRyeSB9O1xyXG4iLCJpbXBvcnQgeyBCdWZmZXJHZW9tZXRyeSB9IGZyb20gJy4uL2NvcmUvQnVmZmVyR2VvbWV0cnkuanMnO1xyXG5pbXBvcnQgeyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlIH0gZnJvbSAnLi4vY29yZS9CdWZmZXJBdHRyaWJ1dGUuanMnO1xyXG5pbXBvcnQgeyBWZWN0b3IzIH0gZnJvbSAnLi4vbWF0aC9WZWN0b3IzLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yMiB9IGZyb20gJy4uL21hdGgvVmVjdG9yMi5qcyc7XHJcblxyXG5jbGFzcyBQb2x5aGVkcm9uR2VvbWV0cnkgZXh0ZW5kcyBCdWZmZXJHZW9tZXRyeSB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCB2ZXJ0aWNlcyA9IFtdLCBpbmRpY2VzID0gW10sIHJhZGl1cyA9IDEsIGRldGFpbCA9IDAgKSB7XHJcblxyXG5cdFx0c3VwZXIoKTtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSAnUG9seWhlZHJvbkdlb21ldHJ5JztcclxuXHJcblx0XHR0aGlzLnBhcmFtZXRlcnMgPSB7XHJcblx0XHRcdHZlcnRpY2VzOiB2ZXJ0aWNlcyxcclxuXHRcdFx0aW5kaWNlczogaW5kaWNlcyxcclxuXHRcdFx0cmFkaXVzOiByYWRpdXMsXHJcblx0XHRcdGRldGFpbDogZGV0YWlsXHJcblx0XHR9O1xyXG5cclxuXHRcdC8vIGRlZmF1bHQgYnVmZmVyIGRhdGFcclxuXHJcblx0XHRjb25zdCB2ZXJ0ZXhCdWZmZXIgPSBbXTtcclxuXHRcdGNvbnN0IHV2QnVmZmVyID0gW107XHJcblxyXG5cdFx0Ly8gdGhlIHN1YmRpdmlzaW9uIGNyZWF0ZXMgdGhlIHZlcnRleCBidWZmZXIgZGF0YVxyXG5cclxuXHRcdHN1YmRpdmlkZSggZGV0YWlsICk7XHJcblxyXG5cdFx0Ly8gYWxsIHZlcnRpY2VzIHNob3VsZCBsaWUgb24gYSBjb25jZXB0dWFsIHNwaGVyZSB3aXRoIGEgZ2l2ZW4gcmFkaXVzXHJcblxyXG5cdFx0YXBwbHlSYWRpdXMoIHJhZGl1cyApO1xyXG5cclxuXHRcdC8vIGZpbmFsbHksIGNyZWF0ZSB0aGUgdXYgZGF0YVxyXG5cclxuXHRcdGdlbmVyYXRlVVZzKCk7XHJcblxyXG5cdFx0Ly8gYnVpbGQgbm9uLWluZGV4ZWQgZ2VvbWV0cnlcclxuXHJcblx0XHR0aGlzLnNldEF0dHJpYnV0ZSggJ3Bvc2l0aW9uJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIHZlcnRleEJ1ZmZlciwgMyApICk7XHJcblx0XHR0aGlzLnNldEF0dHJpYnV0ZSggJ25vcm1hbCcsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCB2ZXJ0ZXhCdWZmZXIuc2xpY2UoKSwgMyApICk7XHJcblx0XHR0aGlzLnNldEF0dHJpYnV0ZSggJ3V2JywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIHV2QnVmZmVyLCAyICkgKTtcclxuXHJcblx0XHRpZiAoIGRldGFpbCA9PT0gMCApIHtcclxuXHJcblx0XHRcdHRoaXMuY29tcHV0ZVZlcnRleE5vcm1hbHMoKTsgLy8gZmxhdCBub3JtYWxzXHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdHRoaXMubm9ybWFsaXplTm9ybWFscygpOyAvLyBzbW9vdGggbm9ybWFsc1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvLyBoZWxwZXIgZnVuY3Rpb25zXHJcblxyXG5cdFx0ZnVuY3Rpb24gc3ViZGl2aWRlKCBkZXRhaWwgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBhID0gbmV3IFZlY3RvcjMoKTtcclxuXHRcdFx0Y29uc3QgYiA9IG5ldyBWZWN0b3IzKCk7XHJcblx0XHRcdGNvbnN0IGMgPSBuZXcgVmVjdG9yMygpO1xyXG5cclxuXHRcdFx0Ly8gaXRlcmF0ZSBvdmVyIGFsbCBmYWNlcyBhbmQgYXBwbHkgYSBzdWJkaXZpc2lvbiB3aXRoIHRoZSBnaXZlbiBkZXRhaWwgdmFsdWVcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IGluZGljZXMubGVuZ3RoOyBpICs9IDMgKSB7XHJcblxyXG5cdFx0XHRcdC8vIGdldCB0aGUgdmVydGljZXMgb2YgdGhlIGZhY2VcclxuXHJcblx0XHRcdFx0Z2V0VmVydGV4QnlJbmRleCggaW5kaWNlc1sgaSArIDAgXSwgYSApO1xyXG5cdFx0XHRcdGdldFZlcnRleEJ5SW5kZXgoIGluZGljZXNbIGkgKyAxIF0sIGIgKTtcclxuXHRcdFx0XHRnZXRWZXJ0ZXhCeUluZGV4KCBpbmRpY2VzWyBpICsgMiBdLCBjICk7XHJcblxyXG5cdFx0XHRcdC8vIHBlcmZvcm0gc3ViZGl2aXNpb25cclxuXHJcblx0XHRcdFx0c3ViZGl2aWRlRmFjZSggYSwgYiwgYywgZGV0YWlsICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGZ1bmN0aW9uIHN1YmRpdmlkZUZhY2UoIGEsIGIsIGMsIGRldGFpbCApIHtcclxuXHJcblx0XHRcdGNvbnN0IGNvbHMgPSBkZXRhaWwgKyAxO1xyXG5cclxuXHRcdFx0Ly8gd2UgdXNlIHRoaXMgbXVsdGlkaW1lbnNpb25hbCBhcnJheSBhcyBhIGRhdGEgc3RydWN0dXJlIGZvciBjcmVhdGluZyB0aGUgc3ViZGl2aXNpb25cclxuXHJcblx0XHRcdGNvbnN0IHYgPSBbXTtcclxuXHJcblx0XHRcdC8vIGNvbnN0cnVjdCBhbGwgb2YgdGhlIHZlcnRpY2VzIGZvciB0aGlzIHN1YmRpdmlzaW9uXHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPD0gY29sczsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0dlsgaSBdID0gW107XHJcblxyXG5cdFx0XHRcdGNvbnN0IGFqID0gYS5jbG9uZSgpLmxlcnAoIGMsIGkgLyBjb2xzICk7XHJcblx0XHRcdFx0Y29uc3QgYmogPSBiLmNsb25lKCkubGVycCggYywgaSAvIGNvbHMgKTtcclxuXHJcblx0XHRcdFx0Y29uc3Qgcm93cyA9IGNvbHMgLSBpO1xyXG5cclxuXHRcdFx0XHRmb3IgKCBsZXQgaiA9IDA7IGogPD0gcm93czsgaiArKyApIHtcclxuXHJcblx0XHRcdFx0XHRpZiAoIGogPT09IDAgJiYgaSA9PT0gY29scyApIHtcclxuXHJcblx0XHRcdFx0XHRcdHZbIGkgXVsgaiBdID0gYWo7XHJcblxyXG5cdFx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRcdHZbIGkgXVsgaiBdID0gYWouY2xvbmUoKS5sZXJwKCBiaiwgaiAvIHJvd3MgKTtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdC8vIGNvbnN0cnVjdCBhbGwgb2YgdGhlIGZhY2VzXHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBjb2xzOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRmb3IgKCBsZXQgaiA9IDA7IGogPCAyICogKCBjb2xzIC0gaSApIC0gMTsgaiArKyApIHtcclxuXHJcblx0XHRcdFx0XHRjb25zdCBrID0gTWF0aC5mbG9vciggaiAvIDIgKTtcclxuXHJcblx0XHRcdFx0XHRpZiAoIGogJSAyID09PSAwICkge1xyXG5cclxuXHRcdFx0XHRcdFx0cHVzaFZlcnRleCggdlsgaSBdWyBrICsgMSBdICk7XHJcblx0XHRcdFx0XHRcdHB1c2hWZXJ0ZXgoIHZbIGkgKyAxIF1bIGsgXSApO1xyXG5cdFx0XHRcdFx0XHRwdXNoVmVydGV4KCB2WyBpIF1bIGsgXSApO1xyXG5cclxuXHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHRwdXNoVmVydGV4KCB2WyBpIF1bIGsgKyAxIF0gKTtcclxuXHRcdFx0XHRcdFx0cHVzaFZlcnRleCggdlsgaSArIDEgXVsgayArIDEgXSApO1xyXG5cdFx0XHRcdFx0XHRwdXNoVmVydGV4KCB2WyBpICsgMSBdWyBrIF0gKTtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0ZnVuY3Rpb24gYXBwbHlSYWRpdXMoIHJhZGl1cyApIHtcclxuXHJcblx0XHRcdGNvbnN0IHZlcnRleCA9IG5ldyBWZWN0b3IzKCk7XHJcblxyXG5cdFx0XHQvLyBpdGVyYXRlIG92ZXIgdGhlIGVudGlyZSBidWZmZXIgYW5kIGFwcGx5IHRoZSByYWRpdXMgdG8gZWFjaCB2ZXJ0ZXhcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHZlcnRleEJ1ZmZlci5sZW5ndGg7IGkgKz0gMyApIHtcclxuXHJcblx0XHRcdFx0dmVydGV4LnggPSB2ZXJ0ZXhCdWZmZXJbIGkgKyAwIF07XHJcblx0XHRcdFx0dmVydGV4LnkgPSB2ZXJ0ZXhCdWZmZXJbIGkgKyAxIF07XHJcblx0XHRcdFx0dmVydGV4LnogPSB2ZXJ0ZXhCdWZmZXJbIGkgKyAyIF07XHJcblxyXG5cdFx0XHRcdHZlcnRleC5ub3JtYWxpemUoKS5tdWx0aXBseVNjYWxhciggcmFkaXVzICk7XHJcblxyXG5cdFx0XHRcdHZlcnRleEJ1ZmZlclsgaSArIDAgXSA9IHZlcnRleC54O1xyXG5cdFx0XHRcdHZlcnRleEJ1ZmZlclsgaSArIDEgXSA9IHZlcnRleC55O1xyXG5cdFx0XHRcdHZlcnRleEJ1ZmZlclsgaSArIDIgXSA9IHZlcnRleC56O1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRmdW5jdGlvbiBnZW5lcmF0ZVVWcygpIHtcclxuXHJcblx0XHRcdGNvbnN0IHZlcnRleCA9IG5ldyBWZWN0b3IzKCk7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCB2ZXJ0ZXhCdWZmZXIubGVuZ3RoOyBpICs9IDMgKSB7XHJcblxyXG5cdFx0XHRcdHZlcnRleC54ID0gdmVydGV4QnVmZmVyWyBpICsgMCBdO1xyXG5cdFx0XHRcdHZlcnRleC55ID0gdmVydGV4QnVmZmVyWyBpICsgMSBdO1xyXG5cdFx0XHRcdHZlcnRleC56ID0gdmVydGV4QnVmZmVyWyBpICsgMiBdO1xyXG5cclxuXHRcdFx0XHRjb25zdCB1ID0gYXppbXV0aCggdmVydGV4ICkgLyAyIC8gTWF0aC5QSSArIDAuNTtcclxuXHRcdFx0XHRjb25zdCB2ID0gaW5jbGluYXRpb24oIHZlcnRleCApIC8gTWF0aC5QSSArIDAuNTtcclxuXHRcdFx0XHR1dkJ1ZmZlci5wdXNoKCB1LCAxIC0gdiApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Y29ycmVjdFVWcygpO1xyXG5cclxuXHRcdFx0Y29ycmVjdFNlYW0oKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0ZnVuY3Rpb24gY29ycmVjdFNlYW0oKSB7XHJcblxyXG5cdFx0XHQvLyBoYW5kbGUgY2FzZSB3aGVuIGZhY2Ugc3RyYWRkbGVzIHRoZSBzZWFtLCBzZWUgIzMyNjlcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHV2QnVmZmVyLmxlbmd0aDsgaSArPSA2ICkge1xyXG5cclxuXHRcdFx0XHQvLyB1diBkYXRhIG9mIGEgc2luZ2xlIGZhY2VcclxuXHJcblx0XHRcdFx0Y29uc3QgeDAgPSB1dkJ1ZmZlclsgaSArIDAgXTtcclxuXHRcdFx0XHRjb25zdCB4MSA9IHV2QnVmZmVyWyBpICsgMiBdO1xyXG5cdFx0XHRcdGNvbnN0IHgyID0gdXZCdWZmZXJbIGkgKyA0IF07XHJcblxyXG5cdFx0XHRcdGNvbnN0IG1heCA9IE1hdGgubWF4KCB4MCwgeDEsIHgyICk7XHJcblx0XHRcdFx0Y29uc3QgbWluID0gTWF0aC5taW4oIHgwLCB4MSwgeDIgKTtcclxuXHJcblx0XHRcdFx0Ly8gMC45IGlzIHNvbWV3aGF0IGFyYml0cmFyeVxyXG5cclxuXHRcdFx0XHRpZiAoIG1heCA+IDAuOSAmJiBtaW4gPCAwLjEgKSB7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCB4MCA8IDAuMiApIHV2QnVmZmVyWyBpICsgMCBdICs9IDE7XHJcblx0XHRcdFx0XHRpZiAoIHgxIDwgMC4yICkgdXZCdWZmZXJbIGkgKyAyIF0gKz0gMTtcclxuXHRcdFx0XHRcdGlmICggeDIgPCAwLjIgKSB1dkJ1ZmZlclsgaSArIDQgXSArPSAxO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGZ1bmN0aW9uIHB1c2hWZXJ0ZXgoIHZlcnRleCApIHtcclxuXHJcblx0XHRcdHZlcnRleEJ1ZmZlci5wdXNoKCB2ZXJ0ZXgueCwgdmVydGV4LnksIHZlcnRleC56ICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGZ1bmN0aW9uIGdldFZlcnRleEJ5SW5kZXgoIGluZGV4LCB2ZXJ0ZXggKSB7XHJcblxyXG5cdFx0XHRjb25zdCBzdHJpZGUgPSBpbmRleCAqIDM7XHJcblxyXG5cdFx0XHR2ZXJ0ZXgueCA9IHZlcnRpY2VzWyBzdHJpZGUgKyAwIF07XHJcblx0XHRcdHZlcnRleC55ID0gdmVydGljZXNbIHN0cmlkZSArIDEgXTtcclxuXHRcdFx0dmVydGV4LnogPSB2ZXJ0aWNlc1sgc3RyaWRlICsgMiBdO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRmdW5jdGlvbiBjb3JyZWN0VVZzKCkge1xyXG5cclxuXHRcdFx0Y29uc3QgYSA9IG5ldyBWZWN0b3IzKCk7XHJcblx0XHRcdGNvbnN0IGIgPSBuZXcgVmVjdG9yMygpO1xyXG5cdFx0XHRjb25zdCBjID0gbmV3IFZlY3RvcjMoKTtcclxuXHJcblx0XHRcdGNvbnN0IGNlbnRyb2lkID0gbmV3IFZlY3RvcjMoKTtcclxuXHJcblx0XHRcdGNvbnN0IHV2QSA9IG5ldyBWZWN0b3IyKCk7XHJcblx0XHRcdGNvbnN0IHV2QiA9IG5ldyBWZWN0b3IyKCk7XHJcblx0XHRcdGNvbnN0IHV2QyA9IG5ldyBWZWN0b3IyKCk7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGogPSAwOyBpIDwgdmVydGV4QnVmZmVyLmxlbmd0aDsgaSArPSA5LCBqICs9IDYgKSB7XHJcblxyXG5cdFx0XHRcdGEuc2V0KCB2ZXJ0ZXhCdWZmZXJbIGkgKyAwIF0sIHZlcnRleEJ1ZmZlclsgaSArIDEgXSwgdmVydGV4QnVmZmVyWyBpICsgMiBdICk7XHJcblx0XHRcdFx0Yi5zZXQoIHZlcnRleEJ1ZmZlclsgaSArIDMgXSwgdmVydGV4QnVmZmVyWyBpICsgNCBdLCB2ZXJ0ZXhCdWZmZXJbIGkgKyA1IF0gKTtcclxuXHRcdFx0XHRjLnNldCggdmVydGV4QnVmZmVyWyBpICsgNiBdLCB2ZXJ0ZXhCdWZmZXJbIGkgKyA3IF0sIHZlcnRleEJ1ZmZlclsgaSArIDggXSApO1xyXG5cclxuXHRcdFx0XHR1dkEuc2V0KCB1dkJ1ZmZlclsgaiArIDAgXSwgdXZCdWZmZXJbIGogKyAxIF0gKTtcclxuXHRcdFx0XHR1dkIuc2V0KCB1dkJ1ZmZlclsgaiArIDIgXSwgdXZCdWZmZXJbIGogKyAzIF0gKTtcclxuXHRcdFx0XHR1dkMuc2V0KCB1dkJ1ZmZlclsgaiArIDQgXSwgdXZCdWZmZXJbIGogKyA1IF0gKTtcclxuXHJcblx0XHRcdFx0Y2VudHJvaWQuY29weSggYSApLmFkZCggYiApLmFkZCggYyApLmRpdmlkZVNjYWxhciggMyApO1xyXG5cclxuXHRcdFx0XHRjb25zdCBhemkgPSBhemltdXRoKCBjZW50cm9pZCApO1xyXG5cclxuXHRcdFx0XHRjb3JyZWN0VVYoIHV2QSwgaiArIDAsIGEsIGF6aSApO1xyXG5cdFx0XHRcdGNvcnJlY3RVViggdXZCLCBqICsgMiwgYiwgYXppICk7XHJcblx0XHRcdFx0Y29ycmVjdFVWKCB1dkMsIGogKyA0LCBjLCBhemkgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0ZnVuY3Rpb24gY29ycmVjdFVWKCB1diwgc3RyaWRlLCB2ZWN0b3IsIGF6aW11dGggKSB7XHJcblxyXG5cdFx0XHRpZiAoICggYXppbXV0aCA8IDAgKSAmJiAoIHV2LnggPT09IDEgKSApIHtcclxuXHJcblx0XHRcdFx0dXZCdWZmZXJbIHN0cmlkZSBdID0gdXYueCAtIDE7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRpZiAoICggdmVjdG9yLnggPT09IDAgKSAmJiAoIHZlY3Rvci56ID09PSAwICkgKSB7XHJcblxyXG5cdFx0XHRcdHV2QnVmZmVyWyBzdHJpZGUgXSA9IGF6aW11dGggLyAyIC8gTWF0aC5QSSArIDAuNTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gQW5nbGUgYXJvdW5kIHRoZSBZIGF4aXMsIGNvdW50ZXItY2xvY2t3aXNlIHdoZW4gbG9va2luZyBmcm9tIGFib3ZlLlxyXG5cclxuXHRcdGZ1bmN0aW9uIGF6aW11dGgoIHZlY3RvciApIHtcclxuXHJcblx0XHRcdHJldHVybiBNYXRoLmF0YW4yKCB2ZWN0b3IueiwgLSB2ZWN0b3IueCApO1xyXG5cclxuXHRcdH1cclxuXHJcblxyXG5cdFx0Ly8gQW5nbGUgYWJvdmUgdGhlIFhaIHBsYW5lLlxyXG5cclxuXHRcdGZ1bmN0aW9uIGluY2xpbmF0aW9uKCB2ZWN0b3IgKSB7XHJcblxyXG5cdFx0XHRyZXR1cm4gTWF0aC5hdGFuMiggLSB2ZWN0b3IueSwgTWF0aC5zcXJ0KCAoIHZlY3Rvci54ICogdmVjdG9yLnggKSArICggdmVjdG9yLnogKiB2ZWN0b3IueiApICkgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xyXG5cclxuXHRcdHRoaXMucGFyYW1ldGVycyA9IE9iamVjdC5hc3NpZ24oIHt9LCBzb3VyY2UucGFyYW1ldGVycyApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHN0YXRpYyBmcm9tSlNPTiggZGF0YSApIHtcclxuXHJcblx0XHRyZXR1cm4gbmV3IFBvbHloZWRyb25HZW9tZXRyeSggZGF0YS52ZXJ0aWNlcywgZGF0YS5pbmRpY2VzLCBkYXRhLnJhZGl1cywgZGF0YS5kZXRhaWxzICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IFBvbHloZWRyb25HZW9tZXRyeSB9O1xyXG4iLCJpbXBvcnQgeyBQb2x5aGVkcm9uR2VvbWV0cnkgfSBmcm9tICcuL1BvbHloZWRyb25HZW9tZXRyeS5qcyc7XHJcblxyXG5jbGFzcyBEb2RlY2FoZWRyb25HZW9tZXRyeSBleHRlbmRzIFBvbHloZWRyb25HZW9tZXRyeSB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCByYWRpdXMgPSAxLCBkZXRhaWwgPSAwICkge1xyXG5cclxuXHRcdGNvbnN0IHQgPSAoIDEgKyBNYXRoLnNxcnQoIDUgKSApIC8gMjtcclxuXHRcdGNvbnN0IHIgPSAxIC8gdDtcclxuXHJcblx0XHRjb25zdCB2ZXJ0aWNlcyA9IFtcclxuXHJcblx0XHRcdC8vICjCsTEsIMKxMSwgwrExKVxyXG5cdFx0XHQtIDEsIC0gMSwgLSAxLFx0LSAxLCAtIDEsIDEsXHJcblx0XHRcdC0gMSwgMSwgLSAxLCAtIDEsIDEsIDEsXHJcblx0XHRcdDEsIC0gMSwgLSAxLCAxLCAtIDEsIDEsXHJcblx0XHRcdDEsIDEsIC0gMSwgMSwgMSwgMSxcclxuXHJcblx0XHRcdC8vICgwLCDCsTEvz4YsIMKxz4YpXHJcblx0XHRcdDAsIC0gciwgLSB0LCAwLCAtIHIsIHQsXHJcblx0XHRcdDAsIHIsIC0gdCwgMCwgciwgdCxcclxuXHJcblx0XHRcdC8vICjCsTEvz4YsIMKxz4YsIDApXHJcblx0XHRcdC0gciwgLSB0LCAwLCAtIHIsIHQsIDAsXHJcblx0XHRcdHIsIC0gdCwgMCwgciwgdCwgMCxcclxuXHJcblx0XHRcdC8vICjCsc+GLCAwLCDCsTEvz4YpXHJcblx0XHRcdC0gdCwgMCwgLSByLCB0LCAwLCAtIHIsXHJcblx0XHRcdC0gdCwgMCwgciwgdCwgMCwgclxyXG5cdFx0XTtcclxuXHJcblx0XHRjb25zdCBpbmRpY2VzID0gW1xyXG5cdFx0XHQzLCAxMSwgNywgXHQzLCA3LCAxNSwgXHQzLCAxNSwgMTMsXHJcblx0XHRcdDcsIDE5LCAxNywgXHQ3LCAxNywgNiwgXHQ3LCA2LCAxNSxcclxuXHRcdFx0MTcsIDQsIDgsIFx0MTcsIDgsIDEwLCBcdDE3LCAxMCwgNixcclxuXHRcdFx0OCwgMCwgMTYsIFx0OCwgMTYsIDIsIFx0OCwgMiwgMTAsXHJcblx0XHRcdDAsIDEyLCAxLCBcdDAsIDEsIDE4LCBcdDAsIDE4LCAxNixcclxuXHRcdFx0NiwgMTAsIDIsIFx0NiwgMiwgMTMsIFx0NiwgMTMsIDE1LFxyXG5cdFx0XHQyLCAxNiwgMTgsIFx0MiwgMTgsIDMsIFx0MiwgMywgMTMsXHJcblx0XHRcdDE4LCAxLCA5LCBcdDE4LCA5LCAxMSwgXHQxOCwgMTEsIDMsXHJcblx0XHRcdDQsIDE0LCAxMiwgXHQ0LCAxMiwgMCwgXHQ0LCAwLCA4LFxyXG5cdFx0XHQxMSwgOSwgNSwgXHQxMSwgNSwgMTksIFx0MTEsIDE5LCA3LFxyXG5cdFx0XHQxOSwgNSwgMTQsIFx0MTksIDE0LCA0LCBcdDE5LCA0LCAxNyxcclxuXHRcdFx0MSwgMTIsIDE0LCBcdDEsIDE0LCA1LCBcdDEsIDUsIDlcclxuXHRcdF07XHJcblxyXG5cdFx0c3VwZXIoIHZlcnRpY2VzLCBpbmRpY2VzLCByYWRpdXMsIGRldGFpbCApO1xyXG5cclxuXHRcdHRoaXMudHlwZSA9ICdEb2RlY2FoZWRyb25HZW9tZXRyeSc7XHJcblxyXG5cdFx0dGhpcy5wYXJhbWV0ZXJzID0ge1xyXG5cdFx0XHRyYWRpdXM6IHJhZGl1cyxcclxuXHRcdFx0ZGV0YWlsOiBkZXRhaWxcclxuXHRcdH07XHJcblxyXG5cdH1cclxuXHJcblx0c3RhdGljIGZyb21KU09OKCBkYXRhICkge1xyXG5cclxuXHRcdHJldHVybiBuZXcgRG9kZWNhaGVkcm9uR2VvbWV0cnkoIGRhdGEucmFkaXVzLCBkYXRhLmRldGFpbCApO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5cclxuZXhwb3J0IHsgRG9kZWNhaGVkcm9uR2VvbWV0cnkgfTtcclxuIiwiaW1wb3J0IHsgQnVmZmVyR2VvbWV0cnkgfSBmcm9tICcuLi9jb3JlL0J1ZmZlckdlb21ldHJ5LmpzJztcclxuaW1wb3J0IHsgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSB9IGZyb20gJy4uL2NvcmUvQnVmZmVyQXR0cmlidXRlLmpzJztcclxuaW1wb3J0ICogYXMgTWF0aFV0aWxzIGZyb20gJy4uL21hdGgvTWF0aFV0aWxzLmpzJztcclxuaW1wb3J0IHsgVHJpYW5nbGUgfSBmcm9tICcuLi9tYXRoL1RyaWFuZ2xlLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yMyB9IGZyb20gJy4uL21hdGgvVmVjdG9yMy5qcyc7XHJcblxyXG5jb25zdCBfdjAgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XHJcbmNvbnN0IF92MSA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuY29uc3QgX25vcm1hbCA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuY29uc3QgX3RyaWFuZ2xlID0gLypAX19QVVJFX18qLyBuZXcgVHJpYW5nbGUoKTtcclxuXHJcbmNsYXNzIEVkZ2VzR2VvbWV0cnkgZXh0ZW5kcyBCdWZmZXJHZW9tZXRyeSB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBnZW9tZXRyeSA9IG51bGwsIHRocmVzaG9sZEFuZ2xlID0gMSApIHtcclxuXHJcblx0XHRzdXBlcigpO1xyXG5cclxuXHRcdHRoaXMudHlwZSA9ICdFZGdlc0dlb21ldHJ5JztcclxuXHJcblx0XHR0aGlzLnBhcmFtZXRlcnMgPSB7XHJcblx0XHRcdGdlb21ldHJ5OiBnZW9tZXRyeSxcclxuXHRcdFx0dGhyZXNob2xkQW5nbGU6IHRocmVzaG9sZEFuZ2xlXHJcblx0XHR9O1xyXG5cclxuXHRcdGlmICggZ2VvbWV0cnkgIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBwcmVjaXNpb25Qb2ludHMgPSA0O1xyXG5cdFx0XHRjb25zdCBwcmVjaXNpb24gPSBNYXRoLnBvdyggMTAsIHByZWNpc2lvblBvaW50cyApO1xyXG5cdFx0XHRjb25zdCB0aHJlc2hvbGREb3QgPSBNYXRoLmNvcyggTWF0aFV0aWxzLkRFRzJSQUQgKiB0aHJlc2hvbGRBbmdsZSApO1xyXG5cclxuXHRcdFx0Y29uc3QgaW5kZXhBdHRyID0gZ2VvbWV0cnkuZ2V0SW5kZXgoKTtcclxuXHRcdFx0Y29uc3QgcG9zaXRpb25BdHRyID0gZ2VvbWV0cnkuZ2V0QXR0cmlidXRlKCAncG9zaXRpb24nICk7XHJcblx0XHRcdGNvbnN0IGluZGV4Q291bnQgPSBpbmRleEF0dHIgPyBpbmRleEF0dHIuY291bnQgOiBwb3NpdGlvbkF0dHIuY291bnQ7XHJcblxyXG5cdFx0XHRjb25zdCBpbmRleEFyciA9IFsgMCwgMCwgMCBdO1xyXG5cdFx0XHRjb25zdCB2ZXJ0S2V5cyA9IFsgJ2EnLCAnYicsICdjJyBdO1xyXG5cdFx0XHRjb25zdCBoYXNoZXMgPSBuZXcgQXJyYXkoIDMgKTtcclxuXHJcblx0XHRcdGNvbnN0IGVkZ2VEYXRhID0ge307XHJcblx0XHRcdGNvbnN0IHZlcnRpY2VzID0gW107XHJcblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IGluZGV4Q291bnQ7IGkgKz0gMyApIHtcclxuXHJcblx0XHRcdFx0aWYgKCBpbmRleEF0dHIgKSB7XHJcblxyXG5cdFx0XHRcdFx0aW5kZXhBcnJbIDAgXSA9IGluZGV4QXR0ci5nZXRYKCBpICk7XHJcblx0XHRcdFx0XHRpbmRleEFyclsgMSBdID0gaW5kZXhBdHRyLmdldFgoIGkgKyAxICk7XHJcblx0XHRcdFx0XHRpbmRleEFyclsgMiBdID0gaW5kZXhBdHRyLmdldFgoIGkgKyAyICk7XHJcblxyXG5cdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0aW5kZXhBcnJbIDAgXSA9IGk7XHJcblx0XHRcdFx0XHRpbmRleEFyclsgMSBdID0gaSArIDE7XHJcblx0XHRcdFx0XHRpbmRleEFyclsgMiBdID0gaSArIDI7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0Y29uc3QgeyBhLCBiLCBjIH0gPSBfdHJpYW5nbGU7XHJcblx0XHRcdFx0YS5mcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbkF0dHIsIGluZGV4QXJyWyAwIF0gKTtcclxuXHRcdFx0XHRiLmZyb21CdWZmZXJBdHRyaWJ1dGUoIHBvc2l0aW9uQXR0ciwgaW5kZXhBcnJbIDEgXSApO1xyXG5cdFx0XHRcdGMuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggcG9zaXRpb25BdHRyLCBpbmRleEFyclsgMiBdICk7XHJcblx0XHRcdFx0X3RyaWFuZ2xlLmdldE5vcm1hbCggX25vcm1hbCApO1xyXG5cclxuXHRcdFx0XHQvLyBjcmVhdGUgaGFzaGVzIGZvciB0aGUgZWRnZSBmcm9tIHRoZSB2ZXJ0aWNlc1xyXG5cdFx0XHRcdGhhc2hlc1sgMCBdID0gYCR7IE1hdGgucm91bmQoIGEueCAqIHByZWNpc2lvbiApIH0sJHsgTWF0aC5yb3VuZCggYS55ICogcHJlY2lzaW9uICkgfSwkeyBNYXRoLnJvdW5kKCBhLnogKiBwcmVjaXNpb24gKSB9YDtcclxuXHRcdFx0XHRoYXNoZXNbIDEgXSA9IGAkeyBNYXRoLnJvdW5kKCBiLnggKiBwcmVjaXNpb24gKSB9LCR7IE1hdGgucm91bmQoIGIueSAqIHByZWNpc2lvbiApIH0sJHsgTWF0aC5yb3VuZCggYi56ICogcHJlY2lzaW9uICkgfWA7XHJcblx0XHRcdFx0aGFzaGVzWyAyIF0gPSBgJHsgTWF0aC5yb3VuZCggYy54ICogcHJlY2lzaW9uICkgfSwkeyBNYXRoLnJvdW5kKCBjLnkgKiBwcmVjaXNpb24gKSB9LCR7IE1hdGgucm91bmQoIGMueiAqIHByZWNpc2lvbiApIH1gO1xyXG5cclxuXHRcdFx0XHQvLyBza2lwIGRlZ2VuZXJhdGUgdHJpYW5nbGVzXHJcblx0XHRcdFx0aWYgKCBoYXNoZXNbIDAgXSA9PT0gaGFzaGVzWyAxIF0gfHwgaGFzaGVzWyAxIF0gPT09IGhhc2hlc1sgMiBdIHx8IGhhc2hlc1sgMiBdID09PSBoYXNoZXNbIDAgXSApIHtcclxuXHJcblx0XHRcdFx0XHRjb250aW51ZTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHQvLyBpdGVyYXRlIG92ZXIgZXZlcnkgZWRnZVxyXG5cdFx0XHRcdGZvciAoIGxldCBqID0gMDsgaiA8IDM7IGogKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0Ly8gZ2V0IHRoZSBmaXJzdCBhbmQgbmV4dCB2ZXJ0ZXggbWFraW5nIHVwIHRoZSBlZGdlXHJcblx0XHRcdFx0XHRjb25zdCBqTmV4dCA9ICggaiArIDEgKSAlIDM7XHJcblx0XHRcdFx0XHRjb25zdCB2ZWNIYXNoMCA9IGhhc2hlc1sgaiBdO1xyXG5cdFx0XHRcdFx0Y29uc3QgdmVjSGFzaDEgPSBoYXNoZXNbIGpOZXh0IF07XHJcblx0XHRcdFx0XHRjb25zdCB2MCA9IF90cmlhbmdsZVsgdmVydEtleXNbIGogXSBdO1xyXG5cdFx0XHRcdFx0Y29uc3QgdjEgPSBfdHJpYW5nbGVbIHZlcnRLZXlzWyBqTmV4dCBdIF07XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgaGFzaCA9IGAkeyB2ZWNIYXNoMCB9XyR7IHZlY0hhc2gxIH1gO1xyXG5cdFx0XHRcdFx0Y29uc3QgcmV2ZXJzZUhhc2ggPSBgJHsgdmVjSGFzaDEgfV8keyB2ZWNIYXNoMCB9YDtcclxuXHJcblx0XHRcdFx0XHRpZiAoIHJldmVyc2VIYXNoIGluIGVkZ2VEYXRhICYmIGVkZ2VEYXRhWyByZXZlcnNlSGFzaCBdICkge1xyXG5cclxuXHRcdFx0XHRcdFx0Ly8gaWYgd2UgZm91bmQgYSBzaWJsaW5nIGVkZ2UgYWRkIGl0IGludG8gdGhlIHZlcnRleCBhcnJheSBpZlxyXG5cdFx0XHRcdFx0XHQvLyBpdCBtZWV0cyB0aGUgYW5nbGUgdGhyZXNob2xkIGFuZCBkZWxldGUgdGhlIGVkZ2UgZnJvbSB0aGUgbWFwLlxyXG5cdFx0XHRcdFx0XHRpZiAoIF9ub3JtYWwuZG90KCBlZGdlRGF0YVsgcmV2ZXJzZUhhc2ggXS5ub3JtYWwgKSA8PSB0aHJlc2hvbGREb3QgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdHZlcnRpY2VzLnB1c2goIHYwLngsIHYwLnksIHYwLnogKTtcclxuXHRcdFx0XHRcdFx0XHR2ZXJ0aWNlcy5wdXNoKCB2MS54LCB2MS55LCB2MS56ICk7XHJcblxyXG5cdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0XHRlZGdlRGF0YVsgcmV2ZXJzZUhhc2ggXSA9IG51bGw7XHJcblxyXG5cdFx0XHRcdFx0fSBlbHNlIGlmICggISAoIGhhc2ggaW4gZWRnZURhdGEgKSApIHtcclxuXHJcblx0XHRcdFx0XHRcdC8vIGlmIHdlJ3ZlIGFscmVhZHkgZ290IGFuIGVkZ2UgaGVyZSB0aGVuIHNraXAgYWRkaW5nIGEgbmV3IG9uZVxyXG5cdFx0XHRcdFx0XHRlZGdlRGF0YVsgaGFzaCBdID0ge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRpbmRleDA6IGluZGV4QXJyWyBqIF0sXHJcblx0XHRcdFx0XHRcdFx0aW5kZXgxOiBpbmRleEFyclsgak5leHQgXSxcclxuXHRcdFx0XHRcdFx0XHRub3JtYWw6IF9ub3JtYWwuY2xvbmUoKSxcclxuXHJcblx0XHRcdFx0XHRcdH07XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyBpdGVyYXRlIG92ZXIgYWxsIHJlbWFpbmluZywgdW5tYXRjaGVkIGVkZ2VzIGFuZCBhZGQgdGhlbSB0byB0aGUgdmVydGV4IGFycmF5XHJcblx0XHRcdGZvciAoIGNvbnN0IGtleSBpbiBlZGdlRGF0YSApIHtcclxuXHJcblx0XHRcdFx0aWYgKCBlZGdlRGF0YVsga2V5IF0gKSB7XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgeyBpbmRleDAsIGluZGV4MSB9ID0gZWRnZURhdGFbIGtleSBdO1xyXG5cdFx0XHRcdFx0X3YwLmZyb21CdWZmZXJBdHRyaWJ1dGUoIHBvc2l0aW9uQXR0ciwgaW5kZXgwICk7XHJcblx0XHRcdFx0XHRfdjEuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggcG9zaXRpb25BdHRyLCBpbmRleDEgKTtcclxuXHJcblx0XHRcdFx0XHR2ZXJ0aWNlcy5wdXNoKCBfdjAueCwgX3YwLnksIF92MC56ICk7XHJcblx0XHRcdFx0XHR2ZXJ0aWNlcy5wdXNoKCBfdjEueCwgX3YxLnksIF92MS56ICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHRoaXMuc2V0QXR0cmlidXRlKCAncG9zaXRpb24nLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggdmVydGljZXMsIDMgKSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRjb3B5KCBzb3VyY2UgKSB7XHJcblxyXG5cdFx0c3VwZXIuY29weSggc291cmNlICk7XHJcblxyXG5cdFx0dGhpcy5wYXJhbWV0ZXJzID0gT2JqZWN0LmFzc2lnbigge30sIHNvdXJjZS5wYXJhbWV0ZXJzICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IEVkZ2VzR2VvbWV0cnkgfTtcclxuIiwiaW1wb3J0IHsgUGF0aCB9IGZyb20gJy4vUGF0aC5qcyc7XHJcbmltcG9ydCAqIGFzIE1hdGhVdGlscyBmcm9tICcuLi8uLi9tYXRoL01hdGhVdGlscy5qcyc7XHJcblxyXG5jbGFzcyBTaGFwZSBleHRlbmRzIFBhdGgge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggcG9pbnRzICkge1xyXG5cclxuXHRcdHN1cGVyKCBwb2ludHMgKTtcclxuXHJcblx0XHR0aGlzLnV1aWQgPSBNYXRoVXRpbHMuZ2VuZXJhdGVVVUlEKCk7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ1NoYXBlJztcclxuXHJcblx0XHR0aGlzLmhvbGVzID0gW107XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0UG9pbnRzSG9sZXMoIGRpdmlzaW9ucyApIHtcclxuXHJcblx0XHRjb25zdCBob2xlc1B0cyA9IFtdO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IHRoaXMuaG9sZXMubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdGhvbGVzUHRzWyBpIF0gPSB0aGlzLmhvbGVzWyBpIF0uZ2V0UG9pbnRzKCBkaXZpc2lvbnMgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIGhvbGVzUHRzO1xyXG5cclxuXHR9XHJcblxyXG5cdC8vIGdldCBwb2ludHMgb2Ygc2hhcGUgYW5kIGhvbGVzIChrZXlwb2ludHMgYmFzZWQgb24gc2VnbWVudHMgcGFyYW1ldGVyKVxyXG5cclxuXHRleHRyYWN0UG9pbnRzKCBkaXZpc2lvbnMgKSB7XHJcblxyXG5cdFx0cmV0dXJuIHtcclxuXHJcblx0XHRcdHNoYXBlOiB0aGlzLmdldFBvaW50cyggZGl2aXNpb25zICksXHJcblx0XHRcdGhvbGVzOiB0aGlzLmdldFBvaW50c0hvbGVzKCBkaXZpc2lvbnMgKVxyXG5cclxuXHRcdH07XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xyXG5cclxuXHRcdHRoaXMuaG9sZXMgPSBbXTtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBzb3VyY2UuaG9sZXMubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdGNvbnN0IGhvbGUgPSBzb3VyY2UuaG9sZXNbIGkgXTtcclxuXHJcblx0XHRcdHRoaXMuaG9sZXMucHVzaCggaG9sZS5jbG9uZSgpICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHRvSlNPTigpIHtcclxuXHJcblx0XHRjb25zdCBkYXRhID0gc3VwZXIudG9KU09OKCk7XHJcblxyXG5cdFx0ZGF0YS51dWlkID0gdGhpcy51dWlkO1xyXG5cdFx0ZGF0YS5ob2xlcyA9IFtdO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IHRoaXMuaG9sZXMubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdGNvbnN0IGhvbGUgPSB0aGlzLmhvbGVzWyBpIF07XHJcblx0XHRcdGRhdGEuaG9sZXMucHVzaCggaG9sZS50b0pTT04oKSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gZGF0YTtcclxuXHJcblx0fVxyXG5cclxuXHRmcm9tSlNPTigganNvbiApIHtcclxuXHJcblx0XHRzdXBlci5mcm9tSlNPTigganNvbiApO1xyXG5cclxuXHRcdHRoaXMudXVpZCA9IGpzb24udXVpZDtcclxuXHRcdHRoaXMuaG9sZXMgPSBbXTtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBqc29uLmhvbGVzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBob2xlID0ganNvbi5ob2xlc1sgaSBdO1xyXG5cdFx0XHR0aGlzLmhvbGVzLnB1c2goIG5ldyBQYXRoKCkuZnJvbUpTT04oIGhvbGUgKSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuXHJcbmV4cG9ydCB7IFNoYXBlIH07XHJcbiIsIi8qKlxyXG4gKiBQb3J0IGZyb20gaHR0cHM6Ly9naXRodWIuY29tL21hcGJveC9lYXJjdXQgKHYyLjIuNClcclxuICovXHJcblxyXG5jb25zdCBFYXJjdXQgPSB7XHJcblxyXG5cdHRyaWFuZ3VsYXRlOiBmdW5jdGlvbiAoIGRhdGEsIGhvbGVJbmRpY2VzLCBkaW0gPSAyICkge1xyXG5cclxuXHRcdGNvbnN0IGhhc0hvbGVzID0gaG9sZUluZGljZXMgJiYgaG9sZUluZGljZXMubGVuZ3RoO1xyXG5cdFx0Y29uc3Qgb3V0ZXJMZW4gPSBoYXNIb2xlcyA/IGhvbGVJbmRpY2VzWyAwIF0gKiBkaW0gOiBkYXRhLmxlbmd0aDtcclxuXHRcdGxldCBvdXRlck5vZGUgPSBsaW5rZWRMaXN0KCBkYXRhLCAwLCBvdXRlckxlbiwgZGltLCB0cnVlICk7XHJcblx0XHRjb25zdCB0cmlhbmdsZXMgPSBbXTtcclxuXHJcblx0XHRpZiAoICEgb3V0ZXJOb2RlIHx8IG91dGVyTm9kZS5uZXh0ID09PSBvdXRlck5vZGUucHJldiApIHJldHVybiB0cmlhbmdsZXM7XHJcblxyXG5cdFx0bGV0IG1pblgsIG1pblksIG1heFgsIG1heFksIHgsIHksIGludlNpemU7XHJcblxyXG5cdFx0aWYgKCBoYXNIb2xlcyApIG91dGVyTm9kZSA9IGVsaW1pbmF0ZUhvbGVzKCBkYXRhLCBob2xlSW5kaWNlcywgb3V0ZXJOb2RlLCBkaW0gKTtcclxuXHJcblx0XHQvLyBpZiB0aGUgc2hhcGUgaXMgbm90IHRvbyBzaW1wbGUsIHdlJ2xsIHVzZSB6LW9yZGVyIGN1cnZlIGhhc2ggbGF0ZXI7IGNhbGN1bGF0ZSBwb2x5Z29uIGJib3hcclxuXHRcdGlmICggZGF0YS5sZW5ndGggPiA4MCAqIGRpbSApIHtcclxuXHJcblx0XHRcdG1pblggPSBtYXhYID0gZGF0YVsgMCBdO1xyXG5cdFx0XHRtaW5ZID0gbWF4WSA9IGRhdGFbIDEgXTtcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gZGltOyBpIDwgb3V0ZXJMZW47IGkgKz0gZGltICkge1xyXG5cclxuXHRcdFx0XHR4ID0gZGF0YVsgaSBdO1xyXG5cdFx0XHRcdHkgPSBkYXRhWyBpICsgMSBdO1xyXG5cdFx0XHRcdGlmICggeCA8IG1pblggKSBtaW5YID0geDtcclxuXHRcdFx0XHRpZiAoIHkgPCBtaW5ZICkgbWluWSA9IHk7XHJcblx0XHRcdFx0aWYgKCB4ID4gbWF4WCApIG1heFggPSB4O1xyXG5cdFx0XHRcdGlmICggeSA+IG1heFkgKSBtYXhZID0geTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdC8vIG1pblgsIG1pblkgYW5kIGludlNpemUgYXJlIGxhdGVyIHVzZWQgdG8gdHJhbnNmb3JtIGNvb3JkcyBpbnRvIGludGVnZXJzIGZvciB6LW9yZGVyIGNhbGN1bGF0aW9uXHJcblx0XHRcdGludlNpemUgPSBNYXRoLm1heCggbWF4WCAtIG1pblgsIG1heFkgLSBtaW5ZICk7XHJcblx0XHRcdGludlNpemUgPSBpbnZTaXplICE9PSAwID8gMzI3NjcgLyBpbnZTaXplIDogMDtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0ZWFyY3V0TGlua2VkKCBvdXRlck5vZGUsIHRyaWFuZ2xlcywgZGltLCBtaW5YLCBtaW5ZLCBpbnZTaXplLCAwICk7XHJcblxyXG5cdFx0cmV0dXJuIHRyaWFuZ2xlcztcclxuXHJcblx0fVxyXG5cclxufTtcclxuXHJcbi8vIGNyZWF0ZSBhIGNpcmN1bGFyIGRvdWJseSBsaW5rZWQgbGlzdCBmcm9tIHBvbHlnb24gcG9pbnRzIGluIHRoZSBzcGVjaWZpZWQgd2luZGluZyBvcmRlclxyXG5mdW5jdGlvbiBsaW5rZWRMaXN0KCBkYXRhLCBzdGFydCwgZW5kLCBkaW0sIGNsb2Nrd2lzZSApIHtcclxuXHJcblx0bGV0IGksIGxhc3Q7XHJcblxyXG5cdGlmICggY2xvY2t3aXNlID09PSAoIHNpZ25lZEFyZWEoIGRhdGEsIHN0YXJ0LCBlbmQsIGRpbSApID4gMCApICkge1xyXG5cclxuXHRcdGZvciAoIGkgPSBzdGFydDsgaSA8IGVuZDsgaSArPSBkaW0gKSBsYXN0ID0gaW5zZXJ0Tm9kZSggaSwgZGF0YVsgaSBdLCBkYXRhWyBpICsgMSBdLCBsYXN0ICk7XHJcblxyXG5cdH0gZWxzZSB7XHJcblxyXG5cdFx0Zm9yICggaSA9IGVuZCAtIGRpbTsgaSA+PSBzdGFydDsgaSAtPSBkaW0gKSBsYXN0ID0gaW5zZXJ0Tm9kZSggaSwgZGF0YVsgaSBdLCBkYXRhWyBpICsgMSBdLCBsYXN0ICk7XHJcblxyXG5cdH1cclxuXHJcblx0aWYgKCBsYXN0ICYmIGVxdWFscyggbGFzdCwgbGFzdC5uZXh0ICkgKSB7XHJcblxyXG5cdFx0cmVtb3ZlTm9kZSggbGFzdCApO1xyXG5cdFx0bGFzdCA9IGxhc3QubmV4dDtcclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4gbGFzdDtcclxuXHJcbn1cclxuXHJcbi8vIGVsaW1pbmF0ZSBjb2xpbmVhciBvciBkdXBsaWNhdGUgcG9pbnRzXHJcbmZ1bmN0aW9uIGZpbHRlclBvaW50cyggc3RhcnQsIGVuZCApIHtcclxuXHJcblx0aWYgKCAhIHN0YXJ0ICkgcmV0dXJuIHN0YXJ0O1xyXG5cdGlmICggISBlbmQgKSBlbmQgPSBzdGFydDtcclxuXHJcblx0bGV0IHAgPSBzdGFydCxcclxuXHRcdGFnYWluO1xyXG5cdGRvIHtcclxuXHJcblx0XHRhZ2FpbiA9IGZhbHNlO1xyXG5cclxuXHRcdGlmICggISBwLnN0ZWluZXIgJiYgKCBlcXVhbHMoIHAsIHAubmV4dCApIHx8IGFyZWEoIHAucHJldiwgcCwgcC5uZXh0ICkgPT09IDAgKSApIHtcclxuXHJcblx0XHRcdHJlbW92ZU5vZGUoIHAgKTtcclxuXHRcdFx0cCA9IGVuZCA9IHAucHJldjtcclxuXHRcdFx0aWYgKCBwID09PSBwLm5leHQgKSBicmVhaztcclxuXHRcdFx0YWdhaW4gPSB0cnVlO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRwID0gcC5uZXh0O1xyXG5cclxuXHRcdH1cclxuXHJcblx0fSB3aGlsZSAoIGFnYWluIHx8IHAgIT09IGVuZCApO1xyXG5cclxuXHRyZXR1cm4gZW5kO1xyXG5cclxufVxyXG5cclxuLy8gbWFpbiBlYXIgc2xpY2luZyBsb29wIHdoaWNoIHRyaWFuZ3VsYXRlcyBhIHBvbHlnb24gKGdpdmVuIGFzIGEgbGlua2VkIGxpc3QpXHJcbmZ1bmN0aW9uIGVhcmN1dExpbmtlZCggZWFyLCB0cmlhbmdsZXMsIGRpbSwgbWluWCwgbWluWSwgaW52U2l6ZSwgcGFzcyApIHtcclxuXHJcblx0aWYgKCAhIGVhciApIHJldHVybjtcclxuXHJcblx0Ly8gaW50ZXJsaW5rIHBvbHlnb24gbm9kZXMgaW4gei1vcmRlclxyXG5cdGlmICggISBwYXNzICYmIGludlNpemUgKSBpbmRleEN1cnZlKCBlYXIsIG1pblgsIG1pblksIGludlNpemUgKTtcclxuXHJcblx0bGV0IHN0b3AgPSBlYXIsXHJcblx0XHRwcmV2LCBuZXh0O1xyXG5cclxuXHQvLyBpdGVyYXRlIHRocm91Z2ggZWFycywgc2xpY2luZyB0aGVtIG9uZSBieSBvbmVcclxuXHR3aGlsZSAoIGVhci5wcmV2ICE9PSBlYXIubmV4dCApIHtcclxuXHJcblx0XHRwcmV2ID0gZWFyLnByZXY7XHJcblx0XHRuZXh0ID0gZWFyLm5leHQ7XHJcblxyXG5cdFx0aWYgKCBpbnZTaXplID8gaXNFYXJIYXNoZWQoIGVhciwgbWluWCwgbWluWSwgaW52U2l6ZSApIDogaXNFYXIoIGVhciApICkge1xyXG5cclxuXHRcdFx0Ly8gY3V0IG9mZiB0aGUgdHJpYW5nbGVcclxuXHRcdFx0dHJpYW5nbGVzLnB1c2goIHByZXYuaSAvIGRpbSB8IDAgKTtcclxuXHRcdFx0dHJpYW5nbGVzLnB1c2goIGVhci5pIC8gZGltIHwgMCApO1xyXG5cdFx0XHR0cmlhbmdsZXMucHVzaCggbmV4dC5pIC8gZGltIHwgMCApO1xyXG5cclxuXHRcdFx0cmVtb3ZlTm9kZSggZWFyICk7XHJcblxyXG5cdFx0XHQvLyBza2lwcGluZyB0aGUgbmV4dCB2ZXJ0ZXggbGVhZHMgdG8gbGVzcyBzbGl2ZXIgdHJpYW5nbGVzXHJcblx0XHRcdGVhciA9IG5leHQubmV4dDtcclxuXHRcdFx0c3RvcCA9IG5leHQubmV4dDtcclxuXHJcblx0XHRcdGNvbnRpbnVlO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRlYXIgPSBuZXh0O1xyXG5cclxuXHRcdC8vIGlmIHdlIGxvb3BlZCB0aHJvdWdoIHRoZSB3aG9sZSByZW1haW5pbmcgcG9seWdvbiBhbmQgY2FuJ3QgZmluZCBhbnkgbW9yZSBlYXJzXHJcblx0XHRpZiAoIGVhciA9PT0gc3RvcCApIHtcclxuXHJcblx0XHRcdC8vIHRyeSBmaWx0ZXJpbmcgcG9pbnRzIGFuZCBzbGljaW5nIGFnYWluXHJcblx0XHRcdGlmICggISBwYXNzICkge1xyXG5cclxuXHRcdFx0XHRlYXJjdXRMaW5rZWQoIGZpbHRlclBvaW50cyggZWFyICksIHRyaWFuZ2xlcywgZGltLCBtaW5YLCBtaW5ZLCBpbnZTaXplLCAxICk7XHJcblxyXG5cdFx0XHRcdC8vIGlmIHRoaXMgZGlkbid0IHdvcmssIHRyeSBjdXJpbmcgYWxsIHNtYWxsIHNlbGYtaW50ZXJzZWN0aW9ucyBsb2NhbGx5XHJcblxyXG5cdFx0XHR9IGVsc2UgaWYgKCBwYXNzID09PSAxICkge1xyXG5cclxuXHRcdFx0XHRlYXIgPSBjdXJlTG9jYWxJbnRlcnNlY3Rpb25zKCBmaWx0ZXJQb2ludHMoIGVhciApLCB0cmlhbmdsZXMsIGRpbSApO1xyXG5cdFx0XHRcdGVhcmN1dExpbmtlZCggZWFyLCB0cmlhbmdsZXMsIGRpbSwgbWluWCwgbWluWSwgaW52U2l6ZSwgMiApO1xyXG5cclxuXHRcdFx0XHQvLyBhcyBhIGxhc3QgcmVzb3J0LCB0cnkgc3BsaXR0aW5nIHRoZSByZW1haW5pbmcgcG9seWdvbiBpbnRvIHR3b1xyXG5cclxuXHRcdFx0fSBlbHNlIGlmICggcGFzcyA9PT0gMiApIHtcclxuXHJcblx0XHRcdFx0c3BsaXRFYXJjdXQoIGVhciwgdHJpYW5nbGVzLCBkaW0sIG1pblgsIG1pblksIGludlNpemUgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuLy8gY2hlY2sgd2hldGhlciBhIHBvbHlnb24gbm9kZSBmb3JtcyBhIHZhbGlkIGVhciB3aXRoIGFkamFjZW50IG5vZGVzXHJcbmZ1bmN0aW9uIGlzRWFyKCBlYXIgKSB7XHJcblxyXG5cdGNvbnN0IGEgPSBlYXIucHJldixcclxuXHRcdGIgPSBlYXIsXHJcblx0XHRjID0gZWFyLm5leHQ7XHJcblxyXG5cdGlmICggYXJlYSggYSwgYiwgYyApID49IDAgKSByZXR1cm4gZmFsc2U7IC8vIHJlZmxleCwgY2FuJ3QgYmUgYW4gZWFyXHJcblxyXG5cdC8vIG5vdyBtYWtlIHN1cmUgd2UgZG9uJ3QgaGF2ZSBvdGhlciBwb2ludHMgaW5zaWRlIHRoZSBwb3RlbnRpYWwgZWFyXHJcblx0Y29uc3QgYXggPSBhLngsIGJ4ID0gYi54LCBjeCA9IGMueCwgYXkgPSBhLnksIGJ5ID0gYi55LCBjeSA9IGMueTtcclxuXHJcblx0Ly8gdHJpYW5nbGUgYmJveDsgbWluICYgbWF4IGFyZSBjYWxjdWxhdGVkIGxpa2UgdGhpcyBmb3Igc3BlZWRcclxuXHRjb25zdCB4MCA9IGF4IDwgYnggPyAoIGF4IDwgY3ggPyBheCA6IGN4ICkgOiAoIGJ4IDwgY3ggPyBieCA6IGN4ICksXHJcblx0XHR5MCA9IGF5IDwgYnkgPyAoIGF5IDwgY3kgPyBheSA6IGN5ICkgOiAoIGJ5IDwgY3kgPyBieSA6IGN5ICksXHJcblx0XHR4MSA9IGF4ID4gYnggPyAoIGF4ID4gY3ggPyBheCA6IGN4ICkgOiAoIGJ4ID4gY3ggPyBieCA6IGN4ICksXHJcblx0XHR5MSA9IGF5ID4gYnkgPyAoIGF5ID4gY3kgPyBheSA6IGN5ICkgOiAoIGJ5ID4gY3kgPyBieSA6IGN5ICk7XHJcblxyXG5cdGxldCBwID0gYy5uZXh0O1xyXG5cdHdoaWxlICggcCAhPT0gYSApIHtcclxuXHJcblx0XHRpZiAoIHAueCA+PSB4MCAmJiBwLnggPD0geDEgJiYgcC55ID49IHkwICYmIHAueSA8PSB5MSAmJlxyXG5cdFx0XHRwb2ludEluVHJpYW5nbGUoIGF4LCBheSwgYngsIGJ5LCBjeCwgY3ksIHAueCwgcC55ICkgJiZcclxuXHRcdFx0YXJlYSggcC5wcmV2LCBwLCBwLm5leHQgKSA+PSAwICkgcmV0dXJuIGZhbHNlO1xyXG5cdFx0cCA9IHAubmV4dDtcclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4gdHJ1ZTtcclxuXHJcbn1cclxuXHJcbmZ1bmN0aW9uIGlzRWFySGFzaGVkKCBlYXIsIG1pblgsIG1pblksIGludlNpemUgKSB7XHJcblxyXG5cdGNvbnN0IGEgPSBlYXIucHJldixcclxuXHRcdGIgPSBlYXIsXHJcblx0XHRjID0gZWFyLm5leHQ7XHJcblxyXG5cdGlmICggYXJlYSggYSwgYiwgYyApID49IDAgKSByZXR1cm4gZmFsc2U7IC8vIHJlZmxleCwgY2FuJ3QgYmUgYW4gZWFyXHJcblxyXG5cdGNvbnN0IGF4ID0gYS54LCBieCA9IGIueCwgY3ggPSBjLngsIGF5ID0gYS55LCBieSA9IGIueSwgY3kgPSBjLnk7XHJcblxyXG5cdC8vIHRyaWFuZ2xlIGJib3g7IG1pbiAmIG1heCBhcmUgY2FsY3VsYXRlZCBsaWtlIHRoaXMgZm9yIHNwZWVkXHJcblx0Y29uc3QgeDAgPSBheCA8IGJ4ID8gKCBheCA8IGN4ID8gYXggOiBjeCApIDogKCBieCA8IGN4ID8gYnggOiBjeCApLFxyXG5cdFx0eTAgPSBheSA8IGJ5ID8gKCBheSA8IGN5ID8gYXkgOiBjeSApIDogKCBieSA8IGN5ID8gYnkgOiBjeSApLFxyXG5cdFx0eDEgPSBheCA+IGJ4ID8gKCBheCA+IGN4ID8gYXggOiBjeCApIDogKCBieCA+IGN4ID8gYnggOiBjeCApLFxyXG5cdFx0eTEgPSBheSA+IGJ5ID8gKCBheSA+IGN5ID8gYXkgOiBjeSApIDogKCBieSA+IGN5ID8gYnkgOiBjeSApO1xyXG5cclxuXHQvLyB6LW9yZGVyIHJhbmdlIGZvciB0aGUgY3VycmVudCB0cmlhbmdsZSBiYm94O1xyXG5cdGNvbnN0IG1pblogPSB6T3JkZXIoIHgwLCB5MCwgbWluWCwgbWluWSwgaW52U2l6ZSApLFxyXG5cdFx0bWF4WiA9IHpPcmRlciggeDEsIHkxLCBtaW5YLCBtaW5ZLCBpbnZTaXplICk7XHJcblxyXG5cdGxldCBwID0gZWFyLnByZXZaLFxyXG5cdFx0biA9IGVhci5uZXh0WjtcclxuXHJcblx0Ly8gbG9vayBmb3IgcG9pbnRzIGluc2lkZSB0aGUgdHJpYW5nbGUgaW4gYm90aCBkaXJlY3Rpb25zXHJcblx0d2hpbGUgKCBwICYmIHAueiA+PSBtaW5aICYmIG4gJiYgbi56IDw9IG1heFogKSB7XHJcblxyXG5cdFx0aWYgKCBwLnggPj0geDAgJiYgcC54IDw9IHgxICYmIHAueSA+PSB5MCAmJiBwLnkgPD0geTEgJiYgcCAhPT0gYSAmJiBwICE9PSBjICYmXHJcblx0XHRcdHBvaW50SW5UcmlhbmdsZSggYXgsIGF5LCBieCwgYnksIGN4LCBjeSwgcC54LCBwLnkgKSAmJiBhcmVhKCBwLnByZXYsIHAsIHAubmV4dCApID49IDAgKSByZXR1cm4gZmFsc2U7XHJcblx0XHRwID0gcC5wcmV2WjtcclxuXHJcblx0XHRpZiAoIG4ueCA+PSB4MCAmJiBuLnggPD0geDEgJiYgbi55ID49IHkwICYmIG4ueSA8PSB5MSAmJiBuICE9PSBhICYmIG4gIT09IGMgJiZcclxuXHRcdFx0cG9pbnRJblRyaWFuZ2xlKCBheCwgYXksIGJ4LCBieSwgY3gsIGN5LCBuLngsIG4ueSApICYmIGFyZWEoIG4ucHJldiwgbiwgbi5uZXh0ICkgPj0gMCApIHJldHVybiBmYWxzZTtcclxuXHRcdG4gPSBuLm5leHRaO1xyXG5cclxuXHR9XHJcblxyXG5cdC8vIGxvb2sgZm9yIHJlbWFpbmluZyBwb2ludHMgaW4gZGVjcmVhc2luZyB6LW9yZGVyXHJcblx0d2hpbGUgKCBwICYmIHAueiA+PSBtaW5aICkge1xyXG5cclxuXHRcdGlmICggcC54ID49IHgwICYmIHAueCA8PSB4MSAmJiBwLnkgPj0geTAgJiYgcC55IDw9IHkxICYmIHAgIT09IGEgJiYgcCAhPT0gYyAmJlxyXG5cdFx0XHRwb2ludEluVHJpYW5nbGUoIGF4LCBheSwgYngsIGJ5LCBjeCwgY3ksIHAueCwgcC55ICkgJiYgYXJlYSggcC5wcmV2LCBwLCBwLm5leHQgKSA+PSAwICkgcmV0dXJuIGZhbHNlO1xyXG5cdFx0cCA9IHAucHJldlo7XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gbG9vayBmb3IgcmVtYWluaW5nIHBvaW50cyBpbiBpbmNyZWFzaW5nIHotb3JkZXJcclxuXHR3aGlsZSAoIG4gJiYgbi56IDw9IG1heFogKSB7XHJcblxyXG5cdFx0aWYgKCBuLnggPj0geDAgJiYgbi54IDw9IHgxICYmIG4ueSA+PSB5MCAmJiBuLnkgPD0geTEgJiYgbiAhPT0gYSAmJiBuICE9PSBjICYmXHJcblx0XHRcdHBvaW50SW5UcmlhbmdsZSggYXgsIGF5LCBieCwgYnksIGN4LCBjeSwgbi54LCBuLnkgKSAmJiBhcmVhKCBuLnByZXYsIG4sIG4ubmV4dCApID49IDAgKSByZXR1cm4gZmFsc2U7XHJcblx0XHRuID0gbi5uZXh0WjtcclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4gdHJ1ZTtcclxuXHJcbn1cclxuXHJcbi8vIGdvIHRocm91Z2ggYWxsIHBvbHlnb24gbm9kZXMgYW5kIGN1cmUgc21hbGwgbG9jYWwgc2VsZi1pbnRlcnNlY3Rpb25zXHJcbmZ1bmN0aW9uIGN1cmVMb2NhbEludGVyc2VjdGlvbnMoIHN0YXJ0LCB0cmlhbmdsZXMsIGRpbSApIHtcclxuXHJcblx0bGV0IHAgPSBzdGFydDtcclxuXHRkbyB7XHJcblxyXG5cdFx0Y29uc3QgYSA9IHAucHJldixcclxuXHRcdFx0YiA9IHAubmV4dC5uZXh0O1xyXG5cclxuXHRcdGlmICggISBlcXVhbHMoIGEsIGIgKSAmJiBpbnRlcnNlY3RzKCBhLCBwLCBwLm5leHQsIGIgKSAmJiBsb2NhbGx5SW5zaWRlKCBhLCBiICkgJiYgbG9jYWxseUluc2lkZSggYiwgYSApICkge1xyXG5cclxuXHRcdFx0dHJpYW5nbGVzLnB1c2goIGEuaSAvIGRpbSB8IDAgKTtcclxuXHRcdFx0dHJpYW5nbGVzLnB1c2goIHAuaSAvIGRpbSB8IDAgKTtcclxuXHRcdFx0dHJpYW5nbGVzLnB1c2goIGIuaSAvIGRpbSB8IDAgKTtcclxuXHJcblx0XHRcdC8vIHJlbW92ZSB0d28gbm9kZXMgaW52b2x2ZWRcclxuXHRcdFx0cmVtb3ZlTm9kZSggcCApO1xyXG5cdFx0XHRyZW1vdmVOb2RlKCBwLm5leHQgKTtcclxuXHJcblx0XHRcdHAgPSBzdGFydCA9IGI7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHAgPSBwLm5leHQ7XHJcblxyXG5cdH0gd2hpbGUgKCBwICE9PSBzdGFydCApO1xyXG5cclxuXHRyZXR1cm4gZmlsdGVyUG9pbnRzKCBwICk7XHJcblxyXG59XHJcblxyXG4vLyB0cnkgc3BsaXR0aW5nIHBvbHlnb24gaW50byB0d28gYW5kIHRyaWFuZ3VsYXRlIHRoZW0gaW5kZXBlbmRlbnRseVxyXG5mdW5jdGlvbiBzcGxpdEVhcmN1dCggc3RhcnQsIHRyaWFuZ2xlcywgZGltLCBtaW5YLCBtaW5ZLCBpbnZTaXplICkge1xyXG5cclxuXHQvLyBsb29rIGZvciBhIHZhbGlkIGRpYWdvbmFsIHRoYXQgZGl2aWRlcyB0aGUgcG9seWdvbiBpbnRvIHR3b1xyXG5cdGxldCBhID0gc3RhcnQ7XHJcblx0ZG8ge1xyXG5cclxuXHRcdGxldCBiID0gYS5uZXh0Lm5leHQ7XHJcblx0XHR3aGlsZSAoIGIgIT09IGEucHJldiApIHtcclxuXHJcblx0XHRcdGlmICggYS5pICE9PSBiLmkgJiYgaXNWYWxpZERpYWdvbmFsKCBhLCBiICkgKSB7XHJcblxyXG5cdFx0XHRcdC8vIHNwbGl0IHRoZSBwb2x5Z29uIGluIHR3byBieSB0aGUgZGlhZ29uYWxcclxuXHRcdFx0XHRsZXQgYyA9IHNwbGl0UG9seWdvbiggYSwgYiApO1xyXG5cclxuXHRcdFx0XHQvLyBmaWx0ZXIgY29saW5lYXIgcG9pbnRzIGFyb3VuZCB0aGUgY3V0c1xyXG5cdFx0XHRcdGEgPSBmaWx0ZXJQb2ludHMoIGEsIGEubmV4dCApO1xyXG5cdFx0XHRcdGMgPSBmaWx0ZXJQb2ludHMoIGMsIGMubmV4dCApO1xyXG5cclxuXHRcdFx0XHQvLyBydW4gZWFyY3V0IG9uIGVhY2ggaGFsZlxyXG5cdFx0XHRcdGVhcmN1dExpbmtlZCggYSwgdHJpYW5nbGVzLCBkaW0sIG1pblgsIG1pblksIGludlNpemUsIDAgKTtcclxuXHRcdFx0XHRlYXJjdXRMaW5rZWQoIGMsIHRyaWFuZ2xlcywgZGltLCBtaW5YLCBtaW5ZLCBpbnZTaXplLCAwICk7XHJcblx0XHRcdFx0cmV0dXJuO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0YiA9IGIubmV4dDtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0YSA9IGEubmV4dDtcclxuXHJcblx0fSB3aGlsZSAoIGEgIT09IHN0YXJ0ICk7XHJcblxyXG59XHJcblxyXG4vLyBsaW5rIGV2ZXJ5IGhvbGUgaW50byB0aGUgb3V0ZXIgbG9vcCwgcHJvZHVjaW5nIGEgc2luZ2xlLXJpbmcgcG9seWdvbiB3aXRob3V0IGhvbGVzXHJcbmZ1bmN0aW9uIGVsaW1pbmF0ZUhvbGVzKCBkYXRhLCBob2xlSW5kaWNlcywgb3V0ZXJOb2RlLCBkaW0gKSB7XHJcblxyXG5cdGNvbnN0IHF1ZXVlID0gW107XHJcblx0bGV0IGksIGxlbiwgc3RhcnQsIGVuZCwgbGlzdDtcclxuXHJcblx0Zm9yICggaSA9IDAsIGxlbiA9IGhvbGVJbmRpY2VzLmxlbmd0aDsgaSA8IGxlbjsgaSArKyApIHtcclxuXHJcblx0XHRzdGFydCA9IGhvbGVJbmRpY2VzWyBpIF0gKiBkaW07XHJcblx0XHRlbmQgPSBpIDwgbGVuIC0gMSA/IGhvbGVJbmRpY2VzWyBpICsgMSBdICogZGltIDogZGF0YS5sZW5ndGg7XHJcblx0XHRsaXN0ID0gbGlua2VkTGlzdCggZGF0YSwgc3RhcnQsIGVuZCwgZGltLCBmYWxzZSApO1xyXG5cdFx0aWYgKCBsaXN0ID09PSBsaXN0Lm5leHQgKSBsaXN0LnN0ZWluZXIgPSB0cnVlO1xyXG5cdFx0cXVldWUucHVzaCggZ2V0TGVmdG1vc3QoIGxpc3QgKSApO1xyXG5cclxuXHR9XHJcblxyXG5cdHF1ZXVlLnNvcnQoIGNvbXBhcmVYICk7XHJcblxyXG5cdC8vIHByb2Nlc3MgaG9sZXMgZnJvbSBsZWZ0IHRvIHJpZ2h0XHJcblx0Zm9yICggaSA9IDA7IGkgPCBxdWV1ZS5sZW5ndGg7IGkgKysgKSB7XHJcblxyXG5cdFx0b3V0ZXJOb2RlID0gZWxpbWluYXRlSG9sZSggcXVldWVbIGkgXSwgb3V0ZXJOb2RlICk7XHJcblxyXG5cdH1cclxuXHJcblx0cmV0dXJuIG91dGVyTm9kZTtcclxuXHJcbn1cclxuXHJcbmZ1bmN0aW9uIGNvbXBhcmVYKCBhLCBiICkge1xyXG5cclxuXHRyZXR1cm4gYS54IC0gYi54O1xyXG5cclxufVxyXG5cclxuLy8gZmluZCBhIGJyaWRnZSBiZXR3ZWVuIHZlcnRpY2VzIHRoYXQgY29ubmVjdHMgaG9sZSB3aXRoIGFuIG91dGVyIHJpbmcgYW5kIGxpbmsgaXRcclxuZnVuY3Rpb24gZWxpbWluYXRlSG9sZSggaG9sZSwgb3V0ZXJOb2RlICkge1xyXG5cclxuXHRjb25zdCBicmlkZ2UgPSBmaW5kSG9sZUJyaWRnZSggaG9sZSwgb3V0ZXJOb2RlICk7XHJcblx0aWYgKCAhIGJyaWRnZSApIHtcclxuXHJcblx0XHRyZXR1cm4gb3V0ZXJOb2RlO1xyXG5cclxuXHR9XHJcblxyXG5cdGNvbnN0IGJyaWRnZVJldmVyc2UgPSBzcGxpdFBvbHlnb24oIGJyaWRnZSwgaG9sZSApO1xyXG5cclxuXHQvLyBmaWx0ZXIgY29sbGluZWFyIHBvaW50cyBhcm91bmQgdGhlIGN1dHNcclxuXHRmaWx0ZXJQb2ludHMoIGJyaWRnZVJldmVyc2UsIGJyaWRnZVJldmVyc2UubmV4dCApO1xyXG5cdHJldHVybiBmaWx0ZXJQb2ludHMoIGJyaWRnZSwgYnJpZGdlLm5leHQgKTtcclxuXHJcbn1cclxuXHJcbi8vIERhdmlkIEViZXJseSdzIGFsZ29yaXRobSBmb3IgZmluZGluZyBhIGJyaWRnZSBiZXR3ZWVuIGhvbGUgYW5kIG91dGVyIHBvbHlnb25cclxuZnVuY3Rpb24gZmluZEhvbGVCcmlkZ2UoIGhvbGUsIG91dGVyTm9kZSApIHtcclxuXHJcblx0bGV0IHAgPSBvdXRlck5vZGUsXHJcblx0XHRxeCA9IC0gSW5maW5pdHksXHJcblx0XHRtO1xyXG5cclxuXHRjb25zdCBoeCA9IGhvbGUueCwgaHkgPSBob2xlLnk7XHJcblxyXG5cdC8vIGZpbmQgYSBzZWdtZW50IGludGVyc2VjdGVkIGJ5IGEgcmF5IGZyb20gdGhlIGhvbGUncyBsZWZ0bW9zdCBwb2ludCB0byB0aGUgbGVmdDtcclxuXHQvLyBzZWdtZW50J3MgZW5kcG9pbnQgd2l0aCBsZXNzZXIgeCB3aWxsIGJlIHBvdGVudGlhbCBjb25uZWN0aW9uIHBvaW50XHJcblx0ZG8ge1xyXG5cclxuXHRcdGlmICggaHkgPD0gcC55ICYmIGh5ID49IHAubmV4dC55ICYmIHAubmV4dC55ICE9PSBwLnkgKSB7XHJcblxyXG5cdFx0XHRjb25zdCB4ID0gcC54ICsgKCBoeSAtIHAueSApICogKCBwLm5leHQueCAtIHAueCApIC8gKCBwLm5leHQueSAtIHAueSApO1xyXG5cdFx0XHRpZiAoIHggPD0gaHggJiYgeCA+IHF4ICkge1xyXG5cclxuXHRcdFx0XHRxeCA9IHg7XHJcblx0XHRcdFx0bSA9IHAueCA8IHAubmV4dC54ID8gcCA6IHAubmV4dDtcclxuXHRcdFx0XHRpZiAoIHggPT09IGh4ICkgcmV0dXJuIG07IC8vIGhvbGUgdG91Y2hlcyBvdXRlciBzZWdtZW50OyBwaWNrIGxlZnRtb3N0IGVuZHBvaW50XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHAgPSBwLm5leHQ7XHJcblxyXG5cdH0gd2hpbGUgKCBwICE9PSBvdXRlck5vZGUgKTtcclxuXHJcblx0aWYgKCAhIG0gKSByZXR1cm4gbnVsbDtcclxuXHJcblx0Ly8gbG9vayBmb3IgcG9pbnRzIGluc2lkZSB0aGUgdHJpYW5nbGUgb2YgaG9sZSBwb2ludCwgc2VnbWVudCBpbnRlcnNlY3Rpb24gYW5kIGVuZHBvaW50O1xyXG5cdC8vIGlmIHRoZXJlIGFyZSBubyBwb2ludHMgZm91bmQsIHdlIGhhdmUgYSB2YWxpZCBjb25uZWN0aW9uO1xyXG5cdC8vIG90aGVyd2lzZSBjaG9vc2UgdGhlIHBvaW50IG9mIHRoZSBtaW5pbXVtIGFuZ2xlIHdpdGggdGhlIHJheSBhcyBjb25uZWN0aW9uIHBvaW50XHJcblxyXG5cdGNvbnN0IHN0b3AgPSBtLFxyXG5cdFx0bXggPSBtLngsXHJcblx0XHRteSA9IG0ueTtcclxuXHRsZXQgdGFuTWluID0gSW5maW5pdHksIHRhbjtcclxuXHJcblx0cCA9IG07XHJcblxyXG5cdGRvIHtcclxuXHJcblx0XHRpZiAoIGh4ID49IHAueCAmJiBwLnggPj0gbXggJiYgaHggIT09IHAueCAmJlxyXG5cdFx0XHRcdHBvaW50SW5UcmlhbmdsZSggaHkgPCBteSA/IGh4IDogcXgsIGh5LCBteCwgbXksIGh5IDwgbXkgPyBxeCA6IGh4LCBoeSwgcC54LCBwLnkgKSApIHtcclxuXHJcblx0XHRcdHRhbiA9IE1hdGguYWJzKCBoeSAtIHAueSApIC8gKCBoeCAtIHAueCApOyAvLyB0YW5nZW50aWFsXHJcblxyXG5cdFx0XHRpZiAoIGxvY2FsbHlJbnNpZGUoIHAsIGhvbGUgKSAmJiAoIHRhbiA8IHRhbk1pbiB8fCAoIHRhbiA9PT0gdGFuTWluICYmICggcC54ID4gbS54IHx8ICggcC54ID09PSBtLnggJiYgc2VjdG9yQ29udGFpbnNTZWN0b3IoIG0sIHAgKSApICkgKSApICkge1xyXG5cclxuXHRcdFx0XHRtID0gcDtcclxuXHRcdFx0XHR0YW5NaW4gPSB0YW47XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHAgPSBwLm5leHQ7XHJcblxyXG5cdH0gd2hpbGUgKCBwICE9PSBzdG9wICk7XHJcblxyXG5cdHJldHVybiBtO1xyXG5cclxufVxyXG5cclxuLy8gd2hldGhlciBzZWN0b3IgaW4gdmVydGV4IG0gY29udGFpbnMgc2VjdG9yIGluIHZlcnRleCBwIGluIHRoZSBzYW1lIGNvb3JkaW5hdGVzXHJcbmZ1bmN0aW9uIHNlY3RvckNvbnRhaW5zU2VjdG9yKCBtLCBwICkge1xyXG5cclxuXHRyZXR1cm4gYXJlYSggbS5wcmV2LCBtLCBwLnByZXYgKSA8IDAgJiYgYXJlYSggcC5uZXh0LCBtLCBtLm5leHQgKSA8IDA7XHJcblxyXG59XHJcblxyXG4vLyBpbnRlcmxpbmsgcG9seWdvbiBub2RlcyBpbiB6LW9yZGVyXHJcbmZ1bmN0aW9uIGluZGV4Q3VydmUoIHN0YXJ0LCBtaW5YLCBtaW5ZLCBpbnZTaXplICkge1xyXG5cclxuXHRsZXQgcCA9IHN0YXJ0O1xyXG5cdGRvIHtcclxuXHJcblx0XHRpZiAoIHAueiA9PT0gMCApIHAueiA9IHpPcmRlciggcC54LCBwLnksIG1pblgsIG1pblksIGludlNpemUgKTtcclxuXHRcdHAucHJldlogPSBwLnByZXY7XHJcblx0XHRwLm5leHRaID0gcC5uZXh0O1xyXG5cdFx0cCA9IHAubmV4dDtcclxuXHJcblx0fSB3aGlsZSAoIHAgIT09IHN0YXJ0ICk7XHJcblxyXG5cdHAucHJldloubmV4dFogPSBudWxsO1xyXG5cdHAucHJldlogPSBudWxsO1xyXG5cclxuXHRzb3J0TGlua2VkKCBwICk7XHJcblxyXG59XHJcblxyXG4vLyBTaW1vbiBUYXRoYW0ncyBsaW5rZWQgbGlzdCBtZXJnZSBzb3J0IGFsZ29yaXRobVxyXG4vLyBodHRwOi8vd3d3LmNoaWFyay5ncmVlbmVuZC5vcmcudWsvfnNndGF0aGFtL2FsZ29yaXRobXMvbGlzdHNvcnQuaHRtbFxyXG5mdW5jdGlvbiBzb3J0TGlua2VkKCBsaXN0ICkge1xyXG5cclxuXHRsZXQgaSwgcCwgcSwgZSwgdGFpbCwgbnVtTWVyZ2VzLCBwU2l6ZSwgcVNpemUsXHJcblx0XHRpblNpemUgPSAxO1xyXG5cclxuXHRkbyB7XHJcblxyXG5cdFx0cCA9IGxpc3Q7XHJcblx0XHRsaXN0ID0gbnVsbDtcclxuXHRcdHRhaWwgPSBudWxsO1xyXG5cdFx0bnVtTWVyZ2VzID0gMDtcclxuXHJcblx0XHR3aGlsZSAoIHAgKSB7XHJcblxyXG5cdFx0XHRudW1NZXJnZXMgKys7XHJcblx0XHRcdHEgPSBwO1xyXG5cdFx0XHRwU2l6ZSA9IDA7XHJcblx0XHRcdGZvciAoIGkgPSAwOyBpIDwgaW5TaXplOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRwU2l6ZSArKztcclxuXHRcdFx0XHRxID0gcS5uZXh0WjtcclxuXHRcdFx0XHRpZiAoICEgcSApIGJyZWFrO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0cVNpemUgPSBpblNpemU7XHJcblxyXG5cdFx0XHR3aGlsZSAoIHBTaXplID4gMCB8fCAoIHFTaXplID4gMCAmJiBxICkgKSB7XHJcblxyXG5cdFx0XHRcdGlmICggcFNpemUgIT09IDAgJiYgKCBxU2l6ZSA9PT0gMCB8fCAhIHEgfHwgcC56IDw9IHEueiApICkge1xyXG5cclxuXHRcdFx0XHRcdGUgPSBwO1xyXG5cdFx0XHRcdFx0cCA9IHAubmV4dFo7XHJcblx0XHRcdFx0XHRwU2l6ZSAtLTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRlID0gcTtcclxuXHRcdFx0XHRcdHEgPSBxLm5leHRaO1xyXG5cdFx0XHRcdFx0cVNpemUgLS07XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0aWYgKCB0YWlsICkgdGFpbC5uZXh0WiA9IGU7XHJcblx0XHRcdFx0ZWxzZSBsaXN0ID0gZTtcclxuXHJcblx0XHRcdFx0ZS5wcmV2WiA9IHRhaWw7XHJcblx0XHRcdFx0dGFpbCA9IGU7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRwID0gcTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGFpbC5uZXh0WiA9IG51bGw7XHJcblx0XHRpblNpemUgKj0gMjtcclxuXHJcblx0fSB3aGlsZSAoIG51bU1lcmdlcyA+IDEgKTtcclxuXHJcblx0cmV0dXJuIGxpc3Q7XHJcblxyXG59XHJcblxyXG4vLyB6LW9yZGVyIG9mIGEgcG9pbnQgZ2l2ZW4gY29vcmRzIGFuZCBpbnZlcnNlIG9mIHRoZSBsb25nZXIgc2lkZSBvZiBkYXRhIGJib3hcclxuZnVuY3Rpb24gek9yZGVyKCB4LCB5LCBtaW5YLCBtaW5ZLCBpbnZTaXplICkge1xyXG5cclxuXHQvLyBjb29yZHMgYXJlIHRyYW5zZm9ybWVkIGludG8gbm9uLW5lZ2F0aXZlIDE1LWJpdCBpbnRlZ2VyIHJhbmdlXHJcblx0eCA9ICggeCAtIG1pblggKSAqIGludlNpemUgfCAwO1xyXG5cdHkgPSAoIHkgLSBtaW5ZICkgKiBpbnZTaXplIHwgMDtcclxuXHJcblx0eCA9ICggeCB8ICggeCA8PCA4ICkgKSAmIDB4MDBGRjAwRkY7XHJcblx0eCA9ICggeCB8ICggeCA8PCA0ICkgKSAmIDB4MEYwRjBGMEY7XHJcblx0eCA9ICggeCB8ICggeCA8PCAyICkgKSAmIDB4MzMzMzMzMzM7XHJcblx0eCA9ICggeCB8ICggeCA8PCAxICkgKSAmIDB4NTU1NTU1NTU7XHJcblxyXG5cdHkgPSAoIHkgfCAoIHkgPDwgOCApICkgJiAweDAwRkYwMEZGO1xyXG5cdHkgPSAoIHkgfCAoIHkgPDwgNCApICkgJiAweDBGMEYwRjBGO1xyXG5cdHkgPSAoIHkgfCAoIHkgPDwgMiApICkgJiAweDMzMzMzMzMzO1xyXG5cdHkgPSAoIHkgfCAoIHkgPDwgMSApICkgJiAweDU1NTU1NTU1O1xyXG5cclxuXHRyZXR1cm4geCB8ICggeSA8PCAxICk7XHJcblxyXG59XHJcblxyXG4vLyBmaW5kIHRoZSBsZWZ0bW9zdCBub2RlIG9mIGEgcG9seWdvbiByaW5nXHJcbmZ1bmN0aW9uIGdldExlZnRtb3N0KCBzdGFydCApIHtcclxuXHJcblx0bGV0IHAgPSBzdGFydCxcclxuXHRcdGxlZnRtb3N0ID0gc3RhcnQ7XHJcblx0ZG8ge1xyXG5cclxuXHRcdGlmICggcC54IDwgbGVmdG1vc3QueCB8fCAoIHAueCA9PT0gbGVmdG1vc3QueCAmJiBwLnkgPCBsZWZ0bW9zdC55ICkgKSBsZWZ0bW9zdCA9IHA7XHJcblx0XHRwID0gcC5uZXh0O1xyXG5cclxuXHR9IHdoaWxlICggcCAhPT0gc3RhcnQgKTtcclxuXHJcblx0cmV0dXJuIGxlZnRtb3N0O1xyXG5cclxufVxyXG5cclxuLy8gY2hlY2sgaWYgYSBwb2ludCBsaWVzIHdpdGhpbiBhIGNvbnZleCB0cmlhbmdsZVxyXG5mdW5jdGlvbiBwb2ludEluVHJpYW5nbGUoIGF4LCBheSwgYngsIGJ5LCBjeCwgY3ksIHB4LCBweSApIHtcclxuXHJcblx0cmV0dXJuICggY3ggLSBweCApICogKCBheSAtIHB5ICkgPj0gKCBheCAtIHB4ICkgKiAoIGN5IC0gcHkgKSAmJlxyXG4gICAgICAgICAgICggYXggLSBweCApICogKCBieSAtIHB5ICkgPj0gKCBieCAtIHB4ICkgKiAoIGF5IC0gcHkgKSAmJlxyXG4gICAgICAgICAgICggYnggLSBweCApICogKCBjeSAtIHB5ICkgPj0gKCBjeCAtIHB4ICkgKiAoIGJ5IC0gcHkgKTtcclxuXHJcbn1cclxuXHJcbi8vIGNoZWNrIGlmIGEgZGlhZ29uYWwgYmV0d2VlbiB0d28gcG9seWdvbiBub2RlcyBpcyB2YWxpZCAobGllcyBpbiBwb2x5Z29uIGludGVyaW9yKVxyXG5mdW5jdGlvbiBpc1ZhbGlkRGlhZ29uYWwoIGEsIGIgKSB7XHJcblxyXG5cdHJldHVybiBhLm5leHQuaSAhPT0gYi5pICYmIGEucHJldi5pICE9PSBiLmkgJiYgISBpbnRlcnNlY3RzUG9seWdvbiggYSwgYiApICYmIC8vIGRvbmVzJ3QgaW50ZXJzZWN0IG90aGVyIGVkZ2VzXHJcbiAgICAgICAgICAgKCBsb2NhbGx5SW5zaWRlKCBhLCBiICkgJiYgbG9jYWxseUluc2lkZSggYiwgYSApICYmIG1pZGRsZUluc2lkZSggYSwgYiApICYmIC8vIGxvY2FsbHkgdmlzaWJsZVxyXG4gICAgICAgICAgICAoIGFyZWEoIGEucHJldiwgYSwgYi5wcmV2ICkgfHwgYXJlYSggYSwgYi5wcmV2LCBiICkgKSB8fCAvLyBkb2VzIG5vdCBjcmVhdGUgb3Bwb3NpdGUtZmFjaW5nIHNlY3RvcnNcclxuICAgICAgICAgICAgZXF1YWxzKCBhLCBiICkgJiYgYXJlYSggYS5wcmV2LCBhLCBhLm5leHQgKSA+IDAgJiYgYXJlYSggYi5wcmV2LCBiLCBiLm5leHQgKSA+IDAgKTsgLy8gc3BlY2lhbCB6ZXJvLWxlbmd0aCBjYXNlXHJcblxyXG59XHJcblxyXG4vLyBzaWduZWQgYXJlYSBvZiBhIHRyaWFuZ2xlXHJcbmZ1bmN0aW9uIGFyZWEoIHAsIHEsIHIgKSB7XHJcblxyXG5cdHJldHVybiAoIHEueSAtIHAueSApICogKCByLnggLSBxLnggKSAtICggcS54IC0gcC54ICkgKiAoIHIueSAtIHEueSApO1xyXG5cclxufVxyXG5cclxuLy8gY2hlY2sgaWYgdHdvIHBvaW50cyBhcmUgZXF1YWxcclxuZnVuY3Rpb24gZXF1YWxzKCBwMSwgcDIgKSB7XHJcblxyXG5cdHJldHVybiBwMS54ID09PSBwMi54ICYmIHAxLnkgPT09IHAyLnk7XHJcblxyXG59XHJcblxyXG4vLyBjaGVjayBpZiB0d28gc2VnbWVudHMgaW50ZXJzZWN0XHJcbmZ1bmN0aW9uIGludGVyc2VjdHMoIHAxLCBxMSwgcDIsIHEyICkge1xyXG5cclxuXHRjb25zdCBvMSA9IHNpZ24oIGFyZWEoIHAxLCBxMSwgcDIgKSApO1xyXG5cdGNvbnN0IG8yID0gc2lnbiggYXJlYSggcDEsIHExLCBxMiApICk7XHJcblx0Y29uc3QgbzMgPSBzaWduKCBhcmVhKCBwMiwgcTIsIHAxICkgKTtcclxuXHRjb25zdCBvNCA9IHNpZ24oIGFyZWEoIHAyLCBxMiwgcTEgKSApO1xyXG5cclxuXHRpZiAoIG8xICE9PSBvMiAmJiBvMyAhPT0gbzQgKSByZXR1cm4gdHJ1ZTsgLy8gZ2VuZXJhbCBjYXNlXHJcblxyXG5cdGlmICggbzEgPT09IDAgJiYgb25TZWdtZW50KCBwMSwgcDIsIHExICkgKSByZXR1cm4gdHJ1ZTsgLy8gcDEsIHExIGFuZCBwMiBhcmUgY29sbGluZWFyIGFuZCBwMiBsaWVzIG9uIHAxcTFcclxuXHRpZiAoIG8yID09PSAwICYmIG9uU2VnbWVudCggcDEsIHEyLCBxMSApICkgcmV0dXJuIHRydWU7IC8vIHAxLCBxMSBhbmQgcTIgYXJlIGNvbGxpbmVhciBhbmQgcTIgbGllcyBvbiBwMXExXHJcblx0aWYgKCBvMyA9PT0gMCAmJiBvblNlZ21lbnQoIHAyLCBwMSwgcTIgKSApIHJldHVybiB0cnVlOyAvLyBwMiwgcTIgYW5kIHAxIGFyZSBjb2xsaW5lYXIgYW5kIHAxIGxpZXMgb24gcDJxMlxyXG5cdGlmICggbzQgPT09IDAgJiYgb25TZWdtZW50KCBwMiwgcTEsIHEyICkgKSByZXR1cm4gdHJ1ZTsgLy8gcDIsIHEyIGFuZCBxMSBhcmUgY29sbGluZWFyIGFuZCBxMSBsaWVzIG9uIHAycTJcclxuXHJcblx0cmV0dXJuIGZhbHNlO1xyXG5cclxufVxyXG5cclxuLy8gZm9yIGNvbGxpbmVhciBwb2ludHMgcCwgcSwgciwgY2hlY2sgaWYgcG9pbnQgcSBsaWVzIG9uIHNlZ21lbnQgcHJcclxuZnVuY3Rpb24gb25TZWdtZW50KCBwLCBxLCByICkge1xyXG5cclxuXHRyZXR1cm4gcS54IDw9IE1hdGgubWF4KCBwLngsIHIueCApICYmIHEueCA+PSBNYXRoLm1pbiggcC54LCByLnggKSAmJiBxLnkgPD0gTWF0aC5tYXgoIHAueSwgci55ICkgJiYgcS55ID49IE1hdGgubWluKCBwLnksIHIueSApO1xyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gc2lnbiggbnVtICkge1xyXG5cclxuXHRyZXR1cm4gbnVtID4gMCA/IDEgOiBudW0gPCAwID8gLSAxIDogMDtcclxuXHJcbn1cclxuXHJcbi8vIGNoZWNrIGlmIGEgcG9seWdvbiBkaWFnb25hbCBpbnRlcnNlY3RzIGFueSBwb2x5Z29uIHNlZ21lbnRzXHJcbmZ1bmN0aW9uIGludGVyc2VjdHNQb2x5Z29uKCBhLCBiICkge1xyXG5cclxuXHRsZXQgcCA9IGE7XHJcblx0ZG8ge1xyXG5cclxuXHRcdGlmICggcC5pICE9PSBhLmkgJiYgcC5uZXh0LmkgIT09IGEuaSAmJiBwLmkgIT09IGIuaSAmJiBwLm5leHQuaSAhPT0gYi5pICYmXHJcblx0XHRcdGludGVyc2VjdHMoIHAsIHAubmV4dCwgYSwgYiApICkgcmV0dXJuIHRydWU7XHJcblx0XHRwID0gcC5uZXh0O1xyXG5cclxuXHR9IHdoaWxlICggcCAhPT0gYSApO1xyXG5cclxuXHRyZXR1cm4gZmFsc2U7XHJcblxyXG59XHJcblxyXG4vLyBjaGVjayBpZiBhIHBvbHlnb24gZGlhZ29uYWwgaXMgbG9jYWxseSBpbnNpZGUgdGhlIHBvbHlnb25cclxuZnVuY3Rpb24gbG9jYWxseUluc2lkZSggYSwgYiApIHtcclxuXHJcblx0cmV0dXJuIGFyZWEoIGEucHJldiwgYSwgYS5uZXh0ICkgPCAwID9cclxuXHRcdGFyZWEoIGEsIGIsIGEubmV4dCApID49IDAgJiYgYXJlYSggYSwgYS5wcmV2LCBiICkgPj0gMCA6XHJcblx0XHRhcmVhKCBhLCBiLCBhLnByZXYgKSA8IDAgfHwgYXJlYSggYSwgYS5uZXh0LCBiICkgPCAwO1xyXG5cclxufVxyXG5cclxuLy8gY2hlY2sgaWYgdGhlIG1pZGRsZSBwb2ludCBvZiBhIHBvbHlnb24gZGlhZ29uYWwgaXMgaW5zaWRlIHRoZSBwb2x5Z29uXHJcbmZ1bmN0aW9uIG1pZGRsZUluc2lkZSggYSwgYiApIHtcclxuXHJcblx0bGV0IHAgPSBhLFxyXG5cdFx0aW5zaWRlID0gZmFsc2U7XHJcblx0Y29uc3QgcHggPSAoIGEueCArIGIueCApIC8gMixcclxuXHRcdHB5ID0gKCBhLnkgKyBiLnkgKSAvIDI7XHJcblx0ZG8ge1xyXG5cclxuXHRcdGlmICggKCAoIHAueSA+IHB5ICkgIT09ICggcC5uZXh0LnkgPiBweSApICkgJiYgcC5uZXh0LnkgIT09IHAueSAmJlxyXG5cdFx0XHQoIHB4IDwgKCBwLm5leHQueCAtIHAueCApICogKCBweSAtIHAueSApIC8gKCBwLm5leHQueSAtIHAueSApICsgcC54ICkgKVxyXG5cdFx0XHRpbnNpZGUgPSAhIGluc2lkZTtcclxuXHRcdHAgPSBwLm5leHQ7XHJcblxyXG5cdH0gd2hpbGUgKCBwICE9PSBhICk7XHJcblxyXG5cdHJldHVybiBpbnNpZGU7XHJcblxyXG59XHJcblxyXG4vLyBsaW5rIHR3byBwb2x5Z29uIHZlcnRpY2VzIHdpdGggYSBicmlkZ2U7IGlmIHRoZSB2ZXJ0aWNlcyBiZWxvbmcgdG8gdGhlIHNhbWUgcmluZywgaXQgc3BsaXRzIHBvbHlnb24gaW50byB0d287XHJcbi8vIGlmIG9uZSBiZWxvbmdzIHRvIHRoZSBvdXRlciByaW5nIGFuZCBhbm90aGVyIHRvIGEgaG9sZSwgaXQgbWVyZ2VzIGl0IGludG8gYSBzaW5nbGUgcmluZ1xyXG5mdW5jdGlvbiBzcGxpdFBvbHlnb24oIGEsIGIgKSB7XHJcblxyXG5cdGNvbnN0IGEyID0gbmV3IE5vZGUoIGEuaSwgYS54LCBhLnkgKSxcclxuXHRcdGIyID0gbmV3IE5vZGUoIGIuaSwgYi54LCBiLnkgKSxcclxuXHRcdGFuID0gYS5uZXh0LFxyXG5cdFx0YnAgPSBiLnByZXY7XHJcblxyXG5cdGEubmV4dCA9IGI7XHJcblx0Yi5wcmV2ID0gYTtcclxuXHJcblx0YTIubmV4dCA9IGFuO1xyXG5cdGFuLnByZXYgPSBhMjtcclxuXHJcblx0YjIubmV4dCA9IGEyO1xyXG5cdGEyLnByZXYgPSBiMjtcclxuXHJcblx0YnAubmV4dCA9IGIyO1xyXG5cdGIyLnByZXYgPSBicDtcclxuXHJcblx0cmV0dXJuIGIyO1xyXG5cclxufVxyXG5cclxuLy8gY3JlYXRlIGEgbm9kZSBhbmQgb3B0aW9uYWxseSBsaW5rIGl0IHdpdGggcHJldmlvdXMgb25lIChpbiBhIGNpcmN1bGFyIGRvdWJseSBsaW5rZWQgbGlzdClcclxuZnVuY3Rpb24gaW5zZXJ0Tm9kZSggaSwgeCwgeSwgbGFzdCApIHtcclxuXHJcblx0Y29uc3QgcCA9IG5ldyBOb2RlKCBpLCB4LCB5ICk7XHJcblxyXG5cdGlmICggISBsYXN0ICkge1xyXG5cclxuXHRcdHAucHJldiA9IHA7XHJcblx0XHRwLm5leHQgPSBwO1xyXG5cclxuXHR9IGVsc2Uge1xyXG5cclxuXHRcdHAubmV4dCA9IGxhc3QubmV4dDtcclxuXHRcdHAucHJldiA9IGxhc3Q7XHJcblx0XHRsYXN0Lm5leHQucHJldiA9IHA7XHJcblx0XHRsYXN0Lm5leHQgPSBwO1xyXG5cclxuXHR9XHJcblxyXG5cdHJldHVybiBwO1xyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gcmVtb3ZlTm9kZSggcCApIHtcclxuXHJcblx0cC5uZXh0LnByZXYgPSBwLnByZXY7XHJcblx0cC5wcmV2Lm5leHQgPSBwLm5leHQ7XHJcblxyXG5cdGlmICggcC5wcmV2WiApIHAucHJldloubmV4dFogPSBwLm5leHRaO1xyXG5cdGlmICggcC5uZXh0WiApIHAubmV4dFoucHJldlogPSBwLnByZXZaO1xyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gTm9kZSggaSwgeCwgeSApIHtcclxuXHJcblx0Ly8gdmVydGV4IGluZGV4IGluIGNvb3JkaW5hdGVzIGFycmF5XHJcblx0dGhpcy5pID0gaTtcclxuXHJcblx0Ly8gdmVydGV4IGNvb3JkaW5hdGVzXHJcblx0dGhpcy54ID0geDtcclxuXHR0aGlzLnkgPSB5O1xyXG5cclxuXHQvLyBwcmV2aW91cyBhbmQgbmV4dCB2ZXJ0ZXggbm9kZXMgaW4gYSBwb2x5Z29uIHJpbmdcclxuXHR0aGlzLnByZXYgPSBudWxsO1xyXG5cdHRoaXMubmV4dCA9IG51bGw7XHJcblxyXG5cdC8vIHotb3JkZXIgY3VydmUgdmFsdWVcclxuXHR0aGlzLnogPSAwO1xyXG5cclxuXHQvLyBwcmV2aW91cyBhbmQgbmV4dCBub2RlcyBpbiB6LW9yZGVyXHJcblx0dGhpcy5wcmV2WiA9IG51bGw7XHJcblx0dGhpcy5uZXh0WiA9IG51bGw7XHJcblxyXG5cdC8vIGluZGljYXRlcyB3aGV0aGVyIHRoaXMgaXMgYSBzdGVpbmVyIHBvaW50XHJcblx0dGhpcy5zdGVpbmVyID0gZmFsc2U7XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiBzaWduZWRBcmVhKCBkYXRhLCBzdGFydCwgZW5kLCBkaW0gKSB7XHJcblxyXG5cdGxldCBzdW0gPSAwO1xyXG5cdGZvciAoIGxldCBpID0gc3RhcnQsIGogPSBlbmQgLSBkaW07IGkgPCBlbmQ7IGkgKz0gZGltICkge1xyXG5cclxuXHRcdHN1bSArPSAoIGRhdGFbIGogXSAtIGRhdGFbIGkgXSApICogKCBkYXRhWyBpICsgMSBdICsgZGF0YVsgaiArIDEgXSApO1xyXG5cdFx0aiA9IGk7XHJcblxyXG5cdH1cclxuXHJcblx0cmV0dXJuIHN1bTtcclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IEVhcmN1dCB9O1xyXG4iLCJpbXBvcnQgeyBFYXJjdXQgfSBmcm9tICcuL0VhcmN1dC5qcyc7XHJcblxyXG5jbGFzcyBTaGFwZVV0aWxzIHtcclxuXHJcblx0Ly8gY2FsY3VsYXRlIGFyZWEgb2YgdGhlIGNvbnRvdXIgcG9seWdvblxyXG5cclxuXHRzdGF0aWMgYXJlYSggY29udG91ciApIHtcclxuXHJcblx0XHRjb25zdCBuID0gY29udG91ci5sZW5ndGg7XHJcblx0XHRsZXQgYSA9IDAuMDtcclxuXHJcblx0XHRmb3IgKCBsZXQgcCA9IG4gLSAxLCBxID0gMDsgcSA8IG47IHAgPSBxICsrICkge1xyXG5cclxuXHRcdFx0YSArPSBjb250b3VyWyBwIF0ueCAqIGNvbnRvdXJbIHEgXS55IC0gY29udG91clsgcSBdLnggKiBjb250b3VyWyBwIF0ueTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIGEgKiAwLjU7XHJcblxyXG5cdH1cclxuXHJcblx0c3RhdGljIGlzQ2xvY2tXaXNlKCBwdHMgKSB7XHJcblxyXG5cdFx0cmV0dXJuIFNoYXBlVXRpbHMuYXJlYSggcHRzICkgPCAwO1xyXG5cclxuXHR9XHJcblxyXG5cdHN0YXRpYyB0cmlhbmd1bGF0ZVNoYXBlKCBjb250b3VyLCBob2xlcyApIHtcclxuXHJcblx0XHRjb25zdCB2ZXJ0aWNlcyA9IFtdOyAvLyBmbGF0IGFycmF5IG9mIHZlcnRpY2VzIGxpa2UgWyB4MCx5MCwgeDEseTEsIHgyLHkyLCAuLi4gXVxyXG5cdFx0Y29uc3QgaG9sZUluZGljZXMgPSBbXTsgLy8gYXJyYXkgb2YgaG9sZSBpbmRpY2VzXHJcblx0XHRjb25zdCBmYWNlcyA9IFtdOyAvLyBmaW5hbCBhcnJheSBvZiB2ZXJ0ZXggaW5kaWNlcyBsaWtlIFsgWyBhLGIsZCBdLCBbIGIsYyxkIF0gXVxyXG5cclxuXHRcdHJlbW92ZUR1cEVuZFB0cyggY29udG91ciApO1xyXG5cdFx0YWRkQ29udG91ciggdmVydGljZXMsIGNvbnRvdXIgKTtcclxuXHJcblx0XHQvL1xyXG5cclxuXHRcdGxldCBob2xlSW5kZXggPSBjb250b3VyLmxlbmd0aDtcclxuXHJcblx0XHRob2xlcy5mb3JFYWNoKCByZW1vdmVEdXBFbmRQdHMgKTtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBob2xlcy5sZW5ndGg7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRob2xlSW5kaWNlcy5wdXNoKCBob2xlSW5kZXggKTtcclxuXHRcdFx0aG9sZUluZGV4ICs9IGhvbGVzWyBpIF0ubGVuZ3RoO1xyXG5cdFx0XHRhZGRDb250b3VyKCB2ZXJ0aWNlcywgaG9sZXNbIGkgXSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvL1xyXG5cclxuXHRcdGNvbnN0IHRyaWFuZ2xlcyA9IEVhcmN1dC50cmlhbmd1bGF0ZSggdmVydGljZXMsIGhvbGVJbmRpY2VzICk7XHJcblxyXG5cdFx0Ly9cclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCB0cmlhbmdsZXMubGVuZ3RoOyBpICs9IDMgKSB7XHJcblxyXG5cdFx0XHRmYWNlcy5wdXNoKCB0cmlhbmdsZXMuc2xpY2UoIGksIGkgKyAzICkgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIGZhY2VzO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiByZW1vdmVEdXBFbmRQdHMoIHBvaW50cyApIHtcclxuXHJcblx0Y29uc3QgbCA9IHBvaW50cy5sZW5ndGg7XHJcblxyXG5cdGlmICggbCA+IDIgJiYgcG9pbnRzWyBsIC0gMSBdLmVxdWFscyggcG9pbnRzWyAwIF0gKSApIHtcclxuXHJcblx0XHRwb2ludHMucG9wKCk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmZ1bmN0aW9uIGFkZENvbnRvdXIoIHZlcnRpY2VzLCBjb250b3VyICkge1xyXG5cclxuXHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBjb250b3VyLmxlbmd0aDsgaSArKyApIHtcclxuXHJcblx0XHR2ZXJ0aWNlcy5wdXNoKCBjb250b3VyWyBpIF0ueCApO1xyXG5cdFx0dmVydGljZXMucHVzaCggY29udG91clsgaSBdLnkgKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgU2hhcGVVdGlscyB9O1xyXG4iLCIvKipcclxuICogQ3JlYXRlcyBleHRydWRlZCBnZW9tZXRyeSBmcm9tIGEgcGF0aCBzaGFwZS5cclxuICpcclxuICogcGFyYW1ldGVycyA9IHtcclxuICpcclxuICogIGN1cnZlU2VnbWVudHM6IDxpbnQ+LCAvLyBudW1iZXIgb2YgcG9pbnRzIG9uIHRoZSBjdXJ2ZXNcclxuICogIHN0ZXBzOiA8aW50PiwgLy8gbnVtYmVyIG9mIHBvaW50cyBmb3Igei1zaWRlIGV4dHJ1c2lvbnMgLyB1c2VkIGZvciBzdWJkaXZpZGluZyBzZWdtZW50cyBvZiBleHRydWRlIHNwbGluZSB0b29cclxuICogIGRlcHRoOiA8ZmxvYXQ+LCAvLyBEZXB0aCB0byBleHRydWRlIHRoZSBzaGFwZVxyXG4gKlxyXG4gKiAgYmV2ZWxFbmFibGVkOiA8Ym9vbD4sIC8vIHR1cm4gb24gYmV2ZWxcclxuICogIGJldmVsVGhpY2tuZXNzOiA8ZmxvYXQ+LCAvLyBob3cgZGVlcCBpbnRvIHRoZSBvcmlnaW5hbCBzaGFwZSBiZXZlbCBnb2VzXHJcbiAqICBiZXZlbFNpemU6IDxmbG9hdD4sIC8vIGhvdyBmYXIgZnJvbSBzaGFwZSBvdXRsaW5lIChpbmNsdWRpbmcgYmV2ZWxPZmZzZXQpIGlzIGJldmVsXHJcbiAqICBiZXZlbE9mZnNldDogPGZsb2F0PiwgLy8gaG93IGZhciBmcm9tIHNoYXBlIG91dGxpbmUgZG9lcyBiZXZlbCBzdGFydFxyXG4gKiAgYmV2ZWxTZWdtZW50czogPGludD4sIC8vIG51bWJlciBvZiBiZXZlbCBsYXllcnNcclxuICpcclxuICogIGV4dHJ1ZGVQYXRoOiA8VEhSRUUuQ3VydmU+IC8vIGN1cnZlIHRvIGV4dHJ1ZGUgc2hhcGUgYWxvbmdcclxuICpcclxuICogIFVWR2VuZXJhdG9yOiA8T2JqZWN0PiAvLyBvYmplY3QgdGhhdCBwcm92aWRlcyBVViBnZW5lcmF0b3IgZnVuY3Rpb25zXHJcbiAqXHJcbiAqIH1cclxuICovXHJcblxyXG5pbXBvcnQgeyBCdWZmZXJHZW9tZXRyeSB9IGZyb20gJy4uL2NvcmUvQnVmZmVyR2VvbWV0cnkuanMnO1xyXG5pbXBvcnQgeyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlIH0gZnJvbSAnLi4vY29yZS9CdWZmZXJBdHRyaWJ1dGUuanMnO1xyXG5pbXBvcnQgKiBhcyBDdXJ2ZXMgZnJvbSAnLi4vZXh0cmFzL2N1cnZlcy9DdXJ2ZXMuanMnO1xyXG5pbXBvcnQgeyBWZWN0b3IyIH0gZnJvbSAnLi4vbWF0aC9WZWN0b3IyLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yMyB9IGZyb20gJy4uL21hdGgvVmVjdG9yMy5qcyc7XHJcbmltcG9ydCB7IFNoYXBlIH0gZnJvbSAnLi4vZXh0cmFzL2NvcmUvU2hhcGUuanMnO1xyXG5pbXBvcnQgeyBTaGFwZVV0aWxzIH0gZnJvbSAnLi4vZXh0cmFzL1NoYXBlVXRpbHMuanMnO1xyXG5cclxuY2xhc3MgRXh0cnVkZUdlb21ldHJ5IGV4dGVuZHMgQnVmZmVyR2VvbWV0cnkge1xyXG5cclxuXHRjb25zdHJ1Y3Rvciggc2hhcGVzID0gbmV3IFNoYXBlKCBbIG5ldyBWZWN0b3IyKCAwLjUsIDAuNSApLCBuZXcgVmVjdG9yMiggLSAwLjUsIDAuNSApLCBuZXcgVmVjdG9yMiggLSAwLjUsIC0gMC41ICksIG5ldyBWZWN0b3IyKCAwLjUsIC0gMC41ICkgXSApLCBvcHRpb25zID0ge30gKSB7XHJcblxyXG5cdFx0c3VwZXIoKTtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSAnRXh0cnVkZUdlb21ldHJ5JztcclxuXHJcblx0XHR0aGlzLnBhcmFtZXRlcnMgPSB7XHJcblx0XHRcdHNoYXBlczogc2hhcGVzLFxyXG5cdFx0XHRvcHRpb25zOiBvcHRpb25zXHJcblx0XHR9O1xyXG5cclxuXHRcdHNoYXBlcyA9IEFycmF5LmlzQXJyYXkoIHNoYXBlcyApID8gc2hhcGVzIDogWyBzaGFwZXMgXTtcclxuXHJcblx0XHRjb25zdCBzY29wZSA9IHRoaXM7XHJcblxyXG5cdFx0Y29uc3QgdmVydGljZXNBcnJheSA9IFtdO1xyXG5cdFx0Y29uc3QgdXZBcnJheSA9IFtdO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IHNoYXBlcy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0Y29uc3Qgc2hhcGUgPSBzaGFwZXNbIGkgXTtcclxuXHRcdFx0YWRkU2hhcGUoIHNoYXBlICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIGJ1aWxkIGdlb21ldHJ5XHJcblxyXG5cdFx0dGhpcy5zZXRBdHRyaWJ1dGUoICdwb3NpdGlvbicsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCB2ZXJ0aWNlc0FycmF5LCAzICkgKTtcclxuXHRcdHRoaXMuc2V0QXR0cmlidXRlKCAndXYnLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggdXZBcnJheSwgMiApICk7XHJcblxyXG5cdFx0dGhpcy5jb21wdXRlVmVydGV4Tm9ybWFscygpO1xyXG5cclxuXHRcdC8vIGZ1bmN0aW9uc1xyXG5cclxuXHRcdGZ1bmN0aW9uIGFkZFNoYXBlKCBzaGFwZSApIHtcclxuXHJcblx0XHRcdGNvbnN0IHBsYWNlaG9sZGVyID0gW107XHJcblxyXG5cdFx0XHQvLyBvcHRpb25zXHJcblxyXG5cdFx0XHRjb25zdCBjdXJ2ZVNlZ21lbnRzID0gb3B0aW9ucy5jdXJ2ZVNlZ21lbnRzICE9PSB1bmRlZmluZWQgPyBvcHRpb25zLmN1cnZlU2VnbWVudHMgOiAxMjtcclxuXHRcdFx0Y29uc3Qgc3RlcHMgPSBvcHRpb25zLnN0ZXBzICE9PSB1bmRlZmluZWQgPyBvcHRpb25zLnN0ZXBzIDogMTtcclxuXHRcdFx0Y29uc3QgZGVwdGggPSBvcHRpb25zLmRlcHRoICE9PSB1bmRlZmluZWQgPyBvcHRpb25zLmRlcHRoIDogMTtcclxuXHJcblx0XHRcdGxldCBiZXZlbEVuYWJsZWQgPSBvcHRpb25zLmJldmVsRW5hYmxlZCAhPT0gdW5kZWZpbmVkID8gb3B0aW9ucy5iZXZlbEVuYWJsZWQgOiB0cnVlO1xyXG5cdFx0XHRsZXQgYmV2ZWxUaGlja25lc3MgPSBvcHRpb25zLmJldmVsVGhpY2tuZXNzICE9PSB1bmRlZmluZWQgPyBvcHRpb25zLmJldmVsVGhpY2tuZXNzIDogMC4yO1xyXG5cdFx0XHRsZXQgYmV2ZWxTaXplID0gb3B0aW9ucy5iZXZlbFNpemUgIT09IHVuZGVmaW5lZCA/IG9wdGlvbnMuYmV2ZWxTaXplIDogYmV2ZWxUaGlja25lc3MgLSAwLjE7XHJcblx0XHRcdGxldCBiZXZlbE9mZnNldCA9IG9wdGlvbnMuYmV2ZWxPZmZzZXQgIT09IHVuZGVmaW5lZCA/IG9wdGlvbnMuYmV2ZWxPZmZzZXQgOiAwO1xyXG5cdFx0XHRsZXQgYmV2ZWxTZWdtZW50cyA9IG9wdGlvbnMuYmV2ZWxTZWdtZW50cyAhPT0gdW5kZWZpbmVkID8gb3B0aW9ucy5iZXZlbFNlZ21lbnRzIDogMztcclxuXHJcblx0XHRcdGNvbnN0IGV4dHJ1ZGVQYXRoID0gb3B0aW9ucy5leHRydWRlUGF0aDtcclxuXHJcblx0XHRcdGNvbnN0IHV2Z2VuID0gb3B0aW9ucy5VVkdlbmVyYXRvciAhPT0gdW5kZWZpbmVkID8gb3B0aW9ucy5VVkdlbmVyYXRvciA6IFdvcmxkVVZHZW5lcmF0b3I7XHJcblxyXG5cdFx0XHQvL1xyXG5cclxuXHRcdFx0bGV0IGV4dHJ1ZGVQdHMsIGV4dHJ1ZGVCeVBhdGggPSBmYWxzZTtcclxuXHRcdFx0bGV0IHNwbGluZVR1YmUsIGJpbm9ybWFsLCBub3JtYWwsIHBvc2l0aW9uMjtcclxuXHJcblx0XHRcdGlmICggZXh0cnVkZVBhdGggKSB7XHJcblxyXG5cdFx0XHRcdGV4dHJ1ZGVQdHMgPSBleHRydWRlUGF0aC5nZXRTcGFjZWRQb2ludHMoIHN0ZXBzICk7XHJcblxyXG5cdFx0XHRcdGV4dHJ1ZGVCeVBhdGggPSB0cnVlO1xyXG5cdFx0XHRcdGJldmVsRW5hYmxlZCA9IGZhbHNlOyAvLyBiZXZlbHMgbm90IHN1cHBvcnRlZCBmb3IgcGF0aCBleHRydXNpb25cclxuXHJcblx0XHRcdFx0Ly8gU0VUVVAgVE5CIHZhcmlhYmxlc1xyXG5cclxuXHRcdFx0XHQvLyBUT0RPMSAtIGhhdmUgYSAuaXNDbG9zZWQgaW4gc3BsaW5lP1xyXG5cclxuXHRcdFx0XHRzcGxpbmVUdWJlID0gZXh0cnVkZVBhdGguY29tcHV0ZUZyZW5ldEZyYW1lcyggc3RlcHMsIGZhbHNlICk7XHJcblxyXG5cdFx0XHRcdC8vIGNvbnNvbGUubG9nKHNwbGluZVR1YmUsICdzcGxpbmVUdWJlJywgc3BsaW5lVHViZS5ub3JtYWxzLmxlbmd0aCwgJ3N0ZXBzJywgc3RlcHMsICdleHRydWRlUHRzJywgZXh0cnVkZVB0cy5sZW5ndGgpO1xyXG5cclxuXHRcdFx0XHRiaW5vcm1hbCA9IG5ldyBWZWN0b3IzKCk7XHJcblx0XHRcdFx0bm9ybWFsID0gbmV3IFZlY3RvcjMoKTtcclxuXHRcdFx0XHRwb3NpdGlvbjIgPSBuZXcgVmVjdG9yMygpO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Ly8gU2FmZWd1YXJkcyBpZiBiZXZlbHMgYXJlIG5vdCBlbmFibGVkXHJcblxyXG5cdFx0XHRpZiAoICEgYmV2ZWxFbmFibGVkICkge1xyXG5cclxuXHRcdFx0XHRiZXZlbFNlZ21lbnRzID0gMDtcclxuXHRcdFx0XHRiZXZlbFRoaWNrbmVzcyA9IDA7XHJcblx0XHRcdFx0YmV2ZWxTaXplID0gMDtcclxuXHRcdFx0XHRiZXZlbE9mZnNldCA9IDA7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyBWYXJpYWJsZXMgaW5pdGlhbGl6YXRpb25cclxuXHJcblx0XHRcdGNvbnN0IHNoYXBlUG9pbnRzID0gc2hhcGUuZXh0cmFjdFBvaW50cyggY3VydmVTZWdtZW50cyApO1xyXG5cclxuXHRcdFx0bGV0IHZlcnRpY2VzID0gc2hhcGVQb2ludHMuc2hhcGU7XHJcblx0XHRcdGNvbnN0IGhvbGVzID0gc2hhcGVQb2ludHMuaG9sZXM7XHJcblxyXG5cdFx0XHRjb25zdCByZXZlcnNlID0gISBTaGFwZVV0aWxzLmlzQ2xvY2tXaXNlKCB2ZXJ0aWNlcyApO1xyXG5cclxuXHRcdFx0aWYgKCByZXZlcnNlICkge1xyXG5cclxuXHRcdFx0XHR2ZXJ0aWNlcyA9IHZlcnRpY2VzLnJldmVyc2UoKTtcclxuXHJcblx0XHRcdFx0Ly8gTWF5YmUgd2Ugc2hvdWxkIGFsc28gY2hlY2sgaWYgaG9sZXMgYXJlIGluIHRoZSBvcHBvc2l0ZSBkaXJlY3Rpb24sIGp1c3QgdG8gYmUgc2FmZSAuLi5cclxuXHJcblx0XHRcdFx0Zm9yICggbGV0IGggPSAwLCBobCA9IGhvbGVzLmxlbmd0aDsgaCA8IGhsOyBoICsrICkge1xyXG5cclxuXHRcdFx0XHRcdGNvbnN0IGFob2xlID0gaG9sZXNbIGggXTtcclxuXHJcblx0XHRcdFx0XHRpZiAoIFNoYXBlVXRpbHMuaXNDbG9ja1dpc2UoIGFob2xlICkgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRob2xlc1sgaCBdID0gYWhvbGUucmV2ZXJzZSgpO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHJcblx0XHRcdGNvbnN0IGZhY2VzID0gU2hhcGVVdGlscy50cmlhbmd1bGF0ZVNoYXBlKCB2ZXJ0aWNlcywgaG9sZXMgKTtcclxuXHJcblx0XHRcdC8qIFZlcnRpY2VzICovXHJcblxyXG5cdFx0XHRjb25zdCBjb250b3VyID0gdmVydGljZXM7IC8vIHZlcnRpY2VzIGhhcyBhbGwgcG9pbnRzIGJ1dCBjb250b3VyIGhhcyBvbmx5IHBvaW50cyBvZiBjaXJjdW1mZXJlbmNlXHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaCA9IDAsIGhsID0gaG9sZXMubGVuZ3RoOyBoIDwgaGw7IGggKysgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IGFob2xlID0gaG9sZXNbIGggXTtcclxuXHJcblx0XHRcdFx0dmVydGljZXMgPSB2ZXJ0aWNlcy5jb25jYXQoIGFob2xlICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cclxuXHRcdFx0ZnVuY3Rpb24gc2NhbGVQdDIoIHB0LCB2ZWMsIHNpemUgKSB7XHJcblxyXG5cdFx0XHRcdGlmICggISB2ZWMgKSBjb25zb2xlLmVycm9yKCAnVEhSRUUuRXh0cnVkZUdlb21ldHJ5OiB2ZWMgZG9lcyBub3QgZXhpc3QnICk7XHJcblxyXG5cdFx0XHRcdHJldHVybiBwdC5jbG9uZSgpLmFkZFNjYWxlZFZlY3RvciggdmVjLCBzaXplICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRjb25zdCB2bGVuID0gdmVydGljZXMubGVuZ3RoLCBmbGVuID0gZmFjZXMubGVuZ3RoO1xyXG5cclxuXHJcblx0XHRcdC8vIEZpbmQgZGlyZWN0aW9ucyBmb3IgcG9pbnQgbW92ZW1lbnRcclxuXHJcblxyXG5cdFx0XHRmdW5jdGlvbiBnZXRCZXZlbFZlYyggaW5QdCwgaW5QcmV2LCBpbk5leHQgKSB7XHJcblxyXG5cdFx0XHRcdC8vIGNvbXB1dGVzIGZvciBpblB0IHRoZSBjb3JyZXNwb25kaW5nIHBvaW50IGluUHQnIG9uIGEgbmV3IGNvbnRvdXJcclxuXHRcdFx0XHQvLyAgIHNoaWZ0ZWQgYnkgMSB1bml0IChsZW5ndGggb2Ygbm9ybWFsaXplZCB2ZWN0b3IpIHRvIHRoZSBsZWZ0XHJcblx0XHRcdFx0Ly8gaWYgd2Ugd2FsayBhbG9uZyBjb250b3VyIGNsb2Nrd2lzZSwgdGhpcyBuZXcgY29udG91ciBpcyBvdXRzaWRlIHRoZSBvbGQgb25lXHJcblx0XHRcdFx0Ly9cclxuXHRcdFx0XHQvLyBpblB0JyBpcyB0aGUgaW50ZXJzZWN0aW9uIG9mIHRoZSB0d28gbGluZXMgcGFyYWxsZWwgdG8gdGhlIHR3b1xyXG5cdFx0XHRcdC8vICBhZGphY2VudCBlZGdlcyBvZiBpblB0IGF0IGEgZGlzdGFuY2Ugb2YgMSB1bml0IG9uIHRoZSBsZWZ0IHNpZGUuXHJcblxyXG5cdFx0XHRcdGxldCB2X3RyYW5zX3gsIHZfdHJhbnNfeSwgc2hyaW5rX2J5OyAvLyByZXN1bHRpbmcgdHJhbnNsYXRpb24gdmVjdG9yIGZvciBpblB0XHJcblxyXG5cdFx0XHRcdC8vIGdvb2QgcmVhZGluZyBmb3IgZ2VvbWV0cnkgYWxnb3JpdGhtcyAoaGVyZTogbGluZS1saW5lIGludGVyc2VjdGlvbilcclxuXHRcdFx0XHQvLyBodHRwOi8vZ2VvbWFsZ29yaXRobXMuY29tL2EwNS1faW50ZXJzZWN0LTEuaHRtbFxyXG5cclxuXHRcdFx0XHRjb25zdCB2X3ByZXZfeCA9IGluUHQueCAtIGluUHJldi54LFxyXG5cdFx0XHRcdFx0dl9wcmV2X3kgPSBpblB0LnkgLSBpblByZXYueTtcclxuXHRcdFx0XHRjb25zdCB2X25leHRfeCA9IGluTmV4dC54IC0gaW5QdC54LFxyXG5cdFx0XHRcdFx0dl9uZXh0X3kgPSBpbk5leHQueSAtIGluUHQueTtcclxuXHJcblx0XHRcdFx0Y29uc3Qgdl9wcmV2X2xlbnNxID0gKCB2X3ByZXZfeCAqIHZfcHJldl94ICsgdl9wcmV2X3kgKiB2X3ByZXZfeSApO1xyXG5cclxuXHRcdFx0XHQvLyBjaGVjayBmb3IgY29sbGluZWFyIGVkZ2VzXHJcblx0XHRcdFx0Y29uc3QgY29sbGluZWFyMCA9ICggdl9wcmV2X3ggKiB2X25leHRfeSAtIHZfcHJldl95ICogdl9uZXh0X3ggKTtcclxuXHJcblx0XHRcdFx0aWYgKCBNYXRoLmFicyggY29sbGluZWFyMCApID4gTnVtYmVyLkVQU0lMT04gKSB7XHJcblxyXG5cdFx0XHRcdFx0Ly8gbm90IGNvbGxpbmVhclxyXG5cclxuXHRcdFx0XHRcdC8vIGxlbmd0aCBvZiB2ZWN0b3JzIGZvciBub3JtYWxpemluZ1xyXG5cclxuXHRcdFx0XHRcdGNvbnN0IHZfcHJldl9sZW4gPSBNYXRoLnNxcnQoIHZfcHJldl9sZW5zcSApO1xyXG5cdFx0XHRcdFx0Y29uc3Qgdl9uZXh0X2xlbiA9IE1hdGguc3FydCggdl9uZXh0X3ggKiB2X25leHRfeCArIHZfbmV4dF95ICogdl9uZXh0X3kgKTtcclxuXHJcblx0XHRcdFx0XHQvLyBzaGlmdCBhZGphY2VudCBwb2ludHMgYnkgdW5pdCB2ZWN0b3JzIHRvIHRoZSBsZWZ0XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgcHRQcmV2U2hpZnRfeCA9ICggaW5QcmV2LnggLSB2X3ByZXZfeSAvIHZfcHJldl9sZW4gKTtcclxuXHRcdFx0XHRcdGNvbnN0IHB0UHJldlNoaWZ0X3kgPSAoIGluUHJldi55ICsgdl9wcmV2X3ggLyB2X3ByZXZfbGVuICk7XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgcHROZXh0U2hpZnRfeCA9ICggaW5OZXh0LnggLSB2X25leHRfeSAvIHZfbmV4dF9sZW4gKTtcclxuXHRcdFx0XHRcdGNvbnN0IHB0TmV4dFNoaWZ0X3kgPSAoIGluTmV4dC55ICsgdl9uZXh0X3ggLyB2X25leHRfbGVuICk7XHJcblxyXG5cdFx0XHRcdFx0Ly8gc2NhbGluZyBmYWN0b3IgZm9yIHZfcHJldiB0byBpbnRlcnNlY3Rpb24gcG9pbnRcclxuXHJcblx0XHRcdFx0XHRjb25zdCBzZiA9ICggKCBwdE5leHRTaGlmdF94IC0gcHRQcmV2U2hpZnRfeCApICogdl9uZXh0X3kgLVxyXG5cdFx0XHRcdFx0XHRcdCggcHROZXh0U2hpZnRfeSAtIHB0UHJldlNoaWZ0X3kgKSAqIHZfbmV4dF94ICkgL1xyXG5cdFx0XHRcdFx0XHQoIHZfcHJldl94ICogdl9uZXh0X3kgLSB2X3ByZXZfeSAqIHZfbmV4dF94ICk7XHJcblxyXG5cdFx0XHRcdFx0Ly8gdmVjdG9yIGZyb20gaW5QdCB0byBpbnRlcnNlY3Rpb24gcG9pbnRcclxuXHJcblx0XHRcdFx0XHR2X3RyYW5zX3ggPSAoIHB0UHJldlNoaWZ0X3ggKyB2X3ByZXZfeCAqIHNmIC0gaW5QdC54ICk7XHJcblx0XHRcdFx0XHR2X3RyYW5zX3kgPSAoIHB0UHJldlNoaWZ0X3kgKyB2X3ByZXZfeSAqIHNmIC0gaW5QdC55ICk7XHJcblxyXG5cdFx0XHRcdFx0Ly8gRG9uJ3Qgbm9ybWFsaXplISwgb3RoZXJ3aXNlIHNoYXJwIGNvcm5lcnMgYmVjb21lIHVnbHlcclxuXHRcdFx0XHRcdC8vICBidXQgcHJldmVudCBjcmF6eSBzcGlrZXNcclxuXHRcdFx0XHRcdGNvbnN0IHZfdHJhbnNfbGVuc3EgPSAoIHZfdHJhbnNfeCAqIHZfdHJhbnNfeCArIHZfdHJhbnNfeSAqIHZfdHJhbnNfeSApO1xyXG5cdFx0XHRcdFx0aWYgKCB2X3RyYW5zX2xlbnNxIDw9IDIgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRyZXR1cm4gbmV3IFZlY3RvcjIoIHZfdHJhbnNfeCwgdl90cmFuc195ICk7XHJcblxyXG5cdFx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRcdHNocmlua19ieSA9IE1hdGguc3FydCggdl90cmFuc19sZW5zcSAvIDIgKTtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0Ly8gaGFuZGxlIHNwZWNpYWwgY2FzZSBvZiBjb2xsaW5lYXIgZWRnZXNcclxuXHJcblx0XHRcdFx0XHRsZXQgZGlyZWN0aW9uX2VxID0gZmFsc2U7IC8vIGFzc3VtZXM6IG9wcG9zaXRlXHJcblxyXG5cdFx0XHRcdFx0aWYgKCB2X3ByZXZfeCA+IE51bWJlci5FUFNJTE9OICkge1xyXG5cclxuXHRcdFx0XHRcdFx0aWYgKCB2X25leHRfeCA+IE51bWJlci5FUFNJTE9OICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRkaXJlY3Rpb25fZXEgPSB0cnVlO1xyXG5cclxuXHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHRpZiAoIHZfcHJldl94IDwgLSBOdW1iZXIuRVBTSUxPTiApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0aWYgKCB2X25leHRfeCA8IC0gTnVtYmVyLkVQU0lMT04gKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0ZGlyZWN0aW9uX2VxID0gdHJ1ZTtcclxuXHJcblx0XHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0aWYgKCBNYXRoLnNpZ24oIHZfcHJldl95ICkgPT09IE1hdGguc2lnbiggdl9uZXh0X3kgKSApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHRkaXJlY3Rpb25fZXEgPSB0cnVlO1xyXG5cclxuXHRcdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdGlmICggZGlyZWN0aW9uX2VxICkge1xyXG5cclxuXHRcdFx0XHRcdFx0Ly8gY29uc29sZS5sb2coXCJXYXJuaW5nOiBsaW5lcyBhcmUgYSBzdHJhaWdodCBzZXF1ZW5jZVwiKTtcclxuXHRcdFx0XHRcdFx0dl90cmFuc194ID0gLSB2X3ByZXZfeTtcclxuXHRcdFx0XHRcdFx0dl90cmFuc195ID0gdl9wcmV2X3g7XHJcblx0XHRcdFx0XHRcdHNocmlua19ieSA9IE1hdGguc3FydCggdl9wcmV2X2xlbnNxICk7XHJcblxyXG5cdFx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRcdC8vIGNvbnNvbGUubG9nKFwiV2FybmluZzogbGluZXMgYXJlIGEgc3RyYWlnaHQgc3Bpa2VcIik7XHJcblx0XHRcdFx0XHRcdHZfdHJhbnNfeCA9IHZfcHJldl94O1xyXG5cdFx0XHRcdFx0XHR2X3RyYW5zX3kgPSB2X3ByZXZfeTtcclxuXHRcdFx0XHRcdFx0c2hyaW5rX2J5ID0gTWF0aC5zcXJ0KCB2X3ByZXZfbGVuc3EgLyAyICk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdHJldHVybiBuZXcgVmVjdG9yMiggdl90cmFuc194IC8gc2hyaW5rX2J5LCB2X3RyYW5zX3kgLyBzaHJpbmtfYnkgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblxyXG5cdFx0XHRjb25zdCBjb250b3VyTW92ZW1lbnRzID0gW107XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gY29udG91ci5sZW5ndGgsIGogPSBpbCAtIDEsIGsgPSBpICsgMTsgaSA8IGlsOyBpICsrLCBqICsrLCBrICsrICkge1xyXG5cclxuXHRcdFx0XHRpZiAoIGogPT09IGlsICkgaiA9IDA7XHJcblx0XHRcdFx0aWYgKCBrID09PSBpbCApIGsgPSAwO1xyXG5cclxuXHRcdFx0XHQvLyAgKGopLS0tKGkpLS0tKGspXHJcblx0XHRcdFx0Ly8gY29uc29sZS5sb2coJ2ksaixrJywgaSwgaiAsIGspXHJcblxyXG5cdFx0XHRcdGNvbnRvdXJNb3ZlbWVudHNbIGkgXSA9IGdldEJldmVsVmVjKCBjb250b3VyWyBpIF0sIGNvbnRvdXJbIGogXSwgY29udG91clsgayBdICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRjb25zdCBob2xlc01vdmVtZW50cyA9IFtdO1xyXG5cdFx0XHRsZXQgb25lSG9sZU1vdmVtZW50cywgdmVydGljZXNNb3ZlbWVudHMgPSBjb250b3VyTW92ZW1lbnRzLmNvbmNhdCgpO1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGggPSAwLCBobCA9IGhvbGVzLmxlbmd0aDsgaCA8IGhsOyBoICsrICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBhaG9sZSA9IGhvbGVzWyBoIF07XHJcblxyXG5cdFx0XHRcdG9uZUhvbGVNb3ZlbWVudHMgPSBbXTtcclxuXHJcblx0XHRcdFx0Zm9yICggbGV0IGkgPSAwLCBpbCA9IGFob2xlLmxlbmd0aCwgaiA9IGlsIC0gMSwgayA9IGkgKyAxOyBpIDwgaWw7IGkgKyssIGogKyssIGsgKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCBqID09PSBpbCApIGogPSAwO1xyXG5cdFx0XHRcdFx0aWYgKCBrID09PSBpbCApIGsgPSAwO1xyXG5cclxuXHRcdFx0XHRcdC8vICAoaiktLS0oaSktLS0oaylcclxuXHRcdFx0XHRcdG9uZUhvbGVNb3ZlbWVudHNbIGkgXSA9IGdldEJldmVsVmVjKCBhaG9sZVsgaSBdLCBhaG9sZVsgaiBdLCBhaG9sZVsgayBdICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0aG9sZXNNb3ZlbWVudHMucHVzaCggb25lSG9sZU1vdmVtZW50cyApO1xyXG5cdFx0XHRcdHZlcnRpY2VzTW92ZW1lbnRzID0gdmVydGljZXNNb3ZlbWVudHMuY29uY2F0KCBvbmVIb2xlTW92ZW1lbnRzICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cclxuXHRcdFx0Ly8gTG9vcCBiZXZlbFNlZ21lbnRzLCAxIGZvciB0aGUgZnJvbnQsIDEgZm9yIHRoZSBiYWNrXHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgYiA9IDA7IGIgPCBiZXZlbFNlZ21lbnRzOyBiICsrICkge1xyXG5cclxuXHRcdFx0XHQvL2ZvciAoIGIgPSBiZXZlbFNlZ21lbnRzOyBiID4gMDsgYiAtLSApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgdCA9IGIgLyBiZXZlbFNlZ21lbnRzO1xyXG5cdFx0XHRcdGNvbnN0IHogPSBiZXZlbFRoaWNrbmVzcyAqIE1hdGguY29zKCB0ICogTWF0aC5QSSAvIDIgKTtcclxuXHRcdFx0XHRjb25zdCBicyA9IGJldmVsU2l6ZSAqIE1hdGguc2luKCB0ICogTWF0aC5QSSAvIDIgKSArIGJldmVsT2Zmc2V0O1xyXG5cclxuXHRcdFx0XHQvLyBjb250cmFjdCBzaGFwZVxyXG5cclxuXHRcdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gY29udG91ci5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0XHRjb25zdCB2ZXJ0ID0gc2NhbGVQdDIoIGNvbnRvdXJbIGkgXSwgY29udG91ck1vdmVtZW50c1sgaSBdLCBicyApO1xyXG5cclxuXHRcdFx0XHRcdHYoIHZlcnQueCwgdmVydC55LCAtIHogKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHQvLyBleHBhbmQgaG9sZXNcclxuXHJcblx0XHRcdFx0Zm9yICggbGV0IGggPSAwLCBobCA9IGhvbGVzLmxlbmd0aDsgaCA8IGhsOyBoICsrICkge1xyXG5cclxuXHRcdFx0XHRcdGNvbnN0IGFob2xlID0gaG9sZXNbIGggXTtcclxuXHRcdFx0XHRcdG9uZUhvbGVNb3ZlbWVudHMgPSBob2xlc01vdmVtZW50c1sgaCBdO1xyXG5cclxuXHRcdFx0XHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSBhaG9sZS5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0XHRcdGNvbnN0IHZlcnQgPSBzY2FsZVB0MiggYWhvbGVbIGkgXSwgb25lSG9sZU1vdmVtZW50c1sgaSBdLCBicyApO1xyXG5cclxuXHRcdFx0XHRcdFx0diggdmVydC54LCB2ZXJ0LnksIC0geiApO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Y29uc3QgYnMgPSBiZXZlbFNpemUgKyBiZXZlbE9mZnNldDtcclxuXHJcblx0XHRcdC8vIEJhY2sgZmFjaW5nIHZlcnRpY2VzXHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCB2bGVuOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCB2ZXJ0ID0gYmV2ZWxFbmFibGVkID8gc2NhbGVQdDIoIHZlcnRpY2VzWyBpIF0sIHZlcnRpY2VzTW92ZW1lbnRzWyBpIF0sIGJzICkgOiB2ZXJ0aWNlc1sgaSBdO1xyXG5cclxuXHRcdFx0XHRpZiAoICEgZXh0cnVkZUJ5UGF0aCApIHtcclxuXHJcblx0XHRcdFx0XHR2KCB2ZXJ0LngsIHZlcnQueSwgMCApO1xyXG5cclxuXHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdC8vIHYoIHZlcnQueCwgdmVydC55ICsgZXh0cnVkZVB0c1sgMCBdLnksIGV4dHJ1ZGVQdHNbIDAgXS54ICk7XHJcblxyXG5cdFx0XHRcdFx0bm9ybWFsLmNvcHkoIHNwbGluZVR1YmUubm9ybWFsc1sgMCBdICkubXVsdGlwbHlTY2FsYXIoIHZlcnQueCApO1xyXG5cdFx0XHRcdFx0Ymlub3JtYWwuY29weSggc3BsaW5lVHViZS5iaW5vcm1hbHNbIDAgXSApLm11bHRpcGx5U2NhbGFyKCB2ZXJ0LnkgKTtcclxuXHJcblx0XHRcdFx0XHRwb3NpdGlvbjIuY29weSggZXh0cnVkZVB0c1sgMCBdICkuYWRkKCBub3JtYWwgKS5hZGQoIGJpbm9ybWFsICk7XHJcblxyXG5cdFx0XHRcdFx0diggcG9zaXRpb24yLngsIHBvc2l0aW9uMi55LCBwb3NpdGlvbjIueiApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyBBZGQgc3RlcHBlZCB2ZXJ0aWNlcy4uLlxyXG5cdFx0XHQvLyBJbmNsdWRpbmcgZnJvbnQgZmFjaW5nIHZlcnRpY2VzXHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgcyA9IDE7IHMgPD0gc3RlcHM7IHMgKysgKSB7XHJcblxyXG5cdFx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHZsZW47IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgdmVydCA9IGJldmVsRW5hYmxlZCA/IHNjYWxlUHQyKCB2ZXJ0aWNlc1sgaSBdLCB2ZXJ0aWNlc01vdmVtZW50c1sgaSBdLCBicyApIDogdmVydGljZXNbIGkgXTtcclxuXHJcblx0XHRcdFx0XHRpZiAoICEgZXh0cnVkZUJ5UGF0aCApIHtcclxuXHJcblx0XHRcdFx0XHRcdHYoIHZlcnQueCwgdmVydC55LCBkZXB0aCAvIHN0ZXBzICogcyApO1xyXG5cclxuXHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHQvLyB2KCB2ZXJ0LngsIHZlcnQueSArIGV4dHJ1ZGVQdHNbIHMgLSAxIF0ueSwgZXh0cnVkZVB0c1sgcyAtIDEgXS54ICk7XHJcblxyXG5cdFx0XHRcdFx0XHRub3JtYWwuY29weSggc3BsaW5lVHViZS5ub3JtYWxzWyBzIF0gKS5tdWx0aXBseVNjYWxhciggdmVydC54ICk7XHJcblx0XHRcdFx0XHRcdGJpbm9ybWFsLmNvcHkoIHNwbGluZVR1YmUuYmlub3JtYWxzWyBzIF0gKS5tdWx0aXBseVNjYWxhciggdmVydC55ICk7XHJcblxyXG5cdFx0XHRcdFx0XHRwb3NpdGlvbjIuY29weSggZXh0cnVkZVB0c1sgcyBdICkuYWRkKCBub3JtYWwgKS5hZGQoIGJpbm9ybWFsICk7XHJcblxyXG5cdFx0XHRcdFx0XHR2KCBwb3NpdGlvbjIueCwgcG9zaXRpb24yLnksIHBvc2l0aW9uMi56ICk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cclxuXHRcdFx0Ly8gQWRkIGJldmVsIHNlZ21lbnRzIHBsYW5lc1xyXG5cclxuXHRcdFx0Ly9mb3IgKCBiID0gMTsgYiA8PSBiZXZlbFNlZ21lbnRzOyBiICsrICkge1xyXG5cdFx0XHRmb3IgKCBsZXQgYiA9IGJldmVsU2VnbWVudHMgLSAxOyBiID49IDA7IGIgLS0gKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IHQgPSBiIC8gYmV2ZWxTZWdtZW50cztcclxuXHRcdFx0XHRjb25zdCB6ID0gYmV2ZWxUaGlja25lc3MgKiBNYXRoLmNvcyggdCAqIE1hdGguUEkgLyAyICk7XHJcblx0XHRcdFx0Y29uc3QgYnMgPSBiZXZlbFNpemUgKiBNYXRoLnNpbiggdCAqIE1hdGguUEkgLyAyICkgKyBiZXZlbE9mZnNldDtcclxuXHJcblx0XHRcdFx0Ly8gY29udHJhY3Qgc2hhcGVcclxuXHJcblx0XHRcdFx0Zm9yICggbGV0IGkgPSAwLCBpbCA9IGNvbnRvdXIubGVuZ3RoOyBpIDwgaWw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgdmVydCA9IHNjYWxlUHQyKCBjb250b3VyWyBpIF0sIGNvbnRvdXJNb3ZlbWVudHNbIGkgXSwgYnMgKTtcclxuXHRcdFx0XHRcdHYoIHZlcnQueCwgdmVydC55LCBkZXB0aCArIHogKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHQvLyBleHBhbmQgaG9sZXNcclxuXHJcblx0XHRcdFx0Zm9yICggbGV0IGggPSAwLCBobCA9IGhvbGVzLmxlbmd0aDsgaCA8IGhsOyBoICsrICkge1xyXG5cclxuXHRcdFx0XHRcdGNvbnN0IGFob2xlID0gaG9sZXNbIGggXTtcclxuXHRcdFx0XHRcdG9uZUhvbGVNb3ZlbWVudHMgPSBob2xlc01vdmVtZW50c1sgaCBdO1xyXG5cclxuXHRcdFx0XHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSBhaG9sZS5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0XHRcdGNvbnN0IHZlcnQgPSBzY2FsZVB0MiggYWhvbGVbIGkgXSwgb25lSG9sZU1vdmVtZW50c1sgaSBdLCBicyApO1xyXG5cclxuXHRcdFx0XHRcdFx0aWYgKCAhIGV4dHJ1ZGVCeVBhdGggKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdHYoIHZlcnQueCwgdmVydC55LCBkZXB0aCArIHogKTtcclxuXHJcblx0XHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdHYoIHZlcnQueCwgdmVydC55ICsgZXh0cnVkZVB0c1sgc3RlcHMgLSAxIF0ueSwgZXh0cnVkZVB0c1sgc3RlcHMgLSAxIF0ueCArIHogKTtcclxuXHJcblx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdC8qIEZhY2VzICovXHJcblxyXG5cdFx0XHQvLyBUb3AgYW5kIGJvdHRvbSBmYWNlc1xyXG5cclxuXHRcdFx0YnVpbGRMaWRGYWNlcygpO1xyXG5cclxuXHRcdFx0Ly8gU2lkZXMgZmFjZXNcclxuXHJcblx0XHRcdGJ1aWxkU2lkZUZhY2VzKCk7XHJcblxyXG5cclxuXHRcdFx0Ly8vLy8gIEludGVybmFsIGZ1bmN0aW9uc1xyXG5cclxuXHRcdFx0ZnVuY3Rpb24gYnVpbGRMaWRGYWNlcygpIHtcclxuXHJcblx0XHRcdFx0Y29uc3Qgc3RhcnQgPSB2ZXJ0aWNlc0FycmF5Lmxlbmd0aCAvIDM7XHJcblxyXG5cdFx0XHRcdGlmICggYmV2ZWxFbmFibGVkICkge1xyXG5cclxuXHRcdFx0XHRcdGxldCBsYXllciA9IDA7IC8vIHN0ZXBzICsgMVxyXG5cdFx0XHRcdFx0bGV0IG9mZnNldCA9IHZsZW4gKiBsYXllcjtcclxuXHJcblx0XHRcdFx0XHQvLyBCb3R0b20gZmFjZXNcclxuXHJcblx0XHRcdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBmbGVuOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRcdFx0Y29uc3QgZmFjZSA9IGZhY2VzWyBpIF07XHJcblx0XHRcdFx0XHRcdGYzKCBmYWNlWyAyIF0gKyBvZmZzZXQsIGZhY2VbIDEgXSArIG9mZnNldCwgZmFjZVsgMCBdICsgb2Zmc2V0ICk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdGxheWVyID0gc3RlcHMgKyBiZXZlbFNlZ21lbnRzICogMjtcclxuXHRcdFx0XHRcdG9mZnNldCA9IHZsZW4gKiBsYXllcjtcclxuXHJcblx0XHRcdFx0XHQvLyBUb3AgZmFjZXNcclxuXHJcblx0XHRcdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBmbGVuOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRcdFx0Y29uc3QgZmFjZSA9IGZhY2VzWyBpIF07XHJcblx0XHRcdFx0XHRcdGYzKCBmYWNlWyAwIF0gKyBvZmZzZXQsIGZhY2VbIDEgXSArIG9mZnNldCwgZmFjZVsgMiBdICsgb2Zmc2V0ICk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdC8vIEJvdHRvbSBmYWNlc1xyXG5cclxuXHRcdFx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IGZsZW47IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRjb25zdCBmYWNlID0gZmFjZXNbIGkgXTtcclxuXHRcdFx0XHRcdFx0ZjMoIGZhY2VbIDIgXSwgZmFjZVsgMSBdLCBmYWNlWyAwIF0gKTtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0Ly8gVG9wIGZhY2VzXHJcblxyXG5cdFx0XHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgZmxlbjsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0XHRcdGNvbnN0IGZhY2UgPSBmYWNlc1sgaSBdO1xyXG5cdFx0XHRcdFx0XHRmMyggZmFjZVsgMCBdICsgdmxlbiAqIHN0ZXBzLCBmYWNlWyAxIF0gKyB2bGVuICogc3RlcHMsIGZhY2VbIDIgXSArIHZsZW4gKiBzdGVwcyApO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRzY29wZS5hZGRHcm91cCggc3RhcnQsIHZlcnRpY2VzQXJyYXkubGVuZ3RoIC8gMyAtIHN0YXJ0LCAwICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyBDcmVhdGUgZmFjZXMgZm9yIHRoZSB6LXNpZGVzIG9mIHRoZSBzaGFwZVxyXG5cclxuXHRcdFx0ZnVuY3Rpb24gYnVpbGRTaWRlRmFjZXMoKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IHN0YXJ0ID0gdmVydGljZXNBcnJheS5sZW5ndGggLyAzO1xyXG5cdFx0XHRcdGxldCBsYXllcm9mZnNldCA9IDA7XHJcblx0XHRcdFx0c2lkZXdhbGxzKCBjb250b3VyLCBsYXllcm9mZnNldCApO1xyXG5cdFx0XHRcdGxheWVyb2Zmc2V0ICs9IGNvbnRvdXIubGVuZ3RoO1xyXG5cclxuXHRcdFx0XHRmb3IgKCBsZXQgaCA9IDAsIGhsID0gaG9sZXMubGVuZ3RoOyBoIDwgaGw7IGggKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgYWhvbGUgPSBob2xlc1sgaCBdO1xyXG5cdFx0XHRcdFx0c2lkZXdhbGxzKCBhaG9sZSwgbGF5ZXJvZmZzZXQgKTtcclxuXHJcblx0XHRcdFx0XHQvLywgdHJ1ZVxyXG5cdFx0XHRcdFx0bGF5ZXJvZmZzZXQgKz0gYWhvbGUubGVuZ3RoO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cclxuXHRcdFx0XHRzY29wZS5hZGRHcm91cCggc3RhcnQsIHZlcnRpY2VzQXJyYXkubGVuZ3RoIC8gMyAtIHN0YXJ0LCAxICk7XHJcblxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0ZnVuY3Rpb24gc2lkZXdhbGxzKCBjb250b3VyLCBsYXllcm9mZnNldCApIHtcclxuXHJcblx0XHRcdFx0bGV0IGkgPSBjb250b3VyLmxlbmd0aDtcclxuXHJcblx0XHRcdFx0d2hpbGUgKCAtLSBpID49IDAgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgaiA9IGk7XHJcblx0XHRcdFx0XHRsZXQgayA9IGkgLSAxO1xyXG5cdFx0XHRcdFx0aWYgKCBrIDwgMCApIGsgPSBjb250b3VyLmxlbmd0aCAtIDE7XHJcblxyXG5cdFx0XHRcdFx0Ly9jb25zb2xlLmxvZygnYicsIGksaiwgaS0xLCBrLHZlcnRpY2VzLmxlbmd0aCk7XHJcblxyXG5cdFx0XHRcdFx0Zm9yICggbGV0IHMgPSAwLCBzbCA9ICggc3RlcHMgKyBiZXZlbFNlZ21lbnRzICogMiApOyBzIDwgc2w7IHMgKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRjb25zdCBzbGVuMSA9IHZsZW4gKiBzO1xyXG5cdFx0XHRcdFx0XHRjb25zdCBzbGVuMiA9IHZsZW4gKiAoIHMgKyAxICk7XHJcblxyXG5cdFx0XHRcdFx0XHRjb25zdCBhID0gbGF5ZXJvZmZzZXQgKyBqICsgc2xlbjEsXHJcblx0XHRcdFx0XHRcdFx0YiA9IGxheWVyb2Zmc2V0ICsgayArIHNsZW4xLFxyXG5cdFx0XHRcdFx0XHRcdGMgPSBsYXllcm9mZnNldCArIGsgKyBzbGVuMixcclxuXHRcdFx0XHRcdFx0XHRkID0gbGF5ZXJvZmZzZXQgKyBqICsgc2xlbjI7XHJcblxyXG5cdFx0XHRcdFx0XHRmNCggYSwgYiwgYywgZCApO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0ZnVuY3Rpb24gdiggeCwgeSwgeiApIHtcclxuXHJcblx0XHRcdFx0cGxhY2Vob2xkZXIucHVzaCggeCApO1xyXG5cdFx0XHRcdHBsYWNlaG9sZGVyLnB1c2goIHkgKTtcclxuXHRcdFx0XHRwbGFjZWhvbGRlci5wdXNoKCB6ICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cclxuXHRcdFx0ZnVuY3Rpb24gZjMoIGEsIGIsIGMgKSB7XHJcblxyXG5cdFx0XHRcdGFkZFZlcnRleCggYSApO1xyXG5cdFx0XHRcdGFkZFZlcnRleCggYiApO1xyXG5cdFx0XHRcdGFkZFZlcnRleCggYyApO1xyXG5cclxuXHRcdFx0XHRjb25zdCBuZXh0SW5kZXggPSB2ZXJ0aWNlc0FycmF5Lmxlbmd0aCAvIDM7XHJcblx0XHRcdFx0Y29uc3QgdXZzID0gdXZnZW4uZ2VuZXJhdGVUb3BVViggc2NvcGUsIHZlcnRpY2VzQXJyYXksIG5leHRJbmRleCAtIDMsIG5leHRJbmRleCAtIDIsIG5leHRJbmRleCAtIDEgKTtcclxuXHJcblx0XHRcdFx0YWRkVVYoIHV2c1sgMCBdICk7XHJcblx0XHRcdFx0YWRkVVYoIHV2c1sgMSBdICk7XHJcblx0XHRcdFx0YWRkVVYoIHV2c1sgMiBdICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRmdW5jdGlvbiBmNCggYSwgYiwgYywgZCApIHtcclxuXHJcblx0XHRcdFx0YWRkVmVydGV4KCBhICk7XHJcblx0XHRcdFx0YWRkVmVydGV4KCBiICk7XHJcblx0XHRcdFx0YWRkVmVydGV4KCBkICk7XHJcblxyXG5cdFx0XHRcdGFkZFZlcnRleCggYiApO1xyXG5cdFx0XHRcdGFkZFZlcnRleCggYyApO1xyXG5cdFx0XHRcdGFkZFZlcnRleCggZCApO1xyXG5cclxuXHJcblx0XHRcdFx0Y29uc3QgbmV4dEluZGV4ID0gdmVydGljZXNBcnJheS5sZW5ndGggLyAzO1xyXG5cdFx0XHRcdGNvbnN0IHV2cyA9IHV2Z2VuLmdlbmVyYXRlU2lkZVdhbGxVViggc2NvcGUsIHZlcnRpY2VzQXJyYXksIG5leHRJbmRleCAtIDYsIG5leHRJbmRleCAtIDMsIG5leHRJbmRleCAtIDIsIG5leHRJbmRleCAtIDEgKTtcclxuXHJcblx0XHRcdFx0YWRkVVYoIHV2c1sgMCBdICk7XHJcblx0XHRcdFx0YWRkVVYoIHV2c1sgMSBdICk7XHJcblx0XHRcdFx0YWRkVVYoIHV2c1sgMyBdICk7XHJcblxyXG5cdFx0XHRcdGFkZFVWKCB1dnNbIDEgXSApO1xyXG5cdFx0XHRcdGFkZFVWKCB1dnNbIDIgXSApO1xyXG5cdFx0XHRcdGFkZFVWKCB1dnNbIDMgXSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0ZnVuY3Rpb24gYWRkVmVydGV4KCBpbmRleCApIHtcclxuXHJcblx0XHRcdFx0dmVydGljZXNBcnJheS5wdXNoKCBwbGFjZWhvbGRlclsgaW5kZXggKiAzICsgMCBdICk7XHJcblx0XHRcdFx0dmVydGljZXNBcnJheS5wdXNoKCBwbGFjZWhvbGRlclsgaW5kZXggKiAzICsgMSBdICk7XHJcblx0XHRcdFx0dmVydGljZXNBcnJheS5wdXNoKCBwbGFjZWhvbGRlclsgaW5kZXggKiAzICsgMiBdICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cclxuXHRcdFx0ZnVuY3Rpb24gYWRkVVYoIHZlY3RvcjIgKSB7XHJcblxyXG5cdFx0XHRcdHV2QXJyYXkucHVzaCggdmVjdG9yMi54ICk7XHJcblx0XHRcdFx0dXZBcnJheS5wdXNoKCB2ZWN0b3IyLnkgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xyXG5cclxuXHRcdHRoaXMucGFyYW1ldGVycyA9IE9iamVjdC5hc3NpZ24oIHt9LCBzb3VyY2UucGFyYW1ldGVycyApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHRvSlNPTigpIHtcclxuXHJcblx0XHRjb25zdCBkYXRhID0gc3VwZXIudG9KU09OKCk7XHJcblxyXG5cdFx0Y29uc3Qgc2hhcGVzID0gdGhpcy5wYXJhbWV0ZXJzLnNoYXBlcztcclxuXHRcdGNvbnN0IG9wdGlvbnMgPSB0aGlzLnBhcmFtZXRlcnMub3B0aW9ucztcclxuXHJcblx0XHRyZXR1cm4gdG9KU09OKCBzaGFwZXMsIG9wdGlvbnMsIGRhdGEgKTtcclxuXHJcblx0fVxyXG5cclxuXHRzdGF0aWMgZnJvbUpTT04oIGRhdGEsIHNoYXBlcyApIHtcclxuXHJcblx0XHRjb25zdCBnZW9tZXRyeVNoYXBlcyA9IFtdO1xyXG5cclxuXHRcdGZvciAoIGxldCBqID0gMCwgamwgPSBkYXRhLnNoYXBlcy5sZW5ndGg7IGogPCBqbDsgaiArKyApIHtcclxuXHJcblx0XHRcdGNvbnN0IHNoYXBlID0gc2hhcGVzWyBkYXRhLnNoYXBlc1sgaiBdIF07XHJcblxyXG5cdFx0XHRnZW9tZXRyeVNoYXBlcy5wdXNoKCBzaGFwZSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCBleHRydWRlUGF0aCA9IGRhdGEub3B0aW9ucy5leHRydWRlUGF0aDtcclxuXHJcblx0XHRpZiAoIGV4dHJ1ZGVQYXRoICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRkYXRhLm9wdGlvbnMuZXh0cnVkZVBhdGggPSBuZXcgQ3VydmVzWyBleHRydWRlUGF0aC50eXBlIF0oKS5mcm9tSlNPTiggZXh0cnVkZVBhdGggKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIG5ldyBFeHRydWRlR2VvbWV0cnkoIGdlb21ldHJ5U2hhcGVzLCBkYXRhLm9wdGlvbnMgKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuY29uc3QgV29ybGRVVkdlbmVyYXRvciA9IHtcclxuXHJcblx0Z2VuZXJhdGVUb3BVVjogZnVuY3Rpb24gKCBnZW9tZXRyeSwgdmVydGljZXMsIGluZGV4QSwgaW5kZXhCLCBpbmRleEMgKSB7XHJcblxyXG5cdFx0Y29uc3QgYV94ID0gdmVydGljZXNbIGluZGV4QSAqIDMgXTtcclxuXHRcdGNvbnN0IGFfeSA9IHZlcnRpY2VzWyBpbmRleEEgKiAzICsgMSBdO1xyXG5cdFx0Y29uc3QgYl94ID0gdmVydGljZXNbIGluZGV4QiAqIDMgXTtcclxuXHRcdGNvbnN0IGJfeSA9IHZlcnRpY2VzWyBpbmRleEIgKiAzICsgMSBdO1xyXG5cdFx0Y29uc3QgY194ID0gdmVydGljZXNbIGluZGV4QyAqIDMgXTtcclxuXHRcdGNvbnN0IGNfeSA9IHZlcnRpY2VzWyBpbmRleEMgKiAzICsgMSBdO1xyXG5cclxuXHRcdHJldHVybiBbXHJcblx0XHRcdG5ldyBWZWN0b3IyKCBhX3gsIGFfeSApLFxyXG5cdFx0XHRuZXcgVmVjdG9yMiggYl94LCBiX3kgKSxcclxuXHRcdFx0bmV3IFZlY3RvcjIoIGNfeCwgY195IClcclxuXHRcdF07XHJcblxyXG5cdH0sXHJcblxyXG5cdGdlbmVyYXRlU2lkZVdhbGxVVjogZnVuY3Rpb24gKCBnZW9tZXRyeSwgdmVydGljZXMsIGluZGV4QSwgaW5kZXhCLCBpbmRleEMsIGluZGV4RCApIHtcclxuXHJcblx0XHRjb25zdCBhX3ggPSB2ZXJ0aWNlc1sgaW5kZXhBICogMyBdO1xyXG5cdFx0Y29uc3QgYV95ID0gdmVydGljZXNbIGluZGV4QSAqIDMgKyAxIF07XHJcblx0XHRjb25zdCBhX3ogPSB2ZXJ0aWNlc1sgaW5kZXhBICogMyArIDIgXTtcclxuXHRcdGNvbnN0IGJfeCA9IHZlcnRpY2VzWyBpbmRleEIgKiAzIF07XHJcblx0XHRjb25zdCBiX3kgPSB2ZXJ0aWNlc1sgaW5kZXhCICogMyArIDEgXTtcclxuXHRcdGNvbnN0IGJfeiA9IHZlcnRpY2VzWyBpbmRleEIgKiAzICsgMiBdO1xyXG5cdFx0Y29uc3QgY194ID0gdmVydGljZXNbIGluZGV4QyAqIDMgXTtcclxuXHRcdGNvbnN0IGNfeSA9IHZlcnRpY2VzWyBpbmRleEMgKiAzICsgMSBdO1xyXG5cdFx0Y29uc3QgY196ID0gdmVydGljZXNbIGluZGV4QyAqIDMgKyAyIF07XHJcblx0XHRjb25zdCBkX3ggPSB2ZXJ0aWNlc1sgaW5kZXhEICogMyBdO1xyXG5cdFx0Y29uc3QgZF95ID0gdmVydGljZXNbIGluZGV4RCAqIDMgKyAxIF07XHJcblx0XHRjb25zdCBkX3ogPSB2ZXJ0aWNlc1sgaW5kZXhEICogMyArIDIgXTtcclxuXHJcblx0XHRpZiAoIE1hdGguYWJzKCBhX3kgLSBiX3kgKSA8IE1hdGguYWJzKCBhX3ggLSBiX3ggKSApIHtcclxuXHJcblx0XHRcdHJldHVybiBbXHJcblx0XHRcdFx0bmV3IFZlY3RvcjIoIGFfeCwgMSAtIGFfeiApLFxyXG5cdFx0XHRcdG5ldyBWZWN0b3IyKCBiX3gsIDEgLSBiX3ogKSxcclxuXHRcdFx0XHRuZXcgVmVjdG9yMiggY194LCAxIC0gY196ICksXHJcblx0XHRcdFx0bmV3IFZlY3RvcjIoIGRfeCwgMSAtIGRfeiApXHJcblx0XHRcdF07XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdHJldHVybiBbXHJcblx0XHRcdFx0bmV3IFZlY3RvcjIoIGFfeSwgMSAtIGFfeiApLFxyXG5cdFx0XHRcdG5ldyBWZWN0b3IyKCBiX3ksIDEgLSBiX3ogKSxcclxuXHRcdFx0XHRuZXcgVmVjdG9yMiggY195LCAxIC0gY196ICksXHJcblx0XHRcdFx0bmV3IFZlY3RvcjIoIGRfeSwgMSAtIGRfeiApXHJcblx0XHRcdF07XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG59O1xyXG5cclxuZnVuY3Rpb24gdG9KU09OKCBzaGFwZXMsIG9wdGlvbnMsIGRhdGEgKSB7XHJcblxyXG5cdGRhdGEuc2hhcGVzID0gW107XHJcblxyXG5cdGlmICggQXJyYXkuaXNBcnJheSggc2hhcGVzICkgKSB7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gc2hhcGVzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBzaGFwZSA9IHNoYXBlc1sgaSBdO1xyXG5cclxuXHRcdFx0ZGF0YS5zaGFwZXMucHVzaCggc2hhcGUudXVpZCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fSBlbHNlIHtcclxuXHJcblx0XHRkYXRhLnNoYXBlcy5wdXNoKCBzaGFwZXMudXVpZCApO1xyXG5cclxuXHR9XHJcblxyXG5cdGRhdGEub3B0aW9ucyA9IE9iamVjdC5hc3NpZ24oIHt9LCBvcHRpb25zICk7XHJcblxyXG5cdGlmICggb3B0aW9ucy5leHRydWRlUGF0aCAhPT0gdW5kZWZpbmVkICkgZGF0YS5vcHRpb25zLmV4dHJ1ZGVQYXRoID0gb3B0aW9ucy5leHRydWRlUGF0aC50b0pTT04oKTtcclxuXHJcblx0cmV0dXJuIGRhdGE7XHJcblxyXG59XHJcblxyXG5cclxuZXhwb3J0IHsgRXh0cnVkZUdlb21ldHJ5IH07XHJcbiIsImltcG9ydCB7IFBvbHloZWRyb25HZW9tZXRyeSB9IGZyb20gJy4vUG9seWhlZHJvbkdlb21ldHJ5LmpzJztcclxuXHJcbmNsYXNzIEljb3NhaGVkcm9uR2VvbWV0cnkgZXh0ZW5kcyBQb2x5aGVkcm9uR2VvbWV0cnkge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggcmFkaXVzID0gMSwgZGV0YWlsID0gMCApIHtcclxuXHJcblx0XHRjb25zdCB0ID0gKCAxICsgTWF0aC5zcXJ0KCA1ICkgKSAvIDI7XHJcblxyXG5cdFx0Y29uc3QgdmVydGljZXMgPSBbXHJcblx0XHRcdC0gMSwgdCwgMCwgXHQxLCB0LCAwLCBcdC0gMSwgLSB0LCAwLCBcdDEsIC0gdCwgMCxcclxuXHRcdFx0MCwgLSAxLCB0LCBcdDAsIDEsIHQsXHQwLCAtIDEsIC0gdCwgXHQwLCAxLCAtIHQsXHJcblx0XHRcdHQsIDAsIC0gMSwgXHR0LCAwLCAxLCBcdC0gdCwgMCwgLSAxLCBcdC0gdCwgMCwgMVxyXG5cdFx0XTtcclxuXHJcblx0XHRjb25zdCBpbmRpY2VzID0gW1xyXG5cdFx0XHQwLCAxMSwgNSwgXHQwLCA1LCAxLCBcdDAsIDEsIDcsIFx0MCwgNywgMTAsIFx0MCwgMTAsIDExLFxyXG5cdFx0XHQxLCA1LCA5LCBcdDUsIDExLCA0LFx0MTEsIDEwLCAyLFx0MTAsIDcsIDYsXHQ3LCAxLCA4LFxyXG5cdFx0XHQzLCA5LCA0LCBcdDMsIDQsIDIsXHQzLCAyLCA2LFx0MywgNiwgOCxcdDMsIDgsIDksXHJcblx0XHRcdDQsIDksIDUsIFx0MiwgNCwgMTEsXHQ2LCAyLCAxMCxcdDgsIDYsIDcsXHQ5LCA4LCAxXHJcblx0XHRdO1xyXG5cclxuXHRcdHN1cGVyKCB2ZXJ0aWNlcywgaW5kaWNlcywgcmFkaXVzLCBkZXRhaWwgKTtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSAnSWNvc2FoZWRyb25HZW9tZXRyeSc7XHJcblxyXG5cdFx0dGhpcy5wYXJhbWV0ZXJzID0ge1xyXG5cdFx0XHRyYWRpdXM6IHJhZGl1cyxcclxuXHRcdFx0ZGV0YWlsOiBkZXRhaWxcclxuXHRcdH07XHJcblxyXG5cdH1cclxuXHJcblx0c3RhdGljIGZyb21KU09OKCBkYXRhICkge1xyXG5cclxuXHRcdHJldHVybiBuZXcgSWNvc2FoZWRyb25HZW9tZXRyeSggZGF0YS5yYWRpdXMsIGRhdGEuZGV0YWlsICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcblxyXG5leHBvcnQgeyBJY29zYWhlZHJvbkdlb21ldHJ5IH07XHJcbiIsImltcG9ydCB7IFBvbHloZWRyb25HZW9tZXRyeSB9IGZyb20gJy4vUG9seWhlZHJvbkdlb21ldHJ5LmpzJztcclxuXHJcbmNsYXNzIE9jdGFoZWRyb25HZW9tZXRyeSBleHRlbmRzIFBvbHloZWRyb25HZW9tZXRyeSB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCByYWRpdXMgPSAxLCBkZXRhaWwgPSAwICkge1xyXG5cclxuXHRcdGNvbnN0IHZlcnRpY2VzID0gW1xyXG5cdFx0XHQxLCAwLCAwLCBcdC0gMSwgMCwgMCxcdDAsIDEsIDAsXHJcblx0XHRcdDAsIC0gMSwgMCwgXHQwLCAwLCAxLFx0MCwgMCwgLSAxXHJcblx0XHRdO1xyXG5cclxuXHRcdGNvbnN0IGluZGljZXMgPSBbXHJcblx0XHRcdDAsIDIsIDQsXHQwLCA0LCAzLFx0MCwgMywgNSxcclxuXHRcdFx0MCwgNSwgMixcdDEsIDIsIDUsXHQxLCA1LCAzLFxyXG5cdFx0XHQxLCAzLCA0LFx0MSwgNCwgMlxyXG5cdFx0XTtcclxuXHJcblx0XHRzdXBlciggdmVydGljZXMsIGluZGljZXMsIHJhZGl1cywgZGV0YWlsICk7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ09jdGFoZWRyb25HZW9tZXRyeSc7XHJcblxyXG5cdFx0dGhpcy5wYXJhbWV0ZXJzID0ge1xyXG5cdFx0XHRyYWRpdXM6IHJhZGl1cyxcclxuXHRcdFx0ZGV0YWlsOiBkZXRhaWxcclxuXHRcdH07XHJcblxyXG5cdH1cclxuXHJcblx0c3RhdGljIGZyb21KU09OKCBkYXRhICkge1xyXG5cclxuXHRcdHJldHVybiBuZXcgT2N0YWhlZHJvbkdlb21ldHJ5KCBkYXRhLnJhZGl1cywgZGF0YS5kZXRhaWwgKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgT2N0YWhlZHJvbkdlb21ldHJ5IH07XHJcbiIsImltcG9ydCB7IEJ1ZmZlckdlb21ldHJ5IH0gZnJvbSAnLi4vY29yZS9CdWZmZXJHZW9tZXRyeS5qcyc7XHJcbmltcG9ydCB7IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUgfSBmcm9tICcuLi9jb3JlL0J1ZmZlckF0dHJpYnV0ZS5qcyc7XHJcbmltcG9ydCB7IFZlY3RvcjIgfSBmcm9tICcuLi9tYXRoL1ZlY3RvcjIuanMnO1xyXG5pbXBvcnQgeyBWZWN0b3IzIH0gZnJvbSAnLi4vbWF0aC9WZWN0b3IzLmpzJztcclxuXHJcbmNsYXNzIFJpbmdHZW9tZXRyeSBleHRlbmRzIEJ1ZmZlckdlb21ldHJ5IHtcclxuXHJcblx0Y29uc3RydWN0b3IoIGlubmVyUmFkaXVzID0gMC41LCBvdXRlclJhZGl1cyA9IDEsIHRoZXRhU2VnbWVudHMgPSAzMiwgcGhpU2VnbWVudHMgPSAxLCB0aGV0YVN0YXJ0ID0gMCwgdGhldGFMZW5ndGggPSBNYXRoLlBJICogMiApIHtcclxuXHJcblx0XHRzdXBlcigpO1xyXG5cclxuXHRcdHRoaXMudHlwZSA9ICdSaW5nR2VvbWV0cnknO1xyXG5cclxuXHRcdHRoaXMucGFyYW1ldGVycyA9IHtcclxuXHRcdFx0aW5uZXJSYWRpdXM6IGlubmVyUmFkaXVzLFxyXG5cdFx0XHRvdXRlclJhZGl1czogb3V0ZXJSYWRpdXMsXHJcblx0XHRcdHRoZXRhU2VnbWVudHM6IHRoZXRhU2VnbWVudHMsXHJcblx0XHRcdHBoaVNlZ21lbnRzOiBwaGlTZWdtZW50cyxcclxuXHRcdFx0dGhldGFTdGFydDogdGhldGFTdGFydCxcclxuXHRcdFx0dGhldGFMZW5ndGg6IHRoZXRhTGVuZ3RoXHJcblx0XHR9O1xyXG5cclxuXHRcdHRoZXRhU2VnbWVudHMgPSBNYXRoLm1heCggMywgdGhldGFTZWdtZW50cyApO1xyXG5cdFx0cGhpU2VnbWVudHMgPSBNYXRoLm1heCggMSwgcGhpU2VnbWVudHMgKTtcclxuXHJcblx0XHQvLyBidWZmZXJzXHJcblxyXG5cdFx0Y29uc3QgaW5kaWNlcyA9IFtdO1xyXG5cdFx0Y29uc3QgdmVydGljZXMgPSBbXTtcclxuXHRcdGNvbnN0IG5vcm1hbHMgPSBbXTtcclxuXHRcdGNvbnN0IHV2cyA9IFtdO1xyXG5cclxuXHRcdC8vIHNvbWUgaGVscGVyIHZhcmlhYmxlc1xyXG5cclxuXHRcdGxldCByYWRpdXMgPSBpbm5lclJhZGl1cztcclxuXHRcdGNvbnN0IHJhZGl1c1N0ZXAgPSAoICggb3V0ZXJSYWRpdXMgLSBpbm5lclJhZGl1cyApIC8gcGhpU2VnbWVudHMgKTtcclxuXHRcdGNvbnN0IHZlcnRleCA9IG5ldyBWZWN0b3IzKCk7XHJcblx0XHRjb25zdCB1diA9IG5ldyBWZWN0b3IyKCk7XHJcblxyXG5cdFx0Ly8gZ2VuZXJhdGUgdmVydGljZXMsIG5vcm1hbHMgYW5kIHV2c1xyXG5cclxuXHRcdGZvciAoIGxldCBqID0gMDsgaiA8PSBwaGlTZWdtZW50czsgaiArKyApIHtcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8PSB0aGV0YVNlZ21lbnRzOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHQvLyB2YWx1ZXMgYXJlIGdlbmVyYXRlIGZyb20gdGhlIGluc2lkZSBvZiB0aGUgcmluZyB0byB0aGUgb3V0c2lkZVxyXG5cclxuXHRcdFx0XHRjb25zdCBzZWdtZW50ID0gdGhldGFTdGFydCArIGkgLyB0aGV0YVNlZ21lbnRzICogdGhldGFMZW5ndGg7XHJcblxyXG5cdFx0XHRcdC8vIHZlcnRleFxyXG5cclxuXHRcdFx0XHR2ZXJ0ZXgueCA9IHJhZGl1cyAqIE1hdGguY29zKCBzZWdtZW50ICk7XHJcblx0XHRcdFx0dmVydGV4LnkgPSByYWRpdXMgKiBNYXRoLnNpbiggc2VnbWVudCApO1xyXG5cclxuXHRcdFx0XHR2ZXJ0aWNlcy5wdXNoKCB2ZXJ0ZXgueCwgdmVydGV4LnksIHZlcnRleC56ICk7XHJcblxyXG5cdFx0XHRcdC8vIG5vcm1hbFxyXG5cclxuXHRcdFx0XHRub3JtYWxzLnB1c2goIDAsIDAsIDEgKTtcclxuXHJcblx0XHRcdFx0Ly8gdXZcclxuXHJcblx0XHRcdFx0dXYueCA9ICggdmVydGV4LnggLyBvdXRlclJhZGl1cyArIDEgKSAvIDI7XHJcblx0XHRcdFx0dXYueSA9ICggdmVydGV4LnkgLyBvdXRlclJhZGl1cyArIDEgKSAvIDI7XHJcblxyXG5cdFx0XHRcdHV2cy5wdXNoKCB1di54LCB1di55ICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyBpbmNyZWFzZSB0aGUgcmFkaXVzIGZvciBuZXh0IHJvdyBvZiB2ZXJ0aWNlc1xyXG5cclxuXHRcdFx0cmFkaXVzICs9IHJhZGl1c1N0ZXA7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIGluZGljZXNcclxuXHJcblx0XHRmb3IgKCBsZXQgaiA9IDA7IGogPCBwaGlTZWdtZW50czsgaiArKyApIHtcclxuXHJcblx0XHRcdGNvbnN0IHRoZXRhU2VnbWVudExldmVsID0gaiAqICggdGhldGFTZWdtZW50cyArIDEgKTtcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHRoZXRhU2VnbWVudHM7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IHNlZ21lbnQgPSBpICsgdGhldGFTZWdtZW50TGV2ZWw7XHJcblxyXG5cdFx0XHRcdGNvbnN0IGEgPSBzZWdtZW50O1xyXG5cdFx0XHRcdGNvbnN0IGIgPSBzZWdtZW50ICsgdGhldGFTZWdtZW50cyArIDE7XHJcblx0XHRcdFx0Y29uc3QgYyA9IHNlZ21lbnQgKyB0aGV0YVNlZ21lbnRzICsgMjtcclxuXHRcdFx0XHRjb25zdCBkID0gc2VnbWVudCArIDE7XHJcblxyXG5cdFx0XHRcdC8vIGZhY2VzXHJcblxyXG5cdFx0XHRcdGluZGljZXMucHVzaCggYSwgYiwgZCApO1xyXG5cdFx0XHRcdGluZGljZXMucHVzaCggYiwgYywgZCApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvLyBidWlsZCBnZW9tZXRyeVxyXG5cclxuXHRcdHRoaXMuc2V0SW5kZXgoIGluZGljZXMgKTtcclxuXHRcdHRoaXMuc2V0QXR0cmlidXRlKCAncG9zaXRpb24nLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggdmVydGljZXMsIDMgKSApO1xyXG5cdFx0dGhpcy5zZXRBdHRyaWJ1dGUoICdub3JtYWwnLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggbm9ybWFscywgMyApICk7XHJcblx0XHR0aGlzLnNldEF0dHJpYnV0ZSggJ3V2JywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIHV2cywgMiApICk7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xyXG5cclxuXHRcdHRoaXMucGFyYW1ldGVycyA9IE9iamVjdC5hc3NpZ24oIHt9LCBzb3VyY2UucGFyYW1ldGVycyApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHN0YXRpYyBmcm9tSlNPTiggZGF0YSApIHtcclxuXHJcblx0XHRyZXR1cm4gbmV3IFJpbmdHZW9tZXRyeSggZGF0YS5pbm5lclJhZGl1cywgZGF0YS5vdXRlclJhZGl1cywgZGF0YS50aGV0YVNlZ21lbnRzLCBkYXRhLnBoaVNlZ21lbnRzLCBkYXRhLnRoZXRhU3RhcnQsIGRhdGEudGhldGFMZW5ndGggKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuXHJcbmV4cG9ydCB7IFJpbmdHZW9tZXRyeSB9O1xyXG4iLCJpbXBvcnQgeyBCdWZmZXJHZW9tZXRyeSB9IGZyb20gJy4uL2NvcmUvQnVmZmVyR2VvbWV0cnkuanMnO1xyXG5pbXBvcnQgeyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlIH0gZnJvbSAnLi4vY29yZS9CdWZmZXJBdHRyaWJ1dGUuanMnO1xyXG5pbXBvcnQgeyBTaGFwZSB9IGZyb20gJy4uL2V4dHJhcy9jb3JlL1NoYXBlLmpzJztcclxuaW1wb3J0IHsgU2hhcGVVdGlscyB9IGZyb20gJy4uL2V4dHJhcy9TaGFwZVV0aWxzLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yMiB9IGZyb20gJy4uL21hdGgvVmVjdG9yMi5qcyc7XHJcblxyXG5jbGFzcyBTaGFwZUdlb21ldHJ5IGV4dGVuZHMgQnVmZmVyR2VvbWV0cnkge1xyXG5cclxuXHRjb25zdHJ1Y3Rvciggc2hhcGVzID0gbmV3IFNoYXBlKCBbIG5ldyBWZWN0b3IyKCAwLCAwLjUgKSwgbmV3IFZlY3RvcjIoIC0gMC41LCAtIDAuNSApLCBuZXcgVmVjdG9yMiggMC41LCAtIDAuNSApIF0gKSwgY3VydmVTZWdtZW50cyA9IDEyICkge1xyXG5cclxuXHRcdHN1cGVyKCk7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ1NoYXBlR2VvbWV0cnknO1xyXG5cclxuXHRcdHRoaXMucGFyYW1ldGVycyA9IHtcclxuXHRcdFx0c2hhcGVzOiBzaGFwZXMsXHJcblx0XHRcdGN1cnZlU2VnbWVudHM6IGN1cnZlU2VnbWVudHNcclxuXHRcdH07XHJcblxyXG5cdFx0Ly8gYnVmZmVyc1xyXG5cclxuXHRcdGNvbnN0IGluZGljZXMgPSBbXTtcclxuXHRcdGNvbnN0IHZlcnRpY2VzID0gW107XHJcblx0XHRjb25zdCBub3JtYWxzID0gW107XHJcblx0XHRjb25zdCB1dnMgPSBbXTtcclxuXHJcblx0XHQvLyBoZWxwZXIgdmFyaWFibGVzXHJcblxyXG5cdFx0bGV0IGdyb3VwU3RhcnQgPSAwO1xyXG5cdFx0bGV0IGdyb3VwQ291bnQgPSAwO1xyXG5cclxuXHRcdC8vIGFsbG93IHNpbmdsZSBhbmQgYXJyYXkgdmFsdWVzIGZvciBcInNoYXBlc1wiIHBhcmFtZXRlclxyXG5cclxuXHRcdGlmICggQXJyYXkuaXNBcnJheSggc2hhcGVzICkgPT09IGZhbHNlICkge1xyXG5cclxuXHRcdFx0YWRkU2hhcGUoIHNoYXBlcyApO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBzaGFwZXMubGVuZ3RoOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRhZGRTaGFwZSggc2hhcGVzWyBpIF0gKTtcclxuXHJcblx0XHRcdFx0dGhpcy5hZGRHcm91cCggZ3JvdXBTdGFydCwgZ3JvdXBDb3VudCwgaSApOyAvLyBlbmFibGVzIE11bHRpTWF0ZXJpYWwgc3VwcG9ydFxyXG5cclxuXHRcdFx0XHRncm91cFN0YXJ0ICs9IGdyb3VwQ291bnQ7XHJcblx0XHRcdFx0Z3JvdXBDb3VudCA9IDA7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIGJ1aWxkIGdlb21ldHJ5XHJcblxyXG5cdFx0dGhpcy5zZXRJbmRleCggaW5kaWNlcyApO1xyXG5cdFx0dGhpcy5zZXRBdHRyaWJ1dGUoICdwb3NpdGlvbicsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCB2ZXJ0aWNlcywgMyApICk7XHJcblx0XHR0aGlzLnNldEF0dHJpYnV0ZSggJ25vcm1hbCcsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCBub3JtYWxzLCAzICkgKTtcclxuXHRcdHRoaXMuc2V0QXR0cmlidXRlKCAndXYnLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggdXZzLCAyICkgKTtcclxuXHJcblxyXG5cdFx0Ly8gaGVscGVyIGZ1bmN0aW9uc1xyXG5cclxuXHRcdGZ1bmN0aW9uIGFkZFNoYXBlKCBzaGFwZSApIHtcclxuXHJcblx0XHRcdGNvbnN0IGluZGV4T2Zmc2V0ID0gdmVydGljZXMubGVuZ3RoIC8gMztcclxuXHRcdFx0Y29uc3QgcG9pbnRzID0gc2hhcGUuZXh0cmFjdFBvaW50cyggY3VydmVTZWdtZW50cyApO1xyXG5cclxuXHRcdFx0bGV0IHNoYXBlVmVydGljZXMgPSBwb2ludHMuc2hhcGU7XHJcblx0XHRcdGNvbnN0IHNoYXBlSG9sZXMgPSBwb2ludHMuaG9sZXM7XHJcblxyXG5cdFx0XHQvLyBjaGVjayBkaXJlY3Rpb24gb2YgdmVydGljZXNcclxuXHJcblx0XHRcdGlmICggU2hhcGVVdGlscy5pc0Nsb2NrV2lzZSggc2hhcGVWZXJ0aWNlcyApID09PSBmYWxzZSApIHtcclxuXHJcblx0XHRcdFx0c2hhcGVWZXJ0aWNlcyA9IHNoYXBlVmVydGljZXMucmV2ZXJzZSgpO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gc2hhcGVIb2xlcy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBzaGFwZUhvbGUgPSBzaGFwZUhvbGVzWyBpIF07XHJcblxyXG5cdFx0XHRcdGlmICggU2hhcGVVdGlscy5pc0Nsb2NrV2lzZSggc2hhcGVIb2xlICkgPT09IHRydWUgKSB7XHJcblxyXG5cdFx0XHRcdFx0c2hhcGVIb2xlc1sgaSBdID0gc2hhcGVIb2xlLnJldmVyc2UoKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Y29uc3QgZmFjZXMgPSBTaGFwZVV0aWxzLnRyaWFuZ3VsYXRlU2hhcGUoIHNoYXBlVmVydGljZXMsIHNoYXBlSG9sZXMgKTtcclxuXHJcblx0XHRcdC8vIGpvaW4gdmVydGljZXMgb2YgaW5uZXIgYW5kIG91dGVyIHBhdGhzIHRvIGEgc2luZ2xlIGFycmF5XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBzaGFwZUhvbGVzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IHNoYXBlSG9sZSA9IHNoYXBlSG9sZXNbIGkgXTtcclxuXHRcdFx0XHRzaGFwZVZlcnRpY2VzID0gc2hhcGVWZXJ0aWNlcy5jb25jYXQoIHNoYXBlSG9sZSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Ly8gdmVydGljZXMsIG5vcm1hbHMsIHV2c1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gc2hhcGVWZXJ0aWNlcy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCB2ZXJ0ZXggPSBzaGFwZVZlcnRpY2VzWyBpIF07XHJcblxyXG5cdFx0XHRcdHZlcnRpY2VzLnB1c2goIHZlcnRleC54LCB2ZXJ0ZXgueSwgMCApO1xyXG5cdFx0XHRcdG5vcm1hbHMucHVzaCggMCwgMCwgMSApO1xyXG5cdFx0XHRcdHV2cy5wdXNoKCB2ZXJ0ZXgueCwgdmVydGV4LnkgKTsgLy8gd29ybGQgdXZzXHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyBpbmRpY2VzXHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBmYWNlcy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBmYWNlID0gZmFjZXNbIGkgXTtcclxuXHJcblx0XHRcdFx0Y29uc3QgYSA9IGZhY2VbIDAgXSArIGluZGV4T2Zmc2V0O1xyXG5cdFx0XHRcdGNvbnN0IGIgPSBmYWNlWyAxIF0gKyBpbmRleE9mZnNldDtcclxuXHRcdFx0XHRjb25zdCBjID0gZmFjZVsgMiBdICsgaW5kZXhPZmZzZXQ7XHJcblxyXG5cdFx0XHRcdGluZGljZXMucHVzaCggYSwgYiwgYyApO1xyXG5cdFx0XHRcdGdyb3VwQ291bnQgKz0gMztcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xyXG5cclxuXHRcdHRoaXMucGFyYW1ldGVycyA9IE9iamVjdC5hc3NpZ24oIHt9LCBzb3VyY2UucGFyYW1ldGVycyApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHRvSlNPTigpIHtcclxuXHJcblx0XHRjb25zdCBkYXRhID0gc3VwZXIudG9KU09OKCk7XHJcblxyXG5cdFx0Y29uc3Qgc2hhcGVzID0gdGhpcy5wYXJhbWV0ZXJzLnNoYXBlcztcclxuXHJcblx0XHRyZXR1cm4gdG9KU09OKCBzaGFwZXMsIGRhdGEgKTtcclxuXHJcblx0fVxyXG5cclxuXHRzdGF0aWMgZnJvbUpTT04oIGRhdGEsIHNoYXBlcyApIHtcclxuXHJcblx0XHRjb25zdCBnZW9tZXRyeVNoYXBlcyA9IFtdO1xyXG5cclxuXHRcdGZvciAoIGxldCBqID0gMCwgamwgPSBkYXRhLnNoYXBlcy5sZW5ndGg7IGogPCBqbDsgaiArKyApIHtcclxuXHJcblx0XHRcdGNvbnN0IHNoYXBlID0gc2hhcGVzWyBkYXRhLnNoYXBlc1sgaiBdIF07XHJcblxyXG5cdFx0XHRnZW9tZXRyeVNoYXBlcy5wdXNoKCBzaGFwZSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gbmV3IFNoYXBlR2VvbWV0cnkoIGdlb21ldHJ5U2hhcGVzLCBkYXRhLmN1cnZlU2VnbWVudHMgKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gdG9KU09OKCBzaGFwZXMsIGRhdGEgKSB7XHJcblxyXG5cdGRhdGEuc2hhcGVzID0gW107XHJcblxyXG5cdGlmICggQXJyYXkuaXNBcnJheSggc2hhcGVzICkgKSB7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gc2hhcGVzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBzaGFwZSA9IHNoYXBlc1sgaSBdO1xyXG5cclxuXHRcdFx0ZGF0YS5zaGFwZXMucHVzaCggc2hhcGUudXVpZCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fSBlbHNlIHtcclxuXHJcblx0XHRkYXRhLnNoYXBlcy5wdXNoKCBzaGFwZXMudXVpZCApO1xyXG5cclxuXHR9XHJcblxyXG5cdHJldHVybiBkYXRhO1xyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgU2hhcGVHZW9tZXRyeSB9O1xyXG4iLCJpbXBvcnQgeyBCdWZmZXJHZW9tZXRyeSB9IGZyb20gJy4uL2NvcmUvQnVmZmVyR2VvbWV0cnkuanMnO1xyXG5pbXBvcnQgeyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlIH0gZnJvbSAnLi4vY29yZS9CdWZmZXJBdHRyaWJ1dGUuanMnO1xyXG5pbXBvcnQgeyBWZWN0b3IzIH0gZnJvbSAnLi4vbWF0aC9WZWN0b3IzLmpzJztcclxuXHJcbmNsYXNzIFNwaGVyZUdlb21ldHJ5IGV4dGVuZHMgQnVmZmVyR2VvbWV0cnkge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggcmFkaXVzID0gMSwgd2lkdGhTZWdtZW50cyA9IDMyLCBoZWlnaHRTZWdtZW50cyA9IDE2LCBwaGlTdGFydCA9IDAsIHBoaUxlbmd0aCA9IE1hdGguUEkgKiAyLCB0aGV0YVN0YXJ0ID0gMCwgdGhldGFMZW5ndGggPSBNYXRoLlBJICkge1xyXG5cclxuXHRcdHN1cGVyKCk7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ1NwaGVyZUdlb21ldHJ5JztcclxuXHJcblx0XHR0aGlzLnBhcmFtZXRlcnMgPSB7XHJcblx0XHRcdHJhZGl1czogcmFkaXVzLFxyXG5cdFx0XHR3aWR0aFNlZ21lbnRzOiB3aWR0aFNlZ21lbnRzLFxyXG5cdFx0XHRoZWlnaHRTZWdtZW50czogaGVpZ2h0U2VnbWVudHMsXHJcblx0XHRcdHBoaVN0YXJ0OiBwaGlTdGFydCxcclxuXHRcdFx0cGhpTGVuZ3RoOiBwaGlMZW5ndGgsXHJcblx0XHRcdHRoZXRhU3RhcnQ6IHRoZXRhU3RhcnQsXHJcblx0XHRcdHRoZXRhTGVuZ3RoOiB0aGV0YUxlbmd0aFxyXG5cdFx0fTtcclxuXHJcblx0XHR3aWR0aFNlZ21lbnRzID0gTWF0aC5tYXgoIDMsIE1hdGguZmxvb3IoIHdpZHRoU2VnbWVudHMgKSApO1xyXG5cdFx0aGVpZ2h0U2VnbWVudHMgPSBNYXRoLm1heCggMiwgTWF0aC5mbG9vciggaGVpZ2h0U2VnbWVudHMgKSApO1xyXG5cclxuXHRcdGNvbnN0IHRoZXRhRW5kID0gTWF0aC5taW4oIHRoZXRhU3RhcnQgKyB0aGV0YUxlbmd0aCwgTWF0aC5QSSApO1xyXG5cclxuXHRcdGxldCBpbmRleCA9IDA7XHJcblx0XHRjb25zdCBncmlkID0gW107XHJcblxyXG5cdFx0Y29uc3QgdmVydGV4ID0gbmV3IFZlY3RvcjMoKTtcclxuXHRcdGNvbnN0IG5vcm1hbCA9IG5ldyBWZWN0b3IzKCk7XHJcblxyXG5cdFx0Ly8gYnVmZmVyc1xyXG5cclxuXHRcdGNvbnN0IGluZGljZXMgPSBbXTtcclxuXHRcdGNvbnN0IHZlcnRpY2VzID0gW107XHJcblx0XHRjb25zdCBub3JtYWxzID0gW107XHJcblx0XHRjb25zdCB1dnMgPSBbXTtcclxuXHJcblx0XHQvLyBnZW5lcmF0ZSB2ZXJ0aWNlcywgbm9ybWFscyBhbmQgdXZzXHJcblxyXG5cdFx0Zm9yICggbGV0IGl5ID0gMDsgaXkgPD0gaGVpZ2h0U2VnbWVudHM7IGl5ICsrICkge1xyXG5cclxuXHRcdFx0Y29uc3QgdmVydGljZXNSb3cgPSBbXTtcclxuXHJcblx0XHRcdGNvbnN0IHYgPSBpeSAvIGhlaWdodFNlZ21lbnRzO1xyXG5cclxuXHRcdFx0Ly8gc3BlY2lhbCBjYXNlIGZvciB0aGUgcG9sZXNcclxuXHJcblx0XHRcdGxldCB1T2Zmc2V0ID0gMDtcclxuXHJcblx0XHRcdGlmICggaXkgPT09IDAgJiYgdGhldGFTdGFydCA9PT0gMCApIHtcclxuXHJcblx0XHRcdFx0dU9mZnNldCA9IDAuNSAvIHdpZHRoU2VnbWVudHM7XHJcblxyXG5cdFx0XHR9IGVsc2UgaWYgKCBpeSA9PT0gaGVpZ2h0U2VnbWVudHMgJiYgdGhldGFFbmQgPT09IE1hdGguUEkgKSB7XHJcblxyXG5cdFx0XHRcdHVPZmZzZXQgPSAtIDAuNSAvIHdpZHRoU2VnbWVudHM7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaXggPSAwOyBpeCA8PSB3aWR0aFNlZ21lbnRzOyBpeCArKyApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgdSA9IGl4IC8gd2lkdGhTZWdtZW50cztcclxuXHJcblx0XHRcdFx0Ly8gdmVydGV4XHJcblxyXG5cdFx0XHRcdHZlcnRleC54ID0gLSByYWRpdXMgKiBNYXRoLmNvcyggcGhpU3RhcnQgKyB1ICogcGhpTGVuZ3RoICkgKiBNYXRoLnNpbiggdGhldGFTdGFydCArIHYgKiB0aGV0YUxlbmd0aCApO1xyXG5cdFx0XHRcdHZlcnRleC55ID0gcmFkaXVzICogTWF0aC5jb3MoIHRoZXRhU3RhcnQgKyB2ICogdGhldGFMZW5ndGggKTtcclxuXHRcdFx0XHR2ZXJ0ZXgueiA9IHJhZGl1cyAqIE1hdGguc2luKCBwaGlTdGFydCArIHUgKiBwaGlMZW5ndGggKSAqIE1hdGguc2luKCB0aGV0YVN0YXJ0ICsgdiAqIHRoZXRhTGVuZ3RoICk7XHJcblxyXG5cdFx0XHRcdHZlcnRpY2VzLnB1c2goIHZlcnRleC54LCB2ZXJ0ZXgueSwgdmVydGV4LnogKTtcclxuXHJcblx0XHRcdFx0Ly8gbm9ybWFsXHJcblxyXG5cdFx0XHRcdG5vcm1hbC5jb3B5KCB2ZXJ0ZXggKS5ub3JtYWxpemUoKTtcclxuXHRcdFx0XHRub3JtYWxzLnB1c2goIG5vcm1hbC54LCBub3JtYWwueSwgbm9ybWFsLnogKTtcclxuXHJcblx0XHRcdFx0Ly8gdXZcclxuXHJcblx0XHRcdFx0dXZzLnB1c2goIHUgKyB1T2Zmc2V0LCAxIC0gdiApO1xyXG5cclxuXHRcdFx0XHR2ZXJ0aWNlc1Jvdy5wdXNoKCBpbmRleCArKyApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Z3JpZC5wdXNoKCB2ZXJ0aWNlc1JvdyApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvLyBpbmRpY2VzXHJcblxyXG5cdFx0Zm9yICggbGV0IGl5ID0gMDsgaXkgPCBoZWlnaHRTZWdtZW50czsgaXkgKysgKSB7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaXggPSAwOyBpeCA8IHdpZHRoU2VnbWVudHM7IGl4ICsrICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBhID0gZ3JpZFsgaXkgXVsgaXggKyAxIF07XHJcblx0XHRcdFx0Y29uc3QgYiA9IGdyaWRbIGl5IF1bIGl4IF07XHJcblx0XHRcdFx0Y29uc3QgYyA9IGdyaWRbIGl5ICsgMSBdWyBpeCBdO1xyXG5cdFx0XHRcdGNvbnN0IGQgPSBncmlkWyBpeSArIDEgXVsgaXggKyAxIF07XHJcblxyXG5cdFx0XHRcdGlmICggaXkgIT09IDAgfHwgdGhldGFTdGFydCA+IDAgKSBpbmRpY2VzLnB1c2goIGEsIGIsIGQgKTtcclxuXHRcdFx0XHRpZiAoIGl5ICE9PSBoZWlnaHRTZWdtZW50cyAtIDEgfHwgdGhldGFFbmQgPCBNYXRoLlBJICkgaW5kaWNlcy5wdXNoKCBiLCBjLCBkICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIGJ1aWxkIGdlb21ldHJ5XHJcblxyXG5cdFx0dGhpcy5zZXRJbmRleCggaW5kaWNlcyApO1xyXG5cdFx0dGhpcy5zZXRBdHRyaWJ1dGUoICdwb3NpdGlvbicsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCB2ZXJ0aWNlcywgMyApICk7XHJcblx0XHR0aGlzLnNldEF0dHJpYnV0ZSggJ25vcm1hbCcsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCBub3JtYWxzLCAzICkgKTtcclxuXHRcdHRoaXMuc2V0QXR0cmlidXRlKCAndXYnLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggdXZzLCAyICkgKTtcclxuXHJcblx0fVxyXG5cclxuXHRjb3B5KCBzb3VyY2UgKSB7XHJcblxyXG5cdFx0c3VwZXIuY29weSggc291cmNlICk7XHJcblxyXG5cdFx0dGhpcy5wYXJhbWV0ZXJzID0gT2JqZWN0LmFzc2lnbigge30sIHNvdXJjZS5wYXJhbWV0ZXJzICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0c3RhdGljIGZyb21KU09OKCBkYXRhICkge1xyXG5cclxuXHRcdHJldHVybiBuZXcgU3BoZXJlR2VvbWV0cnkoIGRhdGEucmFkaXVzLCBkYXRhLndpZHRoU2VnbWVudHMsIGRhdGEuaGVpZ2h0U2VnbWVudHMsIGRhdGEucGhpU3RhcnQsIGRhdGEucGhpTGVuZ3RoLCBkYXRhLnRoZXRhU3RhcnQsIGRhdGEudGhldGFMZW5ndGggKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgU3BoZXJlR2VvbWV0cnkgfTtcclxuIiwiaW1wb3J0IHsgUG9seWhlZHJvbkdlb21ldHJ5IH0gZnJvbSAnLi9Qb2x5aGVkcm9uR2VvbWV0cnkuanMnO1xyXG5cclxuY2xhc3MgVGV0cmFoZWRyb25HZW9tZXRyeSBleHRlbmRzIFBvbHloZWRyb25HZW9tZXRyeSB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCByYWRpdXMgPSAxLCBkZXRhaWwgPSAwICkge1xyXG5cclxuXHRcdGNvbnN0IHZlcnRpY2VzID0gW1xyXG5cdFx0XHQxLCAxLCAxLCBcdC0gMSwgLSAxLCAxLCBcdC0gMSwgMSwgLSAxLCBcdDEsIC0gMSwgLSAxXHJcblx0XHRdO1xyXG5cclxuXHRcdGNvbnN0IGluZGljZXMgPSBbXHJcblx0XHRcdDIsIDEsIDAsIFx0MCwgMywgMixcdDEsIDMsIDAsXHQyLCAzLCAxXHJcblx0XHRdO1xyXG5cclxuXHRcdHN1cGVyKCB2ZXJ0aWNlcywgaW5kaWNlcywgcmFkaXVzLCBkZXRhaWwgKTtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSAnVGV0cmFoZWRyb25HZW9tZXRyeSc7XHJcblxyXG5cdFx0dGhpcy5wYXJhbWV0ZXJzID0ge1xyXG5cdFx0XHRyYWRpdXM6IHJhZGl1cyxcclxuXHRcdFx0ZGV0YWlsOiBkZXRhaWxcclxuXHRcdH07XHJcblxyXG5cdH1cclxuXHJcblx0c3RhdGljIGZyb21KU09OKCBkYXRhICkge1xyXG5cclxuXHRcdHJldHVybiBuZXcgVGV0cmFoZWRyb25HZW9tZXRyeSggZGF0YS5yYWRpdXMsIGRhdGEuZGV0YWlsICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IFRldHJhaGVkcm9uR2VvbWV0cnkgfTtcclxuIiwiaW1wb3J0IHsgQnVmZmVyR2VvbWV0cnkgfSBmcm9tICcuLi9jb3JlL0J1ZmZlckdlb21ldHJ5LmpzJztcclxuaW1wb3J0IHsgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSB9IGZyb20gJy4uL2NvcmUvQnVmZmVyQXR0cmlidXRlLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yMyB9IGZyb20gJy4uL21hdGgvVmVjdG9yMy5qcyc7XHJcblxyXG5jbGFzcyBUb3J1c0dlb21ldHJ5IGV4dGVuZHMgQnVmZmVyR2VvbWV0cnkge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggcmFkaXVzID0gMSwgdHViZSA9IDAuNCwgcmFkaWFsU2VnbWVudHMgPSAxMiwgdHVidWxhclNlZ21lbnRzID0gNDgsIGFyYyA9IE1hdGguUEkgKiAyICkge1xyXG5cclxuXHRcdHN1cGVyKCk7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ1RvcnVzR2VvbWV0cnknO1xyXG5cclxuXHRcdHRoaXMucGFyYW1ldGVycyA9IHtcclxuXHRcdFx0cmFkaXVzOiByYWRpdXMsXHJcblx0XHRcdHR1YmU6IHR1YmUsXHJcblx0XHRcdHJhZGlhbFNlZ21lbnRzOiByYWRpYWxTZWdtZW50cyxcclxuXHRcdFx0dHVidWxhclNlZ21lbnRzOiB0dWJ1bGFyU2VnbWVudHMsXHJcblx0XHRcdGFyYzogYXJjXHJcblx0XHR9O1xyXG5cclxuXHRcdHJhZGlhbFNlZ21lbnRzID0gTWF0aC5mbG9vciggcmFkaWFsU2VnbWVudHMgKTtcclxuXHRcdHR1YnVsYXJTZWdtZW50cyA9IE1hdGguZmxvb3IoIHR1YnVsYXJTZWdtZW50cyApO1xyXG5cclxuXHRcdC8vIGJ1ZmZlcnNcclxuXHJcblx0XHRjb25zdCBpbmRpY2VzID0gW107XHJcblx0XHRjb25zdCB2ZXJ0aWNlcyA9IFtdO1xyXG5cdFx0Y29uc3Qgbm9ybWFscyA9IFtdO1xyXG5cdFx0Y29uc3QgdXZzID0gW107XHJcblxyXG5cdFx0Ly8gaGVscGVyIHZhcmlhYmxlc1xyXG5cclxuXHRcdGNvbnN0IGNlbnRlciA9IG5ldyBWZWN0b3IzKCk7XHJcblx0XHRjb25zdCB2ZXJ0ZXggPSBuZXcgVmVjdG9yMygpO1xyXG5cdFx0Y29uc3Qgbm9ybWFsID0gbmV3IFZlY3RvcjMoKTtcclxuXHJcblx0XHQvLyBnZW5lcmF0ZSB2ZXJ0aWNlcywgbm9ybWFscyBhbmQgdXZzXHJcblxyXG5cdFx0Zm9yICggbGV0IGogPSAwOyBqIDw9IHJhZGlhbFNlZ21lbnRzOyBqICsrICkge1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDw9IHR1YnVsYXJTZWdtZW50czsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgdSA9IGkgLyB0dWJ1bGFyU2VnbWVudHMgKiBhcmM7XHJcblx0XHRcdFx0Y29uc3QgdiA9IGogLyByYWRpYWxTZWdtZW50cyAqIE1hdGguUEkgKiAyO1xyXG5cclxuXHRcdFx0XHQvLyB2ZXJ0ZXhcclxuXHJcblx0XHRcdFx0dmVydGV4LnggPSAoIHJhZGl1cyArIHR1YmUgKiBNYXRoLmNvcyggdiApICkgKiBNYXRoLmNvcyggdSApO1xyXG5cdFx0XHRcdHZlcnRleC55ID0gKCByYWRpdXMgKyB0dWJlICogTWF0aC5jb3MoIHYgKSApICogTWF0aC5zaW4oIHUgKTtcclxuXHRcdFx0XHR2ZXJ0ZXgueiA9IHR1YmUgKiBNYXRoLnNpbiggdiApO1xyXG5cclxuXHRcdFx0XHR2ZXJ0aWNlcy5wdXNoKCB2ZXJ0ZXgueCwgdmVydGV4LnksIHZlcnRleC56ICk7XHJcblxyXG5cdFx0XHRcdC8vIG5vcm1hbFxyXG5cclxuXHRcdFx0XHRjZW50ZXIueCA9IHJhZGl1cyAqIE1hdGguY29zKCB1ICk7XHJcblx0XHRcdFx0Y2VudGVyLnkgPSByYWRpdXMgKiBNYXRoLnNpbiggdSApO1xyXG5cdFx0XHRcdG5vcm1hbC5zdWJWZWN0b3JzKCB2ZXJ0ZXgsIGNlbnRlciApLm5vcm1hbGl6ZSgpO1xyXG5cclxuXHRcdFx0XHRub3JtYWxzLnB1c2goIG5vcm1hbC54LCBub3JtYWwueSwgbm9ybWFsLnogKTtcclxuXHJcblx0XHRcdFx0Ly8gdXZcclxuXHJcblx0XHRcdFx0dXZzLnB1c2goIGkgLyB0dWJ1bGFyU2VnbWVudHMgKTtcclxuXHRcdFx0XHR1dnMucHVzaCggaiAvIHJhZGlhbFNlZ21lbnRzICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIGdlbmVyYXRlIGluZGljZXNcclxuXHJcblx0XHRmb3IgKCBsZXQgaiA9IDE7IGogPD0gcmFkaWFsU2VnbWVudHM7IGogKysgKSB7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDE7IGkgPD0gdHVidWxhclNlZ21lbnRzOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHQvLyBpbmRpY2VzXHJcblxyXG5cdFx0XHRcdGNvbnN0IGEgPSAoIHR1YnVsYXJTZWdtZW50cyArIDEgKSAqIGogKyBpIC0gMTtcclxuXHRcdFx0XHRjb25zdCBiID0gKCB0dWJ1bGFyU2VnbWVudHMgKyAxICkgKiAoIGogLSAxICkgKyBpIC0gMTtcclxuXHRcdFx0XHRjb25zdCBjID0gKCB0dWJ1bGFyU2VnbWVudHMgKyAxICkgKiAoIGogLSAxICkgKyBpO1xyXG5cdFx0XHRcdGNvbnN0IGQgPSAoIHR1YnVsYXJTZWdtZW50cyArIDEgKSAqIGogKyBpO1xyXG5cclxuXHRcdFx0XHQvLyBmYWNlc1xyXG5cclxuXHRcdFx0XHRpbmRpY2VzLnB1c2goIGEsIGIsIGQgKTtcclxuXHRcdFx0XHRpbmRpY2VzLnB1c2goIGIsIGMsIGQgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gYnVpbGQgZ2VvbWV0cnlcclxuXHJcblx0XHR0aGlzLnNldEluZGV4KCBpbmRpY2VzICk7XHJcblx0XHR0aGlzLnNldEF0dHJpYnV0ZSggJ3Bvc2l0aW9uJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIHZlcnRpY2VzLCAzICkgKTtcclxuXHRcdHRoaXMuc2V0QXR0cmlidXRlKCAnbm9ybWFsJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIG5vcm1hbHMsIDMgKSApO1xyXG5cdFx0dGhpcy5zZXRBdHRyaWJ1dGUoICd1dicsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCB1dnMsIDIgKSApO1xyXG5cclxuXHR9XHJcblxyXG5cdGNvcHkoIHNvdXJjZSApIHtcclxuXHJcblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcclxuXHJcblx0XHR0aGlzLnBhcmFtZXRlcnMgPSBPYmplY3QuYXNzaWduKCB7fSwgc291cmNlLnBhcmFtZXRlcnMgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzdGF0aWMgZnJvbUpTT04oIGRhdGEgKSB7XHJcblxyXG5cdFx0cmV0dXJuIG5ldyBUb3J1c0dlb21ldHJ5KCBkYXRhLnJhZGl1cywgZGF0YS50dWJlLCBkYXRhLnJhZGlhbFNlZ21lbnRzLCBkYXRhLnR1YnVsYXJTZWdtZW50cywgZGF0YS5hcmMgKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgVG9ydXNHZW9tZXRyeSB9O1xyXG4iLCJpbXBvcnQgeyBCdWZmZXJHZW9tZXRyeSB9IGZyb20gJy4uL2NvcmUvQnVmZmVyR2VvbWV0cnkuanMnO1xyXG5pbXBvcnQgeyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlIH0gZnJvbSAnLi4vY29yZS9CdWZmZXJBdHRyaWJ1dGUuanMnO1xyXG5pbXBvcnQgeyBWZWN0b3IzIH0gZnJvbSAnLi4vbWF0aC9WZWN0b3IzLmpzJztcclxuXHJcbmNsYXNzIFRvcnVzS25vdEdlb21ldHJ5IGV4dGVuZHMgQnVmZmVyR2VvbWV0cnkge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggcmFkaXVzID0gMSwgdHViZSA9IDAuNCwgdHVidWxhclNlZ21lbnRzID0gNjQsIHJhZGlhbFNlZ21lbnRzID0gOCwgcCA9IDIsIHEgPSAzICkge1xyXG5cclxuXHRcdHN1cGVyKCk7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ1RvcnVzS25vdEdlb21ldHJ5JztcclxuXHJcblx0XHR0aGlzLnBhcmFtZXRlcnMgPSB7XHJcblx0XHRcdHJhZGl1czogcmFkaXVzLFxyXG5cdFx0XHR0dWJlOiB0dWJlLFxyXG5cdFx0XHR0dWJ1bGFyU2VnbWVudHM6IHR1YnVsYXJTZWdtZW50cyxcclxuXHRcdFx0cmFkaWFsU2VnbWVudHM6IHJhZGlhbFNlZ21lbnRzLFxyXG5cdFx0XHRwOiBwLFxyXG5cdFx0XHRxOiBxXHJcblx0XHR9O1xyXG5cclxuXHRcdHR1YnVsYXJTZWdtZW50cyA9IE1hdGguZmxvb3IoIHR1YnVsYXJTZWdtZW50cyApO1xyXG5cdFx0cmFkaWFsU2VnbWVudHMgPSBNYXRoLmZsb29yKCByYWRpYWxTZWdtZW50cyApO1xyXG5cclxuXHRcdC8vIGJ1ZmZlcnNcclxuXHJcblx0XHRjb25zdCBpbmRpY2VzID0gW107XHJcblx0XHRjb25zdCB2ZXJ0aWNlcyA9IFtdO1xyXG5cdFx0Y29uc3Qgbm9ybWFscyA9IFtdO1xyXG5cdFx0Y29uc3QgdXZzID0gW107XHJcblxyXG5cdFx0Ly8gaGVscGVyIHZhcmlhYmxlc1xyXG5cclxuXHRcdGNvbnN0IHZlcnRleCA9IG5ldyBWZWN0b3IzKCk7XHJcblx0XHRjb25zdCBub3JtYWwgPSBuZXcgVmVjdG9yMygpO1xyXG5cclxuXHRcdGNvbnN0IFAxID0gbmV3IFZlY3RvcjMoKTtcclxuXHRcdGNvbnN0IFAyID0gbmV3IFZlY3RvcjMoKTtcclxuXHJcblx0XHRjb25zdCBCID0gbmV3IFZlY3RvcjMoKTtcclxuXHRcdGNvbnN0IFQgPSBuZXcgVmVjdG9yMygpO1xyXG5cdFx0Y29uc3QgTiA9IG5ldyBWZWN0b3IzKCk7XHJcblxyXG5cdFx0Ly8gZ2VuZXJhdGUgdmVydGljZXMsIG5vcm1hbHMgYW5kIHV2c1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8PSB0dWJ1bGFyU2VnbWVudHM7ICsrIGkgKSB7XHJcblxyXG5cdFx0XHQvLyB0aGUgcmFkaWFuIFwidVwiIGlzIHVzZWQgdG8gY2FsY3VsYXRlIHRoZSBwb3NpdGlvbiBvbiB0aGUgdG9ydXMgY3VydmUgb2YgdGhlIGN1cnJlbnQgdHVidWxhciBzZWdtZW50XHJcblxyXG5cdFx0XHRjb25zdCB1ID0gaSAvIHR1YnVsYXJTZWdtZW50cyAqIHAgKiBNYXRoLlBJICogMjtcclxuXHJcblx0XHRcdC8vIG5vdyB3ZSBjYWxjdWxhdGUgdHdvIHBvaW50cy4gUDEgaXMgb3VyIGN1cnJlbnQgcG9zaXRpb24gb24gdGhlIGN1cnZlLCBQMiBpcyBhIGxpdHRsZSBmYXJ0aGVyIGFoZWFkLlxyXG5cdFx0XHQvLyB0aGVzZSBwb2ludHMgYXJlIHVzZWQgdG8gY3JlYXRlIGEgc3BlY2lhbCBcImNvb3JkaW5hdGUgc3BhY2VcIiwgd2hpY2ggaXMgbmVjZXNzYXJ5IHRvIGNhbGN1bGF0ZSB0aGUgY29ycmVjdCB2ZXJ0ZXggcG9zaXRpb25zXHJcblxyXG5cdFx0XHRjYWxjdWxhdGVQb3NpdGlvbk9uQ3VydmUoIHUsIHAsIHEsIHJhZGl1cywgUDEgKTtcclxuXHRcdFx0Y2FsY3VsYXRlUG9zaXRpb25PbkN1cnZlKCB1ICsgMC4wMSwgcCwgcSwgcmFkaXVzLCBQMiApO1xyXG5cclxuXHRcdFx0Ly8gY2FsY3VsYXRlIG9ydGhvbm9ybWFsIGJhc2lzXHJcblxyXG5cdFx0XHRULnN1YlZlY3RvcnMoIFAyLCBQMSApO1xyXG5cdFx0XHROLmFkZFZlY3RvcnMoIFAyLCBQMSApO1xyXG5cdFx0XHRCLmNyb3NzVmVjdG9ycyggVCwgTiApO1xyXG5cdFx0XHROLmNyb3NzVmVjdG9ycyggQiwgVCApO1xyXG5cclxuXHRcdFx0Ly8gbm9ybWFsaXplIEIsIE4uIFQgY2FuIGJlIGlnbm9yZWQsIHdlIGRvbid0IHVzZSBpdFxyXG5cclxuXHRcdFx0Qi5ub3JtYWxpemUoKTtcclxuXHRcdFx0Ti5ub3JtYWxpemUoKTtcclxuXHJcblx0XHRcdGZvciAoIGxldCBqID0gMDsgaiA8PSByYWRpYWxTZWdtZW50czsgKysgaiApIHtcclxuXHJcblx0XHRcdFx0Ly8gbm93IGNhbGN1bGF0ZSB0aGUgdmVydGljZXMuIHRoZXkgYXJlIG5vdGhpbmcgbW9yZSB0aGFuIGFuIGV4dHJ1c2lvbiBvZiB0aGUgdG9ydXMgY3VydmUuXHJcblx0XHRcdFx0Ly8gYmVjYXVzZSB3ZSBleHRydWRlIGEgc2hhcGUgaW4gdGhlIHh5LXBsYW5lLCB0aGVyZSBpcyBubyBuZWVkIHRvIGNhbGN1bGF0ZSBhIHotdmFsdWUuXHJcblxyXG5cdFx0XHRcdGNvbnN0IHYgPSBqIC8gcmFkaWFsU2VnbWVudHMgKiBNYXRoLlBJICogMjtcclxuXHRcdFx0XHRjb25zdCBjeCA9IC0gdHViZSAqIE1hdGguY29zKCB2ICk7XHJcblx0XHRcdFx0Y29uc3QgY3kgPSB0dWJlICogTWF0aC5zaW4oIHYgKTtcclxuXHJcblx0XHRcdFx0Ly8gbm93IGNhbGN1bGF0ZSB0aGUgZmluYWwgdmVydGV4IHBvc2l0aW9uLlxyXG5cdFx0XHRcdC8vIGZpcnN0IHdlIG9yaWVudCB0aGUgZXh0cnVzaW9uIHdpdGggb3VyIGJhc2lzIHZlY3RvcnMsIHRoZW4gd2UgYWRkIGl0IHRvIHRoZSBjdXJyZW50IHBvc2l0aW9uIG9uIHRoZSBjdXJ2ZVxyXG5cclxuXHRcdFx0XHR2ZXJ0ZXgueCA9IFAxLnggKyAoIGN4ICogTi54ICsgY3kgKiBCLnggKTtcclxuXHRcdFx0XHR2ZXJ0ZXgueSA9IFAxLnkgKyAoIGN4ICogTi55ICsgY3kgKiBCLnkgKTtcclxuXHRcdFx0XHR2ZXJ0ZXgueiA9IFAxLnogKyAoIGN4ICogTi56ICsgY3kgKiBCLnogKTtcclxuXHJcblx0XHRcdFx0dmVydGljZXMucHVzaCggdmVydGV4LngsIHZlcnRleC55LCB2ZXJ0ZXgueiApO1xyXG5cclxuXHRcdFx0XHQvLyBub3JtYWwgKFAxIGlzIGFsd2F5cyB0aGUgY2VudGVyL29yaWdpbiBvZiB0aGUgZXh0cnVzaW9uLCB0aHVzIHdlIGNhbiB1c2UgaXQgdG8gY2FsY3VsYXRlIHRoZSBub3JtYWwpXHJcblxyXG5cdFx0XHRcdG5vcm1hbC5zdWJWZWN0b3JzKCB2ZXJ0ZXgsIFAxICkubm9ybWFsaXplKCk7XHJcblxyXG5cdFx0XHRcdG5vcm1hbHMucHVzaCggbm9ybWFsLngsIG5vcm1hbC55LCBub3JtYWwueiApO1xyXG5cclxuXHRcdFx0XHQvLyB1dlxyXG5cclxuXHRcdFx0XHR1dnMucHVzaCggaSAvIHR1YnVsYXJTZWdtZW50cyApO1xyXG5cdFx0XHRcdHV2cy5wdXNoKCBqIC8gcmFkaWFsU2VnbWVudHMgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gZ2VuZXJhdGUgaW5kaWNlc1xyXG5cclxuXHRcdGZvciAoIGxldCBqID0gMTsgaiA8PSB0dWJ1bGFyU2VnbWVudHM7IGogKysgKSB7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDE7IGkgPD0gcmFkaWFsU2VnbWVudHM7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdC8vIGluZGljZXNcclxuXHJcblx0XHRcdFx0Y29uc3QgYSA9ICggcmFkaWFsU2VnbWVudHMgKyAxICkgKiAoIGogLSAxICkgKyAoIGkgLSAxICk7XHJcblx0XHRcdFx0Y29uc3QgYiA9ICggcmFkaWFsU2VnbWVudHMgKyAxICkgKiBqICsgKCBpIC0gMSApO1xyXG5cdFx0XHRcdGNvbnN0IGMgPSAoIHJhZGlhbFNlZ21lbnRzICsgMSApICogaiArIGk7XHJcblx0XHRcdFx0Y29uc3QgZCA9ICggcmFkaWFsU2VnbWVudHMgKyAxICkgKiAoIGogLSAxICkgKyBpO1xyXG5cclxuXHRcdFx0XHQvLyBmYWNlc1xyXG5cclxuXHRcdFx0XHRpbmRpY2VzLnB1c2goIGEsIGIsIGQgKTtcclxuXHRcdFx0XHRpbmRpY2VzLnB1c2goIGIsIGMsIGQgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gYnVpbGQgZ2VvbWV0cnlcclxuXHJcblx0XHR0aGlzLnNldEluZGV4KCBpbmRpY2VzICk7XHJcblx0XHR0aGlzLnNldEF0dHJpYnV0ZSggJ3Bvc2l0aW9uJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIHZlcnRpY2VzLCAzICkgKTtcclxuXHRcdHRoaXMuc2V0QXR0cmlidXRlKCAnbm9ybWFsJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIG5vcm1hbHMsIDMgKSApO1xyXG5cdFx0dGhpcy5zZXRBdHRyaWJ1dGUoICd1dicsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCB1dnMsIDIgKSApO1xyXG5cclxuXHRcdC8vIHRoaXMgZnVuY3Rpb24gY2FsY3VsYXRlcyB0aGUgY3VycmVudCBwb3NpdGlvbiBvbiB0aGUgdG9ydXMgY3VydmVcclxuXHJcblx0XHRmdW5jdGlvbiBjYWxjdWxhdGVQb3NpdGlvbk9uQ3VydmUoIHUsIHAsIHEsIHJhZGl1cywgcG9zaXRpb24gKSB7XHJcblxyXG5cdFx0XHRjb25zdCBjdSA9IE1hdGguY29zKCB1ICk7XHJcblx0XHRcdGNvbnN0IHN1ID0gTWF0aC5zaW4oIHUgKTtcclxuXHRcdFx0Y29uc3QgcXVPdmVyUCA9IHEgLyBwICogdTtcclxuXHRcdFx0Y29uc3QgY3MgPSBNYXRoLmNvcyggcXVPdmVyUCApO1xyXG5cclxuXHRcdFx0cG9zaXRpb24ueCA9IHJhZGl1cyAqICggMiArIGNzICkgKiAwLjUgKiBjdTtcclxuXHRcdFx0cG9zaXRpb24ueSA9IHJhZGl1cyAqICggMiArIGNzICkgKiBzdSAqIDAuNTtcclxuXHRcdFx0cG9zaXRpb24ueiA9IHJhZGl1cyAqIE1hdGguc2luKCBxdU92ZXJQICkgKiAwLjU7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGNvcHkoIHNvdXJjZSApIHtcclxuXHJcblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcclxuXHJcblx0XHR0aGlzLnBhcmFtZXRlcnMgPSBPYmplY3QuYXNzaWduKCB7fSwgc291cmNlLnBhcmFtZXRlcnMgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzdGF0aWMgZnJvbUpTT04oIGRhdGEgKSB7XHJcblxyXG5cdFx0cmV0dXJuIG5ldyBUb3J1c0tub3RHZW9tZXRyeSggZGF0YS5yYWRpdXMsIGRhdGEudHViZSwgZGF0YS50dWJ1bGFyU2VnbWVudHMsIGRhdGEucmFkaWFsU2VnbWVudHMsIGRhdGEucCwgZGF0YS5xICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IFRvcnVzS25vdEdlb21ldHJ5IH07XHJcbiIsImltcG9ydCB7IEJ1ZmZlckdlb21ldHJ5IH0gZnJvbSAnLi4vY29yZS9CdWZmZXJHZW9tZXRyeS5qcyc7XHJcbmltcG9ydCB7IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUgfSBmcm9tICcuLi9jb3JlL0J1ZmZlckF0dHJpYnV0ZS5qcyc7XHJcbmltcG9ydCAqIGFzIEN1cnZlcyBmcm9tICcuLi9leHRyYXMvY3VydmVzL0N1cnZlcy5qcyc7XHJcbmltcG9ydCB7IFZlY3RvcjIgfSBmcm9tICcuLi9tYXRoL1ZlY3RvcjIuanMnO1xyXG5pbXBvcnQgeyBWZWN0b3IzIH0gZnJvbSAnLi4vbWF0aC9WZWN0b3IzLmpzJztcclxuXHJcbmNsYXNzIFR1YmVHZW9tZXRyeSBleHRlbmRzIEJ1ZmZlckdlb21ldHJ5IHtcclxuXHJcblx0Y29uc3RydWN0b3IoIHBhdGggPSBuZXcgQ3VydmVzWyAnUXVhZHJhdGljQmV6aWVyQ3VydmUzJyBdKCBuZXcgVmVjdG9yMyggLSAxLCAtIDEsIDAgKSwgbmV3IFZlY3RvcjMoIC0gMSwgMSwgMCApLCBuZXcgVmVjdG9yMyggMSwgMSwgMCApICksIHR1YnVsYXJTZWdtZW50cyA9IDY0LCByYWRpdXMgPSAxLCByYWRpYWxTZWdtZW50cyA9IDgsIGNsb3NlZCA9IGZhbHNlICkge1xyXG5cclxuXHRcdHN1cGVyKCk7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ1R1YmVHZW9tZXRyeSc7XHJcblxyXG5cdFx0dGhpcy5wYXJhbWV0ZXJzID0ge1xyXG5cdFx0XHRwYXRoOiBwYXRoLFxyXG5cdFx0XHR0dWJ1bGFyU2VnbWVudHM6IHR1YnVsYXJTZWdtZW50cyxcclxuXHRcdFx0cmFkaXVzOiByYWRpdXMsXHJcblx0XHRcdHJhZGlhbFNlZ21lbnRzOiByYWRpYWxTZWdtZW50cyxcclxuXHRcdFx0Y2xvc2VkOiBjbG9zZWRcclxuXHRcdH07XHJcblxyXG5cdFx0Y29uc3QgZnJhbWVzID0gcGF0aC5jb21wdXRlRnJlbmV0RnJhbWVzKCB0dWJ1bGFyU2VnbWVudHMsIGNsb3NlZCApO1xyXG5cclxuXHRcdC8vIGV4cG9zZSBpbnRlcm5hbHNcclxuXHJcblx0XHR0aGlzLnRhbmdlbnRzID0gZnJhbWVzLnRhbmdlbnRzO1xyXG5cdFx0dGhpcy5ub3JtYWxzID0gZnJhbWVzLm5vcm1hbHM7XHJcblx0XHR0aGlzLmJpbm9ybWFscyA9IGZyYW1lcy5iaW5vcm1hbHM7XHJcblxyXG5cdFx0Ly8gaGVscGVyIHZhcmlhYmxlc1xyXG5cclxuXHRcdGNvbnN0IHZlcnRleCA9IG5ldyBWZWN0b3IzKCk7XHJcblx0XHRjb25zdCBub3JtYWwgPSBuZXcgVmVjdG9yMygpO1xyXG5cdFx0Y29uc3QgdXYgPSBuZXcgVmVjdG9yMigpO1xyXG5cdFx0bGV0IFAgPSBuZXcgVmVjdG9yMygpO1xyXG5cclxuXHRcdC8vIGJ1ZmZlclxyXG5cclxuXHRcdGNvbnN0IHZlcnRpY2VzID0gW107XHJcblx0XHRjb25zdCBub3JtYWxzID0gW107XHJcblx0XHRjb25zdCB1dnMgPSBbXTtcclxuXHRcdGNvbnN0IGluZGljZXMgPSBbXTtcclxuXHJcblx0XHQvLyBjcmVhdGUgYnVmZmVyIGRhdGFcclxuXHJcblx0XHRnZW5lcmF0ZUJ1ZmZlckRhdGEoKTtcclxuXHJcblx0XHQvLyBidWlsZCBnZW9tZXRyeVxyXG5cclxuXHRcdHRoaXMuc2V0SW5kZXgoIGluZGljZXMgKTtcclxuXHRcdHRoaXMuc2V0QXR0cmlidXRlKCAncG9zaXRpb24nLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggdmVydGljZXMsIDMgKSApO1xyXG5cdFx0dGhpcy5zZXRBdHRyaWJ1dGUoICdub3JtYWwnLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggbm9ybWFscywgMyApICk7XHJcblx0XHR0aGlzLnNldEF0dHJpYnV0ZSggJ3V2JywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIHV2cywgMiApICk7XHJcblxyXG5cdFx0Ly8gZnVuY3Rpb25zXHJcblxyXG5cdFx0ZnVuY3Rpb24gZ2VuZXJhdGVCdWZmZXJEYXRhKCkge1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgdHVidWxhclNlZ21lbnRzOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRnZW5lcmF0ZVNlZ21lbnQoIGkgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdC8vIGlmIHRoZSBnZW9tZXRyeSBpcyBub3QgY2xvc2VkLCBnZW5lcmF0ZSB0aGUgbGFzdCByb3cgb2YgdmVydGljZXMgYW5kIG5vcm1hbHNcclxuXHRcdFx0Ly8gYXQgdGhlIHJlZ3VsYXIgcG9zaXRpb24gb24gdGhlIGdpdmVuIHBhdGhcclxuXHRcdFx0Ly9cclxuXHRcdFx0Ly8gaWYgdGhlIGdlb21ldHJ5IGlzIGNsb3NlZCwgZHVwbGljYXRlIHRoZSBmaXJzdCByb3cgb2YgdmVydGljZXMgYW5kIG5vcm1hbHMgKHV2cyB3aWxsIGRpZmZlcilcclxuXHJcblx0XHRcdGdlbmVyYXRlU2VnbWVudCggKCBjbG9zZWQgPT09IGZhbHNlICkgPyB0dWJ1bGFyU2VnbWVudHMgOiAwICk7XHJcblxyXG5cdFx0XHQvLyB1dnMgYXJlIGdlbmVyYXRlZCBpbiBhIHNlcGFyYXRlIGZ1bmN0aW9uLlxyXG5cdFx0XHQvLyB0aGlzIG1ha2VzIGl0IGVhc3kgY29tcHV0ZSBjb3JyZWN0IHZhbHVlcyBmb3IgY2xvc2VkIGdlb21ldHJpZXNcclxuXHJcblx0XHRcdGdlbmVyYXRlVVZzKCk7XHJcblxyXG5cdFx0XHQvLyBmaW5hbGx5IGNyZWF0ZSBmYWNlc1xyXG5cclxuXHRcdFx0Z2VuZXJhdGVJbmRpY2VzKCk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGZ1bmN0aW9uIGdlbmVyYXRlU2VnbWVudCggaSApIHtcclxuXHJcblx0XHRcdC8vIHdlIHVzZSBnZXRQb2ludEF0IHRvIHNhbXBsZSBldmVubHkgZGlzdHJpYnV0ZWQgcG9pbnRzIGZyb20gdGhlIGdpdmVuIHBhdGhcclxuXHJcblx0XHRcdFAgPSBwYXRoLmdldFBvaW50QXQoIGkgLyB0dWJ1bGFyU2VnbWVudHMsIFAgKTtcclxuXHJcblx0XHRcdC8vIHJldHJpZXZlIGNvcnJlc3BvbmRpbmcgbm9ybWFsIGFuZCBiaW5vcm1hbFxyXG5cclxuXHRcdFx0Y29uc3QgTiA9IGZyYW1lcy5ub3JtYWxzWyBpIF07XHJcblx0XHRcdGNvbnN0IEIgPSBmcmFtZXMuYmlub3JtYWxzWyBpIF07XHJcblxyXG5cdFx0XHQvLyBnZW5lcmF0ZSBub3JtYWxzIGFuZCB2ZXJ0aWNlcyBmb3IgdGhlIGN1cnJlbnQgc2VnbWVudFxyXG5cclxuXHRcdFx0Zm9yICggbGV0IGogPSAwOyBqIDw9IHJhZGlhbFNlZ21lbnRzOyBqICsrICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCB2ID0gaiAvIHJhZGlhbFNlZ21lbnRzICogTWF0aC5QSSAqIDI7XHJcblxyXG5cdFx0XHRcdGNvbnN0IHNpbiA9IE1hdGguc2luKCB2ICk7XHJcblx0XHRcdFx0Y29uc3QgY29zID0gLSBNYXRoLmNvcyggdiApO1xyXG5cclxuXHRcdFx0XHQvLyBub3JtYWxcclxuXHJcblx0XHRcdFx0bm9ybWFsLnggPSAoIGNvcyAqIE4ueCArIHNpbiAqIEIueCApO1xyXG5cdFx0XHRcdG5vcm1hbC55ID0gKCBjb3MgKiBOLnkgKyBzaW4gKiBCLnkgKTtcclxuXHRcdFx0XHRub3JtYWwueiA9ICggY29zICogTi56ICsgc2luICogQi56ICk7XHJcblx0XHRcdFx0bm9ybWFsLm5vcm1hbGl6ZSgpO1xyXG5cclxuXHRcdFx0XHRub3JtYWxzLnB1c2goIG5vcm1hbC54LCBub3JtYWwueSwgbm9ybWFsLnogKTtcclxuXHJcblx0XHRcdFx0Ly8gdmVydGV4XHJcblxyXG5cdFx0XHRcdHZlcnRleC54ID0gUC54ICsgcmFkaXVzICogbm9ybWFsLng7XHJcblx0XHRcdFx0dmVydGV4LnkgPSBQLnkgKyByYWRpdXMgKiBub3JtYWwueTtcclxuXHRcdFx0XHR2ZXJ0ZXgueiA9IFAueiArIHJhZGl1cyAqIG5vcm1hbC56O1xyXG5cclxuXHRcdFx0XHR2ZXJ0aWNlcy5wdXNoKCB2ZXJ0ZXgueCwgdmVydGV4LnksIHZlcnRleC56ICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGZ1bmN0aW9uIGdlbmVyYXRlSW5kaWNlcygpIHtcclxuXHJcblx0XHRcdGZvciAoIGxldCBqID0gMTsgaiA8PSB0dWJ1bGFyU2VnbWVudHM7IGogKysgKSB7XHJcblxyXG5cdFx0XHRcdGZvciAoIGxldCBpID0gMTsgaSA8PSByYWRpYWxTZWdtZW50czsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0XHRjb25zdCBhID0gKCByYWRpYWxTZWdtZW50cyArIDEgKSAqICggaiAtIDEgKSArICggaSAtIDEgKTtcclxuXHRcdFx0XHRcdGNvbnN0IGIgPSAoIHJhZGlhbFNlZ21lbnRzICsgMSApICogaiArICggaSAtIDEgKTtcclxuXHRcdFx0XHRcdGNvbnN0IGMgPSAoIHJhZGlhbFNlZ21lbnRzICsgMSApICogaiArIGk7XHJcblx0XHRcdFx0XHRjb25zdCBkID0gKCByYWRpYWxTZWdtZW50cyArIDEgKSAqICggaiAtIDEgKSArIGk7XHJcblxyXG5cdFx0XHRcdFx0Ly8gZmFjZXNcclxuXHJcblx0XHRcdFx0XHRpbmRpY2VzLnB1c2goIGEsIGIsIGQgKTtcclxuXHRcdFx0XHRcdGluZGljZXMucHVzaCggYiwgYywgZCApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGZ1bmN0aW9uIGdlbmVyYXRlVVZzKCkge1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDw9IHR1YnVsYXJTZWdtZW50czsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0Zm9yICggbGV0IGogPSAwOyBqIDw9IHJhZGlhbFNlZ21lbnRzOyBqICsrICkge1xyXG5cclxuXHRcdFx0XHRcdHV2LnggPSBpIC8gdHVidWxhclNlZ21lbnRzO1xyXG5cdFx0XHRcdFx0dXYueSA9IGogLyByYWRpYWxTZWdtZW50cztcclxuXHJcblx0XHRcdFx0XHR1dnMucHVzaCggdXYueCwgdXYueSApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGNvcHkoIHNvdXJjZSApIHtcclxuXHJcblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcclxuXHJcblx0XHR0aGlzLnBhcmFtZXRlcnMgPSBPYmplY3QuYXNzaWduKCB7fSwgc291cmNlLnBhcmFtZXRlcnMgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHR0b0pTT04oKSB7XHJcblxyXG5cdFx0Y29uc3QgZGF0YSA9IHN1cGVyLnRvSlNPTigpO1xyXG5cclxuXHRcdGRhdGEucGF0aCA9IHRoaXMucGFyYW1ldGVycy5wYXRoLnRvSlNPTigpO1xyXG5cclxuXHRcdHJldHVybiBkYXRhO1xyXG5cclxuXHR9XHJcblxyXG5cdHN0YXRpYyBmcm9tSlNPTiggZGF0YSApIHtcclxuXHJcblx0XHQvLyBUaGlzIG9ubHkgd29ya3MgZm9yIGJ1aWx0LWluIGN1cnZlcyAoZS5nLiBDYXRtdWxsUm9tQ3VydmUzKS5cclxuXHRcdC8vIFVzZXIgZGVmaW5lZCBjdXJ2ZXMgb3IgaW5zdGFuY2VzIG9mIEN1cnZlUGF0aCB3aWxsIG5vdCBiZSBkZXNlcmlhbGl6ZWQuXHJcblx0XHRyZXR1cm4gbmV3IFR1YmVHZW9tZXRyeShcclxuXHRcdFx0bmV3IEN1cnZlc1sgZGF0YS5wYXRoLnR5cGUgXSgpLmZyb21KU09OKCBkYXRhLnBhdGggKSxcclxuXHRcdFx0ZGF0YS50dWJ1bGFyU2VnbWVudHMsXHJcblx0XHRcdGRhdGEucmFkaXVzLFxyXG5cdFx0XHRkYXRhLnJhZGlhbFNlZ21lbnRzLFxyXG5cdFx0XHRkYXRhLmNsb3NlZFxyXG5cdFx0KTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuXHJcbmV4cG9ydCB7IFR1YmVHZW9tZXRyeSB9O1xyXG4iLCJpbXBvcnQgeyBCdWZmZXJHZW9tZXRyeSB9IGZyb20gJy4uL2NvcmUvQnVmZmVyR2VvbWV0cnkuanMnO1xyXG5pbXBvcnQgeyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlIH0gZnJvbSAnLi4vY29yZS9CdWZmZXJBdHRyaWJ1dGUuanMnO1xyXG5pbXBvcnQgeyBWZWN0b3IzIH0gZnJvbSAnLi4vbWF0aC9WZWN0b3IzLmpzJztcclxuXHJcbmNsYXNzIFdpcmVmcmFtZUdlb21ldHJ5IGV4dGVuZHMgQnVmZmVyR2VvbWV0cnkge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggZ2VvbWV0cnkgPSBudWxsICkge1xyXG5cclxuXHRcdHN1cGVyKCk7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ1dpcmVmcmFtZUdlb21ldHJ5JztcclxuXHJcblx0XHR0aGlzLnBhcmFtZXRlcnMgPSB7XHJcblx0XHRcdGdlb21ldHJ5OiBnZW9tZXRyeVxyXG5cdFx0fTtcclxuXHJcblx0XHRpZiAoIGdlb21ldHJ5ICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0Ly8gYnVmZmVyXHJcblxyXG5cdFx0XHRjb25zdCB2ZXJ0aWNlcyA9IFtdO1xyXG5cdFx0XHRjb25zdCBlZGdlcyA9IG5ldyBTZXQoKTtcclxuXHJcblx0XHRcdC8vIGhlbHBlciB2YXJpYWJsZXNcclxuXHJcblx0XHRcdGNvbnN0IHN0YXJ0ID0gbmV3IFZlY3RvcjMoKTtcclxuXHRcdFx0Y29uc3QgZW5kID0gbmV3IFZlY3RvcjMoKTtcclxuXHJcblx0XHRcdGlmICggZ2VvbWV0cnkuaW5kZXggIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdC8vIGluZGV4ZWQgQnVmZmVyR2VvbWV0cnlcclxuXHJcblx0XHRcdFx0Y29uc3QgcG9zaXRpb24gPSBnZW9tZXRyeS5hdHRyaWJ1dGVzLnBvc2l0aW9uO1xyXG5cdFx0XHRcdGNvbnN0IGluZGljZXMgPSBnZW9tZXRyeS5pbmRleDtcclxuXHRcdFx0XHRsZXQgZ3JvdXBzID0gZ2VvbWV0cnkuZ3JvdXBzO1xyXG5cclxuXHRcdFx0XHRpZiAoIGdyb3Vwcy5sZW5ndGggPT09IDAgKSB7XHJcblxyXG5cdFx0XHRcdFx0Z3JvdXBzID0gWyB7IHN0YXJ0OiAwLCBjb3VudDogaW5kaWNlcy5jb3VudCwgbWF0ZXJpYWxJbmRleDogMCB9IF07XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0Ly8gY3JlYXRlIGEgZGF0YSBzdHJ1Y3R1cmUgdGhhdCBjb250YWlucyBhbGwgZWRnZXMgd2l0aG91dCBkdXBsaWNhdGVzXHJcblxyXG5cdFx0XHRcdGZvciAoIGxldCBvID0gMCwgb2wgPSBncm91cHMubGVuZ3RoOyBvIDwgb2w7ICsrIG8gKSB7XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgZ3JvdXAgPSBncm91cHNbIG8gXTtcclxuXHJcblx0XHRcdFx0XHRjb25zdCBncm91cFN0YXJ0ID0gZ3JvdXAuc3RhcnQ7XHJcblx0XHRcdFx0XHRjb25zdCBncm91cENvdW50ID0gZ3JvdXAuY291bnQ7XHJcblxyXG5cdFx0XHRcdFx0Zm9yICggbGV0IGkgPSBncm91cFN0YXJ0LCBsID0gKCBncm91cFN0YXJ0ICsgZ3JvdXBDb3VudCApOyBpIDwgbDsgaSArPSAzICkge1xyXG5cclxuXHRcdFx0XHRcdFx0Zm9yICggbGV0IGogPSAwOyBqIDwgMzsgaiArKyApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0Y29uc3QgaW5kZXgxID0gaW5kaWNlcy5nZXRYKCBpICsgaiApO1xyXG5cdFx0XHRcdFx0XHRcdGNvbnN0IGluZGV4MiA9IGluZGljZXMuZ2V0WCggaSArICggaiArIDEgKSAlIDMgKTtcclxuXHJcblx0XHRcdFx0XHRcdFx0c3RhcnQuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggcG9zaXRpb24sIGluZGV4MSApO1xyXG5cdFx0XHRcdFx0XHRcdGVuZC5mcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbiwgaW5kZXgyICk7XHJcblxyXG5cdFx0XHRcdFx0XHRcdGlmICggaXNVbmlxdWVFZGdlKCBzdGFydCwgZW5kLCBlZGdlcyApID09PSB0cnVlICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRcdHZlcnRpY2VzLnB1c2goIHN0YXJ0LngsIHN0YXJ0LnksIHN0YXJ0LnogKTtcclxuXHRcdFx0XHRcdFx0XHRcdHZlcnRpY2VzLnB1c2goIGVuZC54LCBlbmQueSwgZW5kLnogKTtcclxuXHJcblx0XHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0Ly8gbm9uLWluZGV4ZWQgQnVmZmVyR2VvbWV0cnlcclxuXHJcblx0XHRcdFx0Y29uc3QgcG9zaXRpb24gPSBnZW9tZXRyeS5hdHRyaWJ1dGVzLnBvc2l0aW9uO1xyXG5cclxuXHRcdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSAoIHBvc2l0aW9uLmNvdW50IC8gMyApOyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0XHRmb3IgKCBsZXQgaiA9IDA7IGogPCAzOyBqICsrICkge1xyXG5cclxuXHRcdFx0XHRcdFx0Ly8gdGhyZWUgZWRnZXMgcGVyIHRyaWFuZ2xlLCBhbiBlZGdlIGlzIHJlcHJlc2VudGVkIGFzIChpbmRleDEsIGluZGV4MilcclxuXHRcdFx0XHRcdFx0Ly8gZS5nLiB0aGUgZmlyc3QgdHJpYW5nbGUgaGFzIHRoZSBmb2xsb3dpbmcgZWRnZXM6ICgwLDEpLCgxLDIpLCgyLDApXHJcblxyXG5cdFx0XHRcdFx0XHRjb25zdCBpbmRleDEgPSAzICogaSArIGo7XHJcblx0XHRcdFx0XHRcdGNvbnN0IGluZGV4MiA9IDMgKiBpICsgKCAoIGogKyAxICkgJSAzICk7XHJcblxyXG5cdFx0XHRcdFx0XHRzdGFydC5mcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbiwgaW5kZXgxICk7XHJcblx0XHRcdFx0XHRcdGVuZC5mcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbiwgaW5kZXgyICk7XHJcblxyXG5cdFx0XHRcdFx0XHRpZiAoIGlzVW5pcXVlRWRnZSggc3RhcnQsIGVuZCwgZWRnZXMgKSA9PT0gdHJ1ZSApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0dmVydGljZXMucHVzaCggc3RhcnQueCwgc3RhcnQueSwgc3RhcnQueiApO1xyXG5cdFx0XHRcdFx0XHRcdHZlcnRpY2VzLnB1c2goIGVuZC54LCBlbmQueSwgZW5kLnogKTtcclxuXHJcblx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdC8vIGJ1aWxkIGdlb21ldHJ5XHJcblxyXG5cdFx0XHR0aGlzLnNldEF0dHJpYnV0ZSggJ3Bvc2l0aW9uJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIHZlcnRpY2VzLCAzICkgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xyXG5cclxuXHRcdHRoaXMucGFyYW1ldGVycyA9IE9iamVjdC5hc3NpZ24oIHt9LCBzb3VyY2UucGFyYW1ldGVycyApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiBpc1VuaXF1ZUVkZ2UoIHN0YXJ0LCBlbmQsIGVkZ2VzICkge1xyXG5cclxuXHRjb25zdCBoYXNoMSA9IGAke3N0YXJ0Lnh9LCR7c3RhcnQueX0sJHtzdGFydC56fS0ke2VuZC54fSwke2VuZC55fSwke2VuZC56fWA7XHJcblx0Y29uc3QgaGFzaDIgPSBgJHtlbmQueH0sJHtlbmQueX0sJHtlbmQuen0tJHtzdGFydC54fSwke3N0YXJ0Lnl9LCR7c3RhcnQuen1gOyAvLyBjb2luY2lkZW50IGVkZ2VcclxuXHJcblx0aWYgKCBlZGdlcy5oYXMoIGhhc2gxICkgPT09IHRydWUgfHwgZWRnZXMuaGFzKCBoYXNoMiApID09PSB0cnVlICkge1xyXG5cclxuXHRcdHJldHVybiBmYWxzZTtcclxuXHJcblx0fSBlbHNlIHtcclxuXHJcblx0XHRlZGdlcy5hZGQoIGhhc2gxICk7XHJcblx0XHRlZGdlcy5hZGQoIGhhc2gyICk7XHJcblx0XHRyZXR1cm4gdHJ1ZTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuXHJcbmV4cG9ydCB7IFdpcmVmcmFtZUdlb21ldHJ5IH07XHJcbiIsImltcG9ydCB7IE1hdGVyaWFsIH0gZnJvbSAnLi9NYXRlcmlhbC5qcyc7XHJcbmltcG9ydCB7IENvbG9yIH0gZnJvbSAnLi4vbWF0aC9Db2xvci5qcyc7XHJcblxyXG5jbGFzcyBTaGFkb3dNYXRlcmlhbCBleHRlbmRzIE1hdGVyaWFsIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIHBhcmFtZXRlcnMgKSB7XHJcblxyXG5cdFx0c3VwZXIoKTtcclxuXHJcblx0XHR0aGlzLmlzU2hhZG93TWF0ZXJpYWwgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMudHlwZSA9ICdTaGFkb3dNYXRlcmlhbCc7XHJcblxyXG5cdFx0dGhpcy5jb2xvciA9IG5ldyBDb2xvciggMHgwMDAwMDAgKTtcclxuXHRcdHRoaXMudHJhbnNwYXJlbnQgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMuZm9nID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLnNldFZhbHVlcyggcGFyYW1ldGVycyApO1xyXG5cclxuXHR9XHJcblxyXG5cdGNvcHkoIHNvdXJjZSApIHtcclxuXHJcblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcclxuXHJcblx0XHR0aGlzLmNvbG9yLmNvcHkoIHNvdXJjZS5jb2xvciApO1xyXG5cclxuXHRcdHRoaXMuZm9nID0gc291cmNlLmZvZztcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgU2hhZG93TWF0ZXJpYWwgfTtcclxuIiwiaW1wb3J0IHsgU2hhZGVyTWF0ZXJpYWwgfSBmcm9tICcuL1NoYWRlck1hdGVyaWFsLmpzJztcclxuXHJcbmNsYXNzIFJhd1NoYWRlck1hdGVyaWFsIGV4dGVuZHMgU2hhZGVyTWF0ZXJpYWwge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggcGFyYW1ldGVycyApIHtcclxuXHJcblx0XHRzdXBlciggcGFyYW1ldGVycyApO1xyXG5cclxuXHRcdHRoaXMuaXNSYXdTaGFkZXJNYXRlcmlhbCA9IHRydWU7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ1Jhd1NoYWRlck1hdGVyaWFsJztcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgUmF3U2hhZGVyTWF0ZXJpYWwgfTtcclxuIiwiaW1wb3J0IHsgVGFuZ2VudFNwYWNlTm9ybWFsTWFwIH0gZnJvbSAnLi4vY29uc3RhbnRzLmpzJztcclxuaW1wb3J0IHsgTWF0ZXJpYWwgfSBmcm9tICcuL01hdGVyaWFsLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yMiB9IGZyb20gJy4uL21hdGgvVmVjdG9yMi5qcyc7XHJcbmltcG9ydCB7IENvbG9yIH0gZnJvbSAnLi4vbWF0aC9Db2xvci5qcyc7XHJcblxyXG5jbGFzcyBNZXNoU3RhbmRhcmRNYXRlcmlhbCBleHRlbmRzIE1hdGVyaWFsIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIHBhcmFtZXRlcnMgKSB7XHJcblxyXG5cdFx0c3VwZXIoKTtcclxuXHJcblx0XHR0aGlzLmlzTWVzaFN0YW5kYXJkTWF0ZXJpYWwgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMuZGVmaW5lcyA9IHsgJ1NUQU5EQVJEJzogJycgfTtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSAnTWVzaFN0YW5kYXJkTWF0ZXJpYWwnO1xyXG5cclxuXHRcdHRoaXMuY29sb3IgPSBuZXcgQ29sb3IoIDB4ZmZmZmZmICk7IC8vIGRpZmZ1c2VcclxuXHRcdHRoaXMucm91Z2huZXNzID0gMS4wO1xyXG5cdFx0dGhpcy5tZXRhbG5lc3MgPSAwLjA7XHJcblxyXG5cdFx0dGhpcy5tYXAgPSBudWxsO1xyXG5cclxuXHRcdHRoaXMubGlnaHRNYXAgPSBudWxsO1xyXG5cdFx0dGhpcy5saWdodE1hcEludGVuc2l0eSA9IDEuMDtcclxuXHJcblx0XHR0aGlzLmFvTWFwID0gbnVsbDtcclxuXHRcdHRoaXMuYW9NYXBJbnRlbnNpdHkgPSAxLjA7XHJcblxyXG5cdFx0dGhpcy5lbWlzc2l2ZSA9IG5ldyBDb2xvciggMHgwMDAwMDAgKTtcclxuXHRcdHRoaXMuZW1pc3NpdmVJbnRlbnNpdHkgPSAxLjA7XHJcblx0XHR0aGlzLmVtaXNzaXZlTWFwID0gbnVsbDtcclxuXHJcblx0XHR0aGlzLmJ1bXBNYXAgPSBudWxsO1xyXG5cdFx0dGhpcy5idW1wU2NhbGUgPSAxO1xyXG5cclxuXHRcdHRoaXMubm9ybWFsTWFwID0gbnVsbDtcclxuXHRcdHRoaXMubm9ybWFsTWFwVHlwZSA9IFRhbmdlbnRTcGFjZU5vcm1hbE1hcDtcclxuXHRcdHRoaXMubm9ybWFsU2NhbGUgPSBuZXcgVmVjdG9yMiggMSwgMSApO1xyXG5cclxuXHRcdHRoaXMuZGlzcGxhY2VtZW50TWFwID0gbnVsbDtcclxuXHRcdHRoaXMuZGlzcGxhY2VtZW50U2NhbGUgPSAxO1xyXG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRCaWFzID0gMDtcclxuXHJcblx0XHR0aGlzLnJvdWdobmVzc01hcCA9IG51bGw7XHJcblxyXG5cdFx0dGhpcy5tZXRhbG5lc3NNYXAgPSBudWxsO1xyXG5cclxuXHRcdHRoaXMuYWxwaGFNYXAgPSBudWxsO1xyXG5cclxuXHRcdHRoaXMuZW52TWFwID0gbnVsbDtcclxuXHRcdHRoaXMuZW52TWFwSW50ZW5zaXR5ID0gMS4wO1xyXG5cclxuXHRcdHRoaXMud2lyZWZyYW1lID0gZmFsc2U7XHJcblx0XHR0aGlzLndpcmVmcmFtZUxpbmV3aWR0aCA9IDE7XHJcblx0XHR0aGlzLndpcmVmcmFtZUxpbmVjYXAgPSAncm91bmQnO1xyXG5cdFx0dGhpcy53aXJlZnJhbWVMaW5lam9pbiA9ICdyb3VuZCc7XHJcblxyXG5cdFx0dGhpcy5mbGF0U2hhZGluZyA9IGZhbHNlO1xyXG5cclxuXHRcdHRoaXMuZm9nID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLnNldFZhbHVlcyggcGFyYW1ldGVycyApO1xyXG5cclxuXHR9XHJcblxyXG5cdGNvcHkoIHNvdXJjZSApIHtcclxuXHJcblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcclxuXHJcblx0XHR0aGlzLmRlZmluZXMgPSB7ICdTVEFOREFSRCc6ICcnIH07XHJcblxyXG5cdFx0dGhpcy5jb2xvci5jb3B5KCBzb3VyY2UuY29sb3IgKTtcclxuXHRcdHRoaXMucm91Z2huZXNzID0gc291cmNlLnJvdWdobmVzcztcclxuXHRcdHRoaXMubWV0YWxuZXNzID0gc291cmNlLm1ldGFsbmVzcztcclxuXHJcblx0XHR0aGlzLm1hcCA9IHNvdXJjZS5tYXA7XHJcblxyXG5cdFx0dGhpcy5saWdodE1hcCA9IHNvdXJjZS5saWdodE1hcDtcclxuXHRcdHRoaXMubGlnaHRNYXBJbnRlbnNpdHkgPSBzb3VyY2UubGlnaHRNYXBJbnRlbnNpdHk7XHJcblxyXG5cdFx0dGhpcy5hb01hcCA9IHNvdXJjZS5hb01hcDtcclxuXHRcdHRoaXMuYW9NYXBJbnRlbnNpdHkgPSBzb3VyY2UuYW9NYXBJbnRlbnNpdHk7XHJcblxyXG5cdFx0dGhpcy5lbWlzc2l2ZS5jb3B5KCBzb3VyY2UuZW1pc3NpdmUgKTtcclxuXHRcdHRoaXMuZW1pc3NpdmVNYXAgPSBzb3VyY2UuZW1pc3NpdmVNYXA7XHJcblx0XHR0aGlzLmVtaXNzaXZlSW50ZW5zaXR5ID0gc291cmNlLmVtaXNzaXZlSW50ZW5zaXR5O1xyXG5cclxuXHRcdHRoaXMuYnVtcE1hcCA9IHNvdXJjZS5idW1wTWFwO1xyXG5cdFx0dGhpcy5idW1wU2NhbGUgPSBzb3VyY2UuYnVtcFNjYWxlO1xyXG5cclxuXHRcdHRoaXMubm9ybWFsTWFwID0gc291cmNlLm5vcm1hbE1hcDtcclxuXHRcdHRoaXMubm9ybWFsTWFwVHlwZSA9IHNvdXJjZS5ub3JtYWxNYXBUeXBlO1xyXG5cdFx0dGhpcy5ub3JtYWxTY2FsZS5jb3B5KCBzb3VyY2Uubm9ybWFsU2NhbGUgKTtcclxuXHJcblx0XHR0aGlzLmRpc3BsYWNlbWVudE1hcCA9IHNvdXJjZS5kaXNwbGFjZW1lbnRNYXA7XHJcblx0XHR0aGlzLmRpc3BsYWNlbWVudFNjYWxlID0gc291cmNlLmRpc3BsYWNlbWVudFNjYWxlO1xyXG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRCaWFzID0gc291cmNlLmRpc3BsYWNlbWVudEJpYXM7XHJcblxyXG5cdFx0dGhpcy5yb3VnaG5lc3NNYXAgPSBzb3VyY2Uucm91Z2huZXNzTWFwO1xyXG5cclxuXHRcdHRoaXMubWV0YWxuZXNzTWFwID0gc291cmNlLm1ldGFsbmVzc01hcDtcclxuXHJcblx0XHR0aGlzLmFscGhhTWFwID0gc291cmNlLmFscGhhTWFwO1xyXG5cclxuXHRcdHRoaXMuZW52TWFwID0gc291cmNlLmVudk1hcDtcclxuXHRcdHRoaXMuZW52TWFwSW50ZW5zaXR5ID0gc291cmNlLmVudk1hcEludGVuc2l0eTtcclxuXHJcblx0XHR0aGlzLndpcmVmcmFtZSA9IHNvdXJjZS53aXJlZnJhbWU7XHJcblx0XHR0aGlzLndpcmVmcmFtZUxpbmV3aWR0aCA9IHNvdXJjZS53aXJlZnJhbWVMaW5ld2lkdGg7XHJcblx0XHR0aGlzLndpcmVmcmFtZUxpbmVjYXAgPSBzb3VyY2Uud2lyZWZyYW1lTGluZWNhcDtcclxuXHRcdHRoaXMud2lyZWZyYW1lTGluZWpvaW4gPSBzb3VyY2Uud2lyZWZyYW1lTGluZWpvaW47XHJcblxyXG5cdFx0dGhpcy5mbGF0U2hhZGluZyA9IHNvdXJjZS5mbGF0U2hhZGluZztcclxuXHJcblx0XHR0aGlzLmZvZyA9IHNvdXJjZS5mb2c7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IE1lc2hTdGFuZGFyZE1hdGVyaWFsIH07XHJcbiIsImltcG9ydCB7IFZlY3RvcjIgfSBmcm9tICcuLi9tYXRoL1ZlY3RvcjIuanMnO1xyXG5pbXBvcnQgeyBNZXNoU3RhbmRhcmRNYXRlcmlhbCB9IGZyb20gJy4vTWVzaFN0YW5kYXJkTWF0ZXJpYWwuanMnO1xyXG5pbXBvcnQgeyBDb2xvciB9IGZyb20gJy4uL21hdGgvQ29sb3IuanMnO1xyXG5pbXBvcnQgKiBhcyBNYXRoVXRpbHMgZnJvbSAnLi4vbWF0aC9NYXRoVXRpbHMuanMnO1xyXG5cclxuY2xhc3MgTWVzaFBoeXNpY2FsTWF0ZXJpYWwgZXh0ZW5kcyBNZXNoU3RhbmRhcmRNYXRlcmlhbCB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBwYXJhbWV0ZXJzICkge1xyXG5cclxuXHRcdHN1cGVyKCk7XHJcblxyXG5cdFx0dGhpcy5pc01lc2hQaHlzaWNhbE1hdGVyaWFsID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLmRlZmluZXMgPSB7XHJcblxyXG5cdFx0XHQnU1RBTkRBUkQnOiAnJyxcclxuXHRcdFx0J1BIWVNJQ0FMJzogJydcclxuXHJcblx0XHR9O1xyXG5cclxuXHRcdHRoaXMudHlwZSA9ICdNZXNoUGh5c2ljYWxNYXRlcmlhbCc7XHJcblxyXG5cdFx0dGhpcy5hbmlzb3Ryb3B5Um90YXRpb24gPSAwO1xyXG5cdFx0dGhpcy5hbmlzb3Ryb3B5TWFwID0gbnVsbDtcclxuXHJcblx0XHR0aGlzLmNsZWFyY29hdE1hcCA9IG51bGw7XHJcblx0XHR0aGlzLmNsZWFyY29hdFJvdWdobmVzcyA9IDAuMDtcclxuXHRcdHRoaXMuY2xlYXJjb2F0Um91Z2huZXNzTWFwID0gbnVsbDtcclxuXHRcdHRoaXMuY2xlYXJjb2F0Tm9ybWFsU2NhbGUgPSBuZXcgVmVjdG9yMiggMSwgMSApO1xyXG5cdFx0dGhpcy5jbGVhcmNvYXROb3JtYWxNYXAgPSBudWxsO1xyXG5cclxuXHRcdHRoaXMuaW9yID0gMS41O1xyXG5cclxuXHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eSggdGhpcywgJ3JlZmxlY3Rpdml0eScsIHtcclxuXHRcdFx0Z2V0OiBmdW5jdGlvbiAoKSB7XHJcblxyXG5cdFx0XHRcdHJldHVybiAoIE1hdGhVdGlscy5jbGFtcCggMi41ICogKCB0aGlzLmlvciAtIDEgKSAvICggdGhpcy5pb3IgKyAxICksIDAsIDEgKSApO1xyXG5cclxuXHRcdFx0fSxcclxuXHRcdFx0c2V0OiBmdW5jdGlvbiAoIHJlZmxlY3Rpdml0eSApIHtcclxuXHJcblx0XHRcdFx0dGhpcy5pb3IgPSAoIDEgKyAwLjQgKiByZWZsZWN0aXZpdHkgKSAvICggMSAtIDAuNCAqIHJlZmxlY3Rpdml0eSApO1xyXG5cclxuXHRcdFx0fVxyXG5cdFx0fSApO1xyXG5cclxuXHRcdHRoaXMuaXJpZGVzY2VuY2VNYXAgPSBudWxsO1xyXG5cdFx0dGhpcy5pcmlkZXNjZW5jZUlPUiA9IDEuMztcclxuXHRcdHRoaXMuaXJpZGVzY2VuY2VUaGlja25lc3NSYW5nZSA9IFsgMTAwLCA0MDAgXTtcclxuXHRcdHRoaXMuaXJpZGVzY2VuY2VUaGlja25lc3NNYXAgPSBudWxsO1xyXG5cclxuXHRcdHRoaXMuc2hlZW5Db2xvciA9IG5ldyBDb2xvciggMHgwMDAwMDAgKTtcclxuXHRcdHRoaXMuc2hlZW5Db2xvck1hcCA9IG51bGw7XHJcblx0XHR0aGlzLnNoZWVuUm91Z2huZXNzID0gMS4wO1xyXG5cdFx0dGhpcy5zaGVlblJvdWdobmVzc01hcCA9IG51bGw7XHJcblxyXG5cdFx0dGhpcy50cmFuc21pc3Npb25NYXAgPSBudWxsO1xyXG5cclxuXHRcdHRoaXMudGhpY2tuZXNzID0gMDtcclxuXHRcdHRoaXMudGhpY2tuZXNzTWFwID0gbnVsbDtcclxuXHRcdHRoaXMuYXR0ZW51YXRpb25EaXN0YW5jZSA9IEluZmluaXR5O1xyXG5cdFx0dGhpcy5hdHRlbnVhdGlvbkNvbG9yID0gbmV3IENvbG9yKCAxLCAxLCAxICk7XHJcblxyXG5cdFx0dGhpcy5zcGVjdWxhckludGVuc2l0eSA9IDEuMDtcclxuXHRcdHRoaXMuc3BlY3VsYXJJbnRlbnNpdHlNYXAgPSBudWxsO1xyXG5cdFx0dGhpcy5zcGVjdWxhckNvbG9yID0gbmV3IENvbG9yKCAxLCAxLCAxICk7XHJcblx0XHR0aGlzLnNwZWN1bGFyQ29sb3JNYXAgPSBudWxsO1xyXG5cclxuXHRcdHRoaXMuX2FuaXNvdHJvcHkgPSAwO1xyXG5cdFx0dGhpcy5fY2xlYXJjb2F0ID0gMDtcclxuXHRcdHRoaXMuX2lyaWRlc2NlbmNlID0gMDtcclxuXHRcdHRoaXMuX3NoZWVuID0gMC4wO1xyXG5cdFx0dGhpcy5fdHJhbnNtaXNzaW9uID0gMDtcclxuXHJcblx0XHR0aGlzLnNldFZhbHVlcyggcGFyYW1ldGVycyApO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldCBhbmlzb3Ryb3B5KCkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLl9hbmlzb3Ryb3B5O1xyXG5cclxuXHR9XHJcblxyXG5cdHNldCBhbmlzb3Ryb3B5KCB2YWx1ZSApIHtcclxuXHJcblx0XHRpZiAoIHRoaXMuX2FuaXNvdHJvcHkgPiAwICE9PSB2YWx1ZSA+IDAgKSB7XHJcblxyXG5cdFx0XHR0aGlzLnZlcnNpb24gKys7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMuX2FuaXNvdHJvcHkgPSB2YWx1ZTtcclxuXHJcblx0fVxyXG5cclxuXHRnZXQgY2xlYXJjb2F0KCkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLl9jbGVhcmNvYXQ7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0IGNsZWFyY29hdCggdmFsdWUgKSB7XHJcblxyXG5cdFx0aWYgKCB0aGlzLl9jbGVhcmNvYXQgPiAwICE9PSB2YWx1ZSA+IDAgKSB7XHJcblxyXG5cdFx0XHR0aGlzLnZlcnNpb24gKys7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMuX2NsZWFyY29hdCA9IHZhbHVlO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldCBpcmlkZXNjZW5jZSgpIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5faXJpZGVzY2VuY2U7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0IGlyaWRlc2NlbmNlKCB2YWx1ZSApIHtcclxuXHJcblx0XHRpZiAoIHRoaXMuX2lyaWRlc2NlbmNlID4gMCAhPT0gdmFsdWUgPiAwICkge1xyXG5cclxuXHRcdFx0dGhpcy52ZXJzaW9uICsrO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLl9pcmlkZXNjZW5jZSA9IHZhbHVlO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldCBzaGVlbigpIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5fc2hlZW47XHJcblxyXG5cdH1cclxuXHJcblx0c2V0IHNoZWVuKCB2YWx1ZSApIHtcclxuXHJcblx0XHRpZiAoIHRoaXMuX3NoZWVuID4gMCAhPT0gdmFsdWUgPiAwICkge1xyXG5cclxuXHRcdFx0dGhpcy52ZXJzaW9uICsrO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLl9zaGVlbiA9IHZhbHVlO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldCB0cmFuc21pc3Npb24oKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuX3RyYW5zbWlzc2lvbjtcclxuXHJcblx0fVxyXG5cclxuXHRzZXQgdHJhbnNtaXNzaW9uKCB2YWx1ZSApIHtcclxuXHJcblx0XHRpZiAoIHRoaXMuX3RyYW5zbWlzc2lvbiA+IDAgIT09IHZhbHVlID4gMCApIHtcclxuXHJcblx0XHRcdHRoaXMudmVyc2lvbiArKztcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5fdHJhbnNtaXNzaW9uID0gdmFsdWU7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xyXG5cclxuXHRcdHRoaXMuZGVmaW5lcyA9IHtcclxuXHJcblx0XHRcdCdTVEFOREFSRCc6ICcnLFxyXG5cdFx0XHQnUEhZU0lDQUwnOiAnJ1xyXG5cclxuXHRcdH07XHJcblxyXG5cdFx0dGhpcy5hbmlzb3Ryb3B5ID0gc291cmNlLmFuaXNvdHJvcHk7XHJcblx0XHR0aGlzLmFuaXNvdHJvcHlSb3RhdGlvbiA9IHNvdXJjZS5hbmlzb3Ryb3B5Um90YXRpb247XHJcblx0XHR0aGlzLmFuaXNvdHJvcHlNYXAgPSBzb3VyY2UuYW5pc290cm9weU1hcDtcclxuXHJcblx0XHR0aGlzLmNsZWFyY29hdCA9IHNvdXJjZS5jbGVhcmNvYXQ7XHJcblx0XHR0aGlzLmNsZWFyY29hdE1hcCA9IHNvdXJjZS5jbGVhcmNvYXRNYXA7XHJcblx0XHR0aGlzLmNsZWFyY29hdFJvdWdobmVzcyA9IHNvdXJjZS5jbGVhcmNvYXRSb3VnaG5lc3M7XHJcblx0XHR0aGlzLmNsZWFyY29hdFJvdWdobmVzc01hcCA9IHNvdXJjZS5jbGVhcmNvYXRSb3VnaG5lc3NNYXA7XHJcblx0XHR0aGlzLmNsZWFyY29hdE5vcm1hbE1hcCA9IHNvdXJjZS5jbGVhcmNvYXROb3JtYWxNYXA7XHJcblx0XHR0aGlzLmNsZWFyY29hdE5vcm1hbFNjYWxlLmNvcHkoIHNvdXJjZS5jbGVhcmNvYXROb3JtYWxTY2FsZSApO1xyXG5cclxuXHRcdHRoaXMuaW9yID0gc291cmNlLmlvcjtcclxuXHJcblx0XHR0aGlzLmlyaWRlc2NlbmNlID0gc291cmNlLmlyaWRlc2NlbmNlO1xyXG5cdFx0dGhpcy5pcmlkZXNjZW5jZU1hcCA9IHNvdXJjZS5pcmlkZXNjZW5jZU1hcDtcclxuXHRcdHRoaXMuaXJpZGVzY2VuY2VJT1IgPSBzb3VyY2UuaXJpZGVzY2VuY2VJT1I7XHJcblx0XHR0aGlzLmlyaWRlc2NlbmNlVGhpY2tuZXNzUmFuZ2UgPSBbIC4uLnNvdXJjZS5pcmlkZXNjZW5jZVRoaWNrbmVzc1JhbmdlIF07XHJcblx0XHR0aGlzLmlyaWRlc2NlbmNlVGhpY2tuZXNzTWFwID0gc291cmNlLmlyaWRlc2NlbmNlVGhpY2tuZXNzTWFwO1xyXG5cclxuXHRcdHRoaXMuc2hlZW4gPSBzb3VyY2Uuc2hlZW47XHJcblx0XHR0aGlzLnNoZWVuQ29sb3IuY29weSggc291cmNlLnNoZWVuQ29sb3IgKTtcclxuXHRcdHRoaXMuc2hlZW5Db2xvck1hcCA9IHNvdXJjZS5zaGVlbkNvbG9yTWFwO1xyXG5cdFx0dGhpcy5zaGVlblJvdWdobmVzcyA9IHNvdXJjZS5zaGVlblJvdWdobmVzcztcclxuXHRcdHRoaXMuc2hlZW5Sb3VnaG5lc3NNYXAgPSBzb3VyY2Uuc2hlZW5Sb3VnaG5lc3NNYXA7XHJcblxyXG5cdFx0dGhpcy50cmFuc21pc3Npb24gPSBzb3VyY2UudHJhbnNtaXNzaW9uO1xyXG5cdFx0dGhpcy50cmFuc21pc3Npb25NYXAgPSBzb3VyY2UudHJhbnNtaXNzaW9uTWFwO1xyXG5cclxuXHRcdHRoaXMudGhpY2tuZXNzID0gc291cmNlLnRoaWNrbmVzcztcclxuXHRcdHRoaXMudGhpY2tuZXNzTWFwID0gc291cmNlLnRoaWNrbmVzc01hcDtcclxuXHRcdHRoaXMuYXR0ZW51YXRpb25EaXN0YW5jZSA9IHNvdXJjZS5hdHRlbnVhdGlvbkRpc3RhbmNlO1xyXG5cdFx0dGhpcy5hdHRlbnVhdGlvbkNvbG9yLmNvcHkoIHNvdXJjZS5hdHRlbnVhdGlvbkNvbG9yICk7XHJcblxyXG5cdFx0dGhpcy5zcGVjdWxhckludGVuc2l0eSA9IHNvdXJjZS5zcGVjdWxhckludGVuc2l0eTtcclxuXHRcdHRoaXMuc3BlY3VsYXJJbnRlbnNpdHlNYXAgPSBzb3VyY2Uuc3BlY3VsYXJJbnRlbnNpdHlNYXA7XHJcblx0XHR0aGlzLnNwZWN1bGFyQ29sb3IuY29weSggc291cmNlLnNwZWN1bGFyQ29sb3IgKTtcclxuXHRcdHRoaXMuc3BlY3VsYXJDb2xvck1hcCA9IHNvdXJjZS5zcGVjdWxhckNvbG9yTWFwO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBNZXNoUGh5c2ljYWxNYXRlcmlhbCB9O1xyXG4iLCJpbXBvcnQgeyBNdWx0aXBseU9wZXJhdGlvbiwgVGFuZ2VudFNwYWNlTm9ybWFsTWFwIH0gZnJvbSAnLi4vY29uc3RhbnRzLmpzJztcclxuaW1wb3J0IHsgTWF0ZXJpYWwgfSBmcm9tICcuL01hdGVyaWFsLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yMiB9IGZyb20gJy4uL21hdGgvVmVjdG9yMi5qcyc7XHJcbmltcG9ydCB7IENvbG9yIH0gZnJvbSAnLi4vbWF0aC9Db2xvci5qcyc7XHJcblxyXG5jbGFzcyBNZXNoUGhvbmdNYXRlcmlhbCBleHRlbmRzIE1hdGVyaWFsIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIHBhcmFtZXRlcnMgKSB7XHJcblxyXG5cdFx0c3VwZXIoKTtcclxuXHJcblx0XHR0aGlzLmlzTWVzaFBob25nTWF0ZXJpYWwgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMudHlwZSA9ICdNZXNoUGhvbmdNYXRlcmlhbCc7XHJcblxyXG5cdFx0dGhpcy5jb2xvciA9IG5ldyBDb2xvciggMHhmZmZmZmYgKTsgLy8gZGlmZnVzZVxyXG5cdFx0dGhpcy5zcGVjdWxhciA9IG5ldyBDb2xvciggMHgxMTExMTEgKTtcclxuXHRcdHRoaXMuc2hpbmluZXNzID0gMzA7XHJcblxyXG5cdFx0dGhpcy5tYXAgPSBudWxsO1xyXG5cclxuXHRcdHRoaXMubGlnaHRNYXAgPSBudWxsO1xyXG5cdFx0dGhpcy5saWdodE1hcEludGVuc2l0eSA9IDEuMDtcclxuXHJcblx0XHR0aGlzLmFvTWFwID0gbnVsbDtcclxuXHRcdHRoaXMuYW9NYXBJbnRlbnNpdHkgPSAxLjA7XHJcblxyXG5cdFx0dGhpcy5lbWlzc2l2ZSA9IG5ldyBDb2xvciggMHgwMDAwMDAgKTtcclxuXHRcdHRoaXMuZW1pc3NpdmVJbnRlbnNpdHkgPSAxLjA7XHJcblx0XHR0aGlzLmVtaXNzaXZlTWFwID0gbnVsbDtcclxuXHJcblx0XHR0aGlzLmJ1bXBNYXAgPSBudWxsO1xyXG5cdFx0dGhpcy5idW1wU2NhbGUgPSAxO1xyXG5cclxuXHRcdHRoaXMubm9ybWFsTWFwID0gbnVsbDtcclxuXHRcdHRoaXMubm9ybWFsTWFwVHlwZSA9IFRhbmdlbnRTcGFjZU5vcm1hbE1hcDtcclxuXHRcdHRoaXMubm9ybWFsU2NhbGUgPSBuZXcgVmVjdG9yMiggMSwgMSApO1xyXG5cclxuXHRcdHRoaXMuZGlzcGxhY2VtZW50TWFwID0gbnVsbDtcclxuXHRcdHRoaXMuZGlzcGxhY2VtZW50U2NhbGUgPSAxO1xyXG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRCaWFzID0gMDtcclxuXHJcblx0XHR0aGlzLnNwZWN1bGFyTWFwID0gbnVsbDtcclxuXHJcblx0XHR0aGlzLmFscGhhTWFwID0gbnVsbDtcclxuXHJcblx0XHR0aGlzLmVudk1hcCA9IG51bGw7XHJcblx0XHR0aGlzLmNvbWJpbmUgPSBNdWx0aXBseU9wZXJhdGlvbjtcclxuXHRcdHRoaXMucmVmbGVjdGl2aXR5ID0gMTtcclxuXHRcdHRoaXMucmVmcmFjdGlvblJhdGlvID0gMC45ODtcclxuXHJcblx0XHR0aGlzLndpcmVmcmFtZSA9IGZhbHNlO1xyXG5cdFx0dGhpcy53aXJlZnJhbWVMaW5ld2lkdGggPSAxO1xyXG5cdFx0dGhpcy53aXJlZnJhbWVMaW5lY2FwID0gJ3JvdW5kJztcclxuXHRcdHRoaXMud2lyZWZyYW1lTGluZWpvaW4gPSAncm91bmQnO1xyXG5cclxuXHRcdHRoaXMuZmxhdFNoYWRpbmcgPSBmYWxzZTtcclxuXHJcblx0XHR0aGlzLmZvZyA9IHRydWU7XHJcblxyXG5cdFx0dGhpcy5zZXRWYWx1ZXMoIHBhcmFtZXRlcnMgKTtcclxuXHJcblx0fVxyXG5cclxuXHRjb3B5KCBzb3VyY2UgKSB7XHJcblxyXG5cdFx0c3VwZXIuY29weSggc291cmNlICk7XHJcblxyXG5cdFx0dGhpcy5jb2xvci5jb3B5KCBzb3VyY2UuY29sb3IgKTtcclxuXHRcdHRoaXMuc3BlY3VsYXIuY29weSggc291cmNlLnNwZWN1bGFyICk7XHJcblx0XHR0aGlzLnNoaW5pbmVzcyA9IHNvdXJjZS5zaGluaW5lc3M7XHJcblxyXG5cdFx0dGhpcy5tYXAgPSBzb3VyY2UubWFwO1xyXG5cclxuXHRcdHRoaXMubGlnaHRNYXAgPSBzb3VyY2UubGlnaHRNYXA7XHJcblx0XHR0aGlzLmxpZ2h0TWFwSW50ZW5zaXR5ID0gc291cmNlLmxpZ2h0TWFwSW50ZW5zaXR5O1xyXG5cclxuXHRcdHRoaXMuYW9NYXAgPSBzb3VyY2UuYW9NYXA7XHJcblx0XHR0aGlzLmFvTWFwSW50ZW5zaXR5ID0gc291cmNlLmFvTWFwSW50ZW5zaXR5O1xyXG5cclxuXHRcdHRoaXMuZW1pc3NpdmUuY29weSggc291cmNlLmVtaXNzaXZlICk7XHJcblx0XHR0aGlzLmVtaXNzaXZlTWFwID0gc291cmNlLmVtaXNzaXZlTWFwO1xyXG5cdFx0dGhpcy5lbWlzc2l2ZUludGVuc2l0eSA9IHNvdXJjZS5lbWlzc2l2ZUludGVuc2l0eTtcclxuXHJcblx0XHR0aGlzLmJ1bXBNYXAgPSBzb3VyY2UuYnVtcE1hcDtcclxuXHRcdHRoaXMuYnVtcFNjYWxlID0gc291cmNlLmJ1bXBTY2FsZTtcclxuXHJcblx0XHR0aGlzLm5vcm1hbE1hcCA9IHNvdXJjZS5ub3JtYWxNYXA7XHJcblx0XHR0aGlzLm5vcm1hbE1hcFR5cGUgPSBzb3VyY2Uubm9ybWFsTWFwVHlwZTtcclxuXHRcdHRoaXMubm9ybWFsU2NhbGUuY29weSggc291cmNlLm5vcm1hbFNjYWxlICk7XHJcblxyXG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRNYXAgPSBzb3VyY2UuZGlzcGxhY2VtZW50TWFwO1xyXG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRTY2FsZSA9IHNvdXJjZS5kaXNwbGFjZW1lbnRTY2FsZTtcclxuXHRcdHRoaXMuZGlzcGxhY2VtZW50QmlhcyA9IHNvdXJjZS5kaXNwbGFjZW1lbnRCaWFzO1xyXG5cclxuXHRcdHRoaXMuc3BlY3VsYXJNYXAgPSBzb3VyY2Uuc3BlY3VsYXJNYXA7XHJcblxyXG5cdFx0dGhpcy5hbHBoYU1hcCA9IHNvdXJjZS5hbHBoYU1hcDtcclxuXHJcblx0XHR0aGlzLmVudk1hcCA9IHNvdXJjZS5lbnZNYXA7XHJcblx0XHR0aGlzLmNvbWJpbmUgPSBzb3VyY2UuY29tYmluZTtcclxuXHRcdHRoaXMucmVmbGVjdGl2aXR5ID0gc291cmNlLnJlZmxlY3Rpdml0eTtcclxuXHRcdHRoaXMucmVmcmFjdGlvblJhdGlvID0gc291cmNlLnJlZnJhY3Rpb25SYXRpbztcclxuXHJcblx0XHR0aGlzLndpcmVmcmFtZSA9IHNvdXJjZS53aXJlZnJhbWU7XHJcblx0XHR0aGlzLndpcmVmcmFtZUxpbmV3aWR0aCA9IHNvdXJjZS53aXJlZnJhbWVMaW5ld2lkdGg7XHJcblx0XHR0aGlzLndpcmVmcmFtZUxpbmVjYXAgPSBzb3VyY2Uud2lyZWZyYW1lTGluZWNhcDtcclxuXHRcdHRoaXMud2lyZWZyYW1lTGluZWpvaW4gPSBzb3VyY2Uud2lyZWZyYW1lTGluZWpvaW47XHJcblxyXG5cdFx0dGhpcy5mbGF0U2hhZGluZyA9IHNvdXJjZS5mbGF0U2hhZGluZztcclxuXHJcblx0XHR0aGlzLmZvZyA9IHNvdXJjZS5mb2c7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IE1lc2hQaG9uZ01hdGVyaWFsIH07XHJcbiIsImltcG9ydCB7IFRhbmdlbnRTcGFjZU5vcm1hbE1hcCB9IGZyb20gJy4uL2NvbnN0YW50cy5qcyc7XHJcbmltcG9ydCB7IE1hdGVyaWFsIH0gZnJvbSAnLi9NYXRlcmlhbC5qcyc7XHJcbmltcG9ydCB7IFZlY3RvcjIgfSBmcm9tICcuLi9tYXRoL1ZlY3RvcjIuanMnO1xyXG5pbXBvcnQgeyBDb2xvciB9IGZyb20gJy4uL21hdGgvQ29sb3IuanMnO1xyXG5cclxuY2xhc3MgTWVzaFRvb25NYXRlcmlhbCBleHRlbmRzIE1hdGVyaWFsIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIHBhcmFtZXRlcnMgKSB7XHJcblxyXG5cdFx0c3VwZXIoKTtcclxuXHJcblx0XHR0aGlzLmlzTWVzaFRvb25NYXRlcmlhbCA9IHRydWU7XHJcblxyXG5cdFx0dGhpcy5kZWZpbmVzID0geyAnVE9PTic6ICcnIH07XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ01lc2hUb29uTWF0ZXJpYWwnO1xyXG5cclxuXHRcdHRoaXMuY29sb3IgPSBuZXcgQ29sb3IoIDB4ZmZmZmZmICk7XHJcblxyXG5cdFx0dGhpcy5tYXAgPSBudWxsO1xyXG5cdFx0dGhpcy5ncmFkaWVudE1hcCA9IG51bGw7XHJcblxyXG5cdFx0dGhpcy5saWdodE1hcCA9IG51bGw7XHJcblx0XHR0aGlzLmxpZ2h0TWFwSW50ZW5zaXR5ID0gMS4wO1xyXG5cclxuXHRcdHRoaXMuYW9NYXAgPSBudWxsO1xyXG5cdFx0dGhpcy5hb01hcEludGVuc2l0eSA9IDEuMDtcclxuXHJcblx0XHR0aGlzLmVtaXNzaXZlID0gbmV3IENvbG9yKCAweDAwMDAwMCApO1xyXG5cdFx0dGhpcy5lbWlzc2l2ZUludGVuc2l0eSA9IDEuMDtcclxuXHRcdHRoaXMuZW1pc3NpdmVNYXAgPSBudWxsO1xyXG5cclxuXHRcdHRoaXMuYnVtcE1hcCA9IG51bGw7XHJcblx0XHR0aGlzLmJ1bXBTY2FsZSA9IDE7XHJcblxyXG5cdFx0dGhpcy5ub3JtYWxNYXAgPSBudWxsO1xyXG5cdFx0dGhpcy5ub3JtYWxNYXBUeXBlID0gVGFuZ2VudFNwYWNlTm9ybWFsTWFwO1xyXG5cdFx0dGhpcy5ub3JtYWxTY2FsZSA9IG5ldyBWZWN0b3IyKCAxLCAxICk7XHJcblxyXG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRNYXAgPSBudWxsO1xyXG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRTY2FsZSA9IDE7XHJcblx0XHR0aGlzLmRpc3BsYWNlbWVudEJpYXMgPSAwO1xyXG5cclxuXHRcdHRoaXMuYWxwaGFNYXAgPSBudWxsO1xyXG5cclxuXHRcdHRoaXMud2lyZWZyYW1lID0gZmFsc2U7XHJcblx0XHR0aGlzLndpcmVmcmFtZUxpbmV3aWR0aCA9IDE7XHJcblx0XHR0aGlzLndpcmVmcmFtZUxpbmVjYXAgPSAncm91bmQnO1xyXG5cdFx0dGhpcy53aXJlZnJhbWVMaW5lam9pbiA9ICdyb3VuZCc7XHJcblxyXG5cdFx0dGhpcy5mb2cgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMuc2V0VmFsdWVzKCBwYXJhbWV0ZXJzICk7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xyXG5cclxuXHRcdHRoaXMuY29sb3IuY29weSggc291cmNlLmNvbG9yICk7XHJcblxyXG5cdFx0dGhpcy5tYXAgPSBzb3VyY2UubWFwO1xyXG5cdFx0dGhpcy5ncmFkaWVudE1hcCA9IHNvdXJjZS5ncmFkaWVudE1hcDtcclxuXHJcblx0XHR0aGlzLmxpZ2h0TWFwID0gc291cmNlLmxpZ2h0TWFwO1xyXG5cdFx0dGhpcy5saWdodE1hcEludGVuc2l0eSA9IHNvdXJjZS5saWdodE1hcEludGVuc2l0eTtcclxuXHJcblx0XHR0aGlzLmFvTWFwID0gc291cmNlLmFvTWFwO1xyXG5cdFx0dGhpcy5hb01hcEludGVuc2l0eSA9IHNvdXJjZS5hb01hcEludGVuc2l0eTtcclxuXHJcblx0XHR0aGlzLmVtaXNzaXZlLmNvcHkoIHNvdXJjZS5lbWlzc2l2ZSApO1xyXG5cdFx0dGhpcy5lbWlzc2l2ZU1hcCA9IHNvdXJjZS5lbWlzc2l2ZU1hcDtcclxuXHRcdHRoaXMuZW1pc3NpdmVJbnRlbnNpdHkgPSBzb3VyY2UuZW1pc3NpdmVJbnRlbnNpdHk7XHJcblxyXG5cdFx0dGhpcy5idW1wTWFwID0gc291cmNlLmJ1bXBNYXA7XHJcblx0XHR0aGlzLmJ1bXBTY2FsZSA9IHNvdXJjZS5idW1wU2NhbGU7XHJcblxyXG5cdFx0dGhpcy5ub3JtYWxNYXAgPSBzb3VyY2Uubm9ybWFsTWFwO1xyXG5cdFx0dGhpcy5ub3JtYWxNYXBUeXBlID0gc291cmNlLm5vcm1hbE1hcFR5cGU7XHJcblx0XHR0aGlzLm5vcm1hbFNjYWxlLmNvcHkoIHNvdXJjZS5ub3JtYWxTY2FsZSApO1xyXG5cclxuXHRcdHRoaXMuZGlzcGxhY2VtZW50TWFwID0gc291cmNlLmRpc3BsYWNlbWVudE1hcDtcclxuXHRcdHRoaXMuZGlzcGxhY2VtZW50U2NhbGUgPSBzb3VyY2UuZGlzcGxhY2VtZW50U2NhbGU7XHJcblx0XHR0aGlzLmRpc3BsYWNlbWVudEJpYXMgPSBzb3VyY2UuZGlzcGxhY2VtZW50QmlhcztcclxuXHJcblx0XHR0aGlzLmFscGhhTWFwID0gc291cmNlLmFscGhhTWFwO1xyXG5cclxuXHRcdHRoaXMud2lyZWZyYW1lID0gc291cmNlLndpcmVmcmFtZTtcclxuXHRcdHRoaXMud2lyZWZyYW1lTGluZXdpZHRoID0gc291cmNlLndpcmVmcmFtZUxpbmV3aWR0aDtcclxuXHRcdHRoaXMud2lyZWZyYW1lTGluZWNhcCA9IHNvdXJjZS53aXJlZnJhbWVMaW5lY2FwO1xyXG5cdFx0dGhpcy53aXJlZnJhbWVMaW5lam9pbiA9IHNvdXJjZS53aXJlZnJhbWVMaW5lam9pbjtcclxuXHJcblx0XHR0aGlzLmZvZyA9IHNvdXJjZS5mb2c7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IE1lc2hUb29uTWF0ZXJpYWwgfTtcclxuIiwiaW1wb3J0IHsgVGFuZ2VudFNwYWNlTm9ybWFsTWFwIH0gZnJvbSAnLi4vY29uc3RhbnRzLmpzJztcclxuaW1wb3J0IHsgTWF0ZXJpYWwgfSBmcm9tICcuL01hdGVyaWFsLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yMiB9IGZyb20gJy4uL21hdGgvVmVjdG9yMi5qcyc7XHJcblxyXG5jbGFzcyBNZXNoTm9ybWFsTWF0ZXJpYWwgZXh0ZW5kcyBNYXRlcmlhbCB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBwYXJhbWV0ZXJzICkge1xyXG5cclxuXHRcdHN1cGVyKCk7XHJcblxyXG5cdFx0dGhpcy5pc01lc2hOb3JtYWxNYXRlcmlhbCA9IHRydWU7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ01lc2hOb3JtYWxNYXRlcmlhbCc7XHJcblxyXG5cdFx0dGhpcy5idW1wTWFwID0gbnVsbDtcclxuXHRcdHRoaXMuYnVtcFNjYWxlID0gMTtcclxuXHJcblx0XHR0aGlzLm5vcm1hbE1hcCA9IG51bGw7XHJcblx0XHR0aGlzLm5vcm1hbE1hcFR5cGUgPSBUYW5nZW50U3BhY2VOb3JtYWxNYXA7XHJcblx0XHR0aGlzLm5vcm1hbFNjYWxlID0gbmV3IFZlY3RvcjIoIDEsIDEgKTtcclxuXHJcblx0XHR0aGlzLmRpc3BsYWNlbWVudE1hcCA9IG51bGw7XHJcblx0XHR0aGlzLmRpc3BsYWNlbWVudFNjYWxlID0gMTtcclxuXHRcdHRoaXMuZGlzcGxhY2VtZW50QmlhcyA9IDA7XHJcblxyXG5cdFx0dGhpcy53aXJlZnJhbWUgPSBmYWxzZTtcclxuXHRcdHRoaXMud2lyZWZyYW1lTGluZXdpZHRoID0gMTtcclxuXHJcblx0XHR0aGlzLmZsYXRTaGFkaW5nID0gZmFsc2U7XHJcblxyXG5cdFx0dGhpcy5zZXRWYWx1ZXMoIHBhcmFtZXRlcnMgKTtcclxuXHJcblx0fVxyXG5cclxuXHRjb3B5KCBzb3VyY2UgKSB7XHJcblxyXG5cdFx0c3VwZXIuY29weSggc291cmNlICk7XHJcblxyXG5cdFx0dGhpcy5idW1wTWFwID0gc291cmNlLmJ1bXBNYXA7XHJcblx0XHR0aGlzLmJ1bXBTY2FsZSA9IHNvdXJjZS5idW1wU2NhbGU7XHJcblxyXG5cdFx0dGhpcy5ub3JtYWxNYXAgPSBzb3VyY2Uubm9ybWFsTWFwO1xyXG5cdFx0dGhpcy5ub3JtYWxNYXBUeXBlID0gc291cmNlLm5vcm1hbE1hcFR5cGU7XHJcblx0XHR0aGlzLm5vcm1hbFNjYWxlLmNvcHkoIHNvdXJjZS5ub3JtYWxTY2FsZSApO1xyXG5cclxuXHRcdHRoaXMuZGlzcGxhY2VtZW50TWFwID0gc291cmNlLmRpc3BsYWNlbWVudE1hcDtcclxuXHRcdHRoaXMuZGlzcGxhY2VtZW50U2NhbGUgPSBzb3VyY2UuZGlzcGxhY2VtZW50U2NhbGU7XHJcblx0XHR0aGlzLmRpc3BsYWNlbWVudEJpYXMgPSBzb3VyY2UuZGlzcGxhY2VtZW50QmlhcztcclxuXHJcblx0XHR0aGlzLndpcmVmcmFtZSA9IHNvdXJjZS53aXJlZnJhbWU7XHJcblx0XHR0aGlzLndpcmVmcmFtZUxpbmV3aWR0aCA9IHNvdXJjZS53aXJlZnJhbWVMaW5ld2lkdGg7XHJcblxyXG5cdFx0dGhpcy5mbGF0U2hhZGluZyA9IHNvdXJjZS5mbGF0U2hhZGluZztcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgTWVzaE5vcm1hbE1hdGVyaWFsIH07XHJcbiIsImltcG9ydCB7IE11bHRpcGx5T3BlcmF0aW9uLCBUYW5nZW50U3BhY2VOb3JtYWxNYXAgfSBmcm9tICcuLi9jb25zdGFudHMuanMnO1xyXG5pbXBvcnQgeyBNYXRlcmlhbCB9IGZyb20gJy4vTWF0ZXJpYWwuanMnO1xyXG5pbXBvcnQgeyBWZWN0b3IyIH0gZnJvbSAnLi4vbWF0aC9WZWN0b3IyLmpzJztcclxuaW1wb3J0IHsgQ29sb3IgfSBmcm9tICcuLi9tYXRoL0NvbG9yLmpzJztcclxuXHJcbmNsYXNzIE1lc2hMYW1iZXJ0TWF0ZXJpYWwgZXh0ZW5kcyBNYXRlcmlhbCB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBwYXJhbWV0ZXJzICkge1xyXG5cclxuXHRcdHN1cGVyKCk7XHJcblxyXG5cdFx0dGhpcy5pc01lc2hMYW1iZXJ0TWF0ZXJpYWwgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMudHlwZSA9ICdNZXNoTGFtYmVydE1hdGVyaWFsJztcclxuXHJcblx0XHR0aGlzLmNvbG9yID0gbmV3IENvbG9yKCAweGZmZmZmZiApOyAvLyBkaWZmdXNlXHJcblxyXG5cdFx0dGhpcy5tYXAgPSBudWxsO1xyXG5cclxuXHRcdHRoaXMubGlnaHRNYXAgPSBudWxsO1xyXG5cdFx0dGhpcy5saWdodE1hcEludGVuc2l0eSA9IDEuMDtcclxuXHJcblx0XHR0aGlzLmFvTWFwID0gbnVsbDtcclxuXHRcdHRoaXMuYW9NYXBJbnRlbnNpdHkgPSAxLjA7XHJcblxyXG5cdFx0dGhpcy5lbWlzc2l2ZSA9IG5ldyBDb2xvciggMHgwMDAwMDAgKTtcclxuXHRcdHRoaXMuZW1pc3NpdmVJbnRlbnNpdHkgPSAxLjA7XHJcblx0XHR0aGlzLmVtaXNzaXZlTWFwID0gbnVsbDtcclxuXHJcblx0XHR0aGlzLmJ1bXBNYXAgPSBudWxsO1xyXG5cdFx0dGhpcy5idW1wU2NhbGUgPSAxO1xyXG5cclxuXHRcdHRoaXMubm9ybWFsTWFwID0gbnVsbDtcclxuXHRcdHRoaXMubm9ybWFsTWFwVHlwZSA9IFRhbmdlbnRTcGFjZU5vcm1hbE1hcDtcclxuXHRcdHRoaXMubm9ybWFsU2NhbGUgPSBuZXcgVmVjdG9yMiggMSwgMSApO1xyXG5cclxuXHRcdHRoaXMuZGlzcGxhY2VtZW50TWFwID0gbnVsbDtcclxuXHRcdHRoaXMuZGlzcGxhY2VtZW50U2NhbGUgPSAxO1xyXG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRCaWFzID0gMDtcclxuXHJcblx0XHR0aGlzLnNwZWN1bGFyTWFwID0gbnVsbDtcclxuXHJcblx0XHR0aGlzLmFscGhhTWFwID0gbnVsbDtcclxuXHJcblx0XHR0aGlzLmVudk1hcCA9IG51bGw7XHJcblx0XHR0aGlzLmNvbWJpbmUgPSBNdWx0aXBseU9wZXJhdGlvbjtcclxuXHRcdHRoaXMucmVmbGVjdGl2aXR5ID0gMTtcclxuXHRcdHRoaXMucmVmcmFjdGlvblJhdGlvID0gMC45ODtcclxuXHJcblx0XHR0aGlzLndpcmVmcmFtZSA9IGZhbHNlO1xyXG5cdFx0dGhpcy53aXJlZnJhbWVMaW5ld2lkdGggPSAxO1xyXG5cdFx0dGhpcy53aXJlZnJhbWVMaW5lY2FwID0gJ3JvdW5kJztcclxuXHRcdHRoaXMud2lyZWZyYW1lTGluZWpvaW4gPSAncm91bmQnO1xyXG5cclxuXHRcdHRoaXMuZmxhdFNoYWRpbmcgPSBmYWxzZTtcclxuXHJcblx0XHR0aGlzLmZvZyA9IHRydWU7XHJcblxyXG5cdFx0dGhpcy5zZXRWYWx1ZXMoIHBhcmFtZXRlcnMgKTtcclxuXHJcblx0fVxyXG5cclxuXHRjb3B5KCBzb3VyY2UgKSB7XHJcblxyXG5cdFx0c3VwZXIuY29weSggc291cmNlICk7XHJcblxyXG5cdFx0dGhpcy5jb2xvci5jb3B5KCBzb3VyY2UuY29sb3IgKTtcclxuXHJcblx0XHR0aGlzLm1hcCA9IHNvdXJjZS5tYXA7XHJcblxyXG5cdFx0dGhpcy5saWdodE1hcCA9IHNvdXJjZS5saWdodE1hcDtcclxuXHRcdHRoaXMubGlnaHRNYXBJbnRlbnNpdHkgPSBzb3VyY2UubGlnaHRNYXBJbnRlbnNpdHk7XHJcblxyXG5cdFx0dGhpcy5hb01hcCA9IHNvdXJjZS5hb01hcDtcclxuXHRcdHRoaXMuYW9NYXBJbnRlbnNpdHkgPSBzb3VyY2UuYW9NYXBJbnRlbnNpdHk7XHJcblxyXG5cdFx0dGhpcy5lbWlzc2l2ZS5jb3B5KCBzb3VyY2UuZW1pc3NpdmUgKTtcclxuXHRcdHRoaXMuZW1pc3NpdmVNYXAgPSBzb3VyY2UuZW1pc3NpdmVNYXA7XHJcblx0XHR0aGlzLmVtaXNzaXZlSW50ZW5zaXR5ID0gc291cmNlLmVtaXNzaXZlSW50ZW5zaXR5O1xyXG5cclxuXHRcdHRoaXMuYnVtcE1hcCA9IHNvdXJjZS5idW1wTWFwO1xyXG5cdFx0dGhpcy5idW1wU2NhbGUgPSBzb3VyY2UuYnVtcFNjYWxlO1xyXG5cclxuXHRcdHRoaXMubm9ybWFsTWFwID0gc291cmNlLm5vcm1hbE1hcDtcclxuXHRcdHRoaXMubm9ybWFsTWFwVHlwZSA9IHNvdXJjZS5ub3JtYWxNYXBUeXBlO1xyXG5cdFx0dGhpcy5ub3JtYWxTY2FsZS5jb3B5KCBzb3VyY2Uubm9ybWFsU2NhbGUgKTtcclxuXHJcblx0XHR0aGlzLmRpc3BsYWNlbWVudE1hcCA9IHNvdXJjZS5kaXNwbGFjZW1lbnRNYXA7XHJcblx0XHR0aGlzLmRpc3BsYWNlbWVudFNjYWxlID0gc291cmNlLmRpc3BsYWNlbWVudFNjYWxlO1xyXG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRCaWFzID0gc291cmNlLmRpc3BsYWNlbWVudEJpYXM7XHJcblxyXG5cdFx0dGhpcy5zcGVjdWxhck1hcCA9IHNvdXJjZS5zcGVjdWxhck1hcDtcclxuXHJcblx0XHR0aGlzLmFscGhhTWFwID0gc291cmNlLmFscGhhTWFwO1xyXG5cclxuXHRcdHRoaXMuZW52TWFwID0gc291cmNlLmVudk1hcDtcclxuXHRcdHRoaXMuY29tYmluZSA9IHNvdXJjZS5jb21iaW5lO1xyXG5cdFx0dGhpcy5yZWZsZWN0aXZpdHkgPSBzb3VyY2UucmVmbGVjdGl2aXR5O1xyXG5cdFx0dGhpcy5yZWZyYWN0aW9uUmF0aW8gPSBzb3VyY2UucmVmcmFjdGlvblJhdGlvO1xyXG5cclxuXHRcdHRoaXMud2lyZWZyYW1lID0gc291cmNlLndpcmVmcmFtZTtcclxuXHRcdHRoaXMud2lyZWZyYW1lTGluZXdpZHRoID0gc291cmNlLndpcmVmcmFtZUxpbmV3aWR0aDtcclxuXHRcdHRoaXMud2lyZWZyYW1lTGluZWNhcCA9IHNvdXJjZS53aXJlZnJhbWVMaW5lY2FwO1xyXG5cdFx0dGhpcy53aXJlZnJhbWVMaW5lam9pbiA9IHNvdXJjZS53aXJlZnJhbWVMaW5lam9pbjtcclxuXHJcblx0XHR0aGlzLmZsYXRTaGFkaW5nID0gc291cmNlLmZsYXRTaGFkaW5nO1xyXG5cclxuXHRcdHRoaXMuZm9nID0gc291cmNlLmZvZztcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgTWVzaExhbWJlcnRNYXRlcmlhbCB9O1xyXG4iLCJpbXBvcnQgeyBUYW5nZW50U3BhY2VOb3JtYWxNYXAgfSBmcm9tICcuLi9jb25zdGFudHMuanMnO1xyXG5pbXBvcnQgeyBNYXRlcmlhbCB9IGZyb20gJy4vTWF0ZXJpYWwuanMnO1xyXG5pbXBvcnQgeyBWZWN0b3IyIH0gZnJvbSAnLi4vbWF0aC9WZWN0b3IyLmpzJztcclxuaW1wb3J0IHsgQ29sb3IgfSBmcm9tICcuLi9tYXRoL0NvbG9yLmpzJztcclxuXHJcbmNsYXNzIE1lc2hNYXRjYXBNYXRlcmlhbCBleHRlbmRzIE1hdGVyaWFsIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIHBhcmFtZXRlcnMgKSB7XHJcblxyXG5cdFx0c3VwZXIoKTtcclxuXHJcblx0XHR0aGlzLmlzTWVzaE1hdGNhcE1hdGVyaWFsID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLmRlZmluZXMgPSB7ICdNQVRDQVAnOiAnJyB9O1xyXG5cclxuXHRcdHRoaXMudHlwZSA9ICdNZXNoTWF0Y2FwTWF0ZXJpYWwnO1xyXG5cclxuXHRcdHRoaXMuY29sb3IgPSBuZXcgQ29sb3IoIDB4ZmZmZmZmICk7IC8vIGRpZmZ1c2VcclxuXHJcblx0XHR0aGlzLm1hdGNhcCA9IG51bGw7XHJcblxyXG5cdFx0dGhpcy5tYXAgPSBudWxsO1xyXG5cclxuXHRcdHRoaXMuYnVtcE1hcCA9IG51bGw7XHJcblx0XHR0aGlzLmJ1bXBTY2FsZSA9IDE7XHJcblxyXG5cdFx0dGhpcy5ub3JtYWxNYXAgPSBudWxsO1xyXG5cdFx0dGhpcy5ub3JtYWxNYXBUeXBlID0gVGFuZ2VudFNwYWNlTm9ybWFsTWFwO1xyXG5cdFx0dGhpcy5ub3JtYWxTY2FsZSA9IG5ldyBWZWN0b3IyKCAxLCAxICk7XHJcblxyXG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRNYXAgPSBudWxsO1xyXG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRTY2FsZSA9IDE7XHJcblx0XHR0aGlzLmRpc3BsYWNlbWVudEJpYXMgPSAwO1xyXG5cclxuXHRcdHRoaXMuYWxwaGFNYXAgPSBudWxsO1xyXG5cclxuXHRcdHRoaXMuZmxhdFNoYWRpbmcgPSBmYWxzZTtcclxuXHJcblx0XHR0aGlzLmZvZyA9IHRydWU7XHJcblxyXG5cdFx0dGhpcy5zZXRWYWx1ZXMoIHBhcmFtZXRlcnMgKTtcclxuXHJcblx0fVxyXG5cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xyXG5cclxuXHRcdHRoaXMuZGVmaW5lcyA9IHsgJ01BVENBUCc6ICcnIH07XHJcblxyXG5cdFx0dGhpcy5jb2xvci5jb3B5KCBzb3VyY2UuY29sb3IgKTtcclxuXHJcblx0XHR0aGlzLm1hdGNhcCA9IHNvdXJjZS5tYXRjYXA7XHJcblxyXG5cdFx0dGhpcy5tYXAgPSBzb3VyY2UubWFwO1xyXG5cclxuXHRcdHRoaXMuYnVtcE1hcCA9IHNvdXJjZS5idW1wTWFwO1xyXG5cdFx0dGhpcy5idW1wU2NhbGUgPSBzb3VyY2UuYnVtcFNjYWxlO1xyXG5cclxuXHRcdHRoaXMubm9ybWFsTWFwID0gc291cmNlLm5vcm1hbE1hcDtcclxuXHRcdHRoaXMubm9ybWFsTWFwVHlwZSA9IHNvdXJjZS5ub3JtYWxNYXBUeXBlO1xyXG5cdFx0dGhpcy5ub3JtYWxTY2FsZS5jb3B5KCBzb3VyY2Uubm9ybWFsU2NhbGUgKTtcclxuXHJcblx0XHR0aGlzLmRpc3BsYWNlbWVudE1hcCA9IHNvdXJjZS5kaXNwbGFjZW1lbnRNYXA7XHJcblx0XHR0aGlzLmRpc3BsYWNlbWVudFNjYWxlID0gc291cmNlLmRpc3BsYWNlbWVudFNjYWxlO1xyXG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRCaWFzID0gc291cmNlLmRpc3BsYWNlbWVudEJpYXM7XHJcblxyXG5cdFx0dGhpcy5hbHBoYU1hcCA9IHNvdXJjZS5hbHBoYU1hcDtcclxuXHJcblx0XHR0aGlzLmZsYXRTaGFkaW5nID0gc291cmNlLmZsYXRTaGFkaW5nO1xyXG5cclxuXHRcdHRoaXMuZm9nID0gc291cmNlLmZvZztcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgTWVzaE1hdGNhcE1hdGVyaWFsIH07XHJcbiIsImltcG9ydCB7IExpbmVCYXNpY01hdGVyaWFsIH0gZnJvbSAnLi9MaW5lQmFzaWNNYXRlcmlhbC5qcyc7XHJcblxyXG5jbGFzcyBMaW5lRGFzaGVkTWF0ZXJpYWwgZXh0ZW5kcyBMaW5lQmFzaWNNYXRlcmlhbCB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBwYXJhbWV0ZXJzICkge1xyXG5cclxuXHRcdHN1cGVyKCk7XHJcblxyXG5cdFx0dGhpcy5pc0xpbmVEYXNoZWRNYXRlcmlhbCA9IHRydWU7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ0xpbmVEYXNoZWRNYXRlcmlhbCc7XHJcblxyXG5cdFx0dGhpcy5zY2FsZSA9IDE7XHJcblx0XHR0aGlzLmRhc2hTaXplID0gMztcclxuXHRcdHRoaXMuZ2FwU2l6ZSA9IDE7XHJcblxyXG5cdFx0dGhpcy5zZXRWYWx1ZXMoIHBhcmFtZXRlcnMgKTtcclxuXHJcblx0fVxyXG5cclxuXHRjb3B5KCBzb3VyY2UgKSB7XHJcblxyXG5cdFx0c3VwZXIuY29weSggc291cmNlICk7XHJcblxyXG5cdFx0dGhpcy5zY2FsZSA9IHNvdXJjZS5zY2FsZTtcclxuXHRcdHRoaXMuZGFzaFNpemUgPSBzb3VyY2UuZGFzaFNpemU7XHJcblx0XHR0aGlzLmdhcFNpemUgPSBzb3VyY2UuZ2FwU2l6ZTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgTGluZURhc2hlZE1hdGVyaWFsIH07XHJcbiIsImltcG9ydCB7IFF1YXRlcm5pb24gfSBmcm9tICcuLi9tYXRoL1F1YXRlcm5pb24uanMnO1xyXG5pbXBvcnQgeyBBZGRpdGl2ZUFuaW1hdGlvbkJsZW5kTW9kZSB9IGZyb20gJy4uL2NvbnN0YW50cy5qcyc7XHJcblxyXG4vLyBjb252ZXJ0cyBhbiBhcnJheSB0byBhIHNwZWNpZmljIHR5cGVcclxuZnVuY3Rpb24gY29udmVydEFycmF5KCBhcnJheSwgdHlwZSwgZm9yY2VDbG9uZSApIHtcclxuXHJcblx0aWYgKCAhIGFycmF5IHx8IC8vIGxldCAndW5kZWZpbmVkJyBhbmQgJ251bGwnIHBhc3NcclxuXHRcdCEgZm9yY2VDbG9uZSAmJiBhcnJheS5jb25zdHJ1Y3RvciA9PT0gdHlwZSApIHJldHVybiBhcnJheTtcclxuXHJcblx0aWYgKCB0eXBlb2YgdHlwZS5CWVRFU19QRVJfRUxFTUVOVCA9PT0gJ251bWJlcicgKSB7XHJcblxyXG5cdFx0cmV0dXJuIG5ldyB0eXBlKCBhcnJheSApOyAvLyBjcmVhdGUgdHlwZWQgYXJyYXlcclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoIGFycmF5ICk7IC8vIGNyZWF0ZSBBcnJheVxyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gaXNUeXBlZEFycmF5KCBvYmplY3QgKSB7XHJcblxyXG5cdHJldHVybiBBcnJheUJ1ZmZlci5pc1ZpZXcoIG9iamVjdCApICYmXHJcblx0XHQhICggb2JqZWN0IGluc3RhbmNlb2YgRGF0YVZpZXcgKTtcclxuXHJcbn1cclxuXHJcbi8vIHJldHVybnMgYW4gYXJyYXkgYnkgd2hpY2ggdGltZXMgYW5kIHZhbHVlcyBjYW4gYmUgc29ydGVkXHJcbmZ1bmN0aW9uIGdldEtleWZyYW1lT3JkZXIoIHRpbWVzICkge1xyXG5cclxuXHRmdW5jdGlvbiBjb21wYXJlVGltZSggaSwgaiApIHtcclxuXHJcblx0XHRyZXR1cm4gdGltZXNbIGkgXSAtIHRpbWVzWyBqIF07XHJcblxyXG5cdH1cclxuXHJcblx0Y29uc3QgbiA9IHRpbWVzLmxlbmd0aDtcclxuXHRjb25zdCByZXN1bHQgPSBuZXcgQXJyYXkoIG4gKTtcclxuXHRmb3IgKCBsZXQgaSA9IDA7IGkgIT09IG47ICsrIGkgKSByZXN1bHRbIGkgXSA9IGk7XHJcblxyXG5cdHJlc3VsdC5zb3J0KCBjb21wYXJlVGltZSApO1xyXG5cclxuXHRyZXR1cm4gcmVzdWx0O1xyXG5cclxufVxyXG5cclxuLy8gdXNlcyB0aGUgYXJyYXkgcHJldmlvdXNseSByZXR1cm5lZCBieSAnZ2V0S2V5ZnJhbWVPcmRlcicgdG8gc29ydCBkYXRhXHJcbmZ1bmN0aW9uIHNvcnRlZEFycmF5KCB2YWx1ZXMsIHN0cmlkZSwgb3JkZXIgKSB7XHJcblxyXG5cdGNvbnN0IG5WYWx1ZXMgPSB2YWx1ZXMubGVuZ3RoO1xyXG5cdGNvbnN0IHJlc3VsdCA9IG5ldyB2YWx1ZXMuY29uc3RydWN0b3IoIG5WYWx1ZXMgKTtcclxuXHJcblx0Zm9yICggbGV0IGkgPSAwLCBkc3RPZmZzZXQgPSAwOyBkc3RPZmZzZXQgIT09IG5WYWx1ZXM7ICsrIGkgKSB7XHJcblxyXG5cdFx0Y29uc3Qgc3JjT2Zmc2V0ID0gb3JkZXJbIGkgXSAqIHN0cmlkZTtcclxuXHJcblx0XHRmb3IgKCBsZXQgaiA9IDA7IGogIT09IHN0cmlkZTsgKysgaiApIHtcclxuXHJcblx0XHRcdHJlc3VsdFsgZHN0T2Zmc2V0ICsrIF0gPSB2YWx1ZXNbIHNyY09mZnNldCArIGogXTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0cmV0dXJuIHJlc3VsdDtcclxuXHJcbn1cclxuXHJcbi8vIGZ1bmN0aW9uIGZvciBwYXJzaW5nIEFPUyBrZXlmcmFtZSBmb3JtYXRzXHJcbmZ1bmN0aW9uIGZsYXR0ZW5KU09OKCBqc29uS2V5cywgdGltZXMsIHZhbHVlcywgdmFsdWVQcm9wZXJ0eU5hbWUgKSB7XHJcblxyXG5cdGxldCBpID0gMSwga2V5ID0ganNvbktleXNbIDAgXTtcclxuXHJcblx0d2hpbGUgKCBrZXkgIT09IHVuZGVmaW5lZCAmJiBrZXlbIHZhbHVlUHJvcGVydHlOYW1lIF0gPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRrZXkgPSBqc29uS2V5c1sgaSArKyBdO1xyXG5cclxuXHR9XHJcblxyXG5cdGlmICgga2V5ID09PSB1bmRlZmluZWQgKSByZXR1cm47IC8vIG5vIGRhdGFcclxuXHJcblx0bGV0IHZhbHVlID0ga2V5WyB2YWx1ZVByb3BlcnR5TmFtZSBdO1xyXG5cdGlmICggdmFsdWUgPT09IHVuZGVmaW5lZCApIHJldHVybjsgLy8gbm8gZGF0YVxyXG5cclxuXHRpZiAoIEFycmF5LmlzQXJyYXkoIHZhbHVlICkgKSB7XHJcblxyXG5cdFx0ZG8ge1xyXG5cclxuXHRcdFx0dmFsdWUgPSBrZXlbIHZhbHVlUHJvcGVydHlOYW1lIF07XHJcblxyXG5cdFx0XHRpZiAoIHZhbHVlICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRcdHRpbWVzLnB1c2goIGtleS50aW1lICk7XHJcblx0XHRcdFx0dmFsdWVzLnB1c2guYXBwbHkoIHZhbHVlcywgdmFsdWUgKTsgLy8gcHVzaCBhbGwgZWxlbWVudHNcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGtleSA9IGpzb25LZXlzWyBpICsrIF07XHJcblxyXG5cdFx0fSB3aGlsZSAoIGtleSAhPT0gdW5kZWZpbmVkICk7XHJcblxyXG5cdH0gZWxzZSBpZiAoIHZhbHVlLnRvQXJyYXkgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHQvLyAuLi5hc3N1bWUgVEhSRUUuTWF0aC1pc2hcclxuXHJcblx0XHRkbyB7XHJcblxyXG5cdFx0XHR2YWx1ZSA9IGtleVsgdmFsdWVQcm9wZXJ0eU5hbWUgXTtcclxuXHJcblx0XHRcdGlmICggdmFsdWUgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0dGltZXMucHVzaCgga2V5LnRpbWUgKTtcclxuXHRcdFx0XHR2YWx1ZS50b0FycmF5KCB2YWx1ZXMsIHZhbHVlcy5sZW5ndGggKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGtleSA9IGpzb25LZXlzWyBpICsrIF07XHJcblxyXG5cdFx0fSB3aGlsZSAoIGtleSAhPT0gdW5kZWZpbmVkICk7XHJcblxyXG5cdH0gZWxzZSB7XHJcblxyXG5cdFx0Ly8gb3RoZXJ3aXNlIHB1c2ggYXMtaXNcclxuXHJcblx0XHRkbyB7XHJcblxyXG5cdFx0XHR2YWx1ZSA9IGtleVsgdmFsdWVQcm9wZXJ0eU5hbWUgXTtcclxuXHJcblx0XHRcdGlmICggdmFsdWUgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0dGltZXMucHVzaCgga2V5LnRpbWUgKTtcclxuXHRcdFx0XHR2YWx1ZXMucHVzaCggdmFsdWUgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGtleSA9IGpzb25LZXlzWyBpICsrIF07XHJcblxyXG5cdFx0fSB3aGlsZSAoIGtleSAhPT0gdW5kZWZpbmVkICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmZ1bmN0aW9uIHN1YmNsaXAoIHNvdXJjZUNsaXAsIG5hbWUsIHN0YXJ0RnJhbWUsIGVuZEZyYW1lLCBmcHMgPSAzMCApIHtcclxuXHJcblx0Y29uc3QgY2xpcCA9IHNvdXJjZUNsaXAuY2xvbmUoKTtcclxuXHJcblx0Y2xpcC5uYW1lID0gbmFtZTtcclxuXHJcblx0Y29uc3QgdHJhY2tzID0gW107XHJcblxyXG5cdGZvciAoIGxldCBpID0gMDsgaSA8IGNsaXAudHJhY2tzLmxlbmd0aDsgKysgaSApIHtcclxuXHJcblx0XHRjb25zdCB0cmFjayA9IGNsaXAudHJhY2tzWyBpIF07XHJcblx0XHRjb25zdCB2YWx1ZVNpemUgPSB0cmFjay5nZXRWYWx1ZVNpemUoKTtcclxuXHJcblx0XHRjb25zdCB0aW1lcyA9IFtdO1xyXG5cdFx0Y29uc3QgdmFsdWVzID0gW107XHJcblxyXG5cdFx0Zm9yICggbGV0IGogPSAwOyBqIDwgdHJhY2sudGltZXMubGVuZ3RoOyArKyBqICkge1xyXG5cclxuXHRcdFx0Y29uc3QgZnJhbWUgPSB0cmFjay50aW1lc1sgaiBdICogZnBzO1xyXG5cclxuXHRcdFx0aWYgKCBmcmFtZSA8IHN0YXJ0RnJhbWUgfHwgZnJhbWUgPj0gZW5kRnJhbWUgKSBjb250aW51ZTtcclxuXHJcblx0XHRcdHRpbWVzLnB1c2goIHRyYWNrLnRpbWVzWyBqIF0gKTtcclxuXHJcblx0XHRcdGZvciAoIGxldCBrID0gMDsgayA8IHZhbHVlU2l6ZTsgKysgayApIHtcclxuXHJcblx0XHRcdFx0dmFsdWVzLnB1c2goIHRyYWNrLnZhbHVlc1sgaiAqIHZhbHVlU2l6ZSArIGsgXSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHRpbWVzLmxlbmd0aCA9PT0gMCApIGNvbnRpbnVlO1xyXG5cclxuXHRcdHRyYWNrLnRpbWVzID0gY29udmVydEFycmF5KCB0aW1lcywgdHJhY2sudGltZXMuY29uc3RydWN0b3IgKTtcclxuXHRcdHRyYWNrLnZhbHVlcyA9IGNvbnZlcnRBcnJheSggdmFsdWVzLCB0cmFjay52YWx1ZXMuY29uc3RydWN0b3IgKTtcclxuXHJcblx0XHR0cmFja3MucHVzaCggdHJhY2sgKTtcclxuXHJcblx0fVxyXG5cclxuXHRjbGlwLnRyYWNrcyA9IHRyYWNrcztcclxuXHJcblx0Ly8gZmluZCBtaW5pbXVtIC50aW1lcyB2YWx1ZSBhY3Jvc3MgYWxsIHRyYWNrcyBpbiB0aGUgdHJpbW1lZCBjbGlwXHJcblxyXG5cdGxldCBtaW5TdGFydFRpbWUgPSBJbmZpbml0eTtcclxuXHJcblx0Zm9yICggbGV0IGkgPSAwOyBpIDwgY2xpcC50cmFja3MubGVuZ3RoOyArKyBpICkge1xyXG5cclxuXHRcdGlmICggbWluU3RhcnRUaW1lID4gY2xpcC50cmFja3NbIGkgXS50aW1lc1sgMCBdICkge1xyXG5cclxuXHRcdFx0bWluU3RhcnRUaW1lID0gY2xpcC50cmFja3NbIGkgXS50aW1lc1sgMCBdO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHQvLyBzaGlmdCBhbGwgdHJhY2tzIHN1Y2ggdGhhdCBjbGlwIGJlZ2lucyBhdCB0PTBcclxuXHJcblx0Zm9yICggbGV0IGkgPSAwOyBpIDwgY2xpcC50cmFja3MubGVuZ3RoOyArKyBpICkge1xyXG5cclxuXHRcdGNsaXAudHJhY2tzWyBpIF0uc2hpZnQoIC0gMSAqIG1pblN0YXJ0VGltZSApO1xyXG5cclxuXHR9XHJcblxyXG5cdGNsaXAucmVzZXREdXJhdGlvbigpO1xyXG5cclxuXHRyZXR1cm4gY2xpcDtcclxuXHJcbn1cclxuXHJcbmZ1bmN0aW9uIG1ha2VDbGlwQWRkaXRpdmUoIHRhcmdldENsaXAsIHJlZmVyZW5jZUZyYW1lID0gMCwgcmVmZXJlbmNlQ2xpcCA9IHRhcmdldENsaXAsIGZwcyA9IDMwICkge1xyXG5cclxuXHRpZiAoIGZwcyA8PSAwICkgZnBzID0gMzA7XHJcblxyXG5cdGNvbnN0IG51bVRyYWNrcyA9IHJlZmVyZW5jZUNsaXAudHJhY2tzLmxlbmd0aDtcclxuXHRjb25zdCByZWZlcmVuY2VUaW1lID0gcmVmZXJlbmNlRnJhbWUgLyBmcHM7XHJcblxyXG5cdC8vIE1ha2UgZWFjaCB0cmFjaydzIHZhbHVlcyByZWxhdGl2ZSB0byB0aGUgdmFsdWVzIGF0IHRoZSByZWZlcmVuY2UgZnJhbWVcclxuXHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBudW1UcmFja3M7ICsrIGkgKSB7XHJcblxyXG5cdFx0Y29uc3QgcmVmZXJlbmNlVHJhY2sgPSByZWZlcmVuY2VDbGlwLnRyYWNrc1sgaSBdO1xyXG5cdFx0Y29uc3QgcmVmZXJlbmNlVHJhY2tUeXBlID0gcmVmZXJlbmNlVHJhY2suVmFsdWVUeXBlTmFtZTtcclxuXHJcblx0XHQvLyBTa2lwIHRoaXMgdHJhY2sgaWYgaXQncyBub24tbnVtZXJpY1xyXG5cdFx0aWYgKCByZWZlcmVuY2VUcmFja1R5cGUgPT09ICdib29sJyB8fCByZWZlcmVuY2VUcmFja1R5cGUgPT09ICdzdHJpbmcnICkgY29udGludWU7XHJcblxyXG5cdFx0Ly8gRmluZCB0aGUgdHJhY2sgaW4gdGhlIHRhcmdldCBjbGlwIHdob3NlIG5hbWUgYW5kIHR5cGUgbWF0Y2hlcyB0aGUgcmVmZXJlbmNlIHRyYWNrXHJcblx0XHRjb25zdCB0YXJnZXRUcmFjayA9IHRhcmdldENsaXAudHJhY2tzLmZpbmQoIGZ1bmN0aW9uICggdHJhY2sgKSB7XHJcblxyXG5cdFx0XHRyZXR1cm4gdHJhY2submFtZSA9PT0gcmVmZXJlbmNlVHJhY2submFtZVxyXG5cdFx0XHRcdCYmIHRyYWNrLlZhbHVlVHlwZU5hbWUgPT09IHJlZmVyZW5jZVRyYWNrVHlwZTtcclxuXHJcblx0XHR9ICk7XHJcblxyXG5cdFx0aWYgKCB0YXJnZXRUcmFjayA9PT0gdW5kZWZpbmVkICkgY29udGludWU7XHJcblxyXG5cdFx0bGV0IHJlZmVyZW5jZU9mZnNldCA9IDA7XHJcblx0XHRjb25zdCByZWZlcmVuY2VWYWx1ZVNpemUgPSByZWZlcmVuY2VUcmFjay5nZXRWYWx1ZVNpemUoKTtcclxuXHJcblx0XHRpZiAoIHJlZmVyZW5jZVRyYWNrLmNyZWF0ZUludGVycG9sYW50LmlzSW50ZXJwb2xhbnRGYWN0b3J5TWV0aG9kR0xURkN1YmljU3BsaW5lICkge1xyXG5cclxuXHRcdFx0cmVmZXJlbmNlT2Zmc2V0ID0gcmVmZXJlbmNlVmFsdWVTaXplIC8gMztcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0bGV0IHRhcmdldE9mZnNldCA9IDA7XHJcblx0XHRjb25zdCB0YXJnZXRWYWx1ZVNpemUgPSB0YXJnZXRUcmFjay5nZXRWYWx1ZVNpemUoKTtcclxuXHJcblx0XHRpZiAoIHRhcmdldFRyYWNrLmNyZWF0ZUludGVycG9sYW50LmlzSW50ZXJwb2xhbnRGYWN0b3J5TWV0aG9kR0xURkN1YmljU3BsaW5lICkge1xyXG5cclxuXHRcdFx0dGFyZ2V0T2Zmc2V0ID0gdGFyZ2V0VmFsdWVTaXplIC8gMztcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Y29uc3QgbGFzdEluZGV4ID0gcmVmZXJlbmNlVHJhY2sudGltZXMubGVuZ3RoIC0gMTtcclxuXHRcdGxldCByZWZlcmVuY2VWYWx1ZTtcclxuXHJcblx0XHQvLyBGaW5kIHRoZSB2YWx1ZSB0byBzdWJ0cmFjdCBvdXQgb2YgdGhlIHRyYWNrXHJcblx0XHRpZiAoIHJlZmVyZW5jZVRpbWUgPD0gcmVmZXJlbmNlVHJhY2sudGltZXNbIDAgXSApIHtcclxuXHJcblx0XHRcdC8vIFJlZmVyZW5jZSBmcmFtZSBpcyBlYXJsaWVyIHRoYW4gdGhlIGZpcnN0IGtleWZyYW1lLCBzbyBqdXN0IHVzZSB0aGUgZmlyc3Qga2V5ZnJhbWVcclxuXHRcdFx0Y29uc3Qgc3RhcnRJbmRleCA9IHJlZmVyZW5jZU9mZnNldDtcclxuXHRcdFx0Y29uc3QgZW5kSW5kZXggPSByZWZlcmVuY2VWYWx1ZVNpemUgLSByZWZlcmVuY2VPZmZzZXQ7XHJcblx0XHRcdHJlZmVyZW5jZVZhbHVlID0gcmVmZXJlbmNlVHJhY2sudmFsdWVzLnNsaWNlKCBzdGFydEluZGV4LCBlbmRJbmRleCApO1xyXG5cclxuXHRcdH0gZWxzZSBpZiAoIHJlZmVyZW5jZVRpbWUgPj0gcmVmZXJlbmNlVHJhY2sudGltZXNbIGxhc3RJbmRleCBdICkge1xyXG5cclxuXHRcdFx0Ly8gUmVmZXJlbmNlIGZyYW1lIGlzIGFmdGVyIHRoZSBsYXN0IGtleWZyYW1lLCBzbyBqdXN0IHVzZSB0aGUgbGFzdCBrZXlmcmFtZVxyXG5cdFx0XHRjb25zdCBzdGFydEluZGV4ID0gbGFzdEluZGV4ICogcmVmZXJlbmNlVmFsdWVTaXplICsgcmVmZXJlbmNlT2Zmc2V0O1xyXG5cdFx0XHRjb25zdCBlbmRJbmRleCA9IHN0YXJ0SW5kZXggKyByZWZlcmVuY2VWYWx1ZVNpemUgLSByZWZlcmVuY2VPZmZzZXQ7XHJcblx0XHRcdHJlZmVyZW5jZVZhbHVlID0gcmVmZXJlbmNlVHJhY2sudmFsdWVzLnNsaWNlKCBzdGFydEluZGV4LCBlbmRJbmRleCApO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHQvLyBJbnRlcnBvbGF0ZSB0byB0aGUgcmVmZXJlbmNlIHZhbHVlXHJcblx0XHRcdGNvbnN0IGludGVycG9sYW50ID0gcmVmZXJlbmNlVHJhY2suY3JlYXRlSW50ZXJwb2xhbnQoKTtcclxuXHRcdFx0Y29uc3Qgc3RhcnRJbmRleCA9IHJlZmVyZW5jZU9mZnNldDtcclxuXHRcdFx0Y29uc3QgZW5kSW5kZXggPSByZWZlcmVuY2VWYWx1ZVNpemUgLSByZWZlcmVuY2VPZmZzZXQ7XHJcblx0XHRcdGludGVycG9sYW50LmV2YWx1YXRlKCByZWZlcmVuY2VUaW1lICk7XHJcblx0XHRcdHJlZmVyZW5jZVZhbHVlID0gaW50ZXJwb2xhbnQucmVzdWx0QnVmZmVyLnNsaWNlKCBzdGFydEluZGV4LCBlbmRJbmRleCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvLyBDb25qdWdhdGUgdGhlIHF1YXRlcm5pb25cclxuXHRcdGlmICggcmVmZXJlbmNlVHJhY2tUeXBlID09PSAncXVhdGVybmlvbicgKSB7XHJcblxyXG5cdFx0XHRjb25zdCByZWZlcmVuY2VRdWF0ID0gbmV3IFF1YXRlcm5pb24oKS5mcm9tQXJyYXkoIHJlZmVyZW5jZVZhbHVlICkubm9ybWFsaXplKCkuY29uanVnYXRlKCk7XHJcblx0XHRcdHJlZmVyZW5jZVF1YXQudG9BcnJheSggcmVmZXJlbmNlVmFsdWUgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gU3VidHJhY3QgdGhlIHJlZmVyZW5jZSB2YWx1ZSBmcm9tIGFsbCBvZiB0aGUgdHJhY2sgdmFsdWVzXHJcblxyXG5cdFx0Y29uc3QgbnVtVGltZXMgPSB0YXJnZXRUcmFjay50aW1lcy5sZW5ndGg7XHJcblx0XHRmb3IgKCBsZXQgaiA9IDA7IGogPCBudW1UaW1lczsgKysgaiApIHtcclxuXHJcblx0XHRcdGNvbnN0IHZhbHVlU3RhcnQgPSBqICogdGFyZ2V0VmFsdWVTaXplICsgdGFyZ2V0T2Zmc2V0O1xyXG5cclxuXHRcdFx0aWYgKCByZWZlcmVuY2VUcmFja1R5cGUgPT09ICdxdWF0ZXJuaW9uJyApIHtcclxuXHJcblx0XHRcdFx0Ly8gTXVsdGlwbHkgdGhlIGNvbmp1Z2F0ZSBmb3IgcXVhdGVybmlvbiB0cmFjayB0eXBlc1xyXG5cdFx0XHRcdFF1YXRlcm5pb24ubXVsdGlwbHlRdWF0ZXJuaW9uc0ZsYXQoXHJcblx0XHRcdFx0XHR0YXJnZXRUcmFjay52YWx1ZXMsXHJcblx0XHRcdFx0XHR2YWx1ZVN0YXJ0LFxyXG5cdFx0XHRcdFx0cmVmZXJlbmNlVmFsdWUsXHJcblx0XHRcdFx0XHQwLFxyXG5cdFx0XHRcdFx0dGFyZ2V0VHJhY2sudmFsdWVzLFxyXG5cdFx0XHRcdFx0dmFsdWVTdGFydFxyXG5cdFx0XHRcdCk7XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRjb25zdCB2YWx1ZUVuZCA9IHRhcmdldFZhbHVlU2l6ZSAtIHRhcmdldE9mZnNldCAqIDI7XHJcblxyXG5cdFx0XHRcdC8vIFN1YnRyYWN0IGVhY2ggdmFsdWUgZm9yIGFsbCBvdGhlciBudW1lcmljIHRyYWNrIHR5cGVzXHJcblx0XHRcdFx0Zm9yICggbGV0IGsgPSAwOyBrIDwgdmFsdWVFbmQ7ICsrIGsgKSB7XHJcblxyXG5cdFx0XHRcdFx0dGFyZ2V0VHJhY2sudmFsdWVzWyB2YWx1ZVN0YXJ0ICsgayBdIC09IHJlZmVyZW5jZVZhbHVlWyBrIF07XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0dGFyZ2V0Q2xpcC5ibGVuZE1vZGUgPSBBZGRpdGl2ZUFuaW1hdGlvbkJsZW5kTW9kZTtcclxuXHJcblx0cmV0dXJuIHRhcmdldENsaXA7XHJcblxyXG59XHJcblxyXG5jb25zdCBBbmltYXRpb25VdGlscyA9IHtcclxuXHRjb252ZXJ0QXJyYXk6IGNvbnZlcnRBcnJheSxcclxuXHRpc1R5cGVkQXJyYXk6IGlzVHlwZWRBcnJheSxcclxuXHRnZXRLZXlmcmFtZU9yZGVyOiBnZXRLZXlmcmFtZU9yZGVyLFxyXG5cdHNvcnRlZEFycmF5OiBzb3J0ZWRBcnJheSxcclxuXHRmbGF0dGVuSlNPTjogZmxhdHRlbkpTT04sXHJcblx0c3ViY2xpcDogc3ViY2xpcCxcclxuXHRtYWtlQ2xpcEFkZGl0aXZlOiBtYWtlQ2xpcEFkZGl0aXZlXHJcbn07XHJcblxyXG5leHBvcnQge1xyXG5cdGNvbnZlcnRBcnJheSxcclxuXHRpc1R5cGVkQXJyYXksXHJcblx0Z2V0S2V5ZnJhbWVPcmRlcixcclxuXHRzb3J0ZWRBcnJheSxcclxuXHRmbGF0dGVuSlNPTixcclxuXHRzdWJjbGlwLFxyXG5cdG1ha2VDbGlwQWRkaXRpdmUsXHJcblx0QW5pbWF0aW9uVXRpbHNcclxufTtcclxuIiwiLyoqXHJcbiAqIEFic3RyYWN0IGJhc2UgY2xhc3Mgb2YgaW50ZXJwb2xhbnRzIG92ZXIgcGFyYW1ldHJpYyBzYW1wbGVzLlxyXG4gKlxyXG4gKiBUaGUgcGFyYW1ldGVyIGRvbWFpbiBpcyBvbmUgZGltZW5zaW9uYWwsIHR5cGljYWxseSB0aGUgdGltZSBvciBhIHBhdGhcclxuICogYWxvbmcgYSBjdXJ2ZSBkZWZpbmVkIGJ5IHRoZSBkYXRhLlxyXG4gKlxyXG4gKiBUaGUgc2FtcGxlIHZhbHVlcyBjYW4gaGF2ZSBhbnkgZGltZW5zaW9uYWxpdHkgYW5kIGRlcml2ZWQgY2xhc3NlcyBtYXlcclxuICogYXBwbHkgc3BlY2lhbCBpbnRlcnByZXRhdGlvbnMgdG8gdGhlIGRhdGEuXHJcbiAqXHJcbiAqIFRoaXMgY2xhc3MgcHJvdmlkZXMgdGhlIGludGVydmFsIHNlZWsgaW4gYSBUZW1wbGF0ZSBNZXRob2QsIGRlZmVycmluZ1xyXG4gKiB0aGUgYWN0dWFsIGludGVycG9sYXRpb24gdG8gZGVyaXZlZCBjbGFzc2VzLlxyXG4gKlxyXG4gKiBUaW1lIGNvbXBsZXhpdHkgaXMgTygxKSBmb3IgbGluZWFyIGFjY2VzcyBjcm9zc2luZyBhdCBtb3N0IHR3byBwb2ludHNcclxuICogYW5kIE8obG9nIE4pIGZvciByYW5kb20gYWNjZXNzLCB3aGVyZSBOIGlzIHRoZSBudW1iZXIgb2YgcG9zaXRpb25zLlxyXG4gKlxyXG4gKiBSZWZlcmVuY2VzOlxyXG4gKlxyXG4gKiBcdFx0aHR0cDovL3d3dy5vb2Rlc2lnbi5jb20vdGVtcGxhdGUtbWV0aG9kLXBhdHRlcm4uaHRtbFxyXG4gKlxyXG4gKi9cclxuXHJcbmNsYXNzIEludGVycG9sYW50IHtcclxuXHJcblx0Y29uc3RydWN0b3IoIHBhcmFtZXRlclBvc2l0aW9ucywgc2FtcGxlVmFsdWVzLCBzYW1wbGVTaXplLCByZXN1bHRCdWZmZXIgKSB7XHJcblxyXG5cdFx0dGhpcy5wYXJhbWV0ZXJQb3NpdGlvbnMgPSBwYXJhbWV0ZXJQb3NpdGlvbnM7XHJcblx0XHR0aGlzLl9jYWNoZWRJbmRleCA9IDA7XHJcblxyXG5cdFx0dGhpcy5yZXN1bHRCdWZmZXIgPSByZXN1bHRCdWZmZXIgIT09IHVuZGVmaW5lZCA/XHJcblx0XHRcdHJlc3VsdEJ1ZmZlciA6IG5ldyBzYW1wbGVWYWx1ZXMuY29uc3RydWN0b3IoIHNhbXBsZVNpemUgKTtcclxuXHRcdHRoaXMuc2FtcGxlVmFsdWVzID0gc2FtcGxlVmFsdWVzO1xyXG5cdFx0dGhpcy52YWx1ZVNpemUgPSBzYW1wbGVTaXplO1xyXG5cclxuXHRcdHRoaXMuc2V0dGluZ3MgPSBudWxsO1xyXG5cdFx0dGhpcy5EZWZhdWx0U2V0dGluZ3NfID0ge307XHJcblxyXG5cdH1cclxuXHJcblx0ZXZhbHVhdGUoIHQgKSB7XHJcblxyXG5cdFx0Y29uc3QgcHAgPSB0aGlzLnBhcmFtZXRlclBvc2l0aW9ucztcclxuXHRcdGxldCBpMSA9IHRoaXMuX2NhY2hlZEluZGV4LFxyXG5cdFx0XHR0MSA9IHBwWyBpMSBdLFxyXG5cdFx0XHR0MCA9IHBwWyBpMSAtIDEgXTtcclxuXHJcblx0XHR2YWxpZGF0ZV9pbnRlcnZhbDoge1xyXG5cclxuXHRcdFx0c2Vlazoge1xyXG5cclxuXHRcdFx0XHRsZXQgcmlnaHQ7XHJcblxyXG5cdFx0XHRcdGxpbmVhcl9zY2FuOiB7XHJcblxyXG5cdFx0XHRcdFx0Ly8tIFNlZSBodHRwOi8vanNwZXJmLmNvbS9jb21wYXJpc29uLXRvLXVuZGVmaW5lZC8zXHJcblx0XHRcdFx0XHQvLy0gc2xvd2VyIGNvZGU6XHJcblx0XHRcdFx0XHQvLy1cclxuXHRcdFx0XHRcdC8vLSBcdFx0XHRcdGlmICggdCA+PSB0MSB8fCB0MSA9PT0gdW5kZWZpbmVkICkge1xyXG5cdFx0XHRcdFx0Zm9yd2FyZF9zY2FuOiBpZiAoICEgKCB0IDwgdDEgKSApIHtcclxuXHJcblx0XHRcdFx0XHRcdGZvciAoIGxldCBnaXZlVXBBdCA9IGkxICsgMjsgOyApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0aWYgKCB0MSA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRcdGlmICggdCA8IHQwICkgYnJlYWsgZm9yd2FyZF9zY2FuO1xyXG5cclxuXHRcdFx0XHRcdFx0XHRcdC8vIGFmdGVyIGVuZFxyXG5cclxuXHRcdFx0XHRcdFx0XHRcdGkxID0gcHAubGVuZ3RoO1xyXG5cdFx0XHRcdFx0XHRcdFx0dGhpcy5fY2FjaGVkSW5kZXggPSBpMTtcclxuXHRcdFx0XHRcdFx0XHRcdHJldHVybiB0aGlzLmNvcHlTYW1wbGVWYWx1ZV8oIGkxIC0gMSApO1xyXG5cclxuXHRcdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0XHRcdGlmICggaTEgPT09IGdpdmVVcEF0ICkgYnJlYWs7IC8vIHRoaXMgbG9vcFxyXG5cclxuXHRcdFx0XHRcdFx0XHR0MCA9IHQxO1xyXG5cdFx0XHRcdFx0XHRcdHQxID0gcHBbICsrIGkxIF07XHJcblxyXG5cdFx0XHRcdFx0XHRcdGlmICggdCA8IHQxICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRcdC8vIHdlIGhhdmUgYXJyaXZlZCBhdCB0aGUgc291Z2h0IGludGVydmFsXHJcblx0XHRcdFx0XHRcdFx0XHRicmVhayBzZWVrO1xyXG5cclxuXHRcdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0XHQvLyBwcmVwYXJlIGJpbmFyeSBzZWFyY2ggb24gdGhlIHJpZ2h0IHNpZGUgb2YgdGhlIGluZGV4XHJcblx0XHRcdFx0XHRcdHJpZ2h0ID0gcHAubGVuZ3RoO1xyXG5cdFx0XHRcdFx0XHRicmVhayBsaW5lYXJfc2NhbjtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0Ly8tIHNsb3dlciBjb2RlOlxyXG5cdFx0XHRcdFx0Ly8tXHRcdFx0XHRcdGlmICggdCA8IHQwIHx8IHQwID09PSB1bmRlZmluZWQgKSB7XHJcblx0XHRcdFx0XHRpZiAoICEgKCB0ID49IHQwICkgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHQvLyBsb29waW5nP1xyXG5cclxuXHRcdFx0XHRcdFx0Y29uc3QgdDFnbG9iYWwgPSBwcFsgMSBdO1xyXG5cclxuXHRcdFx0XHRcdFx0aWYgKCB0IDwgdDFnbG9iYWwgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdGkxID0gMjsgLy8gKyAxLCB1c2luZyB0aGUgc2NhbiBmb3IgdGhlIGRldGFpbHNcclxuXHRcdFx0XHRcdFx0XHR0MCA9IHQxZ2xvYmFsO1xyXG5cclxuXHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdFx0Ly8gbGluZWFyIHJldmVyc2Ugc2NhblxyXG5cclxuXHRcdFx0XHRcdFx0Zm9yICggbGV0IGdpdmVVcEF0ID0gaTEgLSAyOyA7ICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRpZiAoIHQwID09PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0Ly8gYmVmb3JlIHN0YXJ0XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0dGhpcy5fY2FjaGVkSW5kZXggPSAwO1xyXG5cdFx0XHRcdFx0XHRcdFx0cmV0dXJuIHRoaXMuY29weVNhbXBsZVZhbHVlXyggMCApO1xyXG5cclxuXHRcdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0XHRcdGlmICggaTEgPT09IGdpdmVVcEF0ICkgYnJlYWs7IC8vIHRoaXMgbG9vcFxyXG5cclxuXHRcdFx0XHRcdFx0XHR0MSA9IHQwO1xyXG5cdFx0XHRcdFx0XHRcdHQwID0gcHBbIC0tIGkxIC0gMSBdO1xyXG5cclxuXHRcdFx0XHRcdFx0XHRpZiAoIHQgPj0gdDAgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0Ly8gd2UgaGF2ZSBhcnJpdmVkIGF0IHRoZSBzb3VnaHQgaW50ZXJ2YWxcclxuXHRcdFx0XHRcdFx0XHRcdGJyZWFrIHNlZWs7XHJcblxyXG5cdFx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRcdC8vIHByZXBhcmUgYmluYXJ5IHNlYXJjaCBvbiB0aGUgbGVmdCBzaWRlIG9mIHRoZSBpbmRleFxyXG5cdFx0XHRcdFx0XHRyaWdodCA9IGkxO1xyXG5cdFx0XHRcdFx0XHRpMSA9IDA7XHJcblx0XHRcdFx0XHRcdGJyZWFrIGxpbmVhcl9zY2FuO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHQvLyB0aGUgaW50ZXJ2YWwgaXMgdmFsaWRcclxuXHJcblx0XHRcdFx0XHRicmVhayB2YWxpZGF0ZV9pbnRlcnZhbDtcclxuXHJcblx0XHRcdFx0fSAvLyBsaW5lYXIgc2NhblxyXG5cclxuXHRcdFx0XHQvLyBiaW5hcnkgc2VhcmNoXHJcblxyXG5cdFx0XHRcdHdoaWxlICggaTEgPCByaWdodCApIHtcclxuXHJcblx0XHRcdFx0XHRjb25zdCBtaWQgPSAoIGkxICsgcmlnaHQgKSA+Pj4gMTtcclxuXHJcblx0XHRcdFx0XHRpZiAoIHQgPCBwcFsgbWlkIF0gKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRyaWdodCA9IG1pZDtcclxuXHJcblx0XHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdFx0aTEgPSBtaWQgKyAxO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR0MSA9IHBwWyBpMSBdO1xyXG5cdFx0XHRcdHQwID0gcHBbIGkxIC0gMSBdO1xyXG5cclxuXHRcdFx0XHQvLyBjaGVjayBib3VuZGFyeSBjYXNlcywgYWdhaW5cclxuXHJcblx0XHRcdFx0aWYgKCB0MCA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHRcdHRoaXMuX2NhY2hlZEluZGV4ID0gMDtcclxuXHRcdFx0XHRcdHJldHVybiB0aGlzLmNvcHlTYW1wbGVWYWx1ZV8oIDAgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRpZiAoIHQxID09PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRcdFx0aTEgPSBwcC5sZW5ndGg7XHJcblx0XHRcdFx0XHR0aGlzLl9jYWNoZWRJbmRleCA9IGkxO1xyXG5cdFx0XHRcdFx0cmV0dXJuIHRoaXMuY29weVNhbXBsZVZhbHVlXyggaTEgLSAxICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH0gLy8gc2Vla1xyXG5cclxuXHRcdFx0dGhpcy5fY2FjaGVkSW5kZXggPSBpMTtcclxuXHJcblx0XHRcdHRoaXMuaW50ZXJ2YWxDaGFuZ2VkXyggaTEsIHQwLCB0MSApO1xyXG5cclxuXHRcdH0gLy8gdmFsaWRhdGVfaW50ZXJ2YWxcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5pbnRlcnBvbGF0ZV8oIGkxLCB0MCwgdCwgdDEgKTtcclxuXHJcblx0fVxyXG5cclxuXHRnZXRTZXR0aW5nc18oKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuc2V0dGluZ3MgfHwgdGhpcy5EZWZhdWx0U2V0dGluZ3NfO1xyXG5cclxuXHR9XHJcblxyXG5cdGNvcHlTYW1wbGVWYWx1ZV8oIGluZGV4ICkge1xyXG5cclxuXHRcdC8vIGNvcGllcyBhIHNhbXBsZSB2YWx1ZSB0byB0aGUgcmVzdWx0IGJ1ZmZlclxyXG5cclxuXHRcdGNvbnN0IHJlc3VsdCA9IHRoaXMucmVzdWx0QnVmZmVyLFxyXG5cdFx0XHR2YWx1ZXMgPSB0aGlzLnNhbXBsZVZhbHVlcyxcclxuXHRcdFx0c3RyaWRlID0gdGhpcy52YWx1ZVNpemUsXHJcblx0XHRcdG9mZnNldCA9IGluZGV4ICogc3RyaWRlO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMDsgaSAhPT0gc3RyaWRlOyArKyBpICkge1xyXG5cclxuXHRcdFx0cmVzdWx0WyBpIF0gPSB2YWx1ZXNbIG9mZnNldCArIGkgXTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHJlc3VsdDtcclxuXHJcblx0fVxyXG5cclxuXHQvLyBUZW1wbGF0ZSBtZXRob2RzIGZvciBkZXJpdmVkIGNsYXNzZXM6XHJcblxyXG5cdGludGVycG9sYXRlXyggLyogaTEsIHQwLCB0LCB0MSAqLyApIHtcclxuXHJcblx0XHR0aHJvdyBuZXcgRXJyb3IoICdjYWxsIHRvIGFic3RyYWN0IG1ldGhvZCcgKTtcclxuXHRcdC8vIGltcGxlbWVudGF0aW9ucyBzaGFsbCByZXR1cm4gdGhpcy5yZXN1bHRCdWZmZXJcclxuXHJcblx0fVxyXG5cclxuXHRpbnRlcnZhbENoYW5nZWRfKCAvKiBpMSwgdDAsIHQxICovICkge1xyXG5cclxuXHRcdC8vIGVtcHR5XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IEludGVycG9sYW50IH07XHJcbiIsImltcG9ydCB7IFplcm9DdXJ2YXR1cmVFbmRpbmcsIFdyYXBBcm91bmRFbmRpbmcsIFplcm9TbG9wZUVuZGluZyB9IGZyb20gJy4uLy4uL2NvbnN0YW50cy5qcyc7XHJcbmltcG9ydCB7IEludGVycG9sYW50IH0gZnJvbSAnLi4vSW50ZXJwb2xhbnQuanMnO1xyXG5cclxuLyoqXHJcbiAqIEZhc3QgYW5kIHNpbXBsZSBjdWJpYyBzcGxpbmUgaW50ZXJwb2xhbnQuXHJcbiAqXHJcbiAqIEl0IHdhcyBkZXJpdmVkIGZyb20gYSBIZXJtaXRpYW4gY29uc3RydWN0aW9uIHNldHRpbmcgdGhlIGZpcnN0IGRlcml2YXRpdmVcclxuICogYXQgZWFjaCBzYW1wbGUgcG9zaXRpb24gdG8gdGhlIGxpbmVhciBzbG9wZSBiZXR3ZWVuIG5laWdoYm9yaW5nIHBvc2l0aW9uc1xyXG4gKiBvdmVyIHRoZWlyIHBhcmFtZXRlciBpbnRlcnZhbC5cclxuICovXHJcblxyXG5jbGFzcyBDdWJpY0ludGVycG9sYW50IGV4dGVuZHMgSW50ZXJwb2xhbnQge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggcGFyYW1ldGVyUG9zaXRpb25zLCBzYW1wbGVWYWx1ZXMsIHNhbXBsZVNpemUsIHJlc3VsdEJ1ZmZlciApIHtcclxuXHJcblx0XHRzdXBlciggcGFyYW1ldGVyUG9zaXRpb25zLCBzYW1wbGVWYWx1ZXMsIHNhbXBsZVNpemUsIHJlc3VsdEJ1ZmZlciApO1xyXG5cclxuXHRcdHRoaXMuX3dlaWdodFByZXYgPSAtIDA7XHJcblx0XHR0aGlzLl9vZmZzZXRQcmV2ID0gLSAwO1xyXG5cdFx0dGhpcy5fd2VpZ2h0TmV4dCA9IC0gMDtcclxuXHRcdHRoaXMuX29mZnNldE5leHQgPSAtIDA7XHJcblxyXG5cdFx0dGhpcy5EZWZhdWx0U2V0dGluZ3NfID0ge1xyXG5cclxuXHRcdFx0ZW5kaW5nU3RhcnQ6IFplcm9DdXJ2YXR1cmVFbmRpbmcsXHJcblx0XHRcdGVuZGluZ0VuZDogWmVyb0N1cnZhdHVyZUVuZGluZ1xyXG5cclxuXHRcdH07XHJcblxyXG5cdH1cclxuXHJcblx0aW50ZXJ2YWxDaGFuZ2VkXyggaTEsIHQwLCB0MSApIHtcclxuXHJcblx0XHRjb25zdCBwcCA9IHRoaXMucGFyYW1ldGVyUG9zaXRpb25zO1xyXG5cdFx0bGV0IGlQcmV2ID0gaTEgLSAyLFxyXG5cdFx0XHRpTmV4dCA9IGkxICsgMSxcclxuXHJcblx0XHRcdHRQcmV2ID0gcHBbIGlQcmV2IF0sXHJcblx0XHRcdHROZXh0ID0gcHBbIGlOZXh0IF07XHJcblxyXG5cdFx0aWYgKCB0UHJldiA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0c3dpdGNoICggdGhpcy5nZXRTZXR0aW5nc18oKS5lbmRpbmdTdGFydCApIHtcclxuXHJcblx0XHRcdFx0Y2FzZSBaZXJvU2xvcGVFbmRpbmc6XHJcblxyXG5cdFx0XHRcdFx0Ly8gZicodDApID0gMFxyXG5cdFx0XHRcdFx0aVByZXYgPSBpMTtcclxuXHRcdFx0XHRcdHRQcmV2ID0gMiAqIHQwIC0gdDE7XHJcblxyXG5cdFx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRcdGNhc2UgV3JhcEFyb3VuZEVuZGluZzpcclxuXHJcblx0XHRcdFx0XHQvLyB1c2UgdGhlIG90aGVyIGVuZCBvZiB0aGUgY3VydmVcclxuXHRcdFx0XHRcdGlQcmV2ID0gcHAubGVuZ3RoIC0gMjtcclxuXHRcdFx0XHRcdHRQcmV2ID0gdDAgKyBwcFsgaVByZXYgXSAtIHBwWyBpUHJldiArIDEgXTtcclxuXHJcblx0XHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdFx0ZGVmYXVsdDogLy8gWmVyb0N1cnZhdHVyZUVuZGluZ1xyXG5cclxuXHRcdFx0XHRcdC8vIGYnJyh0MCkgPSAwIGEuay5hLiBOYXR1cmFsIFNwbGluZVxyXG5cdFx0XHRcdFx0aVByZXYgPSBpMTtcclxuXHRcdFx0XHRcdHRQcmV2ID0gdDE7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggdE5leHQgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdHN3aXRjaCAoIHRoaXMuZ2V0U2V0dGluZ3NfKCkuZW5kaW5nRW5kICkge1xyXG5cclxuXHRcdFx0XHRjYXNlIFplcm9TbG9wZUVuZGluZzpcclxuXHJcblx0XHRcdFx0XHQvLyBmJyh0TikgPSAwXHJcblx0XHRcdFx0XHRpTmV4dCA9IGkxO1xyXG5cdFx0XHRcdFx0dE5leHQgPSAyICogdDEgLSB0MDtcclxuXHJcblx0XHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdFx0Y2FzZSBXcmFwQXJvdW5kRW5kaW5nOlxyXG5cclxuXHRcdFx0XHRcdC8vIHVzZSB0aGUgb3RoZXIgZW5kIG9mIHRoZSBjdXJ2ZVxyXG5cdFx0XHRcdFx0aU5leHQgPSAxO1xyXG5cdFx0XHRcdFx0dE5leHQgPSB0MSArIHBwWyAxIF0gLSBwcFsgMCBdO1xyXG5cclxuXHRcdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0XHRkZWZhdWx0OiAvLyBaZXJvQ3VydmF0dXJlRW5kaW5nXHJcblxyXG5cdFx0XHRcdFx0Ly8gZicnKHROKSA9IDAsIGEuay5hLiBOYXR1cmFsIFNwbGluZVxyXG5cdFx0XHRcdFx0aU5leHQgPSBpMSAtIDE7XHJcblx0XHRcdFx0XHR0TmV4dCA9IHQwO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCBoYWxmRHQgPSAoIHQxIC0gdDAgKSAqIDAuNSxcclxuXHRcdFx0c3RyaWRlID0gdGhpcy52YWx1ZVNpemU7XHJcblxyXG5cdFx0dGhpcy5fd2VpZ2h0UHJldiA9IGhhbGZEdCAvICggdDAgLSB0UHJldiApO1xyXG5cdFx0dGhpcy5fd2VpZ2h0TmV4dCA9IGhhbGZEdCAvICggdE5leHQgLSB0MSApO1xyXG5cdFx0dGhpcy5fb2Zmc2V0UHJldiA9IGlQcmV2ICogc3RyaWRlO1xyXG5cdFx0dGhpcy5fb2Zmc2V0TmV4dCA9IGlOZXh0ICogc3RyaWRlO1xyXG5cclxuXHR9XHJcblxyXG5cdGludGVycG9sYXRlXyggaTEsIHQwLCB0LCB0MSApIHtcclxuXHJcblx0XHRjb25zdCByZXN1bHQgPSB0aGlzLnJlc3VsdEJ1ZmZlcixcclxuXHRcdFx0dmFsdWVzID0gdGhpcy5zYW1wbGVWYWx1ZXMsXHJcblx0XHRcdHN0cmlkZSA9IHRoaXMudmFsdWVTaXplLFxyXG5cclxuXHRcdFx0bzEgPSBpMSAqIHN0cmlkZSxcdFx0bzAgPSBvMSAtIHN0cmlkZSxcclxuXHRcdFx0b1AgPSB0aGlzLl9vZmZzZXRQcmV2LCBcdG9OID0gdGhpcy5fb2Zmc2V0TmV4dCxcclxuXHRcdFx0d1AgPSB0aGlzLl93ZWlnaHRQcmV2LFx0d04gPSB0aGlzLl93ZWlnaHROZXh0LFxyXG5cclxuXHRcdFx0cCA9ICggdCAtIHQwICkgLyAoIHQxIC0gdDAgKSxcclxuXHRcdFx0cHAgPSBwICogcCxcclxuXHRcdFx0cHBwID0gcHAgKiBwO1xyXG5cclxuXHRcdC8vIGV2YWx1YXRlIHBvbHlub21pYWxzXHJcblxyXG5cdFx0Y29uc3Qgc1AgPSAtIHdQICogcHBwICsgMiAqIHdQICogcHAgLSB3UCAqIHA7XHJcblx0XHRjb25zdCBzMCA9ICggMSArIHdQICkgKiBwcHAgKyAoIC0gMS41IC0gMiAqIHdQICkgKiBwcCArICggLSAwLjUgKyB3UCApICogcCArIDE7XHJcblx0XHRjb25zdCBzMSA9ICggLSAxIC0gd04gKSAqIHBwcCArICggMS41ICsgd04gKSAqIHBwICsgMC41ICogcDtcclxuXHRcdGNvbnN0IHNOID0gd04gKiBwcHAgLSB3TiAqIHBwO1xyXG5cclxuXHRcdC8vIGNvbWJpbmUgZGF0YSBsaW5lYXJseVxyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMDsgaSAhPT0gc3RyaWRlOyArKyBpICkge1xyXG5cclxuXHRcdFx0cmVzdWx0WyBpIF0gPVxyXG5cdFx0XHRcdFx0c1AgKiB2YWx1ZXNbIG9QICsgaSBdICtcclxuXHRcdFx0XHRcdHMwICogdmFsdWVzWyBvMCArIGkgXSArXHJcblx0XHRcdFx0XHRzMSAqIHZhbHVlc1sgbzEgKyBpIF0gK1xyXG5cdFx0XHRcdFx0c04gKiB2YWx1ZXNbIG9OICsgaSBdO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gcmVzdWx0O1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBDdWJpY0ludGVycG9sYW50IH07XHJcbiIsImltcG9ydCB7IEludGVycG9sYW50IH0gZnJvbSAnLi4vSW50ZXJwb2xhbnQuanMnO1xyXG5cclxuY2xhc3MgTGluZWFySW50ZXJwb2xhbnQgZXh0ZW5kcyBJbnRlcnBvbGFudCB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBwYXJhbWV0ZXJQb3NpdGlvbnMsIHNhbXBsZVZhbHVlcywgc2FtcGxlU2l6ZSwgcmVzdWx0QnVmZmVyICkge1xyXG5cclxuXHRcdHN1cGVyKCBwYXJhbWV0ZXJQb3NpdGlvbnMsIHNhbXBsZVZhbHVlcywgc2FtcGxlU2l6ZSwgcmVzdWx0QnVmZmVyICk7XHJcblxyXG5cdH1cclxuXHJcblx0aW50ZXJwb2xhdGVfKCBpMSwgdDAsIHQsIHQxICkge1xyXG5cclxuXHRcdGNvbnN0IHJlc3VsdCA9IHRoaXMucmVzdWx0QnVmZmVyLFxyXG5cdFx0XHR2YWx1ZXMgPSB0aGlzLnNhbXBsZVZhbHVlcyxcclxuXHRcdFx0c3RyaWRlID0gdGhpcy52YWx1ZVNpemUsXHJcblxyXG5cdFx0XHRvZmZzZXQxID0gaTEgKiBzdHJpZGUsXHJcblx0XHRcdG9mZnNldDAgPSBvZmZzZXQxIC0gc3RyaWRlLFxyXG5cclxuXHRcdFx0d2VpZ2h0MSA9ICggdCAtIHQwICkgLyAoIHQxIC0gdDAgKSxcclxuXHRcdFx0d2VpZ2h0MCA9IDEgLSB3ZWlnaHQxO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMDsgaSAhPT0gc3RyaWRlOyArKyBpICkge1xyXG5cclxuXHRcdFx0cmVzdWx0WyBpIF0gPVxyXG5cdFx0XHRcdFx0dmFsdWVzWyBvZmZzZXQwICsgaSBdICogd2VpZ2h0MCArXHJcblx0XHRcdFx0XHR2YWx1ZXNbIG9mZnNldDEgKyBpIF0gKiB3ZWlnaHQxO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gcmVzdWx0O1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5cclxuZXhwb3J0IHsgTGluZWFySW50ZXJwb2xhbnQgfTtcclxuIiwiaW1wb3J0IHsgSW50ZXJwb2xhbnQgfSBmcm9tICcuLi9JbnRlcnBvbGFudC5qcyc7XHJcblxyXG4vKipcclxuICpcclxuICogSW50ZXJwb2xhbnQgdGhhdCBldmFsdWF0ZXMgdG8gdGhlIHNhbXBsZSB2YWx1ZSBhdCB0aGUgcG9zaXRpb24gcHJlY2VkaW5nXHJcbiAqIHRoZSBwYXJhbWV0ZXIuXHJcbiAqL1xyXG5cclxuY2xhc3MgRGlzY3JldGVJbnRlcnBvbGFudCBleHRlbmRzIEludGVycG9sYW50IHtcclxuXHJcblx0Y29uc3RydWN0b3IoIHBhcmFtZXRlclBvc2l0aW9ucywgc2FtcGxlVmFsdWVzLCBzYW1wbGVTaXplLCByZXN1bHRCdWZmZXIgKSB7XHJcblxyXG5cdFx0c3VwZXIoIHBhcmFtZXRlclBvc2l0aW9ucywgc2FtcGxlVmFsdWVzLCBzYW1wbGVTaXplLCByZXN1bHRCdWZmZXIgKTtcclxuXHJcblx0fVxyXG5cclxuXHRpbnRlcnBvbGF0ZV8oIGkxIC8qLCB0MCwgdCwgdDEgKi8gKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuY29weVNhbXBsZVZhbHVlXyggaTEgLSAxICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcblxyXG5leHBvcnQgeyBEaXNjcmV0ZUludGVycG9sYW50IH07XHJcbiIsImltcG9ydCB7XHJcblx0SW50ZXJwb2xhdGVMaW5lYXIsXHJcblx0SW50ZXJwb2xhdGVTbW9vdGgsXHJcblx0SW50ZXJwb2xhdGVEaXNjcmV0ZVxyXG59IGZyb20gJy4uL2NvbnN0YW50cy5qcyc7XHJcbmltcG9ydCB7IEN1YmljSW50ZXJwb2xhbnQgfSBmcm9tICcuLi9tYXRoL2ludGVycG9sYW50cy9DdWJpY0ludGVycG9sYW50LmpzJztcclxuaW1wb3J0IHsgTGluZWFySW50ZXJwb2xhbnQgfSBmcm9tICcuLi9tYXRoL2ludGVycG9sYW50cy9MaW5lYXJJbnRlcnBvbGFudC5qcyc7XHJcbmltcG9ydCB7IERpc2NyZXRlSW50ZXJwb2xhbnQgfSBmcm9tICcuLi9tYXRoL2ludGVycG9sYW50cy9EaXNjcmV0ZUludGVycG9sYW50LmpzJztcclxuaW1wb3J0ICogYXMgQW5pbWF0aW9uVXRpbHMgZnJvbSAnLi9BbmltYXRpb25VdGlscy5qcyc7XHJcblxyXG5jbGFzcyBLZXlmcmFtZVRyYWNrIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIG5hbWUsIHRpbWVzLCB2YWx1ZXMsIGludGVycG9sYXRpb24gKSB7XHJcblxyXG5cdFx0aWYgKCBuYW1lID09PSB1bmRlZmluZWQgKSB0aHJvdyBuZXcgRXJyb3IoICdUSFJFRS5LZXlmcmFtZVRyYWNrOiB0cmFjayBuYW1lIGlzIHVuZGVmaW5lZCcgKTtcclxuXHRcdGlmICggdGltZXMgPT09IHVuZGVmaW5lZCB8fCB0aW1lcy5sZW5ndGggPT09IDAgKSB0aHJvdyBuZXcgRXJyb3IoICdUSFJFRS5LZXlmcmFtZVRyYWNrOiBubyBrZXlmcmFtZXMgaW4gdHJhY2sgbmFtZWQgJyArIG5hbWUgKTtcclxuXHJcblx0XHR0aGlzLm5hbWUgPSBuYW1lO1xyXG5cclxuXHRcdHRoaXMudGltZXMgPSBBbmltYXRpb25VdGlscy5jb252ZXJ0QXJyYXkoIHRpbWVzLCB0aGlzLlRpbWVCdWZmZXJUeXBlICk7XHJcblx0XHR0aGlzLnZhbHVlcyA9IEFuaW1hdGlvblV0aWxzLmNvbnZlcnRBcnJheSggdmFsdWVzLCB0aGlzLlZhbHVlQnVmZmVyVHlwZSApO1xyXG5cclxuXHRcdHRoaXMuc2V0SW50ZXJwb2xhdGlvbiggaW50ZXJwb2xhdGlvbiB8fCB0aGlzLkRlZmF1bHRJbnRlcnBvbGF0aW9uICk7XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gU2VyaWFsaXphdGlvbiAoaW4gc3RhdGljIGNvbnRleHQsIGJlY2F1c2Ugb2YgY29uc3RydWN0b3IgaW52b2NhdGlvblxyXG5cdC8vIGFuZCBhdXRvbWF0aWMgaW52b2NhdGlvbiBvZiAudG9KU09OKTpcclxuXHJcblx0c3RhdGljIHRvSlNPTiggdHJhY2sgKSB7XHJcblxyXG5cdFx0Y29uc3QgdHJhY2tUeXBlID0gdHJhY2suY29uc3RydWN0b3I7XHJcblxyXG5cdFx0bGV0IGpzb247XHJcblxyXG5cdFx0Ly8gZGVyaXZlZCBjbGFzc2VzIGNhbiBkZWZpbmUgYSBzdGF0aWMgdG9KU09OIG1ldGhvZFxyXG5cdFx0aWYgKCB0cmFja1R5cGUudG9KU09OICE9PSB0aGlzLnRvSlNPTiApIHtcclxuXHJcblx0XHRcdGpzb24gPSB0cmFja1R5cGUudG9KU09OKCB0cmFjayApO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHQvLyBieSBkZWZhdWx0LCB3ZSBhc3N1bWUgdGhlIGRhdGEgY2FuIGJlIHNlcmlhbGl6ZWQgYXMtaXNcclxuXHRcdFx0anNvbiA9IHtcclxuXHJcblx0XHRcdFx0J25hbWUnOiB0cmFjay5uYW1lLFxyXG5cdFx0XHRcdCd0aW1lcyc6IEFuaW1hdGlvblV0aWxzLmNvbnZlcnRBcnJheSggdHJhY2sudGltZXMsIEFycmF5ICksXHJcblx0XHRcdFx0J3ZhbHVlcyc6IEFuaW1hdGlvblV0aWxzLmNvbnZlcnRBcnJheSggdHJhY2sudmFsdWVzLCBBcnJheSApXHJcblxyXG5cdFx0XHR9O1xyXG5cclxuXHRcdFx0Y29uc3QgaW50ZXJwb2xhdGlvbiA9IHRyYWNrLmdldEludGVycG9sYXRpb24oKTtcclxuXHJcblx0XHRcdGlmICggaW50ZXJwb2xhdGlvbiAhPT0gdHJhY2suRGVmYXVsdEludGVycG9sYXRpb24gKSB7XHJcblxyXG5cdFx0XHRcdGpzb24uaW50ZXJwb2xhdGlvbiA9IGludGVycG9sYXRpb247XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGpzb24udHlwZSA9IHRyYWNrLlZhbHVlVHlwZU5hbWU7IC8vIG1hbmRhdG9yeVxyXG5cclxuXHRcdHJldHVybiBqc29uO1xyXG5cclxuXHR9XHJcblxyXG5cdEludGVycG9sYW50RmFjdG9yeU1ldGhvZERpc2NyZXRlKCByZXN1bHQgKSB7XHJcblxyXG5cdFx0cmV0dXJuIG5ldyBEaXNjcmV0ZUludGVycG9sYW50KCB0aGlzLnRpbWVzLCB0aGlzLnZhbHVlcywgdGhpcy5nZXRWYWx1ZVNpemUoKSwgcmVzdWx0ICk7XHJcblxyXG5cdH1cclxuXHJcblx0SW50ZXJwb2xhbnRGYWN0b3J5TWV0aG9kTGluZWFyKCByZXN1bHQgKSB7XHJcblxyXG5cdFx0cmV0dXJuIG5ldyBMaW5lYXJJbnRlcnBvbGFudCggdGhpcy50aW1lcywgdGhpcy52YWx1ZXMsIHRoaXMuZ2V0VmFsdWVTaXplKCksIHJlc3VsdCApO1xyXG5cclxuXHR9XHJcblxyXG5cdEludGVycG9sYW50RmFjdG9yeU1ldGhvZFNtb290aCggcmVzdWx0ICkge1xyXG5cclxuXHRcdHJldHVybiBuZXcgQ3ViaWNJbnRlcnBvbGFudCggdGhpcy50aW1lcywgdGhpcy52YWx1ZXMsIHRoaXMuZ2V0VmFsdWVTaXplKCksIHJlc3VsdCApO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldEludGVycG9sYXRpb24oIGludGVycG9sYXRpb24gKSB7XHJcblxyXG5cdFx0bGV0IGZhY3RvcnlNZXRob2Q7XHJcblxyXG5cdFx0c3dpdGNoICggaW50ZXJwb2xhdGlvbiApIHtcclxuXHJcblx0XHRcdGNhc2UgSW50ZXJwb2xhdGVEaXNjcmV0ZTpcclxuXHJcblx0XHRcdFx0ZmFjdG9yeU1ldGhvZCA9IHRoaXMuSW50ZXJwb2xhbnRGYWN0b3J5TWV0aG9kRGlzY3JldGU7XHJcblxyXG5cdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0Y2FzZSBJbnRlcnBvbGF0ZUxpbmVhcjpcclxuXHJcblx0XHRcdFx0ZmFjdG9yeU1ldGhvZCA9IHRoaXMuSW50ZXJwb2xhbnRGYWN0b3J5TWV0aG9kTGluZWFyO1xyXG5cclxuXHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdGNhc2UgSW50ZXJwb2xhdGVTbW9vdGg6XHJcblxyXG5cdFx0XHRcdGZhY3RvcnlNZXRob2QgPSB0aGlzLkludGVycG9sYW50RmFjdG9yeU1ldGhvZFNtb290aDtcclxuXHJcblx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggZmFjdG9yeU1ldGhvZCA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0Y29uc3QgbWVzc2FnZSA9ICd1bnN1cHBvcnRlZCBpbnRlcnBvbGF0aW9uIGZvciAnICtcclxuXHRcdFx0XHR0aGlzLlZhbHVlVHlwZU5hbWUgKyAnIGtleWZyYW1lIHRyYWNrIG5hbWVkICcgKyB0aGlzLm5hbWU7XHJcblxyXG5cdFx0XHRpZiAoIHRoaXMuY3JlYXRlSW50ZXJwb2xhbnQgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0Ly8gZmFsbCBiYWNrIHRvIGRlZmF1bHQsIHVubGVzcyB0aGUgZGVmYXVsdCBpdHNlbGYgaXMgbWVzc2VkIHVwXHJcblx0XHRcdFx0aWYgKCBpbnRlcnBvbGF0aW9uICE9PSB0aGlzLkRlZmF1bHRJbnRlcnBvbGF0aW9uICkge1xyXG5cclxuXHRcdFx0XHRcdHRoaXMuc2V0SW50ZXJwb2xhdGlvbiggdGhpcy5EZWZhdWx0SW50ZXJwb2xhdGlvbiApO1xyXG5cclxuXHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdHRocm93IG5ldyBFcnJvciggbWVzc2FnZSApOyAvLyBmYXRhbCwgaW4gdGhpcyBjYXNlXHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLktleWZyYW1lVHJhY2s6JywgbWVzc2FnZSApO1xyXG5cdFx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5jcmVhdGVJbnRlcnBvbGFudCA9IGZhY3RvcnlNZXRob2Q7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0SW50ZXJwb2xhdGlvbigpIHtcclxuXHJcblx0XHRzd2l0Y2ggKCB0aGlzLmNyZWF0ZUludGVycG9sYW50ICkge1xyXG5cclxuXHRcdFx0Y2FzZSB0aGlzLkludGVycG9sYW50RmFjdG9yeU1ldGhvZERpc2NyZXRlOlxyXG5cclxuXHRcdFx0XHRyZXR1cm4gSW50ZXJwb2xhdGVEaXNjcmV0ZTtcclxuXHJcblx0XHRcdGNhc2UgdGhpcy5JbnRlcnBvbGFudEZhY3RvcnlNZXRob2RMaW5lYXI6XHJcblxyXG5cdFx0XHRcdHJldHVybiBJbnRlcnBvbGF0ZUxpbmVhcjtcclxuXHJcblx0XHRcdGNhc2UgdGhpcy5JbnRlcnBvbGFudEZhY3RvcnlNZXRob2RTbW9vdGg6XHJcblxyXG5cdFx0XHRcdHJldHVybiBJbnRlcnBvbGF0ZVNtb290aDtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0VmFsdWVTaXplKCkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLnZhbHVlcy5sZW5ndGggLyB0aGlzLnRpbWVzLmxlbmd0aDtcclxuXHJcblx0fVxyXG5cclxuXHQvLyBtb3ZlIGFsbCBrZXlmcmFtZXMgZWl0aGVyIGZvcndhcmRzIG9yIGJhY2t3YXJkcyBpbiB0aW1lXHJcblx0c2hpZnQoIHRpbWVPZmZzZXQgKSB7XHJcblxyXG5cdFx0aWYgKCB0aW1lT2Zmc2V0ICE9PSAwLjAgKSB7XHJcblxyXG5cdFx0XHRjb25zdCB0aW1lcyA9IHRoaXMudGltZXM7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIG4gPSB0aW1lcy5sZW5ndGg7IGkgIT09IG47ICsrIGkgKSB7XHJcblxyXG5cdFx0XHRcdHRpbWVzWyBpIF0gKz0gdGltZU9mZnNldDtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gc2NhbGUgYWxsIGtleWZyYW1lIHRpbWVzIGJ5IGEgZmFjdG9yICh1c2VmdWwgZm9yIGZyYW1lIDwtPiBzZWNvbmRzIGNvbnZlcnNpb25zKVxyXG5cdHNjYWxlKCB0aW1lU2NhbGUgKSB7XHJcblxyXG5cdFx0aWYgKCB0aW1lU2NhbGUgIT09IDEuMCApIHtcclxuXHJcblx0XHRcdGNvbnN0IHRpbWVzID0gdGhpcy50aW1lcztcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMCwgbiA9IHRpbWVzLmxlbmd0aDsgaSAhPT0gbjsgKysgaSApIHtcclxuXHJcblx0XHRcdFx0dGltZXNbIGkgXSAqPSB0aW1lU2NhbGU7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdC8vIHJlbW92ZXMga2V5ZnJhbWVzIGJlZm9yZSBhbmQgYWZ0ZXIgYW5pbWF0aW9uIHdpdGhvdXQgY2hhbmdpbmcgYW55IHZhbHVlcyB3aXRoaW4gdGhlIHJhbmdlIFtzdGFydFRpbWUsIGVuZFRpbWVdLlxyXG5cdC8vIElNUE9SVEFOVDogV2UgZG8gbm90IHNoaWZ0IGFyb3VuZCBrZXlzIHRvIHRoZSBzdGFydCBvZiB0aGUgdHJhY2sgdGltZSwgYmVjYXVzZSBmb3IgaW50ZXJwb2xhdGVkIGtleXMgdGhpcyB3aWxsIGNoYW5nZSB0aGVpciB2YWx1ZXNcclxuXHR0cmltKCBzdGFydFRpbWUsIGVuZFRpbWUgKSB7XHJcblxyXG5cdFx0Y29uc3QgdGltZXMgPSB0aGlzLnRpbWVzLFxyXG5cdFx0XHRuS2V5cyA9IHRpbWVzLmxlbmd0aDtcclxuXHJcblx0XHRsZXQgZnJvbSA9IDAsXHJcblx0XHRcdHRvID0gbktleXMgLSAxO1xyXG5cclxuXHRcdHdoaWxlICggZnJvbSAhPT0gbktleXMgJiYgdGltZXNbIGZyb20gXSA8IHN0YXJ0VGltZSApIHtcclxuXHJcblx0XHRcdCsrIGZyb207XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHdoaWxlICggdG8gIT09IC0gMSAmJiB0aW1lc1sgdG8gXSA+IGVuZFRpbWUgKSB7XHJcblxyXG5cdFx0XHQtLSB0bztcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0KysgdG87IC8vIGluY2x1c2l2ZSAtPiBleGNsdXNpdmUgYm91bmRcclxuXHJcblx0XHRpZiAoIGZyb20gIT09IDAgfHwgdG8gIT09IG5LZXlzICkge1xyXG5cclxuXHRcdFx0Ly8gZW1wdHkgdHJhY2tzIGFyZSBmb3JiaWRkZW4sIHNvIGtlZXAgYXQgbGVhc3Qgb25lIGtleWZyYW1lXHJcblx0XHRcdGlmICggZnJvbSA+PSB0byApIHtcclxuXHJcblx0XHRcdFx0dG8gPSBNYXRoLm1heCggdG8sIDEgKTtcclxuXHRcdFx0XHRmcm9tID0gdG8gLSAxO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Y29uc3Qgc3RyaWRlID0gdGhpcy5nZXRWYWx1ZVNpemUoKTtcclxuXHRcdFx0dGhpcy50aW1lcyA9IHRpbWVzLnNsaWNlKCBmcm9tLCB0byApO1xyXG5cdFx0XHR0aGlzLnZhbHVlcyA9IHRoaXMudmFsdWVzLnNsaWNlKCBmcm9tICogc3RyaWRlLCB0byAqIHN0cmlkZSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHQvLyBlbnN1cmUgd2UgZG8gbm90IGdldCBhIEdhcmJhZ2VJbkdhcmJhZ2VPdXQgc2l0dWF0aW9uLCBtYWtlIHN1cmUgdHJhY2tzIGFyZSBhdCBsZWFzdCBtaW5pbWFsbHkgdmlhYmxlXHJcblx0dmFsaWRhdGUoKSB7XHJcblxyXG5cdFx0bGV0IHZhbGlkID0gdHJ1ZTtcclxuXHJcblx0XHRjb25zdCB2YWx1ZVNpemUgPSB0aGlzLmdldFZhbHVlU2l6ZSgpO1xyXG5cdFx0aWYgKCB2YWx1ZVNpemUgLSBNYXRoLmZsb29yKCB2YWx1ZVNpemUgKSAhPT0gMCApIHtcclxuXHJcblx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5LZXlmcmFtZVRyYWNrOiBJbnZhbGlkIHZhbHVlIHNpemUgaW4gdHJhY2suJywgdGhpcyApO1xyXG5cdFx0XHR2YWxpZCA9IGZhbHNlO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCB0aW1lcyA9IHRoaXMudGltZXMsXHJcblx0XHRcdHZhbHVlcyA9IHRoaXMudmFsdWVzLFxyXG5cclxuXHRcdFx0bktleXMgPSB0aW1lcy5sZW5ndGg7XHJcblxyXG5cdFx0aWYgKCBuS2V5cyA9PT0gMCApIHtcclxuXHJcblx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5LZXlmcmFtZVRyYWNrOiBUcmFjayBpcyBlbXB0eS4nLCB0aGlzICk7XHJcblx0XHRcdHZhbGlkID0gZmFsc2U7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGxldCBwcmV2VGltZSA9IG51bGw7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpICE9PSBuS2V5czsgaSArKyApIHtcclxuXHJcblx0XHRcdGNvbnN0IGN1cnJUaW1lID0gdGltZXNbIGkgXTtcclxuXHJcblx0XHRcdGlmICggdHlwZW9mIGN1cnJUaW1lID09PSAnbnVtYmVyJyAmJiBpc05hTiggY3VyclRpbWUgKSApIHtcclxuXHJcblx0XHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLktleWZyYW1lVHJhY2s6IFRpbWUgaXMgbm90IGEgdmFsaWQgbnVtYmVyLicsIHRoaXMsIGksIGN1cnJUaW1lICk7XHJcblx0XHRcdFx0dmFsaWQgPSBmYWxzZTtcclxuXHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGlmICggcHJldlRpbWUgIT09IG51bGwgJiYgcHJldlRpbWUgPiBjdXJyVGltZSApIHtcclxuXHJcblx0XHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLktleWZyYW1lVHJhY2s6IE91dCBvZiBvcmRlciBrZXlzLicsIHRoaXMsIGksIGN1cnJUaW1lLCBwcmV2VGltZSApO1xyXG5cdFx0XHRcdHZhbGlkID0gZmFsc2U7XHJcblx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRwcmV2VGltZSA9IGN1cnJUaW1lO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHZhbHVlcyAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0aWYgKCBBbmltYXRpb25VdGlscy5pc1R5cGVkQXJyYXkoIHZhbHVlcyApICkge1xyXG5cclxuXHRcdFx0XHRmb3IgKCBsZXQgaSA9IDAsIG4gPSB2YWx1ZXMubGVuZ3RoOyBpICE9PSBuOyArKyBpICkge1xyXG5cclxuXHRcdFx0XHRcdGNvbnN0IHZhbHVlID0gdmFsdWVzWyBpIF07XHJcblxyXG5cdFx0XHRcdFx0aWYgKCBpc05hTiggdmFsdWUgKSApIHtcclxuXHJcblx0XHRcdFx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5LZXlmcmFtZVRyYWNrOiBWYWx1ZSBpcyBub3QgYSB2YWxpZCBudW1iZXIuJywgdGhpcywgaSwgdmFsdWUgKTtcclxuXHRcdFx0XHRcdFx0dmFsaWQgPSBmYWxzZTtcclxuXHRcdFx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB2YWxpZDtcclxuXHJcblx0fVxyXG5cclxuXHQvLyByZW1vdmVzIGVxdWl2YWxlbnQgc2VxdWVudGlhbCBrZXlzIGFzIGNvbW1vbiBpbiBtb3JwaCB0YXJnZXQgc2VxdWVuY2VzXHJcblx0Ly8gKDAsMCwwLDAsMSwxLDEsMCwwLDAsMCwwLDAsMCkgLS0+ICgwLDAsMSwxLDAsMClcclxuXHRvcHRpbWl6ZSgpIHtcclxuXHJcblx0XHQvLyB0aW1lcyBvciB2YWx1ZXMgbWF5IGJlIHNoYXJlZCB3aXRoIG90aGVyIHRyYWNrcywgc28gb3ZlcndyaXRpbmcgaXMgdW5zYWZlXHJcblx0XHRjb25zdCB0aW1lcyA9IHRoaXMudGltZXMuc2xpY2UoKSxcclxuXHRcdFx0dmFsdWVzID0gdGhpcy52YWx1ZXMuc2xpY2UoKSxcclxuXHRcdFx0c3RyaWRlID0gdGhpcy5nZXRWYWx1ZVNpemUoKSxcclxuXHJcblx0XHRcdHNtb290aEludGVycG9sYXRpb24gPSB0aGlzLmdldEludGVycG9sYXRpb24oKSA9PT0gSW50ZXJwb2xhdGVTbW9vdGgsXHJcblxyXG5cdFx0XHRsYXN0SW5kZXggPSB0aW1lcy5sZW5ndGggLSAxO1xyXG5cclxuXHRcdGxldCB3cml0ZUluZGV4ID0gMTtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDE7IGkgPCBsYXN0SW5kZXg7ICsrIGkgKSB7XHJcblxyXG5cdFx0XHRsZXQga2VlcCA9IGZhbHNlO1xyXG5cclxuXHRcdFx0Y29uc3QgdGltZSA9IHRpbWVzWyBpIF07XHJcblx0XHRcdGNvbnN0IHRpbWVOZXh0ID0gdGltZXNbIGkgKyAxIF07XHJcblxyXG5cdFx0XHQvLyByZW1vdmUgYWRqYWNlbnQga2V5ZnJhbWVzIHNjaGVkdWxlZCBhdCB0aGUgc2FtZSB0aW1lXHJcblxyXG5cdFx0XHRpZiAoIHRpbWUgIT09IHRpbWVOZXh0ICYmICggaSAhPT0gMSB8fCB0aW1lICE9PSB0aW1lc1sgMCBdICkgKSB7XHJcblxyXG5cdFx0XHRcdGlmICggISBzbW9vdGhJbnRlcnBvbGF0aW9uICkge1xyXG5cclxuXHRcdFx0XHRcdC8vIHJlbW92ZSB1bm5lY2Vzc2FyeSBrZXlmcmFtZXMgc2FtZSBhcyB0aGVpciBuZWlnaGJvcnNcclxuXHJcblx0XHRcdFx0XHRjb25zdCBvZmZzZXQgPSBpICogc3RyaWRlLFxyXG5cdFx0XHRcdFx0XHRvZmZzZXRQID0gb2Zmc2V0IC0gc3RyaWRlLFxyXG5cdFx0XHRcdFx0XHRvZmZzZXROID0gb2Zmc2V0ICsgc3RyaWRlO1xyXG5cclxuXHRcdFx0XHRcdGZvciAoIGxldCBqID0gMDsgaiAhPT0gc3RyaWRlOyArKyBqICkge1xyXG5cclxuXHRcdFx0XHRcdFx0Y29uc3QgdmFsdWUgPSB2YWx1ZXNbIG9mZnNldCArIGogXTtcclxuXHJcblx0XHRcdFx0XHRcdGlmICggdmFsdWUgIT09IHZhbHVlc1sgb2Zmc2V0UCArIGogXSB8fFxyXG5cdFx0XHRcdFx0XHRcdHZhbHVlICE9PSB2YWx1ZXNbIG9mZnNldE4gKyBqIF0gKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdGtlZXAgPSB0cnVlO1xyXG5cdFx0XHRcdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRrZWVwID0gdHJ1ZTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Ly8gaW4tcGxhY2UgY29tcGFjdGlvblxyXG5cclxuXHRcdFx0aWYgKCBrZWVwICkge1xyXG5cclxuXHRcdFx0XHRpZiAoIGkgIT09IHdyaXRlSW5kZXggKSB7XHJcblxyXG5cdFx0XHRcdFx0dGltZXNbIHdyaXRlSW5kZXggXSA9IHRpbWVzWyBpIF07XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgcmVhZE9mZnNldCA9IGkgKiBzdHJpZGUsXHJcblx0XHRcdFx0XHRcdHdyaXRlT2Zmc2V0ID0gd3JpdGVJbmRleCAqIHN0cmlkZTtcclxuXHJcblx0XHRcdFx0XHRmb3IgKCBsZXQgaiA9IDA7IGogIT09IHN0cmlkZTsgKysgaiApIHtcclxuXHJcblx0XHRcdFx0XHRcdHZhbHVlc1sgd3JpdGVPZmZzZXQgKyBqIF0gPSB2YWx1ZXNbIHJlYWRPZmZzZXQgKyBqIF07XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdCsrIHdyaXRlSW5kZXg7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIGZsdXNoIGxhc3Qga2V5ZnJhbWUgKGNvbXBhY3Rpb24gbG9va3MgYWhlYWQpXHJcblxyXG5cdFx0aWYgKCBsYXN0SW5kZXggPiAwICkge1xyXG5cclxuXHRcdFx0dGltZXNbIHdyaXRlSW5kZXggXSA9IHRpbWVzWyBsYXN0SW5kZXggXTtcclxuXHJcblx0XHRcdGZvciAoIGxldCByZWFkT2Zmc2V0ID0gbGFzdEluZGV4ICogc3RyaWRlLCB3cml0ZU9mZnNldCA9IHdyaXRlSW5kZXggKiBzdHJpZGUsIGogPSAwOyBqICE9PSBzdHJpZGU7ICsrIGogKSB7XHJcblxyXG5cdFx0XHRcdHZhbHVlc1sgd3JpdGVPZmZzZXQgKyBqIF0gPSB2YWx1ZXNbIHJlYWRPZmZzZXQgKyBqIF07XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQrKyB3cml0ZUluZGV4O1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHdyaXRlSW5kZXggIT09IHRpbWVzLmxlbmd0aCApIHtcclxuXHJcblx0XHRcdHRoaXMudGltZXMgPSB0aW1lcy5zbGljZSggMCwgd3JpdGVJbmRleCApO1xyXG5cdFx0XHR0aGlzLnZhbHVlcyA9IHZhbHVlcy5zbGljZSggMCwgd3JpdGVJbmRleCAqIHN0cmlkZSApO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHR0aGlzLnRpbWVzID0gdGltZXM7XHJcblx0XHRcdHRoaXMudmFsdWVzID0gdmFsdWVzO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRjbG9uZSgpIHtcclxuXHJcblx0XHRjb25zdCB0aW1lcyA9IHRoaXMudGltZXMuc2xpY2UoKTtcclxuXHRcdGNvbnN0IHZhbHVlcyA9IHRoaXMudmFsdWVzLnNsaWNlKCk7XHJcblxyXG5cdFx0Y29uc3QgVHlwZWRLZXlmcmFtZVRyYWNrID0gdGhpcy5jb25zdHJ1Y3RvcjtcclxuXHRcdGNvbnN0IHRyYWNrID0gbmV3IFR5cGVkS2V5ZnJhbWVUcmFjayggdGhpcy5uYW1lLCB0aW1lcywgdmFsdWVzICk7XHJcblxyXG5cdFx0Ly8gSW50ZXJwb2xhbnQgYXJndW1lbnQgdG8gY29uc3RydWN0b3IgaXMgbm90IHNhdmVkLCBzbyBjb3B5IHRoZSBmYWN0b3J5IG1ldGhvZCBkaXJlY3RseS5cclxuXHRcdHRyYWNrLmNyZWF0ZUludGVycG9sYW50ID0gdGhpcy5jcmVhdGVJbnRlcnBvbGFudDtcclxuXHJcblx0XHRyZXR1cm4gdHJhY2s7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbktleWZyYW1lVHJhY2sucHJvdG90eXBlLlRpbWVCdWZmZXJUeXBlID0gRmxvYXQzMkFycmF5O1xyXG5LZXlmcmFtZVRyYWNrLnByb3RvdHlwZS5WYWx1ZUJ1ZmZlclR5cGUgPSBGbG9hdDMyQXJyYXk7XHJcbktleWZyYW1lVHJhY2sucHJvdG90eXBlLkRlZmF1bHRJbnRlcnBvbGF0aW9uID0gSW50ZXJwb2xhdGVMaW5lYXI7XHJcblxyXG5leHBvcnQgeyBLZXlmcmFtZVRyYWNrIH07XHJcbiIsImltcG9ydCB7IEludGVycG9sYXRlRGlzY3JldGUgfSBmcm9tICcuLi8uLi9jb25zdGFudHMuanMnO1xyXG5pbXBvcnQgeyBLZXlmcmFtZVRyYWNrIH0gZnJvbSAnLi4vS2V5ZnJhbWVUcmFjay5qcyc7XHJcblxyXG4vKipcclxuICogQSBUcmFjayBvZiBCb29sZWFuIGtleWZyYW1lIHZhbHVlcy5cclxuICovXHJcbmNsYXNzIEJvb2xlYW5LZXlmcmFtZVRyYWNrIGV4dGVuZHMgS2V5ZnJhbWVUcmFjayB7fVxyXG5cclxuQm9vbGVhbktleWZyYW1lVHJhY2sucHJvdG90eXBlLlZhbHVlVHlwZU5hbWUgPSAnYm9vbCc7XHJcbkJvb2xlYW5LZXlmcmFtZVRyYWNrLnByb3RvdHlwZS5WYWx1ZUJ1ZmZlclR5cGUgPSBBcnJheTtcclxuQm9vbGVhbktleWZyYW1lVHJhY2sucHJvdG90eXBlLkRlZmF1bHRJbnRlcnBvbGF0aW9uID0gSW50ZXJwb2xhdGVEaXNjcmV0ZTtcclxuQm9vbGVhbktleWZyYW1lVHJhY2sucHJvdG90eXBlLkludGVycG9sYW50RmFjdG9yeU1ldGhvZExpbmVhciA9IHVuZGVmaW5lZDtcclxuQm9vbGVhbktleWZyYW1lVHJhY2sucHJvdG90eXBlLkludGVycG9sYW50RmFjdG9yeU1ldGhvZFNtb290aCA9IHVuZGVmaW5lZDtcclxuXHJcbi8vIE5vdGU6IEFjdHVhbGx5IHRoaXMgdHJhY2sgY291bGQgaGF2ZSBhIG9wdGltaXplZCAvIGNvbXByZXNzZWRcclxuLy8gcmVwcmVzZW50YXRpb24gb2YgYSBzaW5nbGUgdmFsdWUgYW5kIGEgY3VzdG9tIGludGVycG9sYW50IHRoYXRcclxuLy8gY29tcHV0ZXMgXCJmaXJzdFZhbHVlIF4gaXNPZGQoIGluZGV4IClcIi5cclxuXHJcbmV4cG9ydCB7IEJvb2xlYW5LZXlmcmFtZVRyYWNrIH07XHJcbiIsImltcG9ydCB7IEtleWZyYW1lVHJhY2sgfSBmcm9tICcuLi9LZXlmcmFtZVRyYWNrLmpzJztcclxuXHJcbi8qKlxyXG4gKiBBIFRyYWNrIG9mIGtleWZyYW1lIHZhbHVlcyB0aGF0IHJlcHJlc2VudCBjb2xvci5cclxuICovXHJcbmNsYXNzIENvbG9yS2V5ZnJhbWVUcmFjayBleHRlbmRzIEtleWZyYW1lVHJhY2sge31cclxuXHJcbkNvbG9yS2V5ZnJhbWVUcmFjay5wcm90b3R5cGUuVmFsdWVUeXBlTmFtZSA9ICdjb2xvcic7XHJcbi8vIFZhbHVlQnVmZmVyVHlwZSBpcyBpbmhlcml0ZWRcclxuLy8gRGVmYXVsdEludGVycG9sYXRpb24gaXMgaW5oZXJpdGVkXHJcblxyXG4vLyBOb3RlOiBWZXJ5IGJhc2ljIGltcGxlbWVudGF0aW9uIGFuZCBub3RoaW5nIHNwZWNpYWwgeWV0LlxyXG4vLyBIb3dldmVyLCB0aGlzIGlzIHRoZSBwbGFjZSBmb3IgY29sb3Igc3BhY2UgcGFyYW1ldGVyaXphdGlvbi5cclxuXHJcbmV4cG9ydCB7IENvbG9yS2V5ZnJhbWVUcmFjayB9O1xyXG4iLCJpbXBvcnQgeyBLZXlmcmFtZVRyYWNrIH0gZnJvbSAnLi4vS2V5ZnJhbWVUcmFjay5qcyc7XHJcblxyXG4vKipcclxuICogQSBUcmFjayBvZiBudW1lcmljIGtleWZyYW1lIHZhbHVlcy5cclxuICovXHJcbmNsYXNzIE51bWJlcktleWZyYW1lVHJhY2sgZXh0ZW5kcyBLZXlmcmFtZVRyYWNrIHt9XHJcblxyXG5OdW1iZXJLZXlmcmFtZVRyYWNrLnByb3RvdHlwZS5WYWx1ZVR5cGVOYW1lID0gJ251bWJlcic7XHJcbi8vIFZhbHVlQnVmZmVyVHlwZSBpcyBpbmhlcml0ZWRcclxuLy8gRGVmYXVsdEludGVycG9sYXRpb24gaXMgaW5oZXJpdGVkXHJcblxyXG5leHBvcnQgeyBOdW1iZXJLZXlmcmFtZVRyYWNrIH07XHJcbiIsImltcG9ydCB7IEludGVycG9sYW50IH0gZnJvbSAnLi4vSW50ZXJwb2xhbnQuanMnO1xyXG5pbXBvcnQgeyBRdWF0ZXJuaW9uIH0gZnJvbSAnLi4vUXVhdGVybmlvbi5qcyc7XHJcblxyXG4vKipcclxuICogU3BoZXJpY2FsIGxpbmVhciB1bml0IHF1YXRlcm5pb24gaW50ZXJwb2xhbnQuXHJcbiAqL1xyXG5cclxuY2xhc3MgUXVhdGVybmlvbkxpbmVhckludGVycG9sYW50IGV4dGVuZHMgSW50ZXJwb2xhbnQge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggcGFyYW1ldGVyUG9zaXRpb25zLCBzYW1wbGVWYWx1ZXMsIHNhbXBsZVNpemUsIHJlc3VsdEJ1ZmZlciApIHtcclxuXHJcblx0XHRzdXBlciggcGFyYW1ldGVyUG9zaXRpb25zLCBzYW1wbGVWYWx1ZXMsIHNhbXBsZVNpemUsIHJlc3VsdEJ1ZmZlciApO1xyXG5cclxuXHR9XHJcblxyXG5cdGludGVycG9sYXRlXyggaTEsIHQwLCB0LCB0MSApIHtcclxuXHJcblx0XHRjb25zdCByZXN1bHQgPSB0aGlzLnJlc3VsdEJ1ZmZlcixcclxuXHRcdFx0dmFsdWVzID0gdGhpcy5zYW1wbGVWYWx1ZXMsXHJcblx0XHRcdHN0cmlkZSA9IHRoaXMudmFsdWVTaXplLFxyXG5cclxuXHRcdFx0YWxwaGEgPSAoIHQgLSB0MCApIC8gKCB0MSAtIHQwICk7XHJcblxyXG5cdFx0bGV0IG9mZnNldCA9IGkxICogc3RyaWRlO1xyXG5cclxuXHRcdGZvciAoIGxldCBlbmQgPSBvZmZzZXQgKyBzdHJpZGU7IG9mZnNldCAhPT0gZW5kOyBvZmZzZXQgKz0gNCApIHtcclxuXHJcblx0XHRcdFF1YXRlcm5pb24uc2xlcnBGbGF0KCByZXN1bHQsIDAsIHZhbHVlcywgb2Zmc2V0IC0gc3RyaWRlLCB2YWx1ZXMsIG9mZnNldCwgYWxwaGEgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHJlc3VsdDtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuXHJcbmV4cG9ydCB7IFF1YXRlcm5pb25MaW5lYXJJbnRlcnBvbGFudCB9O1xyXG4iLCJpbXBvcnQgeyBJbnRlcnBvbGF0ZUxpbmVhciB9IGZyb20gJy4uLy4uL2NvbnN0YW50cy5qcyc7XHJcbmltcG9ydCB7IEtleWZyYW1lVHJhY2sgfSBmcm9tICcuLi9LZXlmcmFtZVRyYWNrLmpzJztcclxuaW1wb3J0IHsgUXVhdGVybmlvbkxpbmVhckludGVycG9sYW50IH0gZnJvbSAnLi4vLi4vbWF0aC9pbnRlcnBvbGFudHMvUXVhdGVybmlvbkxpbmVhckludGVycG9sYW50LmpzJztcclxuXHJcbi8qKlxyXG4gKiBBIFRyYWNrIG9mIHF1YXRlcm5pb24ga2V5ZnJhbWUgdmFsdWVzLlxyXG4gKi9cclxuY2xhc3MgUXVhdGVybmlvbktleWZyYW1lVHJhY2sgZXh0ZW5kcyBLZXlmcmFtZVRyYWNrIHtcclxuXHJcblx0SW50ZXJwb2xhbnRGYWN0b3J5TWV0aG9kTGluZWFyKCByZXN1bHQgKSB7XHJcblxyXG5cdFx0cmV0dXJuIG5ldyBRdWF0ZXJuaW9uTGluZWFySW50ZXJwb2xhbnQoIHRoaXMudGltZXMsIHRoaXMudmFsdWVzLCB0aGlzLmdldFZhbHVlU2l6ZSgpLCByZXN1bHQgKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuUXVhdGVybmlvbktleWZyYW1lVHJhY2sucHJvdG90eXBlLlZhbHVlVHlwZU5hbWUgPSAncXVhdGVybmlvbic7XHJcbi8vIFZhbHVlQnVmZmVyVHlwZSBpcyBpbmhlcml0ZWRcclxuUXVhdGVybmlvbktleWZyYW1lVHJhY2sucHJvdG90eXBlLkRlZmF1bHRJbnRlcnBvbGF0aW9uID0gSW50ZXJwb2xhdGVMaW5lYXI7XHJcblF1YXRlcm5pb25LZXlmcmFtZVRyYWNrLnByb3RvdHlwZS5JbnRlcnBvbGFudEZhY3RvcnlNZXRob2RTbW9vdGggPSB1bmRlZmluZWQ7XHJcblxyXG5leHBvcnQgeyBRdWF0ZXJuaW9uS2V5ZnJhbWVUcmFjayB9O1xyXG4iLCJpbXBvcnQgeyBJbnRlcnBvbGF0ZURpc2NyZXRlIH0gZnJvbSAnLi4vLi4vY29uc3RhbnRzLmpzJztcclxuaW1wb3J0IHsgS2V5ZnJhbWVUcmFjayB9IGZyb20gJy4uL0tleWZyYW1lVHJhY2suanMnO1xyXG5cclxuLyoqXHJcbiAqIEEgVHJhY2sgdGhhdCBpbnRlcnBvbGF0ZXMgU3RyaW5nc1xyXG4gKi9cclxuY2xhc3MgU3RyaW5nS2V5ZnJhbWVUcmFjayBleHRlbmRzIEtleWZyYW1lVHJhY2sge31cclxuXHJcblN0cmluZ0tleWZyYW1lVHJhY2sucHJvdG90eXBlLlZhbHVlVHlwZU5hbWUgPSAnc3RyaW5nJztcclxuU3RyaW5nS2V5ZnJhbWVUcmFjay5wcm90b3R5cGUuVmFsdWVCdWZmZXJUeXBlID0gQXJyYXk7XHJcblN0cmluZ0tleWZyYW1lVHJhY2sucHJvdG90eXBlLkRlZmF1bHRJbnRlcnBvbGF0aW9uID0gSW50ZXJwb2xhdGVEaXNjcmV0ZTtcclxuU3RyaW5nS2V5ZnJhbWVUcmFjay5wcm90b3R5cGUuSW50ZXJwb2xhbnRGYWN0b3J5TWV0aG9kTGluZWFyID0gdW5kZWZpbmVkO1xyXG5TdHJpbmdLZXlmcmFtZVRyYWNrLnByb3RvdHlwZS5JbnRlcnBvbGFudEZhY3RvcnlNZXRob2RTbW9vdGggPSB1bmRlZmluZWQ7XHJcblxyXG5leHBvcnQgeyBTdHJpbmdLZXlmcmFtZVRyYWNrIH07XHJcbiIsImltcG9ydCB7IEtleWZyYW1lVHJhY2sgfSBmcm9tICcuLi9LZXlmcmFtZVRyYWNrLmpzJztcclxuXHJcbi8qKlxyXG4gKiBBIFRyYWNrIG9mIHZlY3RvcmVkIGtleWZyYW1lIHZhbHVlcy5cclxuICovXHJcbmNsYXNzIFZlY3RvcktleWZyYW1lVHJhY2sgZXh0ZW5kcyBLZXlmcmFtZVRyYWNrIHt9XHJcblxyXG5WZWN0b3JLZXlmcmFtZVRyYWNrLnByb3RvdHlwZS5WYWx1ZVR5cGVOYW1lID0gJ3ZlY3Rvcic7XHJcbi8vIFZhbHVlQnVmZmVyVHlwZSBpcyBpbmhlcml0ZWRcclxuLy8gRGVmYXVsdEludGVycG9sYXRpb24gaXMgaW5oZXJpdGVkXHJcblxyXG5leHBvcnQgeyBWZWN0b3JLZXlmcmFtZVRyYWNrIH07XHJcbiIsImltcG9ydCAqIGFzIEFuaW1hdGlvblV0aWxzIGZyb20gJy4vQW5pbWF0aW9uVXRpbHMuanMnO1xyXG5pbXBvcnQgeyBLZXlmcmFtZVRyYWNrIH0gZnJvbSAnLi9LZXlmcmFtZVRyYWNrLmpzJztcclxuaW1wb3J0IHsgQm9vbGVhbktleWZyYW1lVHJhY2sgfSBmcm9tICcuL3RyYWNrcy9Cb29sZWFuS2V5ZnJhbWVUcmFjay5qcyc7XHJcbmltcG9ydCB7IENvbG9yS2V5ZnJhbWVUcmFjayB9IGZyb20gJy4vdHJhY2tzL0NvbG9yS2V5ZnJhbWVUcmFjay5qcyc7XHJcbmltcG9ydCB7IE51bWJlcktleWZyYW1lVHJhY2sgfSBmcm9tICcuL3RyYWNrcy9OdW1iZXJLZXlmcmFtZVRyYWNrLmpzJztcclxuaW1wb3J0IHsgUXVhdGVybmlvbktleWZyYW1lVHJhY2sgfSBmcm9tICcuL3RyYWNrcy9RdWF0ZXJuaW9uS2V5ZnJhbWVUcmFjay5qcyc7XHJcbmltcG9ydCB7IFN0cmluZ0tleWZyYW1lVHJhY2sgfSBmcm9tICcuL3RyYWNrcy9TdHJpbmdLZXlmcmFtZVRyYWNrLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yS2V5ZnJhbWVUcmFjayB9IGZyb20gJy4vdHJhY2tzL1ZlY3RvcktleWZyYW1lVHJhY2suanMnO1xyXG5pbXBvcnQgKiBhcyBNYXRoVXRpbHMgZnJvbSAnLi4vbWF0aC9NYXRoVXRpbHMuanMnO1xyXG5pbXBvcnQgeyBOb3JtYWxBbmltYXRpb25CbGVuZE1vZGUgfSBmcm9tICcuLi9jb25zdGFudHMuanMnO1xyXG5cclxuY2xhc3MgQW5pbWF0aW9uQ2xpcCB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBuYW1lLCBkdXJhdGlvbiA9IC0gMSwgdHJhY2tzLCBibGVuZE1vZGUgPSBOb3JtYWxBbmltYXRpb25CbGVuZE1vZGUgKSB7XHJcblxyXG5cdFx0dGhpcy5uYW1lID0gbmFtZTtcclxuXHRcdHRoaXMudHJhY2tzID0gdHJhY2tzO1xyXG5cdFx0dGhpcy5kdXJhdGlvbiA9IGR1cmF0aW9uO1xyXG5cdFx0dGhpcy5ibGVuZE1vZGUgPSBibGVuZE1vZGU7XHJcblxyXG5cdFx0dGhpcy51dWlkID0gTWF0aFV0aWxzLmdlbmVyYXRlVVVJRCgpO1xyXG5cclxuXHRcdC8vIHRoaXMgbWVhbnMgaXQgc2hvdWxkIGZpZ3VyZSBvdXQgaXRzIGR1cmF0aW9uIGJ5IHNjYW5uaW5nIHRoZSB0cmFja3NcclxuXHRcdGlmICggdGhpcy5kdXJhdGlvbiA8IDAgKSB7XHJcblxyXG5cdFx0XHR0aGlzLnJlc2V0RHVyYXRpb24oKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblxyXG5cdHN0YXRpYyBwYXJzZSgganNvbiApIHtcclxuXHJcblx0XHRjb25zdCB0cmFja3MgPSBbXSxcclxuXHRcdFx0anNvblRyYWNrcyA9IGpzb24udHJhY2tzLFxyXG5cdFx0XHRmcmFtZVRpbWUgPSAxLjAgLyAoIGpzb24uZnBzIHx8IDEuMCApO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMCwgbiA9IGpzb25UcmFja3MubGVuZ3RoOyBpICE9PSBuOyArKyBpICkge1xyXG5cclxuXHRcdFx0dHJhY2tzLnB1c2goIHBhcnNlS2V5ZnJhbWVUcmFjaygganNvblRyYWNrc1sgaSBdICkuc2NhbGUoIGZyYW1lVGltZSApICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGNvbnN0IGNsaXAgPSBuZXcgdGhpcygganNvbi5uYW1lLCBqc29uLmR1cmF0aW9uLCB0cmFja3MsIGpzb24uYmxlbmRNb2RlICk7XHJcblx0XHRjbGlwLnV1aWQgPSBqc29uLnV1aWQ7XHJcblxyXG5cdFx0cmV0dXJuIGNsaXA7XHJcblxyXG5cdH1cclxuXHJcblx0c3RhdGljIHRvSlNPTiggY2xpcCApIHtcclxuXHJcblx0XHRjb25zdCB0cmFja3MgPSBbXSxcclxuXHRcdFx0Y2xpcFRyYWNrcyA9IGNsaXAudHJhY2tzO1xyXG5cclxuXHRcdGNvbnN0IGpzb24gPSB7XHJcblxyXG5cdFx0XHQnbmFtZSc6IGNsaXAubmFtZSxcclxuXHRcdFx0J2R1cmF0aW9uJzogY2xpcC5kdXJhdGlvbixcclxuXHRcdFx0J3RyYWNrcyc6IHRyYWNrcyxcclxuXHRcdFx0J3V1aWQnOiBjbGlwLnV1aWQsXHJcblx0XHRcdCdibGVuZE1vZGUnOiBjbGlwLmJsZW5kTW9kZVxyXG5cclxuXHRcdH07XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBuID0gY2xpcFRyYWNrcy5sZW5ndGg7IGkgIT09IG47ICsrIGkgKSB7XHJcblxyXG5cdFx0XHR0cmFja3MucHVzaCggS2V5ZnJhbWVUcmFjay50b0pTT04oIGNsaXBUcmFja3NbIGkgXSApICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiBqc29uO1xyXG5cclxuXHR9XHJcblxyXG5cdHN0YXRpYyBDcmVhdGVGcm9tTW9ycGhUYXJnZXRTZXF1ZW5jZSggbmFtZSwgbW9ycGhUYXJnZXRTZXF1ZW5jZSwgZnBzLCBub0xvb3AgKSB7XHJcblxyXG5cdFx0Y29uc3QgbnVtTW9ycGhUYXJnZXRzID0gbW9ycGhUYXJnZXRTZXF1ZW5jZS5sZW5ndGg7XHJcblx0XHRjb25zdCB0cmFja3MgPSBbXTtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBudW1Nb3JwaFRhcmdldHM7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRsZXQgdGltZXMgPSBbXTtcclxuXHRcdFx0bGV0IHZhbHVlcyA9IFtdO1xyXG5cclxuXHRcdFx0dGltZXMucHVzaChcclxuXHRcdFx0XHQoIGkgKyBudW1Nb3JwaFRhcmdldHMgLSAxICkgJSBudW1Nb3JwaFRhcmdldHMsXHJcblx0XHRcdFx0aSxcclxuXHRcdFx0XHQoIGkgKyAxICkgJSBudW1Nb3JwaFRhcmdldHMgKTtcclxuXHJcblx0XHRcdHZhbHVlcy5wdXNoKCAwLCAxLCAwICk7XHJcblxyXG5cdFx0XHRjb25zdCBvcmRlciA9IEFuaW1hdGlvblV0aWxzLmdldEtleWZyYW1lT3JkZXIoIHRpbWVzICk7XHJcblx0XHRcdHRpbWVzID0gQW5pbWF0aW9uVXRpbHMuc29ydGVkQXJyYXkoIHRpbWVzLCAxLCBvcmRlciApO1xyXG5cdFx0XHR2YWx1ZXMgPSBBbmltYXRpb25VdGlscy5zb3J0ZWRBcnJheSggdmFsdWVzLCAxLCBvcmRlciApO1xyXG5cclxuXHRcdFx0Ly8gaWYgdGhlcmUgaXMgYSBrZXkgYXQgdGhlIGZpcnN0IGZyYW1lLCBkdXBsaWNhdGUgaXQgYXMgdGhlXHJcblx0XHRcdC8vIGxhc3QgZnJhbWUgYXMgd2VsbCBmb3IgcGVyZmVjdCBsb29wLlxyXG5cdFx0XHRpZiAoICEgbm9Mb29wICYmIHRpbWVzWyAwIF0gPT09IDAgKSB7XHJcblxyXG5cdFx0XHRcdHRpbWVzLnB1c2goIG51bU1vcnBoVGFyZ2V0cyApO1xyXG5cdFx0XHRcdHZhbHVlcy5wdXNoKCB2YWx1ZXNbIDAgXSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0dHJhY2tzLnB1c2goXHJcblx0XHRcdFx0bmV3IE51bWJlcktleWZyYW1lVHJhY2soXHJcblx0XHRcdFx0XHQnLm1vcnBoVGFyZ2V0SW5mbHVlbmNlc1snICsgbW9ycGhUYXJnZXRTZXF1ZW5jZVsgaSBdLm5hbWUgKyAnXScsXHJcblx0XHRcdFx0XHR0aW1lcywgdmFsdWVzXHJcblx0XHRcdFx0KS5zY2FsZSggMS4wIC8gZnBzICkgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIG5ldyB0aGlzKCBuYW1lLCAtIDEsIHRyYWNrcyApO1xyXG5cclxuXHR9XHJcblxyXG5cdHN0YXRpYyBmaW5kQnlOYW1lKCBvYmplY3RPckNsaXBBcnJheSwgbmFtZSApIHtcclxuXHJcblx0XHRsZXQgY2xpcEFycmF5ID0gb2JqZWN0T3JDbGlwQXJyYXk7XHJcblxyXG5cdFx0aWYgKCAhIEFycmF5LmlzQXJyYXkoIG9iamVjdE9yQ2xpcEFycmF5ICkgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBvID0gb2JqZWN0T3JDbGlwQXJyYXk7XHJcblx0XHRcdGNsaXBBcnJheSA9IG8uZ2VvbWV0cnkgJiYgby5nZW9tZXRyeS5hbmltYXRpb25zIHx8IG8uYW5pbWF0aW9ucztcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgY2xpcEFycmF5Lmxlbmd0aDsgaSArKyApIHtcclxuXHJcblx0XHRcdGlmICggY2xpcEFycmF5WyBpIF0ubmFtZSA9PT0gbmFtZSApIHtcclxuXHJcblx0XHRcdFx0cmV0dXJuIGNsaXBBcnJheVsgaSBdO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gbnVsbDtcclxuXHJcblx0fVxyXG5cclxuXHRzdGF0aWMgQ3JlYXRlQ2xpcHNGcm9tTW9ycGhUYXJnZXRTZXF1ZW5jZXMoIG1vcnBoVGFyZ2V0cywgZnBzLCBub0xvb3AgKSB7XHJcblxyXG5cdFx0Y29uc3QgYW5pbWF0aW9uVG9Nb3JwaFRhcmdldHMgPSB7fTtcclxuXHJcblx0XHQvLyB0ZXN0ZWQgd2l0aCBodHRwczovL3JlZ2V4MTAxLmNvbS8gb24gdHJpY2sgc2VxdWVuY2VzXHJcblx0XHQvLyBzdWNoIGZsYW1pbmdvX2ZseUFfMDAzLCBmbGFtaW5nb19ydW4xXzAwMywgY3JkZWF0aDAwNTlcclxuXHRcdGNvbnN0IHBhdHRlcm4gPSAvXihbXFx3LV0qPykoW1xcZF0rKSQvO1xyXG5cclxuXHRcdC8vIHNvcnQgbW9ycGggdGFyZ2V0IG5hbWVzIGludG8gYW5pbWF0aW9uIGdyb3VwcyBiYXNlZFxyXG5cdFx0Ly8gcGF0dGVybnMgbGlrZSBXYWxrXzAwMSwgV2Fsa18wMDIsIFJ1bl8wMDEsIFJ1bl8wMDJcclxuXHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSBtb3JwaFRhcmdldHMubGVuZ3RoOyBpIDwgaWw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBtb3JwaFRhcmdldCA9IG1vcnBoVGFyZ2V0c1sgaSBdO1xyXG5cdFx0XHRjb25zdCBwYXJ0cyA9IG1vcnBoVGFyZ2V0Lm5hbWUubWF0Y2goIHBhdHRlcm4gKTtcclxuXHJcblx0XHRcdGlmICggcGFydHMgJiYgcGFydHMubGVuZ3RoID4gMSApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgbmFtZSA9IHBhcnRzWyAxIF07XHJcblxyXG5cdFx0XHRcdGxldCBhbmltYXRpb25Nb3JwaFRhcmdldHMgPSBhbmltYXRpb25Ub01vcnBoVGFyZ2V0c1sgbmFtZSBdO1xyXG5cclxuXHRcdFx0XHRpZiAoICEgYW5pbWF0aW9uTW9ycGhUYXJnZXRzICkge1xyXG5cclxuXHRcdFx0XHRcdGFuaW1hdGlvblRvTW9ycGhUYXJnZXRzWyBuYW1lIF0gPSBhbmltYXRpb25Nb3JwaFRhcmdldHMgPSBbXTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRhbmltYXRpb25Nb3JwaFRhcmdldHMucHVzaCggbW9ycGhUYXJnZXQgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Y29uc3QgY2xpcHMgPSBbXTtcclxuXHJcblx0XHRmb3IgKCBjb25zdCBuYW1lIGluIGFuaW1hdGlvblRvTW9ycGhUYXJnZXRzICkge1xyXG5cclxuXHRcdFx0Y2xpcHMucHVzaCggdGhpcy5DcmVhdGVGcm9tTW9ycGhUYXJnZXRTZXF1ZW5jZSggbmFtZSwgYW5pbWF0aW9uVG9Nb3JwaFRhcmdldHNbIG5hbWUgXSwgZnBzLCBub0xvb3AgKSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gY2xpcHM7XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gcGFyc2UgdGhlIGFuaW1hdGlvbi5oaWVyYXJjaHkgZm9ybWF0XHJcblx0c3RhdGljIHBhcnNlQW5pbWF0aW9uKCBhbmltYXRpb24sIGJvbmVzICkge1xyXG5cclxuXHRcdGlmICggISBhbmltYXRpb24gKSB7XHJcblxyXG5cdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuQW5pbWF0aW9uQ2xpcDogTm8gYW5pbWF0aW9uIGluIEpTT05Mb2FkZXIgZGF0YS4nICk7XHJcblx0XHRcdHJldHVybiBudWxsO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCBhZGROb25lbXB0eVRyYWNrID0gZnVuY3Rpb24gKCB0cmFja1R5cGUsIHRyYWNrTmFtZSwgYW5pbWF0aW9uS2V5cywgcHJvcGVydHlOYW1lLCBkZXN0VHJhY2tzICkge1xyXG5cclxuXHRcdFx0Ly8gb25seSByZXR1cm4gdHJhY2sgaWYgdGhlcmUgYXJlIGFjdHVhbGx5IGtleXMuXHJcblx0XHRcdGlmICggYW5pbWF0aW9uS2V5cy5sZW5ndGggIT09IDAgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IHRpbWVzID0gW107XHJcblx0XHRcdFx0Y29uc3QgdmFsdWVzID0gW107XHJcblxyXG5cdFx0XHRcdEFuaW1hdGlvblV0aWxzLmZsYXR0ZW5KU09OKCBhbmltYXRpb25LZXlzLCB0aW1lcywgdmFsdWVzLCBwcm9wZXJ0eU5hbWUgKTtcclxuXHJcblx0XHRcdFx0Ly8gZW1wdHkga2V5cyBhcmUgZmlsdGVyZWQgb3V0LCBzbyBjaGVjayBhZ2FpblxyXG5cdFx0XHRcdGlmICggdGltZXMubGVuZ3RoICE9PSAwICkge1xyXG5cclxuXHRcdFx0XHRcdGRlc3RUcmFja3MucHVzaCggbmV3IHRyYWNrVHlwZSggdHJhY2tOYW1lLCB0aW1lcywgdmFsdWVzICkgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH07XHJcblxyXG5cdFx0Y29uc3QgdHJhY2tzID0gW107XHJcblxyXG5cdFx0Y29uc3QgY2xpcE5hbWUgPSBhbmltYXRpb24ubmFtZSB8fCAnZGVmYXVsdCc7XHJcblx0XHRjb25zdCBmcHMgPSBhbmltYXRpb24uZnBzIHx8IDMwO1xyXG5cdFx0Y29uc3QgYmxlbmRNb2RlID0gYW5pbWF0aW9uLmJsZW5kTW9kZTtcclxuXHJcblx0XHQvLyBhdXRvbWF0aWMgbGVuZ3RoIGRldGVybWluYXRpb24gaW4gQW5pbWF0aW9uQ2xpcC5cclxuXHRcdGxldCBkdXJhdGlvbiA9IGFuaW1hdGlvbi5sZW5ndGggfHwgLSAxO1xyXG5cclxuXHRcdGNvbnN0IGhpZXJhcmNoeVRyYWNrcyA9IGFuaW1hdGlvbi5oaWVyYXJjaHkgfHwgW107XHJcblxyXG5cdFx0Zm9yICggbGV0IGggPSAwOyBoIDwgaGllcmFyY2h5VHJhY2tzLmxlbmd0aDsgaCArKyApIHtcclxuXHJcblx0XHRcdGNvbnN0IGFuaW1hdGlvbktleXMgPSBoaWVyYXJjaHlUcmFja3NbIGggXS5rZXlzO1xyXG5cclxuXHRcdFx0Ly8gc2tpcCBlbXB0eSB0cmFja3NcclxuXHRcdFx0aWYgKCAhIGFuaW1hdGlvbktleXMgfHwgYW5pbWF0aW9uS2V5cy5sZW5ndGggPT09IDAgKSBjb250aW51ZTtcclxuXHJcblx0XHRcdC8vIHByb2Nlc3MgbW9ycGggdGFyZ2V0c1xyXG5cdFx0XHRpZiAoIGFuaW1hdGlvbktleXNbIDAgXS5tb3JwaFRhcmdldHMgKSB7XHJcblxyXG5cdFx0XHRcdC8vIGZpZ3VyZSBvdXQgYWxsIG1vcnBoIHRhcmdldHMgdXNlZCBpbiB0aGlzIHRyYWNrXHJcblx0XHRcdFx0Y29uc3QgbW9ycGhUYXJnZXROYW1lcyA9IHt9O1xyXG5cclxuXHRcdFx0XHRsZXQgaztcclxuXHJcblx0XHRcdFx0Zm9yICggayA9IDA7IGsgPCBhbmltYXRpb25LZXlzLmxlbmd0aDsgayArKyApIHtcclxuXHJcblx0XHRcdFx0XHRpZiAoIGFuaW1hdGlvbktleXNbIGsgXS5tb3JwaFRhcmdldHMgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRmb3IgKCBsZXQgbSA9IDA7IG0gPCBhbmltYXRpb25LZXlzWyBrIF0ubW9ycGhUYXJnZXRzLmxlbmd0aDsgbSArKyApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0bW9ycGhUYXJnZXROYW1lc1sgYW5pbWF0aW9uS2V5c1sgayBdLm1vcnBoVGFyZ2V0c1sgbSBdIF0gPSAtIDE7XHJcblxyXG5cdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdC8vIGNyZWF0ZSBhIHRyYWNrIGZvciBlYWNoIG1vcnBoIHRhcmdldCB3aXRoIGFsbCB6ZXJvXHJcblx0XHRcdFx0Ly8gbW9ycGhUYXJnZXRJbmZsdWVuY2VzIGV4Y2VwdCBmb3IgdGhlIGtleXMgaW4gd2hpY2hcclxuXHRcdFx0XHQvLyB0aGUgbW9ycGhUYXJnZXQgaXMgbmFtZWQuXHJcblx0XHRcdFx0Zm9yICggY29uc3QgbW9ycGhUYXJnZXROYW1lIGluIG1vcnBoVGFyZ2V0TmFtZXMgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgdGltZXMgPSBbXTtcclxuXHRcdFx0XHRcdGNvbnN0IHZhbHVlcyA9IFtdO1xyXG5cclxuXHRcdFx0XHRcdGZvciAoIGxldCBtID0gMDsgbSAhPT0gYW5pbWF0aW9uS2V5c1sgayBdLm1vcnBoVGFyZ2V0cy5sZW5ndGg7ICsrIG0gKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRjb25zdCBhbmltYXRpb25LZXkgPSBhbmltYXRpb25LZXlzWyBrIF07XHJcblxyXG5cdFx0XHRcdFx0XHR0aW1lcy5wdXNoKCBhbmltYXRpb25LZXkudGltZSApO1xyXG5cdFx0XHRcdFx0XHR2YWx1ZXMucHVzaCggKCBhbmltYXRpb25LZXkubW9ycGhUYXJnZXQgPT09IG1vcnBoVGFyZ2V0TmFtZSApID8gMSA6IDAgKTtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0dHJhY2tzLnB1c2goIG5ldyBOdW1iZXJLZXlmcmFtZVRyYWNrKCAnLm1vcnBoVGFyZ2V0SW5mbHVlbmNlWycgKyBtb3JwaFRhcmdldE5hbWUgKyAnXScsIHRpbWVzLCB2YWx1ZXMgKSApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdGR1cmF0aW9uID0gbW9ycGhUYXJnZXROYW1lcy5sZW5ndGggKiBmcHM7XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHQvLyAuLi5hc3N1bWUgc2tlbGV0YWwgYW5pbWF0aW9uXHJcblxyXG5cdFx0XHRcdGNvbnN0IGJvbmVOYW1lID0gJy5ib25lc1snICsgYm9uZXNbIGggXS5uYW1lICsgJ10nO1xyXG5cclxuXHRcdFx0XHRhZGROb25lbXB0eVRyYWNrKFxyXG5cdFx0XHRcdFx0VmVjdG9yS2V5ZnJhbWVUcmFjaywgYm9uZU5hbWUgKyAnLnBvc2l0aW9uJyxcclxuXHRcdFx0XHRcdGFuaW1hdGlvbktleXMsICdwb3MnLCB0cmFja3MgKTtcclxuXHJcblx0XHRcdFx0YWRkTm9uZW1wdHlUcmFjayhcclxuXHRcdFx0XHRcdFF1YXRlcm5pb25LZXlmcmFtZVRyYWNrLCBib25lTmFtZSArICcucXVhdGVybmlvbicsXHJcblx0XHRcdFx0XHRhbmltYXRpb25LZXlzLCAncm90JywgdHJhY2tzICk7XHJcblxyXG5cdFx0XHRcdGFkZE5vbmVtcHR5VHJhY2soXHJcblx0XHRcdFx0XHRWZWN0b3JLZXlmcmFtZVRyYWNrLCBib25lTmFtZSArICcuc2NhbGUnLFxyXG5cdFx0XHRcdFx0YW5pbWF0aW9uS2V5cywgJ3NjbCcsIHRyYWNrcyApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHRyYWNrcy5sZW5ndGggPT09IDAgKSB7XHJcblxyXG5cdFx0XHRyZXR1cm4gbnVsbDtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Y29uc3QgY2xpcCA9IG5ldyB0aGlzKCBjbGlwTmFtZSwgZHVyYXRpb24sIHRyYWNrcywgYmxlbmRNb2RlICk7XHJcblxyXG5cdFx0cmV0dXJuIGNsaXA7XHJcblxyXG5cdH1cclxuXHJcblx0cmVzZXREdXJhdGlvbigpIHtcclxuXHJcblx0XHRjb25zdCB0cmFja3MgPSB0aGlzLnRyYWNrcztcclxuXHRcdGxldCBkdXJhdGlvbiA9IDA7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBuID0gdHJhY2tzLmxlbmd0aDsgaSAhPT0gbjsgKysgaSApIHtcclxuXHJcblx0XHRcdGNvbnN0IHRyYWNrID0gdGhpcy50cmFja3NbIGkgXTtcclxuXHJcblx0XHRcdGR1cmF0aW9uID0gTWF0aC5tYXgoIGR1cmF0aW9uLCB0cmFjay50aW1lc1sgdHJhY2sudGltZXMubGVuZ3RoIC0gMSBdICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMuZHVyYXRpb24gPSBkdXJhdGlvbjtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHR0cmltKCkge1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHRoaXMudHJhY2tzLmxlbmd0aDsgaSArKyApIHtcclxuXHJcblx0XHRcdHRoaXMudHJhY2tzWyBpIF0udHJpbSggMCwgdGhpcy5kdXJhdGlvbiApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHR2YWxpZGF0ZSgpIHtcclxuXHJcblx0XHRsZXQgdmFsaWQgPSB0cnVlO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHRoaXMudHJhY2tzLmxlbmd0aDsgaSArKyApIHtcclxuXHJcblx0XHRcdHZhbGlkID0gdmFsaWQgJiYgdGhpcy50cmFja3NbIGkgXS52YWxpZGF0ZSgpO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdmFsaWQ7XHJcblxyXG5cdH1cclxuXHJcblx0b3B0aW1pemUoKSB7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgdGhpcy50cmFja3MubGVuZ3RoOyBpICsrICkge1xyXG5cclxuXHRcdFx0dGhpcy50cmFja3NbIGkgXS5vcHRpbWl6ZSgpO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRjbG9uZSgpIHtcclxuXHJcblx0XHRjb25zdCB0cmFja3MgPSBbXTtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCB0aGlzLnRyYWNrcy5sZW5ndGg7IGkgKysgKSB7XHJcblxyXG5cdFx0XHR0cmFja3MucHVzaCggdGhpcy50cmFja3NbIGkgXS5jbG9uZSgpICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiBuZXcgdGhpcy5jb25zdHJ1Y3RvciggdGhpcy5uYW1lLCB0aGlzLmR1cmF0aW9uLCB0cmFja3MsIHRoaXMuYmxlbmRNb2RlICk7XHJcblxyXG5cdH1cclxuXHJcblx0dG9KU09OKCkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLmNvbnN0cnVjdG9yLnRvSlNPTiggdGhpcyApO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiBnZXRUcmFja1R5cGVGb3JWYWx1ZVR5cGVOYW1lKCB0eXBlTmFtZSApIHtcclxuXHJcblx0c3dpdGNoICggdHlwZU5hbWUudG9Mb3dlckNhc2UoKSApIHtcclxuXHJcblx0XHRjYXNlICdzY2FsYXInOlxyXG5cdFx0Y2FzZSAnZG91YmxlJzpcclxuXHRcdGNhc2UgJ2Zsb2F0JzpcclxuXHRcdGNhc2UgJ251bWJlcic6XHJcblx0XHRjYXNlICdpbnRlZ2VyJzpcclxuXHJcblx0XHRcdHJldHVybiBOdW1iZXJLZXlmcmFtZVRyYWNrO1xyXG5cclxuXHRcdGNhc2UgJ3ZlY3Rvcic6XHJcblx0XHRjYXNlICd2ZWN0b3IyJzpcclxuXHRcdGNhc2UgJ3ZlY3RvcjMnOlxyXG5cdFx0Y2FzZSAndmVjdG9yNCc6XHJcblxyXG5cdFx0XHRyZXR1cm4gVmVjdG9yS2V5ZnJhbWVUcmFjaztcclxuXHJcblx0XHRjYXNlICdjb2xvcic6XHJcblxyXG5cdFx0XHRyZXR1cm4gQ29sb3JLZXlmcmFtZVRyYWNrO1xyXG5cclxuXHRcdGNhc2UgJ3F1YXRlcm5pb24nOlxyXG5cclxuXHRcdFx0cmV0dXJuIFF1YXRlcm5pb25LZXlmcmFtZVRyYWNrO1xyXG5cclxuXHRcdGNhc2UgJ2Jvb2wnOlxyXG5cdFx0Y2FzZSAnYm9vbGVhbic6XHJcblxyXG5cdFx0XHRyZXR1cm4gQm9vbGVhbktleWZyYW1lVHJhY2s7XHJcblxyXG5cdFx0Y2FzZSAnc3RyaW5nJzpcclxuXHJcblx0XHRcdHJldHVybiBTdHJpbmdLZXlmcmFtZVRyYWNrO1xyXG5cclxuXHR9XHJcblxyXG5cdHRocm93IG5ldyBFcnJvciggJ1RIUkVFLktleWZyYW1lVHJhY2s6IFVuc3VwcG9ydGVkIHR5cGVOYW1lOiAnICsgdHlwZU5hbWUgKTtcclxuXHJcbn1cclxuXHJcbmZ1bmN0aW9uIHBhcnNlS2V5ZnJhbWVUcmFjaygganNvbiApIHtcclxuXHJcblx0aWYgKCBqc29uLnR5cGUgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHR0aHJvdyBuZXcgRXJyb3IoICdUSFJFRS5LZXlmcmFtZVRyYWNrOiB0cmFjayB0eXBlIHVuZGVmaW5lZCwgY2FuIG5vdCBwYXJzZScgKTtcclxuXHJcblx0fVxyXG5cclxuXHRjb25zdCB0cmFja1R5cGUgPSBnZXRUcmFja1R5cGVGb3JWYWx1ZVR5cGVOYW1lKCBqc29uLnR5cGUgKTtcclxuXHJcblx0aWYgKCBqc29uLnRpbWVzID09PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0Y29uc3QgdGltZXMgPSBbXSwgdmFsdWVzID0gW107XHJcblxyXG5cdFx0QW5pbWF0aW9uVXRpbHMuZmxhdHRlbkpTT04oIGpzb24ua2V5cywgdGltZXMsIHZhbHVlcywgJ3ZhbHVlJyApO1xyXG5cclxuXHRcdGpzb24udGltZXMgPSB0aW1lcztcclxuXHRcdGpzb24udmFsdWVzID0gdmFsdWVzO1xyXG5cclxuXHR9XHJcblxyXG5cdC8vIGRlcml2ZWQgY2xhc3NlcyBjYW4gZGVmaW5lIGEgc3RhdGljIHBhcnNlIG1ldGhvZFxyXG5cdGlmICggdHJhY2tUeXBlLnBhcnNlICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRyYWNrVHlwZS5wYXJzZSgganNvbiApO1xyXG5cclxuXHR9IGVsc2Uge1xyXG5cclxuXHRcdC8vIGJ5IGRlZmF1bHQsIHdlIGFzc3VtZSBhIGNvbnN0cnVjdG9yIGNvbXBhdGlibGUgd2l0aCB0aGUgYmFzZVxyXG5cdFx0cmV0dXJuIG5ldyB0cmFja1R5cGUoIGpzb24ubmFtZSwganNvbi50aW1lcywganNvbi52YWx1ZXMsIGpzb24uaW50ZXJwb2xhdGlvbiApO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBBbmltYXRpb25DbGlwIH07XHJcbiIsImNvbnN0IENhY2hlID0ge1xyXG5cclxuXHRlbmFibGVkOiBmYWxzZSxcclxuXHJcblx0ZmlsZXM6IHt9LFxyXG5cclxuXHRhZGQ6IGZ1bmN0aW9uICgga2V5LCBmaWxlICkge1xyXG5cclxuXHRcdGlmICggdGhpcy5lbmFibGVkID09PSBmYWxzZSApIHJldHVybjtcclxuXHJcblx0XHQvLyBjb25zb2xlLmxvZyggJ1RIUkVFLkNhY2hlJywgJ0FkZGluZyBrZXk6Jywga2V5ICk7XHJcblxyXG5cdFx0dGhpcy5maWxlc1sga2V5IF0gPSBmaWxlO1xyXG5cclxuXHR9LFxyXG5cclxuXHRnZXQ6IGZ1bmN0aW9uICgga2V5ICkge1xyXG5cclxuXHRcdGlmICggdGhpcy5lbmFibGVkID09PSBmYWxzZSApIHJldHVybjtcclxuXHJcblx0XHQvLyBjb25zb2xlLmxvZyggJ1RIUkVFLkNhY2hlJywgJ0NoZWNraW5nIGtleTonLCBrZXkgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5maWxlc1sga2V5IF07XHJcblxyXG5cdH0sXHJcblxyXG5cdHJlbW92ZTogZnVuY3Rpb24gKCBrZXkgKSB7XHJcblxyXG5cdFx0ZGVsZXRlIHRoaXMuZmlsZXNbIGtleSBdO1xyXG5cclxuXHR9LFxyXG5cclxuXHRjbGVhcjogZnVuY3Rpb24gKCkge1xyXG5cclxuXHRcdHRoaXMuZmlsZXMgPSB7fTtcclxuXHJcblx0fVxyXG5cclxufTtcclxuXHJcblxyXG5leHBvcnQgeyBDYWNoZSB9O1xyXG4iLCJjbGFzcyBMb2FkaW5nTWFuYWdlciB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBvbkxvYWQsIG9uUHJvZ3Jlc3MsIG9uRXJyb3IgKSB7XHJcblxyXG5cdFx0Y29uc3Qgc2NvcGUgPSB0aGlzO1xyXG5cclxuXHRcdGxldCBpc0xvYWRpbmcgPSBmYWxzZTtcclxuXHRcdGxldCBpdGVtc0xvYWRlZCA9IDA7XHJcblx0XHRsZXQgaXRlbXNUb3RhbCA9IDA7XHJcblx0XHRsZXQgdXJsTW9kaWZpZXIgPSB1bmRlZmluZWQ7XHJcblx0XHRjb25zdCBoYW5kbGVycyA9IFtdO1xyXG5cclxuXHRcdC8vIFJlZmVyIHRvICM1Njg5IGZvciB0aGUgcmVhc29uIHdoeSB3ZSBkb24ndCBzZXQgLm9uU3RhcnRcclxuXHRcdC8vIGluIHRoZSBjb25zdHJ1Y3RvclxyXG5cclxuXHRcdHRoaXMub25TdGFydCA9IHVuZGVmaW5lZDtcclxuXHRcdHRoaXMub25Mb2FkID0gb25Mb2FkO1xyXG5cdFx0dGhpcy5vblByb2dyZXNzID0gb25Qcm9ncmVzcztcclxuXHRcdHRoaXMub25FcnJvciA9IG9uRXJyb3I7XHJcblxyXG5cdFx0dGhpcy5pdGVtU3RhcnQgPSBmdW5jdGlvbiAoIHVybCApIHtcclxuXHJcblx0XHRcdGl0ZW1zVG90YWwgKys7XHJcblxyXG5cdFx0XHRpZiAoIGlzTG9hZGluZyA9PT0gZmFsc2UgKSB7XHJcblxyXG5cdFx0XHRcdGlmICggc2NvcGUub25TdGFydCAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHRcdHNjb3BlLm9uU3RhcnQoIHVybCwgaXRlbXNMb2FkZWQsIGl0ZW1zVG90YWwgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0aXNMb2FkaW5nID0gdHJ1ZTtcclxuXHJcblx0XHR9O1xyXG5cclxuXHRcdHRoaXMuaXRlbUVuZCA9IGZ1bmN0aW9uICggdXJsICkge1xyXG5cclxuXHRcdFx0aXRlbXNMb2FkZWQgKys7XHJcblxyXG5cdFx0XHRpZiAoIHNjb3BlLm9uUHJvZ3Jlc3MgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0c2NvcGUub25Qcm9ncmVzcyggdXJsLCBpdGVtc0xvYWRlZCwgaXRlbXNUb3RhbCApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0aWYgKCBpdGVtc0xvYWRlZCA9PT0gaXRlbXNUb3RhbCApIHtcclxuXHJcblx0XHRcdFx0aXNMb2FkaW5nID0gZmFsc2U7XHJcblxyXG5cdFx0XHRcdGlmICggc2NvcGUub25Mb2FkICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRcdFx0c2NvcGUub25Mb2FkKCk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9O1xyXG5cclxuXHRcdHRoaXMuaXRlbUVycm9yID0gZnVuY3Rpb24gKCB1cmwgKSB7XHJcblxyXG5cdFx0XHRpZiAoIHNjb3BlLm9uRXJyb3IgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0c2NvcGUub25FcnJvciggdXJsICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fTtcclxuXHJcblx0XHR0aGlzLnJlc29sdmVVUkwgPSBmdW5jdGlvbiAoIHVybCApIHtcclxuXHJcblx0XHRcdGlmICggdXJsTW9kaWZpZXIgKSB7XHJcblxyXG5cdFx0XHRcdHJldHVybiB1cmxNb2RpZmllciggdXJsICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRyZXR1cm4gdXJsO1xyXG5cclxuXHRcdH07XHJcblxyXG5cdFx0dGhpcy5zZXRVUkxNb2RpZmllciA9IGZ1bmN0aW9uICggdHJhbnNmb3JtICkge1xyXG5cclxuXHRcdFx0dXJsTW9kaWZpZXIgPSB0cmFuc2Zvcm07XHJcblxyXG5cdFx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0XHR9O1xyXG5cclxuXHRcdHRoaXMuYWRkSGFuZGxlciA9IGZ1bmN0aW9uICggcmVnZXgsIGxvYWRlciApIHtcclxuXHJcblx0XHRcdGhhbmRsZXJzLnB1c2goIHJlZ2V4LCBsb2FkZXIgKTtcclxuXHJcblx0XHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHRcdH07XHJcblxyXG5cdFx0dGhpcy5yZW1vdmVIYW5kbGVyID0gZnVuY3Rpb24gKCByZWdleCApIHtcclxuXHJcblx0XHRcdGNvbnN0IGluZGV4ID0gaGFuZGxlcnMuaW5kZXhPZiggcmVnZXggKTtcclxuXHJcblx0XHRcdGlmICggaW5kZXggIT09IC0gMSApIHtcclxuXHJcblx0XHRcdFx0aGFuZGxlcnMuc3BsaWNlKCBpbmRleCwgMiApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdFx0fTtcclxuXHJcblx0XHR0aGlzLmdldEhhbmRsZXIgPSBmdW5jdGlvbiAoIGZpbGUgKSB7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBoYW5kbGVycy5sZW5ndGg7IGkgPCBsOyBpICs9IDIgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IHJlZ2V4ID0gaGFuZGxlcnNbIGkgXTtcclxuXHRcdFx0XHRjb25zdCBsb2FkZXIgPSBoYW5kbGVyc1sgaSArIDEgXTtcclxuXHJcblx0XHRcdFx0aWYgKCByZWdleC5nbG9iYWwgKSByZWdleC5sYXN0SW5kZXggPSAwOyAvLyBzZWUgIzE3OTIwXHJcblxyXG5cdFx0XHRcdGlmICggcmVnZXgudGVzdCggZmlsZSApICkge1xyXG5cclxuXHRcdFx0XHRcdHJldHVybiBsb2FkZXI7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHJldHVybiBudWxsO1xyXG5cclxuXHRcdH07XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmNvbnN0IERlZmF1bHRMb2FkaW5nTWFuYWdlciA9IC8qQF9fUFVSRV9fKi8gbmV3IExvYWRpbmdNYW5hZ2VyKCk7XHJcblxyXG5leHBvcnQgeyBEZWZhdWx0TG9hZGluZ01hbmFnZXIsIExvYWRpbmdNYW5hZ2VyIH07XHJcbiIsImltcG9ydCB7IERlZmF1bHRMb2FkaW5nTWFuYWdlciB9IGZyb20gJy4vTG9hZGluZ01hbmFnZXIuanMnO1xyXG5cclxuY2xhc3MgTG9hZGVyIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIG1hbmFnZXIgKSB7XHJcblxyXG5cdFx0dGhpcy5tYW5hZ2VyID0gKCBtYW5hZ2VyICE9PSB1bmRlZmluZWQgKSA/IG1hbmFnZXIgOiBEZWZhdWx0TG9hZGluZ01hbmFnZXI7XHJcblxyXG5cdFx0dGhpcy5jcm9zc09yaWdpbiA9ICdhbm9ueW1vdXMnO1xyXG5cdFx0dGhpcy53aXRoQ3JlZGVudGlhbHMgPSBmYWxzZTtcclxuXHRcdHRoaXMucGF0aCA9ICcnO1xyXG5cdFx0dGhpcy5yZXNvdXJjZVBhdGggPSAnJztcclxuXHRcdHRoaXMucmVxdWVzdEhlYWRlciA9IHt9O1xyXG5cclxuXHR9XHJcblxyXG5cdGxvYWQoIC8qIHVybCwgb25Mb2FkLCBvblByb2dyZXNzLCBvbkVycm9yICovICkge31cclxuXHJcblx0bG9hZEFzeW5jKCB1cmwsIG9uUHJvZ3Jlc3MgKSB7XHJcblxyXG5cdFx0Y29uc3Qgc2NvcGUgPSB0aGlzO1xyXG5cclxuXHRcdHJldHVybiBuZXcgUHJvbWlzZSggZnVuY3Rpb24gKCByZXNvbHZlLCByZWplY3QgKSB7XHJcblxyXG5cdFx0XHRzY29wZS5sb2FkKCB1cmwsIHJlc29sdmUsIG9uUHJvZ3Jlc3MsIHJlamVjdCApO1xyXG5cclxuXHRcdH0gKTtcclxuXHJcblx0fVxyXG5cclxuXHRwYXJzZSggLyogZGF0YSAqLyApIHt9XHJcblxyXG5cdHNldENyb3NzT3JpZ2luKCBjcm9zc09yaWdpbiApIHtcclxuXHJcblx0XHR0aGlzLmNyb3NzT3JpZ2luID0gY3Jvc3NPcmlnaW47XHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRXaXRoQ3JlZGVudGlhbHMoIHZhbHVlICkge1xyXG5cclxuXHRcdHRoaXMud2l0aENyZWRlbnRpYWxzID0gdmFsdWU7XHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRQYXRoKCBwYXRoICkge1xyXG5cclxuXHRcdHRoaXMucGF0aCA9IHBhdGg7XHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRSZXNvdXJjZVBhdGgoIHJlc291cmNlUGF0aCApIHtcclxuXHJcblx0XHR0aGlzLnJlc291cmNlUGF0aCA9IHJlc291cmNlUGF0aDtcclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldFJlcXVlc3RIZWFkZXIoIHJlcXVlc3RIZWFkZXIgKSB7XHJcblxyXG5cdFx0dGhpcy5yZXF1ZXN0SGVhZGVyID0gcmVxdWVzdEhlYWRlcjtcclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5Mb2FkZXIuREVGQVVMVF9NQVRFUklBTF9OQU1FID0gJ19fREVGQVVMVCc7XHJcblxyXG5leHBvcnQgeyBMb2FkZXIgfTtcclxuIiwiaW1wb3J0IHsgQ2FjaGUgfSBmcm9tICcuL0NhY2hlLmpzJztcclxuaW1wb3J0IHsgTG9hZGVyIH0gZnJvbSAnLi9Mb2FkZXIuanMnO1xyXG5cclxuY29uc3QgbG9hZGluZyA9IHt9O1xyXG5cclxuY2xhc3MgSHR0cEVycm9yIGV4dGVuZHMgRXJyb3Ige1xyXG5cclxuXHRjb25zdHJ1Y3RvciggbWVzc2FnZSwgcmVzcG9uc2UgKSB7XHJcblxyXG5cdFx0c3VwZXIoIG1lc3NhZ2UgKTtcclxuXHRcdHRoaXMucmVzcG9uc2UgPSByZXNwb25zZTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuY2xhc3MgRmlsZUxvYWRlciBleHRlbmRzIExvYWRlciB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBtYW5hZ2VyICkge1xyXG5cclxuXHRcdHN1cGVyKCBtYW5hZ2VyICk7XHJcblxyXG5cdH1cclxuXHJcblx0bG9hZCggdXJsLCBvbkxvYWQsIG9uUHJvZ3Jlc3MsIG9uRXJyb3IgKSB7XHJcblxyXG5cdFx0aWYgKCB1cmwgPT09IHVuZGVmaW5lZCApIHVybCA9ICcnO1xyXG5cclxuXHRcdGlmICggdGhpcy5wYXRoICE9PSB1bmRlZmluZWQgKSB1cmwgPSB0aGlzLnBhdGggKyB1cmw7XHJcblxyXG5cdFx0dXJsID0gdGhpcy5tYW5hZ2VyLnJlc29sdmVVUkwoIHVybCApO1xyXG5cclxuXHRcdGNvbnN0IGNhY2hlZCA9IENhY2hlLmdldCggdXJsICk7XHJcblxyXG5cdFx0aWYgKCBjYWNoZWQgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdHRoaXMubWFuYWdlci5pdGVtU3RhcnQoIHVybCApO1xyXG5cclxuXHRcdFx0c2V0VGltZW91dCggKCkgPT4ge1xyXG5cclxuXHRcdFx0XHRpZiAoIG9uTG9hZCApIG9uTG9hZCggY2FjaGVkICk7XHJcblxyXG5cdFx0XHRcdHRoaXMubWFuYWdlci5pdGVtRW5kKCB1cmwgKTtcclxuXHJcblx0XHRcdH0sIDAgKTtcclxuXHJcblx0XHRcdHJldHVybiBjYWNoZWQ7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIENoZWNrIGlmIHJlcXVlc3QgaXMgZHVwbGljYXRlXHJcblxyXG5cdFx0aWYgKCBsb2FkaW5nWyB1cmwgXSAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0bG9hZGluZ1sgdXJsIF0ucHVzaCgge1xyXG5cclxuXHRcdFx0XHRvbkxvYWQ6IG9uTG9hZCxcclxuXHRcdFx0XHRvblByb2dyZXNzOiBvblByb2dyZXNzLFxyXG5cdFx0XHRcdG9uRXJyb3I6IG9uRXJyb3JcclxuXHJcblx0XHRcdH0gKTtcclxuXHJcblx0XHRcdHJldHVybjtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gSW5pdGlhbGlzZSBhcnJheSBmb3IgZHVwbGljYXRlIHJlcXVlc3RzXHJcblx0XHRsb2FkaW5nWyB1cmwgXSA9IFtdO1xyXG5cclxuXHRcdGxvYWRpbmdbIHVybCBdLnB1c2goIHtcclxuXHRcdFx0b25Mb2FkOiBvbkxvYWQsXHJcblx0XHRcdG9uUHJvZ3Jlc3M6IG9uUHJvZ3Jlc3MsXHJcblx0XHRcdG9uRXJyb3I6IG9uRXJyb3IsXHJcblx0XHR9ICk7XHJcblxyXG5cdFx0Ly8gY3JlYXRlIHJlcXVlc3RcclxuXHRcdGNvbnN0IHJlcSA9IG5ldyBSZXF1ZXN0KCB1cmwsIHtcclxuXHRcdFx0aGVhZGVyczogbmV3IEhlYWRlcnMoIHRoaXMucmVxdWVzdEhlYWRlciApLFxyXG5cdFx0XHRjcmVkZW50aWFsczogdGhpcy53aXRoQ3JlZGVudGlhbHMgPyAnaW5jbHVkZScgOiAnc2FtZS1vcmlnaW4nLFxyXG5cdFx0XHQvLyBBbiBhYm9ydCBjb250cm9sbGVyIGNvdWxkIGJlIGFkZGVkIHdpdGhpbiBhIGZ1dHVyZSBQUlxyXG5cdFx0fSApO1xyXG5cclxuXHRcdC8vIHJlY29yZCBzdGF0ZXMgKCBhdm9pZCBkYXRhIHJhY2UgKVxyXG5cdFx0Y29uc3QgbWltZVR5cGUgPSB0aGlzLm1pbWVUeXBlO1xyXG5cdFx0Y29uc3QgcmVzcG9uc2VUeXBlID0gdGhpcy5yZXNwb25zZVR5cGU7XHJcblxyXG5cdFx0Ly8gc3RhcnQgdGhlIGZldGNoXHJcblx0XHRmZXRjaCggcmVxIClcclxuXHRcdFx0LnRoZW4oIHJlc3BvbnNlID0+IHtcclxuXHJcblx0XHRcdFx0aWYgKCByZXNwb25zZS5zdGF0dXMgPT09IDIwMCB8fCByZXNwb25zZS5zdGF0dXMgPT09IDAgKSB7XHJcblxyXG5cdFx0XHRcdFx0Ly8gU29tZSBicm93c2VycyByZXR1cm4gSFRUUCBTdGF0dXMgMCB3aGVuIHVzaW5nIG5vbi1odHRwIHByb3RvY29sXHJcblx0XHRcdFx0XHQvLyBlLmcuICdmaWxlOi8vJyBvciAnZGF0YTovLycuIEhhbmRsZSBhcyBzdWNjZXNzLlxyXG5cclxuXHRcdFx0XHRcdGlmICggcmVzcG9uc2Uuc3RhdHVzID09PSAwICkge1xyXG5cclxuXHRcdFx0XHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuRmlsZUxvYWRlcjogSFRUUCBTdGF0dXMgMCByZWNlaXZlZC4nICk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdC8vIFdvcmthcm91bmQ6IENoZWNraW5nIGlmIHJlc3BvbnNlLmJvZHkgPT09IHVuZGVmaW5lZCBmb3IgQWxpcGF5IGJyb3dzZXIgIzIzNTQ4XHJcblxyXG5cdFx0XHRcdFx0aWYgKCB0eXBlb2YgUmVhZGFibGVTdHJlYW0gPT09ICd1bmRlZmluZWQnIHx8IHJlc3BvbnNlLmJvZHkgPT09IHVuZGVmaW5lZCB8fCByZXNwb25zZS5ib2R5LmdldFJlYWRlciA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHRcdFx0cmV0dXJuIHJlc3BvbnNlO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRjb25zdCBjYWxsYmFja3MgPSBsb2FkaW5nWyB1cmwgXTtcclxuXHRcdFx0XHRcdGNvbnN0IHJlYWRlciA9IHJlc3BvbnNlLmJvZHkuZ2V0UmVhZGVyKCk7XHJcblxyXG5cdFx0XHRcdFx0Ly8gTmdpbnggbmVlZHMgWC1GaWxlLVNpemUgY2hlY2tcclxuXHRcdFx0XHRcdC8vIGh0dHBzOi8vc2VydmVyZmF1bHQuY29tL3F1ZXN0aW9ucy80ODI4NzUvd2h5LWRvZXMtbmdpbngtcmVtb3ZlLWNvbnRlbnQtbGVuZ3RoLWhlYWRlci1mb3ItY2h1bmtlZC1jb250ZW50XHJcblx0XHRcdFx0XHRjb25zdCBjb250ZW50TGVuZ3RoID0gcmVzcG9uc2UuaGVhZGVycy5nZXQoICdDb250ZW50LUxlbmd0aCcgKSB8fCByZXNwb25zZS5oZWFkZXJzLmdldCggJ1gtRmlsZS1TaXplJyApO1xyXG5cdFx0XHRcdFx0Y29uc3QgdG90YWwgPSBjb250ZW50TGVuZ3RoID8gcGFyc2VJbnQoIGNvbnRlbnRMZW5ndGggKSA6IDA7XHJcblx0XHRcdFx0XHRjb25zdCBsZW5ndGhDb21wdXRhYmxlID0gdG90YWwgIT09IDA7XHJcblx0XHRcdFx0XHRsZXQgbG9hZGVkID0gMDtcclxuXHJcblx0XHRcdFx0XHQvLyBwZXJpb2RpY2FsbHkgcmVhZCBkYXRhIGludG8gdGhlIG5ldyBzdHJlYW0gdHJhY2tpbmcgd2hpbGUgZG93bmxvYWQgcHJvZ3Jlc3NcclxuXHRcdFx0XHRcdGNvbnN0IHN0cmVhbSA9IG5ldyBSZWFkYWJsZVN0cmVhbSgge1xyXG5cdFx0XHRcdFx0XHRzdGFydCggY29udHJvbGxlciApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0cmVhZERhdGEoKTtcclxuXHJcblx0XHRcdFx0XHRcdFx0ZnVuY3Rpb24gcmVhZERhdGEoKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0cmVhZGVyLnJlYWQoKS50aGVuKCAoIHsgZG9uZSwgdmFsdWUgfSApID0+IHtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHRcdGlmICggZG9uZSApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0Y29udHJvbGxlci5jbG9zZSgpO1xyXG5cclxuXHRcdFx0XHRcdFx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0bG9hZGVkICs9IHZhbHVlLmJ5dGVMZW5ndGg7XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdGNvbnN0IGV2ZW50ID0gbmV3IFByb2dyZXNzRXZlbnQoICdwcm9ncmVzcycsIHsgbGVuZ3RoQ29tcHV0YWJsZSwgbG9hZGVkLCB0b3RhbCB9ICk7XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0Zm9yICggbGV0IGkgPSAwLCBpbCA9IGNhbGxiYWNrcy5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRjb25zdCBjYWxsYmFjayA9IGNhbGxiYWNrc1sgaSBdO1xyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0aWYgKCBjYWxsYmFjay5vblByb2dyZXNzICkgY2FsbGJhY2sub25Qcm9ncmVzcyggZXZlbnQgKTtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRjb250cm9sbGVyLmVucXVldWUoIHZhbHVlICk7XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0cmVhZERhdGEoKTtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRcdFx0XHR9ICk7XHJcblxyXG5cdFx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHR9ICk7XHJcblxyXG5cdFx0XHRcdFx0cmV0dXJuIG5ldyBSZXNwb25zZSggc3RyZWFtICk7XHJcblxyXG5cdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0dGhyb3cgbmV3IEh0dHBFcnJvciggYGZldGNoIGZvciBcIiR7cmVzcG9uc2UudXJsfVwiIHJlc3BvbmRlZCB3aXRoICR7cmVzcG9uc2Uuc3RhdHVzfTogJHtyZXNwb25zZS5zdGF0dXNUZXh0fWAsIHJlc3BvbnNlICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH0gKVxyXG5cdFx0XHQudGhlbiggcmVzcG9uc2UgPT4ge1xyXG5cclxuXHRcdFx0XHRzd2l0Y2ggKCByZXNwb25zZVR5cGUgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y2FzZSAnYXJyYXlidWZmZXInOlxyXG5cclxuXHRcdFx0XHRcdFx0cmV0dXJuIHJlc3BvbnNlLmFycmF5QnVmZmVyKCk7XHJcblxyXG5cdFx0XHRcdFx0Y2FzZSAnYmxvYic6XHJcblxyXG5cdFx0XHRcdFx0XHRyZXR1cm4gcmVzcG9uc2UuYmxvYigpO1xyXG5cclxuXHRcdFx0XHRcdGNhc2UgJ2RvY3VtZW50JzpcclxuXHJcblx0XHRcdFx0XHRcdHJldHVybiByZXNwb25zZS50ZXh0KClcclxuXHRcdFx0XHRcdFx0XHQudGhlbiggdGV4dCA9PiB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0Y29uc3QgcGFyc2VyID0gbmV3IERPTVBhcnNlcigpO1xyXG5cdFx0XHRcdFx0XHRcdFx0cmV0dXJuIHBhcnNlci5wYXJzZUZyb21TdHJpbmcoIHRleHQsIG1pbWVUeXBlICk7XHJcblxyXG5cdFx0XHRcdFx0XHRcdH0gKTtcclxuXHJcblx0XHRcdFx0XHRjYXNlICdqc29uJzpcclxuXHJcblx0XHRcdFx0XHRcdHJldHVybiByZXNwb25zZS5qc29uKCk7XHJcblxyXG5cdFx0XHRcdFx0ZGVmYXVsdDpcclxuXHJcblx0XHRcdFx0XHRcdGlmICggbWltZVR5cGUgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0cmV0dXJuIHJlc3BvbnNlLnRleHQoKTtcclxuXHJcblx0XHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdC8vIHNuaWZmIGVuY29kaW5nXHJcblx0XHRcdFx0XHRcdFx0Y29uc3QgcmUgPSAvY2hhcnNldD1cIj8oW147XCJcXHNdKilcIj8vaTtcclxuXHRcdFx0XHRcdFx0XHRjb25zdCBleGVjID0gcmUuZXhlYyggbWltZVR5cGUgKTtcclxuXHRcdFx0XHRcdFx0XHRjb25zdCBsYWJlbCA9IGV4ZWMgJiYgZXhlY1sgMSBdID8gZXhlY1sgMSBdLnRvTG93ZXJDYXNlKCkgOiB1bmRlZmluZWQ7XHJcblx0XHRcdFx0XHRcdFx0Y29uc3QgZGVjb2RlciA9IG5ldyBUZXh0RGVjb2RlciggbGFiZWwgKTtcclxuXHRcdFx0XHRcdFx0XHRyZXR1cm4gcmVzcG9uc2UuYXJyYXlCdWZmZXIoKS50aGVuKCBhYiA9PiBkZWNvZGVyLmRlY29kZSggYWIgKSApO1xyXG5cclxuXHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9IClcclxuXHRcdFx0LnRoZW4oIGRhdGEgPT4ge1xyXG5cclxuXHRcdFx0XHQvLyBBZGQgdG8gY2FjaGUgb25seSBvbiBIVFRQIHN1Y2Nlc3MsIHNvIHRoYXQgd2UgZG8gbm90IGNhY2hlXHJcblx0XHRcdFx0Ly8gZXJyb3IgcmVzcG9uc2UgYm9kaWVzIGFzIHByb3BlciByZXNwb25zZXMgdG8gcmVxdWVzdHMuXHJcblx0XHRcdFx0Q2FjaGUuYWRkKCB1cmwsIGRhdGEgKTtcclxuXHJcblx0XHRcdFx0Y29uc3QgY2FsbGJhY2tzID0gbG9hZGluZ1sgdXJsIF07XHJcblx0XHRcdFx0ZGVsZXRlIGxvYWRpbmdbIHVybCBdO1xyXG5cclxuXHRcdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gY2FsbGJhY2tzLmxlbmd0aDsgaSA8IGlsOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRcdGNvbnN0IGNhbGxiYWNrID0gY2FsbGJhY2tzWyBpIF07XHJcblx0XHRcdFx0XHRpZiAoIGNhbGxiYWNrLm9uTG9hZCApIGNhbGxiYWNrLm9uTG9hZCggZGF0YSApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9IClcclxuXHRcdFx0LmNhdGNoKCBlcnIgPT4ge1xyXG5cclxuXHRcdFx0XHQvLyBBYm9ydCBlcnJvcnMgYW5kIG90aGVyIGVycm9ycyBhcmUgaGFuZGxlZCB0aGUgc2FtZVxyXG5cclxuXHRcdFx0XHRjb25zdCBjYWxsYmFja3MgPSBsb2FkaW5nWyB1cmwgXTtcclxuXHJcblx0XHRcdFx0aWYgKCBjYWxsYmFja3MgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0XHQvLyBXaGVuIG9uTG9hZCB3YXMgY2FsbGVkIGFuZCB1cmwgd2FzIGRlbGV0ZWQgaW4gYGxvYWRpbmdgXHJcblx0XHRcdFx0XHR0aGlzLm1hbmFnZXIuaXRlbUVycm9yKCB1cmwgKTtcclxuXHRcdFx0XHRcdHRocm93IGVycjtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRkZWxldGUgbG9hZGluZ1sgdXJsIF07XHJcblxyXG5cdFx0XHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSBjYWxsYmFja3MubGVuZ3RoOyBpIDwgaWw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgY2FsbGJhY2sgPSBjYWxsYmFja3NbIGkgXTtcclxuXHRcdFx0XHRcdGlmICggY2FsbGJhY2sub25FcnJvciApIGNhbGxiYWNrLm9uRXJyb3IoIGVyciApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdHRoaXMubWFuYWdlci5pdGVtRXJyb3IoIHVybCApO1xyXG5cclxuXHRcdFx0fSApXHJcblx0XHRcdC5maW5hbGx5KCAoKSA9PiB7XHJcblxyXG5cdFx0XHRcdHRoaXMubWFuYWdlci5pdGVtRW5kKCB1cmwgKTtcclxuXHJcblx0XHRcdH0gKTtcclxuXHJcblx0XHR0aGlzLm1hbmFnZXIuaXRlbVN0YXJ0KCB1cmwgKTtcclxuXHJcblx0fVxyXG5cclxuXHRzZXRSZXNwb25zZVR5cGUoIHZhbHVlICkge1xyXG5cclxuXHRcdHRoaXMucmVzcG9uc2VUeXBlID0gdmFsdWU7XHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRNaW1lVHlwZSggdmFsdWUgKSB7XHJcblxyXG5cdFx0dGhpcy5taW1lVHlwZSA9IHZhbHVlO1xyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcblxyXG5leHBvcnQgeyBGaWxlTG9hZGVyIH07XHJcbiIsImltcG9ydCB7IEFuaW1hdGlvbkNsaXAgfSBmcm9tICcuLi9hbmltYXRpb24vQW5pbWF0aW9uQ2xpcC5qcyc7XHJcbmltcG9ydCB7IEZpbGVMb2FkZXIgfSBmcm9tICcuL0ZpbGVMb2FkZXIuanMnO1xyXG5pbXBvcnQgeyBMb2FkZXIgfSBmcm9tICcuL0xvYWRlci5qcyc7XHJcblxyXG5jbGFzcyBBbmltYXRpb25Mb2FkZXIgZXh0ZW5kcyBMb2FkZXIge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggbWFuYWdlciApIHtcclxuXHJcblx0XHRzdXBlciggbWFuYWdlciApO1xyXG5cclxuXHR9XHJcblxyXG5cdGxvYWQoIHVybCwgb25Mb2FkLCBvblByb2dyZXNzLCBvbkVycm9yICkge1xyXG5cclxuXHRcdGNvbnN0IHNjb3BlID0gdGhpcztcclxuXHJcblx0XHRjb25zdCBsb2FkZXIgPSBuZXcgRmlsZUxvYWRlciggdGhpcy5tYW5hZ2VyICk7XHJcblx0XHRsb2FkZXIuc2V0UGF0aCggdGhpcy5wYXRoICk7XHJcblx0XHRsb2FkZXIuc2V0UmVxdWVzdEhlYWRlciggdGhpcy5yZXF1ZXN0SGVhZGVyICk7XHJcblx0XHRsb2FkZXIuc2V0V2l0aENyZWRlbnRpYWxzKCB0aGlzLndpdGhDcmVkZW50aWFscyApO1xyXG5cdFx0bG9hZGVyLmxvYWQoIHVybCwgZnVuY3Rpb24gKCB0ZXh0ICkge1xyXG5cclxuXHRcdFx0dHJ5IHtcclxuXHJcblx0XHRcdFx0b25Mb2FkKCBzY29wZS5wYXJzZSggSlNPTi5wYXJzZSggdGV4dCApICkgKTtcclxuXHJcblx0XHRcdH0gY2F0Y2ggKCBlICkge1xyXG5cclxuXHRcdFx0XHRpZiAoIG9uRXJyb3IgKSB7XHJcblxyXG5cdFx0XHRcdFx0b25FcnJvciggZSApO1xyXG5cclxuXHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdGNvbnNvbGUuZXJyb3IoIGUgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRzY29wZS5tYW5hZ2VyLml0ZW1FcnJvciggdXJsICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fSwgb25Qcm9ncmVzcywgb25FcnJvciApO1xyXG5cclxuXHR9XHJcblxyXG5cdHBhcnNlKCBqc29uICkge1xyXG5cclxuXHRcdGNvbnN0IGFuaW1hdGlvbnMgPSBbXTtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBqc29uLmxlbmd0aDsgaSArKyApIHtcclxuXHJcblx0XHRcdGNvbnN0IGNsaXAgPSBBbmltYXRpb25DbGlwLnBhcnNlKCBqc29uWyBpIF0gKTtcclxuXHJcblx0XHRcdGFuaW1hdGlvbnMucHVzaCggY2xpcCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gYW5pbWF0aW9ucztcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuXHJcbmV4cG9ydCB7IEFuaW1hdGlvbkxvYWRlciB9O1xyXG4iLCJpbXBvcnQgeyBMaW5lYXJGaWx0ZXIgfSBmcm9tICcuLi9jb25zdGFudHMuanMnO1xyXG5pbXBvcnQgeyBGaWxlTG9hZGVyIH0gZnJvbSAnLi9GaWxlTG9hZGVyLmpzJztcclxuaW1wb3J0IHsgQ29tcHJlc3NlZFRleHR1cmUgfSBmcm9tICcuLi90ZXh0dXJlcy9Db21wcmVzc2VkVGV4dHVyZS5qcyc7XHJcbmltcG9ydCB7IExvYWRlciB9IGZyb20gJy4vTG9hZGVyLmpzJztcclxuXHJcbi8qKlxyXG4gKiBBYnN0cmFjdCBCYXNlIGNsYXNzIHRvIGJsb2NrIGJhc2VkIHRleHR1cmVzIGxvYWRlciAoZGRzLCBwdnIsIC4uLilcclxuICpcclxuICogU3ViIGNsYXNzZXMgaGF2ZSB0byBpbXBsZW1lbnQgdGhlIHBhcnNlKCkgbWV0aG9kIHdoaWNoIHdpbGwgYmUgdXNlZCBpbiBsb2FkKCkuXHJcbiAqL1xyXG5cclxuY2xhc3MgQ29tcHJlc3NlZFRleHR1cmVMb2FkZXIgZXh0ZW5kcyBMb2FkZXIge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggbWFuYWdlciApIHtcclxuXHJcblx0XHRzdXBlciggbWFuYWdlciApO1xyXG5cclxuXHR9XHJcblxyXG5cdGxvYWQoIHVybCwgb25Mb2FkLCBvblByb2dyZXNzLCBvbkVycm9yICkge1xyXG5cclxuXHRcdGNvbnN0IHNjb3BlID0gdGhpcztcclxuXHJcblx0XHRjb25zdCBpbWFnZXMgPSBbXTtcclxuXHJcblx0XHRjb25zdCB0ZXh0dXJlID0gbmV3IENvbXByZXNzZWRUZXh0dXJlKCk7XHJcblxyXG5cdFx0Y29uc3QgbG9hZGVyID0gbmV3IEZpbGVMb2FkZXIoIHRoaXMubWFuYWdlciApO1xyXG5cdFx0bG9hZGVyLnNldFBhdGgoIHRoaXMucGF0aCApO1xyXG5cdFx0bG9hZGVyLnNldFJlc3BvbnNlVHlwZSggJ2FycmF5YnVmZmVyJyApO1xyXG5cdFx0bG9hZGVyLnNldFJlcXVlc3RIZWFkZXIoIHRoaXMucmVxdWVzdEhlYWRlciApO1xyXG5cdFx0bG9hZGVyLnNldFdpdGhDcmVkZW50aWFscyggc2NvcGUud2l0aENyZWRlbnRpYWxzICk7XHJcblxyXG5cdFx0bGV0IGxvYWRlZCA9IDA7XHJcblxyXG5cdFx0ZnVuY3Rpb24gbG9hZFRleHR1cmUoIGkgKSB7XHJcblxyXG5cdFx0XHRsb2FkZXIubG9hZCggdXJsWyBpIF0sIGZ1bmN0aW9uICggYnVmZmVyICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCB0ZXhEYXRhcyA9IHNjb3BlLnBhcnNlKCBidWZmZXIsIHRydWUgKTtcclxuXHJcblx0XHRcdFx0aW1hZ2VzWyBpIF0gPSB7XHJcblx0XHRcdFx0XHR3aWR0aDogdGV4RGF0YXMud2lkdGgsXHJcblx0XHRcdFx0XHRoZWlnaHQ6IHRleERhdGFzLmhlaWdodCxcclxuXHRcdFx0XHRcdGZvcm1hdDogdGV4RGF0YXMuZm9ybWF0LFxyXG5cdFx0XHRcdFx0bWlwbWFwczogdGV4RGF0YXMubWlwbWFwc1xyXG5cdFx0XHRcdH07XHJcblxyXG5cdFx0XHRcdGxvYWRlZCArPSAxO1xyXG5cclxuXHRcdFx0XHRpZiAoIGxvYWRlZCA9PT0gNiApIHtcclxuXHJcblx0XHRcdFx0XHRpZiAoIHRleERhdGFzLm1pcG1hcENvdW50ID09PSAxICkgdGV4dHVyZS5taW5GaWx0ZXIgPSBMaW5lYXJGaWx0ZXI7XHJcblxyXG5cdFx0XHRcdFx0dGV4dHVyZS5pbWFnZSA9IGltYWdlcztcclxuXHRcdFx0XHRcdHRleHR1cmUuZm9ybWF0ID0gdGV4RGF0YXMuZm9ybWF0O1xyXG5cdFx0XHRcdFx0dGV4dHVyZS5uZWVkc1VwZGF0ZSA9IHRydWU7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCBvbkxvYWQgKSBvbkxvYWQoIHRleHR1cmUgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fSwgb25Qcm9ncmVzcywgb25FcnJvciApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIEFycmF5LmlzQXJyYXkoIHVybCApICkge1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGkgPSAwLCBpbCA9IHVybC5sZW5ndGg7IGkgPCBpbDsgKysgaSApIHtcclxuXHJcblx0XHRcdFx0bG9hZFRleHR1cmUoIGkgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0Ly8gY29tcHJlc3NlZCBjdWJlbWFwIHRleHR1cmUgc3RvcmVkIGluIGEgc2luZ2xlIEREUyBmaWxlXHJcblxyXG5cdFx0XHRsb2FkZXIubG9hZCggdXJsLCBmdW5jdGlvbiAoIGJ1ZmZlciApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgdGV4RGF0YXMgPSBzY29wZS5wYXJzZSggYnVmZmVyLCB0cnVlICk7XHJcblxyXG5cdFx0XHRcdGlmICggdGV4RGF0YXMuaXNDdWJlbWFwICkge1xyXG5cclxuXHRcdFx0XHRcdGNvbnN0IGZhY2VzID0gdGV4RGF0YXMubWlwbWFwcy5sZW5ndGggLyB0ZXhEYXRhcy5taXBtYXBDb3VudDtcclxuXHJcblx0XHRcdFx0XHRmb3IgKCBsZXQgZiA9IDA7IGYgPCBmYWNlczsgZiArKyApIHtcclxuXHJcblx0XHRcdFx0XHRcdGltYWdlc1sgZiBdID0geyBtaXBtYXBzOiBbXSB9O1xyXG5cclxuXHRcdFx0XHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgdGV4RGF0YXMubWlwbWFwQ291bnQ7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdGltYWdlc1sgZiBdLm1pcG1hcHMucHVzaCggdGV4RGF0YXMubWlwbWFwc1sgZiAqIHRleERhdGFzLm1pcG1hcENvdW50ICsgaSBdICk7XHJcblx0XHRcdFx0XHRcdFx0aW1hZ2VzWyBmIF0uZm9ybWF0ID0gdGV4RGF0YXMuZm9ybWF0O1xyXG5cdFx0XHRcdFx0XHRcdGltYWdlc1sgZiBdLndpZHRoID0gdGV4RGF0YXMud2lkdGg7XHJcblx0XHRcdFx0XHRcdFx0aW1hZ2VzWyBmIF0uaGVpZ2h0ID0gdGV4RGF0YXMuaGVpZ2h0O1xyXG5cclxuXHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHR0ZXh0dXJlLmltYWdlID0gaW1hZ2VzO1xyXG5cclxuXHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdHRleHR1cmUuaW1hZ2Uud2lkdGggPSB0ZXhEYXRhcy53aWR0aDtcclxuXHRcdFx0XHRcdHRleHR1cmUuaW1hZ2UuaGVpZ2h0ID0gdGV4RGF0YXMuaGVpZ2h0O1xyXG5cdFx0XHRcdFx0dGV4dHVyZS5taXBtYXBzID0gdGV4RGF0YXMubWlwbWFwcztcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRpZiAoIHRleERhdGFzLm1pcG1hcENvdW50ID09PSAxICkge1xyXG5cclxuXHRcdFx0XHRcdHRleHR1cmUubWluRmlsdGVyID0gTGluZWFyRmlsdGVyO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdHRleHR1cmUuZm9ybWF0ID0gdGV4RGF0YXMuZm9ybWF0O1xyXG5cdFx0XHRcdHRleHR1cmUubmVlZHNVcGRhdGUgPSB0cnVlO1xyXG5cclxuXHRcdFx0XHRpZiAoIG9uTG9hZCApIG9uTG9hZCggdGV4dHVyZSApO1xyXG5cclxuXHRcdFx0fSwgb25Qcm9ncmVzcywgb25FcnJvciApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGV4dHVyZTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuXHJcbmV4cG9ydCB7IENvbXByZXNzZWRUZXh0dXJlTG9hZGVyIH07XHJcbiIsImltcG9ydCB7IENhY2hlIH0gZnJvbSAnLi9DYWNoZS5qcyc7XHJcbmltcG9ydCB7IExvYWRlciB9IGZyb20gJy4vTG9hZGVyLmpzJztcclxuaW1wb3J0IHsgY3JlYXRlRWxlbWVudE5TIH0gZnJvbSAnLi4vdXRpbHMuanMnO1xyXG5cclxuY2xhc3MgSW1hZ2VMb2FkZXIgZXh0ZW5kcyBMb2FkZXIge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggbWFuYWdlciApIHtcclxuXHJcblx0XHRzdXBlciggbWFuYWdlciApO1xyXG5cclxuXHR9XHJcblxyXG5cdGxvYWQoIHVybCwgb25Mb2FkLCBvblByb2dyZXNzLCBvbkVycm9yICkge1xyXG5cclxuXHRcdGlmICggdGhpcy5wYXRoICE9PSB1bmRlZmluZWQgKSB1cmwgPSB0aGlzLnBhdGggKyB1cmw7XHJcblxyXG5cdFx0dXJsID0gdGhpcy5tYW5hZ2VyLnJlc29sdmVVUkwoIHVybCApO1xyXG5cclxuXHRcdGNvbnN0IHNjb3BlID0gdGhpcztcclxuXHJcblx0XHRjb25zdCBjYWNoZWQgPSBDYWNoZS5nZXQoIHVybCApO1xyXG5cclxuXHRcdGlmICggY2FjaGVkICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRzY29wZS5tYW5hZ2VyLml0ZW1TdGFydCggdXJsICk7XHJcblxyXG5cdFx0XHRzZXRUaW1lb3V0KCBmdW5jdGlvbiAoKSB7XHJcblxyXG5cdFx0XHRcdGlmICggb25Mb2FkICkgb25Mb2FkKCBjYWNoZWQgKTtcclxuXHJcblx0XHRcdFx0c2NvcGUubWFuYWdlci5pdGVtRW5kKCB1cmwgKTtcclxuXHJcblx0XHRcdH0sIDAgKTtcclxuXHJcblx0XHRcdHJldHVybiBjYWNoZWQ7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGNvbnN0IGltYWdlID0gY3JlYXRlRWxlbWVudE5TKCAnaW1nJyApO1xyXG5cclxuXHRcdGZ1bmN0aW9uIG9uSW1hZ2VMb2FkKCkge1xyXG5cclxuXHRcdFx0cmVtb3ZlRXZlbnRMaXN0ZW5lcnMoKTtcclxuXHJcblx0XHRcdENhY2hlLmFkZCggdXJsLCB0aGlzICk7XHJcblxyXG5cdFx0XHRpZiAoIG9uTG9hZCApIG9uTG9hZCggdGhpcyApO1xyXG5cclxuXHRcdFx0c2NvcGUubWFuYWdlci5pdGVtRW5kKCB1cmwgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0ZnVuY3Rpb24gb25JbWFnZUVycm9yKCBldmVudCApIHtcclxuXHJcblx0XHRcdHJlbW92ZUV2ZW50TGlzdGVuZXJzKCk7XHJcblxyXG5cdFx0XHRpZiAoIG9uRXJyb3IgKSBvbkVycm9yKCBldmVudCApO1xyXG5cclxuXHRcdFx0c2NvcGUubWFuYWdlci5pdGVtRXJyb3IoIHVybCApO1xyXG5cdFx0XHRzY29wZS5tYW5hZ2VyLml0ZW1FbmQoIHVybCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRmdW5jdGlvbiByZW1vdmVFdmVudExpc3RlbmVycygpIHtcclxuXHJcblx0XHRcdGltYWdlLnJlbW92ZUV2ZW50TGlzdGVuZXIoICdsb2FkJywgb25JbWFnZUxvYWQsIGZhbHNlICk7XHJcblx0XHRcdGltYWdlLnJlbW92ZUV2ZW50TGlzdGVuZXIoICdlcnJvcicsIG9uSW1hZ2VFcnJvciwgZmFsc2UgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aW1hZ2UuYWRkRXZlbnRMaXN0ZW5lciggJ2xvYWQnLCBvbkltYWdlTG9hZCwgZmFsc2UgKTtcclxuXHRcdGltYWdlLmFkZEV2ZW50TGlzdGVuZXIoICdlcnJvcicsIG9uSW1hZ2VFcnJvciwgZmFsc2UgKTtcclxuXHJcblx0XHRpZiAoIHVybC5zbGljZSggMCwgNSApICE9PSAnZGF0YTonICkge1xyXG5cclxuXHRcdFx0aWYgKCB0aGlzLmNyb3NzT3JpZ2luICE9PSB1bmRlZmluZWQgKSBpbWFnZS5jcm9zc09yaWdpbiA9IHRoaXMuY3Jvc3NPcmlnaW47XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHNjb3BlLm1hbmFnZXIuaXRlbVN0YXJ0KCB1cmwgKTtcclxuXHJcblx0XHRpbWFnZS5zcmMgPSB1cmw7XHJcblxyXG5cdFx0cmV0dXJuIGltYWdlO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5cclxuZXhwb3J0IHsgSW1hZ2VMb2FkZXIgfTtcclxuIiwiaW1wb3J0IHsgSW1hZ2VMb2FkZXIgfSBmcm9tICcuL0ltYWdlTG9hZGVyLmpzJztcclxuaW1wb3J0IHsgQ3ViZVRleHR1cmUgfSBmcm9tICcuLi90ZXh0dXJlcy9DdWJlVGV4dHVyZS5qcyc7XHJcbmltcG9ydCB7IExvYWRlciB9IGZyb20gJy4vTG9hZGVyLmpzJztcclxuaW1wb3J0IHsgU1JHQkNvbG9yU3BhY2UgfSBmcm9tICcuLi9jb25zdGFudHMuanMnO1xyXG5cclxuY2xhc3MgQ3ViZVRleHR1cmVMb2FkZXIgZXh0ZW5kcyBMb2FkZXIge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggbWFuYWdlciApIHtcclxuXHJcblx0XHRzdXBlciggbWFuYWdlciApO1xyXG5cclxuXHR9XHJcblxyXG5cdGxvYWQoIHVybHMsIG9uTG9hZCwgb25Qcm9ncmVzcywgb25FcnJvciApIHtcclxuXHJcblx0XHRjb25zdCB0ZXh0dXJlID0gbmV3IEN1YmVUZXh0dXJlKCk7XHJcblx0XHR0ZXh0dXJlLmNvbG9yU3BhY2UgPSBTUkdCQ29sb3JTcGFjZTtcclxuXHJcblx0XHRjb25zdCBsb2FkZXIgPSBuZXcgSW1hZ2VMb2FkZXIoIHRoaXMubWFuYWdlciApO1xyXG5cdFx0bG9hZGVyLnNldENyb3NzT3JpZ2luKCB0aGlzLmNyb3NzT3JpZ2luICk7XHJcblx0XHRsb2FkZXIuc2V0UGF0aCggdGhpcy5wYXRoICk7XHJcblxyXG5cdFx0bGV0IGxvYWRlZCA9IDA7XHJcblxyXG5cdFx0ZnVuY3Rpb24gbG9hZFRleHR1cmUoIGkgKSB7XHJcblxyXG5cdFx0XHRsb2FkZXIubG9hZCggdXJsc1sgaSBdLCBmdW5jdGlvbiAoIGltYWdlICkge1xyXG5cclxuXHRcdFx0XHR0ZXh0dXJlLmltYWdlc1sgaSBdID0gaW1hZ2U7XHJcblxyXG5cdFx0XHRcdGxvYWRlZCArKztcclxuXHJcblx0XHRcdFx0aWYgKCBsb2FkZWQgPT09IDYgKSB7XHJcblxyXG5cdFx0XHRcdFx0dGV4dHVyZS5uZWVkc1VwZGF0ZSA9IHRydWU7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCBvbkxvYWQgKSBvbkxvYWQoIHRleHR1cmUgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fSwgdW5kZWZpbmVkLCBvbkVycm9yICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHVybHMubGVuZ3RoOyArKyBpICkge1xyXG5cclxuXHRcdFx0bG9hZFRleHR1cmUoIGkgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRleHR1cmU7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcblxyXG5leHBvcnQgeyBDdWJlVGV4dHVyZUxvYWRlciB9O1xyXG4iLCJpbXBvcnQgeyBMaW5lYXJGaWx0ZXIsIExpbmVhck1pcG1hcExpbmVhckZpbHRlciwgQ2xhbXBUb0VkZ2VXcmFwcGluZyB9IGZyb20gJy4uL2NvbnN0YW50cy5qcyc7XHJcbmltcG9ydCB7IEZpbGVMb2FkZXIgfSBmcm9tICcuL0ZpbGVMb2FkZXIuanMnO1xyXG5pbXBvcnQgeyBEYXRhVGV4dHVyZSB9IGZyb20gJy4uL3RleHR1cmVzL0RhdGFUZXh0dXJlLmpzJztcclxuaW1wb3J0IHsgTG9hZGVyIH0gZnJvbSAnLi9Mb2FkZXIuanMnO1xyXG5cclxuLyoqXHJcbiAqIEFic3RyYWN0IEJhc2UgY2xhc3MgdG8gbG9hZCBnZW5lcmljIGJpbmFyeSB0ZXh0dXJlcyBmb3JtYXRzIChyZ2JlLCBoZHIsIC4uLilcclxuICpcclxuICogU3ViIGNsYXNzZXMgaGF2ZSB0byBpbXBsZW1lbnQgdGhlIHBhcnNlKCkgbWV0aG9kIHdoaWNoIHdpbGwgYmUgdXNlZCBpbiBsb2FkKCkuXHJcbiAqL1xyXG5cclxuY2xhc3MgRGF0YVRleHR1cmVMb2FkZXIgZXh0ZW5kcyBMb2FkZXIge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggbWFuYWdlciApIHtcclxuXHJcblx0XHRzdXBlciggbWFuYWdlciApO1xyXG5cclxuXHR9XHJcblxyXG5cdGxvYWQoIHVybCwgb25Mb2FkLCBvblByb2dyZXNzLCBvbkVycm9yICkge1xyXG5cclxuXHRcdGNvbnN0IHNjb3BlID0gdGhpcztcclxuXHJcblx0XHRjb25zdCB0ZXh0dXJlID0gbmV3IERhdGFUZXh0dXJlKCk7XHJcblxyXG5cdFx0Y29uc3QgbG9hZGVyID0gbmV3IEZpbGVMb2FkZXIoIHRoaXMubWFuYWdlciApO1xyXG5cdFx0bG9hZGVyLnNldFJlc3BvbnNlVHlwZSggJ2FycmF5YnVmZmVyJyApO1xyXG5cdFx0bG9hZGVyLnNldFJlcXVlc3RIZWFkZXIoIHRoaXMucmVxdWVzdEhlYWRlciApO1xyXG5cdFx0bG9hZGVyLnNldFBhdGgoIHRoaXMucGF0aCApO1xyXG5cdFx0bG9hZGVyLnNldFdpdGhDcmVkZW50aWFscyggc2NvcGUud2l0aENyZWRlbnRpYWxzICk7XHJcblx0XHRsb2FkZXIubG9hZCggdXJsLCBmdW5jdGlvbiAoIGJ1ZmZlciApIHtcclxuXHJcblx0XHRcdGxldCB0ZXhEYXRhO1xyXG5cclxuXHRcdFx0dHJ5IHtcclxuXHJcblx0XHRcdFx0dGV4RGF0YSA9IHNjb3BlLnBhcnNlKCBidWZmZXIgKTtcclxuXHJcblx0XHRcdH0gY2F0Y2ggKCBlcnJvciApIHtcclxuXHJcblx0XHRcdFx0aWYgKCBvbkVycm9yICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRcdFx0b25FcnJvciggZXJyb3IgKTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRjb25zb2xlLmVycm9yKCBlcnJvciApO1xyXG5cdFx0XHRcdFx0cmV0dXJuO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRpZiAoIHRleERhdGEuaW1hZ2UgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0dGV4dHVyZS5pbWFnZSA9IHRleERhdGEuaW1hZ2U7XHJcblxyXG5cdFx0XHR9IGVsc2UgaWYgKCB0ZXhEYXRhLmRhdGEgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0dGV4dHVyZS5pbWFnZS53aWR0aCA9IHRleERhdGEud2lkdGg7XHJcblx0XHRcdFx0dGV4dHVyZS5pbWFnZS5oZWlnaHQgPSB0ZXhEYXRhLmhlaWdodDtcclxuXHRcdFx0XHR0ZXh0dXJlLmltYWdlLmRhdGEgPSB0ZXhEYXRhLmRhdGE7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHR0ZXh0dXJlLndyYXBTID0gdGV4RGF0YS53cmFwUyAhPT0gdW5kZWZpbmVkID8gdGV4RGF0YS53cmFwUyA6IENsYW1wVG9FZGdlV3JhcHBpbmc7XHJcblx0XHRcdHRleHR1cmUud3JhcFQgPSB0ZXhEYXRhLndyYXBUICE9PSB1bmRlZmluZWQgPyB0ZXhEYXRhLndyYXBUIDogQ2xhbXBUb0VkZ2VXcmFwcGluZztcclxuXHJcblx0XHRcdHRleHR1cmUubWFnRmlsdGVyID0gdGV4RGF0YS5tYWdGaWx0ZXIgIT09IHVuZGVmaW5lZCA/IHRleERhdGEubWFnRmlsdGVyIDogTGluZWFyRmlsdGVyO1xyXG5cdFx0XHR0ZXh0dXJlLm1pbkZpbHRlciA9IHRleERhdGEubWluRmlsdGVyICE9PSB1bmRlZmluZWQgPyB0ZXhEYXRhLm1pbkZpbHRlciA6IExpbmVhckZpbHRlcjtcclxuXHJcblx0XHRcdHRleHR1cmUuYW5pc290cm9weSA9IHRleERhdGEuYW5pc290cm9weSAhPT0gdW5kZWZpbmVkID8gdGV4RGF0YS5hbmlzb3Ryb3B5IDogMTtcclxuXHJcblx0XHRcdGlmICggdGV4RGF0YS5jb2xvclNwYWNlICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRcdHRleHR1cmUuY29sb3JTcGFjZSA9IHRleERhdGEuY29sb3JTcGFjZTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGlmICggdGV4RGF0YS5mbGlwWSAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHR0ZXh0dXJlLmZsaXBZID0gdGV4RGF0YS5mbGlwWTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGlmICggdGV4RGF0YS5mb3JtYXQgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0dGV4dHVyZS5mb3JtYXQgPSB0ZXhEYXRhLmZvcm1hdDtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGlmICggdGV4RGF0YS50eXBlICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRcdHRleHR1cmUudHlwZSA9IHRleERhdGEudHlwZTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGlmICggdGV4RGF0YS5taXBtYXBzICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRcdHRleHR1cmUubWlwbWFwcyA9IHRleERhdGEubWlwbWFwcztcclxuXHRcdFx0XHR0ZXh0dXJlLm1pbkZpbHRlciA9IExpbmVhck1pcG1hcExpbmVhckZpbHRlcjsgLy8gcHJlc3VtYWJseS4uLlxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0aWYgKCB0ZXhEYXRhLm1pcG1hcENvdW50ID09PSAxICkge1xyXG5cclxuXHRcdFx0XHR0ZXh0dXJlLm1pbkZpbHRlciA9IExpbmVhckZpbHRlcjtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGlmICggdGV4RGF0YS5nZW5lcmF0ZU1pcG1hcHMgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0dGV4dHVyZS5nZW5lcmF0ZU1pcG1hcHMgPSB0ZXhEYXRhLmdlbmVyYXRlTWlwbWFwcztcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHRleHR1cmUubmVlZHNVcGRhdGUgPSB0cnVlO1xyXG5cclxuXHRcdFx0aWYgKCBvbkxvYWQgKSBvbkxvYWQoIHRleHR1cmUsIHRleERhdGEgKTtcclxuXHJcblx0XHR9LCBvblByb2dyZXNzLCBvbkVycm9yICk7XHJcblxyXG5cclxuXHRcdHJldHVybiB0ZXh0dXJlO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5cclxuZXhwb3J0IHsgRGF0YVRleHR1cmVMb2FkZXIgfTtcclxuIiwiaW1wb3J0IHsgSW1hZ2VMb2FkZXIgfSBmcm9tICcuL0ltYWdlTG9hZGVyLmpzJztcclxuaW1wb3J0IHsgVGV4dHVyZSB9IGZyb20gJy4uL3RleHR1cmVzL1RleHR1cmUuanMnO1xyXG5pbXBvcnQgeyBMb2FkZXIgfSBmcm9tICcuL0xvYWRlci5qcyc7XHJcblxyXG5jbGFzcyBUZXh0dXJlTG9hZGVyIGV4dGVuZHMgTG9hZGVyIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIG1hbmFnZXIgKSB7XHJcblxyXG5cdFx0c3VwZXIoIG1hbmFnZXIgKTtcclxuXHJcblx0fVxyXG5cclxuXHRsb2FkKCB1cmwsIG9uTG9hZCwgb25Qcm9ncmVzcywgb25FcnJvciApIHtcclxuXHJcblx0XHRjb25zdCB0ZXh0dXJlID0gbmV3IFRleHR1cmUoKTtcclxuXHJcblx0XHRjb25zdCBsb2FkZXIgPSBuZXcgSW1hZ2VMb2FkZXIoIHRoaXMubWFuYWdlciApO1xyXG5cdFx0bG9hZGVyLnNldENyb3NzT3JpZ2luKCB0aGlzLmNyb3NzT3JpZ2luICk7XHJcblx0XHRsb2FkZXIuc2V0UGF0aCggdGhpcy5wYXRoICk7XHJcblxyXG5cdFx0bG9hZGVyLmxvYWQoIHVybCwgZnVuY3Rpb24gKCBpbWFnZSApIHtcclxuXHJcblx0XHRcdHRleHR1cmUuaW1hZ2UgPSBpbWFnZTtcclxuXHRcdFx0dGV4dHVyZS5uZWVkc1VwZGF0ZSA9IHRydWU7XHJcblxyXG5cdFx0XHRpZiAoIG9uTG9hZCAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHRvbkxvYWQoIHRleHR1cmUgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9LCBvblByb2dyZXNzLCBvbkVycm9yICk7XHJcblxyXG5cdFx0cmV0dXJuIHRleHR1cmU7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcblxyXG5leHBvcnQgeyBUZXh0dXJlTG9hZGVyIH07XHJcbiIsImltcG9ydCB7IE9iamVjdDNEIH0gZnJvbSAnLi4vY29yZS9PYmplY3QzRC5qcyc7XHJcbmltcG9ydCB7IENvbG9yIH0gZnJvbSAnLi4vbWF0aC9Db2xvci5qcyc7XHJcblxyXG5jbGFzcyBMaWdodCBleHRlbmRzIE9iamVjdDNEIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIGNvbG9yLCBpbnRlbnNpdHkgPSAxICkge1xyXG5cclxuXHRcdHN1cGVyKCk7XHJcblxyXG5cdFx0dGhpcy5pc0xpZ2h0ID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSAnTGlnaHQnO1xyXG5cclxuXHRcdHRoaXMuY29sb3IgPSBuZXcgQ29sb3IoIGNvbG9yICk7XHJcblx0XHR0aGlzLmludGVuc2l0eSA9IGludGVuc2l0eTtcclxuXHJcblx0fVxyXG5cclxuXHRkaXNwb3NlKCkge1xyXG5cclxuXHRcdC8vIEVtcHR5IGhlcmUgaW4gYmFzZSBjbGFzczsgc29tZSBzdWJjbGFzc2VzIG92ZXJyaWRlLlxyXG5cclxuXHR9XHJcblxyXG5cdGNvcHkoIHNvdXJjZSwgcmVjdXJzaXZlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSwgcmVjdXJzaXZlICk7XHJcblxyXG5cdFx0dGhpcy5jb2xvci5jb3B5KCBzb3VyY2UuY29sb3IgKTtcclxuXHRcdHRoaXMuaW50ZW5zaXR5ID0gc291cmNlLmludGVuc2l0eTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHR0b0pTT04oIG1ldGEgKSB7XHJcblxyXG5cdFx0Y29uc3QgZGF0YSA9IHN1cGVyLnRvSlNPTiggbWV0YSApO1xyXG5cclxuXHRcdGRhdGEub2JqZWN0LmNvbG9yID0gdGhpcy5jb2xvci5nZXRIZXgoKTtcclxuXHRcdGRhdGEub2JqZWN0LmludGVuc2l0eSA9IHRoaXMuaW50ZW5zaXR5O1xyXG5cclxuXHRcdGlmICggdGhpcy5ncm91bmRDb2xvciAhPT0gdW5kZWZpbmVkICkgZGF0YS5vYmplY3QuZ3JvdW5kQ29sb3IgPSB0aGlzLmdyb3VuZENvbG9yLmdldEhleCgpO1xyXG5cclxuXHRcdGlmICggdGhpcy5kaXN0YW5jZSAhPT0gdW5kZWZpbmVkICkgZGF0YS5vYmplY3QuZGlzdGFuY2UgPSB0aGlzLmRpc3RhbmNlO1xyXG5cdFx0aWYgKCB0aGlzLmFuZ2xlICE9PSB1bmRlZmluZWQgKSBkYXRhLm9iamVjdC5hbmdsZSA9IHRoaXMuYW5nbGU7XHJcblx0XHRpZiAoIHRoaXMuZGVjYXkgIT09IHVuZGVmaW5lZCApIGRhdGEub2JqZWN0LmRlY2F5ID0gdGhpcy5kZWNheTtcclxuXHRcdGlmICggdGhpcy5wZW51bWJyYSAhPT0gdW5kZWZpbmVkICkgZGF0YS5vYmplY3QucGVudW1icmEgPSB0aGlzLnBlbnVtYnJhO1xyXG5cclxuXHRcdGlmICggdGhpcy5zaGFkb3cgIT09IHVuZGVmaW5lZCApIGRhdGEub2JqZWN0LnNoYWRvdyA9IHRoaXMuc2hhZG93LnRvSlNPTigpO1xyXG5cclxuXHRcdHJldHVybiBkYXRhO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBMaWdodCB9O1xyXG4iLCJpbXBvcnQgeyBMaWdodCB9IGZyb20gJy4vTGlnaHQuanMnO1xyXG5pbXBvcnQgeyBDb2xvciB9IGZyb20gJy4uL21hdGgvQ29sb3IuanMnO1xyXG5pbXBvcnQgeyBPYmplY3QzRCB9IGZyb20gJy4uL2NvcmUvT2JqZWN0M0QuanMnO1xyXG5cclxuY2xhc3MgSGVtaXNwaGVyZUxpZ2h0IGV4dGVuZHMgTGlnaHQge1xyXG5cclxuXHRjb25zdHJ1Y3Rvciggc2t5Q29sb3IsIGdyb3VuZENvbG9yLCBpbnRlbnNpdHkgKSB7XHJcblxyXG5cdFx0c3VwZXIoIHNreUNvbG9yLCBpbnRlbnNpdHkgKTtcclxuXHJcblx0XHR0aGlzLmlzSGVtaXNwaGVyZUxpZ2h0ID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSAnSGVtaXNwaGVyZUxpZ2h0JztcclxuXHJcblx0XHR0aGlzLnBvc2l0aW9uLmNvcHkoIE9iamVjdDNELkRFRkFVTFRfVVAgKTtcclxuXHRcdHRoaXMudXBkYXRlTWF0cml4KCk7XHJcblxyXG5cdFx0dGhpcy5ncm91bmRDb2xvciA9IG5ldyBDb2xvciggZ3JvdW5kQ29sb3IgKTtcclxuXHJcblx0fVxyXG5cclxuXHRjb3B5KCBzb3VyY2UsIHJlY3Vyc2l2ZSApIHtcclxuXHJcblx0XHRzdXBlci5jb3B5KCBzb3VyY2UsIHJlY3Vyc2l2ZSApO1xyXG5cclxuXHRcdHRoaXMuZ3JvdW5kQ29sb3IuY29weSggc291cmNlLmdyb3VuZENvbG9yICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IEhlbWlzcGhlcmVMaWdodCB9O1xyXG4iLCJpbXBvcnQgeyBNYXRyaXg0IH0gZnJvbSAnLi4vbWF0aC9NYXRyaXg0LmpzJztcclxuaW1wb3J0IHsgVmVjdG9yMiB9IGZyb20gJy4uL21hdGgvVmVjdG9yMi5qcyc7XHJcbmltcG9ydCB7IFZlY3RvcjMgfSBmcm9tICcuLi9tYXRoL1ZlY3RvcjMuanMnO1xyXG5pbXBvcnQgeyBWZWN0b3I0IH0gZnJvbSAnLi4vbWF0aC9WZWN0b3I0LmpzJztcclxuaW1wb3J0IHsgRnJ1c3R1bSB9IGZyb20gJy4uL21hdGgvRnJ1c3R1bS5qcyc7XHJcblxyXG5jb25zdCBfcHJvalNjcmVlbk1hdHJpeCA9IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDQoKTtcclxuY29uc3QgX2xpZ2h0UG9zaXRpb25Xb3JsZCA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuY29uc3QgX2xvb2tUYXJnZXQgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XHJcblxyXG5jbGFzcyBMaWdodFNoYWRvdyB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBjYW1lcmEgKSB7XHJcblxyXG5cdFx0dGhpcy5jYW1lcmEgPSBjYW1lcmE7XHJcblxyXG5cdFx0dGhpcy5iaWFzID0gMDtcclxuXHRcdHRoaXMubm9ybWFsQmlhcyA9IDA7XHJcblx0XHR0aGlzLnJhZGl1cyA9IDE7XHJcblx0XHR0aGlzLmJsdXJTYW1wbGVzID0gODtcclxuXHJcblx0XHR0aGlzLm1hcFNpemUgPSBuZXcgVmVjdG9yMiggNTEyLCA1MTIgKTtcclxuXHJcblx0XHR0aGlzLm1hcCA9IG51bGw7XHJcblx0XHR0aGlzLm1hcFBhc3MgPSBudWxsO1xyXG5cdFx0dGhpcy5tYXRyaXggPSBuZXcgTWF0cml4NCgpO1xyXG5cclxuXHRcdHRoaXMuYXV0b1VwZGF0ZSA9IHRydWU7XHJcblx0XHR0aGlzLm5lZWRzVXBkYXRlID0gZmFsc2U7XHJcblxyXG5cdFx0dGhpcy5fZnJ1c3R1bSA9IG5ldyBGcnVzdHVtKCk7XHJcblx0XHR0aGlzLl9mcmFtZUV4dGVudHMgPSBuZXcgVmVjdG9yMiggMSwgMSApO1xyXG5cclxuXHRcdHRoaXMuX3ZpZXdwb3J0Q291bnQgPSAxO1xyXG5cclxuXHRcdHRoaXMuX3ZpZXdwb3J0cyA9IFtcclxuXHJcblx0XHRcdG5ldyBWZWN0b3I0KCAwLCAwLCAxLCAxIClcclxuXHJcblx0XHRdO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldFZpZXdwb3J0Q291bnQoKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuX3ZpZXdwb3J0Q291bnQ7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0RnJ1c3R1bSgpIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5fZnJ1c3R1bTtcclxuXHJcblx0fVxyXG5cclxuXHR1cGRhdGVNYXRyaWNlcyggbGlnaHQgKSB7XHJcblxyXG5cdFx0Y29uc3Qgc2hhZG93Q2FtZXJhID0gdGhpcy5jYW1lcmE7XHJcblx0XHRjb25zdCBzaGFkb3dNYXRyaXggPSB0aGlzLm1hdHJpeDtcclxuXHJcblx0XHRfbGlnaHRQb3NpdGlvbldvcmxkLnNldEZyb21NYXRyaXhQb3NpdGlvbiggbGlnaHQubWF0cml4V29ybGQgKTtcclxuXHRcdHNoYWRvd0NhbWVyYS5wb3NpdGlvbi5jb3B5KCBfbGlnaHRQb3NpdGlvbldvcmxkICk7XHJcblxyXG5cdFx0X2xvb2tUYXJnZXQuc2V0RnJvbU1hdHJpeFBvc2l0aW9uKCBsaWdodC50YXJnZXQubWF0cml4V29ybGQgKTtcclxuXHRcdHNoYWRvd0NhbWVyYS5sb29rQXQoIF9sb29rVGFyZ2V0ICk7XHJcblx0XHRzaGFkb3dDYW1lcmEudXBkYXRlTWF0cml4V29ybGQoKTtcclxuXHJcblx0XHRfcHJvalNjcmVlbk1hdHJpeC5tdWx0aXBseU1hdHJpY2VzKCBzaGFkb3dDYW1lcmEucHJvamVjdGlvbk1hdHJpeCwgc2hhZG93Q2FtZXJhLm1hdHJpeFdvcmxkSW52ZXJzZSApO1xyXG5cdFx0dGhpcy5fZnJ1c3R1bS5zZXRGcm9tUHJvamVjdGlvbk1hdHJpeCggX3Byb2pTY3JlZW5NYXRyaXggKTtcclxuXHJcblx0XHRzaGFkb3dNYXRyaXguc2V0KFxyXG5cdFx0XHQwLjUsIDAuMCwgMC4wLCAwLjUsXHJcblx0XHRcdDAuMCwgMC41LCAwLjAsIDAuNSxcclxuXHRcdFx0MC4wLCAwLjAsIDAuNSwgMC41LFxyXG5cdFx0XHQwLjAsIDAuMCwgMC4wLCAxLjBcclxuXHRcdCk7XHJcblxyXG5cdFx0c2hhZG93TWF0cml4Lm11bHRpcGx5KCBfcHJvalNjcmVlbk1hdHJpeCApO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldFZpZXdwb3J0KCB2aWV3cG9ydEluZGV4ICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLl92aWV3cG9ydHNbIHZpZXdwb3J0SW5kZXggXTtcclxuXHJcblx0fVxyXG5cclxuXHRnZXRGcmFtZUV4dGVudHMoKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuX2ZyYW1lRXh0ZW50cztcclxuXHJcblx0fVxyXG5cclxuXHRkaXNwb3NlKCkge1xyXG5cclxuXHRcdGlmICggdGhpcy5tYXAgKSB7XHJcblxyXG5cdFx0XHR0aGlzLm1hcC5kaXNwb3NlKCk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggdGhpcy5tYXBQYXNzICkge1xyXG5cclxuXHRcdFx0dGhpcy5tYXBQYXNzLmRpc3Bvc2UoKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHRoaXMuY2FtZXJhID0gc291cmNlLmNhbWVyYS5jbG9uZSgpO1xyXG5cclxuXHRcdHRoaXMuYmlhcyA9IHNvdXJjZS5iaWFzO1xyXG5cdFx0dGhpcy5yYWRpdXMgPSBzb3VyY2UucmFkaXVzO1xyXG5cclxuXHRcdHRoaXMubWFwU2l6ZS5jb3B5KCBzb3VyY2UubWFwU2l6ZSApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGNsb25lKCkge1xyXG5cclxuXHRcdHJldHVybiBuZXcgdGhpcy5jb25zdHJ1Y3RvcigpLmNvcHkoIHRoaXMgKTtcclxuXHJcblx0fVxyXG5cclxuXHR0b0pTT04oKSB7XHJcblxyXG5cdFx0Y29uc3Qgb2JqZWN0ID0ge307XHJcblxyXG5cdFx0aWYgKCB0aGlzLmJpYXMgIT09IDAgKSBvYmplY3QuYmlhcyA9IHRoaXMuYmlhcztcclxuXHRcdGlmICggdGhpcy5ub3JtYWxCaWFzICE9PSAwICkgb2JqZWN0Lm5vcm1hbEJpYXMgPSB0aGlzLm5vcm1hbEJpYXM7XHJcblx0XHRpZiAoIHRoaXMucmFkaXVzICE9PSAxICkgb2JqZWN0LnJhZGl1cyA9IHRoaXMucmFkaXVzO1xyXG5cdFx0aWYgKCB0aGlzLm1hcFNpemUueCAhPT0gNTEyIHx8IHRoaXMubWFwU2l6ZS55ICE9PSA1MTIgKSBvYmplY3QubWFwU2l6ZSA9IHRoaXMubWFwU2l6ZS50b0FycmF5KCk7XHJcblxyXG5cdFx0b2JqZWN0LmNhbWVyYSA9IHRoaXMuY2FtZXJhLnRvSlNPTiggZmFsc2UgKS5vYmplY3Q7XHJcblx0XHRkZWxldGUgb2JqZWN0LmNhbWVyYS5tYXRyaXg7XHJcblxyXG5cdFx0cmV0dXJuIG9iamVjdDtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgTGlnaHRTaGFkb3cgfTtcclxuIiwiaW1wb3J0IHsgTGlnaHRTaGFkb3cgfSBmcm9tICcuL0xpZ2h0U2hhZG93LmpzJztcclxuaW1wb3J0ICogYXMgTWF0aFV0aWxzIGZyb20gJy4uL21hdGgvTWF0aFV0aWxzLmpzJztcclxuaW1wb3J0IHsgUGVyc3BlY3RpdmVDYW1lcmEgfSBmcm9tICcuLi9jYW1lcmFzL1BlcnNwZWN0aXZlQ2FtZXJhLmpzJztcclxuXHJcbmNsYXNzIFNwb3RMaWdodFNoYWRvdyBleHRlbmRzIExpZ2h0U2hhZG93IHtcclxuXHJcblx0Y29uc3RydWN0b3IoKSB7XHJcblxyXG5cdFx0c3VwZXIoIG5ldyBQZXJzcGVjdGl2ZUNhbWVyYSggNTAsIDEsIDAuNSwgNTAwICkgKTtcclxuXHJcblx0XHR0aGlzLmlzU3BvdExpZ2h0U2hhZG93ID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLmZvY3VzID0gMTtcclxuXHJcblx0fVxyXG5cclxuXHR1cGRhdGVNYXRyaWNlcyggbGlnaHQgKSB7XHJcblxyXG5cdFx0Y29uc3QgY2FtZXJhID0gdGhpcy5jYW1lcmE7XHJcblxyXG5cdFx0Y29uc3QgZm92ID0gTWF0aFV0aWxzLlJBRDJERUcgKiAyICogbGlnaHQuYW5nbGUgKiB0aGlzLmZvY3VzO1xyXG5cdFx0Y29uc3QgYXNwZWN0ID0gdGhpcy5tYXBTaXplLndpZHRoIC8gdGhpcy5tYXBTaXplLmhlaWdodDtcclxuXHRcdGNvbnN0IGZhciA9IGxpZ2h0LmRpc3RhbmNlIHx8IGNhbWVyYS5mYXI7XHJcblxyXG5cdFx0aWYgKCBmb3YgIT09IGNhbWVyYS5mb3YgfHwgYXNwZWN0ICE9PSBjYW1lcmEuYXNwZWN0IHx8IGZhciAhPT0gY2FtZXJhLmZhciApIHtcclxuXHJcblx0XHRcdGNhbWVyYS5mb3YgPSBmb3Y7XHJcblx0XHRcdGNhbWVyYS5hc3BlY3QgPSBhc3BlY3Q7XHJcblx0XHRcdGNhbWVyYS5mYXIgPSBmYXI7XHJcblx0XHRcdGNhbWVyYS51cGRhdGVQcm9qZWN0aW9uTWF0cml4KCk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHN1cGVyLnVwZGF0ZU1hdHJpY2VzKCBsaWdodCApO1xyXG5cclxuXHR9XHJcblxyXG5cdGNvcHkoIHNvdXJjZSApIHtcclxuXHJcblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcclxuXHJcblx0XHR0aGlzLmZvY3VzID0gc291cmNlLmZvY3VzO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBTcG90TGlnaHRTaGFkb3cgfTtcclxuIiwiaW1wb3J0IHsgTGlnaHQgfSBmcm9tICcuL0xpZ2h0LmpzJztcclxuaW1wb3J0IHsgU3BvdExpZ2h0U2hhZG93IH0gZnJvbSAnLi9TcG90TGlnaHRTaGFkb3cuanMnO1xyXG5pbXBvcnQgeyBPYmplY3QzRCB9IGZyb20gJy4uL2NvcmUvT2JqZWN0M0QuanMnO1xyXG5cclxuY2xhc3MgU3BvdExpZ2h0IGV4dGVuZHMgTGlnaHQge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggY29sb3IsIGludGVuc2l0eSwgZGlzdGFuY2UgPSAwLCBhbmdsZSA9IE1hdGguUEkgLyAzLCBwZW51bWJyYSA9IDAsIGRlY2F5ID0gMiApIHtcclxuXHJcblx0XHRzdXBlciggY29sb3IsIGludGVuc2l0eSApO1xyXG5cclxuXHRcdHRoaXMuaXNTcG90TGlnaHQgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMudHlwZSA9ICdTcG90TGlnaHQnO1xyXG5cclxuXHRcdHRoaXMucG9zaXRpb24uY29weSggT2JqZWN0M0QuREVGQVVMVF9VUCApO1xyXG5cdFx0dGhpcy51cGRhdGVNYXRyaXgoKTtcclxuXHJcblx0XHR0aGlzLnRhcmdldCA9IG5ldyBPYmplY3QzRCgpO1xyXG5cclxuXHRcdHRoaXMuZGlzdGFuY2UgPSBkaXN0YW5jZTtcclxuXHRcdHRoaXMuYW5nbGUgPSBhbmdsZTtcclxuXHRcdHRoaXMucGVudW1icmEgPSBwZW51bWJyYTtcclxuXHRcdHRoaXMuZGVjYXkgPSBkZWNheTtcclxuXHJcblx0XHR0aGlzLm1hcCA9IG51bGw7XHJcblxyXG5cdFx0dGhpcy5zaGFkb3cgPSBuZXcgU3BvdExpZ2h0U2hhZG93KCk7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0IHBvd2VyKCkge1xyXG5cclxuXHRcdC8vIGNvbXB1dGUgdGhlIGxpZ2h0J3MgbHVtaW5vdXMgcG93ZXIgKGluIGx1bWVucykgZnJvbSBpdHMgaW50ZW5zaXR5IChpbiBjYW5kZWxhKVxyXG5cdFx0Ly8gYnkgY29udmVudGlvbiBmb3IgYSBzcG90bGlnaHQsIGx1bWlub3VzIHBvd2VyIChsbSkgPSDPgCAqIGx1bWlub3VzIGludGVuc2l0eSAoY2QpXHJcblx0XHRyZXR1cm4gdGhpcy5pbnRlbnNpdHkgKiBNYXRoLlBJO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldCBwb3dlciggcG93ZXIgKSB7XHJcblxyXG5cdFx0Ly8gc2V0IHRoZSBsaWdodCdzIGludGVuc2l0eSAoaW4gY2FuZGVsYSkgZnJvbSB0aGUgZGVzaXJlZCBsdW1pbm91cyBwb3dlciAoaW4gbHVtZW5zKVxyXG5cdFx0dGhpcy5pbnRlbnNpdHkgPSBwb3dlciAvIE1hdGguUEk7XHJcblxyXG5cdH1cclxuXHJcblx0ZGlzcG9zZSgpIHtcclxuXHJcblx0XHR0aGlzLnNoYWRvdy5kaXNwb3NlKCk7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlLCByZWN1cnNpdmUgKSB7XHJcblxyXG5cdFx0c3VwZXIuY29weSggc291cmNlLCByZWN1cnNpdmUgKTtcclxuXHJcblx0XHR0aGlzLmRpc3RhbmNlID0gc291cmNlLmRpc3RhbmNlO1xyXG5cdFx0dGhpcy5hbmdsZSA9IHNvdXJjZS5hbmdsZTtcclxuXHRcdHRoaXMucGVudW1icmEgPSBzb3VyY2UucGVudW1icmE7XHJcblx0XHR0aGlzLmRlY2F5ID0gc291cmNlLmRlY2F5O1xyXG5cclxuXHRcdHRoaXMudGFyZ2V0ID0gc291cmNlLnRhcmdldC5jbG9uZSgpO1xyXG5cclxuXHRcdHRoaXMuc2hhZG93ID0gc291cmNlLnNoYWRvdy5jbG9uZSgpO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBTcG90TGlnaHQgfTtcclxuIiwiaW1wb3J0IHsgTGlnaHRTaGFkb3cgfSBmcm9tICcuL0xpZ2h0U2hhZG93LmpzJztcclxuaW1wb3J0IHsgUGVyc3BlY3RpdmVDYW1lcmEgfSBmcm9tICcuLi9jYW1lcmFzL1BlcnNwZWN0aXZlQ2FtZXJhLmpzJztcclxuaW1wb3J0IHsgTWF0cml4NCB9IGZyb20gJy4uL21hdGgvTWF0cml4NC5qcyc7XHJcbmltcG9ydCB7IFZlY3RvcjIgfSBmcm9tICcuLi9tYXRoL1ZlY3RvcjIuanMnO1xyXG5pbXBvcnQgeyBWZWN0b3IzIH0gZnJvbSAnLi4vbWF0aC9WZWN0b3IzLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yNCB9IGZyb20gJy4uL21hdGgvVmVjdG9yNC5qcyc7XHJcblxyXG5jb25zdCBfcHJvalNjcmVlbk1hdHJpeCA9IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDQoKTtcclxuY29uc3QgX2xpZ2h0UG9zaXRpb25Xb3JsZCA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuY29uc3QgX2xvb2tUYXJnZXQgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XHJcblxyXG5jbGFzcyBQb2ludExpZ2h0U2hhZG93IGV4dGVuZHMgTGlnaHRTaGFkb3cge1xyXG5cclxuXHRjb25zdHJ1Y3RvcigpIHtcclxuXHJcblx0XHRzdXBlciggbmV3IFBlcnNwZWN0aXZlQ2FtZXJhKCA5MCwgMSwgMC41LCA1MDAgKSApO1xyXG5cclxuXHRcdHRoaXMuaXNQb2ludExpZ2h0U2hhZG93ID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLl9mcmFtZUV4dGVudHMgPSBuZXcgVmVjdG9yMiggNCwgMiApO1xyXG5cclxuXHRcdHRoaXMuX3ZpZXdwb3J0Q291bnQgPSA2O1xyXG5cclxuXHRcdHRoaXMuX3ZpZXdwb3J0cyA9IFtcclxuXHRcdFx0Ly8gVGhlc2Ugdmlld3BvcnRzIG1hcCBhIGN1YmUtbWFwIG9udG8gYSAyRCB0ZXh0dXJlIHdpdGggdGhlXHJcblx0XHRcdC8vIGZvbGxvd2luZyBvcmllbnRhdGlvbjpcclxuXHRcdFx0Ly9cclxuXHRcdFx0Ly8gIHh6WFpcclxuXHRcdFx0Ly8gICB5IFlcclxuXHRcdFx0Ly9cclxuXHRcdFx0Ly8gWCAtIFBvc2l0aXZlIHggZGlyZWN0aW9uXHJcblx0XHRcdC8vIHggLSBOZWdhdGl2ZSB4IGRpcmVjdGlvblxyXG5cdFx0XHQvLyBZIC0gUG9zaXRpdmUgeSBkaXJlY3Rpb25cclxuXHRcdFx0Ly8geSAtIE5lZ2F0aXZlIHkgZGlyZWN0aW9uXHJcblx0XHRcdC8vIFogLSBQb3NpdGl2ZSB6IGRpcmVjdGlvblxyXG5cdFx0XHQvLyB6IC0gTmVnYXRpdmUgeiBkaXJlY3Rpb25cclxuXHJcblx0XHRcdC8vIHBvc2l0aXZlIFhcclxuXHRcdFx0bmV3IFZlY3RvcjQoIDIsIDEsIDEsIDEgKSxcclxuXHRcdFx0Ly8gbmVnYXRpdmUgWFxyXG5cdFx0XHRuZXcgVmVjdG9yNCggMCwgMSwgMSwgMSApLFxyXG5cdFx0XHQvLyBwb3NpdGl2ZSBaXHJcblx0XHRcdG5ldyBWZWN0b3I0KCAzLCAxLCAxLCAxICksXHJcblx0XHRcdC8vIG5lZ2F0aXZlIFpcclxuXHRcdFx0bmV3IFZlY3RvcjQoIDEsIDEsIDEsIDEgKSxcclxuXHRcdFx0Ly8gcG9zaXRpdmUgWVxyXG5cdFx0XHRuZXcgVmVjdG9yNCggMywgMCwgMSwgMSApLFxyXG5cdFx0XHQvLyBuZWdhdGl2ZSBZXHJcblx0XHRcdG5ldyBWZWN0b3I0KCAxLCAwLCAxLCAxIClcclxuXHRcdF07XHJcblxyXG5cdFx0dGhpcy5fY3ViZURpcmVjdGlvbnMgPSBbXHJcblx0XHRcdG5ldyBWZWN0b3IzKCAxLCAwLCAwICksIG5ldyBWZWN0b3IzKCAtIDEsIDAsIDAgKSwgbmV3IFZlY3RvcjMoIDAsIDAsIDEgKSxcclxuXHRcdFx0bmV3IFZlY3RvcjMoIDAsIDAsIC0gMSApLCBuZXcgVmVjdG9yMyggMCwgMSwgMCApLCBuZXcgVmVjdG9yMyggMCwgLSAxLCAwIClcclxuXHRcdF07XHJcblxyXG5cdFx0dGhpcy5fY3ViZVVwcyA9IFtcclxuXHRcdFx0bmV3IFZlY3RvcjMoIDAsIDEsIDAgKSwgbmV3IFZlY3RvcjMoIDAsIDEsIDAgKSwgbmV3IFZlY3RvcjMoIDAsIDEsIDAgKSxcclxuXHRcdFx0bmV3IFZlY3RvcjMoIDAsIDEsIDAgKSwgbmV3IFZlY3RvcjMoIDAsIDAsIDEgKSxcdG5ldyBWZWN0b3IzKCAwLCAwLCAtIDEgKVxyXG5cdFx0XTtcclxuXHJcblx0fVxyXG5cclxuXHR1cGRhdGVNYXRyaWNlcyggbGlnaHQsIHZpZXdwb3J0SW5kZXggPSAwICkge1xyXG5cclxuXHRcdGNvbnN0IGNhbWVyYSA9IHRoaXMuY2FtZXJhO1xyXG5cdFx0Y29uc3Qgc2hhZG93TWF0cml4ID0gdGhpcy5tYXRyaXg7XHJcblxyXG5cdFx0Y29uc3QgZmFyID0gbGlnaHQuZGlzdGFuY2UgfHwgY2FtZXJhLmZhcjtcclxuXHJcblx0XHRpZiAoIGZhciAhPT0gY2FtZXJhLmZhciApIHtcclxuXHJcblx0XHRcdGNhbWVyYS5mYXIgPSBmYXI7XHJcblx0XHRcdGNhbWVyYS51cGRhdGVQcm9qZWN0aW9uTWF0cml4KCk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdF9saWdodFBvc2l0aW9uV29ybGQuc2V0RnJvbU1hdHJpeFBvc2l0aW9uKCBsaWdodC5tYXRyaXhXb3JsZCApO1xyXG5cdFx0Y2FtZXJhLnBvc2l0aW9uLmNvcHkoIF9saWdodFBvc2l0aW9uV29ybGQgKTtcclxuXHJcblx0XHRfbG9va1RhcmdldC5jb3B5KCBjYW1lcmEucG9zaXRpb24gKTtcclxuXHRcdF9sb29rVGFyZ2V0LmFkZCggdGhpcy5fY3ViZURpcmVjdGlvbnNbIHZpZXdwb3J0SW5kZXggXSApO1xyXG5cdFx0Y2FtZXJhLnVwLmNvcHkoIHRoaXMuX2N1YmVVcHNbIHZpZXdwb3J0SW5kZXggXSApO1xyXG5cdFx0Y2FtZXJhLmxvb2tBdCggX2xvb2tUYXJnZXQgKTtcclxuXHRcdGNhbWVyYS51cGRhdGVNYXRyaXhXb3JsZCgpO1xyXG5cclxuXHRcdHNoYWRvd01hdHJpeC5tYWtlVHJhbnNsYXRpb24oIC0gX2xpZ2h0UG9zaXRpb25Xb3JsZC54LCAtIF9saWdodFBvc2l0aW9uV29ybGQueSwgLSBfbGlnaHRQb3NpdGlvbldvcmxkLnogKTtcclxuXHJcblx0XHRfcHJvalNjcmVlbk1hdHJpeC5tdWx0aXBseU1hdHJpY2VzKCBjYW1lcmEucHJvamVjdGlvbk1hdHJpeCwgY2FtZXJhLm1hdHJpeFdvcmxkSW52ZXJzZSApO1xyXG5cdFx0dGhpcy5fZnJ1c3R1bS5zZXRGcm9tUHJvamVjdGlvbk1hdHJpeCggX3Byb2pTY3JlZW5NYXRyaXggKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgUG9pbnRMaWdodFNoYWRvdyB9O1xyXG4iLCJpbXBvcnQgeyBMaWdodCB9IGZyb20gJy4vTGlnaHQuanMnO1xyXG5pbXBvcnQgeyBQb2ludExpZ2h0U2hhZG93IH0gZnJvbSAnLi9Qb2ludExpZ2h0U2hhZG93LmpzJztcclxuXHJcbmNsYXNzIFBvaW50TGlnaHQgZXh0ZW5kcyBMaWdodCB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBjb2xvciwgaW50ZW5zaXR5LCBkaXN0YW5jZSA9IDAsIGRlY2F5ID0gMiApIHtcclxuXHJcblx0XHRzdXBlciggY29sb3IsIGludGVuc2l0eSApO1xyXG5cclxuXHRcdHRoaXMuaXNQb2ludExpZ2h0ID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSAnUG9pbnRMaWdodCc7XHJcblxyXG5cdFx0dGhpcy5kaXN0YW5jZSA9IGRpc3RhbmNlO1xyXG5cdFx0dGhpcy5kZWNheSA9IGRlY2F5O1xyXG5cclxuXHRcdHRoaXMuc2hhZG93ID0gbmV3IFBvaW50TGlnaHRTaGFkb3coKTtcclxuXHJcblx0fVxyXG5cclxuXHRnZXQgcG93ZXIoKSB7XHJcblxyXG5cdFx0Ly8gY29tcHV0ZSB0aGUgbGlnaHQncyBsdW1pbm91cyBwb3dlciAoaW4gbHVtZW5zKSBmcm9tIGl0cyBpbnRlbnNpdHkgKGluIGNhbmRlbGEpXHJcblx0XHQvLyBmb3IgYW4gaXNvdHJvcGljIGxpZ2h0IHNvdXJjZSwgbHVtaW5vdXMgcG93ZXIgKGxtKSA9IDQgz4AgbHVtaW5vdXMgaW50ZW5zaXR5IChjZClcclxuXHRcdHJldHVybiB0aGlzLmludGVuc2l0eSAqIDQgKiBNYXRoLlBJO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldCBwb3dlciggcG93ZXIgKSB7XHJcblxyXG5cdFx0Ly8gc2V0IHRoZSBsaWdodCdzIGludGVuc2l0eSAoaW4gY2FuZGVsYSkgZnJvbSB0aGUgZGVzaXJlZCBsdW1pbm91cyBwb3dlciAoaW4gbHVtZW5zKVxyXG5cdFx0dGhpcy5pbnRlbnNpdHkgPSBwb3dlciAvICggNCAqIE1hdGguUEkgKTtcclxuXHJcblx0fVxyXG5cclxuXHRkaXNwb3NlKCkge1xyXG5cclxuXHRcdHRoaXMuc2hhZG93LmRpc3Bvc2UoKTtcclxuXHJcblx0fVxyXG5cclxuXHRjb3B5KCBzb3VyY2UsIHJlY3Vyc2l2ZSApIHtcclxuXHJcblx0XHRzdXBlci5jb3B5KCBzb3VyY2UsIHJlY3Vyc2l2ZSApO1xyXG5cclxuXHRcdHRoaXMuZGlzdGFuY2UgPSBzb3VyY2UuZGlzdGFuY2U7XHJcblx0XHR0aGlzLmRlY2F5ID0gc291cmNlLmRlY2F5O1xyXG5cclxuXHRcdHRoaXMuc2hhZG93ID0gc291cmNlLnNoYWRvdy5jbG9uZSgpO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBQb2ludExpZ2h0IH07XHJcbiIsImltcG9ydCB7IExpZ2h0U2hhZG93IH0gZnJvbSAnLi9MaWdodFNoYWRvdy5qcyc7XHJcbmltcG9ydCB7IE9ydGhvZ3JhcGhpY0NhbWVyYSB9IGZyb20gJy4uL2NhbWVyYXMvT3J0aG9ncmFwaGljQ2FtZXJhLmpzJztcclxuXHJcbmNsYXNzIERpcmVjdGlvbmFsTGlnaHRTaGFkb3cgZXh0ZW5kcyBMaWdodFNoYWRvdyB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCkge1xyXG5cclxuXHRcdHN1cGVyKCBuZXcgT3J0aG9ncmFwaGljQ2FtZXJhKCAtIDUsIDUsIDUsIC0gNSwgMC41LCA1MDAgKSApO1xyXG5cclxuXHRcdHRoaXMuaXNEaXJlY3Rpb25hbExpZ2h0U2hhZG93ID0gdHJ1ZTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgRGlyZWN0aW9uYWxMaWdodFNoYWRvdyB9O1xyXG4iLCJpbXBvcnQgeyBMaWdodCB9IGZyb20gJy4vTGlnaHQuanMnO1xyXG5pbXBvcnQgeyBEaXJlY3Rpb25hbExpZ2h0U2hhZG93IH0gZnJvbSAnLi9EaXJlY3Rpb25hbExpZ2h0U2hhZG93LmpzJztcclxuaW1wb3J0IHsgT2JqZWN0M0QgfSBmcm9tICcuLi9jb3JlL09iamVjdDNELmpzJztcclxuXHJcbmNsYXNzIERpcmVjdGlvbmFsTGlnaHQgZXh0ZW5kcyBMaWdodCB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBjb2xvciwgaW50ZW5zaXR5ICkge1xyXG5cclxuXHRcdHN1cGVyKCBjb2xvciwgaW50ZW5zaXR5ICk7XHJcblxyXG5cdFx0dGhpcy5pc0RpcmVjdGlvbmFsTGlnaHQgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMudHlwZSA9ICdEaXJlY3Rpb25hbExpZ2h0JztcclxuXHJcblx0XHR0aGlzLnBvc2l0aW9uLmNvcHkoIE9iamVjdDNELkRFRkFVTFRfVVAgKTtcclxuXHRcdHRoaXMudXBkYXRlTWF0cml4KCk7XHJcblxyXG5cdFx0dGhpcy50YXJnZXQgPSBuZXcgT2JqZWN0M0QoKTtcclxuXHJcblx0XHR0aGlzLnNoYWRvdyA9IG5ldyBEaXJlY3Rpb25hbExpZ2h0U2hhZG93KCk7XHJcblxyXG5cdH1cclxuXHJcblx0ZGlzcG9zZSgpIHtcclxuXHJcblx0XHR0aGlzLnNoYWRvdy5kaXNwb3NlKCk7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xyXG5cclxuXHRcdHRoaXMudGFyZ2V0ID0gc291cmNlLnRhcmdldC5jbG9uZSgpO1xyXG5cdFx0dGhpcy5zaGFkb3cgPSBzb3VyY2Uuc2hhZG93LmNsb25lKCk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IERpcmVjdGlvbmFsTGlnaHQgfTtcclxuIiwiaW1wb3J0IHsgTGlnaHQgfSBmcm9tICcuL0xpZ2h0LmpzJztcclxuXHJcbmNsYXNzIEFtYmllbnRMaWdodCBleHRlbmRzIExpZ2h0IHtcclxuXHJcblx0Y29uc3RydWN0b3IoIGNvbG9yLCBpbnRlbnNpdHkgKSB7XHJcblxyXG5cdFx0c3VwZXIoIGNvbG9yLCBpbnRlbnNpdHkgKTtcclxuXHJcblx0XHR0aGlzLmlzQW1iaWVudExpZ2h0ID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSAnQW1iaWVudExpZ2h0JztcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgQW1iaWVudExpZ2h0IH07XHJcbiIsImltcG9ydCB7IExpZ2h0IH0gZnJvbSAnLi9MaWdodC5qcyc7XHJcblxyXG5jbGFzcyBSZWN0QXJlYUxpZ2h0IGV4dGVuZHMgTGlnaHQge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggY29sb3IsIGludGVuc2l0eSwgd2lkdGggPSAxMCwgaGVpZ2h0ID0gMTAgKSB7XHJcblxyXG5cdFx0c3VwZXIoIGNvbG9yLCBpbnRlbnNpdHkgKTtcclxuXHJcblx0XHR0aGlzLmlzUmVjdEFyZWFMaWdodCA9IHRydWU7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ1JlY3RBcmVhTGlnaHQnO1xyXG5cclxuXHRcdHRoaXMud2lkdGggPSB3aWR0aDtcclxuXHRcdHRoaXMuaGVpZ2h0ID0gaGVpZ2h0O1xyXG5cclxuXHR9XHJcblxyXG5cdGdldCBwb3dlcigpIHtcclxuXHJcblx0XHQvLyBjb21wdXRlIHRoZSBsaWdodCdzIGx1bWlub3VzIHBvd2VyIChpbiBsdW1lbnMpIGZyb20gaXRzIGludGVuc2l0eSAoaW4gbml0cylcclxuXHRcdHJldHVybiB0aGlzLmludGVuc2l0eSAqIHRoaXMud2lkdGggKiB0aGlzLmhlaWdodCAqIE1hdGguUEk7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0IHBvd2VyKCBwb3dlciApIHtcclxuXHJcblx0XHQvLyBzZXQgdGhlIGxpZ2h0J3MgaW50ZW5zaXR5IChpbiBuaXRzKSBmcm9tIHRoZSBkZXNpcmVkIGx1bWlub3VzIHBvd2VyIChpbiBsdW1lbnMpXHJcblx0XHR0aGlzLmludGVuc2l0eSA9IHBvd2VyIC8gKCB0aGlzLndpZHRoICogdGhpcy5oZWlnaHQgKiBNYXRoLlBJICk7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xyXG5cclxuXHRcdHRoaXMud2lkdGggPSBzb3VyY2Uud2lkdGg7XHJcblx0XHR0aGlzLmhlaWdodCA9IHNvdXJjZS5oZWlnaHQ7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0dG9KU09OKCBtZXRhICkge1xyXG5cclxuXHRcdGNvbnN0IGRhdGEgPSBzdXBlci50b0pTT04oIG1ldGEgKTtcclxuXHJcblx0XHRkYXRhLm9iamVjdC53aWR0aCA9IHRoaXMud2lkdGg7XHJcblx0XHRkYXRhLm9iamVjdC5oZWlnaHQgPSB0aGlzLmhlaWdodDtcclxuXHJcblx0XHRyZXR1cm4gZGF0YTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgUmVjdEFyZWFMaWdodCB9O1xyXG4iLCJpbXBvcnQgeyBWZWN0b3IzIH0gZnJvbSAnLi9WZWN0b3IzLmpzJztcclxuXHJcbi8qKlxyXG4gKiBQcmltYXJ5IHJlZmVyZW5jZTpcclxuICogICBodHRwczovL2dyYXBoaWNzLnN0YW5mb3JkLmVkdS9wYXBlcnMvZW52bWFwL2Vudm1hcC5wZGZcclxuICpcclxuICogU2Vjb25kYXJ5IHJlZmVyZW5jZTpcclxuICogICBodHRwczovL3d3dy5wcHNsb2FuLm9yZy9wdWJsaWNhdGlvbnMvU3R1cGlkU0gzNi5wZGZcclxuICovXHJcblxyXG4vLyAzLWJhbmQgU0ggZGVmaW5lZCBieSA5IGNvZWZmaWNpZW50c1xyXG5cclxuY2xhc3MgU3BoZXJpY2FsSGFybW9uaWNzMyB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCkge1xyXG5cclxuXHRcdHRoaXMuaXNTcGhlcmljYWxIYXJtb25pY3MzID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLmNvZWZmaWNpZW50cyA9IFtdO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IDk7IGkgKysgKSB7XHJcblxyXG5cdFx0XHR0aGlzLmNvZWZmaWNpZW50cy5wdXNoKCBuZXcgVmVjdG9yMygpICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdHNldCggY29lZmZpY2llbnRzICkge1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IDk7IGkgKysgKSB7XHJcblxyXG5cdFx0XHR0aGlzLmNvZWZmaWNpZW50c1sgaSBdLmNvcHkoIGNvZWZmaWNpZW50c1sgaSBdICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHplcm8oKSB7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgOTsgaSArKyApIHtcclxuXHJcblx0XHRcdHRoaXMuY29lZmZpY2llbnRzWyBpIF0uc2V0KCAwLCAwLCAwICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdC8vIGdldCB0aGUgcmFkaWFuY2UgaW4gdGhlIGRpcmVjdGlvbiBvZiB0aGUgbm9ybWFsXHJcblx0Ly8gdGFyZ2V0IGlzIGEgVmVjdG9yM1xyXG5cdGdldEF0KCBub3JtYWwsIHRhcmdldCApIHtcclxuXHJcblx0XHQvLyBub3JtYWwgaXMgYXNzdW1lZCB0byBiZSB1bml0IGxlbmd0aFxyXG5cclxuXHRcdGNvbnN0IHggPSBub3JtYWwueCwgeSA9IG5vcm1hbC55LCB6ID0gbm9ybWFsLno7XHJcblxyXG5cdFx0Y29uc3QgY29lZmYgPSB0aGlzLmNvZWZmaWNpZW50cztcclxuXHJcblx0XHQvLyBiYW5kIDBcclxuXHRcdHRhcmdldC5jb3B5KCBjb2VmZlsgMCBdICkubXVsdGlwbHlTY2FsYXIoIDAuMjgyMDk1ICk7XHJcblxyXG5cdFx0Ly8gYmFuZCAxXHJcblx0XHR0YXJnZXQuYWRkU2NhbGVkVmVjdG9yKCBjb2VmZlsgMSBdLCAwLjQ4ODYwMyAqIHkgKTtcclxuXHRcdHRhcmdldC5hZGRTY2FsZWRWZWN0b3IoIGNvZWZmWyAyIF0sIDAuNDg4NjAzICogeiApO1xyXG5cdFx0dGFyZ2V0LmFkZFNjYWxlZFZlY3RvciggY29lZmZbIDMgXSwgMC40ODg2MDMgKiB4ICk7XHJcblxyXG5cdFx0Ly8gYmFuZCAyXHJcblx0XHR0YXJnZXQuYWRkU2NhbGVkVmVjdG9yKCBjb2VmZlsgNCBdLCAxLjA5MjU0OCAqICggeCAqIHkgKSApO1xyXG5cdFx0dGFyZ2V0LmFkZFNjYWxlZFZlY3RvciggY29lZmZbIDUgXSwgMS4wOTI1NDggKiAoIHkgKiB6ICkgKTtcclxuXHRcdHRhcmdldC5hZGRTY2FsZWRWZWN0b3IoIGNvZWZmWyA2IF0sIDAuMzE1MzkyICogKCAzLjAgKiB6ICogeiAtIDEuMCApICk7XHJcblx0XHR0YXJnZXQuYWRkU2NhbGVkVmVjdG9yKCBjb2VmZlsgNyBdLCAxLjA5MjU0OCAqICggeCAqIHogKSApO1xyXG5cdFx0dGFyZ2V0LmFkZFNjYWxlZFZlY3RvciggY29lZmZbIDggXSwgMC41NDYyNzQgKiAoIHggKiB4IC0geSAqIHkgKSApO1xyXG5cclxuXHRcdHJldHVybiB0YXJnZXQ7XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gZ2V0IHRoZSBpcnJhZGlhbmNlIChyYWRpYW5jZSBjb252b2x2ZWQgd2l0aCBjb3NpbmUgbG9iZSkgaW4gdGhlIGRpcmVjdGlvbiBvZiB0aGUgbm9ybWFsXHJcblx0Ly8gdGFyZ2V0IGlzIGEgVmVjdG9yM1xyXG5cdC8vIGh0dHBzOi8vZ3JhcGhpY3Muc3RhbmZvcmQuZWR1L3BhcGVycy9lbnZtYXAvZW52bWFwLnBkZlxyXG5cdGdldElycmFkaWFuY2VBdCggbm9ybWFsLCB0YXJnZXQgKSB7XHJcblxyXG5cdFx0Ly8gbm9ybWFsIGlzIGFzc3VtZWQgdG8gYmUgdW5pdCBsZW5ndGhcclxuXHJcblx0XHRjb25zdCB4ID0gbm9ybWFsLngsIHkgPSBub3JtYWwueSwgeiA9IG5vcm1hbC56O1xyXG5cclxuXHRcdGNvbnN0IGNvZWZmID0gdGhpcy5jb2VmZmljaWVudHM7XHJcblxyXG5cdFx0Ly8gYmFuZCAwXHJcblx0XHR0YXJnZXQuY29weSggY29lZmZbIDAgXSApLm11bHRpcGx5U2NhbGFyKCAwLjg4NjIyNyApOyAvLyDPgCAqIDAuMjgyMDk1XHJcblxyXG5cdFx0Ly8gYmFuZCAxXHJcblx0XHR0YXJnZXQuYWRkU2NhbGVkVmVjdG9yKCBjb2VmZlsgMSBdLCAyLjAgKiAwLjUxMTY2NCAqIHkgKTsgLy8gKCAyICogz4AgLyAzICkgKiAwLjQ4ODYwM1xyXG5cdFx0dGFyZ2V0LmFkZFNjYWxlZFZlY3RvciggY29lZmZbIDIgXSwgMi4wICogMC41MTE2NjQgKiB6ICk7XHJcblx0XHR0YXJnZXQuYWRkU2NhbGVkVmVjdG9yKCBjb2VmZlsgMyBdLCAyLjAgKiAwLjUxMTY2NCAqIHggKTtcclxuXHJcblx0XHQvLyBiYW5kIDJcclxuXHRcdHRhcmdldC5hZGRTY2FsZWRWZWN0b3IoIGNvZWZmWyA0IF0sIDIuMCAqIDAuNDI5MDQzICogeCAqIHkgKTsgLy8gKCDPgCAvIDQgKSAqIDEuMDkyNTQ4XHJcblx0XHR0YXJnZXQuYWRkU2NhbGVkVmVjdG9yKCBjb2VmZlsgNSBdLCAyLjAgKiAwLjQyOTA0MyAqIHkgKiB6ICk7XHJcblx0XHR0YXJnZXQuYWRkU2NhbGVkVmVjdG9yKCBjb2VmZlsgNiBdLCAwLjc0MzEyNSAqIHogKiB6IC0gMC4yNDc3MDggKTsgLy8gKCDPgCAvIDQgKSAqIDAuMzE1MzkyICogM1xyXG5cdFx0dGFyZ2V0LmFkZFNjYWxlZFZlY3RvciggY29lZmZbIDcgXSwgMi4wICogMC40MjkwNDMgKiB4ICogeiApO1xyXG5cdFx0dGFyZ2V0LmFkZFNjYWxlZFZlY3RvciggY29lZmZbIDggXSwgMC40MjkwNDMgKiAoIHggKiB4IC0geSAqIHkgKSApOyAvLyAoIM+AIC8gNCApICogMC41NDYyNzRcclxuXHJcblx0XHRyZXR1cm4gdGFyZ2V0O1xyXG5cclxuXHR9XHJcblxyXG5cdGFkZCggc2ggKSB7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgOTsgaSArKyApIHtcclxuXHJcblx0XHRcdHRoaXMuY29lZmZpY2llbnRzWyBpIF0uYWRkKCBzaC5jb2VmZmljaWVudHNbIGkgXSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRhZGRTY2FsZWRTSCggc2gsIHMgKSB7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgOTsgaSArKyApIHtcclxuXHJcblx0XHRcdHRoaXMuY29lZmZpY2llbnRzWyBpIF0uYWRkU2NhbGVkVmVjdG9yKCBzaC5jb2VmZmljaWVudHNbIGkgXSwgcyApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzY2FsZSggcyApIHtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCA5OyBpICsrICkge1xyXG5cclxuXHRcdFx0dGhpcy5jb2VmZmljaWVudHNbIGkgXS5tdWx0aXBseVNjYWxhciggcyApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRsZXJwKCBzaCwgYWxwaGEgKSB7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgOTsgaSArKyApIHtcclxuXHJcblx0XHRcdHRoaXMuY29lZmZpY2llbnRzWyBpIF0ubGVycCggc2guY29lZmZpY2llbnRzWyBpIF0sIGFscGhhICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGVxdWFscyggc2ggKSB7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgOTsgaSArKyApIHtcclxuXHJcblx0XHRcdGlmICggISB0aGlzLmNvZWZmaWNpZW50c1sgaSBdLmVxdWFscyggc2guY29lZmZpY2llbnRzWyBpIF0gKSApIHtcclxuXHJcblx0XHRcdFx0cmV0dXJuIGZhbHNlO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdHJ1ZTtcclxuXHJcblx0fVxyXG5cclxuXHRjb3B5KCBzaCApIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5zZXQoIHNoLmNvZWZmaWNpZW50cyApO1xyXG5cclxuXHR9XHJcblxyXG5cdGNsb25lKCkge1xyXG5cclxuXHRcdHJldHVybiBuZXcgdGhpcy5jb25zdHJ1Y3RvcigpLmNvcHkoIHRoaXMgKTtcclxuXHJcblx0fVxyXG5cclxuXHRmcm9tQXJyYXkoIGFycmF5LCBvZmZzZXQgPSAwICkge1xyXG5cclxuXHRcdGNvbnN0IGNvZWZmaWNpZW50cyA9IHRoaXMuY29lZmZpY2llbnRzO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IDk7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRjb2VmZmljaWVudHNbIGkgXS5mcm9tQXJyYXkoIGFycmF5LCBvZmZzZXQgKyAoIGkgKiAzICkgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0dG9BcnJheSggYXJyYXkgPSBbXSwgb2Zmc2V0ID0gMCApIHtcclxuXHJcblx0XHRjb25zdCBjb2VmZmljaWVudHMgPSB0aGlzLmNvZWZmaWNpZW50cztcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCA5OyBpICsrICkge1xyXG5cclxuXHRcdFx0Y29lZmZpY2llbnRzWyBpIF0udG9BcnJheSggYXJyYXksIG9mZnNldCArICggaSAqIDMgKSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gYXJyYXk7XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gZXZhbHVhdGUgdGhlIGJhc2lzIGZ1bmN0aW9uc1xyXG5cdC8vIHNoQmFzaXMgaXMgYW4gQXJyYXlbIDkgXVxyXG5cdHN0YXRpYyBnZXRCYXNpc0F0KCBub3JtYWwsIHNoQmFzaXMgKSB7XHJcblxyXG5cdFx0Ly8gbm9ybWFsIGlzIGFzc3VtZWQgdG8gYmUgdW5pdCBsZW5ndGhcclxuXHJcblx0XHRjb25zdCB4ID0gbm9ybWFsLngsIHkgPSBub3JtYWwueSwgeiA9IG5vcm1hbC56O1xyXG5cclxuXHRcdC8vIGJhbmQgMFxyXG5cdFx0c2hCYXNpc1sgMCBdID0gMC4yODIwOTU7XHJcblxyXG5cdFx0Ly8gYmFuZCAxXHJcblx0XHRzaEJhc2lzWyAxIF0gPSAwLjQ4ODYwMyAqIHk7XHJcblx0XHRzaEJhc2lzWyAyIF0gPSAwLjQ4ODYwMyAqIHo7XHJcblx0XHRzaEJhc2lzWyAzIF0gPSAwLjQ4ODYwMyAqIHg7XHJcblxyXG5cdFx0Ly8gYmFuZCAyXHJcblx0XHRzaEJhc2lzWyA0IF0gPSAxLjA5MjU0OCAqIHggKiB5O1xyXG5cdFx0c2hCYXNpc1sgNSBdID0gMS4wOTI1NDggKiB5ICogejtcclxuXHRcdHNoQmFzaXNbIDYgXSA9IDAuMzE1MzkyICogKCAzICogeiAqIHogLSAxICk7XHJcblx0XHRzaEJhc2lzWyA3IF0gPSAxLjA5MjU0OCAqIHggKiB6O1xyXG5cdFx0c2hCYXNpc1sgOCBdID0gMC41NDYyNzQgKiAoIHggKiB4IC0geSAqIHkgKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgU3BoZXJpY2FsSGFybW9uaWNzMyB9O1xyXG4iLCJpbXBvcnQgeyBTcGhlcmljYWxIYXJtb25pY3MzIH0gZnJvbSAnLi4vbWF0aC9TcGhlcmljYWxIYXJtb25pY3MzLmpzJztcclxuaW1wb3J0IHsgTGlnaHQgfSBmcm9tICcuL0xpZ2h0LmpzJztcclxuXHJcbmNsYXNzIExpZ2h0UHJvYmUgZXh0ZW5kcyBMaWdodCB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBzaCA9IG5ldyBTcGhlcmljYWxIYXJtb25pY3MzKCksIGludGVuc2l0eSA9IDEgKSB7XHJcblxyXG5cdFx0c3VwZXIoIHVuZGVmaW5lZCwgaW50ZW5zaXR5ICk7XHJcblxyXG5cdFx0dGhpcy5pc0xpZ2h0UHJvYmUgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMuc2ggPSBzaDtcclxuXHJcblx0fVxyXG5cclxuXHRjb3B5KCBzb3VyY2UgKSB7XHJcblxyXG5cdFx0c3VwZXIuY29weSggc291cmNlICk7XHJcblxyXG5cdFx0dGhpcy5zaC5jb3B5KCBzb3VyY2Uuc2ggKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRmcm9tSlNPTigganNvbiApIHtcclxuXHJcblx0XHR0aGlzLmludGVuc2l0eSA9IGpzb24uaW50ZW5zaXR5OyAvLyBUT0RPOiBNb3ZlIHRoaXMgYml0IHRvIExpZ2h0LmZyb21KU09OKCk7XHJcblx0XHR0aGlzLnNoLmZyb21BcnJheSgganNvbi5zaCApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHRvSlNPTiggbWV0YSApIHtcclxuXHJcblx0XHRjb25zdCBkYXRhID0gc3VwZXIudG9KU09OKCBtZXRhICk7XHJcblxyXG5cdFx0ZGF0YS5vYmplY3Quc2ggPSB0aGlzLnNoLnRvQXJyYXkoKTtcclxuXHJcblx0XHRyZXR1cm4gZGF0YTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgTGlnaHRQcm9iZSB9O1xyXG4iLCJpbXBvcnQgeyBDb2xvciB9IGZyb20gJy4uL21hdGgvQ29sb3IuanMnO1xyXG5pbXBvcnQgeyBWZWN0b3IyIH0gZnJvbSAnLi4vbWF0aC9WZWN0b3IyLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yMyB9IGZyb20gJy4uL21hdGgvVmVjdG9yMy5qcyc7XHJcbmltcG9ydCB7IFZlY3RvcjQgfSBmcm9tICcuLi9tYXRoL1ZlY3RvcjQuanMnO1xyXG5pbXBvcnQgeyBNYXRyaXgzIH0gZnJvbSAnLi4vbWF0aC9NYXRyaXgzLmpzJztcclxuaW1wb3J0IHsgTWF0cml4NCB9IGZyb20gJy4uL21hdGgvTWF0cml4NC5qcyc7XHJcbmltcG9ydCB7IEZpbGVMb2FkZXIgfSBmcm9tICcuL0ZpbGVMb2FkZXIuanMnO1xyXG5pbXBvcnQgeyBMb2FkZXIgfSBmcm9tICcuL0xvYWRlci5qcyc7XHJcbmltcG9ydCB7XHJcblx0U2hhZG93TWF0ZXJpYWwsXHJcblx0U3ByaXRlTWF0ZXJpYWwsXHJcblx0UmF3U2hhZGVyTWF0ZXJpYWwsXHJcblx0U2hhZGVyTWF0ZXJpYWwsXHJcblx0UG9pbnRzTWF0ZXJpYWwsXHJcblx0TWVzaFBoeXNpY2FsTWF0ZXJpYWwsXHJcblx0TWVzaFN0YW5kYXJkTWF0ZXJpYWwsXHJcblx0TWVzaFBob25nTWF0ZXJpYWwsXHJcblx0TWVzaFRvb25NYXRlcmlhbCxcclxuXHRNZXNoTm9ybWFsTWF0ZXJpYWwsXHJcblx0TWVzaExhbWJlcnRNYXRlcmlhbCxcclxuXHRNZXNoRGVwdGhNYXRlcmlhbCxcclxuXHRNZXNoRGlzdGFuY2VNYXRlcmlhbCxcclxuXHRNZXNoQmFzaWNNYXRlcmlhbCxcclxuXHRNZXNoTWF0Y2FwTWF0ZXJpYWwsXHJcblx0TGluZURhc2hlZE1hdGVyaWFsLFxyXG5cdExpbmVCYXNpY01hdGVyaWFsLFxyXG5cdE1hdGVyaWFsLFxyXG59IGZyb20gJy4uL21hdGVyaWFscy9NYXRlcmlhbHMuanMnO1xyXG5cclxuY2xhc3MgTWF0ZXJpYWxMb2FkZXIgZXh0ZW5kcyBMb2FkZXIge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggbWFuYWdlciApIHtcclxuXHJcblx0XHRzdXBlciggbWFuYWdlciApO1xyXG5cdFx0dGhpcy50ZXh0dXJlcyA9IHt9O1xyXG5cclxuXHR9XHJcblxyXG5cdGxvYWQoIHVybCwgb25Mb2FkLCBvblByb2dyZXNzLCBvbkVycm9yICkge1xyXG5cclxuXHRcdGNvbnN0IHNjb3BlID0gdGhpcztcclxuXHJcblx0XHRjb25zdCBsb2FkZXIgPSBuZXcgRmlsZUxvYWRlciggc2NvcGUubWFuYWdlciApO1xyXG5cdFx0bG9hZGVyLnNldFBhdGgoIHNjb3BlLnBhdGggKTtcclxuXHRcdGxvYWRlci5zZXRSZXF1ZXN0SGVhZGVyKCBzY29wZS5yZXF1ZXN0SGVhZGVyICk7XHJcblx0XHRsb2FkZXIuc2V0V2l0aENyZWRlbnRpYWxzKCBzY29wZS53aXRoQ3JlZGVudGlhbHMgKTtcclxuXHRcdGxvYWRlci5sb2FkKCB1cmwsIGZ1bmN0aW9uICggdGV4dCApIHtcclxuXHJcblx0XHRcdHRyeSB7XHJcblxyXG5cdFx0XHRcdG9uTG9hZCggc2NvcGUucGFyc2UoIEpTT04ucGFyc2UoIHRleHQgKSApICk7XHJcblxyXG5cdFx0XHR9IGNhdGNoICggZSApIHtcclxuXHJcblx0XHRcdFx0aWYgKCBvbkVycm9yICkge1xyXG5cclxuXHRcdFx0XHRcdG9uRXJyb3IoIGUgKTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRjb25zb2xlLmVycm9yKCBlICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0c2NvcGUubWFuYWdlci5pdGVtRXJyb3IoIHVybCApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH0sIG9uUHJvZ3Jlc3MsIG9uRXJyb3IgKTtcclxuXHJcblx0fVxyXG5cclxuXHRwYXJzZSgganNvbiApIHtcclxuXHJcblx0XHRjb25zdCB0ZXh0dXJlcyA9IHRoaXMudGV4dHVyZXM7XHJcblxyXG5cdFx0ZnVuY3Rpb24gZ2V0VGV4dHVyZSggbmFtZSApIHtcclxuXHJcblx0XHRcdGlmICggdGV4dHVyZXNbIG5hbWUgXSA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5NYXRlcmlhbExvYWRlcjogVW5kZWZpbmVkIHRleHR1cmUnLCBuYW1lICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRyZXR1cm4gdGV4dHVyZXNbIG5hbWUgXTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Y29uc3QgbWF0ZXJpYWwgPSBNYXRlcmlhbExvYWRlci5jcmVhdGVNYXRlcmlhbEZyb21UeXBlKCBqc29uLnR5cGUgKTtcclxuXHJcblx0XHRpZiAoIGpzb24udXVpZCAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwudXVpZCA9IGpzb24udXVpZDtcclxuXHRcdGlmICgganNvbi5uYW1lICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5uYW1lID0ganNvbi5uYW1lO1xyXG5cdFx0aWYgKCBqc29uLmNvbG9yICE9PSB1bmRlZmluZWQgJiYgbWF0ZXJpYWwuY29sb3IgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmNvbG9yLnNldEhleCgganNvbi5jb2xvciApO1xyXG5cdFx0aWYgKCBqc29uLnJvdWdobmVzcyAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwucm91Z2huZXNzID0ganNvbi5yb3VnaG5lc3M7XHJcblx0XHRpZiAoIGpzb24ubWV0YWxuZXNzICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5tZXRhbG5lc3MgPSBqc29uLm1ldGFsbmVzcztcclxuXHRcdGlmICgganNvbi5zaGVlbiAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuc2hlZW4gPSBqc29uLnNoZWVuO1xyXG5cdFx0aWYgKCBqc29uLnNoZWVuQ29sb3IgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnNoZWVuQ29sb3IgPSBuZXcgQ29sb3IoKS5zZXRIZXgoIGpzb24uc2hlZW5Db2xvciApO1xyXG5cdFx0aWYgKCBqc29uLnNoZWVuUm91Z2huZXNzICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5zaGVlblJvdWdobmVzcyA9IGpzb24uc2hlZW5Sb3VnaG5lc3M7XHJcblx0XHRpZiAoIGpzb24uZW1pc3NpdmUgIT09IHVuZGVmaW5lZCAmJiBtYXRlcmlhbC5lbWlzc2l2ZSAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuZW1pc3NpdmUuc2V0SGV4KCBqc29uLmVtaXNzaXZlICk7XHJcblx0XHRpZiAoIGpzb24uc3BlY3VsYXIgIT09IHVuZGVmaW5lZCAmJiBtYXRlcmlhbC5zcGVjdWxhciAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuc3BlY3VsYXIuc2V0SGV4KCBqc29uLnNwZWN1bGFyICk7XHJcblx0XHRpZiAoIGpzb24uc3BlY3VsYXJJbnRlbnNpdHkgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnNwZWN1bGFySW50ZW5zaXR5ID0ganNvbi5zcGVjdWxhckludGVuc2l0eTtcclxuXHRcdGlmICgganNvbi5zcGVjdWxhckNvbG9yICE9PSB1bmRlZmluZWQgJiYgbWF0ZXJpYWwuc3BlY3VsYXJDb2xvciAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuc3BlY3VsYXJDb2xvci5zZXRIZXgoIGpzb24uc3BlY3VsYXJDb2xvciApO1xyXG5cdFx0aWYgKCBqc29uLnNoaW5pbmVzcyAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuc2hpbmluZXNzID0ganNvbi5zaGluaW5lc3M7XHJcblx0XHRpZiAoIGpzb24uY2xlYXJjb2F0ICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5jbGVhcmNvYXQgPSBqc29uLmNsZWFyY29hdDtcclxuXHRcdGlmICgganNvbi5jbGVhcmNvYXRSb3VnaG5lc3MgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmNsZWFyY29hdFJvdWdobmVzcyA9IGpzb24uY2xlYXJjb2F0Um91Z2huZXNzO1xyXG5cdFx0aWYgKCBqc29uLmlyaWRlc2NlbmNlICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5pcmlkZXNjZW5jZSA9IGpzb24uaXJpZGVzY2VuY2U7XHJcblx0XHRpZiAoIGpzb24uaXJpZGVzY2VuY2VJT1IgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmlyaWRlc2NlbmNlSU9SID0ganNvbi5pcmlkZXNjZW5jZUlPUjtcclxuXHRcdGlmICgganNvbi5pcmlkZXNjZW5jZVRoaWNrbmVzc1JhbmdlICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5pcmlkZXNjZW5jZVRoaWNrbmVzc1JhbmdlID0ganNvbi5pcmlkZXNjZW5jZVRoaWNrbmVzc1JhbmdlO1xyXG5cdFx0aWYgKCBqc29uLnRyYW5zbWlzc2lvbiAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwudHJhbnNtaXNzaW9uID0ganNvbi50cmFuc21pc3Npb247XHJcblx0XHRpZiAoIGpzb24udGhpY2tuZXNzICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC50aGlja25lc3MgPSBqc29uLnRoaWNrbmVzcztcclxuXHRcdGlmICgganNvbi5hdHRlbnVhdGlvbkRpc3RhbmNlICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5hdHRlbnVhdGlvbkRpc3RhbmNlID0ganNvbi5hdHRlbnVhdGlvbkRpc3RhbmNlO1xyXG5cdFx0aWYgKCBqc29uLmF0dGVudWF0aW9uQ29sb3IgIT09IHVuZGVmaW5lZCAmJiBtYXRlcmlhbC5hdHRlbnVhdGlvbkNvbG9yICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5hdHRlbnVhdGlvbkNvbG9yLnNldEhleCgganNvbi5hdHRlbnVhdGlvbkNvbG9yICk7XHJcblx0XHRpZiAoIGpzb24uYW5pc290cm9weSAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuYW5pc290cm9weSA9IGpzb24uYW5pc290cm9weTtcclxuXHRcdGlmICgganNvbi5hbmlzb3Ryb3B5Um90YXRpb24gIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmFuaXNvdHJvcHlSb3RhdGlvbiA9IGpzb24uYW5pc290cm9weVJvdGF0aW9uO1xyXG5cdFx0aWYgKCBqc29uLmZvZyAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuZm9nID0ganNvbi5mb2c7XHJcblx0XHRpZiAoIGpzb24uZmxhdFNoYWRpbmcgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmZsYXRTaGFkaW5nID0ganNvbi5mbGF0U2hhZGluZztcclxuXHRcdGlmICgganNvbi5ibGVuZGluZyAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuYmxlbmRpbmcgPSBqc29uLmJsZW5kaW5nO1xyXG5cdFx0aWYgKCBqc29uLmNvbWJpbmUgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmNvbWJpbmUgPSBqc29uLmNvbWJpbmU7XHJcblx0XHRpZiAoIGpzb24uc2lkZSAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuc2lkZSA9IGpzb24uc2lkZTtcclxuXHRcdGlmICgganNvbi5zaGFkb3dTaWRlICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5zaGFkb3dTaWRlID0ganNvbi5zaGFkb3dTaWRlO1xyXG5cdFx0aWYgKCBqc29uLm9wYWNpdHkgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLm9wYWNpdHkgPSBqc29uLm9wYWNpdHk7XHJcblx0XHRpZiAoIGpzb24udHJhbnNwYXJlbnQgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnRyYW5zcGFyZW50ID0ganNvbi50cmFuc3BhcmVudDtcclxuXHRcdGlmICgganNvbi5hbHBoYVRlc3QgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmFscGhhVGVzdCA9IGpzb24uYWxwaGFUZXN0O1xyXG5cdFx0aWYgKCBqc29uLmFscGhhSGFzaCAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuYWxwaGFIYXNoID0ganNvbi5hbHBoYUhhc2g7XHJcblx0XHRpZiAoIGpzb24uZGVwdGhGdW5jICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5kZXB0aEZ1bmMgPSBqc29uLmRlcHRoRnVuYztcclxuXHRcdGlmICgganNvbi5kZXB0aFRlc3QgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmRlcHRoVGVzdCA9IGpzb24uZGVwdGhUZXN0O1xyXG5cdFx0aWYgKCBqc29uLmRlcHRoV3JpdGUgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmRlcHRoV3JpdGUgPSBqc29uLmRlcHRoV3JpdGU7XHJcblx0XHRpZiAoIGpzb24uY29sb3JXcml0ZSAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuY29sb3JXcml0ZSA9IGpzb24uY29sb3JXcml0ZTtcclxuXHRcdGlmICgganNvbi5ibGVuZFNyYyAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuYmxlbmRTcmMgPSBqc29uLmJsZW5kU3JjO1xyXG5cdFx0aWYgKCBqc29uLmJsZW5kRHN0ICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5ibGVuZERzdCA9IGpzb24uYmxlbmREc3Q7XHJcblx0XHRpZiAoIGpzb24uYmxlbmRFcXVhdGlvbiAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuYmxlbmRFcXVhdGlvbiA9IGpzb24uYmxlbmRFcXVhdGlvbjtcclxuXHRcdGlmICgganNvbi5ibGVuZFNyY0FscGhhICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5ibGVuZFNyY0FscGhhID0ganNvbi5ibGVuZFNyY0FscGhhO1xyXG5cdFx0aWYgKCBqc29uLmJsZW5kRHN0QWxwaGEgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmJsZW5kRHN0QWxwaGEgPSBqc29uLmJsZW5kRHN0QWxwaGE7XHJcblx0XHRpZiAoIGpzb24uYmxlbmRFcXVhdGlvbkFscGhhICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5ibGVuZEVxdWF0aW9uQWxwaGEgPSBqc29uLmJsZW5kRXF1YXRpb25BbHBoYTtcclxuXHRcdGlmICgganNvbi5ibGVuZENvbG9yICE9PSB1bmRlZmluZWQgJiYgbWF0ZXJpYWwuYmxlbmRDb2xvciAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuYmxlbmRDb2xvci5zZXRIZXgoIGpzb24uYmxlbmRDb2xvciApO1xyXG5cdFx0aWYgKCBqc29uLmJsZW5kQWxwaGEgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmJsZW5kQWxwaGEgPSBqc29uLmJsZW5kQWxwaGE7XHJcblx0XHRpZiAoIGpzb24uc3RlbmNpbFdyaXRlTWFzayAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuc3RlbmNpbFdyaXRlTWFzayA9IGpzb24uc3RlbmNpbFdyaXRlTWFzaztcclxuXHRcdGlmICgganNvbi5zdGVuY2lsRnVuYyAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuc3RlbmNpbEZ1bmMgPSBqc29uLnN0ZW5jaWxGdW5jO1xyXG5cdFx0aWYgKCBqc29uLnN0ZW5jaWxSZWYgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnN0ZW5jaWxSZWYgPSBqc29uLnN0ZW5jaWxSZWY7XHJcblx0XHRpZiAoIGpzb24uc3RlbmNpbEZ1bmNNYXNrICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5zdGVuY2lsRnVuY01hc2sgPSBqc29uLnN0ZW5jaWxGdW5jTWFzaztcclxuXHRcdGlmICgganNvbi5zdGVuY2lsRmFpbCAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuc3RlbmNpbEZhaWwgPSBqc29uLnN0ZW5jaWxGYWlsO1xyXG5cdFx0aWYgKCBqc29uLnN0ZW5jaWxaRmFpbCAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuc3RlbmNpbFpGYWlsID0ganNvbi5zdGVuY2lsWkZhaWw7XHJcblx0XHRpZiAoIGpzb24uc3RlbmNpbFpQYXNzICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5zdGVuY2lsWlBhc3MgPSBqc29uLnN0ZW5jaWxaUGFzcztcclxuXHRcdGlmICgganNvbi5zdGVuY2lsV3JpdGUgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnN0ZW5jaWxXcml0ZSA9IGpzb24uc3RlbmNpbFdyaXRlO1xyXG5cclxuXHRcdGlmICgganNvbi53aXJlZnJhbWUgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLndpcmVmcmFtZSA9IGpzb24ud2lyZWZyYW1lO1xyXG5cdFx0aWYgKCBqc29uLndpcmVmcmFtZUxpbmV3aWR0aCAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwud2lyZWZyYW1lTGluZXdpZHRoID0ganNvbi53aXJlZnJhbWVMaW5ld2lkdGg7XHJcblx0XHRpZiAoIGpzb24ud2lyZWZyYW1lTGluZWNhcCAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwud2lyZWZyYW1lTGluZWNhcCA9IGpzb24ud2lyZWZyYW1lTGluZWNhcDtcclxuXHRcdGlmICgganNvbi53aXJlZnJhbWVMaW5lam9pbiAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwud2lyZWZyYW1lTGluZWpvaW4gPSBqc29uLndpcmVmcmFtZUxpbmVqb2luO1xyXG5cclxuXHRcdGlmICgganNvbi5yb3RhdGlvbiAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwucm90YXRpb24gPSBqc29uLnJvdGF0aW9uO1xyXG5cclxuXHRcdGlmICgganNvbi5saW5ld2lkdGggIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmxpbmV3aWR0aCA9IGpzb24ubGluZXdpZHRoO1xyXG5cdFx0aWYgKCBqc29uLmRhc2hTaXplICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5kYXNoU2l6ZSA9IGpzb24uZGFzaFNpemU7XHJcblx0XHRpZiAoIGpzb24uZ2FwU2l6ZSAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuZ2FwU2l6ZSA9IGpzb24uZ2FwU2l6ZTtcclxuXHRcdGlmICgganNvbi5zY2FsZSAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuc2NhbGUgPSBqc29uLnNjYWxlO1xyXG5cclxuXHRcdGlmICgganNvbi5wb2x5Z29uT2Zmc2V0ICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5wb2x5Z29uT2Zmc2V0ID0ganNvbi5wb2x5Z29uT2Zmc2V0O1xyXG5cdFx0aWYgKCBqc29uLnBvbHlnb25PZmZzZXRGYWN0b3IgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnBvbHlnb25PZmZzZXRGYWN0b3IgPSBqc29uLnBvbHlnb25PZmZzZXRGYWN0b3I7XHJcblx0XHRpZiAoIGpzb24ucG9seWdvbk9mZnNldFVuaXRzICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5wb2x5Z29uT2Zmc2V0VW5pdHMgPSBqc29uLnBvbHlnb25PZmZzZXRVbml0cztcclxuXHJcblx0XHRpZiAoIGpzb24uZGl0aGVyaW5nICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5kaXRoZXJpbmcgPSBqc29uLmRpdGhlcmluZztcclxuXHJcblx0XHRpZiAoIGpzb24uYWxwaGFUb0NvdmVyYWdlICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5hbHBoYVRvQ292ZXJhZ2UgPSBqc29uLmFscGhhVG9Db3ZlcmFnZTtcclxuXHRcdGlmICgganNvbi5wcmVtdWx0aXBsaWVkQWxwaGEgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnByZW11bHRpcGxpZWRBbHBoYSA9IGpzb24ucHJlbXVsdGlwbGllZEFscGhhO1xyXG5cdFx0aWYgKCBqc29uLmZvcmNlU2luZ2xlUGFzcyAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuZm9yY2VTaW5nbGVQYXNzID0ganNvbi5mb3JjZVNpbmdsZVBhc3M7XHJcblxyXG5cdFx0aWYgKCBqc29uLnZpc2libGUgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnZpc2libGUgPSBqc29uLnZpc2libGU7XHJcblxyXG5cdFx0aWYgKCBqc29uLnRvbmVNYXBwZWQgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnRvbmVNYXBwZWQgPSBqc29uLnRvbmVNYXBwZWQ7XHJcblxyXG5cdFx0aWYgKCBqc29uLnVzZXJEYXRhICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC51c2VyRGF0YSA9IGpzb24udXNlckRhdGE7XHJcblxyXG5cdFx0aWYgKCBqc29uLnZlcnRleENvbG9ycyAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0aWYgKCB0eXBlb2YganNvbi52ZXJ0ZXhDb2xvcnMgPT09ICdudW1iZXInICkge1xyXG5cclxuXHRcdFx0XHRtYXRlcmlhbC52ZXJ0ZXhDb2xvcnMgPSAoIGpzb24udmVydGV4Q29sb3JzID4gMCApID8gdHJ1ZSA6IGZhbHNlO1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0bWF0ZXJpYWwudmVydGV4Q29sb3JzID0ganNvbi52ZXJ0ZXhDb2xvcnM7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIFNoYWRlciBNYXRlcmlhbFxyXG5cclxuXHRcdGlmICgganNvbi51bmlmb3JtcyAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0Zm9yICggY29uc3QgbmFtZSBpbiBqc29uLnVuaWZvcm1zICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCB1bmlmb3JtID0ganNvbi51bmlmb3Jtc1sgbmFtZSBdO1xyXG5cclxuXHRcdFx0XHRtYXRlcmlhbC51bmlmb3Jtc1sgbmFtZSBdID0ge307XHJcblxyXG5cdFx0XHRcdHN3aXRjaCAoIHVuaWZvcm0udHlwZSApIHtcclxuXHJcblx0XHRcdFx0XHRjYXNlICd0JzpcclxuXHRcdFx0XHRcdFx0bWF0ZXJpYWwudW5pZm9ybXNbIG5hbWUgXS52YWx1ZSA9IGdldFRleHR1cmUoIHVuaWZvcm0udmFsdWUgKTtcclxuXHRcdFx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRcdFx0Y2FzZSAnYyc6XHJcblx0XHRcdFx0XHRcdG1hdGVyaWFsLnVuaWZvcm1zWyBuYW1lIF0udmFsdWUgPSBuZXcgQ29sb3IoKS5zZXRIZXgoIHVuaWZvcm0udmFsdWUgKTtcclxuXHRcdFx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRcdFx0Y2FzZSAndjInOlxyXG5cdFx0XHRcdFx0XHRtYXRlcmlhbC51bmlmb3Jtc1sgbmFtZSBdLnZhbHVlID0gbmV3IFZlY3RvcjIoKS5mcm9tQXJyYXkoIHVuaWZvcm0udmFsdWUgKTtcclxuXHRcdFx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRcdFx0Y2FzZSAndjMnOlxyXG5cdFx0XHRcdFx0XHRtYXRlcmlhbC51bmlmb3Jtc1sgbmFtZSBdLnZhbHVlID0gbmV3IFZlY3RvcjMoKS5mcm9tQXJyYXkoIHVuaWZvcm0udmFsdWUgKTtcclxuXHRcdFx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRcdFx0Y2FzZSAndjQnOlxyXG5cdFx0XHRcdFx0XHRtYXRlcmlhbC51bmlmb3Jtc1sgbmFtZSBdLnZhbHVlID0gbmV3IFZlY3RvcjQoKS5mcm9tQXJyYXkoIHVuaWZvcm0udmFsdWUgKTtcclxuXHRcdFx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRcdFx0Y2FzZSAnbTMnOlxyXG5cdFx0XHRcdFx0XHRtYXRlcmlhbC51bmlmb3Jtc1sgbmFtZSBdLnZhbHVlID0gbmV3IE1hdHJpeDMoKS5mcm9tQXJyYXkoIHVuaWZvcm0udmFsdWUgKTtcclxuXHRcdFx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRcdFx0Y2FzZSAnbTQnOlxyXG5cdFx0XHRcdFx0XHRtYXRlcmlhbC51bmlmb3Jtc1sgbmFtZSBdLnZhbHVlID0gbmV3IE1hdHJpeDQoKS5mcm9tQXJyYXkoIHVuaWZvcm0udmFsdWUgKTtcclxuXHRcdFx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRcdFx0ZGVmYXVsdDpcclxuXHRcdFx0XHRcdFx0bWF0ZXJpYWwudW5pZm9ybXNbIG5hbWUgXS52YWx1ZSA9IHVuaWZvcm0udmFsdWU7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBqc29uLmRlZmluZXMgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmRlZmluZXMgPSBqc29uLmRlZmluZXM7XHJcblx0XHRpZiAoIGpzb24udmVydGV4U2hhZGVyICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC52ZXJ0ZXhTaGFkZXIgPSBqc29uLnZlcnRleFNoYWRlcjtcclxuXHRcdGlmICgganNvbi5mcmFnbWVudFNoYWRlciAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuZnJhZ21lbnRTaGFkZXIgPSBqc29uLmZyYWdtZW50U2hhZGVyO1xyXG5cdFx0aWYgKCBqc29uLmdsc2xWZXJzaW9uICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5nbHNsVmVyc2lvbiA9IGpzb24uZ2xzbFZlcnNpb247XHJcblxyXG5cdFx0aWYgKCBqc29uLmV4dGVuc2lvbnMgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdGZvciAoIGNvbnN0IGtleSBpbiBqc29uLmV4dGVuc2lvbnMgKSB7XHJcblxyXG5cdFx0XHRcdG1hdGVyaWFsLmV4dGVuc2lvbnNbIGtleSBdID0ganNvbi5leHRlbnNpb25zWyBrZXkgXTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBqc29uLmxpZ2h0cyAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwubGlnaHRzID0ganNvbi5saWdodHM7XHJcblx0XHRpZiAoIGpzb24uY2xpcHBpbmcgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmNsaXBwaW5nID0ganNvbi5jbGlwcGluZztcclxuXHJcblx0XHQvLyBmb3IgUG9pbnRzTWF0ZXJpYWxcclxuXHJcblx0XHRpZiAoIGpzb24uc2l6ZSAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuc2l6ZSA9IGpzb24uc2l6ZTtcclxuXHRcdGlmICgganNvbi5zaXplQXR0ZW51YXRpb24gIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnNpemVBdHRlbnVhdGlvbiA9IGpzb24uc2l6ZUF0dGVudWF0aW9uO1xyXG5cclxuXHRcdC8vIG1hcHNcclxuXHJcblx0XHRpZiAoIGpzb24ubWFwICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5tYXAgPSBnZXRUZXh0dXJlKCBqc29uLm1hcCApO1xyXG5cdFx0aWYgKCBqc29uLm1hdGNhcCAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwubWF0Y2FwID0gZ2V0VGV4dHVyZSgganNvbi5tYXRjYXAgKTtcclxuXHJcblx0XHRpZiAoIGpzb24uYWxwaGFNYXAgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmFscGhhTWFwID0gZ2V0VGV4dHVyZSgganNvbi5hbHBoYU1hcCApO1xyXG5cclxuXHRcdGlmICgganNvbi5idW1wTWFwICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5idW1wTWFwID0gZ2V0VGV4dHVyZSgganNvbi5idW1wTWFwICk7XHJcblx0XHRpZiAoIGpzb24uYnVtcFNjYWxlICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5idW1wU2NhbGUgPSBqc29uLmJ1bXBTY2FsZTtcclxuXHJcblx0XHRpZiAoIGpzb24ubm9ybWFsTWFwICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5ub3JtYWxNYXAgPSBnZXRUZXh0dXJlKCBqc29uLm5vcm1hbE1hcCApO1xyXG5cdFx0aWYgKCBqc29uLm5vcm1hbE1hcFR5cGUgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLm5vcm1hbE1hcFR5cGUgPSBqc29uLm5vcm1hbE1hcFR5cGU7XHJcblx0XHRpZiAoIGpzb24ubm9ybWFsU2NhbGUgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdGxldCBub3JtYWxTY2FsZSA9IGpzb24ubm9ybWFsU2NhbGU7XHJcblxyXG5cdFx0XHRpZiAoIEFycmF5LmlzQXJyYXkoIG5vcm1hbFNjYWxlICkgPT09IGZhbHNlICkge1xyXG5cclxuXHRcdFx0XHQvLyBCbGVuZGVyIGV4cG9ydGVyIHVzZWQgdG8gZXhwb3J0IGEgc2NhbGFyLiBTZWUgIzc0NTlcclxuXHJcblx0XHRcdFx0bm9ybWFsU2NhbGUgPSBbIG5vcm1hbFNjYWxlLCBub3JtYWxTY2FsZSBdO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0bWF0ZXJpYWwubm9ybWFsU2NhbGUgPSBuZXcgVmVjdG9yMigpLmZyb21BcnJheSggbm9ybWFsU2NhbGUgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBqc29uLmRpc3BsYWNlbWVudE1hcCAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuZGlzcGxhY2VtZW50TWFwID0gZ2V0VGV4dHVyZSgganNvbi5kaXNwbGFjZW1lbnRNYXAgKTtcclxuXHRcdGlmICgganNvbi5kaXNwbGFjZW1lbnRTY2FsZSAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuZGlzcGxhY2VtZW50U2NhbGUgPSBqc29uLmRpc3BsYWNlbWVudFNjYWxlO1xyXG5cdFx0aWYgKCBqc29uLmRpc3BsYWNlbWVudEJpYXMgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmRpc3BsYWNlbWVudEJpYXMgPSBqc29uLmRpc3BsYWNlbWVudEJpYXM7XHJcblxyXG5cdFx0aWYgKCBqc29uLnJvdWdobmVzc01hcCAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwucm91Z2huZXNzTWFwID0gZ2V0VGV4dHVyZSgganNvbi5yb3VnaG5lc3NNYXAgKTtcclxuXHRcdGlmICgganNvbi5tZXRhbG5lc3NNYXAgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLm1ldGFsbmVzc01hcCA9IGdldFRleHR1cmUoIGpzb24ubWV0YWxuZXNzTWFwICk7XHJcblxyXG5cdFx0aWYgKCBqc29uLmVtaXNzaXZlTWFwICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5lbWlzc2l2ZU1hcCA9IGdldFRleHR1cmUoIGpzb24uZW1pc3NpdmVNYXAgKTtcclxuXHRcdGlmICgganNvbi5lbWlzc2l2ZUludGVuc2l0eSAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuZW1pc3NpdmVJbnRlbnNpdHkgPSBqc29uLmVtaXNzaXZlSW50ZW5zaXR5O1xyXG5cclxuXHRcdGlmICgganNvbi5zcGVjdWxhck1hcCAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuc3BlY3VsYXJNYXAgPSBnZXRUZXh0dXJlKCBqc29uLnNwZWN1bGFyTWFwICk7XHJcblx0XHRpZiAoIGpzb24uc3BlY3VsYXJJbnRlbnNpdHlNYXAgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnNwZWN1bGFySW50ZW5zaXR5TWFwID0gZ2V0VGV4dHVyZSgganNvbi5zcGVjdWxhckludGVuc2l0eU1hcCApO1xyXG5cdFx0aWYgKCBqc29uLnNwZWN1bGFyQ29sb3JNYXAgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnNwZWN1bGFyQ29sb3JNYXAgPSBnZXRUZXh0dXJlKCBqc29uLnNwZWN1bGFyQ29sb3JNYXAgKTtcclxuXHJcblx0XHRpZiAoIGpzb24uZW52TWFwICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5lbnZNYXAgPSBnZXRUZXh0dXJlKCBqc29uLmVudk1hcCApO1xyXG5cdFx0aWYgKCBqc29uLmVudk1hcEludGVuc2l0eSAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuZW52TWFwSW50ZW5zaXR5ID0ganNvbi5lbnZNYXBJbnRlbnNpdHk7XHJcblxyXG5cdFx0aWYgKCBqc29uLnJlZmxlY3Rpdml0eSAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwucmVmbGVjdGl2aXR5ID0ganNvbi5yZWZsZWN0aXZpdHk7XHJcblx0XHRpZiAoIGpzb24ucmVmcmFjdGlvblJhdGlvICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5yZWZyYWN0aW9uUmF0aW8gPSBqc29uLnJlZnJhY3Rpb25SYXRpbztcclxuXHJcblx0XHRpZiAoIGpzb24ubGlnaHRNYXAgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmxpZ2h0TWFwID0gZ2V0VGV4dHVyZSgganNvbi5saWdodE1hcCApO1xyXG5cdFx0aWYgKCBqc29uLmxpZ2h0TWFwSW50ZW5zaXR5ICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5saWdodE1hcEludGVuc2l0eSA9IGpzb24ubGlnaHRNYXBJbnRlbnNpdHk7XHJcblxyXG5cdFx0aWYgKCBqc29uLmFvTWFwICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5hb01hcCA9IGdldFRleHR1cmUoIGpzb24uYW9NYXAgKTtcclxuXHRcdGlmICgganNvbi5hb01hcEludGVuc2l0eSAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuYW9NYXBJbnRlbnNpdHkgPSBqc29uLmFvTWFwSW50ZW5zaXR5O1xyXG5cclxuXHRcdGlmICgganNvbi5ncmFkaWVudE1hcCAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuZ3JhZGllbnRNYXAgPSBnZXRUZXh0dXJlKCBqc29uLmdyYWRpZW50TWFwICk7XHJcblxyXG5cdFx0aWYgKCBqc29uLmNsZWFyY29hdE1hcCAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuY2xlYXJjb2F0TWFwID0gZ2V0VGV4dHVyZSgganNvbi5jbGVhcmNvYXRNYXAgKTtcclxuXHRcdGlmICgganNvbi5jbGVhcmNvYXRSb3VnaG5lc3NNYXAgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmNsZWFyY29hdFJvdWdobmVzc01hcCA9IGdldFRleHR1cmUoIGpzb24uY2xlYXJjb2F0Um91Z2huZXNzTWFwICk7XHJcblx0XHRpZiAoIGpzb24uY2xlYXJjb2F0Tm9ybWFsTWFwICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5jbGVhcmNvYXROb3JtYWxNYXAgPSBnZXRUZXh0dXJlKCBqc29uLmNsZWFyY29hdE5vcm1hbE1hcCApO1xyXG5cdFx0aWYgKCBqc29uLmNsZWFyY29hdE5vcm1hbFNjYWxlICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5jbGVhcmNvYXROb3JtYWxTY2FsZSA9IG5ldyBWZWN0b3IyKCkuZnJvbUFycmF5KCBqc29uLmNsZWFyY29hdE5vcm1hbFNjYWxlICk7XHJcblxyXG5cdFx0aWYgKCBqc29uLmlyaWRlc2NlbmNlTWFwICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5pcmlkZXNjZW5jZU1hcCA9IGdldFRleHR1cmUoIGpzb24uaXJpZGVzY2VuY2VNYXAgKTtcclxuXHRcdGlmICgganNvbi5pcmlkZXNjZW5jZVRoaWNrbmVzc01hcCAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuaXJpZGVzY2VuY2VUaGlja25lc3NNYXAgPSBnZXRUZXh0dXJlKCBqc29uLmlyaWRlc2NlbmNlVGhpY2tuZXNzTWFwICk7XHJcblxyXG5cdFx0aWYgKCBqc29uLnRyYW5zbWlzc2lvbk1hcCAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwudHJhbnNtaXNzaW9uTWFwID0gZ2V0VGV4dHVyZSgganNvbi50cmFuc21pc3Npb25NYXAgKTtcclxuXHRcdGlmICgganNvbi50aGlja25lc3NNYXAgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnRoaWNrbmVzc01hcCA9IGdldFRleHR1cmUoIGpzb24udGhpY2tuZXNzTWFwICk7XHJcblxyXG5cdFx0aWYgKCBqc29uLmFuaXNvdHJvcHlNYXAgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmFuaXNvdHJvcHlNYXAgPSBnZXRUZXh0dXJlKCBqc29uLmFuaXNvdHJvcHlNYXAgKTtcclxuXHJcblx0XHRpZiAoIGpzb24uc2hlZW5Db2xvck1hcCAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuc2hlZW5Db2xvck1hcCA9IGdldFRleHR1cmUoIGpzb24uc2hlZW5Db2xvck1hcCApO1xyXG5cdFx0aWYgKCBqc29uLnNoZWVuUm91Z2huZXNzTWFwICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5zaGVlblJvdWdobmVzc01hcCA9IGdldFRleHR1cmUoIGpzb24uc2hlZW5Sb3VnaG5lc3NNYXAgKTtcclxuXHJcblx0XHRyZXR1cm4gbWF0ZXJpYWw7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0VGV4dHVyZXMoIHZhbHVlICkge1xyXG5cclxuXHRcdHRoaXMudGV4dHVyZXMgPSB2YWx1ZTtcclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHN0YXRpYyBjcmVhdGVNYXRlcmlhbEZyb21UeXBlKCB0eXBlICkge1xyXG5cclxuXHRcdGNvbnN0IG1hdGVyaWFsTGliID0ge1xyXG5cdFx0XHRTaGFkb3dNYXRlcmlhbCxcclxuXHRcdFx0U3ByaXRlTWF0ZXJpYWwsXHJcblx0XHRcdFJhd1NoYWRlck1hdGVyaWFsLFxyXG5cdFx0XHRTaGFkZXJNYXRlcmlhbCxcclxuXHRcdFx0UG9pbnRzTWF0ZXJpYWwsXHJcblx0XHRcdE1lc2hQaHlzaWNhbE1hdGVyaWFsLFxyXG5cdFx0XHRNZXNoU3RhbmRhcmRNYXRlcmlhbCxcclxuXHRcdFx0TWVzaFBob25nTWF0ZXJpYWwsXHJcblx0XHRcdE1lc2hUb29uTWF0ZXJpYWwsXHJcblx0XHRcdE1lc2hOb3JtYWxNYXRlcmlhbCxcclxuXHRcdFx0TWVzaExhbWJlcnRNYXRlcmlhbCxcclxuXHRcdFx0TWVzaERlcHRoTWF0ZXJpYWwsXHJcblx0XHRcdE1lc2hEaXN0YW5jZU1hdGVyaWFsLFxyXG5cdFx0XHRNZXNoQmFzaWNNYXRlcmlhbCxcclxuXHRcdFx0TWVzaE1hdGNhcE1hdGVyaWFsLFxyXG5cdFx0XHRMaW5lRGFzaGVkTWF0ZXJpYWwsXHJcblx0XHRcdExpbmVCYXNpY01hdGVyaWFsLFxyXG5cdFx0XHRNYXRlcmlhbFxyXG5cdFx0fTtcclxuXHJcblx0XHRyZXR1cm4gbmV3IG1hdGVyaWFsTGliWyB0eXBlIF0oKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgTWF0ZXJpYWxMb2FkZXIgfTtcclxuIiwiY2xhc3MgTG9hZGVyVXRpbHMge1xyXG5cclxuXHRzdGF0aWMgZGVjb2RlVGV4dCggYXJyYXkgKSB7XHJcblxyXG5cdFx0aWYgKCB0eXBlb2YgVGV4dERlY29kZXIgIT09ICd1bmRlZmluZWQnICkge1xyXG5cclxuXHRcdFx0cmV0dXJuIG5ldyBUZXh0RGVjb2RlcigpLmRlY29kZSggYXJyYXkgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gQXZvaWQgdGhlIFN0cmluZy5mcm9tQ2hhckNvZGUuYXBwbHkobnVsbCwgYXJyYXkpIHNob3J0Y3V0LCB3aGljaFxyXG5cdFx0Ly8gdGhyb3dzIGEgXCJtYXhpbXVtIGNhbGwgc3RhY2sgc2l6ZSBleGNlZWRlZFwiIGVycm9yIGZvciBsYXJnZSBhcnJheXMuXHJcblxyXG5cdFx0bGV0IHMgPSAnJztcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gYXJyYXkubGVuZ3RoOyBpIDwgaWw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHQvLyBJbXBsaWNpdGx5IGFzc3VtZXMgbGl0dGxlLWVuZGlhbi5cclxuXHRcdFx0cyArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKCBhcnJheVsgaSBdICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRyeSB7XHJcblxyXG5cdFx0XHQvLyBtZXJnZXMgbXVsdGktYnl0ZSB1dGYtOCBjaGFyYWN0ZXJzLlxyXG5cclxuXHRcdFx0cmV0dXJuIGRlY29kZVVSSUNvbXBvbmVudCggZXNjYXBlKCBzICkgKTtcclxuXHJcblx0XHR9IGNhdGNoICggZSApIHsgLy8gc2VlICMxNjM1OFxyXG5cclxuXHRcdFx0cmV0dXJuIHM7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdHN0YXRpYyBleHRyYWN0VXJsQmFzZSggdXJsICkge1xyXG5cclxuXHRcdGNvbnN0IGluZGV4ID0gdXJsLmxhc3RJbmRleE9mKCAnLycgKTtcclxuXHJcblx0XHRpZiAoIGluZGV4ID09PSAtIDEgKSByZXR1cm4gJy4vJztcclxuXHJcblx0XHRyZXR1cm4gdXJsLnNsaWNlKCAwLCBpbmRleCArIDEgKTtcclxuXHJcblx0fVxyXG5cclxuXHRzdGF0aWMgcmVzb2x2ZVVSTCggdXJsLCBwYXRoICkge1xyXG5cclxuXHRcdC8vIEludmFsaWQgVVJMXHJcblx0XHRpZiAoIHR5cGVvZiB1cmwgIT09ICdzdHJpbmcnIHx8IHVybCA9PT0gJycgKSByZXR1cm4gJyc7XHJcblxyXG5cdFx0Ly8gSG9zdCBSZWxhdGl2ZSBVUkxcclxuXHRcdGlmICggL15odHRwcz86XFwvXFwvL2kudGVzdCggcGF0aCApICYmIC9eXFwvLy50ZXN0KCB1cmwgKSApIHtcclxuXHJcblx0XHRcdHBhdGggPSBwYXRoLnJlcGxhY2UoIC8oXmh0dHBzPzpcXC9cXC9bXlxcL10rKS4qL2ksICckMScgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gQWJzb2x1dGUgVVJMIGh0dHA6Ly8saHR0cHM6Ly8sLy9cclxuXHRcdGlmICggL14oaHR0cHM/Oik/XFwvXFwvL2kudGVzdCggdXJsICkgKSByZXR1cm4gdXJsO1xyXG5cclxuXHRcdC8vIERhdGEgVVJJXHJcblx0XHRpZiAoIC9eZGF0YTouKiwuKiQvaS50ZXN0KCB1cmwgKSApIHJldHVybiB1cmw7XHJcblxyXG5cdFx0Ly8gQmxvYiBVUkxcclxuXHRcdGlmICggL15ibG9iOi4qJC9pLnRlc3QoIHVybCApICkgcmV0dXJuIHVybDtcclxuXHJcblx0XHQvLyBSZWxhdGl2ZSBVUkxcclxuXHRcdHJldHVybiBwYXRoICsgdXJsO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBMb2FkZXJVdGlscyB9O1xyXG4iLCJpbXBvcnQgeyBCdWZmZXJHZW9tZXRyeSB9IGZyb20gJy4vQnVmZmVyR2VvbWV0cnkuanMnO1xyXG5cclxuY2xhc3MgSW5zdGFuY2VkQnVmZmVyR2VvbWV0cnkgZXh0ZW5kcyBCdWZmZXJHZW9tZXRyeSB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCkge1xyXG5cclxuXHRcdHN1cGVyKCk7XHJcblxyXG5cdFx0dGhpcy5pc0luc3RhbmNlZEJ1ZmZlckdlb21ldHJ5ID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSAnSW5zdGFuY2VkQnVmZmVyR2VvbWV0cnknO1xyXG5cdFx0dGhpcy5pbnN0YW5jZUNvdW50ID0gSW5maW5pdHk7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xyXG5cclxuXHRcdHRoaXMuaW5zdGFuY2VDb3VudCA9IHNvdXJjZS5pbnN0YW5jZUNvdW50O1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHRvSlNPTigpIHtcclxuXHJcblx0XHRjb25zdCBkYXRhID0gc3VwZXIudG9KU09OKCk7XHJcblxyXG5cdFx0ZGF0YS5pbnN0YW5jZUNvdW50ID0gdGhpcy5pbnN0YW5jZUNvdW50O1xyXG5cclxuXHRcdGRhdGEuaXNJbnN0YW5jZWRCdWZmZXJHZW9tZXRyeSA9IHRydWU7XHJcblxyXG5cdFx0cmV0dXJuIGRhdGE7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IEluc3RhbmNlZEJ1ZmZlckdlb21ldHJ5IH07XHJcbiIsImltcG9ydCB7IFNwaGVyZSB9IGZyb20gJy4uL21hdGgvU3BoZXJlLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yMyB9IGZyb20gJy4uL21hdGgvVmVjdG9yMy5qcyc7XHJcbmltcG9ydCB7IEJ1ZmZlckF0dHJpYnV0ZSB9IGZyb20gJy4uL2NvcmUvQnVmZmVyQXR0cmlidXRlLmpzJztcclxuaW1wb3J0IHsgQnVmZmVyR2VvbWV0cnkgfSBmcm9tICcuLi9jb3JlL0J1ZmZlckdlb21ldHJ5LmpzJztcclxuaW1wb3J0IHsgRmlsZUxvYWRlciB9IGZyb20gJy4vRmlsZUxvYWRlci5qcyc7XHJcbmltcG9ydCB7IExvYWRlciB9IGZyb20gJy4vTG9hZGVyLmpzJztcclxuaW1wb3J0IHsgSW5zdGFuY2VkQnVmZmVyR2VvbWV0cnkgfSBmcm9tICcuLi9jb3JlL0luc3RhbmNlZEJ1ZmZlckdlb21ldHJ5LmpzJztcclxuaW1wb3J0IHsgSW5zdGFuY2VkQnVmZmVyQXR0cmlidXRlIH0gZnJvbSAnLi4vY29yZS9JbnN0YW5jZWRCdWZmZXJBdHRyaWJ1dGUuanMnO1xyXG5pbXBvcnQgeyBJbnRlcmxlYXZlZEJ1ZmZlckF0dHJpYnV0ZSB9IGZyb20gJy4uL2NvcmUvSW50ZXJsZWF2ZWRCdWZmZXJBdHRyaWJ1dGUuanMnO1xyXG5pbXBvcnQgeyBJbnRlcmxlYXZlZEJ1ZmZlciB9IGZyb20gJy4uL2NvcmUvSW50ZXJsZWF2ZWRCdWZmZXIuanMnO1xyXG5pbXBvcnQgeyBnZXRUeXBlZEFycmF5IH0gZnJvbSAnLi4vdXRpbHMuanMnO1xyXG5cclxuY2xhc3MgQnVmZmVyR2VvbWV0cnlMb2FkZXIgZXh0ZW5kcyBMb2FkZXIge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggbWFuYWdlciApIHtcclxuXHJcblx0XHRzdXBlciggbWFuYWdlciApO1xyXG5cclxuXHR9XHJcblxyXG5cdGxvYWQoIHVybCwgb25Mb2FkLCBvblByb2dyZXNzLCBvbkVycm9yICkge1xyXG5cclxuXHRcdGNvbnN0IHNjb3BlID0gdGhpcztcclxuXHJcblx0XHRjb25zdCBsb2FkZXIgPSBuZXcgRmlsZUxvYWRlciggc2NvcGUubWFuYWdlciApO1xyXG5cdFx0bG9hZGVyLnNldFBhdGgoIHNjb3BlLnBhdGggKTtcclxuXHRcdGxvYWRlci5zZXRSZXF1ZXN0SGVhZGVyKCBzY29wZS5yZXF1ZXN0SGVhZGVyICk7XHJcblx0XHRsb2FkZXIuc2V0V2l0aENyZWRlbnRpYWxzKCBzY29wZS53aXRoQ3JlZGVudGlhbHMgKTtcclxuXHRcdGxvYWRlci5sb2FkKCB1cmwsIGZ1bmN0aW9uICggdGV4dCApIHtcclxuXHJcblx0XHRcdHRyeSB7XHJcblxyXG5cdFx0XHRcdG9uTG9hZCggc2NvcGUucGFyc2UoIEpTT04ucGFyc2UoIHRleHQgKSApICk7XHJcblxyXG5cdFx0XHR9IGNhdGNoICggZSApIHtcclxuXHJcblx0XHRcdFx0aWYgKCBvbkVycm9yICkge1xyXG5cclxuXHRcdFx0XHRcdG9uRXJyb3IoIGUgKTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRjb25zb2xlLmVycm9yKCBlICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0c2NvcGUubWFuYWdlci5pdGVtRXJyb3IoIHVybCApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH0sIG9uUHJvZ3Jlc3MsIG9uRXJyb3IgKTtcclxuXHJcblx0fVxyXG5cclxuXHRwYXJzZSgganNvbiApIHtcclxuXHJcblx0XHRjb25zdCBpbnRlcmxlYXZlZEJ1ZmZlck1hcCA9IHt9O1xyXG5cdFx0Y29uc3QgYXJyYXlCdWZmZXJNYXAgPSB7fTtcclxuXHJcblx0XHRmdW5jdGlvbiBnZXRJbnRlcmxlYXZlZEJ1ZmZlcigganNvbiwgdXVpZCApIHtcclxuXHJcblx0XHRcdGlmICggaW50ZXJsZWF2ZWRCdWZmZXJNYXBbIHV1aWQgXSAhPT0gdW5kZWZpbmVkICkgcmV0dXJuIGludGVybGVhdmVkQnVmZmVyTWFwWyB1dWlkIF07XHJcblxyXG5cdFx0XHRjb25zdCBpbnRlcmxlYXZlZEJ1ZmZlcnMgPSBqc29uLmludGVybGVhdmVkQnVmZmVycztcclxuXHRcdFx0Y29uc3QgaW50ZXJsZWF2ZWRCdWZmZXIgPSBpbnRlcmxlYXZlZEJ1ZmZlcnNbIHV1aWQgXTtcclxuXHJcblx0XHRcdGNvbnN0IGJ1ZmZlciA9IGdldEFycmF5QnVmZmVyKCBqc29uLCBpbnRlcmxlYXZlZEJ1ZmZlci5idWZmZXIgKTtcclxuXHJcblx0XHRcdGNvbnN0IGFycmF5ID0gZ2V0VHlwZWRBcnJheSggaW50ZXJsZWF2ZWRCdWZmZXIudHlwZSwgYnVmZmVyICk7XHJcblx0XHRcdGNvbnN0IGliID0gbmV3IEludGVybGVhdmVkQnVmZmVyKCBhcnJheSwgaW50ZXJsZWF2ZWRCdWZmZXIuc3RyaWRlICk7XHJcblx0XHRcdGliLnV1aWQgPSBpbnRlcmxlYXZlZEJ1ZmZlci51dWlkO1xyXG5cclxuXHRcdFx0aW50ZXJsZWF2ZWRCdWZmZXJNYXBbIHV1aWQgXSA9IGliO1xyXG5cclxuXHRcdFx0cmV0dXJuIGliO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRmdW5jdGlvbiBnZXRBcnJheUJ1ZmZlcigganNvbiwgdXVpZCApIHtcclxuXHJcblx0XHRcdGlmICggYXJyYXlCdWZmZXJNYXBbIHV1aWQgXSAhPT0gdW5kZWZpbmVkICkgcmV0dXJuIGFycmF5QnVmZmVyTWFwWyB1dWlkIF07XHJcblxyXG5cdFx0XHRjb25zdCBhcnJheUJ1ZmZlcnMgPSBqc29uLmFycmF5QnVmZmVycztcclxuXHRcdFx0Y29uc3QgYXJyYXlCdWZmZXIgPSBhcnJheUJ1ZmZlcnNbIHV1aWQgXTtcclxuXHJcblx0XHRcdGNvbnN0IGFiID0gbmV3IFVpbnQzMkFycmF5KCBhcnJheUJ1ZmZlciApLmJ1ZmZlcjtcclxuXHJcblx0XHRcdGFycmF5QnVmZmVyTWFwWyB1dWlkIF0gPSBhYjtcclxuXHJcblx0XHRcdHJldHVybiBhYjtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Y29uc3QgZ2VvbWV0cnkgPSBqc29uLmlzSW5zdGFuY2VkQnVmZmVyR2VvbWV0cnkgPyBuZXcgSW5zdGFuY2VkQnVmZmVyR2VvbWV0cnkoKSA6IG5ldyBCdWZmZXJHZW9tZXRyeSgpO1xyXG5cclxuXHRcdGNvbnN0IGluZGV4ID0ganNvbi5kYXRhLmluZGV4O1xyXG5cclxuXHRcdGlmICggaW5kZXggIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdGNvbnN0IHR5cGVkQXJyYXkgPSBnZXRUeXBlZEFycmF5KCBpbmRleC50eXBlLCBpbmRleC5hcnJheSApO1xyXG5cdFx0XHRnZW9tZXRyeS5zZXRJbmRleCggbmV3IEJ1ZmZlckF0dHJpYnV0ZSggdHlwZWRBcnJheSwgMSApICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGNvbnN0IGF0dHJpYnV0ZXMgPSBqc29uLmRhdGEuYXR0cmlidXRlcztcclxuXHJcblx0XHRmb3IgKCBjb25zdCBrZXkgaW4gYXR0cmlidXRlcyApIHtcclxuXHJcblx0XHRcdGNvbnN0IGF0dHJpYnV0ZSA9IGF0dHJpYnV0ZXNbIGtleSBdO1xyXG5cdFx0XHRsZXQgYnVmZmVyQXR0cmlidXRlO1xyXG5cclxuXHRcdFx0aWYgKCBhdHRyaWJ1dGUuaXNJbnRlcmxlYXZlZEJ1ZmZlckF0dHJpYnV0ZSApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgaW50ZXJsZWF2ZWRCdWZmZXIgPSBnZXRJbnRlcmxlYXZlZEJ1ZmZlcigganNvbi5kYXRhLCBhdHRyaWJ1dGUuZGF0YSApO1xyXG5cdFx0XHRcdGJ1ZmZlckF0dHJpYnV0ZSA9IG5ldyBJbnRlcmxlYXZlZEJ1ZmZlckF0dHJpYnV0ZSggaW50ZXJsZWF2ZWRCdWZmZXIsIGF0dHJpYnV0ZS5pdGVtU2l6ZSwgYXR0cmlidXRlLm9mZnNldCwgYXR0cmlidXRlLm5vcm1hbGl6ZWQgKTtcclxuXHJcblx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IHR5cGVkQXJyYXkgPSBnZXRUeXBlZEFycmF5KCBhdHRyaWJ1dGUudHlwZSwgYXR0cmlidXRlLmFycmF5ICk7XHJcblx0XHRcdFx0Y29uc3QgYnVmZmVyQXR0cmlidXRlQ29uc3RyID0gYXR0cmlidXRlLmlzSW5zdGFuY2VkQnVmZmVyQXR0cmlidXRlID8gSW5zdGFuY2VkQnVmZmVyQXR0cmlidXRlIDogQnVmZmVyQXR0cmlidXRlO1xyXG5cdFx0XHRcdGJ1ZmZlckF0dHJpYnV0ZSA9IG5ldyBidWZmZXJBdHRyaWJ1dGVDb25zdHIoIHR5cGVkQXJyYXksIGF0dHJpYnV0ZS5pdGVtU2l6ZSwgYXR0cmlidXRlLm5vcm1hbGl6ZWQgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGlmICggYXR0cmlidXRlLm5hbWUgIT09IHVuZGVmaW5lZCApIGJ1ZmZlckF0dHJpYnV0ZS5uYW1lID0gYXR0cmlidXRlLm5hbWU7XHJcblx0XHRcdGlmICggYXR0cmlidXRlLnVzYWdlICE9PSB1bmRlZmluZWQgKSBidWZmZXJBdHRyaWJ1dGUuc2V0VXNhZ2UoIGF0dHJpYnV0ZS51c2FnZSApO1xyXG5cclxuXHRcdFx0Z2VvbWV0cnkuc2V0QXR0cmlidXRlKCBrZXksIGJ1ZmZlckF0dHJpYnV0ZSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCBtb3JwaEF0dHJpYnV0ZXMgPSBqc29uLmRhdGEubW9ycGhBdHRyaWJ1dGVzO1xyXG5cclxuXHRcdGlmICggbW9ycGhBdHRyaWJ1dGVzICkge1xyXG5cclxuXHRcdFx0Zm9yICggY29uc3Qga2V5IGluIG1vcnBoQXR0cmlidXRlcyApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgYXR0cmlidXRlQXJyYXkgPSBtb3JwaEF0dHJpYnV0ZXNbIGtleSBdO1xyXG5cclxuXHRcdFx0XHRjb25zdCBhcnJheSA9IFtdO1xyXG5cclxuXHRcdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gYXR0cmlidXRlQXJyYXkubGVuZ3RoOyBpIDwgaWw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgYXR0cmlidXRlID0gYXR0cmlidXRlQXJyYXlbIGkgXTtcclxuXHRcdFx0XHRcdGxldCBidWZmZXJBdHRyaWJ1dGU7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCBhdHRyaWJ1dGUuaXNJbnRlcmxlYXZlZEJ1ZmZlckF0dHJpYnV0ZSApIHtcclxuXHJcblx0XHRcdFx0XHRcdGNvbnN0IGludGVybGVhdmVkQnVmZmVyID0gZ2V0SW50ZXJsZWF2ZWRCdWZmZXIoIGpzb24uZGF0YSwgYXR0cmlidXRlLmRhdGEgKTtcclxuXHRcdFx0XHRcdFx0YnVmZmVyQXR0cmlidXRlID0gbmV3IEludGVybGVhdmVkQnVmZmVyQXR0cmlidXRlKCBpbnRlcmxlYXZlZEJ1ZmZlciwgYXR0cmlidXRlLml0ZW1TaXplLCBhdHRyaWJ1dGUub2Zmc2V0LCBhdHRyaWJ1dGUubm9ybWFsaXplZCApO1xyXG5cclxuXHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHRjb25zdCB0eXBlZEFycmF5ID0gZ2V0VHlwZWRBcnJheSggYXR0cmlidXRlLnR5cGUsIGF0dHJpYnV0ZS5hcnJheSApO1xyXG5cdFx0XHRcdFx0XHRidWZmZXJBdHRyaWJ1dGUgPSBuZXcgQnVmZmVyQXR0cmlidXRlKCB0eXBlZEFycmF5LCBhdHRyaWJ1dGUuaXRlbVNpemUsIGF0dHJpYnV0ZS5ub3JtYWxpemVkICk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdGlmICggYXR0cmlidXRlLm5hbWUgIT09IHVuZGVmaW5lZCApIGJ1ZmZlckF0dHJpYnV0ZS5uYW1lID0gYXR0cmlidXRlLm5hbWU7XHJcblx0XHRcdFx0XHRhcnJheS5wdXNoKCBidWZmZXJBdHRyaWJ1dGUgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRnZW9tZXRyeS5tb3JwaEF0dHJpYnV0ZXNbIGtleSBdID0gYXJyYXk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGNvbnN0IG1vcnBoVGFyZ2V0c1JlbGF0aXZlID0ganNvbi5kYXRhLm1vcnBoVGFyZ2V0c1JlbGF0aXZlO1xyXG5cclxuXHRcdGlmICggbW9ycGhUYXJnZXRzUmVsYXRpdmUgKSB7XHJcblxyXG5cdFx0XHRnZW9tZXRyeS5tb3JwaFRhcmdldHNSZWxhdGl2ZSA9IHRydWU7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGNvbnN0IGdyb3VwcyA9IGpzb24uZGF0YS5ncm91cHMgfHwganNvbi5kYXRhLmRyYXdjYWxscyB8fCBqc29uLmRhdGEub2Zmc2V0cztcclxuXHJcblx0XHRpZiAoIGdyb3VwcyAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGkgPSAwLCBuID0gZ3JvdXBzLmxlbmd0aDsgaSAhPT0gbjsgKysgaSApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgZ3JvdXAgPSBncm91cHNbIGkgXTtcclxuXHJcblx0XHRcdFx0Z2VvbWV0cnkuYWRkR3JvdXAoIGdyb3VwLnN0YXJ0LCBncm91cC5jb3VudCwgZ3JvdXAubWF0ZXJpYWxJbmRleCApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCBib3VuZGluZ1NwaGVyZSA9IGpzb24uZGF0YS5ib3VuZGluZ1NwaGVyZTtcclxuXHJcblx0XHRpZiAoIGJvdW5kaW5nU3BoZXJlICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBjZW50ZXIgPSBuZXcgVmVjdG9yMygpO1xyXG5cclxuXHRcdFx0aWYgKCBib3VuZGluZ1NwaGVyZS5jZW50ZXIgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0Y2VudGVyLmZyb21BcnJheSggYm91bmRpbmdTcGhlcmUuY2VudGVyICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRnZW9tZXRyeS5ib3VuZGluZ1NwaGVyZSA9IG5ldyBTcGhlcmUoIGNlbnRlciwgYm91bmRpbmdTcGhlcmUucmFkaXVzICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICgganNvbi5uYW1lICkgZ2VvbWV0cnkubmFtZSA9IGpzb24ubmFtZTtcclxuXHRcdGlmICgganNvbi51c2VyRGF0YSApIGdlb21ldHJ5LnVzZXJEYXRhID0ganNvbi51c2VyRGF0YTtcclxuXHJcblx0XHRyZXR1cm4gZ2VvbWV0cnk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IEJ1ZmZlckdlb21ldHJ5TG9hZGVyIH07XHJcbiIsImltcG9ydCB7XHJcblx0VVZNYXBwaW5nLFxyXG5cdEN1YmVSZWZsZWN0aW9uTWFwcGluZyxcclxuXHRDdWJlUmVmcmFjdGlvbk1hcHBpbmcsXHJcblx0RXF1aXJlY3Rhbmd1bGFyUmVmbGVjdGlvbk1hcHBpbmcsXHJcblx0RXF1aXJlY3Rhbmd1bGFyUmVmcmFjdGlvbk1hcHBpbmcsXHJcblx0Q3ViZVVWUmVmbGVjdGlvbk1hcHBpbmcsXHJcblxyXG5cdFJlcGVhdFdyYXBwaW5nLFxyXG5cdENsYW1wVG9FZGdlV3JhcHBpbmcsXHJcblx0TWlycm9yZWRSZXBlYXRXcmFwcGluZyxcclxuXHJcblx0TmVhcmVzdEZpbHRlcixcclxuXHROZWFyZXN0TWlwbWFwTmVhcmVzdEZpbHRlcixcclxuXHROZWFyZXN0TWlwbWFwTGluZWFyRmlsdGVyLFxyXG5cdExpbmVhckZpbHRlcixcclxuXHRMaW5lYXJNaXBtYXBOZWFyZXN0RmlsdGVyLFxyXG5cdExpbmVhck1pcG1hcExpbmVhckZpbHRlclxyXG59IGZyb20gJy4uL2NvbnN0YW50cy5qcyc7XHJcbmltcG9ydCB7IEluc3RhbmNlZEJ1ZmZlckF0dHJpYnV0ZSB9IGZyb20gJy4uL2NvcmUvSW5zdGFuY2VkQnVmZmVyQXR0cmlidXRlLmpzJztcclxuaW1wb3J0IHsgQ29sb3IgfSBmcm9tICcuLi9tYXRoL0NvbG9yLmpzJztcclxuaW1wb3J0IHsgT2JqZWN0M0QgfSBmcm9tICcuLi9jb3JlL09iamVjdDNELmpzJztcclxuaW1wb3J0IHsgR3JvdXAgfSBmcm9tICcuLi9vYmplY3RzL0dyb3VwLmpzJztcclxuaW1wb3J0IHsgSW5zdGFuY2VkTWVzaCB9IGZyb20gJy4uL29iamVjdHMvSW5zdGFuY2VkTWVzaC5qcyc7XHJcbmltcG9ydCB7IEJhdGNoZWRNZXNoIH0gZnJvbSAnLi4vb2JqZWN0cy9CYXRjaGVkTWVzaC5qcyc7XHJcbmltcG9ydCB7IFNwcml0ZSB9IGZyb20gJy4uL29iamVjdHMvU3ByaXRlLmpzJztcclxuaW1wb3J0IHsgUG9pbnRzIH0gZnJvbSAnLi4vb2JqZWN0cy9Qb2ludHMuanMnO1xyXG5pbXBvcnQgeyBMaW5lIH0gZnJvbSAnLi4vb2JqZWN0cy9MaW5lLmpzJztcclxuaW1wb3J0IHsgTGluZUxvb3AgfSBmcm9tICcuLi9vYmplY3RzL0xpbmVMb29wLmpzJztcclxuaW1wb3J0IHsgTGluZVNlZ21lbnRzIH0gZnJvbSAnLi4vb2JqZWN0cy9MaW5lU2VnbWVudHMuanMnO1xyXG5pbXBvcnQgeyBMT0QgfSBmcm9tICcuLi9vYmplY3RzL0xPRC5qcyc7XHJcbmltcG9ydCB7IE1lc2ggfSBmcm9tICcuLi9vYmplY3RzL01lc2guanMnO1xyXG5pbXBvcnQgeyBTa2lubmVkTWVzaCB9IGZyb20gJy4uL29iamVjdHMvU2tpbm5lZE1lc2guanMnO1xyXG5pbXBvcnQgeyBCb25lIH0gZnJvbSAnLi4vb2JqZWN0cy9Cb25lLmpzJztcclxuaW1wb3J0IHsgU2tlbGV0b24gfSBmcm9tICcuLi9vYmplY3RzL1NrZWxldG9uLmpzJztcclxuaW1wb3J0IHsgU2hhcGUgfSBmcm9tICcuLi9leHRyYXMvY29yZS9TaGFwZS5qcyc7XHJcbmltcG9ydCB7IEZvZyB9IGZyb20gJy4uL3NjZW5lcy9Gb2cuanMnO1xyXG5pbXBvcnQgeyBGb2dFeHAyIH0gZnJvbSAnLi4vc2NlbmVzL0ZvZ0V4cDIuanMnO1xyXG5pbXBvcnQgeyBIZW1pc3BoZXJlTGlnaHQgfSBmcm9tICcuLi9saWdodHMvSGVtaXNwaGVyZUxpZ2h0LmpzJztcclxuaW1wb3J0IHsgU3BvdExpZ2h0IH0gZnJvbSAnLi4vbGlnaHRzL1Nwb3RMaWdodC5qcyc7XHJcbmltcG9ydCB7IFBvaW50TGlnaHQgfSBmcm9tICcuLi9saWdodHMvUG9pbnRMaWdodC5qcyc7XHJcbmltcG9ydCB7IERpcmVjdGlvbmFsTGlnaHQgfSBmcm9tICcuLi9saWdodHMvRGlyZWN0aW9uYWxMaWdodC5qcyc7XHJcbmltcG9ydCB7IEFtYmllbnRMaWdodCB9IGZyb20gJy4uL2xpZ2h0cy9BbWJpZW50TGlnaHQuanMnO1xyXG5pbXBvcnQgeyBSZWN0QXJlYUxpZ2h0IH0gZnJvbSAnLi4vbGlnaHRzL1JlY3RBcmVhTGlnaHQuanMnO1xyXG5pbXBvcnQgeyBMaWdodFByb2JlIH0gZnJvbSAnLi4vbGlnaHRzL0xpZ2h0UHJvYmUuanMnO1xyXG5pbXBvcnQgeyBPcnRob2dyYXBoaWNDYW1lcmEgfSBmcm9tICcuLi9jYW1lcmFzL09ydGhvZ3JhcGhpY0NhbWVyYS5qcyc7XHJcbmltcG9ydCB7IFBlcnNwZWN0aXZlQ2FtZXJhIH0gZnJvbSAnLi4vY2FtZXJhcy9QZXJzcGVjdGl2ZUNhbWVyYS5qcyc7XHJcbmltcG9ydCB7IFNjZW5lIH0gZnJvbSAnLi4vc2NlbmVzL1NjZW5lLmpzJztcclxuaW1wb3J0IHsgQ3ViZVRleHR1cmUgfSBmcm9tICcuLi90ZXh0dXJlcy9DdWJlVGV4dHVyZS5qcyc7XHJcbmltcG9ydCB7IFRleHR1cmUgfSBmcm9tICcuLi90ZXh0dXJlcy9UZXh0dXJlLmpzJztcclxuaW1wb3J0IHsgU291cmNlIH0gZnJvbSAnLi4vdGV4dHVyZXMvU291cmNlLmpzJztcclxuaW1wb3J0IHsgRGF0YVRleHR1cmUgfSBmcm9tICcuLi90ZXh0dXJlcy9EYXRhVGV4dHVyZS5qcyc7XHJcbmltcG9ydCB7IEltYWdlTG9hZGVyIH0gZnJvbSAnLi9JbWFnZUxvYWRlci5qcyc7XHJcbmltcG9ydCB7IExvYWRpbmdNYW5hZ2VyIH0gZnJvbSAnLi9Mb2FkaW5nTWFuYWdlci5qcyc7XHJcbmltcG9ydCB7IEFuaW1hdGlvbkNsaXAgfSBmcm9tICcuLi9hbmltYXRpb24vQW5pbWF0aW9uQ2xpcC5qcyc7XHJcbmltcG9ydCB7IE1hdGVyaWFsTG9hZGVyIH0gZnJvbSAnLi9NYXRlcmlhbExvYWRlci5qcyc7XHJcbmltcG9ydCB7IExvYWRlclV0aWxzIH0gZnJvbSAnLi9Mb2FkZXJVdGlscy5qcyc7XHJcbmltcG9ydCB7IEJ1ZmZlckdlb21ldHJ5TG9hZGVyIH0gZnJvbSAnLi9CdWZmZXJHZW9tZXRyeUxvYWRlci5qcyc7XHJcbmltcG9ydCB7IExvYWRlciB9IGZyb20gJy4vTG9hZGVyLmpzJztcclxuaW1wb3J0IHsgRmlsZUxvYWRlciB9IGZyb20gJy4vRmlsZUxvYWRlci5qcyc7XHJcbmltcG9ydCAqIGFzIEdlb21ldHJpZXMgZnJvbSAnLi4vZ2VvbWV0cmllcy9HZW9tZXRyaWVzLmpzJztcclxuaW1wb3J0IHsgZ2V0VHlwZWRBcnJheSB9IGZyb20gJy4uL3V0aWxzLmpzJztcclxuaW1wb3J0IHsgQm94MyB9IGZyb20gJy4uL21hdGgvQm94My5qcyc7XHJcbmltcG9ydCB7IFNwaGVyZSB9IGZyb20gJy4uL21hdGgvU3BoZXJlLmpzJztcclxuXHJcbmNsYXNzIE9iamVjdExvYWRlciBleHRlbmRzIExvYWRlciB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBtYW5hZ2VyICkge1xyXG5cclxuXHRcdHN1cGVyKCBtYW5hZ2VyICk7XHJcblxyXG5cdH1cclxuXHJcblx0bG9hZCggdXJsLCBvbkxvYWQsIG9uUHJvZ3Jlc3MsIG9uRXJyb3IgKSB7XHJcblxyXG5cdFx0Y29uc3Qgc2NvcGUgPSB0aGlzO1xyXG5cclxuXHRcdGNvbnN0IHBhdGggPSAoIHRoaXMucGF0aCA9PT0gJycgKSA/IExvYWRlclV0aWxzLmV4dHJhY3RVcmxCYXNlKCB1cmwgKSA6IHRoaXMucGF0aDtcclxuXHRcdHRoaXMucmVzb3VyY2VQYXRoID0gdGhpcy5yZXNvdXJjZVBhdGggfHwgcGF0aDtcclxuXHJcblx0XHRjb25zdCBsb2FkZXIgPSBuZXcgRmlsZUxvYWRlciggdGhpcy5tYW5hZ2VyICk7XHJcblx0XHRsb2FkZXIuc2V0UGF0aCggdGhpcy5wYXRoICk7XHJcblx0XHRsb2FkZXIuc2V0UmVxdWVzdEhlYWRlciggdGhpcy5yZXF1ZXN0SGVhZGVyICk7XHJcblx0XHRsb2FkZXIuc2V0V2l0aENyZWRlbnRpYWxzKCB0aGlzLndpdGhDcmVkZW50aWFscyApO1xyXG5cdFx0bG9hZGVyLmxvYWQoIHVybCwgZnVuY3Rpb24gKCB0ZXh0ICkge1xyXG5cclxuXHRcdFx0bGV0IGpzb24gPSBudWxsO1xyXG5cclxuXHRcdFx0dHJ5IHtcclxuXHJcblx0XHRcdFx0anNvbiA9IEpTT04ucGFyc2UoIHRleHQgKTtcclxuXHJcblx0XHRcdH0gY2F0Y2ggKCBlcnJvciApIHtcclxuXHJcblx0XHRcdFx0aWYgKCBvbkVycm9yICE9PSB1bmRlZmluZWQgKSBvbkVycm9yKCBlcnJvciApO1xyXG5cclxuXHRcdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUU6T2JqZWN0TG9hZGVyOiBDYW5cXCd0IHBhcnNlICcgKyB1cmwgKyAnLicsIGVycm9yLm1lc3NhZ2UgKTtcclxuXHJcblx0XHRcdFx0cmV0dXJuO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Y29uc3QgbWV0YWRhdGEgPSBqc29uLm1ldGFkYXRhO1xyXG5cclxuXHRcdFx0aWYgKCBtZXRhZGF0YSA9PT0gdW5kZWZpbmVkIHx8IG1ldGFkYXRhLnR5cGUgPT09IHVuZGVmaW5lZCB8fCBtZXRhZGF0YS50eXBlLnRvTG93ZXJDYXNlKCkgPT09ICdnZW9tZXRyeScgKSB7XHJcblxyXG5cdFx0XHRcdGlmICggb25FcnJvciAhPT0gdW5kZWZpbmVkICkgb25FcnJvciggbmV3IEVycm9yKCAnVEhSRUUuT2JqZWN0TG9hZGVyOiBDYW5cXCd0IGxvYWQgJyArIHVybCApICk7XHJcblxyXG5cdFx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5PYmplY3RMb2FkZXI6IENhblxcJ3QgbG9hZCAnICsgdXJsICk7XHJcblx0XHRcdFx0cmV0dXJuO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0c2NvcGUucGFyc2UoIGpzb24sIG9uTG9hZCApO1xyXG5cclxuXHRcdH0sIG9uUHJvZ3Jlc3MsIG9uRXJyb3IgKTtcclxuXHJcblx0fVxyXG5cclxuXHRhc3luYyBsb2FkQXN5bmMoIHVybCwgb25Qcm9ncmVzcyApIHtcclxuXHJcblx0XHRjb25zdCBzY29wZSA9IHRoaXM7XHJcblxyXG5cdFx0Y29uc3QgcGF0aCA9ICggdGhpcy5wYXRoID09PSAnJyApID8gTG9hZGVyVXRpbHMuZXh0cmFjdFVybEJhc2UoIHVybCApIDogdGhpcy5wYXRoO1xyXG5cdFx0dGhpcy5yZXNvdXJjZVBhdGggPSB0aGlzLnJlc291cmNlUGF0aCB8fCBwYXRoO1xyXG5cclxuXHRcdGNvbnN0IGxvYWRlciA9IG5ldyBGaWxlTG9hZGVyKCB0aGlzLm1hbmFnZXIgKTtcclxuXHRcdGxvYWRlci5zZXRQYXRoKCB0aGlzLnBhdGggKTtcclxuXHRcdGxvYWRlci5zZXRSZXF1ZXN0SGVhZGVyKCB0aGlzLnJlcXVlc3RIZWFkZXIgKTtcclxuXHRcdGxvYWRlci5zZXRXaXRoQ3JlZGVudGlhbHMoIHRoaXMud2l0aENyZWRlbnRpYWxzICk7XHJcblxyXG5cdFx0Y29uc3QgdGV4dCA9IGF3YWl0IGxvYWRlci5sb2FkQXN5bmMoIHVybCwgb25Qcm9ncmVzcyApO1xyXG5cclxuXHRcdGNvbnN0IGpzb24gPSBKU09OLnBhcnNlKCB0ZXh0ICk7XHJcblxyXG5cdFx0Y29uc3QgbWV0YWRhdGEgPSBqc29uLm1ldGFkYXRhO1xyXG5cclxuXHRcdGlmICggbWV0YWRhdGEgPT09IHVuZGVmaW5lZCB8fCBtZXRhZGF0YS50eXBlID09PSB1bmRlZmluZWQgfHwgbWV0YWRhdGEudHlwZS50b0xvd2VyQ2FzZSgpID09PSAnZ2VvbWV0cnknICkge1xyXG5cclxuXHRcdFx0dGhyb3cgbmV3IEVycm9yKCAnVEhSRUUuT2JqZWN0TG9hZGVyOiBDYW5cXCd0IGxvYWQgJyArIHVybCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gYXdhaXQgc2NvcGUucGFyc2VBc3luYygganNvbiApO1xyXG5cclxuXHR9XHJcblxyXG5cdHBhcnNlKCBqc29uLCBvbkxvYWQgKSB7XHJcblxyXG5cdFx0Y29uc3QgYW5pbWF0aW9ucyA9IHRoaXMucGFyc2VBbmltYXRpb25zKCBqc29uLmFuaW1hdGlvbnMgKTtcclxuXHRcdGNvbnN0IHNoYXBlcyA9IHRoaXMucGFyc2VTaGFwZXMoIGpzb24uc2hhcGVzICk7XHJcblx0XHRjb25zdCBnZW9tZXRyaWVzID0gdGhpcy5wYXJzZUdlb21ldHJpZXMoIGpzb24uZ2VvbWV0cmllcywgc2hhcGVzICk7XHJcblxyXG5cdFx0Y29uc3QgaW1hZ2VzID0gdGhpcy5wYXJzZUltYWdlcygganNvbi5pbWFnZXMsIGZ1bmN0aW9uICgpIHtcclxuXHJcblx0XHRcdGlmICggb25Mb2FkICE9PSB1bmRlZmluZWQgKSBvbkxvYWQoIG9iamVjdCApO1xyXG5cclxuXHRcdH0gKTtcclxuXHJcblx0XHRjb25zdCB0ZXh0dXJlcyA9IHRoaXMucGFyc2VUZXh0dXJlcygganNvbi50ZXh0dXJlcywgaW1hZ2VzICk7XHJcblx0XHRjb25zdCBtYXRlcmlhbHMgPSB0aGlzLnBhcnNlTWF0ZXJpYWxzKCBqc29uLm1hdGVyaWFscywgdGV4dHVyZXMgKTtcclxuXHJcblx0XHRjb25zdCBvYmplY3QgPSB0aGlzLnBhcnNlT2JqZWN0KCBqc29uLm9iamVjdCwgZ2VvbWV0cmllcywgbWF0ZXJpYWxzLCB0ZXh0dXJlcywgYW5pbWF0aW9ucyApO1xyXG5cdFx0Y29uc3Qgc2tlbGV0b25zID0gdGhpcy5wYXJzZVNrZWxldG9ucygganNvbi5za2VsZXRvbnMsIG9iamVjdCApO1xyXG5cclxuXHRcdHRoaXMuYmluZFNrZWxldG9ucyggb2JqZWN0LCBza2VsZXRvbnMgKTtcclxuXHJcblx0XHQvL1xyXG5cclxuXHRcdGlmICggb25Mb2FkICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRsZXQgaGFzSW1hZ2VzID0gZmFsc2U7XHJcblxyXG5cdFx0XHRmb3IgKCBjb25zdCB1dWlkIGluIGltYWdlcyApIHtcclxuXHJcblx0XHRcdFx0aWYgKCBpbWFnZXNbIHV1aWQgXS5kYXRhIGluc3RhbmNlb2YgSFRNTEltYWdlRWxlbWVudCApIHtcclxuXHJcblx0XHRcdFx0XHRoYXNJbWFnZXMgPSB0cnVlO1xyXG5cdFx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGlmICggaGFzSW1hZ2VzID09PSBmYWxzZSApIG9uTG9hZCggb2JqZWN0ICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiBvYmplY3Q7XHJcblxyXG5cdH1cclxuXHJcblx0YXN5bmMgcGFyc2VBc3luYygganNvbiApIHtcclxuXHJcblx0XHRjb25zdCBhbmltYXRpb25zID0gdGhpcy5wYXJzZUFuaW1hdGlvbnMoIGpzb24uYW5pbWF0aW9ucyApO1xyXG5cdFx0Y29uc3Qgc2hhcGVzID0gdGhpcy5wYXJzZVNoYXBlcygganNvbi5zaGFwZXMgKTtcclxuXHRcdGNvbnN0IGdlb21ldHJpZXMgPSB0aGlzLnBhcnNlR2VvbWV0cmllcygganNvbi5nZW9tZXRyaWVzLCBzaGFwZXMgKTtcclxuXHJcblx0XHRjb25zdCBpbWFnZXMgPSBhd2FpdCB0aGlzLnBhcnNlSW1hZ2VzQXN5bmMoIGpzb24uaW1hZ2VzICk7XHJcblxyXG5cdFx0Y29uc3QgdGV4dHVyZXMgPSB0aGlzLnBhcnNlVGV4dHVyZXMoIGpzb24udGV4dHVyZXMsIGltYWdlcyApO1xyXG5cdFx0Y29uc3QgbWF0ZXJpYWxzID0gdGhpcy5wYXJzZU1hdGVyaWFscygganNvbi5tYXRlcmlhbHMsIHRleHR1cmVzICk7XHJcblxyXG5cdFx0Y29uc3Qgb2JqZWN0ID0gdGhpcy5wYXJzZU9iamVjdCgganNvbi5vYmplY3QsIGdlb21ldHJpZXMsIG1hdGVyaWFscywgdGV4dHVyZXMsIGFuaW1hdGlvbnMgKTtcclxuXHRcdGNvbnN0IHNrZWxldG9ucyA9IHRoaXMucGFyc2VTa2VsZXRvbnMoIGpzb24uc2tlbGV0b25zLCBvYmplY3QgKTtcclxuXHJcblx0XHR0aGlzLmJpbmRTa2VsZXRvbnMoIG9iamVjdCwgc2tlbGV0b25zICk7XHJcblxyXG5cdFx0cmV0dXJuIG9iamVjdDtcclxuXHJcblx0fVxyXG5cclxuXHRwYXJzZVNoYXBlcygganNvbiApIHtcclxuXHJcblx0XHRjb25zdCBzaGFwZXMgPSB7fTtcclxuXHJcblx0XHRpZiAoIGpzb24gIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMCwgbCA9IGpzb24ubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0Y29uc3Qgc2hhcGUgPSBuZXcgU2hhcGUoKS5mcm9tSlNPTigganNvblsgaSBdICk7XHJcblxyXG5cdFx0XHRcdHNoYXBlc1sgc2hhcGUudXVpZCBdID0gc2hhcGU7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiBzaGFwZXM7XHJcblxyXG5cdH1cclxuXHJcblx0cGFyc2VTa2VsZXRvbnMoIGpzb24sIG9iamVjdCApIHtcclxuXHJcblx0XHRjb25zdCBza2VsZXRvbnMgPSB7fTtcclxuXHRcdGNvbnN0IGJvbmVzID0ge307XHJcblxyXG5cdFx0Ly8gZ2VuZXJhdGUgYm9uZSBsb29rdXAgdGFibGVcclxuXHJcblx0XHRvYmplY3QudHJhdmVyc2UoIGZ1bmN0aW9uICggY2hpbGQgKSB7XHJcblxyXG5cdFx0XHRpZiAoIGNoaWxkLmlzQm9uZSApIGJvbmVzWyBjaGlsZC51dWlkIF0gPSBjaGlsZDtcclxuXHJcblx0XHR9ICk7XHJcblxyXG5cdFx0Ly8gY3JlYXRlIHNrZWxldG9uc1xyXG5cclxuXHRcdGlmICgganNvbiAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGkgPSAwLCBsID0ganNvbi5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBza2VsZXRvbiA9IG5ldyBTa2VsZXRvbigpLmZyb21KU09OKCBqc29uWyBpIF0sIGJvbmVzICk7XHJcblxyXG5cdFx0XHRcdHNrZWxldG9uc1sgc2tlbGV0b24udXVpZCBdID0gc2tlbGV0b247XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiBza2VsZXRvbnM7XHJcblxyXG5cdH1cclxuXHJcblx0cGFyc2VHZW9tZXRyaWVzKCBqc29uLCBzaGFwZXMgKSB7XHJcblxyXG5cdFx0Y29uc3QgZ2VvbWV0cmllcyA9IHt9O1xyXG5cclxuXHRcdGlmICgganNvbiAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0Y29uc3QgYnVmZmVyR2VvbWV0cnlMb2FkZXIgPSBuZXcgQnVmZmVyR2VvbWV0cnlMb2FkZXIoKTtcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMCwgbCA9IGpzb24ubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0bGV0IGdlb21ldHJ5O1xyXG5cdFx0XHRcdGNvbnN0IGRhdGEgPSBqc29uWyBpIF07XHJcblxyXG5cdFx0XHRcdHN3aXRjaCAoIGRhdGEudHlwZSApIHtcclxuXHJcblx0XHRcdFx0XHRjYXNlICdCdWZmZXJHZW9tZXRyeSc6XHJcblx0XHRcdFx0XHRjYXNlICdJbnN0YW5jZWRCdWZmZXJHZW9tZXRyeSc6XHJcblxyXG5cdFx0XHRcdFx0XHRnZW9tZXRyeSA9IGJ1ZmZlckdlb21ldHJ5TG9hZGVyLnBhcnNlKCBkYXRhICk7XHJcblx0XHRcdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0XHRcdGRlZmF1bHQ6XHJcblxyXG5cdFx0XHRcdFx0XHRpZiAoIGRhdGEudHlwZSBpbiBHZW9tZXRyaWVzICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRnZW9tZXRyeSA9IEdlb21ldHJpZXNbIGRhdGEudHlwZSBdLmZyb21KU09OKCBkYXRhLCBzaGFwZXMgKTtcclxuXHJcblx0XHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdGNvbnNvbGUud2FybiggYFRIUkVFLk9iamVjdExvYWRlcjogVW5zdXBwb3J0ZWQgZ2VvbWV0cnkgdHlwZSBcIiR7IGRhdGEudHlwZSB9XCJgICk7XHJcblxyXG5cdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0Z2VvbWV0cnkudXVpZCA9IGRhdGEudXVpZDtcclxuXHJcblx0XHRcdFx0aWYgKCBkYXRhLm5hbWUgIT09IHVuZGVmaW5lZCApIGdlb21ldHJ5Lm5hbWUgPSBkYXRhLm5hbWU7XHJcblx0XHRcdFx0aWYgKCBkYXRhLnVzZXJEYXRhICE9PSB1bmRlZmluZWQgKSBnZW9tZXRyeS51c2VyRGF0YSA9IGRhdGEudXNlckRhdGE7XHJcblxyXG5cdFx0XHRcdGdlb21ldHJpZXNbIGRhdGEudXVpZCBdID0gZ2VvbWV0cnk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiBnZW9tZXRyaWVzO1xyXG5cclxuXHR9XHJcblxyXG5cdHBhcnNlTWF0ZXJpYWxzKCBqc29uLCB0ZXh0dXJlcyApIHtcclxuXHJcblx0XHRjb25zdCBjYWNoZSA9IHt9OyAvLyBNdWx0aU1hdGVyaWFsXHJcblx0XHRjb25zdCBtYXRlcmlhbHMgPSB7fTtcclxuXHJcblx0XHRpZiAoIGpzb24gIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdGNvbnN0IGxvYWRlciA9IG5ldyBNYXRlcmlhbExvYWRlcigpO1xyXG5cdFx0XHRsb2FkZXIuc2V0VGV4dHVyZXMoIHRleHR1cmVzICk7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBqc29uLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IGRhdGEgPSBqc29uWyBpIF07XHJcblxyXG5cdFx0XHRcdGlmICggY2FjaGVbIGRhdGEudXVpZCBdID09PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y2FjaGVbIGRhdGEudXVpZCBdID0gbG9hZGVyLnBhcnNlKCBkYXRhICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0bWF0ZXJpYWxzWyBkYXRhLnV1aWQgXSA9IGNhY2hlWyBkYXRhLnV1aWQgXTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIG1hdGVyaWFscztcclxuXHJcblx0fVxyXG5cclxuXHRwYXJzZUFuaW1hdGlvbnMoIGpzb24gKSB7XHJcblxyXG5cdFx0Y29uc3QgYW5pbWF0aW9ucyA9IHt9O1xyXG5cclxuXHRcdGlmICgganNvbiAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwganNvbi5sZW5ndGg7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IGRhdGEgPSBqc29uWyBpIF07XHJcblxyXG5cdFx0XHRcdGNvbnN0IGNsaXAgPSBBbmltYXRpb25DbGlwLnBhcnNlKCBkYXRhICk7XHJcblxyXG5cdFx0XHRcdGFuaW1hdGlvbnNbIGNsaXAudXVpZCBdID0gY2xpcDtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIGFuaW1hdGlvbnM7XHJcblxyXG5cdH1cclxuXHJcblx0cGFyc2VJbWFnZXMoIGpzb24sIG9uTG9hZCApIHtcclxuXHJcblx0XHRjb25zdCBzY29wZSA9IHRoaXM7XHJcblx0XHRjb25zdCBpbWFnZXMgPSB7fTtcclxuXHJcblx0XHRsZXQgbG9hZGVyO1xyXG5cclxuXHRcdGZ1bmN0aW9uIGxvYWRJbWFnZSggdXJsICkge1xyXG5cclxuXHRcdFx0c2NvcGUubWFuYWdlci5pdGVtU3RhcnQoIHVybCApO1xyXG5cclxuXHRcdFx0cmV0dXJuIGxvYWRlci5sb2FkKCB1cmwsIGZ1bmN0aW9uICgpIHtcclxuXHJcblx0XHRcdFx0c2NvcGUubWFuYWdlci5pdGVtRW5kKCB1cmwgKTtcclxuXHJcblx0XHRcdH0sIHVuZGVmaW5lZCwgZnVuY3Rpb24gKCkge1xyXG5cclxuXHRcdFx0XHRzY29wZS5tYW5hZ2VyLml0ZW1FcnJvciggdXJsICk7XHJcblx0XHRcdFx0c2NvcGUubWFuYWdlci5pdGVtRW5kKCB1cmwgKTtcclxuXHJcblx0XHRcdH0gKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0ZnVuY3Rpb24gZGVzZXJpYWxpemVJbWFnZSggaW1hZ2UgKSB7XHJcblxyXG5cdFx0XHRpZiAoIHR5cGVvZiBpbWFnZSA9PT0gJ3N0cmluZycgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IHVybCA9IGltYWdlO1xyXG5cclxuXHRcdFx0XHRjb25zdCBwYXRoID0gL14oXFwvXFwvKXwoW2Etel0rOihcXC9cXC8pPykvaS50ZXN0KCB1cmwgKSA/IHVybCA6IHNjb3BlLnJlc291cmNlUGF0aCArIHVybDtcclxuXHJcblx0XHRcdFx0cmV0dXJuIGxvYWRJbWFnZSggcGF0aCApO1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0aWYgKCBpbWFnZS5kYXRhICkge1xyXG5cclxuXHRcdFx0XHRcdHJldHVybiB7XHJcblx0XHRcdFx0XHRcdGRhdGE6IGdldFR5cGVkQXJyYXkoIGltYWdlLnR5cGUsIGltYWdlLmRhdGEgKSxcclxuXHRcdFx0XHRcdFx0d2lkdGg6IGltYWdlLndpZHRoLFxyXG5cdFx0XHRcdFx0XHRoZWlnaHQ6IGltYWdlLmhlaWdodFxyXG5cdFx0XHRcdFx0fTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRyZXR1cm4gbnVsbDtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIGpzb24gIT09IHVuZGVmaW5lZCAmJiBqc29uLmxlbmd0aCA+IDAgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBtYW5hZ2VyID0gbmV3IExvYWRpbmdNYW5hZ2VyKCBvbkxvYWQgKTtcclxuXHJcblx0XHRcdGxvYWRlciA9IG5ldyBJbWFnZUxvYWRlciggbWFuYWdlciApO1xyXG5cdFx0XHRsb2FkZXIuc2V0Q3Jvc3NPcmlnaW4oIHRoaXMuY3Jvc3NPcmlnaW4gKTtcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSBqc29uLmxlbmd0aDsgaSA8IGlsOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBpbWFnZSA9IGpzb25bIGkgXTtcclxuXHRcdFx0XHRjb25zdCB1cmwgPSBpbWFnZS51cmw7XHJcblxyXG5cdFx0XHRcdGlmICggQXJyYXkuaXNBcnJheSggdXJsICkgKSB7XHJcblxyXG5cdFx0XHRcdFx0Ly8gbG9hZCBhcnJheSBvZiBpbWFnZXMgZS5nIEN1YmVUZXh0dXJlXHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgaW1hZ2VBcnJheSA9IFtdO1xyXG5cclxuXHRcdFx0XHRcdGZvciAoIGxldCBqID0gMCwgamwgPSB1cmwubGVuZ3RoOyBqIDwgamw7IGogKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRjb25zdCBjdXJyZW50VXJsID0gdXJsWyBqIF07XHJcblxyXG5cdFx0XHRcdFx0XHRjb25zdCBkZXNlcmlhbGl6ZWRJbWFnZSA9IGRlc2VyaWFsaXplSW1hZ2UoIGN1cnJlbnRVcmwgKTtcclxuXHJcblx0XHRcdFx0XHRcdGlmICggZGVzZXJpYWxpemVkSW1hZ2UgIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdGlmICggZGVzZXJpYWxpemVkSW1hZ2UgaW5zdGFuY2VvZiBIVE1MSW1hZ2VFbGVtZW50ICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRcdGltYWdlQXJyYXkucHVzaCggZGVzZXJpYWxpemVkSW1hZ2UgKTtcclxuXHJcblx0XHRcdFx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHQvLyBzcGVjaWFsIGNhc2U6IGhhbmRsZSBhcnJheSBvZiBkYXRhIHRleHR1cmVzIGZvciBjdWJlIHRleHR1cmVzXHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0aW1hZ2VBcnJheS5wdXNoKCBuZXcgRGF0YVRleHR1cmUoIGRlc2VyaWFsaXplZEltYWdlLmRhdGEsIGRlc2VyaWFsaXplZEltYWdlLndpZHRoLCBkZXNlcmlhbGl6ZWRJbWFnZS5oZWlnaHQgKSApO1xyXG5cclxuXHRcdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdGltYWdlc1sgaW1hZ2UudXVpZCBdID0gbmV3IFNvdXJjZSggaW1hZ2VBcnJheSApO1xyXG5cclxuXHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdC8vIGxvYWQgc2luZ2xlIGltYWdlXHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgZGVzZXJpYWxpemVkSW1hZ2UgPSBkZXNlcmlhbGl6ZUltYWdlKCBpbWFnZS51cmwgKTtcclxuXHRcdFx0XHRcdGltYWdlc1sgaW1hZ2UudXVpZCBdID0gbmV3IFNvdXJjZSggZGVzZXJpYWxpemVkSW1hZ2UgKTtcclxuXHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIGltYWdlcztcclxuXHJcblx0fVxyXG5cclxuXHRhc3luYyBwYXJzZUltYWdlc0FzeW5jKCBqc29uICkge1xyXG5cclxuXHRcdGNvbnN0IHNjb3BlID0gdGhpcztcclxuXHRcdGNvbnN0IGltYWdlcyA9IHt9O1xyXG5cclxuXHRcdGxldCBsb2FkZXI7XHJcblxyXG5cdFx0YXN5bmMgZnVuY3Rpb24gZGVzZXJpYWxpemVJbWFnZSggaW1hZ2UgKSB7XHJcblxyXG5cdFx0XHRpZiAoIHR5cGVvZiBpbWFnZSA9PT0gJ3N0cmluZycgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IHVybCA9IGltYWdlO1xyXG5cclxuXHRcdFx0XHRjb25zdCBwYXRoID0gL14oXFwvXFwvKXwoW2Etel0rOihcXC9cXC8pPykvaS50ZXN0KCB1cmwgKSA/IHVybCA6IHNjb3BlLnJlc291cmNlUGF0aCArIHVybDtcclxuXHJcblx0XHRcdFx0cmV0dXJuIGF3YWl0IGxvYWRlci5sb2FkQXN5bmMoIHBhdGggKTtcclxuXHJcblx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdGlmICggaW1hZ2UuZGF0YSApIHtcclxuXHJcblx0XHRcdFx0XHRyZXR1cm4ge1xyXG5cdFx0XHRcdFx0XHRkYXRhOiBnZXRUeXBlZEFycmF5KCBpbWFnZS50eXBlLCBpbWFnZS5kYXRhICksXHJcblx0XHRcdFx0XHRcdHdpZHRoOiBpbWFnZS53aWR0aCxcclxuXHRcdFx0XHRcdFx0aGVpZ2h0OiBpbWFnZS5oZWlnaHRcclxuXHRcdFx0XHRcdH07XHJcblxyXG5cdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0cmV0dXJuIG51bGw7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBqc29uICE9PSB1bmRlZmluZWQgJiYganNvbi5sZW5ndGggPiAwICkge1xyXG5cclxuXHRcdFx0bG9hZGVyID0gbmV3IEltYWdlTG9hZGVyKCB0aGlzLm1hbmFnZXIgKTtcclxuXHRcdFx0bG9hZGVyLnNldENyb3NzT3JpZ2luKCB0aGlzLmNyb3NzT3JpZ2luICk7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0ganNvbi5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgaW1hZ2UgPSBqc29uWyBpIF07XHJcblx0XHRcdFx0Y29uc3QgdXJsID0gaW1hZ2UudXJsO1xyXG5cclxuXHRcdFx0XHRpZiAoIEFycmF5LmlzQXJyYXkoIHVybCApICkge1xyXG5cclxuXHRcdFx0XHRcdC8vIGxvYWQgYXJyYXkgb2YgaW1hZ2VzIGUuZyBDdWJlVGV4dHVyZVxyXG5cclxuXHRcdFx0XHRcdGNvbnN0IGltYWdlQXJyYXkgPSBbXTtcclxuXHJcblx0XHRcdFx0XHRmb3IgKCBsZXQgaiA9IDAsIGpsID0gdXJsLmxlbmd0aDsgaiA8IGpsOyBqICsrICkge1xyXG5cclxuXHRcdFx0XHRcdFx0Y29uc3QgY3VycmVudFVybCA9IHVybFsgaiBdO1xyXG5cclxuXHRcdFx0XHRcdFx0Y29uc3QgZGVzZXJpYWxpemVkSW1hZ2UgPSBhd2FpdCBkZXNlcmlhbGl6ZUltYWdlKCBjdXJyZW50VXJsICk7XHJcblxyXG5cdFx0XHRcdFx0XHRpZiAoIGRlc2VyaWFsaXplZEltYWdlICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRpZiAoIGRlc2VyaWFsaXplZEltYWdlIGluc3RhbmNlb2YgSFRNTEltYWdlRWxlbWVudCApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHRpbWFnZUFycmF5LnB1c2goIGRlc2VyaWFsaXplZEltYWdlICk7XHJcblxyXG5cdFx0XHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0Ly8gc3BlY2lhbCBjYXNlOiBoYW5kbGUgYXJyYXkgb2YgZGF0YSB0ZXh0dXJlcyBmb3IgY3ViZSB0ZXh0dXJlc1xyXG5cclxuXHRcdFx0XHRcdFx0XHRcdGltYWdlQXJyYXkucHVzaCggbmV3IERhdGFUZXh0dXJlKCBkZXNlcmlhbGl6ZWRJbWFnZS5kYXRhLCBkZXNlcmlhbGl6ZWRJbWFnZS53aWR0aCwgZGVzZXJpYWxpemVkSW1hZ2UuaGVpZ2h0ICkgKTtcclxuXHJcblx0XHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRpbWFnZXNbIGltYWdlLnV1aWQgXSA9IG5ldyBTb3VyY2UoIGltYWdlQXJyYXkgKTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHQvLyBsb2FkIHNpbmdsZSBpbWFnZVxyXG5cclxuXHRcdFx0XHRcdGNvbnN0IGRlc2VyaWFsaXplZEltYWdlID0gYXdhaXQgZGVzZXJpYWxpemVJbWFnZSggaW1hZ2UudXJsICk7XHJcblx0XHRcdFx0XHRpbWFnZXNbIGltYWdlLnV1aWQgXSA9IG5ldyBTb3VyY2UoIGRlc2VyaWFsaXplZEltYWdlICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIGltYWdlcztcclxuXHJcblx0fVxyXG5cclxuXHRwYXJzZVRleHR1cmVzKCBqc29uLCBpbWFnZXMgKSB7XHJcblxyXG5cdFx0ZnVuY3Rpb24gcGFyc2VDb25zdGFudCggdmFsdWUsIHR5cGUgKSB7XHJcblxyXG5cdFx0XHRpZiAoIHR5cGVvZiB2YWx1ZSA9PT0gJ251bWJlcicgKSByZXR1cm4gdmFsdWU7XHJcblxyXG5cdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5PYmplY3RMb2FkZXIucGFyc2VUZXh0dXJlOiBDb25zdGFudCBzaG91bGQgYmUgaW4gbnVtZXJpYyBmb3JtLicsIHZhbHVlICk7XHJcblxyXG5cdFx0XHRyZXR1cm4gdHlwZVsgdmFsdWUgXTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Y29uc3QgdGV4dHVyZXMgPSB7fTtcclxuXHJcblx0XHRpZiAoIGpzb24gIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMCwgbCA9IGpzb24ubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgZGF0YSA9IGpzb25bIGkgXTtcclxuXHJcblx0XHRcdFx0aWYgKCBkYXRhLmltYWdlID09PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuT2JqZWN0TG9hZGVyOiBObyBcImltYWdlXCIgc3BlY2lmaWVkIGZvcicsIGRhdGEudXVpZCApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdGlmICggaW1hZ2VzWyBkYXRhLmltYWdlIF0gPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5PYmplY3RMb2FkZXI6IFVuZGVmaW5lZCBpbWFnZScsIGRhdGEuaW1hZ2UgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRjb25zdCBzb3VyY2UgPSBpbWFnZXNbIGRhdGEuaW1hZ2UgXTtcclxuXHRcdFx0XHRjb25zdCBpbWFnZSA9IHNvdXJjZS5kYXRhO1xyXG5cclxuXHRcdFx0XHRsZXQgdGV4dHVyZTtcclxuXHJcblx0XHRcdFx0aWYgKCBBcnJheS5pc0FycmF5KCBpbWFnZSApICkge1xyXG5cclxuXHRcdFx0XHRcdHRleHR1cmUgPSBuZXcgQ3ViZVRleHR1cmUoKTtcclxuXHJcblx0XHRcdFx0XHRpZiAoIGltYWdlLmxlbmd0aCA9PT0gNiApIHRleHR1cmUubmVlZHNVcGRhdGUgPSB0cnVlO1xyXG5cclxuXHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdGlmICggaW1hZ2UgJiYgaW1hZ2UuZGF0YSApIHtcclxuXHJcblx0XHRcdFx0XHRcdHRleHR1cmUgPSBuZXcgRGF0YVRleHR1cmUoKTtcclxuXHJcblx0XHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdFx0dGV4dHVyZSA9IG5ldyBUZXh0dXJlKCk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdGlmICggaW1hZ2UgKSB0ZXh0dXJlLm5lZWRzVXBkYXRlID0gdHJ1ZTsgLy8gdGV4dHVyZXMgY2FuIGhhdmUgdW5kZWZpbmVkIGltYWdlIGRhdGFcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR0ZXh0dXJlLnNvdXJjZSA9IHNvdXJjZTtcclxuXHJcblx0XHRcdFx0dGV4dHVyZS51dWlkID0gZGF0YS51dWlkO1xyXG5cclxuXHRcdFx0XHRpZiAoIGRhdGEubmFtZSAhPT0gdW5kZWZpbmVkICkgdGV4dHVyZS5uYW1lID0gZGF0YS5uYW1lO1xyXG5cclxuXHRcdFx0XHRpZiAoIGRhdGEubWFwcGluZyAhPT0gdW5kZWZpbmVkICkgdGV4dHVyZS5tYXBwaW5nID0gcGFyc2VDb25zdGFudCggZGF0YS5tYXBwaW5nLCBURVhUVVJFX01BUFBJTkcgKTtcclxuXHRcdFx0XHRpZiAoIGRhdGEuY2hhbm5lbCAhPT0gdW5kZWZpbmVkICkgdGV4dHVyZS5jaGFubmVsID0gZGF0YS5jaGFubmVsO1xyXG5cclxuXHRcdFx0XHRpZiAoIGRhdGEub2Zmc2V0ICE9PSB1bmRlZmluZWQgKSB0ZXh0dXJlLm9mZnNldC5mcm9tQXJyYXkoIGRhdGEub2Zmc2V0ICk7XHJcblx0XHRcdFx0aWYgKCBkYXRhLnJlcGVhdCAhPT0gdW5kZWZpbmVkICkgdGV4dHVyZS5yZXBlYXQuZnJvbUFycmF5KCBkYXRhLnJlcGVhdCApO1xyXG5cdFx0XHRcdGlmICggZGF0YS5jZW50ZXIgIT09IHVuZGVmaW5lZCApIHRleHR1cmUuY2VudGVyLmZyb21BcnJheSggZGF0YS5jZW50ZXIgKTtcclxuXHRcdFx0XHRpZiAoIGRhdGEucm90YXRpb24gIT09IHVuZGVmaW5lZCApIHRleHR1cmUucm90YXRpb24gPSBkYXRhLnJvdGF0aW9uO1xyXG5cclxuXHRcdFx0XHRpZiAoIGRhdGEud3JhcCAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHRcdHRleHR1cmUud3JhcFMgPSBwYXJzZUNvbnN0YW50KCBkYXRhLndyYXBbIDAgXSwgVEVYVFVSRV9XUkFQUElORyApO1xyXG5cdFx0XHRcdFx0dGV4dHVyZS53cmFwVCA9IHBhcnNlQ29uc3RhbnQoIGRhdGEud3JhcFsgMSBdLCBURVhUVVJFX1dSQVBQSU5HICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0aWYgKCBkYXRhLmZvcm1hdCAhPT0gdW5kZWZpbmVkICkgdGV4dHVyZS5mb3JtYXQgPSBkYXRhLmZvcm1hdDtcclxuXHRcdFx0XHRpZiAoIGRhdGEuaW50ZXJuYWxGb3JtYXQgIT09IHVuZGVmaW5lZCApIHRleHR1cmUuaW50ZXJuYWxGb3JtYXQgPSBkYXRhLmludGVybmFsRm9ybWF0O1xyXG5cdFx0XHRcdGlmICggZGF0YS50eXBlICE9PSB1bmRlZmluZWQgKSB0ZXh0dXJlLnR5cGUgPSBkYXRhLnR5cGU7XHJcblx0XHRcdFx0aWYgKCBkYXRhLmNvbG9yU3BhY2UgIT09IHVuZGVmaW5lZCApIHRleHR1cmUuY29sb3JTcGFjZSA9IGRhdGEuY29sb3JTcGFjZTtcclxuXHJcblx0XHRcdFx0aWYgKCBkYXRhLm1pbkZpbHRlciAhPT0gdW5kZWZpbmVkICkgdGV4dHVyZS5taW5GaWx0ZXIgPSBwYXJzZUNvbnN0YW50KCBkYXRhLm1pbkZpbHRlciwgVEVYVFVSRV9GSUxURVIgKTtcclxuXHRcdFx0XHRpZiAoIGRhdGEubWFnRmlsdGVyICE9PSB1bmRlZmluZWQgKSB0ZXh0dXJlLm1hZ0ZpbHRlciA9IHBhcnNlQ29uc3RhbnQoIGRhdGEubWFnRmlsdGVyLCBURVhUVVJFX0ZJTFRFUiApO1xyXG5cdFx0XHRcdGlmICggZGF0YS5hbmlzb3Ryb3B5ICE9PSB1bmRlZmluZWQgKSB0ZXh0dXJlLmFuaXNvdHJvcHkgPSBkYXRhLmFuaXNvdHJvcHk7XHJcblxyXG5cdFx0XHRcdGlmICggZGF0YS5mbGlwWSAhPT0gdW5kZWZpbmVkICkgdGV4dHVyZS5mbGlwWSA9IGRhdGEuZmxpcFk7XHJcblxyXG5cdFx0XHRcdGlmICggZGF0YS5nZW5lcmF0ZU1pcG1hcHMgIT09IHVuZGVmaW5lZCApIHRleHR1cmUuZ2VuZXJhdGVNaXBtYXBzID0gZGF0YS5nZW5lcmF0ZU1pcG1hcHM7XHJcblx0XHRcdFx0aWYgKCBkYXRhLnByZW11bHRpcGx5QWxwaGEgIT09IHVuZGVmaW5lZCApIHRleHR1cmUucHJlbXVsdGlwbHlBbHBoYSA9IGRhdGEucHJlbXVsdGlwbHlBbHBoYTtcclxuXHRcdFx0XHRpZiAoIGRhdGEudW5wYWNrQWxpZ25tZW50ICE9PSB1bmRlZmluZWQgKSB0ZXh0dXJlLnVucGFja0FsaWdubWVudCA9IGRhdGEudW5wYWNrQWxpZ25tZW50O1xyXG5cdFx0XHRcdGlmICggZGF0YS5jb21wYXJlRnVuY3Rpb24gIT09IHVuZGVmaW5lZCApIHRleHR1cmUuY29tcGFyZUZ1bmN0aW9uID0gZGF0YS5jb21wYXJlRnVuY3Rpb247XHJcblxyXG5cdFx0XHRcdGlmICggZGF0YS51c2VyRGF0YSAhPT0gdW5kZWZpbmVkICkgdGV4dHVyZS51c2VyRGF0YSA9IGRhdGEudXNlckRhdGE7XHJcblxyXG5cdFx0XHRcdHRleHR1cmVzWyBkYXRhLnV1aWQgXSA9IHRleHR1cmU7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0ZXh0dXJlcztcclxuXHJcblx0fVxyXG5cclxuXHRwYXJzZU9iamVjdCggZGF0YSwgZ2VvbWV0cmllcywgbWF0ZXJpYWxzLCB0ZXh0dXJlcywgYW5pbWF0aW9ucyApIHtcclxuXHJcblx0XHRsZXQgb2JqZWN0O1xyXG5cclxuXHRcdGZ1bmN0aW9uIGdldEdlb21ldHJ5KCBuYW1lICkge1xyXG5cclxuXHRcdFx0aWYgKCBnZW9tZXRyaWVzWyBuYW1lIF0gPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuT2JqZWN0TG9hZGVyOiBVbmRlZmluZWQgZ2VvbWV0cnknLCBuYW1lICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRyZXR1cm4gZ2VvbWV0cmllc1sgbmFtZSBdO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRmdW5jdGlvbiBnZXRNYXRlcmlhbCggbmFtZSApIHtcclxuXHJcblx0XHRcdGlmICggbmFtZSA9PT0gdW5kZWZpbmVkICkgcmV0dXJuIHVuZGVmaW5lZDtcclxuXHJcblx0XHRcdGlmICggQXJyYXkuaXNBcnJheSggbmFtZSApICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBhcnJheSA9IFtdO1xyXG5cclxuXHRcdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBuYW1lLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgdXVpZCA9IG5hbWVbIGkgXTtcclxuXHJcblx0XHRcdFx0XHRpZiAoIG1hdGVyaWFsc1sgdXVpZCBdID09PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5PYmplY3RMb2FkZXI6IFVuZGVmaW5lZCBtYXRlcmlhbCcsIHV1aWQgKTtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0YXJyYXkucHVzaCggbWF0ZXJpYWxzWyB1dWlkIF0gKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRyZXR1cm4gYXJyYXk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRpZiAoIG1hdGVyaWFsc1sgbmFtZSBdID09PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLk9iamVjdExvYWRlcjogVW5kZWZpbmVkIG1hdGVyaWFsJywgbmFtZSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0cmV0dXJuIG1hdGVyaWFsc1sgbmFtZSBdO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRmdW5jdGlvbiBnZXRUZXh0dXJlKCB1dWlkICkge1xyXG5cclxuXHRcdFx0aWYgKCB0ZXh0dXJlc1sgdXVpZCBdID09PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLk9iamVjdExvYWRlcjogVW5kZWZpbmVkIHRleHR1cmUnLCB1dWlkICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRyZXR1cm4gdGV4dHVyZXNbIHV1aWQgXTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0bGV0IGdlb21ldHJ5LCBtYXRlcmlhbDtcclxuXHJcblx0XHRzd2l0Y2ggKCBkYXRhLnR5cGUgKSB7XHJcblxyXG5cdFx0XHRjYXNlICdTY2VuZSc6XHJcblxyXG5cdFx0XHRcdG9iamVjdCA9IG5ldyBTY2VuZSgpO1xyXG5cclxuXHRcdFx0XHRpZiAoIGRhdGEuYmFja2dyb3VuZCAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHRcdGlmICggTnVtYmVyLmlzSW50ZWdlciggZGF0YS5iYWNrZ3JvdW5kICkgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRvYmplY3QuYmFja2dyb3VuZCA9IG5ldyBDb2xvciggZGF0YS5iYWNrZ3JvdW5kICk7XHJcblxyXG5cdFx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRcdG9iamVjdC5iYWNrZ3JvdW5kID0gZ2V0VGV4dHVyZSggZGF0YS5iYWNrZ3JvdW5kICk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdGlmICggZGF0YS5lbnZpcm9ubWVudCAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHRcdG9iamVjdC5lbnZpcm9ubWVudCA9IGdldFRleHR1cmUoIGRhdGEuZW52aXJvbm1lbnQgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRpZiAoIGRhdGEuZm9nICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCBkYXRhLmZvZy50eXBlID09PSAnRm9nJyApIHtcclxuXHJcblx0XHRcdFx0XHRcdG9iamVjdC5mb2cgPSBuZXcgRm9nKCBkYXRhLmZvZy5jb2xvciwgZGF0YS5mb2cubmVhciwgZGF0YS5mb2cuZmFyICk7XHJcblxyXG5cdFx0XHRcdFx0fSBlbHNlIGlmICggZGF0YS5mb2cudHlwZSA9PT0gJ0ZvZ0V4cDInICkge1xyXG5cclxuXHRcdFx0XHRcdFx0b2JqZWN0LmZvZyA9IG5ldyBGb2dFeHAyKCBkYXRhLmZvZy5jb2xvciwgZGF0YS5mb2cuZGVuc2l0eSApO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRpZiAoIGRhdGEuZm9nLm5hbWUgIT09ICcnICkge1xyXG5cclxuXHRcdFx0XHRcdFx0b2JqZWN0LmZvZy5uYW1lID0gZGF0YS5mb2cubmFtZTtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0aWYgKCBkYXRhLmJhY2tncm91bmRCbHVycmluZXNzICE9PSB1bmRlZmluZWQgKSBvYmplY3QuYmFja2dyb3VuZEJsdXJyaW5lc3MgPSBkYXRhLmJhY2tncm91bmRCbHVycmluZXNzO1xyXG5cdFx0XHRcdGlmICggZGF0YS5iYWNrZ3JvdW5kSW50ZW5zaXR5ICE9PSB1bmRlZmluZWQgKSBvYmplY3QuYmFja2dyb3VuZEludGVuc2l0eSA9IGRhdGEuYmFja2dyb3VuZEludGVuc2l0eTtcclxuXHJcblx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRjYXNlICdQZXJzcGVjdGl2ZUNhbWVyYSc6XHJcblxyXG5cdFx0XHRcdG9iamVjdCA9IG5ldyBQZXJzcGVjdGl2ZUNhbWVyYSggZGF0YS5mb3YsIGRhdGEuYXNwZWN0LCBkYXRhLm5lYXIsIGRhdGEuZmFyICk7XHJcblxyXG5cdFx0XHRcdGlmICggZGF0YS5mb2N1cyAhPT0gdW5kZWZpbmVkICkgb2JqZWN0LmZvY3VzID0gZGF0YS5mb2N1cztcclxuXHRcdFx0XHRpZiAoIGRhdGEuem9vbSAhPT0gdW5kZWZpbmVkICkgb2JqZWN0Lnpvb20gPSBkYXRhLnpvb207XHJcblx0XHRcdFx0aWYgKCBkYXRhLmZpbG1HYXVnZSAhPT0gdW5kZWZpbmVkICkgb2JqZWN0LmZpbG1HYXVnZSA9IGRhdGEuZmlsbUdhdWdlO1xyXG5cdFx0XHRcdGlmICggZGF0YS5maWxtT2Zmc2V0ICE9PSB1bmRlZmluZWQgKSBvYmplY3QuZmlsbU9mZnNldCA9IGRhdGEuZmlsbU9mZnNldDtcclxuXHRcdFx0XHRpZiAoIGRhdGEudmlldyAhPT0gdW5kZWZpbmVkICkgb2JqZWN0LnZpZXcgPSBPYmplY3QuYXNzaWduKCB7fSwgZGF0YS52aWV3ICk7XHJcblxyXG5cdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0Y2FzZSAnT3J0aG9ncmFwaGljQ2FtZXJhJzpcclxuXHJcblx0XHRcdFx0b2JqZWN0ID0gbmV3IE9ydGhvZ3JhcGhpY0NhbWVyYSggZGF0YS5sZWZ0LCBkYXRhLnJpZ2h0LCBkYXRhLnRvcCwgZGF0YS5ib3R0b20sIGRhdGEubmVhciwgZGF0YS5mYXIgKTtcclxuXHJcblx0XHRcdFx0aWYgKCBkYXRhLnpvb20gIT09IHVuZGVmaW5lZCApIG9iamVjdC56b29tID0gZGF0YS56b29tO1xyXG5cdFx0XHRcdGlmICggZGF0YS52aWV3ICE9PSB1bmRlZmluZWQgKSBvYmplY3QudmlldyA9IE9iamVjdC5hc3NpZ24oIHt9LCBkYXRhLnZpZXcgKTtcclxuXHJcblx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRjYXNlICdBbWJpZW50TGlnaHQnOlxyXG5cclxuXHRcdFx0XHRvYmplY3QgPSBuZXcgQW1iaWVudExpZ2h0KCBkYXRhLmNvbG9yLCBkYXRhLmludGVuc2l0eSApO1xyXG5cclxuXHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdGNhc2UgJ0RpcmVjdGlvbmFsTGlnaHQnOlxyXG5cclxuXHRcdFx0XHRvYmplY3QgPSBuZXcgRGlyZWN0aW9uYWxMaWdodCggZGF0YS5jb2xvciwgZGF0YS5pbnRlbnNpdHkgKTtcclxuXHJcblx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRjYXNlICdQb2ludExpZ2h0JzpcclxuXHJcblx0XHRcdFx0b2JqZWN0ID0gbmV3IFBvaW50TGlnaHQoIGRhdGEuY29sb3IsIGRhdGEuaW50ZW5zaXR5LCBkYXRhLmRpc3RhbmNlLCBkYXRhLmRlY2F5ICk7XHJcblxyXG5cdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0Y2FzZSAnUmVjdEFyZWFMaWdodCc6XHJcblxyXG5cdFx0XHRcdG9iamVjdCA9IG5ldyBSZWN0QXJlYUxpZ2h0KCBkYXRhLmNvbG9yLCBkYXRhLmludGVuc2l0eSwgZGF0YS53aWR0aCwgZGF0YS5oZWlnaHQgKTtcclxuXHJcblx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRjYXNlICdTcG90TGlnaHQnOlxyXG5cclxuXHRcdFx0XHRvYmplY3QgPSBuZXcgU3BvdExpZ2h0KCBkYXRhLmNvbG9yLCBkYXRhLmludGVuc2l0eSwgZGF0YS5kaXN0YW5jZSwgZGF0YS5hbmdsZSwgZGF0YS5wZW51bWJyYSwgZGF0YS5kZWNheSApO1xyXG5cclxuXHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdGNhc2UgJ0hlbWlzcGhlcmVMaWdodCc6XHJcblxyXG5cdFx0XHRcdG9iamVjdCA9IG5ldyBIZW1pc3BoZXJlTGlnaHQoIGRhdGEuY29sb3IsIGRhdGEuZ3JvdW5kQ29sb3IsIGRhdGEuaW50ZW5zaXR5ICk7XHJcblxyXG5cdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0Y2FzZSAnTGlnaHRQcm9iZSc6XHJcblxyXG5cdFx0XHRcdG9iamVjdCA9IG5ldyBMaWdodFByb2JlKCkuZnJvbUpTT04oIGRhdGEgKTtcclxuXHJcblx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRjYXNlICdTa2lubmVkTWVzaCc6XHJcblxyXG5cdFx0XHRcdGdlb21ldHJ5ID0gZ2V0R2VvbWV0cnkoIGRhdGEuZ2VvbWV0cnkgKTtcclxuXHRcdFx0IFx0bWF0ZXJpYWwgPSBnZXRNYXRlcmlhbCggZGF0YS5tYXRlcmlhbCApO1xyXG5cclxuXHRcdFx0XHRvYmplY3QgPSBuZXcgU2tpbm5lZE1lc2goIGdlb21ldHJ5LCBtYXRlcmlhbCApO1xyXG5cclxuXHRcdFx0XHRpZiAoIGRhdGEuYmluZE1vZGUgIT09IHVuZGVmaW5lZCApIG9iamVjdC5iaW5kTW9kZSA9IGRhdGEuYmluZE1vZGU7XHJcblx0XHRcdFx0aWYgKCBkYXRhLmJpbmRNYXRyaXggIT09IHVuZGVmaW5lZCApIG9iamVjdC5iaW5kTWF0cml4LmZyb21BcnJheSggZGF0YS5iaW5kTWF0cml4ICk7XHJcblx0XHRcdFx0aWYgKCBkYXRhLnNrZWxldG9uICE9PSB1bmRlZmluZWQgKSBvYmplY3Quc2tlbGV0b24gPSBkYXRhLnNrZWxldG9uO1xyXG5cclxuXHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdGNhc2UgJ01lc2gnOlxyXG5cclxuXHRcdFx0XHRnZW9tZXRyeSA9IGdldEdlb21ldHJ5KCBkYXRhLmdlb21ldHJ5ICk7XHJcblx0XHRcdFx0bWF0ZXJpYWwgPSBnZXRNYXRlcmlhbCggZGF0YS5tYXRlcmlhbCApO1xyXG5cclxuXHRcdFx0XHRvYmplY3QgPSBuZXcgTWVzaCggZ2VvbWV0cnksIG1hdGVyaWFsICk7XHJcblxyXG5cdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0Y2FzZSAnSW5zdGFuY2VkTWVzaCc6XHJcblxyXG5cdFx0XHRcdGdlb21ldHJ5ID0gZ2V0R2VvbWV0cnkoIGRhdGEuZ2VvbWV0cnkgKTtcclxuXHRcdFx0XHRtYXRlcmlhbCA9IGdldE1hdGVyaWFsKCBkYXRhLm1hdGVyaWFsICk7XHJcblx0XHRcdFx0Y29uc3QgY291bnQgPSBkYXRhLmNvdW50O1xyXG5cdFx0XHRcdGNvbnN0IGluc3RhbmNlTWF0cml4ID0gZGF0YS5pbnN0YW5jZU1hdHJpeDtcclxuXHRcdFx0XHRjb25zdCBpbnN0YW5jZUNvbG9yID0gZGF0YS5pbnN0YW5jZUNvbG9yO1xyXG5cclxuXHRcdFx0XHRvYmplY3QgPSBuZXcgSW5zdGFuY2VkTWVzaCggZ2VvbWV0cnksIG1hdGVyaWFsLCBjb3VudCApO1xyXG5cdFx0XHRcdG9iamVjdC5pbnN0YW5jZU1hdHJpeCA9IG5ldyBJbnN0YW5jZWRCdWZmZXJBdHRyaWJ1dGUoIG5ldyBGbG9hdDMyQXJyYXkoIGluc3RhbmNlTWF0cml4LmFycmF5ICksIDE2ICk7XHJcblx0XHRcdFx0aWYgKCBpbnN0YW5jZUNvbG9yICE9PSB1bmRlZmluZWQgKSBvYmplY3QuaW5zdGFuY2VDb2xvciA9IG5ldyBJbnN0YW5jZWRCdWZmZXJBdHRyaWJ1dGUoIG5ldyBGbG9hdDMyQXJyYXkoIGluc3RhbmNlQ29sb3IuYXJyYXkgKSwgaW5zdGFuY2VDb2xvci5pdGVtU2l6ZSApO1xyXG5cclxuXHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdGNhc2UgJ0JhdGNoZWRNZXNoJzpcclxuXHJcblx0XHRcdFx0Z2VvbWV0cnkgPSBnZXRHZW9tZXRyeSggZGF0YS5nZW9tZXRyeSApO1xyXG5cdFx0XHRcdG1hdGVyaWFsID0gZ2V0TWF0ZXJpYWwoIGRhdGEubWF0ZXJpYWwgKTtcclxuXHJcblx0XHRcdFx0b2JqZWN0ID0gbmV3IEJhdGNoZWRNZXNoKCBkYXRhLm1heEdlb21ldHJ5Q291bnQsIGRhdGEubWF4VmVydGV4Q291bnQsIGRhdGEubWF4SW5kZXhDb3VudCwgbWF0ZXJpYWwgKTtcclxuXHRcdFx0XHRvYmplY3QuZ2VvbWV0cnkgPSBnZW9tZXRyeTtcclxuXHRcdFx0XHRvYmplY3QucGVyT2JqZWN0RnJ1c3R1bUN1bGxlZCA9IGRhdGEucGVyT2JqZWN0RnJ1c3R1bUN1bGxlZDtcclxuXHRcdFx0XHRvYmplY3Quc29ydE9iamVjdHMgPSBkYXRhLnNvcnRPYmplY3RzO1xyXG5cclxuXHRcdFx0XHRvYmplY3QuX2RyYXdSYW5nZXMgPSBkYXRhLmRyYXdSYW5nZXM7XHJcblx0XHRcdFx0b2JqZWN0Ll9yZXNlcnZlZFJhbmdlcyA9IGRhdGEucmVzZXJ2ZWRSYW5nZXM7XHJcblxyXG5cdFx0XHRcdG9iamVjdC5fdmlzaWJpbGl0eSA9IGRhdGEudmlzaWJpbGl0eTtcclxuXHRcdFx0XHRvYmplY3QuX2FjdGl2ZSA9IGRhdGEuYWN0aXZlO1xyXG5cdFx0XHRcdG9iamVjdC5fYm91bmRzID0gZGF0YS5ib3VuZHMubWFwKCBib3VuZCA9PiB7XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgYm94ID0gbmV3IEJveDMoKTtcclxuXHRcdFx0XHRcdGJveC5taW4uZnJvbUFycmF5KCBib3VuZC5ib3hNaW4gKTtcclxuXHRcdFx0XHRcdGJveC5tYXguZnJvbUFycmF5KCBib3VuZC5ib3hNYXggKTtcclxuXHJcblx0XHRcdFx0XHRjb25zdCBzcGhlcmUgPSBuZXcgU3BoZXJlKCk7XHJcblx0XHRcdFx0XHRzcGhlcmUucmFkaXVzID0gYm91bmQuc3BoZXJlUmFkaXVzO1xyXG5cdFx0XHRcdFx0c3BoZXJlLmNlbnRlci5mcm9tQXJyYXkoIGJvdW5kLnNwaGVyZUNlbnRlciApO1xyXG5cclxuXHRcdFx0XHRcdHJldHVybiB7XHJcblx0XHRcdFx0XHRcdGJveEluaXRpYWxpemVkOiBib3VuZC5ib3hJbml0aWFsaXplZCxcclxuXHRcdFx0XHRcdFx0Ym94OiBib3gsXHJcblxyXG5cdFx0XHRcdFx0XHRzcGhlcmVJbml0aWFsaXplZDogYm91bmQuc3BoZXJlSW5pdGlhbGl6ZWQsXHJcblx0XHRcdFx0XHRcdHNwaGVyZTogc3BoZXJlXHJcblx0XHRcdFx0XHR9O1xyXG5cclxuXHRcdFx0XHR9ICk7XHJcblxyXG5cdFx0XHRcdG9iamVjdC5fbWF4R2VvbWV0cnlDb3VudCA9IGRhdGEubWF4R2VvbWV0cnlDb3VudDtcclxuXHRcdFx0XHRvYmplY3QuX21heFZlcnRleENvdW50ID0gZGF0YS5tYXhWZXJ0ZXhDb3VudDtcclxuXHRcdFx0XHRvYmplY3QuX21heEluZGV4Q291bnQgPSBkYXRhLm1heEluZGV4Q291bnQ7XHJcblxyXG5cdFx0XHRcdG9iamVjdC5fZ2VvbWV0cnlJbml0aWFsaXplZCA9IGRhdGEuZ2VvbWV0cnlJbml0aWFsaXplZDtcclxuXHRcdFx0XHRvYmplY3QuX2dlb21ldHJ5Q291bnQgPSBkYXRhLmdlb21ldHJ5Q291bnQ7XHJcblxyXG5cdFx0XHRcdG9iamVjdC5fbWF0cmljZXNUZXh0dXJlID0gZ2V0VGV4dHVyZSggZGF0YS5tYXRyaWNlc1RleHR1cmUudXVpZCApO1xyXG5cclxuXHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdGNhc2UgJ0xPRCc6XHJcblxyXG5cdFx0XHRcdG9iamVjdCA9IG5ldyBMT0QoKTtcclxuXHJcblx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRjYXNlICdMaW5lJzpcclxuXHJcblx0XHRcdFx0b2JqZWN0ID0gbmV3IExpbmUoIGdldEdlb21ldHJ5KCBkYXRhLmdlb21ldHJ5ICksIGdldE1hdGVyaWFsKCBkYXRhLm1hdGVyaWFsICkgKTtcclxuXHJcblx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRjYXNlICdMaW5lTG9vcCc6XHJcblxyXG5cdFx0XHRcdG9iamVjdCA9IG5ldyBMaW5lTG9vcCggZ2V0R2VvbWV0cnkoIGRhdGEuZ2VvbWV0cnkgKSwgZ2V0TWF0ZXJpYWwoIGRhdGEubWF0ZXJpYWwgKSApO1xyXG5cclxuXHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdGNhc2UgJ0xpbmVTZWdtZW50cyc6XHJcblxyXG5cdFx0XHRcdG9iamVjdCA9IG5ldyBMaW5lU2VnbWVudHMoIGdldEdlb21ldHJ5KCBkYXRhLmdlb21ldHJ5ICksIGdldE1hdGVyaWFsKCBkYXRhLm1hdGVyaWFsICkgKTtcclxuXHJcblx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRjYXNlICdQb2ludENsb3VkJzpcclxuXHRcdFx0Y2FzZSAnUG9pbnRzJzpcclxuXHJcblx0XHRcdFx0b2JqZWN0ID0gbmV3IFBvaW50cyggZ2V0R2VvbWV0cnkoIGRhdGEuZ2VvbWV0cnkgKSwgZ2V0TWF0ZXJpYWwoIGRhdGEubWF0ZXJpYWwgKSApO1xyXG5cclxuXHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdGNhc2UgJ1Nwcml0ZSc6XHJcblxyXG5cdFx0XHRcdG9iamVjdCA9IG5ldyBTcHJpdGUoIGdldE1hdGVyaWFsKCBkYXRhLm1hdGVyaWFsICkgKTtcclxuXHJcblx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRjYXNlICdHcm91cCc6XHJcblxyXG5cdFx0XHRcdG9iamVjdCA9IG5ldyBHcm91cCgpO1xyXG5cclxuXHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdGNhc2UgJ0JvbmUnOlxyXG5cclxuXHRcdFx0XHRvYmplY3QgPSBuZXcgQm9uZSgpO1xyXG5cclxuXHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdGRlZmF1bHQ6XHJcblxyXG5cdFx0XHRcdG9iamVjdCA9IG5ldyBPYmplY3QzRCgpO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRvYmplY3QudXVpZCA9IGRhdGEudXVpZDtcclxuXHJcblx0XHRpZiAoIGRhdGEubmFtZSAhPT0gdW5kZWZpbmVkICkgb2JqZWN0Lm5hbWUgPSBkYXRhLm5hbWU7XHJcblxyXG5cdFx0aWYgKCBkYXRhLm1hdHJpeCAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0b2JqZWN0Lm1hdHJpeC5mcm9tQXJyYXkoIGRhdGEubWF0cml4ICk7XHJcblxyXG5cdFx0XHRpZiAoIGRhdGEubWF0cml4QXV0b1VwZGF0ZSAhPT0gdW5kZWZpbmVkICkgb2JqZWN0Lm1hdHJpeEF1dG9VcGRhdGUgPSBkYXRhLm1hdHJpeEF1dG9VcGRhdGU7XHJcblx0XHRcdGlmICggb2JqZWN0Lm1hdHJpeEF1dG9VcGRhdGUgKSBvYmplY3QubWF0cml4LmRlY29tcG9zZSggb2JqZWN0LnBvc2l0aW9uLCBvYmplY3QucXVhdGVybmlvbiwgb2JqZWN0LnNjYWxlICk7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdGlmICggZGF0YS5wb3NpdGlvbiAhPT0gdW5kZWZpbmVkICkgb2JqZWN0LnBvc2l0aW9uLmZyb21BcnJheSggZGF0YS5wb3NpdGlvbiApO1xyXG5cdFx0XHRpZiAoIGRhdGEucm90YXRpb24gIT09IHVuZGVmaW5lZCApIG9iamVjdC5yb3RhdGlvbi5mcm9tQXJyYXkoIGRhdGEucm90YXRpb24gKTtcclxuXHRcdFx0aWYgKCBkYXRhLnF1YXRlcm5pb24gIT09IHVuZGVmaW5lZCApIG9iamVjdC5xdWF0ZXJuaW9uLmZyb21BcnJheSggZGF0YS5xdWF0ZXJuaW9uICk7XHJcblx0XHRcdGlmICggZGF0YS5zY2FsZSAhPT0gdW5kZWZpbmVkICkgb2JqZWN0LnNjYWxlLmZyb21BcnJheSggZGF0YS5zY2FsZSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIGRhdGEudXAgIT09IHVuZGVmaW5lZCApIG9iamVjdC51cC5mcm9tQXJyYXkoIGRhdGEudXAgKTtcclxuXHJcblx0XHRpZiAoIGRhdGEuY2FzdFNoYWRvdyAhPT0gdW5kZWZpbmVkICkgb2JqZWN0LmNhc3RTaGFkb3cgPSBkYXRhLmNhc3RTaGFkb3c7XHJcblx0XHRpZiAoIGRhdGEucmVjZWl2ZVNoYWRvdyAhPT0gdW5kZWZpbmVkICkgb2JqZWN0LnJlY2VpdmVTaGFkb3cgPSBkYXRhLnJlY2VpdmVTaGFkb3c7XHJcblxyXG5cdFx0aWYgKCBkYXRhLnNoYWRvdyApIHtcclxuXHJcblx0XHRcdGlmICggZGF0YS5zaGFkb3cuYmlhcyAhPT0gdW5kZWZpbmVkICkgb2JqZWN0LnNoYWRvdy5iaWFzID0gZGF0YS5zaGFkb3cuYmlhcztcclxuXHRcdFx0aWYgKCBkYXRhLnNoYWRvdy5ub3JtYWxCaWFzICE9PSB1bmRlZmluZWQgKSBvYmplY3Quc2hhZG93Lm5vcm1hbEJpYXMgPSBkYXRhLnNoYWRvdy5ub3JtYWxCaWFzO1xyXG5cdFx0XHRpZiAoIGRhdGEuc2hhZG93LnJhZGl1cyAhPT0gdW5kZWZpbmVkICkgb2JqZWN0LnNoYWRvdy5yYWRpdXMgPSBkYXRhLnNoYWRvdy5yYWRpdXM7XHJcblx0XHRcdGlmICggZGF0YS5zaGFkb3cubWFwU2l6ZSAhPT0gdW5kZWZpbmVkICkgb2JqZWN0LnNoYWRvdy5tYXBTaXplLmZyb21BcnJheSggZGF0YS5zaGFkb3cubWFwU2l6ZSApO1xyXG5cdFx0XHRpZiAoIGRhdGEuc2hhZG93LmNhbWVyYSAhPT0gdW5kZWZpbmVkICkgb2JqZWN0LnNoYWRvdy5jYW1lcmEgPSB0aGlzLnBhcnNlT2JqZWN0KCBkYXRhLnNoYWRvdy5jYW1lcmEgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBkYXRhLnZpc2libGUgIT09IHVuZGVmaW5lZCApIG9iamVjdC52aXNpYmxlID0gZGF0YS52aXNpYmxlO1xyXG5cdFx0aWYgKCBkYXRhLmZydXN0dW1DdWxsZWQgIT09IHVuZGVmaW5lZCApIG9iamVjdC5mcnVzdHVtQ3VsbGVkID0gZGF0YS5mcnVzdHVtQ3VsbGVkO1xyXG5cdFx0aWYgKCBkYXRhLnJlbmRlck9yZGVyICE9PSB1bmRlZmluZWQgKSBvYmplY3QucmVuZGVyT3JkZXIgPSBkYXRhLnJlbmRlck9yZGVyO1xyXG5cdFx0aWYgKCBkYXRhLnVzZXJEYXRhICE9PSB1bmRlZmluZWQgKSBvYmplY3QudXNlckRhdGEgPSBkYXRhLnVzZXJEYXRhO1xyXG5cdFx0aWYgKCBkYXRhLmxheWVycyAhPT0gdW5kZWZpbmVkICkgb2JqZWN0LmxheWVycy5tYXNrID0gZGF0YS5sYXllcnM7XHJcblxyXG5cdFx0aWYgKCBkYXRhLmNoaWxkcmVuICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBjaGlsZHJlbiA9IGRhdGEuY2hpbGRyZW47XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBjaGlsZHJlbi5sZW5ndGg7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdG9iamVjdC5hZGQoIHRoaXMucGFyc2VPYmplY3QoIGNoaWxkcmVuWyBpIF0sIGdlb21ldHJpZXMsIG1hdGVyaWFscywgdGV4dHVyZXMsIGFuaW1hdGlvbnMgKSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIGRhdGEuYW5pbWF0aW9ucyAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0Y29uc3Qgb2JqZWN0QW5pbWF0aW9ucyA9IGRhdGEuYW5pbWF0aW9ucztcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IG9iamVjdEFuaW1hdGlvbnMubGVuZ3RoOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCB1dWlkID0gb2JqZWN0QW5pbWF0aW9uc1sgaSBdO1xyXG5cclxuXHRcdFx0XHRvYmplY3QuYW5pbWF0aW9ucy5wdXNoKCBhbmltYXRpb25zWyB1dWlkIF0gKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBkYXRhLnR5cGUgPT09ICdMT0QnICkge1xyXG5cclxuXHRcdFx0aWYgKCBkYXRhLmF1dG9VcGRhdGUgIT09IHVuZGVmaW5lZCApIG9iamVjdC5hdXRvVXBkYXRlID0gZGF0YS5hdXRvVXBkYXRlO1xyXG5cclxuXHRcdFx0Y29uc3QgbGV2ZWxzID0gZGF0YS5sZXZlbHM7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgbCA9IDA7IGwgPCBsZXZlbHMubGVuZ3RoOyBsICsrICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBsZXZlbCA9IGxldmVsc1sgbCBdO1xyXG5cdFx0XHRcdGNvbnN0IGNoaWxkID0gb2JqZWN0LmdldE9iamVjdEJ5UHJvcGVydHkoICd1dWlkJywgbGV2ZWwub2JqZWN0ICk7XHJcblxyXG5cdFx0XHRcdGlmICggY2hpbGQgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0XHRvYmplY3QuYWRkTGV2ZWwoIGNoaWxkLCBsZXZlbC5kaXN0YW5jZSwgbGV2ZWwuaHlzdGVyZXNpcyApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiBvYmplY3Q7XHJcblxyXG5cdH1cclxuXHJcblx0YmluZFNrZWxldG9ucyggb2JqZWN0LCBza2VsZXRvbnMgKSB7XHJcblxyXG5cdFx0aWYgKCBPYmplY3Qua2V5cyggc2tlbGV0b25zICkubGVuZ3RoID09PSAwICkgcmV0dXJuO1xyXG5cclxuXHRcdG9iamVjdC50cmF2ZXJzZSggZnVuY3Rpb24gKCBjaGlsZCApIHtcclxuXHJcblx0XHRcdGlmICggY2hpbGQuaXNTa2lubmVkTWVzaCA9PT0gdHJ1ZSAmJiBjaGlsZC5za2VsZXRvbiAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBza2VsZXRvbiA9IHNrZWxldG9uc1sgY2hpbGQuc2tlbGV0b24gXTtcclxuXHJcblx0XHRcdFx0aWYgKCBza2VsZXRvbiA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLk9iamVjdExvYWRlcjogTm8gc2tlbGV0b24gZm91bmQgd2l0aCBVVUlEOicsIGNoaWxkLnNrZWxldG9uICk7XHJcblxyXG5cdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0Y2hpbGQuYmluZCggc2tlbGV0b24sIGNoaWxkLmJpbmRNYXRyaXggKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH0gKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuY29uc3QgVEVYVFVSRV9NQVBQSU5HID0ge1xyXG5cdFVWTWFwcGluZzogVVZNYXBwaW5nLFxyXG5cdEN1YmVSZWZsZWN0aW9uTWFwcGluZzogQ3ViZVJlZmxlY3Rpb25NYXBwaW5nLFxyXG5cdEN1YmVSZWZyYWN0aW9uTWFwcGluZzogQ3ViZVJlZnJhY3Rpb25NYXBwaW5nLFxyXG5cdEVxdWlyZWN0YW5ndWxhclJlZmxlY3Rpb25NYXBwaW5nOiBFcXVpcmVjdGFuZ3VsYXJSZWZsZWN0aW9uTWFwcGluZyxcclxuXHRFcXVpcmVjdGFuZ3VsYXJSZWZyYWN0aW9uTWFwcGluZzogRXF1aXJlY3Rhbmd1bGFyUmVmcmFjdGlvbk1hcHBpbmcsXHJcblx0Q3ViZVVWUmVmbGVjdGlvbk1hcHBpbmc6IEN1YmVVVlJlZmxlY3Rpb25NYXBwaW5nXHJcbn07XHJcblxyXG5jb25zdCBURVhUVVJFX1dSQVBQSU5HID0ge1xyXG5cdFJlcGVhdFdyYXBwaW5nOiBSZXBlYXRXcmFwcGluZyxcclxuXHRDbGFtcFRvRWRnZVdyYXBwaW5nOiBDbGFtcFRvRWRnZVdyYXBwaW5nLFxyXG5cdE1pcnJvcmVkUmVwZWF0V3JhcHBpbmc6IE1pcnJvcmVkUmVwZWF0V3JhcHBpbmdcclxufTtcclxuXHJcbmNvbnN0IFRFWFRVUkVfRklMVEVSID0ge1xyXG5cdE5lYXJlc3RGaWx0ZXI6IE5lYXJlc3RGaWx0ZXIsXHJcblx0TmVhcmVzdE1pcG1hcE5lYXJlc3RGaWx0ZXI6IE5lYXJlc3RNaXBtYXBOZWFyZXN0RmlsdGVyLFxyXG5cdE5lYXJlc3RNaXBtYXBMaW5lYXJGaWx0ZXI6IE5lYXJlc3RNaXBtYXBMaW5lYXJGaWx0ZXIsXHJcblx0TGluZWFyRmlsdGVyOiBMaW5lYXJGaWx0ZXIsXHJcblx0TGluZWFyTWlwbWFwTmVhcmVzdEZpbHRlcjogTGluZWFyTWlwbWFwTmVhcmVzdEZpbHRlcixcclxuXHRMaW5lYXJNaXBtYXBMaW5lYXJGaWx0ZXI6IExpbmVhck1pcG1hcExpbmVhckZpbHRlclxyXG59O1xyXG5cclxuZXhwb3J0IHsgT2JqZWN0TG9hZGVyIH07XHJcbiIsImltcG9ydCB7IENhY2hlIH0gZnJvbSAnLi9DYWNoZS5qcyc7XHJcbmltcG9ydCB7IExvYWRlciB9IGZyb20gJy4vTG9hZGVyLmpzJztcclxuXHJcbmNsYXNzIEltYWdlQml0bWFwTG9hZGVyIGV4dGVuZHMgTG9hZGVyIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIG1hbmFnZXIgKSB7XHJcblxyXG5cdFx0c3VwZXIoIG1hbmFnZXIgKTtcclxuXHJcblx0XHR0aGlzLmlzSW1hZ2VCaXRtYXBMb2FkZXIgPSB0cnVlO1xyXG5cclxuXHRcdGlmICggdHlwZW9mIGNyZWF0ZUltYWdlQml0bWFwID09PSAndW5kZWZpbmVkJyApIHtcclxuXHJcblx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLkltYWdlQml0bWFwTG9hZGVyOiBjcmVhdGVJbWFnZUJpdG1hcCgpIG5vdCBzdXBwb3J0ZWQuJyApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHR5cGVvZiBmZXRjaCA9PT0gJ3VuZGVmaW5lZCcgKSB7XHJcblxyXG5cdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5JbWFnZUJpdG1hcExvYWRlcjogZmV0Y2goKSBub3Qgc3VwcG9ydGVkLicgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5vcHRpb25zID0geyBwcmVtdWx0aXBseUFscGhhOiAnbm9uZScgfTtcclxuXHJcblx0fVxyXG5cclxuXHRzZXRPcHRpb25zKCBvcHRpb25zICkge1xyXG5cclxuXHRcdHRoaXMub3B0aW9ucyA9IG9wdGlvbnM7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0bG9hZCggdXJsLCBvbkxvYWQsIG9uUHJvZ3Jlc3MsIG9uRXJyb3IgKSB7XHJcblxyXG5cdFx0aWYgKCB1cmwgPT09IHVuZGVmaW5lZCApIHVybCA9ICcnO1xyXG5cclxuXHRcdGlmICggdGhpcy5wYXRoICE9PSB1bmRlZmluZWQgKSB1cmwgPSB0aGlzLnBhdGggKyB1cmw7XHJcblxyXG5cdFx0dXJsID0gdGhpcy5tYW5hZ2VyLnJlc29sdmVVUkwoIHVybCApO1xyXG5cclxuXHRcdGNvbnN0IHNjb3BlID0gdGhpcztcclxuXHJcblx0XHRjb25zdCBjYWNoZWQgPSBDYWNoZS5nZXQoIHVybCApO1xyXG5cclxuXHRcdGlmICggY2FjaGVkICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRzY29wZS5tYW5hZ2VyLml0ZW1TdGFydCggdXJsICk7XHJcblxyXG5cdFx0XHQvLyBJZiBjYWNoZWQgaXMgYSBwcm9taXNlLCB3YWl0IGZvciBpdCB0byByZXNvbHZlXHJcblx0XHRcdGlmICggY2FjaGVkLnRoZW4gKSB7XHJcblxyXG5cdFx0XHRcdGNhY2hlZC50aGVuKCBpbWFnZUJpdG1hcCA9PiB7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCBvbkxvYWQgKSBvbkxvYWQoIGltYWdlQml0bWFwICk7XHJcblxyXG5cdFx0XHRcdFx0c2NvcGUubWFuYWdlci5pdGVtRW5kKCB1cmwgKTtcclxuXHJcblx0XHRcdFx0fSApLmNhdGNoKCBlID0+IHtcclxuXHJcblx0XHRcdFx0XHRpZiAoIG9uRXJyb3IgKSBvbkVycm9yKCBlICk7XHJcblxyXG5cdFx0XHRcdH0gKTtcclxuXHRcdFx0XHRyZXR1cm47XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyBJZiBjYWNoZWQgaXMgbm90IGEgcHJvbWlzZSAoaS5lLiwgaXQncyBhbHJlYWR5IGFuIGltYWdlQml0bWFwKVxyXG5cdFx0XHRzZXRUaW1lb3V0KCBmdW5jdGlvbiAoKSB7XHJcblxyXG5cdFx0XHRcdGlmICggb25Mb2FkICkgb25Mb2FkKCBjYWNoZWQgKTtcclxuXHJcblx0XHRcdFx0c2NvcGUubWFuYWdlci5pdGVtRW5kKCB1cmwgKTtcclxuXHJcblx0XHRcdH0sIDAgKTtcclxuXHJcblx0XHRcdHJldHVybiBjYWNoZWQ7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGNvbnN0IGZldGNoT3B0aW9ucyA9IHt9O1xyXG5cdFx0ZmV0Y2hPcHRpb25zLmNyZWRlbnRpYWxzID0gKCB0aGlzLmNyb3NzT3JpZ2luID09PSAnYW5vbnltb3VzJyApID8gJ3NhbWUtb3JpZ2luJyA6ICdpbmNsdWRlJztcclxuXHRcdGZldGNoT3B0aW9ucy5oZWFkZXJzID0gdGhpcy5yZXF1ZXN0SGVhZGVyO1xyXG5cclxuXHRcdGNvbnN0IHByb21pc2UgPSBmZXRjaCggdXJsLCBmZXRjaE9wdGlvbnMgKS50aGVuKCBmdW5jdGlvbiAoIHJlcyApIHtcclxuXHJcblx0XHRcdHJldHVybiByZXMuYmxvYigpO1xyXG5cclxuXHRcdH0gKS50aGVuKCBmdW5jdGlvbiAoIGJsb2IgKSB7XHJcblxyXG5cdFx0XHRyZXR1cm4gY3JlYXRlSW1hZ2VCaXRtYXAoIGJsb2IsIE9iamVjdC5hc3NpZ24oIHNjb3BlLm9wdGlvbnMsIHsgY29sb3JTcGFjZUNvbnZlcnNpb246ICdub25lJyB9ICkgKTtcclxuXHJcblx0XHR9ICkudGhlbiggZnVuY3Rpb24gKCBpbWFnZUJpdG1hcCApIHtcclxuXHJcblx0XHRcdENhY2hlLmFkZCggdXJsLCBpbWFnZUJpdG1hcCApO1xyXG5cclxuXHRcdFx0aWYgKCBvbkxvYWQgKSBvbkxvYWQoIGltYWdlQml0bWFwICk7XHJcblxyXG5cdFx0XHRzY29wZS5tYW5hZ2VyLml0ZW1FbmQoIHVybCApO1xyXG5cclxuXHRcdFx0cmV0dXJuIGltYWdlQml0bWFwO1xyXG5cclxuXHRcdH0gKS5jYXRjaCggZnVuY3Rpb24gKCBlICkge1xyXG5cclxuXHRcdFx0aWYgKCBvbkVycm9yICkgb25FcnJvciggZSApO1xyXG5cclxuXHRcdFx0Q2FjaGUucmVtb3ZlKCB1cmwgKTtcclxuXHJcblx0XHRcdHNjb3BlLm1hbmFnZXIuaXRlbUVycm9yKCB1cmwgKTtcclxuXHRcdFx0c2NvcGUubWFuYWdlci5pdGVtRW5kKCB1cmwgKTtcclxuXHJcblx0XHR9ICk7XHJcblxyXG5cdFx0Q2FjaGUuYWRkKCB1cmwsIHByb21pc2UgKTtcclxuXHRcdHNjb3BlLm1hbmFnZXIuaXRlbVN0YXJ0KCB1cmwgKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgSW1hZ2VCaXRtYXBMb2FkZXIgfTtcclxuIiwibGV0IF9jb250ZXh0O1xyXG5cclxuY2xhc3MgQXVkaW9Db250ZXh0IHtcclxuXHJcblx0c3RhdGljIGdldENvbnRleHQoKSB7XHJcblxyXG5cdFx0aWYgKCBfY29udGV4dCA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0X2NvbnRleHQgPSBuZXcgKCB3aW5kb3cuQXVkaW9Db250ZXh0IHx8IHdpbmRvdy53ZWJraXRBdWRpb0NvbnRleHQgKSgpO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gX2NvbnRleHQ7XHJcblxyXG5cdH1cclxuXHJcblx0c3RhdGljIHNldENvbnRleHQoIHZhbHVlICkge1xyXG5cclxuXHRcdF9jb250ZXh0ID0gdmFsdWU7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IEF1ZGlvQ29udGV4dCB9O1xyXG4iLCJpbXBvcnQgeyBBdWRpb0NvbnRleHQgfSBmcm9tICcuLi9hdWRpby9BdWRpb0NvbnRleHQuanMnO1xyXG5pbXBvcnQgeyBGaWxlTG9hZGVyIH0gZnJvbSAnLi9GaWxlTG9hZGVyLmpzJztcclxuaW1wb3J0IHsgTG9hZGVyIH0gZnJvbSAnLi9Mb2FkZXIuanMnO1xyXG5cclxuY2xhc3MgQXVkaW9Mb2FkZXIgZXh0ZW5kcyBMb2FkZXIge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggbWFuYWdlciApIHtcclxuXHJcblx0XHRzdXBlciggbWFuYWdlciApO1xyXG5cclxuXHR9XHJcblxyXG5cdGxvYWQoIHVybCwgb25Mb2FkLCBvblByb2dyZXNzLCBvbkVycm9yICkge1xyXG5cclxuXHRcdGNvbnN0IHNjb3BlID0gdGhpcztcclxuXHJcblx0XHRjb25zdCBsb2FkZXIgPSBuZXcgRmlsZUxvYWRlciggdGhpcy5tYW5hZ2VyICk7XHJcblx0XHRsb2FkZXIuc2V0UmVzcG9uc2VUeXBlKCAnYXJyYXlidWZmZXInICk7XHJcblx0XHRsb2FkZXIuc2V0UGF0aCggdGhpcy5wYXRoICk7XHJcblx0XHRsb2FkZXIuc2V0UmVxdWVzdEhlYWRlciggdGhpcy5yZXF1ZXN0SGVhZGVyICk7XHJcblx0XHRsb2FkZXIuc2V0V2l0aENyZWRlbnRpYWxzKCB0aGlzLndpdGhDcmVkZW50aWFscyApO1xyXG5cdFx0bG9hZGVyLmxvYWQoIHVybCwgZnVuY3Rpb24gKCBidWZmZXIgKSB7XHJcblxyXG5cdFx0XHR0cnkge1xyXG5cclxuXHRcdFx0XHQvLyBDcmVhdGUgYSBjb3B5IG9mIHRoZSBidWZmZXIuIFRoZSBgZGVjb2RlQXVkaW9EYXRhYCBtZXRob2RcclxuXHRcdFx0XHQvLyBkZXRhY2hlcyB0aGUgYnVmZmVyIHdoZW4gY29tcGxldGUsIHByZXZlbnRpbmcgcmV1c2UuXHJcblx0XHRcdFx0Y29uc3QgYnVmZmVyQ29weSA9IGJ1ZmZlci5zbGljZSggMCApO1xyXG5cclxuXHRcdFx0XHRjb25zdCBjb250ZXh0ID0gQXVkaW9Db250ZXh0LmdldENvbnRleHQoKTtcclxuXHRcdFx0XHRjb250ZXh0LmRlY29kZUF1ZGlvRGF0YSggYnVmZmVyQ29weSwgZnVuY3Rpb24gKCBhdWRpb0J1ZmZlciApIHtcclxuXHJcblx0XHRcdFx0XHRvbkxvYWQoIGF1ZGlvQnVmZmVyICk7XHJcblxyXG5cdFx0XHRcdH0gKS5jYXRjaCggaGFuZGxlRXJyb3IgKTtcclxuXHJcblx0XHRcdH0gY2F0Y2ggKCBlICkge1xyXG5cclxuXHRcdFx0XHRoYW5kbGVFcnJvciggZSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH0sIG9uUHJvZ3Jlc3MsIG9uRXJyb3IgKTtcclxuXHJcblx0XHRmdW5jdGlvbiBoYW5kbGVFcnJvciggZSApIHtcclxuXHJcblx0XHRcdGlmICggb25FcnJvciApIHtcclxuXHJcblx0XHRcdFx0b25FcnJvciggZSApO1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0Y29uc29sZS5lcnJvciggZSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0c2NvcGUubWFuYWdlci5pdGVtRXJyb3IoIHVybCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuXHJcbmV4cG9ydCB7IEF1ZGlvTG9hZGVyIH07XHJcbiIsImltcG9ydCB7IE1hdHJpeDQgfSBmcm9tICcuLi9tYXRoL01hdHJpeDQuanMnO1xyXG5pbXBvcnQgKiBhcyBNYXRoVXRpbHMgZnJvbSAnLi4vbWF0aC9NYXRoVXRpbHMuanMnO1xyXG5pbXBvcnQgeyBQZXJzcGVjdGl2ZUNhbWVyYSB9IGZyb20gJy4vUGVyc3BlY3RpdmVDYW1lcmEuanMnO1xyXG5cclxuY29uc3QgX2V5ZVJpZ2h0ID0gLypAX19QVVJFX18qLyBuZXcgTWF0cml4NCgpO1xyXG5jb25zdCBfZXllTGVmdCA9IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDQoKTtcclxuY29uc3QgX3Byb2plY3Rpb25NYXRyaXggPSAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXg0KCk7XHJcblxyXG5jbGFzcyBTdGVyZW9DYW1lcmEge1xyXG5cclxuXHRjb25zdHJ1Y3RvcigpIHtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSAnU3RlcmVvQ2FtZXJhJztcclxuXHJcblx0XHR0aGlzLmFzcGVjdCA9IDE7XHJcblxyXG5cdFx0dGhpcy5leWVTZXAgPSAwLjA2NDtcclxuXHJcblx0XHR0aGlzLmNhbWVyYUwgPSBuZXcgUGVyc3BlY3RpdmVDYW1lcmEoKTtcclxuXHRcdHRoaXMuY2FtZXJhTC5sYXllcnMuZW5hYmxlKCAxICk7XHJcblx0XHR0aGlzLmNhbWVyYUwubWF0cml4QXV0b1VwZGF0ZSA9IGZhbHNlO1xyXG5cclxuXHRcdHRoaXMuY2FtZXJhUiA9IG5ldyBQZXJzcGVjdGl2ZUNhbWVyYSgpO1xyXG5cdFx0dGhpcy5jYW1lcmFSLmxheWVycy5lbmFibGUoIDIgKTtcclxuXHRcdHRoaXMuY2FtZXJhUi5tYXRyaXhBdXRvVXBkYXRlID0gZmFsc2U7XHJcblxyXG5cdFx0dGhpcy5fY2FjaGUgPSB7XHJcblx0XHRcdGZvY3VzOiBudWxsLFxyXG5cdFx0XHRmb3Y6IG51bGwsXHJcblx0XHRcdGFzcGVjdDogbnVsbCxcclxuXHRcdFx0bmVhcjogbnVsbCxcclxuXHRcdFx0ZmFyOiBudWxsLFxyXG5cdFx0XHR6b29tOiBudWxsLFxyXG5cdFx0XHRleWVTZXA6IG51bGxcclxuXHRcdH07XHJcblxyXG5cdH1cclxuXHJcblx0dXBkYXRlKCBjYW1lcmEgKSB7XHJcblxyXG5cdFx0Y29uc3QgY2FjaGUgPSB0aGlzLl9jYWNoZTtcclxuXHJcblx0XHRjb25zdCBuZWVkc1VwZGF0ZSA9IGNhY2hlLmZvY3VzICE9PSBjYW1lcmEuZm9jdXMgfHwgY2FjaGUuZm92ICE9PSBjYW1lcmEuZm92IHx8XHJcblx0XHRcdGNhY2hlLmFzcGVjdCAhPT0gY2FtZXJhLmFzcGVjdCAqIHRoaXMuYXNwZWN0IHx8IGNhY2hlLm5lYXIgIT09IGNhbWVyYS5uZWFyIHx8XHJcblx0XHRcdGNhY2hlLmZhciAhPT0gY2FtZXJhLmZhciB8fCBjYWNoZS56b29tICE9PSBjYW1lcmEuem9vbSB8fCBjYWNoZS5leWVTZXAgIT09IHRoaXMuZXllU2VwO1xyXG5cclxuXHRcdGlmICggbmVlZHNVcGRhdGUgKSB7XHJcblxyXG5cdFx0XHRjYWNoZS5mb2N1cyA9IGNhbWVyYS5mb2N1cztcclxuXHRcdFx0Y2FjaGUuZm92ID0gY2FtZXJhLmZvdjtcclxuXHRcdFx0Y2FjaGUuYXNwZWN0ID0gY2FtZXJhLmFzcGVjdCAqIHRoaXMuYXNwZWN0O1xyXG5cdFx0XHRjYWNoZS5uZWFyID0gY2FtZXJhLm5lYXI7XHJcblx0XHRcdGNhY2hlLmZhciA9IGNhbWVyYS5mYXI7XHJcblx0XHRcdGNhY2hlLnpvb20gPSBjYW1lcmEuem9vbTtcclxuXHRcdFx0Y2FjaGUuZXllU2VwID0gdGhpcy5leWVTZXA7XHJcblxyXG5cdFx0XHQvLyBPZmYtYXhpcyBzdGVyZW9zY29waWMgZWZmZWN0IGJhc2VkIG9uXHJcblx0XHRcdC8vIGh0dHA6Ly9wYXVsYm91cmtlLm5ldC9zdGVyZW9ncmFwaGljcy9zdGVyZW9yZW5kZXIvXHJcblxyXG5cdFx0XHRfcHJvamVjdGlvbk1hdHJpeC5jb3B5KCBjYW1lcmEucHJvamVjdGlvbk1hdHJpeCApO1xyXG5cdFx0XHRjb25zdCBleWVTZXBIYWxmID0gY2FjaGUuZXllU2VwIC8gMjtcclxuXHRcdFx0Y29uc3QgZXllU2VwT25Qcm9qZWN0aW9uID0gZXllU2VwSGFsZiAqIGNhY2hlLm5lYXIgLyBjYWNoZS5mb2N1cztcclxuXHRcdFx0Y29uc3QgeW1heCA9ICggY2FjaGUubmVhciAqIE1hdGgudGFuKCBNYXRoVXRpbHMuREVHMlJBRCAqIGNhY2hlLmZvdiAqIDAuNSApICkgLyBjYWNoZS56b29tO1xyXG5cdFx0XHRsZXQgeG1pbiwgeG1heDtcclxuXHJcblx0XHRcdC8vIHRyYW5zbGF0ZSB4T2Zmc2V0XHJcblxyXG5cdFx0XHRfZXllTGVmdC5lbGVtZW50c1sgMTIgXSA9IC0gZXllU2VwSGFsZjtcclxuXHRcdFx0X2V5ZVJpZ2h0LmVsZW1lbnRzWyAxMiBdID0gZXllU2VwSGFsZjtcclxuXHJcblx0XHRcdC8vIGZvciBsZWZ0IGV5ZVxyXG5cclxuXHRcdFx0eG1pbiA9IC0geW1heCAqIGNhY2hlLmFzcGVjdCArIGV5ZVNlcE9uUHJvamVjdGlvbjtcclxuXHRcdFx0eG1heCA9IHltYXggKiBjYWNoZS5hc3BlY3QgKyBleWVTZXBPblByb2plY3Rpb247XHJcblxyXG5cdFx0XHRfcHJvamVjdGlvbk1hdHJpeC5lbGVtZW50c1sgMCBdID0gMiAqIGNhY2hlLm5lYXIgLyAoIHhtYXggLSB4bWluICk7XHJcblx0XHRcdF9wcm9qZWN0aW9uTWF0cml4LmVsZW1lbnRzWyA4IF0gPSAoIHhtYXggKyB4bWluICkgLyAoIHhtYXggLSB4bWluICk7XHJcblxyXG5cdFx0XHR0aGlzLmNhbWVyYUwucHJvamVjdGlvbk1hdHJpeC5jb3B5KCBfcHJvamVjdGlvbk1hdHJpeCApO1xyXG5cclxuXHRcdFx0Ly8gZm9yIHJpZ2h0IGV5ZVxyXG5cclxuXHRcdFx0eG1pbiA9IC0geW1heCAqIGNhY2hlLmFzcGVjdCAtIGV5ZVNlcE9uUHJvamVjdGlvbjtcclxuXHRcdFx0eG1heCA9IHltYXggKiBjYWNoZS5hc3BlY3QgLSBleWVTZXBPblByb2plY3Rpb247XHJcblxyXG5cdFx0XHRfcHJvamVjdGlvbk1hdHJpeC5lbGVtZW50c1sgMCBdID0gMiAqIGNhY2hlLm5lYXIgLyAoIHhtYXggLSB4bWluICk7XHJcblx0XHRcdF9wcm9qZWN0aW9uTWF0cml4LmVsZW1lbnRzWyA4IF0gPSAoIHhtYXggKyB4bWluICkgLyAoIHhtYXggLSB4bWluICk7XHJcblxyXG5cdFx0XHR0aGlzLmNhbWVyYVIucHJvamVjdGlvbk1hdHJpeC5jb3B5KCBfcHJvamVjdGlvbk1hdHJpeCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLmNhbWVyYUwubWF0cml4V29ybGQuY29weSggY2FtZXJhLm1hdHJpeFdvcmxkICkubXVsdGlwbHkoIF9leWVMZWZ0ICk7XHJcblx0XHR0aGlzLmNhbWVyYVIubWF0cml4V29ybGQuY29weSggY2FtZXJhLm1hdHJpeFdvcmxkICkubXVsdGlwbHkoIF9leWVSaWdodCApO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBTdGVyZW9DYW1lcmEgfTtcclxuIiwiY2xhc3MgQ2xvY2sge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggYXV0b1N0YXJ0ID0gdHJ1ZSApIHtcclxuXHJcblx0XHR0aGlzLmF1dG9TdGFydCA9IGF1dG9TdGFydDtcclxuXHJcblx0XHR0aGlzLnN0YXJ0VGltZSA9IDA7XHJcblx0XHR0aGlzLm9sZFRpbWUgPSAwO1xyXG5cdFx0dGhpcy5lbGFwc2VkVGltZSA9IDA7XHJcblxyXG5cdFx0dGhpcy5ydW5uaW5nID0gZmFsc2U7XHJcblxyXG5cdH1cclxuXHJcblx0c3RhcnQoKSB7XHJcblxyXG5cdFx0dGhpcy5zdGFydFRpbWUgPSBub3coKTtcclxuXHJcblx0XHR0aGlzLm9sZFRpbWUgPSB0aGlzLnN0YXJ0VGltZTtcclxuXHRcdHRoaXMuZWxhcHNlZFRpbWUgPSAwO1xyXG5cdFx0dGhpcy5ydW5uaW5nID0gdHJ1ZTtcclxuXHJcblx0fVxyXG5cclxuXHRzdG9wKCkge1xyXG5cclxuXHRcdHRoaXMuZ2V0RWxhcHNlZFRpbWUoKTtcclxuXHRcdHRoaXMucnVubmluZyA9IGZhbHNlO1xyXG5cdFx0dGhpcy5hdXRvU3RhcnQgPSBmYWxzZTtcclxuXHJcblx0fVxyXG5cclxuXHRnZXRFbGFwc2VkVGltZSgpIHtcclxuXHJcblx0XHR0aGlzLmdldERlbHRhKCk7XHJcblx0XHRyZXR1cm4gdGhpcy5lbGFwc2VkVGltZTtcclxuXHJcblx0fVxyXG5cclxuXHRnZXREZWx0YSgpIHtcclxuXHJcblx0XHRsZXQgZGlmZiA9IDA7XHJcblxyXG5cdFx0aWYgKCB0aGlzLmF1dG9TdGFydCAmJiAhIHRoaXMucnVubmluZyApIHtcclxuXHJcblx0XHRcdHRoaXMuc3RhcnQoKTtcclxuXHRcdFx0cmV0dXJuIDA7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggdGhpcy5ydW5uaW5nICkge1xyXG5cclxuXHRcdFx0Y29uc3QgbmV3VGltZSA9IG5vdygpO1xyXG5cclxuXHRcdFx0ZGlmZiA9ICggbmV3VGltZSAtIHRoaXMub2xkVGltZSApIC8gMTAwMDtcclxuXHRcdFx0dGhpcy5vbGRUaW1lID0gbmV3VGltZTtcclxuXHJcblx0XHRcdHRoaXMuZWxhcHNlZFRpbWUgKz0gZGlmZjtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIGRpZmY7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmZ1bmN0aW9uIG5vdygpIHtcclxuXHJcblx0cmV0dXJuICggdHlwZW9mIHBlcmZvcm1hbmNlID09PSAndW5kZWZpbmVkJyA/IERhdGUgOiBwZXJmb3JtYW5jZSApLm5vdygpOyAvLyBzZWUgIzEwNzMyXHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBDbG9jayB9O1xyXG4iLCJpbXBvcnQgeyBWZWN0b3IzIH0gZnJvbSAnLi4vbWF0aC9WZWN0b3IzLmpzJztcclxuaW1wb3J0IHsgUXVhdGVybmlvbiB9IGZyb20gJy4uL21hdGgvUXVhdGVybmlvbi5qcyc7XHJcbmltcG9ydCB7IENsb2NrIH0gZnJvbSAnLi4vY29yZS9DbG9jay5qcyc7XHJcbmltcG9ydCB7IE9iamVjdDNEIH0gZnJvbSAnLi4vY29yZS9PYmplY3QzRC5qcyc7XHJcbmltcG9ydCB7IEF1ZGlvQ29udGV4dCB9IGZyb20gJy4vQXVkaW9Db250ZXh0LmpzJztcclxuXHJcbmNvbnN0IF9wb3NpdGlvbiA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuY29uc3QgX3F1YXRlcm5pb24gPSAvKkBfX1BVUkVfXyovIG5ldyBRdWF0ZXJuaW9uKCk7XHJcbmNvbnN0IF9zY2FsZSA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuY29uc3QgX29yaWVudGF0aW9uID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5cclxuY2xhc3MgQXVkaW9MaXN0ZW5lciBleHRlbmRzIE9iamVjdDNEIHtcclxuXHJcblx0Y29uc3RydWN0b3IoKSB7XHJcblxyXG5cdFx0c3VwZXIoKTtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSAnQXVkaW9MaXN0ZW5lcic7XHJcblxyXG5cdFx0dGhpcy5jb250ZXh0ID0gQXVkaW9Db250ZXh0LmdldENvbnRleHQoKTtcclxuXHJcblx0XHR0aGlzLmdhaW4gPSB0aGlzLmNvbnRleHQuY3JlYXRlR2FpbigpO1xyXG5cdFx0dGhpcy5nYWluLmNvbm5lY3QoIHRoaXMuY29udGV4dC5kZXN0aW5hdGlvbiApO1xyXG5cclxuXHRcdHRoaXMuZmlsdGVyID0gbnVsbDtcclxuXHJcblx0XHR0aGlzLnRpbWVEZWx0YSA9IDA7XHJcblxyXG5cdFx0Ly8gcHJpdmF0ZVxyXG5cclxuXHRcdHRoaXMuX2Nsb2NrID0gbmV3IENsb2NrKCk7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0SW5wdXQoKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuZ2FpbjtcclxuXHJcblx0fVxyXG5cclxuXHRyZW1vdmVGaWx0ZXIoKSB7XHJcblxyXG5cdFx0aWYgKCB0aGlzLmZpbHRlciAhPT0gbnVsbCApIHtcclxuXHJcblx0XHRcdHRoaXMuZ2Fpbi5kaXNjb25uZWN0KCB0aGlzLmZpbHRlciApO1xyXG5cdFx0XHR0aGlzLmZpbHRlci5kaXNjb25uZWN0KCB0aGlzLmNvbnRleHQuZGVzdGluYXRpb24gKTtcclxuXHRcdFx0dGhpcy5nYWluLmNvbm5lY3QoIHRoaXMuY29udGV4dC5kZXN0aW5hdGlvbiApO1xyXG5cdFx0XHR0aGlzLmZpbHRlciA9IG51bGw7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldEZpbHRlcigpIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5maWx0ZXI7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0RmlsdGVyKCB2YWx1ZSApIHtcclxuXHJcblx0XHRpZiAoIHRoaXMuZmlsdGVyICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0dGhpcy5nYWluLmRpc2Nvbm5lY3QoIHRoaXMuZmlsdGVyICk7XHJcblx0XHRcdHRoaXMuZmlsdGVyLmRpc2Nvbm5lY3QoIHRoaXMuY29udGV4dC5kZXN0aW5hdGlvbiApO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHR0aGlzLmdhaW4uZGlzY29ubmVjdCggdGhpcy5jb250ZXh0LmRlc3RpbmF0aW9uICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMuZmlsdGVyID0gdmFsdWU7XHJcblx0XHR0aGlzLmdhaW4uY29ubmVjdCggdGhpcy5maWx0ZXIgKTtcclxuXHRcdHRoaXMuZmlsdGVyLmNvbm5lY3QoIHRoaXMuY29udGV4dC5kZXN0aW5hdGlvbiApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldE1hc3RlclZvbHVtZSgpIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5nYWluLmdhaW4udmFsdWU7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0TWFzdGVyVm9sdW1lKCB2YWx1ZSApIHtcclxuXHJcblx0XHR0aGlzLmdhaW4uZ2Fpbi5zZXRUYXJnZXRBdFRpbWUoIHZhbHVlLCB0aGlzLmNvbnRleHQuY3VycmVudFRpbWUsIDAuMDEgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHR1cGRhdGVNYXRyaXhXb3JsZCggZm9yY2UgKSB7XHJcblxyXG5cdFx0c3VwZXIudXBkYXRlTWF0cml4V29ybGQoIGZvcmNlICk7XHJcblxyXG5cdFx0Y29uc3QgbGlzdGVuZXIgPSB0aGlzLmNvbnRleHQubGlzdGVuZXI7XHJcblx0XHRjb25zdCB1cCA9IHRoaXMudXA7XHJcblxyXG5cdFx0dGhpcy50aW1lRGVsdGEgPSB0aGlzLl9jbG9jay5nZXREZWx0YSgpO1xyXG5cclxuXHRcdHRoaXMubWF0cml4V29ybGQuZGVjb21wb3NlKCBfcG9zaXRpb24sIF9xdWF0ZXJuaW9uLCBfc2NhbGUgKTtcclxuXHJcblx0XHRfb3JpZW50YXRpb24uc2V0KCAwLCAwLCAtIDEgKS5hcHBseVF1YXRlcm5pb24oIF9xdWF0ZXJuaW9uICk7XHJcblxyXG5cdFx0aWYgKCBsaXN0ZW5lci5wb3NpdGlvblggKSB7XHJcblxyXG5cdFx0XHQvLyBjb2RlIHBhdGggZm9yIENocm9tZSAoc2VlICMxNDM5MylcclxuXHJcblx0XHRcdGNvbnN0IGVuZFRpbWUgPSB0aGlzLmNvbnRleHQuY3VycmVudFRpbWUgKyB0aGlzLnRpbWVEZWx0YTtcclxuXHJcblx0XHRcdGxpc3RlbmVyLnBvc2l0aW9uWC5saW5lYXJSYW1wVG9WYWx1ZUF0VGltZSggX3Bvc2l0aW9uLngsIGVuZFRpbWUgKTtcclxuXHRcdFx0bGlzdGVuZXIucG9zaXRpb25ZLmxpbmVhclJhbXBUb1ZhbHVlQXRUaW1lKCBfcG9zaXRpb24ueSwgZW5kVGltZSApO1xyXG5cdFx0XHRsaXN0ZW5lci5wb3NpdGlvbloubGluZWFyUmFtcFRvVmFsdWVBdFRpbWUoIF9wb3NpdGlvbi56LCBlbmRUaW1lICk7XHJcblx0XHRcdGxpc3RlbmVyLmZvcndhcmRYLmxpbmVhclJhbXBUb1ZhbHVlQXRUaW1lKCBfb3JpZW50YXRpb24ueCwgZW5kVGltZSApO1xyXG5cdFx0XHRsaXN0ZW5lci5mb3J3YXJkWS5saW5lYXJSYW1wVG9WYWx1ZUF0VGltZSggX29yaWVudGF0aW9uLnksIGVuZFRpbWUgKTtcclxuXHRcdFx0bGlzdGVuZXIuZm9yd2FyZFoubGluZWFyUmFtcFRvVmFsdWVBdFRpbWUoIF9vcmllbnRhdGlvbi56LCBlbmRUaW1lICk7XHJcblx0XHRcdGxpc3RlbmVyLnVwWC5saW5lYXJSYW1wVG9WYWx1ZUF0VGltZSggdXAueCwgZW5kVGltZSApO1xyXG5cdFx0XHRsaXN0ZW5lci51cFkubGluZWFyUmFtcFRvVmFsdWVBdFRpbWUoIHVwLnksIGVuZFRpbWUgKTtcclxuXHRcdFx0bGlzdGVuZXIudXBaLmxpbmVhclJhbXBUb1ZhbHVlQXRUaW1lKCB1cC56LCBlbmRUaW1lICk7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdGxpc3RlbmVyLnNldFBvc2l0aW9uKCBfcG9zaXRpb24ueCwgX3Bvc2l0aW9uLnksIF9wb3NpdGlvbi56ICk7XHJcblx0XHRcdGxpc3RlbmVyLnNldE9yaWVudGF0aW9uKCBfb3JpZW50YXRpb24ueCwgX29yaWVudGF0aW9uLnksIF9vcmllbnRhdGlvbi56LCB1cC54LCB1cC55LCB1cC56ICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBBdWRpb0xpc3RlbmVyIH07XHJcbiIsImltcG9ydCB7IE9iamVjdDNEIH0gZnJvbSAnLi4vY29yZS9PYmplY3QzRC5qcyc7XHJcblxyXG5jbGFzcyBBdWRpbyBleHRlbmRzIE9iamVjdDNEIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIGxpc3RlbmVyICkge1xyXG5cclxuXHRcdHN1cGVyKCk7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ0F1ZGlvJztcclxuXHJcblx0XHR0aGlzLmxpc3RlbmVyID0gbGlzdGVuZXI7XHJcblx0XHR0aGlzLmNvbnRleHQgPSBsaXN0ZW5lci5jb250ZXh0O1xyXG5cclxuXHRcdHRoaXMuZ2FpbiA9IHRoaXMuY29udGV4dC5jcmVhdGVHYWluKCk7XHJcblx0XHR0aGlzLmdhaW4uY29ubmVjdCggbGlzdGVuZXIuZ2V0SW5wdXQoKSApO1xyXG5cclxuXHRcdHRoaXMuYXV0b3BsYXkgPSBmYWxzZTtcclxuXHJcblx0XHR0aGlzLmJ1ZmZlciA9IG51bGw7XHJcblx0XHR0aGlzLmRldHVuZSA9IDA7XHJcblx0XHR0aGlzLmxvb3AgPSBmYWxzZTtcclxuXHRcdHRoaXMubG9vcFN0YXJ0ID0gMDtcclxuXHRcdHRoaXMubG9vcEVuZCA9IDA7XHJcblx0XHR0aGlzLm9mZnNldCA9IDA7XHJcblx0XHR0aGlzLmR1cmF0aW9uID0gdW5kZWZpbmVkO1xyXG5cdFx0dGhpcy5wbGF5YmFja1JhdGUgPSAxO1xyXG5cdFx0dGhpcy5pc1BsYXlpbmcgPSBmYWxzZTtcclxuXHRcdHRoaXMuaGFzUGxheWJhY2tDb250cm9sID0gdHJ1ZTtcclxuXHRcdHRoaXMuc291cmNlID0gbnVsbDtcclxuXHRcdHRoaXMuc291cmNlVHlwZSA9ICdlbXB0eSc7XHJcblxyXG5cdFx0dGhpcy5fc3RhcnRlZEF0ID0gMDtcclxuXHRcdHRoaXMuX3Byb2dyZXNzID0gMDtcclxuXHRcdHRoaXMuX2Nvbm5lY3RlZCA9IGZhbHNlO1xyXG5cclxuXHRcdHRoaXMuZmlsdGVycyA9IFtdO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldE91dHB1dCgpIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5nYWluO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldE5vZGVTb3VyY2UoIGF1ZGlvTm9kZSApIHtcclxuXHJcblx0XHR0aGlzLmhhc1BsYXliYWNrQ29udHJvbCA9IGZhbHNlO1xyXG5cdFx0dGhpcy5zb3VyY2VUeXBlID0gJ2F1ZGlvTm9kZSc7XHJcblx0XHR0aGlzLnNvdXJjZSA9IGF1ZGlvTm9kZTtcclxuXHRcdHRoaXMuY29ubmVjdCgpO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldE1lZGlhRWxlbWVudFNvdXJjZSggbWVkaWFFbGVtZW50ICkge1xyXG5cclxuXHRcdHRoaXMuaGFzUGxheWJhY2tDb250cm9sID0gZmFsc2U7XHJcblx0XHR0aGlzLnNvdXJjZVR5cGUgPSAnbWVkaWFOb2RlJztcclxuXHRcdHRoaXMuc291cmNlID0gdGhpcy5jb250ZXh0LmNyZWF0ZU1lZGlhRWxlbWVudFNvdXJjZSggbWVkaWFFbGVtZW50ICk7XHJcblx0XHR0aGlzLmNvbm5lY3QoKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRNZWRpYVN0cmVhbVNvdXJjZSggbWVkaWFTdHJlYW0gKSB7XHJcblxyXG5cdFx0dGhpcy5oYXNQbGF5YmFja0NvbnRyb2wgPSBmYWxzZTtcclxuXHRcdHRoaXMuc291cmNlVHlwZSA9ICdtZWRpYVN0cmVhbU5vZGUnO1xyXG5cdFx0dGhpcy5zb3VyY2UgPSB0aGlzLmNvbnRleHQuY3JlYXRlTWVkaWFTdHJlYW1Tb3VyY2UoIG1lZGlhU3RyZWFtICk7XHJcblx0XHR0aGlzLmNvbm5lY3QoKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRCdWZmZXIoIGF1ZGlvQnVmZmVyICkge1xyXG5cclxuXHRcdHRoaXMuYnVmZmVyID0gYXVkaW9CdWZmZXI7XHJcblx0XHR0aGlzLnNvdXJjZVR5cGUgPSAnYnVmZmVyJztcclxuXHJcblx0XHRpZiAoIHRoaXMuYXV0b3BsYXkgKSB0aGlzLnBsYXkoKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRwbGF5KCBkZWxheSA9IDAgKSB7XHJcblxyXG5cdFx0aWYgKCB0aGlzLmlzUGxheWluZyA9PT0gdHJ1ZSApIHtcclxuXHJcblx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLkF1ZGlvOiBBdWRpbyBpcyBhbHJlYWR5IHBsYXlpbmcuJyApO1xyXG5cdFx0XHRyZXR1cm47XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggdGhpcy5oYXNQbGF5YmFja0NvbnRyb2wgPT09IGZhbHNlICkge1xyXG5cclxuXHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuQXVkaW86IHRoaXMgQXVkaW8gaGFzIG5vIHBsYXliYWNrIGNvbnRyb2wuJyApO1xyXG5cdFx0XHRyZXR1cm47XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMuX3N0YXJ0ZWRBdCA9IHRoaXMuY29udGV4dC5jdXJyZW50VGltZSArIGRlbGF5O1xyXG5cclxuXHRcdGNvbnN0IHNvdXJjZSA9IHRoaXMuY29udGV4dC5jcmVhdGVCdWZmZXJTb3VyY2UoKTtcclxuXHRcdHNvdXJjZS5idWZmZXIgPSB0aGlzLmJ1ZmZlcjtcclxuXHRcdHNvdXJjZS5sb29wID0gdGhpcy5sb29wO1xyXG5cdFx0c291cmNlLmxvb3BTdGFydCA9IHRoaXMubG9vcFN0YXJ0O1xyXG5cdFx0c291cmNlLmxvb3BFbmQgPSB0aGlzLmxvb3BFbmQ7XHJcblx0XHRzb3VyY2Uub25lbmRlZCA9IHRoaXMub25FbmRlZC5iaW5kKCB0aGlzICk7XHJcblx0XHRzb3VyY2Uuc3RhcnQoIHRoaXMuX3N0YXJ0ZWRBdCwgdGhpcy5fcHJvZ3Jlc3MgKyB0aGlzLm9mZnNldCwgdGhpcy5kdXJhdGlvbiApO1xyXG5cclxuXHRcdHRoaXMuaXNQbGF5aW5nID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLnNvdXJjZSA9IHNvdXJjZTtcclxuXHJcblx0XHR0aGlzLnNldERldHVuZSggdGhpcy5kZXR1bmUgKTtcclxuXHRcdHRoaXMuc2V0UGxheWJhY2tSYXRlKCB0aGlzLnBsYXliYWNrUmF0ZSApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzLmNvbm5lY3QoKTtcclxuXHJcblx0fVxyXG5cclxuXHRwYXVzZSgpIHtcclxuXHJcblx0XHRpZiAoIHRoaXMuaGFzUGxheWJhY2tDb250cm9sID09PSBmYWxzZSApIHtcclxuXHJcblx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLkF1ZGlvOiB0aGlzIEF1ZGlvIGhhcyBubyBwbGF5YmFjayBjb250cm9sLicgKTtcclxuXHRcdFx0cmV0dXJuO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHRoaXMuaXNQbGF5aW5nID09PSB0cnVlICkge1xyXG5cclxuXHRcdFx0Ly8gdXBkYXRlIGN1cnJlbnQgcHJvZ3Jlc3NcclxuXHJcblx0XHRcdHRoaXMuX3Byb2dyZXNzICs9IE1hdGgubWF4KCB0aGlzLmNvbnRleHQuY3VycmVudFRpbWUgLSB0aGlzLl9zdGFydGVkQXQsIDAgKSAqIHRoaXMucGxheWJhY2tSYXRlO1xyXG5cclxuXHRcdFx0aWYgKCB0aGlzLmxvb3AgPT09IHRydWUgKSB7XHJcblxyXG5cdFx0XHRcdC8vIGVuc3VyZSBfcHJvZ3Jlc3MgZG9lcyBub3QgZXhjZWVkIGR1cmF0aW9uIHdpdGggbG9vcGVkIGF1ZGlvc1xyXG5cclxuXHRcdFx0XHR0aGlzLl9wcm9ncmVzcyA9IHRoaXMuX3Byb2dyZXNzICUgKCB0aGlzLmR1cmF0aW9uIHx8IHRoaXMuYnVmZmVyLmR1cmF0aW9uICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHR0aGlzLnNvdXJjZS5zdG9wKCk7XHJcblx0XHRcdHRoaXMuc291cmNlLm9uZW5kZWQgPSBudWxsO1xyXG5cclxuXHRcdFx0dGhpcy5pc1BsYXlpbmcgPSBmYWxzZTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0c3RvcCgpIHtcclxuXHJcblx0XHRpZiAoIHRoaXMuaGFzUGxheWJhY2tDb250cm9sID09PSBmYWxzZSApIHtcclxuXHJcblx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLkF1ZGlvOiB0aGlzIEF1ZGlvIGhhcyBubyBwbGF5YmFjayBjb250cm9sLicgKTtcclxuXHRcdFx0cmV0dXJuO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLl9wcm9ncmVzcyA9IDA7XHJcblxyXG5cdFx0aWYgKCB0aGlzLnNvdXJjZSAhPT0gbnVsbCApIHtcclxuXHJcblx0XHRcdHRoaXMuc291cmNlLnN0b3AoKTtcclxuXHRcdFx0dGhpcy5zb3VyY2Uub25lbmRlZCA9IG51bGw7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMuaXNQbGF5aW5nID0gZmFsc2U7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Y29ubmVjdCgpIHtcclxuXHJcblx0XHRpZiAoIHRoaXMuZmlsdGVycy5sZW5ndGggPiAwICkge1xyXG5cclxuXHRcdFx0dGhpcy5zb3VyY2UuY29ubmVjdCggdGhpcy5maWx0ZXJzWyAwIF0gKTtcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMSwgbCA9IHRoaXMuZmlsdGVycy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHR0aGlzLmZpbHRlcnNbIGkgLSAxIF0uY29ubmVjdCggdGhpcy5maWx0ZXJzWyBpIF0gKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHRoaXMuZmlsdGVyc1sgdGhpcy5maWx0ZXJzLmxlbmd0aCAtIDEgXS5jb25uZWN0KCB0aGlzLmdldE91dHB1dCgpICk7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdHRoaXMuc291cmNlLmNvbm5lY3QoIHRoaXMuZ2V0T3V0cHV0KCkgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5fY29ubmVjdGVkID0gdHJ1ZTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRkaXNjb25uZWN0KCkge1xyXG5cclxuXHRcdGlmICggdGhpcy5fY29ubmVjdGVkID09PSBmYWxzZSApIHtcclxuXHJcblx0XHRcdHJldHVybjtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCB0aGlzLmZpbHRlcnMubGVuZ3RoID4gMCApIHtcclxuXHJcblx0XHRcdHRoaXMuc291cmNlLmRpc2Nvbm5lY3QoIHRoaXMuZmlsdGVyc1sgMCBdICk7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDEsIGwgPSB0aGlzLmZpbHRlcnMubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0dGhpcy5maWx0ZXJzWyBpIC0gMSBdLmRpc2Nvbm5lY3QoIHRoaXMuZmlsdGVyc1sgaSBdICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHR0aGlzLmZpbHRlcnNbIHRoaXMuZmlsdGVycy5sZW5ndGggLSAxIF0uZGlzY29ubmVjdCggdGhpcy5nZXRPdXRwdXQoKSApO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHR0aGlzLnNvdXJjZS5kaXNjb25uZWN0KCB0aGlzLmdldE91dHB1dCgpICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMuX2Nvbm5lY3RlZCA9IGZhbHNlO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldEZpbHRlcnMoKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuZmlsdGVycztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRGaWx0ZXJzKCB2YWx1ZSApIHtcclxuXHJcblx0XHRpZiAoICEgdmFsdWUgKSB2YWx1ZSA9IFtdO1xyXG5cclxuXHRcdGlmICggdGhpcy5fY29ubmVjdGVkID09PSB0cnVlICkge1xyXG5cclxuXHRcdFx0dGhpcy5kaXNjb25uZWN0KCk7XHJcblx0XHRcdHRoaXMuZmlsdGVycyA9IHZhbHVlLnNsaWNlKCk7XHJcblx0XHRcdHRoaXMuY29ubmVjdCgpO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHR0aGlzLmZpbHRlcnMgPSB2YWx1ZS5zbGljZSgpO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXREZXR1bmUoIHZhbHVlICkge1xyXG5cclxuXHRcdHRoaXMuZGV0dW5lID0gdmFsdWU7XHJcblxyXG5cdFx0aWYgKCB0aGlzLmlzUGxheWluZyA9PT0gdHJ1ZSAmJiB0aGlzLnNvdXJjZS5kZXR1bmUgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdHRoaXMuc291cmNlLmRldHVuZS5zZXRUYXJnZXRBdFRpbWUoIHRoaXMuZGV0dW5lLCB0aGlzLmNvbnRleHQuY3VycmVudFRpbWUsIDAuMDEgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0RGV0dW5lKCkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLmRldHVuZTtcclxuXHJcblx0fVxyXG5cclxuXHRnZXRGaWx0ZXIoKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuZ2V0RmlsdGVycygpWyAwIF07XHJcblxyXG5cdH1cclxuXHJcblx0c2V0RmlsdGVyKCBmaWx0ZXIgKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuc2V0RmlsdGVycyggZmlsdGVyID8gWyBmaWx0ZXIgXSA6IFtdICk7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0UGxheWJhY2tSYXRlKCB2YWx1ZSApIHtcclxuXHJcblx0XHRpZiAoIHRoaXMuaGFzUGxheWJhY2tDb250cm9sID09PSBmYWxzZSApIHtcclxuXHJcblx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLkF1ZGlvOiB0aGlzIEF1ZGlvIGhhcyBubyBwbGF5YmFjayBjb250cm9sLicgKTtcclxuXHRcdFx0cmV0dXJuO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLnBsYXliYWNrUmF0ZSA9IHZhbHVlO1xyXG5cclxuXHRcdGlmICggdGhpcy5pc1BsYXlpbmcgPT09IHRydWUgKSB7XHJcblxyXG5cdFx0XHR0aGlzLnNvdXJjZS5wbGF5YmFja1JhdGUuc2V0VGFyZ2V0QXRUaW1lKCB0aGlzLnBsYXliYWNrUmF0ZSwgdGhpcy5jb250ZXh0LmN1cnJlbnRUaW1lLCAwLjAxICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldFBsYXliYWNrUmF0ZSgpIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5wbGF5YmFja1JhdGU7XHJcblxyXG5cdH1cclxuXHJcblx0b25FbmRlZCgpIHtcclxuXHJcblx0XHR0aGlzLmlzUGxheWluZyA9IGZhbHNlO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldExvb3AoKSB7XHJcblxyXG5cdFx0aWYgKCB0aGlzLmhhc1BsYXliYWNrQ29udHJvbCA9PT0gZmFsc2UgKSB7XHJcblxyXG5cdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5BdWRpbzogdGhpcyBBdWRpbyBoYXMgbm8gcGxheWJhY2sgY29udHJvbC4nICk7XHJcblx0XHRcdHJldHVybiBmYWxzZTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMubG9vcDtcclxuXHJcblx0fVxyXG5cclxuXHRzZXRMb29wKCB2YWx1ZSApIHtcclxuXHJcblx0XHRpZiAoIHRoaXMuaGFzUGxheWJhY2tDb250cm9sID09PSBmYWxzZSApIHtcclxuXHJcblx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLkF1ZGlvOiB0aGlzIEF1ZGlvIGhhcyBubyBwbGF5YmFjayBjb250cm9sLicgKTtcclxuXHRcdFx0cmV0dXJuO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLmxvb3AgPSB2YWx1ZTtcclxuXHJcblx0XHRpZiAoIHRoaXMuaXNQbGF5aW5nID09PSB0cnVlICkge1xyXG5cclxuXHRcdFx0dGhpcy5zb3VyY2UubG9vcCA9IHRoaXMubG9vcDtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0TG9vcFN0YXJ0KCB2YWx1ZSApIHtcclxuXHJcblx0XHR0aGlzLmxvb3BTdGFydCA9IHZhbHVlO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldExvb3BFbmQoIHZhbHVlICkge1xyXG5cclxuXHRcdHRoaXMubG9vcEVuZCA9IHZhbHVlO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldFZvbHVtZSgpIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5nYWluLmdhaW4udmFsdWU7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0Vm9sdW1lKCB2YWx1ZSApIHtcclxuXHJcblx0XHR0aGlzLmdhaW4uZ2Fpbi5zZXRUYXJnZXRBdFRpbWUoIHZhbHVlLCB0aGlzLmNvbnRleHQuY3VycmVudFRpbWUsIDAuMDEgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgQXVkaW8gfTtcclxuIiwiaW1wb3J0IHsgVmVjdG9yMyB9IGZyb20gJy4uL21hdGgvVmVjdG9yMy5qcyc7XHJcbmltcG9ydCB7IFF1YXRlcm5pb24gfSBmcm9tICcuLi9tYXRoL1F1YXRlcm5pb24uanMnO1xyXG5pbXBvcnQgeyBBdWRpbyB9IGZyb20gJy4vQXVkaW8uanMnO1xyXG5cclxuY29uc3QgX3Bvc2l0aW9uID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5jb25zdCBfcXVhdGVybmlvbiA9IC8qQF9fUFVSRV9fKi8gbmV3IFF1YXRlcm5pb24oKTtcclxuY29uc3QgX3NjYWxlID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5jb25zdCBfb3JpZW50YXRpb24gPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XHJcblxyXG5jbGFzcyBQb3NpdGlvbmFsQXVkaW8gZXh0ZW5kcyBBdWRpbyB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBsaXN0ZW5lciApIHtcclxuXHJcblx0XHRzdXBlciggbGlzdGVuZXIgKTtcclxuXHJcblx0XHR0aGlzLnBhbm5lciA9IHRoaXMuY29udGV4dC5jcmVhdGVQYW5uZXIoKTtcclxuXHRcdHRoaXMucGFubmVyLnBhbm5pbmdNb2RlbCA9ICdIUlRGJztcclxuXHRcdHRoaXMucGFubmVyLmNvbm5lY3QoIHRoaXMuZ2FpbiApO1xyXG5cclxuXHR9XHJcblxyXG5cdGNvbm5lY3QoKSB7XHJcblxyXG5cdFx0c3VwZXIuY29ubmVjdCgpO1xyXG5cclxuXHRcdHRoaXMucGFubmVyLmNvbm5lY3QoIHRoaXMuZ2FpbiApO1xyXG5cclxuXHR9XHJcblxyXG5cdGRpc2Nvbm5lY3QoKSB7XHJcblxyXG5cdFx0c3VwZXIuZGlzY29ubmVjdCgpO1xyXG5cclxuXHRcdHRoaXMucGFubmVyLmRpc2Nvbm5lY3QoIHRoaXMuZ2FpbiApO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldE91dHB1dCgpIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5wYW5uZXI7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0UmVmRGlzdGFuY2UoKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMucGFubmVyLnJlZkRpc3RhbmNlO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldFJlZkRpc3RhbmNlKCB2YWx1ZSApIHtcclxuXHJcblx0XHR0aGlzLnBhbm5lci5yZWZEaXN0YW5jZSA9IHZhbHVlO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldFJvbGxvZmZGYWN0b3IoKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMucGFubmVyLnJvbGxvZmZGYWN0b3I7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0Um9sbG9mZkZhY3RvciggdmFsdWUgKSB7XHJcblxyXG5cdFx0dGhpcy5wYW5uZXIucm9sbG9mZkZhY3RvciA9IHZhbHVlO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldERpc3RhbmNlTW9kZWwoKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMucGFubmVyLmRpc3RhbmNlTW9kZWw7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0RGlzdGFuY2VNb2RlbCggdmFsdWUgKSB7XHJcblxyXG5cdFx0dGhpcy5wYW5uZXIuZGlzdGFuY2VNb2RlbCA9IHZhbHVlO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldE1heERpc3RhbmNlKCkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLnBhbm5lci5tYXhEaXN0YW5jZTtcclxuXHJcblx0fVxyXG5cclxuXHRzZXRNYXhEaXN0YW5jZSggdmFsdWUgKSB7XHJcblxyXG5cdFx0dGhpcy5wYW5uZXIubWF4RGlzdGFuY2UgPSB2YWx1ZTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXREaXJlY3Rpb25hbENvbmUoIGNvbmVJbm5lckFuZ2xlLCBjb25lT3V0ZXJBbmdsZSwgY29uZU91dGVyR2FpbiApIHtcclxuXHJcblx0XHR0aGlzLnBhbm5lci5jb25lSW5uZXJBbmdsZSA9IGNvbmVJbm5lckFuZ2xlO1xyXG5cdFx0dGhpcy5wYW5uZXIuY29uZU91dGVyQW5nbGUgPSBjb25lT3V0ZXJBbmdsZTtcclxuXHRcdHRoaXMucGFubmVyLmNvbmVPdXRlckdhaW4gPSBjb25lT3V0ZXJHYWluO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHVwZGF0ZU1hdHJpeFdvcmxkKCBmb3JjZSApIHtcclxuXHJcblx0XHRzdXBlci51cGRhdGVNYXRyaXhXb3JsZCggZm9yY2UgKTtcclxuXHJcblx0XHRpZiAoIHRoaXMuaGFzUGxheWJhY2tDb250cm9sID09PSB0cnVlICYmIHRoaXMuaXNQbGF5aW5nID09PSBmYWxzZSApIHJldHVybjtcclxuXHJcblx0XHR0aGlzLm1hdHJpeFdvcmxkLmRlY29tcG9zZSggX3Bvc2l0aW9uLCBfcXVhdGVybmlvbiwgX3NjYWxlICk7XHJcblxyXG5cdFx0X29yaWVudGF0aW9uLnNldCggMCwgMCwgMSApLmFwcGx5UXVhdGVybmlvbiggX3F1YXRlcm5pb24gKTtcclxuXHJcblx0XHRjb25zdCBwYW5uZXIgPSB0aGlzLnBhbm5lcjtcclxuXHJcblx0XHRpZiAoIHBhbm5lci5wb3NpdGlvblggKSB7XHJcblxyXG5cdFx0XHQvLyBjb2RlIHBhdGggZm9yIENocm9tZSBhbmQgRmlyZWZveCAoc2VlICMxNDM5MylcclxuXHJcblx0XHRcdGNvbnN0IGVuZFRpbWUgPSB0aGlzLmNvbnRleHQuY3VycmVudFRpbWUgKyB0aGlzLmxpc3RlbmVyLnRpbWVEZWx0YTtcclxuXHJcblx0XHRcdHBhbm5lci5wb3NpdGlvblgubGluZWFyUmFtcFRvVmFsdWVBdFRpbWUoIF9wb3NpdGlvbi54LCBlbmRUaW1lICk7XHJcblx0XHRcdHBhbm5lci5wb3NpdGlvblkubGluZWFyUmFtcFRvVmFsdWVBdFRpbWUoIF9wb3NpdGlvbi55LCBlbmRUaW1lICk7XHJcblx0XHRcdHBhbm5lci5wb3NpdGlvbloubGluZWFyUmFtcFRvVmFsdWVBdFRpbWUoIF9wb3NpdGlvbi56LCBlbmRUaW1lICk7XHJcblx0XHRcdHBhbm5lci5vcmllbnRhdGlvblgubGluZWFyUmFtcFRvVmFsdWVBdFRpbWUoIF9vcmllbnRhdGlvbi54LCBlbmRUaW1lICk7XHJcblx0XHRcdHBhbm5lci5vcmllbnRhdGlvblkubGluZWFyUmFtcFRvVmFsdWVBdFRpbWUoIF9vcmllbnRhdGlvbi55LCBlbmRUaW1lICk7XHJcblx0XHRcdHBhbm5lci5vcmllbnRhdGlvbloubGluZWFyUmFtcFRvVmFsdWVBdFRpbWUoIF9vcmllbnRhdGlvbi56LCBlbmRUaW1lICk7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdHBhbm5lci5zZXRQb3NpdGlvbiggX3Bvc2l0aW9uLngsIF9wb3NpdGlvbi55LCBfcG9zaXRpb24ueiApO1xyXG5cdFx0XHRwYW5uZXIuc2V0T3JpZW50YXRpb24oIF9vcmllbnRhdGlvbi54LCBfb3JpZW50YXRpb24ueSwgX29yaWVudGF0aW9uLnogKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IFBvc2l0aW9uYWxBdWRpbyB9O1xyXG4iLCJjbGFzcyBBdWRpb0FuYWx5c2VyIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIGF1ZGlvLCBmZnRTaXplID0gMjA0OCApIHtcclxuXHJcblx0XHR0aGlzLmFuYWx5c2VyID0gYXVkaW8uY29udGV4dC5jcmVhdGVBbmFseXNlcigpO1xyXG5cdFx0dGhpcy5hbmFseXNlci5mZnRTaXplID0gZmZ0U2l6ZTtcclxuXHJcblx0XHR0aGlzLmRhdGEgPSBuZXcgVWludDhBcnJheSggdGhpcy5hbmFseXNlci5mcmVxdWVuY3lCaW5Db3VudCApO1xyXG5cclxuXHRcdGF1ZGlvLmdldE91dHB1dCgpLmNvbm5lY3QoIHRoaXMuYW5hbHlzZXIgKTtcclxuXHJcblx0fVxyXG5cclxuXHJcblx0Z2V0RnJlcXVlbmN5RGF0YSgpIHtcclxuXHJcblx0XHR0aGlzLmFuYWx5c2VyLmdldEJ5dGVGcmVxdWVuY3lEYXRhKCB0aGlzLmRhdGEgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5kYXRhO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldEF2ZXJhZ2VGcmVxdWVuY3koKSB7XHJcblxyXG5cdFx0bGV0IHZhbHVlID0gMDtcclxuXHRcdGNvbnN0IGRhdGEgPSB0aGlzLmdldEZyZXF1ZW5jeURhdGEoKTtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBkYXRhLmxlbmd0aDsgaSArKyApIHtcclxuXHJcblx0XHRcdHZhbHVlICs9IGRhdGFbIGkgXTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHZhbHVlIC8gZGF0YS5sZW5ndGg7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IEF1ZGlvQW5hbHlzZXIgfTtcclxuIiwiaW1wb3J0IHsgUXVhdGVybmlvbiB9IGZyb20gJy4uL21hdGgvUXVhdGVybmlvbi5qcyc7XHJcblxyXG5jbGFzcyBQcm9wZXJ0eU1peGVyIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIGJpbmRpbmcsIHR5cGVOYW1lLCB2YWx1ZVNpemUgKSB7XHJcblxyXG5cdFx0dGhpcy5iaW5kaW5nID0gYmluZGluZztcclxuXHRcdHRoaXMudmFsdWVTaXplID0gdmFsdWVTaXplO1xyXG5cclxuXHRcdGxldCBtaXhGdW5jdGlvbixcclxuXHRcdFx0bWl4RnVuY3Rpb25BZGRpdGl2ZSxcclxuXHRcdFx0c2V0SWRlbnRpdHk7XHJcblxyXG5cdFx0Ly8gYnVmZmVyIGxheW91dDogWyBpbmNvbWluZyB8IGFjY3UwIHwgYWNjdTEgfCBvcmlnIHwgYWRkQWNjdSB8IChvcHRpb25hbCB3b3JrKSBdXHJcblx0XHQvL1xyXG5cdFx0Ly8gaW50ZXJwb2xhdG9ycyBjYW4gdXNlIC5idWZmZXIgYXMgdGhlaXIgLnJlc3VsdFxyXG5cdFx0Ly8gdGhlIGRhdGEgdGhlbiBnb2VzIHRvICdpbmNvbWluZydcclxuXHRcdC8vXHJcblx0XHQvLyAnYWNjdTAnIGFuZCAnYWNjdTEnIGFyZSB1c2VkIGZyYW1lLWludGVybGVhdmVkIGZvclxyXG5cdFx0Ly8gdGhlIGN1bXVsYXRpdmUgcmVzdWx0IGFuZCBhcmUgY29tcGFyZWQgdG8gZGV0ZWN0XHJcblx0XHQvLyBjaGFuZ2VzXHJcblx0XHQvL1xyXG5cdFx0Ly8gJ29yaWcnIHN0b3JlcyB0aGUgb3JpZ2luYWwgc3RhdGUgb2YgdGhlIHByb3BlcnR5XHJcblx0XHQvL1xyXG5cdFx0Ly8gJ2FkZCcgaXMgdXNlZCBmb3IgYWRkaXRpdmUgY3VtdWxhdGl2ZSByZXN1bHRzXHJcblx0XHQvL1xyXG5cdFx0Ly8gJ3dvcmsnIGlzIG9wdGlvbmFsIGFuZCBpcyBvbmx5IHByZXNlbnQgZm9yIHF1YXRlcm5pb24gdHlwZXMuIEl0IGlzIHVzZWRcclxuXHRcdC8vIHRvIHN0b3JlIGludGVybWVkaWF0ZSBxdWF0ZXJuaW9uIG11bHRpcGxpY2F0aW9uIHJlc3VsdHNcclxuXHJcblx0XHRzd2l0Y2ggKCB0eXBlTmFtZSApIHtcclxuXHJcblx0XHRcdGNhc2UgJ3F1YXRlcm5pb24nOlxyXG5cdFx0XHRcdG1peEZ1bmN0aW9uID0gdGhpcy5fc2xlcnA7XHJcblx0XHRcdFx0bWl4RnVuY3Rpb25BZGRpdGl2ZSA9IHRoaXMuX3NsZXJwQWRkaXRpdmU7XHJcblx0XHRcdFx0c2V0SWRlbnRpdHkgPSB0aGlzLl9zZXRBZGRpdGl2ZUlkZW50aXR5UXVhdGVybmlvbjtcclxuXHJcblx0XHRcdFx0dGhpcy5idWZmZXIgPSBuZXcgRmxvYXQ2NEFycmF5KCB2YWx1ZVNpemUgKiA2ICk7XHJcblx0XHRcdFx0dGhpcy5fd29ya0luZGV4ID0gNTtcclxuXHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdGNhc2UgJ3N0cmluZyc6XHJcblx0XHRcdGNhc2UgJ2Jvb2wnOlxyXG5cdFx0XHRcdG1peEZ1bmN0aW9uID0gdGhpcy5fc2VsZWN0O1xyXG5cclxuXHRcdFx0XHQvLyBVc2UgdGhlIHJlZ3VsYXIgbWl4IGZ1bmN0aW9uIGFuZCBmb3IgYWRkaXRpdmUgb24gdGhlc2UgdHlwZXMsXHJcblx0XHRcdFx0Ly8gYWRkaXRpdmUgaXMgbm90IHJlbGV2YW50IGZvciBub24tbnVtZXJpYyB0eXBlc1xyXG5cdFx0XHRcdG1peEZ1bmN0aW9uQWRkaXRpdmUgPSB0aGlzLl9zZWxlY3Q7XHJcblxyXG5cdFx0XHRcdHNldElkZW50aXR5ID0gdGhpcy5fc2V0QWRkaXRpdmVJZGVudGl0eU90aGVyO1xyXG5cclxuXHRcdFx0XHR0aGlzLmJ1ZmZlciA9IG5ldyBBcnJheSggdmFsdWVTaXplICogNSApO1xyXG5cdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0ZGVmYXVsdDpcclxuXHRcdFx0XHRtaXhGdW5jdGlvbiA9IHRoaXMuX2xlcnA7XHJcblx0XHRcdFx0bWl4RnVuY3Rpb25BZGRpdGl2ZSA9IHRoaXMuX2xlcnBBZGRpdGl2ZTtcclxuXHRcdFx0XHRzZXRJZGVudGl0eSA9IHRoaXMuX3NldEFkZGl0aXZlSWRlbnRpdHlOdW1lcmljO1xyXG5cclxuXHRcdFx0XHR0aGlzLmJ1ZmZlciA9IG5ldyBGbG9hdDY0QXJyYXkoIHZhbHVlU2l6ZSAqIDUgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5fbWl4QnVmZmVyUmVnaW9uID0gbWl4RnVuY3Rpb247XHJcblx0XHR0aGlzLl9taXhCdWZmZXJSZWdpb25BZGRpdGl2ZSA9IG1peEZ1bmN0aW9uQWRkaXRpdmU7XHJcblx0XHR0aGlzLl9zZXRJZGVudGl0eSA9IHNldElkZW50aXR5O1xyXG5cdFx0dGhpcy5fb3JpZ0luZGV4ID0gMztcclxuXHRcdHRoaXMuX2FkZEluZGV4ID0gNDtcclxuXHJcblx0XHR0aGlzLmN1bXVsYXRpdmVXZWlnaHQgPSAwO1xyXG5cdFx0dGhpcy5jdW11bGF0aXZlV2VpZ2h0QWRkaXRpdmUgPSAwO1xyXG5cclxuXHRcdHRoaXMudXNlQ291bnQgPSAwO1xyXG5cdFx0dGhpcy5yZWZlcmVuY2VDb3VudCA9IDA7XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gYWNjdW11bGF0ZSBkYXRhIGluIHRoZSAnaW5jb21pbmcnIHJlZ2lvbiBpbnRvICdhY2N1PGk+J1xyXG5cdGFjY3VtdWxhdGUoIGFjY3VJbmRleCwgd2VpZ2h0ICkge1xyXG5cclxuXHRcdC8vIG5vdGU6IGhhcHBpbHkgYWNjdW11bGF0aW5nIG5vdGhpbmcgd2hlbiB3ZWlnaHQgPSAwLCB0aGUgY2FsbGVyIGtub3dzXHJcblx0XHQvLyB0aGUgd2VpZ2h0IGFuZCBzaG91bGRuJ3QgaGF2ZSBtYWRlIHRoZSBjYWxsIGluIHRoZSBmaXJzdCBwbGFjZVxyXG5cclxuXHRcdGNvbnN0IGJ1ZmZlciA9IHRoaXMuYnVmZmVyLFxyXG5cdFx0XHRzdHJpZGUgPSB0aGlzLnZhbHVlU2l6ZSxcclxuXHRcdFx0b2Zmc2V0ID0gYWNjdUluZGV4ICogc3RyaWRlICsgc3RyaWRlO1xyXG5cclxuXHRcdGxldCBjdXJyZW50V2VpZ2h0ID0gdGhpcy5jdW11bGF0aXZlV2VpZ2h0O1xyXG5cclxuXHRcdGlmICggY3VycmVudFdlaWdodCA9PT0gMCApIHtcclxuXHJcblx0XHRcdC8vIGFjY3VOIDo9IGluY29taW5nICogd2VpZ2h0XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgIT09IHN0cmlkZTsgKysgaSApIHtcclxuXHJcblx0XHRcdFx0YnVmZmVyWyBvZmZzZXQgKyBpIF0gPSBidWZmZXJbIGkgXTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGN1cnJlbnRXZWlnaHQgPSB3ZWlnaHQ7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdC8vIGFjY3VOIDo9IGFjY3VOICsgaW5jb21pbmcgKiB3ZWlnaHRcclxuXHJcblx0XHRcdGN1cnJlbnRXZWlnaHQgKz0gd2VpZ2h0O1xyXG5cdFx0XHRjb25zdCBtaXggPSB3ZWlnaHQgLyBjdXJyZW50V2VpZ2h0O1xyXG5cdFx0XHR0aGlzLl9taXhCdWZmZXJSZWdpb24oIGJ1ZmZlciwgb2Zmc2V0LCAwLCBtaXgsIHN0cmlkZSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLmN1bXVsYXRpdmVXZWlnaHQgPSBjdXJyZW50V2VpZ2h0O1xyXG5cclxuXHR9XHJcblxyXG5cdC8vIGFjY3VtdWxhdGUgZGF0YSBpbiB0aGUgJ2luY29taW5nJyByZWdpb24gaW50byAnYWRkJ1xyXG5cdGFjY3VtdWxhdGVBZGRpdGl2ZSggd2VpZ2h0ICkge1xyXG5cclxuXHRcdGNvbnN0IGJ1ZmZlciA9IHRoaXMuYnVmZmVyLFxyXG5cdFx0XHRzdHJpZGUgPSB0aGlzLnZhbHVlU2l6ZSxcclxuXHRcdFx0b2Zmc2V0ID0gc3RyaWRlICogdGhpcy5fYWRkSW5kZXg7XHJcblxyXG5cdFx0aWYgKCB0aGlzLmN1bXVsYXRpdmVXZWlnaHRBZGRpdGl2ZSA9PT0gMCApIHtcclxuXHJcblx0XHRcdC8vIGFkZCA9IGlkZW50aXR5XHJcblxyXG5cdFx0XHR0aGlzLl9zZXRJZGVudGl0eSgpO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvLyBhZGQgOj0gYWRkICsgaW5jb21pbmcgKiB3ZWlnaHRcclxuXHJcblx0XHR0aGlzLl9taXhCdWZmZXJSZWdpb25BZGRpdGl2ZSggYnVmZmVyLCBvZmZzZXQsIDAsIHdlaWdodCwgc3RyaWRlICk7XHJcblx0XHR0aGlzLmN1bXVsYXRpdmVXZWlnaHRBZGRpdGl2ZSArPSB3ZWlnaHQ7XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gYXBwbHkgdGhlIHN0YXRlIG9mICdhY2N1PGk+JyB0byB0aGUgYmluZGluZyB3aGVuIGFjY3VzIGRpZmZlclxyXG5cdGFwcGx5KCBhY2N1SW5kZXggKSB7XHJcblxyXG5cdFx0Y29uc3Qgc3RyaWRlID0gdGhpcy52YWx1ZVNpemUsXHJcblx0XHRcdGJ1ZmZlciA9IHRoaXMuYnVmZmVyLFxyXG5cdFx0XHRvZmZzZXQgPSBhY2N1SW5kZXggKiBzdHJpZGUgKyBzdHJpZGUsXHJcblxyXG5cdFx0XHR3ZWlnaHQgPSB0aGlzLmN1bXVsYXRpdmVXZWlnaHQsXHJcblx0XHRcdHdlaWdodEFkZGl0aXZlID0gdGhpcy5jdW11bGF0aXZlV2VpZ2h0QWRkaXRpdmUsXHJcblxyXG5cdFx0XHRiaW5kaW5nID0gdGhpcy5iaW5kaW5nO1xyXG5cclxuXHRcdHRoaXMuY3VtdWxhdGl2ZVdlaWdodCA9IDA7XHJcblx0XHR0aGlzLmN1bXVsYXRpdmVXZWlnaHRBZGRpdGl2ZSA9IDA7XHJcblxyXG5cdFx0aWYgKCB3ZWlnaHQgPCAxICkge1xyXG5cclxuXHRcdFx0Ly8gYWNjdU4gOj0gYWNjdU4gKyBvcmlnaW5hbCAqICggMSAtIGN1bXVsYXRpdmVXZWlnaHQgKVxyXG5cclxuXHRcdFx0Y29uc3Qgb3JpZ2luYWxWYWx1ZU9mZnNldCA9IHN0cmlkZSAqIHRoaXMuX29yaWdJbmRleDtcclxuXHJcblx0XHRcdHRoaXMuX21peEJ1ZmZlclJlZ2lvbihcclxuXHRcdFx0XHRidWZmZXIsIG9mZnNldCwgb3JpZ2luYWxWYWx1ZU9mZnNldCwgMSAtIHdlaWdodCwgc3RyaWRlICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggd2VpZ2h0QWRkaXRpdmUgPiAwICkge1xyXG5cclxuXHRcdFx0Ly8gYWNjdU4gOj0gYWNjdU4gKyBhZGRpdGl2ZSBhY2N1TlxyXG5cclxuXHRcdFx0dGhpcy5fbWl4QnVmZmVyUmVnaW9uQWRkaXRpdmUoIGJ1ZmZlciwgb2Zmc2V0LCB0aGlzLl9hZGRJbmRleCAqIHN0cmlkZSwgMSwgc3RyaWRlICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGZvciAoIGxldCBpID0gc3RyaWRlLCBlID0gc3RyaWRlICsgc3RyaWRlOyBpICE9PSBlOyArKyBpICkge1xyXG5cclxuXHRcdFx0aWYgKCBidWZmZXJbIGkgXSAhPT0gYnVmZmVyWyBpICsgc3RyaWRlIF0gKSB7XHJcblxyXG5cdFx0XHRcdC8vIHZhbHVlIGhhcyBjaGFuZ2VkIC0+IHVwZGF0ZSBzY2VuZSBncmFwaFxyXG5cclxuXHRcdFx0XHRiaW5kaW5nLnNldFZhbHVlKCBidWZmZXIsIG9mZnNldCApO1xyXG5cdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHQvLyByZW1lbWJlciB0aGUgc3RhdGUgb2YgdGhlIGJvdW5kIHByb3BlcnR5IGFuZCBjb3B5IGl0IHRvIGJvdGggYWNjdXNcclxuXHRzYXZlT3JpZ2luYWxTdGF0ZSgpIHtcclxuXHJcblx0XHRjb25zdCBiaW5kaW5nID0gdGhpcy5iaW5kaW5nO1xyXG5cclxuXHRcdGNvbnN0IGJ1ZmZlciA9IHRoaXMuYnVmZmVyLFxyXG5cdFx0XHRzdHJpZGUgPSB0aGlzLnZhbHVlU2l6ZSxcclxuXHJcblx0XHRcdG9yaWdpbmFsVmFsdWVPZmZzZXQgPSBzdHJpZGUgKiB0aGlzLl9vcmlnSW5kZXg7XHJcblxyXG5cdFx0YmluZGluZy5nZXRWYWx1ZSggYnVmZmVyLCBvcmlnaW5hbFZhbHVlT2Zmc2V0ICk7XHJcblxyXG5cdFx0Ly8gYWNjdVswLi4xXSA6PSBvcmlnIC0tIGluaXRpYWxseSBkZXRlY3QgY2hhbmdlcyBhZ2FpbnN0IHRoZSBvcmlnaW5hbFxyXG5cdFx0Zm9yICggbGV0IGkgPSBzdHJpZGUsIGUgPSBvcmlnaW5hbFZhbHVlT2Zmc2V0OyBpICE9PSBlOyArKyBpICkge1xyXG5cclxuXHRcdFx0YnVmZmVyWyBpIF0gPSBidWZmZXJbIG9yaWdpbmFsVmFsdWVPZmZzZXQgKyAoIGkgJSBzdHJpZGUgKSBdO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvLyBBZGQgdG8gaWRlbnRpdHkgZm9yIGFkZGl0aXZlXHJcblx0XHR0aGlzLl9zZXRJZGVudGl0eSgpO1xyXG5cclxuXHRcdHRoaXMuY3VtdWxhdGl2ZVdlaWdodCA9IDA7XHJcblx0XHR0aGlzLmN1bXVsYXRpdmVXZWlnaHRBZGRpdGl2ZSA9IDA7XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gYXBwbHkgdGhlIHN0YXRlIHByZXZpb3VzbHkgdGFrZW4gdmlhICdzYXZlT3JpZ2luYWxTdGF0ZScgdG8gdGhlIGJpbmRpbmdcclxuXHRyZXN0b3JlT3JpZ2luYWxTdGF0ZSgpIHtcclxuXHJcblx0XHRjb25zdCBvcmlnaW5hbFZhbHVlT2Zmc2V0ID0gdGhpcy52YWx1ZVNpemUgKiAzO1xyXG5cdFx0dGhpcy5iaW5kaW5nLnNldFZhbHVlKCB0aGlzLmJ1ZmZlciwgb3JpZ2luYWxWYWx1ZU9mZnNldCApO1xyXG5cclxuXHR9XHJcblxyXG5cdF9zZXRBZGRpdGl2ZUlkZW50aXR5TnVtZXJpYygpIHtcclxuXHJcblx0XHRjb25zdCBzdGFydEluZGV4ID0gdGhpcy5fYWRkSW5kZXggKiB0aGlzLnZhbHVlU2l6ZTtcclxuXHRcdGNvbnN0IGVuZEluZGV4ID0gc3RhcnRJbmRleCArIHRoaXMudmFsdWVTaXplO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gc3RhcnRJbmRleDsgaSA8IGVuZEluZGV4OyBpICsrICkge1xyXG5cclxuXHRcdFx0dGhpcy5idWZmZXJbIGkgXSA9IDA7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdF9zZXRBZGRpdGl2ZUlkZW50aXR5UXVhdGVybmlvbigpIHtcclxuXHJcblx0XHR0aGlzLl9zZXRBZGRpdGl2ZUlkZW50aXR5TnVtZXJpYygpO1xyXG5cdFx0dGhpcy5idWZmZXJbIHRoaXMuX2FkZEluZGV4ICogdGhpcy52YWx1ZVNpemUgKyAzIF0gPSAxO1xyXG5cclxuXHR9XHJcblxyXG5cdF9zZXRBZGRpdGl2ZUlkZW50aXR5T3RoZXIoKSB7XHJcblxyXG5cdFx0Y29uc3Qgc3RhcnRJbmRleCA9IHRoaXMuX29yaWdJbmRleCAqIHRoaXMudmFsdWVTaXplO1xyXG5cdFx0Y29uc3QgdGFyZ2V0SW5kZXggPSB0aGlzLl9hZGRJbmRleCAqIHRoaXMudmFsdWVTaXplO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHRoaXMudmFsdWVTaXplOyBpICsrICkge1xyXG5cclxuXHRcdFx0dGhpcy5idWZmZXJbIHRhcmdldEluZGV4ICsgaSBdID0gdGhpcy5idWZmZXJbIHN0YXJ0SW5kZXggKyBpIF07XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cclxuXHQvLyBtaXggZnVuY3Rpb25zXHJcblxyXG5cdF9zZWxlY3QoIGJ1ZmZlciwgZHN0T2Zmc2V0LCBzcmNPZmZzZXQsIHQsIHN0cmlkZSApIHtcclxuXHJcblx0XHRpZiAoIHQgPj0gMC41ICkge1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpICE9PSBzdHJpZGU7ICsrIGkgKSB7XHJcblxyXG5cdFx0XHRcdGJ1ZmZlclsgZHN0T2Zmc2V0ICsgaSBdID0gYnVmZmVyWyBzcmNPZmZzZXQgKyBpIF07XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdF9zbGVycCggYnVmZmVyLCBkc3RPZmZzZXQsIHNyY09mZnNldCwgdCApIHtcclxuXHJcblx0XHRRdWF0ZXJuaW9uLnNsZXJwRmxhdCggYnVmZmVyLCBkc3RPZmZzZXQsIGJ1ZmZlciwgZHN0T2Zmc2V0LCBidWZmZXIsIHNyY09mZnNldCwgdCApO1xyXG5cclxuXHR9XHJcblxyXG5cdF9zbGVycEFkZGl0aXZlKCBidWZmZXIsIGRzdE9mZnNldCwgc3JjT2Zmc2V0LCB0LCBzdHJpZGUgKSB7XHJcblxyXG5cdFx0Y29uc3Qgd29ya09mZnNldCA9IHRoaXMuX3dvcmtJbmRleCAqIHN0cmlkZTtcclxuXHJcblx0XHQvLyBTdG9yZSByZXN1bHQgaW4gaW50ZXJtZWRpYXRlIGJ1ZmZlciBvZmZzZXRcclxuXHRcdFF1YXRlcm5pb24ubXVsdGlwbHlRdWF0ZXJuaW9uc0ZsYXQoIGJ1ZmZlciwgd29ya09mZnNldCwgYnVmZmVyLCBkc3RPZmZzZXQsIGJ1ZmZlciwgc3JjT2Zmc2V0ICk7XHJcblxyXG5cdFx0Ly8gU2xlcnAgdG8gdGhlIGludGVybWVkaWF0ZSByZXN1bHRcclxuXHRcdFF1YXRlcm5pb24uc2xlcnBGbGF0KCBidWZmZXIsIGRzdE9mZnNldCwgYnVmZmVyLCBkc3RPZmZzZXQsIGJ1ZmZlciwgd29ya09mZnNldCwgdCApO1xyXG5cclxuXHR9XHJcblxyXG5cdF9sZXJwKCBidWZmZXIsIGRzdE9mZnNldCwgc3JjT2Zmc2V0LCB0LCBzdHJpZGUgKSB7XHJcblxyXG5cdFx0Y29uc3QgcyA9IDEgLSB0O1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMDsgaSAhPT0gc3RyaWRlOyArKyBpICkge1xyXG5cclxuXHRcdFx0Y29uc3QgaiA9IGRzdE9mZnNldCArIGk7XHJcblxyXG5cdFx0XHRidWZmZXJbIGogXSA9IGJ1ZmZlclsgaiBdICogcyArIGJ1ZmZlclsgc3JjT2Zmc2V0ICsgaSBdICogdDtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0X2xlcnBBZGRpdGl2ZSggYnVmZmVyLCBkc3RPZmZzZXQsIHNyY09mZnNldCwgdCwgc3RyaWRlICkge1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMDsgaSAhPT0gc3RyaWRlOyArKyBpICkge1xyXG5cclxuXHRcdFx0Y29uc3QgaiA9IGRzdE9mZnNldCArIGk7XHJcblxyXG5cdFx0XHRidWZmZXJbIGogXSA9IGJ1ZmZlclsgaiBdICsgYnVmZmVyWyBzcmNPZmZzZXQgKyBpIF0gKiB0O1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuXHJcbmV4cG9ydCB7IFByb3BlcnR5TWl4ZXIgfTtcclxuIiwiLy8gQ2hhcmFjdGVycyBbXS46LyBhcmUgcmVzZXJ2ZWQgZm9yIHRyYWNrIGJpbmRpbmcgc3ludGF4LlxyXG5jb25zdCBfUkVTRVJWRURfQ0hBUlNfUkUgPSAnXFxcXFtcXFxcXVxcXFwuOlxcXFwvJztcclxuY29uc3QgX3Jlc2VydmVkUmUgPSBuZXcgUmVnRXhwKCAnWycgKyBfUkVTRVJWRURfQ0hBUlNfUkUgKyAnXScsICdnJyApO1xyXG5cclxuLy8gQXR0ZW1wdHMgdG8gYWxsb3cgbm9kZSBuYW1lcyBmcm9tIGFueSBsYW5ndWFnZS4gRVM1J3MgYFxcd2AgcmVnZXhwIG1hdGNoZXNcclxuLy8gb25seSBsYXRpbiBjaGFyYWN0ZXJzLCBhbmQgdGhlIHVuaWNvZGUgXFxwe0x9IGlzIG5vdCB5ZXQgc3VwcG9ydGVkLiBTb1xyXG4vLyBpbnN0ZWFkLCB3ZSBleGNsdWRlIHJlc2VydmVkIGNoYXJhY3RlcnMgYW5kIG1hdGNoIGV2ZXJ5dGhpbmcgZWxzZS5cclxuY29uc3QgX3dvcmRDaGFyID0gJ1teJyArIF9SRVNFUlZFRF9DSEFSU19SRSArICddJztcclxuY29uc3QgX3dvcmRDaGFyT3JEb3QgPSAnW14nICsgX1JFU0VSVkVEX0NIQVJTX1JFLnJlcGxhY2UoICdcXFxcLicsICcnICkgKyAnXSc7XHJcblxyXG4vLyBQYXJlbnQgZGlyZWN0b3JpZXMsIGRlbGltaXRlZCBieSAnLycgb3IgJzonLiBDdXJyZW50bHkgdW51c2VkLCBidXQgbXVzdFxyXG4vLyBiZSBtYXRjaGVkIHRvIHBhcnNlIHRoZSByZXN0IG9mIHRoZSB0cmFjayBuYW1lLlxyXG5jb25zdCBfZGlyZWN0b3J5UmUgPSAvKkBfX1BVUkVfXyovIC8oKD86V0MrW1xcLzpdKSopLy5zb3VyY2UucmVwbGFjZSggJ1dDJywgX3dvcmRDaGFyICk7XHJcblxyXG4vLyBUYXJnZXQgbm9kZS4gTWF5IGNvbnRhaW4gd29yZCBjaGFyYWN0ZXJzIChhLXpBLVowLTlfKSBhbmQgJy4nIG9yICctJy5cclxuY29uc3QgX25vZGVSZSA9IC8qQF9fUFVSRV9fKi8gLyhXQ09EKyk/Ly5zb3VyY2UucmVwbGFjZSggJ1dDT0QnLCBfd29yZENoYXJPckRvdCApO1xyXG5cclxuLy8gT2JqZWN0IG9uIHRhcmdldCBub2RlLCBhbmQgYWNjZXNzb3IuIE1heSBub3QgY29udGFpbiByZXNlcnZlZFxyXG4vLyBjaGFyYWN0ZXJzLiBBY2Nlc3NvciBtYXkgY29udGFpbiBhbnkgY2hhcmFjdGVyIGV4Y2VwdCBjbG9zaW5nIGJyYWNrZXQuXHJcbmNvbnN0IF9vYmplY3RSZSA9IC8qQF9fUFVSRV9fKi8gLyg/OlxcLihXQyspKD86XFxbKC4rKVxcXSk/KT8vLnNvdXJjZS5yZXBsYWNlKCAnV0MnLCBfd29yZENoYXIgKTtcclxuXHJcbi8vIFByb3BlcnR5IGFuZCBhY2Nlc3Nvci4gTWF5IG5vdCBjb250YWluIHJlc2VydmVkIGNoYXJhY3RlcnMuIEFjY2Vzc29yIG1heVxyXG4vLyBjb250YWluIGFueSBub24tYnJhY2tldCBjaGFyYWN0ZXJzLlxyXG5jb25zdCBfcHJvcGVydHlSZSA9IC8qQF9fUFVSRV9fKi8gL1xcLihXQyspKD86XFxbKC4rKVxcXSk/Ly5zb3VyY2UucmVwbGFjZSggJ1dDJywgX3dvcmRDaGFyICk7XHJcblxyXG5jb25zdCBfdHJhY2tSZSA9IG5ldyBSZWdFeHAoICcnXHJcblx0KyAnXidcclxuXHQrIF9kaXJlY3RvcnlSZVxyXG5cdCsgX25vZGVSZVxyXG5cdCsgX29iamVjdFJlXHJcblx0KyBfcHJvcGVydHlSZVxyXG5cdCsgJyQnXHJcbik7XHJcblxyXG5jb25zdCBfc3VwcG9ydGVkT2JqZWN0TmFtZXMgPSBbICdtYXRlcmlhbCcsICdtYXRlcmlhbHMnLCAnYm9uZXMnLCAnbWFwJyBdO1xyXG5cclxuY2xhc3MgQ29tcG9zaXRlIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIHRhcmdldEdyb3VwLCBwYXRoLCBvcHRpb25hbFBhcnNlZFBhdGggKSB7XHJcblxyXG5cdFx0Y29uc3QgcGFyc2VkUGF0aCA9IG9wdGlvbmFsUGFyc2VkUGF0aCB8fCBQcm9wZXJ0eUJpbmRpbmcucGFyc2VUcmFja05hbWUoIHBhdGggKTtcclxuXHJcblx0XHR0aGlzLl90YXJnZXRHcm91cCA9IHRhcmdldEdyb3VwO1xyXG5cdFx0dGhpcy5fYmluZGluZ3MgPSB0YXJnZXRHcm91cC5zdWJzY3JpYmVfKCBwYXRoLCBwYXJzZWRQYXRoICk7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0VmFsdWUoIGFycmF5LCBvZmZzZXQgKSB7XHJcblxyXG5cdFx0dGhpcy5iaW5kKCk7IC8vIGJpbmQgYWxsIGJpbmRpbmdcclxuXHJcblx0XHRjb25zdCBmaXJzdFZhbGlkSW5kZXggPSB0aGlzLl90YXJnZXRHcm91cC5uQ2FjaGVkT2JqZWN0c18sXHJcblx0XHRcdGJpbmRpbmcgPSB0aGlzLl9iaW5kaW5nc1sgZmlyc3RWYWxpZEluZGV4IF07XHJcblxyXG5cdFx0Ly8gYW5kIG9ubHkgY2FsbCAuZ2V0VmFsdWUgb24gdGhlIGZpcnN0XHJcblx0XHRpZiAoIGJpbmRpbmcgIT09IHVuZGVmaW5lZCApIGJpbmRpbmcuZ2V0VmFsdWUoIGFycmF5LCBvZmZzZXQgKTtcclxuXHJcblx0fVxyXG5cclxuXHRzZXRWYWx1ZSggYXJyYXksIG9mZnNldCApIHtcclxuXHJcblx0XHRjb25zdCBiaW5kaW5ncyA9IHRoaXMuX2JpbmRpbmdzO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gdGhpcy5fdGFyZ2V0R3JvdXAubkNhY2hlZE9iamVjdHNfLCBuID0gYmluZGluZ3MubGVuZ3RoOyBpICE9PSBuOyArKyBpICkge1xyXG5cclxuXHRcdFx0YmluZGluZ3NbIGkgXS5zZXRWYWx1ZSggYXJyYXksIG9mZnNldCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRiaW5kKCkge1xyXG5cclxuXHRcdGNvbnN0IGJpbmRpbmdzID0gdGhpcy5fYmluZGluZ3M7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSB0aGlzLl90YXJnZXRHcm91cC5uQ2FjaGVkT2JqZWN0c18sIG4gPSBiaW5kaW5ncy5sZW5ndGg7IGkgIT09IG47ICsrIGkgKSB7XHJcblxyXG5cdFx0XHRiaW5kaW5nc1sgaSBdLmJpbmQoKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0dW5iaW5kKCkge1xyXG5cclxuXHRcdGNvbnN0IGJpbmRpbmdzID0gdGhpcy5fYmluZGluZ3M7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSB0aGlzLl90YXJnZXRHcm91cC5uQ2FjaGVkT2JqZWN0c18sIG4gPSBiaW5kaW5ncy5sZW5ndGg7IGkgIT09IG47ICsrIGkgKSB7XHJcblxyXG5cdFx0XHRiaW5kaW5nc1sgaSBdLnVuYmluZCgpO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuLy8gTm90ZTogVGhpcyBjbGFzcyB1c2VzIGEgU3RhdGUgcGF0dGVybiBvbiBhIHBlci1tZXRob2QgYmFzaXM6XHJcbi8vICdiaW5kJyBzZXRzICd0aGlzLmdldFZhbHVlJyAvICdzZXRWYWx1ZScgYW5kIHNoYWRvd3MgdGhlXHJcbi8vIHByb3RvdHlwZSB2ZXJzaW9uIG9mIHRoZXNlIG1ldGhvZHMgd2l0aCBvbmUgdGhhdCByZXByZXNlbnRzXHJcbi8vIHRoZSBib3VuZCBzdGF0ZS4gV2hlbiB0aGUgcHJvcGVydHkgaXMgbm90IGZvdW5kLCB0aGUgbWV0aG9kc1xyXG4vLyBiZWNvbWUgbm8tb3BzLlxyXG5jbGFzcyBQcm9wZXJ0eUJpbmRpbmcge1xyXG5cclxuXHRjb25zdHJ1Y3Rvciggcm9vdE5vZGUsIHBhdGgsIHBhcnNlZFBhdGggKSB7XHJcblxyXG5cdFx0dGhpcy5wYXRoID0gcGF0aDtcclxuXHRcdHRoaXMucGFyc2VkUGF0aCA9IHBhcnNlZFBhdGggfHwgUHJvcGVydHlCaW5kaW5nLnBhcnNlVHJhY2tOYW1lKCBwYXRoICk7XHJcblxyXG5cdFx0dGhpcy5ub2RlID0gUHJvcGVydHlCaW5kaW5nLmZpbmROb2RlKCByb290Tm9kZSwgdGhpcy5wYXJzZWRQYXRoLm5vZGVOYW1lICk7XHJcblxyXG5cdFx0dGhpcy5yb290Tm9kZSA9IHJvb3ROb2RlO1xyXG5cclxuXHRcdC8vIGluaXRpYWwgc3RhdGUgb2YgdGhlc2UgbWV0aG9kcyB0aGF0IGNhbGxzICdiaW5kJ1xyXG5cdFx0dGhpcy5nZXRWYWx1ZSA9IHRoaXMuX2dldFZhbHVlX3VuYm91bmQ7XHJcblx0XHR0aGlzLnNldFZhbHVlID0gdGhpcy5fc2V0VmFsdWVfdW5ib3VuZDtcclxuXHJcblx0fVxyXG5cclxuXHJcblx0c3RhdGljIGNyZWF0ZSggcm9vdCwgcGF0aCwgcGFyc2VkUGF0aCApIHtcclxuXHJcblx0XHRpZiAoICEgKCByb290ICYmIHJvb3QuaXNBbmltYXRpb25PYmplY3RHcm91cCApICkge1xyXG5cclxuXHRcdFx0cmV0dXJuIG5ldyBQcm9wZXJ0eUJpbmRpbmcoIHJvb3QsIHBhdGgsIHBhcnNlZFBhdGggKTtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0cmV0dXJuIG5ldyBQcm9wZXJ0eUJpbmRpbmcuQ29tcG9zaXRlKCByb290LCBwYXRoLCBwYXJzZWRQYXRoICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdC8qKlxyXG5cdCAqIFJlcGxhY2VzIHNwYWNlcyB3aXRoIHVuZGVyc2NvcmVzIGFuZCByZW1vdmVzIHVuc3VwcG9ydGVkIGNoYXJhY3RlcnMgZnJvbVxyXG5cdCAqIG5vZGUgbmFtZXMsIHRvIGVuc3VyZSBjb21wYXRpYmlsaXR5IHdpdGggcGFyc2VUcmFja05hbWUoKS5cclxuXHQgKlxyXG5cdCAqIEBwYXJhbSB7c3RyaW5nfSBuYW1lIE5vZGUgbmFtZSB0byBiZSBzYW5pdGl6ZWQuXHJcblx0ICogQHJldHVybiB7c3RyaW5nfVxyXG5cdCAqL1xyXG5cdHN0YXRpYyBzYW5pdGl6ZU5vZGVOYW1lKCBuYW1lICkge1xyXG5cclxuXHRcdHJldHVybiBuYW1lLnJlcGxhY2UoIC9cXHMvZywgJ18nICkucmVwbGFjZSggX3Jlc2VydmVkUmUsICcnICk7XHJcblxyXG5cdH1cclxuXHJcblx0c3RhdGljIHBhcnNlVHJhY2tOYW1lKCB0cmFja05hbWUgKSB7XHJcblxyXG5cdFx0Y29uc3QgbWF0Y2hlcyA9IF90cmFja1JlLmV4ZWMoIHRyYWNrTmFtZSApO1xyXG5cclxuXHRcdGlmICggbWF0Y2hlcyA9PT0gbnVsbCApIHtcclxuXHJcblx0XHRcdHRocm93IG5ldyBFcnJvciggJ1Byb3BlcnR5QmluZGluZzogQ2Fubm90IHBhcnNlIHRyYWNrTmFtZTogJyArIHRyYWNrTmFtZSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCByZXN1bHRzID0ge1xyXG5cdFx0XHQvLyBkaXJlY3RvcnlOYW1lOiBtYXRjaGVzWyAxIF0sIC8vICh0c2NodykgY3VycmVudGx5IHVudXNlZFxyXG5cdFx0XHRub2RlTmFtZTogbWF0Y2hlc1sgMiBdLFxyXG5cdFx0XHRvYmplY3ROYW1lOiBtYXRjaGVzWyAzIF0sXHJcblx0XHRcdG9iamVjdEluZGV4OiBtYXRjaGVzWyA0IF0sXHJcblx0XHRcdHByb3BlcnR5TmFtZTogbWF0Y2hlc1sgNSBdLCAvLyByZXF1aXJlZFxyXG5cdFx0XHRwcm9wZXJ0eUluZGV4OiBtYXRjaGVzWyA2IF1cclxuXHRcdH07XHJcblxyXG5cdFx0Y29uc3QgbGFzdERvdCA9IHJlc3VsdHMubm9kZU5hbWUgJiYgcmVzdWx0cy5ub2RlTmFtZS5sYXN0SW5kZXhPZiggJy4nICk7XHJcblxyXG5cdFx0aWYgKCBsYXN0RG90ICE9PSB1bmRlZmluZWQgJiYgbGFzdERvdCAhPT0gLSAxICkge1xyXG5cclxuXHRcdFx0Y29uc3Qgb2JqZWN0TmFtZSA9IHJlc3VsdHMubm9kZU5hbWUuc3Vic3RyaW5nKCBsYXN0RG90ICsgMSApO1xyXG5cclxuXHRcdFx0Ly8gT2JqZWN0IG5hbWVzIG11c3QgYmUgY2hlY2tlZCBhZ2FpbnN0IGFuIGFsbG93bGlzdC4gT3RoZXJ3aXNlLCB0aGVyZVxyXG5cdFx0XHQvLyBpcyBubyB3YXkgdG8gcGFyc2UgJ2Zvby5iYXIuYmF6JzogJ2JheicgbXVzdCBiZSBhIHByb3BlcnR5LCBidXRcclxuXHRcdFx0Ly8gJ2JhcicgY291bGQgYmUgdGhlIG9iamVjdE5hbWUsIG9yIHBhcnQgb2YgYSBub2RlTmFtZSAod2hpY2ggY2FuXHJcblx0XHRcdC8vIGluY2x1ZGUgJy4nIGNoYXJhY3RlcnMpLlxyXG5cdFx0XHRpZiAoIF9zdXBwb3J0ZWRPYmplY3ROYW1lcy5pbmRleE9mKCBvYmplY3ROYW1lICkgIT09IC0gMSApIHtcclxuXHJcblx0XHRcdFx0cmVzdWx0cy5ub2RlTmFtZSA9IHJlc3VsdHMubm9kZU5hbWUuc3Vic3RyaW5nKCAwLCBsYXN0RG90ICk7XHJcblx0XHRcdFx0cmVzdWx0cy5vYmplY3ROYW1lID0gb2JqZWN0TmFtZTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCByZXN1bHRzLnByb3BlcnR5TmFtZSA9PT0gbnVsbCB8fCByZXN1bHRzLnByb3BlcnR5TmFtZS5sZW5ndGggPT09IDAgKSB7XHJcblxyXG5cdFx0XHR0aHJvdyBuZXcgRXJyb3IoICdQcm9wZXJ0eUJpbmRpbmc6IGNhbiBub3QgcGFyc2UgcHJvcGVydHlOYW1lIGZyb20gdHJhY2tOYW1lOiAnICsgdHJhY2tOYW1lICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiByZXN1bHRzO1xyXG5cclxuXHR9XHJcblxyXG5cdHN0YXRpYyBmaW5kTm9kZSggcm9vdCwgbm9kZU5hbWUgKSB7XHJcblxyXG5cdFx0aWYgKCBub2RlTmFtZSA9PT0gdW5kZWZpbmVkIHx8IG5vZGVOYW1lID09PSAnJyB8fCBub2RlTmFtZSA9PT0gJy4nIHx8IG5vZGVOYW1lID09PSAtIDEgfHwgbm9kZU5hbWUgPT09IHJvb3QubmFtZSB8fCBub2RlTmFtZSA9PT0gcm9vdC51dWlkICkge1xyXG5cclxuXHRcdFx0cmV0dXJuIHJvb3Q7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIHNlYXJjaCBpbnRvIHNrZWxldG9uIGJvbmVzLlxyXG5cdFx0aWYgKCByb290LnNrZWxldG9uICkge1xyXG5cclxuXHRcdFx0Y29uc3QgYm9uZSA9IHJvb3Quc2tlbGV0b24uZ2V0Qm9uZUJ5TmFtZSggbm9kZU5hbWUgKTtcclxuXHJcblx0XHRcdGlmICggYm9uZSAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHRyZXR1cm4gYm9uZTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gc2VhcmNoIGludG8gbm9kZSBzdWJ0cmVlLlxyXG5cdFx0aWYgKCByb290LmNoaWxkcmVuICkge1xyXG5cclxuXHRcdFx0Y29uc3Qgc2VhcmNoTm9kZVN1YnRyZWUgPSBmdW5jdGlvbiAoIGNoaWxkcmVuICkge1xyXG5cclxuXHRcdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBjaGlsZHJlbi5sZW5ndGg7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgY2hpbGROb2RlID0gY2hpbGRyZW5bIGkgXTtcclxuXHJcblx0XHRcdFx0XHRpZiAoIGNoaWxkTm9kZS5uYW1lID09PSBub2RlTmFtZSB8fCBjaGlsZE5vZGUudXVpZCA9PT0gbm9kZU5hbWUgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRyZXR1cm4gY2hpbGROb2RlO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRjb25zdCByZXN1bHQgPSBzZWFyY2hOb2RlU3VidHJlZSggY2hpbGROb2RlLmNoaWxkcmVuICk7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCByZXN1bHQgKSByZXR1cm4gcmVzdWx0O1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdHJldHVybiBudWxsO1xyXG5cclxuXHRcdFx0fTtcclxuXHJcblx0XHRcdGNvbnN0IHN1YlRyZWVOb2RlID0gc2VhcmNoTm9kZVN1YnRyZWUoIHJvb3QuY2hpbGRyZW4gKTtcclxuXHJcblx0XHRcdGlmICggc3ViVHJlZU5vZGUgKSB7XHJcblxyXG5cdFx0XHRcdHJldHVybiBzdWJUcmVlTm9kZTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIG51bGw7XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gdGhlc2UgYXJlIHVzZWQgdG8gXCJiaW5kXCIgYSBub25leGlzdGVudCBwcm9wZXJ0eVxyXG5cdF9nZXRWYWx1ZV91bmF2YWlsYWJsZSgpIHt9XHJcblx0X3NldFZhbHVlX3VuYXZhaWxhYmxlKCkge31cclxuXHJcblx0Ly8gR2V0dGVyc1xyXG5cclxuXHRfZ2V0VmFsdWVfZGlyZWN0KCBidWZmZXIsIG9mZnNldCApIHtcclxuXHJcblx0XHRidWZmZXJbIG9mZnNldCBdID0gdGhpcy50YXJnZXRPYmplY3RbIHRoaXMucHJvcGVydHlOYW1lIF07XHJcblxyXG5cdH1cclxuXHJcblx0X2dldFZhbHVlX2FycmF5KCBidWZmZXIsIG9mZnNldCApIHtcclxuXHJcblx0XHRjb25zdCBzb3VyY2UgPSB0aGlzLnJlc29sdmVkUHJvcGVydHk7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBuID0gc291cmNlLmxlbmd0aDsgaSAhPT0gbjsgKysgaSApIHtcclxuXHJcblx0XHRcdGJ1ZmZlclsgb2Zmc2V0ICsrIF0gPSBzb3VyY2VbIGkgXTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0X2dldFZhbHVlX2FycmF5RWxlbWVudCggYnVmZmVyLCBvZmZzZXQgKSB7XHJcblxyXG5cdFx0YnVmZmVyWyBvZmZzZXQgXSA9IHRoaXMucmVzb2x2ZWRQcm9wZXJ0eVsgdGhpcy5wcm9wZXJ0eUluZGV4IF07XHJcblxyXG5cdH1cclxuXHJcblx0X2dldFZhbHVlX3RvQXJyYXkoIGJ1ZmZlciwgb2Zmc2V0ICkge1xyXG5cclxuXHRcdHRoaXMucmVzb2x2ZWRQcm9wZXJ0eS50b0FycmF5KCBidWZmZXIsIG9mZnNldCApO1xyXG5cclxuXHR9XHJcblxyXG5cdC8vIERpcmVjdFxyXG5cclxuXHRfc2V0VmFsdWVfZGlyZWN0KCBidWZmZXIsIG9mZnNldCApIHtcclxuXHJcblx0XHR0aGlzLnRhcmdldE9iamVjdFsgdGhpcy5wcm9wZXJ0eU5hbWUgXSA9IGJ1ZmZlclsgb2Zmc2V0IF07XHJcblxyXG5cdH1cclxuXHJcblx0X3NldFZhbHVlX2RpcmVjdF9zZXROZWVkc1VwZGF0ZSggYnVmZmVyLCBvZmZzZXQgKSB7XHJcblxyXG5cdFx0dGhpcy50YXJnZXRPYmplY3RbIHRoaXMucHJvcGVydHlOYW1lIF0gPSBidWZmZXJbIG9mZnNldCBdO1xyXG5cdFx0dGhpcy50YXJnZXRPYmplY3QubmVlZHNVcGRhdGUgPSB0cnVlO1xyXG5cclxuXHR9XHJcblxyXG5cdF9zZXRWYWx1ZV9kaXJlY3Rfc2V0TWF0cml4V29ybGROZWVkc1VwZGF0ZSggYnVmZmVyLCBvZmZzZXQgKSB7XHJcblxyXG5cdFx0dGhpcy50YXJnZXRPYmplY3RbIHRoaXMucHJvcGVydHlOYW1lIF0gPSBidWZmZXJbIG9mZnNldCBdO1xyXG5cdFx0dGhpcy50YXJnZXRPYmplY3QubWF0cml4V29ybGROZWVkc1VwZGF0ZSA9IHRydWU7XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gRW50aXJlQXJyYXlcclxuXHJcblx0X3NldFZhbHVlX2FycmF5KCBidWZmZXIsIG9mZnNldCApIHtcclxuXHJcblx0XHRjb25zdCBkZXN0ID0gdGhpcy5yZXNvbHZlZFByb3BlcnR5O1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMCwgbiA9IGRlc3QubGVuZ3RoOyBpICE9PSBuOyArKyBpICkge1xyXG5cclxuXHRcdFx0ZGVzdFsgaSBdID0gYnVmZmVyWyBvZmZzZXQgKysgXTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0X3NldFZhbHVlX2FycmF5X3NldE5lZWRzVXBkYXRlKCBidWZmZXIsIG9mZnNldCApIHtcclxuXHJcblx0XHRjb25zdCBkZXN0ID0gdGhpcy5yZXNvbHZlZFByb3BlcnR5O1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMCwgbiA9IGRlc3QubGVuZ3RoOyBpICE9PSBuOyArKyBpICkge1xyXG5cclxuXHRcdFx0ZGVzdFsgaSBdID0gYnVmZmVyWyBvZmZzZXQgKysgXTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy50YXJnZXRPYmplY3QubmVlZHNVcGRhdGUgPSB0cnVlO1xyXG5cclxuXHR9XHJcblxyXG5cdF9zZXRWYWx1ZV9hcnJheV9zZXRNYXRyaXhXb3JsZE5lZWRzVXBkYXRlKCBidWZmZXIsIG9mZnNldCApIHtcclxuXHJcblx0XHRjb25zdCBkZXN0ID0gdGhpcy5yZXNvbHZlZFByb3BlcnR5O1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMCwgbiA9IGRlc3QubGVuZ3RoOyBpICE9PSBuOyArKyBpICkge1xyXG5cclxuXHRcdFx0ZGVzdFsgaSBdID0gYnVmZmVyWyBvZmZzZXQgKysgXTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy50YXJnZXRPYmplY3QubWF0cml4V29ybGROZWVkc1VwZGF0ZSA9IHRydWU7XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gQXJyYXlFbGVtZW50XHJcblxyXG5cdF9zZXRWYWx1ZV9hcnJheUVsZW1lbnQoIGJ1ZmZlciwgb2Zmc2V0ICkge1xyXG5cclxuXHRcdHRoaXMucmVzb2x2ZWRQcm9wZXJ0eVsgdGhpcy5wcm9wZXJ0eUluZGV4IF0gPSBidWZmZXJbIG9mZnNldCBdO1xyXG5cclxuXHR9XHJcblxyXG5cdF9zZXRWYWx1ZV9hcnJheUVsZW1lbnRfc2V0TmVlZHNVcGRhdGUoIGJ1ZmZlciwgb2Zmc2V0ICkge1xyXG5cclxuXHRcdHRoaXMucmVzb2x2ZWRQcm9wZXJ0eVsgdGhpcy5wcm9wZXJ0eUluZGV4IF0gPSBidWZmZXJbIG9mZnNldCBdO1xyXG5cdFx0dGhpcy50YXJnZXRPYmplY3QubmVlZHNVcGRhdGUgPSB0cnVlO1xyXG5cclxuXHR9XHJcblxyXG5cdF9zZXRWYWx1ZV9hcnJheUVsZW1lbnRfc2V0TWF0cml4V29ybGROZWVkc1VwZGF0ZSggYnVmZmVyLCBvZmZzZXQgKSB7XHJcblxyXG5cdFx0dGhpcy5yZXNvbHZlZFByb3BlcnR5WyB0aGlzLnByb3BlcnR5SW5kZXggXSA9IGJ1ZmZlclsgb2Zmc2V0IF07XHJcblx0XHR0aGlzLnRhcmdldE9iamVjdC5tYXRyaXhXb3JsZE5lZWRzVXBkYXRlID0gdHJ1ZTtcclxuXHJcblx0fVxyXG5cclxuXHQvLyBIYXNUb0Zyb21BcnJheVxyXG5cclxuXHRfc2V0VmFsdWVfZnJvbUFycmF5KCBidWZmZXIsIG9mZnNldCApIHtcclxuXHJcblx0XHR0aGlzLnJlc29sdmVkUHJvcGVydHkuZnJvbUFycmF5KCBidWZmZXIsIG9mZnNldCApO1xyXG5cclxuXHR9XHJcblxyXG5cdF9zZXRWYWx1ZV9mcm9tQXJyYXlfc2V0TmVlZHNVcGRhdGUoIGJ1ZmZlciwgb2Zmc2V0ICkge1xyXG5cclxuXHRcdHRoaXMucmVzb2x2ZWRQcm9wZXJ0eS5mcm9tQXJyYXkoIGJ1ZmZlciwgb2Zmc2V0ICk7XHJcblx0XHR0aGlzLnRhcmdldE9iamVjdC5uZWVkc1VwZGF0ZSA9IHRydWU7XHJcblxyXG5cdH1cclxuXHJcblx0X3NldFZhbHVlX2Zyb21BcnJheV9zZXRNYXRyaXhXb3JsZE5lZWRzVXBkYXRlKCBidWZmZXIsIG9mZnNldCApIHtcclxuXHJcblx0XHR0aGlzLnJlc29sdmVkUHJvcGVydHkuZnJvbUFycmF5KCBidWZmZXIsIG9mZnNldCApO1xyXG5cdFx0dGhpcy50YXJnZXRPYmplY3QubWF0cml4V29ybGROZWVkc1VwZGF0ZSA9IHRydWU7XHJcblxyXG5cdH1cclxuXHJcblx0X2dldFZhbHVlX3VuYm91bmQoIHRhcmdldEFycmF5LCBvZmZzZXQgKSB7XHJcblxyXG5cdFx0dGhpcy5iaW5kKCk7XHJcblx0XHR0aGlzLmdldFZhbHVlKCB0YXJnZXRBcnJheSwgb2Zmc2V0ICk7XHJcblxyXG5cdH1cclxuXHJcblx0X3NldFZhbHVlX3VuYm91bmQoIHNvdXJjZUFycmF5LCBvZmZzZXQgKSB7XHJcblxyXG5cdFx0dGhpcy5iaW5kKCk7XHJcblx0XHR0aGlzLnNldFZhbHVlKCBzb3VyY2VBcnJheSwgb2Zmc2V0ICk7XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gY3JlYXRlIGdldHRlciAvIHNldHRlciBwYWlyIGZvciBhIHByb3BlcnR5IGluIHRoZSBzY2VuZSBncmFwaFxyXG5cdGJpbmQoKSB7XHJcblxyXG5cdFx0bGV0IHRhcmdldE9iamVjdCA9IHRoaXMubm9kZTtcclxuXHRcdGNvbnN0IHBhcnNlZFBhdGggPSB0aGlzLnBhcnNlZFBhdGg7XHJcblxyXG5cdFx0Y29uc3Qgb2JqZWN0TmFtZSA9IHBhcnNlZFBhdGgub2JqZWN0TmFtZTtcclxuXHRcdGNvbnN0IHByb3BlcnR5TmFtZSA9IHBhcnNlZFBhdGgucHJvcGVydHlOYW1lO1xyXG5cdFx0bGV0IHByb3BlcnR5SW5kZXggPSBwYXJzZWRQYXRoLnByb3BlcnR5SW5kZXg7XHJcblxyXG5cdFx0aWYgKCAhIHRhcmdldE9iamVjdCApIHtcclxuXHJcblx0XHRcdHRhcmdldE9iamVjdCA9IFByb3BlcnR5QmluZGluZy5maW5kTm9kZSggdGhpcy5yb290Tm9kZSwgcGFyc2VkUGF0aC5ub2RlTmFtZSApO1xyXG5cclxuXHRcdFx0dGhpcy5ub2RlID0gdGFyZ2V0T2JqZWN0O1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvLyBzZXQgZmFpbCBzdGF0ZSBzbyB3ZSBjYW4ganVzdCAncmV0dXJuJyBvbiBlcnJvclxyXG5cdFx0dGhpcy5nZXRWYWx1ZSA9IHRoaXMuX2dldFZhbHVlX3VuYXZhaWxhYmxlO1xyXG5cdFx0dGhpcy5zZXRWYWx1ZSA9IHRoaXMuX3NldFZhbHVlX3VuYXZhaWxhYmxlO1xyXG5cclxuXHRcdC8vIGVuc3VyZSB0aGVyZSBpcyBhIHZhbHVlIG5vZGVcclxuXHRcdGlmICggISB0YXJnZXRPYmplY3QgKSB7XHJcblxyXG5cdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5Qcm9wZXJ0eUJpbmRpbmc6IE5vIHRhcmdldCBub2RlIGZvdW5kIGZvciB0cmFjazogJyArIHRoaXMucGF0aCArICcuJyApO1xyXG5cdFx0XHRyZXR1cm47XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggb2JqZWN0TmFtZSApIHtcclxuXHJcblx0XHRcdGxldCBvYmplY3RJbmRleCA9IHBhcnNlZFBhdGgub2JqZWN0SW5kZXg7XHJcblxyXG5cdFx0XHQvLyBzcGVjaWFsIGNhc2VzIHdlcmUgd2UgbmVlZCB0byByZWFjaCBkZWVwZXIgaW50byB0aGUgaGllcmFyY2h5IHRvIGdldCB0aGUgZmFjZSBtYXRlcmlhbHMuLi4uXHJcblx0XHRcdHN3aXRjaCAoIG9iamVjdE5hbWUgKSB7XHJcblxyXG5cdFx0XHRcdGNhc2UgJ21hdGVyaWFscyc6XHJcblxyXG5cdFx0XHRcdFx0aWYgKCAhIHRhcmdldE9iamVjdC5tYXRlcmlhbCApIHtcclxuXHJcblx0XHRcdFx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5Qcm9wZXJ0eUJpbmRpbmc6IENhbiBub3QgYmluZCB0byBtYXRlcmlhbCBhcyBub2RlIGRvZXMgbm90IGhhdmUgYSBtYXRlcmlhbC4nLCB0aGlzICk7XHJcblx0XHRcdFx0XHRcdHJldHVybjtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0aWYgKCAhIHRhcmdldE9iamVjdC5tYXRlcmlhbC5tYXRlcmlhbHMgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuUHJvcGVydHlCaW5kaW5nOiBDYW4gbm90IGJpbmQgdG8gbWF0ZXJpYWwubWF0ZXJpYWxzIGFzIG5vZGUubWF0ZXJpYWwgZG9lcyBub3QgaGF2ZSBhIG1hdGVyaWFscyBhcnJheS4nLCB0aGlzICk7XHJcblx0XHRcdFx0XHRcdHJldHVybjtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0dGFyZ2V0T2JqZWN0ID0gdGFyZ2V0T2JqZWN0Lm1hdGVyaWFsLm1hdGVyaWFscztcclxuXHJcblx0XHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdFx0Y2FzZSAnYm9uZXMnOlxyXG5cclxuXHRcdFx0XHRcdGlmICggISB0YXJnZXRPYmplY3Quc2tlbGV0b24gKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuUHJvcGVydHlCaW5kaW5nOiBDYW4gbm90IGJpbmQgdG8gYm9uZXMgYXMgbm9kZSBkb2VzIG5vdCBoYXZlIGEgc2tlbGV0b24uJywgdGhpcyApO1xyXG5cdFx0XHRcdFx0XHRyZXR1cm47XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdC8vIHBvdGVudGlhbCBmdXR1cmUgb3B0aW1pemF0aW9uOiBza2lwIHRoaXMgaWYgcHJvcGVydHlJbmRleCBpcyBhbHJlYWR5IGFuIGludGVnZXJcclxuXHRcdFx0XHRcdC8vIGFuZCBjb252ZXJ0IHRoZSBpbnRlZ2VyIHN0cmluZyB0byBhIHRydWUgaW50ZWdlci5cclxuXHJcblx0XHRcdFx0XHR0YXJnZXRPYmplY3QgPSB0YXJnZXRPYmplY3Quc2tlbGV0b24uYm9uZXM7XHJcblxyXG5cdFx0XHRcdFx0Ly8gc3VwcG9ydCByZXNvbHZpbmcgbW9ycGhUYXJnZXQgbmFtZXMgaW50byBpbmRpY2VzLlxyXG5cdFx0XHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgdGFyZ2V0T2JqZWN0Lmxlbmd0aDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0XHRcdGlmICggdGFyZ2V0T2JqZWN0WyBpIF0ubmFtZSA9PT0gb2JqZWN0SW5kZXggKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdG9iamVjdEluZGV4ID0gaTtcclxuXHRcdFx0XHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRcdGNhc2UgJ21hcCc6XHJcblxyXG5cdFx0XHRcdFx0aWYgKCAnbWFwJyBpbiB0YXJnZXRPYmplY3QgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHR0YXJnZXRPYmplY3QgPSB0YXJnZXRPYmplY3QubWFwO1xyXG5cdFx0XHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0aWYgKCAhIHRhcmdldE9iamVjdC5tYXRlcmlhbCApIHtcclxuXHJcblx0XHRcdFx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5Qcm9wZXJ0eUJpbmRpbmc6IENhbiBub3QgYmluZCB0byBtYXRlcmlhbCBhcyBub2RlIGRvZXMgbm90IGhhdmUgYSBtYXRlcmlhbC4nLCB0aGlzICk7XHJcblx0XHRcdFx0XHRcdHJldHVybjtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0aWYgKCAhIHRhcmdldE9iamVjdC5tYXRlcmlhbC5tYXAgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuUHJvcGVydHlCaW5kaW5nOiBDYW4gbm90IGJpbmQgdG8gbWF0ZXJpYWwubWFwIGFzIG5vZGUubWF0ZXJpYWwgZG9lcyBub3QgaGF2ZSBhIG1hcC4nLCB0aGlzICk7XHJcblx0XHRcdFx0XHRcdHJldHVybjtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0dGFyZ2V0T2JqZWN0ID0gdGFyZ2V0T2JqZWN0Lm1hdGVyaWFsLm1hcDtcclxuXHRcdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0XHRkZWZhdWx0OlxyXG5cclxuXHRcdFx0XHRcdGlmICggdGFyZ2V0T2JqZWN0WyBvYmplY3ROYW1lIF0gPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5Qcm9wZXJ0eUJpbmRpbmc6IENhbiBub3QgYmluZCB0byBvYmplY3ROYW1lIG9mIG5vZGUgdW5kZWZpbmVkLicsIHRoaXMgKTtcclxuXHRcdFx0XHRcdFx0cmV0dXJuO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHR0YXJnZXRPYmplY3QgPSB0YXJnZXRPYmplY3RbIG9iamVjdE5hbWUgXTtcclxuXHJcblx0XHRcdH1cclxuXHJcblxyXG5cdFx0XHRpZiAoIG9iamVjdEluZGV4ICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRcdGlmICggdGFyZ2V0T2JqZWN0WyBvYmplY3RJbmRleCBdID09PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLlByb3BlcnR5QmluZGluZzogVHJ5aW5nIHRvIGJpbmQgdG8gb2JqZWN0SW5kZXggb2Ygb2JqZWN0TmFtZSwgYnV0IGlzIHVuZGVmaW5lZC4nLCB0aGlzLCB0YXJnZXRPYmplY3QgKTtcclxuXHRcdFx0XHRcdHJldHVybjtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR0YXJnZXRPYmplY3QgPSB0YXJnZXRPYmplY3RbIG9iamVjdEluZGV4IF07XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIHJlc29sdmUgcHJvcGVydHlcclxuXHRcdGNvbnN0IG5vZGVQcm9wZXJ0eSA9IHRhcmdldE9iamVjdFsgcHJvcGVydHlOYW1lIF07XHJcblxyXG5cdFx0aWYgKCBub2RlUHJvcGVydHkgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdGNvbnN0IG5vZGVOYW1lID0gcGFyc2VkUGF0aC5ub2RlTmFtZTtcclxuXHJcblx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5Qcm9wZXJ0eUJpbmRpbmc6IFRyeWluZyB0byB1cGRhdGUgcHJvcGVydHkgZm9yIHRyYWNrOiAnICsgbm9kZU5hbWUgK1xyXG5cdFx0XHRcdCcuJyArIHByb3BlcnR5TmFtZSArICcgYnV0IGl0IHdhc25cXCd0IGZvdW5kLicsIHRhcmdldE9iamVjdCApO1xyXG5cdFx0XHRyZXR1cm47XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIGRldGVybWluZSB2ZXJzaW9uaW5nIHNjaGVtZVxyXG5cdFx0bGV0IHZlcnNpb25pbmcgPSB0aGlzLlZlcnNpb25pbmcuTm9uZTtcclxuXHJcblx0XHR0aGlzLnRhcmdldE9iamVjdCA9IHRhcmdldE9iamVjdDtcclxuXHJcblx0XHRpZiAoIHRhcmdldE9iamVjdC5uZWVkc1VwZGF0ZSAhPT0gdW5kZWZpbmVkICkgeyAvLyBtYXRlcmlhbFxyXG5cclxuXHRcdFx0dmVyc2lvbmluZyA9IHRoaXMuVmVyc2lvbmluZy5OZWVkc1VwZGF0ZTtcclxuXHJcblx0XHR9IGVsc2UgaWYgKCB0YXJnZXRPYmplY3QubWF0cml4V29ybGROZWVkc1VwZGF0ZSAhPT0gdW5kZWZpbmVkICkgeyAvLyBub2RlIHRyYW5zZm9ybVxyXG5cclxuXHRcdFx0dmVyc2lvbmluZyA9IHRoaXMuVmVyc2lvbmluZy5NYXRyaXhXb3JsZE5lZWRzVXBkYXRlO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvLyBkZXRlcm1pbmUgaG93IHRoZSBwcm9wZXJ0eSBnZXRzIGJvdW5kXHJcblx0XHRsZXQgYmluZGluZ1R5cGUgPSB0aGlzLkJpbmRpbmdUeXBlLkRpcmVjdDtcclxuXHJcblx0XHRpZiAoIHByb3BlcnR5SW5kZXggIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdC8vIGFjY2VzcyBhIHN1YiBlbGVtZW50IG9mIHRoZSBwcm9wZXJ0eSBhcnJheSAob25seSBwcmltaXRpdmVzIGFyZSBzdXBwb3J0ZWQgcmlnaHQgbm93KVxyXG5cclxuXHRcdFx0aWYgKCBwcm9wZXJ0eU5hbWUgPT09ICdtb3JwaFRhcmdldEluZmx1ZW5jZXMnICkge1xyXG5cclxuXHRcdFx0XHQvLyBwb3RlbnRpYWwgb3B0aW1pemF0aW9uLCBza2lwIHRoaXMgaWYgcHJvcGVydHlJbmRleCBpcyBhbHJlYWR5IGFuIGludGVnZXIsIGFuZCBjb252ZXJ0IHRoZSBpbnRlZ2VyIHN0cmluZyB0byBhIHRydWUgaW50ZWdlci5cclxuXHJcblx0XHRcdFx0Ly8gc3VwcG9ydCByZXNvbHZpbmcgbW9ycGhUYXJnZXQgbmFtZXMgaW50byBpbmRpY2VzLlxyXG5cdFx0XHRcdGlmICggISB0YXJnZXRPYmplY3QuZ2VvbWV0cnkgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLlByb3BlcnR5QmluZGluZzogQ2FuIG5vdCBiaW5kIHRvIG1vcnBoVGFyZ2V0SW5mbHVlbmNlcyBiZWNhdXNlIG5vZGUgZG9lcyBub3QgaGF2ZSBhIGdlb21ldHJ5LicsIHRoaXMgKTtcclxuXHRcdFx0XHRcdHJldHVybjtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRpZiAoICEgdGFyZ2V0T2JqZWN0Lmdlb21ldHJ5Lm1vcnBoQXR0cmlidXRlcyApIHtcclxuXHJcblx0XHRcdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuUHJvcGVydHlCaW5kaW5nOiBDYW4gbm90IGJpbmQgdG8gbW9ycGhUYXJnZXRJbmZsdWVuY2VzIGJlY2F1c2Ugbm9kZSBkb2VzIG5vdCBoYXZlIGEgZ2VvbWV0cnkubW9ycGhBdHRyaWJ1dGVzLicsIHRoaXMgKTtcclxuXHRcdFx0XHRcdHJldHVybjtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRpZiAoIHRhcmdldE9iamVjdC5tb3JwaFRhcmdldERpY3Rpb25hcnlbIHByb3BlcnR5SW5kZXggXSAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHRcdHByb3BlcnR5SW5kZXggPSB0YXJnZXRPYmplY3QubW9ycGhUYXJnZXREaWN0aW9uYXJ5WyBwcm9wZXJ0eUluZGV4IF07XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGJpbmRpbmdUeXBlID0gdGhpcy5CaW5kaW5nVHlwZS5BcnJheUVsZW1lbnQ7XHJcblxyXG5cdFx0XHR0aGlzLnJlc29sdmVkUHJvcGVydHkgPSBub2RlUHJvcGVydHk7XHJcblx0XHRcdHRoaXMucHJvcGVydHlJbmRleCA9IHByb3BlcnR5SW5kZXg7XHJcblxyXG5cdFx0fSBlbHNlIGlmICggbm9kZVByb3BlcnR5LmZyb21BcnJheSAhPT0gdW5kZWZpbmVkICYmIG5vZGVQcm9wZXJ0eS50b0FycmF5ICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHQvLyBtdXN0IHVzZSBjb3B5IGZvciBPYmplY3QzRC5FdWxlci9RdWF0ZXJuaW9uXHJcblxyXG5cdFx0XHRiaW5kaW5nVHlwZSA9IHRoaXMuQmluZGluZ1R5cGUuSGFzRnJvbVRvQXJyYXk7XHJcblxyXG5cdFx0XHR0aGlzLnJlc29sdmVkUHJvcGVydHkgPSBub2RlUHJvcGVydHk7XHJcblxyXG5cdFx0fSBlbHNlIGlmICggQXJyYXkuaXNBcnJheSggbm9kZVByb3BlcnR5ICkgKSB7XHJcblxyXG5cdFx0XHRiaW5kaW5nVHlwZSA9IHRoaXMuQmluZGluZ1R5cGUuRW50aXJlQXJyYXk7XHJcblxyXG5cdFx0XHR0aGlzLnJlc29sdmVkUHJvcGVydHkgPSBub2RlUHJvcGVydHk7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdHRoaXMucHJvcGVydHlOYW1lID0gcHJvcGVydHlOYW1lO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvLyBzZWxlY3QgZ2V0dGVyIC8gc2V0dGVyXHJcblx0XHR0aGlzLmdldFZhbHVlID0gdGhpcy5HZXR0ZXJCeUJpbmRpbmdUeXBlWyBiaW5kaW5nVHlwZSBdO1xyXG5cdFx0dGhpcy5zZXRWYWx1ZSA9IHRoaXMuU2V0dGVyQnlCaW5kaW5nVHlwZUFuZFZlcnNpb25pbmdbIGJpbmRpbmdUeXBlIF1bIHZlcnNpb25pbmcgXTtcclxuXHJcblx0fVxyXG5cclxuXHR1bmJpbmQoKSB7XHJcblxyXG5cdFx0dGhpcy5ub2RlID0gbnVsbDtcclxuXHJcblx0XHQvLyBiYWNrIHRvIHRoZSBwcm90b3R5cGUgdmVyc2lvbiBvZiBnZXRWYWx1ZSAvIHNldFZhbHVlXHJcblx0XHQvLyBub3RlOiBhdm9pZGluZyB0byBtdXRhdGUgdGhlIHNoYXBlIG9mICd0aGlzJyB2aWEgJ2RlbGV0ZSdcclxuXHRcdHRoaXMuZ2V0VmFsdWUgPSB0aGlzLl9nZXRWYWx1ZV91bmJvdW5kO1xyXG5cdFx0dGhpcy5zZXRWYWx1ZSA9IHRoaXMuX3NldFZhbHVlX3VuYm91bmQ7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcblByb3BlcnR5QmluZGluZy5Db21wb3NpdGUgPSBDb21wb3NpdGU7XHJcblxyXG5Qcm9wZXJ0eUJpbmRpbmcucHJvdG90eXBlLkJpbmRpbmdUeXBlID0ge1xyXG5cdERpcmVjdDogMCxcclxuXHRFbnRpcmVBcnJheTogMSxcclxuXHRBcnJheUVsZW1lbnQ6IDIsXHJcblx0SGFzRnJvbVRvQXJyYXk6IDNcclxufTtcclxuXHJcblByb3BlcnR5QmluZGluZy5wcm90b3R5cGUuVmVyc2lvbmluZyA9IHtcclxuXHROb25lOiAwLFxyXG5cdE5lZWRzVXBkYXRlOiAxLFxyXG5cdE1hdHJpeFdvcmxkTmVlZHNVcGRhdGU6IDJcclxufTtcclxuXHJcblByb3BlcnR5QmluZGluZy5wcm90b3R5cGUuR2V0dGVyQnlCaW5kaW5nVHlwZSA9IFtcclxuXHJcblx0UHJvcGVydHlCaW5kaW5nLnByb3RvdHlwZS5fZ2V0VmFsdWVfZGlyZWN0LFxyXG5cdFByb3BlcnR5QmluZGluZy5wcm90b3R5cGUuX2dldFZhbHVlX2FycmF5LFxyXG5cdFByb3BlcnR5QmluZGluZy5wcm90b3R5cGUuX2dldFZhbHVlX2FycmF5RWxlbWVudCxcclxuXHRQcm9wZXJ0eUJpbmRpbmcucHJvdG90eXBlLl9nZXRWYWx1ZV90b0FycmF5LFxyXG5cclxuXTtcclxuXHJcblByb3BlcnR5QmluZGluZy5wcm90b3R5cGUuU2V0dGVyQnlCaW5kaW5nVHlwZUFuZFZlcnNpb25pbmcgPSBbXHJcblxyXG5cdFtcclxuXHRcdC8vIERpcmVjdFxyXG5cdFx0UHJvcGVydHlCaW5kaW5nLnByb3RvdHlwZS5fc2V0VmFsdWVfZGlyZWN0LFxyXG5cdFx0UHJvcGVydHlCaW5kaW5nLnByb3RvdHlwZS5fc2V0VmFsdWVfZGlyZWN0X3NldE5lZWRzVXBkYXRlLFxyXG5cdFx0UHJvcGVydHlCaW5kaW5nLnByb3RvdHlwZS5fc2V0VmFsdWVfZGlyZWN0X3NldE1hdHJpeFdvcmxkTmVlZHNVcGRhdGUsXHJcblxyXG5cdF0sIFtcclxuXHJcblx0XHQvLyBFbnRpcmVBcnJheVxyXG5cclxuXHRcdFByb3BlcnR5QmluZGluZy5wcm90b3R5cGUuX3NldFZhbHVlX2FycmF5LFxyXG5cdFx0UHJvcGVydHlCaW5kaW5nLnByb3RvdHlwZS5fc2V0VmFsdWVfYXJyYXlfc2V0TmVlZHNVcGRhdGUsXHJcblx0XHRQcm9wZXJ0eUJpbmRpbmcucHJvdG90eXBlLl9zZXRWYWx1ZV9hcnJheV9zZXRNYXRyaXhXb3JsZE5lZWRzVXBkYXRlLFxyXG5cclxuXHRdLCBbXHJcblxyXG5cdFx0Ly8gQXJyYXlFbGVtZW50XHJcblx0XHRQcm9wZXJ0eUJpbmRpbmcucHJvdG90eXBlLl9zZXRWYWx1ZV9hcnJheUVsZW1lbnQsXHJcblx0XHRQcm9wZXJ0eUJpbmRpbmcucHJvdG90eXBlLl9zZXRWYWx1ZV9hcnJheUVsZW1lbnRfc2V0TmVlZHNVcGRhdGUsXHJcblx0XHRQcm9wZXJ0eUJpbmRpbmcucHJvdG90eXBlLl9zZXRWYWx1ZV9hcnJheUVsZW1lbnRfc2V0TWF0cml4V29ybGROZWVkc1VwZGF0ZSxcclxuXHJcblx0XSwgW1xyXG5cclxuXHRcdC8vIEhhc1RvRnJvbUFycmF5XHJcblx0XHRQcm9wZXJ0eUJpbmRpbmcucHJvdG90eXBlLl9zZXRWYWx1ZV9mcm9tQXJyYXksXHJcblx0XHRQcm9wZXJ0eUJpbmRpbmcucHJvdG90eXBlLl9zZXRWYWx1ZV9mcm9tQXJyYXlfc2V0TmVlZHNVcGRhdGUsXHJcblx0XHRQcm9wZXJ0eUJpbmRpbmcucHJvdG90eXBlLl9zZXRWYWx1ZV9mcm9tQXJyYXlfc2V0TWF0cml4V29ybGROZWVkc1VwZGF0ZSxcclxuXHJcblx0XVxyXG5cclxuXTtcclxuXHJcblxyXG5leHBvcnQgeyBQcm9wZXJ0eUJpbmRpbmcgfTtcclxuIiwiaW1wb3J0IHsgUHJvcGVydHlCaW5kaW5nIH0gZnJvbSAnLi9Qcm9wZXJ0eUJpbmRpbmcuanMnO1xyXG5pbXBvcnQgKiBhcyBNYXRoVXRpbHMgZnJvbSAnLi4vbWF0aC9NYXRoVXRpbHMuanMnO1xyXG5cclxuLyoqXHJcbiAqXHJcbiAqIEEgZ3JvdXAgb2Ygb2JqZWN0cyB0aGF0IHJlY2VpdmVzIGEgc2hhcmVkIGFuaW1hdGlvbiBzdGF0ZS5cclxuICpcclxuICogVXNhZ2U6XHJcbiAqXHJcbiAqICAtIEFkZCBvYmplY3RzIHlvdSB3b3VsZCBvdGhlcndpc2UgcGFzcyBhcyAncm9vdCcgdG8gdGhlXHJcbiAqICAgIGNvbnN0cnVjdG9yIG9yIHRoZSAuY2xpcEFjdGlvbiBtZXRob2Qgb2YgQW5pbWF0aW9uTWl4ZXIuXHJcbiAqXHJcbiAqICAtIEluc3RlYWQgcGFzcyB0aGlzIG9iamVjdCBhcyAncm9vdCcuXHJcbiAqXHJcbiAqICAtIFlvdSBjYW4gYWxzbyBhZGQgYW5kIHJlbW92ZSBvYmplY3RzIGxhdGVyIHdoZW4gdGhlIG1peGVyXHJcbiAqICAgIGlzIHJ1bm5pbmcuXHJcbiAqXHJcbiAqIE5vdGU6XHJcbiAqXHJcbiAqICAgIE9iamVjdHMgb2YgdGhpcyBjbGFzcyBhcHBlYXIgYXMgb25lIG9iamVjdCB0byB0aGUgbWl4ZXIsXHJcbiAqICAgIHNvIGNhY2hlIGNvbnRyb2wgb2YgdGhlIGluZGl2aWR1YWwgb2JqZWN0cyBtdXN0IGJlIGRvbmVcclxuICogICAgb24gdGhlIGdyb3VwLlxyXG4gKlxyXG4gKiBMaW1pdGF0aW9uOlxyXG4gKlxyXG4gKiAgLSBUaGUgYW5pbWF0ZWQgcHJvcGVydGllcyBtdXN0IGJlIGNvbXBhdGlibGUgYW1vbmcgdGhlXHJcbiAqICAgIGFsbCBvYmplY3RzIGluIHRoZSBncm91cC5cclxuICpcclxuICogIC0gQSBzaW5nbGUgcHJvcGVydHkgY2FuIGVpdGhlciBiZSBjb250cm9sbGVkIHRocm91Z2ggYVxyXG4gKiAgICB0YXJnZXQgZ3JvdXAgb3IgZGlyZWN0bHksIGJ1dCBub3QgYm90aC5cclxuICovXHJcblxyXG5jbGFzcyBBbmltYXRpb25PYmplY3RHcm91cCB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCkge1xyXG5cclxuXHRcdHRoaXMuaXNBbmltYXRpb25PYmplY3RHcm91cCA9IHRydWU7XHJcblxyXG5cdFx0dGhpcy51dWlkID0gTWF0aFV0aWxzLmdlbmVyYXRlVVVJRCgpO1xyXG5cclxuXHRcdC8vIGNhY2hlZCBvYmplY3RzIGZvbGxvd2VkIGJ5IHRoZSBhY3RpdmUgb25lc1xyXG5cdFx0dGhpcy5fb2JqZWN0cyA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKCBhcmd1bWVudHMgKTtcclxuXHJcblx0XHR0aGlzLm5DYWNoZWRPYmplY3RzXyA9IDA7IC8vIHRocmVzaG9sZFxyXG5cdFx0Ly8gbm90ZTogcmVhZCBieSBQcm9wZXJ0eUJpbmRpbmcuQ29tcG9zaXRlXHJcblxyXG5cdFx0Y29uc3QgaW5kaWNlcyA9IHt9O1xyXG5cdFx0dGhpcy5faW5kaWNlc0J5VVVJRCA9IGluZGljZXM7IC8vIGZvciBib29ra2VlcGluZ1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMCwgbiA9IGFyZ3VtZW50cy5sZW5ndGg7IGkgIT09IG47ICsrIGkgKSB7XHJcblxyXG5cdFx0XHRpbmRpY2VzWyBhcmd1bWVudHNbIGkgXS51dWlkIF0gPSBpO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLl9wYXRocyA9IFtdOyAvLyBpbnNpZGU6IHN0cmluZ1xyXG5cdFx0dGhpcy5fcGFyc2VkUGF0aHMgPSBbXTsgLy8gaW5zaWRlOiB7IHdlIGRvbid0IGNhcmUsIGhlcmUgfVxyXG5cdFx0dGhpcy5fYmluZGluZ3MgPSBbXTsgLy8gaW5zaWRlOiBBcnJheTwgUHJvcGVydHlCaW5kaW5nID5cclxuXHRcdHRoaXMuX2JpbmRpbmdzSW5kaWNlc0J5UGF0aCA9IHt9OyAvLyBpbnNpZGU6IGluZGljZXMgaW4gdGhlc2UgYXJyYXlzXHJcblxyXG5cdFx0Y29uc3Qgc2NvcGUgPSB0aGlzO1xyXG5cclxuXHRcdHRoaXMuc3RhdHMgPSB7XHJcblxyXG5cdFx0XHRvYmplY3RzOiB7XHJcblx0XHRcdFx0Z2V0IHRvdGFsKCkge1xyXG5cclxuXHRcdFx0XHRcdHJldHVybiBzY29wZS5fb2JqZWN0cy5sZW5ndGg7XHJcblxyXG5cdFx0XHRcdH0sXHJcblx0XHRcdFx0Z2V0IGluVXNlKCkge1xyXG5cclxuXHRcdFx0XHRcdHJldHVybiB0aGlzLnRvdGFsIC0gc2NvcGUubkNhY2hlZE9iamVjdHNfO1xyXG5cclxuXHRcdFx0XHR9XHJcblx0XHRcdH0sXHJcblx0XHRcdGdldCBiaW5kaW5nc1Blck9iamVjdCgpIHtcclxuXHJcblx0XHRcdFx0cmV0dXJuIHNjb3BlLl9iaW5kaW5ncy5sZW5ndGg7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fTtcclxuXHJcblx0fVxyXG5cclxuXHRhZGQoKSB7XHJcblxyXG5cdFx0Y29uc3Qgb2JqZWN0cyA9IHRoaXMuX29iamVjdHMsXHJcblx0XHRcdGluZGljZXNCeVVVSUQgPSB0aGlzLl9pbmRpY2VzQnlVVUlELFxyXG5cdFx0XHRwYXRocyA9IHRoaXMuX3BhdGhzLFxyXG5cdFx0XHRwYXJzZWRQYXRocyA9IHRoaXMuX3BhcnNlZFBhdGhzLFxyXG5cdFx0XHRiaW5kaW5ncyA9IHRoaXMuX2JpbmRpbmdzLFxyXG5cdFx0XHRuQmluZGluZ3MgPSBiaW5kaW5ncy5sZW5ndGg7XHJcblxyXG5cdFx0bGV0IGtub3duT2JqZWN0ID0gdW5kZWZpbmVkLFxyXG5cdFx0XHRuT2JqZWN0cyA9IG9iamVjdHMubGVuZ3RoLFxyXG5cdFx0XHRuQ2FjaGVkT2JqZWN0cyA9IHRoaXMubkNhY2hlZE9iamVjdHNfO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMCwgbiA9IGFyZ3VtZW50cy5sZW5ndGg7IGkgIT09IG47ICsrIGkgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBvYmplY3QgPSBhcmd1bWVudHNbIGkgXSxcclxuXHRcdFx0XHR1dWlkID0gb2JqZWN0LnV1aWQ7XHJcblx0XHRcdGxldCBpbmRleCA9IGluZGljZXNCeVVVSURbIHV1aWQgXTtcclxuXHJcblx0XHRcdGlmICggaW5kZXggPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0Ly8gdW5rbm93biBvYmplY3QgLT4gYWRkIGl0IHRvIHRoZSBBQ1RJVkUgcmVnaW9uXHJcblxyXG5cdFx0XHRcdGluZGV4ID0gbk9iamVjdHMgKys7XHJcblx0XHRcdFx0aW5kaWNlc0J5VVVJRFsgdXVpZCBdID0gaW5kZXg7XHJcblx0XHRcdFx0b2JqZWN0cy5wdXNoKCBvYmplY3QgKTtcclxuXHJcblx0XHRcdFx0Ly8gYWNjb3VudGluZyBpcyBkb25lLCBub3cgZG8gdGhlIHNhbWUgZm9yIGFsbCBiaW5kaW5nc1xyXG5cclxuXHRcdFx0XHRmb3IgKCBsZXQgaiA9IDAsIG0gPSBuQmluZGluZ3M7IGogIT09IG07ICsrIGogKSB7XHJcblxyXG5cdFx0XHRcdFx0YmluZGluZ3NbIGogXS5wdXNoKCBuZXcgUHJvcGVydHlCaW5kaW5nKCBvYmplY3QsIHBhdGhzWyBqIF0sIHBhcnNlZFBhdGhzWyBqIF0gKSApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9IGVsc2UgaWYgKCBpbmRleCA8IG5DYWNoZWRPYmplY3RzICkge1xyXG5cclxuXHRcdFx0XHRrbm93bk9iamVjdCA9IG9iamVjdHNbIGluZGV4IF07XHJcblxyXG5cdFx0XHRcdC8vIG1vdmUgZXhpc3Rpbmcgb2JqZWN0IHRvIHRoZSBBQ1RJVkUgcmVnaW9uXHJcblxyXG5cdFx0XHRcdGNvbnN0IGZpcnN0QWN0aXZlSW5kZXggPSAtLSBuQ2FjaGVkT2JqZWN0cyxcclxuXHRcdFx0XHRcdGxhc3RDYWNoZWRPYmplY3QgPSBvYmplY3RzWyBmaXJzdEFjdGl2ZUluZGV4IF07XHJcblxyXG5cdFx0XHRcdGluZGljZXNCeVVVSURbIGxhc3RDYWNoZWRPYmplY3QudXVpZCBdID0gaW5kZXg7XHJcblx0XHRcdFx0b2JqZWN0c1sgaW5kZXggXSA9IGxhc3RDYWNoZWRPYmplY3Q7XHJcblxyXG5cdFx0XHRcdGluZGljZXNCeVVVSURbIHV1aWQgXSA9IGZpcnN0QWN0aXZlSW5kZXg7XHJcblx0XHRcdFx0b2JqZWN0c1sgZmlyc3RBY3RpdmVJbmRleCBdID0gb2JqZWN0O1xyXG5cclxuXHRcdFx0XHQvLyBhY2NvdW50aW5nIGlzIGRvbmUsIG5vdyBkbyB0aGUgc2FtZSBmb3IgYWxsIGJpbmRpbmdzXHJcblxyXG5cdFx0XHRcdGZvciAoIGxldCBqID0gMCwgbSA9IG5CaW5kaW5nczsgaiAhPT0gbTsgKysgaiApIHtcclxuXHJcblx0XHRcdFx0XHRjb25zdCBiaW5kaW5nc0ZvclBhdGggPSBiaW5kaW5nc1sgaiBdLFxyXG5cdFx0XHRcdFx0XHRsYXN0Q2FjaGVkID0gYmluZGluZ3NGb3JQYXRoWyBmaXJzdEFjdGl2ZUluZGV4IF07XHJcblxyXG5cdFx0XHRcdFx0bGV0IGJpbmRpbmcgPSBiaW5kaW5nc0ZvclBhdGhbIGluZGV4IF07XHJcblxyXG5cdFx0XHRcdFx0YmluZGluZ3NGb3JQYXRoWyBpbmRleCBdID0gbGFzdENhY2hlZDtcclxuXHJcblx0XHRcdFx0XHRpZiAoIGJpbmRpbmcgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0XHRcdC8vIHNpbmNlIHdlIGRvIG5vdCBib3RoZXIgdG8gY3JlYXRlIG5ldyBiaW5kaW5nc1xyXG5cdFx0XHRcdFx0XHQvLyBmb3Igb2JqZWN0cyB0aGF0IGFyZSBjYWNoZWQsIHRoZSBiaW5kaW5nIG1heVxyXG5cdFx0XHRcdFx0XHQvLyBvciBtYXkgbm90IGV4aXN0XHJcblxyXG5cdFx0XHRcdFx0XHRiaW5kaW5nID0gbmV3IFByb3BlcnR5QmluZGluZyggb2JqZWN0LCBwYXRoc1sgaiBdLCBwYXJzZWRQYXRoc1sgaiBdICk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdGJpbmRpbmdzRm9yUGF0aFsgZmlyc3RBY3RpdmVJbmRleCBdID0gYmluZGluZztcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fSBlbHNlIGlmICggb2JqZWN0c1sgaW5kZXggXSAhPT0ga25vd25PYmplY3QgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5BbmltYXRpb25PYmplY3RHcm91cDogRGlmZmVyZW50IG9iamVjdHMgd2l0aCB0aGUgc2FtZSBVVUlEICcgK1xyXG5cdFx0XHRcdFx0J2RldGVjdGVkLiBDbGVhbiB0aGUgY2FjaGVzIG9yIHJlY3JlYXRlIHlvdXIgaW5mcmFzdHJ1Y3R1cmUgd2hlbiByZWxvYWRpbmcgc2NlbmVzLicgKTtcclxuXHJcblx0XHRcdH0gLy8gZWxzZSB0aGUgb2JqZWN0IGlzIGFscmVhZHkgd2hlcmUgd2Ugd2FudCBpdCB0byBiZVxyXG5cclxuXHRcdH0gLy8gZm9yIGFyZ3VtZW50c1xyXG5cclxuXHRcdHRoaXMubkNhY2hlZE9iamVjdHNfID0gbkNhY2hlZE9iamVjdHM7XHJcblxyXG5cdH1cclxuXHJcblx0cmVtb3ZlKCkge1xyXG5cclxuXHRcdGNvbnN0IG9iamVjdHMgPSB0aGlzLl9vYmplY3RzLFxyXG5cdFx0XHRpbmRpY2VzQnlVVUlEID0gdGhpcy5faW5kaWNlc0J5VVVJRCxcclxuXHRcdFx0YmluZGluZ3MgPSB0aGlzLl9iaW5kaW5ncyxcclxuXHRcdFx0bkJpbmRpbmdzID0gYmluZGluZ3MubGVuZ3RoO1xyXG5cclxuXHRcdGxldCBuQ2FjaGVkT2JqZWN0cyA9IHRoaXMubkNhY2hlZE9iamVjdHNfO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMCwgbiA9IGFyZ3VtZW50cy5sZW5ndGg7IGkgIT09IG47ICsrIGkgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBvYmplY3QgPSBhcmd1bWVudHNbIGkgXSxcclxuXHRcdFx0XHR1dWlkID0gb2JqZWN0LnV1aWQsXHJcblx0XHRcdFx0aW5kZXggPSBpbmRpY2VzQnlVVUlEWyB1dWlkIF07XHJcblxyXG5cdFx0XHRpZiAoIGluZGV4ICE9PSB1bmRlZmluZWQgJiYgaW5kZXggPj0gbkNhY2hlZE9iamVjdHMgKSB7XHJcblxyXG5cdFx0XHRcdC8vIG1vdmUgZXhpc3Rpbmcgb2JqZWN0IGludG8gdGhlIENBQ0hFRCByZWdpb25cclxuXHJcblx0XHRcdFx0Y29uc3QgbGFzdENhY2hlZEluZGV4ID0gbkNhY2hlZE9iamVjdHMgKyssXHJcblx0XHRcdFx0XHRmaXJzdEFjdGl2ZU9iamVjdCA9IG9iamVjdHNbIGxhc3RDYWNoZWRJbmRleCBdO1xyXG5cclxuXHRcdFx0XHRpbmRpY2VzQnlVVUlEWyBmaXJzdEFjdGl2ZU9iamVjdC51dWlkIF0gPSBpbmRleDtcclxuXHRcdFx0XHRvYmplY3RzWyBpbmRleCBdID0gZmlyc3RBY3RpdmVPYmplY3Q7XHJcblxyXG5cdFx0XHRcdGluZGljZXNCeVVVSURbIHV1aWQgXSA9IGxhc3RDYWNoZWRJbmRleDtcclxuXHRcdFx0XHRvYmplY3RzWyBsYXN0Q2FjaGVkSW5kZXggXSA9IG9iamVjdDtcclxuXHJcblx0XHRcdFx0Ly8gYWNjb3VudGluZyBpcyBkb25lLCBub3cgZG8gdGhlIHNhbWUgZm9yIGFsbCBiaW5kaW5nc1xyXG5cclxuXHRcdFx0XHRmb3IgKCBsZXQgaiA9IDAsIG0gPSBuQmluZGluZ3M7IGogIT09IG07ICsrIGogKSB7XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgYmluZGluZ3NGb3JQYXRoID0gYmluZGluZ3NbIGogXSxcclxuXHRcdFx0XHRcdFx0Zmlyc3RBY3RpdmUgPSBiaW5kaW5nc0ZvclBhdGhbIGxhc3RDYWNoZWRJbmRleCBdLFxyXG5cdFx0XHRcdFx0XHRiaW5kaW5nID0gYmluZGluZ3NGb3JQYXRoWyBpbmRleCBdO1xyXG5cclxuXHRcdFx0XHRcdGJpbmRpbmdzRm9yUGF0aFsgaW5kZXggXSA9IGZpcnN0QWN0aXZlO1xyXG5cdFx0XHRcdFx0YmluZGluZ3NGb3JQYXRoWyBsYXN0Q2FjaGVkSW5kZXggXSA9IGJpbmRpbmc7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9IC8vIGZvciBhcmd1bWVudHNcclxuXHJcblx0XHR0aGlzLm5DYWNoZWRPYmplY3RzXyA9IG5DYWNoZWRPYmplY3RzO1xyXG5cclxuXHR9XHJcblxyXG5cdC8vIHJlbW92ZSAmIGZvcmdldFxyXG5cdHVuY2FjaGUoKSB7XHJcblxyXG5cdFx0Y29uc3Qgb2JqZWN0cyA9IHRoaXMuX29iamVjdHMsXHJcblx0XHRcdGluZGljZXNCeVVVSUQgPSB0aGlzLl9pbmRpY2VzQnlVVUlELFxyXG5cdFx0XHRiaW5kaW5ncyA9IHRoaXMuX2JpbmRpbmdzLFxyXG5cdFx0XHRuQmluZGluZ3MgPSBiaW5kaW5ncy5sZW5ndGg7XHJcblxyXG5cdFx0bGV0IG5DYWNoZWRPYmplY3RzID0gdGhpcy5uQ2FjaGVkT2JqZWN0c18sXHJcblx0XHRcdG5PYmplY3RzID0gb2JqZWN0cy5sZW5ndGg7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBuID0gYXJndW1lbnRzLmxlbmd0aDsgaSAhPT0gbjsgKysgaSApIHtcclxuXHJcblx0XHRcdGNvbnN0IG9iamVjdCA9IGFyZ3VtZW50c1sgaSBdLFxyXG5cdFx0XHRcdHV1aWQgPSBvYmplY3QudXVpZCxcclxuXHRcdFx0XHRpbmRleCA9IGluZGljZXNCeVVVSURbIHV1aWQgXTtcclxuXHJcblx0XHRcdGlmICggaW5kZXggIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0ZGVsZXRlIGluZGljZXNCeVVVSURbIHV1aWQgXTtcclxuXHJcblx0XHRcdFx0aWYgKCBpbmRleCA8IG5DYWNoZWRPYmplY3RzICkge1xyXG5cclxuXHRcdFx0XHRcdC8vIG9iamVjdCBpcyBjYWNoZWQsIHNocmluayB0aGUgQ0FDSEVEIHJlZ2lvblxyXG5cclxuXHRcdFx0XHRcdGNvbnN0IGZpcnN0QWN0aXZlSW5kZXggPSAtLSBuQ2FjaGVkT2JqZWN0cyxcclxuXHRcdFx0XHRcdFx0bGFzdENhY2hlZE9iamVjdCA9IG9iamVjdHNbIGZpcnN0QWN0aXZlSW5kZXggXSxcclxuXHRcdFx0XHRcdFx0bGFzdEluZGV4ID0gLS0gbk9iamVjdHMsXHJcblx0XHRcdFx0XHRcdGxhc3RPYmplY3QgPSBvYmplY3RzWyBsYXN0SW5kZXggXTtcclxuXHJcblx0XHRcdFx0XHQvLyBsYXN0IGNhY2hlZCBvYmplY3QgdGFrZXMgdGhpcyBvYmplY3QncyBwbGFjZVxyXG5cdFx0XHRcdFx0aW5kaWNlc0J5VVVJRFsgbGFzdENhY2hlZE9iamVjdC51dWlkIF0gPSBpbmRleDtcclxuXHRcdFx0XHRcdG9iamVjdHNbIGluZGV4IF0gPSBsYXN0Q2FjaGVkT2JqZWN0O1xyXG5cclxuXHRcdFx0XHRcdC8vIGxhc3Qgb2JqZWN0IGdvZXMgdG8gdGhlIGFjdGl2YXRlZCBzbG90IGFuZCBwb3BcclxuXHRcdFx0XHRcdGluZGljZXNCeVVVSURbIGxhc3RPYmplY3QudXVpZCBdID0gZmlyc3RBY3RpdmVJbmRleDtcclxuXHRcdFx0XHRcdG9iamVjdHNbIGZpcnN0QWN0aXZlSW5kZXggXSA9IGxhc3RPYmplY3Q7XHJcblx0XHRcdFx0XHRvYmplY3RzLnBvcCgpO1xyXG5cclxuXHRcdFx0XHRcdC8vIGFjY291bnRpbmcgaXMgZG9uZSwgbm93IGRvIHRoZSBzYW1lIGZvciBhbGwgYmluZGluZ3NcclxuXHJcblx0XHRcdFx0XHRmb3IgKCBsZXQgaiA9IDAsIG0gPSBuQmluZGluZ3M7IGogIT09IG07ICsrIGogKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRjb25zdCBiaW5kaW5nc0ZvclBhdGggPSBiaW5kaW5nc1sgaiBdLFxyXG5cdFx0XHRcdFx0XHRcdGxhc3RDYWNoZWQgPSBiaW5kaW5nc0ZvclBhdGhbIGZpcnN0QWN0aXZlSW5kZXggXSxcclxuXHRcdFx0XHRcdFx0XHRsYXN0ID0gYmluZGluZ3NGb3JQYXRoWyBsYXN0SW5kZXggXTtcclxuXHJcblx0XHRcdFx0XHRcdGJpbmRpbmdzRm9yUGF0aFsgaW5kZXggXSA9IGxhc3RDYWNoZWQ7XHJcblx0XHRcdFx0XHRcdGJpbmRpbmdzRm9yUGF0aFsgZmlyc3RBY3RpdmVJbmRleCBdID0gbGFzdDtcclxuXHRcdFx0XHRcdFx0YmluZGluZ3NGb3JQYXRoLnBvcCgpO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHQvLyBvYmplY3QgaXMgYWN0aXZlLCBqdXN0IHN3YXAgd2l0aCB0aGUgbGFzdCBhbmQgcG9wXHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgbGFzdEluZGV4ID0gLS0gbk9iamVjdHMsXHJcblx0XHRcdFx0XHRcdGxhc3RPYmplY3QgPSBvYmplY3RzWyBsYXN0SW5kZXggXTtcclxuXHJcblx0XHRcdFx0XHRpZiAoIGxhc3RJbmRleCA+IDAgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRpbmRpY2VzQnlVVUlEWyBsYXN0T2JqZWN0LnV1aWQgXSA9IGluZGV4O1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRvYmplY3RzWyBpbmRleCBdID0gbGFzdE9iamVjdDtcclxuXHRcdFx0XHRcdG9iamVjdHMucG9wKCk7XHJcblxyXG5cdFx0XHRcdFx0Ly8gYWNjb3VudGluZyBpcyBkb25lLCBub3cgZG8gdGhlIHNhbWUgZm9yIGFsbCBiaW5kaW5nc1xyXG5cclxuXHRcdFx0XHRcdGZvciAoIGxldCBqID0gMCwgbSA9IG5CaW5kaW5nczsgaiAhPT0gbTsgKysgaiApIHtcclxuXHJcblx0XHRcdFx0XHRcdGNvbnN0IGJpbmRpbmdzRm9yUGF0aCA9IGJpbmRpbmdzWyBqIF07XHJcblxyXG5cdFx0XHRcdFx0XHRiaW5kaW5nc0ZvclBhdGhbIGluZGV4IF0gPSBiaW5kaW5nc0ZvclBhdGhbIGxhc3RJbmRleCBdO1xyXG5cdFx0XHRcdFx0XHRiaW5kaW5nc0ZvclBhdGgucG9wKCk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR9IC8vIGNhY2hlZCBvciBhY3RpdmVcclxuXHJcblx0XHRcdH0gLy8gaWYgb2JqZWN0IGlzIGtub3duXHJcblxyXG5cdFx0fSAvLyBmb3IgYXJndW1lbnRzXHJcblxyXG5cdFx0dGhpcy5uQ2FjaGVkT2JqZWN0c18gPSBuQ2FjaGVkT2JqZWN0cztcclxuXHJcblx0fVxyXG5cclxuXHQvLyBJbnRlcm5hbCBpbnRlcmZhY2UgdXNlZCBieSBiZWZyaWVuZGVkIFByb3BlcnR5QmluZGluZy5Db21wb3NpdGU6XHJcblxyXG5cdHN1YnNjcmliZV8oIHBhdGgsIHBhcnNlZFBhdGggKSB7XHJcblxyXG5cdFx0Ly8gcmV0dXJucyBhbiBhcnJheSBvZiBiaW5kaW5ncyBmb3IgdGhlIGdpdmVuIHBhdGggdGhhdCBpcyBjaGFuZ2VkXHJcblx0XHQvLyBhY2NvcmRpbmcgdG8gdGhlIGNvbnRhaW5lZCBvYmplY3RzIGluIHRoZSBncm91cFxyXG5cclxuXHRcdGNvbnN0IGluZGljZXNCeVBhdGggPSB0aGlzLl9iaW5kaW5nc0luZGljZXNCeVBhdGg7XHJcblx0XHRsZXQgaW5kZXggPSBpbmRpY2VzQnlQYXRoWyBwYXRoIF07XHJcblx0XHRjb25zdCBiaW5kaW5ncyA9IHRoaXMuX2JpbmRpbmdzO1xyXG5cclxuXHRcdGlmICggaW5kZXggIT09IHVuZGVmaW5lZCApIHJldHVybiBiaW5kaW5nc1sgaW5kZXggXTtcclxuXHJcblx0XHRjb25zdCBwYXRocyA9IHRoaXMuX3BhdGhzLFxyXG5cdFx0XHRwYXJzZWRQYXRocyA9IHRoaXMuX3BhcnNlZFBhdGhzLFxyXG5cdFx0XHRvYmplY3RzID0gdGhpcy5fb2JqZWN0cyxcclxuXHRcdFx0bk9iamVjdHMgPSBvYmplY3RzLmxlbmd0aCxcclxuXHRcdFx0bkNhY2hlZE9iamVjdHMgPSB0aGlzLm5DYWNoZWRPYmplY3RzXyxcclxuXHRcdFx0YmluZGluZ3NGb3JQYXRoID0gbmV3IEFycmF5KCBuT2JqZWN0cyApO1xyXG5cclxuXHRcdGluZGV4ID0gYmluZGluZ3MubGVuZ3RoO1xyXG5cclxuXHRcdGluZGljZXNCeVBhdGhbIHBhdGggXSA9IGluZGV4O1xyXG5cclxuXHRcdHBhdGhzLnB1c2goIHBhdGggKTtcclxuXHRcdHBhcnNlZFBhdGhzLnB1c2goIHBhcnNlZFBhdGggKTtcclxuXHRcdGJpbmRpbmdzLnB1c2goIGJpbmRpbmdzRm9yUGF0aCApO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gbkNhY2hlZE9iamVjdHMsIG4gPSBvYmplY3RzLmxlbmd0aDsgaSAhPT0gbjsgKysgaSApIHtcclxuXHJcblx0XHRcdGNvbnN0IG9iamVjdCA9IG9iamVjdHNbIGkgXTtcclxuXHRcdFx0YmluZGluZ3NGb3JQYXRoWyBpIF0gPSBuZXcgUHJvcGVydHlCaW5kaW5nKCBvYmplY3QsIHBhdGgsIHBhcnNlZFBhdGggKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIGJpbmRpbmdzRm9yUGF0aDtcclxuXHJcblx0fVxyXG5cclxuXHR1bnN1YnNjcmliZV8oIHBhdGggKSB7XHJcblxyXG5cdFx0Ly8gdGVsbHMgdGhlIGdyb3VwIHRvIGZvcmdldCBhYm91dCBhIHByb3BlcnR5IHBhdGggYW5kIG5vIGxvbmdlclxyXG5cdFx0Ly8gdXBkYXRlIHRoZSBhcnJheSBwcmV2aW91c2x5IG9idGFpbmVkIHdpdGggJ3N1YnNjcmliZV8nXHJcblxyXG5cdFx0Y29uc3QgaW5kaWNlc0J5UGF0aCA9IHRoaXMuX2JpbmRpbmdzSW5kaWNlc0J5UGF0aCxcclxuXHRcdFx0aW5kZXggPSBpbmRpY2VzQnlQYXRoWyBwYXRoIF07XHJcblxyXG5cdFx0aWYgKCBpbmRleCAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0Y29uc3QgcGF0aHMgPSB0aGlzLl9wYXRocyxcclxuXHRcdFx0XHRwYXJzZWRQYXRocyA9IHRoaXMuX3BhcnNlZFBhdGhzLFxyXG5cdFx0XHRcdGJpbmRpbmdzID0gdGhpcy5fYmluZGluZ3MsXHJcblx0XHRcdFx0bGFzdEJpbmRpbmdzSW5kZXggPSBiaW5kaW5ncy5sZW5ndGggLSAxLFxyXG5cdFx0XHRcdGxhc3RCaW5kaW5ncyA9IGJpbmRpbmdzWyBsYXN0QmluZGluZ3NJbmRleCBdLFxyXG5cdFx0XHRcdGxhc3RCaW5kaW5nc1BhdGggPSBwYXRoWyBsYXN0QmluZGluZ3NJbmRleCBdO1xyXG5cclxuXHRcdFx0aW5kaWNlc0J5UGF0aFsgbGFzdEJpbmRpbmdzUGF0aCBdID0gaW5kZXg7XHJcblxyXG5cdFx0XHRiaW5kaW5nc1sgaW5kZXggXSA9IGxhc3RCaW5kaW5ncztcclxuXHRcdFx0YmluZGluZ3MucG9wKCk7XHJcblxyXG5cdFx0XHRwYXJzZWRQYXRoc1sgaW5kZXggXSA9IHBhcnNlZFBhdGhzWyBsYXN0QmluZGluZ3NJbmRleCBdO1xyXG5cdFx0XHRwYXJzZWRQYXRocy5wb3AoKTtcclxuXHJcblx0XHRcdHBhdGhzWyBpbmRleCBdID0gcGF0aHNbIGxhc3RCaW5kaW5nc0luZGV4IF07XHJcblx0XHRcdHBhdGhzLnBvcCgpO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgQW5pbWF0aW9uT2JqZWN0R3JvdXAgfTtcclxuIiwiaW1wb3J0IHsgV3JhcEFyb3VuZEVuZGluZywgWmVyb0N1cnZhdHVyZUVuZGluZywgWmVyb1Nsb3BlRW5kaW5nLCBMb29wUGluZ1BvbmcsIExvb3BPbmNlLCBMb29wUmVwZWF0LCBOb3JtYWxBbmltYXRpb25CbGVuZE1vZGUsIEFkZGl0aXZlQW5pbWF0aW9uQmxlbmRNb2RlIH0gZnJvbSAnLi4vY29uc3RhbnRzLmpzJztcclxuXHJcblxyXG5jbGFzcyBBbmltYXRpb25BY3Rpb24ge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggbWl4ZXIsIGNsaXAsIGxvY2FsUm9vdCA9IG51bGwsIGJsZW5kTW9kZSA9IGNsaXAuYmxlbmRNb2RlICkge1xyXG5cclxuXHRcdHRoaXMuX21peGVyID0gbWl4ZXI7XHJcblx0XHR0aGlzLl9jbGlwID0gY2xpcDtcclxuXHRcdHRoaXMuX2xvY2FsUm9vdCA9IGxvY2FsUm9vdDtcclxuXHRcdHRoaXMuYmxlbmRNb2RlID0gYmxlbmRNb2RlO1xyXG5cclxuXHRcdGNvbnN0IHRyYWNrcyA9IGNsaXAudHJhY2tzLFxyXG5cdFx0XHRuVHJhY2tzID0gdHJhY2tzLmxlbmd0aCxcclxuXHRcdFx0aW50ZXJwb2xhbnRzID0gbmV3IEFycmF5KCBuVHJhY2tzICk7XHJcblxyXG5cdFx0Y29uc3QgaW50ZXJwb2xhbnRTZXR0aW5ncyA9IHtcclxuXHRcdFx0ZW5kaW5nU3RhcnQ6IFplcm9DdXJ2YXR1cmVFbmRpbmcsXHJcblx0XHRcdGVuZGluZ0VuZDogWmVyb0N1cnZhdHVyZUVuZGluZ1xyXG5cdFx0fTtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgIT09IG5UcmFja3M7ICsrIGkgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBpbnRlcnBvbGFudCA9IHRyYWNrc1sgaSBdLmNyZWF0ZUludGVycG9sYW50KCBudWxsICk7XHJcblx0XHRcdGludGVycG9sYW50c1sgaSBdID0gaW50ZXJwb2xhbnQ7XHJcblx0XHRcdGludGVycG9sYW50LnNldHRpbmdzID0gaW50ZXJwb2xhbnRTZXR0aW5ncztcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5faW50ZXJwb2xhbnRTZXR0aW5ncyA9IGludGVycG9sYW50U2V0dGluZ3M7XHJcblxyXG5cdFx0dGhpcy5faW50ZXJwb2xhbnRzID0gaW50ZXJwb2xhbnRzOyAvLyBib3VuZCBieSB0aGUgbWl4ZXJcclxuXHJcblx0XHQvLyBpbnNpZGU6IFByb3BlcnR5TWl4ZXIgKG1hbmFnZWQgYnkgdGhlIG1peGVyKVxyXG5cdFx0dGhpcy5fcHJvcGVydHlCaW5kaW5ncyA9IG5ldyBBcnJheSggblRyYWNrcyApO1xyXG5cclxuXHRcdHRoaXMuX2NhY2hlSW5kZXggPSBudWxsOyAvLyBmb3IgdGhlIG1lbW9yeSBtYW5hZ2VyXHJcblx0XHR0aGlzLl9ieUNsaXBDYWNoZUluZGV4ID0gbnVsbDsgLy8gZm9yIHRoZSBtZW1vcnkgbWFuYWdlclxyXG5cclxuXHRcdHRoaXMuX3RpbWVTY2FsZUludGVycG9sYW50ID0gbnVsbDtcclxuXHRcdHRoaXMuX3dlaWdodEludGVycG9sYW50ID0gbnVsbDtcclxuXHJcblx0XHR0aGlzLmxvb3AgPSBMb29wUmVwZWF0O1xyXG5cdFx0dGhpcy5fbG9vcENvdW50ID0gLSAxO1xyXG5cclxuXHRcdC8vIGdsb2JhbCBtaXhlciB0aW1lIHdoZW4gdGhlIGFjdGlvbiBpcyB0byBiZSBzdGFydGVkXHJcblx0XHQvLyBpdCdzIHNldCBiYWNrIHRvICdudWxsJyB1cG9uIHN0YXJ0IG9mIHRoZSBhY3Rpb25cclxuXHRcdHRoaXMuX3N0YXJ0VGltZSA9IG51bGw7XHJcblxyXG5cdFx0Ly8gc2NhbGVkIGxvY2FsIHRpbWUgb2YgdGhlIGFjdGlvblxyXG5cdFx0Ly8gZ2V0cyBjbGFtcGVkIG9yIHdyYXBwZWQgdG8gMC4uY2xpcC5kdXJhdGlvbiBhY2NvcmRpbmcgdG8gbG9vcFxyXG5cdFx0dGhpcy50aW1lID0gMDtcclxuXHJcblx0XHR0aGlzLnRpbWVTY2FsZSA9IDE7XHJcblx0XHR0aGlzLl9lZmZlY3RpdmVUaW1lU2NhbGUgPSAxO1xyXG5cclxuXHRcdHRoaXMud2VpZ2h0ID0gMTtcclxuXHRcdHRoaXMuX2VmZmVjdGl2ZVdlaWdodCA9IDE7XHJcblxyXG5cdFx0dGhpcy5yZXBldGl0aW9ucyA9IEluZmluaXR5OyAvLyBuby4gb2YgcmVwZXRpdGlvbnMgd2hlbiBsb29waW5nXHJcblxyXG5cdFx0dGhpcy5wYXVzZWQgPSBmYWxzZTsgLy8gdHJ1ZSAtPiB6ZXJvIGVmZmVjdGl2ZSB0aW1lIHNjYWxlXHJcblx0XHR0aGlzLmVuYWJsZWQgPSB0cnVlOyAvLyBmYWxzZSAtPiB6ZXJvIGVmZmVjdGl2ZSB3ZWlnaHRcclxuXHJcblx0XHR0aGlzLmNsYW1wV2hlbkZpbmlzaGVkID0gZmFsc2U7Ly8ga2VlcCBmZWVkaW5nIHRoZSBsYXN0IGZyYW1lP1xyXG5cclxuXHRcdHRoaXMuemVyb1Nsb3BlQXRTdGFydCA9IHRydWU7Ly8gZm9yIHNtb290aCBpbnRlcnBvbGF0aW9uIHcvbyBzZXBhcmF0ZVxyXG5cdFx0dGhpcy56ZXJvU2xvcGVBdEVuZCA9IHRydWU7Ly8gY2xpcHMgZm9yIHN0YXJ0LCBsb29wIGFuZCBlbmRcclxuXHJcblx0fVxyXG5cclxuXHQvLyBTdGF0ZSAmIFNjaGVkdWxpbmdcclxuXHJcblx0cGxheSgpIHtcclxuXHJcblx0XHR0aGlzLl9taXhlci5fYWN0aXZhdGVBY3Rpb24oIHRoaXMgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzdG9wKCkge1xyXG5cclxuXHRcdHRoaXMuX21peGVyLl9kZWFjdGl2YXRlQWN0aW9uKCB0aGlzICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMucmVzZXQoKTtcclxuXHJcblx0fVxyXG5cclxuXHRyZXNldCgpIHtcclxuXHJcblx0XHR0aGlzLnBhdXNlZCA9IGZhbHNlO1xyXG5cdFx0dGhpcy5lbmFibGVkID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLnRpbWUgPSAwOyAvLyByZXN0YXJ0IGNsaXBcclxuXHRcdHRoaXMuX2xvb3BDb3VudCA9IC0gMTsvLyBmb3JnZXQgcHJldmlvdXMgbG9vcHNcclxuXHRcdHRoaXMuX3N0YXJ0VGltZSA9IG51bGw7Ly8gZm9yZ2V0IHNjaGVkdWxpbmdcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5zdG9wRmFkaW5nKCkuc3RvcFdhcnBpbmcoKTtcclxuXHJcblx0fVxyXG5cclxuXHRpc1J1bm5pbmcoKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuZW5hYmxlZCAmJiAhIHRoaXMucGF1c2VkICYmIHRoaXMudGltZVNjYWxlICE9PSAwICYmXHJcblx0XHRcdHRoaXMuX3N0YXJ0VGltZSA9PT0gbnVsbCAmJiB0aGlzLl9taXhlci5faXNBY3RpdmVBY3Rpb24oIHRoaXMgKTtcclxuXHJcblx0fVxyXG5cclxuXHQvLyByZXR1cm4gdHJ1ZSB3aGVuIHBsYXkgaGFzIGJlZW4gY2FsbGVkXHJcblx0aXNTY2hlZHVsZWQoKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuX21peGVyLl9pc0FjdGl2ZUFjdGlvbiggdGhpcyApO1xyXG5cclxuXHR9XHJcblxyXG5cdHN0YXJ0QXQoIHRpbWUgKSB7XHJcblxyXG5cdFx0dGhpcy5fc3RhcnRUaW1lID0gdGltZTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRMb29wKCBtb2RlLCByZXBldGl0aW9ucyApIHtcclxuXHJcblx0XHR0aGlzLmxvb3AgPSBtb2RlO1xyXG5cdFx0dGhpcy5yZXBldGl0aW9ucyA9IHJlcGV0aXRpb25zO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdC8vIFdlaWdodFxyXG5cclxuXHQvLyBzZXQgdGhlIHdlaWdodCBzdG9wcGluZyBhbnkgc2NoZWR1bGVkIGZhZGluZ1xyXG5cdC8vIGFsdGhvdWdoIC5lbmFibGVkID0gZmFsc2UgeWllbGRzIGFuIGVmZmVjdGl2ZSB3ZWlnaHQgb2YgemVybywgdGhpc1xyXG5cdC8vIG1ldGhvZCBkb2VzICpub3QqIGNoYW5nZSAuZW5hYmxlZCwgYmVjYXVzZSBpdCB3b3VsZCBiZSBjb25mdXNpbmdcclxuXHRzZXRFZmZlY3RpdmVXZWlnaHQoIHdlaWdodCApIHtcclxuXHJcblx0XHR0aGlzLndlaWdodCA9IHdlaWdodDtcclxuXHJcblx0XHQvLyBub3RlOiBzYW1lIGxvZ2ljIGFzIHdoZW4gdXBkYXRlZCBhdCBydW50aW1lXHJcblx0XHR0aGlzLl9lZmZlY3RpdmVXZWlnaHQgPSB0aGlzLmVuYWJsZWQgPyB3ZWlnaHQgOiAwO1xyXG5cclxuXHRcdHJldHVybiB0aGlzLnN0b3BGYWRpbmcoKTtcclxuXHJcblx0fVxyXG5cclxuXHQvLyByZXR1cm4gdGhlIHdlaWdodCBjb25zaWRlcmluZyBmYWRpbmcgYW5kIC5lbmFibGVkXHJcblx0Z2V0RWZmZWN0aXZlV2VpZ2h0KCkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLl9lZmZlY3RpdmVXZWlnaHQ7XHJcblxyXG5cdH1cclxuXHJcblx0ZmFkZUluKCBkdXJhdGlvbiApIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5fc2NoZWR1bGVGYWRpbmcoIGR1cmF0aW9uLCAwLCAxICk7XHJcblxyXG5cdH1cclxuXHJcblx0ZmFkZU91dCggZHVyYXRpb24gKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuX3NjaGVkdWxlRmFkaW5nKCBkdXJhdGlvbiwgMSwgMCApO1xyXG5cclxuXHR9XHJcblxyXG5cdGNyb3NzRmFkZUZyb20oIGZhZGVPdXRBY3Rpb24sIGR1cmF0aW9uLCB3YXJwICkge1xyXG5cclxuXHRcdGZhZGVPdXRBY3Rpb24uZmFkZU91dCggZHVyYXRpb24gKTtcclxuXHRcdHRoaXMuZmFkZUluKCBkdXJhdGlvbiApO1xyXG5cclxuXHRcdGlmICggd2FycCApIHtcclxuXHJcblx0XHRcdGNvbnN0IGZhZGVJbkR1cmF0aW9uID0gdGhpcy5fY2xpcC5kdXJhdGlvbixcclxuXHRcdFx0XHRmYWRlT3V0RHVyYXRpb24gPSBmYWRlT3V0QWN0aW9uLl9jbGlwLmR1cmF0aW9uLFxyXG5cclxuXHRcdFx0XHRzdGFydEVuZFJhdGlvID0gZmFkZU91dER1cmF0aW9uIC8gZmFkZUluRHVyYXRpb24sXHJcblx0XHRcdFx0ZW5kU3RhcnRSYXRpbyA9IGZhZGVJbkR1cmF0aW9uIC8gZmFkZU91dER1cmF0aW9uO1xyXG5cclxuXHRcdFx0ZmFkZU91dEFjdGlvbi53YXJwKCAxLjAsIHN0YXJ0RW5kUmF0aW8sIGR1cmF0aW9uICk7XHJcblx0XHRcdHRoaXMud2FycCggZW5kU3RhcnRSYXRpbywgMS4wLCBkdXJhdGlvbiApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRjcm9zc0ZhZGVUbyggZmFkZUluQWN0aW9uLCBkdXJhdGlvbiwgd2FycCApIHtcclxuXHJcblx0XHRyZXR1cm4gZmFkZUluQWN0aW9uLmNyb3NzRmFkZUZyb20oIHRoaXMsIGR1cmF0aW9uLCB3YXJwICk7XHJcblxyXG5cdH1cclxuXHJcblx0c3RvcEZhZGluZygpIHtcclxuXHJcblx0XHRjb25zdCB3ZWlnaHRJbnRlcnBvbGFudCA9IHRoaXMuX3dlaWdodEludGVycG9sYW50O1xyXG5cclxuXHRcdGlmICggd2VpZ2h0SW50ZXJwb2xhbnQgIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHR0aGlzLl93ZWlnaHRJbnRlcnBvbGFudCA9IG51bGw7XHJcblx0XHRcdHRoaXMuX21peGVyLl90YWtlQmFja0NvbnRyb2xJbnRlcnBvbGFudCggd2VpZ2h0SW50ZXJwb2xhbnQgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gVGltZSBTY2FsZSBDb250cm9sXHJcblxyXG5cdC8vIHNldCB0aGUgdGltZSBzY2FsZSBzdG9wcGluZyBhbnkgc2NoZWR1bGVkIHdhcnBpbmdcclxuXHQvLyBhbHRob3VnaCAucGF1c2VkID0gdHJ1ZSB5aWVsZHMgYW4gZWZmZWN0aXZlIHRpbWUgc2NhbGUgb2YgemVybywgdGhpc1xyXG5cdC8vIG1ldGhvZCBkb2VzICpub3QqIGNoYW5nZSAucGF1c2VkLCBiZWNhdXNlIGl0IHdvdWxkIGJlIGNvbmZ1c2luZ1xyXG5cdHNldEVmZmVjdGl2ZVRpbWVTY2FsZSggdGltZVNjYWxlICkge1xyXG5cclxuXHRcdHRoaXMudGltZVNjYWxlID0gdGltZVNjYWxlO1xyXG5cdFx0dGhpcy5fZWZmZWN0aXZlVGltZVNjYWxlID0gdGhpcy5wYXVzZWQgPyAwIDogdGltZVNjYWxlO1xyXG5cclxuXHRcdHJldHVybiB0aGlzLnN0b3BXYXJwaW5nKCk7XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gcmV0dXJuIHRoZSB0aW1lIHNjYWxlIGNvbnNpZGVyaW5nIHdhcnBpbmcgYW5kIC5wYXVzZWRcclxuXHRnZXRFZmZlY3RpdmVUaW1lU2NhbGUoKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuX2VmZmVjdGl2ZVRpbWVTY2FsZTtcclxuXHJcblx0fVxyXG5cclxuXHRzZXREdXJhdGlvbiggZHVyYXRpb24gKSB7XHJcblxyXG5cdFx0dGhpcy50aW1lU2NhbGUgPSB0aGlzLl9jbGlwLmR1cmF0aW9uIC8gZHVyYXRpb247XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuc3RvcFdhcnBpbmcoKTtcclxuXHJcblx0fVxyXG5cclxuXHRzeW5jV2l0aCggYWN0aW9uICkge1xyXG5cclxuXHRcdHRoaXMudGltZSA9IGFjdGlvbi50aW1lO1xyXG5cdFx0dGhpcy50aW1lU2NhbGUgPSBhY3Rpb24udGltZVNjYWxlO1xyXG5cclxuXHRcdHJldHVybiB0aGlzLnN0b3BXYXJwaW5nKCk7XHJcblxyXG5cdH1cclxuXHJcblx0aGFsdCggZHVyYXRpb24gKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMud2FycCggdGhpcy5fZWZmZWN0aXZlVGltZVNjYWxlLCAwLCBkdXJhdGlvbiApO1xyXG5cclxuXHR9XHJcblxyXG5cdHdhcnAoIHN0YXJ0VGltZVNjYWxlLCBlbmRUaW1lU2NhbGUsIGR1cmF0aW9uICkge1xyXG5cclxuXHRcdGNvbnN0IG1peGVyID0gdGhpcy5fbWl4ZXIsXHJcblx0XHRcdG5vdyA9IG1peGVyLnRpbWUsXHJcblx0XHRcdHRpbWVTY2FsZSA9IHRoaXMudGltZVNjYWxlO1xyXG5cclxuXHRcdGxldCBpbnRlcnBvbGFudCA9IHRoaXMuX3RpbWVTY2FsZUludGVycG9sYW50O1xyXG5cclxuXHRcdGlmICggaW50ZXJwb2xhbnQgPT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRpbnRlcnBvbGFudCA9IG1peGVyLl9sZW5kQ29udHJvbEludGVycG9sYW50KCk7XHJcblx0XHRcdHRoaXMuX3RpbWVTY2FsZUludGVycG9sYW50ID0gaW50ZXJwb2xhbnQ7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGNvbnN0IHRpbWVzID0gaW50ZXJwb2xhbnQucGFyYW1ldGVyUG9zaXRpb25zLFxyXG5cdFx0XHR2YWx1ZXMgPSBpbnRlcnBvbGFudC5zYW1wbGVWYWx1ZXM7XHJcblxyXG5cdFx0dGltZXNbIDAgXSA9IG5vdztcclxuXHRcdHRpbWVzWyAxIF0gPSBub3cgKyBkdXJhdGlvbjtcclxuXHJcblx0XHR2YWx1ZXNbIDAgXSA9IHN0YXJ0VGltZVNjYWxlIC8gdGltZVNjYWxlO1xyXG5cdFx0dmFsdWVzWyAxIF0gPSBlbmRUaW1lU2NhbGUgLyB0aW1lU2NhbGU7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0c3RvcFdhcnBpbmcoKSB7XHJcblxyXG5cdFx0Y29uc3QgdGltZVNjYWxlSW50ZXJwb2xhbnQgPSB0aGlzLl90aW1lU2NhbGVJbnRlcnBvbGFudDtcclxuXHJcblx0XHRpZiAoIHRpbWVTY2FsZUludGVycG9sYW50ICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0dGhpcy5fdGltZVNjYWxlSW50ZXJwb2xhbnQgPSBudWxsO1xyXG5cdFx0XHR0aGlzLl9taXhlci5fdGFrZUJhY2tDb250cm9sSW50ZXJwb2xhbnQoIHRpbWVTY2FsZUludGVycG9sYW50ICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdC8vIE9iamVjdCBBY2Nlc3NvcnNcclxuXHJcblx0Z2V0TWl4ZXIoKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuX21peGVyO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldENsaXAoKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuX2NsaXA7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0Um9vdCgpIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5fbG9jYWxSb290IHx8IHRoaXMuX21peGVyLl9yb290O1xyXG5cclxuXHR9XHJcblxyXG5cdC8vIEludGVybmFcclxuXHJcblx0X3VwZGF0ZSggdGltZSwgZGVsdGFUaW1lLCB0aW1lRGlyZWN0aW9uLCBhY2N1SW5kZXggKSB7XHJcblxyXG5cdFx0Ly8gY2FsbGVkIGJ5IHRoZSBtaXhlclxyXG5cclxuXHRcdGlmICggISB0aGlzLmVuYWJsZWQgKSB7XHJcblxyXG5cdFx0XHQvLyBjYWxsIC5fdXBkYXRlV2VpZ2h0KCkgdG8gdXBkYXRlIC5fZWZmZWN0aXZlV2VpZ2h0XHJcblxyXG5cdFx0XHR0aGlzLl91cGRhdGVXZWlnaHQoIHRpbWUgKTtcclxuXHRcdFx0cmV0dXJuO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCBzdGFydFRpbWUgPSB0aGlzLl9zdGFydFRpbWU7XHJcblxyXG5cdFx0aWYgKCBzdGFydFRpbWUgIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHQvLyBjaGVjayBmb3Igc2NoZWR1bGVkIHN0YXJ0IG9mIGFjdGlvblxyXG5cclxuXHRcdFx0Y29uc3QgdGltZVJ1bm5pbmcgPSAoIHRpbWUgLSBzdGFydFRpbWUgKSAqIHRpbWVEaXJlY3Rpb247XHJcblx0XHRcdGlmICggdGltZVJ1bm5pbmcgPCAwIHx8IHRpbWVEaXJlY3Rpb24gPT09IDAgKSB7XHJcblxyXG5cdFx0XHRcdGRlbHRhVGltZSA9IDA7XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHJcblx0XHRcdFx0dGhpcy5fc3RhcnRUaW1lID0gbnVsbDsgLy8gdW5zY2hlZHVsZVxyXG5cdFx0XHRcdGRlbHRhVGltZSA9IHRpbWVEaXJlY3Rpb24gKiB0aW1lUnVubmluZztcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gYXBwbHkgdGltZSBzY2FsZSBhbmQgYWR2YW5jZSB0aW1lXHJcblxyXG5cdFx0ZGVsdGFUaW1lICo9IHRoaXMuX3VwZGF0ZVRpbWVTY2FsZSggdGltZSApO1xyXG5cdFx0Y29uc3QgY2xpcFRpbWUgPSB0aGlzLl91cGRhdGVUaW1lKCBkZWx0YVRpbWUgKTtcclxuXHJcblx0XHQvLyBub3RlOiBfdXBkYXRlVGltZSBtYXkgZGlzYWJsZSB0aGUgYWN0aW9uIHJlc3VsdGluZyBpblxyXG5cdFx0Ly8gYW4gZWZmZWN0aXZlIHdlaWdodCBvZiAwXHJcblxyXG5cdFx0Y29uc3Qgd2VpZ2h0ID0gdGhpcy5fdXBkYXRlV2VpZ2h0KCB0aW1lICk7XHJcblxyXG5cdFx0aWYgKCB3ZWlnaHQgPiAwICkge1xyXG5cclxuXHRcdFx0Y29uc3QgaW50ZXJwb2xhbnRzID0gdGhpcy5faW50ZXJwb2xhbnRzO1xyXG5cdFx0XHRjb25zdCBwcm9wZXJ0eU1peGVycyA9IHRoaXMuX3Byb3BlcnR5QmluZGluZ3M7XHJcblxyXG5cdFx0XHRzd2l0Y2ggKCB0aGlzLmJsZW5kTW9kZSApIHtcclxuXHJcblx0XHRcdFx0Y2FzZSBBZGRpdGl2ZUFuaW1hdGlvbkJsZW5kTW9kZTpcclxuXHJcblx0XHRcdFx0XHRmb3IgKCBsZXQgaiA9IDAsIG0gPSBpbnRlcnBvbGFudHMubGVuZ3RoOyBqICE9PSBtOyArKyBqICkge1xyXG5cclxuXHRcdFx0XHRcdFx0aW50ZXJwb2xhbnRzWyBqIF0uZXZhbHVhdGUoIGNsaXBUaW1lICk7XHJcblx0XHRcdFx0XHRcdHByb3BlcnR5TWl4ZXJzWyBqIF0uYWNjdW11bGF0ZUFkZGl0aXZlKCB3ZWlnaHQgKTtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRcdGNhc2UgTm9ybWFsQW5pbWF0aW9uQmxlbmRNb2RlOlxyXG5cdFx0XHRcdGRlZmF1bHQ6XHJcblxyXG5cdFx0XHRcdFx0Zm9yICggbGV0IGogPSAwLCBtID0gaW50ZXJwb2xhbnRzLmxlbmd0aDsgaiAhPT0gbTsgKysgaiApIHtcclxuXHJcblx0XHRcdFx0XHRcdGludGVycG9sYW50c1sgaiBdLmV2YWx1YXRlKCBjbGlwVGltZSApO1xyXG5cdFx0XHRcdFx0XHRwcm9wZXJ0eU1peGVyc1sgaiBdLmFjY3VtdWxhdGUoIGFjY3VJbmRleCwgd2VpZ2h0ICk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRfdXBkYXRlV2VpZ2h0KCB0aW1lICkge1xyXG5cclxuXHRcdGxldCB3ZWlnaHQgPSAwO1xyXG5cclxuXHRcdGlmICggdGhpcy5lbmFibGVkICkge1xyXG5cclxuXHRcdFx0d2VpZ2h0ID0gdGhpcy53ZWlnaHQ7XHJcblx0XHRcdGNvbnN0IGludGVycG9sYW50ID0gdGhpcy5fd2VpZ2h0SW50ZXJwb2xhbnQ7XHJcblxyXG5cdFx0XHRpZiAoIGludGVycG9sYW50ICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBpbnRlcnBvbGFudFZhbHVlID0gaW50ZXJwb2xhbnQuZXZhbHVhdGUoIHRpbWUgKVsgMCBdO1xyXG5cclxuXHRcdFx0XHR3ZWlnaHQgKj0gaW50ZXJwb2xhbnRWYWx1ZTtcclxuXHJcblx0XHRcdFx0aWYgKCB0aW1lID4gaW50ZXJwb2xhbnQucGFyYW1ldGVyUG9zaXRpb25zWyAxIF0gKSB7XHJcblxyXG5cdFx0XHRcdFx0dGhpcy5zdG9wRmFkaW5nKCk7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCBpbnRlcnBvbGFudFZhbHVlID09PSAwICkge1xyXG5cclxuXHRcdFx0XHRcdFx0Ly8gZmFkZWQgb3V0LCBkaXNhYmxlXHJcblx0XHRcdFx0XHRcdHRoaXMuZW5hYmxlZCA9IGZhbHNlO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLl9lZmZlY3RpdmVXZWlnaHQgPSB3ZWlnaHQ7XHJcblx0XHRyZXR1cm4gd2VpZ2h0O1xyXG5cclxuXHR9XHJcblxyXG5cdF91cGRhdGVUaW1lU2NhbGUoIHRpbWUgKSB7XHJcblxyXG5cdFx0bGV0IHRpbWVTY2FsZSA9IDA7XHJcblxyXG5cdFx0aWYgKCAhIHRoaXMucGF1c2VkICkge1xyXG5cclxuXHRcdFx0dGltZVNjYWxlID0gdGhpcy50aW1lU2NhbGU7XHJcblxyXG5cdFx0XHRjb25zdCBpbnRlcnBvbGFudCA9IHRoaXMuX3RpbWVTY2FsZUludGVycG9sYW50O1xyXG5cclxuXHRcdFx0aWYgKCBpbnRlcnBvbGFudCAhPT0gbnVsbCApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgaW50ZXJwb2xhbnRWYWx1ZSA9IGludGVycG9sYW50LmV2YWx1YXRlKCB0aW1lIClbIDAgXTtcclxuXHJcblx0XHRcdFx0dGltZVNjYWxlICo9IGludGVycG9sYW50VmFsdWU7XHJcblxyXG5cdFx0XHRcdGlmICggdGltZSA+IGludGVycG9sYW50LnBhcmFtZXRlclBvc2l0aW9uc1sgMSBdICkge1xyXG5cclxuXHRcdFx0XHRcdHRoaXMuc3RvcFdhcnBpbmcoKTtcclxuXHJcblx0XHRcdFx0XHRpZiAoIHRpbWVTY2FsZSA9PT0gMCApIHtcclxuXHJcblx0XHRcdFx0XHRcdC8vIG1vdGlvbiBoYXMgaGFsdGVkLCBwYXVzZVxyXG5cdFx0XHRcdFx0XHR0aGlzLnBhdXNlZCA9IHRydWU7XHJcblxyXG5cdFx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRcdC8vIHdhcnAgZG9uZSAtIGFwcGx5IGZpbmFsIHRpbWUgc2NhbGVcclxuXHRcdFx0XHRcdFx0dGhpcy50aW1lU2NhbGUgPSB0aW1lU2NhbGU7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMuX2VmZmVjdGl2ZVRpbWVTY2FsZSA9IHRpbWVTY2FsZTtcclxuXHRcdHJldHVybiB0aW1lU2NhbGU7XHJcblxyXG5cdH1cclxuXHJcblx0X3VwZGF0ZVRpbWUoIGRlbHRhVGltZSApIHtcclxuXHJcblx0XHRjb25zdCBkdXJhdGlvbiA9IHRoaXMuX2NsaXAuZHVyYXRpb247XHJcblx0XHRjb25zdCBsb29wID0gdGhpcy5sb29wO1xyXG5cclxuXHRcdGxldCB0aW1lID0gdGhpcy50aW1lICsgZGVsdGFUaW1lO1xyXG5cdFx0bGV0IGxvb3BDb3VudCA9IHRoaXMuX2xvb3BDb3VudDtcclxuXHJcblx0XHRjb25zdCBwaW5nUG9uZyA9ICggbG9vcCA9PT0gTG9vcFBpbmdQb25nICk7XHJcblxyXG5cdFx0aWYgKCBkZWx0YVRpbWUgPT09IDAgKSB7XHJcblxyXG5cdFx0XHRpZiAoIGxvb3BDb3VudCA9PT0gLSAxICkgcmV0dXJuIHRpbWU7XHJcblxyXG5cdFx0XHRyZXR1cm4gKCBwaW5nUG9uZyAmJiAoIGxvb3BDb3VudCAmIDEgKSA9PT0gMSApID8gZHVyYXRpb24gLSB0aW1lIDogdGltZTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBsb29wID09PSBMb29wT25jZSApIHtcclxuXHJcblx0XHRcdGlmICggbG9vcENvdW50ID09PSAtIDEgKSB7XHJcblxyXG5cdFx0XHRcdC8vIGp1c3Qgc3RhcnRlZFxyXG5cclxuXHRcdFx0XHR0aGlzLl9sb29wQ291bnQgPSAwO1xyXG5cdFx0XHRcdHRoaXMuX3NldEVuZGluZ3MoIHRydWUsIHRydWUsIGZhbHNlICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRoYW5kbGVfc3RvcDoge1xyXG5cclxuXHRcdFx0XHRpZiAoIHRpbWUgPj0gZHVyYXRpb24gKSB7XHJcblxyXG5cdFx0XHRcdFx0dGltZSA9IGR1cmF0aW9uO1xyXG5cclxuXHRcdFx0XHR9IGVsc2UgaWYgKCB0aW1lIDwgMCApIHtcclxuXHJcblx0XHRcdFx0XHR0aW1lID0gMDtcclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHR0aGlzLnRpbWUgPSB0aW1lO1xyXG5cclxuXHRcdFx0XHRcdGJyZWFrIGhhbmRsZV9zdG9wO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdGlmICggdGhpcy5jbGFtcFdoZW5GaW5pc2hlZCApIHRoaXMucGF1c2VkID0gdHJ1ZTtcclxuXHRcdFx0XHRlbHNlIHRoaXMuZW5hYmxlZCA9IGZhbHNlO1xyXG5cclxuXHRcdFx0XHR0aGlzLnRpbWUgPSB0aW1lO1xyXG5cclxuXHRcdFx0XHR0aGlzLl9taXhlci5kaXNwYXRjaEV2ZW50KCB7XHJcblx0XHRcdFx0XHR0eXBlOiAnZmluaXNoZWQnLCBhY3Rpb246IHRoaXMsXHJcblx0XHRcdFx0XHRkaXJlY3Rpb246IGRlbHRhVGltZSA8IDAgPyAtIDEgOiAxXHJcblx0XHRcdFx0fSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH0gZWxzZSB7IC8vIHJlcGV0aXRpdmUgUmVwZWF0IG9yIFBpbmdQb25nXHJcblxyXG5cdFx0XHRpZiAoIGxvb3BDb3VudCA9PT0gLSAxICkge1xyXG5cclxuXHRcdFx0XHQvLyBqdXN0IHN0YXJ0ZWRcclxuXHJcblx0XHRcdFx0aWYgKCBkZWx0YVRpbWUgPj0gMCApIHtcclxuXHJcblx0XHRcdFx0XHRsb29wQ291bnQgPSAwO1xyXG5cclxuXHRcdFx0XHRcdHRoaXMuX3NldEVuZGluZ3MoIHRydWUsIHRoaXMucmVwZXRpdGlvbnMgPT09IDAsIHBpbmdQb25nICk7XHJcblxyXG5cdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0Ly8gd2hlbiBsb29waW5nIGluIHJldmVyc2UgZGlyZWN0aW9uLCB0aGUgaW5pdGlhbFxyXG5cdFx0XHRcdFx0Ly8gdHJhbnNpdGlvbiB0aHJvdWdoIHplcm8gY291bnRzIGFzIGEgcmVwZXRpdGlvbixcclxuXHRcdFx0XHRcdC8vIHNvIGxlYXZlIGxvb3BDb3VudCBhdCAtMVxyXG5cclxuXHRcdFx0XHRcdHRoaXMuX3NldEVuZGluZ3MoIHRoaXMucmVwZXRpdGlvbnMgPT09IDAsIHRydWUsIHBpbmdQb25nICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGlmICggdGltZSA+PSBkdXJhdGlvbiB8fCB0aW1lIDwgMCApIHtcclxuXHJcblx0XHRcdFx0Ly8gd3JhcCBhcm91bmRcclxuXHJcblx0XHRcdFx0Y29uc3QgbG9vcERlbHRhID0gTWF0aC5mbG9vciggdGltZSAvIGR1cmF0aW9uICk7IC8vIHNpZ25lZFxyXG5cdFx0XHRcdHRpbWUgLT0gZHVyYXRpb24gKiBsb29wRGVsdGE7XHJcblxyXG5cdFx0XHRcdGxvb3BDb3VudCArPSBNYXRoLmFicyggbG9vcERlbHRhICk7XHJcblxyXG5cdFx0XHRcdGNvbnN0IHBlbmRpbmcgPSB0aGlzLnJlcGV0aXRpb25zIC0gbG9vcENvdW50O1xyXG5cclxuXHRcdFx0XHRpZiAoIHBlbmRpbmcgPD0gMCApIHtcclxuXHJcblx0XHRcdFx0XHQvLyBoYXZlIHRvIHN0b3AgKHN3aXRjaCBzdGF0ZSwgY2xhbXAgdGltZSwgZmlyZSBldmVudClcclxuXHJcblx0XHRcdFx0XHRpZiAoIHRoaXMuY2xhbXBXaGVuRmluaXNoZWQgKSB0aGlzLnBhdXNlZCA9IHRydWU7XHJcblx0XHRcdFx0XHRlbHNlIHRoaXMuZW5hYmxlZCA9IGZhbHNlO1xyXG5cclxuXHRcdFx0XHRcdHRpbWUgPSBkZWx0YVRpbWUgPiAwID8gZHVyYXRpb24gOiAwO1xyXG5cclxuXHRcdFx0XHRcdHRoaXMudGltZSA9IHRpbWU7XHJcblxyXG5cdFx0XHRcdFx0dGhpcy5fbWl4ZXIuZGlzcGF0Y2hFdmVudCgge1xyXG5cdFx0XHRcdFx0XHR0eXBlOiAnZmluaXNoZWQnLCBhY3Rpb246IHRoaXMsXHJcblx0XHRcdFx0XHRcdGRpcmVjdGlvbjogZGVsdGFUaW1lID4gMCA/IDEgOiAtIDFcclxuXHRcdFx0XHRcdH0gKTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHQvLyBrZWVwIHJ1bm5pbmdcclxuXHJcblx0XHRcdFx0XHRpZiAoIHBlbmRpbmcgPT09IDEgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHQvLyBlbnRlcmluZyB0aGUgbGFzdCByb3VuZFxyXG5cclxuXHRcdFx0XHRcdFx0Y29uc3QgYXRTdGFydCA9IGRlbHRhVGltZSA8IDA7XHJcblx0XHRcdFx0XHRcdHRoaXMuX3NldEVuZGluZ3MoIGF0U3RhcnQsICEgYXRTdGFydCwgcGluZ1BvbmcgKTtcclxuXHJcblx0XHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdFx0dGhpcy5fc2V0RW5kaW5ncyggZmFsc2UsIGZhbHNlLCBwaW5nUG9uZyApO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHR0aGlzLl9sb29wQ291bnQgPSBsb29wQ291bnQ7XHJcblxyXG5cdFx0XHRcdFx0dGhpcy50aW1lID0gdGltZTtcclxuXHJcblx0XHRcdFx0XHR0aGlzLl9taXhlci5kaXNwYXRjaEV2ZW50KCB7XHJcblx0XHRcdFx0XHRcdHR5cGU6ICdsb29wJywgYWN0aW9uOiB0aGlzLCBsb29wRGVsdGE6IGxvb3BEZWx0YVxyXG5cdFx0XHRcdFx0fSApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHR0aGlzLnRpbWUgPSB0aW1lO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0aWYgKCBwaW5nUG9uZyAmJiAoIGxvb3BDb3VudCAmIDEgKSA9PT0gMSApIHtcclxuXHJcblx0XHRcdFx0Ly8gaW52ZXJ0IHRpbWUgZm9yIHRoZSBcInBvbmcgcm91bmRcIlxyXG5cclxuXHRcdFx0XHRyZXR1cm4gZHVyYXRpb24gLSB0aW1lO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGltZTtcclxuXHJcblx0fVxyXG5cclxuXHRfc2V0RW5kaW5ncyggYXRTdGFydCwgYXRFbmQsIHBpbmdQb25nICkge1xyXG5cclxuXHRcdGNvbnN0IHNldHRpbmdzID0gdGhpcy5faW50ZXJwb2xhbnRTZXR0aW5ncztcclxuXHJcblx0XHRpZiAoIHBpbmdQb25nICkge1xyXG5cclxuXHRcdFx0c2V0dGluZ3MuZW5kaW5nU3RhcnQgPSBaZXJvU2xvcGVFbmRpbmc7XHJcblx0XHRcdHNldHRpbmdzLmVuZGluZ0VuZCA9IFplcm9TbG9wZUVuZGluZztcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0Ly8gYXNzdW1pbmcgZm9yIExvb3BPbmNlIGF0U3RhcnQgPT0gYXRFbmQgPT0gdHJ1ZVxyXG5cclxuXHRcdFx0aWYgKCBhdFN0YXJ0ICkge1xyXG5cclxuXHRcdFx0XHRzZXR0aW5ncy5lbmRpbmdTdGFydCA9IHRoaXMuemVyb1Nsb3BlQXRTdGFydCA/IFplcm9TbG9wZUVuZGluZyA6IFplcm9DdXJ2YXR1cmVFbmRpbmc7XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRzZXR0aW5ncy5lbmRpbmdTdGFydCA9IFdyYXBBcm91bmRFbmRpbmc7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRpZiAoIGF0RW5kICkge1xyXG5cclxuXHRcdFx0XHRzZXR0aW5ncy5lbmRpbmdFbmQgPSB0aGlzLnplcm9TbG9wZUF0RW5kID8gWmVyb1Nsb3BlRW5kaW5nIDogWmVyb0N1cnZhdHVyZUVuZGluZztcclxuXHJcblx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdHNldHRpbmdzLmVuZGluZ0VuZCBcdCA9IFdyYXBBcm91bmRFbmRpbmc7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdF9zY2hlZHVsZUZhZGluZyggZHVyYXRpb24sIHdlaWdodE5vdywgd2VpZ2h0VGhlbiApIHtcclxuXHJcblx0XHRjb25zdCBtaXhlciA9IHRoaXMuX21peGVyLCBub3cgPSBtaXhlci50aW1lO1xyXG5cdFx0bGV0IGludGVycG9sYW50ID0gdGhpcy5fd2VpZ2h0SW50ZXJwb2xhbnQ7XHJcblxyXG5cdFx0aWYgKCBpbnRlcnBvbGFudCA9PT0gbnVsbCApIHtcclxuXHJcblx0XHRcdGludGVycG9sYW50ID0gbWl4ZXIuX2xlbmRDb250cm9sSW50ZXJwb2xhbnQoKTtcclxuXHRcdFx0dGhpcy5fd2VpZ2h0SW50ZXJwb2xhbnQgPSBpbnRlcnBvbGFudDtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Y29uc3QgdGltZXMgPSBpbnRlcnBvbGFudC5wYXJhbWV0ZXJQb3NpdGlvbnMsXHJcblx0XHRcdHZhbHVlcyA9IGludGVycG9sYW50LnNhbXBsZVZhbHVlcztcclxuXHJcblx0XHR0aW1lc1sgMCBdID0gbm93O1xyXG5cdFx0dmFsdWVzWyAwIF0gPSB3ZWlnaHROb3c7XHJcblx0XHR0aW1lc1sgMSBdID0gbm93ICsgZHVyYXRpb247XHJcblx0XHR2YWx1ZXNbIDEgXSA9IHdlaWdodFRoZW47XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcblxyXG5leHBvcnQgeyBBbmltYXRpb25BY3Rpb24gfTtcclxuIiwiaW1wb3J0IHsgQW5pbWF0aW9uQWN0aW9uIH0gZnJvbSAnLi9BbmltYXRpb25BY3Rpb24uanMnO1xyXG5pbXBvcnQgeyBFdmVudERpc3BhdGNoZXIgfSBmcm9tICcuLi9jb3JlL0V2ZW50RGlzcGF0Y2hlci5qcyc7XHJcbmltcG9ydCB7IExpbmVhckludGVycG9sYW50IH0gZnJvbSAnLi4vbWF0aC9pbnRlcnBvbGFudHMvTGluZWFySW50ZXJwb2xhbnQuanMnO1xyXG5pbXBvcnQgeyBQcm9wZXJ0eUJpbmRpbmcgfSBmcm9tICcuL1Byb3BlcnR5QmluZGluZy5qcyc7XHJcbmltcG9ydCB7IFByb3BlcnR5TWl4ZXIgfSBmcm9tICcuL1Byb3BlcnR5TWl4ZXIuanMnO1xyXG5pbXBvcnQgeyBBbmltYXRpb25DbGlwIH0gZnJvbSAnLi9BbmltYXRpb25DbGlwLmpzJztcclxuaW1wb3J0IHsgTm9ybWFsQW5pbWF0aW9uQmxlbmRNb2RlIH0gZnJvbSAnLi4vY29uc3RhbnRzLmpzJztcclxuXHJcblxyXG5jb25zdCBfY29udHJvbEludGVycG9sYW50c1Jlc3VsdEJ1ZmZlciA9IG5ldyBGbG9hdDMyQXJyYXkoIDEgKTtcclxuXHJcblxyXG5jbGFzcyBBbmltYXRpb25NaXhlciBleHRlbmRzIEV2ZW50RGlzcGF0Y2hlciB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCByb290ICkge1xyXG5cclxuXHRcdHN1cGVyKCk7XHJcblxyXG5cdFx0dGhpcy5fcm9vdCA9IHJvb3Q7XHJcblx0XHR0aGlzLl9pbml0TWVtb3J5TWFuYWdlcigpO1xyXG5cdFx0dGhpcy5fYWNjdUluZGV4ID0gMDtcclxuXHRcdHRoaXMudGltZSA9IDA7XHJcblx0XHR0aGlzLnRpbWVTY2FsZSA9IDEuMDtcclxuXHJcblx0fVxyXG5cclxuXHRfYmluZEFjdGlvbiggYWN0aW9uLCBwcm90b3R5cGVBY3Rpb24gKSB7XHJcblxyXG5cdFx0Y29uc3Qgcm9vdCA9IGFjdGlvbi5fbG9jYWxSb290IHx8IHRoaXMuX3Jvb3QsXHJcblx0XHRcdHRyYWNrcyA9IGFjdGlvbi5fY2xpcC50cmFja3MsXHJcblx0XHRcdG5UcmFja3MgPSB0cmFja3MubGVuZ3RoLFxyXG5cdFx0XHRiaW5kaW5ncyA9IGFjdGlvbi5fcHJvcGVydHlCaW5kaW5ncyxcclxuXHRcdFx0aW50ZXJwb2xhbnRzID0gYWN0aW9uLl9pbnRlcnBvbGFudHMsXHJcblx0XHRcdHJvb3RVdWlkID0gcm9vdC51dWlkLFxyXG5cdFx0XHRiaW5kaW5nc0J5Um9vdCA9IHRoaXMuX2JpbmRpbmdzQnlSb290QW5kTmFtZTtcclxuXHJcblx0XHRsZXQgYmluZGluZ3NCeU5hbWUgPSBiaW5kaW5nc0J5Um9vdFsgcm9vdFV1aWQgXTtcclxuXHJcblx0XHRpZiAoIGJpbmRpbmdzQnlOYW1lID09PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRiaW5kaW5nc0J5TmFtZSA9IHt9O1xyXG5cdFx0XHRiaW5kaW5nc0J5Um9vdFsgcm9vdFV1aWQgXSA9IGJpbmRpbmdzQnlOYW1lO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgIT09IG5UcmFja3M7ICsrIGkgKSB7XHJcblxyXG5cdFx0XHRjb25zdCB0cmFjayA9IHRyYWNrc1sgaSBdLFxyXG5cdFx0XHRcdHRyYWNrTmFtZSA9IHRyYWNrLm5hbWU7XHJcblxyXG5cdFx0XHRsZXQgYmluZGluZyA9IGJpbmRpbmdzQnlOYW1lWyB0cmFja05hbWUgXTtcclxuXHJcblx0XHRcdGlmICggYmluZGluZyAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHQrKyBiaW5kaW5nLnJlZmVyZW5jZUNvdW50O1xyXG5cdFx0XHRcdGJpbmRpbmdzWyBpIF0gPSBiaW5kaW5nO1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0YmluZGluZyA9IGJpbmRpbmdzWyBpIF07XHJcblxyXG5cdFx0XHRcdGlmICggYmluZGluZyAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHRcdC8vIGV4aXN0aW5nIGJpbmRpbmcsIG1ha2Ugc3VyZSB0aGUgY2FjaGUga25vd3NcclxuXHJcblx0XHRcdFx0XHRpZiAoIGJpbmRpbmcuX2NhY2hlSW5kZXggPT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHQrKyBiaW5kaW5nLnJlZmVyZW5jZUNvdW50O1xyXG5cdFx0XHRcdFx0XHR0aGlzLl9hZGRJbmFjdGl2ZUJpbmRpbmcoIGJpbmRpbmcsIHJvb3RVdWlkLCB0cmFja05hbWUgKTtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0Y29udGludWU7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0Y29uc3QgcGF0aCA9IHByb3RvdHlwZUFjdGlvbiAmJiBwcm90b3R5cGVBY3Rpb24uXHJcblx0XHRcdFx0XHRfcHJvcGVydHlCaW5kaW5nc1sgaSBdLmJpbmRpbmcucGFyc2VkUGF0aDtcclxuXHJcblx0XHRcdFx0YmluZGluZyA9IG5ldyBQcm9wZXJ0eU1peGVyKFxyXG5cdFx0XHRcdFx0UHJvcGVydHlCaW5kaW5nLmNyZWF0ZSggcm9vdCwgdHJhY2tOYW1lLCBwYXRoICksXHJcblx0XHRcdFx0XHR0cmFjay5WYWx1ZVR5cGVOYW1lLCB0cmFjay5nZXRWYWx1ZVNpemUoKSApO1xyXG5cclxuXHRcdFx0XHQrKyBiaW5kaW5nLnJlZmVyZW5jZUNvdW50O1xyXG5cdFx0XHRcdHRoaXMuX2FkZEluYWN0aXZlQmluZGluZyggYmluZGluZywgcm9vdFV1aWQsIHRyYWNrTmFtZSApO1xyXG5cclxuXHRcdFx0XHRiaW5kaW5nc1sgaSBdID0gYmluZGluZztcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGludGVycG9sYW50c1sgaSBdLnJlc3VsdEJ1ZmZlciA9IGJpbmRpbmcuYnVmZmVyO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRfYWN0aXZhdGVBY3Rpb24oIGFjdGlvbiApIHtcclxuXHJcblx0XHRpZiAoICEgdGhpcy5faXNBY3RpdmVBY3Rpb24oIGFjdGlvbiApICkge1xyXG5cclxuXHRcdFx0aWYgKCBhY3Rpb24uX2NhY2hlSW5kZXggPT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdC8vIHRoaXMgYWN0aW9uIGhhcyBiZWVuIGZvcmdvdHRlbiBieSB0aGUgY2FjaGUsIGJ1dCB0aGUgdXNlclxyXG5cdFx0XHRcdC8vIGFwcGVhcnMgdG8gYmUgc3RpbGwgdXNpbmcgaXQgLT4gcmViaW5kXHJcblxyXG5cdFx0XHRcdGNvbnN0IHJvb3RVdWlkID0gKCBhY3Rpb24uX2xvY2FsUm9vdCB8fCB0aGlzLl9yb290ICkudXVpZCxcclxuXHRcdFx0XHRcdGNsaXBVdWlkID0gYWN0aW9uLl9jbGlwLnV1aWQsXHJcblx0XHRcdFx0XHRhY3Rpb25zRm9yQ2xpcCA9IHRoaXMuX2FjdGlvbnNCeUNsaXBbIGNsaXBVdWlkIF07XHJcblxyXG5cdFx0XHRcdHRoaXMuX2JpbmRBY3Rpb24oIGFjdGlvbixcclxuXHRcdFx0XHRcdGFjdGlvbnNGb3JDbGlwICYmIGFjdGlvbnNGb3JDbGlwLmtub3duQWN0aW9uc1sgMCBdICk7XHJcblxyXG5cdFx0XHRcdHRoaXMuX2FkZEluYWN0aXZlQWN0aW9uKCBhY3Rpb24sIGNsaXBVdWlkLCByb290VXVpZCApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Y29uc3QgYmluZGluZ3MgPSBhY3Rpb24uX3Byb3BlcnR5QmluZGluZ3M7XHJcblxyXG5cdFx0XHQvLyBpbmNyZW1lbnQgcmVmZXJlbmNlIGNvdW50cyAvIHNvcnQgb3V0IHN0YXRlXHJcblx0XHRcdGZvciAoIGxldCBpID0gMCwgbiA9IGJpbmRpbmdzLmxlbmd0aDsgaSAhPT0gbjsgKysgaSApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgYmluZGluZyA9IGJpbmRpbmdzWyBpIF07XHJcblxyXG5cdFx0XHRcdGlmICggYmluZGluZy51c2VDb3VudCArKyA9PT0gMCApIHtcclxuXHJcblx0XHRcdFx0XHR0aGlzLl9sZW5kQmluZGluZyggYmluZGluZyApO1xyXG5cdFx0XHRcdFx0YmluZGluZy5zYXZlT3JpZ2luYWxTdGF0ZSgpO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHR0aGlzLl9sZW5kQWN0aW9uKCBhY3Rpb24gKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0X2RlYWN0aXZhdGVBY3Rpb24oIGFjdGlvbiApIHtcclxuXHJcblx0XHRpZiAoIHRoaXMuX2lzQWN0aXZlQWN0aW9uKCBhY3Rpb24gKSApIHtcclxuXHJcblx0XHRcdGNvbnN0IGJpbmRpbmdzID0gYWN0aW9uLl9wcm9wZXJ0eUJpbmRpbmdzO1xyXG5cclxuXHRcdFx0Ly8gZGVjcmVtZW50IHJlZmVyZW5jZSBjb3VudHMgLyBzb3J0IG91dCBzdGF0ZVxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIG4gPSBiaW5kaW5ncy5sZW5ndGg7IGkgIT09IG47ICsrIGkgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IGJpbmRpbmcgPSBiaW5kaW5nc1sgaSBdO1xyXG5cclxuXHRcdFx0XHRpZiAoIC0tIGJpbmRpbmcudXNlQ291bnQgPT09IDAgKSB7XHJcblxyXG5cdFx0XHRcdFx0YmluZGluZy5yZXN0b3JlT3JpZ2luYWxTdGF0ZSgpO1xyXG5cdFx0XHRcdFx0dGhpcy5fdGFrZUJhY2tCaW5kaW5nKCBiaW5kaW5nICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHRoaXMuX3Rha2VCYWNrQWN0aW9uKCBhY3Rpb24gKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gTWVtb3J5IG1hbmFnZXJcclxuXHJcblx0X2luaXRNZW1vcnlNYW5hZ2VyKCkge1xyXG5cclxuXHRcdHRoaXMuX2FjdGlvbnMgPSBbXTsgLy8gJ25BY3RpdmVBY3Rpb25zJyBmb2xsb3dlZCBieSBpbmFjdGl2ZSBvbmVzXHJcblx0XHR0aGlzLl9uQWN0aXZlQWN0aW9ucyA9IDA7XHJcblxyXG5cdFx0dGhpcy5fYWN0aW9uc0J5Q2xpcCA9IHt9O1xyXG5cdFx0Ly8gaW5zaWRlOlxyXG5cdFx0Ly8ge1xyXG5cdFx0Ly8gXHRrbm93bkFjdGlvbnM6IEFycmF5PCBBbmltYXRpb25BY3Rpb24gPiAtIHVzZWQgYXMgcHJvdG90eXBlc1xyXG5cdFx0Ly8gXHRhY3Rpb25CeVJvb3Q6IEFuaW1hdGlvbkFjdGlvbiAtIGxvb2t1cFxyXG5cdFx0Ly8gfVxyXG5cclxuXHJcblx0XHR0aGlzLl9iaW5kaW5ncyA9IFtdOyAvLyAnbkFjdGl2ZUJpbmRpbmdzJyBmb2xsb3dlZCBieSBpbmFjdGl2ZSBvbmVzXHJcblx0XHR0aGlzLl9uQWN0aXZlQmluZGluZ3MgPSAwO1xyXG5cclxuXHRcdHRoaXMuX2JpbmRpbmdzQnlSb290QW5kTmFtZSA9IHt9OyAvLyBpbnNpZGU6IE1hcDwgbmFtZSwgUHJvcGVydHlNaXhlciA+XHJcblxyXG5cclxuXHRcdHRoaXMuX2NvbnRyb2xJbnRlcnBvbGFudHMgPSBbXTsgLy8gc2FtZSBnYW1lIGFzIGFib3ZlXHJcblx0XHR0aGlzLl9uQWN0aXZlQ29udHJvbEludGVycG9sYW50cyA9IDA7XHJcblxyXG5cdFx0Y29uc3Qgc2NvcGUgPSB0aGlzO1xyXG5cclxuXHRcdHRoaXMuc3RhdHMgPSB7XHJcblxyXG5cdFx0XHRhY3Rpb25zOiB7XHJcblx0XHRcdFx0Z2V0IHRvdGFsKCkge1xyXG5cclxuXHRcdFx0XHRcdHJldHVybiBzY29wZS5fYWN0aW9ucy5sZW5ndGg7XHJcblxyXG5cdFx0XHRcdH0sXHJcblx0XHRcdFx0Z2V0IGluVXNlKCkge1xyXG5cclxuXHRcdFx0XHRcdHJldHVybiBzY29wZS5fbkFjdGl2ZUFjdGlvbnM7XHJcblxyXG5cdFx0XHRcdH1cclxuXHRcdFx0fSxcclxuXHRcdFx0YmluZGluZ3M6IHtcclxuXHRcdFx0XHRnZXQgdG90YWwoKSB7XHJcblxyXG5cdFx0XHRcdFx0cmV0dXJuIHNjb3BlLl9iaW5kaW5ncy5sZW5ndGg7XHJcblxyXG5cdFx0XHRcdH0sXHJcblx0XHRcdFx0Z2V0IGluVXNlKCkge1xyXG5cclxuXHRcdFx0XHRcdHJldHVybiBzY29wZS5fbkFjdGl2ZUJpbmRpbmdzO1xyXG5cclxuXHRcdFx0XHR9XHJcblx0XHRcdH0sXHJcblx0XHRcdGNvbnRyb2xJbnRlcnBvbGFudHM6IHtcclxuXHRcdFx0XHRnZXQgdG90YWwoKSB7XHJcblxyXG5cdFx0XHRcdFx0cmV0dXJuIHNjb3BlLl9jb250cm9sSW50ZXJwb2xhbnRzLmxlbmd0aDtcclxuXHJcblx0XHRcdFx0fSxcclxuXHRcdFx0XHRnZXQgaW5Vc2UoKSB7XHJcblxyXG5cdFx0XHRcdFx0cmV0dXJuIHNjb3BlLl9uQWN0aXZlQ29udHJvbEludGVycG9sYW50cztcclxuXHJcblx0XHRcdFx0fVxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fTtcclxuXHJcblx0fVxyXG5cclxuXHQvLyBNZW1vcnkgbWFuYWdlbWVudCBmb3IgQW5pbWF0aW9uQWN0aW9uIG9iamVjdHNcclxuXHJcblx0X2lzQWN0aXZlQWN0aW9uKCBhY3Rpb24gKSB7XHJcblxyXG5cdFx0Y29uc3QgaW5kZXggPSBhY3Rpb24uX2NhY2hlSW5kZXg7XHJcblx0XHRyZXR1cm4gaW5kZXggIT09IG51bGwgJiYgaW5kZXggPCB0aGlzLl9uQWN0aXZlQWN0aW9ucztcclxuXHJcblx0fVxyXG5cclxuXHRfYWRkSW5hY3RpdmVBY3Rpb24oIGFjdGlvbiwgY2xpcFV1aWQsIHJvb3RVdWlkICkge1xyXG5cclxuXHRcdGNvbnN0IGFjdGlvbnMgPSB0aGlzLl9hY3Rpb25zLFxyXG5cdFx0XHRhY3Rpb25zQnlDbGlwID0gdGhpcy5fYWN0aW9uc0J5Q2xpcDtcclxuXHJcblx0XHRsZXQgYWN0aW9uc0ZvckNsaXAgPSBhY3Rpb25zQnlDbGlwWyBjbGlwVXVpZCBdO1xyXG5cclxuXHRcdGlmICggYWN0aW9uc0ZvckNsaXAgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdGFjdGlvbnNGb3JDbGlwID0ge1xyXG5cclxuXHRcdFx0XHRrbm93bkFjdGlvbnM6IFsgYWN0aW9uIF0sXHJcblx0XHRcdFx0YWN0aW9uQnlSb290OiB7fVxyXG5cclxuXHRcdFx0fTtcclxuXHJcblx0XHRcdGFjdGlvbi5fYnlDbGlwQ2FjaGVJbmRleCA9IDA7XHJcblxyXG5cdFx0XHRhY3Rpb25zQnlDbGlwWyBjbGlwVXVpZCBdID0gYWN0aW9uc0ZvckNsaXA7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdGNvbnN0IGtub3duQWN0aW9ucyA9IGFjdGlvbnNGb3JDbGlwLmtub3duQWN0aW9ucztcclxuXHJcblx0XHRcdGFjdGlvbi5fYnlDbGlwQ2FjaGVJbmRleCA9IGtub3duQWN0aW9ucy5sZW5ndGg7XHJcblx0XHRcdGtub3duQWN0aW9ucy5wdXNoKCBhY3Rpb24gKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0YWN0aW9uLl9jYWNoZUluZGV4ID0gYWN0aW9ucy5sZW5ndGg7XHJcblx0XHRhY3Rpb25zLnB1c2goIGFjdGlvbiApO1xyXG5cclxuXHRcdGFjdGlvbnNGb3JDbGlwLmFjdGlvbkJ5Um9vdFsgcm9vdFV1aWQgXSA9IGFjdGlvbjtcclxuXHJcblx0fVxyXG5cclxuXHRfcmVtb3ZlSW5hY3RpdmVBY3Rpb24oIGFjdGlvbiApIHtcclxuXHJcblx0XHRjb25zdCBhY3Rpb25zID0gdGhpcy5fYWN0aW9ucyxcclxuXHRcdFx0bGFzdEluYWN0aXZlQWN0aW9uID0gYWN0aW9uc1sgYWN0aW9ucy5sZW5ndGggLSAxIF0sXHJcblx0XHRcdGNhY2hlSW5kZXggPSBhY3Rpb24uX2NhY2hlSW5kZXg7XHJcblxyXG5cdFx0bGFzdEluYWN0aXZlQWN0aW9uLl9jYWNoZUluZGV4ID0gY2FjaGVJbmRleDtcclxuXHRcdGFjdGlvbnNbIGNhY2hlSW5kZXggXSA9IGxhc3RJbmFjdGl2ZUFjdGlvbjtcclxuXHRcdGFjdGlvbnMucG9wKCk7XHJcblxyXG5cdFx0YWN0aW9uLl9jYWNoZUluZGV4ID0gbnVsbDtcclxuXHJcblxyXG5cdFx0Y29uc3QgY2xpcFV1aWQgPSBhY3Rpb24uX2NsaXAudXVpZCxcclxuXHRcdFx0YWN0aW9uc0J5Q2xpcCA9IHRoaXMuX2FjdGlvbnNCeUNsaXAsXHJcblx0XHRcdGFjdGlvbnNGb3JDbGlwID0gYWN0aW9uc0J5Q2xpcFsgY2xpcFV1aWQgXSxcclxuXHRcdFx0a25vd25BY3Rpb25zRm9yQ2xpcCA9IGFjdGlvbnNGb3JDbGlwLmtub3duQWN0aW9ucyxcclxuXHJcblx0XHRcdGxhc3RLbm93bkFjdGlvbiA9XHJcblx0XHRcdFx0a25vd25BY3Rpb25zRm9yQ2xpcFsga25vd25BY3Rpb25zRm9yQ2xpcC5sZW5ndGggLSAxIF0sXHJcblxyXG5cdFx0XHRieUNsaXBDYWNoZUluZGV4ID0gYWN0aW9uLl9ieUNsaXBDYWNoZUluZGV4O1xyXG5cclxuXHRcdGxhc3RLbm93bkFjdGlvbi5fYnlDbGlwQ2FjaGVJbmRleCA9IGJ5Q2xpcENhY2hlSW5kZXg7XHJcblx0XHRrbm93bkFjdGlvbnNGb3JDbGlwWyBieUNsaXBDYWNoZUluZGV4IF0gPSBsYXN0S25vd25BY3Rpb247XHJcblx0XHRrbm93bkFjdGlvbnNGb3JDbGlwLnBvcCgpO1xyXG5cclxuXHRcdGFjdGlvbi5fYnlDbGlwQ2FjaGVJbmRleCA9IG51bGw7XHJcblxyXG5cclxuXHRcdGNvbnN0IGFjdGlvbkJ5Um9vdCA9IGFjdGlvbnNGb3JDbGlwLmFjdGlvbkJ5Um9vdCxcclxuXHRcdFx0cm9vdFV1aWQgPSAoIGFjdGlvbi5fbG9jYWxSb290IHx8IHRoaXMuX3Jvb3QgKS51dWlkO1xyXG5cclxuXHRcdGRlbGV0ZSBhY3Rpb25CeVJvb3RbIHJvb3RVdWlkIF07XHJcblxyXG5cdFx0aWYgKCBrbm93bkFjdGlvbnNGb3JDbGlwLmxlbmd0aCA9PT0gMCApIHtcclxuXHJcblx0XHRcdGRlbGV0ZSBhY3Rpb25zQnlDbGlwWyBjbGlwVXVpZCBdO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLl9yZW1vdmVJbmFjdGl2ZUJpbmRpbmdzRm9yQWN0aW9uKCBhY3Rpb24gKTtcclxuXHJcblx0fVxyXG5cclxuXHRfcmVtb3ZlSW5hY3RpdmVCaW5kaW5nc0ZvckFjdGlvbiggYWN0aW9uICkge1xyXG5cclxuXHRcdGNvbnN0IGJpbmRpbmdzID0gYWN0aW9uLl9wcm9wZXJ0eUJpbmRpbmdzO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMCwgbiA9IGJpbmRpbmdzLmxlbmd0aDsgaSAhPT0gbjsgKysgaSApIHtcclxuXHJcblx0XHRcdGNvbnN0IGJpbmRpbmcgPSBiaW5kaW5nc1sgaSBdO1xyXG5cclxuXHRcdFx0aWYgKCAtLSBiaW5kaW5nLnJlZmVyZW5jZUNvdW50ID09PSAwICkge1xyXG5cclxuXHRcdFx0XHR0aGlzLl9yZW1vdmVJbmFjdGl2ZUJpbmRpbmcoIGJpbmRpbmcgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0X2xlbmRBY3Rpb24oIGFjdGlvbiApIHtcclxuXHJcblx0XHQvLyBbIGFjdGl2ZSBhY3Rpb25zIHwgIGluYWN0aXZlIGFjdGlvbnMgIF1cclxuXHRcdC8vIFsgIGFjdGl2ZSBhY3Rpb25zID58IGluYWN0aXZlIGFjdGlvbnMgXVxyXG5cdFx0Ly8gICAgICAgICAgICAgICAgIHMgICAgICAgIGFcclxuXHRcdC8vICAgICAgICAgICAgICAgICAgPC1zd2FwLT5cclxuXHRcdC8vICAgICAgICAgICAgICAgICBhICAgICAgICBzXHJcblxyXG5cdFx0Y29uc3QgYWN0aW9ucyA9IHRoaXMuX2FjdGlvbnMsXHJcblx0XHRcdHByZXZJbmRleCA9IGFjdGlvbi5fY2FjaGVJbmRleCxcclxuXHJcblx0XHRcdGxhc3RBY3RpdmVJbmRleCA9IHRoaXMuX25BY3RpdmVBY3Rpb25zICsrLFxyXG5cclxuXHRcdFx0Zmlyc3RJbmFjdGl2ZUFjdGlvbiA9IGFjdGlvbnNbIGxhc3RBY3RpdmVJbmRleCBdO1xyXG5cclxuXHRcdGFjdGlvbi5fY2FjaGVJbmRleCA9IGxhc3RBY3RpdmVJbmRleDtcclxuXHRcdGFjdGlvbnNbIGxhc3RBY3RpdmVJbmRleCBdID0gYWN0aW9uO1xyXG5cclxuXHRcdGZpcnN0SW5hY3RpdmVBY3Rpb24uX2NhY2hlSW5kZXggPSBwcmV2SW5kZXg7XHJcblx0XHRhY3Rpb25zWyBwcmV2SW5kZXggXSA9IGZpcnN0SW5hY3RpdmVBY3Rpb247XHJcblxyXG5cdH1cclxuXHJcblx0X3Rha2VCYWNrQWN0aW9uKCBhY3Rpb24gKSB7XHJcblxyXG5cdFx0Ly8gWyAgYWN0aXZlIGFjdGlvbnMgIHwgaW5hY3RpdmUgYWN0aW9ucyBdXHJcblx0XHQvLyBbIGFjdGl2ZSBhY3Rpb25zIHw8IGluYWN0aXZlIGFjdGlvbnMgIF1cclxuXHRcdC8vICAgICAgICBhICAgICAgICBzXHJcblx0XHQvLyAgICAgICAgIDwtc3dhcC0+XHJcblx0XHQvLyAgICAgICAgcyAgICAgICAgYVxyXG5cclxuXHRcdGNvbnN0IGFjdGlvbnMgPSB0aGlzLl9hY3Rpb25zLFxyXG5cdFx0XHRwcmV2SW5kZXggPSBhY3Rpb24uX2NhY2hlSW5kZXgsXHJcblxyXG5cdFx0XHRmaXJzdEluYWN0aXZlSW5kZXggPSAtLSB0aGlzLl9uQWN0aXZlQWN0aW9ucyxcclxuXHJcblx0XHRcdGxhc3RBY3RpdmVBY3Rpb24gPSBhY3Rpb25zWyBmaXJzdEluYWN0aXZlSW5kZXggXTtcclxuXHJcblx0XHRhY3Rpb24uX2NhY2hlSW5kZXggPSBmaXJzdEluYWN0aXZlSW5kZXg7XHJcblx0XHRhY3Rpb25zWyBmaXJzdEluYWN0aXZlSW5kZXggXSA9IGFjdGlvbjtcclxuXHJcblx0XHRsYXN0QWN0aXZlQWN0aW9uLl9jYWNoZUluZGV4ID0gcHJldkluZGV4O1xyXG5cdFx0YWN0aW9uc1sgcHJldkluZGV4IF0gPSBsYXN0QWN0aXZlQWN0aW9uO1xyXG5cclxuXHR9XHJcblxyXG5cdC8vIE1lbW9yeSBtYW5hZ2VtZW50IGZvciBQcm9wZXJ0eU1peGVyIG9iamVjdHNcclxuXHJcblx0X2FkZEluYWN0aXZlQmluZGluZyggYmluZGluZywgcm9vdFV1aWQsIHRyYWNrTmFtZSApIHtcclxuXHJcblx0XHRjb25zdCBiaW5kaW5nc0J5Um9vdCA9IHRoaXMuX2JpbmRpbmdzQnlSb290QW5kTmFtZSxcclxuXHRcdFx0YmluZGluZ3MgPSB0aGlzLl9iaW5kaW5ncztcclxuXHJcblx0XHRsZXQgYmluZGluZ0J5TmFtZSA9IGJpbmRpbmdzQnlSb290WyByb290VXVpZCBdO1xyXG5cclxuXHRcdGlmICggYmluZGluZ0J5TmFtZSA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0YmluZGluZ0J5TmFtZSA9IHt9O1xyXG5cdFx0XHRiaW5kaW5nc0J5Um9vdFsgcm9vdFV1aWQgXSA9IGJpbmRpbmdCeU5hbWU7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGJpbmRpbmdCeU5hbWVbIHRyYWNrTmFtZSBdID0gYmluZGluZztcclxuXHJcblx0XHRiaW5kaW5nLl9jYWNoZUluZGV4ID0gYmluZGluZ3MubGVuZ3RoO1xyXG5cdFx0YmluZGluZ3MucHVzaCggYmluZGluZyApO1xyXG5cclxuXHR9XHJcblxyXG5cdF9yZW1vdmVJbmFjdGl2ZUJpbmRpbmcoIGJpbmRpbmcgKSB7XHJcblxyXG5cdFx0Y29uc3QgYmluZGluZ3MgPSB0aGlzLl9iaW5kaW5ncyxcclxuXHRcdFx0cHJvcEJpbmRpbmcgPSBiaW5kaW5nLmJpbmRpbmcsXHJcblx0XHRcdHJvb3RVdWlkID0gcHJvcEJpbmRpbmcucm9vdE5vZGUudXVpZCxcclxuXHRcdFx0dHJhY2tOYW1lID0gcHJvcEJpbmRpbmcucGF0aCxcclxuXHRcdFx0YmluZGluZ3NCeVJvb3QgPSB0aGlzLl9iaW5kaW5nc0J5Um9vdEFuZE5hbWUsXHJcblx0XHRcdGJpbmRpbmdCeU5hbWUgPSBiaW5kaW5nc0J5Um9vdFsgcm9vdFV1aWQgXSxcclxuXHJcblx0XHRcdGxhc3RJbmFjdGl2ZUJpbmRpbmcgPSBiaW5kaW5nc1sgYmluZGluZ3MubGVuZ3RoIC0gMSBdLFxyXG5cdFx0XHRjYWNoZUluZGV4ID0gYmluZGluZy5fY2FjaGVJbmRleDtcclxuXHJcblx0XHRsYXN0SW5hY3RpdmVCaW5kaW5nLl9jYWNoZUluZGV4ID0gY2FjaGVJbmRleDtcclxuXHRcdGJpbmRpbmdzWyBjYWNoZUluZGV4IF0gPSBsYXN0SW5hY3RpdmVCaW5kaW5nO1xyXG5cdFx0YmluZGluZ3MucG9wKCk7XHJcblxyXG5cdFx0ZGVsZXRlIGJpbmRpbmdCeU5hbWVbIHRyYWNrTmFtZSBdO1xyXG5cclxuXHRcdGlmICggT2JqZWN0LmtleXMoIGJpbmRpbmdCeU5hbWUgKS5sZW5ndGggPT09IDAgKSB7XHJcblxyXG5cdFx0XHRkZWxldGUgYmluZGluZ3NCeVJvb3RbIHJvb3RVdWlkIF07XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdF9sZW5kQmluZGluZyggYmluZGluZyApIHtcclxuXHJcblx0XHRjb25zdCBiaW5kaW5ncyA9IHRoaXMuX2JpbmRpbmdzLFxyXG5cdFx0XHRwcmV2SW5kZXggPSBiaW5kaW5nLl9jYWNoZUluZGV4LFxyXG5cclxuXHRcdFx0bGFzdEFjdGl2ZUluZGV4ID0gdGhpcy5fbkFjdGl2ZUJpbmRpbmdzICsrLFxyXG5cclxuXHRcdFx0Zmlyc3RJbmFjdGl2ZUJpbmRpbmcgPSBiaW5kaW5nc1sgbGFzdEFjdGl2ZUluZGV4IF07XHJcblxyXG5cdFx0YmluZGluZy5fY2FjaGVJbmRleCA9IGxhc3RBY3RpdmVJbmRleDtcclxuXHRcdGJpbmRpbmdzWyBsYXN0QWN0aXZlSW5kZXggXSA9IGJpbmRpbmc7XHJcblxyXG5cdFx0Zmlyc3RJbmFjdGl2ZUJpbmRpbmcuX2NhY2hlSW5kZXggPSBwcmV2SW5kZXg7XHJcblx0XHRiaW5kaW5nc1sgcHJldkluZGV4IF0gPSBmaXJzdEluYWN0aXZlQmluZGluZztcclxuXHJcblx0fVxyXG5cclxuXHRfdGFrZUJhY2tCaW5kaW5nKCBiaW5kaW5nICkge1xyXG5cclxuXHRcdGNvbnN0IGJpbmRpbmdzID0gdGhpcy5fYmluZGluZ3MsXHJcblx0XHRcdHByZXZJbmRleCA9IGJpbmRpbmcuX2NhY2hlSW5kZXgsXHJcblxyXG5cdFx0XHRmaXJzdEluYWN0aXZlSW5kZXggPSAtLSB0aGlzLl9uQWN0aXZlQmluZGluZ3MsXHJcblxyXG5cdFx0XHRsYXN0QWN0aXZlQmluZGluZyA9IGJpbmRpbmdzWyBmaXJzdEluYWN0aXZlSW5kZXggXTtcclxuXHJcblx0XHRiaW5kaW5nLl9jYWNoZUluZGV4ID0gZmlyc3RJbmFjdGl2ZUluZGV4O1xyXG5cdFx0YmluZGluZ3NbIGZpcnN0SW5hY3RpdmVJbmRleCBdID0gYmluZGluZztcclxuXHJcblx0XHRsYXN0QWN0aXZlQmluZGluZy5fY2FjaGVJbmRleCA9IHByZXZJbmRleDtcclxuXHRcdGJpbmRpbmdzWyBwcmV2SW5kZXggXSA9IGxhc3RBY3RpdmVCaW5kaW5nO1xyXG5cclxuXHR9XHJcblxyXG5cclxuXHQvLyBNZW1vcnkgbWFuYWdlbWVudCBvZiBJbnRlcnBvbGFudHMgZm9yIHdlaWdodCBhbmQgdGltZSBzY2FsZVxyXG5cclxuXHRfbGVuZENvbnRyb2xJbnRlcnBvbGFudCgpIHtcclxuXHJcblx0XHRjb25zdCBpbnRlcnBvbGFudHMgPSB0aGlzLl9jb250cm9sSW50ZXJwb2xhbnRzLFxyXG5cdFx0XHRsYXN0QWN0aXZlSW5kZXggPSB0aGlzLl9uQWN0aXZlQ29udHJvbEludGVycG9sYW50cyArKztcclxuXHJcblx0XHRsZXQgaW50ZXJwb2xhbnQgPSBpbnRlcnBvbGFudHNbIGxhc3RBY3RpdmVJbmRleCBdO1xyXG5cclxuXHRcdGlmICggaW50ZXJwb2xhbnQgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdGludGVycG9sYW50ID0gbmV3IExpbmVhckludGVycG9sYW50KFxyXG5cdFx0XHRcdG5ldyBGbG9hdDMyQXJyYXkoIDIgKSwgbmV3IEZsb2F0MzJBcnJheSggMiApLFxyXG5cdFx0XHRcdDEsIF9jb250cm9sSW50ZXJwb2xhbnRzUmVzdWx0QnVmZmVyICk7XHJcblxyXG5cdFx0XHRpbnRlcnBvbGFudC5fX2NhY2hlSW5kZXggPSBsYXN0QWN0aXZlSW5kZXg7XHJcblx0XHRcdGludGVycG9sYW50c1sgbGFzdEFjdGl2ZUluZGV4IF0gPSBpbnRlcnBvbGFudDtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIGludGVycG9sYW50O1xyXG5cclxuXHR9XHJcblxyXG5cdF90YWtlQmFja0NvbnRyb2xJbnRlcnBvbGFudCggaW50ZXJwb2xhbnQgKSB7XHJcblxyXG5cdFx0Y29uc3QgaW50ZXJwb2xhbnRzID0gdGhpcy5fY29udHJvbEludGVycG9sYW50cyxcclxuXHRcdFx0cHJldkluZGV4ID0gaW50ZXJwb2xhbnQuX19jYWNoZUluZGV4LFxyXG5cclxuXHRcdFx0Zmlyc3RJbmFjdGl2ZUluZGV4ID0gLS0gdGhpcy5fbkFjdGl2ZUNvbnRyb2xJbnRlcnBvbGFudHMsXHJcblxyXG5cdFx0XHRsYXN0QWN0aXZlSW50ZXJwb2xhbnQgPSBpbnRlcnBvbGFudHNbIGZpcnN0SW5hY3RpdmVJbmRleCBdO1xyXG5cclxuXHRcdGludGVycG9sYW50Ll9fY2FjaGVJbmRleCA9IGZpcnN0SW5hY3RpdmVJbmRleDtcclxuXHRcdGludGVycG9sYW50c1sgZmlyc3RJbmFjdGl2ZUluZGV4IF0gPSBpbnRlcnBvbGFudDtcclxuXHJcblx0XHRsYXN0QWN0aXZlSW50ZXJwb2xhbnQuX19jYWNoZUluZGV4ID0gcHJldkluZGV4O1xyXG5cdFx0aW50ZXJwb2xhbnRzWyBwcmV2SW5kZXggXSA9IGxhc3RBY3RpdmVJbnRlcnBvbGFudDtcclxuXHJcblx0fVxyXG5cclxuXHQvLyByZXR1cm4gYW4gYWN0aW9uIGZvciBhIGNsaXAgb3B0aW9uYWxseSB1c2luZyBhIGN1c3RvbSByb290IHRhcmdldFxyXG5cdC8vIG9iamVjdCAodGhpcyBtZXRob2QgYWxsb2NhdGVzIGEgbG90IG9mIGR5bmFtaWMgbWVtb3J5IGluIGNhc2UgYVxyXG5cdC8vIHByZXZpb3VzbHkgdW5rbm93biBjbGlwL3Jvb3QgY29tYmluYXRpb24gaXMgc3BlY2lmaWVkKVxyXG5cdGNsaXBBY3Rpb24oIGNsaXAsIG9wdGlvbmFsUm9vdCwgYmxlbmRNb2RlICkge1xyXG5cclxuXHRcdGNvbnN0IHJvb3QgPSBvcHRpb25hbFJvb3QgfHwgdGhpcy5fcm9vdCxcclxuXHRcdFx0cm9vdFV1aWQgPSByb290LnV1aWQ7XHJcblxyXG5cdFx0bGV0IGNsaXBPYmplY3QgPSB0eXBlb2YgY2xpcCA9PT0gJ3N0cmluZycgPyBBbmltYXRpb25DbGlwLmZpbmRCeU5hbWUoIHJvb3QsIGNsaXAgKSA6IGNsaXA7XHJcblxyXG5cdFx0Y29uc3QgY2xpcFV1aWQgPSBjbGlwT2JqZWN0ICE9PSBudWxsID8gY2xpcE9iamVjdC51dWlkIDogY2xpcDtcclxuXHJcblx0XHRjb25zdCBhY3Rpb25zRm9yQ2xpcCA9IHRoaXMuX2FjdGlvbnNCeUNsaXBbIGNsaXBVdWlkIF07XHJcblx0XHRsZXQgcHJvdG90eXBlQWN0aW9uID0gbnVsbDtcclxuXHJcblx0XHRpZiAoIGJsZW5kTW9kZSA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0aWYgKCBjbGlwT2JqZWN0ICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0XHRibGVuZE1vZGUgPSBjbGlwT2JqZWN0LmJsZW5kTW9kZTtcclxuXHJcblx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdGJsZW5kTW9kZSA9IE5vcm1hbEFuaW1hdGlvbkJsZW5kTW9kZTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBhY3Rpb25zRm9yQ2xpcCAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0Y29uc3QgZXhpc3RpbmdBY3Rpb24gPSBhY3Rpb25zRm9yQ2xpcC5hY3Rpb25CeVJvb3RbIHJvb3RVdWlkIF07XHJcblxyXG5cdFx0XHRpZiAoIGV4aXN0aW5nQWN0aW9uICE9PSB1bmRlZmluZWQgJiYgZXhpc3RpbmdBY3Rpb24uYmxlbmRNb2RlID09PSBibGVuZE1vZGUgKSB7XHJcblxyXG5cdFx0XHRcdHJldHVybiBleGlzdGluZ0FjdGlvbjtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdC8vIHdlIGtub3cgdGhlIGNsaXAsIHNvIHdlIGRvbid0IGhhdmUgdG8gcGFyc2UgYWxsXHJcblx0XHRcdC8vIHRoZSBiaW5kaW5ncyBhZ2FpbiBidXQgY2FuIGp1c3QgY29weVxyXG5cdFx0XHRwcm90b3R5cGVBY3Rpb24gPSBhY3Rpb25zRm9yQ2xpcC5rbm93bkFjdGlvbnNbIDAgXTtcclxuXHJcblx0XHRcdC8vIGFsc28sIHRha2UgdGhlIGNsaXAgZnJvbSB0aGUgcHJvdG90eXBlIGFjdGlvblxyXG5cdFx0XHRpZiAoIGNsaXBPYmplY3QgPT09IG51bGwgKVxyXG5cdFx0XHRcdGNsaXBPYmplY3QgPSBwcm90b3R5cGVBY3Rpb24uX2NsaXA7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIGNsaXAgbXVzdCBiZSBrbm93biB3aGVuIHNwZWNpZmllZCB2aWEgc3RyaW5nXHJcblx0XHRpZiAoIGNsaXBPYmplY3QgPT09IG51bGwgKSByZXR1cm4gbnVsbDtcclxuXHJcblx0XHQvLyBhbGxvY2F0ZSBhbGwgcmVzb3VyY2VzIHJlcXVpcmVkIHRvIHJ1biBpdFxyXG5cdFx0Y29uc3QgbmV3QWN0aW9uID0gbmV3IEFuaW1hdGlvbkFjdGlvbiggdGhpcywgY2xpcE9iamVjdCwgb3B0aW9uYWxSb290LCBibGVuZE1vZGUgKTtcclxuXHJcblx0XHR0aGlzLl9iaW5kQWN0aW9uKCBuZXdBY3Rpb24sIHByb3RvdHlwZUFjdGlvbiApO1xyXG5cclxuXHRcdC8vIGFuZCBtYWtlIHRoZSBhY3Rpb24ga25vd24gdG8gdGhlIG1lbW9yeSBtYW5hZ2VyXHJcblx0XHR0aGlzLl9hZGRJbmFjdGl2ZUFjdGlvbiggbmV3QWN0aW9uLCBjbGlwVXVpZCwgcm9vdFV1aWQgKTtcclxuXHJcblx0XHRyZXR1cm4gbmV3QWN0aW9uO1xyXG5cclxuXHR9XHJcblxyXG5cdC8vIGdldCBhbiBleGlzdGluZyBhY3Rpb25cclxuXHRleGlzdGluZ0FjdGlvbiggY2xpcCwgb3B0aW9uYWxSb290ICkge1xyXG5cclxuXHRcdGNvbnN0IHJvb3QgPSBvcHRpb25hbFJvb3QgfHwgdGhpcy5fcm9vdCxcclxuXHRcdFx0cm9vdFV1aWQgPSByb290LnV1aWQsXHJcblxyXG5cdFx0XHRjbGlwT2JqZWN0ID0gdHlwZW9mIGNsaXAgPT09ICdzdHJpbmcnID9cclxuXHRcdFx0XHRBbmltYXRpb25DbGlwLmZpbmRCeU5hbWUoIHJvb3QsIGNsaXAgKSA6IGNsaXAsXHJcblxyXG5cdFx0XHRjbGlwVXVpZCA9IGNsaXBPYmplY3QgPyBjbGlwT2JqZWN0LnV1aWQgOiBjbGlwLFxyXG5cclxuXHRcdFx0YWN0aW9uc0ZvckNsaXAgPSB0aGlzLl9hY3Rpb25zQnlDbGlwWyBjbGlwVXVpZCBdO1xyXG5cclxuXHRcdGlmICggYWN0aW9uc0ZvckNsaXAgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdHJldHVybiBhY3Rpb25zRm9yQ2xpcC5hY3Rpb25CeVJvb3RbIHJvb3RVdWlkIF0gfHwgbnVsbDtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIG51bGw7XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gZGVhY3RpdmF0ZXMgYWxsIHByZXZpb3VzbHkgc2NoZWR1bGVkIGFjdGlvbnNcclxuXHRzdG9wQWxsQWN0aW9uKCkge1xyXG5cclxuXHRcdGNvbnN0IGFjdGlvbnMgPSB0aGlzLl9hY3Rpb25zLFxyXG5cdFx0XHRuQWN0aW9ucyA9IHRoaXMuX25BY3RpdmVBY3Rpb25zO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gbkFjdGlvbnMgLSAxOyBpID49IDA7IC0tIGkgKSB7XHJcblxyXG5cdFx0XHRhY3Rpb25zWyBpIF0uc3RvcCgpO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHQvLyBhZHZhbmNlIHRoZSB0aW1lIGFuZCB1cGRhdGUgYXBwbHkgdGhlIGFuaW1hdGlvblxyXG5cdHVwZGF0ZSggZGVsdGFUaW1lICkge1xyXG5cclxuXHRcdGRlbHRhVGltZSAqPSB0aGlzLnRpbWVTY2FsZTtcclxuXHJcblx0XHRjb25zdCBhY3Rpb25zID0gdGhpcy5fYWN0aW9ucyxcclxuXHRcdFx0bkFjdGlvbnMgPSB0aGlzLl9uQWN0aXZlQWN0aW9ucyxcclxuXHJcblx0XHRcdHRpbWUgPSB0aGlzLnRpbWUgKz0gZGVsdGFUaW1lLFxyXG5cdFx0XHR0aW1lRGlyZWN0aW9uID0gTWF0aC5zaWduKCBkZWx0YVRpbWUgKSxcclxuXHJcblx0XHRcdGFjY3VJbmRleCA9IHRoaXMuX2FjY3VJbmRleCBePSAxO1xyXG5cclxuXHRcdC8vIHJ1biBhY3RpdmUgYWN0aW9uc1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMDsgaSAhPT0gbkFjdGlvbnM7ICsrIGkgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBhY3Rpb24gPSBhY3Rpb25zWyBpIF07XHJcblxyXG5cdFx0XHRhY3Rpb24uX3VwZGF0ZSggdGltZSwgZGVsdGFUaW1lLCB0aW1lRGlyZWN0aW9uLCBhY2N1SW5kZXggKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gdXBkYXRlIHNjZW5lIGdyYXBoXHJcblxyXG5cdFx0Y29uc3QgYmluZGluZ3MgPSB0aGlzLl9iaW5kaW5ncyxcclxuXHRcdFx0bkJpbmRpbmdzID0gdGhpcy5fbkFjdGl2ZUJpbmRpbmdzO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMDsgaSAhPT0gbkJpbmRpbmdzOyArKyBpICkge1xyXG5cclxuXHRcdFx0YmluZGluZ3NbIGkgXS5hcHBseSggYWNjdUluZGV4ICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdC8vIEFsbG93cyB5b3UgdG8gc2VlayB0byBhIHNwZWNpZmljIHRpbWUgaW4gYW4gYW5pbWF0aW9uLlxyXG5cdHNldFRpbWUoIHRpbWVJblNlY29uZHMgKSB7XHJcblxyXG5cdFx0dGhpcy50aW1lID0gMDsgLy8gWmVybyBvdXQgdGltZSBhdHRyaWJ1dGUgZm9yIEFuaW1hdGlvbk1peGVyIG9iamVjdDtcclxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHRoaXMuX2FjdGlvbnMubGVuZ3RoOyBpICsrICkge1xyXG5cclxuXHRcdFx0dGhpcy5fYWN0aW9uc1sgaSBdLnRpbWUgPSAwOyAvLyBaZXJvIG91dCB0aW1lIGF0dHJpYnV0ZSBmb3IgYWxsIGFzc29jaWF0ZWQgQW5pbWF0aW9uQWN0aW9uIG9iamVjdHMuXHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzLnVwZGF0ZSggdGltZUluU2Vjb25kcyApOyAvLyBVcGRhdGUgdXNlZCB0byBzZXQgZXhhY3QgdGltZS4gUmV0dXJucyBcInRoaXNcIiBBbmltYXRpb25NaXhlciBvYmplY3QuXHJcblxyXG5cdH1cclxuXHJcblx0Ly8gcmV0dXJuIHRoaXMgbWl4ZXIncyByb290IHRhcmdldCBvYmplY3RcclxuXHRnZXRSb290KCkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLl9yb290O1xyXG5cclxuXHR9XHJcblxyXG5cdC8vIGZyZWUgYWxsIHJlc291cmNlcyBzcGVjaWZpYyB0byBhIHBhcnRpY3VsYXIgY2xpcFxyXG5cdHVuY2FjaGVDbGlwKCBjbGlwICkge1xyXG5cclxuXHRcdGNvbnN0IGFjdGlvbnMgPSB0aGlzLl9hY3Rpb25zLFxyXG5cdFx0XHRjbGlwVXVpZCA9IGNsaXAudXVpZCxcclxuXHRcdFx0YWN0aW9uc0J5Q2xpcCA9IHRoaXMuX2FjdGlvbnNCeUNsaXAsXHJcblx0XHRcdGFjdGlvbnNGb3JDbGlwID0gYWN0aW9uc0J5Q2xpcFsgY2xpcFV1aWQgXTtcclxuXHJcblx0XHRpZiAoIGFjdGlvbnNGb3JDbGlwICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHQvLyBub3RlOiBqdXN0IGNhbGxpbmcgX3JlbW92ZUluYWN0aXZlQWN0aW9uIHdvdWxkIG1lc3MgdXAgdGhlXHJcblx0XHRcdC8vIGl0ZXJhdGlvbiBzdGF0ZSBhbmQgYWxzbyByZXF1aXJlIHVwZGF0aW5nIHRoZSBzdGF0ZSB3ZSBjYW5cclxuXHRcdFx0Ly8ganVzdCB0aHJvdyBhd2F5XHJcblxyXG5cdFx0XHRjb25zdCBhY3Rpb25zVG9SZW1vdmUgPSBhY3Rpb25zRm9yQ2xpcC5rbm93bkFjdGlvbnM7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIG4gPSBhY3Rpb25zVG9SZW1vdmUubGVuZ3RoOyBpICE9PSBuOyArKyBpICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBhY3Rpb24gPSBhY3Rpb25zVG9SZW1vdmVbIGkgXTtcclxuXHJcblx0XHRcdFx0dGhpcy5fZGVhY3RpdmF0ZUFjdGlvbiggYWN0aW9uICk7XHJcblxyXG5cdFx0XHRcdGNvbnN0IGNhY2hlSW5kZXggPSBhY3Rpb24uX2NhY2hlSW5kZXgsXHJcblx0XHRcdFx0XHRsYXN0SW5hY3RpdmVBY3Rpb24gPSBhY3Rpb25zWyBhY3Rpb25zLmxlbmd0aCAtIDEgXTtcclxuXHJcblx0XHRcdFx0YWN0aW9uLl9jYWNoZUluZGV4ID0gbnVsbDtcclxuXHRcdFx0XHRhY3Rpb24uX2J5Q2xpcENhY2hlSW5kZXggPSBudWxsO1xyXG5cclxuXHRcdFx0XHRsYXN0SW5hY3RpdmVBY3Rpb24uX2NhY2hlSW5kZXggPSBjYWNoZUluZGV4O1xyXG5cdFx0XHRcdGFjdGlvbnNbIGNhY2hlSW5kZXggXSA9IGxhc3RJbmFjdGl2ZUFjdGlvbjtcclxuXHRcdFx0XHRhY3Rpb25zLnBvcCgpO1xyXG5cclxuXHRcdFx0XHR0aGlzLl9yZW1vdmVJbmFjdGl2ZUJpbmRpbmdzRm9yQWN0aW9uKCBhY3Rpb24gKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGRlbGV0ZSBhY3Rpb25zQnlDbGlwWyBjbGlwVXVpZCBdO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHQvLyBmcmVlIGFsbCByZXNvdXJjZXMgc3BlY2lmaWMgdG8gYSBwYXJ0aWN1bGFyIHJvb3QgdGFyZ2V0IG9iamVjdFxyXG5cdHVuY2FjaGVSb290KCByb290ICkge1xyXG5cclxuXHRcdGNvbnN0IHJvb3RVdWlkID0gcm9vdC51dWlkLFxyXG5cdFx0XHRhY3Rpb25zQnlDbGlwID0gdGhpcy5fYWN0aW9uc0J5Q2xpcDtcclxuXHJcblx0XHRmb3IgKCBjb25zdCBjbGlwVXVpZCBpbiBhY3Rpb25zQnlDbGlwICkge1xyXG5cclxuXHRcdFx0Y29uc3QgYWN0aW9uQnlSb290ID0gYWN0aW9uc0J5Q2xpcFsgY2xpcFV1aWQgXS5hY3Rpb25CeVJvb3QsXHJcblx0XHRcdFx0YWN0aW9uID0gYWN0aW9uQnlSb290WyByb290VXVpZCBdO1xyXG5cclxuXHRcdFx0aWYgKCBhY3Rpb24gIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0dGhpcy5fZGVhY3RpdmF0ZUFjdGlvbiggYWN0aW9uICk7XHJcblx0XHRcdFx0dGhpcy5fcmVtb3ZlSW5hY3RpdmVBY3Rpb24oIGFjdGlvbiApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCBiaW5kaW5nc0J5Um9vdCA9IHRoaXMuX2JpbmRpbmdzQnlSb290QW5kTmFtZSxcclxuXHRcdFx0YmluZGluZ0J5TmFtZSA9IGJpbmRpbmdzQnlSb290WyByb290VXVpZCBdO1xyXG5cclxuXHRcdGlmICggYmluZGluZ0J5TmFtZSAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0Zm9yICggY29uc3QgdHJhY2tOYW1lIGluIGJpbmRpbmdCeU5hbWUgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IGJpbmRpbmcgPSBiaW5kaW5nQnlOYW1lWyB0cmFja05hbWUgXTtcclxuXHRcdFx0XHRiaW5kaW5nLnJlc3RvcmVPcmlnaW5hbFN0YXRlKCk7XHJcblx0XHRcdFx0dGhpcy5fcmVtb3ZlSW5hY3RpdmVCaW5kaW5nKCBiaW5kaW5nICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdC8vIHJlbW92ZSBhIHRhcmdldGVkIGNsaXAgZnJvbSB0aGUgY2FjaGVcclxuXHR1bmNhY2hlQWN0aW9uKCBjbGlwLCBvcHRpb25hbFJvb3QgKSB7XHJcblxyXG5cdFx0Y29uc3QgYWN0aW9uID0gdGhpcy5leGlzdGluZ0FjdGlvbiggY2xpcCwgb3B0aW9uYWxSb290ICk7XHJcblxyXG5cdFx0aWYgKCBhY3Rpb24gIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHR0aGlzLl9kZWFjdGl2YXRlQWN0aW9uKCBhY3Rpb24gKTtcclxuXHRcdFx0dGhpcy5fcmVtb3ZlSW5hY3RpdmVBY3Rpb24oIGFjdGlvbiApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgQW5pbWF0aW9uTWl4ZXIgfTtcclxuIiwiY2xhc3MgVW5pZm9ybSB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCB2YWx1ZSApIHtcclxuXHJcblx0XHR0aGlzLnZhbHVlID0gdmFsdWU7XHJcblxyXG5cdH1cclxuXHJcblx0Y2xvbmUoKSB7XHJcblxyXG5cdFx0cmV0dXJuIG5ldyBVbmlmb3JtKCB0aGlzLnZhbHVlLmNsb25lID09PSB1bmRlZmluZWQgPyB0aGlzLnZhbHVlIDogdGhpcy52YWx1ZS5jbG9uZSgpICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IFVuaWZvcm0gfTtcclxuIiwiaW1wb3J0IHsgRXZlbnREaXNwYXRjaGVyIH0gZnJvbSAnLi9FdmVudERpc3BhdGNoZXIuanMnO1xyXG5pbXBvcnQgeyBTdGF0aWNEcmF3VXNhZ2UgfSBmcm9tICcuLi9jb25zdGFudHMuanMnO1xyXG5cclxubGV0IF9pZCA9IDA7XHJcblxyXG5jbGFzcyBVbmlmb3Jtc0dyb3VwIGV4dGVuZHMgRXZlbnREaXNwYXRjaGVyIHtcclxuXHJcblx0Y29uc3RydWN0b3IoKSB7XHJcblxyXG5cdFx0c3VwZXIoKTtcclxuXHJcblx0XHR0aGlzLmlzVW5pZm9ybXNHcm91cCA9IHRydWU7XHJcblxyXG5cdFx0T2JqZWN0LmRlZmluZVByb3BlcnR5KCB0aGlzLCAnaWQnLCB7IHZhbHVlOiBfaWQgKysgfSApO1xyXG5cclxuXHRcdHRoaXMubmFtZSA9ICcnO1xyXG5cclxuXHRcdHRoaXMudXNhZ2UgPSBTdGF0aWNEcmF3VXNhZ2U7XHJcblx0XHR0aGlzLnVuaWZvcm1zID0gW107XHJcblxyXG5cdH1cclxuXHJcblx0YWRkKCB1bmlmb3JtICkge1xyXG5cclxuXHRcdHRoaXMudW5pZm9ybXMucHVzaCggdW5pZm9ybSApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHJlbW92ZSggdW5pZm9ybSApIHtcclxuXHJcblx0XHRjb25zdCBpbmRleCA9IHRoaXMudW5pZm9ybXMuaW5kZXhPZiggdW5pZm9ybSApO1xyXG5cclxuXHRcdGlmICggaW5kZXggIT09IC0gMSApIHRoaXMudW5pZm9ybXMuc3BsaWNlKCBpbmRleCwgMSApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldE5hbWUoIG5hbWUgKSB7XHJcblxyXG5cdFx0dGhpcy5uYW1lID0gbmFtZTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRVc2FnZSggdmFsdWUgKSB7XHJcblxyXG5cdFx0dGhpcy51c2FnZSA9IHZhbHVlO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGRpc3Bvc2UoKSB7XHJcblxyXG5cdFx0dGhpcy5kaXNwYXRjaEV2ZW50KCB7IHR5cGU6ICdkaXNwb3NlJyB9ICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHRoaXMubmFtZSA9IHNvdXJjZS5uYW1lO1xyXG5cdFx0dGhpcy51c2FnZSA9IHNvdXJjZS51c2FnZTtcclxuXHJcblx0XHRjb25zdCB1bmlmb3Jtc1NvdXJjZSA9IHNvdXJjZS51bmlmb3JtcztcclxuXHJcblx0XHR0aGlzLnVuaWZvcm1zLmxlbmd0aCA9IDA7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gdW5pZm9ybXNTb3VyY2UubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdGNvbnN0IHVuaWZvcm1zID0gQXJyYXkuaXNBcnJheSggdW5pZm9ybXNTb3VyY2VbIGkgXSApID8gdW5pZm9ybXNTb3VyY2VbIGkgXSA6IFsgdW5pZm9ybXNTb3VyY2VbIGkgXSBdO1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGogPSAwOyBqIDwgdW5pZm9ybXMubGVuZ3RoOyBqICsrICkge1xyXG5cclxuXHRcdFx0XHR0aGlzLnVuaWZvcm1zLnB1c2goIHVuaWZvcm1zWyBqIF0uY2xvbmUoKSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRjbG9uZSgpIHtcclxuXHJcblx0XHRyZXR1cm4gbmV3IHRoaXMuY29uc3RydWN0b3IoKS5jb3B5KCB0aGlzICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IFVuaWZvcm1zR3JvdXAgfTtcclxuIiwiaW1wb3J0IHsgSW50ZXJsZWF2ZWRCdWZmZXIgfSBmcm9tICcuL0ludGVybGVhdmVkQnVmZmVyLmpzJztcclxuXHJcbmNsYXNzIEluc3RhbmNlZEludGVybGVhdmVkQnVmZmVyIGV4dGVuZHMgSW50ZXJsZWF2ZWRCdWZmZXIge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggYXJyYXksIHN0cmlkZSwgbWVzaFBlckF0dHJpYnV0ZSA9IDEgKSB7XHJcblxyXG5cdFx0c3VwZXIoIGFycmF5LCBzdHJpZGUgKTtcclxuXHJcblx0XHR0aGlzLmlzSW5zdGFuY2VkSW50ZXJsZWF2ZWRCdWZmZXIgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMubWVzaFBlckF0dHJpYnV0ZSA9IG1lc2hQZXJBdHRyaWJ1dGU7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xyXG5cclxuXHRcdHRoaXMubWVzaFBlckF0dHJpYnV0ZSA9IHNvdXJjZS5tZXNoUGVyQXR0cmlidXRlO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGNsb25lKCBkYXRhICkge1xyXG5cclxuXHRcdGNvbnN0IGliID0gc3VwZXIuY2xvbmUoIGRhdGEgKTtcclxuXHJcblx0XHRpYi5tZXNoUGVyQXR0cmlidXRlID0gdGhpcy5tZXNoUGVyQXR0cmlidXRlO1xyXG5cclxuXHRcdHJldHVybiBpYjtcclxuXHJcblx0fVxyXG5cclxuXHR0b0pTT04oIGRhdGEgKSB7XHJcblxyXG5cdFx0Y29uc3QganNvbiA9IHN1cGVyLnRvSlNPTiggZGF0YSApO1xyXG5cclxuXHRcdGpzb24uaXNJbnN0YW5jZWRJbnRlcmxlYXZlZEJ1ZmZlciA9IHRydWU7XHJcblx0XHRqc29uLm1lc2hQZXJBdHRyaWJ1dGUgPSB0aGlzLm1lc2hQZXJBdHRyaWJ1dGU7XHJcblxyXG5cdFx0cmV0dXJuIGpzb247XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IEluc3RhbmNlZEludGVybGVhdmVkQnVmZmVyIH07XHJcbiIsImNsYXNzIEdMQnVmZmVyQXR0cmlidXRlIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIGJ1ZmZlciwgdHlwZSwgaXRlbVNpemUsIGVsZW1lbnRTaXplLCBjb3VudCApIHtcclxuXHJcblx0XHR0aGlzLmlzR0xCdWZmZXJBdHRyaWJ1dGUgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMubmFtZSA9ICcnO1xyXG5cclxuXHRcdHRoaXMuYnVmZmVyID0gYnVmZmVyO1xyXG5cdFx0dGhpcy50eXBlID0gdHlwZTtcclxuXHRcdHRoaXMuaXRlbVNpemUgPSBpdGVtU2l6ZTtcclxuXHRcdHRoaXMuZWxlbWVudFNpemUgPSBlbGVtZW50U2l6ZTtcclxuXHRcdHRoaXMuY291bnQgPSBjb3VudDtcclxuXHJcblx0XHR0aGlzLnZlcnNpb24gPSAwO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldCBuZWVkc1VwZGF0ZSggdmFsdWUgKSB7XHJcblxyXG5cdFx0aWYgKCB2YWx1ZSA9PT0gdHJ1ZSApIHRoaXMudmVyc2lvbiArKztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRCdWZmZXIoIGJ1ZmZlciApIHtcclxuXHJcblx0XHR0aGlzLmJ1ZmZlciA9IGJ1ZmZlcjtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRUeXBlKCB0eXBlLCBlbGVtZW50U2l6ZSApIHtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSB0eXBlO1xyXG5cdFx0dGhpcy5lbGVtZW50U2l6ZSA9IGVsZW1lbnRTaXplO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldEl0ZW1TaXplKCBpdGVtU2l6ZSApIHtcclxuXHJcblx0XHR0aGlzLml0ZW1TaXplID0gaXRlbVNpemU7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0Q291bnQoIGNvdW50ICkge1xyXG5cclxuXHRcdHRoaXMuY291bnQgPSBjb3VudDtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgR0xCdWZmZXJBdHRyaWJ1dGUgfTtcclxuIiwiaW1wb3J0IHsgUmF5IH0gZnJvbSAnLi4vbWF0aC9SYXkuanMnO1xyXG5pbXBvcnQgeyBMYXllcnMgfSBmcm9tICcuL0xheWVycy5qcyc7XHJcblxyXG5jbGFzcyBSYXljYXN0ZXIge1xyXG5cclxuXHRjb25zdHJ1Y3Rvciggb3JpZ2luLCBkaXJlY3Rpb24sIG5lYXIgPSAwLCBmYXIgPSBJbmZpbml0eSApIHtcclxuXHJcblx0XHR0aGlzLnJheSA9IG5ldyBSYXkoIG9yaWdpbiwgZGlyZWN0aW9uICk7XHJcblx0XHQvLyBkaXJlY3Rpb24gaXMgYXNzdW1lZCB0byBiZSBub3JtYWxpemVkIChmb3IgYWNjdXJhdGUgZGlzdGFuY2UgY2FsY3VsYXRpb25zKVxyXG5cclxuXHRcdHRoaXMubmVhciA9IG5lYXI7XHJcblx0XHR0aGlzLmZhciA9IGZhcjtcclxuXHRcdHRoaXMuY2FtZXJhID0gbnVsbDtcclxuXHRcdHRoaXMubGF5ZXJzID0gbmV3IExheWVycygpO1xyXG5cclxuXHRcdHRoaXMucGFyYW1zID0ge1xyXG5cdFx0XHRNZXNoOiB7fSxcclxuXHRcdFx0TGluZTogeyB0aHJlc2hvbGQ6IDEgfSxcclxuXHRcdFx0TE9EOiB7fSxcclxuXHRcdFx0UG9pbnRzOiB7IHRocmVzaG9sZDogMSB9LFxyXG5cdFx0XHRTcHJpdGU6IHt9XHJcblx0XHR9O1xyXG5cclxuXHR9XHJcblxyXG5cdHNldCggb3JpZ2luLCBkaXJlY3Rpb24gKSB7XHJcblxyXG5cdFx0Ly8gZGlyZWN0aW9uIGlzIGFzc3VtZWQgdG8gYmUgbm9ybWFsaXplZCAoZm9yIGFjY3VyYXRlIGRpc3RhbmNlIGNhbGN1bGF0aW9ucylcclxuXHJcblx0XHR0aGlzLnJheS5zZXQoIG9yaWdpbiwgZGlyZWN0aW9uICk7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0RnJvbUNhbWVyYSggY29vcmRzLCBjYW1lcmEgKSB7XHJcblxyXG5cdFx0aWYgKCBjYW1lcmEuaXNQZXJzcGVjdGl2ZUNhbWVyYSApIHtcclxuXHJcblx0XHRcdHRoaXMucmF5Lm9yaWdpbi5zZXRGcm9tTWF0cml4UG9zaXRpb24oIGNhbWVyYS5tYXRyaXhXb3JsZCApO1xyXG5cdFx0XHR0aGlzLnJheS5kaXJlY3Rpb24uc2V0KCBjb29yZHMueCwgY29vcmRzLnksIDAuNSApLnVucHJvamVjdCggY2FtZXJhICkuc3ViKCB0aGlzLnJheS5vcmlnaW4gKS5ub3JtYWxpemUoKTtcclxuXHRcdFx0dGhpcy5jYW1lcmEgPSBjYW1lcmE7XHJcblxyXG5cdFx0fSBlbHNlIGlmICggY2FtZXJhLmlzT3J0aG9ncmFwaGljQ2FtZXJhICkge1xyXG5cclxuXHRcdFx0dGhpcy5yYXkub3JpZ2luLnNldCggY29vcmRzLngsIGNvb3Jkcy55LCAoIGNhbWVyYS5uZWFyICsgY2FtZXJhLmZhciApIC8gKCBjYW1lcmEubmVhciAtIGNhbWVyYS5mYXIgKSApLnVucHJvamVjdCggY2FtZXJhICk7IC8vIHNldCBvcmlnaW4gaW4gcGxhbmUgb2YgY2FtZXJhXHJcblx0XHRcdHRoaXMucmF5LmRpcmVjdGlvbi5zZXQoIDAsIDAsIC0gMSApLnRyYW5zZm9ybURpcmVjdGlvbiggY2FtZXJhLm1hdHJpeFdvcmxkICk7XHJcblx0XHRcdHRoaXMuY2FtZXJhID0gY2FtZXJhO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuUmF5Y2FzdGVyOiBVbnN1cHBvcnRlZCBjYW1lcmEgdHlwZTogJyArIGNhbWVyYS50eXBlICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGludGVyc2VjdE9iamVjdCggb2JqZWN0LCByZWN1cnNpdmUgPSB0cnVlLCBpbnRlcnNlY3RzID0gW10gKSB7XHJcblxyXG5cdFx0aW50ZXJzZWN0T2JqZWN0KCBvYmplY3QsIHRoaXMsIGludGVyc2VjdHMsIHJlY3Vyc2l2ZSApO1xyXG5cclxuXHRcdGludGVyc2VjdHMuc29ydCggYXNjU29ydCApO1xyXG5cclxuXHRcdHJldHVybiBpbnRlcnNlY3RzO1xyXG5cclxuXHR9XHJcblxyXG5cdGludGVyc2VjdE9iamVjdHMoIG9iamVjdHMsIHJlY3Vyc2l2ZSA9IHRydWUsIGludGVyc2VjdHMgPSBbXSApIHtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBvYmplY3RzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRpbnRlcnNlY3RPYmplY3QoIG9iamVjdHNbIGkgXSwgdGhpcywgaW50ZXJzZWN0cywgcmVjdXJzaXZlICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGludGVyc2VjdHMuc29ydCggYXNjU29ydCApO1xyXG5cclxuXHRcdHJldHVybiBpbnRlcnNlY3RzO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiBhc2NTb3J0KCBhLCBiICkge1xyXG5cclxuXHRyZXR1cm4gYS5kaXN0YW5jZSAtIGIuZGlzdGFuY2U7XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiBpbnRlcnNlY3RPYmplY3QoIG9iamVjdCwgcmF5Y2FzdGVyLCBpbnRlcnNlY3RzLCByZWN1cnNpdmUgKSB7XHJcblxyXG5cdGlmICggb2JqZWN0LmxheWVycy50ZXN0KCByYXljYXN0ZXIubGF5ZXJzICkgKSB7XHJcblxyXG5cdFx0b2JqZWN0LnJheWNhc3QoIHJheWNhc3RlciwgaW50ZXJzZWN0cyApO1xyXG5cclxuXHR9XHJcblxyXG5cdGlmICggcmVjdXJzaXZlID09PSB0cnVlICkge1xyXG5cclxuXHRcdGNvbnN0IGNoaWxkcmVuID0gb2JqZWN0LmNoaWxkcmVuO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IGNoaWxkcmVuLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRpbnRlcnNlY3RPYmplY3QoIGNoaWxkcmVuWyBpIF0sIHJheWNhc3RlciwgaW50ZXJzZWN0cywgdHJ1ZSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgUmF5Y2FzdGVyIH07XHJcbiIsIi8qKlxyXG4gKiBSZWY6IGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL1NwaGVyaWNhbF9jb29yZGluYXRlX3N5c3RlbVxyXG4gKlxyXG4gKiBUaGUgcG9sYXIgYW5nbGUgKHBoaSkgaXMgbWVhc3VyZWQgZnJvbSB0aGUgcG9zaXRpdmUgeS1heGlzLiBUaGUgcG9zaXRpdmUgeS1heGlzIGlzIHVwLlxyXG4gKiBUaGUgYXppbXV0aGFsIGFuZ2xlICh0aGV0YSkgaXMgbWVhc3VyZWQgZnJvbSB0aGUgcG9zaXRpdmUgei1heGlzLlxyXG4gKi9cclxuXHJcbmltcG9ydCAqIGFzIE1hdGhVdGlscyBmcm9tICcuL01hdGhVdGlscy5qcyc7XHJcblxyXG5jbGFzcyBTcGhlcmljYWwge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggcmFkaXVzID0gMSwgcGhpID0gMCwgdGhldGEgPSAwICkge1xyXG5cclxuXHRcdHRoaXMucmFkaXVzID0gcmFkaXVzO1xyXG5cdFx0dGhpcy5waGkgPSBwaGk7IC8vIHBvbGFyIGFuZ2xlXHJcblx0XHR0aGlzLnRoZXRhID0gdGhldGE7IC8vIGF6aW11dGhhbCBhbmdsZVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldCggcmFkaXVzLCBwaGksIHRoZXRhICkge1xyXG5cclxuXHRcdHRoaXMucmFkaXVzID0gcmFkaXVzO1xyXG5cdFx0dGhpcy5waGkgPSBwaGk7XHJcblx0XHR0aGlzLnRoZXRhID0gdGhldGE7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggb3RoZXIgKSB7XHJcblxyXG5cdFx0dGhpcy5yYWRpdXMgPSBvdGhlci5yYWRpdXM7XHJcblx0XHR0aGlzLnBoaSA9IG90aGVyLnBoaTtcclxuXHRcdHRoaXMudGhldGEgPSBvdGhlci50aGV0YTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHQvLyByZXN0cmljdCBwaGkgdG8gYmUgYmV0d2VlbiBFUFMgYW5kIFBJLUVQU1xyXG5cdG1ha2VTYWZlKCkge1xyXG5cclxuXHRcdGNvbnN0IEVQUyA9IDAuMDAwMDAxO1xyXG5cdFx0dGhpcy5waGkgPSBNYXRoLm1heCggRVBTLCBNYXRoLm1pbiggTWF0aC5QSSAtIEVQUywgdGhpcy5waGkgKSApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldEZyb21WZWN0b3IzKCB2ICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLnNldEZyb21DYXJ0ZXNpYW5Db29yZHMoIHYueCwgdi55LCB2LnogKTtcclxuXHJcblx0fVxyXG5cclxuXHRzZXRGcm9tQ2FydGVzaWFuQ29vcmRzKCB4LCB5LCB6ICkge1xyXG5cclxuXHRcdHRoaXMucmFkaXVzID0gTWF0aC5zcXJ0KCB4ICogeCArIHkgKiB5ICsgeiAqIHogKTtcclxuXHJcblx0XHRpZiAoIHRoaXMucmFkaXVzID09PSAwICkge1xyXG5cclxuXHRcdFx0dGhpcy50aGV0YSA9IDA7XHJcblx0XHRcdHRoaXMucGhpID0gMDtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0dGhpcy50aGV0YSA9IE1hdGguYXRhbjIoIHgsIHogKTtcclxuXHRcdFx0dGhpcy5waGkgPSBNYXRoLmFjb3MoIE1hdGhVdGlscy5jbGFtcCggeSAvIHRoaXMucmFkaXVzLCAtIDEsIDEgKSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRjbG9uZSgpIHtcclxuXHJcblx0XHRyZXR1cm4gbmV3IHRoaXMuY29uc3RydWN0b3IoKS5jb3B5KCB0aGlzICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IFNwaGVyaWNhbCB9O1xyXG4iLCIvKipcclxuICogUmVmOiBodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9DeWxpbmRyaWNhbF9jb29yZGluYXRlX3N5c3RlbVxyXG4gKi9cclxuXHJcbmNsYXNzIEN5bGluZHJpY2FsIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIHJhZGl1cyA9IDEsIHRoZXRhID0gMCwgeSA9IDAgKSB7XHJcblxyXG5cdFx0dGhpcy5yYWRpdXMgPSByYWRpdXM7IC8vIGRpc3RhbmNlIGZyb20gdGhlIG9yaWdpbiB0byBhIHBvaW50IGluIHRoZSB4LXogcGxhbmVcclxuXHRcdHRoaXMudGhldGEgPSB0aGV0YTsgLy8gY291bnRlcmNsb2Nrd2lzZSBhbmdsZSBpbiB0aGUgeC16IHBsYW5lIG1lYXN1cmVkIGluIHJhZGlhbnMgZnJvbSB0aGUgcG9zaXRpdmUgei1heGlzXHJcblx0XHR0aGlzLnkgPSB5OyAvLyBoZWlnaHQgYWJvdmUgdGhlIHgteiBwbGFuZVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldCggcmFkaXVzLCB0aGV0YSwgeSApIHtcclxuXHJcblx0XHR0aGlzLnJhZGl1cyA9IHJhZGl1cztcclxuXHRcdHRoaXMudGhldGEgPSB0aGV0YTtcclxuXHRcdHRoaXMueSA9IHk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggb3RoZXIgKSB7XHJcblxyXG5cdFx0dGhpcy5yYWRpdXMgPSBvdGhlci5yYWRpdXM7XHJcblx0XHR0aGlzLnRoZXRhID0gb3RoZXIudGhldGE7XHJcblx0XHR0aGlzLnkgPSBvdGhlci55O1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldEZyb21WZWN0b3IzKCB2ICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLnNldEZyb21DYXJ0ZXNpYW5Db29yZHMoIHYueCwgdi55LCB2LnogKTtcclxuXHJcblx0fVxyXG5cclxuXHRzZXRGcm9tQ2FydGVzaWFuQ29vcmRzKCB4LCB5LCB6ICkge1xyXG5cclxuXHRcdHRoaXMucmFkaXVzID0gTWF0aC5zcXJ0KCB4ICogeCArIHogKiB6ICk7XHJcblx0XHR0aGlzLnRoZXRhID0gTWF0aC5hdGFuMiggeCwgeiApO1xyXG5cdFx0dGhpcy55ID0geTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRjbG9uZSgpIHtcclxuXHJcblx0XHRyZXR1cm4gbmV3IHRoaXMuY29uc3RydWN0b3IoKS5jb3B5KCB0aGlzICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IEN5bGluZHJpY2FsIH07XHJcbiIsImltcG9ydCB7IFZlY3RvcjIgfSBmcm9tICcuL1ZlY3RvcjIuanMnO1xyXG5cclxuY29uc3QgX3ZlY3RvciA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjIoKTtcclxuXHJcbmNsYXNzIEJveDIge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggbWluID0gbmV3IFZlY3RvcjIoICsgSW5maW5pdHksICsgSW5maW5pdHkgKSwgbWF4ID0gbmV3IFZlY3RvcjIoIC0gSW5maW5pdHksIC0gSW5maW5pdHkgKSApIHtcclxuXHJcblx0XHR0aGlzLmlzQm94MiA9IHRydWU7XHJcblxyXG5cdFx0dGhpcy5taW4gPSBtaW47XHJcblx0XHR0aGlzLm1heCA9IG1heDtcclxuXHJcblx0fVxyXG5cclxuXHRzZXQoIG1pbiwgbWF4ICkge1xyXG5cclxuXHRcdHRoaXMubWluLmNvcHkoIG1pbiApO1xyXG5cdFx0dGhpcy5tYXguY29weSggbWF4ICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0RnJvbVBvaW50cyggcG9pbnRzICkge1xyXG5cclxuXHRcdHRoaXMubWFrZUVtcHR5KCk7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBpbCA9IHBvaW50cy5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcclxuXHJcblx0XHRcdHRoaXMuZXhwYW5kQnlQb2ludCggcG9pbnRzWyBpIF0gKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0RnJvbUNlbnRlckFuZFNpemUoIGNlbnRlciwgc2l6ZSApIHtcclxuXHJcblx0XHRjb25zdCBoYWxmU2l6ZSA9IF92ZWN0b3IuY29weSggc2l6ZSApLm11bHRpcGx5U2NhbGFyKCAwLjUgKTtcclxuXHRcdHRoaXMubWluLmNvcHkoIGNlbnRlciApLnN1YiggaGFsZlNpemUgKTtcclxuXHRcdHRoaXMubWF4LmNvcHkoIGNlbnRlciApLmFkZCggaGFsZlNpemUgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRjbG9uZSgpIHtcclxuXHJcblx0XHRyZXR1cm4gbmV3IHRoaXMuY29uc3RydWN0b3IoKS5jb3B5KCB0aGlzICk7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggYm94ICkge1xyXG5cclxuXHRcdHRoaXMubWluLmNvcHkoIGJveC5taW4gKTtcclxuXHRcdHRoaXMubWF4LmNvcHkoIGJveC5tYXggKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRtYWtlRW1wdHkoKSB7XHJcblxyXG5cdFx0dGhpcy5taW4ueCA9IHRoaXMubWluLnkgPSArIEluZmluaXR5O1xyXG5cdFx0dGhpcy5tYXgueCA9IHRoaXMubWF4LnkgPSAtIEluZmluaXR5O1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGlzRW1wdHkoKSB7XHJcblxyXG5cdFx0Ly8gdGhpcyBpcyBhIG1vcmUgcm9idXN0IGNoZWNrIGZvciBlbXB0eSB0aGFuICggdm9sdW1lIDw9IDAgKSBiZWNhdXNlIHZvbHVtZSBjYW4gZ2V0IHBvc2l0aXZlIHdpdGggdHdvIG5lZ2F0aXZlIGF4ZXNcclxuXHJcblx0XHRyZXR1cm4gKCB0aGlzLm1heC54IDwgdGhpcy5taW4ueCApIHx8ICggdGhpcy5tYXgueSA8IHRoaXMubWluLnkgKTtcclxuXHJcblx0fVxyXG5cclxuXHRnZXRDZW50ZXIoIHRhcmdldCApIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5pc0VtcHR5KCkgPyB0YXJnZXQuc2V0KCAwLCAwICkgOiB0YXJnZXQuYWRkVmVjdG9ycyggdGhpcy5taW4sIHRoaXMubWF4ICkubXVsdGlwbHlTY2FsYXIoIDAuNSApO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldFNpemUoIHRhcmdldCApIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5pc0VtcHR5KCkgPyB0YXJnZXQuc2V0KCAwLCAwICkgOiB0YXJnZXQuc3ViVmVjdG9ycyggdGhpcy5tYXgsIHRoaXMubWluICk7XHJcblxyXG5cdH1cclxuXHJcblx0ZXhwYW5kQnlQb2ludCggcG9pbnQgKSB7XHJcblxyXG5cdFx0dGhpcy5taW4ubWluKCBwb2ludCApO1xyXG5cdFx0dGhpcy5tYXgubWF4KCBwb2ludCApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGV4cGFuZEJ5VmVjdG9yKCB2ZWN0b3IgKSB7XHJcblxyXG5cdFx0dGhpcy5taW4uc3ViKCB2ZWN0b3IgKTtcclxuXHRcdHRoaXMubWF4LmFkZCggdmVjdG9yICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0ZXhwYW5kQnlTY2FsYXIoIHNjYWxhciApIHtcclxuXHJcblx0XHR0aGlzLm1pbi5hZGRTY2FsYXIoIC0gc2NhbGFyICk7XHJcblx0XHR0aGlzLm1heC5hZGRTY2FsYXIoIHNjYWxhciApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGNvbnRhaW5zUG9pbnQoIHBvaW50ICkge1xyXG5cclxuXHRcdHJldHVybiBwb2ludC54IDwgdGhpcy5taW4ueCB8fCBwb2ludC54ID4gdGhpcy5tYXgueCB8fFxyXG5cdFx0XHRwb2ludC55IDwgdGhpcy5taW4ueSB8fCBwb2ludC55ID4gdGhpcy5tYXgueSA/IGZhbHNlIDogdHJ1ZTtcclxuXHJcblx0fVxyXG5cclxuXHRjb250YWluc0JveCggYm94ICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLm1pbi54IDw9IGJveC5taW4ueCAmJiBib3gubWF4LnggPD0gdGhpcy5tYXgueCAmJlxyXG5cdFx0XHR0aGlzLm1pbi55IDw9IGJveC5taW4ueSAmJiBib3gubWF4LnkgPD0gdGhpcy5tYXgueTtcclxuXHJcblx0fVxyXG5cclxuXHRnZXRQYXJhbWV0ZXIoIHBvaW50LCB0YXJnZXQgKSB7XHJcblxyXG5cdFx0Ly8gVGhpcyBjYW4gcG90ZW50aWFsbHkgaGF2ZSBhIGRpdmlkZSBieSB6ZXJvIGlmIHRoZSBib3hcclxuXHRcdC8vIGhhcyBhIHNpemUgZGltZW5zaW9uIG9mIDAuXHJcblxyXG5cdFx0cmV0dXJuIHRhcmdldC5zZXQoXHJcblx0XHRcdCggcG9pbnQueCAtIHRoaXMubWluLnggKSAvICggdGhpcy5tYXgueCAtIHRoaXMubWluLnggKSxcclxuXHRcdFx0KCBwb2ludC55IC0gdGhpcy5taW4ueSApIC8gKCB0aGlzLm1heC55IC0gdGhpcy5taW4ueSApXHJcblx0XHQpO1xyXG5cclxuXHR9XHJcblxyXG5cdGludGVyc2VjdHNCb3goIGJveCApIHtcclxuXHJcblx0XHQvLyB1c2luZyA0IHNwbGl0dGluZyBwbGFuZXMgdG8gcnVsZSBvdXQgaW50ZXJzZWN0aW9uc1xyXG5cclxuXHRcdHJldHVybiBib3gubWF4LnggPCB0aGlzLm1pbi54IHx8IGJveC5taW4ueCA+IHRoaXMubWF4LnggfHxcclxuXHRcdFx0Ym94Lm1heC55IDwgdGhpcy5taW4ueSB8fCBib3gubWluLnkgPiB0aGlzLm1heC55ID8gZmFsc2UgOiB0cnVlO1xyXG5cclxuXHR9XHJcblxyXG5cdGNsYW1wUG9pbnQoIHBvaW50LCB0YXJnZXQgKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRhcmdldC5jb3B5KCBwb2ludCApLmNsYW1wKCB0aGlzLm1pbiwgdGhpcy5tYXggKTtcclxuXHJcblx0fVxyXG5cclxuXHRkaXN0YW5jZVRvUG9pbnQoIHBvaW50ICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLmNsYW1wUG9pbnQoIHBvaW50LCBfdmVjdG9yICkuZGlzdGFuY2VUbyggcG9pbnQgKTtcclxuXHJcblx0fVxyXG5cclxuXHRpbnRlcnNlY3QoIGJveCApIHtcclxuXHJcblx0XHR0aGlzLm1pbi5tYXgoIGJveC5taW4gKTtcclxuXHRcdHRoaXMubWF4Lm1pbiggYm94Lm1heCApO1xyXG5cclxuXHRcdGlmICggdGhpcy5pc0VtcHR5KCkgKSB0aGlzLm1ha2VFbXB0eSgpO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHVuaW9uKCBib3ggKSB7XHJcblxyXG5cdFx0dGhpcy5taW4ubWluKCBib3gubWluICk7XHJcblx0XHR0aGlzLm1heC5tYXgoIGJveC5tYXggKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHR0cmFuc2xhdGUoIG9mZnNldCApIHtcclxuXHJcblx0XHR0aGlzLm1pbi5hZGQoIG9mZnNldCApO1xyXG5cdFx0dGhpcy5tYXguYWRkKCBvZmZzZXQgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRlcXVhbHMoIGJveCApIHtcclxuXHJcblx0XHRyZXR1cm4gYm94Lm1pbi5lcXVhbHMoIHRoaXMubWluICkgJiYgYm94Lm1heC5lcXVhbHMoIHRoaXMubWF4ICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IEJveDIgfTtcclxuIiwiaW1wb3J0IHsgVmVjdG9yMyB9IGZyb20gJy4vVmVjdG9yMy5qcyc7XHJcbmltcG9ydCAqIGFzIE1hdGhVdGlscyBmcm9tICcuL01hdGhVdGlscy5qcyc7XHJcblxyXG5jb25zdCBfc3RhcnRQID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5jb25zdCBfc3RhcnRFbmQgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XHJcblxyXG5jbGFzcyBMaW5lMyB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBzdGFydCA9IG5ldyBWZWN0b3IzKCksIGVuZCA9IG5ldyBWZWN0b3IzKCkgKSB7XHJcblxyXG5cdFx0dGhpcy5zdGFydCA9IHN0YXJ0O1xyXG5cdFx0dGhpcy5lbmQgPSBlbmQ7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0KCBzdGFydCwgZW5kICkge1xyXG5cclxuXHRcdHRoaXMuc3RhcnQuY29weSggc3RhcnQgKTtcclxuXHRcdHRoaXMuZW5kLmNvcHkoIGVuZCApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGNvcHkoIGxpbmUgKSB7XHJcblxyXG5cdFx0dGhpcy5zdGFydC5jb3B5KCBsaW5lLnN0YXJ0ICk7XHJcblx0XHR0aGlzLmVuZC5jb3B5KCBsaW5lLmVuZCApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldENlbnRlciggdGFyZ2V0ICkge1xyXG5cclxuXHRcdHJldHVybiB0YXJnZXQuYWRkVmVjdG9ycyggdGhpcy5zdGFydCwgdGhpcy5lbmQgKS5tdWx0aXBseVNjYWxhciggMC41ICk7XHJcblxyXG5cdH1cclxuXHJcblx0ZGVsdGEoIHRhcmdldCApIHtcclxuXHJcblx0XHRyZXR1cm4gdGFyZ2V0LnN1YlZlY3RvcnMoIHRoaXMuZW5kLCB0aGlzLnN0YXJ0ICk7XHJcblxyXG5cdH1cclxuXHJcblx0ZGlzdGFuY2VTcSgpIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5zdGFydC5kaXN0YW5jZVRvU3F1YXJlZCggdGhpcy5lbmQgKTtcclxuXHJcblx0fVxyXG5cclxuXHRkaXN0YW5jZSgpIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5zdGFydC5kaXN0YW5jZVRvKCB0aGlzLmVuZCApO1xyXG5cclxuXHR9XHJcblxyXG5cdGF0KCB0LCB0YXJnZXQgKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuZGVsdGEoIHRhcmdldCApLm11bHRpcGx5U2NhbGFyKCB0ICkuYWRkKCB0aGlzLnN0YXJ0ICk7XHJcblxyXG5cdH1cclxuXHJcblx0Y2xvc2VzdFBvaW50VG9Qb2ludFBhcmFtZXRlciggcG9pbnQsIGNsYW1wVG9MaW5lICkge1xyXG5cclxuXHRcdF9zdGFydFAuc3ViVmVjdG9ycyggcG9pbnQsIHRoaXMuc3RhcnQgKTtcclxuXHRcdF9zdGFydEVuZC5zdWJWZWN0b3JzKCB0aGlzLmVuZCwgdGhpcy5zdGFydCApO1xyXG5cclxuXHRcdGNvbnN0IHN0YXJ0RW5kMiA9IF9zdGFydEVuZC5kb3QoIF9zdGFydEVuZCApO1xyXG5cdFx0Y29uc3Qgc3RhcnRFbmRfc3RhcnRQID0gX3N0YXJ0RW5kLmRvdCggX3N0YXJ0UCApO1xyXG5cclxuXHRcdGxldCB0ID0gc3RhcnRFbmRfc3RhcnRQIC8gc3RhcnRFbmQyO1xyXG5cclxuXHRcdGlmICggY2xhbXBUb0xpbmUgKSB7XHJcblxyXG5cdFx0XHR0ID0gTWF0aFV0aWxzLmNsYW1wKCB0LCAwLCAxICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0O1xyXG5cclxuXHR9XHJcblxyXG5cdGNsb3Nlc3RQb2ludFRvUG9pbnQoIHBvaW50LCBjbGFtcFRvTGluZSwgdGFyZ2V0ICkge1xyXG5cclxuXHRcdGNvbnN0IHQgPSB0aGlzLmNsb3Nlc3RQb2ludFRvUG9pbnRQYXJhbWV0ZXIoIHBvaW50LCBjbGFtcFRvTGluZSApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzLmRlbHRhKCB0YXJnZXQgKS5tdWx0aXBseVNjYWxhciggdCApLmFkZCggdGhpcy5zdGFydCApO1xyXG5cclxuXHR9XHJcblxyXG5cdGFwcGx5TWF0cml4NCggbWF0cml4ICkge1xyXG5cclxuXHRcdHRoaXMuc3RhcnQuYXBwbHlNYXRyaXg0KCBtYXRyaXggKTtcclxuXHRcdHRoaXMuZW5kLmFwcGx5TWF0cml4NCggbWF0cml4ICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0ZXF1YWxzKCBsaW5lICkge1xyXG5cclxuXHRcdHJldHVybiBsaW5lLnN0YXJ0LmVxdWFscyggdGhpcy5zdGFydCApICYmIGxpbmUuZW5kLmVxdWFscyggdGhpcy5lbmQgKTtcclxuXHJcblx0fVxyXG5cclxuXHRjbG9uZSgpIHtcclxuXHJcblx0XHRyZXR1cm4gbmV3IHRoaXMuY29uc3RydWN0b3IoKS5jb3B5KCB0aGlzICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IExpbmUzIH07XHJcbiIsImltcG9ydCB7IFZlY3RvcjMgfSBmcm9tICcuLi9tYXRoL1ZlY3RvcjMuanMnO1xyXG5pbXBvcnQgeyBPYmplY3QzRCB9IGZyb20gJy4uL2NvcmUvT2JqZWN0M0QuanMnO1xyXG5pbXBvcnQgeyBMaW5lU2VnbWVudHMgfSBmcm9tICcuLi9vYmplY3RzL0xpbmVTZWdtZW50cy5qcyc7XHJcbmltcG9ydCB7IExpbmVCYXNpY01hdGVyaWFsIH0gZnJvbSAnLi4vbWF0ZXJpYWxzL0xpbmVCYXNpY01hdGVyaWFsLmpzJztcclxuaW1wb3J0IHsgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSB9IGZyb20gJy4uL2NvcmUvQnVmZmVyQXR0cmlidXRlLmpzJztcclxuaW1wb3J0IHsgQnVmZmVyR2VvbWV0cnkgfSBmcm9tICcuLi9jb3JlL0J1ZmZlckdlb21ldHJ5LmpzJztcclxuXHJcbmNvbnN0IF92ZWN0b3IgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XHJcblxyXG5jbGFzcyBTcG90TGlnaHRIZWxwZXIgZXh0ZW5kcyBPYmplY3QzRCB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBsaWdodCwgY29sb3IgKSB7XHJcblxyXG5cdFx0c3VwZXIoKTtcclxuXHJcblx0XHR0aGlzLmxpZ2h0ID0gbGlnaHQ7XHJcblxyXG5cdFx0dGhpcy5tYXRyaXggPSBsaWdodC5tYXRyaXhXb3JsZDtcclxuXHRcdHRoaXMubWF0cml4QXV0b1VwZGF0ZSA9IGZhbHNlO1xyXG5cclxuXHRcdHRoaXMuY29sb3IgPSBjb2xvcjtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSAnU3BvdExpZ2h0SGVscGVyJztcclxuXHJcblx0XHRjb25zdCBnZW9tZXRyeSA9IG5ldyBCdWZmZXJHZW9tZXRyeSgpO1xyXG5cclxuXHRcdGNvbnN0IHBvc2l0aW9ucyA9IFtcclxuXHRcdFx0MCwgMCwgMCwgXHQwLCAwLCAxLFxyXG5cdFx0XHQwLCAwLCAwLCBcdDEsIDAsIDEsXHJcblx0XHRcdDAsIDAsIDAsXHQtIDEsIDAsIDEsXHJcblx0XHRcdDAsIDAsIDAsIFx0MCwgMSwgMSxcclxuXHRcdFx0MCwgMCwgMCwgXHQwLCAtIDEsIDFcclxuXHRcdF07XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBqID0gMSwgbCA9IDMyOyBpIDwgbDsgaSArKywgaiArKyApIHtcclxuXHJcblx0XHRcdGNvbnN0IHAxID0gKCBpIC8gbCApICogTWF0aC5QSSAqIDI7XHJcblx0XHRcdGNvbnN0IHAyID0gKCBqIC8gbCApICogTWF0aC5QSSAqIDI7XHJcblxyXG5cdFx0XHRwb3NpdGlvbnMucHVzaChcclxuXHRcdFx0XHRNYXRoLmNvcyggcDEgKSwgTWF0aC5zaW4oIHAxICksIDEsXHJcblx0XHRcdFx0TWF0aC5jb3MoIHAyICksIE1hdGguc2luKCBwMiApLCAxXHJcblx0XHRcdCk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGdlb21ldHJ5LnNldEF0dHJpYnV0ZSggJ3Bvc2l0aW9uJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIHBvc2l0aW9ucywgMyApICk7XHJcblxyXG5cdFx0Y29uc3QgbWF0ZXJpYWwgPSBuZXcgTGluZUJhc2ljTWF0ZXJpYWwoIHsgZm9nOiBmYWxzZSwgdG9uZU1hcHBlZDogZmFsc2UgfSApO1xyXG5cclxuXHRcdHRoaXMuY29uZSA9IG5ldyBMaW5lU2VnbWVudHMoIGdlb21ldHJ5LCBtYXRlcmlhbCApO1xyXG5cdFx0dGhpcy5hZGQoIHRoaXMuY29uZSApO1xyXG5cclxuXHRcdHRoaXMudXBkYXRlKCk7XHJcblxyXG5cdH1cclxuXHJcblx0ZGlzcG9zZSgpIHtcclxuXHJcblx0XHR0aGlzLmNvbmUuZ2VvbWV0cnkuZGlzcG9zZSgpO1xyXG5cdFx0dGhpcy5jb25lLm1hdGVyaWFsLmRpc3Bvc2UoKTtcclxuXHJcblx0fVxyXG5cclxuXHR1cGRhdGUoKSB7XHJcblxyXG5cdFx0dGhpcy5saWdodC51cGRhdGVXb3JsZE1hdHJpeCggdHJ1ZSwgZmFsc2UgKTtcclxuXHRcdHRoaXMubGlnaHQudGFyZ2V0LnVwZGF0ZVdvcmxkTWF0cml4KCB0cnVlLCBmYWxzZSApO1xyXG5cclxuXHRcdGNvbnN0IGNvbmVMZW5ndGggPSB0aGlzLmxpZ2h0LmRpc3RhbmNlID8gdGhpcy5saWdodC5kaXN0YW5jZSA6IDEwMDA7XHJcblx0XHRjb25zdCBjb25lV2lkdGggPSBjb25lTGVuZ3RoICogTWF0aC50YW4oIHRoaXMubGlnaHQuYW5nbGUgKTtcclxuXHJcblx0XHR0aGlzLmNvbmUuc2NhbGUuc2V0KCBjb25lV2lkdGgsIGNvbmVXaWR0aCwgY29uZUxlbmd0aCApO1xyXG5cclxuXHRcdF92ZWN0b3Iuc2V0RnJvbU1hdHJpeFBvc2l0aW9uKCB0aGlzLmxpZ2h0LnRhcmdldC5tYXRyaXhXb3JsZCApO1xyXG5cclxuXHRcdHRoaXMuY29uZS5sb29rQXQoIF92ZWN0b3IgKTtcclxuXHJcblx0XHRpZiAoIHRoaXMuY29sb3IgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdHRoaXMuY29uZS5tYXRlcmlhbC5jb2xvci5zZXQoIHRoaXMuY29sb3IgKTtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0dGhpcy5jb25lLm1hdGVyaWFsLmNvbG9yLmNvcHkoIHRoaXMubGlnaHQuY29sb3IgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcblxyXG5leHBvcnQgeyBTcG90TGlnaHRIZWxwZXIgfTtcclxuIiwiaW1wb3J0IHsgTGluZVNlZ21lbnRzIH0gZnJvbSAnLi4vb2JqZWN0cy9MaW5lU2VnbWVudHMuanMnO1xyXG5pbXBvcnQgeyBNYXRyaXg0IH0gZnJvbSAnLi4vbWF0aC9NYXRyaXg0LmpzJztcclxuaW1wb3J0IHsgTGluZUJhc2ljTWF0ZXJpYWwgfSBmcm9tICcuLi9tYXRlcmlhbHMvTGluZUJhc2ljTWF0ZXJpYWwuanMnO1xyXG5pbXBvcnQgeyBDb2xvciB9IGZyb20gJy4uL21hdGgvQ29sb3IuanMnO1xyXG5pbXBvcnQgeyBWZWN0b3IzIH0gZnJvbSAnLi4vbWF0aC9WZWN0b3IzLmpzJztcclxuaW1wb3J0IHsgQnVmZmVyR2VvbWV0cnkgfSBmcm9tICcuLi9jb3JlL0J1ZmZlckdlb21ldHJ5LmpzJztcclxuaW1wb3J0IHsgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSB9IGZyb20gJy4uL2NvcmUvQnVmZmVyQXR0cmlidXRlLmpzJztcclxuXHJcbmNvbnN0IF92ZWN0b3IgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XHJcbmNvbnN0IF9ib25lTWF0cml4ID0gLypAX19QVVJFX18qLyBuZXcgTWF0cml4NCgpO1xyXG5jb25zdCBfbWF0cml4V29ybGRJbnYgPSAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXg0KCk7XHJcblxyXG5cclxuY2xhc3MgU2tlbGV0b25IZWxwZXIgZXh0ZW5kcyBMaW5lU2VnbWVudHMge1xyXG5cclxuXHRjb25zdHJ1Y3Rvciggb2JqZWN0ICkge1xyXG5cclxuXHRcdGNvbnN0IGJvbmVzID0gZ2V0Qm9uZUxpc3QoIG9iamVjdCApO1xyXG5cclxuXHRcdGNvbnN0IGdlb21ldHJ5ID0gbmV3IEJ1ZmZlckdlb21ldHJ5KCk7XHJcblxyXG5cdFx0Y29uc3QgdmVydGljZXMgPSBbXTtcclxuXHRcdGNvbnN0IGNvbG9ycyA9IFtdO1xyXG5cclxuXHRcdGNvbnN0IGNvbG9yMSA9IG5ldyBDb2xvciggMCwgMCwgMSApO1xyXG5cdFx0Y29uc3QgY29sb3IyID0gbmV3IENvbG9yKCAwLCAxLCAwICk7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgYm9uZXMubGVuZ3RoOyBpICsrICkge1xyXG5cclxuXHRcdFx0Y29uc3QgYm9uZSA9IGJvbmVzWyBpIF07XHJcblxyXG5cdFx0XHRpZiAoIGJvbmUucGFyZW50ICYmIGJvbmUucGFyZW50LmlzQm9uZSApIHtcclxuXHJcblx0XHRcdFx0dmVydGljZXMucHVzaCggMCwgMCwgMCApO1xyXG5cdFx0XHRcdHZlcnRpY2VzLnB1c2goIDAsIDAsIDAgKTtcclxuXHRcdFx0XHRjb2xvcnMucHVzaCggY29sb3IxLnIsIGNvbG9yMS5nLCBjb2xvcjEuYiApO1xyXG5cdFx0XHRcdGNvbG9ycy5wdXNoKCBjb2xvcjIuciwgY29sb3IyLmcsIGNvbG9yMi5iICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGdlb21ldHJ5LnNldEF0dHJpYnV0ZSggJ3Bvc2l0aW9uJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIHZlcnRpY2VzLCAzICkgKTtcclxuXHRcdGdlb21ldHJ5LnNldEF0dHJpYnV0ZSggJ2NvbG9yJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIGNvbG9ycywgMyApICk7XHJcblxyXG5cdFx0Y29uc3QgbWF0ZXJpYWwgPSBuZXcgTGluZUJhc2ljTWF0ZXJpYWwoIHsgdmVydGV4Q29sb3JzOiB0cnVlLCBkZXB0aFRlc3Q6IGZhbHNlLCBkZXB0aFdyaXRlOiBmYWxzZSwgdG9uZU1hcHBlZDogZmFsc2UsIHRyYW5zcGFyZW50OiB0cnVlIH0gKTtcclxuXHJcblx0XHRzdXBlciggZ2VvbWV0cnksIG1hdGVyaWFsICk7XHJcblxyXG5cdFx0dGhpcy5pc1NrZWxldG9uSGVscGVyID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSAnU2tlbGV0b25IZWxwZXInO1xyXG5cclxuXHRcdHRoaXMucm9vdCA9IG9iamVjdDtcclxuXHRcdHRoaXMuYm9uZXMgPSBib25lcztcclxuXHJcblx0XHR0aGlzLm1hdHJpeCA9IG9iamVjdC5tYXRyaXhXb3JsZDtcclxuXHRcdHRoaXMubWF0cml4QXV0b1VwZGF0ZSA9IGZhbHNlO1xyXG5cclxuXHR9XHJcblxyXG5cdHVwZGF0ZU1hdHJpeFdvcmxkKCBmb3JjZSApIHtcclxuXHJcblx0XHRjb25zdCBib25lcyA9IHRoaXMuYm9uZXM7XHJcblxyXG5cdFx0Y29uc3QgZ2VvbWV0cnkgPSB0aGlzLmdlb21ldHJ5O1xyXG5cdFx0Y29uc3QgcG9zaXRpb24gPSBnZW9tZXRyeS5nZXRBdHRyaWJ1dGUoICdwb3NpdGlvbicgKTtcclxuXHJcblx0XHRfbWF0cml4V29ybGRJbnYuY29weSggdGhpcy5yb290Lm1hdHJpeFdvcmxkICkuaW52ZXJ0KCk7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBqID0gMDsgaSA8IGJvbmVzLmxlbmd0aDsgaSArKyApIHtcclxuXHJcblx0XHRcdGNvbnN0IGJvbmUgPSBib25lc1sgaSBdO1xyXG5cclxuXHRcdFx0aWYgKCBib25lLnBhcmVudCAmJiBib25lLnBhcmVudC5pc0JvbmUgKSB7XHJcblxyXG5cdFx0XHRcdF9ib25lTWF0cml4Lm11bHRpcGx5TWF0cmljZXMoIF9tYXRyaXhXb3JsZEludiwgYm9uZS5tYXRyaXhXb3JsZCApO1xyXG5cdFx0XHRcdF92ZWN0b3Iuc2V0RnJvbU1hdHJpeFBvc2l0aW9uKCBfYm9uZU1hdHJpeCApO1xyXG5cdFx0XHRcdHBvc2l0aW9uLnNldFhZWiggaiwgX3ZlY3Rvci54LCBfdmVjdG9yLnksIF92ZWN0b3IueiApO1xyXG5cclxuXHRcdFx0XHRfYm9uZU1hdHJpeC5tdWx0aXBseU1hdHJpY2VzKCBfbWF0cml4V29ybGRJbnYsIGJvbmUucGFyZW50Lm1hdHJpeFdvcmxkICk7XHJcblx0XHRcdFx0X3ZlY3Rvci5zZXRGcm9tTWF0cml4UG9zaXRpb24oIF9ib25lTWF0cml4ICk7XHJcblx0XHRcdFx0cG9zaXRpb24uc2V0WFlaKCBqICsgMSwgX3ZlY3Rvci54LCBfdmVjdG9yLnksIF92ZWN0b3IueiApO1xyXG5cclxuXHRcdFx0XHRqICs9IDI7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGdlb21ldHJ5LmdldEF0dHJpYnV0ZSggJ3Bvc2l0aW9uJyApLm5lZWRzVXBkYXRlID0gdHJ1ZTtcclxuXHJcblx0XHRzdXBlci51cGRhdGVNYXRyaXhXb3JsZCggZm9yY2UgKTtcclxuXHJcblx0fVxyXG5cclxuXHRkaXNwb3NlKCkge1xyXG5cclxuXHRcdHRoaXMuZ2VvbWV0cnkuZGlzcG9zZSgpO1xyXG5cdFx0dGhpcy5tYXRlcmlhbC5kaXNwb3NlKCk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcblxyXG5mdW5jdGlvbiBnZXRCb25lTGlzdCggb2JqZWN0ICkge1xyXG5cclxuXHRjb25zdCBib25lTGlzdCA9IFtdO1xyXG5cclxuXHRpZiAoIG9iamVjdC5pc0JvbmUgPT09IHRydWUgKSB7XHJcblxyXG5cdFx0Ym9uZUxpc3QucHVzaCggb2JqZWN0ICk7XHJcblxyXG5cdH1cclxuXHJcblx0Zm9yICggbGV0IGkgPSAwOyBpIDwgb2JqZWN0LmNoaWxkcmVuLmxlbmd0aDsgaSArKyApIHtcclxuXHJcblx0XHRib25lTGlzdC5wdXNoLmFwcGx5KCBib25lTGlzdCwgZ2V0Qm9uZUxpc3QoIG9iamVjdC5jaGlsZHJlblsgaSBdICkgKTtcclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4gYm9uZUxpc3Q7XHJcblxyXG59XHJcblxyXG5cclxuZXhwb3J0IHsgU2tlbGV0b25IZWxwZXIgfTtcclxuIiwiaW1wb3J0IHsgTWVzaCB9IGZyb20gJy4uL29iamVjdHMvTWVzaC5qcyc7XHJcbmltcG9ydCB7IE1lc2hCYXNpY01hdGVyaWFsIH0gZnJvbSAnLi4vbWF0ZXJpYWxzL01lc2hCYXNpY01hdGVyaWFsLmpzJztcclxuaW1wb3J0IHsgU3BoZXJlR2VvbWV0cnkgfSBmcm9tICcuLi9nZW9tZXRyaWVzL1NwaGVyZUdlb21ldHJ5LmpzJztcclxuXHJcbmNsYXNzIFBvaW50TGlnaHRIZWxwZXIgZXh0ZW5kcyBNZXNoIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIGxpZ2h0LCBzcGhlcmVTaXplLCBjb2xvciApIHtcclxuXHJcblx0XHRjb25zdCBnZW9tZXRyeSA9IG5ldyBTcGhlcmVHZW9tZXRyeSggc3BoZXJlU2l6ZSwgNCwgMiApO1xyXG5cdFx0Y29uc3QgbWF0ZXJpYWwgPSBuZXcgTWVzaEJhc2ljTWF0ZXJpYWwoIHsgd2lyZWZyYW1lOiB0cnVlLCBmb2c6IGZhbHNlLCB0b25lTWFwcGVkOiBmYWxzZSB9ICk7XHJcblxyXG5cdFx0c3VwZXIoIGdlb21ldHJ5LCBtYXRlcmlhbCApO1xyXG5cclxuXHRcdHRoaXMubGlnaHQgPSBsaWdodDtcclxuXHJcblx0XHR0aGlzLmNvbG9yID0gY29sb3I7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ1BvaW50TGlnaHRIZWxwZXInO1xyXG5cclxuXHRcdHRoaXMubWF0cml4ID0gdGhpcy5saWdodC5tYXRyaXhXb3JsZDtcclxuXHRcdHRoaXMubWF0cml4QXV0b1VwZGF0ZSA9IGZhbHNlO1xyXG5cclxuXHRcdHRoaXMudXBkYXRlKCk7XHJcblxyXG5cclxuXHRcdC8qXHJcblx0Ly8gVE9ETzogZGVsZXRlIHRoaXMgY29tbWVudD9cclxuXHRjb25zdCBkaXN0YW5jZUdlb21ldHJ5ID0gbmV3IFRIUkVFLkljb3NhaGVkcm9uR2VvbWV0cnkoIDEsIDIgKTtcclxuXHRjb25zdCBkaXN0YW5jZU1hdGVyaWFsID0gbmV3IFRIUkVFLk1lc2hCYXNpY01hdGVyaWFsKCB7IGNvbG9yOiBoZXhDb2xvciwgZm9nOiBmYWxzZSwgd2lyZWZyYW1lOiB0cnVlLCBvcGFjaXR5OiAwLjEsIHRyYW5zcGFyZW50OiB0cnVlIH0gKTtcclxuXHJcblx0dGhpcy5saWdodFNwaGVyZSA9IG5ldyBUSFJFRS5NZXNoKCBidWxiR2VvbWV0cnksIGJ1bGJNYXRlcmlhbCApO1xyXG5cdHRoaXMubGlnaHREaXN0YW5jZSA9IG5ldyBUSFJFRS5NZXNoKCBkaXN0YW5jZUdlb21ldHJ5LCBkaXN0YW5jZU1hdGVyaWFsICk7XHJcblxyXG5cdGNvbnN0IGQgPSBsaWdodC5kaXN0YW5jZTtcclxuXHJcblx0aWYgKCBkID09PSAwLjAgKSB7XHJcblxyXG5cdFx0dGhpcy5saWdodERpc3RhbmNlLnZpc2libGUgPSBmYWxzZTtcclxuXHJcblx0fSBlbHNlIHtcclxuXHJcblx0XHR0aGlzLmxpZ2h0RGlzdGFuY2Uuc2NhbGUuc2V0KCBkLCBkLCBkICk7XHJcblxyXG5cdH1cclxuXHJcblx0dGhpcy5hZGQoIHRoaXMubGlnaHREaXN0YW5jZSApO1xyXG5cdCovXHJcblxyXG5cdH1cclxuXHJcblx0ZGlzcG9zZSgpIHtcclxuXHJcblx0XHR0aGlzLmdlb21ldHJ5LmRpc3Bvc2UoKTtcclxuXHRcdHRoaXMubWF0ZXJpYWwuZGlzcG9zZSgpO1xyXG5cclxuXHR9XHJcblxyXG5cdHVwZGF0ZSgpIHtcclxuXHJcblx0XHR0aGlzLmxpZ2h0LnVwZGF0ZVdvcmxkTWF0cml4KCB0cnVlLCBmYWxzZSApO1xyXG5cclxuXHRcdGlmICggdGhpcy5jb2xvciAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0dGhpcy5tYXRlcmlhbC5jb2xvci5zZXQoIHRoaXMuY29sb3IgKTtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0dGhpcy5tYXRlcmlhbC5jb2xvci5jb3B5KCB0aGlzLmxpZ2h0LmNvbG9yICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8qXHJcblx0XHRjb25zdCBkID0gdGhpcy5saWdodC5kaXN0YW5jZTtcclxuXHJcblx0XHRpZiAoIGQgPT09IDAuMCApIHtcclxuXHJcblx0XHRcdHRoaXMubGlnaHREaXN0YW5jZS52aXNpYmxlID0gZmFsc2U7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdHRoaXMubGlnaHREaXN0YW5jZS52aXNpYmxlID0gdHJ1ZTtcclxuXHRcdFx0dGhpcy5saWdodERpc3RhbmNlLnNjYWxlLnNldCggZCwgZCwgZCApO1xyXG5cclxuXHRcdH1cclxuXHRcdCovXHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcblxyXG5leHBvcnQgeyBQb2ludExpZ2h0SGVscGVyIH07XHJcbiIsImltcG9ydCB7IFZlY3RvcjMgfSBmcm9tICcuLi9tYXRoL1ZlY3RvcjMuanMnO1xyXG5pbXBvcnQgeyBDb2xvciB9IGZyb20gJy4uL21hdGgvQ29sb3IuanMnO1xyXG5pbXBvcnQgeyBPYmplY3QzRCB9IGZyb20gJy4uL2NvcmUvT2JqZWN0M0QuanMnO1xyXG5pbXBvcnQgeyBNZXNoIH0gZnJvbSAnLi4vb2JqZWN0cy9NZXNoLmpzJztcclxuaW1wb3J0IHsgTWVzaEJhc2ljTWF0ZXJpYWwgfSBmcm9tICcuLi9tYXRlcmlhbHMvTWVzaEJhc2ljTWF0ZXJpYWwuanMnO1xyXG5pbXBvcnQgeyBPY3RhaGVkcm9uR2VvbWV0cnkgfSBmcm9tICcuLi9nZW9tZXRyaWVzL09jdGFoZWRyb25HZW9tZXRyeS5qcyc7XHJcbmltcG9ydCB7IEJ1ZmZlckF0dHJpYnV0ZSB9IGZyb20gJy4uL2NvcmUvQnVmZmVyQXR0cmlidXRlLmpzJztcclxuXHJcbmNvbnN0IF92ZWN0b3IgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XHJcbmNvbnN0IF9jb2xvcjEgPSAvKkBfX1BVUkVfXyovIG5ldyBDb2xvcigpO1xyXG5jb25zdCBfY29sb3IyID0gLypAX19QVVJFX18qLyBuZXcgQ29sb3IoKTtcclxuXHJcbmNsYXNzIEhlbWlzcGhlcmVMaWdodEhlbHBlciBleHRlbmRzIE9iamVjdDNEIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIGxpZ2h0LCBzaXplLCBjb2xvciApIHtcclxuXHJcblx0XHRzdXBlcigpO1xyXG5cclxuXHRcdHRoaXMubGlnaHQgPSBsaWdodDtcclxuXHJcblx0XHR0aGlzLm1hdHJpeCA9IGxpZ2h0Lm1hdHJpeFdvcmxkO1xyXG5cdFx0dGhpcy5tYXRyaXhBdXRvVXBkYXRlID0gZmFsc2U7XHJcblxyXG5cdFx0dGhpcy5jb2xvciA9IGNvbG9yO1xyXG5cclxuXHRcdHRoaXMudHlwZSA9ICdIZW1pc3BoZXJlTGlnaHRIZWxwZXInO1xyXG5cclxuXHRcdGNvbnN0IGdlb21ldHJ5ID0gbmV3IE9jdGFoZWRyb25HZW9tZXRyeSggc2l6ZSApO1xyXG5cdFx0Z2VvbWV0cnkucm90YXRlWSggTWF0aC5QSSAqIDAuNSApO1xyXG5cclxuXHRcdHRoaXMubWF0ZXJpYWwgPSBuZXcgTWVzaEJhc2ljTWF0ZXJpYWwoIHsgd2lyZWZyYW1lOiB0cnVlLCBmb2c6IGZhbHNlLCB0b25lTWFwcGVkOiBmYWxzZSB9ICk7XHJcblx0XHRpZiAoIHRoaXMuY29sb3IgPT09IHVuZGVmaW5lZCApIHRoaXMubWF0ZXJpYWwudmVydGV4Q29sb3JzID0gdHJ1ZTtcclxuXHJcblx0XHRjb25zdCBwb3NpdGlvbiA9IGdlb21ldHJ5LmdldEF0dHJpYnV0ZSggJ3Bvc2l0aW9uJyApO1xyXG5cdFx0Y29uc3QgY29sb3JzID0gbmV3IEZsb2F0MzJBcnJheSggcG9zaXRpb24uY291bnQgKiAzICk7XHJcblxyXG5cdFx0Z2VvbWV0cnkuc2V0QXR0cmlidXRlKCAnY29sb3InLCBuZXcgQnVmZmVyQXR0cmlidXRlKCBjb2xvcnMsIDMgKSApO1xyXG5cclxuXHRcdHRoaXMuYWRkKCBuZXcgTWVzaCggZ2VvbWV0cnksIHRoaXMubWF0ZXJpYWwgKSApO1xyXG5cclxuXHRcdHRoaXMudXBkYXRlKCk7XHJcblxyXG5cdH1cclxuXHJcblx0ZGlzcG9zZSgpIHtcclxuXHJcblx0XHR0aGlzLmNoaWxkcmVuWyAwIF0uZ2VvbWV0cnkuZGlzcG9zZSgpO1xyXG5cdFx0dGhpcy5jaGlsZHJlblsgMCBdLm1hdGVyaWFsLmRpc3Bvc2UoKTtcclxuXHJcblx0fVxyXG5cclxuXHR1cGRhdGUoKSB7XHJcblxyXG5cdFx0Y29uc3QgbWVzaCA9IHRoaXMuY2hpbGRyZW5bIDAgXTtcclxuXHJcblx0XHRpZiAoIHRoaXMuY29sb3IgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdHRoaXMubWF0ZXJpYWwuY29sb3Iuc2V0KCB0aGlzLmNvbG9yICk7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdGNvbnN0IGNvbG9ycyA9IG1lc2guZ2VvbWV0cnkuZ2V0QXR0cmlidXRlKCAnY29sb3InICk7XHJcblxyXG5cdFx0XHRfY29sb3IxLmNvcHkoIHRoaXMubGlnaHQuY29sb3IgKTtcclxuXHRcdFx0X2NvbG9yMi5jb3B5KCB0aGlzLmxpZ2h0Lmdyb3VuZENvbG9yICk7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBjb2xvcnMuY291bnQ7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBjb2xvciA9ICggaSA8ICggbCAvIDIgKSApID8gX2NvbG9yMSA6IF9jb2xvcjI7XHJcblxyXG5cdFx0XHRcdGNvbG9ycy5zZXRYWVooIGksIGNvbG9yLnIsIGNvbG9yLmcsIGNvbG9yLmIgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGNvbG9ycy5uZWVkc1VwZGF0ZSA9IHRydWU7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMubGlnaHQudXBkYXRlV29ybGRNYXRyaXgoIHRydWUsIGZhbHNlICk7XHJcblxyXG5cdFx0bWVzaC5sb29rQXQoIF92ZWN0b3Iuc2V0RnJvbU1hdHJpeFBvc2l0aW9uKCB0aGlzLmxpZ2h0Lm1hdHJpeFdvcmxkICkubmVnYXRlKCkgKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuXHJcbmV4cG9ydCB7IEhlbWlzcGhlcmVMaWdodEhlbHBlciB9O1xyXG4iLCJpbXBvcnQgeyBMaW5lU2VnbWVudHMgfSBmcm9tICcuLi9vYmplY3RzL0xpbmVTZWdtZW50cy5qcyc7XHJcbmltcG9ydCB7IExpbmVCYXNpY01hdGVyaWFsIH0gZnJvbSAnLi4vbWF0ZXJpYWxzL0xpbmVCYXNpY01hdGVyaWFsLmpzJztcclxuaW1wb3J0IHsgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSB9IGZyb20gJy4uL2NvcmUvQnVmZmVyQXR0cmlidXRlLmpzJztcclxuaW1wb3J0IHsgQnVmZmVyR2VvbWV0cnkgfSBmcm9tICcuLi9jb3JlL0J1ZmZlckdlb21ldHJ5LmpzJztcclxuaW1wb3J0IHsgQ29sb3IgfSBmcm9tICcuLi9tYXRoL0NvbG9yLmpzJztcclxuXHJcbmNsYXNzIEdyaWRIZWxwZXIgZXh0ZW5kcyBMaW5lU2VnbWVudHMge1xyXG5cclxuXHRjb25zdHJ1Y3Rvciggc2l6ZSA9IDEwLCBkaXZpc2lvbnMgPSAxMCwgY29sb3IxID0gMHg0NDQ0NDQsIGNvbG9yMiA9IDB4ODg4ODg4ICkge1xyXG5cclxuXHRcdGNvbG9yMSA9IG5ldyBDb2xvciggY29sb3IxICk7XHJcblx0XHRjb2xvcjIgPSBuZXcgQ29sb3IoIGNvbG9yMiApO1xyXG5cclxuXHRcdGNvbnN0IGNlbnRlciA9IGRpdmlzaW9ucyAvIDI7XHJcblx0XHRjb25zdCBzdGVwID0gc2l6ZSAvIGRpdmlzaW9ucztcclxuXHRcdGNvbnN0IGhhbGZTaXplID0gc2l6ZSAvIDI7XHJcblxyXG5cdFx0Y29uc3QgdmVydGljZXMgPSBbXSwgY29sb3JzID0gW107XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBqID0gMCwgayA9IC0gaGFsZlNpemU7IGkgPD0gZGl2aXNpb25zOyBpICsrLCBrICs9IHN0ZXAgKSB7XHJcblxyXG5cdFx0XHR2ZXJ0aWNlcy5wdXNoKCAtIGhhbGZTaXplLCAwLCBrLCBoYWxmU2l6ZSwgMCwgayApO1xyXG5cdFx0XHR2ZXJ0aWNlcy5wdXNoKCBrLCAwLCAtIGhhbGZTaXplLCBrLCAwLCBoYWxmU2l6ZSApO1xyXG5cclxuXHRcdFx0Y29uc3QgY29sb3IgPSBpID09PSBjZW50ZXIgPyBjb2xvcjEgOiBjb2xvcjI7XHJcblxyXG5cdFx0XHRjb2xvci50b0FycmF5KCBjb2xvcnMsIGogKTsgaiArPSAzO1xyXG5cdFx0XHRjb2xvci50b0FycmF5KCBjb2xvcnMsIGogKTsgaiArPSAzO1xyXG5cdFx0XHRjb2xvci50b0FycmF5KCBjb2xvcnMsIGogKTsgaiArPSAzO1xyXG5cdFx0XHRjb2xvci50b0FycmF5KCBjb2xvcnMsIGogKTsgaiArPSAzO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCBnZW9tZXRyeSA9IG5ldyBCdWZmZXJHZW9tZXRyeSgpO1xyXG5cdFx0Z2VvbWV0cnkuc2V0QXR0cmlidXRlKCAncG9zaXRpb24nLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggdmVydGljZXMsIDMgKSApO1xyXG5cdFx0Z2VvbWV0cnkuc2V0QXR0cmlidXRlKCAnY29sb3InLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggY29sb3JzLCAzICkgKTtcclxuXHJcblx0XHRjb25zdCBtYXRlcmlhbCA9IG5ldyBMaW5lQmFzaWNNYXRlcmlhbCggeyB2ZXJ0ZXhDb2xvcnM6IHRydWUsIHRvbmVNYXBwZWQ6IGZhbHNlIH0gKTtcclxuXHJcblx0XHRzdXBlciggZ2VvbWV0cnksIG1hdGVyaWFsICk7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ0dyaWRIZWxwZXInO1xyXG5cclxuXHR9XHJcblxyXG5cdGRpc3Bvc2UoKSB7XHJcblxyXG5cdFx0dGhpcy5nZW9tZXRyeS5kaXNwb3NlKCk7XHJcblx0XHR0aGlzLm1hdGVyaWFsLmRpc3Bvc2UoKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuXHJcbmV4cG9ydCB7IEdyaWRIZWxwZXIgfTtcclxuIiwiaW1wb3J0IHsgTGluZVNlZ21lbnRzIH0gZnJvbSAnLi4vb2JqZWN0cy9MaW5lU2VnbWVudHMuanMnO1xyXG5pbXBvcnQgeyBMaW5lQmFzaWNNYXRlcmlhbCB9IGZyb20gJy4uL21hdGVyaWFscy9MaW5lQmFzaWNNYXRlcmlhbC5qcyc7XHJcbmltcG9ydCB7IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUgfSBmcm9tICcuLi9jb3JlL0J1ZmZlckF0dHJpYnV0ZS5qcyc7XHJcbmltcG9ydCB7IEJ1ZmZlckdlb21ldHJ5IH0gZnJvbSAnLi4vY29yZS9CdWZmZXJHZW9tZXRyeS5qcyc7XHJcbmltcG9ydCB7IENvbG9yIH0gZnJvbSAnLi4vbWF0aC9Db2xvci5qcyc7XHJcblxyXG5jbGFzcyBQb2xhckdyaWRIZWxwZXIgZXh0ZW5kcyBMaW5lU2VnbWVudHMge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggcmFkaXVzID0gMTAsIHNlY3RvcnMgPSAxNiwgcmluZ3MgPSA4LCBkaXZpc2lvbnMgPSA2NCwgY29sb3IxID0gMHg0NDQ0NDQsIGNvbG9yMiA9IDB4ODg4ODg4ICkge1xyXG5cclxuXHRcdGNvbG9yMSA9IG5ldyBDb2xvciggY29sb3IxICk7XHJcblx0XHRjb2xvcjIgPSBuZXcgQ29sb3IoIGNvbG9yMiApO1xyXG5cclxuXHRcdGNvbnN0IHZlcnRpY2VzID0gW107XHJcblx0XHRjb25zdCBjb2xvcnMgPSBbXTtcclxuXHJcblx0XHQvLyBjcmVhdGUgdGhlIHNlY3RvcnNcclxuXHJcblx0XHRpZiAoIHNlY3RvcnMgPiAxICkge1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgc2VjdG9yczsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgdiA9ICggaSAvIHNlY3RvcnMgKSAqICggTWF0aC5QSSAqIDIgKTtcclxuXHJcblx0XHRcdFx0Y29uc3QgeCA9IE1hdGguc2luKCB2ICkgKiByYWRpdXM7XHJcblx0XHRcdFx0Y29uc3QgeiA9IE1hdGguY29zKCB2ICkgKiByYWRpdXM7XHJcblxyXG5cdFx0XHRcdHZlcnRpY2VzLnB1c2goIDAsIDAsIDAgKTtcclxuXHRcdFx0XHR2ZXJ0aWNlcy5wdXNoKCB4LCAwLCB6ICk7XHJcblxyXG5cdFx0XHRcdGNvbnN0IGNvbG9yID0gKCBpICYgMSApID8gY29sb3IxIDogY29sb3IyO1xyXG5cclxuXHRcdFx0XHRjb2xvcnMucHVzaCggY29sb3IuciwgY29sb3IuZywgY29sb3IuYiApO1xyXG5cdFx0XHRcdGNvbG9ycy5wdXNoKCBjb2xvci5yLCBjb2xvci5nLCBjb2xvci5iICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIGNyZWF0ZSB0aGUgcmluZ3NcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCByaW5nczsgaSArKyApIHtcclxuXHJcblx0XHRcdGNvbnN0IGNvbG9yID0gKCBpICYgMSApID8gY29sb3IxIDogY29sb3IyO1xyXG5cclxuXHRcdFx0Y29uc3QgciA9IHJhZGl1cyAtICggcmFkaXVzIC8gcmluZ3MgKiBpICk7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaiA9IDA7IGogPCBkaXZpc2lvbnM7IGogKysgKSB7XHJcblxyXG5cdFx0XHRcdC8vIGZpcnN0IHZlcnRleFxyXG5cclxuXHRcdFx0XHRsZXQgdiA9ICggaiAvIGRpdmlzaW9ucyApICogKCBNYXRoLlBJICogMiApO1xyXG5cclxuXHRcdFx0XHRsZXQgeCA9IE1hdGguc2luKCB2ICkgKiByO1xyXG5cdFx0XHRcdGxldCB6ID0gTWF0aC5jb3MoIHYgKSAqIHI7XHJcblxyXG5cdFx0XHRcdHZlcnRpY2VzLnB1c2goIHgsIDAsIHogKTtcclxuXHRcdFx0XHRjb2xvcnMucHVzaCggY29sb3IuciwgY29sb3IuZywgY29sb3IuYiApO1xyXG5cclxuXHRcdFx0XHQvLyBzZWNvbmQgdmVydGV4XHJcblxyXG5cdFx0XHRcdHYgPSAoICggaiArIDEgKSAvIGRpdmlzaW9ucyApICogKCBNYXRoLlBJICogMiApO1xyXG5cclxuXHRcdFx0XHR4ID0gTWF0aC5zaW4oIHYgKSAqIHI7XHJcblx0XHRcdFx0eiA9IE1hdGguY29zKCB2ICkgKiByO1xyXG5cclxuXHRcdFx0XHR2ZXJ0aWNlcy5wdXNoKCB4LCAwLCB6ICk7XHJcblx0XHRcdFx0Y29sb3JzLnB1c2goIGNvbG9yLnIsIGNvbG9yLmcsIGNvbG9yLmIgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Y29uc3QgZ2VvbWV0cnkgPSBuZXcgQnVmZmVyR2VvbWV0cnkoKTtcclxuXHRcdGdlb21ldHJ5LnNldEF0dHJpYnV0ZSggJ3Bvc2l0aW9uJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIHZlcnRpY2VzLCAzICkgKTtcclxuXHRcdGdlb21ldHJ5LnNldEF0dHJpYnV0ZSggJ2NvbG9yJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIGNvbG9ycywgMyApICk7XHJcblxyXG5cdFx0Y29uc3QgbWF0ZXJpYWwgPSBuZXcgTGluZUJhc2ljTWF0ZXJpYWwoIHsgdmVydGV4Q29sb3JzOiB0cnVlLCB0b25lTWFwcGVkOiBmYWxzZSB9ICk7XHJcblxyXG5cdFx0c3VwZXIoIGdlb21ldHJ5LCBtYXRlcmlhbCApO1xyXG5cclxuXHRcdHRoaXMudHlwZSA9ICdQb2xhckdyaWRIZWxwZXInO1xyXG5cclxuXHR9XHJcblxyXG5cdGRpc3Bvc2UoKSB7XHJcblxyXG5cdFx0dGhpcy5nZW9tZXRyeS5kaXNwb3NlKCk7XHJcblx0XHR0aGlzLm1hdGVyaWFsLmRpc3Bvc2UoKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuXHJcbmV4cG9ydCB7IFBvbGFyR3JpZEhlbHBlciB9O1xyXG4iLCJpbXBvcnQgeyBWZWN0b3IzIH0gZnJvbSAnLi4vbWF0aC9WZWN0b3IzLmpzJztcclxuaW1wb3J0IHsgT2JqZWN0M0QgfSBmcm9tICcuLi9jb3JlL09iamVjdDNELmpzJztcclxuaW1wb3J0IHsgTGluZSB9IGZyb20gJy4uL29iamVjdHMvTGluZS5qcyc7XHJcbmltcG9ydCB7IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUgfSBmcm9tICcuLi9jb3JlL0J1ZmZlckF0dHJpYnV0ZS5qcyc7XHJcbmltcG9ydCB7IEJ1ZmZlckdlb21ldHJ5IH0gZnJvbSAnLi4vY29yZS9CdWZmZXJHZW9tZXRyeS5qcyc7XHJcbmltcG9ydCB7IExpbmVCYXNpY01hdGVyaWFsIH0gZnJvbSAnLi4vbWF0ZXJpYWxzL0xpbmVCYXNpY01hdGVyaWFsLmpzJztcclxuXHJcbmNvbnN0IF92MSA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuY29uc3QgX3YyID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5jb25zdCBfdjMgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XHJcblxyXG5jbGFzcyBEaXJlY3Rpb25hbExpZ2h0SGVscGVyIGV4dGVuZHMgT2JqZWN0M0Qge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggbGlnaHQsIHNpemUsIGNvbG9yICkge1xyXG5cclxuXHRcdHN1cGVyKCk7XHJcblxyXG5cdFx0dGhpcy5saWdodCA9IGxpZ2h0O1xyXG5cclxuXHRcdHRoaXMubWF0cml4ID0gbGlnaHQubWF0cml4V29ybGQ7XHJcblx0XHR0aGlzLm1hdHJpeEF1dG9VcGRhdGUgPSBmYWxzZTtcclxuXHJcblx0XHR0aGlzLmNvbG9yID0gY29sb3I7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ0RpcmVjdGlvbmFsTGlnaHRIZWxwZXInO1xyXG5cclxuXHRcdGlmICggc2l6ZSA9PT0gdW5kZWZpbmVkICkgc2l6ZSA9IDE7XHJcblxyXG5cdFx0bGV0IGdlb21ldHJ5ID0gbmV3IEJ1ZmZlckdlb21ldHJ5KCk7XHJcblx0XHRnZW9tZXRyeS5zZXRBdHRyaWJ1dGUoICdwb3NpdGlvbicsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCBbXHJcblx0XHRcdC0gc2l6ZSwgc2l6ZSwgMCxcclxuXHRcdFx0c2l6ZSwgc2l6ZSwgMCxcclxuXHRcdFx0c2l6ZSwgLSBzaXplLCAwLFxyXG5cdFx0XHQtIHNpemUsIC0gc2l6ZSwgMCxcclxuXHRcdFx0LSBzaXplLCBzaXplLCAwXHJcblx0XHRdLCAzICkgKTtcclxuXHJcblx0XHRjb25zdCBtYXRlcmlhbCA9IG5ldyBMaW5lQmFzaWNNYXRlcmlhbCggeyBmb2c6IGZhbHNlLCB0b25lTWFwcGVkOiBmYWxzZSB9ICk7XHJcblxyXG5cdFx0dGhpcy5saWdodFBsYW5lID0gbmV3IExpbmUoIGdlb21ldHJ5LCBtYXRlcmlhbCApO1xyXG5cdFx0dGhpcy5hZGQoIHRoaXMubGlnaHRQbGFuZSApO1xyXG5cclxuXHRcdGdlb21ldHJ5ID0gbmV3IEJ1ZmZlckdlb21ldHJ5KCk7XHJcblx0XHRnZW9tZXRyeS5zZXRBdHRyaWJ1dGUoICdwb3NpdGlvbicsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCBbIDAsIDAsIDAsIDAsIDAsIDEgXSwgMyApICk7XHJcblxyXG5cdFx0dGhpcy50YXJnZXRMaW5lID0gbmV3IExpbmUoIGdlb21ldHJ5LCBtYXRlcmlhbCApO1xyXG5cdFx0dGhpcy5hZGQoIHRoaXMudGFyZ2V0TGluZSApO1xyXG5cclxuXHRcdHRoaXMudXBkYXRlKCk7XHJcblxyXG5cdH1cclxuXHJcblx0ZGlzcG9zZSgpIHtcclxuXHJcblx0XHR0aGlzLmxpZ2h0UGxhbmUuZ2VvbWV0cnkuZGlzcG9zZSgpO1xyXG5cdFx0dGhpcy5saWdodFBsYW5lLm1hdGVyaWFsLmRpc3Bvc2UoKTtcclxuXHRcdHRoaXMudGFyZ2V0TGluZS5nZW9tZXRyeS5kaXNwb3NlKCk7XHJcblx0XHR0aGlzLnRhcmdldExpbmUubWF0ZXJpYWwuZGlzcG9zZSgpO1xyXG5cclxuXHR9XHJcblxyXG5cdHVwZGF0ZSgpIHtcclxuXHJcblx0XHR0aGlzLmxpZ2h0LnVwZGF0ZVdvcmxkTWF0cml4KCB0cnVlLCBmYWxzZSApO1xyXG5cdFx0dGhpcy5saWdodC50YXJnZXQudXBkYXRlV29ybGRNYXRyaXgoIHRydWUsIGZhbHNlICk7XHJcblxyXG5cdFx0X3YxLnNldEZyb21NYXRyaXhQb3NpdGlvbiggdGhpcy5saWdodC5tYXRyaXhXb3JsZCApO1xyXG5cdFx0X3YyLnNldEZyb21NYXRyaXhQb3NpdGlvbiggdGhpcy5saWdodC50YXJnZXQubWF0cml4V29ybGQgKTtcclxuXHRcdF92My5zdWJWZWN0b3JzKCBfdjIsIF92MSApO1xyXG5cclxuXHRcdHRoaXMubGlnaHRQbGFuZS5sb29rQXQoIF92MiApO1xyXG5cclxuXHRcdGlmICggdGhpcy5jb2xvciAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0dGhpcy5saWdodFBsYW5lLm1hdGVyaWFsLmNvbG9yLnNldCggdGhpcy5jb2xvciApO1xyXG5cdFx0XHR0aGlzLnRhcmdldExpbmUubWF0ZXJpYWwuY29sb3Iuc2V0KCB0aGlzLmNvbG9yICk7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdHRoaXMubGlnaHRQbGFuZS5tYXRlcmlhbC5jb2xvci5jb3B5KCB0aGlzLmxpZ2h0LmNvbG9yICk7XHJcblx0XHRcdHRoaXMudGFyZ2V0TGluZS5tYXRlcmlhbC5jb2xvci5jb3B5KCB0aGlzLmxpZ2h0LmNvbG9yICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMudGFyZ2V0TGluZS5sb29rQXQoIF92MiApO1xyXG5cdFx0dGhpcy50YXJnZXRMaW5lLnNjYWxlLnogPSBfdjMubGVuZ3RoKCk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcblxyXG5leHBvcnQgeyBEaXJlY3Rpb25hbExpZ2h0SGVscGVyIH07XHJcbiIsImltcG9ydCB7IENhbWVyYSB9IGZyb20gJy4uL2NhbWVyYXMvQ2FtZXJhLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yMyB9IGZyb20gJy4uL21hdGgvVmVjdG9yMy5qcyc7XHJcbmltcG9ydCB7IExpbmVTZWdtZW50cyB9IGZyb20gJy4uL29iamVjdHMvTGluZVNlZ21lbnRzLmpzJztcclxuaW1wb3J0IHsgQ29sb3IgfSBmcm9tICcuLi9tYXRoL0NvbG9yLmpzJztcclxuaW1wb3J0IHsgTGluZUJhc2ljTWF0ZXJpYWwgfSBmcm9tICcuLi9tYXRlcmlhbHMvTGluZUJhc2ljTWF0ZXJpYWwuanMnO1xyXG5pbXBvcnQgeyBCdWZmZXJHZW9tZXRyeSB9IGZyb20gJy4uL2NvcmUvQnVmZmVyR2VvbWV0cnkuanMnO1xyXG5pbXBvcnQgeyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlIH0gZnJvbSAnLi4vY29yZS9CdWZmZXJBdHRyaWJ1dGUuanMnO1xyXG5cclxuY29uc3QgX3ZlY3RvciA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuY29uc3QgX2NhbWVyYSA9IC8qQF9fUFVSRV9fKi8gbmV3IENhbWVyYSgpO1xyXG5cclxuLyoqXHJcbiAqXHQtIHNob3dzIGZydXN0dW0sIGxpbmUgb2Ygc2lnaHQgYW5kIHVwIG9mIHRoZSBjYW1lcmFcclxuICpcdC0gc3VpdGFibGUgZm9yIGZhc3QgdXBkYXRlc1xyXG4gKiBcdC0gYmFzZWQgb24gZnJ1c3R1bSB2aXN1YWxpemF0aW9uIGluIGxpZ2h0Z2wuanMgc2hhZG93bWFwIGV4YW1wbGVcclxuICpcdFx0aHR0cHM6Ly9naXRodWIuY29tL2V2YW53L2xpZ2h0Z2wuanMvYmxvYi9tYXN0ZXIvdGVzdHMvc2hhZG93bWFwLmh0bWxcclxuICovXHJcblxyXG5jbGFzcyBDYW1lcmFIZWxwZXIgZXh0ZW5kcyBMaW5lU2VnbWVudHMge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggY2FtZXJhICkge1xyXG5cclxuXHRcdGNvbnN0IGdlb21ldHJ5ID0gbmV3IEJ1ZmZlckdlb21ldHJ5KCk7XHJcblx0XHRjb25zdCBtYXRlcmlhbCA9IG5ldyBMaW5lQmFzaWNNYXRlcmlhbCggeyBjb2xvcjogMHhmZmZmZmYsIHZlcnRleENvbG9yczogdHJ1ZSwgdG9uZU1hcHBlZDogZmFsc2UgfSApO1xyXG5cclxuXHRcdGNvbnN0IHZlcnRpY2VzID0gW107XHJcblx0XHRjb25zdCBjb2xvcnMgPSBbXTtcclxuXHJcblx0XHRjb25zdCBwb2ludE1hcCA9IHt9O1xyXG5cclxuXHRcdC8vIG5lYXJcclxuXHJcblx0XHRhZGRMaW5lKCAnbjEnLCAnbjInICk7XHJcblx0XHRhZGRMaW5lKCAnbjInLCAnbjQnICk7XHJcblx0XHRhZGRMaW5lKCAnbjQnLCAnbjMnICk7XHJcblx0XHRhZGRMaW5lKCAnbjMnLCAnbjEnICk7XHJcblxyXG5cdFx0Ly8gZmFyXHJcblxyXG5cdFx0YWRkTGluZSggJ2YxJywgJ2YyJyApO1xyXG5cdFx0YWRkTGluZSggJ2YyJywgJ2Y0JyApO1xyXG5cdFx0YWRkTGluZSggJ2Y0JywgJ2YzJyApO1xyXG5cdFx0YWRkTGluZSggJ2YzJywgJ2YxJyApO1xyXG5cclxuXHRcdC8vIHNpZGVzXHJcblxyXG5cdFx0YWRkTGluZSggJ24xJywgJ2YxJyApO1xyXG5cdFx0YWRkTGluZSggJ24yJywgJ2YyJyApO1xyXG5cdFx0YWRkTGluZSggJ24zJywgJ2YzJyApO1xyXG5cdFx0YWRkTGluZSggJ240JywgJ2Y0JyApO1xyXG5cclxuXHRcdC8vIGNvbmVcclxuXHJcblx0XHRhZGRMaW5lKCAncCcsICduMScgKTtcclxuXHRcdGFkZExpbmUoICdwJywgJ24yJyApO1xyXG5cdFx0YWRkTGluZSggJ3AnLCAnbjMnICk7XHJcblx0XHRhZGRMaW5lKCAncCcsICduNCcgKTtcclxuXHJcblx0XHQvLyB1cFxyXG5cclxuXHRcdGFkZExpbmUoICd1MScsICd1MicgKTtcclxuXHRcdGFkZExpbmUoICd1MicsICd1MycgKTtcclxuXHRcdGFkZExpbmUoICd1MycsICd1MScgKTtcclxuXHJcblx0XHQvLyB0YXJnZXRcclxuXHJcblx0XHRhZGRMaW5lKCAnYycsICd0JyApO1xyXG5cdFx0YWRkTGluZSggJ3AnLCAnYycgKTtcclxuXHJcblx0XHQvLyBjcm9zc1xyXG5cclxuXHRcdGFkZExpbmUoICdjbjEnLCAnY24yJyApO1xyXG5cdFx0YWRkTGluZSggJ2NuMycsICdjbjQnICk7XHJcblxyXG5cdFx0YWRkTGluZSggJ2NmMScsICdjZjInICk7XHJcblx0XHRhZGRMaW5lKCAnY2YzJywgJ2NmNCcgKTtcclxuXHJcblx0XHRmdW5jdGlvbiBhZGRMaW5lKCBhLCBiICkge1xyXG5cclxuXHRcdFx0YWRkUG9pbnQoIGEgKTtcclxuXHRcdFx0YWRkUG9pbnQoIGIgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0ZnVuY3Rpb24gYWRkUG9pbnQoIGlkICkge1xyXG5cclxuXHRcdFx0dmVydGljZXMucHVzaCggMCwgMCwgMCApO1xyXG5cdFx0XHRjb2xvcnMucHVzaCggMCwgMCwgMCApO1xyXG5cclxuXHRcdFx0aWYgKCBwb2ludE1hcFsgaWQgXSA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHRwb2ludE1hcFsgaWQgXSA9IFtdO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0cG9pbnRNYXBbIGlkIF0ucHVzaCggKCB2ZXJ0aWNlcy5sZW5ndGggLyAzICkgLSAxICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGdlb21ldHJ5LnNldEF0dHJpYnV0ZSggJ3Bvc2l0aW9uJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIHZlcnRpY2VzLCAzICkgKTtcclxuXHRcdGdlb21ldHJ5LnNldEF0dHJpYnV0ZSggJ2NvbG9yJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIGNvbG9ycywgMyApICk7XHJcblxyXG5cdFx0c3VwZXIoIGdlb21ldHJ5LCBtYXRlcmlhbCApO1xyXG5cclxuXHRcdHRoaXMudHlwZSA9ICdDYW1lcmFIZWxwZXInO1xyXG5cclxuXHRcdHRoaXMuY2FtZXJhID0gY2FtZXJhO1xyXG5cdFx0aWYgKCB0aGlzLmNhbWVyYS51cGRhdGVQcm9qZWN0aW9uTWF0cml4ICkgdGhpcy5jYW1lcmEudXBkYXRlUHJvamVjdGlvbk1hdHJpeCgpO1xyXG5cclxuXHRcdHRoaXMubWF0cml4ID0gY2FtZXJhLm1hdHJpeFdvcmxkO1xyXG5cdFx0dGhpcy5tYXRyaXhBdXRvVXBkYXRlID0gZmFsc2U7XHJcblxyXG5cdFx0dGhpcy5wb2ludE1hcCA9IHBvaW50TWFwO1xyXG5cclxuXHRcdHRoaXMudXBkYXRlKCk7XHJcblxyXG5cdFx0Ly8gY29sb3JzXHJcblxyXG5cdFx0Y29uc3QgY29sb3JGcnVzdHVtID0gbmV3IENvbG9yKCAweGZmYWEwMCApO1xyXG5cdFx0Y29uc3QgY29sb3JDb25lID0gbmV3IENvbG9yKCAweGZmMDAwMCApO1xyXG5cdFx0Y29uc3QgY29sb3JVcCA9IG5ldyBDb2xvciggMHgwMGFhZmYgKTtcclxuXHRcdGNvbnN0IGNvbG9yVGFyZ2V0ID0gbmV3IENvbG9yKCAweGZmZmZmZiApO1xyXG5cdFx0Y29uc3QgY29sb3JDcm9zcyA9IG5ldyBDb2xvciggMHgzMzMzMzMgKTtcclxuXHJcblx0XHR0aGlzLnNldENvbG9ycyggY29sb3JGcnVzdHVtLCBjb2xvckNvbmUsIGNvbG9yVXAsIGNvbG9yVGFyZ2V0LCBjb2xvckNyb3NzICk7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0Q29sb3JzKCBmcnVzdHVtLCBjb25lLCB1cCwgdGFyZ2V0LCBjcm9zcyApIHtcclxuXHJcblx0XHRjb25zdCBnZW9tZXRyeSA9IHRoaXMuZ2VvbWV0cnk7XHJcblxyXG5cdFx0Y29uc3QgY29sb3JBdHRyaWJ1dGUgPSBnZW9tZXRyeS5nZXRBdHRyaWJ1dGUoICdjb2xvcicgKTtcclxuXHJcblx0XHQvLyBuZWFyXHJcblxyXG5cdFx0Y29sb3JBdHRyaWJ1dGUuc2V0WFlaKCAwLCBmcnVzdHVtLnIsIGZydXN0dW0uZywgZnJ1c3R1bS5iICk7IGNvbG9yQXR0cmlidXRlLnNldFhZWiggMSwgZnJ1c3R1bS5yLCBmcnVzdHVtLmcsIGZydXN0dW0uYiApOyAvLyBuMSwgbjJcclxuXHRcdGNvbG9yQXR0cmlidXRlLnNldFhZWiggMiwgZnJ1c3R1bS5yLCBmcnVzdHVtLmcsIGZydXN0dW0uYiApOyBjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDMsIGZydXN0dW0uciwgZnJ1c3R1bS5nLCBmcnVzdHVtLmIgKTsgLy8gbjIsIG40XHJcblx0XHRjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDQsIGZydXN0dW0uciwgZnJ1c3R1bS5nLCBmcnVzdHVtLmIgKTsgY29sb3JBdHRyaWJ1dGUuc2V0WFlaKCA1LCBmcnVzdHVtLnIsIGZydXN0dW0uZywgZnJ1c3R1bS5iICk7IC8vIG40LCBuM1xyXG5cdFx0Y29sb3JBdHRyaWJ1dGUuc2V0WFlaKCA2LCBmcnVzdHVtLnIsIGZydXN0dW0uZywgZnJ1c3R1bS5iICk7IGNvbG9yQXR0cmlidXRlLnNldFhZWiggNywgZnJ1c3R1bS5yLCBmcnVzdHVtLmcsIGZydXN0dW0uYiApOyAvLyBuMywgbjFcclxuXHJcblx0XHQvLyBmYXJcclxuXHJcblx0XHRjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDgsIGZydXN0dW0uciwgZnJ1c3R1bS5nLCBmcnVzdHVtLmIgKTsgY29sb3JBdHRyaWJ1dGUuc2V0WFlaKCA5LCBmcnVzdHVtLnIsIGZydXN0dW0uZywgZnJ1c3R1bS5iICk7IC8vIGYxLCBmMlxyXG5cdFx0Y29sb3JBdHRyaWJ1dGUuc2V0WFlaKCAxMCwgZnJ1c3R1bS5yLCBmcnVzdHVtLmcsIGZydXN0dW0uYiApOyBjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDExLCBmcnVzdHVtLnIsIGZydXN0dW0uZywgZnJ1c3R1bS5iICk7IC8vIGYyLCBmNFxyXG5cdFx0Y29sb3JBdHRyaWJ1dGUuc2V0WFlaKCAxMiwgZnJ1c3R1bS5yLCBmcnVzdHVtLmcsIGZydXN0dW0uYiApOyBjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDEzLCBmcnVzdHVtLnIsIGZydXN0dW0uZywgZnJ1c3R1bS5iICk7IC8vIGY0LCBmM1xyXG5cdFx0Y29sb3JBdHRyaWJ1dGUuc2V0WFlaKCAxNCwgZnJ1c3R1bS5yLCBmcnVzdHVtLmcsIGZydXN0dW0uYiApOyBjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDE1LCBmcnVzdHVtLnIsIGZydXN0dW0uZywgZnJ1c3R1bS5iICk7IC8vIGYzLCBmMVxyXG5cclxuXHRcdC8vIHNpZGVzXHJcblxyXG5cdFx0Y29sb3JBdHRyaWJ1dGUuc2V0WFlaKCAxNiwgZnJ1c3R1bS5yLCBmcnVzdHVtLmcsIGZydXN0dW0uYiApOyBjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDE3LCBmcnVzdHVtLnIsIGZydXN0dW0uZywgZnJ1c3R1bS5iICk7IC8vIG4xLCBmMVxyXG5cdFx0Y29sb3JBdHRyaWJ1dGUuc2V0WFlaKCAxOCwgZnJ1c3R1bS5yLCBmcnVzdHVtLmcsIGZydXN0dW0uYiApOyBjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDE5LCBmcnVzdHVtLnIsIGZydXN0dW0uZywgZnJ1c3R1bS5iICk7IC8vIG4yLCBmMlxyXG5cdFx0Y29sb3JBdHRyaWJ1dGUuc2V0WFlaKCAyMCwgZnJ1c3R1bS5yLCBmcnVzdHVtLmcsIGZydXN0dW0uYiApOyBjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDIxLCBmcnVzdHVtLnIsIGZydXN0dW0uZywgZnJ1c3R1bS5iICk7IC8vIG4zLCBmM1xyXG5cdFx0Y29sb3JBdHRyaWJ1dGUuc2V0WFlaKCAyMiwgZnJ1c3R1bS5yLCBmcnVzdHVtLmcsIGZydXN0dW0uYiApOyBjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDIzLCBmcnVzdHVtLnIsIGZydXN0dW0uZywgZnJ1c3R1bS5iICk7IC8vIG40LCBmNFxyXG5cclxuXHRcdC8vIGNvbmVcclxuXHJcblx0XHRjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDI0LCBjb25lLnIsIGNvbmUuZywgY29uZS5iICk7IGNvbG9yQXR0cmlidXRlLnNldFhZWiggMjUsIGNvbmUuciwgY29uZS5nLCBjb25lLmIgKTsgLy8gcCwgbjFcclxuXHRcdGNvbG9yQXR0cmlidXRlLnNldFhZWiggMjYsIGNvbmUuciwgY29uZS5nLCBjb25lLmIgKTsgY29sb3JBdHRyaWJ1dGUuc2V0WFlaKCAyNywgY29uZS5yLCBjb25lLmcsIGNvbmUuYiApOyAvLyBwLCBuMlxyXG5cdFx0Y29sb3JBdHRyaWJ1dGUuc2V0WFlaKCAyOCwgY29uZS5yLCBjb25lLmcsIGNvbmUuYiApOyBjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDI5LCBjb25lLnIsIGNvbmUuZywgY29uZS5iICk7IC8vIHAsIG4zXHJcblx0XHRjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDMwLCBjb25lLnIsIGNvbmUuZywgY29uZS5iICk7IGNvbG9yQXR0cmlidXRlLnNldFhZWiggMzEsIGNvbmUuciwgY29uZS5nLCBjb25lLmIgKTsgLy8gcCwgbjRcclxuXHJcblx0XHQvLyB1cFxyXG5cclxuXHRcdGNvbG9yQXR0cmlidXRlLnNldFhZWiggMzIsIHVwLnIsIHVwLmcsIHVwLmIgKTsgY29sb3JBdHRyaWJ1dGUuc2V0WFlaKCAzMywgdXAuciwgdXAuZywgdXAuYiApOyAvLyB1MSwgdTJcclxuXHRcdGNvbG9yQXR0cmlidXRlLnNldFhZWiggMzQsIHVwLnIsIHVwLmcsIHVwLmIgKTsgY29sb3JBdHRyaWJ1dGUuc2V0WFlaKCAzNSwgdXAuciwgdXAuZywgdXAuYiApOyAvLyB1MiwgdTNcclxuXHRcdGNvbG9yQXR0cmlidXRlLnNldFhZWiggMzYsIHVwLnIsIHVwLmcsIHVwLmIgKTsgY29sb3JBdHRyaWJ1dGUuc2V0WFlaKCAzNywgdXAuciwgdXAuZywgdXAuYiApOyAvLyB1MywgdTFcclxuXHJcblx0XHQvLyB0YXJnZXRcclxuXHJcblx0XHRjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDM4LCB0YXJnZXQuciwgdGFyZ2V0LmcsIHRhcmdldC5iICk7IGNvbG9yQXR0cmlidXRlLnNldFhZWiggMzksIHRhcmdldC5yLCB0YXJnZXQuZywgdGFyZ2V0LmIgKTsgLy8gYywgdFxyXG5cdFx0Y29sb3JBdHRyaWJ1dGUuc2V0WFlaKCA0MCwgY3Jvc3MuciwgY3Jvc3MuZywgY3Jvc3MuYiApOyBjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDQxLCBjcm9zcy5yLCBjcm9zcy5nLCBjcm9zcy5iICk7IC8vIHAsIGNcclxuXHJcblx0XHQvLyBjcm9zc1xyXG5cclxuXHRcdGNvbG9yQXR0cmlidXRlLnNldFhZWiggNDIsIGNyb3NzLnIsIGNyb3NzLmcsIGNyb3NzLmIgKTsgY29sb3JBdHRyaWJ1dGUuc2V0WFlaKCA0MywgY3Jvc3MuciwgY3Jvc3MuZywgY3Jvc3MuYiApOyAvLyBjbjEsIGNuMlxyXG5cdFx0Y29sb3JBdHRyaWJ1dGUuc2V0WFlaKCA0NCwgY3Jvc3MuciwgY3Jvc3MuZywgY3Jvc3MuYiApOyBjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDQ1LCBjcm9zcy5yLCBjcm9zcy5nLCBjcm9zcy5iICk7IC8vIGNuMywgY240XHJcblxyXG5cdFx0Y29sb3JBdHRyaWJ1dGUuc2V0WFlaKCA0NiwgY3Jvc3MuciwgY3Jvc3MuZywgY3Jvc3MuYiApOyBjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDQ3LCBjcm9zcy5yLCBjcm9zcy5nLCBjcm9zcy5iICk7IC8vIGNmMSwgY2YyXHJcblx0XHRjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDQ4LCBjcm9zcy5yLCBjcm9zcy5nLCBjcm9zcy5iICk7IGNvbG9yQXR0cmlidXRlLnNldFhZWiggNDksIGNyb3NzLnIsIGNyb3NzLmcsIGNyb3NzLmIgKTsgLy8gY2YzLCBjZjRcclxuXHJcblx0XHRjb2xvckF0dHJpYnV0ZS5uZWVkc1VwZGF0ZSA9IHRydWU7XHJcblxyXG5cdH1cclxuXHJcblx0dXBkYXRlKCkge1xyXG5cclxuXHRcdGNvbnN0IGdlb21ldHJ5ID0gdGhpcy5nZW9tZXRyeTtcclxuXHRcdGNvbnN0IHBvaW50TWFwID0gdGhpcy5wb2ludE1hcDtcclxuXHJcblx0XHRjb25zdCB3ID0gMSwgaCA9IDE7XHJcblxyXG5cdFx0Ly8gd2UgbmVlZCBqdXN0IGNhbWVyYSBwcm9qZWN0aW9uIG1hdHJpeCBpbnZlcnNlXHJcblx0XHQvLyB3b3JsZCBtYXRyaXggbXVzdCBiZSBpZGVudGl0eVxyXG5cclxuXHRcdF9jYW1lcmEucHJvamVjdGlvbk1hdHJpeEludmVyc2UuY29weSggdGhpcy5jYW1lcmEucHJvamVjdGlvbk1hdHJpeEludmVyc2UgKTtcclxuXHJcblx0XHQvLyBjZW50ZXIgLyB0YXJnZXRcclxuXHJcblx0XHRzZXRQb2ludCggJ2MnLCBwb2ludE1hcCwgZ2VvbWV0cnksIF9jYW1lcmEsIDAsIDAsIC0gMSApO1xyXG5cdFx0c2V0UG9pbnQoICd0JywgcG9pbnRNYXAsIGdlb21ldHJ5LCBfY2FtZXJhLCAwLCAwLCAxICk7XHJcblxyXG5cdFx0Ly8gbmVhclxyXG5cclxuXHRcdHNldFBvaW50KCAnbjEnLCBwb2ludE1hcCwgZ2VvbWV0cnksIF9jYW1lcmEsIC0gdywgLSBoLCAtIDEgKTtcclxuXHRcdHNldFBvaW50KCAnbjInLCBwb2ludE1hcCwgZ2VvbWV0cnksIF9jYW1lcmEsIHcsIC0gaCwgLSAxICk7XHJcblx0XHRzZXRQb2ludCggJ24zJywgcG9pbnRNYXAsIGdlb21ldHJ5LCBfY2FtZXJhLCAtIHcsIGgsIC0gMSApO1xyXG5cdFx0c2V0UG9pbnQoICduNCcsIHBvaW50TWFwLCBnZW9tZXRyeSwgX2NhbWVyYSwgdywgaCwgLSAxICk7XHJcblxyXG5cdFx0Ly8gZmFyXHJcblxyXG5cdFx0c2V0UG9pbnQoICdmMScsIHBvaW50TWFwLCBnZW9tZXRyeSwgX2NhbWVyYSwgLSB3LCAtIGgsIDEgKTtcclxuXHRcdHNldFBvaW50KCAnZjInLCBwb2ludE1hcCwgZ2VvbWV0cnksIF9jYW1lcmEsIHcsIC0gaCwgMSApO1xyXG5cdFx0c2V0UG9pbnQoICdmMycsIHBvaW50TWFwLCBnZW9tZXRyeSwgX2NhbWVyYSwgLSB3LCBoLCAxICk7XHJcblx0XHRzZXRQb2ludCggJ2Y0JywgcG9pbnRNYXAsIGdlb21ldHJ5LCBfY2FtZXJhLCB3LCBoLCAxICk7XHJcblxyXG5cdFx0Ly8gdXBcclxuXHJcblx0XHRzZXRQb2ludCggJ3UxJywgcG9pbnRNYXAsIGdlb21ldHJ5LCBfY2FtZXJhLCB3ICogMC43LCBoICogMS4xLCAtIDEgKTtcclxuXHRcdHNldFBvaW50KCAndTInLCBwb2ludE1hcCwgZ2VvbWV0cnksIF9jYW1lcmEsIC0gdyAqIDAuNywgaCAqIDEuMSwgLSAxICk7XHJcblx0XHRzZXRQb2ludCggJ3UzJywgcG9pbnRNYXAsIGdlb21ldHJ5LCBfY2FtZXJhLCAwLCBoICogMiwgLSAxICk7XHJcblxyXG5cdFx0Ly8gY3Jvc3NcclxuXHJcblx0XHRzZXRQb2ludCggJ2NmMScsIHBvaW50TWFwLCBnZW9tZXRyeSwgX2NhbWVyYSwgLSB3LCAwLCAxICk7XHJcblx0XHRzZXRQb2ludCggJ2NmMicsIHBvaW50TWFwLCBnZW9tZXRyeSwgX2NhbWVyYSwgdywgMCwgMSApO1xyXG5cdFx0c2V0UG9pbnQoICdjZjMnLCBwb2ludE1hcCwgZ2VvbWV0cnksIF9jYW1lcmEsIDAsIC0gaCwgMSApO1xyXG5cdFx0c2V0UG9pbnQoICdjZjQnLCBwb2ludE1hcCwgZ2VvbWV0cnksIF9jYW1lcmEsIDAsIGgsIDEgKTtcclxuXHJcblx0XHRzZXRQb2ludCggJ2NuMScsIHBvaW50TWFwLCBnZW9tZXRyeSwgX2NhbWVyYSwgLSB3LCAwLCAtIDEgKTtcclxuXHRcdHNldFBvaW50KCAnY24yJywgcG9pbnRNYXAsIGdlb21ldHJ5LCBfY2FtZXJhLCB3LCAwLCAtIDEgKTtcclxuXHRcdHNldFBvaW50KCAnY24zJywgcG9pbnRNYXAsIGdlb21ldHJ5LCBfY2FtZXJhLCAwLCAtIGgsIC0gMSApO1xyXG5cdFx0c2V0UG9pbnQoICdjbjQnLCBwb2ludE1hcCwgZ2VvbWV0cnksIF9jYW1lcmEsIDAsIGgsIC0gMSApO1xyXG5cclxuXHRcdGdlb21ldHJ5LmdldEF0dHJpYnV0ZSggJ3Bvc2l0aW9uJyApLm5lZWRzVXBkYXRlID0gdHJ1ZTtcclxuXHJcblx0fVxyXG5cclxuXHRkaXNwb3NlKCkge1xyXG5cclxuXHRcdHRoaXMuZ2VvbWV0cnkuZGlzcG9zZSgpO1xyXG5cdFx0dGhpcy5tYXRlcmlhbC5kaXNwb3NlKCk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcblxyXG5mdW5jdGlvbiBzZXRQb2ludCggcG9pbnQsIHBvaW50TWFwLCBnZW9tZXRyeSwgY2FtZXJhLCB4LCB5LCB6ICkge1xyXG5cclxuXHRfdmVjdG9yLnNldCggeCwgeSwgeiApLnVucHJvamVjdCggY2FtZXJhICk7XHJcblxyXG5cdGNvbnN0IHBvaW50cyA9IHBvaW50TWFwWyBwb2ludCBdO1xyXG5cclxuXHRpZiAoIHBvaW50cyAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdGNvbnN0IHBvc2l0aW9uID0gZ2VvbWV0cnkuZ2V0QXR0cmlidXRlKCAncG9zaXRpb24nICk7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gcG9pbnRzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRwb3NpdGlvbi5zZXRYWVooIHBvaW50c1sgaSBdLCBfdmVjdG9yLngsIF92ZWN0b3IueSwgX3ZlY3Rvci56ICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBDYW1lcmFIZWxwZXIgfTtcclxuIiwiaW1wb3J0IHsgQm94MyB9IGZyb20gJy4uL21hdGgvQm94My5qcyc7XHJcbmltcG9ydCB7IExpbmVTZWdtZW50cyB9IGZyb20gJy4uL29iamVjdHMvTGluZVNlZ21lbnRzLmpzJztcclxuaW1wb3J0IHsgTGluZUJhc2ljTWF0ZXJpYWwgfSBmcm9tICcuLi9tYXRlcmlhbHMvTGluZUJhc2ljTWF0ZXJpYWwuanMnO1xyXG5pbXBvcnQgeyBCdWZmZXJBdHRyaWJ1dGUgfSBmcm9tICcuLi9jb3JlL0J1ZmZlckF0dHJpYnV0ZS5qcyc7XHJcbmltcG9ydCB7IEJ1ZmZlckdlb21ldHJ5IH0gZnJvbSAnLi4vY29yZS9CdWZmZXJHZW9tZXRyeS5qcyc7XHJcblxyXG5jb25zdCBfYm94ID0gLypAX19QVVJFX18qLyBuZXcgQm94MygpO1xyXG5cclxuY2xhc3MgQm94SGVscGVyIGV4dGVuZHMgTGluZVNlZ21lbnRzIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIG9iamVjdCwgY29sb3IgPSAweGZmZmYwMCApIHtcclxuXHJcblx0XHRjb25zdCBpbmRpY2VzID0gbmV3IFVpbnQxNkFycmF5KCBbIDAsIDEsIDEsIDIsIDIsIDMsIDMsIDAsIDQsIDUsIDUsIDYsIDYsIDcsIDcsIDQsIDAsIDQsIDEsIDUsIDIsIDYsIDMsIDcgXSApO1xyXG5cdFx0Y29uc3QgcG9zaXRpb25zID0gbmV3IEZsb2F0MzJBcnJheSggOCAqIDMgKTtcclxuXHJcblx0XHRjb25zdCBnZW9tZXRyeSA9IG5ldyBCdWZmZXJHZW9tZXRyeSgpO1xyXG5cdFx0Z2VvbWV0cnkuc2V0SW5kZXgoIG5ldyBCdWZmZXJBdHRyaWJ1dGUoIGluZGljZXMsIDEgKSApO1xyXG5cdFx0Z2VvbWV0cnkuc2V0QXR0cmlidXRlKCAncG9zaXRpb24nLCBuZXcgQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbnMsIDMgKSApO1xyXG5cclxuXHRcdHN1cGVyKCBnZW9tZXRyeSwgbmV3IExpbmVCYXNpY01hdGVyaWFsKCB7IGNvbG9yOiBjb2xvciwgdG9uZU1hcHBlZDogZmFsc2UgfSApICk7XHJcblxyXG5cdFx0dGhpcy5vYmplY3QgPSBvYmplY3Q7XHJcblx0XHR0aGlzLnR5cGUgPSAnQm94SGVscGVyJztcclxuXHJcblx0XHR0aGlzLm1hdHJpeEF1dG9VcGRhdGUgPSBmYWxzZTtcclxuXHJcblx0XHR0aGlzLnVwZGF0ZSgpO1xyXG5cclxuXHR9XHJcblxyXG5cdHVwZGF0ZSggb2JqZWN0ICkge1xyXG5cclxuXHRcdGlmICggb2JqZWN0ICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5Cb3hIZWxwZXI6IC51cGRhdGUoKSBoYXMgbm8gbG9uZ2VyIGFyZ3VtZW50cy4nICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggdGhpcy5vYmplY3QgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdF9ib3guc2V0RnJvbU9iamVjdCggdGhpcy5vYmplY3QgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBfYm94LmlzRW1wdHkoKSApIHJldHVybjtcclxuXHJcblx0XHRjb25zdCBtaW4gPSBfYm94Lm1pbjtcclxuXHRcdGNvbnN0IG1heCA9IF9ib3gubWF4O1xyXG5cclxuXHRcdC8qXHJcblx0XHRcdDVfX19fNFxyXG5cdFx0MS9fX18wL3xcclxuXHRcdHwgNl9ffF83XHJcblx0XHQyL19fXzMvXHJcblxyXG5cdFx0MDogbWF4LngsIG1heC55LCBtYXguelxyXG5cdFx0MTogbWluLngsIG1heC55LCBtYXguelxyXG5cdFx0MjogbWluLngsIG1pbi55LCBtYXguelxyXG5cdFx0MzogbWF4LngsIG1pbi55LCBtYXguelxyXG5cdFx0NDogbWF4LngsIG1heC55LCBtaW4uelxyXG5cdFx0NTogbWluLngsIG1heC55LCBtaW4uelxyXG5cdFx0NjogbWluLngsIG1pbi55LCBtaW4uelxyXG5cdFx0NzogbWF4LngsIG1pbi55LCBtaW4uelxyXG5cdFx0Ki9cclxuXHJcblx0XHRjb25zdCBwb3NpdGlvbiA9IHRoaXMuZ2VvbWV0cnkuYXR0cmlidXRlcy5wb3NpdGlvbjtcclxuXHRcdGNvbnN0IGFycmF5ID0gcG9zaXRpb24uYXJyYXk7XHJcblxyXG5cdFx0YXJyYXlbIDAgXSA9IG1heC54OyBhcnJheVsgMSBdID0gbWF4Lnk7IGFycmF5WyAyIF0gPSBtYXguejtcclxuXHRcdGFycmF5WyAzIF0gPSBtaW4ueDsgYXJyYXlbIDQgXSA9IG1heC55OyBhcnJheVsgNSBdID0gbWF4Lno7XHJcblx0XHRhcnJheVsgNiBdID0gbWluLng7IGFycmF5WyA3IF0gPSBtaW4ueTsgYXJyYXlbIDggXSA9IG1heC56O1xyXG5cdFx0YXJyYXlbIDkgXSA9IG1heC54OyBhcnJheVsgMTAgXSA9IG1pbi55OyBhcnJheVsgMTEgXSA9IG1heC56O1xyXG5cdFx0YXJyYXlbIDEyIF0gPSBtYXgueDsgYXJyYXlbIDEzIF0gPSBtYXgueTsgYXJyYXlbIDE0IF0gPSBtaW4uejtcclxuXHRcdGFycmF5WyAxNSBdID0gbWluLng7IGFycmF5WyAxNiBdID0gbWF4Lnk7IGFycmF5WyAxNyBdID0gbWluLno7XHJcblx0XHRhcnJheVsgMTggXSA9IG1pbi54OyBhcnJheVsgMTkgXSA9IG1pbi55OyBhcnJheVsgMjAgXSA9IG1pbi56O1xyXG5cdFx0YXJyYXlbIDIxIF0gPSBtYXgueDsgYXJyYXlbIDIyIF0gPSBtaW4ueTsgYXJyYXlbIDIzIF0gPSBtaW4uejtcclxuXHJcblx0XHRwb3NpdGlvbi5uZWVkc1VwZGF0ZSA9IHRydWU7XHJcblxyXG5cdFx0dGhpcy5nZW9tZXRyeS5jb21wdXRlQm91bmRpbmdTcGhlcmUoKTtcclxuXHJcblx0fVxyXG5cclxuXHRzZXRGcm9tT2JqZWN0KCBvYmplY3QgKSB7XHJcblxyXG5cdFx0dGhpcy5vYmplY3QgPSBvYmplY3Q7XHJcblx0XHR0aGlzLnVwZGF0ZSgpO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGNvcHkoIHNvdXJjZSwgcmVjdXJzaXZlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSwgcmVjdXJzaXZlICk7XHJcblxyXG5cdFx0dGhpcy5vYmplY3QgPSBzb3VyY2Uub2JqZWN0O1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGRpc3Bvc2UoKSB7XHJcblxyXG5cdFx0dGhpcy5nZW9tZXRyeS5kaXNwb3NlKCk7XHJcblx0XHR0aGlzLm1hdGVyaWFsLmRpc3Bvc2UoKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuXHJcbmV4cG9ydCB7IEJveEhlbHBlciB9O1xyXG4iLCJpbXBvcnQgeyBMaW5lU2VnbWVudHMgfSBmcm9tICcuLi9vYmplY3RzL0xpbmVTZWdtZW50cy5qcyc7XHJcbmltcG9ydCB7IExpbmVCYXNpY01hdGVyaWFsIH0gZnJvbSAnLi4vbWF0ZXJpYWxzL0xpbmVCYXNpY01hdGVyaWFsLmpzJztcclxuaW1wb3J0IHsgQnVmZmVyQXR0cmlidXRlLCBGbG9hdDMyQnVmZmVyQXR0cmlidXRlIH0gZnJvbSAnLi4vY29yZS9CdWZmZXJBdHRyaWJ1dGUuanMnO1xyXG5pbXBvcnQgeyBCdWZmZXJHZW9tZXRyeSB9IGZyb20gJy4uL2NvcmUvQnVmZmVyR2VvbWV0cnkuanMnO1xyXG5cclxuY2xhc3MgQm94M0hlbHBlciBleHRlbmRzIExpbmVTZWdtZW50cyB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBib3gsIGNvbG9yID0gMHhmZmZmMDAgKSB7XHJcblxyXG5cdFx0Y29uc3QgaW5kaWNlcyA9IG5ldyBVaW50MTZBcnJheSggWyAwLCAxLCAxLCAyLCAyLCAzLCAzLCAwLCA0LCA1LCA1LCA2LCA2LCA3LCA3LCA0LCAwLCA0LCAxLCA1LCAyLCA2LCAzLCA3IF0gKTtcclxuXHJcblx0XHRjb25zdCBwb3NpdGlvbnMgPSBbIDEsIDEsIDEsIC0gMSwgMSwgMSwgLSAxLCAtIDEsIDEsIDEsIC0gMSwgMSwgMSwgMSwgLSAxLCAtIDEsIDEsIC0gMSwgLSAxLCAtIDEsIC0gMSwgMSwgLSAxLCAtIDEgXTtcclxuXHJcblx0XHRjb25zdCBnZW9tZXRyeSA9IG5ldyBCdWZmZXJHZW9tZXRyeSgpO1xyXG5cclxuXHRcdGdlb21ldHJ5LnNldEluZGV4KCBuZXcgQnVmZmVyQXR0cmlidXRlKCBpbmRpY2VzLCAxICkgKTtcclxuXHJcblx0XHRnZW9tZXRyeS5zZXRBdHRyaWJ1dGUoICdwb3NpdGlvbicsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbnMsIDMgKSApO1xyXG5cclxuXHRcdHN1cGVyKCBnZW9tZXRyeSwgbmV3IExpbmVCYXNpY01hdGVyaWFsKCB7IGNvbG9yOiBjb2xvciwgdG9uZU1hcHBlZDogZmFsc2UgfSApICk7XHJcblxyXG5cdFx0dGhpcy5ib3ggPSBib3g7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ0JveDNIZWxwZXInO1xyXG5cclxuXHRcdHRoaXMuZ2VvbWV0cnkuY29tcHV0ZUJvdW5kaW5nU3BoZXJlKCk7XHJcblxyXG5cdH1cclxuXHJcblx0dXBkYXRlTWF0cml4V29ybGQoIGZvcmNlICkge1xyXG5cclxuXHRcdGNvbnN0IGJveCA9IHRoaXMuYm94O1xyXG5cclxuXHRcdGlmICggYm94LmlzRW1wdHkoKSApIHJldHVybjtcclxuXHJcblx0XHRib3guZ2V0Q2VudGVyKCB0aGlzLnBvc2l0aW9uICk7XHJcblxyXG5cdFx0Ym94LmdldFNpemUoIHRoaXMuc2NhbGUgKTtcclxuXHJcblx0XHR0aGlzLnNjYWxlLm11bHRpcGx5U2NhbGFyKCAwLjUgKTtcclxuXHJcblx0XHRzdXBlci51cGRhdGVNYXRyaXhXb3JsZCggZm9yY2UgKTtcclxuXHJcblx0fVxyXG5cclxuXHRkaXNwb3NlKCkge1xyXG5cclxuXHRcdHRoaXMuZ2VvbWV0cnkuZGlzcG9zZSgpO1xyXG5cdFx0dGhpcy5tYXRlcmlhbC5kaXNwb3NlKCk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IEJveDNIZWxwZXIgfTtcclxuIiwiaW1wb3J0IHsgTGluZSB9IGZyb20gJy4uL29iamVjdHMvTGluZS5qcyc7XHJcbmltcG9ydCB7IE1lc2ggfSBmcm9tICcuLi9vYmplY3RzL01lc2guanMnO1xyXG5pbXBvcnQgeyBMaW5lQmFzaWNNYXRlcmlhbCB9IGZyb20gJy4uL21hdGVyaWFscy9MaW5lQmFzaWNNYXRlcmlhbC5qcyc7XHJcbmltcG9ydCB7IE1lc2hCYXNpY01hdGVyaWFsIH0gZnJvbSAnLi4vbWF0ZXJpYWxzL01lc2hCYXNpY01hdGVyaWFsLmpzJztcclxuaW1wb3J0IHsgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSB9IGZyb20gJy4uL2NvcmUvQnVmZmVyQXR0cmlidXRlLmpzJztcclxuaW1wb3J0IHsgQnVmZmVyR2VvbWV0cnkgfSBmcm9tICcuLi9jb3JlL0J1ZmZlckdlb21ldHJ5LmpzJztcclxuXHJcbmNsYXNzIFBsYW5lSGVscGVyIGV4dGVuZHMgTGluZSB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBwbGFuZSwgc2l6ZSA9IDEsIGhleCA9IDB4ZmZmZjAwICkge1xyXG5cclxuXHRcdGNvbnN0IGNvbG9yID0gaGV4O1xyXG5cclxuXHRcdGNvbnN0IHBvc2l0aW9ucyA9IFsgMSwgLSAxLCAwLCAtIDEsIDEsIDAsIC0gMSwgLSAxLCAwLCAxLCAxLCAwLCAtIDEsIDEsIDAsIC0gMSwgLSAxLCAwLCAxLCAtIDEsIDAsIDEsIDEsIDAgXTtcclxuXHJcblx0XHRjb25zdCBnZW9tZXRyeSA9IG5ldyBCdWZmZXJHZW9tZXRyeSgpO1xyXG5cdFx0Z2VvbWV0cnkuc2V0QXR0cmlidXRlKCAncG9zaXRpb24nLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggcG9zaXRpb25zLCAzICkgKTtcclxuXHRcdGdlb21ldHJ5LmNvbXB1dGVCb3VuZGluZ1NwaGVyZSgpO1xyXG5cclxuXHRcdHN1cGVyKCBnZW9tZXRyeSwgbmV3IExpbmVCYXNpY01hdGVyaWFsKCB7IGNvbG9yOiBjb2xvciwgdG9uZU1hcHBlZDogZmFsc2UgfSApICk7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ1BsYW5lSGVscGVyJztcclxuXHJcblx0XHR0aGlzLnBsYW5lID0gcGxhbmU7XHJcblxyXG5cdFx0dGhpcy5zaXplID0gc2l6ZTtcclxuXHJcblx0XHRjb25zdCBwb3NpdGlvbnMyID0gWyAxLCAxLCAwLCAtIDEsIDEsIDAsIC0gMSwgLSAxLCAwLCAxLCAxLCAwLCAtIDEsIC0gMSwgMCwgMSwgLSAxLCAwIF07XHJcblxyXG5cdFx0Y29uc3QgZ2VvbWV0cnkyID0gbmV3IEJ1ZmZlckdlb21ldHJ5KCk7XHJcblx0XHRnZW9tZXRyeTIuc2V0QXR0cmlidXRlKCAncG9zaXRpb24nLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggcG9zaXRpb25zMiwgMyApICk7XHJcblx0XHRnZW9tZXRyeTIuY29tcHV0ZUJvdW5kaW5nU3BoZXJlKCk7XHJcblxyXG5cdFx0dGhpcy5hZGQoIG5ldyBNZXNoKCBnZW9tZXRyeTIsIG5ldyBNZXNoQmFzaWNNYXRlcmlhbCggeyBjb2xvcjogY29sb3IsIG9wYWNpdHk6IDAuMiwgdHJhbnNwYXJlbnQ6IHRydWUsIGRlcHRoV3JpdGU6IGZhbHNlLCB0b25lTWFwcGVkOiBmYWxzZSB9ICkgKSApO1xyXG5cclxuXHR9XHJcblxyXG5cdHVwZGF0ZU1hdHJpeFdvcmxkKCBmb3JjZSApIHtcclxuXHJcblx0XHR0aGlzLnBvc2l0aW9uLnNldCggMCwgMCwgMCApO1xyXG5cclxuXHRcdHRoaXMuc2NhbGUuc2V0KCAwLjUgKiB0aGlzLnNpemUsIDAuNSAqIHRoaXMuc2l6ZSwgMSApO1xyXG5cclxuXHRcdHRoaXMubG9va0F0KCB0aGlzLnBsYW5lLm5vcm1hbCApO1xyXG5cclxuXHRcdHRoaXMudHJhbnNsYXRlWiggLSB0aGlzLnBsYW5lLmNvbnN0YW50ICk7XHJcblxyXG5cdFx0c3VwZXIudXBkYXRlTWF0cml4V29ybGQoIGZvcmNlICk7XHJcblxyXG5cdH1cclxuXHJcblx0ZGlzcG9zZSgpIHtcclxuXHJcblx0XHR0aGlzLmdlb21ldHJ5LmRpc3Bvc2UoKTtcclxuXHRcdHRoaXMubWF0ZXJpYWwuZGlzcG9zZSgpO1xyXG5cdFx0dGhpcy5jaGlsZHJlblsgMCBdLmdlb21ldHJ5LmRpc3Bvc2UoKTtcclxuXHRcdHRoaXMuY2hpbGRyZW5bIDAgXS5tYXRlcmlhbC5kaXNwb3NlKCk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IFBsYW5lSGVscGVyIH07XHJcbiIsImltcG9ydCB7IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUgfSBmcm9tICcuLi9jb3JlL0J1ZmZlckF0dHJpYnV0ZS5qcyc7XHJcbmltcG9ydCB7IEJ1ZmZlckdlb21ldHJ5IH0gZnJvbSAnLi4vY29yZS9CdWZmZXJHZW9tZXRyeS5qcyc7XHJcbmltcG9ydCB7IE9iamVjdDNEIH0gZnJvbSAnLi4vY29yZS9PYmplY3QzRC5qcyc7XHJcbmltcG9ydCB7IEN5bGluZGVyR2VvbWV0cnkgfSBmcm9tICcuLi9nZW9tZXRyaWVzL0N5bGluZGVyR2VvbWV0cnkuanMnO1xyXG5pbXBvcnQgeyBNZXNoQmFzaWNNYXRlcmlhbCB9IGZyb20gJy4uL21hdGVyaWFscy9NZXNoQmFzaWNNYXRlcmlhbC5qcyc7XHJcbmltcG9ydCB7IExpbmVCYXNpY01hdGVyaWFsIH0gZnJvbSAnLi4vbWF0ZXJpYWxzL0xpbmVCYXNpY01hdGVyaWFsLmpzJztcclxuaW1wb3J0IHsgTWVzaCB9IGZyb20gJy4uL29iamVjdHMvTWVzaC5qcyc7XHJcbmltcG9ydCB7IExpbmUgfSBmcm9tICcuLi9vYmplY3RzL0xpbmUuanMnO1xyXG5pbXBvcnQgeyBWZWN0b3IzIH0gZnJvbSAnLi4vbWF0aC9WZWN0b3IzLmpzJztcclxuXHJcbmNvbnN0IF9heGlzID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5sZXQgX2xpbmVHZW9tZXRyeSwgX2NvbmVHZW9tZXRyeTtcclxuXHJcbmNsYXNzIEFycm93SGVscGVyIGV4dGVuZHMgT2JqZWN0M0Qge1xyXG5cclxuXHQvLyBkaXIgaXMgYXNzdW1lZCB0byBiZSBub3JtYWxpemVkXHJcblxyXG5cdGNvbnN0cnVjdG9yKCBkaXIgPSBuZXcgVmVjdG9yMyggMCwgMCwgMSApLCBvcmlnaW4gPSBuZXcgVmVjdG9yMyggMCwgMCwgMCApLCBsZW5ndGggPSAxLCBjb2xvciA9IDB4ZmZmZjAwLCBoZWFkTGVuZ3RoID0gbGVuZ3RoICogMC4yLCBoZWFkV2lkdGggPSBoZWFkTGVuZ3RoICogMC4yICkge1xyXG5cclxuXHRcdHN1cGVyKCk7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ0Fycm93SGVscGVyJztcclxuXHJcblx0XHRpZiAoIF9saW5lR2VvbWV0cnkgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdF9saW5lR2VvbWV0cnkgPSBuZXcgQnVmZmVyR2VvbWV0cnkoKTtcclxuXHRcdFx0X2xpbmVHZW9tZXRyeS5zZXRBdHRyaWJ1dGUoICdwb3NpdGlvbicsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCBbIDAsIDAsIDAsIDAsIDEsIDAgXSwgMyApICk7XHJcblxyXG5cdFx0XHRfY29uZUdlb21ldHJ5ID0gbmV3IEN5bGluZGVyR2VvbWV0cnkoIDAsIDAuNSwgMSwgNSwgMSApO1xyXG5cdFx0XHRfY29uZUdlb21ldHJ5LnRyYW5zbGF0ZSggMCwgLSAwLjUsIDAgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5wb3NpdGlvbi5jb3B5KCBvcmlnaW4gKTtcclxuXHJcblx0XHR0aGlzLmxpbmUgPSBuZXcgTGluZSggX2xpbmVHZW9tZXRyeSwgbmV3IExpbmVCYXNpY01hdGVyaWFsKCB7IGNvbG9yOiBjb2xvciwgdG9uZU1hcHBlZDogZmFsc2UgfSApICk7XHJcblx0XHR0aGlzLmxpbmUubWF0cml4QXV0b1VwZGF0ZSA9IGZhbHNlO1xyXG5cdFx0dGhpcy5hZGQoIHRoaXMubGluZSApO1xyXG5cclxuXHRcdHRoaXMuY29uZSA9IG5ldyBNZXNoKCBfY29uZUdlb21ldHJ5LCBuZXcgTWVzaEJhc2ljTWF0ZXJpYWwoIHsgY29sb3I6IGNvbG9yLCB0b25lTWFwcGVkOiBmYWxzZSB9ICkgKTtcclxuXHRcdHRoaXMuY29uZS5tYXRyaXhBdXRvVXBkYXRlID0gZmFsc2U7XHJcblx0XHR0aGlzLmFkZCggdGhpcy5jb25lICk7XHJcblxyXG5cdFx0dGhpcy5zZXREaXJlY3Rpb24oIGRpciApO1xyXG5cdFx0dGhpcy5zZXRMZW5ndGgoIGxlbmd0aCwgaGVhZExlbmd0aCwgaGVhZFdpZHRoICk7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0RGlyZWN0aW9uKCBkaXIgKSB7XHJcblxyXG5cdFx0Ly8gZGlyIGlzIGFzc3VtZWQgdG8gYmUgbm9ybWFsaXplZFxyXG5cclxuXHRcdGlmICggZGlyLnkgPiAwLjk5OTk5ICkge1xyXG5cclxuXHRcdFx0dGhpcy5xdWF0ZXJuaW9uLnNldCggMCwgMCwgMCwgMSApO1xyXG5cclxuXHRcdH0gZWxzZSBpZiAoIGRpci55IDwgLSAwLjk5OTk5ICkge1xyXG5cclxuXHRcdFx0dGhpcy5xdWF0ZXJuaW9uLnNldCggMSwgMCwgMCwgMCApO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRfYXhpcy5zZXQoIGRpci56LCAwLCAtIGRpci54ICkubm9ybWFsaXplKCk7XHJcblxyXG5cdFx0XHRjb25zdCByYWRpYW5zID0gTWF0aC5hY29zKCBkaXIueSApO1xyXG5cclxuXHRcdFx0dGhpcy5xdWF0ZXJuaW9uLnNldEZyb21BeGlzQW5nbGUoIF9heGlzLCByYWRpYW5zICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdHNldExlbmd0aCggbGVuZ3RoLCBoZWFkTGVuZ3RoID0gbGVuZ3RoICogMC4yLCBoZWFkV2lkdGggPSBoZWFkTGVuZ3RoICogMC4yICkge1xyXG5cclxuXHRcdHRoaXMubGluZS5zY2FsZS5zZXQoIDEsIE1hdGgubWF4KCAwLjAwMDEsIGxlbmd0aCAtIGhlYWRMZW5ndGggKSwgMSApOyAvLyBzZWUgIzE3NDU4XHJcblx0XHR0aGlzLmxpbmUudXBkYXRlTWF0cml4KCk7XHJcblxyXG5cdFx0dGhpcy5jb25lLnNjYWxlLnNldCggaGVhZFdpZHRoLCBoZWFkTGVuZ3RoLCBoZWFkV2lkdGggKTtcclxuXHRcdHRoaXMuY29uZS5wb3NpdGlvbi55ID0gbGVuZ3RoO1xyXG5cdFx0dGhpcy5jb25lLnVwZGF0ZU1hdHJpeCgpO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldENvbG9yKCBjb2xvciApIHtcclxuXHJcblx0XHR0aGlzLmxpbmUubWF0ZXJpYWwuY29sb3Iuc2V0KCBjb2xvciApO1xyXG5cdFx0dGhpcy5jb25lLm1hdGVyaWFsLmNvbG9yLnNldCggY29sb3IgKTtcclxuXHJcblx0fVxyXG5cclxuXHRjb3B5KCBzb3VyY2UgKSB7XHJcblxyXG5cdFx0c3VwZXIuY29weSggc291cmNlLCBmYWxzZSApO1xyXG5cclxuXHRcdHRoaXMubGluZS5jb3B5KCBzb3VyY2UubGluZSApO1xyXG5cdFx0dGhpcy5jb25lLmNvcHkoIHNvdXJjZS5jb25lICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0ZGlzcG9zZSgpIHtcclxuXHJcblx0XHR0aGlzLmxpbmUuZ2VvbWV0cnkuZGlzcG9zZSgpO1xyXG5cdFx0dGhpcy5saW5lLm1hdGVyaWFsLmRpc3Bvc2UoKTtcclxuXHRcdHRoaXMuY29uZS5nZW9tZXRyeS5kaXNwb3NlKCk7XHJcblx0XHR0aGlzLmNvbmUubWF0ZXJpYWwuZGlzcG9zZSgpO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5cclxuZXhwb3J0IHsgQXJyb3dIZWxwZXIgfTtcclxuIiwiaW1wb3J0IHsgTGluZVNlZ21lbnRzIH0gZnJvbSAnLi4vb2JqZWN0cy9MaW5lU2VnbWVudHMuanMnO1xyXG5pbXBvcnQgeyBMaW5lQmFzaWNNYXRlcmlhbCB9IGZyb20gJy4uL21hdGVyaWFscy9MaW5lQmFzaWNNYXRlcmlhbC5qcyc7XHJcbmltcG9ydCB7IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUgfSBmcm9tICcuLi9jb3JlL0J1ZmZlckF0dHJpYnV0ZS5qcyc7XHJcbmltcG9ydCB7IEJ1ZmZlckdlb21ldHJ5IH0gZnJvbSAnLi4vY29yZS9CdWZmZXJHZW9tZXRyeS5qcyc7XHJcbmltcG9ydCB7IENvbG9yIH0gZnJvbSAnLi4vbWF0aC9Db2xvci5qcyc7XHJcblxyXG5jbGFzcyBBeGVzSGVscGVyIGV4dGVuZHMgTGluZVNlZ21lbnRzIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIHNpemUgPSAxICkge1xyXG5cclxuXHRcdGNvbnN0IHZlcnRpY2VzID0gW1xyXG5cdFx0XHQwLCAwLCAwLFx0c2l6ZSwgMCwgMCxcclxuXHRcdFx0MCwgMCwgMCxcdDAsIHNpemUsIDAsXHJcblx0XHRcdDAsIDAsIDAsXHQwLCAwLCBzaXplXHJcblx0XHRdO1xyXG5cclxuXHRcdGNvbnN0IGNvbG9ycyA9IFtcclxuXHRcdFx0MSwgMCwgMCxcdDEsIDAuNiwgMCxcclxuXHRcdFx0MCwgMSwgMCxcdDAuNiwgMSwgMCxcclxuXHRcdFx0MCwgMCwgMSxcdDAsIDAuNiwgMVxyXG5cdFx0XTtcclxuXHJcblx0XHRjb25zdCBnZW9tZXRyeSA9IG5ldyBCdWZmZXJHZW9tZXRyeSgpO1xyXG5cdFx0Z2VvbWV0cnkuc2V0QXR0cmlidXRlKCAncG9zaXRpb24nLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggdmVydGljZXMsIDMgKSApO1xyXG5cdFx0Z2VvbWV0cnkuc2V0QXR0cmlidXRlKCAnY29sb3InLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggY29sb3JzLCAzICkgKTtcclxuXHJcblx0XHRjb25zdCBtYXRlcmlhbCA9IG5ldyBMaW5lQmFzaWNNYXRlcmlhbCggeyB2ZXJ0ZXhDb2xvcnM6IHRydWUsIHRvbmVNYXBwZWQ6IGZhbHNlIH0gKTtcclxuXHJcblx0XHRzdXBlciggZ2VvbWV0cnksIG1hdGVyaWFsICk7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ0F4ZXNIZWxwZXInO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldENvbG9ycyggeEF4aXNDb2xvciwgeUF4aXNDb2xvciwgekF4aXNDb2xvciApIHtcclxuXHJcblx0XHRjb25zdCBjb2xvciA9IG5ldyBDb2xvcigpO1xyXG5cdFx0Y29uc3QgYXJyYXkgPSB0aGlzLmdlb21ldHJ5LmF0dHJpYnV0ZXMuY29sb3IuYXJyYXk7XHJcblxyXG5cdFx0Y29sb3Iuc2V0KCB4QXhpc0NvbG9yICk7XHJcblx0XHRjb2xvci50b0FycmF5KCBhcnJheSwgMCApO1xyXG5cdFx0Y29sb3IudG9BcnJheSggYXJyYXksIDMgKTtcclxuXHJcblx0XHRjb2xvci5zZXQoIHlBeGlzQ29sb3IgKTtcclxuXHRcdGNvbG9yLnRvQXJyYXkoIGFycmF5LCA2ICk7XHJcblx0XHRjb2xvci50b0FycmF5KCBhcnJheSwgOSApO1xyXG5cclxuXHRcdGNvbG9yLnNldCggekF4aXNDb2xvciApO1xyXG5cdFx0Y29sb3IudG9BcnJheSggYXJyYXksIDEyICk7XHJcblx0XHRjb2xvci50b0FycmF5KCBhcnJheSwgMTUgKTtcclxuXHJcblx0XHR0aGlzLmdlb21ldHJ5LmF0dHJpYnV0ZXMuY29sb3IubmVlZHNVcGRhdGUgPSB0cnVlO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGRpc3Bvc2UoKSB7XHJcblxyXG5cdFx0dGhpcy5nZW9tZXRyeS5kaXNwb3NlKCk7XHJcblx0XHR0aGlzLm1hdGVyaWFsLmRpc3Bvc2UoKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuXHJcbmV4cG9ydCB7IEF4ZXNIZWxwZXIgfTtcclxuIiwiaW1wb3J0IHsgQ29sb3IgfSBmcm9tICcuLi8uLi9tYXRoL0NvbG9yLmpzJztcclxuaW1wb3J0IHsgUGF0aCB9IGZyb20gJy4vUGF0aC5qcyc7XHJcbmltcG9ydCB7IFNoYXBlIH0gZnJvbSAnLi9TaGFwZS5qcyc7XHJcbmltcG9ydCB7IFNoYXBlVXRpbHMgfSBmcm9tICcuLi9TaGFwZVV0aWxzLmpzJztcclxuXHJcbmNsYXNzIFNoYXBlUGF0aCB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCkge1xyXG5cclxuXHRcdHRoaXMudHlwZSA9ICdTaGFwZVBhdGgnO1xyXG5cclxuXHRcdHRoaXMuY29sb3IgPSBuZXcgQ29sb3IoKTtcclxuXHJcblx0XHR0aGlzLnN1YlBhdGhzID0gW107XHJcblx0XHR0aGlzLmN1cnJlbnRQYXRoID0gbnVsbDtcclxuXHJcblx0fVxyXG5cclxuXHRtb3ZlVG8oIHgsIHkgKSB7XHJcblxyXG5cdFx0dGhpcy5jdXJyZW50UGF0aCA9IG5ldyBQYXRoKCk7XHJcblx0XHR0aGlzLnN1YlBhdGhzLnB1c2goIHRoaXMuY3VycmVudFBhdGggKTtcclxuXHRcdHRoaXMuY3VycmVudFBhdGgubW92ZVRvKCB4LCB5ICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0bGluZVRvKCB4LCB5ICkge1xyXG5cclxuXHRcdHRoaXMuY3VycmVudFBhdGgubGluZVRvKCB4LCB5ICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0cXVhZHJhdGljQ3VydmVUbyggYUNQeCwgYUNQeSwgYVgsIGFZICkge1xyXG5cclxuXHRcdHRoaXMuY3VycmVudFBhdGgucXVhZHJhdGljQ3VydmVUbyggYUNQeCwgYUNQeSwgYVgsIGFZICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0YmV6aWVyQ3VydmVUbyggYUNQMXgsIGFDUDF5LCBhQ1AyeCwgYUNQMnksIGFYLCBhWSApIHtcclxuXHJcblx0XHR0aGlzLmN1cnJlbnRQYXRoLmJlemllckN1cnZlVG8oIGFDUDF4LCBhQ1AxeSwgYUNQMngsIGFDUDJ5LCBhWCwgYVkgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzcGxpbmVUaHJ1KCBwdHMgKSB7XHJcblxyXG5cdFx0dGhpcy5jdXJyZW50UGF0aC5zcGxpbmVUaHJ1KCBwdHMgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHR0b1NoYXBlcyggaXNDQ1cgKSB7XHJcblxyXG5cdFx0ZnVuY3Rpb24gdG9TaGFwZXNOb0hvbGVzKCBpblN1YnBhdGhzICkge1xyXG5cclxuXHRcdFx0Y29uc3Qgc2hhcGVzID0gW107XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBpblN1YnBhdGhzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IHRtcFBhdGggPSBpblN1YnBhdGhzWyBpIF07XHJcblxyXG5cdFx0XHRcdGNvbnN0IHRtcFNoYXBlID0gbmV3IFNoYXBlKCk7XHJcblx0XHRcdFx0dG1wU2hhcGUuY3VydmVzID0gdG1wUGF0aC5jdXJ2ZXM7XHJcblxyXG5cdFx0XHRcdHNoYXBlcy5wdXNoKCB0bXBTaGFwZSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0cmV0dXJuIHNoYXBlcztcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0ZnVuY3Rpb24gaXNQb2ludEluc2lkZVBvbHlnb24oIGluUHQsIGluUG9seWdvbiApIHtcclxuXHJcblx0XHRcdGNvbnN0IHBvbHlMZW4gPSBpblBvbHlnb24ubGVuZ3RoO1xyXG5cclxuXHRcdFx0Ly8gaW5QdCBvbiBwb2x5Z29uIGNvbnRvdXIgPT4gaW1tZWRpYXRlIHN1Y2Nlc3MgICAgb3JcclxuXHRcdFx0Ly8gdG9nZ2xpbmcgb2YgaW5zaWRlL291dHNpZGUgYXQgZXZlcnkgc2luZ2xlISBpbnRlcnNlY3Rpb24gcG9pbnQgb2YgYW4gZWRnZVxyXG5cdFx0XHQvLyAgd2l0aCB0aGUgaG9yaXpvbnRhbCBsaW5lIHRocm91Z2ggaW5QdCwgbGVmdCBvZiBpblB0XHJcblx0XHRcdC8vICBub3QgY291bnRpbmcgbG93ZXJZIGVuZHBvaW50cyBvZiBlZGdlcyBhbmQgd2hvbGUgZWRnZXMgb24gdGhhdCBsaW5lXHJcblx0XHRcdGxldCBpbnNpZGUgPSBmYWxzZTtcclxuXHRcdFx0Zm9yICggbGV0IHAgPSBwb2x5TGVuIC0gMSwgcSA9IDA7IHEgPCBwb2x5TGVuOyBwID0gcSArKyApIHtcclxuXHJcblx0XHRcdFx0bGV0IGVkZ2VMb3dQdCA9IGluUG9seWdvblsgcCBdO1xyXG5cdFx0XHRcdGxldCBlZGdlSGlnaFB0ID0gaW5Qb2x5Z29uWyBxIF07XHJcblxyXG5cdFx0XHRcdGxldCBlZGdlRHggPSBlZGdlSGlnaFB0LnggLSBlZGdlTG93UHQueDtcclxuXHRcdFx0XHRsZXQgZWRnZUR5ID0gZWRnZUhpZ2hQdC55IC0gZWRnZUxvd1B0Lnk7XHJcblxyXG5cdFx0XHRcdGlmICggTWF0aC5hYnMoIGVkZ2VEeSApID4gTnVtYmVyLkVQU0lMT04gKSB7XHJcblxyXG5cdFx0XHRcdFx0Ly8gbm90IHBhcmFsbGVsXHJcblx0XHRcdFx0XHRpZiAoIGVkZ2VEeSA8IDAgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRlZGdlTG93UHQgPSBpblBvbHlnb25bIHEgXTsgZWRnZUR4ID0gLSBlZGdlRHg7XHJcblx0XHRcdFx0XHRcdGVkZ2VIaWdoUHQgPSBpblBvbHlnb25bIHAgXTsgZWRnZUR5ID0gLSBlZGdlRHk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdGlmICggKCBpblB0LnkgPCBlZGdlTG93UHQueSApIHx8ICggaW5QdC55ID4gZWRnZUhpZ2hQdC55ICkgKSBcdFx0Y29udGludWU7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCBpblB0LnkgPT09IGVkZ2VMb3dQdC55ICkge1xyXG5cclxuXHRcdFx0XHRcdFx0aWYgKCBpblB0LnggPT09IGVkZ2VMb3dQdC54IClcdFx0cmV0dXJuXHR0cnVlO1x0XHQvLyBpblB0IGlzIG9uIGNvbnRvdXIgP1xyXG5cdFx0XHRcdFx0XHQvLyBjb250aW51ZTtcdFx0XHRcdC8vIG5vIGludGVyc2VjdGlvbiBvciBlZGdlTG93UHQgPT4gZG9lc24ndCBjb3VudCAhISFcclxuXHJcblx0XHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdFx0Y29uc3QgcGVycEVkZ2UgPSBlZGdlRHkgKiAoIGluUHQueCAtIGVkZ2VMb3dQdC54ICkgLSBlZGdlRHggKiAoIGluUHQueSAtIGVkZ2VMb3dQdC55ICk7XHJcblx0XHRcdFx0XHRcdGlmICggcGVycEVkZ2UgPT09IDAgKVx0XHRcdFx0cmV0dXJuXHR0cnVlO1x0XHQvLyBpblB0IGlzIG9uIGNvbnRvdXIgP1xyXG5cdFx0XHRcdFx0XHRpZiAoIHBlcnBFZGdlIDwgMCApIFx0XHRcdFx0Y29udGludWU7XHJcblx0XHRcdFx0XHRcdGluc2lkZSA9ICEgaW5zaWRlO1x0XHQvLyB0cnVlIGludGVyc2VjdGlvbiBsZWZ0IG9mIGluUHRcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0Ly8gcGFyYWxsZWwgb3IgY29sbGluZWFyXHJcblx0XHRcdFx0XHRpZiAoIGluUHQueSAhPT0gZWRnZUxvd1B0LnkgKSBcdFx0Y29udGludWU7XHRcdFx0Ly8gcGFyYWxsZWxcclxuXHRcdFx0XHRcdC8vIGVkZ2UgbGllcyBvbiB0aGUgc2FtZSBob3Jpem9udGFsIGxpbmUgYXMgaW5QdFxyXG5cdFx0XHRcdFx0aWYgKCAoICggZWRnZUhpZ2hQdC54IDw9IGluUHQueCApICYmICggaW5QdC54IDw9IGVkZ2VMb3dQdC54ICkgKSB8fFxyXG5cdFx0XHRcdFx0XHQgKCAoIGVkZ2VMb3dQdC54IDw9IGluUHQueCApICYmICggaW5QdC54IDw9IGVkZ2VIaWdoUHQueCApICkgKVx0XHRyZXR1cm5cdHRydWU7XHQvLyBpblB0OiBQb2ludCBvbiBjb250b3VyICFcclxuXHRcdFx0XHRcdC8vIGNvbnRpbnVlO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRyZXR1cm5cdGluc2lkZTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Y29uc3QgaXNDbG9ja1dpc2UgPSBTaGFwZVV0aWxzLmlzQ2xvY2tXaXNlO1xyXG5cclxuXHRcdGNvbnN0IHN1YlBhdGhzID0gdGhpcy5zdWJQYXRocztcclxuXHRcdGlmICggc3ViUGF0aHMubGVuZ3RoID09PSAwICkgcmV0dXJuIFtdO1xyXG5cclxuXHRcdGxldCBzb2xpZCwgdG1wUGF0aCwgdG1wU2hhcGU7XHJcblx0XHRjb25zdCBzaGFwZXMgPSBbXTtcclxuXHJcblx0XHRpZiAoIHN1YlBhdGhzLmxlbmd0aCA9PT0gMSApIHtcclxuXHJcblx0XHRcdHRtcFBhdGggPSBzdWJQYXRoc1sgMCBdO1xyXG5cdFx0XHR0bXBTaGFwZSA9IG5ldyBTaGFwZSgpO1xyXG5cdFx0XHR0bXBTaGFwZS5jdXJ2ZXMgPSB0bXBQYXRoLmN1cnZlcztcclxuXHRcdFx0c2hhcGVzLnB1c2goIHRtcFNoYXBlICk7XHJcblx0XHRcdHJldHVybiBzaGFwZXM7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGxldCBob2xlc0ZpcnN0ID0gISBpc0Nsb2NrV2lzZSggc3ViUGF0aHNbIDAgXS5nZXRQb2ludHMoKSApO1xyXG5cdFx0aG9sZXNGaXJzdCA9IGlzQ0NXID8gISBob2xlc0ZpcnN0IDogaG9sZXNGaXJzdDtcclxuXHJcblx0XHQvLyBjb25zb2xlLmxvZyhcIkhvbGVzIGZpcnN0XCIsIGhvbGVzRmlyc3QpO1xyXG5cclxuXHRcdGNvbnN0IGJldHRlclNoYXBlSG9sZXMgPSBbXTtcclxuXHRcdGNvbnN0IG5ld1NoYXBlcyA9IFtdO1xyXG5cdFx0bGV0IG5ld1NoYXBlSG9sZXMgPSBbXTtcclxuXHRcdGxldCBtYWluSWR4ID0gMDtcclxuXHRcdGxldCB0bXBQb2ludHM7XHJcblxyXG5cdFx0bmV3U2hhcGVzWyBtYWluSWR4IF0gPSB1bmRlZmluZWQ7XHJcblx0XHRuZXdTaGFwZUhvbGVzWyBtYWluSWR4IF0gPSBbXTtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBzdWJQYXRocy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0dG1wUGF0aCA9IHN1YlBhdGhzWyBpIF07XHJcblx0XHRcdHRtcFBvaW50cyA9IHRtcFBhdGguZ2V0UG9pbnRzKCk7XHJcblx0XHRcdHNvbGlkID0gaXNDbG9ja1dpc2UoIHRtcFBvaW50cyApO1xyXG5cdFx0XHRzb2xpZCA9IGlzQ0NXID8gISBzb2xpZCA6IHNvbGlkO1xyXG5cclxuXHRcdFx0aWYgKCBzb2xpZCApIHtcclxuXHJcblx0XHRcdFx0aWYgKCAoICEgaG9sZXNGaXJzdCApICYmICggbmV3U2hhcGVzWyBtYWluSWR4IF0gKSApXHRtYWluSWR4ICsrO1xyXG5cclxuXHRcdFx0XHRuZXdTaGFwZXNbIG1haW5JZHggXSA9IHsgczogbmV3IFNoYXBlKCksIHA6IHRtcFBvaW50cyB9O1xyXG5cdFx0XHRcdG5ld1NoYXBlc1sgbWFpbklkeCBdLnMuY3VydmVzID0gdG1wUGF0aC5jdXJ2ZXM7XHJcblxyXG5cdFx0XHRcdGlmICggaG9sZXNGaXJzdCApXHRtYWluSWR4ICsrO1xyXG5cdFx0XHRcdG5ld1NoYXBlSG9sZXNbIG1haW5JZHggXSA9IFtdO1xyXG5cclxuXHRcdFx0XHQvL2NvbnNvbGUubG9nKCdjdycsIGkpO1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0bmV3U2hhcGVIb2xlc1sgbWFpbklkeCBdLnB1c2goIHsgaDogdG1wUGF0aCwgcDogdG1wUG9pbnRzWyAwIF0gfSApO1xyXG5cclxuXHRcdFx0XHQvL2NvbnNvbGUubG9nKCdjY3cnLCBpKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gb25seSBIb2xlcz8gLT4gcHJvYmFibHkgYWxsIFNoYXBlcyB3aXRoIHdyb25nIG9yaWVudGF0aW9uXHJcblx0XHRpZiAoICEgbmV3U2hhcGVzWyAwIF0gKVx0cmV0dXJuXHR0b1NoYXBlc05vSG9sZXMoIHN1YlBhdGhzICk7XHJcblxyXG5cclxuXHRcdGlmICggbmV3U2hhcGVzLmxlbmd0aCA+IDEgKSB7XHJcblxyXG5cdFx0XHRsZXQgYW1iaWd1b3VzID0gZmFsc2U7XHJcblx0XHRcdGxldCB0b0NoYW5nZSA9IDA7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgc0lkeCA9IDAsIHNMZW4gPSBuZXdTaGFwZXMubGVuZ3RoOyBzSWR4IDwgc0xlbjsgc0lkeCArKyApIHtcclxuXHJcblx0XHRcdFx0YmV0dGVyU2hhcGVIb2xlc1sgc0lkeCBdID0gW107XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgc0lkeCA9IDAsIHNMZW4gPSBuZXdTaGFwZXMubGVuZ3RoOyBzSWR4IDwgc0xlbjsgc0lkeCArKyApIHtcclxuXHJcblx0XHRcdFx0Y29uc3Qgc2hvID0gbmV3U2hhcGVIb2xlc1sgc0lkeCBdO1xyXG5cclxuXHRcdFx0XHRmb3IgKCBsZXQgaElkeCA9IDA7IGhJZHggPCBzaG8ubGVuZ3RoOyBoSWR4ICsrICkge1xyXG5cclxuXHRcdFx0XHRcdGNvbnN0IGhvID0gc2hvWyBoSWR4IF07XHJcblx0XHRcdFx0XHRsZXQgaG9sZV91bmFzc2lnbmVkID0gdHJ1ZTtcclxuXHJcblx0XHRcdFx0XHRmb3IgKCBsZXQgczJJZHggPSAwOyBzMklkeCA8IG5ld1NoYXBlcy5sZW5ndGg7IHMySWR4ICsrICkge1xyXG5cclxuXHRcdFx0XHRcdFx0aWYgKCBpc1BvaW50SW5zaWRlUG9seWdvbiggaG8ucCwgbmV3U2hhcGVzWyBzMklkeCBdLnAgKSApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0aWYgKCBzSWR4ICE9PSBzMklkeCApXHR0b0NoYW5nZSArKztcclxuXHJcblx0XHRcdFx0XHRcdFx0aWYgKCBob2xlX3VuYXNzaWduZWQgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0aG9sZV91bmFzc2lnbmVkID0gZmFsc2U7XHJcblx0XHRcdFx0XHRcdFx0XHRiZXR0ZXJTaGFwZUhvbGVzWyBzMklkeCBdLnB1c2goIGhvICk7XHJcblxyXG5cdFx0XHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0YW1iaWd1b3VzID0gdHJ1ZTtcclxuXHJcblx0XHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRpZiAoIGhvbGVfdW5hc3NpZ25lZCApIHtcclxuXHJcblx0XHRcdFx0XHRcdGJldHRlclNoYXBlSG9sZXNbIHNJZHggXS5wdXNoKCBobyApO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0aWYgKCB0b0NoYW5nZSA+IDAgJiYgYW1iaWd1b3VzID09PSBmYWxzZSApIHtcclxuXHJcblx0XHRcdFx0bmV3U2hhcGVIb2xlcyA9IGJldHRlclNoYXBlSG9sZXM7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGxldCB0bXBIb2xlcztcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gbmV3U2hhcGVzLmxlbmd0aDsgaSA8IGlsOyBpICsrICkge1xyXG5cclxuXHRcdFx0dG1wU2hhcGUgPSBuZXdTaGFwZXNbIGkgXS5zO1xyXG5cdFx0XHRzaGFwZXMucHVzaCggdG1wU2hhcGUgKTtcclxuXHRcdFx0dG1wSG9sZXMgPSBuZXdTaGFwZUhvbGVzWyBpIF07XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaiA9IDAsIGpsID0gdG1wSG9sZXMubGVuZ3RoOyBqIDwgamw7IGogKysgKSB7XHJcblxyXG5cdFx0XHRcdHRtcFNoYXBlLmhvbGVzLnB1c2goIHRtcEhvbGVzWyBqIF0uaCApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvL2NvbnNvbGUubG9nKFwic2hhcGVcIiwgc2hhcGVzKTtcclxuXHJcblx0XHRyZXR1cm4gc2hhcGVzO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5cclxuZXhwb3J0IHsgU2hhcGVQYXRoIH07XHJcbiIsImltcG9ydCB7IFJFVklTSU9OIH0gZnJvbSAnLi9jb25zdGFudHMuanMnO1xyXG5cclxuZXhwb3J0IHsgV2ViR0xBcnJheVJlbmRlclRhcmdldCB9IGZyb20gJy4vcmVuZGVyZXJzL1dlYkdMQXJyYXlSZW5kZXJUYXJnZXQuanMnO1xyXG5leHBvcnQgeyBXZWJHTDNEUmVuZGVyVGFyZ2V0IH0gZnJvbSAnLi9yZW5kZXJlcnMvV2ViR0wzRFJlbmRlclRhcmdldC5qcyc7XHJcbmV4cG9ydCB7IFdlYkdMTXVsdGlwbGVSZW5kZXJUYXJnZXRzIH0gZnJvbSAnLi9yZW5kZXJlcnMvV2ViR0xNdWx0aXBsZVJlbmRlclRhcmdldHMuanMnO1xyXG5leHBvcnQgeyBXZWJHTEN1YmVSZW5kZXJUYXJnZXQgfSBmcm9tICcuL3JlbmRlcmVycy9XZWJHTEN1YmVSZW5kZXJUYXJnZXQuanMnO1xyXG5leHBvcnQgeyBXZWJHTFJlbmRlclRhcmdldCB9IGZyb20gJy4vcmVuZGVyZXJzL1dlYkdMUmVuZGVyVGFyZ2V0LmpzJztcclxuZXhwb3J0IHsgV2ViR0xSZW5kZXJlciB9IGZyb20gJy4vcmVuZGVyZXJzL1dlYkdMUmVuZGVyZXIuanMnO1xyXG5leHBvcnQgeyBXZWJHTDFSZW5kZXJlciB9IGZyb20gJy4vcmVuZGVyZXJzL1dlYkdMMVJlbmRlcmVyLmpzJztcclxuZXhwb3J0IHsgU2hhZGVyTGliIH0gZnJvbSAnLi9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJMaWIuanMnO1xyXG5leHBvcnQgeyBVbmlmb3Jtc0xpYiB9IGZyb20gJy4vcmVuZGVyZXJzL3NoYWRlcnMvVW5pZm9ybXNMaWIuanMnO1xyXG5leHBvcnQgeyBVbmlmb3Jtc1V0aWxzIH0gZnJvbSAnLi9yZW5kZXJlcnMvc2hhZGVycy9Vbmlmb3Jtc1V0aWxzLmpzJztcclxuZXhwb3J0IHsgU2hhZGVyQ2h1bmsgfSBmcm9tICcuL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rLmpzJztcclxuZXhwb3J0IHsgRm9nRXhwMiB9IGZyb20gJy4vc2NlbmVzL0ZvZ0V4cDIuanMnO1xyXG5leHBvcnQgeyBGb2cgfSBmcm9tICcuL3NjZW5lcy9Gb2cuanMnO1xyXG5leHBvcnQgeyBTY2VuZSB9IGZyb20gJy4vc2NlbmVzL1NjZW5lLmpzJztcclxuZXhwb3J0IHsgU3ByaXRlIH0gZnJvbSAnLi9vYmplY3RzL1Nwcml0ZS5qcyc7XHJcbmV4cG9ydCB7IExPRCB9IGZyb20gJy4vb2JqZWN0cy9MT0QuanMnO1xyXG5leHBvcnQgeyBTa2lubmVkTWVzaCB9IGZyb20gJy4vb2JqZWN0cy9Ta2lubmVkTWVzaC5qcyc7XHJcbmV4cG9ydCB7IFNrZWxldG9uIH0gZnJvbSAnLi9vYmplY3RzL1NrZWxldG9uLmpzJztcclxuZXhwb3J0IHsgQm9uZSB9IGZyb20gJy4vb2JqZWN0cy9Cb25lLmpzJztcclxuZXhwb3J0IHsgTWVzaCB9IGZyb20gJy4vb2JqZWN0cy9NZXNoLmpzJztcclxuZXhwb3J0IHsgSW5zdGFuY2VkTWVzaCB9IGZyb20gJy4vb2JqZWN0cy9JbnN0YW5jZWRNZXNoLmpzJztcclxuZXhwb3J0IHsgQmF0Y2hlZE1lc2ggfSBmcm9tICcuL29iamVjdHMvQmF0Y2hlZE1lc2guanMnO1xyXG5leHBvcnQgeyBMaW5lU2VnbWVudHMgfSBmcm9tICcuL29iamVjdHMvTGluZVNlZ21lbnRzLmpzJztcclxuZXhwb3J0IHsgTGluZUxvb3AgfSBmcm9tICcuL29iamVjdHMvTGluZUxvb3AuanMnO1xyXG5leHBvcnQgeyBMaW5lIH0gZnJvbSAnLi9vYmplY3RzL0xpbmUuanMnO1xyXG5leHBvcnQgeyBQb2ludHMgfSBmcm9tICcuL29iamVjdHMvUG9pbnRzLmpzJztcclxuZXhwb3J0IHsgR3JvdXAgfSBmcm9tICcuL29iamVjdHMvR3JvdXAuanMnO1xyXG5leHBvcnQgeyBWaWRlb1RleHR1cmUgfSBmcm9tICcuL3RleHR1cmVzL1ZpZGVvVGV4dHVyZS5qcyc7XHJcbmV4cG9ydCB7IEZyYW1lYnVmZmVyVGV4dHVyZSB9IGZyb20gJy4vdGV4dHVyZXMvRnJhbWVidWZmZXJUZXh0dXJlLmpzJztcclxuZXhwb3J0IHsgU291cmNlIH0gZnJvbSAnLi90ZXh0dXJlcy9Tb3VyY2UuanMnO1xyXG5leHBvcnQgeyBEYXRhVGV4dHVyZSB9IGZyb20gJy4vdGV4dHVyZXMvRGF0YVRleHR1cmUuanMnO1xyXG5leHBvcnQgeyBEYXRhQXJyYXlUZXh0dXJlIH0gZnJvbSAnLi90ZXh0dXJlcy9EYXRhQXJyYXlUZXh0dXJlLmpzJztcclxuZXhwb3J0IHsgRGF0YTNEVGV4dHVyZSB9IGZyb20gJy4vdGV4dHVyZXMvRGF0YTNEVGV4dHVyZS5qcyc7XHJcbmV4cG9ydCB7IENvbXByZXNzZWRUZXh0dXJlIH0gZnJvbSAnLi90ZXh0dXJlcy9Db21wcmVzc2VkVGV4dHVyZS5qcyc7XHJcbmV4cG9ydCB7IENvbXByZXNzZWRBcnJheVRleHR1cmUgfSBmcm9tICcuL3RleHR1cmVzL0NvbXByZXNzZWRBcnJheVRleHR1cmUuanMnO1xyXG5leHBvcnQgeyBDb21wcmVzc2VkQ3ViZVRleHR1cmUgfSBmcm9tICcuL3RleHR1cmVzL0NvbXByZXNzZWRDdWJlVGV4dHVyZS5qcyc7XHJcbmV4cG9ydCB7IEN1YmVUZXh0dXJlIH0gZnJvbSAnLi90ZXh0dXJlcy9DdWJlVGV4dHVyZS5qcyc7XHJcbmV4cG9ydCB7IENhbnZhc1RleHR1cmUgfSBmcm9tICcuL3RleHR1cmVzL0NhbnZhc1RleHR1cmUuanMnO1xyXG5leHBvcnQgeyBEZXB0aFRleHR1cmUgfSBmcm9tICcuL3RleHR1cmVzL0RlcHRoVGV4dHVyZS5qcyc7XHJcbmV4cG9ydCB7IFRleHR1cmUgfSBmcm9tICcuL3RleHR1cmVzL1RleHR1cmUuanMnO1xyXG5leHBvcnQgKiBmcm9tICcuL2dlb21ldHJpZXMvR2VvbWV0cmllcy5qcyc7XHJcbmV4cG9ydCAqIGZyb20gJy4vbWF0ZXJpYWxzL01hdGVyaWFscy5qcyc7XHJcbmV4cG9ydCB7IEFuaW1hdGlvbkxvYWRlciB9IGZyb20gJy4vbG9hZGVycy9BbmltYXRpb25Mb2FkZXIuanMnO1xyXG5leHBvcnQgeyBDb21wcmVzc2VkVGV4dHVyZUxvYWRlciB9IGZyb20gJy4vbG9hZGVycy9Db21wcmVzc2VkVGV4dHVyZUxvYWRlci5qcyc7XHJcbmV4cG9ydCB7IEN1YmVUZXh0dXJlTG9hZGVyIH0gZnJvbSAnLi9sb2FkZXJzL0N1YmVUZXh0dXJlTG9hZGVyLmpzJztcclxuZXhwb3J0IHsgRGF0YVRleHR1cmVMb2FkZXIgfSBmcm9tICcuL2xvYWRlcnMvRGF0YVRleHR1cmVMb2FkZXIuanMnO1xyXG5leHBvcnQgeyBUZXh0dXJlTG9hZGVyIH0gZnJvbSAnLi9sb2FkZXJzL1RleHR1cmVMb2FkZXIuanMnO1xyXG5leHBvcnQgeyBPYmplY3RMb2FkZXIgfSBmcm9tICcuL2xvYWRlcnMvT2JqZWN0TG9hZGVyLmpzJztcclxuZXhwb3J0IHsgTWF0ZXJpYWxMb2FkZXIgfSBmcm9tICcuL2xvYWRlcnMvTWF0ZXJpYWxMb2FkZXIuanMnO1xyXG5leHBvcnQgeyBCdWZmZXJHZW9tZXRyeUxvYWRlciB9IGZyb20gJy4vbG9hZGVycy9CdWZmZXJHZW9tZXRyeUxvYWRlci5qcyc7XHJcbmV4cG9ydCB7IERlZmF1bHRMb2FkaW5nTWFuYWdlciwgTG9hZGluZ01hbmFnZXIgfSBmcm9tICcuL2xvYWRlcnMvTG9hZGluZ01hbmFnZXIuanMnO1xyXG5leHBvcnQgeyBJbWFnZUxvYWRlciB9IGZyb20gJy4vbG9hZGVycy9JbWFnZUxvYWRlci5qcyc7XHJcbmV4cG9ydCB7IEltYWdlQml0bWFwTG9hZGVyIH0gZnJvbSAnLi9sb2FkZXJzL0ltYWdlQml0bWFwTG9hZGVyLmpzJztcclxuZXhwb3J0IHsgRmlsZUxvYWRlciB9IGZyb20gJy4vbG9hZGVycy9GaWxlTG9hZGVyLmpzJztcclxuZXhwb3J0IHsgTG9hZGVyIH0gZnJvbSAnLi9sb2FkZXJzL0xvYWRlci5qcyc7XHJcbmV4cG9ydCB7IExvYWRlclV0aWxzIH0gZnJvbSAnLi9sb2FkZXJzL0xvYWRlclV0aWxzLmpzJztcclxuZXhwb3J0IHsgQ2FjaGUgfSBmcm9tICcuL2xvYWRlcnMvQ2FjaGUuanMnO1xyXG5leHBvcnQgeyBBdWRpb0xvYWRlciB9IGZyb20gJy4vbG9hZGVycy9BdWRpb0xvYWRlci5qcyc7XHJcbmV4cG9ydCB7IFNwb3RMaWdodCB9IGZyb20gJy4vbGlnaHRzL1Nwb3RMaWdodC5qcyc7XHJcbmV4cG9ydCB7IFBvaW50TGlnaHQgfSBmcm9tICcuL2xpZ2h0cy9Qb2ludExpZ2h0LmpzJztcclxuZXhwb3J0IHsgUmVjdEFyZWFMaWdodCB9IGZyb20gJy4vbGlnaHRzL1JlY3RBcmVhTGlnaHQuanMnO1xyXG5leHBvcnQgeyBIZW1pc3BoZXJlTGlnaHQgfSBmcm9tICcuL2xpZ2h0cy9IZW1pc3BoZXJlTGlnaHQuanMnO1xyXG5leHBvcnQgeyBEaXJlY3Rpb25hbExpZ2h0IH0gZnJvbSAnLi9saWdodHMvRGlyZWN0aW9uYWxMaWdodC5qcyc7XHJcbmV4cG9ydCB7IEFtYmllbnRMaWdodCB9IGZyb20gJy4vbGlnaHRzL0FtYmllbnRMaWdodC5qcyc7XHJcbmV4cG9ydCB7IExpZ2h0IH0gZnJvbSAnLi9saWdodHMvTGlnaHQuanMnO1xyXG5leHBvcnQgeyBMaWdodFByb2JlIH0gZnJvbSAnLi9saWdodHMvTGlnaHRQcm9iZS5qcyc7XHJcbmV4cG9ydCB7IFN0ZXJlb0NhbWVyYSB9IGZyb20gJy4vY2FtZXJhcy9TdGVyZW9DYW1lcmEuanMnO1xyXG5leHBvcnQgeyBQZXJzcGVjdGl2ZUNhbWVyYSB9IGZyb20gJy4vY2FtZXJhcy9QZXJzcGVjdGl2ZUNhbWVyYS5qcyc7XHJcbmV4cG9ydCB7IE9ydGhvZ3JhcGhpY0NhbWVyYSB9IGZyb20gJy4vY2FtZXJhcy9PcnRob2dyYXBoaWNDYW1lcmEuanMnO1xyXG5leHBvcnQgeyBDdWJlQ2FtZXJhIH0gZnJvbSAnLi9jYW1lcmFzL0N1YmVDYW1lcmEuanMnO1xyXG5leHBvcnQgeyBBcnJheUNhbWVyYSB9IGZyb20gJy4vY2FtZXJhcy9BcnJheUNhbWVyYS5qcyc7XHJcbmV4cG9ydCB7IENhbWVyYSB9IGZyb20gJy4vY2FtZXJhcy9DYW1lcmEuanMnO1xyXG5leHBvcnQgeyBBdWRpb0xpc3RlbmVyIH0gZnJvbSAnLi9hdWRpby9BdWRpb0xpc3RlbmVyLmpzJztcclxuZXhwb3J0IHsgUG9zaXRpb25hbEF1ZGlvIH0gZnJvbSAnLi9hdWRpby9Qb3NpdGlvbmFsQXVkaW8uanMnO1xyXG5leHBvcnQgeyBBdWRpb0NvbnRleHQgfSBmcm9tICcuL2F1ZGlvL0F1ZGlvQ29udGV4dC5qcyc7XHJcbmV4cG9ydCB7IEF1ZGlvQW5hbHlzZXIgfSBmcm9tICcuL2F1ZGlvL0F1ZGlvQW5hbHlzZXIuanMnO1xyXG5leHBvcnQgeyBBdWRpbyB9IGZyb20gJy4vYXVkaW8vQXVkaW8uanMnO1xyXG5leHBvcnQgeyBWZWN0b3JLZXlmcmFtZVRyYWNrIH0gZnJvbSAnLi9hbmltYXRpb24vdHJhY2tzL1ZlY3RvcktleWZyYW1lVHJhY2suanMnO1xyXG5leHBvcnQgeyBTdHJpbmdLZXlmcmFtZVRyYWNrIH0gZnJvbSAnLi9hbmltYXRpb24vdHJhY2tzL1N0cmluZ0tleWZyYW1lVHJhY2suanMnO1xyXG5leHBvcnQgeyBRdWF0ZXJuaW9uS2V5ZnJhbWVUcmFjayB9IGZyb20gJy4vYW5pbWF0aW9uL3RyYWNrcy9RdWF0ZXJuaW9uS2V5ZnJhbWVUcmFjay5qcyc7XHJcbmV4cG9ydCB7IE51bWJlcktleWZyYW1lVHJhY2sgfSBmcm9tICcuL2FuaW1hdGlvbi90cmFja3MvTnVtYmVyS2V5ZnJhbWVUcmFjay5qcyc7XHJcbmV4cG9ydCB7IENvbG9yS2V5ZnJhbWVUcmFjayB9IGZyb20gJy4vYW5pbWF0aW9uL3RyYWNrcy9Db2xvcktleWZyYW1lVHJhY2suanMnO1xyXG5leHBvcnQgeyBCb29sZWFuS2V5ZnJhbWVUcmFjayB9IGZyb20gJy4vYW5pbWF0aW9uL3RyYWNrcy9Cb29sZWFuS2V5ZnJhbWVUcmFjay5qcyc7XHJcbmV4cG9ydCB7IFByb3BlcnR5TWl4ZXIgfSBmcm9tICcuL2FuaW1hdGlvbi9Qcm9wZXJ0eU1peGVyLmpzJztcclxuZXhwb3J0IHsgUHJvcGVydHlCaW5kaW5nIH0gZnJvbSAnLi9hbmltYXRpb24vUHJvcGVydHlCaW5kaW5nLmpzJztcclxuZXhwb3J0IHsgS2V5ZnJhbWVUcmFjayB9IGZyb20gJy4vYW5pbWF0aW9uL0tleWZyYW1lVHJhY2suanMnO1xyXG5leHBvcnQgeyBBbmltYXRpb25VdGlscyB9IGZyb20gJy4vYW5pbWF0aW9uL0FuaW1hdGlvblV0aWxzLmpzJztcclxuZXhwb3J0IHsgQW5pbWF0aW9uT2JqZWN0R3JvdXAgfSBmcm9tICcuL2FuaW1hdGlvbi9BbmltYXRpb25PYmplY3RHcm91cC5qcyc7XHJcbmV4cG9ydCB7IEFuaW1hdGlvbk1peGVyIH0gZnJvbSAnLi9hbmltYXRpb24vQW5pbWF0aW9uTWl4ZXIuanMnO1xyXG5leHBvcnQgeyBBbmltYXRpb25DbGlwIH0gZnJvbSAnLi9hbmltYXRpb24vQW5pbWF0aW9uQ2xpcC5qcyc7XHJcbmV4cG9ydCB7IEFuaW1hdGlvbkFjdGlvbiB9IGZyb20gJy4vYW5pbWF0aW9uL0FuaW1hdGlvbkFjdGlvbi5qcyc7XHJcbmV4cG9ydCB7IFJlbmRlclRhcmdldCB9IGZyb20gJy4vY29yZS9SZW5kZXJUYXJnZXQuanMnO1xyXG5leHBvcnQgeyBVbmlmb3JtIH0gZnJvbSAnLi9jb3JlL1VuaWZvcm0uanMnO1xyXG5leHBvcnQgeyBVbmlmb3Jtc0dyb3VwIH0gZnJvbSAnLi9jb3JlL1VuaWZvcm1zR3JvdXAuanMnO1xyXG5leHBvcnQgeyBJbnN0YW5jZWRCdWZmZXJHZW9tZXRyeSB9IGZyb20gJy4vY29yZS9JbnN0YW5jZWRCdWZmZXJHZW9tZXRyeS5qcyc7XHJcbmV4cG9ydCB7IEJ1ZmZlckdlb21ldHJ5IH0gZnJvbSAnLi9jb3JlL0J1ZmZlckdlb21ldHJ5LmpzJztcclxuZXhwb3J0IHsgSW50ZXJsZWF2ZWRCdWZmZXJBdHRyaWJ1dGUgfSBmcm9tICcuL2NvcmUvSW50ZXJsZWF2ZWRCdWZmZXJBdHRyaWJ1dGUuanMnO1xyXG5leHBvcnQgeyBJbnN0YW5jZWRJbnRlcmxlYXZlZEJ1ZmZlciB9IGZyb20gJy4vY29yZS9JbnN0YW5jZWRJbnRlcmxlYXZlZEJ1ZmZlci5qcyc7XHJcbmV4cG9ydCB7IEludGVybGVhdmVkQnVmZmVyIH0gZnJvbSAnLi9jb3JlL0ludGVybGVhdmVkQnVmZmVyLmpzJztcclxuZXhwb3J0IHsgSW5zdGFuY2VkQnVmZmVyQXR0cmlidXRlIH0gZnJvbSAnLi9jb3JlL0luc3RhbmNlZEJ1ZmZlckF0dHJpYnV0ZS5qcyc7XHJcbmV4cG9ydCB7IEdMQnVmZmVyQXR0cmlidXRlIH0gZnJvbSAnLi9jb3JlL0dMQnVmZmVyQXR0cmlidXRlLmpzJztcclxuZXhwb3J0ICogZnJvbSAnLi9jb3JlL0J1ZmZlckF0dHJpYnV0ZS5qcyc7XHJcbmV4cG9ydCB7IE9iamVjdDNEIH0gZnJvbSAnLi9jb3JlL09iamVjdDNELmpzJztcclxuZXhwb3J0IHsgUmF5Y2FzdGVyIH0gZnJvbSAnLi9jb3JlL1JheWNhc3Rlci5qcyc7XHJcbmV4cG9ydCB7IExheWVycyB9IGZyb20gJy4vY29yZS9MYXllcnMuanMnO1xyXG5leHBvcnQgeyBFdmVudERpc3BhdGNoZXIgfSBmcm9tICcuL2NvcmUvRXZlbnREaXNwYXRjaGVyLmpzJztcclxuZXhwb3J0IHsgQ2xvY2sgfSBmcm9tICcuL2NvcmUvQ2xvY2suanMnO1xyXG5leHBvcnQgeyBRdWF0ZXJuaW9uTGluZWFySW50ZXJwb2xhbnQgfSBmcm9tICcuL21hdGgvaW50ZXJwb2xhbnRzL1F1YXRlcm5pb25MaW5lYXJJbnRlcnBvbGFudC5qcyc7XHJcbmV4cG9ydCB7IExpbmVhckludGVycG9sYW50IH0gZnJvbSAnLi9tYXRoL2ludGVycG9sYW50cy9MaW5lYXJJbnRlcnBvbGFudC5qcyc7XHJcbmV4cG9ydCB7IERpc2NyZXRlSW50ZXJwb2xhbnQgfSBmcm9tICcuL21hdGgvaW50ZXJwb2xhbnRzL0Rpc2NyZXRlSW50ZXJwb2xhbnQuanMnO1xyXG5leHBvcnQgeyBDdWJpY0ludGVycG9sYW50IH0gZnJvbSAnLi9tYXRoL2ludGVycG9sYW50cy9DdWJpY0ludGVycG9sYW50LmpzJztcclxuZXhwb3J0IHsgSW50ZXJwb2xhbnQgfSBmcm9tICcuL21hdGgvSW50ZXJwb2xhbnQuanMnO1xyXG5leHBvcnQgeyBUcmlhbmdsZSB9IGZyb20gJy4vbWF0aC9UcmlhbmdsZS5qcyc7XHJcbmV4cG9ydCB7IE1hdGhVdGlscyB9IGZyb20gJy4vbWF0aC9NYXRoVXRpbHMuanMnO1xyXG5leHBvcnQgeyBTcGhlcmljYWwgfSBmcm9tICcuL21hdGgvU3BoZXJpY2FsLmpzJztcclxuZXhwb3J0IHsgQ3lsaW5kcmljYWwgfSBmcm9tICcuL21hdGgvQ3lsaW5kcmljYWwuanMnO1xyXG5leHBvcnQgeyBQbGFuZSB9IGZyb20gJy4vbWF0aC9QbGFuZS5qcyc7XHJcbmV4cG9ydCB7IEZydXN0dW0gfSBmcm9tICcuL21hdGgvRnJ1c3R1bS5qcyc7XHJcbmV4cG9ydCB7IFNwaGVyZSB9IGZyb20gJy4vbWF0aC9TcGhlcmUuanMnO1xyXG5leHBvcnQgeyBSYXkgfSBmcm9tICcuL21hdGgvUmF5LmpzJztcclxuZXhwb3J0IHsgTWF0cml4NCB9IGZyb20gJy4vbWF0aC9NYXRyaXg0LmpzJztcclxuZXhwb3J0IHsgTWF0cml4MyB9IGZyb20gJy4vbWF0aC9NYXRyaXgzLmpzJztcclxuZXhwb3J0IHsgQm94MyB9IGZyb20gJy4vbWF0aC9Cb3gzLmpzJztcclxuZXhwb3J0IHsgQm94MiB9IGZyb20gJy4vbWF0aC9Cb3gyLmpzJztcclxuZXhwb3J0IHsgTGluZTMgfSBmcm9tICcuL21hdGgvTGluZTMuanMnO1xyXG5leHBvcnQgeyBFdWxlciB9IGZyb20gJy4vbWF0aC9FdWxlci5qcyc7XHJcbmV4cG9ydCB7IFZlY3RvcjQgfSBmcm9tICcuL21hdGgvVmVjdG9yNC5qcyc7XHJcbmV4cG9ydCB7IFZlY3RvcjMgfSBmcm9tICcuL21hdGgvVmVjdG9yMy5qcyc7XHJcbmV4cG9ydCB7IFZlY3RvcjIgfSBmcm9tICcuL21hdGgvVmVjdG9yMi5qcyc7XHJcbmV4cG9ydCB7IFF1YXRlcm5pb24gfSBmcm9tICcuL21hdGgvUXVhdGVybmlvbi5qcyc7XHJcbmV4cG9ydCB7IENvbG9yIH0gZnJvbSAnLi9tYXRoL0NvbG9yLmpzJztcclxuZXhwb3J0IHsgQ29sb3JNYW5hZ2VtZW50IH0gZnJvbSAnLi9tYXRoL0NvbG9yTWFuYWdlbWVudC5qcyc7XHJcbmV4cG9ydCB7IFNwaGVyaWNhbEhhcm1vbmljczMgfSBmcm9tICcuL21hdGgvU3BoZXJpY2FsSGFybW9uaWNzMy5qcyc7XHJcbmV4cG9ydCB7IFNwb3RMaWdodEhlbHBlciB9IGZyb20gJy4vaGVscGVycy9TcG90TGlnaHRIZWxwZXIuanMnO1xyXG5leHBvcnQgeyBTa2VsZXRvbkhlbHBlciB9IGZyb20gJy4vaGVscGVycy9Ta2VsZXRvbkhlbHBlci5qcyc7XHJcbmV4cG9ydCB7IFBvaW50TGlnaHRIZWxwZXIgfSBmcm9tICcuL2hlbHBlcnMvUG9pbnRMaWdodEhlbHBlci5qcyc7XHJcbmV4cG9ydCB7IEhlbWlzcGhlcmVMaWdodEhlbHBlciB9IGZyb20gJy4vaGVscGVycy9IZW1pc3BoZXJlTGlnaHRIZWxwZXIuanMnO1xyXG5leHBvcnQgeyBHcmlkSGVscGVyIH0gZnJvbSAnLi9oZWxwZXJzL0dyaWRIZWxwZXIuanMnO1xyXG5leHBvcnQgeyBQb2xhckdyaWRIZWxwZXIgfSBmcm9tICcuL2hlbHBlcnMvUG9sYXJHcmlkSGVscGVyLmpzJztcclxuZXhwb3J0IHsgRGlyZWN0aW9uYWxMaWdodEhlbHBlciB9IGZyb20gJy4vaGVscGVycy9EaXJlY3Rpb25hbExpZ2h0SGVscGVyLmpzJztcclxuZXhwb3J0IHsgQ2FtZXJhSGVscGVyIH0gZnJvbSAnLi9oZWxwZXJzL0NhbWVyYUhlbHBlci5qcyc7XHJcbmV4cG9ydCB7IEJveEhlbHBlciB9IGZyb20gJy4vaGVscGVycy9Cb3hIZWxwZXIuanMnO1xyXG5leHBvcnQgeyBCb3gzSGVscGVyIH0gZnJvbSAnLi9oZWxwZXJzL0JveDNIZWxwZXIuanMnO1xyXG5leHBvcnQgeyBQbGFuZUhlbHBlciB9IGZyb20gJy4vaGVscGVycy9QbGFuZUhlbHBlci5qcyc7XHJcbmV4cG9ydCB7IEFycm93SGVscGVyIH0gZnJvbSAnLi9oZWxwZXJzL0Fycm93SGVscGVyLmpzJztcclxuZXhwb3J0IHsgQXhlc0hlbHBlciB9IGZyb20gJy4vaGVscGVycy9BeGVzSGVscGVyLmpzJztcclxuZXhwb3J0ICogZnJvbSAnLi9leHRyYXMvY3VydmVzL0N1cnZlcy5qcyc7XHJcbmV4cG9ydCB7IFNoYXBlIH0gZnJvbSAnLi9leHRyYXMvY29yZS9TaGFwZS5qcyc7XHJcbmV4cG9ydCB7IFBhdGggfSBmcm9tICcuL2V4dHJhcy9jb3JlL1BhdGguanMnO1xyXG5leHBvcnQgeyBTaGFwZVBhdGggfSBmcm9tICcuL2V4dHJhcy9jb3JlL1NoYXBlUGF0aC5qcyc7XHJcbmV4cG9ydCB7IEN1cnZlUGF0aCB9IGZyb20gJy4vZXh0cmFzL2NvcmUvQ3VydmVQYXRoLmpzJztcclxuZXhwb3J0IHsgQ3VydmUgfSBmcm9tICcuL2V4dHJhcy9jb3JlL0N1cnZlLmpzJztcclxuZXhwb3J0IHsgRGF0YVV0aWxzIH0gZnJvbSAnLi9leHRyYXMvRGF0YVV0aWxzLmpzJztcclxuZXhwb3J0IHsgSW1hZ2VVdGlscyB9IGZyb20gJy4vZXh0cmFzL0ltYWdlVXRpbHMuanMnO1xyXG5leHBvcnQgeyBTaGFwZVV0aWxzIH0gZnJvbSAnLi9leHRyYXMvU2hhcGVVdGlscy5qcyc7XHJcbmV4cG9ydCB7IFBNUkVNR2VuZXJhdG9yIH0gZnJvbSAnLi9leHRyYXMvUE1SRU1HZW5lcmF0b3IuanMnO1xyXG5leHBvcnQgeyBXZWJHTFV0aWxzIH0gZnJvbSAnLi9yZW5kZXJlcnMvd2ViZ2wvV2ViR0xVdGlscy5qcyc7XHJcbmV4cG9ydCB7IGNyZWF0ZUNhbnZhc0VsZW1lbnQgfSBmcm9tICcuL3V0aWxzLmpzJztcclxuZXhwb3J0ICogZnJvbSAnLi9jb25zdGFudHMuanMnO1xyXG5leHBvcnQgKiBmcm9tICcuL1RocmVlLkxlZ2FjeS5qcyc7XHJcblxyXG5pZiAoIHR5cGVvZiBfX1RIUkVFX0RFVlRPT0xTX18gIT09ICd1bmRlZmluZWQnICkge1xyXG5cclxuXHRfX1RIUkVFX0RFVlRPT0xTX18uZGlzcGF0Y2hFdmVudCggbmV3IEN1c3RvbUV2ZW50KCAncmVnaXN0ZXInLCB7IGRldGFpbDoge1xyXG5cdFx0cmV2aXNpb246IFJFVklTSU9OLFxyXG5cdH0gfSApICk7XHJcblxyXG59XHJcblxyXG5pZiAoIHR5cGVvZiB3aW5kb3cgIT09ICd1bmRlZmluZWQnICkge1xyXG5cclxuXHRpZiAoIHdpbmRvdy5fX1RIUkVFX18gKSB7XHJcblxyXG5cdFx0Y29uc29sZS53YXJuKCAnV0FSTklORzogTXVsdGlwbGUgaW5zdGFuY2VzIG9mIFRocmVlLmpzIGJlaW5nIGltcG9ydGVkLicgKTtcclxuXHJcblx0fSBlbHNlIHtcclxuXHJcblx0XHR3aW5kb3cuX19USFJFRV9fID0gUkVWSVNJT047XHJcblxyXG5cdH1cclxuXHJcbn1cclxuIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7QUFBWTtBQUNaO0FBQ1k7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNaO0FBQ1k7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNaO0FBQ1k7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNaO0FBQ0E7QUFDWTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ1o7QUFDWTtBQUNBO0FBQ1o7QUFDWTtBQUNBO0FBQ1o7QUFDWTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ1o7QUFDWTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ1o7QUFDWTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ1o7QUFDWTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDWjtBQUNZO0FBQ0E7QUFDWjtBQUNZO0FBQ1o7QUFDWTtBQUNBOztBQ25OWjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbkZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNVVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDN2RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaldBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNyRkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ1k7QUFDWjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNPO0FBQ1A7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNPO0FBQ1A7QUFDQTtBQUNBO0FBQ0E7O0FDdklBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzNIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNUdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNuVEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzNuQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ1RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDN0JBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDakJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM3RUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3ZxQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvc0JBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaGhCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaFBBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2ZUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNTRCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeFRBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMytCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNoVEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2bUJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbmdCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDSztBQUNMO0FBQ0E7QUFDQTs7QUNsS0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzdtQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3ppQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcmFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvS0E7QUFDQTtBQUNBO0FBQ0E7QUFDTztBQUNQO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNPO0FBQ1A7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDTztBQUNQO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ087QUFDUDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0s7O0FDckdMOztBQ0FBOztBQ01BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RMQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDN0RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNyUUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2S0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDckJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1SUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNyTUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdExBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNsREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDOU5BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvRkE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7O0FDQUE7QUFZQTtBQUNBOztBQ2JBO0FBZ0JBO0FBQ0E7O0FDakJBO0FBZ0JBO0FBQ0E7O0FDakJBO0FBMENBO0FBQ0E7O0FDM0NBO0FBd0NBO0FBQ0E7O0FDekNBO0FBY0E7QUFDQTs7QUNmQTtBQThCQTtBQUNBOztBQy9CQTtBQTBDQTtBQUNBOztBQzNDQTtBQWtEQTtBQUNBOztBQ25EQTtBQThDQTtBQUNBOztBQy9DQTtBQStDQTtBQUNBOztBQ2hEQTtBQWtEQTtBQUNBOztBQ25EQTtBQTJEQTtBQUNBOztBQzVEQTtBQWdEQTtBQUNBOztBQ2pEQTtBQWlEQTtBQUNBOztBQ2xEQTtBQStCQTtBQUNBOztBQ2hDQTtBQTRDQTtBQUNBOztBQ2lGWTtBQUNaO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDelFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0s7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM05LO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6VkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDek9BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbm5CQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDakhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwS0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDOUZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1R0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3A0QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvSEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMUZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQy9NQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbEdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDOURBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hTQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3ZEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQU9BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pvQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDSEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xsQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqSEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xwQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwT0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4a0JBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDakRBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4Q0E7QUFPQTtBQUNBOztBQ01BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaGFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdnlDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDam9FQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNyUkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDWkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDWEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDOVVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeEZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2x6QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcGpCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JVQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVoRkE7QUFDQTtBQUNBOztBQ0ZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzlCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4REE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDL0pBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeFZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvS0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDek1BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1UEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDWEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNWQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hSQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzlCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3ZNQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDci9CQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2TkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbERBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ1hBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hLQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbEJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN0QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDWkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNkQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNUQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDelpBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3ZKQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNYQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1UEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4RUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3ZFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6RUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDckZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbkVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7Ozs7Ozs7Ozs7Ozs7QUMzRkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25QQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFMQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdExBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNUZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeFJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFUQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4REE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xKQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbEdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2h4QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDekZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBUUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4eUJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3BDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDN0JBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN0SEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNUxBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcElBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzlKQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25NQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUM1SUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNoQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDVEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3BIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4TkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNoSEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvRkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDckRBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM3QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0s7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hWQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzNPQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqSkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDWkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hjQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNWQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDTEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ0pBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDVkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ0lBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RkSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdENBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0s7O0FDeklMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbEVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcFJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDekRBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM5SEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM0hBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25EQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNUlBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM0NBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDN0RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxRkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbkRBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDVEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdENBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ1pBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25EQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzdPQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDZkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqWEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdEVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNySkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JuQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeEhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbEJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMURBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDakVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwSUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pZQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQy9JQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25DQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxVEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4c0JBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzdYQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvcUJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvdkJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNYQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDN0ZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDN0NBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3REQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM0dBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbkZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeERBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdE1BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDekdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNsRkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNoRkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM5RUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM5Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwUUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4R0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzdDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbERBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeEdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM0RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OzsifQ== diff --git a/build/three.module.js b/build/three.module.js deleted file mode 100644 index f234e11ea3a356..00000000000000 --- a/build/three.module.js +++ /dev/null @@ -1,53253 +0,0 @@ -/** - * @license - * Copyright 2010-2023 Three.js Authors - * SPDX-License-Identifier: MIT - */ -const REVISION = '162dev'; - -const MOUSE = { LEFT: 0, MIDDLE: 1, RIGHT: 2, ROTATE: 0, DOLLY: 1, PAN: 2 }; -const TOUCH = { ROTATE: 0, PAN: 1, DOLLY_PAN: 2, DOLLY_ROTATE: 3 }; -const CullFaceNone = 0; -const CullFaceBack = 1; -const CullFaceFront = 2; -const CullFaceFrontBack = 3; -const BasicShadowMap = 0; -const PCFShadowMap = 1; -const PCFSoftShadowMap = 2; -const VSMShadowMap = 3; -const FrontSide = 0; -const BackSide = 1; -const DoubleSide = 2; -const NoBlending = 0; -const NormalBlending = 1; -const AdditiveBlending = 2; -const SubtractiveBlending = 3; -const MultiplyBlending = 4; -const CustomBlending = 5; -const AddEquation = 100; -const SubtractEquation = 101; -const ReverseSubtractEquation = 102; -const MinEquation = 103; -const MaxEquation = 104; -const ZeroFactor = 200; -const OneFactor = 201; -const SrcColorFactor = 202; -const OneMinusSrcColorFactor = 203; -const SrcAlphaFactor = 204; -const OneMinusSrcAlphaFactor = 205; -const DstAlphaFactor = 206; -const OneMinusDstAlphaFactor = 207; -const DstColorFactor = 208; -const OneMinusDstColorFactor = 209; -const SrcAlphaSaturateFactor = 210; -const ConstantColorFactor = 211; -const OneMinusConstantColorFactor = 212; -const ConstantAlphaFactor = 213; -const OneMinusConstantAlphaFactor = 214; -const NeverDepth = 0; -const AlwaysDepth = 1; -const LessDepth = 2; -const LessEqualDepth = 3; -const EqualDepth = 4; -const GreaterEqualDepth = 5; -const GreaterDepth = 6; -const NotEqualDepth = 7; -const MultiplyOperation = 0; -const MixOperation = 1; -const AddOperation = 2; -const NoToneMapping = 0; -const LinearToneMapping = 1; -const ReinhardToneMapping = 2; -const CineonToneMapping = 3; -const ACESFilmicToneMapping = 4; -const CustomToneMapping = 5; -const AgXToneMapping = 6; -const AttachedBindMode = 'attached'; -const DetachedBindMode = 'detached'; - -const UVMapping = 300; -const CubeReflectionMapping = 301; -const CubeRefractionMapping = 302; -const EquirectangularReflectionMapping = 303; -const EquirectangularRefractionMapping = 304; -const CubeUVReflectionMapping = 306; -const RepeatWrapping = 1000; -const ClampToEdgeWrapping = 1001; -const MirroredRepeatWrapping = 1002; -const NearestFilter = 1003; -const NearestMipmapNearestFilter = 1004; -const NearestMipMapNearestFilter = 1004; -const NearestMipmapLinearFilter = 1005; -const NearestMipMapLinearFilter = 1005; -const LinearFilter = 1006; -const LinearMipmapNearestFilter = 1007; -const LinearMipMapNearestFilter = 1007; -const LinearMipmapLinearFilter = 1008; -const LinearMipMapLinearFilter = 1008; -const UnsignedByteType = 1009; -const ByteType = 1010; -const ShortType = 1011; -const UnsignedShortType = 1012; -const IntType = 1013; -const UnsignedIntType = 1014; -const FloatType = 1015; -const HalfFloatType = 1016; -const UnsignedShort4444Type = 1017; -const UnsignedShort5551Type = 1018; -const UnsignedInt248Type = 1020; -const AlphaFormat = 1021; -const RGBAFormat = 1023; -const LuminanceFormat = 1024; -const LuminanceAlphaFormat = 1025; -const DepthFormat = 1026; -const DepthStencilFormat = 1027; -const RedFormat = 1028; -const RedIntegerFormat = 1029; -const RGFormat = 1030; -const RGIntegerFormat = 1031; -const RGBAIntegerFormat = 1033; - -const RGB_S3TC_DXT1_Format = 33776; -const RGBA_S3TC_DXT1_Format = 33777; -const RGBA_S3TC_DXT3_Format = 33778; -const RGBA_S3TC_DXT5_Format = 33779; -const RGB_PVRTC_4BPPV1_Format = 35840; -const RGB_PVRTC_2BPPV1_Format = 35841; -const RGBA_PVRTC_4BPPV1_Format = 35842; -const RGBA_PVRTC_2BPPV1_Format = 35843; -const RGB_ETC1_Format = 36196; -const RGB_ETC2_Format = 37492; -const RGBA_ETC2_EAC_Format = 37496; -const RGBA_ASTC_4x4_Format = 37808; -const RGBA_ASTC_5x4_Format = 37809; -const RGBA_ASTC_5x5_Format = 37810; -const RGBA_ASTC_6x5_Format = 37811; -const RGBA_ASTC_6x6_Format = 37812; -const RGBA_ASTC_8x5_Format = 37813; -const RGBA_ASTC_8x6_Format = 37814; -const RGBA_ASTC_8x8_Format = 37815; -const RGBA_ASTC_10x5_Format = 37816; -const RGBA_ASTC_10x6_Format = 37817; -const RGBA_ASTC_10x8_Format = 37818; -const RGBA_ASTC_10x10_Format = 37819; -const RGBA_ASTC_12x10_Format = 37820; -const RGBA_ASTC_12x12_Format = 37821; -const RGBA_BPTC_Format = 36492; -const RGB_BPTC_SIGNED_Format = 36494; -const RGB_BPTC_UNSIGNED_Format = 36495; -const RED_RGTC1_Format = 36283; -const SIGNED_RED_RGTC1_Format = 36284; -const RED_GREEN_RGTC2_Format = 36285; -const SIGNED_RED_GREEN_RGTC2_Format = 36286; -const LoopOnce = 2200; -const LoopRepeat = 2201; -const LoopPingPong = 2202; -const InterpolateDiscrete = 2300; -const InterpolateLinear = 2301; -const InterpolateSmooth = 2302; -const ZeroCurvatureEnding = 2400; -const ZeroSlopeEnding = 2401; -const WrapAroundEnding = 2402; -const NormalAnimationBlendMode = 2500; -const AdditiveAnimationBlendMode = 2501; -const TrianglesDrawMode = 0; -const TriangleStripDrawMode = 1; -const TriangleFanDrawMode = 2; -const BasicDepthPacking = 3200; -const RGBADepthPacking = 3201; -const TangentSpaceNormalMap = 0; -const ObjectSpaceNormalMap = 1; - -// Color space string identifiers, matching CSS Color Module Level 4 and WebGPU names where available. -const NoColorSpace = ''; -const SRGBColorSpace = 'srgb'; -const LinearSRGBColorSpace = 'srgb-linear'; -const DisplayP3ColorSpace = 'display-p3'; -const LinearDisplayP3ColorSpace = 'display-p3-linear'; - -const LinearTransfer = 'linear'; -const SRGBTransfer = 'srgb'; - -const Rec709Primaries = 'rec709'; -const P3Primaries = 'p3'; - -const ZeroStencilOp = 0; -const KeepStencilOp = 7680; -const ReplaceStencilOp = 7681; -const IncrementStencilOp = 7682; -const DecrementStencilOp = 7683; -const IncrementWrapStencilOp = 34055; -const DecrementWrapStencilOp = 34056; -const InvertStencilOp = 5386; - -const NeverStencilFunc = 512; -const LessStencilFunc = 513; -const EqualStencilFunc = 514; -const LessEqualStencilFunc = 515; -const GreaterStencilFunc = 516; -const NotEqualStencilFunc = 517; -const GreaterEqualStencilFunc = 518; -const AlwaysStencilFunc = 519; - -const NeverCompare = 512; -const LessCompare = 513; -const EqualCompare = 514; -const LessEqualCompare = 515; -const GreaterCompare = 516; -const NotEqualCompare = 517; -const GreaterEqualCompare = 518; -const AlwaysCompare = 519; - -const StaticDrawUsage = 35044; -const DynamicDrawUsage = 35048; -const StreamDrawUsage = 35040; -const StaticReadUsage = 35045; -const DynamicReadUsage = 35049; -const StreamReadUsage = 35041; -const StaticCopyUsage = 35046; -const DynamicCopyUsage = 35050; -const StreamCopyUsage = 35042; - -const GLSL1 = '100'; -const GLSL3 = '300 es'; - -const _SRGBAFormat = 1035; // fallback for WebGL 1 - -const WebGLCoordinateSystem = 2000; -const WebGPUCoordinateSystem = 2001; - -/** - * https://github.com/mrdoob/eventdispatcher.js/ - */ - -class EventDispatcher { - - addEventListener( type, listener ) { - - if ( this._listeners === undefined ) this._listeners = {}; - - const listeners = this._listeners; - - if ( listeners[ type ] === undefined ) { - - listeners[ type ] = []; - - } - - if ( listeners[ type ].indexOf( listener ) === - 1 ) { - - listeners[ type ].push( listener ); - - } - - } - - hasEventListener( type, listener ) { - - if ( this._listeners === undefined ) return false; - - const listeners = this._listeners; - - return listeners[ type ] !== undefined && listeners[ type ].indexOf( listener ) !== - 1; - - } - - removeEventListener( type, listener ) { - - if ( this._listeners === undefined ) return; - - const listeners = this._listeners; - const listenerArray = listeners[ type ]; - - if ( listenerArray !== undefined ) { - - const index = listenerArray.indexOf( listener ); - - if ( index !== - 1 ) { - - listenerArray.splice( index, 1 ); - - } - - } - - } - - dispatchEvent( event ) { - - if ( this._listeners === undefined ) return; - - const listeners = this._listeners; - const listenerArray = listeners[ event.type ]; - - if ( listenerArray !== undefined ) { - - event.target = this; - - // Make a copy, in case listeners are removed while iterating. - const array = listenerArray.slice( 0 ); - - for ( let i = 0, l = array.length; i < l; i ++ ) { - - array[ i ].call( this, event ); - - } - - event.target = null; - - } - - } - -} - -const _lut = [ '00', '01', '02', '03', '04', '05', '06', '07', '08', '09', '0a', '0b', '0c', '0d', '0e', '0f', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '1a', '1b', '1c', '1d', '1e', '1f', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '2a', '2b', '2c', '2d', '2e', '2f', '30', '31', '32', '33', '34', '35', '36', '37', '38', '39', '3a', '3b', '3c', '3d', '3e', '3f', '40', '41', '42', '43', '44', '45', '46', '47', '48', '49', '4a', '4b', '4c', '4d', '4e', '4f', '50', '51', '52', '53', '54', '55', '56', '57', '58', '59', '5a', '5b', '5c', '5d', '5e', '5f', '60', '61', '62', '63', '64', '65', '66', '67', '68', '69', '6a', '6b', '6c', '6d', '6e', '6f', '70', '71', '72', '73', '74', '75', '76', '77', '78', '79', '7a', '7b', '7c', '7d', '7e', '7f', '80', '81', '82', '83', '84', '85', '86', '87', '88', '89', '8a', '8b', '8c', '8d', '8e', '8f', '90', '91', '92', '93', '94', '95', '96', '97', '98', '99', '9a', '9b', '9c', '9d', '9e', '9f', 'a0', 'a1', 'a2', 'a3', 'a4', 'a5', 'a6', 'a7', 'a8', 'a9', 'aa', 'ab', 'ac', 'ad', 'ae', 'af', 'b0', 'b1', 'b2', 'b3', 'b4', 'b5', 'b6', 'b7', 'b8', 'b9', 'ba', 'bb', 'bc', 'bd', 'be', 'bf', 'c0', 'c1', 'c2', 'c3', 'c4', 'c5', 'c6', 'c7', 'c8', 'c9', 'ca', 'cb', 'cc', 'cd', 'ce', 'cf', 'd0', 'd1', 'd2', 'd3', 'd4', 'd5', 'd6', 'd7', 'd8', 'd9', 'da', 'db', 'dc', 'dd', 'de', 'df', 'e0', 'e1', 'e2', 'e3', 'e4', 'e5', 'e6', 'e7', 'e8', 'e9', 'ea', 'eb', 'ec', 'ed', 'ee', 'ef', 'f0', 'f1', 'f2', 'f3', 'f4', 'f5', 'f6', 'f7', 'f8', 'f9', 'fa', 'fb', 'fc', 'fd', 'fe', 'ff' ]; - -let _seed = 1234567; - - -const DEG2RAD = Math.PI / 180; -const RAD2DEG = 180 / Math.PI; - -// http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/21963136#21963136 -function generateUUID() { - - const d0 = Math.random() * 0xffffffff | 0; - const d1 = Math.random() * 0xffffffff | 0; - const d2 = Math.random() * 0xffffffff | 0; - const d3 = Math.random() * 0xffffffff | 0; - const uuid = _lut[ d0 & 0xff ] + _lut[ d0 >> 8 & 0xff ] + _lut[ d0 >> 16 & 0xff ] + _lut[ d0 >> 24 & 0xff ] + '-' + - _lut[ d1 & 0xff ] + _lut[ d1 >> 8 & 0xff ] + '-' + _lut[ d1 >> 16 & 0x0f | 0x40 ] + _lut[ d1 >> 24 & 0xff ] + '-' + - _lut[ d2 & 0x3f | 0x80 ] + _lut[ d2 >> 8 & 0xff ] + '-' + _lut[ d2 >> 16 & 0xff ] + _lut[ d2 >> 24 & 0xff ] + - _lut[ d3 & 0xff ] + _lut[ d3 >> 8 & 0xff ] + _lut[ d3 >> 16 & 0xff ] + _lut[ d3 >> 24 & 0xff ]; - - // .toLowerCase() here flattens concatenated strings to save heap memory space. - return uuid.toLowerCase(); - -} - -function clamp( value, min, max ) { - - return Math.max( min, Math.min( max, value ) ); - -} - -// compute euclidean modulo of m % n -// https://en.wikipedia.org/wiki/Modulo_operation -function euclideanModulo( n, m ) { - - return ( ( n % m ) + m ) % m; - -} - -// Linear mapping from range to range -function mapLinear( x, a1, a2, b1, b2 ) { - - return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 ); - -} - -// https://www.gamedev.net/tutorials/programming/general-and-gameplay-programming/inverse-lerp-a-super-useful-yet-often-overlooked-function-r5230/ -function inverseLerp( x, y, value ) { - - if ( x !== y ) { - - return ( value - x ) / ( y - x ); - - } else { - - return 0; - - } - -} - -// https://en.wikipedia.org/wiki/Linear_interpolation -function lerp( x, y, t ) { - - return ( 1 - t ) * x + t * y; - -} - -// http://www.rorydriscoll.com/2016/03/07/frame-rate-independent-damping-using-lerp/ -function damp( x, y, lambda, dt ) { - - return lerp( x, y, 1 - Math.exp( - lambda * dt ) ); - -} - -// https://www.desmos.com/calculator/vcsjnyz7x4 -function pingpong( x, length = 1 ) { - - return length - Math.abs( euclideanModulo( x, length * 2 ) - length ); - -} - -// http://en.wikipedia.org/wiki/Smoothstep -function smoothstep( x, min, max ) { - - if ( x <= min ) return 0; - if ( x >= max ) return 1; - - x = ( x - min ) / ( max - min ); - - return x * x * ( 3 - 2 * x ); - -} - -function smootherstep( x, min, max ) { - - if ( x <= min ) return 0; - if ( x >= max ) return 1; - - x = ( x - min ) / ( max - min ); - - return x * x * x * ( x * ( x * 6 - 15 ) + 10 ); - -} - -// Random integer from interval -function randInt( low, high ) { - - return low + Math.floor( Math.random() * ( high - low + 1 ) ); - -} - -// Random float from interval -function randFloat( low, high ) { - - return low + Math.random() * ( high - low ); - -} - -// Random float from <-range/2, range/2> interval -function randFloatSpread( range ) { - - return range * ( 0.5 - Math.random() ); - -} - -// Deterministic pseudo-random float in the interval [ 0, 1 ] -function seededRandom( s ) { - - if ( s !== undefined ) _seed = s; - - // Mulberry32 generator - - let t = _seed += 0x6D2B79F5; - - t = Math.imul( t ^ t >>> 15, t | 1 ); - - t ^= t + Math.imul( t ^ t >>> 7, t | 61 ); - - return ( ( t ^ t >>> 14 ) >>> 0 ) / 4294967296; - -} - -function degToRad( degrees ) { - - return degrees * DEG2RAD; - -} - -function radToDeg( radians ) { - - return radians * RAD2DEG; - -} - -function isPowerOfTwo( value ) { - - return ( value & ( value - 1 ) ) === 0 && value !== 0; - -} - -function ceilPowerOfTwo( value ) { - - return Math.pow( 2, Math.ceil( Math.log( value ) / Math.LN2 ) ); - -} - -function floorPowerOfTwo( value ) { - - return Math.pow( 2, Math.floor( Math.log( value ) / Math.LN2 ) ); - -} - -function setQuaternionFromProperEuler( q, a, b, c, order ) { - - // Intrinsic Proper Euler Angles - see https://en.wikipedia.org/wiki/Euler_angles - - // rotations are applied to the axes in the order specified by 'order' - // rotation by angle 'a' is applied first, then by angle 'b', then by angle 'c' - // angles are in radians - - const cos = Math.cos; - const sin = Math.sin; - - const c2 = cos( b / 2 ); - const s2 = sin( b / 2 ); - - const c13 = cos( ( a + c ) / 2 ); - const s13 = sin( ( a + c ) / 2 ); - - const c1_3 = cos( ( a - c ) / 2 ); - const s1_3 = sin( ( a - c ) / 2 ); - - const c3_1 = cos( ( c - a ) / 2 ); - const s3_1 = sin( ( c - a ) / 2 ); - - switch ( order ) { - - case 'XYX': - q.set( c2 * s13, s2 * c1_3, s2 * s1_3, c2 * c13 ); - break; - - case 'YZY': - q.set( s2 * s1_3, c2 * s13, s2 * c1_3, c2 * c13 ); - break; - - case 'ZXZ': - q.set( s2 * c1_3, s2 * s1_3, c2 * s13, c2 * c13 ); - break; - - case 'XZX': - q.set( c2 * s13, s2 * s3_1, s2 * c3_1, c2 * c13 ); - break; - - case 'YXY': - q.set( s2 * c3_1, c2 * s13, s2 * s3_1, c2 * c13 ); - break; - - case 'ZYZ': - q.set( s2 * s3_1, s2 * c3_1, c2 * s13, c2 * c13 ); - break; - - default: - console.warn( 'THREE.MathUtils: .setQuaternionFromProperEuler() encountered an unknown order: ' + order ); - - } - -} - -function denormalize( value, array ) { - - switch ( array.constructor ) { - - case Float32Array: - - return value; - - case Uint32Array: - - return value / 4294967295.0; - - case Uint16Array: - - return value / 65535.0; - - case Uint8Array: - - return value / 255.0; - - case Int32Array: - - return Math.max( value / 2147483647.0, - 1.0 ); - - case Int16Array: - - return Math.max( value / 32767.0, - 1.0 ); - - case Int8Array: - - return Math.max( value / 127.0, - 1.0 ); - - default: - - throw new Error( 'Invalid component type.' ); - - } - -} - -function normalize( value, array ) { - - switch ( array.constructor ) { - - case Float32Array: - - return value; - - case Uint32Array: - - return Math.round( value * 4294967295.0 ); - - case Uint16Array: - - return Math.round( value * 65535.0 ); - - case Uint8Array: - - return Math.round( value * 255.0 ); - - case Int32Array: - - return Math.round( value * 2147483647.0 ); - - case Int16Array: - - return Math.round( value * 32767.0 ); - - case Int8Array: - - return Math.round( value * 127.0 ); - - default: - - throw new Error( 'Invalid component type.' ); - - } - -} - -const MathUtils = { - DEG2RAD: DEG2RAD, - RAD2DEG: RAD2DEG, - generateUUID: generateUUID, - clamp: clamp, - euclideanModulo: euclideanModulo, - mapLinear: mapLinear, - inverseLerp: inverseLerp, - lerp: lerp, - damp: damp, - pingpong: pingpong, - smoothstep: smoothstep, - smootherstep: smootherstep, - randInt: randInt, - randFloat: randFloat, - randFloatSpread: randFloatSpread, - seededRandom: seededRandom, - degToRad: degToRad, - radToDeg: radToDeg, - isPowerOfTwo: isPowerOfTwo, - ceilPowerOfTwo: ceilPowerOfTwo, - floorPowerOfTwo: floorPowerOfTwo, - setQuaternionFromProperEuler: setQuaternionFromProperEuler, - normalize: normalize, - denormalize: denormalize -}; - -class Vector2 { - - constructor( x = 0, y = 0 ) { - - Vector2.prototype.isVector2 = true; - - this.x = x; - this.y = y; - - } - - get width() { - - return this.x; - - } - - set width( value ) { - - this.x = value; - - } - - get height() { - - return this.y; - - } - - set height( value ) { - - this.y = value; - - } - - set( x, y ) { - - this.x = x; - this.y = y; - - return this; - - } - - setScalar( scalar ) { - - this.x = scalar; - this.y = scalar; - - return this; - - } - - setX( x ) { - - this.x = x; - - return this; - - } - - setY( y ) { - - this.y = y; - - return this; - - } - - setComponent( index, value ) { - - switch ( index ) { - - case 0: this.x = value; break; - case 1: this.y = value; break; - default: throw new Error( 'index is out of range: ' + index ); - - } - - return this; - - } - - getComponent( index ) { - - switch ( index ) { - - case 0: return this.x; - case 1: return this.y; - default: throw new Error( 'index is out of range: ' + index ); - - } - - } - - clone() { - - return new this.constructor( this.x, this.y ); - - } - - copy( v ) { - - this.x = v.x; - this.y = v.y; - - return this; - - } - - add( v ) { - - this.x += v.x; - this.y += v.y; - - return this; - - } - - addScalar( s ) { - - this.x += s; - this.y += s; - - return this; - - } - - addVectors( a, b ) { - - this.x = a.x + b.x; - this.y = a.y + b.y; - - return this; - - } - - addScaledVector( v, s ) { - - this.x += v.x * s; - this.y += v.y * s; - - return this; - - } - - sub( v ) { - - this.x -= v.x; - this.y -= v.y; - - return this; - - } - - subScalar( s ) { - - this.x -= s; - this.y -= s; - - return this; - - } - - subVectors( a, b ) { - - this.x = a.x - b.x; - this.y = a.y - b.y; - - return this; - - } - - multiply( v ) { - - this.x *= v.x; - this.y *= v.y; - - return this; - - } - - multiplyScalar( scalar ) { - - this.x *= scalar; - this.y *= scalar; - - return this; - - } - - divide( v ) { - - this.x /= v.x; - this.y /= v.y; - - return this; - - } - - divideScalar( scalar ) { - - return this.multiplyScalar( 1 / scalar ); - - } - - applyMatrix3( m ) { - - const x = this.x, y = this.y; - const e = m.elements; - - this.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ]; - this.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ]; - - return this; - - } - - min( v ) { - - this.x = Math.min( this.x, v.x ); - this.y = Math.min( this.y, v.y ); - - return this; - - } - - max( v ) { - - this.x = Math.max( this.x, v.x ); - this.y = Math.max( this.y, v.y ); - - return this; - - } - - clamp( min, max ) { - - // assumes min < max, componentwise - - this.x = Math.max( min.x, Math.min( max.x, this.x ) ); - this.y = Math.max( min.y, Math.min( max.y, this.y ) ); - - return this; - - } - - clampScalar( minVal, maxVal ) { - - this.x = Math.max( minVal, Math.min( maxVal, this.x ) ); - this.y = Math.max( minVal, Math.min( maxVal, this.y ) ); - - return this; - - } - - clampLength( min, max ) { - - const length = this.length(); - - return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) ); - - } - - floor() { - - this.x = Math.floor( this.x ); - this.y = Math.floor( this.y ); - - return this; - - } - - ceil() { - - this.x = Math.ceil( this.x ); - this.y = Math.ceil( this.y ); - - return this; - - } - - round() { - - this.x = Math.round( this.x ); - this.y = Math.round( this.y ); - - return this; - - } - - roundToZero() { - - this.x = Math.trunc( this.x ); - this.y = Math.trunc( this.y ); - - return this; - - } - - negate() { - - this.x = - this.x; - this.y = - this.y; - - return this; - - } - - dot( v ) { - - return this.x * v.x + this.y * v.y; - - } - - cross( v ) { - - return this.x * v.y - this.y * v.x; - - } - - lengthSq() { - - return this.x * this.x + this.y * this.y; - - } - - length() { - - return Math.sqrt( this.x * this.x + this.y * this.y ); - - } - - manhattanLength() { - - return Math.abs( this.x ) + Math.abs( this.y ); - - } - - normalize() { - - return this.divideScalar( this.length() || 1 ); - - } - - angle() { - - // computes the angle in radians with respect to the positive x-axis - - const angle = Math.atan2( - this.y, - this.x ) + Math.PI; - - return angle; - - } - - angleTo( v ) { - - const denominator = Math.sqrt( this.lengthSq() * v.lengthSq() ); - - if ( denominator === 0 ) return Math.PI / 2; - - const theta = this.dot( v ) / denominator; - - // clamp, to handle numerical problems - - return Math.acos( clamp( theta, - 1, 1 ) ); - - } - - distanceTo( v ) { - - return Math.sqrt( this.distanceToSquared( v ) ); - - } - - distanceToSquared( v ) { - - const dx = this.x - v.x, dy = this.y - v.y; - return dx * dx + dy * dy; - - } - - manhattanDistanceTo( v ) { - - return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y ); - - } - - setLength( length ) { - - return this.normalize().multiplyScalar( length ); - - } - - lerp( v, alpha ) { - - this.x += ( v.x - this.x ) * alpha; - this.y += ( v.y - this.y ) * alpha; - - return this; - - } - - lerpVectors( v1, v2, alpha ) { - - this.x = v1.x + ( v2.x - v1.x ) * alpha; - this.y = v1.y + ( v2.y - v1.y ) * alpha; - - return this; - - } - - equals( v ) { - - return ( ( v.x === this.x ) && ( v.y === this.y ) ); - - } - - fromArray( array, offset = 0 ) { - - this.x = array[ offset ]; - this.y = array[ offset + 1 ]; - - return this; - - } - - toArray( array = [], offset = 0 ) { - - array[ offset ] = this.x; - array[ offset + 1 ] = this.y; - - return array; - - } - - fromBufferAttribute( attribute, index ) { - - this.x = attribute.getX( index ); - this.y = attribute.getY( index ); - - return this; - - } - - rotateAround( center, angle ) { - - const c = Math.cos( angle ), s = Math.sin( angle ); - - const x = this.x - center.x; - const y = this.y - center.y; - - this.x = x * c - y * s + center.x; - this.y = x * s + y * c + center.y; - - return this; - - } - - random() { - - this.x = Math.random(); - this.y = Math.random(); - - return this; - - } - - *[ Symbol.iterator ]() { - - yield this.x; - yield this.y; - - } - -} - -class Matrix3 { - - constructor( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) { - - Matrix3.prototype.isMatrix3 = true; - - this.elements = [ - - 1, 0, 0, - 0, 1, 0, - 0, 0, 1 - - ]; - - if ( n11 !== undefined ) { - - this.set( n11, n12, n13, n21, n22, n23, n31, n32, n33 ); - - } - - } - - set( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) { - - const te = this.elements; - - te[ 0 ] = n11; te[ 1 ] = n21; te[ 2 ] = n31; - te[ 3 ] = n12; te[ 4 ] = n22; te[ 5 ] = n32; - te[ 6 ] = n13; te[ 7 ] = n23; te[ 8 ] = n33; - - return this; - - } - - identity() { - - this.set( - - 1, 0, 0, - 0, 1, 0, - 0, 0, 1 - - ); - - return this; - - } - - copy( m ) { - - const te = this.elements; - const me = m.elements; - - te[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ]; - te[ 3 ] = me[ 3 ]; te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ]; - te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ]; te[ 8 ] = me[ 8 ]; - - return this; - - } - - extractBasis( xAxis, yAxis, zAxis ) { - - xAxis.setFromMatrix3Column( this, 0 ); - yAxis.setFromMatrix3Column( this, 1 ); - zAxis.setFromMatrix3Column( this, 2 ); - - return this; - - } - - setFromMatrix4( m ) { - - const me = m.elements; - - this.set( - - me[ 0 ], me[ 4 ], me[ 8 ], - me[ 1 ], me[ 5 ], me[ 9 ], - me[ 2 ], me[ 6 ], me[ 10 ] - - ); - - return this; - - } - - multiply( m ) { - - return this.multiplyMatrices( this, m ); - - } - - premultiply( m ) { - - return this.multiplyMatrices( m, this ); - - } - - multiplyMatrices( a, b ) { - - const ae = a.elements; - const be = b.elements; - const te = this.elements; - - const a11 = ae[ 0 ], a12 = ae[ 3 ], a13 = ae[ 6 ]; - const a21 = ae[ 1 ], a22 = ae[ 4 ], a23 = ae[ 7 ]; - const a31 = ae[ 2 ], a32 = ae[ 5 ], a33 = ae[ 8 ]; - - const b11 = be[ 0 ], b12 = be[ 3 ], b13 = be[ 6 ]; - const b21 = be[ 1 ], b22 = be[ 4 ], b23 = be[ 7 ]; - const b31 = be[ 2 ], b32 = be[ 5 ], b33 = be[ 8 ]; - - te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31; - te[ 3 ] = a11 * b12 + a12 * b22 + a13 * b32; - te[ 6 ] = a11 * b13 + a12 * b23 + a13 * b33; - - te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31; - te[ 4 ] = a21 * b12 + a22 * b22 + a23 * b32; - te[ 7 ] = a21 * b13 + a22 * b23 + a23 * b33; - - te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31; - te[ 5 ] = a31 * b12 + a32 * b22 + a33 * b32; - te[ 8 ] = a31 * b13 + a32 * b23 + a33 * b33; - - return this; - - } - - multiplyScalar( s ) { - - const te = this.elements; - - te[ 0 ] *= s; te[ 3 ] *= s; te[ 6 ] *= s; - te[ 1 ] *= s; te[ 4 ] *= s; te[ 7 ] *= s; - te[ 2 ] *= s; te[ 5 ] *= s; te[ 8 ] *= s; - - return this; - - } - - determinant() { - - const te = this.elements; - - const a = te[ 0 ], b = te[ 1 ], c = te[ 2 ], - d = te[ 3 ], e = te[ 4 ], f = te[ 5 ], - g = te[ 6 ], h = te[ 7 ], i = te[ 8 ]; - - return a * e * i - a * f * h - b * d * i + b * f * g + c * d * h - c * e * g; - - } - - invert() { - - const te = this.elements, - - n11 = te[ 0 ], n21 = te[ 1 ], n31 = te[ 2 ], - n12 = te[ 3 ], n22 = te[ 4 ], n32 = te[ 5 ], - n13 = te[ 6 ], n23 = te[ 7 ], n33 = te[ 8 ], - - t11 = n33 * n22 - n32 * n23, - t12 = n32 * n13 - n33 * n12, - t13 = n23 * n12 - n22 * n13, - - det = n11 * t11 + n21 * t12 + n31 * t13; - - if ( det === 0 ) return this.set( 0, 0, 0, 0, 0, 0, 0, 0, 0 ); - - const detInv = 1 / det; - - te[ 0 ] = t11 * detInv; - te[ 1 ] = ( n31 * n23 - n33 * n21 ) * detInv; - te[ 2 ] = ( n32 * n21 - n31 * n22 ) * detInv; - - te[ 3 ] = t12 * detInv; - te[ 4 ] = ( n33 * n11 - n31 * n13 ) * detInv; - te[ 5 ] = ( n31 * n12 - n32 * n11 ) * detInv; - - te[ 6 ] = t13 * detInv; - te[ 7 ] = ( n21 * n13 - n23 * n11 ) * detInv; - te[ 8 ] = ( n22 * n11 - n21 * n12 ) * detInv; - - return this; - - } - - transpose() { - - let tmp; - const m = this.elements; - - tmp = m[ 1 ]; m[ 1 ] = m[ 3 ]; m[ 3 ] = tmp; - tmp = m[ 2 ]; m[ 2 ] = m[ 6 ]; m[ 6 ] = tmp; - tmp = m[ 5 ]; m[ 5 ] = m[ 7 ]; m[ 7 ] = tmp; - - return this; - - } - - getNormalMatrix( matrix4 ) { - - return this.setFromMatrix4( matrix4 ).invert().transpose(); - - } - - transposeIntoArray( r ) { - - const m = this.elements; - - r[ 0 ] = m[ 0 ]; - r[ 1 ] = m[ 3 ]; - r[ 2 ] = m[ 6 ]; - r[ 3 ] = m[ 1 ]; - r[ 4 ] = m[ 4 ]; - r[ 5 ] = m[ 7 ]; - r[ 6 ] = m[ 2 ]; - r[ 7 ] = m[ 5 ]; - r[ 8 ] = m[ 8 ]; - - return this; - - } - - setUvTransform( tx, ty, sx, sy, rotation, cx, cy ) { - - const c = Math.cos( rotation ); - const s = Math.sin( rotation ); - - this.set( - sx * c, sx * s, - sx * ( c * cx + s * cy ) + cx + tx, - - sy * s, sy * c, - sy * ( - s * cx + c * cy ) + cy + ty, - 0, 0, 1 - ); - - return this; - - } - - // - - scale( sx, sy ) { - - this.premultiply( _m3.makeScale( sx, sy ) ); - - return this; - - } - - rotate( theta ) { - - this.premultiply( _m3.makeRotation( - theta ) ); - - return this; - - } - - translate( tx, ty ) { - - this.premultiply( _m3.makeTranslation( tx, ty ) ); - - return this; - - } - - // for 2D Transforms - - makeTranslation( x, y ) { - - if ( x.isVector2 ) { - - this.set( - - 1, 0, x.x, - 0, 1, x.y, - 0, 0, 1 - - ); - - } else { - - this.set( - - 1, 0, x, - 0, 1, y, - 0, 0, 1 - - ); - - } - - return this; - - } - - makeRotation( theta ) { - - // counterclockwise - - const c = Math.cos( theta ); - const s = Math.sin( theta ); - - this.set( - - c, - s, 0, - s, c, 0, - 0, 0, 1 - - ); - - return this; - - } - - makeScale( x, y ) { - - this.set( - - x, 0, 0, - 0, y, 0, - 0, 0, 1 - - ); - - return this; - - } - - // - - equals( matrix ) { - - const te = this.elements; - const me = matrix.elements; - - for ( let i = 0; i < 9; i ++ ) { - - if ( te[ i ] !== me[ i ] ) return false; - - } - - return true; - - } - - fromArray( array, offset = 0 ) { - - for ( let i = 0; i < 9; i ++ ) { - - this.elements[ i ] = array[ i + offset ]; - - } - - return this; - - } - - toArray( array = [], offset = 0 ) { - - const te = this.elements; - - array[ offset ] = te[ 0 ]; - array[ offset + 1 ] = te[ 1 ]; - array[ offset + 2 ] = te[ 2 ]; - - array[ offset + 3 ] = te[ 3 ]; - array[ offset + 4 ] = te[ 4 ]; - array[ offset + 5 ] = te[ 5 ]; - - array[ offset + 6 ] = te[ 6 ]; - array[ offset + 7 ] = te[ 7 ]; - array[ offset + 8 ] = te[ 8 ]; - - return array; - - } - - clone() { - - return new this.constructor().fromArray( this.elements ); - - } - -} - -const _m3 = /*@__PURE__*/ new Matrix3(); - -function arrayNeedsUint32( array ) { - - // assumes larger values usually on last - - for ( let i = array.length - 1; i >= 0; -- i ) { - - if ( array[ i ] >= 65535 ) return true; // account for PRIMITIVE_RESTART_FIXED_INDEX, #24565 - - } - - return false; - -} - -const TYPED_ARRAYS = { - Int8Array: Int8Array, - Uint8Array: Uint8Array, - Uint8ClampedArray: Uint8ClampedArray, - Int16Array: Int16Array, - Uint16Array: Uint16Array, - Int32Array: Int32Array, - Uint32Array: Uint32Array, - Float32Array: Float32Array, - Float64Array: Float64Array -}; - -function getTypedArray( type, buffer ) { - - return new TYPED_ARRAYS[ type ]( buffer ); - -} - -function createElementNS( name ) { - - return document.createElementNS( 'http://www.w3.org/1999/xhtml', name ); - -} - -function createCanvasElement() { - - const canvas = createElementNS( 'canvas' ); - canvas.style.display = 'block'; - return canvas; - -} - -const _cache = {}; - -function warnOnce( message ) { - - if ( message in _cache ) return; - - _cache[ message ] = true; - - console.warn( message ); - -} - -/** - * Matrices converting P3 <-> Rec. 709 primaries, without gamut mapping - * or clipping. Based on W3C specifications for sRGB and Display P3, - * and ICC specifications for the D50 connection space. Values in/out - * are _linear_ sRGB and _linear_ Display P3. - * - * Note that both sRGB and Display P3 use the sRGB transfer functions. - * - * Reference: - * - http://www.russellcottrell.com/photo/matrixCalculator.htm - */ - -const LINEAR_SRGB_TO_LINEAR_DISPLAY_P3 = /*@__PURE__*/ new Matrix3().set( - 0.8224621, 0.177538, 0.0, - 0.0331941, 0.9668058, 0.0, - 0.0170827, 0.0723974, 0.9105199, -); - -const LINEAR_DISPLAY_P3_TO_LINEAR_SRGB = /*@__PURE__*/ new Matrix3().set( - 1.2249401, - 0.2249404, 0.0, - - 0.0420569, 1.0420571, 0.0, - - 0.0196376, - 0.0786361, 1.0982735 -); - -/** - * Defines supported color spaces by transfer function and primaries, - * and provides conversions to/from the Linear-sRGB reference space. - */ -const COLOR_SPACES = { - [ LinearSRGBColorSpace ]: { - transfer: LinearTransfer, - primaries: Rec709Primaries, - toReference: ( color ) => color, - fromReference: ( color ) => color, - }, - [ SRGBColorSpace ]: { - transfer: SRGBTransfer, - primaries: Rec709Primaries, - toReference: ( color ) => color.convertSRGBToLinear(), - fromReference: ( color ) => color.convertLinearToSRGB(), - }, - [ LinearDisplayP3ColorSpace ]: { - transfer: LinearTransfer, - primaries: P3Primaries, - toReference: ( color ) => color.applyMatrix3( LINEAR_DISPLAY_P3_TO_LINEAR_SRGB ), - fromReference: ( color ) => color.applyMatrix3( LINEAR_SRGB_TO_LINEAR_DISPLAY_P3 ), - }, - [ DisplayP3ColorSpace ]: { - transfer: SRGBTransfer, - primaries: P3Primaries, - toReference: ( color ) => color.convertSRGBToLinear().applyMatrix3( LINEAR_DISPLAY_P3_TO_LINEAR_SRGB ), - fromReference: ( color ) => color.applyMatrix3( LINEAR_SRGB_TO_LINEAR_DISPLAY_P3 ).convertLinearToSRGB(), - }, -}; - -const SUPPORTED_WORKING_COLOR_SPACES = new Set( [ LinearSRGBColorSpace, LinearDisplayP3ColorSpace ] ); - -const ColorManagement = { - - enabled: true, - - _workingColorSpace: LinearSRGBColorSpace, - - get workingColorSpace() { - - return this._workingColorSpace; - - }, - - set workingColorSpace( colorSpace ) { - - if ( ! SUPPORTED_WORKING_COLOR_SPACES.has( colorSpace ) ) { - - throw new Error( `Unsupported working color space, "${ colorSpace }".` ); - - } - - this._workingColorSpace = colorSpace; - - }, - - convert: function ( color, sourceColorSpace, targetColorSpace ) { - - if ( this.enabled === false || sourceColorSpace === targetColorSpace || ! sourceColorSpace || ! targetColorSpace ) { - - return color; - - } - - const sourceToReference = COLOR_SPACES[ sourceColorSpace ].toReference; - const targetFromReference = COLOR_SPACES[ targetColorSpace ].fromReference; - - return targetFromReference( sourceToReference( color ) ); - - }, - - fromWorkingColorSpace: function ( color, targetColorSpace ) { - - return this.convert( color, this._workingColorSpace, targetColorSpace ); - - }, - - toWorkingColorSpace: function ( color, sourceColorSpace ) { - - return this.convert( color, sourceColorSpace, this._workingColorSpace ); - - }, - - getPrimaries: function ( colorSpace ) { - - return COLOR_SPACES[ colorSpace ].primaries; - - }, - - getTransfer: function ( colorSpace ) { - - if ( colorSpace === NoColorSpace ) return LinearTransfer; - - return COLOR_SPACES[ colorSpace ].transfer; - - }, - -}; - - -function SRGBToLinear( c ) { - - return ( c < 0.04045 ) ? c * 0.0773993808 : Math.pow( c * 0.9478672986 + 0.0521327014, 2.4 ); - -} - -function LinearToSRGB( c ) { - - return ( c < 0.0031308 ) ? c * 12.92 : 1.055 * ( Math.pow( c, 0.41666 ) ) - 0.055; - -} - -let _canvas; - -class ImageUtils { - - static getDataURL( image ) { - - if ( /^data:/i.test( image.src ) ) { - - return image.src; - - } - - if ( typeof HTMLCanvasElement === 'undefined' ) { - - return image.src; - - } - - let canvas; - - if ( image instanceof HTMLCanvasElement ) { - - canvas = image; - - } else { - - if ( _canvas === undefined ) _canvas = createElementNS( 'canvas' ); - - _canvas.width = image.width; - _canvas.height = image.height; - - const context = _canvas.getContext( '2d' ); - - if ( image instanceof ImageData ) { - - context.putImageData( image, 0, 0 ); - - } else { - - context.drawImage( image, 0, 0, image.width, image.height ); - - } - - canvas = _canvas; - - } - - if ( canvas.width > 2048 || canvas.height > 2048 ) { - - console.warn( 'THREE.ImageUtils.getDataURL: Image converted to jpg for performance reasons', image ); - - return canvas.toDataURL( 'image/jpeg', 0.6 ); - - } else { - - return canvas.toDataURL( 'image/png' ); - - } - - } - - static sRGBToLinear( image ) { - - if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) || - ( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) || - ( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) { - - const canvas = createElementNS( 'canvas' ); - - canvas.width = image.width; - canvas.height = image.height; - - const context = canvas.getContext( '2d' ); - context.drawImage( image, 0, 0, image.width, image.height ); - - const imageData = context.getImageData( 0, 0, image.width, image.height ); - const data = imageData.data; - - for ( let i = 0; i < data.length; i ++ ) { - - data[ i ] = SRGBToLinear( data[ i ] / 255 ) * 255; - - } - - context.putImageData( imageData, 0, 0 ); - - return canvas; - - } else if ( image.data ) { - - const data = image.data.slice( 0 ); - - for ( let i = 0; i < data.length; i ++ ) { - - if ( data instanceof Uint8Array || data instanceof Uint8ClampedArray ) { - - data[ i ] = Math.floor( SRGBToLinear( data[ i ] / 255 ) * 255 ); - - } else { - - // assuming float - - data[ i ] = SRGBToLinear( data[ i ] ); - - } - - } - - return { - data: data, - width: image.width, - height: image.height - }; - - } else { - - console.warn( 'THREE.ImageUtils.sRGBToLinear(): Unsupported image type. No color space conversion applied.' ); - return image; - - } - - } - -} - -let _sourceId = 0; - -class Source { - - constructor( data = null ) { - - this.isSource = true; - - Object.defineProperty( this, 'id', { value: _sourceId ++ } ); - - this.uuid = generateUUID(); - - this.data = data; - this.dataReady = true; - - this.version = 0; - - } - - set needsUpdate( value ) { - - if ( value === true ) this.version ++; - - } - - toJSON( meta ) { - - const isRootObject = ( meta === undefined || typeof meta === 'string' ); - - if ( ! isRootObject && meta.images[ this.uuid ] !== undefined ) { - - return meta.images[ this.uuid ]; - - } - - const output = { - uuid: this.uuid, - url: '' - }; - - const data = this.data; - - if ( data !== null ) { - - let url; - - if ( Array.isArray( data ) ) { - - // cube texture - - url = []; - - for ( let i = 0, l = data.length; i < l; i ++ ) { - - if ( data[ i ].isDataTexture ) { - - url.push( serializeImage( data[ i ].image ) ); - - } else { - - url.push( serializeImage( data[ i ] ) ); - - } - - } - - } else { - - // texture - - url = serializeImage( data ); - - } - - output.url = url; - - } - - if ( ! isRootObject ) { - - meta.images[ this.uuid ] = output; - - } - - return output; - - } - -} - -function serializeImage( image ) { - - if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) || - ( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) || - ( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) { - - // default images - - return ImageUtils.getDataURL( image ); - - } else { - - if ( image.data ) { - - // images of DataTexture - - return { - data: Array.from( image.data ), - width: image.width, - height: image.height, - type: image.data.constructor.name - }; - - } else { - - console.warn( 'THREE.Texture: Unable to serialize Texture.' ); - return {}; - - } - - } - -} - -let _textureId = 0; - -class Texture extends EventDispatcher { - - constructor( image = Texture.DEFAULT_IMAGE, mapping = Texture.DEFAULT_MAPPING, wrapS = ClampToEdgeWrapping, wrapT = ClampToEdgeWrapping, magFilter = LinearFilter, minFilter = LinearMipmapLinearFilter, format = RGBAFormat, type = UnsignedByteType, anisotropy = Texture.DEFAULT_ANISOTROPY, colorSpace = NoColorSpace ) { - - super(); - - this.isTexture = true; - - Object.defineProperty( this, 'id', { value: _textureId ++ } ); - - this.uuid = generateUUID(); - - this.name = ''; - - this.source = new Source( image ); - this.mipmaps = []; - - this.mapping = mapping; - this.channel = 0; - - this.wrapS = wrapS; - this.wrapT = wrapT; - - this.magFilter = magFilter; - this.minFilter = minFilter; - - this.anisotropy = anisotropy; - - this.format = format; - this.internalFormat = null; - this.type = type; - - this.offset = new Vector2( 0, 0 ); - this.repeat = new Vector2( 1, 1 ); - this.center = new Vector2( 0, 0 ); - this.rotation = 0; - - this.matrixAutoUpdate = true; - this.matrix = new Matrix3(); - - this.generateMipmaps = true; - this.premultiplyAlpha = false; - this.flipY = true; - this.unpackAlignment = 4; // valid values: 1, 2, 4, 8 (see http://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml) - - this.colorSpace = colorSpace; - - this.userData = {}; - - this.version = 0; - this.onUpdate = null; - - this.isRenderTargetTexture = false; // indicates whether a texture belongs to a render target or not - this.needsPMREMUpdate = false; // indicates whether this texture should be processed by PMREMGenerator or not (only relevant for render target textures) - - } - - get image() { - - return this.source.data; - - } - - set image( value = null ) { - - this.source.data = value; - - } - - updateMatrix() { - - this.matrix.setUvTransform( this.offset.x, this.offset.y, this.repeat.x, this.repeat.y, this.rotation, this.center.x, this.center.y ); - - } - - clone() { - - return new this.constructor().copy( this ); - - } - - copy( source ) { - - this.name = source.name; - - this.source = source.source; - this.mipmaps = source.mipmaps.slice( 0 ); - - this.mapping = source.mapping; - this.channel = source.channel; - - this.wrapS = source.wrapS; - this.wrapT = source.wrapT; - - this.magFilter = source.magFilter; - this.minFilter = source.minFilter; - - this.anisotropy = source.anisotropy; - - this.format = source.format; - this.internalFormat = source.internalFormat; - this.type = source.type; - - this.offset.copy( source.offset ); - this.repeat.copy( source.repeat ); - this.center.copy( source.center ); - this.rotation = source.rotation; - - this.matrixAutoUpdate = source.matrixAutoUpdate; - this.matrix.copy( source.matrix ); - - this.generateMipmaps = source.generateMipmaps; - this.premultiplyAlpha = source.premultiplyAlpha; - this.flipY = source.flipY; - this.unpackAlignment = source.unpackAlignment; - this.colorSpace = source.colorSpace; - - this.userData = JSON.parse( JSON.stringify( source.userData ) ); - - this.needsUpdate = true; - - return this; - - } - - toJSON( meta ) { - - const isRootObject = ( meta === undefined || typeof meta === 'string' ); - - if ( ! isRootObject && meta.textures[ this.uuid ] !== undefined ) { - - return meta.textures[ this.uuid ]; - - } - - const output = { - - metadata: { - version: 4.6, - type: 'Texture', - generator: 'Texture.toJSON' - }, - - uuid: this.uuid, - name: this.name, - - image: this.source.toJSON( meta ).uuid, - - mapping: this.mapping, - channel: this.channel, - - repeat: [ this.repeat.x, this.repeat.y ], - offset: [ this.offset.x, this.offset.y ], - center: [ this.center.x, this.center.y ], - rotation: this.rotation, - - wrap: [ this.wrapS, this.wrapT ], - - format: this.format, - internalFormat: this.internalFormat, - type: this.type, - colorSpace: this.colorSpace, - - minFilter: this.minFilter, - magFilter: this.magFilter, - anisotropy: this.anisotropy, - - flipY: this.flipY, - - generateMipmaps: this.generateMipmaps, - premultiplyAlpha: this.premultiplyAlpha, - unpackAlignment: this.unpackAlignment - - }; - - if ( Object.keys( this.userData ).length > 0 ) output.userData = this.userData; - - if ( ! isRootObject ) { - - meta.textures[ this.uuid ] = output; - - } - - return output; - - } - - dispose() { - - this.dispatchEvent( { type: 'dispose' } ); - - } - - transformUv( uv ) { - - if ( this.mapping !== UVMapping ) return uv; - - uv.applyMatrix3( this.matrix ); - - if ( uv.x < 0 || uv.x > 1 ) { - - switch ( this.wrapS ) { - - case RepeatWrapping: - - uv.x = uv.x - Math.floor( uv.x ); - break; - - case ClampToEdgeWrapping: - - uv.x = uv.x < 0 ? 0 : 1; - break; - - case MirroredRepeatWrapping: - - if ( Math.abs( Math.floor( uv.x ) % 2 ) === 1 ) { - - uv.x = Math.ceil( uv.x ) - uv.x; - - } else { - - uv.x = uv.x - Math.floor( uv.x ); - - } - - break; - - } - - } - - if ( uv.y < 0 || uv.y > 1 ) { - - switch ( this.wrapT ) { - - case RepeatWrapping: - - uv.y = uv.y - Math.floor( uv.y ); - break; - - case ClampToEdgeWrapping: - - uv.y = uv.y < 0 ? 0 : 1; - break; - - case MirroredRepeatWrapping: - - if ( Math.abs( Math.floor( uv.y ) % 2 ) === 1 ) { - - uv.y = Math.ceil( uv.y ) - uv.y; - - } else { - - uv.y = uv.y - Math.floor( uv.y ); - - } - - break; - - } - - } - - if ( this.flipY ) { - - uv.y = 1 - uv.y; - - } - - return uv; - - } - - set needsUpdate( value ) { - - if ( value === true ) { - - this.version ++; - this.source.needsUpdate = true; - - } - - } - -} - -Texture.DEFAULT_IMAGE = null; -Texture.DEFAULT_MAPPING = UVMapping; -Texture.DEFAULT_ANISOTROPY = 1; - -class Vector4 { - - constructor( x = 0, y = 0, z = 0, w = 1 ) { - - Vector4.prototype.isVector4 = true; - - this.x = x; - this.y = y; - this.z = z; - this.w = w; - - } - - get width() { - - return this.z; - - } - - set width( value ) { - - this.z = value; - - } - - get height() { - - return this.w; - - } - - set height( value ) { - - this.w = value; - - } - - set( x, y, z, w ) { - - this.x = x; - this.y = y; - this.z = z; - this.w = w; - - return this; - - } - - setScalar( scalar ) { - - this.x = scalar; - this.y = scalar; - this.z = scalar; - this.w = scalar; - - return this; - - } - - setX( x ) { - - this.x = x; - - return this; - - } - - setY( y ) { - - this.y = y; - - return this; - - } - - setZ( z ) { - - this.z = z; - - return this; - - } - - setW( w ) { - - this.w = w; - - return this; - - } - - setComponent( index, value ) { - - switch ( index ) { - - case 0: this.x = value; break; - case 1: this.y = value; break; - case 2: this.z = value; break; - case 3: this.w = value; break; - default: throw new Error( 'index is out of range: ' + index ); - - } - - return this; - - } - - getComponent( index ) { - - switch ( index ) { - - case 0: return this.x; - case 1: return this.y; - case 2: return this.z; - case 3: return this.w; - default: throw new Error( 'index is out of range: ' + index ); - - } - - } - - clone() { - - return new this.constructor( this.x, this.y, this.z, this.w ); - - } - - copy( v ) { - - this.x = v.x; - this.y = v.y; - this.z = v.z; - this.w = ( v.w !== undefined ) ? v.w : 1; - - return this; - - } - - add( v ) { - - this.x += v.x; - this.y += v.y; - this.z += v.z; - this.w += v.w; - - return this; - - } - - addScalar( s ) { - - this.x += s; - this.y += s; - this.z += s; - this.w += s; - - return this; - - } - - addVectors( a, b ) { - - this.x = a.x + b.x; - this.y = a.y + b.y; - this.z = a.z + b.z; - this.w = a.w + b.w; - - return this; - - } - - addScaledVector( v, s ) { - - this.x += v.x * s; - this.y += v.y * s; - this.z += v.z * s; - this.w += v.w * s; - - return this; - - } - - sub( v ) { - - this.x -= v.x; - this.y -= v.y; - this.z -= v.z; - this.w -= v.w; - - return this; - - } - - subScalar( s ) { - - this.x -= s; - this.y -= s; - this.z -= s; - this.w -= s; - - return this; - - } - - subVectors( a, b ) { - - this.x = a.x - b.x; - this.y = a.y - b.y; - this.z = a.z - b.z; - this.w = a.w - b.w; - - return this; - - } - - multiply( v ) { - - this.x *= v.x; - this.y *= v.y; - this.z *= v.z; - this.w *= v.w; - - return this; - - } - - multiplyScalar( scalar ) { - - this.x *= scalar; - this.y *= scalar; - this.z *= scalar; - this.w *= scalar; - - return this; - - } - - applyMatrix4( m ) { - - const x = this.x, y = this.y, z = this.z, w = this.w; - const e = m.elements; - - this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] * w; - this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] * w; - this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] * w; - this.w = e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] * w; - - return this; - - } - - divideScalar( scalar ) { - - return this.multiplyScalar( 1 / scalar ); - - } - - setAxisAngleFromQuaternion( q ) { - - // http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm - - // q is assumed to be normalized - - this.w = 2 * Math.acos( q.w ); - - const s = Math.sqrt( 1 - q.w * q.w ); - - if ( s < 0.0001 ) { - - this.x = 1; - this.y = 0; - this.z = 0; - - } else { - - this.x = q.x / s; - this.y = q.y / s; - this.z = q.z / s; - - } - - return this; - - } - - setAxisAngleFromRotationMatrix( m ) { - - // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm - - // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) - - let angle, x, y, z; // variables for result - const epsilon = 0.01, // margin to allow for rounding errors - epsilon2 = 0.1, // margin to distinguish between 0 and 180 degrees - - te = m.elements, - - m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ], - m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ], - m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ]; - - if ( ( Math.abs( m12 - m21 ) < epsilon ) && - ( Math.abs( m13 - m31 ) < epsilon ) && - ( Math.abs( m23 - m32 ) < epsilon ) ) { - - // singularity found - // first check for identity matrix which must have +1 for all terms - // in leading diagonal and zero in other terms - - if ( ( Math.abs( m12 + m21 ) < epsilon2 ) && - ( Math.abs( m13 + m31 ) < epsilon2 ) && - ( Math.abs( m23 + m32 ) < epsilon2 ) && - ( Math.abs( m11 + m22 + m33 - 3 ) < epsilon2 ) ) { - - // this singularity is identity matrix so angle = 0 - - this.set( 1, 0, 0, 0 ); - - return this; // zero angle, arbitrary axis - - } - - // otherwise this singularity is angle = 180 - - angle = Math.PI; - - const xx = ( m11 + 1 ) / 2; - const yy = ( m22 + 1 ) / 2; - const zz = ( m33 + 1 ) / 2; - const xy = ( m12 + m21 ) / 4; - const xz = ( m13 + m31 ) / 4; - const yz = ( m23 + m32 ) / 4; - - if ( ( xx > yy ) && ( xx > zz ) ) { - - // m11 is the largest diagonal term - - if ( xx < epsilon ) { - - x = 0; - y = 0.707106781; - z = 0.707106781; - - } else { - - x = Math.sqrt( xx ); - y = xy / x; - z = xz / x; - - } - - } else if ( yy > zz ) { - - // m22 is the largest diagonal term - - if ( yy < epsilon ) { - - x = 0.707106781; - y = 0; - z = 0.707106781; - - } else { - - y = Math.sqrt( yy ); - x = xy / y; - z = yz / y; - - } - - } else { - - // m33 is the largest diagonal term so base result on this - - if ( zz < epsilon ) { - - x = 0.707106781; - y = 0.707106781; - z = 0; - - } else { - - z = Math.sqrt( zz ); - x = xz / z; - y = yz / z; - - } - - } - - this.set( x, y, z, angle ); - - return this; // return 180 deg rotation - - } - - // as we have reached here there are no singularities so we can handle normally - - let s = Math.sqrt( ( m32 - m23 ) * ( m32 - m23 ) + - ( m13 - m31 ) * ( m13 - m31 ) + - ( m21 - m12 ) * ( m21 - m12 ) ); // used to normalize - - if ( Math.abs( s ) < 0.001 ) s = 1; - - // prevent divide by zero, should not happen if matrix is orthogonal and should be - // caught by singularity test above, but I've left it in just in case - - this.x = ( m32 - m23 ) / s; - this.y = ( m13 - m31 ) / s; - this.z = ( m21 - m12 ) / s; - this.w = Math.acos( ( m11 + m22 + m33 - 1 ) / 2 ); - - return this; - - } - - min( v ) { - - this.x = Math.min( this.x, v.x ); - this.y = Math.min( this.y, v.y ); - this.z = Math.min( this.z, v.z ); - this.w = Math.min( this.w, v.w ); - - return this; - - } - - max( v ) { - - this.x = Math.max( this.x, v.x ); - this.y = Math.max( this.y, v.y ); - this.z = Math.max( this.z, v.z ); - this.w = Math.max( this.w, v.w ); - - return this; - - } - - clamp( min, max ) { - - // assumes min < max, componentwise - - this.x = Math.max( min.x, Math.min( max.x, this.x ) ); - this.y = Math.max( min.y, Math.min( max.y, this.y ) ); - this.z = Math.max( min.z, Math.min( max.z, this.z ) ); - this.w = Math.max( min.w, Math.min( max.w, this.w ) ); - - return this; - - } - - clampScalar( minVal, maxVal ) { - - this.x = Math.max( minVal, Math.min( maxVal, this.x ) ); - this.y = Math.max( minVal, Math.min( maxVal, this.y ) ); - this.z = Math.max( minVal, Math.min( maxVal, this.z ) ); - this.w = Math.max( minVal, Math.min( maxVal, this.w ) ); - - return this; - - } - - clampLength( min, max ) { - - const length = this.length(); - - return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) ); - - } - - floor() { - - this.x = Math.floor( this.x ); - this.y = Math.floor( this.y ); - this.z = Math.floor( this.z ); - this.w = Math.floor( this.w ); - - return this; - - } - - ceil() { - - this.x = Math.ceil( this.x ); - this.y = Math.ceil( this.y ); - this.z = Math.ceil( this.z ); - this.w = Math.ceil( this.w ); - - return this; - - } - - round() { - - this.x = Math.round( this.x ); - this.y = Math.round( this.y ); - this.z = Math.round( this.z ); - this.w = Math.round( this.w ); - - return this; - - } - - roundToZero() { - - this.x = Math.trunc( this.x ); - this.y = Math.trunc( this.y ); - this.z = Math.trunc( this.z ); - this.w = Math.trunc( this.w ); - - return this; - - } - - negate() { - - this.x = - this.x; - this.y = - this.y; - this.z = - this.z; - this.w = - this.w; - - return this; - - } - - dot( v ) { - - return this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w; - - } - - lengthSq() { - - return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w; - - } - - length() { - - return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w ); - - } - - manhattanLength() { - - return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ) + Math.abs( this.w ); - - } - - normalize() { - - return this.divideScalar( this.length() || 1 ); - - } - - setLength( length ) { - - return this.normalize().multiplyScalar( length ); - - } - - lerp( v, alpha ) { - - this.x += ( v.x - this.x ) * alpha; - this.y += ( v.y - this.y ) * alpha; - this.z += ( v.z - this.z ) * alpha; - this.w += ( v.w - this.w ) * alpha; - - return this; - - } - - lerpVectors( v1, v2, alpha ) { - - this.x = v1.x + ( v2.x - v1.x ) * alpha; - this.y = v1.y + ( v2.y - v1.y ) * alpha; - this.z = v1.z + ( v2.z - v1.z ) * alpha; - this.w = v1.w + ( v2.w - v1.w ) * alpha; - - return this; - - } - - equals( v ) { - - return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) && ( v.w === this.w ) ); - - } - - fromArray( array, offset = 0 ) { - - this.x = array[ offset ]; - this.y = array[ offset + 1 ]; - this.z = array[ offset + 2 ]; - this.w = array[ offset + 3 ]; - - return this; - - } - - toArray( array = [], offset = 0 ) { - - array[ offset ] = this.x; - array[ offset + 1 ] = this.y; - array[ offset + 2 ] = this.z; - array[ offset + 3 ] = this.w; - - return array; - - } - - fromBufferAttribute( attribute, index ) { - - this.x = attribute.getX( index ); - this.y = attribute.getY( index ); - this.z = attribute.getZ( index ); - this.w = attribute.getW( index ); - - return this; - - } - - random() { - - this.x = Math.random(); - this.y = Math.random(); - this.z = Math.random(); - this.w = Math.random(); - - return this; - - } - - *[ Symbol.iterator ]() { - - yield this.x; - yield this.y; - yield this.z; - yield this.w; - - } - -} - -/* - In options, we can specify: - * Texture parameters for an auto-generated target texture - * depthBuffer/stencilBuffer: Booleans to indicate if we should generate these buffers -*/ -class RenderTarget extends EventDispatcher { - - constructor( width = 1, height = 1, options = {} ) { - - super(); - - this.isRenderTarget = true; - - this.width = width; - this.height = height; - this.depth = 1; - - this.scissor = new Vector4( 0, 0, width, height ); - this.scissorTest = false; - - this.viewport = new Vector4( 0, 0, width, height ); - - const image = { width: width, height: height, depth: 1 }; - - options = Object.assign( { - generateMipmaps: false, - internalFormat: null, - minFilter: LinearFilter, - depthBuffer: true, - stencilBuffer: false, - depthTexture: null, - samples: 0 - }, options ); - - this.texture = new Texture( image, options.mapping, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.colorSpace ); - this.texture.isRenderTargetTexture = true; - - this.texture.flipY = false; - this.texture.generateMipmaps = options.generateMipmaps; - this.texture.internalFormat = options.internalFormat; - - this.depthBuffer = options.depthBuffer; - this.stencilBuffer = options.stencilBuffer; - - this.depthTexture = options.depthTexture; - - this.samples = options.samples; - - } - - setSize( width, height, depth = 1 ) { - - if ( this.width !== width || this.height !== height || this.depth !== depth ) { - - this.width = width; - this.height = height; - this.depth = depth; - - this.texture.image.width = width; - this.texture.image.height = height; - this.texture.image.depth = depth; - - this.dispose(); - - } - - this.viewport.set( 0, 0, width, height ); - this.scissor.set( 0, 0, width, height ); - - } - - clone() { - - return new this.constructor().copy( this ); - - } - - copy( source ) { - - this.width = source.width; - this.height = source.height; - this.depth = source.depth; - - this.scissor.copy( source.scissor ); - this.scissorTest = source.scissorTest; - - this.viewport.copy( source.viewport ); - - this.texture = source.texture.clone(); - this.texture.isRenderTargetTexture = true; - - // ensure image object is not shared, see #20328 - - const image = Object.assign( {}, source.texture.image ); - this.texture.source = new Source( image ); - - this.depthBuffer = source.depthBuffer; - this.stencilBuffer = source.stencilBuffer; - - if ( source.depthTexture !== null ) this.depthTexture = source.depthTexture.clone(); - - this.samples = source.samples; - - return this; - - } - - dispose() { - - this.dispatchEvent( { type: 'dispose' } ); - - } - -} - -class WebGLRenderTarget extends RenderTarget { - - constructor( width = 1, height = 1, options = {} ) { - - super( width, height, options ); - - this.isWebGLRenderTarget = true; - - } - -} - -class DataArrayTexture extends Texture { - - constructor( data = null, width = 1, height = 1, depth = 1 ) { - - super( null ); - - this.isDataArrayTexture = true; - - this.image = { data, width, height, depth }; - - this.magFilter = NearestFilter; - this.minFilter = NearestFilter; - - this.wrapR = ClampToEdgeWrapping; - - this.generateMipmaps = false; - this.flipY = false; - this.unpackAlignment = 1; - - } - -} - -class WebGLArrayRenderTarget extends WebGLRenderTarget { - - constructor( width = 1, height = 1, depth = 1, options = {} ) { - - super( width, height, options ); - - this.isWebGLArrayRenderTarget = true; - - this.depth = depth; - - this.texture = new DataArrayTexture( null, width, height, depth ); - - this.texture.isRenderTargetTexture = true; - - } - -} - -class Data3DTexture extends Texture { - - constructor( data = null, width = 1, height = 1, depth = 1 ) { - - // We're going to add .setXXX() methods for setting properties later. - // Users can still set in DataTexture3D directly. - // - // const texture = new THREE.DataTexture3D( data, width, height, depth ); - // texture.anisotropy = 16; - // - // See #14839 - - super( null ); - - this.isData3DTexture = true; - - this.image = { data, width, height, depth }; - - this.magFilter = NearestFilter; - this.minFilter = NearestFilter; - - this.wrapR = ClampToEdgeWrapping; - - this.generateMipmaps = false; - this.flipY = false; - this.unpackAlignment = 1; - - } - -} - -class WebGL3DRenderTarget extends WebGLRenderTarget { - - constructor( width = 1, height = 1, depth = 1, options = {} ) { - - super( width, height, options ); - - this.isWebGL3DRenderTarget = true; - - this.depth = depth; - - this.texture = new Data3DTexture( null, width, height, depth ); - - this.texture.isRenderTargetTexture = true; - - } - -} - -class WebGLMultipleRenderTargets extends WebGLRenderTarget { - - constructor( width = 1, height = 1, count = 1, options = {} ) { - - super( width, height, options ); - - this.isWebGLMultipleRenderTargets = true; - - const texture = this.texture; - - this.texture = []; - - for ( let i = 0; i < count; i ++ ) { - - this.texture[ i ] = texture.clone(); - this.texture[ i ].isRenderTargetTexture = true; - - } - - } - - setSize( width, height, depth = 1 ) { - - if ( this.width !== width || this.height !== height || this.depth !== depth ) { - - this.width = width; - this.height = height; - this.depth = depth; - - for ( let i = 0, il = this.texture.length; i < il; i ++ ) { - - this.texture[ i ].image.width = width; - this.texture[ i ].image.height = height; - this.texture[ i ].image.depth = depth; - - } - - this.dispose(); - - } - - this.viewport.set( 0, 0, width, height ); - this.scissor.set( 0, 0, width, height ); - - } - - copy( source ) { - - this.dispose(); - - this.width = source.width; - this.height = source.height; - this.depth = source.depth; - - this.scissor.copy( source.scissor ); - this.scissorTest = source.scissorTest; - - this.viewport.copy( source.viewport ); - - this.depthBuffer = source.depthBuffer; - this.stencilBuffer = source.stencilBuffer; - - if ( source.depthTexture !== null ) this.depthTexture = source.depthTexture.clone(); - - this.texture.length = 0; - - for ( let i = 0, il = source.texture.length; i < il; i ++ ) { - - this.texture[ i ] = source.texture[ i ].clone(); - this.texture[ i ].isRenderTargetTexture = true; - - } - - return this; - - } - -} - -class Quaternion { - - constructor( x = 0, y = 0, z = 0, w = 1 ) { - - this.isQuaternion = true; - - this._x = x; - this._y = y; - this._z = z; - this._w = w; - - } - - static slerpFlat( dst, dstOffset, src0, srcOffset0, src1, srcOffset1, t ) { - - // fuzz-free, array-based Quaternion SLERP operation - - let x0 = src0[ srcOffset0 + 0 ], - y0 = src0[ srcOffset0 + 1 ], - z0 = src0[ srcOffset0 + 2 ], - w0 = src0[ srcOffset0 + 3 ]; - - const x1 = src1[ srcOffset1 + 0 ], - y1 = src1[ srcOffset1 + 1 ], - z1 = src1[ srcOffset1 + 2 ], - w1 = src1[ srcOffset1 + 3 ]; - - if ( t === 0 ) { - - dst[ dstOffset + 0 ] = x0; - dst[ dstOffset + 1 ] = y0; - dst[ dstOffset + 2 ] = z0; - dst[ dstOffset + 3 ] = w0; - return; - - } - - if ( t === 1 ) { - - dst[ dstOffset + 0 ] = x1; - dst[ dstOffset + 1 ] = y1; - dst[ dstOffset + 2 ] = z1; - dst[ dstOffset + 3 ] = w1; - return; - - } - - if ( w0 !== w1 || x0 !== x1 || y0 !== y1 || z0 !== z1 ) { - - let s = 1 - t; - const cos = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1, - dir = ( cos >= 0 ? 1 : - 1 ), - sqrSin = 1 - cos * cos; - - // Skip the Slerp for tiny steps to avoid numeric problems: - if ( sqrSin > Number.EPSILON ) { - - const sin = Math.sqrt( sqrSin ), - len = Math.atan2( sin, cos * dir ); - - s = Math.sin( s * len ) / sin; - t = Math.sin( t * len ) / sin; - - } - - const tDir = t * dir; - - x0 = x0 * s + x1 * tDir; - y0 = y0 * s + y1 * tDir; - z0 = z0 * s + z1 * tDir; - w0 = w0 * s + w1 * tDir; - - // Normalize in case we just did a lerp: - if ( s === 1 - t ) { - - const f = 1 / Math.sqrt( x0 * x0 + y0 * y0 + z0 * z0 + w0 * w0 ); - - x0 *= f; - y0 *= f; - z0 *= f; - w0 *= f; - - } - - } - - dst[ dstOffset ] = x0; - dst[ dstOffset + 1 ] = y0; - dst[ dstOffset + 2 ] = z0; - dst[ dstOffset + 3 ] = w0; - - } - - static multiplyQuaternionsFlat( dst, dstOffset, src0, srcOffset0, src1, srcOffset1 ) { - - const x0 = src0[ srcOffset0 ]; - const y0 = src0[ srcOffset0 + 1 ]; - const z0 = src0[ srcOffset0 + 2 ]; - const w0 = src0[ srcOffset0 + 3 ]; - - const x1 = src1[ srcOffset1 ]; - const y1 = src1[ srcOffset1 + 1 ]; - const z1 = src1[ srcOffset1 + 2 ]; - const w1 = src1[ srcOffset1 + 3 ]; - - dst[ dstOffset ] = x0 * w1 + w0 * x1 + y0 * z1 - z0 * y1; - dst[ dstOffset + 1 ] = y0 * w1 + w0 * y1 + z0 * x1 - x0 * z1; - dst[ dstOffset + 2 ] = z0 * w1 + w0 * z1 + x0 * y1 - y0 * x1; - dst[ dstOffset + 3 ] = w0 * w1 - x0 * x1 - y0 * y1 - z0 * z1; - - return dst; - - } - - get x() { - - return this._x; - - } - - set x( value ) { - - this._x = value; - this._onChangeCallback(); - - } - - get y() { - - return this._y; - - } - - set y( value ) { - - this._y = value; - this._onChangeCallback(); - - } - - get z() { - - return this._z; - - } - - set z( value ) { - - this._z = value; - this._onChangeCallback(); - - } - - get w() { - - return this._w; - - } - - set w( value ) { - - this._w = value; - this._onChangeCallback(); - - } - - set( x, y, z, w ) { - - this._x = x; - this._y = y; - this._z = z; - this._w = w; - - this._onChangeCallback(); - - return this; - - } - - clone() { - - return new this.constructor( this._x, this._y, this._z, this._w ); - - } - - copy( quaternion ) { - - this._x = quaternion.x; - this._y = quaternion.y; - this._z = quaternion.z; - this._w = quaternion.w; - - this._onChangeCallback(); - - return this; - - } - - setFromEuler( euler, update = true ) { - - const x = euler._x, y = euler._y, z = euler._z, order = euler._order; - - // http://www.mathworks.com/matlabcentral/fileexchange/ - // 20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/ - // content/SpinCalc.m - - const cos = Math.cos; - const sin = Math.sin; - - const c1 = cos( x / 2 ); - const c2 = cos( y / 2 ); - const c3 = cos( z / 2 ); - - const s1 = sin( x / 2 ); - const s2 = sin( y / 2 ); - const s3 = sin( z / 2 ); - - switch ( order ) { - - case 'XYZ': - this._x = s1 * c2 * c3 + c1 * s2 * s3; - this._y = c1 * s2 * c3 - s1 * c2 * s3; - this._z = c1 * c2 * s3 + s1 * s2 * c3; - this._w = c1 * c2 * c3 - s1 * s2 * s3; - break; - - case 'YXZ': - this._x = s1 * c2 * c3 + c1 * s2 * s3; - this._y = c1 * s2 * c3 - s1 * c2 * s3; - this._z = c1 * c2 * s3 - s1 * s2 * c3; - this._w = c1 * c2 * c3 + s1 * s2 * s3; - break; - - case 'ZXY': - this._x = s1 * c2 * c3 - c1 * s2 * s3; - this._y = c1 * s2 * c3 + s1 * c2 * s3; - this._z = c1 * c2 * s3 + s1 * s2 * c3; - this._w = c1 * c2 * c3 - s1 * s2 * s3; - break; - - case 'ZYX': - this._x = s1 * c2 * c3 - c1 * s2 * s3; - this._y = c1 * s2 * c3 + s1 * c2 * s3; - this._z = c1 * c2 * s3 - s1 * s2 * c3; - this._w = c1 * c2 * c3 + s1 * s2 * s3; - break; - - case 'YZX': - this._x = s1 * c2 * c3 + c1 * s2 * s3; - this._y = c1 * s2 * c3 + s1 * c2 * s3; - this._z = c1 * c2 * s3 - s1 * s2 * c3; - this._w = c1 * c2 * c3 - s1 * s2 * s3; - break; - - case 'XZY': - this._x = s1 * c2 * c3 - c1 * s2 * s3; - this._y = c1 * s2 * c3 - s1 * c2 * s3; - this._z = c1 * c2 * s3 + s1 * s2 * c3; - this._w = c1 * c2 * c3 + s1 * s2 * s3; - break; - - default: - console.warn( 'THREE.Quaternion: .setFromEuler() encountered an unknown order: ' + order ); - - } - - if ( update === true ) this._onChangeCallback(); - - return this; - - } - - setFromAxisAngle( axis, angle ) { - - // http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm - - // assumes axis is normalized - - const halfAngle = angle / 2, s = Math.sin( halfAngle ); - - this._x = axis.x * s; - this._y = axis.y * s; - this._z = axis.z * s; - this._w = Math.cos( halfAngle ); - - this._onChangeCallback(); - - return this; - - } - - setFromRotationMatrix( m ) { - - // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm - - // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) - - const te = m.elements, - - m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ], - m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ], - m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ], - - trace = m11 + m22 + m33; - - if ( trace > 0 ) { - - const s = 0.5 / Math.sqrt( trace + 1.0 ); - - this._w = 0.25 / s; - this._x = ( m32 - m23 ) * s; - this._y = ( m13 - m31 ) * s; - this._z = ( m21 - m12 ) * s; - - } else if ( m11 > m22 && m11 > m33 ) { - - const s = 2.0 * Math.sqrt( 1.0 + m11 - m22 - m33 ); - - this._w = ( m32 - m23 ) / s; - this._x = 0.25 * s; - this._y = ( m12 + m21 ) / s; - this._z = ( m13 + m31 ) / s; - - } else if ( m22 > m33 ) { - - const s = 2.0 * Math.sqrt( 1.0 + m22 - m11 - m33 ); - - this._w = ( m13 - m31 ) / s; - this._x = ( m12 + m21 ) / s; - this._y = 0.25 * s; - this._z = ( m23 + m32 ) / s; - - } else { - - const s = 2.0 * Math.sqrt( 1.0 + m33 - m11 - m22 ); - - this._w = ( m21 - m12 ) / s; - this._x = ( m13 + m31 ) / s; - this._y = ( m23 + m32 ) / s; - this._z = 0.25 * s; - - } - - this._onChangeCallback(); - - return this; - - } - - setFromUnitVectors( vFrom, vTo ) { - - // assumes direction vectors vFrom and vTo are normalized - - let r = vFrom.dot( vTo ) + 1; - - if ( r < Number.EPSILON ) { - - // vFrom and vTo point in opposite directions - - r = 0; - - if ( Math.abs( vFrom.x ) > Math.abs( vFrom.z ) ) { - - this._x = - vFrom.y; - this._y = vFrom.x; - this._z = 0; - this._w = r; - - } else { - - this._x = 0; - this._y = - vFrom.z; - this._z = vFrom.y; - this._w = r; - - } - - } else { - - // crossVectors( vFrom, vTo ); // inlined to avoid cyclic dependency on Vector3 - - this._x = vFrom.y * vTo.z - vFrom.z * vTo.y; - this._y = vFrom.z * vTo.x - vFrom.x * vTo.z; - this._z = vFrom.x * vTo.y - vFrom.y * vTo.x; - this._w = r; - - } - - return this.normalize(); - - } - - angleTo( q ) { - - return 2 * Math.acos( Math.abs( clamp( this.dot( q ), - 1, 1 ) ) ); - - } - - rotateTowards( q, step ) { - - const angle = this.angleTo( q ); - - if ( angle === 0 ) return this; - - const t = Math.min( 1, step / angle ); - - this.slerp( q, t ); - - return this; - - } - - identity() { - - return this.set( 0, 0, 0, 1 ); - - } - - invert() { - - // quaternion is assumed to have unit length - - return this.conjugate(); - - } - - conjugate() { - - this._x *= - 1; - this._y *= - 1; - this._z *= - 1; - - this._onChangeCallback(); - - return this; - - } - - dot( v ) { - - return this._x * v._x + this._y * v._y + this._z * v._z + this._w * v._w; - - } - - lengthSq() { - - return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w; - - } - - length() { - - return Math.sqrt( this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w ); - - } - - normalize() { - - let l = this.length(); - - if ( l === 0 ) { - - this._x = 0; - this._y = 0; - this._z = 0; - this._w = 1; - - } else { - - l = 1 / l; - - this._x = this._x * l; - this._y = this._y * l; - this._z = this._z * l; - this._w = this._w * l; - - } - - this._onChangeCallback(); - - return this; - - } - - multiply( q ) { - - return this.multiplyQuaternions( this, q ); - - } - - premultiply( q ) { - - return this.multiplyQuaternions( q, this ); - - } - - multiplyQuaternions( a, b ) { - - // from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm - - const qax = a._x, qay = a._y, qaz = a._z, qaw = a._w; - const qbx = b._x, qby = b._y, qbz = b._z, qbw = b._w; - - this._x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby; - this._y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz; - this._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx; - this._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz; - - this._onChangeCallback(); - - return this; - - } - - slerp( qb, t ) { - - if ( t === 0 ) return this; - if ( t === 1 ) return this.copy( qb ); - - const x = this._x, y = this._y, z = this._z, w = this._w; - - // http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/ - - let cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z; - - if ( cosHalfTheta < 0 ) { - - this._w = - qb._w; - this._x = - qb._x; - this._y = - qb._y; - this._z = - qb._z; - - cosHalfTheta = - cosHalfTheta; - - } else { - - this.copy( qb ); - - } - - if ( cosHalfTheta >= 1.0 ) { - - this._w = w; - this._x = x; - this._y = y; - this._z = z; - - return this; - - } - - const sqrSinHalfTheta = 1.0 - cosHalfTheta * cosHalfTheta; - - if ( sqrSinHalfTheta <= Number.EPSILON ) { - - const s = 1 - t; - this._w = s * w + t * this._w; - this._x = s * x + t * this._x; - this._y = s * y + t * this._y; - this._z = s * z + t * this._z; - - this.normalize(); // normalize calls _onChangeCallback() - - return this; - - } - - const sinHalfTheta = Math.sqrt( sqrSinHalfTheta ); - const halfTheta = Math.atan2( sinHalfTheta, cosHalfTheta ); - const ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta, - ratioB = Math.sin( t * halfTheta ) / sinHalfTheta; - - this._w = ( w * ratioA + this._w * ratioB ); - this._x = ( x * ratioA + this._x * ratioB ); - this._y = ( y * ratioA + this._y * ratioB ); - this._z = ( z * ratioA + this._z * ratioB ); - - this._onChangeCallback(); - - return this; - - } - - slerpQuaternions( qa, qb, t ) { - - return this.copy( qa ).slerp( qb, t ); - - } - - random() { - - // Derived from http://planning.cs.uiuc.edu/node198.html - // Note, this source uses w, x, y, z ordering, - // so we swap the order below. - - const u1 = Math.random(); - const sqrt1u1 = Math.sqrt( 1 - u1 ); - const sqrtu1 = Math.sqrt( u1 ); - - const u2 = 2 * Math.PI * Math.random(); - - const u3 = 2 * Math.PI * Math.random(); - - return this.set( - sqrt1u1 * Math.cos( u2 ), - sqrtu1 * Math.sin( u3 ), - sqrtu1 * Math.cos( u3 ), - sqrt1u1 * Math.sin( u2 ), - ); - - } - - equals( quaternion ) { - - return ( quaternion._x === this._x ) && ( quaternion._y === this._y ) && ( quaternion._z === this._z ) && ( quaternion._w === this._w ); - - } - - fromArray( array, offset = 0 ) { - - this._x = array[ offset ]; - this._y = array[ offset + 1 ]; - this._z = array[ offset + 2 ]; - this._w = array[ offset + 3 ]; - - this._onChangeCallback(); - - return this; - - } - - toArray( array = [], offset = 0 ) { - - array[ offset ] = this._x; - array[ offset + 1 ] = this._y; - array[ offset + 2 ] = this._z; - array[ offset + 3 ] = this._w; - - return array; - - } - - fromBufferAttribute( attribute, index ) { - - this._x = attribute.getX( index ); - this._y = attribute.getY( index ); - this._z = attribute.getZ( index ); - this._w = attribute.getW( index ); - - this._onChangeCallback(); - - return this; - - } - - toJSON() { - - return this.toArray(); - - } - - _onChange( callback ) { - - this._onChangeCallback = callback; - - return this; - - } - - _onChangeCallback() {} - - *[ Symbol.iterator ]() { - - yield this._x; - yield this._y; - yield this._z; - yield this._w; - - } - -} - -class Vector3 { - - constructor( x = 0, y = 0, z = 0 ) { - - Vector3.prototype.isVector3 = true; - - this.x = x; - this.y = y; - this.z = z; - - } - - set( x, y, z ) { - - if ( z === undefined ) z = this.z; // sprite.scale.set(x,y) - - this.x = x; - this.y = y; - this.z = z; - - return this; - - } - - setScalar( scalar ) { - - this.x = scalar; - this.y = scalar; - this.z = scalar; - - return this; - - } - - setX( x ) { - - this.x = x; - - return this; - - } - - setY( y ) { - - this.y = y; - - return this; - - } - - setZ( z ) { - - this.z = z; - - return this; - - } - - setComponent( index, value ) { - - switch ( index ) { - - case 0: this.x = value; break; - case 1: this.y = value; break; - case 2: this.z = value; break; - default: throw new Error( 'index is out of range: ' + index ); - - } - - return this; - - } - - getComponent( index ) { - - switch ( index ) { - - case 0: return this.x; - case 1: return this.y; - case 2: return this.z; - default: throw new Error( 'index is out of range: ' + index ); - - } - - } - - clone() { - - return new this.constructor( this.x, this.y, this.z ); - - } - - copy( v ) { - - this.x = v.x; - this.y = v.y; - this.z = v.z; - - return this; - - } - - add( v ) { - - this.x += v.x; - this.y += v.y; - this.z += v.z; - - return this; - - } - - addScalar( s ) { - - this.x += s; - this.y += s; - this.z += s; - - return this; - - } - - addVectors( a, b ) { - - this.x = a.x + b.x; - this.y = a.y + b.y; - this.z = a.z + b.z; - - return this; - - } - - addScaledVector( v, s ) { - - this.x += v.x * s; - this.y += v.y * s; - this.z += v.z * s; - - return this; - - } - - sub( v ) { - - this.x -= v.x; - this.y -= v.y; - this.z -= v.z; - - return this; - - } - - subScalar( s ) { - - this.x -= s; - this.y -= s; - this.z -= s; - - return this; - - } - - subVectors( a, b ) { - - this.x = a.x - b.x; - this.y = a.y - b.y; - this.z = a.z - b.z; - - return this; - - } - - multiply( v ) { - - this.x *= v.x; - this.y *= v.y; - this.z *= v.z; - - return this; - - } - - multiplyScalar( scalar ) { - - this.x *= scalar; - this.y *= scalar; - this.z *= scalar; - - return this; - - } - - multiplyVectors( a, b ) { - - this.x = a.x * b.x; - this.y = a.y * b.y; - this.z = a.z * b.z; - - return this; - - } - - applyEuler( euler ) { - - return this.applyQuaternion( _quaternion$4.setFromEuler( euler ) ); - - } - - applyAxisAngle( axis, angle ) { - - return this.applyQuaternion( _quaternion$4.setFromAxisAngle( axis, angle ) ); - - } - - applyMatrix3( m ) { - - const x = this.x, y = this.y, z = this.z; - const e = m.elements; - - this.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ] * z; - this.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ] * z; - this.z = e[ 2 ] * x + e[ 5 ] * y + e[ 8 ] * z; - - return this; - - } - - applyNormalMatrix( m ) { - - return this.applyMatrix3( m ).normalize(); - - } - - applyMatrix4( m ) { - - const x = this.x, y = this.y, z = this.z; - const e = m.elements; - - const w = 1 / ( e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] ); - - this.x = ( e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] ) * w; - this.y = ( e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] ) * w; - this.z = ( e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] ) * w; - - return this; - - } - - applyQuaternion( q ) { - - // quaternion q is assumed to have unit length - - const vx = this.x, vy = this.y, vz = this.z; - const qx = q.x, qy = q.y, qz = q.z, qw = q.w; - - // t = 2 * cross( q.xyz, v ); - const tx = 2 * ( qy * vz - qz * vy ); - const ty = 2 * ( qz * vx - qx * vz ); - const tz = 2 * ( qx * vy - qy * vx ); - - // v + q.w * t + cross( q.xyz, t ); - this.x = vx + qw * tx + qy * tz - qz * ty; - this.y = vy + qw * ty + qz * tx - qx * tz; - this.z = vz + qw * tz + qx * ty - qy * tx; - - return this; - - } - - project( camera ) { - - return this.applyMatrix4( camera.matrixWorldInverse ).applyMatrix4( camera.projectionMatrix ); - - } - - unproject( camera ) { - - return this.applyMatrix4( camera.projectionMatrixInverse ).applyMatrix4( camera.matrixWorld ); - - } - - transformDirection( m ) { - - // input: THREE.Matrix4 affine matrix - // vector interpreted as a direction - - const x = this.x, y = this.y, z = this.z; - const e = m.elements; - - this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z; - this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z; - this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z; - - return this.normalize(); - - } - - divide( v ) { - - this.x /= v.x; - this.y /= v.y; - this.z /= v.z; - - return this; - - } - - divideScalar( scalar ) { - - return this.multiplyScalar( 1 / scalar ); - - } - - min( v ) { - - this.x = Math.min( this.x, v.x ); - this.y = Math.min( this.y, v.y ); - this.z = Math.min( this.z, v.z ); - - return this; - - } - - max( v ) { - - this.x = Math.max( this.x, v.x ); - this.y = Math.max( this.y, v.y ); - this.z = Math.max( this.z, v.z ); - - return this; - - } - - clamp( min, max ) { - - // assumes min < max, componentwise - - this.x = Math.max( min.x, Math.min( max.x, this.x ) ); - this.y = Math.max( min.y, Math.min( max.y, this.y ) ); - this.z = Math.max( min.z, Math.min( max.z, this.z ) ); - - return this; - - } - - clampScalar( minVal, maxVal ) { - - this.x = Math.max( minVal, Math.min( maxVal, this.x ) ); - this.y = Math.max( minVal, Math.min( maxVal, this.y ) ); - this.z = Math.max( minVal, Math.min( maxVal, this.z ) ); - - return this; - - } - - clampLength( min, max ) { - - const length = this.length(); - - return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) ); - - } - - floor() { - - this.x = Math.floor( this.x ); - this.y = Math.floor( this.y ); - this.z = Math.floor( this.z ); - - return this; - - } - - ceil() { - - this.x = Math.ceil( this.x ); - this.y = Math.ceil( this.y ); - this.z = Math.ceil( this.z ); - - return this; - - } - - round() { - - this.x = Math.round( this.x ); - this.y = Math.round( this.y ); - this.z = Math.round( this.z ); - - return this; - - } - - roundToZero() { - - this.x = Math.trunc( this.x ); - this.y = Math.trunc( this.y ); - this.z = Math.trunc( this.z ); - - return this; - - } - - negate() { - - this.x = - this.x; - this.y = - this.y; - this.z = - this.z; - - return this; - - } - - dot( v ) { - - return this.x * v.x + this.y * v.y + this.z * v.z; - - } - - // TODO lengthSquared? - - lengthSq() { - - return this.x * this.x + this.y * this.y + this.z * this.z; - - } - - length() { - - return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z ); - - } - - manhattanLength() { - - return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ); - - } - - normalize() { - - return this.divideScalar( this.length() || 1 ); - - } - - setLength( length ) { - - return this.normalize().multiplyScalar( length ); - - } - - lerp( v, alpha ) { - - this.x += ( v.x - this.x ) * alpha; - this.y += ( v.y - this.y ) * alpha; - this.z += ( v.z - this.z ) * alpha; - - return this; - - } - - lerpVectors( v1, v2, alpha ) { - - this.x = v1.x + ( v2.x - v1.x ) * alpha; - this.y = v1.y + ( v2.y - v1.y ) * alpha; - this.z = v1.z + ( v2.z - v1.z ) * alpha; - - return this; - - } - - cross( v ) { - - return this.crossVectors( this, v ); - - } - - crossVectors( a, b ) { - - const ax = a.x, ay = a.y, az = a.z; - const bx = b.x, by = b.y, bz = b.z; - - this.x = ay * bz - az * by; - this.y = az * bx - ax * bz; - this.z = ax * by - ay * bx; - - return this; - - } - - projectOnVector( v ) { - - const denominator = v.lengthSq(); - - if ( denominator === 0 ) return this.set( 0, 0, 0 ); - - const scalar = v.dot( this ) / denominator; - - return this.copy( v ).multiplyScalar( scalar ); - - } - - projectOnPlane( planeNormal ) { - - _vector$c.copy( this ).projectOnVector( planeNormal ); - - return this.sub( _vector$c ); - - } - - reflect( normal ) { - - // reflect incident vector off plane orthogonal to normal - // normal is assumed to have unit length - - return this.sub( _vector$c.copy( normal ).multiplyScalar( 2 * this.dot( normal ) ) ); - - } - - angleTo( v ) { - - const denominator = Math.sqrt( this.lengthSq() * v.lengthSq() ); - - if ( denominator === 0 ) return Math.PI / 2; - - const theta = this.dot( v ) / denominator; - - // clamp, to handle numerical problems - - return Math.acos( clamp( theta, - 1, 1 ) ); - - } - - distanceTo( v ) { - - return Math.sqrt( this.distanceToSquared( v ) ); - - } - - distanceToSquared( v ) { - - const dx = this.x - v.x, dy = this.y - v.y, dz = this.z - v.z; - - return dx * dx + dy * dy + dz * dz; - - } - - manhattanDistanceTo( v ) { - - return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y ) + Math.abs( this.z - v.z ); - - } - - setFromSpherical( s ) { - - return this.setFromSphericalCoords( s.radius, s.phi, s.theta ); - - } - - setFromSphericalCoords( radius, phi, theta ) { - - const sinPhiRadius = Math.sin( phi ) * radius; - - this.x = sinPhiRadius * Math.sin( theta ); - this.y = Math.cos( phi ) * radius; - this.z = sinPhiRadius * Math.cos( theta ); - - return this; - - } - - setFromCylindrical( c ) { - - return this.setFromCylindricalCoords( c.radius, c.theta, c.y ); - - } - - setFromCylindricalCoords( radius, theta, y ) { - - this.x = radius * Math.sin( theta ); - this.y = y; - this.z = radius * Math.cos( theta ); - - return this; - - } - - setFromMatrixPosition( m ) { - - const e = m.elements; - - this.x = e[ 12 ]; - this.y = e[ 13 ]; - this.z = e[ 14 ]; - - return this; - - } - - setFromMatrixScale( m ) { - - const sx = this.setFromMatrixColumn( m, 0 ).length(); - const sy = this.setFromMatrixColumn( m, 1 ).length(); - const sz = this.setFromMatrixColumn( m, 2 ).length(); - - this.x = sx; - this.y = sy; - this.z = sz; - - return this; - - } - - setFromMatrixColumn( m, index ) { - - return this.fromArray( m.elements, index * 4 ); - - } - - setFromMatrix3Column( m, index ) { - - return this.fromArray( m.elements, index * 3 ); - - } - - setFromEuler( e ) { - - this.x = e._x; - this.y = e._y; - this.z = e._z; - - return this; - - } - - setFromColor( c ) { - - this.x = c.r; - this.y = c.g; - this.z = c.b; - - return this; - - } - - equals( v ) { - - return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) ); - - } - - fromArray( array, offset = 0 ) { - - this.x = array[ offset ]; - this.y = array[ offset + 1 ]; - this.z = array[ offset + 2 ]; - - return this; - - } - - toArray( array = [], offset = 0 ) { - - array[ offset ] = this.x; - array[ offset + 1 ] = this.y; - array[ offset + 2 ] = this.z; - - return array; - - } - - fromBufferAttribute( attribute, index ) { - - this.x = attribute.getX( index ); - this.y = attribute.getY( index ); - this.z = attribute.getZ( index ); - - return this; - - } - - random() { - - this.x = Math.random(); - this.y = Math.random(); - this.z = Math.random(); - - return this; - - } - - randomDirection() { - - // Derived from https://mathworld.wolfram.com/SpherePointPicking.html - - const u = ( Math.random() - 0.5 ) * 2; - const t = Math.random() * Math.PI * 2; - const f = Math.sqrt( 1 - u ** 2 ); - - this.x = f * Math.cos( t ); - this.y = f * Math.sin( t ); - this.z = u; - - return this; - - } - - *[ Symbol.iterator ]() { - - yield this.x; - yield this.y; - yield this.z; - - } - -} - -const _vector$c = /*@__PURE__*/ new Vector3(); -const _quaternion$4 = /*@__PURE__*/ new Quaternion(); - -class Box3 { - - constructor( min = new Vector3( + Infinity, + Infinity, + Infinity ), max = new Vector3( - Infinity, - Infinity, - Infinity ) ) { - - this.isBox3 = true; - - this.min = min; - this.max = max; - - } - - set( min, max ) { - - this.min.copy( min ); - this.max.copy( max ); - - return this; - - } - - setFromArray( array ) { - - this.makeEmpty(); - - for ( let i = 0, il = array.length; i < il; i += 3 ) { - - this.expandByPoint( _vector$b.fromArray( array, i ) ); - - } - - return this; - - } - - setFromBufferAttribute( attribute ) { - - this.makeEmpty(); - - for ( let i = 0, il = attribute.count; i < il; i ++ ) { - - this.expandByPoint( _vector$b.fromBufferAttribute( attribute, i ) ); - - } - - return this; - - } - - setFromPoints( points ) { - - this.makeEmpty(); - - for ( let i = 0, il = points.length; i < il; i ++ ) { - - this.expandByPoint( points[ i ] ); - - } - - return this; - - } - - setFromCenterAndSize( center, size ) { - - const halfSize = _vector$b.copy( size ).multiplyScalar( 0.5 ); - - this.min.copy( center ).sub( halfSize ); - this.max.copy( center ).add( halfSize ); - - return this; - - } - - setFromObject( object, precise = false ) { - - this.makeEmpty(); - - return this.expandByObject( object, precise ); - - } - - clone() { - - return new this.constructor().copy( this ); - - } - - copy( box ) { - - this.min.copy( box.min ); - this.max.copy( box.max ); - - return this; - - } - - makeEmpty() { - - this.min.x = this.min.y = this.min.z = + Infinity; - this.max.x = this.max.y = this.max.z = - Infinity; - - return this; - - } - - isEmpty() { - - // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes - - return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ) || ( this.max.z < this.min.z ); - - } - - getCenter( target ) { - - return this.isEmpty() ? target.set( 0, 0, 0 ) : target.addVectors( this.min, this.max ).multiplyScalar( 0.5 ); - - } - - getSize( target ) { - - return this.isEmpty() ? target.set( 0, 0, 0 ) : target.subVectors( this.max, this.min ); - - } - - expandByPoint( point ) { - - this.min.min( point ); - this.max.max( point ); - - return this; - - } - - expandByVector( vector ) { - - this.min.sub( vector ); - this.max.add( vector ); - - return this; - - } - - expandByScalar( scalar ) { - - this.min.addScalar( - scalar ); - this.max.addScalar( scalar ); - - return this; - - } - - expandByObject( object, precise = false ) { - - // Computes the world-axis-aligned bounding box of an object (including its children), - // accounting for both the object's, and children's, world transforms - - object.updateWorldMatrix( false, false ); - - const geometry = object.geometry; - - if ( geometry !== undefined ) { - - const positionAttribute = geometry.getAttribute( 'position' ); - - // precise AABB computation based on vertex data requires at least a position attribute. - // instancing isn't supported so far and uses the normal (conservative) code path. - - if ( precise === true && positionAttribute !== undefined && object.isInstancedMesh !== true ) { - - for ( let i = 0, l = positionAttribute.count; i < l; i ++ ) { - - if ( object.isMesh === true ) { - - object.getVertexPosition( i, _vector$b ); - - } else { - - _vector$b.fromBufferAttribute( positionAttribute, i ); - - } - - _vector$b.applyMatrix4( object.matrixWorld ); - this.expandByPoint( _vector$b ); - - } - - } else { - - if ( object.boundingBox !== undefined ) { - - // object-level bounding box - - if ( object.boundingBox === null ) { - - object.computeBoundingBox(); - - } - - _box$4.copy( object.boundingBox ); - - - } else { - - // geometry-level bounding box - - if ( geometry.boundingBox === null ) { - - geometry.computeBoundingBox(); - - } - - _box$4.copy( geometry.boundingBox ); - - } - - _box$4.applyMatrix4( object.matrixWorld ); - - this.union( _box$4 ); - - } - - } - - const children = object.children; - - for ( let i = 0, l = children.length; i < l; i ++ ) { - - this.expandByObject( children[ i ], precise ); - - } - - return this; - - } - - containsPoint( point ) { - - return point.x < this.min.x || point.x > this.max.x || - point.y < this.min.y || point.y > this.max.y || - point.z < this.min.z || point.z > this.max.z ? false : true; - - } - - containsBox( box ) { - - return this.min.x <= box.min.x && box.max.x <= this.max.x && - this.min.y <= box.min.y && box.max.y <= this.max.y && - this.min.z <= box.min.z && box.max.z <= this.max.z; - - } - - getParameter( point, target ) { - - // This can potentially have a divide by zero if the box - // has a size dimension of 0. - - return target.set( - ( point.x - this.min.x ) / ( this.max.x - this.min.x ), - ( point.y - this.min.y ) / ( this.max.y - this.min.y ), - ( point.z - this.min.z ) / ( this.max.z - this.min.z ) - ); - - } - - intersectsBox( box ) { - - // using 6 splitting planes to rule out intersections. - return box.max.x < this.min.x || box.min.x > this.max.x || - box.max.y < this.min.y || box.min.y > this.max.y || - box.max.z < this.min.z || box.min.z > this.max.z ? false : true; - - } - - intersectsSphere( sphere ) { - - // Find the point on the AABB closest to the sphere center. - this.clampPoint( sphere.center, _vector$b ); - - // If that point is inside the sphere, the AABB and sphere intersect. - return _vector$b.distanceToSquared( sphere.center ) <= ( sphere.radius * sphere.radius ); - - } - - intersectsPlane( plane ) { - - // We compute the minimum and maximum dot product values. If those values - // are on the same side (back or front) of the plane, then there is no intersection. - - let min, max; - - if ( plane.normal.x > 0 ) { - - min = plane.normal.x * this.min.x; - max = plane.normal.x * this.max.x; - - } else { - - min = plane.normal.x * this.max.x; - max = plane.normal.x * this.min.x; - - } - - if ( plane.normal.y > 0 ) { - - min += plane.normal.y * this.min.y; - max += plane.normal.y * this.max.y; - - } else { - - min += plane.normal.y * this.max.y; - max += plane.normal.y * this.min.y; - - } - - if ( plane.normal.z > 0 ) { - - min += plane.normal.z * this.min.z; - max += plane.normal.z * this.max.z; - - } else { - - min += plane.normal.z * this.max.z; - max += plane.normal.z * this.min.z; - - } - - return ( min <= - plane.constant && max >= - plane.constant ); - - } - - intersectsTriangle( triangle ) { - - if ( this.isEmpty() ) { - - return false; - - } - - // compute box center and extents - this.getCenter( _center ); - _extents.subVectors( this.max, _center ); - - // translate triangle to aabb origin - _v0$2.subVectors( triangle.a, _center ); - _v1$7.subVectors( triangle.b, _center ); - _v2$4.subVectors( triangle.c, _center ); - - // compute edge vectors for triangle - _f0.subVectors( _v1$7, _v0$2 ); - _f1.subVectors( _v2$4, _v1$7 ); - _f2.subVectors( _v0$2, _v2$4 ); - - // test against axes that are given by cross product combinations of the edges of the triangle and the edges of the aabb - // make an axis testing of each of the 3 sides of the aabb against each of the 3 sides of the triangle = 9 axis of separation - // axis_ij = u_i x f_j (u0, u1, u2 = face normals of aabb = x,y,z axes vectors since aabb is axis aligned) - let axes = [ - 0, - _f0.z, _f0.y, 0, - _f1.z, _f1.y, 0, - _f2.z, _f2.y, - _f0.z, 0, - _f0.x, _f1.z, 0, - _f1.x, _f2.z, 0, - _f2.x, - - _f0.y, _f0.x, 0, - _f1.y, _f1.x, 0, - _f2.y, _f2.x, 0 - ]; - if ( ! satForAxes( axes, _v0$2, _v1$7, _v2$4, _extents ) ) { - - return false; - - } - - // test 3 face normals from the aabb - axes = [ 1, 0, 0, 0, 1, 0, 0, 0, 1 ]; - if ( ! satForAxes( axes, _v0$2, _v1$7, _v2$4, _extents ) ) { - - return false; - - } - - // finally testing the face normal of the triangle - // use already existing triangle edge vectors here - _triangleNormal.crossVectors( _f0, _f1 ); - axes = [ _triangleNormal.x, _triangleNormal.y, _triangleNormal.z ]; - - return satForAxes( axes, _v0$2, _v1$7, _v2$4, _extents ); - - } - - clampPoint( point, target ) { - - return target.copy( point ).clamp( this.min, this.max ); - - } - - distanceToPoint( point ) { - - return this.clampPoint( point, _vector$b ).distanceTo( point ); - - } - - getBoundingSphere( target ) { - - if ( this.isEmpty() ) { - - target.makeEmpty(); - - } else { - - this.getCenter( target.center ); - - target.radius = this.getSize( _vector$b ).length() * 0.5; - - } - - return target; - - } - - intersect( box ) { - - this.min.max( box.min ); - this.max.min( box.max ); - - // ensure that if there is no overlap, the result is fully empty, not slightly empty with non-inf/+inf values that will cause subsequence intersects to erroneously return valid values. - if ( this.isEmpty() ) this.makeEmpty(); - - return this; - - } - - union( box ) { - - this.min.min( box.min ); - this.max.max( box.max ); - - return this; - - } - - applyMatrix4( matrix ) { - - // transform of empty box is an empty box. - if ( this.isEmpty() ) return this; - - // NOTE: I am using a binary pattern to specify all 2^3 combinations below - _points[ 0 ].set( this.min.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 000 - _points[ 1 ].set( this.min.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 001 - _points[ 2 ].set( this.min.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 010 - _points[ 3 ].set( this.min.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 011 - _points[ 4 ].set( this.max.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 100 - _points[ 5 ].set( this.max.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 101 - _points[ 6 ].set( this.max.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 110 - _points[ 7 ].set( this.max.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 111 - - this.setFromPoints( _points ); - - return this; - - } - - translate( offset ) { - - this.min.add( offset ); - this.max.add( offset ); - - return this; - - } - - equals( box ) { - - return box.min.equals( this.min ) && box.max.equals( this.max ); - - } - -} - -const _points = [ - /*@__PURE__*/ new Vector3(), - /*@__PURE__*/ new Vector3(), - /*@__PURE__*/ new Vector3(), - /*@__PURE__*/ new Vector3(), - /*@__PURE__*/ new Vector3(), - /*@__PURE__*/ new Vector3(), - /*@__PURE__*/ new Vector3(), - /*@__PURE__*/ new Vector3() -]; - -const _vector$b = /*@__PURE__*/ new Vector3(); - -const _box$4 = /*@__PURE__*/ new Box3(); - -// triangle centered vertices - -const _v0$2 = /*@__PURE__*/ new Vector3(); -const _v1$7 = /*@__PURE__*/ new Vector3(); -const _v2$4 = /*@__PURE__*/ new Vector3(); - -// triangle edge vectors - -const _f0 = /*@__PURE__*/ new Vector3(); -const _f1 = /*@__PURE__*/ new Vector3(); -const _f2 = /*@__PURE__*/ new Vector3(); - -const _center = /*@__PURE__*/ new Vector3(); -const _extents = /*@__PURE__*/ new Vector3(); -const _triangleNormal = /*@__PURE__*/ new Vector3(); -const _testAxis = /*@__PURE__*/ new Vector3(); - -function satForAxes( axes, v0, v1, v2, extents ) { - - for ( let i = 0, j = axes.length - 3; i <= j; i += 3 ) { - - _testAxis.fromArray( axes, i ); - // project the aabb onto the separating axis - const r = extents.x * Math.abs( _testAxis.x ) + extents.y * Math.abs( _testAxis.y ) + extents.z * Math.abs( _testAxis.z ); - // project all 3 vertices of the triangle onto the separating axis - const p0 = v0.dot( _testAxis ); - const p1 = v1.dot( _testAxis ); - const p2 = v2.dot( _testAxis ); - // actual test, basically see if either of the most extreme of the triangle points intersects r - if ( Math.max( - Math.max( p0, p1, p2 ), Math.min( p0, p1, p2 ) ) > r ) { - - // points of the projected triangle are outside the projected half-length of the aabb - // the axis is separating and we can exit - return false; - - } - - } - - return true; - -} - -const _box$3 = /*@__PURE__*/ new Box3(); -const _v1$6 = /*@__PURE__*/ new Vector3(); -const _v2$3 = /*@__PURE__*/ new Vector3(); - -class Sphere { - - constructor( center = new Vector3(), radius = - 1 ) { - - this.isSphere = true; - - this.center = center; - this.radius = radius; - - } - - set( center, radius ) { - - this.center.copy( center ); - this.radius = radius; - - return this; - - } - - setFromPoints( points, optionalCenter ) { - - const center = this.center; - - if ( optionalCenter !== undefined ) { - - center.copy( optionalCenter ); - - } else { - - _box$3.setFromPoints( points ).getCenter( center ); - - } - - let maxRadiusSq = 0; - - for ( let i = 0, il = points.length; i < il; i ++ ) { - - maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( points[ i ] ) ); - - } - - this.radius = Math.sqrt( maxRadiusSq ); - - return this; - - } - - copy( sphere ) { - - this.center.copy( sphere.center ); - this.radius = sphere.radius; - - return this; - - } - - isEmpty() { - - return ( this.radius < 0 ); - - } - - makeEmpty() { - - this.center.set( 0, 0, 0 ); - this.radius = - 1; - - return this; - - } - - containsPoint( point ) { - - return ( point.distanceToSquared( this.center ) <= ( this.radius * this.radius ) ); - - } - - distanceToPoint( point ) { - - return ( point.distanceTo( this.center ) - this.radius ); - - } - - intersectsSphere( sphere ) { - - const radiusSum = this.radius + sphere.radius; - - return sphere.center.distanceToSquared( this.center ) <= ( radiusSum * radiusSum ); - - } - - intersectsBox( box ) { - - return box.intersectsSphere( this ); - - } - - intersectsPlane( plane ) { - - return Math.abs( plane.distanceToPoint( this.center ) ) <= this.radius; - - } - - clampPoint( point, target ) { - - const deltaLengthSq = this.center.distanceToSquared( point ); - - target.copy( point ); - - if ( deltaLengthSq > ( this.radius * this.radius ) ) { - - target.sub( this.center ).normalize(); - target.multiplyScalar( this.radius ).add( this.center ); - - } - - return target; - - } - - getBoundingBox( target ) { - - if ( this.isEmpty() ) { - - // Empty sphere produces empty bounding box - target.makeEmpty(); - return target; - - } - - target.set( this.center, this.center ); - target.expandByScalar( this.radius ); - - return target; - - } - - applyMatrix4( matrix ) { - - this.center.applyMatrix4( matrix ); - this.radius = this.radius * matrix.getMaxScaleOnAxis(); - - return this; - - } - - translate( offset ) { - - this.center.add( offset ); - - return this; - - } - - expandByPoint( point ) { - - if ( this.isEmpty() ) { - - this.center.copy( point ); - - this.radius = 0; - - return this; - - } - - _v1$6.subVectors( point, this.center ); - - const lengthSq = _v1$6.lengthSq(); - - if ( lengthSq > ( this.radius * this.radius ) ) { - - // calculate the minimal sphere - - const length = Math.sqrt( lengthSq ); - - const delta = ( length - this.radius ) * 0.5; - - this.center.addScaledVector( _v1$6, delta / length ); - - this.radius += delta; - - } - - return this; - - } - - union( sphere ) { - - if ( sphere.isEmpty() ) { - - return this; - - } - - if ( this.isEmpty() ) { - - this.copy( sphere ); - - return this; - - } - - if ( this.center.equals( sphere.center ) === true ) { - - this.radius = Math.max( this.radius, sphere.radius ); - - } else { - - _v2$3.subVectors( sphere.center, this.center ).setLength( sphere.radius ); - - this.expandByPoint( _v1$6.copy( sphere.center ).add( _v2$3 ) ); - - this.expandByPoint( _v1$6.copy( sphere.center ).sub( _v2$3 ) ); - - } - - return this; - - } - - equals( sphere ) { - - return sphere.center.equals( this.center ) && ( sphere.radius === this.radius ); - - } - - clone() { - - return new this.constructor().copy( this ); - - } - -} - -const _vector$a = /*@__PURE__*/ new Vector3(); -const _segCenter = /*@__PURE__*/ new Vector3(); -const _segDir = /*@__PURE__*/ new Vector3(); -const _diff = /*@__PURE__*/ new Vector3(); - -const _edge1 = /*@__PURE__*/ new Vector3(); -const _edge2 = /*@__PURE__*/ new Vector3(); -const _normal$1 = /*@__PURE__*/ new Vector3(); - -class Ray { - - constructor( origin = new Vector3(), direction = new Vector3( 0, 0, - 1 ) ) { - - this.origin = origin; - this.direction = direction; - - } - - set( origin, direction ) { - - this.origin.copy( origin ); - this.direction.copy( direction ); - - return this; - - } - - copy( ray ) { - - this.origin.copy( ray.origin ); - this.direction.copy( ray.direction ); - - return this; - - } - - at( t, target ) { - - return target.copy( this.origin ).addScaledVector( this.direction, t ); - - } - - lookAt( v ) { - - this.direction.copy( v ).sub( this.origin ).normalize(); - - return this; - - } - - recast( t ) { - - this.origin.copy( this.at( t, _vector$a ) ); - - return this; - - } - - closestPointToPoint( point, target ) { - - target.subVectors( point, this.origin ); - - const directionDistance = target.dot( this.direction ); - - if ( directionDistance < 0 ) { - - return target.copy( this.origin ); - - } - - return target.copy( this.origin ).addScaledVector( this.direction, directionDistance ); - - } - - distanceToPoint( point ) { - - return Math.sqrt( this.distanceSqToPoint( point ) ); - - } - - distanceSqToPoint( point ) { - - const directionDistance = _vector$a.subVectors( point, this.origin ).dot( this.direction ); - - // point behind the ray - - if ( directionDistance < 0 ) { - - return this.origin.distanceToSquared( point ); - - } - - _vector$a.copy( this.origin ).addScaledVector( this.direction, directionDistance ); - - return _vector$a.distanceToSquared( point ); - - } - - distanceSqToSegment( v0, v1, optionalPointOnRay, optionalPointOnSegment ) { - - // from https://github.com/pmjoniak/GeometricTools/blob/master/GTEngine/Include/Mathematics/GteDistRaySegment.h - // It returns the min distance between the ray and the segment - // defined by v0 and v1 - // It can also set two optional targets : - // - The closest point on the ray - // - The closest point on the segment - - _segCenter.copy( v0 ).add( v1 ).multiplyScalar( 0.5 ); - _segDir.copy( v1 ).sub( v0 ).normalize(); - _diff.copy( this.origin ).sub( _segCenter ); - - const segExtent = v0.distanceTo( v1 ) * 0.5; - const a01 = - this.direction.dot( _segDir ); - const b0 = _diff.dot( this.direction ); - const b1 = - _diff.dot( _segDir ); - const c = _diff.lengthSq(); - const det = Math.abs( 1 - a01 * a01 ); - let s0, s1, sqrDist, extDet; - - if ( det > 0 ) { - - // The ray and segment are not parallel. - - s0 = a01 * b1 - b0; - s1 = a01 * b0 - b1; - extDet = segExtent * det; - - if ( s0 >= 0 ) { - - if ( s1 >= - extDet ) { - - if ( s1 <= extDet ) { - - // region 0 - // Minimum at interior points of ray and segment. - - const invDet = 1 / det; - s0 *= invDet; - s1 *= invDet; - sqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c; - - } else { - - // region 1 - - s1 = segExtent; - s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); - sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; - - } - - } else { - - // region 5 - - s1 = - segExtent; - s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); - sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; - - } - - } else { - - if ( s1 <= - extDet ) { - - // region 4 - - s0 = Math.max( 0, - ( - a01 * segExtent + b0 ) ); - s1 = ( s0 > 0 ) ? - segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent ); - sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; - - } else if ( s1 <= extDet ) { - - // region 3 - - s0 = 0; - s1 = Math.min( Math.max( - segExtent, - b1 ), segExtent ); - sqrDist = s1 * ( s1 + 2 * b1 ) + c; - - } else { - - // region 2 - - s0 = Math.max( 0, - ( a01 * segExtent + b0 ) ); - s1 = ( s0 > 0 ) ? segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent ); - sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; - - } - - } - - } else { - - // Ray and segment are parallel. - - s1 = ( a01 > 0 ) ? - segExtent : segExtent; - s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); - sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; - - } - - if ( optionalPointOnRay ) { - - optionalPointOnRay.copy( this.origin ).addScaledVector( this.direction, s0 ); - - } - - if ( optionalPointOnSegment ) { - - optionalPointOnSegment.copy( _segCenter ).addScaledVector( _segDir, s1 ); - - } - - return sqrDist; - - } - - intersectSphere( sphere, target ) { - - _vector$a.subVectors( sphere.center, this.origin ); - const tca = _vector$a.dot( this.direction ); - const d2 = _vector$a.dot( _vector$a ) - tca * tca; - const radius2 = sphere.radius * sphere.radius; - - if ( d2 > radius2 ) return null; - - const thc = Math.sqrt( radius2 - d2 ); - - // t0 = first intersect point - entrance on front of sphere - const t0 = tca - thc; - - // t1 = second intersect point - exit point on back of sphere - const t1 = tca + thc; - - // test to see if t1 is behind the ray - if so, return null - if ( t1 < 0 ) return null; - - // test to see if t0 is behind the ray: - // if it is, the ray is inside the sphere, so return the second exit point scaled by t1, - // in order to always return an intersect point that is in front of the ray. - if ( t0 < 0 ) return this.at( t1, target ); - - // else t0 is in front of the ray, so return the first collision point scaled by t0 - return this.at( t0, target ); - - } - - intersectsSphere( sphere ) { - - return this.distanceSqToPoint( sphere.center ) <= ( sphere.radius * sphere.radius ); - - } - - distanceToPlane( plane ) { - - const denominator = plane.normal.dot( this.direction ); - - if ( denominator === 0 ) { - - // line is coplanar, return origin - if ( plane.distanceToPoint( this.origin ) === 0 ) { - - return 0; - - } - - // Null is preferable to undefined since undefined means.... it is undefined - - return null; - - } - - const t = - ( this.origin.dot( plane.normal ) + plane.constant ) / denominator; - - // Return if the ray never intersects the plane - - return t >= 0 ? t : null; - - } - - intersectPlane( plane, target ) { - - const t = this.distanceToPlane( plane ); - - if ( t === null ) { - - return null; - - } - - return this.at( t, target ); - - } - - intersectsPlane( plane ) { - - // check if the ray lies on the plane first - - const distToPoint = plane.distanceToPoint( this.origin ); - - if ( distToPoint === 0 ) { - - return true; - - } - - const denominator = plane.normal.dot( this.direction ); - - if ( denominator * distToPoint < 0 ) { - - return true; - - } - - // ray origin is behind the plane (and is pointing behind it) - - return false; - - } - - intersectBox( box, target ) { - - let tmin, tmax, tymin, tymax, tzmin, tzmax; - - const invdirx = 1 / this.direction.x, - invdiry = 1 / this.direction.y, - invdirz = 1 / this.direction.z; - - const origin = this.origin; - - if ( invdirx >= 0 ) { - - tmin = ( box.min.x - origin.x ) * invdirx; - tmax = ( box.max.x - origin.x ) * invdirx; - - } else { - - tmin = ( box.max.x - origin.x ) * invdirx; - tmax = ( box.min.x - origin.x ) * invdirx; - - } - - if ( invdiry >= 0 ) { - - tymin = ( box.min.y - origin.y ) * invdiry; - tymax = ( box.max.y - origin.y ) * invdiry; - - } else { - - tymin = ( box.max.y - origin.y ) * invdiry; - tymax = ( box.min.y - origin.y ) * invdiry; - - } - - if ( ( tmin > tymax ) || ( tymin > tmax ) ) return null; - - if ( tymin > tmin || isNaN( tmin ) ) tmin = tymin; - - if ( tymax < tmax || isNaN( tmax ) ) tmax = tymax; - - if ( invdirz >= 0 ) { - - tzmin = ( box.min.z - origin.z ) * invdirz; - tzmax = ( box.max.z - origin.z ) * invdirz; - - } else { - - tzmin = ( box.max.z - origin.z ) * invdirz; - tzmax = ( box.min.z - origin.z ) * invdirz; - - } - - if ( ( tmin > tzmax ) || ( tzmin > tmax ) ) return null; - - if ( tzmin > tmin || tmin !== tmin ) tmin = tzmin; - - if ( tzmax < tmax || tmax !== tmax ) tmax = tzmax; - - //return point closest to the ray (positive side) - - if ( tmax < 0 ) return null; - - return this.at( tmin >= 0 ? tmin : tmax, target ); - - } - - intersectsBox( box ) { - - return this.intersectBox( box, _vector$a ) !== null; - - } - - intersectTriangle( a, b, c, backfaceCulling, target ) { - - // Compute the offset origin, edges, and normal. - - // from https://github.com/pmjoniak/GeometricTools/blob/master/GTEngine/Include/Mathematics/GteIntrRay3Triangle3.h - - _edge1.subVectors( b, a ); - _edge2.subVectors( c, a ); - _normal$1.crossVectors( _edge1, _edge2 ); - - // Solve Q + t*D = b1*E1 + b2*E2 (Q = kDiff, D = ray direction, - // E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by - // |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2)) - // |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q)) - // |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N) - let DdN = this.direction.dot( _normal$1 ); - let sign; - - if ( DdN > 0 ) { - - if ( backfaceCulling ) return null; - sign = 1; - - } else if ( DdN < 0 ) { - - sign = - 1; - DdN = - DdN; - - } else { - - return null; - - } - - _diff.subVectors( this.origin, a ); - const DdQxE2 = sign * this.direction.dot( _edge2.crossVectors( _diff, _edge2 ) ); - - // b1 < 0, no intersection - if ( DdQxE2 < 0 ) { - - return null; - - } - - const DdE1xQ = sign * this.direction.dot( _edge1.cross( _diff ) ); - - // b2 < 0, no intersection - if ( DdE1xQ < 0 ) { - - return null; - - } - - // b1+b2 > 1, no intersection - if ( DdQxE2 + DdE1xQ > DdN ) { - - return null; - - } - - // Line intersects triangle, check if ray does. - const QdN = - sign * _diff.dot( _normal$1 ); - - // t < 0, no intersection - if ( QdN < 0 ) { - - return null; - - } - - // Ray intersects triangle. - return this.at( QdN / DdN, target ); - - } - - applyMatrix4( matrix4 ) { - - this.origin.applyMatrix4( matrix4 ); - this.direction.transformDirection( matrix4 ); - - return this; - - } - - equals( ray ) { - - return ray.origin.equals( this.origin ) && ray.direction.equals( this.direction ); - - } - - clone() { - - return new this.constructor().copy( this ); - - } - -} - -class Matrix4 { - - constructor( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) { - - Matrix4.prototype.isMatrix4 = true; - - this.elements = [ - - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1 - - ]; - - if ( n11 !== undefined ) { - - this.set( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ); - - } - - } - - set( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) { - - const te = this.elements; - - te[ 0 ] = n11; te[ 4 ] = n12; te[ 8 ] = n13; te[ 12 ] = n14; - te[ 1 ] = n21; te[ 5 ] = n22; te[ 9 ] = n23; te[ 13 ] = n24; - te[ 2 ] = n31; te[ 6 ] = n32; te[ 10 ] = n33; te[ 14 ] = n34; - te[ 3 ] = n41; te[ 7 ] = n42; te[ 11 ] = n43; te[ 15 ] = n44; - - return this; - - } - - identity() { - - this.set( - - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1 - - ); - - return this; - - } - - clone() { - - return new Matrix4().fromArray( this.elements ); - - } - - copy( m ) { - - const te = this.elements; - const me = m.elements; - - te[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ]; te[ 3 ] = me[ 3 ]; - te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ]; te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ]; - te[ 8 ] = me[ 8 ]; te[ 9 ] = me[ 9 ]; te[ 10 ] = me[ 10 ]; te[ 11 ] = me[ 11 ]; - te[ 12 ] = me[ 12 ]; te[ 13 ] = me[ 13 ]; te[ 14 ] = me[ 14 ]; te[ 15 ] = me[ 15 ]; - - return this; - - } - - copyPosition( m ) { - - const te = this.elements, me = m.elements; - - te[ 12 ] = me[ 12 ]; - te[ 13 ] = me[ 13 ]; - te[ 14 ] = me[ 14 ]; - - return this; - - } - - setFromMatrix3( m ) { - - const me = m.elements; - - this.set( - - me[ 0 ], me[ 3 ], me[ 6 ], 0, - me[ 1 ], me[ 4 ], me[ 7 ], 0, - me[ 2 ], me[ 5 ], me[ 8 ], 0, - 0, 0, 0, 1 - - ); - - return this; - - } - - extractBasis( xAxis, yAxis, zAxis ) { - - xAxis.setFromMatrixColumn( this, 0 ); - yAxis.setFromMatrixColumn( this, 1 ); - zAxis.setFromMatrixColumn( this, 2 ); - - return this; - - } - - makeBasis( xAxis, yAxis, zAxis ) { - - this.set( - xAxis.x, yAxis.x, zAxis.x, 0, - xAxis.y, yAxis.y, zAxis.y, 0, - xAxis.z, yAxis.z, zAxis.z, 0, - 0, 0, 0, 1 - ); - - return this; - - } - - extractRotation( m ) { - - // this method does not support reflection matrices - - const te = this.elements; - const me = m.elements; - - const scaleX = 1 / _v1$5.setFromMatrixColumn( m, 0 ).length(); - const scaleY = 1 / _v1$5.setFromMatrixColumn( m, 1 ).length(); - const scaleZ = 1 / _v1$5.setFromMatrixColumn( m, 2 ).length(); - - te[ 0 ] = me[ 0 ] * scaleX; - te[ 1 ] = me[ 1 ] * scaleX; - te[ 2 ] = me[ 2 ] * scaleX; - te[ 3 ] = 0; - - te[ 4 ] = me[ 4 ] * scaleY; - te[ 5 ] = me[ 5 ] * scaleY; - te[ 6 ] = me[ 6 ] * scaleY; - te[ 7 ] = 0; - - te[ 8 ] = me[ 8 ] * scaleZ; - te[ 9 ] = me[ 9 ] * scaleZ; - te[ 10 ] = me[ 10 ] * scaleZ; - te[ 11 ] = 0; - - te[ 12 ] = 0; - te[ 13 ] = 0; - te[ 14 ] = 0; - te[ 15 ] = 1; - - return this; - - } - - makeRotationFromEuler( euler ) { - - const te = this.elements; - - const x = euler.x, y = euler.y, z = euler.z; - const a = Math.cos( x ), b = Math.sin( x ); - const c = Math.cos( y ), d = Math.sin( y ); - const e = Math.cos( z ), f = Math.sin( z ); - - if ( euler.order === 'XYZ' ) { - - const ae = a * e, af = a * f, be = b * e, bf = b * f; - - te[ 0 ] = c * e; - te[ 4 ] = - c * f; - te[ 8 ] = d; - - te[ 1 ] = af + be * d; - te[ 5 ] = ae - bf * d; - te[ 9 ] = - b * c; - - te[ 2 ] = bf - ae * d; - te[ 6 ] = be + af * d; - te[ 10 ] = a * c; - - } else if ( euler.order === 'YXZ' ) { - - const ce = c * e, cf = c * f, de = d * e, df = d * f; - - te[ 0 ] = ce + df * b; - te[ 4 ] = de * b - cf; - te[ 8 ] = a * d; - - te[ 1 ] = a * f; - te[ 5 ] = a * e; - te[ 9 ] = - b; - - te[ 2 ] = cf * b - de; - te[ 6 ] = df + ce * b; - te[ 10 ] = a * c; - - } else if ( euler.order === 'ZXY' ) { - - const ce = c * e, cf = c * f, de = d * e, df = d * f; - - te[ 0 ] = ce - df * b; - te[ 4 ] = - a * f; - te[ 8 ] = de + cf * b; - - te[ 1 ] = cf + de * b; - te[ 5 ] = a * e; - te[ 9 ] = df - ce * b; - - te[ 2 ] = - a * d; - te[ 6 ] = b; - te[ 10 ] = a * c; - - } else if ( euler.order === 'ZYX' ) { - - const ae = a * e, af = a * f, be = b * e, bf = b * f; - - te[ 0 ] = c * e; - te[ 4 ] = be * d - af; - te[ 8 ] = ae * d + bf; - - te[ 1 ] = c * f; - te[ 5 ] = bf * d + ae; - te[ 9 ] = af * d - be; - - te[ 2 ] = - d; - te[ 6 ] = b * c; - te[ 10 ] = a * c; - - } else if ( euler.order === 'YZX' ) { - - const ac = a * c, ad = a * d, bc = b * c, bd = b * d; - - te[ 0 ] = c * e; - te[ 4 ] = bd - ac * f; - te[ 8 ] = bc * f + ad; - - te[ 1 ] = f; - te[ 5 ] = a * e; - te[ 9 ] = - b * e; - - te[ 2 ] = - d * e; - te[ 6 ] = ad * f + bc; - te[ 10 ] = ac - bd * f; - - } else if ( euler.order === 'XZY' ) { - - const ac = a * c, ad = a * d, bc = b * c, bd = b * d; - - te[ 0 ] = c * e; - te[ 4 ] = - f; - te[ 8 ] = d * e; - - te[ 1 ] = ac * f + bd; - te[ 5 ] = a * e; - te[ 9 ] = ad * f - bc; - - te[ 2 ] = bc * f - ad; - te[ 6 ] = b * e; - te[ 10 ] = bd * f + ac; - - } - - // bottom row - te[ 3 ] = 0; - te[ 7 ] = 0; - te[ 11 ] = 0; - - // last column - te[ 12 ] = 0; - te[ 13 ] = 0; - te[ 14 ] = 0; - te[ 15 ] = 1; - - return this; - - } - - makeRotationFromQuaternion( q ) { - - return this.compose( _zero, q, _one ); - - } - - lookAt( eye, target, up ) { - - const te = this.elements; - - _z.subVectors( eye, target ); - - if ( _z.lengthSq() === 0 ) { - - // eye and target are in the same position - - _z.z = 1; - - } - - _z.normalize(); - _x.crossVectors( up, _z ); - - if ( _x.lengthSq() === 0 ) { - - // up and z are parallel - - if ( Math.abs( up.z ) === 1 ) { - - _z.x += 0.0001; - - } else { - - _z.z += 0.0001; - - } - - _z.normalize(); - _x.crossVectors( up, _z ); - - } - - _x.normalize(); - _y.crossVectors( _z, _x ); - - te[ 0 ] = _x.x; te[ 4 ] = _y.x; te[ 8 ] = _z.x; - te[ 1 ] = _x.y; te[ 5 ] = _y.y; te[ 9 ] = _z.y; - te[ 2 ] = _x.z; te[ 6 ] = _y.z; te[ 10 ] = _z.z; - - return this; - - } - - multiply( m ) { - - return this.multiplyMatrices( this, m ); - - } - - premultiply( m ) { - - return this.multiplyMatrices( m, this ); - - } - - multiplyMatrices( a, b ) { - - const ae = a.elements; - const be = b.elements; - const te = this.elements; - - const a11 = ae[ 0 ], a12 = ae[ 4 ], a13 = ae[ 8 ], a14 = ae[ 12 ]; - const a21 = ae[ 1 ], a22 = ae[ 5 ], a23 = ae[ 9 ], a24 = ae[ 13 ]; - const a31 = ae[ 2 ], a32 = ae[ 6 ], a33 = ae[ 10 ], a34 = ae[ 14 ]; - const a41 = ae[ 3 ], a42 = ae[ 7 ], a43 = ae[ 11 ], a44 = ae[ 15 ]; - - const b11 = be[ 0 ], b12 = be[ 4 ], b13 = be[ 8 ], b14 = be[ 12 ]; - const b21 = be[ 1 ], b22 = be[ 5 ], b23 = be[ 9 ], b24 = be[ 13 ]; - const b31 = be[ 2 ], b32 = be[ 6 ], b33 = be[ 10 ], b34 = be[ 14 ]; - const b41 = be[ 3 ], b42 = be[ 7 ], b43 = be[ 11 ], b44 = be[ 15 ]; - - te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41; - te[ 4 ] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42; - te[ 8 ] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43; - te[ 12 ] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44; - - te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41; - te[ 5 ] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42; - te[ 9 ] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43; - te[ 13 ] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44; - - te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41; - te[ 6 ] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42; - te[ 10 ] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43; - te[ 14 ] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44; - - te[ 3 ] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41; - te[ 7 ] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42; - te[ 11 ] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43; - te[ 15 ] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44; - - return this; - - } - - multiplyScalar( s ) { - - const te = this.elements; - - te[ 0 ] *= s; te[ 4 ] *= s; te[ 8 ] *= s; te[ 12 ] *= s; - te[ 1 ] *= s; te[ 5 ] *= s; te[ 9 ] *= s; te[ 13 ] *= s; - te[ 2 ] *= s; te[ 6 ] *= s; te[ 10 ] *= s; te[ 14 ] *= s; - te[ 3 ] *= s; te[ 7 ] *= s; te[ 11 ] *= s; te[ 15 ] *= s; - - return this; - - } - - determinant() { - - const te = this.elements; - - const n11 = te[ 0 ], n12 = te[ 4 ], n13 = te[ 8 ], n14 = te[ 12 ]; - const n21 = te[ 1 ], n22 = te[ 5 ], n23 = te[ 9 ], n24 = te[ 13 ]; - const n31 = te[ 2 ], n32 = te[ 6 ], n33 = te[ 10 ], n34 = te[ 14 ]; - const n41 = te[ 3 ], n42 = te[ 7 ], n43 = te[ 11 ], n44 = te[ 15 ]; - - //TODO: make this more efficient - //( based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm ) - - return ( - n41 * ( - + n14 * n23 * n32 - - n13 * n24 * n32 - - n14 * n22 * n33 - + n12 * n24 * n33 - + n13 * n22 * n34 - - n12 * n23 * n34 - ) + - n42 * ( - + n11 * n23 * n34 - - n11 * n24 * n33 - + n14 * n21 * n33 - - n13 * n21 * n34 - + n13 * n24 * n31 - - n14 * n23 * n31 - ) + - n43 * ( - + n11 * n24 * n32 - - n11 * n22 * n34 - - n14 * n21 * n32 - + n12 * n21 * n34 - + n14 * n22 * n31 - - n12 * n24 * n31 - ) + - n44 * ( - - n13 * n22 * n31 - - n11 * n23 * n32 - + n11 * n22 * n33 - + n13 * n21 * n32 - - n12 * n21 * n33 - + n12 * n23 * n31 - ) - - ); - - } - - transpose() { - - const te = this.elements; - let tmp; - - tmp = te[ 1 ]; te[ 1 ] = te[ 4 ]; te[ 4 ] = tmp; - tmp = te[ 2 ]; te[ 2 ] = te[ 8 ]; te[ 8 ] = tmp; - tmp = te[ 6 ]; te[ 6 ] = te[ 9 ]; te[ 9 ] = tmp; - - tmp = te[ 3 ]; te[ 3 ] = te[ 12 ]; te[ 12 ] = tmp; - tmp = te[ 7 ]; te[ 7 ] = te[ 13 ]; te[ 13 ] = tmp; - tmp = te[ 11 ]; te[ 11 ] = te[ 14 ]; te[ 14 ] = tmp; - - return this; - - } - - setPosition( x, y, z ) { - - const te = this.elements; - - if ( x.isVector3 ) { - - te[ 12 ] = x.x; - te[ 13 ] = x.y; - te[ 14 ] = x.z; - - } else { - - te[ 12 ] = x; - te[ 13 ] = y; - te[ 14 ] = z; - - } - - return this; - - } - - invert() { - - // based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm - const te = this.elements, - - n11 = te[ 0 ], n21 = te[ 1 ], n31 = te[ 2 ], n41 = te[ 3 ], - n12 = te[ 4 ], n22 = te[ 5 ], n32 = te[ 6 ], n42 = te[ 7 ], - n13 = te[ 8 ], n23 = te[ 9 ], n33 = te[ 10 ], n43 = te[ 11 ], - n14 = te[ 12 ], n24 = te[ 13 ], n34 = te[ 14 ], n44 = te[ 15 ], - - t11 = n23 * n34 * n42 - n24 * n33 * n42 + n24 * n32 * n43 - n22 * n34 * n43 - n23 * n32 * n44 + n22 * n33 * n44, - t12 = n14 * n33 * n42 - n13 * n34 * n42 - n14 * n32 * n43 + n12 * n34 * n43 + n13 * n32 * n44 - n12 * n33 * n44, - t13 = n13 * n24 * n42 - n14 * n23 * n42 + n14 * n22 * n43 - n12 * n24 * n43 - n13 * n22 * n44 + n12 * n23 * n44, - t14 = n14 * n23 * n32 - n13 * n24 * n32 - n14 * n22 * n33 + n12 * n24 * n33 + n13 * n22 * n34 - n12 * n23 * n34; - - const det = n11 * t11 + n21 * t12 + n31 * t13 + n41 * t14; - - if ( det === 0 ) return this.set( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ); - - const detInv = 1 / det; - - te[ 0 ] = t11 * detInv; - te[ 1 ] = ( n24 * n33 * n41 - n23 * n34 * n41 - n24 * n31 * n43 + n21 * n34 * n43 + n23 * n31 * n44 - n21 * n33 * n44 ) * detInv; - te[ 2 ] = ( n22 * n34 * n41 - n24 * n32 * n41 + n24 * n31 * n42 - n21 * n34 * n42 - n22 * n31 * n44 + n21 * n32 * n44 ) * detInv; - te[ 3 ] = ( n23 * n32 * n41 - n22 * n33 * n41 - n23 * n31 * n42 + n21 * n33 * n42 + n22 * n31 * n43 - n21 * n32 * n43 ) * detInv; - - te[ 4 ] = t12 * detInv; - te[ 5 ] = ( n13 * n34 * n41 - n14 * n33 * n41 + n14 * n31 * n43 - n11 * n34 * n43 - n13 * n31 * n44 + n11 * n33 * n44 ) * detInv; - te[ 6 ] = ( n14 * n32 * n41 - n12 * n34 * n41 - n14 * n31 * n42 + n11 * n34 * n42 + n12 * n31 * n44 - n11 * n32 * n44 ) * detInv; - te[ 7 ] = ( n12 * n33 * n41 - n13 * n32 * n41 + n13 * n31 * n42 - n11 * n33 * n42 - n12 * n31 * n43 + n11 * n32 * n43 ) * detInv; - - te[ 8 ] = t13 * detInv; - te[ 9 ] = ( n14 * n23 * n41 - n13 * n24 * n41 - n14 * n21 * n43 + n11 * n24 * n43 + n13 * n21 * n44 - n11 * n23 * n44 ) * detInv; - te[ 10 ] = ( n12 * n24 * n41 - n14 * n22 * n41 + n14 * n21 * n42 - n11 * n24 * n42 - n12 * n21 * n44 + n11 * n22 * n44 ) * detInv; - te[ 11 ] = ( n13 * n22 * n41 - n12 * n23 * n41 - n13 * n21 * n42 + n11 * n23 * n42 + n12 * n21 * n43 - n11 * n22 * n43 ) * detInv; - - te[ 12 ] = t14 * detInv; - te[ 13 ] = ( n13 * n24 * n31 - n14 * n23 * n31 + n14 * n21 * n33 - n11 * n24 * n33 - n13 * n21 * n34 + n11 * n23 * n34 ) * detInv; - te[ 14 ] = ( n14 * n22 * n31 - n12 * n24 * n31 - n14 * n21 * n32 + n11 * n24 * n32 + n12 * n21 * n34 - n11 * n22 * n34 ) * detInv; - te[ 15 ] = ( n12 * n23 * n31 - n13 * n22 * n31 + n13 * n21 * n32 - n11 * n23 * n32 - n12 * n21 * n33 + n11 * n22 * n33 ) * detInv; - - return this; - - } - - scale( v ) { - - const te = this.elements; - const x = v.x, y = v.y, z = v.z; - - te[ 0 ] *= x; te[ 4 ] *= y; te[ 8 ] *= z; - te[ 1 ] *= x; te[ 5 ] *= y; te[ 9 ] *= z; - te[ 2 ] *= x; te[ 6 ] *= y; te[ 10 ] *= z; - te[ 3 ] *= x; te[ 7 ] *= y; te[ 11 ] *= z; - - return this; - - } - - getMaxScaleOnAxis() { - - const te = this.elements; - - const scaleXSq = te[ 0 ] * te[ 0 ] + te[ 1 ] * te[ 1 ] + te[ 2 ] * te[ 2 ]; - const scaleYSq = te[ 4 ] * te[ 4 ] + te[ 5 ] * te[ 5 ] + te[ 6 ] * te[ 6 ]; - const scaleZSq = te[ 8 ] * te[ 8 ] + te[ 9 ] * te[ 9 ] + te[ 10 ] * te[ 10 ]; - - return Math.sqrt( Math.max( scaleXSq, scaleYSq, scaleZSq ) ); - - } - - makeTranslation( x, y, z ) { - - if ( x.isVector3 ) { - - this.set( - - 1, 0, 0, x.x, - 0, 1, 0, x.y, - 0, 0, 1, x.z, - 0, 0, 0, 1 - - ); - - } else { - - this.set( - - 1, 0, 0, x, - 0, 1, 0, y, - 0, 0, 1, z, - 0, 0, 0, 1 - - ); - - } - - return this; - - } - - makeRotationX( theta ) { - - const c = Math.cos( theta ), s = Math.sin( theta ); - - this.set( - - 1, 0, 0, 0, - 0, c, - s, 0, - 0, s, c, 0, - 0, 0, 0, 1 - - ); - - return this; - - } - - makeRotationY( theta ) { - - const c = Math.cos( theta ), s = Math.sin( theta ); - - this.set( - - c, 0, s, 0, - 0, 1, 0, 0, - - s, 0, c, 0, - 0, 0, 0, 1 - - ); - - return this; - - } - - makeRotationZ( theta ) { - - const c = Math.cos( theta ), s = Math.sin( theta ); - - this.set( - - c, - s, 0, 0, - s, c, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1 - - ); - - return this; - - } - - makeRotationAxis( axis, angle ) { - - // Based on http://www.gamedev.net/reference/articles/article1199.asp - - const c = Math.cos( angle ); - const s = Math.sin( angle ); - const t = 1 - c; - const x = axis.x, y = axis.y, z = axis.z; - const tx = t * x, ty = t * y; - - this.set( - - tx * x + c, tx * y - s * z, tx * z + s * y, 0, - tx * y + s * z, ty * y + c, ty * z - s * x, 0, - tx * z - s * y, ty * z + s * x, t * z * z + c, 0, - 0, 0, 0, 1 - - ); - - return this; - - } - - makeScale( x, y, z ) { - - this.set( - - x, 0, 0, 0, - 0, y, 0, 0, - 0, 0, z, 0, - 0, 0, 0, 1 - - ); - - return this; - - } - - makeShear( xy, xz, yx, yz, zx, zy ) { - - this.set( - - 1, yx, zx, 0, - xy, 1, zy, 0, - xz, yz, 1, 0, - 0, 0, 0, 1 - - ); - - return this; - - } - - compose( position, quaternion, scale ) { - - const te = this.elements; - - const x = quaternion._x, y = quaternion._y, z = quaternion._z, w = quaternion._w; - const x2 = x + x, y2 = y + y, z2 = z + z; - const xx = x * x2, xy = x * y2, xz = x * z2; - const yy = y * y2, yz = y * z2, zz = z * z2; - const wx = w * x2, wy = w * y2, wz = w * z2; - - const sx = scale.x, sy = scale.y, sz = scale.z; - - te[ 0 ] = ( 1 - ( yy + zz ) ) * sx; - te[ 1 ] = ( xy + wz ) * sx; - te[ 2 ] = ( xz - wy ) * sx; - te[ 3 ] = 0; - - te[ 4 ] = ( xy - wz ) * sy; - te[ 5 ] = ( 1 - ( xx + zz ) ) * sy; - te[ 6 ] = ( yz + wx ) * sy; - te[ 7 ] = 0; - - te[ 8 ] = ( xz + wy ) * sz; - te[ 9 ] = ( yz - wx ) * sz; - te[ 10 ] = ( 1 - ( xx + yy ) ) * sz; - te[ 11 ] = 0; - - te[ 12 ] = position.x; - te[ 13 ] = position.y; - te[ 14 ] = position.z; - te[ 15 ] = 1; - - return this; - - } - - decompose( position, quaternion, scale ) { - - const te = this.elements; - - let sx = _v1$5.set( te[ 0 ], te[ 1 ], te[ 2 ] ).length(); - const sy = _v1$5.set( te[ 4 ], te[ 5 ], te[ 6 ] ).length(); - const sz = _v1$5.set( te[ 8 ], te[ 9 ], te[ 10 ] ).length(); - - // if determine is negative, we need to invert one scale - const det = this.determinant(); - if ( det < 0 ) sx = - sx; - - position.x = te[ 12 ]; - position.y = te[ 13 ]; - position.z = te[ 14 ]; - - // scale the rotation part - _m1$2.copy( this ); - - const invSX = 1 / sx; - const invSY = 1 / sy; - const invSZ = 1 / sz; - - _m1$2.elements[ 0 ] *= invSX; - _m1$2.elements[ 1 ] *= invSX; - _m1$2.elements[ 2 ] *= invSX; - - _m1$2.elements[ 4 ] *= invSY; - _m1$2.elements[ 5 ] *= invSY; - _m1$2.elements[ 6 ] *= invSY; - - _m1$2.elements[ 8 ] *= invSZ; - _m1$2.elements[ 9 ] *= invSZ; - _m1$2.elements[ 10 ] *= invSZ; - - quaternion.setFromRotationMatrix( _m1$2 ); - - scale.x = sx; - scale.y = sy; - scale.z = sz; - - return this; - - } - - makePerspective( left, right, top, bottom, near, far, coordinateSystem = WebGLCoordinateSystem ) { - - const te = this.elements; - const x = 2 * near / ( right - left ); - const y = 2 * near / ( top - bottom ); - - const a = ( right + left ) / ( right - left ); - const b = ( top + bottom ) / ( top - bottom ); - - let c, d; - - if ( coordinateSystem === WebGLCoordinateSystem ) { - - c = - ( far + near ) / ( far - near ); - d = ( - 2 * far * near ) / ( far - near ); - - } else if ( coordinateSystem === WebGPUCoordinateSystem ) { - - c = - far / ( far - near ); - d = ( - far * near ) / ( far - near ); - - } else { - - throw new Error( 'THREE.Matrix4.makePerspective(): Invalid coordinate system: ' + coordinateSystem ); - - } - - te[ 0 ] = x; te[ 4 ] = 0; te[ 8 ] = a; te[ 12 ] = 0; - te[ 1 ] = 0; te[ 5 ] = y; te[ 9 ] = b; te[ 13 ] = 0; - te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = c; te[ 14 ] = d; - te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = - 1; te[ 15 ] = 0; - - return this; - - } - - makeOrthographic( left, right, top, bottom, near, far, coordinateSystem = WebGLCoordinateSystem ) { - - const te = this.elements; - const w = 1.0 / ( right - left ); - const h = 1.0 / ( top - bottom ); - const p = 1.0 / ( far - near ); - - const x = ( right + left ) * w; - const y = ( top + bottom ) * h; - - let z, zInv; - - if ( coordinateSystem === WebGLCoordinateSystem ) { - - z = ( far + near ) * p; - zInv = - 2 * p; - - } else if ( coordinateSystem === WebGPUCoordinateSystem ) { - - z = near * p; - zInv = - 1 * p; - - } else { - - throw new Error( 'THREE.Matrix4.makeOrthographic(): Invalid coordinate system: ' + coordinateSystem ); - - } - - te[ 0 ] = 2 * w; te[ 4 ] = 0; te[ 8 ] = 0; te[ 12 ] = - x; - te[ 1 ] = 0; te[ 5 ] = 2 * h; te[ 9 ] = 0; te[ 13 ] = - y; - te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = zInv; te[ 14 ] = - z; - te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = 0; te[ 15 ] = 1; - - return this; - - } - - equals( matrix ) { - - const te = this.elements; - const me = matrix.elements; - - for ( let i = 0; i < 16; i ++ ) { - - if ( te[ i ] !== me[ i ] ) return false; - - } - - return true; - - } - - fromArray( array, offset = 0 ) { - - for ( let i = 0; i < 16; i ++ ) { - - this.elements[ i ] = array[ i + offset ]; - - } - - return this; - - } - - toArray( array = [], offset = 0 ) { - - const te = this.elements; - - array[ offset ] = te[ 0 ]; - array[ offset + 1 ] = te[ 1 ]; - array[ offset + 2 ] = te[ 2 ]; - array[ offset + 3 ] = te[ 3 ]; - - array[ offset + 4 ] = te[ 4 ]; - array[ offset + 5 ] = te[ 5 ]; - array[ offset + 6 ] = te[ 6 ]; - array[ offset + 7 ] = te[ 7 ]; - - array[ offset + 8 ] = te[ 8 ]; - array[ offset + 9 ] = te[ 9 ]; - array[ offset + 10 ] = te[ 10 ]; - array[ offset + 11 ] = te[ 11 ]; - - array[ offset + 12 ] = te[ 12 ]; - array[ offset + 13 ] = te[ 13 ]; - array[ offset + 14 ] = te[ 14 ]; - array[ offset + 15 ] = te[ 15 ]; - - return array; - - } - -} - -const _v1$5 = /*@__PURE__*/ new Vector3(); -const _m1$2 = /*@__PURE__*/ new Matrix4(); -const _zero = /*@__PURE__*/ new Vector3( 0, 0, 0 ); -const _one = /*@__PURE__*/ new Vector3( 1, 1, 1 ); -const _x = /*@__PURE__*/ new Vector3(); -const _y = /*@__PURE__*/ new Vector3(); -const _z = /*@__PURE__*/ new Vector3(); - -const _matrix$1 = /*@__PURE__*/ new Matrix4(); -const _quaternion$3 = /*@__PURE__*/ new Quaternion(); - -class Euler { - - constructor( x = 0, y = 0, z = 0, order = Euler.DEFAULT_ORDER ) { - - this.isEuler = true; - - this._x = x; - this._y = y; - this._z = z; - this._order = order; - - } - - get x() { - - return this._x; - - } - - set x( value ) { - - this._x = value; - this._onChangeCallback(); - - } - - get y() { - - return this._y; - - } - - set y( value ) { - - this._y = value; - this._onChangeCallback(); - - } - - get z() { - - return this._z; - - } - - set z( value ) { - - this._z = value; - this._onChangeCallback(); - - } - - get order() { - - return this._order; - - } - - set order( value ) { - - this._order = value; - this._onChangeCallback(); - - } - - set( x, y, z, order = this._order ) { - - this._x = x; - this._y = y; - this._z = z; - this._order = order; - - this._onChangeCallback(); - - return this; - - } - - clone() { - - return new this.constructor( this._x, this._y, this._z, this._order ); - - } - - copy( euler ) { - - this._x = euler._x; - this._y = euler._y; - this._z = euler._z; - this._order = euler._order; - - this._onChangeCallback(); - - return this; - - } - - setFromRotationMatrix( m, order = this._order, update = true ) { - - // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) - - const te = m.elements; - const m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ]; - const m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ]; - const m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ]; - - switch ( order ) { - - case 'XYZ': - - this._y = Math.asin( clamp( m13, - 1, 1 ) ); - - if ( Math.abs( m13 ) < 0.9999999 ) { - - this._x = Math.atan2( - m23, m33 ); - this._z = Math.atan2( - m12, m11 ); - - } else { - - this._x = Math.atan2( m32, m22 ); - this._z = 0; - - } - - break; - - case 'YXZ': - - this._x = Math.asin( - clamp( m23, - 1, 1 ) ); - - if ( Math.abs( m23 ) < 0.9999999 ) { - - this._y = Math.atan2( m13, m33 ); - this._z = Math.atan2( m21, m22 ); - - } else { - - this._y = Math.atan2( - m31, m11 ); - this._z = 0; - - } - - break; - - case 'ZXY': - - this._x = Math.asin( clamp( m32, - 1, 1 ) ); - - if ( Math.abs( m32 ) < 0.9999999 ) { - - this._y = Math.atan2( - m31, m33 ); - this._z = Math.atan2( - m12, m22 ); - - } else { - - this._y = 0; - this._z = Math.atan2( m21, m11 ); - - } - - break; - - case 'ZYX': - - this._y = Math.asin( - clamp( m31, - 1, 1 ) ); - - if ( Math.abs( m31 ) < 0.9999999 ) { - - this._x = Math.atan2( m32, m33 ); - this._z = Math.atan2( m21, m11 ); - - } else { - - this._x = 0; - this._z = Math.atan2( - m12, m22 ); - - } - - break; - - case 'YZX': - - this._z = Math.asin( clamp( m21, - 1, 1 ) ); - - if ( Math.abs( m21 ) < 0.9999999 ) { - - this._x = Math.atan2( - m23, m22 ); - this._y = Math.atan2( - m31, m11 ); - - } else { - - this._x = 0; - this._y = Math.atan2( m13, m33 ); - - } - - break; - - case 'XZY': - - this._z = Math.asin( - clamp( m12, - 1, 1 ) ); - - if ( Math.abs( m12 ) < 0.9999999 ) { - - this._x = Math.atan2( m32, m22 ); - this._y = Math.atan2( m13, m11 ); - - } else { - - this._x = Math.atan2( - m23, m33 ); - this._y = 0; - - } - - break; - - default: - - console.warn( 'THREE.Euler: .setFromRotationMatrix() encountered an unknown order: ' + order ); - - } - - this._order = order; - - if ( update === true ) this._onChangeCallback(); - - return this; - - } - - setFromQuaternion( q, order, update ) { - - _matrix$1.makeRotationFromQuaternion( q ); - - return this.setFromRotationMatrix( _matrix$1, order, update ); - - } - - setFromVector3( v, order = this._order ) { - - return this.set( v.x, v.y, v.z, order ); - - } - - reorder( newOrder ) { - - // WARNING: this discards revolution information -bhouston - - _quaternion$3.setFromEuler( this ); - - return this.setFromQuaternion( _quaternion$3, newOrder ); - - } - - equals( euler ) { - - return ( euler._x === this._x ) && ( euler._y === this._y ) && ( euler._z === this._z ) && ( euler._order === this._order ); - - } - - fromArray( array ) { - - this._x = array[ 0 ]; - this._y = array[ 1 ]; - this._z = array[ 2 ]; - if ( array[ 3 ] !== undefined ) this._order = array[ 3 ]; - - this._onChangeCallback(); - - return this; - - } - - toArray( array = [], offset = 0 ) { - - array[ offset ] = this._x; - array[ offset + 1 ] = this._y; - array[ offset + 2 ] = this._z; - array[ offset + 3 ] = this._order; - - return array; - - } - - _onChange( callback ) { - - this._onChangeCallback = callback; - - return this; - - } - - _onChangeCallback() {} - - *[ Symbol.iterator ]() { - - yield this._x; - yield this._y; - yield this._z; - yield this._order; - - } - -} - -Euler.DEFAULT_ORDER = 'XYZ'; - -class Layers { - - constructor() { - - this.mask = 1 | 0; - - } - - set( channel ) { - - this.mask = ( 1 << channel | 0 ) >>> 0; - - } - - enable( channel ) { - - this.mask |= 1 << channel | 0; - - } - - enableAll() { - - this.mask = 0xffffffff | 0; - - } - - toggle( channel ) { - - this.mask ^= 1 << channel | 0; - - } - - disable( channel ) { - - this.mask &= ~ ( 1 << channel | 0 ); - - } - - disableAll() { - - this.mask = 0; - - } - - test( layers ) { - - return ( this.mask & layers.mask ) !== 0; - - } - - isEnabled( channel ) { - - return ( this.mask & ( 1 << channel | 0 ) ) !== 0; - - } - -} - -let _object3DId = 0; - -const _v1$4 = /*@__PURE__*/ new Vector3(); -const _q1 = /*@__PURE__*/ new Quaternion(); -const _m1$1 = /*@__PURE__*/ new Matrix4(); -const _target = /*@__PURE__*/ new Vector3(); - -const _position$3 = /*@__PURE__*/ new Vector3(); -const _scale$2 = /*@__PURE__*/ new Vector3(); -const _quaternion$2 = /*@__PURE__*/ new Quaternion(); - -const _xAxis = /*@__PURE__*/ new Vector3( 1, 0, 0 ); -const _yAxis = /*@__PURE__*/ new Vector3( 0, 1, 0 ); -const _zAxis = /*@__PURE__*/ new Vector3( 0, 0, 1 ); - -const _addedEvent = { type: 'added' }; -const _removedEvent = { type: 'removed' }; - -class Object3D extends EventDispatcher { - - constructor() { - - super(); - - this.isObject3D = true; - - Object.defineProperty( this, 'id', { value: _object3DId ++ } ); - - this.uuid = generateUUID(); - - this.name = ''; - this.type = 'Object3D'; - - this.parent = null; - this.children = []; - - this.up = Object3D.DEFAULT_UP.clone(); - - const position = new Vector3(); - const rotation = new Euler(); - const quaternion = new Quaternion(); - const scale = new Vector3( 1, 1, 1 ); - - function onRotationChange() { - - quaternion.setFromEuler( rotation, false ); - - } - - function onQuaternionChange() { - - rotation.setFromQuaternion( quaternion, undefined, false ); - - } - - rotation._onChange( onRotationChange ); - quaternion._onChange( onQuaternionChange ); - - Object.defineProperties( this, { - position: { - configurable: true, - enumerable: true, - value: position - }, - rotation: { - configurable: true, - enumerable: true, - value: rotation - }, - quaternion: { - configurable: true, - enumerable: true, - value: quaternion - }, - scale: { - configurable: true, - enumerable: true, - value: scale - }, - modelViewMatrix: { - value: new Matrix4() - }, - normalMatrix: { - value: new Matrix3() - } - } ); - - this.matrix = new Matrix4(); - this.matrixWorld = new Matrix4(); - - this.matrixAutoUpdate = Object3D.DEFAULT_MATRIX_AUTO_UPDATE; - - this.matrixWorldAutoUpdate = Object3D.DEFAULT_MATRIX_WORLD_AUTO_UPDATE; // checked by the renderer - this.matrixWorldNeedsUpdate = false; - - this.layers = new Layers(); - this.visible = true; - - this.castShadow = false; - this.receiveShadow = false; - - this.frustumCulled = true; - this.renderOrder = 0; - - this.animations = []; - - this.userData = {}; - - } - - onBeforeShadow( /* renderer, object, camera, shadowCamera, geometry, depthMaterial, group */ ) {} - - onAfterShadow( /* renderer, object, camera, shadowCamera, geometry, depthMaterial, group */ ) {} - - onBeforeRender( /* renderer, scene, camera, geometry, material, group */ ) {} - - onAfterRender( /* renderer, scene, camera, geometry, material, group */ ) {} - - applyMatrix4( matrix ) { - - if ( this.matrixAutoUpdate ) this.updateMatrix(); - - this.matrix.premultiply( matrix ); - - this.matrix.decompose( this.position, this.quaternion, this.scale ); - - } - - applyQuaternion( q ) { - - this.quaternion.premultiply( q ); - - return this; - - } - - setRotationFromAxisAngle( axis, angle ) { - - // assumes axis is normalized - - this.quaternion.setFromAxisAngle( axis, angle ); - - } - - setRotationFromEuler( euler ) { - - this.quaternion.setFromEuler( euler, true ); - - } - - setRotationFromMatrix( m ) { - - // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) - - this.quaternion.setFromRotationMatrix( m ); - - } - - setRotationFromQuaternion( q ) { - - // assumes q is normalized - - this.quaternion.copy( q ); - - } - - rotateOnAxis( axis, angle ) { - - // rotate object on axis in object space - // axis is assumed to be normalized - - _q1.setFromAxisAngle( axis, angle ); - - this.quaternion.multiply( _q1 ); - - return this; - - } - - rotateOnWorldAxis( axis, angle ) { - - // rotate object on axis in world space - // axis is assumed to be normalized - // method assumes no rotated parent - - _q1.setFromAxisAngle( axis, angle ); - - this.quaternion.premultiply( _q1 ); - - return this; - - } - - rotateX( angle ) { - - return this.rotateOnAxis( _xAxis, angle ); - - } - - rotateY( angle ) { - - return this.rotateOnAxis( _yAxis, angle ); - - } - - rotateZ( angle ) { - - return this.rotateOnAxis( _zAxis, angle ); - - } - - translateOnAxis( axis, distance ) { - - // translate object by distance along axis in object space - // axis is assumed to be normalized - - _v1$4.copy( axis ).applyQuaternion( this.quaternion ); - - this.position.add( _v1$4.multiplyScalar( distance ) ); - - return this; - - } - - translateX( distance ) { - - return this.translateOnAxis( _xAxis, distance ); - - } - - translateY( distance ) { - - return this.translateOnAxis( _yAxis, distance ); - - } - - translateZ( distance ) { - - return this.translateOnAxis( _zAxis, distance ); - - } - - localToWorld( vector ) { - - this.updateWorldMatrix( true, false ); - - return vector.applyMatrix4( this.matrixWorld ); - - } - - worldToLocal( vector ) { - - this.updateWorldMatrix( true, false ); - - return vector.applyMatrix4( _m1$1.copy( this.matrixWorld ).invert() ); - - } - - lookAt( x, y, z ) { - - // This method does not support objects having non-uniformly-scaled parent(s) - - if ( x.isVector3 ) { - - _target.copy( x ); - - } else { - - _target.set( x, y, z ); - - } - - const parent = this.parent; - - this.updateWorldMatrix( true, false ); - - _position$3.setFromMatrixPosition( this.matrixWorld ); - - if ( this.isCamera || this.isLight ) { - - _m1$1.lookAt( _position$3, _target, this.up ); - - } else { - - _m1$1.lookAt( _target, _position$3, this.up ); - - } - - this.quaternion.setFromRotationMatrix( _m1$1 ); - - if ( parent ) { - - _m1$1.extractRotation( parent.matrixWorld ); - _q1.setFromRotationMatrix( _m1$1 ); - this.quaternion.premultiply( _q1.invert() ); - - } - - } - - add( object ) { - - if ( arguments.length > 1 ) { - - for ( let i = 0; i < arguments.length; i ++ ) { - - this.add( arguments[ i ] ); - - } - - return this; - - } - - if ( object === this ) { - - console.error( 'THREE.Object3D.add: object can\'t be added as a child of itself.', object ); - return this; - - } - - if ( object && object.isObject3D ) { - - if ( object.parent !== null ) { - - object.parent.remove( object ); - - } - - object.parent = this; - this.children.push( object ); - - object.dispatchEvent( _addedEvent ); - - } else { - - console.error( 'THREE.Object3D.add: object not an instance of THREE.Object3D.', object ); - - } - - return this; - - } - - remove( object ) { - - if ( arguments.length > 1 ) { - - for ( let i = 0; i < arguments.length; i ++ ) { - - this.remove( arguments[ i ] ); - - } - - return this; - - } - - const index = this.children.indexOf( object ); - - if ( index !== - 1 ) { - - object.parent = null; - this.children.splice( index, 1 ); - - object.dispatchEvent( _removedEvent ); - - } - - return this; - - } - - removeFromParent() { - - const parent = this.parent; - - if ( parent !== null ) { - - parent.remove( this ); - - } - - return this; - - } - - clear() { - - return this.remove( ... this.children ); - - } - - attach( object ) { - - // adds object as a child of this, while maintaining the object's world transform - - // Note: This method does not support scene graphs having non-uniformly-scaled nodes(s) - - this.updateWorldMatrix( true, false ); - - _m1$1.copy( this.matrixWorld ).invert(); - - if ( object.parent !== null ) { - - object.parent.updateWorldMatrix( true, false ); - - _m1$1.multiply( object.parent.matrixWorld ); - - } - - object.applyMatrix4( _m1$1 ); - - this.add( object ); - - object.updateWorldMatrix( false, true ); - - return this; - - } - - getObjectById( id ) { - - return this.getObjectByProperty( 'id', id ); - - } - - getObjectByName( name ) { - - return this.getObjectByProperty( 'name', name ); - - } - - getObjectByProperty( name, value ) { - - if ( this[ name ] === value ) return this; - - for ( let i = 0, l = this.children.length; i < l; i ++ ) { - - const child = this.children[ i ]; - const object = child.getObjectByProperty( name, value ); - - if ( object !== undefined ) { - - return object; - - } - - } - - return undefined; - - } - - getObjectsByProperty( name, value, result = [] ) { - - if ( this[ name ] === value ) result.push( this ); - - const children = this.children; - - for ( let i = 0, l = children.length; i < l; i ++ ) { - - children[ i ].getObjectsByProperty( name, value, result ); - - } - - return result; - - } - - getWorldPosition( target ) { - - this.updateWorldMatrix( true, false ); - - return target.setFromMatrixPosition( this.matrixWorld ); - - } - - getWorldQuaternion( target ) { - - this.updateWorldMatrix( true, false ); - - this.matrixWorld.decompose( _position$3, target, _scale$2 ); - - return target; - - } - - getWorldScale( target ) { - - this.updateWorldMatrix( true, false ); - - this.matrixWorld.decompose( _position$3, _quaternion$2, target ); - - return target; - - } - - getWorldDirection( target ) { - - this.updateWorldMatrix( true, false ); - - const e = this.matrixWorld.elements; - - return target.set( e[ 8 ], e[ 9 ], e[ 10 ] ).normalize(); - - } - - raycast( /* raycaster, intersects */ ) {} - - traverse( callback ) { - - callback( this ); - - const children = this.children; - - for ( let i = 0, l = children.length; i < l; i ++ ) { - - children[ i ].traverse( callback ); - - } - - } - - traverseVisible( callback ) { - - if ( this.visible === false ) return; - - callback( this ); - - const children = this.children; - - for ( let i = 0, l = children.length; i < l; i ++ ) { - - children[ i ].traverseVisible( callback ); - - } - - } - - traverseAncestors( callback ) { - - const parent = this.parent; - - if ( parent !== null ) { - - callback( parent ); - - parent.traverseAncestors( callback ); - - } - - } - - updateMatrix() { - - this.matrix.compose( this.position, this.quaternion, this.scale ); - - this.matrixWorldNeedsUpdate = true; - - } - - updateMatrixWorld( force ) { - - if ( this.matrixAutoUpdate ) this.updateMatrix(); - - if ( this.matrixWorldNeedsUpdate || force ) { - - if ( this.parent === null ) { - - this.matrixWorld.copy( this.matrix ); - - } else { - - this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); - - } - - this.matrixWorldNeedsUpdate = false; - - force = true; - - } - - // update children - - const children = this.children; - - for ( let i = 0, l = children.length; i < l; i ++ ) { - - const child = children[ i ]; - - if ( child.matrixWorldAutoUpdate === true || force === true ) { - - child.updateMatrixWorld( force ); - - } - - } - - } - - updateWorldMatrix( updateParents, updateChildren ) { - - const parent = this.parent; - - if ( updateParents === true && parent !== null && parent.matrixWorldAutoUpdate === true ) { - - parent.updateWorldMatrix( true, false ); - - } - - if ( this.matrixAutoUpdate ) this.updateMatrix(); - - if ( this.parent === null ) { - - this.matrixWorld.copy( this.matrix ); - - } else { - - this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); - - } - - // update children - - if ( updateChildren === true ) { - - const children = this.children; - - for ( let i = 0, l = children.length; i < l; i ++ ) { - - const child = children[ i ]; - - if ( child.matrixWorldAutoUpdate === true ) { - - child.updateWorldMatrix( false, true ); - - } - - } - - } - - } - - toJSON( meta ) { - - // meta is a string when called from JSON.stringify - const isRootObject = ( meta === undefined || typeof meta === 'string' ); - - const output = {}; - - // meta is a hash used to collect geometries, materials. - // not providing it implies that this is the root object - // being serialized. - if ( isRootObject ) { - - // initialize meta obj - meta = { - geometries: {}, - materials: {}, - textures: {}, - images: {}, - shapes: {}, - skeletons: {}, - animations: {}, - nodes: {} - }; - - output.metadata = { - version: 4.6, - type: 'Object', - generator: 'Object3D.toJSON' - }; - - } - - // standard Object3D serialization - - const object = {}; - - object.uuid = this.uuid; - object.type = this.type; - - if ( this.name !== '' ) object.name = this.name; - if ( this.castShadow === true ) object.castShadow = true; - if ( this.receiveShadow === true ) object.receiveShadow = true; - if ( this.visible === false ) object.visible = false; - if ( this.frustumCulled === false ) object.frustumCulled = false; - if ( this.renderOrder !== 0 ) object.renderOrder = this.renderOrder; - if ( Object.keys( this.userData ).length > 0 ) object.userData = this.userData; - - object.layers = this.layers.mask; - object.matrix = this.matrix.toArray(); - object.up = this.up.toArray(); - - if ( this.matrixAutoUpdate === false ) object.matrixAutoUpdate = false; - - // object specific properties - - if ( this.isInstancedMesh ) { - - object.type = 'InstancedMesh'; - object.count = this.count; - object.instanceMatrix = this.instanceMatrix.toJSON(); - if ( this.instanceColor !== null ) object.instanceColor = this.instanceColor.toJSON(); - - } - - if ( this.isBatchedMesh ) { - - object.type = 'BatchedMesh'; - object.perObjectFrustumCulled = this.perObjectFrustumCulled; - object.sortObjects = this.sortObjects; - - object.drawRanges = this._drawRanges; - object.reservedRanges = this._reservedRanges; - - object.visibility = this._visibility; - object.active = this._active; - object.bounds = this._bounds.map( bound => ( { - boxInitialized: bound.boxInitialized, - boxMin: bound.box.min.toArray(), - boxMax: bound.box.max.toArray(), - - sphereInitialized: bound.sphereInitialized, - sphereRadius: bound.sphere.radius, - sphereCenter: bound.sphere.center.toArray() - } ) ); - - object.maxGeometryCount = this._maxGeometryCount; - object.maxVertexCount = this._maxVertexCount; - object.maxIndexCount = this._maxIndexCount; - - object.geometryInitialized = this._geometryInitialized; - object.geometryCount = this._geometryCount; - - object.matricesTexture = this._matricesTexture.toJSON( meta ); - - if ( this.boundingSphere !== null ) { - - object.boundingSphere = { - center: object.boundingSphere.center.toArray(), - radius: object.boundingSphere.radius - }; - - } - - if ( this.boundingBox !== null ) { - - object.boundingBox = { - min: object.boundingBox.min.toArray(), - max: object.boundingBox.max.toArray() - }; - - } - - } - - // - - function serialize( library, element ) { - - if ( library[ element.uuid ] === undefined ) { - - library[ element.uuid ] = element.toJSON( meta ); - - } - - return element.uuid; - - } - - if ( this.isScene ) { - - if ( this.background ) { - - if ( this.background.isColor ) { - - object.background = this.background.toJSON(); - - } else if ( this.background.isTexture ) { - - object.background = this.background.toJSON( meta ).uuid; - - } - - } - - if ( this.environment && this.environment.isTexture && this.environment.isRenderTargetTexture !== true ) { - - object.environment = this.environment.toJSON( meta ).uuid; - - } - - } else if ( this.isMesh || this.isLine || this.isPoints ) { - - object.geometry = serialize( meta.geometries, this.geometry ); - - const parameters = this.geometry.parameters; - - if ( parameters !== undefined && parameters.shapes !== undefined ) { - - const shapes = parameters.shapes; - - if ( Array.isArray( shapes ) ) { - - for ( let i = 0, l = shapes.length; i < l; i ++ ) { - - const shape = shapes[ i ]; - - serialize( meta.shapes, shape ); - - } - - } else { - - serialize( meta.shapes, shapes ); - - } - - } - - } - - if ( this.isSkinnedMesh ) { - - object.bindMode = this.bindMode; - object.bindMatrix = this.bindMatrix.toArray(); - - if ( this.skeleton !== undefined ) { - - serialize( meta.skeletons, this.skeleton ); - - object.skeleton = this.skeleton.uuid; - - } - - } - - if ( this.material !== undefined ) { - - if ( Array.isArray( this.material ) ) { - - const uuids = []; - - for ( let i = 0, l = this.material.length; i < l; i ++ ) { - - uuids.push( serialize( meta.materials, this.material[ i ] ) ); - - } - - object.material = uuids; - - } else { - - object.material = serialize( meta.materials, this.material ); - - } - - } - - // - - if ( this.children.length > 0 ) { - - object.children = []; - - for ( let i = 0; i < this.children.length; i ++ ) { - - object.children.push( this.children[ i ].toJSON( meta ).object ); - - } - - } - - // - - if ( this.animations.length > 0 ) { - - object.animations = []; - - for ( let i = 0; i < this.animations.length; i ++ ) { - - const animation = this.animations[ i ]; - - object.animations.push( serialize( meta.animations, animation ) ); - - } - - } - - if ( isRootObject ) { - - const geometries = extractFromCache( meta.geometries ); - const materials = extractFromCache( meta.materials ); - const textures = extractFromCache( meta.textures ); - const images = extractFromCache( meta.images ); - const shapes = extractFromCache( meta.shapes ); - const skeletons = extractFromCache( meta.skeletons ); - const animations = extractFromCache( meta.animations ); - const nodes = extractFromCache( meta.nodes ); - - if ( geometries.length > 0 ) output.geometries = geometries; - if ( materials.length > 0 ) output.materials = materials; - if ( textures.length > 0 ) output.textures = textures; - if ( images.length > 0 ) output.images = images; - if ( shapes.length > 0 ) output.shapes = shapes; - if ( skeletons.length > 0 ) output.skeletons = skeletons; - if ( animations.length > 0 ) output.animations = animations; - if ( nodes.length > 0 ) output.nodes = nodes; - - } - - output.object = object; - - return output; - - // extract data from the cache hash - // remove metadata on each item - // and return as array - function extractFromCache( cache ) { - - const values = []; - for ( const key in cache ) { - - const data = cache[ key ]; - delete data.metadata; - values.push( data ); - - } - - return values; - - } - - } - - clone( recursive ) { - - return new this.constructor().copy( this, recursive ); - - } - - copy( source, recursive = true ) { - - this.name = source.name; - - this.up.copy( source.up ); - - this.position.copy( source.position ); - this.rotation.order = source.rotation.order; - this.quaternion.copy( source.quaternion ); - this.scale.copy( source.scale ); - - this.matrix.copy( source.matrix ); - this.matrixWorld.copy( source.matrixWorld ); - - this.matrixAutoUpdate = source.matrixAutoUpdate; - - this.matrixWorldAutoUpdate = source.matrixWorldAutoUpdate; - this.matrixWorldNeedsUpdate = source.matrixWorldNeedsUpdate; - - this.layers.mask = source.layers.mask; - this.visible = source.visible; - - this.castShadow = source.castShadow; - this.receiveShadow = source.receiveShadow; - - this.frustumCulled = source.frustumCulled; - this.renderOrder = source.renderOrder; - - this.animations = source.animations.slice(); - - this.userData = JSON.parse( JSON.stringify( source.userData ) ); - - if ( recursive === true ) { - - for ( let i = 0; i < source.children.length; i ++ ) { - - const child = source.children[ i ]; - this.add( child.clone() ); - - } - - } - - return this; - - } - -} - -Object3D.DEFAULT_UP = /*@__PURE__*/ new Vector3( 0, 1, 0 ); -Object3D.DEFAULT_MATRIX_AUTO_UPDATE = true; -Object3D.DEFAULT_MATRIX_WORLD_AUTO_UPDATE = true; - -const _v0$1 = /*@__PURE__*/ new Vector3(); -const _v1$3 = /*@__PURE__*/ new Vector3(); -const _v2$2 = /*@__PURE__*/ new Vector3(); -const _v3$2 = /*@__PURE__*/ new Vector3(); - -const _vab = /*@__PURE__*/ new Vector3(); -const _vac = /*@__PURE__*/ new Vector3(); -const _vbc = /*@__PURE__*/ new Vector3(); -const _vap = /*@__PURE__*/ new Vector3(); -const _vbp = /*@__PURE__*/ new Vector3(); -const _vcp = /*@__PURE__*/ new Vector3(); - -class Triangle { - - constructor( a = new Vector3(), b = new Vector3(), c = new Vector3() ) { - - this.a = a; - this.b = b; - this.c = c; - - } - - static getNormal( a, b, c, target ) { - - target.subVectors( c, b ); - _v0$1.subVectors( a, b ); - target.cross( _v0$1 ); - - const targetLengthSq = target.lengthSq(); - if ( targetLengthSq > 0 ) { - - return target.multiplyScalar( 1 / Math.sqrt( targetLengthSq ) ); - - } - - return target.set( 0, 0, 0 ); - - } - - // static/instance method to calculate barycentric coordinates - // based on: http://www.blackpawn.com/texts/pointinpoly/default.html - static getBarycoord( point, a, b, c, target ) { - - _v0$1.subVectors( c, a ); - _v1$3.subVectors( b, a ); - _v2$2.subVectors( point, a ); - - const dot00 = _v0$1.dot( _v0$1 ); - const dot01 = _v0$1.dot( _v1$3 ); - const dot02 = _v0$1.dot( _v2$2 ); - const dot11 = _v1$3.dot( _v1$3 ); - const dot12 = _v1$3.dot( _v2$2 ); - - const denom = ( dot00 * dot11 - dot01 * dot01 ); - - // collinear or singular triangle - if ( denom === 0 ) { - - target.set( 0, 0, 0 ); - return null; - - } - - const invDenom = 1 / denom; - const u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom; - const v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom; - - // barycentric coordinates must always sum to 1 - return target.set( 1 - u - v, v, u ); - - } - - static containsPoint( point, a, b, c ) { - - // if the triangle is degenerate then we can't contain a point - if ( this.getBarycoord( point, a, b, c, _v3$2 ) === null ) { - - return false; - - } - - return ( _v3$2.x >= 0 ) && ( _v3$2.y >= 0 ) && ( ( _v3$2.x + _v3$2.y ) <= 1 ); - - } - - static getInterpolation( point, p1, p2, p3, v1, v2, v3, target ) { - - if ( this.getBarycoord( point, p1, p2, p3, _v3$2 ) === null ) { - - target.x = 0; - target.y = 0; - if ( 'z' in target ) target.z = 0; - if ( 'w' in target ) target.w = 0; - return null; - - } - - target.setScalar( 0 ); - target.addScaledVector( v1, _v3$2.x ); - target.addScaledVector( v2, _v3$2.y ); - target.addScaledVector( v3, _v3$2.z ); - - return target; - - } - - static isFrontFacing( a, b, c, direction ) { - - _v0$1.subVectors( c, b ); - _v1$3.subVectors( a, b ); - - // strictly front facing - return ( _v0$1.cross( _v1$3 ).dot( direction ) < 0 ) ? true : false; - - } - - set( a, b, c ) { - - this.a.copy( a ); - this.b.copy( b ); - this.c.copy( c ); - - return this; - - } - - setFromPointsAndIndices( points, i0, i1, i2 ) { - - this.a.copy( points[ i0 ] ); - this.b.copy( points[ i1 ] ); - this.c.copy( points[ i2 ] ); - - return this; - - } - - setFromAttributeAndIndices( attribute, i0, i1, i2 ) { - - this.a.fromBufferAttribute( attribute, i0 ); - this.b.fromBufferAttribute( attribute, i1 ); - this.c.fromBufferAttribute( attribute, i2 ); - - return this; - - } - - clone() { - - return new this.constructor().copy( this ); - - } - - copy( triangle ) { - - this.a.copy( triangle.a ); - this.b.copy( triangle.b ); - this.c.copy( triangle.c ); - - return this; - - } - - getArea() { - - _v0$1.subVectors( this.c, this.b ); - _v1$3.subVectors( this.a, this.b ); - - return _v0$1.cross( _v1$3 ).length() * 0.5; - - } - - getMidpoint( target ) { - - return target.addVectors( this.a, this.b ).add( this.c ).multiplyScalar( 1 / 3 ); - - } - - getNormal( target ) { - - return Triangle.getNormal( this.a, this.b, this.c, target ); - - } - - getPlane( target ) { - - return target.setFromCoplanarPoints( this.a, this.b, this.c ); - - } - - getBarycoord( point, target ) { - - return Triangle.getBarycoord( point, this.a, this.b, this.c, target ); - - } - - getInterpolation( point, v1, v2, v3, target ) { - - return Triangle.getInterpolation( point, this.a, this.b, this.c, v1, v2, v3, target ); - - } - - containsPoint( point ) { - - return Triangle.containsPoint( point, this.a, this.b, this.c ); - - } - - isFrontFacing( direction ) { - - return Triangle.isFrontFacing( this.a, this.b, this.c, direction ); - - } - - intersectsBox( box ) { - - return box.intersectsTriangle( this ); - - } - - closestPointToPoint( p, target ) { - - const a = this.a, b = this.b, c = this.c; - let v, w; - - // algorithm thanks to Real-Time Collision Detection by Christer Ericson, - // published by Morgan Kaufmann Publishers, (c) 2005 Elsevier Inc., - // under the accompanying license; see chapter 5.1.5 for detailed explanation. - // basically, we're distinguishing which of the voronoi regions of the triangle - // the point lies in with the minimum amount of redundant computation. - - _vab.subVectors( b, a ); - _vac.subVectors( c, a ); - _vap.subVectors( p, a ); - const d1 = _vab.dot( _vap ); - const d2 = _vac.dot( _vap ); - if ( d1 <= 0 && d2 <= 0 ) { - - // vertex region of A; barycentric coords (1, 0, 0) - return target.copy( a ); - - } - - _vbp.subVectors( p, b ); - const d3 = _vab.dot( _vbp ); - const d4 = _vac.dot( _vbp ); - if ( d3 >= 0 && d4 <= d3 ) { - - // vertex region of B; barycentric coords (0, 1, 0) - return target.copy( b ); - - } - - const vc = d1 * d4 - d3 * d2; - if ( vc <= 0 && d1 >= 0 && d3 <= 0 ) { - - v = d1 / ( d1 - d3 ); - // edge region of AB; barycentric coords (1-v, v, 0) - return target.copy( a ).addScaledVector( _vab, v ); - - } - - _vcp.subVectors( p, c ); - const d5 = _vab.dot( _vcp ); - const d6 = _vac.dot( _vcp ); - if ( d6 >= 0 && d5 <= d6 ) { - - // vertex region of C; barycentric coords (0, 0, 1) - return target.copy( c ); - - } - - const vb = d5 * d2 - d1 * d6; - if ( vb <= 0 && d2 >= 0 && d6 <= 0 ) { - - w = d2 / ( d2 - d6 ); - // edge region of AC; barycentric coords (1-w, 0, w) - return target.copy( a ).addScaledVector( _vac, w ); - - } - - const va = d3 * d6 - d5 * d4; - if ( va <= 0 && ( d4 - d3 ) >= 0 && ( d5 - d6 ) >= 0 ) { - - _vbc.subVectors( c, b ); - w = ( d4 - d3 ) / ( ( d4 - d3 ) + ( d5 - d6 ) ); - // edge region of BC; barycentric coords (0, 1-w, w) - return target.copy( b ).addScaledVector( _vbc, w ); // edge region of BC - - } - - // face region - const denom = 1 / ( va + vb + vc ); - // u = va * denom - v = vb * denom; - w = vc * denom; - - return target.copy( a ).addScaledVector( _vab, v ).addScaledVector( _vac, w ); - - } - - equals( triangle ) { - - return triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c ); - - } - -} - -const _colorKeywords = { 'aliceblue': 0xF0F8FF, 'antiquewhite': 0xFAEBD7, 'aqua': 0x00FFFF, 'aquamarine': 0x7FFFD4, 'azure': 0xF0FFFF, - 'beige': 0xF5F5DC, 'bisque': 0xFFE4C4, 'black': 0x000000, 'blanchedalmond': 0xFFEBCD, 'blue': 0x0000FF, 'blueviolet': 0x8A2BE2, - 'brown': 0xA52A2A, 'burlywood': 0xDEB887, 'cadetblue': 0x5F9EA0, 'chartreuse': 0x7FFF00, 'chocolate': 0xD2691E, 'coral': 0xFF7F50, - 'cornflowerblue': 0x6495ED, 'cornsilk': 0xFFF8DC, 'crimson': 0xDC143C, 'cyan': 0x00FFFF, 'darkblue': 0x00008B, 'darkcyan': 0x008B8B, - 'darkgoldenrod': 0xB8860B, 'darkgray': 0xA9A9A9, 'darkgreen': 0x006400, 'darkgrey': 0xA9A9A9, 'darkkhaki': 0xBDB76B, 'darkmagenta': 0x8B008B, - 'darkolivegreen': 0x556B2F, 'darkorange': 0xFF8C00, 'darkorchid': 0x9932CC, 'darkred': 0x8B0000, 'darksalmon': 0xE9967A, 'darkseagreen': 0x8FBC8F, - 'darkslateblue': 0x483D8B, 'darkslategray': 0x2F4F4F, 'darkslategrey': 0x2F4F4F, 'darkturquoise': 0x00CED1, 'darkviolet': 0x9400D3, - 'deeppink': 0xFF1493, 'deepskyblue': 0x00BFFF, 'dimgray': 0x696969, 'dimgrey': 0x696969, 'dodgerblue': 0x1E90FF, 'firebrick': 0xB22222, - 'floralwhite': 0xFFFAF0, 'forestgreen': 0x228B22, 'fuchsia': 0xFF00FF, 'gainsboro': 0xDCDCDC, 'ghostwhite': 0xF8F8FF, 'gold': 0xFFD700, - 'goldenrod': 0xDAA520, 'gray': 0x808080, 'green': 0x008000, 'greenyellow': 0xADFF2F, 'grey': 0x808080, 'honeydew': 0xF0FFF0, 'hotpink': 0xFF69B4, - 'indianred': 0xCD5C5C, 'indigo': 0x4B0082, 'ivory': 0xFFFFF0, 'khaki': 0xF0E68C, 'lavender': 0xE6E6FA, 'lavenderblush': 0xFFF0F5, 'lawngreen': 0x7CFC00, - 'lemonchiffon': 0xFFFACD, 'lightblue': 0xADD8E6, 'lightcoral': 0xF08080, 'lightcyan': 0xE0FFFF, 'lightgoldenrodyellow': 0xFAFAD2, 'lightgray': 0xD3D3D3, - 'lightgreen': 0x90EE90, 'lightgrey': 0xD3D3D3, 'lightpink': 0xFFB6C1, 'lightsalmon': 0xFFA07A, 'lightseagreen': 0x20B2AA, 'lightskyblue': 0x87CEFA, - 'lightslategray': 0x778899, 'lightslategrey': 0x778899, 'lightsteelblue': 0xB0C4DE, 'lightyellow': 0xFFFFE0, 'lime': 0x00FF00, 'limegreen': 0x32CD32, - 'linen': 0xFAF0E6, 'magenta': 0xFF00FF, 'maroon': 0x800000, 'mediumaquamarine': 0x66CDAA, 'mediumblue': 0x0000CD, 'mediumorchid': 0xBA55D3, - 'mediumpurple': 0x9370DB, 'mediumseagreen': 0x3CB371, 'mediumslateblue': 0x7B68EE, 'mediumspringgreen': 0x00FA9A, 'mediumturquoise': 0x48D1CC, - 'mediumvioletred': 0xC71585, 'midnightblue': 0x191970, 'mintcream': 0xF5FFFA, 'mistyrose': 0xFFE4E1, 'moccasin': 0xFFE4B5, 'navajowhite': 0xFFDEAD, - 'navy': 0x000080, 'oldlace': 0xFDF5E6, 'olive': 0x808000, 'olivedrab': 0x6B8E23, 'orange': 0xFFA500, 'orangered': 0xFF4500, 'orchid': 0xDA70D6, - 'palegoldenrod': 0xEEE8AA, 'palegreen': 0x98FB98, 'paleturquoise': 0xAFEEEE, 'palevioletred': 0xDB7093, 'papayawhip': 0xFFEFD5, 'peachpuff': 0xFFDAB9, - 'peru': 0xCD853F, 'pink': 0xFFC0CB, 'plum': 0xDDA0DD, 'powderblue': 0xB0E0E6, 'purple': 0x800080, 'rebeccapurple': 0x663399, 'red': 0xFF0000, 'rosybrown': 0xBC8F8F, - 'royalblue': 0x4169E1, 'saddlebrown': 0x8B4513, 'salmon': 0xFA8072, 'sandybrown': 0xF4A460, 'seagreen': 0x2E8B57, 'seashell': 0xFFF5EE, - 'sienna': 0xA0522D, 'silver': 0xC0C0C0, 'skyblue': 0x87CEEB, 'slateblue': 0x6A5ACD, 'slategray': 0x708090, 'slategrey': 0x708090, 'snow': 0xFFFAFA, - 'springgreen': 0x00FF7F, 'steelblue': 0x4682B4, 'tan': 0xD2B48C, 'teal': 0x008080, 'thistle': 0xD8BFD8, 'tomato': 0xFF6347, 'turquoise': 0x40E0D0, - 'violet': 0xEE82EE, 'wheat': 0xF5DEB3, 'white': 0xFFFFFF, 'whitesmoke': 0xF5F5F5, 'yellow': 0xFFFF00, 'yellowgreen': 0x9ACD32 }; - -const _hslA = { h: 0, s: 0, l: 0 }; -const _hslB = { h: 0, s: 0, l: 0 }; - -function hue2rgb( p, q, t ) { - - if ( t < 0 ) t += 1; - if ( t > 1 ) t -= 1; - if ( t < 1 / 6 ) return p + ( q - p ) * 6 * t; - if ( t < 1 / 2 ) return q; - if ( t < 2 / 3 ) return p + ( q - p ) * 6 * ( 2 / 3 - t ); - return p; - -} - -class Color { - - constructor( r, g, b ) { - - this.isColor = true; - - this.r = 1; - this.g = 1; - this.b = 1; - - return this.set( r, g, b ); - - } - - set( r, g, b ) { - - if ( g === undefined && b === undefined ) { - - // r is THREE.Color, hex or string - - const value = r; - - if ( value && value.isColor ) { - - this.copy( value ); - - } else if ( typeof value === 'number' ) { - - this.setHex( value ); - - } else if ( typeof value === 'string' ) { - - this.setStyle( value ); - - } - - } else { - - this.setRGB( r, g, b ); - - } - - return this; - - } - - setScalar( scalar ) { - - this.r = scalar; - this.g = scalar; - this.b = scalar; - - return this; - - } - - setHex( hex, colorSpace = SRGBColorSpace ) { - - hex = Math.floor( hex ); - - this.r = ( hex >> 16 & 255 ) / 255; - this.g = ( hex >> 8 & 255 ) / 255; - this.b = ( hex & 255 ) / 255; - - ColorManagement.toWorkingColorSpace( this, colorSpace ); - - return this; - - } - - setRGB( r, g, b, colorSpace = ColorManagement.workingColorSpace ) { - - this.r = r; - this.g = g; - this.b = b; - - ColorManagement.toWorkingColorSpace( this, colorSpace ); - - return this; - - } - - setHSL( h, s, l, colorSpace = ColorManagement.workingColorSpace ) { - - // h,s,l ranges are in 0.0 - 1.0 - h = euclideanModulo( h, 1 ); - s = clamp( s, 0, 1 ); - l = clamp( l, 0, 1 ); - - if ( s === 0 ) { - - this.r = this.g = this.b = l; - - } else { - - const p = l <= 0.5 ? l * ( 1 + s ) : l + s - ( l * s ); - const q = ( 2 * l ) - p; - - this.r = hue2rgb( q, p, h + 1 / 3 ); - this.g = hue2rgb( q, p, h ); - this.b = hue2rgb( q, p, h - 1 / 3 ); - - } - - ColorManagement.toWorkingColorSpace( this, colorSpace ); - - return this; - - } - - setStyle( style, colorSpace = SRGBColorSpace ) { - - function handleAlpha( string ) { - - if ( string === undefined ) return; - - if ( parseFloat( string ) < 1 ) { - - console.warn( 'THREE.Color: Alpha component of ' + style + ' will be ignored.' ); - - } - - } - - - let m; - - if ( m = /^(\w+)\(([^\)]*)\)/.exec( style ) ) { - - // rgb / hsl - - let color; - const name = m[ 1 ]; - const components = m[ 2 ]; - - switch ( name ) { - - case 'rgb': - case 'rgba': - - if ( color = /^\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) { - - // rgb(255,0,0) rgba(255,0,0,0.5) - - handleAlpha( color[ 4 ] ); - - return this.setRGB( - Math.min( 255, parseInt( color[ 1 ], 10 ) ) / 255, - Math.min( 255, parseInt( color[ 2 ], 10 ) ) / 255, - Math.min( 255, parseInt( color[ 3 ], 10 ) ) / 255, - colorSpace - ); - - } - - if ( color = /^\s*(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) { - - // rgb(100%,0%,0%) rgba(100%,0%,0%,0.5) - - handleAlpha( color[ 4 ] ); - - return this.setRGB( - Math.min( 100, parseInt( color[ 1 ], 10 ) ) / 100, - Math.min( 100, parseInt( color[ 2 ], 10 ) ) / 100, - Math.min( 100, parseInt( color[ 3 ], 10 ) ) / 100, - colorSpace - ); - - } - - break; - - case 'hsl': - case 'hsla': - - if ( color = /^\s*(\d*\.?\d+)\s*,\s*(\d*\.?\d+)\%\s*,\s*(\d*\.?\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) { - - // hsl(120,50%,50%) hsla(120,50%,50%,0.5) - - handleAlpha( color[ 4 ] ); - - return this.setHSL( - parseFloat( color[ 1 ] ) / 360, - parseFloat( color[ 2 ] ) / 100, - parseFloat( color[ 3 ] ) / 100, - colorSpace - ); - - } - - break; - - default: - - console.warn( 'THREE.Color: Unknown color model ' + style ); - - } - - } else if ( m = /^\#([A-Fa-f\d]+)$/.exec( style ) ) { - - // hex color - - const hex = m[ 1 ]; - const size = hex.length; - - if ( size === 3 ) { - - // #ff0 - return this.setRGB( - parseInt( hex.charAt( 0 ), 16 ) / 15, - parseInt( hex.charAt( 1 ), 16 ) / 15, - parseInt( hex.charAt( 2 ), 16 ) / 15, - colorSpace - ); - - } else if ( size === 6 ) { - - // #ff0000 - return this.setHex( parseInt( hex, 16 ), colorSpace ); - - } else { - - console.warn( 'THREE.Color: Invalid hex color ' + style ); - - } - - } else if ( style && style.length > 0 ) { - - return this.setColorName( style, colorSpace ); - - } - - return this; - - } - - setColorName( style, colorSpace = SRGBColorSpace ) { - - // color keywords - const hex = _colorKeywords[ style.toLowerCase() ]; - - if ( hex !== undefined ) { - - // red - this.setHex( hex, colorSpace ); - - } else { - - // unknown color - console.warn( 'THREE.Color: Unknown color ' + style ); - - } - - return this; - - } - - clone() { - - return new this.constructor( this.r, this.g, this.b ); - - } - - copy( color ) { - - this.r = color.r; - this.g = color.g; - this.b = color.b; - - return this; - - } - - copySRGBToLinear( color ) { - - this.r = SRGBToLinear( color.r ); - this.g = SRGBToLinear( color.g ); - this.b = SRGBToLinear( color.b ); - - return this; - - } - - copyLinearToSRGB( color ) { - - this.r = LinearToSRGB( color.r ); - this.g = LinearToSRGB( color.g ); - this.b = LinearToSRGB( color.b ); - - return this; - - } - - convertSRGBToLinear() { - - this.copySRGBToLinear( this ); - - return this; - - } - - convertLinearToSRGB() { - - this.copyLinearToSRGB( this ); - - return this; - - } - - getHex( colorSpace = SRGBColorSpace ) { - - ColorManagement.fromWorkingColorSpace( _color.copy( this ), colorSpace ); - - return Math.round( clamp( _color.r * 255, 0, 255 ) ) * 65536 + Math.round( clamp( _color.g * 255, 0, 255 ) ) * 256 + Math.round( clamp( _color.b * 255, 0, 255 ) ); - - } - - getHexString( colorSpace = SRGBColorSpace ) { - - return ( '000000' + this.getHex( colorSpace ).toString( 16 ) ).slice( - 6 ); - - } - - getHSL( target, colorSpace = ColorManagement.workingColorSpace ) { - - // h,s,l ranges are in 0.0 - 1.0 - - ColorManagement.fromWorkingColorSpace( _color.copy( this ), colorSpace ); - - const r = _color.r, g = _color.g, b = _color.b; - - const max = Math.max( r, g, b ); - const min = Math.min( r, g, b ); - - let hue, saturation; - const lightness = ( min + max ) / 2.0; - - if ( min === max ) { - - hue = 0; - saturation = 0; - - } else { - - const delta = max - min; - - saturation = lightness <= 0.5 ? delta / ( max + min ) : delta / ( 2 - max - min ); - - switch ( max ) { - - case r: hue = ( g - b ) / delta + ( g < b ? 6 : 0 ); break; - case g: hue = ( b - r ) / delta + 2; break; - case b: hue = ( r - g ) / delta + 4; break; - - } - - hue /= 6; - - } - - target.h = hue; - target.s = saturation; - target.l = lightness; - - return target; - - } - - getRGB( target, colorSpace = ColorManagement.workingColorSpace ) { - - ColorManagement.fromWorkingColorSpace( _color.copy( this ), colorSpace ); - - target.r = _color.r; - target.g = _color.g; - target.b = _color.b; - - return target; - - } - - getStyle( colorSpace = SRGBColorSpace ) { - - ColorManagement.fromWorkingColorSpace( _color.copy( this ), colorSpace ); - - const r = _color.r, g = _color.g, b = _color.b; - - if ( colorSpace !== SRGBColorSpace ) { - - // Requires CSS Color Module Level 4 (https://www.w3.org/TR/css-color-4/). - return `color(${ colorSpace } ${ r.toFixed( 3 ) } ${ g.toFixed( 3 ) } ${ b.toFixed( 3 ) })`; - - } - - return `rgb(${ Math.round( r * 255 ) },${ Math.round( g * 255 ) },${ Math.round( b * 255 ) })`; - - } - - offsetHSL( h, s, l ) { - - this.getHSL( _hslA ); - - return this.setHSL( _hslA.h + h, _hslA.s + s, _hslA.l + l ); - - } - - add( color ) { - - this.r += color.r; - this.g += color.g; - this.b += color.b; - - return this; - - } - - addColors( color1, color2 ) { - - this.r = color1.r + color2.r; - this.g = color1.g + color2.g; - this.b = color1.b + color2.b; - - return this; - - } - - addScalar( s ) { - - this.r += s; - this.g += s; - this.b += s; - - return this; - - } - - sub( color ) { - - this.r = Math.max( 0, this.r - color.r ); - this.g = Math.max( 0, this.g - color.g ); - this.b = Math.max( 0, this.b - color.b ); - - return this; - - } - - multiply( color ) { - - this.r *= color.r; - this.g *= color.g; - this.b *= color.b; - - return this; - - } - - multiplyScalar( s ) { - - this.r *= s; - this.g *= s; - this.b *= s; - - return this; - - } - - lerp( color, alpha ) { - - this.r += ( color.r - this.r ) * alpha; - this.g += ( color.g - this.g ) * alpha; - this.b += ( color.b - this.b ) * alpha; - - return this; - - } - - lerpColors( color1, color2, alpha ) { - - this.r = color1.r + ( color2.r - color1.r ) * alpha; - this.g = color1.g + ( color2.g - color1.g ) * alpha; - this.b = color1.b + ( color2.b - color1.b ) * alpha; - - return this; - - } - - lerpHSL( color, alpha ) { - - this.getHSL( _hslA ); - color.getHSL( _hslB ); - - const h = lerp( _hslA.h, _hslB.h, alpha ); - const s = lerp( _hslA.s, _hslB.s, alpha ); - const l = lerp( _hslA.l, _hslB.l, alpha ); - - this.setHSL( h, s, l ); - - return this; - - } - - setFromVector3( v ) { - - this.r = v.x; - this.g = v.y; - this.b = v.z; - - return this; - - } - - applyMatrix3( m ) { - - const r = this.r, g = this.g, b = this.b; - const e = m.elements; - - this.r = e[ 0 ] * r + e[ 3 ] * g + e[ 6 ] * b; - this.g = e[ 1 ] * r + e[ 4 ] * g + e[ 7 ] * b; - this.b = e[ 2 ] * r + e[ 5 ] * g + e[ 8 ] * b; - - return this; - - } - - equals( c ) { - - return ( c.r === this.r ) && ( c.g === this.g ) && ( c.b === this.b ); - - } - - fromArray( array, offset = 0 ) { - - this.r = array[ offset ]; - this.g = array[ offset + 1 ]; - this.b = array[ offset + 2 ]; - - return this; - - } - - toArray( array = [], offset = 0 ) { - - array[ offset ] = this.r; - array[ offset + 1 ] = this.g; - array[ offset + 2 ] = this.b; - - return array; - - } - - fromBufferAttribute( attribute, index ) { - - this.r = attribute.getX( index ); - this.g = attribute.getY( index ); - this.b = attribute.getZ( index ); - - return this; - - } - - toJSON() { - - return this.getHex(); - - } - - *[ Symbol.iterator ]() { - - yield this.r; - yield this.g; - yield this.b; - - } - -} - -const _color = /*@__PURE__*/ new Color(); - -Color.NAMES = _colorKeywords; - -let _materialId = 0; - -class Material extends EventDispatcher { - - constructor() { - - super(); - - this.isMaterial = true; - - Object.defineProperty( this, 'id', { value: _materialId ++ } ); - - this.uuid = generateUUID(); - - this.name = ''; - this.type = 'Material'; - - this.blending = NormalBlending; - this.side = FrontSide; - this.vertexColors = false; - - this.opacity = 1; - this.transparent = false; - this.alphaHash = false; - - this.blendSrc = SrcAlphaFactor; - this.blendDst = OneMinusSrcAlphaFactor; - this.blendEquation = AddEquation; - this.blendSrcAlpha = null; - this.blendDstAlpha = null; - this.blendEquationAlpha = null; - this.blendColor = new Color( 0, 0, 0 ); - this.blendAlpha = 0; - - this.depthFunc = LessEqualDepth; - this.depthTest = true; - this.depthWrite = true; - - this.stencilWriteMask = 0xff; - this.stencilFunc = AlwaysStencilFunc; - this.stencilRef = 0; - this.stencilFuncMask = 0xff; - this.stencilFail = KeepStencilOp; - this.stencilZFail = KeepStencilOp; - this.stencilZPass = KeepStencilOp; - this.stencilWrite = false; - - this.clippingPlanes = null; - this.clipIntersection = false; - this.clipShadows = false; - - this.shadowSide = null; - - this.colorWrite = true; - - this.precision = null; // override the renderer's default precision for this material - - this.polygonOffset = false; - this.polygonOffsetFactor = 0; - this.polygonOffsetUnits = 0; - - this.dithering = false; - - this.alphaToCoverage = false; - this.premultipliedAlpha = false; - this.forceSinglePass = false; - - this.visible = true; - - this.toneMapped = true; - - this.userData = {}; - - this.version = 0; - - this._alphaTest = 0; - - } - - get alphaTest() { - - return this._alphaTest; - - } - - set alphaTest( value ) { - - if ( this._alphaTest > 0 !== value > 0 ) { - - this.version ++; - - } - - this._alphaTest = value; - - } - - onBuild( /* shaderobject, renderer */ ) {} - - onBeforeRender( /* renderer, scene, camera, geometry, object, group */ ) {} - - onBeforeCompile( /* shaderobject, renderer */ ) {} - - customProgramCacheKey() { - - return this.onBeforeCompile.toString(); - - } - - setValues( values ) { - - if ( values === undefined ) return; - - for ( const key in values ) { - - const newValue = values[ key ]; - - if ( newValue === undefined ) { - - console.warn( `THREE.Material: parameter '${ key }' has value of undefined.` ); - continue; - - } - - const currentValue = this[ key ]; - - if ( currentValue === undefined ) { - - console.warn( `THREE.Material: '${ key }' is not a property of THREE.${ this.type }.` ); - continue; - - } - - if ( currentValue && currentValue.isColor ) { - - currentValue.set( newValue ); - - } else if ( ( currentValue && currentValue.isVector3 ) && ( newValue && newValue.isVector3 ) ) { - - currentValue.copy( newValue ); - - } else { - - this[ key ] = newValue; - - } - - } - - } - - toJSON( meta ) { - - const isRootObject = ( meta === undefined || typeof meta === 'string' ); - - if ( isRootObject ) { - - meta = { - textures: {}, - images: {} - }; - - } - - const data = { - metadata: { - version: 4.6, - type: 'Material', - generator: 'Material.toJSON' - } - }; - - // standard Material serialization - data.uuid = this.uuid; - data.type = this.type; - - if ( this.name !== '' ) data.name = this.name; - - if ( this.color && this.color.isColor ) data.color = this.color.getHex(); - - if ( this.roughness !== undefined ) data.roughness = this.roughness; - if ( this.metalness !== undefined ) data.metalness = this.metalness; - - if ( this.sheen !== undefined ) data.sheen = this.sheen; - if ( this.sheenColor && this.sheenColor.isColor ) data.sheenColor = this.sheenColor.getHex(); - if ( this.sheenRoughness !== undefined ) data.sheenRoughness = this.sheenRoughness; - if ( this.emissive && this.emissive.isColor ) data.emissive = this.emissive.getHex(); - if ( this.emissiveIntensity && this.emissiveIntensity !== 1 ) data.emissiveIntensity = this.emissiveIntensity; - - if ( this.specular && this.specular.isColor ) data.specular = this.specular.getHex(); - if ( this.specularIntensity !== undefined ) data.specularIntensity = this.specularIntensity; - if ( this.specularColor && this.specularColor.isColor ) data.specularColor = this.specularColor.getHex(); - if ( this.shininess !== undefined ) data.shininess = this.shininess; - if ( this.clearcoat !== undefined ) data.clearcoat = this.clearcoat; - if ( this.clearcoatRoughness !== undefined ) data.clearcoatRoughness = this.clearcoatRoughness; - - if ( this.clearcoatMap && this.clearcoatMap.isTexture ) { - - data.clearcoatMap = this.clearcoatMap.toJSON( meta ).uuid; - - } - - if ( this.clearcoatRoughnessMap && this.clearcoatRoughnessMap.isTexture ) { - - data.clearcoatRoughnessMap = this.clearcoatRoughnessMap.toJSON( meta ).uuid; - - } - - if ( this.clearcoatNormalMap && this.clearcoatNormalMap.isTexture ) { - - data.clearcoatNormalMap = this.clearcoatNormalMap.toJSON( meta ).uuid; - data.clearcoatNormalScale = this.clearcoatNormalScale.toArray(); - - } - - if ( this.iridescence !== undefined ) data.iridescence = this.iridescence; - if ( this.iridescenceIOR !== undefined ) data.iridescenceIOR = this.iridescenceIOR; - if ( this.iridescenceThicknessRange !== undefined ) data.iridescenceThicknessRange = this.iridescenceThicknessRange; - - if ( this.iridescenceMap && this.iridescenceMap.isTexture ) { - - data.iridescenceMap = this.iridescenceMap.toJSON( meta ).uuid; - - } - - if ( this.iridescenceThicknessMap && this.iridescenceThicknessMap.isTexture ) { - - data.iridescenceThicknessMap = this.iridescenceThicknessMap.toJSON( meta ).uuid; - - } - - if ( this.anisotropy !== undefined ) data.anisotropy = this.anisotropy; - if ( this.anisotropyRotation !== undefined ) data.anisotropyRotation = this.anisotropyRotation; - - if ( this.anisotropyMap && this.anisotropyMap.isTexture ) { - - data.anisotropyMap = this.anisotropyMap.toJSON( meta ).uuid; - - } - - if ( this.map && this.map.isTexture ) data.map = this.map.toJSON( meta ).uuid; - if ( this.matcap && this.matcap.isTexture ) data.matcap = this.matcap.toJSON( meta ).uuid; - if ( this.alphaMap && this.alphaMap.isTexture ) data.alphaMap = this.alphaMap.toJSON( meta ).uuid; - - if ( this.lightMap && this.lightMap.isTexture ) { - - data.lightMap = this.lightMap.toJSON( meta ).uuid; - data.lightMapIntensity = this.lightMapIntensity; - - } - - if ( this.aoMap && this.aoMap.isTexture ) { - - data.aoMap = this.aoMap.toJSON( meta ).uuid; - data.aoMapIntensity = this.aoMapIntensity; - - } - - if ( this.bumpMap && this.bumpMap.isTexture ) { - - data.bumpMap = this.bumpMap.toJSON( meta ).uuid; - data.bumpScale = this.bumpScale; - - } - - if ( this.normalMap && this.normalMap.isTexture ) { - - data.normalMap = this.normalMap.toJSON( meta ).uuid; - data.normalMapType = this.normalMapType; - data.normalScale = this.normalScale.toArray(); - - } - - if ( this.displacementMap && this.displacementMap.isTexture ) { - - data.displacementMap = this.displacementMap.toJSON( meta ).uuid; - data.displacementScale = this.displacementScale; - data.displacementBias = this.displacementBias; - - } - - if ( this.roughnessMap && this.roughnessMap.isTexture ) data.roughnessMap = this.roughnessMap.toJSON( meta ).uuid; - if ( this.metalnessMap && this.metalnessMap.isTexture ) data.metalnessMap = this.metalnessMap.toJSON( meta ).uuid; - - if ( this.emissiveMap && this.emissiveMap.isTexture ) data.emissiveMap = this.emissiveMap.toJSON( meta ).uuid; - if ( this.specularMap && this.specularMap.isTexture ) data.specularMap = this.specularMap.toJSON( meta ).uuid; - if ( this.specularIntensityMap && this.specularIntensityMap.isTexture ) data.specularIntensityMap = this.specularIntensityMap.toJSON( meta ).uuid; - if ( this.specularColorMap && this.specularColorMap.isTexture ) data.specularColorMap = this.specularColorMap.toJSON( meta ).uuid; - - if ( this.envMap && this.envMap.isTexture ) { - - data.envMap = this.envMap.toJSON( meta ).uuid; - - if ( this.combine !== undefined ) data.combine = this.combine; - - } - - if ( this.envMapIntensity !== undefined ) data.envMapIntensity = this.envMapIntensity; - if ( this.reflectivity !== undefined ) data.reflectivity = this.reflectivity; - if ( this.refractionRatio !== undefined ) data.refractionRatio = this.refractionRatio; - - if ( this.gradientMap && this.gradientMap.isTexture ) { - - data.gradientMap = this.gradientMap.toJSON( meta ).uuid; - - } - - if ( this.transmission !== undefined ) data.transmission = this.transmission; - if ( this.transmissionMap && this.transmissionMap.isTexture ) data.transmissionMap = this.transmissionMap.toJSON( meta ).uuid; - if ( this.thickness !== undefined ) data.thickness = this.thickness; - if ( this.thicknessMap && this.thicknessMap.isTexture ) data.thicknessMap = this.thicknessMap.toJSON( meta ).uuid; - if ( this.attenuationDistance !== undefined && this.attenuationDistance !== Infinity ) data.attenuationDistance = this.attenuationDistance; - if ( this.attenuationColor !== undefined ) data.attenuationColor = this.attenuationColor.getHex(); - - if ( this.size !== undefined ) data.size = this.size; - if ( this.shadowSide !== null ) data.shadowSide = this.shadowSide; - if ( this.sizeAttenuation !== undefined ) data.sizeAttenuation = this.sizeAttenuation; - - if ( this.blending !== NormalBlending ) data.blending = this.blending; - if ( this.side !== FrontSide ) data.side = this.side; - if ( this.vertexColors === true ) data.vertexColors = true; - - if ( this.opacity < 1 ) data.opacity = this.opacity; - if ( this.transparent === true ) data.transparent = true; - - if ( this.blendSrc !== SrcAlphaFactor ) data.blendSrc = this.blendSrc; - if ( this.blendDst !== OneMinusSrcAlphaFactor ) data.blendDst = this.blendDst; - if ( this.blendEquation !== AddEquation ) data.blendEquation = this.blendEquation; - if ( this.blendSrcAlpha !== null ) data.blendSrcAlpha = this.blendSrcAlpha; - if ( this.blendDstAlpha !== null ) data.blendDstAlpha = this.blendDstAlpha; - if ( this.blendEquationAlpha !== null ) data.blendEquationAlpha = this.blendEquationAlpha; - if ( this.blendColor && this.blendColor.isColor ) data.blendColor = this.blendColor.getHex(); - if ( this.blendAlpha !== 0 ) data.blendAlpha = this.blendAlpha; - - if ( this.depthFunc !== LessEqualDepth ) data.depthFunc = this.depthFunc; - if ( this.depthTest === false ) data.depthTest = this.depthTest; - if ( this.depthWrite === false ) data.depthWrite = this.depthWrite; - if ( this.colorWrite === false ) data.colorWrite = this.colorWrite; - - if ( this.stencilWriteMask !== 0xff ) data.stencilWriteMask = this.stencilWriteMask; - if ( this.stencilFunc !== AlwaysStencilFunc ) data.stencilFunc = this.stencilFunc; - if ( this.stencilRef !== 0 ) data.stencilRef = this.stencilRef; - if ( this.stencilFuncMask !== 0xff ) data.stencilFuncMask = this.stencilFuncMask; - if ( this.stencilFail !== KeepStencilOp ) data.stencilFail = this.stencilFail; - if ( this.stencilZFail !== KeepStencilOp ) data.stencilZFail = this.stencilZFail; - if ( this.stencilZPass !== KeepStencilOp ) data.stencilZPass = this.stencilZPass; - if ( this.stencilWrite === true ) data.stencilWrite = this.stencilWrite; - - // rotation (SpriteMaterial) - if ( this.rotation !== undefined && this.rotation !== 0 ) data.rotation = this.rotation; - - if ( this.polygonOffset === true ) data.polygonOffset = true; - if ( this.polygonOffsetFactor !== 0 ) data.polygonOffsetFactor = this.polygonOffsetFactor; - if ( this.polygonOffsetUnits !== 0 ) data.polygonOffsetUnits = this.polygonOffsetUnits; - - if ( this.linewidth !== undefined && this.linewidth !== 1 ) data.linewidth = this.linewidth; - if ( this.dashSize !== undefined ) data.dashSize = this.dashSize; - if ( this.gapSize !== undefined ) data.gapSize = this.gapSize; - if ( this.scale !== undefined ) data.scale = this.scale; - - if ( this.dithering === true ) data.dithering = true; - - if ( this.alphaTest > 0 ) data.alphaTest = this.alphaTest; - if ( this.alphaHash === true ) data.alphaHash = true; - if ( this.alphaToCoverage === true ) data.alphaToCoverage = true; - if ( this.premultipliedAlpha === true ) data.premultipliedAlpha = true; - if ( this.forceSinglePass === true ) data.forceSinglePass = true; - - if ( this.wireframe === true ) data.wireframe = true; - if ( this.wireframeLinewidth > 1 ) data.wireframeLinewidth = this.wireframeLinewidth; - if ( this.wireframeLinecap !== 'round' ) data.wireframeLinecap = this.wireframeLinecap; - if ( this.wireframeLinejoin !== 'round' ) data.wireframeLinejoin = this.wireframeLinejoin; - - if ( this.flatShading === true ) data.flatShading = true; - - if ( this.visible === false ) data.visible = false; - - if ( this.toneMapped === false ) data.toneMapped = false; - - if ( this.fog === false ) data.fog = false; - - if ( Object.keys( this.userData ).length > 0 ) data.userData = this.userData; - - // TODO: Copied from Object3D.toJSON - - function extractFromCache( cache ) { - - const values = []; - - for ( const key in cache ) { - - const data = cache[ key ]; - delete data.metadata; - values.push( data ); - - } - - return values; - - } - - if ( isRootObject ) { - - const textures = extractFromCache( meta.textures ); - const images = extractFromCache( meta.images ); - - if ( textures.length > 0 ) data.textures = textures; - if ( images.length > 0 ) data.images = images; - - } - - return data; - - } - - clone() { - - return new this.constructor().copy( this ); - - } - - copy( source ) { - - this.name = source.name; - - this.blending = source.blending; - this.side = source.side; - this.vertexColors = source.vertexColors; - - this.opacity = source.opacity; - this.transparent = source.transparent; - - this.blendSrc = source.blendSrc; - this.blendDst = source.blendDst; - this.blendEquation = source.blendEquation; - this.blendSrcAlpha = source.blendSrcAlpha; - this.blendDstAlpha = source.blendDstAlpha; - this.blendEquationAlpha = source.blendEquationAlpha; - this.blendColor.copy( source.blendColor ); - this.blendAlpha = source.blendAlpha; - - this.depthFunc = source.depthFunc; - this.depthTest = source.depthTest; - this.depthWrite = source.depthWrite; - - this.stencilWriteMask = source.stencilWriteMask; - this.stencilFunc = source.stencilFunc; - this.stencilRef = source.stencilRef; - this.stencilFuncMask = source.stencilFuncMask; - this.stencilFail = source.stencilFail; - this.stencilZFail = source.stencilZFail; - this.stencilZPass = source.stencilZPass; - this.stencilWrite = source.stencilWrite; - - const srcPlanes = source.clippingPlanes; - let dstPlanes = null; - - if ( srcPlanes !== null ) { - - const n = srcPlanes.length; - dstPlanes = new Array( n ); - - for ( let i = 0; i !== n; ++ i ) { - - dstPlanes[ i ] = srcPlanes[ i ].clone(); - - } - - } - - this.clippingPlanes = dstPlanes; - this.clipIntersection = source.clipIntersection; - this.clipShadows = source.clipShadows; - - this.shadowSide = source.shadowSide; - - this.colorWrite = source.colorWrite; - - this.precision = source.precision; - - this.polygonOffset = source.polygonOffset; - this.polygonOffsetFactor = source.polygonOffsetFactor; - this.polygonOffsetUnits = source.polygonOffsetUnits; - - this.dithering = source.dithering; - - this.alphaTest = source.alphaTest; - this.alphaHash = source.alphaHash; - this.alphaToCoverage = source.alphaToCoverage; - this.premultipliedAlpha = source.premultipliedAlpha; - this.forceSinglePass = source.forceSinglePass; - - this.visible = source.visible; - - this.toneMapped = source.toneMapped; - - this.userData = JSON.parse( JSON.stringify( source.userData ) ); - - return this; - - } - - dispose() { - - this.dispatchEvent( { type: 'dispose' } ); - - } - - set needsUpdate( value ) { - - if ( value === true ) this.version ++; - - } - -} - -class MeshBasicMaterial extends Material { - - constructor( parameters ) { - - super(); - - this.isMeshBasicMaterial = true; - - this.type = 'MeshBasicMaterial'; - - this.color = new Color( 0xffffff ); // emissive - - this.map = null; - - this.lightMap = null; - this.lightMapIntensity = 1.0; - - this.aoMap = null; - this.aoMapIntensity = 1.0; - - this.specularMap = null; - - this.alphaMap = null; - - this.envMap = null; - this.combine = MultiplyOperation; - this.reflectivity = 1; - this.refractionRatio = 0.98; - - this.wireframe = false; - this.wireframeLinewidth = 1; - this.wireframeLinecap = 'round'; - this.wireframeLinejoin = 'round'; - - this.fog = true; - - this.setValues( parameters ); - - } - - copy( source ) { - - super.copy( source ); - - this.color.copy( source.color ); - - this.map = source.map; - - this.lightMap = source.lightMap; - this.lightMapIntensity = source.lightMapIntensity; - - this.aoMap = source.aoMap; - this.aoMapIntensity = source.aoMapIntensity; - - this.specularMap = source.specularMap; - - this.alphaMap = source.alphaMap; - - this.envMap = source.envMap; - this.combine = source.combine; - this.reflectivity = source.reflectivity; - this.refractionRatio = source.refractionRatio; - - this.wireframe = source.wireframe; - this.wireframeLinewidth = source.wireframeLinewidth; - this.wireframeLinecap = source.wireframeLinecap; - this.wireframeLinejoin = source.wireframeLinejoin; - - this.fog = source.fog; - - return this; - - } - -} - -// Fast Half Float Conversions, http://www.fox-toolkit.org/ftp/fasthalffloatconversion.pdf - -const _tables = /*@__PURE__*/ _generateTables(); - -function _generateTables() { - - // float32 to float16 helpers - - const buffer = new ArrayBuffer( 4 ); - const floatView = new Float32Array( buffer ); - const uint32View = new Uint32Array( buffer ); - - const baseTable = new Uint32Array( 512 ); - const shiftTable = new Uint32Array( 512 ); - - for ( let i = 0; i < 256; ++ i ) { - - const e = i - 127; - - // very small number (0, -0) - - if ( e < - 27 ) { - - baseTable[ i ] = 0x0000; - baseTable[ i | 0x100 ] = 0x8000; - shiftTable[ i ] = 24; - shiftTable[ i | 0x100 ] = 24; - - // small number (denorm) - - } else if ( e < - 14 ) { - - baseTable[ i ] = 0x0400 >> ( - e - 14 ); - baseTable[ i | 0x100 ] = ( 0x0400 >> ( - e - 14 ) ) | 0x8000; - shiftTable[ i ] = - e - 1; - shiftTable[ i | 0x100 ] = - e - 1; - - // normal number - - } else if ( e <= 15 ) { - - baseTable[ i ] = ( e + 15 ) << 10; - baseTable[ i | 0x100 ] = ( ( e + 15 ) << 10 ) | 0x8000; - shiftTable[ i ] = 13; - shiftTable[ i | 0x100 ] = 13; - - // large number (Infinity, -Infinity) - - } else if ( e < 128 ) { - - baseTable[ i ] = 0x7c00; - baseTable[ i | 0x100 ] = 0xfc00; - shiftTable[ i ] = 24; - shiftTable[ i | 0x100 ] = 24; - - // stay (NaN, Infinity, -Infinity) - - } else { - - baseTable[ i ] = 0x7c00; - baseTable[ i | 0x100 ] = 0xfc00; - shiftTable[ i ] = 13; - shiftTable[ i | 0x100 ] = 13; - - } - - } - - // float16 to float32 helpers - - const mantissaTable = new Uint32Array( 2048 ); - const exponentTable = new Uint32Array( 64 ); - const offsetTable = new Uint32Array( 64 ); - - for ( let i = 1; i < 1024; ++ i ) { - - let m = i << 13; // zero pad mantissa bits - let e = 0; // zero exponent - - // normalized - while ( ( m & 0x00800000 ) === 0 ) { - - m <<= 1; - e -= 0x00800000; // decrement exponent - - } - - m &= ~ 0x00800000; // clear leading 1 bit - e += 0x38800000; // adjust bias - - mantissaTable[ i ] = m | e; - - } - - for ( let i = 1024; i < 2048; ++ i ) { - - mantissaTable[ i ] = 0x38000000 + ( ( i - 1024 ) << 13 ); - - } - - for ( let i = 1; i < 31; ++ i ) { - - exponentTable[ i ] = i << 23; - - } - - exponentTable[ 31 ] = 0x47800000; - exponentTable[ 32 ] = 0x80000000; - - for ( let i = 33; i < 63; ++ i ) { - - exponentTable[ i ] = 0x80000000 + ( ( i - 32 ) << 23 ); - - } - - exponentTable[ 63 ] = 0xc7800000; - - for ( let i = 1; i < 64; ++ i ) { - - if ( i !== 32 ) { - - offsetTable[ i ] = 1024; - - } - - } - - return { - floatView: floatView, - uint32View: uint32View, - baseTable: baseTable, - shiftTable: shiftTable, - mantissaTable: mantissaTable, - exponentTable: exponentTable, - offsetTable: offsetTable - }; - -} - -// float32 to float16 - -function toHalfFloat( val ) { - - if ( Math.abs( val ) > 65504 ) console.warn( 'THREE.DataUtils.toHalfFloat(): Value out of range.' ); - - val = clamp( val, - 65504, 65504 ); - - _tables.floatView[ 0 ] = val; - const f = _tables.uint32View[ 0 ]; - const e = ( f >> 23 ) & 0x1ff; - return _tables.baseTable[ e ] + ( ( f & 0x007fffff ) >> _tables.shiftTable[ e ] ); - -} - -// float16 to float32 - -function fromHalfFloat( val ) { - - const m = val >> 10; - _tables.uint32View[ 0 ] = _tables.mantissaTable[ _tables.offsetTable[ m ] + ( val & 0x3ff ) ] + _tables.exponentTable[ m ]; - return _tables.floatView[ 0 ]; - -} - -const DataUtils = { - toHalfFloat: toHalfFloat, - fromHalfFloat: fromHalfFloat, -}; - -const _vector$9 = /*@__PURE__*/ new Vector3(); -const _vector2$1 = /*@__PURE__*/ new Vector2(); - -class BufferAttribute { - - constructor( array, itemSize, normalized = false ) { - - if ( Array.isArray( array ) ) { - - throw new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' ); - - } - - this.isBufferAttribute = true; - - this.name = ''; - - this.array = array; - this.itemSize = itemSize; - this.count = array !== undefined ? array.length / itemSize : 0; - this.normalized = normalized; - - this.usage = StaticDrawUsage; - this._updateRange = { offset: 0, count: - 1 }; - this.updateRanges = []; - this.gpuType = FloatType; - - this.version = 0; - - } - - onUploadCallback() {} - - set needsUpdate( value ) { - - if ( value === true ) this.version ++; - - } - - get updateRange() { - - warnOnce( 'THREE.BufferAttribute: updateRange() is deprecated and will be removed in r169. Use addUpdateRange() instead.' ); // @deprecated, r159 - return this._updateRange; - - } - - setUsage( value ) { - - this.usage = value; - - return this; - - } - - addUpdateRange( start, count ) { - - this.updateRanges.push( { start, count } ); - - } - - clearUpdateRanges() { - - this.updateRanges.length = 0; - - } - - copy( source ) { - - this.name = source.name; - this.array = new source.array.constructor( source.array ); - this.itemSize = source.itemSize; - this.count = source.count; - this.normalized = source.normalized; - - this.usage = source.usage; - this.gpuType = source.gpuType; - - return this; - - } - - copyAt( index1, attribute, index2 ) { - - index1 *= this.itemSize; - index2 *= attribute.itemSize; - - for ( let i = 0, l = this.itemSize; i < l; i ++ ) { - - this.array[ index1 + i ] = attribute.array[ index2 + i ]; - - } - - return this; - - } - - copyArray( array ) { - - this.array.set( array ); - - return this; - - } - - applyMatrix3( m ) { - - if ( this.itemSize === 2 ) { - - for ( let i = 0, l = this.count; i < l; i ++ ) { - - _vector2$1.fromBufferAttribute( this, i ); - _vector2$1.applyMatrix3( m ); - - this.setXY( i, _vector2$1.x, _vector2$1.y ); - - } - - } else if ( this.itemSize === 3 ) { - - for ( let i = 0, l = this.count; i < l; i ++ ) { - - _vector$9.fromBufferAttribute( this, i ); - _vector$9.applyMatrix3( m ); - - this.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z ); - - } - - } - - return this; - - } - - applyMatrix4( m ) { - - for ( let i = 0, l = this.count; i < l; i ++ ) { - - _vector$9.fromBufferAttribute( this, i ); - - _vector$9.applyMatrix4( m ); - - this.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z ); - - } - - return this; - - } - - applyNormalMatrix( m ) { - - for ( let i = 0, l = this.count; i < l; i ++ ) { - - _vector$9.fromBufferAttribute( this, i ); - - _vector$9.applyNormalMatrix( m ); - - this.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z ); - - } - - return this; - - } - - transformDirection( m ) { - - for ( let i = 0, l = this.count; i < l; i ++ ) { - - _vector$9.fromBufferAttribute( this, i ); - - _vector$9.transformDirection( m ); - - this.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z ); - - } - - return this; - - } - - set( value, offset = 0 ) { - - // Matching BufferAttribute constructor, do not normalize the array. - this.array.set( value, offset ); - - return this; - - } - - getComponent( index, component ) { - - let value = this.array[ index * this.itemSize + component ]; - - if ( this.normalized ) value = denormalize( value, this.array ); - - return value; - - } - - setComponent( index, component, value ) { - - if ( this.normalized ) value = normalize( value, this.array ); - - this.array[ index * this.itemSize + component ] = value; - - return this; - - } - - getX( index ) { - - let x = this.array[ index * this.itemSize ]; - - if ( this.normalized ) x = denormalize( x, this.array ); - - return x; - - } - - setX( index, x ) { - - if ( this.normalized ) x = normalize( x, this.array ); - - this.array[ index * this.itemSize ] = x; - - return this; - - } - - getY( index ) { - - let y = this.array[ index * this.itemSize + 1 ]; - - if ( this.normalized ) y = denormalize( y, this.array ); - - return y; - - } - - setY( index, y ) { - - if ( this.normalized ) y = normalize( y, this.array ); - - this.array[ index * this.itemSize + 1 ] = y; - - return this; - - } - - getZ( index ) { - - let z = this.array[ index * this.itemSize + 2 ]; - - if ( this.normalized ) z = denormalize( z, this.array ); - - return z; - - } - - setZ( index, z ) { - - if ( this.normalized ) z = normalize( z, this.array ); - - this.array[ index * this.itemSize + 2 ] = z; - - return this; - - } - - getW( index ) { - - let w = this.array[ index * this.itemSize + 3 ]; - - if ( this.normalized ) w = denormalize( w, this.array ); - - return w; - - } - - setW( index, w ) { - - if ( this.normalized ) w = normalize( w, this.array ); - - this.array[ index * this.itemSize + 3 ] = w; - - return this; - - } - - setXY( index, x, y ) { - - index *= this.itemSize; - - if ( this.normalized ) { - - x = normalize( x, this.array ); - y = normalize( y, this.array ); - - } - - this.array[ index + 0 ] = x; - this.array[ index + 1 ] = y; - - return this; - - } - - setXYZ( index, x, y, z ) { - - index *= this.itemSize; - - if ( this.normalized ) { - - x = normalize( x, this.array ); - y = normalize( y, this.array ); - z = normalize( z, this.array ); - - } - - this.array[ index + 0 ] = x; - this.array[ index + 1 ] = y; - this.array[ index + 2 ] = z; - - return this; - - } - - setXYZW( index, x, y, z, w ) { - - index *= this.itemSize; - - if ( this.normalized ) { - - x = normalize( x, this.array ); - y = normalize( y, this.array ); - z = normalize( z, this.array ); - w = normalize( w, this.array ); - - } - - this.array[ index + 0 ] = x; - this.array[ index + 1 ] = y; - this.array[ index + 2 ] = z; - this.array[ index + 3 ] = w; - - return this; - - } - - onUpload( callback ) { - - this.onUploadCallback = callback; - - return this; - - } - - clone() { - - return new this.constructor( this.array, this.itemSize ).copy( this ); - - } - - toJSON() { - - const data = { - itemSize: this.itemSize, - type: this.array.constructor.name, - array: Array.from( this.array ), - normalized: this.normalized - }; - - if ( this.name !== '' ) data.name = this.name; - if ( this.usage !== StaticDrawUsage ) data.usage = this.usage; - - return data; - - } - -} - -// - -class Int8BufferAttribute extends BufferAttribute { - - constructor( array, itemSize, normalized ) { - - super( new Int8Array( array ), itemSize, normalized ); - - } - -} - -class Uint8BufferAttribute extends BufferAttribute { - - constructor( array, itemSize, normalized ) { - - super( new Uint8Array( array ), itemSize, normalized ); - - } - -} - -class Uint8ClampedBufferAttribute extends BufferAttribute { - - constructor( array, itemSize, normalized ) { - - super( new Uint8ClampedArray( array ), itemSize, normalized ); - - } - -} - -class Int16BufferAttribute extends BufferAttribute { - - constructor( array, itemSize, normalized ) { - - super( new Int16Array( array ), itemSize, normalized ); - - } - -} - -class Uint16BufferAttribute extends BufferAttribute { - - constructor( array, itemSize, normalized ) { - - super( new Uint16Array( array ), itemSize, normalized ); - - } - -} - -class Int32BufferAttribute extends BufferAttribute { - - constructor( array, itemSize, normalized ) { - - super( new Int32Array( array ), itemSize, normalized ); - - } - -} - -class Uint32BufferAttribute extends BufferAttribute { - - constructor( array, itemSize, normalized ) { - - super( new Uint32Array( array ), itemSize, normalized ); - - } - -} - -class Float16BufferAttribute extends BufferAttribute { - - constructor( array, itemSize, normalized ) { - - super( new Uint16Array( array ), itemSize, normalized ); - - this.isFloat16BufferAttribute = true; - - } - - getX( index ) { - - let x = fromHalfFloat( this.array[ index * this.itemSize ] ); - - if ( this.normalized ) x = denormalize( x, this.array ); - - return x; - - } - - setX( index, x ) { - - if ( this.normalized ) x = normalize( x, this.array ); - - this.array[ index * this.itemSize ] = toHalfFloat( x ); - - return this; - - } - - getY( index ) { - - let y = fromHalfFloat( this.array[ index * this.itemSize + 1 ] ); - - if ( this.normalized ) y = denormalize( y, this.array ); - - return y; - - } - - setY( index, y ) { - - if ( this.normalized ) y = normalize( y, this.array ); - - this.array[ index * this.itemSize + 1 ] = toHalfFloat( y ); - - return this; - - } - - getZ( index ) { - - let z = fromHalfFloat( this.array[ index * this.itemSize + 2 ] ); - - if ( this.normalized ) z = denormalize( z, this.array ); - - return z; - - } - - setZ( index, z ) { - - if ( this.normalized ) z = normalize( z, this.array ); - - this.array[ index * this.itemSize + 2 ] = toHalfFloat( z ); - - return this; - - } - - getW( index ) { - - let w = fromHalfFloat( this.array[ index * this.itemSize + 3 ] ); - - if ( this.normalized ) w = denormalize( w, this.array ); - - return w; - - } - - setW( index, w ) { - - if ( this.normalized ) w = normalize( w, this.array ); - - this.array[ index * this.itemSize + 3 ] = toHalfFloat( w ); - - return this; - - } - - setXY( index, x, y ) { - - index *= this.itemSize; - - if ( this.normalized ) { - - x = normalize( x, this.array ); - y = normalize( y, this.array ); - - } - - this.array[ index + 0 ] = toHalfFloat( x ); - this.array[ index + 1 ] = toHalfFloat( y ); - - return this; - - } - - setXYZ( index, x, y, z ) { - - index *= this.itemSize; - - if ( this.normalized ) { - - x = normalize( x, this.array ); - y = normalize( y, this.array ); - z = normalize( z, this.array ); - - } - - this.array[ index + 0 ] = toHalfFloat( x ); - this.array[ index + 1 ] = toHalfFloat( y ); - this.array[ index + 2 ] = toHalfFloat( z ); - - return this; - - } - - setXYZW( index, x, y, z, w ) { - - index *= this.itemSize; - - if ( this.normalized ) { - - x = normalize( x, this.array ); - y = normalize( y, this.array ); - z = normalize( z, this.array ); - w = normalize( w, this.array ); - - } - - this.array[ index + 0 ] = toHalfFloat( x ); - this.array[ index + 1 ] = toHalfFloat( y ); - this.array[ index + 2 ] = toHalfFloat( z ); - this.array[ index + 3 ] = toHalfFloat( w ); - - return this; - - } - -} - - -class Float32BufferAttribute extends BufferAttribute { - - constructor( array, itemSize, normalized ) { - - super( new Float32Array( array ), itemSize, normalized ); - - } - -} - -class Float64BufferAttribute extends BufferAttribute { - - constructor( array, itemSize, normalized ) { - - super( new Float64Array( array ), itemSize, normalized ); - - } - -} - -let _id$2 = 0; - -const _m1 = /*@__PURE__*/ new Matrix4(); -const _obj = /*@__PURE__*/ new Object3D(); -const _offset = /*@__PURE__*/ new Vector3(); -const _box$2 = /*@__PURE__*/ new Box3(); -const _boxMorphTargets = /*@__PURE__*/ new Box3(); -const _vector$8 = /*@__PURE__*/ new Vector3(); - -class BufferGeometry extends EventDispatcher { - - constructor() { - - super(); - - this.isBufferGeometry = true; - - Object.defineProperty( this, 'id', { value: _id$2 ++ } ); - - this.uuid = generateUUID(); - - this.name = ''; - this.type = 'BufferGeometry'; - - this.index = null; - this.attributes = {}; - - this.morphAttributes = {}; - this.morphTargetsRelative = false; - - this.groups = []; - - this.boundingBox = null; - this.boundingSphere = null; - - this.drawRange = { start: 0, count: Infinity }; - - this.userData = {}; - - } - - getIndex() { - - return this.index; - - } - - setIndex( index ) { - - if ( Array.isArray( index ) ) { - - this.index = new ( arrayNeedsUint32( index ) ? Uint32BufferAttribute : Uint16BufferAttribute )( index, 1 ); - - } else { - - this.index = index; - - } - - return this; - - } - - getAttribute( name ) { - - return this.attributes[ name ]; - - } - - setAttribute( name, attribute ) { - - this.attributes[ name ] = attribute; - - return this; - - } - - deleteAttribute( name ) { - - delete this.attributes[ name ]; - - return this; - - } - - hasAttribute( name ) { - - return this.attributes[ name ] !== undefined; - - } - - addGroup( start, count, materialIndex = 0 ) { - - this.groups.push( { - - start: start, - count: count, - materialIndex: materialIndex - - } ); - - } - - clearGroups() { - - this.groups = []; - - } - - setDrawRange( start, count ) { - - this.drawRange.start = start; - this.drawRange.count = count; - - } - - applyMatrix4( matrix ) { - - const position = this.attributes.position; - - if ( position !== undefined ) { - - position.applyMatrix4( matrix ); - - position.needsUpdate = true; - - } - - const normal = this.attributes.normal; - - if ( normal !== undefined ) { - - const normalMatrix = new Matrix3().getNormalMatrix( matrix ); - - normal.applyNormalMatrix( normalMatrix ); - - normal.needsUpdate = true; - - } - - const tangent = this.attributes.tangent; - - if ( tangent !== undefined ) { - - tangent.transformDirection( matrix ); - - tangent.needsUpdate = true; - - } - - if ( this.boundingBox !== null ) { - - this.computeBoundingBox(); - - } - - if ( this.boundingSphere !== null ) { - - this.computeBoundingSphere(); - - } - - return this; - - } - - applyQuaternion( q ) { - - _m1.makeRotationFromQuaternion( q ); - - this.applyMatrix4( _m1 ); - - return this; - - } - - rotateX( angle ) { - - // rotate geometry around world x-axis - - _m1.makeRotationX( angle ); - - this.applyMatrix4( _m1 ); - - return this; - - } - - rotateY( angle ) { - - // rotate geometry around world y-axis - - _m1.makeRotationY( angle ); - - this.applyMatrix4( _m1 ); - - return this; - - } - - rotateZ( angle ) { - - // rotate geometry around world z-axis - - _m1.makeRotationZ( angle ); - - this.applyMatrix4( _m1 ); - - return this; - - } - - translate( x, y, z ) { - - // translate geometry - - _m1.makeTranslation( x, y, z ); - - this.applyMatrix4( _m1 ); - - return this; - - } - - scale( x, y, z ) { - - // scale geometry - - _m1.makeScale( x, y, z ); - - this.applyMatrix4( _m1 ); - - return this; - - } - - lookAt( vector ) { - - _obj.lookAt( vector ); - - _obj.updateMatrix(); - - this.applyMatrix4( _obj.matrix ); - - return this; - - } - - center() { - - this.computeBoundingBox(); - - this.boundingBox.getCenter( _offset ).negate(); - - this.translate( _offset.x, _offset.y, _offset.z ); - - return this; - - } - - setFromPoints( points ) { - - const position = []; - - for ( let i = 0, l = points.length; i < l; i ++ ) { - - const point = points[ i ]; - position.push( point.x, point.y, point.z || 0 ); - - } - - this.setAttribute( 'position', new Float32BufferAttribute( position, 3 ) ); - - return this; - - } - - computeBoundingBox() { - - if ( this.boundingBox === null ) { - - this.boundingBox = new Box3(); - - } - - const position = this.attributes.position; - const morphAttributesPosition = this.morphAttributes.position; - - if ( position && position.isGLBufferAttribute ) { - - console.error( 'THREE.BufferGeometry.computeBoundingBox(): GLBufferAttribute requires a manual bounding box. Alternatively set "mesh.frustumCulled" to "false".', this ); - - this.boundingBox.set( - new Vector3( - Infinity, - Infinity, - Infinity ), - new Vector3( + Infinity, + Infinity, + Infinity ) - ); - - return; - - } - - if ( position !== undefined ) { - - this.boundingBox.setFromBufferAttribute( position ); - - // process morph attributes if present - - if ( morphAttributesPosition ) { - - for ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) { - - const morphAttribute = morphAttributesPosition[ i ]; - _box$2.setFromBufferAttribute( morphAttribute ); - - if ( this.morphTargetsRelative ) { - - _vector$8.addVectors( this.boundingBox.min, _box$2.min ); - this.boundingBox.expandByPoint( _vector$8 ); - - _vector$8.addVectors( this.boundingBox.max, _box$2.max ); - this.boundingBox.expandByPoint( _vector$8 ); - - } else { - - this.boundingBox.expandByPoint( _box$2.min ); - this.boundingBox.expandByPoint( _box$2.max ); - - } - - } - - } - - } else { - - this.boundingBox.makeEmpty(); - - } - - if ( isNaN( this.boundingBox.min.x ) || isNaN( this.boundingBox.min.y ) || isNaN( this.boundingBox.min.z ) ) { - - console.error( 'THREE.BufferGeometry.computeBoundingBox(): Computed min/max have NaN values. The "position" attribute is likely to have NaN values.', this ); - - } - - } - - computeBoundingSphere() { - - if ( this.boundingSphere === null ) { - - this.boundingSphere = new Sphere(); - - } - - const position = this.attributes.position; - const morphAttributesPosition = this.morphAttributes.position; - - if ( position && position.isGLBufferAttribute ) { - - console.error( 'THREE.BufferGeometry.computeBoundingSphere(): GLBufferAttribute requires a manual bounding sphere. Alternatively set "mesh.frustumCulled" to "false".', this ); - - this.boundingSphere.set( new Vector3(), Infinity ); - - return; - - } - - if ( position ) { - - // first, find the center of the bounding sphere - - const center = this.boundingSphere.center; - - _box$2.setFromBufferAttribute( position ); - - // process morph attributes if present - - if ( morphAttributesPosition ) { - - for ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) { - - const morphAttribute = morphAttributesPosition[ i ]; - _boxMorphTargets.setFromBufferAttribute( morphAttribute ); - - if ( this.morphTargetsRelative ) { - - _vector$8.addVectors( _box$2.min, _boxMorphTargets.min ); - _box$2.expandByPoint( _vector$8 ); - - _vector$8.addVectors( _box$2.max, _boxMorphTargets.max ); - _box$2.expandByPoint( _vector$8 ); - - } else { - - _box$2.expandByPoint( _boxMorphTargets.min ); - _box$2.expandByPoint( _boxMorphTargets.max ); - - } - - } - - } - - _box$2.getCenter( center ); - - // second, try to find a boundingSphere with a radius smaller than the - // boundingSphere of the boundingBox: sqrt(3) smaller in the best case - - let maxRadiusSq = 0; - - for ( let i = 0, il = position.count; i < il; i ++ ) { - - _vector$8.fromBufferAttribute( position, i ); - - maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( _vector$8 ) ); - - } - - // process morph attributes if present - - if ( morphAttributesPosition ) { - - for ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) { - - const morphAttribute = morphAttributesPosition[ i ]; - const morphTargetsRelative = this.morphTargetsRelative; - - for ( let j = 0, jl = morphAttribute.count; j < jl; j ++ ) { - - _vector$8.fromBufferAttribute( morphAttribute, j ); - - if ( morphTargetsRelative ) { - - _offset.fromBufferAttribute( position, j ); - _vector$8.add( _offset ); - - } - - maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( _vector$8 ) ); - - } - - } - - } - - this.boundingSphere.radius = Math.sqrt( maxRadiusSq ); - - if ( isNaN( this.boundingSphere.radius ) ) { - - console.error( 'THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.', this ); - - } - - } - - } - - computeTangents() { - - const index = this.index; - const attributes = this.attributes; - - // based on http://www.terathon.com/code/tangent.html - // (per vertex tangents) - - if ( index === null || - attributes.position === undefined || - attributes.normal === undefined || - attributes.uv === undefined ) { - - console.error( 'THREE.BufferGeometry: .computeTangents() failed. Missing required attributes (index, position, normal or uv)' ); - return; - - } - - const indices = index.array; - const positions = attributes.position.array; - const normals = attributes.normal.array; - const uvs = attributes.uv.array; - - const nVertices = positions.length / 3; - - if ( this.hasAttribute( 'tangent' ) === false ) { - - this.setAttribute( 'tangent', new BufferAttribute( new Float32Array( 4 * nVertices ), 4 ) ); - - } - - const tangents = this.getAttribute( 'tangent' ).array; - - const tan1 = [], tan2 = []; - - for ( let i = 0; i < nVertices; i ++ ) { - - tan1[ i ] = new Vector3(); - tan2[ i ] = new Vector3(); - - } - - const vA = new Vector3(), - vB = new Vector3(), - vC = new Vector3(), - - uvA = new Vector2(), - uvB = new Vector2(), - uvC = new Vector2(), - - sdir = new Vector3(), - tdir = new Vector3(); - - function handleTriangle( a, b, c ) { - - vA.fromArray( positions, a * 3 ); - vB.fromArray( positions, b * 3 ); - vC.fromArray( positions, c * 3 ); - - uvA.fromArray( uvs, a * 2 ); - uvB.fromArray( uvs, b * 2 ); - uvC.fromArray( uvs, c * 2 ); - - vB.sub( vA ); - vC.sub( vA ); - - uvB.sub( uvA ); - uvC.sub( uvA ); - - const r = 1.0 / ( uvB.x * uvC.y - uvC.x * uvB.y ); - - // silently ignore degenerate uv triangles having coincident or colinear vertices - - if ( ! isFinite( r ) ) return; - - sdir.copy( vB ).multiplyScalar( uvC.y ).addScaledVector( vC, - uvB.y ).multiplyScalar( r ); - tdir.copy( vC ).multiplyScalar( uvB.x ).addScaledVector( vB, - uvC.x ).multiplyScalar( r ); - - tan1[ a ].add( sdir ); - tan1[ b ].add( sdir ); - tan1[ c ].add( sdir ); - - tan2[ a ].add( tdir ); - tan2[ b ].add( tdir ); - tan2[ c ].add( tdir ); - - } - - let groups = this.groups; - - if ( groups.length === 0 ) { - - groups = [ { - start: 0, - count: indices.length - } ]; - - } - - for ( let i = 0, il = groups.length; i < il; ++ i ) { - - const group = groups[ i ]; - - const start = group.start; - const count = group.count; - - for ( let j = start, jl = start + count; j < jl; j += 3 ) { - - handleTriangle( - indices[ j + 0 ], - indices[ j + 1 ], - indices[ j + 2 ] - ); - - } - - } - - const tmp = new Vector3(), tmp2 = new Vector3(); - const n = new Vector3(), n2 = new Vector3(); - - function handleVertex( v ) { - - n.fromArray( normals, v * 3 ); - n2.copy( n ); - - const t = tan1[ v ]; - - // Gram-Schmidt orthogonalize - - tmp.copy( t ); - tmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize(); - - // Calculate handedness - - tmp2.crossVectors( n2, t ); - const test = tmp2.dot( tan2[ v ] ); - const w = ( test < 0.0 ) ? - 1.0 : 1.0; - - tangents[ v * 4 ] = tmp.x; - tangents[ v * 4 + 1 ] = tmp.y; - tangents[ v * 4 + 2 ] = tmp.z; - tangents[ v * 4 + 3 ] = w; - - } - - for ( let i = 0, il = groups.length; i < il; ++ i ) { - - const group = groups[ i ]; - - const start = group.start; - const count = group.count; - - for ( let j = start, jl = start + count; j < jl; j += 3 ) { - - handleVertex( indices[ j + 0 ] ); - handleVertex( indices[ j + 1 ] ); - handleVertex( indices[ j + 2 ] ); - - } - - } - - } - - computeVertexNormals() { - - const index = this.index; - const positionAttribute = this.getAttribute( 'position' ); - - if ( positionAttribute !== undefined ) { - - let normalAttribute = this.getAttribute( 'normal' ); - - if ( normalAttribute === undefined ) { - - normalAttribute = new BufferAttribute( new Float32Array( positionAttribute.count * 3 ), 3 ); - this.setAttribute( 'normal', normalAttribute ); - - } else { - - // reset existing normals to zero - - for ( let i = 0, il = normalAttribute.count; i < il; i ++ ) { - - normalAttribute.setXYZ( i, 0, 0, 0 ); - - } - - } - - const pA = new Vector3(), pB = new Vector3(), pC = new Vector3(); - const nA = new Vector3(), nB = new Vector3(), nC = new Vector3(); - const cb = new Vector3(), ab = new Vector3(); - - // indexed elements - - if ( index ) { - - for ( let i = 0, il = index.count; i < il; i += 3 ) { - - const vA = index.getX( i + 0 ); - const vB = index.getX( i + 1 ); - const vC = index.getX( i + 2 ); - - pA.fromBufferAttribute( positionAttribute, vA ); - pB.fromBufferAttribute( positionAttribute, vB ); - pC.fromBufferAttribute( positionAttribute, vC ); - - cb.subVectors( pC, pB ); - ab.subVectors( pA, pB ); - cb.cross( ab ); - - nA.fromBufferAttribute( normalAttribute, vA ); - nB.fromBufferAttribute( normalAttribute, vB ); - nC.fromBufferAttribute( normalAttribute, vC ); - - nA.add( cb ); - nB.add( cb ); - nC.add( cb ); - - normalAttribute.setXYZ( vA, nA.x, nA.y, nA.z ); - normalAttribute.setXYZ( vB, nB.x, nB.y, nB.z ); - normalAttribute.setXYZ( vC, nC.x, nC.y, nC.z ); - - } - - } else { - - // non-indexed elements (unconnected triangle soup) - - for ( let i = 0, il = positionAttribute.count; i < il; i += 3 ) { - - pA.fromBufferAttribute( positionAttribute, i + 0 ); - pB.fromBufferAttribute( positionAttribute, i + 1 ); - pC.fromBufferAttribute( positionAttribute, i + 2 ); - - cb.subVectors( pC, pB ); - ab.subVectors( pA, pB ); - cb.cross( ab ); - - normalAttribute.setXYZ( i + 0, cb.x, cb.y, cb.z ); - normalAttribute.setXYZ( i + 1, cb.x, cb.y, cb.z ); - normalAttribute.setXYZ( i + 2, cb.x, cb.y, cb.z ); - - } - - } - - this.normalizeNormals(); - - normalAttribute.needsUpdate = true; - - } - - } - - normalizeNormals() { - - const normals = this.attributes.normal; - - for ( let i = 0, il = normals.count; i < il; i ++ ) { - - _vector$8.fromBufferAttribute( normals, i ); - - _vector$8.normalize(); - - normals.setXYZ( i, _vector$8.x, _vector$8.y, _vector$8.z ); - - } - - } - - toNonIndexed() { - - function convertBufferAttribute( attribute, indices ) { - - const array = attribute.array; - const itemSize = attribute.itemSize; - const normalized = attribute.normalized; - - const array2 = new array.constructor( indices.length * itemSize ); - - let index = 0, index2 = 0; - - for ( let i = 0, l = indices.length; i < l; i ++ ) { - - if ( attribute.isInterleavedBufferAttribute ) { - - index = indices[ i ] * attribute.data.stride + attribute.offset; - - } else { - - index = indices[ i ] * itemSize; - - } - - for ( let j = 0; j < itemSize; j ++ ) { - - array2[ index2 ++ ] = array[ index ++ ]; - - } - - } - - return new BufferAttribute( array2, itemSize, normalized ); - - } - - // - - if ( this.index === null ) { - - console.warn( 'THREE.BufferGeometry.toNonIndexed(): BufferGeometry is already non-indexed.' ); - return this; - - } - - const geometry2 = new BufferGeometry(); - - const indices = this.index.array; - const attributes = this.attributes; - - // attributes - - for ( const name in attributes ) { - - const attribute = attributes[ name ]; - - const newAttribute = convertBufferAttribute( attribute, indices ); - - geometry2.setAttribute( name, newAttribute ); - - } - - // morph attributes - - const morphAttributes = this.morphAttributes; - - for ( const name in morphAttributes ) { - - const morphArray = []; - const morphAttribute = morphAttributes[ name ]; // morphAttribute: array of Float32BufferAttributes - - for ( let i = 0, il = morphAttribute.length; i < il; i ++ ) { - - const attribute = morphAttribute[ i ]; - - const newAttribute = convertBufferAttribute( attribute, indices ); - - morphArray.push( newAttribute ); - - } - - geometry2.morphAttributes[ name ] = morphArray; - - } - - geometry2.morphTargetsRelative = this.morphTargetsRelative; - - // groups - - const groups = this.groups; - - for ( let i = 0, l = groups.length; i < l; i ++ ) { - - const group = groups[ i ]; - geometry2.addGroup( group.start, group.count, group.materialIndex ); - - } - - return geometry2; - - } - - toJSON() { - - const data = { - metadata: { - version: 4.6, - type: 'BufferGeometry', - generator: 'BufferGeometry.toJSON' - } - }; - - // standard BufferGeometry serialization - - data.uuid = this.uuid; - data.type = this.type; - if ( this.name !== '' ) data.name = this.name; - if ( Object.keys( this.userData ).length > 0 ) data.userData = this.userData; - - if ( this.parameters !== undefined ) { - - const parameters = this.parameters; - - for ( const key in parameters ) { - - if ( parameters[ key ] !== undefined ) data[ key ] = parameters[ key ]; - - } - - return data; - - } - - // for simplicity the code assumes attributes are not shared across geometries, see #15811 - - data.data = { attributes: {} }; - - const index = this.index; - - if ( index !== null ) { - - data.data.index = { - type: index.array.constructor.name, - array: Array.prototype.slice.call( index.array ) - }; - - } - - const attributes = this.attributes; - - for ( const key in attributes ) { - - const attribute = attributes[ key ]; - - data.data.attributes[ key ] = attribute.toJSON( data.data ); - - } - - const morphAttributes = {}; - let hasMorphAttributes = false; - - for ( const key in this.morphAttributes ) { - - const attributeArray = this.morphAttributes[ key ]; - - const array = []; - - for ( let i = 0, il = attributeArray.length; i < il; i ++ ) { - - const attribute = attributeArray[ i ]; - - array.push( attribute.toJSON( data.data ) ); - - } - - if ( array.length > 0 ) { - - morphAttributes[ key ] = array; - - hasMorphAttributes = true; - - } - - } - - if ( hasMorphAttributes ) { - - data.data.morphAttributes = morphAttributes; - data.data.morphTargetsRelative = this.morphTargetsRelative; - - } - - const groups = this.groups; - - if ( groups.length > 0 ) { - - data.data.groups = JSON.parse( JSON.stringify( groups ) ); - - } - - const boundingSphere = this.boundingSphere; - - if ( boundingSphere !== null ) { - - data.data.boundingSphere = { - center: boundingSphere.center.toArray(), - radius: boundingSphere.radius - }; - - } - - return data; - - } - - clone() { - - return new this.constructor().copy( this ); - - } - - copy( source ) { - - // reset - - this.index = null; - this.attributes = {}; - this.morphAttributes = {}; - this.groups = []; - this.boundingBox = null; - this.boundingSphere = null; - - // used for storing cloned, shared data - - const data = {}; - - // name - - this.name = source.name; - - // index - - const index = source.index; - - if ( index !== null ) { - - this.setIndex( index.clone( data ) ); - - } - - // attributes - - const attributes = source.attributes; - - for ( const name in attributes ) { - - const attribute = attributes[ name ]; - this.setAttribute( name, attribute.clone( data ) ); - - } - - // morph attributes - - const morphAttributes = source.morphAttributes; - - for ( const name in morphAttributes ) { - - const array = []; - const morphAttribute = morphAttributes[ name ]; // morphAttribute: array of Float32BufferAttributes - - for ( let i = 0, l = morphAttribute.length; i < l; i ++ ) { - - array.push( morphAttribute[ i ].clone( data ) ); - - } - - this.morphAttributes[ name ] = array; - - } - - this.morphTargetsRelative = source.morphTargetsRelative; - - // groups - - const groups = source.groups; - - for ( let i = 0, l = groups.length; i < l; i ++ ) { - - const group = groups[ i ]; - this.addGroup( group.start, group.count, group.materialIndex ); - - } - - // bounding box - - const boundingBox = source.boundingBox; - - if ( boundingBox !== null ) { - - this.boundingBox = boundingBox.clone(); - - } - - // bounding sphere - - const boundingSphere = source.boundingSphere; - - if ( boundingSphere !== null ) { - - this.boundingSphere = boundingSphere.clone(); - - } - - // draw range - - this.drawRange.start = source.drawRange.start; - this.drawRange.count = source.drawRange.count; - - // user data - - this.userData = source.userData; - - return this; - - } - - dispose() { - - this.dispatchEvent( { type: 'dispose' } ); - - } - -} - -const _inverseMatrix$3 = /*@__PURE__*/ new Matrix4(); -const _ray$3 = /*@__PURE__*/ new Ray(); -const _sphere$6 = /*@__PURE__*/ new Sphere(); -const _sphereHitAt = /*@__PURE__*/ new Vector3(); - -const _vA$1 = /*@__PURE__*/ new Vector3(); -const _vB$1 = /*@__PURE__*/ new Vector3(); -const _vC$1 = /*@__PURE__*/ new Vector3(); - -const _tempA = /*@__PURE__*/ new Vector3(); -const _morphA = /*@__PURE__*/ new Vector3(); - -const _uvA$1 = /*@__PURE__*/ new Vector2(); -const _uvB$1 = /*@__PURE__*/ new Vector2(); -const _uvC$1 = /*@__PURE__*/ new Vector2(); - -const _normalA = /*@__PURE__*/ new Vector3(); -const _normalB = /*@__PURE__*/ new Vector3(); -const _normalC = /*@__PURE__*/ new Vector3(); - -const _intersectionPoint = /*@__PURE__*/ new Vector3(); -const _intersectionPointWorld = /*@__PURE__*/ new Vector3(); - -class Mesh extends Object3D { - - constructor( geometry = new BufferGeometry(), material = new MeshBasicMaterial() ) { - - super(); - - this.isMesh = true; - - this.type = 'Mesh'; - - this.geometry = geometry; - this.material = material; - - this.updateMorphTargets(); - - } - - copy( source, recursive ) { - - super.copy( source, recursive ); - - if ( source.morphTargetInfluences !== undefined ) { - - this.morphTargetInfluences = source.morphTargetInfluences.slice(); - - } - - if ( source.morphTargetDictionary !== undefined ) { - - this.morphTargetDictionary = Object.assign( {}, source.morphTargetDictionary ); - - } - - this.material = Array.isArray( source.material ) ? source.material.slice() : source.material; - this.geometry = source.geometry; - - return this; - - } - - updateMorphTargets() { - - const geometry = this.geometry; - - const morphAttributes = geometry.morphAttributes; - const keys = Object.keys( morphAttributes ); - - if ( keys.length > 0 ) { - - const morphAttribute = morphAttributes[ keys[ 0 ] ]; - - if ( morphAttribute !== undefined ) { - - this.morphTargetInfluences = []; - this.morphTargetDictionary = {}; - - for ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) { - - const name = morphAttribute[ m ].name || String( m ); - - this.morphTargetInfluences.push( 0 ); - this.morphTargetDictionary[ name ] = m; - - } - - } - - } - - } - - getVertexPosition( index, target ) { - - const geometry = this.geometry; - const position = geometry.attributes.position; - const morphPosition = geometry.morphAttributes.position; - const morphTargetsRelative = geometry.morphTargetsRelative; - - target.fromBufferAttribute( position, index ); - - const morphInfluences = this.morphTargetInfluences; - - if ( morphPosition && morphInfluences ) { - - _morphA.set( 0, 0, 0 ); - - for ( let i = 0, il = morphPosition.length; i < il; i ++ ) { - - const influence = morphInfluences[ i ]; - const morphAttribute = morphPosition[ i ]; - - if ( influence === 0 ) continue; - - _tempA.fromBufferAttribute( morphAttribute, index ); - - if ( morphTargetsRelative ) { - - _morphA.addScaledVector( _tempA, influence ); - - } else { - - _morphA.addScaledVector( _tempA.sub( target ), influence ); - - } - - } - - target.add( _morphA ); - - } - - return target; - - } - - raycast( raycaster, intersects ) { - - const geometry = this.geometry; - const material = this.material; - const matrixWorld = this.matrixWorld; - - if ( material === undefined ) return; - - // test with bounding sphere in world space - - if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); - - _sphere$6.copy( geometry.boundingSphere ); - _sphere$6.applyMatrix4( matrixWorld ); - - // check distance from ray origin to bounding sphere - - _ray$3.copy( raycaster.ray ).recast( raycaster.near ); - - if ( _sphere$6.containsPoint( _ray$3.origin ) === false ) { - - if ( _ray$3.intersectSphere( _sphere$6, _sphereHitAt ) === null ) return; - - if ( _ray$3.origin.distanceToSquared( _sphereHitAt ) > ( raycaster.far - raycaster.near ) ** 2 ) return; - - } - - // convert ray to local space of mesh - - _inverseMatrix$3.copy( matrixWorld ).invert(); - _ray$3.copy( raycaster.ray ).applyMatrix4( _inverseMatrix$3 ); - - // test with bounding box in local space - - if ( geometry.boundingBox !== null ) { - - if ( _ray$3.intersectsBox( geometry.boundingBox ) === false ) return; - - } - - // test for intersections with geometry - - this._computeIntersections( raycaster, intersects, _ray$3 ); - - } - - _computeIntersections( raycaster, intersects, rayLocalSpace ) { - - let intersection; - - const geometry = this.geometry; - const material = this.material; - - const index = geometry.index; - const position = geometry.attributes.position; - const uv = geometry.attributes.uv; - const uv1 = geometry.attributes.uv1; - const normal = geometry.attributes.normal; - const groups = geometry.groups; - const drawRange = geometry.drawRange; - - if ( index !== null ) { - - // indexed buffer geometry - - if ( Array.isArray( material ) ) { - - for ( let i = 0, il = groups.length; i < il; i ++ ) { - - const group = groups[ i ]; - const groupMaterial = material[ group.materialIndex ]; - - const start = Math.max( group.start, drawRange.start ); - const end = Math.min( index.count, Math.min( ( group.start + group.count ), ( drawRange.start + drawRange.count ) ) ); - - for ( let j = start, jl = end; j < jl; j += 3 ) { - - const a = index.getX( j ); - const b = index.getX( j + 1 ); - const c = index.getX( j + 2 ); - - intersection = checkGeometryIntersection( this, groupMaterial, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c ); - - if ( intersection ) { - - intersection.faceIndex = Math.floor( j / 3 ); // triangle number in indexed buffer semantics - intersection.face.materialIndex = group.materialIndex; - intersects.push( intersection ); - - } - - } - - } - - } else { - - const start = Math.max( 0, drawRange.start ); - const end = Math.min( index.count, ( drawRange.start + drawRange.count ) ); - - for ( let i = start, il = end; i < il; i += 3 ) { - - const a = index.getX( i ); - const b = index.getX( i + 1 ); - const c = index.getX( i + 2 ); - - intersection = checkGeometryIntersection( this, material, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c ); - - if ( intersection ) { - - intersection.faceIndex = Math.floor( i / 3 ); // triangle number in indexed buffer semantics - intersects.push( intersection ); - - } - - } - - } - - } else if ( position !== undefined ) { - - // non-indexed buffer geometry - - if ( Array.isArray( material ) ) { - - for ( let i = 0, il = groups.length; i < il; i ++ ) { - - const group = groups[ i ]; - const groupMaterial = material[ group.materialIndex ]; - - const start = Math.max( group.start, drawRange.start ); - const end = Math.min( position.count, Math.min( ( group.start + group.count ), ( drawRange.start + drawRange.count ) ) ); - - for ( let j = start, jl = end; j < jl; j += 3 ) { - - const a = j; - const b = j + 1; - const c = j + 2; - - intersection = checkGeometryIntersection( this, groupMaterial, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c ); - - if ( intersection ) { - - intersection.faceIndex = Math.floor( j / 3 ); // triangle number in non-indexed buffer semantics - intersection.face.materialIndex = group.materialIndex; - intersects.push( intersection ); - - } - - } - - } - - } else { - - const start = Math.max( 0, drawRange.start ); - const end = Math.min( position.count, ( drawRange.start + drawRange.count ) ); - - for ( let i = start, il = end; i < il; i += 3 ) { - - const a = i; - const b = i + 1; - const c = i + 2; - - intersection = checkGeometryIntersection( this, material, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c ); - - if ( intersection ) { - - intersection.faceIndex = Math.floor( i / 3 ); // triangle number in non-indexed buffer semantics - intersects.push( intersection ); - - } - - } - - } - - } - - } - -} - -function checkIntersection( object, material, raycaster, ray, pA, pB, pC, point ) { - - let intersect; - - if ( material.side === BackSide ) { - - intersect = ray.intersectTriangle( pC, pB, pA, true, point ); - - } else { - - intersect = ray.intersectTriangle( pA, pB, pC, ( material.side === FrontSide ), point ); - - } - - if ( intersect === null ) return null; - - _intersectionPointWorld.copy( point ); - _intersectionPointWorld.applyMatrix4( object.matrixWorld ); - - const distance = raycaster.ray.origin.distanceTo( _intersectionPointWorld ); - - if ( distance < raycaster.near || distance > raycaster.far ) return null; - - return { - distance: distance, - point: _intersectionPointWorld.clone(), - object: object - }; - -} - -function checkGeometryIntersection( object, material, raycaster, ray, uv, uv1, normal, a, b, c ) { - - object.getVertexPosition( a, _vA$1 ); - object.getVertexPosition( b, _vB$1 ); - object.getVertexPosition( c, _vC$1 ); - - const intersection = checkIntersection( object, material, raycaster, ray, _vA$1, _vB$1, _vC$1, _intersectionPoint ); - - if ( intersection ) { - - if ( uv ) { - - _uvA$1.fromBufferAttribute( uv, a ); - _uvB$1.fromBufferAttribute( uv, b ); - _uvC$1.fromBufferAttribute( uv, c ); - - intersection.uv = Triangle.getInterpolation( _intersectionPoint, _vA$1, _vB$1, _vC$1, _uvA$1, _uvB$1, _uvC$1, new Vector2() ); - - } - - if ( uv1 ) { - - _uvA$1.fromBufferAttribute( uv1, a ); - _uvB$1.fromBufferAttribute( uv1, b ); - _uvC$1.fromBufferAttribute( uv1, c ); - - intersection.uv1 = Triangle.getInterpolation( _intersectionPoint, _vA$1, _vB$1, _vC$1, _uvA$1, _uvB$1, _uvC$1, new Vector2() ); - - } - - if ( normal ) { - - _normalA.fromBufferAttribute( normal, a ); - _normalB.fromBufferAttribute( normal, b ); - _normalC.fromBufferAttribute( normal, c ); - - intersection.normal = Triangle.getInterpolation( _intersectionPoint, _vA$1, _vB$1, _vC$1, _normalA, _normalB, _normalC, new Vector3() ); - - if ( intersection.normal.dot( ray.direction ) > 0 ) { - - intersection.normal.multiplyScalar( - 1 ); - - } - - } - - const face = { - a: a, - b: b, - c: c, - normal: new Vector3(), - materialIndex: 0 - }; - - Triangle.getNormal( _vA$1, _vB$1, _vC$1, face.normal ); - - intersection.face = face; - - } - - return intersection; - -} - -class BoxGeometry extends BufferGeometry { - - constructor( width = 1, height = 1, depth = 1, widthSegments = 1, heightSegments = 1, depthSegments = 1 ) { - - super(); - - this.type = 'BoxGeometry'; - - this.parameters = { - width: width, - height: height, - depth: depth, - widthSegments: widthSegments, - heightSegments: heightSegments, - depthSegments: depthSegments - }; - - const scope = this; - - // segments - - widthSegments = Math.floor( widthSegments ); - heightSegments = Math.floor( heightSegments ); - depthSegments = Math.floor( depthSegments ); - - // buffers - - const indices = []; - const vertices = []; - const normals = []; - const uvs = []; - - // helper variables - - let numberOfVertices = 0; - let groupStart = 0; - - // build each side of the box geometry - - buildPlane( 'z', 'y', 'x', - 1, - 1, depth, height, width, depthSegments, heightSegments, 0 ); // px - buildPlane( 'z', 'y', 'x', 1, - 1, depth, height, - width, depthSegments, heightSegments, 1 ); // nx - buildPlane( 'x', 'z', 'y', 1, 1, width, depth, height, widthSegments, depthSegments, 2 ); // py - buildPlane( 'x', 'z', 'y', 1, - 1, width, depth, - height, widthSegments, depthSegments, 3 ); // ny - buildPlane( 'x', 'y', 'z', 1, - 1, width, height, depth, widthSegments, heightSegments, 4 ); // pz - buildPlane( 'x', 'y', 'z', - 1, - 1, width, height, - depth, widthSegments, heightSegments, 5 ); // nz - - // build geometry - - this.setIndex( indices ); - this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - - function buildPlane( u, v, w, udir, vdir, width, height, depth, gridX, gridY, materialIndex ) { - - const segmentWidth = width / gridX; - const segmentHeight = height / gridY; - - const widthHalf = width / 2; - const heightHalf = height / 2; - const depthHalf = depth / 2; - - const gridX1 = gridX + 1; - const gridY1 = gridY + 1; - - let vertexCounter = 0; - let groupCount = 0; - - const vector = new Vector3(); - - // generate vertices, normals and uvs - - for ( let iy = 0; iy < gridY1; iy ++ ) { - - const y = iy * segmentHeight - heightHalf; - - for ( let ix = 0; ix < gridX1; ix ++ ) { - - const x = ix * segmentWidth - widthHalf; - - // set values to correct vector component - - vector[ u ] = x * udir; - vector[ v ] = y * vdir; - vector[ w ] = depthHalf; - - // now apply vector to vertex buffer - - vertices.push( vector.x, vector.y, vector.z ); - - // set values to correct vector component - - vector[ u ] = 0; - vector[ v ] = 0; - vector[ w ] = depth > 0 ? 1 : - 1; - - // now apply vector to normal buffer - - normals.push( vector.x, vector.y, vector.z ); - - // uvs - - uvs.push( ix / gridX ); - uvs.push( 1 - ( iy / gridY ) ); - - // counters - - vertexCounter += 1; - - } - - } - - // indices - - // 1. you need three indices to draw a single face - // 2. a single segment consists of two faces - // 3. so we need to generate six (2*3) indices per segment - - for ( let iy = 0; iy < gridY; iy ++ ) { - - for ( let ix = 0; ix < gridX; ix ++ ) { - - const a = numberOfVertices + ix + gridX1 * iy; - const b = numberOfVertices + ix + gridX1 * ( iy + 1 ); - const c = numberOfVertices + ( ix + 1 ) + gridX1 * ( iy + 1 ); - const d = numberOfVertices + ( ix + 1 ) + gridX1 * iy; - - // faces - - indices.push( a, b, d ); - indices.push( b, c, d ); - - // increase counter - - groupCount += 6; - - } - - } - - // add a group to the geometry. this will ensure multi material support - - scope.addGroup( groupStart, groupCount, materialIndex ); - - // calculate new start value for groups - - groupStart += groupCount; - - // update total number of vertices - - numberOfVertices += vertexCounter; - - } - - } - - copy( source ) { - - super.copy( source ); - - this.parameters = Object.assign( {}, source.parameters ); - - return this; - - } - - static fromJSON( data ) { - - return new BoxGeometry( data.width, data.height, data.depth, data.widthSegments, data.heightSegments, data.depthSegments ); - - } - -} - -/** - * Uniform Utilities - */ - -function cloneUniforms( src ) { - - const dst = {}; - - for ( const u in src ) { - - dst[ u ] = {}; - - for ( const p in src[ u ] ) { - - const property = src[ u ][ p ]; - - if ( property && ( property.isColor || - property.isMatrix3 || property.isMatrix4 || - property.isVector2 || property.isVector3 || property.isVector4 || - property.isTexture || property.isQuaternion ) ) { - - if ( property.isRenderTargetTexture ) { - - console.warn( 'UniformsUtils: Textures of render targets cannot be cloned via cloneUniforms() or mergeUniforms().' ); - dst[ u ][ p ] = null; - - } else { - - dst[ u ][ p ] = property.clone(); - - } - - } else if ( Array.isArray( property ) ) { - - dst[ u ][ p ] = property.slice(); - - } else { - - dst[ u ][ p ] = property; - - } - - } - - } - - return dst; - -} - -function mergeUniforms( uniforms ) { - - const merged = {}; - - for ( let u = 0; u < uniforms.length; u ++ ) { - - const tmp = cloneUniforms( uniforms[ u ] ); - - for ( const p in tmp ) { - - merged[ p ] = tmp[ p ]; - - } - - } - - return merged; - -} - -function cloneUniformsGroups( src ) { - - const dst = []; - - for ( let u = 0; u < src.length; u ++ ) { - - dst.push( src[ u ].clone() ); - - } - - return dst; - -} - -function getUnlitUniformColorSpace( renderer ) { - - if ( renderer.getRenderTarget() === null ) { - - // https://github.com/mrdoob/three.js/pull/23937#issuecomment-1111067398 - return renderer.outputColorSpace; - - } - - return ColorManagement.workingColorSpace; - -} - -// Legacy - -const UniformsUtils = { clone: cloneUniforms, merge: mergeUniforms }; - -var default_vertex = "void main() {\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}"; - -var default_fragment = "void main() {\n\tgl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );\n}"; - -class ShaderMaterial extends Material { - - constructor( parameters ) { - - super(); - - this.isShaderMaterial = true; - - this.type = 'ShaderMaterial'; - - this.defines = {}; - this.uniforms = {}; - this.uniformsGroups = []; - - this.vertexShader = default_vertex; - this.fragmentShader = default_fragment; - - this.linewidth = 1; - - this.wireframe = false; - this.wireframeLinewidth = 1; - - this.fog = false; // set to use scene fog - this.lights = false; // set to use scene lights - this.clipping = false; // set to use user-defined clipping planes - - this.forceSinglePass = true; - - this.extensions = { - derivatives: false, // set to use derivatives - fragDepth: false, // set to use fragment depth values - drawBuffers: false, // set to use draw buffers - shaderTextureLOD: false, // set to use shader texture LOD - clipCullDistance: false, // set to use vertex shader clipping - multiDraw: false // set to use vertex shader multi_draw / enable gl_DrawID - }; - - // When rendered geometry doesn't include these attributes but the material does, - // use these default values in WebGL. This avoids errors when buffer data is missing. - this.defaultAttributeValues = { - 'color': [ 1, 1, 1 ], - 'uv': [ 0, 0 ], - 'uv1': [ 0, 0 ] - }; - - this.index0AttributeName = undefined; - this.uniformsNeedUpdate = false; - - this.glslVersion = null; - - if ( parameters !== undefined ) { - - this.setValues( parameters ); - - } - - } - - copy( source ) { - - super.copy( source ); - - this.fragmentShader = source.fragmentShader; - this.vertexShader = source.vertexShader; - - this.uniforms = cloneUniforms( source.uniforms ); - this.uniformsGroups = cloneUniformsGroups( source.uniformsGroups ); - - this.defines = Object.assign( {}, source.defines ); - - this.wireframe = source.wireframe; - this.wireframeLinewidth = source.wireframeLinewidth; - - this.fog = source.fog; - this.lights = source.lights; - this.clipping = source.clipping; - - this.extensions = Object.assign( {}, source.extensions ); - - this.glslVersion = source.glslVersion; - - return this; - - } - - toJSON( meta ) { - - const data = super.toJSON( meta ); - - data.glslVersion = this.glslVersion; - data.uniforms = {}; - - for ( const name in this.uniforms ) { - - const uniform = this.uniforms[ name ]; - const value = uniform.value; - - if ( value && value.isTexture ) { - - data.uniforms[ name ] = { - type: 't', - value: value.toJSON( meta ).uuid - }; - - } else if ( value && value.isColor ) { - - data.uniforms[ name ] = { - type: 'c', - value: value.getHex() - }; - - } else if ( value && value.isVector2 ) { - - data.uniforms[ name ] = { - type: 'v2', - value: value.toArray() - }; - - } else if ( value && value.isVector3 ) { - - data.uniforms[ name ] = { - type: 'v3', - value: value.toArray() - }; - - } else if ( value && value.isVector4 ) { - - data.uniforms[ name ] = { - type: 'v4', - value: value.toArray() - }; - - } else if ( value && value.isMatrix3 ) { - - data.uniforms[ name ] = { - type: 'm3', - value: value.toArray() - }; - - } else if ( value && value.isMatrix4 ) { - - data.uniforms[ name ] = { - type: 'm4', - value: value.toArray() - }; - - } else { - - data.uniforms[ name ] = { - value: value - }; - - // note: the array variants v2v, v3v, v4v, m4v and tv are not supported so far - - } - - } - - if ( Object.keys( this.defines ).length > 0 ) data.defines = this.defines; - - data.vertexShader = this.vertexShader; - data.fragmentShader = this.fragmentShader; - - data.lights = this.lights; - data.clipping = this.clipping; - - const extensions = {}; - - for ( const key in this.extensions ) { - - if ( this.extensions[ key ] === true ) extensions[ key ] = true; - - } - - if ( Object.keys( extensions ).length > 0 ) data.extensions = extensions; - - return data; - - } - -} - -class Camera extends Object3D { - - constructor() { - - super(); - - this.isCamera = true; - - this.type = 'Camera'; - - this.matrixWorldInverse = new Matrix4(); - - this.projectionMatrix = new Matrix4(); - this.projectionMatrixInverse = new Matrix4(); - - this.coordinateSystem = WebGLCoordinateSystem; - - } - - copy( source, recursive ) { - - super.copy( source, recursive ); - - this.matrixWorldInverse.copy( source.matrixWorldInverse ); - - this.projectionMatrix.copy( source.projectionMatrix ); - this.projectionMatrixInverse.copy( source.projectionMatrixInverse ); - - this.coordinateSystem = source.coordinateSystem; - - return this; - - } - - getWorldDirection( target ) { - - return super.getWorldDirection( target ).negate(); - - } - - updateMatrixWorld( force ) { - - super.updateMatrixWorld( force ); - - this.matrixWorldInverse.copy( this.matrixWorld ).invert(); - - } - - updateWorldMatrix( updateParents, updateChildren ) { - - super.updateWorldMatrix( updateParents, updateChildren ); - - this.matrixWorldInverse.copy( this.matrixWorld ).invert(); - - } - - clone() { - - return new this.constructor().copy( this ); - - } - -} - -const _v3$1 = /*@__PURE__*/ new Vector3(); -const _minTarget = /*@__PURE__*/ new Vector2(); -const _maxTarget = /*@__PURE__*/ new Vector2(); - - -class PerspectiveCamera extends Camera { - - constructor( fov = 50, aspect = 1, near = 0.1, far = 2000 ) { - - super(); - - this.isPerspectiveCamera = true; - - this.type = 'PerspectiveCamera'; - - this.fov = fov; - this.zoom = 1; - - this.near = near; - this.far = far; - this.focus = 10; - - this.aspect = aspect; - this.view = null; - - this.filmGauge = 35; // width of the film (default in millimeters) - this.filmOffset = 0; // horizontal film offset (same unit as gauge) - - this.updateProjectionMatrix(); - - } - - copy( source, recursive ) { - - super.copy( source, recursive ); - - this.fov = source.fov; - this.zoom = source.zoom; - - this.near = source.near; - this.far = source.far; - this.focus = source.focus; - - this.aspect = source.aspect; - this.view = source.view === null ? null : Object.assign( {}, source.view ); - - this.filmGauge = source.filmGauge; - this.filmOffset = source.filmOffset; - - return this; - - } - - /** - * Sets the FOV by focal length in respect to the current .filmGauge. - * - * The default film gauge is 35, so that the focal length can be specified for - * a 35mm (full frame) camera. - * - * Values for focal length and film gauge must have the same unit. - */ - setFocalLength( focalLength ) { - - /** see {@link http://www.bobatkins.com/photography/technical/field_of_view.html} */ - const vExtentSlope = 0.5 * this.getFilmHeight() / focalLength; - - this.fov = RAD2DEG * 2 * Math.atan( vExtentSlope ); - this.updateProjectionMatrix(); - - } - - /** - * Calculates the focal length from the current .fov and .filmGauge. - */ - getFocalLength() { - - const vExtentSlope = Math.tan( DEG2RAD * 0.5 * this.fov ); - - return 0.5 * this.getFilmHeight() / vExtentSlope; - - } - - getEffectiveFOV() { - - return RAD2DEG * 2 * Math.atan( - Math.tan( DEG2RAD * 0.5 * this.fov ) / this.zoom ); - - } - - getFilmWidth() { - - // film not completely covered in portrait format (aspect < 1) - return this.filmGauge * Math.min( this.aspect, 1 ); - - } - - getFilmHeight() { - - // film not completely covered in landscape format (aspect > 1) - return this.filmGauge / Math.max( this.aspect, 1 ); - - } - - /** - * Computes the 2D bounds of the camera's viewable rectangle at a given distance along the viewing direction. - * Sets minTarget and maxTarget to the coordinates of the lower-left and upper-right corners of the view rectangle. - */ - getViewBounds( distance, minTarget, maxTarget ) { - - _v3$1.set( - 1, - 1, 0.5 ).applyMatrix4( this.projectionMatrixInverse ); - - minTarget.set( _v3$1.x, _v3$1.y ).multiplyScalar( - distance / _v3$1.z ); - - _v3$1.set( 1, 1, 0.5 ).applyMatrix4( this.projectionMatrixInverse ); - - maxTarget.set( _v3$1.x, _v3$1.y ).multiplyScalar( - distance / _v3$1.z ); - - } - - /** - * Computes the width and height of the camera's viewable rectangle at a given distance along the viewing direction. - * Copies the result into the target Vector2, where x is width and y is height. - */ - getViewSize( distance, target ) { - - this.getViewBounds( distance, _minTarget, _maxTarget ); - - return target.subVectors( _maxTarget, _minTarget ); - - } - - /** - * Sets an offset in a larger frustum. This is useful for multi-window or - * multi-monitor/multi-machine setups. - * - * For example, if you have 3x2 monitors and each monitor is 1920x1080 and - * the monitors are in grid like this - * - * +---+---+---+ - * | A | B | C | - * +---+---+---+ - * | D | E | F | - * +---+---+---+ - * - * then for each monitor you would call it like this - * - * const w = 1920; - * const h = 1080; - * const fullWidth = w * 3; - * const fullHeight = h * 2; - * - * --A-- - * camera.setViewOffset( fullWidth, fullHeight, w * 0, h * 0, w, h ); - * --B-- - * camera.setViewOffset( fullWidth, fullHeight, w * 1, h * 0, w, h ); - * --C-- - * camera.setViewOffset( fullWidth, fullHeight, w * 2, h * 0, w, h ); - * --D-- - * camera.setViewOffset( fullWidth, fullHeight, w * 0, h * 1, w, h ); - * --E-- - * camera.setViewOffset( fullWidth, fullHeight, w * 1, h * 1, w, h ); - * --F-- - * camera.setViewOffset( fullWidth, fullHeight, w * 2, h * 1, w, h ); - * - * Note there is no reason monitors have to be the same size or in a grid. - */ - setViewOffset( fullWidth, fullHeight, x, y, width, height ) { - - this.aspect = fullWidth / fullHeight; - - if ( this.view === null ) { - - this.view = { - enabled: true, - fullWidth: 1, - fullHeight: 1, - offsetX: 0, - offsetY: 0, - width: 1, - height: 1 - }; - - } - - this.view.enabled = true; - this.view.fullWidth = fullWidth; - this.view.fullHeight = fullHeight; - this.view.offsetX = x; - this.view.offsetY = y; - this.view.width = width; - this.view.height = height; - - this.updateProjectionMatrix(); - - } - - clearViewOffset() { - - if ( this.view !== null ) { - - this.view.enabled = false; - - } - - this.updateProjectionMatrix(); - - } - - updateProjectionMatrix() { - - const near = this.near; - let top = near * Math.tan( DEG2RAD * 0.5 * this.fov ) / this.zoom; - let height = 2 * top; - let width = this.aspect * height; - let left = - 0.5 * width; - const view = this.view; - - if ( this.view !== null && this.view.enabled ) { - - const fullWidth = view.fullWidth, - fullHeight = view.fullHeight; - - left += view.offsetX * width / fullWidth; - top -= view.offsetY * height / fullHeight; - width *= view.width / fullWidth; - height *= view.height / fullHeight; - - } - - const skew = this.filmOffset; - if ( skew !== 0 ) left += near * skew / this.getFilmWidth(); - - this.projectionMatrix.makePerspective( left, left + width, top, top - height, near, this.far, this.coordinateSystem ); - - this.projectionMatrixInverse.copy( this.projectionMatrix ).invert(); - - } - - toJSON( meta ) { - - const data = super.toJSON( meta ); - - data.object.fov = this.fov; - data.object.zoom = this.zoom; - - data.object.near = this.near; - data.object.far = this.far; - data.object.focus = this.focus; - - data.object.aspect = this.aspect; - - if ( this.view !== null ) data.object.view = Object.assign( {}, this.view ); - - data.object.filmGauge = this.filmGauge; - data.object.filmOffset = this.filmOffset; - - return data; - - } - -} - -const fov = - 90; // negative fov is not an error -const aspect = 1; - -class CubeCamera extends Object3D { - - constructor( near, far, renderTarget ) { - - super(); - - this.type = 'CubeCamera'; - - this.renderTarget = renderTarget; - this.coordinateSystem = null; - this.activeMipmapLevel = 0; - - const cameraPX = new PerspectiveCamera( fov, aspect, near, far ); - cameraPX.layers = this.layers; - this.add( cameraPX ); - - const cameraNX = new PerspectiveCamera( fov, aspect, near, far ); - cameraNX.layers = this.layers; - this.add( cameraNX ); - - const cameraPY = new PerspectiveCamera( fov, aspect, near, far ); - cameraPY.layers = this.layers; - this.add( cameraPY ); - - const cameraNY = new PerspectiveCamera( fov, aspect, near, far ); - cameraNY.layers = this.layers; - this.add( cameraNY ); - - const cameraPZ = new PerspectiveCamera( fov, aspect, near, far ); - cameraPZ.layers = this.layers; - this.add( cameraPZ ); - - const cameraNZ = new PerspectiveCamera( fov, aspect, near, far ); - cameraNZ.layers = this.layers; - this.add( cameraNZ ); - - } - - updateCoordinateSystem() { - - const coordinateSystem = this.coordinateSystem; - - const cameras = this.children.concat(); - - const [ cameraPX, cameraNX, cameraPY, cameraNY, cameraPZ, cameraNZ ] = cameras; - - for ( const camera of cameras ) this.remove( camera ); - - if ( coordinateSystem === WebGLCoordinateSystem ) { - - cameraPX.up.set( 0, 1, 0 ); - cameraPX.lookAt( 1, 0, 0 ); - - cameraNX.up.set( 0, 1, 0 ); - cameraNX.lookAt( - 1, 0, 0 ); - - cameraPY.up.set( 0, 0, - 1 ); - cameraPY.lookAt( 0, 1, 0 ); - - cameraNY.up.set( 0, 0, 1 ); - cameraNY.lookAt( 0, - 1, 0 ); - - cameraPZ.up.set( 0, 1, 0 ); - cameraPZ.lookAt( 0, 0, 1 ); - - cameraNZ.up.set( 0, 1, 0 ); - cameraNZ.lookAt( 0, 0, - 1 ); - - } else if ( coordinateSystem === WebGPUCoordinateSystem ) { - - cameraPX.up.set( 0, - 1, 0 ); - cameraPX.lookAt( - 1, 0, 0 ); - - cameraNX.up.set( 0, - 1, 0 ); - cameraNX.lookAt( 1, 0, 0 ); - - cameraPY.up.set( 0, 0, 1 ); - cameraPY.lookAt( 0, 1, 0 ); - - cameraNY.up.set( 0, 0, - 1 ); - cameraNY.lookAt( 0, - 1, 0 ); - - cameraPZ.up.set( 0, - 1, 0 ); - cameraPZ.lookAt( 0, 0, 1 ); - - cameraNZ.up.set( 0, - 1, 0 ); - cameraNZ.lookAt( 0, 0, - 1 ); - - } else { - - throw new Error( 'THREE.CubeCamera.updateCoordinateSystem(): Invalid coordinate system: ' + coordinateSystem ); - - } - - for ( const camera of cameras ) { - - this.add( camera ); - - camera.updateMatrixWorld(); - - } - - } - - update( renderer, scene ) { - - if ( this.parent === null ) this.updateMatrixWorld(); - - const { renderTarget, activeMipmapLevel } = this; - - if ( this.coordinateSystem !== renderer.coordinateSystem ) { - - this.coordinateSystem = renderer.coordinateSystem; - - this.updateCoordinateSystem(); - - } - - const [ cameraPX, cameraNX, cameraPY, cameraNY, cameraPZ, cameraNZ ] = this.children; - - const currentRenderTarget = renderer.getRenderTarget(); - const currentActiveCubeFace = renderer.getActiveCubeFace(); - const currentActiveMipmapLevel = renderer.getActiveMipmapLevel(); - - const currentXrEnabled = renderer.xr.enabled; - - renderer.xr.enabled = false; - - const generateMipmaps = renderTarget.texture.generateMipmaps; - - renderTarget.texture.generateMipmaps = false; - - renderer.setRenderTarget( renderTarget, 0, activeMipmapLevel ); - renderer.render( scene, cameraPX ); - - renderer.setRenderTarget( renderTarget, 1, activeMipmapLevel ); - renderer.render( scene, cameraNX ); - - renderer.setRenderTarget( renderTarget, 2, activeMipmapLevel ); - renderer.render( scene, cameraPY ); - - renderer.setRenderTarget( renderTarget, 3, activeMipmapLevel ); - renderer.render( scene, cameraNY ); - - renderer.setRenderTarget( renderTarget, 4, activeMipmapLevel ); - renderer.render( scene, cameraPZ ); - - // mipmaps are generated during the last call of render() - // at this point, all sides of the cube render target are defined - - renderTarget.texture.generateMipmaps = generateMipmaps; - - renderer.setRenderTarget( renderTarget, 5, activeMipmapLevel ); - renderer.render( scene, cameraNZ ); - - renderer.setRenderTarget( currentRenderTarget, currentActiveCubeFace, currentActiveMipmapLevel ); - - renderer.xr.enabled = currentXrEnabled; - - renderTarget.texture.needsPMREMUpdate = true; - - } - -} - -class CubeTexture extends Texture { - - constructor( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, colorSpace ) { - - images = images !== undefined ? images : []; - mapping = mapping !== undefined ? mapping : CubeReflectionMapping; - - super( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, colorSpace ); - - this.isCubeTexture = true; - - this.flipY = false; - - } - - get images() { - - return this.image; - - } - - set images( value ) { - - this.image = value; - - } - -} - -class WebGLCubeRenderTarget extends WebGLRenderTarget { - - constructor( size = 1, options = {} ) { - - super( size, size, options ); - - this.isWebGLCubeRenderTarget = true; - - const image = { width: size, height: size, depth: 1 }; - const images = [ image, image, image, image, image, image ]; - - this.texture = new CubeTexture( images, options.mapping, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.colorSpace ); - - // By convention -- likely based on the RenderMan spec from the 1990's -- cube maps are specified by WebGL (and three.js) - // in a coordinate system in which positive-x is to the right when looking up the positive-z axis -- in other words, - // in a left-handed coordinate system. By continuing this convention, preexisting cube maps continued to render correctly. - - // three.js uses a right-handed coordinate system. So environment maps used in three.js appear to have px and nx swapped - // and the flag isRenderTargetTexture controls this conversion. The flip is not required when using WebGLCubeRenderTarget.texture - // as a cube texture (this is detected when isRenderTargetTexture is set to true for cube textures). - - this.texture.isRenderTargetTexture = true; - - this.texture.generateMipmaps = options.generateMipmaps !== undefined ? options.generateMipmaps : false; - this.texture.minFilter = options.minFilter !== undefined ? options.minFilter : LinearFilter; - - } - - fromEquirectangularTexture( renderer, texture ) { - - this.texture.type = texture.type; - this.texture.colorSpace = texture.colorSpace; - - this.texture.generateMipmaps = texture.generateMipmaps; - this.texture.minFilter = texture.minFilter; - this.texture.magFilter = texture.magFilter; - - const shader = { - - uniforms: { - tEquirect: { value: null }, - }, - - vertexShader: /* glsl */` - - varying vec3 vWorldDirection; - - vec3 transformDirection( in vec3 dir, in mat4 matrix ) { - - return normalize( ( matrix * vec4( dir, 0.0 ) ).xyz ); - - } - - void main() { - - vWorldDirection = transformDirection( position, modelMatrix ); - - #include - #include - - } - `, - - fragmentShader: /* glsl */` - - uniform sampler2D tEquirect; - - varying vec3 vWorldDirection; - - #include - - void main() { - - vec3 direction = normalize( vWorldDirection ); - - vec2 sampleUV = equirectUv( direction ); - - gl_FragColor = texture2D( tEquirect, sampleUV ); - - } - ` - }; - - const geometry = new BoxGeometry( 5, 5, 5 ); - - const material = new ShaderMaterial( { - - name: 'CubemapFromEquirect', - - uniforms: cloneUniforms( shader.uniforms ), - vertexShader: shader.vertexShader, - fragmentShader: shader.fragmentShader, - side: BackSide, - blending: NoBlending - - } ); - - material.uniforms.tEquirect.value = texture; - - const mesh = new Mesh( geometry, material ); - - const currentMinFilter = texture.minFilter; - - // Avoid blurred poles - if ( texture.minFilter === LinearMipmapLinearFilter ) texture.minFilter = LinearFilter; - - const camera = new CubeCamera( 1, 10, this ); - camera.update( renderer, mesh ); - - texture.minFilter = currentMinFilter; - - mesh.geometry.dispose(); - mesh.material.dispose(); - - return this; - - } - - clear( renderer, color, depth, stencil ) { - - const currentRenderTarget = renderer.getRenderTarget(); - - for ( let i = 0; i < 6; i ++ ) { - - renderer.setRenderTarget( this, i ); - - renderer.clear( color, depth, stencil ); - - } - - renderer.setRenderTarget( currentRenderTarget ); - - } - -} - -const _vector1 = /*@__PURE__*/ new Vector3(); -const _vector2 = /*@__PURE__*/ new Vector3(); -const _normalMatrix = /*@__PURE__*/ new Matrix3(); - -class Plane { - - constructor( normal = new Vector3( 1, 0, 0 ), constant = 0 ) { - - this.isPlane = true; - - // normal is assumed to be normalized - - this.normal = normal; - this.constant = constant; - - } - - set( normal, constant ) { - - this.normal.copy( normal ); - this.constant = constant; - - return this; - - } - - setComponents( x, y, z, w ) { - - this.normal.set( x, y, z ); - this.constant = w; - - return this; - - } - - setFromNormalAndCoplanarPoint( normal, point ) { - - this.normal.copy( normal ); - this.constant = - point.dot( this.normal ); - - return this; - - } - - setFromCoplanarPoints( a, b, c ) { - - const normal = _vector1.subVectors( c, b ).cross( _vector2.subVectors( a, b ) ).normalize(); - - // Q: should an error be thrown if normal is zero (e.g. degenerate plane)? - - this.setFromNormalAndCoplanarPoint( normal, a ); - - return this; - - } - - copy( plane ) { - - this.normal.copy( plane.normal ); - this.constant = plane.constant; - - return this; - - } - - normalize() { - - // Note: will lead to a divide by zero if the plane is invalid. - - const inverseNormalLength = 1.0 / this.normal.length(); - this.normal.multiplyScalar( inverseNormalLength ); - this.constant *= inverseNormalLength; - - return this; - - } - - negate() { - - this.constant *= - 1; - this.normal.negate(); - - return this; - - } - - distanceToPoint( point ) { - - return this.normal.dot( point ) + this.constant; - - } - - distanceToSphere( sphere ) { - - return this.distanceToPoint( sphere.center ) - sphere.radius; - - } - - projectPoint( point, target ) { - - return target.copy( point ).addScaledVector( this.normal, - this.distanceToPoint( point ) ); - - } - - intersectLine( line, target ) { - - const direction = line.delta( _vector1 ); - - const denominator = this.normal.dot( direction ); - - if ( denominator === 0 ) { - - // line is coplanar, return origin - if ( this.distanceToPoint( line.start ) === 0 ) { - - return target.copy( line.start ); - - } - - // Unsure if this is the correct method to handle this case. - return null; - - } - - const t = - ( line.start.dot( this.normal ) + this.constant ) / denominator; - - if ( t < 0 || t > 1 ) { - - return null; - - } - - return target.copy( line.start ).addScaledVector( direction, t ); - - } - - intersectsLine( line ) { - - // Note: this tests if a line intersects the plane, not whether it (or its end-points) are coplanar with it. - - const startSign = this.distanceToPoint( line.start ); - const endSign = this.distanceToPoint( line.end ); - - return ( startSign < 0 && endSign > 0 ) || ( endSign < 0 && startSign > 0 ); - - } - - intersectsBox( box ) { - - return box.intersectsPlane( this ); - - } - - intersectsSphere( sphere ) { - - return sphere.intersectsPlane( this ); - - } - - coplanarPoint( target ) { - - return target.copy( this.normal ).multiplyScalar( - this.constant ); - - } - - applyMatrix4( matrix, optionalNormalMatrix ) { - - const normalMatrix = optionalNormalMatrix || _normalMatrix.getNormalMatrix( matrix ); - - const referencePoint = this.coplanarPoint( _vector1 ).applyMatrix4( matrix ); - - const normal = this.normal.applyMatrix3( normalMatrix ).normalize(); - - this.constant = - referencePoint.dot( normal ); - - return this; - - } - - translate( offset ) { - - this.constant -= offset.dot( this.normal ); - - return this; - - } - - equals( plane ) { - - return plane.normal.equals( this.normal ) && ( plane.constant === this.constant ); - - } - - clone() { - - return new this.constructor().copy( this ); - - } - -} - -const _sphere$5 = /*@__PURE__*/ new Sphere(); -const _vector$7 = /*@__PURE__*/ new Vector3(); - -class Frustum { - - constructor( p0 = new Plane(), p1 = new Plane(), p2 = new Plane(), p3 = new Plane(), p4 = new Plane(), p5 = new Plane() ) { - - this.planes = [ p0, p1, p2, p3, p4, p5 ]; - - } - - set( p0, p1, p2, p3, p4, p5 ) { - - const planes = this.planes; - - planes[ 0 ].copy( p0 ); - planes[ 1 ].copy( p1 ); - planes[ 2 ].copy( p2 ); - planes[ 3 ].copy( p3 ); - planes[ 4 ].copy( p4 ); - planes[ 5 ].copy( p5 ); - - return this; - - } - - copy( frustum ) { - - const planes = this.planes; - - for ( let i = 0; i < 6; i ++ ) { - - planes[ i ].copy( frustum.planes[ i ] ); - - } - - return this; - - } - - setFromProjectionMatrix( m, coordinateSystem = WebGLCoordinateSystem ) { - - const planes = this.planes; - const me = m.elements; - const me0 = me[ 0 ], me1 = me[ 1 ], me2 = me[ 2 ], me3 = me[ 3 ]; - const me4 = me[ 4 ], me5 = me[ 5 ], me6 = me[ 6 ], me7 = me[ 7 ]; - const me8 = me[ 8 ], me9 = me[ 9 ], me10 = me[ 10 ], me11 = me[ 11 ]; - const me12 = me[ 12 ], me13 = me[ 13 ], me14 = me[ 14 ], me15 = me[ 15 ]; - - planes[ 0 ].setComponents( me3 - me0, me7 - me4, me11 - me8, me15 - me12 ).normalize(); - planes[ 1 ].setComponents( me3 + me0, me7 + me4, me11 + me8, me15 + me12 ).normalize(); - planes[ 2 ].setComponents( me3 + me1, me7 + me5, me11 + me9, me15 + me13 ).normalize(); - planes[ 3 ].setComponents( me3 - me1, me7 - me5, me11 - me9, me15 - me13 ).normalize(); - planes[ 4 ].setComponents( me3 - me2, me7 - me6, me11 - me10, me15 - me14 ).normalize(); - - if ( coordinateSystem === WebGLCoordinateSystem ) { - - planes[ 5 ].setComponents( me3 + me2, me7 + me6, me11 + me10, me15 + me14 ).normalize(); - - } else if ( coordinateSystem === WebGPUCoordinateSystem ) { - - planes[ 5 ].setComponents( me2, me6, me10, me14 ).normalize(); - - } else { - - throw new Error( 'THREE.Frustum.setFromProjectionMatrix(): Invalid coordinate system: ' + coordinateSystem ); - - } - - return this; - - } - - intersectsObject( object ) { - - if ( object.boundingSphere !== undefined ) { - - if ( object.boundingSphere === null ) object.computeBoundingSphere(); - - _sphere$5.copy( object.boundingSphere ).applyMatrix4( object.matrixWorld ); - - } else { - - const geometry = object.geometry; - - if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); - - _sphere$5.copy( geometry.boundingSphere ).applyMatrix4( object.matrixWorld ); - - } - - return this.intersectsSphere( _sphere$5 ); - - } - - intersectsSprite( sprite ) { - - _sphere$5.center.set( 0, 0, 0 ); - _sphere$5.radius = 0.7071067811865476; - _sphere$5.applyMatrix4( sprite.matrixWorld ); - - return this.intersectsSphere( _sphere$5 ); - - } - - intersectsSphere( sphere ) { - - const planes = this.planes; - const center = sphere.center; - const negRadius = - sphere.radius; - - for ( let i = 0; i < 6; i ++ ) { - - const distance = planes[ i ].distanceToPoint( center ); - - if ( distance < negRadius ) { - - return false; - - } - - } - - return true; - - } - - intersectsBox( box ) { - - const planes = this.planes; - - for ( let i = 0; i < 6; i ++ ) { - - const plane = planes[ i ]; - - // corner at max distance - - _vector$7.x = plane.normal.x > 0 ? box.max.x : box.min.x; - _vector$7.y = plane.normal.y > 0 ? box.max.y : box.min.y; - _vector$7.z = plane.normal.z > 0 ? box.max.z : box.min.z; - - if ( plane.distanceToPoint( _vector$7 ) < 0 ) { - - return false; - - } - - } - - return true; - - } - - containsPoint( point ) { - - const planes = this.planes; - - for ( let i = 0; i < 6; i ++ ) { - - if ( planes[ i ].distanceToPoint( point ) < 0 ) { - - return false; - - } - - } - - return true; - - } - - clone() { - - return new this.constructor().copy( this ); - - } - -} - -function WebGLAnimation() { - - let context = null; - let isAnimating = false; - let animationLoop = null; - let requestId = null; - - function onAnimationFrame( time, frame ) { - - animationLoop( time, frame ); - - requestId = context.requestAnimationFrame( onAnimationFrame ); - - } - - return { - - start: function () { - - if ( isAnimating === true ) return; - if ( animationLoop === null ) return; - - requestId = context.requestAnimationFrame( onAnimationFrame ); - - isAnimating = true; - - }, - - stop: function () { - - context.cancelAnimationFrame( requestId ); - - isAnimating = false; - - }, - - setAnimationLoop: function ( callback ) { - - animationLoop = callback; - - }, - - setContext: function ( value ) { - - context = value; - - } - - }; - -} - -function WebGLAttributes( gl, capabilities ) { - - const isWebGL2 = capabilities.isWebGL2; - - const buffers = new WeakMap(); - - function createBuffer( attribute, bufferType ) { - - const array = attribute.array; - const usage = attribute.usage; - const size = array.byteLength; - - const buffer = gl.createBuffer(); - - gl.bindBuffer( bufferType, buffer ); - gl.bufferData( bufferType, array, usage ); - - attribute.onUploadCallback(); - - let type; - - if ( array instanceof Float32Array ) { - - type = gl.FLOAT; - - } else if ( array instanceof Uint16Array ) { - - if ( attribute.isFloat16BufferAttribute ) { - - if ( isWebGL2 ) { - - type = gl.HALF_FLOAT; - - } else { - - throw new Error( 'THREE.WebGLAttributes: Usage of Float16BufferAttribute requires WebGL2.' ); - - } - - } else { - - type = gl.UNSIGNED_SHORT; - - } - - } else if ( array instanceof Int16Array ) { - - type = gl.SHORT; - - } else if ( array instanceof Uint32Array ) { - - type = gl.UNSIGNED_INT; - - } else if ( array instanceof Int32Array ) { - - type = gl.INT; - - } else if ( array instanceof Int8Array ) { - - type = gl.BYTE; - - } else if ( array instanceof Uint8Array ) { - - type = gl.UNSIGNED_BYTE; - - } else if ( array instanceof Uint8ClampedArray ) { - - type = gl.UNSIGNED_BYTE; - - } else { - - throw new Error( 'THREE.WebGLAttributes: Unsupported buffer data format: ' + array ); - - } - - return { - buffer: buffer, - type: type, - bytesPerElement: array.BYTES_PER_ELEMENT, - version: attribute.version, - size: size - }; - - } - - function updateBuffer( buffer, attribute, bufferType ) { - - const array = attribute.array; - const updateRange = attribute._updateRange; // @deprecated, r159 - const updateRanges = attribute.updateRanges; - - gl.bindBuffer( bufferType, buffer ); - - if ( updateRange.count === - 1 && updateRanges.length === 0 ) { - - // Not using update ranges - gl.bufferSubData( bufferType, 0, array ); - - } - - if ( updateRanges.length !== 0 ) { - - for ( let i = 0, l = updateRanges.length; i < l; i ++ ) { - - const range = updateRanges[ i ]; - if ( isWebGL2 ) { - - gl.bufferSubData( bufferType, range.start * array.BYTES_PER_ELEMENT, - array, range.start, range.count ); - - } else { - - gl.bufferSubData( bufferType, range.start * array.BYTES_PER_ELEMENT, - array.subarray( range.start, range.start + range.count ) ); - - } - - } - - attribute.clearUpdateRanges(); - - } - - // @deprecated, r159 - if ( updateRange.count !== - 1 ) { - - if ( isWebGL2 ) { - - gl.bufferSubData( bufferType, updateRange.offset * array.BYTES_PER_ELEMENT, - array, updateRange.offset, updateRange.count ); - - } else { - - gl.bufferSubData( bufferType, updateRange.offset * array.BYTES_PER_ELEMENT, - array.subarray( updateRange.offset, updateRange.offset + updateRange.count ) ); - - } - - updateRange.count = - 1; // reset range - - } - - attribute.onUploadCallback(); - - } - - // - - function get( attribute ) { - - if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data; - - return buffers.get( attribute ); - - } - - function remove( attribute ) { - - if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data; - - const data = buffers.get( attribute ); - - if ( data ) { - - gl.deleteBuffer( data.buffer ); - - buffers.delete( attribute ); - - } - - } - - function update( attribute, bufferType ) { - - if ( attribute.isGLBufferAttribute ) { - - const cached = buffers.get( attribute ); - - if ( ! cached || cached.version < attribute.version ) { - - buffers.set( attribute, { - buffer: attribute.buffer, - type: attribute.type, - bytesPerElement: attribute.elementSize, - version: attribute.version - } ); - - } - - return; - - } - - if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data; - - const data = buffers.get( attribute ); - - if ( data === undefined ) { - - buffers.set( attribute, createBuffer( attribute, bufferType ) ); - - } else if ( data.version < attribute.version ) { - - if ( data.size !== attribute.array.byteLength ) { - - throw new Error( 'THREE.WebGLAttributes: The size of the buffer attribute\'s array buffer does not match the original size. Resizing buffer attributes is not supported.' ); - - } - - updateBuffer( data.buffer, attribute, bufferType ); - - data.version = attribute.version; - - } - - } - - return { - - get: get, - remove: remove, - update: update - - }; - -} - -class PlaneGeometry extends BufferGeometry { - - constructor( width = 1, height = 1, widthSegments = 1, heightSegments = 1 ) { - - super(); - - this.type = 'PlaneGeometry'; - - this.parameters = { - width: width, - height: height, - widthSegments: widthSegments, - heightSegments: heightSegments - }; - - const width_half = width / 2; - const height_half = height / 2; - - const gridX = Math.floor( widthSegments ); - const gridY = Math.floor( heightSegments ); - - const gridX1 = gridX + 1; - const gridY1 = gridY + 1; - - const segment_width = width / gridX; - const segment_height = height / gridY; - - // - - const indices = []; - const vertices = []; - const normals = []; - const uvs = []; - - for ( let iy = 0; iy < gridY1; iy ++ ) { - - const y = iy * segment_height - height_half; - - for ( let ix = 0; ix < gridX1; ix ++ ) { - - const x = ix * segment_width - width_half; - - vertices.push( x, - y, 0 ); - - normals.push( 0, 0, 1 ); - - uvs.push( ix / gridX ); - uvs.push( 1 - ( iy / gridY ) ); - - } - - } - - for ( let iy = 0; iy < gridY; iy ++ ) { - - for ( let ix = 0; ix < gridX; ix ++ ) { - - const a = ix + gridX1 * iy; - const b = ix + gridX1 * ( iy + 1 ); - const c = ( ix + 1 ) + gridX1 * ( iy + 1 ); - const d = ( ix + 1 ) + gridX1 * iy; - - indices.push( a, b, d ); - indices.push( b, c, d ); - - } - - } - - this.setIndex( indices ); - this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - - } - - copy( source ) { - - super.copy( source ); - - this.parameters = Object.assign( {}, source.parameters ); - - return this; - - } - - static fromJSON( data ) { - - return new PlaneGeometry( data.width, data.height, data.widthSegments, data.heightSegments ); - - } - -} - -var alphahash_fragment = "#ifdef USE_ALPHAHASH\n\tif ( diffuseColor.a < getAlphaHashThreshold( vPosition ) ) discard;\n#endif"; - -var alphahash_pars_fragment = "#ifdef USE_ALPHAHASH\n\tconst float ALPHA_HASH_SCALE = 0.05;\n\tfloat hash2D( vec2 value ) {\n\t\treturn fract( 1.0e4 * sin( 17.0 * value.x + 0.1 * value.y ) * ( 0.1 + abs( sin( 13.0 * value.y + value.x ) ) ) );\n\t}\n\tfloat hash3D( vec3 value ) {\n\t\treturn hash2D( vec2( hash2D( value.xy ), value.z ) );\n\t}\n\tfloat getAlphaHashThreshold( vec3 position ) {\n\t\tfloat maxDeriv = max(\n\t\t\tlength( dFdx( position.xyz ) ),\n\t\t\tlength( dFdy( position.xyz ) )\n\t\t);\n\t\tfloat pixScale = 1.0 / ( ALPHA_HASH_SCALE * maxDeriv );\n\t\tvec2 pixScales = vec2(\n\t\t\texp2( floor( log2( pixScale ) ) ),\n\t\t\texp2( ceil( log2( pixScale ) ) )\n\t\t);\n\t\tvec2 alpha = vec2(\n\t\t\thash3D( floor( pixScales.x * position.xyz ) ),\n\t\t\thash3D( floor( pixScales.y * position.xyz ) )\n\t\t);\n\t\tfloat lerpFactor = fract( log2( pixScale ) );\n\t\tfloat x = ( 1.0 - lerpFactor ) * alpha.x + lerpFactor * alpha.y;\n\t\tfloat a = min( lerpFactor, 1.0 - lerpFactor );\n\t\tvec3 cases = vec3(\n\t\t\tx * x / ( 2.0 * a * ( 1.0 - a ) ),\n\t\t\t( x - 0.5 * a ) / ( 1.0 - a ),\n\t\t\t1.0 - ( ( 1.0 - x ) * ( 1.0 - x ) / ( 2.0 * a * ( 1.0 - a ) ) )\n\t\t);\n\t\tfloat threshold = ( x < ( 1.0 - a ) )\n\t\t\t? ( ( x < a ) ? cases.x : cases.y )\n\t\t\t: cases.z;\n\t\treturn clamp( threshold , 1.0e-6, 1.0 );\n\t}\n#endif"; - -var alphamap_fragment = "#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, vAlphaMapUv ).g;\n#endif"; - -var alphamap_pars_fragment = "#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif"; - -var alphatest_fragment = "#ifdef USE_ALPHATEST\n\t#ifdef ALPHA_TO_COVERAGE\n\tdiffuseColor.a = smoothstep( alphaTest, alphaTest + fwidth( diffuseColor.a ), diffuseColor.a );\n\tif ( diffuseColor.a == 0.0 ) discard;\n\t#else\n\tif ( diffuseColor.a < alphaTest ) discard;\n\t#endif\n#endif"; - -var alphatest_pars_fragment = "#ifdef USE_ALPHATEST\n\tuniform float alphaTest;\n#endif"; - -var aomap_fragment = "#ifdef USE_AOMAP\n\tfloat ambientOcclusion = ( texture2D( aoMap, vAoMapUv ).r - 1.0 ) * aoMapIntensity + 1.0;\n\treflectedLight.indirectDiffuse *= ambientOcclusion;\n\t#if defined( USE_CLEARCOAT ) \n\t\tclearcoatSpecularIndirect *= ambientOcclusion;\n\t#endif\n\t#if defined( USE_SHEEN ) \n\t\tsheenSpecularIndirect *= ambientOcclusion;\n\t#endif\n\t#if defined( USE_ENVMAP ) && defined( STANDARD )\n\t\tfloat dotNV = saturate( dot( geometryNormal, geometryViewDir ) );\n\t\treflectedLight.indirectSpecular *= computeSpecularOcclusion( dotNV, ambientOcclusion, material.roughness );\n\t#endif\n#endif"; - -var aomap_pars_fragment = "#ifdef USE_AOMAP\n\tuniform sampler2D aoMap;\n\tuniform float aoMapIntensity;\n#endif"; - -var batching_pars_vertex = "#ifdef USE_BATCHING\n\tattribute float batchId;\n\tuniform highp sampler2D batchingTexture;\n\tmat4 getBatchingMatrix( const in float i ) {\n\t\tint size = textureSize( batchingTexture, 0 ).x;\n\t\tint j = int( i ) * 4;\n\t\tint x = j % size;\n\t\tint y = j / size;\n\t\tvec4 v1 = texelFetch( batchingTexture, ivec2( x, y ), 0 );\n\t\tvec4 v2 = texelFetch( batchingTexture, ivec2( x + 1, y ), 0 );\n\t\tvec4 v3 = texelFetch( batchingTexture, ivec2( x + 2, y ), 0 );\n\t\tvec4 v4 = texelFetch( batchingTexture, ivec2( x + 3, y ), 0 );\n\t\treturn mat4( v1, v2, v3, v4 );\n\t}\n#endif"; - -var batching_vertex = "#ifdef USE_BATCHING\n\tmat4 batchingMatrix = getBatchingMatrix( batchId );\n#endif"; - -var begin_vertex = "vec3 transformed = vec3( position );\n#ifdef USE_ALPHAHASH\n\tvPosition = vec3( position );\n#endif"; - -var beginnormal_vertex = "vec3 objectNormal = vec3( normal );\n#ifdef USE_TANGENT\n\tvec3 objectTangent = vec3( tangent.xyz );\n#endif"; - -var bsdfs = "float G_BlinnPhong_Implicit( ) {\n\treturn 0.25;\n}\nfloat D_BlinnPhong( const in float shininess, const in float dotNH ) {\n\treturn RECIPROCAL_PI * ( shininess * 0.5 + 1.0 ) * pow( dotNH, shininess );\n}\nvec3 BRDF_BlinnPhong( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in vec3 specularColor, const in float shininess ) {\n\tvec3 halfDir = normalize( lightDir + viewDir );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat dotVH = saturate( dot( viewDir, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, 1.0, dotVH );\n\tfloat G = G_BlinnPhong_Implicit( );\n\tfloat D = D_BlinnPhong( shininess, dotNH );\n\treturn F * ( G * D );\n} // validated"; - -var iridescence_fragment = "#ifdef USE_IRIDESCENCE\n\tconst mat3 XYZ_TO_REC709 = mat3(\n\t\t 3.2404542, -0.9692660, 0.0556434,\n\t\t-1.5371385, 1.8760108, -0.2040259,\n\t\t-0.4985314, 0.0415560, 1.0572252\n\t);\n\tvec3 Fresnel0ToIor( vec3 fresnel0 ) {\n\t\tvec3 sqrtF0 = sqrt( fresnel0 );\n\t\treturn ( vec3( 1.0 ) + sqrtF0 ) / ( vec3( 1.0 ) - sqrtF0 );\n\t}\n\tvec3 IorToFresnel0( vec3 transmittedIor, float incidentIor ) {\n\t\treturn pow2( ( transmittedIor - vec3( incidentIor ) ) / ( transmittedIor + vec3( incidentIor ) ) );\n\t}\n\tfloat IorToFresnel0( float transmittedIor, float incidentIor ) {\n\t\treturn pow2( ( transmittedIor - incidentIor ) / ( transmittedIor + incidentIor ));\n\t}\n\tvec3 evalSensitivity( float OPD, vec3 shift ) {\n\t\tfloat phase = 2.0 * PI * OPD * 1.0e-9;\n\t\tvec3 val = vec3( 5.4856e-13, 4.4201e-13, 5.2481e-13 );\n\t\tvec3 pos = vec3( 1.6810e+06, 1.7953e+06, 2.2084e+06 );\n\t\tvec3 var = vec3( 4.3278e+09, 9.3046e+09, 6.6121e+09 );\n\t\tvec3 xyz = val * sqrt( 2.0 * PI * var ) * cos( pos * phase + shift ) * exp( - pow2( phase ) * var );\n\t\txyz.x += 9.7470e-14 * sqrt( 2.0 * PI * 4.5282e+09 ) * cos( 2.2399e+06 * phase + shift[ 0 ] ) * exp( - 4.5282e+09 * pow2( phase ) );\n\t\txyz /= 1.0685e-7;\n\t\tvec3 rgb = XYZ_TO_REC709 * xyz;\n\t\treturn rgb;\n\t}\n\tvec3 evalIridescence( float outsideIOR, float eta2, float cosTheta1, float thinFilmThickness, vec3 baseF0 ) {\n\t\tvec3 I;\n\t\tfloat iridescenceIOR = mix( outsideIOR, eta2, smoothstep( 0.0, 0.03, thinFilmThickness ) );\n\t\tfloat sinTheta2Sq = pow2( outsideIOR / iridescenceIOR ) * ( 1.0 - pow2( cosTheta1 ) );\n\t\tfloat cosTheta2Sq = 1.0 - sinTheta2Sq;\n\t\tif ( cosTheta2Sq < 0.0 ) {\n\t\t\treturn vec3( 1.0 );\n\t\t}\n\t\tfloat cosTheta2 = sqrt( cosTheta2Sq );\n\t\tfloat R0 = IorToFresnel0( iridescenceIOR, outsideIOR );\n\t\tfloat R12 = F_Schlick( R0, 1.0, cosTheta1 );\n\t\tfloat T121 = 1.0 - R12;\n\t\tfloat phi12 = 0.0;\n\t\tif ( iridescenceIOR < outsideIOR ) phi12 = PI;\n\t\tfloat phi21 = PI - phi12;\n\t\tvec3 baseIOR = Fresnel0ToIor( clamp( baseF0, 0.0, 0.9999 ) );\t\tvec3 R1 = IorToFresnel0( baseIOR, iridescenceIOR );\n\t\tvec3 R23 = F_Schlick( R1, 1.0, cosTheta2 );\n\t\tvec3 phi23 = vec3( 0.0 );\n\t\tif ( baseIOR[ 0 ] < iridescenceIOR ) phi23[ 0 ] = PI;\n\t\tif ( baseIOR[ 1 ] < iridescenceIOR ) phi23[ 1 ] = PI;\n\t\tif ( baseIOR[ 2 ] < iridescenceIOR ) phi23[ 2 ] = PI;\n\t\tfloat OPD = 2.0 * iridescenceIOR * thinFilmThickness * cosTheta2;\n\t\tvec3 phi = vec3( phi21 ) + phi23;\n\t\tvec3 R123 = clamp( R12 * R23, 1e-5, 0.9999 );\n\t\tvec3 r123 = sqrt( R123 );\n\t\tvec3 Rs = pow2( T121 ) * R23 / ( vec3( 1.0 ) - R123 );\n\t\tvec3 C0 = R12 + Rs;\n\t\tI = C0;\n\t\tvec3 Cm = Rs - T121;\n\t\tfor ( int m = 1; m <= 2; ++ m ) {\n\t\t\tCm *= r123;\n\t\t\tvec3 Sm = 2.0 * evalSensitivity( float( m ) * OPD, float( m ) * phi );\n\t\t\tI += Cm * Sm;\n\t\t}\n\t\treturn max( I, vec3( 0.0 ) );\n\t}\n#endif"; - -var bumpmap_pars_fragment = "#ifdef USE_BUMPMAP\n\tuniform sampler2D bumpMap;\n\tuniform float bumpScale;\n\tvec2 dHdxy_fwd() {\n\t\tvec2 dSTdx = dFdx( vBumpMapUv );\n\t\tvec2 dSTdy = dFdy( vBumpMapUv );\n\t\tfloat Hll = bumpScale * texture2D( bumpMap, vBumpMapUv ).x;\n\t\tfloat dBx = bumpScale * texture2D( bumpMap, vBumpMapUv + dSTdx ).x - Hll;\n\t\tfloat dBy = bumpScale * texture2D( bumpMap, vBumpMapUv + dSTdy ).x - Hll;\n\t\treturn vec2( dBx, dBy );\n\t}\n\tvec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy, float faceDirection ) {\n\t\tvec3 vSigmaX = normalize( dFdx( surf_pos.xyz ) );\n\t\tvec3 vSigmaY = normalize( dFdy( surf_pos.xyz ) );\n\t\tvec3 vN = surf_norm;\n\t\tvec3 R1 = cross( vSigmaY, vN );\n\t\tvec3 R2 = cross( vN, vSigmaX );\n\t\tfloat fDet = dot( vSigmaX, R1 ) * faceDirection;\n\t\tvec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );\n\t\treturn normalize( abs( fDet ) * surf_norm - vGrad );\n\t}\n#endif"; - -var clipping_planes_fragment = "#if NUM_CLIPPING_PLANES > 0\n\tvec4 plane;\n\t#ifdef ALPHA_TO_COVERAGE\n\t\tfloat distanceToPlane, distanceGradient;\n\t\tfloat clipOpacity = 1.0;\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < UNION_CLIPPING_PLANES; i ++ ) {\n\t\t\tplane = clippingPlanes[ i ];\n\t\t\tdistanceToPlane = - dot( vClipPosition, plane.xyz ) + plane.w;\n\t\t\tdistanceGradient = fwidth( distanceToPlane ) / 2.0;\n\t\t\tclipOpacity *= smoothstep( - distanceGradient, distanceGradient, distanceToPlane );\n\t\t\tif ( clipOpacity == 0.0 ) discard;\n\t\t}\n\t\t#pragma unroll_loop_end\n\t\t#if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES\n\t\t\tfloat unionClipOpacity = 1.0;\n\t\t\t#pragma unroll_loop_start\n\t\t\tfor ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; i ++ ) {\n\t\t\t\tplane = clippingPlanes[ i ];\n\t\t\t\tdistanceToPlane = - dot( vClipPosition, plane.xyz ) + plane.w;\n\t\t\t\tdistanceGradient = fwidth( distanceToPlane ) / 2.0;\n\t\t\t\tunionClipOpacity *= 1.0 - smoothstep( - distanceGradient, distanceGradient, distanceToPlane );\n\t\t\t}\n\t\t\t#pragma unroll_loop_end\n\t\t\tclipOpacity *= 1.0 - unionClipOpacity;\n\t\t#endif\n\t\tdiffuseColor.a *= clipOpacity;\n\t\tif ( diffuseColor.a == 0.0 ) discard;\n\t#else\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < UNION_CLIPPING_PLANES; i ++ ) {\n\t\t\tplane = clippingPlanes[ i ];\n\t\t\tif ( dot( vClipPosition, plane.xyz ) > plane.w ) discard;\n\t\t}\n\t\t#pragma unroll_loop_end\n\t\t#if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES\n\t\t\tbool clipped = true;\n\t\t\t#pragma unroll_loop_start\n\t\t\tfor ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; i ++ ) {\n\t\t\t\tplane = clippingPlanes[ i ];\n\t\t\t\tclipped = ( dot( vClipPosition, plane.xyz ) > plane.w ) && clipped;\n\t\t\t}\n\t\t\t#pragma unroll_loop_end\n\t\t\tif ( clipped ) discard;\n\t\t#endif\n\t#endif\n#endif"; - -var clipping_planes_pars_fragment = "#if NUM_CLIPPING_PLANES > 0\n\tvarying vec3 vClipPosition;\n\tuniform vec4 clippingPlanes[ NUM_CLIPPING_PLANES ];\n#endif"; - -var clipping_planes_pars_vertex = "#if NUM_CLIPPING_PLANES > 0\n\tvarying vec3 vClipPosition;\n#endif"; - -var clipping_planes_vertex = "#if NUM_CLIPPING_PLANES > 0\n\tvClipPosition = - mvPosition.xyz;\n#endif"; - -var color_fragment = "#if defined( USE_COLOR_ALPHA )\n\tdiffuseColor *= vColor;\n#elif defined( USE_COLOR )\n\tdiffuseColor.rgb *= vColor;\n#endif"; - -var color_pars_fragment = "#if defined( USE_COLOR_ALPHA )\n\tvarying vec4 vColor;\n#elif defined( USE_COLOR )\n\tvarying vec3 vColor;\n#endif"; - -var color_pars_vertex = "#if defined( USE_COLOR_ALPHA )\n\tvarying vec4 vColor;\n#elif defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR )\n\tvarying vec3 vColor;\n#endif"; - -var color_vertex = "#if defined( USE_COLOR_ALPHA )\n\tvColor = vec4( 1.0 );\n#elif defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR )\n\tvColor = vec3( 1.0 );\n#endif\n#ifdef USE_COLOR\n\tvColor *= color;\n#endif\n#ifdef USE_INSTANCING_COLOR\n\tvColor.xyz *= instanceColor.xyz;\n#endif"; - -var common = "#define PI 3.141592653589793\n#define PI2 6.283185307179586\n#define PI_HALF 1.5707963267948966\n#define RECIPROCAL_PI 0.3183098861837907\n#define RECIPROCAL_PI2 0.15915494309189535\n#define EPSILON 1e-6\n#ifndef saturate\n#define saturate( a ) clamp( a, 0.0, 1.0 )\n#endif\n#define whiteComplement( a ) ( 1.0 - saturate( a ) )\nfloat pow2( const in float x ) { return x*x; }\nvec3 pow2( const in vec3 x ) { return x*x; }\nfloat pow3( const in float x ) { return x*x*x; }\nfloat pow4( const in float x ) { float x2 = x*x; return x2*x2; }\nfloat max3( const in vec3 v ) { return max( max( v.x, v.y ), v.z ); }\nfloat average( const in vec3 v ) { return dot( v, vec3( 0.3333333 ) ); }\nhighp float rand( const in vec2 uv ) {\n\tconst highp float a = 12.9898, b = 78.233, c = 43758.5453;\n\thighp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI );\n\treturn fract( sin( sn ) * c );\n}\n#ifdef HIGH_PRECISION\n\tfloat precisionSafeLength( vec3 v ) { return length( v ); }\n#else\n\tfloat precisionSafeLength( vec3 v ) {\n\t\tfloat maxComponent = max3( abs( v ) );\n\t\treturn length( v / maxComponent ) * maxComponent;\n\t}\n#endif\nstruct IncidentLight {\n\tvec3 color;\n\tvec3 direction;\n\tbool visible;\n};\nstruct ReflectedLight {\n\tvec3 directDiffuse;\n\tvec3 directSpecular;\n\tvec3 indirectDiffuse;\n\tvec3 indirectSpecular;\n};\n#ifdef USE_ALPHAHASH\n\tvarying vec3 vPosition;\n#endif\nvec3 transformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );\n}\nvec3 inverseTransformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( vec4( dir, 0.0 ) * matrix ).xyz );\n}\nmat3 transposeMat3( const in mat3 m ) {\n\tmat3 tmp;\n\ttmp[ 0 ] = vec3( m[ 0 ].x, m[ 1 ].x, m[ 2 ].x );\n\ttmp[ 1 ] = vec3( m[ 0 ].y, m[ 1 ].y, m[ 2 ].y );\n\ttmp[ 2 ] = vec3( m[ 0 ].z, m[ 1 ].z, m[ 2 ].z );\n\treturn tmp;\n}\nfloat luminance( const in vec3 rgb ) {\n\tconst vec3 weights = vec3( 0.2126729, 0.7151522, 0.0721750 );\n\treturn dot( weights, rgb );\n}\nbool isPerspectiveMatrix( mat4 m ) {\n\treturn m[ 2 ][ 3 ] == - 1.0;\n}\nvec2 equirectUv( in vec3 dir ) {\n\tfloat u = atan( dir.z, dir.x ) * RECIPROCAL_PI2 + 0.5;\n\tfloat v = asin( clamp( dir.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;\n\treturn vec2( u, v );\n}\nvec3 BRDF_Lambert( const in vec3 diffuseColor ) {\n\treturn RECIPROCAL_PI * diffuseColor;\n}\nvec3 F_Schlick( const in vec3 f0, const in float f90, const in float dotVH ) {\n\tfloat fresnel = exp2( ( - 5.55473 * dotVH - 6.98316 ) * dotVH );\n\treturn f0 * ( 1.0 - fresnel ) + ( f90 * fresnel );\n}\nfloat F_Schlick( const in float f0, const in float f90, const in float dotVH ) {\n\tfloat fresnel = exp2( ( - 5.55473 * dotVH - 6.98316 ) * dotVH );\n\treturn f0 * ( 1.0 - fresnel ) + ( f90 * fresnel );\n} // validated"; - -var cube_uv_reflection_fragment = "#ifdef ENVMAP_TYPE_CUBE_UV\n\t#define cubeUV_minMipLevel 4.0\n\t#define cubeUV_minTileSize 16.0\n\tfloat getFace( vec3 direction ) {\n\t\tvec3 absDirection = abs( direction );\n\t\tfloat face = - 1.0;\n\t\tif ( absDirection.x > absDirection.z ) {\n\t\t\tif ( absDirection.x > absDirection.y )\n\t\t\t\tface = direction.x > 0.0 ? 0.0 : 3.0;\n\t\t\telse\n\t\t\t\tface = direction.y > 0.0 ? 1.0 : 4.0;\n\t\t} else {\n\t\t\tif ( absDirection.z > absDirection.y )\n\t\t\t\tface = direction.z > 0.0 ? 2.0 : 5.0;\n\t\t\telse\n\t\t\t\tface = direction.y > 0.0 ? 1.0 : 4.0;\n\t\t}\n\t\treturn face;\n\t}\n\tvec2 getUV( vec3 direction, float face ) {\n\t\tvec2 uv;\n\t\tif ( face == 0.0 ) {\n\t\t\tuv = vec2( direction.z, direction.y ) / abs( direction.x );\n\t\t} else if ( face == 1.0 ) {\n\t\t\tuv = vec2( - direction.x, - direction.z ) / abs( direction.y );\n\t\t} else if ( face == 2.0 ) {\n\t\t\tuv = vec2( - direction.x, direction.y ) / abs( direction.z );\n\t\t} else if ( face == 3.0 ) {\n\t\t\tuv = vec2( - direction.z, direction.y ) / abs( direction.x );\n\t\t} else if ( face == 4.0 ) {\n\t\t\tuv = vec2( - direction.x, direction.z ) / abs( direction.y );\n\t\t} else {\n\t\t\tuv = vec2( direction.x, direction.y ) / abs( direction.z );\n\t\t}\n\t\treturn 0.5 * ( uv + 1.0 );\n\t}\n\tvec3 bilinearCubeUV( sampler2D envMap, vec3 direction, float mipInt ) {\n\t\tfloat face = getFace( direction );\n\t\tfloat filterInt = max( cubeUV_minMipLevel - mipInt, 0.0 );\n\t\tmipInt = max( mipInt, cubeUV_minMipLevel );\n\t\tfloat faceSize = exp2( mipInt );\n\t\thighp vec2 uv = getUV( direction, face ) * ( faceSize - 2.0 ) + 1.0;\n\t\tif ( face > 2.0 ) {\n\t\t\tuv.y += faceSize;\n\t\t\tface -= 3.0;\n\t\t}\n\t\tuv.x += face * faceSize;\n\t\tuv.x += filterInt * 3.0 * cubeUV_minTileSize;\n\t\tuv.y += 4.0 * ( exp2( CUBEUV_MAX_MIP ) - faceSize );\n\t\tuv.x *= CUBEUV_TEXEL_WIDTH;\n\t\tuv.y *= CUBEUV_TEXEL_HEIGHT;\n\t\t#ifdef texture2DGradEXT\n\t\t\treturn texture2DGradEXT( envMap, uv, vec2( 0.0 ), vec2( 0.0 ) ).rgb;\n\t\t#else\n\t\t\treturn texture2D( envMap, uv ).rgb;\n\t\t#endif\n\t}\n\t#define cubeUV_r0 1.0\n\t#define cubeUV_m0 - 2.0\n\t#define cubeUV_r1 0.8\n\t#define cubeUV_m1 - 1.0\n\t#define cubeUV_r4 0.4\n\t#define cubeUV_m4 2.0\n\t#define cubeUV_r5 0.305\n\t#define cubeUV_m5 3.0\n\t#define cubeUV_r6 0.21\n\t#define cubeUV_m6 4.0\n\tfloat roughnessToMip( float roughness ) {\n\t\tfloat mip = 0.0;\n\t\tif ( roughness >= cubeUV_r1 ) {\n\t\t\tmip = ( cubeUV_r0 - roughness ) * ( cubeUV_m1 - cubeUV_m0 ) / ( cubeUV_r0 - cubeUV_r1 ) + cubeUV_m0;\n\t\t} else if ( roughness >= cubeUV_r4 ) {\n\t\t\tmip = ( cubeUV_r1 - roughness ) * ( cubeUV_m4 - cubeUV_m1 ) / ( cubeUV_r1 - cubeUV_r4 ) + cubeUV_m1;\n\t\t} else if ( roughness >= cubeUV_r5 ) {\n\t\t\tmip = ( cubeUV_r4 - roughness ) * ( cubeUV_m5 - cubeUV_m4 ) / ( cubeUV_r4 - cubeUV_r5 ) + cubeUV_m4;\n\t\t} else if ( roughness >= cubeUV_r6 ) {\n\t\t\tmip = ( cubeUV_r5 - roughness ) * ( cubeUV_m6 - cubeUV_m5 ) / ( cubeUV_r5 - cubeUV_r6 ) + cubeUV_m5;\n\t\t} else {\n\t\t\tmip = - 2.0 * log2( 1.16 * roughness );\t\t}\n\t\treturn mip;\n\t}\n\tvec4 textureCubeUV( sampler2D envMap, vec3 sampleDir, float roughness ) {\n\t\tfloat mip = clamp( roughnessToMip( roughness ), cubeUV_m0, CUBEUV_MAX_MIP );\n\t\tfloat mipF = fract( mip );\n\t\tfloat mipInt = floor( mip );\n\t\tvec3 color0 = bilinearCubeUV( envMap, sampleDir, mipInt );\n\t\tif ( mipF == 0.0 ) {\n\t\t\treturn vec4( color0, 1.0 );\n\t\t} else {\n\t\t\tvec3 color1 = bilinearCubeUV( envMap, sampleDir, mipInt + 1.0 );\n\t\t\treturn vec4( mix( color0, color1, mipF ), 1.0 );\n\t\t}\n\t}\n#endif"; - -var defaultnormal_vertex = "vec3 transformedNormal = objectNormal;\n#ifdef USE_TANGENT\n\tvec3 transformedTangent = objectTangent;\n#endif\n#ifdef USE_BATCHING\n\tmat3 bm = mat3( batchingMatrix );\n\ttransformedNormal /= vec3( dot( bm[ 0 ], bm[ 0 ] ), dot( bm[ 1 ], bm[ 1 ] ), dot( bm[ 2 ], bm[ 2 ] ) );\n\ttransformedNormal = bm * transformedNormal;\n\t#ifdef USE_TANGENT\n\t\ttransformedTangent = bm * transformedTangent;\n\t#endif\n#endif\n#ifdef USE_INSTANCING\n\tmat3 im = mat3( instanceMatrix );\n\ttransformedNormal /= vec3( dot( im[ 0 ], im[ 0 ] ), dot( im[ 1 ], im[ 1 ] ), dot( im[ 2 ], im[ 2 ] ) );\n\ttransformedNormal = im * transformedNormal;\n\t#ifdef USE_TANGENT\n\t\ttransformedTangent = im * transformedTangent;\n\t#endif\n#endif\ntransformedNormal = normalMatrix * transformedNormal;\n#ifdef FLIP_SIDED\n\ttransformedNormal = - transformedNormal;\n#endif\n#ifdef USE_TANGENT\n\ttransformedTangent = ( modelViewMatrix * vec4( transformedTangent, 0.0 ) ).xyz;\n\t#ifdef FLIP_SIDED\n\t\ttransformedTangent = - transformedTangent;\n\t#endif\n#endif"; - -var displacementmap_pars_vertex = "#ifdef USE_DISPLACEMENTMAP\n\tuniform sampler2D displacementMap;\n\tuniform float displacementScale;\n\tuniform float displacementBias;\n#endif"; - -var displacementmap_vertex = "#ifdef USE_DISPLACEMENTMAP\n\ttransformed += normalize( objectNormal ) * ( texture2D( displacementMap, vDisplacementMapUv ).x * displacementScale + displacementBias );\n#endif"; - -var emissivemap_fragment = "#ifdef USE_EMISSIVEMAP\n\tvec4 emissiveColor = texture2D( emissiveMap, vEmissiveMapUv );\n\ttotalEmissiveRadiance *= emissiveColor.rgb;\n#endif"; - -var emissivemap_pars_fragment = "#ifdef USE_EMISSIVEMAP\n\tuniform sampler2D emissiveMap;\n#endif"; - -var colorspace_fragment = "gl_FragColor = linearToOutputTexel( gl_FragColor );"; - -var colorspace_pars_fragment = "\nconst mat3 LINEAR_SRGB_TO_LINEAR_DISPLAY_P3 = mat3(\n\tvec3( 0.8224621, 0.177538, 0.0 ),\n\tvec3( 0.0331941, 0.9668058, 0.0 ),\n\tvec3( 0.0170827, 0.0723974, 0.9105199 )\n);\nconst mat3 LINEAR_DISPLAY_P3_TO_LINEAR_SRGB = mat3(\n\tvec3( 1.2249401, - 0.2249404, 0.0 ),\n\tvec3( - 0.0420569, 1.0420571, 0.0 ),\n\tvec3( - 0.0196376, - 0.0786361, 1.0982735 )\n);\nvec4 LinearSRGBToLinearDisplayP3( in vec4 value ) {\n\treturn vec4( value.rgb * LINEAR_SRGB_TO_LINEAR_DISPLAY_P3, value.a );\n}\nvec4 LinearDisplayP3ToLinearSRGB( in vec4 value ) {\n\treturn vec4( value.rgb * LINEAR_DISPLAY_P3_TO_LINEAR_SRGB, value.a );\n}\nvec4 LinearTransferOETF( in vec4 value ) {\n\treturn value;\n}\nvec4 sRGBTransferOETF( in vec4 value ) {\n\treturn vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.a );\n}\nvec4 LinearToLinear( in vec4 value ) {\n\treturn value;\n}\nvec4 LinearTosRGB( in vec4 value ) {\n\treturn sRGBTransferOETF( value );\n}"; - -var envmap_fragment = "#ifdef USE_ENVMAP\n\t#ifdef ENV_WORLDPOS\n\t\tvec3 cameraToFrag;\n\t\tif ( isOrthographic ) {\n\t\t\tcameraToFrag = normalize( vec3( - viewMatrix[ 0 ][ 2 ], - viewMatrix[ 1 ][ 2 ], - viewMatrix[ 2 ][ 2 ] ) );\n\t\t} else {\n\t\t\tcameraToFrag = normalize( vWorldPosition - cameraPosition );\n\t\t}\n\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvec3 reflectVec = reflect( cameraToFrag, worldNormal );\n\t\t#else\n\t\t\tvec3 reflectVec = refract( cameraToFrag, worldNormal, refractionRatio );\n\t\t#endif\n\t#else\n\t\tvec3 reflectVec = vReflect;\n\t#endif\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tvec4 envColor = textureCube( envMap, vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\n\t#else\n\t\tvec4 envColor = vec4( 0.0 );\n\t#endif\n\t#ifdef ENVMAP_BLENDING_MULTIPLY\n\t\toutgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_MIX )\n\t\toutgoingLight = mix( outgoingLight, envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_ADD )\n\t\toutgoingLight += envColor.xyz * specularStrength * reflectivity;\n\t#endif\n#endif"; - -var envmap_common_pars_fragment = "#ifdef USE_ENVMAP\n\tuniform float envMapIntensity;\n\tuniform float flipEnvMap;\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tuniform samplerCube envMap;\n\t#else\n\t\tuniform sampler2D envMap;\n\t#endif\n\t\n#endif"; - -var envmap_pars_fragment = "#ifdef USE_ENVMAP\n\tuniform float reflectivity;\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) || defined( LAMBERT )\n\t\t#define ENV_WORLDPOS\n\t#endif\n\t#ifdef ENV_WORLDPOS\n\t\tvarying vec3 vWorldPosition;\n\t\tuniform float refractionRatio;\n\t#else\n\t\tvarying vec3 vReflect;\n\t#endif\n#endif"; - -var envmap_pars_vertex = "#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) || defined( LAMBERT )\n\t\t#define ENV_WORLDPOS\n\t#endif\n\t#ifdef ENV_WORLDPOS\n\t\t\n\t\tvarying vec3 vWorldPosition;\n\t#else\n\t\tvarying vec3 vReflect;\n\t\tuniform float refractionRatio;\n\t#endif\n#endif"; - -var envmap_vertex = "#ifdef USE_ENVMAP\n\t#ifdef ENV_WORLDPOS\n\t\tvWorldPosition = worldPosition.xyz;\n\t#else\n\t\tvec3 cameraToVertex;\n\t\tif ( isOrthographic ) {\n\t\t\tcameraToVertex = normalize( vec3( - viewMatrix[ 0 ][ 2 ], - viewMatrix[ 1 ][ 2 ], - viewMatrix[ 2 ][ 2 ] ) );\n\t\t} else {\n\t\t\tcameraToVertex = normalize( worldPosition.xyz - cameraPosition );\n\t\t}\n\t\tvec3 worldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvReflect = reflect( cameraToVertex, worldNormal );\n\t\t#else\n\t\t\tvReflect = refract( cameraToVertex, worldNormal, refractionRatio );\n\t\t#endif\n\t#endif\n#endif"; - -var fog_vertex = "#ifdef USE_FOG\n\tvFogDepth = - mvPosition.z;\n#endif"; - -var fog_pars_vertex = "#ifdef USE_FOG\n\tvarying float vFogDepth;\n#endif"; - -var fog_fragment = "#ifdef USE_FOG\n\t#ifdef FOG_EXP2\n\t\tfloat fogFactor = 1.0 - exp( - fogDensity * fogDensity * vFogDepth * vFogDepth );\n\t#else\n\t\tfloat fogFactor = smoothstep( fogNear, fogFar, vFogDepth );\n\t#endif\n\tgl_FragColor.rgb = mix( gl_FragColor.rgb, fogColor, fogFactor );\n#endif"; - -var fog_pars_fragment = "#ifdef USE_FOG\n\tuniform vec3 fogColor;\n\tvarying float vFogDepth;\n\t#ifdef FOG_EXP2\n\t\tuniform float fogDensity;\n\t#else\n\t\tuniform float fogNear;\n\t\tuniform float fogFar;\n\t#endif\n#endif"; - -var gradientmap_pars_fragment = "#ifdef USE_GRADIENTMAP\n\tuniform sampler2D gradientMap;\n#endif\nvec3 getGradientIrradiance( vec3 normal, vec3 lightDirection ) {\n\tfloat dotNL = dot( normal, lightDirection );\n\tvec2 coord = vec2( dotNL * 0.5 + 0.5, 0.0 );\n\t#ifdef USE_GRADIENTMAP\n\t\treturn vec3( texture2D( gradientMap, coord ).r );\n\t#else\n\t\tvec2 fw = fwidth( coord ) * 0.5;\n\t\treturn mix( vec3( 0.7 ), vec3( 1.0 ), smoothstep( 0.7 - fw.x, 0.7 + fw.x, coord.x ) );\n\t#endif\n}"; - -var lightmap_fragment = "#ifdef USE_LIGHTMAP\n\tvec4 lightMapTexel = texture2D( lightMap, vLightMapUv );\n\tvec3 lightMapIrradiance = lightMapTexel.rgb * lightMapIntensity;\n\treflectedLight.indirectDiffuse += lightMapIrradiance;\n#endif"; - -var lightmap_pars_fragment = "#ifdef USE_LIGHTMAP\n\tuniform sampler2D lightMap;\n\tuniform float lightMapIntensity;\n#endif"; - -var lights_lambert_fragment = "LambertMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularStrength = specularStrength;"; - -var lights_lambert_pars_fragment = "varying vec3 vViewPosition;\nstruct LambertMaterial {\n\tvec3 diffuseColor;\n\tfloat specularStrength;\n};\nvoid RE_Direct_Lambert( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in LambertMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometryNormal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Lambert( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in LambertMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_Lambert\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Lambert"; - -var lights_pars_begin = "uniform bool receiveShadow;\nuniform vec3 ambientLightColor;\n#if defined( USE_LIGHT_PROBES )\n\tuniform vec3 lightProbe[ 9 ];\n#endif\nvec3 shGetIrradianceAt( in vec3 normal, in vec3 shCoefficients[ 9 ] ) {\n\tfloat x = normal.x, y = normal.y, z = normal.z;\n\tvec3 result = shCoefficients[ 0 ] * 0.886227;\n\tresult += shCoefficients[ 1 ] * 2.0 * 0.511664 * y;\n\tresult += shCoefficients[ 2 ] * 2.0 * 0.511664 * z;\n\tresult += shCoefficients[ 3 ] * 2.0 * 0.511664 * x;\n\tresult += shCoefficients[ 4 ] * 2.0 * 0.429043 * x * y;\n\tresult += shCoefficients[ 5 ] * 2.0 * 0.429043 * y * z;\n\tresult += shCoefficients[ 6 ] * ( 0.743125 * z * z - 0.247708 );\n\tresult += shCoefficients[ 7 ] * 2.0 * 0.429043 * x * z;\n\tresult += shCoefficients[ 8 ] * 0.429043 * ( x * x - y * y );\n\treturn result;\n}\nvec3 getLightProbeIrradiance( const in vec3 lightProbe[ 9 ], const in vec3 normal ) {\n\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\tvec3 irradiance = shGetIrradianceAt( worldNormal, lightProbe );\n\treturn irradiance;\n}\nvec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) {\n\tvec3 irradiance = ambientLightColor;\n\treturn irradiance;\n}\nfloat getDistanceAttenuation( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) {\n\t#if defined ( LEGACY_LIGHTS )\n\t\tif ( cutoffDistance > 0.0 && decayExponent > 0.0 ) {\n\t\t\treturn pow( saturate( - lightDistance / cutoffDistance + 1.0 ), decayExponent );\n\t\t}\n\t\treturn 1.0;\n\t#else\n\t\tfloat distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 );\n\t\tif ( cutoffDistance > 0.0 ) {\n\t\t\tdistanceFalloff *= pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );\n\t\t}\n\t\treturn distanceFalloff;\n\t#endif\n}\nfloat getSpotAttenuation( const in float coneCosine, const in float penumbraCosine, const in float angleCosine ) {\n\treturn smoothstep( coneCosine, penumbraCosine, angleCosine );\n}\n#if NUM_DIR_LIGHTS > 0\n\tstruct DirectionalLight {\n\t\tvec3 direction;\n\t\tvec3 color;\n\t};\n\tuniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ];\n\tvoid getDirectionalLightInfo( const in DirectionalLight directionalLight, out IncidentLight light ) {\n\t\tlight.color = directionalLight.color;\n\t\tlight.direction = directionalLight.direction;\n\t\tlight.visible = true;\n\t}\n#endif\n#if NUM_POINT_LIGHTS > 0\n\tstruct PointLight {\n\t\tvec3 position;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t};\n\tuniform PointLight pointLights[ NUM_POINT_LIGHTS ];\n\tvoid getPointLightInfo( const in PointLight pointLight, const in vec3 geometryPosition, out IncidentLight light ) {\n\t\tvec3 lVector = pointLight.position - geometryPosition;\n\t\tlight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tlight.color = pointLight.color;\n\t\tlight.color *= getDistanceAttenuation( lightDistance, pointLight.distance, pointLight.decay );\n\t\tlight.visible = ( light.color != vec3( 0.0 ) );\n\t}\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\tstruct SpotLight {\n\t\tvec3 position;\n\t\tvec3 direction;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t\tfloat coneCos;\n\t\tfloat penumbraCos;\n\t};\n\tuniform SpotLight spotLights[ NUM_SPOT_LIGHTS ];\n\tvoid getSpotLightInfo( const in SpotLight spotLight, const in vec3 geometryPosition, out IncidentLight light ) {\n\t\tvec3 lVector = spotLight.position - geometryPosition;\n\t\tlight.direction = normalize( lVector );\n\t\tfloat angleCos = dot( light.direction, spotLight.direction );\n\t\tfloat spotAttenuation = getSpotAttenuation( spotLight.coneCos, spotLight.penumbraCos, angleCos );\n\t\tif ( spotAttenuation > 0.0 ) {\n\t\t\tfloat lightDistance = length( lVector );\n\t\t\tlight.color = spotLight.color * spotAttenuation;\n\t\t\tlight.color *= getDistanceAttenuation( lightDistance, spotLight.distance, spotLight.decay );\n\t\t\tlight.visible = ( light.color != vec3( 0.0 ) );\n\t\t} else {\n\t\t\tlight.color = vec3( 0.0 );\n\t\t\tlight.visible = false;\n\t\t}\n\t}\n#endif\n#if NUM_RECT_AREA_LIGHTS > 0\n\tstruct RectAreaLight {\n\t\tvec3 color;\n\t\tvec3 position;\n\t\tvec3 halfWidth;\n\t\tvec3 halfHeight;\n\t};\n\tuniform sampler2D ltc_1;\tuniform sampler2D ltc_2;\n\tuniform RectAreaLight rectAreaLights[ NUM_RECT_AREA_LIGHTS ];\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\tstruct HemisphereLight {\n\t\tvec3 direction;\n\t\tvec3 skyColor;\n\t\tvec3 groundColor;\n\t};\n\tuniform HemisphereLight hemisphereLights[ NUM_HEMI_LIGHTS ];\n\tvec3 getHemisphereLightIrradiance( const in HemisphereLight hemiLight, const in vec3 normal ) {\n\t\tfloat dotNL = dot( normal, hemiLight.direction );\n\t\tfloat hemiDiffuseWeight = 0.5 * dotNL + 0.5;\n\t\tvec3 irradiance = mix( hemiLight.groundColor, hemiLight.skyColor, hemiDiffuseWeight );\n\t\treturn irradiance;\n\t}\n#endif"; - -var envmap_physical_pars_fragment = "#ifdef USE_ENVMAP\n\tvec3 getIBLIrradiance( const in vec3 normal ) {\n\t\t#ifdef ENVMAP_TYPE_CUBE_UV\n\t\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, worldNormal, 1.0 );\n\t\t\treturn PI * envMapColor.rgb * envMapIntensity;\n\t\t#else\n\t\t\treturn vec3( 0.0 );\n\t\t#endif\n\t}\n\tvec3 getIBLRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness ) {\n\t\t#ifdef ENVMAP_TYPE_CUBE_UV\n\t\t\tvec3 reflectVec = reflect( - viewDir, normal );\n\t\t\treflectVec = normalize( mix( reflectVec, normal, roughness * roughness) );\n\t\t\treflectVec = inverseTransformDirection( reflectVec, viewMatrix );\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, reflectVec, roughness );\n\t\t\treturn envMapColor.rgb * envMapIntensity;\n\t\t#else\n\t\t\treturn vec3( 0.0 );\n\t\t#endif\n\t}\n\t#ifdef USE_ANISOTROPY\n\t\tvec3 getIBLAnisotropyRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness, const in vec3 bitangent, const in float anisotropy ) {\n\t\t\t#ifdef ENVMAP_TYPE_CUBE_UV\n\t\t\t\tvec3 bentNormal = cross( bitangent, viewDir );\n\t\t\t\tbentNormal = normalize( cross( bentNormal, bitangent ) );\n\t\t\t\tbentNormal = normalize( mix( bentNormal, normal, pow2( pow2( 1.0 - anisotropy * ( 1.0 - roughness ) ) ) ) );\n\t\t\t\treturn getIBLRadiance( viewDir, bentNormal, roughness );\n\t\t\t#else\n\t\t\t\treturn vec3( 0.0 );\n\t\t\t#endif\n\t\t}\n\t#endif\n#endif"; - -var lights_toon_fragment = "ToonMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;"; - -var lights_toon_pars_fragment = "varying vec3 vViewPosition;\nstruct ToonMaterial {\n\tvec3 diffuseColor;\n};\nvoid RE_Direct_Toon( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in ToonMaterial material, inout ReflectedLight reflectedLight ) {\n\tvec3 irradiance = getGradientIrradiance( geometryNormal, directLight.direction ) * directLight.color;\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Toon( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in ToonMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_Toon\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Toon"; - -var lights_phong_fragment = "BlinnPhongMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularColor = specular;\nmaterial.specularShininess = shininess;\nmaterial.specularStrength = specularStrength;"; - -var lights_phong_pars_fragment = "varying vec3 vViewPosition;\nstruct BlinnPhongMaterial {\n\tvec3 diffuseColor;\n\tvec3 specularColor;\n\tfloat specularShininess;\n\tfloat specularStrength;\n};\nvoid RE_Direct_BlinnPhong( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometryNormal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n\treflectedLight.directSpecular += irradiance * BRDF_BlinnPhong( directLight.direction, geometryViewDir, geometryNormal, material.specularColor, material.specularShininess ) * material.specularStrength;\n}\nvoid RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_BlinnPhong\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_BlinnPhong"; - -var lights_physical_fragment = "PhysicalMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb * ( 1.0 - metalnessFactor );\nvec3 dxy = max( abs( dFdx( nonPerturbedNormal ) ), abs( dFdy( nonPerturbedNormal ) ) );\nfloat geometryRoughness = max( max( dxy.x, dxy.y ), dxy.z );\nmaterial.roughness = max( roughnessFactor, 0.0525 );material.roughness += geometryRoughness;\nmaterial.roughness = min( material.roughness, 1.0 );\n#ifdef IOR\n\tmaterial.ior = ior;\n\t#ifdef USE_SPECULAR\n\t\tfloat specularIntensityFactor = specularIntensity;\n\t\tvec3 specularColorFactor = specularColor;\n\t\t#ifdef USE_SPECULAR_COLORMAP\n\t\t\tspecularColorFactor *= texture2D( specularColorMap, vSpecularColorMapUv ).rgb;\n\t\t#endif\n\t\t#ifdef USE_SPECULAR_INTENSITYMAP\n\t\t\tspecularIntensityFactor *= texture2D( specularIntensityMap, vSpecularIntensityMapUv ).a;\n\t\t#endif\n\t\tmaterial.specularF90 = mix( specularIntensityFactor, 1.0, metalnessFactor );\n\t#else\n\t\tfloat specularIntensityFactor = 1.0;\n\t\tvec3 specularColorFactor = vec3( 1.0 );\n\t\tmaterial.specularF90 = 1.0;\n\t#endif\n\tmaterial.specularColor = mix( min( pow2( ( material.ior - 1.0 ) / ( material.ior + 1.0 ) ) * specularColorFactor, vec3( 1.0 ) ) * specularIntensityFactor, diffuseColor.rgb, metalnessFactor );\n#else\n\tmaterial.specularColor = mix( vec3( 0.04 ), diffuseColor.rgb, metalnessFactor );\n\tmaterial.specularF90 = 1.0;\n#endif\n#ifdef USE_CLEARCOAT\n\tmaterial.clearcoat = clearcoat;\n\tmaterial.clearcoatRoughness = clearcoatRoughness;\n\tmaterial.clearcoatF0 = vec3( 0.04 );\n\tmaterial.clearcoatF90 = 1.0;\n\t#ifdef USE_CLEARCOATMAP\n\t\tmaterial.clearcoat *= texture2D( clearcoatMap, vClearcoatMapUv ).x;\n\t#endif\n\t#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\t\tmaterial.clearcoatRoughness *= texture2D( clearcoatRoughnessMap, vClearcoatRoughnessMapUv ).y;\n\t#endif\n\tmaterial.clearcoat = saturate( material.clearcoat );\tmaterial.clearcoatRoughness = max( material.clearcoatRoughness, 0.0525 );\n\tmaterial.clearcoatRoughness += geometryRoughness;\n\tmaterial.clearcoatRoughness = min( material.clearcoatRoughness, 1.0 );\n#endif\n#ifdef USE_IRIDESCENCE\n\tmaterial.iridescence = iridescence;\n\tmaterial.iridescenceIOR = iridescenceIOR;\n\t#ifdef USE_IRIDESCENCEMAP\n\t\tmaterial.iridescence *= texture2D( iridescenceMap, vIridescenceMapUv ).r;\n\t#endif\n\t#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\t\tmaterial.iridescenceThickness = (iridescenceThicknessMaximum - iridescenceThicknessMinimum) * texture2D( iridescenceThicknessMap, vIridescenceThicknessMapUv ).g + iridescenceThicknessMinimum;\n\t#else\n\t\tmaterial.iridescenceThickness = iridescenceThicknessMaximum;\n\t#endif\n#endif\n#ifdef USE_SHEEN\n\tmaterial.sheenColor = sheenColor;\n\t#ifdef USE_SHEEN_COLORMAP\n\t\tmaterial.sheenColor *= texture2D( sheenColorMap, vSheenColorMapUv ).rgb;\n\t#endif\n\tmaterial.sheenRoughness = clamp( sheenRoughness, 0.07, 1.0 );\n\t#ifdef USE_SHEEN_ROUGHNESSMAP\n\t\tmaterial.sheenRoughness *= texture2D( sheenRoughnessMap, vSheenRoughnessMapUv ).a;\n\t#endif\n#endif\n#ifdef USE_ANISOTROPY\n\t#ifdef USE_ANISOTROPYMAP\n\t\tmat2 anisotropyMat = mat2( anisotropyVector.x, anisotropyVector.y, - anisotropyVector.y, anisotropyVector.x );\n\t\tvec3 anisotropyPolar = texture2D( anisotropyMap, vAnisotropyMapUv ).rgb;\n\t\tvec2 anisotropyV = anisotropyMat * normalize( 2.0 * anisotropyPolar.rg - vec2( 1.0 ) ) * anisotropyPolar.b;\n\t#else\n\t\tvec2 anisotropyV = anisotropyVector;\n\t#endif\n\tmaterial.anisotropy = length( anisotropyV );\n\tif( material.anisotropy == 0.0 ) {\n\t\tanisotropyV = vec2( 1.0, 0.0 );\n\t} else {\n\t\tanisotropyV /= material.anisotropy;\n\t\tmaterial.anisotropy = saturate( material.anisotropy );\n\t}\n\tmaterial.alphaT = mix( pow2( material.roughness ), 1.0, pow2( material.anisotropy ) );\n\tmaterial.anisotropyT = tbn[ 0 ] * anisotropyV.x + tbn[ 1 ] * anisotropyV.y;\n\tmaterial.anisotropyB = tbn[ 1 ] * anisotropyV.x - tbn[ 0 ] * anisotropyV.y;\n#endif"; - -var lights_physical_pars_fragment = "struct PhysicalMaterial {\n\tvec3 diffuseColor;\n\tfloat roughness;\n\tvec3 specularColor;\n\tfloat specularF90;\n\t#ifdef USE_CLEARCOAT\n\t\tfloat clearcoat;\n\t\tfloat clearcoatRoughness;\n\t\tvec3 clearcoatF0;\n\t\tfloat clearcoatF90;\n\t#endif\n\t#ifdef USE_IRIDESCENCE\n\t\tfloat iridescence;\n\t\tfloat iridescenceIOR;\n\t\tfloat iridescenceThickness;\n\t\tvec3 iridescenceFresnel;\n\t\tvec3 iridescenceF0;\n\t#endif\n\t#ifdef USE_SHEEN\n\t\tvec3 sheenColor;\n\t\tfloat sheenRoughness;\n\t#endif\n\t#ifdef IOR\n\t\tfloat ior;\n\t#endif\n\t#ifdef USE_TRANSMISSION\n\t\tfloat transmission;\n\t\tfloat transmissionAlpha;\n\t\tfloat thickness;\n\t\tfloat attenuationDistance;\n\t\tvec3 attenuationColor;\n\t#endif\n\t#ifdef USE_ANISOTROPY\n\t\tfloat anisotropy;\n\t\tfloat alphaT;\n\t\tvec3 anisotropyT;\n\t\tvec3 anisotropyB;\n\t#endif\n};\nvec3 clearcoatSpecularDirect = vec3( 0.0 );\nvec3 clearcoatSpecularIndirect = vec3( 0.0 );\nvec3 sheenSpecularDirect = vec3( 0.0 );\nvec3 sheenSpecularIndirect = vec3(0.0 );\nvec3 Schlick_to_F0( const in vec3 f, const in float f90, const in float dotVH ) {\n float x = clamp( 1.0 - dotVH, 0.0, 1.0 );\n float x2 = x * x;\n float x5 = clamp( x * x2 * x2, 0.0, 0.9999 );\n return ( f - vec3( f90 ) * x5 ) / ( 1.0 - x5 );\n}\nfloat V_GGX_SmithCorrelated( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\tfloat gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\treturn 0.5 / max( gv + gl, EPSILON );\n}\nfloat D_GGX( const in float alpha, const in float dotNH ) {\n\tfloat a2 = pow2( alpha );\n\tfloat denom = pow2( dotNH ) * ( a2 - 1.0 ) + 1.0;\n\treturn RECIPROCAL_PI * a2 / pow2( denom );\n}\n#ifdef USE_ANISOTROPY\n\tfloat V_GGX_SmithCorrelated_Anisotropic( const in float alphaT, const in float alphaB, const in float dotTV, const in float dotBV, const in float dotTL, const in float dotBL, const in float dotNV, const in float dotNL ) {\n\t\tfloat gv = dotNL * length( vec3( alphaT * dotTV, alphaB * dotBV, dotNV ) );\n\t\tfloat gl = dotNV * length( vec3( alphaT * dotTL, alphaB * dotBL, dotNL ) );\n\t\tfloat v = 0.5 / ( gv + gl );\n\t\treturn saturate(v);\n\t}\n\tfloat D_GGX_Anisotropic( const in float alphaT, const in float alphaB, const in float dotNH, const in float dotTH, const in float dotBH ) {\n\t\tfloat a2 = alphaT * alphaB;\n\t\thighp vec3 v = vec3( alphaB * dotTH, alphaT * dotBH, a2 * dotNH );\n\t\thighp float v2 = dot( v, v );\n\t\tfloat w2 = a2 / v2;\n\t\treturn RECIPROCAL_PI * a2 * pow2 ( w2 );\n\t}\n#endif\n#ifdef USE_CLEARCOAT\n\tvec3 BRDF_GGX_Clearcoat( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in PhysicalMaterial material) {\n\t\tvec3 f0 = material.clearcoatF0;\n\t\tfloat f90 = material.clearcoatF90;\n\t\tfloat roughness = material.clearcoatRoughness;\n\t\tfloat alpha = pow2( roughness );\n\t\tvec3 halfDir = normalize( lightDir + viewDir );\n\t\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\t\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\t\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\t\tfloat dotVH = saturate( dot( viewDir, halfDir ) );\n\t\tvec3 F = F_Schlick( f0, f90, dotVH );\n\t\tfloat V = V_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\t\tfloat D = D_GGX( alpha, dotNH );\n\t\treturn F * ( V * D );\n\t}\n#endif\nvec3 BRDF_GGX( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in PhysicalMaterial material ) {\n\tvec3 f0 = material.specularColor;\n\tfloat f90 = material.specularF90;\n\tfloat roughness = material.roughness;\n\tfloat alpha = pow2( roughness );\n\tvec3 halfDir = normalize( lightDir + viewDir );\n\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat dotVH = saturate( dot( viewDir, halfDir ) );\n\tvec3 F = F_Schlick( f0, f90, dotVH );\n\t#ifdef USE_IRIDESCENCE\n\t\tF = mix( F, material.iridescenceFresnel, material.iridescence );\n\t#endif\n\t#ifdef USE_ANISOTROPY\n\t\tfloat dotTL = dot( material.anisotropyT, lightDir );\n\t\tfloat dotTV = dot( material.anisotropyT, viewDir );\n\t\tfloat dotTH = dot( material.anisotropyT, halfDir );\n\t\tfloat dotBL = dot( material.anisotropyB, lightDir );\n\t\tfloat dotBV = dot( material.anisotropyB, viewDir );\n\t\tfloat dotBH = dot( material.anisotropyB, halfDir );\n\t\tfloat V = V_GGX_SmithCorrelated_Anisotropic( material.alphaT, alpha, dotTV, dotBV, dotTL, dotBL, dotNV, dotNL );\n\t\tfloat D = D_GGX_Anisotropic( material.alphaT, alpha, dotNH, dotTH, dotBH );\n\t#else\n\t\tfloat V = V_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\t\tfloat D = D_GGX( alpha, dotNH );\n\t#endif\n\treturn F * ( V * D );\n}\nvec2 LTC_Uv( const in vec3 N, const in vec3 V, const in float roughness ) {\n\tconst float LUT_SIZE = 64.0;\n\tconst float LUT_SCALE = ( LUT_SIZE - 1.0 ) / LUT_SIZE;\n\tconst float LUT_BIAS = 0.5 / LUT_SIZE;\n\tfloat dotNV = saturate( dot( N, V ) );\n\tvec2 uv = vec2( roughness, sqrt( 1.0 - dotNV ) );\n\tuv = uv * LUT_SCALE + LUT_BIAS;\n\treturn uv;\n}\nfloat LTC_ClippedSphereFormFactor( const in vec3 f ) {\n\tfloat l = length( f );\n\treturn max( ( l * l + f.z ) / ( l + 1.0 ), 0.0 );\n}\nvec3 LTC_EdgeVectorFormFactor( const in vec3 v1, const in vec3 v2 ) {\n\tfloat x = dot( v1, v2 );\n\tfloat y = abs( x );\n\tfloat a = 0.8543985 + ( 0.4965155 + 0.0145206 * y ) * y;\n\tfloat b = 3.4175940 + ( 4.1616724 + y ) * y;\n\tfloat v = a / b;\n\tfloat theta_sintheta = ( x > 0.0 ) ? v : 0.5 * inversesqrt( max( 1.0 - x * x, 1e-7 ) ) - v;\n\treturn cross( v1, v2 ) * theta_sintheta;\n}\nvec3 LTC_Evaluate( const in vec3 N, const in vec3 V, const in vec3 P, const in mat3 mInv, const in vec3 rectCoords[ 4 ] ) {\n\tvec3 v1 = rectCoords[ 1 ] - rectCoords[ 0 ];\n\tvec3 v2 = rectCoords[ 3 ] - rectCoords[ 0 ];\n\tvec3 lightNormal = cross( v1, v2 );\n\tif( dot( lightNormal, P - rectCoords[ 0 ] ) < 0.0 ) return vec3( 0.0 );\n\tvec3 T1, T2;\n\tT1 = normalize( V - N * dot( V, N ) );\n\tT2 = - cross( N, T1 );\n\tmat3 mat = mInv * transposeMat3( mat3( T1, T2, N ) );\n\tvec3 coords[ 4 ];\n\tcoords[ 0 ] = mat * ( rectCoords[ 0 ] - P );\n\tcoords[ 1 ] = mat * ( rectCoords[ 1 ] - P );\n\tcoords[ 2 ] = mat * ( rectCoords[ 2 ] - P );\n\tcoords[ 3 ] = mat * ( rectCoords[ 3 ] - P );\n\tcoords[ 0 ] = normalize( coords[ 0 ] );\n\tcoords[ 1 ] = normalize( coords[ 1 ] );\n\tcoords[ 2 ] = normalize( coords[ 2 ] );\n\tcoords[ 3 ] = normalize( coords[ 3 ] );\n\tvec3 vectorFormFactor = vec3( 0.0 );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 0 ], coords[ 1 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 1 ], coords[ 2 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 2 ], coords[ 3 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 3 ], coords[ 0 ] );\n\tfloat result = LTC_ClippedSphereFormFactor( vectorFormFactor );\n\treturn vec3( result );\n}\n#if defined( USE_SHEEN )\nfloat D_Charlie( float roughness, float dotNH ) {\n\tfloat alpha = pow2( roughness );\n\tfloat invAlpha = 1.0 / alpha;\n\tfloat cos2h = dotNH * dotNH;\n\tfloat sin2h = max( 1.0 - cos2h, 0.0078125 );\n\treturn ( 2.0 + invAlpha ) * pow( sin2h, invAlpha * 0.5 ) / ( 2.0 * PI );\n}\nfloat V_Neubelt( float dotNV, float dotNL ) {\n\treturn saturate( 1.0 / ( 4.0 * ( dotNL + dotNV - dotNL * dotNV ) ) );\n}\nvec3 BRDF_Sheen( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, vec3 sheenColor, const in float sheenRoughness ) {\n\tvec3 halfDir = normalize( lightDir + viewDir );\n\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat D = D_Charlie( sheenRoughness, dotNH );\n\tfloat V = V_Neubelt( dotNV, dotNL );\n\treturn sheenColor * ( D * V );\n}\n#endif\nfloat IBLSheenBRDF( const in vec3 normal, const in vec3 viewDir, const in float roughness ) {\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat r2 = roughness * roughness;\n\tfloat a = roughness < 0.25 ? -339.2 * r2 + 161.4 * roughness - 25.9 : -8.48 * r2 + 14.3 * roughness - 9.95;\n\tfloat b = roughness < 0.25 ? 44.0 * r2 - 23.7 * roughness + 3.26 : 1.97 * r2 - 3.27 * roughness + 0.72;\n\tfloat DG = exp( a * dotNV + b ) + ( roughness < 0.25 ? 0.0 : 0.1 * ( roughness - 0.25 ) );\n\treturn saturate( DG * RECIPROCAL_PI );\n}\nvec2 DFGApprox( const in vec3 normal, const in vec3 viewDir, const in float roughness ) {\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tconst vec4 c0 = vec4( - 1, - 0.0275, - 0.572, 0.022 );\n\tconst vec4 c1 = vec4( 1, 0.0425, 1.04, - 0.04 );\n\tvec4 r = roughness * c0 + c1;\n\tfloat a004 = min( r.x * r.x, exp2( - 9.28 * dotNV ) ) * r.x + r.y;\n\tvec2 fab = vec2( - 1.04, 1.04 ) * a004 + r.zw;\n\treturn fab;\n}\nvec3 EnvironmentBRDF( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float roughness ) {\n\tvec2 fab = DFGApprox( normal, viewDir, roughness );\n\treturn specularColor * fab.x + specularF90 * fab.y;\n}\n#ifdef USE_IRIDESCENCE\nvoid computeMultiscatteringIridescence( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float iridescence, const in vec3 iridescenceF0, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter ) {\n#else\nvoid computeMultiscattering( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter ) {\n#endif\n\tvec2 fab = DFGApprox( normal, viewDir, roughness );\n\t#ifdef USE_IRIDESCENCE\n\t\tvec3 Fr = mix( specularColor, iridescenceF0, iridescence );\n\t#else\n\t\tvec3 Fr = specularColor;\n\t#endif\n\tvec3 FssEss = Fr * fab.x + specularF90 * fab.y;\n\tfloat Ess = fab.x + fab.y;\n\tfloat Ems = 1.0 - Ess;\n\tvec3 Favg = Fr + ( 1.0 - Fr ) * 0.047619;\tvec3 Fms = FssEss * Favg / ( 1.0 - Ems * Favg );\n\tsingleScatter += FssEss;\n\tmultiScatter += Fms * Ems;\n}\n#if NUM_RECT_AREA_LIGHTS > 0\n\tvoid RE_Direct_RectArea_Physical( const in RectAreaLight rectAreaLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\t\tvec3 normal = geometryNormal;\n\t\tvec3 viewDir = geometryViewDir;\n\t\tvec3 position = geometryPosition;\n\t\tvec3 lightPos = rectAreaLight.position;\n\t\tvec3 halfWidth = rectAreaLight.halfWidth;\n\t\tvec3 halfHeight = rectAreaLight.halfHeight;\n\t\tvec3 lightColor = rectAreaLight.color;\n\t\tfloat roughness = material.roughness;\n\t\tvec3 rectCoords[ 4 ];\n\t\trectCoords[ 0 ] = lightPos + halfWidth - halfHeight;\t\trectCoords[ 1 ] = lightPos - halfWidth - halfHeight;\n\t\trectCoords[ 2 ] = lightPos - halfWidth + halfHeight;\n\t\trectCoords[ 3 ] = lightPos + halfWidth + halfHeight;\n\t\tvec2 uv = LTC_Uv( normal, viewDir, roughness );\n\t\tvec4 t1 = texture2D( ltc_1, uv );\n\t\tvec4 t2 = texture2D( ltc_2, uv );\n\t\tmat3 mInv = mat3(\n\t\t\tvec3( t1.x, 0, t1.y ),\n\t\t\tvec3( 0, 1, 0 ),\n\t\t\tvec3( t1.z, 0, t1.w )\n\t\t);\n\t\tvec3 fresnel = ( material.specularColor * t2.x + ( vec3( 1.0 ) - material.specularColor ) * t2.y );\n\t\treflectedLight.directSpecular += lightColor * fresnel * LTC_Evaluate( normal, viewDir, position, mInv, rectCoords );\n\t\treflectedLight.directDiffuse += lightColor * material.diffuseColor * LTC_Evaluate( normal, viewDir, position, mat3( 1.0 ), rectCoords );\n\t}\n#endif\nvoid RE_Direct_Physical( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometryNormal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\t#ifdef USE_CLEARCOAT\n\t\tfloat dotNLcc = saturate( dot( geometryClearcoatNormal, directLight.direction ) );\n\t\tvec3 ccIrradiance = dotNLcc * directLight.color;\n\t\tclearcoatSpecularDirect += ccIrradiance * BRDF_GGX_Clearcoat( directLight.direction, geometryViewDir, geometryClearcoatNormal, material );\n\t#endif\n\t#ifdef USE_SHEEN\n\t\tsheenSpecularDirect += irradiance * BRDF_Sheen( directLight.direction, geometryViewDir, geometryNormal, material.sheenColor, material.sheenRoughness );\n\t#endif\n\treflectedLight.directSpecular += irradiance * BRDF_GGX( directLight.direction, geometryViewDir, geometryNormal, material );\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Physical( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 irradiance, const in vec3 clearcoatRadiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight) {\n\t#ifdef USE_CLEARCOAT\n\t\tclearcoatSpecularIndirect += clearcoatRadiance * EnvironmentBRDF( geometryClearcoatNormal, geometryViewDir, material.clearcoatF0, material.clearcoatF90, material.clearcoatRoughness );\n\t#endif\n\t#ifdef USE_SHEEN\n\t\tsheenSpecularIndirect += irradiance * material.sheenColor * IBLSheenBRDF( geometryNormal, geometryViewDir, material.sheenRoughness );\n\t#endif\n\tvec3 singleScattering = vec3( 0.0 );\n\tvec3 multiScattering = vec3( 0.0 );\n\tvec3 cosineWeightedIrradiance = irradiance * RECIPROCAL_PI;\n\t#ifdef USE_IRIDESCENCE\n\t\tcomputeMultiscatteringIridescence( geometryNormal, geometryViewDir, material.specularColor, material.specularF90, material.iridescence, material.iridescenceFresnel, material.roughness, singleScattering, multiScattering );\n\t#else\n\t\tcomputeMultiscattering( geometryNormal, geometryViewDir, material.specularColor, material.specularF90, material.roughness, singleScattering, multiScattering );\n\t#endif\n\tvec3 totalScattering = singleScattering + multiScattering;\n\tvec3 diffuse = material.diffuseColor * ( 1.0 - max( max( totalScattering.r, totalScattering.g ), totalScattering.b ) );\n\treflectedLight.indirectSpecular += radiance * singleScattering;\n\treflectedLight.indirectSpecular += multiScattering * cosineWeightedIrradiance;\n\treflectedLight.indirectDiffuse += diffuse * cosineWeightedIrradiance;\n}\n#define RE_Direct\t\t\t\tRE_Direct_Physical\n#define RE_Direct_RectArea\t\tRE_Direct_RectArea_Physical\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Physical\n#define RE_IndirectSpecular\t\tRE_IndirectSpecular_Physical\nfloat computeSpecularOcclusion( const in float dotNV, const in float ambientOcclusion, const in float roughness ) {\n\treturn saturate( pow( dotNV + ambientOcclusion, exp2( - 16.0 * roughness - 1.0 ) ) - 1.0 + ambientOcclusion );\n}"; - -var lights_fragment_begin = "\nvec3 geometryPosition = - vViewPosition;\nvec3 geometryNormal = normal;\nvec3 geometryViewDir = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( vViewPosition );\nvec3 geometryClearcoatNormal = vec3( 0.0 );\n#ifdef USE_CLEARCOAT\n\tgeometryClearcoatNormal = clearcoatNormal;\n#endif\n#ifdef USE_IRIDESCENCE\n\tfloat dotNVi = saturate( dot( normal, geometryViewDir ) );\n\tif ( material.iridescenceThickness == 0.0 ) {\n\t\tmaterial.iridescence = 0.0;\n\t} else {\n\t\tmaterial.iridescence = saturate( material.iridescence );\n\t}\n\tif ( material.iridescence > 0.0 ) {\n\t\tmaterial.iridescenceFresnel = evalIridescence( 1.0, material.iridescenceIOR, dotNVi, material.iridescenceThickness, material.specularColor );\n\t\tmaterial.iridescenceF0 = Schlick_to_F0( material.iridescenceFresnel, 1.0, dotNVi );\n\t}\n#endif\nIncidentLight directLight;\n#if ( NUM_POINT_LIGHTS > 0 ) && defined( RE_Direct )\n\tPointLight pointLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_POINT_LIGHT_SHADOWS > 0\n\tPointLightShadow pointLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tpointLight = pointLights[ i ];\n\t\tgetPointLightInfo( pointLight, geometryPosition, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_POINT_LIGHT_SHADOWS )\n\t\tpointLightShadow = pointLightShadows[ i ];\n\t\tdirectLight.color *= ( directLight.visible && receiveShadow ) ? getPointShadow( pointShadowMap[ i ], pointLightShadow.shadowMapSize, pointLightShadow.shadowBias, pointLightShadow.shadowRadius, vPointShadowCoord[ i ], pointLightShadow.shadowCameraNear, pointLightShadow.shadowCameraFar ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct )\n\tSpotLight spotLight;\n\tvec4 spotColor;\n\tvec3 spotLightCoord;\n\tbool inSpotLightMap;\n\t#if defined( USE_SHADOWMAP ) && NUM_SPOT_LIGHT_SHADOWS > 0\n\tSpotLightShadow spotLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tspotLight = spotLights[ i ];\n\t\tgetSpotLightInfo( spotLight, geometryPosition, directLight );\n\t\t#if ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS )\n\t\t#define SPOT_LIGHT_MAP_INDEX UNROLLED_LOOP_INDEX\n\t\t#elif ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\t#define SPOT_LIGHT_MAP_INDEX NUM_SPOT_LIGHT_MAPS\n\t\t#else\n\t\t#define SPOT_LIGHT_MAP_INDEX ( UNROLLED_LOOP_INDEX - NUM_SPOT_LIGHT_SHADOWS + NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS )\n\t\t#endif\n\t\t#if ( SPOT_LIGHT_MAP_INDEX < NUM_SPOT_LIGHT_MAPS )\n\t\t\tspotLightCoord = vSpotLightCoord[ i ].xyz / vSpotLightCoord[ i ].w;\n\t\t\tinSpotLightMap = all( lessThan( abs( spotLightCoord * 2. - 1. ), vec3( 1.0 ) ) );\n\t\t\tspotColor = texture2D( spotLightMap[ SPOT_LIGHT_MAP_INDEX ], spotLightCoord.xy );\n\t\t\tdirectLight.color = inSpotLightMap ? directLight.color * spotColor.rgb : directLight.color;\n\t\t#endif\n\t\t#undef SPOT_LIGHT_MAP_INDEX\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\tspotLightShadow = spotLightShadows[ i ];\n\t\tdirectLight.color *= ( directLight.visible && receiveShadow ) ? getShadow( spotShadowMap[ i ], spotLightShadow.shadowMapSize, spotLightShadow.shadowBias, spotLightShadow.shadowRadius, vSpotLightCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_DIR_LIGHTS > 0 ) && defined( RE_Direct )\n\tDirectionalLight directionalLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_DIR_LIGHT_SHADOWS > 0\n\tDirectionalLightShadow directionalLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tdirectionalLight = directionalLights[ i ];\n\t\tgetDirectionalLightInfo( directionalLight, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_DIR_LIGHT_SHADOWS )\n\t\tdirectionalLightShadow = directionalLightShadows[ i ];\n\t\tdirectLight.color *= ( directLight.visible && receiveShadow ) ? getShadow( directionalShadowMap[ i ], directionalLightShadow.shadowMapSize, directionalLightShadow.shadowBias, directionalLightShadow.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_RECT_AREA_LIGHTS > 0 ) && defined( RE_Direct_RectArea )\n\tRectAreaLight rectAreaLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_RECT_AREA_LIGHTS; i ++ ) {\n\t\trectAreaLight = rectAreaLights[ i ];\n\t\tRE_Direct_RectArea( rectAreaLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if defined( RE_IndirectDiffuse )\n\tvec3 iblIrradiance = vec3( 0.0 );\n\tvec3 irradiance = getAmbientLightIrradiance( ambientLightColor );\n\t#if defined( USE_LIGHT_PROBES )\n\t\tirradiance += getLightProbeIrradiance( lightProbe, geometryNormal );\n\t#endif\n\t#if ( NUM_HEMI_LIGHTS > 0 )\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\t\tirradiance += getHemisphereLightIrradiance( hemisphereLights[ i ], geometryNormal );\n\t\t}\n\t\t#pragma unroll_loop_end\n\t#endif\n#endif\n#if defined( RE_IndirectSpecular )\n\tvec3 radiance = vec3( 0.0 );\n\tvec3 clearcoatRadiance = vec3( 0.0 );\n#endif"; - -var lights_fragment_maps = "#if defined( RE_IndirectDiffuse )\n\t#ifdef USE_LIGHTMAP\n\t\tvec4 lightMapTexel = texture2D( lightMap, vLightMapUv );\n\t\tvec3 lightMapIrradiance = lightMapTexel.rgb * lightMapIntensity;\n\t\tirradiance += lightMapIrradiance;\n\t#endif\n\t#if defined( USE_ENVMAP ) && defined( STANDARD ) && defined( ENVMAP_TYPE_CUBE_UV )\n\t\tiblIrradiance += getIBLIrradiance( geometryNormal );\n\t#endif\n#endif\n#if defined( USE_ENVMAP ) && defined( RE_IndirectSpecular )\n\t#ifdef USE_ANISOTROPY\n\t\tradiance += getIBLAnisotropyRadiance( geometryViewDir, geometryNormal, material.roughness, material.anisotropyB, material.anisotropy );\n\t#else\n\t\tradiance += getIBLRadiance( geometryViewDir, geometryNormal, material.roughness );\n\t#endif\n\t#ifdef USE_CLEARCOAT\n\t\tclearcoatRadiance += getIBLRadiance( geometryViewDir, geometryClearcoatNormal, material.clearcoatRoughness );\n\t#endif\n#endif"; - -var lights_fragment_end = "#if defined( RE_IndirectDiffuse )\n\tRE_IndirectDiffuse( irradiance, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n#endif\n#if defined( RE_IndirectSpecular )\n\tRE_IndirectSpecular( radiance, iblIrradiance, clearcoatRadiance, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n#endif"; - -var logdepthbuf_fragment = "#if defined( USE_LOGDEPTHBUF ) && defined( USE_LOGDEPTHBUF_EXT )\n\tgl_FragDepthEXT = vIsPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;\n#endif"; - -var logdepthbuf_pars_fragment = "#if defined( USE_LOGDEPTHBUF ) && defined( USE_LOGDEPTHBUF_EXT )\n\tuniform float logDepthBufFC;\n\tvarying float vFragDepth;\n\tvarying float vIsPerspective;\n#endif"; - -var logdepthbuf_pars_vertex = "#ifdef USE_LOGDEPTHBUF\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvarying float vFragDepth;\n\t\tvarying float vIsPerspective;\n\t#else\n\t\tuniform float logDepthBufFC;\n\t#endif\n#endif"; - -var logdepthbuf_vertex = "#ifdef USE_LOGDEPTHBUF\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvFragDepth = 1.0 + gl_Position.w;\n\t\tvIsPerspective = float( isPerspectiveMatrix( projectionMatrix ) );\n\t#else\n\t\tif ( isPerspectiveMatrix( projectionMatrix ) ) {\n\t\t\tgl_Position.z = log2( max( EPSILON, gl_Position.w + 1.0 ) ) * logDepthBufFC - 1.0;\n\t\t\tgl_Position.z *= gl_Position.w;\n\t\t}\n\t#endif\n#endif"; - -var map_fragment = "#ifdef USE_MAP\n\tvec4 sampledDiffuseColor = texture2D( map, vMapUv );\n\t#ifdef DECODE_VIDEO_TEXTURE\n\t\tsampledDiffuseColor = vec4( mix( pow( sampledDiffuseColor.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), sampledDiffuseColor.rgb * 0.0773993808, vec3( lessThanEqual( sampledDiffuseColor.rgb, vec3( 0.04045 ) ) ) ), sampledDiffuseColor.w );\n\t\n\t#endif\n\tdiffuseColor *= sampledDiffuseColor;\n#endif"; - -var map_pars_fragment = "#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif"; - -var map_particle_fragment = "#if defined( USE_MAP ) || defined( USE_ALPHAMAP )\n\t#if defined( USE_POINTS_UV )\n\t\tvec2 uv = vUv;\n\t#else\n\t\tvec2 uv = ( uvTransform * vec3( gl_PointCoord.x, 1.0 - gl_PointCoord.y, 1 ) ).xy;\n\t#endif\n#endif\n#ifdef USE_MAP\n\tdiffuseColor *= texture2D( map, uv );\n#endif\n#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, uv ).g;\n#endif"; - -var map_particle_pars_fragment = "#if defined( USE_POINTS_UV )\n\tvarying vec2 vUv;\n#else\n\t#if defined( USE_MAP ) || defined( USE_ALPHAMAP )\n\t\tuniform mat3 uvTransform;\n\t#endif\n#endif\n#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif\n#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif"; - -var metalnessmap_fragment = "float metalnessFactor = metalness;\n#ifdef USE_METALNESSMAP\n\tvec4 texelMetalness = texture2D( metalnessMap, vMetalnessMapUv );\n\tmetalnessFactor *= texelMetalness.b;\n#endif"; - -var metalnessmap_pars_fragment = "#ifdef USE_METALNESSMAP\n\tuniform sampler2D metalnessMap;\n#endif"; - -var morphcolor_vertex = "#if defined( USE_MORPHCOLORS ) && defined( MORPHTARGETS_TEXTURE )\n\tvColor *= morphTargetBaseInfluence;\n\tfor ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) {\n\t\t#if defined( USE_COLOR_ALPHA )\n\t\t\tif ( morphTargetInfluences[ i ] != 0.0 ) vColor += getMorph( gl_VertexID, i, 2 ) * morphTargetInfluences[ i ];\n\t\t#elif defined( USE_COLOR )\n\t\t\tif ( morphTargetInfluences[ i ] != 0.0 ) vColor += getMorph( gl_VertexID, i, 2 ).rgb * morphTargetInfluences[ i ];\n\t\t#endif\n\t}\n#endif"; - -var morphnormal_vertex = "#ifdef USE_MORPHNORMALS\n\tobjectNormal *= morphTargetBaseInfluence;\n\t#ifdef MORPHTARGETS_TEXTURE\n\t\tfor ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) {\n\t\t\tif ( morphTargetInfluences[ i ] != 0.0 ) objectNormal += getMorph( gl_VertexID, i, 1 ).xyz * morphTargetInfluences[ i ];\n\t\t}\n\t#else\n\t\tobjectNormal += morphNormal0 * morphTargetInfluences[ 0 ];\n\t\tobjectNormal += morphNormal1 * morphTargetInfluences[ 1 ];\n\t\tobjectNormal += morphNormal2 * morphTargetInfluences[ 2 ];\n\t\tobjectNormal += morphNormal3 * morphTargetInfluences[ 3 ];\n\t#endif\n#endif"; - -var morphtarget_pars_vertex = "#ifdef USE_MORPHTARGETS\n\tuniform float morphTargetBaseInfluence;\n\t#ifdef MORPHTARGETS_TEXTURE\n\t\tuniform float morphTargetInfluences[ MORPHTARGETS_COUNT ];\n\t\tuniform sampler2DArray morphTargetsTexture;\n\t\tuniform ivec2 morphTargetsTextureSize;\n\t\tvec4 getMorph( const in int vertexIndex, const in int morphTargetIndex, const in int offset ) {\n\t\t\tint texelIndex = vertexIndex * MORPHTARGETS_TEXTURE_STRIDE + offset;\n\t\t\tint y = texelIndex / morphTargetsTextureSize.x;\n\t\t\tint x = texelIndex - y * morphTargetsTextureSize.x;\n\t\t\tivec3 morphUV = ivec3( x, y, morphTargetIndex );\n\t\t\treturn texelFetch( morphTargetsTexture, morphUV, 0 );\n\t\t}\n\t#else\n\t\t#ifndef USE_MORPHNORMALS\n\t\t\tuniform float morphTargetInfluences[ 8 ];\n\t\t#else\n\t\t\tuniform float morphTargetInfluences[ 4 ];\n\t\t#endif\n\t#endif\n#endif"; - -var morphtarget_vertex = "#ifdef USE_MORPHTARGETS\n\ttransformed *= morphTargetBaseInfluence;\n\t#ifdef MORPHTARGETS_TEXTURE\n\t\tfor ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) {\n\t\t\tif ( morphTargetInfluences[ i ] != 0.0 ) transformed += getMorph( gl_VertexID, i, 0 ).xyz * morphTargetInfluences[ i ];\n\t\t}\n\t#else\n\t\ttransformed += morphTarget0 * morphTargetInfluences[ 0 ];\n\t\ttransformed += morphTarget1 * morphTargetInfluences[ 1 ];\n\t\ttransformed += morphTarget2 * morphTargetInfluences[ 2 ];\n\t\ttransformed += morphTarget3 * morphTargetInfluences[ 3 ];\n\t\t#ifndef USE_MORPHNORMALS\n\t\t\ttransformed += morphTarget4 * morphTargetInfluences[ 4 ];\n\t\t\ttransformed += morphTarget5 * morphTargetInfluences[ 5 ];\n\t\t\ttransformed += morphTarget6 * morphTargetInfluences[ 6 ];\n\t\t\ttransformed += morphTarget7 * morphTargetInfluences[ 7 ];\n\t\t#endif\n\t#endif\n#endif"; - -var normal_fragment_begin = "float faceDirection = gl_FrontFacing ? 1.0 : - 1.0;\n#ifdef FLAT_SHADED\n\tvec3 fdx = dFdx( vViewPosition );\n\tvec3 fdy = dFdy( vViewPosition );\n\tvec3 normal = normalize( cross( fdx, fdy ) );\n#else\n\tvec3 normal = normalize( vNormal );\n\t#ifdef DOUBLE_SIDED\n\t\tnormal *= faceDirection;\n\t#endif\n#endif\n#if defined( USE_NORMALMAP_TANGENTSPACE ) || defined( USE_CLEARCOAT_NORMALMAP ) || defined( USE_ANISOTROPY )\n\t#ifdef USE_TANGENT\n\t\tmat3 tbn = mat3( normalize( vTangent ), normalize( vBitangent ), normal );\n\t#else\n\t\tmat3 tbn = getTangentFrame( - vViewPosition, normal,\n\t\t#if defined( USE_NORMALMAP )\n\t\t\tvNormalMapUv\n\t\t#elif defined( USE_CLEARCOAT_NORMALMAP )\n\t\t\tvClearcoatNormalMapUv\n\t\t#else\n\t\t\tvUv\n\t\t#endif\n\t\t);\n\t#endif\n\t#if defined( DOUBLE_SIDED ) && ! defined( FLAT_SHADED )\n\t\ttbn[0] *= faceDirection;\n\t\ttbn[1] *= faceDirection;\n\t#endif\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\t#ifdef USE_TANGENT\n\t\tmat3 tbn2 = mat3( normalize( vTangent ), normalize( vBitangent ), normal );\n\t#else\n\t\tmat3 tbn2 = getTangentFrame( - vViewPosition, normal, vClearcoatNormalMapUv );\n\t#endif\n\t#if defined( DOUBLE_SIDED ) && ! defined( FLAT_SHADED )\n\t\ttbn2[0] *= faceDirection;\n\t\ttbn2[1] *= faceDirection;\n\t#endif\n#endif\nvec3 nonPerturbedNormal = normal;"; - -var normal_fragment_maps = "#ifdef USE_NORMALMAP_OBJECTSPACE\n\tnormal = texture2D( normalMap, vNormalMapUv ).xyz * 2.0 - 1.0;\n\t#ifdef FLIP_SIDED\n\t\tnormal = - normal;\n\t#endif\n\t#ifdef DOUBLE_SIDED\n\t\tnormal = normal * faceDirection;\n\t#endif\n\tnormal = normalize( normalMatrix * normal );\n#elif defined( USE_NORMALMAP_TANGENTSPACE )\n\tvec3 mapN = texture2D( normalMap, vNormalMapUv ).xyz * 2.0 - 1.0;\n\tmapN.xy *= normalScale;\n\tnormal = normalize( tbn * mapN );\n#elif defined( USE_BUMPMAP )\n\tnormal = perturbNormalArb( - vViewPosition, normal, dHdxy_fwd(), faceDirection );\n#endif"; - -var normal_pars_fragment = "#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n\t#ifdef USE_TANGENT\n\t\tvarying vec3 vTangent;\n\t\tvarying vec3 vBitangent;\n\t#endif\n#endif"; - -var normal_pars_vertex = "#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n\t#ifdef USE_TANGENT\n\t\tvarying vec3 vTangent;\n\t\tvarying vec3 vBitangent;\n\t#endif\n#endif"; - -var normal_vertex = "#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n\t#ifdef USE_TANGENT\n\t\tvTangent = normalize( transformedTangent );\n\t\tvBitangent = normalize( cross( vNormal, vTangent ) * tangent.w );\n\t#endif\n#endif"; - -var normalmap_pars_fragment = "#ifdef USE_NORMALMAP\n\tuniform sampler2D normalMap;\n\tuniform vec2 normalScale;\n#endif\n#ifdef USE_NORMALMAP_OBJECTSPACE\n\tuniform mat3 normalMatrix;\n#endif\n#if ! defined ( USE_TANGENT ) && ( defined ( USE_NORMALMAP_TANGENTSPACE ) || defined ( USE_CLEARCOAT_NORMALMAP ) || defined( USE_ANISOTROPY ) )\n\tmat3 getTangentFrame( vec3 eye_pos, vec3 surf_norm, vec2 uv ) {\n\t\tvec3 q0 = dFdx( eye_pos.xyz );\n\t\tvec3 q1 = dFdy( eye_pos.xyz );\n\t\tvec2 st0 = dFdx( uv.st );\n\t\tvec2 st1 = dFdy( uv.st );\n\t\tvec3 N = surf_norm;\n\t\tvec3 q1perp = cross( q1, N );\n\t\tvec3 q0perp = cross( N, q0 );\n\t\tvec3 T = q1perp * st0.x + q0perp * st1.x;\n\t\tvec3 B = q1perp * st0.y + q0perp * st1.y;\n\t\tfloat det = max( dot( T, T ), dot( B, B ) );\n\t\tfloat scale = ( det == 0.0 ) ? 0.0 : inversesqrt( det );\n\t\treturn mat3( T * scale, B * scale, N );\n\t}\n#endif"; - -var clearcoat_normal_fragment_begin = "#ifdef USE_CLEARCOAT\n\tvec3 clearcoatNormal = nonPerturbedNormal;\n#endif"; - -var clearcoat_normal_fragment_maps = "#ifdef USE_CLEARCOAT_NORMALMAP\n\tvec3 clearcoatMapN = texture2D( clearcoatNormalMap, vClearcoatNormalMapUv ).xyz * 2.0 - 1.0;\n\tclearcoatMapN.xy *= clearcoatNormalScale;\n\tclearcoatNormal = normalize( tbn2 * clearcoatMapN );\n#endif"; - -var clearcoat_pars_fragment = "#ifdef USE_CLEARCOATMAP\n\tuniform sampler2D clearcoatMap;\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\tuniform sampler2D clearcoatNormalMap;\n\tuniform vec2 clearcoatNormalScale;\n#endif\n#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\tuniform sampler2D clearcoatRoughnessMap;\n#endif"; - -var iridescence_pars_fragment = "#ifdef USE_IRIDESCENCEMAP\n\tuniform sampler2D iridescenceMap;\n#endif\n#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\tuniform sampler2D iridescenceThicknessMap;\n#endif"; - -var opaque_fragment = "#ifdef OPAQUE\ndiffuseColor.a = 1.0;\n#endif\n#ifdef USE_TRANSMISSION\ndiffuseColor.a *= material.transmissionAlpha;\n#endif\ngl_FragColor = vec4( outgoingLight, diffuseColor.a );"; - -var packing = "vec3 packNormalToRGB( const in vec3 normal ) {\n\treturn normalize( normal ) * 0.5 + 0.5;\n}\nvec3 unpackRGBToNormal( const in vec3 rgb ) {\n\treturn 2.0 * rgb.xyz - 1.0;\n}\nconst float PackUpscale = 256. / 255.;const float UnpackDownscale = 255. / 256.;\nconst vec3 PackFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );\nconst vec4 UnpackFactors = UnpackDownscale / vec4( PackFactors, 1. );\nconst float ShiftRight8 = 1. / 256.;\nvec4 packDepthToRGBA( const in float v ) {\n\tvec4 r = vec4( fract( v * PackFactors ), v );\n\tr.yzw -= r.xyz * ShiftRight8;\treturn r * PackUpscale;\n}\nfloat unpackRGBAToDepth( const in vec4 v ) {\n\treturn dot( v, UnpackFactors );\n}\nvec2 packDepthToRG( in highp float v ) {\n\treturn packDepthToRGBA( v ).yx;\n}\nfloat unpackRGToDepth( const in highp vec2 v ) {\n\treturn unpackRGBAToDepth( vec4( v.xy, 0.0, 0.0 ) );\n}\nvec4 pack2HalfToRGBA( vec2 v ) {\n\tvec4 r = vec4( v.x, fract( v.x * 255.0 ), v.y, fract( v.y * 255.0 ) );\n\treturn vec4( r.x - r.y / 255.0, r.y, r.z - r.w / 255.0, r.w );\n}\nvec2 unpackRGBATo2Half( vec4 v ) {\n\treturn vec2( v.x + ( v.y / 255.0 ), v.z + ( v.w / 255.0 ) );\n}\nfloat viewZToOrthographicDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn ( viewZ + near ) / ( near - far );\n}\nfloat orthographicDepthToViewZ( const in float depth, const in float near, const in float far ) {\n\treturn depth * ( near - far ) - near;\n}\nfloat viewZToPerspectiveDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn ( ( near + viewZ ) * far ) / ( ( far - near ) * viewZ );\n}\nfloat perspectiveDepthToViewZ( const in float depth, const in float near, const in float far ) {\n\treturn ( near * far ) / ( ( far - near ) * depth - far );\n}"; - -var premultiplied_alpha_fragment = "#ifdef PREMULTIPLIED_ALPHA\n\tgl_FragColor.rgb *= gl_FragColor.a;\n#endif"; - -var project_vertex = "vec4 mvPosition = vec4( transformed, 1.0 );\n#ifdef USE_BATCHING\n\tmvPosition = batchingMatrix * mvPosition;\n#endif\n#ifdef USE_INSTANCING\n\tmvPosition = instanceMatrix * mvPosition;\n#endif\nmvPosition = modelViewMatrix * mvPosition;\ngl_Position = projectionMatrix * mvPosition;"; - -var dithering_fragment = "#ifdef DITHERING\n\tgl_FragColor.rgb = dithering( gl_FragColor.rgb );\n#endif"; - -var dithering_pars_fragment = "#ifdef DITHERING\n\tvec3 dithering( vec3 color ) {\n\t\tfloat grid_position = rand( gl_FragCoord.xy );\n\t\tvec3 dither_shift_RGB = vec3( 0.25 / 255.0, -0.25 / 255.0, 0.25 / 255.0 );\n\t\tdither_shift_RGB = mix( 2.0 * dither_shift_RGB, -2.0 * dither_shift_RGB, grid_position );\n\t\treturn color + dither_shift_RGB;\n\t}\n#endif"; - -var roughnessmap_fragment = "float roughnessFactor = roughness;\n#ifdef USE_ROUGHNESSMAP\n\tvec4 texelRoughness = texture2D( roughnessMap, vRoughnessMapUv );\n\troughnessFactor *= texelRoughness.g;\n#endif"; - -var roughnessmap_pars_fragment = "#ifdef USE_ROUGHNESSMAP\n\tuniform sampler2D roughnessMap;\n#endif"; - -var shadowmap_pars_fragment = "#if NUM_SPOT_LIGHT_COORDS > 0\n\tvarying vec4 vSpotLightCoord[ NUM_SPOT_LIGHT_COORDS ];\n#endif\n#if NUM_SPOT_LIGHT_MAPS > 0\n\tuniform sampler2D spotLightMap[ NUM_SPOT_LIGHT_MAPS ];\n#endif\n#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D directionalShadowMap[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tstruct DirectionalLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D spotShadowMap[ NUM_SPOT_LIGHT_SHADOWS ];\n\t\tstruct SpotLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D pointShadowMap[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tstruct PointLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t\tfloat shadowCameraNear;\n\t\t\tfloat shadowCameraFar;\n\t\t};\n\t\tuniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ];\n\t#endif\n\tfloat texture2DCompare( sampler2D depths, vec2 uv, float compare ) {\n\t\treturn step( compare, unpackRGBAToDepth( texture2D( depths, uv ) ) );\n\t}\n\tvec2 texture2DDistribution( sampler2D shadow, vec2 uv ) {\n\t\treturn unpackRGBATo2Half( texture2D( shadow, uv ) );\n\t}\n\tfloat VSMShadow (sampler2D shadow, vec2 uv, float compare ){\n\t\tfloat occlusion = 1.0;\n\t\tvec2 distribution = texture2DDistribution( shadow, uv );\n\t\tfloat hard_shadow = step( compare , distribution.x );\n\t\tif (hard_shadow != 1.0 ) {\n\t\t\tfloat distance = compare - distribution.x ;\n\t\t\tfloat variance = max( 0.00000, distribution.y * distribution.y );\n\t\t\tfloat softness_probability = variance / (variance + distance * distance );\t\t\tsoftness_probability = clamp( ( softness_probability - 0.3 ) / ( 0.95 - 0.3 ), 0.0, 1.0 );\t\t\tocclusion = clamp( max( hard_shadow, softness_probability ), 0.0, 1.0 );\n\t\t}\n\t\treturn occlusion;\n\t}\n\tfloat getShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord ) {\n\t\tfloat shadow = 1.0;\n\t\tshadowCoord.xyz /= shadowCoord.w;\n\t\tshadowCoord.z += shadowBias;\n\t\tbool inFrustum = shadowCoord.x >= 0.0 && shadowCoord.x <= 1.0 && shadowCoord.y >= 0.0 && shadowCoord.y <= 1.0;\n\t\tbool frustumTest = inFrustum && shadowCoord.z <= 1.0;\n\t\tif ( frustumTest ) {\n\t\t#if defined( SHADOWMAP_TYPE_PCF )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx0 = - texelSize.x * shadowRadius;\n\t\t\tfloat dy0 = - texelSize.y * shadowRadius;\n\t\t\tfloat dx1 = + texelSize.x * shadowRadius;\n\t\t\tfloat dy1 = + texelSize.y * shadowRadius;\n\t\t\tfloat dx2 = dx0 / 2.0;\n\t\t\tfloat dy2 = dy0 / 2.0;\n\t\t\tfloat dx3 = dx1 / 2.0;\n\t\t\tfloat dy3 = dy1 / 2.0;\n\t\t\tshadow = (\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )\n\t\t\t) * ( 1.0 / 17.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_PCF_SOFT )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx = texelSize.x;\n\t\t\tfloat dy = texelSize.y;\n\t\t\tvec2 uv = shadowCoord.xy;\n\t\t\tvec2 f = fract( uv * shadowMapSize + 0.5 );\n\t\t\tuv -= f * texelSize;\n\t\t\tshadow = (\n\t\t\t\ttexture2DCompare( shadowMap, uv, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + vec2( dx, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + vec2( 0.0, dy ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + texelSize, shadowCoord.z ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( -dx, 0.0 ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 0.0 ), shadowCoord.z ),\n\t\t\t\t\t f.x ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( -dx, dy ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, dy ), shadowCoord.z ),\n\t\t\t\t\t f.x ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( 0.0, -dy ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 0.0, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t f.y ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( dx, -dy ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t f.y ) +\n\t\t\t\tmix( mix( texture2DCompare( shadowMap, uv + vec2( -dx, -dy ), shadowCoord.z ),\n\t\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, -dy ), shadowCoord.z ),\n\t\t\t\t\t\t f.x ),\n\t\t\t\t\t mix( texture2DCompare( shadowMap, uv + vec2( -dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t\t f.x ),\n\t\t\t\t\t f.y )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_VSM )\n\t\t\tshadow = VSMShadow( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#else\n\t\t\tshadow = texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#endif\n\t\t}\n\t\treturn shadow;\n\t}\n\tvec2 cubeToUV( vec3 v, float texelSizeY ) {\n\t\tvec3 absV = abs( v );\n\t\tfloat scaleToCube = 1.0 / max( absV.x, max( absV.y, absV.z ) );\n\t\tabsV *= scaleToCube;\n\t\tv *= scaleToCube * ( 1.0 - 2.0 * texelSizeY );\n\t\tvec2 planar = v.xy;\n\t\tfloat almostATexel = 1.5 * texelSizeY;\n\t\tfloat almostOne = 1.0 - almostATexel;\n\t\tif ( absV.z >= almostOne ) {\n\t\t\tif ( v.z > 0.0 )\n\t\t\t\tplanar.x = 4.0 - v.x;\n\t\t} else if ( absV.x >= almostOne ) {\n\t\t\tfloat signX = sign( v.x );\n\t\t\tplanar.x = v.z * signX + 2.0 * signX;\n\t\t} else if ( absV.y >= almostOne ) {\n\t\t\tfloat signY = sign( v.y );\n\t\t\tplanar.x = v.x + 2.0 * signY + 2.0;\n\t\t\tplanar.y = v.z * signY - 2.0;\n\t\t}\n\t\treturn vec2( 0.125, 0.25 ) * planar + vec2( 0.375, 0.75 );\n\t}\n\tfloat getPointShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord, float shadowCameraNear, float shadowCameraFar ) {\n\t\tvec2 texelSize = vec2( 1.0 ) / ( shadowMapSize * vec2( 4.0, 2.0 ) );\n\t\tvec3 lightToPosition = shadowCoord.xyz;\n\t\tfloat dp = ( length( lightToPosition ) - shadowCameraNear ) / ( shadowCameraFar - shadowCameraNear );\t\tdp += shadowBias;\n\t\tvec3 bd3D = normalize( lightToPosition );\n\t\t#if defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_PCF_SOFT ) || defined( SHADOWMAP_TYPE_VSM )\n\t\t\tvec2 offset = vec2( - 1, 1 ) * shadowRadius * texelSize.y;\n\t\t\treturn (\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxx, texelSize.y ), dp )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#else\n\t\t\treturn texture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp );\n\t\t#endif\n\t}\n#endif"; - -var shadowmap_pars_vertex = "#if NUM_SPOT_LIGHT_COORDS > 0\n\tuniform mat4 spotLightMatrix[ NUM_SPOT_LIGHT_COORDS ];\n\tvarying vec4 vSpotLightCoord[ NUM_SPOT_LIGHT_COORDS ];\n#endif\n#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\tuniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tstruct DirectionalLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t\tstruct SpotLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\tuniform mat4 pointShadowMatrix[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tstruct PointLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t\tfloat shadowCameraNear;\n\t\t\tfloat shadowCameraFar;\n\t\t};\n\t\tuniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ];\n\t#endif\n#endif"; - -var shadowmap_vertex = "#if ( defined( USE_SHADOWMAP ) && ( NUM_DIR_LIGHT_SHADOWS > 0 || NUM_POINT_LIGHT_SHADOWS > 0 ) ) || ( NUM_SPOT_LIGHT_COORDS > 0 )\n\tvec3 shadowWorldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\n\tvec4 shadowWorldPosition;\n#endif\n#if defined( USE_SHADOWMAP )\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {\n\t\t\tshadowWorldPosition = worldPosition + vec4( shadowWorldNormal * directionalLightShadows[ i ].shadowNormalBias, 0 );\n\t\t\tvDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * shadowWorldPosition;\n\t\t}\n\t\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {\n\t\t\tshadowWorldPosition = worldPosition + vec4( shadowWorldNormal * pointLightShadows[ i ].shadowNormalBias, 0 );\n\t\t\tvPointShadowCoord[ i ] = pointShadowMatrix[ i ] * shadowWorldPosition;\n\t\t}\n\t\t#pragma unroll_loop_end\n\t#endif\n#endif\n#if NUM_SPOT_LIGHT_COORDS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHT_COORDS; i ++ ) {\n\t\tshadowWorldPosition = worldPosition;\n\t\t#if ( defined( USE_SHADOWMAP ) && UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\t\tshadowWorldPosition.xyz += shadowWorldNormal * spotLightShadows[ i ].shadowNormalBias;\n\t\t#endif\n\t\tvSpotLightCoord[ i ] = spotLightMatrix[ i ] * shadowWorldPosition;\n\t}\n\t#pragma unroll_loop_end\n#endif"; - -var shadowmask_pars_fragment = "float getShadowMask() {\n\tfloat shadow = 1.0;\n\t#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\tDirectionalLightShadow directionalLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {\n\t\tdirectionalLight = directionalLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\tSpotLightShadow spotLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHT_SHADOWS; i ++ ) {\n\t\tspotLight = spotLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotLightCoord[ i ] ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\tPointLightShadow pointLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {\n\t\tpointLight = pointLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ], pointLight.shadowCameraNear, pointLight.shadowCameraFar ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#endif\n\treturn shadow;\n}"; - -var skinbase_vertex = "#ifdef USE_SKINNING\n\tmat4 boneMatX = getBoneMatrix( skinIndex.x );\n\tmat4 boneMatY = getBoneMatrix( skinIndex.y );\n\tmat4 boneMatZ = getBoneMatrix( skinIndex.z );\n\tmat4 boneMatW = getBoneMatrix( skinIndex.w );\n#endif"; - -var skinning_pars_vertex = "#ifdef USE_SKINNING\n\tuniform mat4 bindMatrix;\n\tuniform mat4 bindMatrixInverse;\n\tuniform highp sampler2D boneTexture;\n\tmat4 getBoneMatrix( const in float i ) {\n\t\tint size = textureSize( boneTexture, 0 ).x;\n\t\tint j = int( i ) * 4;\n\t\tint x = j % size;\n\t\tint y = j / size;\n\t\tvec4 v1 = texelFetch( boneTexture, ivec2( x, y ), 0 );\n\t\tvec4 v2 = texelFetch( boneTexture, ivec2( x + 1, y ), 0 );\n\t\tvec4 v3 = texelFetch( boneTexture, ivec2( x + 2, y ), 0 );\n\t\tvec4 v4 = texelFetch( boneTexture, ivec2( x + 3, y ), 0 );\n\t\treturn mat4( v1, v2, v3, v4 );\n\t}\n#endif"; - -var skinning_vertex = "#ifdef USE_SKINNING\n\tvec4 skinVertex = bindMatrix * vec4( transformed, 1.0 );\n\tvec4 skinned = vec4( 0.0 );\n\tskinned += boneMatX * skinVertex * skinWeight.x;\n\tskinned += boneMatY * skinVertex * skinWeight.y;\n\tskinned += boneMatZ * skinVertex * skinWeight.z;\n\tskinned += boneMatW * skinVertex * skinWeight.w;\n\ttransformed = ( bindMatrixInverse * skinned ).xyz;\n#endif"; - -var skinnormal_vertex = "#ifdef USE_SKINNING\n\tmat4 skinMatrix = mat4( 0.0 );\n\tskinMatrix += skinWeight.x * boneMatX;\n\tskinMatrix += skinWeight.y * boneMatY;\n\tskinMatrix += skinWeight.z * boneMatZ;\n\tskinMatrix += skinWeight.w * boneMatW;\n\tskinMatrix = bindMatrixInverse * skinMatrix * bindMatrix;\n\tobjectNormal = vec4( skinMatrix * vec4( objectNormal, 0.0 ) ).xyz;\n\t#ifdef USE_TANGENT\n\t\tobjectTangent = vec4( skinMatrix * vec4( objectTangent, 0.0 ) ).xyz;\n\t#endif\n#endif"; - -var specularmap_fragment = "float specularStrength;\n#ifdef USE_SPECULARMAP\n\tvec4 texelSpecular = texture2D( specularMap, vSpecularMapUv );\n\tspecularStrength = texelSpecular.r;\n#else\n\tspecularStrength = 1.0;\n#endif"; - -var specularmap_pars_fragment = "#ifdef USE_SPECULARMAP\n\tuniform sampler2D specularMap;\n#endif"; - -var tonemapping_fragment = "#if defined( TONE_MAPPING )\n\tgl_FragColor.rgb = toneMapping( gl_FragColor.rgb );\n#endif"; - -var tonemapping_pars_fragment = "#ifndef saturate\n#define saturate( a ) clamp( a, 0.0, 1.0 )\n#endif\nuniform float toneMappingExposure;\nvec3 LinearToneMapping( vec3 color ) {\n\treturn saturate( toneMappingExposure * color );\n}\nvec3 ReinhardToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\treturn saturate( color / ( vec3( 1.0 ) + color ) );\n}\nvec3 OptimizedCineonToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\tcolor = max( vec3( 0.0 ), color - 0.004 );\n\treturn pow( ( color * ( 6.2 * color + 0.5 ) ) / ( color * ( 6.2 * color + 1.7 ) + 0.06 ), vec3( 2.2 ) );\n}\nvec3 RRTAndODTFit( vec3 v ) {\n\tvec3 a = v * ( v + 0.0245786 ) - 0.000090537;\n\tvec3 b = v * ( 0.983729 * v + 0.4329510 ) + 0.238081;\n\treturn a / b;\n}\nvec3 ACESFilmicToneMapping( vec3 color ) {\n\tconst mat3 ACESInputMat = mat3(\n\t\tvec3( 0.59719, 0.07600, 0.02840 ),\t\tvec3( 0.35458, 0.90834, 0.13383 ),\n\t\tvec3( 0.04823, 0.01566, 0.83777 )\n\t);\n\tconst mat3 ACESOutputMat = mat3(\n\t\tvec3( 1.60475, -0.10208, -0.00327 ),\t\tvec3( -0.53108, 1.10813, -0.07276 ),\n\t\tvec3( -0.07367, -0.00605, 1.07602 )\n\t);\n\tcolor *= toneMappingExposure / 0.6;\n\tcolor = ACESInputMat * color;\n\tcolor = RRTAndODTFit( color );\n\tcolor = ACESOutputMat * color;\n\treturn saturate( color );\n}\nconst mat3 LINEAR_REC2020_TO_LINEAR_SRGB = mat3(\n\tvec3( 1.6605, - 0.1246, - 0.0182 ),\n\tvec3( - 0.5876, 1.1329, - 0.1006 ),\n\tvec3( - 0.0728, - 0.0083, 1.1187 )\n);\nconst mat3 LINEAR_SRGB_TO_LINEAR_REC2020 = mat3(\n\tvec3( 0.6274, 0.0691, 0.0164 ),\n\tvec3( 0.3293, 0.9195, 0.0880 ),\n\tvec3( 0.0433, 0.0113, 0.8956 )\n);\nvec3 agxDefaultContrastApprox( vec3 x ) {\n\tvec3 x2 = x * x;\n\tvec3 x4 = x2 * x2;\n\treturn + 15.5 * x4 * x2\n\t\t- 40.14 * x4 * x\n\t\t+ 31.96 * x4\n\t\t- 6.868 * x2 * x\n\t\t+ 0.4298 * x2\n\t\t+ 0.1191 * x\n\t\t- 0.00232;\n}\nvec3 AgXToneMapping( vec3 color ) {\n\tconst mat3 AgXInsetMatrix = mat3(\n\t\tvec3( 0.856627153315983, 0.137318972929847, 0.11189821299995 ),\n\t\tvec3( 0.0951212405381588, 0.761241990602591, 0.0767994186031903 ),\n\t\tvec3( 0.0482516061458583, 0.101439036467562, 0.811302368396859 )\n\t);\n\tconst mat3 AgXOutsetMatrix = mat3(\n\t\tvec3( 1.1271005818144368, - 0.1413297634984383, - 0.14132976349843826 ),\n\t\tvec3( - 0.11060664309660323, 1.157823702216272, - 0.11060664309660294 ),\n\t\tvec3( - 0.016493938717834573, - 0.016493938717834257, 1.2519364065950405 )\n\t);\n\tconst float AgxMinEv = - 12.47393;\tconst float AgxMaxEv = 4.026069;\n\tcolor *= toneMappingExposure;\n\tcolor = LINEAR_SRGB_TO_LINEAR_REC2020 * color;\n\tcolor = AgXInsetMatrix * color;\n\tcolor = max( color, 1e-10 );\tcolor = log2( color );\n\tcolor = ( color - AgxMinEv ) / ( AgxMaxEv - AgxMinEv );\n\tcolor = clamp( color, 0.0, 1.0 );\n\tcolor = agxDefaultContrastApprox( color );\n\tcolor = AgXOutsetMatrix * color;\n\tcolor = pow( max( vec3( 0.0 ), color ), vec3( 2.2 ) );\n\tcolor = LINEAR_REC2020_TO_LINEAR_SRGB * color;\n\tcolor = clamp( color, 0.0, 1.0 );\n\treturn color;\n}\nvec3 CustomToneMapping( vec3 color ) { return color; }"; - -var transmission_fragment = "#ifdef USE_TRANSMISSION\n\tmaterial.transmission = transmission;\n\tmaterial.transmissionAlpha = 1.0;\n\tmaterial.thickness = thickness;\n\tmaterial.attenuationDistance = attenuationDistance;\n\tmaterial.attenuationColor = attenuationColor;\n\t#ifdef USE_TRANSMISSIONMAP\n\t\tmaterial.transmission *= texture2D( transmissionMap, vTransmissionMapUv ).r;\n\t#endif\n\t#ifdef USE_THICKNESSMAP\n\t\tmaterial.thickness *= texture2D( thicknessMap, vThicknessMapUv ).g;\n\t#endif\n\tvec3 pos = vWorldPosition;\n\tvec3 v = normalize( cameraPosition - pos );\n\tvec3 n = inverseTransformDirection( normal, viewMatrix );\n\tvec4 transmitted = getIBLVolumeRefraction(\n\t\tn, v, material.roughness, material.diffuseColor, material.specularColor, material.specularF90,\n\t\tpos, modelMatrix, viewMatrix, projectionMatrix, material.ior, material.thickness,\n\t\tmaterial.attenuationColor, material.attenuationDistance );\n\tmaterial.transmissionAlpha = mix( material.transmissionAlpha, transmitted.a, material.transmission );\n\ttotalDiffuse = mix( totalDiffuse, transmitted.rgb, material.transmission );\n#endif"; - -var transmission_pars_fragment = "#ifdef USE_TRANSMISSION\n\tuniform float transmission;\n\tuniform float thickness;\n\tuniform float attenuationDistance;\n\tuniform vec3 attenuationColor;\n\t#ifdef USE_TRANSMISSIONMAP\n\t\tuniform sampler2D transmissionMap;\n\t#endif\n\t#ifdef USE_THICKNESSMAP\n\t\tuniform sampler2D thicknessMap;\n\t#endif\n\tuniform vec2 transmissionSamplerSize;\n\tuniform sampler2D transmissionSamplerMap;\n\tuniform mat4 modelMatrix;\n\tuniform mat4 projectionMatrix;\n\tvarying vec3 vWorldPosition;\n\tfloat w0( float a ) {\n\t\treturn ( 1.0 / 6.0 ) * ( a * ( a * ( - a + 3.0 ) - 3.0 ) + 1.0 );\n\t}\n\tfloat w1( float a ) {\n\t\treturn ( 1.0 / 6.0 ) * ( a * a * ( 3.0 * a - 6.0 ) + 4.0 );\n\t}\n\tfloat w2( float a ){\n\t\treturn ( 1.0 / 6.0 ) * ( a * ( a * ( - 3.0 * a + 3.0 ) + 3.0 ) + 1.0 );\n\t}\n\tfloat w3( float a ) {\n\t\treturn ( 1.0 / 6.0 ) * ( a * a * a );\n\t}\n\tfloat g0( float a ) {\n\t\treturn w0( a ) + w1( a );\n\t}\n\tfloat g1( float a ) {\n\t\treturn w2( a ) + w3( a );\n\t}\n\tfloat h0( float a ) {\n\t\treturn - 1.0 + w1( a ) / ( w0( a ) + w1( a ) );\n\t}\n\tfloat h1( float a ) {\n\t\treturn 1.0 + w3( a ) / ( w2( a ) + w3( a ) );\n\t}\n\tvec4 bicubic( sampler2D tex, vec2 uv, vec4 texelSize, float lod ) {\n\t\tuv = uv * texelSize.zw + 0.5;\n\t\tvec2 iuv = floor( uv );\n\t\tvec2 fuv = fract( uv );\n\t\tfloat g0x = g0( fuv.x );\n\t\tfloat g1x = g1( fuv.x );\n\t\tfloat h0x = h0( fuv.x );\n\t\tfloat h1x = h1( fuv.x );\n\t\tfloat h0y = h0( fuv.y );\n\t\tfloat h1y = h1( fuv.y );\n\t\tvec2 p0 = ( vec2( iuv.x + h0x, iuv.y + h0y ) - 0.5 ) * texelSize.xy;\n\t\tvec2 p1 = ( vec2( iuv.x + h1x, iuv.y + h0y ) - 0.5 ) * texelSize.xy;\n\t\tvec2 p2 = ( vec2( iuv.x + h0x, iuv.y + h1y ) - 0.5 ) * texelSize.xy;\n\t\tvec2 p3 = ( vec2( iuv.x + h1x, iuv.y + h1y ) - 0.5 ) * texelSize.xy;\n\t\treturn g0( fuv.y ) * ( g0x * textureLod( tex, p0, lod ) + g1x * textureLod( tex, p1, lod ) ) +\n\t\t\tg1( fuv.y ) * ( g0x * textureLod( tex, p2, lod ) + g1x * textureLod( tex, p3, lod ) );\n\t}\n\tvec4 textureBicubic( sampler2D sampler, vec2 uv, float lod ) {\n\t\tvec2 fLodSize = vec2( textureSize( sampler, int( lod ) ) );\n\t\tvec2 cLodSize = vec2( textureSize( sampler, int( lod + 1.0 ) ) );\n\t\tvec2 fLodSizeInv = 1.0 / fLodSize;\n\t\tvec2 cLodSizeInv = 1.0 / cLodSize;\n\t\tvec4 fSample = bicubic( sampler, uv, vec4( fLodSizeInv, fLodSize ), floor( lod ) );\n\t\tvec4 cSample = bicubic( sampler, uv, vec4( cLodSizeInv, cLodSize ), ceil( lod ) );\n\t\treturn mix( fSample, cSample, fract( lod ) );\n\t}\n\tvec3 getVolumeTransmissionRay( const in vec3 n, const in vec3 v, const in float thickness, const in float ior, const in mat4 modelMatrix ) {\n\t\tvec3 refractionVector = refract( - v, normalize( n ), 1.0 / ior );\n\t\tvec3 modelScale;\n\t\tmodelScale.x = length( vec3( modelMatrix[ 0 ].xyz ) );\n\t\tmodelScale.y = length( vec3( modelMatrix[ 1 ].xyz ) );\n\t\tmodelScale.z = length( vec3( modelMatrix[ 2 ].xyz ) );\n\t\treturn normalize( refractionVector ) * thickness * modelScale;\n\t}\n\tfloat applyIorToRoughness( const in float roughness, const in float ior ) {\n\t\treturn roughness * clamp( ior * 2.0 - 2.0, 0.0, 1.0 );\n\t}\n\tvec4 getTransmissionSample( const in vec2 fragCoord, const in float roughness, const in float ior ) {\n\t\tfloat lod = log2( transmissionSamplerSize.x ) * applyIorToRoughness( roughness, ior );\n\t\treturn textureBicubic( transmissionSamplerMap, fragCoord.xy, lod );\n\t}\n\tvec3 volumeAttenuation( const in float transmissionDistance, const in vec3 attenuationColor, const in float attenuationDistance ) {\n\t\tif ( isinf( attenuationDistance ) ) {\n\t\t\treturn vec3( 1.0 );\n\t\t} else {\n\t\t\tvec3 attenuationCoefficient = -log( attenuationColor ) / attenuationDistance;\n\t\t\tvec3 transmittance = exp( - attenuationCoefficient * transmissionDistance );\t\t\treturn transmittance;\n\t\t}\n\t}\n\tvec4 getIBLVolumeRefraction( const in vec3 n, const in vec3 v, const in float roughness, const in vec3 diffuseColor,\n\t\tconst in vec3 specularColor, const in float specularF90, const in vec3 position, const in mat4 modelMatrix,\n\t\tconst in mat4 viewMatrix, const in mat4 projMatrix, const in float ior, const in float thickness,\n\t\tconst in vec3 attenuationColor, const in float attenuationDistance ) {\n\t\tvec3 transmissionRay = getVolumeTransmissionRay( n, v, thickness, ior, modelMatrix );\n\t\tvec3 refractedRayExit = position + transmissionRay;\n\t\tvec4 ndcPos = projMatrix * viewMatrix * vec4( refractedRayExit, 1.0 );\n\t\tvec2 refractionCoords = ndcPos.xy / ndcPos.w;\n\t\trefractionCoords += 1.0;\n\t\trefractionCoords /= 2.0;\n\t\tvec4 transmittedLight = getTransmissionSample( refractionCoords, roughness, ior );\n\t\tvec3 transmittance = diffuseColor * volumeAttenuation( length( transmissionRay ), attenuationColor, attenuationDistance );\n\t\tvec3 attenuatedColor = transmittance * transmittedLight.rgb;\n\t\tvec3 F = EnvironmentBRDF( n, v, specularColor, specularF90, roughness );\n\t\tfloat transmittanceFactor = ( transmittance.r + transmittance.g + transmittance.b ) / 3.0;\n\t\treturn vec4( ( 1.0 - F ) * attenuatedColor, 1.0 - ( 1.0 - transmittedLight.a ) * transmittanceFactor );\n\t}\n#endif"; - -var uv_pars_fragment = "#if defined( USE_UV ) || defined( USE_ANISOTROPY )\n\tvarying vec2 vUv;\n#endif\n#ifdef USE_MAP\n\tvarying vec2 vMapUv;\n#endif\n#ifdef USE_ALPHAMAP\n\tvarying vec2 vAlphaMapUv;\n#endif\n#ifdef USE_LIGHTMAP\n\tvarying vec2 vLightMapUv;\n#endif\n#ifdef USE_AOMAP\n\tvarying vec2 vAoMapUv;\n#endif\n#ifdef USE_BUMPMAP\n\tvarying vec2 vBumpMapUv;\n#endif\n#ifdef USE_NORMALMAP\n\tvarying vec2 vNormalMapUv;\n#endif\n#ifdef USE_EMISSIVEMAP\n\tvarying vec2 vEmissiveMapUv;\n#endif\n#ifdef USE_METALNESSMAP\n\tvarying vec2 vMetalnessMapUv;\n#endif\n#ifdef USE_ROUGHNESSMAP\n\tvarying vec2 vRoughnessMapUv;\n#endif\n#ifdef USE_ANISOTROPYMAP\n\tvarying vec2 vAnisotropyMapUv;\n#endif\n#ifdef USE_CLEARCOATMAP\n\tvarying vec2 vClearcoatMapUv;\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\tvarying vec2 vClearcoatNormalMapUv;\n#endif\n#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\tvarying vec2 vClearcoatRoughnessMapUv;\n#endif\n#ifdef USE_IRIDESCENCEMAP\n\tvarying vec2 vIridescenceMapUv;\n#endif\n#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\tvarying vec2 vIridescenceThicknessMapUv;\n#endif\n#ifdef USE_SHEEN_COLORMAP\n\tvarying vec2 vSheenColorMapUv;\n#endif\n#ifdef USE_SHEEN_ROUGHNESSMAP\n\tvarying vec2 vSheenRoughnessMapUv;\n#endif\n#ifdef USE_SPECULARMAP\n\tvarying vec2 vSpecularMapUv;\n#endif\n#ifdef USE_SPECULAR_COLORMAP\n\tvarying vec2 vSpecularColorMapUv;\n#endif\n#ifdef USE_SPECULAR_INTENSITYMAP\n\tvarying vec2 vSpecularIntensityMapUv;\n#endif\n#ifdef USE_TRANSMISSIONMAP\n\tuniform mat3 transmissionMapTransform;\n\tvarying vec2 vTransmissionMapUv;\n#endif\n#ifdef USE_THICKNESSMAP\n\tuniform mat3 thicknessMapTransform;\n\tvarying vec2 vThicknessMapUv;\n#endif"; - -var uv_pars_vertex = "#if defined( USE_UV ) || defined( USE_ANISOTROPY )\n\tvarying vec2 vUv;\n#endif\n#ifdef USE_MAP\n\tuniform mat3 mapTransform;\n\tvarying vec2 vMapUv;\n#endif\n#ifdef USE_ALPHAMAP\n\tuniform mat3 alphaMapTransform;\n\tvarying vec2 vAlphaMapUv;\n#endif\n#ifdef USE_LIGHTMAP\n\tuniform mat3 lightMapTransform;\n\tvarying vec2 vLightMapUv;\n#endif\n#ifdef USE_AOMAP\n\tuniform mat3 aoMapTransform;\n\tvarying vec2 vAoMapUv;\n#endif\n#ifdef USE_BUMPMAP\n\tuniform mat3 bumpMapTransform;\n\tvarying vec2 vBumpMapUv;\n#endif\n#ifdef USE_NORMALMAP\n\tuniform mat3 normalMapTransform;\n\tvarying vec2 vNormalMapUv;\n#endif\n#ifdef USE_DISPLACEMENTMAP\n\tuniform mat3 displacementMapTransform;\n\tvarying vec2 vDisplacementMapUv;\n#endif\n#ifdef USE_EMISSIVEMAP\n\tuniform mat3 emissiveMapTransform;\n\tvarying vec2 vEmissiveMapUv;\n#endif\n#ifdef USE_METALNESSMAP\n\tuniform mat3 metalnessMapTransform;\n\tvarying vec2 vMetalnessMapUv;\n#endif\n#ifdef USE_ROUGHNESSMAP\n\tuniform mat3 roughnessMapTransform;\n\tvarying vec2 vRoughnessMapUv;\n#endif\n#ifdef USE_ANISOTROPYMAP\n\tuniform mat3 anisotropyMapTransform;\n\tvarying vec2 vAnisotropyMapUv;\n#endif\n#ifdef USE_CLEARCOATMAP\n\tuniform mat3 clearcoatMapTransform;\n\tvarying vec2 vClearcoatMapUv;\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\tuniform mat3 clearcoatNormalMapTransform;\n\tvarying vec2 vClearcoatNormalMapUv;\n#endif\n#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\tuniform mat3 clearcoatRoughnessMapTransform;\n\tvarying vec2 vClearcoatRoughnessMapUv;\n#endif\n#ifdef USE_SHEEN_COLORMAP\n\tuniform mat3 sheenColorMapTransform;\n\tvarying vec2 vSheenColorMapUv;\n#endif\n#ifdef USE_SHEEN_ROUGHNESSMAP\n\tuniform mat3 sheenRoughnessMapTransform;\n\tvarying vec2 vSheenRoughnessMapUv;\n#endif\n#ifdef USE_IRIDESCENCEMAP\n\tuniform mat3 iridescenceMapTransform;\n\tvarying vec2 vIridescenceMapUv;\n#endif\n#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\tuniform mat3 iridescenceThicknessMapTransform;\n\tvarying vec2 vIridescenceThicknessMapUv;\n#endif\n#ifdef USE_SPECULARMAP\n\tuniform mat3 specularMapTransform;\n\tvarying vec2 vSpecularMapUv;\n#endif\n#ifdef USE_SPECULAR_COLORMAP\n\tuniform mat3 specularColorMapTransform;\n\tvarying vec2 vSpecularColorMapUv;\n#endif\n#ifdef USE_SPECULAR_INTENSITYMAP\n\tuniform mat3 specularIntensityMapTransform;\n\tvarying vec2 vSpecularIntensityMapUv;\n#endif\n#ifdef USE_TRANSMISSIONMAP\n\tuniform mat3 transmissionMapTransform;\n\tvarying vec2 vTransmissionMapUv;\n#endif\n#ifdef USE_THICKNESSMAP\n\tuniform mat3 thicknessMapTransform;\n\tvarying vec2 vThicknessMapUv;\n#endif"; - -var uv_vertex = "#if defined( USE_UV ) || defined( USE_ANISOTROPY )\n\tvUv = vec3( uv, 1 ).xy;\n#endif\n#ifdef USE_MAP\n\tvMapUv = ( mapTransform * vec3( MAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_ALPHAMAP\n\tvAlphaMapUv = ( alphaMapTransform * vec3( ALPHAMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_LIGHTMAP\n\tvLightMapUv = ( lightMapTransform * vec3( LIGHTMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_AOMAP\n\tvAoMapUv = ( aoMapTransform * vec3( AOMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_BUMPMAP\n\tvBumpMapUv = ( bumpMapTransform * vec3( BUMPMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_NORMALMAP\n\tvNormalMapUv = ( normalMapTransform * vec3( NORMALMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_DISPLACEMENTMAP\n\tvDisplacementMapUv = ( displacementMapTransform * vec3( DISPLACEMENTMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_EMISSIVEMAP\n\tvEmissiveMapUv = ( emissiveMapTransform * vec3( EMISSIVEMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_METALNESSMAP\n\tvMetalnessMapUv = ( metalnessMapTransform * vec3( METALNESSMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_ROUGHNESSMAP\n\tvRoughnessMapUv = ( roughnessMapTransform * vec3( ROUGHNESSMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_ANISOTROPYMAP\n\tvAnisotropyMapUv = ( anisotropyMapTransform * vec3( ANISOTROPYMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_CLEARCOATMAP\n\tvClearcoatMapUv = ( clearcoatMapTransform * vec3( CLEARCOATMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\tvClearcoatNormalMapUv = ( clearcoatNormalMapTransform * vec3( CLEARCOAT_NORMALMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\tvClearcoatRoughnessMapUv = ( clearcoatRoughnessMapTransform * vec3( CLEARCOAT_ROUGHNESSMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_IRIDESCENCEMAP\n\tvIridescenceMapUv = ( iridescenceMapTransform * vec3( IRIDESCENCEMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\tvIridescenceThicknessMapUv = ( iridescenceThicknessMapTransform * vec3( IRIDESCENCE_THICKNESSMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_SHEEN_COLORMAP\n\tvSheenColorMapUv = ( sheenColorMapTransform * vec3( SHEEN_COLORMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_SHEEN_ROUGHNESSMAP\n\tvSheenRoughnessMapUv = ( sheenRoughnessMapTransform * vec3( SHEEN_ROUGHNESSMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_SPECULARMAP\n\tvSpecularMapUv = ( specularMapTransform * vec3( SPECULARMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_SPECULAR_COLORMAP\n\tvSpecularColorMapUv = ( specularColorMapTransform * vec3( SPECULAR_COLORMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_SPECULAR_INTENSITYMAP\n\tvSpecularIntensityMapUv = ( specularIntensityMapTransform * vec3( SPECULAR_INTENSITYMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_TRANSMISSIONMAP\n\tvTransmissionMapUv = ( transmissionMapTransform * vec3( TRANSMISSIONMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_THICKNESSMAP\n\tvThicknessMapUv = ( thicknessMapTransform * vec3( THICKNESSMAP_UV, 1 ) ).xy;\n#endif"; - -var worldpos_vertex = "#if defined( USE_ENVMAP ) || defined( DISTANCE ) || defined ( USE_SHADOWMAP ) || defined ( USE_TRANSMISSION ) || NUM_SPOT_LIGHT_COORDS > 0\n\tvec4 worldPosition = vec4( transformed, 1.0 );\n\t#ifdef USE_BATCHING\n\t\tworldPosition = batchingMatrix * worldPosition;\n\t#endif\n\t#ifdef USE_INSTANCING\n\t\tworldPosition = instanceMatrix * worldPosition;\n\t#endif\n\tworldPosition = modelMatrix * worldPosition;\n#endif"; - -const vertex$h = "varying vec2 vUv;\nuniform mat3 uvTransform;\nvoid main() {\n\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n\tgl_Position = vec4( position.xy, 1.0, 1.0 );\n}"; - -const fragment$h = "uniform sampler2D t2D;\nuniform float backgroundIntensity;\nvarying vec2 vUv;\nvoid main() {\n\tvec4 texColor = texture2D( t2D, vUv );\n\t#ifdef DECODE_VIDEO_TEXTURE\n\t\ttexColor = vec4( mix( pow( texColor.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), texColor.rgb * 0.0773993808, vec3( lessThanEqual( texColor.rgb, vec3( 0.04045 ) ) ) ), texColor.w );\n\t#endif\n\ttexColor.rgb *= backgroundIntensity;\n\tgl_FragColor = texColor;\n\t#include \n\t#include \n}"; - -const vertex$g = "varying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n\tgl_Position.z = gl_Position.w;\n}"; - -const fragment$g = "#ifdef ENVMAP_TYPE_CUBE\n\tuniform samplerCube envMap;\n#elif defined( ENVMAP_TYPE_CUBE_UV )\n\tuniform sampler2D envMap;\n#endif\nuniform float flipEnvMap;\nuniform float backgroundBlurriness;\nuniform float backgroundIntensity;\nvarying vec3 vWorldDirection;\n#include \nvoid main() {\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tvec4 texColor = textureCube( envMap, vec3( flipEnvMap * vWorldDirection.x, vWorldDirection.yz ) );\n\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\tvec4 texColor = textureCubeUV( envMap, vWorldDirection, backgroundBlurriness );\n\t#else\n\t\tvec4 texColor = vec4( 0.0, 0.0, 0.0, 1.0 );\n\t#endif\n\ttexColor.rgb *= backgroundIntensity;\n\tgl_FragColor = texColor;\n\t#include \n\t#include \n}"; - -const vertex$f = "varying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n\tgl_Position.z = gl_Position.w;\n}"; - -const fragment$f = "uniform samplerCube tCube;\nuniform float tFlip;\nuniform float opacity;\nvarying vec3 vWorldDirection;\nvoid main() {\n\tvec4 texColor = textureCube( tCube, vec3( tFlip * vWorldDirection.x, vWorldDirection.yz ) );\n\tgl_FragColor = texColor;\n\tgl_FragColor.a *= opacity;\n\t#include \n\t#include \n}"; - -const vertex$e = "#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvarying vec2 vHighPrecisionZW;\nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include \n\t\t#include \n\t\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvHighPrecisionZW = gl_Position.zw;\n}"; - -const fragment$e = "#if DEPTH_PACKING == 3200\n\tuniform float opacity;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvarying vec2 vHighPrecisionZW;\nvoid main() {\n\tvec4 diffuseColor = vec4( 1.0 );\n\t#include \n\t#if DEPTH_PACKING == 3200\n\t\tdiffuseColor.a = opacity;\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tfloat fragCoordZ = 0.5 * vHighPrecisionZW[0] / vHighPrecisionZW[1] + 0.5;\n\t#if DEPTH_PACKING == 3200\n\t\tgl_FragColor = vec4( vec3( 1.0 - fragCoordZ ), opacity );\n\t#elif DEPTH_PACKING == 3201\n\t\tgl_FragColor = packDepthToRGBA( fragCoordZ );\n\t#endif\n}"; - -const vertex$d = "#define DISTANCE\nvarying vec3 vWorldPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include \n\t\t#include \n\t\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvWorldPosition = worldPosition.xyz;\n}"; - -const fragment$d = "#define DISTANCE\nuniform vec3 referencePosition;\nuniform float nearDistance;\nuniform float farDistance;\nvarying vec3 vWorldPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main () {\n\tvec4 diffuseColor = vec4( 1.0 );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tfloat dist = length( vWorldPosition - referencePosition );\n\tdist = ( dist - nearDistance ) / ( farDistance - nearDistance );\n\tdist = saturate( dist );\n\tgl_FragColor = packDepthToRGBA( dist );\n}"; - -const vertex$c = "varying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n}"; - -const fragment$c = "uniform sampler2D tEquirect;\nvarying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvec3 direction = normalize( vWorldDirection );\n\tvec2 sampleUV = equirectUv( direction );\n\tgl_FragColor = texture2D( tEquirect, sampleUV );\n\t#include \n\t#include \n}"; - -const vertex$b = "uniform float scale;\nattribute float lineDistance;\nvarying float vLineDistance;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvLineDistance = scale * lineDistance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - -const fragment$b = "uniform vec3 diffuse;\nuniform float opacity;\nuniform float dashSize;\nuniform float totalSize;\nvarying float vLineDistance;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\tif ( mod( vLineDistance, totalSize ) > dashSize ) {\n\t\tdiscard;\n\t}\n\tvec3 outgoingLight = vec3( 0.0 );\n\t#include \n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - -const vertex$a = "#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#if defined ( USE_ENVMAP ) || defined ( USE_SKINNING )\n\t\t#include \n\t\t#include \n\t\t#include \n\t\t#include \n\t\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - -const fragment$a = "uniform vec3 diffuse;\nuniform float opacity;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\t#ifdef USE_LIGHTMAP\n\t\tvec4 lightMapTexel = texture2D( lightMap, vLightMapUv );\n\t\treflectedLight.indirectDiffuse += lightMapTexel.rgb * lightMapIntensity * RECIPROCAL_PI;\n\t#else\n\t\treflectedLight.indirectDiffuse += vec3( 1.0 );\n\t#endif\n\t#include \n\treflectedLight.indirectDiffuse *= diffuseColor.rgb;\n\tvec3 outgoingLight = reflectedLight.indirectDiffuse;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - -const vertex$9 = "#define LAMBERT\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n\t#include \n}"; - -const fragment$9 = "#define LAMBERT\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - -const vertex$8 = "#define MATCAP\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n}"; - -const fragment$8 = "#define MATCAP\nuniform vec3 diffuse;\nuniform float opacity;\nuniform sampler2D matcap;\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 viewDir = normalize( vViewPosition );\n\tvec3 x = normalize( vec3( viewDir.z, 0.0, - viewDir.x ) );\n\tvec3 y = cross( viewDir, x );\n\tvec2 uv = vec2( dot( x, normal ), dot( y, normal ) ) * 0.495 + 0.5;\n\t#ifdef USE_MATCAP\n\t\tvec4 matcapColor = texture2D( matcap, uv );\n\t#else\n\t\tvec4 matcapColor = vec4( vec3( mix( 0.2, 0.8, uv.y ) ), 1.0 );\n\t#endif\n\tvec3 outgoingLight = diffuseColor.rgb * matcapColor.rgb;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - -const vertex$7 = "#define NORMAL\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP_TANGENTSPACE )\n\tvarying vec3 vViewPosition;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP_TANGENTSPACE )\n\tvViewPosition = - mvPosition.xyz;\n#endif\n}"; - -const fragment$7 = "#define NORMAL\nuniform float opacity;\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP_TANGENTSPACE )\n\tvarying vec3 vViewPosition;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvec4 diffuseColor = vec4( 0.0, 0.0, 0.0, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\tgl_FragColor = vec4( packNormalToRGB( normal ), diffuseColor.a );\n\t#ifdef OPAQUE\n\t\tgl_FragColor.a = 1.0;\n\t#endif\n}"; - -const vertex$6 = "#define PHONG\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n\t#include \n}"; - -const fragment$6 = "#define PHONG\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform vec3 specular;\nuniform float shininess;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - -const vertex$5 = "#define STANDARD\nvarying vec3 vViewPosition;\n#ifdef USE_TRANSMISSION\n\tvarying vec3 vWorldPosition;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n#ifdef USE_TRANSMISSION\n\tvWorldPosition = worldPosition.xyz;\n#endif\n}"; - -const fragment$5 = "#define STANDARD\n#ifdef PHYSICAL\n\t#define IOR\n\t#define USE_SPECULAR\n#endif\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float roughness;\nuniform float metalness;\nuniform float opacity;\n#ifdef IOR\n\tuniform float ior;\n#endif\n#ifdef USE_SPECULAR\n\tuniform float specularIntensity;\n\tuniform vec3 specularColor;\n\t#ifdef USE_SPECULAR_COLORMAP\n\t\tuniform sampler2D specularColorMap;\n\t#endif\n\t#ifdef USE_SPECULAR_INTENSITYMAP\n\t\tuniform sampler2D specularIntensityMap;\n\t#endif\n#endif\n#ifdef USE_CLEARCOAT\n\tuniform float clearcoat;\n\tuniform float clearcoatRoughness;\n#endif\n#ifdef USE_IRIDESCENCE\n\tuniform float iridescence;\n\tuniform float iridescenceIOR;\n\tuniform float iridescenceThicknessMinimum;\n\tuniform float iridescenceThicknessMaximum;\n#endif\n#ifdef USE_SHEEN\n\tuniform vec3 sheenColor;\n\tuniform float sheenRoughness;\n\t#ifdef USE_SHEEN_COLORMAP\n\t\tuniform sampler2D sheenColorMap;\n\t#endif\n\t#ifdef USE_SHEEN_ROUGHNESSMAP\n\t\tuniform sampler2D sheenRoughnessMap;\n\t#endif\n#endif\n#ifdef USE_ANISOTROPY\n\tuniform vec2 anisotropyVector;\n\t#ifdef USE_ANISOTROPYMAP\n\t\tuniform sampler2D anisotropyMap;\n\t#endif\n#endif\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 totalDiffuse = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse;\n\tvec3 totalSpecular = reflectedLight.directSpecular + reflectedLight.indirectSpecular;\n\t#include \n\tvec3 outgoingLight = totalDiffuse + totalSpecular + totalEmissiveRadiance;\n\t#ifdef USE_SHEEN\n\t\tfloat sheenEnergyComp = 1.0 - 0.157 * max3( material.sheenColor );\n\t\toutgoingLight = outgoingLight * sheenEnergyComp + sheenSpecularDirect + sheenSpecularIndirect;\n\t#endif\n\t#ifdef USE_CLEARCOAT\n\t\tfloat dotNVcc = saturate( dot( geometryClearcoatNormal, geometryViewDir ) );\n\t\tvec3 Fcc = F_Schlick( material.clearcoatF0, material.clearcoatF90, dotNVcc );\n\t\toutgoingLight = outgoingLight * ( 1.0 - material.clearcoat * Fcc ) + ( clearcoatSpecularDirect + clearcoatSpecularIndirect ) * material.clearcoat;\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - -const vertex$4 = "#define TOON\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n}"; - -const fragment$4 = "#define TOON\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - -const vertex$3 = "uniform float size;\nuniform float scale;\n#include \n#include \n#include \n#include \n#include \n#include \n#ifdef USE_POINTS_UV\n\tvarying vec2 vUv;\n\tuniform mat3 uvTransform;\n#endif\nvoid main() {\n\t#ifdef USE_POINTS_UV\n\t\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tgl_PointSize = size;\n\t#ifdef USE_SIZEATTENUATION\n\t\tbool isPerspective = isPerspectiveMatrix( projectionMatrix );\n\t\tif ( isPerspective ) gl_PointSize *= ( scale / - mvPosition.z );\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n}"; - -const fragment$3 = "uniform vec3 diffuse;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\tvec3 outgoingLight = vec3( 0.0 );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - -const vertex$2 = "#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - -const fragment$2 = "uniform vec3 color;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tgl_FragColor = vec4( color, opacity * ( 1.0 - getShadowMask() ) );\n\t#include \n\t#include \n\t#include \n}"; - -const vertex$1 = "uniform float rotation;\nuniform vec2 center;\n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 mvPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );\n\tvec2 scale;\n\tscale.x = length( vec3( modelMatrix[ 0 ].x, modelMatrix[ 0 ].y, modelMatrix[ 0 ].z ) );\n\tscale.y = length( vec3( modelMatrix[ 1 ].x, modelMatrix[ 1 ].y, modelMatrix[ 1 ].z ) );\n\t#ifndef USE_SIZEATTENUATION\n\t\tbool isPerspective = isPerspectiveMatrix( projectionMatrix );\n\t\tif ( isPerspective ) scale *= - mvPosition.z;\n\t#endif\n\tvec2 alignedPosition = ( position.xy - ( center - vec2( 0.5 ) ) ) * scale;\n\tvec2 rotatedPosition;\n\trotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;\n\trotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;\n\tmvPosition.xy += rotatedPosition;\n\tgl_Position = projectionMatrix * mvPosition;\n\t#include \n\t#include \n\t#include \n}"; - -const fragment$1 = "uniform vec3 diffuse;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\tvec3 outgoingLight = vec3( 0.0 );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\t#include \n\t#include \n\t#include \n\t#include \n}"; - -const ShaderChunk = { - alphahash_fragment: alphahash_fragment, - alphahash_pars_fragment: alphahash_pars_fragment, - alphamap_fragment: alphamap_fragment, - alphamap_pars_fragment: alphamap_pars_fragment, - alphatest_fragment: alphatest_fragment, - alphatest_pars_fragment: alphatest_pars_fragment, - aomap_fragment: aomap_fragment, - aomap_pars_fragment: aomap_pars_fragment, - batching_pars_vertex: batching_pars_vertex, - batching_vertex: batching_vertex, - begin_vertex: begin_vertex, - beginnormal_vertex: beginnormal_vertex, - bsdfs: bsdfs, - iridescence_fragment: iridescence_fragment, - bumpmap_pars_fragment: bumpmap_pars_fragment, - clipping_planes_fragment: clipping_planes_fragment, - clipping_planes_pars_fragment: clipping_planes_pars_fragment, - clipping_planes_pars_vertex: clipping_planes_pars_vertex, - clipping_planes_vertex: clipping_planes_vertex, - color_fragment: color_fragment, - color_pars_fragment: color_pars_fragment, - color_pars_vertex: color_pars_vertex, - color_vertex: color_vertex, - common: common, - cube_uv_reflection_fragment: cube_uv_reflection_fragment, - defaultnormal_vertex: defaultnormal_vertex, - displacementmap_pars_vertex: displacementmap_pars_vertex, - displacementmap_vertex: displacementmap_vertex, - emissivemap_fragment: emissivemap_fragment, - emissivemap_pars_fragment: emissivemap_pars_fragment, - colorspace_fragment: colorspace_fragment, - colorspace_pars_fragment: colorspace_pars_fragment, - envmap_fragment: envmap_fragment, - envmap_common_pars_fragment: envmap_common_pars_fragment, - envmap_pars_fragment: envmap_pars_fragment, - envmap_pars_vertex: envmap_pars_vertex, - envmap_physical_pars_fragment: envmap_physical_pars_fragment, - envmap_vertex: envmap_vertex, - fog_vertex: fog_vertex, - fog_pars_vertex: fog_pars_vertex, - fog_fragment: fog_fragment, - fog_pars_fragment: fog_pars_fragment, - gradientmap_pars_fragment: gradientmap_pars_fragment, - lightmap_fragment: lightmap_fragment, - lightmap_pars_fragment: lightmap_pars_fragment, - lights_lambert_fragment: lights_lambert_fragment, - lights_lambert_pars_fragment: lights_lambert_pars_fragment, - lights_pars_begin: lights_pars_begin, - lights_toon_fragment: lights_toon_fragment, - lights_toon_pars_fragment: lights_toon_pars_fragment, - lights_phong_fragment: lights_phong_fragment, - lights_phong_pars_fragment: lights_phong_pars_fragment, - lights_physical_fragment: lights_physical_fragment, - lights_physical_pars_fragment: lights_physical_pars_fragment, - lights_fragment_begin: lights_fragment_begin, - lights_fragment_maps: lights_fragment_maps, - lights_fragment_end: lights_fragment_end, - logdepthbuf_fragment: logdepthbuf_fragment, - logdepthbuf_pars_fragment: logdepthbuf_pars_fragment, - logdepthbuf_pars_vertex: logdepthbuf_pars_vertex, - logdepthbuf_vertex: logdepthbuf_vertex, - map_fragment: map_fragment, - map_pars_fragment: map_pars_fragment, - map_particle_fragment: map_particle_fragment, - map_particle_pars_fragment: map_particle_pars_fragment, - metalnessmap_fragment: metalnessmap_fragment, - metalnessmap_pars_fragment: metalnessmap_pars_fragment, - morphcolor_vertex: morphcolor_vertex, - morphnormal_vertex: morphnormal_vertex, - morphtarget_pars_vertex: morphtarget_pars_vertex, - morphtarget_vertex: morphtarget_vertex, - normal_fragment_begin: normal_fragment_begin, - normal_fragment_maps: normal_fragment_maps, - normal_pars_fragment: normal_pars_fragment, - normal_pars_vertex: normal_pars_vertex, - normal_vertex: normal_vertex, - normalmap_pars_fragment: normalmap_pars_fragment, - clearcoat_normal_fragment_begin: clearcoat_normal_fragment_begin, - clearcoat_normal_fragment_maps: clearcoat_normal_fragment_maps, - clearcoat_pars_fragment: clearcoat_pars_fragment, - iridescence_pars_fragment: iridescence_pars_fragment, - opaque_fragment: opaque_fragment, - packing: packing, - premultiplied_alpha_fragment: premultiplied_alpha_fragment, - project_vertex: project_vertex, - dithering_fragment: dithering_fragment, - dithering_pars_fragment: dithering_pars_fragment, - roughnessmap_fragment: roughnessmap_fragment, - roughnessmap_pars_fragment: roughnessmap_pars_fragment, - shadowmap_pars_fragment: shadowmap_pars_fragment, - shadowmap_pars_vertex: shadowmap_pars_vertex, - shadowmap_vertex: shadowmap_vertex, - shadowmask_pars_fragment: shadowmask_pars_fragment, - skinbase_vertex: skinbase_vertex, - skinning_pars_vertex: skinning_pars_vertex, - skinning_vertex: skinning_vertex, - skinnormal_vertex: skinnormal_vertex, - specularmap_fragment: specularmap_fragment, - specularmap_pars_fragment: specularmap_pars_fragment, - tonemapping_fragment: tonemapping_fragment, - tonemapping_pars_fragment: tonemapping_pars_fragment, - transmission_fragment: transmission_fragment, - transmission_pars_fragment: transmission_pars_fragment, - uv_pars_fragment: uv_pars_fragment, - uv_pars_vertex: uv_pars_vertex, - uv_vertex: uv_vertex, - worldpos_vertex: worldpos_vertex, - - background_vert: vertex$h, - background_frag: fragment$h, - backgroundCube_vert: vertex$g, - backgroundCube_frag: fragment$g, - cube_vert: vertex$f, - cube_frag: fragment$f, - depth_vert: vertex$e, - depth_frag: fragment$e, - distanceRGBA_vert: vertex$d, - distanceRGBA_frag: fragment$d, - equirect_vert: vertex$c, - equirect_frag: fragment$c, - linedashed_vert: vertex$b, - linedashed_frag: fragment$b, - meshbasic_vert: vertex$a, - meshbasic_frag: fragment$a, - meshlambert_vert: vertex$9, - meshlambert_frag: fragment$9, - meshmatcap_vert: vertex$8, - meshmatcap_frag: fragment$8, - meshnormal_vert: vertex$7, - meshnormal_frag: fragment$7, - meshphong_vert: vertex$6, - meshphong_frag: fragment$6, - meshphysical_vert: vertex$5, - meshphysical_frag: fragment$5, - meshtoon_vert: vertex$4, - meshtoon_frag: fragment$4, - points_vert: vertex$3, - points_frag: fragment$3, - shadow_vert: vertex$2, - shadow_frag: fragment$2, - sprite_vert: vertex$1, - sprite_frag: fragment$1 -}; - -/** - * Uniforms library for shared webgl shaders - */ - -const UniformsLib = { - - common: { - - diffuse: { value: /*@__PURE__*/ new Color( 0xffffff ) }, - opacity: { value: 1.0 }, - - map: { value: null }, - mapTransform: { value: /*@__PURE__*/ new Matrix3() }, - - alphaMap: { value: null }, - alphaMapTransform: { value: /*@__PURE__*/ new Matrix3() }, - - alphaTest: { value: 0 } - - }, - - specularmap: { - - specularMap: { value: null }, - specularMapTransform: { value: /*@__PURE__*/ new Matrix3() } - - }, - - envmap: { - - envMap: { value: null }, - flipEnvMap: { value: - 1 }, - reflectivity: { value: 1.0 }, // basic, lambert, phong - ior: { value: 1.5 }, // physical - refractionRatio: { value: 0.98 }, // basic, lambert, phong - - }, - - aomap: { - - aoMap: { value: null }, - aoMapIntensity: { value: 1 }, - aoMapTransform: { value: /*@__PURE__*/ new Matrix3() } - - }, - - lightmap: { - - lightMap: { value: null }, - lightMapIntensity: { value: 1 }, - lightMapTransform: { value: /*@__PURE__*/ new Matrix3() } - - }, - - bumpmap: { - - bumpMap: { value: null }, - bumpMapTransform: { value: /*@__PURE__*/ new Matrix3() }, - bumpScale: { value: 1 } - - }, - - normalmap: { - - normalMap: { value: null }, - normalMapTransform: { value: /*@__PURE__*/ new Matrix3() }, - normalScale: { value: /*@__PURE__*/ new Vector2( 1, 1 ) } - - }, - - displacementmap: { - - displacementMap: { value: null }, - displacementMapTransform: { value: /*@__PURE__*/ new Matrix3() }, - displacementScale: { value: 1 }, - displacementBias: { value: 0 } - - }, - - emissivemap: { - - emissiveMap: { value: null }, - emissiveMapTransform: { value: /*@__PURE__*/ new Matrix3() } - - }, - - metalnessmap: { - - metalnessMap: { value: null }, - metalnessMapTransform: { value: /*@__PURE__*/ new Matrix3() } - - }, - - roughnessmap: { - - roughnessMap: { value: null }, - roughnessMapTransform: { value: /*@__PURE__*/ new Matrix3() } - - }, - - gradientmap: { - - gradientMap: { value: null } - - }, - - fog: { - - fogDensity: { value: 0.00025 }, - fogNear: { value: 1 }, - fogFar: { value: 2000 }, - fogColor: { value: /*@__PURE__*/ new Color( 0xffffff ) } - - }, - - lights: { - - ambientLightColor: { value: [] }, - - lightProbe: { value: [] }, - - directionalLights: { value: [], properties: { - direction: {}, - color: {} - } }, - - directionalLightShadows: { value: [], properties: { - shadowBias: {}, - shadowNormalBias: {}, - shadowRadius: {}, - shadowMapSize: {} - } }, - - directionalShadowMap: { value: [] }, - directionalShadowMatrix: { value: [] }, - - spotLights: { value: [], properties: { - color: {}, - position: {}, - direction: {}, - distance: {}, - coneCos: {}, - penumbraCos: {}, - decay: {} - } }, - - spotLightShadows: { value: [], properties: { - shadowBias: {}, - shadowNormalBias: {}, - shadowRadius: {}, - shadowMapSize: {} - } }, - - spotLightMap: { value: [] }, - spotShadowMap: { value: [] }, - spotLightMatrix: { value: [] }, - - pointLights: { value: [], properties: { - color: {}, - position: {}, - decay: {}, - distance: {} - } }, - - pointLightShadows: { value: [], properties: { - shadowBias: {}, - shadowNormalBias: {}, - shadowRadius: {}, - shadowMapSize: {}, - shadowCameraNear: {}, - shadowCameraFar: {} - } }, - - pointShadowMap: { value: [] }, - pointShadowMatrix: { value: [] }, - - hemisphereLights: { value: [], properties: { - direction: {}, - skyColor: {}, - groundColor: {} - } }, - - // TODO (abelnation): RectAreaLight BRDF data needs to be moved from example to main src - rectAreaLights: { value: [], properties: { - color: {}, - position: {}, - width: {}, - height: {} - } }, - - ltc_1: { value: null }, - ltc_2: { value: null } - - }, - - points: { - - diffuse: { value: /*@__PURE__*/ new Color( 0xffffff ) }, - opacity: { value: 1.0 }, - size: { value: 1.0 }, - scale: { value: 1.0 }, - map: { value: null }, - alphaMap: { value: null }, - alphaMapTransform: { value: /*@__PURE__*/ new Matrix3() }, - alphaTest: { value: 0 }, - uvTransform: { value: /*@__PURE__*/ new Matrix3() } - - }, - - sprite: { - - diffuse: { value: /*@__PURE__*/ new Color( 0xffffff ) }, - opacity: { value: 1.0 }, - center: { value: /*@__PURE__*/ new Vector2( 0.5, 0.5 ) }, - rotation: { value: 0.0 }, - map: { value: null }, - mapTransform: { value: /*@__PURE__*/ new Matrix3() }, - alphaMap: { value: null }, - alphaMapTransform: { value: /*@__PURE__*/ new Matrix3() }, - alphaTest: { value: 0 } - - } - -}; - -const ShaderLib = { - - basic: { - - uniforms: /*@__PURE__*/ mergeUniforms( [ - UniformsLib.common, - UniformsLib.specularmap, - UniformsLib.envmap, - UniformsLib.aomap, - UniformsLib.lightmap, - UniformsLib.fog - ] ), - - vertexShader: ShaderChunk.meshbasic_vert, - fragmentShader: ShaderChunk.meshbasic_frag - - }, - - lambert: { - - uniforms: /*@__PURE__*/ mergeUniforms( [ - UniformsLib.common, - UniformsLib.specularmap, - UniformsLib.envmap, - UniformsLib.aomap, - UniformsLib.lightmap, - UniformsLib.emissivemap, - UniformsLib.bumpmap, - UniformsLib.normalmap, - UniformsLib.displacementmap, - UniformsLib.fog, - UniformsLib.lights, - { - emissive: { value: /*@__PURE__*/ new Color( 0x000000 ) } - } - ] ), - - vertexShader: ShaderChunk.meshlambert_vert, - fragmentShader: ShaderChunk.meshlambert_frag - - }, - - phong: { - - uniforms: /*@__PURE__*/ mergeUniforms( [ - UniformsLib.common, - UniformsLib.specularmap, - UniformsLib.envmap, - UniformsLib.aomap, - UniformsLib.lightmap, - UniformsLib.emissivemap, - UniformsLib.bumpmap, - UniformsLib.normalmap, - UniformsLib.displacementmap, - UniformsLib.fog, - UniformsLib.lights, - { - emissive: { value: /*@__PURE__*/ new Color( 0x000000 ) }, - specular: { value: /*@__PURE__*/ new Color( 0x111111 ) }, - shininess: { value: 30 } - } - ] ), - - vertexShader: ShaderChunk.meshphong_vert, - fragmentShader: ShaderChunk.meshphong_frag - - }, - - standard: { - - uniforms: /*@__PURE__*/ mergeUniforms( [ - UniformsLib.common, - UniformsLib.envmap, - UniformsLib.aomap, - UniformsLib.lightmap, - UniformsLib.emissivemap, - UniformsLib.bumpmap, - UniformsLib.normalmap, - UniformsLib.displacementmap, - UniformsLib.roughnessmap, - UniformsLib.metalnessmap, - UniformsLib.fog, - UniformsLib.lights, - { - emissive: { value: /*@__PURE__*/ new Color( 0x000000 ) }, - roughness: { value: 1.0 }, - metalness: { value: 0.0 }, - envMapIntensity: { value: 1 } // temporary - } - ] ), - - vertexShader: ShaderChunk.meshphysical_vert, - fragmentShader: ShaderChunk.meshphysical_frag - - }, - - toon: { - - uniforms: /*@__PURE__*/ mergeUniforms( [ - UniformsLib.common, - UniformsLib.aomap, - UniformsLib.lightmap, - UniformsLib.emissivemap, - UniformsLib.bumpmap, - UniformsLib.normalmap, - UniformsLib.displacementmap, - UniformsLib.gradientmap, - UniformsLib.fog, - UniformsLib.lights, - { - emissive: { value: /*@__PURE__*/ new Color( 0x000000 ) } - } - ] ), - - vertexShader: ShaderChunk.meshtoon_vert, - fragmentShader: ShaderChunk.meshtoon_frag - - }, - - matcap: { - - uniforms: /*@__PURE__*/ mergeUniforms( [ - UniformsLib.common, - UniformsLib.bumpmap, - UniformsLib.normalmap, - UniformsLib.displacementmap, - UniformsLib.fog, - { - matcap: { value: null } - } - ] ), - - vertexShader: ShaderChunk.meshmatcap_vert, - fragmentShader: ShaderChunk.meshmatcap_frag - - }, - - points: { - - uniforms: /*@__PURE__*/ mergeUniforms( [ - UniformsLib.points, - UniformsLib.fog - ] ), - - vertexShader: ShaderChunk.points_vert, - fragmentShader: ShaderChunk.points_frag - - }, - - dashed: { - - uniforms: /*@__PURE__*/ mergeUniforms( [ - UniformsLib.common, - UniformsLib.fog, - { - scale: { value: 1 }, - dashSize: { value: 1 }, - totalSize: { value: 2 } - } - ] ), - - vertexShader: ShaderChunk.linedashed_vert, - fragmentShader: ShaderChunk.linedashed_frag - - }, - - depth: { - - uniforms: /*@__PURE__*/ mergeUniforms( [ - UniformsLib.common, - UniformsLib.displacementmap - ] ), - - vertexShader: ShaderChunk.depth_vert, - fragmentShader: ShaderChunk.depth_frag - - }, - - normal: { - - uniforms: /*@__PURE__*/ mergeUniforms( [ - UniformsLib.common, - UniformsLib.bumpmap, - UniformsLib.normalmap, - UniformsLib.displacementmap, - { - opacity: { value: 1.0 } - } - ] ), - - vertexShader: ShaderChunk.meshnormal_vert, - fragmentShader: ShaderChunk.meshnormal_frag - - }, - - sprite: { - - uniforms: /*@__PURE__*/ mergeUniforms( [ - UniformsLib.sprite, - UniformsLib.fog - ] ), - - vertexShader: ShaderChunk.sprite_vert, - fragmentShader: ShaderChunk.sprite_frag - - }, - - background: { - - uniforms: { - uvTransform: { value: /*@__PURE__*/ new Matrix3() }, - t2D: { value: null }, - backgroundIntensity: { value: 1 } - }, - - vertexShader: ShaderChunk.background_vert, - fragmentShader: ShaderChunk.background_frag - - }, - - backgroundCube: { - - uniforms: { - envMap: { value: null }, - flipEnvMap: { value: - 1 }, - backgroundBlurriness: { value: 0 }, - backgroundIntensity: { value: 1 } - }, - - vertexShader: ShaderChunk.backgroundCube_vert, - fragmentShader: ShaderChunk.backgroundCube_frag - - }, - - cube: { - - uniforms: { - tCube: { value: null }, - tFlip: { value: - 1 }, - opacity: { value: 1.0 } - }, - - vertexShader: ShaderChunk.cube_vert, - fragmentShader: ShaderChunk.cube_frag - - }, - - equirect: { - - uniforms: { - tEquirect: { value: null }, - }, - - vertexShader: ShaderChunk.equirect_vert, - fragmentShader: ShaderChunk.equirect_frag - - }, - - distanceRGBA: { - - uniforms: /*@__PURE__*/ mergeUniforms( [ - UniformsLib.common, - UniformsLib.displacementmap, - { - referencePosition: { value: /*@__PURE__*/ new Vector3() }, - nearDistance: { value: 1 }, - farDistance: { value: 1000 } - } - ] ), - - vertexShader: ShaderChunk.distanceRGBA_vert, - fragmentShader: ShaderChunk.distanceRGBA_frag - - }, - - shadow: { - - uniforms: /*@__PURE__*/ mergeUniforms( [ - UniformsLib.lights, - UniformsLib.fog, - { - color: { value: /*@__PURE__*/ new Color( 0x00000 ) }, - opacity: { value: 1.0 } - }, - ] ), - - vertexShader: ShaderChunk.shadow_vert, - fragmentShader: ShaderChunk.shadow_frag - - } - -}; - -ShaderLib.physical = { - - uniforms: /*@__PURE__*/ mergeUniforms( [ - ShaderLib.standard.uniforms, - { - clearcoat: { value: 0 }, - clearcoatMap: { value: null }, - clearcoatMapTransform: { value: /*@__PURE__*/ new Matrix3() }, - clearcoatNormalMap: { value: null }, - clearcoatNormalMapTransform: { value: /*@__PURE__*/ new Matrix3() }, - clearcoatNormalScale: { value: /*@__PURE__*/ new Vector2( 1, 1 ) }, - clearcoatRoughness: { value: 0 }, - clearcoatRoughnessMap: { value: null }, - clearcoatRoughnessMapTransform: { value: /*@__PURE__*/ new Matrix3() }, - iridescence: { value: 0 }, - iridescenceMap: { value: null }, - iridescenceMapTransform: { value: /*@__PURE__*/ new Matrix3() }, - iridescenceIOR: { value: 1.3 }, - iridescenceThicknessMinimum: { value: 100 }, - iridescenceThicknessMaximum: { value: 400 }, - iridescenceThicknessMap: { value: null }, - iridescenceThicknessMapTransform: { value: /*@__PURE__*/ new Matrix3() }, - sheen: { value: 0 }, - sheenColor: { value: /*@__PURE__*/ new Color( 0x000000 ) }, - sheenColorMap: { value: null }, - sheenColorMapTransform: { value: /*@__PURE__*/ new Matrix3() }, - sheenRoughness: { value: 1 }, - sheenRoughnessMap: { value: null }, - sheenRoughnessMapTransform: { value: /*@__PURE__*/ new Matrix3() }, - transmission: { value: 0 }, - transmissionMap: { value: null }, - transmissionMapTransform: { value: /*@__PURE__*/ new Matrix3() }, - transmissionSamplerSize: { value: /*@__PURE__*/ new Vector2() }, - transmissionSamplerMap: { value: null }, - thickness: { value: 0 }, - thicknessMap: { value: null }, - thicknessMapTransform: { value: /*@__PURE__*/ new Matrix3() }, - attenuationDistance: { value: 0 }, - attenuationColor: { value: /*@__PURE__*/ new Color( 0x000000 ) }, - specularColor: { value: /*@__PURE__*/ new Color( 1, 1, 1 ) }, - specularColorMap: { value: null }, - specularColorMapTransform: { value: /*@__PURE__*/ new Matrix3() }, - specularIntensity: { value: 1 }, - specularIntensityMap: { value: null }, - specularIntensityMapTransform: { value: /*@__PURE__*/ new Matrix3() }, - anisotropyVector: { value: /*@__PURE__*/ new Vector2() }, - anisotropyMap: { value: null }, - anisotropyMapTransform: { value: /*@__PURE__*/ new Matrix3() }, - } - ] ), - - vertexShader: ShaderChunk.meshphysical_vert, - fragmentShader: ShaderChunk.meshphysical_frag - -}; - -const _rgb = { r: 0, b: 0, g: 0 }; - -function WebGLBackground( renderer, cubemaps, cubeuvmaps, state, objects, alpha, premultipliedAlpha ) { - - const clearColor = new Color( 0x000000 ); - let clearAlpha = alpha === true ? 0 : 1; - - let planeMesh; - let boxMesh; - - let currentBackground = null; - let currentBackgroundVersion = 0; - let currentTonemapping = null; - - function render( renderList, scene ) { - - let forceClear = false; - let background = scene.isScene === true ? scene.background : null; - - if ( background && background.isTexture ) { - - const usePMREM = scene.backgroundBlurriness > 0; // use PMREM if the user wants to blur the background - background = ( usePMREM ? cubeuvmaps : cubemaps ).get( background ); - - } - - if ( background === null ) { - - setClear( clearColor, clearAlpha ); - - } else if ( background && background.isColor ) { - - setClear( background, 1 ); - forceClear = true; - - } - - const environmentBlendMode = renderer.xr.getEnvironmentBlendMode(); - - if ( environmentBlendMode === 'additive' ) { - - state.buffers.color.setClear( 0, 0, 0, 1, premultipliedAlpha ); - - } else if ( environmentBlendMode === 'alpha-blend' ) { - - state.buffers.color.setClear( 0, 0, 0, 0, premultipliedAlpha ); - - } - - if ( renderer.autoClear || forceClear ) { - - renderer.clear( renderer.autoClearColor, renderer.autoClearDepth, renderer.autoClearStencil ); - - } - - if ( background && ( background.isCubeTexture || background.mapping === CubeUVReflectionMapping ) ) { - - if ( boxMesh === undefined ) { - - boxMesh = new Mesh( - new BoxGeometry( 1, 1, 1 ), - new ShaderMaterial( { - name: 'BackgroundCubeMaterial', - uniforms: cloneUniforms( ShaderLib.backgroundCube.uniforms ), - vertexShader: ShaderLib.backgroundCube.vertexShader, - fragmentShader: ShaderLib.backgroundCube.fragmentShader, - side: BackSide, - depthTest: false, - depthWrite: false, - fog: false - } ) - ); - - boxMesh.geometry.deleteAttribute( 'normal' ); - boxMesh.geometry.deleteAttribute( 'uv' ); - - boxMesh.onBeforeRender = function ( renderer, scene, camera ) { - - this.matrixWorld.copyPosition( camera.matrixWorld ); - - }; - - // add "envMap" material property so the renderer can evaluate it like for built-in materials - Object.defineProperty( boxMesh.material, 'envMap', { - - get: function () { - - return this.uniforms.envMap.value; - - } - - } ); - - objects.update( boxMesh ); - - } - - boxMesh.material.uniforms.envMap.value = background; - boxMesh.material.uniforms.flipEnvMap.value = ( background.isCubeTexture && background.isRenderTargetTexture === false ) ? - 1 : 1; - boxMesh.material.uniforms.backgroundBlurriness.value = scene.backgroundBlurriness; - boxMesh.material.uniforms.backgroundIntensity.value = scene.backgroundIntensity; - boxMesh.material.toneMapped = ColorManagement.getTransfer( background.colorSpace ) !== SRGBTransfer; - - if ( currentBackground !== background || - currentBackgroundVersion !== background.version || - currentTonemapping !== renderer.toneMapping ) { - - boxMesh.material.needsUpdate = true; - - currentBackground = background; - currentBackgroundVersion = background.version; - currentTonemapping = renderer.toneMapping; - - } - - boxMesh.layers.enableAll(); - - // push to the pre-sorted opaque render list - renderList.unshift( boxMesh, boxMesh.geometry, boxMesh.material, 0, 0, null ); - - } else if ( background && background.isTexture ) { - - if ( planeMesh === undefined ) { - - planeMesh = new Mesh( - new PlaneGeometry( 2, 2 ), - new ShaderMaterial( { - name: 'BackgroundMaterial', - uniforms: cloneUniforms( ShaderLib.background.uniforms ), - vertexShader: ShaderLib.background.vertexShader, - fragmentShader: ShaderLib.background.fragmentShader, - side: FrontSide, - depthTest: false, - depthWrite: false, - fog: false - } ) - ); - - planeMesh.geometry.deleteAttribute( 'normal' ); - - // add "map" material property so the renderer can evaluate it like for built-in materials - Object.defineProperty( planeMesh.material, 'map', { - - get: function () { - - return this.uniforms.t2D.value; - - } - - } ); - - objects.update( planeMesh ); - - } - - planeMesh.material.uniforms.t2D.value = background; - planeMesh.material.uniforms.backgroundIntensity.value = scene.backgroundIntensity; - planeMesh.material.toneMapped = ColorManagement.getTransfer( background.colorSpace ) !== SRGBTransfer; - - if ( background.matrixAutoUpdate === true ) { - - background.updateMatrix(); - - } - - planeMesh.material.uniforms.uvTransform.value.copy( background.matrix ); - - if ( currentBackground !== background || - currentBackgroundVersion !== background.version || - currentTonemapping !== renderer.toneMapping ) { - - planeMesh.material.needsUpdate = true; - - currentBackground = background; - currentBackgroundVersion = background.version; - currentTonemapping = renderer.toneMapping; - - } - - planeMesh.layers.enableAll(); - - // push to the pre-sorted opaque render list - renderList.unshift( planeMesh, planeMesh.geometry, planeMesh.material, 0, 0, null ); - - } - - } - - function setClear( color, alpha ) { - - color.getRGB( _rgb, getUnlitUniformColorSpace( renderer ) ); - - state.buffers.color.setClear( _rgb.r, _rgb.g, _rgb.b, alpha, premultipliedAlpha ); - - } - - return { - - getClearColor: function () { - - return clearColor; - - }, - setClearColor: function ( color, alpha = 1 ) { - - clearColor.set( color ); - clearAlpha = alpha; - setClear( clearColor, clearAlpha ); - - }, - getClearAlpha: function () { - - return clearAlpha; - - }, - setClearAlpha: function ( alpha ) { - - clearAlpha = alpha; - setClear( clearColor, clearAlpha ); - - }, - render: render - - }; - -} - -function WebGLBindingStates( gl, extensions, attributes, capabilities ) { - - const maxVertexAttributes = gl.getParameter( gl.MAX_VERTEX_ATTRIBS ); - - const extension = capabilities.isWebGL2 ? null : extensions.get( 'OES_vertex_array_object' ); - const vaoAvailable = capabilities.isWebGL2 || extension !== null; - - const bindingStates = {}; - - const defaultState = createBindingState( null ); - let currentState = defaultState; - let forceUpdate = false; - - function setup( object, material, program, geometry, index ) { - - let updateBuffers = false; - - if ( vaoAvailable ) { - - const state = getBindingState( geometry, program, material ); - - if ( currentState !== state ) { - - currentState = state; - bindVertexArrayObject( currentState.object ); - - } - - updateBuffers = needsUpdate( object, geometry, program, index ); - - if ( updateBuffers ) saveCache( object, geometry, program, index ); - - } else { - - const wireframe = ( material.wireframe === true ); - - if ( currentState.geometry !== geometry.id || - currentState.program !== program.id || - currentState.wireframe !== wireframe ) { - - currentState.geometry = geometry.id; - currentState.program = program.id; - currentState.wireframe = wireframe; - - updateBuffers = true; - - } - - } - - if ( index !== null ) { - - attributes.update( index, gl.ELEMENT_ARRAY_BUFFER ); - - } - - if ( updateBuffers || forceUpdate ) { - - forceUpdate = false; - - setupVertexAttributes( object, material, program, geometry ); - - if ( index !== null ) { - - gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, attributes.get( index ).buffer ); - - } - - } - - } - - function createVertexArrayObject() { - - if ( capabilities.isWebGL2 ) return gl.createVertexArray(); - - return extension.createVertexArrayOES(); - - } - - function bindVertexArrayObject( vao ) { - - if ( capabilities.isWebGL2 ) return gl.bindVertexArray( vao ); - - return extension.bindVertexArrayOES( vao ); - - } - - function deleteVertexArrayObject( vao ) { - - if ( capabilities.isWebGL2 ) return gl.deleteVertexArray( vao ); - - return extension.deleteVertexArrayOES( vao ); - - } - - function getBindingState( geometry, program, material ) { - - const wireframe = ( material.wireframe === true ); - - let programMap = bindingStates[ geometry.id ]; - - if ( programMap === undefined ) { - - programMap = {}; - bindingStates[ geometry.id ] = programMap; - - } - - let stateMap = programMap[ program.id ]; - - if ( stateMap === undefined ) { - - stateMap = {}; - programMap[ program.id ] = stateMap; - - } - - let state = stateMap[ wireframe ]; - - if ( state === undefined ) { - - state = createBindingState( createVertexArrayObject() ); - stateMap[ wireframe ] = state; - - } - - return state; - - } - - function createBindingState( vao ) { - - const newAttributes = []; - const enabledAttributes = []; - const attributeDivisors = []; - - for ( let i = 0; i < maxVertexAttributes; i ++ ) { - - newAttributes[ i ] = 0; - enabledAttributes[ i ] = 0; - attributeDivisors[ i ] = 0; - - } - - return { - - // for backward compatibility on non-VAO support browser - geometry: null, - program: null, - wireframe: false, - - newAttributes: newAttributes, - enabledAttributes: enabledAttributes, - attributeDivisors: attributeDivisors, - object: vao, - attributes: {}, - index: null - - }; - - } - - function needsUpdate( object, geometry, program, index ) { - - const cachedAttributes = currentState.attributes; - const geometryAttributes = geometry.attributes; - - let attributesNum = 0; - - const programAttributes = program.getAttributes(); - - for ( const name in programAttributes ) { - - const programAttribute = programAttributes[ name ]; - - if ( programAttribute.location >= 0 ) { - - const cachedAttribute = cachedAttributes[ name ]; - let geometryAttribute = geometryAttributes[ name ]; - - if ( geometryAttribute === undefined ) { - - if ( name === 'instanceMatrix' && object.instanceMatrix ) geometryAttribute = object.instanceMatrix; - if ( name === 'instanceColor' && object.instanceColor ) geometryAttribute = object.instanceColor; - - } - - if ( cachedAttribute === undefined ) return true; - - if ( cachedAttribute.attribute !== geometryAttribute ) return true; - - if ( geometryAttribute && cachedAttribute.data !== geometryAttribute.data ) return true; - - attributesNum ++; - - } - - } - - if ( currentState.attributesNum !== attributesNum ) return true; - - if ( currentState.index !== index ) return true; - - return false; - - } - - function saveCache( object, geometry, program, index ) { - - const cache = {}; - const attributes = geometry.attributes; - let attributesNum = 0; - - const programAttributes = program.getAttributes(); - - for ( const name in programAttributes ) { - - const programAttribute = programAttributes[ name ]; - - if ( programAttribute.location >= 0 ) { - - let attribute = attributes[ name ]; - - if ( attribute === undefined ) { - - if ( name === 'instanceMatrix' && object.instanceMatrix ) attribute = object.instanceMatrix; - if ( name === 'instanceColor' && object.instanceColor ) attribute = object.instanceColor; - - } - - const data = {}; - data.attribute = attribute; - - if ( attribute && attribute.data ) { - - data.data = attribute.data; - - } - - cache[ name ] = data; - - attributesNum ++; - - } - - } - - currentState.attributes = cache; - currentState.attributesNum = attributesNum; - - currentState.index = index; - - } - - function initAttributes() { - - const newAttributes = currentState.newAttributes; - - for ( let i = 0, il = newAttributes.length; i < il; i ++ ) { - - newAttributes[ i ] = 0; - - } - - } - - function enableAttribute( attribute ) { - - enableAttributeAndDivisor( attribute, 0 ); - - } - - function enableAttributeAndDivisor( attribute, meshPerAttribute ) { - - const newAttributes = currentState.newAttributes; - const enabledAttributes = currentState.enabledAttributes; - const attributeDivisors = currentState.attributeDivisors; - - newAttributes[ attribute ] = 1; - - if ( enabledAttributes[ attribute ] === 0 ) { - - gl.enableVertexAttribArray( attribute ); - enabledAttributes[ attribute ] = 1; - - } - - if ( attributeDivisors[ attribute ] !== meshPerAttribute ) { - - const extension = capabilities.isWebGL2 ? gl : extensions.get( 'ANGLE_instanced_arrays' ); - - extension[ capabilities.isWebGL2 ? 'vertexAttribDivisor' : 'vertexAttribDivisorANGLE' ]( attribute, meshPerAttribute ); - attributeDivisors[ attribute ] = meshPerAttribute; - - } - - } - - function disableUnusedAttributes() { - - const newAttributes = currentState.newAttributes; - const enabledAttributes = currentState.enabledAttributes; - - for ( let i = 0, il = enabledAttributes.length; i < il; i ++ ) { - - if ( enabledAttributes[ i ] !== newAttributes[ i ] ) { - - gl.disableVertexAttribArray( i ); - enabledAttributes[ i ] = 0; - - } - - } - - } - - function vertexAttribPointer( index, size, type, normalized, stride, offset, integer ) { - - if ( integer === true ) { - - gl.vertexAttribIPointer( index, size, type, stride, offset ); - - } else { - - gl.vertexAttribPointer( index, size, type, normalized, stride, offset ); - - } - - } - - function setupVertexAttributes( object, material, program, geometry ) { - - if ( capabilities.isWebGL2 === false && ( object.isInstancedMesh || geometry.isInstancedBufferGeometry ) ) { - - if ( extensions.get( 'ANGLE_instanced_arrays' ) === null ) return; - - } - - initAttributes(); - - const geometryAttributes = geometry.attributes; - - const programAttributes = program.getAttributes(); - - const materialDefaultAttributeValues = material.defaultAttributeValues; - - for ( const name in programAttributes ) { - - const programAttribute = programAttributes[ name ]; - - if ( programAttribute.location >= 0 ) { - - let geometryAttribute = geometryAttributes[ name ]; - - if ( geometryAttribute === undefined ) { - - if ( name === 'instanceMatrix' && object.instanceMatrix ) geometryAttribute = object.instanceMatrix; - if ( name === 'instanceColor' && object.instanceColor ) geometryAttribute = object.instanceColor; - - } - - if ( geometryAttribute !== undefined ) { - - const normalized = geometryAttribute.normalized; - const size = geometryAttribute.itemSize; - - const attribute = attributes.get( geometryAttribute ); - - // TODO Attribute may not be available on context restore - - if ( attribute === undefined ) continue; - - const buffer = attribute.buffer; - const type = attribute.type; - const bytesPerElement = attribute.bytesPerElement; - - // check for integer attributes (WebGL 2 only) - - const integer = ( capabilities.isWebGL2 === true && ( type === gl.INT || type === gl.UNSIGNED_INT || geometryAttribute.gpuType === IntType ) ); - - if ( geometryAttribute.isInterleavedBufferAttribute ) { - - const data = geometryAttribute.data; - const stride = data.stride; - const offset = geometryAttribute.offset; - - if ( data.isInstancedInterleavedBuffer ) { - - for ( let i = 0; i < programAttribute.locationSize; i ++ ) { - - enableAttributeAndDivisor( programAttribute.location + i, data.meshPerAttribute ); - - } - - if ( object.isInstancedMesh !== true && geometry._maxInstanceCount === undefined ) { - - geometry._maxInstanceCount = data.meshPerAttribute * data.count; - - } - - } else { - - for ( let i = 0; i < programAttribute.locationSize; i ++ ) { - - enableAttribute( programAttribute.location + i ); - - } - - } - - gl.bindBuffer( gl.ARRAY_BUFFER, buffer ); - - for ( let i = 0; i < programAttribute.locationSize; i ++ ) { - - vertexAttribPointer( - programAttribute.location + i, - size / programAttribute.locationSize, - type, - normalized, - stride * bytesPerElement, - ( offset + ( size / programAttribute.locationSize ) * i ) * bytesPerElement, - integer - ); - - } - - } else { - - if ( geometryAttribute.isInstancedBufferAttribute ) { - - for ( let i = 0; i < programAttribute.locationSize; i ++ ) { - - enableAttributeAndDivisor( programAttribute.location + i, geometryAttribute.meshPerAttribute ); - - } - - if ( object.isInstancedMesh !== true && geometry._maxInstanceCount === undefined ) { - - geometry._maxInstanceCount = geometryAttribute.meshPerAttribute * geometryAttribute.count; - - } - - } else { - - for ( let i = 0; i < programAttribute.locationSize; i ++ ) { - - enableAttribute( programAttribute.location + i ); - - } - - } - - gl.bindBuffer( gl.ARRAY_BUFFER, buffer ); - - for ( let i = 0; i < programAttribute.locationSize; i ++ ) { - - vertexAttribPointer( - programAttribute.location + i, - size / programAttribute.locationSize, - type, - normalized, - size * bytesPerElement, - ( size / programAttribute.locationSize ) * i * bytesPerElement, - integer - ); - - } - - } - - } else if ( materialDefaultAttributeValues !== undefined ) { - - const value = materialDefaultAttributeValues[ name ]; - - if ( value !== undefined ) { - - switch ( value.length ) { - - case 2: - gl.vertexAttrib2fv( programAttribute.location, value ); - break; - - case 3: - gl.vertexAttrib3fv( programAttribute.location, value ); - break; - - case 4: - gl.vertexAttrib4fv( programAttribute.location, value ); - break; - - default: - gl.vertexAttrib1fv( programAttribute.location, value ); - - } - - } - - } - - } - - } - - disableUnusedAttributes(); - - } - - function dispose() { - - reset(); - - for ( const geometryId in bindingStates ) { - - const programMap = bindingStates[ geometryId ]; - - for ( const programId in programMap ) { - - const stateMap = programMap[ programId ]; - - for ( const wireframe in stateMap ) { - - deleteVertexArrayObject( stateMap[ wireframe ].object ); - - delete stateMap[ wireframe ]; - - } - - delete programMap[ programId ]; - - } - - delete bindingStates[ geometryId ]; - - } - - } - - function releaseStatesOfGeometry( geometry ) { - - if ( bindingStates[ geometry.id ] === undefined ) return; - - const programMap = bindingStates[ geometry.id ]; - - for ( const programId in programMap ) { - - const stateMap = programMap[ programId ]; - - for ( const wireframe in stateMap ) { - - deleteVertexArrayObject( stateMap[ wireframe ].object ); - - delete stateMap[ wireframe ]; - - } - - delete programMap[ programId ]; - - } - - delete bindingStates[ geometry.id ]; - - } - - function releaseStatesOfProgram( program ) { - - for ( const geometryId in bindingStates ) { - - const programMap = bindingStates[ geometryId ]; - - if ( programMap[ program.id ] === undefined ) continue; - - const stateMap = programMap[ program.id ]; - - for ( const wireframe in stateMap ) { - - deleteVertexArrayObject( stateMap[ wireframe ].object ); - - delete stateMap[ wireframe ]; - - } - - delete programMap[ program.id ]; - - } - - } - - function reset() { - - resetDefaultState(); - forceUpdate = true; - - if ( currentState === defaultState ) return; - - currentState = defaultState; - bindVertexArrayObject( currentState.object ); - - } - - // for backward-compatibility - - function resetDefaultState() { - - defaultState.geometry = null; - defaultState.program = null; - defaultState.wireframe = false; - - } - - return { - - setup: setup, - reset: reset, - resetDefaultState: resetDefaultState, - dispose: dispose, - releaseStatesOfGeometry: releaseStatesOfGeometry, - releaseStatesOfProgram: releaseStatesOfProgram, - - initAttributes: initAttributes, - enableAttribute: enableAttribute, - disableUnusedAttributes: disableUnusedAttributes - - }; - -} - -function WebGLBufferRenderer( gl, extensions, info, capabilities ) { - - const isWebGL2 = capabilities.isWebGL2; - - let mode; - - function setMode( value ) { - - mode = value; - - } - - function render( start, count ) { - - gl.drawArrays( mode, start, count ); - - info.update( count, mode, 1 ); - - } - - function renderInstances( start, count, primcount ) { - - if ( primcount === 0 ) return; - - let extension, methodName; - - if ( isWebGL2 ) { - - extension = gl; - methodName = 'drawArraysInstanced'; - - } else { - - extension = extensions.get( 'ANGLE_instanced_arrays' ); - methodName = 'drawArraysInstancedANGLE'; - - if ( extension === null ) { - - console.error( 'THREE.WebGLBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' ); - return; - - } - - } - - extension[ methodName ]( mode, start, count, primcount ); - - info.update( count, mode, primcount ); - - } - - function renderMultiDraw( starts, counts, drawCount ) { - - if ( drawCount === 0 ) return; - - const extension = extensions.get( 'WEBGL_multi_draw' ); - if ( extension === null ) { - - for ( let i = 0; i < drawCount; i ++ ) { - - this.render( starts[ i ], counts[ i ] ); - - } - - } else { - - extension.multiDrawArraysWEBGL( mode, starts, 0, counts, 0, drawCount ); - - let elementCount = 0; - for ( let i = 0; i < drawCount; i ++ ) { - - elementCount += counts[ i ]; - - } - - info.update( elementCount, mode, 1 ); - - } - - } - - // - - this.setMode = setMode; - this.render = render; - this.renderInstances = renderInstances; - this.renderMultiDraw = renderMultiDraw; - -} - -function WebGLCapabilities( gl, extensions, parameters ) { - - let maxAnisotropy; - - function getMaxAnisotropy() { - - if ( maxAnisotropy !== undefined ) return maxAnisotropy; - - if ( extensions.has( 'EXT_texture_filter_anisotropic' ) === true ) { - - const extension = extensions.get( 'EXT_texture_filter_anisotropic' ); - - maxAnisotropy = gl.getParameter( extension.MAX_TEXTURE_MAX_ANISOTROPY_EXT ); - - } else { - - maxAnisotropy = 0; - - } - - return maxAnisotropy; - - } - - function getMaxPrecision( precision ) { - - if ( precision === 'highp' ) { - - if ( gl.getShaderPrecisionFormat( gl.VERTEX_SHADER, gl.HIGH_FLOAT ).precision > 0 && - gl.getShaderPrecisionFormat( gl.FRAGMENT_SHADER, gl.HIGH_FLOAT ).precision > 0 ) { - - return 'highp'; - - } - - precision = 'mediump'; - - } - - if ( precision === 'mediump' ) { - - if ( gl.getShaderPrecisionFormat( gl.VERTEX_SHADER, gl.MEDIUM_FLOAT ).precision > 0 && - gl.getShaderPrecisionFormat( gl.FRAGMENT_SHADER, gl.MEDIUM_FLOAT ).precision > 0 ) { - - return 'mediump'; - - } - - } - - return 'lowp'; - - } - - const isWebGL2 = typeof WebGL2RenderingContext !== 'undefined' && gl.constructor.name === 'WebGL2RenderingContext'; - - let precision = parameters.precision !== undefined ? parameters.precision : 'highp'; - const maxPrecision = getMaxPrecision( precision ); - - if ( maxPrecision !== precision ) { - - console.warn( 'THREE.WebGLRenderer:', precision, 'not supported, using', maxPrecision, 'instead.' ); - precision = maxPrecision; - - } - - const drawBuffers = isWebGL2 || extensions.has( 'WEBGL_draw_buffers' ); - - const logarithmicDepthBuffer = parameters.logarithmicDepthBuffer === true; - - const maxTextures = gl.getParameter( gl.MAX_TEXTURE_IMAGE_UNITS ); - const maxVertexTextures = gl.getParameter( gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS ); - const maxTextureSize = gl.getParameter( gl.MAX_TEXTURE_SIZE ); - const maxCubemapSize = gl.getParameter( gl.MAX_CUBE_MAP_TEXTURE_SIZE ); - - const maxAttributes = gl.getParameter( gl.MAX_VERTEX_ATTRIBS ); - const maxVertexUniforms = gl.getParameter( gl.MAX_VERTEX_UNIFORM_VECTORS ); - const maxVaryings = gl.getParameter( gl.MAX_VARYING_VECTORS ); - const maxFragmentUniforms = gl.getParameter( gl.MAX_FRAGMENT_UNIFORM_VECTORS ); - - const vertexTextures = maxVertexTextures > 0; - const floatFragmentTextures = isWebGL2 || extensions.has( 'OES_texture_float' ); - const floatVertexTextures = vertexTextures && floatFragmentTextures; - - const maxSamples = isWebGL2 ? gl.getParameter( gl.MAX_SAMPLES ) : 0; - - return { - - isWebGL2: isWebGL2, - - drawBuffers: drawBuffers, - - getMaxAnisotropy: getMaxAnisotropy, - getMaxPrecision: getMaxPrecision, - - precision: precision, - logarithmicDepthBuffer: logarithmicDepthBuffer, - - maxTextures: maxTextures, - maxVertexTextures: maxVertexTextures, - maxTextureSize: maxTextureSize, - maxCubemapSize: maxCubemapSize, - - maxAttributes: maxAttributes, - maxVertexUniforms: maxVertexUniforms, - maxVaryings: maxVaryings, - maxFragmentUniforms: maxFragmentUniforms, - - vertexTextures: vertexTextures, - floatFragmentTextures: floatFragmentTextures, - floatVertexTextures: floatVertexTextures, - - maxSamples: maxSamples - - }; - -} - -function WebGLClipping( properties ) { - - const scope = this; - - let globalState = null, - numGlobalPlanes = 0, - localClippingEnabled = false, - renderingShadows = false; - - const plane = new Plane(), - viewNormalMatrix = new Matrix3(), - - uniform = { value: null, needsUpdate: false }; - - this.uniform = uniform; - this.numPlanes = 0; - this.numIntersection = 0; - - this.init = function ( planes, enableLocalClipping ) { - - const enabled = - planes.length !== 0 || - enableLocalClipping || - // enable state of previous frame - the clipping code has to - // run another frame in order to reset the state: - numGlobalPlanes !== 0 || - localClippingEnabled; - - localClippingEnabled = enableLocalClipping; - - numGlobalPlanes = planes.length; - - return enabled; - - }; - - this.beginShadows = function () { - - renderingShadows = true; - projectPlanes( null ); - - }; - - this.endShadows = function () { - - renderingShadows = false; - - }; - - this.setGlobalState = function ( planes, camera ) { - - globalState = projectPlanes( planes, camera, 0 ); - - }; - - this.setState = function ( material, camera, useCache ) { - - const planes = material.clippingPlanes, - clipIntersection = material.clipIntersection, - clipShadows = material.clipShadows; - - const materialProperties = properties.get( material ); - - if ( ! localClippingEnabled || planes === null || planes.length === 0 || renderingShadows && ! clipShadows ) { - - // there's no local clipping - - if ( renderingShadows ) { - - // there's no global clipping - - projectPlanes( null ); - - } else { - - resetGlobalState(); - - } - - } else { - - const nGlobal = renderingShadows ? 0 : numGlobalPlanes, - lGlobal = nGlobal * 4; - - let dstArray = materialProperties.clippingState || null; - - uniform.value = dstArray; // ensure unique state - - dstArray = projectPlanes( planes, camera, lGlobal, useCache ); - - for ( let i = 0; i !== lGlobal; ++ i ) { - - dstArray[ i ] = globalState[ i ]; - - } - - materialProperties.clippingState = dstArray; - this.numIntersection = clipIntersection ? this.numPlanes : 0; - this.numPlanes += nGlobal; - - } - - - }; - - function resetGlobalState() { - - if ( uniform.value !== globalState ) { - - uniform.value = globalState; - uniform.needsUpdate = numGlobalPlanes > 0; - - } - - scope.numPlanes = numGlobalPlanes; - scope.numIntersection = 0; - - } - - function projectPlanes( planes, camera, dstOffset, skipTransform ) { - - const nPlanes = planes !== null ? planes.length : 0; - let dstArray = null; - - if ( nPlanes !== 0 ) { - - dstArray = uniform.value; - - if ( skipTransform !== true || dstArray === null ) { - - const flatSize = dstOffset + nPlanes * 4, - viewMatrix = camera.matrixWorldInverse; - - viewNormalMatrix.getNormalMatrix( viewMatrix ); - - if ( dstArray === null || dstArray.length < flatSize ) { - - dstArray = new Float32Array( flatSize ); - - } - - for ( let i = 0, i4 = dstOffset; i !== nPlanes; ++ i, i4 += 4 ) { - - plane.copy( planes[ i ] ).applyMatrix4( viewMatrix, viewNormalMatrix ); - - plane.normal.toArray( dstArray, i4 ); - dstArray[ i4 + 3 ] = plane.constant; - - } - - } - - uniform.value = dstArray; - uniform.needsUpdate = true; - - } - - scope.numPlanes = nPlanes; - scope.numIntersection = 0; - - return dstArray; - - } - -} - -function WebGLCubeMaps( renderer ) { - - let cubemaps = new WeakMap(); - - function mapTextureMapping( texture, mapping ) { - - if ( mapping === EquirectangularReflectionMapping ) { - - texture.mapping = CubeReflectionMapping; - - } else if ( mapping === EquirectangularRefractionMapping ) { - - texture.mapping = CubeRefractionMapping; - - } - - return texture; - - } - - function get( texture ) { - - if ( texture && texture.isTexture ) { - - const mapping = texture.mapping; - - if ( mapping === EquirectangularReflectionMapping || mapping === EquirectangularRefractionMapping ) { - - if ( cubemaps.has( texture ) ) { - - const cubemap = cubemaps.get( texture ).texture; - return mapTextureMapping( cubemap, texture.mapping ); - - } else { - - const image = texture.image; - - if ( image && image.height > 0 ) { - - const renderTarget = new WebGLCubeRenderTarget( image.height ); - renderTarget.fromEquirectangularTexture( renderer, texture ); - cubemaps.set( texture, renderTarget ); - - texture.addEventListener( 'dispose', onTextureDispose ); - - return mapTextureMapping( renderTarget.texture, texture.mapping ); - - } else { - - // image not yet ready. try the conversion next frame - - return null; - - } - - } - - } - - } - - return texture; - - } - - function onTextureDispose( event ) { - - const texture = event.target; - - texture.removeEventListener( 'dispose', onTextureDispose ); - - const cubemap = cubemaps.get( texture ); - - if ( cubemap !== undefined ) { - - cubemaps.delete( texture ); - cubemap.dispose(); - - } - - } - - function dispose() { - - cubemaps = new WeakMap(); - - } - - return { - get: get, - dispose: dispose - }; - -} - -class OrthographicCamera extends Camera { - - constructor( left = - 1, right = 1, top = 1, bottom = - 1, near = 0.1, far = 2000 ) { - - super(); - - this.isOrthographicCamera = true; - - this.type = 'OrthographicCamera'; - - this.zoom = 1; - this.view = null; - - this.left = left; - this.right = right; - this.top = top; - this.bottom = bottom; - - this.near = near; - this.far = far; - - this.updateProjectionMatrix(); - - } - - copy( source, recursive ) { - - super.copy( source, recursive ); - - this.left = source.left; - this.right = source.right; - this.top = source.top; - this.bottom = source.bottom; - this.near = source.near; - this.far = source.far; - - this.zoom = source.zoom; - this.view = source.view === null ? null : Object.assign( {}, source.view ); - - return this; - - } - - setViewOffset( fullWidth, fullHeight, x, y, width, height ) { - - if ( this.view === null ) { - - this.view = { - enabled: true, - fullWidth: 1, - fullHeight: 1, - offsetX: 0, - offsetY: 0, - width: 1, - height: 1 - }; - - } - - this.view.enabled = true; - this.view.fullWidth = fullWidth; - this.view.fullHeight = fullHeight; - this.view.offsetX = x; - this.view.offsetY = y; - this.view.width = width; - this.view.height = height; - - this.updateProjectionMatrix(); - - } - - clearViewOffset() { - - if ( this.view !== null ) { - - this.view.enabled = false; - - } - - this.updateProjectionMatrix(); - - } - - updateProjectionMatrix() { - - const dx = ( this.right - this.left ) / ( 2 * this.zoom ); - const dy = ( this.top - this.bottom ) / ( 2 * this.zoom ); - const cx = ( this.right + this.left ) / 2; - const cy = ( this.top + this.bottom ) / 2; - - let left = cx - dx; - let right = cx + dx; - let top = cy + dy; - let bottom = cy - dy; - - if ( this.view !== null && this.view.enabled ) { - - const scaleW = ( this.right - this.left ) / this.view.fullWidth / this.zoom; - const scaleH = ( this.top - this.bottom ) / this.view.fullHeight / this.zoom; - - left += scaleW * this.view.offsetX; - right = left + scaleW * this.view.width; - top -= scaleH * this.view.offsetY; - bottom = top - scaleH * this.view.height; - - } - - this.projectionMatrix.makeOrthographic( left, right, top, bottom, this.near, this.far, this.coordinateSystem ); - - this.projectionMatrixInverse.copy( this.projectionMatrix ).invert(); - - } - - toJSON( meta ) { - - const data = super.toJSON( meta ); - - data.object.zoom = this.zoom; - data.object.left = this.left; - data.object.right = this.right; - data.object.top = this.top; - data.object.bottom = this.bottom; - data.object.near = this.near; - data.object.far = this.far; - - if ( this.view !== null ) data.object.view = Object.assign( {}, this.view ); - - return data; - - } - -} - -const LOD_MIN = 4; - -// The standard deviations (radians) associated with the extra mips. These are -// chosen to approximate a Trowbridge-Reitz distribution function times the -// geometric shadowing function. These sigma values squared must match the -// variance #defines in cube_uv_reflection_fragment.glsl.js. -const EXTRA_LOD_SIGMA = [ 0.125, 0.215, 0.35, 0.446, 0.526, 0.582 ]; - -// The maximum length of the blur for loop. Smaller sigmas will use fewer -// samples and exit early, but not recompile the shader. -const MAX_SAMPLES = 20; - -const _flatCamera = /*@__PURE__*/ new OrthographicCamera(); -const _clearColor = /*@__PURE__*/ new Color(); -let _oldTarget = null; -let _oldActiveCubeFace = 0; -let _oldActiveMipmapLevel = 0; - -// Golden Ratio -const PHI = ( 1 + Math.sqrt( 5 ) ) / 2; -const INV_PHI = 1 / PHI; - -// Vertices of a dodecahedron (except the opposites, which represent the -// same axis), used as axis directions evenly spread on a sphere. -const _axisDirections = [ - /*@__PURE__*/ new Vector3( 1, 1, 1 ), - /*@__PURE__*/ new Vector3( - 1, 1, 1 ), - /*@__PURE__*/ new Vector3( 1, 1, - 1 ), - /*@__PURE__*/ new Vector3( - 1, 1, - 1 ), - /*@__PURE__*/ new Vector3( 0, PHI, INV_PHI ), - /*@__PURE__*/ new Vector3( 0, PHI, - INV_PHI ), - /*@__PURE__*/ new Vector3( INV_PHI, 0, PHI ), - /*@__PURE__*/ new Vector3( - INV_PHI, 0, PHI ), - /*@__PURE__*/ new Vector3( PHI, INV_PHI, 0 ), - /*@__PURE__*/ new Vector3( - PHI, INV_PHI, 0 ) ]; - -/** - * This class generates a Prefiltered, Mipmapped Radiance Environment Map - * (PMREM) from a cubeMap environment texture. This allows different levels of - * blur to be quickly accessed based on material roughness. It is packed into a - * special CubeUV format that allows us to perform custom interpolation so that - * we can support nonlinear formats such as RGBE. Unlike a traditional mipmap - * chain, it only goes down to the LOD_MIN level (above), and then creates extra - * even more filtered 'mips' at the same LOD_MIN resolution, associated with - * higher roughness levels. In this way we maintain resolution to smoothly - * interpolate diffuse lighting while limiting sampling computation. - * - * Paper: Fast, Accurate Image-Based Lighting - * https://drive.google.com/file/d/15y8r_UpKlU9SvV4ILb0C3qCPecS8pvLz/view -*/ - -class PMREMGenerator { - - constructor( renderer ) { - - this._renderer = renderer; - this._pingPongRenderTarget = null; - - this._lodMax = 0; - this._cubeSize = 0; - this._lodPlanes = []; - this._sizeLods = []; - this._sigmas = []; - - this._blurMaterial = null; - this._cubemapMaterial = null; - this._equirectMaterial = null; - - this._compileMaterial( this._blurMaterial ); - - } - - /** - * Generates a PMREM from a supplied Scene, which can be faster than using an - * image if networking bandwidth is low. Optional sigma specifies a blur radius - * in radians to be applied to the scene before PMREM generation. Optional near - * and far planes ensure the scene is rendered in its entirety (the cubeCamera - * is placed at the origin). - */ - fromScene( scene, sigma = 0, near = 0.1, far = 100 ) { - - _oldTarget = this._renderer.getRenderTarget(); - _oldActiveCubeFace = this._renderer.getActiveCubeFace(); - _oldActiveMipmapLevel = this._renderer.getActiveMipmapLevel(); - - this._setSize( 256 ); - - const cubeUVRenderTarget = this._allocateTargets(); - cubeUVRenderTarget.depthBuffer = true; - - this._sceneToCubeUV( scene, near, far, cubeUVRenderTarget ); - - if ( sigma > 0 ) { - - this._blur( cubeUVRenderTarget, 0, 0, sigma ); - - } - - this._applyPMREM( cubeUVRenderTarget ); - this._cleanup( cubeUVRenderTarget ); - - return cubeUVRenderTarget; - - } - - /** - * Generates a PMREM from an equirectangular texture, which can be either LDR - * or HDR. The ideal input image size is 1k (1024 x 512), - * as this matches best with the 256 x 256 cubemap output. - */ - fromEquirectangular( equirectangular, renderTarget = null ) { - - return this._fromTexture( equirectangular, renderTarget ); - - } - - /** - * Generates a PMREM from an cubemap texture, which can be either LDR - * or HDR. The ideal input cube size is 256 x 256, - * as this matches best with the 256 x 256 cubemap output. - */ - fromCubemap( cubemap, renderTarget = null ) { - - return this._fromTexture( cubemap, renderTarget ); - - } - - /** - * Pre-compiles the cubemap shader. You can get faster start-up by invoking this method during - * your texture's network fetch for increased concurrency. - */ - compileCubemapShader() { - - if ( this._cubemapMaterial === null ) { - - this._cubemapMaterial = _getCubemapMaterial(); - this._compileMaterial( this._cubemapMaterial ); - - } - - } - - /** - * Pre-compiles the equirectangular shader. You can get faster start-up by invoking this method during - * your texture's network fetch for increased concurrency. - */ - compileEquirectangularShader() { - - if ( this._equirectMaterial === null ) { - - this._equirectMaterial = _getEquirectMaterial(); - this._compileMaterial( this._equirectMaterial ); - - } - - } - - /** - * Disposes of the PMREMGenerator's internal memory. Note that PMREMGenerator is a static class, - * so you should not need more than one PMREMGenerator object. If you do, calling dispose() on - * one of them will cause any others to also become unusable. - */ - dispose() { - - this._dispose(); - - if ( this._cubemapMaterial !== null ) this._cubemapMaterial.dispose(); - if ( this._equirectMaterial !== null ) this._equirectMaterial.dispose(); - - } - - // private interface - - _setSize( cubeSize ) { - - this._lodMax = Math.floor( Math.log2( cubeSize ) ); - this._cubeSize = Math.pow( 2, this._lodMax ); - - } - - _dispose() { - - if ( this._blurMaterial !== null ) this._blurMaterial.dispose(); - - if ( this._pingPongRenderTarget !== null ) this._pingPongRenderTarget.dispose(); - - for ( let i = 0; i < this._lodPlanes.length; i ++ ) { - - this._lodPlanes[ i ].dispose(); - - } - - } - - _cleanup( outputTarget ) { - - this._renderer.setRenderTarget( _oldTarget, _oldActiveCubeFace, _oldActiveMipmapLevel ); - outputTarget.scissorTest = false; - _setViewport( outputTarget, 0, 0, outputTarget.width, outputTarget.height ); - - } - - _fromTexture( texture, renderTarget ) { - - if ( texture.mapping === CubeReflectionMapping || texture.mapping === CubeRefractionMapping ) { - - this._setSize( texture.image.length === 0 ? 16 : ( texture.image[ 0 ].width || texture.image[ 0 ].image.width ) ); - - } else { // Equirectangular - - this._setSize( texture.image.width / 4 ); - - } - - _oldTarget = this._renderer.getRenderTarget(); - _oldActiveCubeFace = this._renderer.getActiveCubeFace(); - _oldActiveMipmapLevel = this._renderer.getActiveMipmapLevel(); - - const cubeUVRenderTarget = renderTarget || this._allocateTargets(); - this._textureToCubeUV( texture, cubeUVRenderTarget ); - this._applyPMREM( cubeUVRenderTarget ); - this._cleanup( cubeUVRenderTarget ); - - return cubeUVRenderTarget; - - } - - _allocateTargets() { - - const width = 3 * Math.max( this._cubeSize, 16 * 7 ); - const height = 4 * this._cubeSize; - - const params = { - magFilter: LinearFilter, - minFilter: LinearFilter, - generateMipmaps: false, - type: HalfFloatType, - format: RGBAFormat, - colorSpace: LinearSRGBColorSpace, - depthBuffer: false - }; - - const cubeUVRenderTarget = _createRenderTarget( width, height, params ); - - if ( this._pingPongRenderTarget === null || this._pingPongRenderTarget.width !== width || this._pingPongRenderTarget.height !== height ) { - - if ( this._pingPongRenderTarget !== null ) { - - this._dispose(); - - } - - this._pingPongRenderTarget = _createRenderTarget( width, height, params ); - - const { _lodMax } = this; - ( { sizeLods: this._sizeLods, lodPlanes: this._lodPlanes, sigmas: this._sigmas } = _createPlanes( _lodMax ) ); - - this._blurMaterial = _getBlurShader( _lodMax, width, height ); - - } - - return cubeUVRenderTarget; - - } - - _compileMaterial( material ) { - - const tmpMesh = new Mesh( this._lodPlanes[ 0 ], material ); - this._renderer.compile( tmpMesh, _flatCamera ); - - } - - _sceneToCubeUV( scene, near, far, cubeUVRenderTarget ) { - - const fov = 90; - const aspect = 1; - const cubeCamera = new PerspectiveCamera( fov, aspect, near, far ); - const upSign = [ 1, - 1, 1, 1, 1, 1 ]; - const forwardSign = [ 1, 1, 1, - 1, - 1, - 1 ]; - const renderer = this._renderer; - - const originalAutoClear = renderer.autoClear; - const toneMapping = renderer.toneMapping; - renderer.getClearColor( _clearColor ); - - renderer.toneMapping = NoToneMapping; - renderer.autoClear = false; - - const backgroundMaterial = new MeshBasicMaterial( { - name: 'PMREM.Background', - side: BackSide, - depthWrite: false, - depthTest: false, - } ); - - const backgroundBox = new Mesh( new BoxGeometry(), backgroundMaterial ); - - let useSolidColor = false; - const background = scene.background; - - if ( background ) { - - if ( background.isColor ) { - - backgroundMaterial.color.copy( background ); - scene.background = null; - useSolidColor = true; - - } - - } else { - - backgroundMaterial.color.copy( _clearColor ); - useSolidColor = true; - - } - - for ( let i = 0; i < 6; i ++ ) { - - const col = i % 3; - - if ( col === 0 ) { - - cubeCamera.up.set( 0, upSign[ i ], 0 ); - cubeCamera.lookAt( forwardSign[ i ], 0, 0 ); - - } else if ( col === 1 ) { - - cubeCamera.up.set( 0, 0, upSign[ i ] ); - cubeCamera.lookAt( 0, forwardSign[ i ], 0 ); - - } else { - - cubeCamera.up.set( 0, upSign[ i ], 0 ); - cubeCamera.lookAt( 0, 0, forwardSign[ i ] ); - - } - - const size = this._cubeSize; - - _setViewport( cubeUVRenderTarget, col * size, i > 2 ? size : 0, size, size ); - - renderer.setRenderTarget( cubeUVRenderTarget ); - - if ( useSolidColor ) { - - renderer.render( backgroundBox, cubeCamera ); - - } - - renderer.render( scene, cubeCamera ); - - } - - backgroundBox.geometry.dispose(); - backgroundBox.material.dispose(); - - renderer.toneMapping = toneMapping; - renderer.autoClear = originalAutoClear; - scene.background = background; - - } - - _textureToCubeUV( texture, cubeUVRenderTarget ) { - - const renderer = this._renderer; - - const isCubeTexture = ( texture.mapping === CubeReflectionMapping || texture.mapping === CubeRefractionMapping ); - - if ( isCubeTexture ) { - - if ( this._cubemapMaterial === null ) { - - this._cubemapMaterial = _getCubemapMaterial(); - - } - - this._cubemapMaterial.uniforms.flipEnvMap.value = ( texture.isRenderTargetTexture === false ) ? - 1 : 1; - - } else { - - if ( this._equirectMaterial === null ) { - - this._equirectMaterial = _getEquirectMaterial(); - - } - - } - - const material = isCubeTexture ? this._cubemapMaterial : this._equirectMaterial; - const mesh = new Mesh( this._lodPlanes[ 0 ], material ); - - const uniforms = material.uniforms; - - uniforms[ 'envMap' ].value = texture; - - const size = this._cubeSize; - - _setViewport( cubeUVRenderTarget, 0, 0, 3 * size, 2 * size ); - - renderer.setRenderTarget( cubeUVRenderTarget ); - renderer.render( mesh, _flatCamera ); - - } - - _applyPMREM( cubeUVRenderTarget ) { - - const renderer = this._renderer; - const autoClear = renderer.autoClear; - renderer.autoClear = false; - - for ( let i = 1; i < this._lodPlanes.length; i ++ ) { - - const sigma = Math.sqrt( this._sigmas[ i ] * this._sigmas[ i ] - this._sigmas[ i - 1 ] * this._sigmas[ i - 1 ] ); - - const poleAxis = _axisDirections[ ( i - 1 ) % _axisDirections.length ]; - - this._blur( cubeUVRenderTarget, i - 1, i, sigma, poleAxis ); - - } - - renderer.autoClear = autoClear; - - } - - /** - * This is a two-pass Gaussian blur for a cubemap. Normally this is done - * vertically and horizontally, but this breaks down on a cube. Here we apply - * the blur latitudinally (around the poles), and then longitudinally (towards - * the poles) to approximate the orthogonally-separable blur. It is least - * accurate at the poles, but still does a decent job. - */ - _blur( cubeUVRenderTarget, lodIn, lodOut, sigma, poleAxis ) { - - const pingPongRenderTarget = this._pingPongRenderTarget; - - this._halfBlur( - cubeUVRenderTarget, - pingPongRenderTarget, - lodIn, - lodOut, - sigma, - 'latitudinal', - poleAxis ); - - this._halfBlur( - pingPongRenderTarget, - cubeUVRenderTarget, - lodOut, - lodOut, - sigma, - 'longitudinal', - poleAxis ); - - } - - _halfBlur( targetIn, targetOut, lodIn, lodOut, sigmaRadians, direction, poleAxis ) { - - const renderer = this._renderer; - const blurMaterial = this._blurMaterial; - - if ( direction !== 'latitudinal' && direction !== 'longitudinal' ) { - - console.error( - 'blur direction must be either latitudinal or longitudinal!' ); - - } - - // Number of standard deviations at which to cut off the discrete approximation. - const STANDARD_DEVIATIONS = 3; - - const blurMesh = new Mesh( this._lodPlanes[ lodOut ], blurMaterial ); - const blurUniforms = blurMaterial.uniforms; - - const pixels = this._sizeLods[ lodIn ] - 1; - const radiansPerPixel = isFinite( sigmaRadians ) ? Math.PI / ( 2 * pixels ) : 2 * Math.PI / ( 2 * MAX_SAMPLES - 1 ); - const sigmaPixels = sigmaRadians / radiansPerPixel; - const samples = isFinite( sigmaRadians ) ? 1 + Math.floor( STANDARD_DEVIATIONS * sigmaPixels ) : MAX_SAMPLES; - - if ( samples > MAX_SAMPLES ) { - - console.warn( `sigmaRadians, ${ - sigmaRadians}, is too large and will clip, as it requested ${ - samples} samples when the maximum is set to ${MAX_SAMPLES}` ); - - } - - const weights = []; - let sum = 0; - - for ( let i = 0; i < MAX_SAMPLES; ++ i ) { - - const x = i / sigmaPixels; - const weight = Math.exp( - x * x / 2 ); - weights.push( weight ); - - if ( i === 0 ) { - - sum += weight; - - } else if ( i < samples ) { - - sum += 2 * weight; - - } - - } - - for ( let i = 0; i < weights.length; i ++ ) { - - weights[ i ] = weights[ i ] / sum; - - } - - blurUniforms[ 'envMap' ].value = targetIn.texture; - blurUniforms[ 'samples' ].value = samples; - blurUniforms[ 'weights' ].value = weights; - blurUniforms[ 'latitudinal' ].value = direction === 'latitudinal'; - - if ( poleAxis ) { - - blurUniforms[ 'poleAxis' ].value = poleAxis; - - } - - const { _lodMax } = this; - blurUniforms[ 'dTheta' ].value = radiansPerPixel; - blurUniforms[ 'mipInt' ].value = _lodMax - lodIn; - - const outputSize = this._sizeLods[ lodOut ]; - const x = 3 * outputSize * ( lodOut > _lodMax - LOD_MIN ? lodOut - _lodMax + LOD_MIN : 0 ); - const y = 4 * ( this._cubeSize - outputSize ); - - _setViewport( targetOut, x, y, 3 * outputSize, 2 * outputSize ); - renderer.setRenderTarget( targetOut ); - renderer.render( blurMesh, _flatCamera ); - - } - -} - - - -function _createPlanes( lodMax ) { - - const lodPlanes = []; - const sizeLods = []; - const sigmas = []; - - let lod = lodMax; - - const totalLods = lodMax - LOD_MIN + 1 + EXTRA_LOD_SIGMA.length; - - for ( let i = 0; i < totalLods; i ++ ) { - - const sizeLod = Math.pow( 2, lod ); - sizeLods.push( sizeLod ); - let sigma = 1.0 / sizeLod; - - if ( i > lodMax - LOD_MIN ) { - - sigma = EXTRA_LOD_SIGMA[ i - lodMax + LOD_MIN - 1 ]; - - } else if ( i === 0 ) { - - sigma = 0; - - } - - sigmas.push( sigma ); - - const texelSize = 1.0 / ( sizeLod - 2 ); - const min = - texelSize; - const max = 1 + texelSize; - const uv1 = [ min, min, max, min, max, max, min, min, max, max, min, max ]; - - const cubeFaces = 6; - const vertices = 6; - const positionSize = 3; - const uvSize = 2; - const faceIndexSize = 1; - - const position = new Float32Array( positionSize * vertices * cubeFaces ); - const uv = new Float32Array( uvSize * vertices * cubeFaces ); - const faceIndex = new Float32Array( faceIndexSize * vertices * cubeFaces ); - - for ( let face = 0; face < cubeFaces; face ++ ) { - - const x = ( face % 3 ) * 2 / 3 - 1; - const y = face > 2 ? 0 : - 1; - const coordinates = [ - x, y, 0, - x + 2 / 3, y, 0, - x + 2 / 3, y + 1, 0, - x, y, 0, - x + 2 / 3, y + 1, 0, - x, y + 1, 0 - ]; - position.set( coordinates, positionSize * vertices * face ); - uv.set( uv1, uvSize * vertices * face ); - const fill = [ face, face, face, face, face, face ]; - faceIndex.set( fill, faceIndexSize * vertices * face ); - - } - - const planes = new BufferGeometry(); - planes.setAttribute( 'position', new BufferAttribute( position, positionSize ) ); - planes.setAttribute( 'uv', new BufferAttribute( uv, uvSize ) ); - planes.setAttribute( 'faceIndex', new BufferAttribute( faceIndex, faceIndexSize ) ); - lodPlanes.push( planes ); - - if ( lod > LOD_MIN ) { - - lod --; - - } - - } - - return { lodPlanes, sizeLods, sigmas }; - -} - -function _createRenderTarget( width, height, params ) { - - const cubeUVRenderTarget = new WebGLRenderTarget( width, height, params ); - cubeUVRenderTarget.texture.mapping = CubeUVReflectionMapping; - cubeUVRenderTarget.texture.name = 'PMREM.cubeUv'; - cubeUVRenderTarget.scissorTest = true; - return cubeUVRenderTarget; - -} - -function _setViewport( target, x, y, width, height ) { - - target.viewport.set( x, y, width, height ); - target.scissor.set( x, y, width, height ); - -} - -function _getBlurShader( lodMax, width, height ) { - - const weights = new Float32Array( MAX_SAMPLES ); - const poleAxis = new Vector3( 0, 1, 0 ); - const shaderMaterial = new ShaderMaterial( { - - name: 'SphericalGaussianBlur', - - defines: { - 'n': MAX_SAMPLES, - 'CUBEUV_TEXEL_WIDTH': 1.0 / width, - 'CUBEUV_TEXEL_HEIGHT': 1.0 / height, - 'CUBEUV_MAX_MIP': `${lodMax}.0`, - }, - - uniforms: { - 'envMap': { value: null }, - 'samples': { value: 1 }, - 'weights': { value: weights }, - 'latitudinal': { value: false }, - 'dTheta': { value: 0 }, - 'mipInt': { value: 0 }, - 'poleAxis': { value: poleAxis } - }, - - vertexShader: _getCommonVertexShader(), - - fragmentShader: /* glsl */` - - precision mediump float; - precision mediump int; - - varying vec3 vOutputDirection; - - uniform sampler2D envMap; - uniform int samples; - uniform float weights[ n ]; - uniform bool latitudinal; - uniform float dTheta; - uniform float mipInt; - uniform vec3 poleAxis; - - #define ENVMAP_TYPE_CUBE_UV - #include - - vec3 getSample( float theta, vec3 axis ) { - - float cosTheta = cos( theta ); - // Rodrigues' axis-angle rotation - vec3 sampleDirection = vOutputDirection * cosTheta - + cross( axis, vOutputDirection ) * sin( theta ) - + axis * dot( axis, vOutputDirection ) * ( 1.0 - cosTheta ); - - return bilinearCubeUV( envMap, sampleDirection, mipInt ); - - } - - void main() { - - vec3 axis = latitudinal ? poleAxis : cross( poleAxis, vOutputDirection ); - - if ( all( equal( axis, vec3( 0.0 ) ) ) ) { - - axis = vec3( vOutputDirection.z, 0.0, - vOutputDirection.x ); - - } - - axis = normalize( axis ); - - gl_FragColor = vec4( 0.0, 0.0, 0.0, 1.0 ); - gl_FragColor.rgb += weights[ 0 ] * getSample( 0.0, axis ); - - for ( int i = 1; i < n; i++ ) { - - if ( i >= samples ) { - - break; - - } - - float theta = dTheta * float( i ); - gl_FragColor.rgb += weights[ i ] * getSample( -1.0 * theta, axis ); - gl_FragColor.rgb += weights[ i ] * getSample( theta, axis ); - - } - - } - `, - - blending: NoBlending, - depthTest: false, - depthWrite: false - - } ); - - return shaderMaterial; - -} - -function _getEquirectMaterial() { - - return new ShaderMaterial( { - - name: 'EquirectangularToCubeUV', - - uniforms: { - 'envMap': { value: null } - }, - - vertexShader: _getCommonVertexShader(), - - fragmentShader: /* glsl */` - - precision mediump float; - precision mediump int; - - varying vec3 vOutputDirection; - - uniform sampler2D envMap; - - #include - - void main() { - - vec3 outputDirection = normalize( vOutputDirection ); - vec2 uv = equirectUv( outputDirection ); - - gl_FragColor = vec4( texture2D ( envMap, uv ).rgb, 1.0 ); - - } - `, - - blending: NoBlending, - depthTest: false, - depthWrite: false - - } ); - -} - -function _getCubemapMaterial() { - - return new ShaderMaterial( { - - name: 'CubemapToCubeUV', - - uniforms: { - 'envMap': { value: null }, - 'flipEnvMap': { value: - 1 } - }, - - vertexShader: _getCommonVertexShader(), - - fragmentShader: /* glsl */` - - precision mediump float; - precision mediump int; - - uniform float flipEnvMap; - - varying vec3 vOutputDirection; - - uniform samplerCube envMap; - - void main() { - - gl_FragColor = textureCube( envMap, vec3( flipEnvMap * vOutputDirection.x, vOutputDirection.yz ) ); - - } - `, - - blending: NoBlending, - depthTest: false, - depthWrite: false - - } ); - -} - -function _getCommonVertexShader() { - - return /* glsl */` - - precision mediump float; - precision mediump int; - - attribute float faceIndex; - - varying vec3 vOutputDirection; - - // RH coordinate system; PMREM face-indexing convention - vec3 getDirection( vec2 uv, float face ) { - - uv = 2.0 * uv - 1.0; - - vec3 direction = vec3( uv, 1.0 ); - - if ( face == 0.0 ) { - - direction = direction.zyx; // ( 1, v, u ) pos x - - } else if ( face == 1.0 ) { - - direction = direction.xzy; - direction.xz *= -1.0; // ( -u, 1, -v ) pos y - - } else if ( face == 2.0 ) { - - direction.x *= -1.0; // ( -u, v, 1 ) pos z - - } else if ( face == 3.0 ) { - - direction = direction.zyx; - direction.xz *= -1.0; // ( -1, v, -u ) neg x - - } else if ( face == 4.0 ) { - - direction = direction.xzy; - direction.xy *= -1.0; // ( -u, -1, v ) neg y - - } else if ( face == 5.0 ) { - - direction.z *= -1.0; // ( u, v, -1 ) neg z - - } - - return direction; - - } - - void main() { - - vOutputDirection = getDirection( uv, faceIndex ); - gl_Position = vec4( position, 1.0 ); - - } - `; - -} - -function WebGLCubeUVMaps( renderer ) { - - let cubeUVmaps = new WeakMap(); - - let pmremGenerator = null; - - function get( texture ) { - - if ( texture && texture.isTexture ) { - - const mapping = texture.mapping; - - const isEquirectMap = ( mapping === EquirectangularReflectionMapping || mapping === EquirectangularRefractionMapping ); - const isCubeMap = ( mapping === CubeReflectionMapping || mapping === CubeRefractionMapping ); - - // equirect/cube map to cubeUV conversion - - if ( isEquirectMap || isCubeMap ) { - - if ( texture.isRenderTargetTexture && texture.needsPMREMUpdate === true ) { - - texture.needsPMREMUpdate = false; - - let renderTarget = cubeUVmaps.get( texture ); - - if ( pmremGenerator === null ) pmremGenerator = new PMREMGenerator( renderer ); - - renderTarget = isEquirectMap ? pmremGenerator.fromEquirectangular( texture, renderTarget ) : pmremGenerator.fromCubemap( texture, renderTarget ); - cubeUVmaps.set( texture, renderTarget ); - - return renderTarget.texture; - - } else { - - if ( cubeUVmaps.has( texture ) ) { - - return cubeUVmaps.get( texture ).texture; - - } else { - - const image = texture.image; - - if ( ( isEquirectMap && image && image.height > 0 ) || ( isCubeMap && image && isCubeTextureComplete( image ) ) ) { - - if ( pmremGenerator === null ) pmremGenerator = new PMREMGenerator( renderer ); - - const renderTarget = isEquirectMap ? pmremGenerator.fromEquirectangular( texture ) : pmremGenerator.fromCubemap( texture ); - cubeUVmaps.set( texture, renderTarget ); - - texture.addEventListener( 'dispose', onTextureDispose ); - - return renderTarget.texture; - - } else { - - // image not yet ready. try the conversion next frame - - return null; - - } - - } - - } - - } - - } - - return texture; - - } - - function isCubeTextureComplete( image ) { - - let count = 0; - const length = 6; - - for ( let i = 0; i < length; i ++ ) { - - if ( image[ i ] !== undefined ) count ++; - - } - - return count === length; - - - } - - function onTextureDispose( event ) { - - const texture = event.target; - - texture.removeEventListener( 'dispose', onTextureDispose ); - - const cubemapUV = cubeUVmaps.get( texture ); - - if ( cubemapUV !== undefined ) { - - cubeUVmaps.delete( texture ); - cubemapUV.dispose(); - - } - - } - - function dispose() { - - cubeUVmaps = new WeakMap(); - - if ( pmremGenerator !== null ) { - - pmremGenerator.dispose(); - pmremGenerator = null; - - } - - } - - return { - get: get, - dispose: dispose - }; - -} - -function WebGLExtensions( gl ) { - - const extensions = {}; - - function getExtension( name ) { - - if ( extensions[ name ] !== undefined ) { - - return extensions[ name ]; - - } - - let extension; - - switch ( name ) { - - case 'WEBGL_depth_texture': - extension = gl.getExtension( 'WEBGL_depth_texture' ) || gl.getExtension( 'MOZ_WEBGL_depth_texture' ) || gl.getExtension( 'WEBKIT_WEBGL_depth_texture' ); - break; - - case 'EXT_texture_filter_anisotropic': - extension = gl.getExtension( 'EXT_texture_filter_anisotropic' ) || gl.getExtension( 'MOZ_EXT_texture_filter_anisotropic' ) || gl.getExtension( 'WEBKIT_EXT_texture_filter_anisotropic' ); - break; - - case 'WEBGL_compressed_texture_s3tc': - extension = gl.getExtension( 'WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'MOZ_WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_s3tc' ); - break; - - case 'WEBGL_compressed_texture_pvrtc': - extension = gl.getExtension( 'WEBGL_compressed_texture_pvrtc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_pvrtc' ); - break; - - default: - extension = gl.getExtension( name ); - - } - - extensions[ name ] = extension; - - return extension; - - } - - return { - - has: function ( name ) { - - return getExtension( name ) !== null; - - }, - - init: function ( capabilities ) { - - if ( capabilities.isWebGL2 ) { - - getExtension( 'EXT_color_buffer_float' ); - getExtension( 'WEBGL_clip_cull_distance' ); - - } else { - - getExtension( 'WEBGL_depth_texture' ); - getExtension( 'OES_texture_float' ); - getExtension( 'OES_texture_half_float' ); - getExtension( 'OES_texture_half_float_linear' ); - getExtension( 'OES_standard_derivatives' ); - getExtension( 'OES_element_index_uint' ); - getExtension( 'OES_vertex_array_object' ); - getExtension( 'ANGLE_instanced_arrays' ); - - } - - getExtension( 'OES_texture_float_linear' ); - getExtension( 'EXT_color_buffer_half_float' ); - getExtension( 'WEBGL_multisampled_render_to_texture' ); - - }, - - get: function ( name ) { - - const extension = getExtension( name ); - - if ( extension === null ) { - - console.warn( 'THREE.WebGLRenderer: ' + name + ' extension not supported.' ); - - } - - return extension; - - } - - }; - -} - -function WebGLGeometries( gl, attributes, info, bindingStates ) { - - const geometries = {}; - const wireframeAttributes = new WeakMap(); - - function onGeometryDispose( event ) { - - const geometry = event.target; - - if ( geometry.index !== null ) { - - attributes.remove( geometry.index ); - - } - - for ( const name in geometry.attributes ) { - - attributes.remove( geometry.attributes[ name ] ); - - } - - for ( const name in geometry.morphAttributes ) { - - const array = geometry.morphAttributes[ name ]; - - for ( let i = 0, l = array.length; i < l; i ++ ) { - - attributes.remove( array[ i ] ); - - } - - } - - geometry.removeEventListener( 'dispose', onGeometryDispose ); - - delete geometries[ geometry.id ]; - - const attribute = wireframeAttributes.get( geometry ); - - if ( attribute ) { - - attributes.remove( attribute ); - wireframeAttributes.delete( geometry ); - - } - - bindingStates.releaseStatesOfGeometry( geometry ); - - if ( geometry.isInstancedBufferGeometry === true ) { - - delete geometry._maxInstanceCount; - - } - - // - - info.memory.geometries --; - - } - - function get( object, geometry ) { - - if ( geometries[ geometry.id ] === true ) return geometry; - - geometry.addEventListener( 'dispose', onGeometryDispose ); - - geometries[ geometry.id ] = true; - - info.memory.geometries ++; - - return geometry; - - } - - function update( geometry ) { - - const geometryAttributes = geometry.attributes; - - // Updating index buffer in VAO now. See WebGLBindingStates. - - for ( const name in geometryAttributes ) { - - attributes.update( geometryAttributes[ name ], gl.ARRAY_BUFFER ); - - } - - // morph targets - - const morphAttributes = geometry.morphAttributes; - - for ( const name in morphAttributes ) { - - const array = morphAttributes[ name ]; - - for ( let i = 0, l = array.length; i < l; i ++ ) { - - attributes.update( array[ i ], gl.ARRAY_BUFFER ); - - } - - } - - } - - function updateWireframeAttribute( geometry ) { - - const indices = []; - - const geometryIndex = geometry.index; - const geometryPosition = geometry.attributes.position; - let version = 0; - - if ( geometryIndex !== null ) { - - const array = geometryIndex.array; - version = geometryIndex.version; - - for ( let i = 0, l = array.length; i < l; i += 3 ) { - - const a = array[ i + 0 ]; - const b = array[ i + 1 ]; - const c = array[ i + 2 ]; - - indices.push( a, b, b, c, c, a ); - - } - - } else if ( geometryPosition !== undefined ) { - - const array = geometryPosition.array; - version = geometryPosition.version; - - for ( let i = 0, l = ( array.length / 3 ) - 1; i < l; i += 3 ) { - - const a = i + 0; - const b = i + 1; - const c = i + 2; - - indices.push( a, b, b, c, c, a ); - - } - - } else { - - return; - - } - - const attribute = new ( arrayNeedsUint32( indices ) ? Uint32BufferAttribute : Uint16BufferAttribute )( indices, 1 ); - attribute.version = version; - - // Updating index buffer in VAO now. See WebGLBindingStates - - // - - const previousAttribute = wireframeAttributes.get( geometry ); - - if ( previousAttribute ) attributes.remove( previousAttribute ); - - // - - wireframeAttributes.set( geometry, attribute ); - - } - - function getWireframeAttribute( geometry ) { - - const currentAttribute = wireframeAttributes.get( geometry ); - - if ( currentAttribute ) { - - const geometryIndex = geometry.index; - - if ( geometryIndex !== null ) { - - // if the attribute is obsolete, create a new one - - if ( currentAttribute.version < geometryIndex.version ) { - - updateWireframeAttribute( geometry ); - - } - - } - - } else { - - updateWireframeAttribute( geometry ); - - } - - return wireframeAttributes.get( geometry ); - - } - - return { - - get: get, - update: update, - - getWireframeAttribute: getWireframeAttribute - - }; - -} - -function WebGLIndexedBufferRenderer( gl, extensions, info, capabilities ) { - - const isWebGL2 = capabilities.isWebGL2; - - let mode; - - function setMode( value ) { - - mode = value; - - } - - let type, bytesPerElement; - - function setIndex( value ) { - - type = value.type; - bytesPerElement = value.bytesPerElement; - - } - - function render( start, count ) { - - gl.drawElements( mode, count, type, start * bytesPerElement ); - - info.update( count, mode, 1 ); - - } - - function renderInstances( start, count, primcount ) { - - if ( primcount === 0 ) return; - - let extension, methodName; - - if ( isWebGL2 ) { - - extension = gl; - methodName = 'drawElementsInstanced'; - - } else { - - extension = extensions.get( 'ANGLE_instanced_arrays' ); - methodName = 'drawElementsInstancedANGLE'; - - if ( extension === null ) { - - console.error( 'THREE.WebGLIndexedBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' ); - return; - - } - - } - - extension[ methodName ]( mode, count, type, start * bytesPerElement, primcount ); - - info.update( count, mode, primcount ); - - } - - function renderMultiDraw( starts, counts, drawCount ) { - - if ( drawCount === 0 ) return; - - const extension = extensions.get( 'WEBGL_multi_draw' ); - if ( extension === null ) { - - for ( let i = 0; i < drawCount; i ++ ) { - - this.render( starts[ i ] / bytesPerElement, counts[ i ] ); - - } - - } else { - - extension.multiDrawElementsWEBGL( mode, counts, 0, type, starts, 0, drawCount ); - - let elementCount = 0; - for ( let i = 0; i < drawCount; i ++ ) { - - elementCount += counts[ i ]; - - } - - info.update( elementCount, mode, 1 ); - - } - - } - - // - - this.setMode = setMode; - this.setIndex = setIndex; - this.render = render; - this.renderInstances = renderInstances; - this.renderMultiDraw = renderMultiDraw; - -} - -function WebGLInfo( gl ) { - - const memory = { - geometries: 0, - textures: 0 - }; - - const render = { - frame: 0, - calls: 0, - triangles: 0, - points: 0, - lines: 0 - }; - - function update( count, mode, instanceCount ) { - - render.calls ++; - - switch ( mode ) { - - case gl.TRIANGLES: - render.triangles += instanceCount * ( count / 3 ); - break; - - case gl.LINES: - render.lines += instanceCount * ( count / 2 ); - break; - - case gl.LINE_STRIP: - render.lines += instanceCount * ( count - 1 ); - break; - - case gl.LINE_LOOP: - render.lines += instanceCount * count; - break; - - case gl.POINTS: - render.points += instanceCount * count; - break; - - default: - console.error( 'THREE.WebGLInfo: Unknown draw mode:', mode ); - break; - - } - - } - - function reset() { - - render.calls = 0; - render.triangles = 0; - render.points = 0; - render.lines = 0; - - } - - return { - memory: memory, - render: render, - programs: null, - autoReset: true, - reset: reset, - update: update - }; - -} - -function numericalSort( a, b ) { - - return a[ 0 ] - b[ 0 ]; - -} - -function absNumericalSort( a, b ) { - - return Math.abs( b[ 1 ] ) - Math.abs( a[ 1 ] ); - -} - -function WebGLMorphtargets( gl, capabilities, textures ) { - - const influencesList = {}; - const morphInfluences = new Float32Array( 8 ); - const morphTextures = new WeakMap(); - const morph = new Vector4(); - - const workInfluences = []; - - for ( let i = 0; i < 8; i ++ ) { - - workInfluences[ i ] = [ i, 0 ]; - - } - - function update( object, geometry, program ) { - - const objectInfluences = object.morphTargetInfluences; - - if ( capabilities.isWebGL2 === true ) { - - // instead of using attributes, the WebGL 2 code path encodes morph targets - // into an array of data textures. Each layer represents a single morph target. - - const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color; - const morphTargetsCount = ( morphAttribute !== undefined ) ? morphAttribute.length : 0; - - let entry = morphTextures.get( geometry ); - - if ( entry === undefined || entry.count !== morphTargetsCount ) { - - if ( entry !== undefined ) entry.texture.dispose(); - - const hasMorphPosition = geometry.morphAttributes.position !== undefined; - const hasMorphNormals = geometry.morphAttributes.normal !== undefined; - const hasMorphColors = geometry.morphAttributes.color !== undefined; - - const morphTargets = geometry.morphAttributes.position || []; - const morphNormals = geometry.morphAttributes.normal || []; - const morphColors = geometry.morphAttributes.color || []; - - let vertexDataCount = 0; - - if ( hasMorphPosition === true ) vertexDataCount = 1; - if ( hasMorphNormals === true ) vertexDataCount = 2; - if ( hasMorphColors === true ) vertexDataCount = 3; - - let width = geometry.attributes.position.count * vertexDataCount; - let height = 1; - - if ( width > capabilities.maxTextureSize ) { - - height = Math.ceil( width / capabilities.maxTextureSize ); - width = capabilities.maxTextureSize; - - } - - const buffer = new Float32Array( width * height * 4 * morphTargetsCount ); - - const texture = new DataArrayTexture( buffer, width, height, morphTargetsCount ); - texture.type = FloatType; - texture.needsUpdate = true; - - // fill buffer - - const vertexDataStride = vertexDataCount * 4; - - for ( let i = 0; i < morphTargetsCount; i ++ ) { - - const morphTarget = morphTargets[ i ]; - const morphNormal = morphNormals[ i ]; - const morphColor = morphColors[ i ]; - - const offset = width * height * 4 * i; - - for ( let j = 0; j < morphTarget.count; j ++ ) { - - const stride = j * vertexDataStride; - - if ( hasMorphPosition === true ) { - - morph.fromBufferAttribute( morphTarget, j ); - - buffer[ offset + stride + 0 ] = morph.x; - buffer[ offset + stride + 1 ] = morph.y; - buffer[ offset + stride + 2 ] = morph.z; - buffer[ offset + stride + 3 ] = 0; - - } - - if ( hasMorphNormals === true ) { - - morph.fromBufferAttribute( morphNormal, j ); - - buffer[ offset + stride + 4 ] = morph.x; - buffer[ offset + stride + 5 ] = morph.y; - buffer[ offset + stride + 6 ] = morph.z; - buffer[ offset + stride + 7 ] = 0; - - } - - if ( hasMorphColors === true ) { - - morph.fromBufferAttribute( morphColor, j ); - - buffer[ offset + stride + 8 ] = morph.x; - buffer[ offset + stride + 9 ] = morph.y; - buffer[ offset + stride + 10 ] = morph.z; - buffer[ offset + stride + 11 ] = ( morphColor.itemSize === 4 ) ? morph.w : 1; - - } - - } - - } - - entry = { - count: morphTargetsCount, - texture: texture, - size: new Vector2( width, height ) - }; - - morphTextures.set( geometry, entry ); - - function disposeTexture() { - - texture.dispose(); - - morphTextures.delete( geometry ); - - geometry.removeEventListener( 'dispose', disposeTexture ); - - } - - geometry.addEventListener( 'dispose', disposeTexture ); - - } - - // - - let morphInfluencesSum = 0; - - for ( let i = 0; i < objectInfluences.length; i ++ ) { - - morphInfluencesSum += objectInfluences[ i ]; - - } - - const morphBaseInfluence = geometry.morphTargetsRelative ? 1 : 1 - morphInfluencesSum; - - program.getUniforms().setValue( gl, 'morphTargetBaseInfluence', morphBaseInfluence ); - program.getUniforms().setValue( gl, 'morphTargetInfluences', objectInfluences ); - - program.getUniforms().setValue( gl, 'morphTargetsTexture', entry.texture, textures ); - program.getUniforms().setValue( gl, 'morphTargetsTextureSize', entry.size ); - - - } else { - - // When object doesn't have morph target influences defined, we treat it as a 0-length array - // This is important to make sure we set up morphTargetBaseInfluence / morphTargetInfluences - - const length = objectInfluences === undefined ? 0 : objectInfluences.length; - - let influences = influencesList[ geometry.id ]; - - if ( influences === undefined || influences.length !== length ) { - - // initialise list - - influences = []; - - for ( let i = 0; i < length; i ++ ) { - - influences[ i ] = [ i, 0 ]; - - } - - influencesList[ geometry.id ] = influences; - - } - - // Collect influences - - for ( let i = 0; i < length; i ++ ) { - - const influence = influences[ i ]; - - influence[ 0 ] = i; - influence[ 1 ] = objectInfluences[ i ]; - - } - - influences.sort( absNumericalSort ); - - for ( let i = 0; i < 8; i ++ ) { - - if ( i < length && influences[ i ][ 1 ] ) { - - workInfluences[ i ][ 0 ] = influences[ i ][ 0 ]; - workInfluences[ i ][ 1 ] = influences[ i ][ 1 ]; - - } else { - - workInfluences[ i ][ 0 ] = Number.MAX_SAFE_INTEGER; - workInfluences[ i ][ 1 ] = 0; - - } - - } - - workInfluences.sort( numericalSort ); - - const morphTargets = geometry.morphAttributes.position; - const morphNormals = geometry.morphAttributes.normal; - - let morphInfluencesSum = 0; - - for ( let i = 0; i < 8; i ++ ) { - - const influence = workInfluences[ i ]; - const index = influence[ 0 ]; - const value = influence[ 1 ]; - - if ( index !== Number.MAX_SAFE_INTEGER && value ) { - - if ( morphTargets && geometry.getAttribute( 'morphTarget' + i ) !== morphTargets[ index ] ) { - - geometry.setAttribute( 'morphTarget' + i, morphTargets[ index ] ); - - } - - if ( morphNormals && geometry.getAttribute( 'morphNormal' + i ) !== morphNormals[ index ] ) { - - geometry.setAttribute( 'morphNormal' + i, morphNormals[ index ] ); - - } - - morphInfluences[ i ] = value; - morphInfluencesSum += value; - - } else { - - if ( morphTargets && geometry.hasAttribute( 'morphTarget' + i ) === true ) { - - geometry.deleteAttribute( 'morphTarget' + i ); - - } - - if ( morphNormals && geometry.hasAttribute( 'morphNormal' + i ) === true ) { - - geometry.deleteAttribute( 'morphNormal' + i ); - - } - - morphInfluences[ i ] = 0; - - } - - } - - // GLSL shader uses formula baseinfluence * base + sum(target * influence) - // This allows us to switch between absolute morphs and relative morphs without changing shader code - // When baseinfluence = 1 - sum(influence), the above is equivalent to sum((target - base) * influence) - const morphBaseInfluence = geometry.morphTargetsRelative ? 1 : 1 - morphInfluencesSum; - - program.getUniforms().setValue( gl, 'morphTargetBaseInfluence', morphBaseInfluence ); - program.getUniforms().setValue( gl, 'morphTargetInfluences', morphInfluences ); - - } - - } - - return { - - update: update - - }; - -} - -function WebGLObjects( gl, geometries, attributes, info ) { - - let updateMap = new WeakMap(); - - function update( object ) { - - const frame = info.render.frame; - - const geometry = object.geometry; - const buffergeometry = geometries.get( object, geometry ); - - // Update once per frame - - if ( updateMap.get( buffergeometry ) !== frame ) { - - geometries.update( buffergeometry ); - - updateMap.set( buffergeometry, frame ); - - } - - if ( object.isInstancedMesh ) { - - if ( object.hasEventListener( 'dispose', onInstancedMeshDispose ) === false ) { - - object.addEventListener( 'dispose', onInstancedMeshDispose ); - - } - - if ( updateMap.get( object ) !== frame ) { - - attributes.update( object.instanceMatrix, gl.ARRAY_BUFFER ); - - if ( object.instanceColor !== null ) { - - attributes.update( object.instanceColor, gl.ARRAY_BUFFER ); - - } - - updateMap.set( object, frame ); - - } - - } - - if ( object.isSkinnedMesh ) { - - const skeleton = object.skeleton; - - if ( updateMap.get( skeleton ) !== frame ) { - - skeleton.update(); - - updateMap.set( skeleton, frame ); - - } - - } - - return buffergeometry; - - } - - function dispose() { - - updateMap = new WeakMap(); - - } - - function onInstancedMeshDispose( event ) { - - const instancedMesh = event.target; - - instancedMesh.removeEventListener( 'dispose', onInstancedMeshDispose ); - - attributes.remove( instancedMesh.instanceMatrix ); - - if ( instancedMesh.instanceColor !== null ) attributes.remove( instancedMesh.instanceColor ); - - } - - return { - - update: update, - dispose: dispose - - }; - -} - -class DepthTexture extends Texture { - - constructor( width, height, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, format ) { - - format = format !== undefined ? format : DepthFormat; - - if ( format !== DepthFormat && format !== DepthStencilFormat ) { - - throw new Error( 'DepthTexture format must be either THREE.DepthFormat or THREE.DepthStencilFormat' ); - - } - - if ( type === undefined && format === DepthFormat ) type = UnsignedIntType; - if ( type === undefined && format === DepthStencilFormat ) type = UnsignedInt248Type; - - super( null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); - - this.isDepthTexture = true; - - this.image = { width: width, height: height }; - - this.magFilter = magFilter !== undefined ? magFilter : NearestFilter; - this.minFilter = minFilter !== undefined ? minFilter : NearestFilter; - - this.flipY = false; - this.generateMipmaps = false; - - this.compareFunction = null; - - } - - - copy( source ) { - - super.copy( source ); - - this.compareFunction = source.compareFunction; - - return this; - - } - - toJSON( meta ) { - - const data = super.toJSON( meta ); - - if ( this.compareFunction !== null ) data.compareFunction = this.compareFunction; - - return data; - - } - -} - -/** - * Uniforms of a program. - * Those form a tree structure with a special top-level container for the root, - * which you get by calling 'new WebGLUniforms( gl, program )'. - * - * - * Properties of inner nodes including the top-level container: - * - * .seq - array of nested uniforms - * .map - nested uniforms by name - * - * - * Methods of all nodes except the top-level container: - * - * .setValue( gl, value, [textures] ) - * - * uploads a uniform value(s) - * the 'textures' parameter is needed for sampler uniforms - * - * - * Static methods of the top-level container (textures factorizations): - * - * .upload( gl, seq, values, textures ) - * - * sets uniforms in 'seq' to 'values[id].value' - * - * .seqWithValue( seq, values ) : filteredSeq - * - * filters 'seq' entries with corresponding entry in values - * - * - * Methods of the top-level container (textures factorizations): - * - * .setValue( gl, name, value, textures ) - * - * sets uniform with name 'name' to 'value' - * - * .setOptional( gl, obj, prop ) - * - * like .set for an optional property of the object - * - */ - - -const emptyTexture = /*@__PURE__*/ new Texture(); - -const emptyShadowTexture = /*@__PURE__*/ new DepthTexture( 1, 1 ); -emptyShadowTexture.compareFunction = LessEqualCompare; - -const emptyArrayTexture = /*@__PURE__*/ new DataArrayTexture(); -const empty3dTexture = /*@__PURE__*/ new Data3DTexture(); -const emptyCubeTexture = /*@__PURE__*/ new CubeTexture(); - -// --- Utilities --- - -// Array Caches (provide typed arrays for temporary by size) - -const arrayCacheF32 = []; -const arrayCacheI32 = []; - -// Float32Array caches used for uploading Matrix uniforms - -const mat4array = new Float32Array( 16 ); -const mat3array = new Float32Array( 9 ); -const mat2array = new Float32Array( 4 ); - -// Flattening for arrays of vectors and matrices - -function flatten( array, nBlocks, blockSize ) { - - const firstElem = array[ 0 ]; - - if ( firstElem <= 0 || firstElem > 0 ) return array; - // unoptimized: ! isNaN( firstElem ) - // see http://jacksondunstan.com/articles/983 - - const n = nBlocks * blockSize; - let r = arrayCacheF32[ n ]; - - if ( r === undefined ) { - - r = new Float32Array( n ); - arrayCacheF32[ n ] = r; - - } - - if ( nBlocks !== 0 ) { - - firstElem.toArray( r, 0 ); - - for ( let i = 1, offset = 0; i !== nBlocks; ++ i ) { - - offset += blockSize; - array[ i ].toArray( r, offset ); - - } - - } - - return r; - -} - -function arraysEqual( a, b ) { - - if ( a.length !== b.length ) return false; - - for ( let i = 0, l = a.length; i < l; i ++ ) { - - if ( a[ i ] !== b[ i ] ) return false; - - } - - return true; - -} - -function copyArray( a, b ) { - - for ( let i = 0, l = b.length; i < l; i ++ ) { - - a[ i ] = b[ i ]; - - } - -} - -// Texture unit allocation - -function allocTexUnits( textures, n ) { - - let r = arrayCacheI32[ n ]; - - if ( r === undefined ) { - - r = new Int32Array( n ); - arrayCacheI32[ n ] = r; - - } - - for ( let i = 0; i !== n; ++ i ) { - - r[ i ] = textures.allocateTextureUnit(); - - } - - return r; - -} - -// --- Setters --- - -// Note: Defining these methods externally, because they come in a bunch -// and this way their names minify. - -// Single scalar - -function setValueV1f( gl, v ) { - - const cache = this.cache; - - if ( cache[ 0 ] === v ) return; - - gl.uniform1f( this.addr, v ); - - cache[ 0 ] = v; - -} - -// Single float vector (from flat array or THREE.VectorN) - -function setValueV2f( gl, v ) { - - const cache = this.cache; - - if ( v.x !== undefined ) { - - if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y ) { - - gl.uniform2f( this.addr, v.x, v.y ); - - cache[ 0 ] = v.x; - cache[ 1 ] = v.y; - - } - - } else { - - if ( arraysEqual( cache, v ) ) return; - - gl.uniform2fv( this.addr, v ); - - copyArray( cache, v ); - - } - -} - -function setValueV3f( gl, v ) { - - const cache = this.cache; - - if ( v.x !== undefined ) { - - if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z ) { - - gl.uniform3f( this.addr, v.x, v.y, v.z ); - - cache[ 0 ] = v.x; - cache[ 1 ] = v.y; - cache[ 2 ] = v.z; - - } - - } else if ( v.r !== undefined ) { - - if ( cache[ 0 ] !== v.r || cache[ 1 ] !== v.g || cache[ 2 ] !== v.b ) { - - gl.uniform3f( this.addr, v.r, v.g, v.b ); - - cache[ 0 ] = v.r; - cache[ 1 ] = v.g; - cache[ 2 ] = v.b; - - } - - } else { - - if ( arraysEqual( cache, v ) ) return; - - gl.uniform3fv( this.addr, v ); - - copyArray( cache, v ); - - } - -} - -function setValueV4f( gl, v ) { - - const cache = this.cache; - - if ( v.x !== undefined ) { - - if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z || cache[ 3 ] !== v.w ) { - - gl.uniform4f( this.addr, v.x, v.y, v.z, v.w ); - - cache[ 0 ] = v.x; - cache[ 1 ] = v.y; - cache[ 2 ] = v.z; - cache[ 3 ] = v.w; - - } - - } else { - - if ( arraysEqual( cache, v ) ) return; - - gl.uniform4fv( this.addr, v ); - - copyArray( cache, v ); - - } - -} - -// Single matrix (from flat array or THREE.MatrixN) - -function setValueM2( gl, v ) { - - const cache = this.cache; - const elements = v.elements; - - if ( elements === undefined ) { - - if ( arraysEqual( cache, v ) ) return; - - gl.uniformMatrix2fv( this.addr, false, v ); - - copyArray( cache, v ); - - } else { - - if ( arraysEqual( cache, elements ) ) return; - - mat2array.set( elements ); - - gl.uniformMatrix2fv( this.addr, false, mat2array ); - - copyArray( cache, elements ); - - } - -} - -function setValueM3( gl, v ) { - - const cache = this.cache; - const elements = v.elements; - - if ( elements === undefined ) { - - if ( arraysEqual( cache, v ) ) return; - - gl.uniformMatrix3fv( this.addr, false, v ); - - copyArray( cache, v ); - - } else { - - if ( arraysEqual( cache, elements ) ) return; - - mat3array.set( elements ); - - gl.uniformMatrix3fv( this.addr, false, mat3array ); - - copyArray( cache, elements ); - - } - -} - -function setValueM4( gl, v ) { - - const cache = this.cache; - const elements = v.elements; - - if ( elements === undefined ) { - - if ( arraysEqual( cache, v ) ) return; - - gl.uniformMatrix4fv( this.addr, false, v ); - - copyArray( cache, v ); - - } else { - - if ( arraysEqual( cache, elements ) ) return; - - mat4array.set( elements ); - - gl.uniformMatrix4fv( this.addr, false, mat4array ); - - copyArray( cache, elements ); - - } - -} - -// Single integer / boolean - -function setValueV1i( gl, v ) { - - const cache = this.cache; - - if ( cache[ 0 ] === v ) return; - - gl.uniform1i( this.addr, v ); - - cache[ 0 ] = v; - -} - -// Single integer / boolean vector (from flat array or THREE.VectorN) - -function setValueV2i( gl, v ) { - - const cache = this.cache; - - if ( v.x !== undefined ) { - - if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y ) { - - gl.uniform2i( this.addr, v.x, v.y ); - - cache[ 0 ] = v.x; - cache[ 1 ] = v.y; - - } - - } else { - - if ( arraysEqual( cache, v ) ) return; - - gl.uniform2iv( this.addr, v ); - - copyArray( cache, v ); - - } - -} - -function setValueV3i( gl, v ) { - - const cache = this.cache; - - if ( v.x !== undefined ) { - - if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z ) { - - gl.uniform3i( this.addr, v.x, v.y, v.z ); - - cache[ 0 ] = v.x; - cache[ 1 ] = v.y; - cache[ 2 ] = v.z; - - } - - } else { - - if ( arraysEqual( cache, v ) ) return; - - gl.uniform3iv( this.addr, v ); - - copyArray( cache, v ); - - } - -} - -function setValueV4i( gl, v ) { - - const cache = this.cache; - - if ( v.x !== undefined ) { - - if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z || cache[ 3 ] !== v.w ) { - - gl.uniform4i( this.addr, v.x, v.y, v.z, v.w ); - - cache[ 0 ] = v.x; - cache[ 1 ] = v.y; - cache[ 2 ] = v.z; - cache[ 3 ] = v.w; - - } - - } else { - - if ( arraysEqual( cache, v ) ) return; - - gl.uniform4iv( this.addr, v ); - - copyArray( cache, v ); - - } - -} - -// Single unsigned integer - -function setValueV1ui( gl, v ) { - - const cache = this.cache; - - if ( cache[ 0 ] === v ) return; - - gl.uniform1ui( this.addr, v ); - - cache[ 0 ] = v; - -} - -// Single unsigned integer vector (from flat array or THREE.VectorN) - -function setValueV2ui( gl, v ) { - - const cache = this.cache; - - if ( v.x !== undefined ) { - - if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y ) { - - gl.uniform2ui( this.addr, v.x, v.y ); - - cache[ 0 ] = v.x; - cache[ 1 ] = v.y; - - } - - } else { - - if ( arraysEqual( cache, v ) ) return; - - gl.uniform2uiv( this.addr, v ); - - copyArray( cache, v ); - - } - -} - -function setValueV3ui( gl, v ) { - - const cache = this.cache; - - if ( v.x !== undefined ) { - - if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z ) { - - gl.uniform3ui( this.addr, v.x, v.y, v.z ); - - cache[ 0 ] = v.x; - cache[ 1 ] = v.y; - cache[ 2 ] = v.z; - - } - - } else { - - if ( arraysEqual( cache, v ) ) return; - - gl.uniform3uiv( this.addr, v ); - - copyArray( cache, v ); - - } - -} - -function setValueV4ui( gl, v ) { - - const cache = this.cache; - - if ( v.x !== undefined ) { - - if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z || cache[ 3 ] !== v.w ) { - - gl.uniform4ui( this.addr, v.x, v.y, v.z, v.w ); - - cache[ 0 ] = v.x; - cache[ 1 ] = v.y; - cache[ 2 ] = v.z; - cache[ 3 ] = v.w; - - } - - } else { - - if ( arraysEqual( cache, v ) ) return; - - gl.uniform4uiv( this.addr, v ); - - copyArray( cache, v ); - - } - -} - - -// Single texture (2D / Cube) - -function setValueT1( gl, v, textures ) { - - const cache = this.cache; - const unit = textures.allocateTextureUnit(); - - if ( cache[ 0 ] !== unit ) { - - gl.uniform1i( this.addr, unit ); - cache[ 0 ] = unit; - - } - - const emptyTexture2D = ( this.type === gl.SAMPLER_2D_SHADOW ) ? emptyShadowTexture : emptyTexture; - - textures.setTexture2D( v || emptyTexture2D, unit ); - -} - -function setValueT3D1( gl, v, textures ) { - - const cache = this.cache; - const unit = textures.allocateTextureUnit(); - - if ( cache[ 0 ] !== unit ) { - - gl.uniform1i( this.addr, unit ); - cache[ 0 ] = unit; - - } - - textures.setTexture3D( v || empty3dTexture, unit ); - -} - -function setValueT6( gl, v, textures ) { - - const cache = this.cache; - const unit = textures.allocateTextureUnit(); - - if ( cache[ 0 ] !== unit ) { - - gl.uniform1i( this.addr, unit ); - cache[ 0 ] = unit; - - } - - textures.setTextureCube( v || emptyCubeTexture, unit ); - -} - -function setValueT2DArray1( gl, v, textures ) { - - const cache = this.cache; - const unit = textures.allocateTextureUnit(); - - if ( cache[ 0 ] !== unit ) { - - gl.uniform1i( this.addr, unit ); - cache[ 0 ] = unit; - - } - - textures.setTexture2DArray( v || emptyArrayTexture, unit ); - -} - -// Helper to pick the right setter for the singular case - -function getSingularSetter( type ) { - - switch ( type ) { - - case 0x1406: return setValueV1f; // FLOAT - case 0x8b50: return setValueV2f; // _VEC2 - case 0x8b51: return setValueV3f; // _VEC3 - case 0x8b52: return setValueV4f; // _VEC4 - - case 0x8b5a: return setValueM2; // _MAT2 - case 0x8b5b: return setValueM3; // _MAT3 - case 0x8b5c: return setValueM4; // _MAT4 - - case 0x1404: case 0x8b56: return setValueV1i; // INT, BOOL - case 0x8b53: case 0x8b57: return setValueV2i; // _VEC2 - case 0x8b54: case 0x8b58: return setValueV3i; // _VEC3 - case 0x8b55: case 0x8b59: return setValueV4i; // _VEC4 - - case 0x1405: return setValueV1ui; // UINT - case 0x8dc6: return setValueV2ui; // _VEC2 - case 0x8dc7: return setValueV3ui; // _VEC3 - case 0x8dc8: return setValueV4ui; // _VEC4 - - case 0x8b5e: // SAMPLER_2D - case 0x8d66: // SAMPLER_EXTERNAL_OES - case 0x8dca: // INT_SAMPLER_2D - case 0x8dd2: // UNSIGNED_INT_SAMPLER_2D - case 0x8b62: // SAMPLER_2D_SHADOW - return setValueT1; - - case 0x8b5f: // SAMPLER_3D - case 0x8dcb: // INT_SAMPLER_3D - case 0x8dd3: // UNSIGNED_INT_SAMPLER_3D - return setValueT3D1; - - case 0x8b60: // SAMPLER_CUBE - case 0x8dcc: // INT_SAMPLER_CUBE - case 0x8dd4: // UNSIGNED_INT_SAMPLER_CUBE - case 0x8dc5: // SAMPLER_CUBE_SHADOW - return setValueT6; - - case 0x8dc1: // SAMPLER_2D_ARRAY - case 0x8dcf: // INT_SAMPLER_2D_ARRAY - case 0x8dd7: // UNSIGNED_INT_SAMPLER_2D_ARRAY - case 0x8dc4: // SAMPLER_2D_ARRAY_SHADOW - return setValueT2DArray1; - - } - -} - - -// Array of scalars - -function setValueV1fArray( gl, v ) { - - gl.uniform1fv( this.addr, v ); - -} - -// Array of vectors (from flat array or array of THREE.VectorN) - -function setValueV2fArray( gl, v ) { - - const data = flatten( v, this.size, 2 ); - - gl.uniform2fv( this.addr, data ); - -} - -function setValueV3fArray( gl, v ) { - - const data = flatten( v, this.size, 3 ); - - gl.uniform3fv( this.addr, data ); - -} - -function setValueV4fArray( gl, v ) { - - const data = flatten( v, this.size, 4 ); - - gl.uniform4fv( this.addr, data ); - -} - -// Array of matrices (from flat array or array of THREE.MatrixN) - -function setValueM2Array( gl, v ) { - - const data = flatten( v, this.size, 4 ); - - gl.uniformMatrix2fv( this.addr, false, data ); - -} - -function setValueM3Array( gl, v ) { - - const data = flatten( v, this.size, 9 ); - - gl.uniformMatrix3fv( this.addr, false, data ); - -} - -function setValueM4Array( gl, v ) { - - const data = flatten( v, this.size, 16 ); - - gl.uniformMatrix4fv( this.addr, false, data ); - -} - -// Array of integer / boolean - -function setValueV1iArray( gl, v ) { - - gl.uniform1iv( this.addr, v ); - -} - -// Array of integer / boolean vectors (from flat array) - -function setValueV2iArray( gl, v ) { - - gl.uniform2iv( this.addr, v ); - -} - -function setValueV3iArray( gl, v ) { - - gl.uniform3iv( this.addr, v ); - -} - -function setValueV4iArray( gl, v ) { - - gl.uniform4iv( this.addr, v ); - -} - -// Array of unsigned integer - -function setValueV1uiArray( gl, v ) { - - gl.uniform1uiv( this.addr, v ); - -} - -// Array of unsigned integer vectors (from flat array) - -function setValueV2uiArray( gl, v ) { - - gl.uniform2uiv( this.addr, v ); - -} - -function setValueV3uiArray( gl, v ) { - - gl.uniform3uiv( this.addr, v ); - -} - -function setValueV4uiArray( gl, v ) { - - gl.uniform4uiv( this.addr, v ); - -} - - -// Array of textures (2D / 3D / Cube / 2DArray) - -function setValueT1Array( gl, v, textures ) { - - const cache = this.cache; - - const n = v.length; - - const units = allocTexUnits( textures, n ); - - if ( ! arraysEqual( cache, units ) ) { - - gl.uniform1iv( this.addr, units ); - - copyArray( cache, units ); - - } - - for ( let i = 0; i !== n; ++ i ) { - - textures.setTexture2D( v[ i ] || emptyTexture, units[ i ] ); - - } - -} - -function setValueT3DArray( gl, v, textures ) { - - const cache = this.cache; - - const n = v.length; - - const units = allocTexUnits( textures, n ); - - if ( ! arraysEqual( cache, units ) ) { - - gl.uniform1iv( this.addr, units ); - - copyArray( cache, units ); - - } - - for ( let i = 0; i !== n; ++ i ) { - - textures.setTexture3D( v[ i ] || empty3dTexture, units[ i ] ); - - } - -} - -function setValueT6Array( gl, v, textures ) { - - const cache = this.cache; - - const n = v.length; - - const units = allocTexUnits( textures, n ); - - if ( ! arraysEqual( cache, units ) ) { - - gl.uniform1iv( this.addr, units ); - - copyArray( cache, units ); - - } - - for ( let i = 0; i !== n; ++ i ) { - - textures.setTextureCube( v[ i ] || emptyCubeTexture, units[ i ] ); - - } - -} - -function setValueT2DArrayArray( gl, v, textures ) { - - const cache = this.cache; - - const n = v.length; - - const units = allocTexUnits( textures, n ); - - if ( ! arraysEqual( cache, units ) ) { - - gl.uniform1iv( this.addr, units ); - - copyArray( cache, units ); - - } - - for ( let i = 0; i !== n; ++ i ) { - - textures.setTexture2DArray( v[ i ] || emptyArrayTexture, units[ i ] ); - - } - -} - - -// Helper to pick the right setter for a pure (bottom-level) array - -function getPureArraySetter( type ) { - - switch ( type ) { - - case 0x1406: return setValueV1fArray; // FLOAT - case 0x8b50: return setValueV2fArray; // _VEC2 - case 0x8b51: return setValueV3fArray; // _VEC3 - case 0x8b52: return setValueV4fArray; // _VEC4 - - case 0x8b5a: return setValueM2Array; // _MAT2 - case 0x8b5b: return setValueM3Array; // _MAT3 - case 0x8b5c: return setValueM4Array; // _MAT4 - - case 0x1404: case 0x8b56: return setValueV1iArray; // INT, BOOL - case 0x8b53: case 0x8b57: return setValueV2iArray; // _VEC2 - case 0x8b54: case 0x8b58: return setValueV3iArray; // _VEC3 - case 0x8b55: case 0x8b59: return setValueV4iArray; // _VEC4 - - case 0x1405: return setValueV1uiArray; // UINT - case 0x8dc6: return setValueV2uiArray; // _VEC2 - case 0x8dc7: return setValueV3uiArray; // _VEC3 - case 0x8dc8: return setValueV4uiArray; // _VEC4 - - case 0x8b5e: // SAMPLER_2D - case 0x8d66: // SAMPLER_EXTERNAL_OES - case 0x8dca: // INT_SAMPLER_2D - case 0x8dd2: // UNSIGNED_INT_SAMPLER_2D - case 0x8b62: // SAMPLER_2D_SHADOW - return setValueT1Array; - - case 0x8b5f: // SAMPLER_3D - case 0x8dcb: // INT_SAMPLER_3D - case 0x8dd3: // UNSIGNED_INT_SAMPLER_3D - return setValueT3DArray; - - case 0x8b60: // SAMPLER_CUBE - case 0x8dcc: // INT_SAMPLER_CUBE - case 0x8dd4: // UNSIGNED_INT_SAMPLER_CUBE - case 0x8dc5: // SAMPLER_CUBE_SHADOW - return setValueT6Array; - - case 0x8dc1: // SAMPLER_2D_ARRAY - case 0x8dcf: // INT_SAMPLER_2D_ARRAY - case 0x8dd7: // UNSIGNED_INT_SAMPLER_2D_ARRAY - case 0x8dc4: // SAMPLER_2D_ARRAY_SHADOW - return setValueT2DArrayArray; - - } - -} - -// --- Uniform Classes --- - -class SingleUniform { - - constructor( id, activeInfo, addr ) { - - this.id = id; - this.addr = addr; - this.cache = []; - this.type = activeInfo.type; - this.setValue = getSingularSetter( activeInfo.type ); - - // this.path = activeInfo.name; // DEBUG - - } - -} - -class PureArrayUniform { - - constructor( id, activeInfo, addr ) { - - this.id = id; - this.addr = addr; - this.cache = []; - this.type = activeInfo.type; - this.size = activeInfo.size; - this.setValue = getPureArraySetter( activeInfo.type ); - - // this.path = activeInfo.name; // DEBUG - - } - -} - -class StructuredUniform { - - constructor( id ) { - - this.id = id; - - this.seq = []; - this.map = {}; - - } - - setValue( gl, value, textures ) { - - const seq = this.seq; - - for ( let i = 0, n = seq.length; i !== n; ++ i ) { - - const u = seq[ i ]; - u.setValue( gl, value[ u.id ], textures ); - - } - - } - -} - -// --- Top-level --- - -// Parser - builds up the property tree from the path strings - -const RePathPart = /(\w+)(\])?(\[|\.)?/g; - -// extracts -// - the identifier (member name or array index) -// - followed by an optional right bracket (found when array index) -// - followed by an optional left bracket or dot (type of subscript) -// -// Note: These portions can be read in a non-overlapping fashion and -// allow straightforward parsing of the hierarchy that WebGL encodes -// in the uniform names. - -function addUniform( container, uniformObject ) { - - container.seq.push( uniformObject ); - container.map[ uniformObject.id ] = uniformObject; - -} - -function parseUniform( activeInfo, addr, container ) { - - const path = activeInfo.name, - pathLength = path.length; - - // reset RegExp object, because of the early exit of a previous run - RePathPart.lastIndex = 0; - - while ( true ) { - - const match = RePathPart.exec( path ), - matchEnd = RePathPart.lastIndex; - - let id = match[ 1 ]; - const idIsIndex = match[ 2 ] === ']', - subscript = match[ 3 ]; - - if ( idIsIndex ) id = id | 0; // convert to integer - - if ( subscript === undefined || subscript === '[' && matchEnd + 2 === pathLength ) { - - // bare name or "pure" bottom-level array "[0]" suffix - - addUniform( container, subscript === undefined ? - new SingleUniform( id, activeInfo, addr ) : - new PureArrayUniform( id, activeInfo, addr ) ); - - break; - - } else { - - // step into inner node / create it in case it doesn't exist - - const map = container.map; - let next = map[ id ]; - - if ( next === undefined ) { - - next = new StructuredUniform( id ); - addUniform( container, next ); - - } - - container = next; - - } - - } - -} - -// Root Container - -class WebGLUniforms { - - constructor( gl, program ) { - - this.seq = []; - this.map = {}; - - const n = gl.getProgramParameter( program, gl.ACTIVE_UNIFORMS ); - - for ( let i = 0; i < n; ++ i ) { - - const info = gl.getActiveUniform( program, i ), - addr = gl.getUniformLocation( program, info.name ); - - parseUniform( info, addr, this ); - - } - - } - - setValue( gl, name, value, textures ) { - - const u = this.map[ name ]; - - if ( u !== undefined ) u.setValue( gl, value, textures ); - - } - - setOptional( gl, object, name ) { - - const v = object[ name ]; - - if ( v !== undefined ) this.setValue( gl, name, v ); - - } - - static upload( gl, seq, values, textures ) { - - for ( let i = 0, n = seq.length; i !== n; ++ i ) { - - const u = seq[ i ], - v = values[ u.id ]; - - if ( v.needsUpdate !== false ) { - - // note: always updating when .needsUpdate is undefined - u.setValue( gl, v.value, textures ); - - } - - } - - } - - static seqWithValue( seq, values ) { - - const r = []; - - for ( let i = 0, n = seq.length; i !== n; ++ i ) { - - const u = seq[ i ]; - if ( u.id in values ) r.push( u ); - - } - - return r; - - } - -} - -function WebGLShader( gl, type, string ) { - - const shader = gl.createShader( type ); - - gl.shaderSource( shader, string ); - gl.compileShader( shader ); - - return shader; - -} - -// From https://www.khronos.org/registry/webgl/extensions/KHR_parallel_shader_compile/ -const COMPLETION_STATUS_KHR = 0x91B1; - -let programIdCount = 0; - -function handleSource( string, errorLine ) { - - const lines = string.split( '\n' ); - const lines2 = []; - - const from = Math.max( errorLine - 6, 0 ); - const to = Math.min( errorLine + 6, lines.length ); - - for ( let i = from; i < to; i ++ ) { - - const line = i + 1; - lines2.push( `${line === errorLine ? '>' : ' '} ${line}: ${lines[ i ]}` ); - - } - - return lines2.join( '\n' ); - -} - -function getEncodingComponents( colorSpace ) { - - const workingPrimaries = ColorManagement.getPrimaries( ColorManagement.workingColorSpace ); - const encodingPrimaries = ColorManagement.getPrimaries( colorSpace ); - - let gamutMapping; - - if ( workingPrimaries === encodingPrimaries ) { - - gamutMapping = ''; - - } else if ( workingPrimaries === P3Primaries && encodingPrimaries === Rec709Primaries ) { - - gamutMapping = 'LinearDisplayP3ToLinearSRGB'; - - } else if ( workingPrimaries === Rec709Primaries && encodingPrimaries === P3Primaries ) { - - gamutMapping = 'LinearSRGBToLinearDisplayP3'; - - } - - switch ( colorSpace ) { - - case LinearSRGBColorSpace: - case LinearDisplayP3ColorSpace: - return [ gamutMapping, 'LinearTransferOETF' ]; - - case SRGBColorSpace: - case DisplayP3ColorSpace: - return [ gamutMapping, 'sRGBTransferOETF' ]; - - default: - console.warn( 'THREE.WebGLProgram: Unsupported color space:', colorSpace ); - return [ gamutMapping, 'LinearTransferOETF' ]; - - } - -} - -function getShaderErrors( gl, shader, type ) { - - const status = gl.getShaderParameter( shader, gl.COMPILE_STATUS ); - const errors = gl.getShaderInfoLog( shader ).trim(); - - if ( status && errors === '' ) return ''; - - const errorMatches = /ERROR: 0:(\d+)/.exec( errors ); - if ( errorMatches ) { - - // --enable-privileged-webgl-extension - // console.log( '**' + type + '**', gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( shader ) ); - - const errorLine = parseInt( errorMatches[ 1 ] ); - return type.toUpperCase() + '\n\n' + errors + '\n\n' + handleSource( gl.getShaderSource( shader ), errorLine ); - - } else { - - return errors; - - } - -} - -function getTexelEncodingFunction( functionName, colorSpace ) { - - const components = getEncodingComponents( colorSpace ); - return `vec4 ${functionName}( vec4 value ) { return ${components[ 0 ]}( ${components[ 1 ]}( value ) ); }`; - -} - -function getToneMappingFunction( functionName, toneMapping ) { - - let toneMappingName; - - switch ( toneMapping ) { - - case LinearToneMapping: - toneMappingName = 'Linear'; - break; - - case ReinhardToneMapping: - toneMappingName = 'Reinhard'; - break; - - case CineonToneMapping: - toneMappingName = 'OptimizedCineon'; - break; - - case ACESFilmicToneMapping: - toneMappingName = 'ACESFilmic'; - break; - - case AgXToneMapping: - toneMappingName = 'AgX'; - break; - - case CustomToneMapping: - toneMappingName = 'Custom'; - break; - - default: - console.warn( 'THREE.WebGLProgram: Unsupported toneMapping:', toneMapping ); - toneMappingName = 'Linear'; - - } - - return 'vec3 ' + functionName + '( vec3 color ) { return ' + toneMappingName + 'ToneMapping( color ); }'; - -} - -function generateExtensions( parameters ) { - - const chunks = [ - ( parameters.extensionDerivatives || !! parameters.envMapCubeUVHeight || parameters.bumpMap || parameters.normalMapTangentSpace || parameters.clearcoatNormalMap || parameters.flatShading || parameters.alphaToCoverage || parameters.shaderID === 'physical' ) ? '#extension GL_OES_standard_derivatives : enable' : '', - ( parameters.extensionFragDepth || parameters.logarithmicDepthBuffer ) && parameters.rendererExtensionFragDepth ? '#extension GL_EXT_frag_depth : enable' : '', - ( parameters.extensionDrawBuffers && parameters.rendererExtensionDrawBuffers ) ? '#extension GL_EXT_draw_buffers : require' : '', - ( parameters.extensionShaderTextureLOD || parameters.envMap || parameters.transmission ) && parameters.rendererExtensionShaderTextureLod ? '#extension GL_EXT_shader_texture_lod : enable' : '' - ]; - - return chunks.filter( filterEmptyLine ).join( '\n' ); - -} - -function generateVertexExtensions( parameters ) { - - const chunks = [ - parameters.extensionClipCullDistance ? '#extension GL_ANGLE_clip_cull_distance : require' : '', - parameters.extensionMultiDraw ? '#extension GL_ANGLE_multi_draw : require' : '', - ]; - - return chunks.filter( filterEmptyLine ).join( '\n' ); - -} - -function generateDefines( defines ) { - - const chunks = []; - - for ( const name in defines ) { - - const value = defines[ name ]; - - if ( value === false ) continue; - - chunks.push( '#define ' + name + ' ' + value ); - - } - - return chunks.join( '\n' ); - -} - -function fetchAttributeLocations( gl, program ) { - - const attributes = {}; - - const n = gl.getProgramParameter( program, gl.ACTIVE_ATTRIBUTES ); - - for ( let i = 0; i < n; i ++ ) { - - const info = gl.getActiveAttrib( program, i ); - const name = info.name; - - let locationSize = 1; - if ( info.type === gl.FLOAT_MAT2 ) locationSize = 2; - if ( info.type === gl.FLOAT_MAT3 ) locationSize = 3; - if ( info.type === gl.FLOAT_MAT4 ) locationSize = 4; - - // console.log( 'THREE.WebGLProgram: ACTIVE VERTEX ATTRIBUTE:', name, i ); - - attributes[ name ] = { - type: info.type, - location: gl.getAttribLocation( program, name ), - locationSize: locationSize - }; - - } - - return attributes; - -} - -function filterEmptyLine( string ) { - - return string !== ''; - -} - -function replaceLightNums( string, parameters ) { - - const numSpotLightCoords = parameters.numSpotLightShadows + parameters.numSpotLightMaps - parameters.numSpotLightShadowsWithMaps; - - return string - .replace( /NUM_DIR_LIGHTS/g, parameters.numDirLights ) - .replace( /NUM_SPOT_LIGHTS/g, parameters.numSpotLights ) - .replace( /NUM_SPOT_LIGHT_MAPS/g, parameters.numSpotLightMaps ) - .replace( /NUM_SPOT_LIGHT_COORDS/g, numSpotLightCoords ) - .replace( /NUM_RECT_AREA_LIGHTS/g, parameters.numRectAreaLights ) - .replace( /NUM_POINT_LIGHTS/g, parameters.numPointLights ) - .replace( /NUM_HEMI_LIGHTS/g, parameters.numHemiLights ) - .replace( /NUM_DIR_LIGHT_SHADOWS/g, parameters.numDirLightShadows ) - .replace( /NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS/g, parameters.numSpotLightShadowsWithMaps ) - .replace( /NUM_SPOT_LIGHT_SHADOWS/g, parameters.numSpotLightShadows ) - .replace( /NUM_POINT_LIGHT_SHADOWS/g, parameters.numPointLightShadows ); - -} - -function replaceClippingPlaneNums( string, parameters ) { - - return string - .replace( /NUM_CLIPPING_PLANES/g, parameters.numClippingPlanes ) - .replace( /UNION_CLIPPING_PLANES/g, ( parameters.numClippingPlanes - parameters.numClipIntersection ) ); - -} - -// Resolve Includes - -const includePattern = /^[ \t]*#include +<([\w\d./]+)>/gm; - -function resolveIncludes( string ) { - - return string.replace( includePattern, includeReplacer ); - -} - -const shaderChunkMap = new Map( [ - [ 'encodings_fragment', 'colorspace_fragment' ], // @deprecated, r154 - [ 'encodings_pars_fragment', 'colorspace_pars_fragment' ], // @deprecated, r154 - [ 'output_fragment', 'opaque_fragment' ], // @deprecated, r154 -] ); - -function includeReplacer( match, include ) { - - let string = ShaderChunk[ include ]; - - if ( string === undefined ) { - - const newInclude = shaderChunkMap.get( include ); - - if ( newInclude !== undefined ) { - - string = ShaderChunk[ newInclude ]; - console.warn( 'THREE.WebGLRenderer: Shader chunk "%s" has been deprecated. Use "%s" instead.', include, newInclude ); - - } else { - - throw new Error( 'Can not resolve #include <' + include + '>' ); - - } - - } - - return resolveIncludes( string ); - -} - -// Unroll Loops - -const unrollLoopPattern = /#pragma unroll_loop_start\s+for\s*\(\s*int\s+i\s*=\s*(\d+)\s*;\s*i\s*<\s*(\d+)\s*;\s*i\s*\+\+\s*\)\s*{([\s\S]+?)}\s+#pragma unroll_loop_end/g; - -function unrollLoops( string ) { - - return string.replace( unrollLoopPattern, loopReplacer ); - -} - -function loopReplacer( match, start, end, snippet ) { - - let string = ''; - - for ( let i = parseInt( start ); i < parseInt( end ); i ++ ) { - - string += snippet - .replace( /\[\s*i\s*\]/g, '[ ' + i + ' ]' ) - .replace( /UNROLLED_LOOP_INDEX/g, i ); - - } - - return string; - -} - -// - -function generatePrecision( parameters ) { - - let precisionstring = `precision ${parameters.precision} float; - precision ${parameters.precision} int; - precision ${parameters.precision} sampler2D; - precision ${parameters.precision} samplerCube; - `; - - if ( parameters.isWebGL2 ) { - - precisionstring += `precision ${parameters.precision} sampler3D; - precision ${parameters.precision} sampler2DArray; - precision ${parameters.precision} sampler2DShadow; - precision ${parameters.precision} samplerCubeShadow; - precision ${parameters.precision} sampler2DArrayShadow; - precision ${parameters.precision} isampler2D; - precision ${parameters.precision} isampler3D; - precision ${parameters.precision} isamplerCube; - precision ${parameters.precision} isampler2DArray; - precision ${parameters.precision} usampler2D; - precision ${parameters.precision} usampler3D; - precision ${parameters.precision} usamplerCube; - precision ${parameters.precision} usampler2DArray; - `; - - } - - if ( parameters.precision === 'highp' ) { - - precisionstring += '\n#define HIGH_PRECISION'; - - } else if ( parameters.precision === 'mediump' ) { - - precisionstring += '\n#define MEDIUM_PRECISION'; - - } else if ( parameters.precision === 'lowp' ) { - - precisionstring += '\n#define LOW_PRECISION'; - - } - - return precisionstring; - -} - -function generateShadowMapTypeDefine( parameters ) { - - let shadowMapTypeDefine = 'SHADOWMAP_TYPE_BASIC'; - - if ( parameters.shadowMapType === PCFShadowMap ) { - - shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF'; - - } else if ( parameters.shadowMapType === PCFSoftShadowMap ) { - - shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF_SOFT'; - - } else if ( parameters.shadowMapType === VSMShadowMap ) { - - shadowMapTypeDefine = 'SHADOWMAP_TYPE_VSM'; - - } - - return shadowMapTypeDefine; - -} - -function generateEnvMapTypeDefine( parameters ) { - - let envMapTypeDefine = 'ENVMAP_TYPE_CUBE'; - - if ( parameters.envMap ) { - - switch ( parameters.envMapMode ) { - - case CubeReflectionMapping: - case CubeRefractionMapping: - envMapTypeDefine = 'ENVMAP_TYPE_CUBE'; - break; - - case CubeUVReflectionMapping: - envMapTypeDefine = 'ENVMAP_TYPE_CUBE_UV'; - break; - - } - - } - - return envMapTypeDefine; - -} - -function generateEnvMapModeDefine( parameters ) { - - let envMapModeDefine = 'ENVMAP_MODE_REFLECTION'; - - if ( parameters.envMap ) { - - switch ( parameters.envMapMode ) { - - case CubeRefractionMapping: - - envMapModeDefine = 'ENVMAP_MODE_REFRACTION'; - break; - - } - - } - - return envMapModeDefine; - -} - -function generateEnvMapBlendingDefine( parameters ) { - - let envMapBlendingDefine = 'ENVMAP_BLENDING_NONE'; - - if ( parameters.envMap ) { - - switch ( parameters.combine ) { - - case MultiplyOperation: - envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY'; - break; - - case MixOperation: - envMapBlendingDefine = 'ENVMAP_BLENDING_MIX'; - break; - - case AddOperation: - envMapBlendingDefine = 'ENVMAP_BLENDING_ADD'; - break; - - } - - } - - return envMapBlendingDefine; - -} - -function generateCubeUVSize( parameters ) { - - const imageHeight = parameters.envMapCubeUVHeight; - - if ( imageHeight === null ) return null; - - const maxMip = Math.log2( imageHeight ) - 2; - - const texelHeight = 1.0 / imageHeight; - - const texelWidth = 1.0 / ( 3 * Math.max( Math.pow( 2, maxMip ), 7 * 16 ) ); - - return { texelWidth, texelHeight, maxMip }; - -} - -function WebGLProgram( renderer, cacheKey, parameters, bindingStates ) { - - // TODO Send this event to Three.js DevTools - // console.log( 'WebGLProgram', cacheKey ); - - const gl = renderer.getContext(); - - const defines = parameters.defines; - - let vertexShader = parameters.vertexShader; - let fragmentShader = parameters.fragmentShader; - - const shadowMapTypeDefine = generateShadowMapTypeDefine( parameters ); - const envMapTypeDefine = generateEnvMapTypeDefine( parameters ); - const envMapModeDefine = generateEnvMapModeDefine( parameters ); - const envMapBlendingDefine = generateEnvMapBlendingDefine( parameters ); - const envMapCubeUVSize = generateCubeUVSize( parameters ); - - const customExtensions = parameters.isWebGL2 ? '' : generateExtensions( parameters ); - - const customVertexExtensions = generateVertexExtensions( parameters ); - - const customDefines = generateDefines( defines ); - - const program = gl.createProgram(); - - let prefixVertex, prefixFragment; - let versionString = parameters.glslVersion ? '#version ' + parameters.glslVersion + '\n' : ''; - - if ( parameters.isRawShaderMaterial ) { - - prefixVertex = [ - - '#define SHADER_TYPE ' + parameters.shaderType, - '#define SHADER_NAME ' + parameters.shaderName, - - customDefines - - ].filter( filterEmptyLine ).join( '\n' ); - - if ( prefixVertex.length > 0 ) { - - prefixVertex += '\n'; - - } - - prefixFragment = [ - - customExtensions, - - '#define SHADER_TYPE ' + parameters.shaderType, - '#define SHADER_NAME ' + parameters.shaderName, - - customDefines - - ].filter( filterEmptyLine ).join( '\n' ); - - if ( prefixFragment.length > 0 ) { - - prefixFragment += '\n'; - - } - - } else { - - prefixVertex = [ - - generatePrecision( parameters ), - - '#define SHADER_TYPE ' + parameters.shaderType, - '#define SHADER_NAME ' + parameters.shaderName, - - customDefines, - - parameters.extensionClipCullDistance ? '#define USE_CLIP_DISTANCE' : '', - parameters.batching ? '#define USE_BATCHING' : '', - parameters.instancing ? '#define USE_INSTANCING' : '', - parameters.instancingColor ? '#define USE_INSTANCING_COLOR' : '', - - parameters.useFog && parameters.fog ? '#define USE_FOG' : '', - parameters.useFog && parameters.fogExp2 ? '#define FOG_EXP2' : '', - - parameters.map ? '#define USE_MAP' : '', - parameters.envMap ? '#define USE_ENVMAP' : '', - parameters.envMap ? '#define ' + envMapModeDefine : '', - parameters.lightMap ? '#define USE_LIGHTMAP' : '', - parameters.aoMap ? '#define USE_AOMAP' : '', - parameters.bumpMap ? '#define USE_BUMPMAP' : '', - parameters.normalMap ? '#define USE_NORMALMAP' : '', - parameters.normalMapObjectSpace ? '#define USE_NORMALMAP_OBJECTSPACE' : '', - parameters.normalMapTangentSpace ? '#define USE_NORMALMAP_TANGENTSPACE' : '', - parameters.displacementMap ? '#define USE_DISPLACEMENTMAP' : '', - parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '', - - parameters.anisotropy ? '#define USE_ANISOTROPY' : '', - parameters.anisotropyMap ? '#define USE_ANISOTROPYMAP' : '', - - parameters.clearcoatMap ? '#define USE_CLEARCOATMAP' : '', - parameters.clearcoatRoughnessMap ? '#define USE_CLEARCOAT_ROUGHNESSMAP' : '', - parameters.clearcoatNormalMap ? '#define USE_CLEARCOAT_NORMALMAP' : '', - - parameters.iridescenceMap ? '#define USE_IRIDESCENCEMAP' : '', - parameters.iridescenceThicknessMap ? '#define USE_IRIDESCENCE_THICKNESSMAP' : '', - - parameters.specularMap ? '#define USE_SPECULARMAP' : '', - parameters.specularColorMap ? '#define USE_SPECULAR_COLORMAP' : '', - parameters.specularIntensityMap ? '#define USE_SPECULAR_INTENSITYMAP' : '', - - parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '', - parameters.metalnessMap ? '#define USE_METALNESSMAP' : '', - parameters.alphaMap ? '#define USE_ALPHAMAP' : '', - parameters.alphaHash ? '#define USE_ALPHAHASH' : '', - - parameters.transmission ? '#define USE_TRANSMISSION' : '', - parameters.transmissionMap ? '#define USE_TRANSMISSIONMAP' : '', - parameters.thicknessMap ? '#define USE_THICKNESSMAP' : '', - - parameters.sheenColorMap ? '#define USE_SHEEN_COLORMAP' : '', - parameters.sheenRoughnessMap ? '#define USE_SHEEN_ROUGHNESSMAP' : '', - - // - - parameters.mapUv ? '#define MAP_UV ' + parameters.mapUv : '', - parameters.alphaMapUv ? '#define ALPHAMAP_UV ' + parameters.alphaMapUv : '', - parameters.lightMapUv ? '#define LIGHTMAP_UV ' + parameters.lightMapUv : '', - parameters.aoMapUv ? '#define AOMAP_UV ' + parameters.aoMapUv : '', - parameters.emissiveMapUv ? '#define EMISSIVEMAP_UV ' + parameters.emissiveMapUv : '', - parameters.bumpMapUv ? '#define BUMPMAP_UV ' + parameters.bumpMapUv : '', - parameters.normalMapUv ? '#define NORMALMAP_UV ' + parameters.normalMapUv : '', - parameters.displacementMapUv ? '#define DISPLACEMENTMAP_UV ' + parameters.displacementMapUv : '', - - parameters.metalnessMapUv ? '#define METALNESSMAP_UV ' + parameters.metalnessMapUv : '', - parameters.roughnessMapUv ? '#define ROUGHNESSMAP_UV ' + parameters.roughnessMapUv : '', - - parameters.anisotropyMapUv ? '#define ANISOTROPYMAP_UV ' + parameters.anisotropyMapUv : '', - - parameters.clearcoatMapUv ? '#define CLEARCOATMAP_UV ' + parameters.clearcoatMapUv : '', - parameters.clearcoatNormalMapUv ? '#define CLEARCOAT_NORMALMAP_UV ' + parameters.clearcoatNormalMapUv : '', - parameters.clearcoatRoughnessMapUv ? '#define CLEARCOAT_ROUGHNESSMAP_UV ' + parameters.clearcoatRoughnessMapUv : '', - - parameters.iridescenceMapUv ? '#define IRIDESCENCEMAP_UV ' + parameters.iridescenceMapUv : '', - parameters.iridescenceThicknessMapUv ? '#define IRIDESCENCE_THICKNESSMAP_UV ' + parameters.iridescenceThicknessMapUv : '', - - parameters.sheenColorMapUv ? '#define SHEEN_COLORMAP_UV ' + parameters.sheenColorMapUv : '', - parameters.sheenRoughnessMapUv ? '#define SHEEN_ROUGHNESSMAP_UV ' + parameters.sheenRoughnessMapUv : '', - - parameters.specularMapUv ? '#define SPECULARMAP_UV ' + parameters.specularMapUv : '', - parameters.specularColorMapUv ? '#define SPECULAR_COLORMAP_UV ' + parameters.specularColorMapUv : '', - parameters.specularIntensityMapUv ? '#define SPECULAR_INTENSITYMAP_UV ' + parameters.specularIntensityMapUv : '', - - parameters.transmissionMapUv ? '#define TRANSMISSIONMAP_UV ' + parameters.transmissionMapUv : '', - parameters.thicknessMapUv ? '#define THICKNESSMAP_UV ' + parameters.thicknessMapUv : '', - - // - - parameters.vertexTangents && parameters.flatShading === false ? '#define USE_TANGENT' : '', - parameters.vertexColors ? '#define USE_COLOR' : '', - parameters.vertexAlphas ? '#define USE_COLOR_ALPHA' : '', - parameters.vertexUv1s ? '#define USE_UV1' : '', - parameters.vertexUv2s ? '#define USE_UV2' : '', - parameters.vertexUv3s ? '#define USE_UV3' : '', - - parameters.pointsUvs ? '#define USE_POINTS_UV' : '', - - parameters.flatShading ? '#define FLAT_SHADED' : '', - - parameters.skinning ? '#define USE_SKINNING' : '', - - parameters.morphTargets ? '#define USE_MORPHTARGETS' : '', - parameters.morphNormals && parameters.flatShading === false ? '#define USE_MORPHNORMALS' : '', - ( parameters.morphColors && parameters.isWebGL2 ) ? '#define USE_MORPHCOLORS' : '', - ( parameters.morphTargetsCount > 0 && parameters.isWebGL2 ) ? '#define MORPHTARGETS_TEXTURE' : '', - ( parameters.morphTargetsCount > 0 && parameters.isWebGL2 ) ? '#define MORPHTARGETS_TEXTURE_STRIDE ' + parameters.morphTextureStride : '', - ( parameters.morphTargetsCount > 0 && parameters.isWebGL2 ) ? '#define MORPHTARGETS_COUNT ' + parameters.morphTargetsCount : '', - parameters.doubleSided ? '#define DOUBLE_SIDED' : '', - parameters.flipSided ? '#define FLIP_SIDED' : '', - - parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '', - parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '', - - parameters.sizeAttenuation ? '#define USE_SIZEATTENUATION' : '', - - parameters.numLightProbes > 0 ? '#define USE_LIGHT_PROBES' : '', - - parameters.useLegacyLights ? '#define LEGACY_LIGHTS' : '', - - parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '', - ( parameters.logarithmicDepthBuffer && parameters.rendererExtensionFragDepth ) ? '#define USE_LOGDEPTHBUF_EXT' : '', - - 'uniform mat4 modelMatrix;', - 'uniform mat4 modelViewMatrix;', - 'uniform mat4 projectionMatrix;', - 'uniform mat4 viewMatrix;', - 'uniform mat3 normalMatrix;', - 'uniform vec3 cameraPosition;', - 'uniform bool isOrthographic;', - - '#ifdef USE_INSTANCING', - - ' attribute mat4 instanceMatrix;', - - '#endif', - - '#ifdef USE_INSTANCING_COLOR', - - ' attribute vec3 instanceColor;', - - '#endif', - - 'attribute vec3 position;', - 'attribute vec3 normal;', - 'attribute vec2 uv;', - - '#ifdef USE_UV1', - - ' attribute vec2 uv1;', - - '#endif', - - '#ifdef USE_UV2', - - ' attribute vec2 uv2;', - - '#endif', - - '#ifdef USE_UV3', - - ' attribute vec2 uv3;', - - '#endif', - - '#ifdef USE_TANGENT', - - ' attribute vec4 tangent;', - - '#endif', - - '#if defined( USE_COLOR_ALPHA )', - - ' attribute vec4 color;', - - '#elif defined( USE_COLOR )', - - ' attribute vec3 color;', - - '#endif', - - '#if ( defined( USE_MORPHTARGETS ) && ! defined( MORPHTARGETS_TEXTURE ) )', - - ' attribute vec3 morphTarget0;', - ' attribute vec3 morphTarget1;', - ' attribute vec3 morphTarget2;', - ' attribute vec3 morphTarget3;', - - ' #ifdef USE_MORPHNORMALS', - - ' attribute vec3 morphNormal0;', - ' attribute vec3 morphNormal1;', - ' attribute vec3 morphNormal2;', - ' attribute vec3 morphNormal3;', - - ' #else', - - ' attribute vec3 morphTarget4;', - ' attribute vec3 morphTarget5;', - ' attribute vec3 morphTarget6;', - ' attribute vec3 morphTarget7;', - - ' #endif', - - '#endif', - - '#ifdef USE_SKINNING', - - ' attribute vec4 skinIndex;', - ' attribute vec4 skinWeight;', - - '#endif', - - '\n' - - ].filter( filterEmptyLine ).join( '\n' ); - - prefixFragment = [ - - customExtensions, - - generatePrecision( parameters ), - - '#define SHADER_TYPE ' + parameters.shaderType, - '#define SHADER_NAME ' + parameters.shaderName, - - customDefines, - - parameters.useFog && parameters.fog ? '#define USE_FOG' : '', - parameters.useFog && parameters.fogExp2 ? '#define FOG_EXP2' : '', - - parameters.alphaToCoverage ? '#define ALPHA_TO_COVERAGE' : '', - parameters.map ? '#define USE_MAP' : '', - parameters.matcap ? '#define USE_MATCAP' : '', - parameters.envMap ? '#define USE_ENVMAP' : '', - parameters.envMap ? '#define ' + envMapTypeDefine : '', - parameters.envMap ? '#define ' + envMapModeDefine : '', - parameters.envMap ? '#define ' + envMapBlendingDefine : '', - envMapCubeUVSize ? '#define CUBEUV_TEXEL_WIDTH ' + envMapCubeUVSize.texelWidth : '', - envMapCubeUVSize ? '#define CUBEUV_TEXEL_HEIGHT ' + envMapCubeUVSize.texelHeight : '', - envMapCubeUVSize ? '#define CUBEUV_MAX_MIP ' + envMapCubeUVSize.maxMip + '.0' : '', - parameters.lightMap ? '#define USE_LIGHTMAP' : '', - parameters.aoMap ? '#define USE_AOMAP' : '', - parameters.bumpMap ? '#define USE_BUMPMAP' : '', - parameters.normalMap ? '#define USE_NORMALMAP' : '', - parameters.normalMapObjectSpace ? '#define USE_NORMALMAP_OBJECTSPACE' : '', - parameters.normalMapTangentSpace ? '#define USE_NORMALMAP_TANGENTSPACE' : '', - parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '', - - parameters.anisotropy ? '#define USE_ANISOTROPY' : '', - parameters.anisotropyMap ? '#define USE_ANISOTROPYMAP' : '', - - parameters.clearcoat ? '#define USE_CLEARCOAT' : '', - parameters.clearcoatMap ? '#define USE_CLEARCOATMAP' : '', - parameters.clearcoatRoughnessMap ? '#define USE_CLEARCOAT_ROUGHNESSMAP' : '', - parameters.clearcoatNormalMap ? '#define USE_CLEARCOAT_NORMALMAP' : '', - - parameters.iridescence ? '#define USE_IRIDESCENCE' : '', - parameters.iridescenceMap ? '#define USE_IRIDESCENCEMAP' : '', - parameters.iridescenceThicknessMap ? '#define USE_IRIDESCENCE_THICKNESSMAP' : '', - - parameters.specularMap ? '#define USE_SPECULARMAP' : '', - parameters.specularColorMap ? '#define USE_SPECULAR_COLORMAP' : '', - parameters.specularIntensityMap ? '#define USE_SPECULAR_INTENSITYMAP' : '', - - parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '', - parameters.metalnessMap ? '#define USE_METALNESSMAP' : '', - - parameters.alphaMap ? '#define USE_ALPHAMAP' : '', - parameters.alphaTest ? '#define USE_ALPHATEST' : '', - parameters.alphaHash ? '#define USE_ALPHAHASH' : '', - - parameters.sheen ? '#define USE_SHEEN' : '', - parameters.sheenColorMap ? '#define USE_SHEEN_COLORMAP' : '', - parameters.sheenRoughnessMap ? '#define USE_SHEEN_ROUGHNESSMAP' : '', - - parameters.transmission ? '#define USE_TRANSMISSION' : '', - parameters.transmissionMap ? '#define USE_TRANSMISSIONMAP' : '', - parameters.thicknessMap ? '#define USE_THICKNESSMAP' : '', - - parameters.vertexTangents && parameters.flatShading === false ? '#define USE_TANGENT' : '', - parameters.vertexColors || parameters.instancingColor ? '#define USE_COLOR' : '', - parameters.vertexAlphas ? '#define USE_COLOR_ALPHA' : '', - parameters.vertexUv1s ? '#define USE_UV1' : '', - parameters.vertexUv2s ? '#define USE_UV2' : '', - parameters.vertexUv3s ? '#define USE_UV3' : '', - - parameters.pointsUvs ? '#define USE_POINTS_UV' : '', - - parameters.gradientMap ? '#define USE_GRADIENTMAP' : '', - - parameters.flatShading ? '#define FLAT_SHADED' : '', - - parameters.doubleSided ? '#define DOUBLE_SIDED' : '', - parameters.flipSided ? '#define FLIP_SIDED' : '', - - parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '', - parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '', - - parameters.premultipliedAlpha ? '#define PREMULTIPLIED_ALPHA' : '', - - parameters.numLightProbes > 0 ? '#define USE_LIGHT_PROBES' : '', - - parameters.useLegacyLights ? '#define LEGACY_LIGHTS' : '', - - parameters.decodeVideoTexture ? '#define DECODE_VIDEO_TEXTURE' : '', - - parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '', - ( parameters.logarithmicDepthBuffer && parameters.rendererExtensionFragDepth ) ? '#define USE_LOGDEPTHBUF_EXT' : '', - - 'uniform mat4 viewMatrix;', - 'uniform vec3 cameraPosition;', - 'uniform bool isOrthographic;', - - ( parameters.toneMapping !== NoToneMapping ) ? '#define TONE_MAPPING' : '', - ( parameters.toneMapping !== NoToneMapping ) ? ShaderChunk[ 'tonemapping_pars_fragment' ] : '', // this code is required here because it is used by the toneMapping() function defined below - ( parameters.toneMapping !== NoToneMapping ) ? getToneMappingFunction( 'toneMapping', parameters.toneMapping ) : '', - - parameters.dithering ? '#define DITHERING' : '', - parameters.opaque ? '#define OPAQUE' : '', - - ShaderChunk[ 'colorspace_pars_fragment' ], // this code is required here because it is used by the various encoding/decoding function defined below - getTexelEncodingFunction( 'linearToOutputTexel', parameters.outputColorSpace ), - - parameters.useDepthPacking ? '#define DEPTH_PACKING ' + parameters.depthPacking : '', - - '\n' - - ].filter( filterEmptyLine ).join( '\n' ); - - } - - vertexShader = resolveIncludes( vertexShader ); - vertexShader = replaceLightNums( vertexShader, parameters ); - vertexShader = replaceClippingPlaneNums( vertexShader, parameters ); - - fragmentShader = resolveIncludes( fragmentShader ); - fragmentShader = replaceLightNums( fragmentShader, parameters ); - fragmentShader = replaceClippingPlaneNums( fragmentShader, parameters ); - - vertexShader = unrollLoops( vertexShader ); - fragmentShader = unrollLoops( fragmentShader ); - - if ( parameters.isWebGL2 && parameters.isRawShaderMaterial !== true ) { - - // GLSL 3.0 conversion for built-in materials and ShaderMaterial - - versionString = '#version 300 es\n'; - - prefixVertex = [ - customVertexExtensions, - 'precision mediump sampler2DArray;', - '#define attribute in', - '#define varying out', - '#define texture2D texture' - ].join( '\n' ) + '\n' + prefixVertex; - - prefixFragment = [ - 'precision mediump sampler2DArray;', - '#define varying in', - ( parameters.glslVersion === GLSL3 ) ? '' : 'layout(location = 0) out highp vec4 pc_fragColor;', - ( parameters.glslVersion === GLSL3 ) ? '' : '#define gl_FragColor pc_fragColor', - '#define gl_FragDepthEXT gl_FragDepth', - '#define texture2D texture', - '#define textureCube texture', - '#define texture2DProj textureProj', - '#define texture2DLodEXT textureLod', - '#define texture2DProjLodEXT textureProjLod', - '#define textureCubeLodEXT textureLod', - '#define texture2DGradEXT textureGrad', - '#define texture2DProjGradEXT textureProjGrad', - '#define textureCubeGradEXT textureGrad' - ].join( '\n' ) + '\n' + prefixFragment; - - } - - const vertexGlsl = versionString + prefixVertex + vertexShader; - const fragmentGlsl = versionString + prefixFragment + fragmentShader; - - // console.log( '*VERTEX*', vertexGlsl ); - // console.log( '*FRAGMENT*', fragmentGlsl ); - - const glVertexShader = WebGLShader( gl, gl.VERTEX_SHADER, vertexGlsl ); - const glFragmentShader = WebGLShader( gl, gl.FRAGMENT_SHADER, fragmentGlsl ); - - gl.attachShader( program, glVertexShader ); - gl.attachShader( program, glFragmentShader ); - - // Force a particular attribute to index 0. - - if ( parameters.index0AttributeName !== undefined ) { - - gl.bindAttribLocation( program, 0, parameters.index0AttributeName ); - - } else if ( parameters.morphTargets === true ) { - - // programs with morphTargets displace position out of attribute 0 - gl.bindAttribLocation( program, 0, 'position' ); - - } - - gl.linkProgram( program ); - - function onFirstUse( self ) { - - // check for link errors - if ( renderer.debug.checkShaderErrors ) { - - const programLog = gl.getProgramInfoLog( program ).trim(); - const vertexLog = gl.getShaderInfoLog( glVertexShader ).trim(); - const fragmentLog = gl.getShaderInfoLog( glFragmentShader ).trim(); - - let runnable = true; - let haveDiagnostics = true; - - if ( gl.getProgramParameter( program, gl.LINK_STATUS ) === false ) { - - runnable = false; - - if ( typeof renderer.debug.onShaderError === 'function' ) { - - renderer.debug.onShaderError( gl, program, glVertexShader, glFragmentShader ); - - } else { - - // default error reporting - - const vertexErrors = getShaderErrors( gl, glVertexShader, 'vertex' ); - const fragmentErrors = getShaderErrors( gl, glFragmentShader, 'fragment' ); - - console.error( - 'THREE.WebGLProgram: Shader Error ' + gl.getError() + ' - ' + - 'VALIDATE_STATUS ' + gl.getProgramParameter( program, gl.VALIDATE_STATUS ) + '\n\n' + - 'Material Name: ' + self.name + '\n' + - 'Material Type: ' + self.type + '\n\n' + - 'Program Info Log: ' + programLog + '\n' + - vertexErrors + '\n' + - fragmentErrors - ); - - } - - } else if ( programLog !== '' ) { - - console.warn( 'THREE.WebGLProgram: Program Info Log:', programLog ); - - } else if ( vertexLog === '' || fragmentLog === '' ) { - - haveDiagnostics = false; - - } - - if ( haveDiagnostics ) { - - self.diagnostics = { - - runnable: runnable, - - programLog: programLog, - - vertexShader: { - - log: vertexLog, - prefix: prefixVertex - - }, - - fragmentShader: { - - log: fragmentLog, - prefix: prefixFragment - - } - - }; - - } - - } - - // Clean up - - // Crashes in iOS9 and iOS10. #18402 - // gl.detachShader( program, glVertexShader ); - // gl.detachShader( program, glFragmentShader ); - - gl.deleteShader( glVertexShader ); - gl.deleteShader( glFragmentShader ); - - cachedUniforms = new WebGLUniforms( gl, program ); - cachedAttributes = fetchAttributeLocations( gl, program ); - - } - - // set up caching for uniform locations - - let cachedUniforms; - - this.getUniforms = function () { - - if ( cachedUniforms === undefined ) { - - // Populates cachedUniforms and cachedAttributes - onFirstUse( this ); - - } - - return cachedUniforms; - - }; - - // set up caching for attribute locations - - let cachedAttributes; - - this.getAttributes = function () { - - if ( cachedAttributes === undefined ) { - - // Populates cachedAttributes and cachedUniforms - onFirstUse( this ); - - } - - return cachedAttributes; - - }; - - // indicate when the program is ready to be used. if the KHR_parallel_shader_compile extension isn't supported, - // flag the program as ready immediately. It may cause a stall when it's first used. - - let programReady = ( parameters.rendererExtensionParallelShaderCompile === false ); - - this.isReady = function () { - - if ( programReady === false ) { - - programReady = gl.getProgramParameter( program, COMPLETION_STATUS_KHR ); - - } - - return programReady; - - }; - - // free resource - - this.destroy = function () { - - bindingStates.releaseStatesOfProgram( this ); - - gl.deleteProgram( program ); - this.program = undefined; - - }; - - // - - this.type = parameters.shaderType; - this.name = parameters.shaderName; - this.id = programIdCount ++; - this.cacheKey = cacheKey; - this.usedTimes = 1; - this.program = program; - this.vertexShader = glVertexShader; - this.fragmentShader = glFragmentShader; - - return this; - -} - -let _id$1 = 0; - -class WebGLShaderCache { - - constructor() { - - this.shaderCache = new Map(); - this.materialCache = new Map(); - - } - - update( material ) { - - const vertexShader = material.vertexShader; - const fragmentShader = material.fragmentShader; - - const vertexShaderStage = this._getShaderStage( vertexShader ); - const fragmentShaderStage = this._getShaderStage( fragmentShader ); - - const materialShaders = this._getShaderCacheForMaterial( material ); - - if ( materialShaders.has( vertexShaderStage ) === false ) { - - materialShaders.add( vertexShaderStage ); - vertexShaderStage.usedTimes ++; - - } - - if ( materialShaders.has( fragmentShaderStage ) === false ) { - - materialShaders.add( fragmentShaderStage ); - fragmentShaderStage.usedTimes ++; - - } - - return this; - - } - - remove( material ) { - - const materialShaders = this.materialCache.get( material ); - - for ( const shaderStage of materialShaders ) { - - shaderStage.usedTimes --; - - if ( shaderStage.usedTimes === 0 ) this.shaderCache.delete( shaderStage.code ); - - } - - this.materialCache.delete( material ); - - return this; - - } - - getVertexShaderID( material ) { - - return this._getShaderStage( material.vertexShader ).id; - - } - - getFragmentShaderID( material ) { - - return this._getShaderStage( material.fragmentShader ).id; - - } - - dispose() { - - this.shaderCache.clear(); - this.materialCache.clear(); - - } - - _getShaderCacheForMaterial( material ) { - - const cache = this.materialCache; - let set = cache.get( material ); - - if ( set === undefined ) { - - set = new Set(); - cache.set( material, set ); - - } - - return set; - - } - - _getShaderStage( code ) { - - const cache = this.shaderCache; - let stage = cache.get( code ); - - if ( stage === undefined ) { - - stage = new WebGLShaderStage( code ); - cache.set( code, stage ); - - } - - return stage; - - } - -} - -class WebGLShaderStage { - - constructor( code ) { - - this.id = _id$1 ++; - - this.code = code; - this.usedTimes = 0; - - } - -} - -function WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities, bindingStates, clipping ) { - - const _programLayers = new Layers(); - const _customShaders = new WebGLShaderCache(); - const _activeChannels = new Set(); - const programs = []; - - const IS_WEBGL2 = capabilities.isWebGL2; - const logarithmicDepthBuffer = capabilities.logarithmicDepthBuffer; - const SUPPORTS_VERTEX_TEXTURES = capabilities.vertexTextures; - - let precision = capabilities.precision; - - const shaderIDs = { - MeshDepthMaterial: 'depth', - MeshDistanceMaterial: 'distanceRGBA', - MeshNormalMaterial: 'normal', - MeshBasicMaterial: 'basic', - MeshLambertMaterial: 'lambert', - MeshPhongMaterial: 'phong', - MeshToonMaterial: 'toon', - MeshStandardMaterial: 'physical', - MeshPhysicalMaterial: 'physical', - MeshMatcapMaterial: 'matcap', - LineBasicMaterial: 'basic', - LineDashedMaterial: 'dashed', - PointsMaterial: 'points', - ShadowMaterial: 'shadow', - SpriteMaterial: 'sprite' - }; - - function getChannel( value ) { - - _activeChannels.add( value ); - - if ( value === 0 ) return 'uv'; - - return `uv${ value }`; - - } - - function getParameters( material, lights, shadows, scene, object ) { - - const fog = scene.fog; - const geometry = object.geometry; - const environment = material.isMeshStandardMaterial ? scene.environment : null; - - const envMap = ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get( material.envMap || environment ); - const envMapCubeUVHeight = ( !! envMap ) && ( envMap.mapping === CubeUVReflectionMapping ) ? envMap.image.height : null; - - const shaderID = shaderIDs[ material.type ]; - - // heuristics to create shader parameters according to lights in the scene - // (not to blow over maxLights budget) - - if ( material.precision !== null ) { - - precision = capabilities.getMaxPrecision( material.precision ); - - if ( precision !== material.precision ) { - - console.warn( 'THREE.WebGLProgram.getParameters:', material.precision, 'not supported, using', precision, 'instead.' ); - - } - - } - - // - - const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color; - const morphTargetsCount = ( morphAttribute !== undefined ) ? morphAttribute.length : 0; - - let morphTextureStride = 0; - - if ( geometry.morphAttributes.position !== undefined ) morphTextureStride = 1; - if ( geometry.morphAttributes.normal !== undefined ) morphTextureStride = 2; - if ( geometry.morphAttributes.color !== undefined ) morphTextureStride = 3; - - // - - let vertexShader, fragmentShader; - let customVertexShaderID, customFragmentShaderID; - - if ( shaderID ) { - - const shader = ShaderLib[ shaderID ]; - - vertexShader = shader.vertexShader; - fragmentShader = shader.fragmentShader; - - } else { - - vertexShader = material.vertexShader; - fragmentShader = material.fragmentShader; - - _customShaders.update( material ); - - customVertexShaderID = _customShaders.getVertexShaderID( material ); - customFragmentShaderID = _customShaders.getFragmentShaderID( material ); - - } - - const currentRenderTarget = renderer.getRenderTarget(); - - const IS_INSTANCEDMESH = object.isInstancedMesh === true; - const IS_BATCHEDMESH = object.isBatchedMesh === true; - - const HAS_MAP = !! material.map; - const HAS_MATCAP = !! material.matcap; - const HAS_ENVMAP = !! envMap; - const HAS_AOMAP = !! material.aoMap; - const HAS_LIGHTMAP = !! material.lightMap; - const HAS_BUMPMAP = !! material.bumpMap; - const HAS_NORMALMAP = !! material.normalMap; - const HAS_DISPLACEMENTMAP = !! material.displacementMap; - const HAS_EMISSIVEMAP = !! material.emissiveMap; - - const HAS_METALNESSMAP = !! material.metalnessMap; - const HAS_ROUGHNESSMAP = !! material.roughnessMap; - - const HAS_ANISOTROPY = material.anisotropy > 0; - const HAS_CLEARCOAT = material.clearcoat > 0; - const HAS_IRIDESCENCE = material.iridescence > 0; - const HAS_SHEEN = material.sheen > 0; - const HAS_TRANSMISSION = material.transmission > 0; - - const HAS_ANISOTROPYMAP = HAS_ANISOTROPY && !! material.anisotropyMap; - - const HAS_CLEARCOATMAP = HAS_CLEARCOAT && !! material.clearcoatMap; - const HAS_CLEARCOAT_NORMALMAP = HAS_CLEARCOAT && !! material.clearcoatNormalMap; - const HAS_CLEARCOAT_ROUGHNESSMAP = HAS_CLEARCOAT && !! material.clearcoatRoughnessMap; - - const HAS_IRIDESCENCEMAP = HAS_IRIDESCENCE && !! material.iridescenceMap; - const HAS_IRIDESCENCE_THICKNESSMAP = HAS_IRIDESCENCE && !! material.iridescenceThicknessMap; - - const HAS_SHEEN_COLORMAP = HAS_SHEEN && !! material.sheenColorMap; - const HAS_SHEEN_ROUGHNESSMAP = HAS_SHEEN && !! material.sheenRoughnessMap; - - const HAS_SPECULARMAP = !! material.specularMap; - const HAS_SPECULAR_COLORMAP = !! material.specularColorMap; - const HAS_SPECULAR_INTENSITYMAP = !! material.specularIntensityMap; - - const HAS_TRANSMISSIONMAP = HAS_TRANSMISSION && !! material.transmissionMap; - const HAS_THICKNESSMAP = HAS_TRANSMISSION && !! material.thicknessMap; - - const HAS_GRADIENTMAP = !! material.gradientMap; - - const HAS_ALPHAMAP = !! material.alphaMap; - - const HAS_ALPHATEST = material.alphaTest > 0; - - const HAS_ALPHAHASH = !! material.alphaHash; - - const HAS_EXTENSIONS = !! material.extensions; - - let toneMapping = NoToneMapping; - - if ( material.toneMapped ) { - - if ( currentRenderTarget === null || currentRenderTarget.isXRRenderTarget === true ) { - - toneMapping = renderer.toneMapping; - - } - - } - - const parameters = { - - isWebGL2: IS_WEBGL2, - - shaderID: shaderID, - shaderType: material.type, - shaderName: material.name, - - vertexShader: vertexShader, - fragmentShader: fragmentShader, - defines: material.defines, - - customVertexShaderID: customVertexShaderID, - customFragmentShaderID: customFragmentShaderID, - - isRawShaderMaterial: material.isRawShaderMaterial === true, - glslVersion: material.glslVersion, - - precision: precision, - - batching: IS_BATCHEDMESH, - instancing: IS_INSTANCEDMESH, - instancingColor: IS_INSTANCEDMESH && object.instanceColor !== null, - - supportsVertexTextures: SUPPORTS_VERTEX_TEXTURES, - outputColorSpace: ( currentRenderTarget === null ) ? renderer.outputColorSpace : ( currentRenderTarget.isXRRenderTarget === true ? currentRenderTarget.texture.colorSpace : LinearSRGBColorSpace ), - alphaToCoverage: !! material.alphaToCoverage, - - map: HAS_MAP, - matcap: HAS_MATCAP, - envMap: HAS_ENVMAP, - envMapMode: HAS_ENVMAP && envMap.mapping, - envMapCubeUVHeight: envMapCubeUVHeight, - aoMap: HAS_AOMAP, - lightMap: HAS_LIGHTMAP, - bumpMap: HAS_BUMPMAP, - normalMap: HAS_NORMALMAP, - displacementMap: SUPPORTS_VERTEX_TEXTURES && HAS_DISPLACEMENTMAP, - emissiveMap: HAS_EMISSIVEMAP, - - normalMapObjectSpace: HAS_NORMALMAP && material.normalMapType === ObjectSpaceNormalMap, - normalMapTangentSpace: HAS_NORMALMAP && material.normalMapType === TangentSpaceNormalMap, - - metalnessMap: HAS_METALNESSMAP, - roughnessMap: HAS_ROUGHNESSMAP, - - anisotropy: HAS_ANISOTROPY, - anisotropyMap: HAS_ANISOTROPYMAP, - - clearcoat: HAS_CLEARCOAT, - clearcoatMap: HAS_CLEARCOATMAP, - clearcoatNormalMap: HAS_CLEARCOAT_NORMALMAP, - clearcoatRoughnessMap: HAS_CLEARCOAT_ROUGHNESSMAP, - - iridescence: HAS_IRIDESCENCE, - iridescenceMap: HAS_IRIDESCENCEMAP, - iridescenceThicknessMap: HAS_IRIDESCENCE_THICKNESSMAP, - - sheen: HAS_SHEEN, - sheenColorMap: HAS_SHEEN_COLORMAP, - sheenRoughnessMap: HAS_SHEEN_ROUGHNESSMAP, - - specularMap: HAS_SPECULARMAP, - specularColorMap: HAS_SPECULAR_COLORMAP, - specularIntensityMap: HAS_SPECULAR_INTENSITYMAP, - - transmission: HAS_TRANSMISSION, - transmissionMap: HAS_TRANSMISSIONMAP, - thicknessMap: HAS_THICKNESSMAP, - - gradientMap: HAS_GRADIENTMAP, - - opaque: material.transparent === false && material.blending === NormalBlending && material.alphaToCoverage === false, - - alphaMap: HAS_ALPHAMAP, - alphaTest: HAS_ALPHATEST, - alphaHash: HAS_ALPHAHASH, - - combine: material.combine, - - // - - mapUv: HAS_MAP && getChannel( material.map.channel ), - aoMapUv: HAS_AOMAP && getChannel( material.aoMap.channel ), - lightMapUv: HAS_LIGHTMAP && getChannel( material.lightMap.channel ), - bumpMapUv: HAS_BUMPMAP && getChannel( material.bumpMap.channel ), - normalMapUv: HAS_NORMALMAP && getChannel( material.normalMap.channel ), - displacementMapUv: HAS_DISPLACEMENTMAP && getChannel( material.displacementMap.channel ), - emissiveMapUv: HAS_EMISSIVEMAP && getChannel( material.emissiveMap.channel ), - - metalnessMapUv: HAS_METALNESSMAP && getChannel( material.metalnessMap.channel ), - roughnessMapUv: HAS_ROUGHNESSMAP && getChannel( material.roughnessMap.channel ), - - anisotropyMapUv: HAS_ANISOTROPYMAP && getChannel( material.anisotropyMap.channel ), - - clearcoatMapUv: HAS_CLEARCOATMAP && getChannel( material.clearcoatMap.channel ), - clearcoatNormalMapUv: HAS_CLEARCOAT_NORMALMAP && getChannel( material.clearcoatNormalMap.channel ), - clearcoatRoughnessMapUv: HAS_CLEARCOAT_ROUGHNESSMAP && getChannel( material.clearcoatRoughnessMap.channel ), - - iridescenceMapUv: HAS_IRIDESCENCEMAP && getChannel( material.iridescenceMap.channel ), - iridescenceThicknessMapUv: HAS_IRIDESCENCE_THICKNESSMAP && getChannel( material.iridescenceThicknessMap.channel ), - - sheenColorMapUv: HAS_SHEEN_COLORMAP && getChannel( material.sheenColorMap.channel ), - sheenRoughnessMapUv: HAS_SHEEN_ROUGHNESSMAP && getChannel( material.sheenRoughnessMap.channel ), - - specularMapUv: HAS_SPECULARMAP && getChannel( material.specularMap.channel ), - specularColorMapUv: HAS_SPECULAR_COLORMAP && getChannel( material.specularColorMap.channel ), - specularIntensityMapUv: HAS_SPECULAR_INTENSITYMAP && getChannel( material.specularIntensityMap.channel ), - - transmissionMapUv: HAS_TRANSMISSIONMAP && getChannel( material.transmissionMap.channel ), - thicknessMapUv: HAS_THICKNESSMAP && getChannel( material.thicknessMap.channel ), - - alphaMapUv: HAS_ALPHAMAP && getChannel( material.alphaMap.channel ), - - // - - vertexTangents: !! geometry.attributes.tangent && ( HAS_NORMALMAP || HAS_ANISOTROPY ), - vertexColors: material.vertexColors, - vertexAlphas: material.vertexColors === true && !! geometry.attributes.color && geometry.attributes.color.itemSize === 4, - - pointsUvs: object.isPoints === true && !! geometry.attributes.uv && ( HAS_MAP || HAS_ALPHAMAP ), - - fog: !! fog, - useFog: material.fog === true, - fogExp2: ( !! fog && fog.isFogExp2 ), - - flatShading: material.flatShading === true, - - sizeAttenuation: material.sizeAttenuation === true, - logarithmicDepthBuffer: logarithmicDepthBuffer, - - skinning: object.isSkinnedMesh === true, - - morphTargets: geometry.morphAttributes.position !== undefined, - morphNormals: geometry.morphAttributes.normal !== undefined, - morphColors: geometry.morphAttributes.color !== undefined, - morphTargetsCount: morphTargetsCount, - morphTextureStride: morphTextureStride, - - numDirLights: lights.directional.length, - numPointLights: lights.point.length, - numSpotLights: lights.spot.length, - numSpotLightMaps: lights.spotLightMap.length, - numRectAreaLights: lights.rectArea.length, - numHemiLights: lights.hemi.length, - - numDirLightShadows: lights.directionalShadowMap.length, - numPointLightShadows: lights.pointShadowMap.length, - numSpotLightShadows: lights.spotShadowMap.length, - numSpotLightShadowsWithMaps: lights.numSpotLightShadowsWithMaps, - - numLightProbes: lights.numLightProbes, - - numClippingPlanes: clipping.numPlanes, - numClipIntersection: clipping.numIntersection, - - dithering: material.dithering, - - shadowMapEnabled: renderer.shadowMap.enabled && shadows.length > 0, - shadowMapType: renderer.shadowMap.type, - - toneMapping: toneMapping, - useLegacyLights: renderer._useLegacyLights, - - decodeVideoTexture: HAS_MAP && ( material.map.isVideoTexture === true ) && ( ColorManagement.getTransfer( material.map.colorSpace ) === SRGBTransfer ), - - premultipliedAlpha: material.premultipliedAlpha, - - doubleSided: material.side === DoubleSide, - flipSided: material.side === BackSide, - - useDepthPacking: material.depthPacking >= 0, - depthPacking: material.depthPacking || 0, - - index0AttributeName: material.index0AttributeName, - - extensionDerivatives: HAS_EXTENSIONS && material.extensions.derivatives === true, - extensionFragDepth: HAS_EXTENSIONS && material.extensions.fragDepth === true, - extensionDrawBuffers: HAS_EXTENSIONS && material.extensions.drawBuffers === true, - extensionShaderTextureLOD: HAS_EXTENSIONS && material.extensions.shaderTextureLOD === true, - extensionClipCullDistance: HAS_EXTENSIONS && material.extensions.clipCullDistance === true && extensions.has( 'WEBGL_clip_cull_distance' ), - extensionMultiDraw: HAS_EXTENSIONS && material.extensions.multiDraw === true && extensions.has( 'WEBGL_multi_draw' ), - - rendererExtensionFragDepth: IS_WEBGL2 || extensions.has( 'EXT_frag_depth' ), - rendererExtensionDrawBuffers: IS_WEBGL2 || extensions.has( 'WEBGL_draw_buffers' ), - rendererExtensionShaderTextureLod: IS_WEBGL2 || extensions.has( 'EXT_shader_texture_lod' ), - rendererExtensionParallelShaderCompile: extensions.has( 'KHR_parallel_shader_compile' ), - - customProgramCacheKey: material.customProgramCacheKey() - - }; - - // the usage of getChannel() determines the active texture channels for this shader - - parameters.vertexUv1s = _activeChannels.has( 1 ); - parameters.vertexUv2s = _activeChannels.has( 2 ); - parameters.vertexUv3s = _activeChannels.has( 3 ); - - _activeChannels.clear(); - - return parameters; - - } - - function getProgramCacheKey( parameters ) { - - const array = []; - - if ( parameters.shaderID ) { - - array.push( parameters.shaderID ); - - } else { - - array.push( parameters.customVertexShaderID ); - array.push( parameters.customFragmentShaderID ); - - } - - if ( parameters.defines !== undefined ) { - - for ( const name in parameters.defines ) { - - array.push( name ); - array.push( parameters.defines[ name ] ); - - } - - } - - if ( parameters.isRawShaderMaterial === false ) { - - getProgramCacheKeyParameters( array, parameters ); - getProgramCacheKeyBooleans( array, parameters ); - array.push( renderer.outputColorSpace ); - - } - - array.push( parameters.customProgramCacheKey ); - - return array.join(); - - } - - function getProgramCacheKeyParameters( array, parameters ) { - - array.push( parameters.precision ); - array.push( parameters.outputColorSpace ); - array.push( parameters.envMapMode ); - array.push( parameters.envMapCubeUVHeight ); - array.push( parameters.mapUv ); - array.push( parameters.alphaMapUv ); - array.push( parameters.lightMapUv ); - array.push( parameters.aoMapUv ); - array.push( parameters.bumpMapUv ); - array.push( parameters.normalMapUv ); - array.push( parameters.displacementMapUv ); - array.push( parameters.emissiveMapUv ); - array.push( parameters.metalnessMapUv ); - array.push( parameters.roughnessMapUv ); - array.push( parameters.anisotropyMapUv ); - array.push( parameters.clearcoatMapUv ); - array.push( parameters.clearcoatNormalMapUv ); - array.push( parameters.clearcoatRoughnessMapUv ); - array.push( parameters.iridescenceMapUv ); - array.push( parameters.iridescenceThicknessMapUv ); - array.push( parameters.sheenColorMapUv ); - array.push( parameters.sheenRoughnessMapUv ); - array.push( parameters.specularMapUv ); - array.push( parameters.specularColorMapUv ); - array.push( parameters.specularIntensityMapUv ); - array.push( parameters.transmissionMapUv ); - array.push( parameters.thicknessMapUv ); - array.push( parameters.combine ); - array.push( parameters.fogExp2 ); - array.push( parameters.sizeAttenuation ); - array.push( parameters.morphTargetsCount ); - array.push( parameters.morphAttributeCount ); - array.push( parameters.numDirLights ); - array.push( parameters.numPointLights ); - array.push( parameters.numSpotLights ); - array.push( parameters.numSpotLightMaps ); - array.push( parameters.numHemiLights ); - array.push( parameters.numRectAreaLights ); - array.push( parameters.numDirLightShadows ); - array.push( parameters.numPointLightShadows ); - array.push( parameters.numSpotLightShadows ); - array.push( parameters.numSpotLightShadowsWithMaps ); - array.push( parameters.numLightProbes ); - array.push( parameters.shadowMapType ); - array.push( parameters.toneMapping ); - array.push( parameters.numClippingPlanes ); - array.push( parameters.numClipIntersection ); - array.push( parameters.depthPacking ); - - } - - function getProgramCacheKeyBooleans( array, parameters ) { - - _programLayers.disableAll(); - - if ( parameters.isWebGL2 ) - _programLayers.enable( 0 ); - if ( parameters.supportsVertexTextures ) - _programLayers.enable( 1 ); - if ( parameters.instancing ) - _programLayers.enable( 2 ); - if ( parameters.instancingColor ) - _programLayers.enable( 3 ); - if ( parameters.matcap ) - _programLayers.enable( 4 ); - if ( parameters.envMap ) - _programLayers.enable( 5 ); - if ( parameters.normalMapObjectSpace ) - _programLayers.enable( 6 ); - if ( parameters.normalMapTangentSpace ) - _programLayers.enable( 7 ); - if ( parameters.clearcoat ) - _programLayers.enable( 8 ); - if ( parameters.iridescence ) - _programLayers.enable( 9 ); - if ( parameters.alphaTest ) - _programLayers.enable( 10 ); - if ( parameters.vertexColors ) - _programLayers.enable( 11 ); - if ( parameters.vertexAlphas ) - _programLayers.enable( 12 ); - if ( parameters.vertexUv1s ) - _programLayers.enable( 13 ); - if ( parameters.vertexUv2s ) - _programLayers.enable( 14 ); - if ( parameters.vertexUv3s ) - _programLayers.enable( 15 ); - if ( parameters.vertexTangents ) - _programLayers.enable( 16 ); - if ( parameters.anisotropy ) - _programLayers.enable( 17 ); - if ( parameters.alphaHash ) - _programLayers.enable( 18 ); - if ( parameters.batching ) - _programLayers.enable( 19 ); - - array.push( _programLayers.mask ); - _programLayers.disableAll(); - - if ( parameters.fog ) - _programLayers.enable( 0 ); - if ( parameters.useFog ) - _programLayers.enable( 1 ); - if ( parameters.flatShading ) - _programLayers.enable( 2 ); - if ( parameters.logarithmicDepthBuffer ) - _programLayers.enable( 3 ); - if ( parameters.skinning ) - _programLayers.enable( 4 ); - if ( parameters.morphTargets ) - _programLayers.enable( 5 ); - if ( parameters.morphNormals ) - _programLayers.enable( 6 ); - if ( parameters.morphColors ) - _programLayers.enable( 7 ); - if ( parameters.premultipliedAlpha ) - _programLayers.enable( 8 ); - if ( parameters.shadowMapEnabled ) - _programLayers.enable( 9 ); - if ( parameters.useLegacyLights ) - _programLayers.enable( 10 ); - if ( parameters.doubleSided ) - _programLayers.enable( 11 ); - if ( parameters.flipSided ) - _programLayers.enable( 12 ); - if ( parameters.useDepthPacking ) - _programLayers.enable( 13 ); - if ( parameters.dithering ) - _programLayers.enable( 14 ); - if ( parameters.transmission ) - _programLayers.enable( 15 ); - if ( parameters.sheen ) - _programLayers.enable( 16 ); - if ( parameters.opaque ) - _programLayers.enable( 17 ); - if ( parameters.pointsUvs ) - _programLayers.enable( 18 ); - if ( parameters.decodeVideoTexture ) - _programLayers.enable( 19 ); - if ( parameters.alphaToCoverage ) - _programLayers.enable( 20 ); - - array.push( _programLayers.mask ); - - } - - function getUniforms( material ) { - - const shaderID = shaderIDs[ material.type ]; - let uniforms; - - if ( shaderID ) { - - const shader = ShaderLib[ shaderID ]; - uniforms = UniformsUtils.clone( shader.uniforms ); - - } else { - - uniforms = material.uniforms; - - } - - return uniforms; - - } - - function acquireProgram( parameters, cacheKey ) { - - let program; - - // Check if code has been already compiled - for ( let p = 0, pl = programs.length; p < pl; p ++ ) { - - const preexistingProgram = programs[ p ]; - - if ( preexistingProgram.cacheKey === cacheKey ) { - - program = preexistingProgram; - ++ program.usedTimes; - - break; - - } - - } - - if ( program === undefined ) { - - program = new WebGLProgram( renderer, cacheKey, parameters, bindingStates ); - programs.push( program ); - - } - - return program; - - } - - function releaseProgram( program ) { - - if ( -- program.usedTimes === 0 ) { - - // Remove from unordered set - const i = programs.indexOf( program ); - programs[ i ] = programs[ programs.length - 1 ]; - programs.pop(); - - // Free WebGL resources - program.destroy(); - - } - - } - - function releaseShaderCache( material ) { - - _customShaders.remove( material ); - - } - - function dispose() { - - _customShaders.dispose(); - - } - - return { - getParameters: getParameters, - getProgramCacheKey: getProgramCacheKey, - getUniforms: getUniforms, - acquireProgram: acquireProgram, - releaseProgram: releaseProgram, - releaseShaderCache: releaseShaderCache, - // Exposed for resource monitoring & error feedback via renderer.info: - programs: programs, - dispose: dispose - }; - -} - -function WebGLProperties() { - - let properties = new WeakMap(); - - function get( object ) { - - let map = properties.get( object ); - - if ( map === undefined ) { - - map = {}; - properties.set( object, map ); - - } - - return map; - - } - - function remove( object ) { - - properties.delete( object ); - - } - - function update( object, key, value ) { - - properties.get( object )[ key ] = value; - - } - - function dispose() { - - properties = new WeakMap(); - - } - - return { - get: get, - remove: remove, - update: update, - dispose: dispose - }; - -} - -function painterSortStable( a, b ) { - - if ( a.groupOrder !== b.groupOrder ) { - - return a.groupOrder - b.groupOrder; - - } else if ( a.renderOrder !== b.renderOrder ) { - - return a.renderOrder - b.renderOrder; - - } else if ( a.material.id !== b.material.id ) { - - return a.material.id - b.material.id; - - } else if ( a.z !== b.z ) { - - return a.z - b.z; - - } else { - - return a.id - b.id; - - } - -} - -function reversePainterSortStable( a, b ) { - - if ( a.groupOrder !== b.groupOrder ) { - - return a.groupOrder - b.groupOrder; - - } else if ( a.renderOrder !== b.renderOrder ) { - - return a.renderOrder - b.renderOrder; - - } else if ( a.z !== b.z ) { - - return b.z - a.z; - - } else { - - return a.id - b.id; - - } - -} - - -function WebGLRenderList() { - - const renderItems = []; - let renderItemsIndex = 0; - - const opaque = []; - const transmissive = []; - const transparent = []; - - function init() { - - renderItemsIndex = 0; - - opaque.length = 0; - transmissive.length = 0; - transparent.length = 0; - - } - - function getNextRenderItem( object, geometry, material, groupOrder, z, group ) { - - let renderItem = renderItems[ renderItemsIndex ]; - - if ( renderItem === undefined ) { - - renderItem = { - id: object.id, - object: object, - geometry: geometry, - material: material, - groupOrder: groupOrder, - renderOrder: object.renderOrder, - z: z, - group: group - }; - - renderItems[ renderItemsIndex ] = renderItem; - - } else { - - renderItem.id = object.id; - renderItem.object = object; - renderItem.geometry = geometry; - renderItem.material = material; - renderItem.groupOrder = groupOrder; - renderItem.renderOrder = object.renderOrder; - renderItem.z = z; - renderItem.group = group; - - } - - renderItemsIndex ++; - - return renderItem; - - } - - function push( object, geometry, material, groupOrder, z, group ) { - - const renderItem = getNextRenderItem( object, geometry, material, groupOrder, z, group ); - - if ( material.transmission > 0.0 ) { - - transmissive.push( renderItem ); - - } else if ( material.transparent === true ) { - - transparent.push( renderItem ); - - } else { - - opaque.push( renderItem ); - - } - - } - - function unshift( object, geometry, material, groupOrder, z, group ) { - - const renderItem = getNextRenderItem( object, geometry, material, groupOrder, z, group ); - - if ( material.transmission > 0.0 ) { - - transmissive.unshift( renderItem ); - - } else if ( material.transparent === true ) { - - transparent.unshift( renderItem ); - - } else { - - opaque.unshift( renderItem ); - - } - - } - - function sort( customOpaqueSort, customTransparentSort ) { - - if ( opaque.length > 1 ) opaque.sort( customOpaqueSort || painterSortStable ); - if ( transmissive.length > 1 ) transmissive.sort( customTransparentSort || reversePainterSortStable ); - if ( transparent.length > 1 ) transparent.sort( customTransparentSort || reversePainterSortStable ); - - } - - function finish() { - - // Clear references from inactive renderItems in the list - - for ( let i = renderItemsIndex, il = renderItems.length; i < il; i ++ ) { - - const renderItem = renderItems[ i ]; - - if ( renderItem.id === null ) break; - - renderItem.id = null; - renderItem.object = null; - renderItem.geometry = null; - renderItem.material = null; - renderItem.group = null; - - } - - } - - return { - - opaque: opaque, - transmissive: transmissive, - transparent: transparent, - - init: init, - push: push, - unshift: unshift, - finish: finish, - - sort: sort - }; - -} - -function WebGLRenderLists() { - - let lists = new WeakMap(); - - function get( scene, renderCallDepth ) { - - const listArray = lists.get( scene ); - let list; - - if ( listArray === undefined ) { - - list = new WebGLRenderList(); - lists.set( scene, [ list ] ); - - } else { - - if ( renderCallDepth >= listArray.length ) { - - list = new WebGLRenderList(); - listArray.push( list ); - - } else { - - list = listArray[ renderCallDepth ]; - - } - - } - - return list; - - } - - function dispose() { - - lists = new WeakMap(); - - } - - return { - get: get, - dispose: dispose - }; - -} - -function UniformsCache() { - - const lights = {}; - - return { - - get: function ( light ) { - - if ( lights[ light.id ] !== undefined ) { - - return lights[ light.id ]; - - } - - let uniforms; - - switch ( light.type ) { - - case 'DirectionalLight': - uniforms = { - direction: new Vector3(), - color: new Color() - }; - break; - - case 'SpotLight': - uniforms = { - position: new Vector3(), - direction: new Vector3(), - color: new Color(), - distance: 0, - coneCos: 0, - penumbraCos: 0, - decay: 0 - }; - break; - - case 'PointLight': - uniforms = { - position: new Vector3(), - color: new Color(), - distance: 0, - decay: 0 - }; - break; - - case 'HemisphereLight': - uniforms = { - direction: new Vector3(), - skyColor: new Color(), - groundColor: new Color() - }; - break; - - case 'RectAreaLight': - uniforms = { - color: new Color(), - position: new Vector3(), - halfWidth: new Vector3(), - halfHeight: new Vector3() - }; - break; - - } - - lights[ light.id ] = uniforms; - - return uniforms; - - } - - }; - -} - -function ShadowUniformsCache() { - - const lights = {}; - - return { - - get: function ( light ) { - - if ( lights[ light.id ] !== undefined ) { - - return lights[ light.id ]; - - } - - let uniforms; - - switch ( light.type ) { - - case 'DirectionalLight': - uniforms = { - shadowBias: 0, - shadowNormalBias: 0, - shadowRadius: 1, - shadowMapSize: new Vector2() - }; - break; - - case 'SpotLight': - uniforms = { - shadowBias: 0, - shadowNormalBias: 0, - shadowRadius: 1, - shadowMapSize: new Vector2() - }; - break; - - case 'PointLight': - uniforms = { - shadowBias: 0, - shadowNormalBias: 0, - shadowRadius: 1, - shadowMapSize: new Vector2(), - shadowCameraNear: 1, - shadowCameraFar: 1000 - }; - break; - - // TODO (abelnation): set RectAreaLight shadow uniforms - - } - - lights[ light.id ] = uniforms; - - return uniforms; - - } - - }; - -} - - - -let nextVersion = 0; - -function shadowCastingAndTexturingLightsFirst( lightA, lightB ) { - - return ( lightB.castShadow ? 2 : 0 ) - ( lightA.castShadow ? 2 : 0 ) + ( lightB.map ? 1 : 0 ) - ( lightA.map ? 1 : 0 ); - -} - -function WebGLLights( extensions, capabilities ) { - - const cache = new UniformsCache(); - - const shadowCache = ShadowUniformsCache(); - - const state = { - - version: 0, - - hash: { - directionalLength: - 1, - pointLength: - 1, - spotLength: - 1, - rectAreaLength: - 1, - hemiLength: - 1, - - numDirectionalShadows: - 1, - numPointShadows: - 1, - numSpotShadows: - 1, - numSpotMaps: - 1, - - numLightProbes: - 1 - }, - - ambient: [ 0, 0, 0 ], - probe: [], - directional: [], - directionalShadow: [], - directionalShadowMap: [], - directionalShadowMatrix: [], - spot: [], - spotLightMap: [], - spotShadow: [], - spotShadowMap: [], - spotLightMatrix: [], - rectArea: [], - rectAreaLTC1: null, - rectAreaLTC2: null, - point: [], - pointShadow: [], - pointShadowMap: [], - pointShadowMatrix: [], - hemi: [], - numSpotLightShadowsWithMaps: 0, - numLightProbes: 0 - - }; - - for ( let i = 0; i < 9; i ++ ) state.probe.push( new Vector3() ); - - const vector3 = new Vector3(); - const matrix4 = new Matrix4(); - const matrix42 = new Matrix4(); - - function setup( lights, useLegacyLights ) { - - let r = 0, g = 0, b = 0; - - for ( let i = 0; i < 9; i ++ ) state.probe[ i ].set( 0, 0, 0 ); - - let directionalLength = 0; - let pointLength = 0; - let spotLength = 0; - let rectAreaLength = 0; - let hemiLength = 0; - - let numDirectionalShadows = 0; - let numPointShadows = 0; - let numSpotShadows = 0; - let numSpotMaps = 0; - let numSpotShadowsWithMaps = 0; - - let numLightProbes = 0; - - // ordering : [shadow casting + map texturing, map texturing, shadow casting, none ] - lights.sort( shadowCastingAndTexturingLightsFirst ); - - // artist-friendly light intensity scaling factor - const scaleFactor = ( useLegacyLights === true ) ? Math.PI : 1; - - for ( let i = 0, l = lights.length; i < l; i ++ ) { - - const light = lights[ i ]; - - const color = light.color; - const intensity = light.intensity; - const distance = light.distance; - - const shadowMap = ( light.shadow && light.shadow.map ) ? light.shadow.map.texture : null; - - if ( light.isAmbientLight ) { - - r += color.r * intensity * scaleFactor; - g += color.g * intensity * scaleFactor; - b += color.b * intensity * scaleFactor; - - } else if ( light.isLightProbe ) { - - for ( let j = 0; j < 9; j ++ ) { - - state.probe[ j ].addScaledVector( light.sh.coefficients[ j ], intensity ); - - } - - numLightProbes ++; - - } else if ( light.isDirectionalLight ) { - - const uniforms = cache.get( light ); - - uniforms.color.copy( light.color ).multiplyScalar( light.intensity * scaleFactor ); - - if ( light.castShadow ) { - - const shadow = light.shadow; - - const shadowUniforms = shadowCache.get( light ); - - shadowUniforms.shadowBias = shadow.bias; - shadowUniforms.shadowNormalBias = shadow.normalBias; - shadowUniforms.shadowRadius = shadow.radius; - shadowUniforms.shadowMapSize = shadow.mapSize; - - state.directionalShadow[ directionalLength ] = shadowUniforms; - state.directionalShadowMap[ directionalLength ] = shadowMap; - state.directionalShadowMatrix[ directionalLength ] = light.shadow.matrix; - - numDirectionalShadows ++; - - } - - state.directional[ directionalLength ] = uniforms; - - directionalLength ++; - - } else if ( light.isSpotLight ) { - - const uniforms = cache.get( light ); - - uniforms.position.setFromMatrixPosition( light.matrixWorld ); - - uniforms.color.copy( color ).multiplyScalar( intensity * scaleFactor ); - uniforms.distance = distance; - - uniforms.coneCos = Math.cos( light.angle ); - uniforms.penumbraCos = Math.cos( light.angle * ( 1 - light.penumbra ) ); - uniforms.decay = light.decay; - - state.spot[ spotLength ] = uniforms; - - const shadow = light.shadow; - - if ( light.map ) { - - state.spotLightMap[ numSpotMaps ] = light.map; - numSpotMaps ++; - - // make sure the lightMatrix is up to date - // TODO : do it if required only - shadow.updateMatrices( light ); - - if ( light.castShadow ) numSpotShadowsWithMaps ++; - - } - - state.spotLightMatrix[ spotLength ] = shadow.matrix; - - if ( light.castShadow ) { - - const shadowUniforms = shadowCache.get( light ); - - shadowUniforms.shadowBias = shadow.bias; - shadowUniforms.shadowNormalBias = shadow.normalBias; - shadowUniforms.shadowRadius = shadow.radius; - shadowUniforms.shadowMapSize = shadow.mapSize; - - state.spotShadow[ spotLength ] = shadowUniforms; - state.spotShadowMap[ spotLength ] = shadowMap; - - numSpotShadows ++; - - } - - spotLength ++; - - } else if ( light.isRectAreaLight ) { - - const uniforms = cache.get( light ); - - uniforms.color.copy( color ).multiplyScalar( intensity ); - - uniforms.halfWidth.set( light.width * 0.5, 0.0, 0.0 ); - uniforms.halfHeight.set( 0.0, light.height * 0.5, 0.0 ); - - state.rectArea[ rectAreaLength ] = uniforms; - - rectAreaLength ++; - - } else if ( light.isPointLight ) { - - const uniforms = cache.get( light ); - - uniforms.color.copy( light.color ).multiplyScalar( light.intensity * scaleFactor ); - uniforms.distance = light.distance; - uniforms.decay = light.decay; - - if ( light.castShadow ) { - - const shadow = light.shadow; - - const shadowUniforms = shadowCache.get( light ); - - shadowUniforms.shadowBias = shadow.bias; - shadowUniforms.shadowNormalBias = shadow.normalBias; - shadowUniforms.shadowRadius = shadow.radius; - shadowUniforms.shadowMapSize = shadow.mapSize; - shadowUniforms.shadowCameraNear = shadow.camera.near; - shadowUniforms.shadowCameraFar = shadow.camera.far; - - state.pointShadow[ pointLength ] = shadowUniforms; - state.pointShadowMap[ pointLength ] = shadowMap; - state.pointShadowMatrix[ pointLength ] = light.shadow.matrix; - - numPointShadows ++; - - } - - state.point[ pointLength ] = uniforms; - - pointLength ++; - - } else if ( light.isHemisphereLight ) { - - const uniforms = cache.get( light ); - - uniforms.skyColor.copy( light.color ).multiplyScalar( intensity * scaleFactor ); - uniforms.groundColor.copy( light.groundColor ).multiplyScalar( intensity * scaleFactor ); - - state.hemi[ hemiLength ] = uniforms; - - hemiLength ++; - - } - - } - - if ( rectAreaLength > 0 ) { - - if ( capabilities.isWebGL2 ) { - - // WebGL 2 - - if ( extensions.has( 'OES_texture_float_linear' ) === true ) { - - state.rectAreaLTC1 = UniformsLib.LTC_FLOAT_1; - state.rectAreaLTC2 = UniformsLib.LTC_FLOAT_2; - - } else { - - state.rectAreaLTC1 = UniformsLib.LTC_HALF_1; - state.rectAreaLTC2 = UniformsLib.LTC_HALF_2; - - } - - } else { - - // WebGL 1 - - if ( extensions.has( 'OES_texture_float_linear' ) === true ) { - - state.rectAreaLTC1 = UniformsLib.LTC_FLOAT_1; - state.rectAreaLTC2 = UniformsLib.LTC_FLOAT_2; - - } else if ( extensions.has( 'OES_texture_half_float_linear' ) === true ) { - - state.rectAreaLTC1 = UniformsLib.LTC_HALF_1; - state.rectAreaLTC2 = UniformsLib.LTC_HALF_2; - - } else { - - console.error( 'THREE.WebGLRenderer: Unable to use RectAreaLight. Missing WebGL extensions.' ); - - } - - } - - } - - state.ambient[ 0 ] = r; - state.ambient[ 1 ] = g; - state.ambient[ 2 ] = b; - - const hash = state.hash; - - if ( hash.directionalLength !== directionalLength || - hash.pointLength !== pointLength || - hash.spotLength !== spotLength || - hash.rectAreaLength !== rectAreaLength || - hash.hemiLength !== hemiLength || - hash.numDirectionalShadows !== numDirectionalShadows || - hash.numPointShadows !== numPointShadows || - hash.numSpotShadows !== numSpotShadows || - hash.numSpotMaps !== numSpotMaps || - hash.numLightProbes !== numLightProbes ) { - - state.directional.length = directionalLength; - state.spot.length = spotLength; - state.rectArea.length = rectAreaLength; - state.point.length = pointLength; - state.hemi.length = hemiLength; - - state.directionalShadow.length = numDirectionalShadows; - state.directionalShadowMap.length = numDirectionalShadows; - state.pointShadow.length = numPointShadows; - state.pointShadowMap.length = numPointShadows; - state.spotShadow.length = numSpotShadows; - state.spotShadowMap.length = numSpotShadows; - state.directionalShadowMatrix.length = numDirectionalShadows; - state.pointShadowMatrix.length = numPointShadows; - state.spotLightMatrix.length = numSpotShadows + numSpotMaps - numSpotShadowsWithMaps; - state.spotLightMap.length = numSpotMaps; - state.numSpotLightShadowsWithMaps = numSpotShadowsWithMaps; - state.numLightProbes = numLightProbes; - - hash.directionalLength = directionalLength; - hash.pointLength = pointLength; - hash.spotLength = spotLength; - hash.rectAreaLength = rectAreaLength; - hash.hemiLength = hemiLength; - - hash.numDirectionalShadows = numDirectionalShadows; - hash.numPointShadows = numPointShadows; - hash.numSpotShadows = numSpotShadows; - hash.numSpotMaps = numSpotMaps; - - hash.numLightProbes = numLightProbes; - - state.version = nextVersion ++; - - } - - } - - function setupView( lights, camera ) { - - let directionalLength = 0; - let pointLength = 0; - let spotLength = 0; - let rectAreaLength = 0; - let hemiLength = 0; - - const viewMatrix = camera.matrixWorldInverse; - - for ( let i = 0, l = lights.length; i < l; i ++ ) { - - const light = lights[ i ]; - - if ( light.isDirectionalLight ) { - - const uniforms = state.directional[ directionalLength ]; - - uniforms.direction.setFromMatrixPosition( light.matrixWorld ); - vector3.setFromMatrixPosition( light.target.matrixWorld ); - uniforms.direction.sub( vector3 ); - uniforms.direction.transformDirection( viewMatrix ); - - directionalLength ++; - - } else if ( light.isSpotLight ) { - - const uniforms = state.spot[ spotLength ]; - - uniforms.position.setFromMatrixPosition( light.matrixWorld ); - uniforms.position.applyMatrix4( viewMatrix ); - - uniforms.direction.setFromMatrixPosition( light.matrixWorld ); - vector3.setFromMatrixPosition( light.target.matrixWorld ); - uniforms.direction.sub( vector3 ); - uniforms.direction.transformDirection( viewMatrix ); - - spotLength ++; - - } else if ( light.isRectAreaLight ) { - - const uniforms = state.rectArea[ rectAreaLength ]; - - uniforms.position.setFromMatrixPosition( light.matrixWorld ); - uniforms.position.applyMatrix4( viewMatrix ); - - // extract local rotation of light to derive width/height half vectors - matrix42.identity(); - matrix4.copy( light.matrixWorld ); - matrix4.premultiply( viewMatrix ); - matrix42.extractRotation( matrix4 ); - - uniforms.halfWidth.set( light.width * 0.5, 0.0, 0.0 ); - uniforms.halfHeight.set( 0.0, light.height * 0.5, 0.0 ); - - uniforms.halfWidth.applyMatrix4( matrix42 ); - uniforms.halfHeight.applyMatrix4( matrix42 ); - - rectAreaLength ++; - - } else if ( light.isPointLight ) { - - const uniforms = state.point[ pointLength ]; - - uniforms.position.setFromMatrixPosition( light.matrixWorld ); - uniforms.position.applyMatrix4( viewMatrix ); - - pointLength ++; - - } else if ( light.isHemisphereLight ) { - - const uniforms = state.hemi[ hemiLength ]; - - uniforms.direction.setFromMatrixPosition( light.matrixWorld ); - uniforms.direction.transformDirection( viewMatrix ); - - hemiLength ++; - - } - - } - - } - - return { - setup: setup, - setupView: setupView, - state: state - }; - -} - -function WebGLRenderState( extensions, capabilities ) { - - const lights = new WebGLLights( extensions, capabilities ); - - const lightsArray = []; - const shadowsArray = []; - - function init() { - - lightsArray.length = 0; - shadowsArray.length = 0; - - } - - function pushLight( light ) { - - lightsArray.push( light ); - - } - - function pushShadow( shadowLight ) { - - shadowsArray.push( shadowLight ); - - } - - function setupLights( useLegacyLights ) { - - lights.setup( lightsArray, useLegacyLights ); - - } - - function setupLightsView( camera ) { - - lights.setupView( lightsArray, camera ); - - } - - const state = { - lightsArray: lightsArray, - shadowsArray: shadowsArray, - - lights: lights - }; - - return { - init: init, - state: state, - setupLights: setupLights, - setupLightsView: setupLightsView, - - pushLight: pushLight, - pushShadow: pushShadow - }; - -} - -function WebGLRenderStates( extensions, capabilities ) { - - let renderStates = new WeakMap(); - - function get( scene, renderCallDepth = 0 ) { - - const renderStateArray = renderStates.get( scene ); - let renderState; - - if ( renderStateArray === undefined ) { - - renderState = new WebGLRenderState( extensions, capabilities ); - renderStates.set( scene, [ renderState ] ); - - } else { - - if ( renderCallDepth >= renderStateArray.length ) { - - renderState = new WebGLRenderState( extensions, capabilities ); - renderStateArray.push( renderState ); - - } else { - - renderState = renderStateArray[ renderCallDepth ]; - - } - - } - - return renderState; - - } - - function dispose() { - - renderStates = new WeakMap(); - - } - - return { - get: get, - dispose: dispose - }; - -} - -class MeshDepthMaterial extends Material { - - constructor( parameters ) { - - super(); - - this.isMeshDepthMaterial = true; - - this.type = 'MeshDepthMaterial'; - - this.depthPacking = BasicDepthPacking; - - this.map = null; - - this.alphaMap = null; - - this.displacementMap = null; - this.displacementScale = 1; - this.displacementBias = 0; - - this.wireframe = false; - this.wireframeLinewidth = 1; - - this.setValues( parameters ); - - } - - copy( source ) { - - super.copy( source ); - - this.depthPacking = source.depthPacking; - - this.map = source.map; - - this.alphaMap = source.alphaMap; - - this.displacementMap = source.displacementMap; - this.displacementScale = source.displacementScale; - this.displacementBias = source.displacementBias; - - this.wireframe = source.wireframe; - this.wireframeLinewidth = source.wireframeLinewidth; - - return this; - - } - -} - -class MeshDistanceMaterial extends Material { - - constructor( parameters ) { - - super(); - - this.isMeshDistanceMaterial = true; - - this.type = 'MeshDistanceMaterial'; - - this.map = null; - - this.alphaMap = null; - - this.displacementMap = null; - this.displacementScale = 1; - this.displacementBias = 0; - - this.setValues( parameters ); - - } - - copy( source ) { - - super.copy( source ); - - this.map = source.map; - - this.alphaMap = source.alphaMap; - - this.displacementMap = source.displacementMap; - this.displacementScale = source.displacementScale; - this.displacementBias = source.displacementBias; - - return this; - - } - -} - -const vertex = "void main() {\n\tgl_Position = vec4( position, 1.0 );\n}"; - -const fragment = "uniform sampler2D shadow_pass;\nuniform vec2 resolution;\nuniform float radius;\n#include \nvoid main() {\n\tconst float samples = float( VSM_SAMPLES );\n\tfloat mean = 0.0;\n\tfloat squared_mean = 0.0;\n\tfloat uvStride = samples <= 1.0 ? 0.0 : 2.0 / ( samples - 1.0 );\n\tfloat uvStart = samples <= 1.0 ? 0.0 : - 1.0;\n\tfor ( float i = 0.0; i < samples; i ++ ) {\n\t\tfloat uvOffset = uvStart + i * uvStride;\n\t\t#ifdef HORIZONTAL_PASS\n\t\t\tvec2 distribution = unpackRGBATo2Half( texture2D( shadow_pass, ( gl_FragCoord.xy + vec2( uvOffset, 0.0 ) * radius ) / resolution ) );\n\t\t\tmean += distribution.x;\n\t\t\tsquared_mean += distribution.y * distribution.y + distribution.x * distribution.x;\n\t\t#else\n\t\t\tfloat depth = unpackRGBAToDepth( texture2D( shadow_pass, ( gl_FragCoord.xy + vec2( 0.0, uvOffset ) * radius ) / resolution ) );\n\t\t\tmean += depth;\n\t\t\tsquared_mean += depth * depth;\n\t\t#endif\n\t}\n\tmean = mean / samples;\n\tsquared_mean = squared_mean / samples;\n\tfloat std_dev = sqrt( squared_mean - mean * mean );\n\tgl_FragColor = pack2HalfToRGBA( vec2( mean, std_dev ) );\n}"; - -function WebGLShadowMap( _renderer, _objects, _capabilities ) { - - let _frustum = new Frustum(); - - const _shadowMapSize = new Vector2(), - _viewportSize = new Vector2(), - - _viewport = new Vector4(), - - _depthMaterial = new MeshDepthMaterial( { depthPacking: RGBADepthPacking } ), - _distanceMaterial = new MeshDistanceMaterial(), - - _materialCache = {}, - - _maxTextureSize = _capabilities.maxTextureSize; - - const shadowSide = { [ FrontSide ]: BackSide, [ BackSide ]: FrontSide, [ DoubleSide ]: DoubleSide }; - - const shadowMaterialVertical = new ShaderMaterial( { - defines: { - VSM_SAMPLES: 8 - }, - uniforms: { - shadow_pass: { value: null }, - resolution: { value: new Vector2() }, - radius: { value: 4.0 } - }, - - vertexShader: vertex, - fragmentShader: fragment - - } ); - - const shadowMaterialHorizontal = shadowMaterialVertical.clone(); - shadowMaterialHorizontal.defines.HORIZONTAL_PASS = 1; - - const fullScreenTri = new BufferGeometry(); - fullScreenTri.setAttribute( - 'position', - new BufferAttribute( - new Float32Array( [ - 1, - 1, 0.5, 3, - 1, 0.5, - 1, 3, 0.5 ] ), - 3 - ) - ); - - const fullScreenMesh = new Mesh( fullScreenTri, shadowMaterialVertical ); - - const scope = this; - - this.enabled = false; - - this.autoUpdate = true; - this.needsUpdate = false; - - this.type = PCFShadowMap; - let _previousType = this.type; - - this.render = function ( lights, scene, camera ) { - - if ( scope.enabled === false ) return; - if ( scope.autoUpdate === false && scope.needsUpdate === false ) return; - - if ( lights.length === 0 ) return; - - const currentRenderTarget = _renderer.getRenderTarget(); - const activeCubeFace = _renderer.getActiveCubeFace(); - const activeMipmapLevel = _renderer.getActiveMipmapLevel(); - - const _state = _renderer.state; - - // Set GL state for depth map. - _state.setBlending( NoBlending ); - _state.buffers.color.setClear( 1, 1, 1, 1 ); - _state.buffers.depth.setTest( true ); - _state.setScissorTest( false ); - - // check for shadow map type changes - - const toVSM = ( _previousType !== VSMShadowMap && this.type === VSMShadowMap ); - const fromVSM = ( _previousType === VSMShadowMap && this.type !== VSMShadowMap ); - - // render depth map - - for ( let i = 0, il = lights.length; i < il; i ++ ) { - - const light = lights[ i ]; - const shadow = light.shadow; - - if ( shadow === undefined ) { - - console.warn( 'THREE.WebGLShadowMap:', light, 'has no shadow.' ); - continue; - - } - - if ( shadow.autoUpdate === false && shadow.needsUpdate === false ) continue; - - _shadowMapSize.copy( shadow.mapSize ); - - const shadowFrameExtents = shadow.getFrameExtents(); - - _shadowMapSize.multiply( shadowFrameExtents ); - - _viewportSize.copy( shadow.mapSize ); - - if ( _shadowMapSize.x > _maxTextureSize || _shadowMapSize.y > _maxTextureSize ) { - - if ( _shadowMapSize.x > _maxTextureSize ) { - - _viewportSize.x = Math.floor( _maxTextureSize / shadowFrameExtents.x ); - _shadowMapSize.x = _viewportSize.x * shadowFrameExtents.x; - shadow.mapSize.x = _viewportSize.x; - - } - - if ( _shadowMapSize.y > _maxTextureSize ) { - - _viewportSize.y = Math.floor( _maxTextureSize / shadowFrameExtents.y ); - _shadowMapSize.y = _viewportSize.y * shadowFrameExtents.y; - shadow.mapSize.y = _viewportSize.y; - - } - - } - - if ( shadow.map === null || toVSM === true || fromVSM === true ) { - - const pars = ( this.type !== VSMShadowMap ) ? { minFilter: NearestFilter, magFilter: NearestFilter } : {}; - - if ( shadow.map !== null ) { - - shadow.map.dispose(); - - } - - shadow.map = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y, pars ); - shadow.map.texture.name = light.name + '.shadowMap'; - - shadow.camera.updateProjectionMatrix(); - - } - - _renderer.setRenderTarget( shadow.map ); - _renderer.clear(); - - const viewportCount = shadow.getViewportCount(); - - for ( let vp = 0; vp < viewportCount; vp ++ ) { - - const viewport = shadow.getViewport( vp ); - - _viewport.set( - _viewportSize.x * viewport.x, - _viewportSize.y * viewport.y, - _viewportSize.x * viewport.z, - _viewportSize.y * viewport.w - ); - - _state.viewport( _viewport ); - - shadow.updateMatrices( light, vp ); - - _frustum = shadow.getFrustum(); - - renderObject( scene, camera, shadow.camera, light, this.type ); - - } - - // do blur pass for VSM - - if ( shadow.isPointLightShadow !== true && this.type === VSMShadowMap ) { - - VSMPass( shadow, camera ); - - } - - shadow.needsUpdate = false; - - } - - _previousType = this.type; - - scope.needsUpdate = false; - - _renderer.setRenderTarget( currentRenderTarget, activeCubeFace, activeMipmapLevel ); - - }; - - function VSMPass( shadow, camera ) { - - const geometry = _objects.update( fullScreenMesh ); - - if ( shadowMaterialVertical.defines.VSM_SAMPLES !== shadow.blurSamples ) { - - shadowMaterialVertical.defines.VSM_SAMPLES = shadow.blurSamples; - shadowMaterialHorizontal.defines.VSM_SAMPLES = shadow.blurSamples; - - shadowMaterialVertical.needsUpdate = true; - shadowMaterialHorizontal.needsUpdate = true; - - } - - if ( shadow.mapPass === null ) { - - shadow.mapPass = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y ); - - } - - // vertical pass - - shadowMaterialVertical.uniforms.shadow_pass.value = shadow.map.texture; - shadowMaterialVertical.uniforms.resolution.value = shadow.mapSize; - shadowMaterialVertical.uniforms.radius.value = shadow.radius; - _renderer.setRenderTarget( shadow.mapPass ); - _renderer.clear(); - _renderer.renderBufferDirect( camera, null, geometry, shadowMaterialVertical, fullScreenMesh, null ); - - // horizontal pass - - shadowMaterialHorizontal.uniforms.shadow_pass.value = shadow.mapPass.texture; - shadowMaterialHorizontal.uniforms.resolution.value = shadow.mapSize; - shadowMaterialHorizontal.uniforms.radius.value = shadow.radius; - _renderer.setRenderTarget( shadow.map ); - _renderer.clear(); - _renderer.renderBufferDirect( camera, null, geometry, shadowMaterialHorizontal, fullScreenMesh, null ); - - } - - function getDepthMaterial( object, material, light, type ) { - - let result = null; - - const customMaterial = ( light.isPointLight === true ) ? object.customDistanceMaterial : object.customDepthMaterial; - - if ( customMaterial !== undefined ) { - - result = customMaterial; - - } else { - - result = ( light.isPointLight === true ) ? _distanceMaterial : _depthMaterial; - - if ( ( _renderer.localClippingEnabled && material.clipShadows === true && Array.isArray( material.clippingPlanes ) && material.clippingPlanes.length !== 0 ) || - ( material.displacementMap && material.displacementScale !== 0 ) || - ( material.alphaMap && material.alphaTest > 0 ) || - ( material.map && material.alphaTest > 0 ) ) { - - // in this case we need a unique material instance reflecting the - // appropriate state - - const keyA = result.uuid, keyB = material.uuid; - - let materialsForVariant = _materialCache[ keyA ]; - - if ( materialsForVariant === undefined ) { - - materialsForVariant = {}; - _materialCache[ keyA ] = materialsForVariant; - - } - - let cachedMaterial = materialsForVariant[ keyB ]; - - if ( cachedMaterial === undefined ) { - - cachedMaterial = result.clone(); - materialsForVariant[ keyB ] = cachedMaterial; - material.addEventListener( 'dispose', onMaterialDispose ); - - } - - result = cachedMaterial; - - } - - } - - result.visible = material.visible; - result.wireframe = material.wireframe; - - if ( type === VSMShadowMap ) { - - result.side = ( material.shadowSide !== null ) ? material.shadowSide : material.side; - - } else { - - result.side = ( material.shadowSide !== null ) ? material.shadowSide : shadowSide[ material.side ]; - - } - - result.alphaMap = material.alphaMap; - result.alphaTest = material.alphaTest; - result.map = material.map; - - result.clipShadows = material.clipShadows; - result.clippingPlanes = material.clippingPlanes; - result.clipIntersection = material.clipIntersection; - - result.displacementMap = material.displacementMap; - result.displacementScale = material.displacementScale; - result.displacementBias = material.displacementBias; - - result.wireframeLinewidth = material.wireframeLinewidth; - result.linewidth = material.linewidth; - - if ( light.isPointLight === true && result.isMeshDistanceMaterial === true ) { - - const materialProperties = _renderer.properties.get( result ); - materialProperties.light = light; - - } - - return result; - - } - - function renderObject( object, camera, shadowCamera, light, type ) { - - if ( object.visible === false ) return; - - const visible = object.layers.test( camera.layers ); - - if ( visible && ( object.isMesh || object.isLine || object.isPoints ) ) { - - if ( ( object.castShadow || ( object.receiveShadow && type === VSMShadowMap ) ) && ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) ) { - - object.modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld ); - - const geometry = _objects.update( object ); - const material = object.material; - - if ( Array.isArray( material ) ) { - - const groups = geometry.groups; - - for ( let k = 0, kl = groups.length; k < kl; k ++ ) { - - const group = groups[ k ]; - const groupMaterial = material[ group.materialIndex ]; - - if ( groupMaterial && groupMaterial.visible ) { - - const depthMaterial = getDepthMaterial( object, groupMaterial, light, type ); - - object.onBeforeShadow( _renderer, object, camera, shadowCamera, geometry, depthMaterial, group ); - - _renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, group ); - - object.onAfterShadow( _renderer, object, camera, shadowCamera, geometry, depthMaterial, group ); - - } - - } - - } else if ( material.visible ) { - - const depthMaterial = getDepthMaterial( object, material, light, type ); - - object.onBeforeShadow( _renderer, object, camera, shadowCamera, geometry, depthMaterial, null ); - - _renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, null ); - - object.onAfterShadow( _renderer, object, camera, shadowCamera, geometry, depthMaterial, null ); - - } - - } - - } - - const children = object.children; - - for ( let i = 0, l = children.length; i < l; i ++ ) { - - renderObject( children[ i ], camera, shadowCamera, light, type ); - - } - - } - - function onMaterialDispose( event ) { - - const material = event.target; - - material.removeEventListener( 'dispose', onMaterialDispose ); - - // make sure to remove the unique distance/depth materials used for shadow map rendering - - for ( const id in _materialCache ) { - - const cache = _materialCache[ id ]; - - const uuid = event.target.uuid; - - if ( uuid in cache ) { - - const shadowMaterial = cache[ uuid ]; - shadowMaterial.dispose(); - delete cache[ uuid ]; - - } - - } - - } - -} - -function WebGLState( gl, extensions, capabilities ) { - - const isWebGL2 = capabilities.isWebGL2; - - function ColorBuffer() { - - let locked = false; - - const color = new Vector4(); - let currentColorMask = null; - const currentColorClear = new Vector4( 0, 0, 0, 0 ); - - return { - - setMask: function ( colorMask ) { - - if ( currentColorMask !== colorMask && ! locked ) { - - gl.colorMask( colorMask, colorMask, colorMask, colorMask ); - currentColorMask = colorMask; - - } - - }, - - setLocked: function ( lock ) { - - locked = lock; - - }, - - setClear: function ( r, g, b, a, premultipliedAlpha ) { - - if ( premultipliedAlpha === true ) { - - r *= a; g *= a; b *= a; - - } - - color.set( r, g, b, a ); - - if ( currentColorClear.equals( color ) === false ) { - - gl.clearColor( r, g, b, a ); - currentColorClear.copy( color ); - - } - - }, - - reset: function () { - - locked = false; - - currentColorMask = null; - currentColorClear.set( - 1, 0, 0, 0 ); // set to invalid state - - } - - }; - - } - - function DepthBuffer() { - - let locked = false; - - let currentDepthMask = null; - let currentDepthFunc = null; - let currentDepthClear = null; - - return { - - setTest: function ( depthTest ) { - - if ( depthTest ) { - - enable( gl.DEPTH_TEST ); - - } else { - - disable( gl.DEPTH_TEST ); - - } - - }, - - setMask: function ( depthMask ) { - - if ( currentDepthMask !== depthMask && ! locked ) { - - gl.depthMask( depthMask ); - currentDepthMask = depthMask; - - } - - }, - - setFunc: function ( depthFunc ) { - - if ( currentDepthFunc !== depthFunc ) { - - switch ( depthFunc ) { - - case NeverDepth: - - gl.depthFunc( gl.NEVER ); - break; - - case AlwaysDepth: - - gl.depthFunc( gl.ALWAYS ); - break; - - case LessDepth: - - gl.depthFunc( gl.LESS ); - break; - - case LessEqualDepth: - - gl.depthFunc( gl.LEQUAL ); - break; - - case EqualDepth: - - gl.depthFunc( gl.EQUAL ); - break; - - case GreaterEqualDepth: - - gl.depthFunc( gl.GEQUAL ); - break; - - case GreaterDepth: - - gl.depthFunc( gl.GREATER ); - break; - - case NotEqualDepth: - - gl.depthFunc( gl.NOTEQUAL ); - break; - - default: - - gl.depthFunc( gl.LEQUAL ); - - } - - currentDepthFunc = depthFunc; - - } - - }, - - setLocked: function ( lock ) { - - locked = lock; - - }, - - setClear: function ( depth ) { - - if ( currentDepthClear !== depth ) { - - gl.clearDepth( depth ); - currentDepthClear = depth; - - } - - }, - - reset: function () { - - locked = false; - - currentDepthMask = null; - currentDepthFunc = null; - currentDepthClear = null; - - } - - }; - - } - - function StencilBuffer() { - - let locked = false; - - let currentStencilMask = null; - let currentStencilFunc = null; - let currentStencilRef = null; - let currentStencilFuncMask = null; - let currentStencilFail = null; - let currentStencilZFail = null; - let currentStencilZPass = null; - let currentStencilClear = null; - - return { - - setTest: function ( stencilTest ) { - - if ( ! locked ) { - - if ( stencilTest ) { - - enable( gl.STENCIL_TEST ); - - } else { - - disable( gl.STENCIL_TEST ); - - } - - } - - }, - - setMask: function ( stencilMask ) { - - if ( currentStencilMask !== stencilMask && ! locked ) { - - gl.stencilMask( stencilMask ); - currentStencilMask = stencilMask; - - } - - }, - - setFunc: function ( stencilFunc, stencilRef, stencilMask ) { - - if ( currentStencilFunc !== stencilFunc || - currentStencilRef !== stencilRef || - currentStencilFuncMask !== stencilMask ) { - - gl.stencilFunc( stencilFunc, stencilRef, stencilMask ); - - currentStencilFunc = stencilFunc; - currentStencilRef = stencilRef; - currentStencilFuncMask = stencilMask; - - } - - }, - - setOp: function ( stencilFail, stencilZFail, stencilZPass ) { - - if ( currentStencilFail !== stencilFail || - currentStencilZFail !== stencilZFail || - currentStencilZPass !== stencilZPass ) { - - gl.stencilOp( stencilFail, stencilZFail, stencilZPass ); - - currentStencilFail = stencilFail; - currentStencilZFail = stencilZFail; - currentStencilZPass = stencilZPass; - - } - - }, - - setLocked: function ( lock ) { - - locked = lock; - - }, - - setClear: function ( stencil ) { - - if ( currentStencilClear !== stencil ) { - - gl.clearStencil( stencil ); - currentStencilClear = stencil; - - } - - }, - - reset: function () { - - locked = false; - - currentStencilMask = null; - currentStencilFunc = null; - currentStencilRef = null; - currentStencilFuncMask = null; - currentStencilFail = null; - currentStencilZFail = null; - currentStencilZPass = null; - currentStencilClear = null; - - } - - }; - - } - - // - - const colorBuffer = new ColorBuffer(); - const depthBuffer = new DepthBuffer(); - const stencilBuffer = new StencilBuffer(); - - const uboBindings = new WeakMap(); - const uboProgramMap = new WeakMap(); - - let enabledCapabilities = {}; - - let currentBoundFramebuffers = {}; - let currentDrawbuffers = new WeakMap(); - let defaultDrawbuffers = []; - - let currentProgram = null; - - let currentBlendingEnabled = false; - let currentBlending = null; - let currentBlendEquation = null; - let currentBlendSrc = null; - let currentBlendDst = null; - let currentBlendEquationAlpha = null; - let currentBlendSrcAlpha = null; - let currentBlendDstAlpha = null; - let currentBlendColor = new Color( 0, 0, 0 ); - let currentBlendAlpha = 0; - let currentPremultipledAlpha = false; - - let currentFlipSided = null; - let currentCullFace = null; - - let currentLineWidth = null; - - let currentPolygonOffsetFactor = null; - let currentPolygonOffsetUnits = null; - - const maxTextures = gl.getParameter( gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS ); - - let lineWidthAvailable = false; - let version = 0; - const glVersion = gl.getParameter( gl.VERSION ); - - if ( glVersion.indexOf( 'WebGL' ) !== - 1 ) { - - version = parseFloat( /^WebGL (\d)/.exec( glVersion )[ 1 ] ); - lineWidthAvailable = ( version >= 1.0 ); - - } else if ( glVersion.indexOf( 'OpenGL ES' ) !== - 1 ) { - - version = parseFloat( /^OpenGL ES (\d)/.exec( glVersion )[ 1 ] ); - lineWidthAvailable = ( version >= 2.0 ); - - } - - let currentTextureSlot = null; - let currentBoundTextures = {}; - - const scissorParam = gl.getParameter( gl.SCISSOR_BOX ); - const viewportParam = gl.getParameter( gl.VIEWPORT ); - - const currentScissor = new Vector4().fromArray( scissorParam ); - const currentViewport = new Vector4().fromArray( viewportParam ); - - function createTexture( type, target, count, dimensions ) { - - const data = new Uint8Array( 4 ); // 4 is required to match default unpack alignment of 4. - const texture = gl.createTexture(); - - gl.bindTexture( type, texture ); - gl.texParameteri( type, gl.TEXTURE_MIN_FILTER, gl.NEAREST ); - gl.texParameteri( type, gl.TEXTURE_MAG_FILTER, gl.NEAREST ); - - for ( let i = 0; i < count; i ++ ) { - - if ( isWebGL2 && ( type === gl.TEXTURE_3D || type === gl.TEXTURE_2D_ARRAY ) ) { - - gl.texImage3D( target, 0, gl.RGBA, 1, 1, dimensions, 0, gl.RGBA, gl.UNSIGNED_BYTE, data ); - - } else { - - gl.texImage2D( target + i, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, data ); - - } - - } - - return texture; - - } - - const emptyTextures = {}; - emptyTextures[ gl.TEXTURE_2D ] = createTexture( gl.TEXTURE_2D, gl.TEXTURE_2D, 1 ); - emptyTextures[ gl.TEXTURE_CUBE_MAP ] = createTexture( gl.TEXTURE_CUBE_MAP, gl.TEXTURE_CUBE_MAP_POSITIVE_X, 6 ); - - if ( isWebGL2 ) { - - emptyTextures[ gl.TEXTURE_2D_ARRAY ] = createTexture( gl.TEXTURE_2D_ARRAY, gl.TEXTURE_2D_ARRAY, 1, 1 ); - emptyTextures[ gl.TEXTURE_3D ] = createTexture( gl.TEXTURE_3D, gl.TEXTURE_3D, 1, 1 ); - - } - - // init - - colorBuffer.setClear( 0, 0, 0, 1 ); - depthBuffer.setClear( 1 ); - stencilBuffer.setClear( 0 ); - - enable( gl.DEPTH_TEST ); - depthBuffer.setFunc( LessEqualDepth ); - - setFlipSided( false ); - setCullFace( CullFaceBack ); - enable( gl.CULL_FACE ); - - setBlending( NoBlending ); - - // - - function enable( id ) { - - if ( enabledCapabilities[ id ] !== true ) { - - gl.enable( id ); - enabledCapabilities[ id ] = true; - - } - - } - - function disable( id ) { - - if ( enabledCapabilities[ id ] !== false ) { - - gl.disable( id ); - enabledCapabilities[ id ] = false; - - } - - } - - function bindFramebuffer( target, framebuffer ) { - - if ( currentBoundFramebuffers[ target ] !== framebuffer ) { - - gl.bindFramebuffer( target, framebuffer ); - - currentBoundFramebuffers[ target ] = framebuffer; - - if ( isWebGL2 ) { - - // gl.DRAW_FRAMEBUFFER is equivalent to gl.FRAMEBUFFER - - if ( target === gl.DRAW_FRAMEBUFFER ) { - - currentBoundFramebuffers[ gl.FRAMEBUFFER ] = framebuffer; - - } - - if ( target === gl.FRAMEBUFFER ) { - - currentBoundFramebuffers[ gl.DRAW_FRAMEBUFFER ] = framebuffer; - - } - - } - - return true; - - } - - return false; - - } - - function drawBuffers( renderTarget, framebuffer ) { - - let drawBuffers = defaultDrawbuffers; - - let needsUpdate = false; - - if ( renderTarget ) { - - drawBuffers = currentDrawbuffers.get( framebuffer ); - - if ( drawBuffers === undefined ) { - - drawBuffers = []; - currentDrawbuffers.set( framebuffer, drawBuffers ); - - } - - if ( renderTarget.isWebGLMultipleRenderTargets ) { - - const textures = renderTarget.texture; - - if ( drawBuffers.length !== textures.length || drawBuffers[ 0 ] !== gl.COLOR_ATTACHMENT0 ) { - - for ( let i = 0, il = textures.length; i < il; i ++ ) { - - drawBuffers[ i ] = gl.COLOR_ATTACHMENT0 + i; - - } - - drawBuffers.length = textures.length; - - needsUpdate = true; - - } - - } else { - - if ( drawBuffers[ 0 ] !== gl.COLOR_ATTACHMENT0 ) { - - drawBuffers[ 0 ] = gl.COLOR_ATTACHMENT0; - - needsUpdate = true; - - } - - } - - } else { - - if ( drawBuffers[ 0 ] !== gl.BACK ) { - - drawBuffers[ 0 ] = gl.BACK; - - needsUpdate = true; - - } - - } - - if ( needsUpdate ) { - - if ( capabilities.isWebGL2 ) { - - gl.drawBuffers( drawBuffers ); - - } else { - - extensions.get( 'WEBGL_draw_buffers' ).drawBuffersWEBGL( drawBuffers ); - - } - - } - - - } - - function useProgram( program ) { - - if ( currentProgram !== program ) { - - gl.useProgram( program ); - - currentProgram = program; - - return true; - - } - - return false; - - } - - const equationToGL = { - [ AddEquation ]: gl.FUNC_ADD, - [ SubtractEquation ]: gl.FUNC_SUBTRACT, - [ ReverseSubtractEquation ]: gl.FUNC_REVERSE_SUBTRACT - }; - - if ( isWebGL2 ) { - - equationToGL[ MinEquation ] = gl.MIN; - equationToGL[ MaxEquation ] = gl.MAX; - - } else { - - const extension = extensions.get( 'EXT_blend_minmax' ); - - if ( extension !== null ) { - - equationToGL[ MinEquation ] = extension.MIN_EXT; - equationToGL[ MaxEquation ] = extension.MAX_EXT; - - } - - } - - const factorToGL = { - [ ZeroFactor ]: gl.ZERO, - [ OneFactor ]: gl.ONE, - [ SrcColorFactor ]: gl.SRC_COLOR, - [ SrcAlphaFactor ]: gl.SRC_ALPHA, - [ SrcAlphaSaturateFactor ]: gl.SRC_ALPHA_SATURATE, - [ DstColorFactor ]: gl.DST_COLOR, - [ DstAlphaFactor ]: gl.DST_ALPHA, - [ OneMinusSrcColorFactor ]: gl.ONE_MINUS_SRC_COLOR, - [ OneMinusSrcAlphaFactor ]: gl.ONE_MINUS_SRC_ALPHA, - [ OneMinusDstColorFactor ]: gl.ONE_MINUS_DST_COLOR, - [ OneMinusDstAlphaFactor ]: gl.ONE_MINUS_DST_ALPHA, - [ ConstantColorFactor ]: gl.CONSTANT_COLOR, - [ OneMinusConstantColorFactor ]: gl.ONE_MINUS_CONSTANT_COLOR, - [ ConstantAlphaFactor ]: gl.CONSTANT_ALPHA, - [ OneMinusConstantAlphaFactor ]: gl.ONE_MINUS_CONSTANT_ALPHA - }; - - function setBlending( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha, blendColor, blendAlpha, premultipliedAlpha ) { - - if ( blending === NoBlending ) { - - if ( currentBlendingEnabled === true ) { - - disable( gl.BLEND ); - currentBlendingEnabled = false; - - } - - return; - - } - - if ( currentBlendingEnabled === false ) { - - enable( gl.BLEND ); - currentBlendingEnabled = true; - - } - - if ( blending !== CustomBlending ) { - - if ( blending !== currentBlending || premultipliedAlpha !== currentPremultipledAlpha ) { - - if ( currentBlendEquation !== AddEquation || currentBlendEquationAlpha !== AddEquation ) { - - gl.blendEquation( gl.FUNC_ADD ); - - currentBlendEquation = AddEquation; - currentBlendEquationAlpha = AddEquation; - - } - - if ( premultipliedAlpha ) { - - switch ( blending ) { - - case NormalBlending: - gl.blendFuncSeparate( gl.ONE, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA ); - break; - - case AdditiveBlending: - gl.blendFunc( gl.ONE, gl.ONE ); - break; - - case SubtractiveBlending: - gl.blendFuncSeparate( gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ZERO, gl.ONE ); - break; - - case MultiplyBlending: - gl.blendFuncSeparate( gl.ZERO, gl.SRC_COLOR, gl.ZERO, gl.SRC_ALPHA ); - break; - - default: - console.error( 'THREE.WebGLState: Invalid blending: ', blending ); - break; - - } - - } else { - - switch ( blending ) { - - case NormalBlending: - gl.blendFuncSeparate( gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA ); - break; - - case AdditiveBlending: - gl.blendFunc( gl.SRC_ALPHA, gl.ONE ); - break; - - case SubtractiveBlending: - gl.blendFuncSeparate( gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ZERO, gl.ONE ); - break; - - case MultiplyBlending: - gl.blendFunc( gl.ZERO, gl.SRC_COLOR ); - break; - - default: - console.error( 'THREE.WebGLState: Invalid blending: ', blending ); - break; - - } - - } - - currentBlendSrc = null; - currentBlendDst = null; - currentBlendSrcAlpha = null; - currentBlendDstAlpha = null; - currentBlendColor.set( 0, 0, 0 ); - currentBlendAlpha = 0; - - currentBlending = blending; - currentPremultipledAlpha = premultipliedAlpha; - - } - - return; - - } - - // custom blending - - blendEquationAlpha = blendEquationAlpha || blendEquation; - blendSrcAlpha = blendSrcAlpha || blendSrc; - blendDstAlpha = blendDstAlpha || blendDst; - - if ( blendEquation !== currentBlendEquation || blendEquationAlpha !== currentBlendEquationAlpha ) { - - gl.blendEquationSeparate( equationToGL[ blendEquation ], equationToGL[ blendEquationAlpha ] ); - - currentBlendEquation = blendEquation; - currentBlendEquationAlpha = blendEquationAlpha; - - } - - if ( blendSrc !== currentBlendSrc || blendDst !== currentBlendDst || blendSrcAlpha !== currentBlendSrcAlpha || blendDstAlpha !== currentBlendDstAlpha ) { - - gl.blendFuncSeparate( factorToGL[ blendSrc ], factorToGL[ blendDst ], factorToGL[ blendSrcAlpha ], factorToGL[ blendDstAlpha ] ); - - currentBlendSrc = blendSrc; - currentBlendDst = blendDst; - currentBlendSrcAlpha = blendSrcAlpha; - currentBlendDstAlpha = blendDstAlpha; - - } - - if ( blendColor.equals( currentBlendColor ) === false || blendAlpha !== currentBlendAlpha ) { - - gl.blendColor( blendColor.r, blendColor.g, blendColor.b, blendAlpha ); - - currentBlendColor.copy( blendColor ); - currentBlendAlpha = blendAlpha; - - } - - currentBlending = blending; - currentPremultipledAlpha = false; - - } - - function setMaterial( material, frontFaceCW ) { - - material.side === DoubleSide - ? disable( gl.CULL_FACE ) - : enable( gl.CULL_FACE ); - - let flipSided = ( material.side === BackSide ); - if ( frontFaceCW ) flipSided = ! flipSided; - - setFlipSided( flipSided ); - - ( material.blending === NormalBlending && material.transparent === false ) - ? setBlending( NoBlending ) - : setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.blendColor, material.blendAlpha, material.premultipliedAlpha ); - - depthBuffer.setFunc( material.depthFunc ); - depthBuffer.setTest( material.depthTest ); - depthBuffer.setMask( material.depthWrite ); - colorBuffer.setMask( material.colorWrite ); - - const stencilWrite = material.stencilWrite; - stencilBuffer.setTest( stencilWrite ); - if ( stencilWrite ) { - - stencilBuffer.setMask( material.stencilWriteMask ); - stencilBuffer.setFunc( material.stencilFunc, material.stencilRef, material.stencilFuncMask ); - stencilBuffer.setOp( material.stencilFail, material.stencilZFail, material.stencilZPass ); - - } - - setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits ); - - material.alphaToCoverage === true - ? enable( gl.SAMPLE_ALPHA_TO_COVERAGE ) - : disable( gl.SAMPLE_ALPHA_TO_COVERAGE ); - - } - - // - - function setFlipSided( flipSided ) { - - if ( currentFlipSided !== flipSided ) { - - if ( flipSided ) { - - gl.frontFace( gl.CW ); - - } else { - - gl.frontFace( gl.CCW ); - - } - - currentFlipSided = flipSided; - - } - - } - - function setCullFace( cullFace ) { - - if ( cullFace !== CullFaceNone ) { - - enable( gl.CULL_FACE ); - - if ( cullFace !== currentCullFace ) { - - if ( cullFace === CullFaceBack ) { - - gl.cullFace( gl.BACK ); - - } else if ( cullFace === CullFaceFront ) { - - gl.cullFace( gl.FRONT ); - - } else { - - gl.cullFace( gl.FRONT_AND_BACK ); - - } - - } - - } else { - - disable( gl.CULL_FACE ); - - } - - currentCullFace = cullFace; - - } - - function setLineWidth( width ) { - - if ( width !== currentLineWidth ) { - - if ( lineWidthAvailable ) gl.lineWidth( width ); - - currentLineWidth = width; - - } - - } - - function setPolygonOffset( polygonOffset, factor, units ) { - - if ( polygonOffset ) { - - enable( gl.POLYGON_OFFSET_FILL ); - - if ( currentPolygonOffsetFactor !== factor || currentPolygonOffsetUnits !== units ) { - - gl.polygonOffset( factor, units ); - - currentPolygonOffsetFactor = factor; - currentPolygonOffsetUnits = units; - - } - - } else { - - disable( gl.POLYGON_OFFSET_FILL ); - - } - - } - - function setScissorTest( scissorTest ) { - - if ( scissorTest ) { - - enable( gl.SCISSOR_TEST ); - - } else { - - disable( gl.SCISSOR_TEST ); - - } - - } - - // texture - - function activeTexture( webglSlot ) { - - if ( webglSlot === undefined ) webglSlot = gl.TEXTURE0 + maxTextures - 1; - - if ( currentTextureSlot !== webglSlot ) { - - gl.activeTexture( webglSlot ); - currentTextureSlot = webglSlot; - - } - - } - - function bindTexture( webglType, webglTexture, webglSlot ) { - - if ( webglSlot === undefined ) { - - if ( currentTextureSlot === null ) { - - webglSlot = gl.TEXTURE0 + maxTextures - 1; - - } else { - - webglSlot = currentTextureSlot; - - } - - } - - let boundTexture = currentBoundTextures[ webglSlot ]; - - if ( boundTexture === undefined ) { - - boundTexture = { type: undefined, texture: undefined }; - currentBoundTextures[ webglSlot ] = boundTexture; - - } - - if ( boundTexture.type !== webglType || boundTexture.texture !== webglTexture ) { - - if ( currentTextureSlot !== webglSlot ) { - - gl.activeTexture( webglSlot ); - currentTextureSlot = webglSlot; - - } - - gl.bindTexture( webglType, webglTexture || emptyTextures[ webglType ] ); - - boundTexture.type = webglType; - boundTexture.texture = webglTexture; - - } - - } - - function unbindTexture() { - - const boundTexture = currentBoundTextures[ currentTextureSlot ]; - - if ( boundTexture !== undefined && boundTexture.type !== undefined ) { - - gl.bindTexture( boundTexture.type, null ); - - boundTexture.type = undefined; - boundTexture.texture = undefined; - - } - - } - - function compressedTexImage2D() { - - try { - - gl.compressedTexImage2D.apply( gl, arguments ); - - } catch ( error ) { - - console.error( 'THREE.WebGLState:', error ); - - } - - } - - function compressedTexImage3D() { - - try { - - gl.compressedTexImage3D.apply( gl, arguments ); - - } catch ( error ) { - - console.error( 'THREE.WebGLState:', error ); - - } - - } - - function texSubImage2D() { - - try { - - gl.texSubImage2D.apply( gl, arguments ); - - } catch ( error ) { - - console.error( 'THREE.WebGLState:', error ); - - } - - } - - function texSubImage3D() { - - try { - - gl.texSubImage3D.apply( gl, arguments ); - - } catch ( error ) { - - console.error( 'THREE.WebGLState:', error ); - - } - - } - - function compressedTexSubImage2D() { - - try { - - gl.compressedTexSubImage2D.apply( gl, arguments ); - - } catch ( error ) { - - console.error( 'THREE.WebGLState:', error ); - - } - - } - - function compressedTexSubImage3D() { - - try { - - gl.compressedTexSubImage3D.apply( gl, arguments ); - - } catch ( error ) { - - console.error( 'THREE.WebGLState:', error ); - - } - - } - - function texStorage2D() { - - try { - - gl.texStorage2D.apply( gl, arguments ); - - } catch ( error ) { - - console.error( 'THREE.WebGLState:', error ); - - } - - } - - function texStorage3D() { - - try { - - gl.texStorage3D.apply( gl, arguments ); - - } catch ( error ) { - - console.error( 'THREE.WebGLState:', error ); - - } - - } - - function texImage2D() { - - try { - - gl.texImage2D.apply( gl, arguments ); - - } catch ( error ) { - - console.error( 'THREE.WebGLState:', error ); - - } - - } - - function texImage3D() { - - try { - - gl.texImage3D.apply( gl, arguments ); - - } catch ( error ) { - - console.error( 'THREE.WebGLState:', error ); - - } - - } - - // - - function scissor( scissor ) { - - if ( currentScissor.equals( scissor ) === false ) { - - gl.scissor( scissor.x, scissor.y, scissor.z, scissor.w ); - currentScissor.copy( scissor ); - - } - - } - - function viewport( viewport ) { - - if ( currentViewport.equals( viewport ) === false ) { - - gl.viewport( viewport.x, viewport.y, viewport.z, viewport.w ); - currentViewport.copy( viewport ); - - } - - } - - function updateUBOMapping( uniformsGroup, program ) { - - let mapping = uboProgramMap.get( program ); - - if ( mapping === undefined ) { - - mapping = new WeakMap(); - - uboProgramMap.set( program, mapping ); - - } - - let blockIndex = mapping.get( uniformsGroup ); - - if ( blockIndex === undefined ) { - - blockIndex = gl.getUniformBlockIndex( program, uniformsGroup.name ); - - mapping.set( uniformsGroup, blockIndex ); - - } - - } - - function uniformBlockBinding( uniformsGroup, program ) { - - const mapping = uboProgramMap.get( program ); - const blockIndex = mapping.get( uniformsGroup ); - - if ( uboBindings.get( program ) !== blockIndex ) { - - // bind shader specific block index to global block point - gl.uniformBlockBinding( program, blockIndex, uniformsGroup.__bindingPointIndex ); - - uboBindings.set( program, blockIndex ); - - } - - } - - // - - function reset() { - - // reset state - - gl.disable( gl.BLEND ); - gl.disable( gl.CULL_FACE ); - gl.disable( gl.DEPTH_TEST ); - gl.disable( gl.POLYGON_OFFSET_FILL ); - gl.disable( gl.SCISSOR_TEST ); - gl.disable( gl.STENCIL_TEST ); - gl.disable( gl.SAMPLE_ALPHA_TO_COVERAGE ); - - gl.blendEquation( gl.FUNC_ADD ); - gl.blendFunc( gl.ONE, gl.ZERO ); - gl.blendFuncSeparate( gl.ONE, gl.ZERO, gl.ONE, gl.ZERO ); - gl.blendColor( 0, 0, 0, 0 ); - - gl.colorMask( true, true, true, true ); - gl.clearColor( 0, 0, 0, 0 ); - - gl.depthMask( true ); - gl.depthFunc( gl.LESS ); - gl.clearDepth( 1 ); - - gl.stencilMask( 0xffffffff ); - gl.stencilFunc( gl.ALWAYS, 0, 0xffffffff ); - gl.stencilOp( gl.KEEP, gl.KEEP, gl.KEEP ); - gl.clearStencil( 0 ); - - gl.cullFace( gl.BACK ); - gl.frontFace( gl.CCW ); - - gl.polygonOffset( 0, 0 ); - - gl.activeTexture( gl.TEXTURE0 ); - - gl.bindFramebuffer( gl.FRAMEBUFFER, null ); - - if ( isWebGL2 === true ) { - - gl.bindFramebuffer( gl.DRAW_FRAMEBUFFER, null ); - gl.bindFramebuffer( gl.READ_FRAMEBUFFER, null ); - - } - - gl.useProgram( null ); - - gl.lineWidth( 1 ); - - gl.scissor( 0, 0, gl.canvas.width, gl.canvas.height ); - gl.viewport( 0, 0, gl.canvas.width, gl.canvas.height ); - - // reset internals - - enabledCapabilities = {}; - - currentTextureSlot = null; - currentBoundTextures = {}; - - currentBoundFramebuffers = {}; - currentDrawbuffers = new WeakMap(); - defaultDrawbuffers = []; - - currentProgram = null; - - currentBlendingEnabled = false; - currentBlending = null; - currentBlendEquation = null; - currentBlendSrc = null; - currentBlendDst = null; - currentBlendEquationAlpha = null; - currentBlendSrcAlpha = null; - currentBlendDstAlpha = null; - currentBlendColor = new Color( 0, 0, 0 ); - currentBlendAlpha = 0; - currentPremultipledAlpha = false; - - currentFlipSided = null; - currentCullFace = null; - - currentLineWidth = null; - - currentPolygonOffsetFactor = null; - currentPolygonOffsetUnits = null; - - currentScissor.set( 0, 0, gl.canvas.width, gl.canvas.height ); - currentViewport.set( 0, 0, gl.canvas.width, gl.canvas.height ); - - colorBuffer.reset(); - depthBuffer.reset(); - stencilBuffer.reset(); - - } - - return { - - buffers: { - color: colorBuffer, - depth: depthBuffer, - stencil: stencilBuffer - }, - - enable: enable, - disable: disable, - - bindFramebuffer: bindFramebuffer, - drawBuffers: drawBuffers, - - useProgram: useProgram, - - setBlending: setBlending, - setMaterial: setMaterial, - - setFlipSided: setFlipSided, - setCullFace: setCullFace, - - setLineWidth: setLineWidth, - setPolygonOffset: setPolygonOffset, - - setScissorTest: setScissorTest, - - activeTexture: activeTexture, - bindTexture: bindTexture, - unbindTexture: unbindTexture, - compressedTexImage2D: compressedTexImage2D, - compressedTexImage3D: compressedTexImage3D, - texImage2D: texImage2D, - texImage3D: texImage3D, - - updateUBOMapping: updateUBOMapping, - uniformBlockBinding: uniformBlockBinding, - - texStorage2D: texStorage2D, - texStorage3D: texStorage3D, - texSubImage2D: texSubImage2D, - texSubImage3D: texSubImage3D, - compressedTexSubImage2D: compressedTexSubImage2D, - compressedTexSubImage3D: compressedTexSubImage3D, - - scissor: scissor, - viewport: viewport, - - reset: reset - - }; - -} - -function WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info ) { - - const isWebGL2 = capabilities.isWebGL2; - const multisampledRTTExt = extensions.has( 'WEBGL_multisampled_render_to_texture' ) ? extensions.get( 'WEBGL_multisampled_render_to_texture' ) : null; - const supportsInvalidateFramebuffer = typeof navigator === 'undefined' ? false : /OculusBrowser/g.test( navigator.userAgent ); - - const _videoTextures = new WeakMap(); - let _canvas; - - const _sources = new WeakMap(); // maps WebglTexture objects to instances of Source - - // cordova iOS (as of 5.0) still uses UIWebView, which provides OffscreenCanvas, - // also OffscreenCanvas.getContext("webgl"), but not OffscreenCanvas.getContext("2d")! - // Some implementations may only implement OffscreenCanvas partially (e.g. lacking 2d). - - let useOffscreenCanvas = false; - - try { - - useOffscreenCanvas = typeof OffscreenCanvas !== 'undefined' - // eslint-disable-next-line compat/compat - && ( new OffscreenCanvas( 1, 1 ).getContext( '2d' ) ) !== null; - - } catch ( err ) { - - // Ignore any errors - - } - - function createCanvas( width, height ) { - - // Use OffscreenCanvas when available. Specially needed in web workers - - return useOffscreenCanvas ? - // eslint-disable-next-line compat/compat - new OffscreenCanvas( width, height ) : createElementNS( 'canvas' ); - - } - - function resizeImage( image, needsPowerOfTwo, needsNewCanvas, maxSize ) { - - let scale = 1; - - // handle case if texture exceeds max size - - if ( image.width > maxSize || image.height > maxSize ) { - - scale = maxSize / Math.max( image.width, image.height ); - - } - - // only perform resize if necessary - - if ( scale < 1 || needsPowerOfTwo === true ) { - - // only perform resize for certain image types - - if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) || - ( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) || - ( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) { - - const floor = needsPowerOfTwo ? floorPowerOfTwo : Math.floor; - - const width = floor( scale * image.width ); - const height = floor( scale * image.height ); - - if ( _canvas === undefined ) _canvas = createCanvas( width, height ); - - // cube textures can't reuse the same canvas - - const canvas = needsNewCanvas ? createCanvas( width, height ) : _canvas; - - canvas.width = width; - canvas.height = height; - - const context = canvas.getContext( '2d' ); - context.drawImage( image, 0, 0, width, height ); - - console.warn( 'THREE.WebGLRenderer: Texture has been resized from (' + image.width + 'x' + image.height + ') to (' + width + 'x' + height + ').' ); - - return canvas; - - } else { - - if ( 'data' in image ) { - - console.warn( 'THREE.WebGLRenderer: Image in DataTexture is too big (' + image.width + 'x' + image.height + ').' ); - - } - - return image; - - } - - } - - return image; - - } - - function isPowerOfTwo$1( image ) { - - return isPowerOfTwo( image.width ) && isPowerOfTwo( image.height ); - - } - - function textureNeedsPowerOfTwo( texture ) { - - if ( isWebGL2 ) return false; - - return ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) || - ( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ); - - } - - function textureNeedsGenerateMipmaps( texture, supportsMips ) { - - return texture.generateMipmaps && supportsMips && - texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter; - - } - - function generateMipmap( target ) { - - _gl.generateMipmap( target ); - - } - - function getInternalFormat( internalFormatName, glFormat, glType, colorSpace, forceLinearTransfer = false ) { - - if ( isWebGL2 === false ) return glFormat; - - if ( internalFormatName !== null ) { - - if ( _gl[ internalFormatName ] !== undefined ) return _gl[ internalFormatName ]; - - console.warn( 'THREE.WebGLRenderer: Attempt to use non-existing WebGL internal format \'' + internalFormatName + '\'' ); - - } - - let internalFormat = glFormat; - - if ( glFormat === _gl.RED ) { - - if ( glType === _gl.FLOAT ) internalFormat = _gl.R32F; - if ( glType === _gl.HALF_FLOAT ) internalFormat = _gl.R16F; - if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.R8; - - } - - if ( glFormat === _gl.RED_INTEGER ) { - - if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.R8UI; - if ( glType === _gl.UNSIGNED_SHORT ) internalFormat = _gl.R16UI; - if ( glType === _gl.UNSIGNED_INT ) internalFormat = _gl.R32UI; - if ( glType === _gl.BYTE ) internalFormat = _gl.R8I; - if ( glType === _gl.SHORT ) internalFormat = _gl.R16I; - if ( glType === _gl.INT ) internalFormat = _gl.R32I; - - } - - if ( glFormat === _gl.RG ) { - - if ( glType === _gl.FLOAT ) internalFormat = _gl.RG32F; - if ( glType === _gl.HALF_FLOAT ) internalFormat = _gl.RG16F; - if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.RG8; - - } - - if ( glFormat === _gl.RGBA ) { - - const transfer = forceLinearTransfer ? LinearTransfer : ColorManagement.getTransfer( colorSpace ); - - if ( glType === _gl.FLOAT ) internalFormat = _gl.RGBA32F; - if ( glType === _gl.HALF_FLOAT ) internalFormat = _gl.RGBA16F; - if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = ( transfer === SRGBTransfer ) ? _gl.SRGB8_ALPHA8 : _gl.RGBA8; - if ( glType === _gl.UNSIGNED_SHORT_4_4_4_4 ) internalFormat = _gl.RGBA4; - if ( glType === _gl.UNSIGNED_SHORT_5_5_5_1 ) internalFormat = _gl.RGB5_A1; - - } - - if ( internalFormat === _gl.R16F || internalFormat === _gl.R32F || - internalFormat === _gl.RG16F || internalFormat === _gl.RG32F || - internalFormat === _gl.RGBA16F || internalFormat === _gl.RGBA32F ) { - - extensions.get( 'EXT_color_buffer_float' ); - - } - - return internalFormat; - - } - - function getMipLevels( texture, image, supportsMips ) { - - if ( textureNeedsGenerateMipmaps( texture, supportsMips ) === true || ( texture.isFramebufferTexture && texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ) ) { - - return Math.log2( Math.max( image.width, image.height ) ) + 1; - - } else if ( texture.mipmaps !== undefined && texture.mipmaps.length > 0 ) { - - // user-defined mipmaps - - return texture.mipmaps.length; - - } else if ( texture.isCompressedTexture && Array.isArray( texture.image ) ) { - - return image.mipmaps.length; - - } else { - - // texture without mipmaps (only base level) - - return 1; - - } - - } - - // Fallback filters for non-power-of-2 textures - - function filterFallback( f ) { - - if ( f === NearestFilter || f === NearestMipmapNearestFilter || f === NearestMipmapLinearFilter ) { - - return _gl.NEAREST; - - } - - return _gl.LINEAR; - - } - - // - - function onTextureDispose( event ) { - - const texture = event.target; - - texture.removeEventListener( 'dispose', onTextureDispose ); - - deallocateTexture( texture ); - - if ( texture.isVideoTexture ) { - - _videoTextures.delete( texture ); - - } - - } - - function onRenderTargetDispose( event ) { - - const renderTarget = event.target; - - renderTarget.removeEventListener( 'dispose', onRenderTargetDispose ); - - deallocateRenderTarget( renderTarget ); - - } - - // - - function deallocateTexture( texture ) { - - const textureProperties = properties.get( texture ); - - if ( textureProperties.__webglInit === undefined ) return; - - // check if it's necessary to remove the WebGLTexture object - - const source = texture.source; - const webglTextures = _sources.get( source ); - - if ( webglTextures ) { - - const webglTexture = webglTextures[ textureProperties.__cacheKey ]; - webglTexture.usedTimes --; - - // the WebGLTexture object is not used anymore, remove it - - if ( webglTexture.usedTimes === 0 ) { - - deleteTexture( texture ); - - } - - // remove the weak map entry if no WebGLTexture uses the source anymore - - if ( Object.keys( webglTextures ).length === 0 ) { - - _sources.delete( source ); - - } - - } - - properties.remove( texture ); - - } - - function deleteTexture( texture ) { - - const textureProperties = properties.get( texture ); - _gl.deleteTexture( textureProperties.__webglTexture ); - - const source = texture.source; - const webglTextures = _sources.get( source ); - delete webglTextures[ textureProperties.__cacheKey ]; - - info.memory.textures --; - - } - - function deallocateRenderTarget( renderTarget ) { - - const texture = renderTarget.texture; - - const renderTargetProperties = properties.get( renderTarget ); - const textureProperties = properties.get( texture ); - - if ( textureProperties.__webglTexture !== undefined ) { - - _gl.deleteTexture( textureProperties.__webglTexture ); - - info.memory.textures --; - - } - - if ( renderTarget.depthTexture ) { - - renderTarget.depthTexture.dispose(); - - } - - if ( renderTarget.isWebGLCubeRenderTarget ) { - - for ( let i = 0; i < 6; i ++ ) { - - if ( Array.isArray( renderTargetProperties.__webglFramebuffer[ i ] ) ) { - - for ( let level = 0; level < renderTargetProperties.__webglFramebuffer[ i ].length; level ++ ) _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ i ][ level ] ); - - } else { - - _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ i ] ); - - } - - if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer[ i ] ); - - } - - } else { - - if ( Array.isArray( renderTargetProperties.__webglFramebuffer ) ) { - - for ( let level = 0; level < renderTargetProperties.__webglFramebuffer.length; level ++ ) _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ level ] ); - - } else { - - _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer ); - - } - - if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer ); - if ( renderTargetProperties.__webglMultisampledFramebuffer ) _gl.deleteFramebuffer( renderTargetProperties.__webglMultisampledFramebuffer ); - - if ( renderTargetProperties.__webglColorRenderbuffer ) { - - for ( let i = 0; i < renderTargetProperties.__webglColorRenderbuffer.length; i ++ ) { - - if ( renderTargetProperties.__webglColorRenderbuffer[ i ] ) _gl.deleteRenderbuffer( renderTargetProperties.__webglColorRenderbuffer[ i ] ); - - } - - } - - if ( renderTargetProperties.__webglDepthRenderbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthRenderbuffer ); - - } - - if ( renderTarget.isWebGLMultipleRenderTargets ) { - - for ( let i = 0, il = texture.length; i < il; i ++ ) { - - const attachmentProperties = properties.get( texture[ i ] ); - - if ( attachmentProperties.__webglTexture ) { - - _gl.deleteTexture( attachmentProperties.__webglTexture ); - - info.memory.textures --; - - } - - properties.remove( texture[ i ] ); - - } - - } - - properties.remove( texture ); - properties.remove( renderTarget ); - - } - - // - - let textureUnits = 0; - - function resetTextureUnits() { - - textureUnits = 0; - - } - - function allocateTextureUnit() { - - const textureUnit = textureUnits; - - if ( textureUnit >= capabilities.maxTextures ) { - - console.warn( 'THREE.WebGLTextures: Trying to use ' + textureUnit + ' texture units while this GPU supports only ' + capabilities.maxTextures ); - - } - - textureUnits += 1; - - return textureUnit; - - } - - function getTextureCacheKey( texture ) { - - const array = []; - - array.push( texture.wrapS ); - array.push( texture.wrapT ); - array.push( texture.wrapR || 0 ); - array.push( texture.magFilter ); - array.push( texture.minFilter ); - array.push( texture.anisotropy ); - array.push( texture.internalFormat ); - array.push( texture.format ); - array.push( texture.type ); - array.push( texture.generateMipmaps ); - array.push( texture.premultiplyAlpha ); - array.push( texture.flipY ); - array.push( texture.unpackAlignment ); - array.push( texture.colorSpace ); - - return array.join(); - - } - - // - - function setTexture2D( texture, slot ) { - - const textureProperties = properties.get( texture ); - - if ( texture.isVideoTexture ) updateVideoTexture( texture ); - - if ( texture.isRenderTargetTexture === false && texture.version > 0 && textureProperties.__version !== texture.version ) { - - const image = texture.image; - - if ( image === null ) { - - console.warn( 'THREE.WebGLRenderer: Texture marked for update but no image data found.' ); - - } else if ( image.complete === false ) { - - console.warn( 'THREE.WebGLRenderer: Texture marked for update but image is incomplete' ); - - } else { - - uploadTexture( textureProperties, texture, slot ); - return; - - } - - } - - state.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture, _gl.TEXTURE0 + slot ); - - } - - function setTexture2DArray( texture, slot ) { - - const textureProperties = properties.get( texture ); - - if ( texture.version > 0 && textureProperties.__version !== texture.version ) { - - uploadTexture( textureProperties, texture, slot ); - return; - - } - - state.bindTexture( _gl.TEXTURE_2D_ARRAY, textureProperties.__webglTexture, _gl.TEXTURE0 + slot ); - - } - - function setTexture3D( texture, slot ) { - - const textureProperties = properties.get( texture ); - - if ( texture.version > 0 && textureProperties.__version !== texture.version ) { - - uploadTexture( textureProperties, texture, slot ); - return; - - } - - state.bindTexture( _gl.TEXTURE_3D, textureProperties.__webglTexture, _gl.TEXTURE0 + slot ); - - } - - function setTextureCube( texture, slot ) { - - const textureProperties = properties.get( texture ); - - if ( texture.version > 0 && textureProperties.__version !== texture.version ) { - - uploadCubeTexture( textureProperties, texture, slot ); - return; - - } - - state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture, _gl.TEXTURE0 + slot ); - - } - - const wrappingToGL = { - [ RepeatWrapping ]: _gl.REPEAT, - [ ClampToEdgeWrapping ]: _gl.CLAMP_TO_EDGE, - [ MirroredRepeatWrapping ]: _gl.MIRRORED_REPEAT - }; - - const filterToGL = { - [ NearestFilter ]: _gl.NEAREST, - [ NearestMipmapNearestFilter ]: _gl.NEAREST_MIPMAP_NEAREST, - [ NearestMipmapLinearFilter ]: _gl.NEAREST_MIPMAP_LINEAR, - - [ LinearFilter ]: _gl.LINEAR, - [ LinearMipmapNearestFilter ]: _gl.LINEAR_MIPMAP_NEAREST, - [ LinearMipmapLinearFilter ]: _gl.LINEAR_MIPMAP_LINEAR - }; - - const compareToGL = { - [ NeverCompare ]: _gl.NEVER, - [ AlwaysCompare ]: _gl.ALWAYS, - [ LessCompare ]: _gl.LESS, - [ LessEqualCompare ]: _gl.LEQUAL, - [ EqualCompare ]: _gl.EQUAL, - [ GreaterEqualCompare ]: _gl.GEQUAL, - [ GreaterCompare ]: _gl.GREATER, - [ NotEqualCompare ]: _gl.NOTEQUAL - }; - - function setTextureParameters( textureType, texture, supportsMips ) { - - if ( texture.type === FloatType && extensions.has( 'OES_texture_float_linear' ) === false && - ( texture.magFilter === LinearFilter || texture.magFilter === LinearMipmapNearestFilter || texture.magFilter === NearestMipmapLinearFilter || texture.magFilter === LinearMipmapLinearFilter || - texture.minFilter === LinearFilter || texture.minFilter === LinearMipmapNearestFilter || texture.minFilter === NearestMipmapLinearFilter || texture.minFilter === LinearMipmapLinearFilter ) ) { - - console.warn( 'THREE.WebGLRenderer: Unable to use linear filtering with floating point textures. OES_texture_float_linear not supported on this device.' ); - - } - - if ( supportsMips ) { - - _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, wrappingToGL[ texture.wrapS ] ); - _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, wrappingToGL[ texture.wrapT ] ); - - if ( textureType === _gl.TEXTURE_3D || textureType === _gl.TEXTURE_2D_ARRAY ) { - - _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_R, wrappingToGL[ texture.wrapR ] ); - - } - - _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterToGL[ texture.magFilter ] ); - _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterToGL[ texture.minFilter ] ); - - } else { - - _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE ); - _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE ); - - if ( textureType === _gl.TEXTURE_3D || textureType === _gl.TEXTURE_2D_ARRAY ) { - - _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_R, _gl.CLAMP_TO_EDGE ); - - } - - if ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) { - - console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.wrapS and Texture.wrapT should be set to THREE.ClampToEdgeWrapping.' ); - - } - - _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterFallback( texture.magFilter ) ); - _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterFallback( texture.minFilter ) ); - - if ( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ) { - - console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.minFilter should be set to THREE.NearestFilter or THREE.LinearFilter.' ); - - } - - } - - if ( texture.compareFunction ) { - - _gl.texParameteri( textureType, _gl.TEXTURE_COMPARE_MODE, _gl.COMPARE_REF_TO_TEXTURE ); - _gl.texParameteri( textureType, _gl.TEXTURE_COMPARE_FUNC, compareToGL[ texture.compareFunction ] ); - - } - - if ( extensions.has( 'EXT_texture_filter_anisotropic' ) === true ) { - - const extension = extensions.get( 'EXT_texture_filter_anisotropic' ); - - if ( texture.magFilter === NearestFilter ) return; - if ( texture.minFilter !== NearestMipmapLinearFilter && texture.minFilter !== LinearMipmapLinearFilter ) return; - if ( texture.type === FloatType && extensions.has( 'OES_texture_float_linear' ) === false ) return; // verify extension for WebGL 1 and WebGL 2 - if ( isWebGL2 === false && ( texture.type === HalfFloatType && extensions.has( 'OES_texture_half_float_linear' ) === false ) ) return; // verify extension for WebGL 1 only - - if ( texture.anisotropy > 1 || properties.get( texture ).__currentAnisotropy ) { - - _gl.texParameterf( textureType, extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, capabilities.getMaxAnisotropy() ) ); - properties.get( texture ).__currentAnisotropy = texture.anisotropy; - - } - - } - - } - - function initTexture( textureProperties, texture ) { - - let forceUpload = false; - - if ( textureProperties.__webglInit === undefined ) { - - textureProperties.__webglInit = true; - - texture.addEventListener( 'dispose', onTextureDispose ); - - } - - // create Source <-> WebGLTextures mapping if necessary - - const source = texture.source; - let webglTextures = _sources.get( source ); - - if ( webglTextures === undefined ) { - - webglTextures = {}; - _sources.set( source, webglTextures ); - - } - - // check if there is already a WebGLTexture object for the given texture parameters - - const textureCacheKey = getTextureCacheKey( texture ); - - if ( textureCacheKey !== textureProperties.__cacheKey ) { - - // if not, create a new instance of WebGLTexture - - if ( webglTextures[ textureCacheKey ] === undefined ) { - - // create new entry - - webglTextures[ textureCacheKey ] = { - texture: _gl.createTexture(), - usedTimes: 0 - }; - - info.memory.textures ++; - - // when a new instance of WebGLTexture was created, a texture upload is required - // even if the image contents are identical - - forceUpload = true; - - } - - webglTextures[ textureCacheKey ].usedTimes ++; - - // every time the texture cache key changes, it's necessary to check if an instance of - // WebGLTexture can be deleted in order to avoid a memory leak. - - const webglTexture = webglTextures[ textureProperties.__cacheKey ]; - - if ( webglTexture !== undefined ) { - - webglTextures[ textureProperties.__cacheKey ].usedTimes --; - - if ( webglTexture.usedTimes === 0 ) { - - deleteTexture( texture ); - - } - - } - - // store references to cache key and WebGLTexture object - - textureProperties.__cacheKey = textureCacheKey; - textureProperties.__webglTexture = webglTextures[ textureCacheKey ].texture; - - } - - return forceUpload; - - } - - function uploadTexture( textureProperties, texture, slot ) { - - let textureType = _gl.TEXTURE_2D; - - if ( texture.isDataArrayTexture || texture.isCompressedArrayTexture ) textureType = _gl.TEXTURE_2D_ARRAY; - if ( texture.isData3DTexture ) textureType = _gl.TEXTURE_3D; - - const forceUpload = initTexture( textureProperties, texture ); - const source = texture.source; - - state.bindTexture( textureType, textureProperties.__webglTexture, _gl.TEXTURE0 + slot ); - - const sourceProperties = properties.get( source ); - - if ( source.version !== sourceProperties.__version || forceUpload === true ) { - - state.activeTexture( _gl.TEXTURE0 + slot ); - - const workingPrimaries = ColorManagement.getPrimaries( ColorManagement.workingColorSpace ); - const texturePrimaries = texture.colorSpace === NoColorSpace ? null : ColorManagement.getPrimaries( texture.colorSpace ); - const unpackConversion = texture.colorSpace === NoColorSpace || workingPrimaries === texturePrimaries ? _gl.NONE : _gl.BROWSER_DEFAULT_WEBGL; - - _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY ); - _gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha ); - _gl.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment ); - _gl.pixelStorei( _gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, unpackConversion ); - - const needsPowerOfTwo = textureNeedsPowerOfTwo( texture ) && isPowerOfTwo$1( texture.image ) === false; - let image = resizeImage( texture.image, needsPowerOfTwo, false, capabilities.maxTextureSize ); - image = verifyColorSpace( texture, image ); - - const supportsMips = isPowerOfTwo$1( image ) || isWebGL2, - glFormat = utils.convert( texture.format, texture.colorSpace ); - - let glType = utils.convert( texture.type ), - glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace, texture.isVideoTexture ); - - setTextureParameters( textureType, texture, supportsMips ); - - let mipmap; - const mipmaps = texture.mipmaps; - - const useTexStorage = ( isWebGL2 && texture.isVideoTexture !== true && glInternalFormat !== RGB_ETC1_Format ); - const allocateMemory = ( sourceProperties.__version === undefined ) || ( forceUpload === true ); - const dataReady = source.dataReady; - const levels = getMipLevels( texture, image, supportsMips ); - - if ( texture.isDepthTexture ) { - - // populate depth texture with dummy data - - glInternalFormat = _gl.DEPTH_COMPONENT; - - if ( isWebGL2 ) { - - if ( texture.type === FloatType ) { - - glInternalFormat = _gl.DEPTH_COMPONENT32F; - - } else if ( texture.type === UnsignedIntType ) { - - glInternalFormat = _gl.DEPTH_COMPONENT24; - - } else if ( texture.type === UnsignedInt248Type ) { - - glInternalFormat = _gl.DEPTH24_STENCIL8; - - } else { - - glInternalFormat = _gl.DEPTH_COMPONENT16; // WebGL2 requires sized internalformat for glTexImage2D - - } - - } else { - - if ( texture.type === FloatType ) { - - console.error( 'WebGLRenderer: Floating point depth texture requires WebGL2.' ); - - } - - } - - // validation checks for WebGL 1 - - if ( texture.format === DepthFormat && glInternalFormat === _gl.DEPTH_COMPONENT ) { - - // The error INVALID_OPERATION is generated by texImage2D if format and internalformat are - // DEPTH_COMPONENT and type is not UNSIGNED_SHORT or UNSIGNED_INT - // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/) - if ( texture.type !== UnsignedShortType && texture.type !== UnsignedIntType ) { - - console.warn( 'THREE.WebGLRenderer: Use UnsignedShortType or UnsignedIntType for DepthFormat DepthTexture.' ); - - texture.type = UnsignedIntType; - glType = utils.convert( texture.type ); - - } - - } - - if ( texture.format === DepthStencilFormat && glInternalFormat === _gl.DEPTH_COMPONENT ) { - - // Depth stencil textures need the DEPTH_STENCIL internal format - // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/) - glInternalFormat = _gl.DEPTH_STENCIL; - - // The error INVALID_OPERATION is generated by texImage2D if format and internalformat are - // DEPTH_STENCIL and type is not UNSIGNED_INT_24_8_WEBGL. - // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/) - if ( texture.type !== UnsignedInt248Type ) { - - console.warn( 'THREE.WebGLRenderer: Use UnsignedInt248Type for DepthStencilFormat DepthTexture.' ); - - texture.type = UnsignedInt248Type; - glType = utils.convert( texture.type ); - - } - - } - - // - - if ( allocateMemory ) { - - if ( useTexStorage ) { - - state.texStorage2D( _gl.TEXTURE_2D, 1, glInternalFormat, image.width, image.height ); - - } else { - - state.texImage2D( _gl.TEXTURE_2D, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, null ); - - } - - } - - } else if ( texture.isDataTexture ) { - - // use manually created mipmaps if available - // if there are no manual mipmaps - // set 0 level mipmap and then use GL to generate other mipmap levels - - if ( mipmaps.length > 0 && supportsMips ) { - - if ( useTexStorage && allocateMemory ) { - - state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height ); - - } - - for ( let i = 0, il = mipmaps.length; i < il; i ++ ) { - - mipmap = mipmaps[ i ]; - - if ( useTexStorage ) { - - if ( dataReady ) { - - state.texSubImage2D( _gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data ); - - } - - } else { - - state.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); - - } - - } - - texture.generateMipmaps = false; - - } else { - - if ( useTexStorage ) { - - if ( allocateMemory ) { - - state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, image.width, image.height ); - - } - - if ( dataReady ) { - - state.texSubImage2D( _gl.TEXTURE_2D, 0, 0, 0, image.width, image.height, glFormat, glType, image.data ); - - } - - } else { - - state.texImage2D( _gl.TEXTURE_2D, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, image.data ); - - } - - } - - } else if ( texture.isCompressedTexture ) { - - if ( texture.isCompressedArrayTexture ) { - - if ( useTexStorage && allocateMemory ) { - - state.texStorage3D( _gl.TEXTURE_2D_ARRAY, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height, image.depth ); - - } - - for ( let i = 0, il = mipmaps.length; i < il; i ++ ) { - - mipmap = mipmaps[ i ]; - - if ( texture.format !== RGBAFormat ) { - - if ( glFormat !== null ) { - - if ( useTexStorage ) { - - if ( dataReady ) { - - state.compressedTexSubImage3D( _gl.TEXTURE_2D_ARRAY, i, 0, 0, 0, mipmap.width, mipmap.height, image.depth, glFormat, mipmap.data, 0, 0 ); - - } - - } else { - - state.compressedTexImage3D( _gl.TEXTURE_2D_ARRAY, i, glInternalFormat, mipmap.width, mipmap.height, image.depth, 0, mipmap.data, 0, 0 ); - - } - - } else { - - console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()' ); - - } - - } else { - - if ( useTexStorage ) { - - if ( dataReady ) { - - state.texSubImage3D( _gl.TEXTURE_2D_ARRAY, i, 0, 0, 0, mipmap.width, mipmap.height, image.depth, glFormat, glType, mipmap.data ); - - } - - } else { - - state.texImage3D( _gl.TEXTURE_2D_ARRAY, i, glInternalFormat, mipmap.width, mipmap.height, image.depth, 0, glFormat, glType, mipmap.data ); - - } - - } - - } - - } else { - - if ( useTexStorage && allocateMemory ) { - - state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height ); - - } - - for ( let i = 0, il = mipmaps.length; i < il; i ++ ) { - - mipmap = mipmaps[ i ]; - - if ( texture.format !== RGBAFormat ) { - - if ( glFormat !== null ) { - - if ( useTexStorage ) { - - if ( dataReady ) { - - state.compressedTexSubImage2D( _gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, mipmap.data ); - - } - - } else { - - state.compressedTexImage2D( _gl.TEXTURE_2D, i, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data ); - - } - - } else { - - console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()' ); - - } - - } else { - - if ( useTexStorage ) { - - if ( dataReady ) { - - state.texSubImage2D( _gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data ); - - } - - } else { - - state.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); - - } - - } - - } - - } - - } else if ( texture.isDataArrayTexture ) { - - if ( useTexStorage ) { - - if ( allocateMemory ) { - - state.texStorage3D( _gl.TEXTURE_2D_ARRAY, levels, glInternalFormat, image.width, image.height, image.depth ); - - } - - if ( dataReady ) { - - state.texSubImage3D( _gl.TEXTURE_2D_ARRAY, 0, 0, 0, 0, image.width, image.height, image.depth, glFormat, glType, image.data ); - - } - - } else { - - state.texImage3D( _gl.TEXTURE_2D_ARRAY, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data ); - - } - - } else if ( texture.isData3DTexture ) { - - if ( useTexStorage ) { - - if ( allocateMemory ) { - - state.texStorage3D( _gl.TEXTURE_3D, levels, glInternalFormat, image.width, image.height, image.depth ); - - } - - if ( dataReady ) { - - state.texSubImage3D( _gl.TEXTURE_3D, 0, 0, 0, 0, image.width, image.height, image.depth, glFormat, glType, image.data ); - - } - - } else { - - state.texImage3D( _gl.TEXTURE_3D, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data ); - - } - - } else if ( texture.isFramebufferTexture ) { - - if ( allocateMemory ) { - - if ( useTexStorage ) { - - state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, image.width, image.height ); - - } else { - - let width = image.width, height = image.height; - - for ( let i = 0; i < levels; i ++ ) { - - state.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, width, height, 0, glFormat, glType, null ); - - width >>= 1; - height >>= 1; - - } - - } - - } - - } else { - - // regular Texture (image, video, canvas) - - // use manually created mipmaps if available - // if there are no manual mipmaps - // set 0 level mipmap and then use GL to generate other mipmap levels - - if ( mipmaps.length > 0 && supportsMips ) { - - if ( useTexStorage && allocateMemory ) { - - state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height ); - - } - - for ( let i = 0, il = mipmaps.length; i < il; i ++ ) { - - mipmap = mipmaps[ i ]; - - if ( useTexStorage ) { - - if ( dataReady ) { - - state.texSubImage2D( _gl.TEXTURE_2D, i, 0, 0, glFormat, glType, mipmap ); - - } - - } else { - - state.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, glFormat, glType, mipmap ); - - } - - } - - texture.generateMipmaps = false; - - } else { - - if ( useTexStorage ) { - - if ( allocateMemory ) { - - state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, image.width, image.height ); - - } - - if ( dataReady ) { - - state.texSubImage2D( _gl.TEXTURE_2D, 0, 0, 0, glFormat, glType, image ); - - } - - } else { - - state.texImage2D( _gl.TEXTURE_2D, 0, glInternalFormat, glFormat, glType, image ); - - } - - } - - } - - if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) { - - generateMipmap( textureType ); - - } - - sourceProperties.__version = source.version; - - if ( texture.onUpdate ) texture.onUpdate( texture ); - - } - - textureProperties.__version = texture.version; - - } - - function uploadCubeTexture( textureProperties, texture, slot ) { - - if ( texture.image.length !== 6 ) return; - - const forceUpload = initTexture( textureProperties, texture ); - const source = texture.source; - - state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture, _gl.TEXTURE0 + slot ); - - const sourceProperties = properties.get( source ); - - if ( source.version !== sourceProperties.__version || forceUpload === true ) { - - state.activeTexture( _gl.TEXTURE0 + slot ); - - const workingPrimaries = ColorManagement.getPrimaries( ColorManagement.workingColorSpace ); - const texturePrimaries = texture.colorSpace === NoColorSpace ? null : ColorManagement.getPrimaries( texture.colorSpace ); - const unpackConversion = texture.colorSpace === NoColorSpace || workingPrimaries === texturePrimaries ? _gl.NONE : _gl.BROWSER_DEFAULT_WEBGL; - - _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY ); - _gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha ); - _gl.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment ); - _gl.pixelStorei( _gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, unpackConversion ); - - const isCompressed = ( texture.isCompressedTexture || texture.image[ 0 ].isCompressedTexture ); - const isDataTexture = ( texture.image[ 0 ] && texture.image[ 0 ].isDataTexture ); - - const cubeImage = []; - - for ( let i = 0; i < 6; i ++ ) { - - if ( ! isCompressed && ! isDataTexture ) { - - cubeImage[ i ] = resizeImage( texture.image[ i ], false, true, capabilities.maxCubemapSize ); - - } else { - - cubeImage[ i ] = isDataTexture ? texture.image[ i ].image : texture.image[ i ]; - - } - - cubeImage[ i ] = verifyColorSpace( texture, cubeImage[ i ] ); - - } - - const image = cubeImage[ 0 ], - supportsMips = isPowerOfTwo$1( image ) || isWebGL2, - glFormat = utils.convert( texture.format, texture.colorSpace ), - glType = utils.convert( texture.type ), - glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace ); - - const useTexStorage = ( isWebGL2 && texture.isVideoTexture !== true ); - const allocateMemory = ( sourceProperties.__version === undefined ) || ( forceUpload === true ); - const dataReady = source.dataReady; - let levels = getMipLevels( texture, image, supportsMips ); - - setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture, supportsMips ); - - let mipmaps; - - if ( isCompressed ) { - - if ( useTexStorage && allocateMemory ) { - - state.texStorage2D( _gl.TEXTURE_CUBE_MAP, levels, glInternalFormat, image.width, image.height ); - - } - - for ( let i = 0; i < 6; i ++ ) { - - mipmaps = cubeImage[ i ].mipmaps; - - for ( let j = 0; j < mipmaps.length; j ++ ) { - - const mipmap = mipmaps[ j ]; - - if ( texture.format !== RGBAFormat ) { - - if ( glFormat !== null ) { - - if ( useTexStorage ) { - - if ( dataReady ) { - - state.compressedTexSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, 0, 0, mipmap.width, mipmap.height, glFormat, mipmap.data ); - - } - - } else { - - state.compressedTexImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data ); - - } - - } else { - - console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .setTextureCube()' ); - - } - - } else { - - if ( useTexStorage ) { - - if ( dataReady ) { - - state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data ); - - } - - } else { - - state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); - - } - - } - - } - - } - - } else { - - mipmaps = texture.mipmaps; - - if ( useTexStorage && allocateMemory ) { - - // TODO: Uniformly handle mipmap definitions - // Normal textures and compressed cube textures define base level + mips with their mipmap array - // Uncompressed cube textures use their mipmap array only for mips (no base level) - - if ( mipmaps.length > 0 ) levels ++; - - state.texStorage2D( _gl.TEXTURE_CUBE_MAP, levels, glInternalFormat, cubeImage[ 0 ].width, cubeImage[ 0 ].height ); - - } - - for ( let i = 0; i < 6; i ++ ) { - - if ( isDataTexture ) { - - if ( useTexStorage ) { - - if ( dataReady ) { - - state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, 0, 0, cubeImage[ i ].width, cubeImage[ i ].height, glFormat, glType, cubeImage[ i ].data ); - - } - - } else { - - state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glInternalFormat, cubeImage[ i ].width, cubeImage[ i ].height, 0, glFormat, glType, cubeImage[ i ].data ); - - } - - for ( let j = 0; j < mipmaps.length; j ++ ) { - - const mipmap = mipmaps[ j ]; - const mipmapImage = mipmap.image[ i ].image; - - if ( useTexStorage ) { - - if ( dataReady ) { - - state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, 0, 0, mipmapImage.width, mipmapImage.height, glFormat, glType, mipmapImage.data ); - - } - - } else { - - state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, glInternalFormat, mipmapImage.width, mipmapImage.height, 0, glFormat, glType, mipmapImage.data ); - - } - - } - - } else { - - if ( useTexStorage ) { - - if ( dataReady ) { - - state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, 0, 0, glFormat, glType, cubeImage[ i ] ); - - } - - } else { - - state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glInternalFormat, glFormat, glType, cubeImage[ i ] ); - - } - - for ( let j = 0; j < mipmaps.length; j ++ ) { - - const mipmap = mipmaps[ j ]; - - if ( useTexStorage ) { - - if ( dataReady ) { - - state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, 0, 0, glFormat, glType, mipmap.image[ i ] ); - - } - - } else { - - state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, glInternalFormat, glFormat, glType, mipmap.image[ i ] ); - - } - - } - - } - - } - - } - - if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) { - - // We assume images for cube map have the same size. - generateMipmap( _gl.TEXTURE_CUBE_MAP ); - - } - - sourceProperties.__version = source.version; - - if ( texture.onUpdate ) texture.onUpdate( texture ); - - } - - textureProperties.__version = texture.version; - - } - - // Render targets - - // Setup storage for target texture and bind it to correct framebuffer - function setupFrameBufferTexture( framebuffer, renderTarget, texture, attachment, textureTarget, level ) { - - const glFormat = utils.convert( texture.format, texture.colorSpace ); - const glType = utils.convert( texture.type ); - const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace ); - const renderTargetProperties = properties.get( renderTarget ); - - if ( ! renderTargetProperties.__hasExternalTextures ) { - - const width = Math.max( 1, renderTarget.width >> level ); - const height = Math.max( 1, renderTarget.height >> level ); - - if ( textureTarget === _gl.TEXTURE_3D || textureTarget === _gl.TEXTURE_2D_ARRAY ) { - - state.texImage3D( textureTarget, level, glInternalFormat, width, height, renderTarget.depth, 0, glFormat, glType, null ); - - } else { - - state.texImage2D( textureTarget, level, glInternalFormat, width, height, 0, glFormat, glType, null ); - - } - - } - - state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); - - if ( useMultisampledRTT( renderTarget ) ) { - - multisampledRTTExt.framebufferTexture2DMultisampleEXT( _gl.FRAMEBUFFER, attachment, textureTarget, properties.get( texture ).__webglTexture, 0, getRenderTargetSamples( renderTarget ) ); - - } else if ( textureTarget === _gl.TEXTURE_2D || ( textureTarget >= _gl.TEXTURE_CUBE_MAP_POSITIVE_X && textureTarget <= _gl.TEXTURE_CUBE_MAP_NEGATIVE_Z ) ) { // see #24753 - - _gl.framebufferTexture2D( _gl.FRAMEBUFFER, attachment, textureTarget, properties.get( texture ).__webglTexture, level ); - - } - - state.bindFramebuffer( _gl.FRAMEBUFFER, null ); - - } - - - // Setup storage for internal depth/stencil buffers and bind to correct framebuffer - function setupRenderBufferStorage( renderbuffer, renderTarget, isMultisample ) { - - _gl.bindRenderbuffer( _gl.RENDERBUFFER, renderbuffer ); - - if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) { - - let glInternalFormat = ( isWebGL2 === true ) ? _gl.DEPTH_COMPONENT24 : _gl.DEPTH_COMPONENT16; - - if ( isMultisample || useMultisampledRTT( renderTarget ) ) { - - const depthTexture = renderTarget.depthTexture; - - if ( depthTexture && depthTexture.isDepthTexture ) { - - if ( depthTexture.type === FloatType ) { - - glInternalFormat = _gl.DEPTH_COMPONENT32F; - - } else if ( depthTexture.type === UnsignedIntType ) { - - glInternalFormat = _gl.DEPTH_COMPONENT24; - - } - - } - - const samples = getRenderTargetSamples( renderTarget ); - - if ( useMultisampledRTT( renderTarget ) ) { - - multisampledRTTExt.renderbufferStorageMultisampleEXT( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height ); - - } else { - - _gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height ); - - } - - } else { - - _gl.renderbufferStorage( _gl.RENDERBUFFER, glInternalFormat, renderTarget.width, renderTarget.height ); - - } - - _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer ); - - } else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) { - - const samples = getRenderTargetSamples( renderTarget ); - - if ( isMultisample && useMultisampledRTT( renderTarget ) === false ) { - - _gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, _gl.DEPTH24_STENCIL8, renderTarget.width, renderTarget.height ); - - } else if ( useMultisampledRTT( renderTarget ) ) { - - multisampledRTTExt.renderbufferStorageMultisampleEXT( _gl.RENDERBUFFER, samples, _gl.DEPTH24_STENCIL8, renderTarget.width, renderTarget.height ); - - } else { - - _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_STENCIL, renderTarget.width, renderTarget.height ); - - } - - - _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer ); - - } else { - - const textures = renderTarget.isWebGLMultipleRenderTargets === true ? renderTarget.texture : [ renderTarget.texture ]; - - for ( let i = 0; i < textures.length; i ++ ) { - - const texture = textures[ i ]; - - const glFormat = utils.convert( texture.format, texture.colorSpace ); - const glType = utils.convert( texture.type ); - const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace ); - const samples = getRenderTargetSamples( renderTarget ); - - if ( isMultisample && useMultisampledRTT( renderTarget ) === false ) { - - _gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height ); - - } else if ( useMultisampledRTT( renderTarget ) ) { - - multisampledRTTExt.renderbufferStorageMultisampleEXT( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height ); - - } else { - - _gl.renderbufferStorage( _gl.RENDERBUFFER, glInternalFormat, renderTarget.width, renderTarget.height ); - - } - - } - - } - - _gl.bindRenderbuffer( _gl.RENDERBUFFER, null ); - - } - - // Setup resources for a Depth Texture for a FBO (needs an extension) - function setupDepthTexture( framebuffer, renderTarget ) { - - const isCube = ( renderTarget && renderTarget.isWebGLCubeRenderTarget ); - if ( isCube ) throw new Error( 'Depth Texture with cube render targets is not supported' ); - - state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); - - if ( ! ( renderTarget.depthTexture && renderTarget.depthTexture.isDepthTexture ) ) { - - throw new Error( 'renderTarget.depthTexture must be an instance of THREE.DepthTexture' ); - - } - - // upload an empty depth texture with framebuffer size - if ( ! properties.get( renderTarget.depthTexture ).__webglTexture || - renderTarget.depthTexture.image.width !== renderTarget.width || - renderTarget.depthTexture.image.height !== renderTarget.height ) { - - renderTarget.depthTexture.image.width = renderTarget.width; - renderTarget.depthTexture.image.height = renderTarget.height; - renderTarget.depthTexture.needsUpdate = true; - - } - - setTexture2D( renderTarget.depthTexture, 0 ); - - const webglDepthTexture = properties.get( renderTarget.depthTexture ).__webglTexture; - const samples = getRenderTargetSamples( renderTarget ); - - if ( renderTarget.depthTexture.format === DepthFormat ) { - - if ( useMultisampledRTT( renderTarget ) ) { - - multisampledRTTExt.framebufferTexture2DMultisampleEXT( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0, samples ); - - } else { - - _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0 ); - - } - - } else if ( renderTarget.depthTexture.format === DepthStencilFormat ) { - - if ( useMultisampledRTT( renderTarget ) ) { - - multisampledRTTExt.framebufferTexture2DMultisampleEXT( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0, samples ); - - } else { - - _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0 ); - - } - - } else { - - throw new Error( 'Unknown depthTexture format' ); - - } - - } - - // Setup GL resources for a non-texture depth buffer - function setupDepthRenderbuffer( renderTarget ) { - - const renderTargetProperties = properties.get( renderTarget ); - const isCube = ( renderTarget.isWebGLCubeRenderTarget === true ); - - if ( renderTarget.depthTexture && ! renderTargetProperties.__autoAllocateDepthBuffer ) { - - if ( isCube ) throw new Error( 'target.depthTexture not supported in Cube render targets' ); - - setupDepthTexture( renderTargetProperties.__webglFramebuffer, renderTarget ); - - } else { - - if ( isCube ) { - - renderTargetProperties.__webglDepthbuffer = []; - - for ( let i = 0; i < 6; i ++ ) { - - state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer[ i ] ); - renderTargetProperties.__webglDepthbuffer[ i ] = _gl.createRenderbuffer(); - setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer[ i ], renderTarget, false ); - - } - - } else { - - state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer ); - renderTargetProperties.__webglDepthbuffer = _gl.createRenderbuffer(); - setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer, renderTarget, false ); - - } - - } - - state.bindFramebuffer( _gl.FRAMEBUFFER, null ); - - } - - // rebind framebuffer with external textures - function rebindTextures( renderTarget, colorTexture, depthTexture ) { - - const renderTargetProperties = properties.get( renderTarget ); - - if ( colorTexture !== undefined ) { - - setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, renderTarget.texture, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D, 0 ); - - } - - if ( depthTexture !== undefined ) { - - setupDepthRenderbuffer( renderTarget ); - - } - - } - - // Set up GL resources for the render target - function setupRenderTarget( renderTarget ) { - - const texture = renderTarget.texture; - - const renderTargetProperties = properties.get( renderTarget ); - const textureProperties = properties.get( texture ); - - renderTarget.addEventListener( 'dispose', onRenderTargetDispose ); - - if ( renderTarget.isWebGLMultipleRenderTargets !== true ) { - - if ( textureProperties.__webglTexture === undefined ) { - - textureProperties.__webglTexture = _gl.createTexture(); - - } - - textureProperties.__version = texture.version; - info.memory.textures ++; - - } - - const isCube = ( renderTarget.isWebGLCubeRenderTarget === true ); - const isMultipleRenderTargets = ( renderTarget.isWebGLMultipleRenderTargets === true ); - const supportsMips = isPowerOfTwo$1( renderTarget ) || isWebGL2; - - // Setup framebuffer - - if ( isCube ) { - - renderTargetProperties.__webglFramebuffer = []; - - for ( let i = 0; i < 6; i ++ ) { - - if ( isWebGL2 && texture.mipmaps && texture.mipmaps.length > 0 ) { - - renderTargetProperties.__webglFramebuffer[ i ] = []; - - for ( let level = 0; level < texture.mipmaps.length; level ++ ) { - - renderTargetProperties.__webglFramebuffer[ i ][ level ] = _gl.createFramebuffer(); - - } - - } else { - - renderTargetProperties.__webglFramebuffer[ i ] = _gl.createFramebuffer(); - - } - - } - - } else { - - if ( isWebGL2 && texture.mipmaps && texture.mipmaps.length > 0 ) { - - renderTargetProperties.__webglFramebuffer = []; - - for ( let level = 0; level < texture.mipmaps.length; level ++ ) { - - renderTargetProperties.__webglFramebuffer[ level ] = _gl.createFramebuffer(); - - } - - } else { - - renderTargetProperties.__webglFramebuffer = _gl.createFramebuffer(); - - } - - if ( isMultipleRenderTargets ) { - - if ( capabilities.drawBuffers ) { - - const textures = renderTarget.texture; - - for ( let i = 0, il = textures.length; i < il; i ++ ) { - - const attachmentProperties = properties.get( textures[ i ] ); - - if ( attachmentProperties.__webglTexture === undefined ) { - - attachmentProperties.__webglTexture = _gl.createTexture(); - - info.memory.textures ++; - - } - - } - - } else { - - console.warn( 'THREE.WebGLRenderer: WebGLMultipleRenderTargets can only be used with WebGL2 or WEBGL_draw_buffers extension.' ); - - } - - } - - if ( ( isWebGL2 && renderTarget.samples > 0 ) && useMultisampledRTT( renderTarget ) === false ) { - - const textures = isMultipleRenderTargets ? texture : [ texture ]; - - renderTargetProperties.__webglMultisampledFramebuffer = _gl.createFramebuffer(); - renderTargetProperties.__webglColorRenderbuffer = []; - - state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer ); - - for ( let i = 0; i < textures.length; i ++ ) { - - const texture = textures[ i ]; - renderTargetProperties.__webglColorRenderbuffer[ i ] = _gl.createRenderbuffer(); - - _gl.bindRenderbuffer( _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer[ i ] ); - - const glFormat = utils.convert( texture.format, texture.colorSpace ); - const glType = utils.convert( texture.type ); - const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace, renderTarget.isXRRenderTarget === true ); - const samples = getRenderTargetSamples( renderTarget ); - _gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height ); - - _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer[ i ] ); - - } - - _gl.bindRenderbuffer( _gl.RENDERBUFFER, null ); - - if ( renderTarget.depthBuffer ) { - - renderTargetProperties.__webglDepthRenderbuffer = _gl.createRenderbuffer(); - setupRenderBufferStorage( renderTargetProperties.__webglDepthRenderbuffer, renderTarget, true ); - - } - - state.bindFramebuffer( _gl.FRAMEBUFFER, null ); - - } - - } - - // Setup color buffer - - if ( isCube ) { - - state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture ); - setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture, supportsMips ); - - for ( let i = 0; i < 6; i ++ ) { - - if ( isWebGL2 && texture.mipmaps && texture.mipmaps.length > 0 ) { - - for ( let level = 0; level < texture.mipmaps.length; level ++ ) { - - setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ i ][ level ], renderTarget, texture, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, level ); - - } - - } else { - - setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ i ], renderTarget, texture, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0 ); - - } - - } - - if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) { - - generateMipmap( _gl.TEXTURE_CUBE_MAP ); - - } - - state.unbindTexture(); - - } else if ( isMultipleRenderTargets ) { - - const textures = renderTarget.texture; - - for ( let i = 0, il = textures.length; i < il; i ++ ) { - - const attachment = textures[ i ]; - const attachmentProperties = properties.get( attachment ); - - state.bindTexture( _gl.TEXTURE_2D, attachmentProperties.__webglTexture ); - setTextureParameters( _gl.TEXTURE_2D, attachment, supportsMips ); - setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, attachment, _gl.COLOR_ATTACHMENT0 + i, _gl.TEXTURE_2D, 0 ); - - if ( textureNeedsGenerateMipmaps( attachment, supportsMips ) ) { - - generateMipmap( _gl.TEXTURE_2D ); - - } - - } - - state.unbindTexture(); - - } else { - - let glTextureType = _gl.TEXTURE_2D; - - if ( renderTarget.isWebGL3DRenderTarget || renderTarget.isWebGLArrayRenderTarget ) { - - if ( isWebGL2 ) { - - glTextureType = renderTarget.isWebGL3DRenderTarget ? _gl.TEXTURE_3D : _gl.TEXTURE_2D_ARRAY; - - } else { - - console.error( 'THREE.WebGLTextures: THREE.Data3DTexture and THREE.DataArrayTexture only supported with WebGL2.' ); - - } - - } - - state.bindTexture( glTextureType, textureProperties.__webglTexture ); - setTextureParameters( glTextureType, texture, supportsMips ); - - if ( isWebGL2 && texture.mipmaps && texture.mipmaps.length > 0 ) { - - for ( let level = 0; level < texture.mipmaps.length; level ++ ) { - - setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ level ], renderTarget, texture, _gl.COLOR_ATTACHMENT0, glTextureType, level ); - - } - - } else { - - setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, texture, _gl.COLOR_ATTACHMENT0, glTextureType, 0 ); - - } - - if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) { - - generateMipmap( glTextureType ); - - } - - state.unbindTexture(); - - } - - // Setup depth and stencil buffers - - if ( renderTarget.depthBuffer ) { - - setupDepthRenderbuffer( renderTarget ); - - } - - } - - function updateRenderTargetMipmap( renderTarget ) { - - const supportsMips = isPowerOfTwo$1( renderTarget ) || isWebGL2; - - const textures = renderTarget.isWebGLMultipleRenderTargets === true ? renderTarget.texture : [ renderTarget.texture ]; - - for ( let i = 0, il = textures.length; i < il; i ++ ) { - - const texture = textures[ i ]; - - if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) { - - const target = renderTarget.isWebGLCubeRenderTarget ? _gl.TEXTURE_CUBE_MAP : _gl.TEXTURE_2D; - const webglTexture = properties.get( texture ).__webglTexture; - - state.bindTexture( target, webglTexture ); - generateMipmap( target ); - state.unbindTexture(); - - } - - } - - } - - function updateMultisampleRenderTarget( renderTarget ) { - - if ( ( isWebGL2 && renderTarget.samples > 0 ) && useMultisampledRTT( renderTarget ) === false ) { - - const textures = renderTarget.isWebGLMultipleRenderTargets ? renderTarget.texture : [ renderTarget.texture ]; - const width = renderTarget.width; - const height = renderTarget.height; - let mask = _gl.COLOR_BUFFER_BIT; - const invalidationArray = []; - const depthStyle = renderTarget.stencilBuffer ? _gl.DEPTH_STENCIL_ATTACHMENT : _gl.DEPTH_ATTACHMENT; - const renderTargetProperties = properties.get( renderTarget ); - const isMultipleRenderTargets = ( renderTarget.isWebGLMultipleRenderTargets === true ); - - // If MRT we need to remove FBO attachments - if ( isMultipleRenderTargets ) { - - for ( let i = 0; i < textures.length; i ++ ) { - - state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer ); - _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.RENDERBUFFER, null ); - - state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer ); - _gl.framebufferTexture2D( _gl.DRAW_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.TEXTURE_2D, null, 0 ); - - } - - } - - state.bindFramebuffer( _gl.READ_FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer ); - state.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, renderTargetProperties.__webglFramebuffer ); - - for ( let i = 0; i < textures.length; i ++ ) { - - invalidationArray.push( _gl.COLOR_ATTACHMENT0 + i ); - - if ( renderTarget.depthBuffer ) { - - invalidationArray.push( depthStyle ); - - } - - const ignoreDepthValues = ( renderTargetProperties.__ignoreDepthValues !== undefined ) ? renderTargetProperties.__ignoreDepthValues : false; - - if ( ignoreDepthValues === false ) { - - if ( renderTarget.depthBuffer ) mask |= _gl.DEPTH_BUFFER_BIT; - if ( renderTarget.stencilBuffer ) mask |= _gl.STENCIL_BUFFER_BIT; - - } - - if ( isMultipleRenderTargets ) { - - _gl.framebufferRenderbuffer( _gl.READ_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer[ i ] ); - - } - - if ( ignoreDepthValues === true ) { - - _gl.invalidateFramebuffer( _gl.READ_FRAMEBUFFER, [ depthStyle ] ); - _gl.invalidateFramebuffer( _gl.DRAW_FRAMEBUFFER, [ depthStyle ] ); - - } - - if ( isMultipleRenderTargets ) { - - const webglTexture = properties.get( textures[ i ] ).__webglTexture; - _gl.framebufferTexture2D( _gl.DRAW_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D, webglTexture, 0 ); - - } - - _gl.blitFramebuffer( 0, 0, width, height, 0, 0, width, height, mask, _gl.NEAREST ); - - if ( supportsInvalidateFramebuffer ) { - - _gl.invalidateFramebuffer( _gl.READ_FRAMEBUFFER, invalidationArray ); - - } - - - } - - state.bindFramebuffer( _gl.READ_FRAMEBUFFER, null ); - state.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, null ); - - // If MRT since pre-blit we removed the FBO we need to reconstruct the attachments - if ( isMultipleRenderTargets ) { - - for ( let i = 0; i < textures.length; i ++ ) { - - state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer ); - _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer[ i ] ); - - const webglTexture = properties.get( textures[ i ] ).__webglTexture; - - state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer ); - _gl.framebufferTexture2D( _gl.DRAW_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.TEXTURE_2D, webglTexture, 0 ); - - } - - } - - state.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer ); - - } - - } - - function getRenderTargetSamples( renderTarget ) { - - return Math.min( capabilities.maxSamples, renderTarget.samples ); - - } - - function useMultisampledRTT( renderTarget ) { - - const renderTargetProperties = properties.get( renderTarget ); - - return isWebGL2 && renderTarget.samples > 0 && extensions.has( 'WEBGL_multisampled_render_to_texture' ) === true && renderTargetProperties.__useRenderToTexture !== false; - - } - - function updateVideoTexture( texture ) { - - const frame = info.render.frame; - - // Check the last frame we updated the VideoTexture - - if ( _videoTextures.get( texture ) !== frame ) { - - _videoTextures.set( texture, frame ); - texture.update(); - - } - - } - - function verifyColorSpace( texture, image ) { - - const colorSpace = texture.colorSpace; - const format = texture.format; - const type = texture.type; - - if ( texture.isCompressedTexture === true || texture.isVideoTexture === true || texture.format === _SRGBAFormat ) return image; - - if ( colorSpace !== LinearSRGBColorSpace && colorSpace !== NoColorSpace ) { - - // sRGB - - if ( ColorManagement.getTransfer( colorSpace ) === SRGBTransfer ) { - - if ( isWebGL2 === false ) { - - // in WebGL 1, try to use EXT_sRGB extension and unsized formats - - if ( extensions.has( 'EXT_sRGB' ) === true && format === RGBAFormat ) { - - texture.format = _SRGBAFormat; - - // it's not possible to generate mips in WebGL 1 with this extension - - texture.minFilter = LinearFilter; - texture.generateMipmaps = false; - - } else { - - // slow fallback (CPU decode) - - image = ImageUtils.sRGBToLinear( image ); - - } - - } else { - - // in WebGL 2 uncompressed textures can only be sRGB encoded if they have the RGBA8 format - - if ( format !== RGBAFormat || type !== UnsignedByteType ) { - - console.warn( 'THREE.WebGLTextures: sRGB encoded textures have to use RGBAFormat and UnsignedByteType.' ); - - } - - } - - } else { - - console.error( 'THREE.WebGLTextures: Unsupported texture color space:', colorSpace ); - - } - - } - - return image; - - } - - // - - this.allocateTextureUnit = allocateTextureUnit; - this.resetTextureUnits = resetTextureUnits; - - this.setTexture2D = setTexture2D; - this.setTexture2DArray = setTexture2DArray; - this.setTexture3D = setTexture3D; - this.setTextureCube = setTextureCube; - this.rebindTextures = rebindTextures; - this.setupRenderTarget = setupRenderTarget; - this.updateRenderTargetMipmap = updateRenderTargetMipmap; - this.updateMultisampleRenderTarget = updateMultisampleRenderTarget; - this.setupDepthRenderbuffer = setupDepthRenderbuffer; - this.setupFrameBufferTexture = setupFrameBufferTexture; - this.useMultisampledRTT = useMultisampledRTT; - -} - -function WebGLUtils( gl, extensions, capabilities ) { - - const isWebGL2 = capabilities.isWebGL2; - - function convert( p, colorSpace = NoColorSpace ) { - - let extension; - - const transfer = ColorManagement.getTransfer( colorSpace ); - - if ( p === UnsignedByteType ) return gl.UNSIGNED_BYTE; - if ( p === UnsignedShort4444Type ) return gl.UNSIGNED_SHORT_4_4_4_4; - if ( p === UnsignedShort5551Type ) return gl.UNSIGNED_SHORT_5_5_5_1; - - if ( p === ByteType ) return gl.BYTE; - if ( p === ShortType ) return gl.SHORT; - if ( p === UnsignedShortType ) return gl.UNSIGNED_SHORT; - if ( p === IntType ) return gl.INT; - if ( p === UnsignedIntType ) return gl.UNSIGNED_INT; - if ( p === FloatType ) return gl.FLOAT; - - if ( p === HalfFloatType ) { - - if ( isWebGL2 ) return gl.HALF_FLOAT; - - extension = extensions.get( 'OES_texture_half_float' ); - - if ( extension !== null ) { - - return extension.HALF_FLOAT_OES; - - } else { - - return null; - - } - - } - - if ( p === AlphaFormat ) return gl.ALPHA; - if ( p === RGBAFormat ) return gl.RGBA; - if ( p === LuminanceFormat ) return gl.LUMINANCE; - if ( p === LuminanceAlphaFormat ) return gl.LUMINANCE_ALPHA; - if ( p === DepthFormat ) return gl.DEPTH_COMPONENT; - if ( p === DepthStencilFormat ) return gl.DEPTH_STENCIL; - - // WebGL 1 sRGB fallback - - if ( p === _SRGBAFormat ) { - - extension = extensions.get( 'EXT_sRGB' ); - - if ( extension !== null ) { - - return extension.SRGB_ALPHA_EXT; - - } else { - - return null; - - } - - } - - // WebGL2 formats. - - if ( p === RedFormat ) return gl.RED; - if ( p === RedIntegerFormat ) return gl.RED_INTEGER; - if ( p === RGFormat ) return gl.RG; - if ( p === RGIntegerFormat ) return gl.RG_INTEGER; - if ( p === RGBAIntegerFormat ) return gl.RGBA_INTEGER; - - // S3TC - - if ( p === RGB_S3TC_DXT1_Format || p === RGBA_S3TC_DXT1_Format || p === RGBA_S3TC_DXT3_Format || p === RGBA_S3TC_DXT5_Format ) { - - if ( transfer === SRGBTransfer ) { - - extension = extensions.get( 'WEBGL_compressed_texture_s3tc_srgb' ); - - if ( extension !== null ) { - - if ( p === RGB_S3TC_DXT1_Format ) return extension.COMPRESSED_SRGB_S3TC_DXT1_EXT; - if ( p === RGBA_S3TC_DXT1_Format ) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT; - if ( p === RGBA_S3TC_DXT3_Format ) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT; - if ( p === RGBA_S3TC_DXT5_Format ) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT; - - } else { - - return null; - - } - - } else { - - extension = extensions.get( 'WEBGL_compressed_texture_s3tc' ); - - if ( extension !== null ) { - - if ( p === RGB_S3TC_DXT1_Format ) return extension.COMPRESSED_RGB_S3TC_DXT1_EXT; - if ( p === RGBA_S3TC_DXT1_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT1_EXT; - if ( p === RGBA_S3TC_DXT3_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT3_EXT; - if ( p === RGBA_S3TC_DXT5_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT5_EXT; - - } else { - - return null; - - } - - } - - } - - // PVRTC - - if ( p === RGB_PVRTC_4BPPV1_Format || p === RGB_PVRTC_2BPPV1_Format || p === RGBA_PVRTC_4BPPV1_Format || p === RGBA_PVRTC_2BPPV1_Format ) { - - extension = extensions.get( 'WEBGL_compressed_texture_pvrtc' ); - - if ( extension !== null ) { - - if ( p === RGB_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_4BPPV1_IMG; - if ( p === RGB_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_2BPPV1_IMG; - if ( p === RGBA_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; - if ( p === RGBA_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG; - - } else { - - return null; - - } - - } - - // ETC1 - - if ( p === RGB_ETC1_Format ) { - - extension = extensions.get( 'WEBGL_compressed_texture_etc1' ); - - if ( extension !== null ) { - - return extension.COMPRESSED_RGB_ETC1_WEBGL; - - } else { - - return null; - - } - - } - - // ETC2 - - if ( p === RGB_ETC2_Format || p === RGBA_ETC2_EAC_Format ) { - - extension = extensions.get( 'WEBGL_compressed_texture_etc' ); - - if ( extension !== null ) { - - if ( p === RGB_ETC2_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ETC2 : extension.COMPRESSED_RGB8_ETC2; - if ( p === RGBA_ETC2_EAC_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC : extension.COMPRESSED_RGBA8_ETC2_EAC; - - } else { - - return null; - - } - - } - - // ASTC - - if ( p === RGBA_ASTC_4x4_Format || p === RGBA_ASTC_5x4_Format || p === RGBA_ASTC_5x5_Format || - p === RGBA_ASTC_6x5_Format || p === RGBA_ASTC_6x6_Format || p === RGBA_ASTC_8x5_Format || - p === RGBA_ASTC_8x6_Format || p === RGBA_ASTC_8x8_Format || p === RGBA_ASTC_10x5_Format || - p === RGBA_ASTC_10x6_Format || p === RGBA_ASTC_10x8_Format || p === RGBA_ASTC_10x10_Format || - p === RGBA_ASTC_12x10_Format || p === RGBA_ASTC_12x12_Format ) { - - extension = extensions.get( 'WEBGL_compressed_texture_astc' ); - - if ( extension !== null ) { - - if ( p === RGBA_ASTC_4x4_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR : extension.COMPRESSED_RGBA_ASTC_4x4_KHR; - if ( p === RGBA_ASTC_5x4_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR : extension.COMPRESSED_RGBA_ASTC_5x4_KHR; - if ( p === RGBA_ASTC_5x5_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR : extension.COMPRESSED_RGBA_ASTC_5x5_KHR; - if ( p === RGBA_ASTC_6x5_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR : extension.COMPRESSED_RGBA_ASTC_6x5_KHR; - if ( p === RGBA_ASTC_6x6_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR : extension.COMPRESSED_RGBA_ASTC_6x6_KHR; - if ( p === RGBA_ASTC_8x5_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR : extension.COMPRESSED_RGBA_ASTC_8x5_KHR; - if ( p === RGBA_ASTC_8x6_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR : extension.COMPRESSED_RGBA_ASTC_8x6_KHR; - if ( p === RGBA_ASTC_8x8_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR : extension.COMPRESSED_RGBA_ASTC_8x8_KHR; - if ( p === RGBA_ASTC_10x5_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR : extension.COMPRESSED_RGBA_ASTC_10x5_KHR; - if ( p === RGBA_ASTC_10x6_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR : extension.COMPRESSED_RGBA_ASTC_10x6_KHR; - if ( p === RGBA_ASTC_10x8_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR : extension.COMPRESSED_RGBA_ASTC_10x8_KHR; - if ( p === RGBA_ASTC_10x10_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR : extension.COMPRESSED_RGBA_ASTC_10x10_KHR; - if ( p === RGBA_ASTC_12x10_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR : extension.COMPRESSED_RGBA_ASTC_12x10_KHR; - if ( p === RGBA_ASTC_12x12_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR : extension.COMPRESSED_RGBA_ASTC_12x12_KHR; - - } else { - - return null; - - } - - } - - // BPTC - - if ( p === RGBA_BPTC_Format || p === RGB_BPTC_SIGNED_Format || p === RGB_BPTC_UNSIGNED_Format ) { - - extension = extensions.get( 'EXT_texture_compression_bptc' ); - - if ( extension !== null ) { - - if ( p === RGBA_BPTC_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT : extension.COMPRESSED_RGBA_BPTC_UNORM_EXT; - if ( p === RGB_BPTC_SIGNED_Format ) return extension.COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT; - if ( p === RGB_BPTC_UNSIGNED_Format ) return extension.COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT; - - } else { - - return null; - - } - - } - - // RGTC - - if ( p === RED_RGTC1_Format || p === SIGNED_RED_RGTC1_Format || p === RED_GREEN_RGTC2_Format || p === SIGNED_RED_GREEN_RGTC2_Format ) { - - extension = extensions.get( 'EXT_texture_compression_rgtc' ); - - if ( extension !== null ) { - - if ( p === RGBA_BPTC_Format ) return extension.COMPRESSED_RED_RGTC1_EXT; - if ( p === SIGNED_RED_RGTC1_Format ) return extension.COMPRESSED_SIGNED_RED_RGTC1_EXT; - if ( p === RED_GREEN_RGTC2_Format ) return extension.COMPRESSED_RED_GREEN_RGTC2_EXT; - if ( p === SIGNED_RED_GREEN_RGTC2_Format ) return extension.COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT; - - } else { - - return null; - - } - - } - - // - - if ( p === UnsignedInt248Type ) { - - if ( isWebGL2 ) return gl.UNSIGNED_INT_24_8; - - extension = extensions.get( 'WEBGL_depth_texture' ); - - if ( extension !== null ) { - - return extension.UNSIGNED_INT_24_8_WEBGL; - - } else { - - return null; - - } - - } - - // if "p" can't be resolved, assume the user defines a WebGL constant as a string (fallback/workaround for packed RGB formats) - - return ( gl[ p ] !== undefined ) ? gl[ p ] : null; - - } - - return { convert: convert }; - -} - -class ArrayCamera extends PerspectiveCamera { - - constructor( array = [] ) { - - super(); - - this.isArrayCamera = true; - - this.cameras = array; - - } - -} - -class Group extends Object3D { - - constructor() { - - super(); - - this.isGroup = true; - - this.type = 'Group'; - - } - -} - -const _moveEvent = { type: 'move' }; - -class WebXRController { - - constructor() { - - this._targetRay = null; - this._grip = null; - this._hand = null; - - } - - getHandSpace() { - - if ( this._hand === null ) { - - this._hand = new Group(); - this._hand.matrixAutoUpdate = false; - this._hand.visible = false; - - this._hand.joints = {}; - this._hand.inputState = { pinching: false }; - - } - - return this._hand; - - } - - getTargetRaySpace() { - - if ( this._targetRay === null ) { - - this._targetRay = new Group(); - this._targetRay.matrixAutoUpdate = false; - this._targetRay.visible = false; - this._targetRay.hasLinearVelocity = false; - this._targetRay.linearVelocity = new Vector3(); - this._targetRay.hasAngularVelocity = false; - this._targetRay.angularVelocity = new Vector3(); - - } - - return this._targetRay; - - } - - getGripSpace() { - - if ( this._grip === null ) { - - this._grip = new Group(); - this._grip.matrixAutoUpdate = false; - this._grip.visible = false; - this._grip.hasLinearVelocity = false; - this._grip.linearVelocity = new Vector3(); - this._grip.hasAngularVelocity = false; - this._grip.angularVelocity = new Vector3(); - - } - - return this._grip; - - } - - dispatchEvent( event ) { - - if ( this._targetRay !== null ) { - - this._targetRay.dispatchEvent( event ); - - } - - if ( this._grip !== null ) { - - this._grip.dispatchEvent( event ); - - } - - if ( this._hand !== null ) { - - this._hand.dispatchEvent( event ); - - } - - return this; - - } - - connect( inputSource ) { - - if ( inputSource && inputSource.hand ) { - - const hand = this._hand; - - if ( hand ) { - - for ( const inputjoint of inputSource.hand.values() ) { - - // Initialize hand with joints when connected - this._getHandJoint( hand, inputjoint ); - - } - - } - - } - - this.dispatchEvent( { type: 'connected', data: inputSource } ); - - return this; - - } - - disconnect( inputSource ) { - - this.dispatchEvent( { type: 'disconnected', data: inputSource } ); - - if ( this._targetRay !== null ) { - - this._targetRay.visible = false; - - } - - if ( this._grip !== null ) { - - this._grip.visible = false; - - } - - if ( this._hand !== null ) { - - this._hand.visible = false; - - } - - return this; - - } - - update( inputSource, frame, referenceSpace ) { - - let inputPose = null; - let gripPose = null; - let handPose = null; - - const targetRay = this._targetRay; - const grip = this._grip; - const hand = this._hand; - - if ( inputSource && frame.session.visibilityState !== 'visible-blurred' ) { - - if ( hand && inputSource.hand ) { - - handPose = true; - - for ( const inputjoint of inputSource.hand.values() ) { - - // Update the joints groups with the XRJoint poses - const jointPose = frame.getJointPose( inputjoint, referenceSpace ); - - // The transform of this joint will be updated with the joint pose on each frame - const joint = this._getHandJoint( hand, inputjoint ); - - if ( jointPose !== null ) { - - joint.matrix.fromArray( jointPose.transform.matrix ); - joint.matrix.decompose( joint.position, joint.rotation, joint.scale ); - joint.matrixWorldNeedsUpdate = true; - joint.jointRadius = jointPose.radius; - - } - - joint.visible = jointPose !== null; - - } - - // Custom events - - // Check pinchz - const indexTip = hand.joints[ 'index-finger-tip' ]; - const thumbTip = hand.joints[ 'thumb-tip' ]; - const distance = indexTip.position.distanceTo( thumbTip.position ); - - const distanceToPinch = 0.02; - const threshold = 0.005; - - if ( hand.inputState.pinching && distance > distanceToPinch + threshold ) { - - hand.inputState.pinching = false; - this.dispatchEvent( { - type: 'pinchend', - handedness: inputSource.handedness, - target: this - } ); - - } else if ( ! hand.inputState.pinching && distance <= distanceToPinch - threshold ) { - - hand.inputState.pinching = true; - this.dispatchEvent( { - type: 'pinchstart', - handedness: inputSource.handedness, - target: this - } ); - - } - - } else { - - if ( grip !== null && inputSource.gripSpace ) { - - gripPose = frame.getPose( inputSource.gripSpace, referenceSpace ); - - if ( gripPose !== null ) { - - grip.matrix.fromArray( gripPose.transform.matrix ); - grip.matrix.decompose( grip.position, grip.rotation, grip.scale ); - grip.matrixWorldNeedsUpdate = true; - - if ( gripPose.linearVelocity ) { - - grip.hasLinearVelocity = true; - grip.linearVelocity.copy( gripPose.linearVelocity ); - - } else { - - grip.hasLinearVelocity = false; - - } - - if ( gripPose.angularVelocity ) { - - grip.hasAngularVelocity = true; - grip.angularVelocity.copy( gripPose.angularVelocity ); - - } else { - - grip.hasAngularVelocity = false; - - } - - } - - } - - } - - if ( targetRay !== null ) { - - inputPose = frame.getPose( inputSource.targetRaySpace, referenceSpace ); - - // Some runtimes (namely Vive Cosmos with Vive OpenXR Runtime) have only grip space and ray space is equal to it - if ( inputPose === null && gripPose !== null ) { - - inputPose = gripPose; - - } - - if ( inputPose !== null ) { - - targetRay.matrix.fromArray( inputPose.transform.matrix ); - targetRay.matrix.decompose( targetRay.position, targetRay.rotation, targetRay.scale ); - targetRay.matrixWorldNeedsUpdate = true; - - if ( inputPose.linearVelocity ) { - - targetRay.hasLinearVelocity = true; - targetRay.linearVelocity.copy( inputPose.linearVelocity ); - - } else { - - targetRay.hasLinearVelocity = false; - - } - - if ( inputPose.angularVelocity ) { - - targetRay.hasAngularVelocity = true; - targetRay.angularVelocity.copy( inputPose.angularVelocity ); - - } else { - - targetRay.hasAngularVelocity = false; - - } - - this.dispatchEvent( _moveEvent ); - - } - - } - - - } - - if ( targetRay !== null ) { - - targetRay.visible = ( inputPose !== null ); - - } - - if ( grip !== null ) { - - grip.visible = ( gripPose !== null ); - - } - - if ( hand !== null ) { - - hand.visible = ( handPose !== null ); - - } - - return this; - - } - - // private method - - _getHandJoint( hand, inputjoint ) { - - if ( hand.joints[ inputjoint.jointName ] === undefined ) { - - const joint = new Group(); - joint.matrixAutoUpdate = false; - joint.visible = false; - hand.joints[ inputjoint.jointName ] = joint; - - hand.add( joint ); - - } - - return hand.joints[ inputjoint.jointName ]; - - } - -} - -const _occlusion_vertex = ` -void main() { - - gl_Position = vec4( position, 1.0 ); - -}`; - -const _occlusion_fragment = ` -uniform sampler2DArray depthColor; -uniform float depthWidth; -uniform float depthHeight; - -void main() { - - vec2 coord = vec2( gl_FragCoord.x / depthWidth, gl_FragCoord.y / depthHeight ); - - if ( coord.x >= 1.0 ) { - - gl_FragDepthEXT = texture( depthColor, vec3( coord.x - 1.0, coord.y, 1 ) ).r; - - } else { - - gl_FragDepthEXT = texture( depthColor, vec3( coord.x, coord.y, 0 ) ).r; - - } - -}`; - -class WebXRDepthSensing { - - constructor() { - - this.texture = null; - this.mesh = null; - - this.depthNear = 0; - this.depthFar = 0; - - } - - init( renderer, depthData, renderState ) { - - if ( this.texture === null ) { - - const texture = new Texture(); - - const texProps = renderer.properties.get( texture ); - texProps.__webglTexture = depthData.texture; - - if ( ( depthData.depthNear != renderState.depthNear ) || ( depthData.depthFar != renderState.depthFar ) ) { - - this.depthNear = depthData.depthNear; - this.depthFar = depthData.depthFar; - - } - - this.texture = texture; - - } - - } - - render( renderer, cameraXR ) { - - if ( this.texture !== null ) { - - if ( this.mesh === null ) { - - const viewport = cameraXR.cameras[ 0 ].viewport; - const material = new ShaderMaterial( { - extensions: { fragDepth: true }, - vertexShader: _occlusion_vertex, - fragmentShader: _occlusion_fragment, - uniforms: { - depthColor: { value: this.texture }, - depthWidth: { value: viewport.z }, - depthHeight: { value: viewport.w } - } - } ); - - this.mesh = new Mesh( new PlaneGeometry( 20, 20 ), material ); - - } - - renderer.render( this.mesh, cameraXR ); - - } - - } - - reset() { - - this.texture = null; - this.mesh = null; - - } - -} - -class WebXRManager extends EventDispatcher { - - constructor( renderer, gl ) { - - super(); - - const scope = this; - - let session = null; - - let framebufferScaleFactor = 1.0; - - let referenceSpace = null; - let referenceSpaceType = 'local-floor'; - // Set default foveation to maximum. - let foveation = 1.0; - let customReferenceSpace = null; - - let pose = null; - let glBinding = null; - let glProjLayer = null; - let glBaseLayer = null; - let xrFrame = null; - - const depthSensing = new WebXRDepthSensing(); - const attributes = gl.getContextAttributes(); - - let initialRenderTarget = null; - let newRenderTarget = null; - - const controllers = []; - const controllerInputSources = []; - - const currentSize = new Vector2(); - let currentPixelRatio = null; - - // - - const cameraL = new PerspectiveCamera(); - cameraL.layers.enable( 1 ); - cameraL.viewport = new Vector4(); - - const cameraR = new PerspectiveCamera(); - cameraR.layers.enable( 2 ); - cameraR.viewport = new Vector4(); - - const cameras = [ cameraL, cameraR ]; - - const cameraXR = new ArrayCamera(); - cameraXR.layers.enable( 1 ); - cameraXR.layers.enable( 2 ); - - let _currentDepthNear = null; - let _currentDepthFar = null; - - // - - this.cameraAutoUpdate = true; - this.enabled = false; - - this.isPresenting = false; - - this.getController = function ( index ) { - - let controller = controllers[ index ]; - - if ( controller === undefined ) { - - controller = new WebXRController(); - controllers[ index ] = controller; - - } - - return controller.getTargetRaySpace(); - - }; - - this.getControllerGrip = function ( index ) { - - let controller = controllers[ index ]; - - if ( controller === undefined ) { - - controller = new WebXRController(); - controllers[ index ] = controller; - - } - - return controller.getGripSpace(); - - }; - - this.getHand = function ( index ) { - - let controller = controllers[ index ]; - - if ( controller === undefined ) { - - controller = new WebXRController(); - controllers[ index ] = controller; - - } - - return controller.getHandSpace(); - - }; - - // - - function onSessionEvent( event ) { - - const controllerIndex = controllerInputSources.indexOf( event.inputSource ); - - if ( controllerIndex === - 1 ) { - - return; - - } - - const controller = controllers[ controllerIndex ]; - - if ( controller !== undefined ) { - - controller.update( event.inputSource, event.frame, customReferenceSpace || referenceSpace ); - controller.dispatchEvent( { type: event.type, data: event.inputSource } ); - - } - - } - - function onSessionEnd() { - - session.removeEventListener( 'select', onSessionEvent ); - session.removeEventListener( 'selectstart', onSessionEvent ); - session.removeEventListener( 'selectend', onSessionEvent ); - session.removeEventListener( 'squeeze', onSessionEvent ); - session.removeEventListener( 'squeezestart', onSessionEvent ); - session.removeEventListener( 'squeezeend', onSessionEvent ); - session.removeEventListener( 'end', onSessionEnd ); - session.removeEventListener( 'inputsourceschange', onInputSourcesChange ); - - for ( let i = 0; i < controllers.length; i ++ ) { - - const inputSource = controllerInputSources[ i ]; - - if ( inputSource === null ) continue; - - controllerInputSources[ i ] = null; - - controllers[ i ].disconnect( inputSource ); - - } - - _currentDepthNear = null; - _currentDepthFar = null; - - depthSensing.reset(); - - // restore framebuffer/rendering state - - renderer.setRenderTarget( initialRenderTarget ); - - glBaseLayer = null; - glProjLayer = null; - glBinding = null; - session = null; - newRenderTarget = null; - - // - - animation.stop(); - - scope.isPresenting = false; - - renderer.setPixelRatio( currentPixelRatio ); - renderer.setSize( currentSize.width, currentSize.height, false ); - - scope.dispatchEvent( { type: 'sessionend' } ); - - } - - this.setFramebufferScaleFactor = function ( value ) { - - framebufferScaleFactor = value; - - if ( scope.isPresenting === true ) { - - console.warn( 'THREE.WebXRManager: Cannot change framebuffer scale while presenting.' ); - - } - - }; - - this.setReferenceSpaceType = function ( value ) { - - referenceSpaceType = value; - - if ( scope.isPresenting === true ) { - - console.warn( 'THREE.WebXRManager: Cannot change reference space type while presenting.' ); - - } - - }; - - this.getReferenceSpace = function () { - - return customReferenceSpace || referenceSpace; - - }; - - this.setReferenceSpace = function ( space ) { - - customReferenceSpace = space; - - }; - - this.getBaseLayer = function () { - - return glProjLayer !== null ? glProjLayer : glBaseLayer; - - }; - - this.getBinding = function () { - - return glBinding; - - }; - - this.getFrame = function () { - - return xrFrame; - - }; - - this.getSession = function () { - - return session; - - }; - - this.setSession = async function ( value ) { - - session = value; - - if ( session !== null ) { - - initialRenderTarget = renderer.getRenderTarget(); - - session.addEventListener( 'select', onSessionEvent ); - session.addEventListener( 'selectstart', onSessionEvent ); - session.addEventListener( 'selectend', onSessionEvent ); - session.addEventListener( 'squeeze', onSessionEvent ); - session.addEventListener( 'squeezestart', onSessionEvent ); - session.addEventListener( 'squeezeend', onSessionEvent ); - session.addEventListener( 'end', onSessionEnd ); - session.addEventListener( 'inputsourceschange', onInputSourcesChange ); - - if ( attributes.xrCompatible !== true ) { - - await gl.makeXRCompatible(); - - } - - currentPixelRatio = renderer.getPixelRatio(); - renderer.getSize( currentSize ); - - if ( ( session.renderState.layers === undefined ) || ( renderer.capabilities.isWebGL2 === false ) ) { - - const layerInit = { - antialias: ( session.renderState.layers === undefined ) ? attributes.antialias : true, - alpha: true, - depth: attributes.depth, - stencil: attributes.stencil, - framebufferScaleFactor: framebufferScaleFactor - }; - - glBaseLayer = new XRWebGLLayer( session, gl, layerInit ); - - session.updateRenderState( { baseLayer: glBaseLayer } ); - - renderer.setPixelRatio( 1 ); - renderer.setSize( glBaseLayer.framebufferWidth, glBaseLayer.framebufferHeight, false ); - - newRenderTarget = new WebGLRenderTarget( - glBaseLayer.framebufferWidth, - glBaseLayer.framebufferHeight, - { - format: RGBAFormat, - type: UnsignedByteType, - colorSpace: renderer.outputColorSpace, - stencilBuffer: attributes.stencil - } - ); - - } else { - - let depthFormat = null; - let depthType = null; - let glDepthFormat = null; - - if ( attributes.depth ) { - - glDepthFormat = attributes.stencil ? gl.DEPTH24_STENCIL8 : gl.DEPTH_COMPONENT24; - depthFormat = attributes.stencil ? DepthStencilFormat : DepthFormat; - depthType = attributes.stencil ? UnsignedInt248Type : UnsignedIntType; - - } - - const projectionlayerInit = { - colorFormat: gl.RGBA8, - depthFormat: glDepthFormat, - scaleFactor: framebufferScaleFactor - }; - - glBinding = new XRWebGLBinding( session, gl ); - - glProjLayer = glBinding.createProjectionLayer( projectionlayerInit ); - - session.updateRenderState( { layers: [ glProjLayer ] } ); - - renderer.setPixelRatio( 1 ); - renderer.setSize( glProjLayer.textureWidth, glProjLayer.textureHeight, false ); - - newRenderTarget = new WebGLRenderTarget( - glProjLayer.textureWidth, - glProjLayer.textureHeight, - { - format: RGBAFormat, - type: UnsignedByteType, - depthTexture: new DepthTexture( glProjLayer.textureWidth, glProjLayer.textureHeight, depthType, undefined, undefined, undefined, undefined, undefined, undefined, depthFormat ), - stencilBuffer: attributes.stencil, - colorSpace: renderer.outputColorSpace, - samples: attributes.antialias ? 4 : 0 - } ); - - const renderTargetProperties = renderer.properties.get( newRenderTarget ); - renderTargetProperties.__ignoreDepthValues = glProjLayer.ignoreDepthValues; - - } - - newRenderTarget.isXRRenderTarget = true; // TODO Remove this when possible, see #23278 - - this.setFoveation( foveation ); - - customReferenceSpace = null; - referenceSpace = await session.requestReferenceSpace( referenceSpaceType ); - - animation.setContext( session ); - animation.start(); - - scope.isPresenting = true; - - scope.dispatchEvent( { type: 'sessionstart' } ); - - } - - }; - - this.getEnvironmentBlendMode = function () { - - if ( session !== null ) { - - return session.environmentBlendMode; - - } - - }; - - function onInputSourcesChange( event ) { - - // Notify disconnected - - for ( let i = 0; i < event.removed.length; i ++ ) { - - const inputSource = event.removed[ i ]; - const index = controllerInputSources.indexOf( inputSource ); - - if ( index >= 0 ) { - - controllerInputSources[ index ] = null; - controllers[ index ].disconnect( inputSource ); - - } - - } - - // Notify connected - - for ( let i = 0; i < event.added.length; i ++ ) { - - const inputSource = event.added[ i ]; - - let controllerIndex = controllerInputSources.indexOf( inputSource ); - - if ( controllerIndex === - 1 ) { - - // Assign input source a controller that currently has no input source - - for ( let i = 0; i < controllers.length; i ++ ) { - - if ( i >= controllerInputSources.length ) { - - controllerInputSources.push( inputSource ); - controllerIndex = i; - break; - - } else if ( controllerInputSources[ i ] === null ) { - - controllerInputSources[ i ] = inputSource; - controllerIndex = i; - break; - - } - - } - - // If all controllers do currently receive input we ignore new ones - - if ( controllerIndex === - 1 ) break; - - } - - const controller = controllers[ controllerIndex ]; - - if ( controller ) { - - controller.connect( inputSource ); - - } - - } - - } - - // - - const cameraLPos = new Vector3(); - const cameraRPos = new Vector3(); - - /** - * Assumes 2 cameras that are parallel and share an X-axis, and that - * the cameras' projection and world matrices have already been set. - * And that near and far planes are identical for both cameras. - * Visualization of this technique: https://computergraphics.stackexchange.com/a/4765 - */ - function setProjectionFromUnion( camera, cameraL, cameraR ) { - - cameraLPos.setFromMatrixPosition( cameraL.matrixWorld ); - cameraRPos.setFromMatrixPosition( cameraR.matrixWorld ); - - const ipd = cameraLPos.distanceTo( cameraRPos ); - - const projL = cameraL.projectionMatrix.elements; - const projR = cameraR.projectionMatrix.elements; - - // VR systems will have identical far and near planes, and - // most likely identical top and bottom frustum extents. - // Use the left camera for these values. - const near = projL[ 14 ] / ( projL[ 10 ] - 1 ); - const far = projL[ 14 ] / ( projL[ 10 ] + 1 ); - const topFov = ( projL[ 9 ] + 1 ) / projL[ 5 ]; - const bottomFov = ( projL[ 9 ] - 1 ) / projL[ 5 ]; - - const leftFov = ( projL[ 8 ] - 1 ) / projL[ 0 ]; - const rightFov = ( projR[ 8 ] + 1 ) / projR[ 0 ]; - const left = near * leftFov; - const right = near * rightFov; - - // Calculate the new camera's position offset from the - // left camera. xOffset should be roughly half `ipd`. - const zOffset = ipd / ( - leftFov + rightFov ); - const xOffset = zOffset * - leftFov; - - // TODO: Better way to apply this offset? - cameraL.matrixWorld.decompose( camera.position, camera.quaternion, camera.scale ); - camera.translateX( xOffset ); - camera.translateZ( zOffset ); - camera.matrixWorld.compose( camera.position, camera.quaternion, camera.scale ); - camera.matrixWorldInverse.copy( camera.matrixWorld ).invert(); - - // Find the union of the frustum values of the cameras and scale - // the values so that the near plane's position does not change in world space, - // although must now be relative to the new union camera. - const near2 = near + zOffset; - const far2 = far + zOffset; - const left2 = left - xOffset; - const right2 = right + ( ipd - xOffset ); - const top2 = topFov * far / far2 * near2; - const bottom2 = bottomFov * far / far2 * near2; - - camera.projectionMatrix.makePerspective( left2, right2, top2, bottom2, near2, far2 ); - camera.projectionMatrixInverse.copy( camera.projectionMatrix ).invert(); - - } - - function updateCamera( camera, parent ) { - - if ( parent === null ) { - - camera.matrixWorld.copy( camera.matrix ); - - } else { - - camera.matrixWorld.multiplyMatrices( parent.matrixWorld, camera.matrix ); - - } - - camera.matrixWorldInverse.copy( camera.matrixWorld ).invert(); - - } - - this.updateCamera = function ( camera ) { - - if ( session === null ) return; - - if ( depthSensing.texture !== null ) { - - camera.near = depthSensing.depthNear; - camera.far = depthSensing.depthFar; - - } - - cameraXR.near = cameraR.near = cameraL.near = camera.near; - cameraXR.far = cameraR.far = cameraL.far = camera.far; - - if ( _currentDepthNear !== cameraXR.near || _currentDepthFar !== cameraXR.far ) { - - // Note that the new renderState won't apply until the next frame. See #18320 - - session.updateRenderState( { - depthNear: cameraXR.near, - depthFar: cameraXR.far - } ); - - _currentDepthNear = cameraXR.near; - _currentDepthFar = cameraXR.far; - - cameraL.near = _currentDepthNear; - cameraL.far = _currentDepthFar; - cameraR.near = _currentDepthNear; - cameraR.far = _currentDepthFar; - - cameraL.updateProjectionMatrix(); - cameraR.updateProjectionMatrix(); - camera.updateProjectionMatrix(); - - } - - const parent = camera.parent; - const cameras = cameraXR.cameras; - - updateCamera( cameraXR, parent ); - - for ( let i = 0; i < cameras.length; i ++ ) { - - updateCamera( cameras[ i ], parent ); - - } - - // update projection matrix for proper view frustum culling - - if ( cameras.length === 2 ) { - - setProjectionFromUnion( cameraXR, cameraL, cameraR ); - - } else { - - // assume single camera setup (AR) - - cameraXR.projectionMatrix.copy( cameraL.projectionMatrix ); - - } - - // update user camera and its children - - updateUserCamera( camera, cameraXR, parent ); - - }; - - function updateUserCamera( camera, cameraXR, parent ) { - - if ( parent === null ) { - - camera.matrix.copy( cameraXR.matrixWorld ); - - } else { - - camera.matrix.copy( parent.matrixWorld ); - camera.matrix.invert(); - camera.matrix.multiply( cameraXR.matrixWorld ); - - } - - camera.matrix.decompose( camera.position, camera.quaternion, camera.scale ); - camera.updateMatrixWorld( true ); - - camera.projectionMatrix.copy( cameraXR.projectionMatrix ); - camera.projectionMatrixInverse.copy( cameraXR.projectionMatrixInverse ); - - if ( camera.isPerspectiveCamera ) { - - camera.fov = RAD2DEG * 2 * Math.atan( 1 / camera.projectionMatrix.elements[ 5 ] ); - camera.zoom = 1; - - } - - } - - this.getCamera = function () { - - return cameraXR; - - }; - - this.getFoveation = function () { - - if ( glProjLayer === null && glBaseLayer === null ) { - - return undefined; - - } - - return foveation; - - }; - - this.setFoveation = function ( value ) { - - // 0 = no foveation = full resolution - // 1 = maximum foveation = the edges render at lower resolution - - foveation = value; - - if ( glProjLayer !== null ) { - - glProjLayer.fixedFoveation = value; - - } - - if ( glBaseLayer !== null && glBaseLayer.fixedFoveation !== undefined ) { - - glBaseLayer.fixedFoveation = value; - - } - - }; - - this.hasDepthSensing = function () { - - return depthSensing.texture !== null; - - }; - - // Animation Loop - - let onAnimationFrameCallback = null; - - function onAnimationFrame( time, frame ) { - - pose = frame.getViewerPose( customReferenceSpace || referenceSpace ); - xrFrame = frame; - - if ( pose !== null ) { - - const views = pose.views; - - if ( glBaseLayer !== null ) { - - renderer.setRenderTargetFramebuffer( newRenderTarget, glBaseLayer.framebuffer ); - renderer.setRenderTarget( newRenderTarget ); - - } - - let cameraXRNeedsUpdate = false; - - // check if it's necessary to rebuild cameraXR's camera list - - if ( views.length !== cameraXR.cameras.length ) { - - cameraXR.cameras.length = 0; - cameraXRNeedsUpdate = true; - - } - - for ( let i = 0; i < views.length; i ++ ) { - - const view = views[ i ]; - - let viewport = null; - - if ( glBaseLayer !== null ) { - - viewport = glBaseLayer.getViewport( view ); - - } else { - - const glSubImage = glBinding.getViewSubImage( glProjLayer, view ); - viewport = glSubImage.viewport; - - // For side-by-side projection, we only produce a single texture for both eyes. - if ( i === 0 ) { - - renderer.setRenderTargetTextures( - newRenderTarget, - glSubImage.colorTexture, - glProjLayer.ignoreDepthValues ? undefined : glSubImage.depthStencilTexture ); - - renderer.setRenderTarget( newRenderTarget ); - - } - - } - - let camera = cameras[ i ]; - - if ( camera === undefined ) { - - camera = new PerspectiveCamera(); - camera.layers.enable( i ); - camera.viewport = new Vector4(); - cameras[ i ] = camera; - - } - - camera.matrix.fromArray( view.transform.matrix ); - camera.matrix.decompose( camera.position, camera.quaternion, camera.scale ); - camera.projectionMatrix.fromArray( view.projectionMatrix ); - camera.projectionMatrixInverse.copy( camera.projectionMatrix ).invert(); - camera.viewport.set( viewport.x, viewport.y, viewport.width, viewport.height ); - - if ( i === 0 ) { - - cameraXR.matrix.copy( camera.matrix ); - cameraXR.matrix.decompose( cameraXR.position, cameraXR.quaternion, cameraXR.scale ); - - } - - if ( cameraXRNeedsUpdate === true ) { - - cameraXR.cameras.push( camera ); - - } - - } - - // - - const enabledFeatures = session.enabledFeatures; - - if ( enabledFeatures && enabledFeatures.includes( 'depth-sensing' ) ) { - - const depthData = glBinding.getDepthInformation( views[ 0 ] ); - - if ( depthData && depthData.isValid && depthData.texture ) { - - depthSensing.init( renderer, depthData, session.renderState ); - - } - - } - - } - - // - - for ( let i = 0; i < controllers.length; i ++ ) { - - const inputSource = controllerInputSources[ i ]; - const controller = controllers[ i ]; - - if ( inputSource !== null && controller !== undefined ) { - - controller.update( inputSource, frame, customReferenceSpace || referenceSpace ); - - } - - } - - depthSensing.render( renderer, cameraXR ); - - if ( onAnimationFrameCallback ) onAnimationFrameCallback( time, frame ); - - if ( frame.detectedPlanes ) { - - scope.dispatchEvent( { type: 'planesdetected', data: frame } ); - - } - - xrFrame = null; - - } - - const animation = new WebGLAnimation(); - - animation.setAnimationLoop( onAnimationFrame ); - - this.setAnimationLoop = function ( callback ) { - - onAnimationFrameCallback = callback; - - }; - - this.dispose = function () {}; - - } - -} - -function WebGLMaterials( renderer, properties ) { - - function refreshTransformUniform( map, uniform ) { - - if ( map.matrixAutoUpdate === true ) { - - map.updateMatrix(); - - } - - uniform.value.copy( map.matrix ); - - } - - function refreshFogUniforms( uniforms, fog ) { - - fog.color.getRGB( uniforms.fogColor.value, getUnlitUniformColorSpace( renderer ) ); - - if ( fog.isFog ) { - - uniforms.fogNear.value = fog.near; - uniforms.fogFar.value = fog.far; - - } else if ( fog.isFogExp2 ) { - - uniforms.fogDensity.value = fog.density; - - } - - } - - function refreshMaterialUniforms( uniforms, material, pixelRatio, height, transmissionRenderTarget ) { - - if ( material.isMeshBasicMaterial ) { - - refreshUniformsCommon( uniforms, material ); - - } else if ( material.isMeshLambertMaterial ) { - - refreshUniformsCommon( uniforms, material ); - - } else if ( material.isMeshToonMaterial ) { - - refreshUniformsCommon( uniforms, material ); - refreshUniformsToon( uniforms, material ); - - } else if ( material.isMeshPhongMaterial ) { - - refreshUniformsCommon( uniforms, material ); - refreshUniformsPhong( uniforms, material ); - - } else if ( material.isMeshStandardMaterial ) { - - refreshUniformsCommon( uniforms, material ); - refreshUniformsStandard( uniforms, material ); - - if ( material.isMeshPhysicalMaterial ) { - - refreshUniformsPhysical( uniforms, material, transmissionRenderTarget ); - - } - - } else if ( material.isMeshMatcapMaterial ) { - - refreshUniformsCommon( uniforms, material ); - refreshUniformsMatcap( uniforms, material ); - - } else if ( material.isMeshDepthMaterial ) { - - refreshUniformsCommon( uniforms, material ); - - } else if ( material.isMeshDistanceMaterial ) { - - refreshUniformsCommon( uniforms, material ); - refreshUniformsDistance( uniforms, material ); - - } else if ( material.isMeshNormalMaterial ) { - - refreshUniformsCommon( uniforms, material ); - - } else if ( material.isLineBasicMaterial ) { - - refreshUniformsLine( uniforms, material ); - - if ( material.isLineDashedMaterial ) { - - refreshUniformsDash( uniforms, material ); - - } - - } else if ( material.isPointsMaterial ) { - - refreshUniformsPoints( uniforms, material, pixelRatio, height ); - - } else if ( material.isSpriteMaterial ) { - - refreshUniformsSprites( uniforms, material ); - - } else if ( material.isShadowMaterial ) { - - uniforms.color.value.copy( material.color ); - uniforms.opacity.value = material.opacity; - - } else if ( material.isShaderMaterial ) { - - material.uniformsNeedUpdate = false; // #15581 - - } - - } - - function refreshUniformsCommon( uniforms, material ) { - - uniforms.opacity.value = material.opacity; - - if ( material.color ) { - - uniforms.diffuse.value.copy( material.color ); - - } - - if ( material.emissive ) { - - uniforms.emissive.value.copy( material.emissive ).multiplyScalar( material.emissiveIntensity ); - - } - - if ( material.map ) { - - uniforms.map.value = material.map; - - refreshTransformUniform( material.map, uniforms.mapTransform ); - - } - - if ( material.alphaMap ) { - - uniforms.alphaMap.value = material.alphaMap; - - refreshTransformUniform( material.alphaMap, uniforms.alphaMapTransform ); - - } - - if ( material.bumpMap ) { - - uniforms.bumpMap.value = material.bumpMap; - - refreshTransformUniform( material.bumpMap, uniforms.bumpMapTransform ); - - uniforms.bumpScale.value = material.bumpScale; - - if ( material.side === BackSide ) { - - uniforms.bumpScale.value *= - 1; - - } - - } - - if ( material.normalMap ) { - - uniforms.normalMap.value = material.normalMap; - - refreshTransformUniform( material.normalMap, uniforms.normalMapTransform ); - - uniforms.normalScale.value.copy( material.normalScale ); - - if ( material.side === BackSide ) { - - uniforms.normalScale.value.negate(); - - } - - } - - if ( material.displacementMap ) { - - uniforms.displacementMap.value = material.displacementMap; - - refreshTransformUniform( material.displacementMap, uniforms.displacementMapTransform ); - - uniforms.displacementScale.value = material.displacementScale; - uniforms.displacementBias.value = material.displacementBias; - - } - - if ( material.emissiveMap ) { - - uniforms.emissiveMap.value = material.emissiveMap; - - refreshTransformUniform( material.emissiveMap, uniforms.emissiveMapTransform ); - - } - - if ( material.specularMap ) { - - uniforms.specularMap.value = material.specularMap; - - refreshTransformUniform( material.specularMap, uniforms.specularMapTransform ); - - } - - if ( material.alphaTest > 0 ) { - - uniforms.alphaTest.value = material.alphaTest; - - } - - const envMap = properties.get( material ).envMap; - - if ( envMap ) { - - uniforms.envMap.value = envMap; - - uniforms.flipEnvMap.value = ( envMap.isCubeTexture && envMap.isRenderTargetTexture === false ) ? - 1 : 1; - - uniforms.reflectivity.value = material.reflectivity; - uniforms.ior.value = material.ior; - uniforms.refractionRatio.value = material.refractionRatio; - - } - - if ( material.lightMap ) { - - uniforms.lightMap.value = material.lightMap; - - // artist-friendly light intensity scaling factor - const scaleFactor = ( renderer._useLegacyLights === true ) ? Math.PI : 1; - - uniforms.lightMapIntensity.value = material.lightMapIntensity * scaleFactor; - - refreshTransformUniform( material.lightMap, uniforms.lightMapTransform ); - - } - - if ( material.aoMap ) { - - uniforms.aoMap.value = material.aoMap; - uniforms.aoMapIntensity.value = material.aoMapIntensity; - - refreshTransformUniform( material.aoMap, uniforms.aoMapTransform ); - - } - - } - - function refreshUniformsLine( uniforms, material ) { - - uniforms.diffuse.value.copy( material.color ); - uniforms.opacity.value = material.opacity; - - if ( material.map ) { - - uniforms.map.value = material.map; - - refreshTransformUniform( material.map, uniforms.mapTransform ); - - } - - } - - function refreshUniformsDash( uniforms, material ) { - - uniforms.dashSize.value = material.dashSize; - uniforms.totalSize.value = material.dashSize + material.gapSize; - uniforms.scale.value = material.scale; - - } - - function refreshUniformsPoints( uniforms, material, pixelRatio, height ) { - - uniforms.diffuse.value.copy( material.color ); - uniforms.opacity.value = material.opacity; - uniforms.size.value = material.size * pixelRatio; - uniforms.scale.value = height * 0.5; - - if ( material.map ) { - - uniforms.map.value = material.map; - - refreshTransformUniform( material.map, uniforms.uvTransform ); - - } - - if ( material.alphaMap ) { - - uniforms.alphaMap.value = material.alphaMap; - - refreshTransformUniform( material.alphaMap, uniforms.alphaMapTransform ); - - } - - if ( material.alphaTest > 0 ) { - - uniforms.alphaTest.value = material.alphaTest; - - } - - } - - function refreshUniformsSprites( uniforms, material ) { - - uniforms.diffuse.value.copy( material.color ); - uniforms.opacity.value = material.opacity; - uniforms.rotation.value = material.rotation; - - if ( material.map ) { - - uniforms.map.value = material.map; - - refreshTransformUniform( material.map, uniforms.mapTransform ); - - } - - if ( material.alphaMap ) { - - uniforms.alphaMap.value = material.alphaMap; - - refreshTransformUniform( material.alphaMap, uniforms.alphaMapTransform ); - - } - - if ( material.alphaTest > 0 ) { - - uniforms.alphaTest.value = material.alphaTest; - - } - - } - - function refreshUniformsPhong( uniforms, material ) { - - uniforms.specular.value.copy( material.specular ); - uniforms.shininess.value = Math.max( material.shininess, 1e-4 ); // to prevent pow( 0.0, 0.0 ) - - } - - function refreshUniformsToon( uniforms, material ) { - - if ( material.gradientMap ) { - - uniforms.gradientMap.value = material.gradientMap; - - } - - } - - function refreshUniformsStandard( uniforms, material ) { - - uniforms.metalness.value = material.metalness; - - if ( material.metalnessMap ) { - - uniforms.metalnessMap.value = material.metalnessMap; - - refreshTransformUniform( material.metalnessMap, uniforms.metalnessMapTransform ); - - } - - uniforms.roughness.value = material.roughness; - - if ( material.roughnessMap ) { - - uniforms.roughnessMap.value = material.roughnessMap; - - refreshTransformUniform( material.roughnessMap, uniforms.roughnessMapTransform ); - - } - - const envMap = properties.get( material ).envMap; - - if ( envMap ) { - - //uniforms.envMap.value = material.envMap; // part of uniforms common - uniforms.envMapIntensity.value = material.envMapIntensity; - - } - - } - - function refreshUniformsPhysical( uniforms, material, transmissionRenderTarget ) { - - uniforms.ior.value = material.ior; // also part of uniforms common - - if ( material.sheen > 0 ) { - - uniforms.sheenColor.value.copy( material.sheenColor ).multiplyScalar( material.sheen ); - - uniforms.sheenRoughness.value = material.sheenRoughness; - - if ( material.sheenColorMap ) { - - uniforms.sheenColorMap.value = material.sheenColorMap; - - refreshTransformUniform( material.sheenColorMap, uniforms.sheenColorMapTransform ); - - } - - if ( material.sheenRoughnessMap ) { - - uniforms.sheenRoughnessMap.value = material.sheenRoughnessMap; - - refreshTransformUniform( material.sheenRoughnessMap, uniforms.sheenRoughnessMapTransform ); - - } - - } - - if ( material.clearcoat > 0 ) { - - uniforms.clearcoat.value = material.clearcoat; - uniforms.clearcoatRoughness.value = material.clearcoatRoughness; - - if ( material.clearcoatMap ) { - - uniforms.clearcoatMap.value = material.clearcoatMap; - - refreshTransformUniform( material.clearcoatMap, uniforms.clearcoatMapTransform ); - - } - - if ( material.clearcoatRoughnessMap ) { - - uniforms.clearcoatRoughnessMap.value = material.clearcoatRoughnessMap; - - refreshTransformUniform( material.clearcoatRoughnessMap, uniforms.clearcoatRoughnessMapTransform ); - - } - - if ( material.clearcoatNormalMap ) { - - uniforms.clearcoatNormalMap.value = material.clearcoatNormalMap; - - refreshTransformUniform( material.clearcoatNormalMap, uniforms.clearcoatNormalMapTransform ); - - uniforms.clearcoatNormalScale.value.copy( material.clearcoatNormalScale ); - - if ( material.side === BackSide ) { - - uniforms.clearcoatNormalScale.value.negate(); - - } - - } - - } - - if ( material.iridescence > 0 ) { - - uniforms.iridescence.value = material.iridescence; - uniforms.iridescenceIOR.value = material.iridescenceIOR; - uniforms.iridescenceThicknessMinimum.value = material.iridescenceThicknessRange[ 0 ]; - uniforms.iridescenceThicknessMaximum.value = material.iridescenceThicknessRange[ 1 ]; - - if ( material.iridescenceMap ) { - - uniforms.iridescenceMap.value = material.iridescenceMap; - - refreshTransformUniform( material.iridescenceMap, uniforms.iridescenceMapTransform ); - - } - - if ( material.iridescenceThicknessMap ) { - - uniforms.iridescenceThicknessMap.value = material.iridescenceThicknessMap; - - refreshTransformUniform( material.iridescenceThicknessMap, uniforms.iridescenceThicknessMapTransform ); - - } - - } - - if ( material.transmission > 0 ) { - - uniforms.transmission.value = material.transmission; - uniforms.transmissionSamplerMap.value = transmissionRenderTarget.texture; - uniforms.transmissionSamplerSize.value.set( transmissionRenderTarget.width, transmissionRenderTarget.height ); - - if ( material.transmissionMap ) { - - uniforms.transmissionMap.value = material.transmissionMap; - - refreshTransformUniform( material.transmissionMap, uniforms.transmissionMapTransform ); - - } - - uniforms.thickness.value = material.thickness; - - if ( material.thicknessMap ) { - - uniforms.thicknessMap.value = material.thicknessMap; - - refreshTransformUniform( material.thicknessMap, uniforms.thicknessMapTransform ); - - } - - uniforms.attenuationDistance.value = material.attenuationDistance; - uniforms.attenuationColor.value.copy( material.attenuationColor ); - - } - - if ( material.anisotropy > 0 ) { - - uniforms.anisotropyVector.value.set( material.anisotropy * Math.cos( material.anisotropyRotation ), material.anisotropy * Math.sin( material.anisotropyRotation ) ); - - if ( material.anisotropyMap ) { - - uniforms.anisotropyMap.value = material.anisotropyMap; - - refreshTransformUniform( material.anisotropyMap, uniforms.anisotropyMapTransform ); - - } - - } - - uniforms.specularIntensity.value = material.specularIntensity; - uniforms.specularColor.value.copy( material.specularColor ); - - if ( material.specularColorMap ) { - - uniforms.specularColorMap.value = material.specularColorMap; - - refreshTransformUniform( material.specularColorMap, uniforms.specularColorMapTransform ); - - } - - if ( material.specularIntensityMap ) { - - uniforms.specularIntensityMap.value = material.specularIntensityMap; - - refreshTransformUniform( material.specularIntensityMap, uniforms.specularIntensityMapTransform ); - - } - - } - - function refreshUniformsMatcap( uniforms, material ) { - - if ( material.matcap ) { - - uniforms.matcap.value = material.matcap; - - } - - } - - function refreshUniformsDistance( uniforms, material ) { - - const light = properties.get( material ).light; - - uniforms.referencePosition.value.setFromMatrixPosition( light.matrixWorld ); - uniforms.nearDistance.value = light.shadow.camera.near; - uniforms.farDistance.value = light.shadow.camera.far; - - } - - return { - refreshFogUniforms: refreshFogUniforms, - refreshMaterialUniforms: refreshMaterialUniforms - }; - -} - -function WebGLUniformsGroups( gl, info, capabilities, state ) { - - let buffers = {}; - let updateList = {}; - let allocatedBindingPoints = []; - - const maxBindingPoints = ( capabilities.isWebGL2 ) ? gl.getParameter( gl.MAX_UNIFORM_BUFFER_BINDINGS ) : 0; // binding points are global whereas block indices are per shader program - - function bind( uniformsGroup, program ) { - - const webglProgram = program.program; - state.uniformBlockBinding( uniformsGroup, webglProgram ); - - } - - function update( uniformsGroup, program ) { - - let buffer = buffers[ uniformsGroup.id ]; - - if ( buffer === undefined ) { - - prepareUniformsGroup( uniformsGroup ); - - buffer = createBuffer( uniformsGroup ); - buffers[ uniformsGroup.id ] = buffer; - - uniformsGroup.addEventListener( 'dispose', onUniformsGroupsDispose ); - - } - - // ensure to update the binding points/block indices mapping for this program - - const webglProgram = program.program; - state.updateUBOMapping( uniformsGroup, webglProgram ); - - // update UBO once per frame - - const frame = info.render.frame; - - if ( updateList[ uniformsGroup.id ] !== frame ) { - - updateBufferData( uniformsGroup ); - - updateList[ uniformsGroup.id ] = frame; - - } - - } - - function createBuffer( uniformsGroup ) { - - // the setup of an UBO is independent of a particular shader program but global - - const bindingPointIndex = allocateBindingPointIndex(); - uniformsGroup.__bindingPointIndex = bindingPointIndex; - - const buffer = gl.createBuffer(); - const size = uniformsGroup.__size; - const usage = uniformsGroup.usage; - - gl.bindBuffer( gl.UNIFORM_BUFFER, buffer ); - gl.bufferData( gl.UNIFORM_BUFFER, size, usage ); - gl.bindBuffer( gl.UNIFORM_BUFFER, null ); - gl.bindBufferBase( gl.UNIFORM_BUFFER, bindingPointIndex, buffer ); - - return buffer; - - } - - function allocateBindingPointIndex() { - - for ( let i = 0; i < maxBindingPoints; i ++ ) { - - if ( allocatedBindingPoints.indexOf( i ) === - 1 ) { - - allocatedBindingPoints.push( i ); - return i; - - } - - } - - console.error( 'THREE.WebGLRenderer: Maximum number of simultaneously usable uniforms groups reached.' ); - - return 0; - - } - - function updateBufferData( uniformsGroup ) { - - const buffer = buffers[ uniformsGroup.id ]; - const uniforms = uniformsGroup.uniforms; - const cache = uniformsGroup.__cache; - - gl.bindBuffer( gl.UNIFORM_BUFFER, buffer ); - - for ( let i = 0, il = uniforms.length; i < il; i ++ ) { - - const uniformArray = Array.isArray( uniforms[ i ] ) ? uniforms[ i ] : [ uniforms[ i ] ]; - - for ( let j = 0, jl = uniformArray.length; j < jl; j ++ ) { - - const uniform = uniformArray[ j ]; - - if ( hasUniformChanged( uniform, i, j, cache ) === true ) { - - const offset = uniform.__offset; - - const values = Array.isArray( uniform.value ) ? uniform.value : [ uniform.value ]; - - let arrayOffset = 0; - - for ( let k = 0; k < values.length; k ++ ) { - - const value = values[ k ]; - - const info = getUniformSize( value ); - - // TODO add integer and struct support - if ( typeof value === 'number' || typeof value === 'boolean' ) { - - uniform.__data[ 0 ] = value; - gl.bufferSubData( gl.UNIFORM_BUFFER, offset + arrayOffset, uniform.__data ); - - } else if ( value.isMatrix3 ) { - - // manually converting 3x3 to 3x4 - - uniform.__data[ 0 ] = value.elements[ 0 ]; - uniform.__data[ 1 ] = value.elements[ 1 ]; - uniform.__data[ 2 ] = value.elements[ 2 ]; - uniform.__data[ 3 ] = 0; - uniform.__data[ 4 ] = value.elements[ 3 ]; - uniform.__data[ 5 ] = value.elements[ 4 ]; - uniform.__data[ 6 ] = value.elements[ 5 ]; - uniform.__data[ 7 ] = 0; - uniform.__data[ 8 ] = value.elements[ 6 ]; - uniform.__data[ 9 ] = value.elements[ 7 ]; - uniform.__data[ 10 ] = value.elements[ 8 ]; - uniform.__data[ 11 ] = 0; - - } else { - - value.toArray( uniform.__data, arrayOffset ); - - arrayOffset += info.storage / Float32Array.BYTES_PER_ELEMENT; - - } - - } - - gl.bufferSubData( gl.UNIFORM_BUFFER, offset, uniform.__data ); - - } - - } - - } - - gl.bindBuffer( gl.UNIFORM_BUFFER, null ); - - } - - function hasUniformChanged( uniform, index, indexArray, cache ) { - - const value = uniform.value; - const indexString = index + '_' + indexArray; - - if ( cache[ indexString ] === undefined ) { - - // cache entry does not exist so far - - if ( typeof value === 'number' || typeof value === 'boolean' ) { - - cache[ indexString ] = value; - - } else { - - cache[ indexString ] = value.clone(); - - } - - return true; - - } else { - - const cachedObject = cache[ indexString ]; - - // compare current value with cached entry - - if ( typeof value === 'number' || typeof value === 'boolean' ) { - - if ( cachedObject !== value ) { - - cache[ indexString ] = value; - return true; - - } - - } else { - - if ( cachedObject.equals( value ) === false ) { - - cachedObject.copy( value ); - return true; - - } - - } - - } - - return false; - - } - - function prepareUniformsGroup( uniformsGroup ) { - - // determine total buffer size according to the STD140 layout - // Hint: STD140 is the only supported layout in WebGL 2 - - const uniforms = uniformsGroup.uniforms; - - let offset = 0; // global buffer offset in bytes - const chunkSize = 16; // size of a chunk in bytes - - for ( let i = 0, l = uniforms.length; i < l; i ++ ) { - - const uniformArray = Array.isArray( uniforms[ i ] ) ? uniforms[ i ] : [ uniforms[ i ] ]; - - for ( let j = 0, jl = uniformArray.length; j < jl; j ++ ) { - - const uniform = uniformArray[ j ]; - - const values = Array.isArray( uniform.value ) ? uniform.value : [ uniform.value ]; - - for ( let k = 0, kl = values.length; k < kl; k ++ ) { - - const value = values[ k ]; - - const info = getUniformSize( value ); - - // Calculate the chunk offset - const chunkOffsetUniform = offset % chunkSize; - - // Check for chunk overflow - if ( chunkOffsetUniform !== 0 && ( chunkSize - chunkOffsetUniform ) < info.boundary ) { - - // Add padding and adjust offset - offset += ( chunkSize - chunkOffsetUniform ); - - } - - // the following two properties will be used for partial buffer updates - - uniform.__data = new Float32Array( info.storage / Float32Array.BYTES_PER_ELEMENT ); - uniform.__offset = offset; - - - // Update the global offset - offset += info.storage; - - - } - - } - - } - - // ensure correct final padding - - const chunkOffset = offset % chunkSize; - - if ( chunkOffset > 0 ) offset += ( chunkSize - chunkOffset ); - - // - - uniformsGroup.__size = offset; - uniformsGroup.__cache = {}; - - return this; - - } - - function getUniformSize( value ) { - - const info = { - boundary: 0, // bytes - storage: 0 // bytes - }; - - // determine sizes according to STD140 - - if ( typeof value === 'number' || typeof value === 'boolean' ) { - - // float/int/bool - - info.boundary = 4; - info.storage = 4; - - } else if ( value.isVector2 ) { - - // vec2 - - info.boundary = 8; - info.storage = 8; - - } else if ( value.isVector3 || value.isColor ) { - - // vec3 - - info.boundary = 16; - info.storage = 12; // evil: vec3 must start on a 16-byte boundary but it only consumes 12 bytes - - } else if ( value.isVector4 ) { - - // vec4 - - info.boundary = 16; - info.storage = 16; - - } else if ( value.isMatrix3 ) { - - // mat3 (in STD140 a 3x3 matrix is represented as 3x4) - - info.boundary = 48; - info.storage = 48; - - } else if ( value.isMatrix4 ) { - - // mat4 - - info.boundary = 64; - info.storage = 64; - - } else if ( value.isTexture ) { - - console.warn( 'THREE.WebGLRenderer: Texture samplers can not be part of an uniforms group.' ); - - } else { - - console.warn( 'THREE.WebGLRenderer: Unsupported uniform value type.', value ); - - } - - return info; - - } - - function onUniformsGroupsDispose( event ) { - - const uniformsGroup = event.target; - - uniformsGroup.removeEventListener( 'dispose', onUniformsGroupsDispose ); - - const index = allocatedBindingPoints.indexOf( uniformsGroup.__bindingPointIndex ); - allocatedBindingPoints.splice( index, 1 ); - - gl.deleteBuffer( buffers[ uniformsGroup.id ] ); - - delete buffers[ uniformsGroup.id ]; - delete updateList[ uniformsGroup.id ]; - - } - - function dispose() { - - for ( const id in buffers ) { - - gl.deleteBuffer( buffers[ id ] ); - - } - - allocatedBindingPoints = []; - buffers = {}; - updateList = {}; - - } - - return { - - bind: bind, - update: update, - - dispose: dispose - - }; - -} - -class WebGLRenderer { - - constructor( parameters = {} ) { - - const { - canvas = createCanvasElement(), - context = null, - depth = true, - stencil = true, - alpha = false, - antialias = false, - premultipliedAlpha = true, - preserveDrawingBuffer = false, - powerPreference = 'default', - failIfMajorPerformanceCaveat = false, - } = parameters; - - this.isWebGLRenderer = true; - - let _alpha; - - if ( context !== null ) { - - _alpha = context.getContextAttributes().alpha; - - } else { - - _alpha = alpha; - - } - - const uintClearColor = new Uint32Array( 4 ); - const intClearColor = new Int32Array( 4 ); - - let currentRenderList = null; - let currentRenderState = null; - - // render() can be called from within a callback triggered by another render. - // We track this so that the nested render call gets its list and state isolated from the parent render call. - - const renderListStack = []; - const renderStateStack = []; - - // public properties - - this.domElement = canvas; - - // Debug configuration container - this.debug = { - - /** - * Enables error checking and reporting when shader programs are being compiled - * @type {boolean} - */ - checkShaderErrors: true, - /** - * Callback for custom error reporting. - * @type {?Function} - */ - onShaderError: null - }; - - // clearing - - this.autoClear = true; - this.autoClearColor = true; - this.autoClearDepth = true; - this.autoClearStencil = true; - - // scene graph - - this.sortObjects = true; - - // user-defined clipping - - this.clippingPlanes = []; - this.localClippingEnabled = false; - - // physically based shading - - this._outputColorSpace = SRGBColorSpace; - - // physical lights - - this._useLegacyLights = false; - - // tone mapping - - this.toneMapping = NoToneMapping; - this.toneMappingExposure = 1.0; - - // internal properties - - const _this = this; - - let _isContextLost = false; - - // internal state cache - - let _currentActiveCubeFace = 0; - let _currentActiveMipmapLevel = 0; - let _currentRenderTarget = null; - let _currentMaterialId = - 1; - - let _currentCamera = null; - - const _currentViewport = new Vector4(); - const _currentScissor = new Vector4(); - let _currentScissorTest = null; - - const _currentClearColor = new Color( 0x000000 ); - let _currentClearAlpha = 0; - - // - - let _width = canvas.width; - let _height = canvas.height; - - let _pixelRatio = 1; - let _opaqueSort = null; - let _transparentSort = null; - - const _viewport = new Vector4( 0, 0, _width, _height ); - const _scissor = new Vector4( 0, 0, _width, _height ); - let _scissorTest = false; - - // frustum - - const _frustum = new Frustum(); - - // clipping - - let _clippingEnabled = false; - let _localClippingEnabled = false; - - // transmission - - let _transmissionRenderTarget = null; - - // camera matrices cache - - const _projScreenMatrix = new Matrix4(); - - const _vector2 = new Vector2(); - const _vector3 = new Vector3(); - - const _emptyScene = { background: null, fog: null, environment: null, overrideMaterial: null, isScene: true }; - - function getTargetPixelRatio() { - - return _currentRenderTarget === null ? _pixelRatio : 1; - - } - - // initialize - - let _gl = context; - - function getContext( contextNames, contextAttributes ) { - - for ( let i = 0; i < contextNames.length; i ++ ) { - - const contextName = contextNames[ i ]; - const context = canvas.getContext( contextName, contextAttributes ); - if ( context !== null ) return context; - - } - - return null; - - } - - try { - - const contextAttributes = { - alpha: true, - depth, - stencil, - antialias, - premultipliedAlpha, - preserveDrawingBuffer, - powerPreference, - failIfMajorPerformanceCaveat, - }; - - // OffscreenCanvas does not have setAttribute, see #22811 - if ( 'setAttribute' in canvas ) canvas.setAttribute( 'data-engine', `three.js r${REVISION}` ); - - // event listeners must be registered before WebGL context is created, see #12753 - canvas.addEventListener( 'webglcontextlost', onContextLost, false ); - canvas.addEventListener( 'webglcontextrestored', onContextRestore, false ); - canvas.addEventListener( 'webglcontextcreationerror', onContextCreationError, false ); - - if ( _gl === null ) { - - const contextNames = [ 'webgl2', 'webgl', 'experimental-webgl' ]; - - if ( _this.isWebGL1Renderer === true ) { - - contextNames.shift(); - - } - - _gl = getContext( contextNames, contextAttributes ); - - if ( _gl === null ) { - - if ( getContext( contextNames ) ) { - - throw new Error( 'Error creating WebGL context with your selected attributes.' ); - - } else { - - throw new Error( 'Error creating WebGL context.' ); - - } - - } - - } - - if ( typeof WebGLRenderingContext !== 'undefined' && _gl instanceof WebGLRenderingContext ) { // @deprecated, r153 - - console.warn( 'THREE.WebGLRenderer: WebGL 1 support was deprecated in r153 and will be removed in r163.' ); - - } - - // Some experimental-webgl implementations do not have getShaderPrecisionFormat - - if ( _gl.getShaderPrecisionFormat === undefined ) { - - _gl.getShaderPrecisionFormat = function () { - - return { 'rangeMin': 1, 'rangeMax': 1, 'precision': 1 }; - - }; - - } - - } catch ( error ) { - - console.error( 'THREE.WebGLRenderer: ' + error.message ); - throw error; - - } - - let extensions, capabilities, state, info; - let properties, textures, cubemaps, cubeuvmaps, attributes, geometries, objects; - let programCache, materials, renderLists, renderStates, clipping, shadowMap; - - let background, morphtargets, bufferRenderer, indexedBufferRenderer; - - let utils, bindingStates, uniformsGroups; - - function initGLContext() { - - extensions = new WebGLExtensions( _gl ); - - capabilities = new WebGLCapabilities( _gl, extensions, parameters ); - - extensions.init( capabilities ); - - utils = new WebGLUtils( _gl, extensions, capabilities ); - - state = new WebGLState( _gl, extensions, capabilities ); - - info = new WebGLInfo( _gl ); - properties = new WebGLProperties(); - textures = new WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info ); - cubemaps = new WebGLCubeMaps( _this ); - cubeuvmaps = new WebGLCubeUVMaps( _this ); - attributes = new WebGLAttributes( _gl, capabilities ); - bindingStates = new WebGLBindingStates( _gl, extensions, attributes, capabilities ); - geometries = new WebGLGeometries( _gl, attributes, info, bindingStates ); - objects = new WebGLObjects( _gl, geometries, attributes, info ); - morphtargets = new WebGLMorphtargets( _gl, capabilities, textures ); - clipping = new WebGLClipping( properties ); - programCache = new WebGLPrograms( _this, cubemaps, cubeuvmaps, extensions, capabilities, bindingStates, clipping ); - materials = new WebGLMaterials( _this, properties ); - renderLists = new WebGLRenderLists(); - renderStates = new WebGLRenderStates( extensions, capabilities ); - background = new WebGLBackground( _this, cubemaps, cubeuvmaps, state, objects, _alpha, premultipliedAlpha ); - shadowMap = new WebGLShadowMap( _this, objects, capabilities ); - uniformsGroups = new WebGLUniformsGroups( _gl, info, capabilities, state ); - - bufferRenderer = new WebGLBufferRenderer( _gl, extensions, info, capabilities ); - indexedBufferRenderer = new WebGLIndexedBufferRenderer( _gl, extensions, info, capabilities ); - - info.programs = programCache.programs; - - _this.capabilities = capabilities; - _this.extensions = extensions; - _this.properties = properties; - _this.renderLists = renderLists; - _this.shadowMap = shadowMap; - _this.state = state; - _this.info = info; - - } - - initGLContext(); - - // xr - - const xr = new WebXRManager( _this, _gl ); - - this.xr = xr; - - // API - - this.getContext = function () { - - return _gl; - - }; - - this.getContextAttributes = function () { - - return _gl.getContextAttributes(); - - }; - - this.forceContextLoss = function () { - - const extension = extensions.get( 'WEBGL_lose_context' ); - if ( extension ) extension.loseContext(); - - }; - - this.forceContextRestore = function () { - - const extension = extensions.get( 'WEBGL_lose_context' ); - if ( extension ) extension.restoreContext(); - - }; - - this.getPixelRatio = function () { - - return _pixelRatio; - - }; - - this.setPixelRatio = function ( value ) { - - if ( value === undefined ) return; - - _pixelRatio = value; - - this.setSize( _width, _height, false ); - - }; - - this.getSize = function ( target ) { - - return target.set( _width, _height ); - - }; - - this.setSize = function ( width, height, updateStyle = true ) { - - if ( xr.isPresenting ) { - - console.warn( 'THREE.WebGLRenderer: Can\'t change size while VR device is presenting.' ); - return; - - } - - _width = width; - _height = height; - - canvas.width = Math.floor( width * _pixelRatio ); - canvas.height = Math.floor( height * _pixelRatio ); - - if ( updateStyle === true ) { - - canvas.style.width = width + 'px'; - canvas.style.height = height + 'px'; - - } - - this.setViewport( 0, 0, width, height ); - - }; - - this.getDrawingBufferSize = function ( target ) { - - return target.set( _width * _pixelRatio, _height * _pixelRatio ).floor(); - - }; - - this.setDrawingBufferSize = function ( width, height, pixelRatio ) { - - _width = width; - _height = height; - - _pixelRatio = pixelRatio; - - canvas.width = Math.floor( width * pixelRatio ); - canvas.height = Math.floor( height * pixelRatio ); - - this.setViewport( 0, 0, width, height ); - - }; - - this.getCurrentViewport = function ( target ) { - - return target.copy( _currentViewport ); - - }; - - this.getViewport = function ( target ) { - - return target.copy( _viewport ); - - }; - - this.setViewport = function ( x, y, width, height ) { - - if ( x.isVector4 ) { - - _viewport.set( x.x, x.y, x.z, x.w ); - - } else { - - _viewport.set( x, y, width, height ); - - } - - state.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).floor() ); - - }; - - this.getScissor = function ( target ) { - - return target.copy( _scissor ); - - }; - - this.setScissor = function ( x, y, width, height ) { - - if ( x.isVector4 ) { - - _scissor.set( x.x, x.y, x.z, x.w ); - - } else { - - _scissor.set( x, y, width, height ); - - } - - state.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).floor() ); - - }; - - this.getScissorTest = function () { - - return _scissorTest; - - }; - - this.setScissorTest = function ( boolean ) { - - state.setScissorTest( _scissorTest = boolean ); - - }; - - this.setOpaqueSort = function ( method ) { - - _opaqueSort = method; - - }; - - this.setTransparentSort = function ( method ) { - - _transparentSort = method; - - }; - - // Clearing - - this.getClearColor = function ( target ) { - - return target.copy( background.getClearColor() ); - - }; - - this.setClearColor = function () { - - background.setClearColor.apply( background, arguments ); - - }; - - this.getClearAlpha = function () { - - return background.getClearAlpha(); - - }; - - this.setClearAlpha = function () { - - background.setClearAlpha.apply( background, arguments ); - - }; - - this.clear = function ( color = true, depth = true, stencil = true ) { - - let bits = 0; - - if ( color ) { - - // check if we're trying to clear an integer target - let isIntegerFormat = false; - if ( _currentRenderTarget !== null ) { - - const targetFormat = _currentRenderTarget.texture.format; - isIntegerFormat = targetFormat === RGBAIntegerFormat || - targetFormat === RGIntegerFormat || - targetFormat === RedIntegerFormat; - - } - - // use the appropriate clear functions to clear the target if it's a signed - // or unsigned integer target - if ( isIntegerFormat ) { - - const targetType = _currentRenderTarget.texture.type; - const isUnsignedType = targetType === UnsignedByteType || - targetType === UnsignedIntType || - targetType === UnsignedShortType || - targetType === UnsignedInt248Type || - targetType === UnsignedShort4444Type || - targetType === UnsignedShort5551Type; - - const clearColor = background.getClearColor(); - const a = background.getClearAlpha(); - const r = clearColor.r; - const g = clearColor.g; - const b = clearColor.b; - - if ( isUnsignedType ) { - - uintClearColor[ 0 ] = r; - uintClearColor[ 1 ] = g; - uintClearColor[ 2 ] = b; - uintClearColor[ 3 ] = a; - _gl.clearBufferuiv( _gl.COLOR, 0, uintClearColor ); - - } else { - - intClearColor[ 0 ] = r; - intClearColor[ 1 ] = g; - intClearColor[ 2 ] = b; - intClearColor[ 3 ] = a; - _gl.clearBufferiv( _gl.COLOR, 0, intClearColor ); - - } - - } else { - - bits |= _gl.COLOR_BUFFER_BIT; - - } - - } - - if ( depth ) bits |= _gl.DEPTH_BUFFER_BIT; - if ( stencil ) { - - bits |= _gl.STENCIL_BUFFER_BIT; - this.state.buffers.stencil.setMask( 0xffffffff ); - - } - - _gl.clear( bits ); - - }; - - this.clearColor = function () { - - this.clear( true, false, false ); - - }; - - this.clearDepth = function () { - - this.clear( false, true, false ); - - }; - - this.clearStencil = function () { - - this.clear( false, false, true ); - - }; - - // - - this.dispose = function () { - - canvas.removeEventListener( 'webglcontextlost', onContextLost, false ); - canvas.removeEventListener( 'webglcontextrestored', onContextRestore, false ); - canvas.removeEventListener( 'webglcontextcreationerror', onContextCreationError, false ); - - renderLists.dispose(); - renderStates.dispose(); - properties.dispose(); - cubemaps.dispose(); - cubeuvmaps.dispose(); - objects.dispose(); - bindingStates.dispose(); - uniformsGroups.dispose(); - programCache.dispose(); - - xr.dispose(); - - xr.removeEventListener( 'sessionstart', onXRSessionStart ); - xr.removeEventListener( 'sessionend', onXRSessionEnd ); - - if ( _transmissionRenderTarget ) { - - _transmissionRenderTarget.dispose(); - _transmissionRenderTarget = null; - - } - - animation.stop(); - - }; - - // Events - - function onContextLost( event ) { - - event.preventDefault(); - - console.log( 'THREE.WebGLRenderer: Context Lost.' ); - - _isContextLost = true; - - } - - function onContextRestore( /* event */ ) { - - console.log( 'THREE.WebGLRenderer: Context Restored.' ); - - _isContextLost = false; - - const infoAutoReset = info.autoReset; - const shadowMapEnabled = shadowMap.enabled; - const shadowMapAutoUpdate = shadowMap.autoUpdate; - const shadowMapNeedsUpdate = shadowMap.needsUpdate; - const shadowMapType = shadowMap.type; - - initGLContext(); - - info.autoReset = infoAutoReset; - shadowMap.enabled = shadowMapEnabled; - shadowMap.autoUpdate = shadowMapAutoUpdate; - shadowMap.needsUpdate = shadowMapNeedsUpdate; - shadowMap.type = shadowMapType; - - } - - function onContextCreationError( event ) { - - console.error( 'THREE.WebGLRenderer: A WebGL context could not be created. Reason: ', event.statusMessage ); - - } - - function onMaterialDispose( event ) { - - const material = event.target; - - material.removeEventListener( 'dispose', onMaterialDispose ); - - deallocateMaterial( material ); - - } - - // Buffer deallocation - - function deallocateMaterial( material ) { - - releaseMaterialProgramReferences( material ); - - properties.remove( material ); - - } - - - function releaseMaterialProgramReferences( material ) { - - const programs = properties.get( material ).programs; - - if ( programs !== undefined ) { - - programs.forEach( function ( program ) { - - programCache.releaseProgram( program ); - - } ); - - if ( material.isShaderMaterial ) { - - programCache.releaseShaderCache( material ); - - } - - } - - } - - // Buffer rendering - - this.renderBufferDirect = function ( camera, scene, geometry, material, object, group ) { - - if ( scene === null ) scene = _emptyScene; // renderBufferDirect second parameter used to be fog (could be null) - - const frontFaceCW = ( object.isMesh && object.matrixWorld.determinant() < 0 ); - - const program = setProgram( camera, scene, geometry, material, object ); - - state.setMaterial( material, frontFaceCW ); - - // - - let index = geometry.index; - let rangeFactor = 1; - - if ( material.wireframe === true ) { - - index = geometries.getWireframeAttribute( geometry ); - - if ( index === undefined ) return; - - rangeFactor = 2; - - } - - // - - const drawRange = geometry.drawRange; - const position = geometry.attributes.position; - - let drawStart = drawRange.start * rangeFactor; - let drawEnd = ( drawRange.start + drawRange.count ) * rangeFactor; - - if ( group !== null ) { - - drawStart = Math.max( drawStart, group.start * rangeFactor ); - drawEnd = Math.min( drawEnd, ( group.start + group.count ) * rangeFactor ); - - } - - if ( index !== null ) { - - drawStart = Math.max( drawStart, 0 ); - drawEnd = Math.min( drawEnd, index.count ); - - } else if ( position !== undefined && position !== null ) { - - drawStart = Math.max( drawStart, 0 ); - drawEnd = Math.min( drawEnd, position.count ); - - } - - const drawCount = drawEnd - drawStart; - - if ( drawCount < 0 || drawCount === Infinity ) return; - - // - - bindingStates.setup( object, material, program, geometry, index ); - - let attribute; - let renderer = bufferRenderer; - - if ( index !== null ) { - - attribute = attributes.get( index ); - - renderer = indexedBufferRenderer; - renderer.setIndex( attribute ); - - } - - // - - if ( object.isMesh ) { - - if ( material.wireframe === true ) { - - state.setLineWidth( material.wireframeLinewidth * getTargetPixelRatio() ); - renderer.setMode( _gl.LINES ); - - } else { - - renderer.setMode( _gl.TRIANGLES ); - - } - - } else if ( object.isLine ) { - - let lineWidth = material.linewidth; - - if ( lineWidth === undefined ) lineWidth = 1; // Not using Line*Material - - state.setLineWidth( lineWidth * getTargetPixelRatio() ); - - if ( object.isLineSegments ) { - - renderer.setMode( _gl.LINES ); - - } else if ( object.isLineLoop ) { - - renderer.setMode( _gl.LINE_LOOP ); - - } else { - - renderer.setMode( _gl.LINE_STRIP ); - - } - - } else if ( object.isPoints ) { - - renderer.setMode( _gl.POINTS ); - - } else if ( object.isSprite ) { - - renderer.setMode( _gl.TRIANGLES ); - - } - - if ( object.isBatchedMesh ) { - - renderer.renderMultiDraw( object._multiDrawStarts, object._multiDrawCounts, object._multiDrawCount ); - - } else if ( object.isInstancedMesh ) { - - renderer.renderInstances( drawStart, drawCount, object.count ); - - } else if ( geometry.isInstancedBufferGeometry ) { - - const maxInstanceCount = geometry._maxInstanceCount !== undefined ? geometry._maxInstanceCount : Infinity; - const instanceCount = Math.min( geometry.instanceCount, maxInstanceCount ); - - renderer.renderInstances( drawStart, drawCount, instanceCount ); - - } else { - - renderer.render( drawStart, drawCount ); - - } - - }; - - // Compile - - function prepareMaterial( material, scene, object ) { - - if ( material.transparent === true && material.side === DoubleSide && material.forceSinglePass === false ) { - - material.side = BackSide; - material.needsUpdate = true; - getProgram( material, scene, object ); - - material.side = FrontSide; - material.needsUpdate = true; - getProgram( material, scene, object ); - - material.side = DoubleSide; - - } else { - - getProgram( material, scene, object ); - - } - - } - - this.compile = function ( scene, camera, targetScene = null ) { - - if ( targetScene === null ) targetScene = scene; - - currentRenderState = renderStates.get( targetScene ); - currentRenderState.init(); - - renderStateStack.push( currentRenderState ); - - // gather lights from both the target scene and the new object that will be added to the scene. - - targetScene.traverseVisible( function ( object ) { - - if ( object.isLight && object.layers.test( camera.layers ) ) { - - currentRenderState.pushLight( object ); - - if ( object.castShadow ) { - - currentRenderState.pushShadow( object ); - - } - - } - - } ); - - if ( scene !== targetScene ) { - - scene.traverseVisible( function ( object ) { - - if ( object.isLight && object.layers.test( camera.layers ) ) { - - currentRenderState.pushLight( object ); - - if ( object.castShadow ) { - - currentRenderState.pushShadow( object ); - - } - - } - - } ); - - } - - currentRenderState.setupLights( _this._useLegacyLights ); - - // Only initialize materials in the new scene, not the targetScene. - - const materials = new Set(); - - scene.traverse( function ( object ) { - - const material = object.material; - - if ( material ) { - - if ( Array.isArray( material ) ) { - - for ( let i = 0; i < material.length; i ++ ) { - - const material2 = material[ i ]; - - prepareMaterial( material2, targetScene, object ); - materials.add( material2 ); - - } - - } else { - - prepareMaterial( material, targetScene, object ); - materials.add( material ); - - } - - } - - } ); - - renderStateStack.pop(); - currentRenderState = null; - - return materials; - - }; - - // compileAsync - - this.compileAsync = function ( scene, camera, targetScene = null ) { - - const materials = this.compile( scene, camera, targetScene ); - - // Wait for all the materials in the new object to indicate that they're - // ready to be used before resolving the promise. - - return new Promise( ( resolve ) => { - - function checkMaterialsReady() { - - materials.forEach( function ( material ) { - - const materialProperties = properties.get( material ); - const program = materialProperties.currentProgram; - - if ( program.isReady() ) { - - // remove any programs that report they're ready to use from the list - materials.delete( material ); - - } - - } ); - - // once the list of compiling materials is empty, call the callback - - if ( materials.size === 0 ) { - - resolve( scene ); - return; - - } - - // if some materials are still not ready, wait a bit and check again - - setTimeout( checkMaterialsReady, 10 ); - - } - - if ( extensions.get( 'KHR_parallel_shader_compile' ) !== null ) { - - // If we can check the compilation status of the materials without - // blocking then do so right away. - - checkMaterialsReady(); - - } else { - - // Otherwise start by waiting a bit to give the materials we just - // initialized a chance to finish. - - setTimeout( checkMaterialsReady, 10 ); - - } - - } ); - - }; - - // Animation Loop - - let onAnimationFrameCallback = null; - - function onAnimationFrame( time ) { - - if ( onAnimationFrameCallback ) onAnimationFrameCallback( time ); - - } - - function onXRSessionStart() { - - animation.stop(); - - } - - function onXRSessionEnd() { - - animation.start(); - - } - - const animation = new WebGLAnimation(); - animation.setAnimationLoop( onAnimationFrame ); - - if ( typeof self !== 'undefined' ) animation.setContext( self ); - - this.setAnimationLoop = function ( callback ) { - - onAnimationFrameCallback = callback; - xr.setAnimationLoop( callback ); - - ( callback === null ) ? animation.stop() : animation.start(); - - }; - - xr.addEventListener( 'sessionstart', onXRSessionStart ); - xr.addEventListener( 'sessionend', onXRSessionEnd ); - - // Rendering - - this.render = function ( scene, camera ) { - - if ( camera !== undefined && camera.isCamera !== true ) { - - console.error( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' ); - return; - - } - - if ( _isContextLost === true ) return; - - // update scene graph - - if ( scene.matrixWorldAutoUpdate === true ) scene.updateMatrixWorld(); - - // update camera matrices and frustum - - if ( camera.parent === null && camera.matrixWorldAutoUpdate === true ) camera.updateMatrixWorld(); - - if ( xr.enabled === true && xr.isPresenting === true ) { - - if ( xr.cameraAutoUpdate === true ) xr.updateCamera( camera ); - - camera = xr.getCamera(); // use XR camera for rendering - - } - - // - if ( scene.isScene === true ) scene.onBeforeRender( _this, scene, camera, _currentRenderTarget ); - - currentRenderState = renderStates.get( scene, renderStateStack.length ); - currentRenderState.init(); - - renderStateStack.push( currentRenderState ); - - _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); - _frustum.setFromProjectionMatrix( _projScreenMatrix ); - - _localClippingEnabled = this.localClippingEnabled; - _clippingEnabled = clipping.init( this.clippingPlanes, _localClippingEnabled ); - - currentRenderList = renderLists.get( scene, renderListStack.length ); - currentRenderList.init(); - - renderListStack.push( currentRenderList ); - - projectObject( scene, camera, 0, _this.sortObjects ); - - currentRenderList.finish(); - - if ( _this.sortObjects === true ) { - - currentRenderList.sort( _opaqueSort, _transparentSort ); - - } - - // - - this.info.render.frame ++; - - if ( _clippingEnabled === true ) clipping.beginShadows(); - - const shadowsArray = currentRenderState.state.shadowsArray; - - shadowMap.render( shadowsArray, scene, camera ); - - if ( _clippingEnabled === true ) clipping.endShadows(); - - // - - if ( this.info.autoReset === true ) this.info.reset(); - - - // - - if ( xr.enabled === false || xr.isPresenting === false || xr.hasDepthSensing() === false ) { - - background.render( currentRenderList, scene ); - - } - - // render scene - - currentRenderState.setupLights( _this._useLegacyLights ); - - if ( camera.isArrayCamera ) { - - const cameras = camera.cameras; - - for ( let i = 0, l = cameras.length; i < l; i ++ ) { - - const camera2 = cameras[ i ]; - - renderScene( currentRenderList, scene, camera2, camera2.viewport ); - - } - - } else { - - renderScene( currentRenderList, scene, camera ); - - } - - // - - if ( _currentRenderTarget !== null ) { - - // resolve multisample renderbuffers to a single-sample texture if necessary - - textures.updateMultisampleRenderTarget( _currentRenderTarget ); - - // Generate mipmap if we're using any kind of mipmap filtering - - textures.updateRenderTargetMipmap( _currentRenderTarget ); - - } - - // - - if ( scene.isScene === true ) scene.onAfterRender( _this, scene, camera ); - - // _gl.finish(); - - bindingStates.resetDefaultState(); - _currentMaterialId = - 1; - _currentCamera = null; - - renderStateStack.pop(); - - if ( renderStateStack.length > 0 ) { - - currentRenderState = renderStateStack[ renderStateStack.length - 1 ]; - - } else { - - currentRenderState = null; - - } - - renderListStack.pop(); - - if ( renderListStack.length > 0 ) { - - currentRenderList = renderListStack[ renderListStack.length - 1 ]; - - } else { - - currentRenderList = null; - - } - - }; - - function projectObject( object, camera, groupOrder, sortObjects ) { - - if ( object.visible === false ) return; - - const visible = object.layers.test( camera.layers ); - - if ( visible ) { - - if ( object.isGroup ) { - - groupOrder = object.renderOrder; - - } else if ( object.isLOD ) { - - if ( object.autoUpdate === true ) object.update( camera ); - - } else if ( object.isLight ) { - - currentRenderState.pushLight( object ); - - if ( object.castShadow ) { - - currentRenderState.pushShadow( object ); - - } - - } else if ( object.isSprite ) { - - if ( ! object.frustumCulled || _frustum.intersectsSprite( object ) ) { - - if ( sortObjects ) { - - _vector3.setFromMatrixPosition( object.matrixWorld ) - .applyMatrix4( _projScreenMatrix ); - - } - - const geometry = objects.update( object ); - const material = object.material; - - if ( material.visible ) { - - currentRenderList.push( object, geometry, material, groupOrder, _vector3.z, null ); - - } - - } - - } else if ( object.isMesh || object.isLine || object.isPoints ) { - - if ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) { - - const geometry = objects.update( object ); - const material = object.material; - - if ( sortObjects ) { - - if ( object.boundingSphere !== undefined ) { - - if ( object.boundingSphere === null ) object.computeBoundingSphere(); - _vector3.copy( object.boundingSphere.center ); - - } else { - - if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); - _vector3.copy( geometry.boundingSphere.center ); - - } - - _vector3 - .applyMatrix4( object.matrixWorld ) - .applyMatrix4( _projScreenMatrix ); - - } - - if ( Array.isArray( material ) ) { - - const groups = geometry.groups; - - for ( let i = 0, l = groups.length; i < l; i ++ ) { - - const group = groups[ i ]; - const groupMaterial = material[ group.materialIndex ]; - - if ( groupMaterial && groupMaterial.visible ) { - - currentRenderList.push( object, geometry, groupMaterial, groupOrder, _vector3.z, group ); - - } - - } - - } else if ( material.visible ) { - - currentRenderList.push( object, geometry, material, groupOrder, _vector3.z, null ); - - } - - } - - } - - } - - const children = object.children; - - for ( let i = 0, l = children.length; i < l; i ++ ) { - - projectObject( children[ i ], camera, groupOrder, sortObjects ); - - } - - } - - function renderScene( currentRenderList, scene, camera, viewport ) { - - const opaqueObjects = currentRenderList.opaque; - const transmissiveObjects = currentRenderList.transmissive; - const transparentObjects = currentRenderList.transparent; - - currentRenderState.setupLightsView( camera ); - - if ( _clippingEnabled === true ) clipping.setGlobalState( _this.clippingPlanes, camera ); - - if ( transmissiveObjects.length > 0 ) renderTransmissionPass( opaqueObjects, transmissiveObjects, scene, camera ); - - if ( viewport ) state.viewport( _currentViewport.copy( viewport ) ); - - if ( opaqueObjects.length > 0 ) renderObjects( opaqueObjects, scene, camera ); - if ( transmissiveObjects.length > 0 ) renderObjects( transmissiveObjects, scene, camera ); - if ( transparentObjects.length > 0 ) renderObjects( transparentObjects, scene, camera ); - - // Ensure depth buffer writing is enabled so it can be cleared on next render - - state.buffers.depth.setTest( true ); - state.buffers.depth.setMask( true ); - state.buffers.color.setMask( true ); - - state.setPolygonOffset( false ); - - } - - function renderTransmissionPass( opaqueObjects, transmissiveObjects, scene, camera ) { - - const overrideMaterial = scene.isScene === true ? scene.overrideMaterial : null; - - if ( overrideMaterial !== null ) { - - return; - - } - - const isWebGL2 = capabilities.isWebGL2; - - if ( _transmissionRenderTarget === null ) { - - _transmissionRenderTarget = new WebGLRenderTarget( 1, 1, { - generateMipmaps: true, - type: extensions.has( 'EXT_color_buffer_half_float' ) ? HalfFloatType : UnsignedByteType, - minFilter: LinearMipmapLinearFilter, - samples: ( isWebGL2 ) ? 4 : 0 - } ); - - // debug - - /* - const geometry = new PlaneGeometry(); - const material = new MeshBasicMaterial( { map: _transmissionRenderTarget.texture } ); - - const mesh = new Mesh( geometry, material ); - scene.add( mesh ); - */ - - } - - _this.getDrawingBufferSize( _vector2 ); - - if ( isWebGL2 ) { - - _transmissionRenderTarget.setSize( _vector2.x, _vector2.y ); - - } else { - - _transmissionRenderTarget.setSize( floorPowerOfTwo( _vector2.x ), floorPowerOfTwo( _vector2.y ) ); - - } - - // - - const currentRenderTarget = _this.getRenderTarget(); - _this.setRenderTarget( _transmissionRenderTarget ); - - _this.getClearColor( _currentClearColor ); - _currentClearAlpha = _this.getClearAlpha(); - if ( _currentClearAlpha < 1 ) _this.setClearColor( 0xffffff, 0.5 ); - - _this.clear(); - - // Turn off the features which can affect the frag color for opaque objects pass. - // Otherwise they are applied twice in opaque objects pass and transmission objects pass. - const currentToneMapping = _this.toneMapping; - _this.toneMapping = NoToneMapping; - - renderObjects( opaqueObjects, scene, camera ); - - textures.updateMultisampleRenderTarget( _transmissionRenderTarget ); - textures.updateRenderTargetMipmap( _transmissionRenderTarget ); - - let renderTargetNeedsUpdate = false; - - for ( let i = 0, l = transmissiveObjects.length; i < l; i ++ ) { - - const renderItem = transmissiveObjects[ i ]; - - const object = renderItem.object; - const geometry = renderItem.geometry; - const material = renderItem.material; - const group = renderItem.group; - - if ( material.side === DoubleSide && object.layers.test( camera.layers ) ) { - - const currentSide = material.side; - - material.side = BackSide; - material.needsUpdate = true; - - renderObject( object, scene, camera, geometry, material, group ); - - material.side = currentSide; - material.needsUpdate = true; - - renderTargetNeedsUpdate = true; - - } - - } - - if ( renderTargetNeedsUpdate === true ) { - - textures.updateMultisampleRenderTarget( _transmissionRenderTarget ); - textures.updateRenderTargetMipmap( _transmissionRenderTarget ); - - } - - _this.setRenderTarget( currentRenderTarget ); - - _this.setClearColor( _currentClearColor, _currentClearAlpha ); - - _this.toneMapping = currentToneMapping; - - } - - function renderObjects( renderList, scene, camera ) { - - const overrideMaterial = scene.isScene === true ? scene.overrideMaterial : null; - - for ( let i = 0, l = renderList.length; i < l; i ++ ) { - - const renderItem = renderList[ i ]; - - const object = renderItem.object; - const geometry = renderItem.geometry; - const material = overrideMaterial === null ? renderItem.material : overrideMaterial; - const group = renderItem.group; - - if ( object.layers.test( camera.layers ) ) { - - renderObject( object, scene, camera, geometry, material, group ); - - } - - } - - } - - function renderObject( object, scene, camera, geometry, material, group ) { - - object.onBeforeRender( _this, scene, camera, geometry, material, group ); - - object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); - object.normalMatrix.getNormalMatrix( object.modelViewMatrix ); - - material.onBeforeRender( _this, scene, camera, geometry, object, group ); - - if ( material.transparent === true && material.side === DoubleSide && material.forceSinglePass === false ) { - - material.side = BackSide; - material.needsUpdate = true; - _this.renderBufferDirect( camera, scene, geometry, material, object, group ); - - material.side = FrontSide; - material.needsUpdate = true; - _this.renderBufferDirect( camera, scene, geometry, material, object, group ); - - material.side = DoubleSide; - - } else { - - _this.renderBufferDirect( camera, scene, geometry, material, object, group ); - - } - - object.onAfterRender( _this, scene, camera, geometry, material, group ); - - } - - function getProgram( material, scene, object ) { - - if ( scene.isScene !== true ) scene = _emptyScene; // scene could be a Mesh, Line, Points, ... - - const materialProperties = properties.get( material ); - - const lights = currentRenderState.state.lights; - const shadowsArray = currentRenderState.state.shadowsArray; - - const lightsStateVersion = lights.state.version; - - const parameters = programCache.getParameters( material, lights.state, shadowsArray, scene, object ); - const programCacheKey = programCache.getProgramCacheKey( parameters ); - - let programs = materialProperties.programs; - - // always update environment and fog - changing these trigger an getProgram call, but it's possible that the program doesn't change - - materialProperties.environment = material.isMeshStandardMaterial ? scene.environment : null; - materialProperties.fog = scene.fog; - materialProperties.envMap = ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get( material.envMap || materialProperties.environment ); - - if ( programs === undefined ) { - - // new material - - material.addEventListener( 'dispose', onMaterialDispose ); - - programs = new Map(); - materialProperties.programs = programs; - - } - - let program = programs.get( programCacheKey ); - - if ( program !== undefined ) { - - // early out if program and light state is identical - - if ( materialProperties.currentProgram === program && materialProperties.lightsStateVersion === lightsStateVersion ) { - - updateCommonMaterialProperties( material, parameters ); - - return program; - - } - - } else { - - parameters.uniforms = programCache.getUniforms( material ); - - material.onBuild( object, parameters, _this ); - - material.onBeforeCompile( parameters, _this ); - - program = programCache.acquireProgram( parameters, programCacheKey ); - programs.set( programCacheKey, program ); - - materialProperties.uniforms = parameters.uniforms; - - } - - const uniforms = materialProperties.uniforms; - - if ( ( ! material.isShaderMaterial && ! material.isRawShaderMaterial ) || material.clipping === true ) { - - uniforms.clippingPlanes = clipping.uniform; - - } - - updateCommonMaterialProperties( material, parameters ); - - // store the light setup it was created for - - materialProperties.needsLights = materialNeedsLights( material ); - materialProperties.lightsStateVersion = lightsStateVersion; - - if ( materialProperties.needsLights ) { - - // wire up the material to this renderer's lighting state - - uniforms.ambientLightColor.value = lights.state.ambient; - uniforms.lightProbe.value = lights.state.probe; - uniforms.directionalLights.value = lights.state.directional; - uniforms.directionalLightShadows.value = lights.state.directionalShadow; - uniforms.spotLights.value = lights.state.spot; - uniforms.spotLightShadows.value = lights.state.spotShadow; - uniforms.rectAreaLights.value = lights.state.rectArea; - uniforms.ltc_1.value = lights.state.rectAreaLTC1; - uniforms.ltc_2.value = lights.state.rectAreaLTC2; - uniforms.pointLights.value = lights.state.point; - uniforms.pointLightShadows.value = lights.state.pointShadow; - uniforms.hemisphereLights.value = lights.state.hemi; - - uniforms.directionalShadowMap.value = lights.state.directionalShadowMap; - uniforms.directionalShadowMatrix.value = lights.state.directionalShadowMatrix; - uniforms.spotShadowMap.value = lights.state.spotShadowMap; - uniforms.spotLightMatrix.value = lights.state.spotLightMatrix; - uniforms.spotLightMap.value = lights.state.spotLightMap; - uniforms.pointShadowMap.value = lights.state.pointShadowMap; - uniforms.pointShadowMatrix.value = lights.state.pointShadowMatrix; - // TODO (abelnation): add area lights shadow info to uniforms - - } - - materialProperties.currentProgram = program; - materialProperties.uniformsList = null; - - return program; - - } - - function getUniformList( materialProperties ) { - - if ( materialProperties.uniformsList === null ) { - - const progUniforms = materialProperties.currentProgram.getUniforms(); - materialProperties.uniformsList = WebGLUniforms.seqWithValue( progUniforms.seq, materialProperties.uniforms ); - - } - - return materialProperties.uniformsList; - - } - - function updateCommonMaterialProperties( material, parameters ) { - - const materialProperties = properties.get( material ); - - materialProperties.outputColorSpace = parameters.outputColorSpace; - materialProperties.batching = parameters.batching; - materialProperties.instancing = parameters.instancing; - materialProperties.instancingColor = parameters.instancingColor; - materialProperties.skinning = parameters.skinning; - materialProperties.morphTargets = parameters.morphTargets; - materialProperties.morphNormals = parameters.morphNormals; - materialProperties.morphColors = parameters.morphColors; - materialProperties.morphTargetsCount = parameters.morphTargetsCount; - materialProperties.numClippingPlanes = parameters.numClippingPlanes; - materialProperties.numIntersection = parameters.numClipIntersection; - materialProperties.vertexAlphas = parameters.vertexAlphas; - materialProperties.vertexTangents = parameters.vertexTangents; - materialProperties.toneMapping = parameters.toneMapping; - - } - - function setProgram( camera, scene, geometry, material, object ) { - - if ( scene.isScene !== true ) scene = _emptyScene; // scene could be a Mesh, Line, Points, ... - - textures.resetTextureUnits(); - - const fog = scene.fog; - const environment = material.isMeshStandardMaterial ? scene.environment : null; - const colorSpace = ( _currentRenderTarget === null ) ? _this.outputColorSpace : ( _currentRenderTarget.isXRRenderTarget === true ? _currentRenderTarget.texture.colorSpace : LinearSRGBColorSpace ); - const envMap = ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get( material.envMap || environment ); - const vertexAlphas = material.vertexColors === true && !! geometry.attributes.color && geometry.attributes.color.itemSize === 4; - const vertexTangents = !! geometry.attributes.tangent && ( !! material.normalMap || material.anisotropy > 0 ); - const morphTargets = !! geometry.morphAttributes.position; - const morphNormals = !! geometry.morphAttributes.normal; - const morphColors = !! geometry.morphAttributes.color; - - let toneMapping = NoToneMapping; - - if ( material.toneMapped ) { - - if ( _currentRenderTarget === null || _currentRenderTarget.isXRRenderTarget === true ) { - - toneMapping = _this.toneMapping; - - } - - } - - const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color; - const morphTargetsCount = ( morphAttribute !== undefined ) ? morphAttribute.length : 0; - - const materialProperties = properties.get( material ); - const lights = currentRenderState.state.lights; - - if ( _clippingEnabled === true ) { - - if ( _localClippingEnabled === true || camera !== _currentCamera ) { - - const useCache = - camera === _currentCamera && - material.id === _currentMaterialId; - - // we might want to call this function with some ClippingGroup - // object instead of the material, once it becomes feasible - // (#8465, #8379) - clipping.setState( material, camera, useCache ); - - } - - } - - // - - let needsProgramChange = false; - - if ( material.version === materialProperties.__version ) { - - if ( materialProperties.needsLights && ( materialProperties.lightsStateVersion !== lights.state.version ) ) { - - needsProgramChange = true; - - } else if ( materialProperties.outputColorSpace !== colorSpace ) { - - needsProgramChange = true; - - } else if ( object.isBatchedMesh && materialProperties.batching === false ) { - - needsProgramChange = true; - - } else if ( ! object.isBatchedMesh && materialProperties.batching === true ) { - - needsProgramChange = true; - - } else if ( object.isInstancedMesh && materialProperties.instancing === false ) { - - needsProgramChange = true; - - } else if ( ! object.isInstancedMesh && materialProperties.instancing === true ) { - - needsProgramChange = true; - - } else if ( object.isSkinnedMesh && materialProperties.skinning === false ) { - - needsProgramChange = true; - - } else if ( ! object.isSkinnedMesh && materialProperties.skinning === true ) { - - needsProgramChange = true; - - } else if ( object.isInstancedMesh && materialProperties.instancingColor === true && object.instanceColor === null ) { - - needsProgramChange = true; - - } else if ( object.isInstancedMesh && materialProperties.instancingColor === false && object.instanceColor !== null ) { - - needsProgramChange = true; - - } else if ( materialProperties.envMap !== envMap ) { - - needsProgramChange = true; - - } else if ( material.fog === true && materialProperties.fog !== fog ) { - - needsProgramChange = true; - - } else if ( materialProperties.numClippingPlanes !== undefined && - ( materialProperties.numClippingPlanes !== clipping.numPlanes || - materialProperties.numIntersection !== clipping.numIntersection ) ) { - - needsProgramChange = true; - - } else if ( materialProperties.vertexAlphas !== vertexAlphas ) { - - needsProgramChange = true; - - } else if ( materialProperties.vertexTangents !== vertexTangents ) { - - needsProgramChange = true; - - } else if ( materialProperties.morphTargets !== morphTargets ) { - - needsProgramChange = true; - - } else if ( materialProperties.morphNormals !== morphNormals ) { - - needsProgramChange = true; - - } else if ( materialProperties.morphColors !== morphColors ) { - - needsProgramChange = true; - - } else if ( materialProperties.toneMapping !== toneMapping ) { - - needsProgramChange = true; - - } else if ( capabilities.isWebGL2 === true && materialProperties.morphTargetsCount !== morphTargetsCount ) { - - needsProgramChange = true; - - } - - } else { - - needsProgramChange = true; - materialProperties.__version = material.version; - - } - - // - - let program = materialProperties.currentProgram; - - if ( needsProgramChange === true ) { - - program = getProgram( material, scene, object ); - - } - - let refreshProgram = false; - let refreshMaterial = false; - let refreshLights = false; - - const p_uniforms = program.getUniforms(), - m_uniforms = materialProperties.uniforms; - - if ( state.useProgram( program.program ) ) { - - refreshProgram = true; - refreshMaterial = true; - refreshLights = true; - - } - - if ( material.id !== _currentMaterialId ) { - - _currentMaterialId = material.id; - - refreshMaterial = true; - - } - - if ( refreshProgram || _currentCamera !== camera ) { - - // common camera uniforms - - p_uniforms.setValue( _gl, 'projectionMatrix', camera.projectionMatrix ); - p_uniforms.setValue( _gl, 'viewMatrix', camera.matrixWorldInverse ); - - const uCamPos = p_uniforms.map.cameraPosition; - - if ( uCamPos !== undefined ) { - - uCamPos.setValue( _gl, _vector3.setFromMatrixPosition( camera.matrixWorld ) ); - - } - - if ( capabilities.logarithmicDepthBuffer ) { - - p_uniforms.setValue( _gl, 'logDepthBufFC', - 2.0 / ( Math.log( camera.far + 1.0 ) / Math.LN2 ) ); - - } - - // consider moving isOrthographic to UniformLib and WebGLMaterials, see https://github.com/mrdoob/three.js/pull/26467#issuecomment-1645185067 - - if ( material.isMeshPhongMaterial || - material.isMeshToonMaterial || - material.isMeshLambertMaterial || - material.isMeshBasicMaterial || - material.isMeshStandardMaterial || - material.isShaderMaterial ) { - - p_uniforms.setValue( _gl, 'isOrthographic', camera.isOrthographicCamera === true ); - - } - - if ( _currentCamera !== camera ) { - - _currentCamera = camera; - - // lighting uniforms depend on the camera so enforce an update - // now, in case this material supports lights - or later, when - // the next material that does gets activated: - - refreshMaterial = true; // set to true on material change - refreshLights = true; // remains set until update done - - } - - } - - // skinning and morph target uniforms must be set even if material didn't change - // auto-setting of texture unit for bone and morph texture must go before other textures - // otherwise textures used for skinning and morphing can take over texture units reserved for other material textures - - if ( object.isSkinnedMesh ) { - - p_uniforms.setOptional( _gl, object, 'bindMatrix' ); - p_uniforms.setOptional( _gl, object, 'bindMatrixInverse' ); - - const skeleton = object.skeleton; - - if ( skeleton ) { - - if ( capabilities.floatVertexTextures ) { - - if ( skeleton.boneTexture === null ) skeleton.computeBoneTexture(); - - p_uniforms.setValue( _gl, 'boneTexture', skeleton.boneTexture, textures ); - - } else { - - console.warn( 'THREE.WebGLRenderer: SkinnedMesh can only be used with WebGL 2. With WebGL 1 OES_texture_float and vertex textures support is required.' ); - - } - - } - - } - - if ( object.isBatchedMesh ) { - - p_uniforms.setOptional( _gl, object, 'batchingTexture' ); - p_uniforms.setValue( _gl, 'batchingTexture', object._matricesTexture, textures ); - - } - - const morphAttributes = geometry.morphAttributes; - - if ( morphAttributes.position !== undefined || morphAttributes.normal !== undefined || ( morphAttributes.color !== undefined && capabilities.isWebGL2 === true ) ) { - - morphtargets.update( object, geometry, program ); - - } - - if ( refreshMaterial || materialProperties.receiveShadow !== object.receiveShadow ) { - - materialProperties.receiveShadow = object.receiveShadow; - p_uniforms.setValue( _gl, 'receiveShadow', object.receiveShadow ); - - } - - // https://github.com/mrdoob/three.js/pull/24467#issuecomment-1209031512 - - if ( material.isMeshGouraudMaterial && material.envMap !== null ) { - - m_uniforms.envMap.value = envMap; - - m_uniforms.flipEnvMap.value = ( envMap.isCubeTexture && envMap.isRenderTargetTexture === false ) ? - 1 : 1; - - } - - if ( refreshMaterial ) { - - p_uniforms.setValue( _gl, 'toneMappingExposure', _this.toneMappingExposure ); - - if ( materialProperties.needsLights ) { - - // the current material requires lighting info - - // note: all lighting uniforms are always set correctly - // they simply reference the renderer's state for their - // values - // - // use the current material's .needsUpdate flags to set - // the GL state when required - - markUniformsLightsNeedsUpdate( m_uniforms, refreshLights ); - - } - - // refresh uniforms common to several materials - - if ( fog && material.fog === true ) { - - materials.refreshFogUniforms( m_uniforms, fog ); - - } - - materials.refreshMaterialUniforms( m_uniforms, material, _pixelRatio, _height, _transmissionRenderTarget ); - - WebGLUniforms.upload( _gl, getUniformList( materialProperties ), m_uniforms, textures ); - - } - - if ( material.isShaderMaterial && material.uniformsNeedUpdate === true ) { - - WebGLUniforms.upload( _gl, getUniformList( materialProperties ), m_uniforms, textures ); - material.uniformsNeedUpdate = false; - - } - - if ( material.isSpriteMaterial ) { - - p_uniforms.setValue( _gl, 'center', object.center ); - - } - - // common matrices - - p_uniforms.setValue( _gl, 'modelViewMatrix', object.modelViewMatrix ); - p_uniforms.setValue( _gl, 'normalMatrix', object.normalMatrix ); - p_uniforms.setValue( _gl, 'modelMatrix', object.matrixWorld ); - - // UBOs - - if ( material.isShaderMaterial || material.isRawShaderMaterial ) { - - const groups = material.uniformsGroups; - - for ( let i = 0, l = groups.length; i < l; i ++ ) { - - if ( capabilities.isWebGL2 ) { - - const group = groups[ i ]; - - uniformsGroups.update( group, program ); - uniformsGroups.bind( group, program ); - - } else { - - console.warn( 'THREE.WebGLRenderer: Uniform Buffer Objects can only be used with WebGL 2.' ); - - } - - } - - } - - return program; - - } - - // If uniforms are marked as clean, they don't need to be loaded to the GPU. - - function markUniformsLightsNeedsUpdate( uniforms, value ) { - - uniforms.ambientLightColor.needsUpdate = value; - uniforms.lightProbe.needsUpdate = value; - - uniforms.directionalLights.needsUpdate = value; - uniforms.directionalLightShadows.needsUpdate = value; - uniforms.pointLights.needsUpdate = value; - uniforms.pointLightShadows.needsUpdate = value; - uniforms.spotLights.needsUpdate = value; - uniforms.spotLightShadows.needsUpdate = value; - uniforms.rectAreaLights.needsUpdate = value; - uniforms.hemisphereLights.needsUpdate = value; - - } - - function materialNeedsLights( material ) { - - return material.isMeshLambertMaterial || material.isMeshToonMaterial || material.isMeshPhongMaterial || - material.isMeshStandardMaterial || material.isShadowMaterial || - ( material.isShaderMaterial && material.lights === true ); - - } - - this.getActiveCubeFace = function () { - - return _currentActiveCubeFace; - - }; - - this.getActiveMipmapLevel = function () { - - return _currentActiveMipmapLevel; - - }; - - this.getRenderTarget = function () { - - return _currentRenderTarget; - - }; - - this.setRenderTargetTextures = function ( renderTarget, colorTexture, depthTexture ) { - - properties.get( renderTarget.texture ).__webglTexture = colorTexture; - properties.get( renderTarget.depthTexture ).__webglTexture = depthTexture; - - const renderTargetProperties = properties.get( renderTarget ); - renderTargetProperties.__hasExternalTextures = true; - - if ( renderTargetProperties.__hasExternalTextures ) { - - renderTargetProperties.__autoAllocateDepthBuffer = depthTexture === undefined; - - if ( ! renderTargetProperties.__autoAllocateDepthBuffer ) { - - // The multisample_render_to_texture extension doesn't work properly if there - // are midframe flushes and an external depth buffer. Disable use of the extension. - if ( extensions.has( 'WEBGL_multisampled_render_to_texture' ) === true ) { - - console.warn( 'THREE.WebGLRenderer: Render-to-texture extension was disabled because an external texture was provided' ); - renderTargetProperties.__useRenderToTexture = false; - - } - - } - - } - - }; - - this.setRenderTargetFramebuffer = function ( renderTarget, defaultFramebuffer ) { - - const renderTargetProperties = properties.get( renderTarget ); - renderTargetProperties.__webglFramebuffer = defaultFramebuffer; - renderTargetProperties.__useDefaultFramebuffer = defaultFramebuffer === undefined; - - }; - - this.setRenderTarget = function ( renderTarget, activeCubeFace = 0, activeMipmapLevel = 0 ) { - - _currentRenderTarget = renderTarget; - _currentActiveCubeFace = activeCubeFace; - _currentActiveMipmapLevel = activeMipmapLevel; - - let useDefaultFramebuffer = true; - let framebuffer = null; - let isCube = false; - let isRenderTarget3D = false; - - if ( renderTarget ) { - - const renderTargetProperties = properties.get( renderTarget ); - - if ( renderTargetProperties.__useDefaultFramebuffer !== undefined ) { - - // We need to make sure to rebind the framebuffer. - state.bindFramebuffer( _gl.FRAMEBUFFER, null ); - useDefaultFramebuffer = false; - - } else if ( renderTargetProperties.__webglFramebuffer === undefined ) { - - textures.setupRenderTarget( renderTarget ); - - } else if ( renderTargetProperties.__hasExternalTextures ) { - - // Color and depth texture must be rebound in order for the swapchain to update. - textures.rebindTextures( renderTarget, properties.get( renderTarget.texture ).__webglTexture, properties.get( renderTarget.depthTexture ).__webglTexture ); - - } - - const texture = renderTarget.texture; - - if ( texture.isData3DTexture || texture.isDataArrayTexture || texture.isCompressedArrayTexture ) { - - isRenderTarget3D = true; - - } - - const __webglFramebuffer = properties.get( renderTarget ).__webglFramebuffer; - - if ( renderTarget.isWebGLCubeRenderTarget ) { - - if ( Array.isArray( __webglFramebuffer[ activeCubeFace ] ) ) { - - framebuffer = __webglFramebuffer[ activeCubeFace ][ activeMipmapLevel ]; - - } else { - - framebuffer = __webglFramebuffer[ activeCubeFace ]; - - } - - isCube = true; - - } else if ( ( capabilities.isWebGL2 && renderTarget.samples > 0 ) && textures.useMultisampledRTT( renderTarget ) === false ) { - - framebuffer = properties.get( renderTarget ).__webglMultisampledFramebuffer; - - } else { - - if ( Array.isArray( __webglFramebuffer ) ) { - - framebuffer = __webglFramebuffer[ activeMipmapLevel ]; - - } else { - - framebuffer = __webglFramebuffer; - - } - - } - - _currentViewport.copy( renderTarget.viewport ); - _currentScissor.copy( renderTarget.scissor ); - _currentScissorTest = renderTarget.scissorTest; - - } else { - - _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).floor(); - _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).floor(); - _currentScissorTest = _scissorTest; - - } - - const framebufferBound = state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); - - if ( framebufferBound && capabilities.drawBuffers && useDefaultFramebuffer ) { - - state.drawBuffers( renderTarget, framebuffer ); - - } - - state.viewport( _currentViewport ); - state.scissor( _currentScissor ); - state.setScissorTest( _currentScissorTest ); - - if ( isCube ) { - - const textureProperties = properties.get( renderTarget.texture ); - _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + activeCubeFace, textureProperties.__webglTexture, activeMipmapLevel ); - - } else if ( isRenderTarget3D ) { - - const textureProperties = properties.get( renderTarget.texture ); - const layer = activeCubeFace || 0; - _gl.framebufferTextureLayer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, textureProperties.__webglTexture, activeMipmapLevel || 0, layer ); - - } - - _currentMaterialId = - 1; // reset current material to ensure correct uniform bindings - - }; - - this.readRenderTargetPixels = function ( renderTarget, x, y, width, height, buffer, activeCubeFaceIndex ) { - - if ( ! ( renderTarget && renderTarget.isWebGLRenderTarget ) ) { - - console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' ); - return; - - } - - let framebuffer = properties.get( renderTarget ).__webglFramebuffer; - - if ( renderTarget.isWebGLCubeRenderTarget && activeCubeFaceIndex !== undefined ) { - - framebuffer = framebuffer[ activeCubeFaceIndex ]; - - } - - if ( framebuffer ) { - - state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); - - try { - - const texture = renderTarget.texture; - const textureFormat = texture.format; - const textureType = texture.type; - - if ( textureFormat !== RGBAFormat && utils.convert( textureFormat ) !== _gl.getParameter( _gl.IMPLEMENTATION_COLOR_READ_FORMAT ) ) { - - console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.' ); - return; - - } - - const halfFloatSupportedByExt = ( textureType === HalfFloatType ) && ( extensions.has( 'EXT_color_buffer_half_float' ) || ( capabilities.isWebGL2 && extensions.has( 'EXT_color_buffer_float' ) ) ); - - if ( textureType !== UnsignedByteType && utils.convert( textureType ) !== _gl.getParameter( _gl.IMPLEMENTATION_COLOR_READ_TYPE ) && // Edge and Chrome Mac < 52 (#9513) - ! ( textureType === FloatType && ( capabilities.isWebGL2 || extensions.has( 'OES_texture_float' ) || extensions.has( 'WEBGL_color_buffer_float' ) ) ) && // Chrome Mac >= 52 and Firefox - ! halfFloatSupportedByExt ) { - - console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.' ); - return; - - } - - // the following if statement ensures valid read requests (no out-of-bounds pixels, see #8604) - - if ( ( x >= 0 && x <= ( renderTarget.width - width ) ) && ( y >= 0 && y <= ( renderTarget.height - height ) ) ) { - - _gl.readPixels( x, y, width, height, utils.convert( textureFormat ), utils.convert( textureType ), buffer ); - - } - - } finally { - - // restore framebuffer of current render target if necessary - - const framebuffer = ( _currentRenderTarget !== null ) ? properties.get( _currentRenderTarget ).__webglFramebuffer : null; - state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); - - } - - } - - }; - - this.copyFramebufferToTexture = function ( position, texture, level = 0 ) { - - const levelScale = Math.pow( 2, - level ); - const width = Math.floor( texture.image.width * levelScale ); - const height = Math.floor( texture.image.height * levelScale ); - - textures.setTexture2D( texture, 0 ); - - _gl.copyTexSubImage2D( _gl.TEXTURE_2D, level, 0, 0, position.x, position.y, width, height ); - - state.unbindTexture(); - - }; - - this.copyTextureToTexture = function ( position, srcTexture, dstTexture, level = 0 ) { - - const width = srcTexture.image.width; - const height = srcTexture.image.height; - const glFormat = utils.convert( dstTexture.format ); - const glType = utils.convert( dstTexture.type ); - - textures.setTexture2D( dstTexture, 0 ); - - // As another texture upload may have changed pixelStorei - // parameters, make sure they are correct for the dstTexture - _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, dstTexture.flipY ); - _gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, dstTexture.premultiplyAlpha ); - _gl.pixelStorei( _gl.UNPACK_ALIGNMENT, dstTexture.unpackAlignment ); - - if ( srcTexture.isDataTexture ) { - - _gl.texSubImage2D( _gl.TEXTURE_2D, level, position.x, position.y, width, height, glFormat, glType, srcTexture.image.data ); - - } else { - - if ( srcTexture.isCompressedTexture ) { - - _gl.compressedTexSubImage2D( _gl.TEXTURE_2D, level, position.x, position.y, srcTexture.mipmaps[ 0 ].width, srcTexture.mipmaps[ 0 ].height, glFormat, srcTexture.mipmaps[ 0 ].data ); - - } else { - - _gl.texSubImage2D( _gl.TEXTURE_2D, level, position.x, position.y, glFormat, glType, srcTexture.image ); - - } - - } - - // Generate mipmaps only when copying level 0 - if ( level === 0 && dstTexture.generateMipmaps ) _gl.generateMipmap( _gl.TEXTURE_2D ); - - state.unbindTexture(); - - }; - - this.copyTextureToTexture3D = function ( sourceBox, position, srcTexture, dstTexture, level = 0 ) { - - if ( _this.isWebGL1Renderer ) { - - console.warn( 'THREE.WebGLRenderer.copyTextureToTexture3D: can only be used with WebGL2.' ); - return; - - } - - const width = sourceBox.max.x - sourceBox.min.x + 1; - const height = sourceBox.max.y - sourceBox.min.y + 1; - const depth = sourceBox.max.z - sourceBox.min.z + 1; - const glFormat = utils.convert( dstTexture.format ); - const glType = utils.convert( dstTexture.type ); - let glTarget; - - if ( dstTexture.isData3DTexture ) { - - textures.setTexture3D( dstTexture, 0 ); - glTarget = _gl.TEXTURE_3D; - - } else if ( dstTexture.isDataArrayTexture || dstTexture.isCompressedArrayTexture ) { - - textures.setTexture2DArray( dstTexture, 0 ); - glTarget = _gl.TEXTURE_2D_ARRAY; - - } else { - - console.warn( 'THREE.WebGLRenderer.copyTextureToTexture3D: only supports THREE.DataTexture3D and THREE.DataTexture2DArray.' ); - return; - - } - - _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, dstTexture.flipY ); - _gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, dstTexture.premultiplyAlpha ); - _gl.pixelStorei( _gl.UNPACK_ALIGNMENT, dstTexture.unpackAlignment ); - - const unpackRowLen = _gl.getParameter( _gl.UNPACK_ROW_LENGTH ); - const unpackImageHeight = _gl.getParameter( _gl.UNPACK_IMAGE_HEIGHT ); - const unpackSkipPixels = _gl.getParameter( _gl.UNPACK_SKIP_PIXELS ); - const unpackSkipRows = _gl.getParameter( _gl.UNPACK_SKIP_ROWS ); - const unpackSkipImages = _gl.getParameter( _gl.UNPACK_SKIP_IMAGES ); - - const image = srcTexture.isCompressedTexture ? srcTexture.mipmaps[ level ] : srcTexture.image; - - _gl.pixelStorei( _gl.UNPACK_ROW_LENGTH, image.width ); - _gl.pixelStorei( _gl.UNPACK_IMAGE_HEIGHT, image.height ); - _gl.pixelStorei( _gl.UNPACK_SKIP_PIXELS, sourceBox.min.x ); - _gl.pixelStorei( _gl.UNPACK_SKIP_ROWS, sourceBox.min.y ); - _gl.pixelStorei( _gl.UNPACK_SKIP_IMAGES, sourceBox.min.z ); - - if ( srcTexture.isDataTexture || srcTexture.isData3DTexture ) { - - _gl.texSubImage3D( glTarget, level, position.x, position.y, position.z, width, height, depth, glFormat, glType, image.data ); - - } else { - - if ( srcTexture.isCompressedArrayTexture ) { - - console.warn( 'THREE.WebGLRenderer.copyTextureToTexture3D: untested support for compressed srcTexture.' ); - _gl.compressedTexSubImage3D( glTarget, level, position.x, position.y, position.z, width, height, depth, glFormat, image.data ); - - } else { - - _gl.texSubImage3D( glTarget, level, position.x, position.y, position.z, width, height, depth, glFormat, glType, image ); - - } - - } - - _gl.pixelStorei( _gl.UNPACK_ROW_LENGTH, unpackRowLen ); - _gl.pixelStorei( _gl.UNPACK_IMAGE_HEIGHT, unpackImageHeight ); - _gl.pixelStorei( _gl.UNPACK_SKIP_PIXELS, unpackSkipPixels ); - _gl.pixelStorei( _gl.UNPACK_SKIP_ROWS, unpackSkipRows ); - _gl.pixelStorei( _gl.UNPACK_SKIP_IMAGES, unpackSkipImages ); - - // Generate mipmaps only when copying level 0 - if ( level === 0 && dstTexture.generateMipmaps ) _gl.generateMipmap( glTarget ); - - state.unbindTexture(); - - }; - - this.initTexture = function ( texture ) { - - if ( texture.isCubeTexture ) { - - textures.setTextureCube( texture, 0 ); - - } else if ( texture.isData3DTexture ) { - - textures.setTexture3D( texture, 0 ); - - } else if ( texture.isDataArrayTexture || texture.isCompressedArrayTexture ) { - - textures.setTexture2DArray( texture, 0 ); - - } else { - - textures.setTexture2D( texture, 0 ); - - } - - state.unbindTexture(); - - }; - - this.resetState = function () { - - _currentActiveCubeFace = 0; - _currentActiveMipmapLevel = 0; - _currentRenderTarget = null; - - state.reset(); - bindingStates.reset(); - - }; - - if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) { - - __THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'observe', { detail: this } ) ); - - } - - } - - get coordinateSystem() { - - return WebGLCoordinateSystem; - - } - - get outputColorSpace() { - - return this._outputColorSpace; - - } - - set outputColorSpace( colorSpace ) { - - this._outputColorSpace = colorSpace; - - const gl = this.getContext(); - gl.drawingBufferColorSpace = colorSpace === DisplayP3ColorSpace ? 'display-p3' : 'srgb'; - gl.unpackColorSpace = ColorManagement.workingColorSpace === LinearDisplayP3ColorSpace ? 'display-p3' : 'srgb'; - - } - - get useLegacyLights() { // @deprecated, r155 - - console.warn( 'THREE.WebGLRenderer: The property .useLegacyLights has been deprecated. Migrate your lighting according to the following guide: https://discourse.threejs.org/t/updates-to-lighting-in-three-js-r155/53733.' ); - return this._useLegacyLights; - - } - - set useLegacyLights( value ) { // @deprecated, r155 - - console.warn( 'THREE.WebGLRenderer: The property .useLegacyLights has been deprecated. Migrate your lighting according to the following guide: https://discourse.threejs.org/t/updates-to-lighting-in-three-js-r155/53733.' ); - this._useLegacyLights = value; - - } - -} - -class WebGL1Renderer extends WebGLRenderer {} - -WebGL1Renderer.prototype.isWebGL1Renderer = true; - -class FogExp2 { - - constructor( color, density = 0.00025 ) { - - this.isFogExp2 = true; - - this.name = ''; - - this.color = new Color( color ); - this.density = density; - - } - - clone() { - - return new FogExp2( this.color, this.density ); - - } - - toJSON( /* meta */ ) { - - return { - type: 'FogExp2', - name: this.name, - color: this.color.getHex(), - density: this.density - }; - - } - -} - -class Fog { - - constructor( color, near = 1, far = 1000 ) { - - this.isFog = true; - - this.name = ''; - - this.color = new Color( color ); - - this.near = near; - this.far = far; - - } - - clone() { - - return new Fog( this.color, this.near, this.far ); - - } - - toJSON( /* meta */ ) { - - return { - type: 'Fog', - name: this.name, - color: this.color.getHex(), - near: this.near, - far: this.far - }; - - } - -} - -class Scene extends Object3D { - - constructor() { - - super(); - - this.isScene = true; - - this.type = 'Scene'; - - this.background = null; - this.environment = null; - this.fog = null; - - this.backgroundBlurriness = 0; - this.backgroundIntensity = 1; - - this.overrideMaterial = null; - - if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) { - - __THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'observe', { detail: this } ) ); - - } - - } - - copy( source, recursive ) { - - super.copy( source, recursive ); - - if ( source.background !== null ) this.background = source.background.clone(); - if ( source.environment !== null ) this.environment = source.environment.clone(); - if ( source.fog !== null ) this.fog = source.fog.clone(); - - this.backgroundBlurriness = source.backgroundBlurriness; - this.backgroundIntensity = source.backgroundIntensity; - - if ( source.overrideMaterial !== null ) this.overrideMaterial = source.overrideMaterial.clone(); - - this.matrixAutoUpdate = source.matrixAutoUpdate; - - return this; - - } - - toJSON( meta ) { - - const data = super.toJSON( meta ); - - if ( this.fog !== null ) data.object.fog = this.fog.toJSON(); - if ( this.backgroundBlurriness > 0 ) data.object.backgroundBlurriness = this.backgroundBlurriness; - if ( this.backgroundIntensity !== 1 ) data.object.backgroundIntensity = this.backgroundIntensity; - - return data; - - } - -} - -class InterleavedBuffer { - - constructor( array, stride ) { - - this.isInterleavedBuffer = true; - - this.array = array; - this.stride = stride; - this.count = array !== undefined ? array.length / stride : 0; - - this.usage = StaticDrawUsage; - this._updateRange = { offset: 0, count: - 1 }; - this.updateRanges = []; - - this.version = 0; - - this.uuid = generateUUID(); - - } - - onUploadCallback() {} - - set needsUpdate( value ) { - - if ( value === true ) this.version ++; - - } - - get updateRange() { - - warnOnce( 'THREE.InterleavedBuffer: updateRange() is deprecated and will be removed in r169. Use addUpdateRange() instead.' ); // @deprecated, r159 - return this._updateRange; - - } - - setUsage( value ) { - - this.usage = value; - - return this; - - } - - addUpdateRange( start, count ) { - - this.updateRanges.push( { start, count } ); - - } - - clearUpdateRanges() { - - this.updateRanges.length = 0; - - } - - copy( source ) { - - this.array = new source.array.constructor( source.array ); - this.count = source.count; - this.stride = source.stride; - this.usage = source.usage; - - return this; - - } - - copyAt( index1, attribute, index2 ) { - - index1 *= this.stride; - index2 *= attribute.stride; - - for ( let i = 0, l = this.stride; i < l; i ++ ) { - - this.array[ index1 + i ] = attribute.array[ index2 + i ]; - - } - - return this; - - } - - set( value, offset = 0 ) { - - this.array.set( value, offset ); - - return this; - - } - - clone( data ) { - - if ( data.arrayBuffers === undefined ) { - - data.arrayBuffers = {}; - - } - - if ( this.array.buffer._uuid === undefined ) { - - this.array.buffer._uuid = generateUUID(); - - } - - if ( data.arrayBuffers[ this.array.buffer._uuid ] === undefined ) { - - data.arrayBuffers[ this.array.buffer._uuid ] = this.array.slice( 0 ).buffer; - - } - - const array = new this.array.constructor( data.arrayBuffers[ this.array.buffer._uuid ] ); - - const ib = new this.constructor( array, this.stride ); - ib.setUsage( this.usage ); - - return ib; - - } - - onUpload( callback ) { - - this.onUploadCallback = callback; - - return this; - - } - - toJSON( data ) { - - if ( data.arrayBuffers === undefined ) { - - data.arrayBuffers = {}; - - } - - // generate UUID for array buffer if necessary - - if ( this.array.buffer._uuid === undefined ) { - - this.array.buffer._uuid = generateUUID(); - - } - - if ( data.arrayBuffers[ this.array.buffer._uuid ] === undefined ) { - - data.arrayBuffers[ this.array.buffer._uuid ] = Array.from( new Uint32Array( this.array.buffer ) ); - - } - - // - - return { - uuid: this.uuid, - buffer: this.array.buffer._uuid, - type: this.array.constructor.name, - stride: this.stride - }; - - } - -} - -const _vector$6 = /*@__PURE__*/ new Vector3(); - -class InterleavedBufferAttribute { - - constructor( interleavedBuffer, itemSize, offset, normalized = false ) { - - this.isInterleavedBufferAttribute = true; - - this.name = ''; - - this.data = interleavedBuffer; - this.itemSize = itemSize; - this.offset = offset; - - this.normalized = normalized; - - } - - get count() { - - return this.data.count; - - } - - get array() { - - return this.data.array; - - } - - set needsUpdate( value ) { - - this.data.needsUpdate = value; - - } - - applyMatrix4( m ) { - - for ( let i = 0, l = this.data.count; i < l; i ++ ) { - - _vector$6.fromBufferAttribute( this, i ); - - _vector$6.applyMatrix4( m ); - - this.setXYZ( i, _vector$6.x, _vector$6.y, _vector$6.z ); - - } - - return this; - - } - - applyNormalMatrix( m ) { - - for ( let i = 0, l = this.count; i < l; i ++ ) { - - _vector$6.fromBufferAttribute( this, i ); - - _vector$6.applyNormalMatrix( m ); - - this.setXYZ( i, _vector$6.x, _vector$6.y, _vector$6.z ); - - } - - return this; - - } - - transformDirection( m ) { - - for ( let i = 0, l = this.count; i < l; i ++ ) { - - _vector$6.fromBufferAttribute( this, i ); - - _vector$6.transformDirection( m ); - - this.setXYZ( i, _vector$6.x, _vector$6.y, _vector$6.z ); - - } - - return this; - - } - - getComponent( index, component ) { - - let value = this.array[ index * this.data.stride + this.offset + component ]; - - if ( this.normalized ) value = denormalize( value, this.array ); - - return value; - - } - - setComponent( index, component, value ) { - - if ( this.normalized ) value = normalize( value, this.array ); - - this.data.array[ index * this.data.stride + this.offset + component ] = value; - - return this; - - } - - setX( index, x ) { - - if ( this.normalized ) x = normalize( x, this.array ); - - this.data.array[ index * this.data.stride + this.offset ] = x; - - return this; - - } - - setY( index, y ) { - - if ( this.normalized ) y = normalize( y, this.array ); - - this.data.array[ index * this.data.stride + this.offset + 1 ] = y; - - return this; - - } - - setZ( index, z ) { - - if ( this.normalized ) z = normalize( z, this.array ); - - this.data.array[ index * this.data.stride + this.offset + 2 ] = z; - - return this; - - } - - setW( index, w ) { - - if ( this.normalized ) w = normalize( w, this.array ); - - this.data.array[ index * this.data.stride + this.offset + 3 ] = w; - - return this; - - } - - getX( index ) { - - let x = this.data.array[ index * this.data.stride + this.offset ]; - - if ( this.normalized ) x = denormalize( x, this.array ); - - return x; - - } - - getY( index ) { - - let y = this.data.array[ index * this.data.stride + this.offset + 1 ]; - - if ( this.normalized ) y = denormalize( y, this.array ); - - return y; - - } - - getZ( index ) { - - let z = this.data.array[ index * this.data.stride + this.offset + 2 ]; - - if ( this.normalized ) z = denormalize( z, this.array ); - - return z; - - } - - getW( index ) { - - let w = this.data.array[ index * this.data.stride + this.offset + 3 ]; - - if ( this.normalized ) w = denormalize( w, this.array ); - - return w; - - } - - setXY( index, x, y ) { - - index = index * this.data.stride + this.offset; - - if ( this.normalized ) { - - x = normalize( x, this.array ); - y = normalize( y, this.array ); - - } - - this.data.array[ index + 0 ] = x; - this.data.array[ index + 1 ] = y; - - return this; - - } - - setXYZ( index, x, y, z ) { - - index = index * this.data.stride + this.offset; - - if ( this.normalized ) { - - x = normalize( x, this.array ); - y = normalize( y, this.array ); - z = normalize( z, this.array ); - - } - - this.data.array[ index + 0 ] = x; - this.data.array[ index + 1 ] = y; - this.data.array[ index + 2 ] = z; - - return this; - - } - - setXYZW( index, x, y, z, w ) { - - index = index * this.data.stride + this.offset; - - if ( this.normalized ) { - - x = normalize( x, this.array ); - y = normalize( y, this.array ); - z = normalize( z, this.array ); - w = normalize( w, this.array ); - - } - - this.data.array[ index + 0 ] = x; - this.data.array[ index + 1 ] = y; - this.data.array[ index + 2 ] = z; - this.data.array[ index + 3 ] = w; - - return this; - - } - - clone( data ) { - - if ( data === undefined ) { - - console.log( 'THREE.InterleavedBufferAttribute.clone(): Cloning an interleaved buffer attribute will de-interleave buffer data.' ); - - const array = []; - - for ( let i = 0; i < this.count; i ++ ) { - - const index = i * this.data.stride + this.offset; - - for ( let j = 0; j < this.itemSize; j ++ ) { - - array.push( this.data.array[ index + j ] ); - - } - - } - - return new BufferAttribute( new this.array.constructor( array ), this.itemSize, this.normalized ); - - } else { - - if ( data.interleavedBuffers === undefined ) { - - data.interleavedBuffers = {}; - - } - - if ( data.interleavedBuffers[ this.data.uuid ] === undefined ) { - - data.interleavedBuffers[ this.data.uuid ] = this.data.clone( data ); - - } - - return new InterleavedBufferAttribute( data.interleavedBuffers[ this.data.uuid ], this.itemSize, this.offset, this.normalized ); - - } - - } - - toJSON( data ) { - - if ( data === undefined ) { - - console.log( 'THREE.InterleavedBufferAttribute.toJSON(): Serializing an interleaved buffer attribute will de-interleave buffer data.' ); - - const array = []; - - for ( let i = 0; i < this.count; i ++ ) { - - const index = i * this.data.stride + this.offset; - - for ( let j = 0; j < this.itemSize; j ++ ) { - - array.push( this.data.array[ index + j ] ); - - } - - } - - // de-interleave data and save it as an ordinary buffer attribute for now - - return { - itemSize: this.itemSize, - type: this.array.constructor.name, - array: array, - normalized: this.normalized - }; - - } else { - - // save as true interleaved attribute - - if ( data.interleavedBuffers === undefined ) { - - data.interleavedBuffers = {}; - - } - - if ( data.interleavedBuffers[ this.data.uuid ] === undefined ) { - - data.interleavedBuffers[ this.data.uuid ] = this.data.toJSON( data ); - - } - - return { - isInterleavedBufferAttribute: true, - itemSize: this.itemSize, - data: this.data.uuid, - offset: this.offset, - normalized: this.normalized - }; - - } - - } - -} - -class SpriteMaterial extends Material { - - constructor( parameters ) { - - super(); - - this.isSpriteMaterial = true; - - this.type = 'SpriteMaterial'; - - this.color = new Color( 0xffffff ); - - this.map = null; - - this.alphaMap = null; - - this.rotation = 0; - - this.sizeAttenuation = true; - - this.transparent = true; - - this.fog = true; - - this.setValues( parameters ); - - } - - copy( source ) { - - super.copy( source ); - - this.color.copy( source.color ); - - this.map = source.map; - - this.alphaMap = source.alphaMap; - - this.rotation = source.rotation; - - this.sizeAttenuation = source.sizeAttenuation; - - this.fog = source.fog; - - return this; - - } - -} - -let _geometry; - -const _intersectPoint = /*@__PURE__*/ new Vector3(); -const _worldScale = /*@__PURE__*/ new Vector3(); -const _mvPosition = /*@__PURE__*/ new Vector3(); - -const _alignedPosition = /*@__PURE__*/ new Vector2(); -const _rotatedPosition = /*@__PURE__*/ new Vector2(); -const _viewWorldMatrix = /*@__PURE__*/ new Matrix4(); - -const _vA = /*@__PURE__*/ new Vector3(); -const _vB = /*@__PURE__*/ new Vector3(); -const _vC = /*@__PURE__*/ new Vector3(); - -const _uvA = /*@__PURE__*/ new Vector2(); -const _uvB = /*@__PURE__*/ new Vector2(); -const _uvC = /*@__PURE__*/ new Vector2(); - -class Sprite extends Object3D { - - constructor( material = new SpriteMaterial() ) { - - super(); - - this.isSprite = true; - - this.type = 'Sprite'; - - if ( _geometry === undefined ) { - - _geometry = new BufferGeometry(); - - const float32Array = new Float32Array( [ - - 0.5, - 0.5, 0, 0, 0, - 0.5, - 0.5, 0, 1, 0, - 0.5, 0.5, 0, 1, 1, - - 0.5, 0.5, 0, 0, 1 - ] ); - - const interleavedBuffer = new InterleavedBuffer( float32Array, 5 ); - - _geometry.setIndex( [ 0, 1, 2, 0, 2, 3 ] ); - _geometry.setAttribute( 'position', new InterleavedBufferAttribute( interleavedBuffer, 3, 0, false ) ); - _geometry.setAttribute( 'uv', new InterleavedBufferAttribute( interleavedBuffer, 2, 3, false ) ); - - } - - this.geometry = _geometry; - this.material = material; - - this.center = new Vector2( 0.5, 0.5 ); - - } - - raycast( raycaster, intersects ) { - - if ( raycaster.camera === null ) { - - console.error( 'THREE.Sprite: "Raycaster.camera" needs to be set in order to raycast against sprites.' ); - - } - - _worldScale.setFromMatrixScale( this.matrixWorld ); - - _viewWorldMatrix.copy( raycaster.camera.matrixWorld ); - this.modelViewMatrix.multiplyMatrices( raycaster.camera.matrixWorldInverse, this.matrixWorld ); - - _mvPosition.setFromMatrixPosition( this.modelViewMatrix ); - - if ( raycaster.camera.isPerspectiveCamera && this.material.sizeAttenuation === false ) { - - _worldScale.multiplyScalar( - _mvPosition.z ); - - } - - const rotation = this.material.rotation; - let sin, cos; - - if ( rotation !== 0 ) { - - cos = Math.cos( rotation ); - sin = Math.sin( rotation ); - - } - - const center = this.center; - - transformVertex( _vA.set( - 0.5, - 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos ); - transformVertex( _vB.set( 0.5, - 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos ); - transformVertex( _vC.set( 0.5, 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos ); - - _uvA.set( 0, 0 ); - _uvB.set( 1, 0 ); - _uvC.set( 1, 1 ); - - // check first triangle - let intersect = raycaster.ray.intersectTriangle( _vA, _vB, _vC, false, _intersectPoint ); - - if ( intersect === null ) { - - // check second triangle - transformVertex( _vB.set( - 0.5, 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos ); - _uvB.set( 0, 1 ); - - intersect = raycaster.ray.intersectTriangle( _vA, _vC, _vB, false, _intersectPoint ); - if ( intersect === null ) { - - return; - - } - - } - - const distance = raycaster.ray.origin.distanceTo( _intersectPoint ); - - if ( distance < raycaster.near || distance > raycaster.far ) return; - - intersects.push( { - - distance: distance, - point: _intersectPoint.clone(), - uv: Triangle.getInterpolation( _intersectPoint, _vA, _vB, _vC, _uvA, _uvB, _uvC, new Vector2() ), - face: null, - object: this - - } ); - - } - - copy( source, recursive ) { - - super.copy( source, recursive ); - - if ( source.center !== undefined ) this.center.copy( source.center ); - - this.material = source.material; - - return this; - - } - -} - -function transformVertex( vertexPosition, mvPosition, center, scale, sin, cos ) { - - // compute position in camera space - _alignedPosition.subVectors( vertexPosition, center ).addScalar( 0.5 ).multiply( scale ); - - // to check if rotation is not zero - if ( sin !== undefined ) { - - _rotatedPosition.x = ( cos * _alignedPosition.x ) - ( sin * _alignedPosition.y ); - _rotatedPosition.y = ( sin * _alignedPosition.x ) + ( cos * _alignedPosition.y ); - - } else { - - _rotatedPosition.copy( _alignedPosition ); - - } - - - vertexPosition.copy( mvPosition ); - vertexPosition.x += _rotatedPosition.x; - vertexPosition.y += _rotatedPosition.y; - - // transform to world space - vertexPosition.applyMatrix4( _viewWorldMatrix ); - -} - -const _v1$2 = /*@__PURE__*/ new Vector3(); -const _v2$1 = /*@__PURE__*/ new Vector3(); - -class LOD extends Object3D { - - constructor() { - - super(); - - this._currentLevel = 0; - - this.type = 'LOD'; - - Object.defineProperties( this, { - levels: { - enumerable: true, - value: [] - }, - isLOD: { - value: true, - } - } ); - - this.autoUpdate = true; - - } - - copy( source ) { - - super.copy( source, false ); - - const levels = source.levels; - - for ( let i = 0, l = levels.length; i < l; i ++ ) { - - const level = levels[ i ]; - - this.addLevel( level.object.clone(), level.distance, level.hysteresis ); - - } - - this.autoUpdate = source.autoUpdate; - - return this; - - } - - addLevel( object, distance = 0, hysteresis = 0 ) { - - distance = Math.abs( distance ); - - const levels = this.levels; - - let l; - - for ( l = 0; l < levels.length; l ++ ) { - - if ( distance < levels[ l ].distance ) { - - break; - - } - - } - - levels.splice( l, 0, { distance: distance, hysteresis: hysteresis, object: object } ); - - this.add( object ); - - return this; - - } - - getCurrentLevel() { - - return this._currentLevel; - - } - - - - getObjectForDistance( distance ) { - - const levels = this.levels; - - if ( levels.length > 0 ) { - - let i, l; - - for ( i = 1, l = levels.length; i < l; i ++ ) { - - let levelDistance = levels[ i ].distance; - - if ( levels[ i ].object.visible ) { - - levelDistance -= levelDistance * levels[ i ].hysteresis; - - } - - if ( distance < levelDistance ) { - - break; - - } - - } - - return levels[ i - 1 ].object; - - } - - return null; - - } - - raycast( raycaster, intersects ) { - - const levels = this.levels; - - if ( levels.length > 0 ) { - - _v1$2.setFromMatrixPosition( this.matrixWorld ); - - const distance = raycaster.ray.origin.distanceTo( _v1$2 ); - - this.getObjectForDistance( distance ).raycast( raycaster, intersects ); - - } - - } - - update( camera ) { - - const levels = this.levels; - - if ( levels.length > 1 ) { - - _v1$2.setFromMatrixPosition( camera.matrixWorld ); - _v2$1.setFromMatrixPosition( this.matrixWorld ); - - const distance = _v1$2.distanceTo( _v2$1 ) / camera.zoom; - - levels[ 0 ].object.visible = true; - - let i, l; - - for ( i = 1, l = levels.length; i < l; i ++ ) { - - let levelDistance = levels[ i ].distance; - - if ( levels[ i ].object.visible ) { - - levelDistance -= levelDistance * levels[ i ].hysteresis; - - } - - if ( distance >= levelDistance ) { - - levels[ i - 1 ].object.visible = false; - levels[ i ].object.visible = true; - - } else { - - break; - - } - - } - - this._currentLevel = i - 1; - - for ( ; i < l; i ++ ) { - - levels[ i ].object.visible = false; - - } - - } - - } - - toJSON( meta ) { - - const data = super.toJSON( meta ); - - if ( this.autoUpdate === false ) data.object.autoUpdate = false; - - data.object.levels = []; - - const levels = this.levels; - - for ( let i = 0, l = levels.length; i < l; i ++ ) { - - const level = levels[ i ]; - - data.object.levels.push( { - object: level.object.uuid, - distance: level.distance, - hysteresis: level.hysteresis - } ); - - } - - return data; - - } - -} - -const _basePosition = /*@__PURE__*/ new Vector3(); - -const _skinIndex = /*@__PURE__*/ new Vector4(); -const _skinWeight = /*@__PURE__*/ new Vector4(); - -const _vector3 = /*@__PURE__*/ new Vector3(); -const _matrix4 = /*@__PURE__*/ new Matrix4(); -const _vertex = /*@__PURE__*/ new Vector3(); - -const _sphere$4 = /*@__PURE__*/ new Sphere(); -const _inverseMatrix$2 = /*@__PURE__*/ new Matrix4(); -const _ray$2 = /*@__PURE__*/ new Ray(); - -class SkinnedMesh extends Mesh { - - constructor( geometry, material ) { - - super( geometry, material ); - - this.isSkinnedMesh = true; - - this.type = 'SkinnedMesh'; - - this.bindMode = AttachedBindMode; - this.bindMatrix = new Matrix4(); - this.bindMatrixInverse = new Matrix4(); - - this.boundingBox = null; - this.boundingSphere = null; - - } - - computeBoundingBox() { - - const geometry = this.geometry; - - if ( this.boundingBox === null ) { - - this.boundingBox = new Box3(); - - } - - this.boundingBox.makeEmpty(); - - const positionAttribute = geometry.getAttribute( 'position' ); - - for ( let i = 0; i < positionAttribute.count; i ++ ) { - - this.getVertexPosition( i, _vertex ); - this.boundingBox.expandByPoint( _vertex ); - - } - - } - - computeBoundingSphere() { - - const geometry = this.geometry; - - if ( this.boundingSphere === null ) { - - this.boundingSphere = new Sphere(); - - } - - this.boundingSphere.makeEmpty(); - - const positionAttribute = geometry.getAttribute( 'position' ); - - for ( let i = 0; i < positionAttribute.count; i ++ ) { - - this.getVertexPosition( i, _vertex ); - this.boundingSphere.expandByPoint( _vertex ); - - } - - } - - copy( source, recursive ) { - - super.copy( source, recursive ); - - this.bindMode = source.bindMode; - this.bindMatrix.copy( source.bindMatrix ); - this.bindMatrixInverse.copy( source.bindMatrixInverse ); - - this.skeleton = source.skeleton; - - if ( source.boundingBox !== null ) this.boundingBox = source.boundingBox.clone(); - if ( source.boundingSphere !== null ) this.boundingSphere = source.boundingSphere.clone(); - - return this; - - } - - raycast( raycaster, intersects ) { - - const material = this.material; - const matrixWorld = this.matrixWorld; - - if ( material === undefined ) return; - - // test with bounding sphere in world space - - if ( this.boundingSphere === null ) this.computeBoundingSphere(); - - _sphere$4.copy( this.boundingSphere ); - _sphere$4.applyMatrix4( matrixWorld ); - - if ( raycaster.ray.intersectsSphere( _sphere$4 ) === false ) return; - - // convert ray to local space of skinned mesh - - _inverseMatrix$2.copy( matrixWorld ).invert(); - _ray$2.copy( raycaster.ray ).applyMatrix4( _inverseMatrix$2 ); - - // test with bounding box in local space - - if ( this.boundingBox !== null ) { - - if ( _ray$2.intersectsBox( this.boundingBox ) === false ) return; - - } - - // test for intersections with geometry - - this._computeIntersections( raycaster, intersects, _ray$2 ); - - } - - getVertexPosition( index, target ) { - - super.getVertexPosition( index, target ); - - this.applyBoneTransform( index, target ); - - return target; - - } - - bind( skeleton, bindMatrix ) { - - this.skeleton = skeleton; - - if ( bindMatrix === undefined ) { - - this.updateMatrixWorld( true ); - - this.skeleton.calculateInverses(); - - bindMatrix = this.matrixWorld; - - } - - this.bindMatrix.copy( bindMatrix ); - this.bindMatrixInverse.copy( bindMatrix ).invert(); - - } - - pose() { - - this.skeleton.pose(); - - } - - normalizeSkinWeights() { - - const vector = new Vector4(); - - const skinWeight = this.geometry.attributes.skinWeight; - - for ( let i = 0, l = skinWeight.count; i < l; i ++ ) { - - vector.fromBufferAttribute( skinWeight, i ); - - const scale = 1.0 / vector.manhattanLength(); - - if ( scale !== Infinity ) { - - vector.multiplyScalar( scale ); - - } else { - - vector.set( 1, 0, 0, 0 ); // do something reasonable - - } - - skinWeight.setXYZW( i, vector.x, vector.y, vector.z, vector.w ); - - } - - } - - updateMatrixWorld( force ) { - - super.updateMatrixWorld( force ); - - if ( this.bindMode === AttachedBindMode ) { - - this.bindMatrixInverse.copy( this.matrixWorld ).invert(); - - } else if ( this.bindMode === DetachedBindMode ) { - - this.bindMatrixInverse.copy( this.bindMatrix ).invert(); - - } else { - - console.warn( 'THREE.SkinnedMesh: Unrecognized bindMode: ' + this.bindMode ); - - } - - } - - applyBoneTransform( index, vector ) { - - const skeleton = this.skeleton; - const geometry = this.geometry; - - _skinIndex.fromBufferAttribute( geometry.attributes.skinIndex, index ); - _skinWeight.fromBufferAttribute( geometry.attributes.skinWeight, index ); - - _basePosition.copy( vector ).applyMatrix4( this.bindMatrix ); - - vector.set( 0, 0, 0 ); - - for ( let i = 0; i < 4; i ++ ) { - - const weight = _skinWeight.getComponent( i ); - - if ( weight !== 0 ) { - - const boneIndex = _skinIndex.getComponent( i ); - - _matrix4.multiplyMatrices( skeleton.bones[ boneIndex ].matrixWorld, skeleton.boneInverses[ boneIndex ] ); - - vector.addScaledVector( _vector3.copy( _basePosition ).applyMatrix4( _matrix4 ), weight ); - - } - - } - - return vector.applyMatrix4( this.bindMatrixInverse ); - - } - -} - -class Bone extends Object3D { - - constructor() { - - super(); - - this.isBone = true; - - this.type = 'Bone'; - - } - -} - -class DataTexture extends Texture { - - constructor( data = null, width = 1, height = 1, format, type, mapping, wrapS, wrapT, magFilter = NearestFilter, minFilter = NearestFilter, anisotropy, colorSpace ) { - - super( null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, colorSpace ); - - this.isDataTexture = true; - - this.image = { data: data, width: width, height: height }; - - this.generateMipmaps = false; - this.flipY = false; - this.unpackAlignment = 1; - - } - -} - -const _offsetMatrix = /*@__PURE__*/ new Matrix4(); -const _identityMatrix$1 = /*@__PURE__*/ new Matrix4(); - -class Skeleton { - - constructor( bones = [], boneInverses = [] ) { - - this.uuid = generateUUID(); - - this.bones = bones.slice( 0 ); - this.boneInverses = boneInverses; - this.boneMatrices = null; - - this.boneTexture = null; - - this.init(); - - } - - init() { - - const bones = this.bones; - const boneInverses = this.boneInverses; - - this.boneMatrices = new Float32Array( bones.length * 16 ); - - // calculate inverse bone matrices if necessary - - if ( boneInverses.length === 0 ) { - - this.calculateInverses(); - - } else { - - // handle special case - - if ( bones.length !== boneInverses.length ) { - - console.warn( 'THREE.Skeleton: Number of inverse bone matrices does not match amount of bones.' ); - - this.boneInverses = []; - - for ( let i = 0, il = this.bones.length; i < il; i ++ ) { - - this.boneInverses.push( new Matrix4() ); - - } - - } - - } - - } - - calculateInverses() { - - this.boneInverses.length = 0; - - for ( let i = 0, il = this.bones.length; i < il; i ++ ) { - - const inverse = new Matrix4(); - - if ( this.bones[ i ] ) { - - inverse.copy( this.bones[ i ].matrixWorld ).invert(); - - } - - this.boneInverses.push( inverse ); - - } - - } - - pose() { - - // recover the bind-time world matrices - - for ( let i = 0, il = this.bones.length; i < il; i ++ ) { - - const bone = this.bones[ i ]; - - if ( bone ) { - - bone.matrixWorld.copy( this.boneInverses[ i ] ).invert(); - - } - - } - - // compute the local matrices, positions, rotations and scales - - for ( let i = 0, il = this.bones.length; i < il; i ++ ) { - - const bone = this.bones[ i ]; - - if ( bone ) { - - if ( bone.parent && bone.parent.isBone ) { - - bone.matrix.copy( bone.parent.matrixWorld ).invert(); - bone.matrix.multiply( bone.matrixWorld ); - - } else { - - bone.matrix.copy( bone.matrixWorld ); - - } - - bone.matrix.decompose( bone.position, bone.quaternion, bone.scale ); - - } - - } - - } - - update() { - - const bones = this.bones; - const boneInverses = this.boneInverses; - const boneMatrices = this.boneMatrices; - const boneTexture = this.boneTexture; - - // flatten bone matrices to array - - for ( let i = 0, il = bones.length; i < il; i ++ ) { - - // compute the offset between the current and the original transform - - const matrix = bones[ i ] ? bones[ i ].matrixWorld : _identityMatrix$1; - - _offsetMatrix.multiplyMatrices( matrix, boneInverses[ i ] ); - _offsetMatrix.toArray( boneMatrices, i * 16 ); - - } - - if ( boneTexture !== null ) { - - boneTexture.needsUpdate = true; - - } - - } - - clone() { - - return new Skeleton( this.bones, this.boneInverses ); - - } - - computeBoneTexture() { - - // layout (1 matrix = 4 pixels) - // RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4) - // with 8x8 pixel texture max 16 bones * 4 pixels = (8 * 8) - // 16x16 pixel texture max 64 bones * 4 pixels = (16 * 16) - // 32x32 pixel texture max 256 bones * 4 pixels = (32 * 32) - // 64x64 pixel texture max 1024 bones * 4 pixels = (64 * 64) - - let size = Math.sqrt( this.bones.length * 4 ); // 4 pixels needed for 1 matrix - size = Math.ceil( size / 4 ) * 4; - size = Math.max( size, 4 ); - - const boneMatrices = new Float32Array( size * size * 4 ); // 4 floats per RGBA pixel - boneMatrices.set( this.boneMatrices ); // copy current values - - const boneTexture = new DataTexture( boneMatrices, size, size, RGBAFormat, FloatType ); - boneTexture.needsUpdate = true; - - this.boneMatrices = boneMatrices; - this.boneTexture = boneTexture; - - return this; - - } - - getBoneByName( name ) { - - for ( let i = 0, il = this.bones.length; i < il; i ++ ) { - - const bone = this.bones[ i ]; - - if ( bone.name === name ) { - - return bone; - - } - - } - - return undefined; - - } - - dispose( ) { - - if ( this.boneTexture !== null ) { - - this.boneTexture.dispose(); - - this.boneTexture = null; - - } - - } - - fromJSON( json, bones ) { - - this.uuid = json.uuid; - - for ( let i = 0, l = json.bones.length; i < l; i ++ ) { - - const uuid = json.bones[ i ]; - let bone = bones[ uuid ]; - - if ( bone === undefined ) { - - console.warn( 'THREE.Skeleton: No bone found with UUID:', uuid ); - bone = new Bone(); - - } - - this.bones.push( bone ); - this.boneInverses.push( new Matrix4().fromArray( json.boneInverses[ i ] ) ); - - } - - this.init(); - - return this; - - } - - toJSON() { - - const data = { - metadata: { - version: 4.6, - type: 'Skeleton', - generator: 'Skeleton.toJSON' - }, - bones: [], - boneInverses: [] - }; - - data.uuid = this.uuid; - - const bones = this.bones; - const boneInverses = this.boneInverses; - - for ( let i = 0, l = bones.length; i < l; i ++ ) { - - const bone = bones[ i ]; - data.bones.push( bone.uuid ); - - const boneInverse = boneInverses[ i ]; - data.boneInverses.push( boneInverse.toArray() ); - - } - - return data; - - } - -} - -class InstancedBufferAttribute extends BufferAttribute { - - constructor( array, itemSize, normalized, meshPerAttribute = 1 ) { - - super( array, itemSize, normalized ); - - this.isInstancedBufferAttribute = true; - - this.meshPerAttribute = meshPerAttribute; - - } - - copy( source ) { - - super.copy( source ); - - this.meshPerAttribute = source.meshPerAttribute; - - return this; - - } - - toJSON() { - - const data = super.toJSON(); - - data.meshPerAttribute = this.meshPerAttribute; - - data.isInstancedBufferAttribute = true; - - return data; - - } - -} - -const _instanceLocalMatrix = /*@__PURE__*/ new Matrix4(); -const _instanceWorldMatrix = /*@__PURE__*/ new Matrix4(); - -const _instanceIntersects = []; - -const _box3 = /*@__PURE__*/ new Box3(); -const _identity = /*@__PURE__*/ new Matrix4(); -const _mesh$1 = /*@__PURE__*/ new Mesh(); -const _sphere$3 = /*@__PURE__*/ new Sphere(); - -class InstancedMesh extends Mesh { - - constructor( geometry, material, count ) { - - super( geometry, material ); - - this.isInstancedMesh = true; - - this.instanceMatrix = new InstancedBufferAttribute( new Float32Array( count * 16 ), 16 ); - this.instanceColor = null; - - this.count = count; - - this.boundingBox = null; - this.boundingSphere = null; - - for ( let i = 0; i < count; i ++ ) { - - this.setMatrixAt( i, _identity ); - - } - - } - - computeBoundingBox() { - - const geometry = this.geometry; - const count = this.count; - - if ( this.boundingBox === null ) { - - this.boundingBox = new Box3(); - - } - - if ( geometry.boundingBox === null ) { - - geometry.computeBoundingBox(); - - } - - this.boundingBox.makeEmpty(); - - for ( let i = 0; i < count; i ++ ) { - - this.getMatrixAt( i, _instanceLocalMatrix ); - - _box3.copy( geometry.boundingBox ).applyMatrix4( _instanceLocalMatrix ); - - this.boundingBox.union( _box3 ); - - } - - } - - computeBoundingSphere() { - - const geometry = this.geometry; - const count = this.count; - - if ( this.boundingSphere === null ) { - - this.boundingSphere = new Sphere(); - - } - - if ( geometry.boundingSphere === null ) { - - geometry.computeBoundingSphere(); - - } - - this.boundingSphere.makeEmpty(); - - for ( let i = 0; i < count; i ++ ) { - - this.getMatrixAt( i, _instanceLocalMatrix ); - - _sphere$3.copy( geometry.boundingSphere ).applyMatrix4( _instanceLocalMatrix ); - - this.boundingSphere.union( _sphere$3 ); - - } - - } - - copy( source, recursive ) { - - super.copy( source, recursive ); - - this.instanceMatrix.copy( source.instanceMatrix ); - - if ( source.instanceColor !== null ) this.instanceColor = source.instanceColor.clone(); - - this.count = source.count; - - if ( source.boundingBox !== null ) this.boundingBox = source.boundingBox.clone(); - if ( source.boundingSphere !== null ) this.boundingSphere = source.boundingSphere.clone(); - - return this; - - } - - getColorAt( index, color ) { - - color.fromArray( this.instanceColor.array, index * 3 ); - - } - - getMatrixAt( index, matrix ) { - - matrix.fromArray( this.instanceMatrix.array, index * 16 ); - - } - - raycast( raycaster, intersects ) { - - const matrixWorld = this.matrixWorld; - const raycastTimes = this.count; - - _mesh$1.geometry = this.geometry; - _mesh$1.material = this.material; - - if ( _mesh$1.material === undefined ) return; - - // test with bounding sphere first - - if ( this.boundingSphere === null ) this.computeBoundingSphere(); - - _sphere$3.copy( this.boundingSphere ); - _sphere$3.applyMatrix4( matrixWorld ); - - if ( raycaster.ray.intersectsSphere( _sphere$3 ) === false ) return; - - // now test each instance - - for ( let instanceId = 0; instanceId < raycastTimes; instanceId ++ ) { - - // calculate the world matrix for each instance - - this.getMatrixAt( instanceId, _instanceLocalMatrix ); - - _instanceWorldMatrix.multiplyMatrices( matrixWorld, _instanceLocalMatrix ); - - // the mesh represents this single instance - - _mesh$1.matrixWorld = _instanceWorldMatrix; - - _mesh$1.raycast( raycaster, _instanceIntersects ); - - // process the result of raycast - - for ( let i = 0, l = _instanceIntersects.length; i < l; i ++ ) { - - const intersect = _instanceIntersects[ i ]; - intersect.instanceId = instanceId; - intersect.object = this; - intersects.push( intersect ); - - } - - _instanceIntersects.length = 0; - - } - - } - - setColorAt( index, color ) { - - if ( this.instanceColor === null ) { - - this.instanceColor = new InstancedBufferAttribute( new Float32Array( this.instanceMatrix.count * 3 ), 3 ); - - } - - color.toArray( this.instanceColor.array, index * 3 ); - - } - - setMatrixAt( index, matrix ) { - - matrix.toArray( this.instanceMatrix.array, index * 16 ); - - } - - updateMorphTargets() { - - } - - dispose() { - - this.dispatchEvent( { type: 'dispose' } ); - - } - -} - -function sortOpaque( a, b ) { - - return a.z - b.z; - -} - -function sortTransparent( a, b ) { - - return b.z - a.z; - -} - -class MultiDrawRenderList { - - constructor() { - - this.index = 0; - this.pool = []; - this.list = []; - - } - - push( drawRange, z ) { - - const pool = this.pool; - const list = this.list; - if ( this.index >= pool.length ) { - - pool.push( { - - start: - 1, - count: - 1, - z: - 1, - - } ); - - } - - const item = pool[ this.index ]; - list.push( item ); - this.index ++; - - item.start = drawRange.start; - item.count = drawRange.count; - item.z = z; - - } - - reset() { - - this.list.length = 0; - this.index = 0; - - } - -} - -const ID_ATTR_NAME = 'batchId'; -const _matrix = /*@__PURE__*/ new Matrix4(); -const _invMatrixWorld = /*@__PURE__*/ new Matrix4(); -const _identityMatrix = /*@__PURE__*/ new Matrix4(); -const _projScreenMatrix$2 = /*@__PURE__*/ new Matrix4(); -const _frustum = /*@__PURE__*/ new Frustum(); -const _box$1 = /*@__PURE__*/ new Box3(); -const _sphere$2 = /*@__PURE__*/ new Sphere(); -const _vector$5 = /*@__PURE__*/ new Vector3(); -const _renderList = /*@__PURE__*/ new MultiDrawRenderList(); -const _mesh = /*@__PURE__*/ new Mesh(); -const _batchIntersects = []; - -// @TODO: SkinnedMesh support? -// @TODO: geometry.groups support? -// @TODO: geometry.drawRange support? -// @TODO: geometry.morphAttributes support? -// @TODO: Support uniform parameter per geometry -// @TODO: Add an "optimize" function to pack geometry and remove data gaps - -// copies data from attribute "src" into "target" starting at "targetOffset" -function copyAttributeData( src, target, targetOffset = 0 ) { - - const itemSize = target.itemSize; - if ( src.isInterleavedBufferAttribute || src.array.constructor !== target.array.constructor ) { - - // use the component getters and setters if the array data cannot - // be copied directly - const vertexCount = src.count; - for ( let i = 0; i < vertexCount; i ++ ) { - - for ( let c = 0; c < itemSize; c ++ ) { - - target.setComponent( i + targetOffset, c, src.getComponent( i, c ) ); - - } - - } - - } else { - - // faster copy approach using typed array set function - target.array.set( src.array, targetOffset * itemSize ); - - } - - target.needsUpdate = true; - -} - -class BatchedMesh extends Mesh { - - get maxGeometryCount() { - - return this._maxGeometryCount; - - } - - constructor( maxGeometryCount, maxVertexCount, maxIndexCount = maxVertexCount * 2, material ) { - - super( new BufferGeometry(), material ); - - this.isBatchedMesh = true; - this.perObjectFrustumCulled = true; - this.sortObjects = true; - this.boundingBox = null; - this.boundingSphere = null; - this.customSort = null; - - this._drawRanges = []; - this._reservedRanges = []; - - this._visibility = []; - this._active = []; - this._bounds = []; - - this._maxGeometryCount = maxGeometryCount; - this._maxVertexCount = maxVertexCount; - this._maxIndexCount = maxIndexCount; - - this._geometryInitialized = false; - this._geometryCount = 0; - this._multiDrawCounts = new Int32Array( maxGeometryCount ); - this._multiDrawStarts = new Int32Array( maxGeometryCount ); - this._multiDrawCount = 0; - this._visibilityChanged = true; - - // Local matrix per geometry by using data texture - this._matricesTexture = null; - - this._initMatricesTexture(); - - } - - _initMatricesTexture() { - - // layout (1 matrix = 4 pixels) - // RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4) - // with 8x8 pixel texture max 16 matrices * 4 pixels = (8 * 8) - // 16x16 pixel texture max 64 matrices * 4 pixels = (16 * 16) - // 32x32 pixel texture max 256 matrices * 4 pixels = (32 * 32) - // 64x64 pixel texture max 1024 matrices * 4 pixels = (64 * 64) - - let size = Math.sqrt( this._maxGeometryCount * 4 ); // 4 pixels needed for 1 matrix - size = Math.ceil( size / 4 ) * 4; - size = Math.max( size, 4 ); - - const matricesArray = new Float32Array( size * size * 4 ); // 4 floats per RGBA pixel - const matricesTexture = new DataTexture( matricesArray, size, size, RGBAFormat, FloatType ); - - this._matricesTexture = matricesTexture; - - } - - _initializeGeometry( reference ) { - - const geometry = this.geometry; - const maxVertexCount = this._maxVertexCount; - const maxGeometryCount = this._maxGeometryCount; - const maxIndexCount = this._maxIndexCount; - if ( this._geometryInitialized === false ) { - - for ( const attributeName in reference.attributes ) { - - const srcAttribute = reference.getAttribute( attributeName ); - const { array, itemSize, normalized } = srcAttribute; - - const dstArray = new array.constructor( maxVertexCount * itemSize ); - const dstAttribute = new srcAttribute.constructor( dstArray, itemSize, normalized ); - dstAttribute.setUsage( srcAttribute.usage ); - - geometry.setAttribute( attributeName, dstAttribute ); - - } - - if ( reference.getIndex() !== null ) { - - const indexArray = maxVertexCount > 65536 - ? new Uint32Array( maxIndexCount ) - : new Uint16Array( maxIndexCount ); - - geometry.setIndex( new BufferAttribute( indexArray, 1 ) ); - - } - - const idArray = maxGeometryCount > 65536 - ? new Uint32Array( maxVertexCount ) - : new Uint16Array( maxVertexCount ); - geometry.setAttribute( ID_ATTR_NAME, new BufferAttribute( idArray, 1 ) ); - - this._geometryInitialized = true; - - } - - } - - // Make sure the geometry is compatible with the existing combined geometry atributes - _validateGeometry( geometry ) { - - // check that the geometry doesn't have a version of our reserved id attribute - if ( geometry.getAttribute( ID_ATTR_NAME ) ) { - - throw new Error( `BatchedMesh: Geometry cannot use attribute "${ ID_ATTR_NAME }"` ); - - } - - // check to ensure the geometries are using consistent attributes and indices - const batchGeometry = this.geometry; - if ( Boolean( geometry.getIndex() ) !== Boolean( batchGeometry.getIndex() ) ) { - - throw new Error( 'BatchedMesh: All geometries must consistently have "index".' ); - - } - - for ( const attributeName in batchGeometry.attributes ) { - - if ( attributeName === ID_ATTR_NAME ) { - - continue; - - } - - if ( ! geometry.hasAttribute( attributeName ) ) { - - throw new Error( `BatchedMesh: Added geometry missing "${ attributeName }". All geometries must have consistent attributes.` ); - - } - - const srcAttribute = geometry.getAttribute( attributeName ); - const dstAttribute = batchGeometry.getAttribute( attributeName ); - if ( srcAttribute.itemSize !== dstAttribute.itemSize || srcAttribute.normalized !== dstAttribute.normalized ) { - - throw new Error( 'BatchedMesh: All attributes must have a consistent itemSize and normalized value.' ); - - } - - } - - } - - setCustomSort( func ) { - - this.customSort = func; - return this; - - } - - computeBoundingBox() { - - if ( this.boundingBox === null ) { - - this.boundingBox = new Box3(); - - } - - const geometryCount = this._geometryCount; - const boundingBox = this.boundingBox; - const active = this._active; - - boundingBox.makeEmpty(); - for ( let i = 0; i < geometryCount; i ++ ) { - - if ( active[ i ] === false ) continue; - - this.getMatrixAt( i, _matrix ); - this.getBoundingBoxAt( i, _box$1 ).applyMatrix4( _matrix ); - boundingBox.union( _box$1 ); - - } - - } - - computeBoundingSphere() { - - if ( this.boundingSphere === null ) { - - this.boundingSphere = new Sphere(); - - } - - const geometryCount = this._geometryCount; - const boundingSphere = this.boundingSphere; - const active = this._active; - - boundingSphere.makeEmpty(); - for ( let i = 0; i < geometryCount; i ++ ) { - - if ( active[ i ] === false ) continue; - - this.getMatrixAt( i, _matrix ); - this.getBoundingSphereAt( i, _sphere$2 ).applyMatrix4( _matrix ); - boundingSphere.union( _sphere$2 ); - - } - - } - - addGeometry( geometry, vertexCount = - 1, indexCount = - 1 ) { - - this._initializeGeometry( geometry ); - - this._validateGeometry( geometry ); - - // ensure we're not over geometry - if ( this._geometryCount >= this._maxGeometryCount ) { - - throw new Error( 'BatchedMesh: Maximum geometry count reached.' ); - - } - - // get the necessary range fo the geometry - const reservedRange = { - vertexStart: - 1, - vertexCount: - 1, - indexStart: - 1, - indexCount: - 1, - }; - - let lastRange = null; - const reservedRanges = this._reservedRanges; - const drawRanges = this._drawRanges; - const bounds = this._bounds; - if ( this._geometryCount !== 0 ) { - - lastRange = reservedRanges[ reservedRanges.length - 1 ]; - - } - - if ( vertexCount === - 1 ) { - - reservedRange.vertexCount = geometry.getAttribute( 'position' ).count; - - } else { - - reservedRange.vertexCount = vertexCount; - - } - - if ( lastRange === null ) { - - reservedRange.vertexStart = 0; - - } else { - - reservedRange.vertexStart = lastRange.vertexStart + lastRange.vertexCount; - - } - - const index = geometry.getIndex(); - const hasIndex = index !== null; - if ( hasIndex ) { - - if ( indexCount === - 1 ) { - - reservedRange.indexCount = index.count; - - } else { - - reservedRange.indexCount = indexCount; - - } - - if ( lastRange === null ) { - - reservedRange.indexStart = 0; - - } else { - - reservedRange.indexStart = lastRange.indexStart + lastRange.indexCount; - - } - - } - - if ( - reservedRange.indexStart !== - 1 && - reservedRange.indexStart + reservedRange.indexCount > this._maxIndexCount || - reservedRange.vertexStart + reservedRange.vertexCount > this._maxVertexCount - ) { - - throw new Error( 'BatchedMesh: Reserved space request exceeds the maximum buffer size.' ); - - } - - const visibility = this._visibility; - const active = this._active; - const matricesTexture = this._matricesTexture; - const matricesArray = this._matricesTexture.image.data; - - // push new visibility states - visibility.push( true ); - active.push( true ); - - // update id - const geometryId = this._geometryCount; - this._geometryCount ++; - - // initialize matrix information - _identityMatrix.toArray( matricesArray, geometryId * 16 ); - matricesTexture.needsUpdate = true; - - // add the reserved range and draw range objects - reservedRanges.push( reservedRange ); - drawRanges.push( { - start: hasIndex ? reservedRange.indexStart : reservedRange.vertexStart, - count: - 1 - } ); - bounds.push( { - boxInitialized: false, - box: new Box3(), - - sphereInitialized: false, - sphere: new Sphere() - } ); - - // set the id for the geometry - const idAttribute = this.geometry.getAttribute( ID_ATTR_NAME ); - for ( let i = 0; i < reservedRange.vertexCount; i ++ ) { - - idAttribute.setX( reservedRange.vertexStart + i, geometryId ); - - } - - idAttribute.needsUpdate = true; - - // update the geometry - this.setGeometryAt( geometryId, geometry ); - - return geometryId; - - } - - setGeometryAt( id, geometry ) { - - if ( id >= this._geometryCount ) { - - throw new Error( 'BatchedMesh: Maximum geometry count reached.' ); - - } - - this._validateGeometry( geometry ); - - const batchGeometry = this.geometry; - const hasIndex = batchGeometry.getIndex() !== null; - const dstIndex = batchGeometry.getIndex(); - const srcIndex = geometry.getIndex(); - const reservedRange = this._reservedRanges[ id ]; - if ( - hasIndex && - srcIndex.count > reservedRange.indexCount || - geometry.attributes.position.count > reservedRange.vertexCount - ) { - - throw new Error( 'BatchedMesh: Reserved space not large enough for provided geometry.' ); - - } - - // copy geometry over - const vertexStart = reservedRange.vertexStart; - const vertexCount = reservedRange.vertexCount; - for ( const attributeName in batchGeometry.attributes ) { - - if ( attributeName === ID_ATTR_NAME ) { - - continue; - - } - - // copy attribute data - const srcAttribute = geometry.getAttribute( attributeName ); - const dstAttribute = batchGeometry.getAttribute( attributeName ); - copyAttributeData( srcAttribute, dstAttribute, vertexStart ); - - // fill the rest in with zeroes - const itemSize = srcAttribute.itemSize; - for ( let i = srcAttribute.count, l = vertexCount; i < l; i ++ ) { - - const index = vertexStart + i; - for ( let c = 0; c < itemSize; c ++ ) { - - dstAttribute.setComponent( index, c, 0 ); - - } - - } - - dstAttribute.needsUpdate = true; - - } - - // copy index - if ( hasIndex ) { - - const indexStart = reservedRange.indexStart; - - // copy index data over - for ( let i = 0; i < srcIndex.count; i ++ ) { - - dstIndex.setX( indexStart + i, vertexStart + srcIndex.getX( i ) ); - - } - - // fill the rest in with zeroes - for ( let i = srcIndex.count, l = reservedRange.indexCount; i < l; i ++ ) { - - dstIndex.setX( indexStart + i, vertexStart ); - - } - - dstIndex.needsUpdate = true; - - } - - // store the bounding boxes - const bound = this._bounds[ id ]; - if ( geometry.boundingBox !== null ) { - - bound.box.copy( geometry.boundingBox ); - bound.boxInitialized = true; - - } else { - - bound.boxInitialized = false; - - } - - if ( geometry.boundingSphere !== null ) { - - bound.sphere.copy( geometry.boundingSphere ); - bound.sphereInitialized = true; - - } else { - - bound.sphereInitialized = false; - - } - - // set drawRange count - const drawRange = this._drawRanges[ id ]; - const posAttr = geometry.getAttribute( 'position' ); - drawRange.count = hasIndex ? srcIndex.count : posAttr.count; - this._visibilityChanged = true; - - return id; - - } - - deleteGeometry( geometryId ) { - - // Note: User needs to call optimize() afterward to pack the data. - - const active = this._active; - if ( geometryId >= active.length || active[ geometryId ] === false ) { - - return this; - - } - - active[ geometryId ] = false; - this._visibilityChanged = true; - - return this; - - } - - // get bounding box and compute it if it doesn't exist - getBoundingBoxAt( id, target ) { - - const active = this._active; - if ( active[ id ] === false ) { - - return null; - - } - - // compute bounding box - const bound = this._bounds[ id ]; - const box = bound.box; - const geometry = this.geometry; - if ( bound.boxInitialized === false ) { - - box.makeEmpty(); - - const index = geometry.index; - const position = geometry.attributes.position; - const drawRange = this._drawRanges[ id ]; - for ( let i = drawRange.start, l = drawRange.start + drawRange.count; i < l; i ++ ) { - - let iv = i; - if ( index ) { - - iv = index.getX( iv ); - - } - - box.expandByPoint( _vector$5.fromBufferAttribute( position, iv ) ); - - } - - bound.boxInitialized = true; - - } - - target.copy( box ); - return target; - - } - - // get bounding sphere and compute it if it doesn't exist - getBoundingSphereAt( id, target ) { - - const active = this._active; - if ( active[ id ] === false ) { - - return null; - - } - - // compute bounding sphere - const bound = this._bounds[ id ]; - const sphere = bound.sphere; - const geometry = this.geometry; - if ( bound.sphereInitialized === false ) { - - sphere.makeEmpty(); - - this.getBoundingBoxAt( id, _box$1 ); - _box$1.getCenter( sphere.center ); - - const index = geometry.index; - const position = geometry.attributes.position; - const drawRange = this._drawRanges[ id ]; - - let maxRadiusSq = 0; - for ( let i = drawRange.start, l = drawRange.start + drawRange.count; i < l; i ++ ) { - - let iv = i; - if ( index ) { - - iv = index.getX( iv ); - - } - - _vector$5.fromBufferAttribute( position, iv ); - maxRadiusSq = Math.max( maxRadiusSq, sphere.center.distanceToSquared( _vector$5 ) ); - - } - - sphere.radius = Math.sqrt( maxRadiusSq ); - bound.sphereInitialized = true; - - } - - target.copy( sphere ); - return target; - - } - - setMatrixAt( geometryId, matrix ) { - - // @TODO: Map geometryId to index of the arrays because - // optimize() can make geometryId mismatch the index - - const active = this._active; - const matricesTexture = this._matricesTexture; - const matricesArray = this._matricesTexture.image.data; - const geometryCount = this._geometryCount; - if ( geometryId >= geometryCount || active[ geometryId ] === false ) { - - return this; - - } - - matrix.toArray( matricesArray, geometryId * 16 ); - matricesTexture.needsUpdate = true; - - return this; - - } - - getMatrixAt( geometryId, matrix ) { - - const active = this._active; - const matricesArray = this._matricesTexture.image.data; - const geometryCount = this._geometryCount; - if ( geometryId >= geometryCount || active[ geometryId ] === false ) { - - return null; - - } - - return matrix.fromArray( matricesArray, geometryId * 16 ); - - } - - setVisibleAt( geometryId, value ) { - - const visibility = this._visibility; - const active = this._active; - const geometryCount = this._geometryCount; - - // if the geometry is out of range, not active, or visibility state - // does not change then return early - if ( - geometryId >= geometryCount || - active[ geometryId ] === false || - visibility[ geometryId ] === value - ) { - - return this; - - } - - visibility[ geometryId ] = value; - this._visibilityChanged = true; - - return this; - - } - - getVisibleAt( geometryId ) { - - const visibility = this._visibility; - const active = this._active; - const geometryCount = this._geometryCount; - - // return early if the geometry is out of range or not active - if ( geometryId >= geometryCount || active[ geometryId ] === false ) { - - return false; - - } - - return visibility[ geometryId ]; - - } - - raycast( raycaster, intersects ) { - - const visibility = this._visibility; - const active = this._active; - const drawRanges = this._drawRanges; - const geometryCount = this._geometryCount; - const matrixWorld = this.matrixWorld; - const batchGeometry = this.geometry; - - // iterate over each geometry - _mesh.material = this.material; - _mesh.geometry.index = batchGeometry.index; - _mesh.geometry.attributes = batchGeometry.attributes; - if ( _mesh.geometry.boundingBox === null ) { - - _mesh.geometry.boundingBox = new Box3(); - - } - - if ( _mesh.geometry.boundingSphere === null ) { - - _mesh.geometry.boundingSphere = new Sphere(); - - } - - for ( let i = 0; i < geometryCount; i ++ ) { - - if ( ! visibility[ i ] || ! active[ i ] ) { - - continue; - - } - - const drawRange = drawRanges[ i ]; - _mesh.geometry.setDrawRange( drawRange.start, drawRange.count ); - - // ge the intersects - this.getMatrixAt( i, _mesh.matrixWorld ).premultiply( matrixWorld ); - this.getBoundingBoxAt( i, _mesh.geometry.boundingBox ); - this.getBoundingSphereAt( i, _mesh.geometry.boundingSphere ); - _mesh.raycast( raycaster, _batchIntersects ); - - // add batch id to the intersects - for ( let j = 0, l = _batchIntersects.length; j < l; j ++ ) { - - const intersect = _batchIntersects[ j ]; - intersect.object = this; - intersect.batchId = i; - intersects.push( intersect ); - - } - - _batchIntersects.length = 0; - - } - - _mesh.material = null; - _mesh.geometry.index = null; - _mesh.geometry.attributes = {}; - _mesh.geometry.setDrawRange( 0, Infinity ); - - } - - copy( source ) { - - super.copy( source ); - - this.geometry = source.geometry.clone(); - this.perObjectFrustumCulled = source.perObjectFrustumCulled; - this.sortObjects = source.sortObjects; - this.boundingBox = source.boundingBox !== null ? source.boundingBox.clone() : null; - this.boundingSphere = source.boundingSphere !== null ? source.boundingSphere.clone() : null; - - this._drawRanges = source._drawRanges.map( range => ( { ...range } ) ); - this._reservedRanges = source._reservedRanges.map( range => ( { ...range } ) ); - - this._visibility = source._visibility.slice(); - this._active = source._active.slice(); - this._bounds = source._bounds.map( bound => ( { - boxInitialized: bound.boxInitialized, - box: bound.box.clone(), - - sphereInitialized: bound.sphereInitialized, - sphere: bound.sphere.clone() - } ) ); - - this._maxGeometryCount = source._maxGeometryCount; - this._maxVertexCount = source._maxVertexCount; - this._maxIndexCount = source._maxIndexCount; - - this._geometryInitialized = source._geometryInitialized; - this._geometryCount = source._geometryCount; - this._multiDrawCounts = source._multiDrawCounts.slice(); - this._multiDrawStarts = source._multiDrawStarts.slice(); - - this._matricesTexture = source._matricesTexture.clone(); - this._matricesTexture.image.data = this._matricesTexture.image.slice(); - - return this; - - } - - dispose() { - - // Assuming the geometry is not shared with other meshes - this.geometry.dispose(); - - this._matricesTexture.dispose(); - this._matricesTexture = null; - return this; - - } - - onBeforeRender( renderer, scene, camera, geometry, material/*, _group*/ ) { - - // if visibility has not changed and frustum culling and object sorting is not required - // then skip iterating over all items - if ( ! this._visibilityChanged && ! this.perObjectFrustumCulled && ! this.sortObjects ) { - - return; - - } - - // the indexed version of the multi draw function requires specifying the start - // offset in bytes. - const index = geometry.getIndex(); - const bytesPerElement = index === null ? 1 : index.array.BYTES_PER_ELEMENT; - - const active = this._active; - const visibility = this._visibility; - const multiDrawStarts = this._multiDrawStarts; - const multiDrawCounts = this._multiDrawCounts; - const drawRanges = this._drawRanges; - const perObjectFrustumCulled = this.perObjectFrustumCulled; - - // prepare the frustum in the local frame - if ( perObjectFrustumCulled ) { - - _projScreenMatrix$2 - .multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ) - .multiply( this.matrixWorld ); - _frustum.setFromProjectionMatrix( - _projScreenMatrix$2, - renderer.coordinateSystem - ); - - } - - let count = 0; - if ( this.sortObjects ) { - - // get the camera position in the local frame - _invMatrixWorld.copy( this.matrixWorld ).invert(); - _vector$5.setFromMatrixPosition( camera.matrixWorld ).applyMatrix4( _invMatrixWorld ); - - for ( let i = 0, l = visibility.length; i < l; i ++ ) { - - if ( visibility[ i ] && active[ i ] ) { - - // get the bounds in world space - this.getMatrixAt( i, _matrix ); - this.getBoundingSphereAt( i, _sphere$2 ).applyMatrix4( _matrix ); - - // determine whether the batched geometry is within the frustum - let culled = false; - if ( perObjectFrustumCulled ) { - - culled = ! _frustum.intersectsSphere( _sphere$2 ); - - } - - if ( ! culled ) { - - // get the distance from camera used for sorting - const z = _vector$5.distanceTo( _sphere$2.center ); - _renderList.push( drawRanges[ i ], z ); - - } - - } - - } - - // Sort the draw ranges and prep for rendering - const list = _renderList.list; - const customSort = this.customSort; - if ( customSort === null ) { - - list.sort( material.transparent ? sortTransparent : sortOpaque ); - - } else { - - customSort.call( this, list, camera ); - - } - - for ( let i = 0, l = list.length; i < l; i ++ ) { - - const item = list[ i ]; - multiDrawStarts[ count ] = item.start * bytesPerElement; - multiDrawCounts[ count ] = item.count; - count ++; - - } - - _renderList.reset(); - - } else { - - for ( let i = 0, l = visibility.length; i < l; i ++ ) { - - if ( visibility[ i ] && active[ i ] ) { - - // determine whether the batched geometry is within the frustum - let culled = false; - if ( perObjectFrustumCulled ) { - - // get the bounds in world space - this.getMatrixAt( i, _matrix ); - this.getBoundingSphereAt( i, _sphere$2 ).applyMatrix4( _matrix ); - culled = ! _frustum.intersectsSphere( _sphere$2 ); - - } - - if ( ! culled ) { - - const range = drawRanges[ i ]; - multiDrawStarts[ count ] = range.start * bytesPerElement; - multiDrawCounts[ count ] = range.count; - count ++; - - } - - } - - } - - } - - this._multiDrawCount = count; - this._visibilityChanged = false; - - } - - onBeforeShadow( renderer, object, camera, shadowCamera, geometry, depthMaterial/* , group */ ) { - - this.onBeforeRender( renderer, null, shadowCamera, geometry, depthMaterial ); - - } - -} - -class LineBasicMaterial extends Material { - - constructor( parameters ) { - - super(); - - this.isLineBasicMaterial = true; - - this.type = 'LineBasicMaterial'; - - this.color = new Color( 0xffffff ); - - this.map = null; - - this.linewidth = 1; - this.linecap = 'round'; - this.linejoin = 'round'; - - this.fog = true; - - this.setValues( parameters ); - - } - - - copy( source ) { - - super.copy( source ); - - this.color.copy( source.color ); - - this.map = source.map; - - this.linewidth = source.linewidth; - this.linecap = source.linecap; - this.linejoin = source.linejoin; - - this.fog = source.fog; - - return this; - - } - -} - -const _start$1 = /*@__PURE__*/ new Vector3(); -const _end$1 = /*@__PURE__*/ new Vector3(); -const _inverseMatrix$1 = /*@__PURE__*/ new Matrix4(); -const _ray$1 = /*@__PURE__*/ new Ray(); -const _sphere$1 = /*@__PURE__*/ new Sphere(); - -class Line extends Object3D { - - constructor( geometry = new BufferGeometry(), material = new LineBasicMaterial() ) { - - super(); - - this.isLine = true; - - this.type = 'Line'; - - this.geometry = geometry; - this.material = material; - - this.updateMorphTargets(); - - } - - copy( source, recursive ) { - - super.copy( source, recursive ); - - this.material = Array.isArray( source.material ) ? source.material.slice() : source.material; - this.geometry = source.geometry; - - return this; - - } - - computeLineDistances() { - - const geometry = this.geometry; - - // we assume non-indexed geometry - - if ( geometry.index === null ) { - - const positionAttribute = geometry.attributes.position; - const lineDistances = [ 0 ]; - - for ( let i = 1, l = positionAttribute.count; i < l; i ++ ) { - - _start$1.fromBufferAttribute( positionAttribute, i - 1 ); - _end$1.fromBufferAttribute( positionAttribute, i ); - - lineDistances[ i ] = lineDistances[ i - 1 ]; - lineDistances[ i ] += _start$1.distanceTo( _end$1 ); - - } - - geometry.setAttribute( 'lineDistance', new Float32BufferAttribute( lineDistances, 1 ) ); - - } else { - - console.warn( 'THREE.Line.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.' ); - - } - - return this; - - } - - raycast( raycaster, intersects ) { - - const geometry = this.geometry; - const matrixWorld = this.matrixWorld; - const threshold = raycaster.params.Line.threshold; - const drawRange = geometry.drawRange; - - // Checking boundingSphere distance to ray - - if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); - - _sphere$1.copy( geometry.boundingSphere ); - _sphere$1.applyMatrix4( matrixWorld ); - _sphere$1.radius += threshold; - - if ( raycaster.ray.intersectsSphere( _sphere$1 ) === false ) return; - - // - - _inverseMatrix$1.copy( matrixWorld ).invert(); - _ray$1.copy( raycaster.ray ).applyMatrix4( _inverseMatrix$1 ); - - const localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 ); - const localThresholdSq = localThreshold * localThreshold; - - const vStart = new Vector3(); - const vEnd = new Vector3(); - const interSegment = new Vector3(); - const interRay = new Vector3(); - const step = this.isLineSegments ? 2 : 1; - - const index = geometry.index; - const attributes = geometry.attributes; - const positionAttribute = attributes.position; - - if ( index !== null ) { - - const start = Math.max( 0, drawRange.start ); - const end = Math.min( index.count, ( drawRange.start + drawRange.count ) ); - - for ( let i = start, l = end - 1; i < l; i += step ) { - - const a = index.getX( i ); - const b = index.getX( i + 1 ); - - vStart.fromBufferAttribute( positionAttribute, a ); - vEnd.fromBufferAttribute( positionAttribute, b ); - - const distSq = _ray$1.distanceSqToSegment( vStart, vEnd, interRay, interSegment ); - - if ( distSq > localThresholdSq ) continue; - - interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation - - const distance = raycaster.ray.origin.distanceTo( interRay ); - - if ( distance < raycaster.near || distance > raycaster.far ) continue; - - intersects.push( { - - distance: distance, - // What do we want? intersection point on the ray or on the segment?? - // point: raycaster.ray.at( distance ), - point: interSegment.clone().applyMatrix4( this.matrixWorld ), - index: i, - face: null, - faceIndex: null, - object: this - - } ); - - } - - } else { - - const start = Math.max( 0, drawRange.start ); - const end = Math.min( positionAttribute.count, ( drawRange.start + drawRange.count ) ); - - for ( let i = start, l = end - 1; i < l; i += step ) { - - vStart.fromBufferAttribute( positionAttribute, i ); - vEnd.fromBufferAttribute( positionAttribute, i + 1 ); - - const distSq = _ray$1.distanceSqToSegment( vStart, vEnd, interRay, interSegment ); - - if ( distSq > localThresholdSq ) continue; - - interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation - - const distance = raycaster.ray.origin.distanceTo( interRay ); - - if ( distance < raycaster.near || distance > raycaster.far ) continue; - - intersects.push( { - - distance: distance, - // What do we want? intersection point on the ray or on the segment?? - // point: raycaster.ray.at( distance ), - point: interSegment.clone().applyMatrix4( this.matrixWorld ), - index: i, - face: null, - faceIndex: null, - object: this - - } ); - - } - - } - - } - - updateMorphTargets() { - - const geometry = this.geometry; - - const morphAttributes = geometry.morphAttributes; - const keys = Object.keys( morphAttributes ); - - if ( keys.length > 0 ) { - - const morphAttribute = morphAttributes[ keys[ 0 ] ]; - - if ( morphAttribute !== undefined ) { - - this.morphTargetInfluences = []; - this.morphTargetDictionary = {}; - - for ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) { - - const name = morphAttribute[ m ].name || String( m ); - - this.morphTargetInfluences.push( 0 ); - this.morphTargetDictionary[ name ] = m; - - } - - } - - } - - } - -} - -const _start = /*@__PURE__*/ new Vector3(); -const _end = /*@__PURE__*/ new Vector3(); - -class LineSegments extends Line { - - constructor( geometry, material ) { - - super( geometry, material ); - - this.isLineSegments = true; - - this.type = 'LineSegments'; - - } - - computeLineDistances() { - - const geometry = this.geometry; - - // we assume non-indexed geometry - - if ( geometry.index === null ) { - - const positionAttribute = geometry.attributes.position; - const lineDistances = []; - - for ( let i = 0, l = positionAttribute.count; i < l; i += 2 ) { - - _start.fromBufferAttribute( positionAttribute, i ); - _end.fromBufferAttribute( positionAttribute, i + 1 ); - - lineDistances[ i ] = ( i === 0 ) ? 0 : lineDistances[ i - 1 ]; - lineDistances[ i + 1 ] = lineDistances[ i ] + _start.distanceTo( _end ); - - } - - geometry.setAttribute( 'lineDistance', new Float32BufferAttribute( lineDistances, 1 ) ); - - } else { - - console.warn( 'THREE.LineSegments.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.' ); - - } - - return this; - - } - -} - -class LineLoop extends Line { - - constructor( geometry, material ) { - - super( geometry, material ); - - this.isLineLoop = true; - - this.type = 'LineLoop'; - - } - -} - -class PointsMaterial extends Material { - - constructor( parameters ) { - - super(); - - this.isPointsMaterial = true; - - this.type = 'PointsMaterial'; - - this.color = new Color( 0xffffff ); - - this.map = null; - - this.alphaMap = null; - - this.size = 1; - this.sizeAttenuation = true; - - this.fog = true; - - this.setValues( parameters ); - - } - - copy( source ) { - - super.copy( source ); - - this.color.copy( source.color ); - - this.map = source.map; - - this.alphaMap = source.alphaMap; - - this.size = source.size; - this.sizeAttenuation = source.sizeAttenuation; - - this.fog = source.fog; - - return this; - - } - -} - -const _inverseMatrix = /*@__PURE__*/ new Matrix4(); -const _ray = /*@__PURE__*/ new Ray(); -const _sphere = /*@__PURE__*/ new Sphere(); -const _position$2 = /*@__PURE__*/ new Vector3(); - -class Points extends Object3D { - - constructor( geometry = new BufferGeometry(), material = new PointsMaterial() ) { - - super(); - - this.isPoints = true; - - this.type = 'Points'; - - this.geometry = geometry; - this.material = material; - - this.updateMorphTargets(); - - } - - copy( source, recursive ) { - - super.copy( source, recursive ); - - this.material = Array.isArray( source.material ) ? source.material.slice() : source.material; - this.geometry = source.geometry; - - return this; - - } - - raycast( raycaster, intersects ) { - - const geometry = this.geometry; - const matrixWorld = this.matrixWorld; - const threshold = raycaster.params.Points.threshold; - const drawRange = geometry.drawRange; - - // Checking boundingSphere distance to ray - - if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); - - _sphere.copy( geometry.boundingSphere ); - _sphere.applyMatrix4( matrixWorld ); - _sphere.radius += threshold; - - if ( raycaster.ray.intersectsSphere( _sphere ) === false ) return; - - // - - _inverseMatrix.copy( matrixWorld ).invert(); - _ray.copy( raycaster.ray ).applyMatrix4( _inverseMatrix ); - - const localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 ); - const localThresholdSq = localThreshold * localThreshold; - - const index = geometry.index; - const attributes = geometry.attributes; - const positionAttribute = attributes.position; - - if ( index !== null ) { - - const start = Math.max( 0, drawRange.start ); - const end = Math.min( index.count, ( drawRange.start + drawRange.count ) ); - - for ( let i = start, il = end; i < il; i ++ ) { - - const a = index.getX( i ); - - _position$2.fromBufferAttribute( positionAttribute, a ); - - testPoint( _position$2, a, localThresholdSq, matrixWorld, raycaster, intersects, this ); - - } - - } else { - - const start = Math.max( 0, drawRange.start ); - const end = Math.min( positionAttribute.count, ( drawRange.start + drawRange.count ) ); - - for ( let i = start, l = end; i < l; i ++ ) { - - _position$2.fromBufferAttribute( positionAttribute, i ); - - testPoint( _position$2, i, localThresholdSq, matrixWorld, raycaster, intersects, this ); - - } - - } - - } - - updateMorphTargets() { - - const geometry = this.geometry; - - const morphAttributes = geometry.morphAttributes; - const keys = Object.keys( morphAttributes ); - - if ( keys.length > 0 ) { - - const morphAttribute = morphAttributes[ keys[ 0 ] ]; - - if ( morphAttribute !== undefined ) { - - this.morphTargetInfluences = []; - this.morphTargetDictionary = {}; - - for ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) { - - const name = morphAttribute[ m ].name || String( m ); - - this.morphTargetInfluences.push( 0 ); - this.morphTargetDictionary[ name ] = m; - - } - - } - - } - - } - -} - -function testPoint( point, index, localThresholdSq, matrixWorld, raycaster, intersects, object ) { - - const rayPointDistanceSq = _ray.distanceSqToPoint( point ); - - if ( rayPointDistanceSq < localThresholdSq ) { - - const intersectPoint = new Vector3(); - - _ray.closestPointToPoint( point, intersectPoint ); - intersectPoint.applyMatrix4( matrixWorld ); - - const distance = raycaster.ray.origin.distanceTo( intersectPoint ); - - if ( distance < raycaster.near || distance > raycaster.far ) return; - - intersects.push( { - - distance: distance, - distanceToRay: Math.sqrt( rayPointDistanceSq ), - point: intersectPoint, - index: index, - face: null, - object: object - - } ); - - } - -} - -class VideoTexture extends Texture { - - constructor( video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) { - - super( video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); - - this.isVideoTexture = true; - - this.minFilter = minFilter !== undefined ? minFilter : LinearFilter; - this.magFilter = magFilter !== undefined ? magFilter : LinearFilter; - - this.generateMipmaps = false; - - const scope = this; - - function updateVideo() { - - scope.needsUpdate = true; - video.requestVideoFrameCallback( updateVideo ); - - } - - if ( 'requestVideoFrameCallback' in video ) { - - video.requestVideoFrameCallback( updateVideo ); - - } - - } - - clone() { - - return new this.constructor( this.image ).copy( this ); - - } - - update() { - - const video = this.image; - const hasVideoFrameCallback = 'requestVideoFrameCallback' in video; - - if ( hasVideoFrameCallback === false && video.readyState >= video.HAVE_CURRENT_DATA ) { - - this.needsUpdate = true; - - } - - } - -} - -class FramebufferTexture extends Texture { - - constructor( width, height ) { - - super( { width, height } ); - - this.isFramebufferTexture = true; - - this.magFilter = NearestFilter; - this.minFilter = NearestFilter; - - this.generateMipmaps = false; - - this.needsUpdate = true; - - } - -} - -class CompressedTexture extends Texture { - - constructor( mipmaps, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, colorSpace ) { - - super( null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, colorSpace ); - - this.isCompressedTexture = true; - - this.image = { width: width, height: height }; - this.mipmaps = mipmaps; - - // no flipping for cube textures - // (also flipping doesn't work for compressed textures ) - - this.flipY = false; - - // can't generate mipmaps for compressed textures - // mips must be embedded in DDS files - - this.generateMipmaps = false; - - } - -} - -class CompressedArrayTexture extends CompressedTexture { - - constructor( mipmaps, width, height, depth, format, type ) { - - super( mipmaps, width, height, format, type ); - - this.isCompressedArrayTexture = true; - this.image.depth = depth; - this.wrapR = ClampToEdgeWrapping; - - } - -} - -class CompressedCubeTexture extends CompressedTexture { - - constructor( images, format, type ) { - - super( undefined, images[ 0 ].width, images[ 0 ].height, format, type, CubeReflectionMapping ); - - this.isCompressedCubeTexture = true; - this.isCubeTexture = true; - - this.image = images; - - } - -} - -class CanvasTexture extends Texture { - - constructor( canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) { - - super( canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); - - this.isCanvasTexture = true; - - this.needsUpdate = true; - - } - -} - -/** - * Extensible curve object. - * - * Some common of curve methods: - * .getPoint( t, optionalTarget ), .getTangent( t, optionalTarget ) - * .getPointAt( u, optionalTarget ), .getTangentAt( u, optionalTarget ) - * .getPoints(), .getSpacedPoints() - * .getLength() - * .updateArcLengths() - * - * This following curves inherit from THREE.Curve: - * - * -- 2D curves -- - * THREE.ArcCurve - * THREE.CubicBezierCurve - * THREE.EllipseCurve - * THREE.LineCurve - * THREE.QuadraticBezierCurve - * THREE.SplineCurve - * - * -- 3D curves -- - * THREE.CatmullRomCurve3 - * THREE.CubicBezierCurve3 - * THREE.LineCurve3 - * THREE.QuadraticBezierCurve3 - * - * A series of curves can be represented as a THREE.CurvePath. - * - **/ - -class Curve { - - constructor() { - - this.type = 'Curve'; - - this.arcLengthDivisions = 200; - - } - - // Virtual base class method to overwrite and implement in subclasses - // - t [0 .. 1] - - getPoint( /* t, optionalTarget */ ) { - - console.warn( 'THREE.Curve: .getPoint() not implemented.' ); - return null; - - } - - // Get point at relative position in curve according to arc length - // - u [0 .. 1] - - getPointAt( u, optionalTarget ) { - - const t = this.getUtoTmapping( u ); - return this.getPoint( t, optionalTarget ); - - } - - // Get sequence of points using getPoint( t ) - - getPoints( divisions = 5 ) { - - const points = []; - - for ( let d = 0; d <= divisions; d ++ ) { - - points.push( this.getPoint( d / divisions ) ); - - } - - return points; - - } - - // Get sequence of points using getPointAt( u ) - - getSpacedPoints( divisions = 5 ) { - - const points = []; - - for ( let d = 0; d <= divisions; d ++ ) { - - points.push( this.getPointAt( d / divisions ) ); - - } - - return points; - - } - - // Get total curve arc length - - getLength() { - - const lengths = this.getLengths(); - return lengths[ lengths.length - 1 ]; - - } - - // Get list of cumulative segment lengths - - getLengths( divisions = this.arcLengthDivisions ) { - - if ( this.cacheArcLengths && - ( this.cacheArcLengths.length === divisions + 1 ) && - ! this.needsUpdate ) { - - return this.cacheArcLengths; - - } - - this.needsUpdate = false; - - const cache = []; - let current, last = this.getPoint( 0 ); - let sum = 0; - - cache.push( 0 ); - - for ( let p = 1; p <= divisions; p ++ ) { - - current = this.getPoint( p / divisions ); - sum += current.distanceTo( last ); - cache.push( sum ); - last = current; - - } - - this.cacheArcLengths = cache; - - return cache; // { sums: cache, sum: sum }; Sum is in the last element. - - } - - updateArcLengths() { - - this.needsUpdate = true; - this.getLengths(); - - } - - // Given u ( 0 .. 1 ), get a t to find p. This gives you points which are equidistant - - getUtoTmapping( u, distance ) { - - const arcLengths = this.getLengths(); - - let i = 0; - const il = arcLengths.length; - - let targetArcLength; // The targeted u distance value to get - - if ( distance ) { - - targetArcLength = distance; - - } else { - - targetArcLength = u * arcLengths[ il - 1 ]; - - } - - // binary search for the index with largest value smaller than target u distance - - let low = 0, high = il - 1, comparison; - - while ( low <= high ) { - - i = Math.floor( low + ( high - low ) / 2 ); // less likely to overflow, though probably not issue here, JS doesn't really have integers, all numbers are floats - - comparison = arcLengths[ i ] - targetArcLength; - - if ( comparison < 0 ) { - - low = i + 1; - - } else if ( comparison > 0 ) { - - high = i - 1; - - } else { - - high = i; - break; - - // DONE - - } - - } - - i = high; - - if ( arcLengths[ i ] === targetArcLength ) { - - return i / ( il - 1 ); - - } - - // we could get finer grain at lengths, or use simple interpolation between two points - - const lengthBefore = arcLengths[ i ]; - const lengthAfter = arcLengths[ i + 1 ]; - - const segmentLength = lengthAfter - lengthBefore; - - // determine where we are between the 'before' and 'after' points - - const segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength; - - // add that fractional amount to t - - const t = ( i + segmentFraction ) / ( il - 1 ); - - return t; - - } - - // Returns a unit vector tangent at t - // In case any sub curve does not implement its tangent derivation, - // 2 points a small delta apart will be used to find its gradient - // which seems to give a reasonable approximation - - getTangent( t, optionalTarget ) { - - const delta = 0.0001; - let t1 = t - delta; - let t2 = t + delta; - - // Capping in case of danger - - if ( t1 < 0 ) t1 = 0; - if ( t2 > 1 ) t2 = 1; - - const pt1 = this.getPoint( t1 ); - const pt2 = this.getPoint( t2 ); - - const tangent = optionalTarget || ( ( pt1.isVector2 ) ? new Vector2() : new Vector3() ); - - tangent.copy( pt2 ).sub( pt1 ).normalize(); - - return tangent; - - } - - getTangentAt( u, optionalTarget ) { - - const t = this.getUtoTmapping( u ); - return this.getTangent( t, optionalTarget ); - - } - - computeFrenetFrames( segments, closed ) { - - // see http://www.cs.indiana.edu/pub/techreports/TR425.pdf - - const normal = new Vector3(); - - const tangents = []; - const normals = []; - const binormals = []; - - const vec = new Vector3(); - const mat = new Matrix4(); - - // compute the tangent vectors for each segment on the curve - - for ( let i = 0; i <= segments; i ++ ) { - - const u = i / segments; - - tangents[ i ] = this.getTangentAt( u, new Vector3() ); - - } - - // select an initial normal vector perpendicular to the first tangent vector, - // and in the direction of the minimum tangent xyz component - - normals[ 0 ] = new Vector3(); - binormals[ 0 ] = new Vector3(); - let min = Number.MAX_VALUE; - const tx = Math.abs( tangents[ 0 ].x ); - const ty = Math.abs( tangents[ 0 ].y ); - const tz = Math.abs( tangents[ 0 ].z ); - - if ( tx <= min ) { - - min = tx; - normal.set( 1, 0, 0 ); - - } - - if ( ty <= min ) { - - min = ty; - normal.set( 0, 1, 0 ); - - } - - if ( tz <= min ) { - - normal.set( 0, 0, 1 ); - - } - - vec.crossVectors( tangents[ 0 ], normal ).normalize(); - - normals[ 0 ].crossVectors( tangents[ 0 ], vec ); - binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ); - - - // compute the slowly-varying normal and binormal vectors for each segment on the curve - - for ( let i = 1; i <= segments; i ++ ) { - - normals[ i ] = normals[ i - 1 ].clone(); - - binormals[ i ] = binormals[ i - 1 ].clone(); - - vec.crossVectors( tangents[ i - 1 ], tangents[ i ] ); - - if ( vec.length() > Number.EPSILON ) { - - vec.normalize(); - - const theta = Math.acos( clamp( tangents[ i - 1 ].dot( tangents[ i ] ), - 1, 1 ) ); // clamp for floating pt errors - - normals[ i ].applyMatrix4( mat.makeRotationAxis( vec, theta ) ); - - } - - binormals[ i ].crossVectors( tangents[ i ], normals[ i ] ); - - } - - // if the curve is closed, postprocess the vectors so the first and last normal vectors are the same - - if ( closed === true ) { - - let theta = Math.acos( clamp( normals[ 0 ].dot( normals[ segments ] ), - 1, 1 ) ); - theta /= segments; - - if ( tangents[ 0 ].dot( vec.crossVectors( normals[ 0 ], normals[ segments ] ) ) > 0 ) { - - theta = - theta; - - } - - for ( let i = 1; i <= segments; i ++ ) { - - // twist a little... - normals[ i ].applyMatrix4( mat.makeRotationAxis( tangents[ i ], theta * i ) ); - binormals[ i ].crossVectors( tangents[ i ], normals[ i ] ); - - } - - } - - return { - tangents: tangents, - normals: normals, - binormals: binormals - }; - - } - - clone() { - - return new this.constructor().copy( this ); - - } - - copy( source ) { - - this.arcLengthDivisions = source.arcLengthDivisions; - - return this; - - } - - toJSON() { - - const data = { - metadata: { - version: 4.6, - type: 'Curve', - generator: 'Curve.toJSON' - } - }; - - data.arcLengthDivisions = this.arcLengthDivisions; - data.type = this.type; - - return data; - - } - - fromJSON( json ) { - - this.arcLengthDivisions = json.arcLengthDivisions; - - return this; - - } - -} - -class EllipseCurve extends Curve { - - constructor( aX = 0, aY = 0, xRadius = 1, yRadius = 1, aStartAngle = 0, aEndAngle = Math.PI * 2, aClockwise = false, aRotation = 0 ) { - - super(); - - this.isEllipseCurve = true; - - this.type = 'EllipseCurve'; - - this.aX = aX; - this.aY = aY; - - this.xRadius = xRadius; - this.yRadius = yRadius; - - this.aStartAngle = aStartAngle; - this.aEndAngle = aEndAngle; - - this.aClockwise = aClockwise; - - this.aRotation = aRotation; - - } - - getPoint( t, optionalTarget ) { - - const point = optionalTarget || new Vector2(); - - const twoPi = Math.PI * 2; - let deltaAngle = this.aEndAngle - this.aStartAngle; - const samePoints = Math.abs( deltaAngle ) < Number.EPSILON; - - // ensures that deltaAngle is 0 .. 2 PI - while ( deltaAngle < 0 ) deltaAngle += twoPi; - while ( deltaAngle > twoPi ) deltaAngle -= twoPi; - - if ( deltaAngle < Number.EPSILON ) { - - if ( samePoints ) { - - deltaAngle = 0; - - } else { - - deltaAngle = twoPi; - - } - - } - - if ( this.aClockwise === true && ! samePoints ) { - - if ( deltaAngle === twoPi ) { - - deltaAngle = - twoPi; - - } else { - - deltaAngle = deltaAngle - twoPi; - - } - - } - - const angle = this.aStartAngle + t * deltaAngle; - let x = this.aX + this.xRadius * Math.cos( angle ); - let y = this.aY + this.yRadius * Math.sin( angle ); - - if ( this.aRotation !== 0 ) { - - const cos = Math.cos( this.aRotation ); - const sin = Math.sin( this.aRotation ); - - const tx = x - this.aX; - const ty = y - this.aY; - - // Rotate the point about the center of the ellipse. - x = tx * cos - ty * sin + this.aX; - y = tx * sin + ty * cos + this.aY; - - } - - return point.set( x, y ); - - } - - copy( source ) { - - super.copy( source ); - - this.aX = source.aX; - this.aY = source.aY; - - this.xRadius = source.xRadius; - this.yRadius = source.yRadius; - - this.aStartAngle = source.aStartAngle; - this.aEndAngle = source.aEndAngle; - - this.aClockwise = source.aClockwise; - - this.aRotation = source.aRotation; - - return this; - - } - - toJSON() { - - const data = super.toJSON(); - - data.aX = this.aX; - data.aY = this.aY; - - data.xRadius = this.xRadius; - data.yRadius = this.yRadius; - - data.aStartAngle = this.aStartAngle; - data.aEndAngle = this.aEndAngle; - - data.aClockwise = this.aClockwise; - - data.aRotation = this.aRotation; - - return data; - - } - - fromJSON( json ) { - - super.fromJSON( json ); - - this.aX = json.aX; - this.aY = json.aY; - - this.xRadius = json.xRadius; - this.yRadius = json.yRadius; - - this.aStartAngle = json.aStartAngle; - this.aEndAngle = json.aEndAngle; - - this.aClockwise = json.aClockwise; - - this.aRotation = json.aRotation; - - return this; - - } - -} - -class ArcCurve extends EllipseCurve { - - constructor( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { - - super( aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise ); - - this.isArcCurve = true; - - this.type = 'ArcCurve'; - - } - -} - -/** - * Centripetal CatmullRom Curve - which is useful for avoiding - * cusps and self-intersections in non-uniform catmull rom curves. - * http://www.cemyuksel.com/research/catmullrom_param/catmullrom.pdf - * - * curve.type accepts centripetal(default), chordal and catmullrom - * curve.tension is used for catmullrom which defaults to 0.5 - */ - - -/* -Based on an optimized c++ solution in - - http://stackoverflow.com/questions/9489736/catmull-rom-curve-with-no-cusps-and-no-self-intersections/ - - http://ideone.com/NoEbVM - -This CubicPoly class could be used for reusing some variables and calculations, -but for three.js curve use, it could be possible inlined and flatten into a single function call -which can be placed in CurveUtils. -*/ - -function CubicPoly() { - - let c0 = 0, c1 = 0, c2 = 0, c3 = 0; - - /* - * Compute coefficients for a cubic polynomial - * p(s) = c0 + c1*s + c2*s^2 + c3*s^3 - * such that - * p(0) = x0, p(1) = x1 - * and - * p'(0) = t0, p'(1) = t1. - */ - function init( x0, x1, t0, t1 ) { - - c0 = x0; - c1 = t0; - c2 = - 3 * x0 + 3 * x1 - 2 * t0 - t1; - c3 = 2 * x0 - 2 * x1 + t0 + t1; - - } - - return { - - initCatmullRom: function ( x0, x1, x2, x3, tension ) { - - init( x1, x2, tension * ( x2 - x0 ), tension * ( x3 - x1 ) ); - - }, - - initNonuniformCatmullRom: function ( x0, x1, x2, x3, dt0, dt1, dt2 ) { - - // compute tangents when parameterized in [t1,t2] - let t1 = ( x1 - x0 ) / dt0 - ( x2 - x0 ) / ( dt0 + dt1 ) + ( x2 - x1 ) / dt1; - let t2 = ( x2 - x1 ) / dt1 - ( x3 - x1 ) / ( dt1 + dt2 ) + ( x3 - x2 ) / dt2; - - // rescale tangents for parametrization in [0,1] - t1 *= dt1; - t2 *= dt1; - - init( x1, x2, t1, t2 ); - - }, - - calc: function ( t ) { - - const t2 = t * t; - const t3 = t2 * t; - return c0 + c1 * t + c2 * t2 + c3 * t3; - - } - - }; - -} - -// - -const tmp = /*@__PURE__*/ new Vector3(); -const px = /*@__PURE__*/ new CubicPoly(); -const py = /*@__PURE__*/ new CubicPoly(); -const pz = /*@__PURE__*/ new CubicPoly(); - -class CatmullRomCurve3 extends Curve { - - constructor( points = [], closed = false, curveType = 'centripetal', tension = 0.5 ) { - - super(); - - this.isCatmullRomCurve3 = true; - - this.type = 'CatmullRomCurve3'; - - this.points = points; - this.closed = closed; - this.curveType = curveType; - this.tension = tension; - - } - - getPoint( t, optionalTarget = new Vector3() ) { - - const point = optionalTarget; - - const points = this.points; - const l = points.length; - - const p = ( l - ( this.closed ? 0 : 1 ) ) * t; - let intPoint = Math.floor( p ); - let weight = p - intPoint; - - if ( this.closed ) { - - intPoint += intPoint > 0 ? 0 : ( Math.floor( Math.abs( intPoint ) / l ) + 1 ) * l; - - } else if ( weight === 0 && intPoint === l - 1 ) { - - intPoint = l - 2; - weight = 1; - - } - - let p0, p3; // 4 points (p1 & p2 defined below) - - if ( this.closed || intPoint > 0 ) { - - p0 = points[ ( intPoint - 1 ) % l ]; - - } else { - - // extrapolate first point - tmp.subVectors( points[ 0 ], points[ 1 ] ).add( points[ 0 ] ); - p0 = tmp; - - } - - const p1 = points[ intPoint % l ]; - const p2 = points[ ( intPoint + 1 ) % l ]; - - if ( this.closed || intPoint + 2 < l ) { - - p3 = points[ ( intPoint + 2 ) % l ]; - - } else { - - // extrapolate last point - tmp.subVectors( points[ l - 1 ], points[ l - 2 ] ).add( points[ l - 1 ] ); - p3 = tmp; - - } - - if ( this.curveType === 'centripetal' || this.curveType === 'chordal' ) { - - // init Centripetal / Chordal Catmull-Rom - const pow = this.curveType === 'chordal' ? 0.5 : 0.25; - let dt0 = Math.pow( p0.distanceToSquared( p1 ), pow ); - let dt1 = Math.pow( p1.distanceToSquared( p2 ), pow ); - let dt2 = Math.pow( p2.distanceToSquared( p3 ), pow ); - - // safety check for repeated points - if ( dt1 < 1e-4 ) dt1 = 1.0; - if ( dt0 < 1e-4 ) dt0 = dt1; - if ( dt2 < 1e-4 ) dt2 = dt1; - - px.initNonuniformCatmullRom( p0.x, p1.x, p2.x, p3.x, dt0, dt1, dt2 ); - py.initNonuniformCatmullRom( p0.y, p1.y, p2.y, p3.y, dt0, dt1, dt2 ); - pz.initNonuniformCatmullRom( p0.z, p1.z, p2.z, p3.z, dt0, dt1, dt2 ); - - } else if ( this.curveType === 'catmullrom' ) { - - px.initCatmullRom( p0.x, p1.x, p2.x, p3.x, this.tension ); - py.initCatmullRom( p0.y, p1.y, p2.y, p3.y, this.tension ); - pz.initCatmullRom( p0.z, p1.z, p2.z, p3.z, this.tension ); - - } - - point.set( - px.calc( weight ), - py.calc( weight ), - pz.calc( weight ) - ); - - return point; - - } - - copy( source ) { - - super.copy( source ); - - this.points = []; - - for ( let i = 0, l = source.points.length; i < l; i ++ ) { - - const point = source.points[ i ]; - - this.points.push( point.clone() ); - - } - - this.closed = source.closed; - this.curveType = source.curveType; - this.tension = source.tension; - - return this; - - } - - toJSON() { - - const data = super.toJSON(); - - data.points = []; - - for ( let i = 0, l = this.points.length; i < l; i ++ ) { - - const point = this.points[ i ]; - data.points.push( point.toArray() ); - - } - - data.closed = this.closed; - data.curveType = this.curveType; - data.tension = this.tension; - - return data; - - } - - fromJSON( json ) { - - super.fromJSON( json ); - - this.points = []; - - for ( let i = 0, l = json.points.length; i < l; i ++ ) { - - const point = json.points[ i ]; - this.points.push( new Vector3().fromArray( point ) ); - - } - - this.closed = json.closed; - this.curveType = json.curveType; - this.tension = json.tension; - - return this; - - } - -} - -/** - * Bezier Curves formulas obtained from - * https://en.wikipedia.org/wiki/B%C3%A9zier_curve - */ - -function CatmullRom( t, p0, p1, p2, p3 ) { - - const v0 = ( p2 - p0 ) * 0.5; - const v1 = ( p3 - p1 ) * 0.5; - const t2 = t * t; - const t3 = t * t2; - return ( 2 * p1 - 2 * p2 + v0 + v1 ) * t3 + ( - 3 * p1 + 3 * p2 - 2 * v0 - v1 ) * t2 + v0 * t + p1; - -} - -// - -function QuadraticBezierP0( t, p ) { - - const k = 1 - t; - return k * k * p; - -} - -function QuadraticBezierP1( t, p ) { - - return 2 * ( 1 - t ) * t * p; - -} - -function QuadraticBezierP2( t, p ) { - - return t * t * p; - -} - -function QuadraticBezier( t, p0, p1, p2 ) { - - return QuadraticBezierP0( t, p0 ) + QuadraticBezierP1( t, p1 ) + - QuadraticBezierP2( t, p2 ); - -} - -// - -function CubicBezierP0( t, p ) { - - const k = 1 - t; - return k * k * k * p; - -} - -function CubicBezierP1( t, p ) { - - const k = 1 - t; - return 3 * k * k * t * p; - -} - -function CubicBezierP2( t, p ) { - - return 3 * ( 1 - t ) * t * t * p; - -} - -function CubicBezierP3( t, p ) { - - return t * t * t * p; - -} - -function CubicBezier( t, p0, p1, p2, p3 ) { - - return CubicBezierP0( t, p0 ) + CubicBezierP1( t, p1 ) + CubicBezierP2( t, p2 ) + - CubicBezierP3( t, p3 ); - -} - -class CubicBezierCurve extends Curve { - - constructor( v0 = new Vector2(), v1 = new Vector2(), v2 = new Vector2(), v3 = new Vector2() ) { - - super(); - - this.isCubicBezierCurve = true; - - this.type = 'CubicBezierCurve'; - - this.v0 = v0; - this.v1 = v1; - this.v2 = v2; - this.v3 = v3; - - } - - getPoint( t, optionalTarget = new Vector2() ) { - - const point = optionalTarget; - - const v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3; - - point.set( - CubicBezier( t, v0.x, v1.x, v2.x, v3.x ), - CubicBezier( t, v0.y, v1.y, v2.y, v3.y ) - ); - - return point; - - } - - copy( source ) { - - super.copy( source ); - - this.v0.copy( source.v0 ); - this.v1.copy( source.v1 ); - this.v2.copy( source.v2 ); - this.v3.copy( source.v3 ); - - return this; - - } - - toJSON() { - - const data = super.toJSON(); - - data.v0 = this.v0.toArray(); - data.v1 = this.v1.toArray(); - data.v2 = this.v2.toArray(); - data.v3 = this.v3.toArray(); - - return data; - - } - - fromJSON( json ) { - - super.fromJSON( json ); - - this.v0.fromArray( json.v0 ); - this.v1.fromArray( json.v1 ); - this.v2.fromArray( json.v2 ); - this.v3.fromArray( json.v3 ); - - return this; - - } - -} - -class CubicBezierCurve3 extends Curve { - - constructor( v0 = new Vector3(), v1 = new Vector3(), v2 = new Vector3(), v3 = new Vector3() ) { - - super(); - - this.isCubicBezierCurve3 = true; - - this.type = 'CubicBezierCurve3'; - - this.v0 = v0; - this.v1 = v1; - this.v2 = v2; - this.v3 = v3; - - } - - getPoint( t, optionalTarget = new Vector3() ) { - - const point = optionalTarget; - - const v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3; - - point.set( - CubicBezier( t, v0.x, v1.x, v2.x, v3.x ), - CubicBezier( t, v0.y, v1.y, v2.y, v3.y ), - CubicBezier( t, v0.z, v1.z, v2.z, v3.z ) - ); - - return point; - - } - - copy( source ) { - - super.copy( source ); - - this.v0.copy( source.v0 ); - this.v1.copy( source.v1 ); - this.v2.copy( source.v2 ); - this.v3.copy( source.v3 ); - - return this; - - } - - toJSON() { - - const data = super.toJSON(); - - data.v0 = this.v0.toArray(); - data.v1 = this.v1.toArray(); - data.v2 = this.v2.toArray(); - data.v3 = this.v3.toArray(); - - return data; - - } - - fromJSON( json ) { - - super.fromJSON( json ); - - this.v0.fromArray( json.v0 ); - this.v1.fromArray( json.v1 ); - this.v2.fromArray( json.v2 ); - this.v3.fromArray( json.v3 ); - - return this; - - } - -} - -class LineCurve extends Curve { - - constructor( v1 = new Vector2(), v2 = new Vector2() ) { - - super(); - - this.isLineCurve = true; - - this.type = 'LineCurve'; - - this.v1 = v1; - this.v2 = v2; - - } - - getPoint( t, optionalTarget = new Vector2() ) { - - const point = optionalTarget; - - if ( t === 1 ) { - - point.copy( this.v2 ); - - } else { - - point.copy( this.v2 ).sub( this.v1 ); - point.multiplyScalar( t ).add( this.v1 ); - - } - - return point; - - } - - // Line curve is linear, so we can overwrite default getPointAt - getPointAt( u, optionalTarget ) { - - return this.getPoint( u, optionalTarget ); - - } - - getTangent( t, optionalTarget = new Vector2() ) { - - return optionalTarget.subVectors( this.v2, this.v1 ).normalize(); - - } - - getTangentAt( u, optionalTarget ) { - - return this.getTangent( u, optionalTarget ); - - } - - copy( source ) { - - super.copy( source ); - - this.v1.copy( source.v1 ); - this.v2.copy( source.v2 ); - - return this; - - } - - toJSON() { - - const data = super.toJSON(); - - data.v1 = this.v1.toArray(); - data.v2 = this.v2.toArray(); - - return data; - - } - - fromJSON( json ) { - - super.fromJSON( json ); - - this.v1.fromArray( json.v1 ); - this.v2.fromArray( json.v2 ); - - return this; - - } - -} - -class LineCurve3 extends Curve { - - constructor( v1 = new Vector3(), v2 = new Vector3() ) { - - super(); - - this.isLineCurve3 = true; - - this.type = 'LineCurve3'; - - this.v1 = v1; - this.v2 = v2; - - } - - getPoint( t, optionalTarget = new Vector3() ) { - - const point = optionalTarget; - - if ( t === 1 ) { - - point.copy( this.v2 ); - - } else { - - point.copy( this.v2 ).sub( this.v1 ); - point.multiplyScalar( t ).add( this.v1 ); - - } - - return point; - - } - - // Line curve is linear, so we can overwrite default getPointAt - getPointAt( u, optionalTarget ) { - - return this.getPoint( u, optionalTarget ); - - } - - getTangent( t, optionalTarget = new Vector3() ) { - - return optionalTarget.subVectors( this.v2, this.v1 ).normalize(); - - } - - getTangentAt( u, optionalTarget ) { - - return this.getTangent( u, optionalTarget ); - - } - - copy( source ) { - - super.copy( source ); - - this.v1.copy( source.v1 ); - this.v2.copy( source.v2 ); - - return this; - - } - - toJSON() { - - const data = super.toJSON(); - - data.v1 = this.v1.toArray(); - data.v2 = this.v2.toArray(); - - return data; - - } - - fromJSON( json ) { - - super.fromJSON( json ); - - this.v1.fromArray( json.v1 ); - this.v2.fromArray( json.v2 ); - - return this; - - } - -} - -class QuadraticBezierCurve extends Curve { - - constructor( v0 = new Vector2(), v1 = new Vector2(), v2 = new Vector2() ) { - - super(); - - this.isQuadraticBezierCurve = true; - - this.type = 'QuadraticBezierCurve'; - - this.v0 = v0; - this.v1 = v1; - this.v2 = v2; - - } - - getPoint( t, optionalTarget = new Vector2() ) { - - const point = optionalTarget; - - const v0 = this.v0, v1 = this.v1, v2 = this.v2; - - point.set( - QuadraticBezier( t, v0.x, v1.x, v2.x ), - QuadraticBezier( t, v0.y, v1.y, v2.y ) - ); - - return point; - - } - - copy( source ) { - - super.copy( source ); - - this.v0.copy( source.v0 ); - this.v1.copy( source.v1 ); - this.v2.copy( source.v2 ); - - return this; - - } - - toJSON() { - - const data = super.toJSON(); - - data.v0 = this.v0.toArray(); - data.v1 = this.v1.toArray(); - data.v2 = this.v2.toArray(); - - return data; - - } - - fromJSON( json ) { - - super.fromJSON( json ); - - this.v0.fromArray( json.v0 ); - this.v1.fromArray( json.v1 ); - this.v2.fromArray( json.v2 ); - - return this; - - } - -} - -class QuadraticBezierCurve3 extends Curve { - - constructor( v0 = new Vector3(), v1 = new Vector3(), v2 = new Vector3() ) { - - super(); - - this.isQuadraticBezierCurve3 = true; - - this.type = 'QuadraticBezierCurve3'; - - this.v0 = v0; - this.v1 = v1; - this.v2 = v2; - - } - - getPoint( t, optionalTarget = new Vector3() ) { - - const point = optionalTarget; - - const v0 = this.v0, v1 = this.v1, v2 = this.v2; - - point.set( - QuadraticBezier( t, v0.x, v1.x, v2.x ), - QuadraticBezier( t, v0.y, v1.y, v2.y ), - QuadraticBezier( t, v0.z, v1.z, v2.z ) - ); - - return point; - - } - - copy( source ) { - - super.copy( source ); - - this.v0.copy( source.v0 ); - this.v1.copy( source.v1 ); - this.v2.copy( source.v2 ); - - return this; - - } - - toJSON() { - - const data = super.toJSON(); - - data.v0 = this.v0.toArray(); - data.v1 = this.v1.toArray(); - data.v2 = this.v2.toArray(); - - return data; - - } - - fromJSON( json ) { - - super.fromJSON( json ); - - this.v0.fromArray( json.v0 ); - this.v1.fromArray( json.v1 ); - this.v2.fromArray( json.v2 ); - - return this; - - } - -} - -class SplineCurve extends Curve { - - constructor( points = [] ) { - - super(); - - this.isSplineCurve = true; - - this.type = 'SplineCurve'; - - this.points = points; - - } - - getPoint( t, optionalTarget = new Vector2() ) { - - const point = optionalTarget; - - const points = this.points; - const p = ( points.length - 1 ) * t; - - const intPoint = Math.floor( p ); - const weight = p - intPoint; - - const p0 = points[ intPoint === 0 ? intPoint : intPoint - 1 ]; - const p1 = points[ intPoint ]; - const p2 = points[ intPoint > points.length - 2 ? points.length - 1 : intPoint + 1 ]; - const p3 = points[ intPoint > points.length - 3 ? points.length - 1 : intPoint + 2 ]; - - point.set( - CatmullRom( weight, p0.x, p1.x, p2.x, p3.x ), - CatmullRom( weight, p0.y, p1.y, p2.y, p3.y ) - ); - - return point; - - } - - copy( source ) { - - super.copy( source ); - - this.points = []; - - for ( let i = 0, l = source.points.length; i < l; i ++ ) { - - const point = source.points[ i ]; - - this.points.push( point.clone() ); - - } - - return this; - - } - - toJSON() { - - const data = super.toJSON(); - - data.points = []; - - for ( let i = 0, l = this.points.length; i < l; i ++ ) { - - const point = this.points[ i ]; - data.points.push( point.toArray() ); - - } - - return data; - - } - - fromJSON( json ) { - - super.fromJSON( json ); - - this.points = []; - - for ( let i = 0, l = json.points.length; i < l; i ++ ) { - - const point = json.points[ i ]; - this.points.push( new Vector2().fromArray( point ) ); - - } - - return this; - - } - -} - -var Curves = /*#__PURE__*/Object.freeze({ - __proto__: null, - ArcCurve: ArcCurve, - CatmullRomCurve3: CatmullRomCurve3, - CubicBezierCurve: CubicBezierCurve, - CubicBezierCurve3: CubicBezierCurve3, - EllipseCurve: EllipseCurve, - LineCurve: LineCurve, - LineCurve3: LineCurve3, - QuadraticBezierCurve: QuadraticBezierCurve, - QuadraticBezierCurve3: QuadraticBezierCurve3, - SplineCurve: SplineCurve -}); - -/************************************************************** - * Curved Path - a curve path is simply a array of connected - * curves, but retains the api of a curve - **************************************************************/ - -class CurvePath extends Curve { - - constructor() { - - super(); - - this.type = 'CurvePath'; - - this.curves = []; - this.autoClose = false; // Automatically closes the path - - } - - add( curve ) { - - this.curves.push( curve ); - - } - - closePath() { - - // Add a line curve if start and end of lines are not connected - const startPoint = this.curves[ 0 ].getPoint( 0 ); - const endPoint = this.curves[ this.curves.length - 1 ].getPoint( 1 ); - - if ( ! startPoint.equals( endPoint ) ) { - - const lineType = ( startPoint.isVector2 === true ) ? 'LineCurve' : 'LineCurve3'; - this.curves.push( new Curves[ lineType ]( endPoint, startPoint ) ); - - } - - return this; - - } - - // To get accurate point with reference to - // entire path distance at time t, - // following has to be done: - - // 1. Length of each sub path have to be known - // 2. Locate and identify type of curve - // 3. Get t for the curve - // 4. Return curve.getPointAt(t') - - getPoint( t, optionalTarget ) { - - const d = t * this.getLength(); - const curveLengths = this.getCurveLengths(); - let i = 0; - - // To think about boundaries points. - - while ( i < curveLengths.length ) { - - if ( curveLengths[ i ] >= d ) { - - const diff = curveLengths[ i ] - d; - const curve = this.curves[ i ]; - - const segmentLength = curve.getLength(); - const u = segmentLength === 0 ? 0 : 1 - diff / segmentLength; - - return curve.getPointAt( u, optionalTarget ); - - } - - i ++; - - } - - return null; - - // loop where sum != 0, sum > d , sum+1 1 && ! points[ points.length - 1 ].equals( points[ 0 ] ) ) { - - points.push( points[ 0 ] ); - - } - - return points; - - } - - copy( source ) { - - super.copy( source ); - - this.curves = []; - - for ( let i = 0, l = source.curves.length; i < l; i ++ ) { - - const curve = source.curves[ i ]; - - this.curves.push( curve.clone() ); - - } - - this.autoClose = source.autoClose; - - return this; - - } - - toJSON() { - - const data = super.toJSON(); - - data.autoClose = this.autoClose; - data.curves = []; - - for ( let i = 0, l = this.curves.length; i < l; i ++ ) { - - const curve = this.curves[ i ]; - data.curves.push( curve.toJSON() ); - - } - - return data; - - } - - fromJSON( json ) { - - super.fromJSON( json ); - - this.autoClose = json.autoClose; - this.curves = []; - - for ( let i = 0, l = json.curves.length; i < l; i ++ ) { - - const curve = json.curves[ i ]; - this.curves.push( new Curves[ curve.type ]().fromJSON( curve ) ); - - } - - return this; - - } - -} - -class Path extends CurvePath { - - constructor( points ) { - - super(); - - this.type = 'Path'; - - this.currentPoint = new Vector2(); - - if ( points ) { - - this.setFromPoints( points ); - - } - - } - - setFromPoints( points ) { - - this.moveTo( points[ 0 ].x, points[ 0 ].y ); - - for ( let i = 1, l = points.length; i < l; i ++ ) { - - this.lineTo( points[ i ].x, points[ i ].y ); - - } - - return this; - - } - - moveTo( x, y ) { - - this.currentPoint.set( x, y ); // TODO consider referencing vectors instead of copying? - - return this; - - } - - lineTo( x, y ) { - - const curve = new LineCurve( this.currentPoint.clone(), new Vector2( x, y ) ); - this.curves.push( curve ); - - this.currentPoint.set( x, y ); - - return this; - - } - - quadraticCurveTo( aCPx, aCPy, aX, aY ) { - - const curve = new QuadraticBezierCurve( - this.currentPoint.clone(), - new Vector2( aCPx, aCPy ), - new Vector2( aX, aY ) - ); - - this.curves.push( curve ); - - this.currentPoint.set( aX, aY ); - - return this; - - } - - bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) { - - const curve = new CubicBezierCurve( - this.currentPoint.clone(), - new Vector2( aCP1x, aCP1y ), - new Vector2( aCP2x, aCP2y ), - new Vector2( aX, aY ) - ); - - this.curves.push( curve ); - - this.currentPoint.set( aX, aY ); - - return this; - - } - - splineThru( pts /*Array of Vector*/ ) { - - const npts = [ this.currentPoint.clone() ].concat( pts ); - - const curve = new SplineCurve( npts ); - this.curves.push( curve ); - - this.currentPoint.copy( pts[ pts.length - 1 ] ); - - return this; - - } - - arc( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { - - const x0 = this.currentPoint.x; - const y0 = this.currentPoint.y; - - this.absarc( aX + x0, aY + y0, aRadius, - aStartAngle, aEndAngle, aClockwise ); - - return this; - - } - - absarc( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { - - this.absellipse( aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise ); - - return this; - - } - - ellipse( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) { - - const x0 = this.currentPoint.x; - const y0 = this.currentPoint.y; - - this.absellipse( aX + x0, aY + y0, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ); - - return this; - - } - - absellipse( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) { - - const curve = new EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ); - - if ( this.curves.length > 0 ) { - - // if a previous curve is present, attempt to join - const firstPoint = curve.getPoint( 0 ); - - if ( ! firstPoint.equals( this.currentPoint ) ) { - - this.lineTo( firstPoint.x, firstPoint.y ); - - } - - } - - this.curves.push( curve ); - - const lastPoint = curve.getPoint( 1 ); - this.currentPoint.copy( lastPoint ); - - return this; - - } - - copy( source ) { - - super.copy( source ); - - this.currentPoint.copy( source.currentPoint ); - - return this; - - } - - toJSON() { - - const data = super.toJSON(); - - data.currentPoint = this.currentPoint.toArray(); - - return data; - - } - - fromJSON( json ) { - - super.fromJSON( json ); - - this.currentPoint.fromArray( json.currentPoint ); - - return this; - - } - -} - -class LatheGeometry extends BufferGeometry { - - constructor( points = [ new Vector2( 0, - 0.5 ), new Vector2( 0.5, 0 ), new Vector2( 0, 0.5 ) ], segments = 12, phiStart = 0, phiLength = Math.PI * 2 ) { - - super(); - - this.type = 'LatheGeometry'; - - this.parameters = { - points: points, - segments: segments, - phiStart: phiStart, - phiLength: phiLength - }; - - segments = Math.floor( segments ); - - // clamp phiLength so it's in range of [ 0, 2PI ] - - phiLength = clamp( phiLength, 0, Math.PI * 2 ); - - // buffers - - const indices = []; - const vertices = []; - const uvs = []; - const initNormals = []; - const normals = []; - - // helper variables - - const inverseSegments = 1.0 / segments; - const vertex = new Vector3(); - const uv = new Vector2(); - const normal = new Vector3(); - const curNormal = new Vector3(); - const prevNormal = new Vector3(); - let dx = 0; - let dy = 0; - - // pre-compute normals for initial "meridian" - - for ( let j = 0; j <= ( points.length - 1 ); j ++ ) { - - switch ( j ) { - - case 0: // special handling for 1st vertex on path - - dx = points[ j + 1 ].x - points[ j ].x; - dy = points[ j + 1 ].y - points[ j ].y; - - normal.x = dy * 1.0; - normal.y = - dx; - normal.z = dy * 0.0; - - prevNormal.copy( normal ); - - normal.normalize(); - - initNormals.push( normal.x, normal.y, normal.z ); - - break; - - case ( points.length - 1 ): // special handling for last Vertex on path - - initNormals.push( prevNormal.x, prevNormal.y, prevNormal.z ); - - break; - - default: // default handling for all vertices in between - - dx = points[ j + 1 ].x - points[ j ].x; - dy = points[ j + 1 ].y - points[ j ].y; - - normal.x = dy * 1.0; - normal.y = - dx; - normal.z = dy * 0.0; - - curNormal.copy( normal ); - - normal.x += prevNormal.x; - normal.y += prevNormal.y; - normal.z += prevNormal.z; - - normal.normalize(); - - initNormals.push( normal.x, normal.y, normal.z ); - - prevNormal.copy( curNormal ); - - } - - } - - // generate vertices, uvs and normals - - for ( let i = 0; i <= segments; i ++ ) { - - const phi = phiStart + i * inverseSegments * phiLength; - - const sin = Math.sin( phi ); - const cos = Math.cos( phi ); - - for ( let j = 0; j <= ( points.length - 1 ); j ++ ) { - - // vertex - - vertex.x = points[ j ].x * sin; - vertex.y = points[ j ].y; - vertex.z = points[ j ].x * cos; - - vertices.push( vertex.x, vertex.y, vertex.z ); - - // uv - - uv.x = i / segments; - uv.y = j / ( points.length - 1 ); - - uvs.push( uv.x, uv.y ); - - // normal - - const x = initNormals[ 3 * j + 0 ] * sin; - const y = initNormals[ 3 * j + 1 ]; - const z = initNormals[ 3 * j + 0 ] * cos; - - normals.push( x, y, z ); - - } - - } - - // indices - - for ( let i = 0; i < segments; i ++ ) { - - for ( let j = 0; j < ( points.length - 1 ); j ++ ) { - - const base = j + i * points.length; - - const a = base; - const b = base + points.length; - const c = base + points.length + 1; - const d = base + 1; - - // faces - - indices.push( a, b, d ); - indices.push( c, d, b ); - - } - - } - - // build geometry - - this.setIndex( indices ); - this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - - } - - copy( source ) { - - super.copy( source ); - - this.parameters = Object.assign( {}, source.parameters ); - - return this; - - } - - static fromJSON( data ) { - - return new LatheGeometry( data.points, data.segments, data.phiStart, data.phiLength ); - - } - -} - -class CapsuleGeometry extends LatheGeometry { - - constructor( radius = 1, length = 1, capSegments = 4, radialSegments = 8 ) { - - const path = new Path(); - path.absarc( 0, - length / 2, radius, Math.PI * 1.5, 0 ); - path.absarc( 0, length / 2, radius, 0, Math.PI * 0.5 ); - - super( path.getPoints( capSegments ), radialSegments ); - - this.type = 'CapsuleGeometry'; - - this.parameters = { - radius: radius, - length: length, - capSegments: capSegments, - radialSegments: radialSegments, - }; - - } - - static fromJSON( data ) { - - return new CapsuleGeometry( data.radius, data.length, data.capSegments, data.radialSegments ); - - } - -} - -class CircleGeometry extends BufferGeometry { - - constructor( radius = 1, segments = 32, thetaStart = 0, thetaLength = Math.PI * 2 ) { - - super(); - - this.type = 'CircleGeometry'; - - this.parameters = { - radius: radius, - segments: segments, - thetaStart: thetaStart, - thetaLength: thetaLength - }; - - segments = Math.max( 3, segments ); - - // buffers - - const indices = []; - const vertices = []; - const normals = []; - const uvs = []; - - // helper variables - - const vertex = new Vector3(); - const uv = new Vector2(); - - // center point - - vertices.push( 0, 0, 0 ); - normals.push( 0, 0, 1 ); - uvs.push( 0.5, 0.5 ); - - for ( let s = 0, i = 3; s <= segments; s ++, i += 3 ) { - - const segment = thetaStart + s / segments * thetaLength; - - // vertex - - vertex.x = radius * Math.cos( segment ); - vertex.y = radius * Math.sin( segment ); - - vertices.push( vertex.x, vertex.y, vertex.z ); - - // normal - - normals.push( 0, 0, 1 ); - - // uvs - - uv.x = ( vertices[ i ] / radius + 1 ) / 2; - uv.y = ( vertices[ i + 1 ] / radius + 1 ) / 2; - - uvs.push( uv.x, uv.y ); - - } - - // indices - - for ( let i = 1; i <= segments; i ++ ) { - - indices.push( i, i + 1, 0 ); - - } - - // build geometry - - this.setIndex( indices ); - this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - - } - - copy( source ) { - - super.copy( source ); - - this.parameters = Object.assign( {}, source.parameters ); - - return this; - - } - - static fromJSON( data ) { - - return new CircleGeometry( data.radius, data.segments, data.thetaStart, data.thetaLength ); - - } - -} - -class CylinderGeometry extends BufferGeometry { - - constructor( radiusTop = 1, radiusBottom = 1, height = 1, radialSegments = 32, heightSegments = 1, openEnded = false, thetaStart = 0, thetaLength = Math.PI * 2 ) { - - super(); - - this.type = 'CylinderGeometry'; - - this.parameters = { - radiusTop: radiusTop, - radiusBottom: radiusBottom, - height: height, - radialSegments: radialSegments, - heightSegments: heightSegments, - openEnded: openEnded, - thetaStart: thetaStart, - thetaLength: thetaLength - }; - - const scope = this; - - radialSegments = Math.floor( radialSegments ); - heightSegments = Math.floor( heightSegments ); - - // buffers - - const indices = []; - const vertices = []; - const normals = []; - const uvs = []; - - // helper variables - - let index = 0; - const indexArray = []; - const halfHeight = height / 2; - let groupStart = 0; - - // generate geometry - - generateTorso(); - - if ( openEnded === false ) { - - if ( radiusTop > 0 ) generateCap( true ); - if ( radiusBottom > 0 ) generateCap( false ); - - } - - // build geometry - - this.setIndex( indices ); - this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - - function generateTorso() { - - const normal = new Vector3(); - const vertex = new Vector3(); - - let groupCount = 0; - - // this will be used to calculate the normal - const slope = ( radiusBottom - radiusTop ) / height; - - // generate vertices, normals and uvs - - for ( let y = 0; y <= heightSegments; y ++ ) { - - const indexRow = []; - - const v = y / heightSegments; - - // calculate the radius of the current row - - const radius = v * ( radiusBottom - radiusTop ) + radiusTop; - - for ( let x = 0; x <= radialSegments; x ++ ) { - - const u = x / radialSegments; - - const theta = u * thetaLength + thetaStart; - - const sinTheta = Math.sin( theta ); - const cosTheta = Math.cos( theta ); - - // vertex - - vertex.x = radius * sinTheta; - vertex.y = - v * height + halfHeight; - vertex.z = radius * cosTheta; - vertices.push( vertex.x, vertex.y, vertex.z ); - - // normal - - normal.set( sinTheta, slope, cosTheta ).normalize(); - normals.push( normal.x, normal.y, normal.z ); - - // uv - - uvs.push( u, 1 - v ); - - // save index of vertex in respective row - - indexRow.push( index ++ ); - - } - - // now save vertices of the row in our index array - - indexArray.push( indexRow ); - - } - - // generate indices - - for ( let x = 0; x < radialSegments; x ++ ) { - - for ( let y = 0; y < heightSegments; y ++ ) { - - // we use the index array to access the correct indices - - const a = indexArray[ y ][ x ]; - const b = indexArray[ y + 1 ][ x ]; - const c = indexArray[ y + 1 ][ x + 1 ]; - const d = indexArray[ y ][ x + 1 ]; - - // faces - - indices.push( a, b, d ); - indices.push( b, c, d ); - - // update group counter - - groupCount += 6; - - } - - } - - // add a group to the geometry. this will ensure multi material support - - scope.addGroup( groupStart, groupCount, 0 ); - - // calculate new start value for groups - - groupStart += groupCount; - - } - - function generateCap( top ) { - - // save the index of the first center vertex - const centerIndexStart = index; - - const uv = new Vector2(); - const vertex = new Vector3(); - - let groupCount = 0; - - const radius = ( top === true ) ? radiusTop : radiusBottom; - const sign = ( top === true ) ? 1 : - 1; - - // first we generate the center vertex data of the cap. - // because the geometry needs one set of uvs per face, - // we must generate a center vertex per face/segment - - for ( let x = 1; x <= radialSegments; x ++ ) { - - // vertex - - vertices.push( 0, halfHeight * sign, 0 ); - - // normal - - normals.push( 0, sign, 0 ); - - // uv - - uvs.push( 0.5, 0.5 ); - - // increase index - - index ++; - - } - - // save the index of the last center vertex - const centerIndexEnd = index; - - // now we generate the surrounding vertices, normals and uvs - - for ( let x = 0; x <= radialSegments; x ++ ) { - - const u = x / radialSegments; - const theta = u * thetaLength + thetaStart; - - const cosTheta = Math.cos( theta ); - const sinTheta = Math.sin( theta ); - - // vertex - - vertex.x = radius * sinTheta; - vertex.y = halfHeight * sign; - vertex.z = radius * cosTheta; - vertices.push( vertex.x, vertex.y, vertex.z ); - - // normal - - normals.push( 0, sign, 0 ); - - // uv - - uv.x = ( cosTheta * 0.5 ) + 0.5; - uv.y = ( sinTheta * 0.5 * sign ) + 0.5; - uvs.push( uv.x, uv.y ); - - // increase index - - index ++; - - } - - // generate indices - - for ( let x = 0; x < radialSegments; x ++ ) { - - const c = centerIndexStart + x; - const i = centerIndexEnd + x; - - if ( top === true ) { - - // face top - - indices.push( i, i + 1, c ); - - } else { - - // face bottom - - indices.push( i + 1, i, c ); - - } - - groupCount += 3; - - } - - // add a group to the geometry. this will ensure multi material support - - scope.addGroup( groupStart, groupCount, top === true ? 1 : 2 ); - - // calculate new start value for groups - - groupStart += groupCount; - - } - - } - - copy( source ) { - - super.copy( source ); - - this.parameters = Object.assign( {}, source.parameters ); - - return this; - - } - - static fromJSON( data ) { - - return new CylinderGeometry( data.radiusTop, data.radiusBottom, data.height, data.radialSegments, data.heightSegments, data.openEnded, data.thetaStart, data.thetaLength ); - - } - -} - -class ConeGeometry extends CylinderGeometry { - - constructor( radius = 1, height = 1, radialSegments = 32, heightSegments = 1, openEnded = false, thetaStart = 0, thetaLength = Math.PI * 2 ) { - - super( 0, radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ); - - this.type = 'ConeGeometry'; - - this.parameters = { - radius: radius, - height: height, - radialSegments: radialSegments, - heightSegments: heightSegments, - openEnded: openEnded, - thetaStart: thetaStart, - thetaLength: thetaLength - }; - - } - - static fromJSON( data ) { - - return new ConeGeometry( data.radius, data.height, data.radialSegments, data.heightSegments, data.openEnded, data.thetaStart, data.thetaLength ); - - } - -} - -class PolyhedronGeometry extends BufferGeometry { - - constructor( vertices = [], indices = [], radius = 1, detail = 0 ) { - - super(); - - this.type = 'PolyhedronGeometry'; - - this.parameters = { - vertices: vertices, - indices: indices, - radius: radius, - detail: detail - }; - - // default buffer data - - const vertexBuffer = []; - const uvBuffer = []; - - // the subdivision creates the vertex buffer data - - subdivide( detail ); - - // all vertices should lie on a conceptual sphere with a given radius - - applyRadius( radius ); - - // finally, create the uv data - - generateUVs(); - - // build non-indexed geometry - - this.setAttribute( 'position', new Float32BufferAttribute( vertexBuffer, 3 ) ); - this.setAttribute( 'normal', new Float32BufferAttribute( vertexBuffer.slice(), 3 ) ); - this.setAttribute( 'uv', new Float32BufferAttribute( uvBuffer, 2 ) ); - - if ( detail === 0 ) { - - this.computeVertexNormals(); // flat normals - - } else { - - this.normalizeNormals(); // smooth normals - - } - - // helper functions - - function subdivide( detail ) { - - const a = new Vector3(); - const b = new Vector3(); - const c = new Vector3(); - - // iterate over all faces and apply a subdivision with the given detail value - - for ( let i = 0; i < indices.length; i += 3 ) { - - // get the vertices of the face - - getVertexByIndex( indices[ i + 0 ], a ); - getVertexByIndex( indices[ i + 1 ], b ); - getVertexByIndex( indices[ i + 2 ], c ); - - // perform subdivision - - subdivideFace( a, b, c, detail ); - - } - - } - - function subdivideFace( a, b, c, detail ) { - - const cols = detail + 1; - - // we use this multidimensional array as a data structure for creating the subdivision - - const v = []; - - // construct all of the vertices for this subdivision - - for ( let i = 0; i <= cols; i ++ ) { - - v[ i ] = []; - - const aj = a.clone().lerp( c, i / cols ); - const bj = b.clone().lerp( c, i / cols ); - - const rows = cols - i; - - for ( let j = 0; j <= rows; j ++ ) { - - if ( j === 0 && i === cols ) { - - v[ i ][ j ] = aj; - - } else { - - v[ i ][ j ] = aj.clone().lerp( bj, j / rows ); - - } - - } - - } - - // construct all of the faces - - for ( let i = 0; i < cols; i ++ ) { - - for ( let j = 0; j < 2 * ( cols - i ) - 1; j ++ ) { - - const k = Math.floor( j / 2 ); - - if ( j % 2 === 0 ) { - - pushVertex( v[ i ][ k + 1 ] ); - pushVertex( v[ i + 1 ][ k ] ); - pushVertex( v[ i ][ k ] ); - - } else { - - pushVertex( v[ i ][ k + 1 ] ); - pushVertex( v[ i + 1 ][ k + 1 ] ); - pushVertex( v[ i + 1 ][ k ] ); - - } - - } - - } - - } - - function applyRadius( radius ) { - - const vertex = new Vector3(); - - // iterate over the entire buffer and apply the radius to each vertex - - for ( let i = 0; i < vertexBuffer.length; i += 3 ) { - - vertex.x = vertexBuffer[ i + 0 ]; - vertex.y = vertexBuffer[ i + 1 ]; - vertex.z = vertexBuffer[ i + 2 ]; - - vertex.normalize().multiplyScalar( radius ); - - vertexBuffer[ i + 0 ] = vertex.x; - vertexBuffer[ i + 1 ] = vertex.y; - vertexBuffer[ i + 2 ] = vertex.z; - - } - - } - - function generateUVs() { - - const vertex = new Vector3(); - - for ( let i = 0; i < vertexBuffer.length; i += 3 ) { - - vertex.x = vertexBuffer[ i + 0 ]; - vertex.y = vertexBuffer[ i + 1 ]; - vertex.z = vertexBuffer[ i + 2 ]; - - const u = azimuth( vertex ) / 2 / Math.PI + 0.5; - const v = inclination( vertex ) / Math.PI + 0.5; - uvBuffer.push( u, 1 - v ); - - } - - correctUVs(); - - correctSeam(); - - } - - function correctSeam() { - - // handle case when face straddles the seam, see #3269 - - for ( let i = 0; i < uvBuffer.length; i += 6 ) { - - // uv data of a single face - - const x0 = uvBuffer[ i + 0 ]; - const x1 = uvBuffer[ i + 2 ]; - const x2 = uvBuffer[ i + 4 ]; - - const max = Math.max( x0, x1, x2 ); - const min = Math.min( x0, x1, x2 ); - - // 0.9 is somewhat arbitrary - - if ( max > 0.9 && min < 0.1 ) { - - if ( x0 < 0.2 ) uvBuffer[ i + 0 ] += 1; - if ( x1 < 0.2 ) uvBuffer[ i + 2 ] += 1; - if ( x2 < 0.2 ) uvBuffer[ i + 4 ] += 1; - - } - - } - - } - - function pushVertex( vertex ) { - - vertexBuffer.push( vertex.x, vertex.y, vertex.z ); - - } - - function getVertexByIndex( index, vertex ) { - - const stride = index * 3; - - vertex.x = vertices[ stride + 0 ]; - vertex.y = vertices[ stride + 1 ]; - vertex.z = vertices[ stride + 2 ]; - - } - - function correctUVs() { - - const a = new Vector3(); - const b = new Vector3(); - const c = new Vector3(); - - const centroid = new Vector3(); - - const uvA = new Vector2(); - const uvB = new Vector2(); - const uvC = new Vector2(); - - for ( let i = 0, j = 0; i < vertexBuffer.length; i += 9, j += 6 ) { - - a.set( vertexBuffer[ i + 0 ], vertexBuffer[ i + 1 ], vertexBuffer[ i + 2 ] ); - b.set( vertexBuffer[ i + 3 ], vertexBuffer[ i + 4 ], vertexBuffer[ i + 5 ] ); - c.set( vertexBuffer[ i + 6 ], vertexBuffer[ i + 7 ], vertexBuffer[ i + 8 ] ); - - uvA.set( uvBuffer[ j + 0 ], uvBuffer[ j + 1 ] ); - uvB.set( uvBuffer[ j + 2 ], uvBuffer[ j + 3 ] ); - uvC.set( uvBuffer[ j + 4 ], uvBuffer[ j + 5 ] ); - - centroid.copy( a ).add( b ).add( c ).divideScalar( 3 ); - - const azi = azimuth( centroid ); - - correctUV( uvA, j + 0, a, azi ); - correctUV( uvB, j + 2, b, azi ); - correctUV( uvC, j + 4, c, azi ); - - } - - } - - function correctUV( uv, stride, vector, azimuth ) { - - if ( ( azimuth < 0 ) && ( uv.x === 1 ) ) { - - uvBuffer[ stride ] = uv.x - 1; - - } - - if ( ( vector.x === 0 ) && ( vector.z === 0 ) ) { - - uvBuffer[ stride ] = azimuth / 2 / Math.PI + 0.5; - - } - - } - - // Angle around the Y axis, counter-clockwise when looking from above. - - function azimuth( vector ) { - - return Math.atan2( vector.z, - vector.x ); - - } - - - // Angle above the XZ plane. - - function inclination( vector ) { - - return Math.atan2( - vector.y, Math.sqrt( ( vector.x * vector.x ) + ( vector.z * vector.z ) ) ); - - } - - } - - copy( source ) { - - super.copy( source ); - - this.parameters = Object.assign( {}, source.parameters ); - - return this; - - } - - static fromJSON( data ) { - - return new PolyhedronGeometry( data.vertices, data.indices, data.radius, data.details ); - - } - -} - -class DodecahedronGeometry extends PolyhedronGeometry { - - constructor( radius = 1, detail = 0 ) { - - const t = ( 1 + Math.sqrt( 5 ) ) / 2; - const r = 1 / t; - - const vertices = [ - - // (±1, ±1, ±1) - - 1, - 1, - 1, - 1, - 1, 1, - - 1, 1, - 1, - 1, 1, 1, - 1, - 1, - 1, 1, - 1, 1, - 1, 1, - 1, 1, 1, 1, - - // (0, ±1/φ, ±φ) - 0, - r, - t, 0, - r, t, - 0, r, - t, 0, r, t, - - // (±1/φ, ±φ, 0) - - r, - t, 0, - r, t, 0, - r, - t, 0, r, t, 0, - - // (±φ, 0, ±1/φ) - - t, 0, - r, t, 0, - r, - - t, 0, r, t, 0, r - ]; - - const indices = [ - 3, 11, 7, 3, 7, 15, 3, 15, 13, - 7, 19, 17, 7, 17, 6, 7, 6, 15, - 17, 4, 8, 17, 8, 10, 17, 10, 6, - 8, 0, 16, 8, 16, 2, 8, 2, 10, - 0, 12, 1, 0, 1, 18, 0, 18, 16, - 6, 10, 2, 6, 2, 13, 6, 13, 15, - 2, 16, 18, 2, 18, 3, 2, 3, 13, - 18, 1, 9, 18, 9, 11, 18, 11, 3, - 4, 14, 12, 4, 12, 0, 4, 0, 8, - 11, 9, 5, 11, 5, 19, 11, 19, 7, - 19, 5, 14, 19, 14, 4, 19, 4, 17, - 1, 12, 14, 1, 14, 5, 1, 5, 9 - ]; - - super( vertices, indices, radius, detail ); - - this.type = 'DodecahedronGeometry'; - - this.parameters = { - radius: radius, - detail: detail - }; - - } - - static fromJSON( data ) { - - return new DodecahedronGeometry( data.radius, data.detail ); - - } - -} - -const _v0 = /*@__PURE__*/ new Vector3(); -const _v1$1 = /*@__PURE__*/ new Vector3(); -const _normal = /*@__PURE__*/ new Vector3(); -const _triangle = /*@__PURE__*/ new Triangle(); - -class EdgesGeometry extends BufferGeometry { - - constructor( geometry = null, thresholdAngle = 1 ) { - - super(); - - this.type = 'EdgesGeometry'; - - this.parameters = { - geometry: geometry, - thresholdAngle: thresholdAngle - }; - - if ( geometry !== null ) { - - const precisionPoints = 4; - const precision = Math.pow( 10, precisionPoints ); - const thresholdDot = Math.cos( DEG2RAD * thresholdAngle ); - - const indexAttr = geometry.getIndex(); - const positionAttr = geometry.getAttribute( 'position' ); - const indexCount = indexAttr ? indexAttr.count : positionAttr.count; - - const indexArr = [ 0, 0, 0 ]; - const vertKeys = [ 'a', 'b', 'c' ]; - const hashes = new Array( 3 ); - - const edgeData = {}; - const vertices = []; - for ( let i = 0; i < indexCount; i += 3 ) { - - if ( indexAttr ) { - - indexArr[ 0 ] = indexAttr.getX( i ); - indexArr[ 1 ] = indexAttr.getX( i + 1 ); - indexArr[ 2 ] = indexAttr.getX( i + 2 ); - - } else { - - indexArr[ 0 ] = i; - indexArr[ 1 ] = i + 1; - indexArr[ 2 ] = i + 2; - - } - - const { a, b, c } = _triangle; - a.fromBufferAttribute( positionAttr, indexArr[ 0 ] ); - b.fromBufferAttribute( positionAttr, indexArr[ 1 ] ); - c.fromBufferAttribute( positionAttr, indexArr[ 2 ] ); - _triangle.getNormal( _normal ); - - // create hashes for the edge from the vertices - hashes[ 0 ] = `${ Math.round( a.x * precision ) },${ Math.round( a.y * precision ) },${ Math.round( a.z * precision ) }`; - hashes[ 1 ] = `${ Math.round( b.x * precision ) },${ Math.round( b.y * precision ) },${ Math.round( b.z * precision ) }`; - hashes[ 2 ] = `${ Math.round( c.x * precision ) },${ Math.round( c.y * precision ) },${ Math.round( c.z * precision ) }`; - - // skip degenerate triangles - if ( hashes[ 0 ] === hashes[ 1 ] || hashes[ 1 ] === hashes[ 2 ] || hashes[ 2 ] === hashes[ 0 ] ) { - - continue; - - } - - // iterate over every edge - for ( let j = 0; j < 3; j ++ ) { - - // get the first and next vertex making up the edge - const jNext = ( j + 1 ) % 3; - const vecHash0 = hashes[ j ]; - const vecHash1 = hashes[ jNext ]; - const v0 = _triangle[ vertKeys[ j ] ]; - const v1 = _triangle[ vertKeys[ jNext ] ]; - - const hash = `${ vecHash0 }_${ vecHash1 }`; - const reverseHash = `${ vecHash1 }_${ vecHash0 }`; - - if ( reverseHash in edgeData && edgeData[ reverseHash ] ) { - - // if we found a sibling edge add it into the vertex array if - // it meets the angle threshold and delete the edge from the map. - if ( _normal.dot( edgeData[ reverseHash ].normal ) <= thresholdDot ) { - - vertices.push( v0.x, v0.y, v0.z ); - vertices.push( v1.x, v1.y, v1.z ); - - } - - edgeData[ reverseHash ] = null; - - } else if ( ! ( hash in edgeData ) ) { - - // if we've already got an edge here then skip adding a new one - edgeData[ hash ] = { - - index0: indexArr[ j ], - index1: indexArr[ jNext ], - normal: _normal.clone(), - - }; - - } - - } - - } - - // iterate over all remaining, unmatched edges and add them to the vertex array - for ( const key in edgeData ) { - - if ( edgeData[ key ] ) { - - const { index0, index1 } = edgeData[ key ]; - _v0.fromBufferAttribute( positionAttr, index0 ); - _v1$1.fromBufferAttribute( positionAttr, index1 ); - - vertices.push( _v0.x, _v0.y, _v0.z ); - vertices.push( _v1$1.x, _v1$1.y, _v1$1.z ); - - } - - } - - this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - - } - - } - - copy( source ) { - - super.copy( source ); - - this.parameters = Object.assign( {}, source.parameters ); - - return this; - - } - -} - -class Shape extends Path { - - constructor( points ) { - - super( points ); - - this.uuid = generateUUID(); - - this.type = 'Shape'; - - this.holes = []; - - } - - getPointsHoles( divisions ) { - - const holesPts = []; - - for ( let i = 0, l = this.holes.length; i < l; i ++ ) { - - holesPts[ i ] = this.holes[ i ].getPoints( divisions ); - - } - - return holesPts; - - } - - // get points of shape and holes (keypoints based on segments parameter) - - extractPoints( divisions ) { - - return { - - shape: this.getPoints( divisions ), - holes: this.getPointsHoles( divisions ) - - }; - - } - - copy( source ) { - - super.copy( source ); - - this.holes = []; - - for ( let i = 0, l = source.holes.length; i < l; i ++ ) { - - const hole = source.holes[ i ]; - - this.holes.push( hole.clone() ); - - } - - return this; - - } - - toJSON() { - - const data = super.toJSON(); - - data.uuid = this.uuid; - data.holes = []; - - for ( let i = 0, l = this.holes.length; i < l; i ++ ) { - - const hole = this.holes[ i ]; - data.holes.push( hole.toJSON() ); - - } - - return data; - - } - - fromJSON( json ) { - - super.fromJSON( json ); - - this.uuid = json.uuid; - this.holes = []; - - for ( let i = 0, l = json.holes.length; i < l; i ++ ) { - - const hole = json.holes[ i ]; - this.holes.push( new Path().fromJSON( hole ) ); - - } - - return this; - - } - -} - -/** - * Port from https://github.com/mapbox/earcut (v2.2.4) - */ - -const Earcut = { - - triangulate: function ( data, holeIndices, dim = 2 ) { - - const hasHoles = holeIndices && holeIndices.length; - const outerLen = hasHoles ? holeIndices[ 0 ] * dim : data.length; - let outerNode = linkedList( data, 0, outerLen, dim, true ); - const triangles = []; - - if ( ! outerNode || outerNode.next === outerNode.prev ) return triangles; - - let minX, minY, maxX, maxY, x, y, invSize; - - if ( hasHoles ) outerNode = eliminateHoles( data, holeIndices, outerNode, dim ); - - // if the shape is not too simple, we'll use z-order curve hash later; calculate polygon bbox - if ( data.length > 80 * dim ) { - - minX = maxX = data[ 0 ]; - minY = maxY = data[ 1 ]; - - for ( let i = dim; i < outerLen; i += dim ) { - - x = data[ i ]; - y = data[ i + 1 ]; - if ( x < minX ) minX = x; - if ( y < minY ) minY = y; - if ( x > maxX ) maxX = x; - if ( y > maxY ) maxY = y; - - } - - // minX, minY and invSize are later used to transform coords into integers for z-order calculation - invSize = Math.max( maxX - minX, maxY - minY ); - invSize = invSize !== 0 ? 32767 / invSize : 0; - - } - - earcutLinked( outerNode, triangles, dim, minX, minY, invSize, 0 ); - - return triangles; - - } - -}; - -// create a circular doubly linked list from polygon points in the specified winding order -function linkedList( data, start, end, dim, clockwise ) { - - let i, last; - - if ( clockwise === ( signedArea( data, start, end, dim ) > 0 ) ) { - - for ( i = start; i < end; i += dim ) last = insertNode( i, data[ i ], data[ i + 1 ], last ); - - } else { - - for ( i = end - dim; i >= start; i -= dim ) last = insertNode( i, data[ i ], data[ i + 1 ], last ); - - } - - if ( last && equals( last, last.next ) ) { - - removeNode( last ); - last = last.next; - - } - - return last; - -} - -// eliminate colinear or duplicate points -function filterPoints( start, end ) { - - if ( ! start ) return start; - if ( ! end ) end = start; - - let p = start, - again; - do { - - again = false; - - if ( ! p.steiner && ( equals( p, p.next ) || area( p.prev, p, p.next ) === 0 ) ) { - - removeNode( p ); - p = end = p.prev; - if ( p === p.next ) break; - again = true; - - } else { - - p = p.next; - - } - - } while ( again || p !== end ); - - return end; - -} - -// main ear slicing loop which triangulates a polygon (given as a linked list) -function earcutLinked( ear, triangles, dim, minX, minY, invSize, pass ) { - - if ( ! ear ) return; - - // interlink polygon nodes in z-order - if ( ! pass && invSize ) indexCurve( ear, minX, minY, invSize ); - - let stop = ear, - prev, next; - - // iterate through ears, slicing them one by one - while ( ear.prev !== ear.next ) { - - prev = ear.prev; - next = ear.next; - - if ( invSize ? isEarHashed( ear, minX, minY, invSize ) : isEar( ear ) ) { - - // cut off the triangle - triangles.push( prev.i / dim | 0 ); - triangles.push( ear.i / dim | 0 ); - triangles.push( next.i / dim | 0 ); - - removeNode( ear ); - - // skipping the next vertex leads to less sliver triangles - ear = next.next; - stop = next.next; - - continue; - - } - - ear = next; - - // if we looped through the whole remaining polygon and can't find any more ears - if ( ear === stop ) { - - // try filtering points and slicing again - if ( ! pass ) { - - earcutLinked( filterPoints( ear ), triangles, dim, minX, minY, invSize, 1 ); - - // if this didn't work, try curing all small self-intersections locally - - } else if ( pass === 1 ) { - - ear = cureLocalIntersections( filterPoints( ear ), triangles, dim ); - earcutLinked( ear, triangles, dim, minX, minY, invSize, 2 ); - - // as a last resort, try splitting the remaining polygon into two - - } else if ( pass === 2 ) { - - splitEarcut( ear, triangles, dim, minX, minY, invSize ); - - } - - break; - - } - - } - -} - -// check whether a polygon node forms a valid ear with adjacent nodes -function isEar( ear ) { - - const a = ear.prev, - b = ear, - c = ear.next; - - if ( area( a, b, c ) >= 0 ) return false; // reflex, can't be an ear - - // now make sure we don't have other points inside the potential ear - const ax = a.x, bx = b.x, cx = c.x, ay = a.y, by = b.y, cy = c.y; - - // triangle bbox; min & max are calculated like this for speed - const x0 = ax < bx ? ( ax < cx ? ax : cx ) : ( bx < cx ? bx : cx ), - y0 = ay < by ? ( ay < cy ? ay : cy ) : ( by < cy ? by : cy ), - x1 = ax > bx ? ( ax > cx ? ax : cx ) : ( bx > cx ? bx : cx ), - y1 = ay > by ? ( ay > cy ? ay : cy ) : ( by > cy ? by : cy ); - - let p = c.next; - while ( p !== a ) { - - if ( p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && - pointInTriangle( ax, ay, bx, by, cx, cy, p.x, p.y ) && - area( p.prev, p, p.next ) >= 0 ) return false; - p = p.next; - - } - - return true; - -} - -function isEarHashed( ear, minX, minY, invSize ) { - - const a = ear.prev, - b = ear, - c = ear.next; - - if ( area( a, b, c ) >= 0 ) return false; // reflex, can't be an ear - - const ax = a.x, bx = b.x, cx = c.x, ay = a.y, by = b.y, cy = c.y; - - // triangle bbox; min & max are calculated like this for speed - const x0 = ax < bx ? ( ax < cx ? ax : cx ) : ( bx < cx ? bx : cx ), - y0 = ay < by ? ( ay < cy ? ay : cy ) : ( by < cy ? by : cy ), - x1 = ax > bx ? ( ax > cx ? ax : cx ) : ( bx > cx ? bx : cx ), - y1 = ay > by ? ( ay > cy ? ay : cy ) : ( by > cy ? by : cy ); - - // z-order range for the current triangle bbox; - const minZ = zOrder( x0, y0, minX, minY, invSize ), - maxZ = zOrder( x1, y1, minX, minY, invSize ); - - let p = ear.prevZ, - n = ear.nextZ; - - // look for points inside the triangle in both directions - while ( p && p.z >= minZ && n && n.z <= maxZ ) { - - if ( p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== a && p !== c && - pointInTriangle( ax, ay, bx, by, cx, cy, p.x, p.y ) && area( p.prev, p, p.next ) >= 0 ) return false; - p = p.prevZ; - - if ( n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a && n !== c && - pointInTriangle( ax, ay, bx, by, cx, cy, n.x, n.y ) && area( n.prev, n, n.next ) >= 0 ) return false; - n = n.nextZ; - - } - - // look for remaining points in decreasing z-order - while ( p && p.z >= minZ ) { - - if ( p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== a && p !== c && - pointInTriangle( ax, ay, bx, by, cx, cy, p.x, p.y ) && area( p.prev, p, p.next ) >= 0 ) return false; - p = p.prevZ; - - } - - // look for remaining points in increasing z-order - while ( n && n.z <= maxZ ) { - - if ( n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a && n !== c && - pointInTriangle( ax, ay, bx, by, cx, cy, n.x, n.y ) && area( n.prev, n, n.next ) >= 0 ) return false; - n = n.nextZ; - - } - - return true; - -} - -// go through all polygon nodes and cure small local self-intersections -function cureLocalIntersections( start, triangles, dim ) { - - let p = start; - do { - - const a = p.prev, - b = p.next.next; - - if ( ! equals( a, b ) && intersects( a, p, p.next, b ) && locallyInside( a, b ) && locallyInside( b, a ) ) { - - triangles.push( a.i / dim | 0 ); - triangles.push( p.i / dim | 0 ); - triangles.push( b.i / dim | 0 ); - - // remove two nodes involved - removeNode( p ); - removeNode( p.next ); - - p = start = b; - - } - - p = p.next; - - } while ( p !== start ); - - return filterPoints( p ); - -} - -// try splitting polygon into two and triangulate them independently -function splitEarcut( start, triangles, dim, minX, minY, invSize ) { - - // look for a valid diagonal that divides the polygon into two - let a = start; - do { - - let b = a.next.next; - while ( b !== a.prev ) { - - if ( a.i !== b.i && isValidDiagonal( a, b ) ) { - - // split the polygon in two by the diagonal - let c = splitPolygon( a, b ); - - // filter colinear points around the cuts - a = filterPoints( a, a.next ); - c = filterPoints( c, c.next ); - - // run earcut on each half - earcutLinked( a, triangles, dim, minX, minY, invSize, 0 ); - earcutLinked( c, triangles, dim, minX, minY, invSize, 0 ); - return; - - } - - b = b.next; - - } - - a = a.next; - - } while ( a !== start ); - -} - -// link every hole into the outer loop, producing a single-ring polygon without holes -function eliminateHoles( data, holeIndices, outerNode, dim ) { - - const queue = []; - let i, len, start, end, list; - - for ( i = 0, len = holeIndices.length; i < len; i ++ ) { - - start = holeIndices[ i ] * dim; - end = i < len - 1 ? holeIndices[ i + 1 ] * dim : data.length; - list = linkedList( data, start, end, dim, false ); - if ( list === list.next ) list.steiner = true; - queue.push( getLeftmost( list ) ); - - } - - queue.sort( compareX ); - - // process holes from left to right - for ( i = 0; i < queue.length; i ++ ) { - - outerNode = eliminateHole( queue[ i ], outerNode ); - - } - - return outerNode; - -} - -function compareX( a, b ) { - - return a.x - b.x; - -} - -// find a bridge between vertices that connects hole with an outer ring and link it -function eliminateHole( hole, outerNode ) { - - const bridge = findHoleBridge( hole, outerNode ); - if ( ! bridge ) { - - return outerNode; - - } - - const bridgeReverse = splitPolygon( bridge, hole ); - - // filter collinear points around the cuts - filterPoints( bridgeReverse, bridgeReverse.next ); - return filterPoints( bridge, bridge.next ); - -} - -// David Eberly's algorithm for finding a bridge between hole and outer polygon -function findHoleBridge( hole, outerNode ) { - - let p = outerNode, - qx = - Infinity, - m; - - const hx = hole.x, hy = hole.y; - - // find a segment intersected by a ray from the hole's leftmost point to the left; - // segment's endpoint with lesser x will be potential connection point - do { - - if ( hy <= p.y && hy >= p.next.y && p.next.y !== p.y ) { - - const x = p.x + ( hy - p.y ) * ( p.next.x - p.x ) / ( p.next.y - p.y ); - if ( x <= hx && x > qx ) { - - qx = x; - m = p.x < p.next.x ? p : p.next; - if ( x === hx ) return m; // hole touches outer segment; pick leftmost endpoint - - } - - } - - p = p.next; - - } while ( p !== outerNode ); - - if ( ! m ) return null; - - // look for points inside the triangle of hole point, segment intersection and endpoint; - // if there are no points found, we have a valid connection; - // otherwise choose the point of the minimum angle with the ray as connection point - - const stop = m, - mx = m.x, - my = m.y; - let tanMin = Infinity, tan; - - p = m; - - do { - - if ( hx >= p.x && p.x >= mx && hx !== p.x && - pointInTriangle( hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p.x, p.y ) ) { - - tan = Math.abs( hy - p.y ) / ( hx - p.x ); // tangential - - if ( locallyInside( p, hole ) && ( tan < tanMin || ( tan === tanMin && ( p.x > m.x || ( p.x === m.x && sectorContainsSector( m, p ) ) ) ) ) ) { - - m = p; - tanMin = tan; - - } - - } - - p = p.next; - - } while ( p !== stop ); - - return m; - -} - -// whether sector in vertex m contains sector in vertex p in the same coordinates -function sectorContainsSector( m, p ) { - - return area( m.prev, m, p.prev ) < 0 && area( p.next, m, m.next ) < 0; - -} - -// interlink polygon nodes in z-order -function indexCurve( start, minX, minY, invSize ) { - - let p = start; - do { - - if ( p.z === 0 ) p.z = zOrder( p.x, p.y, minX, minY, invSize ); - p.prevZ = p.prev; - p.nextZ = p.next; - p = p.next; - - } while ( p !== start ); - - p.prevZ.nextZ = null; - p.prevZ = null; - - sortLinked( p ); - -} - -// Simon Tatham's linked list merge sort algorithm -// http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html -function sortLinked( list ) { - - let i, p, q, e, tail, numMerges, pSize, qSize, - inSize = 1; - - do { - - p = list; - list = null; - tail = null; - numMerges = 0; - - while ( p ) { - - numMerges ++; - q = p; - pSize = 0; - for ( i = 0; i < inSize; i ++ ) { - - pSize ++; - q = q.nextZ; - if ( ! q ) break; - - } - - qSize = inSize; - - while ( pSize > 0 || ( qSize > 0 && q ) ) { - - if ( pSize !== 0 && ( qSize === 0 || ! q || p.z <= q.z ) ) { - - e = p; - p = p.nextZ; - pSize --; - - } else { - - e = q; - q = q.nextZ; - qSize --; - - } - - if ( tail ) tail.nextZ = e; - else list = e; - - e.prevZ = tail; - tail = e; - - } - - p = q; - - } - - tail.nextZ = null; - inSize *= 2; - - } while ( numMerges > 1 ); - - return list; - -} - -// z-order of a point given coords and inverse of the longer side of data bbox -function zOrder( x, y, minX, minY, invSize ) { - - // coords are transformed into non-negative 15-bit integer range - x = ( x - minX ) * invSize | 0; - y = ( y - minY ) * invSize | 0; - - x = ( x | ( x << 8 ) ) & 0x00FF00FF; - x = ( x | ( x << 4 ) ) & 0x0F0F0F0F; - x = ( x | ( x << 2 ) ) & 0x33333333; - x = ( x | ( x << 1 ) ) & 0x55555555; - - y = ( y | ( y << 8 ) ) & 0x00FF00FF; - y = ( y | ( y << 4 ) ) & 0x0F0F0F0F; - y = ( y | ( y << 2 ) ) & 0x33333333; - y = ( y | ( y << 1 ) ) & 0x55555555; - - return x | ( y << 1 ); - -} - -// find the leftmost node of a polygon ring -function getLeftmost( start ) { - - let p = start, - leftmost = start; - do { - - if ( p.x < leftmost.x || ( p.x === leftmost.x && p.y < leftmost.y ) ) leftmost = p; - p = p.next; - - } while ( p !== start ); - - return leftmost; - -} - -// check if a point lies within a convex triangle -function pointInTriangle( ax, ay, bx, by, cx, cy, px, py ) { - - return ( cx - px ) * ( ay - py ) >= ( ax - px ) * ( cy - py ) && - ( ax - px ) * ( by - py ) >= ( bx - px ) * ( ay - py ) && - ( bx - px ) * ( cy - py ) >= ( cx - px ) * ( by - py ); - -} - -// check if a diagonal between two polygon nodes is valid (lies in polygon interior) -function isValidDiagonal( a, b ) { - - return a.next.i !== b.i && a.prev.i !== b.i && ! intersectsPolygon( a, b ) && // dones't intersect other edges - ( locallyInside( a, b ) && locallyInside( b, a ) && middleInside( a, b ) && // locally visible - ( area( a.prev, a, b.prev ) || area( a, b.prev, b ) ) || // does not create opposite-facing sectors - equals( a, b ) && area( a.prev, a, a.next ) > 0 && area( b.prev, b, b.next ) > 0 ); // special zero-length case - -} - -// signed area of a triangle -function area( p, q, r ) { - - return ( q.y - p.y ) * ( r.x - q.x ) - ( q.x - p.x ) * ( r.y - q.y ); - -} - -// check if two points are equal -function equals( p1, p2 ) { - - return p1.x === p2.x && p1.y === p2.y; - -} - -// check if two segments intersect -function intersects( p1, q1, p2, q2 ) { - - const o1 = sign( area( p1, q1, p2 ) ); - const o2 = sign( area( p1, q1, q2 ) ); - const o3 = sign( area( p2, q2, p1 ) ); - const o4 = sign( area( p2, q2, q1 ) ); - - if ( o1 !== o2 && o3 !== o4 ) return true; // general case - - if ( o1 === 0 && onSegment( p1, p2, q1 ) ) return true; // p1, q1 and p2 are collinear and p2 lies on p1q1 - if ( o2 === 0 && onSegment( p1, q2, q1 ) ) return true; // p1, q1 and q2 are collinear and q2 lies on p1q1 - if ( o3 === 0 && onSegment( p2, p1, q2 ) ) return true; // p2, q2 and p1 are collinear and p1 lies on p2q2 - if ( o4 === 0 && onSegment( p2, q1, q2 ) ) return true; // p2, q2 and q1 are collinear and q1 lies on p2q2 - - return false; - -} - -// for collinear points p, q, r, check if point q lies on segment pr -function onSegment( p, q, r ) { - - return q.x <= Math.max( p.x, r.x ) && q.x >= Math.min( p.x, r.x ) && q.y <= Math.max( p.y, r.y ) && q.y >= Math.min( p.y, r.y ); - -} - -function sign( num ) { - - return num > 0 ? 1 : num < 0 ? - 1 : 0; - -} - -// check if a polygon diagonal intersects any polygon segments -function intersectsPolygon( a, b ) { - - let p = a; - do { - - if ( p.i !== a.i && p.next.i !== a.i && p.i !== b.i && p.next.i !== b.i && - intersects( p, p.next, a, b ) ) return true; - p = p.next; - - } while ( p !== a ); - - return false; - -} - -// check if a polygon diagonal is locally inside the polygon -function locallyInside( a, b ) { - - return area( a.prev, a, a.next ) < 0 ? - area( a, b, a.next ) >= 0 && area( a, a.prev, b ) >= 0 : - area( a, b, a.prev ) < 0 || area( a, a.next, b ) < 0; - -} - -// check if the middle point of a polygon diagonal is inside the polygon -function middleInside( a, b ) { - - let p = a, - inside = false; - const px = ( a.x + b.x ) / 2, - py = ( a.y + b.y ) / 2; - do { - - if ( ( ( p.y > py ) !== ( p.next.y > py ) ) && p.next.y !== p.y && - ( px < ( p.next.x - p.x ) * ( py - p.y ) / ( p.next.y - p.y ) + p.x ) ) - inside = ! inside; - p = p.next; - - } while ( p !== a ); - - return inside; - -} - -// link two polygon vertices with a bridge; if the vertices belong to the same ring, it splits polygon into two; -// if one belongs to the outer ring and another to a hole, it merges it into a single ring -function splitPolygon( a, b ) { - - const a2 = new Node( a.i, a.x, a.y ), - b2 = new Node( b.i, b.x, b.y ), - an = a.next, - bp = b.prev; - - a.next = b; - b.prev = a; - - a2.next = an; - an.prev = a2; - - b2.next = a2; - a2.prev = b2; - - bp.next = b2; - b2.prev = bp; - - return b2; - -} - -// create a node and optionally link it with previous one (in a circular doubly linked list) -function insertNode( i, x, y, last ) { - - const p = new Node( i, x, y ); - - if ( ! last ) { - - p.prev = p; - p.next = p; - - } else { - - p.next = last.next; - p.prev = last; - last.next.prev = p; - last.next = p; - - } - - return p; - -} - -function removeNode( p ) { - - p.next.prev = p.prev; - p.prev.next = p.next; - - if ( p.prevZ ) p.prevZ.nextZ = p.nextZ; - if ( p.nextZ ) p.nextZ.prevZ = p.prevZ; - -} - -function Node( i, x, y ) { - - // vertex index in coordinates array - this.i = i; - - // vertex coordinates - this.x = x; - this.y = y; - - // previous and next vertex nodes in a polygon ring - this.prev = null; - this.next = null; - - // z-order curve value - this.z = 0; - - // previous and next nodes in z-order - this.prevZ = null; - this.nextZ = null; - - // indicates whether this is a steiner point - this.steiner = false; - -} - -function signedArea( data, start, end, dim ) { - - let sum = 0; - for ( let i = start, j = end - dim; i < end; i += dim ) { - - sum += ( data[ j ] - data[ i ] ) * ( data[ i + 1 ] + data[ j + 1 ] ); - j = i; - - } - - return sum; - -} - -class ShapeUtils { - - // calculate area of the contour polygon - - static area( contour ) { - - const n = contour.length; - let a = 0.0; - - for ( let p = n - 1, q = 0; q < n; p = q ++ ) { - - a += contour[ p ].x * contour[ q ].y - contour[ q ].x * contour[ p ].y; - - } - - return a * 0.5; - - } - - static isClockWise( pts ) { - - return ShapeUtils.area( pts ) < 0; - - } - - static triangulateShape( contour, holes ) { - - const vertices = []; // flat array of vertices like [ x0,y0, x1,y1, x2,y2, ... ] - const holeIndices = []; // array of hole indices - const faces = []; // final array of vertex indices like [ [ a,b,d ], [ b,c,d ] ] - - removeDupEndPts( contour ); - addContour( vertices, contour ); - - // - - let holeIndex = contour.length; - - holes.forEach( removeDupEndPts ); - - for ( let i = 0; i < holes.length; i ++ ) { - - holeIndices.push( holeIndex ); - holeIndex += holes[ i ].length; - addContour( vertices, holes[ i ] ); - - } - - // - - const triangles = Earcut.triangulate( vertices, holeIndices ); - - // - - for ( let i = 0; i < triangles.length; i += 3 ) { - - faces.push( triangles.slice( i, i + 3 ) ); - - } - - return faces; - - } - -} - -function removeDupEndPts( points ) { - - const l = points.length; - - if ( l > 2 && points[ l - 1 ].equals( points[ 0 ] ) ) { - - points.pop(); - - } - -} - -function addContour( vertices, contour ) { - - for ( let i = 0; i < contour.length; i ++ ) { - - vertices.push( contour[ i ].x ); - vertices.push( contour[ i ].y ); - - } - -} - -/** - * Creates extruded geometry from a path shape. - * - * parameters = { - * - * curveSegments: , // number of points on the curves - * steps: , // number of points for z-side extrusions / used for subdividing segments of extrude spline too - * depth: , // Depth to extrude the shape - * - * bevelEnabled: , // turn on bevel - * bevelThickness: , // how deep into the original shape bevel goes - * bevelSize: , // how far from shape outline (including bevelOffset) is bevel - * bevelOffset: , // how far from shape outline does bevel start - * bevelSegments: , // number of bevel layers - * - * extrudePath: // curve to extrude shape along - * - * UVGenerator: // object that provides UV generator functions - * - * } - */ - - -class ExtrudeGeometry extends BufferGeometry { - - constructor( shapes = new Shape( [ new Vector2( 0.5, 0.5 ), new Vector2( - 0.5, 0.5 ), new Vector2( - 0.5, - 0.5 ), new Vector2( 0.5, - 0.5 ) ] ), options = {} ) { - - super(); - - this.type = 'ExtrudeGeometry'; - - this.parameters = { - shapes: shapes, - options: options - }; - - shapes = Array.isArray( shapes ) ? shapes : [ shapes ]; - - const scope = this; - - const verticesArray = []; - const uvArray = []; - - for ( let i = 0, l = shapes.length; i < l; i ++ ) { - - const shape = shapes[ i ]; - addShape( shape ); - - } - - // build geometry - - this.setAttribute( 'position', new Float32BufferAttribute( verticesArray, 3 ) ); - this.setAttribute( 'uv', new Float32BufferAttribute( uvArray, 2 ) ); - - this.computeVertexNormals(); - - // functions - - function addShape( shape ) { - - const placeholder = []; - - // options - - const curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12; - const steps = options.steps !== undefined ? options.steps : 1; - const depth = options.depth !== undefined ? options.depth : 1; - - let bevelEnabled = options.bevelEnabled !== undefined ? options.bevelEnabled : true; - let bevelThickness = options.bevelThickness !== undefined ? options.bevelThickness : 0.2; - let bevelSize = options.bevelSize !== undefined ? options.bevelSize : bevelThickness - 0.1; - let bevelOffset = options.bevelOffset !== undefined ? options.bevelOffset : 0; - let bevelSegments = options.bevelSegments !== undefined ? options.bevelSegments : 3; - - const extrudePath = options.extrudePath; - - const uvgen = options.UVGenerator !== undefined ? options.UVGenerator : WorldUVGenerator; - - // - - let extrudePts, extrudeByPath = false; - let splineTube, binormal, normal, position2; - - if ( extrudePath ) { - - extrudePts = extrudePath.getSpacedPoints( steps ); - - extrudeByPath = true; - bevelEnabled = false; // bevels not supported for path extrusion - - // SETUP TNB variables - - // TODO1 - have a .isClosed in spline? - - splineTube = extrudePath.computeFrenetFrames( steps, false ); - - // console.log(splineTube, 'splineTube', splineTube.normals.length, 'steps', steps, 'extrudePts', extrudePts.length); - - binormal = new Vector3(); - normal = new Vector3(); - position2 = new Vector3(); - - } - - // Safeguards if bevels are not enabled - - if ( ! bevelEnabled ) { - - bevelSegments = 0; - bevelThickness = 0; - bevelSize = 0; - bevelOffset = 0; - - } - - // Variables initialization - - const shapePoints = shape.extractPoints( curveSegments ); - - let vertices = shapePoints.shape; - const holes = shapePoints.holes; - - const reverse = ! ShapeUtils.isClockWise( vertices ); - - if ( reverse ) { - - vertices = vertices.reverse(); - - // Maybe we should also check if holes are in the opposite direction, just to be safe ... - - for ( let h = 0, hl = holes.length; h < hl; h ++ ) { - - const ahole = holes[ h ]; - - if ( ShapeUtils.isClockWise( ahole ) ) { - - holes[ h ] = ahole.reverse(); - - } - - } - - } - - - const faces = ShapeUtils.triangulateShape( vertices, holes ); - - /* Vertices */ - - const contour = vertices; // vertices has all points but contour has only points of circumference - - for ( let h = 0, hl = holes.length; h < hl; h ++ ) { - - const ahole = holes[ h ]; - - vertices = vertices.concat( ahole ); - - } - - - function scalePt2( pt, vec, size ) { - - if ( ! vec ) console.error( 'THREE.ExtrudeGeometry: vec does not exist' ); - - return pt.clone().addScaledVector( vec, size ); - - } - - const vlen = vertices.length, flen = faces.length; - - - // Find directions for point movement - - - function getBevelVec( inPt, inPrev, inNext ) { - - // computes for inPt the corresponding point inPt' on a new contour - // shifted by 1 unit (length of normalized vector) to the left - // if we walk along contour clockwise, this new contour is outside the old one - // - // inPt' is the intersection of the two lines parallel to the two - // adjacent edges of inPt at a distance of 1 unit on the left side. - - let v_trans_x, v_trans_y, shrink_by; // resulting translation vector for inPt - - // good reading for geometry algorithms (here: line-line intersection) - // http://geomalgorithms.com/a05-_intersect-1.html - - const v_prev_x = inPt.x - inPrev.x, - v_prev_y = inPt.y - inPrev.y; - const v_next_x = inNext.x - inPt.x, - v_next_y = inNext.y - inPt.y; - - const v_prev_lensq = ( v_prev_x * v_prev_x + v_prev_y * v_prev_y ); - - // check for collinear edges - const collinear0 = ( v_prev_x * v_next_y - v_prev_y * v_next_x ); - - if ( Math.abs( collinear0 ) > Number.EPSILON ) { - - // not collinear - - // length of vectors for normalizing - - const v_prev_len = Math.sqrt( v_prev_lensq ); - const v_next_len = Math.sqrt( v_next_x * v_next_x + v_next_y * v_next_y ); - - // shift adjacent points by unit vectors to the left - - const ptPrevShift_x = ( inPrev.x - v_prev_y / v_prev_len ); - const ptPrevShift_y = ( inPrev.y + v_prev_x / v_prev_len ); - - const ptNextShift_x = ( inNext.x - v_next_y / v_next_len ); - const ptNextShift_y = ( inNext.y + v_next_x / v_next_len ); - - // scaling factor for v_prev to intersection point - - const sf = ( ( ptNextShift_x - ptPrevShift_x ) * v_next_y - - ( ptNextShift_y - ptPrevShift_y ) * v_next_x ) / - ( v_prev_x * v_next_y - v_prev_y * v_next_x ); - - // vector from inPt to intersection point - - v_trans_x = ( ptPrevShift_x + v_prev_x * sf - inPt.x ); - v_trans_y = ( ptPrevShift_y + v_prev_y * sf - inPt.y ); - - // Don't normalize!, otherwise sharp corners become ugly - // but prevent crazy spikes - const v_trans_lensq = ( v_trans_x * v_trans_x + v_trans_y * v_trans_y ); - if ( v_trans_lensq <= 2 ) { - - return new Vector2( v_trans_x, v_trans_y ); - - } else { - - shrink_by = Math.sqrt( v_trans_lensq / 2 ); - - } - - } else { - - // handle special case of collinear edges - - let direction_eq = false; // assumes: opposite - - if ( v_prev_x > Number.EPSILON ) { - - if ( v_next_x > Number.EPSILON ) { - - direction_eq = true; - - } - - } else { - - if ( v_prev_x < - Number.EPSILON ) { - - if ( v_next_x < - Number.EPSILON ) { - - direction_eq = true; - - } - - } else { - - if ( Math.sign( v_prev_y ) === Math.sign( v_next_y ) ) { - - direction_eq = true; - - } - - } - - } - - if ( direction_eq ) { - - // console.log("Warning: lines are a straight sequence"); - v_trans_x = - v_prev_y; - v_trans_y = v_prev_x; - shrink_by = Math.sqrt( v_prev_lensq ); - - } else { - - // console.log("Warning: lines are a straight spike"); - v_trans_x = v_prev_x; - v_trans_y = v_prev_y; - shrink_by = Math.sqrt( v_prev_lensq / 2 ); - - } - - } - - return new Vector2( v_trans_x / shrink_by, v_trans_y / shrink_by ); - - } - - - const contourMovements = []; - - for ( let i = 0, il = contour.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) { - - if ( j === il ) j = 0; - if ( k === il ) k = 0; - - // (j)---(i)---(k) - // console.log('i,j,k', i, j , k) - - contourMovements[ i ] = getBevelVec( contour[ i ], contour[ j ], contour[ k ] ); - - } - - const holesMovements = []; - let oneHoleMovements, verticesMovements = contourMovements.concat(); - - for ( let h = 0, hl = holes.length; h < hl; h ++ ) { - - const ahole = holes[ h ]; - - oneHoleMovements = []; - - for ( let i = 0, il = ahole.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) { - - if ( j === il ) j = 0; - if ( k === il ) k = 0; - - // (j)---(i)---(k) - oneHoleMovements[ i ] = getBevelVec( ahole[ i ], ahole[ j ], ahole[ k ] ); - - } - - holesMovements.push( oneHoleMovements ); - verticesMovements = verticesMovements.concat( oneHoleMovements ); - - } - - - // Loop bevelSegments, 1 for the front, 1 for the back - - for ( let b = 0; b < bevelSegments; b ++ ) { - - //for ( b = bevelSegments; b > 0; b -- ) { - - const t = b / bevelSegments; - const z = bevelThickness * Math.cos( t * Math.PI / 2 ); - const bs = bevelSize * Math.sin( t * Math.PI / 2 ) + bevelOffset; - - // contract shape - - for ( let i = 0, il = contour.length; i < il; i ++ ) { - - const vert = scalePt2( contour[ i ], contourMovements[ i ], bs ); - - v( vert.x, vert.y, - z ); - - } - - // expand holes - - for ( let h = 0, hl = holes.length; h < hl; h ++ ) { - - const ahole = holes[ h ]; - oneHoleMovements = holesMovements[ h ]; - - for ( let i = 0, il = ahole.length; i < il; i ++ ) { - - const vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs ); - - v( vert.x, vert.y, - z ); - - } - - } - - } - - const bs = bevelSize + bevelOffset; - - // Back facing vertices - - for ( let i = 0; i < vlen; i ++ ) { - - const vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ]; - - if ( ! extrudeByPath ) { - - v( vert.x, vert.y, 0 ); - - } else { - - // v( vert.x, vert.y + extrudePts[ 0 ].y, extrudePts[ 0 ].x ); - - normal.copy( splineTube.normals[ 0 ] ).multiplyScalar( vert.x ); - binormal.copy( splineTube.binormals[ 0 ] ).multiplyScalar( vert.y ); - - position2.copy( extrudePts[ 0 ] ).add( normal ).add( binormal ); - - v( position2.x, position2.y, position2.z ); - - } - - } - - // Add stepped vertices... - // Including front facing vertices - - for ( let s = 1; s <= steps; s ++ ) { - - for ( let i = 0; i < vlen; i ++ ) { - - const vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ]; - - if ( ! extrudeByPath ) { - - v( vert.x, vert.y, depth / steps * s ); - - } else { - - // v( vert.x, vert.y + extrudePts[ s - 1 ].y, extrudePts[ s - 1 ].x ); - - normal.copy( splineTube.normals[ s ] ).multiplyScalar( vert.x ); - binormal.copy( splineTube.binormals[ s ] ).multiplyScalar( vert.y ); - - position2.copy( extrudePts[ s ] ).add( normal ).add( binormal ); - - v( position2.x, position2.y, position2.z ); - - } - - } - - } - - - // Add bevel segments planes - - //for ( b = 1; b <= bevelSegments; b ++ ) { - for ( let b = bevelSegments - 1; b >= 0; b -- ) { - - const t = b / bevelSegments; - const z = bevelThickness * Math.cos( t * Math.PI / 2 ); - const bs = bevelSize * Math.sin( t * Math.PI / 2 ) + bevelOffset; - - // contract shape - - for ( let i = 0, il = contour.length; i < il; i ++ ) { - - const vert = scalePt2( contour[ i ], contourMovements[ i ], bs ); - v( vert.x, vert.y, depth + z ); - - } - - // expand holes - - for ( let h = 0, hl = holes.length; h < hl; h ++ ) { - - const ahole = holes[ h ]; - oneHoleMovements = holesMovements[ h ]; - - for ( let i = 0, il = ahole.length; i < il; i ++ ) { - - const vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs ); - - if ( ! extrudeByPath ) { - - v( vert.x, vert.y, depth + z ); - - } else { - - v( vert.x, vert.y + extrudePts[ steps - 1 ].y, extrudePts[ steps - 1 ].x + z ); - - } - - } - - } - - } - - /* Faces */ - - // Top and bottom faces - - buildLidFaces(); - - // Sides faces - - buildSideFaces(); - - - ///// Internal functions - - function buildLidFaces() { - - const start = verticesArray.length / 3; - - if ( bevelEnabled ) { - - let layer = 0; // steps + 1 - let offset = vlen * layer; - - // Bottom faces - - for ( let i = 0; i < flen; i ++ ) { - - const face = faces[ i ]; - f3( face[ 2 ] + offset, face[ 1 ] + offset, face[ 0 ] + offset ); - - } - - layer = steps + bevelSegments * 2; - offset = vlen * layer; - - // Top faces - - for ( let i = 0; i < flen; i ++ ) { - - const face = faces[ i ]; - f3( face[ 0 ] + offset, face[ 1 ] + offset, face[ 2 ] + offset ); - - } - - } else { - - // Bottom faces - - for ( let i = 0; i < flen; i ++ ) { - - const face = faces[ i ]; - f3( face[ 2 ], face[ 1 ], face[ 0 ] ); - - } - - // Top faces - - for ( let i = 0; i < flen; i ++ ) { - - const face = faces[ i ]; - f3( face[ 0 ] + vlen * steps, face[ 1 ] + vlen * steps, face[ 2 ] + vlen * steps ); - - } - - } - - scope.addGroup( start, verticesArray.length / 3 - start, 0 ); - - } - - // Create faces for the z-sides of the shape - - function buildSideFaces() { - - const start = verticesArray.length / 3; - let layeroffset = 0; - sidewalls( contour, layeroffset ); - layeroffset += contour.length; - - for ( let h = 0, hl = holes.length; h < hl; h ++ ) { - - const ahole = holes[ h ]; - sidewalls( ahole, layeroffset ); - - //, true - layeroffset += ahole.length; - - } - - - scope.addGroup( start, verticesArray.length / 3 - start, 1 ); - - - } - - function sidewalls( contour, layeroffset ) { - - let i = contour.length; - - while ( -- i >= 0 ) { - - const j = i; - let k = i - 1; - if ( k < 0 ) k = contour.length - 1; - - //console.log('b', i,j, i-1, k,vertices.length); - - for ( let s = 0, sl = ( steps + bevelSegments * 2 ); s < sl; s ++ ) { - - const slen1 = vlen * s; - const slen2 = vlen * ( s + 1 ); - - const a = layeroffset + j + slen1, - b = layeroffset + k + slen1, - c = layeroffset + k + slen2, - d = layeroffset + j + slen2; - - f4( a, b, c, d ); - - } - - } - - } - - function v( x, y, z ) { - - placeholder.push( x ); - placeholder.push( y ); - placeholder.push( z ); - - } - - - function f3( a, b, c ) { - - addVertex( a ); - addVertex( b ); - addVertex( c ); - - const nextIndex = verticesArray.length / 3; - const uvs = uvgen.generateTopUV( scope, verticesArray, nextIndex - 3, nextIndex - 2, nextIndex - 1 ); - - addUV( uvs[ 0 ] ); - addUV( uvs[ 1 ] ); - addUV( uvs[ 2 ] ); - - } - - function f4( a, b, c, d ) { - - addVertex( a ); - addVertex( b ); - addVertex( d ); - - addVertex( b ); - addVertex( c ); - addVertex( d ); - - - const nextIndex = verticesArray.length / 3; - const uvs = uvgen.generateSideWallUV( scope, verticesArray, nextIndex - 6, nextIndex - 3, nextIndex - 2, nextIndex - 1 ); - - addUV( uvs[ 0 ] ); - addUV( uvs[ 1 ] ); - addUV( uvs[ 3 ] ); - - addUV( uvs[ 1 ] ); - addUV( uvs[ 2 ] ); - addUV( uvs[ 3 ] ); - - } - - function addVertex( index ) { - - verticesArray.push( placeholder[ index * 3 + 0 ] ); - verticesArray.push( placeholder[ index * 3 + 1 ] ); - verticesArray.push( placeholder[ index * 3 + 2 ] ); - - } - - - function addUV( vector2 ) { - - uvArray.push( vector2.x ); - uvArray.push( vector2.y ); - - } - - } - - } - - copy( source ) { - - super.copy( source ); - - this.parameters = Object.assign( {}, source.parameters ); - - return this; - - } - - toJSON() { - - const data = super.toJSON(); - - const shapes = this.parameters.shapes; - const options = this.parameters.options; - - return toJSON$1( shapes, options, data ); - - } - - static fromJSON( data, shapes ) { - - const geometryShapes = []; - - for ( let j = 0, jl = data.shapes.length; j < jl; j ++ ) { - - const shape = shapes[ data.shapes[ j ] ]; - - geometryShapes.push( shape ); - - } - - const extrudePath = data.options.extrudePath; - - if ( extrudePath !== undefined ) { - - data.options.extrudePath = new Curves[ extrudePath.type ]().fromJSON( extrudePath ); - - } - - return new ExtrudeGeometry( geometryShapes, data.options ); - - } - -} - -const WorldUVGenerator = { - - generateTopUV: function ( geometry, vertices, indexA, indexB, indexC ) { - - const a_x = vertices[ indexA * 3 ]; - const a_y = vertices[ indexA * 3 + 1 ]; - const b_x = vertices[ indexB * 3 ]; - const b_y = vertices[ indexB * 3 + 1 ]; - const c_x = vertices[ indexC * 3 ]; - const c_y = vertices[ indexC * 3 + 1 ]; - - return [ - new Vector2( a_x, a_y ), - new Vector2( b_x, b_y ), - new Vector2( c_x, c_y ) - ]; - - }, - - generateSideWallUV: function ( geometry, vertices, indexA, indexB, indexC, indexD ) { - - const a_x = vertices[ indexA * 3 ]; - const a_y = vertices[ indexA * 3 + 1 ]; - const a_z = vertices[ indexA * 3 + 2 ]; - const b_x = vertices[ indexB * 3 ]; - const b_y = vertices[ indexB * 3 + 1 ]; - const b_z = vertices[ indexB * 3 + 2 ]; - const c_x = vertices[ indexC * 3 ]; - const c_y = vertices[ indexC * 3 + 1 ]; - const c_z = vertices[ indexC * 3 + 2 ]; - const d_x = vertices[ indexD * 3 ]; - const d_y = vertices[ indexD * 3 + 1 ]; - const d_z = vertices[ indexD * 3 + 2 ]; - - if ( Math.abs( a_y - b_y ) < Math.abs( a_x - b_x ) ) { - - return [ - new Vector2( a_x, 1 - a_z ), - new Vector2( b_x, 1 - b_z ), - new Vector2( c_x, 1 - c_z ), - new Vector2( d_x, 1 - d_z ) - ]; - - } else { - - return [ - new Vector2( a_y, 1 - a_z ), - new Vector2( b_y, 1 - b_z ), - new Vector2( c_y, 1 - c_z ), - new Vector2( d_y, 1 - d_z ) - ]; - - } - - } - -}; - -function toJSON$1( shapes, options, data ) { - - data.shapes = []; - - if ( Array.isArray( shapes ) ) { - - for ( let i = 0, l = shapes.length; i < l; i ++ ) { - - const shape = shapes[ i ]; - - data.shapes.push( shape.uuid ); - - } - - } else { - - data.shapes.push( shapes.uuid ); - - } - - data.options = Object.assign( {}, options ); - - if ( options.extrudePath !== undefined ) data.options.extrudePath = options.extrudePath.toJSON(); - - return data; - -} - -class IcosahedronGeometry extends PolyhedronGeometry { - - constructor( radius = 1, detail = 0 ) { - - const t = ( 1 + Math.sqrt( 5 ) ) / 2; - - const vertices = [ - - 1, t, 0, 1, t, 0, - 1, - t, 0, 1, - t, 0, - 0, - 1, t, 0, 1, t, 0, - 1, - t, 0, 1, - t, - t, 0, - 1, t, 0, 1, - t, 0, - 1, - t, 0, 1 - ]; - - const indices = [ - 0, 11, 5, 0, 5, 1, 0, 1, 7, 0, 7, 10, 0, 10, 11, - 1, 5, 9, 5, 11, 4, 11, 10, 2, 10, 7, 6, 7, 1, 8, - 3, 9, 4, 3, 4, 2, 3, 2, 6, 3, 6, 8, 3, 8, 9, - 4, 9, 5, 2, 4, 11, 6, 2, 10, 8, 6, 7, 9, 8, 1 - ]; - - super( vertices, indices, radius, detail ); - - this.type = 'IcosahedronGeometry'; - - this.parameters = { - radius: radius, - detail: detail - }; - - } - - static fromJSON( data ) { - - return new IcosahedronGeometry( data.radius, data.detail ); - - } - -} - -class OctahedronGeometry extends PolyhedronGeometry { - - constructor( radius = 1, detail = 0 ) { - - const vertices = [ - 1, 0, 0, - 1, 0, 0, 0, 1, 0, - 0, - 1, 0, 0, 0, 1, 0, 0, - 1 - ]; - - const indices = [ - 0, 2, 4, 0, 4, 3, 0, 3, 5, - 0, 5, 2, 1, 2, 5, 1, 5, 3, - 1, 3, 4, 1, 4, 2 - ]; - - super( vertices, indices, radius, detail ); - - this.type = 'OctahedronGeometry'; - - this.parameters = { - radius: radius, - detail: detail - }; - - } - - static fromJSON( data ) { - - return new OctahedronGeometry( data.radius, data.detail ); - - } - -} - -class RingGeometry extends BufferGeometry { - - constructor( innerRadius = 0.5, outerRadius = 1, thetaSegments = 32, phiSegments = 1, thetaStart = 0, thetaLength = Math.PI * 2 ) { - - super(); - - this.type = 'RingGeometry'; - - this.parameters = { - innerRadius: innerRadius, - outerRadius: outerRadius, - thetaSegments: thetaSegments, - phiSegments: phiSegments, - thetaStart: thetaStart, - thetaLength: thetaLength - }; - - thetaSegments = Math.max( 3, thetaSegments ); - phiSegments = Math.max( 1, phiSegments ); - - // buffers - - const indices = []; - const vertices = []; - const normals = []; - const uvs = []; - - // some helper variables - - let radius = innerRadius; - const radiusStep = ( ( outerRadius - innerRadius ) / phiSegments ); - const vertex = new Vector3(); - const uv = new Vector2(); - - // generate vertices, normals and uvs - - for ( let j = 0; j <= phiSegments; j ++ ) { - - for ( let i = 0; i <= thetaSegments; i ++ ) { - - // values are generate from the inside of the ring to the outside - - const segment = thetaStart + i / thetaSegments * thetaLength; - - // vertex - - vertex.x = radius * Math.cos( segment ); - vertex.y = radius * Math.sin( segment ); - - vertices.push( vertex.x, vertex.y, vertex.z ); - - // normal - - normals.push( 0, 0, 1 ); - - // uv - - uv.x = ( vertex.x / outerRadius + 1 ) / 2; - uv.y = ( vertex.y / outerRadius + 1 ) / 2; - - uvs.push( uv.x, uv.y ); - - } - - // increase the radius for next row of vertices - - radius += radiusStep; - - } - - // indices - - for ( let j = 0; j < phiSegments; j ++ ) { - - const thetaSegmentLevel = j * ( thetaSegments + 1 ); - - for ( let i = 0; i < thetaSegments; i ++ ) { - - const segment = i + thetaSegmentLevel; - - const a = segment; - const b = segment + thetaSegments + 1; - const c = segment + thetaSegments + 2; - const d = segment + 1; - - // faces - - indices.push( a, b, d ); - indices.push( b, c, d ); - - } - - } - - // build geometry - - this.setIndex( indices ); - this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - - } - - copy( source ) { - - super.copy( source ); - - this.parameters = Object.assign( {}, source.parameters ); - - return this; - - } - - static fromJSON( data ) { - - return new RingGeometry( data.innerRadius, data.outerRadius, data.thetaSegments, data.phiSegments, data.thetaStart, data.thetaLength ); - - } - -} - -class ShapeGeometry extends BufferGeometry { - - constructor( shapes = new Shape( [ new Vector2( 0, 0.5 ), new Vector2( - 0.5, - 0.5 ), new Vector2( 0.5, - 0.5 ) ] ), curveSegments = 12 ) { - - super(); - - this.type = 'ShapeGeometry'; - - this.parameters = { - shapes: shapes, - curveSegments: curveSegments - }; - - // buffers - - const indices = []; - const vertices = []; - const normals = []; - const uvs = []; - - // helper variables - - let groupStart = 0; - let groupCount = 0; - - // allow single and array values for "shapes" parameter - - if ( Array.isArray( shapes ) === false ) { - - addShape( shapes ); - - } else { - - for ( let i = 0; i < shapes.length; i ++ ) { - - addShape( shapes[ i ] ); - - this.addGroup( groupStart, groupCount, i ); // enables MultiMaterial support - - groupStart += groupCount; - groupCount = 0; - - } - - } - - // build geometry - - this.setIndex( indices ); - this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - - - // helper functions - - function addShape( shape ) { - - const indexOffset = vertices.length / 3; - const points = shape.extractPoints( curveSegments ); - - let shapeVertices = points.shape; - const shapeHoles = points.holes; - - // check direction of vertices - - if ( ShapeUtils.isClockWise( shapeVertices ) === false ) { - - shapeVertices = shapeVertices.reverse(); - - } - - for ( let i = 0, l = shapeHoles.length; i < l; i ++ ) { - - const shapeHole = shapeHoles[ i ]; - - if ( ShapeUtils.isClockWise( shapeHole ) === true ) { - - shapeHoles[ i ] = shapeHole.reverse(); - - } - - } - - const faces = ShapeUtils.triangulateShape( shapeVertices, shapeHoles ); - - // join vertices of inner and outer paths to a single array - - for ( let i = 0, l = shapeHoles.length; i < l; i ++ ) { - - const shapeHole = shapeHoles[ i ]; - shapeVertices = shapeVertices.concat( shapeHole ); - - } - - // vertices, normals, uvs - - for ( let i = 0, l = shapeVertices.length; i < l; i ++ ) { - - const vertex = shapeVertices[ i ]; - - vertices.push( vertex.x, vertex.y, 0 ); - normals.push( 0, 0, 1 ); - uvs.push( vertex.x, vertex.y ); // world uvs - - } - - // indices - - for ( let i = 0, l = faces.length; i < l; i ++ ) { - - const face = faces[ i ]; - - const a = face[ 0 ] + indexOffset; - const b = face[ 1 ] + indexOffset; - const c = face[ 2 ] + indexOffset; - - indices.push( a, b, c ); - groupCount += 3; - - } - - } - - } - - copy( source ) { - - super.copy( source ); - - this.parameters = Object.assign( {}, source.parameters ); - - return this; - - } - - toJSON() { - - const data = super.toJSON(); - - const shapes = this.parameters.shapes; - - return toJSON( shapes, data ); - - } - - static fromJSON( data, shapes ) { - - const geometryShapes = []; - - for ( let j = 0, jl = data.shapes.length; j < jl; j ++ ) { - - const shape = shapes[ data.shapes[ j ] ]; - - geometryShapes.push( shape ); - - } - - return new ShapeGeometry( geometryShapes, data.curveSegments ); - - } - -} - -function toJSON( shapes, data ) { - - data.shapes = []; - - if ( Array.isArray( shapes ) ) { - - for ( let i = 0, l = shapes.length; i < l; i ++ ) { - - const shape = shapes[ i ]; - - data.shapes.push( shape.uuid ); - - } - - } else { - - data.shapes.push( shapes.uuid ); - - } - - return data; - -} - -class SphereGeometry extends BufferGeometry { - - constructor( radius = 1, widthSegments = 32, heightSegments = 16, phiStart = 0, phiLength = Math.PI * 2, thetaStart = 0, thetaLength = Math.PI ) { - - super(); - - this.type = 'SphereGeometry'; - - this.parameters = { - radius: radius, - widthSegments: widthSegments, - heightSegments: heightSegments, - phiStart: phiStart, - phiLength: phiLength, - thetaStart: thetaStart, - thetaLength: thetaLength - }; - - widthSegments = Math.max( 3, Math.floor( widthSegments ) ); - heightSegments = Math.max( 2, Math.floor( heightSegments ) ); - - const thetaEnd = Math.min( thetaStart + thetaLength, Math.PI ); - - let index = 0; - const grid = []; - - const vertex = new Vector3(); - const normal = new Vector3(); - - // buffers - - const indices = []; - const vertices = []; - const normals = []; - const uvs = []; - - // generate vertices, normals and uvs - - for ( let iy = 0; iy <= heightSegments; iy ++ ) { - - const verticesRow = []; - - const v = iy / heightSegments; - - // special case for the poles - - let uOffset = 0; - - if ( iy === 0 && thetaStart === 0 ) { - - uOffset = 0.5 / widthSegments; - - } else if ( iy === heightSegments && thetaEnd === Math.PI ) { - - uOffset = - 0.5 / widthSegments; - - } - - for ( let ix = 0; ix <= widthSegments; ix ++ ) { - - const u = ix / widthSegments; - - // vertex - - vertex.x = - radius * Math.cos( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength ); - vertex.y = radius * Math.cos( thetaStart + v * thetaLength ); - vertex.z = radius * Math.sin( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength ); - - vertices.push( vertex.x, vertex.y, vertex.z ); - - // normal - - normal.copy( vertex ).normalize(); - normals.push( normal.x, normal.y, normal.z ); - - // uv - - uvs.push( u + uOffset, 1 - v ); - - verticesRow.push( index ++ ); - - } - - grid.push( verticesRow ); - - } - - // indices - - for ( let iy = 0; iy < heightSegments; iy ++ ) { - - for ( let ix = 0; ix < widthSegments; ix ++ ) { - - const a = grid[ iy ][ ix + 1 ]; - const b = grid[ iy ][ ix ]; - const c = grid[ iy + 1 ][ ix ]; - const d = grid[ iy + 1 ][ ix + 1 ]; - - if ( iy !== 0 || thetaStart > 0 ) indices.push( a, b, d ); - if ( iy !== heightSegments - 1 || thetaEnd < Math.PI ) indices.push( b, c, d ); - - } - - } - - // build geometry - - this.setIndex( indices ); - this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - - } - - copy( source ) { - - super.copy( source ); - - this.parameters = Object.assign( {}, source.parameters ); - - return this; - - } - - static fromJSON( data ) { - - return new SphereGeometry( data.radius, data.widthSegments, data.heightSegments, data.phiStart, data.phiLength, data.thetaStart, data.thetaLength ); - - } - -} - -class TetrahedronGeometry extends PolyhedronGeometry { - - constructor( radius = 1, detail = 0 ) { - - const vertices = [ - 1, 1, 1, - 1, - 1, 1, - 1, 1, - 1, 1, - 1, - 1 - ]; - - const indices = [ - 2, 1, 0, 0, 3, 2, 1, 3, 0, 2, 3, 1 - ]; - - super( vertices, indices, radius, detail ); - - this.type = 'TetrahedronGeometry'; - - this.parameters = { - radius: radius, - detail: detail - }; - - } - - static fromJSON( data ) { - - return new TetrahedronGeometry( data.radius, data.detail ); - - } - -} - -class TorusGeometry extends BufferGeometry { - - constructor( radius = 1, tube = 0.4, radialSegments = 12, tubularSegments = 48, arc = Math.PI * 2 ) { - - super(); - - this.type = 'TorusGeometry'; - - this.parameters = { - radius: radius, - tube: tube, - radialSegments: radialSegments, - tubularSegments: tubularSegments, - arc: arc - }; - - radialSegments = Math.floor( radialSegments ); - tubularSegments = Math.floor( tubularSegments ); - - // buffers - - const indices = []; - const vertices = []; - const normals = []; - const uvs = []; - - // helper variables - - const center = new Vector3(); - const vertex = new Vector3(); - const normal = new Vector3(); - - // generate vertices, normals and uvs - - for ( let j = 0; j <= radialSegments; j ++ ) { - - for ( let i = 0; i <= tubularSegments; i ++ ) { - - const u = i / tubularSegments * arc; - const v = j / radialSegments * Math.PI * 2; - - // vertex - - vertex.x = ( radius + tube * Math.cos( v ) ) * Math.cos( u ); - vertex.y = ( radius + tube * Math.cos( v ) ) * Math.sin( u ); - vertex.z = tube * Math.sin( v ); - - vertices.push( vertex.x, vertex.y, vertex.z ); - - // normal - - center.x = radius * Math.cos( u ); - center.y = radius * Math.sin( u ); - normal.subVectors( vertex, center ).normalize(); - - normals.push( normal.x, normal.y, normal.z ); - - // uv - - uvs.push( i / tubularSegments ); - uvs.push( j / radialSegments ); - - } - - } - - // generate indices - - for ( let j = 1; j <= radialSegments; j ++ ) { - - for ( let i = 1; i <= tubularSegments; i ++ ) { - - // indices - - const a = ( tubularSegments + 1 ) * j + i - 1; - const b = ( tubularSegments + 1 ) * ( j - 1 ) + i - 1; - const c = ( tubularSegments + 1 ) * ( j - 1 ) + i; - const d = ( tubularSegments + 1 ) * j + i; - - // faces - - indices.push( a, b, d ); - indices.push( b, c, d ); - - } - - } - - // build geometry - - this.setIndex( indices ); - this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - - } - - copy( source ) { - - super.copy( source ); - - this.parameters = Object.assign( {}, source.parameters ); - - return this; - - } - - static fromJSON( data ) { - - return new TorusGeometry( data.radius, data.tube, data.radialSegments, data.tubularSegments, data.arc ); - - } - -} - -class TorusKnotGeometry extends BufferGeometry { - - constructor( radius = 1, tube = 0.4, tubularSegments = 64, radialSegments = 8, p = 2, q = 3 ) { - - super(); - - this.type = 'TorusKnotGeometry'; - - this.parameters = { - radius: radius, - tube: tube, - tubularSegments: tubularSegments, - radialSegments: radialSegments, - p: p, - q: q - }; - - tubularSegments = Math.floor( tubularSegments ); - radialSegments = Math.floor( radialSegments ); - - // buffers - - const indices = []; - const vertices = []; - const normals = []; - const uvs = []; - - // helper variables - - const vertex = new Vector3(); - const normal = new Vector3(); - - const P1 = new Vector3(); - const P2 = new Vector3(); - - const B = new Vector3(); - const T = new Vector3(); - const N = new Vector3(); - - // generate vertices, normals and uvs - - for ( let i = 0; i <= tubularSegments; ++ i ) { - - // the radian "u" is used to calculate the position on the torus curve of the current tubular segment - - const u = i / tubularSegments * p * Math.PI * 2; - - // now we calculate two points. P1 is our current position on the curve, P2 is a little farther ahead. - // these points are used to create a special "coordinate space", which is necessary to calculate the correct vertex positions - - calculatePositionOnCurve( u, p, q, radius, P1 ); - calculatePositionOnCurve( u + 0.01, p, q, radius, P2 ); - - // calculate orthonormal basis - - T.subVectors( P2, P1 ); - N.addVectors( P2, P1 ); - B.crossVectors( T, N ); - N.crossVectors( B, T ); - - // normalize B, N. T can be ignored, we don't use it - - B.normalize(); - N.normalize(); - - for ( let j = 0; j <= radialSegments; ++ j ) { - - // now calculate the vertices. they are nothing more than an extrusion of the torus curve. - // because we extrude a shape in the xy-plane, there is no need to calculate a z-value. - - const v = j / radialSegments * Math.PI * 2; - const cx = - tube * Math.cos( v ); - const cy = tube * Math.sin( v ); - - // now calculate the final vertex position. - // first we orient the extrusion with our basis vectors, then we add it to the current position on the curve - - vertex.x = P1.x + ( cx * N.x + cy * B.x ); - vertex.y = P1.y + ( cx * N.y + cy * B.y ); - vertex.z = P1.z + ( cx * N.z + cy * B.z ); - - vertices.push( vertex.x, vertex.y, vertex.z ); - - // normal (P1 is always the center/origin of the extrusion, thus we can use it to calculate the normal) - - normal.subVectors( vertex, P1 ).normalize(); - - normals.push( normal.x, normal.y, normal.z ); - - // uv - - uvs.push( i / tubularSegments ); - uvs.push( j / radialSegments ); - - } - - } - - // generate indices - - for ( let j = 1; j <= tubularSegments; j ++ ) { - - for ( let i = 1; i <= radialSegments; i ++ ) { - - // indices - - const a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 ); - const b = ( radialSegments + 1 ) * j + ( i - 1 ); - const c = ( radialSegments + 1 ) * j + i; - const d = ( radialSegments + 1 ) * ( j - 1 ) + i; - - // faces - - indices.push( a, b, d ); - indices.push( b, c, d ); - - } - - } - - // build geometry - - this.setIndex( indices ); - this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - - // this function calculates the current position on the torus curve - - function calculatePositionOnCurve( u, p, q, radius, position ) { - - const cu = Math.cos( u ); - const su = Math.sin( u ); - const quOverP = q / p * u; - const cs = Math.cos( quOverP ); - - position.x = radius * ( 2 + cs ) * 0.5 * cu; - position.y = radius * ( 2 + cs ) * su * 0.5; - position.z = radius * Math.sin( quOverP ) * 0.5; - - } - - } - - copy( source ) { - - super.copy( source ); - - this.parameters = Object.assign( {}, source.parameters ); - - return this; - - } - - static fromJSON( data ) { - - return new TorusKnotGeometry( data.radius, data.tube, data.tubularSegments, data.radialSegments, data.p, data.q ); - - } - -} - -class TubeGeometry extends BufferGeometry { - - constructor( path = new QuadraticBezierCurve3( new Vector3( - 1, - 1, 0 ), new Vector3( - 1, 1, 0 ), new Vector3( 1, 1, 0 ) ), tubularSegments = 64, radius = 1, radialSegments = 8, closed = false ) { - - super(); - - this.type = 'TubeGeometry'; - - this.parameters = { - path: path, - tubularSegments: tubularSegments, - radius: radius, - radialSegments: radialSegments, - closed: closed - }; - - const frames = path.computeFrenetFrames( tubularSegments, closed ); - - // expose internals - - this.tangents = frames.tangents; - this.normals = frames.normals; - this.binormals = frames.binormals; - - // helper variables - - const vertex = new Vector3(); - const normal = new Vector3(); - const uv = new Vector2(); - let P = new Vector3(); - - // buffer - - const vertices = []; - const normals = []; - const uvs = []; - const indices = []; - - // create buffer data - - generateBufferData(); - - // build geometry - - this.setIndex( indices ); - this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - - // functions - - function generateBufferData() { - - for ( let i = 0; i < tubularSegments; i ++ ) { - - generateSegment( i ); - - } - - // if the geometry is not closed, generate the last row of vertices and normals - // at the regular position on the given path - // - // if the geometry is closed, duplicate the first row of vertices and normals (uvs will differ) - - generateSegment( ( closed === false ) ? tubularSegments : 0 ); - - // uvs are generated in a separate function. - // this makes it easy compute correct values for closed geometries - - generateUVs(); - - // finally create faces - - generateIndices(); - - } - - function generateSegment( i ) { - - // we use getPointAt to sample evenly distributed points from the given path - - P = path.getPointAt( i / tubularSegments, P ); - - // retrieve corresponding normal and binormal - - const N = frames.normals[ i ]; - const B = frames.binormals[ i ]; - - // generate normals and vertices for the current segment - - for ( let j = 0; j <= radialSegments; j ++ ) { - - const v = j / radialSegments * Math.PI * 2; - - const sin = Math.sin( v ); - const cos = - Math.cos( v ); - - // normal - - normal.x = ( cos * N.x + sin * B.x ); - normal.y = ( cos * N.y + sin * B.y ); - normal.z = ( cos * N.z + sin * B.z ); - normal.normalize(); - - normals.push( normal.x, normal.y, normal.z ); - - // vertex - - vertex.x = P.x + radius * normal.x; - vertex.y = P.y + radius * normal.y; - vertex.z = P.z + radius * normal.z; - - vertices.push( vertex.x, vertex.y, vertex.z ); - - } - - } - - function generateIndices() { - - for ( let j = 1; j <= tubularSegments; j ++ ) { - - for ( let i = 1; i <= radialSegments; i ++ ) { - - const a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 ); - const b = ( radialSegments + 1 ) * j + ( i - 1 ); - const c = ( radialSegments + 1 ) * j + i; - const d = ( radialSegments + 1 ) * ( j - 1 ) + i; - - // faces - - indices.push( a, b, d ); - indices.push( b, c, d ); - - } - - } - - } - - function generateUVs() { - - for ( let i = 0; i <= tubularSegments; i ++ ) { - - for ( let j = 0; j <= radialSegments; j ++ ) { - - uv.x = i / tubularSegments; - uv.y = j / radialSegments; - - uvs.push( uv.x, uv.y ); - - } - - } - - } - - } - - copy( source ) { - - super.copy( source ); - - this.parameters = Object.assign( {}, source.parameters ); - - return this; - - } - - toJSON() { - - const data = super.toJSON(); - - data.path = this.parameters.path.toJSON(); - - return data; - - } - - static fromJSON( data ) { - - // This only works for built-in curves (e.g. CatmullRomCurve3). - // User defined curves or instances of CurvePath will not be deserialized. - return new TubeGeometry( - new Curves[ data.path.type ]().fromJSON( data.path ), - data.tubularSegments, - data.radius, - data.radialSegments, - data.closed - ); - - } - -} - -class WireframeGeometry extends BufferGeometry { - - constructor( geometry = null ) { - - super(); - - this.type = 'WireframeGeometry'; - - this.parameters = { - geometry: geometry - }; - - if ( geometry !== null ) { - - // buffer - - const vertices = []; - const edges = new Set(); - - // helper variables - - const start = new Vector3(); - const end = new Vector3(); - - if ( geometry.index !== null ) { - - // indexed BufferGeometry - - const position = geometry.attributes.position; - const indices = geometry.index; - let groups = geometry.groups; - - if ( groups.length === 0 ) { - - groups = [ { start: 0, count: indices.count, materialIndex: 0 } ]; - - } - - // create a data structure that contains all edges without duplicates - - for ( let o = 0, ol = groups.length; o < ol; ++ o ) { - - const group = groups[ o ]; - - const groupStart = group.start; - const groupCount = group.count; - - for ( let i = groupStart, l = ( groupStart + groupCount ); i < l; i += 3 ) { - - for ( let j = 0; j < 3; j ++ ) { - - const index1 = indices.getX( i + j ); - const index2 = indices.getX( i + ( j + 1 ) % 3 ); - - start.fromBufferAttribute( position, index1 ); - end.fromBufferAttribute( position, index2 ); - - if ( isUniqueEdge( start, end, edges ) === true ) { - - vertices.push( start.x, start.y, start.z ); - vertices.push( end.x, end.y, end.z ); - - } - - } - - } - - } - - } else { - - // non-indexed BufferGeometry - - const position = geometry.attributes.position; - - for ( let i = 0, l = ( position.count / 3 ); i < l; i ++ ) { - - for ( let j = 0; j < 3; j ++ ) { - - // three edges per triangle, an edge is represented as (index1, index2) - // e.g. the first triangle has the following edges: (0,1),(1,2),(2,0) - - const index1 = 3 * i + j; - const index2 = 3 * i + ( ( j + 1 ) % 3 ); - - start.fromBufferAttribute( position, index1 ); - end.fromBufferAttribute( position, index2 ); - - if ( isUniqueEdge( start, end, edges ) === true ) { - - vertices.push( start.x, start.y, start.z ); - vertices.push( end.x, end.y, end.z ); - - } - - } - - } - - } - - // build geometry - - this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - - } - - } - - copy( source ) { - - super.copy( source ); - - this.parameters = Object.assign( {}, source.parameters ); - - return this; - - } - -} - -function isUniqueEdge( start, end, edges ) { - - const hash1 = `${start.x},${start.y},${start.z}-${end.x},${end.y},${end.z}`; - const hash2 = `${end.x},${end.y},${end.z}-${start.x},${start.y},${start.z}`; // coincident edge - - if ( edges.has( hash1 ) === true || edges.has( hash2 ) === true ) { - - return false; - - } else { - - edges.add( hash1 ); - edges.add( hash2 ); - return true; - - } - -} - -var Geometries = /*#__PURE__*/Object.freeze({ - __proto__: null, - BoxGeometry: BoxGeometry, - CapsuleGeometry: CapsuleGeometry, - CircleGeometry: CircleGeometry, - ConeGeometry: ConeGeometry, - CylinderGeometry: CylinderGeometry, - DodecahedronGeometry: DodecahedronGeometry, - EdgesGeometry: EdgesGeometry, - ExtrudeGeometry: ExtrudeGeometry, - IcosahedronGeometry: IcosahedronGeometry, - LatheGeometry: LatheGeometry, - OctahedronGeometry: OctahedronGeometry, - PlaneGeometry: PlaneGeometry, - PolyhedronGeometry: PolyhedronGeometry, - RingGeometry: RingGeometry, - ShapeGeometry: ShapeGeometry, - SphereGeometry: SphereGeometry, - TetrahedronGeometry: TetrahedronGeometry, - TorusGeometry: TorusGeometry, - TorusKnotGeometry: TorusKnotGeometry, - TubeGeometry: TubeGeometry, - WireframeGeometry: WireframeGeometry -}); - -class ShadowMaterial extends Material { - - constructor( parameters ) { - - super(); - - this.isShadowMaterial = true; - - this.type = 'ShadowMaterial'; - - this.color = new Color( 0x000000 ); - this.transparent = true; - - this.fog = true; - - this.setValues( parameters ); - - } - - copy( source ) { - - super.copy( source ); - - this.color.copy( source.color ); - - this.fog = source.fog; - - return this; - - } - -} - -class RawShaderMaterial extends ShaderMaterial { - - constructor( parameters ) { - - super( parameters ); - - this.isRawShaderMaterial = true; - - this.type = 'RawShaderMaterial'; - - } - -} - -class MeshStandardMaterial extends Material { - - constructor( parameters ) { - - super(); - - this.isMeshStandardMaterial = true; - - this.defines = { 'STANDARD': '' }; - - this.type = 'MeshStandardMaterial'; - - this.color = new Color( 0xffffff ); // diffuse - this.roughness = 1.0; - this.metalness = 0.0; - - this.map = null; - - this.lightMap = null; - this.lightMapIntensity = 1.0; - - this.aoMap = null; - this.aoMapIntensity = 1.0; - - this.emissive = new Color( 0x000000 ); - this.emissiveIntensity = 1.0; - this.emissiveMap = null; - - this.bumpMap = null; - this.bumpScale = 1; - - this.normalMap = null; - this.normalMapType = TangentSpaceNormalMap; - this.normalScale = new Vector2( 1, 1 ); - - this.displacementMap = null; - this.displacementScale = 1; - this.displacementBias = 0; - - this.roughnessMap = null; - - this.metalnessMap = null; - - this.alphaMap = null; - - this.envMap = null; - this.envMapIntensity = 1.0; - - this.wireframe = false; - this.wireframeLinewidth = 1; - this.wireframeLinecap = 'round'; - this.wireframeLinejoin = 'round'; - - this.flatShading = false; - - this.fog = true; - - this.setValues( parameters ); - - } - - copy( source ) { - - super.copy( source ); - - this.defines = { 'STANDARD': '' }; - - this.color.copy( source.color ); - this.roughness = source.roughness; - this.metalness = source.metalness; - - this.map = source.map; - - this.lightMap = source.lightMap; - this.lightMapIntensity = source.lightMapIntensity; - - this.aoMap = source.aoMap; - this.aoMapIntensity = source.aoMapIntensity; - - this.emissive.copy( source.emissive ); - this.emissiveMap = source.emissiveMap; - this.emissiveIntensity = source.emissiveIntensity; - - this.bumpMap = source.bumpMap; - this.bumpScale = source.bumpScale; - - this.normalMap = source.normalMap; - this.normalMapType = source.normalMapType; - this.normalScale.copy( source.normalScale ); - - this.displacementMap = source.displacementMap; - this.displacementScale = source.displacementScale; - this.displacementBias = source.displacementBias; - - this.roughnessMap = source.roughnessMap; - - this.metalnessMap = source.metalnessMap; - - this.alphaMap = source.alphaMap; - - this.envMap = source.envMap; - this.envMapIntensity = source.envMapIntensity; - - this.wireframe = source.wireframe; - this.wireframeLinewidth = source.wireframeLinewidth; - this.wireframeLinecap = source.wireframeLinecap; - this.wireframeLinejoin = source.wireframeLinejoin; - - this.flatShading = source.flatShading; - - this.fog = source.fog; - - return this; - - } - -} - -class MeshPhysicalMaterial extends MeshStandardMaterial { - - constructor( parameters ) { - - super(); - - this.isMeshPhysicalMaterial = true; - - this.defines = { - - 'STANDARD': '', - 'PHYSICAL': '' - - }; - - this.type = 'MeshPhysicalMaterial'; - - this.anisotropyRotation = 0; - this.anisotropyMap = null; - - this.clearcoatMap = null; - this.clearcoatRoughness = 0.0; - this.clearcoatRoughnessMap = null; - this.clearcoatNormalScale = new Vector2( 1, 1 ); - this.clearcoatNormalMap = null; - - this.ior = 1.5; - - Object.defineProperty( this, 'reflectivity', { - get: function () { - - return ( clamp( 2.5 * ( this.ior - 1 ) / ( this.ior + 1 ), 0, 1 ) ); - - }, - set: function ( reflectivity ) { - - this.ior = ( 1 + 0.4 * reflectivity ) / ( 1 - 0.4 * reflectivity ); - - } - } ); - - this.iridescenceMap = null; - this.iridescenceIOR = 1.3; - this.iridescenceThicknessRange = [ 100, 400 ]; - this.iridescenceThicknessMap = null; - - this.sheenColor = new Color( 0x000000 ); - this.sheenColorMap = null; - this.sheenRoughness = 1.0; - this.sheenRoughnessMap = null; - - this.transmissionMap = null; - - this.thickness = 0; - this.thicknessMap = null; - this.attenuationDistance = Infinity; - this.attenuationColor = new Color( 1, 1, 1 ); - - this.specularIntensity = 1.0; - this.specularIntensityMap = null; - this.specularColor = new Color( 1, 1, 1 ); - this.specularColorMap = null; - - this._anisotropy = 0; - this._clearcoat = 0; - this._iridescence = 0; - this._sheen = 0.0; - this._transmission = 0; - - this.setValues( parameters ); - - } - - get anisotropy() { - - return this._anisotropy; - - } - - set anisotropy( value ) { - - if ( this._anisotropy > 0 !== value > 0 ) { - - this.version ++; - - } - - this._anisotropy = value; - - } - - get clearcoat() { - - return this._clearcoat; - - } - - set clearcoat( value ) { - - if ( this._clearcoat > 0 !== value > 0 ) { - - this.version ++; - - } - - this._clearcoat = value; - - } - - get iridescence() { - - return this._iridescence; - - } - - set iridescence( value ) { - - if ( this._iridescence > 0 !== value > 0 ) { - - this.version ++; - - } - - this._iridescence = value; - - } - - get sheen() { - - return this._sheen; - - } - - set sheen( value ) { - - if ( this._sheen > 0 !== value > 0 ) { - - this.version ++; - - } - - this._sheen = value; - - } - - get transmission() { - - return this._transmission; - - } - - set transmission( value ) { - - if ( this._transmission > 0 !== value > 0 ) { - - this.version ++; - - } - - this._transmission = value; - - } - - copy( source ) { - - super.copy( source ); - - this.defines = { - - 'STANDARD': '', - 'PHYSICAL': '' - - }; - - this.anisotropy = source.anisotropy; - this.anisotropyRotation = source.anisotropyRotation; - this.anisotropyMap = source.anisotropyMap; - - this.clearcoat = source.clearcoat; - this.clearcoatMap = source.clearcoatMap; - this.clearcoatRoughness = source.clearcoatRoughness; - this.clearcoatRoughnessMap = source.clearcoatRoughnessMap; - this.clearcoatNormalMap = source.clearcoatNormalMap; - this.clearcoatNormalScale.copy( source.clearcoatNormalScale ); - - this.ior = source.ior; - - this.iridescence = source.iridescence; - this.iridescenceMap = source.iridescenceMap; - this.iridescenceIOR = source.iridescenceIOR; - this.iridescenceThicknessRange = [ ...source.iridescenceThicknessRange ]; - this.iridescenceThicknessMap = source.iridescenceThicknessMap; - - this.sheen = source.sheen; - this.sheenColor.copy( source.sheenColor ); - this.sheenColorMap = source.sheenColorMap; - this.sheenRoughness = source.sheenRoughness; - this.sheenRoughnessMap = source.sheenRoughnessMap; - - this.transmission = source.transmission; - this.transmissionMap = source.transmissionMap; - - this.thickness = source.thickness; - this.thicknessMap = source.thicknessMap; - this.attenuationDistance = source.attenuationDistance; - this.attenuationColor.copy( source.attenuationColor ); - - this.specularIntensity = source.specularIntensity; - this.specularIntensityMap = source.specularIntensityMap; - this.specularColor.copy( source.specularColor ); - this.specularColorMap = source.specularColorMap; - - return this; - - } - -} - -class MeshPhongMaterial extends Material { - - constructor( parameters ) { - - super(); - - this.isMeshPhongMaterial = true; - - this.type = 'MeshPhongMaterial'; - - this.color = new Color( 0xffffff ); // diffuse - this.specular = new Color( 0x111111 ); - this.shininess = 30; - - this.map = null; - - this.lightMap = null; - this.lightMapIntensity = 1.0; - - this.aoMap = null; - this.aoMapIntensity = 1.0; - - this.emissive = new Color( 0x000000 ); - this.emissiveIntensity = 1.0; - this.emissiveMap = null; - - this.bumpMap = null; - this.bumpScale = 1; - - this.normalMap = null; - this.normalMapType = TangentSpaceNormalMap; - this.normalScale = new Vector2( 1, 1 ); - - this.displacementMap = null; - this.displacementScale = 1; - this.displacementBias = 0; - - this.specularMap = null; - - this.alphaMap = null; - - this.envMap = null; - this.combine = MultiplyOperation; - this.reflectivity = 1; - this.refractionRatio = 0.98; - - this.wireframe = false; - this.wireframeLinewidth = 1; - this.wireframeLinecap = 'round'; - this.wireframeLinejoin = 'round'; - - this.flatShading = false; - - this.fog = true; - - this.setValues( parameters ); - - } - - copy( source ) { - - super.copy( source ); - - this.color.copy( source.color ); - this.specular.copy( source.specular ); - this.shininess = source.shininess; - - this.map = source.map; - - this.lightMap = source.lightMap; - this.lightMapIntensity = source.lightMapIntensity; - - this.aoMap = source.aoMap; - this.aoMapIntensity = source.aoMapIntensity; - - this.emissive.copy( source.emissive ); - this.emissiveMap = source.emissiveMap; - this.emissiveIntensity = source.emissiveIntensity; - - this.bumpMap = source.bumpMap; - this.bumpScale = source.bumpScale; - - this.normalMap = source.normalMap; - this.normalMapType = source.normalMapType; - this.normalScale.copy( source.normalScale ); - - this.displacementMap = source.displacementMap; - this.displacementScale = source.displacementScale; - this.displacementBias = source.displacementBias; - - this.specularMap = source.specularMap; - - this.alphaMap = source.alphaMap; - - this.envMap = source.envMap; - this.combine = source.combine; - this.reflectivity = source.reflectivity; - this.refractionRatio = source.refractionRatio; - - this.wireframe = source.wireframe; - this.wireframeLinewidth = source.wireframeLinewidth; - this.wireframeLinecap = source.wireframeLinecap; - this.wireframeLinejoin = source.wireframeLinejoin; - - this.flatShading = source.flatShading; - - this.fog = source.fog; - - return this; - - } - -} - -class MeshToonMaterial extends Material { - - constructor( parameters ) { - - super(); - - this.isMeshToonMaterial = true; - - this.defines = { 'TOON': '' }; - - this.type = 'MeshToonMaterial'; - - this.color = new Color( 0xffffff ); - - this.map = null; - this.gradientMap = null; - - this.lightMap = null; - this.lightMapIntensity = 1.0; - - this.aoMap = null; - this.aoMapIntensity = 1.0; - - this.emissive = new Color( 0x000000 ); - this.emissiveIntensity = 1.0; - this.emissiveMap = null; - - this.bumpMap = null; - this.bumpScale = 1; - - this.normalMap = null; - this.normalMapType = TangentSpaceNormalMap; - this.normalScale = new Vector2( 1, 1 ); - - this.displacementMap = null; - this.displacementScale = 1; - this.displacementBias = 0; - - this.alphaMap = null; - - this.wireframe = false; - this.wireframeLinewidth = 1; - this.wireframeLinecap = 'round'; - this.wireframeLinejoin = 'round'; - - this.fog = true; - - this.setValues( parameters ); - - } - - copy( source ) { - - super.copy( source ); - - this.color.copy( source.color ); - - this.map = source.map; - this.gradientMap = source.gradientMap; - - this.lightMap = source.lightMap; - this.lightMapIntensity = source.lightMapIntensity; - - this.aoMap = source.aoMap; - this.aoMapIntensity = source.aoMapIntensity; - - this.emissive.copy( source.emissive ); - this.emissiveMap = source.emissiveMap; - this.emissiveIntensity = source.emissiveIntensity; - - this.bumpMap = source.bumpMap; - this.bumpScale = source.bumpScale; - - this.normalMap = source.normalMap; - this.normalMapType = source.normalMapType; - this.normalScale.copy( source.normalScale ); - - this.displacementMap = source.displacementMap; - this.displacementScale = source.displacementScale; - this.displacementBias = source.displacementBias; - - this.alphaMap = source.alphaMap; - - this.wireframe = source.wireframe; - this.wireframeLinewidth = source.wireframeLinewidth; - this.wireframeLinecap = source.wireframeLinecap; - this.wireframeLinejoin = source.wireframeLinejoin; - - this.fog = source.fog; - - return this; - - } - -} - -class MeshNormalMaterial extends Material { - - constructor( parameters ) { - - super(); - - this.isMeshNormalMaterial = true; - - this.type = 'MeshNormalMaterial'; - - this.bumpMap = null; - this.bumpScale = 1; - - this.normalMap = null; - this.normalMapType = TangentSpaceNormalMap; - this.normalScale = new Vector2( 1, 1 ); - - this.displacementMap = null; - this.displacementScale = 1; - this.displacementBias = 0; - - this.wireframe = false; - this.wireframeLinewidth = 1; - - this.flatShading = false; - - this.setValues( parameters ); - - } - - copy( source ) { - - super.copy( source ); - - this.bumpMap = source.bumpMap; - this.bumpScale = source.bumpScale; - - this.normalMap = source.normalMap; - this.normalMapType = source.normalMapType; - this.normalScale.copy( source.normalScale ); - - this.displacementMap = source.displacementMap; - this.displacementScale = source.displacementScale; - this.displacementBias = source.displacementBias; - - this.wireframe = source.wireframe; - this.wireframeLinewidth = source.wireframeLinewidth; - - this.flatShading = source.flatShading; - - return this; - - } - -} - -class MeshLambertMaterial extends Material { - - constructor( parameters ) { - - super(); - - this.isMeshLambertMaterial = true; - - this.type = 'MeshLambertMaterial'; - - this.color = new Color( 0xffffff ); // diffuse - - this.map = null; - - this.lightMap = null; - this.lightMapIntensity = 1.0; - - this.aoMap = null; - this.aoMapIntensity = 1.0; - - this.emissive = new Color( 0x000000 ); - this.emissiveIntensity = 1.0; - this.emissiveMap = null; - - this.bumpMap = null; - this.bumpScale = 1; - - this.normalMap = null; - this.normalMapType = TangentSpaceNormalMap; - this.normalScale = new Vector2( 1, 1 ); - - this.displacementMap = null; - this.displacementScale = 1; - this.displacementBias = 0; - - this.specularMap = null; - - this.alphaMap = null; - - this.envMap = null; - this.combine = MultiplyOperation; - this.reflectivity = 1; - this.refractionRatio = 0.98; - - this.wireframe = false; - this.wireframeLinewidth = 1; - this.wireframeLinecap = 'round'; - this.wireframeLinejoin = 'round'; - - this.flatShading = false; - - this.fog = true; - - this.setValues( parameters ); - - } - - copy( source ) { - - super.copy( source ); - - this.color.copy( source.color ); - - this.map = source.map; - - this.lightMap = source.lightMap; - this.lightMapIntensity = source.lightMapIntensity; - - this.aoMap = source.aoMap; - this.aoMapIntensity = source.aoMapIntensity; - - this.emissive.copy( source.emissive ); - this.emissiveMap = source.emissiveMap; - this.emissiveIntensity = source.emissiveIntensity; - - this.bumpMap = source.bumpMap; - this.bumpScale = source.bumpScale; - - this.normalMap = source.normalMap; - this.normalMapType = source.normalMapType; - this.normalScale.copy( source.normalScale ); - - this.displacementMap = source.displacementMap; - this.displacementScale = source.displacementScale; - this.displacementBias = source.displacementBias; - - this.specularMap = source.specularMap; - - this.alphaMap = source.alphaMap; - - this.envMap = source.envMap; - this.combine = source.combine; - this.reflectivity = source.reflectivity; - this.refractionRatio = source.refractionRatio; - - this.wireframe = source.wireframe; - this.wireframeLinewidth = source.wireframeLinewidth; - this.wireframeLinecap = source.wireframeLinecap; - this.wireframeLinejoin = source.wireframeLinejoin; - - this.flatShading = source.flatShading; - - this.fog = source.fog; - - return this; - - } - -} - -class MeshMatcapMaterial extends Material { - - constructor( parameters ) { - - super(); - - this.isMeshMatcapMaterial = true; - - this.defines = { 'MATCAP': '' }; - - this.type = 'MeshMatcapMaterial'; - - this.color = new Color( 0xffffff ); // diffuse - - this.matcap = null; - - this.map = null; - - this.bumpMap = null; - this.bumpScale = 1; - - this.normalMap = null; - this.normalMapType = TangentSpaceNormalMap; - this.normalScale = new Vector2( 1, 1 ); - - this.displacementMap = null; - this.displacementScale = 1; - this.displacementBias = 0; - - this.alphaMap = null; - - this.flatShading = false; - - this.fog = true; - - this.setValues( parameters ); - - } - - - copy( source ) { - - super.copy( source ); - - this.defines = { 'MATCAP': '' }; - - this.color.copy( source.color ); - - this.matcap = source.matcap; - - this.map = source.map; - - this.bumpMap = source.bumpMap; - this.bumpScale = source.bumpScale; - - this.normalMap = source.normalMap; - this.normalMapType = source.normalMapType; - this.normalScale.copy( source.normalScale ); - - this.displacementMap = source.displacementMap; - this.displacementScale = source.displacementScale; - this.displacementBias = source.displacementBias; - - this.alphaMap = source.alphaMap; - - this.flatShading = source.flatShading; - - this.fog = source.fog; - - return this; - - } - -} - -class LineDashedMaterial extends LineBasicMaterial { - - constructor( parameters ) { - - super(); - - this.isLineDashedMaterial = true; - - this.type = 'LineDashedMaterial'; - - this.scale = 1; - this.dashSize = 3; - this.gapSize = 1; - - this.setValues( parameters ); - - } - - copy( source ) { - - super.copy( source ); - - this.scale = source.scale; - this.dashSize = source.dashSize; - this.gapSize = source.gapSize; - - return this; - - } - -} - -// converts an array to a specific type -function convertArray( array, type, forceClone ) { - - if ( ! array || // let 'undefined' and 'null' pass - ! forceClone && array.constructor === type ) return array; - - if ( typeof type.BYTES_PER_ELEMENT === 'number' ) { - - return new type( array ); // create typed array - - } - - return Array.prototype.slice.call( array ); // create Array - -} - -function isTypedArray( object ) { - - return ArrayBuffer.isView( object ) && - ! ( object instanceof DataView ); - -} - -// returns an array by which times and values can be sorted -function getKeyframeOrder( times ) { - - function compareTime( i, j ) { - - return times[ i ] - times[ j ]; - - } - - const n = times.length; - const result = new Array( n ); - for ( let i = 0; i !== n; ++ i ) result[ i ] = i; - - result.sort( compareTime ); - - return result; - -} - -// uses the array previously returned by 'getKeyframeOrder' to sort data -function sortedArray( values, stride, order ) { - - const nValues = values.length; - const result = new values.constructor( nValues ); - - for ( let i = 0, dstOffset = 0; dstOffset !== nValues; ++ i ) { - - const srcOffset = order[ i ] * stride; - - for ( let j = 0; j !== stride; ++ j ) { - - result[ dstOffset ++ ] = values[ srcOffset + j ]; - - } - - } - - return result; - -} - -// function for parsing AOS keyframe formats -function flattenJSON( jsonKeys, times, values, valuePropertyName ) { - - let i = 1, key = jsonKeys[ 0 ]; - - while ( key !== undefined && key[ valuePropertyName ] === undefined ) { - - key = jsonKeys[ i ++ ]; - - } - - if ( key === undefined ) return; // no data - - let value = key[ valuePropertyName ]; - if ( value === undefined ) return; // no data - - if ( Array.isArray( value ) ) { - - do { - - value = key[ valuePropertyName ]; - - if ( value !== undefined ) { - - times.push( key.time ); - values.push.apply( values, value ); // push all elements - - } - - key = jsonKeys[ i ++ ]; - - } while ( key !== undefined ); - - } else if ( value.toArray !== undefined ) { - - // ...assume THREE.Math-ish - - do { - - value = key[ valuePropertyName ]; - - if ( value !== undefined ) { - - times.push( key.time ); - value.toArray( values, values.length ); - - } - - key = jsonKeys[ i ++ ]; - - } while ( key !== undefined ); - - } else { - - // otherwise push as-is - - do { - - value = key[ valuePropertyName ]; - - if ( value !== undefined ) { - - times.push( key.time ); - values.push( value ); - - } - - key = jsonKeys[ i ++ ]; - - } while ( key !== undefined ); - - } - -} - -function subclip( sourceClip, name, startFrame, endFrame, fps = 30 ) { - - const clip = sourceClip.clone(); - - clip.name = name; - - const tracks = []; - - for ( let i = 0; i < clip.tracks.length; ++ i ) { - - const track = clip.tracks[ i ]; - const valueSize = track.getValueSize(); - - const times = []; - const values = []; - - for ( let j = 0; j < track.times.length; ++ j ) { - - const frame = track.times[ j ] * fps; - - if ( frame < startFrame || frame >= endFrame ) continue; - - times.push( track.times[ j ] ); - - for ( let k = 0; k < valueSize; ++ k ) { - - values.push( track.values[ j * valueSize + k ] ); - - } - - } - - if ( times.length === 0 ) continue; - - track.times = convertArray( times, track.times.constructor ); - track.values = convertArray( values, track.values.constructor ); - - tracks.push( track ); - - } - - clip.tracks = tracks; - - // find minimum .times value across all tracks in the trimmed clip - - let minStartTime = Infinity; - - for ( let i = 0; i < clip.tracks.length; ++ i ) { - - if ( minStartTime > clip.tracks[ i ].times[ 0 ] ) { - - minStartTime = clip.tracks[ i ].times[ 0 ]; - - } - - } - - // shift all tracks such that clip begins at t=0 - - for ( let i = 0; i < clip.tracks.length; ++ i ) { - - clip.tracks[ i ].shift( - 1 * minStartTime ); - - } - - clip.resetDuration(); - - return clip; - -} - -function makeClipAdditive( targetClip, referenceFrame = 0, referenceClip = targetClip, fps = 30 ) { - - if ( fps <= 0 ) fps = 30; - - const numTracks = referenceClip.tracks.length; - const referenceTime = referenceFrame / fps; - - // Make each track's values relative to the values at the reference frame - for ( let i = 0; i < numTracks; ++ i ) { - - const referenceTrack = referenceClip.tracks[ i ]; - const referenceTrackType = referenceTrack.ValueTypeName; - - // Skip this track if it's non-numeric - if ( referenceTrackType === 'bool' || referenceTrackType === 'string' ) continue; - - // Find the track in the target clip whose name and type matches the reference track - const targetTrack = targetClip.tracks.find( function ( track ) { - - return track.name === referenceTrack.name - && track.ValueTypeName === referenceTrackType; - - } ); - - if ( targetTrack === undefined ) continue; - - let referenceOffset = 0; - const referenceValueSize = referenceTrack.getValueSize(); - - if ( referenceTrack.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline ) { - - referenceOffset = referenceValueSize / 3; - - } - - let targetOffset = 0; - const targetValueSize = targetTrack.getValueSize(); - - if ( targetTrack.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline ) { - - targetOffset = targetValueSize / 3; - - } - - const lastIndex = referenceTrack.times.length - 1; - let referenceValue; - - // Find the value to subtract out of the track - if ( referenceTime <= referenceTrack.times[ 0 ] ) { - - // Reference frame is earlier than the first keyframe, so just use the first keyframe - const startIndex = referenceOffset; - const endIndex = referenceValueSize - referenceOffset; - referenceValue = referenceTrack.values.slice( startIndex, endIndex ); - - } else if ( referenceTime >= referenceTrack.times[ lastIndex ] ) { - - // Reference frame is after the last keyframe, so just use the last keyframe - const startIndex = lastIndex * referenceValueSize + referenceOffset; - const endIndex = startIndex + referenceValueSize - referenceOffset; - referenceValue = referenceTrack.values.slice( startIndex, endIndex ); - - } else { - - // Interpolate to the reference value - const interpolant = referenceTrack.createInterpolant(); - const startIndex = referenceOffset; - const endIndex = referenceValueSize - referenceOffset; - interpolant.evaluate( referenceTime ); - referenceValue = interpolant.resultBuffer.slice( startIndex, endIndex ); - - } - - // Conjugate the quaternion - if ( referenceTrackType === 'quaternion' ) { - - const referenceQuat = new Quaternion().fromArray( referenceValue ).normalize().conjugate(); - referenceQuat.toArray( referenceValue ); - - } - - // Subtract the reference value from all of the track values - - const numTimes = targetTrack.times.length; - for ( let j = 0; j < numTimes; ++ j ) { - - const valueStart = j * targetValueSize + targetOffset; - - if ( referenceTrackType === 'quaternion' ) { - - // Multiply the conjugate for quaternion track types - Quaternion.multiplyQuaternionsFlat( - targetTrack.values, - valueStart, - referenceValue, - 0, - targetTrack.values, - valueStart - ); - - } else { - - const valueEnd = targetValueSize - targetOffset * 2; - - // Subtract each value for all other numeric track types - for ( let k = 0; k < valueEnd; ++ k ) { - - targetTrack.values[ valueStart + k ] -= referenceValue[ k ]; - - } - - } - - } - - } - - targetClip.blendMode = AdditiveAnimationBlendMode; - - return targetClip; - -} - -const AnimationUtils = { - convertArray: convertArray, - isTypedArray: isTypedArray, - getKeyframeOrder: getKeyframeOrder, - sortedArray: sortedArray, - flattenJSON: flattenJSON, - subclip: subclip, - makeClipAdditive: makeClipAdditive -}; - -/** - * Abstract base class of interpolants over parametric samples. - * - * The parameter domain is one dimensional, typically the time or a path - * along a curve defined by the data. - * - * The sample values can have any dimensionality and derived classes may - * apply special interpretations to the data. - * - * This class provides the interval seek in a Template Method, deferring - * the actual interpolation to derived classes. - * - * Time complexity is O(1) for linear access crossing at most two points - * and O(log N) for random access, where N is the number of positions. - * - * References: - * - * http://www.oodesign.com/template-method-pattern.html - * - */ - -class Interpolant { - - constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) { - - this.parameterPositions = parameterPositions; - this._cachedIndex = 0; - - this.resultBuffer = resultBuffer !== undefined ? - resultBuffer : new sampleValues.constructor( sampleSize ); - this.sampleValues = sampleValues; - this.valueSize = sampleSize; - - this.settings = null; - this.DefaultSettings_ = {}; - - } - - evaluate( t ) { - - const pp = this.parameterPositions; - let i1 = this._cachedIndex, - t1 = pp[ i1 ], - t0 = pp[ i1 - 1 ]; - - validate_interval: { - - seek: { - - let right; - - linear_scan: { - - //- See http://jsperf.com/comparison-to-undefined/3 - //- slower code: - //- - //- if ( t >= t1 || t1 === undefined ) { - forward_scan: if ( ! ( t < t1 ) ) { - - for ( let giveUpAt = i1 + 2; ; ) { - - if ( t1 === undefined ) { - - if ( t < t0 ) break forward_scan; - - // after end - - i1 = pp.length; - this._cachedIndex = i1; - return this.copySampleValue_( i1 - 1 ); - - } - - if ( i1 === giveUpAt ) break; // this loop - - t0 = t1; - t1 = pp[ ++ i1 ]; - - if ( t < t1 ) { - - // we have arrived at the sought interval - break seek; - - } - - } - - // prepare binary search on the right side of the index - right = pp.length; - break linear_scan; - - } - - //- slower code: - //- if ( t < t0 || t0 === undefined ) { - if ( ! ( t >= t0 ) ) { - - // looping? - - const t1global = pp[ 1 ]; - - if ( t < t1global ) { - - i1 = 2; // + 1, using the scan for the details - t0 = t1global; - - } - - // linear reverse scan - - for ( let giveUpAt = i1 - 2; ; ) { - - if ( t0 === undefined ) { - - // before start - - this._cachedIndex = 0; - return this.copySampleValue_( 0 ); - - } - - if ( i1 === giveUpAt ) break; // this loop - - t1 = t0; - t0 = pp[ -- i1 - 1 ]; - - if ( t >= t0 ) { - - // we have arrived at the sought interval - break seek; - - } - - } - - // prepare binary search on the left side of the index - right = i1; - i1 = 0; - break linear_scan; - - } - - // the interval is valid - - break validate_interval; - - } // linear scan - - // binary search - - while ( i1 < right ) { - - const mid = ( i1 + right ) >>> 1; - - if ( t < pp[ mid ] ) { - - right = mid; - - } else { - - i1 = mid + 1; - - } - - } - - t1 = pp[ i1 ]; - t0 = pp[ i1 - 1 ]; - - // check boundary cases, again - - if ( t0 === undefined ) { - - this._cachedIndex = 0; - return this.copySampleValue_( 0 ); - - } - - if ( t1 === undefined ) { - - i1 = pp.length; - this._cachedIndex = i1; - return this.copySampleValue_( i1 - 1 ); - - } - - } // seek - - this._cachedIndex = i1; - - this.intervalChanged_( i1, t0, t1 ); - - } // validate_interval - - return this.interpolate_( i1, t0, t, t1 ); - - } - - getSettings_() { - - return this.settings || this.DefaultSettings_; - - } - - copySampleValue_( index ) { - - // copies a sample value to the result buffer - - const result = this.resultBuffer, - values = this.sampleValues, - stride = this.valueSize, - offset = index * stride; - - for ( let i = 0; i !== stride; ++ i ) { - - result[ i ] = values[ offset + i ]; - - } - - return result; - - } - - // Template methods for derived classes: - - interpolate_( /* i1, t0, t, t1 */ ) { - - throw new Error( 'call to abstract method' ); - // implementations shall return this.resultBuffer - - } - - intervalChanged_( /* i1, t0, t1 */ ) { - - // empty - - } - -} - -/** - * Fast and simple cubic spline interpolant. - * - * It was derived from a Hermitian construction setting the first derivative - * at each sample position to the linear slope between neighboring positions - * over their parameter interval. - */ - -class CubicInterpolant extends Interpolant { - - constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) { - - super( parameterPositions, sampleValues, sampleSize, resultBuffer ); - - this._weightPrev = - 0; - this._offsetPrev = - 0; - this._weightNext = - 0; - this._offsetNext = - 0; - - this.DefaultSettings_ = { - - endingStart: ZeroCurvatureEnding, - endingEnd: ZeroCurvatureEnding - - }; - - } - - intervalChanged_( i1, t0, t1 ) { - - const pp = this.parameterPositions; - let iPrev = i1 - 2, - iNext = i1 + 1, - - tPrev = pp[ iPrev ], - tNext = pp[ iNext ]; - - if ( tPrev === undefined ) { - - switch ( this.getSettings_().endingStart ) { - - case ZeroSlopeEnding: - - // f'(t0) = 0 - iPrev = i1; - tPrev = 2 * t0 - t1; - - break; - - case WrapAroundEnding: - - // use the other end of the curve - iPrev = pp.length - 2; - tPrev = t0 + pp[ iPrev ] - pp[ iPrev + 1 ]; - - break; - - default: // ZeroCurvatureEnding - - // f''(t0) = 0 a.k.a. Natural Spline - iPrev = i1; - tPrev = t1; - - } - - } - - if ( tNext === undefined ) { - - switch ( this.getSettings_().endingEnd ) { - - case ZeroSlopeEnding: - - // f'(tN) = 0 - iNext = i1; - tNext = 2 * t1 - t0; - - break; - - case WrapAroundEnding: - - // use the other end of the curve - iNext = 1; - tNext = t1 + pp[ 1 ] - pp[ 0 ]; - - break; - - default: // ZeroCurvatureEnding - - // f''(tN) = 0, a.k.a. Natural Spline - iNext = i1 - 1; - tNext = t0; - - } - - } - - const halfDt = ( t1 - t0 ) * 0.5, - stride = this.valueSize; - - this._weightPrev = halfDt / ( t0 - tPrev ); - this._weightNext = halfDt / ( tNext - t1 ); - this._offsetPrev = iPrev * stride; - this._offsetNext = iNext * stride; - - } - - interpolate_( i1, t0, t, t1 ) { - - const result = this.resultBuffer, - values = this.sampleValues, - stride = this.valueSize, - - o1 = i1 * stride, o0 = o1 - stride, - oP = this._offsetPrev, oN = this._offsetNext, - wP = this._weightPrev, wN = this._weightNext, - - p = ( t - t0 ) / ( t1 - t0 ), - pp = p * p, - ppp = pp * p; - - // evaluate polynomials - - const sP = - wP * ppp + 2 * wP * pp - wP * p; - const s0 = ( 1 + wP ) * ppp + ( - 1.5 - 2 * wP ) * pp + ( - 0.5 + wP ) * p + 1; - const s1 = ( - 1 - wN ) * ppp + ( 1.5 + wN ) * pp + 0.5 * p; - const sN = wN * ppp - wN * pp; - - // combine data linearly - - for ( let i = 0; i !== stride; ++ i ) { - - result[ i ] = - sP * values[ oP + i ] + - s0 * values[ o0 + i ] + - s1 * values[ o1 + i ] + - sN * values[ oN + i ]; - - } - - return result; - - } - -} - -class LinearInterpolant extends Interpolant { - - constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) { - - super( parameterPositions, sampleValues, sampleSize, resultBuffer ); - - } - - interpolate_( i1, t0, t, t1 ) { - - const result = this.resultBuffer, - values = this.sampleValues, - stride = this.valueSize, - - offset1 = i1 * stride, - offset0 = offset1 - stride, - - weight1 = ( t - t0 ) / ( t1 - t0 ), - weight0 = 1 - weight1; - - for ( let i = 0; i !== stride; ++ i ) { - - result[ i ] = - values[ offset0 + i ] * weight0 + - values[ offset1 + i ] * weight1; - - } - - return result; - - } - -} - -/** - * - * Interpolant that evaluates to the sample value at the position preceding - * the parameter. - */ - -class DiscreteInterpolant extends Interpolant { - - constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) { - - super( parameterPositions, sampleValues, sampleSize, resultBuffer ); - - } - - interpolate_( i1 /*, t0, t, t1 */ ) { - - return this.copySampleValue_( i1 - 1 ); - - } - -} - -class KeyframeTrack { - - constructor( name, times, values, interpolation ) { - - if ( name === undefined ) throw new Error( 'THREE.KeyframeTrack: track name is undefined' ); - if ( times === undefined || times.length === 0 ) throw new Error( 'THREE.KeyframeTrack: no keyframes in track named ' + name ); - - this.name = name; - - this.times = convertArray( times, this.TimeBufferType ); - this.values = convertArray( values, this.ValueBufferType ); - - this.setInterpolation( interpolation || this.DefaultInterpolation ); - - } - - // Serialization (in static context, because of constructor invocation - // and automatic invocation of .toJSON): - - static toJSON( track ) { - - const trackType = track.constructor; - - let json; - - // derived classes can define a static toJSON method - if ( trackType.toJSON !== this.toJSON ) { - - json = trackType.toJSON( track ); - - } else { - - // by default, we assume the data can be serialized as-is - json = { - - 'name': track.name, - 'times': convertArray( track.times, Array ), - 'values': convertArray( track.values, Array ) - - }; - - const interpolation = track.getInterpolation(); - - if ( interpolation !== track.DefaultInterpolation ) { - - json.interpolation = interpolation; - - } - - } - - json.type = track.ValueTypeName; // mandatory - - return json; - - } - - InterpolantFactoryMethodDiscrete( result ) { - - return new DiscreteInterpolant( this.times, this.values, this.getValueSize(), result ); - - } - - InterpolantFactoryMethodLinear( result ) { - - return new LinearInterpolant( this.times, this.values, this.getValueSize(), result ); - - } - - InterpolantFactoryMethodSmooth( result ) { - - return new CubicInterpolant( this.times, this.values, this.getValueSize(), result ); - - } - - setInterpolation( interpolation ) { - - let factoryMethod; - - switch ( interpolation ) { - - case InterpolateDiscrete: - - factoryMethod = this.InterpolantFactoryMethodDiscrete; - - break; - - case InterpolateLinear: - - factoryMethod = this.InterpolantFactoryMethodLinear; - - break; - - case InterpolateSmooth: - - factoryMethod = this.InterpolantFactoryMethodSmooth; - - break; - - } - - if ( factoryMethod === undefined ) { - - const message = 'unsupported interpolation for ' + - this.ValueTypeName + ' keyframe track named ' + this.name; - - if ( this.createInterpolant === undefined ) { - - // fall back to default, unless the default itself is messed up - if ( interpolation !== this.DefaultInterpolation ) { - - this.setInterpolation( this.DefaultInterpolation ); - - } else { - - throw new Error( message ); // fatal, in this case - - } - - } - - console.warn( 'THREE.KeyframeTrack:', message ); - return this; - - } - - this.createInterpolant = factoryMethod; - - return this; - - } - - getInterpolation() { - - switch ( this.createInterpolant ) { - - case this.InterpolantFactoryMethodDiscrete: - - return InterpolateDiscrete; - - case this.InterpolantFactoryMethodLinear: - - return InterpolateLinear; - - case this.InterpolantFactoryMethodSmooth: - - return InterpolateSmooth; - - } - - } - - getValueSize() { - - return this.values.length / this.times.length; - - } - - // move all keyframes either forwards or backwards in time - shift( timeOffset ) { - - if ( timeOffset !== 0.0 ) { - - const times = this.times; - - for ( let i = 0, n = times.length; i !== n; ++ i ) { - - times[ i ] += timeOffset; - - } - - } - - return this; - - } - - // scale all keyframe times by a factor (useful for frame <-> seconds conversions) - scale( timeScale ) { - - if ( timeScale !== 1.0 ) { - - const times = this.times; - - for ( let i = 0, n = times.length; i !== n; ++ i ) { - - times[ i ] *= timeScale; - - } - - } - - return this; - - } - - // removes keyframes before and after animation without changing any values within the range [startTime, endTime]. - // IMPORTANT: We do not shift around keys to the start of the track time, because for interpolated keys this will change their values - trim( startTime, endTime ) { - - const times = this.times, - nKeys = times.length; - - let from = 0, - to = nKeys - 1; - - while ( from !== nKeys && times[ from ] < startTime ) { - - ++ from; - - } - - while ( to !== - 1 && times[ to ] > endTime ) { - - -- to; - - } - - ++ to; // inclusive -> exclusive bound - - if ( from !== 0 || to !== nKeys ) { - - // empty tracks are forbidden, so keep at least one keyframe - if ( from >= to ) { - - to = Math.max( to, 1 ); - from = to - 1; - - } - - const stride = this.getValueSize(); - this.times = times.slice( from, to ); - this.values = this.values.slice( from * stride, to * stride ); - - } - - return this; - - } - - // ensure we do not get a GarbageInGarbageOut situation, make sure tracks are at least minimally viable - validate() { - - let valid = true; - - const valueSize = this.getValueSize(); - if ( valueSize - Math.floor( valueSize ) !== 0 ) { - - console.error( 'THREE.KeyframeTrack: Invalid value size in track.', this ); - valid = false; - - } - - const times = this.times, - values = this.values, - - nKeys = times.length; - - if ( nKeys === 0 ) { - - console.error( 'THREE.KeyframeTrack: Track is empty.', this ); - valid = false; - - } - - let prevTime = null; - - for ( let i = 0; i !== nKeys; i ++ ) { - - const currTime = times[ i ]; - - if ( typeof currTime === 'number' && isNaN( currTime ) ) { - - console.error( 'THREE.KeyframeTrack: Time is not a valid number.', this, i, currTime ); - valid = false; - break; - - } - - if ( prevTime !== null && prevTime > currTime ) { - - console.error( 'THREE.KeyframeTrack: Out of order keys.', this, i, currTime, prevTime ); - valid = false; - break; - - } - - prevTime = currTime; - - } - - if ( values !== undefined ) { - - if ( isTypedArray( values ) ) { - - for ( let i = 0, n = values.length; i !== n; ++ i ) { - - const value = values[ i ]; - - if ( isNaN( value ) ) { - - console.error( 'THREE.KeyframeTrack: Value is not a valid number.', this, i, value ); - valid = false; - break; - - } - - } - - } - - } - - return valid; - - } - - // removes equivalent sequential keys as common in morph target sequences - // (0,0,0,0,1,1,1,0,0,0,0,0,0,0) --> (0,0,1,1,0,0) - optimize() { - - // times or values may be shared with other tracks, so overwriting is unsafe - const times = this.times.slice(), - values = this.values.slice(), - stride = this.getValueSize(), - - smoothInterpolation = this.getInterpolation() === InterpolateSmooth, - - lastIndex = times.length - 1; - - let writeIndex = 1; - - for ( let i = 1; i < lastIndex; ++ i ) { - - let keep = false; - - const time = times[ i ]; - const timeNext = times[ i + 1 ]; - - // remove adjacent keyframes scheduled at the same time - - if ( time !== timeNext && ( i !== 1 || time !== times[ 0 ] ) ) { - - if ( ! smoothInterpolation ) { - - // remove unnecessary keyframes same as their neighbors - - const offset = i * stride, - offsetP = offset - stride, - offsetN = offset + stride; - - for ( let j = 0; j !== stride; ++ j ) { - - const value = values[ offset + j ]; - - if ( value !== values[ offsetP + j ] || - value !== values[ offsetN + j ] ) { - - keep = true; - break; - - } - - } - - } else { - - keep = true; - - } - - } - - // in-place compaction - - if ( keep ) { - - if ( i !== writeIndex ) { - - times[ writeIndex ] = times[ i ]; - - const readOffset = i * stride, - writeOffset = writeIndex * stride; - - for ( let j = 0; j !== stride; ++ j ) { - - values[ writeOffset + j ] = values[ readOffset + j ]; - - } - - } - - ++ writeIndex; - - } - - } - - // flush last keyframe (compaction looks ahead) - - if ( lastIndex > 0 ) { - - times[ writeIndex ] = times[ lastIndex ]; - - for ( let readOffset = lastIndex * stride, writeOffset = writeIndex * stride, j = 0; j !== stride; ++ j ) { - - values[ writeOffset + j ] = values[ readOffset + j ]; - - } - - ++ writeIndex; - - } - - if ( writeIndex !== times.length ) { - - this.times = times.slice( 0, writeIndex ); - this.values = values.slice( 0, writeIndex * stride ); - - } else { - - this.times = times; - this.values = values; - - } - - return this; - - } - - clone() { - - const times = this.times.slice(); - const values = this.values.slice(); - - const TypedKeyframeTrack = this.constructor; - const track = new TypedKeyframeTrack( this.name, times, values ); - - // Interpolant argument to constructor is not saved, so copy the factory method directly. - track.createInterpolant = this.createInterpolant; - - return track; - - } - -} - -KeyframeTrack.prototype.TimeBufferType = Float32Array; -KeyframeTrack.prototype.ValueBufferType = Float32Array; -KeyframeTrack.prototype.DefaultInterpolation = InterpolateLinear; - -/** - * A Track of Boolean keyframe values. - */ -class BooleanKeyframeTrack extends KeyframeTrack {} - -BooleanKeyframeTrack.prototype.ValueTypeName = 'bool'; -BooleanKeyframeTrack.prototype.ValueBufferType = Array; -BooleanKeyframeTrack.prototype.DefaultInterpolation = InterpolateDiscrete; -BooleanKeyframeTrack.prototype.InterpolantFactoryMethodLinear = undefined; -BooleanKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = undefined; - -/** - * A Track of keyframe values that represent color. - */ -class ColorKeyframeTrack extends KeyframeTrack {} - -ColorKeyframeTrack.prototype.ValueTypeName = 'color'; - -/** - * A Track of numeric keyframe values. - */ -class NumberKeyframeTrack extends KeyframeTrack {} - -NumberKeyframeTrack.prototype.ValueTypeName = 'number'; - -/** - * Spherical linear unit quaternion interpolant. - */ - -class QuaternionLinearInterpolant extends Interpolant { - - constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) { - - super( parameterPositions, sampleValues, sampleSize, resultBuffer ); - - } - - interpolate_( i1, t0, t, t1 ) { - - const result = this.resultBuffer, - values = this.sampleValues, - stride = this.valueSize, - - alpha = ( t - t0 ) / ( t1 - t0 ); - - let offset = i1 * stride; - - for ( let end = offset + stride; offset !== end; offset += 4 ) { - - Quaternion.slerpFlat( result, 0, values, offset - stride, values, offset, alpha ); - - } - - return result; - - } - -} - -/** - * A Track of quaternion keyframe values. - */ -class QuaternionKeyframeTrack extends KeyframeTrack { - - InterpolantFactoryMethodLinear( result ) { - - return new QuaternionLinearInterpolant( this.times, this.values, this.getValueSize(), result ); - - } - -} - -QuaternionKeyframeTrack.prototype.ValueTypeName = 'quaternion'; -// ValueBufferType is inherited -QuaternionKeyframeTrack.prototype.DefaultInterpolation = InterpolateLinear; -QuaternionKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = undefined; - -/** - * A Track that interpolates Strings - */ -class StringKeyframeTrack extends KeyframeTrack {} - -StringKeyframeTrack.prototype.ValueTypeName = 'string'; -StringKeyframeTrack.prototype.ValueBufferType = Array; -StringKeyframeTrack.prototype.DefaultInterpolation = InterpolateDiscrete; -StringKeyframeTrack.prototype.InterpolantFactoryMethodLinear = undefined; -StringKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = undefined; - -/** - * A Track of vectored keyframe values. - */ -class VectorKeyframeTrack extends KeyframeTrack {} - -VectorKeyframeTrack.prototype.ValueTypeName = 'vector'; - -class AnimationClip { - - constructor( name, duration = - 1, tracks, blendMode = NormalAnimationBlendMode ) { - - this.name = name; - this.tracks = tracks; - this.duration = duration; - this.blendMode = blendMode; - - this.uuid = generateUUID(); - - // this means it should figure out its duration by scanning the tracks - if ( this.duration < 0 ) { - - this.resetDuration(); - - } - - } - - - static parse( json ) { - - const tracks = [], - jsonTracks = json.tracks, - frameTime = 1.0 / ( json.fps || 1.0 ); - - for ( let i = 0, n = jsonTracks.length; i !== n; ++ i ) { - - tracks.push( parseKeyframeTrack( jsonTracks[ i ] ).scale( frameTime ) ); - - } - - const clip = new this( json.name, json.duration, tracks, json.blendMode ); - clip.uuid = json.uuid; - - return clip; - - } - - static toJSON( clip ) { - - const tracks = [], - clipTracks = clip.tracks; - - const json = { - - 'name': clip.name, - 'duration': clip.duration, - 'tracks': tracks, - 'uuid': clip.uuid, - 'blendMode': clip.blendMode - - }; - - for ( let i = 0, n = clipTracks.length; i !== n; ++ i ) { - - tracks.push( KeyframeTrack.toJSON( clipTracks[ i ] ) ); - - } - - return json; - - } - - static CreateFromMorphTargetSequence( name, morphTargetSequence, fps, noLoop ) { - - const numMorphTargets = morphTargetSequence.length; - const tracks = []; - - for ( let i = 0; i < numMorphTargets; i ++ ) { - - let times = []; - let values = []; - - times.push( - ( i + numMorphTargets - 1 ) % numMorphTargets, - i, - ( i + 1 ) % numMorphTargets ); - - values.push( 0, 1, 0 ); - - const order = getKeyframeOrder( times ); - times = sortedArray( times, 1, order ); - values = sortedArray( values, 1, order ); - - // if there is a key at the first frame, duplicate it as the - // last frame as well for perfect loop. - if ( ! noLoop && times[ 0 ] === 0 ) { - - times.push( numMorphTargets ); - values.push( values[ 0 ] ); - - } - - tracks.push( - new NumberKeyframeTrack( - '.morphTargetInfluences[' + morphTargetSequence[ i ].name + ']', - times, values - ).scale( 1.0 / fps ) ); - - } - - return new this( name, - 1, tracks ); - - } - - static findByName( objectOrClipArray, name ) { - - let clipArray = objectOrClipArray; - - if ( ! Array.isArray( objectOrClipArray ) ) { - - const o = objectOrClipArray; - clipArray = o.geometry && o.geometry.animations || o.animations; - - } - - for ( let i = 0; i < clipArray.length; i ++ ) { - - if ( clipArray[ i ].name === name ) { - - return clipArray[ i ]; - - } - - } - - return null; - - } - - static CreateClipsFromMorphTargetSequences( morphTargets, fps, noLoop ) { - - const animationToMorphTargets = {}; - - // tested with https://regex101.com/ on trick sequences - // such flamingo_flyA_003, flamingo_run1_003, crdeath0059 - const pattern = /^([\w-]*?)([\d]+)$/; - - // sort morph target names into animation groups based - // patterns like Walk_001, Walk_002, Run_001, Run_002 - for ( let i = 0, il = morphTargets.length; i < il; i ++ ) { - - const morphTarget = morphTargets[ i ]; - const parts = morphTarget.name.match( pattern ); - - if ( parts && parts.length > 1 ) { - - const name = parts[ 1 ]; - - let animationMorphTargets = animationToMorphTargets[ name ]; - - if ( ! animationMorphTargets ) { - - animationToMorphTargets[ name ] = animationMorphTargets = []; - - } - - animationMorphTargets.push( morphTarget ); - - } - - } - - const clips = []; - - for ( const name in animationToMorphTargets ) { - - clips.push( this.CreateFromMorphTargetSequence( name, animationToMorphTargets[ name ], fps, noLoop ) ); - - } - - return clips; - - } - - // parse the animation.hierarchy format - static parseAnimation( animation, bones ) { - - if ( ! animation ) { - - console.error( 'THREE.AnimationClip: No animation in JSONLoader data.' ); - return null; - - } - - const addNonemptyTrack = function ( trackType, trackName, animationKeys, propertyName, destTracks ) { - - // only return track if there are actually keys. - if ( animationKeys.length !== 0 ) { - - const times = []; - const values = []; - - flattenJSON( animationKeys, times, values, propertyName ); - - // empty keys are filtered out, so check again - if ( times.length !== 0 ) { - - destTracks.push( new trackType( trackName, times, values ) ); - - } - - } - - }; - - const tracks = []; - - const clipName = animation.name || 'default'; - const fps = animation.fps || 30; - const blendMode = animation.blendMode; - - // automatic length determination in AnimationClip. - let duration = animation.length || - 1; - - const hierarchyTracks = animation.hierarchy || []; - - for ( let h = 0; h < hierarchyTracks.length; h ++ ) { - - const animationKeys = hierarchyTracks[ h ].keys; - - // skip empty tracks - if ( ! animationKeys || animationKeys.length === 0 ) continue; - - // process morph targets - if ( animationKeys[ 0 ].morphTargets ) { - - // figure out all morph targets used in this track - const morphTargetNames = {}; - - let k; - - for ( k = 0; k < animationKeys.length; k ++ ) { - - if ( animationKeys[ k ].morphTargets ) { - - for ( let m = 0; m < animationKeys[ k ].morphTargets.length; m ++ ) { - - morphTargetNames[ animationKeys[ k ].morphTargets[ m ] ] = - 1; - - } - - } - - } - - // create a track for each morph target with all zero - // morphTargetInfluences except for the keys in which - // the morphTarget is named. - for ( const morphTargetName in morphTargetNames ) { - - const times = []; - const values = []; - - for ( let m = 0; m !== animationKeys[ k ].morphTargets.length; ++ m ) { - - const animationKey = animationKeys[ k ]; - - times.push( animationKey.time ); - values.push( ( animationKey.morphTarget === morphTargetName ) ? 1 : 0 ); - - } - - tracks.push( new NumberKeyframeTrack( '.morphTargetInfluence[' + morphTargetName + ']', times, values ) ); - - } - - duration = morphTargetNames.length * fps; - - } else { - - // ...assume skeletal animation - - const boneName = '.bones[' + bones[ h ].name + ']'; - - addNonemptyTrack( - VectorKeyframeTrack, boneName + '.position', - animationKeys, 'pos', tracks ); - - addNonemptyTrack( - QuaternionKeyframeTrack, boneName + '.quaternion', - animationKeys, 'rot', tracks ); - - addNonemptyTrack( - VectorKeyframeTrack, boneName + '.scale', - animationKeys, 'scl', tracks ); - - } - - } - - if ( tracks.length === 0 ) { - - return null; - - } - - const clip = new this( clipName, duration, tracks, blendMode ); - - return clip; - - } - - resetDuration() { - - const tracks = this.tracks; - let duration = 0; - - for ( let i = 0, n = tracks.length; i !== n; ++ i ) { - - const track = this.tracks[ i ]; - - duration = Math.max( duration, track.times[ track.times.length - 1 ] ); - - } - - this.duration = duration; - - return this; - - } - - trim() { - - for ( let i = 0; i < this.tracks.length; i ++ ) { - - this.tracks[ i ].trim( 0, this.duration ); - - } - - return this; - - } - - validate() { - - let valid = true; - - for ( let i = 0; i < this.tracks.length; i ++ ) { - - valid = valid && this.tracks[ i ].validate(); - - } - - return valid; - - } - - optimize() { - - for ( let i = 0; i < this.tracks.length; i ++ ) { - - this.tracks[ i ].optimize(); - - } - - return this; - - } - - clone() { - - const tracks = []; - - for ( let i = 0; i < this.tracks.length; i ++ ) { - - tracks.push( this.tracks[ i ].clone() ); - - } - - return new this.constructor( this.name, this.duration, tracks, this.blendMode ); - - } - - toJSON() { - - return this.constructor.toJSON( this ); - - } - -} - -function getTrackTypeForValueTypeName( typeName ) { - - switch ( typeName.toLowerCase() ) { - - case 'scalar': - case 'double': - case 'float': - case 'number': - case 'integer': - - return NumberKeyframeTrack; - - case 'vector': - case 'vector2': - case 'vector3': - case 'vector4': - - return VectorKeyframeTrack; - - case 'color': - - return ColorKeyframeTrack; - - case 'quaternion': - - return QuaternionKeyframeTrack; - - case 'bool': - case 'boolean': - - return BooleanKeyframeTrack; - - case 'string': - - return StringKeyframeTrack; - - } - - throw new Error( 'THREE.KeyframeTrack: Unsupported typeName: ' + typeName ); - -} - -function parseKeyframeTrack( json ) { - - if ( json.type === undefined ) { - - throw new Error( 'THREE.KeyframeTrack: track type undefined, can not parse' ); - - } - - const trackType = getTrackTypeForValueTypeName( json.type ); - - if ( json.times === undefined ) { - - const times = [], values = []; - - flattenJSON( json.keys, times, values, 'value' ); - - json.times = times; - json.values = values; - - } - - // derived classes can define a static parse method - if ( trackType.parse !== undefined ) { - - return trackType.parse( json ); - - } else { - - // by default, we assume a constructor compatible with the base - return new trackType( json.name, json.times, json.values, json.interpolation ); - - } - -} - -const Cache = { - - enabled: false, - - files: {}, - - add: function ( key, file ) { - - if ( this.enabled === false ) return; - - // console.log( 'THREE.Cache', 'Adding key:', key ); - - this.files[ key ] = file; - - }, - - get: function ( key ) { - - if ( this.enabled === false ) return; - - // console.log( 'THREE.Cache', 'Checking key:', key ); - - return this.files[ key ]; - - }, - - remove: function ( key ) { - - delete this.files[ key ]; - - }, - - clear: function () { - - this.files = {}; - - } - -}; - -class LoadingManager { - - constructor( onLoad, onProgress, onError ) { - - const scope = this; - - let isLoading = false; - let itemsLoaded = 0; - let itemsTotal = 0; - let urlModifier = undefined; - const handlers = []; - - // Refer to #5689 for the reason why we don't set .onStart - // in the constructor - - this.onStart = undefined; - this.onLoad = onLoad; - this.onProgress = onProgress; - this.onError = onError; - - this.itemStart = function ( url ) { - - itemsTotal ++; - - if ( isLoading === false ) { - - if ( scope.onStart !== undefined ) { - - scope.onStart( url, itemsLoaded, itemsTotal ); - - } - - } - - isLoading = true; - - }; - - this.itemEnd = function ( url ) { - - itemsLoaded ++; - - if ( scope.onProgress !== undefined ) { - - scope.onProgress( url, itemsLoaded, itemsTotal ); - - } - - if ( itemsLoaded === itemsTotal ) { - - isLoading = false; - - if ( scope.onLoad !== undefined ) { - - scope.onLoad(); - - } - - } - - }; - - this.itemError = function ( url ) { - - if ( scope.onError !== undefined ) { - - scope.onError( url ); - - } - - }; - - this.resolveURL = function ( url ) { - - if ( urlModifier ) { - - return urlModifier( url ); - - } - - return url; - - }; - - this.setURLModifier = function ( transform ) { - - urlModifier = transform; - - return this; - - }; - - this.addHandler = function ( regex, loader ) { - - handlers.push( regex, loader ); - - return this; - - }; - - this.removeHandler = function ( regex ) { - - const index = handlers.indexOf( regex ); - - if ( index !== - 1 ) { - - handlers.splice( index, 2 ); - - } - - return this; - - }; - - this.getHandler = function ( file ) { - - for ( let i = 0, l = handlers.length; i < l; i += 2 ) { - - const regex = handlers[ i ]; - const loader = handlers[ i + 1 ]; - - if ( regex.global ) regex.lastIndex = 0; // see #17920 - - if ( regex.test( file ) ) { - - return loader; - - } - - } - - return null; - - }; - - } - -} - -const DefaultLoadingManager = /*@__PURE__*/ new LoadingManager(); - -class Loader { - - constructor( manager ) { - - this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; - - this.crossOrigin = 'anonymous'; - this.withCredentials = false; - this.path = ''; - this.resourcePath = ''; - this.requestHeader = {}; - - } - - load( /* url, onLoad, onProgress, onError */ ) {} - - loadAsync( url, onProgress ) { - - const scope = this; - - return new Promise( function ( resolve, reject ) { - - scope.load( url, resolve, onProgress, reject ); - - } ); - - } - - parse( /* data */ ) {} - - setCrossOrigin( crossOrigin ) { - - this.crossOrigin = crossOrigin; - return this; - - } - - setWithCredentials( value ) { - - this.withCredentials = value; - return this; - - } - - setPath( path ) { - - this.path = path; - return this; - - } - - setResourcePath( resourcePath ) { - - this.resourcePath = resourcePath; - return this; - - } - - setRequestHeader( requestHeader ) { - - this.requestHeader = requestHeader; - return this; - - } - -} - -Loader.DEFAULT_MATERIAL_NAME = '__DEFAULT'; - -const loading = {}; - -class HttpError extends Error { - - constructor( message, response ) { - - super( message ); - this.response = response; - - } - -} - -class FileLoader extends Loader { - - constructor( manager ) { - - super( manager ); - - } - - load( url, onLoad, onProgress, onError ) { - - if ( url === undefined ) url = ''; - - if ( this.path !== undefined ) url = this.path + url; - - url = this.manager.resolveURL( url ); - - const cached = Cache.get( url ); - - if ( cached !== undefined ) { - - this.manager.itemStart( url ); - - setTimeout( () => { - - if ( onLoad ) onLoad( cached ); - - this.manager.itemEnd( url ); - - }, 0 ); - - return cached; - - } - - // Check if request is duplicate - - if ( loading[ url ] !== undefined ) { - - loading[ url ].push( { - - onLoad: onLoad, - onProgress: onProgress, - onError: onError - - } ); - - return; - - } - - // Initialise array for duplicate requests - loading[ url ] = []; - - loading[ url ].push( { - onLoad: onLoad, - onProgress: onProgress, - onError: onError, - } ); - - // create request - const req = new Request( url, { - headers: new Headers( this.requestHeader ), - credentials: this.withCredentials ? 'include' : 'same-origin', - // An abort controller could be added within a future PR - } ); - - // record states ( avoid data race ) - const mimeType = this.mimeType; - const responseType = this.responseType; - - // start the fetch - fetch( req ) - .then( response => { - - if ( response.status === 200 || response.status === 0 ) { - - // Some browsers return HTTP Status 0 when using non-http protocol - // e.g. 'file://' or 'data://'. Handle as success. - - if ( response.status === 0 ) { - - console.warn( 'THREE.FileLoader: HTTP Status 0 received.' ); - - } - - // Workaround: Checking if response.body === undefined for Alipay browser #23548 - - if ( typeof ReadableStream === 'undefined' || response.body === undefined || response.body.getReader === undefined ) { - - return response; - - } - - const callbacks = loading[ url ]; - const reader = response.body.getReader(); - - // Nginx needs X-File-Size check - // https://serverfault.com/questions/482875/why-does-nginx-remove-content-length-header-for-chunked-content - const contentLength = response.headers.get( 'Content-Length' ) || response.headers.get( 'X-File-Size' ); - const total = contentLength ? parseInt( contentLength ) : 0; - const lengthComputable = total !== 0; - let loaded = 0; - - // periodically read data into the new stream tracking while download progress - const stream = new ReadableStream( { - start( controller ) { - - readData(); - - function readData() { - - reader.read().then( ( { done, value } ) => { - - if ( done ) { - - controller.close(); - - } else { - - loaded += value.byteLength; - - const event = new ProgressEvent( 'progress', { lengthComputable, loaded, total } ); - for ( let i = 0, il = callbacks.length; i < il; i ++ ) { - - const callback = callbacks[ i ]; - if ( callback.onProgress ) callback.onProgress( event ); - - } - - controller.enqueue( value ); - readData(); - - } - - } ); - - } - - } - - } ); - - return new Response( stream ); - - } else { - - throw new HttpError( `fetch for "${response.url}" responded with ${response.status}: ${response.statusText}`, response ); - - } - - } ) - .then( response => { - - switch ( responseType ) { - - case 'arraybuffer': - - return response.arrayBuffer(); - - case 'blob': - - return response.blob(); - - case 'document': - - return response.text() - .then( text => { - - const parser = new DOMParser(); - return parser.parseFromString( text, mimeType ); - - } ); - - case 'json': - - return response.json(); - - default: - - if ( mimeType === undefined ) { - - return response.text(); - - } else { - - // sniff encoding - const re = /charset="?([^;"\s]*)"?/i; - const exec = re.exec( mimeType ); - const label = exec && exec[ 1 ] ? exec[ 1 ].toLowerCase() : undefined; - const decoder = new TextDecoder( label ); - return response.arrayBuffer().then( ab => decoder.decode( ab ) ); - - } - - } - - } ) - .then( data => { - - // Add to cache only on HTTP success, so that we do not cache - // error response bodies as proper responses to requests. - Cache.add( url, data ); - - const callbacks = loading[ url ]; - delete loading[ url ]; - - for ( let i = 0, il = callbacks.length; i < il; i ++ ) { - - const callback = callbacks[ i ]; - if ( callback.onLoad ) callback.onLoad( data ); - - } - - } ) - .catch( err => { - - // Abort errors and other errors are handled the same - - const callbacks = loading[ url ]; - - if ( callbacks === undefined ) { - - // When onLoad was called and url was deleted in `loading` - this.manager.itemError( url ); - throw err; - - } - - delete loading[ url ]; - - for ( let i = 0, il = callbacks.length; i < il; i ++ ) { - - const callback = callbacks[ i ]; - if ( callback.onError ) callback.onError( err ); - - } - - this.manager.itemError( url ); - - } ) - .finally( () => { - - this.manager.itemEnd( url ); - - } ); - - this.manager.itemStart( url ); - - } - - setResponseType( value ) { - - this.responseType = value; - return this; - - } - - setMimeType( value ) { - - this.mimeType = value; - return this; - - } - -} - -class AnimationLoader extends Loader { - - constructor( manager ) { - - super( manager ); - - } - - load( url, onLoad, onProgress, onError ) { - - const scope = this; - - const loader = new FileLoader( this.manager ); - loader.setPath( this.path ); - loader.setRequestHeader( this.requestHeader ); - loader.setWithCredentials( this.withCredentials ); - loader.load( url, function ( text ) { - - try { - - onLoad( scope.parse( JSON.parse( text ) ) ); - - } catch ( e ) { - - if ( onError ) { - - onError( e ); - - } else { - - console.error( e ); - - } - - scope.manager.itemError( url ); - - } - - }, onProgress, onError ); - - } - - parse( json ) { - - const animations = []; - - for ( let i = 0; i < json.length; i ++ ) { - - const clip = AnimationClip.parse( json[ i ] ); - - animations.push( clip ); - - } - - return animations; - - } - -} - -/** - * Abstract Base class to block based textures loader (dds, pvr, ...) - * - * Sub classes have to implement the parse() method which will be used in load(). - */ - -class CompressedTextureLoader extends Loader { - - constructor( manager ) { - - super( manager ); - - } - - load( url, onLoad, onProgress, onError ) { - - const scope = this; - - const images = []; - - const texture = new CompressedTexture(); - - const loader = new FileLoader( this.manager ); - loader.setPath( this.path ); - loader.setResponseType( 'arraybuffer' ); - loader.setRequestHeader( this.requestHeader ); - loader.setWithCredentials( scope.withCredentials ); - - let loaded = 0; - - function loadTexture( i ) { - - loader.load( url[ i ], function ( buffer ) { - - const texDatas = scope.parse( buffer, true ); - - images[ i ] = { - width: texDatas.width, - height: texDatas.height, - format: texDatas.format, - mipmaps: texDatas.mipmaps - }; - - loaded += 1; - - if ( loaded === 6 ) { - - if ( texDatas.mipmapCount === 1 ) texture.minFilter = LinearFilter; - - texture.image = images; - texture.format = texDatas.format; - texture.needsUpdate = true; - - if ( onLoad ) onLoad( texture ); - - } - - }, onProgress, onError ); - - } - - if ( Array.isArray( url ) ) { - - for ( let i = 0, il = url.length; i < il; ++ i ) { - - loadTexture( i ); - - } - - } else { - - // compressed cubemap texture stored in a single DDS file - - loader.load( url, function ( buffer ) { - - const texDatas = scope.parse( buffer, true ); - - if ( texDatas.isCubemap ) { - - const faces = texDatas.mipmaps.length / texDatas.mipmapCount; - - for ( let f = 0; f < faces; f ++ ) { - - images[ f ] = { mipmaps: [] }; - - for ( let i = 0; i < texDatas.mipmapCount; i ++ ) { - - images[ f ].mipmaps.push( texDatas.mipmaps[ f * texDatas.mipmapCount + i ] ); - images[ f ].format = texDatas.format; - images[ f ].width = texDatas.width; - images[ f ].height = texDatas.height; - - } - - } - - texture.image = images; - - } else { - - texture.image.width = texDatas.width; - texture.image.height = texDatas.height; - texture.mipmaps = texDatas.mipmaps; - - } - - if ( texDatas.mipmapCount === 1 ) { - - texture.minFilter = LinearFilter; - - } - - texture.format = texDatas.format; - texture.needsUpdate = true; - - if ( onLoad ) onLoad( texture ); - - }, onProgress, onError ); - - } - - return texture; - - } - -} - -class ImageLoader extends Loader { - - constructor( manager ) { - - super( manager ); - - } - - load( url, onLoad, onProgress, onError ) { - - if ( this.path !== undefined ) url = this.path + url; - - url = this.manager.resolveURL( url ); - - const scope = this; - - const cached = Cache.get( url ); - - if ( cached !== undefined ) { - - scope.manager.itemStart( url ); - - setTimeout( function () { - - if ( onLoad ) onLoad( cached ); - - scope.manager.itemEnd( url ); - - }, 0 ); - - return cached; - - } - - const image = createElementNS( 'img' ); - - function onImageLoad() { - - removeEventListeners(); - - Cache.add( url, this ); - - if ( onLoad ) onLoad( this ); - - scope.manager.itemEnd( url ); - - } - - function onImageError( event ) { - - removeEventListeners(); - - if ( onError ) onError( event ); - - scope.manager.itemError( url ); - scope.manager.itemEnd( url ); - - } - - function removeEventListeners() { - - image.removeEventListener( 'load', onImageLoad, false ); - image.removeEventListener( 'error', onImageError, false ); - - } - - image.addEventListener( 'load', onImageLoad, false ); - image.addEventListener( 'error', onImageError, false ); - - if ( url.slice( 0, 5 ) !== 'data:' ) { - - if ( this.crossOrigin !== undefined ) image.crossOrigin = this.crossOrigin; - - } - - scope.manager.itemStart( url ); - - image.src = url; - - return image; - - } - -} - -class CubeTextureLoader extends Loader { - - constructor( manager ) { - - super( manager ); - - } - - load( urls, onLoad, onProgress, onError ) { - - const texture = new CubeTexture(); - texture.colorSpace = SRGBColorSpace; - - const loader = new ImageLoader( this.manager ); - loader.setCrossOrigin( this.crossOrigin ); - loader.setPath( this.path ); - - let loaded = 0; - - function loadTexture( i ) { - - loader.load( urls[ i ], function ( image ) { - - texture.images[ i ] = image; - - loaded ++; - - if ( loaded === 6 ) { - - texture.needsUpdate = true; - - if ( onLoad ) onLoad( texture ); - - } - - }, undefined, onError ); - - } - - for ( let i = 0; i < urls.length; ++ i ) { - - loadTexture( i ); - - } - - return texture; - - } - -} - -/** - * Abstract Base class to load generic binary textures formats (rgbe, hdr, ...) - * - * Sub classes have to implement the parse() method which will be used in load(). - */ - -class DataTextureLoader extends Loader { - - constructor( manager ) { - - super( manager ); - - } - - load( url, onLoad, onProgress, onError ) { - - const scope = this; - - const texture = new DataTexture(); - - const loader = new FileLoader( this.manager ); - loader.setResponseType( 'arraybuffer' ); - loader.setRequestHeader( this.requestHeader ); - loader.setPath( this.path ); - loader.setWithCredentials( scope.withCredentials ); - loader.load( url, function ( buffer ) { - - let texData; - - try { - - texData = scope.parse( buffer ); - - } catch ( error ) { - - if ( onError !== undefined ) { - - onError( error ); - - } else { - - console.error( error ); - return; - - } - - } - - if ( texData.image !== undefined ) { - - texture.image = texData.image; - - } else if ( texData.data !== undefined ) { - - texture.image.width = texData.width; - texture.image.height = texData.height; - texture.image.data = texData.data; - - } - - texture.wrapS = texData.wrapS !== undefined ? texData.wrapS : ClampToEdgeWrapping; - texture.wrapT = texData.wrapT !== undefined ? texData.wrapT : ClampToEdgeWrapping; - - texture.magFilter = texData.magFilter !== undefined ? texData.magFilter : LinearFilter; - texture.minFilter = texData.minFilter !== undefined ? texData.minFilter : LinearFilter; - - texture.anisotropy = texData.anisotropy !== undefined ? texData.anisotropy : 1; - - if ( texData.colorSpace !== undefined ) { - - texture.colorSpace = texData.colorSpace; - - } - - if ( texData.flipY !== undefined ) { - - texture.flipY = texData.flipY; - - } - - if ( texData.format !== undefined ) { - - texture.format = texData.format; - - } - - if ( texData.type !== undefined ) { - - texture.type = texData.type; - - } - - if ( texData.mipmaps !== undefined ) { - - texture.mipmaps = texData.mipmaps; - texture.minFilter = LinearMipmapLinearFilter; // presumably... - - } - - if ( texData.mipmapCount === 1 ) { - - texture.minFilter = LinearFilter; - - } - - if ( texData.generateMipmaps !== undefined ) { - - texture.generateMipmaps = texData.generateMipmaps; - - } - - texture.needsUpdate = true; - - if ( onLoad ) onLoad( texture, texData ); - - }, onProgress, onError ); - - - return texture; - - } - -} - -class TextureLoader extends Loader { - - constructor( manager ) { - - super( manager ); - - } - - load( url, onLoad, onProgress, onError ) { - - const texture = new Texture(); - - const loader = new ImageLoader( this.manager ); - loader.setCrossOrigin( this.crossOrigin ); - loader.setPath( this.path ); - - loader.load( url, function ( image ) { - - texture.image = image; - texture.needsUpdate = true; - - if ( onLoad !== undefined ) { - - onLoad( texture ); - - } - - }, onProgress, onError ); - - return texture; - - } - -} - -class Light extends Object3D { - - constructor( color, intensity = 1 ) { - - super(); - - this.isLight = true; - - this.type = 'Light'; - - this.color = new Color( color ); - this.intensity = intensity; - - } - - dispose() { - - // Empty here in base class; some subclasses override. - - } - - copy( source, recursive ) { - - super.copy( source, recursive ); - - this.color.copy( source.color ); - this.intensity = source.intensity; - - return this; - - } - - toJSON( meta ) { - - const data = super.toJSON( meta ); - - data.object.color = this.color.getHex(); - data.object.intensity = this.intensity; - - if ( this.groundColor !== undefined ) data.object.groundColor = this.groundColor.getHex(); - - if ( this.distance !== undefined ) data.object.distance = this.distance; - if ( this.angle !== undefined ) data.object.angle = this.angle; - if ( this.decay !== undefined ) data.object.decay = this.decay; - if ( this.penumbra !== undefined ) data.object.penumbra = this.penumbra; - - if ( this.shadow !== undefined ) data.object.shadow = this.shadow.toJSON(); - - return data; - - } - -} - -class HemisphereLight extends Light { - - constructor( skyColor, groundColor, intensity ) { - - super( skyColor, intensity ); - - this.isHemisphereLight = true; - - this.type = 'HemisphereLight'; - - this.position.copy( Object3D.DEFAULT_UP ); - this.updateMatrix(); - - this.groundColor = new Color( groundColor ); - - } - - copy( source, recursive ) { - - super.copy( source, recursive ); - - this.groundColor.copy( source.groundColor ); - - return this; - - } - -} - -const _projScreenMatrix$1 = /*@__PURE__*/ new Matrix4(); -const _lightPositionWorld$1 = /*@__PURE__*/ new Vector3(); -const _lookTarget$1 = /*@__PURE__*/ new Vector3(); - -class LightShadow { - - constructor( camera ) { - - this.camera = camera; - - this.bias = 0; - this.normalBias = 0; - this.radius = 1; - this.blurSamples = 8; - - this.mapSize = new Vector2( 512, 512 ); - - this.map = null; - this.mapPass = null; - this.matrix = new Matrix4(); - - this.autoUpdate = true; - this.needsUpdate = false; - - this._frustum = new Frustum(); - this._frameExtents = new Vector2( 1, 1 ); - - this._viewportCount = 1; - - this._viewports = [ - - new Vector4( 0, 0, 1, 1 ) - - ]; - - } - - getViewportCount() { - - return this._viewportCount; - - } - - getFrustum() { - - return this._frustum; - - } - - updateMatrices( light ) { - - const shadowCamera = this.camera; - const shadowMatrix = this.matrix; - - _lightPositionWorld$1.setFromMatrixPosition( light.matrixWorld ); - shadowCamera.position.copy( _lightPositionWorld$1 ); - - _lookTarget$1.setFromMatrixPosition( light.target.matrixWorld ); - shadowCamera.lookAt( _lookTarget$1 ); - shadowCamera.updateMatrixWorld(); - - _projScreenMatrix$1.multiplyMatrices( shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse ); - this._frustum.setFromProjectionMatrix( _projScreenMatrix$1 ); - - shadowMatrix.set( - 0.5, 0.0, 0.0, 0.5, - 0.0, 0.5, 0.0, 0.5, - 0.0, 0.0, 0.5, 0.5, - 0.0, 0.0, 0.0, 1.0 - ); - - shadowMatrix.multiply( _projScreenMatrix$1 ); - - } - - getViewport( viewportIndex ) { - - return this._viewports[ viewportIndex ]; - - } - - getFrameExtents() { - - return this._frameExtents; - - } - - dispose() { - - if ( this.map ) { - - this.map.dispose(); - - } - - if ( this.mapPass ) { - - this.mapPass.dispose(); - - } - - } - - copy( source ) { - - this.camera = source.camera.clone(); - - this.bias = source.bias; - this.radius = source.radius; - - this.mapSize.copy( source.mapSize ); - - return this; - - } - - clone() { - - return new this.constructor().copy( this ); - - } - - toJSON() { - - const object = {}; - - if ( this.bias !== 0 ) object.bias = this.bias; - if ( this.normalBias !== 0 ) object.normalBias = this.normalBias; - if ( this.radius !== 1 ) object.radius = this.radius; - if ( this.mapSize.x !== 512 || this.mapSize.y !== 512 ) object.mapSize = this.mapSize.toArray(); - - object.camera = this.camera.toJSON( false ).object; - delete object.camera.matrix; - - return object; - - } - -} - -class SpotLightShadow extends LightShadow { - - constructor() { - - super( new PerspectiveCamera( 50, 1, 0.5, 500 ) ); - - this.isSpotLightShadow = true; - - this.focus = 1; - - } - - updateMatrices( light ) { - - const camera = this.camera; - - const fov = RAD2DEG * 2 * light.angle * this.focus; - const aspect = this.mapSize.width / this.mapSize.height; - const far = light.distance || camera.far; - - if ( fov !== camera.fov || aspect !== camera.aspect || far !== camera.far ) { - - camera.fov = fov; - camera.aspect = aspect; - camera.far = far; - camera.updateProjectionMatrix(); - - } - - super.updateMatrices( light ); - - } - - copy( source ) { - - super.copy( source ); - - this.focus = source.focus; - - return this; - - } - -} - -class SpotLight extends Light { - - constructor( color, intensity, distance = 0, angle = Math.PI / 3, penumbra = 0, decay = 2 ) { - - super( color, intensity ); - - this.isSpotLight = true; - - this.type = 'SpotLight'; - - this.position.copy( Object3D.DEFAULT_UP ); - this.updateMatrix(); - - this.target = new Object3D(); - - this.distance = distance; - this.angle = angle; - this.penumbra = penumbra; - this.decay = decay; - - this.map = null; - - this.shadow = new SpotLightShadow(); - - } - - get power() { - - // compute the light's luminous power (in lumens) from its intensity (in candela) - // by convention for a spotlight, luminous power (lm) = π * luminous intensity (cd) - return this.intensity * Math.PI; - - } - - set power( power ) { - - // set the light's intensity (in candela) from the desired luminous power (in lumens) - this.intensity = power / Math.PI; - - } - - dispose() { - - this.shadow.dispose(); - - } - - copy( source, recursive ) { - - super.copy( source, recursive ); - - this.distance = source.distance; - this.angle = source.angle; - this.penumbra = source.penumbra; - this.decay = source.decay; - - this.target = source.target.clone(); - - this.shadow = source.shadow.clone(); - - return this; - - } - -} - -const _projScreenMatrix = /*@__PURE__*/ new Matrix4(); -const _lightPositionWorld = /*@__PURE__*/ new Vector3(); -const _lookTarget = /*@__PURE__*/ new Vector3(); - -class PointLightShadow extends LightShadow { - - constructor() { - - super( new PerspectiveCamera( 90, 1, 0.5, 500 ) ); - - this.isPointLightShadow = true; - - this._frameExtents = new Vector2( 4, 2 ); - - this._viewportCount = 6; - - this._viewports = [ - // These viewports map a cube-map onto a 2D texture with the - // following orientation: - // - // xzXZ - // y Y - // - // X - Positive x direction - // x - Negative x direction - // Y - Positive y direction - // y - Negative y direction - // Z - Positive z direction - // z - Negative z direction - - // positive X - new Vector4( 2, 1, 1, 1 ), - // negative X - new Vector4( 0, 1, 1, 1 ), - // positive Z - new Vector4( 3, 1, 1, 1 ), - // negative Z - new Vector4( 1, 1, 1, 1 ), - // positive Y - new Vector4( 3, 0, 1, 1 ), - // negative Y - new Vector4( 1, 0, 1, 1 ) - ]; - - this._cubeDirections = [ - new Vector3( 1, 0, 0 ), new Vector3( - 1, 0, 0 ), new Vector3( 0, 0, 1 ), - new Vector3( 0, 0, - 1 ), new Vector3( 0, 1, 0 ), new Vector3( 0, - 1, 0 ) - ]; - - this._cubeUps = [ - new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ), - new Vector3( 0, 1, 0 ), new Vector3( 0, 0, 1 ), new Vector3( 0, 0, - 1 ) - ]; - - } - - updateMatrices( light, viewportIndex = 0 ) { - - const camera = this.camera; - const shadowMatrix = this.matrix; - - const far = light.distance || camera.far; - - if ( far !== camera.far ) { - - camera.far = far; - camera.updateProjectionMatrix(); - - } - - _lightPositionWorld.setFromMatrixPosition( light.matrixWorld ); - camera.position.copy( _lightPositionWorld ); - - _lookTarget.copy( camera.position ); - _lookTarget.add( this._cubeDirections[ viewportIndex ] ); - camera.up.copy( this._cubeUps[ viewportIndex ] ); - camera.lookAt( _lookTarget ); - camera.updateMatrixWorld(); - - shadowMatrix.makeTranslation( - _lightPositionWorld.x, - _lightPositionWorld.y, - _lightPositionWorld.z ); - - _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); - this._frustum.setFromProjectionMatrix( _projScreenMatrix ); - - } - -} - -class PointLight extends Light { - - constructor( color, intensity, distance = 0, decay = 2 ) { - - super( color, intensity ); - - this.isPointLight = true; - - this.type = 'PointLight'; - - this.distance = distance; - this.decay = decay; - - this.shadow = new PointLightShadow(); - - } - - get power() { - - // compute the light's luminous power (in lumens) from its intensity (in candela) - // for an isotropic light source, luminous power (lm) = 4 π luminous intensity (cd) - return this.intensity * 4 * Math.PI; - - } - - set power( power ) { - - // set the light's intensity (in candela) from the desired luminous power (in lumens) - this.intensity = power / ( 4 * Math.PI ); - - } - - dispose() { - - this.shadow.dispose(); - - } - - copy( source, recursive ) { - - super.copy( source, recursive ); - - this.distance = source.distance; - this.decay = source.decay; - - this.shadow = source.shadow.clone(); - - return this; - - } - -} - -class DirectionalLightShadow extends LightShadow { - - constructor() { - - super( new OrthographicCamera( - 5, 5, 5, - 5, 0.5, 500 ) ); - - this.isDirectionalLightShadow = true; - - } - -} - -class DirectionalLight extends Light { - - constructor( color, intensity ) { - - super( color, intensity ); - - this.isDirectionalLight = true; - - this.type = 'DirectionalLight'; - - this.position.copy( Object3D.DEFAULT_UP ); - this.updateMatrix(); - - this.target = new Object3D(); - - this.shadow = new DirectionalLightShadow(); - - } - - dispose() { - - this.shadow.dispose(); - - } - - copy( source ) { - - super.copy( source ); - - this.target = source.target.clone(); - this.shadow = source.shadow.clone(); - - return this; - - } - -} - -class AmbientLight extends Light { - - constructor( color, intensity ) { - - super( color, intensity ); - - this.isAmbientLight = true; - - this.type = 'AmbientLight'; - - } - -} - -class RectAreaLight extends Light { - - constructor( color, intensity, width = 10, height = 10 ) { - - super( color, intensity ); - - this.isRectAreaLight = true; - - this.type = 'RectAreaLight'; - - this.width = width; - this.height = height; - - } - - get power() { - - // compute the light's luminous power (in lumens) from its intensity (in nits) - return this.intensity * this.width * this.height * Math.PI; - - } - - set power( power ) { - - // set the light's intensity (in nits) from the desired luminous power (in lumens) - this.intensity = power / ( this.width * this.height * Math.PI ); - - } - - copy( source ) { - - super.copy( source ); - - this.width = source.width; - this.height = source.height; - - return this; - - } - - toJSON( meta ) { - - const data = super.toJSON( meta ); - - data.object.width = this.width; - data.object.height = this.height; - - return data; - - } - -} - -/** - * Primary reference: - * https://graphics.stanford.edu/papers/envmap/envmap.pdf - * - * Secondary reference: - * https://www.ppsloan.org/publications/StupidSH36.pdf - */ - -// 3-band SH defined by 9 coefficients - -class SphericalHarmonics3 { - - constructor() { - - this.isSphericalHarmonics3 = true; - - this.coefficients = []; - - for ( let i = 0; i < 9; i ++ ) { - - this.coefficients.push( new Vector3() ); - - } - - } - - set( coefficients ) { - - for ( let i = 0; i < 9; i ++ ) { - - this.coefficients[ i ].copy( coefficients[ i ] ); - - } - - return this; - - } - - zero() { - - for ( let i = 0; i < 9; i ++ ) { - - this.coefficients[ i ].set( 0, 0, 0 ); - - } - - return this; - - } - - // get the radiance in the direction of the normal - // target is a Vector3 - getAt( normal, target ) { - - // normal is assumed to be unit length - - const x = normal.x, y = normal.y, z = normal.z; - - const coeff = this.coefficients; - - // band 0 - target.copy( coeff[ 0 ] ).multiplyScalar( 0.282095 ); - - // band 1 - target.addScaledVector( coeff[ 1 ], 0.488603 * y ); - target.addScaledVector( coeff[ 2 ], 0.488603 * z ); - target.addScaledVector( coeff[ 3 ], 0.488603 * x ); - - // band 2 - target.addScaledVector( coeff[ 4 ], 1.092548 * ( x * y ) ); - target.addScaledVector( coeff[ 5 ], 1.092548 * ( y * z ) ); - target.addScaledVector( coeff[ 6 ], 0.315392 * ( 3.0 * z * z - 1.0 ) ); - target.addScaledVector( coeff[ 7 ], 1.092548 * ( x * z ) ); - target.addScaledVector( coeff[ 8 ], 0.546274 * ( x * x - y * y ) ); - - return target; - - } - - // get the irradiance (radiance convolved with cosine lobe) in the direction of the normal - // target is a Vector3 - // https://graphics.stanford.edu/papers/envmap/envmap.pdf - getIrradianceAt( normal, target ) { - - // normal is assumed to be unit length - - const x = normal.x, y = normal.y, z = normal.z; - - const coeff = this.coefficients; - - // band 0 - target.copy( coeff[ 0 ] ).multiplyScalar( 0.886227 ); // π * 0.282095 - - // band 1 - target.addScaledVector( coeff[ 1 ], 2.0 * 0.511664 * y ); // ( 2 * π / 3 ) * 0.488603 - target.addScaledVector( coeff[ 2 ], 2.0 * 0.511664 * z ); - target.addScaledVector( coeff[ 3 ], 2.0 * 0.511664 * x ); - - // band 2 - target.addScaledVector( coeff[ 4 ], 2.0 * 0.429043 * x * y ); // ( π / 4 ) * 1.092548 - target.addScaledVector( coeff[ 5 ], 2.0 * 0.429043 * y * z ); - target.addScaledVector( coeff[ 6 ], 0.743125 * z * z - 0.247708 ); // ( π / 4 ) * 0.315392 * 3 - target.addScaledVector( coeff[ 7 ], 2.0 * 0.429043 * x * z ); - target.addScaledVector( coeff[ 8 ], 0.429043 * ( x * x - y * y ) ); // ( π / 4 ) * 0.546274 - - return target; - - } - - add( sh ) { - - for ( let i = 0; i < 9; i ++ ) { - - this.coefficients[ i ].add( sh.coefficients[ i ] ); - - } - - return this; - - } - - addScaledSH( sh, s ) { - - for ( let i = 0; i < 9; i ++ ) { - - this.coefficients[ i ].addScaledVector( sh.coefficients[ i ], s ); - - } - - return this; - - } - - scale( s ) { - - for ( let i = 0; i < 9; i ++ ) { - - this.coefficients[ i ].multiplyScalar( s ); - - } - - return this; - - } - - lerp( sh, alpha ) { - - for ( let i = 0; i < 9; i ++ ) { - - this.coefficients[ i ].lerp( sh.coefficients[ i ], alpha ); - - } - - return this; - - } - - equals( sh ) { - - for ( let i = 0; i < 9; i ++ ) { - - if ( ! this.coefficients[ i ].equals( sh.coefficients[ i ] ) ) { - - return false; - - } - - } - - return true; - - } - - copy( sh ) { - - return this.set( sh.coefficients ); - - } - - clone() { - - return new this.constructor().copy( this ); - - } - - fromArray( array, offset = 0 ) { - - const coefficients = this.coefficients; - - for ( let i = 0; i < 9; i ++ ) { - - coefficients[ i ].fromArray( array, offset + ( i * 3 ) ); - - } - - return this; - - } - - toArray( array = [], offset = 0 ) { - - const coefficients = this.coefficients; - - for ( let i = 0; i < 9; i ++ ) { - - coefficients[ i ].toArray( array, offset + ( i * 3 ) ); - - } - - return array; - - } - - // evaluate the basis functions - // shBasis is an Array[ 9 ] - static getBasisAt( normal, shBasis ) { - - // normal is assumed to be unit length - - const x = normal.x, y = normal.y, z = normal.z; - - // band 0 - shBasis[ 0 ] = 0.282095; - - // band 1 - shBasis[ 1 ] = 0.488603 * y; - shBasis[ 2 ] = 0.488603 * z; - shBasis[ 3 ] = 0.488603 * x; - - // band 2 - shBasis[ 4 ] = 1.092548 * x * y; - shBasis[ 5 ] = 1.092548 * y * z; - shBasis[ 6 ] = 0.315392 * ( 3 * z * z - 1 ); - shBasis[ 7 ] = 1.092548 * x * z; - shBasis[ 8 ] = 0.546274 * ( x * x - y * y ); - - } - -} - -class LightProbe extends Light { - - constructor( sh = new SphericalHarmonics3(), intensity = 1 ) { - - super( undefined, intensity ); - - this.isLightProbe = true; - - this.sh = sh; - - } - - copy( source ) { - - super.copy( source ); - - this.sh.copy( source.sh ); - - return this; - - } - - fromJSON( json ) { - - this.intensity = json.intensity; // TODO: Move this bit to Light.fromJSON(); - this.sh.fromArray( json.sh ); - - return this; - - } - - toJSON( meta ) { - - const data = super.toJSON( meta ); - - data.object.sh = this.sh.toArray(); - - return data; - - } - -} - -class MaterialLoader extends Loader { - - constructor( manager ) { - - super( manager ); - this.textures = {}; - - } - - load( url, onLoad, onProgress, onError ) { - - const scope = this; - - const loader = new FileLoader( scope.manager ); - loader.setPath( scope.path ); - loader.setRequestHeader( scope.requestHeader ); - loader.setWithCredentials( scope.withCredentials ); - loader.load( url, function ( text ) { - - try { - - onLoad( scope.parse( JSON.parse( text ) ) ); - - } catch ( e ) { - - if ( onError ) { - - onError( e ); - - } else { - - console.error( e ); - - } - - scope.manager.itemError( url ); - - } - - }, onProgress, onError ); - - } - - parse( json ) { - - const textures = this.textures; - - function getTexture( name ) { - - if ( textures[ name ] === undefined ) { - - console.warn( 'THREE.MaterialLoader: Undefined texture', name ); - - } - - return textures[ name ]; - - } - - const material = MaterialLoader.createMaterialFromType( json.type ); - - if ( json.uuid !== undefined ) material.uuid = json.uuid; - if ( json.name !== undefined ) material.name = json.name; - if ( json.color !== undefined && material.color !== undefined ) material.color.setHex( json.color ); - if ( json.roughness !== undefined ) material.roughness = json.roughness; - if ( json.metalness !== undefined ) material.metalness = json.metalness; - if ( json.sheen !== undefined ) material.sheen = json.sheen; - if ( json.sheenColor !== undefined ) material.sheenColor = new Color().setHex( json.sheenColor ); - if ( json.sheenRoughness !== undefined ) material.sheenRoughness = json.sheenRoughness; - if ( json.emissive !== undefined && material.emissive !== undefined ) material.emissive.setHex( json.emissive ); - if ( json.specular !== undefined && material.specular !== undefined ) material.specular.setHex( json.specular ); - if ( json.specularIntensity !== undefined ) material.specularIntensity = json.specularIntensity; - if ( json.specularColor !== undefined && material.specularColor !== undefined ) material.specularColor.setHex( json.specularColor ); - if ( json.shininess !== undefined ) material.shininess = json.shininess; - if ( json.clearcoat !== undefined ) material.clearcoat = json.clearcoat; - if ( json.clearcoatRoughness !== undefined ) material.clearcoatRoughness = json.clearcoatRoughness; - if ( json.iridescence !== undefined ) material.iridescence = json.iridescence; - if ( json.iridescenceIOR !== undefined ) material.iridescenceIOR = json.iridescenceIOR; - if ( json.iridescenceThicknessRange !== undefined ) material.iridescenceThicknessRange = json.iridescenceThicknessRange; - if ( json.transmission !== undefined ) material.transmission = json.transmission; - if ( json.thickness !== undefined ) material.thickness = json.thickness; - if ( json.attenuationDistance !== undefined ) material.attenuationDistance = json.attenuationDistance; - if ( json.attenuationColor !== undefined && material.attenuationColor !== undefined ) material.attenuationColor.setHex( json.attenuationColor ); - if ( json.anisotropy !== undefined ) material.anisotropy = json.anisotropy; - if ( json.anisotropyRotation !== undefined ) material.anisotropyRotation = json.anisotropyRotation; - if ( json.fog !== undefined ) material.fog = json.fog; - if ( json.flatShading !== undefined ) material.flatShading = json.flatShading; - if ( json.blending !== undefined ) material.blending = json.blending; - if ( json.combine !== undefined ) material.combine = json.combine; - if ( json.side !== undefined ) material.side = json.side; - if ( json.shadowSide !== undefined ) material.shadowSide = json.shadowSide; - if ( json.opacity !== undefined ) material.opacity = json.opacity; - if ( json.transparent !== undefined ) material.transparent = json.transparent; - if ( json.alphaTest !== undefined ) material.alphaTest = json.alphaTest; - if ( json.alphaHash !== undefined ) material.alphaHash = json.alphaHash; - if ( json.depthFunc !== undefined ) material.depthFunc = json.depthFunc; - if ( json.depthTest !== undefined ) material.depthTest = json.depthTest; - if ( json.depthWrite !== undefined ) material.depthWrite = json.depthWrite; - if ( json.colorWrite !== undefined ) material.colorWrite = json.colorWrite; - if ( json.blendSrc !== undefined ) material.blendSrc = json.blendSrc; - if ( json.blendDst !== undefined ) material.blendDst = json.blendDst; - if ( json.blendEquation !== undefined ) material.blendEquation = json.blendEquation; - if ( json.blendSrcAlpha !== undefined ) material.blendSrcAlpha = json.blendSrcAlpha; - if ( json.blendDstAlpha !== undefined ) material.blendDstAlpha = json.blendDstAlpha; - if ( json.blendEquationAlpha !== undefined ) material.blendEquationAlpha = json.blendEquationAlpha; - if ( json.blendColor !== undefined && material.blendColor !== undefined ) material.blendColor.setHex( json.blendColor ); - if ( json.blendAlpha !== undefined ) material.blendAlpha = json.blendAlpha; - if ( json.stencilWriteMask !== undefined ) material.stencilWriteMask = json.stencilWriteMask; - if ( json.stencilFunc !== undefined ) material.stencilFunc = json.stencilFunc; - if ( json.stencilRef !== undefined ) material.stencilRef = json.stencilRef; - if ( json.stencilFuncMask !== undefined ) material.stencilFuncMask = json.stencilFuncMask; - if ( json.stencilFail !== undefined ) material.stencilFail = json.stencilFail; - if ( json.stencilZFail !== undefined ) material.stencilZFail = json.stencilZFail; - if ( json.stencilZPass !== undefined ) material.stencilZPass = json.stencilZPass; - if ( json.stencilWrite !== undefined ) material.stencilWrite = json.stencilWrite; - - if ( json.wireframe !== undefined ) material.wireframe = json.wireframe; - if ( json.wireframeLinewidth !== undefined ) material.wireframeLinewidth = json.wireframeLinewidth; - if ( json.wireframeLinecap !== undefined ) material.wireframeLinecap = json.wireframeLinecap; - if ( json.wireframeLinejoin !== undefined ) material.wireframeLinejoin = json.wireframeLinejoin; - - if ( json.rotation !== undefined ) material.rotation = json.rotation; - - if ( json.linewidth !== undefined ) material.linewidth = json.linewidth; - if ( json.dashSize !== undefined ) material.dashSize = json.dashSize; - if ( json.gapSize !== undefined ) material.gapSize = json.gapSize; - if ( json.scale !== undefined ) material.scale = json.scale; - - if ( json.polygonOffset !== undefined ) material.polygonOffset = json.polygonOffset; - if ( json.polygonOffsetFactor !== undefined ) material.polygonOffsetFactor = json.polygonOffsetFactor; - if ( json.polygonOffsetUnits !== undefined ) material.polygonOffsetUnits = json.polygonOffsetUnits; - - if ( json.dithering !== undefined ) material.dithering = json.dithering; - - if ( json.alphaToCoverage !== undefined ) material.alphaToCoverage = json.alphaToCoverage; - if ( json.premultipliedAlpha !== undefined ) material.premultipliedAlpha = json.premultipliedAlpha; - if ( json.forceSinglePass !== undefined ) material.forceSinglePass = json.forceSinglePass; - - if ( json.visible !== undefined ) material.visible = json.visible; - - if ( json.toneMapped !== undefined ) material.toneMapped = json.toneMapped; - - if ( json.userData !== undefined ) material.userData = json.userData; - - if ( json.vertexColors !== undefined ) { - - if ( typeof json.vertexColors === 'number' ) { - - material.vertexColors = ( json.vertexColors > 0 ) ? true : false; - - } else { - - material.vertexColors = json.vertexColors; - - } - - } - - // Shader Material - - if ( json.uniforms !== undefined ) { - - for ( const name in json.uniforms ) { - - const uniform = json.uniforms[ name ]; - - material.uniforms[ name ] = {}; - - switch ( uniform.type ) { - - case 't': - material.uniforms[ name ].value = getTexture( uniform.value ); - break; - - case 'c': - material.uniforms[ name ].value = new Color().setHex( uniform.value ); - break; - - case 'v2': - material.uniforms[ name ].value = new Vector2().fromArray( uniform.value ); - break; - - case 'v3': - material.uniforms[ name ].value = new Vector3().fromArray( uniform.value ); - break; - - case 'v4': - material.uniforms[ name ].value = new Vector4().fromArray( uniform.value ); - break; - - case 'm3': - material.uniforms[ name ].value = new Matrix3().fromArray( uniform.value ); - break; - - case 'm4': - material.uniforms[ name ].value = new Matrix4().fromArray( uniform.value ); - break; - - default: - material.uniforms[ name ].value = uniform.value; - - } - - } - - } - - if ( json.defines !== undefined ) material.defines = json.defines; - if ( json.vertexShader !== undefined ) material.vertexShader = json.vertexShader; - if ( json.fragmentShader !== undefined ) material.fragmentShader = json.fragmentShader; - if ( json.glslVersion !== undefined ) material.glslVersion = json.glslVersion; - - if ( json.extensions !== undefined ) { - - for ( const key in json.extensions ) { - - material.extensions[ key ] = json.extensions[ key ]; - - } - - } - - if ( json.lights !== undefined ) material.lights = json.lights; - if ( json.clipping !== undefined ) material.clipping = json.clipping; - - // for PointsMaterial - - if ( json.size !== undefined ) material.size = json.size; - if ( json.sizeAttenuation !== undefined ) material.sizeAttenuation = json.sizeAttenuation; - - // maps - - if ( json.map !== undefined ) material.map = getTexture( json.map ); - if ( json.matcap !== undefined ) material.matcap = getTexture( json.matcap ); - - if ( json.alphaMap !== undefined ) material.alphaMap = getTexture( json.alphaMap ); - - if ( json.bumpMap !== undefined ) material.bumpMap = getTexture( json.bumpMap ); - if ( json.bumpScale !== undefined ) material.bumpScale = json.bumpScale; - - if ( json.normalMap !== undefined ) material.normalMap = getTexture( json.normalMap ); - if ( json.normalMapType !== undefined ) material.normalMapType = json.normalMapType; - if ( json.normalScale !== undefined ) { - - let normalScale = json.normalScale; - - if ( Array.isArray( normalScale ) === false ) { - - // Blender exporter used to export a scalar. See #7459 - - normalScale = [ normalScale, normalScale ]; - - } - - material.normalScale = new Vector2().fromArray( normalScale ); - - } - - if ( json.displacementMap !== undefined ) material.displacementMap = getTexture( json.displacementMap ); - if ( json.displacementScale !== undefined ) material.displacementScale = json.displacementScale; - if ( json.displacementBias !== undefined ) material.displacementBias = json.displacementBias; - - if ( json.roughnessMap !== undefined ) material.roughnessMap = getTexture( json.roughnessMap ); - if ( json.metalnessMap !== undefined ) material.metalnessMap = getTexture( json.metalnessMap ); - - if ( json.emissiveMap !== undefined ) material.emissiveMap = getTexture( json.emissiveMap ); - if ( json.emissiveIntensity !== undefined ) material.emissiveIntensity = json.emissiveIntensity; - - if ( json.specularMap !== undefined ) material.specularMap = getTexture( json.specularMap ); - if ( json.specularIntensityMap !== undefined ) material.specularIntensityMap = getTexture( json.specularIntensityMap ); - if ( json.specularColorMap !== undefined ) material.specularColorMap = getTexture( json.specularColorMap ); - - if ( json.envMap !== undefined ) material.envMap = getTexture( json.envMap ); - if ( json.envMapIntensity !== undefined ) material.envMapIntensity = json.envMapIntensity; - - if ( json.reflectivity !== undefined ) material.reflectivity = json.reflectivity; - if ( json.refractionRatio !== undefined ) material.refractionRatio = json.refractionRatio; - - if ( json.lightMap !== undefined ) material.lightMap = getTexture( json.lightMap ); - if ( json.lightMapIntensity !== undefined ) material.lightMapIntensity = json.lightMapIntensity; - - if ( json.aoMap !== undefined ) material.aoMap = getTexture( json.aoMap ); - if ( json.aoMapIntensity !== undefined ) material.aoMapIntensity = json.aoMapIntensity; - - if ( json.gradientMap !== undefined ) material.gradientMap = getTexture( json.gradientMap ); - - if ( json.clearcoatMap !== undefined ) material.clearcoatMap = getTexture( json.clearcoatMap ); - if ( json.clearcoatRoughnessMap !== undefined ) material.clearcoatRoughnessMap = getTexture( json.clearcoatRoughnessMap ); - if ( json.clearcoatNormalMap !== undefined ) material.clearcoatNormalMap = getTexture( json.clearcoatNormalMap ); - if ( json.clearcoatNormalScale !== undefined ) material.clearcoatNormalScale = new Vector2().fromArray( json.clearcoatNormalScale ); - - if ( json.iridescenceMap !== undefined ) material.iridescenceMap = getTexture( json.iridescenceMap ); - if ( json.iridescenceThicknessMap !== undefined ) material.iridescenceThicknessMap = getTexture( json.iridescenceThicknessMap ); - - if ( json.transmissionMap !== undefined ) material.transmissionMap = getTexture( json.transmissionMap ); - if ( json.thicknessMap !== undefined ) material.thicknessMap = getTexture( json.thicknessMap ); - - if ( json.anisotropyMap !== undefined ) material.anisotropyMap = getTexture( json.anisotropyMap ); - - if ( json.sheenColorMap !== undefined ) material.sheenColorMap = getTexture( json.sheenColorMap ); - if ( json.sheenRoughnessMap !== undefined ) material.sheenRoughnessMap = getTexture( json.sheenRoughnessMap ); - - return material; - - } - - setTextures( value ) { - - this.textures = value; - return this; - - } - - static createMaterialFromType( type ) { - - const materialLib = { - ShadowMaterial, - SpriteMaterial, - RawShaderMaterial, - ShaderMaterial, - PointsMaterial, - MeshPhysicalMaterial, - MeshStandardMaterial, - MeshPhongMaterial, - MeshToonMaterial, - MeshNormalMaterial, - MeshLambertMaterial, - MeshDepthMaterial, - MeshDistanceMaterial, - MeshBasicMaterial, - MeshMatcapMaterial, - LineDashedMaterial, - LineBasicMaterial, - Material - }; - - return new materialLib[ type ](); - - } - -} - -class LoaderUtils { - - static decodeText( array ) { - - if ( typeof TextDecoder !== 'undefined' ) { - - return new TextDecoder().decode( array ); - - } - - // Avoid the String.fromCharCode.apply(null, array) shortcut, which - // throws a "maximum call stack size exceeded" error for large arrays. - - let s = ''; - - for ( let i = 0, il = array.length; i < il; i ++ ) { - - // Implicitly assumes little-endian. - s += String.fromCharCode( array[ i ] ); - - } - - try { - - // merges multi-byte utf-8 characters. - - return decodeURIComponent( escape( s ) ); - - } catch ( e ) { // see #16358 - - return s; - - } - - } - - static extractUrlBase( url ) { - - const index = url.lastIndexOf( '/' ); - - if ( index === - 1 ) return './'; - - return url.slice( 0, index + 1 ); - - } - - static resolveURL( url, path ) { - - // Invalid URL - if ( typeof url !== 'string' || url === '' ) return ''; - - // Host Relative URL - if ( /^https?:\/\//i.test( path ) && /^\//.test( url ) ) { - - path = path.replace( /(^https?:\/\/[^\/]+).*/i, '$1' ); - - } - - // Absolute URL http://,https://,// - if ( /^(https?:)?\/\//i.test( url ) ) return url; - - // Data URI - if ( /^data:.*,.*$/i.test( url ) ) return url; - - // Blob URL - if ( /^blob:.*$/i.test( url ) ) return url; - - // Relative URL - return path + url; - - } - -} - -class InstancedBufferGeometry extends BufferGeometry { - - constructor() { - - super(); - - this.isInstancedBufferGeometry = true; - - this.type = 'InstancedBufferGeometry'; - this.instanceCount = Infinity; - - } - - copy( source ) { - - super.copy( source ); - - this.instanceCount = source.instanceCount; - - return this; - - } - - toJSON() { - - const data = super.toJSON(); - - data.instanceCount = this.instanceCount; - - data.isInstancedBufferGeometry = true; - - return data; - - } - -} - -class BufferGeometryLoader extends Loader { - - constructor( manager ) { - - super( manager ); - - } - - load( url, onLoad, onProgress, onError ) { - - const scope = this; - - const loader = new FileLoader( scope.manager ); - loader.setPath( scope.path ); - loader.setRequestHeader( scope.requestHeader ); - loader.setWithCredentials( scope.withCredentials ); - loader.load( url, function ( text ) { - - try { - - onLoad( scope.parse( JSON.parse( text ) ) ); - - } catch ( e ) { - - if ( onError ) { - - onError( e ); - - } else { - - console.error( e ); - - } - - scope.manager.itemError( url ); - - } - - }, onProgress, onError ); - - } - - parse( json ) { - - const interleavedBufferMap = {}; - const arrayBufferMap = {}; - - function getInterleavedBuffer( json, uuid ) { - - if ( interleavedBufferMap[ uuid ] !== undefined ) return interleavedBufferMap[ uuid ]; - - const interleavedBuffers = json.interleavedBuffers; - const interleavedBuffer = interleavedBuffers[ uuid ]; - - const buffer = getArrayBuffer( json, interleavedBuffer.buffer ); - - const array = getTypedArray( interleavedBuffer.type, buffer ); - const ib = new InterleavedBuffer( array, interleavedBuffer.stride ); - ib.uuid = interleavedBuffer.uuid; - - interleavedBufferMap[ uuid ] = ib; - - return ib; - - } - - function getArrayBuffer( json, uuid ) { - - if ( arrayBufferMap[ uuid ] !== undefined ) return arrayBufferMap[ uuid ]; - - const arrayBuffers = json.arrayBuffers; - const arrayBuffer = arrayBuffers[ uuid ]; - - const ab = new Uint32Array( arrayBuffer ).buffer; - - arrayBufferMap[ uuid ] = ab; - - return ab; - - } - - const geometry = json.isInstancedBufferGeometry ? new InstancedBufferGeometry() : new BufferGeometry(); - - const index = json.data.index; - - if ( index !== undefined ) { - - const typedArray = getTypedArray( index.type, index.array ); - geometry.setIndex( new BufferAttribute( typedArray, 1 ) ); - - } - - const attributes = json.data.attributes; - - for ( const key in attributes ) { - - const attribute = attributes[ key ]; - let bufferAttribute; - - if ( attribute.isInterleavedBufferAttribute ) { - - const interleavedBuffer = getInterleavedBuffer( json.data, attribute.data ); - bufferAttribute = new InterleavedBufferAttribute( interleavedBuffer, attribute.itemSize, attribute.offset, attribute.normalized ); - - } else { - - const typedArray = getTypedArray( attribute.type, attribute.array ); - const bufferAttributeConstr = attribute.isInstancedBufferAttribute ? InstancedBufferAttribute : BufferAttribute; - bufferAttribute = new bufferAttributeConstr( typedArray, attribute.itemSize, attribute.normalized ); - - } - - if ( attribute.name !== undefined ) bufferAttribute.name = attribute.name; - if ( attribute.usage !== undefined ) bufferAttribute.setUsage( attribute.usage ); - - geometry.setAttribute( key, bufferAttribute ); - - } - - const morphAttributes = json.data.morphAttributes; - - if ( morphAttributes ) { - - for ( const key in morphAttributes ) { - - const attributeArray = morphAttributes[ key ]; - - const array = []; - - for ( let i = 0, il = attributeArray.length; i < il; i ++ ) { - - const attribute = attributeArray[ i ]; - let bufferAttribute; - - if ( attribute.isInterleavedBufferAttribute ) { - - const interleavedBuffer = getInterleavedBuffer( json.data, attribute.data ); - bufferAttribute = new InterleavedBufferAttribute( interleavedBuffer, attribute.itemSize, attribute.offset, attribute.normalized ); - - } else { - - const typedArray = getTypedArray( attribute.type, attribute.array ); - bufferAttribute = new BufferAttribute( typedArray, attribute.itemSize, attribute.normalized ); - - } - - if ( attribute.name !== undefined ) bufferAttribute.name = attribute.name; - array.push( bufferAttribute ); - - } - - geometry.morphAttributes[ key ] = array; - - } - - } - - const morphTargetsRelative = json.data.morphTargetsRelative; - - if ( morphTargetsRelative ) { - - geometry.morphTargetsRelative = true; - - } - - const groups = json.data.groups || json.data.drawcalls || json.data.offsets; - - if ( groups !== undefined ) { - - for ( let i = 0, n = groups.length; i !== n; ++ i ) { - - const group = groups[ i ]; - - geometry.addGroup( group.start, group.count, group.materialIndex ); - - } - - } - - const boundingSphere = json.data.boundingSphere; - - if ( boundingSphere !== undefined ) { - - const center = new Vector3(); - - if ( boundingSphere.center !== undefined ) { - - center.fromArray( boundingSphere.center ); - - } - - geometry.boundingSphere = new Sphere( center, boundingSphere.radius ); - - } - - if ( json.name ) geometry.name = json.name; - if ( json.userData ) geometry.userData = json.userData; - - return geometry; - - } - -} - -class ObjectLoader extends Loader { - - constructor( manager ) { - - super( manager ); - - } - - load( url, onLoad, onProgress, onError ) { - - const scope = this; - - const path = ( this.path === '' ) ? LoaderUtils.extractUrlBase( url ) : this.path; - this.resourcePath = this.resourcePath || path; - - const loader = new FileLoader( this.manager ); - loader.setPath( this.path ); - loader.setRequestHeader( this.requestHeader ); - loader.setWithCredentials( this.withCredentials ); - loader.load( url, function ( text ) { - - let json = null; - - try { - - json = JSON.parse( text ); - - } catch ( error ) { - - if ( onError !== undefined ) onError( error ); - - console.error( 'THREE:ObjectLoader: Can\'t parse ' + url + '.', error.message ); - - return; - - } - - const metadata = json.metadata; - - if ( metadata === undefined || metadata.type === undefined || metadata.type.toLowerCase() === 'geometry' ) { - - if ( onError !== undefined ) onError( new Error( 'THREE.ObjectLoader: Can\'t load ' + url ) ); - - console.error( 'THREE.ObjectLoader: Can\'t load ' + url ); - return; - - } - - scope.parse( json, onLoad ); - - }, onProgress, onError ); - - } - - async loadAsync( url, onProgress ) { - - const scope = this; - - const path = ( this.path === '' ) ? LoaderUtils.extractUrlBase( url ) : this.path; - this.resourcePath = this.resourcePath || path; - - const loader = new FileLoader( this.manager ); - loader.setPath( this.path ); - loader.setRequestHeader( this.requestHeader ); - loader.setWithCredentials( this.withCredentials ); - - const text = await loader.loadAsync( url, onProgress ); - - const json = JSON.parse( text ); - - const metadata = json.metadata; - - if ( metadata === undefined || metadata.type === undefined || metadata.type.toLowerCase() === 'geometry' ) { - - throw new Error( 'THREE.ObjectLoader: Can\'t load ' + url ); - - } - - return await scope.parseAsync( json ); - - } - - parse( json, onLoad ) { - - const animations = this.parseAnimations( json.animations ); - const shapes = this.parseShapes( json.shapes ); - const geometries = this.parseGeometries( json.geometries, shapes ); - - const images = this.parseImages( json.images, function () { - - if ( onLoad !== undefined ) onLoad( object ); - - } ); - - const textures = this.parseTextures( json.textures, images ); - const materials = this.parseMaterials( json.materials, textures ); - - const object = this.parseObject( json.object, geometries, materials, textures, animations ); - const skeletons = this.parseSkeletons( json.skeletons, object ); - - this.bindSkeletons( object, skeletons ); - - // - - if ( onLoad !== undefined ) { - - let hasImages = false; - - for ( const uuid in images ) { - - if ( images[ uuid ].data instanceof HTMLImageElement ) { - - hasImages = true; - break; - - } - - } - - if ( hasImages === false ) onLoad( object ); - - } - - return object; - - } - - async parseAsync( json ) { - - const animations = this.parseAnimations( json.animations ); - const shapes = this.parseShapes( json.shapes ); - const geometries = this.parseGeometries( json.geometries, shapes ); - - const images = await this.parseImagesAsync( json.images ); - - const textures = this.parseTextures( json.textures, images ); - const materials = this.parseMaterials( json.materials, textures ); - - const object = this.parseObject( json.object, geometries, materials, textures, animations ); - const skeletons = this.parseSkeletons( json.skeletons, object ); - - this.bindSkeletons( object, skeletons ); - - return object; - - } - - parseShapes( json ) { - - const shapes = {}; - - if ( json !== undefined ) { - - for ( let i = 0, l = json.length; i < l; i ++ ) { - - const shape = new Shape().fromJSON( json[ i ] ); - - shapes[ shape.uuid ] = shape; - - } - - } - - return shapes; - - } - - parseSkeletons( json, object ) { - - const skeletons = {}; - const bones = {}; - - // generate bone lookup table - - object.traverse( function ( child ) { - - if ( child.isBone ) bones[ child.uuid ] = child; - - } ); - - // create skeletons - - if ( json !== undefined ) { - - for ( let i = 0, l = json.length; i < l; i ++ ) { - - const skeleton = new Skeleton().fromJSON( json[ i ], bones ); - - skeletons[ skeleton.uuid ] = skeleton; - - } - - } - - return skeletons; - - } - - parseGeometries( json, shapes ) { - - const geometries = {}; - - if ( json !== undefined ) { - - const bufferGeometryLoader = new BufferGeometryLoader(); - - for ( let i = 0, l = json.length; i < l; i ++ ) { - - let geometry; - const data = json[ i ]; - - switch ( data.type ) { - - case 'BufferGeometry': - case 'InstancedBufferGeometry': - - geometry = bufferGeometryLoader.parse( data ); - break; - - default: - - if ( data.type in Geometries ) { - - geometry = Geometries[ data.type ].fromJSON( data, shapes ); - - } else { - - console.warn( `THREE.ObjectLoader: Unsupported geometry type "${ data.type }"` ); - - } - - } - - geometry.uuid = data.uuid; - - if ( data.name !== undefined ) geometry.name = data.name; - if ( data.userData !== undefined ) geometry.userData = data.userData; - - geometries[ data.uuid ] = geometry; - - } - - } - - return geometries; - - } - - parseMaterials( json, textures ) { - - const cache = {}; // MultiMaterial - const materials = {}; - - if ( json !== undefined ) { - - const loader = new MaterialLoader(); - loader.setTextures( textures ); - - for ( let i = 0, l = json.length; i < l; i ++ ) { - - const data = json[ i ]; - - if ( cache[ data.uuid ] === undefined ) { - - cache[ data.uuid ] = loader.parse( data ); - - } - - materials[ data.uuid ] = cache[ data.uuid ]; - - } - - } - - return materials; - - } - - parseAnimations( json ) { - - const animations = {}; - - if ( json !== undefined ) { - - for ( let i = 0; i < json.length; i ++ ) { - - const data = json[ i ]; - - const clip = AnimationClip.parse( data ); - - animations[ clip.uuid ] = clip; - - } - - } - - return animations; - - } - - parseImages( json, onLoad ) { - - const scope = this; - const images = {}; - - let loader; - - function loadImage( url ) { - - scope.manager.itemStart( url ); - - return loader.load( url, function () { - - scope.manager.itemEnd( url ); - - }, undefined, function () { - - scope.manager.itemError( url ); - scope.manager.itemEnd( url ); - - } ); - - } - - function deserializeImage( image ) { - - if ( typeof image === 'string' ) { - - const url = image; - - const path = /^(\/\/)|([a-z]+:(\/\/)?)/i.test( url ) ? url : scope.resourcePath + url; - - return loadImage( path ); - - } else { - - if ( image.data ) { - - return { - data: getTypedArray( image.type, image.data ), - width: image.width, - height: image.height - }; - - } else { - - return null; - - } - - } - - } - - if ( json !== undefined && json.length > 0 ) { - - const manager = new LoadingManager( onLoad ); - - loader = new ImageLoader( manager ); - loader.setCrossOrigin( this.crossOrigin ); - - for ( let i = 0, il = json.length; i < il; i ++ ) { - - const image = json[ i ]; - const url = image.url; - - if ( Array.isArray( url ) ) { - - // load array of images e.g CubeTexture - - const imageArray = []; - - for ( let j = 0, jl = url.length; j < jl; j ++ ) { - - const currentUrl = url[ j ]; - - const deserializedImage = deserializeImage( currentUrl ); - - if ( deserializedImage !== null ) { - - if ( deserializedImage instanceof HTMLImageElement ) { - - imageArray.push( deserializedImage ); - - } else { - - // special case: handle array of data textures for cube textures - - imageArray.push( new DataTexture( deserializedImage.data, deserializedImage.width, deserializedImage.height ) ); - - } - - } - - } - - images[ image.uuid ] = new Source( imageArray ); - - } else { - - // load single image - - const deserializedImage = deserializeImage( image.url ); - images[ image.uuid ] = new Source( deserializedImage ); - - - } - - } - - } - - return images; - - } - - async parseImagesAsync( json ) { - - const scope = this; - const images = {}; - - let loader; - - async function deserializeImage( image ) { - - if ( typeof image === 'string' ) { - - const url = image; - - const path = /^(\/\/)|([a-z]+:(\/\/)?)/i.test( url ) ? url : scope.resourcePath + url; - - return await loader.loadAsync( path ); - - } else { - - if ( image.data ) { - - return { - data: getTypedArray( image.type, image.data ), - width: image.width, - height: image.height - }; - - } else { - - return null; - - } - - } - - } - - if ( json !== undefined && json.length > 0 ) { - - loader = new ImageLoader( this.manager ); - loader.setCrossOrigin( this.crossOrigin ); - - for ( let i = 0, il = json.length; i < il; i ++ ) { - - const image = json[ i ]; - const url = image.url; - - if ( Array.isArray( url ) ) { - - // load array of images e.g CubeTexture - - const imageArray = []; - - for ( let j = 0, jl = url.length; j < jl; j ++ ) { - - const currentUrl = url[ j ]; - - const deserializedImage = await deserializeImage( currentUrl ); - - if ( deserializedImage !== null ) { - - if ( deserializedImage instanceof HTMLImageElement ) { - - imageArray.push( deserializedImage ); - - } else { - - // special case: handle array of data textures for cube textures - - imageArray.push( new DataTexture( deserializedImage.data, deserializedImage.width, deserializedImage.height ) ); - - } - - } - - } - - images[ image.uuid ] = new Source( imageArray ); - - } else { - - // load single image - - const deserializedImage = await deserializeImage( image.url ); - images[ image.uuid ] = new Source( deserializedImage ); - - } - - } - - } - - return images; - - } - - parseTextures( json, images ) { - - function parseConstant( value, type ) { - - if ( typeof value === 'number' ) return value; - - console.warn( 'THREE.ObjectLoader.parseTexture: Constant should be in numeric form.', value ); - - return type[ value ]; - - } - - const textures = {}; - - if ( json !== undefined ) { - - for ( let i = 0, l = json.length; i < l; i ++ ) { - - const data = json[ i ]; - - if ( data.image === undefined ) { - - console.warn( 'THREE.ObjectLoader: No "image" specified for', data.uuid ); - - } - - if ( images[ data.image ] === undefined ) { - - console.warn( 'THREE.ObjectLoader: Undefined image', data.image ); - - } - - const source = images[ data.image ]; - const image = source.data; - - let texture; - - if ( Array.isArray( image ) ) { - - texture = new CubeTexture(); - - if ( image.length === 6 ) texture.needsUpdate = true; - - } else { - - if ( image && image.data ) { - - texture = new DataTexture(); - - } else { - - texture = new Texture(); - - } - - if ( image ) texture.needsUpdate = true; // textures can have undefined image data - - } - - texture.source = source; - - texture.uuid = data.uuid; - - if ( data.name !== undefined ) texture.name = data.name; - - if ( data.mapping !== undefined ) texture.mapping = parseConstant( data.mapping, TEXTURE_MAPPING ); - if ( data.channel !== undefined ) texture.channel = data.channel; - - if ( data.offset !== undefined ) texture.offset.fromArray( data.offset ); - if ( data.repeat !== undefined ) texture.repeat.fromArray( data.repeat ); - if ( data.center !== undefined ) texture.center.fromArray( data.center ); - if ( data.rotation !== undefined ) texture.rotation = data.rotation; - - if ( data.wrap !== undefined ) { - - texture.wrapS = parseConstant( data.wrap[ 0 ], TEXTURE_WRAPPING ); - texture.wrapT = parseConstant( data.wrap[ 1 ], TEXTURE_WRAPPING ); - - } - - if ( data.format !== undefined ) texture.format = data.format; - if ( data.internalFormat !== undefined ) texture.internalFormat = data.internalFormat; - if ( data.type !== undefined ) texture.type = data.type; - if ( data.colorSpace !== undefined ) texture.colorSpace = data.colorSpace; - - if ( data.minFilter !== undefined ) texture.minFilter = parseConstant( data.minFilter, TEXTURE_FILTER ); - if ( data.magFilter !== undefined ) texture.magFilter = parseConstant( data.magFilter, TEXTURE_FILTER ); - if ( data.anisotropy !== undefined ) texture.anisotropy = data.anisotropy; - - if ( data.flipY !== undefined ) texture.flipY = data.flipY; - - if ( data.generateMipmaps !== undefined ) texture.generateMipmaps = data.generateMipmaps; - if ( data.premultiplyAlpha !== undefined ) texture.premultiplyAlpha = data.premultiplyAlpha; - if ( data.unpackAlignment !== undefined ) texture.unpackAlignment = data.unpackAlignment; - if ( data.compareFunction !== undefined ) texture.compareFunction = data.compareFunction; - - if ( data.userData !== undefined ) texture.userData = data.userData; - - textures[ data.uuid ] = texture; - - } - - } - - return textures; - - } - - parseObject( data, geometries, materials, textures, animations ) { - - let object; - - function getGeometry( name ) { - - if ( geometries[ name ] === undefined ) { - - console.warn( 'THREE.ObjectLoader: Undefined geometry', name ); - - } - - return geometries[ name ]; - - } - - function getMaterial( name ) { - - if ( name === undefined ) return undefined; - - if ( Array.isArray( name ) ) { - - const array = []; - - for ( let i = 0, l = name.length; i < l; i ++ ) { - - const uuid = name[ i ]; - - if ( materials[ uuid ] === undefined ) { - - console.warn( 'THREE.ObjectLoader: Undefined material', uuid ); - - } - - array.push( materials[ uuid ] ); - - } - - return array; - - } - - if ( materials[ name ] === undefined ) { - - console.warn( 'THREE.ObjectLoader: Undefined material', name ); - - } - - return materials[ name ]; - - } - - function getTexture( uuid ) { - - if ( textures[ uuid ] === undefined ) { - - console.warn( 'THREE.ObjectLoader: Undefined texture', uuid ); - - } - - return textures[ uuid ]; - - } - - let geometry, material; - - switch ( data.type ) { - - case 'Scene': - - object = new Scene(); - - if ( data.background !== undefined ) { - - if ( Number.isInteger( data.background ) ) { - - object.background = new Color( data.background ); - - } else { - - object.background = getTexture( data.background ); - - } - - } - - if ( data.environment !== undefined ) { - - object.environment = getTexture( data.environment ); - - } - - if ( data.fog !== undefined ) { - - if ( data.fog.type === 'Fog' ) { - - object.fog = new Fog( data.fog.color, data.fog.near, data.fog.far ); - - } else if ( data.fog.type === 'FogExp2' ) { - - object.fog = new FogExp2( data.fog.color, data.fog.density ); - - } - - if ( data.fog.name !== '' ) { - - object.fog.name = data.fog.name; - - } - - } - - if ( data.backgroundBlurriness !== undefined ) object.backgroundBlurriness = data.backgroundBlurriness; - if ( data.backgroundIntensity !== undefined ) object.backgroundIntensity = data.backgroundIntensity; - - break; - - case 'PerspectiveCamera': - - object = new PerspectiveCamera( data.fov, data.aspect, data.near, data.far ); - - if ( data.focus !== undefined ) object.focus = data.focus; - if ( data.zoom !== undefined ) object.zoom = data.zoom; - if ( data.filmGauge !== undefined ) object.filmGauge = data.filmGauge; - if ( data.filmOffset !== undefined ) object.filmOffset = data.filmOffset; - if ( data.view !== undefined ) object.view = Object.assign( {}, data.view ); - - break; - - case 'OrthographicCamera': - - object = new OrthographicCamera( data.left, data.right, data.top, data.bottom, data.near, data.far ); - - if ( data.zoom !== undefined ) object.zoom = data.zoom; - if ( data.view !== undefined ) object.view = Object.assign( {}, data.view ); - - break; - - case 'AmbientLight': - - object = new AmbientLight( data.color, data.intensity ); - - break; - - case 'DirectionalLight': - - object = new DirectionalLight( data.color, data.intensity ); - - break; - - case 'PointLight': - - object = new PointLight( data.color, data.intensity, data.distance, data.decay ); - - break; - - case 'RectAreaLight': - - object = new RectAreaLight( data.color, data.intensity, data.width, data.height ); - - break; - - case 'SpotLight': - - object = new SpotLight( data.color, data.intensity, data.distance, data.angle, data.penumbra, data.decay ); - - break; - - case 'HemisphereLight': - - object = new HemisphereLight( data.color, data.groundColor, data.intensity ); - - break; - - case 'LightProbe': - - object = new LightProbe().fromJSON( data ); - - break; - - case 'SkinnedMesh': - - geometry = getGeometry( data.geometry ); - material = getMaterial( data.material ); - - object = new SkinnedMesh( geometry, material ); - - if ( data.bindMode !== undefined ) object.bindMode = data.bindMode; - if ( data.bindMatrix !== undefined ) object.bindMatrix.fromArray( data.bindMatrix ); - if ( data.skeleton !== undefined ) object.skeleton = data.skeleton; - - break; - - case 'Mesh': - - geometry = getGeometry( data.geometry ); - material = getMaterial( data.material ); - - object = new Mesh( geometry, material ); - - break; - - case 'InstancedMesh': - - geometry = getGeometry( data.geometry ); - material = getMaterial( data.material ); - const count = data.count; - const instanceMatrix = data.instanceMatrix; - const instanceColor = data.instanceColor; - - object = new InstancedMesh( geometry, material, count ); - object.instanceMatrix = new InstancedBufferAttribute( new Float32Array( instanceMatrix.array ), 16 ); - if ( instanceColor !== undefined ) object.instanceColor = new InstancedBufferAttribute( new Float32Array( instanceColor.array ), instanceColor.itemSize ); - - break; - - case 'BatchedMesh': - - geometry = getGeometry( data.geometry ); - material = getMaterial( data.material ); - - object = new BatchedMesh( data.maxGeometryCount, data.maxVertexCount, data.maxIndexCount, material ); - object.geometry = geometry; - object.perObjectFrustumCulled = data.perObjectFrustumCulled; - object.sortObjects = data.sortObjects; - - object._drawRanges = data.drawRanges; - object._reservedRanges = data.reservedRanges; - - object._visibility = data.visibility; - object._active = data.active; - object._bounds = data.bounds.map( bound => { - - const box = new Box3(); - box.min.fromArray( bound.boxMin ); - box.max.fromArray( bound.boxMax ); - - const sphere = new Sphere(); - sphere.radius = bound.sphereRadius; - sphere.center.fromArray( bound.sphereCenter ); - - return { - boxInitialized: bound.boxInitialized, - box: box, - - sphereInitialized: bound.sphereInitialized, - sphere: sphere - }; - - } ); - - object._maxGeometryCount = data.maxGeometryCount; - object._maxVertexCount = data.maxVertexCount; - object._maxIndexCount = data.maxIndexCount; - - object._geometryInitialized = data.geometryInitialized; - object._geometryCount = data.geometryCount; - - object._matricesTexture = getTexture( data.matricesTexture.uuid ); - - break; - - case 'LOD': - - object = new LOD(); - - break; - - case 'Line': - - object = new Line( getGeometry( data.geometry ), getMaterial( data.material ) ); - - break; - - case 'LineLoop': - - object = new LineLoop( getGeometry( data.geometry ), getMaterial( data.material ) ); - - break; - - case 'LineSegments': - - object = new LineSegments( getGeometry( data.geometry ), getMaterial( data.material ) ); - - break; - - case 'PointCloud': - case 'Points': - - object = new Points( getGeometry( data.geometry ), getMaterial( data.material ) ); - - break; - - case 'Sprite': - - object = new Sprite( getMaterial( data.material ) ); - - break; - - case 'Group': - - object = new Group(); - - break; - - case 'Bone': - - object = new Bone(); - - break; - - default: - - object = new Object3D(); - - } - - object.uuid = data.uuid; - - if ( data.name !== undefined ) object.name = data.name; - - if ( data.matrix !== undefined ) { - - object.matrix.fromArray( data.matrix ); - - if ( data.matrixAutoUpdate !== undefined ) object.matrixAutoUpdate = data.matrixAutoUpdate; - if ( object.matrixAutoUpdate ) object.matrix.decompose( object.position, object.quaternion, object.scale ); - - } else { - - if ( data.position !== undefined ) object.position.fromArray( data.position ); - if ( data.rotation !== undefined ) object.rotation.fromArray( data.rotation ); - if ( data.quaternion !== undefined ) object.quaternion.fromArray( data.quaternion ); - if ( data.scale !== undefined ) object.scale.fromArray( data.scale ); - - } - - if ( data.up !== undefined ) object.up.fromArray( data.up ); - - if ( data.castShadow !== undefined ) object.castShadow = data.castShadow; - if ( data.receiveShadow !== undefined ) object.receiveShadow = data.receiveShadow; - - if ( data.shadow ) { - - if ( data.shadow.bias !== undefined ) object.shadow.bias = data.shadow.bias; - if ( data.shadow.normalBias !== undefined ) object.shadow.normalBias = data.shadow.normalBias; - if ( data.shadow.radius !== undefined ) object.shadow.radius = data.shadow.radius; - if ( data.shadow.mapSize !== undefined ) object.shadow.mapSize.fromArray( data.shadow.mapSize ); - if ( data.shadow.camera !== undefined ) object.shadow.camera = this.parseObject( data.shadow.camera ); - - } - - if ( data.visible !== undefined ) object.visible = data.visible; - if ( data.frustumCulled !== undefined ) object.frustumCulled = data.frustumCulled; - if ( data.renderOrder !== undefined ) object.renderOrder = data.renderOrder; - if ( data.userData !== undefined ) object.userData = data.userData; - if ( data.layers !== undefined ) object.layers.mask = data.layers; - - if ( data.children !== undefined ) { - - const children = data.children; - - for ( let i = 0; i < children.length; i ++ ) { - - object.add( this.parseObject( children[ i ], geometries, materials, textures, animations ) ); - - } - - } - - if ( data.animations !== undefined ) { - - const objectAnimations = data.animations; - - for ( let i = 0; i < objectAnimations.length; i ++ ) { - - const uuid = objectAnimations[ i ]; - - object.animations.push( animations[ uuid ] ); - - } - - } - - if ( data.type === 'LOD' ) { - - if ( data.autoUpdate !== undefined ) object.autoUpdate = data.autoUpdate; - - const levels = data.levels; - - for ( let l = 0; l < levels.length; l ++ ) { - - const level = levels[ l ]; - const child = object.getObjectByProperty( 'uuid', level.object ); - - if ( child !== undefined ) { - - object.addLevel( child, level.distance, level.hysteresis ); - - } - - } - - } - - return object; - - } - - bindSkeletons( object, skeletons ) { - - if ( Object.keys( skeletons ).length === 0 ) return; - - object.traverse( function ( child ) { - - if ( child.isSkinnedMesh === true && child.skeleton !== undefined ) { - - const skeleton = skeletons[ child.skeleton ]; - - if ( skeleton === undefined ) { - - console.warn( 'THREE.ObjectLoader: No skeleton found with UUID:', child.skeleton ); - - } else { - - child.bind( skeleton, child.bindMatrix ); - - } - - } - - } ); - - } - -} - -const TEXTURE_MAPPING = { - UVMapping: UVMapping, - CubeReflectionMapping: CubeReflectionMapping, - CubeRefractionMapping: CubeRefractionMapping, - EquirectangularReflectionMapping: EquirectangularReflectionMapping, - EquirectangularRefractionMapping: EquirectangularRefractionMapping, - CubeUVReflectionMapping: CubeUVReflectionMapping -}; - -const TEXTURE_WRAPPING = { - RepeatWrapping: RepeatWrapping, - ClampToEdgeWrapping: ClampToEdgeWrapping, - MirroredRepeatWrapping: MirroredRepeatWrapping -}; - -const TEXTURE_FILTER = { - NearestFilter: NearestFilter, - NearestMipmapNearestFilter: NearestMipmapNearestFilter, - NearestMipmapLinearFilter: NearestMipmapLinearFilter, - LinearFilter: LinearFilter, - LinearMipmapNearestFilter: LinearMipmapNearestFilter, - LinearMipmapLinearFilter: LinearMipmapLinearFilter -}; - -class ImageBitmapLoader extends Loader { - - constructor( manager ) { - - super( manager ); - - this.isImageBitmapLoader = true; - - if ( typeof createImageBitmap === 'undefined' ) { - - console.warn( 'THREE.ImageBitmapLoader: createImageBitmap() not supported.' ); - - } - - if ( typeof fetch === 'undefined' ) { - - console.warn( 'THREE.ImageBitmapLoader: fetch() not supported.' ); - - } - - this.options = { premultiplyAlpha: 'none' }; - - } - - setOptions( options ) { - - this.options = options; - - return this; - - } - - load( url, onLoad, onProgress, onError ) { - - if ( url === undefined ) url = ''; - - if ( this.path !== undefined ) url = this.path + url; - - url = this.manager.resolveURL( url ); - - const scope = this; - - const cached = Cache.get( url ); - - if ( cached !== undefined ) { - - scope.manager.itemStart( url ); - - // If cached is a promise, wait for it to resolve - if ( cached.then ) { - - cached.then( imageBitmap => { - - if ( onLoad ) onLoad( imageBitmap ); - - scope.manager.itemEnd( url ); - - } ).catch( e => { - - if ( onError ) onError( e ); - - } ); - return; - - } - - // If cached is not a promise (i.e., it's already an imageBitmap) - setTimeout( function () { - - if ( onLoad ) onLoad( cached ); - - scope.manager.itemEnd( url ); - - }, 0 ); - - return cached; - - } - - const fetchOptions = {}; - fetchOptions.credentials = ( this.crossOrigin === 'anonymous' ) ? 'same-origin' : 'include'; - fetchOptions.headers = this.requestHeader; - - const promise = fetch( url, fetchOptions ).then( function ( res ) { - - return res.blob(); - - } ).then( function ( blob ) { - - return createImageBitmap( blob, Object.assign( scope.options, { colorSpaceConversion: 'none' } ) ); - - } ).then( function ( imageBitmap ) { - - Cache.add( url, imageBitmap ); - - if ( onLoad ) onLoad( imageBitmap ); - - scope.manager.itemEnd( url ); - - return imageBitmap; - - } ).catch( function ( e ) { - - if ( onError ) onError( e ); - - Cache.remove( url ); - - scope.manager.itemError( url ); - scope.manager.itemEnd( url ); - - } ); - - Cache.add( url, promise ); - scope.manager.itemStart( url ); - - } - -} - -let _context; - -class AudioContext { - - static getContext() { - - if ( _context === undefined ) { - - _context = new ( window.AudioContext || window.webkitAudioContext )(); - - } - - return _context; - - } - - static setContext( value ) { - - _context = value; - - } - -} - -class AudioLoader extends Loader { - - constructor( manager ) { - - super( manager ); - - } - - load( url, onLoad, onProgress, onError ) { - - const scope = this; - - const loader = new FileLoader( this.manager ); - loader.setResponseType( 'arraybuffer' ); - loader.setPath( this.path ); - loader.setRequestHeader( this.requestHeader ); - loader.setWithCredentials( this.withCredentials ); - loader.load( url, function ( buffer ) { - - try { - - // Create a copy of the buffer. The `decodeAudioData` method - // detaches the buffer when complete, preventing reuse. - const bufferCopy = buffer.slice( 0 ); - - const context = AudioContext.getContext(); - context.decodeAudioData( bufferCopy, function ( audioBuffer ) { - - onLoad( audioBuffer ); - - } ).catch( handleError ); - - } catch ( e ) { - - handleError( e ); - - } - - }, onProgress, onError ); - - function handleError( e ) { - - if ( onError ) { - - onError( e ); - - } else { - - console.error( e ); - - } - - scope.manager.itemError( url ); - - } - - } - -} - -const _eyeRight = /*@__PURE__*/ new Matrix4(); -const _eyeLeft = /*@__PURE__*/ new Matrix4(); -const _projectionMatrix = /*@__PURE__*/ new Matrix4(); - -class StereoCamera { - - constructor() { - - this.type = 'StereoCamera'; - - this.aspect = 1; - - this.eyeSep = 0.064; - - this.cameraL = new PerspectiveCamera(); - this.cameraL.layers.enable( 1 ); - this.cameraL.matrixAutoUpdate = false; - - this.cameraR = new PerspectiveCamera(); - this.cameraR.layers.enable( 2 ); - this.cameraR.matrixAutoUpdate = false; - - this._cache = { - focus: null, - fov: null, - aspect: null, - near: null, - far: null, - zoom: null, - eyeSep: null - }; - - } - - update( camera ) { - - const cache = this._cache; - - const needsUpdate = cache.focus !== camera.focus || cache.fov !== camera.fov || - cache.aspect !== camera.aspect * this.aspect || cache.near !== camera.near || - cache.far !== camera.far || cache.zoom !== camera.zoom || cache.eyeSep !== this.eyeSep; - - if ( needsUpdate ) { - - cache.focus = camera.focus; - cache.fov = camera.fov; - cache.aspect = camera.aspect * this.aspect; - cache.near = camera.near; - cache.far = camera.far; - cache.zoom = camera.zoom; - cache.eyeSep = this.eyeSep; - - // Off-axis stereoscopic effect based on - // http://paulbourke.net/stereographics/stereorender/ - - _projectionMatrix.copy( camera.projectionMatrix ); - const eyeSepHalf = cache.eyeSep / 2; - const eyeSepOnProjection = eyeSepHalf * cache.near / cache.focus; - const ymax = ( cache.near * Math.tan( DEG2RAD * cache.fov * 0.5 ) ) / cache.zoom; - let xmin, xmax; - - // translate xOffset - - _eyeLeft.elements[ 12 ] = - eyeSepHalf; - _eyeRight.elements[ 12 ] = eyeSepHalf; - - // for left eye - - xmin = - ymax * cache.aspect + eyeSepOnProjection; - xmax = ymax * cache.aspect + eyeSepOnProjection; - - _projectionMatrix.elements[ 0 ] = 2 * cache.near / ( xmax - xmin ); - _projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin ); - - this.cameraL.projectionMatrix.copy( _projectionMatrix ); - - // for right eye - - xmin = - ymax * cache.aspect - eyeSepOnProjection; - xmax = ymax * cache.aspect - eyeSepOnProjection; - - _projectionMatrix.elements[ 0 ] = 2 * cache.near / ( xmax - xmin ); - _projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin ); - - this.cameraR.projectionMatrix.copy( _projectionMatrix ); - - } - - this.cameraL.matrixWorld.copy( camera.matrixWorld ).multiply( _eyeLeft ); - this.cameraR.matrixWorld.copy( camera.matrixWorld ).multiply( _eyeRight ); - - } - -} - -class Clock { - - constructor( autoStart = true ) { - - this.autoStart = autoStart; - - this.startTime = 0; - this.oldTime = 0; - this.elapsedTime = 0; - - this.running = false; - - } - - start() { - - this.startTime = now(); - - this.oldTime = this.startTime; - this.elapsedTime = 0; - this.running = true; - - } - - stop() { - - this.getElapsedTime(); - this.running = false; - this.autoStart = false; - - } - - getElapsedTime() { - - this.getDelta(); - return this.elapsedTime; - - } - - getDelta() { - - let diff = 0; - - if ( this.autoStart && ! this.running ) { - - this.start(); - return 0; - - } - - if ( this.running ) { - - const newTime = now(); - - diff = ( newTime - this.oldTime ) / 1000; - this.oldTime = newTime; - - this.elapsedTime += diff; - - } - - return diff; - - } - -} - -function now() { - - return ( typeof performance === 'undefined' ? Date : performance ).now(); // see #10732 - -} - -const _position$1 = /*@__PURE__*/ new Vector3(); -const _quaternion$1 = /*@__PURE__*/ new Quaternion(); -const _scale$1 = /*@__PURE__*/ new Vector3(); -const _orientation$1 = /*@__PURE__*/ new Vector3(); - -class AudioListener extends Object3D { - - constructor() { - - super(); - - this.type = 'AudioListener'; - - this.context = AudioContext.getContext(); - - this.gain = this.context.createGain(); - this.gain.connect( this.context.destination ); - - this.filter = null; - - this.timeDelta = 0; - - // private - - this._clock = new Clock(); - - } - - getInput() { - - return this.gain; - - } - - removeFilter() { - - if ( this.filter !== null ) { - - this.gain.disconnect( this.filter ); - this.filter.disconnect( this.context.destination ); - this.gain.connect( this.context.destination ); - this.filter = null; - - } - - return this; - - } - - getFilter() { - - return this.filter; - - } - - setFilter( value ) { - - if ( this.filter !== null ) { - - this.gain.disconnect( this.filter ); - this.filter.disconnect( this.context.destination ); - - } else { - - this.gain.disconnect( this.context.destination ); - - } - - this.filter = value; - this.gain.connect( this.filter ); - this.filter.connect( this.context.destination ); - - return this; - - } - - getMasterVolume() { - - return this.gain.gain.value; - - } - - setMasterVolume( value ) { - - this.gain.gain.setTargetAtTime( value, this.context.currentTime, 0.01 ); - - return this; - - } - - updateMatrixWorld( force ) { - - super.updateMatrixWorld( force ); - - const listener = this.context.listener; - const up = this.up; - - this.timeDelta = this._clock.getDelta(); - - this.matrixWorld.decompose( _position$1, _quaternion$1, _scale$1 ); - - _orientation$1.set( 0, 0, - 1 ).applyQuaternion( _quaternion$1 ); - - if ( listener.positionX ) { - - // code path for Chrome (see #14393) - - const endTime = this.context.currentTime + this.timeDelta; - - listener.positionX.linearRampToValueAtTime( _position$1.x, endTime ); - listener.positionY.linearRampToValueAtTime( _position$1.y, endTime ); - listener.positionZ.linearRampToValueAtTime( _position$1.z, endTime ); - listener.forwardX.linearRampToValueAtTime( _orientation$1.x, endTime ); - listener.forwardY.linearRampToValueAtTime( _orientation$1.y, endTime ); - listener.forwardZ.linearRampToValueAtTime( _orientation$1.z, endTime ); - listener.upX.linearRampToValueAtTime( up.x, endTime ); - listener.upY.linearRampToValueAtTime( up.y, endTime ); - listener.upZ.linearRampToValueAtTime( up.z, endTime ); - - } else { - - listener.setPosition( _position$1.x, _position$1.y, _position$1.z ); - listener.setOrientation( _orientation$1.x, _orientation$1.y, _orientation$1.z, up.x, up.y, up.z ); - - } - - } - -} - -class Audio extends Object3D { - - constructor( listener ) { - - super(); - - this.type = 'Audio'; - - this.listener = listener; - this.context = listener.context; - - this.gain = this.context.createGain(); - this.gain.connect( listener.getInput() ); - - this.autoplay = false; - - this.buffer = null; - this.detune = 0; - this.loop = false; - this.loopStart = 0; - this.loopEnd = 0; - this.offset = 0; - this.duration = undefined; - this.playbackRate = 1; - this.isPlaying = false; - this.hasPlaybackControl = true; - this.source = null; - this.sourceType = 'empty'; - - this._startedAt = 0; - this._progress = 0; - this._connected = false; - - this.filters = []; - - } - - getOutput() { - - return this.gain; - - } - - setNodeSource( audioNode ) { - - this.hasPlaybackControl = false; - this.sourceType = 'audioNode'; - this.source = audioNode; - this.connect(); - - return this; - - } - - setMediaElementSource( mediaElement ) { - - this.hasPlaybackControl = false; - this.sourceType = 'mediaNode'; - this.source = this.context.createMediaElementSource( mediaElement ); - this.connect(); - - return this; - - } - - setMediaStreamSource( mediaStream ) { - - this.hasPlaybackControl = false; - this.sourceType = 'mediaStreamNode'; - this.source = this.context.createMediaStreamSource( mediaStream ); - this.connect(); - - return this; - - } - - setBuffer( audioBuffer ) { - - this.buffer = audioBuffer; - this.sourceType = 'buffer'; - - if ( this.autoplay ) this.play(); - - return this; - - } - - play( delay = 0 ) { - - if ( this.isPlaying === true ) { - - console.warn( 'THREE.Audio: Audio is already playing.' ); - return; - - } - - if ( this.hasPlaybackControl === false ) { - - console.warn( 'THREE.Audio: this Audio has no playback control.' ); - return; - - } - - this._startedAt = this.context.currentTime + delay; - - const source = this.context.createBufferSource(); - source.buffer = this.buffer; - source.loop = this.loop; - source.loopStart = this.loopStart; - source.loopEnd = this.loopEnd; - source.onended = this.onEnded.bind( this ); - source.start( this._startedAt, this._progress + this.offset, this.duration ); - - this.isPlaying = true; - - this.source = source; - - this.setDetune( this.detune ); - this.setPlaybackRate( this.playbackRate ); - - return this.connect(); - - } - - pause() { - - if ( this.hasPlaybackControl === false ) { - - console.warn( 'THREE.Audio: this Audio has no playback control.' ); - return; - - } - - if ( this.isPlaying === true ) { - - // update current progress - - this._progress += Math.max( this.context.currentTime - this._startedAt, 0 ) * this.playbackRate; - - if ( this.loop === true ) { - - // ensure _progress does not exceed duration with looped audios - - this._progress = this._progress % ( this.duration || this.buffer.duration ); - - } - - this.source.stop(); - this.source.onended = null; - - this.isPlaying = false; - - } - - return this; - - } - - stop() { - - if ( this.hasPlaybackControl === false ) { - - console.warn( 'THREE.Audio: this Audio has no playback control.' ); - return; - - } - - this._progress = 0; - - if ( this.source !== null ) { - - this.source.stop(); - this.source.onended = null; - - } - - this.isPlaying = false; - - return this; - - } - - connect() { - - if ( this.filters.length > 0 ) { - - this.source.connect( this.filters[ 0 ] ); - - for ( let i = 1, l = this.filters.length; i < l; i ++ ) { - - this.filters[ i - 1 ].connect( this.filters[ i ] ); - - } - - this.filters[ this.filters.length - 1 ].connect( this.getOutput() ); - - } else { - - this.source.connect( this.getOutput() ); - - } - - this._connected = true; - - return this; - - } - - disconnect() { - - if ( this._connected === false ) { - - return; - - } - - if ( this.filters.length > 0 ) { - - this.source.disconnect( this.filters[ 0 ] ); - - for ( let i = 1, l = this.filters.length; i < l; i ++ ) { - - this.filters[ i - 1 ].disconnect( this.filters[ i ] ); - - } - - this.filters[ this.filters.length - 1 ].disconnect( this.getOutput() ); - - } else { - - this.source.disconnect( this.getOutput() ); - - } - - this._connected = false; - - return this; - - } - - getFilters() { - - return this.filters; - - } - - setFilters( value ) { - - if ( ! value ) value = []; - - if ( this._connected === true ) { - - this.disconnect(); - this.filters = value.slice(); - this.connect(); - - } else { - - this.filters = value.slice(); - - } - - return this; - - } - - setDetune( value ) { - - this.detune = value; - - if ( this.isPlaying === true && this.source.detune !== undefined ) { - - this.source.detune.setTargetAtTime( this.detune, this.context.currentTime, 0.01 ); - - } - - return this; - - } - - getDetune() { - - return this.detune; - - } - - getFilter() { - - return this.getFilters()[ 0 ]; - - } - - setFilter( filter ) { - - return this.setFilters( filter ? [ filter ] : [] ); - - } - - setPlaybackRate( value ) { - - if ( this.hasPlaybackControl === false ) { - - console.warn( 'THREE.Audio: this Audio has no playback control.' ); - return; - - } - - this.playbackRate = value; - - if ( this.isPlaying === true ) { - - this.source.playbackRate.setTargetAtTime( this.playbackRate, this.context.currentTime, 0.01 ); - - } - - return this; - - } - - getPlaybackRate() { - - return this.playbackRate; - - } - - onEnded() { - - this.isPlaying = false; - - } - - getLoop() { - - if ( this.hasPlaybackControl === false ) { - - console.warn( 'THREE.Audio: this Audio has no playback control.' ); - return false; - - } - - return this.loop; - - } - - setLoop( value ) { - - if ( this.hasPlaybackControl === false ) { - - console.warn( 'THREE.Audio: this Audio has no playback control.' ); - return; - - } - - this.loop = value; - - if ( this.isPlaying === true ) { - - this.source.loop = this.loop; - - } - - return this; - - } - - setLoopStart( value ) { - - this.loopStart = value; - - return this; - - } - - setLoopEnd( value ) { - - this.loopEnd = value; - - return this; - - } - - getVolume() { - - return this.gain.gain.value; - - } - - setVolume( value ) { - - this.gain.gain.setTargetAtTime( value, this.context.currentTime, 0.01 ); - - return this; - - } - -} - -const _position = /*@__PURE__*/ new Vector3(); -const _quaternion = /*@__PURE__*/ new Quaternion(); -const _scale = /*@__PURE__*/ new Vector3(); -const _orientation = /*@__PURE__*/ new Vector3(); - -class PositionalAudio extends Audio { - - constructor( listener ) { - - super( listener ); - - this.panner = this.context.createPanner(); - this.panner.panningModel = 'HRTF'; - this.panner.connect( this.gain ); - - } - - connect() { - - super.connect(); - - this.panner.connect( this.gain ); - - } - - disconnect() { - - super.disconnect(); - - this.panner.disconnect( this.gain ); - - } - - getOutput() { - - return this.panner; - - } - - getRefDistance() { - - return this.panner.refDistance; - - } - - setRefDistance( value ) { - - this.panner.refDistance = value; - - return this; - - } - - getRolloffFactor() { - - return this.panner.rolloffFactor; - - } - - setRolloffFactor( value ) { - - this.panner.rolloffFactor = value; - - return this; - - } - - getDistanceModel() { - - return this.panner.distanceModel; - - } - - setDistanceModel( value ) { - - this.panner.distanceModel = value; - - return this; - - } - - getMaxDistance() { - - return this.panner.maxDistance; - - } - - setMaxDistance( value ) { - - this.panner.maxDistance = value; - - return this; - - } - - setDirectionalCone( coneInnerAngle, coneOuterAngle, coneOuterGain ) { - - this.panner.coneInnerAngle = coneInnerAngle; - this.panner.coneOuterAngle = coneOuterAngle; - this.panner.coneOuterGain = coneOuterGain; - - return this; - - } - - updateMatrixWorld( force ) { - - super.updateMatrixWorld( force ); - - if ( this.hasPlaybackControl === true && this.isPlaying === false ) return; - - this.matrixWorld.decompose( _position, _quaternion, _scale ); - - _orientation.set( 0, 0, 1 ).applyQuaternion( _quaternion ); - - const panner = this.panner; - - if ( panner.positionX ) { - - // code path for Chrome and Firefox (see #14393) - - const endTime = this.context.currentTime + this.listener.timeDelta; - - panner.positionX.linearRampToValueAtTime( _position.x, endTime ); - panner.positionY.linearRampToValueAtTime( _position.y, endTime ); - panner.positionZ.linearRampToValueAtTime( _position.z, endTime ); - panner.orientationX.linearRampToValueAtTime( _orientation.x, endTime ); - panner.orientationY.linearRampToValueAtTime( _orientation.y, endTime ); - panner.orientationZ.linearRampToValueAtTime( _orientation.z, endTime ); - - } else { - - panner.setPosition( _position.x, _position.y, _position.z ); - panner.setOrientation( _orientation.x, _orientation.y, _orientation.z ); - - } - - } - -} - -class AudioAnalyser { - - constructor( audio, fftSize = 2048 ) { - - this.analyser = audio.context.createAnalyser(); - this.analyser.fftSize = fftSize; - - this.data = new Uint8Array( this.analyser.frequencyBinCount ); - - audio.getOutput().connect( this.analyser ); - - } - - - getFrequencyData() { - - this.analyser.getByteFrequencyData( this.data ); - - return this.data; - - } - - getAverageFrequency() { - - let value = 0; - const data = this.getFrequencyData(); - - for ( let i = 0; i < data.length; i ++ ) { - - value += data[ i ]; - - } - - return value / data.length; - - } - -} - -class PropertyMixer { - - constructor( binding, typeName, valueSize ) { - - this.binding = binding; - this.valueSize = valueSize; - - let mixFunction, - mixFunctionAdditive, - setIdentity; - - // buffer layout: [ incoming | accu0 | accu1 | orig | addAccu | (optional work) ] - // - // interpolators can use .buffer as their .result - // the data then goes to 'incoming' - // - // 'accu0' and 'accu1' are used frame-interleaved for - // the cumulative result and are compared to detect - // changes - // - // 'orig' stores the original state of the property - // - // 'add' is used for additive cumulative results - // - // 'work' is optional and is only present for quaternion types. It is used - // to store intermediate quaternion multiplication results - - switch ( typeName ) { - - case 'quaternion': - mixFunction = this._slerp; - mixFunctionAdditive = this._slerpAdditive; - setIdentity = this._setAdditiveIdentityQuaternion; - - this.buffer = new Float64Array( valueSize * 6 ); - this._workIndex = 5; - break; - - case 'string': - case 'bool': - mixFunction = this._select; - - // Use the regular mix function and for additive on these types, - // additive is not relevant for non-numeric types - mixFunctionAdditive = this._select; - - setIdentity = this._setAdditiveIdentityOther; - - this.buffer = new Array( valueSize * 5 ); - break; - - default: - mixFunction = this._lerp; - mixFunctionAdditive = this._lerpAdditive; - setIdentity = this._setAdditiveIdentityNumeric; - - this.buffer = new Float64Array( valueSize * 5 ); - - } - - this._mixBufferRegion = mixFunction; - this._mixBufferRegionAdditive = mixFunctionAdditive; - this._setIdentity = setIdentity; - this._origIndex = 3; - this._addIndex = 4; - - this.cumulativeWeight = 0; - this.cumulativeWeightAdditive = 0; - - this.useCount = 0; - this.referenceCount = 0; - - } - - // accumulate data in the 'incoming' region into 'accu' - accumulate( accuIndex, weight ) { - - // note: happily accumulating nothing when weight = 0, the caller knows - // the weight and shouldn't have made the call in the first place - - const buffer = this.buffer, - stride = this.valueSize, - offset = accuIndex * stride + stride; - - let currentWeight = this.cumulativeWeight; - - if ( currentWeight === 0 ) { - - // accuN := incoming * weight - - for ( let i = 0; i !== stride; ++ i ) { - - buffer[ offset + i ] = buffer[ i ]; - - } - - currentWeight = weight; - - } else { - - // accuN := accuN + incoming * weight - - currentWeight += weight; - const mix = weight / currentWeight; - this._mixBufferRegion( buffer, offset, 0, mix, stride ); - - } - - this.cumulativeWeight = currentWeight; - - } - - // accumulate data in the 'incoming' region into 'add' - accumulateAdditive( weight ) { - - const buffer = this.buffer, - stride = this.valueSize, - offset = stride * this._addIndex; - - if ( this.cumulativeWeightAdditive === 0 ) { - - // add = identity - - this._setIdentity(); - - } - - // add := add + incoming * weight - - this._mixBufferRegionAdditive( buffer, offset, 0, weight, stride ); - this.cumulativeWeightAdditive += weight; - - } - - // apply the state of 'accu' to the binding when accus differ - apply( accuIndex ) { - - const stride = this.valueSize, - buffer = this.buffer, - offset = accuIndex * stride + stride, - - weight = this.cumulativeWeight, - weightAdditive = this.cumulativeWeightAdditive, - - binding = this.binding; - - this.cumulativeWeight = 0; - this.cumulativeWeightAdditive = 0; - - if ( weight < 1 ) { - - // accuN := accuN + original * ( 1 - cumulativeWeight ) - - const originalValueOffset = stride * this._origIndex; - - this._mixBufferRegion( - buffer, offset, originalValueOffset, 1 - weight, stride ); - - } - - if ( weightAdditive > 0 ) { - - // accuN := accuN + additive accuN - - this._mixBufferRegionAdditive( buffer, offset, this._addIndex * stride, 1, stride ); - - } - - for ( let i = stride, e = stride + stride; i !== e; ++ i ) { - - if ( buffer[ i ] !== buffer[ i + stride ] ) { - - // value has changed -> update scene graph - - binding.setValue( buffer, offset ); - break; - - } - - } - - } - - // remember the state of the bound property and copy it to both accus - saveOriginalState() { - - const binding = this.binding; - - const buffer = this.buffer, - stride = this.valueSize, - - originalValueOffset = stride * this._origIndex; - - binding.getValue( buffer, originalValueOffset ); - - // accu[0..1] := orig -- initially detect changes against the original - for ( let i = stride, e = originalValueOffset; i !== e; ++ i ) { - - buffer[ i ] = buffer[ originalValueOffset + ( i % stride ) ]; - - } - - // Add to identity for additive - this._setIdentity(); - - this.cumulativeWeight = 0; - this.cumulativeWeightAdditive = 0; - - } - - // apply the state previously taken via 'saveOriginalState' to the binding - restoreOriginalState() { - - const originalValueOffset = this.valueSize * 3; - this.binding.setValue( this.buffer, originalValueOffset ); - - } - - _setAdditiveIdentityNumeric() { - - const startIndex = this._addIndex * this.valueSize; - const endIndex = startIndex + this.valueSize; - - for ( let i = startIndex; i < endIndex; i ++ ) { - - this.buffer[ i ] = 0; - - } - - } - - _setAdditiveIdentityQuaternion() { - - this._setAdditiveIdentityNumeric(); - this.buffer[ this._addIndex * this.valueSize + 3 ] = 1; - - } - - _setAdditiveIdentityOther() { - - const startIndex = this._origIndex * this.valueSize; - const targetIndex = this._addIndex * this.valueSize; - - for ( let i = 0; i < this.valueSize; i ++ ) { - - this.buffer[ targetIndex + i ] = this.buffer[ startIndex + i ]; - - } - - } - - - // mix functions - - _select( buffer, dstOffset, srcOffset, t, stride ) { - - if ( t >= 0.5 ) { - - for ( let i = 0; i !== stride; ++ i ) { - - buffer[ dstOffset + i ] = buffer[ srcOffset + i ]; - - } - - } - - } - - _slerp( buffer, dstOffset, srcOffset, t ) { - - Quaternion.slerpFlat( buffer, dstOffset, buffer, dstOffset, buffer, srcOffset, t ); - - } - - _slerpAdditive( buffer, dstOffset, srcOffset, t, stride ) { - - const workOffset = this._workIndex * stride; - - // Store result in intermediate buffer offset - Quaternion.multiplyQuaternionsFlat( buffer, workOffset, buffer, dstOffset, buffer, srcOffset ); - - // Slerp to the intermediate result - Quaternion.slerpFlat( buffer, dstOffset, buffer, dstOffset, buffer, workOffset, t ); - - } - - _lerp( buffer, dstOffset, srcOffset, t, stride ) { - - const s = 1 - t; - - for ( let i = 0; i !== stride; ++ i ) { - - const j = dstOffset + i; - - buffer[ j ] = buffer[ j ] * s + buffer[ srcOffset + i ] * t; - - } - - } - - _lerpAdditive( buffer, dstOffset, srcOffset, t, stride ) { - - for ( let i = 0; i !== stride; ++ i ) { - - const j = dstOffset + i; - - buffer[ j ] = buffer[ j ] + buffer[ srcOffset + i ] * t; - - } - - } - -} - -// Characters [].:/ are reserved for track binding syntax. -const _RESERVED_CHARS_RE = '\\[\\]\\.:\\/'; -const _reservedRe = new RegExp( '[' + _RESERVED_CHARS_RE + ']', 'g' ); - -// Attempts to allow node names from any language. ES5's `\w` regexp matches -// only latin characters, and the unicode \p{L} is not yet supported. So -// instead, we exclude reserved characters and match everything else. -const _wordChar = '[^' + _RESERVED_CHARS_RE + ']'; -const _wordCharOrDot = '[^' + _RESERVED_CHARS_RE.replace( '\\.', '' ) + ']'; - -// Parent directories, delimited by '/' or ':'. Currently unused, but must -// be matched to parse the rest of the track name. -const _directoryRe = /*@__PURE__*/ /((?:WC+[\/:])*)/.source.replace( 'WC', _wordChar ); - -// Target node. May contain word characters (a-zA-Z0-9_) and '.' or '-'. -const _nodeRe = /*@__PURE__*/ /(WCOD+)?/.source.replace( 'WCOD', _wordCharOrDot ); - -// Object on target node, and accessor. May not contain reserved -// characters. Accessor may contain any character except closing bracket. -const _objectRe = /*@__PURE__*/ /(?:\.(WC+)(?:\[(.+)\])?)?/.source.replace( 'WC', _wordChar ); - -// Property and accessor. May not contain reserved characters. Accessor may -// contain any non-bracket characters. -const _propertyRe = /*@__PURE__*/ /\.(WC+)(?:\[(.+)\])?/.source.replace( 'WC', _wordChar ); - -const _trackRe = new RegExp( '' - + '^' - + _directoryRe - + _nodeRe - + _objectRe - + _propertyRe - + '$' -); - -const _supportedObjectNames = [ 'material', 'materials', 'bones', 'map' ]; - -class Composite { - - constructor( targetGroup, path, optionalParsedPath ) { - - const parsedPath = optionalParsedPath || PropertyBinding.parseTrackName( path ); - - this._targetGroup = targetGroup; - this._bindings = targetGroup.subscribe_( path, parsedPath ); - - } - - getValue( array, offset ) { - - this.bind(); // bind all binding - - const firstValidIndex = this._targetGroup.nCachedObjects_, - binding = this._bindings[ firstValidIndex ]; - - // and only call .getValue on the first - if ( binding !== undefined ) binding.getValue( array, offset ); - - } - - setValue( array, offset ) { - - const bindings = this._bindings; - - for ( let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) { - - bindings[ i ].setValue( array, offset ); - - } - - } - - bind() { - - const bindings = this._bindings; - - for ( let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) { - - bindings[ i ].bind(); - - } - - } - - unbind() { - - const bindings = this._bindings; - - for ( let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) { - - bindings[ i ].unbind(); - - } - - } - -} - -// Note: This class uses a State pattern on a per-method basis: -// 'bind' sets 'this.getValue' / 'setValue' and shadows the -// prototype version of these methods with one that represents -// the bound state. When the property is not found, the methods -// become no-ops. -class PropertyBinding { - - constructor( rootNode, path, parsedPath ) { - - this.path = path; - this.parsedPath = parsedPath || PropertyBinding.parseTrackName( path ); - - this.node = PropertyBinding.findNode( rootNode, this.parsedPath.nodeName ); - - this.rootNode = rootNode; - - // initial state of these methods that calls 'bind' - this.getValue = this._getValue_unbound; - this.setValue = this._setValue_unbound; - - } - - - static create( root, path, parsedPath ) { - - if ( ! ( root && root.isAnimationObjectGroup ) ) { - - return new PropertyBinding( root, path, parsedPath ); - - } else { - - return new PropertyBinding.Composite( root, path, parsedPath ); - - } - - } - - /** - * Replaces spaces with underscores and removes unsupported characters from - * node names, to ensure compatibility with parseTrackName(). - * - * @param {string} name Node name to be sanitized. - * @return {string} - */ - static sanitizeNodeName( name ) { - - return name.replace( /\s/g, '_' ).replace( _reservedRe, '' ); - - } - - static parseTrackName( trackName ) { - - const matches = _trackRe.exec( trackName ); - - if ( matches === null ) { - - throw new Error( 'PropertyBinding: Cannot parse trackName: ' + trackName ); - - } - - const results = { - // directoryName: matches[ 1 ], // (tschw) currently unused - nodeName: matches[ 2 ], - objectName: matches[ 3 ], - objectIndex: matches[ 4 ], - propertyName: matches[ 5 ], // required - propertyIndex: matches[ 6 ] - }; - - const lastDot = results.nodeName && results.nodeName.lastIndexOf( '.' ); - - if ( lastDot !== undefined && lastDot !== - 1 ) { - - const objectName = results.nodeName.substring( lastDot + 1 ); - - // Object names must be checked against an allowlist. Otherwise, there - // is no way to parse 'foo.bar.baz': 'baz' must be a property, but - // 'bar' could be the objectName, or part of a nodeName (which can - // include '.' characters). - if ( _supportedObjectNames.indexOf( objectName ) !== - 1 ) { - - results.nodeName = results.nodeName.substring( 0, lastDot ); - results.objectName = objectName; - - } - - } - - if ( results.propertyName === null || results.propertyName.length === 0 ) { - - throw new Error( 'PropertyBinding: can not parse propertyName from trackName: ' + trackName ); - - } - - return results; - - } - - static findNode( root, nodeName ) { - - if ( nodeName === undefined || nodeName === '' || nodeName === '.' || nodeName === - 1 || nodeName === root.name || nodeName === root.uuid ) { - - return root; - - } - - // search into skeleton bones. - if ( root.skeleton ) { - - const bone = root.skeleton.getBoneByName( nodeName ); - - if ( bone !== undefined ) { - - return bone; - - } - - } - - // search into node subtree. - if ( root.children ) { - - const searchNodeSubtree = function ( children ) { - - for ( let i = 0; i < children.length; i ++ ) { - - const childNode = children[ i ]; - - if ( childNode.name === nodeName || childNode.uuid === nodeName ) { - - return childNode; - - } - - const result = searchNodeSubtree( childNode.children ); - - if ( result ) return result; - - } - - return null; - - }; - - const subTreeNode = searchNodeSubtree( root.children ); - - if ( subTreeNode ) { - - return subTreeNode; - - } - - } - - return null; - - } - - // these are used to "bind" a nonexistent property - _getValue_unavailable() {} - _setValue_unavailable() {} - - // Getters - - _getValue_direct( buffer, offset ) { - - buffer[ offset ] = this.targetObject[ this.propertyName ]; - - } - - _getValue_array( buffer, offset ) { - - const source = this.resolvedProperty; - - for ( let i = 0, n = source.length; i !== n; ++ i ) { - - buffer[ offset ++ ] = source[ i ]; - - } - - } - - _getValue_arrayElement( buffer, offset ) { - - buffer[ offset ] = this.resolvedProperty[ this.propertyIndex ]; - - } - - _getValue_toArray( buffer, offset ) { - - this.resolvedProperty.toArray( buffer, offset ); - - } - - // Direct - - _setValue_direct( buffer, offset ) { - - this.targetObject[ this.propertyName ] = buffer[ offset ]; - - } - - _setValue_direct_setNeedsUpdate( buffer, offset ) { - - this.targetObject[ this.propertyName ] = buffer[ offset ]; - this.targetObject.needsUpdate = true; - - } - - _setValue_direct_setMatrixWorldNeedsUpdate( buffer, offset ) { - - this.targetObject[ this.propertyName ] = buffer[ offset ]; - this.targetObject.matrixWorldNeedsUpdate = true; - - } - - // EntireArray - - _setValue_array( buffer, offset ) { - - const dest = this.resolvedProperty; - - for ( let i = 0, n = dest.length; i !== n; ++ i ) { - - dest[ i ] = buffer[ offset ++ ]; - - } - - } - - _setValue_array_setNeedsUpdate( buffer, offset ) { - - const dest = this.resolvedProperty; - - for ( let i = 0, n = dest.length; i !== n; ++ i ) { - - dest[ i ] = buffer[ offset ++ ]; - - } - - this.targetObject.needsUpdate = true; - - } - - _setValue_array_setMatrixWorldNeedsUpdate( buffer, offset ) { - - const dest = this.resolvedProperty; - - for ( let i = 0, n = dest.length; i !== n; ++ i ) { - - dest[ i ] = buffer[ offset ++ ]; - - } - - this.targetObject.matrixWorldNeedsUpdate = true; - - } - - // ArrayElement - - _setValue_arrayElement( buffer, offset ) { - - this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ]; - - } - - _setValue_arrayElement_setNeedsUpdate( buffer, offset ) { - - this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ]; - this.targetObject.needsUpdate = true; - - } - - _setValue_arrayElement_setMatrixWorldNeedsUpdate( buffer, offset ) { - - this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ]; - this.targetObject.matrixWorldNeedsUpdate = true; - - } - - // HasToFromArray - - _setValue_fromArray( buffer, offset ) { - - this.resolvedProperty.fromArray( buffer, offset ); - - } - - _setValue_fromArray_setNeedsUpdate( buffer, offset ) { - - this.resolvedProperty.fromArray( buffer, offset ); - this.targetObject.needsUpdate = true; - - } - - _setValue_fromArray_setMatrixWorldNeedsUpdate( buffer, offset ) { - - this.resolvedProperty.fromArray( buffer, offset ); - this.targetObject.matrixWorldNeedsUpdate = true; - - } - - _getValue_unbound( targetArray, offset ) { - - this.bind(); - this.getValue( targetArray, offset ); - - } - - _setValue_unbound( sourceArray, offset ) { - - this.bind(); - this.setValue( sourceArray, offset ); - - } - - // create getter / setter pair for a property in the scene graph - bind() { - - let targetObject = this.node; - const parsedPath = this.parsedPath; - - const objectName = parsedPath.objectName; - const propertyName = parsedPath.propertyName; - let propertyIndex = parsedPath.propertyIndex; - - if ( ! targetObject ) { - - targetObject = PropertyBinding.findNode( this.rootNode, parsedPath.nodeName ); - - this.node = targetObject; - - } - - // set fail state so we can just 'return' on error - this.getValue = this._getValue_unavailable; - this.setValue = this._setValue_unavailable; - - // ensure there is a value node - if ( ! targetObject ) { - - console.warn( 'THREE.PropertyBinding: No target node found for track: ' + this.path + '.' ); - return; - - } - - if ( objectName ) { - - let objectIndex = parsedPath.objectIndex; - - // special cases were we need to reach deeper into the hierarchy to get the face materials.... - switch ( objectName ) { - - case 'materials': - - if ( ! targetObject.material ) { - - console.error( 'THREE.PropertyBinding: Can not bind to material as node does not have a material.', this ); - return; - - } - - if ( ! targetObject.material.materials ) { - - console.error( 'THREE.PropertyBinding: Can not bind to material.materials as node.material does not have a materials array.', this ); - return; - - } - - targetObject = targetObject.material.materials; - - break; - - case 'bones': - - if ( ! targetObject.skeleton ) { - - console.error( 'THREE.PropertyBinding: Can not bind to bones as node does not have a skeleton.', this ); - return; - - } - - // potential future optimization: skip this if propertyIndex is already an integer - // and convert the integer string to a true integer. - - targetObject = targetObject.skeleton.bones; - - // support resolving morphTarget names into indices. - for ( let i = 0; i < targetObject.length; i ++ ) { - - if ( targetObject[ i ].name === objectIndex ) { - - objectIndex = i; - break; - - } - - } - - break; - - case 'map': - - if ( 'map' in targetObject ) { - - targetObject = targetObject.map; - break; - - } - - if ( ! targetObject.material ) { - - console.error( 'THREE.PropertyBinding: Can not bind to material as node does not have a material.', this ); - return; - - } - - if ( ! targetObject.material.map ) { - - console.error( 'THREE.PropertyBinding: Can not bind to material.map as node.material does not have a map.', this ); - return; - - } - - targetObject = targetObject.material.map; - break; - - default: - - if ( targetObject[ objectName ] === undefined ) { - - console.error( 'THREE.PropertyBinding: Can not bind to objectName of node undefined.', this ); - return; - - } - - targetObject = targetObject[ objectName ]; - - } - - - if ( objectIndex !== undefined ) { - - if ( targetObject[ objectIndex ] === undefined ) { - - console.error( 'THREE.PropertyBinding: Trying to bind to objectIndex of objectName, but is undefined.', this, targetObject ); - return; - - } - - targetObject = targetObject[ objectIndex ]; - - } - - } - - // resolve property - const nodeProperty = targetObject[ propertyName ]; - - if ( nodeProperty === undefined ) { - - const nodeName = parsedPath.nodeName; - - console.error( 'THREE.PropertyBinding: Trying to update property for track: ' + nodeName + - '.' + propertyName + ' but it wasn\'t found.', targetObject ); - return; - - } - - // determine versioning scheme - let versioning = this.Versioning.None; - - this.targetObject = targetObject; - - if ( targetObject.needsUpdate !== undefined ) { // material - - versioning = this.Versioning.NeedsUpdate; - - } else if ( targetObject.matrixWorldNeedsUpdate !== undefined ) { // node transform - - versioning = this.Versioning.MatrixWorldNeedsUpdate; - - } - - // determine how the property gets bound - let bindingType = this.BindingType.Direct; - - if ( propertyIndex !== undefined ) { - - // access a sub element of the property array (only primitives are supported right now) - - if ( propertyName === 'morphTargetInfluences' ) { - - // potential optimization, skip this if propertyIndex is already an integer, and convert the integer string to a true integer. - - // support resolving morphTarget names into indices. - if ( ! targetObject.geometry ) { - - console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.', this ); - return; - - } - - if ( ! targetObject.geometry.morphAttributes ) { - - console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.morphAttributes.', this ); - return; - - } - - if ( targetObject.morphTargetDictionary[ propertyIndex ] !== undefined ) { - - propertyIndex = targetObject.morphTargetDictionary[ propertyIndex ]; - - } - - } - - bindingType = this.BindingType.ArrayElement; - - this.resolvedProperty = nodeProperty; - this.propertyIndex = propertyIndex; - - } else if ( nodeProperty.fromArray !== undefined && nodeProperty.toArray !== undefined ) { - - // must use copy for Object3D.Euler/Quaternion - - bindingType = this.BindingType.HasFromToArray; - - this.resolvedProperty = nodeProperty; - - } else if ( Array.isArray( nodeProperty ) ) { - - bindingType = this.BindingType.EntireArray; - - this.resolvedProperty = nodeProperty; - - } else { - - this.propertyName = propertyName; - - } - - // select getter / setter - this.getValue = this.GetterByBindingType[ bindingType ]; - this.setValue = this.SetterByBindingTypeAndVersioning[ bindingType ][ versioning ]; - - } - - unbind() { - - this.node = null; - - // back to the prototype version of getValue / setValue - // note: avoiding to mutate the shape of 'this' via 'delete' - this.getValue = this._getValue_unbound; - this.setValue = this._setValue_unbound; - - } - -} - -PropertyBinding.Composite = Composite; - -PropertyBinding.prototype.BindingType = { - Direct: 0, - EntireArray: 1, - ArrayElement: 2, - HasFromToArray: 3 -}; - -PropertyBinding.prototype.Versioning = { - None: 0, - NeedsUpdate: 1, - MatrixWorldNeedsUpdate: 2 -}; - -PropertyBinding.prototype.GetterByBindingType = [ - - PropertyBinding.prototype._getValue_direct, - PropertyBinding.prototype._getValue_array, - PropertyBinding.prototype._getValue_arrayElement, - PropertyBinding.prototype._getValue_toArray, - -]; - -PropertyBinding.prototype.SetterByBindingTypeAndVersioning = [ - - [ - // Direct - PropertyBinding.prototype._setValue_direct, - PropertyBinding.prototype._setValue_direct_setNeedsUpdate, - PropertyBinding.prototype._setValue_direct_setMatrixWorldNeedsUpdate, - - ], [ - - // EntireArray - - PropertyBinding.prototype._setValue_array, - PropertyBinding.prototype._setValue_array_setNeedsUpdate, - PropertyBinding.prototype._setValue_array_setMatrixWorldNeedsUpdate, - - ], [ - - // ArrayElement - PropertyBinding.prototype._setValue_arrayElement, - PropertyBinding.prototype._setValue_arrayElement_setNeedsUpdate, - PropertyBinding.prototype._setValue_arrayElement_setMatrixWorldNeedsUpdate, - - ], [ - - // HasToFromArray - PropertyBinding.prototype._setValue_fromArray, - PropertyBinding.prototype._setValue_fromArray_setNeedsUpdate, - PropertyBinding.prototype._setValue_fromArray_setMatrixWorldNeedsUpdate, - - ] - -]; - -/** - * - * A group of objects that receives a shared animation state. - * - * Usage: - * - * - Add objects you would otherwise pass as 'root' to the - * constructor or the .clipAction method of AnimationMixer. - * - * - Instead pass this object as 'root'. - * - * - You can also add and remove objects later when the mixer - * is running. - * - * Note: - * - * Objects of this class appear as one object to the mixer, - * so cache control of the individual objects must be done - * on the group. - * - * Limitation: - * - * - The animated properties must be compatible among the - * all objects in the group. - * - * - A single property can either be controlled through a - * target group or directly, but not both. - */ - -class AnimationObjectGroup { - - constructor() { - - this.isAnimationObjectGroup = true; - - this.uuid = generateUUID(); - - // cached objects followed by the active ones - this._objects = Array.prototype.slice.call( arguments ); - - this.nCachedObjects_ = 0; // threshold - // note: read by PropertyBinding.Composite - - const indices = {}; - this._indicesByUUID = indices; // for bookkeeping - - for ( let i = 0, n = arguments.length; i !== n; ++ i ) { - - indices[ arguments[ i ].uuid ] = i; - - } - - this._paths = []; // inside: string - this._parsedPaths = []; // inside: { we don't care, here } - this._bindings = []; // inside: Array< PropertyBinding > - this._bindingsIndicesByPath = {}; // inside: indices in these arrays - - const scope = this; - - this.stats = { - - objects: { - get total() { - - return scope._objects.length; - - }, - get inUse() { - - return this.total - scope.nCachedObjects_; - - } - }, - get bindingsPerObject() { - - return scope._bindings.length; - - } - - }; - - } - - add() { - - const objects = this._objects, - indicesByUUID = this._indicesByUUID, - paths = this._paths, - parsedPaths = this._parsedPaths, - bindings = this._bindings, - nBindings = bindings.length; - - let knownObject = undefined, - nObjects = objects.length, - nCachedObjects = this.nCachedObjects_; - - for ( let i = 0, n = arguments.length; i !== n; ++ i ) { - - const object = arguments[ i ], - uuid = object.uuid; - let index = indicesByUUID[ uuid ]; - - if ( index === undefined ) { - - // unknown object -> add it to the ACTIVE region - - index = nObjects ++; - indicesByUUID[ uuid ] = index; - objects.push( object ); - - // accounting is done, now do the same for all bindings - - for ( let j = 0, m = nBindings; j !== m; ++ j ) { - - bindings[ j ].push( new PropertyBinding( object, paths[ j ], parsedPaths[ j ] ) ); - - } - - } else if ( index < nCachedObjects ) { - - knownObject = objects[ index ]; - - // move existing object to the ACTIVE region - - const firstActiveIndex = -- nCachedObjects, - lastCachedObject = objects[ firstActiveIndex ]; - - indicesByUUID[ lastCachedObject.uuid ] = index; - objects[ index ] = lastCachedObject; - - indicesByUUID[ uuid ] = firstActiveIndex; - objects[ firstActiveIndex ] = object; - - // accounting is done, now do the same for all bindings - - for ( let j = 0, m = nBindings; j !== m; ++ j ) { - - const bindingsForPath = bindings[ j ], - lastCached = bindingsForPath[ firstActiveIndex ]; - - let binding = bindingsForPath[ index ]; - - bindingsForPath[ index ] = lastCached; - - if ( binding === undefined ) { - - // since we do not bother to create new bindings - // for objects that are cached, the binding may - // or may not exist - - binding = new PropertyBinding( object, paths[ j ], parsedPaths[ j ] ); - - } - - bindingsForPath[ firstActiveIndex ] = binding; - - } - - } else if ( objects[ index ] !== knownObject ) { - - console.error( 'THREE.AnimationObjectGroup: Different objects with the same UUID ' + - 'detected. Clean the caches or recreate your infrastructure when reloading scenes.' ); - - } // else the object is already where we want it to be - - } // for arguments - - this.nCachedObjects_ = nCachedObjects; - - } - - remove() { - - const objects = this._objects, - indicesByUUID = this._indicesByUUID, - bindings = this._bindings, - nBindings = bindings.length; - - let nCachedObjects = this.nCachedObjects_; - - for ( let i = 0, n = arguments.length; i !== n; ++ i ) { - - const object = arguments[ i ], - uuid = object.uuid, - index = indicesByUUID[ uuid ]; - - if ( index !== undefined && index >= nCachedObjects ) { - - // move existing object into the CACHED region - - const lastCachedIndex = nCachedObjects ++, - firstActiveObject = objects[ lastCachedIndex ]; - - indicesByUUID[ firstActiveObject.uuid ] = index; - objects[ index ] = firstActiveObject; - - indicesByUUID[ uuid ] = lastCachedIndex; - objects[ lastCachedIndex ] = object; - - // accounting is done, now do the same for all bindings - - for ( let j = 0, m = nBindings; j !== m; ++ j ) { - - const bindingsForPath = bindings[ j ], - firstActive = bindingsForPath[ lastCachedIndex ], - binding = bindingsForPath[ index ]; - - bindingsForPath[ index ] = firstActive; - bindingsForPath[ lastCachedIndex ] = binding; - - } - - } - - } // for arguments - - this.nCachedObjects_ = nCachedObjects; - - } - - // remove & forget - uncache() { - - const objects = this._objects, - indicesByUUID = this._indicesByUUID, - bindings = this._bindings, - nBindings = bindings.length; - - let nCachedObjects = this.nCachedObjects_, - nObjects = objects.length; - - for ( let i = 0, n = arguments.length; i !== n; ++ i ) { - - const object = arguments[ i ], - uuid = object.uuid, - index = indicesByUUID[ uuid ]; - - if ( index !== undefined ) { - - delete indicesByUUID[ uuid ]; - - if ( index < nCachedObjects ) { - - // object is cached, shrink the CACHED region - - const firstActiveIndex = -- nCachedObjects, - lastCachedObject = objects[ firstActiveIndex ], - lastIndex = -- nObjects, - lastObject = objects[ lastIndex ]; - - // last cached object takes this object's place - indicesByUUID[ lastCachedObject.uuid ] = index; - objects[ index ] = lastCachedObject; - - // last object goes to the activated slot and pop - indicesByUUID[ lastObject.uuid ] = firstActiveIndex; - objects[ firstActiveIndex ] = lastObject; - objects.pop(); - - // accounting is done, now do the same for all bindings - - for ( let j = 0, m = nBindings; j !== m; ++ j ) { - - const bindingsForPath = bindings[ j ], - lastCached = bindingsForPath[ firstActiveIndex ], - last = bindingsForPath[ lastIndex ]; - - bindingsForPath[ index ] = lastCached; - bindingsForPath[ firstActiveIndex ] = last; - bindingsForPath.pop(); - - } - - } else { - - // object is active, just swap with the last and pop - - const lastIndex = -- nObjects, - lastObject = objects[ lastIndex ]; - - if ( lastIndex > 0 ) { - - indicesByUUID[ lastObject.uuid ] = index; - - } - - objects[ index ] = lastObject; - objects.pop(); - - // accounting is done, now do the same for all bindings - - for ( let j = 0, m = nBindings; j !== m; ++ j ) { - - const bindingsForPath = bindings[ j ]; - - bindingsForPath[ index ] = bindingsForPath[ lastIndex ]; - bindingsForPath.pop(); - - } - - } // cached or active - - } // if object is known - - } // for arguments - - this.nCachedObjects_ = nCachedObjects; - - } - - // Internal interface used by befriended PropertyBinding.Composite: - - subscribe_( path, parsedPath ) { - - // returns an array of bindings for the given path that is changed - // according to the contained objects in the group - - const indicesByPath = this._bindingsIndicesByPath; - let index = indicesByPath[ path ]; - const bindings = this._bindings; - - if ( index !== undefined ) return bindings[ index ]; - - const paths = this._paths, - parsedPaths = this._parsedPaths, - objects = this._objects, - nObjects = objects.length, - nCachedObjects = this.nCachedObjects_, - bindingsForPath = new Array( nObjects ); - - index = bindings.length; - - indicesByPath[ path ] = index; - - paths.push( path ); - parsedPaths.push( parsedPath ); - bindings.push( bindingsForPath ); - - for ( let i = nCachedObjects, n = objects.length; i !== n; ++ i ) { - - const object = objects[ i ]; - bindingsForPath[ i ] = new PropertyBinding( object, path, parsedPath ); - - } - - return bindingsForPath; - - } - - unsubscribe_( path ) { - - // tells the group to forget about a property path and no longer - // update the array previously obtained with 'subscribe_' - - const indicesByPath = this._bindingsIndicesByPath, - index = indicesByPath[ path ]; - - if ( index !== undefined ) { - - const paths = this._paths, - parsedPaths = this._parsedPaths, - bindings = this._bindings, - lastBindingsIndex = bindings.length - 1, - lastBindings = bindings[ lastBindingsIndex ], - lastBindingsPath = path[ lastBindingsIndex ]; - - indicesByPath[ lastBindingsPath ] = index; - - bindings[ index ] = lastBindings; - bindings.pop(); - - parsedPaths[ index ] = parsedPaths[ lastBindingsIndex ]; - parsedPaths.pop(); - - paths[ index ] = paths[ lastBindingsIndex ]; - paths.pop(); - - } - - } - -} - -class AnimationAction { - - constructor( mixer, clip, localRoot = null, blendMode = clip.blendMode ) { - - this._mixer = mixer; - this._clip = clip; - this._localRoot = localRoot; - this.blendMode = blendMode; - - const tracks = clip.tracks, - nTracks = tracks.length, - interpolants = new Array( nTracks ); - - const interpolantSettings = { - endingStart: ZeroCurvatureEnding, - endingEnd: ZeroCurvatureEnding - }; - - for ( let i = 0; i !== nTracks; ++ i ) { - - const interpolant = tracks[ i ].createInterpolant( null ); - interpolants[ i ] = interpolant; - interpolant.settings = interpolantSettings; - - } - - this._interpolantSettings = interpolantSettings; - - this._interpolants = interpolants; // bound by the mixer - - // inside: PropertyMixer (managed by the mixer) - this._propertyBindings = new Array( nTracks ); - - this._cacheIndex = null; // for the memory manager - this._byClipCacheIndex = null; // for the memory manager - - this._timeScaleInterpolant = null; - this._weightInterpolant = null; - - this.loop = LoopRepeat; - this._loopCount = - 1; - - // global mixer time when the action is to be started - // it's set back to 'null' upon start of the action - this._startTime = null; - - // scaled local time of the action - // gets clamped or wrapped to 0..clip.duration according to loop - this.time = 0; - - this.timeScale = 1; - this._effectiveTimeScale = 1; - - this.weight = 1; - this._effectiveWeight = 1; - - this.repetitions = Infinity; // no. of repetitions when looping - - this.paused = false; // true -> zero effective time scale - this.enabled = true; // false -> zero effective weight - - this.clampWhenFinished = false;// keep feeding the last frame? - - this.zeroSlopeAtStart = true;// for smooth interpolation w/o separate - this.zeroSlopeAtEnd = true;// clips for start, loop and end - - } - - // State & Scheduling - - play() { - - this._mixer._activateAction( this ); - - return this; - - } - - stop() { - - this._mixer._deactivateAction( this ); - - return this.reset(); - - } - - reset() { - - this.paused = false; - this.enabled = true; - - this.time = 0; // restart clip - this._loopCount = - 1;// forget previous loops - this._startTime = null;// forget scheduling - - return this.stopFading().stopWarping(); - - } - - isRunning() { - - return this.enabled && ! this.paused && this.timeScale !== 0 && - this._startTime === null && this._mixer._isActiveAction( this ); - - } - - // return true when play has been called - isScheduled() { - - return this._mixer._isActiveAction( this ); - - } - - startAt( time ) { - - this._startTime = time; - - return this; - - } - - setLoop( mode, repetitions ) { - - this.loop = mode; - this.repetitions = repetitions; - - return this; - - } - - // Weight - - // set the weight stopping any scheduled fading - // although .enabled = false yields an effective weight of zero, this - // method does *not* change .enabled, because it would be confusing - setEffectiveWeight( weight ) { - - this.weight = weight; - - // note: same logic as when updated at runtime - this._effectiveWeight = this.enabled ? weight : 0; - - return this.stopFading(); - - } - - // return the weight considering fading and .enabled - getEffectiveWeight() { - - return this._effectiveWeight; - - } - - fadeIn( duration ) { - - return this._scheduleFading( duration, 0, 1 ); - - } - - fadeOut( duration ) { - - return this._scheduleFading( duration, 1, 0 ); - - } - - crossFadeFrom( fadeOutAction, duration, warp ) { - - fadeOutAction.fadeOut( duration ); - this.fadeIn( duration ); - - if ( warp ) { - - const fadeInDuration = this._clip.duration, - fadeOutDuration = fadeOutAction._clip.duration, - - startEndRatio = fadeOutDuration / fadeInDuration, - endStartRatio = fadeInDuration / fadeOutDuration; - - fadeOutAction.warp( 1.0, startEndRatio, duration ); - this.warp( endStartRatio, 1.0, duration ); - - } - - return this; - - } - - crossFadeTo( fadeInAction, duration, warp ) { - - return fadeInAction.crossFadeFrom( this, duration, warp ); - - } - - stopFading() { - - const weightInterpolant = this._weightInterpolant; - - if ( weightInterpolant !== null ) { - - this._weightInterpolant = null; - this._mixer._takeBackControlInterpolant( weightInterpolant ); - - } - - return this; - - } - - // Time Scale Control - - // set the time scale stopping any scheduled warping - // although .paused = true yields an effective time scale of zero, this - // method does *not* change .paused, because it would be confusing - setEffectiveTimeScale( timeScale ) { - - this.timeScale = timeScale; - this._effectiveTimeScale = this.paused ? 0 : timeScale; - - return this.stopWarping(); - - } - - // return the time scale considering warping and .paused - getEffectiveTimeScale() { - - return this._effectiveTimeScale; - - } - - setDuration( duration ) { - - this.timeScale = this._clip.duration / duration; - - return this.stopWarping(); - - } - - syncWith( action ) { - - this.time = action.time; - this.timeScale = action.timeScale; - - return this.stopWarping(); - - } - - halt( duration ) { - - return this.warp( this._effectiveTimeScale, 0, duration ); - - } - - warp( startTimeScale, endTimeScale, duration ) { - - const mixer = this._mixer, - now = mixer.time, - timeScale = this.timeScale; - - let interpolant = this._timeScaleInterpolant; - - if ( interpolant === null ) { - - interpolant = mixer._lendControlInterpolant(); - this._timeScaleInterpolant = interpolant; - - } - - const times = interpolant.parameterPositions, - values = interpolant.sampleValues; - - times[ 0 ] = now; - times[ 1 ] = now + duration; - - values[ 0 ] = startTimeScale / timeScale; - values[ 1 ] = endTimeScale / timeScale; - - return this; - - } - - stopWarping() { - - const timeScaleInterpolant = this._timeScaleInterpolant; - - if ( timeScaleInterpolant !== null ) { - - this._timeScaleInterpolant = null; - this._mixer._takeBackControlInterpolant( timeScaleInterpolant ); - - } - - return this; - - } - - // Object Accessors - - getMixer() { - - return this._mixer; - - } - - getClip() { - - return this._clip; - - } - - getRoot() { - - return this._localRoot || this._mixer._root; - - } - - // Interna - - _update( time, deltaTime, timeDirection, accuIndex ) { - - // called by the mixer - - if ( ! this.enabled ) { - - // call ._updateWeight() to update ._effectiveWeight - - this._updateWeight( time ); - return; - - } - - const startTime = this._startTime; - - if ( startTime !== null ) { - - // check for scheduled start of action - - const timeRunning = ( time - startTime ) * timeDirection; - if ( timeRunning < 0 || timeDirection === 0 ) { - - deltaTime = 0; - - } else { - - - this._startTime = null; // unschedule - deltaTime = timeDirection * timeRunning; - - } - - } - - // apply time scale and advance time - - deltaTime *= this._updateTimeScale( time ); - const clipTime = this._updateTime( deltaTime ); - - // note: _updateTime may disable the action resulting in - // an effective weight of 0 - - const weight = this._updateWeight( time ); - - if ( weight > 0 ) { - - const interpolants = this._interpolants; - const propertyMixers = this._propertyBindings; - - switch ( this.blendMode ) { - - case AdditiveAnimationBlendMode: - - for ( let j = 0, m = interpolants.length; j !== m; ++ j ) { - - interpolants[ j ].evaluate( clipTime ); - propertyMixers[ j ].accumulateAdditive( weight ); - - } - - break; - - case NormalAnimationBlendMode: - default: - - for ( let j = 0, m = interpolants.length; j !== m; ++ j ) { - - interpolants[ j ].evaluate( clipTime ); - propertyMixers[ j ].accumulate( accuIndex, weight ); - - } - - } - - } - - } - - _updateWeight( time ) { - - let weight = 0; - - if ( this.enabled ) { - - weight = this.weight; - const interpolant = this._weightInterpolant; - - if ( interpolant !== null ) { - - const interpolantValue = interpolant.evaluate( time )[ 0 ]; - - weight *= interpolantValue; - - if ( time > interpolant.parameterPositions[ 1 ] ) { - - this.stopFading(); - - if ( interpolantValue === 0 ) { - - // faded out, disable - this.enabled = false; - - } - - } - - } - - } - - this._effectiveWeight = weight; - return weight; - - } - - _updateTimeScale( time ) { - - let timeScale = 0; - - if ( ! this.paused ) { - - timeScale = this.timeScale; - - const interpolant = this._timeScaleInterpolant; - - if ( interpolant !== null ) { - - const interpolantValue = interpolant.evaluate( time )[ 0 ]; - - timeScale *= interpolantValue; - - if ( time > interpolant.parameterPositions[ 1 ] ) { - - this.stopWarping(); - - if ( timeScale === 0 ) { - - // motion has halted, pause - this.paused = true; - - } else { - - // warp done - apply final time scale - this.timeScale = timeScale; - - } - - } - - } - - } - - this._effectiveTimeScale = timeScale; - return timeScale; - - } - - _updateTime( deltaTime ) { - - const duration = this._clip.duration; - const loop = this.loop; - - let time = this.time + deltaTime; - let loopCount = this._loopCount; - - const pingPong = ( loop === LoopPingPong ); - - if ( deltaTime === 0 ) { - - if ( loopCount === - 1 ) return time; - - return ( pingPong && ( loopCount & 1 ) === 1 ) ? duration - time : time; - - } - - if ( loop === LoopOnce ) { - - if ( loopCount === - 1 ) { - - // just started - - this._loopCount = 0; - this._setEndings( true, true, false ); - - } - - handle_stop: { - - if ( time >= duration ) { - - time = duration; - - } else if ( time < 0 ) { - - time = 0; - - } else { - - this.time = time; - - break handle_stop; - - } - - if ( this.clampWhenFinished ) this.paused = true; - else this.enabled = false; - - this.time = time; - - this._mixer.dispatchEvent( { - type: 'finished', action: this, - direction: deltaTime < 0 ? - 1 : 1 - } ); - - } - - } else { // repetitive Repeat or PingPong - - if ( loopCount === - 1 ) { - - // just started - - if ( deltaTime >= 0 ) { - - loopCount = 0; - - this._setEndings( true, this.repetitions === 0, pingPong ); - - } else { - - // when looping in reverse direction, the initial - // transition through zero counts as a repetition, - // so leave loopCount at -1 - - this._setEndings( this.repetitions === 0, true, pingPong ); - - } - - } - - if ( time >= duration || time < 0 ) { - - // wrap around - - const loopDelta = Math.floor( time / duration ); // signed - time -= duration * loopDelta; - - loopCount += Math.abs( loopDelta ); - - const pending = this.repetitions - loopCount; - - if ( pending <= 0 ) { - - // have to stop (switch state, clamp time, fire event) - - if ( this.clampWhenFinished ) this.paused = true; - else this.enabled = false; - - time = deltaTime > 0 ? duration : 0; - - this.time = time; - - this._mixer.dispatchEvent( { - type: 'finished', action: this, - direction: deltaTime > 0 ? 1 : - 1 - } ); - - } else { - - // keep running - - if ( pending === 1 ) { - - // entering the last round - - const atStart = deltaTime < 0; - this._setEndings( atStart, ! atStart, pingPong ); - - } else { - - this._setEndings( false, false, pingPong ); - - } - - this._loopCount = loopCount; - - this.time = time; - - this._mixer.dispatchEvent( { - type: 'loop', action: this, loopDelta: loopDelta - } ); - - } - - } else { - - this.time = time; - - } - - if ( pingPong && ( loopCount & 1 ) === 1 ) { - - // invert time for the "pong round" - - return duration - time; - - } - - } - - return time; - - } - - _setEndings( atStart, atEnd, pingPong ) { - - const settings = this._interpolantSettings; - - if ( pingPong ) { - - settings.endingStart = ZeroSlopeEnding; - settings.endingEnd = ZeroSlopeEnding; - - } else { - - // assuming for LoopOnce atStart == atEnd == true - - if ( atStart ) { - - settings.endingStart = this.zeroSlopeAtStart ? ZeroSlopeEnding : ZeroCurvatureEnding; - - } else { - - settings.endingStart = WrapAroundEnding; - - } - - if ( atEnd ) { - - settings.endingEnd = this.zeroSlopeAtEnd ? ZeroSlopeEnding : ZeroCurvatureEnding; - - } else { - - settings.endingEnd = WrapAroundEnding; - - } - - } - - } - - _scheduleFading( duration, weightNow, weightThen ) { - - const mixer = this._mixer, now = mixer.time; - let interpolant = this._weightInterpolant; - - if ( interpolant === null ) { - - interpolant = mixer._lendControlInterpolant(); - this._weightInterpolant = interpolant; - - } - - const times = interpolant.parameterPositions, - values = interpolant.sampleValues; - - times[ 0 ] = now; - values[ 0 ] = weightNow; - times[ 1 ] = now + duration; - values[ 1 ] = weightThen; - - return this; - - } - -} - -const _controlInterpolantsResultBuffer = new Float32Array( 1 ); - - -class AnimationMixer extends EventDispatcher { - - constructor( root ) { - - super(); - - this._root = root; - this._initMemoryManager(); - this._accuIndex = 0; - this.time = 0; - this.timeScale = 1.0; - - } - - _bindAction( action, prototypeAction ) { - - const root = action._localRoot || this._root, - tracks = action._clip.tracks, - nTracks = tracks.length, - bindings = action._propertyBindings, - interpolants = action._interpolants, - rootUuid = root.uuid, - bindingsByRoot = this._bindingsByRootAndName; - - let bindingsByName = bindingsByRoot[ rootUuid ]; - - if ( bindingsByName === undefined ) { - - bindingsByName = {}; - bindingsByRoot[ rootUuid ] = bindingsByName; - - } - - for ( let i = 0; i !== nTracks; ++ i ) { - - const track = tracks[ i ], - trackName = track.name; - - let binding = bindingsByName[ trackName ]; - - if ( binding !== undefined ) { - - ++ binding.referenceCount; - bindings[ i ] = binding; - - } else { - - binding = bindings[ i ]; - - if ( binding !== undefined ) { - - // existing binding, make sure the cache knows - - if ( binding._cacheIndex === null ) { - - ++ binding.referenceCount; - this._addInactiveBinding( binding, rootUuid, trackName ); - - } - - continue; - - } - - const path = prototypeAction && prototypeAction. - _propertyBindings[ i ].binding.parsedPath; - - binding = new PropertyMixer( - PropertyBinding.create( root, trackName, path ), - track.ValueTypeName, track.getValueSize() ); - - ++ binding.referenceCount; - this._addInactiveBinding( binding, rootUuid, trackName ); - - bindings[ i ] = binding; - - } - - interpolants[ i ].resultBuffer = binding.buffer; - - } - - } - - _activateAction( action ) { - - if ( ! this._isActiveAction( action ) ) { - - if ( action._cacheIndex === null ) { - - // this action has been forgotten by the cache, but the user - // appears to be still using it -> rebind - - const rootUuid = ( action._localRoot || this._root ).uuid, - clipUuid = action._clip.uuid, - actionsForClip = this._actionsByClip[ clipUuid ]; - - this._bindAction( action, - actionsForClip && actionsForClip.knownActions[ 0 ] ); - - this._addInactiveAction( action, clipUuid, rootUuid ); - - } - - const bindings = action._propertyBindings; - - // increment reference counts / sort out state - for ( let i = 0, n = bindings.length; i !== n; ++ i ) { - - const binding = bindings[ i ]; - - if ( binding.useCount ++ === 0 ) { - - this._lendBinding( binding ); - binding.saveOriginalState(); - - } - - } - - this._lendAction( action ); - - } - - } - - _deactivateAction( action ) { - - if ( this._isActiveAction( action ) ) { - - const bindings = action._propertyBindings; - - // decrement reference counts / sort out state - for ( let i = 0, n = bindings.length; i !== n; ++ i ) { - - const binding = bindings[ i ]; - - if ( -- binding.useCount === 0 ) { - - binding.restoreOriginalState(); - this._takeBackBinding( binding ); - - } - - } - - this._takeBackAction( action ); - - } - - } - - // Memory manager - - _initMemoryManager() { - - this._actions = []; // 'nActiveActions' followed by inactive ones - this._nActiveActions = 0; - - this._actionsByClip = {}; - // inside: - // { - // knownActions: Array< AnimationAction > - used as prototypes - // actionByRoot: AnimationAction - lookup - // } - - - this._bindings = []; // 'nActiveBindings' followed by inactive ones - this._nActiveBindings = 0; - - this._bindingsByRootAndName = {}; // inside: Map< name, PropertyMixer > - - - this._controlInterpolants = []; // same game as above - this._nActiveControlInterpolants = 0; - - const scope = this; - - this.stats = { - - actions: { - get total() { - - return scope._actions.length; - - }, - get inUse() { - - return scope._nActiveActions; - - } - }, - bindings: { - get total() { - - return scope._bindings.length; - - }, - get inUse() { - - return scope._nActiveBindings; - - } - }, - controlInterpolants: { - get total() { - - return scope._controlInterpolants.length; - - }, - get inUse() { - - return scope._nActiveControlInterpolants; - - } - } - - }; - - } - - // Memory management for AnimationAction objects - - _isActiveAction( action ) { - - const index = action._cacheIndex; - return index !== null && index < this._nActiveActions; - - } - - _addInactiveAction( action, clipUuid, rootUuid ) { - - const actions = this._actions, - actionsByClip = this._actionsByClip; - - let actionsForClip = actionsByClip[ clipUuid ]; - - if ( actionsForClip === undefined ) { - - actionsForClip = { - - knownActions: [ action ], - actionByRoot: {} - - }; - - action._byClipCacheIndex = 0; - - actionsByClip[ clipUuid ] = actionsForClip; - - } else { - - const knownActions = actionsForClip.knownActions; - - action._byClipCacheIndex = knownActions.length; - knownActions.push( action ); - - } - - action._cacheIndex = actions.length; - actions.push( action ); - - actionsForClip.actionByRoot[ rootUuid ] = action; - - } - - _removeInactiveAction( action ) { - - const actions = this._actions, - lastInactiveAction = actions[ actions.length - 1 ], - cacheIndex = action._cacheIndex; - - lastInactiveAction._cacheIndex = cacheIndex; - actions[ cacheIndex ] = lastInactiveAction; - actions.pop(); - - action._cacheIndex = null; - - - const clipUuid = action._clip.uuid, - actionsByClip = this._actionsByClip, - actionsForClip = actionsByClip[ clipUuid ], - knownActionsForClip = actionsForClip.knownActions, - - lastKnownAction = - knownActionsForClip[ knownActionsForClip.length - 1 ], - - byClipCacheIndex = action._byClipCacheIndex; - - lastKnownAction._byClipCacheIndex = byClipCacheIndex; - knownActionsForClip[ byClipCacheIndex ] = lastKnownAction; - knownActionsForClip.pop(); - - action._byClipCacheIndex = null; - - - const actionByRoot = actionsForClip.actionByRoot, - rootUuid = ( action._localRoot || this._root ).uuid; - - delete actionByRoot[ rootUuid ]; - - if ( knownActionsForClip.length === 0 ) { - - delete actionsByClip[ clipUuid ]; - - } - - this._removeInactiveBindingsForAction( action ); - - } - - _removeInactiveBindingsForAction( action ) { - - const bindings = action._propertyBindings; - - for ( let i = 0, n = bindings.length; i !== n; ++ i ) { - - const binding = bindings[ i ]; - - if ( -- binding.referenceCount === 0 ) { - - this._removeInactiveBinding( binding ); - - } - - } - - } - - _lendAction( action ) { - - // [ active actions | inactive actions ] - // [ active actions >| inactive actions ] - // s a - // <-swap-> - // a s - - const actions = this._actions, - prevIndex = action._cacheIndex, - - lastActiveIndex = this._nActiveActions ++, - - firstInactiveAction = actions[ lastActiveIndex ]; - - action._cacheIndex = lastActiveIndex; - actions[ lastActiveIndex ] = action; - - firstInactiveAction._cacheIndex = prevIndex; - actions[ prevIndex ] = firstInactiveAction; - - } - - _takeBackAction( action ) { - - // [ active actions | inactive actions ] - // [ active actions |< inactive actions ] - // a s - // <-swap-> - // s a - - const actions = this._actions, - prevIndex = action._cacheIndex, - - firstInactiveIndex = -- this._nActiveActions, - - lastActiveAction = actions[ firstInactiveIndex ]; - - action._cacheIndex = firstInactiveIndex; - actions[ firstInactiveIndex ] = action; - - lastActiveAction._cacheIndex = prevIndex; - actions[ prevIndex ] = lastActiveAction; - - } - - // Memory management for PropertyMixer objects - - _addInactiveBinding( binding, rootUuid, trackName ) { - - const bindingsByRoot = this._bindingsByRootAndName, - bindings = this._bindings; - - let bindingByName = bindingsByRoot[ rootUuid ]; - - if ( bindingByName === undefined ) { - - bindingByName = {}; - bindingsByRoot[ rootUuid ] = bindingByName; - - } - - bindingByName[ trackName ] = binding; - - binding._cacheIndex = bindings.length; - bindings.push( binding ); - - } - - _removeInactiveBinding( binding ) { - - const bindings = this._bindings, - propBinding = binding.binding, - rootUuid = propBinding.rootNode.uuid, - trackName = propBinding.path, - bindingsByRoot = this._bindingsByRootAndName, - bindingByName = bindingsByRoot[ rootUuid ], - - lastInactiveBinding = bindings[ bindings.length - 1 ], - cacheIndex = binding._cacheIndex; - - lastInactiveBinding._cacheIndex = cacheIndex; - bindings[ cacheIndex ] = lastInactiveBinding; - bindings.pop(); - - delete bindingByName[ trackName ]; - - if ( Object.keys( bindingByName ).length === 0 ) { - - delete bindingsByRoot[ rootUuid ]; - - } - - } - - _lendBinding( binding ) { - - const bindings = this._bindings, - prevIndex = binding._cacheIndex, - - lastActiveIndex = this._nActiveBindings ++, - - firstInactiveBinding = bindings[ lastActiveIndex ]; - - binding._cacheIndex = lastActiveIndex; - bindings[ lastActiveIndex ] = binding; - - firstInactiveBinding._cacheIndex = prevIndex; - bindings[ prevIndex ] = firstInactiveBinding; - - } - - _takeBackBinding( binding ) { - - const bindings = this._bindings, - prevIndex = binding._cacheIndex, - - firstInactiveIndex = -- this._nActiveBindings, - - lastActiveBinding = bindings[ firstInactiveIndex ]; - - binding._cacheIndex = firstInactiveIndex; - bindings[ firstInactiveIndex ] = binding; - - lastActiveBinding._cacheIndex = prevIndex; - bindings[ prevIndex ] = lastActiveBinding; - - } - - - // Memory management of Interpolants for weight and time scale - - _lendControlInterpolant() { - - const interpolants = this._controlInterpolants, - lastActiveIndex = this._nActiveControlInterpolants ++; - - let interpolant = interpolants[ lastActiveIndex ]; - - if ( interpolant === undefined ) { - - interpolant = new LinearInterpolant( - new Float32Array( 2 ), new Float32Array( 2 ), - 1, _controlInterpolantsResultBuffer ); - - interpolant.__cacheIndex = lastActiveIndex; - interpolants[ lastActiveIndex ] = interpolant; - - } - - return interpolant; - - } - - _takeBackControlInterpolant( interpolant ) { - - const interpolants = this._controlInterpolants, - prevIndex = interpolant.__cacheIndex, - - firstInactiveIndex = -- this._nActiveControlInterpolants, - - lastActiveInterpolant = interpolants[ firstInactiveIndex ]; - - interpolant.__cacheIndex = firstInactiveIndex; - interpolants[ firstInactiveIndex ] = interpolant; - - lastActiveInterpolant.__cacheIndex = prevIndex; - interpolants[ prevIndex ] = lastActiveInterpolant; - - } - - // return an action for a clip optionally using a custom root target - // object (this method allocates a lot of dynamic memory in case a - // previously unknown clip/root combination is specified) - clipAction( clip, optionalRoot, blendMode ) { - - const root = optionalRoot || this._root, - rootUuid = root.uuid; - - let clipObject = typeof clip === 'string' ? AnimationClip.findByName( root, clip ) : clip; - - const clipUuid = clipObject !== null ? clipObject.uuid : clip; - - const actionsForClip = this._actionsByClip[ clipUuid ]; - let prototypeAction = null; - - if ( blendMode === undefined ) { - - if ( clipObject !== null ) { - - blendMode = clipObject.blendMode; - - } else { - - blendMode = NormalAnimationBlendMode; - - } - - } - - if ( actionsForClip !== undefined ) { - - const existingAction = actionsForClip.actionByRoot[ rootUuid ]; - - if ( existingAction !== undefined && existingAction.blendMode === blendMode ) { - - return existingAction; - - } - - // we know the clip, so we don't have to parse all - // the bindings again but can just copy - prototypeAction = actionsForClip.knownActions[ 0 ]; - - // also, take the clip from the prototype action - if ( clipObject === null ) - clipObject = prototypeAction._clip; - - } - - // clip must be known when specified via string - if ( clipObject === null ) return null; - - // allocate all resources required to run it - const newAction = new AnimationAction( this, clipObject, optionalRoot, blendMode ); - - this._bindAction( newAction, prototypeAction ); - - // and make the action known to the memory manager - this._addInactiveAction( newAction, clipUuid, rootUuid ); - - return newAction; - - } - - // get an existing action - existingAction( clip, optionalRoot ) { - - const root = optionalRoot || this._root, - rootUuid = root.uuid, - - clipObject = typeof clip === 'string' ? - AnimationClip.findByName( root, clip ) : clip, - - clipUuid = clipObject ? clipObject.uuid : clip, - - actionsForClip = this._actionsByClip[ clipUuid ]; - - if ( actionsForClip !== undefined ) { - - return actionsForClip.actionByRoot[ rootUuid ] || null; - - } - - return null; - - } - - // deactivates all previously scheduled actions - stopAllAction() { - - const actions = this._actions, - nActions = this._nActiveActions; - - for ( let i = nActions - 1; i >= 0; -- i ) { - - actions[ i ].stop(); - - } - - return this; - - } - - // advance the time and update apply the animation - update( deltaTime ) { - - deltaTime *= this.timeScale; - - const actions = this._actions, - nActions = this._nActiveActions, - - time = this.time += deltaTime, - timeDirection = Math.sign( deltaTime ), - - accuIndex = this._accuIndex ^= 1; - - // run active actions - - for ( let i = 0; i !== nActions; ++ i ) { - - const action = actions[ i ]; - - action._update( time, deltaTime, timeDirection, accuIndex ); - - } - - // update scene graph - - const bindings = this._bindings, - nBindings = this._nActiveBindings; - - for ( let i = 0; i !== nBindings; ++ i ) { - - bindings[ i ].apply( accuIndex ); - - } - - return this; - - } - - // Allows you to seek to a specific time in an animation. - setTime( timeInSeconds ) { - - this.time = 0; // Zero out time attribute for AnimationMixer object; - for ( let i = 0; i < this._actions.length; i ++ ) { - - this._actions[ i ].time = 0; // Zero out time attribute for all associated AnimationAction objects. - - } - - return this.update( timeInSeconds ); // Update used to set exact time. Returns "this" AnimationMixer object. - - } - - // return this mixer's root target object - getRoot() { - - return this._root; - - } - - // free all resources specific to a particular clip - uncacheClip( clip ) { - - const actions = this._actions, - clipUuid = clip.uuid, - actionsByClip = this._actionsByClip, - actionsForClip = actionsByClip[ clipUuid ]; - - if ( actionsForClip !== undefined ) { - - // note: just calling _removeInactiveAction would mess up the - // iteration state and also require updating the state we can - // just throw away - - const actionsToRemove = actionsForClip.knownActions; - - for ( let i = 0, n = actionsToRemove.length; i !== n; ++ i ) { - - const action = actionsToRemove[ i ]; - - this._deactivateAction( action ); - - const cacheIndex = action._cacheIndex, - lastInactiveAction = actions[ actions.length - 1 ]; - - action._cacheIndex = null; - action._byClipCacheIndex = null; - - lastInactiveAction._cacheIndex = cacheIndex; - actions[ cacheIndex ] = lastInactiveAction; - actions.pop(); - - this._removeInactiveBindingsForAction( action ); - - } - - delete actionsByClip[ clipUuid ]; - - } - - } - - // free all resources specific to a particular root target object - uncacheRoot( root ) { - - const rootUuid = root.uuid, - actionsByClip = this._actionsByClip; - - for ( const clipUuid in actionsByClip ) { - - const actionByRoot = actionsByClip[ clipUuid ].actionByRoot, - action = actionByRoot[ rootUuid ]; - - if ( action !== undefined ) { - - this._deactivateAction( action ); - this._removeInactiveAction( action ); - - } - - } - - const bindingsByRoot = this._bindingsByRootAndName, - bindingByName = bindingsByRoot[ rootUuid ]; - - if ( bindingByName !== undefined ) { - - for ( const trackName in bindingByName ) { - - const binding = bindingByName[ trackName ]; - binding.restoreOriginalState(); - this._removeInactiveBinding( binding ); - - } - - } - - } - - // remove a targeted clip from the cache - uncacheAction( clip, optionalRoot ) { - - const action = this.existingAction( clip, optionalRoot ); - - if ( action !== null ) { - - this._deactivateAction( action ); - this._removeInactiveAction( action ); - - } - - } - -} - -class Uniform { - - constructor( value ) { - - this.value = value; - - } - - clone() { - - return new Uniform( this.value.clone === undefined ? this.value : this.value.clone() ); - - } - -} - -let _id = 0; - -class UniformsGroup extends EventDispatcher { - - constructor() { - - super(); - - this.isUniformsGroup = true; - - Object.defineProperty( this, 'id', { value: _id ++ } ); - - this.name = ''; - - this.usage = StaticDrawUsage; - this.uniforms = []; - - } - - add( uniform ) { - - this.uniforms.push( uniform ); - - return this; - - } - - remove( uniform ) { - - const index = this.uniforms.indexOf( uniform ); - - if ( index !== - 1 ) this.uniforms.splice( index, 1 ); - - return this; - - } - - setName( name ) { - - this.name = name; - - return this; - - } - - setUsage( value ) { - - this.usage = value; - - return this; - - } - - dispose() { - - this.dispatchEvent( { type: 'dispose' } ); - - return this; - - } - - copy( source ) { - - this.name = source.name; - this.usage = source.usage; - - const uniformsSource = source.uniforms; - - this.uniforms.length = 0; - - for ( let i = 0, l = uniformsSource.length; i < l; i ++ ) { - - const uniforms = Array.isArray( uniformsSource[ i ] ) ? uniformsSource[ i ] : [ uniformsSource[ i ] ]; - - for ( let j = 0; j < uniforms.length; j ++ ) { - - this.uniforms.push( uniforms[ j ].clone() ); - - } - - } - - return this; - - } - - clone() { - - return new this.constructor().copy( this ); - - } - -} - -class InstancedInterleavedBuffer extends InterleavedBuffer { - - constructor( array, stride, meshPerAttribute = 1 ) { - - super( array, stride ); - - this.isInstancedInterleavedBuffer = true; - - this.meshPerAttribute = meshPerAttribute; - - } - - copy( source ) { - - super.copy( source ); - - this.meshPerAttribute = source.meshPerAttribute; - - return this; - - } - - clone( data ) { - - const ib = super.clone( data ); - - ib.meshPerAttribute = this.meshPerAttribute; - - return ib; - - } - - toJSON( data ) { - - const json = super.toJSON( data ); - - json.isInstancedInterleavedBuffer = true; - json.meshPerAttribute = this.meshPerAttribute; - - return json; - - } - -} - -class GLBufferAttribute { - - constructor( buffer, type, itemSize, elementSize, count ) { - - this.isGLBufferAttribute = true; - - this.name = ''; - - this.buffer = buffer; - this.type = type; - this.itemSize = itemSize; - this.elementSize = elementSize; - this.count = count; - - this.version = 0; - - } - - set needsUpdate( value ) { - - if ( value === true ) this.version ++; - - } - - setBuffer( buffer ) { - - this.buffer = buffer; - - return this; - - } - - setType( type, elementSize ) { - - this.type = type; - this.elementSize = elementSize; - - return this; - - } - - setItemSize( itemSize ) { - - this.itemSize = itemSize; - - return this; - - } - - setCount( count ) { - - this.count = count; - - return this; - - } - -} - -class Raycaster { - - constructor( origin, direction, near = 0, far = Infinity ) { - - this.ray = new Ray( origin, direction ); - // direction is assumed to be normalized (for accurate distance calculations) - - this.near = near; - this.far = far; - this.camera = null; - this.layers = new Layers(); - - this.params = { - Mesh: {}, - Line: { threshold: 1 }, - LOD: {}, - Points: { threshold: 1 }, - Sprite: {} - }; - - } - - set( origin, direction ) { - - // direction is assumed to be normalized (for accurate distance calculations) - - this.ray.set( origin, direction ); - - } - - setFromCamera( coords, camera ) { - - if ( camera.isPerspectiveCamera ) { - - this.ray.origin.setFromMatrixPosition( camera.matrixWorld ); - this.ray.direction.set( coords.x, coords.y, 0.5 ).unproject( camera ).sub( this.ray.origin ).normalize(); - this.camera = camera; - - } else if ( camera.isOrthographicCamera ) { - - this.ray.origin.set( coords.x, coords.y, ( camera.near + camera.far ) / ( camera.near - camera.far ) ).unproject( camera ); // set origin in plane of camera - this.ray.direction.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld ); - this.camera = camera; - - } else { - - console.error( 'THREE.Raycaster: Unsupported camera type: ' + camera.type ); - - } - - } - - intersectObject( object, recursive = true, intersects = [] ) { - - intersectObject( object, this, intersects, recursive ); - - intersects.sort( ascSort ); - - return intersects; - - } - - intersectObjects( objects, recursive = true, intersects = [] ) { - - for ( let i = 0, l = objects.length; i < l; i ++ ) { - - intersectObject( objects[ i ], this, intersects, recursive ); - - } - - intersects.sort( ascSort ); - - return intersects; - - } - -} - -function ascSort( a, b ) { - - return a.distance - b.distance; - -} - -function intersectObject( object, raycaster, intersects, recursive ) { - - if ( object.layers.test( raycaster.layers ) ) { - - object.raycast( raycaster, intersects ); - - } - - if ( recursive === true ) { - - const children = object.children; - - for ( let i = 0, l = children.length; i < l; i ++ ) { - - intersectObject( children[ i ], raycaster, intersects, true ); - - } - - } - -} - -/** - * Ref: https://en.wikipedia.org/wiki/Spherical_coordinate_system - * - * The polar angle (phi) is measured from the positive y-axis. The positive y-axis is up. - * The azimuthal angle (theta) is measured from the positive z-axis. - */ - - -class Spherical { - - constructor( radius = 1, phi = 0, theta = 0 ) { - - this.radius = radius; - this.phi = phi; // polar angle - this.theta = theta; // azimuthal angle - - return this; - - } - - set( radius, phi, theta ) { - - this.radius = radius; - this.phi = phi; - this.theta = theta; - - return this; - - } - - copy( other ) { - - this.radius = other.radius; - this.phi = other.phi; - this.theta = other.theta; - - return this; - - } - - // restrict phi to be between EPS and PI-EPS - makeSafe() { - - const EPS = 0.000001; - this.phi = Math.max( EPS, Math.min( Math.PI - EPS, this.phi ) ); - - return this; - - } - - setFromVector3( v ) { - - return this.setFromCartesianCoords( v.x, v.y, v.z ); - - } - - setFromCartesianCoords( x, y, z ) { - - this.radius = Math.sqrt( x * x + y * y + z * z ); - - if ( this.radius === 0 ) { - - this.theta = 0; - this.phi = 0; - - } else { - - this.theta = Math.atan2( x, z ); - this.phi = Math.acos( clamp( y / this.radius, - 1, 1 ) ); - - } - - return this; - - } - - clone() { - - return new this.constructor().copy( this ); - - } - -} - -/** - * Ref: https://en.wikipedia.org/wiki/Cylindrical_coordinate_system - */ - -class Cylindrical { - - constructor( radius = 1, theta = 0, y = 0 ) { - - this.radius = radius; // distance from the origin to a point in the x-z plane - this.theta = theta; // counterclockwise angle in the x-z plane measured in radians from the positive z-axis - this.y = y; // height above the x-z plane - - return this; - - } - - set( radius, theta, y ) { - - this.radius = radius; - this.theta = theta; - this.y = y; - - return this; - - } - - copy( other ) { - - this.radius = other.radius; - this.theta = other.theta; - this.y = other.y; - - return this; - - } - - setFromVector3( v ) { - - return this.setFromCartesianCoords( v.x, v.y, v.z ); - - } - - setFromCartesianCoords( x, y, z ) { - - this.radius = Math.sqrt( x * x + z * z ); - this.theta = Math.atan2( x, z ); - this.y = y; - - return this; - - } - - clone() { - - return new this.constructor().copy( this ); - - } - -} - -const _vector$4 = /*@__PURE__*/ new Vector2(); - -class Box2 { - - constructor( min = new Vector2( + Infinity, + Infinity ), max = new Vector2( - Infinity, - Infinity ) ) { - - this.isBox2 = true; - - this.min = min; - this.max = max; - - } - - set( min, max ) { - - this.min.copy( min ); - this.max.copy( max ); - - return this; - - } - - setFromPoints( points ) { - - this.makeEmpty(); - - for ( let i = 0, il = points.length; i < il; i ++ ) { - - this.expandByPoint( points[ i ] ); - - } - - return this; - - } - - setFromCenterAndSize( center, size ) { - - const halfSize = _vector$4.copy( size ).multiplyScalar( 0.5 ); - this.min.copy( center ).sub( halfSize ); - this.max.copy( center ).add( halfSize ); - - return this; - - } - - clone() { - - return new this.constructor().copy( this ); - - } - - copy( box ) { - - this.min.copy( box.min ); - this.max.copy( box.max ); - - return this; - - } - - makeEmpty() { - - this.min.x = this.min.y = + Infinity; - this.max.x = this.max.y = - Infinity; - - return this; - - } - - isEmpty() { - - // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes - - return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ); - - } - - getCenter( target ) { - - return this.isEmpty() ? target.set( 0, 0 ) : target.addVectors( this.min, this.max ).multiplyScalar( 0.5 ); - - } - - getSize( target ) { - - return this.isEmpty() ? target.set( 0, 0 ) : target.subVectors( this.max, this.min ); - - } - - expandByPoint( point ) { - - this.min.min( point ); - this.max.max( point ); - - return this; - - } - - expandByVector( vector ) { - - this.min.sub( vector ); - this.max.add( vector ); - - return this; - - } - - expandByScalar( scalar ) { - - this.min.addScalar( - scalar ); - this.max.addScalar( scalar ); - - return this; - - } - - containsPoint( point ) { - - return point.x < this.min.x || point.x > this.max.x || - point.y < this.min.y || point.y > this.max.y ? false : true; - - } - - containsBox( box ) { - - return this.min.x <= box.min.x && box.max.x <= this.max.x && - this.min.y <= box.min.y && box.max.y <= this.max.y; - - } - - getParameter( point, target ) { - - // This can potentially have a divide by zero if the box - // has a size dimension of 0. - - return target.set( - ( point.x - this.min.x ) / ( this.max.x - this.min.x ), - ( point.y - this.min.y ) / ( this.max.y - this.min.y ) - ); - - } - - intersectsBox( box ) { - - // using 4 splitting planes to rule out intersections - - return box.max.x < this.min.x || box.min.x > this.max.x || - box.max.y < this.min.y || box.min.y > this.max.y ? false : true; - - } - - clampPoint( point, target ) { - - return target.copy( point ).clamp( this.min, this.max ); - - } - - distanceToPoint( point ) { - - return this.clampPoint( point, _vector$4 ).distanceTo( point ); - - } - - intersect( box ) { - - this.min.max( box.min ); - this.max.min( box.max ); - - if ( this.isEmpty() ) this.makeEmpty(); - - return this; - - } - - union( box ) { - - this.min.min( box.min ); - this.max.max( box.max ); - - return this; - - } - - translate( offset ) { - - this.min.add( offset ); - this.max.add( offset ); - - return this; - - } - - equals( box ) { - - return box.min.equals( this.min ) && box.max.equals( this.max ); - - } - -} - -const _startP = /*@__PURE__*/ new Vector3(); -const _startEnd = /*@__PURE__*/ new Vector3(); - -class Line3 { - - constructor( start = new Vector3(), end = new Vector3() ) { - - this.start = start; - this.end = end; - - } - - set( start, end ) { - - this.start.copy( start ); - this.end.copy( end ); - - return this; - - } - - copy( line ) { - - this.start.copy( line.start ); - this.end.copy( line.end ); - - return this; - - } - - getCenter( target ) { - - return target.addVectors( this.start, this.end ).multiplyScalar( 0.5 ); - - } - - delta( target ) { - - return target.subVectors( this.end, this.start ); - - } - - distanceSq() { - - return this.start.distanceToSquared( this.end ); - - } - - distance() { - - return this.start.distanceTo( this.end ); - - } - - at( t, target ) { - - return this.delta( target ).multiplyScalar( t ).add( this.start ); - - } - - closestPointToPointParameter( point, clampToLine ) { - - _startP.subVectors( point, this.start ); - _startEnd.subVectors( this.end, this.start ); - - const startEnd2 = _startEnd.dot( _startEnd ); - const startEnd_startP = _startEnd.dot( _startP ); - - let t = startEnd_startP / startEnd2; - - if ( clampToLine ) { - - t = clamp( t, 0, 1 ); - - } - - return t; - - } - - closestPointToPoint( point, clampToLine, target ) { - - const t = this.closestPointToPointParameter( point, clampToLine ); - - return this.delta( target ).multiplyScalar( t ).add( this.start ); - - } - - applyMatrix4( matrix ) { - - this.start.applyMatrix4( matrix ); - this.end.applyMatrix4( matrix ); - - return this; - - } - - equals( line ) { - - return line.start.equals( this.start ) && line.end.equals( this.end ); - - } - - clone() { - - return new this.constructor().copy( this ); - - } - -} - -const _vector$3 = /*@__PURE__*/ new Vector3(); - -class SpotLightHelper extends Object3D { - - constructor( light, color ) { - - super(); - - this.light = light; - - this.matrix = light.matrixWorld; - this.matrixAutoUpdate = false; - - this.color = color; - - this.type = 'SpotLightHelper'; - - const geometry = new BufferGeometry(); - - const positions = [ - 0, 0, 0, 0, 0, 1, - 0, 0, 0, 1, 0, 1, - 0, 0, 0, - 1, 0, 1, - 0, 0, 0, 0, 1, 1, - 0, 0, 0, 0, - 1, 1 - ]; - - for ( let i = 0, j = 1, l = 32; i < l; i ++, j ++ ) { - - const p1 = ( i / l ) * Math.PI * 2; - const p2 = ( j / l ) * Math.PI * 2; - - positions.push( - Math.cos( p1 ), Math.sin( p1 ), 1, - Math.cos( p2 ), Math.sin( p2 ), 1 - ); - - } - - geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) ); - - const material = new LineBasicMaterial( { fog: false, toneMapped: false } ); - - this.cone = new LineSegments( geometry, material ); - this.add( this.cone ); - - this.update(); - - } - - dispose() { - - this.cone.geometry.dispose(); - this.cone.material.dispose(); - - } - - update() { - - this.light.updateWorldMatrix( true, false ); - this.light.target.updateWorldMatrix( true, false ); - - const coneLength = this.light.distance ? this.light.distance : 1000; - const coneWidth = coneLength * Math.tan( this.light.angle ); - - this.cone.scale.set( coneWidth, coneWidth, coneLength ); - - _vector$3.setFromMatrixPosition( this.light.target.matrixWorld ); - - this.cone.lookAt( _vector$3 ); - - if ( this.color !== undefined ) { - - this.cone.material.color.set( this.color ); - - } else { - - this.cone.material.color.copy( this.light.color ); - - } - - } - -} - -const _vector$2 = /*@__PURE__*/ new Vector3(); -const _boneMatrix = /*@__PURE__*/ new Matrix4(); -const _matrixWorldInv = /*@__PURE__*/ new Matrix4(); - - -class SkeletonHelper extends LineSegments { - - constructor( object ) { - - const bones = getBoneList( object ); - - const geometry = new BufferGeometry(); - - const vertices = []; - const colors = []; - - const color1 = new Color( 0, 0, 1 ); - const color2 = new Color( 0, 1, 0 ); - - for ( let i = 0; i < bones.length; i ++ ) { - - const bone = bones[ i ]; - - if ( bone.parent && bone.parent.isBone ) { - - vertices.push( 0, 0, 0 ); - vertices.push( 0, 0, 0 ); - colors.push( color1.r, color1.g, color1.b ); - colors.push( color2.r, color2.g, color2.b ); - - } - - } - - geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); - - const material = new LineBasicMaterial( { vertexColors: true, depthTest: false, depthWrite: false, toneMapped: false, transparent: true } ); - - super( geometry, material ); - - this.isSkeletonHelper = true; - - this.type = 'SkeletonHelper'; - - this.root = object; - this.bones = bones; - - this.matrix = object.matrixWorld; - this.matrixAutoUpdate = false; - - } - - updateMatrixWorld( force ) { - - const bones = this.bones; - - const geometry = this.geometry; - const position = geometry.getAttribute( 'position' ); - - _matrixWorldInv.copy( this.root.matrixWorld ).invert(); - - for ( let i = 0, j = 0; i < bones.length; i ++ ) { - - const bone = bones[ i ]; - - if ( bone.parent && bone.parent.isBone ) { - - _boneMatrix.multiplyMatrices( _matrixWorldInv, bone.matrixWorld ); - _vector$2.setFromMatrixPosition( _boneMatrix ); - position.setXYZ( j, _vector$2.x, _vector$2.y, _vector$2.z ); - - _boneMatrix.multiplyMatrices( _matrixWorldInv, bone.parent.matrixWorld ); - _vector$2.setFromMatrixPosition( _boneMatrix ); - position.setXYZ( j + 1, _vector$2.x, _vector$2.y, _vector$2.z ); - - j += 2; - - } - - } - - geometry.getAttribute( 'position' ).needsUpdate = true; - - super.updateMatrixWorld( force ); - - } - - dispose() { - - this.geometry.dispose(); - this.material.dispose(); - - } - -} - - -function getBoneList( object ) { - - const boneList = []; - - if ( object.isBone === true ) { - - boneList.push( object ); - - } - - for ( let i = 0; i < object.children.length; i ++ ) { - - boneList.push.apply( boneList, getBoneList( object.children[ i ] ) ); - - } - - return boneList; - -} - -class PointLightHelper extends Mesh { - - constructor( light, sphereSize, color ) { - - const geometry = new SphereGeometry( sphereSize, 4, 2 ); - const material = new MeshBasicMaterial( { wireframe: true, fog: false, toneMapped: false } ); - - super( geometry, material ); - - this.light = light; - - this.color = color; - - this.type = 'PointLightHelper'; - - this.matrix = this.light.matrixWorld; - this.matrixAutoUpdate = false; - - this.update(); - - - /* - // TODO: delete this comment? - const distanceGeometry = new THREE.IcosahedronGeometry( 1, 2 ); - const distanceMaterial = new THREE.MeshBasicMaterial( { color: hexColor, fog: false, wireframe: true, opacity: 0.1, transparent: true } ); - - this.lightSphere = new THREE.Mesh( bulbGeometry, bulbMaterial ); - this.lightDistance = new THREE.Mesh( distanceGeometry, distanceMaterial ); - - const d = light.distance; - - if ( d === 0.0 ) { - - this.lightDistance.visible = false; - - } else { - - this.lightDistance.scale.set( d, d, d ); - - } - - this.add( this.lightDistance ); - */ - - } - - dispose() { - - this.geometry.dispose(); - this.material.dispose(); - - } - - update() { - - this.light.updateWorldMatrix( true, false ); - - if ( this.color !== undefined ) { - - this.material.color.set( this.color ); - - } else { - - this.material.color.copy( this.light.color ); - - } - - /* - const d = this.light.distance; - - if ( d === 0.0 ) { - - this.lightDistance.visible = false; - - } else { - - this.lightDistance.visible = true; - this.lightDistance.scale.set( d, d, d ); - - } - */ - - } - -} - -const _vector$1 = /*@__PURE__*/ new Vector3(); -const _color1 = /*@__PURE__*/ new Color(); -const _color2 = /*@__PURE__*/ new Color(); - -class HemisphereLightHelper extends Object3D { - - constructor( light, size, color ) { - - super(); - - this.light = light; - - this.matrix = light.matrixWorld; - this.matrixAutoUpdate = false; - - this.color = color; - - this.type = 'HemisphereLightHelper'; - - const geometry = new OctahedronGeometry( size ); - geometry.rotateY( Math.PI * 0.5 ); - - this.material = new MeshBasicMaterial( { wireframe: true, fog: false, toneMapped: false } ); - if ( this.color === undefined ) this.material.vertexColors = true; - - const position = geometry.getAttribute( 'position' ); - const colors = new Float32Array( position.count * 3 ); - - geometry.setAttribute( 'color', new BufferAttribute( colors, 3 ) ); - - this.add( new Mesh( geometry, this.material ) ); - - this.update(); - - } - - dispose() { - - this.children[ 0 ].geometry.dispose(); - this.children[ 0 ].material.dispose(); - - } - - update() { - - const mesh = this.children[ 0 ]; - - if ( this.color !== undefined ) { - - this.material.color.set( this.color ); - - } else { - - const colors = mesh.geometry.getAttribute( 'color' ); - - _color1.copy( this.light.color ); - _color2.copy( this.light.groundColor ); - - for ( let i = 0, l = colors.count; i < l; i ++ ) { - - const color = ( i < ( l / 2 ) ) ? _color1 : _color2; - - colors.setXYZ( i, color.r, color.g, color.b ); - - } - - colors.needsUpdate = true; - - } - - this.light.updateWorldMatrix( true, false ); - - mesh.lookAt( _vector$1.setFromMatrixPosition( this.light.matrixWorld ).negate() ); - - } - -} - -class GridHelper extends LineSegments { - - constructor( size = 10, divisions = 10, color1 = 0x444444, color2 = 0x888888 ) { - - color1 = new Color( color1 ); - color2 = new Color( color2 ); - - const center = divisions / 2; - const step = size / divisions; - const halfSize = size / 2; - - const vertices = [], colors = []; - - for ( let i = 0, j = 0, k = - halfSize; i <= divisions; i ++, k += step ) { - - vertices.push( - halfSize, 0, k, halfSize, 0, k ); - vertices.push( k, 0, - halfSize, k, 0, halfSize ); - - const color = i === center ? color1 : color2; - - color.toArray( colors, j ); j += 3; - color.toArray( colors, j ); j += 3; - color.toArray( colors, j ); j += 3; - color.toArray( colors, j ); j += 3; - - } - - const geometry = new BufferGeometry(); - geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); - - const material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } ); - - super( geometry, material ); - - this.type = 'GridHelper'; - - } - - dispose() { - - this.geometry.dispose(); - this.material.dispose(); - - } - -} - -class PolarGridHelper extends LineSegments { - - constructor( radius = 10, sectors = 16, rings = 8, divisions = 64, color1 = 0x444444, color2 = 0x888888 ) { - - color1 = new Color( color1 ); - color2 = new Color( color2 ); - - const vertices = []; - const colors = []; - - // create the sectors - - if ( sectors > 1 ) { - - for ( let i = 0; i < sectors; i ++ ) { - - const v = ( i / sectors ) * ( Math.PI * 2 ); - - const x = Math.sin( v ) * radius; - const z = Math.cos( v ) * radius; - - vertices.push( 0, 0, 0 ); - vertices.push( x, 0, z ); - - const color = ( i & 1 ) ? color1 : color2; - - colors.push( color.r, color.g, color.b ); - colors.push( color.r, color.g, color.b ); - - } - - } - - // create the rings - - for ( let i = 0; i < rings; i ++ ) { - - const color = ( i & 1 ) ? color1 : color2; - - const r = radius - ( radius / rings * i ); - - for ( let j = 0; j < divisions; j ++ ) { - - // first vertex - - let v = ( j / divisions ) * ( Math.PI * 2 ); - - let x = Math.sin( v ) * r; - let z = Math.cos( v ) * r; - - vertices.push( x, 0, z ); - colors.push( color.r, color.g, color.b ); - - // second vertex - - v = ( ( j + 1 ) / divisions ) * ( Math.PI * 2 ); - - x = Math.sin( v ) * r; - z = Math.cos( v ) * r; - - vertices.push( x, 0, z ); - colors.push( color.r, color.g, color.b ); - - } - - } - - const geometry = new BufferGeometry(); - geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); - - const material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } ); - - super( geometry, material ); - - this.type = 'PolarGridHelper'; - - } - - dispose() { - - this.geometry.dispose(); - this.material.dispose(); - - } - -} - -const _v1 = /*@__PURE__*/ new Vector3(); -const _v2 = /*@__PURE__*/ new Vector3(); -const _v3 = /*@__PURE__*/ new Vector3(); - -class DirectionalLightHelper extends Object3D { - - constructor( light, size, color ) { - - super(); - - this.light = light; - - this.matrix = light.matrixWorld; - this.matrixAutoUpdate = false; - - this.color = color; - - this.type = 'DirectionalLightHelper'; - - if ( size === undefined ) size = 1; - - let geometry = new BufferGeometry(); - geometry.setAttribute( 'position', new Float32BufferAttribute( [ - - size, size, 0, - size, size, 0, - size, - size, 0, - - size, - size, 0, - - size, size, 0 - ], 3 ) ); - - const material = new LineBasicMaterial( { fog: false, toneMapped: false } ); - - this.lightPlane = new Line( geometry, material ); - this.add( this.lightPlane ); - - geometry = new BufferGeometry(); - geometry.setAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 0, 1 ], 3 ) ); - - this.targetLine = new Line( geometry, material ); - this.add( this.targetLine ); - - this.update(); - - } - - dispose() { - - this.lightPlane.geometry.dispose(); - this.lightPlane.material.dispose(); - this.targetLine.geometry.dispose(); - this.targetLine.material.dispose(); - - } - - update() { - - this.light.updateWorldMatrix( true, false ); - this.light.target.updateWorldMatrix( true, false ); - - _v1.setFromMatrixPosition( this.light.matrixWorld ); - _v2.setFromMatrixPosition( this.light.target.matrixWorld ); - _v3.subVectors( _v2, _v1 ); - - this.lightPlane.lookAt( _v2 ); - - if ( this.color !== undefined ) { - - this.lightPlane.material.color.set( this.color ); - this.targetLine.material.color.set( this.color ); - - } else { - - this.lightPlane.material.color.copy( this.light.color ); - this.targetLine.material.color.copy( this.light.color ); - - } - - this.targetLine.lookAt( _v2 ); - this.targetLine.scale.z = _v3.length(); - - } - -} - -const _vector = /*@__PURE__*/ new Vector3(); -const _camera = /*@__PURE__*/ new Camera(); - -/** - * - shows frustum, line of sight and up of the camera - * - suitable for fast updates - * - based on frustum visualization in lightgl.js shadowmap example - * https://github.com/evanw/lightgl.js/blob/master/tests/shadowmap.html - */ - -class CameraHelper extends LineSegments { - - constructor( camera ) { - - const geometry = new BufferGeometry(); - const material = new LineBasicMaterial( { color: 0xffffff, vertexColors: true, toneMapped: false } ); - - const vertices = []; - const colors = []; - - const pointMap = {}; - - // near - - addLine( 'n1', 'n2' ); - addLine( 'n2', 'n4' ); - addLine( 'n4', 'n3' ); - addLine( 'n3', 'n1' ); - - // far - - addLine( 'f1', 'f2' ); - addLine( 'f2', 'f4' ); - addLine( 'f4', 'f3' ); - addLine( 'f3', 'f1' ); - - // sides - - addLine( 'n1', 'f1' ); - addLine( 'n2', 'f2' ); - addLine( 'n3', 'f3' ); - addLine( 'n4', 'f4' ); - - // cone - - addLine( 'p', 'n1' ); - addLine( 'p', 'n2' ); - addLine( 'p', 'n3' ); - addLine( 'p', 'n4' ); - - // up - - addLine( 'u1', 'u2' ); - addLine( 'u2', 'u3' ); - addLine( 'u3', 'u1' ); - - // target - - addLine( 'c', 't' ); - addLine( 'p', 'c' ); - - // cross - - addLine( 'cn1', 'cn2' ); - addLine( 'cn3', 'cn4' ); - - addLine( 'cf1', 'cf2' ); - addLine( 'cf3', 'cf4' ); - - function addLine( a, b ) { - - addPoint( a ); - addPoint( b ); - - } - - function addPoint( id ) { - - vertices.push( 0, 0, 0 ); - colors.push( 0, 0, 0 ); - - if ( pointMap[ id ] === undefined ) { - - pointMap[ id ] = []; - - } - - pointMap[ id ].push( ( vertices.length / 3 ) - 1 ); - - } - - geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); - - super( geometry, material ); - - this.type = 'CameraHelper'; - - this.camera = camera; - if ( this.camera.updateProjectionMatrix ) this.camera.updateProjectionMatrix(); - - this.matrix = camera.matrixWorld; - this.matrixAutoUpdate = false; - - this.pointMap = pointMap; - - this.update(); - - // colors - - const colorFrustum = new Color( 0xffaa00 ); - const colorCone = new Color( 0xff0000 ); - const colorUp = new Color( 0x00aaff ); - const colorTarget = new Color( 0xffffff ); - const colorCross = new Color( 0x333333 ); - - this.setColors( colorFrustum, colorCone, colorUp, colorTarget, colorCross ); - - } - - setColors( frustum, cone, up, target, cross ) { - - const geometry = this.geometry; - - const colorAttribute = geometry.getAttribute( 'color' ); - - // near - - colorAttribute.setXYZ( 0, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 1, frustum.r, frustum.g, frustum.b ); // n1, n2 - colorAttribute.setXYZ( 2, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 3, frustum.r, frustum.g, frustum.b ); // n2, n4 - colorAttribute.setXYZ( 4, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 5, frustum.r, frustum.g, frustum.b ); // n4, n3 - colorAttribute.setXYZ( 6, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 7, frustum.r, frustum.g, frustum.b ); // n3, n1 - - // far - - colorAttribute.setXYZ( 8, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 9, frustum.r, frustum.g, frustum.b ); // f1, f2 - colorAttribute.setXYZ( 10, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 11, frustum.r, frustum.g, frustum.b ); // f2, f4 - colorAttribute.setXYZ( 12, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 13, frustum.r, frustum.g, frustum.b ); // f4, f3 - colorAttribute.setXYZ( 14, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 15, frustum.r, frustum.g, frustum.b ); // f3, f1 - - // sides - - colorAttribute.setXYZ( 16, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 17, frustum.r, frustum.g, frustum.b ); // n1, f1 - colorAttribute.setXYZ( 18, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 19, frustum.r, frustum.g, frustum.b ); // n2, f2 - colorAttribute.setXYZ( 20, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 21, frustum.r, frustum.g, frustum.b ); // n3, f3 - colorAttribute.setXYZ( 22, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 23, frustum.r, frustum.g, frustum.b ); // n4, f4 - - // cone - - colorAttribute.setXYZ( 24, cone.r, cone.g, cone.b ); colorAttribute.setXYZ( 25, cone.r, cone.g, cone.b ); // p, n1 - colorAttribute.setXYZ( 26, cone.r, cone.g, cone.b ); colorAttribute.setXYZ( 27, cone.r, cone.g, cone.b ); // p, n2 - colorAttribute.setXYZ( 28, cone.r, cone.g, cone.b ); colorAttribute.setXYZ( 29, cone.r, cone.g, cone.b ); // p, n3 - colorAttribute.setXYZ( 30, cone.r, cone.g, cone.b ); colorAttribute.setXYZ( 31, cone.r, cone.g, cone.b ); // p, n4 - - // up - - colorAttribute.setXYZ( 32, up.r, up.g, up.b ); colorAttribute.setXYZ( 33, up.r, up.g, up.b ); // u1, u2 - colorAttribute.setXYZ( 34, up.r, up.g, up.b ); colorAttribute.setXYZ( 35, up.r, up.g, up.b ); // u2, u3 - colorAttribute.setXYZ( 36, up.r, up.g, up.b ); colorAttribute.setXYZ( 37, up.r, up.g, up.b ); // u3, u1 - - // target - - colorAttribute.setXYZ( 38, target.r, target.g, target.b ); colorAttribute.setXYZ( 39, target.r, target.g, target.b ); // c, t - colorAttribute.setXYZ( 40, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 41, cross.r, cross.g, cross.b ); // p, c - - // cross - - colorAttribute.setXYZ( 42, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 43, cross.r, cross.g, cross.b ); // cn1, cn2 - colorAttribute.setXYZ( 44, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 45, cross.r, cross.g, cross.b ); // cn3, cn4 - - colorAttribute.setXYZ( 46, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 47, cross.r, cross.g, cross.b ); // cf1, cf2 - colorAttribute.setXYZ( 48, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 49, cross.r, cross.g, cross.b ); // cf3, cf4 - - colorAttribute.needsUpdate = true; - - } - - update() { - - const geometry = this.geometry; - const pointMap = this.pointMap; - - const w = 1, h = 1; - - // we need just camera projection matrix inverse - // world matrix must be identity - - _camera.projectionMatrixInverse.copy( this.camera.projectionMatrixInverse ); - - // center / target - - setPoint( 'c', pointMap, geometry, _camera, 0, 0, - 1 ); - setPoint( 't', pointMap, geometry, _camera, 0, 0, 1 ); - - // near - - setPoint( 'n1', pointMap, geometry, _camera, - w, - h, - 1 ); - setPoint( 'n2', pointMap, geometry, _camera, w, - h, - 1 ); - setPoint( 'n3', pointMap, geometry, _camera, - w, h, - 1 ); - setPoint( 'n4', pointMap, geometry, _camera, w, h, - 1 ); - - // far - - setPoint( 'f1', pointMap, geometry, _camera, - w, - h, 1 ); - setPoint( 'f2', pointMap, geometry, _camera, w, - h, 1 ); - setPoint( 'f3', pointMap, geometry, _camera, - w, h, 1 ); - setPoint( 'f4', pointMap, geometry, _camera, w, h, 1 ); - - // up - - setPoint( 'u1', pointMap, geometry, _camera, w * 0.7, h * 1.1, - 1 ); - setPoint( 'u2', pointMap, geometry, _camera, - w * 0.7, h * 1.1, - 1 ); - setPoint( 'u3', pointMap, geometry, _camera, 0, h * 2, - 1 ); - - // cross - - setPoint( 'cf1', pointMap, geometry, _camera, - w, 0, 1 ); - setPoint( 'cf2', pointMap, geometry, _camera, w, 0, 1 ); - setPoint( 'cf3', pointMap, geometry, _camera, 0, - h, 1 ); - setPoint( 'cf4', pointMap, geometry, _camera, 0, h, 1 ); - - setPoint( 'cn1', pointMap, geometry, _camera, - w, 0, - 1 ); - setPoint( 'cn2', pointMap, geometry, _camera, w, 0, - 1 ); - setPoint( 'cn3', pointMap, geometry, _camera, 0, - h, - 1 ); - setPoint( 'cn4', pointMap, geometry, _camera, 0, h, - 1 ); - - geometry.getAttribute( 'position' ).needsUpdate = true; - - } - - dispose() { - - this.geometry.dispose(); - this.material.dispose(); - - } - -} - - -function setPoint( point, pointMap, geometry, camera, x, y, z ) { - - _vector.set( x, y, z ).unproject( camera ); - - const points = pointMap[ point ]; - - if ( points !== undefined ) { - - const position = geometry.getAttribute( 'position' ); - - for ( let i = 0, l = points.length; i < l; i ++ ) { - - position.setXYZ( points[ i ], _vector.x, _vector.y, _vector.z ); - - } - - } - -} - -const _box = /*@__PURE__*/ new Box3(); - -class BoxHelper extends LineSegments { - - constructor( object, color = 0xffff00 ) { - - const indices = new Uint16Array( [ 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7 ] ); - const positions = new Float32Array( 8 * 3 ); - - const geometry = new BufferGeometry(); - geometry.setIndex( new BufferAttribute( indices, 1 ) ); - geometry.setAttribute( 'position', new BufferAttribute( positions, 3 ) ); - - super( geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) ); - - this.object = object; - this.type = 'BoxHelper'; - - this.matrixAutoUpdate = false; - - this.update(); - - } - - update( object ) { - - if ( object !== undefined ) { - - console.warn( 'THREE.BoxHelper: .update() has no longer arguments.' ); - - } - - if ( this.object !== undefined ) { - - _box.setFromObject( this.object ); - - } - - if ( _box.isEmpty() ) return; - - const min = _box.min; - const max = _box.max; - - /* - 5____4 - 1/___0/| - | 6__|_7 - 2/___3/ - - 0: max.x, max.y, max.z - 1: min.x, max.y, max.z - 2: min.x, min.y, max.z - 3: max.x, min.y, max.z - 4: max.x, max.y, min.z - 5: min.x, max.y, min.z - 6: min.x, min.y, min.z - 7: max.x, min.y, min.z - */ - - const position = this.geometry.attributes.position; - const array = position.array; - - array[ 0 ] = max.x; array[ 1 ] = max.y; array[ 2 ] = max.z; - array[ 3 ] = min.x; array[ 4 ] = max.y; array[ 5 ] = max.z; - array[ 6 ] = min.x; array[ 7 ] = min.y; array[ 8 ] = max.z; - array[ 9 ] = max.x; array[ 10 ] = min.y; array[ 11 ] = max.z; - array[ 12 ] = max.x; array[ 13 ] = max.y; array[ 14 ] = min.z; - array[ 15 ] = min.x; array[ 16 ] = max.y; array[ 17 ] = min.z; - array[ 18 ] = min.x; array[ 19 ] = min.y; array[ 20 ] = min.z; - array[ 21 ] = max.x; array[ 22 ] = min.y; array[ 23 ] = min.z; - - position.needsUpdate = true; - - this.geometry.computeBoundingSphere(); - - } - - setFromObject( object ) { - - this.object = object; - this.update(); - - return this; - - } - - copy( source, recursive ) { - - super.copy( source, recursive ); - - this.object = source.object; - - return this; - - } - - dispose() { - - this.geometry.dispose(); - this.material.dispose(); - - } - -} - -class Box3Helper extends LineSegments { - - constructor( box, color = 0xffff00 ) { - - const indices = new Uint16Array( [ 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7 ] ); - - const positions = [ 1, 1, 1, - 1, 1, 1, - 1, - 1, 1, 1, - 1, 1, 1, 1, - 1, - 1, 1, - 1, - 1, - 1, - 1, 1, - 1, - 1 ]; - - const geometry = new BufferGeometry(); - - geometry.setIndex( new BufferAttribute( indices, 1 ) ); - - geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) ); - - super( geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) ); - - this.box = box; - - this.type = 'Box3Helper'; - - this.geometry.computeBoundingSphere(); - - } - - updateMatrixWorld( force ) { - - const box = this.box; - - if ( box.isEmpty() ) return; - - box.getCenter( this.position ); - - box.getSize( this.scale ); - - this.scale.multiplyScalar( 0.5 ); - - super.updateMatrixWorld( force ); - - } - - dispose() { - - this.geometry.dispose(); - this.material.dispose(); - - } - -} - -class PlaneHelper extends Line { - - constructor( plane, size = 1, hex = 0xffff00 ) { - - const color = hex; - - const positions = [ 1, - 1, 0, - 1, 1, 0, - 1, - 1, 0, 1, 1, 0, - 1, 1, 0, - 1, - 1, 0, 1, - 1, 0, 1, 1, 0 ]; - - const geometry = new BufferGeometry(); - geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) ); - geometry.computeBoundingSphere(); - - super( geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) ); - - this.type = 'PlaneHelper'; - - this.plane = plane; - - this.size = size; - - const positions2 = [ 1, 1, 0, - 1, 1, 0, - 1, - 1, 0, 1, 1, 0, - 1, - 1, 0, 1, - 1, 0 ]; - - const geometry2 = new BufferGeometry(); - geometry2.setAttribute( 'position', new Float32BufferAttribute( positions2, 3 ) ); - geometry2.computeBoundingSphere(); - - this.add( new Mesh( geometry2, new MeshBasicMaterial( { color: color, opacity: 0.2, transparent: true, depthWrite: false, toneMapped: false } ) ) ); - - } - - updateMatrixWorld( force ) { - - this.position.set( 0, 0, 0 ); - - this.scale.set( 0.5 * this.size, 0.5 * this.size, 1 ); - - this.lookAt( this.plane.normal ); - - this.translateZ( - this.plane.constant ); - - super.updateMatrixWorld( force ); - - } - - dispose() { - - this.geometry.dispose(); - this.material.dispose(); - this.children[ 0 ].geometry.dispose(); - this.children[ 0 ].material.dispose(); - - } - -} - -const _axis = /*@__PURE__*/ new Vector3(); -let _lineGeometry, _coneGeometry; - -class ArrowHelper extends Object3D { - - // dir is assumed to be normalized - - constructor( dir = new Vector3( 0, 0, 1 ), origin = new Vector3( 0, 0, 0 ), length = 1, color = 0xffff00, headLength = length * 0.2, headWidth = headLength * 0.2 ) { - - super(); - - this.type = 'ArrowHelper'; - - if ( _lineGeometry === undefined ) { - - _lineGeometry = new BufferGeometry(); - _lineGeometry.setAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 1, 0 ], 3 ) ); - - _coneGeometry = new CylinderGeometry( 0, 0.5, 1, 5, 1 ); - _coneGeometry.translate( 0, - 0.5, 0 ); - - } - - this.position.copy( origin ); - - this.line = new Line( _lineGeometry, new LineBasicMaterial( { color: color, toneMapped: false } ) ); - this.line.matrixAutoUpdate = false; - this.add( this.line ); - - this.cone = new Mesh( _coneGeometry, new MeshBasicMaterial( { color: color, toneMapped: false } ) ); - this.cone.matrixAutoUpdate = false; - this.add( this.cone ); - - this.setDirection( dir ); - this.setLength( length, headLength, headWidth ); - - } - - setDirection( dir ) { - - // dir is assumed to be normalized - - if ( dir.y > 0.99999 ) { - - this.quaternion.set( 0, 0, 0, 1 ); - - } else if ( dir.y < - 0.99999 ) { - - this.quaternion.set( 1, 0, 0, 0 ); - - } else { - - _axis.set( dir.z, 0, - dir.x ).normalize(); - - const radians = Math.acos( dir.y ); - - this.quaternion.setFromAxisAngle( _axis, radians ); - - } - - } - - setLength( length, headLength = length * 0.2, headWidth = headLength * 0.2 ) { - - this.line.scale.set( 1, Math.max( 0.0001, length - headLength ), 1 ); // see #17458 - this.line.updateMatrix(); - - this.cone.scale.set( headWidth, headLength, headWidth ); - this.cone.position.y = length; - this.cone.updateMatrix(); - - } - - setColor( color ) { - - this.line.material.color.set( color ); - this.cone.material.color.set( color ); - - } - - copy( source ) { - - super.copy( source, false ); - - this.line.copy( source.line ); - this.cone.copy( source.cone ); - - return this; - - } - - dispose() { - - this.line.geometry.dispose(); - this.line.material.dispose(); - this.cone.geometry.dispose(); - this.cone.material.dispose(); - - } - -} - -class AxesHelper extends LineSegments { - - constructor( size = 1 ) { - - const vertices = [ - 0, 0, 0, size, 0, 0, - 0, 0, 0, 0, size, 0, - 0, 0, 0, 0, 0, size - ]; - - const colors = [ - 1, 0, 0, 1, 0.6, 0, - 0, 1, 0, 0.6, 1, 0, - 0, 0, 1, 0, 0.6, 1 - ]; - - const geometry = new BufferGeometry(); - geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); - - const material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } ); - - super( geometry, material ); - - this.type = 'AxesHelper'; - - } - - setColors( xAxisColor, yAxisColor, zAxisColor ) { - - const color = new Color(); - const array = this.geometry.attributes.color.array; - - color.set( xAxisColor ); - color.toArray( array, 0 ); - color.toArray( array, 3 ); - - color.set( yAxisColor ); - color.toArray( array, 6 ); - color.toArray( array, 9 ); - - color.set( zAxisColor ); - color.toArray( array, 12 ); - color.toArray( array, 15 ); - - this.geometry.attributes.color.needsUpdate = true; - - return this; - - } - - dispose() { - - this.geometry.dispose(); - this.material.dispose(); - - } - -} - -class ShapePath { - - constructor() { - - this.type = 'ShapePath'; - - this.color = new Color(); - - this.subPaths = []; - this.currentPath = null; - - } - - moveTo( x, y ) { - - this.currentPath = new Path(); - this.subPaths.push( this.currentPath ); - this.currentPath.moveTo( x, y ); - - return this; - - } - - lineTo( x, y ) { - - this.currentPath.lineTo( x, y ); - - return this; - - } - - quadraticCurveTo( aCPx, aCPy, aX, aY ) { - - this.currentPath.quadraticCurveTo( aCPx, aCPy, aX, aY ); - - return this; - - } - - bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) { - - this.currentPath.bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ); - - return this; - - } - - splineThru( pts ) { - - this.currentPath.splineThru( pts ); - - return this; - - } - - toShapes( isCCW ) { - - function toShapesNoHoles( inSubpaths ) { - - const shapes = []; - - for ( let i = 0, l = inSubpaths.length; i < l; i ++ ) { - - const tmpPath = inSubpaths[ i ]; - - const tmpShape = new Shape(); - tmpShape.curves = tmpPath.curves; - - shapes.push( tmpShape ); - - } - - return shapes; - - } - - function isPointInsidePolygon( inPt, inPolygon ) { - - const polyLen = inPolygon.length; - - // inPt on polygon contour => immediate success or - // toggling of inside/outside at every single! intersection point of an edge - // with the horizontal line through inPt, left of inPt - // not counting lowerY endpoints of edges and whole edges on that line - let inside = false; - for ( let p = polyLen - 1, q = 0; q < polyLen; p = q ++ ) { - - let edgeLowPt = inPolygon[ p ]; - let edgeHighPt = inPolygon[ q ]; - - let edgeDx = edgeHighPt.x - edgeLowPt.x; - let edgeDy = edgeHighPt.y - edgeLowPt.y; - - if ( Math.abs( edgeDy ) > Number.EPSILON ) { - - // not parallel - if ( edgeDy < 0 ) { - - edgeLowPt = inPolygon[ q ]; edgeDx = - edgeDx; - edgeHighPt = inPolygon[ p ]; edgeDy = - edgeDy; - - } - - if ( ( inPt.y < edgeLowPt.y ) || ( inPt.y > edgeHighPt.y ) ) continue; - - if ( inPt.y === edgeLowPt.y ) { - - if ( inPt.x === edgeLowPt.x ) return true; // inPt is on contour ? - // continue; // no intersection or edgeLowPt => doesn't count !!! - - } else { - - const perpEdge = edgeDy * ( inPt.x - edgeLowPt.x ) - edgeDx * ( inPt.y - edgeLowPt.y ); - if ( perpEdge === 0 ) return true; // inPt is on contour ? - if ( perpEdge < 0 ) continue; - inside = ! inside; // true intersection left of inPt - - } - - } else { - - // parallel or collinear - if ( inPt.y !== edgeLowPt.y ) continue; // parallel - // edge lies on the same horizontal line as inPt - if ( ( ( edgeHighPt.x <= inPt.x ) && ( inPt.x <= edgeLowPt.x ) ) || - ( ( edgeLowPt.x <= inPt.x ) && ( inPt.x <= edgeHighPt.x ) ) ) return true; // inPt: Point on contour ! - // continue; - - } - - } - - return inside; - - } - - const isClockWise = ShapeUtils.isClockWise; - - const subPaths = this.subPaths; - if ( subPaths.length === 0 ) return []; - - let solid, tmpPath, tmpShape; - const shapes = []; - - if ( subPaths.length === 1 ) { - - tmpPath = subPaths[ 0 ]; - tmpShape = new Shape(); - tmpShape.curves = tmpPath.curves; - shapes.push( tmpShape ); - return shapes; - - } - - let holesFirst = ! isClockWise( subPaths[ 0 ].getPoints() ); - holesFirst = isCCW ? ! holesFirst : holesFirst; - - // console.log("Holes first", holesFirst); - - const betterShapeHoles = []; - const newShapes = []; - let newShapeHoles = []; - let mainIdx = 0; - let tmpPoints; - - newShapes[ mainIdx ] = undefined; - newShapeHoles[ mainIdx ] = []; - - for ( let i = 0, l = subPaths.length; i < l; i ++ ) { - - tmpPath = subPaths[ i ]; - tmpPoints = tmpPath.getPoints(); - solid = isClockWise( tmpPoints ); - solid = isCCW ? ! solid : solid; - - if ( solid ) { - - if ( ( ! holesFirst ) && ( newShapes[ mainIdx ] ) ) mainIdx ++; - - newShapes[ mainIdx ] = { s: new Shape(), p: tmpPoints }; - newShapes[ mainIdx ].s.curves = tmpPath.curves; - - if ( holesFirst ) mainIdx ++; - newShapeHoles[ mainIdx ] = []; - - //console.log('cw', i); - - } else { - - newShapeHoles[ mainIdx ].push( { h: tmpPath, p: tmpPoints[ 0 ] } ); - - //console.log('ccw', i); - - } - - } - - // only Holes? -> probably all Shapes with wrong orientation - if ( ! newShapes[ 0 ] ) return toShapesNoHoles( subPaths ); - - - if ( newShapes.length > 1 ) { - - let ambiguous = false; - let toChange = 0; - - for ( let sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) { - - betterShapeHoles[ sIdx ] = []; - - } - - for ( let sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) { - - const sho = newShapeHoles[ sIdx ]; - - for ( let hIdx = 0; hIdx < sho.length; hIdx ++ ) { - - const ho = sho[ hIdx ]; - let hole_unassigned = true; - - for ( let s2Idx = 0; s2Idx < newShapes.length; s2Idx ++ ) { - - if ( isPointInsidePolygon( ho.p, newShapes[ s2Idx ].p ) ) { - - if ( sIdx !== s2Idx ) toChange ++; - - if ( hole_unassigned ) { - - hole_unassigned = false; - betterShapeHoles[ s2Idx ].push( ho ); - - } else { - - ambiguous = true; - - } - - } - - } - - if ( hole_unassigned ) { - - betterShapeHoles[ sIdx ].push( ho ); - - } - - } - - } - - if ( toChange > 0 && ambiguous === false ) { - - newShapeHoles = betterShapeHoles; - - } - - } - - let tmpHoles; - - for ( let i = 0, il = newShapes.length; i < il; i ++ ) { - - tmpShape = newShapes[ i ].s; - shapes.push( tmpShape ); - tmpHoles = newShapeHoles[ i ]; - - for ( let j = 0, jl = tmpHoles.length; j < jl; j ++ ) { - - tmpShape.holes.push( tmpHoles[ j ].h ); - - } - - } - - //console.log("shape", shapes); - - return shapes; - - } - -} - -if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) { - - __THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'register', { detail: { - revision: REVISION, - } } ) ); - -} - -if ( typeof window !== 'undefined' ) { - - if ( window.__THREE__ ) { - - console.warn( 'WARNING: Multiple instances of Three.js being imported.' ); - - } else { - - window.__THREE__ = REVISION; - - } - -} - -export { ACESFilmicToneMapping, AddEquation, AddOperation, AdditiveAnimationBlendMode, AdditiveBlending, AgXToneMapping, AlphaFormat, AlwaysCompare, AlwaysDepth, AlwaysStencilFunc, AmbientLight, AnimationAction, AnimationClip, AnimationLoader, AnimationMixer, AnimationObjectGroup, AnimationUtils, ArcCurve, ArrayCamera, ArrowHelper, AttachedBindMode, Audio, AudioAnalyser, AudioContext, AudioListener, AudioLoader, AxesHelper, BackSide, BasicDepthPacking, BasicShadowMap, BatchedMesh, Bone, BooleanKeyframeTrack, Box2, Box3, Box3Helper, BoxGeometry, BoxHelper, BufferAttribute, BufferGeometry, BufferGeometryLoader, ByteType, Cache, Camera, CameraHelper, CanvasTexture, CapsuleGeometry, CatmullRomCurve3, CineonToneMapping, CircleGeometry, ClampToEdgeWrapping, Clock, Color, ColorKeyframeTrack, ColorManagement, CompressedArrayTexture, CompressedCubeTexture, CompressedTexture, CompressedTextureLoader, ConeGeometry, ConstantAlphaFactor, ConstantColorFactor, CubeCamera, CubeReflectionMapping, CubeRefractionMapping, CubeTexture, CubeTextureLoader, CubeUVReflectionMapping, CubicBezierCurve, CubicBezierCurve3, CubicInterpolant, CullFaceBack, CullFaceFront, CullFaceFrontBack, CullFaceNone, Curve, CurvePath, CustomBlending, CustomToneMapping, CylinderGeometry, Cylindrical, Data3DTexture, DataArrayTexture, DataTexture, DataTextureLoader, DataUtils, DecrementStencilOp, DecrementWrapStencilOp, DefaultLoadingManager, DepthFormat, DepthStencilFormat, DepthTexture, DetachedBindMode, DirectionalLight, DirectionalLightHelper, DiscreteInterpolant, DisplayP3ColorSpace, DodecahedronGeometry, DoubleSide, DstAlphaFactor, DstColorFactor, DynamicCopyUsage, DynamicDrawUsage, DynamicReadUsage, EdgesGeometry, EllipseCurve, EqualCompare, EqualDepth, EqualStencilFunc, EquirectangularReflectionMapping, EquirectangularRefractionMapping, Euler, EventDispatcher, ExtrudeGeometry, FileLoader, Float16BufferAttribute, Float32BufferAttribute, Float64BufferAttribute, FloatType, Fog, FogExp2, FramebufferTexture, FrontSide, Frustum, GLBufferAttribute, GLSL1, GLSL3, GreaterCompare, GreaterDepth, GreaterEqualCompare, GreaterEqualDepth, GreaterEqualStencilFunc, GreaterStencilFunc, GridHelper, Group, HalfFloatType, HemisphereLight, HemisphereLightHelper, IcosahedronGeometry, ImageBitmapLoader, ImageLoader, ImageUtils, IncrementStencilOp, IncrementWrapStencilOp, InstancedBufferAttribute, InstancedBufferGeometry, InstancedInterleavedBuffer, InstancedMesh, Int16BufferAttribute, Int32BufferAttribute, Int8BufferAttribute, IntType, InterleavedBuffer, InterleavedBufferAttribute, Interpolant, InterpolateDiscrete, InterpolateLinear, InterpolateSmooth, InvertStencilOp, KeepStencilOp, KeyframeTrack, LOD, LatheGeometry, Layers, LessCompare, LessDepth, LessEqualCompare, LessEqualDepth, LessEqualStencilFunc, LessStencilFunc, Light, LightProbe, Line, Line3, LineBasicMaterial, LineCurve, LineCurve3, LineDashedMaterial, LineLoop, LineSegments, LinearDisplayP3ColorSpace, LinearFilter, LinearInterpolant, LinearMipMapLinearFilter, LinearMipMapNearestFilter, LinearMipmapLinearFilter, LinearMipmapNearestFilter, LinearSRGBColorSpace, LinearToneMapping, LinearTransfer, Loader, LoaderUtils, LoadingManager, LoopOnce, LoopPingPong, LoopRepeat, LuminanceAlphaFormat, LuminanceFormat, MOUSE, Material, MaterialLoader, MathUtils, Matrix3, Matrix4, MaxEquation, Mesh, MeshBasicMaterial, MeshDepthMaterial, MeshDistanceMaterial, MeshLambertMaterial, MeshMatcapMaterial, MeshNormalMaterial, MeshPhongMaterial, MeshPhysicalMaterial, MeshStandardMaterial, MeshToonMaterial, MinEquation, MirroredRepeatWrapping, MixOperation, MultiplyBlending, MultiplyOperation, NearestFilter, NearestMipMapLinearFilter, NearestMipMapNearestFilter, NearestMipmapLinearFilter, NearestMipmapNearestFilter, NeverCompare, NeverDepth, NeverStencilFunc, NoBlending, NoColorSpace, NoToneMapping, NormalAnimationBlendMode, NormalBlending, NotEqualCompare, NotEqualDepth, NotEqualStencilFunc, NumberKeyframeTrack, Object3D, ObjectLoader, ObjectSpaceNormalMap, OctahedronGeometry, OneFactor, OneMinusConstantAlphaFactor, OneMinusConstantColorFactor, OneMinusDstAlphaFactor, OneMinusDstColorFactor, OneMinusSrcAlphaFactor, OneMinusSrcColorFactor, OrthographicCamera, P3Primaries, PCFShadowMap, PCFSoftShadowMap, PMREMGenerator, Path, PerspectiveCamera, Plane, PlaneGeometry, PlaneHelper, PointLight, PointLightHelper, Points, PointsMaterial, PolarGridHelper, PolyhedronGeometry, PositionalAudio, PropertyBinding, PropertyMixer, QuadraticBezierCurve, QuadraticBezierCurve3, Quaternion, QuaternionKeyframeTrack, QuaternionLinearInterpolant, RED_GREEN_RGTC2_Format, RED_RGTC1_Format, REVISION, RGBADepthPacking, RGBAFormat, RGBAIntegerFormat, RGBA_ASTC_10x10_Format, RGBA_ASTC_10x5_Format, RGBA_ASTC_10x6_Format, RGBA_ASTC_10x8_Format, RGBA_ASTC_12x10_Format, RGBA_ASTC_12x12_Format, RGBA_ASTC_4x4_Format, RGBA_ASTC_5x4_Format, RGBA_ASTC_5x5_Format, RGBA_ASTC_6x5_Format, RGBA_ASTC_6x6_Format, RGBA_ASTC_8x5_Format, RGBA_ASTC_8x6_Format, RGBA_ASTC_8x8_Format, RGBA_BPTC_Format, RGBA_ETC2_EAC_Format, RGBA_PVRTC_2BPPV1_Format, RGBA_PVRTC_4BPPV1_Format, RGBA_S3TC_DXT1_Format, RGBA_S3TC_DXT3_Format, RGBA_S3TC_DXT5_Format, RGB_BPTC_SIGNED_Format, RGB_BPTC_UNSIGNED_Format, RGB_ETC1_Format, RGB_ETC2_Format, RGB_PVRTC_2BPPV1_Format, RGB_PVRTC_4BPPV1_Format, RGB_S3TC_DXT1_Format, RGFormat, RGIntegerFormat, RawShaderMaterial, Ray, Raycaster, Rec709Primaries, RectAreaLight, RedFormat, RedIntegerFormat, ReinhardToneMapping, RenderTarget, RepeatWrapping, ReplaceStencilOp, ReverseSubtractEquation, RingGeometry, SIGNED_RED_GREEN_RGTC2_Format, SIGNED_RED_RGTC1_Format, SRGBColorSpace, SRGBTransfer, Scene, ShaderChunk, ShaderLib, ShaderMaterial, ShadowMaterial, Shape, ShapeGeometry, ShapePath, ShapeUtils, ShortType, Skeleton, SkeletonHelper, SkinnedMesh, Source, Sphere, SphereGeometry, Spherical, SphericalHarmonics3, SplineCurve, SpotLight, SpotLightHelper, Sprite, SpriteMaterial, SrcAlphaFactor, SrcAlphaSaturateFactor, SrcColorFactor, StaticCopyUsage, StaticDrawUsage, StaticReadUsage, StereoCamera, StreamCopyUsage, StreamDrawUsage, StreamReadUsage, StringKeyframeTrack, SubtractEquation, SubtractiveBlending, TOUCH, TangentSpaceNormalMap, TetrahedronGeometry, Texture, TextureLoader, TorusGeometry, TorusKnotGeometry, Triangle, TriangleFanDrawMode, TriangleStripDrawMode, TrianglesDrawMode, TubeGeometry, UVMapping, Uint16BufferAttribute, Uint32BufferAttribute, Uint8BufferAttribute, Uint8ClampedBufferAttribute, Uniform, UniformsGroup, UniformsLib, UniformsUtils, UnsignedByteType, UnsignedInt248Type, UnsignedIntType, UnsignedShort4444Type, UnsignedShort5551Type, UnsignedShortType, VSMShadowMap, Vector2, Vector3, Vector4, VectorKeyframeTrack, VideoTexture, WebGL1Renderer, WebGL3DRenderTarget, WebGLArrayRenderTarget, WebGLCoordinateSystem, WebGLCubeRenderTarget, WebGLMultipleRenderTargets, WebGLRenderTarget, WebGLRenderer, WebGLUtils, WebGPUCoordinateSystem, WireframeGeometry, WrapAroundEnding, ZeroCurvatureEnding, ZeroFactor, ZeroSlopeEnding, ZeroStencilOp, _SRGBAFormat, createCanvasElement }; -//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGhyZWUubW9kdWxlLmpzIiwic291cmNlcyI6WyIuLi9zcmMvY29uc3RhbnRzLmpzIiwiLi4vc3JjL2NvcmUvRXZlbnREaXNwYXRjaGVyLmpzIiwiLi4vc3JjL21hdGgvTWF0aFV0aWxzLmpzIiwiLi4vc3JjL21hdGgvVmVjdG9yMi5qcyIsIi4uL3NyYy9tYXRoL01hdHJpeDMuanMiLCIuLi9zcmMvdXRpbHMuanMiLCIuLi9zcmMvbWF0aC9Db2xvck1hbmFnZW1lbnQuanMiLCIuLi9zcmMvZXh0cmFzL0ltYWdlVXRpbHMuanMiLCIuLi9zcmMvdGV4dHVyZXMvU291cmNlLmpzIiwiLi4vc3JjL3RleHR1cmVzL1RleHR1cmUuanMiLCIuLi9zcmMvbWF0aC9WZWN0b3I0LmpzIiwiLi4vc3JjL2NvcmUvUmVuZGVyVGFyZ2V0LmpzIiwiLi4vc3JjL3JlbmRlcmVycy9XZWJHTFJlbmRlclRhcmdldC5qcyIsIi4uL3NyYy90ZXh0dXJlcy9EYXRhQXJyYXlUZXh0dXJlLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9XZWJHTEFycmF5UmVuZGVyVGFyZ2V0LmpzIiwiLi4vc3JjL3RleHR1cmVzL0RhdGEzRFRleHR1cmUuanMiLCIuLi9zcmMvcmVuZGVyZXJzL1dlYkdMM0RSZW5kZXJUYXJnZXQuanMiLCIuLi9zcmMvcmVuZGVyZXJzL1dlYkdMTXVsdGlwbGVSZW5kZXJUYXJnZXRzLmpzIiwiLi4vc3JjL21hdGgvUXVhdGVybmlvbi5qcyIsIi4uL3NyYy9tYXRoL1ZlY3RvcjMuanMiLCIuLi9zcmMvbWF0aC9Cb3gzLmpzIiwiLi4vc3JjL21hdGgvU3BoZXJlLmpzIiwiLi4vc3JjL21hdGgvUmF5LmpzIiwiLi4vc3JjL21hdGgvTWF0cml4NC5qcyIsIi4uL3NyYy9tYXRoL0V1bGVyLmpzIiwiLi4vc3JjL2NvcmUvTGF5ZXJzLmpzIiwiLi4vc3JjL2NvcmUvT2JqZWN0M0QuanMiLCIuLi9zcmMvbWF0aC9UcmlhbmdsZS5qcyIsIi4uL3NyYy9tYXRoL0NvbG9yLmpzIiwiLi4vc3JjL21hdGVyaWFscy9NYXRlcmlhbC5qcyIsIi4uL3NyYy9tYXRlcmlhbHMvTWVzaEJhc2ljTWF0ZXJpYWwuanMiLCIuLi9zcmMvZXh0cmFzL0RhdGFVdGlscy5qcyIsIi4uL3NyYy9jb3JlL0J1ZmZlckF0dHJpYnV0ZS5qcyIsIi4uL3NyYy9jb3JlL0J1ZmZlckdlb21ldHJ5LmpzIiwiLi4vc3JjL29iamVjdHMvTWVzaC5qcyIsIi4uL3NyYy9nZW9tZXRyaWVzL0JveEdlb21ldHJ5LmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1VuaWZvcm1zVXRpbHMuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvZGVmYXVsdF92ZXJ0ZXguZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9kZWZhdWx0X2ZyYWdtZW50Lmdsc2wuanMiLCIuLi9zcmMvbWF0ZXJpYWxzL1NoYWRlck1hdGVyaWFsLmpzIiwiLi4vc3JjL2NhbWVyYXMvQ2FtZXJhLmpzIiwiLi4vc3JjL2NhbWVyYXMvUGVyc3BlY3RpdmVDYW1lcmEuanMiLCIuLi9zcmMvY2FtZXJhcy9DdWJlQ2FtZXJhLmpzIiwiLi4vc3JjL3RleHR1cmVzL0N1YmVUZXh0dXJlLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9XZWJHTEN1YmVSZW5kZXJUYXJnZXQuanMiLCIuLi9zcmMvbWF0aC9QbGFuZS5qcyIsIi4uL3NyYy9tYXRoL0ZydXN0dW0uanMiLCIuLi9zcmMvcmVuZGVyZXJzL3dlYmdsL1dlYkdMQW5pbWF0aW9uLmpzIiwiLi4vc3JjL3JlbmRlcmVycy93ZWJnbC9XZWJHTEF0dHJpYnV0ZXMuanMiLCIuLi9zcmMvZ2VvbWV0cmllcy9QbGFuZUdlb21ldHJ5LmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL2FscGhhaGFzaF9mcmFnbWVudC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL2FscGhhaGFzaF9wYXJzX2ZyYWdtZW50Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvYWxwaGFtYXBfZnJhZ21lbnQuZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9hbHBoYW1hcF9wYXJzX2ZyYWdtZW50Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvYWxwaGF0ZXN0X2ZyYWdtZW50Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvYWxwaGF0ZXN0X3BhcnNfZnJhZ21lbnQuZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9hb21hcF9mcmFnbWVudC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL2FvbWFwX3BhcnNfZnJhZ21lbnQuZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9iYXRjaGluZ19wYXJzX3ZlcnRleC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL2JhdGNoaW5nX3ZlcnRleC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL2JlZ2luX3ZlcnRleC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL2JlZ2lubm9ybWFsX3ZlcnRleC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL2JzZGZzLmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvaXJpZGVzY2VuY2VfZnJhZ21lbnQuZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9idW1wbWFwX3BhcnNfZnJhZ21lbnQuZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9jbGlwcGluZ19wbGFuZXNfZnJhZ21lbnQuZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9jbGlwcGluZ19wbGFuZXNfcGFyc19mcmFnbWVudC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL2NsaXBwaW5nX3BsYW5lc19wYXJzX3ZlcnRleC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL2NsaXBwaW5nX3BsYW5lc192ZXJ0ZXguZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9jb2xvcl9mcmFnbWVudC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL2NvbG9yX3BhcnNfZnJhZ21lbnQuZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9jb2xvcl9wYXJzX3ZlcnRleC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL2NvbG9yX3ZlcnRleC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL2NvbW1vbi5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL2N1YmVfdXZfcmVmbGVjdGlvbl9mcmFnbWVudC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL2RlZmF1bHRub3JtYWxfdmVydGV4Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvZGlzcGxhY2VtZW50bWFwX3BhcnNfdmVydGV4Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvZGlzcGxhY2VtZW50bWFwX3ZlcnRleC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL2VtaXNzaXZlbWFwX2ZyYWdtZW50Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvZW1pc3NpdmVtYXBfcGFyc19mcmFnbWVudC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL2NvbG9yc3BhY2VfZnJhZ21lbnQuZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9jb2xvcnNwYWNlX3BhcnNfZnJhZ21lbnQuZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9lbnZtYXBfZnJhZ21lbnQuZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9lbnZtYXBfY29tbW9uX3BhcnNfZnJhZ21lbnQuZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9lbnZtYXBfcGFyc19mcmFnbWVudC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL2Vudm1hcF9wYXJzX3ZlcnRleC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL2Vudm1hcF92ZXJ0ZXguZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9mb2dfdmVydGV4Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvZm9nX3BhcnNfdmVydGV4Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvZm9nX2ZyYWdtZW50Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvZm9nX3BhcnNfZnJhZ21lbnQuZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9ncmFkaWVudG1hcF9wYXJzX2ZyYWdtZW50Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvbGlnaHRtYXBfZnJhZ21lbnQuZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9saWdodG1hcF9wYXJzX2ZyYWdtZW50Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvbGlnaHRzX2xhbWJlcnRfZnJhZ21lbnQuZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9saWdodHNfbGFtYmVydF9wYXJzX2ZyYWdtZW50Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvbGlnaHRzX3BhcnNfYmVnaW4uZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9lbnZtYXBfcGh5c2ljYWxfcGFyc19mcmFnbWVudC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL2xpZ2h0c190b29uX2ZyYWdtZW50Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvbGlnaHRzX3Rvb25fcGFyc19mcmFnbWVudC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL2xpZ2h0c19waG9uZ19mcmFnbWVudC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL2xpZ2h0c19waG9uZ19wYXJzX2ZyYWdtZW50Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvbGlnaHRzX3BoeXNpY2FsX2ZyYWdtZW50Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvbGlnaHRzX3BoeXNpY2FsX3BhcnNfZnJhZ21lbnQuZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9saWdodHNfZnJhZ21lbnRfYmVnaW4uZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9saWdodHNfZnJhZ21lbnRfbWFwcy5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL2xpZ2h0c19mcmFnbWVudF9lbmQuZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9sb2dkZXB0aGJ1Zl9mcmFnbWVudC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL2xvZ2RlcHRoYnVmX3BhcnNfZnJhZ21lbnQuZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9sb2dkZXB0aGJ1Zl9wYXJzX3ZlcnRleC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL2xvZ2RlcHRoYnVmX3ZlcnRleC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL21hcF9mcmFnbWVudC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL21hcF9wYXJzX2ZyYWdtZW50Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvbWFwX3BhcnRpY2xlX2ZyYWdtZW50Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvbWFwX3BhcnRpY2xlX3BhcnNfZnJhZ21lbnQuZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9tZXRhbG5lc3NtYXBfZnJhZ21lbnQuZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9tZXRhbG5lc3NtYXBfcGFyc19mcmFnbWVudC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL21vcnBoY29sb3JfdmVydGV4Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvbW9ycGhub3JtYWxfdmVydGV4Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvbW9ycGh0YXJnZXRfcGFyc192ZXJ0ZXguZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9tb3JwaHRhcmdldF92ZXJ0ZXguZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9ub3JtYWxfZnJhZ21lbnRfYmVnaW4uZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9ub3JtYWxfZnJhZ21lbnRfbWFwcy5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL25vcm1hbF9wYXJzX2ZyYWdtZW50Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvbm9ybWFsX3BhcnNfdmVydGV4Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvbm9ybWFsX3ZlcnRleC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL25vcm1hbG1hcF9wYXJzX2ZyYWdtZW50Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvY2xlYXJjb2F0X25vcm1hbF9mcmFnbWVudF9iZWdpbi5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL2NsZWFyY29hdF9ub3JtYWxfZnJhZ21lbnRfbWFwcy5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL2NsZWFyY29hdF9wYXJzX2ZyYWdtZW50Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvaXJpZGVzY2VuY2VfcGFyc19mcmFnbWVudC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL29wYXF1ZV9mcmFnbWVudC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL3BhY2tpbmcuZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9wcmVtdWx0aXBsaWVkX2FscGhhX2ZyYWdtZW50Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvcHJvamVjdF92ZXJ0ZXguZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9kaXRoZXJpbmdfZnJhZ21lbnQuZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9kaXRoZXJpbmdfcGFyc19mcmFnbWVudC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL3JvdWdobmVzc21hcF9mcmFnbWVudC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL3JvdWdobmVzc21hcF9wYXJzX2ZyYWdtZW50Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvc2hhZG93bWFwX3BhcnNfZnJhZ21lbnQuZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9zaGFkb3dtYXBfcGFyc192ZXJ0ZXguZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9zaGFkb3dtYXBfdmVydGV4Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvc2hhZG93bWFza19wYXJzX2ZyYWdtZW50Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvc2tpbmJhc2VfdmVydGV4Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvc2tpbm5pbmdfcGFyc192ZXJ0ZXguZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9za2lubmluZ192ZXJ0ZXguZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9za2lubm9ybWFsX3ZlcnRleC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL3NwZWN1bGFybWFwX2ZyYWdtZW50Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvc3BlY3VsYXJtYXBfcGFyc19mcmFnbWVudC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL3RvbmVtYXBwaW5nX2ZyYWdtZW50Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvdG9uZW1hcHBpbmdfcGFyc19mcmFnbWVudC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL3RyYW5zbWlzc2lvbl9mcmFnbWVudC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL3RyYW5zbWlzc2lvbl9wYXJzX2ZyYWdtZW50Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvdXZfcGFyc19mcmFnbWVudC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rL3V2X3BhcnNfdmVydGV4Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvdXZfdmVydGV4Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvd29ybGRwb3NfdmVydGV4Lmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyTGliL2JhY2tncm91bmQuZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJMaWIvYmFja2dyb3VuZEN1YmUuZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJMaWIvY3ViZS5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckxpYi9kZXB0aC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckxpYi9kaXN0YW5jZVJHQkEuZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJMaWIvZXF1aXJlY3QuZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJMaWIvbGluZWRhc2hlZC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckxpYi9tZXNoYmFzaWMuZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJMaWIvbWVzaGxhbWJlcnQuZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJMaWIvbWVzaG1hdGNhcC5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckxpYi9tZXNobm9ybWFsLmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyTGliL21lc2hwaG9uZy5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckxpYi9tZXNocGh5c2ljYWwuZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJMaWIvbWVzaHRvb24uZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJMaWIvcG9pbnRzLmdsc2wuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyTGliL3NoYWRvdy5nbHNsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckxpYi9zcHJpdGUuZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9Vbmlmb3Jtc0xpYi5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJMaWIuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3dlYmdsL1dlYkdMQmFja2dyb3VuZC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvd2ViZ2wvV2ViR0xCaW5kaW5nU3RhdGVzLmpzIiwiLi4vc3JjL3JlbmRlcmVycy93ZWJnbC9XZWJHTEJ1ZmZlclJlbmRlcmVyLmpzIiwiLi4vc3JjL3JlbmRlcmVycy93ZWJnbC9XZWJHTENhcGFiaWxpdGllcy5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvd2ViZ2wvV2ViR0xDbGlwcGluZy5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvd2ViZ2wvV2ViR0xDdWJlTWFwcy5qcyIsIi4uL3NyYy9jYW1lcmFzL09ydGhvZ3JhcGhpY0NhbWVyYS5qcyIsIi4uL3NyYy9leHRyYXMvUE1SRU1HZW5lcmF0b3IuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3dlYmdsL1dlYkdMQ3ViZVVWTWFwcy5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvd2ViZ2wvV2ViR0xFeHRlbnNpb25zLmpzIiwiLi4vc3JjL3JlbmRlcmVycy93ZWJnbC9XZWJHTEdlb21ldHJpZXMuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3dlYmdsL1dlYkdMSW5kZXhlZEJ1ZmZlclJlbmRlcmVyLmpzIiwiLi4vc3JjL3JlbmRlcmVycy93ZWJnbC9XZWJHTEluZm8uanMiLCIuLi9zcmMvcmVuZGVyZXJzL3dlYmdsL1dlYkdMTW9ycGh0YXJnZXRzLmpzIiwiLi4vc3JjL3JlbmRlcmVycy93ZWJnbC9XZWJHTE9iamVjdHMuanMiLCIuLi9zcmMvdGV4dHVyZXMvRGVwdGhUZXh0dXJlLmpzIiwiLi4vc3JjL3JlbmRlcmVycy93ZWJnbC9XZWJHTFVuaWZvcm1zLmpzIiwiLi4vc3JjL3JlbmRlcmVycy93ZWJnbC9XZWJHTFNoYWRlci5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvd2ViZ2wvV2ViR0xQcm9ncmFtLmpzIiwiLi4vc3JjL3JlbmRlcmVycy93ZWJnbC9XZWJHTFNoYWRlckNhY2hlLmpzIiwiLi4vc3JjL3JlbmRlcmVycy93ZWJnbC9XZWJHTFByb2dyYW1zLmpzIiwiLi4vc3JjL3JlbmRlcmVycy93ZWJnbC9XZWJHTFByb3BlcnRpZXMuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3dlYmdsL1dlYkdMUmVuZGVyTGlzdHMuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3dlYmdsL1dlYkdMTGlnaHRzLmpzIiwiLi4vc3JjL3JlbmRlcmVycy93ZWJnbC9XZWJHTFJlbmRlclN0YXRlcy5qcyIsIi4uL3NyYy9tYXRlcmlhbHMvTWVzaERlcHRoTWF0ZXJpYWwuanMiLCIuLi9zcmMvbWF0ZXJpYWxzL01lc2hEaXN0YW5jZU1hdGVyaWFsLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckxpYi92c20uZ2xzbC5qcyIsIi4uL3NyYy9yZW5kZXJlcnMvd2ViZ2wvV2ViR0xTaGFkb3dNYXAuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3dlYmdsL1dlYkdMU3RhdGUuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3dlYmdsL1dlYkdMVGV4dHVyZXMuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3dlYmdsL1dlYkdMVXRpbHMuanMiLCIuLi9zcmMvY2FtZXJhcy9BcnJheUNhbWVyYS5qcyIsIi4uL3NyYy9vYmplY3RzL0dyb3VwLmpzIiwiLi4vc3JjL3JlbmRlcmVycy93ZWJ4ci9XZWJYUkNvbnRyb2xsZXIuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3dlYnhyL1dlYlhSRGVwdGhTZW5zaW5nLmpzIiwiLi4vc3JjL3JlbmRlcmVycy93ZWJ4ci9XZWJYUk1hbmFnZXIuanMiLCIuLi9zcmMvcmVuZGVyZXJzL3dlYmdsL1dlYkdMTWF0ZXJpYWxzLmpzIiwiLi4vc3JjL3JlbmRlcmVycy93ZWJnbC9XZWJHTFVuaWZvcm1zR3JvdXBzLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9XZWJHTFJlbmRlcmVyLmpzIiwiLi4vc3JjL3JlbmRlcmVycy9XZWJHTDFSZW5kZXJlci5qcyIsIi4uL3NyYy9zY2VuZXMvRm9nRXhwMi5qcyIsIi4uL3NyYy9zY2VuZXMvRm9nLmpzIiwiLi4vc3JjL3NjZW5lcy9TY2VuZS5qcyIsIi4uL3NyYy9jb3JlL0ludGVybGVhdmVkQnVmZmVyLmpzIiwiLi4vc3JjL2NvcmUvSW50ZXJsZWF2ZWRCdWZmZXJBdHRyaWJ1dGUuanMiLCIuLi9zcmMvbWF0ZXJpYWxzL1Nwcml0ZU1hdGVyaWFsLmpzIiwiLi4vc3JjL29iamVjdHMvU3ByaXRlLmpzIiwiLi4vc3JjL29iamVjdHMvTE9ELmpzIiwiLi4vc3JjL29iamVjdHMvU2tpbm5lZE1lc2guanMiLCIuLi9zcmMvb2JqZWN0cy9Cb25lLmpzIiwiLi4vc3JjL3RleHR1cmVzL0RhdGFUZXh0dXJlLmpzIiwiLi4vc3JjL29iamVjdHMvU2tlbGV0b24uanMiLCIuLi9zcmMvY29yZS9JbnN0YW5jZWRCdWZmZXJBdHRyaWJ1dGUuanMiLCIuLi9zcmMvb2JqZWN0cy9JbnN0YW5jZWRNZXNoLmpzIiwiLi4vc3JjL29iamVjdHMvQmF0Y2hlZE1lc2guanMiLCIuLi9zcmMvbWF0ZXJpYWxzL0xpbmVCYXNpY01hdGVyaWFsLmpzIiwiLi4vc3JjL29iamVjdHMvTGluZS5qcyIsIi4uL3NyYy9vYmplY3RzL0xpbmVTZWdtZW50cy5qcyIsIi4uL3NyYy9vYmplY3RzL0xpbmVMb29wLmpzIiwiLi4vc3JjL21hdGVyaWFscy9Qb2ludHNNYXRlcmlhbC5qcyIsIi4uL3NyYy9vYmplY3RzL1BvaW50cy5qcyIsIi4uL3NyYy90ZXh0dXJlcy9WaWRlb1RleHR1cmUuanMiLCIuLi9zcmMvdGV4dHVyZXMvRnJhbWVidWZmZXJUZXh0dXJlLmpzIiwiLi4vc3JjL3RleHR1cmVzL0NvbXByZXNzZWRUZXh0dXJlLmpzIiwiLi4vc3JjL3RleHR1cmVzL0NvbXByZXNzZWRBcnJheVRleHR1cmUuanMiLCIuLi9zcmMvdGV4dHVyZXMvQ29tcHJlc3NlZEN1YmVUZXh0dXJlLmpzIiwiLi4vc3JjL3RleHR1cmVzL0NhbnZhc1RleHR1cmUuanMiLCIuLi9zcmMvZXh0cmFzL2NvcmUvQ3VydmUuanMiLCIuLi9zcmMvZXh0cmFzL2N1cnZlcy9FbGxpcHNlQ3VydmUuanMiLCIuLi9zcmMvZXh0cmFzL2N1cnZlcy9BcmNDdXJ2ZS5qcyIsIi4uL3NyYy9leHRyYXMvY3VydmVzL0NhdG11bGxSb21DdXJ2ZTMuanMiLCIuLi9zcmMvZXh0cmFzL2NvcmUvSW50ZXJwb2xhdGlvbnMuanMiLCIuLi9zcmMvZXh0cmFzL2N1cnZlcy9DdWJpY0JlemllckN1cnZlLmpzIiwiLi4vc3JjL2V4dHJhcy9jdXJ2ZXMvQ3ViaWNCZXppZXJDdXJ2ZTMuanMiLCIuLi9zcmMvZXh0cmFzL2N1cnZlcy9MaW5lQ3VydmUuanMiLCIuLi9zcmMvZXh0cmFzL2N1cnZlcy9MaW5lQ3VydmUzLmpzIiwiLi4vc3JjL2V4dHJhcy9jdXJ2ZXMvUXVhZHJhdGljQmV6aWVyQ3VydmUuanMiLCIuLi9zcmMvZXh0cmFzL2N1cnZlcy9RdWFkcmF0aWNCZXppZXJDdXJ2ZTMuanMiLCIuLi9zcmMvZXh0cmFzL2N1cnZlcy9TcGxpbmVDdXJ2ZS5qcyIsIi4uL3NyYy9leHRyYXMvY29yZS9DdXJ2ZVBhdGguanMiLCIuLi9zcmMvZXh0cmFzL2NvcmUvUGF0aC5qcyIsIi4uL3NyYy9nZW9tZXRyaWVzL0xhdGhlR2VvbWV0cnkuanMiLCIuLi9zcmMvZ2VvbWV0cmllcy9DYXBzdWxlR2VvbWV0cnkuanMiLCIuLi9zcmMvZ2VvbWV0cmllcy9DaXJjbGVHZW9tZXRyeS5qcyIsIi4uL3NyYy9nZW9tZXRyaWVzL0N5bGluZGVyR2VvbWV0cnkuanMiLCIuLi9zcmMvZ2VvbWV0cmllcy9Db25lR2VvbWV0cnkuanMiLCIuLi9zcmMvZ2VvbWV0cmllcy9Qb2x5aGVkcm9uR2VvbWV0cnkuanMiLCIuLi9zcmMvZ2VvbWV0cmllcy9Eb2RlY2FoZWRyb25HZW9tZXRyeS5qcyIsIi4uL3NyYy9nZW9tZXRyaWVzL0VkZ2VzR2VvbWV0cnkuanMiLCIuLi9zcmMvZXh0cmFzL2NvcmUvU2hhcGUuanMiLCIuLi9zcmMvZXh0cmFzL0VhcmN1dC5qcyIsIi4uL3NyYy9leHRyYXMvU2hhcGVVdGlscy5qcyIsIi4uL3NyYy9nZW9tZXRyaWVzL0V4dHJ1ZGVHZW9tZXRyeS5qcyIsIi4uL3NyYy9nZW9tZXRyaWVzL0ljb3NhaGVkcm9uR2VvbWV0cnkuanMiLCIuLi9zcmMvZ2VvbWV0cmllcy9PY3RhaGVkcm9uR2VvbWV0cnkuanMiLCIuLi9zcmMvZ2VvbWV0cmllcy9SaW5nR2VvbWV0cnkuanMiLCIuLi9zcmMvZ2VvbWV0cmllcy9TaGFwZUdlb21ldHJ5LmpzIiwiLi4vc3JjL2dlb21ldHJpZXMvU3BoZXJlR2VvbWV0cnkuanMiLCIuLi9zcmMvZ2VvbWV0cmllcy9UZXRyYWhlZHJvbkdlb21ldHJ5LmpzIiwiLi4vc3JjL2dlb21ldHJpZXMvVG9ydXNHZW9tZXRyeS5qcyIsIi4uL3NyYy9nZW9tZXRyaWVzL1RvcnVzS25vdEdlb21ldHJ5LmpzIiwiLi4vc3JjL2dlb21ldHJpZXMvVHViZUdlb21ldHJ5LmpzIiwiLi4vc3JjL2dlb21ldHJpZXMvV2lyZWZyYW1lR2VvbWV0cnkuanMiLCIuLi9zcmMvbWF0ZXJpYWxzL1NoYWRvd01hdGVyaWFsLmpzIiwiLi4vc3JjL21hdGVyaWFscy9SYXdTaGFkZXJNYXRlcmlhbC5qcyIsIi4uL3NyYy9tYXRlcmlhbHMvTWVzaFN0YW5kYXJkTWF0ZXJpYWwuanMiLCIuLi9zcmMvbWF0ZXJpYWxzL01lc2hQaHlzaWNhbE1hdGVyaWFsLmpzIiwiLi4vc3JjL21hdGVyaWFscy9NZXNoUGhvbmdNYXRlcmlhbC5qcyIsIi4uL3NyYy9tYXRlcmlhbHMvTWVzaFRvb25NYXRlcmlhbC5qcyIsIi4uL3NyYy9tYXRlcmlhbHMvTWVzaE5vcm1hbE1hdGVyaWFsLmpzIiwiLi4vc3JjL21hdGVyaWFscy9NZXNoTGFtYmVydE1hdGVyaWFsLmpzIiwiLi4vc3JjL21hdGVyaWFscy9NZXNoTWF0Y2FwTWF0ZXJpYWwuanMiLCIuLi9zcmMvbWF0ZXJpYWxzL0xpbmVEYXNoZWRNYXRlcmlhbC5qcyIsIi4uL3NyYy9hbmltYXRpb24vQW5pbWF0aW9uVXRpbHMuanMiLCIuLi9zcmMvbWF0aC9JbnRlcnBvbGFudC5qcyIsIi4uL3NyYy9tYXRoL2ludGVycG9sYW50cy9DdWJpY0ludGVycG9sYW50LmpzIiwiLi4vc3JjL21hdGgvaW50ZXJwb2xhbnRzL0xpbmVhckludGVycG9sYW50LmpzIiwiLi4vc3JjL21hdGgvaW50ZXJwb2xhbnRzL0Rpc2NyZXRlSW50ZXJwb2xhbnQuanMiLCIuLi9zcmMvYW5pbWF0aW9uL0tleWZyYW1lVHJhY2suanMiLCIuLi9zcmMvYW5pbWF0aW9uL3RyYWNrcy9Cb29sZWFuS2V5ZnJhbWVUcmFjay5qcyIsIi4uL3NyYy9hbmltYXRpb24vdHJhY2tzL0NvbG9yS2V5ZnJhbWVUcmFjay5qcyIsIi4uL3NyYy9hbmltYXRpb24vdHJhY2tzL051bWJlcktleWZyYW1lVHJhY2suanMiLCIuLi9zcmMvbWF0aC9pbnRlcnBvbGFudHMvUXVhdGVybmlvbkxpbmVhckludGVycG9sYW50LmpzIiwiLi4vc3JjL2FuaW1hdGlvbi90cmFja3MvUXVhdGVybmlvbktleWZyYW1lVHJhY2suanMiLCIuLi9zcmMvYW5pbWF0aW9uL3RyYWNrcy9TdHJpbmdLZXlmcmFtZVRyYWNrLmpzIiwiLi4vc3JjL2FuaW1hdGlvbi90cmFja3MvVmVjdG9yS2V5ZnJhbWVUcmFjay5qcyIsIi4uL3NyYy9hbmltYXRpb24vQW5pbWF0aW9uQ2xpcC5qcyIsIi4uL3NyYy9sb2FkZXJzL0NhY2hlLmpzIiwiLi4vc3JjL2xvYWRlcnMvTG9hZGluZ01hbmFnZXIuanMiLCIuLi9zcmMvbG9hZGVycy9Mb2FkZXIuanMiLCIuLi9zcmMvbG9hZGVycy9GaWxlTG9hZGVyLmpzIiwiLi4vc3JjL2xvYWRlcnMvQW5pbWF0aW9uTG9hZGVyLmpzIiwiLi4vc3JjL2xvYWRlcnMvQ29tcHJlc3NlZFRleHR1cmVMb2FkZXIuanMiLCIuLi9zcmMvbG9hZGVycy9JbWFnZUxvYWRlci5qcyIsIi4uL3NyYy9sb2FkZXJzL0N1YmVUZXh0dXJlTG9hZGVyLmpzIiwiLi4vc3JjL2xvYWRlcnMvRGF0YVRleHR1cmVMb2FkZXIuanMiLCIuLi9zcmMvbG9hZGVycy9UZXh0dXJlTG9hZGVyLmpzIiwiLi4vc3JjL2xpZ2h0cy9MaWdodC5qcyIsIi4uL3NyYy9saWdodHMvSGVtaXNwaGVyZUxpZ2h0LmpzIiwiLi4vc3JjL2xpZ2h0cy9MaWdodFNoYWRvdy5qcyIsIi4uL3NyYy9saWdodHMvU3BvdExpZ2h0U2hhZG93LmpzIiwiLi4vc3JjL2xpZ2h0cy9TcG90TGlnaHQuanMiLCIuLi9zcmMvbGlnaHRzL1BvaW50TGlnaHRTaGFkb3cuanMiLCIuLi9zcmMvbGlnaHRzL1BvaW50TGlnaHQuanMiLCIuLi9zcmMvbGlnaHRzL0RpcmVjdGlvbmFsTGlnaHRTaGFkb3cuanMiLCIuLi9zcmMvbGlnaHRzL0RpcmVjdGlvbmFsTGlnaHQuanMiLCIuLi9zcmMvbGlnaHRzL0FtYmllbnRMaWdodC5qcyIsIi4uL3NyYy9saWdodHMvUmVjdEFyZWFMaWdodC5qcyIsIi4uL3NyYy9tYXRoL1NwaGVyaWNhbEhhcm1vbmljczMuanMiLCIuLi9zcmMvbGlnaHRzL0xpZ2h0UHJvYmUuanMiLCIuLi9zcmMvbG9hZGVycy9NYXRlcmlhbExvYWRlci5qcyIsIi4uL3NyYy9sb2FkZXJzL0xvYWRlclV0aWxzLmpzIiwiLi4vc3JjL2NvcmUvSW5zdGFuY2VkQnVmZmVyR2VvbWV0cnkuanMiLCIuLi9zcmMvbG9hZGVycy9CdWZmZXJHZW9tZXRyeUxvYWRlci5qcyIsIi4uL3NyYy9sb2FkZXJzL09iamVjdExvYWRlci5qcyIsIi4uL3NyYy9sb2FkZXJzL0ltYWdlQml0bWFwTG9hZGVyLmpzIiwiLi4vc3JjL2F1ZGlvL0F1ZGlvQ29udGV4dC5qcyIsIi4uL3NyYy9sb2FkZXJzL0F1ZGlvTG9hZGVyLmpzIiwiLi4vc3JjL2NhbWVyYXMvU3RlcmVvQ2FtZXJhLmpzIiwiLi4vc3JjL2NvcmUvQ2xvY2suanMiLCIuLi9zcmMvYXVkaW8vQXVkaW9MaXN0ZW5lci5qcyIsIi4uL3NyYy9hdWRpby9BdWRpby5qcyIsIi4uL3NyYy9hdWRpby9Qb3NpdGlvbmFsQXVkaW8uanMiLCIuLi9zcmMvYXVkaW8vQXVkaW9BbmFseXNlci5qcyIsIi4uL3NyYy9hbmltYXRpb24vUHJvcGVydHlNaXhlci5qcyIsIi4uL3NyYy9hbmltYXRpb24vUHJvcGVydHlCaW5kaW5nLmpzIiwiLi4vc3JjL2FuaW1hdGlvbi9BbmltYXRpb25PYmplY3RHcm91cC5qcyIsIi4uL3NyYy9hbmltYXRpb24vQW5pbWF0aW9uQWN0aW9uLmpzIiwiLi4vc3JjL2FuaW1hdGlvbi9BbmltYXRpb25NaXhlci5qcyIsIi4uL3NyYy9jb3JlL1VuaWZvcm0uanMiLCIuLi9zcmMvY29yZS9Vbmlmb3Jtc0dyb3VwLmpzIiwiLi4vc3JjL2NvcmUvSW5zdGFuY2VkSW50ZXJsZWF2ZWRCdWZmZXIuanMiLCIuLi9zcmMvY29yZS9HTEJ1ZmZlckF0dHJpYnV0ZS5qcyIsIi4uL3NyYy9jb3JlL1JheWNhc3Rlci5qcyIsIi4uL3NyYy9tYXRoL1NwaGVyaWNhbC5qcyIsIi4uL3NyYy9tYXRoL0N5bGluZHJpY2FsLmpzIiwiLi4vc3JjL21hdGgvQm94Mi5qcyIsIi4uL3NyYy9tYXRoL0xpbmUzLmpzIiwiLi4vc3JjL2hlbHBlcnMvU3BvdExpZ2h0SGVscGVyLmpzIiwiLi4vc3JjL2hlbHBlcnMvU2tlbGV0b25IZWxwZXIuanMiLCIuLi9zcmMvaGVscGVycy9Qb2ludExpZ2h0SGVscGVyLmpzIiwiLi4vc3JjL2hlbHBlcnMvSGVtaXNwaGVyZUxpZ2h0SGVscGVyLmpzIiwiLi4vc3JjL2hlbHBlcnMvR3JpZEhlbHBlci5qcyIsIi4uL3NyYy9oZWxwZXJzL1BvbGFyR3JpZEhlbHBlci5qcyIsIi4uL3NyYy9oZWxwZXJzL0RpcmVjdGlvbmFsTGlnaHRIZWxwZXIuanMiLCIuLi9zcmMvaGVscGVycy9DYW1lcmFIZWxwZXIuanMiLCIuLi9zcmMvaGVscGVycy9Cb3hIZWxwZXIuanMiLCIuLi9zcmMvaGVscGVycy9Cb3gzSGVscGVyLmpzIiwiLi4vc3JjL2hlbHBlcnMvUGxhbmVIZWxwZXIuanMiLCIuLi9zcmMvaGVscGVycy9BcnJvd0hlbHBlci5qcyIsIi4uL3NyYy9oZWxwZXJzL0F4ZXNIZWxwZXIuanMiLCIuLi9zcmMvZXh0cmFzL2NvcmUvU2hhcGVQYXRoLmpzIiwiLi4vc3JjL1RocmVlLmpzIl0sInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCBjb25zdCBSRVZJU0lPTiA9ICcxNjJkZXYnO1xyXG5cclxuZXhwb3J0IGNvbnN0IE1PVVNFID0geyBMRUZUOiAwLCBNSURETEU6IDEsIFJJR0hUOiAyLCBST1RBVEU6IDAsIERPTExZOiAxLCBQQU46IDIgfTtcclxuZXhwb3J0IGNvbnN0IFRPVUNIID0geyBST1RBVEU6IDAsIFBBTjogMSwgRE9MTFlfUEFOOiAyLCBET0xMWV9ST1RBVEU6IDMgfTtcclxuZXhwb3J0IGNvbnN0IEN1bGxGYWNlTm9uZSA9IDA7XHJcbmV4cG9ydCBjb25zdCBDdWxsRmFjZUJhY2sgPSAxO1xyXG5leHBvcnQgY29uc3QgQ3VsbEZhY2VGcm9udCA9IDI7XHJcbmV4cG9ydCBjb25zdCBDdWxsRmFjZUZyb250QmFjayA9IDM7XHJcbmV4cG9ydCBjb25zdCBCYXNpY1NoYWRvd01hcCA9IDA7XHJcbmV4cG9ydCBjb25zdCBQQ0ZTaGFkb3dNYXAgPSAxO1xyXG5leHBvcnQgY29uc3QgUENGU29mdFNoYWRvd01hcCA9IDI7XHJcbmV4cG9ydCBjb25zdCBWU01TaGFkb3dNYXAgPSAzO1xyXG5leHBvcnQgY29uc3QgRnJvbnRTaWRlID0gMDtcclxuZXhwb3J0IGNvbnN0IEJhY2tTaWRlID0gMTtcclxuZXhwb3J0IGNvbnN0IERvdWJsZVNpZGUgPSAyO1xyXG5leHBvcnQgY29uc3QgTm9CbGVuZGluZyA9IDA7XHJcbmV4cG9ydCBjb25zdCBOb3JtYWxCbGVuZGluZyA9IDE7XHJcbmV4cG9ydCBjb25zdCBBZGRpdGl2ZUJsZW5kaW5nID0gMjtcclxuZXhwb3J0IGNvbnN0IFN1YnRyYWN0aXZlQmxlbmRpbmcgPSAzO1xyXG5leHBvcnQgY29uc3QgTXVsdGlwbHlCbGVuZGluZyA9IDQ7XHJcbmV4cG9ydCBjb25zdCBDdXN0b21CbGVuZGluZyA9IDU7XHJcbmV4cG9ydCBjb25zdCBBZGRFcXVhdGlvbiA9IDEwMDtcclxuZXhwb3J0IGNvbnN0IFN1YnRyYWN0RXF1YXRpb24gPSAxMDE7XHJcbmV4cG9ydCBjb25zdCBSZXZlcnNlU3VidHJhY3RFcXVhdGlvbiA9IDEwMjtcclxuZXhwb3J0IGNvbnN0IE1pbkVxdWF0aW9uID0gMTAzO1xyXG5leHBvcnQgY29uc3QgTWF4RXF1YXRpb24gPSAxMDQ7XHJcbmV4cG9ydCBjb25zdCBaZXJvRmFjdG9yID0gMjAwO1xyXG5leHBvcnQgY29uc3QgT25lRmFjdG9yID0gMjAxO1xyXG5leHBvcnQgY29uc3QgU3JjQ29sb3JGYWN0b3IgPSAyMDI7XHJcbmV4cG9ydCBjb25zdCBPbmVNaW51c1NyY0NvbG9yRmFjdG9yID0gMjAzO1xyXG5leHBvcnQgY29uc3QgU3JjQWxwaGFGYWN0b3IgPSAyMDQ7XHJcbmV4cG9ydCBjb25zdCBPbmVNaW51c1NyY0FscGhhRmFjdG9yID0gMjA1O1xyXG5leHBvcnQgY29uc3QgRHN0QWxwaGFGYWN0b3IgPSAyMDY7XHJcbmV4cG9ydCBjb25zdCBPbmVNaW51c0RzdEFscGhhRmFjdG9yID0gMjA3O1xyXG5leHBvcnQgY29uc3QgRHN0Q29sb3JGYWN0b3IgPSAyMDg7XHJcbmV4cG9ydCBjb25zdCBPbmVNaW51c0RzdENvbG9yRmFjdG9yID0gMjA5O1xyXG5leHBvcnQgY29uc3QgU3JjQWxwaGFTYXR1cmF0ZUZhY3RvciA9IDIxMDtcclxuZXhwb3J0IGNvbnN0IENvbnN0YW50Q29sb3JGYWN0b3IgPSAyMTE7XHJcbmV4cG9ydCBjb25zdCBPbmVNaW51c0NvbnN0YW50Q29sb3JGYWN0b3IgPSAyMTI7XHJcbmV4cG9ydCBjb25zdCBDb25zdGFudEFscGhhRmFjdG9yID0gMjEzO1xyXG5leHBvcnQgY29uc3QgT25lTWludXNDb25zdGFudEFscGhhRmFjdG9yID0gMjE0O1xyXG5leHBvcnQgY29uc3QgTmV2ZXJEZXB0aCA9IDA7XHJcbmV4cG9ydCBjb25zdCBBbHdheXNEZXB0aCA9IDE7XHJcbmV4cG9ydCBjb25zdCBMZXNzRGVwdGggPSAyO1xyXG5leHBvcnQgY29uc3QgTGVzc0VxdWFsRGVwdGggPSAzO1xyXG5leHBvcnQgY29uc3QgRXF1YWxEZXB0aCA9IDQ7XHJcbmV4cG9ydCBjb25zdCBHcmVhdGVyRXF1YWxEZXB0aCA9IDU7XHJcbmV4cG9ydCBjb25zdCBHcmVhdGVyRGVwdGggPSA2O1xyXG5leHBvcnQgY29uc3QgTm90RXF1YWxEZXB0aCA9IDc7XHJcbmV4cG9ydCBjb25zdCBNdWx0aXBseU9wZXJhdGlvbiA9IDA7XHJcbmV4cG9ydCBjb25zdCBNaXhPcGVyYXRpb24gPSAxO1xyXG5leHBvcnQgY29uc3QgQWRkT3BlcmF0aW9uID0gMjtcclxuZXhwb3J0IGNvbnN0IE5vVG9uZU1hcHBpbmcgPSAwO1xyXG5leHBvcnQgY29uc3QgTGluZWFyVG9uZU1hcHBpbmcgPSAxO1xyXG5leHBvcnQgY29uc3QgUmVpbmhhcmRUb25lTWFwcGluZyA9IDI7XHJcbmV4cG9ydCBjb25zdCBDaW5lb25Ub25lTWFwcGluZyA9IDM7XHJcbmV4cG9ydCBjb25zdCBBQ0VTRmlsbWljVG9uZU1hcHBpbmcgPSA0O1xyXG5leHBvcnQgY29uc3QgQ3VzdG9tVG9uZU1hcHBpbmcgPSA1O1xyXG5leHBvcnQgY29uc3QgQWdYVG9uZU1hcHBpbmcgPSA2O1xyXG5leHBvcnQgY29uc3QgQXR0YWNoZWRCaW5kTW9kZSA9ICdhdHRhY2hlZCc7XHJcbmV4cG9ydCBjb25zdCBEZXRhY2hlZEJpbmRNb2RlID0gJ2RldGFjaGVkJztcclxuXHJcbmV4cG9ydCBjb25zdCBVVk1hcHBpbmcgPSAzMDA7XHJcbmV4cG9ydCBjb25zdCBDdWJlUmVmbGVjdGlvbk1hcHBpbmcgPSAzMDE7XHJcbmV4cG9ydCBjb25zdCBDdWJlUmVmcmFjdGlvbk1hcHBpbmcgPSAzMDI7XHJcbmV4cG9ydCBjb25zdCBFcXVpcmVjdGFuZ3VsYXJSZWZsZWN0aW9uTWFwcGluZyA9IDMwMztcclxuZXhwb3J0IGNvbnN0IEVxdWlyZWN0YW5ndWxhclJlZnJhY3Rpb25NYXBwaW5nID0gMzA0O1xyXG5leHBvcnQgY29uc3QgQ3ViZVVWUmVmbGVjdGlvbk1hcHBpbmcgPSAzMDY7XHJcbmV4cG9ydCBjb25zdCBSZXBlYXRXcmFwcGluZyA9IDEwMDA7XHJcbmV4cG9ydCBjb25zdCBDbGFtcFRvRWRnZVdyYXBwaW5nID0gMTAwMTtcclxuZXhwb3J0IGNvbnN0IE1pcnJvcmVkUmVwZWF0V3JhcHBpbmcgPSAxMDAyO1xyXG5leHBvcnQgY29uc3QgTmVhcmVzdEZpbHRlciA9IDEwMDM7XHJcbmV4cG9ydCBjb25zdCBOZWFyZXN0TWlwbWFwTmVhcmVzdEZpbHRlciA9IDEwMDQ7XHJcbmV4cG9ydCBjb25zdCBOZWFyZXN0TWlwTWFwTmVhcmVzdEZpbHRlciA9IDEwMDQ7XHJcbmV4cG9ydCBjb25zdCBOZWFyZXN0TWlwbWFwTGluZWFyRmlsdGVyID0gMTAwNTtcclxuZXhwb3J0IGNvbnN0IE5lYXJlc3RNaXBNYXBMaW5lYXJGaWx0ZXIgPSAxMDA1O1xyXG5leHBvcnQgY29uc3QgTGluZWFyRmlsdGVyID0gMTAwNjtcclxuZXhwb3J0IGNvbnN0IExpbmVhck1pcG1hcE5lYXJlc3RGaWx0ZXIgPSAxMDA3O1xyXG5leHBvcnQgY29uc3QgTGluZWFyTWlwTWFwTmVhcmVzdEZpbHRlciA9IDEwMDc7XHJcbmV4cG9ydCBjb25zdCBMaW5lYXJNaXBtYXBMaW5lYXJGaWx0ZXIgPSAxMDA4O1xyXG5leHBvcnQgY29uc3QgTGluZWFyTWlwTWFwTGluZWFyRmlsdGVyID0gMTAwODtcclxuZXhwb3J0IGNvbnN0IFVuc2lnbmVkQnl0ZVR5cGUgPSAxMDA5O1xyXG5leHBvcnQgY29uc3QgQnl0ZVR5cGUgPSAxMDEwO1xyXG5leHBvcnQgY29uc3QgU2hvcnRUeXBlID0gMTAxMTtcclxuZXhwb3J0IGNvbnN0IFVuc2lnbmVkU2hvcnRUeXBlID0gMTAxMjtcclxuZXhwb3J0IGNvbnN0IEludFR5cGUgPSAxMDEzO1xyXG5leHBvcnQgY29uc3QgVW5zaWduZWRJbnRUeXBlID0gMTAxNDtcclxuZXhwb3J0IGNvbnN0IEZsb2F0VHlwZSA9IDEwMTU7XHJcbmV4cG9ydCBjb25zdCBIYWxmRmxvYXRUeXBlID0gMTAxNjtcclxuZXhwb3J0IGNvbnN0IFVuc2lnbmVkU2hvcnQ0NDQ0VHlwZSA9IDEwMTc7XHJcbmV4cG9ydCBjb25zdCBVbnNpZ25lZFNob3J0NTU1MVR5cGUgPSAxMDE4O1xyXG5leHBvcnQgY29uc3QgVW5zaWduZWRJbnQyNDhUeXBlID0gMTAyMDtcclxuZXhwb3J0IGNvbnN0IEFscGhhRm9ybWF0ID0gMTAyMTtcclxuZXhwb3J0IGNvbnN0IFJHQkFGb3JtYXQgPSAxMDIzO1xyXG5leHBvcnQgY29uc3QgTHVtaW5hbmNlRm9ybWF0ID0gMTAyNDtcclxuZXhwb3J0IGNvbnN0IEx1bWluYW5jZUFscGhhRm9ybWF0ID0gMTAyNTtcclxuZXhwb3J0IGNvbnN0IERlcHRoRm9ybWF0ID0gMTAyNjtcclxuZXhwb3J0IGNvbnN0IERlcHRoU3RlbmNpbEZvcm1hdCA9IDEwMjc7XHJcbmV4cG9ydCBjb25zdCBSZWRGb3JtYXQgPSAxMDI4O1xyXG5leHBvcnQgY29uc3QgUmVkSW50ZWdlckZvcm1hdCA9IDEwMjk7XHJcbmV4cG9ydCBjb25zdCBSR0Zvcm1hdCA9IDEwMzA7XHJcbmV4cG9ydCBjb25zdCBSR0ludGVnZXJGb3JtYXQgPSAxMDMxO1xyXG5leHBvcnQgY29uc3QgUkdCQUludGVnZXJGb3JtYXQgPSAxMDMzO1xyXG5cclxuZXhwb3J0IGNvbnN0IFJHQl9TM1RDX0RYVDFfRm9ybWF0ID0gMzM3NzY7XHJcbmV4cG9ydCBjb25zdCBSR0JBX1MzVENfRFhUMV9Gb3JtYXQgPSAzMzc3NztcclxuZXhwb3J0IGNvbnN0IFJHQkFfUzNUQ19EWFQzX0Zvcm1hdCA9IDMzNzc4O1xyXG5leHBvcnQgY29uc3QgUkdCQV9TM1RDX0RYVDVfRm9ybWF0ID0gMzM3Nzk7XHJcbmV4cG9ydCBjb25zdCBSR0JfUFZSVENfNEJQUFYxX0Zvcm1hdCA9IDM1ODQwO1xyXG5leHBvcnQgY29uc3QgUkdCX1BWUlRDXzJCUFBWMV9Gb3JtYXQgPSAzNTg0MTtcclxuZXhwb3J0IGNvbnN0IFJHQkFfUFZSVENfNEJQUFYxX0Zvcm1hdCA9IDM1ODQyO1xyXG5leHBvcnQgY29uc3QgUkdCQV9QVlJUQ18yQlBQVjFfRm9ybWF0ID0gMzU4NDM7XHJcbmV4cG9ydCBjb25zdCBSR0JfRVRDMV9Gb3JtYXQgPSAzNjE5NjtcclxuZXhwb3J0IGNvbnN0IFJHQl9FVEMyX0Zvcm1hdCA9IDM3NDkyO1xyXG5leHBvcnQgY29uc3QgUkdCQV9FVEMyX0VBQ19Gb3JtYXQgPSAzNzQ5NjtcclxuZXhwb3J0IGNvbnN0IFJHQkFfQVNUQ180eDRfRm9ybWF0ID0gMzc4MDg7XHJcbmV4cG9ydCBjb25zdCBSR0JBX0FTVENfNXg0X0Zvcm1hdCA9IDM3ODA5O1xyXG5leHBvcnQgY29uc3QgUkdCQV9BU1RDXzV4NV9Gb3JtYXQgPSAzNzgxMDtcclxuZXhwb3J0IGNvbnN0IFJHQkFfQVNUQ182eDVfRm9ybWF0ID0gMzc4MTE7XHJcbmV4cG9ydCBjb25zdCBSR0JBX0FTVENfNng2X0Zvcm1hdCA9IDM3ODEyO1xyXG5leHBvcnQgY29uc3QgUkdCQV9BU1RDXzh4NV9Gb3JtYXQgPSAzNzgxMztcclxuZXhwb3J0IGNvbnN0IFJHQkFfQVNUQ184eDZfRm9ybWF0ID0gMzc4MTQ7XHJcbmV4cG9ydCBjb25zdCBSR0JBX0FTVENfOHg4X0Zvcm1hdCA9IDM3ODE1O1xyXG5leHBvcnQgY29uc3QgUkdCQV9BU1RDXzEweDVfRm9ybWF0ID0gMzc4MTY7XHJcbmV4cG9ydCBjb25zdCBSR0JBX0FTVENfMTB4Nl9Gb3JtYXQgPSAzNzgxNztcclxuZXhwb3J0IGNvbnN0IFJHQkFfQVNUQ18xMHg4X0Zvcm1hdCA9IDM3ODE4O1xyXG5leHBvcnQgY29uc3QgUkdCQV9BU1RDXzEweDEwX0Zvcm1hdCA9IDM3ODE5O1xyXG5leHBvcnQgY29uc3QgUkdCQV9BU1RDXzEyeDEwX0Zvcm1hdCA9IDM3ODIwO1xyXG5leHBvcnQgY29uc3QgUkdCQV9BU1RDXzEyeDEyX0Zvcm1hdCA9IDM3ODIxO1xyXG5leHBvcnQgY29uc3QgUkdCQV9CUFRDX0Zvcm1hdCA9IDM2NDkyO1xyXG5leHBvcnQgY29uc3QgUkdCX0JQVENfU0lHTkVEX0Zvcm1hdCA9IDM2NDk0O1xyXG5leHBvcnQgY29uc3QgUkdCX0JQVENfVU5TSUdORURfRm9ybWF0ID0gMzY0OTU7XHJcbmV4cG9ydCBjb25zdCBSRURfUkdUQzFfRm9ybWF0ID0gMzYyODM7XHJcbmV4cG9ydCBjb25zdCBTSUdORURfUkVEX1JHVEMxX0Zvcm1hdCA9IDM2Mjg0O1xyXG5leHBvcnQgY29uc3QgUkVEX0dSRUVOX1JHVEMyX0Zvcm1hdCA9IDM2Mjg1O1xyXG5leHBvcnQgY29uc3QgU0lHTkVEX1JFRF9HUkVFTl9SR1RDMl9Gb3JtYXQgPSAzNjI4NjtcclxuZXhwb3J0IGNvbnN0IExvb3BPbmNlID0gMjIwMDtcclxuZXhwb3J0IGNvbnN0IExvb3BSZXBlYXQgPSAyMjAxO1xyXG5leHBvcnQgY29uc3QgTG9vcFBpbmdQb25nID0gMjIwMjtcclxuZXhwb3J0IGNvbnN0IEludGVycG9sYXRlRGlzY3JldGUgPSAyMzAwO1xyXG5leHBvcnQgY29uc3QgSW50ZXJwb2xhdGVMaW5lYXIgPSAyMzAxO1xyXG5leHBvcnQgY29uc3QgSW50ZXJwb2xhdGVTbW9vdGggPSAyMzAyO1xyXG5leHBvcnQgY29uc3QgWmVyb0N1cnZhdHVyZUVuZGluZyA9IDI0MDA7XHJcbmV4cG9ydCBjb25zdCBaZXJvU2xvcGVFbmRpbmcgPSAyNDAxO1xyXG5leHBvcnQgY29uc3QgV3JhcEFyb3VuZEVuZGluZyA9IDI0MDI7XHJcbmV4cG9ydCBjb25zdCBOb3JtYWxBbmltYXRpb25CbGVuZE1vZGUgPSAyNTAwO1xyXG5leHBvcnQgY29uc3QgQWRkaXRpdmVBbmltYXRpb25CbGVuZE1vZGUgPSAyNTAxO1xyXG5leHBvcnQgY29uc3QgVHJpYW5nbGVzRHJhd01vZGUgPSAwO1xyXG5leHBvcnQgY29uc3QgVHJpYW5nbGVTdHJpcERyYXdNb2RlID0gMTtcclxuZXhwb3J0IGNvbnN0IFRyaWFuZ2xlRmFuRHJhd01vZGUgPSAyO1xyXG5leHBvcnQgY29uc3QgQmFzaWNEZXB0aFBhY2tpbmcgPSAzMjAwO1xyXG5leHBvcnQgY29uc3QgUkdCQURlcHRoUGFja2luZyA9IDMyMDE7XHJcbmV4cG9ydCBjb25zdCBUYW5nZW50U3BhY2VOb3JtYWxNYXAgPSAwO1xyXG5leHBvcnQgY29uc3QgT2JqZWN0U3BhY2VOb3JtYWxNYXAgPSAxO1xyXG5cclxuLy8gQ29sb3Igc3BhY2Ugc3RyaW5nIGlkZW50aWZpZXJzLCBtYXRjaGluZyBDU1MgQ29sb3IgTW9kdWxlIExldmVsIDQgYW5kIFdlYkdQVSBuYW1lcyB3aGVyZSBhdmFpbGFibGUuXHJcbmV4cG9ydCBjb25zdCBOb0NvbG9yU3BhY2UgPSAnJztcclxuZXhwb3J0IGNvbnN0IFNSR0JDb2xvclNwYWNlID0gJ3NyZ2InO1xyXG5leHBvcnQgY29uc3QgTGluZWFyU1JHQkNvbG9yU3BhY2UgPSAnc3JnYi1saW5lYXInO1xyXG5leHBvcnQgY29uc3QgRGlzcGxheVAzQ29sb3JTcGFjZSA9ICdkaXNwbGF5LXAzJztcclxuZXhwb3J0IGNvbnN0IExpbmVhckRpc3BsYXlQM0NvbG9yU3BhY2UgPSAnZGlzcGxheS1wMy1saW5lYXInO1xyXG5cclxuZXhwb3J0IGNvbnN0IExpbmVhclRyYW5zZmVyID0gJ2xpbmVhcic7XHJcbmV4cG9ydCBjb25zdCBTUkdCVHJhbnNmZXIgPSAnc3JnYic7XHJcblxyXG5leHBvcnQgY29uc3QgUmVjNzA5UHJpbWFyaWVzID0gJ3JlYzcwOSc7XHJcbmV4cG9ydCBjb25zdCBQM1ByaW1hcmllcyA9ICdwMyc7XHJcblxyXG5leHBvcnQgY29uc3QgWmVyb1N0ZW5jaWxPcCA9IDA7XHJcbmV4cG9ydCBjb25zdCBLZWVwU3RlbmNpbE9wID0gNzY4MDtcclxuZXhwb3J0IGNvbnN0IFJlcGxhY2VTdGVuY2lsT3AgPSA3NjgxO1xyXG5leHBvcnQgY29uc3QgSW5jcmVtZW50U3RlbmNpbE9wID0gNzY4MjtcclxuZXhwb3J0IGNvbnN0IERlY3JlbWVudFN0ZW5jaWxPcCA9IDc2ODM7XHJcbmV4cG9ydCBjb25zdCBJbmNyZW1lbnRXcmFwU3RlbmNpbE9wID0gMzQwNTU7XHJcbmV4cG9ydCBjb25zdCBEZWNyZW1lbnRXcmFwU3RlbmNpbE9wID0gMzQwNTY7XHJcbmV4cG9ydCBjb25zdCBJbnZlcnRTdGVuY2lsT3AgPSA1Mzg2O1xyXG5cclxuZXhwb3J0IGNvbnN0IE5ldmVyU3RlbmNpbEZ1bmMgPSA1MTI7XHJcbmV4cG9ydCBjb25zdCBMZXNzU3RlbmNpbEZ1bmMgPSA1MTM7XHJcbmV4cG9ydCBjb25zdCBFcXVhbFN0ZW5jaWxGdW5jID0gNTE0O1xyXG5leHBvcnQgY29uc3QgTGVzc0VxdWFsU3RlbmNpbEZ1bmMgPSA1MTU7XHJcbmV4cG9ydCBjb25zdCBHcmVhdGVyU3RlbmNpbEZ1bmMgPSA1MTY7XHJcbmV4cG9ydCBjb25zdCBOb3RFcXVhbFN0ZW5jaWxGdW5jID0gNTE3O1xyXG5leHBvcnQgY29uc3QgR3JlYXRlckVxdWFsU3RlbmNpbEZ1bmMgPSA1MTg7XHJcbmV4cG9ydCBjb25zdCBBbHdheXNTdGVuY2lsRnVuYyA9IDUxOTtcclxuXHJcbmV4cG9ydCBjb25zdCBOZXZlckNvbXBhcmUgPSA1MTI7XHJcbmV4cG9ydCBjb25zdCBMZXNzQ29tcGFyZSA9IDUxMztcclxuZXhwb3J0IGNvbnN0IEVxdWFsQ29tcGFyZSA9IDUxNDtcclxuZXhwb3J0IGNvbnN0IExlc3NFcXVhbENvbXBhcmUgPSA1MTU7XHJcbmV4cG9ydCBjb25zdCBHcmVhdGVyQ29tcGFyZSA9IDUxNjtcclxuZXhwb3J0IGNvbnN0IE5vdEVxdWFsQ29tcGFyZSA9IDUxNztcclxuZXhwb3J0IGNvbnN0IEdyZWF0ZXJFcXVhbENvbXBhcmUgPSA1MTg7XHJcbmV4cG9ydCBjb25zdCBBbHdheXNDb21wYXJlID0gNTE5O1xyXG5cclxuZXhwb3J0IGNvbnN0IFN0YXRpY0RyYXdVc2FnZSA9IDM1MDQ0O1xyXG5leHBvcnQgY29uc3QgRHluYW1pY0RyYXdVc2FnZSA9IDM1MDQ4O1xyXG5leHBvcnQgY29uc3QgU3RyZWFtRHJhd1VzYWdlID0gMzUwNDA7XHJcbmV4cG9ydCBjb25zdCBTdGF0aWNSZWFkVXNhZ2UgPSAzNTA0NTtcclxuZXhwb3J0IGNvbnN0IER5bmFtaWNSZWFkVXNhZ2UgPSAzNTA0OTtcclxuZXhwb3J0IGNvbnN0IFN0cmVhbVJlYWRVc2FnZSA9IDM1MDQxO1xyXG5leHBvcnQgY29uc3QgU3RhdGljQ29weVVzYWdlID0gMzUwNDY7XHJcbmV4cG9ydCBjb25zdCBEeW5hbWljQ29weVVzYWdlID0gMzUwNTA7XHJcbmV4cG9ydCBjb25zdCBTdHJlYW1Db3B5VXNhZ2UgPSAzNTA0MjtcclxuXHJcbmV4cG9ydCBjb25zdCBHTFNMMSA9ICcxMDAnO1xyXG5leHBvcnQgY29uc3QgR0xTTDMgPSAnMzAwIGVzJztcclxuXHJcbmV4cG9ydCBjb25zdCBfU1JHQkFGb3JtYXQgPSAxMDM1OyAvLyBmYWxsYmFjayBmb3IgV2ViR0wgMVxyXG5cclxuZXhwb3J0IGNvbnN0IFdlYkdMQ29vcmRpbmF0ZVN5c3RlbSA9IDIwMDA7XHJcbmV4cG9ydCBjb25zdCBXZWJHUFVDb29yZGluYXRlU3lzdGVtID0gMjAwMTtcclxuIiwiLyoqXHJcbiAqIGh0dHBzOi8vZ2l0aHViLmNvbS9tcmRvb2IvZXZlbnRkaXNwYXRjaGVyLmpzL1xyXG4gKi9cclxuXHJcbmNsYXNzIEV2ZW50RGlzcGF0Y2hlciB7XHJcblxyXG5cdGFkZEV2ZW50TGlzdGVuZXIoIHR5cGUsIGxpc3RlbmVyICkge1xyXG5cclxuXHRcdGlmICggdGhpcy5fbGlzdGVuZXJzID09PSB1bmRlZmluZWQgKSB0aGlzLl9saXN0ZW5lcnMgPSB7fTtcclxuXHJcblx0XHRjb25zdCBsaXN0ZW5lcnMgPSB0aGlzLl9saXN0ZW5lcnM7XHJcblxyXG5cdFx0aWYgKCBsaXN0ZW5lcnNbIHR5cGUgXSA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0bGlzdGVuZXJzWyB0eXBlIF0gPSBbXTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBsaXN0ZW5lcnNbIHR5cGUgXS5pbmRleE9mKCBsaXN0ZW5lciApID09PSAtIDEgKSB7XHJcblxyXG5cdFx0XHRsaXN0ZW5lcnNbIHR5cGUgXS5wdXNoKCBsaXN0ZW5lciApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRoYXNFdmVudExpc3RlbmVyKCB0eXBlLCBsaXN0ZW5lciApIHtcclxuXHJcblx0XHRpZiAoIHRoaXMuX2xpc3RlbmVycyA9PT0gdW5kZWZpbmVkICkgcmV0dXJuIGZhbHNlO1xyXG5cclxuXHRcdGNvbnN0IGxpc3RlbmVycyA9IHRoaXMuX2xpc3RlbmVycztcclxuXHJcblx0XHRyZXR1cm4gbGlzdGVuZXJzWyB0eXBlIF0gIT09IHVuZGVmaW5lZCAmJiBsaXN0ZW5lcnNbIHR5cGUgXS5pbmRleE9mKCBsaXN0ZW5lciApICE9PSAtIDE7XHJcblxyXG5cdH1cclxuXHJcblx0cmVtb3ZlRXZlbnRMaXN0ZW5lciggdHlwZSwgbGlzdGVuZXIgKSB7XHJcblxyXG5cdFx0aWYgKCB0aGlzLl9saXN0ZW5lcnMgPT09IHVuZGVmaW5lZCApIHJldHVybjtcclxuXHJcblx0XHRjb25zdCBsaXN0ZW5lcnMgPSB0aGlzLl9saXN0ZW5lcnM7XHJcblx0XHRjb25zdCBsaXN0ZW5lckFycmF5ID0gbGlzdGVuZXJzWyB0eXBlIF07XHJcblxyXG5cdFx0aWYgKCBsaXN0ZW5lckFycmF5ICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBpbmRleCA9IGxpc3RlbmVyQXJyYXkuaW5kZXhPZiggbGlzdGVuZXIgKTtcclxuXHJcblx0XHRcdGlmICggaW5kZXggIT09IC0gMSApIHtcclxuXHJcblx0XHRcdFx0bGlzdGVuZXJBcnJheS5zcGxpY2UoIGluZGV4LCAxICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGRpc3BhdGNoRXZlbnQoIGV2ZW50ICkge1xyXG5cclxuXHRcdGlmICggdGhpcy5fbGlzdGVuZXJzID09PSB1bmRlZmluZWQgKSByZXR1cm47XHJcblxyXG5cdFx0Y29uc3QgbGlzdGVuZXJzID0gdGhpcy5fbGlzdGVuZXJzO1xyXG5cdFx0Y29uc3QgbGlzdGVuZXJBcnJheSA9IGxpc3RlbmVyc1sgZXZlbnQudHlwZSBdO1xyXG5cclxuXHRcdGlmICggbGlzdGVuZXJBcnJheSAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0ZXZlbnQudGFyZ2V0ID0gdGhpcztcclxuXHJcblx0XHRcdC8vIE1ha2UgYSBjb3B5LCBpbiBjYXNlIGxpc3RlbmVycyBhcmUgcmVtb3ZlZCB3aGlsZSBpdGVyYXRpbmcuXHJcblx0XHRcdGNvbnN0IGFycmF5ID0gbGlzdGVuZXJBcnJheS5zbGljZSggMCApO1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gYXJyYXkubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0YXJyYXlbIGkgXS5jYWxsKCB0aGlzLCBldmVudCApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0ZXZlbnQudGFyZ2V0ID0gbnVsbDtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcblxyXG5leHBvcnQgeyBFdmVudERpc3BhdGNoZXIgfTtcclxuIiwiY29uc3QgX2x1dCA9IFsgJzAwJywgJzAxJywgJzAyJywgJzAzJywgJzA0JywgJzA1JywgJzA2JywgJzA3JywgJzA4JywgJzA5JywgJzBhJywgJzBiJywgJzBjJywgJzBkJywgJzBlJywgJzBmJywgJzEwJywgJzExJywgJzEyJywgJzEzJywgJzE0JywgJzE1JywgJzE2JywgJzE3JywgJzE4JywgJzE5JywgJzFhJywgJzFiJywgJzFjJywgJzFkJywgJzFlJywgJzFmJywgJzIwJywgJzIxJywgJzIyJywgJzIzJywgJzI0JywgJzI1JywgJzI2JywgJzI3JywgJzI4JywgJzI5JywgJzJhJywgJzJiJywgJzJjJywgJzJkJywgJzJlJywgJzJmJywgJzMwJywgJzMxJywgJzMyJywgJzMzJywgJzM0JywgJzM1JywgJzM2JywgJzM3JywgJzM4JywgJzM5JywgJzNhJywgJzNiJywgJzNjJywgJzNkJywgJzNlJywgJzNmJywgJzQwJywgJzQxJywgJzQyJywgJzQzJywgJzQ0JywgJzQ1JywgJzQ2JywgJzQ3JywgJzQ4JywgJzQ5JywgJzRhJywgJzRiJywgJzRjJywgJzRkJywgJzRlJywgJzRmJywgJzUwJywgJzUxJywgJzUyJywgJzUzJywgJzU0JywgJzU1JywgJzU2JywgJzU3JywgJzU4JywgJzU5JywgJzVhJywgJzViJywgJzVjJywgJzVkJywgJzVlJywgJzVmJywgJzYwJywgJzYxJywgJzYyJywgJzYzJywgJzY0JywgJzY1JywgJzY2JywgJzY3JywgJzY4JywgJzY5JywgJzZhJywgJzZiJywgJzZjJywgJzZkJywgJzZlJywgJzZmJywgJzcwJywgJzcxJywgJzcyJywgJzczJywgJzc0JywgJzc1JywgJzc2JywgJzc3JywgJzc4JywgJzc5JywgJzdhJywgJzdiJywgJzdjJywgJzdkJywgJzdlJywgJzdmJywgJzgwJywgJzgxJywgJzgyJywgJzgzJywgJzg0JywgJzg1JywgJzg2JywgJzg3JywgJzg4JywgJzg5JywgJzhhJywgJzhiJywgJzhjJywgJzhkJywgJzhlJywgJzhmJywgJzkwJywgJzkxJywgJzkyJywgJzkzJywgJzk0JywgJzk1JywgJzk2JywgJzk3JywgJzk4JywgJzk5JywgJzlhJywgJzliJywgJzljJywgJzlkJywgJzllJywgJzlmJywgJ2EwJywgJ2ExJywgJ2EyJywgJ2EzJywgJ2E0JywgJ2E1JywgJ2E2JywgJ2E3JywgJ2E4JywgJ2E5JywgJ2FhJywgJ2FiJywgJ2FjJywgJ2FkJywgJ2FlJywgJ2FmJywgJ2IwJywgJ2IxJywgJ2IyJywgJ2IzJywgJ2I0JywgJ2I1JywgJ2I2JywgJ2I3JywgJ2I4JywgJ2I5JywgJ2JhJywgJ2JiJywgJ2JjJywgJ2JkJywgJ2JlJywgJ2JmJywgJ2MwJywgJ2MxJywgJ2MyJywgJ2MzJywgJ2M0JywgJ2M1JywgJ2M2JywgJ2M3JywgJ2M4JywgJ2M5JywgJ2NhJywgJ2NiJywgJ2NjJywgJ2NkJywgJ2NlJywgJ2NmJywgJ2QwJywgJ2QxJywgJ2QyJywgJ2QzJywgJ2Q0JywgJ2Q1JywgJ2Q2JywgJ2Q3JywgJ2Q4JywgJ2Q5JywgJ2RhJywgJ2RiJywgJ2RjJywgJ2RkJywgJ2RlJywgJ2RmJywgJ2UwJywgJ2UxJywgJ2UyJywgJ2UzJywgJ2U0JywgJ2U1JywgJ2U2JywgJ2U3JywgJ2U4JywgJ2U5JywgJ2VhJywgJ2ViJywgJ2VjJywgJ2VkJywgJ2VlJywgJ2VmJywgJ2YwJywgJ2YxJywgJ2YyJywgJ2YzJywgJ2Y0JywgJ2Y1JywgJ2Y2JywgJ2Y3JywgJ2Y4JywgJ2Y5JywgJ2ZhJywgJ2ZiJywgJ2ZjJywgJ2ZkJywgJ2ZlJywgJ2ZmJyBdO1xyXG5cclxubGV0IF9zZWVkID0gMTIzNDU2NztcclxuXHJcblxyXG5jb25zdCBERUcyUkFEID0gTWF0aC5QSSAvIDE4MDtcclxuY29uc3QgUkFEMkRFRyA9IDE4MCAvIE1hdGguUEk7XHJcblxyXG4vLyBodHRwOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzEwNTAzNC9ob3ctdG8tY3JlYXRlLWEtZ3VpZC11dWlkLWluLWphdmFzY3JpcHQvMjE5NjMxMzYjMjE5NjMxMzZcclxuZnVuY3Rpb24gZ2VuZXJhdGVVVUlEKCkge1xyXG5cclxuXHRjb25zdCBkMCA9IE1hdGgucmFuZG9tKCkgKiAweGZmZmZmZmZmIHwgMDtcclxuXHRjb25zdCBkMSA9IE1hdGgucmFuZG9tKCkgKiAweGZmZmZmZmZmIHwgMDtcclxuXHRjb25zdCBkMiA9IE1hdGgucmFuZG9tKCkgKiAweGZmZmZmZmZmIHwgMDtcclxuXHRjb25zdCBkMyA9IE1hdGgucmFuZG9tKCkgKiAweGZmZmZmZmZmIHwgMDtcclxuXHRjb25zdCB1dWlkID0gX2x1dFsgZDAgJiAweGZmIF0gKyBfbHV0WyBkMCA+PiA4ICYgMHhmZiBdICsgX2x1dFsgZDAgPj4gMTYgJiAweGZmIF0gKyBfbHV0WyBkMCA+PiAyNCAmIDB4ZmYgXSArICctJyArXHJcblx0XHRcdF9sdXRbIGQxICYgMHhmZiBdICsgX2x1dFsgZDEgPj4gOCAmIDB4ZmYgXSArICctJyArIF9sdXRbIGQxID4+IDE2ICYgMHgwZiB8IDB4NDAgXSArIF9sdXRbIGQxID4+IDI0ICYgMHhmZiBdICsgJy0nICtcclxuXHRcdFx0X2x1dFsgZDIgJiAweDNmIHwgMHg4MCBdICsgX2x1dFsgZDIgPj4gOCAmIDB4ZmYgXSArICctJyArIF9sdXRbIGQyID4+IDE2ICYgMHhmZiBdICsgX2x1dFsgZDIgPj4gMjQgJiAweGZmIF0gK1xyXG5cdFx0XHRfbHV0WyBkMyAmIDB4ZmYgXSArIF9sdXRbIGQzID4+IDggJiAweGZmIF0gKyBfbHV0WyBkMyA+PiAxNiAmIDB4ZmYgXSArIF9sdXRbIGQzID4+IDI0ICYgMHhmZiBdO1xyXG5cclxuXHQvLyAudG9Mb3dlckNhc2UoKSBoZXJlIGZsYXR0ZW5zIGNvbmNhdGVuYXRlZCBzdHJpbmdzIHRvIHNhdmUgaGVhcCBtZW1vcnkgc3BhY2UuXHJcblx0cmV0dXJuIHV1aWQudG9Mb3dlckNhc2UoKTtcclxuXHJcbn1cclxuXHJcbmZ1bmN0aW9uIGNsYW1wKCB2YWx1ZSwgbWluLCBtYXggKSB7XHJcblxyXG5cdHJldHVybiBNYXRoLm1heCggbWluLCBNYXRoLm1pbiggbWF4LCB2YWx1ZSApICk7XHJcblxyXG59XHJcblxyXG4vLyBjb21wdXRlIGV1Y2xpZGVhbiBtb2R1bG8gb2YgbSAlIG5cclxuLy8gaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvTW9kdWxvX29wZXJhdGlvblxyXG5mdW5jdGlvbiBldWNsaWRlYW5Nb2R1bG8oIG4sIG0gKSB7XHJcblxyXG5cdHJldHVybiAoICggbiAlIG0gKSArIG0gKSAlIG07XHJcblxyXG59XHJcblxyXG4vLyBMaW5lYXIgbWFwcGluZyBmcm9tIHJhbmdlIDxhMSwgYTI+IHRvIHJhbmdlIDxiMSwgYjI+XHJcbmZ1bmN0aW9uIG1hcExpbmVhciggeCwgYTEsIGEyLCBiMSwgYjIgKSB7XHJcblxyXG5cdHJldHVybiBiMSArICggeCAtIGExICkgKiAoIGIyIC0gYjEgKSAvICggYTIgLSBhMSApO1xyXG5cclxufVxyXG5cclxuLy8gaHR0cHM6Ly93d3cuZ2FtZWRldi5uZXQvdHV0b3JpYWxzL3Byb2dyYW1taW5nL2dlbmVyYWwtYW5kLWdhbWVwbGF5LXByb2dyYW1taW5nL2ludmVyc2UtbGVycC1hLXN1cGVyLXVzZWZ1bC15ZXQtb2Z0ZW4tb3Zlcmxvb2tlZC1mdW5jdGlvbi1yNTIzMC9cclxuZnVuY3Rpb24gaW52ZXJzZUxlcnAoIHgsIHksIHZhbHVlICkge1xyXG5cclxuXHRpZiAoIHggIT09IHkgKSB7XHJcblxyXG5cdFx0cmV0dXJuICggdmFsdWUgLSB4ICkgLyAoIHkgLSB4ICk7XHJcblxyXG5cdH0gZWxzZSB7XHJcblxyXG5cdFx0cmV0dXJuIDA7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbi8vIGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0xpbmVhcl9pbnRlcnBvbGF0aW9uXHJcbmZ1bmN0aW9uIGxlcnAoIHgsIHksIHQgKSB7XHJcblxyXG5cdHJldHVybiAoIDEgLSB0ICkgKiB4ICsgdCAqIHk7XHJcblxyXG59XHJcblxyXG4vLyBodHRwOi8vd3d3LnJvcnlkcmlzY29sbC5jb20vMjAxNi8wMy8wNy9mcmFtZS1yYXRlLWluZGVwZW5kZW50LWRhbXBpbmctdXNpbmctbGVycC9cclxuZnVuY3Rpb24gZGFtcCggeCwgeSwgbGFtYmRhLCBkdCApIHtcclxuXHJcblx0cmV0dXJuIGxlcnAoIHgsIHksIDEgLSBNYXRoLmV4cCggLSBsYW1iZGEgKiBkdCApICk7XHJcblxyXG59XHJcblxyXG4vLyBodHRwczovL3d3dy5kZXNtb3MuY29tL2NhbGN1bGF0b3IvdmNzam55ejd4NFxyXG5mdW5jdGlvbiBwaW5ncG9uZyggeCwgbGVuZ3RoID0gMSApIHtcclxuXHJcblx0cmV0dXJuIGxlbmd0aCAtIE1hdGguYWJzKCBldWNsaWRlYW5Nb2R1bG8oIHgsIGxlbmd0aCAqIDIgKSAtIGxlbmd0aCApO1xyXG5cclxufVxyXG5cclxuLy8gaHR0cDovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9TbW9vdGhzdGVwXHJcbmZ1bmN0aW9uIHNtb290aHN0ZXAoIHgsIG1pbiwgbWF4ICkge1xyXG5cclxuXHRpZiAoIHggPD0gbWluICkgcmV0dXJuIDA7XHJcblx0aWYgKCB4ID49IG1heCApIHJldHVybiAxO1xyXG5cclxuXHR4ID0gKCB4IC0gbWluICkgLyAoIG1heCAtIG1pbiApO1xyXG5cclxuXHRyZXR1cm4geCAqIHggKiAoIDMgLSAyICogeCApO1xyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gc21vb3RoZXJzdGVwKCB4LCBtaW4sIG1heCApIHtcclxuXHJcblx0aWYgKCB4IDw9IG1pbiApIHJldHVybiAwO1xyXG5cdGlmICggeCA+PSBtYXggKSByZXR1cm4gMTtcclxuXHJcblx0eCA9ICggeCAtIG1pbiApIC8gKCBtYXggLSBtaW4gKTtcclxuXHJcblx0cmV0dXJuIHggKiB4ICogeCAqICggeCAqICggeCAqIDYgLSAxNSApICsgMTAgKTtcclxuXHJcbn1cclxuXHJcbi8vIFJhbmRvbSBpbnRlZ2VyIGZyb20gPGxvdywgaGlnaD4gaW50ZXJ2YWxcclxuZnVuY3Rpb24gcmFuZEludCggbG93LCBoaWdoICkge1xyXG5cclxuXHRyZXR1cm4gbG93ICsgTWF0aC5mbG9vciggTWF0aC5yYW5kb20oKSAqICggaGlnaCAtIGxvdyArIDEgKSApO1xyXG5cclxufVxyXG5cclxuLy8gUmFuZG9tIGZsb2F0IGZyb20gPGxvdywgaGlnaD4gaW50ZXJ2YWxcclxuZnVuY3Rpb24gcmFuZEZsb2F0KCBsb3csIGhpZ2ggKSB7XHJcblxyXG5cdHJldHVybiBsb3cgKyBNYXRoLnJhbmRvbSgpICogKCBoaWdoIC0gbG93ICk7XHJcblxyXG59XHJcblxyXG4vLyBSYW5kb20gZmxvYXQgZnJvbSA8LXJhbmdlLzIsIHJhbmdlLzI+IGludGVydmFsXHJcbmZ1bmN0aW9uIHJhbmRGbG9hdFNwcmVhZCggcmFuZ2UgKSB7XHJcblxyXG5cdHJldHVybiByYW5nZSAqICggMC41IC0gTWF0aC5yYW5kb20oKSApO1xyXG5cclxufVxyXG5cclxuLy8gRGV0ZXJtaW5pc3RpYyBwc2V1ZG8tcmFuZG9tIGZsb2F0IGluIHRoZSBpbnRlcnZhbCBbIDAsIDEgXVxyXG5mdW5jdGlvbiBzZWVkZWRSYW5kb20oIHMgKSB7XHJcblxyXG5cdGlmICggcyAhPT0gdW5kZWZpbmVkICkgX3NlZWQgPSBzO1xyXG5cclxuXHQvLyBNdWxiZXJyeTMyIGdlbmVyYXRvclxyXG5cclxuXHRsZXQgdCA9IF9zZWVkICs9IDB4NkQyQjc5RjU7XHJcblxyXG5cdHQgPSBNYXRoLmltdWwoIHQgXiB0ID4+PiAxNSwgdCB8IDEgKTtcclxuXHJcblx0dCBePSB0ICsgTWF0aC5pbXVsKCB0IF4gdCA+Pj4gNywgdCB8IDYxICk7XHJcblxyXG5cdHJldHVybiAoICggdCBeIHQgPj4+IDE0ICkgPj4+IDAgKSAvIDQyOTQ5NjcyOTY7XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiBkZWdUb1JhZCggZGVncmVlcyApIHtcclxuXHJcblx0cmV0dXJuIGRlZ3JlZXMgKiBERUcyUkFEO1xyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gcmFkVG9EZWcoIHJhZGlhbnMgKSB7XHJcblxyXG5cdHJldHVybiByYWRpYW5zICogUkFEMkRFRztcclxuXHJcbn1cclxuXHJcbmZ1bmN0aW9uIGlzUG93ZXJPZlR3byggdmFsdWUgKSB7XHJcblxyXG5cdHJldHVybiAoIHZhbHVlICYgKCB2YWx1ZSAtIDEgKSApID09PSAwICYmIHZhbHVlICE9PSAwO1xyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gY2VpbFBvd2VyT2ZUd28oIHZhbHVlICkge1xyXG5cclxuXHRyZXR1cm4gTWF0aC5wb3coIDIsIE1hdGguY2VpbCggTWF0aC5sb2coIHZhbHVlICkgLyBNYXRoLkxOMiApICk7XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiBmbG9vclBvd2VyT2ZUd28oIHZhbHVlICkge1xyXG5cclxuXHRyZXR1cm4gTWF0aC5wb3coIDIsIE1hdGguZmxvb3IoIE1hdGgubG9nKCB2YWx1ZSApIC8gTWF0aC5MTjIgKSApO1xyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gc2V0UXVhdGVybmlvbkZyb21Qcm9wZXJFdWxlciggcSwgYSwgYiwgYywgb3JkZXIgKSB7XHJcblxyXG5cdC8vIEludHJpbnNpYyBQcm9wZXIgRXVsZXIgQW5nbGVzIC0gc2VlIGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0V1bGVyX2FuZ2xlc1xyXG5cclxuXHQvLyByb3RhdGlvbnMgYXJlIGFwcGxpZWQgdG8gdGhlIGF4ZXMgaW4gdGhlIG9yZGVyIHNwZWNpZmllZCBieSAnb3JkZXInXHJcblx0Ly8gcm90YXRpb24gYnkgYW5nbGUgJ2EnIGlzIGFwcGxpZWQgZmlyc3QsIHRoZW4gYnkgYW5nbGUgJ2InLCB0aGVuIGJ5IGFuZ2xlICdjJ1xyXG5cdC8vIGFuZ2xlcyBhcmUgaW4gcmFkaWFuc1xyXG5cclxuXHRjb25zdCBjb3MgPSBNYXRoLmNvcztcclxuXHRjb25zdCBzaW4gPSBNYXRoLnNpbjtcclxuXHJcblx0Y29uc3QgYzIgPSBjb3MoIGIgLyAyICk7XHJcblx0Y29uc3QgczIgPSBzaW4oIGIgLyAyICk7XHJcblxyXG5cdGNvbnN0IGMxMyA9IGNvcyggKCBhICsgYyApIC8gMiApO1xyXG5cdGNvbnN0IHMxMyA9IHNpbiggKCBhICsgYyApIC8gMiApO1xyXG5cclxuXHRjb25zdCBjMV8zID0gY29zKCAoIGEgLSBjICkgLyAyICk7XHJcblx0Y29uc3QgczFfMyA9IHNpbiggKCBhIC0gYyApIC8gMiApO1xyXG5cclxuXHRjb25zdCBjM18xID0gY29zKCAoIGMgLSBhICkgLyAyICk7XHJcblx0Y29uc3QgczNfMSA9IHNpbiggKCBjIC0gYSApIC8gMiApO1xyXG5cclxuXHRzd2l0Y2ggKCBvcmRlciApIHtcclxuXHJcblx0XHRjYXNlICdYWVgnOlxyXG5cdFx0XHRxLnNldCggYzIgKiBzMTMsIHMyICogYzFfMywgczIgKiBzMV8zLCBjMiAqIGMxMyApO1xyXG5cdFx0XHRicmVhaztcclxuXHJcblx0XHRjYXNlICdZWlknOlxyXG5cdFx0XHRxLnNldCggczIgKiBzMV8zLCBjMiAqIHMxMywgczIgKiBjMV8zLCBjMiAqIGMxMyApO1xyXG5cdFx0XHRicmVhaztcclxuXHJcblx0XHRjYXNlICdaWFonOlxyXG5cdFx0XHRxLnNldCggczIgKiBjMV8zLCBzMiAqIHMxXzMsIGMyICogczEzLCBjMiAqIGMxMyApO1xyXG5cdFx0XHRicmVhaztcclxuXHJcblx0XHRjYXNlICdYWlgnOlxyXG5cdFx0XHRxLnNldCggYzIgKiBzMTMsIHMyICogczNfMSwgczIgKiBjM18xLCBjMiAqIGMxMyApO1xyXG5cdFx0XHRicmVhaztcclxuXHJcblx0XHRjYXNlICdZWFknOlxyXG5cdFx0XHRxLnNldCggczIgKiBjM18xLCBjMiAqIHMxMywgczIgKiBzM18xLCBjMiAqIGMxMyApO1xyXG5cdFx0XHRicmVhaztcclxuXHJcblx0XHRjYXNlICdaWVonOlxyXG5cdFx0XHRxLnNldCggczIgKiBzM18xLCBzMiAqIGMzXzEsIGMyICogczEzLCBjMiAqIGMxMyApO1xyXG5cdFx0XHRicmVhaztcclxuXHJcblx0XHRkZWZhdWx0OlxyXG5cdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5NYXRoVXRpbHM6IC5zZXRRdWF0ZXJuaW9uRnJvbVByb3BlckV1bGVyKCkgZW5jb3VudGVyZWQgYW4gdW5rbm93biBvcmRlcjogJyArIG9yZGVyICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmZ1bmN0aW9uIGRlbm9ybWFsaXplKCB2YWx1ZSwgYXJyYXkgKSB7XHJcblxyXG5cdHN3aXRjaCAoIGFycmF5LmNvbnN0cnVjdG9yICkge1xyXG5cclxuXHRcdGNhc2UgRmxvYXQzMkFycmF5OlxyXG5cclxuXHRcdFx0cmV0dXJuIHZhbHVlO1xyXG5cclxuXHRcdGNhc2UgVWludDMyQXJyYXk6XHJcblxyXG5cdFx0XHRyZXR1cm4gdmFsdWUgLyA0Mjk0OTY3Mjk1LjA7XHJcblxyXG5cdFx0Y2FzZSBVaW50MTZBcnJheTpcclxuXHJcblx0XHRcdHJldHVybiB2YWx1ZSAvIDY1NTM1LjA7XHJcblxyXG5cdFx0Y2FzZSBVaW50OEFycmF5OlxyXG5cclxuXHRcdFx0cmV0dXJuIHZhbHVlIC8gMjU1LjA7XHJcblxyXG5cdFx0Y2FzZSBJbnQzMkFycmF5OlxyXG5cclxuXHRcdFx0cmV0dXJuIE1hdGgubWF4KCB2YWx1ZSAvIDIxNDc0ODM2NDcuMCwgLSAxLjAgKTtcclxuXHJcblx0XHRjYXNlIEludDE2QXJyYXk6XHJcblxyXG5cdFx0XHRyZXR1cm4gTWF0aC5tYXgoIHZhbHVlIC8gMzI3NjcuMCwgLSAxLjAgKTtcclxuXHJcblx0XHRjYXNlIEludDhBcnJheTpcclxuXHJcblx0XHRcdHJldHVybiBNYXRoLm1heCggdmFsdWUgLyAxMjcuMCwgLSAxLjAgKTtcclxuXHJcblx0XHRkZWZhdWx0OlxyXG5cclxuXHRcdFx0dGhyb3cgbmV3IEVycm9yKCAnSW52YWxpZCBjb21wb25lbnQgdHlwZS4nICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmZ1bmN0aW9uIG5vcm1hbGl6ZSggdmFsdWUsIGFycmF5ICkge1xyXG5cclxuXHRzd2l0Y2ggKCBhcnJheS5jb25zdHJ1Y3RvciApIHtcclxuXHJcblx0XHRjYXNlIEZsb2F0MzJBcnJheTpcclxuXHJcblx0XHRcdHJldHVybiB2YWx1ZTtcclxuXHJcblx0XHRjYXNlIFVpbnQzMkFycmF5OlxyXG5cclxuXHRcdFx0cmV0dXJuIE1hdGgucm91bmQoIHZhbHVlICogNDI5NDk2NzI5NS4wICk7XHJcblxyXG5cdFx0Y2FzZSBVaW50MTZBcnJheTpcclxuXHJcblx0XHRcdHJldHVybiBNYXRoLnJvdW5kKCB2YWx1ZSAqIDY1NTM1LjAgKTtcclxuXHJcblx0XHRjYXNlIFVpbnQ4QXJyYXk6XHJcblxyXG5cdFx0XHRyZXR1cm4gTWF0aC5yb3VuZCggdmFsdWUgKiAyNTUuMCApO1xyXG5cclxuXHRcdGNhc2UgSW50MzJBcnJheTpcclxuXHJcblx0XHRcdHJldHVybiBNYXRoLnJvdW5kKCB2YWx1ZSAqIDIxNDc0ODM2NDcuMCApO1xyXG5cclxuXHRcdGNhc2UgSW50MTZBcnJheTpcclxuXHJcblx0XHRcdHJldHVybiBNYXRoLnJvdW5kKCB2YWx1ZSAqIDMyNzY3LjAgKTtcclxuXHJcblx0XHRjYXNlIEludDhBcnJheTpcclxuXHJcblx0XHRcdHJldHVybiBNYXRoLnJvdW5kKCB2YWx1ZSAqIDEyNy4wICk7XHJcblxyXG5cdFx0ZGVmYXVsdDpcclxuXHJcblx0XHRcdHRocm93IG5ldyBFcnJvciggJ0ludmFsaWQgY29tcG9uZW50IHR5cGUuJyApO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5jb25zdCBNYXRoVXRpbHMgPSB7XHJcblx0REVHMlJBRDogREVHMlJBRCxcclxuXHRSQUQyREVHOiBSQUQyREVHLFxyXG5cdGdlbmVyYXRlVVVJRDogZ2VuZXJhdGVVVUlELFxyXG5cdGNsYW1wOiBjbGFtcCxcclxuXHRldWNsaWRlYW5Nb2R1bG86IGV1Y2xpZGVhbk1vZHVsbyxcclxuXHRtYXBMaW5lYXI6IG1hcExpbmVhcixcclxuXHRpbnZlcnNlTGVycDogaW52ZXJzZUxlcnAsXHJcblx0bGVycDogbGVycCxcclxuXHRkYW1wOiBkYW1wLFxyXG5cdHBpbmdwb25nOiBwaW5ncG9uZyxcclxuXHRzbW9vdGhzdGVwOiBzbW9vdGhzdGVwLFxyXG5cdHNtb290aGVyc3RlcDogc21vb3RoZXJzdGVwLFxyXG5cdHJhbmRJbnQ6IHJhbmRJbnQsXHJcblx0cmFuZEZsb2F0OiByYW5kRmxvYXQsXHJcblx0cmFuZEZsb2F0U3ByZWFkOiByYW5kRmxvYXRTcHJlYWQsXHJcblx0c2VlZGVkUmFuZG9tOiBzZWVkZWRSYW5kb20sXHJcblx0ZGVnVG9SYWQ6IGRlZ1RvUmFkLFxyXG5cdHJhZFRvRGVnOiByYWRUb0RlZyxcclxuXHRpc1Bvd2VyT2ZUd286IGlzUG93ZXJPZlR3byxcclxuXHRjZWlsUG93ZXJPZlR3bzogY2VpbFBvd2VyT2ZUd28sXHJcblx0Zmxvb3JQb3dlck9mVHdvOiBmbG9vclBvd2VyT2ZUd28sXHJcblx0c2V0UXVhdGVybmlvbkZyb21Qcm9wZXJFdWxlcjogc2V0UXVhdGVybmlvbkZyb21Qcm9wZXJFdWxlcixcclxuXHRub3JtYWxpemU6IG5vcm1hbGl6ZSxcclxuXHRkZW5vcm1hbGl6ZTogZGVub3JtYWxpemVcclxufTtcclxuXHJcbmV4cG9ydCB7XHJcblx0REVHMlJBRCxcclxuXHRSQUQyREVHLFxyXG5cdGdlbmVyYXRlVVVJRCxcclxuXHRjbGFtcCxcclxuXHRldWNsaWRlYW5Nb2R1bG8sXHJcblx0bWFwTGluZWFyLFxyXG5cdGludmVyc2VMZXJwLFxyXG5cdGxlcnAsXHJcblx0ZGFtcCxcclxuXHRwaW5ncG9uZyxcclxuXHRzbW9vdGhzdGVwLFxyXG5cdHNtb290aGVyc3RlcCxcclxuXHRyYW5kSW50LFxyXG5cdHJhbmRGbG9hdCxcclxuXHRyYW5kRmxvYXRTcHJlYWQsXHJcblx0c2VlZGVkUmFuZG9tLFxyXG5cdGRlZ1RvUmFkLFxyXG5cdHJhZFRvRGVnLFxyXG5cdGlzUG93ZXJPZlR3byxcclxuXHRjZWlsUG93ZXJPZlR3byxcclxuXHRmbG9vclBvd2VyT2ZUd28sXHJcblx0c2V0UXVhdGVybmlvbkZyb21Qcm9wZXJFdWxlcixcclxuXHRub3JtYWxpemUsXHJcblx0ZGVub3JtYWxpemUsXHJcblx0TWF0aFV0aWxzXHJcbn07XHJcbiIsImltcG9ydCAqIGFzIE1hdGhVdGlscyBmcm9tICcuL01hdGhVdGlscy5qcyc7XHJcblxyXG5jbGFzcyBWZWN0b3IyIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIHggPSAwLCB5ID0gMCApIHtcclxuXHJcblx0XHRWZWN0b3IyLnByb3RvdHlwZS5pc1ZlY3RvcjIgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMueCA9IHg7XHJcblx0XHR0aGlzLnkgPSB5O1xyXG5cclxuXHR9XHJcblxyXG5cdGdldCB3aWR0aCgpIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy54O1xyXG5cclxuXHR9XHJcblxyXG5cdHNldCB3aWR0aCggdmFsdWUgKSB7XHJcblxyXG5cdFx0dGhpcy54ID0gdmFsdWU7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0IGhlaWdodCgpIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy55O1xyXG5cclxuXHR9XHJcblxyXG5cdHNldCBoZWlnaHQoIHZhbHVlICkge1xyXG5cclxuXHRcdHRoaXMueSA9IHZhbHVlO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldCggeCwgeSApIHtcclxuXHJcblx0XHR0aGlzLnggPSB4O1xyXG5cdFx0dGhpcy55ID0geTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRTY2FsYXIoIHNjYWxhciApIHtcclxuXHJcblx0XHR0aGlzLnggPSBzY2FsYXI7XHJcblx0XHR0aGlzLnkgPSBzY2FsYXI7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0WCggeCApIHtcclxuXHJcblx0XHR0aGlzLnggPSB4O1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldFkoIHkgKSB7XHJcblxyXG5cdFx0dGhpcy55ID0geTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRDb21wb25lbnQoIGluZGV4LCB2YWx1ZSApIHtcclxuXHJcblx0XHRzd2l0Y2ggKCBpbmRleCApIHtcclxuXHJcblx0XHRcdGNhc2UgMDogdGhpcy54ID0gdmFsdWU7IGJyZWFrO1xyXG5cdFx0XHRjYXNlIDE6IHRoaXMueSA9IHZhbHVlOyBicmVhaztcclxuXHRcdFx0ZGVmYXVsdDogdGhyb3cgbmV3IEVycm9yKCAnaW5kZXggaXMgb3V0IG9mIHJhbmdlOiAnICsgaW5kZXggKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0Q29tcG9uZW50KCBpbmRleCApIHtcclxuXHJcblx0XHRzd2l0Y2ggKCBpbmRleCApIHtcclxuXHJcblx0XHRcdGNhc2UgMDogcmV0dXJuIHRoaXMueDtcclxuXHRcdFx0Y2FzZSAxOiByZXR1cm4gdGhpcy55O1xyXG5cdFx0XHRkZWZhdWx0OiB0aHJvdyBuZXcgRXJyb3IoICdpbmRleCBpcyBvdXQgb2YgcmFuZ2U6ICcgKyBpbmRleCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRjbG9uZSgpIHtcclxuXHJcblx0XHRyZXR1cm4gbmV3IHRoaXMuY29uc3RydWN0b3IoIHRoaXMueCwgdGhpcy55ICk7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggdiApIHtcclxuXHJcblx0XHR0aGlzLnggPSB2Lng7XHJcblx0XHR0aGlzLnkgPSB2Lnk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0YWRkKCB2ICkge1xyXG5cclxuXHRcdHRoaXMueCArPSB2Lng7XHJcblx0XHR0aGlzLnkgKz0gdi55O1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGFkZFNjYWxhciggcyApIHtcclxuXHJcblx0XHR0aGlzLnggKz0gcztcclxuXHRcdHRoaXMueSArPSBzO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGFkZFZlY3RvcnMoIGEsIGIgKSB7XHJcblxyXG5cdFx0dGhpcy54ID0gYS54ICsgYi54O1xyXG5cdFx0dGhpcy55ID0gYS55ICsgYi55O1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGFkZFNjYWxlZFZlY3RvciggdiwgcyApIHtcclxuXHJcblx0XHR0aGlzLnggKz0gdi54ICogcztcclxuXHRcdHRoaXMueSArPSB2LnkgKiBzO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHN1YiggdiApIHtcclxuXHJcblx0XHR0aGlzLnggLT0gdi54O1xyXG5cdFx0dGhpcy55IC09IHYueTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzdWJTY2FsYXIoIHMgKSB7XHJcblxyXG5cdFx0dGhpcy54IC09IHM7XHJcblx0XHR0aGlzLnkgLT0gcztcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzdWJWZWN0b3JzKCBhLCBiICkge1xyXG5cclxuXHRcdHRoaXMueCA9IGEueCAtIGIueDtcclxuXHRcdHRoaXMueSA9IGEueSAtIGIueTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRtdWx0aXBseSggdiApIHtcclxuXHJcblx0XHR0aGlzLnggKj0gdi54O1xyXG5cdFx0dGhpcy55ICo9IHYueTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRtdWx0aXBseVNjYWxhciggc2NhbGFyICkge1xyXG5cclxuXHRcdHRoaXMueCAqPSBzY2FsYXI7XHJcblx0XHR0aGlzLnkgKj0gc2NhbGFyO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGRpdmlkZSggdiApIHtcclxuXHJcblx0XHR0aGlzLnggLz0gdi54O1xyXG5cdFx0dGhpcy55IC89IHYueTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRkaXZpZGVTY2FsYXIoIHNjYWxhciApIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5tdWx0aXBseVNjYWxhciggMSAvIHNjYWxhciApO1xyXG5cclxuXHR9XHJcblxyXG5cdGFwcGx5TWF0cml4MyggbSApIHtcclxuXHJcblx0XHRjb25zdCB4ID0gdGhpcy54LCB5ID0gdGhpcy55O1xyXG5cdFx0Y29uc3QgZSA9IG0uZWxlbWVudHM7XHJcblxyXG5cdFx0dGhpcy54ID0gZVsgMCBdICogeCArIGVbIDMgXSAqIHkgKyBlWyA2IF07XHJcblx0XHR0aGlzLnkgPSBlWyAxIF0gKiB4ICsgZVsgNCBdICogeSArIGVbIDcgXTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRtaW4oIHYgKSB7XHJcblxyXG5cdFx0dGhpcy54ID0gTWF0aC5taW4oIHRoaXMueCwgdi54ICk7XHJcblx0XHR0aGlzLnkgPSBNYXRoLm1pbiggdGhpcy55LCB2LnkgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRtYXgoIHYgKSB7XHJcblxyXG5cdFx0dGhpcy54ID0gTWF0aC5tYXgoIHRoaXMueCwgdi54ICk7XHJcblx0XHR0aGlzLnkgPSBNYXRoLm1heCggdGhpcy55LCB2LnkgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRjbGFtcCggbWluLCBtYXggKSB7XHJcblxyXG5cdFx0Ly8gYXNzdW1lcyBtaW4gPCBtYXgsIGNvbXBvbmVudHdpc2VcclxuXHJcblx0XHR0aGlzLnggPSBNYXRoLm1heCggbWluLngsIE1hdGgubWluKCBtYXgueCwgdGhpcy54ICkgKTtcclxuXHRcdHRoaXMueSA9IE1hdGgubWF4KCBtaW4ueSwgTWF0aC5taW4oIG1heC55LCB0aGlzLnkgKSApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGNsYW1wU2NhbGFyKCBtaW5WYWwsIG1heFZhbCApIHtcclxuXHJcblx0XHR0aGlzLnggPSBNYXRoLm1heCggbWluVmFsLCBNYXRoLm1pbiggbWF4VmFsLCB0aGlzLnggKSApO1xyXG5cdFx0dGhpcy55ID0gTWF0aC5tYXgoIG1pblZhbCwgTWF0aC5taW4oIG1heFZhbCwgdGhpcy55ICkgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRjbGFtcExlbmd0aCggbWluLCBtYXggKSB7XHJcblxyXG5cdFx0Y29uc3QgbGVuZ3RoID0gdGhpcy5sZW5ndGgoKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5kaXZpZGVTY2FsYXIoIGxlbmd0aCB8fCAxICkubXVsdGlwbHlTY2FsYXIoIE1hdGgubWF4KCBtaW4sIE1hdGgubWluKCBtYXgsIGxlbmd0aCApICkgKTtcclxuXHJcblx0fVxyXG5cclxuXHRmbG9vcigpIHtcclxuXHJcblx0XHR0aGlzLnggPSBNYXRoLmZsb29yKCB0aGlzLnggKTtcclxuXHRcdHRoaXMueSA9IE1hdGguZmxvb3IoIHRoaXMueSApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGNlaWwoKSB7XHJcblxyXG5cdFx0dGhpcy54ID0gTWF0aC5jZWlsKCB0aGlzLnggKTtcclxuXHRcdHRoaXMueSA9IE1hdGguY2VpbCggdGhpcy55ICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0cm91bmQoKSB7XHJcblxyXG5cdFx0dGhpcy54ID0gTWF0aC5yb3VuZCggdGhpcy54ICk7XHJcblx0XHR0aGlzLnkgPSBNYXRoLnJvdW5kKCB0aGlzLnkgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRyb3VuZFRvWmVybygpIHtcclxuXHJcblx0XHR0aGlzLnggPSBNYXRoLnRydW5jKCB0aGlzLnggKTtcclxuXHRcdHRoaXMueSA9IE1hdGgudHJ1bmMoIHRoaXMueSApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdG5lZ2F0ZSgpIHtcclxuXHJcblx0XHR0aGlzLnggPSAtIHRoaXMueDtcclxuXHRcdHRoaXMueSA9IC0gdGhpcy55O1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGRvdCggdiApIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy54ICogdi54ICsgdGhpcy55ICogdi55O1xyXG5cclxuXHR9XHJcblxyXG5cdGNyb3NzKCB2ICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLnggKiB2LnkgLSB0aGlzLnkgKiB2Lng7XHJcblxyXG5cdH1cclxuXHJcblx0bGVuZ3RoU3EoKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMueCAqIHRoaXMueCArIHRoaXMueSAqIHRoaXMueTtcclxuXHJcblx0fVxyXG5cclxuXHRsZW5ndGgoKSB7XHJcblxyXG5cdFx0cmV0dXJuIE1hdGguc3FydCggdGhpcy54ICogdGhpcy54ICsgdGhpcy55ICogdGhpcy55ICk7XHJcblxyXG5cdH1cclxuXHJcblx0bWFuaGF0dGFuTGVuZ3RoKCkge1xyXG5cclxuXHRcdHJldHVybiBNYXRoLmFicyggdGhpcy54ICkgKyBNYXRoLmFicyggdGhpcy55ICk7XHJcblxyXG5cdH1cclxuXHJcblx0bm9ybWFsaXplKCkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLmRpdmlkZVNjYWxhciggdGhpcy5sZW5ndGgoKSB8fCAxICk7XHJcblxyXG5cdH1cclxuXHJcblx0YW5nbGUoKSB7XHJcblxyXG5cdFx0Ly8gY29tcHV0ZXMgdGhlIGFuZ2xlIGluIHJhZGlhbnMgd2l0aCByZXNwZWN0IHRvIHRoZSBwb3NpdGl2ZSB4LWF4aXNcclxuXHJcblx0XHRjb25zdCBhbmdsZSA9IE1hdGguYXRhbjIoIC0gdGhpcy55LCAtIHRoaXMueCApICsgTWF0aC5QSTtcclxuXHJcblx0XHRyZXR1cm4gYW5nbGU7XHJcblxyXG5cdH1cclxuXHJcblx0YW5nbGVUbyggdiApIHtcclxuXHJcblx0XHRjb25zdCBkZW5vbWluYXRvciA9IE1hdGguc3FydCggdGhpcy5sZW5ndGhTcSgpICogdi5sZW5ndGhTcSgpICk7XHJcblxyXG5cdFx0aWYgKCBkZW5vbWluYXRvciA9PT0gMCApIHJldHVybiBNYXRoLlBJIC8gMjtcclxuXHJcblx0XHRjb25zdCB0aGV0YSA9IHRoaXMuZG90KCB2ICkgLyBkZW5vbWluYXRvcjtcclxuXHJcblx0XHQvLyBjbGFtcCwgdG8gaGFuZGxlIG51bWVyaWNhbCBwcm9ibGVtc1xyXG5cclxuXHRcdHJldHVybiBNYXRoLmFjb3MoIE1hdGhVdGlscy5jbGFtcCggdGhldGEsIC0gMSwgMSApICk7XHJcblxyXG5cdH1cclxuXHJcblx0ZGlzdGFuY2VUbyggdiApIHtcclxuXHJcblx0XHRyZXR1cm4gTWF0aC5zcXJ0KCB0aGlzLmRpc3RhbmNlVG9TcXVhcmVkKCB2ICkgKTtcclxuXHJcblx0fVxyXG5cclxuXHRkaXN0YW5jZVRvU3F1YXJlZCggdiApIHtcclxuXHJcblx0XHRjb25zdCBkeCA9IHRoaXMueCAtIHYueCwgZHkgPSB0aGlzLnkgLSB2Lnk7XHJcblx0XHRyZXR1cm4gZHggKiBkeCArIGR5ICogZHk7XHJcblxyXG5cdH1cclxuXHJcblx0bWFuaGF0dGFuRGlzdGFuY2VUbyggdiApIHtcclxuXHJcblx0XHRyZXR1cm4gTWF0aC5hYnMoIHRoaXMueCAtIHYueCApICsgTWF0aC5hYnMoIHRoaXMueSAtIHYueSApO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldExlbmd0aCggbGVuZ3RoICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLm5vcm1hbGl6ZSgpLm11bHRpcGx5U2NhbGFyKCBsZW5ndGggKTtcclxuXHJcblx0fVxyXG5cclxuXHRsZXJwKCB2LCBhbHBoYSApIHtcclxuXHJcblx0XHR0aGlzLnggKz0gKCB2LnggLSB0aGlzLnggKSAqIGFscGhhO1xyXG5cdFx0dGhpcy55ICs9ICggdi55IC0gdGhpcy55ICkgKiBhbHBoYTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRsZXJwVmVjdG9ycyggdjEsIHYyLCBhbHBoYSApIHtcclxuXHJcblx0XHR0aGlzLnggPSB2MS54ICsgKCB2Mi54IC0gdjEueCApICogYWxwaGE7XHJcblx0XHR0aGlzLnkgPSB2MS55ICsgKCB2Mi55IC0gdjEueSApICogYWxwaGE7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0ZXF1YWxzKCB2ICkge1xyXG5cclxuXHRcdHJldHVybiAoICggdi54ID09PSB0aGlzLnggKSAmJiAoIHYueSA9PT0gdGhpcy55ICkgKTtcclxuXHJcblx0fVxyXG5cclxuXHRmcm9tQXJyYXkoIGFycmF5LCBvZmZzZXQgPSAwICkge1xyXG5cclxuXHRcdHRoaXMueCA9IGFycmF5WyBvZmZzZXQgXTtcclxuXHRcdHRoaXMueSA9IGFycmF5WyBvZmZzZXQgKyAxIF07XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0dG9BcnJheSggYXJyYXkgPSBbXSwgb2Zmc2V0ID0gMCApIHtcclxuXHJcblx0XHRhcnJheVsgb2Zmc2V0IF0gPSB0aGlzLng7XHJcblx0XHRhcnJheVsgb2Zmc2V0ICsgMSBdID0gdGhpcy55O1xyXG5cclxuXHRcdHJldHVybiBhcnJheTtcclxuXHJcblx0fVxyXG5cclxuXHRmcm9tQnVmZmVyQXR0cmlidXRlKCBhdHRyaWJ1dGUsIGluZGV4ICkge1xyXG5cclxuXHRcdHRoaXMueCA9IGF0dHJpYnV0ZS5nZXRYKCBpbmRleCApO1xyXG5cdFx0dGhpcy55ID0gYXR0cmlidXRlLmdldFkoIGluZGV4ICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0cm90YXRlQXJvdW5kKCBjZW50ZXIsIGFuZ2xlICkge1xyXG5cclxuXHRcdGNvbnN0IGMgPSBNYXRoLmNvcyggYW5nbGUgKSwgcyA9IE1hdGguc2luKCBhbmdsZSApO1xyXG5cclxuXHRcdGNvbnN0IHggPSB0aGlzLnggLSBjZW50ZXIueDtcclxuXHRcdGNvbnN0IHkgPSB0aGlzLnkgLSBjZW50ZXIueTtcclxuXHJcblx0XHR0aGlzLnggPSB4ICogYyAtIHkgKiBzICsgY2VudGVyLng7XHJcblx0XHR0aGlzLnkgPSB4ICogcyArIHkgKiBjICsgY2VudGVyLnk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0cmFuZG9tKCkge1xyXG5cclxuXHRcdHRoaXMueCA9IE1hdGgucmFuZG9tKCk7XHJcblx0XHR0aGlzLnkgPSBNYXRoLnJhbmRvbSgpO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdCpbIFN5bWJvbC5pdGVyYXRvciBdKCkge1xyXG5cclxuXHRcdHlpZWxkIHRoaXMueDtcclxuXHRcdHlpZWxkIHRoaXMueTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgVmVjdG9yMiB9O1xyXG4iLCJjbGFzcyBNYXRyaXgzIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIG4xMSwgbjEyLCBuMTMsIG4yMSwgbjIyLCBuMjMsIG4zMSwgbjMyLCBuMzMgKSB7XHJcblxyXG5cdFx0TWF0cml4My5wcm90b3R5cGUuaXNNYXRyaXgzID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLmVsZW1lbnRzID0gW1xyXG5cclxuXHRcdFx0MSwgMCwgMCxcclxuXHRcdFx0MCwgMSwgMCxcclxuXHRcdFx0MCwgMCwgMVxyXG5cclxuXHRcdF07XHJcblxyXG5cdFx0aWYgKCBuMTEgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdHRoaXMuc2V0KCBuMTEsIG4xMiwgbjEzLCBuMjEsIG4yMiwgbjIzLCBuMzEsIG4zMiwgbjMzICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdHNldCggbjExLCBuMTIsIG4xMywgbjIxLCBuMjIsIG4yMywgbjMxLCBuMzIsIG4zMyApIHtcclxuXHJcblx0XHRjb25zdCB0ZSA9IHRoaXMuZWxlbWVudHM7XHJcblxyXG5cdFx0dGVbIDAgXSA9IG4xMTsgdGVbIDEgXSA9IG4yMTsgdGVbIDIgXSA9IG4zMTtcclxuXHRcdHRlWyAzIF0gPSBuMTI7IHRlWyA0IF0gPSBuMjI7IHRlWyA1IF0gPSBuMzI7XHJcblx0XHR0ZVsgNiBdID0gbjEzOyB0ZVsgNyBdID0gbjIzOyB0ZVsgOCBdID0gbjMzO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGlkZW50aXR5KCkge1xyXG5cclxuXHRcdHRoaXMuc2V0KFxyXG5cclxuXHRcdFx0MSwgMCwgMCxcclxuXHRcdFx0MCwgMSwgMCxcclxuXHRcdFx0MCwgMCwgMVxyXG5cclxuXHRcdCk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggbSApIHtcclxuXHJcblx0XHRjb25zdCB0ZSA9IHRoaXMuZWxlbWVudHM7XHJcblx0XHRjb25zdCBtZSA9IG0uZWxlbWVudHM7XHJcblxyXG5cdFx0dGVbIDAgXSA9IG1lWyAwIF07IHRlWyAxIF0gPSBtZVsgMSBdOyB0ZVsgMiBdID0gbWVbIDIgXTtcclxuXHRcdHRlWyAzIF0gPSBtZVsgMyBdOyB0ZVsgNCBdID0gbWVbIDQgXTsgdGVbIDUgXSA9IG1lWyA1IF07XHJcblx0XHR0ZVsgNiBdID0gbWVbIDYgXTsgdGVbIDcgXSA9IG1lWyA3IF07IHRlWyA4IF0gPSBtZVsgOCBdO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGV4dHJhY3RCYXNpcyggeEF4aXMsIHlBeGlzLCB6QXhpcyApIHtcclxuXHJcblx0XHR4QXhpcy5zZXRGcm9tTWF0cml4M0NvbHVtbiggdGhpcywgMCApO1xyXG5cdFx0eUF4aXMuc2V0RnJvbU1hdHJpeDNDb2x1bW4oIHRoaXMsIDEgKTtcclxuXHRcdHpBeGlzLnNldEZyb21NYXRyaXgzQ29sdW1uKCB0aGlzLCAyICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0RnJvbU1hdHJpeDQoIG0gKSB7XHJcblxyXG5cdFx0Y29uc3QgbWUgPSBtLmVsZW1lbnRzO1xyXG5cclxuXHRcdHRoaXMuc2V0KFxyXG5cclxuXHRcdFx0bWVbIDAgXSwgbWVbIDQgXSwgbWVbIDggXSxcclxuXHRcdFx0bWVbIDEgXSwgbWVbIDUgXSwgbWVbIDkgXSxcclxuXHRcdFx0bWVbIDIgXSwgbWVbIDYgXSwgbWVbIDEwIF1cclxuXHJcblx0XHQpO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdG11bHRpcGx5KCBtICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLm11bHRpcGx5TWF0cmljZXMoIHRoaXMsIG0gKTtcclxuXHJcblx0fVxyXG5cclxuXHRwcmVtdWx0aXBseSggbSApIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5tdWx0aXBseU1hdHJpY2VzKCBtLCB0aGlzICk7XHJcblxyXG5cdH1cclxuXHJcblx0bXVsdGlwbHlNYXRyaWNlcyggYSwgYiApIHtcclxuXHJcblx0XHRjb25zdCBhZSA9IGEuZWxlbWVudHM7XHJcblx0XHRjb25zdCBiZSA9IGIuZWxlbWVudHM7XHJcblx0XHRjb25zdCB0ZSA9IHRoaXMuZWxlbWVudHM7XHJcblxyXG5cdFx0Y29uc3QgYTExID0gYWVbIDAgXSwgYTEyID0gYWVbIDMgXSwgYTEzID0gYWVbIDYgXTtcclxuXHRcdGNvbnN0IGEyMSA9IGFlWyAxIF0sIGEyMiA9IGFlWyA0IF0sIGEyMyA9IGFlWyA3IF07XHJcblx0XHRjb25zdCBhMzEgPSBhZVsgMiBdLCBhMzIgPSBhZVsgNSBdLCBhMzMgPSBhZVsgOCBdO1xyXG5cclxuXHRcdGNvbnN0IGIxMSA9IGJlWyAwIF0sIGIxMiA9IGJlWyAzIF0sIGIxMyA9IGJlWyA2IF07XHJcblx0XHRjb25zdCBiMjEgPSBiZVsgMSBdLCBiMjIgPSBiZVsgNCBdLCBiMjMgPSBiZVsgNyBdO1xyXG5cdFx0Y29uc3QgYjMxID0gYmVbIDIgXSwgYjMyID0gYmVbIDUgXSwgYjMzID0gYmVbIDggXTtcclxuXHJcblx0XHR0ZVsgMCBdID0gYTExICogYjExICsgYTEyICogYjIxICsgYTEzICogYjMxO1xyXG5cdFx0dGVbIDMgXSA9IGExMSAqIGIxMiArIGExMiAqIGIyMiArIGExMyAqIGIzMjtcclxuXHRcdHRlWyA2IF0gPSBhMTEgKiBiMTMgKyBhMTIgKiBiMjMgKyBhMTMgKiBiMzM7XHJcblxyXG5cdFx0dGVbIDEgXSA9IGEyMSAqIGIxMSArIGEyMiAqIGIyMSArIGEyMyAqIGIzMTtcclxuXHRcdHRlWyA0IF0gPSBhMjEgKiBiMTIgKyBhMjIgKiBiMjIgKyBhMjMgKiBiMzI7XHJcblx0XHR0ZVsgNyBdID0gYTIxICogYjEzICsgYTIyICogYjIzICsgYTIzICogYjMzO1xyXG5cclxuXHRcdHRlWyAyIF0gPSBhMzEgKiBiMTEgKyBhMzIgKiBiMjEgKyBhMzMgKiBiMzE7XHJcblx0XHR0ZVsgNSBdID0gYTMxICogYjEyICsgYTMyICogYjIyICsgYTMzICogYjMyO1xyXG5cdFx0dGVbIDggXSA9IGEzMSAqIGIxMyArIGEzMiAqIGIyMyArIGEzMyAqIGIzMztcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRtdWx0aXBseVNjYWxhciggcyApIHtcclxuXHJcblx0XHRjb25zdCB0ZSA9IHRoaXMuZWxlbWVudHM7XHJcblxyXG5cdFx0dGVbIDAgXSAqPSBzOyB0ZVsgMyBdICo9IHM7IHRlWyA2IF0gKj0gcztcclxuXHRcdHRlWyAxIF0gKj0gczsgdGVbIDQgXSAqPSBzOyB0ZVsgNyBdICo9IHM7XHJcblx0XHR0ZVsgMiBdICo9IHM7IHRlWyA1IF0gKj0gczsgdGVbIDggXSAqPSBzO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGRldGVybWluYW50KCkge1xyXG5cclxuXHRcdGNvbnN0IHRlID0gdGhpcy5lbGVtZW50cztcclxuXHJcblx0XHRjb25zdCBhID0gdGVbIDAgXSwgYiA9IHRlWyAxIF0sIGMgPSB0ZVsgMiBdLFxyXG5cdFx0XHRkID0gdGVbIDMgXSwgZSA9IHRlWyA0IF0sIGYgPSB0ZVsgNSBdLFxyXG5cdFx0XHRnID0gdGVbIDYgXSwgaCA9IHRlWyA3IF0sIGkgPSB0ZVsgOCBdO1xyXG5cclxuXHRcdHJldHVybiBhICogZSAqIGkgLSBhICogZiAqIGggLSBiICogZCAqIGkgKyBiICogZiAqIGcgKyBjICogZCAqIGggLSBjICogZSAqIGc7XHJcblxyXG5cdH1cclxuXHJcblx0aW52ZXJ0KCkge1xyXG5cclxuXHRcdGNvbnN0IHRlID0gdGhpcy5lbGVtZW50cyxcclxuXHJcblx0XHRcdG4xMSA9IHRlWyAwIF0sIG4yMSA9IHRlWyAxIF0sIG4zMSA9IHRlWyAyIF0sXHJcblx0XHRcdG4xMiA9IHRlWyAzIF0sIG4yMiA9IHRlWyA0IF0sIG4zMiA9IHRlWyA1IF0sXHJcblx0XHRcdG4xMyA9IHRlWyA2IF0sIG4yMyA9IHRlWyA3IF0sIG4zMyA9IHRlWyA4IF0sXHJcblxyXG5cdFx0XHR0MTEgPSBuMzMgKiBuMjIgLSBuMzIgKiBuMjMsXHJcblx0XHRcdHQxMiA9IG4zMiAqIG4xMyAtIG4zMyAqIG4xMixcclxuXHRcdFx0dDEzID0gbjIzICogbjEyIC0gbjIyICogbjEzLFxyXG5cclxuXHRcdFx0ZGV0ID0gbjExICogdDExICsgbjIxICogdDEyICsgbjMxICogdDEzO1xyXG5cclxuXHRcdGlmICggZGV0ID09PSAwICkgcmV0dXJuIHRoaXMuc2V0KCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwICk7XHJcblxyXG5cdFx0Y29uc3QgZGV0SW52ID0gMSAvIGRldDtcclxuXHJcblx0XHR0ZVsgMCBdID0gdDExICogZGV0SW52O1xyXG5cdFx0dGVbIDEgXSA9ICggbjMxICogbjIzIC0gbjMzICogbjIxICkgKiBkZXRJbnY7XHJcblx0XHR0ZVsgMiBdID0gKCBuMzIgKiBuMjEgLSBuMzEgKiBuMjIgKSAqIGRldEludjtcclxuXHJcblx0XHR0ZVsgMyBdID0gdDEyICogZGV0SW52O1xyXG5cdFx0dGVbIDQgXSA9ICggbjMzICogbjExIC0gbjMxICogbjEzICkgKiBkZXRJbnY7XHJcblx0XHR0ZVsgNSBdID0gKCBuMzEgKiBuMTIgLSBuMzIgKiBuMTEgKSAqIGRldEludjtcclxuXHJcblx0XHR0ZVsgNiBdID0gdDEzICogZGV0SW52O1xyXG5cdFx0dGVbIDcgXSA9ICggbjIxICogbjEzIC0gbjIzICogbjExICkgKiBkZXRJbnY7XHJcblx0XHR0ZVsgOCBdID0gKCBuMjIgKiBuMTEgLSBuMjEgKiBuMTIgKSAqIGRldEludjtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHR0cmFuc3Bvc2UoKSB7XHJcblxyXG5cdFx0bGV0IHRtcDtcclxuXHRcdGNvbnN0IG0gPSB0aGlzLmVsZW1lbnRzO1xyXG5cclxuXHRcdHRtcCA9IG1bIDEgXTsgbVsgMSBdID0gbVsgMyBdOyBtWyAzIF0gPSB0bXA7XHJcblx0XHR0bXAgPSBtWyAyIF07IG1bIDIgXSA9IG1bIDYgXTsgbVsgNiBdID0gdG1wO1xyXG5cdFx0dG1wID0gbVsgNSBdOyBtWyA1IF0gPSBtWyA3IF07IG1bIDcgXSA9IHRtcDtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRnZXROb3JtYWxNYXRyaXgoIG1hdHJpeDQgKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuc2V0RnJvbU1hdHJpeDQoIG1hdHJpeDQgKS5pbnZlcnQoKS50cmFuc3Bvc2UoKTtcclxuXHJcblx0fVxyXG5cclxuXHR0cmFuc3Bvc2VJbnRvQXJyYXkoIHIgKSB7XHJcblxyXG5cdFx0Y29uc3QgbSA9IHRoaXMuZWxlbWVudHM7XHJcblxyXG5cdFx0clsgMCBdID0gbVsgMCBdO1xyXG5cdFx0clsgMSBdID0gbVsgMyBdO1xyXG5cdFx0clsgMiBdID0gbVsgNiBdO1xyXG5cdFx0clsgMyBdID0gbVsgMSBdO1xyXG5cdFx0clsgNCBdID0gbVsgNCBdO1xyXG5cdFx0clsgNSBdID0gbVsgNyBdO1xyXG5cdFx0clsgNiBdID0gbVsgMiBdO1xyXG5cdFx0clsgNyBdID0gbVsgNSBdO1xyXG5cdFx0clsgOCBdID0gbVsgOCBdO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldFV2VHJhbnNmb3JtKCB0eCwgdHksIHN4LCBzeSwgcm90YXRpb24sIGN4LCBjeSApIHtcclxuXHJcblx0XHRjb25zdCBjID0gTWF0aC5jb3MoIHJvdGF0aW9uICk7XHJcblx0XHRjb25zdCBzID0gTWF0aC5zaW4oIHJvdGF0aW9uICk7XHJcblxyXG5cdFx0dGhpcy5zZXQoXHJcblx0XHRcdHN4ICogYywgc3ggKiBzLCAtIHN4ICogKCBjICogY3ggKyBzICogY3kgKSArIGN4ICsgdHgsXHJcblx0XHRcdC0gc3kgKiBzLCBzeSAqIGMsIC0gc3kgKiAoIC0gcyAqIGN4ICsgYyAqIGN5ICkgKyBjeSArIHR5LFxyXG5cdFx0XHQwLCAwLCAxXHJcblx0XHQpO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdC8vXHJcblxyXG5cdHNjYWxlKCBzeCwgc3kgKSB7XHJcblxyXG5cdFx0dGhpcy5wcmVtdWx0aXBseSggX20zLm1ha2VTY2FsZSggc3gsIHN5ICkgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRyb3RhdGUoIHRoZXRhICkge1xyXG5cclxuXHRcdHRoaXMucHJlbXVsdGlwbHkoIF9tMy5tYWtlUm90YXRpb24oIC0gdGhldGEgKSApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHRyYW5zbGF0ZSggdHgsIHR5ICkge1xyXG5cclxuXHRcdHRoaXMucHJlbXVsdGlwbHkoIF9tMy5tYWtlVHJhbnNsYXRpb24oIHR4LCB0eSApICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gZm9yIDJEIFRyYW5zZm9ybXNcclxuXHJcblx0bWFrZVRyYW5zbGF0aW9uKCB4LCB5ICkge1xyXG5cclxuXHRcdGlmICggeC5pc1ZlY3RvcjIgKSB7XHJcblxyXG5cdFx0XHR0aGlzLnNldChcclxuXHJcblx0XHRcdFx0MSwgMCwgeC54LFxyXG5cdFx0XHRcdDAsIDEsIHgueSxcclxuXHRcdFx0XHQwLCAwLCAxXHJcblxyXG5cdFx0XHQpO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHR0aGlzLnNldChcclxuXHJcblx0XHRcdFx0MSwgMCwgeCxcclxuXHRcdFx0XHQwLCAxLCB5LFxyXG5cdFx0XHRcdDAsIDAsIDFcclxuXHJcblx0XHRcdCk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdG1ha2VSb3RhdGlvbiggdGhldGEgKSB7XHJcblxyXG5cdFx0Ly8gY291bnRlcmNsb2Nrd2lzZVxyXG5cclxuXHRcdGNvbnN0IGMgPSBNYXRoLmNvcyggdGhldGEgKTtcclxuXHRcdGNvbnN0IHMgPSBNYXRoLnNpbiggdGhldGEgKTtcclxuXHJcblx0XHR0aGlzLnNldChcclxuXHJcblx0XHRcdGMsIC0gcywgMCxcclxuXHRcdFx0cywgYywgMCxcclxuXHRcdFx0MCwgMCwgMVxyXG5cclxuXHRcdCk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0bWFrZVNjYWxlKCB4LCB5ICkge1xyXG5cclxuXHRcdHRoaXMuc2V0KFxyXG5cclxuXHRcdFx0eCwgMCwgMCxcclxuXHRcdFx0MCwgeSwgMCxcclxuXHRcdFx0MCwgMCwgMVxyXG5cclxuXHRcdCk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Ly9cclxuXHJcblx0ZXF1YWxzKCBtYXRyaXggKSB7XHJcblxyXG5cdFx0Y29uc3QgdGUgPSB0aGlzLmVsZW1lbnRzO1xyXG5cdFx0Y29uc3QgbWUgPSBtYXRyaXguZWxlbWVudHM7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgOTsgaSArKyApIHtcclxuXHJcblx0XHRcdGlmICggdGVbIGkgXSAhPT0gbWVbIGkgXSApIHJldHVybiBmYWxzZTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRydWU7XHJcblxyXG5cdH1cclxuXHJcblx0ZnJvbUFycmF5KCBhcnJheSwgb2Zmc2V0ID0gMCApIHtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCA5OyBpICsrICkge1xyXG5cclxuXHRcdFx0dGhpcy5lbGVtZW50c1sgaSBdID0gYXJyYXlbIGkgKyBvZmZzZXQgXTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0dG9BcnJheSggYXJyYXkgPSBbXSwgb2Zmc2V0ID0gMCApIHtcclxuXHJcblx0XHRjb25zdCB0ZSA9IHRoaXMuZWxlbWVudHM7XHJcblxyXG5cdFx0YXJyYXlbIG9mZnNldCBdID0gdGVbIDAgXTtcclxuXHRcdGFycmF5WyBvZmZzZXQgKyAxIF0gPSB0ZVsgMSBdO1xyXG5cdFx0YXJyYXlbIG9mZnNldCArIDIgXSA9IHRlWyAyIF07XHJcblxyXG5cdFx0YXJyYXlbIG9mZnNldCArIDMgXSA9IHRlWyAzIF07XHJcblx0XHRhcnJheVsgb2Zmc2V0ICsgNCBdID0gdGVbIDQgXTtcclxuXHRcdGFycmF5WyBvZmZzZXQgKyA1IF0gPSB0ZVsgNSBdO1xyXG5cclxuXHRcdGFycmF5WyBvZmZzZXQgKyA2IF0gPSB0ZVsgNiBdO1xyXG5cdFx0YXJyYXlbIG9mZnNldCArIDcgXSA9IHRlWyA3IF07XHJcblx0XHRhcnJheVsgb2Zmc2V0ICsgOCBdID0gdGVbIDggXTtcclxuXHJcblx0XHRyZXR1cm4gYXJyYXk7XHJcblxyXG5cdH1cclxuXHJcblx0Y2xvbmUoKSB7XHJcblxyXG5cdFx0cmV0dXJuIG5ldyB0aGlzLmNvbnN0cnVjdG9yKCkuZnJvbUFycmF5KCB0aGlzLmVsZW1lbnRzICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmNvbnN0IF9tMyA9IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDMoKTtcclxuXHJcbmV4cG9ydCB7IE1hdHJpeDMgfTtcclxuIiwiZnVuY3Rpb24gYXJyYXlNaW4oIGFycmF5ICkge1xyXG5cclxuXHRpZiAoIGFycmF5Lmxlbmd0aCA9PT0gMCApIHJldHVybiBJbmZpbml0eTtcclxuXHJcblx0bGV0IG1pbiA9IGFycmF5WyAwIF07XHJcblxyXG5cdGZvciAoIGxldCBpID0gMSwgbCA9IGFycmF5Lmxlbmd0aDsgaSA8IGw7ICsrIGkgKSB7XHJcblxyXG5cdFx0aWYgKCBhcnJheVsgaSBdIDwgbWluICkgbWluID0gYXJyYXlbIGkgXTtcclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4gbWluO1xyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gYXJyYXlNYXgoIGFycmF5ICkge1xyXG5cclxuXHRpZiAoIGFycmF5Lmxlbmd0aCA9PT0gMCApIHJldHVybiAtIEluZmluaXR5O1xyXG5cclxuXHRsZXQgbWF4ID0gYXJyYXlbIDAgXTtcclxuXHJcblx0Zm9yICggbGV0IGkgPSAxLCBsID0gYXJyYXkubGVuZ3RoOyBpIDwgbDsgKysgaSApIHtcclxuXHJcblx0XHRpZiAoIGFycmF5WyBpIF0gPiBtYXggKSBtYXggPSBhcnJheVsgaSBdO1xyXG5cclxuXHR9XHJcblxyXG5cdHJldHVybiBtYXg7XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiBhcnJheU5lZWRzVWludDMyKCBhcnJheSApIHtcclxuXHJcblx0Ly8gYXNzdW1lcyBsYXJnZXIgdmFsdWVzIHVzdWFsbHkgb24gbGFzdFxyXG5cclxuXHRmb3IgKCBsZXQgaSA9IGFycmF5Lmxlbmd0aCAtIDE7IGkgPj0gMDsgLS0gaSApIHtcclxuXHJcblx0XHRpZiAoIGFycmF5WyBpIF0gPj0gNjU1MzUgKSByZXR1cm4gdHJ1ZTsgLy8gYWNjb3VudCBmb3IgUFJJTUlUSVZFX1JFU1RBUlRfRklYRURfSU5ERVgsICMyNDU2NVxyXG5cclxuXHR9XHJcblxyXG5cdHJldHVybiBmYWxzZTtcclxuXHJcbn1cclxuXHJcbmNvbnN0IFRZUEVEX0FSUkFZUyA9IHtcclxuXHRJbnQ4QXJyYXk6IEludDhBcnJheSxcclxuXHRVaW50OEFycmF5OiBVaW50OEFycmF5LFxyXG5cdFVpbnQ4Q2xhbXBlZEFycmF5OiBVaW50OENsYW1wZWRBcnJheSxcclxuXHRJbnQxNkFycmF5OiBJbnQxNkFycmF5LFxyXG5cdFVpbnQxNkFycmF5OiBVaW50MTZBcnJheSxcclxuXHRJbnQzMkFycmF5OiBJbnQzMkFycmF5LFxyXG5cdFVpbnQzMkFycmF5OiBVaW50MzJBcnJheSxcclxuXHRGbG9hdDMyQXJyYXk6IEZsb2F0MzJBcnJheSxcclxuXHRGbG9hdDY0QXJyYXk6IEZsb2F0NjRBcnJheVxyXG59O1xyXG5cclxuZnVuY3Rpb24gZ2V0VHlwZWRBcnJheSggdHlwZSwgYnVmZmVyICkge1xyXG5cclxuXHRyZXR1cm4gbmV3IFRZUEVEX0FSUkFZU1sgdHlwZSBdKCBidWZmZXIgKTtcclxuXHJcbn1cclxuXHJcbmZ1bmN0aW9uIGNyZWF0ZUVsZW1lbnROUyggbmFtZSApIHtcclxuXHJcblx0cmV0dXJuIGRvY3VtZW50LmNyZWF0ZUVsZW1lbnROUyggJ2h0dHA6Ly93d3cudzMub3JnLzE5OTkveGh0bWwnLCBuYW1lICk7XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiBjcmVhdGVDYW52YXNFbGVtZW50KCkge1xyXG5cclxuXHRjb25zdCBjYW52YXMgPSBjcmVhdGVFbGVtZW50TlMoICdjYW52YXMnICk7XHJcblx0Y2FudmFzLnN0eWxlLmRpc3BsYXkgPSAnYmxvY2snO1xyXG5cdHJldHVybiBjYW52YXM7XHJcblxyXG59XHJcblxyXG5jb25zdCBfY2FjaGUgPSB7fTtcclxuXHJcbmZ1bmN0aW9uIHdhcm5PbmNlKCBtZXNzYWdlICkge1xyXG5cclxuXHRpZiAoIG1lc3NhZ2UgaW4gX2NhY2hlICkgcmV0dXJuO1xyXG5cclxuXHRfY2FjaGVbIG1lc3NhZ2UgXSA9IHRydWU7XHJcblxyXG5cdGNvbnNvbGUud2FybiggbWVzc2FnZSApO1xyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgYXJyYXlNaW4sIGFycmF5TWF4LCBhcnJheU5lZWRzVWludDMyLCBnZXRUeXBlZEFycmF5LCBjcmVhdGVFbGVtZW50TlMsIGNyZWF0ZUNhbnZhc0VsZW1lbnQsIHdhcm5PbmNlIH07XHJcbiIsImltcG9ydCB7IFNSR0JDb2xvclNwYWNlLCBMaW5lYXJTUkdCQ29sb3JTcGFjZSwgRGlzcGxheVAzQ29sb3JTcGFjZSwgTGluZWFyRGlzcGxheVAzQ29sb3JTcGFjZSwgUmVjNzA5UHJpbWFyaWVzLCBQM1ByaW1hcmllcywgU1JHQlRyYW5zZmVyLCBMaW5lYXJUcmFuc2ZlciwgTm9Db2xvclNwYWNlLCB9IGZyb20gJy4uL2NvbnN0YW50cy5qcyc7XHJcbmltcG9ydCB7IE1hdHJpeDMgfSBmcm9tICcuL01hdHJpeDMuanMnO1xyXG5cclxuLyoqXHJcbiAqIE1hdHJpY2VzIGNvbnZlcnRpbmcgUDMgPC0+IFJlYy4gNzA5IHByaW1hcmllcywgd2l0aG91dCBnYW11dCBtYXBwaW5nXHJcbiAqIG9yIGNsaXBwaW5nLiBCYXNlZCBvbiBXM0Mgc3BlY2lmaWNhdGlvbnMgZm9yIHNSR0IgYW5kIERpc3BsYXkgUDMsXHJcbiAqIGFuZCBJQ0Mgc3BlY2lmaWNhdGlvbnMgZm9yIHRoZSBENTAgY29ubmVjdGlvbiBzcGFjZS4gVmFsdWVzIGluL291dFxyXG4gKiBhcmUgX2xpbmVhcl8gc1JHQiBhbmQgX2xpbmVhcl8gRGlzcGxheSBQMy5cclxuICpcclxuICogTm90ZSB0aGF0IGJvdGggc1JHQiBhbmQgRGlzcGxheSBQMyB1c2UgdGhlIHNSR0IgdHJhbnNmZXIgZnVuY3Rpb25zLlxyXG4gKlxyXG4gKiBSZWZlcmVuY2U6XHJcbiAqIC0gaHR0cDovL3d3dy5ydXNzZWxsY290dHJlbGwuY29tL3Bob3RvL21hdHJpeENhbGN1bGF0b3IuaHRtXHJcbiAqL1xyXG5cclxuY29uc3QgTElORUFSX1NSR0JfVE9fTElORUFSX0RJU1BMQVlfUDMgPSAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXgzKCkuc2V0KFxyXG5cdDAuODIyNDYyMSwgMC4xNzc1MzgsIDAuMCxcclxuXHQwLjAzMzE5NDEsIDAuOTY2ODA1OCwgMC4wLFxyXG5cdDAuMDE3MDgyNywgMC4wNzIzOTc0LCAwLjkxMDUxOTksXHJcbik7XHJcblxyXG5jb25zdCBMSU5FQVJfRElTUExBWV9QM19UT19MSU5FQVJfU1JHQiA9IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDMoKS5zZXQoXHJcblx0MS4yMjQ5NDAxLCAtIDAuMjI0OTQwNCwgMC4wLFxyXG5cdC0gMC4wNDIwNTY5LCAxLjA0MjA1NzEsIDAuMCxcclxuXHQtIDAuMDE5NjM3NiwgLSAwLjA3ODYzNjEsIDEuMDk4MjczNVxyXG4pO1xyXG5cclxuLyoqXHJcbiAqIERlZmluZXMgc3VwcG9ydGVkIGNvbG9yIHNwYWNlcyBieSB0cmFuc2ZlciBmdW5jdGlvbiBhbmQgcHJpbWFyaWVzLFxyXG4gKiBhbmQgcHJvdmlkZXMgY29udmVyc2lvbnMgdG8vZnJvbSB0aGUgTGluZWFyLXNSR0IgcmVmZXJlbmNlIHNwYWNlLlxyXG4gKi9cclxuY29uc3QgQ09MT1JfU1BBQ0VTID0ge1xyXG5cdFsgTGluZWFyU1JHQkNvbG9yU3BhY2UgXToge1xyXG5cdFx0dHJhbnNmZXI6IExpbmVhclRyYW5zZmVyLFxyXG5cdFx0cHJpbWFyaWVzOiBSZWM3MDlQcmltYXJpZXMsXHJcblx0XHR0b1JlZmVyZW5jZTogKCBjb2xvciApID0+IGNvbG9yLFxyXG5cdFx0ZnJvbVJlZmVyZW5jZTogKCBjb2xvciApID0+IGNvbG9yLFxyXG5cdH0sXHJcblx0WyBTUkdCQ29sb3JTcGFjZSBdOiB7XHJcblx0XHR0cmFuc2ZlcjogU1JHQlRyYW5zZmVyLFxyXG5cdFx0cHJpbWFyaWVzOiBSZWM3MDlQcmltYXJpZXMsXHJcblx0XHR0b1JlZmVyZW5jZTogKCBjb2xvciApID0+IGNvbG9yLmNvbnZlcnRTUkdCVG9MaW5lYXIoKSxcclxuXHRcdGZyb21SZWZlcmVuY2U6ICggY29sb3IgKSA9PiBjb2xvci5jb252ZXJ0TGluZWFyVG9TUkdCKCksXHJcblx0fSxcclxuXHRbIExpbmVhckRpc3BsYXlQM0NvbG9yU3BhY2UgXToge1xyXG5cdFx0dHJhbnNmZXI6IExpbmVhclRyYW5zZmVyLFxyXG5cdFx0cHJpbWFyaWVzOiBQM1ByaW1hcmllcyxcclxuXHRcdHRvUmVmZXJlbmNlOiAoIGNvbG9yICkgPT4gY29sb3IuYXBwbHlNYXRyaXgzKCBMSU5FQVJfRElTUExBWV9QM19UT19MSU5FQVJfU1JHQiApLFxyXG5cdFx0ZnJvbVJlZmVyZW5jZTogKCBjb2xvciApID0+IGNvbG9yLmFwcGx5TWF0cml4MyggTElORUFSX1NSR0JfVE9fTElORUFSX0RJU1BMQVlfUDMgKSxcclxuXHR9LFxyXG5cdFsgRGlzcGxheVAzQ29sb3JTcGFjZSBdOiB7XHJcblx0XHR0cmFuc2ZlcjogU1JHQlRyYW5zZmVyLFxyXG5cdFx0cHJpbWFyaWVzOiBQM1ByaW1hcmllcyxcclxuXHRcdHRvUmVmZXJlbmNlOiAoIGNvbG9yICkgPT4gY29sb3IuY29udmVydFNSR0JUb0xpbmVhcigpLmFwcGx5TWF0cml4MyggTElORUFSX0RJU1BMQVlfUDNfVE9fTElORUFSX1NSR0IgKSxcclxuXHRcdGZyb21SZWZlcmVuY2U6ICggY29sb3IgKSA9PiBjb2xvci5hcHBseU1hdHJpeDMoIExJTkVBUl9TUkdCX1RPX0xJTkVBUl9ESVNQTEFZX1AzICkuY29udmVydExpbmVhclRvU1JHQigpLFxyXG5cdH0sXHJcbn07XHJcblxyXG5jb25zdCBTVVBQT1JURURfV09SS0lOR19DT0xPUl9TUEFDRVMgPSBuZXcgU2V0KCBbIExpbmVhclNSR0JDb2xvclNwYWNlLCBMaW5lYXJEaXNwbGF5UDNDb2xvclNwYWNlIF0gKTtcclxuXHJcbmV4cG9ydCBjb25zdCBDb2xvck1hbmFnZW1lbnQgPSB7XHJcblxyXG5cdGVuYWJsZWQ6IHRydWUsXHJcblxyXG5cdF93b3JraW5nQ29sb3JTcGFjZTogTGluZWFyU1JHQkNvbG9yU3BhY2UsXHJcblxyXG5cdGdldCB3b3JraW5nQ29sb3JTcGFjZSgpIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5fd29ya2luZ0NvbG9yU3BhY2U7XHJcblxyXG5cdH0sXHJcblxyXG5cdHNldCB3b3JraW5nQ29sb3JTcGFjZSggY29sb3JTcGFjZSApIHtcclxuXHJcblx0XHRpZiAoICEgU1VQUE9SVEVEX1dPUktJTkdfQ09MT1JfU1BBQ0VTLmhhcyggY29sb3JTcGFjZSApICkge1xyXG5cclxuXHRcdFx0dGhyb3cgbmV3IEVycm9yKCBgVW5zdXBwb3J0ZWQgd29ya2luZyBjb2xvciBzcGFjZSwgXCIkeyBjb2xvclNwYWNlIH1cIi5gICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMuX3dvcmtpbmdDb2xvclNwYWNlID0gY29sb3JTcGFjZTtcclxuXHJcblx0fSxcclxuXHJcblx0Y29udmVydDogZnVuY3Rpb24gKCBjb2xvciwgc291cmNlQ29sb3JTcGFjZSwgdGFyZ2V0Q29sb3JTcGFjZSApIHtcclxuXHJcblx0XHRpZiAoIHRoaXMuZW5hYmxlZCA9PT0gZmFsc2UgfHwgc291cmNlQ29sb3JTcGFjZSA9PT0gdGFyZ2V0Q29sb3JTcGFjZSB8fCAhIHNvdXJjZUNvbG9yU3BhY2UgfHwgISB0YXJnZXRDb2xvclNwYWNlICkge1xyXG5cclxuXHRcdFx0cmV0dXJuIGNvbG9yO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCBzb3VyY2VUb1JlZmVyZW5jZSA9IENPTE9SX1NQQUNFU1sgc291cmNlQ29sb3JTcGFjZSBdLnRvUmVmZXJlbmNlO1xyXG5cdFx0Y29uc3QgdGFyZ2V0RnJvbVJlZmVyZW5jZSA9IENPTE9SX1NQQUNFU1sgdGFyZ2V0Q29sb3JTcGFjZSBdLmZyb21SZWZlcmVuY2U7XHJcblxyXG5cdFx0cmV0dXJuIHRhcmdldEZyb21SZWZlcmVuY2UoIHNvdXJjZVRvUmVmZXJlbmNlKCBjb2xvciApICk7XHJcblxyXG5cdH0sXHJcblxyXG5cdGZyb21Xb3JraW5nQ29sb3JTcGFjZTogZnVuY3Rpb24gKCBjb2xvciwgdGFyZ2V0Q29sb3JTcGFjZSApIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5jb252ZXJ0KCBjb2xvciwgdGhpcy5fd29ya2luZ0NvbG9yU3BhY2UsIHRhcmdldENvbG9yU3BhY2UgKTtcclxuXHJcblx0fSxcclxuXHJcblx0dG9Xb3JraW5nQ29sb3JTcGFjZTogZnVuY3Rpb24gKCBjb2xvciwgc291cmNlQ29sb3JTcGFjZSApIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5jb252ZXJ0KCBjb2xvciwgc291cmNlQ29sb3JTcGFjZSwgdGhpcy5fd29ya2luZ0NvbG9yU3BhY2UgKTtcclxuXHJcblx0fSxcclxuXHJcblx0Z2V0UHJpbWFyaWVzOiBmdW5jdGlvbiAoIGNvbG9yU3BhY2UgKSB7XHJcblxyXG5cdFx0cmV0dXJuIENPTE9SX1NQQUNFU1sgY29sb3JTcGFjZSBdLnByaW1hcmllcztcclxuXHJcblx0fSxcclxuXHJcblx0Z2V0VHJhbnNmZXI6IGZ1bmN0aW9uICggY29sb3JTcGFjZSApIHtcclxuXHJcblx0XHRpZiAoIGNvbG9yU3BhY2UgPT09IE5vQ29sb3JTcGFjZSApIHJldHVybiBMaW5lYXJUcmFuc2ZlcjtcclxuXHJcblx0XHRyZXR1cm4gQ09MT1JfU1BBQ0VTWyBjb2xvclNwYWNlIF0udHJhbnNmZXI7XHJcblxyXG5cdH0sXHJcblxyXG59O1xyXG5cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBTUkdCVG9MaW5lYXIoIGMgKSB7XHJcblxyXG5cdHJldHVybiAoIGMgPCAwLjA0MDQ1ICkgPyBjICogMC4wNzczOTkzODA4IDogTWF0aC5wb3coIGMgKiAwLjk0Nzg2NzI5ODYgKyAwLjA1MjEzMjcwMTQsIDIuNCApO1xyXG5cclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIExpbmVhclRvU1JHQiggYyApIHtcclxuXHJcblx0cmV0dXJuICggYyA8IDAuMDAzMTMwOCApID8gYyAqIDEyLjkyIDogMS4wNTUgKiAoIE1hdGgucG93KCBjLCAwLjQxNjY2ICkgKSAtIDAuMDU1O1xyXG5cclxufVxyXG4iLCJpbXBvcnQgeyBjcmVhdGVFbGVtZW50TlMgfSBmcm9tICcuLi91dGlscy5qcyc7XHJcbmltcG9ydCB7IFNSR0JUb0xpbmVhciB9IGZyb20gJy4uL21hdGgvQ29sb3JNYW5hZ2VtZW50LmpzJztcclxuXHJcbmxldCBfY2FudmFzO1xyXG5cclxuY2xhc3MgSW1hZ2VVdGlscyB7XHJcblxyXG5cdHN0YXRpYyBnZXREYXRhVVJMKCBpbWFnZSApIHtcclxuXHJcblx0XHRpZiAoIC9eZGF0YTovaS50ZXN0KCBpbWFnZS5zcmMgKSApIHtcclxuXHJcblx0XHRcdHJldHVybiBpbWFnZS5zcmM7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggdHlwZW9mIEhUTUxDYW52YXNFbGVtZW50ID09PSAndW5kZWZpbmVkJyApIHtcclxuXHJcblx0XHRcdHJldHVybiBpbWFnZS5zcmM7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGxldCBjYW52YXM7XHJcblxyXG5cdFx0aWYgKCBpbWFnZSBpbnN0YW5jZW9mIEhUTUxDYW52YXNFbGVtZW50ICkge1xyXG5cclxuXHRcdFx0Y2FudmFzID0gaW1hZ2U7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdGlmICggX2NhbnZhcyA9PT0gdW5kZWZpbmVkICkgX2NhbnZhcyA9IGNyZWF0ZUVsZW1lbnROUyggJ2NhbnZhcycgKTtcclxuXHJcblx0XHRcdF9jYW52YXMud2lkdGggPSBpbWFnZS53aWR0aDtcclxuXHRcdFx0X2NhbnZhcy5oZWlnaHQgPSBpbWFnZS5oZWlnaHQ7XHJcblxyXG5cdFx0XHRjb25zdCBjb250ZXh0ID0gX2NhbnZhcy5nZXRDb250ZXh0KCAnMmQnICk7XHJcblxyXG5cdFx0XHRpZiAoIGltYWdlIGluc3RhbmNlb2YgSW1hZ2VEYXRhICkge1xyXG5cclxuXHRcdFx0XHRjb250ZXh0LnB1dEltYWdlRGF0YSggaW1hZ2UsIDAsIDAgKTtcclxuXHJcblx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdGNvbnRleHQuZHJhd0ltYWdlKCBpbWFnZSwgMCwgMCwgaW1hZ2Uud2lkdGgsIGltYWdlLmhlaWdodCApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Y2FudmFzID0gX2NhbnZhcztcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBjYW52YXMud2lkdGggPiAyMDQ4IHx8IGNhbnZhcy5oZWlnaHQgPiAyMDQ4ICkge1xyXG5cclxuXHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuSW1hZ2VVdGlscy5nZXREYXRhVVJMOiBJbWFnZSBjb252ZXJ0ZWQgdG8ganBnIGZvciBwZXJmb3JtYW5jZSByZWFzb25zJywgaW1hZ2UgKTtcclxuXHJcblx0XHRcdHJldHVybiBjYW52YXMudG9EYXRhVVJMKCAnaW1hZ2UvanBlZycsIDAuNiApO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRyZXR1cm4gY2FudmFzLnRvRGF0YVVSTCggJ2ltYWdlL3BuZycgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0c3RhdGljIHNSR0JUb0xpbmVhciggaW1hZ2UgKSB7XHJcblxyXG5cdFx0aWYgKCAoIHR5cGVvZiBIVE1MSW1hZ2VFbGVtZW50ICE9PSAndW5kZWZpbmVkJyAmJiBpbWFnZSBpbnN0YW5jZW9mIEhUTUxJbWFnZUVsZW1lbnQgKSB8fFxyXG5cdFx0XHQoIHR5cGVvZiBIVE1MQ2FudmFzRWxlbWVudCAhPT0gJ3VuZGVmaW5lZCcgJiYgaW1hZ2UgaW5zdGFuY2VvZiBIVE1MQ2FudmFzRWxlbWVudCApIHx8XHJcblx0XHRcdCggdHlwZW9mIEltYWdlQml0bWFwICE9PSAndW5kZWZpbmVkJyAmJiBpbWFnZSBpbnN0YW5jZW9mIEltYWdlQml0bWFwICkgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBjYW52YXMgPSBjcmVhdGVFbGVtZW50TlMoICdjYW52YXMnICk7XHJcblxyXG5cdFx0XHRjYW52YXMud2lkdGggPSBpbWFnZS53aWR0aDtcclxuXHRcdFx0Y2FudmFzLmhlaWdodCA9IGltYWdlLmhlaWdodDtcclxuXHJcblx0XHRcdGNvbnN0IGNvbnRleHQgPSBjYW52YXMuZ2V0Q29udGV4dCggJzJkJyApO1xyXG5cdFx0XHRjb250ZXh0LmRyYXdJbWFnZSggaW1hZ2UsIDAsIDAsIGltYWdlLndpZHRoLCBpbWFnZS5oZWlnaHQgKTtcclxuXHJcblx0XHRcdGNvbnN0IGltYWdlRGF0YSA9IGNvbnRleHQuZ2V0SW1hZ2VEYXRhKCAwLCAwLCBpbWFnZS53aWR0aCwgaW1hZ2UuaGVpZ2h0ICk7XHJcblx0XHRcdGNvbnN0IGRhdGEgPSBpbWFnZURhdGEuZGF0YTtcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IGRhdGEubGVuZ3RoOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRkYXRhWyBpIF0gPSBTUkdCVG9MaW5lYXIoIGRhdGFbIGkgXSAvIDI1NSApICogMjU1O1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Y29udGV4dC5wdXRJbWFnZURhdGEoIGltYWdlRGF0YSwgMCwgMCApO1xyXG5cclxuXHRcdFx0cmV0dXJuIGNhbnZhcztcclxuXHJcblx0XHR9IGVsc2UgaWYgKCBpbWFnZS5kYXRhICkge1xyXG5cclxuXHRcdFx0Y29uc3QgZGF0YSA9IGltYWdlLmRhdGEuc2xpY2UoIDAgKTtcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IGRhdGEubGVuZ3RoOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRpZiAoIGRhdGEgaW5zdGFuY2VvZiBVaW50OEFycmF5IHx8IGRhdGEgaW5zdGFuY2VvZiBVaW50OENsYW1wZWRBcnJheSApIHtcclxuXHJcblx0XHRcdFx0XHRkYXRhWyBpIF0gPSBNYXRoLmZsb29yKCBTUkdCVG9MaW5lYXIoIGRhdGFbIGkgXSAvIDI1NSApICogMjU1ICk7XHJcblxyXG5cdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0Ly8gYXNzdW1pbmcgZmxvYXRcclxuXHJcblx0XHRcdFx0XHRkYXRhWyBpIF0gPSBTUkdCVG9MaW5lYXIoIGRhdGFbIGkgXSApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRyZXR1cm4ge1xyXG5cdFx0XHRcdGRhdGE6IGRhdGEsXHJcblx0XHRcdFx0d2lkdGg6IGltYWdlLndpZHRoLFxyXG5cdFx0XHRcdGhlaWdodDogaW1hZ2UuaGVpZ2h0XHJcblx0XHRcdH07XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLkltYWdlVXRpbHMuc1JHQlRvTGluZWFyKCk6IFVuc3VwcG9ydGVkIGltYWdlIHR5cGUuIE5vIGNvbG9yIHNwYWNlIGNvbnZlcnNpb24gYXBwbGllZC4nICk7XHJcblx0XHRcdHJldHVybiBpbWFnZTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IEltYWdlVXRpbHMgfTtcclxuIiwiaW1wb3J0IHsgSW1hZ2VVdGlscyB9IGZyb20gJy4uL2V4dHJhcy9JbWFnZVV0aWxzLmpzJztcclxuaW1wb3J0ICogYXMgTWF0aFV0aWxzIGZyb20gJy4uL21hdGgvTWF0aFV0aWxzLmpzJztcclxuXHJcbmxldCBfc291cmNlSWQgPSAwO1xyXG5cclxuY2xhc3MgU291cmNlIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIGRhdGEgPSBudWxsICkge1xyXG5cclxuXHRcdHRoaXMuaXNTb3VyY2UgPSB0cnVlO1xyXG5cclxuXHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eSggdGhpcywgJ2lkJywgeyB2YWx1ZTogX3NvdXJjZUlkICsrIH0gKTtcclxuXHJcblx0XHR0aGlzLnV1aWQgPSBNYXRoVXRpbHMuZ2VuZXJhdGVVVUlEKCk7XHJcblxyXG5cdFx0dGhpcy5kYXRhID0gZGF0YTtcclxuXHRcdHRoaXMuZGF0YVJlYWR5ID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLnZlcnNpb24gPSAwO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldCBuZWVkc1VwZGF0ZSggdmFsdWUgKSB7XHJcblxyXG5cdFx0aWYgKCB2YWx1ZSA9PT0gdHJ1ZSApIHRoaXMudmVyc2lvbiArKztcclxuXHJcblx0fVxyXG5cclxuXHR0b0pTT04oIG1ldGEgKSB7XHJcblxyXG5cdFx0Y29uc3QgaXNSb290T2JqZWN0ID0gKCBtZXRhID09PSB1bmRlZmluZWQgfHwgdHlwZW9mIG1ldGEgPT09ICdzdHJpbmcnICk7XHJcblxyXG5cdFx0aWYgKCAhIGlzUm9vdE9iamVjdCAmJiBtZXRhLmltYWdlc1sgdGhpcy51dWlkIF0gIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdHJldHVybiBtZXRhLmltYWdlc1sgdGhpcy51dWlkIF07XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGNvbnN0IG91dHB1dCA9IHtcclxuXHRcdFx0dXVpZDogdGhpcy51dWlkLFxyXG5cdFx0XHR1cmw6ICcnXHJcblx0XHR9O1xyXG5cclxuXHRcdGNvbnN0IGRhdGEgPSB0aGlzLmRhdGE7XHJcblxyXG5cdFx0aWYgKCBkYXRhICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0bGV0IHVybDtcclxuXHJcblx0XHRcdGlmICggQXJyYXkuaXNBcnJheSggZGF0YSApICkge1xyXG5cclxuXHRcdFx0XHQvLyBjdWJlIHRleHR1cmVcclxuXHJcblx0XHRcdFx0dXJsID0gW107XHJcblxyXG5cdFx0XHRcdGZvciAoIGxldCBpID0gMCwgbCA9IGRhdGEubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0XHRpZiAoIGRhdGFbIGkgXS5pc0RhdGFUZXh0dXJlICkge1xyXG5cclxuXHRcdFx0XHRcdFx0dXJsLnB1c2goIHNlcmlhbGl6ZUltYWdlKCBkYXRhWyBpIF0uaW1hZ2UgKSApO1xyXG5cclxuXHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHR1cmwucHVzaCggc2VyaWFsaXplSW1hZ2UoIGRhdGFbIGkgXSApICk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHQvLyB0ZXh0dXJlXHJcblxyXG5cdFx0XHRcdHVybCA9IHNlcmlhbGl6ZUltYWdlKCBkYXRhICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRvdXRwdXQudXJsID0gdXJsO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoICEgaXNSb290T2JqZWN0ICkge1xyXG5cclxuXHRcdFx0bWV0YS5pbWFnZXNbIHRoaXMudXVpZCBdID0gb3V0cHV0O1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gb3V0cHV0O1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiBzZXJpYWxpemVJbWFnZSggaW1hZ2UgKSB7XHJcblxyXG5cdGlmICggKCB0eXBlb2YgSFRNTEltYWdlRWxlbWVudCAhPT0gJ3VuZGVmaW5lZCcgJiYgaW1hZ2UgaW5zdGFuY2VvZiBIVE1MSW1hZ2VFbGVtZW50ICkgfHxcclxuXHRcdCggdHlwZW9mIEhUTUxDYW52YXNFbGVtZW50ICE9PSAndW5kZWZpbmVkJyAmJiBpbWFnZSBpbnN0YW5jZW9mIEhUTUxDYW52YXNFbGVtZW50ICkgfHxcclxuXHRcdCggdHlwZW9mIEltYWdlQml0bWFwICE9PSAndW5kZWZpbmVkJyAmJiBpbWFnZSBpbnN0YW5jZW9mIEltYWdlQml0bWFwICkgKSB7XHJcblxyXG5cdFx0Ly8gZGVmYXVsdCBpbWFnZXNcclxuXHJcblx0XHRyZXR1cm4gSW1hZ2VVdGlscy5nZXREYXRhVVJMKCBpbWFnZSApO1xyXG5cclxuXHR9IGVsc2Uge1xyXG5cclxuXHRcdGlmICggaW1hZ2UuZGF0YSApIHtcclxuXHJcblx0XHRcdC8vIGltYWdlcyBvZiBEYXRhVGV4dHVyZVxyXG5cclxuXHRcdFx0cmV0dXJuIHtcclxuXHRcdFx0XHRkYXRhOiBBcnJheS5mcm9tKCBpbWFnZS5kYXRhICksXHJcblx0XHRcdFx0d2lkdGg6IGltYWdlLndpZHRoLFxyXG5cdFx0XHRcdGhlaWdodDogaW1hZ2UuaGVpZ2h0LFxyXG5cdFx0XHRcdHR5cGU6IGltYWdlLmRhdGEuY29uc3RydWN0b3IubmFtZVxyXG5cdFx0XHR9O1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5UZXh0dXJlOiBVbmFibGUgdG8gc2VyaWFsaXplIFRleHR1cmUuJyApO1xyXG5cdFx0XHRyZXR1cm4ge307XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBTb3VyY2UgfTtcclxuIiwiaW1wb3J0IHsgRXZlbnREaXNwYXRjaGVyIH0gZnJvbSAnLi4vY29yZS9FdmVudERpc3BhdGNoZXIuanMnO1xyXG5pbXBvcnQge1xyXG5cdE1pcnJvcmVkUmVwZWF0V3JhcHBpbmcsXHJcblx0Q2xhbXBUb0VkZ2VXcmFwcGluZyxcclxuXHRSZXBlYXRXcmFwcGluZyxcclxuXHRVbnNpZ25lZEJ5dGVUeXBlLFxyXG5cdFJHQkFGb3JtYXQsXHJcblx0TGluZWFyTWlwbWFwTGluZWFyRmlsdGVyLFxyXG5cdExpbmVhckZpbHRlcixcclxuXHRVVk1hcHBpbmcsXHJcblx0Tm9Db2xvclNwYWNlLFxyXG59IGZyb20gJy4uL2NvbnN0YW50cy5qcyc7XHJcbmltcG9ydCAqIGFzIE1hdGhVdGlscyBmcm9tICcuLi9tYXRoL01hdGhVdGlscy5qcyc7XHJcbmltcG9ydCB7IFZlY3RvcjIgfSBmcm9tICcuLi9tYXRoL1ZlY3RvcjIuanMnO1xyXG5pbXBvcnQgeyBNYXRyaXgzIH0gZnJvbSAnLi4vbWF0aC9NYXRyaXgzLmpzJztcclxuaW1wb3J0IHsgU291cmNlIH0gZnJvbSAnLi9Tb3VyY2UuanMnO1xyXG5cclxubGV0IF90ZXh0dXJlSWQgPSAwO1xyXG5cclxuY2xhc3MgVGV4dHVyZSBleHRlbmRzIEV2ZW50RGlzcGF0Y2hlciB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBpbWFnZSA9IFRleHR1cmUuREVGQVVMVF9JTUFHRSwgbWFwcGluZyA9IFRleHR1cmUuREVGQVVMVF9NQVBQSU5HLCB3cmFwUyA9IENsYW1wVG9FZGdlV3JhcHBpbmcsIHdyYXBUID0gQ2xhbXBUb0VkZ2VXcmFwcGluZywgbWFnRmlsdGVyID0gTGluZWFyRmlsdGVyLCBtaW5GaWx0ZXIgPSBMaW5lYXJNaXBtYXBMaW5lYXJGaWx0ZXIsIGZvcm1hdCA9IFJHQkFGb3JtYXQsIHR5cGUgPSBVbnNpZ25lZEJ5dGVUeXBlLCBhbmlzb3Ryb3B5ID0gVGV4dHVyZS5ERUZBVUxUX0FOSVNPVFJPUFksIGNvbG9yU3BhY2UgPSBOb0NvbG9yU3BhY2UgKSB7XHJcblxyXG5cdFx0c3VwZXIoKTtcclxuXHJcblx0XHR0aGlzLmlzVGV4dHVyZSA9IHRydWU7XHJcblxyXG5cdFx0T2JqZWN0LmRlZmluZVByb3BlcnR5KCB0aGlzLCAnaWQnLCB7IHZhbHVlOiBfdGV4dHVyZUlkICsrIH0gKTtcclxuXHJcblx0XHR0aGlzLnV1aWQgPSBNYXRoVXRpbHMuZ2VuZXJhdGVVVUlEKCk7XHJcblxyXG5cdFx0dGhpcy5uYW1lID0gJyc7XHJcblxyXG5cdFx0dGhpcy5zb3VyY2UgPSBuZXcgU291cmNlKCBpbWFnZSApO1xyXG5cdFx0dGhpcy5taXBtYXBzID0gW107XHJcblxyXG5cdFx0dGhpcy5tYXBwaW5nID0gbWFwcGluZztcclxuXHRcdHRoaXMuY2hhbm5lbCA9IDA7XHJcblxyXG5cdFx0dGhpcy53cmFwUyA9IHdyYXBTO1xyXG5cdFx0dGhpcy53cmFwVCA9IHdyYXBUO1xyXG5cclxuXHRcdHRoaXMubWFnRmlsdGVyID0gbWFnRmlsdGVyO1xyXG5cdFx0dGhpcy5taW5GaWx0ZXIgPSBtaW5GaWx0ZXI7XHJcblxyXG5cdFx0dGhpcy5hbmlzb3Ryb3B5ID0gYW5pc290cm9weTtcclxuXHJcblx0XHR0aGlzLmZvcm1hdCA9IGZvcm1hdDtcclxuXHRcdHRoaXMuaW50ZXJuYWxGb3JtYXQgPSBudWxsO1xyXG5cdFx0dGhpcy50eXBlID0gdHlwZTtcclxuXHJcblx0XHR0aGlzLm9mZnNldCA9IG5ldyBWZWN0b3IyKCAwLCAwICk7XHJcblx0XHR0aGlzLnJlcGVhdCA9IG5ldyBWZWN0b3IyKCAxLCAxICk7XHJcblx0XHR0aGlzLmNlbnRlciA9IG5ldyBWZWN0b3IyKCAwLCAwICk7XHJcblx0XHR0aGlzLnJvdGF0aW9uID0gMDtcclxuXHJcblx0XHR0aGlzLm1hdHJpeEF1dG9VcGRhdGUgPSB0cnVlO1xyXG5cdFx0dGhpcy5tYXRyaXggPSBuZXcgTWF0cml4MygpO1xyXG5cclxuXHRcdHRoaXMuZ2VuZXJhdGVNaXBtYXBzID0gdHJ1ZTtcclxuXHRcdHRoaXMucHJlbXVsdGlwbHlBbHBoYSA9IGZhbHNlO1xyXG5cdFx0dGhpcy5mbGlwWSA9IHRydWU7XHJcblx0XHR0aGlzLnVucGFja0FsaWdubWVudCA9IDQ7XHQvLyB2YWxpZCB2YWx1ZXM6IDEsIDIsIDQsIDggKHNlZSBodHRwOi8vd3d3Lmtocm9ub3Mub3JnL29wZW5nbGVzL3Nkay9kb2NzL21hbi94aHRtbC9nbFBpeGVsU3RvcmVpLnhtbClcclxuXHJcblx0XHR0aGlzLmNvbG9yU3BhY2UgPSBjb2xvclNwYWNlO1xyXG5cclxuXHRcdHRoaXMudXNlckRhdGEgPSB7fTtcclxuXHJcblx0XHR0aGlzLnZlcnNpb24gPSAwO1xyXG5cdFx0dGhpcy5vblVwZGF0ZSA9IG51bGw7XHJcblxyXG5cdFx0dGhpcy5pc1JlbmRlclRhcmdldFRleHR1cmUgPSBmYWxzZTsgLy8gaW5kaWNhdGVzIHdoZXRoZXIgYSB0ZXh0dXJlIGJlbG9uZ3MgdG8gYSByZW5kZXIgdGFyZ2V0IG9yIG5vdFxyXG5cdFx0dGhpcy5uZWVkc1BNUkVNVXBkYXRlID0gZmFsc2U7IC8vIGluZGljYXRlcyB3aGV0aGVyIHRoaXMgdGV4dHVyZSBzaG91bGQgYmUgcHJvY2Vzc2VkIGJ5IFBNUkVNR2VuZXJhdG9yIG9yIG5vdCAob25seSByZWxldmFudCBmb3IgcmVuZGVyIHRhcmdldCB0ZXh0dXJlcylcclxuXHJcblx0fVxyXG5cclxuXHRnZXQgaW1hZ2UoKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuc291cmNlLmRhdGE7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0IGltYWdlKCB2YWx1ZSA9IG51bGwgKSB7XHJcblxyXG5cdFx0dGhpcy5zb3VyY2UuZGF0YSA9IHZhbHVlO1xyXG5cclxuXHR9XHJcblxyXG5cdHVwZGF0ZU1hdHJpeCgpIHtcclxuXHJcblx0XHR0aGlzLm1hdHJpeC5zZXRVdlRyYW5zZm9ybSggdGhpcy5vZmZzZXQueCwgdGhpcy5vZmZzZXQueSwgdGhpcy5yZXBlYXQueCwgdGhpcy5yZXBlYXQueSwgdGhpcy5yb3RhdGlvbiwgdGhpcy5jZW50ZXIueCwgdGhpcy5jZW50ZXIueSApO1xyXG5cclxuXHR9XHJcblxyXG5cdGNsb25lKCkge1xyXG5cclxuXHRcdHJldHVybiBuZXcgdGhpcy5jb25zdHJ1Y3RvcigpLmNvcHkoIHRoaXMgKTtcclxuXHJcblx0fVxyXG5cclxuXHRjb3B5KCBzb3VyY2UgKSB7XHJcblxyXG5cdFx0dGhpcy5uYW1lID0gc291cmNlLm5hbWU7XHJcblxyXG5cdFx0dGhpcy5zb3VyY2UgPSBzb3VyY2Uuc291cmNlO1xyXG5cdFx0dGhpcy5taXBtYXBzID0gc291cmNlLm1pcG1hcHMuc2xpY2UoIDAgKTtcclxuXHJcblx0XHR0aGlzLm1hcHBpbmcgPSBzb3VyY2UubWFwcGluZztcclxuXHRcdHRoaXMuY2hhbm5lbCA9IHNvdXJjZS5jaGFubmVsO1xyXG5cclxuXHRcdHRoaXMud3JhcFMgPSBzb3VyY2Uud3JhcFM7XHJcblx0XHR0aGlzLndyYXBUID0gc291cmNlLndyYXBUO1xyXG5cclxuXHRcdHRoaXMubWFnRmlsdGVyID0gc291cmNlLm1hZ0ZpbHRlcjtcclxuXHRcdHRoaXMubWluRmlsdGVyID0gc291cmNlLm1pbkZpbHRlcjtcclxuXHJcblx0XHR0aGlzLmFuaXNvdHJvcHkgPSBzb3VyY2UuYW5pc290cm9weTtcclxuXHJcblx0XHR0aGlzLmZvcm1hdCA9IHNvdXJjZS5mb3JtYXQ7XHJcblx0XHR0aGlzLmludGVybmFsRm9ybWF0ID0gc291cmNlLmludGVybmFsRm9ybWF0O1xyXG5cdFx0dGhpcy50eXBlID0gc291cmNlLnR5cGU7XHJcblxyXG5cdFx0dGhpcy5vZmZzZXQuY29weSggc291cmNlLm9mZnNldCApO1xyXG5cdFx0dGhpcy5yZXBlYXQuY29weSggc291cmNlLnJlcGVhdCApO1xyXG5cdFx0dGhpcy5jZW50ZXIuY29weSggc291cmNlLmNlbnRlciApO1xyXG5cdFx0dGhpcy5yb3RhdGlvbiA9IHNvdXJjZS5yb3RhdGlvbjtcclxuXHJcblx0XHR0aGlzLm1hdHJpeEF1dG9VcGRhdGUgPSBzb3VyY2UubWF0cml4QXV0b1VwZGF0ZTtcclxuXHRcdHRoaXMubWF0cml4LmNvcHkoIHNvdXJjZS5tYXRyaXggKTtcclxuXHJcblx0XHR0aGlzLmdlbmVyYXRlTWlwbWFwcyA9IHNvdXJjZS5nZW5lcmF0ZU1pcG1hcHM7XHJcblx0XHR0aGlzLnByZW11bHRpcGx5QWxwaGEgPSBzb3VyY2UucHJlbXVsdGlwbHlBbHBoYTtcclxuXHRcdHRoaXMuZmxpcFkgPSBzb3VyY2UuZmxpcFk7XHJcblx0XHR0aGlzLnVucGFja0FsaWdubWVudCA9IHNvdXJjZS51bnBhY2tBbGlnbm1lbnQ7XHJcblx0XHR0aGlzLmNvbG9yU3BhY2UgPSBzb3VyY2UuY29sb3JTcGFjZTtcclxuXHJcblx0XHR0aGlzLnVzZXJEYXRhID0gSlNPTi5wYXJzZSggSlNPTi5zdHJpbmdpZnkoIHNvdXJjZS51c2VyRGF0YSApICk7XHJcblxyXG5cdFx0dGhpcy5uZWVkc1VwZGF0ZSA9IHRydWU7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0dG9KU09OKCBtZXRhICkge1xyXG5cclxuXHRcdGNvbnN0IGlzUm9vdE9iamVjdCA9ICggbWV0YSA9PT0gdW5kZWZpbmVkIHx8IHR5cGVvZiBtZXRhID09PSAnc3RyaW5nJyApO1xyXG5cclxuXHRcdGlmICggISBpc1Jvb3RPYmplY3QgJiYgbWV0YS50ZXh0dXJlc1sgdGhpcy51dWlkIF0gIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdHJldHVybiBtZXRhLnRleHR1cmVzWyB0aGlzLnV1aWQgXTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Y29uc3Qgb3V0cHV0ID0ge1xyXG5cclxuXHRcdFx0bWV0YWRhdGE6IHtcclxuXHRcdFx0XHR2ZXJzaW9uOiA0LjYsXHJcblx0XHRcdFx0dHlwZTogJ1RleHR1cmUnLFxyXG5cdFx0XHRcdGdlbmVyYXRvcjogJ1RleHR1cmUudG9KU09OJ1xyXG5cdFx0XHR9LFxyXG5cclxuXHRcdFx0dXVpZDogdGhpcy51dWlkLFxyXG5cdFx0XHRuYW1lOiB0aGlzLm5hbWUsXHJcblxyXG5cdFx0XHRpbWFnZTogdGhpcy5zb3VyY2UudG9KU09OKCBtZXRhICkudXVpZCxcclxuXHJcblx0XHRcdG1hcHBpbmc6IHRoaXMubWFwcGluZyxcclxuXHRcdFx0Y2hhbm5lbDogdGhpcy5jaGFubmVsLFxyXG5cclxuXHRcdFx0cmVwZWF0OiBbIHRoaXMucmVwZWF0LngsIHRoaXMucmVwZWF0LnkgXSxcclxuXHRcdFx0b2Zmc2V0OiBbIHRoaXMub2Zmc2V0LngsIHRoaXMub2Zmc2V0LnkgXSxcclxuXHRcdFx0Y2VudGVyOiBbIHRoaXMuY2VudGVyLngsIHRoaXMuY2VudGVyLnkgXSxcclxuXHRcdFx0cm90YXRpb246IHRoaXMucm90YXRpb24sXHJcblxyXG5cdFx0XHR3cmFwOiBbIHRoaXMud3JhcFMsIHRoaXMud3JhcFQgXSxcclxuXHJcblx0XHRcdGZvcm1hdDogdGhpcy5mb3JtYXQsXHJcblx0XHRcdGludGVybmFsRm9ybWF0OiB0aGlzLmludGVybmFsRm9ybWF0LFxyXG5cdFx0XHR0eXBlOiB0aGlzLnR5cGUsXHJcblx0XHRcdGNvbG9yU3BhY2U6IHRoaXMuY29sb3JTcGFjZSxcclxuXHJcblx0XHRcdG1pbkZpbHRlcjogdGhpcy5taW5GaWx0ZXIsXHJcblx0XHRcdG1hZ0ZpbHRlcjogdGhpcy5tYWdGaWx0ZXIsXHJcblx0XHRcdGFuaXNvdHJvcHk6IHRoaXMuYW5pc290cm9weSxcclxuXHJcblx0XHRcdGZsaXBZOiB0aGlzLmZsaXBZLFxyXG5cclxuXHRcdFx0Z2VuZXJhdGVNaXBtYXBzOiB0aGlzLmdlbmVyYXRlTWlwbWFwcyxcclxuXHRcdFx0cHJlbXVsdGlwbHlBbHBoYTogdGhpcy5wcmVtdWx0aXBseUFscGhhLFxyXG5cdFx0XHR1bnBhY2tBbGlnbm1lbnQ6IHRoaXMudW5wYWNrQWxpZ25tZW50XHJcblxyXG5cdFx0fTtcclxuXHJcblx0XHRpZiAoIE9iamVjdC5rZXlzKCB0aGlzLnVzZXJEYXRhICkubGVuZ3RoID4gMCApIG91dHB1dC51c2VyRGF0YSA9IHRoaXMudXNlckRhdGE7XHJcblxyXG5cdFx0aWYgKCAhIGlzUm9vdE9iamVjdCApIHtcclxuXHJcblx0XHRcdG1ldGEudGV4dHVyZXNbIHRoaXMudXVpZCBdID0gb3V0cHV0O1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gb3V0cHV0O1xyXG5cclxuXHR9XHJcblxyXG5cdGRpc3Bvc2UoKSB7XHJcblxyXG5cdFx0dGhpcy5kaXNwYXRjaEV2ZW50KCB7IHR5cGU6ICdkaXNwb3NlJyB9ICk7XHJcblxyXG5cdH1cclxuXHJcblx0dHJhbnNmb3JtVXYoIHV2ICkge1xyXG5cclxuXHRcdGlmICggdGhpcy5tYXBwaW5nICE9PSBVVk1hcHBpbmcgKSByZXR1cm4gdXY7XHJcblxyXG5cdFx0dXYuYXBwbHlNYXRyaXgzKCB0aGlzLm1hdHJpeCApO1xyXG5cclxuXHRcdGlmICggdXYueCA8IDAgfHwgdXYueCA+IDEgKSB7XHJcblxyXG5cdFx0XHRzd2l0Y2ggKCB0aGlzLndyYXBTICkge1xyXG5cclxuXHRcdFx0XHRjYXNlIFJlcGVhdFdyYXBwaW5nOlxyXG5cclxuXHRcdFx0XHRcdHV2LnggPSB1di54IC0gTWF0aC5mbG9vciggdXYueCApO1xyXG5cdFx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRcdGNhc2UgQ2xhbXBUb0VkZ2VXcmFwcGluZzpcclxuXHJcblx0XHRcdFx0XHR1di54ID0gdXYueCA8IDAgPyAwIDogMTtcclxuXHRcdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0XHRjYXNlIE1pcnJvcmVkUmVwZWF0V3JhcHBpbmc6XHJcblxyXG5cdFx0XHRcdFx0aWYgKCBNYXRoLmFicyggTWF0aC5mbG9vciggdXYueCApICUgMiApID09PSAxICkge1xyXG5cclxuXHRcdFx0XHRcdFx0dXYueCA9IE1hdGguY2VpbCggdXYueCApIC0gdXYueDtcclxuXHJcblx0XHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdFx0dXYueCA9IHV2LnggLSBNYXRoLmZsb29yKCB1di54ICk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHV2LnkgPCAwIHx8IHV2LnkgPiAxICkge1xyXG5cclxuXHRcdFx0c3dpdGNoICggdGhpcy53cmFwVCApIHtcclxuXHJcblx0XHRcdFx0Y2FzZSBSZXBlYXRXcmFwcGluZzpcclxuXHJcblx0XHRcdFx0XHR1di55ID0gdXYueSAtIE1hdGguZmxvb3IoIHV2LnkgKTtcclxuXHRcdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0XHRjYXNlIENsYW1wVG9FZGdlV3JhcHBpbmc6XHJcblxyXG5cdFx0XHRcdFx0dXYueSA9IHV2LnkgPCAwID8gMCA6IDE7XHJcblx0XHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdFx0Y2FzZSBNaXJyb3JlZFJlcGVhdFdyYXBwaW5nOlxyXG5cclxuXHRcdFx0XHRcdGlmICggTWF0aC5hYnMoIE1hdGguZmxvb3IoIHV2LnkgKSAlIDIgKSA9PT0gMSApIHtcclxuXHJcblx0XHRcdFx0XHRcdHV2LnkgPSBNYXRoLmNlaWwoIHV2LnkgKSAtIHV2Lnk7XHJcblxyXG5cdFx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRcdHV2LnkgPSB1di55IC0gTWF0aC5mbG9vciggdXYueSApO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCB0aGlzLmZsaXBZICkge1xyXG5cclxuXHRcdFx0dXYueSA9IDEgLSB1di55O1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdXY7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0IG5lZWRzVXBkYXRlKCB2YWx1ZSApIHtcclxuXHJcblx0XHRpZiAoIHZhbHVlID09PSB0cnVlICkge1xyXG5cclxuXHRcdFx0dGhpcy52ZXJzaW9uICsrO1xyXG5cdFx0XHR0aGlzLnNvdXJjZS5uZWVkc1VwZGF0ZSA9IHRydWU7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5UZXh0dXJlLkRFRkFVTFRfSU1BR0UgPSBudWxsO1xyXG5UZXh0dXJlLkRFRkFVTFRfTUFQUElORyA9IFVWTWFwcGluZztcclxuVGV4dHVyZS5ERUZBVUxUX0FOSVNPVFJPUFkgPSAxO1xyXG5cclxuZXhwb3J0IHsgVGV4dHVyZSB9O1xyXG4iLCJjbGFzcyBWZWN0b3I0IHtcclxuXHJcblx0Y29uc3RydWN0b3IoIHggPSAwLCB5ID0gMCwgeiA9IDAsIHcgPSAxICkge1xyXG5cclxuXHRcdFZlY3RvcjQucHJvdG90eXBlLmlzVmVjdG9yNCA9IHRydWU7XHJcblxyXG5cdFx0dGhpcy54ID0geDtcclxuXHRcdHRoaXMueSA9IHk7XHJcblx0XHR0aGlzLnogPSB6O1xyXG5cdFx0dGhpcy53ID0gdztcclxuXHJcblx0fVxyXG5cclxuXHRnZXQgd2lkdGgoKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuejtcclxuXHJcblx0fVxyXG5cclxuXHRzZXQgd2lkdGgoIHZhbHVlICkge1xyXG5cclxuXHRcdHRoaXMueiA9IHZhbHVlO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldCBoZWlnaHQoKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMudztcclxuXHJcblx0fVxyXG5cclxuXHRzZXQgaGVpZ2h0KCB2YWx1ZSApIHtcclxuXHJcblx0XHR0aGlzLncgPSB2YWx1ZTtcclxuXHJcblx0fVxyXG5cclxuXHRzZXQoIHgsIHksIHosIHcgKSB7XHJcblxyXG5cdFx0dGhpcy54ID0geDtcclxuXHRcdHRoaXMueSA9IHk7XHJcblx0XHR0aGlzLnogPSB6O1xyXG5cdFx0dGhpcy53ID0gdztcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRTY2FsYXIoIHNjYWxhciApIHtcclxuXHJcblx0XHR0aGlzLnggPSBzY2FsYXI7XHJcblx0XHR0aGlzLnkgPSBzY2FsYXI7XHJcblx0XHR0aGlzLnogPSBzY2FsYXI7XHJcblx0XHR0aGlzLncgPSBzY2FsYXI7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0WCggeCApIHtcclxuXHJcblx0XHR0aGlzLnggPSB4O1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldFkoIHkgKSB7XHJcblxyXG5cdFx0dGhpcy55ID0geTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRaKCB6ICkge1xyXG5cclxuXHRcdHRoaXMueiA9IHo7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0VyggdyApIHtcclxuXHJcblx0XHR0aGlzLncgPSB3O1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldENvbXBvbmVudCggaW5kZXgsIHZhbHVlICkge1xyXG5cclxuXHRcdHN3aXRjaCAoIGluZGV4ICkge1xyXG5cclxuXHRcdFx0Y2FzZSAwOiB0aGlzLnggPSB2YWx1ZTsgYnJlYWs7XHJcblx0XHRcdGNhc2UgMTogdGhpcy55ID0gdmFsdWU7IGJyZWFrO1xyXG5cdFx0XHRjYXNlIDI6IHRoaXMueiA9IHZhbHVlOyBicmVhaztcclxuXHRcdFx0Y2FzZSAzOiB0aGlzLncgPSB2YWx1ZTsgYnJlYWs7XHJcblx0XHRcdGRlZmF1bHQ6IHRocm93IG5ldyBFcnJvciggJ2luZGV4IGlzIG91dCBvZiByYW5nZTogJyArIGluZGV4ICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldENvbXBvbmVudCggaW5kZXggKSB7XHJcblxyXG5cdFx0c3dpdGNoICggaW5kZXggKSB7XHJcblxyXG5cdFx0XHRjYXNlIDA6IHJldHVybiB0aGlzLng7XHJcblx0XHRcdGNhc2UgMTogcmV0dXJuIHRoaXMueTtcclxuXHRcdFx0Y2FzZSAyOiByZXR1cm4gdGhpcy56O1xyXG5cdFx0XHRjYXNlIDM6IHJldHVybiB0aGlzLnc7XHJcblx0XHRcdGRlZmF1bHQ6IHRocm93IG5ldyBFcnJvciggJ2luZGV4IGlzIG91dCBvZiByYW5nZTogJyArIGluZGV4ICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGNsb25lKCkge1xyXG5cclxuXHRcdHJldHVybiBuZXcgdGhpcy5jb25zdHJ1Y3RvciggdGhpcy54LCB0aGlzLnksIHRoaXMueiwgdGhpcy53ICk7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggdiApIHtcclxuXHJcblx0XHR0aGlzLnggPSB2Lng7XHJcblx0XHR0aGlzLnkgPSB2Lnk7XHJcblx0XHR0aGlzLnogPSB2Lno7XHJcblx0XHR0aGlzLncgPSAoIHYudyAhPT0gdW5kZWZpbmVkICkgPyB2LncgOiAxO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGFkZCggdiApIHtcclxuXHJcblx0XHR0aGlzLnggKz0gdi54O1xyXG5cdFx0dGhpcy55ICs9IHYueTtcclxuXHRcdHRoaXMueiArPSB2Lno7XHJcblx0XHR0aGlzLncgKz0gdi53O1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGFkZFNjYWxhciggcyApIHtcclxuXHJcblx0XHR0aGlzLnggKz0gcztcclxuXHRcdHRoaXMueSArPSBzO1xyXG5cdFx0dGhpcy56ICs9IHM7XHJcblx0XHR0aGlzLncgKz0gcztcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRhZGRWZWN0b3JzKCBhLCBiICkge1xyXG5cclxuXHRcdHRoaXMueCA9IGEueCArIGIueDtcclxuXHRcdHRoaXMueSA9IGEueSArIGIueTtcclxuXHRcdHRoaXMueiA9IGEueiArIGIuejtcclxuXHRcdHRoaXMudyA9IGEudyArIGIudztcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRhZGRTY2FsZWRWZWN0b3IoIHYsIHMgKSB7XHJcblxyXG5cdFx0dGhpcy54ICs9IHYueCAqIHM7XHJcblx0XHR0aGlzLnkgKz0gdi55ICogcztcclxuXHRcdHRoaXMueiArPSB2LnogKiBzO1xyXG5cdFx0dGhpcy53ICs9IHYudyAqIHM7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0c3ViKCB2ICkge1xyXG5cclxuXHRcdHRoaXMueCAtPSB2Lng7XHJcblx0XHR0aGlzLnkgLT0gdi55O1xyXG5cdFx0dGhpcy56IC09IHYuejtcclxuXHRcdHRoaXMudyAtPSB2Lnc7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0c3ViU2NhbGFyKCBzICkge1xyXG5cclxuXHRcdHRoaXMueCAtPSBzO1xyXG5cdFx0dGhpcy55IC09IHM7XHJcblx0XHR0aGlzLnogLT0gcztcclxuXHRcdHRoaXMudyAtPSBzO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHN1YlZlY3RvcnMoIGEsIGIgKSB7XHJcblxyXG5cdFx0dGhpcy54ID0gYS54IC0gYi54O1xyXG5cdFx0dGhpcy55ID0gYS55IC0gYi55O1xyXG5cdFx0dGhpcy56ID0gYS56IC0gYi56O1xyXG5cdFx0dGhpcy53ID0gYS53IC0gYi53O1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdG11bHRpcGx5KCB2ICkge1xyXG5cclxuXHRcdHRoaXMueCAqPSB2Lng7XHJcblx0XHR0aGlzLnkgKj0gdi55O1xyXG5cdFx0dGhpcy56ICo9IHYuejtcclxuXHRcdHRoaXMudyAqPSB2Lnc7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0bXVsdGlwbHlTY2FsYXIoIHNjYWxhciApIHtcclxuXHJcblx0XHR0aGlzLnggKj0gc2NhbGFyO1xyXG5cdFx0dGhpcy55ICo9IHNjYWxhcjtcclxuXHRcdHRoaXMueiAqPSBzY2FsYXI7XHJcblx0XHR0aGlzLncgKj0gc2NhbGFyO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGFwcGx5TWF0cml4NCggbSApIHtcclxuXHJcblx0XHRjb25zdCB4ID0gdGhpcy54LCB5ID0gdGhpcy55LCB6ID0gdGhpcy56LCB3ID0gdGhpcy53O1xyXG5cdFx0Y29uc3QgZSA9IG0uZWxlbWVudHM7XHJcblxyXG5cdFx0dGhpcy54ID0gZVsgMCBdICogeCArIGVbIDQgXSAqIHkgKyBlWyA4IF0gKiB6ICsgZVsgMTIgXSAqIHc7XHJcblx0XHR0aGlzLnkgPSBlWyAxIF0gKiB4ICsgZVsgNSBdICogeSArIGVbIDkgXSAqIHogKyBlWyAxMyBdICogdztcclxuXHRcdHRoaXMueiA9IGVbIDIgXSAqIHggKyBlWyA2IF0gKiB5ICsgZVsgMTAgXSAqIHogKyBlWyAxNCBdICogdztcclxuXHRcdHRoaXMudyA9IGVbIDMgXSAqIHggKyBlWyA3IF0gKiB5ICsgZVsgMTEgXSAqIHogKyBlWyAxNSBdICogdztcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRkaXZpZGVTY2FsYXIoIHNjYWxhciApIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5tdWx0aXBseVNjYWxhciggMSAvIHNjYWxhciApO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldEF4aXNBbmdsZUZyb21RdWF0ZXJuaW9uKCBxICkge1xyXG5cclxuXHRcdC8vIGh0dHA6Ly93d3cuZXVjbGlkZWFuc3BhY2UuY29tL21hdGhzL2dlb21ldHJ5L3JvdGF0aW9ucy9jb252ZXJzaW9ucy9xdWF0ZXJuaW9uVG9BbmdsZS9pbmRleC5odG1cclxuXHJcblx0XHQvLyBxIGlzIGFzc3VtZWQgdG8gYmUgbm9ybWFsaXplZFxyXG5cclxuXHRcdHRoaXMudyA9IDIgKiBNYXRoLmFjb3MoIHEudyApO1xyXG5cclxuXHRcdGNvbnN0IHMgPSBNYXRoLnNxcnQoIDEgLSBxLncgKiBxLncgKTtcclxuXHJcblx0XHRpZiAoIHMgPCAwLjAwMDEgKSB7XHJcblxyXG5cdFx0XHR0aGlzLnggPSAxO1xyXG5cdFx0XHR0aGlzLnkgPSAwO1xyXG5cdFx0XHR0aGlzLnogPSAwO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHR0aGlzLnggPSBxLnggLyBzO1xyXG5cdFx0XHR0aGlzLnkgPSBxLnkgLyBzO1xyXG5cdFx0XHR0aGlzLnogPSBxLnogLyBzO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRBeGlzQW5nbGVGcm9tUm90YXRpb25NYXRyaXgoIG0gKSB7XHJcblxyXG5cdFx0Ly8gaHR0cDovL3d3dy5ldWNsaWRlYW5zcGFjZS5jb20vbWF0aHMvZ2VvbWV0cnkvcm90YXRpb25zL2NvbnZlcnNpb25zL21hdHJpeFRvQW5nbGUvaW5kZXguaHRtXHJcblxyXG5cdFx0Ly8gYXNzdW1lcyB0aGUgdXBwZXIgM3gzIG9mIG0gaXMgYSBwdXJlIHJvdGF0aW9uIG1hdHJpeCAoaS5lLCB1bnNjYWxlZClcclxuXHJcblx0XHRsZXQgYW5nbGUsIHgsIHksIHo7IC8vIHZhcmlhYmxlcyBmb3IgcmVzdWx0XHJcblx0XHRjb25zdCBlcHNpbG9uID0gMC4wMSxcdFx0Ly8gbWFyZ2luIHRvIGFsbG93IGZvciByb3VuZGluZyBlcnJvcnNcclxuXHRcdFx0ZXBzaWxvbjIgPSAwLjEsXHRcdC8vIG1hcmdpbiB0byBkaXN0aW5ndWlzaCBiZXR3ZWVuIDAgYW5kIDE4MCBkZWdyZWVzXHJcblxyXG5cdFx0XHR0ZSA9IG0uZWxlbWVudHMsXHJcblxyXG5cdFx0XHRtMTEgPSB0ZVsgMCBdLCBtMTIgPSB0ZVsgNCBdLCBtMTMgPSB0ZVsgOCBdLFxyXG5cdFx0XHRtMjEgPSB0ZVsgMSBdLCBtMjIgPSB0ZVsgNSBdLCBtMjMgPSB0ZVsgOSBdLFxyXG5cdFx0XHRtMzEgPSB0ZVsgMiBdLCBtMzIgPSB0ZVsgNiBdLCBtMzMgPSB0ZVsgMTAgXTtcclxuXHJcblx0XHRpZiAoICggTWF0aC5hYnMoIG0xMiAtIG0yMSApIDwgZXBzaWxvbiApICYmXHJcblx0XHQgICAgICggTWF0aC5hYnMoIG0xMyAtIG0zMSApIDwgZXBzaWxvbiApICYmXHJcblx0XHQgICAgICggTWF0aC5hYnMoIG0yMyAtIG0zMiApIDwgZXBzaWxvbiApICkge1xyXG5cclxuXHRcdFx0Ly8gc2luZ3VsYXJpdHkgZm91bmRcclxuXHRcdFx0Ly8gZmlyc3QgY2hlY2sgZm9yIGlkZW50aXR5IG1hdHJpeCB3aGljaCBtdXN0IGhhdmUgKzEgZm9yIGFsbCB0ZXJtc1xyXG5cdFx0XHQvLyBpbiBsZWFkaW5nIGRpYWdvbmFsIGFuZCB6ZXJvIGluIG90aGVyIHRlcm1zXHJcblxyXG5cdFx0XHRpZiAoICggTWF0aC5hYnMoIG0xMiArIG0yMSApIDwgZXBzaWxvbjIgKSAmJlxyXG5cdFx0XHQgICAgICggTWF0aC5hYnMoIG0xMyArIG0zMSApIDwgZXBzaWxvbjIgKSAmJlxyXG5cdFx0XHQgICAgICggTWF0aC5hYnMoIG0yMyArIG0zMiApIDwgZXBzaWxvbjIgKSAmJlxyXG5cdFx0XHQgICAgICggTWF0aC5hYnMoIG0xMSArIG0yMiArIG0zMyAtIDMgKSA8IGVwc2lsb24yICkgKSB7XHJcblxyXG5cdFx0XHRcdC8vIHRoaXMgc2luZ3VsYXJpdHkgaXMgaWRlbnRpdHkgbWF0cml4IHNvIGFuZ2xlID0gMFxyXG5cclxuXHRcdFx0XHR0aGlzLnNldCggMSwgMCwgMCwgMCApO1xyXG5cclxuXHRcdFx0XHRyZXR1cm4gdGhpczsgLy8gemVybyBhbmdsZSwgYXJiaXRyYXJ5IGF4aXNcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdC8vIG90aGVyd2lzZSB0aGlzIHNpbmd1bGFyaXR5IGlzIGFuZ2xlID0gMTgwXHJcblxyXG5cdFx0XHRhbmdsZSA9IE1hdGguUEk7XHJcblxyXG5cdFx0XHRjb25zdCB4eCA9ICggbTExICsgMSApIC8gMjtcclxuXHRcdFx0Y29uc3QgeXkgPSAoIG0yMiArIDEgKSAvIDI7XHJcblx0XHRcdGNvbnN0IHp6ID0gKCBtMzMgKyAxICkgLyAyO1xyXG5cdFx0XHRjb25zdCB4eSA9ICggbTEyICsgbTIxICkgLyA0O1xyXG5cdFx0XHRjb25zdCB4eiA9ICggbTEzICsgbTMxICkgLyA0O1xyXG5cdFx0XHRjb25zdCB5eiA9ICggbTIzICsgbTMyICkgLyA0O1xyXG5cclxuXHRcdFx0aWYgKCAoIHh4ID4geXkgKSAmJiAoIHh4ID4genogKSApIHtcclxuXHJcblx0XHRcdFx0Ly8gbTExIGlzIHRoZSBsYXJnZXN0IGRpYWdvbmFsIHRlcm1cclxuXHJcblx0XHRcdFx0aWYgKCB4eCA8IGVwc2lsb24gKSB7XHJcblxyXG5cdFx0XHRcdFx0eCA9IDA7XHJcblx0XHRcdFx0XHR5ID0gMC43MDcxMDY3ODE7XHJcblx0XHRcdFx0XHR6ID0gMC43MDcxMDY3ODE7XHJcblxyXG5cdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0eCA9IE1hdGguc3FydCggeHggKTtcclxuXHRcdFx0XHRcdHkgPSB4eSAvIHg7XHJcblx0XHRcdFx0XHR6ID0geHogLyB4O1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9IGVsc2UgaWYgKCB5eSA+IHp6ICkge1xyXG5cclxuXHRcdFx0XHQvLyBtMjIgaXMgdGhlIGxhcmdlc3QgZGlhZ29uYWwgdGVybVxyXG5cclxuXHRcdFx0XHRpZiAoIHl5IDwgZXBzaWxvbiApIHtcclxuXHJcblx0XHRcdFx0XHR4ID0gMC43MDcxMDY3ODE7XHJcblx0XHRcdFx0XHR5ID0gMDtcclxuXHRcdFx0XHRcdHogPSAwLjcwNzEwNjc4MTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHR5ID0gTWF0aC5zcXJ0KCB5eSApO1xyXG5cdFx0XHRcdFx0eCA9IHh5IC8geTtcclxuXHRcdFx0XHRcdHogPSB5eiAvIHk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdC8vIG0zMyBpcyB0aGUgbGFyZ2VzdCBkaWFnb25hbCB0ZXJtIHNvIGJhc2UgcmVzdWx0IG9uIHRoaXNcclxuXHJcblx0XHRcdFx0aWYgKCB6eiA8IGVwc2lsb24gKSB7XHJcblxyXG5cdFx0XHRcdFx0eCA9IDAuNzA3MTA2NzgxO1xyXG5cdFx0XHRcdFx0eSA9IDAuNzA3MTA2NzgxO1xyXG5cdFx0XHRcdFx0eiA9IDA7XHJcblxyXG5cdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0eiA9IE1hdGguc3FydCggenogKTtcclxuXHRcdFx0XHRcdHggPSB4eiAvIHo7XHJcblx0XHRcdFx0XHR5ID0geXogLyB6O1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHR0aGlzLnNldCggeCwgeSwgeiwgYW5nbGUgKTtcclxuXHJcblx0XHRcdHJldHVybiB0aGlzOyAvLyByZXR1cm4gMTgwIGRlZyByb3RhdGlvblxyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvLyBhcyB3ZSBoYXZlIHJlYWNoZWQgaGVyZSB0aGVyZSBhcmUgbm8gc2luZ3VsYXJpdGllcyBzbyB3ZSBjYW4gaGFuZGxlIG5vcm1hbGx5XHJcblxyXG5cdFx0bGV0IHMgPSBNYXRoLnNxcnQoICggbTMyIC0gbTIzICkgKiAoIG0zMiAtIG0yMyApICtcclxuXHRcdFx0KCBtMTMgLSBtMzEgKSAqICggbTEzIC0gbTMxICkgK1xyXG5cdFx0XHQoIG0yMSAtIG0xMiApICogKCBtMjEgLSBtMTIgKSApOyAvLyB1c2VkIHRvIG5vcm1hbGl6ZVxyXG5cclxuXHRcdGlmICggTWF0aC5hYnMoIHMgKSA8IDAuMDAxICkgcyA9IDE7XHJcblxyXG5cdFx0Ly8gcHJldmVudCBkaXZpZGUgYnkgemVybywgc2hvdWxkIG5vdCBoYXBwZW4gaWYgbWF0cml4IGlzIG9ydGhvZ29uYWwgYW5kIHNob3VsZCBiZVxyXG5cdFx0Ly8gY2F1Z2h0IGJ5IHNpbmd1bGFyaXR5IHRlc3QgYWJvdmUsIGJ1dCBJJ3ZlIGxlZnQgaXQgaW4ganVzdCBpbiBjYXNlXHJcblxyXG5cdFx0dGhpcy54ID0gKCBtMzIgLSBtMjMgKSAvIHM7XHJcblx0XHR0aGlzLnkgPSAoIG0xMyAtIG0zMSApIC8gcztcclxuXHRcdHRoaXMueiA9ICggbTIxIC0gbTEyICkgLyBzO1xyXG5cdFx0dGhpcy53ID0gTWF0aC5hY29zKCAoIG0xMSArIG0yMiArIG0zMyAtIDEgKSAvIDIgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRtaW4oIHYgKSB7XHJcblxyXG5cdFx0dGhpcy54ID0gTWF0aC5taW4oIHRoaXMueCwgdi54ICk7XHJcblx0XHR0aGlzLnkgPSBNYXRoLm1pbiggdGhpcy55LCB2LnkgKTtcclxuXHRcdHRoaXMueiA9IE1hdGgubWluKCB0aGlzLnosIHYueiApO1xyXG5cdFx0dGhpcy53ID0gTWF0aC5taW4oIHRoaXMudywgdi53ICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0bWF4KCB2ICkge1xyXG5cclxuXHRcdHRoaXMueCA9IE1hdGgubWF4KCB0aGlzLngsIHYueCApO1xyXG5cdFx0dGhpcy55ID0gTWF0aC5tYXgoIHRoaXMueSwgdi55ICk7XHJcblx0XHR0aGlzLnogPSBNYXRoLm1heCggdGhpcy56LCB2LnogKTtcclxuXHRcdHRoaXMudyA9IE1hdGgubWF4KCB0aGlzLncsIHYudyApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGNsYW1wKCBtaW4sIG1heCApIHtcclxuXHJcblx0XHQvLyBhc3N1bWVzIG1pbiA8IG1heCwgY29tcG9uZW50d2lzZVxyXG5cclxuXHRcdHRoaXMueCA9IE1hdGgubWF4KCBtaW4ueCwgTWF0aC5taW4oIG1heC54LCB0aGlzLnggKSApO1xyXG5cdFx0dGhpcy55ID0gTWF0aC5tYXgoIG1pbi55LCBNYXRoLm1pbiggbWF4LnksIHRoaXMueSApICk7XHJcblx0XHR0aGlzLnogPSBNYXRoLm1heCggbWluLnosIE1hdGgubWluKCBtYXgueiwgdGhpcy56ICkgKTtcclxuXHRcdHRoaXMudyA9IE1hdGgubWF4KCBtaW4udywgTWF0aC5taW4oIG1heC53LCB0aGlzLncgKSApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGNsYW1wU2NhbGFyKCBtaW5WYWwsIG1heFZhbCApIHtcclxuXHJcblx0XHR0aGlzLnggPSBNYXRoLm1heCggbWluVmFsLCBNYXRoLm1pbiggbWF4VmFsLCB0aGlzLnggKSApO1xyXG5cdFx0dGhpcy55ID0gTWF0aC5tYXgoIG1pblZhbCwgTWF0aC5taW4oIG1heFZhbCwgdGhpcy55ICkgKTtcclxuXHRcdHRoaXMueiA9IE1hdGgubWF4KCBtaW5WYWwsIE1hdGgubWluKCBtYXhWYWwsIHRoaXMueiApICk7XHJcblx0XHR0aGlzLncgPSBNYXRoLm1heCggbWluVmFsLCBNYXRoLm1pbiggbWF4VmFsLCB0aGlzLncgKSApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGNsYW1wTGVuZ3RoKCBtaW4sIG1heCApIHtcclxuXHJcblx0XHRjb25zdCBsZW5ndGggPSB0aGlzLmxlbmd0aCgpO1xyXG5cclxuXHRcdHJldHVybiB0aGlzLmRpdmlkZVNjYWxhciggbGVuZ3RoIHx8IDEgKS5tdWx0aXBseVNjYWxhciggTWF0aC5tYXgoIG1pbiwgTWF0aC5taW4oIG1heCwgbGVuZ3RoICkgKSApO1xyXG5cclxuXHR9XHJcblxyXG5cdGZsb29yKCkge1xyXG5cclxuXHRcdHRoaXMueCA9IE1hdGguZmxvb3IoIHRoaXMueCApO1xyXG5cdFx0dGhpcy55ID0gTWF0aC5mbG9vciggdGhpcy55ICk7XHJcblx0XHR0aGlzLnogPSBNYXRoLmZsb29yKCB0aGlzLnogKTtcclxuXHRcdHRoaXMudyA9IE1hdGguZmxvb3IoIHRoaXMudyApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGNlaWwoKSB7XHJcblxyXG5cdFx0dGhpcy54ID0gTWF0aC5jZWlsKCB0aGlzLnggKTtcclxuXHRcdHRoaXMueSA9IE1hdGguY2VpbCggdGhpcy55ICk7XHJcblx0XHR0aGlzLnogPSBNYXRoLmNlaWwoIHRoaXMueiApO1xyXG5cdFx0dGhpcy53ID0gTWF0aC5jZWlsKCB0aGlzLncgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRyb3VuZCgpIHtcclxuXHJcblx0XHR0aGlzLnggPSBNYXRoLnJvdW5kKCB0aGlzLnggKTtcclxuXHRcdHRoaXMueSA9IE1hdGgucm91bmQoIHRoaXMueSApO1xyXG5cdFx0dGhpcy56ID0gTWF0aC5yb3VuZCggdGhpcy56ICk7XHJcblx0XHR0aGlzLncgPSBNYXRoLnJvdW5kKCB0aGlzLncgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRyb3VuZFRvWmVybygpIHtcclxuXHJcblx0XHR0aGlzLnggPSBNYXRoLnRydW5jKCB0aGlzLnggKTtcclxuXHRcdHRoaXMueSA9IE1hdGgudHJ1bmMoIHRoaXMueSApO1xyXG5cdFx0dGhpcy56ID0gTWF0aC50cnVuYyggdGhpcy56ICk7XHJcblx0XHR0aGlzLncgPSBNYXRoLnRydW5jKCB0aGlzLncgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRuZWdhdGUoKSB7XHJcblxyXG5cdFx0dGhpcy54ID0gLSB0aGlzLng7XHJcblx0XHR0aGlzLnkgPSAtIHRoaXMueTtcclxuXHRcdHRoaXMueiA9IC0gdGhpcy56O1xyXG5cdFx0dGhpcy53ID0gLSB0aGlzLnc7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0ZG90KCB2ICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLnggKiB2LnggKyB0aGlzLnkgKiB2LnkgKyB0aGlzLnogKiB2LnogKyB0aGlzLncgKiB2Lnc7XHJcblxyXG5cdH1cclxuXHJcblx0bGVuZ3RoU3EoKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMueCAqIHRoaXMueCArIHRoaXMueSAqIHRoaXMueSArIHRoaXMueiAqIHRoaXMueiArIHRoaXMudyAqIHRoaXMudztcclxuXHJcblx0fVxyXG5cclxuXHRsZW5ndGgoKSB7XHJcblxyXG5cdFx0cmV0dXJuIE1hdGguc3FydCggdGhpcy54ICogdGhpcy54ICsgdGhpcy55ICogdGhpcy55ICsgdGhpcy56ICogdGhpcy56ICsgdGhpcy53ICogdGhpcy53ICk7XHJcblxyXG5cdH1cclxuXHJcblx0bWFuaGF0dGFuTGVuZ3RoKCkge1xyXG5cclxuXHRcdHJldHVybiBNYXRoLmFicyggdGhpcy54ICkgKyBNYXRoLmFicyggdGhpcy55ICkgKyBNYXRoLmFicyggdGhpcy56ICkgKyBNYXRoLmFicyggdGhpcy53ICk7XHJcblxyXG5cdH1cclxuXHJcblx0bm9ybWFsaXplKCkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLmRpdmlkZVNjYWxhciggdGhpcy5sZW5ndGgoKSB8fCAxICk7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0TGVuZ3RoKCBsZW5ndGggKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMubm9ybWFsaXplKCkubXVsdGlwbHlTY2FsYXIoIGxlbmd0aCApO1xyXG5cclxuXHR9XHJcblxyXG5cdGxlcnAoIHYsIGFscGhhICkge1xyXG5cclxuXHRcdHRoaXMueCArPSAoIHYueCAtIHRoaXMueCApICogYWxwaGE7XHJcblx0XHR0aGlzLnkgKz0gKCB2LnkgLSB0aGlzLnkgKSAqIGFscGhhO1xyXG5cdFx0dGhpcy56ICs9ICggdi56IC0gdGhpcy56ICkgKiBhbHBoYTtcclxuXHRcdHRoaXMudyArPSAoIHYudyAtIHRoaXMudyApICogYWxwaGE7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0bGVycFZlY3RvcnMoIHYxLCB2MiwgYWxwaGEgKSB7XHJcblxyXG5cdFx0dGhpcy54ID0gdjEueCArICggdjIueCAtIHYxLnggKSAqIGFscGhhO1xyXG5cdFx0dGhpcy55ID0gdjEueSArICggdjIueSAtIHYxLnkgKSAqIGFscGhhO1xyXG5cdFx0dGhpcy56ID0gdjEueiArICggdjIueiAtIHYxLnogKSAqIGFscGhhO1xyXG5cdFx0dGhpcy53ID0gdjEudyArICggdjIudyAtIHYxLncgKSAqIGFscGhhO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGVxdWFscyggdiApIHtcclxuXHJcblx0XHRyZXR1cm4gKCAoIHYueCA9PT0gdGhpcy54ICkgJiYgKCB2LnkgPT09IHRoaXMueSApICYmICggdi56ID09PSB0aGlzLnogKSAmJiAoIHYudyA9PT0gdGhpcy53ICkgKTtcclxuXHJcblx0fVxyXG5cclxuXHRmcm9tQXJyYXkoIGFycmF5LCBvZmZzZXQgPSAwICkge1xyXG5cclxuXHRcdHRoaXMueCA9IGFycmF5WyBvZmZzZXQgXTtcclxuXHRcdHRoaXMueSA9IGFycmF5WyBvZmZzZXQgKyAxIF07XHJcblx0XHR0aGlzLnogPSBhcnJheVsgb2Zmc2V0ICsgMiBdO1xyXG5cdFx0dGhpcy53ID0gYXJyYXlbIG9mZnNldCArIDMgXTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHR0b0FycmF5KCBhcnJheSA9IFtdLCBvZmZzZXQgPSAwICkge1xyXG5cclxuXHRcdGFycmF5WyBvZmZzZXQgXSA9IHRoaXMueDtcclxuXHRcdGFycmF5WyBvZmZzZXQgKyAxIF0gPSB0aGlzLnk7XHJcblx0XHRhcnJheVsgb2Zmc2V0ICsgMiBdID0gdGhpcy56O1xyXG5cdFx0YXJyYXlbIG9mZnNldCArIDMgXSA9IHRoaXMudztcclxuXHJcblx0XHRyZXR1cm4gYXJyYXk7XHJcblxyXG5cdH1cclxuXHJcblx0ZnJvbUJ1ZmZlckF0dHJpYnV0ZSggYXR0cmlidXRlLCBpbmRleCApIHtcclxuXHJcblx0XHR0aGlzLnggPSBhdHRyaWJ1dGUuZ2V0WCggaW5kZXggKTtcclxuXHRcdHRoaXMueSA9IGF0dHJpYnV0ZS5nZXRZKCBpbmRleCApO1xyXG5cdFx0dGhpcy56ID0gYXR0cmlidXRlLmdldFooIGluZGV4ICk7XHJcblx0XHR0aGlzLncgPSBhdHRyaWJ1dGUuZ2V0VyggaW5kZXggKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRyYW5kb20oKSB7XHJcblxyXG5cdFx0dGhpcy54ID0gTWF0aC5yYW5kb20oKTtcclxuXHRcdHRoaXMueSA9IE1hdGgucmFuZG9tKCk7XHJcblx0XHR0aGlzLnogPSBNYXRoLnJhbmRvbSgpO1xyXG5cdFx0dGhpcy53ID0gTWF0aC5yYW5kb20oKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHQqWyBTeW1ib2wuaXRlcmF0b3IgXSgpIHtcclxuXHJcblx0XHR5aWVsZCB0aGlzLng7XHJcblx0XHR5aWVsZCB0aGlzLnk7XHJcblx0XHR5aWVsZCB0aGlzLno7XHJcblx0XHR5aWVsZCB0aGlzLnc7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IFZlY3RvcjQgfTtcclxuIiwiaW1wb3J0IHsgRXZlbnREaXNwYXRjaGVyIH0gZnJvbSAnLi9FdmVudERpc3BhdGNoZXIuanMnO1xyXG5pbXBvcnQgeyBUZXh0dXJlIH0gZnJvbSAnLi4vdGV4dHVyZXMvVGV4dHVyZS5qcyc7XHJcbmltcG9ydCB7IExpbmVhckZpbHRlciB9IGZyb20gJy4uL2NvbnN0YW50cy5qcyc7XHJcbmltcG9ydCB7IFZlY3RvcjQgfSBmcm9tICcuLi9tYXRoL1ZlY3RvcjQuanMnO1xyXG5pbXBvcnQgeyBTb3VyY2UgfSBmcm9tICcuLi90ZXh0dXJlcy9Tb3VyY2UuanMnO1xyXG5cclxuLypcclxuIEluIG9wdGlvbnMsIHdlIGNhbiBzcGVjaWZ5OlxyXG4gKiBUZXh0dXJlIHBhcmFtZXRlcnMgZm9yIGFuIGF1dG8tZ2VuZXJhdGVkIHRhcmdldCB0ZXh0dXJlXHJcbiAqIGRlcHRoQnVmZmVyL3N0ZW5jaWxCdWZmZXI6IEJvb2xlYW5zIHRvIGluZGljYXRlIGlmIHdlIHNob3VsZCBnZW5lcmF0ZSB0aGVzZSBidWZmZXJzXHJcbiovXHJcbmNsYXNzIFJlbmRlclRhcmdldCBleHRlbmRzIEV2ZW50RGlzcGF0Y2hlciB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCB3aWR0aCA9IDEsIGhlaWdodCA9IDEsIG9wdGlvbnMgPSB7fSApIHtcclxuXHJcblx0XHRzdXBlcigpO1xyXG5cclxuXHRcdHRoaXMuaXNSZW5kZXJUYXJnZXQgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMud2lkdGggPSB3aWR0aDtcclxuXHRcdHRoaXMuaGVpZ2h0ID0gaGVpZ2h0O1xyXG5cdFx0dGhpcy5kZXB0aCA9IDE7XHJcblxyXG5cdFx0dGhpcy5zY2lzc29yID0gbmV3IFZlY3RvcjQoIDAsIDAsIHdpZHRoLCBoZWlnaHQgKTtcclxuXHRcdHRoaXMuc2Npc3NvclRlc3QgPSBmYWxzZTtcclxuXHJcblx0XHR0aGlzLnZpZXdwb3J0ID0gbmV3IFZlY3RvcjQoIDAsIDAsIHdpZHRoLCBoZWlnaHQgKTtcclxuXHJcblx0XHRjb25zdCBpbWFnZSA9IHsgd2lkdGg6IHdpZHRoLCBoZWlnaHQ6IGhlaWdodCwgZGVwdGg6IDEgfTtcclxuXHJcblx0XHRvcHRpb25zID0gT2JqZWN0LmFzc2lnbigge1xyXG5cdFx0XHRnZW5lcmF0ZU1pcG1hcHM6IGZhbHNlLFxyXG5cdFx0XHRpbnRlcm5hbEZvcm1hdDogbnVsbCxcclxuXHRcdFx0bWluRmlsdGVyOiBMaW5lYXJGaWx0ZXIsXHJcblx0XHRcdGRlcHRoQnVmZmVyOiB0cnVlLFxyXG5cdFx0XHRzdGVuY2lsQnVmZmVyOiBmYWxzZSxcclxuXHRcdFx0ZGVwdGhUZXh0dXJlOiBudWxsLFxyXG5cdFx0XHRzYW1wbGVzOiAwXHJcblx0XHR9LCBvcHRpb25zICk7XHJcblxyXG5cdFx0dGhpcy50ZXh0dXJlID0gbmV3IFRleHR1cmUoIGltYWdlLCBvcHRpb25zLm1hcHBpbmcsIG9wdGlvbnMud3JhcFMsIG9wdGlvbnMud3JhcFQsIG9wdGlvbnMubWFnRmlsdGVyLCBvcHRpb25zLm1pbkZpbHRlciwgb3B0aW9ucy5mb3JtYXQsIG9wdGlvbnMudHlwZSwgb3B0aW9ucy5hbmlzb3Ryb3B5LCBvcHRpb25zLmNvbG9yU3BhY2UgKTtcclxuXHRcdHRoaXMudGV4dHVyZS5pc1JlbmRlclRhcmdldFRleHR1cmUgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMudGV4dHVyZS5mbGlwWSA9IGZhbHNlO1xyXG5cdFx0dGhpcy50ZXh0dXJlLmdlbmVyYXRlTWlwbWFwcyA9IG9wdGlvbnMuZ2VuZXJhdGVNaXBtYXBzO1xyXG5cdFx0dGhpcy50ZXh0dXJlLmludGVybmFsRm9ybWF0ID0gb3B0aW9ucy5pbnRlcm5hbEZvcm1hdDtcclxuXHJcblx0XHR0aGlzLmRlcHRoQnVmZmVyID0gb3B0aW9ucy5kZXB0aEJ1ZmZlcjtcclxuXHRcdHRoaXMuc3RlbmNpbEJ1ZmZlciA9IG9wdGlvbnMuc3RlbmNpbEJ1ZmZlcjtcclxuXHJcblx0XHR0aGlzLmRlcHRoVGV4dHVyZSA9IG9wdGlvbnMuZGVwdGhUZXh0dXJlO1xyXG5cclxuXHRcdHRoaXMuc2FtcGxlcyA9IG9wdGlvbnMuc2FtcGxlcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRTaXplKCB3aWR0aCwgaGVpZ2h0LCBkZXB0aCA9IDEgKSB7XHJcblxyXG5cdFx0aWYgKCB0aGlzLndpZHRoICE9PSB3aWR0aCB8fCB0aGlzLmhlaWdodCAhPT0gaGVpZ2h0IHx8IHRoaXMuZGVwdGggIT09IGRlcHRoICkge1xyXG5cclxuXHRcdFx0dGhpcy53aWR0aCA9IHdpZHRoO1xyXG5cdFx0XHR0aGlzLmhlaWdodCA9IGhlaWdodDtcclxuXHRcdFx0dGhpcy5kZXB0aCA9IGRlcHRoO1xyXG5cclxuXHRcdFx0dGhpcy50ZXh0dXJlLmltYWdlLndpZHRoID0gd2lkdGg7XHJcblx0XHRcdHRoaXMudGV4dHVyZS5pbWFnZS5oZWlnaHQgPSBoZWlnaHQ7XHJcblx0XHRcdHRoaXMudGV4dHVyZS5pbWFnZS5kZXB0aCA9IGRlcHRoO1xyXG5cclxuXHRcdFx0dGhpcy5kaXNwb3NlKCk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMudmlld3BvcnQuc2V0KCAwLCAwLCB3aWR0aCwgaGVpZ2h0ICk7XHJcblx0XHR0aGlzLnNjaXNzb3Iuc2V0KCAwLCAwLCB3aWR0aCwgaGVpZ2h0ICk7XHJcblxyXG5cdH1cclxuXHJcblx0Y2xvbmUoKSB7XHJcblxyXG5cdFx0cmV0dXJuIG5ldyB0aGlzLmNvbnN0cnVjdG9yKCkuY29weSggdGhpcyApO1xyXG5cclxuXHR9XHJcblxyXG5cdGNvcHkoIHNvdXJjZSApIHtcclxuXHJcblx0XHR0aGlzLndpZHRoID0gc291cmNlLndpZHRoO1xyXG5cdFx0dGhpcy5oZWlnaHQgPSBzb3VyY2UuaGVpZ2h0O1xyXG5cdFx0dGhpcy5kZXB0aCA9IHNvdXJjZS5kZXB0aDtcclxuXHJcblx0XHR0aGlzLnNjaXNzb3IuY29weSggc291cmNlLnNjaXNzb3IgKTtcclxuXHRcdHRoaXMuc2Npc3NvclRlc3QgPSBzb3VyY2Uuc2Npc3NvclRlc3Q7XHJcblxyXG5cdFx0dGhpcy52aWV3cG9ydC5jb3B5KCBzb3VyY2Uudmlld3BvcnQgKTtcclxuXHJcblx0XHR0aGlzLnRleHR1cmUgPSBzb3VyY2UudGV4dHVyZS5jbG9uZSgpO1xyXG5cdFx0dGhpcy50ZXh0dXJlLmlzUmVuZGVyVGFyZ2V0VGV4dHVyZSA9IHRydWU7XHJcblxyXG5cdFx0Ly8gZW5zdXJlIGltYWdlIG9iamVjdCBpcyBub3Qgc2hhcmVkLCBzZWUgIzIwMzI4XHJcblxyXG5cdFx0Y29uc3QgaW1hZ2UgPSBPYmplY3QuYXNzaWduKCB7fSwgc291cmNlLnRleHR1cmUuaW1hZ2UgKTtcclxuXHRcdHRoaXMudGV4dHVyZS5zb3VyY2UgPSBuZXcgU291cmNlKCBpbWFnZSApO1xyXG5cclxuXHRcdHRoaXMuZGVwdGhCdWZmZXIgPSBzb3VyY2UuZGVwdGhCdWZmZXI7XHJcblx0XHR0aGlzLnN0ZW5jaWxCdWZmZXIgPSBzb3VyY2Uuc3RlbmNpbEJ1ZmZlcjtcclxuXHJcblx0XHRpZiAoIHNvdXJjZS5kZXB0aFRleHR1cmUgIT09IG51bGwgKSB0aGlzLmRlcHRoVGV4dHVyZSA9IHNvdXJjZS5kZXB0aFRleHR1cmUuY2xvbmUoKTtcclxuXHJcblx0XHR0aGlzLnNhbXBsZXMgPSBzb3VyY2Uuc2FtcGxlcztcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRkaXNwb3NlKCkge1xyXG5cclxuXHRcdHRoaXMuZGlzcGF0Y2hFdmVudCggeyB0eXBlOiAnZGlzcG9zZScgfSApO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBSZW5kZXJUYXJnZXQgfTtcclxuIiwiaW1wb3J0IHsgUmVuZGVyVGFyZ2V0IH0gZnJvbSAnLi4vY29yZS9SZW5kZXJUYXJnZXQuanMnO1xyXG5cclxuY2xhc3MgV2ViR0xSZW5kZXJUYXJnZXQgZXh0ZW5kcyBSZW5kZXJUYXJnZXQge1xyXG5cclxuXHRjb25zdHJ1Y3Rvciggd2lkdGggPSAxLCBoZWlnaHQgPSAxLCBvcHRpb25zID0ge30gKSB7XHJcblxyXG5cdFx0c3VwZXIoIHdpZHRoLCBoZWlnaHQsIG9wdGlvbnMgKTtcclxuXHJcblx0XHR0aGlzLmlzV2ViR0xSZW5kZXJUYXJnZXQgPSB0cnVlO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBXZWJHTFJlbmRlclRhcmdldCB9O1xyXG4iLCJpbXBvcnQgeyBUZXh0dXJlIH0gZnJvbSAnLi9UZXh0dXJlLmpzJztcclxuaW1wb3J0IHsgQ2xhbXBUb0VkZ2VXcmFwcGluZywgTmVhcmVzdEZpbHRlciB9IGZyb20gJy4uL2NvbnN0YW50cy5qcyc7XHJcblxyXG5jbGFzcyBEYXRhQXJyYXlUZXh0dXJlIGV4dGVuZHMgVGV4dHVyZSB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBkYXRhID0gbnVsbCwgd2lkdGggPSAxLCBoZWlnaHQgPSAxLCBkZXB0aCA9IDEgKSB7XHJcblxyXG5cdFx0c3VwZXIoIG51bGwgKTtcclxuXHJcblx0XHR0aGlzLmlzRGF0YUFycmF5VGV4dHVyZSA9IHRydWU7XHJcblxyXG5cdFx0dGhpcy5pbWFnZSA9IHsgZGF0YSwgd2lkdGgsIGhlaWdodCwgZGVwdGggfTtcclxuXHJcblx0XHR0aGlzLm1hZ0ZpbHRlciA9IE5lYXJlc3RGaWx0ZXI7XHJcblx0XHR0aGlzLm1pbkZpbHRlciA9IE5lYXJlc3RGaWx0ZXI7XHJcblxyXG5cdFx0dGhpcy53cmFwUiA9IENsYW1wVG9FZGdlV3JhcHBpbmc7XHJcblxyXG5cdFx0dGhpcy5nZW5lcmF0ZU1pcG1hcHMgPSBmYWxzZTtcclxuXHRcdHRoaXMuZmxpcFkgPSBmYWxzZTtcclxuXHRcdHRoaXMudW5wYWNrQWxpZ25tZW50ID0gMTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgRGF0YUFycmF5VGV4dHVyZSB9O1xyXG4iLCJpbXBvcnQgeyBXZWJHTFJlbmRlclRhcmdldCB9IGZyb20gJy4vV2ViR0xSZW5kZXJUYXJnZXQuanMnO1xyXG5pbXBvcnQgeyBEYXRhQXJyYXlUZXh0dXJlIH0gZnJvbSAnLi4vdGV4dHVyZXMvRGF0YUFycmF5VGV4dHVyZS5qcyc7XHJcblxyXG5jbGFzcyBXZWJHTEFycmF5UmVuZGVyVGFyZ2V0IGV4dGVuZHMgV2ViR0xSZW5kZXJUYXJnZXQge1xyXG5cclxuXHRjb25zdHJ1Y3Rvciggd2lkdGggPSAxLCBoZWlnaHQgPSAxLCBkZXB0aCA9IDEsIG9wdGlvbnMgPSB7fSApIHtcclxuXHJcblx0XHRzdXBlciggd2lkdGgsIGhlaWdodCwgb3B0aW9ucyApO1xyXG5cclxuXHRcdHRoaXMuaXNXZWJHTEFycmF5UmVuZGVyVGFyZ2V0ID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLmRlcHRoID0gZGVwdGg7XHJcblxyXG5cdFx0dGhpcy50ZXh0dXJlID0gbmV3IERhdGFBcnJheVRleHR1cmUoIG51bGwsIHdpZHRoLCBoZWlnaHQsIGRlcHRoICk7XHJcblxyXG5cdFx0dGhpcy50ZXh0dXJlLmlzUmVuZGVyVGFyZ2V0VGV4dHVyZSA9IHRydWU7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IFdlYkdMQXJyYXlSZW5kZXJUYXJnZXQgfTtcclxuIiwiaW1wb3J0IHsgVGV4dHVyZSB9IGZyb20gJy4vVGV4dHVyZS5qcyc7XHJcbmltcG9ydCB7IENsYW1wVG9FZGdlV3JhcHBpbmcsIE5lYXJlc3RGaWx0ZXIgfSBmcm9tICcuLi9jb25zdGFudHMuanMnO1xyXG5cclxuY2xhc3MgRGF0YTNEVGV4dHVyZSBleHRlbmRzIFRleHR1cmUge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggZGF0YSA9IG51bGwsIHdpZHRoID0gMSwgaGVpZ2h0ID0gMSwgZGVwdGggPSAxICkge1xyXG5cclxuXHRcdC8vIFdlJ3JlIGdvaW5nIHRvIGFkZCAuc2V0WFhYKCkgbWV0aG9kcyBmb3Igc2V0dGluZyBwcm9wZXJ0aWVzIGxhdGVyLlxyXG5cdFx0Ly8gVXNlcnMgY2FuIHN0aWxsIHNldCBpbiBEYXRhVGV4dHVyZTNEIGRpcmVjdGx5LlxyXG5cdFx0Ly9cclxuXHRcdC8vXHRjb25zdCB0ZXh0dXJlID0gbmV3IFRIUkVFLkRhdGFUZXh0dXJlM0QoIGRhdGEsIHdpZHRoLCBoZWlnaHQsIGRlcHRoICk7XHJcblx0XHQvLyBcdHRleHR1cmUuYW5pc290cm9weSA9IDE2O1xyXG5cdFx0Ly9cclxuXHRcdC8vIFNlZSAjMTQ4MzlcclxuXHJcblx0XHRzdXBlciggbnVsbCApO1xyXG5cclxuXHRcdHRoaXMuaXNEYXRhM0RUZXh0dXJlID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLmltYWdlID0geyBkYXRhLCB3aWR0aCwgaGVpZ2h0LCBkZXB0aCB9O1xyXG5cclxuXHRcdHRoaXMubWFnRmlsdGVyID0gTmVhcmVzdEZpbHRlcjtcclxuXHRcdHRoaXMubWluRmlsdGVyID0gTmVhcmVzdEZpbHRlcjtcclxuXHJcblx0XHR0aGlzLndyYXBSID0gQ2xhbXBUb0VkZ2VXcmFwcGluZztcclxuXHJcblx0XHR0aGlzLmdlbmVyYXRlTWlwbWFwcyA9IGZhbHNlO1xyXG5cdFx0dGhpcy5mbGlwWSA9IGZhbHNlO1xyXG5cdFx0dGhpcy51bnBhY2tBbGlnbm1lbnQgPSAxO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBEYXRhM0RUZXh0dXJlIH07XHJcbiIsImltcG9ydCB7IFdlYkdMUmVuZGVyVGFyZ2V0IH0gZnJvbSAnLi9XZWJHTFJlbmRlclRhcmdldC5qcyc7XHJcbmltcG9ydCB7IERhdGEzRFRleHR1cmUgfSBmcm9tICcuLi90ZXh0dXJlcy9EYXRhM0RUZXh0dXJlLmpzJztcclxuXHJcbmNsYXNzIFdlYkdMM0RSZW5kZXJUYXJnZXQgZXh0ZW5kcyBXZWJHTFJlbmRlclRhcmdldCB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCB3aWR0aCA9IDEsIGhlaWdodCA9IDEsIGRlcHRoID0gMSwgb3B0aW9ucyA9IHt9ICkge1xyXG5cclxuXHRcdHN1cGVyKCB3aWR0aCwgaGVpZ2h0LCBvcHRpb25zICk7XHJcblxyXG5cdFx0dGhpcy5pc1dlYkdMM0RSZW5kZXJUYXJnZXQgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMuZGVwdGggPSBkZXB0aDtcclxuXHJcblx0XHR0aGlzLnRleHR1cmUgPSBuZXcgRGF0YTNEVGV4dHVyZSggbnVsbCwgd2lkdGgsIGhlaWdodCwgZGVwdGggKTtcclxuXHJcblx0XHR0aGlzLnRleHR1cmUuaXNSZW5kZXJUYXJnZXRUZXh0dXJlID0gdHJ1ZTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgV2ViR0wzRFJlbmRlclRhcmdldCB9O1xyXG4iLCJpbXBvcnQgeyBXZWJHTFJlbmRlclRhcmdldCB9IGZyb20gJy4vV2ViR0xSZW5kZXJUYXJnZXQuanMnO1xyXG5cclxuY2xhc3MgV2ViR0xNdWx0aXBsZVJlbmRlclRhcmdldHMgZXh0ZW5kcyBXZWJHTFJlbmRlclRhcmdldCB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCB3aWR0aCA9IDEsIGhlaWdodCA9IDEsIGNvdW50ID0gMSwgb3B0aW9ucyA9IHt9ICkge1xyXG5cclxuXHRcdHN1cGVyKCB3aWR0aCwgaGVpZ2h0LCBvcHRpb25zICk7XHJcblxyXG5cdFx0dGhpcy5pc1dlYkdMTXVsdGlwbGVSZW5kZXJUYXJnZXRzID0gdHJ1ZTtcclxuXHJcblx0XHRjb25zdCB0ZXh0dXJlID0gdGhpcy50ZXh0dXJlO1xyXG5cclxuXHRcdHRoaXMudGV4dHVyZSA9IFtdO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IGNvdW50OyBpICsrICkge1xyXG5cclxuXHRcdFx0dGhpcy50ZXh0dXJlWyBpIF0gPSB0ZXh0dXJlLmNsb25lKCk7XHJcblx0XHRcdHRoaXMudGV4dHVyZVsgaSBdLmlzUmVuZGVyVGFyZ2V0VGV4dHVyZSA9IHRydWU7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdHNldFNpemUoIHdpZHRoLCBoZWlnaHQsIGRlcHRoID0gMSApIHtcclxuXHJcblx0XHRpZiAoIHRoaXMud2lkdGggIT09IHdpZHRoIHx8IHRoaXMuaGVpZ2h0ICE9PSBoZWlnaHQgfHwgdGhpcy5kZXB0aCAhPT0gZGVwdGggKSB7XHJcblxyXG5cdFx0XHR0aGlzLndpZHRoID0gd2lkdGg7XHJcblx0XHRcdHRoaXMuaGVpZ2h0ID0gaGVpZ2h0O1xyXG5cdFx0XHR0aGlzLmRlcHRoID0gZGVwdGg7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gdGhpcy50ZXh0dXJlLmxlbmd0aDsgaSA8IGlsOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHR0aGlzLnRleHR1cmVbIGkgXS5pbWFnZS53aWR0aCA9IHdpZHRoO1xyXG5cdFx0XHRcdHRoaXMudGV4dHVyZVsgaSBdLmltYWdlLmhlaWdodCA9IGhlaWdodDtcclxuXHRcdFx0XHR0aGlzLnRleHR1cmVbIGkgXS5pbWFnZS5kZXB0aCA9IGRlcHRoO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0dGhpcy5kaXNwb3NlKCk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMudmlld3BvcnQuc2V0KCAwLCAwLCB3aWR0aCwgaGVpZ2h0ICk7XHJcblx0XHR0aGlzLnNjaXNzb3Iuc2V0KCAwLCAwLCB3aWR0aCwgaGVpZ2h0ICk7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHRoaXMuZGlzcG9zZSgpO1xyXG5cclxuXHRcdHRoaXMud2lkdGggPSBzb3VyY2Uud2lkdGg7XHJcblx0XHR0aGlzLmhlaWdodCA9IHNvdXJjZS5oZWlnaHQ7XHJcblx0XHR0aGlzLmRlcHRoID0gc291cmNlLmRlcHRoO1xyXG5cclxuXHRcdHRoaXMuc2Npc3Nvci5jb3B5KCBzb3VyY2Uuc2Npc3NvciApO1xyXG5cdFx0dGhpcy5zY2lzc29yVGVzdCA9IHNvdXJjZS5zY2lzc29yVGVzdDtcclxuXHJcblx0XHR0aGlzLnZpZXdwb3J0LmNvcHkoIHNvdXJjZS52aWV3cG9ydCApO1xyXG5cclxuXHRcdHRoaXMuZGVwdGhCdWZmZXIgPSBzb3VyY2UuZGVwdGhCdWZmZXI7XHJcblx0XHR0aGlzLnN0ZW5jaWxCdWZmZXIgPSBzb3VyY2Uuc3RlbmNpbEJ1ZmZlcjtcclxuXHJcblx0XHRpZiAoIHNvdXJjZS5kZXB0aFRleHR1cmUgIT09IG51bGwgKSB0aGlzLmRlcHRoVGV4dHVyZSA9IHNvdXJjZS5kZXB0aFRleHR1cmUuY2xvbmUoKTtcclxuXHJcblx0XHR0aGlzLnRleHR1cmUubGVuZ3RoID0gMDtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gc291cmNlLnRleHR1cmUubGVuZ3RoOyBpIDwgaWw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHR0aGlzLnRleHR1cmVbIGkgXSA9IHNvdXJjZS50ZXh0dXJlWyBpIF0uY2xvbmUoKTtcclxuXHRcdFx0dGhpcy50ZXh0dXJlWyBpIF0uaXNSZW5kZXJUYXJnZXRUZXh0dXJlID0gdHJ1ZTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IFdlYkdMTXVsdGlwbGVSZW5kZXJUYXJnZXRzIH07XHJcbiIsImltcG9ydCAqIGFzIE1hdGhVdGlscyBmcm9tICcuL01hdGhVdGlscy5qcyc7XHJcblxyXG5jbGFzcyBRdWF0ZXJuaW9uIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIHggPSAwLCB5ID0gMCwgeiA9IDAsIHcgPSAxICkge1xyXG5cclxuXHRcdHRoaXMuaXNRdWF0ZXJuaW9uID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLl94ID0geDtcclxuXHRcdHRoaXMuX3kgPSB5O1xyXG5cdFx0dGhpcy5feiA9IHo7XHJcblx0XHR0aGlzLl93ID0gdztcclxuXHJcblx0fVxyXG5cclxuXHRzdGF0aWMgc2xlcnBGbGF0KCBkc3QsIGRzdE9mZnNldCwgc3JjMCwgc3JjT2Zmc2V0MCwgc3JjMSwgc3JjT2Zmc2V0MSwgdCApIHtcclxuXHJcblx0XHQvLyBmdXp6LWZyZWUsIGFycmF5LWJhc2VkIFF1YXRlcm5pb24gU0xFUlAgb3BlcmF0aW9uXHJcblxyXG5cdFx0bGV0IHgwID0gc3JjMFsgc3JjT2Zmc2V0MCArIDAgXSxcclxuXHRcdFx0eTAgPSBzcmMwWyBzcmNPZmZzZXQwICsgMSBdLFxyXG5cdFx0XHR6MCA9IHNyYzBbIHNyY09mZnNldDAgKyAyIF0sXHJcblx0XHRcdHcwID0gc3JjMFsgc3JjT2Zmc2V0MCArIDMgXTtcclxuXHJcblx0XHRjb25zdCB4MSA9IHNyYzFbIHNyY09mZnNldDEgKyAwIF0sXHJcblx0XHRcdHkxID0gc3JjMVsgc3JjT2Zmc2V0MSArIDEgXSxcclxuXHRcdFx0ejEgPSBzcmMxWyBzcmNPZmZzZXQxICsgMiBdLFxyXG5cdFx0XHR3MSA9IHNyYzFbIHNyY09mZnNldDEgKyAzIF07XHJcblxyXG5cdFx0aWYgKCB0ID09PSAwICkge1xyXG5cclxuXHRcdFx0ZHN0WyBkc3RPZmZzZXQgKyAwIF0gPSB4MDtcclxuXHRcdFx0ZHN0WyBkc3RPZmZzZXQgKyAxIF0gPSB5MDtcclxuXHRcdFx0ZHN0WyBkc3RPZmZzZXQgKyAyIF0gPSB6MDtcclxuXHRcdFx0ZHN0WyBkc3RPZmZzZXQgKyAzIF0gPSB3MDtcclxuXHRcdFx0cmV0dXJuO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHQgPT09IDEgKSB7XHJcblxyXG5cdFx0XHRkc3RbIGRzdE9mZnNldCArIDAgXSA9IHgxO1xyXG5cdFx0XHRkc3RbIGRzdE9mZnNldCArIDEgXSA9IHkxO1xyXG5cdFx0XHRkc3RbIGRzdE9mZnNldCArIDIgXSA9IHoxO1xyXG5cdFx0XHRkc3RbIGRzdE9mZnNldCArIDMgXSA9IHcxO1xyXG5cdFx0XHRyZXR1cm47XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggdzAgIT09IHcxIHx8IHgwICE9PSB4MSB8fCB5MCAhPT0geTEgfHwgejAgIT09IHoxICkge1xyXG5cclxuXHRcdFx0bGV0IHMgPSAxIC0gdDtcclxuXHRcdFx0Y29uc3QgY29zID0geDAgKiB4MSArIHkwICogeTEgKyB6MCAqIHoxICsgdzAgKiB3MSxcclxuXHRcdFx0XHRkaXIgPSAoIGNvcyA+PSAwID8gMSA6IC0gMSApLFxyXG5cdFx0XHRcdHNxclNpbiA9IDEgLSBjb3MgKiBjb3M7XHJcblxyXG5cdFx0XHQvLyBTa2lwIHRoZSBTbGVycCBmb3IgdGlueSBzdGVwcyB0byBhdm9pZCBudW1lcmljIHByb2JsZW1zOlxyXG5cdFx0XHRpZiAoIHNxclNpbiA+IE51bWJlci5FUFNJTE9OICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBzaW4gPSBNYXRoLnNxcnQoIHNxclNpbiApLFxyXG5cdFx0XHRcdFx0bGVuID0gTWF0aC5hdGFuMiggc2luLCBjb3MgKiBkaXIgKTtcclxuXHJcblx0XHRcdFx0cyA9IE1hdGguc2luKCBzICogbGVuICkgLyBzaW47XHJcblx0XHRcdFx0dCA9IE1hdGguc2luKCB0ICogbGVuICkgLyBzaW47XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRjb25zdCB0RGlyID0gdCAqIGRpcjtcclxuXHJcblx0XHRcdHgwID0geDAgKiBzICsgeDEgKiB0RGlyO1xyXG5cdFx0XHR5MCA9IHkwICogcyArIHkxICogdERpcjtcclxuXHRcdFx0ejAgPSB6MCAqIHMgKyB6MSAqIHREaXI7XHJcblx0XHRcdHcwID0gdzAgKiBzICsgdzEgKiB0RGlyO1xyXG5cclxuXHRcdFx0Ly8gTm9ybWFsaXplIGluIGNhc2Ugd2UganVzdCBkaWQgYSBsZXJwOlxyXG5cdFx0XHRpZiAoIHMgPT09IDEgLSB0ICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBmID0gMSAvIE1hdGguc3FydCggeDAgKiB4MCArIHkwICogeTAgKyB6MCAqIHowICsgdzAgKiB3MCApO1xyXG5cclxuXHRcdFx0XHR4MCAqPSBmO1xyXG5cdFx0XHRcdHkwICo9IGY7XHJcblx0XHRcdFx0ejAgKj0gZjtcclxuXHRcdFx0XHR3MCAqPSBmO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRkc3RbIGRzdE9mZnNldCBdID0geDA7XHJcblx0XHRkc3RbIGRzdE9mZnNldCArIDEgXSA9IHkwO1xyXG5cdFx0ZHN0WyBkc3RPZmZzZXQgKyAyIF0gPSB6MDtcclxuXHRcdGRzdFsgZHN0T2Zmc2V0ICsgMyBdID0gdzA7XHJcblxyXG5cdH1cclxuXHJcblx0c3RhdGljIG11bHRpcGx5UXVhdGVybmlvbnNGbGF0KCBkc3QsIGRzdE9mZnNldCwgc3JjMCwgc3JjT2Zmc2V0MCwgc3JjMSwgc3JjT2Zmc2V0MSApIHtcclxuXHJcblx0XHRjb25zdCB4MCA9IHNyYzBbIHNyY09mZnNldDAgXTtcclxuXHRcdGNvbnN0IHkwID0gc3JjMFsgc3JjT2Zmc2V0MCArIDEgXTtcclxuXHRcdGNvbnN0IHowID0gc3JjMFsgc3JjT2Zmc2V0MCArIDIgXTtcclxuXHRcdGNvbnN0IHcwID0gc3JjMFsgc3JjT2Zmc2V0MCArIDMgXTtcclxuXHJcblx0XHRjb25zdCB4MSA9IHNyYzFbIHNyY09mZnNldDEgXTtcclxuXHRcdGNvbnN0IHkxID0gc3JjMVsgc3JjT2Zmc2V0MSArIDEgXTtcclxuXHRcdGNvbnN0IHoxID0gc3JjMVsgc3JjT2Zmc2V0MSArIDIgXTtcclxuXHRcdGNvbnN0IHcxID0gc3JjMVsgc3JjT2Zmc2V0MSArIDMgXTtcclxuXHJcblx0XHRkc3RbIGRzdE9mZnNldCBdID0geDAgKiB3MSArIHcwICogeDEgKyB5MCAqIHoxIC0gejAgKiB5MTtcclxuXHRcdGRzdFsgZHN0T2Zmc2V0ICsgMSBdID0geTAgKiB3MSArIHcwICogeTEgKyB6MCAqIHgxIC0geDAgKiB6MTtcclxuXHRcdGRzdFsgZHN0T2Zmc2V0ICsgMiBdID0gejAgKiB3MSArIHcwICogejEgKyB4MCAqIHkxIC0geTAgKiB4MTtcclxuXHRcdGRzdFsgZHN0T2Zmc2V0ICsgMyBdID0gdzAgKiB3MSAtIHgwICogeDEgLSB5MCAqIHkxIC0gejAgKiB6MTtcclxuXHJcblx0XHRyZXR1cm4gZHN0O1xyXG5cclxuXHR9XHJcblxyXG5cdGdldCB4KCkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLl94O1xyXG5cclxuXHR9XHJcblxyXG5cdHNldCB4KCB2YWx1ZSApIHtcclxuXHJcblx0XHR0aGlzLl94ID0gdmFsdWU7XHJcblx0XHR0aGlzLl9vbkNoYW5nZUNhbGxiYWNrKCk7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0IHkoKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuX3k7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0IHkoIHZhbHVlICkge1xyXG5cclxuXHRcdHRoaXMuX3kgPSB2YWx1ZTtcclxuXHRcdHRoaXMuX29uQ2hhbmdlQ2FsbGJhY2soKTtcclxuXHJcblx0fVxyXG5cclxuXHRnZXQgeigpIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5fejtcclxuXHJcblx0fVxyXG5cclxuXHRzZXQgeiggdmFsdWUgKSB7XHJcblxyXG5cdFx0dGhpcy5feiA9IHZhbHVlO1xyXG5cdFx0dGhpcy5fb25DaGFuZ2VDYWxsYmFjaygpO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldCB3KCkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLl93O1xyXG5cclxuXHR9XHJcblxyXG5cdHNldCB3KCB2YWx1ZSApIHtcclxuXHJcblx0XHR0aGlzLl93ID0gdmFsdWU7XHJcblx0XHR0aGlzLl9vbkNoYW5nZUNhbGxiYWNrKCk7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0KCB4LCB5LCB6LCB3ICkge1xyXG5cclxuXHRcdHRoaXMuX3ggPSB4O1xyXG5cdFx0dGhpcy5feSA9IHk7XHJcblx0XHR0aGlzLl96ID0gejtcclxuXHRcdHRoaXMuX3cgPSB3O1xyXG5cclxuXHRcdHRoaXMuX29uQ2hhbmdlQ2FsbGJhY2soKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRjbG9uZSgpIHtcclxuXHJcblx0XHRyZXR1cm4gbmV3IHRoaXMuY29uc3RydWN0b3IoIHRoaXMuX3gsIHRoaXMuX3ksIHRoaXMuX3osIHRoaXMuX3cgKTtcclxuXHJcblx0fVxyXG5cclxuXHRjb3B5KCBxdWF0ZXJuaW9uICkge1xyXG5cclxuXHRcdHRoaXMuX3ggPSBxdWF0ZXJuaW9uLng7XHJcblx0XHR0aGlzLl95ID0gcXVhdGVybmlvbi55O1xyXG5cdFx0dGhpcy5feiA9IHF1YXRlcm5pb24uejtcclxuXHRcdHRoaXMuX3cgPSBxdWF0ZXJuaW9uLnc7XHJcblxyXG5cdFx0dGhpcy5fb25DaGFuZ2VDYWxsYmFjaygpO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldEZyb21FdWxlciggZXVsZXIsIHVwZGF0ZSA9IHRydWUgKSB7XHJcblxyXG5cdFx0Y29uc3QgeCA9IGV1bGVyLl94LCB5ID0gZXVsZXIuX3ksIHogPSBldWxlci5feiwgb3JkZXIgPSBldWxlci5fb3JkZXI7XHJcblxyXG5cdFx0Ly8gaHR0cDovL3d3dy5tYXRod29ya3MuY29tL21hdGxhYmNlbnRyYWwvZmlsZWV4Y2hhbmdlL1xyXG5cdFx0Ly8gXHQyMDY5Ni1mdW5jdGlvbi10by1jb252ZXJ0LWJldHdlZW4tZGNtLWV1bGVyLWFuZ2xlcy1xdWF0ZXJuaW9ucy1hbmQtZXVsZXItdmVjdG9ycy9cclxuXHRcdC8vXHRjb250ZW50L1NwaW5DYWxjLm1cclxuXHJcblx0XHRjb25zdCBjb3MgPSBNYXRoLmNvcztcclxuXHRcdGNvbnN0IHNpbiA9IE1hdGguc2luO1xyXG5cclxuXHRcdGNvbnN0IGMxID0gY29zKCB4IC8gMiApO1xyXG5cdFx0Y29uc3QgYzIgPSBjb3MoIHkgLyAyICk7XHJcblx0XHRjb25zdCBjMyA9IGNvcyggeiAvIDIgKTtcclxuXHJcblx0XHRjb25zdCBzMSA9IHNpbiggeCAvIDIgKTtcclxuXHRcdGNvbnN0IHMyID0gc2luKCB5IC8gMiApO1xyXG5cdFx0Y29uc3QgczMgPSBzaW4oIHogLyAyICk7XHJcblxyXG5cdFx0c3dpdGNoICggb3JkZXIgKSB7XHJcblxyXG5cdFx0XHRjYXNlICdYWVonOlxyXG5cdFx0XHRcdHRoaXMuX3ggPSBzMSAqIGMyICogYzMgKyBjMSAqIHMyICogczM7XHJcblx0XHRcdFx0dGhpcy5feSA9IGMxICogczIgKiBjMyAtIHMxICogYzIgKiBzMztcclxuXHRcdFx0XHR0aGlzLl96ID0gYzEgKiBjMiAqIHMzICsgczEgKiBzMiAqIGMzO1xyXG5cdFx0XHRcdHRoaXMuX3cgPSBjMSAqIGMyICogYzMgLSBzMSAqIHMyICogczM7XHJcblx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRjYXNlICdZWFonOlxyXG5cdFx0XHRcdHRoaXMuX3ggPSBzMSAqIGMyICogYzMgKyBjMSAqIHMyICogczM7XHJcblx0XHRcdFx0dGhpcy5feSA9IGMxICogczIgKiBjMyAtIHMxICogYzIgKiBzMztcclxuXHRcdFx0XHR0aGlzLl96ID0gYzEgKiBjMiAqIHMzIC0gczEgKiBzMiAqIGMzO1xyXG5cdFx0XHRcdHRoaXMuX3cgPSBjMSAqIGMyICogYzMgKyBzMSAqIHMyICogczM7XHJcblx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRjYXNlICdaWFknOlxyXG5cdFx0XHRcdHRoaXMuX3ggPSBzMSAqIGMyICogYzMgLSBjMSAqIHMyICogczM7XHJcblx0XHRcdFx0dGhpcy5feSA9IGMxICogczIgKiBjMyArIHMxICogYzIgKiBzMztcclxuXHRcdFx0XHR0aGlzLl96ID0gYzEgKiBjMiAqIHMzICsgczEgKiBzMiAqIGMzO1xyXG5cdFx0XHRcdHRoaXMuX3cgPSBjMSAqIGMyICogYzMgLSBzMSAqIHMyICogczM7XHJcblx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRjYXNlICdaWVgnOlxyXG5cdFx0XHRcdHRoaXMuX3ggPSBzMSAqIGMyICogYzMgLSBjMSAqIHMyICogczM7XHJcblx0XHRcdFx0dGhpcy5feSA9IGMxICogczIgKiBjMyArIHMxICogYzIgKiBzMztcclxuXHRcdFx0XHR0aGlzLl96ID0gYzEgKiBjMiAqIHMzIC0gczEgKiBzMiAqIGMzO1xyXG5cdFx0XHRcdHRoaXMuX3cgPSBjMSAqIGMyICogYzMgKyBzMSAqIHMyICogczM7XHJcblx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRjYXNlICdZWlgnOlxyXG5cdFx0XHRcdHRoaXMuX3ggPSBzMSAqIGMyICogYzMgKyBjMSAqIHMyICogczM7XHJcblx0XHRcdFx0dGhpcy5feSA9IGMxICogczIgKiBjMyArIHMxICogYzIgKiBzMztcclxuXHRcdFx0XHR0aGlzLl96ID0gYzEgKiBjMiAqIHMzIC0gczEgKiBzMiAqIGMzO1xyXG5cdFx0XHRcdHRoaXMuX3cgPSBjMSAqIGMyICogYzMgLSBzMSAqIHMyICogczM7XHJcblx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRjYXNlICdYWlknOlxyXG5cdFx0XHRcdHRoaXMuX3ggPSBzMSAqIGMyICogYzMgLSBjMSAqIHMyICogczM7XHJcblx0XHRcdFx0dGhpcy5feSA9IGMxICogczIgKiBjMyAtIHMxICogYzIgKiBzMztcclxuXHRcdFx0XHR0aGlzLl96ID0gYzEgKiBjMiAqIHMzICsgczEgKiBzMiAqIGMzO1xyXG5cdFx0XHRcdHRoaXMuX3cgPSBjMSAqIGMyICogYzMgKyBzMSAqIHMyICogczM7XHJcblx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRkZWZhdWx0OlxyXG5cdFx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLlF1YXRlcm5pb246IC5zZXRGcm9tRXVsZXIoKSBlbmNvdW50ZXJlZCBhbiB1bmtub3duIG9yZGVyOiAnICsgb3JkZXIgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCB1cGRhdGUgPT09IHRydWUgKSB0aGlzLl9vbkNoYW5nZUNhbGxiYWNrKCk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0RnJvbUF4aXNBbmdsZSggYXhpcywgYW5nbGUgKSB7XHJcblxyXG5cdFx0Ly8gaHR0cDovL3d3dy5ldWNsaWRlYW5zcGFjZS5jb20vbWF0aHMvZ2VvbWV0cnkvcm90YXRpb25zL2NvbnZlcnNpb25zL2FuZ2xlVG9RdWF0ZXJuaW9uL2luZGV4Lmh0bVxyXG5cclxuXHRcdC8vIGFzc3VtZXMgYXhpcyBpcyBub3JtYWxpemVkXHJcblxyXG5cdFx0Y29uc3QgaGFsZkFuZ2xlID0gYW5nbGUgLyAyLCBzID0gTWF0aC5zaW4oIGhhbGZBbmdsZSApO1xyXG5cclxuXHRcdHRoaXMuX3ggPSBheGlzLnggKiBzO1xyXG5cdFx0dGhpcy5feSA9IGF4aXMueSAqIHM7XHJcblx0XHR0aGlzLl96ID0gYXhpcy56ICogcztcclxuXHRcdHRoaXMuX3cgPSBNYXRoLmNvcyggaGFsZkFuZ2xlICk7XHJcblxyXG5cdFx0dGhpcy5fb25DaGFuZ2VDYWxsYmFjaygpO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldEZyb21Sb3RhdGlvbk1hdHJpeCggbSApIHtcclxuXHJcblx0XHQvLyBodHRwOi8vd3d3LmV1Y2xpZGVhbnNwYWNlLmNvbS9tYXRocy9nZW9tZXRyeS9yb3RhdGlvbnMvY29udmVyc2lvbnMvbWF0cml4VG9RdWF0ZXJuaW9uL2luZGV4Lmh0bVxyXG5cclxuXHRcdC8vIGFzc3VtZXMgdGhlIHVwcGVyIDN4MyBvZiBtIGlzIGEgcHVyZSByb3RhdGlvbiBtYXRyaXggKGkuZSwgdW5zY2FsZWQpXHJcblxyXG5cdFx0Y29uc3QgdGUgPSBtLmVsZW1lbnRzLFxyXG5cclxuXHRcdFx0bTExID0gdGVbIDAgXSwgbTEyID0gdGVbIDQgXSwgbTEzID0gdGVbIDggXSxcclxuXHRcdFx0bTIxID0gdGVbIDEgXSwgbTIyID0gdGVbIDUgXSwgbTIzID0gdGVbIDkgXSxcclxuXHRcdFx0bTMxID0gdGVbIDIgXSwgbTMyID0gdGVbIDYgXSwgbTMzID0gdGVbIDEwIF0sXHJcblxyXG5cdFx0XHR0cmFjZSA9IG0xMSArIG0yMiArIG0zMztcclxuXHJcblx0XHRpZiAoIHRyYWNlID4gMCApIHtcclxuXHJcblx0XHRcdGNvbnN0IHMgPSAwLjUgLyBNYXRoLnNxcnQoIHRyYWNlICsgMS4wICk7XHJcblxyXG5cdFx0XHR0aGlzLl93ID0gMC4yNSAvIHM7XHJcblx0XHRcdHRoaXMuX3ggPSAoIG0zMiAtIG0yMyApICogcztcclxuXHRcdFx0dGhpcy5feSA9ICggbTEzIC0gbTMxICkgKiBzO1xyXG5cdFx0XHR0aGlzLl96ID0gKCBtMjEgLSBtMTIgKSAqIHM7XHJcblxyXG5cdFx0fSBlbHNlIGlmICggbTExID4gbTIyICYmIG0xMSA+IG0zMyApIHtcclxuXHJcblx0XHRcdGNvbnN0IHMgPSAyLjAgKiBNYXRoLnNxcnQoIDEuMCArIG0xMSAtIG0yMiAtIG0zMyApO1xyXG5cclxuXHRcdFx0dGhpcy5fdyA9ICggbTMyIC0gbTIzICkgLyBzO1xyXG5cdFx0XHR0aGlzLl94ID0gMC4yNSAqIHM7XHJcblx0XHRcdHRoaXMuX3kgPSAoIG0xMiArIG0yMSApIC8gcztcclxuXHRcdFx0dGhpcy5feiA9ICggbTEzICsgbTMxICkgLyBzO1xyXG5cclxuXHRcdH0gZWxzZSBpZiAoIG0yMiA+IG0zMyApIHtcclxuXHJcblx0XHRcdGNvbnN0IHMgPSAyLjAgKiBNYXRoLnNxcnQoIDEuMCArIG0yMiAtIG0xMSAtIG0zMyApO1xyXG5cclxuXHRcdFx0dGhpcy5fdyA9ICggbTEzIC0gbTMxICkgLyBzO1xyXG5cdFx0XHR0aGlzLl94ID0gKCBtMTIgKyBtMjEgKSAvIHM7XHJcblx0XHRcdHRoaXMuX3kgPSAwLjI1ICogcztcclxuXHRcdFx0dGhpcy5feiA9ICggbTIzICsgbTMyICkgLyBzO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRjb25zdCBzID0gMi4wICogTWF0aC5zcXJ0KCAxLjAgKyBtMzMgLSBtMTEgLSBtMjIgKTtcclxuXHJcblx0XHRcdHRoaXMuX3cgPSAoIG0yMSAtIG0xMiApIC8gcztcclxuXHRcdFx0dGhpcy5feCA9ICggbTEzICsgbTMxICkgLyBzO1xyXG5cdFx0XHR0aGlzLl95ID0gKCBtMjMgKyBtMzIgKSAvIHM7XHJcblx0XHRcdHRoaXMuX3ogPSAwLjI1ICogcztcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5fb25DaGFuZ2VDYWxsYmFjaygpO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldEZyb21Vbml0VmVjdG9ycyggdkZyb20sIHZUbyApIHtcclxuXHJcblx0XHQvLyBhc3N1bWVzIGRpcmVjdGlvbiB2ZWN0b3JzIHZGcm9tIGFuZCB2VG8gYXJlIG5vcm1hbGl6ZWRcclxuXHJcblx0XHRsZXQgciA9IHZGcm9tLmRvdCggdlRvICkgKyAxO1xyXG5cclxuXHRcdGlmICggciA8IE51bWJlci5FUFNJTE9OICkge1xyXG5cclxuXHRcdFx0Ly8gdkZyb20gYW5kIHZUbyBwb2ludCBpbiBvcHBvc2l0ZSBkaXJlY3Rpb25zXHJcblxyXG5cdFx0XHRyID0gMDtcclxuXHJcblx0XHRcdGlmICggTWF0aC5hYnMoIHZGcm9tLnggKSA+IE1hdGguYWJzKCB2RnJvbS56ICkgKSB7XHJcblxyXG5cdFx0XHRcdHRoaXMuX3ggPSAtIHZGcm9tLnk7XHJcblx0XHRcdFx0dGhpcy5feSA9IHZGcm9tLng7XHJcblx0XHRcdFx0dGhpcy5feiA9IDA7XHJcblx0XHRcdFx0dGhpcy5fdyA9IHI7XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHR0aGlzLl94ID0gMDtcclxuXHRcdFx0XHR0aGlzLl95ID0gLSB2RnJvbS56O1xyXG5cdFx0XHRcdHRoaXMuX3ogPSB2RnJvbS55O1xyXG5cdFx0XHRcdHRoaXMuX3cgPSByO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHQvLyBjcm9zc1ZlY3RvcnMoIHZGcm9tLCB2VG8gKTsgLy8gaW5saW5lZCB0byBhdm9pZCBjeWNsaWMgZGVwZW5kZW5jeSBvbiBWZWN0b3IzXHJcblxyXG5cdFx0XHR0aGlzLl94ID0gdkZyb20ueSAqIHZUby56IC0gdkZyb20ueiAqIHZUby55O1xyXG5cdFx0XHR0aGlzLl95ID0gdkZyb20ueiAqIHZUby54IC0gdkZyb20ueCAqIHZUby56O1xyXG5cdFx0XHR0aGlzLl96ID0gdkZyb20ueCAqIHZUby55IC0gdkZyb20ueSAqIHZUby54O1xyXG5cdFx0XHR0aGlzLl93ID0gcjtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMubm9ybWFsaXplKCk7XHJcblxyXG5cdH1cclxuXHJcblx0YW5nbGVUbyggcSApIHtcclxuXHJcblx0XHRyZXR1cm4gMiAqIE1hdGguYWNvcyggTWF0aC5hYnMoIE1hdGhVdGlscy5jbGFtcCggdGhpcy5kb3QoIHEgKSwgLSAxLCAxICkgKSApO1xyXG5cclxuXHR9XHJcblxyXG5cdHJvdGF0ZVRvd2FyZHMoIHEsIHN0ZXAgKSB7XHJcblxyXG5cdFx0Y29uc3QgYW5nbGUgPSB0aGlzLmFuZ2xlVG8oIHEgKTtcclxuXHJcblx0XHRpZiAoIGFuZ2xlID09PSAwICkgcmV0dXJuIHRoaXM7XHJcblxyXG5cdFx0Y29uc3QgdCA9IE1hdGgubWluKCAxLCBzdGVwIC8gYW5nbGUgKTtcclxuXHJcblx0XHR0aGlzLnNsZXJwKCBxLCB0ICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0aWRlbnRpdHkoKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuc2V0KCAwLCAwLCAwLCAxICk7XHJcblxyXG5cdH1cclxuXHJcblx0aW52ZXJ0KCkge1xyXG5cclxuXHRcdC8vIHF1YXRlcm5pb24gaXMgYXNzdW1lZCB0byBoYXZlIHVuaXQgbGVuZ3RoXHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuY29uanVnYXRlKCk7XHJcblxyXG5cdH1cclxuXHJcblx0Y29uanVnYXRlKCkge1xyXG5cclxuXHRcdHRoaXMuX3ggKj0gLSAxO1xyXG5cdFx0dGhpcy5feSAqPSAtIDE7XHJcblx0XHR0aGlzLl96ICo9IC0gMTtcclxuXHJcblx0XHR0aGlzLl9vbkNoYW5nZUNhbGxiYWNrKCk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0ZG90KCB2ICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLl94ICogdi5feCArIHRoaXMuX3kgKiB2Ll95ICsgdGhpcy5feiAqIHYuX3ogKyB0aGlzLl93ICogdi5fdztcclxuXHJcblx0fVxyXG5cclxuXHRsZW5ndGhTcSgpIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5feCAqIHRoaXMuX3ggKyB0aGlzLl95ICogdGhpcy5feSArIHRoaXMuX3ogKiB0aGlzLl96ICsgdGhpcy5fdyAqIHRoaXMuX3c7XHJcblxyXG5cdH1cclxuXHJcblx0bGVuZ3RoKCkge1xyXG5cclxuXHRcdHJldHVybiBNYXRoLnNxcnQoIHRoaXMuX3ggKiB0aGlzLl94ICsgdGhpcy5feSAqIHRoaXMuX3kgKyB0aGlzLl96ICogdGhpcy5feiArIHRoaXMuX3cgKiB0aGlzLl93ICk7XHJcblxyXG5cdH1cclxuXHJcblx0bm9ybWFsaXplKCkge1xyXG5cclxuXHRcdGxldCBsID0gdGhpcy5sZW5ndGgoKTtcclxuXHJcblx0XHRpZiAoIGwgPT09IDAgKSB7XHJcblxyXG5cdFx0XHR0aGlzLl94ID0gMDtcclxuXHRcdFx0dGhpcy5feSA9IDA7XHJcblx0XHRcdHRoaXMuX3ogPSAwO1xyXG5cdFx0XHR0aGlzLl93ID0gMTtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0bCA9IDEgLyBsO1xyXG5cclxuXHRcdFx0dGhpcy5feCA9IHRoaXMuX3ggKiBsO1xyXG5cdFx0XHR0aGlzLl95ID0gdGhpcy5feSAqIGw7XHJcblx0XHRcdHRoaXMuX3ogPSB0aGlzLl96ICogbDtcclxuXHRcdFx0dGhpcy5fdyA9IHRoaXMuX3cgKiBsO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLl9vbkNoYW5nZUNhbGxiYWNrKCk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0bXVsdGlwbHkoIHEgKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMubXVsdGlwbHlRdWF0ZXJuaW9ucyggdGhpcywgcSApO1xyXG5cclxuXHR9XHJcblxyXG5cdHByZW11bHRpcGx5KCBxICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLm11bHRpcGx5UXVhdGVybmlvbnMoIHEsIHRoaXMgKTtcclxuXHJcblx0fVxyXG5cclxuXHRtdWx0aXBseVF1YXRlcm5pb25zKCBhLCBiICkge1xyXG5cclxuXHRcdC8vIGZyb20gaHR0cDovL3d3dy5ldWNsaWRlYW5zcGFjZS5jb20vbWF0aHMvYWxnZWJyYS9yZWFsTm9ybWVkQWxnZWJyYS9xdWF0ZXJuaW9ucy9jb2RlL2luZGV4Lmh0bVxyXG5cclxuXHRcdGNvbnN0IHFheCA9IGEuX3gsIHFheSA9IGEuX3ksIHFheiA9IGEuX3osIHFhdyA9IGEuX3c7XHJcblx0XHRjb25zdCBxYnggPSBiLl94LCBxYnkgPSBiLl95LCBxYnogPSBiLl96LCBxYncgPSBiLl93O1xyXG5cclxuXHRcdHRoaXMuX3ggPSBxYXggKiBxYncgKyBxYXcgKiBxYnggKyBxYXkgKiBxYnogLSBxYXogKiBxYnk7XHJcblx0XHR0aGlzLl95ID0gcWF5ICogcWJ3ICsgcWF3ICogcWJ5ICsgcWF6ICogcWJ4IC0gcWF4ICogcWJ6O1xyXG5cdFx0dGhpcy5feiA9IHFheiAqIHFidyArIHFhdyAqIHFieiArIHFheCAqIHFieSAtIHFheSAqIHFieDtcclxuXHRcdHRoaXMuX3cgPSBxYXcgKiBxYncgLSBxYXggKiBxYnggLSBxYXkgKiBxYnkgLSBxYXogKiBxYno7XHJcblxyXG5cdFx0dGhpcy5fb25DaGFuZ2VDYWxsYmFjaygpO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNsZXJwKCBxYiwgdCApIHtcclxuXHJcblx0XHRpZiAoIHQgPT09IDAgKSByZXR1cm4gdGhpcztcclxuXHRcdGlmICggdCA9PT0gMSApIHJldHVybiB0aGlzLmNvcHkoIHFiICk7XHJcblxyXG5cdFx0Y29uc3QgeCA9IHRoaXMuX3gsIHkgPSB0aGlzLl95LCB6ID0gdGhpcy5feiwgdyA9IHRoaXMuX3c7XHJcblxyXG5cdFx0Ly8gaHR0cDovL3d3dy5ldWNsaWRlYW5zcGFjZS5jb20vbWF0aHMvYWxnZWJyYS9yZWFsTm9ybWVkQWxnZWJyYS9xdWF0ZXJuaW9ucy9zbGVycC9cclxuXHJcblx0XHRsZXQgY29zSGFsZlRoZXRhID0gdyAqIHFiLl93ICsgeCAqIHFiLl94ICsgeSAqIHFiLl95ICsgeiAqIHFiLl96O1xyXG5cclxuXHRcdGlmICggY29zSGFsZlRoZXRhIDwgMCApIHtcclxuXHJcblx0XHRcdHRoaXMuX3cgPSAtIHFiLl93O1xyXG5cdFx0XHR0aGlzLl94ID0gLSBxYi5feDtcclxuXHRcdFx0dGhpcy5feSA9IC0gcWIuX3k7XHJcblx0XHRcdHRoaXMuX3ogPSAtIHFiLl96O1xyXG5cclxuXHRcdFx0Y29zSGFsZlRoZXRhID0gLSBjb3NIYWxmVGhldGE7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdHRoaXMuY29weSggcWIgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBjb3NIYWxmVGhldGEgPj0gMS4wICkge1xyXG5cclxuXHRcdFx0dGhpcy5fdyA9IHc7XHJcblx0XHRcdHRoaXMuX3ggPSB4O1xyXG5cdFx0XHR0aGlzLl95ID0geTtcclxuXHRcdFx0dGhpcy5feiA9IHo7XHJcblxyXG5cdFx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Y29uc3Qgc3FyU2luSGFsZlRoZXRhID0gMS4wIC0gY29zSGFsZlRoZXRhICogY29zSGFsZlRoZXRhO1xyXG5cclxuXHRcdGlmICggc3FyU2luSGFsZlRoZXRhIDw9IE51bWJlci5FUFNJTE9OICkge1xyXG5cclxuXHRcdFx0Y29uc3QgcyA9IDEgLSB0O1xyXG5cdFx0XHR0aGlzLl93ID0gcyAqIHcgKyB0ICogdGhpcy5fdztcclxuXHRcdFx0dGhpcy5feCA9IHMgKiB4ICsgdCAqIHRoaXMuX3g7XHJcblx0XHRcdHRoaXMuX3kgPSBzICogeSArIHQgKiB0aGlzLl95O1xyXG5cdFx0XHR0aGlzLl96ID0gcyAqIHogKyB0ICogdGhpcy5fejtcclxuXHJcblx0XHRcdHRoaXMubm9ybWFsaXplKCk7IC8vIG5vcm1hbGl6ZSBjYWxscyBfb25DaGFuZ2VDYWxsYmFjaygpXHJcblxyXG5cdFx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Y29uc3Qgc2luSGFsZlRoZXRhID0gTWF0aC5zcXJ0KCBzcXJTaW5IYWxmVGhldGEgKTtcclxuXHRcdGNvbnN0IGhhbGZUaGV0YSA9IE1hdGguYXRhbjIoIHNpbkhhbGZUaGV0YSwgY29zSGFsZlRoZXRhICk7XHJcblx0XHRjb25zdCByYXRpb0EgPSBNYXRoLnNpbiggKCAxIC0gdCApICogaGFsZlRoZXRhICkgLyBzaW5IYWxmVGhldGEsXHJcblx0XHRcdHJhdGlvQiA9IE1hdGguc2luKCB0ICogaGFsZlRoZXRhICkgLyBzaW5IYWxmVGhldGE7XHJcblxyXG5cdFx0dGhpcy5fdyA9ICggdyAqIHJhdGlvQSArIHRoaXMuX3cgKiByYXRpb0IgKTtcclxuXHRcdHRoaXMuX3ggPSAoIHggKiByYXRpb0EgKyB0aGlzLl94ICogcmF0aW9CICk7XHJcblx0XHR0aGlzLl95ID0gKCB5ICogcmF0aW9BICsgdGhpcy5feSAqIHJhdGlvQiApO1xyXG5cdFx0dGhpcy5feiA9ICggeiAqIHJhdGlvQSArIHRoaXMuX3ogKiByYXRpb0IgKTtcclxuXHJcblx0XHR0aGlzLl9vbkNoYW5nZUNhbGxiYWNrKCk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0c2xlcnBRdWF0ZXJuaW9ucyggcWEsIHFiLCB0ICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLmNvcHkoIHFhICkuc2xlcnAoIHFiLCB0ICk7XHJcblxyXG5cdH1cclxuXHJcblx0cmFuZG9tKCkge1xyXG5cclxuXHRcdC8vIERlcml2ZWQgZnJvbSBodHRwOi8vcGxhbm5pbmcuY3MudWl1Yy5lZHUvbm9kZTE5OC5odG1sXHJcblx0XHQvLyBOb3RlLCB0aGlzIHNvdXJjZSB1c2VzIHcsIHgsIHksIHogb3JkZXJpbmcsXHJcblx0XHQvLyBzbyB3ZSBzd2FwIHRoZSBvcmRlciBiZWxvdy5cclxuXHJcblx0XHRjb25zdCB1MSA9IE1hdGgucmFuZG9tKCk7XHJcblx0XHRjb25zdCBzcXJ0MXUxID0gTWF0aC5zcXJ0KCAxIC0gdTEgKTtcclxuXHRcdGNvbnN0IHNxcnR1MSA9IE1hdGguc3FydCggdTEgKTtcclxuXHJcblx0XHRjb25zdCB1MiA9IDIgKiBNYXRoLlBJICogTWF0aC5yYW5kb20oKTtcclxuXHJcblx0XHRjb25zdCB1MyA9IDIgKiBNYXRoLlBJICogTWF0aC5yYW5kb20oKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5zZXQoXHJcblx0XHRcdHNxcnQxdTEgKiBNYXRoLmNvcyggdTIgKSxcclxuXHRcdFx0c3FydHUxICogTWF0aC5zaW4oIHUzICksXHJcblx0XHRcdHNxcnR1MSAqIE1hdGguY29zKCB1MyApLFxyXG5cdFx0XHRzcXJ0MXUxICogTWF0aC5zaW4oIHUyICksXHJcblx0XHQpO1xyXG5cclxuXHR9XHJcblxyXG5cdGVxdWFscyggcXVhdGVybmlvbiApIHtcclxuXHJcblx0XHRyZXR1cm4gKCBxdWF0ZXJuaW9uLl94ID09PSB0aGlzLl94ICkgJiYgKCBxdWF0ZXJuaW9uLl95ID09PSB0aGlzLl95ICkgJiYgKCBxdWF0ZXJuaW9uLl96ID09PSB0aGlzLl96ICkgJiYgKCBxdWF0ZXJuaW9uLl93ID09PSB0aGlzLl93ICk7XHJcblxyXG5cdH1cclxuXHJcblx0ZnJvbUFycmF5KCBhcnJheSwgb2Zmc2V0ID0gMCApIHtcclxuXHJcblx0XHR0aGlzLl94ID0gYXJyYXlbIG9mZnNldCBdO1xyXG5cdFx0dGhpcy5feSA9IGFycmF5WyBvZmZzZXQgKyAxIF07XHJcblx0XHR0aGlzLl96ID0gYXJyYXlbIG9mZnNldCArIDIgXTtcclxuXHRcdHRoaXMuX3cgPSBhcnJheVsgb2Zmc2V0ICsgMyBdO1xyXG5cclxuXHRcdHRoaXMuX29uQ2hhbmdlQ2FsbGJhY2soKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHR0b0FycmF5KCBhcnJheSA9IFtdLCBvZmZzZXQgPSAwICkge1xyXG5cclxuXHRcdGFycmF5WyBvZmZzZXQgXSA9IHRoaXMuX3g7XHJcblx0XHRhcnJheVsgb2Zmc2V0ICsgMSBdID0gdGhpcy5feTtcclxuXHRcdGFycmF5WyBvZmZzZXQgKyAyIF0gPSB0aGlzLl96O1xyXG5cdFx0YXJyYXlbIG9mZnNldCArIDMgXSA9IHRoaXMuX3c7XHJcblxyXG5cdFx0cmV0dXJuIGFycmF5O1xyXG5cclxuXHR9XHJcblxyXG5cdGZyb21CdWZmZXJBdHRyaWJ1dGUoIGF0dHJpYnV0ZSwgaW5kZXggKSB7XHJcblxyXG5cdFx0dGhpcy5feCA9IGF0dHJpYnV0ZS5nZXRYKCBpbmRleCApO1xyXG5cdFx0dGhpcy5feSA9IGF0dHJpYnV0ZS5nZXRZKCBpbmRleCApO1xyXG5cdFx0dGhpcy5feiA9IGF0dHJpYnV0ZS5nZXRaKCBpbmRleCApO1xyXG5cdFx0dGhpcy5fdyA9IGF0dHJpYnV0ZS5nZXRXKCBpbmRleCApO1xyXG5cclxuXHRcdHRoaXMuX29uQ2hhbmdlQ2FsbGJhY2soKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHR0b0pTT04oKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMudG9BcnJheSgpO1xyXG5cclxuXHR9XHJcblxyXG5cdF9vbkNoYW5nZSggY2FsbGJhY2sgKSB7XHJcblxyXG5cdFx0dGhpcy5fb25DaGFuZ2VDYWxsYmFjayA9IGNhbGxiYWNrO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdF9vbkNoYW5nZUNhbGxiYWNrKCkge31cclxuXHJcblx0KlsgU3ltYm9sLml0ZXJhdG9yIF0oKSB7XHJcblxyXG5cdFx0eWllbGQgdGhpcy5feDtcclxuXHRcdHlpZWxkIHRoaXMuX3k7XHJcblx0XHR5aWVsZCB0aGlzLl96O1xyXG5cdFx0eWllbGQgdGhpcy5fdztcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgUXVhdGVybmlvbiB9O1xyXG4iLCJpbXBvcnQgKiBhcyBNYXRoVXRpbHMgZnJvbSAnLi9NYXRoVXRpbHMuanMnO1xyXG5pbXBvcnQgeyBRdWF0ZXJuaW9uIH0gZnJvbSAnLi9RdWF0ZXJuaW9uLmpzJztcclxuXHJcbmNsYXNzIFZlY3RvcjMge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggeCA9IDAsIHkgPSAwLCB6ID0gMCApIHtcclxuXHJcblx0XHRWZWN0b3IzLnByb3RvdHlwZS5pc1ZlY3RvcjMgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMueCA9IHg7XHJcblx0XHR0aGlzLnkgPSB5O1xyXG5cdFx0dGhpcy56ID0gejtcclxuXHJcblx0fVxyXG5cclxuXHRzZXQoIHgsIHksIHogKSB7XHJcblxyXG5cdFx0aWYgKCB6ID09PSB1bmRlZmluZWQgKSB6ID0gdGhpcy56OyAvLyBzcHJpdGUuc2NhbGUuc2V0KHgseSlcclxuXHJcblx0XHR0aGlzLnggPSB4O1xyXG5cdFx0dGhpcy55ID0geTtcclxuXHRcdHRoaXMueiA9IHo7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0U2NhbGFyKCBzY2FsYXIgKSB7XHJcblxyXG5cdFx0dGhpcy54ID0gc2NhbGFyO1xyXG5cdFx0dGhpcy55ID0gc2NhbGFyO1xyXG5cdFx0dGhpcy56ID0gc2NhbGFyO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldFgoIHggKSB7XHJcblxyXG5cdFx0dGhpcy54ID0geDtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRZKCB5ICkge1xyXG5cclxuXHRcdHRoaXMueSA9IHk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0WiggeiApIHtcclxuXHJcblx0XHR0aGlzLnogPSB6O1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldENvbXBvbmVudCggaW5kZXgsIHZhbHVlICkge1xyXG5cclxuXHRcdHN3aXRjaCAoIGluZGV4ICkge1xyXG5cclxuXHRcdFx0Y2FzZSAwOiB0aGlzLnggPSB2YWx1ZTsgYnJlYWs7XHJcblx0XHRcdGNhc2UgMTogdGhpcy55ID0gdmFsdWU7IGJyZWFrO1xyXG5cdFx0XHRjYXNlIDI6IHRoaXMueiA9IHZhbHVlOyBicmVhaztcclxuXHRcdFx0ZGVmYXVsdDogdGhyb3cgbmV3IEVycm9yKCAnaW5kZXggaXMgb3V0IG9mIHJhbmdlOiAnICsgaW5kZXggKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0Q29tcG9uZW50KCBpbmRleCApIHtcclxuXHJcblx0XHRzd2l0Y2ggKCBpbmRleCApIHtcclxuXHJcblx0XHRcdGNhc2UgMDogcmV0dXJuIHRoaXMueDtcclxuXHRcdFx0Y2FzZSAxOiByZXR1cm4gdGhpcy55O1xyXG5cdFx0XHRjYXNlIDI6IHJldHVybiB0aGlzLno7XHJcblx0XHRcdGRlZmF1bHQ6IHRocm93IG5ldyBFcnJvciggJ2luZGV4IGlzIG91dCBvZiByYW5nZTogJyArIGluZGV4ICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGNsb25lKCkge1xyXG5cclxuXHRcdHJldHVybiBuZXcgdGhpcy5jb25zdHJ1Y3RvciggdGhpcy54LCB0aGlzLnksIHRoaXMueiApO1xyXG5cclxuXHR9XHJcblxyXG5cdGNvcHkoIHYgKSB7XHJcblxyXG5cdFx0dGhpcy54ID0gdi54O1xyXG5cdFx0dGhpcy55ID0gdi55O1xyXG5cdFx0dGhpcy56ID0gdi56O1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGFkZCggdiApIHtcclxuXHJcblx0XHR0aGlzLnggKz0gdi54O1xyXG5cdFx0dGhpcy55ICs9IHYueTtcclxuXHRcdHRoaXMueiArPSB2Lno7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0YWRkU2NhbGFyKCBzICkge1xyXG5cclxuXHRcdHRoaXMueCArPSBzO1xyXG5cdFx0dGhpcy55ICs9IHM7XHJcblx0XHR0aGlzLnogKz0gcztcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRhZGRWZWN0b3JzKCBhLCBiICkge1xyXG5cclxuXHRcdHRoaXMueCA9IGEueCArIGIueDtcclxuXHRcdHRoaXMueSA9IGEueSArIGIueTtcclxuXHRcdHRoaXMueiA9IGEueiArIGIuejtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRhZGRTY2FsZWRWZWN0b3IoIHYsIHMgKSB7XHJcblxyXG5cdFx0dGhpcy54ICs9IHYueCAqIHM7XHJcblx0XHR0aGlzLnkgKz0gdi55ICogcztcclxuXHRcdHRoaXMueiArPSB2LnogKiBzO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHN1YiggdiApIHtcclxuXHJcblx0XHR0aGlzLnggLT0gdi54O1xyXG5cdFx0dGhpcy55IC09IHYueTtcclxuXHRcdHRoaXMueiAtPSB2Lno7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0c3ViU2NhbGFyKCBzICkge1xyXG5cclxuXHRcdHRoaXMueCAtPSBzO1xyXG5cdFx0dGhpcy55IC09IHM7XHJcblx0XHR0aGlzLnogLT0gcztcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzdWJWZWN0b3JzKCBhLCBiICkge1xyXG5cclxuXHRcdHRoaXMueCA9IGEueCAtIGIueDtcclxuXHRcdHRoaXMueSA9IGEueSAtIGIueTtcclxuXHRcdHRoaXMueiA9IGEueiAtIGIuejtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRtdWx0aXBseSggdiApIHtcclxuXHJcblx0XHR0aGlzLnggKj0gdi54O1xyXG5cdFx0dGhpcy55ICo9IHYueTtcclxuXHRcdHRoaXMueiAqPSB2Lno7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0bXVsdGlwbHlTY2FsYXIoIHNjYWxhciApIHtcclxuXHJcblx0XHR0aGlzLnggKj0gc2NhbGFyO1xyXG5cdFx0dGhpcy55ICo9IHNjYWxhcjtcclxuXHRcdHRoaXMueiAqPSBzY2FsYXI7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0bXVsdGlwbHlWZWN0b3JzKCBhLCBiICkge1xyXG5cclxuXHRcdHRoaXMueCA9IGEueCAqIGIueDtcclxuXHRcdHRoaXMueSA9IGEueSAqIGIueTtcclxuXHRcdHRoaXMueiA9IGEueiAqIGIuejtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRhcHBseUV1bGVyKCBldWxlciApIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5hcHBseVF1YXRlcm5pb24oIF9xdWF0ZXJuaW9uLnNldEZyb21FdWxlciggZXVsZXIgKSApO1xyXG5cclxuXHR9XHJcblxyXG5cdGFwcGx5QXhpc0FuZ2xlKCBheGlzLCBhbmdsZSApIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5hcHBseVF1YXRlcm5pb24oIF9xdWF0ZXJuaW9uLnNldEZyb21BeGlzQW5nbGUoIGF4aXMsIGFuZ2xlICkgKTtcclxuXHJcblx0fVxyXG5cclxuXHRhcHBseU1hdHJpeDMoIG0gKSB7XHJcblxyXG5cdFx0Y29uc3QgeCA9IHRoaXMueCwgeSA9IHRoaXMueSwgeiA9IHRoaXMuejtcclxuXHRcdGNvbnN0IGUgPSBtLmVsZW1lbnRzO1xyXG5cclxuXHRcdHRoaXMueCA9IGVbIDAgXSAqIHggKyBlWyAzIF0gKiB5ICsgZVsgNiBdICogejtcclxuXHRcdHRoaXMueSA9IGVbIDEgXSAqIHggKyBlWyA0IF0gKiB5ICsgZVsgNyBdICogejtcclxuXHRcdHRoaXMueiA9IGVbIDIgXSAqIHggKyBlWyA1IF0gKiB5ICsgZVsgOCBdICogejtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRhcHBseU5vcm1hbE1hdHJpeCggbSApIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5hcHBseU1hdHJpeDMoIG0gKS5ub3JtYWxpemUoKTtcclxuXHJcblx0fVxyXG5cclxuXHRhcHBseU1hdHJpeDQoIG0gKSB7XHJcblxyXG5cdFx0Y29uc3QgeCA9IHRoaXMueCwgeSA9IHRoaXMueSwgeiA9IHRoaXMuejtcclxuXHRcdGNvbnN0IGUgPSBtLmVsZW1lbnRzO1xyXG5cclxuXHRcdGNvbnN0IHcgPSAxIC8gKCBlWyAzIF0gKiB4ICsgZVsgNyBdICogeSArIGVbIDExIF0gKiB6ICsgZVsgMTUgXSApO1xyXG5cclxuXHRcdHRoaXMueCA9ICggZVsgMCBdICogeCArIGVbIDQgXSAqIHkgKyBlWyA4IF0gKiB6ICsgZVsgMTIgXSApICogdztcclxuXHRcdHRoaXMueSA9ICggZVsgMSBdICogeCArIGVbIDUgXSAqIHkgKyBlWyA5IF0gKiB6ICsgZVsgMTMgXSApICogdztcclxuXHRcdHRoaXMueiA9ICggZVsgMiBdICogeCArIGVbIDYgXSAqIHkgKyBlWyAxMCBdICogeiArIGVbIDE0IF0gKSAqIHc7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0YXBwbHlRdWF0ZXJuaW9uKCBxICkge1xyXG5cclxuXHRcdC8vIHF1YXRlcm5pb24gcSBpcyBhc3N1bWVkIHRvIGhhdmUgdW5pdCBsZW5ndGhcclxuXHJcblx0XHRjb25zdCB2eCA9IHRoaXMueCwgdnkgPSB0aGlzLnksIHZ6ID0gdGhpcy56O1xyXG5cdFx0Y29uc3QgcXggPSBxLngsIHF5ID0gcS55LCBxeiA9IHEueiwgcXcgPSBxLnc7XHJcblxyXG5cdFx0Ly8gdCA9IDIgKiBjcm9zcyggcS54eXosIHYgKTtcclxuXHRcdGNvbnN0IHR4ID0gMiAqICggcXkgKiB2eiAtIHF6ICogdnkgKTtcclxuXHRcdGNvbnN0IHR5ID0gMiAqICggcXogKiB2eCAtIHF4ICogdnogKTtcclxuXHRcdGNvbnN0IHR6ID0gMiAqICggcXggKiB2eSAtIHF5ICogdnggKTtcclxuXHJcblx0XHQvLyB2ICsgcS53ICogdCArIGNyb3NzKCBxLnh5eiwgdCApO1xyXG5cdFx0dGhpcy54ID0gdnggKyBxdyAqIHR4ICsgcXkgKiB0eiAtIHF6ICogdHk7XHJcblx0XHR0aGlzLnkgPSB2eSArIHF3ICogdHkgKyBxeiAqIHR4IC0gcXggKiB0ejtcclxuXHRcdHRoaXMueiA9IHZ6ICsgcXcgKiB0eiArIHF4ICogdHkgLSBxeSAqIHR4O1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHByb2plY3QoIGNhbWVyYSApIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5hcHBseU1hdHJpeDQoIGNhbWVyYS5tYXRyaXhXb3JsZEludmVyc2UgKS5hcHBseU1hdHJpeDQoIGNhbWVyYS5wcm9qZWN0aW9uTWF0cml4ICk7XHJcblxyXG5cdH1cclxuXHJcblx0dW5wcm9qZWN0KCBjYW1lcmEgKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuYXBwbHlNYXRyaXg0KCBjYW1lcmEucHJvamVjdGlvbk1hdHJpeEludmVyc2UgKS5hcHBseU1hdHJpeDQoIGNhbWVyYS5tYXRyaXhXb3JsZCApO1xyXG5cclxuXHR9XHJcblxyXG5cdHRyYW5zZm9ybURpcmVjdGlvbiggbSApIHtcclxuXHJcblx0XHQvLyBpbnB1dDogVEhSRUUuTWF0cml4NCBhZmZpbmUgbWF0cml4XHJcblx0XHQvLyB2ZWN0b3IgaW50ZXJwcmV0ZWQgYXMgYSBkaXJlY3Rpb25cclxuXHJcblx0XHRjb25zdCB4ID0gdGhpcy54LCB5ID0gdGhpcy55LCB6ID0gdGhpcy56O1xyXG5cdFx0Y29uc3QgZSA9IG0uZWxlbWVudHM7XHJcblxyXG5cdFx0dGhpcy54ID0gZVsgMCBdICogeCArIGVbIDQgXSAqIHkgKyBlWyA4IF0gKiB6O1xyXG5cdFx0dGhpcy55ID0gZVsgMSBdICogeCArIGVbIDUgXSAqIHkgKyBlWyA5IF0gKiB6O1xyXG5cdFx0dGhpcy56ID0gZVsgMiBdICogeCArIGVbIDYgXSAqIHkgKyBlWyAxMCBdICogejtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5ub3JtYWxpemUoKTtcclxuXHJcblx0fVxyXG5cclxuXHRkaXZpZGUoIHYgKSB7XHJcblxyXG5cdFx0dGhpcy54IC89IHYueDtcclxuXHRcdHRoaXMueSAvPSB2Lnk7XHJcblx0XHR0aGlzLnogLz0gdi56O1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGRpdmlkZVNjYWxhciggc2NhbGFyICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLm11bHRpcGx5U2NhbGFyKCAxIC8gc2NhbGFyICk7XHJcblxyXG5cdH1cclxuXHJcblx0bWluKCB2ICkge1xyXG5cclxuXHRcdHRoaXMueCA9IE1hdGgubWluKCB0aGlzLngsIHYueCApO1xyXG5cdFx0dGhpcy55ID0gTWF0aC5taW4oIHRoaXMueSwgdi55ICk7XHJcblx0XHR0aGlzLnogPSBNYXRoLm1pbiggdGhpcy56LCB2LnogKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRtYXgoIHYgKSB7XHJcblxyXG5cdFx0dGhpcy54ID0gTWF0aC5tYXgoIHRoaXMueCwgdi54ICk7XHJcblx0XHR0aGlzLnkgPSBNYXRoLm1heCggdGhpcy55LCB2LnkgKTtcclxuXHRcdHRoaXMueiA9IE1hdGgubWF4KCB0aGlzLnosIHYueiApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGNsYW1wKCBtaW4sIG1heCApIHtcclxuXHJcblx0XHQvLyBhc3N1bWVzIG1pbiA8IG1heCwgY29tcG9uZW50d2lzZVxyXG5cclxuXHRcdHRoaXMueCA9IE1hdGgubWF4KCBtaW4ueCwgTWF0aC5taW4oIG1heC54LCB0aGlzLnggKSApO1xyXG5cdFx0dGhpcy55ID0gTWF0aC5tYXgoIG1pbi55LCBNYXRoLm1pbiggbWF4LnksIHRoaXMueSApICk7XHJcblx0XHR0aGlzLnogPSBNYXRoLm1heCggbWluLnosIE1hdGgubWluKCBtYXgueiwgdGhpcy56ICkgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRjbGFtcFNjYWxhciggbWluVmFsLCBtYXhWYWwgKSB7XHJcblxyXG5cdFx0dGhpcy54ID0gTWF0aC5tYXgoIG1pblZhbCwgTWF0aC5taW4oIG1heFZhbCwgdGhpcy54ICkgKTtcclxuXHRcdHRoaXMueSA9IE1hdGgubWF4KCBtaW5WYWwsIE1hdGgubWluKCBtYXhWYWwsIHRoaXMueSApICk7XHJcblx0XHR0aGlzLnogPSBNYXRoLm1heCggbWluVmFsLCBNYXRoLm1pbiggbWF4VmFsLCB0aGlzLnogKSApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGNsYW1wTGVuZ3RoKCBtaW4sIG1heCApIHtcclxuXHJcblx0XHRjb25zdCBsZW5ndGggPSB0aGlzLmxlbmd0aCgpO1xyXG5cclxuXHRcdHJldHVybiB0aGlzLmRpdmlkZVNjYWxhciggbGVuZ3RoIHx8IDEgKS5tdWx0aXBseVNjYWxhciggTWF0aC5tYXgoIG1pbiwgTWF0aC5taW4oIG1heCwgbGVuZ3RoICkgKSApO1xyXG5cclxuXHR9XHJcblxyXG5cdGZsb29yKCkge1xyXG5cclxuXHRcdHRoaXMueCA9IE1hdGguZmxvb3IoIHRoaXMueCApO1xyXG5cdFx0dGhpcy55ID0gTWF0aC5mbG9vciggdGhpcy55ICk7XHJcblx0XHR0aGlzLnogPSBNYXRoLmZsb29yKCB0aGlzLnogKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRjZWlsKCkge1xyXG5cclxuXHRcdHRoaXMueCA9IE1hdGguY2VpbCggdGhpcy54ICk7XHJcblx0XHR0aGlzLnkgPSBNYXRoLmNlaWwoIHRoaXMueSApO1xyXG5cdFx0dGhpcy56ID0gTWF0aC5jZWlsKCB0aGlzLnogKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRyb3VuZCgpIHtcclxuXHJcblx0XHR0aGlzLnggPSBNYXRoLnJvdW5kKCB0aGlzLnggKTtcclxuXHRcdHRoaXMueSA9IE1hdGgucm91bmQoIHRoaXMueSApO1xyXG5cdFx0dGhpcy56ID0gTWF0aC5yb3VuZCggdGhpcy56ICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0cm91bmRUb1plcm8oKSB7XHJcblxyXG5cdFx0dGhpcy54ID0gTWF0aC50cnVuYyggdGhpcy54ICk7XHJcblx0XHR0aGlzLnkgPSBNYXRoLnRydW5jKCB0aGlzLnkgKTtcclxuXHRcdHRoaXMueiA9IE1hdGgudHJ1bmMoIHRoaXMueiApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdG5lZ2F0ZSgpIHtcclxuXHJcblx0XHR0aGlzLnggPSAtIHRoaXMueDtcclxuXHRcdHRoaXMueSA9IC0gdGhpcy55O1xyXG5cdFx0dGhpcy56ID0gLSB0aGlzLno7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0ZG90KCB2ICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLnggKiB2LnggKyB0aGlzLnkgKiB2LnkgKyB0aGlzLnogKiB2Lno7XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gVE9ETyBsZW5ndGhTcXVhcmVkP1xyXG5cclxuXHRsZW5ndGhTcSgpIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy54ICogdGhpcy54ICsgdGhpcy55ICogdGhpcy55ICsgdGhpcy56ICogdGhpcy56O1xyXG5cclxuXHR9XHJcblxyXG5cdGxlbmd0aCgpIHtcclxuXHJcblx0XHRyZXR1cm4gTWF0aC5zcXJ0KCB0aGlzLnggKiB0aGlzLnggKyB0aGlzLnkgKiB0aGlzLnkgKyB0aGlzLnogKiB0aGlzLnogKTtcclxuXHJcblx0fVxyXG5cclxuXHRtYW5oYXR0YW5MZW5ndGgoKSB7XHJcblxyXG5cdFx0cmV0dXJuIE1hdGguYWJzKCB0aGlzLnggKSArIE1hdGguYWJzKCB0aGlzLnkgKSArIE1hdGguYWJzKCB0aGlzLnogKTtcclxuXHJcblx0fVxyXG5cclxuXHRub3JtYWxpemUoKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuZGl2aWRlU2NhbGFyKCB0aGlzLmxlbmd0aCgpIHx8IDEgKTtcclxuXHJcblx0fVxyXG5cclxuXHRzZXRMZW5ndGgoIGxlbmd0aCApIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5ub3JtYWxpemUoKS5tdWx0aXBseVNjYWxhciggbGVuZ3RoICk7XHJcblxyXG5cdH1cclxuXHJcblx0bGVycCggdiwgYWxwaGEgKSB7XHJcblxyXG5cdFx0dGhpcy54ICs9ICggdi54IC0gdGhpcy54ICkgKiBhbHBoYTtcclxuXHRcdHRoaXMueSArPSAoIHYueSAtIHRoaXMueSApICogYWxwaGE7XHJcblx0XHR0aGlzLnogKz0gKCB2LnogLSB0aGlzLnogKSAqIGFscGhhO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGxlcnBWZWN0b3JzKCB2MSwgdjIsIGFscGhhICkge1xyXG5cclxuXHRcdHRoaXMueCA9IHYxLnggKyAoIHYyLnggLSB2MS54ICkgKiBhbHBoYTtcclxuXHRcdHRoaXMueSA9IHYxLnkgKyAoIHYyLnkgLSB2MS55ICkgKiBhbHBoYTtcclxuXHRcdHRoaXMueiA9IHYxLnogKyAoIHYyLnogLSB2MS56ICkgKiBhbHBoYTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRjcm9zcyggdiApIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5jcm9zc1ZlY3RvcnMoIHRoaXMsIHYgKTtcclxuXHJcblx0fVxyXG5cclxuXHRjcm9zc1ZlY3RvcnMoIGEsIGIgKSB7XHJcblxyXG5cdFx0Y29uc3QgYXggPSBhLngsIGF5ID0gYS55LCBheiA9IGEuejtcclxuXHRcdGNvbnN0IGJ4ID0gYi54LCBieSA9IGIueSwgYnogPSBiLno7XHJcblxyXG5cdFx0dGhpcy54ID0gYXkgKiBieiAtIGF6ICogYnk7XHJcblx0XHR0aGlzLnkgPSBheiAqIGJ4IC0gYXggKiBiejtcclxuXHRcdHRoaXMueiA9IGF4ICogYnkgLSBheSAqIGJ4O1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHByb2plY3RPblZlY3RvciggdiApIHtcclxuXHJcblx0XHRjb25zdCBkZW5vbWluYXRvciA9IHYubGVuZ3RoU3EoKTtcclxuXHJcblx0XHRpZiAoIGRlbm9taW5hdG9yID09PSAwICkgcmV0dXJuIHRoaXMuc2V0KCAwLCAwLCAwICk7XHJcblxyXG5cdFx0Y29uc3Qgc2NhbGFyID0gdi5kb3QoIHRoaXMgKSAvIGRlbm9taW5hdG9yO1xyXG5cclxuXHRcdHJldHVybiB0aGlzLmNvcHkoIHYgKS5tdWx0aXBseVNjYWxhciggc2NhbGFyICk7XHJcblxyXG5cdH1cclxuXHJcblx0cHJvamVjdE9uUGxhbmUoIHBsYW5lTm9ybWFsICkge1xyXG5cclxuXHRcdF92ZWN0b3IuY29weSggdGhpcyApLnByb2plY3RPblZlY3RvciggcGxhbmVOb3JtYWwgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5zdWIoIF92ZWN0b3IgKTtcclxuXHJcblx0fVxyXG5cclxuXHRyZWZsZWN0KCBub3JtYWwgKSB7XHJcblxyXG5cdFx0Ly8gcmVmbGVjdCBpbmNpZGVudCB2ZWN0b3Igb2ZmIHBsYW5lIG9ydGhvZ29uYWwgdG8gbm9ybWFsXHJcblx0XHQvLyBub3JtYWwgaXMgYXNzdW1lZCB0byBoYXZlIHVuaXQgbGVuZ3RoXHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuc3ViKCBfdmVjdG9yLmNvcHkoIG5vcm1hbCApLm11bHRpcGx5U2NhbGFyKCAyICogdGhpcy5kb3QoIG5vcm1hbCApICkgKTtcclxuXHJcblx0fVxyXG5cclxuXHRhbmdsZVRvKCB2ICkge1xyXG5cclxuXHRcdGNvbnN0IGRlbm9taW5hdG9yID0gTWF0aC5zcXJ0KCB0aGlzLmxlbmd0aFNxKCkgKiB2Lmxlbmd0aFNxKCkgKTtcclxuXHJcblx0XHRpZiAoIGRlbm9taW5hdG9yID09PSAwICkgcmV0dXJuIE1hdGguUEkgLyAyO1xyXG5cclxuXHRcdGNvbnN0IHRoZXRhID0gdGhpcy5kb3QoIHYgKSAvIGRlbm9taW5hdG9yO1xyXG5cclxuXHRcdC8vIGNsYW1wLCB0byBoYW5kbGUgbnVtZXJpY2FsIHByb2JsZW1zXHJcblxyXG5cdFx0cmV0dXJuIE1hdGguYWNvcyggTWF0aFV0aWxzLmNsYW1wKCB0aGV0YSwgLSAxLCAxICkgKTtcclxuXHJcblx0fVxyXG5cclxuXHRkaXN0YW5jZVRvKCB2ICkge1xyXG5cclxuXHRcdHJldHVybiBNYXRoLnNxcnQoIHRoaXMuZGlzdGFuY2VUb1NxdWFyZWQoIHYgKSApO1xyXG5cclxuXHR9XHJcblxyXG5cdGRpc3RhbmNlVG9TcXVhcmVkKCB2ICkge1xyXG5cclxuXHRcdGNvbnN0IGR4ID0gdGhpcy54IC0gdi54LCBkeSA9IHRoaXMueSAtIHYueSwgZHogPSB0aGlzLnogLSB2Lno7XHJcblxyXG5cdFx0cmV0dXJuIGR4ICogZHggKyBkeSAqIGR5ICsgZHogKiBkejtcclxuXHJcblx0fVxyXG5cclxuXHRtYW5oYXR0YW5EaXN0YW5jZVRvKCB2ICkge1xyXG5cclxuXHRcdHJldHVybiBNYXRoLmFicyggdGhpcy54IC0gdi54ICkgKyBNYXRoLmFicyggdGhpcy55IC0gdi55ICkgKyBNYXRoLmFicyggdGhpcy56IC0gdi56ICk7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0RnJvbVNwaGVyaWNhbCggcyApIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5zZXRGcm9tU3BoZXJpY2FsQ29vcmRzKCBzLnJhZGl1cywgcy5waGksIHMudGhldGEgKTtcclxuXHJcblx0fVxyXG5cclxuXHRzZXRGcm9tU3BoZXJpY2FsQ29vcmRzKCByYWRpdXMsIHBoaSwgdGhldGEgKSB7XHJcblxyXG5cdFx0Y29uc3Qgc2luUGhpUmFkaXVzID0gTWF0aC5zaW4oIHBoaSApICogcmFkaXVzO1xyXG5cclxuXHRcdHRoaXMueCA9IHNpblBoaVJhZGl1cyAqIE1hdGguc2luKCB0aGV0YSApO1xyXG5cdFx0dGhpcy55ID0gTWF0aC5jb3MoIHBoaSApICogcmFkaXVzO1xyXG5cdFx0dGhpcy56ID0gc2luUGhpUmFkaXVzICogTWF0aC5jb3MoIHRoZXRhICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0RnJvbUN5bGluZHJpY2FsKCBjICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLnNldEZyb21DeWxpbmRyaWNhbENvb3JkcyggYy5yYWRpdXMsIGMudGhldGEsIGMueSApO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldEZyb21DeWxpbmRyaWNhbENvb3JkcyggcmFkaXVzLCB0aGV0YSwgeSApIHtcclxuXHJcblx0XHR0aGlzLnggPSByYWRpdXMgKiBNYXRoLnNpbiggdGhldGEgKTtcclxuXHRcdHRoaXMueSA9IHk7XHJcblx0XHR0aGlzLnogPSByYWRpdXMgKiBNYXRoLmNvcyggdGhldGEgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRGcm9tTWF0cml4UG9zaXRpb24oIG0gKSB7XHJcblxyXG5cdFx0Y29uc3QgZSA9IG0uZWxlbWVudHM7XHJcblxyXG5cdFx0dGhpcy54ID0gZVsgMTIgXTtcclxuXHRcdHRoaXMueSA9IGVbIDEzIF07XHJcblx0XHR0aGlzLnogPSBlWyAxNCBdO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldEZyb21NYXRyaXhTY2FsZSggbSApIHtcclxuXHJcblx0XHRjb25zdCBzeCA9IHRoaXMuc2V0RnJvbU1hdHJpeENvbHVtbiggbSwgMCApLmxlbmd0aCgpO1xyXG5cdFx0Y29uc3Qgc3kgPSB0aGlzLnNldEZyb21NYXRyaXhDb2x1bW4oIG0sIDEgKS5sZW5ndGgoKTtcclxuXHRcdGNvbnN0IHN6ID0gdGhpcy5zZXRGcm9tTWF0cml4Q29sdW1uKCBtLCAyICkubGVuZ3RoKCk7XHJcblxyXG5cdFx0dGhpcy54ID0gc3g7XHJcblx0XHR0aGlzLnkgPSBzeTtcclxuXHRcdHRoaXMueiA9IHN6O1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldEZyb21NYXRyaXhDb2x1bW4oIG0sIGluZGV4ICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLmZyb21BcnJheSggbS5lbGVtZW50cywgaW5kZXggKiA0ICk7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0RnJvbU1hdHJpeDNDb2x1bW4oIG0sIGluZGV4ICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLmZyb21BcnJheSggbS5lbGVtZW50cywgaW5kZXggKiAzICk7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0RnJvbUV1bGVyKCBlICkge1xyXG5cclxuXHRcdHRoaXMueCA9IGUuX3g7XHJcblx0XHR0aGlzLnkgPSBlLl95O1xyXG5cdFx0dGhpcy56ID0gZS5fejtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRGcm9tQ29sb3IoIGMgKSB7XHJcblxyXG5cdFx0dGhpcy54ID0gYy5yO1xyXG5cdFx0dGhpcy55ID0gYy5nO1xyXG5cdFx0dGhpcy56ID0gYy5iO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGVxdWFscyggdiApIHtcclxuXHJcblx0XHRyZXR1cm4gKCAoIHYueCA9PT0gdGhpcy54ICkgJiYgKCB2LnkgPT09IHRoaXMueSApICYmICggdi56ID09PSB0aGlzLnogKSApO1xyXG5cclxuXHR9XHJcblxyXG5cdGZyb21BcnJheSggYXJyYXksIG9mZnNldCA9IDAgKSB7XHJcblxyXG5cdFx0dGhpcy54ID0gYXJyYXlbIG9mZnNldCBdO1xyXG5cdFx0dGhpcy55ID0gYXJyYXlbIG9mZnNldCArIDEgXTtcclxuXHRcdHRoaXMueiA9IGFycmF5WyBvZmZzZXQgKyAyIF07XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0dG9BcnJheSggYXJyYXkgPSBbXSwgb2Zmc2V0ID0gMCApIHtcclxuXHJcblx0XHRhcnJheVsgb2Zmc2V0IF0gPSB0aGlzLng7XHJcblx0XHRhcnJheVsgb2Zmc2V0ICsgMSBdID0gdGhpcy55O1xyXG5cdFx0YXJyYXlbIG9mZnNldCArIDIgXSA9IHRoaXMuejtcclxuXHJcblx0XHRyZXR1cm4gYXJyYXk7XHJcblxyXG5cdH1cclxuXHJcblx0ZnJvbUJ1ZmZlckF0dHJpYnV0ZSggYXR0cmlidXRlLCBpbmRleCApIHtcclxuXHJcblx0XHR0aGlzLnggPSBhdHRyaWJ1dGUuZ2V0WCggaW5kZXggKTtcclxuXHRcdHRoaXMueSA9IGF0dHJpYnV0ZS5nZXRZKCBpbmRleCApO1xyXG5cdFx0dGhpcy56ID0gYXR0cmlidXRlLmdldFooIGluZGV4ICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0cmFuZG9tKCkge1xyXG5cclxuXHRcdHRoaXMueCA9IE1hdGgucmFuZG9tKCk7XHJcblx0XHR0aGlzLnkgPSBNYXRoLnJhbmRvbSgpO1xyXG5cdFx0dGhpcy56ID0gTWF0aC5yYW5kb20oKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRyYW5kb21EaXJlY3Rpb24oKSB7XHJcblxyXG5cdFx0Ly8gRGVyaXZlZCBmcm9tIGh0dHBzOi8vbWF0aHdvcmxkLndvbGZyYW0uY29tL1NwaGVyZVBvaW50UGlja2luZy5odG1sXHJcblxyXG5cdFx0Y29uc3QgdSA9ICggTWF0aC5yYW5kb20oKSAtIDAuNSApICogMjtcclxuXHRcdGNvbnN0IHQgPSBNYXRoLnJhbmRvbSgpICogTWF0aC5QSSAqIDI7XHJcblx0XHRjb25zdCBmID0gTWF0aC5zcXJ0KCAxIC0gdSAqKiAyICk7XHJcblxyXG5cdFx0dGhpcy54ID0gZiAqIE1hdGguY29zKCB0ICk7XHJcblx0XHR0aGlzLnkgPSBmICogTWF0aC5zaW4oIHQgKTtcclxuXHRcdHRoaXMueiA9IHU7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0KlsgU3ltYm9sLml0ZXJhdG9yIF0oKSB7XHJcblxyXG5cdFx0eWllbGQgdGhpcy54O1xyXG5cdFx0eWllbGQgdGhpcy55O1xyXG5cdFx0eWllbGQgdGhpcy56O1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5jb25zdCBfdmVjdG9yID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5jb25zdCBfcXVhdGVybmlvbiA9IC8qQF9fUFVSRV9fKi8gbmV3IFF1YXRlcm5pb24oKTtcclxuXHJcbmV4cG9ydCB7IFZlY3RvcjMgfTtcclxuIiwiaW1wb3J0IHsgVmVjdG9yMyB9IGZyb20gJy4vVmVjdG9yMy5qcyc7XHJcblxyXG5jbGFzcyBCb3gzIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIG1pbiA9IG5ldyBWZWN0b3IzKCArIEluZmluaXR5LCArIEluZmluaXR5LCArIEluZmluaXR5ICksIG1heCA9IG5ldyBWZWN0b3IzKCAtIEluZmluaXR5LCAtIEluZmluaXR5LCAtIEluZmluaXR5ICkgKSB7XHJcblxyXG5cdFx0dGhpcy5pc0JveDMgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMubWluID0gbWluO1xyXG5cdFx0dGhpcy5tYXggPSBtYXg7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0KCBtaW4sIG1heCApIHtcclxuXHJcblx0XHR0aGlzLm1pbi5jb3B5KCBtaW4gKTtcclxuXHRcdHRoaXMubWF4LmNvcHkoIG1heCApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldEZyb21BcnJheSggYXJyYXkgKSB7XHJcblxyXG5cdFx0dGhpcy5tYWtlRW1wdHkoKTtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gYXJyYXkubGVuZ3RoOyBpIDwgaWw7IGkgKz0gMyApIHtcclxuXHJcblx0XHRcdHRoaXMuZXhwYW5kQnlQb2ludCggX3ZlY3Rvci5mcm9tQXJyYXkoIGFycmF5LCBpICkgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0RnJvbUJ1ZmZlckF0dHJpYnV0ZSggYXR0cmlidXRlICkge1xyXG5cclxuXHRcdHRoaXMubWFrZUVtcHR5KCk7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBpbCA9IGF0dHJpYnV0ZS5jb3VudDsgaSA8IGlsOyBpICsrICkge1xyXG5cclxuXHRcdFx0dGhpcy5leHBhbmRCeVBvaW50KCBfdmVjdG9yLmZyb21CdWZmZXJBdHRyaWJ1dGUoIGF0dHJpYnV0ZSwgaSApICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldEZyb21Qb2ludHMoIHBvaW50cyApIHtcclxuXHJcblx0XHR0aGlzLm1ha2VFbXB0eSgpO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSBwb2ludHMubGVuZ3RoOyBpIDwgaWw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHR0aGlzLmV4cGFuZEJ5UG9pbnQoIHBvaW50c1sgaSBdICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldEZyb21DZW50ZXJBbmRTaXplKCBjZW50ZXIsIHNpemUgKSB7XHJcblxyXG5cdFx0Y29uc3QgaGFsZlNpemUgPSBfdmVjdG9yLmNvcHkoIHNpemUgKS5tdWx0aXBseVNjYWxhciggMC41ICk7XHJcblxyXG5cdFx0dGhpcy5taW4uY29weSggY2VudGVyICkuc3ViKCBoYWxmU2l6ZSApO1xyXG5cdFx0dGhpcy5tYXguY29weSggY2VudGVyICkuYWRkKCBoYWxmU2l6ZSApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldEZyb21PYmplY3QoIG9iamVjdCwgcHJlY2lzZSA9IGZhbHNlICkge1xyXG5cclxuXHRcdHRoaXMubWFrZUVtcHR5KCk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuZXhwYW5kQnlPYmplY3QoIG9iamVjdCwgcHJlY2lzZSApO1xyXG5cclxuXHR9XHJcblxyXG5cdGNsb25lKCkge1xyXG5cclxuXHRcdHJldHVybiBuZXcgdGhpcy5jb25zdHJ1Y3RvcigpLmNvcHkoIHRoaXMgKTtcclxuXHJcblx0fVxyXG5cclxuXHRjb3B5KCBib3ggKSB7XHJcblxyXG5cdFx0dGhpcy5taW4uY29weSggYm94Lm1pbiApO1xyXG5cdFx0dGhpcy5tYXguY29weSggYm94Lm1heCApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdG1ha2VFbXB0eSgpIHtcclxuXHJcblx0XHR0aGlzLm1pbi54ID0gdGhpcy5taW4ueSA9IHRoaXMubWluLnogPSArIEluZmluaXR5O1xyXG5cdFx0dGhpcy5tYXgueCA9IHRoaXMubWF4LnkgPSB0aGlzLm1heC56ID0gLSBJbmZpbml0eTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRpc0VtcHR5KCkge1xyXG5cclxuXHRcdC8vIHRoaXMgaXMgYSBtb3JlIHJvYnVzdCBjaGVjayBmb3IgZW1wdHkgdGhhbiAoIHZvbHVtZSA8PSAwICkgYmVjYXVzZSB2b2x1bWUgY2FuIGdldCBwb3NpdGl2ZSB3aXRoIHR3byBuZWdhdGl2ZSBheGVzXHJcblxyXG5cdFx0cmV0dXJuICggdGhpcy5tYXgueCA8IHRoaXMubWluLnggKSB8fCAoIHRoaXMubWF4LnkgPCB0aGlzLm1pbi55ICkgfHwgKCB0aGlzLm1heC56IDwgdGhpcy5taW4ueiApO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldENlbnRlciggdGFyZ2V0ICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLmlzRW1wdHkoKSA/IHRhcmdldC5zZXQoIDAsIDAsIDAgKSA6IHRhcmdldC5hZGRWZWN0b3JzKCB0aGlzLm1pbiwgdGhpcy5tYXggKS5tdWx0aXBseVNjYWxhciggMC41ICk7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0U2l6ZSggdGFyZ2V0ICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLmlzRW1wdHkoKSA/IHRhcmdldC5zZXQoIDAsIDAsIDAgKSA6IHRhcmdldC5zdWJWZWN0b3JzKCB0aGlzLm1heCwgdGhpcy5taW4gKTtcclxuXHJcblx0fVxyXG5cclxuXHRleHBhbmRCeVBvaW50KCBwb2ludCApIHtcclxuXHJcblx0XHR0aGlzLm1pbi5taW4oIHBvaW50ICk7XHJcblx0XHR0aGlzLm1heC5tYXgoIHBvaW50ICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0ZXhwYW5kQnlWZWN0b3IoIHZlY3RvciApIHtcclxuXHJcblx0XHR0aGlzLm1pbi5zdWIoIHZlY3RvciApO1xyXG5cdFx0dGhpcy5tYXguYWRkKCB2ZWN0b3IgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRleHBhbmRCeVNjYWxhciggc2NhbGFyICkge1xyXG5cclxuXHRcdHRoaXMubWluLmFkZFNjYWxhciggLSBzY2FsYXIgKTtcclxuXHRcdHRoaXMubWF4LmFkZFNjYWxhciggc2NhbGFyICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0ZXhwYW5kQnlPYmplY3QoIG9iamVjdCwgcHJlY2lzZSA9IGZhbHNlICkge1xyXG5cclxuXHRcdC8vIENvbXB1dGVzIHRoZSB3b3JsZC1heGlzLWFsaWduZWQgYm91bmRpbmcgYm94IG9mIGFuIG9iamVjdCAoaW5jbHVkaW5nIGl0cyBjaGlsZHJlbiksXHJcblx0XHQvLyBhY2NvdW50aW5nIGZvciBib3RoIHRoZSBvYmplY3QncywgYW5kIGNoaWxkcmVuJ3MsIHdvcmxkIHRyYW5zZm9ybXNcclxuXHJcblx0XHRvYmplY3QudXBkYXRlV29ybGRNYXRyaXgoIGZhbHNlLCBmYWxzZSApO1xyXG5cclxuXHRcdGNvbnN0IGdlb21ldHJ5ID0gb2JqZWN0Lmdlb21ldHJ5O1xyXG5cclxuXHRcdGlmICggZ2VvbWV0cnkgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdGNvbnN0IHBvc2l0aW9uQXR0cmlidXRlID0gZ2VvbWV0cnkuZ2V0QXR0cmlidXRlKCAncG9zaXRpb24nICk7XHJcblxyXG5cdFx0XHQvLyBwcmVjaXNlIEFBQkIgY29tcHV0YXRpb24gYmFzZWQgb24gdmVydGV4IGRhdGEgcmVxdWlyZXMgYXQgbGVhc3QgYSBwb3NpdGlvbiBhdHRyaWJ1dGUuXHJcblx0XHRcdC8vIGluc3RhbmNpbmcgaXNuJ3Qgc3VwcG9ydGVkIHNvIGZhciBhbmQgdXNlcyB0aGUgbm9ybWFsIChjb25zZXJ2YXRpdmUpIGNvZGUgcGF0aC5cclxuXHJcblx0XHRcdGlmICggcHJlY2lzZSA9PT0gdHJ1ZSAmJiBwb3NpdGlvbkF0dHJpYnV0ZSAhPT0gdW5kZWZpbmVkICYmIG9iamVjdC5pc0luc3RhbmNlZE1lc2ggIT09IHRydWUgKSB7XHJcblxyXG5cdFx0XHRcdGZvciAoIGxldCBpID0gMCwgbCA9IHBvc2l0aW9uQXR0cmlidXRlLmNvdW50OyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0XHRpZiAoIG9iamVjdC5pc01lc2ggPT09IHRydWUgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRvYmplY3QuZ2V0VmVydGV4UG9zaXRpb24oIGksIF92ZWN0b3IgKTtcclxuXHJcblx0XHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdFx0X3ZlY3Rvci5mcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbkF0dHJpYnV0ZSwgaSApO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRfdmVjdG9yLmFwcGx5TWF0cml4NCggb2JqZWN0Lm1hdHJpeFdvcmxkICk7XHJcblx0XHRcdFx0XHR0aGlzLmV4cGFuZEJ5UG9pbnQoIF92ZWN0b3IgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0aWYgKCBvYmplY3QuYm91bmRpbmdCb3ggIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0XHQvLyBvYmplY3QtbGV2ZWwgYm91bmRpbmcgYm94XHJcblxyXG5cdFx0XHRcdFx0aWYgKCBvYmplY3QuYm91bmRpbmdCb3ggPT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRvYmplY3QuY29tcHV0ZUJvdW5kaW5nQm94KCk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdF9ib3guY29weSggb2JqZWN0LmJvdW5kaW5nQm94ICk7XHJcblxyXG5cclxuXHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdC8vIGdlb21ldHJ5LWxldmVsIGJvdW5kaW5nIGJveFxyXG5cclxuXHRcdFx0XHRcdGlmICggZ2VvbWV0cnkuYm91bmRpbmdCb3ggPT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRnZW9tZXRyeS5jb21wdXRlQm91bmRpbmdCb3goKTtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0X2JveC5jb3B5KCBnZW9tZXRyeS5ib3VuZGluZ0JveCApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdF9ib3guYXBwbHlNYXRyaXg0KCBvYmplY3QubWF0cml4V29ybGQgKTtcclxuXHJcblx0XHRcdFx0dGhpcy51bmlvbiggX2JveCApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCBjaGlsZHJlbiA9IG9iamVjdC5jaGlsZHJlbjtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBjaGlsZHJlbi5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0dGhpcy5leHBhbmRCeU9iamVjdCggY2hpbGRyZW5bIGkgXSwgcHJlY2lzZSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRjb250YWluc1BvaW50KCBwb2ludCApIHtcclxuXHJcblx0XHRyZXR1cm4gcG9pbnQueCA8IHRoaXMubWluLnggfHwgcG9pbnQueCA+IHRoaXMubWF4LnggfHxcclxuXHRcdFx0cG9pbnQueSA8IHRoaXMubWluLnkgfHwgcG9pbnQueSA+IHRoaXMubWF4LnkgfHxcclxuXHRcdFx0cG9pbnQueiA8IHRoaXMubWluLnogfHwgcG9pbnQueiA+IHRoaXMubWF4LnogPyBmYWxzZSA6IHRydWU7XHJcblxyXG5cdH1cclxuXHJcblx0Y29udGFpbnNCb3goIGJveCApIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5taW4ueCA8PSBib3gubWluLnggJiYgYm94Lm1heC54IDw9IHRoaXMubWF4LnggJiZcclxuXHRcdFx0dGhpcy5taW4ueSA8PSBib3gubWluLnkgJiYgYm94Lm1heC55IDw9IHRoaXMubWF4LnkgJiZcclxuXHRcdFx0dGhpcy5taW4ueiA8PSBib3gubWluLnogJiYgYm94Lm1heC56IDw9IHRoaXMubWF4Lno7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0UGFyYW1ldGVyKCBwb2ludCwgdGFyZ2V0ICkge1xyXG5cclxuXHRcdC8vIFRoaXMgY2FuIHBvdGVudGlhbGx5IGhhdmUgYSBkaXZpZGUgYnkgemVybyBpZiB0aGUgYm94XHJcblx0XHQvLyBoYXMgYSBzaXplIGRpbWVuc2lvbiBvZiAwLlxyXG5cclxuXHRcdHJldHVybiB0YXJnZXQuc2V0KFxyXG5cdFx0XHQoIHBvaW50LnggLSB0aGlzLm1pbi54ICkgLyAoIHRoaXMubWF4LnggLSB0aGlzLm1pbi54ICksXHJcblx0XHRcdCggcG9pbnQueSAtIHRoaXMubWluLnkgKSAvICggdGhpcy5tYXgueSAtIHRoaXMubWluLnkgKSxcclxuXHRcdFx0KCBwb2ludC56IC0gdGhpcy5taW4ueiApIC8gKCB0aGlzLm1heC56IC0gdGhpcy5taW4ueiApXHJcblx0XHQpO1xyXG5cclxuXHR9XHJcblxyXG5cdGludGVyc2VjdHNCb3goIGJveCApIHtcclxuXHJcblx0XHQvLyB1c2luZyA2IHNwbGl0dGluZyBwbGFuZXMgdG8gcnVsZSBvdXQgaW50ZXJzZWN0aW9ucy5cclxuXHRcdHJldHVybiBib3gubWF4LnggPCB0aGlzLm1pbi54IHx8IGJveC5taW4ueCA+IHRoaXMubWF4LnggfHxcclxuXHRcdFx0Ym94Lm1heC55IDwgdGhpcy5taW4ueSB8fCBib3gubWluLnkgPiB0aGlzLm1heC55IHx8XHJcblx0XHRcdGJveC5tYXgueiA8IHRoaXMubWluLnogfHwgYm94Lm1pbi56ID4gdGhpcy5tYXgueiA/IGZhbHNlIDogdHJ1ZTtcclxuXHJcblx0fVxyXG5cclxuXHRpbnRlcnNlY3RzU3BoZXJlKCBzcGhlcmUgKSB7XHJcblxyXG5cdFx0Ly8gRmluZCB0aGUgcG9pbnQgb24gdGhlIEFBQkIgY2xvc2VzdCB0byB0aGUgc3BoZXJlIGNlbnRlci5cclxuXHRcdHRoaXMuY2xhbXBQb2ludCggc3BoZXJlLmNlbnRlciwgX3ZlY3RvciApO1xyXG5cclxuXHRcdC8vIElmIHRoYXQgcG9pbnQgaXMgaW5zaWRlIHRoZSBzcGhlcmUsIHRoZSBBQUJCIGFuZCBzcGhlcmUgaW50ZXJzZWN0LlxyXG5cdFx0cmV0dXJuIF92ZWN0b3IuZGlzdGFuY2VUb1NxdWFyZWQoIHNwaGVyZS5jZW50ZXIgKSA8PSAoIHNwaGVyZS5yYWRpdXMgKiBzcGhlcmUucmFkaXVzICk7XHJcblxyXG5cdH1cclxuXHJcblx0aW50ZXJzZWN0c1BsYW5lKCBwbGFuZSApIHtcclxuXHJcblx0XHQvLyBXZSBjb21wdXRlIHRoZSBtaW5pbXVtIGFuZCBtYXhpbXVtIGRvdCBwcm9kdWN0IHZhbHVlcy4gSWYgdGhvc2UgdmFsdWVzXHJcblx0XHQvLyBhcmUgb24gdGhlIHNhbWUgc2lkZSAoYmFjayBvciBmcm9udCkgb2YgdGhlIHBsYW5lLCB0aGVuIHRoZXJlIGlzIG5vIGludGVyc2VjdGlvbi5cclxuXHJcblx0XHRsZXQgbWluLCBtYXg7XHJcblxyXG5cdFx0aWYgKCBwbGFuZS5ub3JtYWwueCA+IDAgKSB7XHJcblxyXG5cdFx0XHRtaW4gPSBwbGFuZS5ub3JtYWwueCAqIHRoaXMubWluLng7XHJcblx0XHRcdG1heCA9IHBsYW5lLm5vcm1hbC54ICogdGhpcy5tYXgueDtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0bWluID0gcGxhbmUubm9ybWFsLnggKiB0aGlzLm1heC54O1xyXG5cdFx0XHRtYXggPSBwbGFuZS5ub3JtYWwueCAqIHRoaXMubWluLng7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggcGxhbmUubm9ybWFsLnkgPiAwICkge1xyXG5cclxuXHRcdFx0bWluICs9IHBsYW5lLm5vcm1hbC55ICogdGhpcy5taW4ueTtcclxuXHRcdFx0bWF4ICs9IHBsYW5lLm5vcm1hbC55ICogdGhpcy5tYXgueTtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0bWluICs9IHBsYW5lLm5vcm1hbC55ICogdGhpcy5tYXgueTtcclxuXHRcdFx0bWF4ICs9IHBsYW5lLm5vcm1hbC55ICogdGhpcy5taW4ueTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBwbGFuZS5ub3JtYWwueiA+IDAgKSB7XHJcblxyXG5cdFx0XHRtaW4gKz0gcGxhbmUubm9ybWFsLnogKiB0aGlzLm1pbi56O1xyXG5cdFx0XHRtYXggKz0gcGxhbmUubm9ybWFsLnogKiB0aGlzLm1heC56O1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRtaW4gKz0gcGxhbmUubm9ybWFsLnogKiB0aGlzLm1heC56O1xyXG5cdFx0XHRtYXggKz0gcGxhbmUubm9ybWFsLnogKiB0aGlzLm1pbi56O1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gKCBtaW4gPD0gLSBwbGFuZS5jb25zdGFudCAmJiBtYXggPj0gLSBwbGFuZS5jb25zdGFudCApO1xyXG5cclxuXHR9XHJcblxyXG5cdGludGVyc2VjdHNUcmlhbmdsZSggdHJpYW5nbGUgKSB7XHJcblxyXG5cdFx0aWYgKCB0aGlzLmlzRW1wdHkoKSApIHtcclxuXHJcblx0XHRcdHJldHVybiBmYWxzZTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gY29tcHV0ZSBib3ggY2VudGVyIGFuZCBleHRlbnRzXHJcblx0XHR0aGlzLmdldENlbnRlciggX2NlbnRlciApO1xyXG5cdFx0X2V4dGVudHMuc3ViVmVjdG9ycyggdGhpcy5tYXgsIF9jZW50ZXIgKTtcclxuXHJcblx0XHQvLyB0cmFuc2xhdGUgdHJpYW5nbGUgdG8gYWFiYiBvcmlnaW5cclxuXHRcdF92MC5zdWJWZWN0b3JzKCB0cmlhbmdsZS5hLCBfY2VudGVyICk7XHJcblx0XHRfdjEuc3ViVmVjdG9ycyggdHJpYW5nbGUuYiwgX2NlbnRlciApO1xyXG5cdFx0X3YyLnN1YlZlY3RvcnMoIHRyaWFuZ2xlLmMsIF9jZW50ZXIgKTtcclxuXHJcblx0XHQvLyBjb21wdXRlIGVkZ2UgdmVjdG9ycyBmb3IgdHJpYW5nbGVcclxuXHRcdF9mMC5zdWJWZWN0b3JzKCBfdjEsIF92MCApO1xyXG5cdFx0X2YxLnN1YlZlY3RvcnMoIF92MiwgX3YxICk7XHJcblx0XHRfZjIuc3ViVmVjdG9ycyggX3YwLCBfdjIgKTtcclxuXHJcblx0XHQvLyB0ZXN0IGFnYWluc3QgYXhlcyB0aGF0IGFyZSBnaXZlbiBieSBjcm9zcyBwcm9kdWN0IGNvbWJpbmF0aW9ucyBvZiB0aGUgZWRnZXMgb2YgdGhlIHRyaWFuZ2xlIGFuZCB0aGUgZWRnZXMgb2YgdGhlIGFhYmJcclxuXHRcdC8vIG1ha2UgYW4gYXhpcyB0ZXN0aW5nIG9mIGVhY2ggb2YgdGhlIDMgc2lkZXMgb2YgdGhlIGFhYmIgYWdhaW5zdCBlYWNoIG9mIHRoZSAzIHNpZGVzIG9mIHRoZSB0cmlhbmdsZSA9IDkgYXhpcyBvZiBzZXBhcmF0aW9uXHJcblx0XHQvLyBheGlzX2lqID0gdV9pIHggZl9qICh1MCwgdTEsIHUyID0gZmFjZSBub3JtYWxzIG9mIGFhYmIgPSB4LHkseiBheGVzIHZlY3RvcnMgc2luY2UgYWFiYiBpcyBheGlzIGFsaWduZWQpXHJcblx0XHRsZXQgYXhlcyA9IFtcclxuXHRcdFx0MCwgLSBfZjAueiwgX2YwLnksIDAsIC0gX2YxLnosIF9mMS55LCAwLCAtIF9mMi56LCBfZjIueSxcclxuXHRcdFx0X2YwLnosIDAsIC0gX2YwLngsIF9mMS56LCAwLCAtIF9mMS54LCBfZjIueiwgMCwgLSBfZjIueCxcclxuXHRcdFx0LSBfZjAueSwgX2YwLngsIDAsIC0gX2YxLnksIF9mMS54LCAwLCAtIF9mMi55LCBfZjIueCwgMFxyXG5cdFx0XTtcclxuXHRcdGlmICggISBzYXRGb3JBeGVzKCBheGVzLCBfdjAsIF92MSwgX3YyLCBfZXh0ZW50cyApICkge1xyXG5cclxuXHRcdFx0cmV0dXJuIGZhbHNlO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvLyB0ZXN0IDMgZmFjZSBub3JtYWxzIGZyb20gdGhlIGFhYmJcclxuXHRcdGF4ZXMgPSBbIDEsIDAsIDAsIDAsIDEsIDAsIDAsIDAsIDEgXTtcclxuXHRcdGlmICggISBzYXRGb3JBeGVzKCBheGVzLCBfdjAsIF92MSwgX3YyLCBfZXh0ZW50cyApICkge1xyXG5cclxuXHRcdFx0cmV0dXJuIGZhbHNlO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvLyBmaW5hbGx5IHRlc3RpbmcgdGhlIGZhY2Ugbm9ybWFsIG9mIHRoZSB0cmlhbmdsZVxyXG5cdFx0Ly8gdXNlIGFscmVhZHkgZXhpc3RpbmcgdHJpYW5nbGUgZWRnZSB2ZWN0b3JzIGhlcmVcclxuXHRcdF90cmlhbmdsZU5vcm1hbC5jcm9zc1ZlY3RvcnMoIF9mMCwgX2YxICk7XHJcblx0XHRheGVzID0gWyBfdHJpYW5nbGVOb3JtYWwueCwgX3RyaWFuZ2xlTm9ybWFsLnksIF90cmlhbmdsZU5vcm1hbC56IF07XHJcblxyXG5cdFx0cmV0dXJuIHNhdEZvckF4ZXMoIGF4ZXMsIF92MCwgX3YxLCBfdjIsIF9leHRlbnRzICk7XHJcblxyXG5cdH1cclxuXHJcblx0Y2xhbXBQb2ludCggcG9pbnQsIHRhcmdldCApIHtcclxuXHJcblx0XHRyZXR1cm4gdGFyZ2V0LmNvcHkoIHBvaW50ICkuY2xhbXAoIHRoaXMubWluLCB0aGlzLm1heCApO1xyXG5cclxuXHR9XHJcblxyXG5cdGRpc3RhbmNlVG9Qb2ludCggcG9pbnQgKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuY2xhbXBQb2ludCggcG9pbnQsIF92ZWN0b3IgKS5kaXN0YW5jZVRvKCBwb2ludCApO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldEJvdW5kaW5nU3BoZXJlKCB0YXJnZXQgKSB7XHJcblxyXG5cdFx0aWYgKCB0aGlzLmlzRW1wdHkoKSApIHtcclxuXHJcblx0XHRcdHRhcmdldC5tYWtlRW1wdHkoKTtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0dGhpcy5nZXRDZW50ZXIoIHRhcmdldC5jZW50ZXIgKTtcclxuXHJcblx0XHRcdHRhcmdldC5yYWRpdXMgPSB0aGlzLmdldFNpemUoIF92ZWN0b3IgKS5sZW5ndGgoKSAqIDAuNTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRhcmdldDtcclxuXHJcblx0fVxyXG5cclxuXHRpbnRlcnNlY3QoIGJveCApIHtcclxuXHJcblx0XHR0aGlzLm1pbi5tYXgoIGJveC5taW4gKTtcclxuXHRcdHRoaXMubWF4Lm1pbiggYm94Lm1heCApO1xyXG5cclxuXHRcdC8vIGVuc3VyZSB0aGF0IGlmIHRoZXJlIGlzIG5vIG92ZXJsYXAsIHRoZSByZXN1bHQgaXMgZnVsbHkgZW1wdHksIG5vdCBzbGlnaHRseSBlbXB0eSB3aXRoIG5vbi1pbmYvK2luZiB2YWx1ZXMgdGhhdCB3aWxsIGNhdXNlIHN1YnNlcXVlbmNlIGludGVyc2VjdHMgdG8gZXJyb25lb3VzbHkgcmV0dXJuIHZhbGlkIHZhbHVlcy5cclxuXHRcdGlmICggdGhpcy5pc0VtcHR5KCkgKSB0aGlzLm1ha2VFbXB0eSgpO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHVuaW9uKCBib3ggKSB7XHJcblxyXG5cdFx0dGhpcy5taW4ubWluKCBib3gubWluICk7XHJcblx0XHR0aGlzLm1heC5tYXgoIGJveC5tYXggKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRhcHBseU1hdHJpeDQoIG1hdHJpeCApIHtcclxuXHJcblx0XHQvLyB0cmFuc2Zvcm0gb2YgZW1wdHkgYm94IGlzIGFuIGVtcHR5IGJveC5cclxuXHRcdGlmICggdGhpcy5pc0VtcHR5KCkgKSByZXR1cm4gdGhpcztcclxuXHJcblx0XHQvLyBOT1RFOiBJIGFtIHVzaW5nIGEgYmluYXJ5IHBhdHRlcm4gdG8gc3BlY2lmeSBhbGwgMl4zIGNvbWJpbmF0aW9ucyBiZWxvd1xyXG5cdFx0X3BvaW50c1sgMCBdLnNldCggdGhpcy5taW4ueCwgdGhpcy5taW4ueSwgdGhpcy5taW4ueiApLmFwcGx5TWF0cml4NCggbWF0cml4ICk7IC8vIDAwMFxyXG5cdFx0X3BvaW50c1sgMSBdLnNldCggdGhpcy5taW4ueCwgdGhpcy5taW4ueSwgdGhpcy5tYXgueiApLmFwcGx5TWF0cml4NCggbWF0cml4ICk7IC8vIDAwMVxyXG5cdFx0X3BvaW50c1sgMiBdLnNldCggdGhpcy5taW4ueCwgdGhpcy5tYXgueSwgdGhpcy5taW4ueiApLmFwcGx5TWF0cml4NCggbWF0cml4ICk7IC8vIDAxMFxyXG5cdFx0X3BvaW50c1sgMyBdLnNldCggdGhpcy5taW4ueCwgdGhpcy5tYXgueSwgdGhpcy5tYXgueiApLmFwcGx5TWF0cml4NCggbWF0cml4ICk7IC8vIDAxMVxyXG5cdFx0X3BvaW50c1sgNCBdLnNldCggdGhpcy5tYXgueCwgdGhpcy5taW4ueSwgdGhpcy5taW4ueiApLmFwcGx5TWF0cml4NCggbWF0cml4ICk7IC8vIDEwMFxyXG5cdFx0X3BvaW50c1sgNSBdLnNldCggdGhpcy5tYXgueCwgdGhpcy5taW4ueSwgdGhpcy5tYXgueiApLmFwcGx5TWF0cml4NCggbWF0cml4ICk7IC8vIDEwMVxyXG5cdFx0X3BvaW50c1sgNiBdLnNldCggdGhpcy5tYXgueCwgdGhpcy5tYXgueSwgdGhpcy5taW4ueiApLmFwcGx5TWF0cml4NCggbWF0cml4ICk7IC8vIDExMFxyXG5cdFx0X3BvaW50c1sgNyBdLnNldCggdGhpcy5tYXgueCwgdGhpcy5tYXgueSwgdGhpcy5tYXgueiApLmFwcGx5TWF0cml4NCggbWF0cml4ICk7IC8vIDExMVxyXG5cclxuXHRcdHRoaXMuc2V0RnJvbVBvaW50cyggX3BvaW50cyApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHRyYW5zbGF0ZSggb2Zmc2V0ICkge1xyXG5cclxuXHRcdHRoaXMubWluLmFkZCggb2Zmc2V0ICk7XHJcblx0XHR0aGlzLm1heC5hZGQoIG9mZnNldCApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGVxdWFscyggYm94ICkge1xyXG5cclxuXHRcdHJldHVybiBib3gubWluLmVxdWFscyggdGhpcy5taW4gKSAmJiBib3gubWF4LmVxdWFscyggdGhpcy5tYXggKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuY29uc3QgX3BvaW50cyA9IFtcclxuXHQvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCksXHJcblx0LypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpLFxyXG5cdC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKSxcclxuXHQvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCksXHJcblx0LypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpLFxyXG5cdC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKSxcclxuXHQvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCksXHJcblx0LypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpXHJcbl07XHJcblxyXG5jb25zdCBfdmVjdG9yID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5cclxuY29uc3QgX2JveCA9IC8qQF9fUFVSRV9fKi8gbmV3IEJveDMoKTtcclxuXHJcbi8vIHRyaWFuZ2xlIGNlbnRlcmVkIHZlcnRpY2VzXHJcblxyXG5jb25zdCBfdjAgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XHJcbmNvbnN0IF92MSA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuY29uc3QgX3YyID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5cclxuLy8gdHJpYW5nbGUgZWRnZSB2ZWN0b3JzXHJcblxyXG5jb25zdCBfZjAgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XHJcbmNvbnN0IF9mMSA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuY29uc3QgX2YyID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5cclxuY29uc3QgX2NlbnRlciA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuY29uc3QgX2V4dGVudHMgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XHJcbmNvbnN0IF90cmlhbmdsZU5vcm1hbCA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuY29uc3QgX3Rlc3RBeGlzID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5cclxuZnVuY3Rpb24gc2F0Rm9yQXhlcyggYXhlcywgdjAsIHYxLCB2MiwgZXh0ZW50cyApIHtcclxuXHJcblx0Zm9yICggbGV0IGkgPSAwLCBqID0gYXhlcy5sZW5ndGggLSAzOyBpIDw9IGo7IGkgKz0gMyApIHtcclxuXHJcblx0XHRfdGVzdEF4aXMuZnJvbUFycmF5KCBheGVzLCBpICk7XHJcblx0XHQvLyBwcm9qZWN0IHRoZSBhYWJiIG9udG8gdGhlIHNlcGFyYXRpbmcgYXhpc1xyXG5cdFx0Y29uc3QgciA9IGV4dGVudHMueCAqIE1hdGguYWJzKCBfdGVzdEF4aXMueCApICsgZXh0ZW50cy55ICogTWF0aC5hYnMoIF90ZXN0QXhpcy55ICkgKyBleHRlbnRzLnogKiBNYXRoLmFicyggX3Rlc3RBeGlzLnogKTtcclxuXHRcdC8vIHByb2plY3QgYWxsIDMgdmVydGljZXMgb2YgdGhlIHRyaWFuZ2xlIG9udG8gdGhlIHNlcGFyYXRpbmcgYXhpc1xyXG5cdFx0Y29uc3QgcDAgPSB2MC5kb3QoIF90ZXN0QXhpcyApO1xyXG5cdFx0Y29uc3QgcDEgPSB2MS5kb3QoIF90ZXN0QXhpcyApO1xyXG5cdFx0Y29uc3QgcDIgPSB2Mi5kb3QoIF90ZXN0QXhpcyApO1xyXG5cdFx0Ly8gYWN0dWFsIHRlc3QsIGJhc2ljYWxseSBzZWUgaWYgZWl0aGVyIG9mIHRoZSBtb3N0IGV4dHJlbWUgb2YgdGhlIHRyaWFuZ2xlIHBvaW50cyBpbnRlcnNlY3RzIHJcclxuXHRcdGlmICggTWF0aC5tYXgoIC0gTWF0aC5tYXgoIHAwLCBwMSwgcDIgKSwgTWF0aC5taW4oIHAwLCBwMSwgcDIgKSApID4gciApIHtcclxuXHJcblx0XHRcdC8vIHBvaW50cyBvZiB0aGUgcHJvamVjdGVkIHRyaWFuZ2xlIGFyZSBvdXRzaWRlIHRoZSBwcm9qZWN0ZWQgaGFsZi1sZW5ndGggb2YgdGhlIGFhYmJcclxuXHRcdFx0Ly8gdGhlIGF4aXMgaXMgc2VwYXJhdGluZyBhbmQgd2UgY2FuIGV4aXRcclxuXHRcdFx0cmV0dXJuIGZhbHNlO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4gdHJ1ZTtcclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IEJveDMgfTtcclxuIiwiaW1wb3J0IHsgQm94MyB9IGZyb20gJy4vQm94My5qcyc7XHJcbmltcG9ydCB7IFZlY3RvcjMgfSBmcm9tICcuL1ZlY3RvcjMuanMnO1xyXG5cclxuY29uc3QgX2JveCA9IC8qQF9fUFVSRV9fKi8gbmV3IEJveDMoKTtcclxuY29uc3QgX3YxID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5jb25zdCBfdjIgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XHJcblxyXG5jbGFzcyBTcGhlcmUge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggY2VudGVyID0gbmV3IFZlY3RvcjMoKSwgcmFkaXVzID0gLSAxICkge1xyXG5cclxuXHRcdHRoaXMuaXNTcGhlcmUgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMuY2VudGVyID0gY2VudGVyO1xyXG5cdFx0dGhpcy5yYWRpdXMgPSByYWRpdXM7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0KCBjZW50ZXIsIHJhZGl1cyApIHtcclxuXHJcblx0XHR0aGlzLmNlbnRlci5jb3B5KCBjZW50ZXIgKTtcclxuXHRcdHRoaXMucmFkaXVzID0gcmFkaXVzO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldEZyb21Qb2ludHMoIHBvaW50cywgb3B0aW9uYWxDZW50ZXIgKSB7XHJcblxyXG5cdFx0Y29uc3QgY2VudGVyID0gdGhpcy5jZW50ZXI7XHJcblxyXG5cdFx0aWYgKCBvcHRpb25hbENlbnRlciAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0Y2VudGVyLmNvcHkoIG9wdGlvbmFsQ2VudGVyICk7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdF9ib3guc2V0RnJvbVBvaW50cyggcG9pbnRzICkuZ2V0Q2VudGVyKCBjZW50ZXIgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0bGV0IG1heFJhZGl1c1NxID0gMDtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gcG9pbnRzLmxlbmd0aDsgaSA8IGlsOyBpICsrICkge1xyXG5cclxuXHRcdFx0bWF4UmFkaXVzU3EgPSBNYXRoLm1heCggbWF4UmFkaXVzU3EsIGNlbnRlci5kaXN0YW5jZVRvU3F1YXJlZCggcG9pbnRzWyBpIF0gKSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLnJhZGl1cyA9IE1hdGguc3FydCggbWF4UmFkaXVzU3EgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRjb3B5KCBzcGhlcmUgKSB7XHJcblxyXG5cdFx0dGhpcy5jZW50ZXIuY29weSggc3BoZXJlLmNlbnRlciApO1xyXG5cdFx0dGhpcy5yYWRpdXMgPSBzcGhlcmUucmFkaXVzO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGlzRW1wdHkoKSB7XHJcblxyXG5cdFx0cmV0dXJuICggdGhpcy5yYWRpdXMgPCAwICk7XHJcblxyXG5cdH1cclxuXHJcblx0bWFrZUVtcHR5KCkge1xyXG5cclxuXHRcdHRoaXMuY2VudGVyLnNldCggMCwgMCwgMCApO1xyXG5cdFx0dGhpcy5yYWRpdXMgPSAtIDE7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Y29udGFpbnNQb2ludCggcG9pbnQgKSB7XHJcblxyXG5cdFx0cmV0dXJuICggcG9pbnQuZGlzdGFuY2VUb1NxdWFyZWQoIHRoaXMuY2VudGVyICkgPD0gKCB0aGlzLnJhZGl1cyAqIHRoaXMucmFkaXVzICkgKTtcclxuXHJcblx0fVxyXG5cclxuXHRkaXN0YW5jZVRvUG9pbnQoIHBvaW50ICkge1xyXG5cclxuXHRcdHJldHVybiAoIHBvaW50LmRpc3RhbmNlVG8oIHRoaXMuY2VudGVyICkgLSB0aGlzLnJhZGl1cyApO1xyXG5cclxuXHR9XHJcblxyXG5cdGludGVyc2VjdHNTcGhlcmUoIHNwaGVyZSApIHtcclxuXHJcblx0XHRjb25zdCByYWRpdXNTdW0gPSB0aGlzLnJhZGl1cyArIHNwaGVyZS5yYWRpdXM7XHJcblxyXG5cdFx0cmV0dXJuIHNwaGVyZS5jZW50ZXIuZGlzdGFuY2VUb1NxdWFyZWQoIHRoaXMuY2VudGVyICkgPD0gKCByYWRpdXNTdW0gKiByYWRpdXNTdW0gKTtcclxuXHJcblx0fVxyXG5cclxuXHRpbnRlcnNlY3RzQm94KCBib3ggKSB7XHJcblxyXG5cdFx0cmV0dXJuIGJveC5pbnRlcnNlY3RzU3BoZXJlKCB0aGlzICk7XHJcblxyXG5cdH1cclxuXHJcblx0aW50ZXJzZWN0c1BsYW5lKCBwbGFuZSApIHtcclxuXHJcblx0XHRyZXR1cm4gTWF0aC5hYnMoIHBsYW5lLmRpc3RhbmNlVG9Qb2ludCggdGhpcy5jZW50ZXIgKSApIDw9IHRoaXMucmFkaXVzO1xyXG5cclxuXHR9XHJcblxyXG5cdGNsYW1wUG9pbnQoIHBvaW50LCB0YXJnZXQgKSB7XHJcblxyXG5cdFx0Y29uc3QgZGVsdGFMZW5ndGhTcSA9IHRoaXMuY2VudGVyLmRpc3RhbmNlVG9TcXVhcmVkKCBwb2ludCApO1xyXG5cclxuXHRcdHRhcmdldC5jb3B5KCBwb2ludCApO1xyXG5cclxuXHRcdGlmICggZGVsdGFMZW5ndGhTcSA+ICggdGhpcy5yYWRpdXMgKiB0aGlzLnJhZGl1cyApICkge1xyXG5cclxuXHRcdFx0dGFyZ2V0LnN1YiggdGhpcy5jZW50ZXIgKS5ub3JtYWxpemUoKTtcclxuXHRcdFx0dGFyZ2V0Lm11bHRpcGx5U2NhbGFyKCB0aGlzLnJhZGl1cyApLmFkZCggdGhpcy5jZW50ZXIgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRhcmdldDtcclxuXHJcblx0fVxyXG5cclxuXHRnZXRCb3VuZGluZ0JveCggdGFyZ2V0ICkge1xyXG5cclxuXHRcdGlmICggdGhpcy5pc0VtcHR5KCkgKSB7XHJcblxyXG5cdFx0XHQvLyBFbXB0eSBzcGhlcmUgcHJvZHVjZXMgZW1wdHkgYm91bmRpbmcgYm94XHJcblx0XHRcdHRhcmdldC5tYWtlRW1wdHkoKTtcclxuXHRcdFx0cmV0dXJuIHRhcmdldDtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGFyZ2V0LnNldCggdGhpcy5jZW50ZXIsIHRoaXMuY2VudGVyICk7XHJcblx0XHR0YXJnZXQuZXhwYW5kQnlTY2FsYXIoIHRoaXMucmFkaXVzICk7XHJcblxyXG5cdFx0cmV0dXJuIHRhcmdldDtcclxuXHJcblx0fVxyXG5cclxuXHRhcHBseU1hdHJpeDQoIG1hdHJpeCApIHtcclxuXHJcblx0XHR0aGlzLmNlbnRlci5hcHBseU1hdHJpeDQoIG1hdHJpeCApO1xyXG5cdFx0dGhpcy5yYWRpdXMgPSB0aGlzLnJhZGl1cyAqIG1hdHJpeC5nZXRNYXhTY2FsZU9uQXhpcygpO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHRyYW5zbGF0ZSggb2Zmc2V0ICkge1xyXG5cclxuXHRcdHRoaXMuY2VudGVyLmFkZCggb2Zmc2V0ICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0ZXhwYW5kQnlQb2ludCggcG9pbnQgKSB7XHJcblxyXG5cdFx0aWYgKCB0aGlzLmlzRW1wdHkoKSApIHtcclxuXHJcblx0XHRcdHRoaXMuY2VudGVyLmNvcHkoIHBvaW50ICk7XHJcblxyXG5cdFx0XHR0aGlzLnJhZGl1cyA9IDA7XHJcblxyXG5cdFx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0X3YxLnN1YlZlY3RvcnMoIHBvaW50LCB0aGlzLmNlbnRlciApO1xyXG5cclxuXHRcdGNvbnN0IGxlbmd0aFNxID0gX3YxLmxlbmd0aFNxKCk7XHJcblxyXG5cdFx0aWYgKCBsZW5ndGhTcSA+ICggdGhpcy5yYWRpdXMgKiB0aGlzLnJhZGl1cyApICkge1xyXG5cclxuXHRcdFx0Ly8gY2FsY3VsYXRlIHRoZSBtaW5pbWFsIHNwaGVyZVxyXG5cclxuXHRcdFx0Y29uc3QgbGVuZ3RoID0gTWF0aC5zcXJ0KCBsZW5ndGhTcSApO1xyXG5cclxuXHRcdFx0Y29uc3QgZGVsdGEgPSAoIGxlbmd0aCAtIHRoaXMucmFkaXVzICkgKiAwLjU7XHJcblxyXG5cdFx0XHR0aGlzLmNlbnRlci5hZGRTY2FsZWRWZWN0b3IoIF92MSwgZGVsdGEgLyBsZW5ndGggKTtcclxuXHJcblx0XHRcdHRoaXMucmFkaXVzICs9IGRlbHRhO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHR1bmlvbiggc3BoZXJlICkge1xyXG5cclxuXHRcdGlmICggc3BoZXJlLmlzRW1wdHkoKSApIHtcclxuXHJcblx0XHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHRoaXMuaXNFbXB0eSgpICkge1xyXG5cclxuXHRcdFx0dGhpcy5jb3B5KCBzcGhlcmUgKTtcclxuXHJcblx0XHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHRoaXMuY2VudGVyLmVxdWFscyggc3BoZXJlLmNlbnRlciApID09PSB0cnVlICkge1xyXG5cclxuXHRcdFx0IHRoaXMucmFkaXVzID0gTWF0aC5tYXgoIHRoaXMucmFkaXVzLCBzcGhlcmUucmFkaXVzICk7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdF92Mi5zdWJWZWN0b3JzKCBzcGhlcmUuY2VudGVyLCB0aGlzLmNlbnRlciApLnNldExlbmd0aCggc3BoZXJlLnJhZGl1cyApO1xyXG5cclxuXHRcdFx0dGhpcy5leHBhbmRCeVBvaW50KCBfdjEuY29weSggc3BoZXJlLmNlbnRlciApLmFkZCggX3YyICkgKTtcclxuXHJcblx0XHRcdHRoaXMuZXhwYW5kQnlQb2ludCggX3YxLmNvcHkoIHNwaGVyZS5jZW50ZXIgKS5zdWIoIF92MiApICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGVxdWFscyggc3BoZXJlICkge1xyXG5cclxuXHRcdHJldHVybiBzcGhlcmUuY2VudGVyLmVxdWFscyggdGhpcy5jZW50ZXIgKSAmJiAoIHNwaGVyZS5yYWRpdXMgPT09IHRoaXMucmFkaXVzICk7XHJcblxyXG5cdH1cclxuXHJcblx0Y2xvbmUoKSB7XHJcblxyXG5cdFx0cmV0dXJuIG5ldyB0aGlzLmNvbnN0cnVjdG9yKCkuY29weSggdGhpcyApO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBTcGhlcmUgfTtcclxuIiwiaW1wb3J0IHsgVmVjdG9yMyB9IGZyb20gJy4vVmVjdG9yMy5qcyc7XHJcblxyXG5jb25zdCBfdmVjdG9yID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5jb25zdCBfc2VnQ2VudGVyID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5jb25zdCBfc2VnRGlyID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5jb25zdCBfZGlmZiA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuXHJcbmNvbnN0IF9lZGdlMSA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuY29uc3QgX2VkZ2UyID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5jb25zdCBfbm9ybWFsID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5cclxuY2xhc3MgUmF5IHtcclxuXHJcblx0Y29uc3RydWN0b3IoIG9yaWdpbiA9IG5ldyBWZWN0b3IzKCksIGRpcmVjdGlvbiA9IG5ldyBWZWN0b3IzKCAwLCAwLCAtIDEgKSApIHtcclxuXHJcblx0XHR0aGlzLm9yaWdpbiA9IG9yaWdpbjtcclxuXHRcdHRoaXMuZGlyZWN0aW9uID0gZGlyZWN0aW9uO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldCggb3JpZ2luLCBkaXJlY3Rpb24gKSB7XHJcblxyXG5cdFx0dGhpcy5vcmlnaW4uY29weSggb3JpZ2luICk7XHJcblx0XHR0aGlzLmRpcmVjdGlvbi5jb3B5KCBkaXJlY3Rpb24gKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRjb3B5KCByYXkgKSB7XHJcblxyXG5cdFx0dGhpcy5vcmlnaW4uY29weSggcmF5Lm9yaWdpbiApO1xyXG5cdFx0dGhpcy5kaXJlY3Rpb24uY29weSggcmF5LmRpcmVjdGlvbiApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGF0KCB0LCB0YXJnZXQgKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRhcmdldC5jb3B5KCB0aGlzLm9yaWdpbiApLmFkZFNjYWxlZFZlY3RvciggdGhpcy5kaXJlY3Rpb24sIHQgKTtcclxuXHJcblx0fVxyXG5cclxuXHRsb29rQXQoIHYgKSB7XHJcblxyXG5cdFx0dGhpcy5kaXJlY3Rpb24uY29weSggdiApLnN1YiggdGhpcy5vcmlnaW4gKS5ub3JtYWxpemUoKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRyZWNhc3QoIHQgKSB7XHJcblxyXG5cdFx0dGhpcy5vcmlnaW4uY29weSggdGhpcy5hdCggdCwgX3ZlY3RvciApICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Y2xvc2VzdFBvaW50VG9Qb2ludCggcG9pbnQsIHRhcmdldCApIHtcclxuXHJcblx0XHR0YXJnZXQuc3ViVmVjdG9ycyggcG9pbnQsIHRoaXMub3JpZ2luICk7XHJcblxyXG5cdFx0Y29uc3QgZGlyZWN0aW9uRGlzdGFuY2UgPSB0YXJnZXQuZG90KCB0aGlzLmRpcmVjdGlvbiApO1xyXG5cclxuXHRcdGlmICggZGlyZWN0aW9uRGlzdGFuY2UgPCAwICkge1xyXG5cclxuXHRcdFx0cmV0dXJuIHRhcmdldC5jb3B5KCB0aGlzLm9yaWdpbiApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGFyZ2V0LmNvcHkoIHRoaXMub3JpZ2luICkuYWRkU2NhbGVkVmVjdG9yKCB0aGlzLmRpcmVjdGlvbiwgZGlyZWN0aW9uRGlzdGFuY2UgKTtcclxuXHJcblx0fVxyXG5cclxuXHRkaXN0YW5jZVRvUG9pbnQoIHBvaW50ICkge1xyXG5cclxuXHRcdHJldHVybiBNYXRoLnNxcnQoIHRoaXMuZGlzdGFuY2VTcVRvUG9pbnQoIHBvaW50ICkgKTtcclxuXHJcblx0fVxyXG5cclxuXHRkaXN0YW5jZVNxVG9Qb2ludCggcG9pbnQgKSB7XHJcblxyXG5cdFx0Y29uc3QgZGlyZWN0aW9uRGlzdGFuY2UgPSBfdmVjdG9yLnN1YlZlY3RvcnMoIHBvaW50LCB0aGlzLm9yaWdpbiApLmRvdCggdGhpcy5kaXJlY3Rpb24gKTtcclxuXHJcblx0XHQvLyBwb2ludCBiZWhpbmQgdGhlIHJheVxyXG5cclxuXHRcdGlmICggZGlyZWN0aW9uRGlzdGFuY2UgPCAwICkge1xyXG5cclxuXHRcdFx0cmV0dXJuIHRoaXMub3JpZ2luLmRpc3RhbmNlVG9TcXVhcmVkKCBwb2ludCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRfdmVjdG9yLmNvcHkoIHRoaXMub3JpZ2luICkuYWRkU2NhbGVkVmVjdG9yKCB0aGlzLmRpcmVjdGlvbiwgZGlyZWN0aW9uRGlzdGFuY2UgKTtcclxuXHJcblx0XHRyZXR1cm4gX3ZlY3Rvci5kaXN0YW5jZVRvU3F1YXJlZCggcG9pbnQgKTtcclxuXHJcblx0fVxyXG5cclxuXHRkaXN0YW5jZVNxVG9TZWdtZW50KCB2MCwgdjEsIG9wdGlvbmFsUG9pbnRPblJheSwgb3B0aW9uYWxQb2ludE9uU2VnbWVudCApIHtcclxuXHJcblx0XHQvLyBmcm9tIGh0dHBzOi8vZ2l0aHViLmNvbS9wbWpvbmlhay9HZW9tZXRyaWNUb29scy9ibG9iL21hc3Rlci9HVEVuZ2luZS9JbmNsdWRlL01hdGhlbWF0aWNzL0d0ZURpc3RSYXlTZWdtZW50LmhcclxuXHRcdC8vIEl0IHJldHVybnMgdGhlIG1pbiBkaXN0YW5jZSBiZXR3ZWVuIHRoZSByYXkgYW5kIHRoZSBzZWdtZW50XHJcblx0XHQvLyBkZWZpbmVkIGJ5IHYwIGFuZCB2MVxyXG5cdFx0Ly8gSXQgY2FuIGFsc28gc2V0IHR3byBvcHRpb25hbCB0YXJnZXRzIDpcclxuXHRcdC8vIC0gVGhlIGNsb3Nlc3QgcG9pbnQgb24gdGhlIHJheVxyXG5cdFx0Ly8gLSBUaGUgY2xvc2VzdCBwb2ludCBvbiB0aGUgc2VnbWVudFxyXG5cclxuXHRcdF9zZWdDZW50ZXIuY29weSggdjAgKS5hZGQoIHYxICkubXVsdGlwbHlTY2FsYXIoIDAuNSApO1xyXG5cdFx0X3NlZ0Rpci5jb3B5KCB2MSApLnN1YiggdjAgKS5ub3JtYWxpemUoKTtcclxuXHRcdF9kaWZmLmNvcHkoIHRoaXMub3JpZ2luICkuc3ViKCBfc2VnQ2VudGVyICk7XHJcblxyXG5cdFx0Y29uc3Qgc2VnRXh0ZW50ID0gdjAuZGlzdGFuY2VUbyggdjEgKSAqIDAuNTtcclxuXHRcdGNvbnN0IGEwMSA9IC0gdGhpcy5kaXJlY3Rpb24uZG90KCBfc2VnRGlyICk7XHJcblx0XHRjb25zdCBiMCA9IF9kaWZmLmRvdCggdGhpcy5kaXJlY3Rpb24gKTtcclxuXHRcdGNvbnN0IGIxID0gLSBfZGlmZi5kb3QoIF9zZWdEaXIgKTtcclxuXHRcdGNvbnN0IGMgPSBfZGlmZi5sZW5ndGhTcSgpO1xyXG5cdFx0Y29uc3QgZGV0ID0gTWF0aC5hYnMoIDEgLSBhMDEgKiBhMDEgKTtcclxuXHRcdGxldCBzMCwgczEsIHNxckRpc3QsIGV4dERldDtcclxuXHJcblx0XHRpZiAoIGRldCA+IDAgKSB7XHJcblxyXG5cdFx0XHQvLyBUaGUgcmF5IGFuZCBzZWdtZW50IGFyZSBub3QgcGFyYWxsZWwuXHJcblxyXG5cdFx0XHRzMCA9IGEwMSAqIGIxIC0gYjA7XHJcblx0XHRcdHMxID0gYTAxICogYjAgLSBiMTtcclxuXHRcdFx0ZXh0RGV0ID0gc2VnRXh0ZW50ICogZGV0O1xyXG5cclxuXHRcdFx0aWYgKCBzMCA+PSAwICkge1xyXG5cclxuXHRcdFx0XHRpZiAoIHMxID49IC0gZXh0RGV0ICkge1xyXG5cclxuXHRcdFx0XHRcdGlmICggczEgPD0gZXh0RGV0ICkge1xyXG5cclxuXHRcdFx0XHRcdFx0Ly8gcmVnaW9uIDBcclxuXHRcdFx0XHRcdFx0Ly8gTWluaW11bSBhdCBpbnRlcmlvciBwb2ludHMgb2YgcmF5IGFuZCBzZWdtZW50LlxyXG5cclxuXHRcdFx0XHRcdFx0Y29uc3QgaW52RGV0ID0gMSAvIGRldDtcclxuXHRcdFx0XHRcdFx0czAgKj0gaW52RGV0O1xyXG5cdFx0XHRcdFx0XHRzMSAqPSBpbnZEZXQ7XHJcblx0XHRcdFx0XHRcdHNxckRpc3QgPSBzMCAqICggczAgKyBhMDEgKiBzMSArIDIgKiBiMCApICsgczEgKiAoIGEwMSAqIHMwICsgczEgKyAyICogYjEgKSArIGM7XHJcblxyXG5cdFx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRcdC8vIHJlZ2lvbiAxXHJcblxyXG5cdFx0XHRcdFx0XHRzMSA9IHNlZ0V4dGVudDtcclxuXHRcdFx0XHRcdFx0czAgPSBNYXRoLm1heCggMCwgLSAoIGEwMSAqIHMxICsgYjAgKSApO1xyXG5cdFx0XHRcdFx0XHRzcXJEaXN0ID0gLSBzMCAqIHMwICsgczEgKiAoIHMxICsgMiAqIGIxICkgKyBjO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHQvLyByZWdpb24gNVxyXG5cclxuXHRcdFx0XHRcdHMxID0gLSBzZWdFeHRlbnQ7XHJcblx0XHRcdFx0XHRzMCA9IE1hdGgubWF4KCAwLCAtICggYTAxICogczEgKyBiMCApICk7XHJcblx0XHRcdFx0XHRzcXJEaXN0ID0gLSBzMCAqIHMwICsgczEgKiAoIHMxICsgMiAqIGIxICkgKyBjO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRpZiAoIHMxIDw9IC0gZXh0RGV0ICkge1xyXG5cclxuXHRcdFx0XHRcdC8vIHJlZ2lvbiA0XHJcblxyXG5cdFx0XHRcdFx0czAgPSBNYXRoLm1heCggMCwgLSAoIC0gYTAxICogc2VnRXh0ZW50ICsgYjAgKSApO1xyXG5cdFx0XHRcdFx0czEgPSAoIHMwID4gMCApID8gLSBzZWdFeHRlbnQgOiBNYXRoLm1pbiggTWF0aC5tYXgoIC0gc2VnRXh0ZW50LCAtIGIxICksIHNlZ0V4dGVudCApO1xyXG5cdFx0XHRcdFx0c3FyRGlzdCA9IC0gczAgKiBzMCArIHMxICogKCBzMSArIDIgKiBiMSApICsgYztcclxuXHJcblx0XHRcdFx0fSBlbHNlIGlmICggczEgPD0gZXh0RGV0ICkge1xyXG5cclxuXHRcdFx0XHRcdC8vIHJlZ2lvbiAzXHJcblxyXG5cdFx0XHRcdFx0czAgPSAwO1xyXG5cdFx0XHRcdFx0czEgPSBNYXRoLm1pbiggTWF0aC5tYXgoIC0gc2VnRXh0ZW50LCAtIGIxICksIHNlZ0V4dGVudCApO1xyXG5cdFx0XHRcdFx0c3FyRGlzdCA9IHMxICogKCBzMSArIDIgKiBiMSApICsgYztcclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHQvLyByZWdpb24gMlxyXG5cclxuXHRcdFx0XHRcdHMwID0gTWF0aC5tYXgoIDAsIC0gKCBhMDEgKiBzZWdFeHRlbnQgKyBiMCApICk7XHJcblx0XHRcdFx0XHRzMSA9ICggczAgPiAwICkgPyBzZWdFeHRlbnQgOiBNYXRoLm1pbiggTWF0aC5tYXgoIC0gc2VnRXh0ZW50LCAtIGIxICksIHNlZ0V4dGVudCApO1xyXG5cdFx0XHRcdFx0c3FyRGlzdCA9IC0gczAgKiBzMCArIHMxICogKCBzMSArIDIgKiBiMSApICsgYztcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHQvLyBSYXkgYW5kIHNlZ21lbnQgYXJlIHBhcmFsbGVsLlxyXG5cclxuXHRcdFx0czEgPSAoIGEwMSA+IDAgKSA/IC0gc2VnRXh0ZW50IDogc2VnRXh0ZW50O1xyXG5cdFx0XHRzMCA9IE1hdGgubWF4KCAwLCAtICggYTAxICogczEgKyBiMCApICk7XHJcblx0XHRcdHNxckRpc3QgPSAtIHMwICogczAgKyBzMSAqICggczEgKyAyICogYjEgKSArIGM7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggb3B0aW9uYWxQb2ludE9uUmF5ICkge1xyXG5cclxuXHRcdFx0b3B0aW9uYWxQb2ludE9uUmF5LmNvcHkoIHRoaXMub3JpZ2luICkuYWRkU2NhbGVkVmVjdG9yKCB0aGlzLmRpcmVjdGlvbiwgczAgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBvcHRpb25hbFBvaW50T25TZWdtZW50ICkge1xyXG5cclxuXHRcdFx0b3B0aW9uYWxQb2ludE9uU2VnbWVudC5jb3B5KCBfc2VnQ2VudGVyICkuYWRkU2NhbGVkVmVjdG9yKCBfc2VnRGlyLCBzMSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gc3FyRGlzdDtcclxuXHJcblx0fVxyXG5cclxuXHRpbnRlcnNlY3RTcGhlcmUoIHNwaGVyZSwgdGFyZ2V0ICkge1xyXG5cclxuXHRcdF92ZWN0b3Iuc3ViVmVjdG9ycyggc3BoZXJlLmNlbnRlciwgdGhpcy5vcmlnaW4gKTtcclxuXHRcdGNvbnN0IHRjYSA9IF92ZWN0b3IuZG90KCB0aGlzLmRpcmVjdGlvbiApO1xyXG5cdFx0Y29uc3QgZDIgPSBfdmVjdG9yLmRvdCggX3ZlY3RvciApIC0gdGNhICogdGNhO1xyXG5cdFx0Y29uc3QgcmFkaXVzMiA9IHNwaGVyZS5yYWRpdXMgKiBzcGhlcmUucmFkaXVzO1xyXG5cclxuXHRcdGlmICggZDIgPiByYWRpdXMyICkgcmV0dXJuIG51bGw7XHJcblxyXG5cdFx0Y29uc3QgdGhjID0gTWF0aC5zcXJ0KCByYWRpdXMyIC0gZDIgKTtcclxuXHJcblx0XHQvLyB0MCA9IGZpcnN0IGludGVyc2VjdCBwb2ludCAtIGVudHJhbmNlIG9uIGZyb250IG9mIHNwaGVyZVxyXG5cdFx0Y29uc3QgdDAgPSB0Y2EgLSB0aGM7XHJcblxyXG5cdFx0Ly8gdDEgPSBzZWNvbmQgaW50ZXJzZWN0IHBvaW50IC0gZXhpdCBwb2ludCBvbiBiYWNrIG9mIHNwaGVyZVxyXG5cdFx0Y29uc3QgdDEgPSB0Y2EgKyB0aGM7XHJcblxyXG5cdFx0Ly8gdGVzdCB0byBzZWUgaWYgdDEgaXMgYmVoaW5kIHRoZSByYXkgLSBpZiBzbywgcmV0dXJuIG51bGxcclxuXHRcdGlmICggdDEgPCAwICkgcmV0dXJuIG51bGw7XHJcblxyXG5cdFx0Ly8gdGVzdCB0byBzZWUgaWYgdDAgaXMgYmVoaW5kIHRoZSByYXk6XHJcblx0XHQvLyBpZiBpdCBpcywgdGhlIHJheSBpcyBpbnNpZGUgdGhlIHNwaGVyZSwgc28gcmV0dXJuIHRoZSBzZWNvbmQgZXhpdCBwb2ludCBzY2FsZWQgYnkgdDEsXHJcblx0XHQvLyBpbiBvcmRlciB0byBhbHdheXMgcmV0dXJuIGFuIGludGVyc2VjdCBwb2ludCB0aGF0IGlzIGluIGZyb250IG9mIHRoZSByYXkuXHJcblx0XHRpZiAoIHQwIDwgMCApIHJldHVybiB0aGlzLmF0KCB0MSwgdGFyZ2V0ICk7XHJcblxyXG5cdFx0Ly8gZWxzZSB0MCBpcyBpbiBmcm9udCBvZiB0aGUgcmF5LCBzbyByZXR1cm4gdGhlIGZpcnN0IGNvbGxpc2lvbiBwb2ludCBzY2FsZWQgYnkgdDBcclxuXHRcdHJldHVybiB0aGlzLmF0KCB0MCwgdGFyZ2V0ICk7XHJcblxyXG5cdH1cclxuXHJcblx0aW50ZXJzZWN0c1NwaGVyZSggc3BoZXJlICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLmRpc3RhbmNlU3FUb1BvaW50KCBzcGhlcmUuY2VudGVyICkgPD0gKCBzcGhlcmUucmFkaXVzICogc3BoZXJlLnJhZGl1cyApO1xyXG5cclxuXHR9XHJcblxyXG5cdGRpc3RhbmNlVG9QbGFuZSggcGxhbmUgKSB7XHJcblxyXG5cdFx0Y29uc3QgZGVub21pbmF0b3IgPSBwbGFuZS5ub3JtYWwuZG90KCB0aGlzLmRpcmVjdGlvbiApO1xyXG5cclxuXHRcdGlmICggZGVub21pbmF0b3IgPT09IDAgKSB7XHJcblxyXG5cdFx0XHQvLyBsaW5lIGlzIGNvcGxhbmFyLCByZXR1cm4gb3JpZ2luXHJcblx0XHRcdGlmICggcGxhbmUuZGlzdGFuY2VUb1BvaW50KCB0aGlzLm9yaWdpbiApID09PSAwICkge1xyXG5cclxuXHRcdFx0XHRyZXR1cm4gMDtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdC8vIE51bGwgaXMgcHJlZmVyYWJsZSB0byB1bmRlZmluZWQgc2luY2UgdW5kZWZpbmVkIG1lYW5zLi4uLiBpdCBpcyB1bmRlZmluZWRcclxuXHJcblx0XHRcdHJldHVybiBudWxsO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCB0ID0gLSAoIHRoaXMub3JpZ2luLmRvdCggcGxhbmUubm9ybWFsICkgKyBwbGFuZS5jb25zdGFudCApIC8gZGVub21pbmF0b3I7XHJcblxyXG5cdFx0Ly8gUmV0dXJuIGlmIHRoZSByYXkgbmV2ZXIgaW50ZXJzZWN0cyB0aGUgcGxhbmVcclxuXHJcblx0XHRyZXR1cm4gdCA+PSAwID8gdCA6IG51bGw7XHJcblxyXG5cdH1cclxuXHJcblx0aW50ZXJzZWN0UGxhbmUoIHBsYW5lLCB0YXJnZXQgKSB7XHJcblxyXG5cdFx0Y29uc3QgdCA9IHRoaXMuZGlzdGFuY2VUb1BsYW5lKCBwbGFuZSApO1xyXG5cclxuXHRcdGlmICggdCA9PT0gbnVsbCApIHtcclxuXHJcblx0XHRcdHJldHVybiBudWxsO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcy5hdCggdCwgdGFyZ2V0ICk7XHJcblxyXG5cdH1cclxuXHJcblx0aW50ZXJzZWN0c1BsYW5lKCBwbGFuZSApIHtcclxuXHJcblx0XHQvLyBjaGVjayBpZiB0aGUgcmF5IGxpZXMgb24gdGhlIHBsYW5lIGZpcnN0XHJcblxyXG5cdFx0Y29uc3QgZGlzdFRvUG9pbnQgPSBwbGFuZS5kaXN0YW5jZVRvUG9pbnQoIHRoaXMub3JpZ2luICk7XHJcblxyXG5cdFx0aWYgKCBkaXN0VG9Qb2ludCA9PT0gMCApIHtcclxuXHJcblx0XHRcdHJldHVybiB0cnVlO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCBkZW5vbWluYXRvciA9IHBsYW5lLm5vcm1hbC5kb3QoIHRoaXMuZGlyZWN0aW9uICk7XHJcblxyXG5cdFx0aWYgKCBkZW5vbWluYXRvciAqIGRpc3RUb1BvaW50IDwgMCApIHtcclxuXHJcblx0XHRcdHJldHVybiB0cnVlO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvLyByYXkgb3JpZ2luIGlzIGJlaGluZCB0aGUgcGxhbmUgKGFuZCBpcyBwb2ludGluZyBiZWhpbmQgaXQpXHJcblxyXG5cdFx0cmV0dXJuIGZhbHNlO1xyXG5cclxuXHR9XHJcblxyXG5cdGludGVyc2VjdEJveCggYm94LCB0YXJnZXQgKSB7XHJcblxyXG5cdFx0bGV0IHRtaW4sIHRtYXgsIHR5bWluLCB0eW1heCwgdHptaW4sIHR6bWF4O1xyXG5cclxuXHRcdGNvbnN0IGludmRpcnggPSAxIC8gdGhpcy5kaXJlY3Rpb24ueCxcclxuXHRcdFx0aW52ZGlyeSA9IDEgLyB0aGlzLmRpcmVjdGlvbi55LFxyXG5cdFx0XHRpbnZkaXJ6ID0gMSAvIHRoaXMuZGlyZWN0aW9uLno7XHJcblxyXG5cdFx0Y29uc3Qgb3JpZ2luID0gdGhpcy5vcmlnaW47XHJcblxyXG5cdFx0aWYgKCBpbnZkaXJ4ID49IDAgKSB7XHJcblxyXG5cdFx0XHR0bWluID0gKCBib3gubWluLnggLSBvcmlnaW4ueCApICogaW52ZGlyeDtcclxuXHRcdFx0dG1heCA9ICggYm94Lm1heC54IC0gb3JpZ2luLnggKSAqIGludmRpcng7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdHRtaW4gPSAoIGJveC5tYXgueCAtIG9yaWdpbi54ICkgKiBpbnZkaXJ4O1xyXG5cdFx0XHR0bWF4ID0gKCBib3gubWluLnggLSBvcmlnaW4ueCApICogaW52ZGlyeDtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBpbnZkaXJ5ID49IDAgKSB7XHJcblxyXG5cdFx0XHR0eW1pbiA9ICggYm94Lm1pbi55IC0gb3JpZ2luLnkgKSAqIGludmRpcnk7XHJcblx0XHRcdHR5bWF4ID0gKCBib3gubWF4LnkgLSBvcmlnaW4ueSApICogaW52ZGlyeTtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0dHltaW4gPSAoIGJveC5tYXgueSAtIG9yaWdpbi55ICkgKiBpbnZkaXJ5O1xyXG5cdFx0XHR0eW1heCA9ICggYm94Lm1pbi55IC0gb3JpZ2luLnkgKSAqIGludmRpcnk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggKCB0bWluID4gdHltYXggKSB8fCAoIHR5bWluID4gdG1heCApICkgcmV0dXJuIG51bGw7XHJcblxyXG5cdFx0aWYgKCB0eW1pbiA+IHRtaW4gfHwgaXNOYU4oIHRtaW4gKSApIHRtaW4gPSB0eW1pbjtcclxuXHJcblx0XHRpZiAoIHR5bWF4IDwgdG1heCB8fCBpc05hTiggdG1heCApICkgdG1heCA9IHR5bWF4O1xyXG5cclxuXHRcdGlmICggaW52ZGlyeiA+PSAwICkge1xyXG5cclxuXHRcdFx0dHptaW4gPSAoIGJveC5taW4ueiAtIG9yaWdpbi56ICkgKiBpbnZkaXJ6O1xyXG5cdFx0XHR0em1heCA9ICggYm94Lm1heC56IC0gb3JpZ2luLnogKSAqIGludmRpcno7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdHR6bWluID0gKCBib3gubWF4LnogLSBvcmlnaW4ueiApICogaW52ZGlyejtcclxuXHRcdFx0dHptYXggPSAoIGJveC5taW4ueiAtIG9yaWdpbi56ICkgKiBpbnZkaXJ6O1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoICggdG1pbiA+IHR6bWF4ICkgfHwgKCB0em1pbiA+IHRtYXggKSApIHJldHVybiBudWxsO1xyXG5cclxuXHRcdGlmICggdHptaW4gPiB0bWluIHx8IHRtaW4gIT09IHRtaW4gKSB0bWluID0gdHptaW47XHJcblxyXG5cdFx0aWYgKCB0em1heCA8IHRtYXggfHwgdG1heCAhPT0gdG1heCApIHRtYXggPSB0em1heDtcclxuXHJcblx0XHQvL3JldHVybiBwb2ludCBjbG9zZXN0IHRvIHRoZSByYXkgKHBvc2l0aXZlIHNpZGUpXHJcblxyXG5cdFx0aWYgKCB0bWF4IDwgMCApIHJldHVybiBudWxsO1xyXG5cclxuXHRcdHJldHVybiB0aGlzLmF0KCB0bWluID49IDAgPyB0bWluIDogdG1heCwgdGFyZ2V0ICk7XHJcblxyXG5cdH1cclxuXHJcblx0aW50ZXJzZWN0c0JveCggYm94ICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLmludGVyc2VjdEJveCggYm94LCBfdmVjdG9yICkgIT09IG51bGw7XHJcblxyXG5cdH1cclxuXHJcblx0aW50ZXJzZWN0VHJpYW5nbGUoIGEsIGIsIGMsIGJhY2tmYWNlQ3VsbGluZywgdGFyZ2V0ICkge1xyXG5cclxuXHRcdC8vIENvbXB1dGUgdGhlIG9mZnNldCBvcmlnaW4sIGVkZ2VzLCBhbmQgbm9ybWFsLlxyXG5cclxuXHRcdC8vIGZyb20gaHR0cHM6Ly9naXRodWIuY29tL3Btam9uaWFrL0dlb21ldHJpY1Rvb2xzL2Jsb2IvbWFzdGVyL0dURW5naW5lL0luY2x1ZGUvTWF0aGVtYXRpY3MvR3RlSW50clJheTNUcmlhbmdsZTMuaFxyXG5cclxuXHRcdF9lZGdlMS5zdWJWZWN0b3JzKCBiLCBhICk7XHJcblx0XHRfZWRnZTIuc3ViVmVjdG9ycyggYywgYSApO1xyXG5cdFx0X25vcm1hbC5jcm9zc1ZlY3RvcnMoIF9lZGdlMSwgX2VkZ2UyICk7XHJcblxyXG5cdFx0Ly8gU29sdmUgUSArIHQqRCA9IGIxKkUxICsgYjIqRTIgKFEgPSBrRGlmZiwgRCA9IHJheSBkaXJlY3Rpb24sXHJcblx0XHQvLyBFMSA9IGtFZGdlMSwgRTIgPSBrRWRnZTIsIE4gPSBDcm9zcyhFMSxFMikpIGJ5XHJcblx0XHQvLyAgIHxEb3QoRCxOKXwqYjEgPSBzaWduKERvdChELE4pKSpEb3QoRCxDcm9zcyhRLEUyKSlcclxuXHRcdC8vICAgfERvdChELE4pfCpiMiA9IHNpZ24oRG90KEQsTikpKkRvdChELENyb3NzKEUxLFEpKVxyXG5cdFx0Ly8gICB8RG90KEQsTil8KnQgPSAtc2lnbihEb3QoRCxOKSkqRG90KFEsTilcclxuXHRcdGxldCBEZE4gPSB0aGlzLmRpcmVjdGlvbi5kb3QoIF9ub3JtYWwgKTtcclxuXHRcdGxldCBzaWduO1xyXG5cclxuXHRcdGlmICggRGROID4gMCApIHtcclxuXHJcblx0XHRcdGlmICggYmFja2ZhY2VDdWxsaW5nICkgcmV0dXJuIG51bGw7XHJcblx0XHRcdHNpZ24gPSAxO1xyXG5cclxuXHRcdH0gZWxzZSBpZiAoIERkTiA8IDAgKSB7XHJcblxyXG5cdFx0XHRzaWduID0gLSAxO1xyXG5cdFx0XHREZE4gPSAtIERkTjtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0cmV0dXJuIG51bGw7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdF9kaWZmLnN1YlZlY3RvcnMoIHRoaXMub3JpZ2luLCBhICk7XHJcblx0XHRjb25zdCBEZFF4RTIgPSBzaWduICogdGhpcy5kaXJlY3Rpb24uZG90KCBfZWRnZTIuY3Jvc3NWZWN0b3JzKCBfZGlmZiwgX2VkZ2UyICkgKTtcclxuXHJcblx0XHQvLyBiMSA8IDAsIG5vIGludGVyc2VjdGlvblxyXG5cdFx0aWYgKCBEZFF4RTIgPCAwICkge1xyXG5cclxuXHRcdFx0cmV0dXJuIG51bGw7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGNvbnN0IERkRTF4USA9IHNpZ24gKiB0aGlzLmRpcmVjdGlvbi5kb3QoIF9lZGdlMS5jcm9zcyggX2RpZmYgKSApO1xyXG5cclxuXHRcdC8vIGIyIDwgMCwgbm8gaW50ZXJzZWN0aW9uXHJcblx0XHRpZiAoIERkRTF4USA8IDAgKSB7XHJcblxyXG5cdFx0XHRyZXR1cm4gbnVsbDtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gYjErYjIgPiAxLCBubyBpbnRlcnNlY3Rpb25cclxuXHRcdGlmICggRGRReEUyICsgRGRFMXhRID4gRGROICkge1xyXG5cclxuXHRcdFx0cmV0dXJuIG51bGw7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIExpbmUgaW50ZXJzZWN0cyB0cmlhbmdsZSwgY2hlY2sgaWYgcmF5IGRvZXMuXHJcblx0XHRjb25zdCBRZE4gPSAtIHNpZ24gKiBfZGlmZi5kb3QoIF9ub3JtYWwgKTtcclxuXHJcblx0XHQvLyB0IDwgMCwgbm8gaW50ZXJzZWN0aW9uXHJcblx0XHRpZiAoIFFkTiA8IDAgKSB7XHJcblxyXG5cdFx0XHRyZXR1cm4gbnVsbDtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gUmF5IGludGVyc2VjdHMgdHJpYW5nbGUuXHJcblx0XHRyZXR1cm4gdGhpcy5hdCggUWROIC8gRGROLCB0YXJnZXQgKTtcclxuXHJcblx0fVxyXG5cclxuXHRhcHBseU1hdHJpeDQoIG1hdHJpeDQgKSB7XHJcblxyXG5cdFx0dGhpcy5vcmlnaW4uYXBwbHlNYXRyaXg0KCBtYXRyaXg0ICk7XHJcblx0XHR0aGlzLmRpcmVjdGlvbi50cmFuc2Zvcm1EaXJlY3Rpb24oIG1hdHJpeDQgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRlcXVhbHMoIHJheSApIHtcclxuXHJcblx0XHRyZXR1cm4gcmF5Lm9yaWdpbi5lcXVhbHMoIHRoaXMub3JpZ2luICkgJiYgcmF5LmRpcmVjdGlvbi5lcXVhbHMoIHRoaXMuZGlyZWN0aW9uICk7XHJcblxyXG5cdH1cclxuXHJcblx0Y2xvbmUoKSB7XHJcblxyXG5cdFx0cmV0dXJuIG5ldyB0aGlzLmNvbnN0cnVjdG9yKCkuY29weSggdGhpcyApO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBSYXkgfTtcclxuIiwiaW1wb3J0IHsgV2ViR0xDb29yZGluYXRlU3lzdGVtLCBXZWJHUFVDb29yZGluYXRlU3lzdGVtIH0gZnJvbSAnLi4vY29uc3RhbnRzLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yMyB9IGZyb20gJy4vVmVjdG9yMy5qcyc7XHJcblxyXG5jbGFzcyBNYXRyaXg0IHtcclxuXHJcblx0Y29uc3RydWN0b3IoIG4xMSwgbjEyLCBuMTMsIG4xNCwgbjIxLCBuMjIsIG4yMywgbjI0LCBuMzEsIG4zMiwgbjMzLCBuMzQsIG40MSwgbjQyLCBuNDMsIG40NCApIHtcclxuXHJcblx0XHRNYXRyaXg0LnByb3RvdHlwZS5pc01hdHJpeDQgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMuZWxlbWVudHMgPSBbXHJcblxyXG5cdFx0XHQxLCAwLCAwLCAwLFxyXG5cdFx0XHQwLCAxLCAwLCAwLFxyXG5cdFx0XHQwLCAwLCAxLCAwLFxyXG5cdFx0XHQwLCAwLCAwLCAxXHJcblxyXG5cdFx0XTtcclxuXHJcblx0XHRpZiAoIG4xMSAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0dGhpcy5zZXQoIG4xMSwgbjEyLCBuMTMsIG4xNCwgbjIxLCBuMjIsIG4yMywgbjI0LCBuMzEsIG4zMiwgbjMzLCBuMzQsIG40MSwgbjQyLCBuNDMsIG40NCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRzZXQoIG4xMSwgbjEyLCBuMTMsIG4xNCwgbjIxLCBuMjIsIG4yMywgbjI0LCBuMzEsIG4zMiwgbjMzLCBuMzQsIG40MSwgbjQyLCBuNDMsIG40NCApIHtcclxuXHJcblx0XHRjb25zdCB0ZSA9IHRoaXMuZWxlbWVudHM7XHJcblxyXG5cdFx0dGVbIDAgXSA9IG4xMTsgdGVbIDQgXSA9IG4xMjsgdGVbIDggXSA9IG4xMzsgdGVbIDEyIF0gPSBuMTQ7XHJcblx0XHR0ZVsgMSBdID0gbjIxOyB0ZVsgNSBdID0gbjIyOyB0ZVsgOSBdID0gbjIzOyB0ZVsgMTMgXSA9IG4yNDtcclxuXHRcdHRlWyAyIF0gPSBuMzE7IHRlWyA2IF0gPSBuMzI7IHRlWyAxMCBdID0gbjMzOyB0ZVsgMTQgXSA9IG4zNDtcclxuXHRcdHRlWyAzIF0gPSBuNDE7IHRlWyA3IF0gPSBuNDI7IHRlWyAxMSBdID0gbjQzOyB0ZVsgMTUgXSA9IG40NDtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRpZGVudGl0eSgpIHtcclxuXHJcblx0XHR0aGlzLnNldChcclxuXHJcblx0XHRcdDEsIDAsIDAsIDAsXHJcblx0XHRcdDAsIDEsIDAsIDAsXHJcblx0XHRcdDAsIDAsIDEsIDAsXHJcblx0XHRcdDAsIDAsIDAsIDFcclxuXHJcblx0XHQpO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGNsb25lKCkge1xyXG5cclxuXHRcdHJldHVybiBuZXcgTWF0cml4NCgpLmZyb21BcnJheSggdGhpcy5lbGVtZW50cyApO1xyXG5cclxuXHR9XHJcblxyXG5cdGNvcHkoIG0gKSB7XHJcblxyXG5cdFx0Y29uc3QgdGUgPSB0aGlzLmVsZW1lbnRzO1xyXG5cdFx0Y29uc3QgbWUgPSBtLmVsZW1lbnRzO1xyXG5cclxuXHRcdHRlWyAwIF0gPSBtZVsgMCBdOyB0ZVsgMSBdID0gbWVbIDEgXTsgdGVbIDIgXSA9IG1lWyAyIF07IHRlWyAzIF0gPSBtZVsgMyBdO1xyXG5cdFx0dGVbIDQgXSA9IG1lWyA0IF07IHRlWyA1IF0gPSBtZVsgNSBdOyB0ZVsgNiBdID0gbWVbIDYgXTsgdGVbIDcgXSA9IG1lWyA3IF07XHJcblx0XHR0ZVsgOCBdID0gbWVbIDggXTsgdGVbIDkgXSA9IG1lWyA5IF07IHRlWyAxMCBdID0gbWVbIDEwIF07IHRlWyAxMSBdID0gbWVbIDExIF07XHJcblx0XHR0ZVsgMTIgXSA9IG1lWyAxMiBdOyB0ZVsgMTMgXSA9IG1lWyAxMyBdOyB0ZVsgMTQgXSA9IG1lWyAxNCBdOyB0ZVsgMTUgXSA9IG1lWyAxNSBdO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGNvcHlQb3NpdGlvbiggbSApIHtcclxuXHJcblx0XHRjb25zdCB0ZSA9IHRoaXMuZWxlbWVudHMsIG1lID0gbS5lbGVtZW50cztcclxuXHJcblx0XHR0ZVsgMTIgXSA9IG1lWyAxMiBdO1xyXG5cdFx0dGVbIDEzIF0gPSBtZVsgMTMgXTtcclxuXHRcdHRlWyAxNCBdID0gbWVbIDE0IF07XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0RnJvbU1hdHJpeDMoIG0gKSB7XHJcblxyXG5cdFx0Y29uc3QgbWUgPSBtLmVsZW1lbnRzO1xyXG5cclxuXHRcdHRoaXMuc2V0KFxyXG5cclxuXHRcdFx0bWVbIDAgXSwgbWVbIDMgXSwgbWVbIDYgXSwgMCxcclxuXHRcdFx0bWVbIDEgXSwgbWVbIDQgXSwgbWVbIDcgXSwgMCxcclxuXHRcdFx0bWVbIDIgXSwgbWVbIDUgXSwgbWVbIDggXSwgMCxcclxuXHRcdFx0MCwgMCwgMCwgMVxyXG5cclxuXHRcdCk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0ZXh0cmFjdEJhc2lzKCB4QXhpcywgeUF4aXMsIHpBeGlzICkge1xyXG5cclxuXHRcdHhBeGlzLnNldEZyb21NYXRyaXhDb2x1bW4oIHRoaXMsIDAgKTtcclxuXHRcdHlBeGlzLnNldEZyb21NYXRyaXhDb2x1bW4oIHRoaXMsIDEgKTtcclxuXHRcdHpBeGlzLnNldEZyb21NYXRyaXhDb2x1bW4oIHRoaXMsIDIgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRtYWtlQmFzaXMoIHhBeGlzLCB5QXhpcywgekF4aXMgKSB7XHJcblxyXG5cdFx0dGhpcy5zZXQoXHJcblx0XHRcdHhBeGlzLngsIHlBeGlzLngsIHpBeGlzLngsIDAsXHJcblx0XHRcdHhBeGlzLnksIHlBeGlzLnksIHpBeGlzLnksIDAsXHJcblx0XHRcdHhBeGlzLnosIHlBeGlzLnosIHpBeGlzLnosIDAsXHJcblx0XHRcdDAsIDAsIDAsIDFcclxuXHRcdCk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0ZXh0cmFjdFJvdGF0aW9uKCBtICkge1xyXG5cclxuXHRcdC8vIHRoaXMgbWV0aG9kIGRvZXMgbm90IHN1cHBvcnQgcmVmbGVjdGlvbiBtYXRyaWNlc1xyXG5cclxuXHRcdGNvbnN0IHRlID0gdGhpcy5lbGVtZW50cztcclxuXHRcdGNvbnN0IG1lID0gbS5lbGVtZW50cztcclxuXHJcblx0XHRjb25zdCBzY2FsZVggPSAxIC8gX3YxLnNldEZyb21NYXRyaXhDb2x1bW4oIG0sIDAgKS5sZW5ndGgoKTtcclxuXHRcdGNvbnN0IHNjYWxlWSA9IDEgLyBfdjEuc2V0RnJvbU1hdHJpeENvbHVtbiggbSwgMSApLmxlbmd0aCgpO1xyXG5cdFx0Y29uc3Qgc2NhbGVaID0gMSAvIF92MS5zZXRGcm9tTWF0cml4Q29sdW1uKCBtLCAyICkubGVuZ3RoKCk7XHJcblxyXG5cdFx0dGVbIDAgXSA9IG1lWyAwIF0gKiBzY2FsZVg7XHJcblx0XHR0ZVsgMSBdID0gbWVbIDEgXSAqIHNjYWxlWDtcclxuXHRcdHRlWyAyIF0gPSBtZVsgMiBdICogc2NhbGVYO1xyXG5cdFx0dGVbIDMgXSA9IDA7XHJcblxyXG5cdFx0dGVbIDQgXSA9IG1lWyA0IF0gKiBzY2FsZVk7XHJcblx0XHR0ZVsgNSBdID0gbWVbIDUgXSAqIHNjYWxlWTtcclxuXHRcdHRlWyA2IF0gPSBtZVsgNiBdICogc2NhbGVZO1xyXG5cdFx0dGVbIDcgXSA9IDA7XHJcblxyXG5cdFx0dGVbIDggXSA9IG1lWyA4IF0gKiBzY2FsZVo7XHJcblx0XHR0ZVsgOSBdID0gbWVbIDkgXSAqIHNjYWxlWjtcclxuXHRcdHRlWyAxMCBdID0gbWVbIDEwIF0gKiBzY2FsZVo7XHJcblx0XHR0ZVsgMTEgXSA9IDA7XHJcblxyXG5cdFx0dGVbIDEyIF0gPSAwO1xyXG5cdFx0dGVbIDEzIF0gPSAwO1xyXG5cdFx0dGVbIDE0IF0gPSAwO1xyXG5cdFx0dGVbIDE1IF0gPSAxO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdG1ha2VSb3RhdGlvbkZyb21FdWxlciggZXVsZXIgKSB7XHJcblxyXG5cdFx0Y29uc3QgdGUgPSB0aGlzLmVsZW1lbnRzO1xyXG5cclxuXHRcdGNvbnN0IHggPSBldWxlci54LCB5ID0gZXVsZXIueSwgeiA9IGV1bGVyLno7XHJcblx0XHRjb25zdCBhID0gTWF0aC5jb3MoIHggKSwgYiA9IE1hdGguc2luKCB4ICk7XHJcblx0XHRjb25zdCBjID0gTWF0aC5jb3MoIHkgKSwgZCA9IE1hdGguc2luKCB5ICk7XHJcblx0XHRjb25zdCBlID0gTWF0aC5jb3MoIHogKSwgZiA9IE1hdGguc2luKCB6ICk7XHJcblxyXG5cdFx0aWYgKCBldWxlci5vcmRlciA9PT0gJ1hZWicgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBhZSA9IGEgKiBlLCBhZiA9IGEgKiBmLCBiZSA9IGIgKiBlLCBiZiA9IGIgKiBmO1xyXG5cclxuXHRcdFx0dGVbIDAgXSA9IGMgKiBlO1xyXG5cdFx0XHR0ZVsgNCBdID0gLSBjICogZjtcclxuXHRcdFx0dGVbIDggXSA9IGQ7XHJcblxyXG5cdFx0XHR0ZVsgMSBdID0gYWYgKyBiZSAqIGQ7XHJcblx0XHRcdHRlWyA1IF0gPSBhZSAtIGJmICogZDtcclxuXHRcdFx0dGVbIDkgXSA9IC0gYiAqIGM7XHJcblxyXG5cdFx0XHR0ZVsgMiBdID0gYmYgLSBhZSAqIGQ7XHJcblx0XHRcdHRlWyA2IF0gPSBiZSArIGFmICogZDtcclxuXHRcdFx0dGVbIDEwIF0gPSBhICogYztcclxuXHJcblx0XHR9IGVsc2UgaWYgKCBldWxlci5vcmRlciA9PT0gJ1lYWicgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBjZSA9IGMgKiBlLCBjZiA9IGMgKiBmLCBkZSA9IGQgKiBlLCBkZiA9IGQgKiBmO1xyXG5cclxuXHRcdFx0dGVbIDAgXSA9IGNlICsgZGYgKiBiO1xyXG5cdFx0XHR0ZVsgNCBdID0gZGUgKiBiIC0gY2Y7XHJcblx0XHRcdHRlWyA4IF0gPSBhICogZDtcclxuXHJcblx0XHRcdHRlWyAxIF0gPSBhICogZjtcclxuXHRcdFx0dGVbIDUgXSA9IGEgKiBlO1xyXG5cdFx0XHR0ZVsgOSBdID0gLSBiO1xyXG5cclxuXHRcdFx0dGVbIDIgXSA9IGNmICogYiAtIGRlO1xyXG5cdFx0XHR0ZVsgNiBdID0gZGYgKyBjZSAqIGI7XHJcblx0XHRcdHRlWyAxMCBdID0gYSAqIGM7XHJcblxyXG5cdFx0fSBlbHNlIGlmICggZXVsZXIub3JkZXIgPT09ICdaWFknICkge1xyXG5cclxuXHRcdFx0Y29uc3QgY2UgPSBjICogZSwgY2YgPSBjICogZiwgZGUgPSBkICogZSwgZGYgPSBkICogZjtcclxuXHJcblx0XHRcdHRlWyAwIF0gPSBjZSAtIGRmICogYjtcclxuXHRcdFx0dGVbIDQgXSA9IC0gYSAqIGY7XHJcblx0XHRcdHRlWyA4IF0gPSBkZSArIGNmICogYjtcclxuXHJcblx0XHRcdHRlWyAxIF0gPSBjZiArIGRlICogYjtcclxuXHRcdFx0dGVbIDUgXSA9IGEgKiBlO1xyXG5cdFx0XHR0ZVsgOSBdID0gZGYgLSBjZSAqIGI7XHJcblxyXG5cdFx0XHR0ZVsgMiBdID0gLSBhICogZDtcclxuXHRcdFx0dGVbIDYgXSA9IGI7XHJcblx0XHRcdHRlWyAxMCBdID0gYSAqIGM7XHJcblxyXG5cdFx0fSBlbHNlIGlmICggZXVsZXIub3JkZXIgPT09ICdaWVgnICkge1xyXG5cclxuXHRcdFx0Y29uc3QgYWUgPSBhICogZSwgYWYgPSBhICogZiwgYmUgPSBiICogZSwgYmYgPSBiICogZjtcclxuXHJcblx0XHRcdHRlWyAwIF0gPSBjICogZTtcclxuXHRcdFx0dGVbIDQgXSA9IGJlICogZCAtIGFmO1xyXG5cdFx0XHR0ZVsgOCBdID0gYWUgKiBkICsgYmY7XHJcblxyXG5cdFx0XHR0ZVsgMSBdID0gYyAqIGY7XHJcblx0XHRcdHRlWyA1IF0gPSBiZiAqIGQgKyBhZTtcclxuXHRcdFx0dGVbIDkgXSA9IGFmICogZCAtIGJlO1xyXG5cclxuXHRcdFx0dGVbIDIgXSA9IC0gZDtcclxuXHRcdFx0dGVbIDYgXSA9IGIgKiBjO1xyXG5cdFx0XHR0ZVsgMTAgXSA9IGEgKiBjO1xyXG5cclxuXHRcdH0gZWxzZSBpZiAoIGV1bGVyLm9yZGVyID09PSAnWVpYJyApIHtcclxuXHJcblx0XHRcdGNvbnN0IGFjID0gYSAqIGMsIGFkID0gYSAqIGQsIGJjID0gYiAqIGMsIGJkID0gYiAqIGQ7XHJcblxyXG5cdFx0XHR0ZVsgMCBdID0gYyAqIGU7XHJcblx0XHRcdHRlWyA0IF0gPSBiZCAtIGFjICogZjtcclxuXHRcdFx0dGVbIDggXSA9IGJjICogZiArIGFkO1xyXG5cclxuXHRcdFx0dGVbIDEgXSA9IGY7XHJcblx0XHRcdHRlWyA1IF0gPSBhICogZTtcclxuXHRcdFx0dGVbIDkgXSA9IC0gYiAqIGU7XHJcblxyXG5cdFx0XHR0ZVsgMiBdID0gLSBkICogZTtcclxuXHRcdFx0dGVbIDYgXSA9IGFkICogZiArIGJjO1xyXG5cdFx0XHR0ZVsgMTAgXSA9IGFjIC0gYmQgKiBmO1xyXG5cclxuXHRcdH0gZWxzZSBpZiAoIGV1bGVyLm9yZGVyID09PSAnWFpZJyApIHtcclxuXHJcblx0XHRcdGNvbnN0IGFjID0gYSAqIGMsIGFkID0gYSAqIGQsIGJjID0gYiAqIGMsIGJkID0gYiAqIGQ7XHJcblxyXG5cdFx0XHR0ZVsgMCBdID0gYyAqIGU7XHJcblx0XHRcdHRlWyA0IF0gPSAtIGY7XHJcblx0XHRcdHRlWyA4IF0gPSBkICogZTtcclxuXHJcblx0XHRcdHRlWyAxIF0gPSBhYyAqIGYgKyBiZDtcclxuXHRcdFx0dGVbIDUgXSA9IGEgKiBlO1xyXG5cdFx0XHR0ZVsgOSBdID0gYWQgKiBmIC0gYmM7XHJcblxyXG5cdFx0XHR0ZVsgMiBdID0gYmMgKiBmIC0gYWQ7XHJcblx0XHRcdHRlWyA2IF0gPSBiICogZTtcclxuXHRcdFx0dGVbIDEwIF0gPSBiZCAqIGYgKyBhYztcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gYm90dG9tIHJvd1xyXG5cdFx0dGVbIDMgXSA9IDA7XHJcblx0XHR0ZVsgNyBdID0gMDtcclxuXHRcdHRlWyAxMSBdID0gMDtcclxuXHJcblx0XHQvLyBsYXN0IGNvbHVtblxyXG5cdFx0dGVbIDEyIF0gPSAwO1xyXG5cdFx0dGVbIDEzIF0gPSAwO1xyXG5cdFx0dGVbIDE0IF0gPSAwO1xyXG5cdFx0dGVbIDE1IF0gPSAxO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdG1ha2VSb3RhdGlvbkZyb21RdWF0ZXJuaW9uKCBxICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLmNvbXBvc2UoIF96ZXJvLCBxLCBfb25lICk7XHJcblxyXG5cdH1cclxuXHJcblx0bG9va0F0KCBleWUsIHRhcmdldCwgdXAgKSB7XHJcblxyXG5cdFx0Y29uc3QgdGUgPSB0aGlzLmVsZW1lbnRzO1xyXG5cclxuXHRcdF96LnN1YlZlY3RvcnMoIGV5ZSwgdGFyZ2V0ICk7XHJcblxyXG5cdFx0aWYgKCBfei5sZW5ndGhTcSgpID09PSAwICkge1xyXG5cclxuXHRcdFx0Ly8gZXllIGFuZCB0YXJnZXQgYXJlIGluIHRoZSBzYW1lIHBvc2l0aW9uXHJcblxyXG5cdFx0XHRfei56ID0gMTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0X3oubm9ybWFsaXplKCk7XHJcblx0XHRfeC5jcm9zc1ZlY3RvcnMoIHVwLCBfeiApO1xyXG5cclxuXHRcdGlmICggX3gubGVuZ3RoU3EoKSA9PT0gMCApIHtcclxuXHJcblx0XHRcdC8vIHVwIGFuZCB6IGFyZSBwYXJhbGxlbFxyXG5cclxuXHRcdFx0aWYgKCBNYXRoLmFicyggdXAueiApID09PSAxICkge1xyXG5cclxuXHRcdFx0XHRfei54ICs9IDAuMDAwMTtcclxuXHJcblx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdF96LnogKz0gMC4wMDAxO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0X3oubm9ybWFsaXplKCk7XHJcblx0XHRcdF94LmNyb3NzVmVjdG9ycyggdXAsIF96ICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdF94Lm5vcm1hbGl6ZSgpO1xyXG5cdFx0X3kuY3Jvc3NWZWN0b3JzKCBfeiwgX3ggKTtcclxuXHJcblx0XHR0ZVsgMCBdID0gX3gueDsgdGVbIDQgXSA9IF95Lng7IHRlWyA4IF0gPSBfei54O1xyXG5cdFx0dGVbIDEgXSA9IF94Lnk7IHRlWyA1IF0gPSBfeS55OyB0ZVsgOSBdID0gX3oueTtcclxuXHRcdHRlWyAyIF0gPSBfeC56OyB0ZVsgNiBdID0gX3kuejsgdGVbIDEwIF0gPSBfei56O1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdG11bHRpcGx5KCBtICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLm11bHRpcGx5TWF0cmljZXMoIHRoaXMsIG0gKTtcclxuXHJcblx0fVxyXG5cclxuXHRwcmVtdWx0aXBseSggbSApIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5tdWx0aXBseU1hdHJpY2VzKCBtLCB0aGlzICk7XHJcblxyXG5cdH1cclxuXHJcblx0bXVsdGlwbHlNYXRyaWNlcyggYSwgYiApIHtcclxuXHJcblx0XHRjb25zdCBhZSA9IGEuZWxlbWVudHM7XHJcblx0XHRjb25zdCBiZSA9IGIuZWxlbWVudHM7XHJcblx0XHRjb25zdCB0ZSA9IHRoaXMuZWxlbWVudHM7XHJcblxyXG5cdFx0Y29uc3QgYTExID0gYWVbIDAgXSwgYTEyID0gYWVbIDQgXSwgYTEzID0gYWVbIDggXSwgYTE0ID0gYWVbIDEyIF07XHJcblx0XHRjb25zdCBhMjEgPSBhZVsgMSBdLCBhMjIgPSBhZVsgNSBdLCBhMjMgPSBhZVsgOSBdLCBhMjQgPSBhZVsgMTMgXTtcclxuXHRcdGNvbnN0IGEzMSA9IGFlWyAyIF0sIGEzMiA9IGFlWyA2IF0sIGEzMyA9IGFlWyAxMCBdLCBhMzQgPSBhZVsgMTQgXTtcclxuXHRcdGNvbnN0IGE0MSA9IGFlWyAzIF0sIGE0MiA9IGFlWyA3IF0sIGE0MyA9IGFlWyAxMSBdLCBhNDQgPSBhZVsgMTUgXTtcclxuXHJcblx0XHRjb25zdCBiMTEgPSBiZVsgMCBdLCBiMTIgPSBiZVsgNCBdLCBiMTMgPSBiZVsgOCBdLCBiMTQgPSBiZVsgMTIgXTtcclxuXHRcdGNvbnN0IGIyMSA9IGJlWyAxIF0sIGIyMiA9IGJlWyA1IF0sIGIyMyA9IGJlWyA5IF0sIGIyNCA9IGJlWyAxMyBdO1xyXG5cdFx0Y29uc3QgYjMxID0gYmVbIDIgXSwgYjMyID0gYmVbIDYgXSwgYjMzID0gYmVbIDEwIF0sIGIzNCA9IGJlWyAxNCBdO1xyXG5cdFx0Y29uc3QgYjQxID0gYmVbIDMgXSwgYjQyID0gYmVbIDcgXSwgYjQzID0gYmVbIDExIF0sIGI0NCA9IGJlWyAxNSBdO1xyXG5cclxuXHRcdHRlWyAwIF0gPSBhMTEgKiBiMTEgKyBhMTIgKiBiMjEgKyBhMTMgKiBiMzEgKyBhMTQgKiBiNDE7XHJcblx0XHR0ZVsgNCBdID0gYTExICogYjEyICsgYTEyICogYjIyICsgYTEzICogYjMyICsgYTE0ICogYjQyO1xyXG5cdFx0dGVbIDggXSA9IGExMSAqIGIxMyArIGExMiAqIGIyMyArIGExMyAqIGIzMyArIGExNCAqIGI0MztcclxuXHRcdHRlWyAxMiBdID0gYTExICogYjE0ICsgYTEyICogYjI0ICsgYTEzICogYjM0ICsgYTE0ICogYjQ0O1xyXG5cclxuXHRcdHRlWyAxIF0gPSBhMjEgKiBiMTEgKyBhMjIgKiBiMjEgKyBhMjMgKiBiMzEgKyBhMjQgKiBiNDE7XHJcblx0XHR0ZVsgNSBdID0gYTIxICogYjEyICsgYTIyICogYjIyICsgYTIzICogYjMyICsgYTI0ICogYjQyO1xyXG5cdFx0dGVbIDkgXSA9IGEyMSAqIGIxMyArIGEyMiAqIGIyMyArIGEyMyAqIGIzMyArIGEyNCAqIGI0MztcclxuXHRcdHRlWyAxMyBdID0gYTIxICogYjE0ICsgYTIyICogYjI0ICsgYTIzICogYjM0ICsgYTI0ICogYjQ0O1xyXG5cclxuXHRcdHRlWyAyIF0gPSBhMzEgKiBiMTEgKyBhMzIgKiBiMjEgKyBhMzMgKiBiMzEgKyBhMzQgKiBiNDE7XHJcblx0XHR0ZVsgNiBdID0gYTMxICogYjEyICsgYTMyICogYjIyICsgYTMzICogYjMyICsgYTM0ICogYjQyO1xyXG5cdFx0dGVbIDEwIF0gPSBhMzEgKiBiMTMgKyBhMzIgKiBiMjMgKyBhMzMgKiBiMzMgKyBhMzQgKiBiNDM7XHJcblx0XHR0ZVsgMTQgXSA9IGEzMSAqIGIxNCArIGEzMiAqIGIyNCArIGEzMyAqIGIzNCArIGEzNCAqIGI0NDtcclxuXHJcblx0XHR0ZVsgMyBdID0gYTQxICogYjExICsgYTQyICogYjIxICsgYTQzICogYjMxICsgYTQ0ICogYjQxO1xyXG5cdFx0dGVbIDcgXSA9IGE0MSAqIGIxMiArIGE0MiAqIGIyMiArIGE0MyAqIGIzMiArIGE0NCAqIGI0MjtcclxuXHRcdHRlWyAxMSBdID0gYTQxICogYjEzICsgYTQyICogYjIzICsgYTQzICogYjMzICsgYTQ0ICogYjQzO1xyXG5cdFx0dGVbIDE1IF0gPSBhNDEgKiBiMTQgKyBhNDIgKiBiMjQgKyBhNDMgKiBiMzQgKyBhNDQgKiBiNDQ7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0bXVsdGlwbHlTY2FsYXIoIHMgKSB7XHJcblxyXG5cdFx0Y29uc3QgdGUgPSB0aGlzLmVsZW1lbnRzO1xyXG5cclxuXHRcdHRlWyAwIF0gKj0gczsgdGVbIDQgXSAqPSBzOyB0ZVsgOCBdICo9IHM7IHRlWyAxMiBdICo9IHM7XHJcblx0XHR0ZVsgMSBdICo9IHM7IHRlWyA1IF0gKj0gczsgdGVbIDkgXSAqPSBzOyB0ZVsgMTMgXSAqPSBzO1xyXG5cdFx0dGVbIDIgXSAqPSBzOyB0ZVsgNiBdICo9IHM7IHRlWyAxMCBdICo9IHM7IHRlWyAxNCBdICo9IHM7XHJcblx0XHR0ZVsgMyBdICo9IHM7IHRlWyA3IF0gKj0gczsgdGVbIDExIF0gKj0gczsgdGVbIDE1IF0gKj0gcztcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRkZXRlcm1pbmFudCgpIHtcclxuXHJcblx0XHRjb25zdCB0ZSA9IHRoaXMuZWxlbWVudHM7XHJcblxyXG5cdFx0Y29uc3QgbjExID0gdGVbIDAgXSwgbjEyID0gdGVbIDQgXSwgbjEzID0gdGVbIDggXSwgbjE0ID0gdGVbIDEyIF07XHJcblx0XHRjb25zdCBuMjEgPSB0ZVsgMSBdLCBuMjIgPSB0ZVsgNSBdLCBuMjMgPSB0ZVsgOSBdLCBuMjQgPSB0ZVsgMTMgXTtcclxuXHRcdGNvbnN0IG4zMSA9IHRlWyAyIF0sIG4zMiA9IHRlWyA2IF0sIG4zMyA9IHRlWyAxMCBdLCBuMzQgPSB0ZVsgMTQgXTtcclxuXHRcdGNvbnN0IG40MSA9IHRlWyAzIF0sIG40MiA9IHRlWyA3IF0sIG40MyA9IHRlWyAxMSBdLCBuNDQgPSB0ZVsgMTUgXTtcclxuXHJcblx0XHQvL1RPRE86IG1ha2UgdGhpcyBtb3JlIGVmZmljaWVudFxyXG5cdFx0Ly8oIGJhc2VkIG9uIGh0dHA6Ly93d3cuZXVjbGlkZWFuc3BhY2UuY29tL21hdGhzL2FsZ2VicmEvbWF0cml4L2Z1bmN0aW9ucy9pbnZlcnNlL2ZvdXJEL2luZGV4Lmh0bSApXHJcblxyXG5cdFx0cmV0dXJuIChcclxuXHRcdFx0bjQxICogKFxyXG5cdFx0XHRcdCsgbjE0ICogbjIzICogbjMyXHJcblx0XHRcdFx0IC0gbjEzICogbjI0ICogbjMyXHJcblx0XHRcdFx0IC0gbjE0ICogbjIyICogbjMzXHJcblx0XHRcdFx0ICsgbjEyICogbjI0ICogbjMzXHJcblx0XHRcdFx0ICsgbjEzICogbjIyICogbjM0XHJcblx0XHRcdFx0IC0gbjEyICogbjIzICogbjM0XHJcblx0XHRcdCkgK1xyXG5cdFx0XHRuNDIgKiAoXHJcblx0XHRcdFx0KyBuMTEgKiBuMjMgKiBuMzRcclxuXHRcdFx0XHQgLSBuMTEgKiBuMjQgKiBuMzNcclxuXHRcdFx0XHQgKyBuMTQgKiBuMjEgKiBuMzNcclxuXHRcdFx0XHQgLSBuMTMgKiBuMjEgKiBuMzRcclxuXHRcdFx0XHQgKyBuMTMgKiBuMjQgKiBuMzFcclxuXHRcdFx0XHQgLSBuMTQgKiBuMjMgKiBuMzFcclxuXHRcdFx0KSArXHJcblx0XHRcdG40MyAqIChcclxuXHRcdFx0XHQrIG4xMSAqIG4yNCAqIG4zMlxyXG5cdFx0XHRcdCAtIG4xMSAqIG4yMiAqIG4zNFxyXG5cdFx0XHRcdCAtIG4xNCAqIG4yMSAqIG4zMlxyXG5cdFx0XHRcdCArIG4xMiAqIG4yMSAqIG4zNFxyXG5cdFx0XHRcdCArIG4xNCAqIG4yMiAqIG4zMVxyXG5cdFx0XHRcdCAtIG4xMiAqIG4yNCAqIG4zMVxyXG5cdFx0XHQpICtcclxuXHRcdFx0bjQ0ICogKFxyXG5cdFx0XHRcdC0gbjEzICogbjIyICogbjMxXHJcblx0XHRcdFx0IC0gbjExICogbjIzICogbjMyXHJcblx0XHRcdFx0ICsgbjExICogbjIyICogbjMzXHJcblx0XHRcdFx0ICsgbjEzICogbjIxICogbjMyXHJcblx0XHRcdFx0IC0gbjEyICogbjIxICogbjMzXHJcblx0XHRcdFx0ICsgbjEyICogbjIzICogbjMxXHJcblx0XHRcdClcclxuXHJcblx0XHQpO1xyXG5cclxuXHR9XHJcblxyXG5cdHRyYW5zcG9zZSgpIHtcclxuXHJcblx0XHRjb25zdCB0ZSA9IHRoaXMuZWxlbWVudHM7XHJcblx0XHRsZXQgdG1wO1xyXG5cclxuXHRcdHRtcCA9IHRlWyAxIF07IHRlWyAxIF0gPSB0ZVsgNCBdOyB0ZVsgNCBdID0gdG1wO1xyXG5cdFx0dG1wID0gdGVbIDIgXTsgdGVbIDIgXSA9IHRlWyA4IF07IHRlWyA4IF0gPSB0bXA7XHJcblx0XHR0bXAgPSB0ZVsgNiBdOyB0ZVsgNiBdID0gdGVbIDkgXTsgdGVbIDkgXSA9IHRtcDtcclxuXHJcblx0XHR0bXAgPSB0ZVsgMyBdOyB0ZVsgMyBdID0gdGVbIDEyIF07IHRlWyAxMiBdID0gdG1wO1xyXG5cdFx0dG1wID0gdGVbIDcgXTsgdGVbIDcgXSA9IHRlWyAxMyBdOyB0ZVsgMTMgXSA9IHRtcDtcclxuXHRcdHRtcCA9IHRlWyAxMSBdOyB0ZVsgMTEgXSA9IHRlWyAxNCBdOyB0ZVsgMTQgXSA9IHRtcDtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRQb3NpdGlvbiggeCwgeSwgeiApIHtcclxuXHJcblx0XHRjb25zdCB0ZSA9IHRoaXMuZWxlbWVudHM7XHJcblxyXG5cdFx0aWYgKCB4LmlzVmVjdG9yMyApIHtcclxuXHJcblx0XHRcdHRlWyAxMiBdID0geC54O1xyXG5cdFx0XHR0ZVsgMTMgXSA9IHgueTtcclxuXHRcdFx0dGVbIDE0IF0gPSB4Lno7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdHRlWyAxMiBdID0geDtcclxuXHRcdFx0dGVbIDEzIF0gPSB5O1xyXG5cdFx0XHR0ZVsgMTQgXSA9IHo7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGludmVydCgpIHtcclxuXHJcblx0XHQvLyBiYXNlZCBvbiBodHRwOi8vd3d3LmV1Y2xpZGVhbnNwYWNlLmNvbS9tYXRocy9hbGdlYnJhL21hdHJpeC9mdW5jdGlvbnMvaW52ZXJzZS9mb3VyRC9pbmRleC5odG1cclxuXHRcdGNvbnN0IHRlID0gdGhpcy5lbGVtZW50cyxcclxuXHJcblx0XHRcdG4xMSA9IHRlWyAwIF0sIG4yMSA9IHRlWyAxIF0sIG4zMSA9IHRlWyAyIF0sIG40MSA9IHRlWyAzIF0sXHJcblx0XHRcdG4xMiA9IHRlWyA0IF0sIG4yMiA9IHRlWyA1IF0sIG4zMiA9IHRlWyA2IF0sIG40MiA9IHRlWyA3IF0sXHJcblx0XHRcdG4xMyA9IHRlWyA4IF0sIG4yMyA9IHRlWyA5IF0sIG4zMyA9IHRlWyAxMCBdLCBuNDMgPSB0ZVsgMTEgXSxcclxuXHRcdFx0bjE0ID0gdGVbIDEyIF0sIG4yNCA9IHRlWyAxMyBdLCBuMzQgPSB0ZVsgMTQgXSwgbjQ0ID0gdGVbIDE1IF0sXHJcblxyXG5cdFx0XHR0MTEgPSBuMjMgKiBuMzQgKiBuNDIgLSBuMjQgKiBuMzMgKiBuNDIgKyBuMjQgKiBuMzIgKiBuNDMgLSBuMjIgKiBuMzQgKiBuNDMgLSBuMjMgKiBuMzIgKiBuNDQgKyBuMjIgKiBuMzMgKiBuNDQsXHJcblx0XHRcdHQxMiA9IG4xNCAqIG4zMyAqIG40MiAtIG4xMyAqIG4zNCAqIG40MiAtIG4xNCAqIG4zMiAqIG40MyArIG4xMiAqIG4zNCAqIG40MyArIG4xMyAqIG4zMiAqIG40NCAtIG4xMiAqIG4zMyAqIG40NCxcclxuXHRcdFx0dDEzID0gbjEzICogbjI0ICogbjQyIC0gbjE0ICogbjIzICogbjQyICsgbjE0ICogbjIyICogbjQzIC0gbjEyICogbjI0ICogbjQzIC0gbjEzICogbjIyICogbjQ0ICsgbjEyICogbjIzICogbjQ0LFxyXG5cdFx0XHR0MTQgPSBuMTQgKiBuMjMgKiBuMzIgLSBuMTMgKiBuMjQgKiBuMzIgLSBuMTQgKiBuMjIgKiBuMzMgKyBuMTIgKiBuMjQgKiBuMzMgKyBuMTMgKiBuMjIgKiBuMzQgLSBuMTIgKiBuMjMgKiBuMzQ7XHJcblxyXG5cdFx0Y29uc3QgZGV0ID0gbjExICogdDExICsgbjIxICogdDEyICsgbjMxICogdDEzICsgbjQxICogdDE0O1xyXG5cclxuXHRcdGlmICggZGV0ID09PSAwICkgcmV0dXJuIHRoaXMuc2V0KCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwICk7XHJcblxyXG5cdFx0Y29uc3QgZGV0SW52ID0gMSAvIGRldDtcclxuXHJcblx0XHR0ZVsgMCBdID0gdDExICogZGV0SW52O1xyXG5cdFx0dGVbIDEgXSA9ICggbjI0ICogbjMzICogbjQxIC0gbjIzICogbjM0ICogbjQxIC0gbjI0ICogbjMxICogbjQzICsgbjIxICogbjM0ICogbjQzICsgbjIzICogbjMxICogbjQ0IC0gbjIxICogbjMzICogbjQ0ICkgKiBkZXRJbnY7XHJcblx0XHR0ZVsgMiBdID0gKCBuMjIgKiBuMzQgKiBuNDEgLSBuMjQgKiBuMzIgKiBuNDEgKyBuMjQgKiBuMzEgKiBuNDIgLSBuMjEgKiBuMzQgKiBuNDIgLSBuMjIgKiBuMzEgKiBuNDQgKyBuMjEgKiBuMzIgKiBuNDQgKSAqIGRldEludjtcclxuXHRcdHRlWyAzIF0gPSAoIG4yMyAqIG4zMiAqIG40MSAtIG4yMiAqIG4zMyAqIG40MSAtIG4yMyAqIG4zMSAqIG40MiArIG4yMSAqIG4zMyAqIG40MiArIG4yMiAqIG4zMSAqIG40MyAtIG4yMSAqIG4zMiAqIG40MyApICogZGV0SW52O1xyXG5cclxuXHRcdHRlWyA0IF0gPSB0MTIgKiBkZXRJbnY7XHJcblx0XHR0ZVsgNSBdID0gKCBuMTMgKiBuMzQgKiBuNDEgLSBuMTQgKiBuMzMgKiBuNDEgKyBuMTQgKiBuMzEgKiBuNDMgLSBuMTEgKiBuMzQgKiBuNDMgLSBuMTMgKiBuMzEgKiBuNDQgKyBuMTEgKiBuMzMgKiBuNDQgKSAqIGRldEludjtcclxuXHRcdHRlWyA2IF0gPSAoIG4xNCAqIG4zMiAqIG40MSAtIG4xMiAqIG4zNCAqIG40MSAtIG4xNCAqIG4zMSAqIG40MiArIG4xMSAqIG4zNCAqIG40MiArIG4xMiAqIG4zMSAqIG40NCAtIG4xMSAqIG4zMiAqIG40NCApICogZGV0SW52O1xyXG5cdFx0dGVbIDcgXSA9ICggbjEyICogbjMzICogbjQxIC0gbjEzICogbjMyICogbjQxICsgbjEzICogbjMxICogbjQyIC0gbjExICogbjMzICogbjQyIC0gbjEyICogbjMxICogbjQzICsgbjExICogbjMyICogbjQzICkgKiBkZXRJbnY7XHJcblxyXG5cdFx0dGVbIDggXSA9IHQxMyAqIGRldEludjtcclxuXHRcdHRlWyA5IF0gPSAoIG4xNCAqIG4yMyAqIG40MSAtIG4xMyAqIG4yNCAqIG40MSAtIG4xNCAqIG4yMSAqIG40MyArIG4xMSAqIG4yNCAqIG40MyArIG4xMyAqIG4yMSAqIG40NCAtIG4xMSAqIG4yMyAqIG40NCApICogZGV0SW52O1xyXG5cdFx0dGVbIDEwIF0gPSAoIG4xMiAqIG4yNCAqIG40MSAtIG4xNCAqIG4yMiAqIG40MSArIG4xNCAqIG4yMSAqIG40MiAtIG4xMSAqIG4yNCAqIG40MiAtIG4xMiAqIG4yMSAqIG40NCArIG4xMSAqIG4yMiAqIG40NCApICogZGV0SW52O1xyXG5cdFx0dGVbIDExIF0gPSAoIG4xMyAqIG4yMiAqIG40MSAtIG4xMiAqIG4yMyAqIG40MSAtIG4xMyAqIG4yMSAqIG40MiArIG4xMSAqIG4yMyAqIG40MiArIG4xMiAqIG4yMSAqIG40MyAtIG4xMSAqIG4yMiAqIG40MyApICogZGV0SW52O1xyXG5cclxuXHRcdHRlWyAxMiBdID0gdDE0ICogZGV0SW52O1xyXG5cdFx0dGVbIDEzIF0gPSAoIG4xMyAqIG4yNCAqIG4zMSAtIG4xNCAqIG4yMyAqIG4zMSArIG4xNCAqIG4yMSAqIG4zMyAtIG4xMSAqIG4yNCAqIG4zMyAtIG4xMyAqIG4yMSAqIG4zNCArIG4xMSAqIG4yMyAqIG4zNCApICogZGV0SW52O1xyXG5cdFx0dGVbIDE0IF0gPSAoIG4xNCAqIG4yMiAqIG4zMSAtIG4xMiAqIG4yNCAqIG4zMSAtIG4xNCAqIG4yMSAqIG4zMiArIG4xMSAqIG4yNCAqIG4zMiArIG4xMiAqIG4yMSAqIG4zNCAtIG4xMSAqIG4yMiAqIG4zNCApICogZGV0SW52O1xyXG5cdFx0dGVbIDE1IF0gPSAoIG4xMiAqIG4yMyAqIG4zMSAtIG4xMyAqIG4yMiAqIG4zMSArIG4xMyAqIG4yMSAqIG4zMiAtIG4xMSAqIG4yMyAqIG4zMiAtIG4xMiAqIG4yMSAqIG4zMyArIG4xMSAqIG4yMiAqIG4zMyApICogZGV0SW52O1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNjYWxlKCB2ICkge1xyXG5cclxuXHRcdGNvbnN0IHRlID0gdGhpcy5lbGVtZW50cztcclxuXHRcdGNvbnN0IHggPSB2LngsIHkgPSB2LnksIHogPSB2Lno7XHJcblxyXG5cdFx0dGVbIDAgXSAqPSB4OyB0ZVsgNCBdICo9IHk7IHRlWyA4IF0gKj0gejtcclxuXHRcdHRlWyAxIF0gKj0geDsgdGVbIDUgXSAqPSB5OyB0ZVsgOSBdICo9IHo7XHJcblx0XHR0ZVsgMiBdICo9IHg7IHRlWyA2IF0gKj0geTsgdGVbIDEwIF0gKj0gejtcclxuXHRcdHRlWyAzIF0gKj0geDsgdGVbIDcgXSAqPSB5OyB0ZVsgMTEgXSAqPSB6O1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldE1heFNjYWxlT25BeGlzKCkge1xyXG5cclxuXHRcdGNvbnN0IHRlID0gdGhpcy5lbGVtZW50cztcclxuXHJcblx0XHRjb25zdCBzY2FsZVhTcSA9IHRlWyAwIF0gKiB0ZVsgMCBdICsgdGVbIDEgXSAqIHRlWyAxIF0gKyB0ZVsgMiBdICogdGVbIDIgXTtcclxuXHRcdGNvbnN0IHNjYWxlWVNxID0gdGVbIDQgXSAqIHRlWyA0IF0gKyB0ZVsgNSBdICogdGVbIDUgXSArIHRlWyA2IF0gKiB0ZVsgNiBdO1xyXG5cdFx0Y29uc3Qgc2NhbGVaU3EgPSB0ZVsgOCBdICogdGVbIDggXSArIHRlWyA5IF0gKiB0ZVsgOSBdICsgdGVbIDEwIF0gKiB0ZVsgMTAgXTtcclxuXHJcblx0XHRyZXR1cm4gTWF0aC5zcXJ0KCBNYXRoLm1heCggc2NhbGVYU3EsIHNjYWxlWVNxLCBzY2FsZVpTcSApICk7XHJcblxyXG5cdH1cclxuXHJcblx0bWFrZVRyYW5zbGF0aW9uKCB4LCB5LCB6ICkge1xyXG5cclxuXHRcdGlmICggeC5pc1ZlY3RvcjMgKSB7XHJcblxyXG5cdFx0XHR0aGlzLnNldChcclxuXHJcblx0XHRcdFx0MSwgMCwgMCwgeC54LFxyXG5cdFx0XHRcdDAsIDEsIDAsIHgueSxcclxuXHRcdFx0XHQwLCAwLCAxLCB4LnosXHJcblx0XHRcdFx0MCwgMCwgMCwgMVxyXG5cclxuXHRcdFx0KTtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0dGhpcy5zZXQoXHJcblxyXG5cdFx0XHRcdDEsIDAsIDAsIHgsXHJcblx0XHRcdFx0MCwgMSwgMCwgeSxcclxuXHRcdFx0XHQwLCAwLCAxLCB6LFxyXG5cdFx0XHRcdDAsIDAsIDAsIDFcclxuXHJcblx0XHRcdCk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdG1ha2VSb3RhdGlvblgoIHRoZXRhICkge1xyXG5cclxuXHRcdGNvbnN0IGMgPSBNYXRoLmNvcyggdGhldGEgKSwgcyA9IE1hdGguc2luKCB0aGV0YSApO1xyXG5cclxuXHRcdHRoaXMuc2V0KFxyXG5cclxuXHRcdFx0MSwgMCwgMCwgMCxcclxuXHRcdFx0MCwgYywgLSBzLCAwLFxyXG5cdFx0XHQwLCBzLCBjLCAwLFxyXG5cdFx0XHQwLCAwLCAwLCAxXHJcblxyXG5cdFx0KTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRtYWtlUm90YXRpb25ZKCB0aGV0YSApIHtcclxuXHJcblx0XHRjb25zdCBjID0gTWF0aC5jb3MoIHRoZXRhICksIHMgPSBNYXRoLnNpbiggdGhldGEgKTtcclxuXHJcblx0XHR0aGlzLnNldChcclxuXHJcblx0XHRcdCBjLCAwLCBzLCAwLFxyXG5cdFx0XHQgMCwgMSwgMCwgMCxcclxuXHRcdFx0LSBzLCAwLCBjLCAwLFxyXG5cdFx0XHQgMCwgMCwgMCwgMVxyXG5cclxuXHRcdCk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0bWFrZVJvdGF0aW9uWiggdGhldGEgKSB7XHJcblxyXG5cdFx0Y29uc3QgYyA9IE1hdGguY29zKCB0aGV0YSApLCBzID0gTWF0aC5zaW4oIHRoZXRhICk7XHJcblxyXG5cdFx0dGhpcy5zZXQoXHJcblxyXG5cdFx0XHRjLCAtIHMsIDAsIDAsXHJcblx0XHRcdHMsIGMsIDAsIDAsXHJcblx0XHRcdDAsIDAsIDEsIDAsXHJcblx0XHRcdDAsIDAsIDAsIDFcclxuXHJcblx0XHQpO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdG1ha2VSb3RhdGlvbkF4aXMoIGF4aXMsIGFuZ2xlICkge1xyXG5cclxuXHRcdC8vIEJhc2VkIG9uIGh0dHA6Ly93d3cuZ2FtZWRldi5uZXQvcmVmZXJlbmNlL2FydGljbGVzL2FydGljbGUxMTk5LmFzcFxyXG5cclxuXHRcdGNvbnN0IGMgPSBNYXRoLmNvcyggYW5nbGUgKTtcclxuXHRcdGNvbnN0IHMgPSBNYXRoLnNpbiggYW5nbGUgKTtcclxuXHRcdGNvbnN0IHQgPSAxIC0gYztcclxuXHRcdGNvbnN0IHggPSBheGlzLngsIHkgPSBheGlzLnksIHogPSBheGlzLno7XHJcblx0XHRjb25zdCB0eCA9IHQgKiB4LCB0eSA9IHQgKiB5O1xyXG5cclxuXHRcdHRoaXMuc2V0KFxyXG5cclxuXHRcdFx0dHggKiB4ICsgYywgdHggKiB5IC0gcyAqIHosIHR4ICogeiArIHMgKiB5LCAwLFxyXG5cdFx0XHR0eCAqIHkgKyBzICogeiwgdHkgKiB5ICsgYywgdHkgKiB6IC0gcyAqIHgsIDAsXHJcblx0XHRcdHR4ICogeiAtIHMgKiB5LCB0eSAqIHogKyBzICogeCwgdCAqIHogKiB6ICsgYywgMCxcclxuXHRcdFx0MCwgMCwgMCwgMVxyXG5cclxuXHRcdCk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0bWFrZVNjYWxlKCB4LCB5LCB6ICkge1xyXG5cclxuXHRcdHRoaXMuc2V0KFxyXG5cclxuXHRcdFx0eCwgMCwgMCwgMCxcclxuXHRcdFx0MCwgeSwgMCwgMCxcclxuXHRcdFx0MCwgMCwgeiwgMCxcclxuXHRcdFx0MCwgMCwgMCwgMVxyXG5cclxuXHRcdCk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0bWFrZVNoZWFyKCB4eSwgeHosIHl4LCB5eiwgengsIHp5ICkge1xyXG5cclxuXHRcdHRoaXMuc2V0KFxyXG5cclxuXHRcdFx0MSwgeXgsIHp4LCAwLFxyXG5cdFx0XHR4eSwgMSwgenksIDAsXHJcblx0XHRcdHh6LCB5eiwgMSwgMCxcclxuXHRcdFx0MCwgMCwgMCwgMVxyXG5cclxuXHRcdCk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Y29tcG9zZSggcG9zaXRpb24sIHF1YXRlcm5pb24sIHNjYWxlICkge1xyXG5cclxuXHRcdGNvbnN0IHRlID0gdGhpcy5lbGVtZW50cztcclxuXHJcblx0XHRjb25zdCB4ID0gcXVhdGVybmlvbi5feCwgeSA9IHF1YXRlcm5pb24uX3ksIHogPSBxdWF0ZXJuaW9uLl96LCB3ID0gcXVhdGVybmlvbi5fdztcclxuXHRcdGNvbnN0IHgyID0geCArIHgsXHR5MiA9IHkgKyB5LCB6MiA9IHogKyB6O1xyXG5cdFx0Y29uc3QgeHggPSB4ICogeDIsIHh5ID0geCAqIHkyLCB4eiA9IHggKiB6MjtcclxuXHRcdGNvbnN0IHl5ID0geSAqIHkyLCB5eiA9IHkgKiB6MiwgenogPSB6ICogejI7XHJcblx0XHRjb25zdCB3eCA9IHcgKiB4Miwgd3kgPSB3ICogeTIsIHd6ID0gdyAqIHoyO1xyXG5cclxuXHRcdGNvbnN0IHN4ID0gc2NhbGUueCwgc3kgPSBzY2FsZS55LCBzeiA9IHNjYWxlLno7XHJcblxyXG5cdFx0dGVbIDAgXSA9ICggMSAtICggeXkgKyB6eiApICkgKiBzeDtcclxuXHRcdHRlWyAxIF0gPSAoIHh5ICsgd3ogKSAqIHN4O1xyXG5cdFx0dGVbIDIgXSA9ICggeHogLSB3eSApICogc3g7XHJcblx0XHR0ZVsgMyBdID0gMDtcclxuXHJcblx0XHR0ZVsgNCBdID0gKCB4eSAtIHd6ICkgKiBzeTtcclxuXHRcdHRlWyA1IF0gPSAoIDEgLSAoIHh4ICsgenogKSApICogc3k7XHJcblx0XHR0ZVsgNiBdID0gKCB5eiArIHd4ICkgKiBzeTtcclxuXHRcdHRlWyA3IF0gPSAwO1xyXG5cclxuXHRcdHRlWyA4IF0gPSAoIHh6ICsgd3kgKSAqIHN6O1xyXG5cdFx0dGVbIDkgXSA9ICggeXogLSB3eCApICogc3o7XHJcblx0XHR0ZVsgMTAgXSA9ICggMSAtICggeHggKyB5eSApICkgKiBzejtcclxuXHRcdHRlWyAxMSBdID0gMDtcclxuXHJcblx0XHR0ZVsgMTIgXSA9IHBvc2l0aW9uLng7XHJcblx0XHR0ZVsgMTMgXSA9IHBvc2l0aW9uLnk7XHJcblx0XHR0ZVsgMTQgXSA9IHBvc2l0aW9uLno7XHJcblx0XHR0ZVsgMTUgXSA9IDE7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0ZGVjb21wb3NlKCBwb3NpdGlvbiwgcXVhdGVybmlvbiwgc2NhbGUgKSB7XHJcblxyXG5cdFx0Y29uc3QgdGUgPSB0aGlzLmVsZW1lbnRzO1xyXG5cclxuXHRcdGxldCBzeCA9IF92MS5zZXQoIHRlWyAwIF0sIHRlWyAxIF0sIHRlWyAyIF0gKS5sZW5ndGgoKTtcclxuXHRcdGNvbnN0IHN5ID0gX3YxLnNldCggdGVbIDQgXSwgdGVbIDUgXSwgdGVbIDYgXSApLmxlbmd0aCgpO1xyXG5cdFx0Y29uc3Qgc3ogPSBfdjEuc2V0KCB0ZVsgOCBdLCB0ZVsgOSBdLCB0ZVsgMTAgXSApLmxlbmd0aCgpO1xyXG5cclxuXHRcdC8vIGlmIGRldGVybWluZSBpcyBuZWdhdGl2ZSwgd2UgbmVlZCB0byBpbnZlcnQgb25lIHNjYWxlXHJcblx0XHRjb25zdCBkZXQgPSB0aGlzLmRldGVybWluYW50KCk7XHJcblx0XHRpZiAoIGRldCA8IDAgKSBzeCA9IC0gc3g7XHJcblxyXG5cdFx0cG9zaXRpb24ueCA9IHRlWyAxMiBdO1xyXG5cdFx0cG9zaXRpb24ueSA9IHRlWyAxMyBdO1xyXG5cdFx0cG9zaXRpb24ueiA9IHRlWyAxNCBdO1xyXG5cclxuXHRcdC8vIHNjYWxlIHRoZSByb3RhdGlvbiBwYXJ0XHJcblx0XHRfbTEuY29weSggdGhpcyApO1xyXG5cclxuXHRcdGNvbnN0IGludlNYID0gMSAvIHN4O1xyXG5cdFx0Y29uc3QgaW52U1kgPSAxIC8gc3k7XHJcblx0XHRjb25zdCBpbnZTWiA9IDEgLyBzejtcclxuXHJcblx0XHRfbTEuZWxlbWVudHNbIDAgXSAqPSBpbnZTWDtcclxuXHRcdF9tMS5lbGVtZW50c1sgMSBdICo9IGludlNYO1xyXG5cdFx0X20xLmVsZW1lbnRzWyAyIF0gKj0gaW52U1g7XHJcblxyXG5cdFx0X20xLmVsZW1lbnRzWyA0IF0gKj0gaW52U1k7XHJcblx0XHRfbTEuZWxlbWVudHNbIDUgXSAqPSBpbnZTWTtcclxuXHRcdF9tMS5lbGVtZW50c1sgNiBdICo9IGludlNZO1xyXG5cclxuXHRcdF9tMS5lbGVtZW50c1sgOCBdICo9IGludlNaO1xyXG5cdFx0X20xLmVsZW1lbnRzWyA5IF0gKj0gaW52U1o7XHJcblx0XHRfbTEuZWxlbWVudHNbIDEwIF0gKj0gaW52U1o7XHJcblxyXG5cdFx0cXVhdGVybmlvbi5zZXRGcm9tUm90YXRpb25NYXRyaXgoIF9tMSApO1xyXG5cclxuXHRcdHNjYWxlLnggPSBzeDtcclxuXHRcdHNjYWxlLnkgPSBzeTtcclxuXHRcdHNjYWxlLnogPSBzejtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRtYWtlUGVyc3BlY3RpdmUoIGxlZnQsIHJpZ2h0LCB0b3AsIGJvdHRvbSwgbmVhciwgZmFyLCBjb29yZGluYXRlU3lzdGVtID0gV2ViR0xDb29yZGluYXRlU3lzdGVtICkge1xyXG5cclxuXHRcdGNvbnN0IHRlID0gdGhpcy5lbGVtZW50cztcclxuXHRcdGNvbnN0IHggPSAyICogbmVhciAvICggcmlnaHQgLSBsZWZ0ICk7XHJcblx0XHRjb25zdCB5ID0gMiAqIG5lYXIgLyAoIHRvcCAtIGJvdHRvbSApO1xyXG5cclxuXHRcdGNvbnN0IGEgPSAoIHJpZ2h0ICsgbGVmdCApIC8gKCByaWdodCAtIGxlZnQgKTtcclxuXHRcdGNvbnN0IGIgPSAoIHRvcCArIGJvdHRvbSApIC8gKCB0b3AgLSBib3R0b20gKTtcclxuXHJcblx0XHRsZXQgYywgZDtcclxuXHJcblx0XHRpZiAoIGNvb3JkaW5hdGVTeXN0ZW0gPT09IFdlYkdMQ29vcmRpbmF0ZVN5c3RlbSApIHtcclxuXHJcblx0XHRcdGMgPSAtICggZmFyICsgbmVhciApIC8gKCBmYXIgLSBuZWFyICk7XHJcblx0XHRcdGQgPSAoIC0gMiAqIGZhciAqIG5lYXIgKSAvICggZmFyIC0gbmVhciApO1xyXG5cclxuXHRcdH0gZWxzZSBpZiAoIGNvb3JkaW5hdGVTeXN0ZW0gPT09IFdlYkdQVUNvb3JkaW5hdGVTeXN0ZW0gKSB7XHJcblxyXG5cdFx0XHRjID0gLSBmYXIgLyAoIGZhciAtIG5lYXIgKTtcclxuXHRcdFx0ZCA9ICggLSBmYXIgKiBuZWFyICkgLyAoIGZhciAtIG5lYXIgKTtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0dGhyb3cgbmV3IEVycm9yKCAnVEhSRUUuTWF0cml4NC5tYWtlUGVyc3BlY3RpdmUoKTogSW52YWxpZCBjb29yZGluYXRlIHN5c3RlbTogJyArIGNvb3JkaW5hdGVTeXN0ZW0gKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGVbIDAgXSA9IHg7XHR0ZVsgNCBdID0gMDtcdHRlWyA4IF0gPSBhOyBcdHRlWyAxMiBdID0gMDtcclxuXHRcdHRlWyAxIF0gPSAwO1x0dGVbIDUgXSA9IHk7XHR0ZVsgOSBdID0gYjsgXHR0ZVsgMTMgXSA9IDA7XHJcblx0XHR0ZVsgMiBdID0gMDtcdHRlWyA2IF0gPSAwO1x0dGVbIDEwIF0gPSBjOyBcdHRlWyAxNCBdID0gZDtcclxuXHRcdHRlWyAzIF0gPSAwO1x0dGVbIDcgXSA9IDA7XHR0ZVsgMTEgXSA9IC0gMTtcdHRlWyAxNSBdID0gMDtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRtYWtlT3J0aG9ncmFwaGljKCBsZWZ0LCByaWdodCwgdG9wLCBib3R0b20sIG5lYXIsIGZhciwgY29vcmRpbmF0ZVN5c3RlbSA9IFdlYkdMQ29vcmRpbmF0ZVN5c3RlbSApIHtcclxuXHJcblx0XHRjb25zdCB0ZSA9IHRoaXMuZWxlbWVudHM7XHJcblx0XHRjb25zdCB3ID0gMS4wIC8gKCByaWdodCAtIGxlZnQgKTtcclxuXHRcdGNvbnN0IGggPSAxLjAgLyAoIHRvcCAtIGJvdHRvbSApO1xyXG5cdFx0Y29uc3QgcCA9IDEuMCAvICggZmFyIC0gbmVhciApO1xyXG5cclxuXHRcdGNvbnN0IHggPSAoIHJpZ2h0ICsgbGVmdCApICogdztcclxuXHRcdGNvbnN0IHkgPSAoIHRvcCArIGJvdHRvbSApICogaDtcclxuXHJcblx0XHRsZXQgeiwgekludjtcclxuXHJcblx0XHRpZiAoIGNvb3JkaW5hdGVTeXN0ZW0gPT09IFdlYkdMQ29vcmRpbmF0ZVN5c3RlbSApIHtcclxuXHJcblx0XHRcdHogPSAoIGZhciArIG5lYXIgKSAqIHA7XHJcblx0XHRcdHpJbnYgPSAtIDIgKiBwO1xyXG5cclxuXHRcdH0gZWxzZSBpZiAoIGNvb3JkaW5hdGVTeXN0ZW0gPT09IFdlYkdQVUNvb3JkaW5hdGVTeXN0ZW0gKSB7XHJcblxyXG5cdFx0XHR6ID0gbmVhciAqIHA7XHJcblx0XHRcdHpJbnYgPSAtIDEgKiBwO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHR0aHJvdyBuZXcgRXJyb3IoICdUSFJFRS5NYXRyaXg0Lm1ha2VPcnRob2dyYXBoaWMoKTogSW52YWxpZCBjb29yZGluYXRlIHN5c3RlbTogJyArIGNvb3JkaW5hdGVTeXN0ZW0gKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGVbIDAgXSA9IDIgKiB3O1x0dGVbIDQgXSA9IDA7XHRcdHRlWyA4IF0gPSAwOyBcdFx0dGVbIDEyIF0gPSAtIHg7XHJcblx0XHR0ZVsgMSBdID0gMDsgXHRcdHRlWyA1IF0gPSAyICogaDtcdHRlWyA5IF0gPSAwOyBcdFx0dGVbIDEzIF0gPSAtIHk7XHJcblx0XHR0ZVsgMiBdID0gMDsgXHRcdHRlWyA2IF0gPSAwO1x0XHR0ZVsgMTAgXSA9IHpJbnY7XHR0ZVsgMTQgXSA9IC0gejtcclxuXHRcdHRlWyAzIF0gPSAwOyBcdFx0dGVbIDcgXSA9IDA7XHRcdHRlWyAxMSBdID0gMDtcdFx0dGVbIDE1IF0gPSAxO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGVxdWFscyggbWF0cml4ICkge1xyXG5cclxuXHRcdGNvbnN0IHRlID0gdGhpcy5lbGVtZW50cztcclxuXHRcdGNvbnN0IG1lID0gbWF0cml4LmVsZW1lbnRzO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IDE2OyBpICsrICkge1xyXG5cclxuXHRcdFx0aWYgKCB0ZVsgaSBdICE9PSBtZVsgaSBdICkgcmV0dXJuIGZhbHNlO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdHJ1ZTtcclxuXHJcblx0fVxyXG5cclxuXHRmcm9tQXJyYXkoIGFycmF5LCBvZmZzZXQgPSAwICkge1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IDE2OyBpICsrICkge1xyXG5cclxuXHRcdFx0dGhpcy5lbGVtZW50c1sgaSBdID0gYXJyYXlbIGkgKyBvZmZzZXQgXTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0dG9BcnJheSggYXJyYXkgPSBbXSwgb2Zmc2V0ID0gMCApIHtcclxuXHJcblx0XHRjb25zdCB0ZSA9IHRoaXMuZWxlbWVudHM7XHJcblxyXG5cdFx0YXJyYXlbIG9mZnNldCBdID0gdGVbIDAgXTtcclxuXHRcdGFycmF5WyBvZmZzZXQgKyAxIF0gPSB0ZVsgMSBdO1xyXG5cdFx0YXJyYXlbIG9mZnNldCArIDIgXSA9IHRlWyAyIF07XHJcblx0XHRhcnJheVsgb2Zmc2V0ICsgMyBdID0gdGVbIDMgXTtcclxuXHJcblx0XHRhcnJheVsgb2Zmc2V0ICsgNCBdID0gdGVbIDQgXTtcclxuXHRcdGFycmF5WyBvZmZzZXQgKyA1IF0gPSB0ZVsgNSBdO1xyXG5cdFx0YXJyYXlbIG9mZnNldCArIDYgXSA9IHRlWyA2IF07XHJcblx0XHRhcnJheVsgb2Zmc2V0ICsgNyBdID0gdGVbIDcgXTtcclxuXHJcblx0XHRhcnJheVsgb2Zmc2V0ICsgOCBdID0gdGVbIDggXTtcclxuXHRcdGFycmF5WyBvZmZzZXQgKyA5IF0gPSB0ZVsgOSBdO1xyXG5cdFx0YXJyYXlbIG9mZnNldCArIDEwIF0gPSB0ZVsgMTAgXTtcclxuXHRcdGFycmF5WyBvZmZzZXQgKyAxMSBdID0gdGVbIDExIF07XHJcblxyXG5cdFx0YXJyYXlbIG9mZnNldCArIDEyIF0gPSB0ZVsgMTIgXTtcclxuXHRcdGFycmF5WyBvZmZzZXQgKyAxMyBdID0gdGVbIDEzIF07XHJcblx0XHRhcnJheVsgb2Zmc2V0ICsgMTQgXSA9IHRlWyAxNCBdO1xyXG5cdFx0YXJyYXlbIG9mZnNldCArIDE1IF0gPSB0ZVsgMTUgXTtcclxuXHJcblx0XHRyZXR1cm4gYXJyYXk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmNvbnN0IF92MSA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuY29uc3QgX20xID0gLypAX19QVVJFX18qLyBuZXcgTWF0cml4NCgpO1xyXG5jb25zdCBfemVybyA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoIDAsIDAsIDAgKTtcclxuY29uc3QgX29uZSA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoIDEsIDEsIDEgKTtcclxuY29uc3QgX3ggPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XHJcbmNvbnN0IF95ID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5jb25zdCBfeiA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuXHJcbmV4cG9ydCB7IE1hdHJpeDQgfTtcclxuIiwiaW1wb3J0IHsgUXVhdGVybmlvbiB9IGZyb20gJy4vUXVhdGVybmlvbi5qcyc7XHJcbmltcG9ydCB7IE1hdHJpeDQgfSBmcm9tICcuL01hdHJpeDQuanMnO1xyXG5pbXBvcnQgeyBjbGFtcCB9IGZyb20gJy4vTWF0aFV0aWxzLmpzJztcclxuXHJcbmNvbnN0IF9tYXRyaXggPSAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXg0KCk7XHJcbmNvbnN0IF9xdWF0ZXJuaW9uID0gLypAX19QVVJFX18qLyBuZXcgUXVhdGVybmlvbigpO1xyXG5cclxuY2xhc3MgRXVsZXIge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggeCA9IDAsIHkgPSAwLCB6ID0gMCwgb3JkZXIgPSBFdWxlci5ERUZBVUxUX09SREVSICkge1xyXG5cclxuXHRcdHRoaXMuaXNFdWxlciA9IHRydWU7XHJcblxyXG5cdFx0dGhpcy5feCA9IHg7XHJcblx0XHR0aGlzLl95ID0geTtcclxuXHRcdHRoaXMuX3ogPSB6O1xyXG5cdFx0dGhpcy5fb3JkZXIgPSBvcmRlcjtcclxuXHJcblx0fVxyXG5cclxuXHRnZXQgeCgpIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5feDtcclxuXHJcblx0fVxyXG5cclxuXHRzZXQgeCggdmFsdWUgKSB7XHJcblxyXG5cdFx0dGhpcy5feCA9IHZhbHVlO1xyXG5cdFx0dGhpcy5fb25DaGFuZ2VDYWxsYmFjaygpO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldCB5KCkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLl95O1xyXG5cclxuXHR9XHJcblxyXG5cdHNldCB5KCB2YWx1ZSApIHtcclxuXHJcblx0XHR0aGlzLl95ID0gdmFsdWU7XHJcblx0XHR0aGlzLl9vbkNoYW5nZUNhbGxiYWNrKCk7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0IHooKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuX3o7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0IHooIHZhbHVlICkge1xyXG5cclxuXHRcdHRoaXMuX3ogPSB2YWx1ZTtcclxuXHRcdHRoaXMuX29uQ2hhbmdlQ2FsbGJhY2soKTtcclxuXHJcblx0fVxyXG5cclxuXHRnZXQgb3JkZXIoKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuX29yZGVyO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldCBvcmRlciggdmFsdWUgKSB7XHJcblxyXG5cdFx0dGhpcy5fb3JkZXIgPSB2YWx1ZTtcclxuXHRcdHRoaXMuX29uQ2hhbmdlQ2FsbGJhY2soKTtcclxuXHJcblx0fVxyXG5cclxuXHRzZXQoIHgsIHksIHosIG9yZGVyID0gdGhpcy5fb3JkZXIgKSB7XHJcblxyXG5cdFx0dGhpcy5feCA9IHg7XHJcblx0XHR0aGlzLl95ID0geTtcclxuXHRcdHRoaXMuX3ogPSB6O1xyXG5cdFx0dGhpcy5fb3JkZXIgPSBvcmRlcjtcclxuXHJcblx0XHR0aGlzLl9vbkNoYW5nZUNhbGxiYWNrKCk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Y2xvbmUoKSB7XHJcblxyXG5cdFx0cmV0dXJuIG5ldyB0aGlzLmNvbnN0cnVjdG9yKCB0aGlzLl94LCB0aGlzLl95LCB0aGlzLl96LCB0aGlzLl9vcmRlciApO1xyXG5cclxuXHR9XHJcblxyXG5cdGNvcHkoIGV1bGVyICkge1xyXG5cclxuXHRcdHRoaXMuX3ggPSBldWxlci5feDtcclxuXHRcdHRoaXMuX3kgPSBldWxlci5feTtcclxuXHRcdHRoaXMuX3ogPSBldWxlci5fejtcclxuXHRcdHRoaXMuX29yZGVyID0gZXVsZXIuX29yZGVyO1xyXG5cclxuXHRcdHRoaXMuX29uQ2hhbmdlQ2FsbGJhY2soKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRGcm9tUm90YXRpb25NYXRyaXgoIG0sIG9yZGVyID0gdGhpcy5fb3JkZXIsIHVwZGF0ZSA9IHRydWUgKSB7XHJcblxyXG5cdFx0Ly8gYXNzdW1lcyB0aGUgdXBwZXIgM3gzIG9mIG0gaXMgYSBwdXJlIHJvdGF0aW9uIG1hdHJpeCAoaS5lLCB1bnNjYWxlZClcclxuXHJcblx0XHRjb25zdCB0ZSA9IG0uZWxlbWVudHM7XHJcblx0XHRjb25zdCBtMTEgPSB0ZVsgMCBdLCBtMTIgPSB0ZVsgNCBdLCBtMTMgPSB0ZVsgOCBdO1xyXG5cdFx0Y29uc3QgbTIxID0gdGVbIDEgXSwgbTIyID0gdGVbIDUgXSwgbTIzID0gdGVbIDkgXTtcclxuXHRcdGNvbnN0IG0zMSA9IHRlWyAyIF0sIG0zMiA9IHRlWyA2IF0sIG0zMyA9IHRlWyAxMCBdO1xyXG5cclxuXHRcdHN3aXRjaCAoIG9yZGVyICkge1xyXG5cclxuXHRcdFx0Y2FzZSAnWFlaJzpcclxuXHJcblx0XHRcdFx0dGhpcy5feSA9IE1hdGguYXNpbiggY2xhbXAoIG0xMywgLSAxLCAxICkgKTtcclxuXHJcblx0XHRcdFx0aWYgKCBNYXRoLmFicyggbTEzICkgPCAwLjk5OTk5OTkgKSB7XHJcblxyXG5cdFx0XHRcdFx0dGhpcy5feCA9IE1hdGguYXRhbjIoIC0gbTIzLCBtMzMgKTtcclxuXHRcdFx0XHRcdHRoaXMuX3ogPSBNYXRoLmF0YW4yKCAtIG0xMiwgbTExICk7XHJcblxyXG5cdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0dGhpcy5feCA9IE1hdGguYXRhbjIoIG0zMiwgbTIyICk7XHJcblx0XHRcdFx0XHR0aGlzLl96ID0gMDtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdGNhc2UgJ1lYWic6XHJcblxyXG5cdFx0XHRcdHRoaXMuX3ggPSBNYXRoLmFzaW4oIC0gY2xhbXAoIG0yMywgLSAxLCAxICkgKTtcclxuXHJcblx0XHRcdFx0aWYgKCBNYXRoLmFicyggbTIzICkgPCAwLjk5OTk5OTkgKSB7XHJcblxyXG5cdFx0XHRcdFx0dGhpcy5feSA9IE1hdGguYXRhbjIoIG0xMywgbTMzICk7XHJcblx0XHRcdFx0XHR0aGlzLl96ID0gTWF0aC5hdGFuMiggbTIxLCBtMjIgKTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHR0aGlzLl95ID0gTWF0aC5hdGFuMiggLSBtMzEsIG0xMSApO1xyXG5cdFx0XHRcdFx0dGhpcy5feiA9IDA7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRjYXNlICdaWFknOlxyXG5cclxuXHRcdFx0XHR0aGlzLl94ID0gTWF0aC5hc2luKCBjbGFtcCggbTMyLCAtIDEsIDEgKSApO1xyXG5cclxuXHRcdFx0XHRpZiAoIE1hdGguYWJzKCBtMzIgKSA8IDAuOTk5OTk5OSApIHtcclxuXHJcblx0XHRcdFx0XHR0aGlzLl95ID0gTWF0aC5hdGFuMiggLSBtMzEsIG0zMyApO1xyXG5cdFx0XHRcdFx0dGhpcy5feiA9IE1hdGguYXRhbjIoIC0gbTEyLCBtMjIgKTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHR0aGlzLl95ID0gMDtcclxuXHRcdFx0XHRcdHRoaXMuX3ogPSBNYXRoLmF0YW4yKCBtMjEsIG0xMSApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0Y2FzZSAnWllYJzpcclxuXHJcblx0XHRcdFx0dGhpcy5feSA9IE1hdGguYXNpbiggLSBjbGFtcCggbTMxLCAtIDEsIDEgKSApO1xyXG5cclxuXHRcdFx0XHRpZiAoIE1hdGguYWJzKCBtMzEgKSA8IDAuOTk5OTk5OSApIHtcclxuXHJcblx0XHRcdFx0XHR0aGlzLl94ID0gTWF0aC5hdGFuMiggbTMyLCBtMzMgKTtcclxuXHRcdFx0XHRcdHRoaXMuX3ogPSBNYXRoLmF0YW4yKCBtMjEsIG0xMSApO1xyXG5cclxuXHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdHRoaXMuX3ggPSAwO1xyXG5cdFx0XHRcdFx0dGhpcy5feiA9IE1hdGguYXRhbjIoIC0gbTEyLCBtMjIgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdGNhc2UgJ1laWCc6XHJcblxyXG5cdFx0XHRcdHRoaXMuX3ogPSBNYXRoLmFzaW4oIGNsYW1wKCBtMjEsIC0gMSwgMSApICk7XHJcblxyXG5cdFx0XHRcdGlmICggTWF0aC5hYnMoIG0yMSApIDwgMC45OTk5OTk5ICkge1xyXG5cclxuXHRcdFx0XHRcdHRoaXMuX3ggPSBNYXRoLmF0YW4yKCAtIG0yMywgbTIyICk7XHJcblx0XHRcdFx0XHR0aGlzLl95ID0gTWF0aC5hdGFuMiggLSBtMzEsIG0xMSApO1xyXG5cclxuXHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdHRoaXMuX3ggPSAwO1xyXG5cdFx0XHRcdFx0dGhpcy5feSA9IE1hdGguYXRhbjIoIG0xMywgbTMzICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRjYXNlICdYWlknOlxyXG5cclxuXHRcdFx0XHR0aGlzLl96ID0gTWF0aC5hc2luKCAtIGNsYW1wKCBtMTIsIC0gMSwgMSApICk7XHJcblxyXG5cdFx0XHRcdGlmICggTWF0aC5hYnMoIG0xMiApIDwgMC45OTk5OTk5ICkge1xyXG5cclxuXHRcdFx0XHRcdHRoaXMuX3ggPSBNYXRoLmF0YW4yKCBtMzIsIG0yMiApO1xyXG5cdFx0XHRcdFx0dGhpcy5feSA9IE1hdGguYXRhbjIoIG0xMywgbTExICk7XHJcblxyXG5cdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0dGhpcy5feCA9IE1hdGguYXRhbjIoIC0gbTIzLCBtMzMgKTtcclxuXHRcdFx0XHRcdHRoaXMuX3kgPSAwO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0ZGVmYXVsdDpcclxuXHJcblx0XHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuRXVsZXI6IC5zZXRGcm9tUm90YXRpb25NYXRyaXgoKSBlbmNvdW50ZXJlZCBhbiB1bmtub3duIG9yZGVyOiAnICsgb3JkZXIgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5fb3JkZXIgPSBvcmRlcjtcclxuXHJcblx0XHRpZiAoIHVwZGF0ZSA9PT0gdHJ1ZSApIHRoaXMuX29uQ2hhbmdlQ2FsbGJhY2soKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRGcm9tUXVhdGVybmlvbiggcSwgb3JkZXIsIHVwZGF0ZSApIHtcclxuXHJcblx0XHRfbWF0cml4Lm1ha2VSb3RhdGlvbkZyb21RdWF0ZXJuaW9uKCBxICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuc2V0RnJvbVJvdGF0aW9uTWF0cml4KCBfbWF0cml4LCBvcmRlciwgdXBkYXRlICk7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0RnJvbVZlY3RvcjMoIHYsIG9yZGVyID0gdGhpcy5fb3JkZXIgKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuc2V0KCB2LngsIHYueSwgdi56LCBvcmRlciApO1xyXG5cclxuXHR9XHJcblxyXG5cdHJlb3JkZXIoIG5ld09yZGVyICkge1xyXG5cclxuXHRcdC8vIFdBUk5JTkc6IHRoaXMgZGlzY2FyZHMgcmV2b2x1dGlvbiBpbmZvcm1hdGlvbiAtYmhvdXN0b25cclxuXHJcblx0XHRfcXVhdGVybmlvbi5zZXRGcm9tRXVsZXIoIHRoaXMgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5zZXRGcm9tUXVhdGVybmlvbiggX3F1YXRlcm5pb24sIG5ld09yZGVyICk7XHJcblxyXG5cdH1cclxuXHJcblx0ZXF1YWxzKCBldWxlciApIHtcclxuXHJcblx0XHRyZXR1cm4gKCBldWxlci5feCA9PT0gdGhpcy5feCApICYmICggZXVsZXIuX3kgPT09IHRoaXMuX3kgKSAmJiAoIGV1bGVyLl96ID09PSB0aGlzLl96ICkgJiYgKCBldWxlci5fb3JkZXIgPT09IHRoaXMuX29yZGVyICk7XHJcblxyXG5cdH1cclxuXHJcblx0ZnJvbUFycmF5KCBhcnJheSApIHtcclxuXHJcblx0XHR0aGlzLl94ID0gYXJyYXlbIDAgXTtcclxuXHRcdHRoaXMuX3kgPSBhcnJheVsgMSBdO1xyXG5cdFx0dGhpcy5feiA9IGFycmF5WyAyIF07XHJcblx0XHRpZiAoIGFycmF5WyAzIF0gIT09IHVuZGVmaW5lZCApIHRoaXMuX29yZGVyID0gYXJyYXlbIDMgXTtcclxuXHJcblx0XHR0aGlzLl9vbkNoYW5nZUNhbGxiYWNrKCk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0dG9BcnJheSggYXJyYXkgPSBbXSwgb2Zmc2V0ID0gMCApIHtcclxuXHJcblx0XHRhcnJheVsgb2Zmc2V0IF0gPSB0aGlzLl94O1xyXG5cdFx0YXJyYXlbIG9mZnNldCArIDEgXSA9IHRoaXMuX3k7XHJcblx0XHRhcnJheVsgb2Zmc2V0ICsgMiBdID0gdGhpcy5fejtcclxuXHRcdGFycmF5WyBvZmZzZXQgKyAzIF0gPSB0aGlzLl9vcmRlcjtcclxuXHJcblx0XHRyZXR1cm4gYXJyYXk7XHJcblxyXG5cdH1cclxuXHJcblx0X29uQ2hhbmdlKCBjYWxsYmFjayApIHtcclxuXHJcblx0XHR0aGlzLl9vbkNoYW5nZUNhbGxiYWNrID0gY2FsbGJhY2s7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0X29uQ2hhbmdlQ2FsbGJhY2soKSB7fVxyXG5cclxuXHQqWyBTeW1ib2wuaXRlcmF0b3IgXSgpIHtcclxuXHJcblx0XHR5aWVsZCB0aGlzLl94O1xyXG5cdFx0eWllbGQgdGhpcy5feTtcclxuXHRcdHlpZWxkIHRoaXMuX3o7XHJcblx0XHR5aWVsZCB0aGlzLl9vcmRlcjtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuRXVsZXIuREVGQVVMVF9PUkRFUiA9ICdYWVonO1xyXG5cclxuZXhwb3J0IHsgRXVsZXIgfTtcclxuIiwiY2xhc3MgTGF5ZXJzIHtcclxuXHJcblx0Y29uc3RydWN0b3IoKSB7XHJcblxyXG5cdFx0dGhpcy5tYXNrID0gMSB8IDA7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0KCBjaGFubmVsICkge1xyXG5cclxuXHRcdHRoaXMubWFzayA9ICggMSA8PCBjaGFubmVsIHwgMCApID4+PiAwO1xyXG5cclxuXHR9XHJcblxyXG5cdGVuYWJsZSggY2hhbm5lbCApIHtcclxuXHJcblx0XHR0aGlzLm1hc2sgfD0gMSA8PCBjaGFubmVsIHwgMDtcclxuXHJcblx0fVxyXG5cclxuXHRlbmFibGVBbGwoKSB7XHJcblxyXG5cdFx0dGhpcy5tYXNrID0gMHhmZmZmZmZmZiB8IDA7XHJcblxyXG5cdH1cclxuXHJcblx0dG9nZ2xlKCBjaGFubmVsICkge1xyXG5cclxuXHRcdHRoaXMubWFzayBePSAxIDw8IGNoYW5uZWwgfCAwO1xyXG5cclxuXHR9XHJcblxyXG5cdGRpc2FibGUoIGNoYW5uZWwgKSB7XHJcblxyXG5cdFx0dGhpcy5tYXNrICY9IH4gKCAxIDw8IGNoYW5uZWwgfCAwICk7XHJcblxyXG5cdH1cclxuXHJcblx0ZGlzYWJsZUFsbCgpIHtcclxuXHJcblx0XHR0aGlzLm1hc2sgPSAwO1xyXG5cclxuXHR9XHJcblxyXG5cdHRlc3QoIGxheWVycyApIHtcclxuXHJcblx0XHRyZXR1cm4gKCB0aGlzLm1hc2sgJiBsYXllcnMubWFzayApICE9PSAwO1xyXG5cclxuXHR9XHJcblxyXG5cdGlzRW5hYmxlZCggY2hhbm5lbCApIHtcclxuXHJcblx0XHRyZXR1cm4gKCB0aGlzLm1hc2sgJiAoIDEgPDwgY2hhbm5lbCB8IDAgKSApICE9PSAwO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5cclxuZXhwb3J0IHsgTGF5ZXJzIH07XHJcbiIsImltcG9ydCB7IFF1YXRlcm5pb24gfSBmcm9tICcuLi9tYXRoL1F1YXRlcm5pb24uanMnO1xyXG5pbXBvcnQgeyBWZWN0b3IzIH0gZnJvbSAnLi4vbWF0aC9WZWN0b3IzLmpzJztcclxuaW1wb3J0IHsgTWF0cml4NCB9IGZyb20gJy4uL21hdGgvTWF0cml4NC5qcyc7XHJcbmltcG9ydCB7IEV2ZW50RGlzcGF0Y2hlciB9IGZyb20gJy4vRXZlbnREaXNwYXRjaGVyLmpzJztcclxuaW1wb3J0IHsgRXVsZXIgfSBmcm9tICcuLi9tYXRoL0V1bGVyLmpzJztcclxuaW1wb3J0IHsgTGF5ZXJzIH0gZnJvbSAnLi9MYXllcnMuanMnO1xyXG5pbXBvcnQgeyBNYXRyaXgzIH0gZnJvbSAnLi4vbWF0aC9NYXRyaXgzLmpzJztcclxuaW1wb3J0ICogYXMgTWF0aFV0aWxzIGZyb20gJy4uL21hdGgvTWF0aFV0aWxzLmpzJztcclxuXHJcbmxldCBfb2JqZWN0M0RJZCA9IDA7XHJcblxyXG5jb25zdCBfdjEgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XHJcbmNvbnN0IF9xMSA9IC8qQF9fUFVSRV9fKi8gbmV3IFF1YXRlcm5pb24oKTtcclxuY29uc3QgX20xID0gLypAX19QVVJFX18qLyBuZXcgTWF0cml4NCgpO1xyXG5jb25zdCBfdGFyZ2V0ID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5cclxuY29uc3QgX3Bvc2l0aW9uID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5jb25zdCBfc2NhbGUgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XHJcbmNvbnN0IF9xdWF0ZXJuaW9uID0gLypAX19QVVJFX18qLyBuZXcgUXVhdGVybmlvbigpO1xyXG5cclxuY29uc3QgX3hBeGlzID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMyggMSwgMCwgMCApO1xyXG5jb25zdCBfeUF4aXMgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCAwLCAxLCAwICk7XHJcbmNvbnN0IF96QXhpcyA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoIDAsIDAsIDEgKTtcclxuXHJcbmNvbnN0IF9hZGRlZEV2ZW50ID0geyB0eXBlOiAnYWRkZWQnIH07XHJcbmNvbnN0IF9yZW1vdmVkRXZlbnQgPSB7IHR5cGU6ICdyZW1vdmVkJyB9O1xyXG5cclxuY2xhc3MgT2JqZWN0M0QgZXh0ZW5kcyBFdmVudERpc3BhdGNoZXIge1xyXG5cclxuXHRjb25zdHJ1Y3RvcigpIHtcclxuXHJcblx0XHRzdXBlcigpO1xyXG5cclxuXHRcdHRoaXMuaXNPYmplY3QzRCA9IHRydWU7XHJcblxyXG5cdFx0T2JqZWN0LmRlZmluZVByb3BlcnR5KCB0aGlzLCAnaWQnLCB7IHZhbHVlOiBfb2JqZWN0M0RJZCArKyB9ICk7XHJcblxyXG5cdFx0dGhpcy51dWlkID0gTWF0aFV0aWxzLmdlbmVyYXRlVVVJRCgpO1xyXG5cclxuXHRcdHRoaXMubmFtZSA9ICcnO1xyXG5cdFx0dGhpcy50eXBlID0gJ09iamVjdDNEJztcclxuXHJcblx0XHR0aGlzLnBhcmVudCA9IG51bGw7XHJcblx0XHR0aGlzLmNoaWxkcmVuID0gW107XHJcblxyXG5cdFx0dGhpcy51cCA9IE9iamVjdDNELkRFRkFVTFRfVVAuY2xvbmUoKTtcclxuXHJcblx0XHRjb25zdCBwb3NpdGlvbiA9IG5ldyBWZWN0b3IzKCk7XHJcblx0XHRjb25zdCByb3RhdGlvbiA9IG5ldyBFdWxlcigpO1xyXG5cdFx0Y29uc3QgcXVhdGVybmlvbiA9IG5ldyBRdWF0ZXJuaW9uKCk7XHJcblx0XHRjb25zdCBzY2FsZSA9IG5ldyBWZWN0b3IzKCAxLCAxLCAxICk7XHJcblxyXG5cdFx0ZnVuY3Rpb24gb25Sb3RhdGlvbkNoYW5nZSgpIHtcclxuXHJcblx0XHRcdHF1YXRlcm5pb24uc2V0RnJvbUV1bGVyKCByb3RhdGlvbiwgZmFsc2UgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0ZnVuY3Rpb24gb25RdWF0ZXJuaW9uQ2hhbmdlKCkge1xyXG5cclxuXHRcdFx0cm90YXRpb24uc2V0RnJvbVF1YXRlcm5pb24oIHF1YXRlcm5pb24sIHVuZGVmaW5lZCwgZmFsc2UgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cm90YXRpb24uX29uQ2hhbmdlKCBvblJvdGF0aW9uQ2hhbmdlICk7XHJcblx0XHRxdWF0ZXJuaW9uLl9vbkNoYW5nZSggb25RdWF0ZXJuaW9uQ2hhbmdlICk7XHJcblxyXG5cdFx0T2JqZWN0LmRlZmluZVByb3BlcnRpZXMoIHRoaXMsIHtcclxuXHRcdFx0cG9zaXRpb246IHtcclxuXHRcdFx0XHRjb25maWd1cmFibGU6IHRydWUsXHJcblx0XHRcdFx0ZW51bWVyYWJsZTogdHJ1ZSxcclxuXHRcdFx0XHR2YWx1ZTogcG9zaXRpb25cclxuXHRcdFx0fSxcclxuXHRcdFx0cm90YXRpb246IHtcclxuXHRcdFx0XHRjb25maWd1cmFibGU6IHRydWUsXHJcblx0XHRcdFx0ZW51bWVyYWJsZTogdHJ1ZSxcclxuXHRcdFx0XHR2YWx1ZTogcm90YXRpb25cclxuXHRcdFx0fSxcclxuXHRcdFx0cXVhdGVybmlvbjoge1xyXG5cdFx0XHRcdGNvbmZpZ3VyYWJsZTogdHJ1ZSxcclxuXHRcdFx0XHRlbnVtZXJhYmxlOiB0cnVlLFxyXG5cdFx0XHRcdHZhbHVlOiBxdWF0ZXJuaW9uXHJcblx0XHRcdH0sXHJcblx0XHRcdHNjYWxlOiB7XHJcblx0XHRcdFx0Y29uZmlndXJhYmxlOiB0cnVlLFxyXG5cdFx0XHRcdGVudW1lcmFibGU6IHRydWUsXHJcblx0XHRcdFx0dmFsdWU6IHNjYWxlXHJcblx0XHRcdH0sXHJcblx0XHRcdG1vZGVsVmlld01hdHJpeDoge1xyXG5cdFx0XHRcdHZhbHVlOiBuZXcgTWF0cml4NCgpXHJcblx0XHRcdH0sXHJcblx0XHRcdG5vcm1hbE1hdHJpeDoge1xyXG5cdFx0XHRcdHZhbHVlOiBuZXcgTWF0cml4MygpXHJcblx0XHRcdH1cclxuXHRcdH0gKTtcclxuXHJcblx0XHR0aGlzLm1hdHJpeCA9IG5ldyBNYXRyaXg0KCk7XHJcblx0XHR0aGlzLm1hdHJpeFdvcmxkID0gbmV3IE1hdHJpeDQoKTtcclxuXHJcblx0XHR0aGlzLm1hdHJpeEF1dG9VcGRhdGUgPSBPYmplY3QzRC5ERUZBVUxUX01BVFJJWF9BVVRPX1VQREFURTtcclxuXHJcblx0XHR0aGlzLm1hdHJpeFdvcmxkQXV0b1VwZGF0ZSA9IE9iamVjdDNELkRFRkFVTFRfTUFUUklYX1dPUkxEX0FVVE9fVVBEQVRFOyAvLyBjaGVja2VkIGJ5IHRoZSByZW5kZXJlclxyXG5cdFx0dGhpcy5tYXRyaXhXb3JsZE5lZWRzVXBkYXRlID0gZmFsc2U7XHJcblxyXG5cdFx0dGhpcy5sYXllcnMgPSBuZXcgTGF5ZXJzKCk7XHJcblx0XHR0aGlzLnZpc2libGUgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMuY2FzdFNoYWRvdyA9IGZhbHNlO1xyXG5cdFx0dGhpcy5yZWNlaXZlU2hhZG93ID0gZmFsc2U7XHJcblxyXG5cdFx0dGhpcy5mcnVzdHVtQ3VsbGVkID0gdHJ1ZTtcclxuXHRcdHRoaXMucmVuZGVyT3JkZXIgPSAwO1xyXG5cclxuXHRcdHRoaXMuYW5pbWF0aW9ucyA9IFtdO1xyXG5cclxuXHRcdHRoaXMudXNlckRhdGEgPSB7fTtcclxuXHJcblx0fVxyXG5cclxuXHRvbkJlZm9yZVNoYWRvdyggLyogcmVuZGVyZXIsIG9iamVjdCwgY2FtZXJhLCBzaGFkb3dDYW1lcmEsIGdlb21ldHJ5LCBkZXB0aE1hdGVyaWFsLCBncm91cCAqLyApIHt9XHJcblxyXG5cdG9uQWZ0ZXJTaGFkb3coIC8qIHJlbmRlcmVyLCBvYmplY3QsIGNhbWVyYSwgc2hhZG93Q2FtZXJhLCBnZW9tZXRyeSwgZGVwdGhNYXRlcmlhbCwgZ3JvdXAgKi8gKSB7fVxyXG5cclxuXHRvbkJlZm9yZVJlbmRlciggLyogcmVuZGVyZXIsIHNjZW5lLCBjYW1lcmEsIGdlb21ldHJ5LCBtYXRlcmlhbCwgZ3JvdXAgKi8gKSB7fVxyXG5cclxuXHRvbkFmdGVyUmVuZGVyKCAvKiByZW5kZXJlciwgc2NlbmUsIGNhbWVyYSwgZ2VvbWV0cnksIG1hdGVyaWFsLCBncm91cCAqLyApIHt9XHJcblxyXG5cdGFwcGx5TWF0cml4NCggbWF0cml4ICkge1xyXG5cclxuXHRcdGlmICggdGhpcy5tYXRyaXhBdXRvVXBkYXRlICkgdGhpcy51cGRhdGVNYXRyaXgoKTtcclxuXHJcblx0XHR0aGlzLm1hdHJpeC5wcmVtdWx0aXBseSggbWF0cml4ICk7XHJcblxyXG5cdFx0dGhpcy5tYXRyaXguZGVjb21wb3NlKCB0aGlzLnBvc2l0aW9uLCB0aGlzLnF1YXRlcm5pb24sIHRoaXMuc2NhbGUgKTtcclxuXHJcblx0fVxyXG5cclxuXHRhcHBseVF1YXRlcm5pb24oIHEgKSB7XHJcblxyXG5cdFx0dGhpcy5xdWF0ZXJuaW9uLnByZW11bHRpcGx5KCBxICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0Um90YXRpb25Gcm9tQXhpc0FuZ2xlKCBheGlzLCBhbmdsZSApIHtcclxuXHJcblx0XHQvLyBhc3N1bWVzIGF4aXMgaXMgbm9ybWFsaXplZFxyXG5cclxuXHRcdHRoaXMucXVhdGVybmlvbi5zZXRGcm9tQXhpc0FuZ2xlKCBheGlzLCBhbmdsZSApO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldFJvdGF0aW9uRnJvbUV1bGVyKCBldWxlciApIHtcclxuXHJcblx0XHR0aGlzLnF1YXRlcm5pb24uc2V0RnJvbUV1bGVyKCBldWxlciwgdHJ1ZSApO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldFJvdGF0aW9uRnJvbU1hdHJpeCggbSApIHtcclxuXHJcblx0XHQvLyBhc3N1bWVzIHRoZSB1cHBlciAzeDMgb2YgbSBpcyBhIHB1cmUgcm90YXRpb24gbWF0cml4IChpLmUsIHVuc2NhbGVkKVxyXG5cclxuXHRcdHRoaXMucXVhdGVybmlvbi5zZXRGcm9tUm90YXRpb25NYXRyaXgoIG0gKTtcclxuXHJcblx0fVxyXG5cclxuXHRzZXRSb3RhdGlvbkZyb21RdWF0ZXJuaW9uKCBxICkge1xyXG5cclxuXHRcdC8vIGFzc3VtZXMgcSBpcyBub3JtYWxpemVkXHJcblxyXG5cdFx0dGhpcy5xdWF0ZXJuaW9uLmNvcHkoIHEgKTtcclxuXHJcblx0fVxyXG5cclxuXHRyb3RhdGVPbkF4aXMoIGF4aXMsIGFuZ2xlICkge1xyXG5cclxuXHRcdC8vIHJvdGF0ZSBvYmplY3Qgb24gYXhpcyBpbiBvYmplY3Qgc3BhY2VcclxuXHRcdC8vIGF4aXMgaXMgYXNzdW1lZCB0byBiZSBub3JtYWxpemVkXHJcblxyXG5cdFx0X3ExLnNldEZyb21BeGlzQW5nbGUoIGF4aXMsIGFuZ2xlICk7XHJcblxyXG5cdFx0dGhpcy5xdWF0ZXJuaW9uLm11bHRpcGx5KCBfcTEgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRyb3RhdGVPbldvcmxkQXhpcyggYXhpcywgYW5nbGUgKSB7XHJcblxyXG5cdFx0Ly8gcm90YXRlIG9iamVjdCBvbiBheGlzIGluIHdvcmxkIHNwYWNlXHJcblx0XHQvLyBheGlzIGlzIGFzc3VtZWQgdG8gYmUgbm9ybWFsaXplZFxyXG5cdFx0Ly8gbWV0aG9kIGFzc3VtZXMgbm8gcm90YXRlZCBwYXJlbnRcclxuXHJcblx0XHRfcTEuc2V0RnJvbUF4aXNBbmdsZSggYXhpcywgYW5nbGUgKTtcclxuXHJcblx0XHR0aGlzLnF1YXRlcm5pb24ucHJlbXVsdGlwbHkoIF9xMSApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHJvdGF0ZVgoIGFuZ2xlICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLnJvdGF0ZU9uQXhpcyggX3hBeGlzLCBhbmdsZSApO1xyXG5cclxuXHR9XHJcblxyXG5cdHJvdGF0ZVkoIGFuZ2xlICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLnJvdGF0ZU9uQXhpcyggX3lBeGlzLCBhbmdsZSApO1xyXG5cclxuXHR9XHJcblxyXG5cdHJvdGF0ZVooIGFuZ2xlICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLnJvdGF0ZU9uQXhpcyggX3pBeGlzLCBhbmdsZSApO1xyXG5cclxuXHR9XHJcblxyXG5cdHRyYW5zbGF0ZU9uQXhpcyggYXhpcywgZGlzdGFuY2UgKSB7XHJcblxyXG5cdFx0Ly8gdHJhbnNsYXRlIG9iamVjdCBieSBkaXN0YW5jZSBhbG9uZyBheGlzIGluIG9iamVjdCBzcGFjZVxyXG5cdFx0Ly8gYXhpcyBpcyBhc3N1bWVkIHRvIGJlIG5vcm1hbGl6ZWRcclxuXHJcblx0XHRfdjEuY29weSggYXhpcyApLmFwcGx5UXVhdGVybmlvbiggdGhpcy5xdWF0ZXJuaW9uICk7XHJcblxyXG5cdFx0dGhpcy5wb3NpdGlvbi5hZGQoIF92MS5tdWx0aXBseVNjYWxhciggZGlzdGFuY2UgKSApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHRyYW5zbGF0ZVgoIGRpc3RhbmNlICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLnRyYW5zbGF0ZU9uQXhpcyggX3hBeGlzLCBkaXN0YW5jZSApO1xyXG5cclxuXHR9XHJcblxyXG5cdHRyYW5zbGF0ZVkoIGRpc3RhbmNlICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLnRyYW5zbGF0ZU9uQXhpcyggX3lBeGlzLCBkaXN0YW5jZSApO1xyXG5cclxuXHR9XHJcblxyXG5cdHRyYW5zbGF0ZVooIGRpc3RhbmNlICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLnRyYW5zbGF0ZU9uQXhpcyggX3pBeGlzLCBkaXN0YW5jZSApO1xyXG5cclxuXHR9XHJcblxyXG5cdGxvY2FsVG9Xb3JsZCggdmVjdG9yICkge1xyXG5cclxuXHRcdHRoaXMudXBkYXRlV29ybGRNYXRyaXgoIHRydWUsIGZhbHNlICk7XHJcblxyXG5cdFx0cmV0dXJuIHZlY3Rvci5hcHBseU1hdHJpeDQoIHRoaXMubWF0cml4V29ybGQgKTtcclxuXHJcblx0fVxyXG5cclxuXHR3b3JsZFRvTG9jYWwoIHZlY3RvciApIHtcclxuXHJcblx0XHR0aGlzLnVwZGF0ZVdvcmxkTWF0cml4KCB0cnVlLCBmYWxzZSApO1xyXG5cclxuXHRcdHJldHVybiB2ZWN0b3IuYXBwbHlNYXRyaXg0KCBfbTEuY29weSggdGhpcy5tYXRyaXhXb3JsZCApLmludmVydCgpICk7XHJcblxyXG5cdH1cclxuXHJcblx0bG9va0F0KCB4LCB5LCB6ICkge1xyXG5cclxuXHRcdC8vIFRoaXMgbWV0aG9kIGRvZXMgbm90IHN1cHBvcnQgb2JqZWN0cyBoYXZpbmcgbm9uLXVuaWZvcm1seS1zY2FsZWQgcGFyZW50KHMpXHJcblxyXG5cdFx0aWYgKCB4LmlzVmVjdG9yMyApIHtcclxuXHJcblx0XHRcdF90YXJnZXQuY29weSggeCApO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRfdGFyZ2V0LnNldCggeCwgeSwgeiApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCBwYXJlbnQgPSB0aGlzLnBhcmVudDtcclxuXHJcblx0XHR0aGlzLnVwZGF0ZVdvcmxkTWF0cml4KCB0cnVlLCBmYWxzZSApO1xyXG5cclxuXHRcdF9wb3NpdGlvbi5zZXRGcm9tTWF0cml4UG9zaXRpb24oIHRoaXMubWF0cml4V29ybGQgKTtcclxuXHJcblx0XHRpZiAoIHRoaXMuaXNDYW1lcmEgfHwgdGhpcy5pc0xpZ2h0ICkge1xyXG5cclxuXHRcdFx0X20xLmxvb2tBdCggX3Bvc2l0aW9uLCBfdGFyZ2V0LCB0aGlzLnVwICk7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdF9tMS5sb29rQXQoIF90YXJnZXQsIF9wb3NpdGlvbiwgdGhpcy51cCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLnF1YXRlcm5pb24uc2V0RnJvbVJvdGF0aW9uTWF0cml4KCBfbTEgKTtcclxuXHJcblx0XHRpZiAoIHBhcmVudCApIHtcclxuXHJcblx0XHRcdF9tMS5leHRyYWN0Um90YXRpb24oIHBhcmVudC5tYXRyaXhXb3JsZCApO1xyXG5cdFx0XHRfcTEuc2V0RnJvbVJvdGF0aW9uTWF0cml4KCBfbTEgKTtcclxuXHRcdFx0dGhpcy5xdWF0ZXJuaW9uLnByZW11bHRpcGx5KCBfcTEuaW52ZXJ0KCkgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0YWRkKCBvYmplY3QgKSB7XHJcblxyXG5cdFx0aWYgKCBhcmd1bWVudHMubGVuZ3RoID4gMSApIHtcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IGFyZ3VtZW50cy5sZW5ndGg7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdHRoaXMuYWRkKCBhcmd1bWVudHNbIGkgXSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggb2JqZWN0ID09PSB0aGlzICkge1xyXG5cclxuXHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLk9iamVjdDNELmFkZDogb2JqZWN0IGNhblxcJ3QgYmUgYWRkZWQgYXMgYSBjaGlsZCBvZiBpdHNlbGYuJywgb2JqZWN0ICk7XHJcblx0XHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIG9iamVjdCAmJiBvYmplY3QuaXNPYmplY3QzRCApIHtcclxuXHJcblx0XHRcdGlmICggb2JqZWN0LnBhcmVudCAhPT0gbnVsbCApIHtcclxuXHJcblx0XHRcdFx0b2JqZWN0LnBhcmVudC5yZW1vdmUoIG9iamVjdCApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0b2JqZWN0LnBhcmVudCA9IHRoaXM7XHJcblx0XHRcdHRoaXMuY2hpbGRyZW4ucHVzaCggb2JqZWN0ICk7XHJcblxyXG5cdFx0XHRvYmplY3QuZGlzcGF0Y2hFdmVudCggX2FkZGVkRXZlbnQgKTtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLk9iamVjdDNELmFkZDogb2JqZWN0IG5vdCBhbiBpbnN0YW5jZSBvZiBUSFJFRS5PYmplY3QzRC4nLCBvYmplY3QgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0cmVtb3ZlKCBvYmplY3QgKSB7XHJcblxyXG5cdFx0aWYgKCBhcmd1bWVudHMubGVuZ3RoID4gMSApIHtcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IGFyZ3VtZW50cy5sZW5ndGg7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdHRoaXMucmVtb3ZlKCBhcmd1bWVudHNbIGkgXSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGNvbnN0IGluZGV4ID0gdGhpcy5jaGlsZHJlbi5pbmRleE9mKCBvYmplY3QgKTtcclxuXHJcblx0XHRpZiAoIGluZGV4ICE9PSAtIDEgKSB7XHJcblxyXG5cdFx0XHRvYmplY3QucGFyZW50ID0gbnVsbDtcclxuXHRcdFx0dGhpcy5jaGlsZHJlbi5zcGxpY2UoIGluZGV4LCAxICk7XHJcblxyXG5cdFx0XHRvYmplY3QuZGlzcGF0Y2hFdmVudCggX3JlbW92ZWRFdmVudCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRyZW1vdmVGcm9tUGFyZW50KCkge1xyXG5cclxuXHRcdGNvbnN0IHBhcmVudCA9IHRoaXMucGFyZW50O1xyXG5cclxuXHRcdGlmICggcGFyZW50ICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0cGFyZW50LnJlbW92ZSggdGhpcyApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRjbGVhcigpIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5yZW1vdmUoIC4uLiB0aGlzLmNoaWxkcmVuICk7XHJcblxyXG5cdH1cclxuXHJcblx0YXR0YWNoKCBvYmplY3QgKSB7XHJcblxyXG5cdFx0Ly8gYWRkcyBvYmplY3QgYXMgYSBjaGlsZCBvZiB0aGlzLCB3aGlsZSBtYWludGFpbmluZyB0aGUgb2JqZWN0J3Mgd29ybGQgdHJhbnNmb3JtXHJcblxyXG5cdFx0Ly8gTm90ZTogVGhpcyBtZXRob2QgZG9lcyBub3Qgc3VwcG9ydCBzY2VuZSBncmFwaHMgaGF2aW5nIG5vbi11bmlmb3JtbHktc2NhbGVkIG5vZGVzKHMpXHJcblxyXG5cdFx0dGhpcy51cGRhdGVXb3JsZE1hdHJpeCggdHJ1ZSwgZmFsc2UgKTtcclxuXHJcblx0XHRfbTEuY29weSggdGhpcy5tYXRyaXhXb3JsZCApLmludmVydCgpO1xyXG5cclxuXHRcdGlmICggb2JqZWN0LnBhcmVudCAhPT0gbnVsbCApIHtcclxuXHJcblx0XHRcdG9iamVjdC5wYXJlbnQudXBkYXRlV29ybGRNYXRyaXgoIHRydWUsIGZhbHNlICk7XHJcblxyXG5cdFx0XHRfbTEubXVsdGlwbHkoIG9iamVjdC5wYXJlbnQubWF0cml4V29ybGQgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0b2JqZWN0LmFwcGx5TWF0cml4NCggX20xICk7XHJcblxyXG5cdFx0dGhpcy5hZGQoIG9iamVjdCApO1xyXG5cclxuXHRcdG9iamVjdC51cGRhdGVXb3JsZE1hdHJpeCggZmFsc2UsIHRydWUgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRnZXRPYmplY3RCeUlkKCBpZCApIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5nZXRPYmplY3RCeVByb3BlcnR5KCAnaWQnLCBpZCApO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldE9iamVjdEJ5TmFtZSggbmFtZSApIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5nZXRPYmplY3RCeVByb3BlcnR5KCAnbmFtZScsIG5hbWUgKTtcclxuXHJcblx0fVxyXG5cclxuXHRnZXRPYmplY3RCeVByb3BlcnR5KCBuYW1lLCB2YWx1ZSApIHtcclxuXHJcblx0XHRpZiAoIHRoaXNbIG5hbWUgXSA9PT0gdmFsdWUgKSByZXR1cm4gdGhpcztcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSB0aGlzLmNoaWxkcmVuLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBjaGlsZCA9IHRoaXMuY2hpbGRyZW5bIGkgXTtcclxuXHRcdFx0Y29uc3Qgb2JqZWN0ID0gY2hpbGQuZ2V0T2JqZWN0QnlQcm9wZXJ0eSggbmFtZSwgdmFsdWUgKTtcclxuXHJcblx0XHRcdGlmICggb2JqZWN0ICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRcdHJldHVybiBvYmplY3Q7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB1bmRlZmluZWQ7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0T2JqZWN0c0J5UHJvcGVydHkoIG5hbWUsIHZhbHVlLCByZXN1bHQgPSBbXSApIHtcclxuXHJcblx0XHRpZiAoIHRoaXNbIG5hbWUgXSA9PT0gdmFsdWUgKSByZXN1bHQucHVzaCggdGhpcyApO1xyXG5cclxuXHRcdGNvbnN0IGNoaWxkcmVuID0gdGhpcy5jaGlsZHJlbjtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBjaGlsZHJlbi5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0Y2hpbGRyZW5bIGkgXS5nZXRPYmplY3RzQnlQcm9wZXJ0eSggbmFtZSwgdmFsdWUsIHJlc3VsdCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gcmVzdWx0O1xyXG5cclxuXHR9XHJcblxyXG5cdGdldFdvcmxkUG9zaXRpb24oIHRhcmdldCApIHtcclxuXHJcblx0XHR0aGlzLnVwZGF0ZVdvcmxkTWF0cml4KCB0cnVlLCBmYWxzZSApO1xyXG5cclxuXHRcdHJldHVybiB0YXJnZXQuc2V0RnJvbU1hdHJpeFBvc2l0aW9uKCB0aGlzLm1hdHJpeFdvcmxkICk7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0V29ybGRRdWF0ZXJuaW9uKCB0YXJnZXQgKSB7XHJcblxyXG5cdFx0dGhpcy51cGRhdGVXb3JsZE1hdHJpeCggdHJ1ZSwgZmFsc2UgKTtcclxuXHJcblx0XHR0aGlzLm1hdHJpeFdvcmxkLmRlY29tcG9zZSggX3Bvc2l0aW9uLCB0YXJnZXQsIF9zY2FsZSApO1xyXG5cclxuXHRcdHJldHVybiB0YXJnZXQ7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0V29ybGRTY2FsZSggdGFyZ2V0ICkge1xyXG5cclxuXHRcdHRoaXMudXBkYXRlV29ybGRNYXRyaXgoIHRydWUsIGZhbHNlICk7XHJcblxyXG5cdFx0dGhpcy5tYXRyaXhXb3JsZC5kZWNvbXBvc2UoIF9wb3NpdGlvbiwgX3F1YXRlcm5pb24sIHRhcmdldCApO1xyXG5cclxuXHRcdHJldHVybiB0YXJnZXQ7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0V29ybGREaXJlY3Rpb24oIHRhcmdldCApIHtcclxuXHJcblx0XHR0aGlzLnVwZGF0ZVdvcmxkTWF0cml4KCB0cnVlLCBmYWxzZSApO1xyXG5cclxuXHRcdGNvbnN0IGUgPSB0aGlzLm1hdHJpeFdvcmxkLmVsZW1lbnRzO1xyXG5cclxuXHRcdHJldHVybiB0YXJnZXQuc2V0KCBlWyA4IF0sIGVbIDkgXSwgZVsgMTAgXSApLm5vcm1hbGl6ZSgpO1xyXG5cclxuXHR9XHJcblxyXG5cdHJheWNhc3QoIC8qIHJheWNhc3RlciwgaW50ZXJzZWN0cyAqLyApIHt9XHJcblxyXG5cdHRyYXZlcnNlKCBjYWxsYmFjayApIHtcclxuXHJcblx0XHRjYWxsYmFjayggdGhpcyApO1xyXG5cclxuXHRcdGNvbnN0IGNoaWxkcmVuID0gdGhpcy5jaGlsZHJlbjtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBjaGlsZHJlbi5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0Y2hpbGRyZW5bIGkgXS50cmF2ZXJzZSggY2FsbGJhY2sgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0dHJhdmVyc2VWaXNpYmxlKCBjYWxsYmFjayApIHtcclxuXHJcblx0XHRpZiAoIHRoaXMudmlzaWJsZSA9PT0gZmFsc2UgKSByZXR1cm47XHJcblxyXG5cdFx0Y2FsbGJhY2soIHRoaXMgKTtcclxuXHJcblx0XHRjb25zdCBjaGlsZHJlbiA9IHRoaXMuY2hpbGRyZW47XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gY2hpbGRyZW4ubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdGNoaWxkcmVuWyBpIF0udHJhdmVyc2VWaXNpYmxlKCBjYWxsYmFjayApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHR0cmF2ZXJzZUFuY2VzdG9ycyggY2FsbGJhY2sgKSB7XHJcblxyXG5cdFx0Y29uc3QgcGFyZW50ID0gdGhpcy5wYXJlbnQ7XHJcblxyXG5cdFx0aWYgKCBwYXJlbnQgIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRjYWxsYmFjayggcGFyZW50ICk7XHJcblxyXG5cdFx0XHRwYXJlbnQudHJhdmVyc2VBbmNlc3RvcnMoIGNhbGxiYWNrICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdHVwZGF0ZU1hdHJpeCgpIHtcclxuXHJcblx0XHR0aGlzLm1hdHJpeC5jb21wb3NlKCB0aGlzLnBvc2l0aW9uLCB0aGlzLnF1YXRlcm5pb24sIHRoaXMuc2NhbGUgKTtcclxuXHJcblx0XHR0aGlzLm1hdHJpeFdvcmxkTmVlZHNVcGRhdGUgPSB0cnVlO1xyXG5cclxuXHR9XHJcblxyXG5cdHVwZGF0ZU1hdHJpeFdvcmxkKCBmb3JjZSApIHtcclxuXHJcblx0XHRpZiAoIHRoaXMubWF0cml4QXV0b1VwZGF0ZSApIHRoaXMudXBkYXRlTWF0cml4KCk7XHJcblxyXG5cdFx0aWYgKCB0aGlzLm1hdHJpeFdvcmxkTmVlZHNVcGRhdGUgfHwgZm9yY2UgKSB7XHJcblxyXG5cdFx0XHRpZiAoIHRoaXMucGFyZW50ID09PSBudWxsICkge1xyXG5cclxuXHRcdFx0XHR0aGlzLm1hdHJpeFdvcmxkLmNvcHkoIHRoaXMubWF0cml4ICk7XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHR0aGlzLm1hdHJpeFdvcmxkLm11bHRpcGx5TWF0cmljZXMoIHRoaXMucGFyZW50Lm1hdHJpeFdvcmxkLCB0aGlzLm1hdHJpeCApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0dGhpcy5tYXRyaXhXb3JsZE5lZWRzVXBkYXRlID0gZmFsc2U7XHJcblxyXG5cdFx0XHRmb3JjZSA9IHRydWU7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIHVwZGF0ZSBjaGlsZHJlblxyXG5cclxuXHRcdGNvbnN0IGNoaWxkcmVuID0gdGhpcy5jaGlsZHJlbjtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBjaGlsZHJlbi5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0Y29uc3QgY2hpbGQgPSBjaGlsZHJlblsgaSBdO1xyXG5cclxuXHRcdFx0aWYgKCBjaGlsZC5tYXRyaXhXb3JsZEF1dG9VcGRhdGUgPT09IHRydWUgfHwgZm9yY2UgPT09IHRydWUgKSB7XHJcblxyXG5cdFx0XHRcdGNoaWxkLnVwZGF0ZU1hdHJpeFdvcmxkKCBmb3JjZSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHR1cGRhdGVXb3JsZE1hdHJpeCggdXBkYXRlUGFyZW50cywgdXBkYXRlQ2hpbGRyZW4gKSB7XHJcblxyXG5cdFx0Y29uc3QgcGFyZW50ID0gdGhpcy5wYXJlbnQ7XHJcblxyXG5cdFx0aWYgKCB1cGRhdGVQYXJlbnRzID09PSB0cnVlICYmIHBhcmVudCAhPT0gbnVsbCAmJiBwYXJlbnQubWF0cml4V29ybGRBdXRvVXBkYXRlID09PSB0cnVlICkge1xyXG5cclxuXHRcdFx0cGFyZW50LnVwZGF0ZVdvcmxkTWF0cml4KCB0cnVlLCBmYWxzZSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHRoaXMubWF0cml4QXV0b1VwZGF0ZSApIHRoaXMudXBkYXRlTWF0cml4KCk7XHJcblxyXG5cdFx0aWYgKCB0aGlzLnBhcmVudCA9PT0gbnVsbCApIHtcclxuXHJcblx0XHRcdHRoaXMubWF0cml4V29ybGQuY29weSggdGhpcy5tYXRyaXggKTtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0dGhpcy5tYXRyaXhXb3JsZC5tdWx0aXBseU1hdHJpY2VzKCB0aGlzLnBhcmVudC5tYXRyaXhXb3JsZCwgdGhpcy5tYXRyaXggKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gdXBkYXRlIGNoaWxkcmVuXHJcblxyXG5cdFx0aWYgKCB1cGRhdGVDaGlsZHJlbiA9PT0gdHJ1ZSApIHtcclxuXHJcblx0XHRcdGNvbnN0IGNoaWxkcmVuID0gdGhpcy5jaGlsZHJlbjtcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMCwgbCA9IGNoaWxkcmVuLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IGNoaWxkID0gY2hpbGRyZW5bIGkgXTtcclxuXHJcblx0XHRcdFx0aWYgKCBjaGlsZC5tYXRyaXhXb3JsZEF1dG9VcGRhdGUgPT09IHRydWUgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y2hpbGQudXBkYXRlV29ybGRNYXRyaXgoIGZhbHNlLCB0cnVlICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0dG9KU09OKCBtZXRhICkge1xyXG5cclxuXHRcdC8vIG1ldGEgaXMgYSBzdHJpbmcgd2hlbiBjYWxsZWQgZnJvbSBKU09OLnN0cmluZ2lmeVxyXG5cdFx0Y29uc3QgaXNSb290T2JqZWN0ID0gKCBtZXRhID09PSB1bmRlZmluZWQgfHwgdHlwZW9mIG1ldGEgPT09ICdzdHJpbmcnICk7XHJcblxyXG5cdFx0Y29uc3Qgb3V0cHV0ID0ge307XHJcblxyXG5cdFx0Ly8gbWV0YSBpcyBhIGhhc2ggdXNlZCB0byBjb2xsZWN0IGdlb21ldHJpZXMsIG1hdGVyaWFscy5cclxuXHRcdC8vIG5vdCBwcm92aWRpbmcgaXQgaW1wbGllcyB0aGF0IHRoaXMgaXMgdGhlIHJvb3Qgb2JqZWN0XHJcblx0XHQvLyBiZWluZyBzZXJpYWxpemVkLlxyXG5cdFx0aWYgKCBpc1Jvb3RPYmplY3QgKSB7XHJcblxyXG5cdFx0XHQvLyBpbml0aWFsaXplIG1ldGEgb2JqXHJcblx0XHRcdG1ldGEgPSB7XHJcblx0XHRcdFx0Z2VvbWV0cmllczoge30sXHJcblx0XHRcdFx0bWF0ZXJpYWxzOiB7fSxcclxuXHRcdFx0XHR0ZXh0dXJlczoge30sXHJcblx0XHRcdFx0aW1hZ2VzOiB7fSxcclxuXHRcdFx0XHRzaGFwZXM6IHt9LFxyXG5cdFx0XHRcdHNrZWxldG9uczoge30sXHJcblx0XHRcdFx0YW5pbWF0aW9uczoge30sXHJcblx0XHRcdFx0bm9kZXM6IHt9XHJcblx0XHRcdH07XHJcblxyXG5cdFx0XHRvdXRwdXQubWV0YWRhdGEgPSB7XHJcblx0XHRcdFx0dmVyc2lvbjogNC42LFxyXG5cdFx0XHRcdHR5cGU6ICdPYmplY3QnLFxyXG5cdFx0XHRcdGdlbmVyYXRvcjogJ09iamVjdDNELnRvSlNPTidcclxuXHRcdFx0fTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gc3RhbmRhcmQgT2JqZWN0M0Qgc2VyaWFsaXphdGlvblxyXG5cclxuXHRcdGNvbnN0IG9iamVjdCA9IHt9O1xyXG5cclxuXHRcdG9iamVjdC51dWlkID0gdGhpcy51dWlkO1xyXG5cdFx0b2JqZWN0LnR5cGUgPSB0aGlzLnR5cGU7XHJcblxyXG5cdFx0aWYgKCB0aGlzLm5hbWUgIT09ICcnICkgb2JqZWN0Lm5hbWUgPSB0aGlzLm5hbWU7XHJcblx0XHRpZiAoIHRoaXMuY2FzdFNoYWRvdyA9PT0gdHJ1ZSApIG9iamVjdC5jYXN0U2hhZG93ID0gdHJ1ZTtcclxuXHRcdGlmICggdGhpcy5yZWNlaXZlU2hhZG93ID09PSB0cnVlICkgb2JqZWN0LnJlY2VpdmVTaGFkb3cgPSB0cnVlO1xyXG5cdFx0aWYgKCB0aGlzLnZpc2libGUgPT09IGZhbHNlICkgb2JqZWN0LnZpc2libGUgPSBmYWxzZTtcclxuXHRcdGlmICggdGhpcy5mcnVzdHVtQ3VsbGVkID09PSBmYWxzZSApIG9iamVjdC5mcnVzdHVtQ3VsbGVkID0gZmFsc2U7XHJcblx0XHRpZiAoIHRoaXMucmVuZGVyT3JkZXIgIT09IDAgKSBvYmplY3QucmVuZGVyT3JkZXIgPSB0aGlzLnJlbmRlck9yZGVyO1xyXG5cdFx0aWYgKCBPYmplY3Qua2V5cyggdGhpcy51c2VyRGF0YSApLmxlbmd0aCA+IDAgKSBvYmplY3QudXNlckRhdGEgPSB0aGlzLnVzZXJEYXRhO1xyXG5cclxuXHRcdG9iamVjdC5sYXllcnMgPSB0aGlzLmxheWVycy5tYXNrO1xyXG5cdFx0b2JqZWN0Lm1hdHJpeCA9IHRoaXMubWF0cml4LnRvQXJyYXkoKTtcclxuXHRcdG9iamVjdC51cCA9IHRoaXMudXAudG9BcnJheSgpO1xyXG5cclxuXHRcdGlmICggdGhpcy5tYXRyaXhBdXRvVXBkYXRlID09PSBmYWxzZSApIG9iamVjdC5tYXRyaXhBdXRvVXBkYXRlID0gZmFsc2U7XHJcblxyXG5cdFx0Ly8gb2JqZWN0IHNwZWNpZmljIHByb3BlcnRpZXNcclxuXHJcblx0XHRpZiAoIHRoaXMuaXNJbnN0YW5jZWRNZXNoICkge1xyXG5cclxuXHRcdFx0b2JqZWN0LnR5cGUgPSAnSW5zdGFuY2VkTWVzaCc7XHJcblx0XHRcdG9iamVjdC5jb3VudCA9IHRoaXMuY291bnQ7XHJcblx0XHRcdG9iamVjdC5pbnN0YW5jZU1hdHJpeCA9IHRoaXMuaW5zdGFuY2VNYXRyaXgudG9KU09OKCk7XHJcblx0XHRcdGlmICggdGhpcy5pbnN0YW5jZUNvbG9yICE9PSBudWxsICkgb2JqZWN0Lmluc3RhbmNlQ29sb3IgPSB0aGlzLmluc3RhbmNlQ29sb3IudG9KU09OKCk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggdGhpcy5pc0JhdGNoZWRNZXNoICkge1xyXG5cclxuXHRcdFx0b2JqZWN0LnR5cGUgPSAnQmF0Y2hlZE1lc2gnO1xyXG5cdFx0XHRvYmplY3QucGVyT2JqZWN0RnJ1c3R1bUN1bGxlZCA9IHRoaXMucGVyT2JqZWN0RnJ1c3R1bUN1bGxlZDtcclxuXHRcdFx0b2JqZWN0LnNvcnRPYmplY3RzID0gdGhpcy5zb3J0T2JqZWN0cztcclxuXHJcblx0XHRcdG9iamVjdC5kcmF3UmFuZ2VzID0gdGhpcy5fZHJhd1JhbmdlcztcclxuXHRcdFx0b2JqZWN0LnJlc2VydmVkUmFuZ2VzID0gdGhpcy5fcmVzZXJ2ZWRSYW5nZXM7XHJcblxyXG5cdFx0XHRvYmplY3QudmlzaWJpbGl0eSA9IHRoaXMuX3Zpc2liaWxpdHk7XHJcblx0XHRcdG9iamVjdC5hY3RpdmUgPSB0aGlzLl9hY3RpdmU7XHJcblx0XHRcdG9iamVjdC5ib3VuZHMgPSB0aGlzLl9ib3VuZHMubWFwKCBib3VuZCA9PiAoIHtcclxuXHRcdFx0XHRib3hJbml0aWFsaXplZDogYm91bmQuYm94SW5pdGlhbGl6ZWQsXHJcblx0XHRcdFx0Ym94TWluOiBib3VuZC5ib3gubWluLnRvQXJyYXkoKSxcclxuXHRcdFx0XHRib3hNYXg6IGJvdW5kLmJveC5tYXgudG9BcnJheSgpLFxyXG5cclxuXHRcdFx0XHRzcGhlcmVJbml0aWFsaXplZDogYm91bmQuc3BoZXJlSW5pdGlhbGl6ZWQsXHJcblx0XHRcdFx0c3BoZXJlUmFkaXVzOiBib3VuZC5zcGhlcmUucmFkaXVzLFxyXG5cdFx0XHRcdHNwaGVyZUNlbnRlcjogYm91bmQuc3BoZXJlLmNlbnRlci50b0FycmF5KClcclxuXHRcdFx0fSApICk7XHJcblxyXG5cdFx0XHRvYmplY3QubWF4R2VvbWV0cnlDb3VudCA9IHRoaXMuX21heEdlb21ldHJ5Q291bnQ7XHJcblx0XHRcdG9iamVjdC5tYXhWZXJ0ZXhDb3VudCA9IHRoaXMuX21heFZlcnRleENvdW50O1xyXG5cdFx0XHRvYmplY3QubWF4SW5kZXhDb3VudCA9IHRoaXMuX21heEluZGV4Q291bnQ7XHJcblxyXG5cdFx0XHRvYmplY3QuZ2VvbWV0cnlJbml0aWFsaXplZCA9IHRoaXMuX2dlb21ldHJ5SW5pdGlhbGl6ZWQ7XHJcblx0XHRcdG9iamVjdC5nZW9tZXRyeUNvdW50ID0gdGhpcy5fZ2VvbWV0cnlDb3VudDtcclxuXHJcblx0XHRcdG9iamVjdC5tYXRyaWNlc1RleHR1cmUgPSB0aGlzLl9tYXRyaWNlc1RleHR1cmUudG9KU09OKCBtZXRhICk7XHJcblxyXG5cdFx0XHRpZiAoIHRoaXMuYm91bmRpbmdTcGhlcmUgIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdG9iamVjdC5ib3VuZGluZ1NwaGVyZSA9IHtcclxuXHRcdFx0XHRcdGNlbnRlcjogb2JqZWN0LmJvdW5kaW5nU3BoZXJlLmNlbnRlci50b0FycmF5KCksXHJcblx0XHRcdFx0XHRyYWRpdXM6IG9iamVjdC5ib3VuZGluZ1NwaGVyZS5yYWRpdXNcclxuXHRcdFx0XHR9O1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0aWYgKCB0aGlzLmJvdW5kaW5nQm94ICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0XHRvYmplY3QuYm91bmRpbmdCb3ggPSB7XHJcblx0XHRcdFx0XHRtaW46IG9iamVjdC5ib3VuZGluZ0JveC5taW4udG9BcnJheSgpLFxyXG5cdFx0XHRcdFx0bWF4OiBvYmplY3QuYm91bmRpbmdCb3gubWF4LnRvQXJyYXkoKVxyXG5cdFx0XHRcdH07XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vXHJcblxyXG5cdFx0ZnVuY3Rpb24gc2VyaWFsaXplKCBsaWJyYXJ5LCBlbGVtZW50ICkge1xyXG5cclxuXHRcdFx0aWYgKCBsaWJyYXJ5WyBlbGVtZW50LnV1aWQgXSA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHRsaWJyYXJ5WyBlbGVtZW50LnV1aWQgXSA9IGVsZW1lbnQudG9KU09OKCBtZXRhICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRyZXR1cm4gZWxlbWVudC51dWlkO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHRoaXMuaXNTY2VuZSApIHtcclxuXHJcblx0XHRcdGlmICggdGhpcy5iYWNrZ3JvdW5kICkge1xyXG5cclxuXHRcdFx0XHRpZiAoIHRoaXMuYmFja2dyb3VuZC5pc0NvbG9yICkge1xyXG5cclxuXHRcdFx0XHRcdG9iamVjdC5iYWNrZ3JvdW5kID0gdGhpcy5iYWNrZ3JvdW5kLnRvSlNPTigpO1xyXG5cclxuXHRcdFx0XHR9IGVsc2UgaWYgKCB0aGlzLmJhY2tncm91bmQuaXNUZXh0dXJlICkge1xyXG5cclxuXHRcdFx0XHRcdG9iamVjdC5iYWNrZ3JvdW5kID0gdGhpcy5iYWNrZ3JvdW5kLnRvSlNPTiggbWV0YSApLnV1aWQ7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGlmICggdGhpcy5lbnZpcm9ubWVudCAmJiB0aGlzLmVudmlyb25tZW50LmlzVGV4dHVyZSAmJiB0aGlzLmVudmlyb25tZW50LmlzUmVuZGVyVGFyZ2V0VGV4dHVyZSAhPT0gdHJ1ZSApIHtcclxuXHJcblx0XHRcdFx0b2JqZWN0LmVudmlyb25tZW50ID0gdGhpcy5lbnZpcm9ubWVudC50b0pTT04oIG1ldGEgKS51dWlkO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH0gZWxzZSBpZiAoIHRoaXMuaXNNZXNoIHx8IHRoaXMuaXNMaW5lIHx8IHRoaXMuaXNQb2ludHMgKSB7XHJcblxyXG5cdFx0XHRvYmplY3QuZ2VvbWV0cnkgPSBzZXJpYWxpemUoIG1ldGEuZ2VvbWV0cmllcywgdGhpcy5nZW9tZXRyeSApO1xyXG5cclxuXHRcdFx0Y29uc3QgcGFyYW1ldGVycyA9IHRoaXMuZ2VvbWV0cnkucGFyYW1ldGVycztcclxuXHJcblx0XHRcdGlmICggcGFyYW1ldGVycyAhPT0gdW5kZWZpbmVkICYmIHBhcmFtZXRlcnMuc2hhcGVzICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IHNoYXBlcyA9IHBhcmFtZXRlcnMuc2hhcGVzO1xyXG5cclxuXHRcdFx0XHRpZiAoIEFycmF5LmlzQXJyYXkoIHNoYXBlcyApICkge1xyXG5cclxuXHRcdFx0XHRcdGZvciAoIGxldCBpID0gMCwgbCA9IHNoYXBlcy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRcdFx0Y29uc3Qgc2hhcGUgPSBzaGFwZXNbIGkgXTtcclxuXHJcblx0XHRcdFx0XHRcdHNlcmlhbGl6ZSggbWV0YS5zaGFwZXMsIHNoYXBlICk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdHNlcmlhbGl6ZSggbWV0YS5zaGFwZXMsIHNoYXBlcyApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggdGhpcy5pc1NraW5uZWRNZXNoICkge1xyXG5cclxuXHRcdFx0b2JqZWN0LmJpbmRNb2RlID0gdGhpcy5iaW5kTW9kZTtcclxuXHRcdFx0b2JqZWN0LmJpbmRNYXRyaXggPSB0aGlzLmJpbmRNYXRyaXgudG9BcnJheSgpO1xyXG5cclxuXHRcdFx0aWYgKCB0aGlzLnNrZWxldG9uICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRcdHNlcmlhbGl6ZSggbWV0YS5za2VsZXRvbnMsIHRoaXMuc2tlbGV0b24gKTtcclxuXHJcblx0XHRcdFx0b2JqZWN0LnNrZWxldG9uID0gdGhpcy5za2VsZXRvbi51dWlkO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHRoaXMubWF0ZXJpYWwgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdGlmICggQXJyYXkuaXNBcnJheSggdGhpcy5tYXRlcmlhbCApICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCB1dWlkcyA9IFtdO1xyXG5cclxuXHRcdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSB0aGlzLm1hdGVyaWFsLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0dXVpZHMucHVzaCggc2VyaWFsaXplKCBtZXRhLm1hdGVyaWFscywgdGhpcy5tYXRlcmlhbFsgaSBdICkgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRvYmplY3QubWF0ZXJpYWwgPSB1dWlkcztcclxuXHJcblx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdG9iamVjdC5tYXRlcmlhbCA9IHNlcmlhbGl6ZSggbWV0YS5tYXRlcmlhbHMsIHRoaXMubWF0ZXJpYWwgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly9cclxuXHJcblx0XHRpZiAoIHRoaXMuY2hpbGRyZW4ubGVuZ3RoID4gMCApIHtcclxuXHJcblx0XHRcdG9iamVjdC5jaGlsZHJlbiA9IFtdO1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgdGhpcy5jaGlsZHJlbi5sZW5ndGg7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdG9iamVjdC5jaGlsZHJlbi5wdXNoKCB0aGlzLmNoaWxkcmVuWyBpIF0udG9KU09OKCBtZXRhICkub2JqZWN0ICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vXHJcblxyXG5cdFx0aWYgKCB0aGlzLmFuaW1hdGlvbnMubGVuZ3RoID4gMCApIHtcclxuXHJcblx0XHRcdG9iamVjdC5hbmltYXRpb25zID0gW107XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCB0aGlzLmFuaW1hdGlvbnMubGVuZ3RoOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBhbmltYXRpb24gPSB0aGlzLmFuaW1hdGlvbnNbIGkgXTtcclxuXHJcblx0XHRcdFx0b2JqZWN0LmFuaW1hdGlvbnMucHVzaCggc2VyaWFsaXplKCBtZXRhLmFuaW1hdGlvbnMsIGFuaW1hdGlvbiApICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggaXNSb290T2JqZWN0ICkge1xyXG5cclxuXHRcdFx0Y29uc3QgZ2VvbWV0cmllcyA9IGV4dHJhY3RGcm9tQ2FjaGUoIG1ldGEuZ2VvbWV0cmllcyApO1xyXG5cdFx0XHRjb25zdCBtYXRlcmlhbHMgPSBleHRyYWN0RnJvbUNhY2hlKCBtZXRhLm1hdGVyaWFscyApO1xyXG5cdFx0XHRjb25zdCB0ZXh0dXJlcyA9IGV4dHJhY3RGcm9tQ2FjaGUoIG1ldGEudGV4dHVyZXMgKTtcclxuXHRcdFx0Y29uc3QgaW1hZ2VzID0gZXh0cmFjdEZyb21DYWNoZSggbWV0YS5pbWFnZXMgKTtcclxuXHRcdFx0Y29uc3Qgc2hhcGVzID0gZXh0cmFjdEZyb21DYWNoZSggbWV0YS5zaGFwZXMgKTtcclxuXHRcdFx0Y29uc3Qgc2tlbGV0b25zID0gZXh0cmFjdEZyb21DYWNoZSggbWV0YS5za2VsZXRvbnMgKTtcclxuXHRcdFx0Y29uc3QgYW5pbWF0aW9ucyA9IGV4dHJhY3RGcm9tQ2FjaGUoIG1ldGEuYW5pbWF0aW9ucyApO1xyXG5cdFx0XHRjb25zdCBub2RlcyA9IGV4dHJhY3RGcm9tQ2FjaGUoIG1ldGEubm9kZXMgKTtcclxuXHJcblx0XHRcdGlmICggZ2VvbWV0cmllcy5sZW5ndGggPiAwICkgb3V0cHV0Lmdlb21ldHJpZXMgPSBnZW9tZXRyaWVzO1xyXG5cdFx0XHRpZiAoIG1hdGVyaWFscy5sZW5ndGggPiAwICkgb3V0cHV0Lm1hdGVyaWFscyA9IG1hdGVyaWFscztcclxuXHRcdFx0aWYgKCB0ZXh0dXJlcy5sZW5ndGggPiAwICkgb3V0cHV0LnRleHR1cmVzID0gdGV4dHVyZXM7XHJcblx0XHRcdGlmICggaW1hZ2VzLmxlbmd0aCA+IDAgKSBvdXRwdXQuaW1hZ2VzID0gaW1hZ2VzO1xyXG5cdFx0XHRpZiAoIHNoYXBlcy5sZW5ndGggPiAwICkgb3V0cHV0LnNoYXBlcyA9IHNoYXBlcztcclxuXHRcdFx0aWYgKCBza2VsZXRvbnMubGVuZ3RoID4gMCApIG91dHB1dC5za2VsZXRvbnMgPSBza2VsZXRvbnM7XHJcblx0XHRcdGlmICggYW5pbWF0aW9ucy5sZW5ndGggPiAwICkgb3V0cHV0LmFuaW1hdGlvbnMgPSBhbmltYXRpb25zO1xyXG5cdFx0XHRpZiAoIG5vZGVzLmxlbmd0aCA+IDAgKSBvdXRwdXQubm9kZXMgPSBub2RlcztcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0b3V0cHV0Lm9iamVjdCA9IG9iamVjdDtcclxuXHJcblx0XHRyZXR1cm4gb3V0cHV0O1xyXG5cclxuXHRcdC8vIGV4dHJhY3QgZGF0YSBmcm9tIHRoZSBjYWNoZSBoYXNoXHJcblx0XHQvLyByZW1vdmUgbWV0YWRhdGEgb24gZWFjaCBpdGVtXHJcblx0XHQvLyBhbmQgcmV0dXJuIGFzIGFycmF5XHJcblx0XHRmdW5jdGlvbiBleHRyYWN0RnJvbUNhY2hlKCBjYWNoZSApIHtcclxuXHJcblx0XHRcdGNvbnN0IHZhbHVlcyA9IFtdO1xyXG5cdFx0XHRmb3IgKCBjb25zdCBrZXkgaW4gY2FjaGUgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IGRhdGEgPSBjYWNoZVsga2V5IF07XHJcblx0XHRcdFx0ZGVsZXRlIGRhdGEubWV0YWRhdGE7XHJcblx0XHRcdFx0dmFsdWVzLnB1c2goIGRhdGEgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHJldHVybiB2YWx1ZXM7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGNsb25lKCByZWN1cnNpdmUgKSB7XHJcblxyXG5cdFx0cmV0dXJuIG5ldyB0aGlzLmNvbnN0cnVjdG9yKCkuY29weSggdGhpcywgcmVjdXJzaXZlICk7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlLCByZWN1cnNpdmUgPSB0cnVlICkge1xyXG5cclxuXHRcdHRoaXMubmFtZSA9IHNvdXJjZS5uYW1lO1xyXG5cclxuXHRcdHRoaXMudXAuY29weSggc291cmNlLnVwICk7XHJcblxyXG5cdFx0dGhpcy5wb3NpdGlvbi5jb3B5KCBzb3VyY2UucG9zaXRpb24gKTtcclxuXHRcdHRoaXMucm90YXRpb24ub3JkZXIgPSBzb3VyY2Uucm90YXRpb24ub3JkZXI7XHJcblx0XHR0aGlzLnF1YXRlcm5pb24uY29weSggc291cmNlLnF1YXRlcm5pb24gKTtcclxuXHRcdHRoaXMuc2NhbGUuY29weSggc291cmNlLnNjYWxlICk7XHJcblxyXG5cdFx0dGhpcy5tYXRyaXguY29weSggc291cmNlLm1hdHJpeCApO1xyXG5cdFx0dGhpcy5tYXRyaXhXb3JsZC5jb3B5KCBzb3VyY2UubWF0cml4V29ybGQgKTtcclxuXHJcblx0XHR0aGlzLm1hdHJpeEF1dG9VcGRhdGUgPSBzb3VyY2UubWF0cml4QXV0b1VwZGF0ZTtcclxuXHJcblx0XHR0aGlzLm1hdHJpeFdvcmxkQXV0b1VwZGF0ZSA9IHNvdXJjZS5tYXRyaXhXb3JsZEF1dG9VcGRhdGU7XHJcblx0XHR0aGlzLm1hdHJpeFdvcmxkTmVlZHNVcGRhdGUgPSBzb3VyY2UubWF0cml4V29ybGROZWVkc1VwZGF0ZTtcclxuXHJcblx0XHR0aGlzLmxheWVycy5tYXNrID0gc291cmNlLmxheWVycy5tYXNrO1xyXG5cdFx0dGhpcy52aXNpYmxlID0gc291cmNlLnZpc2libGU7XHJcblxyXG5cdFx0dGhpcy5jYXN0U2hhZG93ID0gc291cmNlLmNhc3RTaGFkb3c7XHJcblx0XHR0aGlzLnJlY2VpdmVTaGFkb3cgPSBzb3VyY2UucmVjZWl2ZVNoYWRvdztcclxuXHJcblx0XHR0aGlzLmZydXN0dW1DdWxsZWQgPSBzb3VyY2UuZnJ1c3R1bUN1bGxlZDtcclxuXHRcdHRoaXMucmVuZGVyT3JkZXIgPSBzb3VyY2UucmVuZGVyT3JkZXI7XHJcblxyXG5cdFx0dGhpcy5hbmltYXRpb25zID0gc291cmNlLmFuaW1hdGlvbnMuc2xpY2UoKTtcclxuXHJcblx0XHR0aGlzLnVzZXJEYXRhID0gSlNPTi5wYXJzZSggSlNPTi5zdHJpbmdpZnkoIHNvdXJjZS51c2VyRGF0YSApICk7XHJcblxyXG5cdFx0aWYgKCByZWN1cnNpdmUgPT09IHRydWUgKSB7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBzb3VyY2UuY2hpbGRyZW4ubGVuZ3RoOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBjaGlsZCA9IHNvdXJjZS5jaGlsZHJlblsgaSBdO1xyXG5cdFx0XHRcdHRoaXMuYWRkKCBjaGlsZC5jbG9uZSgpICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5PYmplY3QzRC5ERUZBVUxUX1VQID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMyggMCwgMSwgMCApO1xyXG5PYmplY3QzRC5ERUZBVUxUX01BVFJJWF9BVVRPX1VQREFURSA9IHRydWU7XHJcbk9iamVjdDNELkRFRkFVTFRfTUFUUklYX1dPUkxEX0FVVE9fVVBEQVRFID0gdHJ1ZTtcclxuXHJcbmV4cG9ydCB7IE9iamVjdDNEIH07XHJcbiIsImltcG9ydCB7IFZlY3RvcjMgfSBmcm9tICcuL1ZlY3RvcjMuanMnO1xyXG5cclxuY29uc3QgX3YwID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5jb25zdCBfdjEgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XHJcbmNvbnN0IF92MiA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuY29uc3QgX3YzID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5cclxuY29uc3QgX3ZhYiA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuY29uc3QgX3ZhYyA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuY29uc3QgX3ZiYyA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuY29uc3QgX3ZhcCA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuY29uc3QgX3ZicCA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuY29uc3QgX3ZjcCA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuXHJcbmNsYXNzIFRyaWFuZ2xlIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIGEgPSBuZXcgVmVjdG9yMygpLCBiID0gbmV3IFZlY3RvcjMoKSwgYyA9IG5ldyBWZWN0b3IzKCkgKSB7XHJcblxyXG5cdFx0dGhpcy5hID0gYTtcclxuXHRcdHRoaXMuYiA9IGI7XHJcblx0XHR0aGlzLmMgPSBjO1xyXG5cclxuXHR9XHJcblxyXG5cdHN0YXRpYyBnZXROb3JtYWwoIGEsIGIsIGMsIHRhcmdldCApIHtcclxuXHJcblx0XHR0YXJnZXQuc3ViVmVjdG9ycyggYywgYiApO1xyXG5cdFx0X3YwLnN1YlZlY3RvcnMoIGEsIGIgKTtcclxuXHRcdHRhcmdldC5jcm9zcyggX3YwICk7XHJcblxyXG5cdFx0Y29uc3QgdGFyZ2V0TGVuZ3RoU3EgPSB0YXJnZXQubGVuZ3RoU3EoKTtcclxuXHRcdGlmICggdGFyZ2V0TGVuZ3RoU3EgPiAwICkge1xyXG5cclxuXHRcdFx0cmV0dXJuIHRhcmdldC5tdWx0aXBseVNjYWxhciggMSAvIE1hdGguc3FydCggdGFyZ2V0TGVuZ3RoU3EgKSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGFyZ2V0LnNldCggMCwgMCwgMCApO1xyXG5cclxuXHR9XHJcblxyXG5cdC8vIHN0YXRpYy9pbnN0YW5jZSBtZXRob2QgdG8gY2FsY3VsYXRlIGJhcnljZW50cmljIGNvb3JkaW5hdGVzXHJcblx0Ly8gYmFzZWQgb246IGh0dHA6Ly93d3cuYmxhY2twYXduLmNvbS90ZXh0cy9wb2ludGlucG9seS9kZWZhdWx0Lmh0bWxcclxuXHRzdGF0aWMgZ2V0QmFyeWNvb3JkKCBwb2ludCwgYSwgYiwgYywgdGFyZ2V0ICkge1xyXG5cclxuXHRcdF92MC5zdWJWZWN0b3JzKCBjLCBhICk7XHJcblx0XHRfdjEuc3ViVmVjdG9ycyggYiwgYSApO1xyXG5cdFx0X3YyLnN1YlZlY3RvcnMoIHBvaW50LCBhICk7XHJcblxyXG5cdFx0Y29uc3QgZG90MDAgPSBfdjAuZG90KCBfdjAgKTtcclxuXHRcdGNvbnN0IGRvdDAxID0gX3YwLmRvdCggX3YxICk7XHJcblx0XHRjb25zdCBkb3QwMiA9IF92MC5kb3QoIF92MiApO1xyXG5cdFx0Y29uc3QgZG90MTEgPSBfdjEuZG90KCBfdjEgKTtcclxuXHRcdGNvbnN0IGRvdDEyID0gX3YxLmRvdCggX3YyICk7XHJcblxyXG5cdFx0Y29uc3QgZGVub20gPSAoIGRvdDAwICogZG90MTEgLSBkb3QwMSAqIGRvdDAxICk7XHJcblxyXG5cdFx0Ly8gY29sbGluZWFyIG9yIHNpbmd1bGFyIHRyaWFuZ2xlXHJcblx0XHRpZiAoIGRlbm9tID09PSAwICkge1xyXG5cclxuXHRcdFx0dGFyZ2V0LnNldCggMCwgMCwgMCApO1xyXG5cdFx0XHRyZXR1cm4gbnVsbDtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Y29uc3QgaW52RGVub20gPSAxIC8gZGVub207XHJcblx0XHRjb25zdCB1ID0gKCBkb3QxMSAqIGRvdDAyIC0gZG90MDEgKiBkb3QxMiApICogaW52RGVub207XHJcblx0XHRjb25zdCB2ID0gKCBkb3QwMCAqIGRvdDEyIC0gZG90MDEgKiBkb3QwMiApICogaW52RGVub207XHJcblxyXG5cdFx0Ly8gYmFyeWNlbnRyaWMgY29vcmRpbmF0ZXMgbXVzdCBhbHdheXMgc3VtIHRvIDFcclxuXHRcdHJldHVybiB0YXJnZXQuc2V0KCAxIC0gdSAtIHYsIHYsIHUgKTtcclxuXHJcblx0fVxyXG5cclxuXHRzdGF0aWMgY29udGFpbnNQb2ludCggcG9pbnQsIGEsIGIsIGMgKSB7XHJcblxyXG5cdFx0Ly8gaWYgdGhlIHRyaWFuZ2xlIGlzIGRlZ2VuZXJhdGUgdGhlbiB3ZSBjYW4ndCBjb250YWluIGEgcG9pbnRcclxuXHRcdGlmICggdGhpcy5nZXRCYXJ5Y29vcmQoIHBvaW50LCBhLCBiLCBjLCBfdjMgKSA9PT0gbnVsbCApIHtcclxuXHJcblx0XHRcdHJldHVybiBmYWxzZTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuICggX3YzLnggPj0gMCApICYmICggX3YzLnkgPj0gMCApICYmICggKCBfdjMueCArIF92My55ICkgPD0gMSApO1xyXG5cclxuXHR9XHJcblxyXG5cdHN0YXRpYyBnZXRJbnRlcnBvbGF0aW9uKCBwb2ludCwgcDEsIHAyLCBwMywgdjEsIHYyLCB2MywgdGFyZ2V0ICkge1xyXG5cclxuXHRcdGlmICggdGhpcy5nZXRCYXJ5Y29vcmQoIHBvaW50LCBwMSwgcDIsIHAzLCBfdjMgKSA9PT0gbnVsbCApIHtcclxuXHJcblx0XHRcdHRhcmdldC54ID0gMDtcclxuXHRcdFx0dGFyZ2V0LnkgPSAwO1xyXG5cdFx0XHRpZiAoICd6JyBpbiB0YXJnZXQgKSB0YXJnZXQueiA9IDA7XHJcblx0XHRcdGlmICggJ3cnIGluIHRhcmdldCApIHRhcmdldC53ID0gMDtcclxuXHRcdFx0cmV0dXJuIG51bGw7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRhcmdldC5zZXRTY2FsYXIoIDAgKTtcclxuXHRcdHRhcmdldC5hZGRTY2FsZWRWZWN0b3IoIHYxLCBfdjMueCApO1xyXG5cdFx0dGFyZ2V0LmFkZFNjYWxlZFZlY3RvciggdjIsIF92My55ICk7XHJcblx0XHR0YXJnZXQuYWRkU2NhbGVkVmVjdG9yKCB2MywgX3YzLnogKTtcclxuXHJcblx0XHRyZXR1cm4gdGFyZ2V0O1xyXG5cclxuXHR9XHJcblxyXG5cdHN0YXRpYyBpc0Zyb250RmFjaW5nKCBhLCBiLCBjLCBkaXJlY3Rpb24gKSB7XHJcblxyXG5cdFx0X3YwLnN1YlZlY3RvcnMoIGMsIGIgKTtcclxuXHRcdF92MS5zdWJWZWN0b3JzKCBhLCBiICk7XHJcblxyXG5cdFx0Ly8gc3RyaWN0bHkgZnJvbnQgZmFjaW5nXHJcblx0XHRyZXR1cm4gKCBfdjAuY3Jvc3MoIF92MSApLmRvdCggZGlyZWN0aW9uICkgPCAwICkgPyB0cnVlIDogZmFsc2U7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0KCBhLCBiLCBjICkge1xyXG5cclxuXHRcdHRoaXMuYS5jb3B5KCBhICk7XHJcblx0XHR0aGlzLmIuY29weSggYiApO1xyXG5cdFx0dGhpcy5jLmNvcHkoIGMgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRGcm9tUG9pbnRzQW5kSW5kaWNlcyggcG9pbnRzLCBpMCwgaTEsIGkyICkge1xyXG5cclxuXHRcdHRoaXMuYS5jb3B5KCBwb2ludHNbIGkwIF0gKTtcclxuXHRcdHRoaXMuYi5jb3B5KCBwb2ludHNbIGkxIF0gKTtcclxuXHRcdHRoaXMuYy5jb3B5KCBwb2ludHNbIGkyIF0gKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRGcm9tQXR0cmlidXRlQW5kSW5kaWNlcyggYXR0cmlidXRlLCBpMCwgaTEsIGkyICkge1xyXG5cclxuXHRcdHRoaXMuYS5mcm9tQnVmZmVyQXR0cmlidXRlKCBhdHRyaWJ1dGUsIGkwICk7XHJcblx0XHR0aGlzLmIuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggYXR0cmlidXRlLCBpMSApO1xyXG5cdFx0dGhpcy5jLmZyb21CdWZmZXJBdHRyaWJ1dGUoIGF0dHJpYnV0ZSwgaTIgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRjbG9uZSgpIHtcclxuXHJcblx0XHRyZXR1cm4gbmV3IHRoaXMuY29uc3RydWN0b3IoKS5jb3B5KCB0aGlzICk7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggdHJpYW5nbGUgKSB7XHJcblxyXG5cdFx0dGhpcy5hLmNvcHkoIHRyaWFuZ2xlLmEgKTtcclxuXHRcdHRoaXMuYi5jb3B5KCB0cmlhbmdsZS5iICk7XHJcblx0XHR0aGlzLmMuY29weSggdHJpYW5nbGUuYyApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldEFyZWEoKSB7XHJcblxyXG5cdFx0X3YwLnN1YlZlY3RvcnMoIHRoaXMuYywgdGhpcy5iICk7XHJcblx0XHRfdjEuc3ViVmVjdG9ycyggdGhpcy5hLCB0aGlzLmIgKTtcclxuXHJcblx0XHRyZXR1cm4gX3YwLmNyb3NzKCBfdjEgKS5sZW5ndGgoKSAqIDAuNTtcclxuXHJcblx0fVxyXG5cclxuXHRnZXRNaWRwb2ludCggdGFyZ2V0ICkge1xyXG5cclxuXHRcdHJldHVybiB0YXJnZXQuYWRkVmVjdG9ycyggdGhpcy5hLCB0aGlzLmIgKS5hZGQoIHRoaXMuYyApLm11bHRpcGx5U2NhbGFyKCAxIC8gMyApO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldE5vcm1hbCggdGFyZ2V0ICkge1xyXG5cclxuXHRcdHJldHVybiBUcmlhbmdsZS5nZXROb3JtYWwoIHRoaXMuYSwgdGhpcy5iLCB0aGlzLmMsIHRhcmdldCApO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldFBsYW5lKCB0YXJnZXQgKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRhcmdldC5zZXRGcm9tQ29wbGFuYXJQb2ludHMoIHRoaXMuYSwgdGhpcy5iLCB0aGlzLmMgKTtcclxuXHJcblx0fVxyXG5cclxuXHRnZXRCYXJ5Y29vcmQoIHBvaW50LCB0YXJnZXQgKSB7XHJcblxyXG5cdFx0cmV0dXJuIFRyaWFuZ2xlLmdldEJhcnljb29yZCggcG9pbnQsIHRoaXMuYSwgdGhpcy5iLCB0aGlzLmMsIHRhcmdldCApO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldEludGVycG9sYXRpb24oIHBvaW50LCB2MSwgdjIsIHYzLCB0YXJnZXQgKSB7XHJcblxyXG5cdFx0cmV0dXJuIFRyaWFuZ2xlLmdldEludGVycG9sYXRpb24oIHBvaW50LCB0aGlzLmEsIHRoaXMuYiwgdGhpcy5jLCB2MSwgdjIsIHYzLCB0YXJnZXQgKTtcclxuXHJcblx0fVxyXG5cclxuXHRjb250YWluc1BvaW50KCBwb2ludCApIHtcclxuXHJcblx0XHRyZXR1cm4gVHJpYW5nbGUuY29udGFpbnNQb2ludCggcG9pbnQsIHRoaXMuYSwgdGhpcy5iLCB0aGlzLmMgKTtcclxuXHJcblx0fVxyXG5cclxuXHRpc0Zyb250RmFjaW5nKCBkaXJlY3Rpb24gKSB7XHJcblxyXG5cdFx0cmV0dXJuIFRyaWFuZ2xlLmlzRnJvbnRGYWNpbmcoIHRoaXMuYSwgdGhpcy5iLCB0aGlzLmMsIGRpcmVjdGlvbiApO1xyXG5cclxuXHR9XHJcblxyXG5cdGludGVyc2VjdHNCb3goIGJveCApIHtcclxuXHJcblx0XHRyZXR1cm4gYm94LmludGVyc2VjdHNUcmlhbmdsZSggdGhpcyApO1xyXG5cclxuXHR9XHJcblxyXG5cdGNsb3Nlc3RQb2ludFRvUG9pbnQoIHAsIHRhcmdldCApIHtcclxuXHJcblx0XHRjb25zdCBhID0gdGhpcy5hLCBiID0gdGhpcy5iLCBjID0gdGhpcy5jO1xyXG5cdFx0bGV0IHYsIHc7XHJcblxyXG5cdFx0Ly8gYWxnb3JpdGhtIHRoYW5rcyB0byBSZWFsLVRpbWUgQ29sbGlzaW9uIERldGVjdGlvbiBieSBDaHJpc3RlciBFcmljc29uLFxyXG5cdFx0Ly8gcHVibGlzaGVkIGJ5IE1vcmdhbiBLYXVmbWFubiBQdWJsaXNoZXJzLCAoYykgMjAwNSBFbHNldmllciBJbmMuLFxyXG5cdFx0Ly8gdW5kZXIgdGhlIGFjY29tcGFueWluZyBsaWNlbnNlOyBzZWUgY2hhcHRlciA1LjEuNSBmb3IgZGV0YWlsZWQgZXhwbGFuYXRpb24uXHJcblx0XHQvLyBiYXNpY2FsbHksIHdlJ3JlIGRpc3Rpbmd1aXNoaW5nIHdoaWNoIG9mIHRoZSB2b3Jvbm9pIHJlZ2lvbnMgb2YgdGhlIHRyaWFuZ2xlXHJcblx0XHQvLyB0aGUgcG9pbnQgbGllcyBpbiB3aXRoIHRoZSBtaW5pbXVtIGFtb3VudCBvZiByZWR1bmRhbnQgY29tcHV0YXRpb24uXHJcblxyXG5cdFx0X3ZhYi5zdWJWZWN0b3JzKCBiLCBhICk7XHJcblx0XHRfdmFjLnN1YlZlY3RvcnMoIGMsIGEgKTtcclxuXHRcdF92YXAuc3ViVmVjdG9ycyggcCwgYSApO1xyXG5cdFx0Y29uc3QgZDEgPSBfdmFiLmRvdCggX3ZhcCApO1xyXG5cdFx0Y29uc3QgZDIgPSBfdmFjLmRvdCggX3ZhcCApO1xyXG5cdFx0aWYgKCBkMSA8PSAwICYmIGQyIDw9IDAgKSB7XHJcblxyXG5cdFx0XHQvLyB2ZXJ0ZXggcmVnaW9uIG9mIEE7IGJhcnljZW50cmljIGNvb3JkcyAoMSwgMCwgMClcclxuXHRcdFx0cmV0dXJuIHRhcmdldC5jb3B5KCBhICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdF92YnAuc3ViVmVjdG9ycyggcCwgYiApO1xyXG5cdFx0Y29uc3QgZDMgPSBfdmFiLmRvdCggX3ZicCApO1xyXG5cdFx0Y29uc3QgZDQgPSBfdmFjLmRvdCggX3ZicCApO1xyXG5cdFx0aWYgKCBkMyA+PSAwICYmIGQ0IDw9IGQzICkge1xyXG5cclxuXHRcdFx0Ly8gdmVydGV4IHJlZ2lvbiBvZiBCOyBiYXJ5Y2VudHJpYyBjb29yZHMgKDAsIDEsIDApXHJcblx0XHRcdHJldHVybiB0YXJnZXQuY29weSggYiApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCB2YyA9IGQxICogZDQgLSBkMyAqIGQyO1xyXG5cdFx0aWYgKCB2YyA8PSAwICYmIGQxID49IDAgJiYgZDMgPD0gMCApIHtcclxuXHJcblx0XHRcdHYgPSBkMSAvICggZDEgLSBkMyApO1xyXG5cdFx0XHQvLyBlZGdlIHJlZ2lvbiBvZiBBQjsgYmFyeWNlbnRyaWMgY29vcmRzICgxLXYsIHYsIDApXHJcblx0XHRcdHJldHVybiB0YXJnZXQuY29weSggYSApLmFkZFNjYWxlZFZlY3RvciggX3ZhYiwgdiApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRfdmNwLnN1YlZlY3RvcnMoIHAsIGMgKTtcclxuXHRcdGNvbnN0IGQ1ID0gX3ZhYi5kb3QoIF92Y3AgKTtcclxuXHRcdGNvbnN0IGQ2ID0gX3ZhYy5kb3QoIF92Y3AgKTtcclxuXHRcdGlmICggZDYgPj0gMCAmJiBkNSA8PSBkNiApIHtcclxuXHJcblx0XHRcdC8vIHZlcnRleCByZWdpb24gb2YgQzsgYmFyeWNlbnRyaWMgY29vcmRzICgwLCAwLCAxKVxyXG5cdFx0XHRyZXR1cm4gdGFyZ2V0LmNvcHkoIGMgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Y29uc3QgdmIgPSBkNSAqIGQyIC0gZDEgKiBkNjtcclxuXHRcdGlmICggdmIgPD0gMCAmJiBkMiA+PSAwICYmIGQ2IDw9IDAgKSB7XHJcblxyXG5cdFx0XHR3ID0gZDIgLyAoIGQyIC0gZDYgKTtcclxuXHRcdFx0Ly8gZWRnZSByZWdpb24gb2YgQUM7IGJhcnljZW50cmljIGNvb3JkcyAoMS13LCAwLCB3KVxyXG5cdFx0XHRyZXR1cm4gdGFyZ2V0LmNvcHkoIGEgKS5hZGRTY2FsZWRWZWN0b3IoIF92YWMsIHcgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Y29uc3QgdmEgPSBkMyAqIGQ2IC0gZDUgKiBkNDtcclxuXHRcdGlmICggdmEgPD0gMCAmJiAoIGQ0IC0gZDMgKSA+PSAwICYmICggZDUgLSBkNiApID49IDAgKSB7XHJcblxyXG5cdFx0XHRfdmJjLnN1YlZlY3RvcnMoIGMsIGIgKTtcclxuXHRcdFx0dyA9ICggZDQgLSBkMyApIC8gKCAoIGQ0IC0gZDMgKSArICggZDUgLSBkNiApICk7XHJcblx0XHRcdC8vIGVkZ2UgcmVnaW9uIG9mIEJDOyBiYXJ5Y2VudHJpYyBjb29yZHMgKDAsIDEtdywgdylcclxuXHRcdFx0cmV0dXJuIHRhcmdldC5jb3B5KCBiICkuYWRkU2NhbGVkVmVjdG9yKCBfdmJjLCB3ICk7IC8vIGVkZ2UgcmVnaW9uIG9mIEJDXHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIGZhY2UgcmVnaW9uXHJcblx0XHRjb25zdCBkZW5vbSA9IDEgLyAoIHZhICsgdmIgKyB2YyApO1xyXG5cdFx0Ly8gdSA9IHZhICogZGVub21cclxuXHRcdHYgPSB2YiAqIGRlbm9tO1xyXG5cdFx0dyA9IHZjICogZGVub207XHJcblxyXG5cdFx0cmV0dXJuIHRhcmdldC5jb3B5KCBhICkuYWRkU2NhbGVkVmVjdG9yKCBfdmFiLCB2ICkuYWRkU2NhbGVkVmVjdG9yKCBfdmFjLCB3ICk7XHJcblxyXG5cdH1cclxuXHJcblx0ZXF1YWxzKCB0cmlhbmdsZSApIHtcclxuXHJcblx0XHRyZXR1cm4gdHJpYW5nbGUuYS5lcXVhbHMoIHRoaXMuYSApICYmIHRyaWFuZ2xlLmIuZXF1YWxzKCB0aGlzLmIgKSAmJiB0cmlhbmdsZS5jLmVxdWFscyggdGhpcy5jICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IFRyaWFuZ2xlIH07XHJcbiIsImltcG9ydCB7IGNsYW1wLCBldWNsaWRlYW5Nb2R1bG8sIGxlcnAgfSBmcm9tICcuL01hdGhVdGlscy5qcyc7XHJcbmltcG9ydCB7IENvbG9yTWFuYWdlbWVudCwgU1JHQlRvTGluZWFyLCBMaW5lYXJUb1NSR0IgfSBmcm9tICcuL0NvbG9yTWFuYWdlbWVudC5qcyc7XHJcbmltcG9ydCB7IFNSR0JDb2xvclNwYWNlIH0gZnJvbSAnLi4vY29uc3RhbnRzLmpzJztcclxuXHJcbmNvbnN0IF9jb2xvcktleXdvcmRzID0geyAnYWxpY2VibHVlJzogMHhGMEY4RkYsICdhbnRpcXVld2hpdGUnOiAweEZBRUJENywgJ2FxdWEnOiAweDAwRkZGRiwgJ2FxdWFtYXJpbmUnOiAweDdGRkZENCwgJ2F6dXJlJzogMHhGMEZGRkYsXHJcblx0J2JlaWdlJzogMHhGNUY1REMsICdiaXNxdWUnOiAweEZGRTRDNCwgJ2JsYWNrJzogMHgwMDAwMDAsICdibGFuY2hlZGFsbW9uZCc6IDB4RkZFQkNELCAnYmx1ZSc6IDB4MDAwMEZGLCAnYmx1ZXZpb2xldCc6IDB4OEEyQkUyLFxyXG5cdCdicm93bic6IDB4QTUyQTJBLCAnYnVybHl3b29kJzogMHhERUI4ODcsICdjYWRldGJsdWUnOiAweDVGOUVBMCwgJ2NoYXJ0cmV1c2UnOiAweDdGRkYwMCwgJ2Nob2NvbGF0ZSc6IDB4RDI2OTFFLCAnY29yYWwnOiAweEZGN0Y1MCxcclxuXHQnY29ybmZsb3dlcmJsdWUnOiAweDY0OTVFRCwgJ2Nvcm5zaWxrJzogMHhGRkY4REMsICdjcmltc29uJzogMHhEQzE0M0MsICdjeWFuJzogMHgwMEZGRkYsICdkYXJrYmx1ZSc6IDB4MDAwMDhCLCAnZGFya2N5YW4nOiAweDAwOEI4QixcclxuXHQnZGFya2dvbGRlbnJvZCc6IDB4Qjg4NjBCLCAnZGFya2dyYXknOiAweEE5QTlBOSwgJ2RhcmtncmVlbic6IDB4MDA2NDAwLCAnZGFya2dyZXknOiAweEE5QTlBOSwgJ2RhcmtraGFraSc6IDB4QkRCNzZCLCAnZGFya21hZ2VudGEnOiAweDhCMDA4QixcclxuXHQnZGFya29saXZlZ3JlZW4nOiAweDU1NkIyRiwgJ2RhcmtvcmFuZ2UnOiAweEZGOEMwMCwgJ2RhcmtvcmNoaWQnOiAweDk5MzJDQywgJ2RhcmtyZWQnOiAweDhCMDAwMCwgJ2RhcmtzYWxtb24nOiAweEU5OTY3QSwgJ2RhcmtzZWFncmVlbic6IDB4OEZCQzhGLFxyXG5cdCdkYXJrc2xhdGVibHVlJzogMHg0ODNEOEIsICdkYXJrc2xhdGVncmF5JzogMHgyRjRGNEYsICdkYXJrc2xhdGVncmV5JzogMHgyRjRGNEYsICdkYXJrdHVycXVvaXNlJzogMHgwMENFRDEsICdkYXJrdmlvbGV0JzogMHg5NDAwRDMsXHJcblx0J2RlZXBwaW5rJzogMHhGRjE0OTMsICdkZWVwc2t5Ymx1ZSc6IDB4MDBCRkZGLCAnZGltZ3JheSc6IDB4Njk2OTY5LCAnZGltZ3JleSc6IDB4Njk2OTY5LCAnZG9kZ2VyYmx1ZSc6IDB4MUU5MEZGLCAnZmlyZWJyaWNrJzogMHhCMjIyMjIsXHJcblx0J2Zsb3JhbHdoaXRlJzogMHhGRkZBRjAsICdmb3Jlc3RncmVlbic6IDB4MjI4QjIyLCAnZnVjaHNpYSc6IDB4RkYwMEZGLCAnZ2FpbnNib3JvJzogMHhEQ0RDREMsICdnaG9zdHdoaXRlJzogMHhGOEY4RkYsICdnb2xkJzogMHhGRkQ3MDAsXHJcblx0J2dvbGRlbnJvZCc6IDB4REFBNTIwLCAnZ3JheSc6IDB4ODA4MDgwLCAnZ3JlZW4nOiAweDAwODAwMCwgJ2dyZWVueWVsbG93JzogMHhBREZGMkYsICdncmV5JzogMHg4MDgwODAsICdob25leWRldyc6IDB4RjBGRkYwLCAnaG90cGluayc6IDB4RkY2OUI0LFxyXG5cdCdpbmRpYW5yZWQnOiAweENENUM1QywgJ2luZGlnbyc6IDB4NEIwMDgyLCAnaXZvcnknOiAweEZGRkZGMCwgJ2toYWtpJzogMHhGMEU2OEMsICdsYXZlbmRlcic6IDB4RTZFNkZBLCAnbGF2ZW5kZXJibHVzaCc6IDB4RkZGMEY1LCAnbGF3bmdyZWVuJzogMHg3Q0ZDMDAsXHJcblx0J2xlbW9uY2hpZmZvbic6IDB4RkZGQUNELCAnbGlnaHRibHVlJzogMHhBREQ4RTYsICdsaWdodGNvcmFsJzogMHhGMDgwODAsICdsaWdodGN5YW4nOiAweEUwRkZGRiwgJ2xpZ2h0Z29sZGVucm9keWVsbG93JzogMHhGQUZBRDIsICdsaWdodGdyYXknOiAweEQzRDNEMyxcclxuXHQnbGlnaHRncmVlbic6IDB4OTBFRTkwLCAnbGlnaHRncmV5JzogMHhEM0QzRDMsICdsaWdodHBpbmsnOiAweEZGQjZDMSwgJ2xpZ2h0c2FsbW9uJzogMHhGRkEwN0EsICdsaWdodHNlYWdyZWVuJzogMHgyMEIyQUEsICdsaWdodHNreWJsdWUnOiAweDg3Q0VGQSxcclxuXHQnbGlnaHRzbGF0ZWdyYXknOiAweDc3ODg5OSwgJ2xpZ2h0c2xhdGVncmV5JzogMHg3Nzg4OTksICdsaWdodHN0ZWVsYmx1ZSc6IDB4QjBDNERFLCAnbGlnaHR5ZWxsb3cnOiAweEZGRkZFMCwgJ2xpbWUnOiAweDAwRkYwMCwgJ2xpbWVncmVlbic6IDB4MzJDRDMyLFxyXG5cdCdsaW5lbic6IDB4RkFGMEU2LCAnbWFnZW50YSc6IDB4RkYwMEZGLCAnbWFyb29uJzogMHg4MDAwMDAsICdtZWRpdW1hcXVhbWFyaW5lJzogMHg2NkNEQUEsICdtZWRpdW1ibHVlJzogMHgwMDAwQ0QsICdtZWRpdW1vcmNoaWQnOiAweEJBNTVEMyxcclxuXHQnbWVkaXVtcHVycGxlJzogMHg5MzcwREIsICdtZWRpdW1zZWFncmVlbic6IDB4M0NCMzcxLCAnbWVkaXVtc2xhdGVibHVlJzogMHg3QjY4RUUsICdtZWRpdW1zcHJpbmdncmVlbic6IDB4MDBGQTlBLCAnbWVkaXVtdHVycXVvaXNlJzogMHg0OEQxQ0MsXHJcblx0J21lZGl1bXZpb2xldHJlZCc6IDB4QzcxNTg1LCAnbWlkbmlnaHRibHVlJzogMHgxOTE5NzAsICdtaW50Y3JlYW0nOiAweEY1RkZGQSwgJ21pc3R5cm9zZSc6IDB4RkZFNEUxLCAnbW9jY2FzaW4nOiAweEZGRTRCNSwgJ25hdmFqb3doaXRlJzogMHhGRkRFQUQsXHJcblx0J25hdnknOiAweDAwMDA4MCwgJ29sZGxhY2UnOiAweEZERjVFNiwgJ29saXZlJzogMHg4MDgwMDAsICdvbGl2ZWRyYWInOiAweDZCOEUyMywgJ29yYW5nZSc6IDB4RkZBNTAwLCAnb3JhbmdlcmVkJzogMHhGRjQ1MDAsICdvcmNoaWQnOiAweERBNzBENixcclxuXHQncGFsZWdvbGRlbnJvZCc6IDB4RUVFOEFBLCAncGFsZWdyZWVuJzogMHg5OEZCOTgsICdwYWxldHVycXVvaXNlJzogMHhBRkVFRUUsICdwYWxldmlvbGV0cmVkJzogMHhEQjcwOTMsICdwYXBheWF3aGlwJzogMHhGRkVGRDUsICdwZWFjaHB1ZmYnOiAweEZGREFCOSxcclxuXHQncGVydSc6IDB4Q0Q4NTNGLCAncGluayc6IDB4RkZDMENCLCAncGx1bSc6IDB4RERBMERELCAncG93ZGVyYmx1ZSc6IDB4QjBFMEU2LCAncHVycGxlJzogMHg4MDAwODAsICdyZWJlY2NhcHVycGxlJzogMHg2NjMzOTksICdyZWQnOiAweEZGMDAwMCwgJ3Jvc3licm93bic6IDB4QkM4RjhGLFxyXG5cdCdyb3lhbGJsdWUnOiAweDQxNjlFMSwgJ3NhZGRsZWJyb3duJzogMHg4QjQ1MTMsICdzYWxtb24nOiAweEZBODA3MiwgJ3NhbmR5YnJvd24nOiAweEY0QTQ2MCwgJ3NlYWdyZWVuJzogMHgyRThCNTcsICdzZWFzaGVsbCc6IDB4RkZGNUVFLFxyXG5cdCdzaWVubmEnOiAweEEwNTIyRCwgJ3NpbHZlcic6IDB4QzBDMEMwLCAnc2t5Ymx1ZSc6IDB4ODdDRUVCLCAnc2xhdGVibHVlJzogMHg2QTVBQ0QsICdzbGF0ZWdyYXknOiAweDcwODA5MCwgJ3NsYXRlZ3JleSc6IDB4NzA4MDkwLCAnc25vdyc6IDB4RkZGQUZBLFxyXG5cdCdzcHJpbmdncmVlbic6IDB4MDBGRjdGLCAnc3RlZWxibHVlJzogMHg0NjgyQjQsICd0YW4nOiAweEQyQjQ4QywgJ3RlYWwnOiAweDAwODA4MCwgJ3RoaXN0bGUnOiAweEQ4QkZEOCwgJ3RvbWF0byc6IDB4RkY2MzQ3LCAndHVycXVvaXNlJzogMHg0MEUwRDAsXHJcblx0J3Zpb2xldCc6IDB4RUU4MkVFLCAnd2hlYXQnOiAweEY1REVCMywgJ3doaXRlJzogMHhGRkZGRkYsICd3aGl0ZXNtb2tlJzogMHhGNUY1RjUsICd5ZWxsb3cnOiAweEZGRkYwMCwgJ3llbGxvd2dyZWVuJzogMHg5QUNEMzIgfTtcclxuXHJcbmNvbnN0IF9oc2xBID0geyBoOiAwLCBzOiAwLCBsOiAwIH07XHJcbmNvbnN0IF9oc2xCID0geyBoOiAwLCBzOiAwLCBsOiAwIH07XHJcblxyXG5mdW5jdGlvbiBodWUycmdiKCBwLCBxLCB0ICkge1xyXG5cclxuXHRpZiAoIHQgPCAwICkgdCArPSAxO1xyXG5cdGlmICggdCA+IDEgKSB0IC09IDE7XHJcblx0aWYgKCB0IDwgMSAvIDYgKSByZXR1cm4gcCArICggcSAtIHAgKSAqIDYgKiB0O1xyXG5cdGlmICggdCA8IDEgLyAyICkgcmV0dXJuIHE7XHJcblx0aWYgKCB0IDwgMiAvIDMgKSByZXR1cm4gcCArICggcSAtIHAgKSAqIDYgKiAoIDIgLyAzIC0gdCApO1xyXG5cdHJldHVybiBwO1xyXG5cclxufVxyXG5cclxuY2xhc3MgQ29sb3Ige1xyXG5cclxuXHRjb25zdHJ1Y3RvciggciwgZywgYiApIHtcclxuXHJcblx0XHR0aGlzLmlzQ29sb3IgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMuciA9IDE7XHJcblx0XHR0aGlzLmcgPSAxO1xyXG5cdFx0dGhpcy5iID0gMTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5zZXQoIHIsIGcsIGIgKTtcclxuXHJcblx0fVxyXG5cclxuXHRzZXQoIHIsIGcsIGIgKSB7XHJcblxyXG5cdFx0aWYgKCBnID09PSB1bmRlZmluZWQgJiYgYiA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0Ly8gciBpcyBUSFJFRS5Db2xvciwgaGV4IG9yIHN0cmluZ1xyXG5cclxuXHRcdFx0Y29uc3QgdmFsdWUgPSByO1xyXG5cclxuXHRcdFx0aWYgKCB2YWx1ZSAmJiB2YWx1ZS5pc0NvbG9yICkge1xyXG5cclxuXHRcdFx0XHR0aGlzLmNvcHkoIHZhbHVlICk7XHJcblxyXG5cdFx0XHR9IGVsc2UgaWYgKCB0eXBlb2YgdmFsdWUgPT09ICdudW1iZXInICkge1xyXG5cclxuXHRcdFx0XHR0aGlzLnNldEhleCggdmFsdWUgKTtcclxuXHJcblx0XHRcdH0gZWxzZSBpZiAoIHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZycgKSB7XHJcblxyXG5cdFx0XHRcdHRoaXMuc2V0U3R5bGUoIHZhbHVlICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdHRoaXMuc2V0UkdCKCByLCBnLCBiICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldFNjYWxhciggc2NhbGFyICkge1xyXG5cclxuXHRcdHRoaXMuciA9IHNjYWxhcjtcclxuXHRcdHRoaXMuZyA9IHNjYWxhcjtcclxuXHRcdHRoaXMuYiA9IHNjYWxhcjtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRIZXgoIGhleCwgY29sb3JTcGFjZSA9IFNSR0JDb2xvclNwYWNlICkge1xyXG5cclxuXHRcdGhleCA9IE1hdGguZmxvb3IoIGhleCApO1xyXG5cclxuXHRcdHRoaXMuciA9ICggaGV4ID4+IDE2ICYgMjU1ICkgLyAyNTU7XHJcblx0XHR0aGlzLmcgPSAoIGhleCA+PiA4ICYgMjU1ICkgLyAyNTU7XHJcblx0XHR0aGlzLmIgPSAoIGhleCAmIDI1NSApIC8gMjU1O1xyXG5cclxuXHRcdENvbG9yTWFuYWdlbWVudC50b1dvcmtpbmdDb2xvclNwYWNlKCB0aGlzLCBjb2xvclNwYWNlICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0UkdCKCByLCBnLCBiLCBjb2xvclNwYWNlID0gQ29sb3JNYW5hZ2VtZW50LndvcmtpbmdDb2xvclNwYWNlICkge1xyXG5cclxuXHRcdHRoaXMuciA9IHI7XHJcblx0XHR0aGlzLmcgPSBnO1xyXG5cdFx0dGhpcy5iID0gYjtcclxuXHJcblx0XHRDb2xvck1hbmFnZW1lbnQudG9Xb3JraW5nQ29sb3JTcGFjZSggdGhpcywgY29sb3JTcGFjZSApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldEhTTCggaCwgcywgbCwgY29sb3JTcGFjZSA9IENvbG9yTWFuYWdlbWVudC53b3JraW5nQ29sb3JTcGFjZSApIHtcclxuXHJcblx0XHQvLyBoLHMsbCByYW5nZXMgYXJlIGluIDAuMCAtIDEuMFxyXG5cdFx0aCA9IGV1Y2xpZGVhbk1vZHVsbyggaCwgMSApO1xyXG5cdFx0cyA9IGNsYW1wKCBzLCAwLCAxICk7XHJcblx0XHRsID0gY2xhbXAoIGwsIDAsIDEgKTtcclxuXHJcblx0XHRpZiAoIHMgPT09IDAgKSB7XHJcblxyXG5cdFx0XHR0aGlzLnIgPSB0aGlzLmcgPSB0aGlzLmIgPSBsO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRjb25zdCBwID0gbCA8PSAwLjUgPyBsICogKCAxICsgcyApIDogbCArIHMgLSAoIGwgKiBzICk7XHJcblx0XHRcdGNvbnN0IHEgPSAoIDIgKiBsICkgLSBwO1xyXG5cclxuXHRcdFx0dGhpcy5yID0gaHVlMnJnYiggcSwgcCwgaCArIDEgLyAzICk7XHJcblx0XHRcdHRoaXMuZyA9IGh1ZTJyZ2IoIHEsIHAsIGggKTtcclxuXHRcdFx0dGhpcy5iID0gaHVlMnJnYiggcSwgcCwgaCAtIDEgLyAzICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdENvbG9yTWFuYWdlbWVudC50b1dvcmtpbmdDb2xvclNwYWNlKCB0aGlzLCBjb2xvclNwYWNlICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0U3R5bGUoIHN0eWxlLCBjb2xvclNwYWNlID0gU1JHQkNvbG9yU3BhY2UgKSB7XHJcblxyXG5cdFx0ZnVuY3Rpb24gaGFuZGxlQWxwaGEoIHN0cmluZyApIHtcclxuXHJcblx0XHRcdGlmICggc3RyaW5nID09PSB1bmRlZmluZWQgKSByZXR1cm47XHJcblxyXG5cdFx0XHRpZiAoIHBhcnNlRmxvYXQoIHN0cmluZyApIDwgMSApIHtcclxuXHJcblx0XHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuQ29sb3I6IEFscGhhIGNvbXBvbmVudCBvZiAnICsgc3R5bGUgKyAnIHdpbGwgYmUgaWdub3JlZC4nICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHJcblx0XHRsZXQgbTtcclxuXHJcblx0XHRpZiAoIG0gPSAvXihcXHcrKVxcKChbXlxcKV0qKVxcKS8uZXhlYyggc3R5bGUgKSApIHtcclxuXHJcblx0XHRcdC8vIHJnYiAvIGhzbFxyXG5cclxuXHRcdFx0bGV0IGNvbG9yO1xyXG5cdFx0XHRjb25zdCBuYW1lID0gbVsgMSBdO1xyXG5cdFx0XHRjb25zdCBjb21wb25lbnRzID0gbVsgMiBdO1xyXG5cclxuXHRcdFx0c3dpdGNoICggbmFtZSApIHtcclxuXHJcblx0XHRcdFx0Y2FzZSAncmdiJzpcclxuXHRcdFx0XHRjYXNlICdyZ2JhJzpcclxuXHJcblx0XHRcdFx0XHRpZiAoIGNvbG9yID0gL15cXHMqKFxcZCspXFxzKixcXHMqKFxcZCspXFxzKixcXHMqKFxcZCspXFxzKig/OixcXHMqKFxcZCpcXC4/XFxkKylcXHMqKT8kLy5leGVjKCBjb21wb25lbnRzICkgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHQvLyByZ2IoMjU1LDAsMCkgcmdiYSgyNTUsMCwwLDAuNSlcclxuXHJcblx0XHRcdFx0XHRcdGhhbmRsZUFscGhhKCBjb2xvclsgNCBdICk7XHJcblxyXG5cdFx0XHRcdFx0XHRyZXR1cm4gdGhpcy5zZXRSR0IoXHJcblx0XHRcdFx0XHRcdFx0TWF0aC5taW4oIDI1NSwgcGFyc2VJbnQoIGNvbG9yWyAxIF0sIDEwICkgKSAvIDI1NSxcclxuXHRcdFx0XHRcdFx0XHRNYXRoLm1pbiggMjU1LCBwYXJzZUludCggY29sb3JbIDIgXSwgMTAgKSApIC8gMjU1LFxyXG5cdFx0XHRcdFx0XHRcdE1hdGgubWluKCAyNTUsIHBhcnNlSW50KCBjb2xvclsgMyBdLCAxMCApICkgLyAyNTUsXHJcblx0XHRcdFx0XHRcdFx0Y29sb3JTcGFjZVxyXG5cdFx0XHRcdFx0XHQpO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRpZiAoIGNvbG9yID0gL15cXHMqKFxcZCspXFwlXFxzKixcXHMqKFxcZCspXFwlXFxzKixcXHMqKFxcZCspXFwlXFxzKig/OixcXHMqKFxcZCpcXC4/XFxkKylcXHMqKT8kLy5leGVjKCBjb21wb25lbnRzICkgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHQvLyByZ2IoMTAwJSwwJSwwJSkgcmdiYSgxMDAlLDAlLDAlLDAuNSlcclxuXHJcblx0XHRcdFx0XHRcdGhhbmRsZUFscGhhKCBjb2xvclsgNCBdICk7XHJcblxyXG5cdFx0XHRcdFx0XHRyZXR1cm4gdGhpcy5zZXRSR0IoXHJcblx0XHRcdFx0XHRcdFx0TWF0aC5taW4oIDEwMCwgcGFyc2VJbnQoIGNvbG9yWyAxIF0sIDEwICkgKSAvIDEwMCxcclxuXHRcdFx0XHRcdFx0XHRNYXRoLm1pbiggMTAwLCBwYXJzZUludCggY29sb3JbIDIgXSwgMTAgKSApIC8gMTAwLFxyXG5cdFx0XHRcdFx0XHRcdE1hdGgubWluKCAxMDAsIHBhcnNlSW50KCBjb2xvclsgMyBdLCAxMCApICkgLyAxMDAsXHJcblx0XHRcdFx0XHRcdFx0Y29sb3JTcGFjZVxyXG5cdFx0XHRcdFx0XHQpO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdFx0Y2FzZSAnaHNsJzpcclxuXHRcdFx0XHRjYXNlICdoc2xhJzpcclxuXHJcblx0XHRcdFx0XHRpZiAoIGNvbG9yID0gL15cXHMqKFxcZCpcXC4/XFxkKylcXHMqLFxccyooXFxkKlxcLj9cXGQrKVxcJVxccyosXFxzKihcXGQqXFwuP1xcZCspXFwlXFxzKig/OixcXHMqKFxcZCpcXC4/XFxkKylcXHMqKT8kLy5leGVjKCBjb21wb25lbnRzICkgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHQvLyBoc2woMTIwLDUwJSw1MCUpIGhzbGEoMTIwLDUwJSw1MCUsMC41KVxyXG5cclxuXHRcdFx0XHRcdFx0aGFuZGxlQWxwaGEoIGNvbG9yWyA0IF0gKTtcclxuXHJcblx0XHRcdFx0XHRcdHJldHVybiB0aGlzLnNldEhTTChcclxuXHRcdFx0XHRcdFx0XHRwYXJzZUZsb2F0KCBjb2xvclsgMSBdICkgLyAzNjAsXHJcblx0XHRcdFx0XHRcdFx0cGFyc2VGbG9hdCggY29sb3JbIDIgXSApIC8gMTAwLFxyXG5cdFx0XHRcdFx0XHRcdHBhcnNlRmxvYXQoIGNvbG9yWyAzIF0gKSAvIDEwMCxcclxuXHRcdFx0XHRcdFx0XHRjb2xvclNwYWNlXHJcblx0XHRcdFx0XHRcdCk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0XHRkZWZhdWx0OlxyXG5cclxuXHRcdFx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLkNvbG9yOiBVbmtub3duIGNvbG9yIG1vZGVsICcgKyBzdHlsZSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH0gZWxzZSBpZiAoIG0gPSAvXlxcIyhbQS1GYS1mXFxkXSspJC8uZXhlYyggc3R5bGUgKSApIHtcclxuXHJcblx0XHRcdC8vIGhleCBjb2xvclxyXG5cclxuXHRcdFx0Y29uc3QgaGV4ID0gbVsgMSBdO1xyXG5cdFx0XHRjb25zdCBzaXplID0gaGV4Lmxlbmd0aDtcclxuXHJcblx0XHRcdGlmICggc2l6ZSA9PT0gMyApIHtcclxuXHJcblx0XHRcdFx0Ly8gI2ZmMFxyXG5cdFx0XHRcdHJldHVybiB0aGlzLnNldFJHQihcclxuXHRcdFx0XHRcdHBhcnNlSW50KCBoZXguY2hhckF0KCAwICksIDE2ICkgLyAxNSxcclxuXHRcdFx0XHRcdHBhcnNlSW50KCBoZXguY2hhckF0KCAxICksIDE2ICkgLyAxNSxcclxuXHRcdFx0XHRcdHBhcnNlSW50KCBoZXguY2hhckF0KCAyICksIDE2ICkgLyAxNSxcclxuXHRcdFx0XHRcdGNvbG9yU3BhY2VcclxuXHRcdFx0XHQpO1xyXG5cclxuXHRcdFx0fSBlbHNlIGlmICggc2l6ZSA9PT0gNiApIHtcclxuXHJcblx0XHRcdFx0Ly8gI2ZmMDAwMFxyXG5cdFx0XHRcdHJldHVybiB0aGlzLnNldEhleCggcGFyc2VJbnQoIGhleCwgMTYgKSwgY29sb3JTcGFjZSApO1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuQ29sb3I6IEludmFsaWQgaGV4IGNvbG9yICcgKyBzdHlsZSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH0gZWxzZSBpZiAoIHN0eWxlICYmIHN0eWxlLmxlbmd0aCA+IDAgKSB7XHJcblxyXG5cdFx0XHRyZXR1cm4gdGhpcy5zZXRDb2xvck5hbWUoIHN0eWxlLCBjb2xvclNwYWNlICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldENvbG9yTmFtZSggc3R5bGUsIGNvbG9yU3BhY2UgPSBTUkdCQ29sb3JTcGFjZSApIHtcclxuXHJcblx0XHQvLyBjb2xvciBrZXl3b3Jkc1xyXG5cdFx0Y29uc3QgaGV4ID0gX2NvbG9yS2V5d29yZHNbIHN0eWxlLnRvTG93ZXJDYXNlKCkgXTtcclxuXHJcblx0XHRpZiAoIGhleCAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0Ly8gcmVkXHJcblx0XHRcdHRoaXMuc2V0SGV4KCBoZXgsIGNvbG9yU3BhY2UgKTtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0Ly8gdW5rbm93biBjb2xvclxyXG5cdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5Db2xvcjogVW5rbm93biBjb2xvciAnICsgc3R5bGUgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Y2xvbmUoKSB7XHJcblxyXG5cdFx0cmV0dXJuIG5ldyB0aGlzLmNvbnN0cnVjdG9yKCB0aGlzLnIsIHRoaXMuZywgdGhpcy5iICk7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggY29sb3IgKSB7XHJcblxyXG5cdFx0dGhpcy5yID0gY29sb3IucjtcclxuXHRcdHRoaXMuZyA9IGNvbG9yLmc7XHJcblx0XHR0aGlzLmIgPSBjb2xvci5iO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGNvcHlTUkdCVG9MaW5lYXIoIGNvbG9yICkge1xyXG5cclxuXHRcdHRoaXMuciA9IFNSR0JUb0xpbmVhciggY29sb3IuciApO1xyXG5cdFx0dGhpcy5nID0gU1JHQlRvTGluZWFyKCBjb2xvci5nICk7XHJcblx0XHR0aGlzLmIgPSBTUkdCVG9MaW5lYXIoIGNvbG9yLmIgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRjb3B5TGluZWFyVG9TUkdCKCBjb2xvciApIHtcclxuXHJcblx0XHR0aGlzLnIgPSBMaW5lYXJUb1NSR0IoIGNvbG9yLnIgKTtcclxuXHRcdHRoaXMuZyA9IExpbmVhclRvU1JHQiggY29sb3IuZyApO1xyXG5cdFx0dGhpcy5iID0gTGluZWFyVG9TUkdCKCBjb2xvci5iICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Y29udmVydFNSR0JUb0xpbmVhcigpIHtcclxuXHJcblx0XHR0aGlzLmNvcHlTUkdCVG9MaW5lYXIoIHRoaXMgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRjb252ZXJ0TGluZWFyVG9TUkdCKCkge1xyXG5cclxuXHRcdHRoaXMuY29weUxpbmVhclRvU1JHQiggdGhpcyApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldEhleCggY29sb3JTcGFjZSA9IFNSR0JDb2xvclNwYWNlICkge1xyXG5cclxuXHRcdENvbG9yTWFuYWdlbWVudC5mcm9tV29ya2luZ0NvbG9yU3BhY2UoIF9jb2xvci5jb3B5KCB0aGlzICksIGNvbG9yU3BhY2UgKTtcclxuXHJcblx0XHRyZXR1cm4gTWF0aC5yb3VuZCggY2xhbXAoIF9jb2xvci5yICogMjU1LCAwLCAyNTUgKSApICogNjU1MzYgKyBNYXRoLnJvdW5kKCBjbGFtcCggX2NvbG9yLmcgKiAyNTUsIDAsIDI1NSApICkgKiAyNTYgKyBNYXRoLnJvdW5kKCBjbGFtcCggX2NvbG9yLmIgKiAyNTUsIDAsIDI1NSApICk7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0SGV4U3RyaW5nKCBjb2xvclNwYWNlID0gU1JHQkNvbG9yU3BhY2UgKSB7XHJcblxyXG5cdFx0cmV0dXJuICggJzAwMDAwMCcgKyB0aGlzLmdldEhleCggY29sb3JTcGFjZSApLnRvU3RyaW5nKCAxNiApICkuc2xpY2UoIC0gNiApO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldEhTTCggdGFyZ2V0LCBjb2xvclNwYWNlID0gQ29sb3JNYW5hZ2VtZW50LndvcmtpbmdDb2xvclNwYWNlICkge1xyXG5cclxuXHRcdC8vIGgscyxsIHJhbmdlcyBhcmUgaW4gMC4wIC0gMS4wXHJcblxyXG5cdFx0Q29sb3JNYW5hZ2VtZW50LmZyb21Xb3JraW5nQ29sb3JTcGFjZSggX2NvbG9yLmNvcHkoIHRoaXMgKSwgY29sb3JTcGFjZSApO1xyXG5cclxuXHRcdGNvbnN0IHIgPSBfY29sb3IuciwgZyA9IF9jb2xvci5nLCBiID0gX2NvbG9yLmI7XHJcblxyXG5cdFx0Y29uc3QgbWF4ID0gTWF0aC5tYXgoIHIsIGcsIGIgKTtcclxuXHRcdGNvbnN0IG1pbiA9IE1hdGgubWluKCByLCBnLCBiICk7XHJcblxyXG5cdFx0bGV0IGh1ZSwgc2F0dXJhdGlvbjtcclxuXHRcdGNvbnN0IGxpZ2h0bmVzcyA9ICggbWluICsgbWF4ICkgLyAyLjA7XHJcblxyXG5cdFx0aWYgKCBtaW4gPT09IG1heCApIHtcclxuXHJcblx0XHRcdGh1ZSA9IDA7XHJcblx0XHRcdHNhdHVyYXRpb24gPSAwO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRjb25zdCBkZWx0YSA9IG1heCAtIG1pbjtcclxuXHJcblx0XHRcdHNhdHVyYXRpb24gPSBsaWdodG5lc3MgPD0gMC41ID8gZGVsdGEgLyAoIG1heCArIG1pbiApIDogZGVsdGEgLyAoIDIgLSBtYXggLSBtaW4gKTtcclxuXHJcblx0XHRcdHN3aXRjaCAoIG1heCApIHtcclxuXHJcblx0XHRcdFx0Y2FzZSByOiBodWUgPSAoIGcgLSBiICkgLyBkZWx0YSArICggZyA8IGIgPyA2IDogMCApOyBicmVhaztcclxuXHRcdFx0XHRjYXNlIGc6IGh1ZSA9ICggYiAtIHIgKSAvIGRlbHRhICsgMjsgYnJlYWs7XHJcblx0XHRcdFx0Y2FzZSBiOiBodWUgPSAoIHIgLSBnICkgLyBkZWx0YSArIDQ7IGJyZWFrO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0aHVlIC89IDY7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRhcmdldC5oID0gaHVlO1xyXG5cdFx0dGFyZ2V0LnMgPSBzYXR1cmF0aW9uO1xyXG5cdFx0dGFyZ2V0LmwgPSBsaWdodG5lc3M7XHJcblxyXG5cdFx0cmV0dXJuIHRhcmdldDtcclxuXHJcblx0fVxyXG5cclxuXHRnZXRSR0IoIHRhcmdldCwgY29sb3JTcGFjZSA9IENvbG9yTWFuYWdlbWVudC53b3JraW5nQ29sb3JTcGFjZSApIHtcclxuXHJcblx0XHRDb2xvck1hbmFnZW1lbnQuZnJvbVdvcmtpbmdDb2xvclNwYWNlKCBfY29sb3IuY29weSggdGhpcyApLCBjb2xvclNwYWNlICk7XHJcblxyXG5cdFx0dGFyZ2V0LnIgPSBfY29sb3IucjtcclxuXHRcdHRhcmdldC5nID0gX2NvbG9yLmc7XHJcblx0XHR0YXJnZXQuYiA9IF9jb2xvci5iO1xyXG5cclxuXHRcdHJldHVybiB0YXJnZXQ7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0U3R5bGUoIGNvbG9yU3BhY2UgPSBTUkdCQ29sb3JTcGFjZSApIHtcclxuXHJcblx0XHRDb2xvck1hbmFnZW1lbnQuZnJvbVdvcmtpbmdDb2xvclNwYWNlKCBfY29sb3IuY29weSggdGhpcyApLCBjb2xvclNwYWNlICk7XHJcblxyXG5cdFx0Y29uc3QgciA9IF9jb2xvci5yLCBnID0gX2NvbG9yLmcsIGIgPSBfY29sb3IuYjtcclxuXHJcblx0XHRpZiAoIGNvbG9yU3BhY2UgIT09IFNSR0JDb2xvclNwYWNlICkge1xyXG5cclxuXHRcdFx0Ly8gUmVxdWlyZXMgQ1NTIENvbG9yIE1vZHVsZSBMZXZlbCA0IChodHRwczovL3d3dy53My5vcmcvVFIvY3NzLWNvbG9yLTQvKS5cclxuXHRcdFx0cmV0dXJuIGBjb2xvcigkeyBjb2xvclNwYWNlIH0gJHsgci50b0ZpeGVkKCAzICkgfSAkeyBnLnRvRml4ZWQoIDMgKSB9ICR7IGIudG9GaXhlZCggMyApIH0pYDtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIGByZ2IoJHsgTWF0aC5yb3VuZCggciAqIDI1NSApIH0sJHsgTWF0aC5yb3VuZCggZyAqIDI1NSApIH0sJHsgTWF0aC5yb3VuZCggYiAqIDI1NSApIH0pYDtcclxuXHJcblx0fVxyXG5cclxuXHRvZmZzZXRIU0woIGgsIHMsIGwgKSB7XHJcblxyXG5cdFx0dGhpcy5nZXRIU0woIF9oc2xBICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuc2V0SFNMKCBfaHNsQS5oICsgaCwgX2hzbEEucyArIHMsIF9oc2xBLmwgKyBsICk7XHJcblxyXG5cdH1cclxuXHJcblx0YWRkKCBjb2xvciApIHtcclxuXHJcblx0XHR0aGlzLnIgKz0gY29sb3IucjtcclxuXHRcdHRoaXMuZyArPSBjb2xvci5nO1xyXG5cdFx0dGhpcy5iICs9IGNvbG9yLmI7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0YWRkQ29sb3JzKCBjb2xvcjEsIGNvbG9yMiApIHtcclxuXHJcblx0XHR0aGlzLnIgPSBjb2xvcjEuciArIGNvbG9yMi5yO1xyXG5cdFx0dGhpcy5nID0gY29sb3IxLmcgKyBjb2xvcjIuZztcclxuXHRcdHRoaXMuYiA9IGNvbG9yMS5iICsgY29sb3IyLmI7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0YWRkU2NhbGFyKCBzICkge1xyXG5cclxuXHRcdHRoaXMuciArPSBzO1xyXG5cdFx0dGhpcy5nICs9IHM7XHJcblx0XHR0aGlzLmIgKz0gcztcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzdWIoIGNvbG9yICkge1xyXG5cclxuXHRcdHRoaXMuciA9IE1hdGgubWF4KCAwLCB0aGlzLnIgLSBjb2xvci5yICk7XHJcblx0XHR0aGlzLmcgPSBNYXRoLm1heCggMCwgdGhpcy5nIC0gY29sb3IuZyApO1xyXG5cdFx0dGhpcy5iID0gTWF0aC5tYXgoIDAsIHRoaXMuYiAtIGNvbG9yLmIgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRtdWx0aXBseSggY29sb3IgKSB7XHJcblxyXG5cdFx0dGhpcy5yICo9IGNvbG9yLnI7XHJcblx0XHR0aGlzLmcgKj0gY29sb3IuZztcclxuXHRcdHRoaXMuYiAqPSBjb2xvci5iO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdG11bHRpcGx5U2NhbGFyKCBzICkge1xyXG5cclxuXHRcdHRoaXMuciAqPSBzO1xyXG5cdFx0dGhpcy5nICo9IHM7XHJcblx0XHR0aGlzLmIgKj0gcztcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRsZXJwKCBjb2xvciwgYWxwaGEgKSB7XHJcblxyXG5cdFx0dGhpcy5yICs9ICggY29sb3IuciAtIHRoaXMuciApICogYWxwaGE7XHJcblx0XHR0aGlzLmcgKz0gKCBjb2xvci5nIC0gdGhpcy5nICkgKiBhbHBoYTtcclxuXHRcdHRoaXMuYiArPSAoIGNvbG9yLmIgLSB0aGlzLmIgKSAqIGFscGhhO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGxlcnBDb2xvcnMoIGNvbG9yMSwgY29sb3IyLCBhbHBoYSApIHtcclxuXHJcblx0XHR0aGlzLnIgPSBjb2xvcjEuciArICggY29sb3IyLnIgLSBjb2xvcjEuciApICogYWxwaGE7XHJcblx0XHR0aGlzLmcgPSBjb2xvcjEuZyArICggY29sb3IyLmcgLSBjb2xvcjEuZyApICogYWxwaGE7XHJcblx0XHR0aGlzLmIgPSBjb2xvcjEuYiArICggY29sb3IyLmIgLSBjb2xvcjEuYiApICogYWxwaGE7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0bGVycEhTTCggY29sb3IsIGFscGhhICkge1xyXG5cclxuXHRcdHRoaXMuZ2V0SFNMKCBfaHNsQSApO1xyXG5cdFx0Y29sb3IuZ2V0SFNMKCBfaHNsQiApO1xyXG5cclxuXHRcdGNvbnN0IGggPSBsZXJwKCBfaHNsQS5oLCBfaHNsQi5oLCBhbHBoYSApO1xyXG5cdFx0Y29uc3QgcyA9IGxlcnAoIF9oc2xBLnMsIF9oc2xCLnMsIGFscGhhICk7XHJcblx0XHRjb25zdCBsID0gbGVycCggX2hzbEEubCwgX2hzbEIubCwgYWxwaGEgKTtcclxuXHJcblx0XHR0aGlzLnNldEhTTCggaCwgcywgbCApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldEZyb21WZWN0b3IzKCB2ICkge1xyXG5cclxuXHRcdHRoaXMuciA9IHYueDtcclxuXHRcdHRoaXMuZyA9IHYueTtcclxuXHRcdHRoaXMuYiA9IHYuejtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRhcHBseU1hdHJpeDMoIG0gKSB7XHJcblxyXG5cdFx0Y29uc3QgciA9IHRoaXMuciwgZyA9IHRoaXMuZywgYiA9IHRoaXMuYjtcclxuXHRcdGNvbnN0IGUgPSBtLmVsZW1lbnRzO1xyXG5cclxuXHRcdHRoaXMuciA9IGVbIDAgXSAqIHIgKyBlWyAzIF0gKiBnICsgZVsgNiBdICogYjtcclxuXHRcdHRoaXMuZyA9IGVbIDEgXSAqIHIgKyBlWyA0IF0gKiBnICsgZVsgNyBdICogYjtcclxuXHRcdHRoaXMuYiA9IGVbIDIgXSAqIHIgKyBlWyA1IF0gKiBnICsgZVsgOCBdICogYjtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRlcXVhbHMoIGMgKSB7XHJcblxyXG5cdFx0cmV0dXJuICggYy5yID09PSB0aGlzLnIgKSAmJiAoIGMuZyA9PT0gdGhpcy5nICkgJiYgKCBjLmIgPT09IHRoaXMuYiApO1xyXG5cclxuXHR9XHJcblxyXG5cdGZyb21BcnJheSggYXJyYXksIG9mZnNldCA9IDAgKSB7XHJcblxyXG5cdFx0dGhpcy5yID0gYXJyYXlbIG9mZnNldCBdO1xyXG5cdFx0dGhpcy5nID0gYXJyYXlbIG9mZnNldCArIDEgXTtcclxuXHRcdHRoaXMuYiA9IGFycmF5WyBvZmZzZXQgKyAyIF07XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0dG9BcnJheSggYXJyYXkgPSBbXSwgb2Zmc2V0ID0gMCApIHtcclxuXHJcblx0XHRhcnJheVsgb2Zmc2V0IF0gPSB0aGlzLnI7XHJcblx0XHRhcnJheVsgb2Zmc2V0ICsgMSBdID0gdGhpcy5nO1xyXG5cdFx0YXJyYXlbIG9mZnNldCArIDIgXSA9IHRoaXMuYjtcclxuXHJcblx0XHRyZXR1cm4gYXJyYXk7XHJcblxyXG5cdH1cclxuXHJcblx0ZnJvbUJ1ZmZlckF0dHJpYnV0ZSggYXR0cmlidXRlLCBpbmRleCApIHtcclxuXHJcblx0XHR0aGlzLnIgPSBhdHRyaWJ1dGUuZ2V0WCggaW5kZXggKTtcclxuXHRcdHRoaXMuZyA9IGF0dHJpYnV0ZS5nZXRZKCBpbmRleCApO1xyXG5cdFx0dGhpcy5iID0gYXR0cmlidXRlLmdldFooIGluZGV4ICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0dG9KU09OKCkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLmdldEhleCgpO1xyXG5cclxuXHR9XHJcblxyXG5cdCpbIFN5bWJvbC5pdGVyYXRvciBdKCkge1xyXG5cclxuXHRcdHlpZWxkIHRoaXMucjtcclxuXHRcdHlpZWxkIHRoaXMuZztcclxuXHRcdHlpZWxkIHRoaXMuYjtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuY29uc3QgX2NvbG9yID0gLypAX19QVVJFX18qLyBuZXcgQ29sb3IoKTtcclxuXHJcbkNvbG9yLk5BTUVTID0gX2NvbG9yS2V5d29yZHM7XHJcblxyXG5leHBvcnQgeyBDb2xvciB9O1xyXG4iLCJpbXBvcnQgeyBDb2xvciB9IGZyb20gJy4uL21hdGgvQ29sb3IuanMnO1xyXG5pbXBvcnQgeyBFdmVudERpc3BhdGNoZXIgfSBmcm9tICcuLi9jb3JlL0V2ZW50RGlzcGF0Y2hlci5qcyc7XHJcbmltcG9ydCB7IEZyb250U2lkZSwgTm9ybWFsQmxlbmRpbmcsIExlc3NFcXVhbERlcHRoLCBBZGRFcXVhdGlvbiwgT25lTWludXNTcmNBbHBoYUZhY3RvciwgU3JjQWxwaGFGYWN0b3IsIEFsd2F5c1N0ZW5jaWxGdW5jLCBLZWVwU3RlbmNpbE9wIH0gZnJvbSAnLi4vY29uc3RhbnRzLmpzJztcclxuaW1wb3J0ICogYXMgTWF0aFV0aWxzIGZyb20gJy4uL21hdGgvTWF0aFV0aWxzLmpzJztcclxuXHJcbmxldCBfbWF0ZXJpYWxJZCA9IDA7XHJcblxyXG5jbGFzcyBNYXRlcmlhbCBleHRlbmRzIEV2ZW50RGlzcGF0Y2hlciB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCkge1xyXG5cclxuXHRcdHN1cGVyKCk7XHJcblxyXG5cdFx0dGhpcy5pc01hdGVyaWFsID0gdHJ1ZTtcclxuXHJcblx0XHRPYmplY3QuZGVmaW5lUHJvcGVydHkoIHRoaXMsICdpZCcsIHsgdmFsdWU6IF9tYXRlcmlhbElkICsrIH0gKTtcclxuXHJcblx0XHR0aGlzLnV1aWQgPSBNYXRoVXRpbHMuZ2VuZXJhdGVVVUlEKCk7XHJcblxyXG5cdFx0dGhpcy5uYW1lID0gJyc7XHJcblx0XHR0aGlzLnR5cGUgPSAnTWF0ZXJpYWwnO1xyXG5cclxuXHRcdHRoaXMuYmxlbmRpbmcgPSBOb3JtYWxCbGVuZGluZztcclxuXHRcdHRoaXMuc2lkZSA9IEZyb250U2lkZTtcclxuXHRcdHRoaXMudmVydGV4Q29sb3JzID0gZmFsc2U7XHJcblxyXG5cdFx0dGhpcy5vcGFjaXR5ID0gMTtcclxuXHRcdHRoaXMudHJhbnNwYXJlbnQgPSBmYWxzZTtcclxuXHRcdHRoaXMuYWxwaGFIYXNoID0gZmFsc2U7XHJcblxyXG5cdFx0dGhpcy5ibGVuZFNyYyA9IFNyY0FscGhhRmFjdG9yO1xyXG5cdFx0dGhpcy5ibGVuZERzdCA9IE9uZU1pbnVzU3JjQWxwaGFGYWN0b3I7XHJcblx0XHR0aGlzLmJsZW5kRXF1YXRpb24gPSBBZGRFcXVhdGlvbjtcclxuXHRcdHRoaXMuYmxlbmRTcmNBbHBoYSA9IG51bGw7XHJcblx0XHR0aGlzLmJsZW5kRHN0QWxwaGEgPSBudWxsO1xyXG5cdFx0dGhpcy5ibGVuZEVxdWF0aW9uQWxwaGEgPSBudWxsO1xyXG5cdFx0dGhpcy5ibGVuZENvbG9yID0gbmV3IENvbG9yKCAwLCAwLCAwICk7XHJcblx0XHR0aGlzLmJsZW5kQWxwaGEgPSAwO1xyXG5cclxuXHRcdHRoaXMuZGVwdGhGdW5jID0gTGVzc0VxdWFsRGVwdGg7XHJcblx0XHR0aGlzLmRlcHRoVGVzdCA9IHRydWU7XHJcblx0XHR0aGlzLmRlcHRoV3JpdGUgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMuc3RlbmNpbFdyaXRlTWFzayA9IDB4ZmY7XHJcblx0XHR0aGlzLnN0ZW5jaWxGdW5jID0gQWx3YXlzU3RlbmNpbEZ1bmM7XHJcblx0XHR0aGlzLnN0ZW5jaWxSZWYgPSAwO1xyXG5cdFx0dGhpcy5zdGVuY2lsRnVuY01hc2sgPSAweGZmO1xyXG5cdFx0dGhpcy5zdGVuY2lsRmFpbCA9IEtlZXBTdGVuY2lsT3A7XHJcblx0XHR0aGlzLnN0ZW5jaWxaRmFpbCA9IEtlZXBTdGVuY2lsT3A7XHJcblx0XHR0aGlzLnN0ZW5jaWxaUGFzcyA9IEtlZXBTdGVuY2lsT3A7XHJcblx0XHR0aGlzLnN0ZW5jaWxXcml0ZSA9IGZhbHNlO1xyXG5cclxuXHRcdHRoaXMuY2xpcHBpbmdQbGFuZXMgPSBudWxsO1xyXG5cdFx0dGhpcy5jbGlwSW50ZXJzZWN0aW9uID0gZmFsc2U7XHJcblx0XHR0aGlzLmNsaXBTaGFkb3dzID0gZmFsc2U7XHJcblxyXG5cdFx0dGhpcy5zaGFkb3dTaWRlID0gbnVsbDtcclxuXHJcblx0XHR0aGlzLmNvbG9yV3JpdGUgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMucHJlY2lzaW9uID0gbnVsbDsgLy8gb3ZlcnJpZGUgdGhlIHJlbmRlcmVyJ3MgZGVmYXVsdCBwcmVjaXNpb24gZm9yIHRoaXMgbWF0ZXJpYWxcclxuXHJcblx0XHR0aGlzLnBvbHlnb25PZmZzZXQgPSBmYWxzZTtcclxuXHRcdHRoaXMucG9seWdvbk9mZnNldEZhY3RvciA9IDA7XHJcblx0XHR0aGlzLnBvbHlnb25PZmZzZXRVbml0cyA9IDA7XHJcblxyXG5cdFx0dGhpcy5kaXRoZXJpbmcgPSBmYWxzZTtcclxuXHJcblx0XHR0aGlzLmFscGhhVG9Db3ZlcmFnZSA9IGZhbHNlO1xyXG5cdFx0dGhpcy5wcmVtdWx0aXBsaWVkQWxwaGEgPSBmYWxzZTtcclxuXHRcdHRoaXMuZm9yY2VTaW5nbGVQYXNzID0gZmFsc2U7XHJcblxyXG5cdFx0dGhpcy52aXNpYmxlID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLnRvbmVNYXBwZWQgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMudXNlckRhdGEgPSB7fTtcclxuXHJcblx0XHR0aGlzLnZlcnNpb24gPSAwO1xyXG5cclxuXHRcdHRoaXMuX2FscGhhVGVzdCA9IDA7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0IGFscGhhVGVzdCgpIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5fYWxwaGFUZXN0O1xyXG5cclxuXHR9XHJcblxyXG5cdHNldCBhbHBoYVRlc3QoIHZhbHVlICkge1xyXG5cclxuXHRcdGlmICggdGhpcy5fYWxwaGFUZXN0ID4gMCAhPT0gdmFsdWUgPiAwICkge1xyXG5cclxuXHRcdFx0dGhpcy52ZXJzaW9uICsrO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLl9hbHBoYVRlc3QgPSB2YWx1ZTtcclxuXHJcblx0fVxyXG5cclxuXHRvbkJ1aWxkKCAvKiBzaGFkZXJvYmplY3QsIHJlbmRlcmVyICovICkge31cclxuXHJcblx0b25CZWZvcmVSZW5kZXIoIC8qIHJlbmRlcmVyLCBzY2VuZSwgY2FtZXJhLCBnZW9tZXRyeSwgb2JqZWN0LCBncm91cCAqLyApIHt9XHJcblxyXG5cdG9uQmVmb3JlQ29tcGlsZSggLyogc2hhZGVyb2JqZWN0LCByZW5kZXJlciAqLyApIHt9XHJcblxyXG5cdGN1c3RvbVByb2dyYW1DYWNoZUtleSgpIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5vbkJlZm9yZUNvbXBpbGUudG9TdHJpbmcoKTtcclxuXHJcblx0fVxyXG5cclxuXHRzZXRWYWx1ZXMoIHZhbHVlcyApIHtcclxuXHJcblx0XHRpZiAoIHZhbHVlcyA9PT0gdW5kZWZpbmVkICkgcmV0dXJuO1xyXG5cclxuXHRcdGZvciAoIGNvbnN0IGtleSBpbiB2YWx1ZXMgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBuZXdWYWx1ZSA9IHZhbHVlc1sga2V5IF07XHJcblxyXG5cdFx0XHRpZiAoIG5ld1ZhbHVlID09PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnNvbGUud2FybiggYFRIUkVFLk1hdGVyaWFsOiBwYXJhbWV0ZXIgJyR7IGtleSB9JyBoYXMgdmFsdWUgb2YgdW5kZWZpbmVkLmAgKTtcclxuXHRcdFx0XHRjb250aW51ZTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGNvbnN0IGN1cnJlbnRWYWx1ZSA9IHRoaXNbIGtleSBdO1xyXG5cclxuXHRcdFx0aWYgKCBjdXJyZW50VmFsdWUgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0Y29uc29sZS53YXJuKCBgVEhSRUUuTWF0ZXJpYWw6ICckeyBrZXkgfScgaXMgbm90IGEgcHJvcGVydHkgb2YgVEhSRUUuJHsgdGhpcy50eXBlIH0uYCApO1xyXG5cdFx0XHRcdGNvbnRpbnVlO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0aWYgKCBjdXJyZW50VmFsdWUgJiYgY3VycmVudFZhbHVlLmlzQ29sb3IgKSB7XHJcblxyXG5cdFx0XHRcdGN1cnJlbnRWYWx1ZS5zZXQoIG5ld1ZhbHVlICk7XHJcblxyXG5cdFx0XHR9IGVsc2UgaWYgKCAoIGN1cnJlbnRWYWx1ZSAmJiBjdXJyZW50VmFsdWUuaXNWZWN0b3IzICkgJiYgKCBuZXdWYWx1ZSAmJiBuZXdWYWx1ZS5pc1ZlY3RvcjMgKSApIHtcclxuXHJcblx0XHRcdFx0Y3VycmVudFZhbHVlLmNvcHkoIG5ld1ZhbHVlICk7XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHR0aGlzWyBrZXkgXSA9IG5ld1ZhbHVlO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHR0b0pTT04oIG1ldGEgKSB7XHJcblxyXG5cdFx0Y29uc3QgaXNSb290T2JqZWN0ID0gKCBtZXRhID09PSB1bmRlZmluZWQgfHwgdHlwZW9mIG1ldGEgPT09ICdzdHJpbmcnICk7XHJcblxyXG5cdFx0aWYgKCBpc1Jvb3RPYmplY3QgKSB7XHJcblxyXG5cdFx0XHRtZXRhID0ge1xyXG5cdFx0XHRcdHRleHR1cmVzOiB7fSxcclxuXHRcdFx0XHRpbWFnZXM6IHt9XHJcblx0XHRcdH07XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGNvbnN0IGRhdGEgPSB7XHJcblx0XHRcdG1ldGFkYXRhOiB7XHJcblx0XHRcdFx0dmVyc2lvbjogNC42LFxyXG5cdFx0XHRcdHR5cGU6ICdNYXRlcmlhbCcsXHJcblx0XHRcdFx0Z2VuZXJhdG9yOiAnTWF0ZXJpYWwudG9KU09OJ1xyXG5cdFx0XHR9XHJcblx0XHR9O1xyXG5cclxuXHRcdC8vIHN0YW5kYXJkIE1hdGVyaWFsIHNlcmlhbGl6YXRpb25cclxuXHRcdGRhdGEudXVpZCA9IHRoaXMudXVpZDtcclxuXHRcdGRhdGEudHlwZSA9IHRoaXMudHlwZTtcclxuXHJcblx0XHRpZiAoIHRoaXMubmFtZSAhPT0gJycgKSBkYXRhLm5hbWUgPSB0aGlzLm5hbWU7XHJcblxyXG5cdFx0aWYgKCB0aGlzLmNvbG9yICYmIHRoaXMuY29sb3IuaXNDb2xvciApIGRhdGEuY29sb3IgPSB0aGlzLmNvbG9yLmdldEhleCgpO1xyXG5cclxuXHRcdGlmICggdGhpcy5yb3VnaG5lc3MgIT09IHVuZGVmaW5lZCApIGRhdGEucm91Z2huZXNzID0gdGhpcy5yb3VnaG5lc3M7XHJcblx0XHRpZiAoIHRoaXMubWV0YWxuZXNzICE9PSB1bmRlZmluZWQgKSBkYXRhLm1ldGFsbmVzcyA9IHRoaXMubWV0YWxuZXNzO1xyXG5cclxuXHRcdGlmICggdGhpcy5zaGVlbiAhPT0gdW5kZWZpbmVkICkgZGF0YS5zaGVlbiA9IHRoaXMuc2hlZW47XHJcblx0XHRpZiAoIHRoaXMuc2hlZW5Db2xvciAmJiB0aGlzLnNoZWVuQ29sb3IuaXNDb2xvciApIGRhdGEuc2hlZW5Db2xvciA9IHRoaXMuc2hlZW5Db2xvci5nZXRIZXgoKTtcclxuXHRcdGlmICggdGhpcy5zaGVlblJvdWdobmVzcyAhPT0gdW5kZWZpbmVkICkgZGF0YS5zaGVlblJvdWdobmVzcyA9IHRoaXMuc2hlZW5Sb3VnaG5lc3M7XHJcblx0XHRpZiAoIHRoaXMuZW1pc3NpdmUgJiYgdGhpcy5lbWlzc2l2ZS5pc0NvbG9yICkgZGF0YS5lbWlzc2l2ZSA9IHRoaXMuZW1pc3NpdmUuZ2V0SGV4KCk7XHJcblx0XHRpZiAoIHRoaXMuZW1pc3NpdmVJbnRlbnNpdHkgJiYgdGhpcy5lbWlzc2l2ZUludGVuc2l0eSAhPT0gMSApIGRhdGEuZW1pc3NpdmVJbnRlbnNpdHkgPSB0aGlzLmVtaXNzaXZlSW50ZW5zaXR5O1xyXG5cclxuXHRcdGlmICggdGhpcy5zcGVjdWxhciAmJiB0aGlzLnNwZWN1bGFyLmlzQ29sb3IgKSBkYXRhLnNwZWN1bGFyID0gdGhpcy5zcGVjdWxhci5nZXRIZXgoKTtcclxuXHRcdGlmICggdGhpcy5zcGVjdWxhckludGVuc2l0eSAhPT0gdW5kZWZpbmVkICkgZGF0YS5zcGVjdWxhckludGVuc2l0eSA9IHRoaXMuc3BlY3VsYXJJbnRlbnNpdHk7XHJcblx0XHRpZiAoIHRoaXMuc3BlY3VsYXJDb2xvciAmJiB0aGlzLnNwZWN1bGFyQ29sb3IuaXNDb2xvciApIGRhdGEuc3BlY3VsYXJDb2xvciA9IHRoaXMuc3BlY3VsYXJDb2xvci5nZXRIZXgoKTtcclxuXHRcdGlmICggdGhpcy5zaGluaW5lc3MgIT09IHVuZGVmaW5lZCApIGRhdGEuc2hpbmluZXNzID0gdGhpcy5zaGluaW5lc3M7XHJcblx0XHRpZiAoIHRoaXMuY2xlYXJjb2F0ICE9PSB1bmRlZmluZWQgKSBkYXRhLmNsZWFyY29hdCA9IHRoaXMuY2xlYXJjb2F0O1xyXG5cdFx0aWYgKCB0aGlzLmNsZWFyY29hdFJvdWdobmVzcyAhPT0gdW5kZWZpbmVkICkgZGF0YS5jbGVhcmNvYXRSb3VnaG5lc3MgPSB0aGlzLmNsZWFyY29hdFJvdWdobmVzcztcclxuXHJcblx0XHRpZiAoIHRoaXMuY2xlYXJjb2F0TWFwICYmIHRoaXMuY2xlYXJjb2F0TWFwLmlzVGV4dHVyZSApIHtcclxuXHJcblx0XHRcdGRhdGEuY2xlYXJjb2F0TWFwID0gdGhpcy5jbGVhcmNvYXRNYXAudG9KU09OKCBtZXRhICkudXVpZDtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCB0aGlzLmNsZWFyY29hdFJvdWdobmVzc01hcCAmJiB0aGlzLmNsZWFyY29hdFJvdWdobmVzc01hcC5pc1RleHR1cmUgKSB7XHJcblxyXG5cdFx0XHRkYXRhLmNsZWFyY29hdFJvdWdobmVzc01hcCA9IHRoaXMuY2xlYXJjb2F0Um91Z2huZXNzTWFwLnRvSlNPTiggbWV0YSApLnV1aWQ7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggdGhpcy5jbGVhcmNvYXROb3JtYWxNYXAgJiYgdGhpcy5jbGVhcmNvYXROb3JtYWxNYXAuaXNUZXh0dXJlICkge1xyXG5cclxuXHRcdFx0ZGF0YS5jbGVhcmNvYXROb3JtYWxNYXAgPSB0aGlzLmNsZWFyY29hdE5vcm1hbE1hcC50b0pTT04oIG1ldGEgKS51dWlkO1xyXG5cdFx0XHRkYXRhLmNsZWFyY29hdE5vcm1hbFNjYWxlID0gdGhpcy5jbGVhcmNvYXROb3JtYWxTY2FsZS50b0FycmF5KCk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggdGhpcy5pcmlkZXNjZW5jZSAhPT0gdW5kZWZpbmVkICkgZGF0YS5pcmlkZXNjZW5jZSA9IHRoaXMuaXJpZGVzY2VuY2U7XHJcblx0XHRpZiAoIHRoaXMuaXJpZGVzY2VuY2VJT1IgIT09IHVuZGVmaW5lZCApIGRhdGEuaXJpZGVzY2VuY2VJT1IgPSB0aGlzLmlyaWRlc2NlbmNlSU9SO1xyXG5cdFx0aWYgKCB0aGlzLmlyaWRlc2NlbmNlVGhpY2tuZXNzUmFuZ2UgIT09IHVuZGVmaW5lZCApIGRhdGEuaXJpZGVzY2VuY2VUaGlja25lc3NSYW5nZSA9IHRoaXMuaXJpZGVzY2VuY2VUaGlja25lc3NSYW5nZTtcclxuXHJcblx0XHRpZiAoIHRoaXMuaXJpZGVzY2VuY2VNYXAgJiYgdGhpcy5pcmlkZXNjZW5jZU1hcC5pc1RleHR1cmUgKSB7XHJcblxyXG5cdFx0XHRkYXRhLmlyaWRlc2NlbmNlTWFwID0gdGhpcy5pcmlkZXNjZW5jZU1hcC50b0pTT04oIG1ldGEgKS51dWlkO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHRoaXMuaXJpZGVzY2VuY2VUaGlja25lc3NNYXAgJiYgdGhpcy5pcmlkZXNjZW5jZVRoaWNrbmVzc01hcC5pc1RleHR1cmUgKSB7XHJcblxyXG5cdFx0XHRkYXRhLmlyaWRlc2NlbmNlVGhpY2tuZXNzTWFwID0gdGhpcy5pcmlkZXNjZW5jZVRoaWNrbmVzc01hcC50b0pTT04oIG1ldGEgKS51dWlkO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHRoaXMuYW5pc290cm9weSAhPT0gdW5kZWZpbmVkICkgZGF0YS5hbmlzb3Ryb3B5ID0gdGhpcy5hbmlzb3Ryb3B5O1xyXG5cdFx0aWYgKCB0aGlzLmFuaXNvdHJvcHlSb3RhdGlvbiAhPT0gdW5kZWZpbmVkICkgZGF0YS5hbmlzb3Ryb3B5Um90YXRpb24gPSB0aGlzLmFuaXNvdHJvcHlSb3RhdGlvbjtcclxuXHJcblx0XHRpZiAoIHRoaXMuYW5pc290cm9weU1hcCAmJiB0aGlzLmFuaXNvdHJvcHlNYXAuaXNUZXh0dXJlICkge1xyXG5cclxuXHRcdFx0ZGF0YS5hbmlzb3Ryb3B5TWFwID0gdGhpcy5hbmlzb3Ryb3B5TWFwLnRvSlNPTiggbWV0YSApLnV1aWQ7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggdGhpcy5tYXAgJiYgdGhpcy5tYXAuaXNUZXh0dXJlICkgZGF0YS5tYXAgPSB0aGlzLm1hcC50b0pTT04oIG1ldGEgKS51dWlkO1xyXG5cdFx0aWYgKCB0aGlzLm1hdGNhcCAmJiB0aGlzLm1hdGNhcC5pc1RleHR1cmUgKSBkYXRhLm1hdGNhcCA9IHRoaXMubWF0Y2FwLnRvSlNPTiggbWV0YSApLnV1aWQ7XHJcblx0XHRpZiAoIHRoaXMuYWxwaGFNYXAgJiYgdGhpcy5hbHBoYU1hcC5pc1RleHR1cmUgKSBkYXRhLmFscGhhTWFwID0gdGhpcy5hbHBoYU1hcC50b0pTT04oIG1ldGEgKS51dWlkO1xyXG5cclxuXHRcdGlmICggdGhpcy5saWdodE1hcCAmJiB0aGlzLmxpZ2h0TWFwLmlzVGV4dHVyZSApIHtcclxuXHJcblx0XHRcdGRhdGEubGlnaHRNYXAgPSB0aGlzLmxpZ2h0TWFwLnRvSlNPTiggbWV0YSApLnV1aWQ7XHJcblx0XHRcdGRhdGEubGlnaHRNYXBJbnRlbnNpdHkgPSB0aGlzLmxpZ2h0TWFwSW50ZW5zaXR5O1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHRoaXMuYW9NYXAgJiYgdGhpcy5hb01hcC5pc1RleHR1cmUgKSB7XHJcblxyXG5cdFx0XHRkYXRhLmFvTWFwID0gdGhpcy5hb01hcC50b0pTT04oIG1ldGEgKS51dWlkO1xyXG5cdFx0XHRkYXRhLmFvTWFwSW50ZW5zaXR5ID0gdGhpcy5hb01hcEludGVuc2l0eTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCB0aGlzLmJ1bXBNYXAgJiYgdGhpcy5idW1wTWFwLmlzVGV4dHVyZSApIHtcclxuXHJcblx0XHRcdGRhdGEuYnVtcE1hcCA9IHRoaXMuYnVtcE1hcC50b0pTT04oIG1ldGEgKS51dWlkO1xyXG5cdFx0XHRkYXRhLmJ1bXBTY2FsZSA9IHRoaXMuYnVtcFNjYWxlO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHRoaXMubm9ybWFsTWFwICYmIHRoaXMubm9ybWFsTWFwLmlzVGV4dHVyZSApIHtcclxuXHJcblx0XHRcdGRhdGEubm9ybWFsTWFwID0gdGhpcy5ub3JtYWxNYXAudG9KU09OKCBtZXRhICkudXVpZDtcclxuXHRcdFx0ZGF0YS5ub3JtYWxNYXBUeXBlID0gdGhpcy5ub3JtYWxNYXBUeXBlO1xyXG5cdFx0XHRkYXRhLm5vcm1hbFNjYWxlID0gdGhpcy5ub3JtYWxTY2FsZS50b0FycmF5KCk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggdGhpcy5kaXNwbGFjZW1lbnRNYXAgJiYgdGhpcy5kaXNwbGFjZW1lbnRNYXAuaXNUZXh0dXJlICkge1xyXG5cclxuXHRcdFx0ZGF0YS5kaXNwbGFjZW1lbnRNYXAgPSB0aGlzLmRpc3BsYWNlbWVudE1hcC50b0pTT04oIG1ldGEgKS51dWlkO1xyXG5cdFx0XHRkYXRhLmRpc3BsYWNlbWVudFNjYWxlID0gdGhpcy5kaXNwbGFjZW1lbnRTY2FsZTtcclxuXHRcdFx0ZGF0YS5kaXNwbGFjZW1lbnRCaWFzID0gdGhpcy5kaXNwbGFjZW1lbnRCaWFzO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHRoaXMucm91Z2huZXNzTWFwICYmIHRoaXMucm91Z2huZXNzTWFwLmlzVGV4dHVyZSApIGRhdGEucm91Z2huZXNzTWFwID0gdGhpcy5yb3VnaG5lc3NNYXAudG9KU09OKCBtZXRhICkudXVpZDtcclxuXHRcdGlmICggdGhpcy5tZXRhbG5lc3NNYXAgJiYgdGhpcy5tZXRhbG5lc3NNYXAuaXNUZXh0dXJlICkgZGF0YS5tZXRhbG5lc3NNYXAgPSB0aGlzLm1ldGFsbmVzc01hcC50b0pTT04oIG1ldGEgKS51dWlkO1xyXG5cclxuXHRcdGlmICggdGhpcy5lbWlzc2l2ZU1hcCAmJiB0aGlzLmVtaXNzaXZlTWFwLmlzVGV4dHVyZSApIGRhdGEuZW1pc3NpdmVNYXAgPSB0aGlzLmVtaXNzaXZlTWFwLnRvSlNPTiggbWV0YSApLnV1aWQ7XHJcblx0XHRpZiAoIHRoaXMuc3BlY3VsYXJNYXAgJiYgdGhpcy5zcGVjdWxhck1hcC5pc1RleHR1cmUgKSBkYXRhLnNwZWN1bGFyTWFwID0gdGhpcy5zcGVjdWxhck1hcC50b0pTT04oIG1ldGEgKS51dWlkO1xyXG5cdFx0aWYgKCB0aGlzLnNwZWN1bGFySW50ZW5zaXR5TWFwICYmIHRoaXMuc3BlY3VsYXJJbnRlbnNpdHlNYXAuaXNUZXh0dXJlICkgZGF0YS5zcGVjdWxhckludGVuc2l0eU1hcCA9IHRoaXMuc3BlY3VsYXJJbnRlbnNpdHlNYXAudG9KU09OKCBtZXRhICkudXVpZDtcclxuXHRcdGlmICggdGhpcy5zcGVjdWxhckNvbG9yTWFwICYmIHRoaXMuc3BlY3VsYXJDb2xvck1hcC5pc1RleHR1cmUgKSBkYXRhLnNwZWN1bGFyQ29sb3JNYXAgPSB0aGlzLnNwZWN1bGFyQ29sb3JNYXAudG9KU09OKCBtZXRhICkudXVpZDtcclxuXHJcblx0XHRpZiAoIHRoaXMuZW52TWFwICYmIHRoaXMuZW52TWFwLmlzVGV4dHVyZSApIHtcclxuXHJcblx0XHRcdGRhdGEuZW52TWFwID0gdGhpcy5lbnZNYXAudG9KU09OKCBtZXRhICkudXVpZDtcclxuXHJcblx0XHRcdGlmICggdGhpcy5jb21iaW5lICE9PSB1bmRlZmluZWQgKSBkYXRhLmNvbWJpbmUgPSB0aGlzLmNvbWJpbmU7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggdGhpcy5lbnZNYXBJbnRlbnNpdHkgIT09IHVuZGVmaW5lZCApIGRhdGEuZW52TWFwSW50ZW5zaXR5ID0gdGhpcy5lbnZNYXBJbnRlbnNpdHk7XHJcblx0XHRpZiAoIHRoaXMucmVmbGVjdGl2aXR5ICE9PSB1bmRlZmluZWQgKSBkYXRhLnJlZmxlY3Rpdml0eSA9IHRoaXMucmVmbGVjdGl2aXR5O1xyXG5cdFx0aWYgKCB0aGlzLnJlZnJhY3Rpb25SYXRpbyAhPT0gdW5kZWZpbmVkICkgZGF0YS5yZWZyYWN0aW9uUmF0aW8gPSB0aGlzLnJlZnJhY3Rpb25SYXRpbztcclxuXHJcblx0XHRpZiAoIHRoaXMuZ3JhZGllbnRNYXAgJiYgdGhpcy5ncmFkaWVudE1hcC5pc1RleHR1cmUgKSB7XHJcblxyXG5cdFx0XHRkYXRhLmdyYWRpZW50TWFwID0gdGhpcy5ncmFkaWVudE1hcC50b0pTT04oIG1ldGEgKS51dWlkO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHRoaXMudHJhbnNtaXNzaW9uICE9PSB1bmRlZmluZWQgKSBkYXRhLnRyYW5zbWlzc2lvbiA9IHRoaXMudHJhbnNtaXNzaW9uO1xyXG5cdFx0aWYgKCB0aGlzLnRyYW5zbWlzc2lvbk1hcCAmJiB0aGlzLnRyYW5zbWlzc2lvbk1hcC5pc1RleHR1cmUgKSBkYXRhLnRyYW5zbWlzc2lvbk1hcCA9IHRoaXMudHJhbnNtaXNzaW9uTWFwLnRvSlNPTiggbWV0YSApLnV1aWQ7XHJcblx0XHRpZiAoIHRoaXMudGhpY2tuZXNzICE9PSB1bmRlZmluZWQgKSBkYXRhLnRoaWNrbmVzcyA9IHRoaXMudGhpY2tuZXNzO1xyXG5cdFx0aWYgKCB0aGlzLnRoaWNrbmVzc01hcCAmJiB0aGlzLnRoaWNrbmVzc01hcC5pc1RleHR1cmUgKSBkYXRhLnRoaWNrbmVzc01hcCA9IHRoaXMudGhpY2tuZXNzTWFwLnRvSlNPTiggbWV0YSApLnV1aWQ7XHJcblx0XHRpZiAoIHRoaXMuYXR0ZW51YXRpb25EaXN0YW5jZSAhPT0gdW5kZWZpbmVkICYmIHRoaXMuYXR0ZW51YXRpb25EaXN0YW5jZSAhPT0gSW5maW5pdHkgKSBkYXRhLmF0dGVudWF0aW9uRGlzdGFuY2UgPSB0aGlzLmF0dGVudWF0aW9uRGlzdGFuY2U7XHJcblx0XHRpZiAoIHRoaXMuYXR0ZW51YXRpb25Db2xvciAhPT0gdW5kZWZpbmVkICkgZGF0YS5hdHRlbnVhdGlvbkNvbG9yID0gdGhpcy5hdHRlbnVhdGlvbkNvbG9yLmdldEhleCgpO1xyXG5cclxuXHRcdGlmICggdGhpcy5zaXplICE9PSB1bmRlZmluZWQgKSBkYXRhLnNpemUgPSB0aGlzLnNpemU7XHJcblx0XHRpZiAoIHRoaXMuc2hhZG93U2lkZSAhPT0gbnVsbCApIGRhdGEuc2hhZG93U2lkZSA9IHRoaXMuc2hhZG93U2lkZTtcclxuXHRcdGlmICggdGhpcy5zaXplQXR0ZW51YXRpb24gIT09IHVuZGVmaW5lZCApIGRhdGEuc2l6ZUF0dGVudWF0aW9uID0gdGhpcy5zaXplQXR0ZW51YXRpb247XHJcblxyXG5cdFx0aWYgKCB0aGlzLmJsZW5kaW5nICE9PSBOb3JtYWxCbGVuZGluZyApIGRhdGEuYmxlbmRpbmcgPSB0aGlzLmJsZW5kaW5nO1xyXG5cdFx0aWYgKCB0aGlzLnNpZGUgIT09IEZyb250U2lkZSApIGRhdGEuc2lkZSA9IHRoaXMuc2lkZTtcclxuXHRcdGlmICggdGhpcy52ZXJ0ZXhDb2xvcnMgPT09IHRydWUgKSBkYXRhLnZlcnRleENvbG9ycyA9IHRydWU7XHJcblxyXG5cdFx0aWYgKCB0aGlzLm9wYWNpdHkgPCAxICkgZGF0YS5vcGFjaXR5ID0gdGhpcy5vcGFjaXR5O1xyXG5cdFx0aWYgKCB0aGlzLnRyYW5zcGFyZW50ID09PSB0cnVlICkgZGF0YS50cmFuc3BhcmVudCA9IHRydWU7XHJcblxyXG5cdFx0aWYgKCB0aGlzLmJsZW5kU3JjICE9PSBTcmNBbHBoYUZhY3RvciApIGRhdGEuYmxlbmRTcmMgPSB0aGlzLmJsZW5kU3JjO1xyXG5cdFx0aWYgKCB0aGlzLmJsZW5kRHN0ICE9PSBPbmVNaW51c1NyY0FscGhhRmFjdG9yICkgZGF0YS5ibGVuZERzdCA9IHRoaXMuYmxlbmREc3Q7XHJcblx0XHRpZiAoIHRoaXMuYmxlbmRFcXVhdGlvbiAhPT0gQWRkRXF1YXRpb24gKSBkYXRhLmJsZW5kRXF1YXRpb24gPSB0aGlzLmJsZW5kRXF1YXRpb247XHJcblx0XHRpZiAoIHRoaXMuYmxlbmRTcmNBbHBoYSAhPT0gbnVsbCApIGRhdGEuYmxlbmRTcmNBbHBoYSA9IHRoaXMuYmxlbmRTcmNBbHBoYTtcclxuXHRcdGlmICggdGhpcy5ibGVuZERzdEFscGhhICE9PSBudWxsICkgZGF0YS5ibGVuZERzdEFscGhhID0gdGhpcy5ibGVuZERzdEFscGhhO1xyXG5cdFx0aWYgKCB0aGlzLmJsZW5kRXF1YXRpb25BbHBoYSAhPT0gbnVsbCApIGRhdGEuYmxlbmRFcXVhdGlvbkFscGhhID0gdGhpcy5ibGVuZEVxdWF0aW9uQWxwaGE7XHJcblx0XHRpZiAoIHRoaXMuYmxlbmRDb2xvciAmJiB0aGlzLmJsZW5kQ29sb3IuaXNDb2xvciApIGRhdGEuYmxlbmRDb2xvciA9IHRoaXMuYmxlbmRDb2xvci5nZXRIZXgoKTtcclxuXHRcdGlmICggdGhpcy5ibGVuZEFscGhhICE9PSAwICkgZGF0YS5ibGVuZEFscGhhID0gdGhpcy5ibGVuZEFscGhhO1xyXG5cclxuXHRcdGlmICggdGhpcy5kZXB0aEZ1bmMgIT09IExlc3NFcXVhbERlcHRoICkgZGF0YS5kZXB0aEZ1bmMgPSB0aGlzLmRlcHRoRnVuYztcclxuXHRcdGlmICggdGhpcy5kZXB0aFRlc3QgPT09IGZhbHNlICkgZGF0YS5kZXB0aFRlc3QgPSB0aGlzLmRlcHRoVGVzdDtcclxuXHRcdGlmICggdGhpcy5kZXB0aFdyaXRlID09PSBmYWxzZSApIGRhdGEuZGVwdGhXcml0ZSA9IHRoaXMuZGVwdGhXcml0ZTtcclxuXHRcdGlmICggdGhpcy5jb2xvcldyaXRlID09PSBmYWxzZSApIGRhdGEuY29sb3JXcml0ZSA9IHRoaXMuY29sb3JXcml0ZTtcclxuXHJcblx0XHRpZiAoIHRoaXMuc3RlbmNpbFdyaXRlTWFzayAhPT0gMHhmZiApIGRhdGEuc3RlbmNpbFdyaXRlTWFzayA9IHRoaXMuc3RlbmNpbFdyaXRlTWFzaztcclxuXHRcdGlmICggdGhpcy5zdGVuY2lsRnVuYyAhPT0gQWx3YXlzU3RlbmNpbEZ1bmMgKSBkYXRhLnN0ZW5jaWxGdW5jID0gdGhpcy5zdGVuY2lsRnVuYztcclxuXHRcdGlmICggdGhpcy5zdGVuY2lsUmVmICE9PSAwICkgZGF0YS5zdGVuY2lsUmVmID0gdGhpcy5zdGVuY2lsUmVmO1xyXG5cdFx0aWYgKCB0aGlzLnN0ZW5jaWxGdW5jTWFzayAhPT0gMHhmZiApIGRhdGEuc3RlbmNpbEZ1bmNNYXNrID0gdGhpcy5zdGVuY2lsRnVuY01hc2s7XHJcblx0XHRpZiAoIHRoaXMuc3RlbmNpbEZhaWwgIT09IEtlZXBTdGVuY2lsT3AgKSBkYXRhLnN0ZW5jaWxGYWlsID0gdGhpcy5zdGVuY2lsRmFpbDtcclxuXHRcdGlmICggdGhpcy5zdGVuY2lsWkZhaWwgIT09IEtlZXBTdGVuY2lsT3AgKSBkYXRhLnN0ZW5jaWxaRmFpbCA9IHRoaXMuc3RlbmNpbFpGYWlsO1xyXG5cdFx0aWYgKCB0aGlzLnN0ZW5jaWxaUGFzcyAhPT0gS2VlcFN0ZW5jaWxPcCApIGRhdGEuc3RlbmNpbFpQYXNzID0gdGhpcy5zdGVuY2lsWlBhc3M7XHJcblx0XHRpZiAoIHRoaXMuc3RlbmNpbFdyaXRlID09PSB0cnVlICkgZGF0YS5zdGVuY2lsV3JpdGUgPSB0aGlzLnN0ZW5jaWxXcml0ZTtcclxuXHJcblx0XHQvLyByb3RhdGlvbiAoU3ByaXRlTWF0ZXJpYWwpXHJcblx0XHRpZiAoIHRoaXMucm90YXRpb24gIT09IHVuZGVmaW5lZCAmJiB0aGlzLnJvdGF0aW9uICE9PSAwICkgZGF0YS5yb3RhdGlvbiA9IHRoaXMucm90YXRpb247XHJcblxyXG5cdFx0aWYgKCB0aGlzLnBvbHlnb25PZmZzZXQgPT09IHRydWUgKSBkYXRhLnBvbHlnb25PZmZzZXQgPSB0cnVlO1xyXG5cdFx0aWYgKCB0aGlzLnBvbHlnb25PZmZzZXRGYWN0b3IgIT09IDAgKSBkYXRhLnBvbHlnb25PZmZzZXRGYWN0b3IgPSB0aGlzLnBvbHlnb25PZmZzZXRGYWN0b3I7XHJcblx0XHRpZiAoIHRoaXMucG9seWdvbk9mZnNldFVuaXRzICE9PSAwICkgZGF0YS5wb2x5Z29uT2Zmc2V0VW5pdHMgPSB0aGlzLnBvbHlnb25PZmZzZXRVbml0cztcclxuXHJcblx0XHRpZiAoIHRoaXMubGluZXdpZHRoICE9PSB1bmRlZmluZWQgJiYgdGhpcy5saW5ld2lkdGggIT09IDEgKSBkYXRhLmxpbmV3aWR0aCA9IHRoaXMubGluZXdpZHRoO1xyXG5cdFx0aWYgKCB0aGlzLmRhc2hTaXplICE9PSB1bmRlZmluZWQgKSBkYXRhLmRhc2hTaXplID0gdGhpcy5kYXNoU2l6ZTtcclxuXHRcdGlmICggdGhpcy5nYXBTaXplICE9PSB1bmRlZmluZWQgKSBkYXRhLmdhcFNpemUgPSB0aGlzLmdhcFNpemU7XHJcblx0XHRpZiAoIHRoaXMuc2NhbGUgIT09IHVuZGVmaW5lZCApIGRhdGEuc2NhbGUgPSB0aGlzLnNjYWxlO1xyXG5cclxuXHRcdGlmICggdGhpcy5kaXRoZXJpbmcgPT09IHRydWUgKSBkYXRhLmRpdGhlcmluZyA9IHRydWU7XHJcblxyXG5cdFx0aWYgKCB0aGlzLmFscGhhVGVzdCA+IDAgKSBkYXRhLmFscGhhVGVzdCA9IHRoaXMuYWxwaGFUZXN0O1xyXG5cdFx0aWYgKCB0aGlzLmFscGhhSGFzaCA9PT0gdHJ1ZSApIGRhdGEuYWxwaGFIYXNoID0gdHJ1ZTtcclxuXHRcdGlmICggdGhpcy5hbHBoYVRvQ292ZXJhZ2UgPT09IHRydWUgKSBkYXRhLmFscGhhVG9Db3ZlcmFnZSA9IHRydWU7XHJcblx0XHRpZiAoIHRoaXMucHJlbXVsdGlwbGllZEFscGhhID09PSB0cnVlICkgZGF0YS5wcmVtdWx0aXBsaWVkQWxwaGEgPSB0cnVlO1xyXG5cdFx0aWYgKCB0aGlzLmZvcmNlU2luZ2xlUGFzcyA9PT0gdHJ1ZSApIGRhdGEuZm9yY2VTaW5nbGVQYXNzID0gdHJ1ZTtcclxuXHJcblx0XHRpZiAoIHRoaXMud2lyZWZyYW1lID09PSB0cnVlICkgZGF0YS53aXJlZnJhbWUgPSB0cnVlO1xyXG5cdFx0aWYgKCB0aGlzLndpcmVmcmFtZUxpbmV3aWR0aCA+IDEgKSBkYXRhLndpcmVmcmFtZUxpbmV3aWR0aCA9IHRoaXMud2lyZWZyYW1lTGluZXdpZHRoO1xyXG5cdFx0aWYgKCB0aGlzLndpcmVmcmFtZUxpbmVjYXAgIT09ICdyb3VuZCcgKSBkYXRhLndpcmVmcmFtZUxpbmVjYXAgPSB0aGlzLndpcmVmcmFtZUxpbmVjYXA7XHJcblx0XHRpZiAoIHRoaXMud2lyZWZyYW1lTGluZWpvaW4gIT09ICdyb3VuZCcgKSBkYXRhLndpcmVmcmFtZUxpbmVqb2luID0gdGhpcy53aXJlZnJhbWVMaW5lam9pbjtcclxuXHJcblx0XHRpZiAoIHRoaXMuZmxhdFNoYWRpbmcgPT09IHRydWUgKSBkYXRhLmZsYXRTaGFkaW5nID0gdHJ1ZTtcclxuXHJcblx0XHRpZiAoIHRoaXMudmlzaWJsZSA9PT0gZmFsc2UgKSBkYXRhLnZpc2libGUgPSBmYWxzZTtcclxuXHJcblx0XHRpZiAoIHRoaXMudG9uZU1hcHBlZCA9PT0gZmFsc2UgKSBkYXRhLnRvbmVNYXBwZWQgPSBmYWxzZTtcclxuXHJcblx0XHRpZiAoIHRoaXMuZm9nID09PSBmYWxzZSApIGRhdGEuZm9nID0gZmFsc2U7XHJcblxyXG5cdFx0aWYgKCBPYmplY3Qua2V5cyggdGhpcy51c2VyRGF0YSApLmxlbmd0aCA+IDAgKSBkYXRhLnVzZXJEYXRhID0gdGhpcy51c2VyRGF0YTtcclxuXHJcblx0XHQvLyBUT0RPOiBDb3BpZWQgZnJvbSBPYmplY3QzRC50b0pTT05cclxuXHJcblx0XHRmdW5jdGlvbiBleHRyYWN0RnJvbUNhY2hlKCBjYWNoZSApIHtcclxuXHJcblx0XHRcdGNvbnN0IHZhbHVlcyA9IFtdO1xyXG5cclxuXHRcdFx0Zm9yICggY29uc3Qga2V5IGluIGNhY2hlICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBkYXRhID0gY2FjaGVbIGtleSBdO1xyXG5cdFx0XHRcdGRlbGV0ZSBkYXRhLm1ldGFkYXRhO1xyXG5cdFx0XHRcdHZhbHVlcy5wdXNoKCBkYXRhICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRyZXR1cm4gdmFsdWVzO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIGlzUm9vdE9iamVjdCApIHtcclxuXHJcblx0XHRcdGNvbnN0IHRleHR1cmVzID0gZXh0cmFjdEZyb21DYWNoZSggbWV0YS50ZXh0dXJlcyApO1xyXG5cdFx0XHRjb25zdCBpbWFnZXMgPSBleHRyYWN0RnJvbUNhY2hlKCBtZXRhLmltYWdlcyApO1xyXG5cclxuXHRcdFx0aWYgKCB0ZXh0dXJlcy5sZW5ndGggPiAwICkgZGF0YS50ZXh0dXJlcyA9IHRleHR1cmVzO1xyXG5cdFx0XHRpZiAoIGltYWdlcy5sZW5ndGggPiAwICkgZGF0YS5pbWFnZXMgPSBpbWFnZXM7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiBkYXRhO1xyXG5cclxuXHR9XHJcblxyXG5cdGNsb25lKCkge1xyXG5cclxuXHRcdHJldHVybiBuZXcgdGhpcy5jb25zdHJ1Y3RvcigpLmNvcHkoIHRoaXMgKTtcclxuXHJcblx0fVxyXG5cclxuXHRjb3B5KCBzb3VyY2UgKSB7XHJcblxyXG5cdFx0dGhpcy5uYW1lID0gc291cmNlLm5hbWU7XHJcblxyXG5cdFx0dGhpcy5ibGVuZGluZyA9IHNvdXJjZS5ibGVuZGluZztcclxuXHRcdHRoaXMuc2lkZSA9IHNvdXJjZS5zaWRlO1xyXG5cdFx0dGhpcy52ZXJ0ZXhDb2xvcnMgPSBzb3VyY2UudmVydGV4Q29sb3JzO1xyXG5cclxuXHRcdHRoaXMub3BhY2l0eSA9IHNvdXJjZS5vcGFjaXR5O1xyXG5cdFx0dGhpcy50cmFuc3BhcmVudCA9IHNvdXJjZS50cmFuc3BhcmVudDtcclxuXHJcblx0XHR0aGlzLmJsZW5kU3JjID0gc291cmNlLmJsZW5kU3JjO1xyXG5cdFx0dGhpcy5ibGVuZERzdCA9IHNvdXJjZS5ibGVuZERzdDtcclxuXHRcdHRoaXMuYmxlbmRFcXVhdGlvbiA9IHNvdXJjZS5ibGVuZEVxdWF0aW9uO1xyXG5cdFx0dGhpcy5ibGVuZFNyY0FscGhhID0gc291cmNlLmJsZW5kU3JjQWxwaGE7XHJcblx0XHR0aGlzLmJsZW5kRHN0QWxwaGEgPSBzb3VyY2UuYmxlbmREc3RBbHBoYTtcclxuXHRcdHRoaXMuYmxlbmRFcXVhdGlvbkFscGhhID0gc291cmNlLmJsZW5kRXF1YXRpb25BbHBoYTtcclxuXHRcdHRoaXMuYmxlbmRDb2xvci5jb3B5KCBzb3VyY2UuYmxlbmRDb2xvciApO1xyXG5cdFx0dGhpcy5ibGVuZEFscGhhID0gc291cmNlLmJsZW5kQWxwaGE7XHJcblxyXG5cdFx0dGhpcy5kZXB0aEZ1bmMgPSBzb3VyY2UuZGVwdGhGdW5jO1xyXG5cdFx0dGhpcy5kZXB0aFRlc3QgPSBzb3VyY2UuZGVwdGhUZXN0O1xyXG5cdFx0dGhpcy5kZXB0aFdyaXRlID0gc291cmNlLmRlcHRoV3JpdGU7XHJcblxyXG5cdFx0dGhpcy5zdGVuY2lsV3JpdGVNYXNrID0gc291cmNlLnN0ZW5jaWxXcml0ZU1hc2s7XHJcblx0XHR0aGlzLnN0ZW5jaWxGdW5jID0gc291cmNlLnN0ZW5jaWxGdW5jO1xyXG5cdFx0dGhpcy5zdGVuY2lsUmVmID0gc291cmNlLnN0ZW5jaWxSZWY7XHJcblx0XHR0aGlzLnN0ZW5jaWxGdW5jTWFzayA9IHNvdXJjZS5zdGVuY2lsRnVuY01hc2s7XHJcblx0XHR0aGlzLnN0ZW5jaWxGYWlsID0gc291cmNlLnN0ZW5jaWxGYWlsO1xyXG5cdFx0dGhpcy5zdGVuY2lsWkZhaWwgPSBzb3VyY2Uuc3RlbmNpbFpGYWlsO1xyXG5cdFx0dGhpcy5zdGVuY2lsWlBhc3MgPSBzb3VyY2Uuc3RlbmNpbFpQYXNzO1xyXG5cdFx0dGhpcy5zdGVuY2lsV3JpdGUgPSBzb3VyY2Uuc3RlbmNpbFdyaXRlO1xyXG5cclxuXHRcdGNvbnN0IHNyY1BsYW5lcyA9IHNvdXJjZS5jbGlwcGluZ1BsYW5lcztcclxuXHRcdGxldCBkc3RQbGFuZXMgPSBudWxsO1xyXG5cclxuXHRcdGlmICggc3JjUGxhbmVzICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0Y29uc3QgbiA9IHNyY1BsYW5lcy5sZW5ndGg7XHJcblx0XHRcdGRzdFBsYW5lcyA9IG5ldyBBcnJheSggbiApO1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpICE9PSBuOyArKyBpICkge1xyXG5cclxuXHRcdFx0XHRkc3RQbGFuZXNbIGkgXSA9IHNyY1BsYW5lc1sgaSBdLmNsb25lKCk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMuY2xpcHBpbmdQbGFuZXMgPSBkc3RQbGFuZXM7XHJcblx0XHR0aGlzLmNsaXBJbnRlcnNlY3Rpb24gPSBzb3VyY2UuY2xpcEludGVyc2VjdGlvbjtcclxuXHRcdHRoaXMuY2xpcFNoYWRvd3MgPSBzb3VyY2UuY2xpcFNoYWRvd3M7XHJcblxyXG5cdFx0dGhpcy5zaGFkb3dTaWRlID0gc291cmNlLnNoYWRvd1NpZGU7XHJcblxyXG5cdFx0dGhpcy5jb2xvcldyaXRlID0gc291cmNlLmNvbG9yV3JpdGU7XHJcblxyXG5cdFx0dGhpcy5wcmVjaXNpb24gPSBzb3VyY2UucHJlY2lzaW9uO1xyXG5cclxuXHRcdHRoaXMucG9seWdvbk9mZnNldCA9IHNvdXJjZS5wb2x5Z29uT2Zmc2V0O1xyXG5cdFx0dGhpcy5wb2x5Z29uT2Zmc2V0RmFjdG9yID0gc291cmNlLnBvbHlnb25PZmZzZXRGYWN0b3I7XHJcblx0XHR0aGlzLnBvbHlnb25PZmZzZXRVbml0cyA9IHNvdXJjZS5wb2x5Z29uT2Zmc2V0VW5pdHM7XHJcblxyXG5cdFx0dGhpcy5kaXRoZXJpbmcgPSBzb3VyY2UuZGl0aGVyaW5nO1xyXG5cclxuXHRcdHRoaXMuYWxwaGFUZXN0ID0gc291cmNlLmFscGhhVGVzdDtcclxuXHRcdHRoaXMuYWxwaGFIYXNoID0gc291cmNlLmFscGhhSGFzaDtcclxuXHRcdHRoaXMuYWxwaGFUb0NvdmVyYWdlID0gc291cmNlLmFscGhhVG9Db3ZlcmFnZTtcclxuXHRcdHRoaXMucHJlbXVsdGlwbGllZEFscGhhID0gc291cmNlLnByZW11bHRpcGxpZWRBbHBoYTtcclxuXHRcdHRoaXMuZm9yY2VTaW5nbGVQYXNzID0gc291cmNlLmZvcmNlU2luZ2xlUGFzcztcclxuXHJcblx0XHR0aGlzLnZpc2libGUgPSBzb3VyY2UudmlzaWJsZTtcclxuXHJcblx0XHR0aGlzLnRvbmVNYXBwZWQgPSBzb3VyY2UudG9uZU1hcHBlZDtcclxuXHJcblx0XHR0aGlzLnVzZXJEYXRhID0gSlNPTi5wYXJzZSggSlNPTi5zdHJpbmdpZnkoIHNvdXJjZS51c2VyRGF0YSApICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0ZGlzcG9zZSgpIHtcclxuXHJcblx0XHR0aGlzLmRpc3BhdGNoRXZlbnQoIHsgdHlwZTogJ2Rpc3Bvc2UnIH0gKTtcclxuXHJcblx0fVxyXG5cclxuXHRzZXQgbmVlZHNVcGRhdGUoIHZhbHVlICkge1xyXG5cclxuXHRcdGlmICggdmFsdWUgPT09IHRydWUgKSB0aGlzLnZlcnNpb24gKys7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IE1hdGVyaWFsIH07XHJcbiIsImltcG9ydCB7IE1hdGVyaWFsIH0gZnJvbSAnLi9NYXRlcmlhbC5qcyc7XHJcbmltcG9ydCB7IE11bHRpcGx5T3BlcmF0aW9uIH0gZnJvbSAnLi4vY29uc3RhbnRzLmpzJztcclxuaW1wb3J0IHsgQ29sb3IgfSBmcm9tICcuLi9tYXRoL0NvbG9yLmpzJztcclxuXHJcbmNsYXNzIE1lc2hCYXNpY01hdGVyaWFsIGV4dGVuZHMgTWF0ZXJpYWwge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggcGFyYW1ldGVycyApIHtcclxuXHJcblx0XHRzdXBlcigpO1xyXG5cclxuXHRcdHRoaXMuaXNNZXNoQmFzaWNNYXRlcmlhbCA9IHRydWU7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ01lc2hCYXNpY01hdGVyaWFsJztcclxuXHJcblx0XHR0aGlzLmNvbG9yID0gbmV3IENvbG9yKCAweGZmZmZmZiApOyAvLyBlbWlzc2l2ZVxyXG5cclxuXHRcdHRoaXMubWFwID0gbnVsbDtcclxuXHJcblx0XHR0aGlzLmxpZ2h0TWFwID0gbnVsbDtcclxuXHRcdHRoaXMubGlnaHRNYXBJbnRlbnNpdHkgPSAxLjA7XHJcblxyXG5cdFx0dGhpcy5hb01hcCA9IG51bGw7XHJcblx0XHR0aGlzLmFvTWFwSW50ZW5zaXR5ID0gMS4wO1xyXG5cclxuXHRcdHRoaXMuc3BlY3VsYXJNYXAgPSBudWxsO1xyXG5cclxuXHRcdHRoaXMuYWxwaGFNYXAgPSBudWxsO1xyXG5cclxuXHRcdHRoaXMuZW52TWFwID0gbnVsbDtcclxuXHRcdHRoaXMuY29tYmluZSA9IE11bHRpcGx5T3BlcmF0aW9uO1xyXG5cdFx0dGhpcy5yZWZsZWN0aXZpdHkgPSAxO1xyXG5cdFx0dGhpcy5yZWZyYWN0aW9uUmF0aW8gPSAwLjk4O1xyXG5cclxuXHRcdHRoaXMud2lyZWZyYW1lID0gZmFsc2U7XHJcblx0XHR0aGlzLndpcmVmcmFtZUxpbmV3aWR0aCA9IDE7XHJcblx0XHR0aGlzLndpcmVmcmFtZUxpbmVjYXAgPSAncm91bmQnO1xyXG5cdFx0dGhpcy53aXJlZnJhbWVMaW5lam9pbiA9ICdyb3VuZCc7XHJcblxyXG5cdFx0dGhpcy5mb2cgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMuc2V0VmFsdWVzKCBwYXJhbWV0ZXJzICk7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xyXG5cclxuXHRcdHRoaXMuY29sb3IuY29weSggc291cmNlLmNvbG9yICk7XHJcblxyXG5cdFx0dGhpcy5tYXAgPSBzb3VyY2UubWFwO1xyXG5cclxuXHRcdHRoaXMubGlnaHRNYXAgPSBzb3VyY2UubGlnaHRNYXA7XHJcblx0XHR0aGlzLmxpZ2h0TWFwSW50ZW5zaXR5ID0gc291cmNlLmxpZ2h0TWFwSW50ZW5zaXR5O1xyXG5cclxuXHRcdHRoaXMuYW9NYXAgPSBzb3VyY2UuYW9NYXA7XHJcblx0XHR0aGlzLmFvTWFwSW50ZW5zaXR5ID0gc291cmNlLmFvTWFwSW50ZW5zaXR5O1xyXG5cclxuXHRcdHRoaXMuc3BlY3VsYXJNYXAgPSBzb3VyY2Uuc3BlY3VsYXJNYXA7XHJcblxyXG5cdFx0dGhpcy5hbHBoYU1hcCA9IHNvdXJjZS5hbHBoYU1hcDtcclxuXHJcblx0XHR0aGlzLmVudk1hcCA9IHNvdXJjZS5lbnZNYXA7XHJcblx0XHR0aGlzLmNvbWJpbmUgPSBzb3VyY2UuY29tYmluZTtcclxuXHRcdHRoaXMucmVmbGVjdGl2aXR5ID0gc291cmNlLnJlZmxlY3Rpdml0eTtcclxuXHRcdHRoaXMucmVmcmFjdGlvblJhdGlvID0gc291cmNlLnJlZnJhY3Rpb25SYXRpbztcclxuXHJcblx0XHR0aGlzLndpcmVmcmFtZSA9IHNvdXJjZS53aXJlZnJhbWU7XHJcblx0XHR0aGlzLndpcmVmcmFtZUxpbmV3aWR0aCA9IHNvdXJjZS53aXJlZnJhbWVMaW5ld2lkdGg7XHJcblx0XHR0aGlzLndpcmVmcmFtZUxpbmVjYXAgPSBzb3VyY2Uud2lyZWZyYW1lTGluZWNhcDtcclxuXHRcdHRoaXMud2lyZWZyYW1lTGluZWpvaW4gPSBzb3VyY2Uud2lyZWZyYW1lTGluZWpvaW47XHJcblxyXG5cdFx0dGhpcy5mb2cgPSBzb3VyY2UuZm9nO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBNZXNoQmFzaWNNYXRlcmlhbCB9O1xyXG4iLCJpbXBvcnQgeyBjbGFtcCB9IGZyb20gJy4uL21hdGgvTWF0aFV0aWxzLmpzJztcclxuXHJcbi8vIEZhc3QgSGFsZiBGbG9hdCBDb252ZXJzaW9ucywgaHR0cDovL3d3dy5mb3gtdG9vbGtpdC5vcmcvZnRwL2Zhc3RoYWxmZmxvYXRjb252ZXJzaW9uLnBkZlxyXG5cclxuY29uc3QgX3RhYmxlcyA9IC8qQF9fUFVSRV9fKi8gX2dlbmVyYXRlVGFibGVzKCk7XHJcblxyXG5mdW5jdGlvbiBfZ2VuZXJhdGVUYWJsZXMoKSB7XHJcblxyXG5cdC8vIGZsb2F0MzIgdG8gZmxvYXQxNiBoZWxwZXJzXHJcblxyXG5cdGNvbnN0IGJ1ZmZlciA9IG5ldyBBcnJheUJ1ZmZlciggNCApO1xyXG5cdGNvbnN0IGZsb2F0VmlldyA9IG5ldyBGbG9hdDMyQXJyYXkoIGJ1ZmZlciApO1xyXG5cdGNvbnN0IHVpbnQzMlZpZXcgPSBuZXcgVWludDMyQXJyYXkoIGJ1ZmZlciApO1xyXG5cclxuXHRjb25zdCBiYXNlVGFibGUgPSBuZXcgVWludDMyQXJyYXkoIDUxMiApO1xyXG5cdGNvbnN0IHNoaWZ0VGFibGUgPSBuZXcgVWludDMyQXJyYXkoIDUxMiApO1xyXG5cclxuXHRmb3IgKCBsZXQgaSA9IDA7IGkgPCAyNTY7ICsrIGkgKSB7XHJcblxyXG5cdFx0Y29uc3QgZSA9IGkgLSAxMjc7XHJcblxyXG5cdFx0Ly8gdmVyeSBzbWFsbCBudW1iZXIgKDAsIC0wKVxyXG5cclxuXHRcdGlmICggZSA8IC0gMjcgKSB7XHJcblxyXG5cdFx0XHRiYXNlVGFibGVbIGkgXSA9IDB4MDAwMDtcclxuXHRcdFx0YmFzZVRhYmxlWyBpIHwgMHgxMDAgXSA9IDB4ODAwMDtcclxuXHRcdFx0c2hpZnRUYWJsZVsgaSBdID0gMjQ7XHJcblx0XHRcdHNoaWZ0VGFibGVbIGkgfCAweDEwMCBdID0gMjQ7XHJcblxyXG5cdFx0XHQvLyBzbWFsbCBudW1iZXIgKGRlbm9ybSlcclxuXHJcblx0XHR9IGVsc2UgaWYgKCBlIDwgLSAxNCApIHtcclxuXHJcblx0XHRcdGJhc2VUYWJsZVsgaSBdID0gMHgwNDAwID4+ICggLSBlIC0gMTQgKTtcclxuXHRcdFx0YmFzZVRhYmxlWyBpIHwgMHgxMDAgXSA9ICggMHgwNDAwID4+ICggLSBlIC0gMTQgKSApIHwgMHg4MDAwO1xyXG5cdFx0XHRzaGlmdFRhYmxlWyBpIF0gPSAtIGUgLSAxO1xyXG5cdFx0XHRzaGlmdFRhYmxlWyBpIHwgMHgxMDAgXSA9IC0gZSAtIDE7XHJcblxyXG5cdFx0XHQvLyBub3JtYWwgbnVtYmVyXHJcblxyXG5cdFx0fSBlbHNlIGlmICggZSA8PSAxNSApIHtcclxuXHJcblx0XHRcdGJhc2VUYWJsZVsgaSBdID0gKCBlICsgMTUgKSA8PCAxMDtcclxuXHRcdFx0YmFzZVRhYmxlWyBpIHwgMHgxMDAgXSA9ICggKCBlICsgMTUgKSA8PCAxMCApIHwgMHg4MDAwO1xyXG5cdFx0XHRzaGlmdFRhYmxlWyBpIF0gPSAxMztcclxuXHRcdFx0c2hpZnRUYWJsZVsgaSB8IDB4MTAwIF0gPSAxMztcclxuXHJcblx0XHRcdC8vIGxhcmdlIG51bWJlciAoSW5maW5pdHksIC1JbmZpbml0eSlcclxuXHJcblx0XHR9IGVsc2UgaWYgKCBlIDwgMTI4ICkge1xyXG5cclxuXHRcdFx0YmFzZVRhYmxlWyBpIF0gPSAweDdjMDA7XHJcblx0XHRcdGJhc2VUYWJsZVsgaSB8IDB4MTAwIF0gPSAweGZjMDA7XHJcblx0XHRcdHNoaWZ0VGFibGVbIGkgXSA9IDI0O1xyXG5cdFx0XHRzaGlmdFRhYmxlWyBpIHwgMHgxMDAgXSA9IDI0O1xyXG5cclxuXHRcdFx0Ly8gc3RheSAoTmFOLCBJbmZpbml0eSwgLUluZmluaXR5KVxyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRiYXNlVGFibGVbIGkgXSA9IDB4N2MwMDtcclxuXHRcdFx0YmFzZVRhYmxlWyBpIHwgMHgxMDAgXSA9IDB4ZmMwMDtcclxuXHRcdFx0c2hpZnRUYWJsZVsgaSBdID0gMTM7XHJcblx0XHRcdHNoaWZ0VGFibGVbIGkgfCAweDEwMCBdID0gMTM7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdC8vIGZsb2F0MTYgdG8gZmxvYXQzMiBoZWxwZXJzXHJcblxyXG5cdGNvbnN0IG1hbnRpc3NhVGFibGUgPSBuZXcgVWludDMyQXJyYXkoIDIwNDggKTtcclxuXHRjb25zdCBleHBvbmVudFRhYmxlID0gbmV3IFVpbnQzMkFycmF5KCA2NCApO1xyXG5cdGNvbnN0IG9mZnNldFRhYmxlID0gbmV3IFVpbnQzMkFycmF5KCA2NCApO1xyXG5cclxuXHRmb3IgKCBsZXQgaSA9IDE7IGkgPCAxMDI0OyArKyBpICkge1xyXG5cclxuXHRcdGxldCBtID0gaSA8PCAxMzsgLy8gemVybyBwYWQgbWFudGlzc2EgYml0c1xyXG5cdFx0bGV0IGUgPSAwOyAvLyB6ZXJvIGV4cG9uZW50XHJcblxyXG5cdFx0Ly8gbm9ybWFsaXplZFxyXG5cdFx0d2hpbGUgKCAoIG0gJiAweDAwODAwMDAwICkgPT09IDAgKSB7XHJcblxyXG5cdFx0XHRtIDw8PSAxO1xyXG5cdFx0XHRlIC09IDB4MDA4MDAwMDA7IC8vIGRlY3JlbWVudCBleHBvbmVudFxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRtICY9IH4gMHgwMDgwMDAwMDsgLy8gY2xlYXIgbGVhZGluZyAxIGJpdFxyXG5cdFx0ZSArPSAweDM4ODAwMDAwOyAvLyBhZGp1c3QgYmlhc1xyXG5cclxuXHRcdG1hbnRpc3NhVGFibGVbIGkgXSA9IG0gfCBlO1xyXG5cclxuXHR9XHJcblxyXG5cdGZvciAoIGxldCBpID0gMTAyNDsgaSA8IDIwNDg7ICsrIGkgKSB7XHJcblxyXG5cdFx0bWFudGlzc2FUYWJsZVsgaSBdID0gMHgzODAwMDAwMCArICggKCBpIC0gMTAyNCApIDw8IDEzICk7XHJcblxyXG5cdH1cclxuXHJcblx0Zm9yICggbGV0IGkgPSAxOyBpIDwgMzE7ICsrIGkgKSB7XHJcblxyXG5cdFx0ZXhwb25lbnRUYWJsZVsgaSBdID0gaSA8PCAyMztcclxuXHJcblx0fVxyXG5cclxuXHRleHBvbmVudFRhYmxlWyAzMSBdID0gMHg0NzgwMDAwMDtcclxuXHRleHBvbmVudFRhYmxlWyAzMiBdID0gMHg4MDAwMDAwMDtcclxuXHJcblx0Zm9yICggbGV0IGkgPSAzMzsgaSA8IDYzOyArKyBpICkge1xyXG5cclxuXHRcdGV4cG9uZW50VGFibGVbIGkgXSA9IDB4ODAwMDAwMDAgKyAoICggaSAtIDMyICkgPDwgMjMgKTtcclxuXHJcblx0fVxyXG5cclxuXHRleHBvbmVudFRhYmxlWyA2MyBdID0gMHhjNzgwMDAwMDtcclxuXHJcblx0Zm9yICggbGV0IGkgPSAxOyBpIDwgNjQ7ICsrIGkgKSB7XHJcblxyXG5cdFx0aWYgKCBpICE9PSAzMiApIHtcclxuXHJcblx0XHRcdG9mZnNldFRhYmxlWyBpIF0gPSAxMDI0O1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4ge1xyXG5cdFx0ZmxvYXRWaWV3OiBmbG9hdFZpZXcsXHJcblx0XHR1aW50MzJWaWV3OiB1aW50MzJWaWV3LFxyXG5cdFx0YmFzZVRhYmxlOiBiYXNlVGFibGUsXHJcblx0XHRzaGlmdFRhYmxlOiBzaGlmdFRhYmxlLFxyXG5cdFx0bWFudGlzc2FUYWJsZTogbWFudGlzc2FUYWJsZSxcclxuXHRcdGV4cG9uZW50VGFibGU6IGV4cG9uZW50VGFibGUsXHJcblx0XHRvZmZzZXRUYWJsZTogb2Zmc2V0VGFibGVcclxuXHR9O1xyXG5cclxufVxyXG5cclxuLy8gZmxvYXQzMiB0byBmbG9hdDE2XHJcblxyXG5mdW5jdGlvbiB0b0hhbGZGbG9hdCggdmFsICkge1xyXG5cclxuXHRpZiAoIE1hdGguYWJzKCB2YWwgKSA+IDY1NTA0ICkgY29uc29sZS53YXJuKCAnVEhSRUUuRGF0YVV0aWxzLnRvSGFsZkZsb2F0KCk6IFZhbHVlIG91dCBvZiByYW5nZS4nICk7XHJcblxyXG5cdHZhbCA9IGNsYW1wKCB2YWwsIC0gNjU1MDQsIDY1NTA0ICk7XHJcblxyXG5cdF90YWJsZXMuZmxvYXRWaWV3WyAwIF0gPSB2YWw7XHJcblx0Y29uc3QgZiA9IF90YWJsZXMudWludDMyVmlld1sgMCBdO1xyXG5cdGNvbnN0IGUgPSAoIGYgPj4gMjMgKSAmIDB4MWZmO1xyXG5cdHJldHVybiBfdGFibGVzLmJhc2VUYWJsZVsgZSBdICsgKCAoIGYgJiAweDAwN2ZmZmZmICkgPj4gX3RhYmxlcy5zaGlmdFRhYmxlWyBlIF0gKTtcclxuXHJcbn1cclxuXHJcbi8vIGZsb2F0MTYgdG8gZmxvYXQzMlxyXG5cclxuZnVuY3Rpb24gZnJvbUhhbGZGbG9hdCggdmFsICkge1xyXG5cclxuXHRjb25zdCBtID0gdmFsID4+IDEwO1xyXG5cdF90YWJsZXMudWludDMyVmlld1sgMCBdID0gX3RhYmxlcy5tYW50aXNzYVRhYmxlWyBfdGFibGVzLm9mZnNldFRhYmxlWyBtIF0gKyAoIHZhbCAmIDB4M2ZmICkgXSArIF90YWJsZXMuZXhwb25lbnRUYWJsZVsgbSBdO1xyXG5cdHJldHVybiBfdGFibGVzLmZsb2F0Vmlld1sgMCBdO1xyXG5cclxufVxyXG5cclxuY29uc3QgRGF0YVV0aWxzID0ge1xyXG5cdHRvSGFsZkZsb2F0OiB0b0hhbGZGbG9hdCxcclxuXHRmcm9tSGFsZkZsb2F0OiBmcm9tSGFsZkZsb2F0LFxyXG59O1xyXG5cclxuZXhwb3J0IHtcclxuXHR0b0hhbGZGbG9hdCxcclxuXHRmcm9tSGFsZkZsb2F0LFxyXG5cdERhdGFVdGlsc1xyXG59O1xyXG4iLCJpbXBvcnQgeyBWZWN0b3IzIH0gZnJvbSAnLi4vbWF0aC9WZWN0b3IzLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yMiB9IGZyb20gJy4uL21hdGgvVmVjdG9yMi5qcyc7XHJcbmltcG9ydCB7IGRlbm9ybWFsaXplLCBub3JtYWxpemUgfSBmcm9tICcuLi9tYXRoL01hdGhVdGlscy5qcyc7XHJcbmltcG9ydCB7IFN0YXRpY0RyYXdVc2FnZSwgRmxvYXRUeXBlIH0gZnJvbSAnLi4vY29uc3RhbnRzLmpzJztcclxuaW1wb3J0IHsgZnJvbUhhbGZGbG9hdCwgdG9IYWxmRmxvYXQgfSBmcm9tICcuLi9leHRyYXMvRGF0YVV0aWxzLmpzJztcclxuaW1wb3J0IHsgd2Fybk9uY2UgfSBmcm9tICcuLi91dGlscy5qcyc7XHJcblxyXG5jb25zdCBfdmVjdG9yID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5jb25zdCBfdmVjdG9yMiA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjIoKTtcclxuXHJcbmNsYXNzIEJ1ZmZlckF0dHJpYnV0ZSB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBhcnJheSwgaXRlbVNpemUsIG5vcm1hbGl6ZWQgPSBmYWxzZSApIHtcclxuXHJcblx0XHRpZiAoIEFycmF5LmlzQXJyYXkoIGFycmF5ICkgKSB7XHJcblxyXG5cdFx0XHR0aHJvdyBuZXcgVHlwZUVycm9yKCAnVEhSRUUuQnVmZmVyQXR0cmlidXRlOiBhcnJheSBzaG91bGQgYmUgYSBUeXBlZCBBcnJheS4nICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMuaXNCdWZmZXJBdHRyaWJ1dGUgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMubmFtZSA9ICcnO1xyXG5cclxuXHRcdHRoaXMuYXJyYXkgPSBhcnJheTtcclxuXHRcdHRoaXMuaXRlbVNpemUgPSBpdGVtU2l6ZTtcclxuXHRcdHRoaXMuY291bnQgPSBhcnJheSAhPT0gdW5kZWZpbmVkID8gYXJyYXkubGVuZ3RoIC8gaXRlbVNpemUgOiAwO1xyXG5cdFx0dGhpcy5ub3JtYWxpemVkID0gbm9ybWFsaXplZDtcclxuXHJcblx0XHR0aGlzLnVzYWdlID0gU3RhdGljRHJhd1VzYWdlO1xyXG5cdFx0dGhpcy5fdXBkYXRlUmFuZ2UgPSB7IG9mZnNldDogMCwgY291bnQ6IC0gMSB9O1xyXG5cdFx0dGhpcy51cGRhdGVSYW5nZXMgPSBbXTtcclxuXHRcdHRoaXMuZ3B1VHlwZSA9IEZsb2F0VHlwZTtcclxuXHJcblx0XHR0aGlzLnZlcnNpb24gPSAwO1xyXG5cclxuXHR9XHJcblxyXG5cdG9uVXBsb2FkQ2FsbGJhY2soKSB7fVxyXG5cclxuXHRzZXQgbmVlZHNVcGRhdGUoIHZhbHVlICkge1xyXG5cclxuXHRcdGlmICggdmFsdWUgPT09IHRydWUgKSB0aGlzLnZlcnNpb24gKys7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0IHVwZGF0ZVJhbmdlKCkge1xyXG5cclxuXHRcdHdhcm5PbmNlKCAnVEhSRUUuQnVmZmVyQXR0cmlidXRlOiB1cGRhdGVSYW5nZSgpIGlzIGRlcHJlY2F0ZWQgYW5kIHdpbGwgYmUgcmVtb3ZlZCBpbiByMTY5LiBVc2UgYWRkVXBkYXRlUmFuZ2UoKSBpbnN0ZWFkLicgKTsgLy8gQGRlcHJlY2F0ZWQsIHIxNTlcclxuXHRcdHJldHVybiB0aGlzLl91cGRhdGVSYW5nZTtcclxuXHJcblx0fVxyXG5cclxuXHRzZXRVc2FnZSggdmFsdWUgKSB7XHJcblxyXG5cdFx0dGhpcy51c2FnZSA9IHZhbHVlO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGFkZFVwZGF0ZVJhbmdlKCBzdGFydCwgY291bnQgKSB7XHJcblxyXG5cdFx0dGhpcy51cGRhdGVSYW5nZXMucHVzaCggeyBzdGFydCwgY291bnQgfSApO1xyXG5cclxuXHR9XHJcblxyXG5cdGNsZWFyVXBkYXRlUmFuZ2VzKCkge1xyXG5cclxuXHRcdHRoaXMudXBkYXRlUmFuZ2VzLmxlbmd0aCA9IDA7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHRoaXMubmFtZSA9IHNvdXJjZS5uYW1lO1xyXG5cdFx0dGhpcy5hcnJheSA9IG5ldyBzb3VyY2UuYXJyYXkuY29uc3RydWN0b3IoIHNvdXJjZS5hcnJheSApO1xyXG5cdFx0dGhpcy5pdGVtU2l6ZSA9IHNvdXJjZS5pdGVtU2l6ZTtcclxuXHRcdHRoaXMuY291bnQgPSBzb3VyY2UuY291bnQ7XHJcblx0XHR0aGlzLm5vcm1hbGl6ZWQgPSBzb3VyY2Uubm9ybWFsaXplZDtcclxuXHJcblx0XHR0aGlzLnVzYWdlID0gc291cmNlLnVzYWdlO1xyXG5cdFx0dGhpcy5ncHVUeXBlID0gc291cmNlLmdwdVR5cGU7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weUF0KCBpbmRleDEsIGF0dHJpYnV0ZSwgaW5kZXgyICkge1xyXG5cclxuXHRcdGluZGV4MSAqPSB0aGlzLml0ZW1TaXplO1xyXG5cdFx0aW5kZXgyICo9IGF0dHJpYnV0ZS5pdGVtU2l6ZTtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSB0aGlzLml0ZW1TaXplOyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdHRoaXMuYXJyYXlbIGluZGV4MSArIGkgXSA9IGF0dHJpYnV0ZS5hcnJheVsgaW5kZXgyICsgaSBdO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRjb3B5QXJyYXkoIGFycmF5ICkge1xyXG5cclxuXHRcdHRoaXMuYXJyYXkuc2V0KCBhcnJheSApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGFwcGx5TWF0cml4MyggbSApIHtcclxuXHJcblx0XHRpZiAoIHRoaXMuaXRlbVNpemUgPT09IDIgKSB7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSB0aGlzLmNvdW50OyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0X3ZlY3RvcjIuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggdGhpcywgaSApO1xyXG5cdFx0XHRcdF92ZWN0b3IyLmFwcGx5TWF0cml4MyggbSApO1xyXG5cclxuXHRcdFx0XHR0aGlzLnNldFhZKCBpLCBfdmVjdG9yMi54LCBfdmVjdG9yMi55ICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fSBlbHNlIGlmICggdGhpcy5pdGVtU2l6ZSA9PT0gMyApIHtcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMCwgbCA9IHRoaXMuY291bnQ7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRfdmVjdG9yLmZyb21CdWZmZXJBdHRyaWJ1dGUoIHRoaXMsIGkgKTtcclxuXHRcdFx0XHRfdmVjdG9yLmFwcGx5TWF0cml4MyggbSApO1xyXG5cclxuXHRcdFx0XHR0aGlzLnNldFhZWiggaSwgX3ZlY3Rvci54LCBfdmVjdG9yLnksIF92ZWN0b3IueiApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRhcHBseU1hdHJpeDQoIG0gKSB7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gdGhpcy5jb3VudDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRfdmVjdG9yLmZyb21CdWZmZXJBdHRyaWJ1dGUoIHRoaXMsIGkgKTtcclxuXHJcblx0XHRcdF92ZWN0b3IuYXBwbHlNYXRyaXg0KCBtICk7XHJcblxyXG5cdFx0XHR0aGlzLnNldFhZWiggaSwgX3ZlY3Rvci54LCBfdmVjdG9yLnksIF92ZWN0b3IueiApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRhcHBseU5vcm1hbE1hdHJpeCggbSApIHtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSB0aGlzLmNvdW50OyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdF92ZWN0b3IuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggdGhpcywgaSApO1xyXG5cclxuXHRcdFx0X3ZlY3Rvci5hcHBseU5vcm1hbE1hdHJpeCggbSApO1xyXG5cclxuXHRcdFx0dGhpcy5zZXRYWVooIGksIF92ZWN0b3IueCwgX3ZlY3Rvci55LCBfdmVjdG9yLnogKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0dHJhbnNmb3JtRGlyZWN0aW9uKCBtICkge1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IHRoaXMuY291bnQ7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0X3ZlY3Rvci5mcm9tQnVmZmVyQXR0cmlidXRlKCB0aGlzLCBpICk7XHJcblxyXG5cdFx0XHRfdmVjdG9yLnRyYW5zZm9ybURpcmVjdGlvbiggbSApO1xyXG5cclxuXHRcdFx0dGhpcy5zZXRYWVooIGksIF92ZWN0b3IueCwgX3ZlY3Rvci55LCBfdmVjdG9yLnogKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0KCB2YWx1ZSwgb2Zmc2V0ID0gMCApIHtcclxuXHJcblx0XHQvLyBNYXRjaGluZyBCdWZmZXJBdHRyaWJ1dGUgY29uc3RydWN0b3IsIGRvIG5vdCBub3JtYWxpemUgdGhlIGFycmF5LlxyXG5cdFx0dGhpcy5hcnJheS5zZXQoIHZhbHVlLCBvZmZzZXQgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRnZXRDb21wb25lbnQoIGluZGV4LCBjb21wb25lbnQgKSB7XHJcblxyXG5cdFx0bGV0IHZhbHVlID0gdGhpcy5hcnJheVsgaW5kZXggKiB0aGlzLml0ZW1TaXplICsgY29tcG9uZW50IF07XHJcblxyXG5cdFx0aWYgKCB0aGlzLm5vcm1hbGl6ZWQgKSB2YWx1ZSA9IGRlbm9ybWFsaXplKCB2YWx1ZSwgdGhpcy5hcnJheSApO1xyXG5cclxuXHRcdHJldHVybiB2YWx1ZTtcclxuXHJcblx0fVxyXG5cclxuXHRzZXRDb21wb25lbnQoIGluZGV4LCBjb21wb25lbnQsIHZhbHVlICkge1xyXG5cclxuXHRcdGlmICggdGhpcy5ub3JtYWxpemVkICkgdmFsdWUgPSBub3JtYWxpemUoIHZhbHVlLCB0aGlzLmFycmF5ICk7XHJcblxyXG5cdFx0dGhpcy5hcnJheVsgaW5kZXggKiB0aGlzLml0ZW1TaXplICsgY29tcG9uZW50IF0gPSB2YWx1ZTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRnZXRYKCBpbmRleCApIHtcclxuXHJcblx0XHRsZXQgeCA9IHRoaXMuYXJyYXlbIGluZGV4ICogdGhpcy5pdGVtU2l6ZSBdO1xyXG5cclxuXHRcdGlmICggdGhpcy5ub3JtYWxpemVkICkgeCA9IGRlbm9ybWFsaXplKCB4LCB0aGlzLmFycmF5ICk7XHJcblxyXG5cdFx0cmV0dXJuIHg7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0WCggaW5kZXgsIHggKSB7XHJcblxyXG5cdFx0aWYgKCB0aGlzLm5vcm1hbGl6ZWQgKSB4ID0gbm9ybWFsaXplKCB4LCB0aGlzLmFycmF5ICk7XHJcblxyXG5cdFx0dGhpcy5hcnJheVsgaW5kZXggKiB0aGlzLml0ZW1TaXplIF0gPSB4O1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldFkoIGluZGV4ICkge1xyXG5cclxuXHRcdGxldCB5ID0gdGhpcy5hcnJheVsgaW5kZXggKiB0aGlzLml0ZW1TaXplICsgMSBdO1xyXG5cclxuXHRcdGlmICggdGhpcy5ub3JtYWxpemVkICkgeSA9IGRlbm9ybWFsaXplKCB5LCB0aGlzLmFycmF5ICk7XHJcblxyXG5cdFx0cmV0dXJuIHk7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0WSggaW5kZXgsIHkgKSB7XHJcblxyXG5cdFx0aWYgKCB0aGlzLm5vcm1hbGl6ZWQgKSB5ID0gbm9ybWFsaXplKCB5LCB0aGlzLmFycmF5ICk7XHJcblxyXG5cdFx0dGhpcy5hcnJheVsgaW5kZXggKiB0aGlzLml0ZW1TaXplICsgMSBdID0geTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRnZXRaKCBpbmRleCApIHtcclxuXHJcblx0XHRsZXQgeiA9IHRoaXMuYXJyYXlbIGluZGV4ICogdGhpcy5pdGVtU2l6ZSArIDIgXTtcclxuXHJcblx0XHRpZiAoIHRoaXMubm9ybWFsaXplZCApIHogPSBkZW5vcm1hbGl6ZSggeiwgdGhpcy5hcnJheSApO1xyXG5cclxuXHRcdHJldHVybiB6O1xyXG5cclxuXHR9XHJcblxyXG5cdHNldFooIGluZGV4LCB6ICkge1xyXG5cclxuXHRcdGlmICggdGhpcy5ub3JtYWxpemVkICkgeiA9IG5vcm1hbGl6ZSggeiwgdGhpcy5hcnJheSApO1xyXG5cclxuXHRcdHRoaXMuYXJyYXlbIGluZGV4ICogdGhpcy5pdGVtU2l6ZSArIDIgXSA9IHo7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0VyggaW5kZXggKSB7XHJcblxyXG5cdFx0bGV0IHcgPSB0aGlzLmFycmF5WyBpbmRleCAqIHRoaXMuaXRlbVNpemUgKyAzIF07XHJcblxyXG5cdFx0aWYgKCB0aGlzLm5vcm1hbGl6ZWQgKSB3ID0gZGVub3JtYWxpemUoIHcsIHRoaXMuYXJyYXkgKTtcclxuXHJcblx0XHRyZXR1cm4gdztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRXKCBpbmRleCwgdyApIHtcclxuXHJcblx0XHRpZiAoIHRoaXMubm9ybWFsaXplZCApIHcgPSBub3JtYWxpemUoIHcsIHRoaXMuYXJyYXkgKTtcclxuXHJcblx0XHR0aGlzLmFycmF5WyBpbmRleCAqIHRoaXMuaXRlbVNpemUgKyAzIF0gPSB3O1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldFhZKCBpbmRleCwgeCwgeSApIHtcclxuXHJcblx0XHRpbmRleCAqPSB0aGlzLml0ZW1TaXplO1xyXG5cclxuXHRcdGlmICggdGhpcy5ub3JtYWxpemVkICkge1xyXG5cclxuXHRcdFx0eCA9IG5vcm1hbGl6ZSggeCwgdGhpcy5hcnJheSApO1xyXG5cdFx0XHR5ID0gbm9ybWFsaXplKCB5LCB0aGlzLmFycmF5ICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMuYXJyYXlbIGluZGV4ICsgMCBdID0geDtcclxuXHRcdHRoaXMuYXJyYXlbIGluZGV4ICsgMSBdID0geTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRYWVooIGluZGV4LCB4LCB5LCB6ICkge1xyXG5cclxuXHRcdGluZGV4ICo9IHRoaXMuaXRlbVNpemU7XHJcblxyXG5cdFx0aWYgKCB0aGlzLm5vcm1hbGl6ZWQgKSB7XHJcblxyXG5cdFx0XHR4ID0gbm9ybWFsaXplKCB4LCB0aGlzLmFycmF5ICk7XHJcblx0XHRcdHkgPSBub3JtYWxpemUoIHksIHRoaXMuYXJyYXkgKTtcclxuXHRcdFx0eiA9IG5vcm1hbGl6ZSggeiwgdGhpcy5hcnJheSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLmFycmF5WyBpbmRleCArIDAgXSA9IHg7XHJcblx0XHR0aGlzLmFycmF5WyBpbmRleCArIDEgXSA9IHk7XHJcblx0XHR0aGlzLmFycmF5WyBpbmRleCArIDIgXSA9IHo7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0WFlaVyggaW5kZXgsIHgsIHksIHosIHcgKSB7XHJcblxyXG5cdFx0aW5kZXggKj0gdGhpcy5pdGVtU2l6ZTtcclxuXHJcblx0XHRpZiAoIHRoaXMubm9ybWFsaXplZCApIHtcclxuXHJcblx0XHRcdHggPSBub3JtYWxpemUoIHgsIHRoaXMuYXJyYXkgKTtcclxuXHRcdFx0eSA9IG5vcm1hbGl6ZSggeSwgdGhpcy5hcnJheSApO1xyXG5cdFx0XHR6ID0gbm9ybWFsaXplKCB6LCB0aGlzLmFycmF5ICk7XHJcblx0XHRcdHcgPSBub3JtYWxpemUoIHcsIHRoaXMuYXJyYXkgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5hcnJheVsgaW5kZXggKyAwIF0gPSB4O1xyXG5cdFx0dGhpcy5hcnJheVsgaW5kZXggKyAxIF0gPSB5O1xyXG5cdFx0dGhpcy5hcnJheVsgaW5kZXggKyAyIF0gPSB6O1xyXG5cdFx0dGhpcy5hcnJheVsgaW5kZXggKyAzIF0gPSB3O1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdG9uVXBsb2FkKCBjYWxsYmFjayApIHtcclxuXHJcblx0XHR0aGlzLm9uVXBsb2FkQ2FsbGJhY2sgPSBjYWxsYmFjaztcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRjbG9uZSgpIHtcclxuXHJcblx0XHRyZXR1cm4gbmV3IHRoaXMuY29uc3RydWN0b3IoIHRoaXMuYXJyYXksIHRoaXMuaXRlbVNpemUgKS5jb3B5KCB0aGlzICk7XHJcblxyXG5cdH1cclxuXHJcblx0dG9KU09OKCkge1xyXG5cclxuXHRcdGNvbnN0IGRhdGEgPSB7XHJcblx0XHRcdGl0ZW1TaXplOiB0aGlzLml0ZW1TaXplLFxyXG5cdFx0XHR0eXBlOiB0aGlzLmFycmF5LmNvbnN0cnVjdG9yLm5hbWUsXHJcblx0XHRcdGFycmF5OiBBcnJheS5mcm9tKCB0aGlzLmFycmF5ICksXHJcblx0XHRcdG5vcm1hbGl6ZWQ6IHRoaXMubm9ybWFsaXplZFxyXG5cdFx0fTtcclxuXHJcblx0XHRpZiAoIHRoaXMubmFtZSAhPT0gJycgKSBkYXRhLm5hbWUgPSB0aGlzLm5hbWU7XHJcblx0XHRpZiAoIHRoaXMudXNhZ2UgIT09IFN0YXRpY0RyYXdVc2FnZSApIGRhdGEudXNhZ2UgPSB0aGlzLnVzYWdlO1xyXG5cclxuXHRcdHJldHVybiBkYXRhO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG4vL1xyXG5cclxuY2xhc3MgSW50OEJ1ZmZlckF0dHJpYnV0ZSBleHRlbmRzIEJ1ZmZlckF0dHJpYnV0ZSB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBhcnJheSwgaXRlbVNpemUsIG5vcm1hbGl6ZWQgKSB7XHJcblxyXG5cdFx0c3VwZXIoIG5ldyBJbnQ4QXJyYXkoIGFycmF5ICksIGl0ZW1TaXplLCBub3JtYWxpemVkICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmNsYXNzIFVpbnQ4QnVmZmVyQXR0cmlidXRlIGV4dGVuZHMgQnVmZmVyQXR0cmlidXRlIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIGFycmF5LCBpdGVtU2l6ZSwgbm9ybWFsaXplZCApIHtcclxuXHJcblx0XHRzdXBlciggbmV3IFVpbnQ4QXJyYXkoIGFycmF5ICksIGl0ZW1TaXplLCBub3JtYWxpemVkICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmNsYXNzIFVpbnQ4Q2xhbXBlZEJ1ZmZlckF0dHJpYnV0ZSBleHRlbmRzIEJ1ZmZlckF0dHJpYnV0ZSB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBhcnJheSwgaXRlbVNpemUsIG5vcm1hbGl6ZWQgKSB7XHJcblxyXG5cdFx0c3VwZXIoIG5ldyBVaW50OENsYW1wZWRBcnJheSggYXJyYXkgKSwgaXRlbVNpemUsIG5vcm1hbGl6ZWQgKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuY2xhc3MgSW50MTZCdWZmZXJBdHRyaWJ1dGUgZXh0ZW5kcyBCdWZmZXJBdHRyaWJ1dGUge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggYXJyYXksIGl0ZW1TaXplLCBub3JtYWxpemVkICkge1xyXG5cclxuXHRcdHN1cGVyKCBuZXcgSW50MTZBcnJheSggYXJyYXkgKSwgaXRlbVNpemUsIG5vcm1hbGl6ZWQgKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuY2xhc3MgVWludDE2QnVmZmVyQXR0cmlidXRlIGV4dGVuZHMgQnVmZmVyQXR0cmlidXRlIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIGFycmF5LCBpdGVtU2l6ZSwgbm9ybWFsaXplZCApIHtcclxuXHJcblx0XHRzdXBlciggbmV3IFVpbnQxNkFycmF5KCBhcnJheSApLCBpdGVtU2l6ZSwgbm9ybWFsaXplZCApO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5jbGFzcyBJbnQzMkJ1ZmZlckF0dHJpYnV0ZSBleHRlbmRzIEJ1ZmZlckF0dHJpYnV0ZSB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBhcnJheSwgaXRlbVNpemUsIG5vcm1hbGl6ZWQgKSB7XHJcblxyXG5cdFx0c3VwZXIoIG5ldyBJbnQzMkFycmF5KCBhcnJheSApLCBpdGVtU2l6ZSwgbm9ybWFsaXplZCApO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5jbGFzcyBVaW50MzJCdWZmZXJBdHRyaWJ1dGUgZXh0ZW5kcyBCdWZmZXJBdHRyaWJ1dGUge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggYXJyYXksIGl0ZW1TaXplLCBub3JtYWxpemVkICkge1xyXG5cclxuXHRcdHN1cGVyKCBuZXcgVWludDMyQXJyYXkoIGFycmF5ICksIGl0ZW1TaXplLCBub3JtYWxpemVkICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmNsYXNzIEZsb2F0MTZCdWZmZXJBdHRyaWJ1dGUgZXh0ZW5kcyBCdWZmZXJBdHRyaWJ1dGUge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggYXJyYXksIGl0ZW1TaXplLCBub3JtYWxpemVkICkge1xyXG5cclxuXHRcdHN1cGVyKCBuZXcgVWludDE2QXJyYXkoIGFycmF5ICksIGl0ZW1TaXplLCBub3JtYWxpemVkICk7XHJcblxyXG5cdFx0dGhpcy5pc0Zsb2F0MTZCdWZmZXJBdHRyaWJ1dGUgPSB0cnVlO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldFgoIGluZGV4ICkge1xyXG5cclxuXHRcdGxldCB4ID0gZnJvbUhhbGZGbG9hdCggdGhpcy5hcnJheVsgaW5kZXggKiB0aGlzLml0ZW1TaXplIF0gKTtcclxuXHJcblx0XHRpZiAoIHRoaXMubm9ybWFsaXplZCApIHggPSBkZW5vcm1hbGl6ZSggeCwgdGhpcy5hcnJheSApO1xyXG5cclxuXHRcdHJldHVybiB4O1xyXG5cclxuXHR9XHJcblxyXG5cdHNldFgoIGluZGV4LCB4ICkge1xyXG5cclxuXHRcdGlmICggdGhpcy5ub3JtYWxpemVkICkgeCA9IG5vcm1hbGl6ZSggeCwgdGhpcy5hcnJheSApO1xyXG5cclxuXHRcdHRoaXMuYXJyYXlbIGluZGV4ICogdGhpcy5pdGVtU2l6ZSBdID0gdG9IYWxmRmxvYXQoIHggKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRnZXRZKCBpbmRleCApIHtcclxuXHJcblx0XHRsZXQgeSA9IGZyb21IYWxmRmxvYXQoIHRoaXMuYXJyYXlbIGluZGV4ICogdGhpcy5pdGVtU2l6ZSArIDEgXSApO1xyXG5cclxuXHRcdGlmICggdGhpcy5ub3JtYWxpemVkICkgeSA9IGRlbm9ybWFsaXplKCB5LCB0aGlzLmFycmF5ICk7XHJcblxyXG5cdFx0cmV0dXJuIHk7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0WSggaW5kZXgsIHkgKSB7XHJcblxyXG5cdFx0aWYgKCB0aGlzLm5vcm1hbGl6ZWQgKSB5ID0gbm9ybWFsaXplKCB5LCB0aGlzLmFycmF5ICk7XHJcblxyXG5cdFx0dGhpcy5hcnJheVsgaW5kZXggKiB0aGlzLml0ZW1TaXplICsgMSBdID0gdG9IYWxmRmxvYXQoIHkgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRnZXRaKCBpbmRleCApIHtcclxuXHJcblx0XHRsZXQgeiA9IGZyb21IYWxmRmxvYXQoIHRoaXMuYXJyYXlbIGluZGV4ICogdGhpcy5pdGVtU2l6ZSArIDIgXSApO1xyXG5cclxuXHRcdGlmICggdGhpcy5ub3JtYWxpemVkICkgeiA9IGRlbm9ybWFsaXplKCB6LCB0aGlzLmFycmF5ICk7XHJcblxyXG5cdFx0cmV0dXJuIHo7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0WiggaW5kZXgsIHogKSB7XHJcblxyXG5cdFx0aWYgKCB0aGlzLm5vcm1hbGl6ZWQgKSB6ID0gbm9ybWFsaXplKCB6LCB0aGlzLmFycmF5ICk7XHJcblxyXG5cdFx0dGhpcy5hcnJheVsgaW5kZXggKiB0aGlzLml0ZW1TaXplICsgMiBdID0gdG9IYWxmRmxvYXQoIHogKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRnZXRXKCBpbmRleCApIHtcclxuXHJcblx0XHRsZXQgdyA9IGZyb21IYWxmRmxvYXQoIHRoaXMuYXJyYXlbIGluZGV4ICogdGhpcy5pdGVtU2l6ZSArIDMgXSApO1xyXG5cclxuXHRcdGlmICggdGhpcy5ub3JtYWxpemVkICkgdyA9IGRlbm9ybWFsaXplKCB3LCB0aGlzLmFycmF5ICk7XHJcblxyXG5cdFx0cmV0dXJuIHc7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0VyggaW5kZXgsIHcgKSB7XHJcblxyXG5cdFx0aWYgKCB0aGlzLm5vcm1hbGl6ZWQgKSB3ID0gbm9ybWFsaXplKCB3LCB0aGlzLmFycmF5ICk7XHJcblxyXG5cdFx0dGhpcy5hcnJheVsgaW5kZXggKiB0aGlzLml0ZW1TaXplICsgMyBdID0gdG9IYWxmRmxvYXQoIHcgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRYWSggaW5kZXgsIHgsIHkgKSB7XHJcblxyXG5cdFx0aW5kZXggKj0gdGhpcy5pdGVtU2l6ZTtcclxuXHJcblx0XHRpZiAoIHRoaXMubm9ybWFsaXplZCApIHtcclxuXHJcblx0XHRcdHggPSBub3JtYWxpemUoIHgsIHRoaXMuYXJyYXkgKTtcclxuXHRcdFx0eSA9IG5vcm1hbGl6ZSggeSwgdGhpcy5hcnJheSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLmFycmF5WyBpbmRleCArIDAgXSA9IHRvSGFsZkZsb2F0KCB4ICk7XHJcblx0XHR0aGlzLmFycmF5WyBpbmRleCArIDEgXSA9IHRvSGFsZkZsb2F0KCB5ICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0WFlaKCBpbmRleCwgeCwgeSwgeiApIHtcclxuXHJcblx0XHRpbmRleCAqPSB0aGlzLml0ZW1TaXplO1xyXG5cclxuXHRcdGlmICggdGhpcy5ub3JtYWxpemVkICkge1xyXG5cclxuXHRcdFx0eCA9IG5vcm1hbGl6ZSggeCwgdGhpcy5hcnJheSApO1xyXG5cdFx0XHR5ID0gbm9ybWFsaXplKCB5LCB0aGlzLmFycmF5ICk7XHJcblx0XHRcdHogPSBub3JtYWxpemUoIHosIHRoaXMuYXJyYXkgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5hcnJheVsgaW5kZXggKyAwIF0gPSB0b0hhbGZGbG9hdCggeCApO1xyXG5cdFx0dGhpcy5hcnJheVsgaW5kZXggKyAxIF0gPSB0b0hhbGZGbG9hdCggeSApO1xyXG5cdFx0dGhpcy5hcnJheVsgaW5kZXggKyAyIF0gPSB0b0hhbGZGbG9hdCggeiApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldFhZWlcoIGluZGV4LCB4LCB5LCB6LCB3ICkge1xyXG5cclxuXHRcdGluZGV4ICo9IHRoaXMuaXRlbVNpemU7XHJcblxyXG5cdFx0aWYgKCB0aGlzLm5vcm1hbGl6ZWQgKSB7XHJcblxyXG5cdFx0XHR4ID0gbm9ybWFsaXplKCB4LCB0aGlzLmFycmF5ICk7XHJcblx0XHRcdHkgPSBub3JtYWxpemUoIHksIHRoaXMuYXJyYXkgKTtcclxuXHRcdFx0eiA9IG5vcm1hbGl6ZSggeiwgdGhpcy5hcnJheSApO1xyXG5cdFx0XHR3ID0gbm9ybWFsaXplKCB3LCB0aGlzLmFycmF5ICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMuYXJyYXlbIGluZGV4ICsgMCBdID0gdG9IYWxmRmxvYXQoIHggKTtcclxuXHRcdHRoaXMuYXJyYXlbIGluZGV4ICsgMSBdID0gdG9IYWxmRmxvYXQoIHkgKTtcclxuXHRcdHRoaXMuYXJyYXlbIGluZGV4ICsgMiBdID0gdG9IYWxmRmxvYXQoIHogKTtcclxuXHRcdHRoaXMuYXJyYXlbIGluZGV4ICsgMyBdID0gdG9IYWxmRmxvYXQoIHcgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuXHJcbmNsYXNzIEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUgZXh0ZW5kcyBCdWZmZXJBdHRyaWJ1dGUge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggYXJyYXksIGl0ZW1TaXplLCBub3JtYWxpemVkICkge1xyXG5cclxuXHRcdHN1cGVyKCBuZXcgRmxvYXQzMkFycmF5KCBhcnJheSApLCBpdGVtU2l6ZSwgbm9ybWFsaXplZCApO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5jbGFzcyBGbG9hdDY0QnVmZmVyQXR0cmlidXRlIGV4dGVuZHMgQnVmZmVyQXR0cmlidXRlIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIGFycmF5LCBpdGVtU2l6ZSwgbm9ybWFsaXplZCApIHtcclxuXHJcblx0XHRzdXBlciggbmV3IEZsb2F0NjRBcnJheSggYXJyYXkgKSwgaXRlbVNpemUsIG5vcm1hbGl6ZWQgKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuLy9cclxuXHJcbmV4cG9ydCB7XHJcblx0RmxvYXQ2NEJ1ZmZlckF0dHJpYnV0ZSxcclxuXHRGbG9hdDMyQnVmZmVyQXR0cmlidXRlLFxyXG5cdEZsb2F0MTZCdWZmZXJBdHRyaWJ1dGUsXHJcblx0VWludDMyQnVmZmVyQXR0cmlidXRlLFxyXG5cdEludDMyQnVmZmVyQXR0cmlidXRlLFxyXG5cdFVpbnQxNkJ1ZmZlckF0dHJpYnV0ZSxcclxuXHRJbnQxNkJ1ZmZlckF0dHJpYnV0ZSxcclxuXHRVaW50OENsYW1wZWRCdWZmZXJBdHRyaWJ1dGUsXHJcblx0VWludDhCdWZmZXJBdHRyaWJ1dGUsXHJcblx0SW50OEJ1ZmZlckF0dHJpYnV0ZSxcclxuXHRCdWZmZXJBdHRyaWJ1dGVcclxufTtcclxuIiwiaW1wb3J0IHsgVmVjdG9yMyB9IGZyb20gJy4uL21hdGgvVmVjdG9yMy5qcyc7XHJcbmltcG9ydCB7IFZlY3RvcjIgfSBmcm9tICcuLi9tYXRoL1ZlY3RvcjIuanMnO1xyXG5pbXBvcnQgeyBCb3gzIH0gZnJvbSAnLi4vbWF0aC9Cb3gzLmpzJztcclxuaW1wb3J0IHsgRXZlbnREaXNwYXRjaGVyIH0gZnJvbSAnLi9FdmVudERpc3BhdGNoZXIuanMnO1xyXG5pbXBvcnQgeyBCdWZmZXJBdHRyaWJ1dGUsIEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUsIFVpbnQxNkJ1ZmZlckF0dHJpYnV0ZSwgVWludDMyQnVmZmVyQXR0cmlidXRlIH0gZnJvbSAnLi9CdWZmZXJBdHRyaWJ1dGUuanMnO1xyXG5pbXBvcnQgeyBTcGhlcmUgfSBmcm9tICcuLi9tYXRoL1NwaGVyZS5qcyc7XHJcbmltcG9ydCB7IE9iamVjdDNEIH0gZnJvbSAnLi9PYmplY3QzRC5qcyc7XHJcbmltcG9ydCB7IE1hdHJpeDQgfSBmcm9tICcuLi9tYXRoL01hdHJpeDQuanMnO1xyXG5pbXBvcnQgeyBNYXRyaXgzIH0gZnJvbSAnLi4vbWF0aC9NYXRyaXgzLmpzJztcclxuaW1wb3J0ICogYXMgTWF0aFV0aWxzIGZyb20gJy4uL21hdGgvTWF0aFV0aWxzLmpzJztcclxuaW1wb3J0IHsgYXJyYXlOZWVkc1VpbnQzMiB9IGZyb20gJy4uL3V0aWxzLmpzJztcclxuXHJcbmxldCBfaWQgPSAwO1xyXG5cclxuY29uc3QgX20xID0gLypAX19QVVJFX18qLyBuZXcgTWF0cml4NCgpO1xyXG5jb25zdCBfb2JqID0gLypAX19QVVJFX18qLyBuZXcgT2JqZWN0M0QoKTtcclxuY29uc3QgX29mZnNldCA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuY29uc3QgX2JveCA9IC8qQF9fUFVSRV9fKi8gbmV3IEJveDMoKTtcclxuY29uc3QgX2JveE1vcnBoVGFyZ2V0cyA9IC8qQF9fUFVSRV9fKi8gbmV3IEJveDMoKTtcclxuY29uc3QgX3ZlY3RvciA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuXHJcbmNsYXNzIEJ1ZmZlckdlb21ldHJ5IGV4dGVuZHMgRXZlbnREaXNwYXRjaGVyIHtcclxuXHJcblx0Y29uc3RydWN0b3IoKSB7XHJcblxyXG5cdFx0c3VwZXIoKTtcclxuXHJcblx0XHR0aGlzLmlzQnVmZmVyR2VvbWV0cnkgPSB0cnVlO1xyXG5cclxuXHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eSggdGhpcywgJ2lkJywgeyB2YWx1ZTogX2lkICsrIH0gKTtcclxuXHJcblx0XHR0aGlzLnV1aWQgPSBNYXRoVXRpbHMuZ2VuZXJhdGVVVUlEKCk7XHJcblxyXG5cdFx0dGhpcy5uYW1lID0gJyc7XHJcblx0XHR0aGlzLnR5cGUgPSAnQnVmZmVyR2VvbWV0cnknO1xyXG5cclxuXHRcdHRoaXMuaW5kZXggPSBudWxsO1xyXG5cdFx0dGhpcy5hdHRyaWJ1dGVzID0ge307XHJcblxyXG5cdFx0dGhpcy5tb3JwaEF0dHJpYnV0ZXMgPSB7fTtcclxuXHRcdHRoaXMubW9ycGhUYXJnZXRzUmVsYXRpdmUgPSBmYWxzZTtcclxuXHJcblx0XHR0aGlzLmdyb3VwcyA9IFtdO1xyXG5cclxuXHRcdHRoaXMuYm91bmRpbmdCb3ggPSBudWxsO1xyXG5cdFx0dGhpcy5ib3VuZGluZ1NwaGVyZSA9IG51bGw7XHJcblxyXG5cdFx0dGhpcy5kcmF3UmFuZ2UgPSB7IHN0YXJ0OiAwLCBjb3VudDogSW5maW5pdHkgfTtcclxuXHJcblx0XHR0aGlzLnVzZXJEYXRhID0ge307XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0SW5kZXgoKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuaW5kZXg7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0SW5kZXgoIGluZGV4ICkge1xyXG5cclxuXHRcdGlmICggQXJyYXkuaXNBcnJheSggaW5kZXggKSApIHtcclxuXHJcblx0XHRcdHRoaXMuaW5kZXggPSBuZXcgKCBhcnJheU5lZWRzVWludDMyKCBpbmRleCApID8gVWludDMyQnVmZmVyQXR0cmlidXRlIDogVWludDE2QnVmZmVyQXR0cmlidXRlICkoIGluZGV4LCAxICk7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdHRoaXMuaW5kZXggPSBpbmRleDtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0QXR0cmlidXRlKCBuYW1lICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLmF0dHJpYnV0ZXNbIG5hbWUgXTtcclxuXHJcblx0fVxyXG5cclxuXHRzZXRBdHRyaWJ1dGUoIG5hbWUsIGF0dHJpYnV0ZSApIHtcclxuXHJcblx0XHR0aGlzLmF0dHJpYnV0ZXNbIG5hbWUgXSA9IGF0dHJpYnV0ZTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRkZWxldGVBdHRyaWJ1dGUoIG5hbWUgKSB7XHJcblxyXG5cdFx0ZGVsZXRlIHRoaXMuYXR0cmlidXRlc1sgbmFtZSBdO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGhhc0F0dHJpYnV0ZSggbmFtZSApIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5hdHRyaWJ1dGVzWyBuYW1lIF0gIT09IHVuZGVmaW5lZDtcclxuXHJcblx0fVxyXG5cclxuXHRhZGRHcm91cCggc3RhcnQsIGNvdW50LCBtYXRlcmlhbEluZGV4ID0gMCApIHtcclxuXHJcblx0XHR0aGlzLmdyb3Vwcy5wdXNoKCB7XHJcblxyXG5cdFx0XHRzdGFydDogc3RhcnQsXHJcblx0XHRcdGNvdW50OiBjb3VudCxcclxuXHRcdFx0bWF0ZXJpYWxJbmRleDogbWF0ZXJpYWxJbmRleFxyXG5cclxuXHRcdH0gKTtcclxuXHJcblx0fVxyXG5cclxuXHRjbGVhckdyb3VwcygpIHtcclxuXHJcblx0XHR0aGlzLmdyb3VwcyA9IFtdO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldERyYXdSYW5nZSggc3RhcnQsIGNvdW50ICkge1xyXG5cclxuXHRcdHRoaXMuZHJhd1JhbmdlLnN0YXJ0ID0gc3RhcnQ7XHJcblx0XHR0aGlzLmRyYXdSYW5nZS5jb3VudCA9IGNvdW50O1xyXG5cclxuXHR9XHJcblxyXG5cdGFwcGx5TWF0cml4NCggbWF0cml4ICkge1xyXG5cclxuXHRcdGNvbnN0IHBvc2l0aW9uID0gdGhpcy5hdHRyaWJ1dGVzLnBvc2l0aW9uO1xyXG5cclxuXHRcdGlmICggcG9zaXRpb24gIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdHBvc2l0aW9uLmFwcGx5TWF0cml4NCggbWF0cml4ICk7XHJcblxyXG5cdFx0XHRwb3NpdGlvbi5uZWVkc1VwZGF0ZSA9IHRydWU7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGNvbnN0IG5vcm1hbCA9IHRoaXMuYXR0cmlidXRlcy5ub3JtYWw7XHJcblxyXG5cdFx0aWYgKCBub3JtYWwgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdGNvbnN0IG5vcm1hbE1hdHJpeCA9IG5ldyBNYXRyaXgzKCkuZ2V0Tm9ybWFsTWF0cml4KCBtYXRyaXggKTtcclxuXHJcblx0XHRcdG5vcm1hbC5hcHBseU5vcm1hbE1hdHJpeCggbm9ybWFsTWF0cml4ICk7XHJcblxyXG5cdFx0XHRub3JtYWwubmVlZHNVcGRhdGUgPSB0cnVlO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCB0YW5nZW50ID0gdGhpcy5hdHRyaWJ1dGVzLnRhbmdlbnQ7XHJcblxyXG5cdFx0aWYgKCB0YW5nZW50ICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHR0YW5nZW50LnRyYW5zZm9ybURpcmVjdGlvbiggbWF0cml4ICk7XHJcblxyXG5cdFx0XHR0YW5nZW50Lm5lZWRzVXBkYXRlID0gdHJ1ZTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCB0aGlzLmJvdW5kaW5nQm94ICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0dGhpcy5jb21wdXRlQm91bmRpbmdCb3goKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCB0aGlzLmJvdW5kaW5nU3BoZXJlICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0dGhpcy5jb21wdXRlQm91bmRpbmdTcGhlcmUoKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0YXBwbHlRdWF0ZXJuaW9uKCBxICkge1xyXG5cclxuXHRcdF9tMS5tYWtlUm90YXRpb25Gcm9tUXVhdGVybmlvbiggcSApO1xyXG5cclxuXHRcdHRoaXMuYXBwbHlNYXRyaXg0KCBfbTEgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRyb3RhdGVYKCBhbmdsZSApIHtcclxuXHJcblx0XHQvLyByb3RhdGUgZ2VvbWV0cnkgYXJvdW5kIHdvcmxkIHgtYXhpc1xyXG5cclxuXHRcdF9tMS5tYWtlUm90YXRpb25YKCBhbmdsZSApO1xyXG5cclxuXHRcdHRoaXMuYXBwbHlNYXRyaXg0KCBfbTEgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRyb3RhdGVZKCBhbmdsZSApIHtcclxuXHJcblx0XHQvLyByb3RhdGUgZ2VvbWV0cnkgYXJvdW5kIHdvcmxkIHktYXhpc1xyXG5cclxuXHRcdF9tMS5tYWtlUm90YXRpb25ZKCBhbmdsZSApO1xyXG5cclxuXHRcdHRoaXMuYXBwbHlNYXRyaXg0KCBfbTEgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRyb3RhdGVaKCBhbmdsZSApIHtcclxuXHJcblx0XHQvLyByb3RhdGUgZ2VvbWV0cnkgYXJvdW5kIHdvcmxkIHotYXhpc1xyXG5cclxuXHRcdF9tMS5tYWtlUm90YXRpb25aKCBhbmdsZSApO1xyXG5cclxuXHRcdHRoaXMuYXBwbHlNYXRyaXg0KCBfbTEgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHR0cmFuc2xhdGUoIHgsIHksIHogKSB7XHJcblxyXG5cdFx0Ly8gdHJhbnNsYXRlIGdlb21ldHJ5XHJcblxyXG5cdFx0X20xLm1ha2VUcmFuc2xhdGlvbiggeCwgeSwgeiApO1xyXG5cclxuXHRcdHRoaXMuYXBwbHlNYXRyaXg0KCBfbTEgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzY2FsZSggeCwgeSwgeiApIHtcclxuXHJcblx0XHQvLyBzY2FsZSBnZW9tZXRyeVxyXG5cclxuXHRcdF9tMS5tYWtlU2NhbGUoIHgsIHksIHogKTtcclxuXHJcblx0XHR0aGlzLmFwcGx5TWF0cml4NCggX20xICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0bG9va0F0KCB2ZWN0b3IgKSB7XHJcblxyXG5cdFx0X29iai5sb29rQXQoIHZlY3RvciApO1xyXG5cclxuXHRcdF9vYmoudXBkYXRlTWF0cml4KCk7XHJcblxyXG5cdFx0dGhpcy5hcHBseU1hdHJpeDQoIF9vYmoubWF0cml4ICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Y2VudGVyKCkge1xyXG5cclxuXHRcdHRoaXMuY29tcHV0ZUJvdW5kaW5nQm94KCk7XHJcblxyXG5cdFx0dGhpcy5ib3VuZGluZ0JveC5nZXRDZW50ZXIoIF9vZmZzZXQgKS5uZWdhdGUoKTtcclxuXHJcblx0XHR0aGlzLnRyYW5zbGF0ZSggX29mZnNldC54LCBfb2Zmc2V0LnksIF9vZmZzZXQueiApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldEZyb21Qb2ludHMoIHBvaW50cyApIHtcclxuXHJcblx0XHRjb25zdCBwb3NpdGlvbiA9IFtdO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IHBvaW50cy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0Y29uc3QgcG9pbnQgPSBwb2ludHNbIGkgXTtcclxuXHRcdFx0cG9zaXRpb24ucHVzaCggcG9pbnQueCwgcG9pbnQueSwgcG9pbnQueiB8fCAwICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMuc2V0QXR0cmlidXRlKCAncG9zaXRpb24nLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggcG9zaXRpb24sIDMgKSApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGNvbXB1dGVCb3VuZGluZ0JveCgpIHtcclxuXHJcblx0XHRpZiAoIHRoaXMuYm91bmRpbmdCb3ggPT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHR0aGlzLmJvdW5kaW5nQm94ID0gbmV3IEJveDMoKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Y29uc3QgcG9zaXRpb24gPSB0aGlzLmF0dHJpYnV0ZXMucG9zaXRpb247XHJcblx0XHRjb25zdCBtb3JwaEF0dHJpYnV0ZXNQb3NpdGlvbiA9IHRoaXMubW9ycGhBdHRyaWJ1dGVzLnBvc2l0aW9uO1xyXG5cclxuXHRcdGlmICggcG9zaXRpb24gJiYgcG9zaXRpb24uaXNHTEJ1ZmZlckF0dHJpYnV0ZSApIHtcclxuXHJcblx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5CdWZmZXJHZW9tZXRyeS5jb21wdXRlQm91bmRpbmdCb3goKTogR0xCdWZmZXJBdHRyaWJ1dGUgcmVxdWlyZXMgYSBtYW51YWwgYm91bmRpbmcgYm94LiBBbHRlcm5hdGl2ZWx5IHNldCBcIm1lc2guZnJ1c3R1bUN1bGxlZFwiIHRvIFwiZmFsc2VcIi4nLCB0aGlzICk7XHJcblxyXG5cdFx0XHR0aGlzLmJvdW5kaW5nQm94LnNldChcclxuXHRcdFx0XHRuZXcgVmVjdG9yMyggLSBJbmZpbml0eSwgLSBJbmZpbml0eSwgLSBJbmZpbml0eSApLFxyXG5cdFx0XHRcdG5ldyBWZWN0b3IzKCArIEluZmluaXR5LCArIEluZmluaXR5LCArIEluZmluaXR5IClcclxuXHRcdFx0KTtcclxuXHJcblx0XHRcdHJldHVybjtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBwb3NpdGlvbiAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0dGhpcy5ib3VuZGluZ0JveC5zZXRGcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbiApO1xyXG5cclxuXHRcdFx0Ly8gcHJvY2VzcyBtb3JwaCBhdHRyaWJ1dGVzIGlmIHByZXNlbnRcclxuXHJcblx0XHRcdGlmICggbW9ycGhBdHRyaWJ1dGVzUG9zaXRpb24gKSB7XHJcblxyXG5cdFx0XHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSBtb3JwaEF0dHJpYnV0ZXNQb3NpdGlvbi5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0XHRjb25zdCBtb3JwaEF0dHJpYnV0ZSA9IG1vcnBoQXR0cmlidXRlc1Bvc2l0aW9uWyBpIF07XHJcblx0XHRcdFx0XHRfYm94LnNldEZyb21CdWZmZXJBdHRyaWJ1dGUoIG1vcnBoQXR0cmlidXRlICk7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCB0aGlzLm1vcnBoVGFyZ2V0c1JlbGF0aXZlICkge1xyXG5cclxuXHRcdFx0XHRcdFx0X3ZlY3Rvci5hZGRWZWN0b3JzKCB0aGlzLmJvdW5kaW5nQm94Lm1pbiwgX2JveC5taW4gKTtcclxuXHRcdFx0XHRcdFx0dGhpcy5ib3VuZGluZ0JveC5leHBhbmRCeVBvaW50KCBfdmVjdG9yICk7XHJcblxyXG5cdFx0XHRcdFx0XHRfdmVjdG9yLmFkZFZlY3RvcnMoIHRoaXMuYm91bmRpbmdCb3gubWF4LCBfYm94Lm1heCApO1xyXG5cdFx0XHRcdFx0XHR0aGlzLmJvdW5kaW5nQm94LmV4cGFuZEJ5UG9pbnQoIF92ZWN0b3IgKTtcclxuXHJcblx0XHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdFx0dGhpcy5ib3VuZGluZ0JveC5leHBhbmRCeVBvaW50KCBfYm94Lm1pbiApO1xyXG5cdFx0XHRcdFx0XHR0aGlzLmJvdW5kaW5nQm94LmV4cGFuZEJ5UG9pbnQoIF9ib3gubWF4ICk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdHRoaXMuYm91bmRpbmdCb3gubWFrZUVtcHR5KCk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggaXNOYU4oIHRoaXMuYm91bmRpbmdCb3gubWluLnggKSB8fCBpc05hTiggdGhpcy5ib3VuZGluZ0JveC5taW4ueSApIHx8IGlzTmFOKCB0aGlzLmJvdW5kaW5nQm94Lm1pbi56ICkgKSB7XHJcblxyXG5cdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuQnVmZmVyR2VvbWV0cnkuY29tcHV0ZUJvdW5kaW5nQm94KCk6IENvbXB1dGVkIG1pbi9tYXggaGF2ZSBOYU4gdmFsdWVzLiBUaGUgXCJwb3NpdGlvblwiIGF0dHJpYnV0ZSBpcyBsaWtlbHkgdG8gaGF2ZSBOYU4gdmFsdWVzLicsIHRoaXMgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0Y29tcHV0ZUJvdW5kaW5nU3BoZXJlKCkge1xyXG5cclxuXHRcdGlmICggdGhpcy5ib3VuZGluZ1NwaGVyZSA9PT0gbnVsbCApIHtcclxuXHJcblx0XHRcdHRoaXMuYm91bmRpbmdTcGhlcmUgPSBuZXcgU3BoZXJlKCk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGNvbnN0IHBvc2l0aW9uID0gdGhpcy5hdHRyaWJ1dGVzLnBvc2l0aW9uO1xyXG5cdFx0Y29uc3QgbW9ycGhBdHRyaWJ1dGVzUG9zaXRpb24gPSB0aGlzLm1vcnBoQXR0cmlidXRlcy5wb3NpdGlvbjtcclxuXHJcblx0XHRpZiAoIHBvc2l0aW9uICYmIHBvc2l0aW9uLmlzR0xCdWZmZXJBdHRyaWJ1dGUgKSB7XHJcblxyXG5cdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuQnVmZmVyR2VvbWV0cnkuY29tcHV0ZUJvdW5kaW5nU3BoZXJlKCk6IEdMQnVmZmVyQXR0cmlidXRlIHJlcXVpcmVzIGEgbWFudWFsIGJvdW5kaW5nIHNwaGVyZS4gQWx0ZXJuYXRpdmVseSBzZXQgXCJtZXNoLmZydXN0dW1DdWxsZWRcIiB0byBcImZhbHNlXCIuJywgdGhpcyApO1xyXG5cclxuXHRcdFx0dGhpcy5ib3VuZGluZ1NwaGVyZS5zZXQoIG5ldyBWZWN0b3IzKCksIEluZmluaXR5ICk7XHJcblxyXG5cdFx0XHRyZXR1cm47XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggcG9zaXRpb24gKSB7XHJcblxyXG5cdFx0XHQvLyBmaXJzdCwgZmluZCB0aGUgY2VudGVyIG9mIHRoZSBib3VuZGluZyBzcGhlcmVcclxuXHJcblx0XHRcdGNvbnN0IGNlbnRlciA9IHRoaXMuYm91bmRpbmdTcGhlcmUuY2VudGVyO1xyXG5cclxuXHRcdFx0X2JveC5zZXRGcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbiApO1xyXG5cclxuXHRcdFx0Ly8gcHJvY2VzcyBtb3JwaCBhdHRyaWJ1dGVzIGlmIHByZXNlbnRcclxuXHJcblx0XHRcdGlmICggbW9ycGhBdHRyaWJ1dGVzUG9zaXRpb24gKSB7XHJcblxyXG5cdFx0XHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSBtb3JwaEF0dHJpYnV0ZXNQb3NpdGlvbi5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0XHRjb25zdCBtb3JwaEF0dHJpYnV0ZSA9IG1vcnBoQXR0cmlidXRlc1Bvc2l0aW9uWyBpIF07XHJcblx0XHRcdFx0XHRfYm94TW9ycGhUYXJnZXRzLnNldEZyb21CdWZmZXJBdHRyaWJ1dGUoIG1vcnBoQXR0cmlidXRlICk7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCB0aGlzLm1vcnBoVGFyZ2V0c1JlbGF0aXZlICkge1xyXG5cclxuXHRcdFx0XHRcdFx0X3ZlY3Rvci5hZGRWZWN0b3JzKCBfYm94Lm1pbiwgX2JveE1vcnBoVGFyZ2V0cy5taW4gKTtcclxuXHRcdFx0XHRcdFx0X2JveC5leHBhbmRCeVBvaW50KCBfdmVjdG9yICk7XHJcblxyXG5cdFx0XHRcdFx0XHRfdmVjdG9yLmFkZFZlY3RvcnMoIF9ib3gubWF4LCBfYm94TW9ycGhUYXJnZXRzLm1heCApO1xyXG5cdFx0XHRcdFx0XHRfYm94LmV4cGFuZEJ5UG9pbnQoIF92ZWN0b3IgKTtcclxuXHJcblx0XHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdFx0X2JveC5leHBhbmRCeVBvaW50KCBfYm94TW9ycGhUYXJnZXRzLm1pbiApO1xyXG5cdFx0XHRcdFx0XHRfYm94LmV4cGFuZEJ5UG9pbnQoIF9ib3hNb3JwaFRhcmdldHMubWF4ICk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRfYm94LmdldENlbnRlciggY2VudGVyICk7XHJcblxyXG5cdFx0XHQvLyBzZWNvbmQsIHRyeSB0byBmaW5kIGEgYm91bmRpbmdTcGhlcmUgd2l0aCBhIHJhZGl1cyBzbWFsbGVyIHRoYW4gdGhlXHJcblx0XHRcdC8vIGJvdW5kaW5nU3BoZXJlIG9mIHRoZSBib3VuZGluZ0JveDogc3FydCgzKSBzbWFsbGVyIGluIHRoZSBiZXN0IGNhc2VcclxuXHJcblx0XHRcdGxldCBtYXhSYWRpdXNTcSA9IDA7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gcG9zaXRpb24uY291bnQ7IGkgPCBpbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0X3ZlY3Rvci5mcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbiwgaSApO1xyXG5cclxuXHRcdFx0XHRtYXhSYWRpdXNTcSA9IE1hdGgubWF4KCBtYXhSYWRpdXNTcSwgY2VudGVyLmRpc3RhbmNlVG9TcXVhcmVkKCBfdmVjdG9yICkgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdC8vIHByb2Nlc3MgbW9ycGggYXR0cmlidXRlcyBpZiBwcmVzZW50XHJcblxyXG5cdFx0XHRpZiAoIG1vcnBoQXR0cmlidXRlc1Bvc2l0aW9uICkge1xyXG5cclxuXHRcdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gbW9ycGhBdHRyaWJ1dGVzUG9zaXRpb24ubGVuZ3RoOyBpIDwgaWw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgbW9ycGhBdHRyaWJ1dGUgPSBtb3JwaEF0dHJpYnV0ZXNQb3NpdGlvblsgaSBdO1xyXG5cdFx0XHRcdFx0Y29uc3QgbW9ycGhUYXJnZXRzUmVsYXRpdmUgPSB0aGlzLm1vcnBoVGFyZ2V0c1JlbGF0aXZlO1xyXG5cclxuXHRcdFx0XHRcdGZvciAoIGxldCBqID0gMCwgamwgPSBtb3JwaEF0dHJpYnV0ZS5jb3VudDsgaiA8IGpsOyBqICsrICkge1xyXG5cclxuXHRcdFx0XHRcdFx0X3ZlY3Rvci5mcm9tQnVmZmVyQXR0cmlidXRlKCBtb3JwaEF0dHJpYnV0ZSwgaiApO1xyXG5cclxuXHRcdFx0XHRcdFx0aWYgKCBtb3JwaFRhcmdldHNSZWxhdGl2ZSApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0X29mZnNldC5mcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbiwgaiApO1xyXG5cdFx0XHRcdFx0XHRcdF92ZWN0b3IuYWRkKCBfb2Zmc2V0ICk7XHJcblxyXG5cdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0XHRtYXhSYWRpdXNTcSA9IE1hdGgubWF4KCBtYXhSYWRpdXNTcSwgY2VudGVyLmRpc3RhbmNlVG9TcXVhcmVkKCBfdmVjdG9yICkgKTtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHRoaXMuYm91bmRpbmdTcGhlcmUucmFkaXVzID0gTWF0aC5zcXJ0KCBtYXhSYWRpdXNTcSApO1xyXG5cclxuXHRcdFx0aWYgKCBpc05hTiggdGhpcy5ib3VuZGluZ1NwaGVyZS5yYWRpdXMgKSApIHtcclxuXHJcblx0XHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLkJ1ZmZlckdlb21ldHJ5LmNvbXB1dGVCb3VuZGluZ1NwaGVyZSgpOiBDb21wdXRlZCByYWRpdXMgaXMgTmFOLiBUaGUgXCJwb3NpdGlvblwiIGF0dHJpYnV0ZSBpcyBsaWtlbHkgdG8gaGF2ZSBOYU4gdmFsdWVzLicsIHRoaXMgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0Y29tcHV0ZVRhbmdlbnRzKCkge1xyXG5cclxuXHRcdGNvbnN0IGluZGV4ID0gdGhpcy5pbmRleDtcclxuXHRcdGNvbnN0IGF0dHJpYnV0ZXMgPSB0aGlzLmF0dHJpYnV0ZXM7XHJcblxyXG5cdFx0Ly8gYmFzZWQgb24gaHR0cDovL3d3dy50ZXJhdGhvbi5jb20vY29kZS90YW5nZW50Lmh0bWxcclxuXHRcdC8vIChwZXIgdmVydGV4IHRhbmdlbnRzKVxyXG5cclxuXHRcdGlmICggaW5kZXggPT09IG51bGwgfHxcclxuXHRcdFx0IGF0dHJpYnV0ZXMucG9zaXRpb24gPT09IHVuZGVmaW5lZCB8fFxyXG5cdFx0XHQgYXR0cmlidXRlcy5ub3JtYWwgPT09IHVuZGVmaW5lZCB8fFxyXG5cdFx0XHQgYXR0cmlidXRlcy51diA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLkJ1ZmZlckdlb21ldHJ5OiAuY29tcHV0ZVRhbmdlbnRzKCkgZmFpbGVkLiBNaXNzaW5nIHJlcXVpcmVkIGF0dHJpYnV0ZXMgKGluZGV4LCBwb3NpdGlvbiwgbm9ybWFsIG9yIHV2KScgKTtcclxuXHRcdFx0cmV0dXJuO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCBpbmRpY2VzID0gaW5kZXguYXJyYXk7XHJcblx0XHRjb25zdCBwb3NpdGlvbnMgPSBhdHRyaWJ1dGVzLnBvc2l0aW9uLmFycmF5O1xyXG5cdFx0Y29uc3Qgbm9ybWFscyA9IGF0dHJpYnV0ZXMubm9ybWFsLmFycmF5O1xyXG5cdFx0Y29uc3QgdXZzID0gYXR0cmlidXRlcy51di5hcnJheTtcclxuXHJcblx0XHRjb25zdCBuVmVydGljZXMgPSBwb3NpdGlvbnMubGVuZ3RoIC8gMztcclxuXHJcblx0XHRpZiAoIHRoaXMuaGFzQXR0cmlidXRlKCAndGFuZ2VudCcgKSA9PT0gZmFsc2UgKSB7XHJcblxyXG5cdFx0XHR0aGlzLnNldEF0dHJpYnV0ZSggJ3RhbmdlbnQnLCBuZXcgQnVmZmVyQXR0cmlidXRlKCBuZXcgRmxvYXQzMkFycmF5KCA0ICogblZlcnRpY2VzICksIDQgKSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCB0YW5nZW50cyA9IHRoaXMuZ2V0QXR0cmlidXRlKCAndGFuZ2VudCcgKS5hcnJheTtcclxuXHJcblx0XHRjb25zdCB0YW4xID0gW10sIHRhbjIgPSBbXTtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBuVmVydGljZXM7IGkgKysgKSB7XHJcblxyXG5cdFx0XHR0YW4xWyBpIF0gPSBuZXcgVmVjdG9yMygpO1xyXG5cdFx0XHR0YW4yWyBpIF0gPSBuZXcgVmVjdG9yMygpO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCB2QSA9IG5ldyBWZWN0b3IzKCksXHJcblx0XHRcdHZCID0gbmV3IFZlY3RvcjMoKSxcclxuXHRcdFx0dkMgPSBuZXcgVmVjdG9yMygpLFxyXG5cclxuXHRcdFx0dXZBID0gbmV3IFZlY3RvcjIoKSxcclxuXHRcdFx0dXZCID0gbmV3IFZlY3RvcjIoKSxcclxuXHRcdFx0dXZDID0gbmV3IFZlY3RvcjIoKSxcclxuXHJcblx0XHRcdHNkaXIgPSBuZXcgVmVjdG9yMygpLFxyXG5cdFx0XHR0ZGlyID0gbmV3IFZlY3RvcjMoKTtcclxuXHJcblx0XHRmdW5jdGlvbiBoYW5kbGVUcmlhbmdsZSggYSwgYiwgYyApIHtcclxuXHJcblx0XHRcdHZBLmZyb21BcnJheSggcG9zaXRpb25zLCBhICogMyApO1xyXG5cdFx0XHR2Qi5mcm9tQXJyYXkoIHBvc2l0aW9ucywgYiAqIDMgKTtcclxuXHRcdFx0dkMuZnJvbUFycmF5KCBwb3NpdGlvbnMsIGMgKiAzICk7XHJcblxyXG5cdFx0XHR1dkEuZnJvbUFycmF5KCB1dnMsIGEgKiAyICk7XHJcblx0XHRcdHV2Qi5mcm9tQXJyYXkoIHV2cywgYiAqIDIgKTtcclxuXHRcdFx0dXZDLmZyb21BcnJheSggdXZzLCBjICogMiApO1xyXG5cclxuXHRcdFx0dkIuc3ViKCB2QSApO1xyXG5cdFx0XHR2Qy5zdWIoIHZBICk7XHJcblxyXG5cdFx0XHR1dkIuc3ViKCB1dkEgKTtcclxuXHRcdFx0dXZDLnN1YiggdXZBICk7XHJcblxyXG5cdFx0XHRjb25zdCByID0gMS4wIC8gKCB1dkIueCAqIHV2Qy55IC0gdXZDLnggKiB1dkIueSApO1xyXG5cclxuXHRcdFx0Ly8gc2lsZW50bHkgaWdub3JlIGRlZ2VuZXJhdGUgdXYgdHJpYW5nbGVzIGhhdmluZyBjb2luY2lkZW50IG9yIGNvbGluZWFyIHZlcnRpY2VzXHJcblxyXG5cdFx0XHRpZiAoICEgaXNGaW5pdGUoIHIgKSApIHJldHVybjtcclxuXHJcblx0XHRcdHNkaXIuY29weSggdkIgKS5tdWx0aXBseVNjYWxhciggdXZDLnkgKS5hZGRTY2FsZWRWZWN0b3IoIHZDLCAtIHV2Qi55ICkubXVsdGlwbHlTY2FsYXIoIHIgKTtcclxuXHRcdFx0dGRpci5jb3B5KCB2QyApLm11bHRpcGx5U2NhbGFyKCB1dkIueCApLmFkZFNjYWxlZFZlY3RvciggdkIsIC0gdXZDLnggKS5tdWx0aXBseVNjYWxhciggciApO1xyXG5cclxuXHRcdFx0dGFuMVsgYSBdLmFkZCggc2RpciApO1xyXG5cdFx0XHR0YW4xWyBiIF0uYWRkKCBzZGlyICk7XHJcblx0XHRcdHRhbjFbIGMgXS5hZGQoIHNkaXIgKTtcclxuXHJcblx0XHRcdHRhbjJbIGEgXS5hZGQoIHRkaXIgKTtcclxuXHRcdFx0dGFuMlsgYiBdLmFkZCggdGRpciApO1xyXG5cdFx0XHR0YW4yWyBjIF0uYWRkKCB0ZGlyICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGxldCBncm91cHMgPSB0aGlzLmdyb3VwcztcclxuXHJcblx0XHRpZiAoIGdyb3Vwcy5sZW5ndGggPT09IDAgKSB7XHJcblxyXG5cdFx0XHRncm91cHMgPSBbIHtcclxuXHRcdFx0XHRzdGFydDogMCxcclxuXHRcdFx0XHRjb3VudDogaW5kaWNlcy5sZW5ndGhcclxuXHRcdFx0fSBdO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gZ3JvdXBzLmxlbmd0aDsgaSA8IGlsOyArKyBpICkge1xyXG5cclxuXHRcdFx0Y29uc3QgZ3JvdXAgPSBncm91cHNbIGkgXTtcclxuXHJcblx0XHRcdGNvbnN0IHN0YXJ0ID0gZ3JvdXAuc3RhcnQ7XHJcblx0XHRcdGNvbnN0IGNvdW50ID0gZ3JvdXAuY291bnQ7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaiA9IHN0YXJ0LCBqbCA9IHN0YXJ0ICsgY291bnQ7IGogPCBqbDsgaiArPSAzICkge1xyXG5cclxuXHRcdFx0XHRoYW5kbGVUcmlhbmdsZShcclxuXHRcdFx0XHRcdGluZGljZXNbIGogKyAwIF0sXHJcblx0XHRcdFx0XHRpbmRpY2VzWyBqICsgMSBdLFxyXG5cdFx0XHRcdFx0aW5kaWNlc1sgaiArIDIgXVxyXG5cdFx0XHRcdCk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGNvbnN0IHRtcCA9IG5ldyBWZWN0b3IzKCksIHRtcDIgPSBuZXcgVmVjdG9yMygpO1xyXG5cdFx0Y29uc3QgbiA9IG5ldyBWZWN0b3IzKCksIG4yID0gbmV3IFZlY3RvcjMoKTtcclxuXHJcblx0XHRmdW5jdGlvbiBoYW5kbGVWZXJ0ZXgoIHYgKSB7XHJcblxyXG5cdFx0XHRuLmZyb21BcnJheSggbm9ybWFscywgdiAqIDMgKTtcclxuXHRcdFx0bjIuY29weSggbiApO1xyXG5cclxuXHRcdFx0Y29uc3QgdCA9IHRhbjFbIHYgXTtcclxuXHJcblx0XHRcdC8vIEdyYW0tU2NobWlkdCBvcnRob2dvbmFsaXplXHJcblxyXG5cdFx0XHR0bXAuY29weSggdCApO1xyXG5cdFx0XHR0bXAuc3ViKCBuLm11bHRpcGx5U2NhbGFyKCBuLmRvdCggdCApICkgKS5ub3JtYWxpemUoKTtcclxuXHJcblx0XHRcdC8vIENhbGN1bGF0ZSBoYW5kZWRuZXNzXHJcblxyXG5cdFx0XHR0bXAyLmNyb3NzVmVjdG9ycyggbjIsIHQgKTtcclxuXHRcdFx0Y29uc3QgdGVzdCA9IHRtcDIuZG90KCB0YW4yWyB2IF0gKTtcclxuXHRcdFx0Y29uc3QgdyA9ICggdGVzdCA8IDAuMCApID8gLSAxLjAgOiAxLjA7XHJcblxyXG5cdFx0XHR0YW5nZW50c1sgdiAqIDQgXSA9IHRtcC54O1xyXG5cdFx0XHR0YW5nZW50c1sgdiAqIDQgKyAxIF0gPSB0bXAueTtcclxuXHRcdFx0dGFuZ2VudHNbIHYgKiA0ICsgMiBdID0gdG1wLno7XHJcblx0XHRcdHRhbmdlbnRzWyB2ICogNCArIDMgXSA9IHc7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSBncm91cHMubGVuZ3RoOyBpIDwgaWw7ICsrIGkgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBncm91cCA9IGdyb3Vwc1sgaSBdO1xyXG5cclxuXHRcdFx0Y29uc3Qgc3RhcnQgPSBncm91cC5zdGFydDtcclxuXHRcdFx0Y29uc3QgY291bnQgPSBncm91cC5jb3VudDtcclxuXHJcblx0XHRcdGZvciAoIGxldCBqID0gc3RhcnQsIGpsID0gc3RhcnQgKyBjb3VudDsgaiA8IGpsOyBqICs9IDMgKSB7XHJcblxyXG5cdFx0XHRcdGhhbmRsZVZlcnRleCggaW5kaWNlc1sgaiArIDAgXSApO1xyXG5cdFx0XHRcdGhhbmRsZVZlcnRleCggaW5kaWNlc1sgaiArIDEgXSApO1xyXG5cdFx0XHRcdGhhbmRsZVZlcnRleCggaW5kaWNlc1sgaiArIDIgXSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRjb21wdXRlVmVydGV4Tm9ybWFscygpIHtcclxuXHJcblx0XHRjb25zdCBpbmRleCA9IHRoaXMuaW5kZXg7XHJcblx0XHRjb25zdCBwb3NpdGlvbkF0dHJpYnV0ZSA9IHRoaXMuZ2V0QXR0cmlidXRlKCAncG9zaXRpb24nICk7XHJcblxyXG5cdFx0aWYgKCBwb3NpdGlvbkF0dHJpYnV0ZSAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0bGV0IG5vcm1hbEF0dHJpYnV0ZSA9IHRoaXMuZ2V0QXR0cmlidXRlKCAnbm9ybWFsJyApO1xyXG5cclxuXHRcdFx0aWYgKCBub3JtYWxBdHRyaWJ1dGUgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0bm9ybWFsQXR0cmlidXRlID0gbmV3IEJ1ZmZlckF0dHJpYnV0ZSggbmV3IEZsb2F0MzJBcnJheSggcG9zaXRpb25BdHRyaWJ1dGUuY291bnQgKiAzICksIDMgKTtcclxuXHRcdFx0XHR0aGlzLnNldEF0dHJpYnV0ZSggJ25vcm1hbCcsIG5vcm1hbEF0dHJpYnV0ZSApO1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0Ly8gcmVzZXQgZXhpc3Rpbmcgbm9ybWFscyB0byB6ZXJvXHJcblxyXG5cdFx0XHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSBub3JtYWxBdHRyaWJ1dGUuY291bnQ7IGkgPCBpbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0XHRub3JtYWxBdHRyaWJ1dGUuc2V0WFlaKCBpLCAwLCAwLCAwICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGNvbnN0IHBBID0gbmV3IFZlY3RvcjMoKSwgcEIgPSBuZXcgVmVjdG9yMygpLCBwQyA9IG5ldyBWZWN0b3IzKCk7XHJcblx0XHRcdGNvbnN0IG5BID0gbmV3IFZlY3RvcjMoKSwgbkIgPSBuZXcgVmVjdG9yMygpLCBuQyA9IG5ldyBWZWN0b3IzKCk7XHJcblx0XHRcdGNvbnN0IGNiID0gbmV3IFZlY3RvcjMoKSwgYWIgPSBuZXcgVmVjdG9yMygpO1xyXG5cclxuXHRcdFx0Ly8gaW5kZXhlZCBlbGVtZW50c1xyXG5cclxuXHRcdFx0aWYgKCBpbmRleCApIHtcclxuXHJcblx0XHRcdFx0Zm9yICggbGV0IGkgPSAwLCBpbCA9IGluZGV4LmNvdW50OyBpIDwgaWw7IGkgKz0gMyApIHtcclxuXHJcblx0XHRcdFx0XHRjb25zdCB2QSA9IGluZGV4LmdldFgoIGkgKyAwICk7XHJcblx0XHRcdFx0XHRjb25zdCB2QiA9IGluZGV4LmdldFgoIGkgKyAxICk7XHJcblx0XHRcdFx0XHRjb25zdCB2QyA9IGluZGV4LmdldFgoIGkgKyAyICk7XHJcblxyXG5cdFx0XHRcdFx0cEEuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggcG9zaXRpb25BdHRyaWJ1dGUsIHZBICk7XHJcblx0XHRcdFx0XHRwQi5mcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbkF0dHJpYnV0ZSwgdkIgKTtcclxuXHRcdFx0XHRcdHBDLmZyb21CdWZmZXJBdHRyaWJ1dGUoIHBvc2l0aW9uQXR0cmlidXRlLCB2QyApO1xyXG5cclxuXHRcdFx0XHRcdGNiLnN1YlZlY3RvcnMoIHBDLCBwQiApO1xyXG5cdFx0XHRcdFx0YWIuc3ViVmVjdG9ycyggcEEsIHBCICk7XHJcblx0XHRcdFx0XHRjYi5jcm9zcyggYWIgKTtcclxuXHJcblx0XHRcdFx0XHRuQS5mcm9tQnVmZmVyQXR0cmlidXRlKCBub3JtYWxBdHRyaWJ1dGUsIHZBICk7XHJcblx0XHRcdFx0XHRuQi5mcm9tQnVmZmVyQXR0cmlidXRlKCBub3JtYWxBdHRyaWJ1dGUsIHZCICk7XHJcblx0XHRcdFx0XHRuQy5mcm9tQnVmZmVyQXR0cmlidXRlKCBub3JtYWxBdHRyaWJ1dGUsIHZDICk7XHJcblxyXG5cdFx0XHRcdFx0bkEuYWRkKCBjYiApO1xyXG5cdFx0XHRcdFx0bkIuYWRkKCBjYiApO1xyXG5cdFx0XHRcdFx0bkMuYWRkKCBjYiApO1xyXG5cclxuXHRcdFx0XHRcdG5vcm1hbEF0dHJpYnV0ZS5zZXRYWVooIHZBLCBuQS54LCBuQS55LCBuQS56ICk7XHJcblx0XHRcdFx0XHRub3JtYWxBdHRyaWJ1dGUuc2V0WFlaKCB2QiwgbkIueCwgbkIueSwgbkIueiApO1xyXG5cdFx0XHRcdFx0bm9ybWFsQXR0cmlidXRlLnNldFhZWiggdkMsIG5DLngsIG5DLnksIG5DLnogKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0Ly8gbm9uLWluZGV4ZWQgZWxlbWVudHMgKHVuY29ubmVjdGVkIHRyaWFuZ2xlIHNvdXApXHJcblxyXG5cdFx0XHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSBwb3NpdGlvbkF0dHJpYnV0ZS5jb3VudDsgaSA8IGlsOyBpICs9IDMgKSB7XHJcblxyXG5cdFx0XHRcdFx0cEEuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggcG9zaXRpb25BdHRyaWJ1dGUsIGkgKyAwICk7XHJcblx0XHRcdFx0XHRwQi5mcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbkF0dHJpYnV0ZSwgaSArIDEgKTtcclxuXHRcdFx0XHRcdHBDLmZyb21CdWZmZXJBdHRyaWJ1dGUoIHBvc2l0aW9uQXR0cmlidXRlLCBpICsgMiApO1xyXG5cclxuXHRcdFx0XHRcdGNiLnN1YlZlY3RvcnMoIHBDLCBwQiApO1xyXG5cdFx0XHRcdFx0YWIuc3ViVmVjdG9ycyggcEEsIHBCICk7XHJcblx0XHRcdFx0XHRjYi5jcm9zcyggYWIgKTtcclxuXHJcblx0XHRcdFx0XHRub3JtYWxBdHRyaWJ1dGUuc2V0WFlaKCBpICsgMCwgY2IueCwgY2IueSwgY2IueiApO1xyXG5cdFx0XHRcdFx0bm9ybWFsQXR0cmlidXRlLnNldFhZWiggaSArIDEsIGNiLngsIGNiLnksIGNiLnogKTtcclxuXHRcdFx0XHRcdG5vcm1hbEF0dHJpYnV0ZS5zZXRYWVooIGkgKyAyLCBjYi54LCBjYi55LCBjYi56ICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHRoaXMubm9ybWFsaXplTm9ybWFscygpO1xyXG5cclxuXHRcdFx0bm9ybWFsQXR0cmlidXRlLm5lZWRzVXBkYXRlID0gdHJ1ZTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0bm9ybWFsaXplTm9ybWFscygpIHtcclxuXHJcblx0XHRjb25zdCBub3JtYWxzID0gdGhpcy5hdHRyaWJ1dGVzLm5vcm1hbDtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gbm9ybWFscy5jb3VudDsgaSA8IGlsOyBpICsrICkge1xyXG5cclxuXHRcdFx0X3ZlY3Rvci5mcm9tQnVmZmVyQXR0cmlidXRlKCBub3JtYWxzLCBpICk7XHJcblxyXG5cdFx0XHRfdmVjdG9yLm5vcm1hbGl6ZSgpO1xyXG5cclxuXHRcdFx0bm9ybWFscy5zZXRYWVooIGksIF92ZWN0b3IueCwgX3ZlY3Rvci55LCBfdmVjdG9yLnogKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0dG9Ob25JbmRleGVkKCkge1xyXG5cclxuXHRcdGZ1bmN0aW9uIGNvbnZlcnRCdWZmZXJBdHRyaWJ1dGUoIGF0dHJpYnV0ZSwgaW5kaWNlcyApIHtcclxuXHJcblx0XHRcdGNvbnN0IGFycmF5ID0gYXR0cmlidXRlLmFycmF5O1xyXG5cdFx0XHRjb25zdCBpdGVtU2l6ZSA9IGF0dHJpYnV0ZS5pdGVtU2l6ZTtcclxuXHRcdFx0Y29uc3Qgbm9ybWFsaXplZCA9IGF0dHJpYnV0ZS5ub3JtYWxpemVkO1xyXG5cclxuXHRcdFx0Y29uc3QgYXJyYXkyID0gbmV3IGFycmF5LmNvbnN0cnVjdG9yKCBpbmRpY2VzLmxlbmd0aCAqIGl0ZW1TaXplICk7XHJcblxyXG5cdFx0XHRsZXQgaW5kZXggPSAwLCBpbmRleDIgPSAwO1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gaW5kaWNlcy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRpZiAoIGF0dHJpYnV0ZS5pc0ludGVybGVhdmVkQnVmZmVyQXR0cmlidXRlICkge1xyXG5cclxuXHRcdFx0XHRcdGluZGV4ID0gaW5kaWNlc1sgaSBdICogYXR0cmlidXRlLmRhdGEuc3RyaWRlICsgYXR0cmlidXRlLm9mZnNldDtcclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRpbmRleCA9IGluZGljZXNbIGkgXSAqIGl0ZW1TaXplO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdGZvciAoIGxldCBqID0gMDsgaiA8IGl0ZW1TaXplOyBqICsrICkge1xyXG5cclxuXHRcdFx0XHRcdGFycmF5MlsgaW5kZXgyICsrIF0gPSBhcnJheVsgaW5kZXggKysgXTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0cmV0dXJuIG5ldyBCdWZmZXJBdHRyaWJ1dGUoIGFycmF5MiwgaXRlbVNpemUsIG5vcm1hbGl6ZWQgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly9cclxuXHJcblx0XHRpZiAoIHRoaXMuaW5kZXggPT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5CdWZmZXJHZW9tZXRyeS50b05vbkluZGV4ZWQoKTogQnVmZmVyR2VvbWV0cnkgaXMgYWxyZWFkeSBub24taW5kZXhlZC4nICk7XHJcblx0XHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCBnZW9tZXRyeTIgPSBuZXcgQnVmZmVyR2VvbWV0cnkoKTtcclxuXHJcblx0XHRjb25zdCBpbmRpY2VzID0gdGhpcy5pbmRleC5hcnJheTtcclxuXHRcdGNvbnN0IGF0dHJpYnV0ZXMgPSB0aGlzLmF0dHJpYnV0ZXM7XHJcblxyXG5cdFx0Ly8gYXR0cmlidXRlc1xyXG5cclxuXHRcdGZvciAoIGNvbnN0IG5hbWUgaW4gYXR0cmlidXRlcyApIHtcclxuXHJcblx0XHRcdGNvbnN0IGF0dHJpYnV0ZSA9IGF0dHJpYnV0ZXNbIG5hbWUgXTtcclxuXHJcblx0XHRcdGNvbnN0IG5ld0F0dHJpYnV0ZSA9IGNvbnZlcnRCdWZmZXJBdHRyaWJ1dGUoIGF0dHJpYnV0ZSwgaW5kaWNlcyApO1xyXG5cclxuXHRcdFx0Z2VvbWV0cnkyLnNldEF0dHJpYnV0ZSggbmFtZSwgbmV3QXR0cmlidXRlICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIG1vcnBoIGF0dHJpYnV0ZXNcclxuXHJcblx0XHRjb25zdCBtb3JwaEF0dHJpYnV0ZXMgPSB0aGlzLm1vcnBoQXR0cmlidXRlcztcclxuXHJcblx0XHRmb3IgKCBjb25zdCBuYW1lIGluIG1vcnBoQXR0cmlidXRlcyApIHtcclxuXHJcblx0XHRcdGNvbnN0IG1vcnBoQXJyYXkgPSBbXTtcclxuXHRcdFx0Y29uc3QgbW9ycGhBdHRyaWJ1dGUgPSBtb3JwaEF0dHJpYnV0ZXNbIG5hbWUgXTsgLy8gbW9ycGhBdHRyaWJ1dGU6IGFycmF5IG9mIEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGVzXHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gbW9ycGhBdHRyaWJ1dGUubGVuZ3RoOyBpIDwgaWw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IGF0dHJpYnV0ZSA9IG1vcnBoQXR0cmlidXRlWyBpIF07XHJcblxyXG5cdFx0XHRcdGNvbnN0IG5ld0F0dHJpYnV0ZSA9IGNvbnZlcnRCdWZmZXJBdHRyaWJ1dGUoIGF0dHJpYnV0ZSwgaW5kaWNlcyApO1xyXG5cclxuXHRcdFx0XHRtb3JwaEFycmF5LnB1c2goIG5ld0F0dHJpYnV0ZSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Z2VvbWV0cnkyLm1vcnBoQXR0cmlidXRlc1sgbmFtZSBdID0gbW9ycGhBcnJheTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Z2VvbWV0cnkyLm1vcnBoVGFyZ2V0c1JlbGF0aXZlID0gdGhpcy5tb3JwaFRhcmdldHNSZWxhdGl2ZTtcclxuXHJcblx0XHQvLyBncm91cHNcclxuXHJcblx0XHRjb25zdCBncm91cHMgPSB0aGlzLmdyb3VwcztcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBncm91cHMubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdGNvbnN0IGdyb3VwID0gZ3JvdXBzWyBpIF07XHJcblx0XHRcdGdlb21ldHJ5Mi5hZGRHcm91cCggZ3JvdXAuc3RhcnQsIGdyb3VwLmNvdW50LCBncm91cC5tYXRlcmlhbEluZGV4ICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiBnZW9tZXRyeTI7XHJcblxyXG5cdH1cclxuXHJcblx0dG9KU09OKCkge1xyXG5cclxuXHRcdGNvbnN0IGRhdGEgPSB7XHJcblx0XHRcdG1ldGFkYXRhOiB7XHJcblx0XHRcdFx0dmVyc2lvbjogNC42LFxyXG5cdFx0XHRcdHR5cGU6ICdCdWZmZXJHZW9tZXRyeScsXHJcblx0XHRcdFx0Z2VuZXJhdG9yOiAnQnVmZmVyR2VvbWV0cnkudG9KU09OJ1xyXG5cdFx0XHR9XHJcblx0XHR9O1xyXG5cclxuXHRcdC8vIHN0YW5kYXJkIEJ1ZmZlckdlb21ldHJ5IHNlcmlhbGl6YXRpb25cclxuXHJcblx0XHRkYXRhLnV1aWQgPSB0aGlzLnV1aWQ7XHJcblx0XHRkYXRhLnR5cGUgPSB0aGlzLnR5cGU7XHJcblx0XHRpZiAoIHRoaXMubmFtZSAhPT0gJycgKSBkYXRhLm5hbWUgPSB0aGlzLm5hbWU7XHJcblx0XHRpZiAoIE9iamVjdC5rZXlzKCB0aGlzLnVzZXJEYXRhICkubGVuZ3RoID4gMCApIGRhdGEudXNlckRhdGEgPSB0aGlzLnVzZXJEYXRhO1xyXG5cclxuXHRcdGlmICggdGhpcy5wYXJhbWV0ZXJzICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBwYXJhbWV0ZXJzID0gdGhpcy5wYXJhbWV0ZXJzO1xyXG5cclxuXHRcdFx0Zm9yICggY29uc3Qga2V5IGluIHBhcmFtZXRlcnMgKSB7XHJcblxyXG5cdFx0XHRcdGlmICggcGFyYW1ldGVyc1sga2V5IF0gIT09IHVuZGVmaW5lZCApIGRhdGFbIGtleSBdID0gcGFyYW1ldGVyc1sga2V5IF07XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRyZXR1cm4gZGF0YTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gZm9yIHNpbXBsaWNpdHkgdGhlIGNvZGUgYXNzdW1lcyBhdHRyaWJ1dGVzIGFyZSBub3Qgc2hhcmVkIGFjcm9zcyBnZW9tZXRyaWVzLCBzZWUgIzE1ODExXHJcblxyXG5cdFx0ZGF0YS5kYXRhID0geyBhdHRyaWJ1dGVzOiB7fSB9O1xyXG5cclxuXHRcdGNvbnN0IGluZGV4ID0gdGhpcy5pbmRleDtcclxuXHJcblx0XHRpZiAoIGluZGV4ICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0ZGF0YS5kYXRhLmluZGV4ID0ge1xyXG5cdFx0XHRcdHR5cGU6IGluZGV4LmFycmF5LmNvbnN0cnVjdG9yLm5hbWUsXHJcblx0XHRcdFx0YXJyYXk6IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKCBpbmRleC5hcnJheSApXHJcblx0XHRcdH07XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGNvbnN0IGF0dHJpYnV0ZXMgPSB0aGlzLmF0dHJpYnV0ZXM7XHJcblxyXG5cdFx0Zm9yICggY29uc3Qga2V5IGluIGF0dHJpYnV0ZXMgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBhdHRyaWJ1dGUgPSBhdHRyaWJ1dGVzWyBrZXkgXTtcclxuXHJcblx0XHRcdGRhdGEuZGF0YS5hdHRyaWJ1dGVzWyBrZXkgXSA9IGF0dHJpYnV0ZS50b0pTT04oIGRhdGEuZGF0YSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCBtb3JwaEF0dHJpYnV0ZXMgPSB7fTtcclxuXHRcdGxldCBoYXNNb3JwaEF0dHJpYnV0ZXMgPSBmYWxzZTtcclxuXHJcblx0XHRmb3IgKCBjb25zdCBrZXkgaW4gdGhpcy5tb3JwaEF0dHJpYnV0ZXMgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBhdHRyaWJ1dGVBcnJheSA9IHRoaXMubW9ycGhBdHRyaWJ1dGVzWyBrZXkgXTtcclxuXHJcblx0XHRcdGNvbnN0IGFycmF5ID0gW107XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gYXR0cmlidXRlQXJyYXkubGVuZ3RoOyBpIDwgaWw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IGF0dHJpYnV0ZSA9IGF0dHJpYnV0ZUFycmF5WyBpIF07XHJcblxyXG5cdFx0XHRcdGFycmF5LnB1c2goIGF0dHJpYnV0ZS50b0pTT04oIGRhdGEuZGF0YSApICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRpZiAoIGFycmF5Lmxlbmd0aCA+IDAgKSB7XHJcblxyXG5cdFx0XHRcdG1vcnBoQXR0cmlidXRlc1sga2V5IF0gPSBhcnJheTtcclxuXHJcblx0XHRcdFx0aGFzTW9ycGhBdHRyaWJ1dGVzID0gdHJ1ZTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBoYXNNb3JwaEF0dHJpYnV0ZXMgKSB7XHJcblxyXG5cdFx0XHRkYXRhLmRhdGEubW9ycGhBdHRyaWJ1dGVzID0gbW9ycGhBdHRyaWJ1dGVzO1xyXG5cdFx0XHRkYXRhLmRhdGEubW9ycGhUYXJnZXRzUmVsYXRpdmUgPSB0aGlzLm1vcnBoVGFyZ2V0c1JlbGF0aXZlO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCBncm91cHMgPSB0aGlzLmdyb3VwcztcclxuXHJcblx0XHRpZiAoIGdyb3Vwcy5sZW5ndGggPiAwICkge1xyXG5cclxuXHRcdFx0ZGF0YS5kYXRhLmdyb3VwcyA9IEpTT04ucGFyc2UoIEpTT04uc3RyaW5naWZ5KCBncm91cHMgKSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCBib3VuZGluZ1NwaGVyZSA9IHRoaXMuYm91bmRpbmdTcGhlcmU7XHJcblxyXG5cdFx0aWYgKCBib3VuZGluZ1NwaGVyZSAhPT0gbnVsbCApIHtcclxuXHJcblx0XHRcdGRhdGEuZGF0YS5ib3VuZGluZ1NwaGVyZSA9IHtcclxuXHRcdFx0XHRjZW50ZXI6IGJvdW5kaW5nU3BoZXJlLmNlbnRlci50b0FycmF5KCksXHJcblx0XHRcdFx0cmFkaXVzOiBib3VuZGluZ1NwaGVyZS5yYWRpdXNcclxuXHRcdFx0fTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIGRhdGE7XHJcblxyXG5cdH1cclxuXHJcblx0Y2xvbmUoKSB7XHJcblxyXG5cdFx0cmV0dXJuIG5ldyB0aGlzLmNvbnN0cnVjdG9yKCkuY29weSggdGhpcyApO1xyXG5cclxuXHR9XHJcblxyXG5cdGNvcHkoIHNvdXJjZSApIHtcclxuXHJcblx0XHQvLyByZXNldFxyXG5cclxuXHRcdHRoaXMuaW5kZXggPSBudWxsO1xyXG5cdFx0dGhpcy5hdHRyaWJ1dGVzID0ge307XHJcblx0XHR0aGlzLm1vcnBoQXR0cmlidXRlcyA9IHt9O1xyXG5cdFx0dGhpcy5ncm91cHMgPSBbXTtcclxuXHRcdHRoaXMuYm91bmRpbmdCb3ggPSBudWxsO1xyXG5cdFx0dGhpcy5ib3VuZGluZ1NwaGVyZSA9IG51bGw7XHJcblxyXG5cdFx0Ly8gdXNlZCBmb3Igc3RvcmluZyBjbG9uZWQsIHNoYXJlZCBkYXRhXHJcblxyXG5cdFx0Y29uc3QgZGF0YSA9IHt9O1xyXG5cclxuXHRcdC8vIG5hbWVcclxuXHJcblx0XHR0aGlzLm5hbWUgPSBzb3VyY2UubmFtZTtcclxuXHJcblx0XHQvLyBpbmRleFxyXG5cclxuXHRcdGNvbnN0IGluZGV4ID0gc291cmNlLmluZGV4O1xyXG5cclxuXHRcdGlmICggaW5kZXggIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHR0aGlzLnNldEluZGV4KCBpbmRleC5jbG9uZSggZGF0YSApICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIGF0dHJpYnV0ZXNcclxuXHJcblx0XHRjb25zdCBhdHRyaWJ1dGVzID0gc291cmNlLmF0dHJpYnV0ZXM7XHJcblxyXG5cdFx0Zm9yICggY29uc3QgbmFtZSBpbiBhdHRyaWJ1dGVzICkge1xyXG5cclxuXHRcdFx0Y29uc3QgYXR0cmlidXRlID0gYXR0cmlidXRlc1sgbmFtZSBdO1xyXG5cdFx0XHR0aGlzLnNldEF0dHJpYnV0ZSggbmFtZSwgYXR0cmlidXRlLmNsb25lKCBkYXRhICkgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gbW9ycGggYXR0cmlidXRlc1xyXG5cclxuXHRcdGNvbnN0IG1vcnBoQXR0cmlidXRlcyA9IHNvdXJjZS5tb3JwaEF0dHJpYnV0ZXM7XHJcblxyXG5cdFx0Zm9yICggY29uc3QgbmFtZSBpbiBtb3JwaEF0dHJpYnV0ZXMgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBhcnJheSA9IFtdO1xyXG5cdFx0XHRjb25zdCBtb3JwaEF0dHJpYnV0ZSA9IG1vcnBoQXR0cmlidXRlc1sgbmFtZSBdOyAvLyBtb3JwaEF0dHJpYnV0ZTogYXJyYXkgb2YgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZXNcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMCwgbCA9IG1vcnBoQXR0cmlidXRlLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdGFycmF5LnB1c2goIG1vcnBoQXR0cmlidXRlWyBpIF0uY2xvbmUoIGRhdGEgKSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0dGhpcy5tb3JwaEF0dHJpYnV0ZXNbIG5hbWUgXSA9IGFycmF5O1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLm1vcnBoVGFyZ2V0c1JlbGF0aXZlID0gc291cmNlLm1vcnBoVGFyZ2V0c1JlbGF0aXZlO1xyXG5cclxuXHRcdC8vIGdyb3Vwc1xyXG5cclxuXHRcdGNvbnN0IGdyb3VwcyA9IHNvdXJjZS5ncm91cHM7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gZ3JvdXBzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBncm91cCA9IGdyb3Vwc1sgaSBdO1xyXG5cdFx0XHR0aGlzLmFkZEdyb3VwKCBncm91cC5zdGFydCwgZ3JvdXAuY291bnQsIGdyb3VwLm1hdGVyaWFsSW5kZXggKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gYm91bmRpbmcgYm94XHJcblxyXG5cdFx0Y29uc3QgYm91bmRpbmdCb3ggPSBzb3VyY2UuYm91bmRpbmdCb3g7XHJcblxyXG5cdFx0aWYgKCBib3VuZGluZ0JveCAhPT0gbnVsbCApIHtcclxuXHJcblx0XHRcdHRoaXMuYm91bmRpbmdCb3ggPSBib3VuZGluZ0JveC5jbG9uZSgpO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvLyBib3VuZGluZyBzcGhlcmVcclxuXHJcblx0XHRjb25zdCBib3VuZGluZ1NwaGVyZSA9IHNvdXJjZS5ib3VuZGluZ1NwaGVyZTtcclxuXHJcblx0XHRpZiAoIGJvdW5kaW5nU3BoZXJlICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0dGhpcy5ib3VuZGluZ1NwaGVyZSA9IGJvdW5kaW5nU3BoZXJlLmNsb25lKCk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIGRyYXcgcmFuZ2VcclxuXHJcblx0XHR0aGlzLmRyYXdSYW5nZS5zdGFydCA9IHNvdXJjZS5kcmF3UmFuZ2Uuc3RhcnQ7XHJcblx0XHR0aGlzLmRyYXdSYW5nZS5jb3VudCA9IHNvdXJjZS5kcmF3UmFuZ2UuY291bnQ7XHJcblxyXG5cdFx0Ly8gdXNlciBkYXRhXHJcblxyXG5cdFx0dGhpcy51c2VyRGF0YSA9IHNvdXJjZS51c2VyRGF0YTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRkaXNwb3NlKCkge1xyXG5cclxuXHRcdHRoaXMuZGlzcGF0Y2hFdmVudCggeyB0eXBlOiAnZGlzcG9zZScgfSApO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBCdWZmZXJHZW9tZXRyeSB9O1xyXG4iLCJpbXBvcnQgeyBWZWN0b3IzIH0gZnJvbSAnLi4vbWF0aC9WZWN0b3IzLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yMiB9IGZyb20gJy4uL21hdGgvVmVjdG9yMi5qcyc7XHJcbmltcG9ydCB7IFNwaGVyZSB9IGZyb20gJy4uL21hdGgvU3BoZXJlLmpzJztcclxuaW1wb3J0IHsgUmF5IH0gZnJvbSAnLi4vbWF0aC9SYXkuanMnO1xyXG5pbXBvcnQgeyBNYXRyaXg0IH0gZnJvbSAnLi4vbWF0aC9NYXRyaXg0LmpzJztcclxuaW1wb3J0IHsgT2JqZWN0M0QgfSBmcm9tICcuLi9jb3JlL09iamVjdDNELmpzJztcclxuaW1wb3J0IHsgVHJpYW5nbGUgfSBmcm9tICcuLi9tYXRoL1RyaWFuZ2xlLmpzJztcclxuaW1wb3J0IHsgQmFja1NpZGUsIEZyb250U2lkZSB9IGZyb20gJy4uL2NvbnN0YW50cy5qcyc7XHJcbmltcG9ydCB7IE1lc2hCYXNpY01hdGVyaWFsIH0gZnJvbSAnLi4vbWF0ZXJpYWxzL01lc2hCYXNpY01hdGVyaWFsLmpzJztcclxuaW1wb3J0IHsgQnVmZmVyR2VvbWV0cnkgfSBmcm9tICcuLi9jb3JlL0J1ZmZlckdlb21ldHJ5LmpzJztcclxuXHJcbmNvbnN0IF9pbnZlcnNlTWF0cml4ID0gLypAX19QVVJFX18qLyBuZXcgTWF0cml4NCgpO1xyXG5jb25zdCBfcmF5ID0gLypAX19QVVJFX18qLyBuZXcgUmF5KCk7XHJcbmNvbnN0IF9zcGhlcmUgPSAvKkBfX1BVUkVfXyovIG5ldyBTcGhlcmUoKTtcclxuY29uc3QgX3NwaGVyZUhpdEF0ID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5cclxuY29uc3QgX3ZBID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5jb25zdCBfdkIgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XHJcbmNvbnN0IF92QyA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuXHJcbmNvbnN0IF90ZW1wQSA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuY29uc3QgX21vcnBoQSA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuXHJcbmNvbnN0IF91dkEgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IyKCk7XHJcbmNvbnN0IF91dkIgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IyKCk7XHJcbmNvbnN0IF91dkMgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IyKCk7XHJcblxyXG5jb25zdCBfbm9ybWFsQSA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuY29uc3QgX25vcm1hbEIgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XHJcbmNvbnN0IF9ub3JtYWxDID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5cclxuY29uc3QgX2ludGVyc2VjdGlvblBvaW50ID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5jb25zdCBfaW50ZXJzZWN0aW9uUG9pbnRXb3JsZCA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuXHJcbmNsYXNzIE1lc2ggZXh0ZW5kcyBPYmplY3QzRCB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBnZW9tZXRyeSA9IG5ldyBCdWZmZXJHZW9tZXRyeSgpLCBtYXRlcmlhbCA9IG5ldyBNZXNoQmFzaWNNYXRlcmlhbCgpICkge1xyXG5cclxuXHRcdHN1cGVyKCk7XHJcblxyXG5cdFx0dGhpcy5pc01lc2ggPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMudHlwZSA9ICdNZXNoJztcclxuXHJcblx0XHR0aGlzLmdlb21ldHJ5ID0gZ2VvbWV0cnk7XHJcblx0XHR0aGlzLm1hdGVyaWFsID0gbWF0ZXJpYWw7XHJcblxyXG5cdFx0dGhpcy51cGRhdGVNb3JwaFRhcmdldHMoKTtcclxuXHJcblx0fVxyXG5cclxuXHRjb3B5KCBzb3VyY2UsIHJlY3Vyc2l2ZSApIHtcclxuXHJcblx0XHRzdXBlci5jb3B5KCBzb3VyY2UsIHJlY3Vyc2l2ZSApO1xyXG5cclxuXHRcdGlmICggc291cmNlLm1vcnBoVGFyZ2V0SW5mbHVlbmNlcyAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0dGhpcy5tb3JwaFRhcmdldEluZmx1ZW5jZXMgPSBzb3VyY2UubW9ycGhUYXJnZXRJbmZsdWVuY2VzLnNsaWNlKCk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggc291cmNlLm1vcnBoVGFyZ2V0RGljdGlvbmFyeSAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0dGhpcy5tb3JwaFRhcmdldERpY3Rpb25hcnkgPSBPYmplY3QuYXNzaWduKCB7fSwgc291cmNlLm1vcnBoVGFyZ2V0RGljdGlvbmFyeSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLm1hdGVyaWFsID0gQXJyYXkuaXNBcnJheSggc291cmNlLm1hdGVyaWFsICkgPyBzb3VyY2UubWF0ZXJpYWwuc2xpY2UoKSA6IHNvdXJjZS5tYXRlcmlhbDtcclxuXHRcdHRoaXMuZ2VvbWV0cnkgPSBzb3VyY2UuZ2VvbWV0cnk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0dXBkYXRlTW9ycGhUYXJnZXRzKCkge1xyXG5cclxuXHRcdGNvbnN0IGdlb21ldHJ5ID0gdGhpcy5nZW9tZXRyeTtcclxuXHJcblx0XHRjb25zdCBtb3JwaEF0dHJpYnV0ZXMgPSBnZW9tZXRyeS5tb3JwaEF0dHJpYnV0ZXM7XHJcblx0XHRjb25zdCBrZXlzID0gT2JqZWN0LmtleXMoIG1vcnBoQXR0cmlidXRlcyApO1xyXG5cclxuXHRcdGlmICgga2V5cy5sZW5ndGggPiAwICkge1xyXG5cclxuXHRcdFx0Y29uc3QgbW9ycGhBdHRyaWJ1dGUgPSBtb3JwaEF0dHJpYnV0ZXNbIGtleXNbIDAgXSBdO1xyXG5cclxuXHRcdFx0aWYgKCBtb3JwaEF0dHJpYnV0ZSAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHR0aGlzLm1vcnBoVGFyZ2V0SW5mbHVlbmNlcyA9IFtdO1xyXG5cdFx0XHRcdHRoaXMubW9ycGhUYXJnZXREaWN0aW9uYXJ5ID0ge307XHJcblxyXG5cdFx0XHRcdGZvciAoIGxldCBtID0gMCwgbWwgPSBtb3JwaEF0dHJpYnV0ZS5sZW5ndGg7IG0gPCBtbDsgbSArKyApIHtcclxuXHJcblx0XHRcdFx0XHRjb25zdCBuYW1lID0gbW9ycGhBdHRyaWJ1dGVbIG0gXS5uYW1lIHx8IFN0cmluZyggbSApO1xyXG5cclxuXHRcdFx0XHRcdHRoaXMubW9ycGhUYXJnZXRJbmZsdWVuY2VzLnB1c2goIDAgKTtcclxuXHRcdFx0XHRcdHRoaXMubW9ycGhUYXJnZXREaWN0aW9uYXJ5WyBuYW1lIF0gPSBtO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGdldFZlcnRleFBvc2l0aW9uKCBpbmRleCwgdGFyZ2V0ICkge1xyXG5cclxuXHRcdGNvbnN0IGdlb21ldHJ5ID0gdGhpcy5nZW9tZXRyeTtcclxuXHRcdGNvbnN0IHBvc2l0aW9uID0gZ2VvbWV0cnkuYXR0cmlidXRlcy5wb3NpdGlvbjtcclxuXHRcdGNvbnN0IG1vcnBoUG9zaXRpb24gPSBnZW9tZXRyeS5tb3JwaEF0dHJpYnV0ZXMucG9zaXRpb247XHJcblx0XHRjb25zdCBtb3JwaFRhcmdldHNSZWxhdGl2ZSA9IGdlb21ldHJ5Lm1vcnBoVGFyZ2V0c1JlbGF0aXZlO1xyXG5cclxuXHRcdHRhcmdldC5mcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbiwgaW5kZXggKTtcclxuXHJcblx0XHRjb25zdCBtb3JwaEluZmx1ZW5jZXMgPSB0aGlzLm1vcnBoVGFyZ2V0SW5mbHVlbmNlcztcclxuXHJcblx0XHRpZiAoIG1vcnBoUG9zaXRpb24gJiYgbW9ycGhJbmZsdWVuY2VzICkge1xyXG5cclxuXHRcdFx0X21vcnBoQS5zZXQoIDAsIDAsIDAgKTtcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSBtb3JwaFBvc2l0aW9uLmxlbmd0aDsgaSA8IGlsOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBpbmZsdWVuY2UgPSBtb3JwaEluZmx1ZW5jZXNbIGkgXTtcclxuXHRcdFx0XHRjb25zdCBtb3JwaEF0dHJpYnV0ZSA9IG1vcnBoUG9zaXRpb25bIGkgXTtcclxuXHJcblx0XHRcdFx0aWYgKCBpbmZsdWVuY2UgPT09IDAgKSBjb250aW51ZTtcclxuXHJcblx0XHRcdFx0X3RlbXBBLmZyb21CdWZmZXJBdHRyaWJ1dGUoIG1vcnBoQXR0cmlidXRlLCBpbmRleCApO1xyXG5cclxuXHRcdFx0XHRpZiAoIG1vcnBoVGFyZ2V0c1JlbGF0aXZlICkge1xyXG5cclxuXHRcdFx0XHRcdF9tb3JwaEEuYWRkU2NhbGVkVmVjdG9yKCBfdGVtcEEsIGluZmx1ZW5jZSApO1xyXG5cclxuXHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdF9tb3JwaEEuYWRkU2NhbGVkVmVjdG9yKCBfdGVtcEEuc3ViKCB0YXJnZXQgKSwgaW5mbHVlbmNlICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHRhcmdldC5hZGQoIF9tb3JwaEEgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRhcmdldDtcclxuXHJcblx0fVxyXG5cclxuXHRyYXljYXN0KCByYXljYXN0ZXIsIGludGVyc2VjdHMgKSB7XHJcblxyXG5cdFx0Y29uc3QgZ2VvbWV0cnkgPSB0aGlzLmdlb21ldHJ5O1xyXG5cdFx0Y29uc3QgbWF0ZXJpYWwgPSB0aGlzLm1hdGVyaWFsO1xyXG5cdFx0Y29uc3QgbWF0cml4V29ybGQgPSB0aGlzLm1hdHJpeFdvcmxkO1xyXG5cclxuXHRcdGlmICggbWF0ZXJpYWwgPT09IHVuZGVmaW5lZCApIHJldHVybjtcclxuXHJcblx0XHQvLyB0ZXN0IHdpdGggYm91bmRpbmcgc3BoZXJlIGluIHdvcmxkIHNwYWNlXHJcblxyXG5cdFx0aWYgKCBnZW9tZXRyeS5ib3VuZGluZ1NwaGVyZSA9PT0gbnVsbCApIGdlb21ldHJ5LmNvbXB1dGVCb3VuZGluZ1NwaGVyZSgpO1xyXG5cclxuXHRcdF9zcGhlcmUuY29weSggZ2VvbWV0cnkuYm91bmRpbmdTcGhlcmUgKTtcclxuXHRcdF9zcGhlcmUuYXBwbHlNYXRyaXg0KCBtYXRyaXhXb3JsZCApO1xyXG5cclxuXHRcdC8vIGNoZWNrIGRpc3RhbmNlIGZyb20gcmF5IG9yaWdpbiB0byBib3VuZGluZyBzcGhlcmVcclxuXHJcblx0XHRfcmF5LmNvcHkoIHJheWNhc3Rlci5yYXkgKS5yZWNhc3QoIHJheWNhc3Rlci5uZWFyICk7XHJcblxyXG5cdFx0aWYgKCBfc3BoZXJlLmNvbnRhaW5zUG9pbnQoIF9yYXkub3JpZ2luICkgPT09IGZhbHNlICkge1xyXG5cclxuXHRcdFx0aWYgKCBfcmF5LmludGVyc2VjdFNwaGVyZSggX3NwaGVyZSwgX3NwaGVyZUhpdEF0ICkgPT09IG51bGwgKSByZXR1cm47XHJcblxyXG5cdFx0XHRpZiAoIF9yYXkub3JpZ2luLmRpc3RhbmNlVG9TcXVhcmVkKCBfc3BoZXJlSGl0QXQgKSA+ICggcmF5Y2FzdGVyLmZhciAtIHJheWNhc3Rlci5uZWFyICkgKiogMiApIHJldHVybjtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gY29udmVydCByYXkgdG8gbG9jYWwgc3BhY2Ugb2YgbWVzaFxyXG5cclxuXHRcdF9pbnZlcnNlTWF0cml4LmNvcHkoIG1hdHJpeFdvcmxkICkuaW52ZXJ0KCk7XHJcblx0XHRfcmF5LmNvcHkoIHJheWNhc3Rlci5yYXkgKS5hcHBseU1hdHJpeDQoIF9pbnZlcnNlTWF0cml4ICk7XHJcblxyXG5cdFx0Ly8gdGVzdCB3aXRoIGJvdW5kaW5nIGJveCBpbiBsb2NhbCBzcGFjZVxyXG5cclxuXHRcdGlmICggZ2VvbWV0cnkuYm91bmRpbmdCb3ggIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRpZiAoIF9yYXkuaW50ZXJzZWN0c0JveCggZ2VvbWV0cnkuYm91bmRpbmdCb3ggKSA9PT0gZmFsc2UgKSByZXR1cm47XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIHRlc3QgZm9yIGludGVyc2VjdGlvbnMgd2l0aCBnZW9tZXRyeVxyXG5cclxuXHRcdHRoaXMuX2NvbXB1dGVJbnRlcnNlY3Rpb25zKCByYXljYXN0ZXIsIGludGVyc2VjdHMsIF9yYXkgKTtcclxuXHJcblx0fVxyXG5cclxuXHRfY29tcHV0ZUludGVyc2VjdGlvbnMoIHJheWNhc3RlciwgaW50ZXJzZWN0cywgcmF5TG9jYWxTcGFjZSApIHtcclxuXHJcblx0XHRsZXQgaW50ZXJzZWN0aW9uO1xyXG5cclxuXHRcdGNvbnN0IGdlb21ldHJ5ID0gdGhpcy5nZW9tZXRyeTtcclxuXHRcdGNvbnN0IG1hdGVyaWFsID0gdGhpcy5tYXRlcmlhbDtcclxuXHJcblx0XHRjb25zdCBpbmRleCA9IGdlb21ldHJ5LmluZGV4O1xyXG5cdFx0Y29uc3QgcG9zaXRpb24gPSBnZW9tZXRyeS5hdHRyaWJ1dGVzLnBvc2l0aW9uO1xyXG5cdFx0Y29uc3QgdXYgPSBnZW9tZXRyeS5hdHRyaWJ1dGVzLnV2O1xyXG5cdFx0Y29uc3QgdXYxID0gZ2VvbWV0cnkuYXR0cmlidXRlcy51djE7XHJcblx0XHRjb25zdCBub3JtYWwgPSBnZW9tZXRyeS5hdHRyaWJ1dGVzLm5vcm1hbDtcclxuXHRcdGNvbnN0IGdyb3VwcyA9IGdlb21ldHJ5Lmdyb3VwcztcclxuXHRcdGNvbnN0IGRyYXdSYW5nZSA9IGdlb21ldHJ5LmRyYXdSYW5nZTtcclxuXHJcblx0XHRpZiAoIGluZGV4ICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0Ly8gaW5kZXhlZCBidWZmZXIgZ2VvbWV0cnlcclxuXHJcblx0XHRcdGlmICggQXJyYXkuaXNBcnJheSggbWF0ZXJpYWwgKSApIHtcclxuXHJcblx0XHRcdFx0Zm9yICggbGV0IGkgPSAwLCBpbCA9IGdyb3Vwcy5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0XHRjb25zdCBncm91cCA9IGdyb3Vwc1sgaSBdO1xyXG5cdFx0XHRcdFx0Y29uc3QgZ3JvdXBNYXRlcmlhbCA9IG1hdGVyaWFsWyBncm91cC5tYXRlcmlhbEluZGV4IF07XHJcblxyXG5cdFx0XHRcdFx0Y29uc3Qgc3RhcnQgPSBNYXRoLm1heCggZ3JvdXAuc3RhcnQsIGRyYXdSYW5nZS5zdGFydCApO1xyXG5cdFx0XHRcdFx0Y29uc3QgZW5kID0gTWF0aC5taW4oIGluZGV4LmNvdW50LCBNYXRoLm1pbiggKCBncm91cC5zdGFydCArIGdyb3VwLmNvdW50ICksICggZHJhd1JhbmdlLnN0YXJ0ICsgZHJhd1JhbmdlLmNvdW50ICkgKSApO1xyXG5cclxuXHRcdFx0XHRcdGZvciAoIGxldCBqID0gc3RhcnQsIGpsID0gZW5kOyBqIDwgamw7IGogKz0gMyApIHtcclxuXHJcblx0XHRcdFx0XHRcdGNvbnN0IGEgPSBpbmRleC5nZXRYKCBqICk7XHJcblx0XHRcdFx0XHRcdGNvbnN0IGIgPSBpbmRleC5nZXRYKCBqICsgMSApO1xyXG5cdFx0XHRcdFx0XHRjb25zdCBjID0gaW5kZXguZ2V0WCggaiArIDIgKTtcclxuXHJcblx0XHRcdFx0XHRcdGludGVyc2VjdGlvbiA9IGNoZWNrR2VvbWV0cnlJbnRlcnNlY3Rpb24oIHRoaXMsIGdyb3VwTWF0ZXJpYWwsIHJheWNhc3RlciwgcmF5TG9jYWxTcGFjZSwgdXYsIHV2MSwgbm9ybWFsLCBhLCBiLCBjICk7XHJcblxyXG5cdFx0XHRcdFx0XHRpZiAoIGludGVyc2VjdGlvbiApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0aW50ZXJzZWN0aW9uLmZhY2VJbmRleCA9IE1hdGguZmxvb3IoIGogLyAzICk7IC8vIHRyaWFuZ2xlIG51bWJlciBpbiBpbmRleGVkIGJ1ZmZlciBzZW1hbnRpY3NcclxuXHRcdFx0XHRcdFx0XHRpbnRlcnNlY3Rpb24uZmFjZS5tYXRlcmlhbEluZGV4ID0gZ3JvdXAubWF0ZXJpYWxJbmRleDtcclxuXHRcdFx0XHRcdFx0XHRpbnRlcnNlY3RzLnB1c2goIGludGVyc2VjdGlvbiApO1xyXG5cclxuXHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0Y29uc3Qgc3RhcnQgPSBNYXRoLm1heCggMCwgZHJhd1JhbmdlLnN0YXJ0ICk7XHJcblx0XHRcdFx0Y29uc3QgZW5kID0gTWF0aC5taW4oIGluZGV4LmNvdW50LCAoIGRyYXdSYW5nZS5zdGFydCArIGRyYXdSYW5nZS5jb3VudCApICk7XHJcblxyXG5cdFx0XHRcdGZvciAoIGxldCBpID0gc3RhcnQsIGlsID0gZW5kOyBpIDwgaWw7IGkgKz0gMyApIHtcclxuXHJcblx0XHRcdFx0XHRjb25zdCBhID0gaW5kZXguZ2V0WCggaSApO1xyXG5cdFx0XHRcdFx0Y29uc3QgYiA9IGluZGV4LmdldFgoIGkgKyAxICk7XHJcblx0XHRcdFx0XHRjb25zdCBjID0gaW5kZXguZ2V0WCggaSArIDIgKTtcclxuXHJcblx0XHRcdFx0XHRpbnRlcnNlY3Rpb24gPSBjaGVja0dlb21ldHJ5SW50ZXJzZWN0aW9uKCB0aGlzLCBtYXRlcmlhbCwgcmF5Y2FzdGVyLCByYXlMb2NhbFNwYWNlLCB1diwgdXYxLCBub3JtYWwsIGEsIGIsIGMgKTtcclxuXHJcblx0XHRcdFx0XHRpZiAoIGludGVyc2VjdGlvbiApIHtcclxuXHJcblx0XHRcdFx0XHRcdGludGVyc2VjdGlvbi5mYWNlSW5kZXggPSBNYXRoLmZsb29yKCBpIC8gMyApOyAvLyB0cmlhbmdsZSBudW1iZXIgaW4gaW5kZXhlZCBidWZmZXIgc2VtYW50aWNzXHJcblx0XHRcdFx0XHRcdGludGVyc2VjdHMucHVzaCggaW50ZXJzZWN0aW9uICk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fSBlbHNlIGlmICggcG9zaXRpb24gIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdC8vIG5vbi1pbmRleGVkIGJ1ZmZlciBnZW9tZXRyeVxyXG5cclxuXHRcdFx0aWYgKCBBcnJheS5pc0FycmF5KCBtYXRlcmlhbCApICkge1xyXG5cclxuXHRcdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gZ3JvdXBzLmxlbmd0aDsgaSA8IGlsOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRcdGNvbnN0IGdyb3VwID0gZ3JvdXBzWyBpIF07XHJcblx0XHRcdFx0XHRjb25zdCBncm91cE1hdGVyaWFsID0gbWF0ZXJpYWxbIGdyb3VwLm1hdGVyaWFsSW5kZXggXTtcclxuXHJcblx0XHRcdFx0XHRjb25zdCBzdGFydCA9IE1hdGgubWF4KCBncm91cC5zdGFydCwgZHJhd1JhbmdlLnN0YXJ0ICk7XHJcblx0XHRcdFx0XHRjb25zdCBlbmQgPSBNYXRoLm1pbiggcG9zaXRpb24uY291bnQsIE1hdGgubWluKCAoIGdyb3VwLnN0YXJ0ICsgZ3JvdXAuY291bnQgKSwgKCBkcmF3UmFuZ2Uuc3RhcnQgKyBkcmF3UmFuZ2UuY291bnQgKSApICk7XHJcblxyXG5cdFx0XHRcdFx0Zm9yICggbGV0IGogPSBzdGFydCwgamwgPSBlbmQ7IGogPCBqbDsgaiArPSAzICkge1xyXG5cclxuXHRcdFx0XHRcdFx0Y29uc3QgYSA9IGo7XHJcblx0XHRcdFx0XHRcdGNvbnN0IGIgPSBqICsgMTtcclxuXHRcdFx0XHRcdFx0Y29uc3QgYyA9IGogKyAyO1xyXG5cclxuXHRcdFx0XHRcdFx0aW50ZXJzZWN0aW9uID0gY2hlY2tHZW9tZXRyeUludGVyc2VjdGlvbiggdGhpcywgZ3JvdXBNYXRlcmlhbCwgcmF5Y2FzdGVyLCByYXlMb2NhbFNwYWNlLCB1diwgdXYxLCBub3JtYWwsIGEsIGIsIGMgKTtcclxuXHJcblx0XHRcdFx0XHRcdGlmICggaW50ZXJzZWN0aW9uICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRpbnRlcnNlY3Rpb24uZmFjZUluZGV4ID0gTWF0aC5mbG9vciggaiAvIDMgKTsgLy8gdHJpYW5nbGUgbnVtYmVyIGluIG5vbi1pbmRleGVkIGJ1ZmZlciBzZW1hbnRpY3NcclxuXHRcdFx0XHRcdFx0XHRpbnRlcnNlY3Rpb24uZmFjZS5tYXRlcmlhbEluZGV4ID0gZ3JvdXAubWF0ZXJpYWxJbmRleDtcclxuXHRcdFx0XHRcdFx0XHRpbnRlcnNlY3RzLnB1c2goIGludGVyc2VjdGlvbiApO1xyXG5cclxuXHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0Y29uc3Qgc3RhcnQgPSBNYXRoLm1heCggMCwgZHJhd1JhbmdlLnN0YXJ0ICk7XHJcblx0XHRcdFx0Y29uc3QgZW5kID0gTWF0aC5taW4oIHBvc2l0aW9uLmNvdW50LCAoIGRyYXdSYW5nZS5zdGFydCArIGRyYXdSYW5nZS5jb3VudCApICk7XHJcblxyXG5cdFx0XHRcdGZvciAoIGxldCBpID0gc3RhcnQsIGlsID0gZW5kOyBpIDwgaWw7IGkgKz0gMyApIHtcclxuXHJcblx0XHRcdFx0XHRjb25zdCBhID0gaTtcclxuXHRcdFx0XHRcdGNvbnN0IGIgPSBpICsgMTtcclxuXHRcdFx0XHRcdGNvbnN0IGMgPSBpICsgMjtcclxuXHJcblx0XHRcdFx0XHRpbnRlcnNlY3Rpb24gPSBjaGVja0dlb21ldHJ5SW50ZXJzZWN0aW9uKCB0aGlzLCBtYXRlcmlhbCwgcmF5Y2FzdGVyLCByYXlMb2NhbFNwYWNlLCB1diwgdXYxLCBub3JtYWwsIGEsIGIsIGMgKTtcclxuXHJcblx0XHRcdFx0XHRpZiAoIGludGVyc2VjdGlvbiApIHtcclxuXHJcblx0XHRcdFx0XHRcdGludGVyc2VjdGlvbi5mYWNlSW5kZXggPSBNYXRoLmZsb29yKCBpIC8gMyApOyAvLyB0cmlhbmdsZSBudW1iZXIgaW4gbm9uLWluZGV4ZWQgYnVmZmVyIHNlbWFudGljc1xyXG5cdFx0XHRcdFx0XHRpbnRlcnNlY3RzLnB1c2goIGludGVyc2VjdGlvbiApO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gY2hlY2tJbnRlcnNlY3Rpb24oIG9iamVjdCwgbWF0ZXJpYWwsIHJheWNhc3RlciwgcmF5LCBwQSwgcEIsIHBDLCBwb2ludCApIHtcclxuXHJcblx0bGV0IGludGVyc2VjdDtcclxuXHJcblx0aWYgKCBtYXRlcmlhbC5zaWRlID09PSBCYWNrU2lkZSApIHtcclxuXHJcblx0XHRpbnRlcnNlY3QgPSByYXkuaW50ZXJzZWN0VHJpYW5nbGUoIHBDLCBwQiwgcEEsIHRydWUsIHBvaW50ICk7XHJcblxyXG5cdH0gZWxzZSB7XHJcblxyXG5cdFx0aW50ZXJzZWN0ID0gcmF5LmludGVyc2VjdFRyaWFuZ2xlKCBwQSwgcEIsIHBDLCAoIG1hdGVyaWFsLnNpZGUgPT09IEZyb250U2lkZSApLCBwb2ludCApO1xyXG5cclxuXHR9XHJcblxyXG5cdGlmICggaW50ZXJzZWN0ID09PSBudWxsICkgcmV0dXJuIG51bGw7XHJcblxyXG5cdF9pbnRlcnNlY3Rpb25Qb2ludFdvcmxkLmNvcHkoIHBvaW50ICk7XHJcblx0X2ludGVyc2VjdGlvblBvaW50V29ybGQuYXBwbHlNYXRyaXg0KCBvYmplY3QubWF0cml4V29ybGQgKTtcclxuXHJcblx0Y29uc3QgZGlzdGFuY2UgPSByYXljYXN0ZXIucmF5Lm9yaWdpbi5kaXN0YW5jZVRvKCBfaW50ZXJzZWN0aW9uUG9pbnRXb3JsZCApO1xyXG5cclxuXHRpZiAoIGRpc3RhbmNlIDwgcmF5Y2FzdGVyLm5lYXIgfHwgZGlzdGFuY2UgPiByYXljYXN0ZXIuZmFyICkgcmV0dXJuIG51bGw7XHJcblxyXG5cdHJldHVybiB7XHJcblx0XHRkaXN0YW5jZTogZGlzdGFuY2UsXHJcblx0XHRwb2ludDogX2ludGVyc2VjdGlvblBvaW50V29ybGQuY2xvbmUoKSxcclxuXHRcdG9iamVjdDogb2JqZWN0XHJcblx0fTtcclxuXHJcbn1cclxuXHJcbmZ1bmN0aW9uIGNoZWNrR2VvbWV0cnlJbnRlcnNlY3Rpb24oIG9iamVjdCwgbWF0ZXJpYWwsIHJheWNhc3RlciwgcmF5LCB1diwgdXYxLCBub3JtYWwsIGEsIGIsIGMgKSB7XHJcblxyXG5cdG9iamVjdC5nZXRWZXJ0ZXhQb3NpdGlvbiggYSwgX3ZBICk7XHJcblx0b2JqZWN0LmdldFZlcnRleFBvc2l0aW9uKCBiLCBfdkIgKTtcclxuXHRvYmplY3QuZ2V0VmVydGV4UG9zaXRpb24oIGMsIF92QyApO1xyXG5cclxuXHRjb25zdCBpbnRlcnNlY3Rpb24gPSBjaGVja0ludGVyc2VjdGlvbiggb2JqZWN0LCBtYXRlcmlhbCwgcmF5Y2FzdGVyLCByYXksIF92QSwgX3ZCLCBfdkMsIF9pbnRlcnNlY3Rpb25Qb2ludCApO1xyXG5cclxuXHRpZiAoIGludGVyc2VjdGlvbiApIHtcclxuXHJcblx0XHRpZiAoIHV2ICkge1xyXG5cclxuXHRcdFx0X3V2QS5mcm9tQnVmZmVyQXR0cmlidXRlKCB1diwgYSApO1xyXG5cdFx0XHRfdXZCLmZyb21CdWZmZXJBdHRyaWJ1dGUoIHV2LCBiICk7XHJcblx0XHRcdF91dkMuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggdXYsIGMgKTtcclxuXHJcblx0XHRcdGludGVyc2VjdGlvbi51diA9IFRyaWFuZ2xlLmdldEludGVycG9sYXRpb24oIF9pbnRlcnNlY3Rpb25Qb2ludCwgX3ZBLCBfdkIsIF92QywgX3V2QSwgX3V2QiwgX3V2QywgbmV3IFZlY3RvcjIoKSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHV2MSApIHtcclxuXHJcblx0XHRcdF91dkEuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggdXYxLCBhICk7XHJcblx0XHRcdF91dkIuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggdXYxLCBiICk7XHJcblx0XHRcdF91dkMuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggdXYxLCBjICk7XHJcblxyXG5cdFx0XHRpbnRlcnNlY3Rpb24udXYxID0gVHJpYW5nbGUuZ2V0SW50ZXJwb2xhdGlvbiggX2ludGVyc2VjdGlvblBvaW50LCBfdkEsIF92QiwgX3ZDLCBfdXZBLCBfdXZCLCBfdXZDLCBuZXcgVmVjdG9yMigpICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggbm9ybWFsICkge1xyXG5cclxuXHRcdFx0X25vcm1hbEEuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggbm9ybWFsLCBhICk7XHJcblx0XHRcdF9ub3JtYWxCLmZyb21CdWZmZXJBdHRyaWJ1dGUoIG5vcm1hbCwgYiApO1xyXG5cdFx0XHRfbm9ybWFsQy5mcm9tQnVmZmVyQXR0cmlidXRlKCBub3JtYWwsIGMgKTtcclxuXHJcblx0XHRcdGludGVyc2VjdGlvbi5ub3JtYWwgPSBUcmlhbmdsZS5nZXRJbnRlcnBvbGF0aW9uKCBfaW50ZXJzZWN0aW9uUG9pbnQsIF92QSwgX3ZCLCBfdkMsIF9ub3JtYWxBLCBfbm9ybWFsQiwgX25vcm1hbEMsIG5ldyBWZWN0b3IzKCkgKTtcclxuXHJcblx0XHRcdGlmICggaW50ZXJzZWN0aW9uLm5vcm1hbC5kb3QoIHJheS5kaXJlY3Rpb24gKSA+IDAgKSB7XHJcblxyXG5cdFx0XHRcdGludGVyc2VjdGlvbi5ub3JtYWwubXVsdGlwbHlTY2FsYXIoIC0gMSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCBmYWNlID0ge1xyXG5cdFx0XHRhOiBhLFxyXG5cdFx0XHRiOiBiLFxyXG5cdFx0XHRjOiBjLFxyXG5cdFx0XHRub3JtYWw6IG5ldyBWZWN0b3IzKCksXHJcblx0XHRcdG1hdGVyaWFsSW5kZXg6IDBcclxuXHRcdH07XHJcblxyXG5cdFx0VHJpYW5nbGUuZ2V0Tm9ybWFsKCBfdkEsIF92QiwgX3ZDLCBmYWNlLm5vcm1hbCApO1xyXG5cclxuXHRcdGludGVyc2VjdGlvbi5mYWNlID0gZmFjZTtcclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4gaW50ZXJzZWN0aW9uO1xyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgTWVzaCB9O1xyXG4iLCJpbXBvcnQgeyBCdWZmZXJHZW9tZXRyeSB9IGZyb20gJy4uL2NvcmUvQnVmZmVyR2VvbWV0cnkuanMnO1xyXG5pbXBvcnQgeyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlIH0gZnJvbSAnLi4vY29yZS9CdWZmZXJBdHRyaWJ1dGUuanMnO1xyXG5pbXBvcnQgeyBWZWN0b3IzIH0gZnJvbSAnLi4vbWF0aC9WZWN0b3IzLmpzJztcclxuXHJcbmNsYXNzIEJveEdlb21ldHJ5IGV4dGVuZHMgQnVmZmVyR2VvbWV0cnkge1xyXG5cclxuXHRjb25zdHJ1Y3Rvciggd2lkdGggPSAxLCBoZWlnaHQgPSAxLCBkZXB0aCA9IDEsIHdpZHRoU2VnbWVudHMgPSAxLCBoZWlnaHRTZWdtZW50cyA9IDEsIGRlcHRoU2VnbWVudHMgPSAxICkge1xyXG5cclxuXHRcdHN1cGVyKCk7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ0JveEdlb21ldHJ5JztcclxuXHJcblx0XHR0aGlzLnBhcmFtZXRlcnMgPSB7XHJcblx0XHRcdHdpZHRoOiB3aWR0aCxcclxuXHRcdFx0aGVpZ2h0OiBoZWlnaHQsXHJcblx0XHRcdGRlcHRoOiBkZXB0aCxcclxuXHRcdFx0d2lkdGhTZWdtZW50czogd2lkdGhTZWdtZW50cyxcclxuXHRcdFx0aGVpZ2h0U2VnbWVudHM6IGhlaWdodFNlZ21lbnRzLFxyXG5cdFx0XHRkZXB0aFNlZ21lbnRzOiBkZXB0aFNlZ21lbnRzXHJcblx0XHR9O1xyXG5cclxuXHRcdGNvbnN0IHNjb3BlID0gdGhpcztcclxuXHJcblx0XHQvLyBzZWdtZW50c1xyXG5cclxuXHRcdHdpZHRoU2VnbWVudHMgPSBNYXRoLmZsb29yKCB3aWR0aFNlZ21lbnRzICk7XHJcblx0XHRoZWlnaHRTZWdtZW50cyA9IE1hdGguZmxvb3IoIGhlaWdodFNlZ21lbnRzICk7XHJcblx0XHRkZXB0aFNlZ21lbnRzID0gTWF0aC5mbG9vciggZGVwdGhTZWdtZW50cyApO1xyXG5cclxuXHRcdC8vIGJ1ZmZlcnNcclxuXHJcblx0XHRjb25zdCBpbmRpY2VzID0gW107XHJcblx0XHRjb25zdCB2ZXJ0aWNlcyA9IFtdO1xyXG5cdFx0Y29uc3Qgbm9ybWFscyA9IFtdO1xyXG5cdFx0Y29uc3QgdXZzID0gW107XHJcblxyXG5cdFx0Ly8gaGVscGVyIHZhcmlhYmxlc1xyXG5cclxuXHRcdGxldCBudW1iZXJPZlZlcnRpY2VzID0gMDtcclxuXHRcdGxldCBncm91cFN0YXJ0ID0gMDtcclxuXHJcblx0XHQvLyBidWlsZCBlYWNoIHNpZGUgb2YgdGhlIGJveCBnZW9tZXRyeVxyXG5cclxuXHRcdGJ1aWxkUGxhbmUoICd6JywgJ3knLCAneCcsIC0gMSwgLSAxLCBkZXB0aCwgaGVpZ2h0LCB3aWR0aCwgZGVwdGhTZWdtZW50cywgaGVpZ2h0U2VnbWVudHMsIDAgKTsgLy8gcHhcclxuXHRcdGJ1aWxkUGxhbmUoICd6JywgJ3knLCAneCcsIDEsIC0gMSwgZGVwdGgsIGhlaWdodCwgLSB3aWR0aCwgZGVwdGhTZWdtZW50cywgaGVpZ2h0U2VnbWVudHMsIDEgKTsgLy8gbnhcclxuXHRcdGJ1aWxkUGxhbmUoICd4JywgJ3onLCAneScsIDEsIDEsIHdpZHRoLCBkZXB0aCwgaGVpZ2h0LCB3aWR0aFNlZ21lbnRzLCBkZXB0aFNlZ21lbnRzLCAyICk7IC8vIHB5XHJcblx0XHRidWlsZFBsYW5lKCAneCcsICd6JywgJ3knLCAxLCAtIDEsIHdpZHRoLCBkZXB0aCwgLSBoZWlnaHQsIHdpZHRoU2VnbWVudHMsIGRlcHRoU2VnbWVudHMsIDMgKTsgLy8gbnlcclxuXHRcdGJ1aWxkUGxhbmUoICd4JywgJ3knLCAneicsIDEsIC0gMSwgd2lkdGgsIGhlaWdodCwgZGVwdGgsIHdpZHRoU2VnbWVudHMsIGhlaWdodFNlZ21lbnRzLCA0ICk7IC8vIHB6XHJcblx0XHRidWlsZFBsYW5lKCAneCcsICd5JywgJ3onLCAtIDEsIC0gMSwgd2lkdGgsIGhlaWdodCwgLSBkZXB0aCwgd2lkdGhTZWdtZW50cywgaGVpZ2h0U2VnbWVudHMsIDUgKTsgLy8gbnpcclxuXHJcblx0XHQvLyBidWlsZCBnZW9tZXRyeVxyXG5cclxuXHRcdHRoaXMuc2V0SW5kZXgoIGluZGljZXMgKTtcclxuXHRcdHRoaXMuc2V0QXR0cmlidXRlKCAncG9zaXRpb24nLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggdmVydGljZXMsIDMgKSApO1xyXG5cdFx0dGhpcy5zZXRBdHRyaWJ1dGUoICdub3JtYWwnLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggbm9ybWFscywgMyApICk7XHJcblx0XHR0aGlzLnNldEF0dHJpYnV0ZSggJ3V2JywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIHV2cywgMiApICk7XHJcblxyXG5cdFx0ZnVuY3Rpb24gYnVpbGRQbGFuZSggdSwgdiwgdywgdWRpciwgdmRpciwgd2lkdGgsIGhlaWdodCwgZGVwdGgsIGdyaWRYLCBncmlkWSwgbWF0ZXJpYWxJbmRleCApIHtcclxuXHJcblx0XHRcdGNvbnN0IHNlZ21lbnRXaWR0aCA9IHdpZHRoIC8gZ3JpZFg7XHJcblx0XHRcdGNvbnN0IHNlZ21lbnRIZWlnaHQgPSBoZWlnaHQgLyBncmlkWTtcclxuXHJcblx0XHRcdGNvbnN0IHdpZHRoSGFsZiA9IHdpZHRoIC8gMjtcclxuXHRcdFx0Y29uc3QgaGVpZ2h0SGFsZiA9IGhlaWdodCAvIDI7XHJcblx0XHRcdGNvbnN0IGRlcHRoSGFsZiA9IGRlcHRoIC8gMjtcclxuXHJcblx0XHRcdGNvbnN0IGdyaWRYMSA9IGdyaWRYICsgMTtcclxuXHRcdFx0Y29uc3QgZ3JpZFkxID0gZ3JpZFkgKyAxO1xyXG5cclxuXHRcdFx0bGV0IHZlcnRleENvdW50ZXIgPSAwO1xyXG5cdFx0XHRsZXQgZ3JvdXBDb3VudCA9IDA7XHJcblxyXG5cdFx0XHRjb25zdCB2ZWN0b3IgPSBuZXcgVmVjdG9yMygpO1xyXG5cclxuXHRcdFx0Ly8gZ2VuZXJhdGUgdmVydGljZXMsIG5vcm1hbHMgYW5kIHV2c1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGl5ID0gMDsgaXkgPCBncmlkWTE7IGl5ICsrICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCB5ID0gaXkgKiBzZWdtZW50SGVpZ2h0IC0gaGVpZ2h0SGFsZjtcclxuXHJcblx0XHRcdFx0Zm9yICggbGV0IGl4ID0gMDsgaXggPCBncmlkWDE7IGl4ICsrICkge1xyXG5cclxuXHRcdFx0XHRcdGNvbnN0IHggPSBpeCAqIHNlZ21lbnRXaWR0aCAtIHdpZHRoSGFsZjtcclxuXHJcblx0XHRcdFx0XHQvLyBzZXQgdmFsdWVzIHRvIGNvcnJlY3QgdmVjdG9yIGNvbXBvbmVudFxyXG5cclxuXHRcdFx0XHRcdHZlY3RvclsgdSBdID0geCAqIHVkaXI7XHJcblx0XHRcdFx0XHR2ZWN0b3JbIHYgXSA9IHkgKiB2ZGlyO1xyXG5cdFx0XHRcdFx0dmVjdG9yWyB3IF0gPSBkZXB0aEhhbGY7XHJcblxyXG5cdFx0XHRcdFx0Ly8gbm93IGFwcGx5IHZlY3RvciB0byB2ZXJ0ZXggYnVmZmVyXHJcblxyXG5cdFx0XHRcdFx0dmVydGljZXMucHVzaCggdmVjdG9yLngsIHZlY3Rvci55LCB2ZWN0b3IueiApO1xyXG5cclxuXHRcdFx0XHRcdC8vIHNldCB2YWx1ZXMgdG8gY29ycmVjdCB2ZWN0b3IgY29tcG9uZW50XHJcblxyXG5cdFx0XHRcdFx0dmVjdG9yWyB1IF0gPSAwO1xyXG5cdFx0XHRcdFx0dmVjdG9yWyB2IF0gPSAwO1xyXG5cdFx0XHRcdFx0dmVjdG9yWyB3IF0gPSBkZXB0aCA+IDAgPyAxIDogLSAxO1xyXG5cclxuXHRcdFx0XHRcdC8vIG5vdyBhcHBseSB2ZWN0b3IgdG8gbm9ybWFsIGJ1ZmZlclxyXG5cclxuXHRcdFx0XHRcdG5vcm1hbHMucHVzaCggdmVjdG9yLngsIHZlY3Rvci55LCB2ZWN0b3IueiApO1xyXG5cclxuXHRcdFx0XHRcdC8vIHV2c1xyXG5cclxuXHRcdFx0XHRcdHV2cy5wdXNoKCBpeCAvIGdyaWRYICk7XHJcblx0XHRcdFx0XHR1dnMucHVzaCggMSAtICggaXkgLyBncmlkWSApICk7XHJcblxyXG5cdFx0XHRcdFx0Ly8gY291bnRlcnNcclxuXHJcblx0XHRcdFx0XHR2ZXJ0ZXhDb3VudGVyICs9IDE7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdC8vIGluZGljZXNcclxuXHJcblx0XHRcdC8vIDEuIHlvdSBuZWVkIHRocmVlIGluZGljZXMgdG8gZHJhdyBhIHNpbmdsZSBmYWNlXHJcblx0XHRcdC8vIDIuIGEgc2luZ2xlIHNlZ21lbnQgY29uc2lzdHMgb2YgdHdvIGZhY2VzXHJcblx0XHRcdC8vIDMuIHNvIHdlIG5lZWQgdG8gZ2VuZXJhdGUgc2l4ICgyKjMpIGluZGljZXMgcGVyIHNlZ21lbnRcclxuXHJcblx0XHRcdGZvciAoIGxldCBpeSA9IDA7IGl5IDwgZ3JpZFk7IGl5ICsrICkge1xyXG5cclxuXHRcdFx0XHRmb3IgKCBsZXQgaXggPSAwOyBpeCA8IGdyaWRYOyBpeCArKyApIHtcclxuXHJcblx0XHRcdFx0XHRjb25zdCBhID0gbnVtYmVyT2ZWZXJ0aWNlcyArIGl4ICsgZ3JpZFgxICogaXk7XHJcblx0XHRcdFx0XHRjb25zdCBiID0gbnVtYmVyT2ZWZXJ0aWNlcyArIGl4ICsgZ3JpZFgxICogKCBpeSArIDEgKTtcclxuXHRcdFx0XHRcdGNvbnN0IGMgPSBudW1iZXJPZlZlcnRpY2VzICsgKCBpeCArIDEgKSArIGdyaWRYMSAqICggaXkgKyAxICk7XHJcblx0XHRcdFx0XHRjb25zdCBkID0gbnVtYmVyT2ZWZXJ0aWNlcyArICggaXggKyAxICkgKyBncmlkWDEgKiBpeTtcclxuXHJcblx0XHRcdFx0XHQvLyBmYWNlc1xyXG5cclxuXHRcdFx0XHRcdGluZGljZXMucHVzaCggYSwgYiwgZCApO1xyXG5cdFx0XHRcdFx0aW5kaWNlcy5wdXNoKCBiLCBjLCBkICk7XHJcblxyXG5cdFx0XHRcdFx0Ly8gaW5jcmVhc2UgY291bnRlclxyXG5cclxuXHRcdFx0XHRcdGdyb3VwQ291bnQgKz0gNjtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Ly8gYWRkIGEgZ3JvdXAgdG8gdGhlIGdlb21ldHJ5LiB0aGlzIHdpbGwgZW5zdXJlIG11bHRpIG1hdGVyaWFsIHN1cHBvcnRcclxuXHJcblx0XHRcdHNjb3BlLmFkZEdyb3VwKCBncm91cFN0YXJ0LCBncm91cENvdW50LCBtYXRlcmlhbEluZGV4ICk7XHJcblxyXG5cdFx0XHQvLyBjYWxjdWxhdGUgbmV3IHN0YXJ0IHZhbHVlIGZvciBncm91cHNcclxuXHJcblx0XHRcdGdyb3VwU3RhcnQgKz0gZ3JvdXBDb3VudDtcclxuXHJcblx0XHRcdC8vIHVwZGF0ZSB0b3RhbCBudW1iZXIgb2YgdmVydGljZXNcclxuXHJcblx0XHRcdG51bWJlck9mVmVydGljZXMgKz0gdmVydGV4Q291bnRlcjtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xyXG5cclxuXHRcdHRoaXMucGFyYW1ldGVycyA9IE9iamVjdC5hc3NpZ24oIHt9LCBzb3VyY2UucGFyYW1ldGVycyApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHN0YXRpYyBmcm9tSlNPTiggZGF0YSApIHtcclxuXHJcblx0XHRyZXR1cm4gbmV3IEJveEdlb21ldHJ5KCBkYXRhLndpZHRoLCBkYXRhLmhlaWdodCwgZGF0YS5kZXB0aCwgZGF0YS53aWR0aFNlZ21lbnRzLCBkYXRhLmhlaWdodFNlZ21lbnRzLCBkYXRhLmRlcHRoU2VnbWVudHMgKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgQm94R2VvbWV0cnkgfTtcclxuIiwiaW1wb3J0IHsgQ29sb3JNYW5hZ2VtZW50IH0gZnJvbSAnLi4vLi4vbWF0aC9Db2xvck1hbmFnZW1lbnQuanMnO1xyXG5cclxuLyoqXHJcbiAqIFVuaWZvcm0gVXRpbGl0aWVzXHJcbiAqL1xyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIGNsb25lVW5pZm9ybXMoIHNyYyApIHtcclxuXHJcblx0Y29uc3QgZHN0ID0ge307XHJcblxyXG5cdGZvciAoIGNvbnN0IHUgaW4gc3JjICkge1xyXG5cclxuXHRcdGRzdFsgdSBdID0ge307XHJcblxyXG5cdFx0Zm9yICggY29uc3QgcCBpbiBzcmNbIHUgXSApIHtcclxuXHJcblx0XHRcdGNvbnN0IHByb3BlcnR5ID0gc3JjWyB1IF1bIHAgXTtcclxuXHJcblx0XHRcdGlmICggcHJvcGVydHkgJiYgKCBwcm9wZXJ0eS5pc0NvbG9yIHx8XHJcblx0XHRcdFx0cHJvcGVydHkuaXNNYXRyaXgzIHx8IHByb3BlcnR5LmlzTWF0cml4NCB8fFxyXG5cdFx0XHRcdHByb3BlcnR5LmlzVmVjdG9yMiB8fCBwcm9wZXJ0eS5pc1ZlY3RvcjMgfHwgcHJvcGVydHkuaXNWZWN0b3I0IHx8XHJcblx0XHRcdFx0cHJvcGVydHkuaXNUZXh0dXJlIHx8IHByb3BlcnR5LmlzUXVhdGVybmlvbiApICkge1xyXG5cclxuXHRcdFx0XHRpZiAoIHByb3BlcnR5LmlzUmVuZGVyVGFyZ2V0VGV4dHVyZSApIHtcclxuXHJcblx0XHRcdFx0XHRjb25zb2xlLndhcm4oICdVbmlmb3Jtc1V0aWxzOiBUZXh0dXJlcyBvZiByZW5kZXIgdGFyZ2V0cyBjYW5ub3QgYmUgY2xvbmVkIHZpYSBjbG9uZVVuaWZvcm1zKCkgb3IgbWVyZ2VVbmlmb3JtcygpLicgKTtcclxuXHRcdFx0XHRcdGRzdFsgdSBdWyBwIF0gPSBudWxsO1xyXG5cclxuXHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdGRzdFsgdSBdWyBwIF0gPSBwcm9wZXJ0eS5jbG9uZSgpO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9IGVsc2UgaWYgKCBBcnJheS5pc0FycmF5KCBwcm9wZXJ0eSApICkge1xyXG5cclxuXHRcdFx0XHRkc3RbIHUgXVsgcCBdID0gcHJvcGVydHkuc2xpY2UoKTtcclxuXHJcblx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdGRzdFsgdSBdWyBwIF0gPSBwcm9wZXJ0eTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0cmV0dXJuIGRzdDtcclxuXHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBtZXJnZVVuaWZvcm1zKCB1bmlmb3JtcyApIHtcclxuXHJcblx0Y29uc3QgbWVyZ2VkID0ge307XHJcblxyXG5cdGZvciAoIGxldCB1ID0gMDsgdSA8IHVuaWZvcm1zLmxlbmd0aDsgdSArKyApIHtcclxuXHJcblx0XHRjb25zdCB0bXAgPSBjbG9uZVVuaWZvcm1zKCB1bmlmb3Jtc1sgdSBdICk7XHJcblxyXG5cdFx0Zm9yICggY29uc3QgcCBpbiB0bXAgKSB7XHJcblxyXG5cdFx0XHRtZXJnZWRbIHAgXSA9IHRtcFsgcCBdO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4gbWVyZ2VkO1xyXG5cclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIGNsb25lVW5pZm9ybXNHcm91cHMoIHNyYyApIHtcclxuXHJcblx0Y29uc3QgZHN0ID0gW107XHJcblxyXG5cdGZvciAoIGxldCB1ID0gMDsgdSA8IHNyYy5sZW5ndGg7IHUgKysgKSB7XHJcblxyXG5cdFx0ZHN0LnB1c2goIHNyY1sgdSBdLmNsb25lKCkgKTtcclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4gZHN0O1xyXG5cclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIGdldFVubGl0VW5pZm9ybUNvbG9yU3BhY2UoIHJlbmRlcmVyICkge1xyXG5cclxuXHRpZiAoIHJlbmRlcmVyLmdldFJlbmRlclRhcmdldCgpID09PSBudWxsICkge1xyXG5cclxuXHRcdC8vIGh0dHBzOi8vZ2l0aHViLmNvbS9tcmRvb2IvdGhyZWUuanMvcHVsbC8yMzkzNyNpc3N1ZWNvbW1lbnQtMTExMTA2NzM5OFxyXG5cdFx0cmV0dXJuIHJlbmRlcmVyLm91dHB1dENvbG9yU3BhY2U7XHJcblxyXG5cdH1cclxuXHJcblx0cmV0dXJuIENvbG9yTWFuYWdlbWVudC53b3JraW5nQ29sb3JTcGFjZTtcclxuXHJcbn1cclxuXHJcbi8vIExlZ2FjeVxyXG5cclxuY29uc3QgVW5pZm9ybXNVdGlscyA9IHsgY2xvbmU6IGNsb25lVW5pZm9ybXMsIG1lcmdlOiBtZXJnZVVuaWZvcm1zIH07XHJcblxyXG5leHBvcnQgeyBVbmlmb3Jtc1V0aWxzIH07XHJcbiIsImV4cG9ydCBkZWZhdWx0IC8qIGdsc2wgKi9gXHJcbnZvaWQgbWFpbigpIHtcclxuXHRnbF9Qb3NpdGlvbiA9IHByb2plY3Rpb25NYXRyaXggKiBtb2RlbFZpZXdNYXRyaXggKiB2ZWM0KCBwb3NpdGlvbiwgMS4wICk7XHJcbn1cclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2Bcclxudm9pZCBtYWluKCkge1xyXG5cdGdsX0ZyYWdDb2xvciA9IHZlYzQoIDEuMCwgMC4wLCAwLjAsIDEuMCApO1xyXG59XHJcbmA7XHJcbiIsImltcG9ydCB7IE1hdGVyaWFsIH0gZnJvbSAnLi9NYXRlcmlhbC5qcyc7XHJcbmltcG9ydCB7IGNsb25lVW5pZm9ybXMsIGNsb25lVW5pZm9ybXNHcm91cHMgfSBmcm9tICcuLi9yZW5kZXJlcnMvc2hhZGVycy9Vbmlmb3Jtc1V0aWxzLmpzJztcclxuXHJcbmltcG9ydCBkZWZhdWx0X3ZlcnRleCBmcm9tICcuLi9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJDaHVuay9kZWZhdWx0X3ZlcnRleC5nbHNsLmpzJztcclxuaW1wb3J0IGRlZmF1bHRfZnJhZ21lbnQgZnJvbSAnLi4vcmVuZGVyZXJzL3NoYWRlcnMvU2hhZGVyQ2h1bmsvZGVmYXVsdF9mcmFnbWVudC5nbHNsLmpzJztcclxuXHJcbmNsYXNzIFNoYWRlck1hdGVyaWFsIGV4dGVuZHMgTWF0ZXJpYWwge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggcGFyYW1ldGVycyApIHtcclxuXHJcblx0XHRzdXBlcigpO1xyXG5cclxuXHRcdHRoaXMuaXNTaGFkZXJNYXRlcmlhbCA9IHRydWU7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ1NoYWRlck1hdGVyaWFsJztcclxuXHJcblx0XHR0aGlzLmRlZmluZXMgPSB7fTtcclxuXHRcdHRoaXMudW5pZm9ybXMgPSB7fTtcclxuXHRcdHRoaXMudW5pZm9ybXNHcm91cHMgPSBbXTtcclxuXHJcblx0XHR0aGlzLnZlcnRleFNoYWRlciA9IGRlZmF1bHRfdmVydGV4O1xyXG5cdFx0dGhpcy5mcmFnbWVudFNoYWRlciA9IGRlZmF1bHRfZnJhZ21lbnQ7XHJcblxyXG5cdFx0dGhpcy5saW5ld2lkdGggPSAxO1xyXG5cclxuXHRcdHRoaXMud2lyZWZyYW1lID0gZmFsc2U7XHJcblx0XHR0aGlzLndpcmVmcmFtZUxpbmV3aWR0aCA9IDE7XHJcblxyXG5cdFx0dGhpcy5mb2cgPSBmYWxzZTsgLy8gc2V0IHRvIHVzZSBzY2VuZSBmb2dcclxuXHRcdHRoaXMubGlnaHRzID0gZmFsc2U7IC8vIHNldCB0byB1c2Ugc2NlbmUgbGlnaHRzXHJcblx0XHR0aGlzLmNsaXBwaW5nID0gZmFsc2U7IC8vIHNldCB0byB1c2UgdXNlci1kZWZpbmVkIGNsaXBwaW5nIHBsYW5lc1xyXG5cclxuXHRcdHRoaXMuZm9yY2VTaW5nbGVQYXNzID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLmV4dGVuc2lvbnMgPSB7XHJcblx0XHRcdGRlcml2YXRpdmVzOiBmYWxzZSwgLy8gc2V0IHRvIHVzZSBkZXJpdmF0aXZlc1xyXG5cdFx0XHRmcmFnRGVwdGg6IGZhbHNlLCAvLyBzZXQgdG8gdXNlIGZyYWdtZW50IGRlcHRoIHZhbHVlc1xyXG5cdFx0XHRkcmF3QnVmZmVyczogZmFsc2UsIC8vIHNldCB0byB1c2UgZHJhdyBidWZmZXJzXHJcblx0XHRcdHNoYWRlclRleHR1cmVMT0Q6IGZhbHNlLCAvLyBzZXQgdG8gdXNlIHNoYWRlciB0ZXh0dXJlIExPRFxyXG5cdFx0XHRjbGlwQ3VsbERpc3RhbmNlOiBmYWxzZSwgLy8gc2V0IHRvIHVzZSB2ZXJ0ZXggc2hhZGVyIGNsaXBwaW5nXHJcblx0XHRcdG11bHRpRHJhdzogZmFsc2UgLy8gc2V0IHRvIHVzZSB2ZXJ0ZXggc2hhZGVyIG11bHRpX2RyYXcgLyBlbmFibGUgZ2xfRHJhd0lEXHJcblx0XHR9O1xyXG5cclxuXHRcdC8vIFdoZW4gcmVuZGVyZWQgZ2VvbWV0cnkgZG9lc24ndCBpbmNsdWRlIHRoZXNlIGF0dHJpYnV0ZXMgYnV0IHRoZSBtYXRlcmlhbCBkb2VzLFxyXG5cdFx0Ly8gdXNlIHRoZXNlIGRlZmF1bHQgdmFsdWVzIGluIFdlYkdMLiBUaGlzIGF2b2lkcyBlcnJvcnMgd2hlbiBidWZmZXIgZGF0YSBpcyBtaXNzaW5nLlxyXG5cdFx0dGhpcy5kZWZhdWx0QXR0cmlidXRlVmFsdWVzID0ge1xyXG5cdFx0XHQnY29sb3InOiBbIDEsIDEsIDEgXSxcclxuXHRcdFx0J3V2JzogWyAwLCAwIF0sXHJcblx0XHRcdCd1djEnOiBbIDAsIDAgXVxyXG5cdFx0fTtcclxuXHJcblx0XHR0aGlzLmluZGV4MEF0dHJpYnV0ZU5hbWUgPSB1bmRlZmluZWQ7XHJcblx0XHR0aGlzLnVuaWZvcm1zTmVlZFVwZGF0ZSA9IGZhbHNlO1xyXG5cclxuXHRcdHRoaXMuZ2xzbFZlcnNpb24gPSBudWxsO1xyXG5cclxuXHRcdGlmICggcGFyYW1ldGVycyAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0dGhpcy5zZXRWYWx1ZXMoIHBhcmFtZXRlcnMgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xyXG5cclxuXHRcdHRoaXMuZnJhZ21lbnRTaGFkZXIgPSBzb3VyY2UuZnJhZ21lbnRTaGFkZXI7XHJcblx0XHR0aGlzLnZlcnRleFNoYWRlciA9IHNvdXJjZS52ZXJ0ZXhTaGFkZXI7XHJcblxyXG5cdFx0dGhpcy51bmlmb3JtcyA9IGNsb25lVW5pZm9ybXMoIHNvdXJjZS51bmlmb3JtcyApO1xyXG5cdFx0dGhpcy51bmlmb3Jtc0dyb3VwcyA9IGNsb25lVW5pZm9ybXNHcm91cHMoIHNvdXJjZS51bmlmb3Jtc0dyb3VwcyApO1xyXG5cclxuXHRcdHRoaXMuZGVmaW5lcyA9IE9iamVjdC5hc3NpZ24oIHt9LCBzb3VyY2UuZGVmaW5lcyApO1xyXG5cclxuXHRcdHRoaXMud2lyZWZyYW1lID0gc291cmNlLndpcmVmcmFtZTtcclxuXHRcdHRoaXMud2lyZWZyYW1lTGluZXdpZHRoID0gc291cmNlLndpcmVmcmFtZUxpbmV3aWR0aDtcclxuXHJcblx0XHR0aGlzLmZvZyA9IHNvdXJjZS5mb2c7XHJcblx0XHR0aGlzLmxpZ2h0cyA9IHNvdXJjZS5saWdodHM7XHJcblx0XHR0aGlzLmNsaXBwaW5nID0gc291cmNlLmNsaXBwaW5nO1xyXG5cclxuXHRcdHRoaXMuZXh0ZW5zaW9ucyA9IE9iamVjdC5hc3NpZ24oIHt9LCBzb3VyY2UuZXh0ZW5zaW9ucyApO1xyXG5cclxuXHRcdHRoaXMuZ2xzbFZlcnNpb24gPSBzb3VyY2UuZ2xzbFZlcnNpb247XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0dG9KU09OKCBtZXRhICkge1xyXG5cclxuXHRcdGNvbnN0IGRhdGEgPSBzdXBlci50b0pTT04oIG1ldGEgKTtcclxuXHJcblx0XHRkYXRhLmdsc2xWZXJzaW9uID0gdGhpcy5nbHNsVmVyc2lvbjtcclxuXHRcdGRhdGEudW5pZm9ybXMgPSB7fTtcclxuXHJcblx0XHRmb3IgKCBjb25zdCBuYW1lIGluIHRoaXMudW5pZm9ybXMgKSB7XHJcblxyXG5cdFx0XHRjb25zdCB1bmlmb3JtID0gdGhpcy51bmlmb3Jtc1sgbmFtZSBdO1xyXG5cdFx0XHRjb25zdCB2YWx1ZSA9IHVuaWZvcm0udmFsdWU7XHJcblxyXG5cdFx0XHRpZiAoIHZhbHVlICYmIHZhbHVlLmlzVGV4dHVyZSApIHtcclxuXHJcblx0XHRcdFx0ZGF0YS51bmlmb3Jtc1sgbmFtZSBdID0ge1xyXG5cdFx0XHRcdFx0dHlwZTogJ3QnLFxyXG5cdFx0XHRcdFx0dmFsdWU6IHZhbHVlLnRvSlNPTiggbWV0YSApLnV1aWRcclxuXHRcdFx0XHR9O1xyXG5cclxuXHRcdFx0fSBlbHNlIGlmICggdmFsdWUgJiYgdmFsdWUuaXNDb2xvciApIHtcclxuXHJcblx0XHRcdFx0ZGF0YS51bmlmb3Jtc1sgbmFtZSBdID0ge1xyXG5cdFx0XHRcdFx0dHlwZTogJ2MnLFxyXG5cdFx0XHRcdFx0dmFsdWU6IHZhbHVlLmdldEhleCgpXHJcblx0XHRcdFx0fTtcclxuXHJcblx0XHRcdH0gZWxzZSBpZiAoIHZhbHVlICYmIHZhbHVlLmlzVmVjdG9yMiApIHtcclxuXHJcblx0XHRcdFx0ZGF0YS51bmlmb3Jtc1sgbmFtZSBdID0ge1xyXG5cdFx0XHRcdFx0dHlwZTogJ3YyJyxcclxuXHRcdFx0XHRcdHZhbHVlOiB2YWx1ZS50b0FycmF5KClcclxuXHRcdFx0XHR9O1xyXG5cclxuXHRcdFx0fSBlbHNlIGlmICggdmFsdWUgJiYgdmFsdWUuaXNWZWN0b3IzICkge1xyXG5cclxuXHRcdFx0XHRkYXRhLnVuaWZvcm1zWyBuYW1lIF0gPSB7XHJcblx0XHRcdFx0XHR0eXBlOiAndjMnLFxyXG5cdFx0XHRcdFx0dmFsdWU6IHZhbHVlLnRvQXJyYXkoKVxyXG5cdFx0XHRcdH07XHJcblxyXG5cdFx0XHR9IGVsc2UgaWYgKCB2YWx1ZSAmJiB2YWx1ZS5pc1ZlY3RvcjQgKSB7XHJcblxyXG5cdFx0XHRcdGRhdGEudW5pZm9ybXNbIG5hbWUgXSA9IHtcclxuXHRcdFx0XHRcdHR5cGU6ICd2NCcsXHJcblx0XHRcdFx0XHR2YWx1ZTogdmFsdWUudG9BcnJheSgpXHJcblx0XHRcdFx0fTtcclxuXHJcblx0XHRcdH0gZWxzZSBpZiAoIHZhbHVlICYmIHZhbHVlLmlzTWF0cml4MyApIHtcclxuXHJcblx0XHRcdFx0ZGF0YS51bmlmb3Jtc1sgbmFtZSBdID0ge1xyXG5cdFx0XHRcdFx0dHlwZTogJ20zJyxcclxuXHRcdFx0XHRcdHZhbHVlOiB2YWx1ZS50b0FycmF5KClcclxuXHRcdFx0XHR9O1xyXG5cclxuXHRcdFx0fSBlbHNlIGlmICggdmFsdWUgJiYgdmFsdWUuaXNNYXRyaXg0ICkge1xyXG5cclxuXHRcdFx0XHRkYXRhLnVuaWZvcm1zWyBuYW1lIF0gPSB7XHJcblx0XHRcdFx0XHR0eXBlOiAnbTQnLFxyXG5cdFx0XHRcdFx0dmFsdWU6IHZhbHVlLnRvQXJyYXkoKVxyXG5cdFx0XHRcdH07XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRkYXRhLnVuaWZvcm1zWyBuYW1lIF0gPSB7XHJcblx0XHRcdFx0XHR2YWx1ZTogdmFsdWVcclxuXHRcdFx0XHR9O1xyXG5cclxuXHRcdFx0XHQvLyBub3RlOiB0aGUgYXJyYXkgdmFyaWFudHMgdjJ2LCB2M3YsIHY0diwgbTR2IGFuZCB0diBhcmUgbm90IHN1cHBvcnRlZCBzbyBmYXJcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBPYmplY3Qua2V5cyggdGhpcy5kZWZpbmVzICkubGVuZ3RoID4gMCApIGRhdGEuZGVmaW5lcyA9IHRoaXMuZGVmaW5lcztcclxuXHJcblx0XHRkYXRhLnZlcnRleFNoYWRlciA9IHRoaXMudmVydGV4U2hhZGVyO1xyXG5cdFx0ZGF0YS5mcmFnbWVudFNoYWRlciA9IHRoaXMuZnJhZ21lbnRTaGFkZXI7XHJcblxyXG5cdFx0ZGF0YS5saWdodHMgPSB0aGlzLmxpZ2h0cztcclxuXHRcdGRhdGEuY2xpcHBpbmcgPSB0aGlzLmNsaXBwaW5nO1xyXG5cclxuXHRcdGNvbnN0IGV4dGVuc2lvbnMgPSB7fTtcclxuXHJcblx0XHRmb3IgKCBjb25zdCBrZXkgaW4gdGhpcy5leHRlbnNpb25zICkge1xyXG5cclxuXHRcdFx0aWYgKCB0aGlzLmV4dGVuc2lvbnNbIGtleSBdID09PSB0cnVlICkgZXh0ZW5zaW9uc1sga2V5IF0gPSB0cnVlO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIE9iamVjdC5rZXlzKCBleHRlbnNpb25zICkubGVuZ3RoID4gMCApIGRhdGEuZXh0ZW5zaW9ucyA9IGV4dGVuc2lvbnM7XHJcblxyXG5cdFx0cmV0dXJuIGRhdGE7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IFNoYWRlck1hdGVyaWFsIH07XHJcbiIsImltcG9ydCB7IFdlYkdMQ29vcmRpbmF0ZVN5c3RlbSB9IGZyb20gJy4uL2NvbnN0YW50cy5qcyc7XHJcbmltcG9ydCB7IE1hdHJpeDQgfSBmcm9tICcuLi9tYXRoL01hdHJpeDQuanMnO1xyXG5pbXBvcnQgeyBPYmplY3QzRCB9IGZyb20gJy4uL2NvcmUvT2JqZWN0M0QuanMnO1xyXG5cclxuY2xhc3MgQ2FtZXJhIGV4dGVuZHMgT2JqZWN0M0Qge1xyXG5cclxuXHRjb25zdHJ1Y3RvcigpIHtcclxuXHJcblx0XHRzdXBlcigpO1xyXG5cclxuXHRcdHRoaXMuaXNDYW1lcmEgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMudHlwZSA9ICdDYW1lcmEnO1xyXG5cclxuXHRcdHRoaXMubWF0cml4V29ybGRJbnZlcnNlID0gbmV3IE1hdHJpeDQoKTtcclxuXHJcblx0XHR0aGlzLnByb2plY3Rpb25NYXRyaXggPSBuZXcgTWF0cml4NCgpO1xyXG5cdFx0dGhpcy5wcm9qZWN0aW9uTWF0cml4SW52ZXJzZSA9IG5ldyBNYXRyaXg0KCk7XHJcblxyXG5cdFx0dGhpcy5jb29yZGluYXRlU3lzdGVtID0gV2ViR0xDb29yZGluYXRlU3lzdGVtO1xyXG5cclxuXHR9XHJcblxyXG5cdGNvcHkoIHNvdXJjZSwgcmVjdXJzaXZlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSwgcmVjdXJzaXZlICk7XHJcblxyXG5cdFx0dGhpcy5tYXRyaXhXb3JsZEludmVyc2UuY29weSggc291cmNlLm1hdHJpeFdvcmxkSW52ZXJzZSApO1xyXG5cclxuXHRcdHRoaXMucHJvamVjdGlvbk1hdHJpeC5jb3B5KCBzb3VyY2UucHJvamVjdGlvbk1hdHJpeCApO1xyXG5cdFx0dGhpcy5wcm9qZWN0aW9uTWF0cml4SW52ZXJzZS5jb3B5KCBzb3VyY2UucHJvamVjdGlvbk1hdHJpeEludmVyc2UgKTtcclxuXHJcblx0XHR0aGlzLmNvb3JkaW5hdGVTeXN0ZW0gPSBzb3VyY2UuY29vcmRpbmF0ZVN5c3RlbTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRnZXRXb3JsZERpcmVjdGlvbiggdGFyZ2V0ICkge1xyXG5cclxuXHRcdHJldHVybiBzdXBlci5nZXRXb3JsZERpcmVjdGlvbiggdGFyZ2V0ICkubmVnYXRlKCk7XHJcblxyXG5cdH1cclxuXHJcblx0dXBkYXRlTWF0cml4V29ybGQoIGZvcmNlICkge1xyXG5cclxuXHRcdHN1cGVyLnVwZGF0ZU1hdHJpeFdvcmxkKCBmb3JjZSApO1xyXG5cclxuXHRcdHRoaXMubWF0cml4V29ybGRJbnZlcnNlLmNvcHkoIHRoaXMubWF0cml4V29ybGQgKS5pbnZlcnQoKTtcclxuXHJcblx0fVxyXG5cclxuXHR1cGRhdGVXb3JsZE1hdHJpeCggdXBkYXRlUGFyZW50cywgdXBkYXRlQ2hpbGRyZW4gKSB7XHJcblxyXG5cdFx0c3VwZXIudXBkYXRlV29ybGRNYXRyaXgoIHVwZGF0ZVBhcmVudHMsIHVwZGF0ZUNoaWxkcmVuICk7XHJcblxyXG5cdFx0dGhpcy5tYXRyaXhXb3JsZEludmVyc2UuY29weSggdGhpcy5tYXRyaXhXb3JsZCApLmludmVydCgpO1xyXG5cclxuXHR9XHJcblxyXG5cdGNsb25lKCkge1xyXG5cclxuXHRcdHJldHVybiBuZXcgdGhpcy5jb25zdHJ1Y3RvcigpLmNvcHkoIHRoaXMgKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgQ2FtZXJhIH07XHJcbiIsImltcG9ydCB7IENhbWVyYSB9IGZyb20gJy4vQ2FtZXJhLmpzJztcclxuaW1wb3J0ICogYXMgTWF0aFV0aWxzIGZyb20gJy4uL21hdGgvTWF0aFV0aWxzLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yMiB9IGZyb20gJy4uL21hdGgvVmVjdG9yMi5qcyc7XHJcbmltcG9ydCB7IFZlY3RvcjMgfSBmcm9tICcuLi9tYXRoL1ZlY3RvcjMuanMnO1xyXG5cclxuY29uc3QgX3YzID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5jb25zdCBfbWluVGFyZ2V0ID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMigpO1xyXG5jb25zdCBfbWF4VGFyZ2V0ID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMigpO1xyXG5cclxuXHJcbmNsYXNzIFBlcnNwZWN0aXZlQ2FtZXJhIGV4dGVuZHMgQ2FtZXJhIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIGZvdiA9IDUwLCBhc3BlY3QgPSAxLCBuZWFyID0gMC4xLCBmYXIgPSAyMDAwICkge1xyXG5cclxuXHRcdHN1cGVyKCk7XHJcblxyXG5cdFx0dGhpcy5pc1BlcnNwZWN0aXZlQ2FtZXJhID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSAnUGVyc3BlY3RpdmVDYW1lcmEnO1xyXG5cclxuXHRcdHRoaXMuZm92ID0gZm92O1xyXG5cdFx0dGhpcy56b29tID0gMTtcclxuXHJcblx0XHR0aGlzLm5lYXIgPSBuZWFyO1xyXG5cdFx0dGhpcy5mYXIgPSBmYXI7XHJcblx0XHR0aGlzLmZvY3VzID0gMTA7XHJcblxyXG5cdFx0dGhpcy5hc3BlY3QgPSBhc3BlY3Q7XHJcblx0XHR0aGlzLnZpZXcgPSBudWxsO1xyXG5cclxuXHRcdHRoaXMuZmlsbUdhdWdlID0gMzU7XHQvLyB3aWR0aCBvZiB0aGUgZmlsbSAoZGVmYXVsdCBpbiBtaWxsaW1ldGVycylcclxuXHRcdHRoaXMuZmlsbU9mZnNldCA9IDA7XHQvLyBob3Jpem9udGFsIGZpbG0gb2Zmc2V0IChzYW1lIHVuaXQgYXMgZ2F1Z2UpXHJcblxyXG5cdFx0dGhpcy51cGRhdGVQcm9qZWN0aW9uTWF0cml4KCk7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlLCByZWN1cnNpdmUgKSB7XHJcblxyXG5cdFx0c3VwZXIuY29weSggc291cmNlLCByZWN1cnNpdmUgKTtcclxuXHJcblx0XHR0aGlzLmZvdiA9IHNvdXJjZS5mb3Y7XHJcblx0XHR0aGlzLnpvb20gPSBzb3VyY2Uuem9vbTtcclxuXHJcblx0XHR0aGlzLm5lYXIgPSBzb3VyY2UubmVhcjtcclxuXHRcdHRoaXMuZmFyID0gc291cmNlLmZhcjtcclxuXHRcdHRoaXMuZm9jdXMgPSBzb3VyY2UuZm9jdXM7XHJcblxyXG5cdFx0dGhpcy5hc3BlY3QgPSBzb3VyY2UuYXNwZWN0O1xyXG5cdFx0dGhpcy52aWV3ID0gc291cmNlLnZpZXcgPT09IG51bGwgPyBudWxsIDogT2JqZWN0LmFzc2lnbigge30sIHNvdXJjZS52aWV3ICk7XHJcblxyXG5cdFx0dGhpcy5maWxtR2F1Z2UgPSBzb3VyY2UuZmlsbUdhdWdlO1xyXG5cdFx0dGhpcy5maWxtT2Zmc2V0ID0gc291cmNlLmZpbG1PZmZzZXQ7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0LyoqXHJcblx0ICogU2V0cyB0aGUgRk9WIGJ5IGZvY2FsIGxlbmd0aCBpbiByZXNwZWN0IHRvIHRoZSBjdXJyZW50IC5maWxtR2F1Z2UuXHJcblx0ICpcclxuXHQgKiBUaGUgZGVmYXVsdCBmaWxtIGdhdWdlIGlzIDM1LCBzbyB0aGF0IHRoZSBmb2NhbCBsZW5ndGggY2FuIGJlIHNwZWNpZmllZCBmb3JcclxuXHQgKiBhIDM1bW0gKGZ1bGwgZnJhbWUpIGNhbWVyYS5cclxuXHQgKlxyXG5cdCAqIFZhbHVlcyBmb3IgZm9jYWwgbGVuZ3RoIGFuZCBmaWxtIGdhdWdlIG11c3QgaGF2ZSB0aGUgc2FtZSB1bml0LlxyXG5cdCAqL1xyXG5cdHNldEZvY2FsTGVuZ3RoKCBmb2NhbExlbmd0aCApIHtcclxuXHJcblx0XHQvKiogc2VlIHtAbGluayBodHRwOi8vd3d3LmJvYmF0a2lucy5jb20vcGhvdG9ncmFwaHkvdGVjaG5pY2FsL2ZpZWxkX29mX3ZpZXcuaHRtbH0gKi9cclxuXHRcdGNvbnN0IHZFeHRlbnRTbG9wZSA9IDAuNSAqIHRoaXMuZ2V0RmlsbUhlaWdodCgpIC8gZm9jYWxMZW5ndGg7XHJcblxyXG5cdFx0dGhpcy5mb3YgPSBNYXRoVXRpbHMuUkFEMkRFRyAqIDIgKiBNYXRoLmF0YW4oIHZFeHRlbnRTbG9wZSApO1xyXG5cdFx0dGhpcy51cGRhdGVQcm9qZWN0aW9uTWF0cml4KCk7XHJcblxyXG5cdH1cclxuXHJcblx0LyoqXHJcblx0ICogQ2FsY3VsYXRlcyB0aGUgZm9jYWwgbGVuZ3RoIGZyb20gdGhlIGN1cnJlbnQgLmZvdiBhbmQgLmZpbG1HYXVnZS5cclxuXHQgKi9cclxuXHRnZXRGb2NhbExlbmd0aCgpIHtcclxuXHJcblx0XHRjb25zdCB2RXh0ZW50U2xvcGUgPSBNYXRoLnRhbiggTWF0aFV0aWxzLkRFRzJSQUQgKiAwLjUgKiB0aGlzLmZvdiApO1xyXG5cclxuXHRcdHJldHVybiAwLjUgKiB0aGlzLmdldEZpbG1IZWlnaHQoKSAvIHZFeHRlbnRTbG9wZTtcclxuXHJcblx0fVxyXG5cclxuXHRnZXRFZmZlY3RpdmVGT1YoKSB7XHJcblxyXG5cdFx0cmV0dXJuIE1hdGhVdGlscy5SQUQyREVHICogMiAqIE1hdGguYXRhbihcclxuXHRcdFx0TWF0aC50YW4oIE1hdGhVdGlscy5ERUcyUkFEICogMC41ICogdGhpcy5mb3YgKSAvIHRoaXMuem9vbSApO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldEZpbG1XaWR0aCgpIHtcclxuXHJcblx0XHQvLyBmaWxtIG5vdCBjb21wbGV0ZWx5IGNvdmVyZWQgaW4gcG9ydHJhaXQgZm9ybWF0IChhc3BlY3QgPCAxKVxyXG5cdFx0cmV0dXJuIHRoaXMuZmlsbUdhdWdlICogTWF0aC5taW4oIHRoaXMuYXNwZWN0LCAxICk7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0RmlsbUhlaWdodCgpIHtcclxuXHJcblx0XHQvLyBmaWxtIG5vdCBjb21wbGV0ZWx5IGNvdmVyZWQgaW4gbGFuZHNjYXBlIGZvcm1hdCAoYXNwZWN0ID4gMSlcclxuXHRcdHJldHVybiB0aGlzLmZpbG1HYXVnZSAvIE1hdGgubWF4KCB0aGlzLmFzcGVjdCwgMSApO1xyXG5cclxuXHR9XHJcblxyXG5cdC8qKlxyXG5cdCAqIENvbXB1dGVzIHRoZSAyRCBib3VuZHMgb2YgdGhlIGNhbWVyYSdzIHZpZXdhYmxlIHJlY3RhbmdsZSBhdCBhIGdpdmVuIGRpc3RhbmNlIGFsb25nIHRoZSB2aWV3aW5nIGRpcmVjdGlvbi5cclxuXHQgKiBTZXRzIG1pblRhcmdldCBhbmQgbWF4VGFyZ2V0IHRvIHRoZSBjb29yZGluYXRlcyBvZiB0aGUgbG93ZXItbGVmdCBhbmQgdXBwZXItcmlnaHQgY29ybmVycyBvZiB0aGUgdmlldyByZWN0YW5nbGUuXHJcblx0ICovXHJcblx0Z2V0Vmlld0JvdW5kcyggZGlzdGFuY2UsIG1pblRhcmdldCwgbWF4VGFyZ2V0ICkge1xyXG5cclxuXHRcdF92My5zZXQoIC0gMSwgLSAxLCAwLjUgKS5hcHBseU1hdHJpeDQoIHRoaXMucHJvamVjdGlvbk1hdHJpeEludmVyc2UgKTtcclxuXHJcblx0XHRtaW5UYXJnZXQuc2V0KCBfdjMueCwgX3YzLnkgKS5tdWx0aXBseVNjYWxhciggLSBkaXN0YW5jZSAvIF92My56ICk7XHJcblxyXG5cdFx0X3YzLnNldCggMSwgMSwgMC41ICkuYXBwbHlNYXRyaXg0KCB0aGlzLnByb2plY3Rpb25NYXRyaXhJbnZlcnNlICk7XHJcblxyXG5cdFx0bWF4VGFyZ2V0LnNldCggX3YzLngsIF92My55ICkubXVsdGlwbHlTY2FsYXIoIC0gZGlzdGFuY2UgLyBfdjMueiApO1xyXG5cclxuXHR9XHJcblxyXG5cdC8qKlxyXG5cdCAqIENvbXB1dGVzIHRoZSB3aWR0aCBhbmQgaGVpZ2h0IG9mIHRoZSBjYW1lcmEncyB2aWV3YWJsZSByZWN0YW5nbGUgYXQgYSBnaXZlbiBkaXN0YW5jZSBhbG9uZyB0aGUgdmlld2luZyBkaXJlY3Rpb24uXHJcblx0ICogQ29waWVzIHRoZSByZXN1bHQgaW50byB0aGUgdGFyZ2V0IFZlY3RvcjIsIHdoZXJlIHggaXMgd2lkdGggYW5kIHkgaXMgaGVpZ2h0LlxyXG5cdCAqL1xyXG5cdGdldFZpZXdTaXplKCBkaXN0YW5jZSwgdGFyZ2V0ICkge1xyXG5cclxuXHRcdHRoaXMuZ2V0Vmlld0JvdW5kcyggZGlzdGFuY2UsIF9taW5UYXJnZXQsIF9tYXhUYXJnZXQgKTtcclxuXHJcblx0XHRyZXR1cm4gdGFyZ2V0LnN1YlZlY3RvcnMoIF9tYXhUYXJnZXQsIF9taW5UYXJnZXQgKTtcclxuXHJcblx0fVxyXG5cclxuXHQvKipcclxuXHQgKiBTZXRzIGFuIG9mZnNldCBpbiBhIGxhcmdlciBmcnVzdHVtLiBUaGlzIGlzIHVzZWZ1bCBmb3IgbXVsdGktd2luZG93IG9yXHJcblx0ICogbXVsdGktbW9uaXRvci9tdWx0aS1tYWNoaW5lIHNldHVwcy5cclxuXHQgKlxyXG5cdCAqIEZvciBleGFtcGxlLCBpZiB5b3UgaGF2ZSAzeDIgbW9uaXRvcnMgYW5kIGVhY2ggbW9uaXRvciBpcyAxOTIweDEwODAgYW5kXHJcblx0ICogdGhlIG1vbml0b3JzIGFyZSBpbiBncmlkIGxpa2UgdGhpc1xyXG5cdCAqXHJcblx0ICogICArLS0tKy0tLSstLS0rXHJcblx0ICogICB8IEEgfCBCIHwgQyB8XHJcblx0ICogICArLS0tKy0tLSstLS0rXHJcblx0ICogICB8IEQgfCBFIHwgRiB8XHJcblx0ICogICArLS0tKy0tLSstLS0rXHJcblx0ICpcclxuXHQgKiB0aGVuIGZvciBlYWNoIG1vbml0b3IgeW91IHdvdWxkIGNhbGwgaXQgbGlrZSB0aGlzXHJcblx0ICpcclxuXHQgKiAgIGNvbnN0IHcgPSAxOTIwO1xyXG5cdCAqICAgY29uc3QgaCA9IDEwODA7XHJcblx0ICogICBjb25zdCBmdWxsV2lkdGggPSB3ICogMztcclxuXHQgKiAgIGNvbnN0IGZ1bGxIZWlnaHQgPSBoICogMjtcclxuXHQgKlxyXG5cdCAqICAgLS1BLS1cclxuXHQgKiAgIGNhbWVyYS5zZXRWaWV3T2Zmc2V0KCBmdWxsV2lkdGgsIGZ1bGxIZWlnaHQsIHcgKiAwLCBoICogMCwgdywgaCApO1xyXG5cdCAqICAgLS1CLS1cclxuXHQgKiAgIGNhbWVyYS5zZXRWaWV3T2Zmc2V0KCBmdWxsV2lkdGgsIGZ1bGxIZWlnaHQsIHcgKiAxLCBoICogMCwgdywgaCApO1xyXG5cdCAqICAgLS1DLS1cclxuXHQgKiAgIGNhbWVyYS5zZXRWaWV3T2Zmc2V0KCBmdWxsV2lkdGgsIGZ1bGxIZWlnaHQsIHcgKiAyLCBoICogMCwgdywgaCApO1xyXG5cdCAqICAgLS1ELS1cclxuXHQgKiAgIGNhbWVyYS5zZXRWaWV3T2Zmc2V0KCBmdWxsV2lkdGgsIGZ1bGxIZWlnaHQsIHcgKiAwLCBoICogMSwgdywgaCApO1xyXG5cdCAqICAgLS1FLS1cclxuXHQgKiAgIGNhbWVyYS5zZXRWaWV3T2Zmc2V0KCBmdWxsV2lkdGgsIGZ1bGxIZWlnaHQsIHcgKiAxLCBoICogMSwgdywgaCApO1xyXG5cdCAqICAgLS1GLS1cclxuXHQgKiAgIGNhbWVyYS5zZXRWaWV3T2Zmc2V0KCBmdWxsV2lkdGgsIGZ1bGxIZWlnaHQsIHcgKiAyLCBoICogMSwgdywgaCApO1xyXG5cdCAqXHJcblx0ICogICBOb3RlIHRoZXJlIGlzIG5vIHJlYXNvbiBtb25pdG9ycyBoYXZlIHRvIGJlIHRoZSBzYW1lIHNpemUgb3IgaW4gYSBncmlkLlxyXG5cdCAqL1xyXG5cdHNldFZpZXdPZmZzZXQoIGZ1bGxXaWR0aCwgZnVsbEhlaWdodCwgeCwgeSwgd2lkdGgsIGhlaWdodCApIHtcclxuXHJcblx0XHR0aGlzLmFzcGVjdCA9IGZ1bGxXaWR0aCAvIGZ1bGxIZWlnaHQ7XHJcblxyXG5cdFx0aWYgKCB0aGlzLnZpZXcgPT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHR0aGlzLnZpZXcgPSB7XHJcblx0XHRcdFx0ZW5hYmxlZDogdHJ1ZSxcclxuXHRcdFx0XHRmdWxsV2lkdGg6IDEsXHJcblx0XHRcdFx0ZnVsbEhlaWdodDogMSxcclxuXHRcdFx0XHRvZmZzZXRYOiAwLFxyXG5cdFx0XHRcdG9mZnNldFk6IDAsXHJcblx0XHRcdFx0d2lkdGg6IDEsXHJcblx0XHRcdFx0aGVpZ2h0OiAxXHJcblx0XHRcdH07XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMudmlldy5lbmFibGVkID0gdHJ1ZTtcclxuXHRcdHRoaXMudmlldy5mdWxsV2lkdGggPSBmdWxsV2lkdGg7XHJcblx0XHR0aGlzLnZpZXcuZnVsbEhlaWdodCA9IGZ1bGxIZWlnaHQ7XHJcblx0XHR0aGlzLnZpZXcub2Zmc2V0WCA9IHg7XHJcblx0XHR0aGlzLnZpZXcub2Zmc2V0WSA9IHk7XHJcblx0XHR0aGlzLnZpZXcud2lkdGggPSB3aWR0aDtcclxuXHRcdHRoaXMudmlldy5oZWlnaHQgPSBoZWlnaHQ7XHJcblxyXG5cdFx0dGhpcy51cGRhdGVQcm9qZWN0aW9uTWF0cml4KCk7XHJcblxyXG5cdH1cclxuXHJcblx0Y2xlYXJWaWV3T2Zmc2V0KCkge1xyXG5cclxuXHRcdGlmICggdGhpcy52aWV3ICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0dGhpcy52aWV3LmVuYWJsZWQgPSBmYWxzZTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy51cGRhdGVQcm9qZWN0aW9uTWF0cml4KCk7XHJcblxyXG5cdH1cclxuXHJcblx0dXBkYXRlUHJvamVjdGlvbk1hdHJpeCgpIHtcclxuXHJcblx0XHRjb25zdCBuZWFyID0gdGhpcy5uZWFyO1xyXG5cdFx0bGV0IHRvcCA9IG5lYXIgKiBNYXRoLnRhbiggTWF0aFV0aWxzLkRFRzJSQUQgKiAwLjUgKiB0aGlzLmZvdiApIC8gdGhpcy56b29tO1xyXG5cdFx0bGV0IGhlaWdodCA9IDIgKiB0b3A7XHJcblx0XHRsZXQgd2lkdGggPSB0aGlzLmFzcGVjdCAqIGhlaWdodDtcclxuXHRcdGxldCBsZWZ0ID0gLSAwLjUgKiB3aWR0aDtcclxuXHRcdGNvbnN0IHZpZXcgPSB0aGlzLnZpZXc7XHJcblxyXG5cdFx0aWYgKCB0aGlzLnZpZXcgIT09IG51bGwgJiYgdGhpcy52aWV3LmVuYWJsZWQgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBmdWxsV2lkdGggPSB2aWV3LmZ1bGxXaWR0aCxcclxuXHRcdFx0XHRmdWxsSGVpZ2h0ID0gdmlldy5mdWxsSGVpZ2h0O1xyXG5cclxuXHRcdFx0bGVmdCArPSB2aWV3Lm9mZnNldFggKiB3aWR0aCAvIGZ1bGxXaWR0aDtcclxuXHRcdFx0dG9wIC09IHZpZXcub2Zmc2V0WSAqIGhlaWdodCAvIGZ1bGxIZWlnaHQ7XHJcblx0XHRcdHdpZHRoICo9IHZpZXcud2lkdGggLyBmdWxsV2lkdGg7XHJcblx0XHRcdGhlaWdodCAqPSB2aWV3LmhlaWdodCAvIGZ1bGxIZWlnaHQ7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGNvbnN0IHNrZXcgPSB0aGlzLmZpbG1PZmZzZXQ7XHJcblx0XHRpZiAoIHNrZXcgIT09IDAgKSBsZWZ0ICs9IG5lYXIgKiBza2V3IC8gdGhpcy5nZXRGaWxtV2lkdGgoKTtcclxuXHJcblx0XHR0aGlzLnByb2plY3Rpb25NYXRyaXgubWFrZVBlcnNwZWN0aXZlKCBsZWZ0LCBsZWZ0ICsgd2lkdGgsIHRvcCwgdG9wIC0gaGVpZ2h0LCBuZWFyLCB0aGlzLmZhciwgdGhpcy5jb29yZGluYXRlU3lzdGVtICk7XHJcblxyXG5cdFx0dGhpcy5wcm9qZWN0aW9uTWF0cml4SW52ZXJzZS5jb3B5KCB0aGlzLnByb2plY3Rpb25NYXRyaXggKS5pbnZlcnQoKTtcclxuXHJcblx0fVxyXG5cclxuXHR0b0pTT04oIG1ldGEgKSB7XHJcblxyXG5cdFx0Y29uc3QgZGF0YSA9IHN1cGVyLnRvSlNPTiggbWV0YSApO1xyXG5cclxuXHRcdGRhdGEub2JqZWN0LmZvdiA9IHRoaXMuZm92O1xyXG5cdFx0ZGF0YS5vYmplY3Quem9vbSA9IHRoaXMuem9vbTtcclxuXHJcblx0XHRkYXRhLm9iamVjdC5uZWFyID0gdGhpcy5uZWFyO1xyXG5cdFx0ZGF0YS5vYmplY3QuZmFyID0gdGhpcy5mYXI7XHJcblx0XHRkYXRhLm9iamVjdC5mb2N1cyA9IHRoaXMuZm9jdXM7XHJcblxyXG5cdFx0ZGF0YS5vYmplY3QuYXNwZWN0ID0gdGhpcy5hc3BlY3Q7XHJcblxyXG5cdFx0aWYgKCB0aGlzLnZpZXcgIT09IG51bGwgKSBkYXRhLm9iamVjdC52aWV3ID0gT2JqZWN0LmFzc2lnbigge30sIHRoaXMudmlldyApO1xyXG5cclxuXHRcdGRhdGEub2JqZWN0LmZpbG1HYXVnZSA9IHRoaXMuZmlsbUdhdWdlO1xyXG5cdFx0ZGF0YS5vYmplY3QuZmlsbU9mZnNldCA9IHRoaXMuZmlsbU9mZnNldDtcclxuXHJcblx0XHRyZXR1cm4gZGF0YTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgUGVyc3BlY3RpdmVDYW1lcmEgfTtcclxuIiwiaW1wb3J0IHsgV2ViR0xDb29yZGluYXRlU3lzdGVtLCBXZWJHUFVDb29yZGluYXRlU3lzdGVtIH0gZnJvbSAnLi4vY29uc3RhbnRzLmpzJztcclxuaW1wb3J0IHsgT2JqZWN0M0QgfSBmcm9tICcuLi9jb3JlL09iamVjdDNELmpzJztcclxuaW1wb3J0IHsgUGVyc3BlY3RpdmVDYW1lcmEgfSBmcm9tICcuL1BlcnNwZWN0aXZlQ2FtZXJhLmpzJztcclxuXHJcbmNvbnN0IGZvdiA9IC0gOTA7IC8vIG5lZ2F0aXZlIGZvdiBpcyBub3QgYW4gZXJyb3JcclxuY29uc3QgYXNwZWN0ID0gMTtcclxuXHJcbmNsYXNzIEN1YmVDYW1lcmEgZXh0ZW5kcyBPYmplY3QzRCB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBuZWFyLCBmYXIsIHJlbmRlclRhcmdldCApIHtcclxuXHJcblx0XHRzdXBlcigpO1xyXG5cclxuXHRcdHRoaXMudHlwZSA9ICdDdWJlQ2FtZXJhJztcclxuXHJcblx0XHR0aGlzLnJlbmRlclRhcmdldCA9IHJlbmRlclRhcmdldDtcclxuXHRcdHRoaXMuY29vcmRpbmF0ZVN5c3RlbSA9IG51bGw7XHJcblx0XHR0aGlzLmFjdGl2ZU1pcG1hcExldmVsID0gMDtcclxuXHJcblx0XHRjb25zdCBjYW1lcmFQWCA9IG5ldyBQZXJzcGVjdGl2ZUNhbWVyYSggZm92LCBhc3BlY3QsIG5lYXIsIGZhciApO1xyXG5cdFx0Y2FtZXJhUFgubGF5ZXJzID0gdGhpcy5sYXllcnM7XHJcblx0XHR0aGlzLmFkZCggY2FtZXJhUFggKTtcclxuXHJcblx0XHRjb25zdCBjYW1lcmFOWCA9IG5ldyBQZXJzcGVjdGl2ZUNhbWVyYSggZm92LCBhc3BlY3QsIG5lYXIsIGZhciApO1xyXG5cdFx0Y2FtZXJhTlgubGF5ZXJzID0gdGhpcy5sYXllcnM7XHJcblx0XHR0aGlzLmFkZCggY2FtZXJhTlggKTtcclxuXHJcblx0XHRjb25zdCBjYW1lcmFQWSA9IG5ldyBQZXJzcGVjdGl2ZUNhbWVyYSggZm92LCBhc3BlY3QsIG5lYXIsIGZhciApO1xyXG5cdFx0Y2FtZXJhUFkubGF5ZXJzID0gdGhpcy5sYXllcnM7XHJcblx0XHR0aGlzLmFkZCggY2FtZXJhUFkgKTtcclxuXHJcblx0XHRjb25zdCBjYW1lcmFOWSA9IG5ldyBQZXJzcGVjdGl2ZUNhbWVyYSggZm92LCBhc3BlY3QsIG5lYXIsIGZhciApO1xyXG5cdFx0Y2FtZXJhTlkubGF5ZXJzID0gdGhpcy5sYXllcnM7XHJcblx0XHR0aGlzLmFkZCggY2FtZXJhTlkgKTtcclxuXHJcblx0XHRjb25zdCBjYW1lcmFQWiA9IG5ldyBQZXJzcGVjdGl2ZUNhbWVyYSggZm92LCBhc3BlY3QsIG5lYXIsIGZhciApO1xyXG5cdFx0Y2FtZXJhUFoubGF5ZXJzID0gdGhpcy5sYXllcnM7XHJcblx0XHR0aGlzLmFkZCggY2FtZXJhUFogKTtcclxuXHJcblx0XHRjb25zdCBjYW1lcmFOWiA9IG5ldyBQZXJzcGVjdGl2ZUNhbWVyYSggZm92LCBhc3BlY3QsIG5lYXIsIGZhciApO1xyXG5cdFx0Y2FtZXJhTloubGF5ZXJzID0gdGhpcy5sYXllcnM7XHJcblx0XHR0aGlzLmFkZCggY2FtZXJhTlogKTtcclxuXHJcblx0fVxyXG5cclxuXHR1cGRhdGVDb29yZGluYXRlU3lzdGVtKCkge1xyXG5cclxuXHRcdGNvbnN0IGNvb3JkaW5hdGVTeXN0ZW0gPSB0aGlzLmNvb3JkaW5hdGVTeXN0ZW07XHJcblxyXG5cdFx0Y29uc3QgY2FtZXJhcyA9IHRoaXMuY2hpbGRyZW4uY29uY2F0KCk7XHJcblxyXG5cdFx0Y29uc3QgWyBjYW1lcmFQWCwgY2FtZXJhTlgsIGNhbWVyYVBZLCBjYW1lcmFOWSwgY2FtZXJhUFosIGNhbWVyYU5aIF0gPSBjYW1lcmFzO1xyXG5cclxuXHRcdGZvciAoIGNvbnN0IGNhbWVyYSBvZiBjYW1lcmFzICkgdGhpcy5yZW1vdmUoIGNhbWVyYSApO1xyXG5cclxuXHRcdGlmICggY29vcmRpbmF0ZVN5c3RlbSA9PT0gV2ViR0xDb29yZGluYXRlU3lzdGVtICkge1xyXG5cclxuXHRcdFx0Y2FtZXJhUFgudXAuc2V0KCAwLCAxLCAwICk7XHJcblx0XHRcdGNhbWVyYVBYLmxvb2tBdCggMSwgMCwgMCApO1xyXG5cclxuXHRcdFx0Y2FtZXJhTlgudXAuc2V0KCAwLCAxLCAwICk7XHJcblx0XHRcdGNhbWVyYU5YLmxvb2tBdCggLSAxLCAwLCAwICk7XHJcblxyXG5cdFx0XHRjYW1lcmFQWS51cC5zZXQoIDAsIDAsIC0gMSApO1xyXG5cdFx0XHRjYW1lcmFQWS5sb29rQXQoIDAsIDEsIDAgKTtcclxuXHJcblx0XHRcdGNhbWVyYU5ZLnVwLnNldCggMCwgMCwgMSApO1xyXG5cdFx0XHRjYW1lcmFOWS5sb29rQXQoIDAsIC0gMSwgMCApO1xyXG5cclxuXHRcdFx0Y2FtZXJhUFoudXAuc2V0KCAwLCAxLCAwICk7XHJcblx0XHRcdGNhbWVyYVBaLmxvb2tBdCggMCwgMCwgMSApO1xyXG5cclxuXHRcdFx0Y2FtZXJhTloudXAuc2V0KCAwLCAxLCAwICk7XHJcblx0XHRcdGNhbWVyYU5aLmxvb2tBdCggMCwgMCwgLSAxICk7XHJcblxyXG5cdFx0fSBlbHNlIGlmICggY29vcmRpbmF0ZVN5c3RlbSA9PT0gV2ViR1BVQ29vcmRpbmF0ZVN5c3RlbSApIHtcclxuXHJcblx0XHRcdGNhbWVyYVBYLnVwLnNldCggMCwgLSAxLCAwICk7XHJcblx0XHRcdGNhbWVyYVBYLmxvb2tBdCggLSAxLCAwLCAwICk7XHJcblxyXG5cdFx0XHRjYW1lcmFOWC51cC5zZXQoIDAsIC0gMSwgMCApO1xyXG5cdFx0XHRjYW1lcmFOWC5sb29rQXQoIDEsIDAsIDAgKTtcclxuXHJcblx0XHRcdGNhbWVyYVBZLnVwLnNldCggMCwgMCwgMSApO1xyXG5cdFx0XHRjYW1lcmFQWS5sb29rQXQoIDAsIDEsIDAgKTtcclxuXHJcblx0XHRcdGNhbWVyYU5ZLnVwLnNldCggMCwgMCwgLSAxICk7XHJcblx0XHRcdGNhbWVyYU5ZLmxvb2tBdCggMCwgLSAxLCAwICk7XHJcblxyXG5cdFx0XHRjYW1lcmFQWi51cC5zZXQoIDAsIC0gMSwgMCApO1xyXG5cdFx0XHRjYW1lcmFQWi5sb29rQXQoIDAsIDAsIDEgKTtcclxuXHJcblx0XHRcdGNhbWVyYU5aLnVwLnNldCggMCwgLSAxLCAwICk7XHJcblx0XHRcdGNhbWVyYU5aLmxvb2tBdCggMCwgMCwgLSAxICk7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdHRocm93IG5ldyBFcnJvciggJ1RIUkVFLkN1YmVDYW1lcmEudXBkYXRlQ29vcmRpbmF0ZVN5c3RlbSgpOiBJbnZhbGlkIGNvb3JkaW5hdGUgc3lzdGVtOiAnICsgY29vcmRpbmF0ZVN5c3RlbSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRmb3IgKCBjb25zdCBjYW1lcmEgb2YgY2FtZXJhcyApIHtcclxuXHJcblx0XHRcdHRoaXMuYWRkKCBjYW1lcmEgKTtcclxuXHJcblx0XHRcdGNhbWVyYS51cGRhdGVNYXRyaXhXb3JsZCgpO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHR1cGRhdGUoIHJlbmRlcmVyLCBzY2VuZSApIHtcclxuXHJcblx0XHRpZiAoIHRoaXMucGFyZW50ID09PSBudWxsICkgdGhpcy51cGRhdGVNYXRyaXhXb3JsZCgpO1xyXG5cclxuXHRcdGNvbnN0IHsgcmVuZGVyVGFyZ2V0LCBhY3RpdmVNaXBtYXBMZXZlbCB9ID0gdGhpcztcclxuXHJcblx0XHRpZiAoIHRoaXMuY29vcmRpbmF0ZVN5c3RlbSAhPT0gcmVuZGVyZXIuY29vcmRpbmF0ZVN5c3RlbSApIHtcclxuXHJcblx0XHRcdHRoaXMuY29vcmRpbmF0ZVN5c3RlbSA9IHJlbmRlcmVyLmNvb3JkaW5hdGVTeXN0ZW07XHJcblxyXG5cdFx0XHR0aGlzLnVwZGF0ZUNvb3JkaW5hdGVTeXN0ZW0oKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Y29uc3QgWyBjYW1lcmFQWCwgY2FtZXJhTlgsIGNhbWVyYVBZLCBjYW1lcmFOWSwgY2FtZXJhUFosIGNhbWVyYU5aIF0gPSB0aGlzLmNoaWxkcmVuO1xyXG5cclxuXHRcdGNvbnN0IGN1cnJlbnRSZW5kZXJUYXJnZXQgPSByZW5kZXJlci5nZXRSZW5kZXJUYXJnZXQoKTtcclxuXHRcdGNvbnN0IGN1cnJlbnRBY3RpdmVDdWJlRmFjZSA9IHJlbmRlcmVyLmdldEFjdGl2ZUN1YmVGYWNlKCk7XHJcblx0XHRjb25zdCBjdXJyZW50QWN0aXZlTWlwbWFwTGV2ZWwgPSByZW5kZXJlci5nZXRBY3RpdmVNaXBtYXBMZXZlbCgpO1xyXG5cclxuXHRcdGNvbnN0IGN1cnJlbnRYckVuYWJsZWQgPSByZW5kZXJlci54ci5lbmFibGVkO1xyXG5cclxuXHRcdHJlbmRlcmVyLnhyLmVuYWJsZWQgPSBmYWxzZTtcclxuXHJcblx0XHRjb25zdCBnZW5lcmF0ZU1pcG1hcHMgPSByZW5kZXJUYXJnZXQudGV4dHVyZS5nZW5lcmF0ZU1pcG1hcHM7XHJcblxyXG5cdFx0cmVuZGVyVGFyZ2V0LnRleHR1cmUuZ2VuZXJhdGVNaXBtYXBzID0gZmFsc2U7XHJcblxyXG5cdFx0cmVuZGVyZXIuc2V0UmVuZGVyVGFyZ2V0KCByZW5kZXJUYXJnZXQsIDAsIGFjdGl2ZU1pcG1hcExldmVsICk7XHJcblx0XHRyZW5kZXJlci5yZW5kZXIoIHNjZW5lLCBjYW1lcmFQWCApO1xyXG5cclxuXHRcdHJlbmRlcmVyLnNldFJlbmRlclRhcmdldCggcmVuZGVyVGFyZ2V0LCAxLCBhY3RpdmVNaXBtYXBMZXZlbCApO1xyXG5cdFx0cmVuZGVyZXIucmVuZGVyKCBzY2VuZSwgY2FtZXJhTlggKTtcclxuXHJcblx0XHRyZW5kZXJlci5zZXRSZW5kZXJUYXJnZXQoIHJlbmRlclRhcmdldCwgMiwgYWN0aXZlTWlwbWFwTGV2ZWwgKTtcclxuXHRcdHJlbmRlcmVyLnJlbmRlciggc2NlbmUsIGNhbWVyYVBZICk7XHJcblxyXG5cdFx0cmVuZGVyZXIuc2V0UmVuZGVyVGFyZ2V0KCByZW5kZXJUYXJnZXQsIDMsIGFjdGl2ZU1pcG1hcExldmVsICk7XHJcblx0XHRyZW5kZXJlci5yZW5kZXIoIHNjZW5lLCBjYW1lcmFOWSApO1xyXG5cclxuXHRcdHJlbmRlcmVyLnNldFJlbmRlclRhcmdldCggcmVuZGVyVGFyZ2V0LCA0LCBhY3RpdmVNaXBtYXBMZXZlbCApO1xyXG5cdFx0cmVuZGVyZXIucmVuZGVyKCBzY2VuZSwgY2FtZXJhUFogKTtcclxuXHJcblx0XHQvLyBtaXBtYXBzIGFyZSBnZW5lcmF0ZWQgZHVyaW5nIHRoZSBsYXN0IGNhbGwgb2YgcmVuZGVyKClcclxuXHRcdC8vIGF0IHRoaXMgcG9pbnQsIGFsbCBzaWRlcyBvZiB0aGUgY3ViZSByZW5kZXIgdGFyZ2V0IGFyZSBkZWZpbmVkXHJcblxyXG5cdFx0cmVuZGVyVGFyZ2V0LnRleHR1cmUuZ2VuZXJhdGVNaXBtYXBzID0gZ2VuZXJhdGVNaXBtYXBzO1xyXG5cclxuXHRcdHJlbmRlcmVyLnNldFJlbmRlclRhcmdldCggcmVuZGVyVGFyZ2V0LCA1LCBhY3RpdmVNaXBtYXBMZXZlbCApO1xyXG5cdFx0cmVuZGVyZXIucmVuZGVyKCBzY2VuZSwgY2FtZXJhTlogKTtcclxuXHJcblx0XHRyZW5kZXJlci5zZXRSZW5kZXJUYXJnZXQoIGN1cnJlbnRSZW5kZXJUYXJnZXQsIGN1cnJlbnRBY3RpdmVDdWJlRmFjZSwgY3VycmVudEFjdGl2ZU1pcG1hcExldmVsICk7XHJcblxyXG5cdFx0cmVuZGVyZXIueHIuZW5hYmxlZCA9IGN1cnJlbnRYckVuYWJsZWQ7XHJcblxyXG5cdFx0cmVuZGVyVGFyZ2V0LnRleHR1cmUubmVlZHNQTVJFTVVwZGF0ZSA9IHRydWU7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IEN1YmVDYW1lcmEgfTtcclxuIiwiaW1wb3J0IHsgVGV4dHVyZSB9IGZyb20gJy4vVGV4dHVyZS5qcyc7XHJcbmltcG9ydCB7IEN1YmVSZWZsZWN0aW9uTWFwcGluZyB9IGZyb20gJy4uL2NvbnN0YW50cy5qcyc7XHJcblxyXG5jbGFzcyBDdWJlVGV4dHVyZSBleHRlbmRzIFRleHR1cmUge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggaW1hZ2VzLCBtYXBwaW5nLCB3cmFwUywgd3JhcFQsIG1hZ0ZpbHRlciwgbWluRmlsdGVyLCBmb3JtYXQsIHR5cGUsIGFuaXNvdHJvcHksIGNvbG9yU3BhY2UgKSB7XHJcblxyXG5cdFx0aW1hZ2VzID0gaW1hZ2VzICE9PSB1bmRlZmluZWQgPyBpbWFnZXMgOiBbXTtcclxuXHRcdG1hcHBpbmcgPSBtYXBwaW5nICE9PSB1bmRlZmluZWQgPyBtYXBwaW5nIDogQ3ViZVJlZmxlY3Rpb25NYXBwaW5nO1xyXG5cclxuXHRcdHN1cGVyKCBpbWFnZXMsIG1hcHBpbmcsIHdyYXBTLCB3cmFwVCwgbWFnRmlsdGVyLCBtaW5GaWx0ZXIsIGZvcm1hdCwgdHlwZSwgYW5pc290cm9weSwgY29sb3JTcGFjZSApO1xyXG5cclxuXHRcdHRoaXMuaXNDdWJlVGV4dHVyZSA9IHRydWU7XHJcblxyXG5cdFx0dGhpcy5mbGlwWSA9IGZhbHNlO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldCBpbWFnZXMoKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuaW1hZ2U7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0IGltYWdlcyggdmFsdWUgKSB7XHJcblxyXG5cdFx0dGhpcy5pbWFnZSA9IHZhbHVlO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBDdWJlVGV4dHVyZSB9O1xyXG4iLCJpbXBvcnQgeyBCYWNrU2lkZSwgTGluZWFyRmlsdGVyLCBMaW5lYXJNaXBtYXBMaW5lYXJGaWx0ZXIsIE5vQmxlbmRpbmcgfSBmcm9tICcuLi9jb25zdGFudHMuanMnO1xyXG5pbXBvcnQgeyBNZXNoIH0gZnJvbSAnLi4vb2JqZWN0cy9NZXNoLmpzJztcclxuaW1wb3J0IHsgQm94R2VvbWV0cnkgfSBmcm9tICcuLi9nZW9tZXRyaWVzL0JveEdlb21ldHJ5LmpzJztcclxuaW1wb3J0IHsgU2hhZGVyTWF0ZXJpYWwgfSBmcm9tICcuLi9tYXRlcmlhbHMvU2hhZGVyTWF0ZXJpYWwuanMnO1xyXG5pbXBvcnQgeyBjbG9uZVVuaWZvcm1zIH0gZnJvbSAnLi9zaGFkZXJzL1VuaWZvcm1zVXRpbHMuanMnO1xyXG5pbXBvcnQgeyBXZWJHTFJlbmRlclRhcmdldCB9IGZyb20gJy4vV2ViR0xSZW5kZXJUYXJnZXQuanMnO1xyXG5pbXBvcnQgeyBDdWJlQ2FtZXJhIH0gZnJvbSAnLi4vY2FtZXJhcy9DdWJlQ2FtZXJhLmpzJztcclxuaW1wb3J0IHsgQ3ViZVRleHR1cmUgfSBmcm9tICcuLi90ZXh0dXJlcy9DdWJlVGV4dHVyZS5qcyc7XHJcblxyXG5jbGFzcyBXZWJHTEN1YmVSZW5kZXJUYXJnZXQgZXh0ZW5kcyBXZWJHTFJlbmRlclRhcmdldCB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBzaXplID0gMSwgb3B0aW9ucyA9IHt9ICkge1xyXG5cclxuXHRcdHN1cGVyKCBzaXplLCBzaXplLCBvcHRpb25zICk7XHJcblxyXG5cdFx0dGhpcy5pc1dlYkdMQ3ViZVJlbmRlclRhcmdldCA9IHRydWU7XHJcblxyXG5cdFx0Y29uc3QgaW1hZ2UgPSB7IHdpZHRoOiBzaXplLCBoZWlnaHQ6IHNpemUsIGRlcHRoOiAxIH07XHJcblx0XHRjb25zdCBpbWFnZXMgPSBbIGltYWdlLCBpbWFnZSwgaW1hZ2UsIGltYWdlLCBpbWFnZSwgaW1hZ2UgXTtcclxuXHJcblx0XHR0aGlzLnRleHR1cmUgPSBuZXcgQ3ViZVRleHR1cmUoIGltYWdlcywgb3B0aW9ucy5tYXBwaW5nLCBvcHRpb25zLndyYXBTLCBvcHRpb25zLndyYXBULCBvcHRpb25zLm1hZ0ZpbHRlciwgb3B0aW9ucy5taW5GaWx0ZXIsIG9wdGlvbnMuZm9ybWF0LCBvcHRpb25zLnR5cGUsIG9wdGlvbnMuYW5pc290cm9weSwgb3B0aW9ucy5jb2xvclNwYWNlICk7XHJcblxyXG5cdFx0Ly8gQnkgY29udmVudGlvbiAtLSBsaWtlbHkgYmFzZWQgb24gdGhlIFJlbmRlck1hbiBzcGVjIGZyb20gdGhlIDE5OTAncyAtLSBjdWJlIG1hcHMgYXJlIHNwZWNpZmllZCBieSBXZWJHTCAoYW5kIHRocmVlLmpzKVxyXG5cdFx0Ly8gaW4gYSBjb29yZGluYXRlIHN5c3RlbSBpbiB3aGljaCBwb3NpdGl2ZS14IGlzIHRvIHRoZSByaWdodCB3aGVuIGxvb2tpbmcgdXAgdGhlIHBvc2l0aXZlLXogYXhpcyAtLSBpbiBvdGhlciB3b3JkcyxcclxuXHRcdC8vIGluIGEgbGVmdC1oYW5kZWQgY29vcmRpbmF0ZSBzeXN0ZW0uIEJ5IGNvbnRpbnVpbmcgdGhpcyBjb252ZW50aW9uLCBwcmVleGlzdGluZyBjdWJlIG1hcHMgY29udGludWVkIHRvIHJlbmRlciBjb3JyZWN0bHkuXHJcblxyXG5cdFx0Ly8gdGhyZWUuanMgdXNlcyBhIHJpZ2h0LWhhbmRlZCBjb29yZGluYXRlIHN5c3RlbS4gU28gZW52aXJvbm1lbnQgbWFwcyB1c2VkIGluIHRocmVlLmpzIGFwcGVhciB0byBoYXZlIHB4IGFuZCBueCBzd2FwcGVkXHJcblx0XHQvLyBhbmQgdGhlIGZsYWcgaXNSZW5kZXJUYXJnZXRUZXh0dXJlIGNvbnRyb2xzIHRoaXMgY29udmVyc2lvbi4gVGhlIGZsaXAgaXMgbm90IHJlcXVpcmVkIHdoZW4gdXNpbmcgV2ViR0xDdWJlUmVuZGVyVGFyZ2V0LnRleHR1cmVcclxuXHRcdC8vIGFzIGEgY3ViZSB0ZXh0dXJlICh0aGlzIGlzIGRldGVjdGVkIHdoZW4gaXNSZW5kZXJUYXJnZXRUZXh0dXJlIGlzIHNldCB0byB0cnVlIGZvciBjdWJlIHRleHR1cmVzKS5cclxuXHJcblx0XHR0aGlzLnRleHR1cmUuaXNSZW5kZXJUYXJnZXRUZXh0dXJlID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLnRleHR1cmUuZ2VuZXJhdGVNaXBtYXBzID0gb3B0aW9ucy5nZW5lcmF0ZU1pcG1hcHMgIT09IHVuZGVmaW5lZCA/IG9wdGlvbnMuZ2VuZXJhdGVNaXBtYXBzIDogZmFsc2U7XHJcblx0XHR0aGlzLnRleHR1cmUubWluRmlsdGVyID0gb3B0aW9ucy5taW5GaWx0ZXIgIT09IHVuZGVmaW5lZCA/IG9wdGlvbnMubWluRmlsdGVyIDogTGluZWFyRmlsdGVyO1xyXG5cclxuXHR9XHJcblxyXG5cdGZyb21FcXVpcmVjdGFuZ3VsYXJUZXh0dXJlKCByZW5kZXJlciwgdGV4dHVyZSApIHtcclxuXHJcblx0XHR0aGlzLnRleHR1cmUudHlwZSA9IHRleHR1cmUudHlwZTtcclxuXHRcdHRoaXMudGV4dHVyZS5jb2xvclNwYWNlID0gdGV4dHVyZS5jb2xvclNwYWNlO1xyXG5cclxuXHRcdHRoaXMudGV4dHVyZS5nZW5lcmF0ZU1pcG1hcHMgPSB0ZXh0dXJlLmdlbmVyYXRlTWlwbWFwcztcclxuXHRcdHRoaXMudGV4dHVyZS5taW5GaWx0ZXIgPSB0ZXh0dXJlLm1pbkZpbHRlcjtcclxuXHRcdHRoaXMudGV4dHVyZS5tYWdGaWx0ZXIgPSB0ZXh0dXJlLm1hZ0ZpbHRlcjtcclxuXHJcblx0XHRjb25zdCBzaGFkZXIgPSB7XHJcblxyXG5cdFx0XHR1bmlmb3Jtczoge1xyXG5cdFx0XHRcdHRFcXVpcmVjdDogeyB2YWx1ZTogbnVsbCB9LFxyXG5cdFx0XHR9LFxyXG5cclxuXHRcdFx0dmVydGV4U2hhZGVyOiAvKiBnbHNsICovYFxyXG5cclxuXHRcdFx0XHR2YXJ5aW5nIHZlYzMgdldvcmxkRGlyZWN0aW9uO1xyXG5cclxuXHRcdFx0XHR2ZWMzIHRyYW5zZm9ybURpcmVjdGlvbiggaW4gdmVjMyBkaXIsIGluIG1hdDQgbWF0cml4ICkge1xyXG5cclxuXHRcdFx0XHRcdHJldHVybiBub3JtYWxpemUoICggbWF0cml4ICogdmVjNCggZGlyLCAwLjAgKSApLnh5eiApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdHZvaWQgbWFpbigpIHtcclxuXHJcblx0XHRcdFx0XHR2V29ybGREaXJlY3Rpb24gPSB0cmFuc2Zvcm1EaXJlY3Rpb24oIHBvc2l0aW9uLCBtb2RlbE1hdHJpeCApO1xyXG5cclxuXHRcdFx0XHRcdCNpbmNsdWRlIDxiZWdpbl92ZXJ0ZXg+XHJcblx0XHRcdFx0XHQjaW5jbHVkZSA8cHJvamVjdF92ZXJ0ZXg+XHJcblxyXG5cdFx0XHRcdH1cclxuXHRcdFx0YCxcclxuXHJcblx0XHRcdGZyYWdtZW50U2hhZGVyOiAvKiBnbHNsICovYFxyXG5cclxuXHRcdFx0XHR1bmlmb3JtIHNhbXBsZXIyRCB0RXF1aXJlY3Q7XHJcblxyXG5cdFx0XHRcdHZhcnlpbmcgdmVjMyB2V29ybGREaXJlY3Rpb247XHJcblxyXG5cdFx0XHRcdCNpbmNsdWRlIDxjb21tb24+XHJcblxyXG5cdFx0XHRcdHZvaWQgbWFpbigpIHtcclxuXHJcblx0XHRcdFx0XHR2ZWMzIGRpcmVjdGlvbiA9IG5vcm1hbGl6ZSggdldvcmxkRGlyZWN0aW9uICk7XHJcblxyXG5cdFx0XHRcdFx0dmVjMiBzYW1wbGVVViA9IGVxdWlyZWN0VXYoIGRpcmVjdGlvbiApO1xyXG5cclxuXHRcdFx0XHRcdGdsX0ZyYWdDb2xvciA9IHRleHR1cmUyRCggdEVxdWlyZWN0LCBzYW1wbGVVViApO1xyXG5cclxuXHRcdFx0XHR9XHJcblx0XHRcdGBcclxuXHRcdH07XHJcblxyXG5cdFx0Y29uc3QgZ2VvbWV0cnkgPSBuZXcgQm94R2VvbWV0cnkoIDUsIDUsIDUgKTtcclxuXHJcblx0XHRjb25zdCBtYXRlcmlhbCA9IG5ldyBTaGFkZXJNYXRlcmlhbCgge1xyXG5cclxuXHRcdFx0bmFtZTogJ0N1YmVtYXBGcm9tRXF1aXJlY3QnLFxyXG5cclxuXHRcdFx0dW5pZm9ybXM6IGNsb25lVW5pZm9ybXMoIHNoYWRlci51bmlmb3JtcyApLFxyXG5cdFx0XHR2ZXJ0ZXhTaGFkZXI6IHNoYWRlci52ZXJ0ZXhTaGFkZXIsXHJcblx0XHRcdGZyYWdtZW50U2hhZGVyOiBzaGFkZXIuZnJhZ21lbnRTaGFkZXIsXHJcblx0XHRcdHNpZGU6IEJhY2tTaWRlLFxyXG5cdFx0XHRibGVuZGluZzogTm9CbGVuZGluZ1xyXG5cclxuXHRcdH0gKTtcclxuXHJcblx0XHRtYXRlcmlhbC51bmlmb3Jtcy50RXF1aXJlY3QudmFsdWUgPSB0ZXh0dXJlO1xyXG5cclxuXHRcdGNvbnN0IG1lc2ggPSBuZXcgTWVzaCggZ2VvbWV0cnksIG1hdGVyaWFsICk7XHJcblxyXG5cdFx0Y29uc3QgY3VycmVudE1pbkZpbHRlciA9IHRleHR1cmUubWluRmlsdGVyO1xyXG5cclxuXHRcdC8vIEF2b2lkIGJsdXJyZWQgcG9sZXNcclxuXHRcdGlmICggdGV4dHVyZS5taW5GaWx0ZXIgPT09IExpbmVhck1pcG1hcExpbmVhckZpbHRlciApIHRleHR1cmUubWluRmlsdGVyID0gTGluZWFyRmlsdGVyO1xyXG5cclxuXHRcdGNvbnN0IGNhbWVyYSA9IG5ldyBDdWJlQ2FtZXJhKCAxLCAxMCwgdGhpcyApO1xyXG5cdFx0Y2FtZXJhLnVwZGF0ZSggcmVuZGVyZXIsIG1lc2ggKTtcclxuXHJcblx0XHR0ZXh0dXJlLm1pbkZpbHRlciA9IGN1cnJlbnRNaW5GaWx0ZXI7XHJcblxyXG5cdFx0bWVzaC5nZW9tZXRyeS5kaXNwb3NlKCk7XHJcblx0XHRtZXNoLm1hdGVyaWFsLmRpc3Bvc2UoKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRjbGVhciggcmVuZGVyZXIsIGNvbG9yLCBkZXB0aCwgc3RlbmNpbCApIHtcclxuXHJcblx0XHRjb25zdCBjdXJyZW50UmVuZGVyVGFyZ2V0ID0gcmVuZGVyZXIuZ2V0UmVuZGVyVGFyZ2V0KCk7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgNjsgaSArKyApIHtcclxuXHJcblx0XHRcdHJlbmRlcmVyLnNldFJlbmRlclRhcmdldCggdGhpcywgaSApO1xyXG5cclxuXHRcdFx0cmVuZGVyZXIuY2xlYXIoIGNvbG9yLCBkZXB0aCwgc3RlbmNpbCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZW5kZXJlci5zZXRSZW5kZXJUYXJnZXQoIGN1cnJlbnRSZW5kZXJUYXJnZXQgKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgV2ViR0xDdWJlUmVuZGVyVGFyZ2V0IH07XHJcbiIsImltcG9ydCB7IE1hdHJpeDMgfSBmcm9tICcuL01hdHJpeDMuanMnO1xyXG5pbXBvcnQgeyBWZWN0b3IzIH0gZnJvbSAnLi9WZWN0b3IzLmpzJztcclxuXHJcbmNvbnN0IF92ZWN0b3IxID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5jb25zdCBfdmVjdG9yMiA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuY29uc3QgX25vcm1hbE1hdHJpeCA9IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDMoKTtcclxuXHJcbmNsYXNzIFBsYW5lIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIG5vcm1hbCA9IG5ldyBWZWN0b3IzKCAxLCAwLCAwICksIGNvbnN0YW50ID0gMCApIHtcclxuXHJcblx0XHR0aGlzLmlzUGxhbmUgPSB0cnVlO1xyXG5cclxuXHRcdC8vIG5vcm1hbCBpcyBhc3N1bWVkIHRvIGJlIG5vcm1hbGl6ZWRcclxuXHJcblx0XHR0aGlzLm5vcm1hbCA9IG5vcm1hbDtcclxuXHRcdHRoaXMuY29uc3RhbnQgPSBjb25zdGFudDtcclxuXHJcblx0fVxyXG5cclxuXHRzZXQoIG5vcm1hbCwgY29uc3RhbnQgKSB7XHJcblxyXG5cdFx0dGhpcy5ub3JtYWwuY29weSggbm9ybWFsICk7XHJcblx0XHR0aGlzLmNvbnN0YW50ID0gY29uc3RhbnQ7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0Q29tcG9uZW50cyggeCwgeSwgeiwgdyApIHtcclxuXHJcblx0XHR0aGlzLm5vcm1hbC5zZXQoIHgsIHksIHogKTtcclxuXHRcdHRoaXMuY29uc3RhbnQgPSB3O1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldEZyb21Ob3JtYWxBbmRDb3BsYW5hclBvaW50KCBub3JtYWwsIHBvaW50ICkge1xyXG5cclxuXHRcdHRoaXMubm9ybWFsLmNvcHkoIG5vcm1hbCApO1xyXG5cdFx0dGhpcy5jb25zdGFudCA9IC0gcG9pbnQuZG90KCB0aGlzLm5vcm1hbCApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldEZyb21Db3BsYW5hclBvaW50cyggYSwgYiwgYyApIHtcclxuXHJcblx0XHRjb25zdCBub3JtYWwgPSBfdmVjdG9yMS5zdWJWZWN0b3JzKCBjLCBiICkuY3Jvc3MoIF92ZWN0b3IyLnN1YlZlY3RvcnMoIGEsIGIgKSApLm5vcm1hbGl6ZSgpO1xyXG5cclxuXHRcdC8vIFE6IHNob3VsZCBhbiBlcnJvciBiZSB0aHJvd24gaWYgbm9ybWFsIGlzIHplcm8gKGUuZy4gZGVnZW5lcmF0ZSBwbGFuZSk/XHJcblxyXG5cdFx0dGhpcy5zZXRGcm9tTm9ybWFsQW5kQ29wbGFuYXJQb2ludCggbm9ybWFsLCBhICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggcGxhbmUgKSB7XHJcblxyXG5cdFx0dGhpcy5ub3JtYWwuY29weSggcGxhbmUubm9ybWFsICk7XHJcblx0XHR0aGlzLmNvbnN0YW50ID0gcGxhbmUuY29uc3RhbnQ7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0bm9ybWFsaXplKCkge1xyXG5cclxuXHRcdC8vIE5vdGU6IHdpbGwgbGVhZCB0byBhIGRpdmlkZSBieSB6ZXJvIGlmIHRoZSBwbGFuZSBpcyBpbnZhbGlkLlxyXG5cclxuXHRcdGNvbnN0IGludmVyc2VOb3JtYWxMZW5ndGggPSAxLjAgLyB0aGlzLm5vcm1hbC5sZW5ndGgoKTtcclxuXHRcdHRoaXMubm9ybWFsLm11bHRpcGx5U2NhbGFyKCBpbnZlcnNlTm9ybWFsTGVuZ3RoICk7XHJcblx0XHR0aGlzLmNvbnN0YW50ICo9IGludmVyc2VOb3JtYWxMZW5ndGg7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0bmVnYXRlKCkge1xyXG5cclxuXHRcdHRoaXMuY29uc3RhbnQgKj0gLSAxO1xyXG5cdFx0dGhpcy5ub3JtYWwubmVnYXRlKCk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0ZGlzdGFuY2VUb1BvaW50KCBwb2ludCApIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5ub3JtYWwuZG90KCBwb2ludCApICsgdGhpcy5jb25zdGFudDtcclxuXHJcblx0fVxyXG5cclxuXHRkaXN0YW5jZVRvU3BoZXJlKCBzcGhlcmUgKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuZGlzdGFuY2VUb1BvaW50KCBzcGhlcmUuY2VudGVyICkgLSBzcGhlcmUucmFkaXVzO1xyXG5cclxuXHR9XHJcblxyXG5cdHByb2plY3RQb2ludCggcG9pbnQsIHRhcmdldCApIHtcclxuXHJcblx0XHRyZXR1cm4gdGFyZ2V0LmNvcHkoIHBvaW50ICkuYWRkU2NhbGVkVmVjdG9yKCB0aGlzLm5vcm1hbCwgLSB0aGlzLmRpc3RhbmNlVG9Qb2ludCggcG9pbnQgKSApO1xyXG5cclxuXHR9XHJcblxyXG5cdGludGVyc2VjdExpbmUoIGxpbmUsIHRhcmdldCApIHtcclxuXHJcblx0XHRjb25zdCBkaXJlY3Rpb24gPSBsaW5lLmRlbHRhKCBfdmVjdG9yMSApO1xyXG5cclxuXHRcdGNvbnN0IGRlbm9taW5hdG9yID0gdGhpcy5ub3JtYWwuZG90KCBkaXJlY3Rpb24gKTtcclxuXHJcblx0XHRpZiAoIGRlbm9taW5hdG9yID09PSAwICkge1xyXG5cclxuXHRcdFx0Ly8gbGluZSBpcyBjb3BsYW5hciwgcmV0dXJuIG9yaWdpblxyXG5cdFx0XHRpZiAoIHRoaXMuZGlzdGFuY2VUb1BvaW50KCBsaW5lLnN0YXJ0ICkgPT09IDAgKSB7XHJcblxyXG5cdFx0XHRcdHJldHVybiB0YXJnZXQuY29weSggbGluZS5zdGFydCApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Ly8gVW5zdXJlIGlmIHRoaXMgaXMgdGhlIGNvcnJlY3QgbWV0aG9kIHRvIGhhbmRsZSB0aGlzIGNhc2UuXHJcblx0XHRcdHJldHVybiBudWxsO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCB0ID0gLSAoIGxpbmUuc3RhcnQuZG90KCB0aGlzLm5vcm1hbCApICsgdGhpcy5jb25zdGFudCApIC8gZGVub21pbmF0b3I7XHJcblxyXG5cdFx0aWYgKCB0IDwgMCB8fCB0ID4gMSApIHtcclxuXHJcblx0XHRcdHJldHVybiBudWxsO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGFyZ2V0LmNvcHkoIGxpbmUuc3RhcnQgKS5hZGRTY2FsZWRWZWN0b3IoIGRpcmVjdGlvbiwgdCApO1xyXG5cclxuXHR9XHJcblxyXG5cdGludGVyc2VjdHNMaW5lKCBsaW5lICkge1xyXG5cclxuXHRcdC8vIE5vdGU6IHRoaXMgdGVzdHMgaWYgYSBsaW5lIGludGVyc2VjdHMgdGhlIHBsYW5lLCBub3Qgd2hldGhlciBpdCAob3IgaXRzIGVuZC1wb2ludHMpIGFyZSBjb3BsYW5hciB3aXRoIGl0LlxyXG5cclxuXHRcdGNvbnN0IHN0YXJ0U2lnbiA9IHRoaXMuZGlzdGFuY2VUb1BvaW50KCBsaW5lLnN0YXJ0ICk7XHJcblx0XHRjb25zdCBlbmRTaWduID0gdGhpcy5kaXN0YW5jZVRvUG9pbnQoIGxpbmUuZW5kICk7XHJcblxyXG5cdFx0cmV0dXJuICggc3RhcnRTaWduIDwgMCAmJiBlbmRTaWduID4gMCApIHx8ICggZW5kU2lnbiA8IDAgJiYgc3RhcnRTaWduID4gMCApO1xyXG5cclxuXHR9XHJcblxyXG5cdGludGVyc2VjdHNCb3goIGJveCApIHtcclxuXHJcblx0XHRyZXR1cm4gYm94LmludGVyc2VjdHNQbGFuZSggdGhpcyApO1xyXG5cclxuXHR9XHJcblxyXG5cdGludGVyc2VjdHNTcGhlcmUoIHNwaGVyZSApIHtcclxuXHJcblx0XHRyZXR1cm4gc3BoZXJlLmludGVyc2VjdHNQbGFuZSggdGhpcyApO1xyXG5cclxuXHR9XHJcblxyXG5cdGNvcGxhbmFyUG9pbnQoIHRhcmdldCApIHtcclxuXHJcblx0XHRyZXR1cm4gdGFyZ2V0LmNvcHkoIHRoaXMubm9ybWFsICkubXVsdGlwbHlTY2FsYXIoIC0gdGhpcy5jb25zdGFudCApO1xyXG5cclxuXHR9XHJcblxyXG5cdGFwcGx5TWF0cml4NCggbWF0cml4LCBvcHRpb25hbE5vcm1hbE1hdHJpeCApIHtcclxuXHJcblx0XHRjb25zdCBub3JtYWxNYXRyaXggPSBvcHRpb25hbE5vcm1hbE1hdHJpeCB8fCBfbm9ybWFsTWF0cml4LmdldE5vcm1hbE1hdHJpeCggbWF0cml4ICk7XHJcblxyXG5cdFx0Y29uc3QgcmVmZXJlbmNlUG9pbnQgPSB0aGlzLmNvcGxhbmFyUG9pbnQoIF92ZWN0b3IxICkuYXBwbHlNYXRyaXg0KCBtYXRyaXggKTtcclxuXHJcblx0XHRjb25zdCBub3JtYWwgPSB0aGlzLm5vcm1hbC5hcHBseU1hdHJpeDMoIG5vcm1hbE1hdHJpeCApLm5vcm1hbGl6ZSgpO1xyXG5cclxuXHRcdHRoaXMuY29uc3RhbnQgPSAtIHJlZmVyZW5jZVBvaW50LmRvdCggbm9ybWFsICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0dHJhbnNsYXRlKCBvZmZzZXQgKSB7XHJcblxyXG5cdFx0dGhpcy5jb25zdGFudCAtPSBvZmZzZXQuZG90KCB0aGlzLm5vcm1hbCApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGVxdWFscyggcGxhbmUgKSB7XHJcblxyXG5cdFx0cmV0dXJuIHBsYW5lLm5vcm1hbC5lcXVhbHMoIHRoaXMubm9ybWFsICkgJiYgKCBwbGFuZS5jb25zdGFudCA9PT0gdGhpcy5jb25zdGFudCApO1xyXG5cclxuXHR9XHJcblxyXG5cdGNsb25lKCkge1xyXG5cclxuXHRcdHJldHVybiBuZXcgdGhpcy5jb25zdHJ1Y3RvcigpLmNvcHkoIHRoaXMgKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgUGxhbmUgfTtcclxuIiwiaW1wb3J0IHsgV2ViR0xDb29yZGluYXRlU3lzdGVtLCBXZWJHUFVDb29yZGluYXRlU3lzdGVtIH0gZnJvbSAnLi4vY29uc3RhbnRzLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yMyB9IGZyb20gJy4vVmVjdG9yMy5qcyc7XHJcbmltcG9ydCB7IFNwaGVyZSB9IGZyb20gJy4vU3BoZXJlLmpzJztcclxuaW1wb3J0IHsgUGxhbmUgfSBmcm9tICcuL1BsYW5lLmpzJztcclxuXHJcbmNvbnN0IF9zcGhlcmUgPSAvKkBfX1BVUkVfXyovIG5ldyBTcGhlcmUoKTtcclxuY29uc3QgX3ZlY3RvciA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuXHJcbmNsYXNzIEZydXN0dW0ge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggcDAgPSBuZXcgUGxhbmUoKSwgcDEgPSBuZXcgUGxhbmUoKSwgcDIgPSBuZXcgUGxhbmUoKSwgcDMgPSBuZXcgUGxhbmUoKSwgcDQgPSBuZXcgUGxhbmUoKSwgcDUgPSBuZXcgUGxhbmUoKSApIHtcclxuXHJcblx0XHR0aGlzLnBsYW5lcyA9IFsgcDAsIHAxLCBwMiwgcDMsIHA0LCBwNSBdO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldCggcDAsIHAxLCBwMiwgcDMsIHA0LCBwNSApIHtcclxuXHJcblx0XHRjb25zdCBwbGFuZXMgPSB0aGlzLnBsYW5lcztcclxuXHJcblx0XHRwbGFuZXNbIDAgXS5jb3B5KCBwMCApO1xyXG5cdFx0cGxhbmVzWyAxIF0uY29weSggcDEgKTtcclxuXHRcdHBsYW5lc1sgMiBdLmNvcHkoIHAyICk7XHJcblx0XHRwbGFuZXNbIDMgXS5jb3B5KCBwMyApO1xyXG5cdFx0cGxhbmVzWyA0IF0uY29weSggcDQgKTtcclxuXHRcdHBsYW5lc1sgNSBdLmNvcHkoIHA1ICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggZnJ1c3R1bSApIHtcclxuXHJcblx0XHRjb25zdCBwbGFuZXMgPSB0aGlzLnBsYW5lcztcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCA2OyBpICsrICkge1xyXG5cclxuXHRcdFx0cGxhbmVzWyBpIF0uY29weSggZnJ1c3R1bS5wbGFuZXNbIGkgXSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRGcm9tUHJvamVjdGlvbk1hdHJpeCggbSwgY29vcmRpbmF0ZVN5c3RlbSA9IFdlYkdMQ29vcmRpbmF0ZVN5c3RlbSApIHtcclxuXHJcblx0XHRjb25zdCBwbGFuZXMgPSB0aGlzLnBsYW5lcztcclxuXHRcdGNvbnN0IG1lID0gbS5lbGVtZW50cztcclxuXHRcdGNvbnN0IG1lMCA9IG1lWyAwIF0sIG1lMSA9IG1lWyAxIF0sIG1lMiA9IG1lWyAyIF0sIG1lMyA9IG1lWyAzIF07XHJcblx0XHRjb25zdCBtZTQgPSBtZVsgNCBdLCBtZTUgPSBtZVsgNSBdLCBtZTYgPSBtZVsgNiBdLCBtZTcgPSBtZVsgNyBdO1xyXG5cdFx0Y29uc3QgbWU4ID0gbWVbIDggXSwgbWU5ID0gbWVbIDkgXSwgbWUxMCA9IG1lWyAxMCBdLCBtZTExID0gbWVbIDExIF07XHJcblx0XHRjb25zdCBtZTEyID0gbWVbIDEyIF0sIG1lMTMgPSBtZVsgMTMgXSwgbWUxNCA9IG1lWyAxNCBdLCBtZTE1ID0gbWVbIDE1IF07XHJcblxyXG5cdFx0cGxhbmVzWyAwIF0uc2V0Q29tcG9uZW50cyggbWUzIC0gbWUwLCBtZTcgLSBtZTQsIG1lMTEgLSBtZTgsIG1lMTUgLSBtZTEyICkubm9ybWFsaXplKCk7XHJcblx0XHRwbGFuZXNbIDEgXS5zZXRDb21wb25lbnRzKCBtZTMgKyBtZTAsIG1lNyArIG1lNCwgbWUxMSArIG1lOCwgbWUxNSArIG1lMTIgKS5ub3JtYWxpemUoKTtcclxuXHRcdHBsYW5lc1sgMiBdLnNldENvbXBvbmVudHMoIG1lMyArIG1lMSwgbWU3ICsgbWU1LCBtZTExICsgbWU5LCBtZTE1ICsgbWUxMyApLm5vcm1hbGl6ZSgpO1xyXG5cdFx0cGxhbmVzWyAzIF0uc2V0Q29tcG9uZW50cyggbWUzIC0gbWUxLCBtZTcgLSBtZTUsIG1lMTEgLSBtZTksIG1lMTUgLSBtZTEzICkubm9ybWFsaXplKCk7XHJcblx0XHRwbGFuZXNbIDQgXS5zZXRDb21wb25lbnRzKCBtZTMgLSBtZTIsIG1lNyAtIG1lNiwgbWUxMSAtIG1lMTAsIG1lMTUgLSBtZTE0ICkubm9ybWFsaXplKCk7XHJcblxyXG5cdFx0aWYgKCBjb29yZGluYXRlU3lzdGVtID09PSBXZWJHTENvb3JkaW5hdGVTeXN0ZW0gKSB7XHJcblxyXG5cdFx0XHRwbGFuZXNbIDUgXS5zZXRDb21wb25lbnRzKCBtZTMgKyBtZTIsIG1lNyArIG1lNiwgbWUxMSArIG1lMTAsIG1lMTUgKyBtZTE0ICkubm9ybWFsaXplKCk7XHJcblxyXG5cdFx0fSBlbHNlIGlmICggY29vcmRpbmF0ZVN5c3RlbSA9PT0gV2ViR1BVQ29vcmRpbmF0ZVN5c3RlbSApIHtcclxuXHJcblx0XHRcdHBsYW5lc1sgNSBdLnNldENvbXBvbmVudHMoIG1lMiwgbWU2LCBtZTEwLCBtZTE0ICkubm9ybWFsaXplKCk7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdHRocm93IG5ldyBFcnJvciggJ1RIUkVFLkZydXN0dW0uc2V0RnJvbVByb2plY3Rpb25NYXRyaXgoKTogSW52YWxpZCBjb29yZGluYXRlIHN5c3RlbTogJyArIGNvb3JkaW5hdGVTeXN0ZW0gKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0aW50ZXJzZWN0c09iamVjdCggb2JqZWN0ICkge1xyXG5cclxuXHRcdGlmICggb2JqZWN0LmJvdW5kaW5nU3BoZXJlICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRpZiAoIG9iamVjdC5ib3VuZGluZ1NwaGVyZSA9PT0gbnVsbCApIG9iamVjdC5jb21wdXRlQm91bmRpbmdTcGhlcmUoKTtcclxuXHJcblx0XHRcdF9zcGhlcmUuY29weSggb2JqZWN0LmJvdW5kaW5nU3BoZXJlICkuYXBwbHlNYXRyaXg0KCBvYmplY3QubWF0cml4V29ybGQgKTtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0Y29uc3QgZ2VvbWV0cnkgPSBvYmplY3QuZ2VvbWV0cnk7XHJcblxyXG5cdFx0XHRpZiAoIGdlb21ldHJ5LmJvdW5kaW5nU3BoZXJlID09PSBudWxsICkgZ2VvbWV0cnkuY29tcHV0ZUJvdW5kaW5nU3BoZXJlKCk7XHJcblxyXG5cdFx0XHRfc3BoZXJlLmNvcHkoIGdlb21ldHJ5LmJvdW5kaW5nU3BoZXJlICkuYXBwbHlNYXRyaXg0KCBvYmplY3QubWF0cml4V29ybGQgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuaW50ZXJzZWN0c1NwaGVyZSggX3NwaGVyZSApO1xyXG5cclxuXHR9XHJcblxyXG5cdGludGVyc2VjdHNTcHJpdGUoIHNwcml0ZSApIHtcclxuXHJcblx0XHRfc3BoZXJlLmNlbnRlci5zZXQoIDAsIDAsIDAgKTtcclxuXHRcdF9zcGhlcmUucmFkaXVzID0gMC43MDcxMDY3ODExODY1NDc2O1xyXG5cdFx0X3NwaGVyZS5hcHBseU1hdHJpeDQoIHNwcml0ZS5tYXRyaXhXb3JsZCApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzLmludGVyc2VjdHNTcGhlcmUoIF9zcGhlcmUgKTtcclxuXHJcblx0fVxyXG5cclxuXHRpbnRlcnNlY3RzU3BoZXJlKCBzcGhlcmUgKSB7XHJcblxyXG5cdFx0Y29uc3QgcGxhbmVzID0gdGhpcy5wbGFuZXM7XHJcblx0XHRjb25zdCBjZW50ZXIgPSBzcGhlcmUuY2VudGVyO1xyXG5cdFx0Y29uc3QgbmVnUmFkaXVzID0gLSBzcGhlcmUucmFkaXVzO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IDY7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBkaXN0YW5jZSA9IHBsYW5lc1sgaSBdLmRpc3RhbmNlVG9Qb2ludCggY2VudGVyICk7XHJcblxyXG5cdFx0XHRpZiAoIGRpc3RhbmNlIDwgbmVnUmFkaXVzICkge1xyXG5cclxuXHRcdFx0XHRyZXR1cm4gZmFsc2U7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0cnVlO1xyXG5cclxuXHR9XHJcblxyXG5cdGludGVyc2VjdHNCb3goIGJveCApIHtcclxuXHJcblx0XHRjb25zdCBwbGFuZXMgPSB0aGlzLnBsYW5lcztcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCA2OyBpICsrICkge1xyXG5cclxuXHRcdFx0Y29uc3QgcGxhbmUgPSBwbGFuZXNbIGkgXTtcclxuXHJcblx0XHRcdC8vIGNvcm5lciBhdCBtYXggZGlzdGFuY2VcclxuXHJcblx0XHRcdF92ZWN0b3IueCA9IHBsYW5lLm5vcm1hbC54ID4gMCA/IGJveC5tYXgueCA6IGJveC5taW4ueDtcclxuXHRcdFx0X3ZlY3Rvci55ID0gcGxhbmUubm9ybWFsLnkgPiAwID8gYm94Lm1heC55IDogYm94Lm1pbi55O1xyXG5cdFx0XHRfdmVjdG9yLnogPSBwbGFuZS5ub3JtYWwueiA+IDAgPyBib3gubWF4LnogOiBib3gubWluLno7XHJcblxyXG5cdFx0XHRpZiAoIHBsYW5lLmRpc3RhbmNlVG9Qb2ludCggX3ZlY3RvciApIDwgMCApIHtcclxuXHJcblx0XHRcdFx0cmV0dXJuIGZhbHNlO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdHJ1ZTtcclxuXHJcblx0fVxyXG5cclxuXHRjb250YWluc1BvaW50KCBwb2ludCApIHtcclxuXHJcblx0XHRjb25zdCBwbGFuZXMgPSB0aGlzLnBsYW5lcztcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCA2OyBpICsrICkge1xyXG5cclxuXHRcdFx0aWYgKCBwbGFuZXNbIGkgXS5kaXN0YW5jZVRvUG9pbnQoIHBvaW50ICkgPCAwICkge1xyXG5cclxuXHRcdFx0XHRyZXR1cm4gZmFsc2U7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0cnVlO1xyXG5cclxuXHR9XHJcblxyXG5cdGNsb25lKCkge1xyXG5cclxuXHRcdHJldHVybiBuZXcgdGhpcy5jb25zdHJ1Y3RvcigpLmNvcHkoIHRoaXMgKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuXHJcbmV4cG9ydCB7IEZydXN0dW0gfTtcclxuIiwiZnVuY3Rpb24gV2ViR0xBbmltYXRpb24oKSB7XHJcblxyXG5cdGxldCBjb250ZXh0ID0gbnVsbDtcclxuXHRsZXQgaXNBbmltYXRpbmcgPSBmYWxzZTtcclxuXHRsZXQgYW5pbWF0aW9uTG9vcCA9IG51bGw7XHJcblx0bGV0IHJlcXVlc3RJZCA9IG51bGw7XHJcblxyXG5cdGZ1bmN0aW9uIG9uQW5pbWF0aW9uRnJhbWUoIHRpbWUsIGZyYW1lICkge1xyXG5cclxuXHRcdGFuaW1hdGlvbkxvb3AoIHRpbWUsIGZyYW1lICk7XHJcblxyXG5cdFx0cmVxdWVzdElkID0gY29udGV4dC5yZXF1ZXN0QW5pbWF0aW9uRnJhbWUoIG9uQW5pbWF0aW9uRnJhbWUgKTtcclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4ge1xyXG5cclxuXHRcdHN0YXJ0OiBmdW5jdGlvbiAoKSB7XHJcblxyXG5cdFx0XHRpZiAoIGlzQW5pbWF0aW5nID09PSB0cnVlICkgcmV0dXJuO1xyXG5cdFx0XHRpZiAoIGFuaW1hdGlvbkxvb3AgPT09IG51bGwgKSByZXR1cm47XHJcblxyXG5cdFx0XHRyZXF1ZXN0SWQgPSBjb250ZXh0LnJlcXVlc3RBbmltYXRpb25GcmFtZSggb25BbmltYXRpb25GcmFtZSApO1xyXG5cclxuXHRcdFx0aXNBbmltYXRpbmcgPSB0cnVlO1xyXG5cclxuXHRcdH0sXHJcblxyXG5cdFx0c3RvcDogZnVuY3Rpb24gKCkge1xyXG5cclxuXHRcdFx0Y29udGV4dC5jYW5jZWxBbmltYXRpb25GcmFtZSggcmVxdWVzdElkICk7XHJcblxyXG5cdFx0XHRpc0FuaW1hdGluZyA9IGZhbHNlO1xyXG5cclxuXHRcdH0sXHJcblxyXG5cdFx0c2V0QW5pbWF0aW9uTG9vcDogZnVuY3Rpb24gKCBjYWxsYmFjayApIHtcclxuXHJcblx0XHRcdGFuaW1hdGlvbkxvb3AgPSBjYWxsYmFjaztcclxuXHJcblx0XHR9LFxyXG5cclxuXHRcdHNldENvbnRleHQ6IGZ1bmN0aW9uICggdmFsdWUgKSB7XHJcblxyXG5cdFx0XHRjb250ZXh0ID0gdmFsdWU7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9O1xyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgV2ViR0xBbmltYXRpb24gfTtcclxuIiwiZnVuY3Rpb24gV2ViR0xBdHRyaWJ1dGVzKCBnbCwgY2FwYWJpbGl0aWVzICkge1xyXG5cclxuXHRjb25zdCBpc1dlYkdMMiA9IGNhcGFiaWxpdGllcy5pc1dlYkdMMjtcclxuXHJcblx0Y29uc3QgYnVmZmVycyA9IG5ldyBXZWFrTWFwKCk7XHJcblxyXG5cdGZ1bmN0aW9uIGNyZWF0ZUJ1ZmZlciggYXR0cmlidXRlLCBidWZmZXJUeXBlICkge1xyXG5cclxuXHRcdGNvbnN0IGFycmF5ID0gYXR0cmlidXRlLmFycmF5O1xyXG5cdFx0Y29uc3QgdXNhZ2UgPSBhdHRyaWJ1dGUudXNhZ2U7XHJcblx0XHRjb25zdCBzaXplID0gYXJyYXkuYnl0ZUxlbmd0aDtcclxuXHJcblx0XHRjb25zdCBidWZmZXIgPSBnbC5jcmVhdGVCdWZmZXIoKTtcclxuXHJcblx0XHRnbC5iaW5kQnVmZmVyKCBidWZmZXJUeXBlLCBidWZmZXIgKTtcclxuXHRcdGdsLmJ1ZmZlckRhdGEoIGJ1ZmZlclR5cGUsIGFycmF5LCB1c2FnZSApO1xyXG5cclxuXHRcdGF0dHJpYnV0ZS5vblVwbG9hZENhbGxiYWNrKCk7XHJcblxyXG5cdFx0bGV0IHR5cGU7XHJcblxyXG5cdFx0aWYgKCBhcnJheSBpbnN0YW5jZW9mIEZsb2F0MzJBcnJheSApIHtcclxuXHJcblx0XHRcdHR5cGUgPSBnbC5GTE9BVDtcclxuXHJcblx0XHR9IGVsc2UgaWYgKCBhcnJheSBpbnN0YW5jZW9mIFVpbnQxNkFycmF5ICkge1xyXG5cclxuXHRcdFx0aWYgKCBhdHRyaWJ1dGUuaXNGbG9hdDE2QnVmZmVyQXR0cmlidXRlICkge1xyXG5cclxuXHRcdFx0XHRpZiAoIGlzV2ViR0wyICkge1xyXG5cclxuXHRcdFx0XHRcdHR5cGUgPSBnbC5IQUxGX0ZMT0FUO1xyXG5cclxuXHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdHRocm93IG5ldyBFcnJvciggJ1RIUkVFLldlYkdMQXR0cmlidXRlczogVXNhZ2Ugb2YgRmxvYXQxNkJ1ZmZlckF0dHJpYnV0ZSByZXF1aXJlcyBXZWJHTDIuJyApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHR0eXBlID0gZ2wuVU5TSUdORURfU0hPUlQ7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fSBlbHNlIGlmICggYXJyYXkgaW5zdGFuY2VvZiBJbnQxNkFycmF5ICkge1xyXG5cclxuXHRcdFx0dHlwZSA9IGdsLlNIT1JUO1xyXG5cclxuXHRcdH0gZWxzZSBpZiAoIGFycmF5IGluc3RhbmNlb2YgVWludDMyQXJyYXkgKSB7XHJcblxyXG5cdFx0XHR0eXBlID0gZ2wuVU5TSUdORURfSU5UO1xyXG5cclxuXHRcdH0gZWxzZSBpZiAoIGFycmF5IGluc3RhbmNlb2YgSW50MzJBcnJheSApIHtcclxuXHJcblx0XHRcdHR5cGUgPSBnbC5JTlQ7XHJcblxyXG5cdFx0fSBlbHNlIGlmICggYXJyYXkgaW5zdGFuY2VvZiBJbnQ4QXJyYXkgKSB7XHJcblxyXG5cdFx0XHR0eXBlID0gZ2wuQllURTtcclxuXHJcblx0XHR9IGVsc2UgaWYgKCBhcnJheSBpbnN0YW5jZW9mIFVpbnQ4QXJyYXkgKSB7XHJcblxyXG5cdFx0XHR0eXBlID0gZ2wuVU5TSUdORURfQllURTtcclxuXHJcblx0XHR9IGVsc2UgaWYgKCBhcnJheSBpbnN0YW5jZW9mIFVpbnQ4Q2xhbXBlZEFycmF5ICkge1xyXG5cclxuXHRcdFx0dHlwZSA9IGdsLlVOU0lHTkVEX0JZVEU7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdHRocm93IG5ldyBFcnJvciggJ1RIUkVFLldlYkdMQXR0cmlidXRlczogVW5zdXBwb3J0ZWQgYnVmZmVyIGRhdGEgZm9ybWF0OiAnICsgYXJyYXkgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHtcclxuXHRcdFx0YnVmZmVyOiBidWZmZXIsXHJcblx0XHRcdHR5cGU6IHR5cGUsXHJcblx0XHRcdGJ5dGVzUGVyRWxlbWVudDogYXJyYXkuQllURVNfUEVSX0VMRU1FTlQsXHJcblx0XHRcdHZlcnNpb246IGF0dHJpYnV0ZS52ZXJzaW9uLFxyXG5cdFx0XHRzaXplOiBzaXplXHJcblx0XHR9O1xyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHVwZGF0ZUJ1ZmZlciggYnVmZmVyLCBhdHRyaWJ1dGUsIGJ1ZmZlclR5cGUgKSB7XHJcblxyXG5cdFx0Y29uc3QgYXJyYXkgPSBhdHRyaWJ1dGUuYXJyYXk7XHJcblx0XHRjb25zdCB1cGRhdGVSYW5nZSA9IGF0dHJpYnV0ZS5fdXBkYXRlUmFuZ2U7IC8vIEBkZXByZWNhdGVkLCByMTU5XHJcblx0XHRjb25zdCB1cGRhdGVSYW5nZXMgPSBhdHRyaWJ1dGUudXBkYXRlUmFuZ2VzO1xyXG5cclxuXHRcdGdsLmJpbmRCdWZmZXIoIGJ1ZmZlclR5cGUsIGJ1ZmZlciApO1xyXG5cclxuXHRcdGlmICggdXBkYXRlUmFuZ2UuY291bnQgPT09IC0gMSAmJiB1cGRhdGVSYW5nZXMubGVuZ3RoID09PSAwICkge1xyXG5cclxuXHRcdFx0Ly8gTm90IHVzaW5nIHVwZGF0ZSByYW5nZXNcclxuXHRcdFx0Z2wuYnVmZmVyU3ViRGF0YSggYnVmZmVyVHlwZSwgMCwgYXJyYXkgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCB1cGRhdGVSYW5nZXMubGVuZ3RoICE9PSAwICkge1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gdXBkYXRlUmFuZ2VzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IHJhbmdlID0gdXBkYXRlUmFuZ2VzWyBpIF07XHJcblx0XHRcdFx0aWYgKCBpc1dlYkdMMiApIHtcclxuXHJcblx0XHRcdFx0XHRnbC5idWZmZXJTdWJEYXRhKCBidWZmZXJUeXBlLCByYW5nZS5zdGFydCAqIGFycmF5LkJZVEVTX1BFUl9FTEVNRU5ULFxyXG5cdFx0XHRcdFx0XHRhcnJheSwgcmFuZ2Uuc3RhcnQsIHJhbmdlLmNvdW50ICk7XHJcblxyXG5cdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0Z2wuYnVmZmVyU3ViRGF0YSggYnVmZmVyVHlwZSwgcmFuZ2Uuc3RhcnQgKiBhcnJheS5CWVRFU19QRVJfRUxFTUVOVCxcclxuXHRcdFx0XHRcdFx0YXJyYXkuc3ViYXJyYXkoIHJhbmdlLnN0YXJ0LCByYW5nZS5zdGFydCArIHJhbmdlLmNvdW50ICkgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0YXR0cmlidXRlLmNsZWFyVXBkYXRlUmFuZ2VzKCk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIEBkZXByZWNhdGVkLCByMTU5XHJcblx0XHRpZiAoIHVwZGF0ZVJhbmdlLmNvdW50ICE9PSAtIDEgKSB7XHJcblxyXG5cdFx0XHRpZiAoIGlzV2ViR0wyICkge1xyXG5cclxuXHRcdFx0XHRnbC5idWZmZXJTdWJEYXRhKCBidWZmZXJUeXBlLCB1cGRhdGVSYW5nZS5vZmZzZXQgKiBhcnJheS5CWVRFU19QRVJfRUxFTUVOVCxcclxuXHRcdFx0XHRcdGFycmF5LCB1cGRhdGVSYW5nZS5vZmZzZXQsIHVwZGF0ZVJhbmdlLmNvdW50ICk7XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRnbC5idWZmZXJTdWJEYXRhKCBidWZmZXJUeXBlLCB1cGRhdGVSYW5nZS5vZmZzZXQgKiBhcnJheS5CWVRFU19QRVJfRUxFTUVOVCxcclxuXHRcdFx0XHRcdGFycmF5LnN1YmFycmF5KCB1cGRhdGVSYW5nZS5vZmZzZXQsIHVwZGF0ZVJhbmdlLm9mZnNldCArIHVwZGF0ZVJhbmdlLmNvdW50ICkgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHVwZGF0ZVJhbmdlLmNvdW50ID0gLSAxOyAvLyByZXNldCByYW5nZVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRhdHRyaWJ1dGUub25VcGxvYWRDYWxsYmFjaygpO1xyXG5cclxuXHR9XHJcblxyXG5cdC8vXHJcblxyXG5cdGZ1bmN0aW9uIGdldCggYXR0cmlidXRlICkge1xyXG5cclxuXHRcdGlmICggYXR0cmlidXRlLmlzSW50ZXJsZWF2ZWRCdWZmZXJBdHRyaWJ1dGUgKSBhdHRyaWJ1dGUgPSBhdHRyaWJ1dGUuZGF0YTtcclxuXHJcblx0XHRyZXR1cm4gYnVmZmVycy5nZXQoIGF0dHJpYnV0ZSApO1xyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHJlbW92ZSggYXR0cmlidXRlICkge1xyXG5cclxuXHRcdGlmICggYXR0cmlidXRlLmlzSW50ZXJsZWF2ZWRCdWZmZXJBdHRyaWJ1dGUgKSBhdHRyaWJ1dGUgPSBhdHRyaWJ1dGUuZGF0YTtcclxuXHJcblx0XHRjb25zdCBkYXRhID0gYnVmZmVycy5nZXQoIGF0dHJpYnV0ZSApO1xyXG5cclxuXHRcdGlmICggZGF0YSApIHtcclxuXHJcblx0XHRcdGdsLmRlbGV0ZUJ1ZmZlciggZGF0YS5idWZmZXIgKTtcclxuXHJcblx0XHRcdGJ1ZmZlcnMuZGVsZXRlKCBhdHRyaWJ1dGUgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gdXBkYXRlKCBhdHRyaWJ1dGUsIGJ1ZmZlclR5cGUgKSB7XHJcblxyXG5cdFx0aWYgKCBhdHRyaWJ1dGUuaXNHTEJ1ZmZlckF0dHJpYnV0ZSApIHtcclxuXHJcblx0XHRcdGNvbnN0IGNhY2hlZCA9IGJ1ZmZlcnMuZ2V0KCBhdHRyaWJ1dGUgKTtcclxuXHJcblx0XHRcdGlmICggISBjYWNoZWQgfHwgY2FjaGVkLnZlcnNpb24gPCBhdHRyaWJ1dGUudmVyc2lvbiApIHtcclxuXHJcblx0XHRcdFx0YnVmZmVycy5zZXQoIGF0dHJpYnV0ZSwge1xyXG5cdFx0XHRcdFx0YnVmZmVyOiBhdHRyaWJ1dGUuYnVmZmVyLFxyXG5cdFx0XHRcdFx0dHlwZTogYXR0cmlidXRlLnR5cGUsXHJcblx0XHRcdFx0XHRieXRlc1BlckVsZW1lbnQ6IGF0dHJpYnV0ZS5lbGVtZW50U2l6ZSxcclxuXHRcdFx0XHRcdHZlcnNpb246IGF0dHJpYnV0ZS52ZXJzaW9uXHJcblx0XHRcdFx0fSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0cmV0dXJuO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIGF0dHJpYnV0ZS5pc0ludGVybGVhdmVkQnVmZmVyQXR0cmlidXRlICkgYXR0cmlidXRlID0gYXR0cmlidXRlLmRhdGE7XHJcblxyXG5cdFx0Y29uc3QgZGF0YSA9IGJ1ZmZlcnMuZ2V0KCBhdHRyaWJ1dGUgKTtcclxuXHJcblx0XHRpZiAoIGRhdGEgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdGJ1ZmZlcnMuc2V0KCBhdHRyaWJ1dGUsIGNyZWF0ZUJ1ZmZlciggYXR0cmlidXRlLCBidWZmZXJUeXBlICkgKTtcclxuXHJcblx0XHR9IGVsc2UgaWYgKCBkYXRhLnZlcnNpb24gPCBhdHRyaWJ1dGUudmVyc2lvbiApIHtcclxuXHJcblx0XHRcdGlmICggZGF0YS5zaXplICE9PSBhdHRyaWJ1dGUuYXJyYXkuYnl0ZUxlbmd0aCApIHtcclxuXHJcblx0XHRcdFx0dGhyb3cgbmV3IEVycm9yKCAnVEhSRUUuV2ViR0xBdHRyaWJ1dGVzOiBUaGUgc2l6ZSBvZiB0aGUgYnVmZmVyIGF0dHJpYnV0ZVxcJ3MgYXJyYXkgYnVmZmVyIGRvZXMgbm90IG1hdGNoIHRoZSBvcmlnaW5hbCBzaXplLiBSZXNpemluZyBidWZmZXIgYXR0cmlidXRlcyBpcyBub3Qgc3VwcG9ydGVkLicgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHVwZGF0ZUJ1ZmZlciggZGF0YS5idWZmZXIsIGF0dHJpYnV0ZSwgYnVmZmVyVHlwZSApO1xyXG5cclxuXHRcdFx0ZGF0YS52ZXJzaW9uID0gYXR0cmlidXRlLnZlcnNpb247XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdHJldHVybiB7XHJcblxyXG5cdFx0Z2V0OiBnZXQsXHJcblx0XHRyZW1vdmU6IHJlbW92ZSxcclxuXHRcdHVwZGF0ZTogdXBkYXRlXHJcblxyXG5cdH07XHJcblxyXG59XHJcblxyXG5cclxuZXhwb3J0IHsgV2ViR0xBdHRyaWJ1dGVzIH07XHJcbiIsImltcG9ydCB7IEJ1ZmZlckdlb21ldHJ5IH0gZnJvbSAnLi4vY29yZS9CdWZmZXJHZW9tZXRyeS5qcyc7XHJcbmltcG9ydCB7IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUgfSBmcm9tICcuLi9jb3JlL0J1ZmZlckF0dHJpYnV0ZS5qcyc7XHJcblxyXG5jbGFzcyBQbGFuZUdlb21ldHJ5IGV4dGVuZHMgQnVmZmVyR2VvbWV0cnkge1xyXG5cclxuXHRjb25zdHJ1Y3Rvciggd2lkdGggPSAxLCBoZWlnaHQgPSAxLCB3aWR0aFNlZ21lbnRzID0gMSwgaGVpZ2h0U2VnbWVudHMgPSAxICkge1xyXG5cclxuXHRcdHN1cGVyKCk7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ1BsYW5lR2VvbWV0cnknO1xyXG5cclxuXHRcdHRoaXMucGFyYW1ldGVycyA9IHtcclxuXHRcdFx0d2lkdGg6IHdpZHRoLFxyXG5cdFx0XHRoZWlnaHQ6IGhlaWdodCxcclxuXHRcdFx0d2lkdGhTZWdtZW50czogd2lkdGhTZWdtZW50cyxcclxuXHRcdFx0aGVpZ2h0U2VnbWVudHM6IGhlaWdodFNlZ21lbnRzXHJcblx0XHR9O1xyXG5cclxuXHRcdGNvbnN0IHdpZHRoX2hhbGYgPSB3aWR0aCAvIDI7XHJcblx0XHRjb25zdCBoZWlnaHRfaGFsZiA9IGhlaWdodCAvIDI7XHJcblxyXG5cdFx0Y29uc3QgZ3JpZFggPSBNYXRoLmZsb29yKCB3aWR0aFNlZ21lbnRzICk7XHJcblx0XHRjb25zdCBncmlkWSA9IE1hdGguZmxvb3IoIGhlaWdodFNlZ21lbnRzICk7XHJcblxyXG5cdFx0Y29uc3QgZ3JpZFgxID0gZ3JpZFggKyAxO1xyXG5cdFx0Y29uc3QgZ3JpZFkxID0gZ3JpZFkgKyAxO1xyXG5cclxuXHRcdGNvbnN0IHNlZ21lbnRfd2lkdGggPSB3aWR0aCAvIGdyaWRYO1xyXG5cdFx0Y29uc3Qgc2VnbWVudF9oZWlnaHQgPSBoZWlnaHQgLyBncmlkWTtcclxuXHJcblx0XHQvL1xyXG5cclxuXHRcdGNvbnN0IGluZGljZXMgPSBbXTtcclxuXHRcdGNvbnN0IHZlcnRpY2VzID0gW107XHJcblx0XHRjb25zdCBub3JtYWxzID0gW107XHJcblx0XHRjb25zdCB1dnMgPSBbXTtcclxuXHJcblx0XHRmb3IgKCBsZXQgaXkgPSAwOyBpeSA8IGdyaWRZMTsgaXkgKysgKSB7XHJcblxyXG5cdFx0XHRjb25zdCB5ID0gaXkgKiBzZWdtZW50X2hlaWdodCAtIGhlaWdodF9oYWxmO1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGl4ID0gMDsgaXggPCBncmlkWDE7IGl4ICsrICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCB4ID0gaXggKiBzZWdtZW50X3dpZHRoIC0gd2lkdGhfaGFsZjtcclxuXHJcblx0XHRcdFx0dmVydGljZXMucHVzaCggeCwgLSB5LCAwICk7XHJcblxyXG5cdFx0XHRcdG5vcm1hbHMucHVzaCggMCwgMCwgMSApO1xyXG5cclxuXHRcdFx0XHR1dnMucHVzaCggaXggLyBncmlkWCApO1xyXG5cdFx0XHRcdHV2cy5wdXNoKCAxIC0gKCBpeSAvIGdyaWRZICkgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Zm9yICggbGV0IGl5ID0gMDsgaXkgPCBncmlkWTsgaXkgKysgKSB7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaXggPSAwOyBpeCA8IGdyaWRYOyBpeCArKyApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgYSA9IGl4ICsgZ3JpZFgxICogaXk7XHJcblx0XHRcdFx0Y29uc3QgYiA9IGl4ICsgZ3JpZFgxICogKCBpeSArIDEgKTtcclxuXHRcdFx0XHRjb25zdCBjID0gKCBpeCArIDEgKSArIGdyaWRYMSAqICggaXkgKyAxICk7XHJcblx0XHRcdFx0Y29uc3QgZCA9ICggaXggKyAxICkgKyBncmlkWDEgKiBpeTtcclxuXHJcblx0XHRcdFx0aW5kaWNlcy5wdXNoKCBhLCBiLCBkICk7XHJcblx0XHRcdFx0aW5kaWNlcy5wdXNoKCBiLCBjLCBkICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMuc2V0SW5kZXgoIGluZGljZXMgKTtcclxuXHRcdHRoaXMuc2V0QXR0cmlidXRlKCAncG9zaXRpb24nLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggdmVydGljZXMsIDMgKSApO1xyXG5cdFx0dGhpcy5zZXRBdHRyaWJ1dGUoICdub3JtYWwnLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggbm9ybWFscywgMyApICk7XHJcblx0XHR0aGlzLnNldEF0dHJpYnV0ZSggJ3V2JywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIHV2cywgMiApICk7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xyXG5cclxuXHRcdHRoaXMucGFyYW1ldGVycyA9IE9iamVjdC5hc3NpZ24oIHt9LCBzb3VyY2UucGFyYW1ldGVycyApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHN0YXRpYyBmcm9tSlNPTiggZGF0YSApIHtcclxuXHJcblx0XHRyZXR1cm4gbmV3IFBsYW5lR2VvbWV0cnkoIGRhdGEud2lkdGgsIGRhdGEuaGVpZ2h0LCBkYXRhLndpZHRoU2VnbWVudHMsIGRhdGEuaGVpZ2h0U2VnbWVudHMgKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgUGxhbmVHZW9tZXRyeSB9O1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWZkZWYgVVNFX0FMUEhBSEFTSFxyXG5cclxuXHRpZiAoIGRpZmZ1c2VDb2xvci5hIDwgZ2V0QWxwaGFIYXNoVGhyZXNob2xkKCB2UG9zaXRpb24gKSApIGRpc2NhcmQ7XHJcblxyXG4jZW5kaWZcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuI2lmZGVmIFVTRV9BTFBIQUhBU0hcclxuXHJcblx0LyoqXHJcblx0ICogU2VlOiBodHRwczovL2Nhc3VhbC1lZmZlY3RzLmNvbS9yZXNlYXJjaC9XeW1hbjIwMTdIYXNoZWQvaW5kZXguaHRtbFxyXG5cdCAqL1xyXG5cclxuXHRjb25zdCBmbG9hdCBBTFBIQV9IQVNIX1NDQUxFID0gMC4wNTsgLy8gRGVyaXZlZCBmcm9tIHRyaWFscyBvbmx5LCBhbmQgbWF5IGJlIGNoYW5nZWQuXHJcblxyXG5cdGZsb2F0IGhhc2gyRCggdmVjMiB2YWx1ZSApIHtcclxuXHJcblx0XHRyZXR1cm4gZnJhY3QoIDEuMGU0ICogc2luKCAxNy4wICogdmFsdWUueCArIDAuMSAqIHZhbHVlLnkgKSAqICggMC4xICsgYWJzKCBzaW4oIDEzLjAgKiB2YWx1ZS55ICsgdmFsdWUueCApICkgKSApO1xyXG5cclxuXHR9XHJcblxyXG5cdGZsb2F0IGhhc2gzRCggdmVjMyB2YWx1ZSApIHtcclxuXHJcblx0XHRyZXR1cm4gaGFzaDJEKCB2ZWMyKCBoYXNoMkQoIHZhbHVlLnh5ICksIHZhbHVlLnogKSApO1xyXG5cclxuXHR9XHJcblxyXG5cdGZsb2F0IGdldEFscGhhSGFzaFRocmVzaG9sZCggdmVjMyBwb3NpdGlvbiApIHtcclxuXHJcblx0XHQvLyBGaW5kIHRoZSBkaXNjcmV0aXplZCBkZXJpdmF0aXZlcyBvZiBvdXIgY29vcmRpbmF0ZXNcclxuXHRcdGZsb2F0IG1heERlcml2ID0gbWF4KFxyXG5cdFx0XHRsZW5ndGgoIGRGZHgoIHBvc2l0aW9uLnh5eiApICksXHJcblx0XHRcdGxlbmd0aCggZEZkeSggcG9zaXRpb24ueHl6ICkgKVxyXG5cdFx0KTtcclxuXHRcdGZsb2F0IHBpeFNjYWxlID0gMS4wIC8gKCBBTFBIQV9IQVNIX1NDQUxFICogbWF4RGVyaXYgKTtcclxuXHJcblx0XHQvLyBGaW5kIHR3byBuZWFyZXN0IGxvZy1kaXNjcmV0aXplZCBub2lzZSBzY2FsZXNcclxuXHRcdHZlYzIgcGl4U2NhbGVzID0gdmVjMihcclxuXHRcdFx0ZXhwMiggZmxvb3IoIGxvZzIoIHBpeFNjYWxlICkgKSApLFxyXG5cdFx0XHRleHAyKCBjZWlsKCBsb2cyKCBwaXhTY2FsZSApICkgKVxyXG5cdFx0KTtcclxuXHJcblx0XHQvLyBDb21wdXRlIGFscGhhIHRocmVzaG9sZHMgYXQgb3VyIHR3byBub2lzZSBzY2FsZXNcclxuXHRcdHZlYzIgYWxwaGEgPSB2ZWMyKFxyXG5cdFx0XHRoYXNoM0QoIGZsb29yKCBwaXhTY2FsZXMueCAqIHBvc2l0aW9uLnh5eiApICksXHJcblx0XHRcdGhhc2gzRCggZmxvb3IoIHBpeFNjYWxlcy55ICogcG9zaXRpb24ueHl6ICkgKVxyXG5cdFx0KTtcclxuXHJcblx0XHQvLyBGYWN0b3IgdG8gaW50ZXJwb2xhdGUgbGVycCB3aXRoXHJcblx0XHRmbG9hdCBsZXJwRmFjdG9yID0gZnJhY3QoIGxvZzIoIHBpeFNjYWxlICkgKTtcclxuXHJcblx0XHQvLyBJbnRlcnBvbGF0ZSBhbHBoYSB0aHJlc2hvbGQgZnJvbSBub2lzZSBhdCB0d28gc2NhbGVzXHJcblx0XHRmbG9hdCB4ID0gKCAxLjAgLSBsZXJwRmFjdG9yICkgKiBhbHBoYS54ICsgbGVycEZhY3RvciAqIGFscGhhLnk7XHJcblxyXG5cdFx0Ly8gUGFzcyBpbnRvIENERiB0byBjb21wdXRlIHVuaWZvcm1seSBkaXN0cmliIHRocmVzaG9sZFxyXG5cdFx0ZmxvYXQgYSA9IG1pbiggbGVycEZhY3RvciwgMS4wIC0gbGVycEZhY3RvciApO1xyXG5cdFx0dmVjMyBjYXNlcyA9IHZlYzMoXHJcblx0XHRcdHggKiB4IC8gKCAyLjAgKiBhICogKCAxLjAgLSBhICkgKSxcclxuXHRcdFx0KCB4IC0gMC41ICogYSApIC8gKCAxLjAgLSBhICksXHJcblx0XHRcdDEuMCAtICggKCAxLjAgLSB4ICkgKiAoIDEuMCAtIHggKSAvICggMi4wICogYSAqICggMS4wIC0gYSApICkgKVxyXG5cdFx0KTtcclxuXHJcblx0XHQvLyBGaW5kIG91ciBmaW5hbCwgdW5pZm9ybWx5IGRpc3RyaWJ1dGVkIGFscGhhIHRocmVzaG9sZCAozrHPhClcclxuXHRcdGZsb2F0IHRocmVzaG9sZCA9ICggeCA8ICggMS4wIC0gYSApIClcclxuXHRcdFx0PyAoICggeCA8IGEgKSA/IGNhc2VzLnggOiBjYXNlcy55IClcclxuXHRcdFx0OiBjYXNlcy56O1xyXG5cclxuXHRcdC8vIEF2b2lkcyDOsc+EID09IDAuIENvdWxkIGFsc28gZG8gzrHPhCA9MS3Osc+EXHJcblx0XHRyZXR1cm4gY2xhbXAoIHRocmVzaG9sZCAsIDEuMGUtNiwgMS4wICk7XHJcblxyXG5cdH1cclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWZkZWYgVVNFX0FMUEhBTUFQXHJcblxyXG5cdGRpZmZ1c2VDb2xvci5hICo9IHRleHR1cmUyRCggYWxwaGFNYXAsIHZBbHBoYU1hcFV2ICkuZztcclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWZkZWYgVVNFX0FMUEhBTUFQXHJcblxyXG5cdHVuaWZvcm0gc2FtcGxlcjJEIGFscGhhTWFwO1xyXG5cclxuI2VuZGlmXHJcbmA7XHJcbiIsImV4cG9ydCBkZWZhdWx0IC8qIGdsc2wgKi9gXHJcbiNpZmRlZiBVU0VfQUxQSEFURVNUXHJcblxyXG5cdCNpZmRlZiBBTFBIQV9UT19DT1ZFUkFHRVxyXG5cclxuXHRkaWZmdXNlQ29sb3IuYSA9IHNtb290aHN0ZXAoIGFscGhhVGVzdCwgYWxwaGFUZXN0ICsgZndpZHRoKCBkaWZmdXNlQ29sb3IuYSApLCBkaWZmdXNlQ29sb3IuYSApO1xyXG5cdGlmICggZGlmZnVzZUNvbG9yLmEgPT0gMC4wICkgZGlzY2FyZDtcclxuXHJcblx0I2Vsc2VcclxuXHJcblx0aWYgKCBkaWZmdXNlQ29sb3IuYSA8IGFscGhhVGVzdCApIGRpc2NhcmQ7XHJcblxyXG5cdCNlbmRpZlxyXG5cclxuI2VuZGlmXHJcbmA7XHJcbiIsImV4cG9ydCBkZWZhdWx0IC8qIGdsc2wgKi9gXHJcbiNpZmRlZiBVU0VfQUxQSEFURVNUXHJcblx0dW5pZm9ybSBmbG9hdCBhbHBoYVRlc3Q7XHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWZkZWYgVVNFX0FPTUFQXHJcblxyXG5cdC8vIHJlYWRzIGNoYW5uZWwgUiwgY29tcGF0aWJsZSB3aXRoIGEgY29tYmluZWQgT2NjbHVzaW9uUm91Z2huZXNzTWV0YWxsaWMgKFJHQikgdGV4dHVyZVxyXG5cdGZsb2F0IGFtYmllbnRPY2NsdXNpb24gPSAoIHRleHR1cmUyRCggYW9NYXAsIHZBb01hcFV2ICkuciAtIDEuMCApICogYW9NYXBJbnRlbnNpdHkgKyAxLjA7XHJcblxyXG5cdHJlZmxlY3RlZExpZ2h0LmluZGlyZWN0RGlmZnVzZSAqPSBhbWJpZW50T2NjbHVzaW9uO1xyXG5cclxuXHQjaWYgZGVmaW5lZCggVVNFX0NMRUFSQ09BVCApIFxyXG5cdFx0Y2xlYXJjb2F0U3BlY3VsYXJJbmRpcmVjdCAqPSBhbWJpZW50T2NjbHVzaW9uO1xyXG5cdCNlbmRpZlxyXG5cclxuXHQjaWYgZGVmaW5lZCggVVNFX1NIRUVOICkgXHJcblx0XHRzaGVlblNwZWN1bGFySW5kaXJlY3QgKj0gYW1iaWVudE9jY2x1c2lvbjtcclxuXHQjZW5kaWZcclxuXHJcblx0I2lmIGRlZmluZWQoIFVTRV9FTlZNQVAgKSAmJiBkZWZpbmVkKCBTVEFOREFSRCApXHJcblxyXG5cdFx0ZmxvYXQgZG90TlYgPSBzYXR1cmF0ZSggZG90KCBnZW9tZXRyeU5vcm1hbCwgZ2VvbWV0cnlWaWV3RGlyICkgKTtcclxuXHJcblx0XHRyZWZsZWN0ZWRMaWdodC5pbmRpcmVjdFNwZWN1bGFyICo9IGNvbXB1dGVTcGVjdWxhck9jY2x1c2lvbiggZG90TlYsIGFtYmllbnRPY2NsdXNpb24sIG1hdGVyaWFsLnJvdWdobmVzcyApO1xyXG5cclxuXHQjZW5kaWZcclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWZkZWYgVVNFX0FPTUFQXHJcblxyXG5cdHVuaWZvcm0gc2FtcGxlcjJEIGFvTWFwO1xyXG5cdHVuaWZvcm0gZmxvYXQgYW9NYXBJbnRlbnNpdHk7XHJcblxyXG4jZW5kaWZcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuI2lmZGVmIFVTRV9CQVRDSElOR1xyXG5cdGF0dHJpYnV0ZSBmbG9hdCBiYXRjaElkO1xyXG5cdHVuaWZvcm0gaGlnaHAgc2FtcGxlcjJEIGJhdGNoaW5nVGV4dHVyZTtcclxuXHRtYXQ0IGdldEJhdGNoaW5nTWF0cml4KCBjb25zdCBpbiBmbG9hdCBpICkge1xyXG5cclxuXHRcdGludCBzaXplID0gdGV4dHVyZVNpemUoIGJhdGNoaW5nVGV4dHVyZSwgMCApLng7XHJcblx0XHRpbnQgaiA9IGludCggaSApICogNDtcclxuXHRcdGludCB4ID0gaiAlIHNpemU7XHJcblx0XHRpbnQgeSA9IGogLyBzaXplO1xyXG5cdFx0dmVjNCB2MSA9IHRleGVsRmV0Y2goIGJhdGNoaW5nVGV4dHVyZSwgaXZlYzIoIHgsIHkgKSwgMCApO1xyXG5cdFx0dmVjNCB2MiA9IHRleGVsRmV0Y2goIGJhdGNoaW5nVGV4dHVyZSwgaXZlYzIoIHggKyAxLCB5ICksIDAgKTtcclxuXHRcdHZlYzQgdjMgPSB0ZXhlbEZldGNoKCBiYXRjaGluZ1RleHR1cmUsIGl2ZWMyKCB4ICsgMiwgeSApLCAwICk7XHJcblx0XHR2ZWM0IHY0ID0gdGV4ZWxGZXRjaCggYmF0Y2hpbmdUZXh0dXJlLCBpdmVjMiggeCArIDMsIHkgKSwgMCApO1xyXG5cdFx0cmV0dXJuIG1hdDQoIHYxLCB2MiwgdjMsIHY0ICk7XHJcblxyXG5cdH1cclxuI2VuZGlmXHJcbmA7XHJcbiIsImV4cG9ydCBkZWZhdWx0IC8qIGdsc2wgKi9gXHJcbiNpZmRlZiBVU0VfQkFUQ0hJTkdcclxuXHRtYXQ0IGJhdGNoaW5nTWF0cml4ID0gZ2V0QmF0Y2hpbmdNYXRyaXgoIGJhdGNoSWQgKTtcclxuI2VuZGlmXHJcbmA7XHJcbiIsImV4cG9ydCBkZWZhdWx0IC8qIGdsc2wgKi9gXHJcbnZlYzMgdHJhbnNmb3JtZWQgPSB2ZWMzKCBwb3NpdGlvbiApO1xyXG5cclxuI2lmZGVmIFVTRV9BTFBIQUhBU0hcclxuXHJcblx0dlBvc2l0aW9uID0gdmVjMyggcG9zaXRpb24gKTtcclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG52ZWMzIG9iamVjdE5vcm1hbCA9IHZlYzMoIG5vcm1hbCApO1xyXG5cclxuI2lmZGVmIFVTRV9UQU5HRU5UXHJcblxyXG5cdHZlYzMgb2JqZWN0VGFuZ2VudCA9IHZlYzMoIHRhbmdlbnQueHl6ICk7XHJcblxyXG4jZW5kaWZcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuXHJcbmZsb2F0IEdfQmxpbm5QaG9uZ19JbXBsaWNpdCggLyogY29uc3QgaW4gZmxvYXQgZG90TkwsIGNvbnN0IGluIGZsb2F0IGRvdE5WICovICkge1xyXG5cclxuXHQvLyBnZW9tZXRyeSB0ZXJtIGlzIChuIGRvdCBsKShuIGRvdCB2KSAvIDQobiBkb3QgbCkobiBkb3QgdilcclxuXHRyZXR1cm4gMC4yNTtcclxuXHJcbn1cclxuXHJcbmZsb2F0IERfQmxpbm5QaG9uZyggY29uc3QgaW4gZmxvYXQgc2hpbmluZXNzLCBjb25zdCBpbiBmbG9hdCBkb3ROSCApIHtcclxuXHJcblx0cmV0dXJuIFJFQ0lQUk9DQUxfUEkgKiAoIHNoaW5pbmVzcyAqIDAuNSArIDEuMCApICogcG93KCBkb3ROSCwgc2hpbmluZXNzICk7XHJcblxyXG59XHJcblxyXG52ZWMzIEJSREZfQmxpbm5QaG9uZyggY29uc3QgaW4gdmVjMyBsaWdodERpciwgY29uc3QgaW4gdmVjMyB2aWV3RGlyLCBjb25zdCBpbiB2ZWMzIG5vcm1hbCwgY29uc3QgaW4gdmVjMyBzcGVjdWxhckNvbG9yLCBjb25zdCBpbiBmbG9hdCBzaGluaW5lc3MgKSB7XHJcblxyXG5cdHZlYzMgaGFsZkRpciA9IG5vcm1hbGl6ZSggbGlnaHREaXIgKyB2aWV3RGlyICk7XHJcblxyXG5cdGZsb2F0IGRvdE5IID0gc2F0dXJhdGUoIGRvdCggbm9ybWFsLCBoYWxmRGlyICkgKTtcclxuXHRmbG9hdCBkb3RWSCA9IHNhdHVyYXRlKCBkb3QoIHZpZXdEaXIsIGhhbGZEaXIgKSApO1xyXG5cclxuXHR2ZWMzIEYgPSBGX1NjaGxpY2soIHNwZWN1bGFyQ29sb3IsIDEuMCwgZG90VkggKTtcclxuXHJcblx0ZmxvYXQgRyA9IEdfQmxpbm5QaG9uZ19JbXBsaWNpdCggLyogZG90TkwsIGRvdE5WICovICk7XHJcblxyXG5cdGZsb2F0IEQgPSBEX0JsaW5uUGhvbmcoIHNoaW5pbmVzcywgZG90TkggKTtcclxuXHJcblx0cmV0dXJuIEYgKiAoIEcgKiBEICk7XHJcblxyXG59IC8vIHZhbGlkYXRlZFxyXG5cclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuXHJcbiNpZmRlZiBVU0VfSVJJREVTQ0VOQ0VcclxuXHJcblx0Ly8gWFlaIHRvIGxpbmVhci1zUkdCIGNvbG9yIHNwYWNlXHJcblx0Y29uc3QgbWF0MyBYWVpfVE9fUkVDNzA5ID0gbWF0MyhcclxuXHRcdCAzLjI0MDQ1NDIsIC0wLjk2OTI2NjAsICAwLjA1NTY0MzQsXHJcblx0XHQtMS41MzcxMzg1LCAgMS44NzYwMTA4LCAtMC4yMDQwMjU5LFxyXG5cdFx0LTAuNDk4NTMxNCwgIDAuMDQxNTU2MCwgIDEuMDU3MjI1MlxyXG5cdCk7XHJcblxyXG5cdC8vIEFzc3VtZSBhaXIgaW50ZXJmYWNlIGZvciB0b3BcclxuXHQvLyBOb3RlOiBXZSBkb24ndCBoYW5kbGUgdGhlIGNhc2UgZnJlc25lbDAgPT0gMVxyXG5cdHZlYzMgRnJlc25lbDBUb0lvciggdmVjMyBmcmVzbmVsMCApIHtcclxuXHJcblx0XHR2ZWMzIHNxcnRGMCA9IHNxcnQoIGZyZXNuZWwwICk7XHJcblx0XHRyZXR1cm4gKCB2ZWMzKCAxLjAgKSArIHNxcnRGMCApIC8gKCB2ZWMzKCAxLjAgKSAtIHNxcnRGMCApO1xyXG5cclxuXHR9XHJcblxyXG5cdC8vIENvbnZlcnNpb24gRk8vSU9SXHJcblx0dmVjMyBJb3JUb0ZyZXNuZWwwKCB2ZWMzIHRyYW5zbWl0dGVkSW9yLCBmbG9hdCBpbmNpZGVudElvciApIHtcclxuXHJcblx0XHRyZXR1cm4gcG93MiggKCB0cmFuc21pdHRlZElvciAtIHZlYzMoIGluY2lkZW50SW9yICkgKSAvICggdHJhbnNtaXR0ZWRJb3IgKyB2ZWMzKCBpbmNpZGVudElvciApICkgKTtcclxuXHJcblx0fVxyXG5cclxuXHQvLyBpb3IgaXMgYSB2YWx1ZSBiZXR3ZWVuIDEuMCBhbmQgMy4wLiAxLjAgaXMgYWlyIGludGVyZmFjZVxyXG5cdGZsb2F0IElvclRvRnJlc25lbDAoIGZsb2F0IHRyYW5zbWl0dGVkSW9yLCBmbG9hdCBpbmNpZGVudElvciApIHtcclxuXHJcblx0XHRyZXR1cm4gcG93MiggKCB0cmFuc21pdHRlZElvciAtIGluY2lkZW50SW9yICkgLyAoIHRyYW5zbWl0dGVkSW9yICsgaW5jaWRlbnRJb3IgKSk7XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gRnJlc25lbCBlcXVhdGlvbnMgZm9yIGRpZWxlY3RyaWMvZGllbGVjdHJpYyBpbnRlcmZhY2VzLlxyXG5cdC8vIFJlZjogaHR0cHM6Ly9iZWxjb3VyLmdpdGh1Yi5pby9ibG9nL3Jlc2VhcmNoLzIwMTcvMDUvMDEvYnJkZi10aGluLWZpbG0uaHRtbFxyXG5cdC8vIEV2YWx1YXRpb24gWFlaIHNlbnNpdGl2aXR5IGN1cnZlcyBpbiBGb3VyaWVyIHNwYWNlXHJcblx0dmVjMyBldmFsU2Vuc2l0aXZpdHkoIGZsb2F0IE9QRCwgdmVjMyBzaGlmdCApIHtcclxuXHJcblx0XHRmbG9hdCBwaGFzZSA9IDIuMCAqIFBJICogT1BEICogMS4wZS05O1xyXG5cdFx0dmVjMyB2YWwgPSB2ZWMzKCA1LjQ4NTZlLTEzLCA0LjQyMDFlLTEzLCA1LjI0ODFlLTEzICk7XHJcblx0XHR2ZWMzIHBvcyA9IHZlYzMoIDEuNjgxMGUrMDYsIDEuNzk1M2UrMDYsIDIuMjA4NGUrMDYgKTtcclxuXHRcdHZlYzMgdmFyID0gdmVjMyggNC4zMjc4ZSswOSwgOS4zMDQ2ZSswOSwgNi42MTIxZSswOSApO1xyXG5cclxuXHRcdHZlYzMgeHl6ID0gdmFsICogc3FydCggMi4wICogUEkgKiB2YXIgKSAqIGNvcyggcG9zICogcGhhc2UgKyBzaGlmdCApICogZXhwKCAtIHBvdzIoIHBoYXNlICkgKiB2YXIgKTtcclxuXHRcdHh5ei54ICs9IDkuNzQ3MGUtMTQgKiBzcXJ0KCAyLjAgKiBQSSAqIDQuNTI4MmUrMDkgKSAqIGNvcyggMi4yMzk5ZSswNiAqIHBoYXNlICsgc2hpZnRbIDAgXSApICogZXhwKCAtIDQuNTI4MmUrMDkgKiBwb3cyKCBwaGFzZSApICk7XHJcblx0XHR4eXogLz0gMS4wNjg1ZS03O1xyXG5cclxuXHRcdHZlYzMgcmdiID0gWFlaX1RPX1JFQzcwOSAqIHh5ejtcclxuXHRcdHJldHVybiByZ2I7XHJcblxyXG5cdH1cclxuXHJcblx0dmVjMyBldmFsSXJpZGVzY2VuY2UoIGZsb2F0IG91dHNpZGVJT1IsIGZsb2F0IGV0YTIsIGZsb2F0IGNvc1RoZXRhMSwgZmxvYXQgdGhpbkZpbG1UaGlja25lc3MsIHZlYzMgYmFzZUYwICkge1xyXG5cclxuXHRcdHZlYzMgSTtcclxuXHJcblx0XHQvLyBGb3JjZSBpcmlkZXNjZW5jZUlPUiAtPiBvdXRzaWRlSU9SIHdoZW4gdGhpbkZpbG1UaGlja25lc3MgLT4gMC4wXHJcblx0XHRmbG9hdCBpcmlkZXNjZW5jZUlPUiA9IG1peCggb3V0c2lkZUlPUiwgZXRhMiwgc21vb3Roc3RlcCggMC4wLCAwLjAzLCB0aGluRmlsbVRoaWNrbmVzcyApICk7XHJcblx0XHQvLyBFdmFsdWF0ZSB0aGUgY29zVGhldGEgb24gdGhlIGJhc2UgbGF5ZXIgKFNuZWxsIGxhdylcclxuXHRcdGZsb2F0IHNpblRoZXRhMlNxID0gcG93Miggb3V0c2lkZUlPUiAvIGlyaWRlc2NlbmNlSU9SICkgKiAoIDEuMCAtIHBvdzIoIGNvc1RoZXRhMSApICk7XHJcblxyXG5cdFx0Ly8gSGFuZGxlIFRJUjpcclxuXHRcdGZsb2F0IGNvc1RoZXRhMlNxID0gMS4wIC0gc2luVGhldGEyU3E7XHJcblx0XHRpZiAoIGNvc1RoZXRhMlNxIDwgMC4wICkge1xyXG5cclxuXHRcdFx0cmV0dXJuIHZlYzMoIDEuMCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRmbG9hdCBjb3NUaGV0YTIgPSBzcXJ0KCBjb3NUaGV0YTJTcSApO1xyXG5cclxuXHRcdC8vIEZpcnN0IGludGVyZmFjZVxyXG5cdFx0ZmxvYXQgUjAgPSBJb3JUb0ZyZXNuZWwwKCBpcmlkZXNjZW5jZUlPUiwgb3V0c2lkZUlPUiApO1xyXG5cdFx0ZmxvYXQgUjEyID0gRl9TY2hsaWNrKCBSMCwgMS4wLCBjb3NUaGV0YTEgKTtcclxuXHRcdGZsb2F0IFQxMjEgPSAxLjAgLSBSMTI7XHJcblx0XHRmbG9hdCBwaGkxMiA9IDAuMDtcclxuXHRcdGlmICggaXJpZGVzY2VuY2VJT1IgPCBvdXRzaWRlSU9SICkgcGhpMTIgPSBQSTtcclxuXHRcdGZsb2F0IHBoaTIxID0gUEkgLSBwaGkxMjtcclxuXHJcblx0XHQvLyBTZWNvbmQgaW50ZXJmYWNlXHJcblx0XHR2ZWMzIGJhc2VJT1IgPSBGcmVzbmVsMFRvSW9yKCBjbGFtcCggYmFzZUYwLCAwLjAsIDAuOTk5OSApICk7IC8vIGd1YXJkIGFnYWluc3QgMS4wXHJcblx0XHR2ZWMzIFIxID0gSW9yVG9GcmVzbmVsMCggYmFzZUlPUiwgaXJpZGVzY2VuY2VJT1IgKTtcclxuXHRcdHZlYzMgUjIzID0gRl9TY2hsaWNrKCBSMSwgMS4wLCBjb3NUaGV0YTIgKTtcclxuXHRcdHZlYzMgcGhpMjMgPSB2ZWMzKCAwLjAgKTtcclxuXHRcdGlmICggYmFzZUlPUlsgMCBdIDwgaXJpZGVzY2VuY2VJT1IgKSBwaGkyM1sgMCBdID0gUEk7XHJcblx0XHRpZiAoIGJhc2VJT1JbIDEgXSA8IGlyaWRlc2NlbmNlSU9SICkgcGhpMjNbIDEgXSA9IFBJO1xyXG5cdFx0aWYgKCBiYXNlSU9SWyAyIF0gPCBpcmlkZXNjZW5jZUlPUiApIHBoaTIzWyAyIF0gPSBQSTtcclxuXHJcblx0XHQvLyBQaGFzZSBzaGlmdFxyXG5cdFx0ZmxvYXQgT1BEID0gMi4wICogaXJpZGVzY2VuY2VJT1IgKiB0aGluRmlsbVRoaWNrbmVzcyAqIGNvc1RoZXRhMjtcclxuXHRcdHZlYzMgcGhpID0gdmVjMyggcGhpMjEgKSArIHBoaTIzO1xyXG5cclxuXHRcdC8vIENvbXBvdW5kIHRlcm1zXHJcblx0XHR2ZWMzIFIxMjMgPSBjbGFtcCggUjEyICogUjIzLCAxZS01LCAwLjk5OTkgKTtcclxuXHRcdHZlYzMgcjEyMyA9IHNxcnQoIFIxMjMgKTtcclxuXHRcdHZlYzMgUnMgPSBwb3cyKCBUMTIxICkgKiBSMjMgLyAoIHZlYzMoIDEuMCApIC0gUjEyMyApO1xyXG5cclxuXHRcdC8vIFJlZmxlY3RhbmNlIHRlcm0gZm9yIG0gPSAwIChEQyB0ZXJtIGFtcGxpdHVkZSlcclxuXHRcdHZlYzMgQzAgPSBSMTIgKyBScztcclxuXHRcdEkgPSBDMDtcclxuXHJcblx0XHQvLyBSZWZsZWN0YW5jZSB0ZXJtIGZvciBtID4gMCAocGFpcnMgb2YgZGlyYWNzKVxyXG5cdFx0dmVjMyBDbSA9IFJzIC0gVDEyMTtcclxuXHRcdGZvciAoIGludCBtID0gMTsgbSA8PSAyOyArKyBtICkge1xyXG5cclxuXHRcdFx0Q20gKj0gcjEyMztcclxuXHRcdFx0dmVjMyBTbSA9IDIuMCAqIGV2YWxTZW5zaXRpdml0eSggZmxvYXQoIG0gKSAqIE9QRCwgZmxvYXQoIG0gKSAqIHBoaSApO1xyXG5cdFx0XHRJICs9IENtICogU207XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIFNpbmNlIG91dCBvZiBnYW11dCBjb2xvcnMgbWlnaHQgYmUgcHJvZHVjZWQsIG5lZ2F0aXZlIGNvbG9yIHZhbHVlcyBhcmUgY2xhbXBlZCB0byAwLlxyXG5cdFx0cmV0dXJuIG1heCggSSwgdmVjMyggMC4wICkgKTtcclxuXHJcblx0fVxyXG5cclxuI2VuZGlmXHJcblxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWZkZWYgVVNFX0JVTVBNQVBcclxuXHJcblx0dW5pZm9ybSBzYW1wbGVyMkQgYnVtcE1hcDtcclxuXHR1bmlmb3JtIGZsb2F0IGJ1bXBTY2FsZTtcclxuXHJcblx0Ly8gQnVtcCBNYXBwaW5nIFVucGFyYW1ldHJpemVkIFN1cmZhY2VzIG9uIHRoZSBHUFUgYnkgTW9ydGVuIFMuIE1pa2tlbHNlblxyXG5cdC8vIGh0dHBzOi8vbW1pa2suZ2l0aHViLmlvL3BhcGVyczNkL21tX3NmZ3JhZF9idW1wLnBkZlxyXG5cclxuXHQvLyBFdmFsdWF0ZSB0aGUgZGVyaXZhdGl2ZSBvZiB0aGUgaGVpZ2h0IHcuci50LiBzY3JlZW4tc3BhY2UgdXNpbmcgZm9yd2FyZCBkaWZmZXJlbmNpbmcgKGxpc3RpbmcgMilcclxuXHJcblx0dmVjMiBkSGR4eV9md2QoKSB7XHJcblxyXG5cdFx0dmVjMiBkU1RkeCA9IGRGZHgoIHZCdW1wTWFwVXYgKTtcclxuXHRcdHZlYzIgZFNUZHkgPSBkRmR5KCB2QnVtcE1hcFV2ICk7XHJcblxyXG5cdFx0ZmxvYXQgSGxsID0gYnVtcFNjYWxlICogdGV4dHVyZTJEKCBidW1wTWFwLCB2QnVtcE1hcFV2ICkueDtcclxuXHRcdGZsb2F0IGRCeCA9IGJ1bXBTY2FsZSAqIHRleHR1cmUyRCggYnVtcE1hcCwgdkJ1bXBNYXBVdiArIGRTVGR4ICkueCAtIEhsbDtcclxuXHRcdGZsb2F0IGRCeSA9IGJ1bXBTY2FsZSAqIHRleHR1cmUyRCggYnVtcE1hcCwgdkJ1bXBNYXBVdiArIGRTVGR5ICkueCAtIEhsbDtcclxuXHJcblx0XHRyZXR1cm4gdmVjMiggZEJ4LCBkQnkgKTtcclxuXHJcblx0fVxyXG5cclxuXHR2ZWMzIHBlcnR1cmJOb3JtYWxBcmIoIHZlYzMgc3VyZl9wb3MsIHZlYzMgc3VyZl9ub3JtLCB2ZWMyIGRIZHh5LCBmbG9hdCBmYWNlRGlyZWN0aW9uICkge1xyXG5cclxuXHRcdC8vIG5vcm1hbGl6ZSBpcyBkb25lIHRvIGVuc3VyZSB0aGF0IHRoZSBidW1wIG1hcCBsb29rcyB0aGUgc2FtZSByZWdhcmRsZXNzIG9mIHRoZSB0ZXh0dXJlJ3Mgc2NhbGVcclxuXHRcdHZlYzMgdlNpZ21hWCA9IG5vcm1hbGl6ZSggZEZkeCggc3VyZl9wb3MueHl6ICkgKTtcclxuXHRcdHZlYzMgdlNpZ21hWSA9IG5vcm1hbGl6ZSggZEZkeSggc3VyZl9wb3MueHl6ICkgKTtcclxuXHRcdHZlYzMgdk4gPSBzdXJmX25vcm07IC8vIG5vcm1hbGl6ZWRcclxuXHJcblx0XHR2ZWMzIFIxID0gY3Jvc3MoIHZTaWdtYVksIHZOICk7XHJcblx0XHR2ZWMzIFIyID0gY3Jvc3MoIHZOLCB2U2lnbWFYICk7XHJcblxyXG5cdFx0ZmxvYXQgZkRldCA9IGRvdCggdlNpZ21hWCwgUjEgKSAqIGZhY2VEaXJlY3Rpb247XHJcblxyXG5cdFx0dmVjMyB2R3JhZCA9IHNpZ24oIGZEZXQgKSAqICggZEhkeHkueCAqIFIxICsgZEhkeHkueSAqIFIyICk7XHJcblx0XHRyZXR1cm4gbm9ybWFsaXplKCBhYnMoIGZEZXQgKSAqIHN1cmZfbm9ybSAtIHZHcmFkICk7XHJcblxyXG5cdH1cclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWYgTlVNX0NMSVBQSU5HX1BMQU5FUyA+IDBcclxuXHJcblx0dmVjNCBwbGFuZTtcclxuXHJcblx0I2lmZGVmIEFMUEhBX1RPX0NPVkVSQUdFXHJcblxyXG5cdFx0ZmxvYXQgZGlzdGFuY2VUb1BsYW5lLCBkaXN0YW5jZUdyYWRpZW50O1xyXG5cdFx0ZmxvYXQgY2xpcE9wYWNpdHkgPSAxLjA7XHJcblxyXG5cdFx0I3ByYWdtYSB1bnJvbGxfbG9vcF9zdGFydFxyXG5cdFx0Zm9yICggaW50IGkgPSAwOyBpIDwgVU5JT05fQ0xJUFBJTkdfUExBTkVTOyBpICsrICkge1xyXG5cclxuXHRcdFx0cGxhbmUgPSBjbGlwcGluZ1BsYW5lc1sgaSBdO1xyXG5cdFx0XHRkaXN0YW5jZVRvUGxhbmUgPSAtIGRvdCggdkNsaXBQb3NpdGlvbiwgcGxhbmUueHl6ICkgKyBwbGFuZS53O1xyXG5cdFx0XHRkaXN0YW5jZUdyYWRpZW50ID0gZndpZHRoKCBkaXN0YW5jZVRvUGxhbmUgKSAvIDIuMDtcclxuXHRcdFx0Y2xpcE9wYWNpdHkgKj0gc21vb3Roc3RlcCggLSBkaXN0YW5jZUdyYWRpZW50LCBkaXN0YW5jZUdyYWRpZW50LCBkaXN0YW5jZVRvUGxhbmUgKTtcclxuXHJcblx0XHRcdGlmICggY2xpcE9wYWNpdHkgPT0gMC4wICkgZGlzY2FyZDtcclxuXHJcblx0XHR9XHJcblx0XHQjcHJhZ21hIHVucm9sbF9sb29wX2VuZFxyXG5cclxuXHRcdCNpZiBVTklPTl9DTElQUElOR19QTEFORVMgPCBOVU1fQ0xJUFBJTkdfUExBTkVTXHJcblxyXG5cdFx0XHRmbG9hdCB1bmlvbkNsaXBPcGFjaXR5ID0gMS4wO1xyXG5cclxuXHRcdFx0I3ByYWdtYSB1bnJvbGxfbG9vcF9zdGFydFxyXG5cdFx0XHRmb3IgKCBpbnQgaSA9IFVOSU9OX0NMSVBQSU5HX1BMQU5FUzsgaSA8IE5VTV9DTElQUElOR19QTEFORVM7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdHBsYW5lID0gY2xpcHBpbmdQbGFuZXNbIGkgXTtcclxuXHRcdFx0XHRkaXN0YW5jZVRvUGxhbmUgPSAtIGRvdCggdkNsaXBQb3NpdGlvbiwgcGxhbmUueHl6ICkgKyBwbGFuZS53O1xyXG5cdFx0XHRcdGRpc3RhbmNlR3JhZGllbnQgPSBmd2lkdGgoIGRpc3RhbmNlVG9QbGFuZSApIC8gMi4wO1xyXG5cdFx0XHRcdHVuaW9uQ2xpcE9wYWNpdHkgKj0gMS4wIC0gc21vb3Roc3RlcCggLSBkaXN0YW5jZUdyYWRpZW50LCBkaXN0YW5jZUdyYWRpZW50LCBkaXN0YW5jZVRvUGxhbmUgKTtcclxuXHJcblx0XHRcdH1cclxuXHRcdFx0I3ByYWdtYSB1bnJvbGxfbG9vcF9lbmRcclxuXHJcblx0XHRcdGNsaXBPcGFjaXR5ICo9IDEuMCAtIHVuaW9uQ2xpcE9wYWNpdHk7XHJcblxyXG5cdFx0I2VuZGlmXHJcblxyXG5cdFx0ZGlmZnVzZUNvbG9yLmEgKj0gY2xpcE9wYWNpdHk7XHJcblxyXG5cdFx0aWYgKCBkaWZmdXNlQ29sb3IuYSA9PSAwLjAgKSBkaXNjYXJkO1xyXG5cclxuXHQjZWxzZVxyXG5cclxuXHRcdCNwcmFnbWEgdW5yb2xsX2xvb3Bfc3RhcnRcclxuXHRcdGZvciAoIGludCBpID0gMDsgaSA8IFVOSU9OX0NMSVBQSU5HX1BMQU5FUzsgaSArKyApIHtcclxuXHJcblx0XHRcdHBsYW5lID0gY2xpcHBpbmdQbGFuZXNbIGkgXTtcclxuXHRcdFx0aWYgKCBkb3QoIHZDbGlwUG9zaXRpb24sIHBsYW5lLnh5eiApID4gcGxhbmUudyApIGRpc2NhcmQ7XHJcblxyXG5cdFx0fVxyXG5cdFx0I3ByYWdtYSB1bnJvbGxfbG9vcF9lbmRcclxuXHJcblx0XHQjaWYgVU5JT05fQ0xJUFBJTkdfUExBTkVTIDwgTlVNX0NMSVBQSU5HX1BMQU5FU1xyXG5cclxuXHRcdFx0Ym9vbCBjbGlwcGVkID0gdHJ1ZTtcclxuXHJcblx0XHRcdCNwcmFnbWEgdW5yb2xsX2xvb3Bfc3RhcnRcclxuXHRcdFx0Zm9yICggaW50IGkgPSBVTklPTl9DTElQUElOR19QTEFORVM7IGkgPCBOVU1fQ0xJUFBJTkdfUExBTkVTOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRwbGFuZSA9IGNsaXBwaW5nUGxhbmVzWyBpIF07XHJcblx0XHRcdFx0Y2xpcHBlZCA9ICggZG90KCB2Q2xpcFBvc2l0aW9uLCBwbGFuZS54eXogKSA+IHBsYW5lLncgKSAmJiBjbGlwcGVkO1xyXG5cclxuXHRcdFx0fVxyXG5cdFx0XHQjcHJhZ21hIHVucm9sbF9sb29wX2VuZFxyXG5cclxuXHRcdFx0aWYgKCBjbGlwcGVkICkgZGlzY2FyZDtcclxuXHJcblx0XHQjZW5kaWZcclxuXHJcblx0I2VuZGlmXHJcblxyXG4jZW5kaWZcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuI2lmIE5VTV9DTElQUElOR19QTEFORVMgPiAwXHJcblxyXG5cdHZhcnlpbmcgdmVjMyB2Q2xpcFBvc2l0aW9uO1xyXG5cclxuXHR1bmlmb3JtIHZlYzQgY2xpcHBpbmdQbGFuZXNbIE5VTV9DTElQUElOR19QTEFORVMgXTtcclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWYgTlVNX0NMSVBQSU5HX1BMQU5FUyA+IDBcclxuXHJcblx0dmFyeWluZyB2ZWMzIHZDbGlwUG9zaXRpb247XHJcblxyXG4jZW5kaWZcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuI2lmIE5VTV9DTElQUElOR19QTEFORVMgPiAwXHJcblxyXG5cdHZDbGlwUG9zaXRpb24gPSAtIG12UG9zaXRpb24ueHl6O1xyXG5cclxuI2VuZGlmXHJcbmA7XHJcbiIsImV4cG9ydCBkZWZhdWx0IC8qIGdsc2wgKi9gXHJcbiNpZiBkZWZpbmVkKCBVU0VfQ09MT1JfQUxQSEEgKVxyXG5cclxuXHRkaWZmdXNlQ29sb3IgKj0gdkNvbG9yO1xyXG5cclxuI2VsaWYgZGVmaW5lZCggVVNFX0NPTE9SIClcclxuXHJcblx0ZGlmZnVzZUNvbG9yLnJnYiAqPSB2Q29sb3I7XHJcblxyXG4jZW5kaWZcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuI2lmIGRlZmluZWQoIFVTRV9DT0xPUl9BTFBIQSApXHJcblxyXG5cdHZhcnlpbmcgdmVjNCB2Q29sb3I7XHJcblxyXG4jZWxpZiBkZWZpbmVkKCBVU0VfQ09MT1IgKVxyXG5cclxuXHR2YXJ5aW5nIHZlYzMgdkNvbG9yO1xyXG5cclxuI2VuZGlmXHJcbmA7XHJcbiIsImV4cG9ydCBkZWZhdWx0IC8qIGdsc2wgKi9gXHJcbiNpZiBkZWZpbmVkKCBVU0VfQ09MT1JfQUxQSEEgKVxyXG5cclxuXHR2YXJ5aW5nIHZlYzQgdkNvbG9yO1xyXG5cclxuI2VsaWYgZGVmaW5lZCggVVNFX0NPTE9SICkgfHwgZGVmaW5lZCggVVNFX0lOU1RBTkNJTkdfQ09MT1IgKVxyXG5cclxuXHR2YXJ5aW5nIHZlYzMgdkNvbG9yO1xyXG5cclxuI2VuZGlmXHJcbmA7XHJcbiIsImV4cG9ydCBkZWZhdWx0IC8qIGdsc2wgKi9gXHJcbiNpZiBkZWZpbmVkKCBVU0VfQ09MT1JfQUxQSEEgKVxyXG5cclxuXHR2Q29sb3IgPSB2ZWM0KCAxLjAgKTtcclxuXHJcbiNlbGlmIGRlZmluZWQoIFVTRV9DT0xPUiApIHx8IGRlZmluZWQoIFVTRV9JTlNUQU5DSU5HX0NPTE9SIClcclxuXHJcblx0dkNvbG9yID0gdmVjMyggMS4wICk7XHJcblxyXG4jZW5kaWZcclxuXHJcbiNpZmRlZiBVU0VfQ09MT1JcclxuXHJcblx0dkNvbG9yICo9IGNvbG9yO1xyXG5cclxuI2VuZGlmXHJcblxyXG4jaWZkZWYgVVNFX0lOU1RBTkNJTkdfQ09MT1JcclxuXHJcblx0dkNvbG9yLnh5eiAqPSBpbnN0YW5jZUNvbG9yLnh5ejtcclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jZGVmaW5lIFBJIDMuMTQxNTkyNjUzNTg5NzkzXHJcbiNkZWZpbmUgUEkyIDYuMjgzMTg1MzA3MTc5NTg2XHJcbiNkZWZpbmUgUElfSEFMRiAxLjU3MDc5NjMyNjc5NDg5NjZcclxuI2RlZmluZSBSRUNJUFJPQ0FMX1BJIDAuMzE4MzA5ODg2MTgzNzkwN1xyXG4jZGVmaW5lIFJFQ0lQUk9DQUxfUEkyIDAuMTU5MTU0OTQzMDkxODk1MzVcclxuI2RlZmluZSBFUFNJTE9OIDFlLTZcclxuXHJcbiNpZm5kZWYgc2F0dXJhdGVcclxuLy8gPHRvbmVtYXBwaW5nX3BhcnNfZnJhZ21lbnQ+IG1heSBoYXZlIGRlZmluZWQgc2F0dXJhdGUoKSBhbHJlYWR5XHJcbiNkZWZpbmUgc2F0dXJhdGUoIGEgKSBjbGFtcCggYSwgMC4wLCAxLjAgKVxyXG4jZW5kaWZcclxuI2RlZmluZSB3aGl0ZUNvbXBsZW1lbnQoIGEgKSAoIDEuMCAtIHNhdHVyYXRlKCBhICkgKVxyXG5cclxuZmxvYXQgcG93MiggY29uc3QgaW4gZmxvYXQgeCApIHsgcmV0dXJuIHgqeDsgfVxyXG52ZWMzIHBvdzIoIGNvbnN0IGluIHZlYzMgeCApIHsgcmV0dXJuIHgqeDsgfVxyXG5mbG9hdCBwb3czKCBjb25zdCBpbiBmbG9hdCB4ICkgeyByZXR1cm4geCp4Kng7IH1cclxuZmxvYXQgcG93NCggY29uc3QgaW4gZmxvYXQgeCApIHsgZmxvYXQgeDIgPSB4Kng7IHJldHVybiB4Mip4MjsgfVxyXG5mbG9hdCBtYXgzKCBjb25zdCBpbiB2ZWMzIHYgKSB7IHJldHVybiBtYXgoIG1heCggdi54LCB2LnkgKSwgdi56ICk7IH1cclxuZmxvYXQgYXZlcmFnZSggY29uc3QgaW4gdmVjMyB2ICkgeyByZXR1cm4gZG90KCB2LCB2ZWMzKCAwLjMzMzMzMzMgKSApOyB9XHJcblxyXG4vLyBleHBlY3RzIHZhbHVlcyBpbiB0aGUgcmFuZ2Ugb2YgWzAsMV14WzAsMV0sIHJldHVybnMgdmFsdWVzIGluIHRoZSBbMCwxXSByYW5nZS5cclxuLy8gZG8gbm90IGNvbGxhcHNlIGludG8gYSBzaW5nbGUgZnVuY3Rpb24gcGVyOiBodHRwOi8vYnl0ZWJsYWNrc21pdGguY29tL2ltcHJvdmVtZW50cy10by10aGUtY2Fub25pY2FsLW9uZS1saW5lci1nbHNsLXJhbmQtZm9yLW9wZW5nbC1lcy0yLTAvXHJcbmhpZ2hwIGZsb2F0IHJhbmQoIGNvbnN0IGluIHZlYzIgdXYgKSB7XHJcblxyXG5cdGNvbnN0IGhpZ2hwIGZsb2F0IGEgPSAxMi45ODk4LCBiID0gNzguMjMzLCBjID0gNDM3NTguNTQ1MztcclxuXHRoaWdocCBmbG9hdCBkdCA9IGRvdCggdXYueHksIHZlYzIoIGEsYiApICksIHNuID0gbW9kKCBkdCwgUEkgKTtcclxuXHJcblx0cmV0dXJuIGZyYWN0KCBzaW4oIHNuICkgKiBjICk7XHJcblxyXG59XHJcblxyXG4jaWZkZWYgSElHSF9QUkVDSVNJT05cclxuXHRmbG9hdCBwcmVjaXNpb25TYWZlTGVuZ3RoKCB2ZWMzIHYgKSB7IHJldHVybiBsZW5ndGgoIHYgKTsgfVxyXG4jZWxzZVxyXG5cdGZsb2F0IHByZWNpc2lvblNhZmVMZW5ndGgoIHZlYzMgdiApIHtcclxuXHRcdGZsb2F0IG1heENvbXBvbmVudCA9IG1heDMoIGFicyggdiApICk7XHJcblx0XHRyZXR1cm4gbGVuZ3RoKCB2IC8gbWF4Q29tcG9uZW50ICkgKiBtYXhDb21wb25lbnQ7XHJcblx0fVxyXG4jZW5kaWZcclxuXHJcbnN0cnVjdCBJbmNpZGVudExpZ2h0IHtcclxuXHR2ZWMzIGNvbG9yO1xyXG5cdHZlYzMgZGlyZWN0aW9uO1xyXG5cdGJvb2wgdmlzaWJsZTtcclxufTtcclxuXHJcbnN0cnVjdCBSZWZsZWN0ZWRMaWdodCB7XHJcblx0dmVjMyBkaXJlY3REaWZmdXNlO1xyXG5cdHZlYzMgZGlyZWN0U3BlY3VsYXI7XHJcblx0dmVjMyBpbmRpcmVjdERpZmZ1c2U7XHJcblx0dmVjMyBpbmRpcmVjdFNwZWN1bGFyO1xyXG59O1xyXG5cclxuI2lmZGVmIFVTRV9BTFBIQUhBU0hcclxuXHJcblx0dmFyeWluZyB2ZWMzIHZQb3NpdGlvbjtcclxuXHJcbiNlbmRpZlxyXG5cclxudmVjMyB0cmFuc2Zvcm1EaXJlY3Rpb24oIGluIHZlYzMgZGlyLCBpbiBtYXQ0IG1hdHJpeCApIHtcclxuXHJcblx0cmV0dXJuIG5vcm1hbGl6ZSggKCBtYXRyaXggKiB2ZWM0KCBkaXIsIDAuMCApICkueHl6ICk7XHJcblxyXG59XHJcblxyXG52ZWMzIGludmVyc2VUcmFuc2Zvcm1EaXJlY3Rpb24oIGluIHZlYzMgZGlyLCBpbiBtYXQ0IG1hdHJpeCApIHtcclxuXHJcblx0Ly8gZGlyIGNhbiBiZSBlaXRoZXIgYSBkaXJlY3Rpb24gdmVjdG9yIG9yIGEgbm9ybWFsIHZlY3RvclxyXG5cdC8vIHVwcGVyLWxlZnQgM3gzIG9mIG1hdHJpeCBpcyBhc3N1bWVkIHRvIGJlIG9ydGhvZ29uYWxcclxuXHJcblx0cmV0dXJuIG5vcm1hbGl6ZSggKCB2ZWM0KCBkaXIsIDAuMCApICogbWF0cml4ICkueHl6ICk7XHJcblxyXG59XHJcblxyXG5tYXQzIHRyYW5zcG9zZU1hdDMoIGNvbnN0IGluIG1hdDMgbSApIHtcclxuXHJcblx0bWF0MyB0bXA7XHJcblxyXG5cdHRtcFsgMCBdID0gdmVjMyggbVsgMCBdLngsIG1bIDEgXS54LCBtWyAyIF0ueCApO1xyXG5cdHRtcFsgMSBdID0gdmVjMyggbVsgMCBdLnksIG1bIDEgXS55LCBtWyAyIF0ueSApO1xyXG5cdHRtcFsgMiBdID0gdmVjMyggbVsgMCBdLnosIG1bIDEgXS56LCBtWyAyIF0ueiApO1xyXG5cclxuXHRyZXR1cm4gdG1wO1xyXG5cclxufVxyXG5cclxuZmxvYXQgbHVtaW5hbmNlKCBjb25zdCBpbiB2ZWMzIHJnYiApIHtcclxuXHJcblx0Ly8gYXNzdW1lcyByZ2IgaXMgaW4gbGluZWFyIGNvbG9yIHNwYWNlIHdpdGggc1JHQiBwcmltYXJpZXMgYW5kIEQ2NSB3aGl0ZSBwb2ludFxyXG5cclxuXHRjb25zdCB2ZWMzIHdlaWdodHMgPSB2ZWMzKCAwLjIxMjY3MjksIDAuNzE1MTUyMiwgMC4wNzIxNzUwICk7XHJcblxyXG5cdHJldHVybiBkb3QoIHdlaWdodHMsIHJnYiApO1xyXG5cclxufVxyXG5cclxuYm9vbCBpc1BlcnNwZWN0aXZlTWF0cml4KCBtYXQ0IG0gKSB7XHJcblxyXG5cdHJldHVybiBtWyAyIF1bIDMgXSA9PSAtIDEuMDtcclxuXHJcbn1cclxuXHJcbnZlYzIgZXF1aXJlY3RVdiggaW4gdmVjMyBkaXIgKSB7XHJcblxyXG5cdC8vIGRpciBpcyBhc3N1bWVkIHRvIGJlIHVuaXQgbGVuZ3RoXHJcblxyXG5cdGZsb2F0IHUgPSBhdGFuKCBkaXIueiwgZGlyLnggKSAqIFJFQ0lQUk9DQUxfUEkyICsgMC41O1xyXG5cclxuXHRmbG9hdCB2ID0gYXNpbiggY2xhbXAoIGRpci55LCAtIDEuMCwgMS4wICkgKSAqIFJFQ0lQUk9DQUxfUEkgKyAwLjU7XHJcblxyXG5cdHJldHVybiB2ZWMyKCB1LCB2ICk7XHJcblxyXG59XHJcblxyXG52ZWMzIEJSREZfTGFtYmVydCggY29uc3QgaW4gdmVjMyBkaWZmdXNlQ29sb3IgKSB7XHJcblxyXG5cdHJldHVybiBSRUNJUFJPQ0FMX1BJICogZGlmZnVzZUNvbG9yO1xyXG5cclxufSAvLyB2YWxpZGF0ZWRcclxuXHJcbnZlYzMgRl9TY2hsaWNrKCBjb25zdCBpbiB2ZWMzIGYwLCBjb25zdCBpbiBmbG9hdCBmOTAsIGNvbnN0IGluIGZsb2F0IGRvdFZIICkge1xyXG5cclxuXHQvLyBPcmlnaW5hbCBhcHByb3hpbWF0aW9uIGJ5IENocmlzdG9waGUgU2NobGljayAnOTRcclxuXHQvLyBmbG9hdCBmcmVzbmVsID0gcG93KCAxLjAgLSBkb3RWSCwgNS4wICk7XHJcblxyXG5cdC8vIE9wdGltaXplZCB2YXJpYW50IChwcmVzZW50ZWQgYnkgRXBpYyBhdCBTSUdHUkFQSCAnMTMpXHJcblx0Ly8gaHR0cHM6Ly9jZG4yLnVucmVhbGVuZ2luZS5jb20vUmVzb3VyY2VzL2ZpbGVzLzIwMTNTaWdncmFwaFByZXNlbnRhdGlvbnNOb3Rlcy0yNjkxNTczOC5wZGZcclxuXHRmbG9hdCBmcmVzbmVsID0gZXhwMiggKCAtIDUuNTU0NzMgKiBkb3RWSCAtIDYuOTgzMTYgKSAqIGRvdFZIICk7XHJcblxyXG5cdHJldHVybiBmMCAqICggMS4wIC0gZnJlc25lbCApICsgKCBmOTAgKiBmcmVzbmVsICk7XHJcblxyXG59IC8vIHZhbGlkYXRlZFxyXG5cclxuZmxvYXQgRl9TY2hsaWNrKCBjb25zdCBpbiBmbG9hdCBmMCwgY29uc3QgaW4gZmxvYXQgZjkwLCBjb25zdCBpbiBmbG9hdCBkb3RWSCApIHtcclxuXHJcblx0Ly8gT3JpZ2luYWwgYXBwcm94aW1hdGlvbiBieSBDaHJpc3RvcGhlIFNjaGxpY2sgJzk0XHJcblx0Ly8gZmxvYXQgZnJlc25lbCA9IHBvdyggMS4wIC0gZG90VkgsIDUuMCApO1xyXG5cclxuXHQvLyBPcHRpbWl6ZWQgdmFyaWFudCAocHJlc2VudGVkIGJ5IEVwaWMgYXQgU0lHR1JBUEggJzEzKVxyXG5cdC8vIGh0dHBzOi8vY2RuMi51bnJlYWxlbmdpbmUuY29tL1Jlc291cmNlcy9maWxlcy8yMDEzU2lnZ3JhcGhQcmVzZW50YXRpb25zTm90ZXMtMjY5MTU3MzgucGRmXHJcblx0ZmxvYXQgZnJlc25lbCA9IGV4cDIoICggLSA1LjU1NDczICogZG90VkggLSA2Ljk4MzE2ICkgKiBkb3RWSCApO1xyXG5cclxuXHRyZXR1cm4gZjAgKiAoIDEuMCAtIGZyZXNuZWwgKSArICggZjkwICogZnJlc25lbCApO1xyXG5cclxufSAvLyB2YWxpZGF0ZWRcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuI2lmZGVmIEVOVk1BUF9UWVBFX0NVQkVfVVZcclxuXHJcblx0I2RlZmluZSBjdWJlVVZfbWluTWlwTGV2ZWwgNC4wXHJcblx0I2RlZmluZSBjdWJlVVZfbWluVGlsZVNpemUgMTYuMFxyXG5cclxuXHQvLyBUaGVzZSBzaGFkZXIgZnVuY3Rpb25zIGNvbnZlcnQgYmV0d2VlbiB0aGUgVVYgY29vcmRpbmF0ZXMgb2YgYSBzaW5nbGUgZmFjZSBvZlxyXG5cdC8vIGEgY3ViZW1hcCwgdGhlIDAtNSBpbnRlZ2VyIGluZGV4IG9mIGEgY3ViZSBmYWNlLCBhbmQgdGhlIGRpcmVjdGlvbiB2ZWN0b3IgZm9yXHJcblx0Ly8gc2FtcGxpbmcgYSB0ZXh0dXJlQ3ViZSAobm90IGdlbmVyYWxseSBub3JtYWxpemVkICkuXHJcblxyXG5cdGZsb2F0IGdldEZhY2UoIHZlYzMgZGlyZWN0aW9uICkge1xyXG5cclxuXHRcdHZlYzMgYWJzRGlyZWN0aW9uID0gYWJzKCBkaXJlY3Rpb24gKTtcclxuXHJcblx0XHRmbG9hdCBmYWNlID0gLSAxLjA7XHJcblxyXG5cdFx0aWYgKCBhYnNEaXJlY3Rpb24ueCA+IGFic0RpcmVjdGlvbi56ICkge1xyXG5cclxuXHRcdFx0aWYgKCBhYnNEaXJlY3Rpb24ueCA+IGFic0RpcmVjdGlvbi55IClcclxuXHJcblx0XHRcdFx0ZmFjZSA9IGRpcmVjdGlvbi54ID4gMC4wID8gMC4wIDogMy4wO1xyXG5cclxuXHRcdFx0ZWxzZVxyXG5cclxuXHRcdFx0XHRmYWNlID0gZGlyZWN0aW9uLnkgPiAwLjAgPyAxLjAgOiA0LjA7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdGlmICggYWJzRGlyZWN0aW9uLnogPiBhYnNEaXJlY3Rpb24ueSApXHJcblxyXG5cdFx0XHRcdGZhY2UgPSBkaXJlY3Rpb24ueiA+IDAuMCA/IDIuMCA6IDUuMDtcclxuXHJcblx0XHRcdGVsc2VcclxuXHJcblx0XHRcdFx0ZmFjZSA9IGRpcmVjdGlvbi55ID4gMC4wID8gMS4wIDogNC4wO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gZmFjZTtcclxuXHJcblx0fVxyXG5cclxuXHQvLyBSSCBjb29yZGluYXRlIHN5c3RlbTsgUE1SRU0gZmFjZS1pbmRleGluZyBjb252ZW50aW9uXHJcblx0dmVjMiBnZXRVViggdmVjMyBkaXJlY3Rpb24sIGZsb2F0IGZhY2UgKSB7XHJcblxyXG5cdFx0dmVjMiB1djtcclxuXHJcblx0XHRpZiAoIGZhY2UgPT0gMC4wICkge1xyXG5cclxuXHRcdFx0dXYgPSB2ZWMyKCBkaXJlY3Rpb24ueiwgZGlyZWN0aW9uLnkgKSAvIGFicyggZGlyZWN0aW9uLnggKTsgLy8gcG9zIHhcclxuXHJcblx0XHR9IGVsc2UgaWYgKCBmYWNlID09IDEuMCApIHtcclxuXHJcblx0XHRcdHV2ID0gdmVjMiggLSBkaXJlY3Rpb24ueCwgLSBkaXJlY3Rpb24ueiApIC8gYWJzKCBkaXJlY3Rpb24ueSApOyAvLyBwb3MgeVxyXG5cclxuXHRcdH0gZWxzZSBpZiAoIGZhY2UgPT0gMi4wICkge1xyXG5cclxuXHRcdFx0dXYgPSB2ZWMyKCAtIGRpcmVjdGlvbi54LCBkaXJlY3Rpb24ueSApIC8gYWJzKCBkaXJlY3Rpb24ueiApOyAvLyBwb3MgelxyXG5cclxuXHRcdH0gZWxzZSBpZiAoIGZhY2UgPT0gMy4wICkge1xyXG5cclxuXHRcdFx0dXYgPSB2ZWMyKCAtIGRpcmVjdGlvbi56LCBkaXJlY3Rpb24ueSApIC8gYWJzKCBkaXJlY3Rpb24ueCApOyAvLyBuZWcgeFxyXG5cclxuXHRcdH0gZWxzZSBpZiAoIGZhY2UgPT0gNC4wICkge1xyXG5cclxuXHRcdFx0dXYgPSB2ZWMyKCAtIGRpcmVjdGlvbi54LCBkaXJlY3Rpb24ueiApIC8gYWJzKCBkaXJlY3Rpb24ueSApOyAvLyBuZWcgeVxyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHR1diA9IHZlYzIoIGRpcmVjdGlvbi54LCBkaXJlY3Rpb24ueSApIC8gYWJzKCBkaXJlY3Rpb24ueiApOyAvLyBuZWcgelxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gMC41ICogKCB1diArIDEuMCApO1xyXG5cclxuXHR9XHJcblxyXG5cdHZlYzMgYmlsaW5lYXJDdWJlVVYoIHNhbXBsZXIyRCBlbnZNYXAsIHZlYzMgZGlyZWN0aW9uLCBmbG9hdCBtaXBJbnQgKSB7XHJcblxyXG5cdFx0ZmxvYXQgZmFjZSA9IGdldEZhY2UoIGRpcmVjdGlvbiApO1xyXG5cclxuXHRcdGZsb2F0IGZpbHRlckludCA9IG1heCggY3ViZVVWX21pbk1pcExldmVsIC0gbWlwSW50LCAwLjAgKTtcclxuXHJcblx0XHRtaXBJbnQgPSBtYXgoIG1pcEludCwgY3ViZVVWX21pbk1pcExldmVsICk7XHJcblxyXG5cdFx0ZmxvYXQgZmFjZVNpemUgPSBleHAyKCBtaXBJbnQgKTtcclxuXHJcblx0XHRoaWdocCB2ZWMyIHV2ID0gZ2V0VVYoIGRpcmVjdGlvbiwgZmFjZSApICogKCBmYWNlU2l6ZSAtIDIuMCApICsgMS4wOyAvLyAjMjUwNzFcclxuXHJcblx0XHRpZiAoIGZhY2UgPiAyLjAgKSB7XHJcblxyXG5cdFx0XHR1di55ICs9IGZhY2VTaXplO1xyXG5cclxuXHRcdFx0ZmFjZSAtPSAzLjA7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHV2LnggKz0gZmFjZSAqIGZhY2VTaXplO1xyXG5cclxuXHRcdHV2LnggKz0gZmlsdGVySW50ICogMy4wICogY3ViZVVWX21pblRpbGVTaXplO1xyXG5cclxuXHRcdHV2LnkgKz0gNC4wICogKCBleHAyKCBDVUJFVVZfTUFYX01JUCApIC0gZmFjZVNpemUgKTtcclxuXHJcblx0XHR1di54ICo9IENVQkVVVl9URVhFTF9XSURUSDtcclxuXHRcdHV2LnkgKj0gQ1VCRVVWX1RFWEVMX0hFSUdIVDtcclxuXHJcblx0XHQjaWZkZWYgdGV4dHVyZTJER3JhZEVYVFxyXG5cclxuXHRcdFx0cmV0dXJuIHRleHR1cmUyREdyYWRFWFQoIGVudk1hcCwgdXYsIHZlYzIoIDAuMCApLCB2ZWMyKCAwLjAgKSApLnJnYjsgLy8gZGlzYWJsZSBhbmlzb3Ryb3BpYyBmaWx0ZXJpbmdcclxuXHJcblx0XHQjZWxzZVxyXG5cclxuXHRcdFx0cmV0dXJuIHRleHR1cmUyRCggZW52TWFwLCB1diApLnJnYjtcclxuXHJcblx0XHQjZW5kaWZcclxuXHJcblx0fVxyXG5cclxuXHQvLyBUaGVzZSBkZWZpbmVzIG11c3QgbWF0Y2ggd2l0aCBQTVJFTUdlbmVyYXRvclxyXG5cclxuXHQjZGVmaW5lIGN1YmVVVl9yMCAxLjBcclxuXHQjZGVmaW5lIGN1YmVVVl9tMCAtIDIuMFxyXG5cdCNkZWZpbmUgY3ViZVVWX3IxIDAuOFxyXG5cdCNkZWZpbmUgY3ViZVVWX20xIC0gMS4wXHJcblx0I2RlZmluZSBjdWJlVVZfcjQgMC40XHJcblx0I2RlZmluZSBjdWJlVVZfbTQgMi4wXHJcblx0I2RlZmluZSBjdWJlVVZfcjUgMC4zMDVcclxuXHQjZGVmaW5lIGN1YmVVVl9tNSAzLjBcclxuXHQjZGVmaW5lIGN1YmVVVl9yNiAwLjIxXHJcblx0I2RlZmluZSBjdWJlVVZfbTYgNC4wXHJcblxyXG5cdGZsb2F0IHJvdWdobmVzc1RvTWlwKCBmbG9hdCByb3VnaG5lc3MgKSB7XHJcblxyXG5cdFx0ZmxvYXQgbWlwID0gMC4wO1xyXG5cclxuXHRcdGlmICggcm91Z2huZXNzID49IGN1YmVVVl9yMSApIHtcclxuXHJcblx0XHRcdG1pcCA9ICggY3ViZVVWX3IwIC0gcm91Z2huZXNzICkgKiAoIGN1YmVVVl9tMSAtIGN1YmVVVl9tMCApIC8gKCBjdWJlVVZfcjAgLSBjdWJlVVZfcjEgKSArIGN1YmVVVl9tMDtcclxuXHJcblx0XHR9IGVsc2UgaWYgKCByb3VnaG5lc3MgPj0gY3ViZVVWX3I0ICkge1xyXG5cclxuXHRcdFx0bWlwID0gKCBjdWJlVVZfcjEgLSByb3VnaG5lc3MgKSAqICggY3ViZVVWX200IC0gY3ViZVVWX20xICkgLyAoIGN1YmVVVl9yMSAtIGN1YmVVVl9yNCApICsgY3ViZVVWX20xO1xyXG5cclxuXHRcdH0gZWxzZSBpZiAoIHJvdWdobmVzcyA+PSBjdWJlVVZfcjUgKSB7XHJcblxyXG5cdFx0XHRtaXAgPSAoIGN1YmVVVl9yNCAtIHJvdWdobmVzcyApICogKCBjdWJlVVZfbTUgLSBjdWJlVVZfbTQgKSAvICggY3ViZVVWX3I0IC0gY3ViZVVWX3I1ICkgKyBjdWJlVVZfbTQ7XHJcblxyXG5cdFx0fSBlbHNlIGlmICggcm91Z2huZXNzID49IGN1YmVVVl9yNiApIHtcclxuXHJcblx0XHRcdG1pcCA9ICggY3ViZVVWX3I1IC0gcm91Z2huZXNzICkgKiAoIGN1YmVVVl9tNiAtIGN1YmVVVl9tNSApIC8gKCBjdWJlVVZfcjUgLSBjdWJlVVZfcjYgKSArIGN1YmVVVl9tNTtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0bWlwID0gLSAyLjAgKiBsb2cyKCAxLjE2ICogcm91Z2huZXNzICk7IC8vIDEuMTYgPSAxLjc5XjAuMjVcclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gbWlwO1xyXG5cclxuXHR9XHJcblxyXG5cdHZlYzQgdGV4dHVyZUN1YmVVViggc2FtcGxlcjJEIGVudk1hcCwgdmVjMyBzYW1wbGVEaXIsIGZsb2F0IHJvdWdobmVzcyApIHtcclxuXHJcblx0XHRmbG9hdCBtaXAgPSBjbGFtcCggcm91Z2huZXNzVG9NaXAoIHJvdWdobmVzcyApLCBjdWJlVVZfbTAsIENVQkVVVl9NQVhfTUlQICk7XHJcblxyXG5cdFx0ZmxvYXQgbWlwRiA9IGZyYWN0KCBtaXAgKTtcclxuXHJcblx0XHRmbG9hdCBtaXBJbnQgPSBmbG9vciggbWlwICk7XHJcblxyXG5cdFx0dmVjMyBjb2xvcjAgPSBiaWxpbmVhckN1YmVVViggZW52TWFwLCBzYW1wbGVEaXIsIG1pcEludCApO1xyXG5cclxuXHRcdGlmICggbWlwRiA9PSAwLjAgKSB7XHJcblxyXG5cdFx0XHRyZXR1cm4gdmVjNCggY29sb3IwLCAxLjAgKTtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0dmVjMyBjb2xvcjEgPSBiaWxpbmVhckN1YmVVViggZW52TWFwLCBzYW1wbGVEaXIsIG1pcEludCArIDEuMCApO1xyXG5cclxuXHRcdFx0cmV0dXJuIHZlYzQoIG1peCggY29sb3IwLCBjb2xvcjEsIG1pcEYgKSwgMS4wICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG4jZW5kaWZcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuXHJcbnZlYzMgdHJhbnNmb3JtZWROb3JtYWwgPSBvYmplY3ROb3JtYWw7XHJcbiNpZmRlZiBVU0VfVEFOR0VOVFxyXG5cclxuXHR2ZWMzIHRyYW5zZm9ybWVkVGFuZ2VudCA9IG9iamVjdFRhbmdlbnQ7XHJcblxyXG4jZW5kaWZcclxuXHJcbiNpZmRlZiBVU0VfQkFUQ0hJTkdcclxuXHJcblx0Ly8gdGhpcyBpcyBpbiBsaWV1IG9mIGEgcGVyLWluc3RhbmNlIG5vcm1hbC1tYXRyaXhcclxuXHQvLyBzaGVhciB0cmFuc2Zvcm1zIGluIHRoZSBpbnN0YW5jZSBtYXRyaXggYXJlIG5vdCBzdXBwb3J0ZWRcclxuXHJcblx0bWF0MyBibSA9IG1hdDMoIGJhdGNoaW5nTWF0cml4ICk7XHJcblx0dHJhbnNmb3JtZWROb3JtYWwgLz0gdmVjMyggZG90KCBibVsgMCBdLCBibVsgMCBdICksIGRvdCggYm1bIDEgXSwgYm1bIDEgXSApLCBkb3QoIGJtWyAyIF0sIGJtWyAyIF0gKSApO1xyXG5cdHRyYW5zZm9ybWVkTm9ybWFsID0gYm0gKiB0cmFuc2Zvcm1lZE5vcm1hbDtcclxuXHJcblx0I2lmZGVmIFVTRV9UQU5HRU5UXHJcblxyXG5cdFx0dHJhbnNmb3JtZWRUYW5nZW50ID0gYm0gKiB0cmFuc2Zvcm1lZFRhbmdlbnQ7XHJcblxyXG5cdCNlbmRpZlxyXG5cclxuI2VuZGlmXHJcblxyXG4jaWZkZWYgVVNFX0lOU1RBTkNJTkdcclxuXHJcblx0Ly8gdGhpcyBpcyBpbiBsaWV1IG9mIGEgcGVyLWluc3RhbmNlIG5vcm1hbC1tYXRyaXhcclxuXHQvLyBzaGVhciB0cmFuc2Zvcm1zIGluIHRoZSBpbnN0YW5jZSBtYXRyaXggYXJlIG5vdCBzdXBwb3J0ZWRcclxuXHJcblx0bWF0MyBpbSA9IG1hdDMoIGluc3RhbmNlTWF0cml4ICk7XHJcblx0dHJhbnNmb3JtZWROb3JtYWwgLz0gdmVjMyggZG90KCBpbVsgMCBdLCBpbVsgMCBdICksIGRvdCggaW1bIDEgXSwgaW1bIDEgXSApLCBkb3QoIGltWyAyIF0sIGltWyAyIF0gKSApO1xyXG5cdHRyYW5zZm9ybWVkTm9ybWFsID0gaW0gKiB0cmFuc2Zvcm1lZE5vcm1hbDtcclxuXHJcblx0I2lmZGVmIFVTRV9UQU5HRU5UXHJcblxyXG5cdFx0dHJhbnNmb3JtZWRUYW5nZW50ID0gaW0gKiB0cmFuc2Zvcm1lZFRhbmdlbnQ7XHJcblxyXG5cdCNlbmRpZlxyXG5cclxuI2VuZGlmXHJcblxyXG50cmFuc2Zvcm1lZE5vcm1hbCA9IG5vcm1hbE1hdHJpeCAqIHRyYW5zZm9ybWVkTm9ybWFsO1xyXG5cclxuI2lmZGVmIEZMSVBfU0lERURcclxuXHJcblx0dHJhbnNmb3JtZWROb3JtYWwgPSAtIHRyYW5zZm9ybWVkTm9ybWFsO1xyXG5cclxuI2VuZGlmXHJcblxyXG4jaWZkZWYgVVNFX1RBTkdFTlRcclxuXHJcblx0dHJhbnNmb3JtZWRUYW5nZW50ID0gKCBtb2RlbFZpZXdNYXRyaXggKiB2ZWM0KCB0cmFuc2Zvcm1lZFRhbmdlbnQsIDAuMCApICkueHl6O1xyXG5cclxuXHQjaWZkZWYgRkxJUF9TSURFRFxyXG5cclxuXHRcdHRyYW5zZm9ybWVkVGFuZ2VudCA9IC0gdHJhbnNmb3JtZWRUYW5nZW50O1xyXG5cclxuXHQjZW5kaWZcclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWZkZWYgVVNFX0RJU1BMQUNFTUVOVE1BUFxyXG5cclxuXHR1bmlmb3JtIHNhbXBsZXIyRCBkaXNwbGFjZW1lbnRNYXA7XHJcblx0dW5pZm9ybSBmbG9hdCBkaXNwbGFjZW1lbnRTY2FsZTtcclxuXHR1bmlmb3JtIGZsb2F0IGRpc3BsYWNlbWVudEJpYXM7XHJcblxyXG4jZW5kaWZcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuI2lmZGVmIFVTRV9ESVNQTEFDRU1FTlRNQVBcclxuXHJcblx0dHJhbnNmb3JtZWQgKz0gbm9ybWFsaXplKCBvYmplY3ROb3JtYWwgKSAqICggdGV4dHVyZTJEKCBkaXNwbGFjZW1lbnRNYXAsIHZEaXNwbGFjZW1lbnRNYXBVdiApLnggKiBkaXNwbGFjZW1lbnRTY2FsZSArIGRpc3BsYWNlbWVudEJpYXMgKTtcclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWZkZWYgVVNFX0VNSVNTSVZFTUFQXHJcblxyXG5cdHZlYzQgZW1pc3NpdmVDb2xvciA9IHRleHR1cmUyRCggZW1pc3NpdmVNYXAsIHZFbWlzc2l2ZU1hcFV2ICk7XHJcblxyXG5cdHRvdGFsRW1pc3NpdmVSYWRpYW5jZSAqPSBlbWlzc2l2ZUNvbG9yLnJnYjtcclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWZkZWYgVVNFX0VNSVNTSVZFTUFQXHJcblxyXG5cdHVuaWZvcm0gc2FtcGxlcjJEIGVtaXNzaXZlTWFwO1xyXG5cclxuI2VuZGlmXHJcbmA7XHJcbiIsImV4cG9ydCBkZWZhdWx0IC8qIGdsc2wgKi9gXHJcbmdsX0ZyYWdDb2xvciA9IGxpbmVhclRvT3V0cHV0VGV4ZWwoIGdsX0ZyYWdDb2xvciApO1xyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG5cclxuLy8gaHR0cDovL3d3dy5ydXNzZWxsY290dHJlbGwuY29tL3Bob3RvL21hdHJpeENhbGN1bGF0b3IuaHRtXHJcblxyXG4vLyBMaW5lYXIgc1JHQiA9PiBYWVogPT4gTGluZWFyIERpc3BsYXkgUDNcclxuY29uc3QgbWF0MyBMSU5FQVJfU1JHQl9UT19MSU5FQVJfRElTUExBWV9QMyA9IG1hdDMoXHJcblx0dmVjMyggMC44MjI0NjIxLCAwLjE3NzUzOCwgMC4wICksXHJcblx0dmVjMyggMC4wMzMxOTQxLCAwLjk2NjgwNTgsIDAuMCApLFxyXG5cdHZlYzMoIDAuMDE3MDgyNywgMC4wNzIzOTc0LCAwLjkxMDUxOTkgKVxyXG4pO1xyXG5cclxuLy8gTGluZWFyIERpc3BsYXkgUDMgPT4gWFlaID0+IExpbmVhciBzUkdCXHJcbmNvbnN0IG1hdDMgTElORUFSX0RJU1BMQVlfUDNfVE9fTElORUFSX1NSR0IgPSBtYXQzKFxyXG5cdHZlYzMoIDEuMjI0OTQwMSwgLSAwLjIyNDk0MDQsIDAuMCApLFxyXG5cdHZlYzMoIC0gMC4wNDIwNTY5LCAxLjA0MjA1NzEsIDAuMCApLFxyXG5cdHZlYzMoIC0gMC4wMTk2Mzc2LCAtIDAuMDc4NjM2MSwgMS4wOTgyNzM1IClcclxuKTtcclxuXHJcbnZlYzQgTGluZWFyU1JHQlRvTGluZWFyRGlzcGxheVAzKCBpbiB2ZWM0IHZhbHVlICkge1xyXG5cdHJldHVybiB2ZWM0KCB2YWx1ZS5yZ2IgKiBMSU5FQVJfU1JHQl9UT19MSU5FQVJfRElTUExBWV9QMywgdmFsdWUuYSApO1xyXG59XHJcblxyXG52ZWM0IExpbmVhckRpc3BsYXlQM1RvTGluZWFyU1JHQiggaW4gdmVjNCB2YWx1ZSApIHtcclxuXHRyZXR1cm4gdmVjNCggdmFsdWUucmdiICogTElORUFSX0RJU1BMQVlfUDNfVE9fTElORUFSX1NSR0IsIHZhbHVlLmEgKTtcclxufVxyXG5cclxudmVjNCBMaW5lYXJUcmFuc2Zlck9FVEYoIGluIHZlYzQgdmFsdWUgKSB7XHJcblx0cmV0dXJuIHZhbHVlO1xyXG59XHJcblxyXG52ZWM0IHNSR0JUcmFuc2Zlck9FVEYoIGluIHZlYzQgdmFsdWUgKSB7XHJcblx0cmV0dXJuIHZlYzQoIG1peCggcG93KCB2YWx1ZS5yZ2IsIHZlYzMoIDAuNDE2NjYgKSApICogMS4wNTUgLSB2ZWMzKCAwLjA1NSApLCB2YWx1ZS5yZ2IgKiAxMi45MiwgdmVjMyggbGVzc1RoYW5FcXVhbCggdmFsdWUucmdiLCB2ZWMzKCAwLjAwMzEzMDggKSApICkgKSwgdmFsdWUuYSApO1xyXG59XHJcblxyXG4vLyBAZGVwcmVjYXRlZCwgcjE1NlxyXG52ZWM0IExpbmVhclRvTGluZWFyKCBpbiB2ZWM0IHZhbHVlICkge1xyXG5cdHJldHVybiB2YWx1ZTtcclxufVxyXG5cclxuLy8gQGRlcHJlY2F0ZWQsIHIxNTZcclxudmVjNCBMaW5lYXJUb3NSR0IoIGluIHZlYzQgdmFsdWUgKSB7XHJcblx0cmV0dXJuIHNSR0JUcmFuc2Zlck9FVEYoIHZhbHVlICk7XHJcbn1cclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuI2lmZGVmIFVTRV9FTlZNQVBcclxuXHJcblx0I2lmZGVmIEVOVl9XT1JMRFBPU1xyXG5cclxuXHRcdHZlYzMgY2FtZXJhVG9GcmFnO1xyXG5cclxuXHRcdGlmICggaXNPcnRob2dyYXBoaWMgKSB7XHJcblxyXG5cdFx0XHRjYW1lcmFUb0ZyYWcgPSBub3JtYWxpemUoIHZlYzMoIC0gdmlld01hdHJpeFsgMCBdWyAyIF0sIC0gdmlld01hdHJpeFsgMSBdWyAyIF0sIC0gdmlld01hdHJpeFsgMiBdWyAyIF0gKSApO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRjYW1lcmFUb0ZyYWcgPSBub3JtYWxpemUoIHZXb3JsZFBvc2l0aW9uIC0gY2FtZXJhUG9zaXRpb24gKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gVHJhbnNmb3JtaW5nIE5vcm1hbCBWZWN0b3JzIHdpdGggdGhlIEludmVyc2UgVHJhbnNmb3JtYXRpb25cclxuXHRcdHZlYzMgd29ybGROb3JtYWwgPSBpbnZlcnNlVHJhbnNmb3JtRGlyZWN0aW9uKCBub3JtYWwsIHZpZXdNYXRyaXggKTtcclxuXHJcblx0XHQjaWZkZWYgRU5WTUFQX01PREVfUkVGTEVDVElPTlxyXG5cclxuXHRcdFx0dmVjMyByZWZsZWN0VmVjID0gcmVmbGVjdCggY2FtZXJhVG9GcmFnLCB3b3JsZE5vcm1hbCApO1xyXG5cclxuXHRcdCNlbHNlXHJcblxyXG5cdFx0XHR2ZWMzIHJlZmxlY3RWZWMgPSByZWZyYWN0KCBjYW1lcmFUb0ZyYWcsIHdvcmxkTm9ybWFsLCByZWZyYWN0aW9uUmF0aW8gKTtcclxuXHJcblx0XHQjZW5kaWZcclxuXHJcblx0I2Vsc2VcclxuXHJcblx0XHR2ZWMzIHJlZmxlY3RWZWMgPSB2UmVmbGVjdDtcclxuXHJcblx0I2VuZGlmXHJcblxyXG5cdCNpZmRlZiBFTlZNQVBfVFlQRV9DVUJFXHJcblxyXG5cdFx0dmVjNCBlbnZDb2xvciA9IHRleHR1cmVDdWJlKCBlbnZNYXAsIHZlYzMoIGZsaXBFbnZNYXAgKiByZWZsZWN0VmVjLngsIHJlZmxlY3RWZWMueXogKSApO1xyXG5cclxuXHQjZWxzZVxyXG5cclxuXHRcdHZlYzQgZW52Q29sb3IgPSB2ZWM0KCAwLjAgKTtcclxuXHJcblx0I2VuZGlmXHJcblxyXG5cdCNpZmRlZiBFTlZNQVBfQkxFTkRJTkdfTVVMVElQTFlcclxuXHJcblx0XHRvdXRnb2luZ0xpZ2h0ID0gbWl4KCBvdXRnb2luZ0xpZ2h0LCBvdXRnb2luZ0xpZ2h0ICogZW52Q29sb3IueHl6LCBzcGVjdWxhclN0cmVuZ3RoICogcmVmbGVjdGl2aXR5ICk7XHJcblxyXG5cdCNlbGlmIGRlZmluZWQoIEVOVk1BUF9CTEVORElOR19NSVggKVxyXG5cclxuXHRcdG91dGdvaW5nTGlnaHQgPSBtaXgoIG91dGdvaW5nTGlnaHQsIGVudkNvbG9yLnh5eiwgc3BlY3VsYXJTdHJlbmd0aCAqIHJlZmxlY3Rpdml0eSApO1xyXG5cclxuXHQjZWxpZiBkZWZpbmVkKCBFTlZNQVBfQkxFTkRJTkdfQUREIClcclxuXHJcblx0XHRvdXRnb2luZ0xpZ2h0ICs9IGVudkNvbG9yLnh5eiAqIHNwZWN1bGFyU3RyZW5ndGggKiByZWZsZWN0aXZpdHk7XHJcblxyXG5cdCNlbmRpZlxyXG5cclxuI2VuZGlmXHJcbmA7XHJcbiIsImV4cG9ydCBkZWZhdWx0IC8qIGdsc2wgKi9gXHJcbiNpZmRlZiBVU0VfRU5WTUFQXHJcblxyXG5cdHVuaWZvcm0gZmxvYXQgZW52TWFwSW50ZW5zaXR5O1xyXG5cdHVuaWZvcm0gZmxvYXQgZmxpcEVudk1hcDtcclxuXHJcblx0I2lmZGVmIEVOVk1BUF9UWVBFX0NVQkVcclxuXHRcdHVuaWZvcm0gc2FtcGxlckN1YmUgZW52TWFwO1xyXG5cdCNlbHNlXHJcblx0XHR1bmlmb3JtIHNhbXBsZXIyRCBlbnZNYXA7XHJcblx0I2VuZGlmXHJcblx0XHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWZkZWYgVVNFX0VOVk1BUFxyXG5cclxuXHR1bmlmb3JtIGZsb2F0IHJlZmxlY3Rpdml0eTtcclxuXHJcblx0I2lmIGRlZmluZWQoIFVTRV9CVU1QTUFQICkgfHwgZGVmaW5lZCggVVNFX05PUk1BTE1BUCApIHx8IGRlZmluZWQoIFBIT05HICkgfHwgZGVmaW5lZCggTEFNQkVSVCApXHJcblxyXG5cdFx0I2RlZmluZSBFTlZfV09STERQT1NcclxuXHJcblx0I2VuZGlmXHJcblxyXG5cdCNpZmRlZiBFTlZfV09STERQT1NcclxuXHJcblx0XHR2YXJ5aW5nIHZlYzMgdldvcmxkUG9zaXRpb247XHJcblx0XHR1bmlmb3JtIGZsb2F0IHJlZnJhY3Rpb25SYXRpbztcclxuXHQjZWxzZVxyXG5cdFx0dmFyeWluZyB2ZWMzIHZSZWZsZWN0O1xyXG5cdCNlbmRpZlxyXG5cclxuI2VuZGlmXHJcbmA7XHJcbiIsImV4cG9ydCBkZWZhdWx0IC8qIGdsc2wgKi9gXHJcbiNpZmRlZiBVU0VfRU5WTUFQXHJcblxyXG5cdCNpZiBkZWZpbmVkKCBVU0VfQlVNUE1BUCApIHx8IGRlZmluZWQoIFVTRV9OT1JNQUxNQVAgKSB8fCBkZWZpbmVkKCBQSE9ORyApIHx8IGRlZmluZWQoIExBTUJFUlQgKVxyXG5cclxuXHRcdCNkZWZpbmUgRU5WX1dPUkxEUE9TXHJcblxyXG5cdCNlbmRpZlxyXG5cclxuXHQjaWZkZWYgRU5WX1dPUkxEUE9TXHJcblx0XHRcclxuXHRcdHZhcnlpbmcgdmVjMyB2V29ybGRQb3NpdGlvbjtcclxuXHJcblx0I2Vsc2VcclxuXHJcblx0XHR2YXJ5aW5nIHZlYzMgdlJlZmxlY3Q7XHJcblx0XHR1bmlmb3JtIGZsb2F0IHJlZnJhY3Rpb25SYXRpbztcclxuXHJcblx0I2VuZGlmXHJcblxyXG4jZW5kaWZcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuI2lmZGVmIFVTRV9FTlZNQVBcclxuXHJcblx0I2lmZGVmIEVOVl9XT1JMRFBPU1xyXG5cclxuXHRcdHZXb3JsZFBvc2l0aW9uID0gd29ybGRQb3NpdGlvbi54eXo7XHJcblxyXG5cdCNlbHNlXHJcblxyXG5cdFx0dmVjMyBjYW1lcmFUb1ZlcnRleDtcclxuXHJcblx0XHRpZiAoIGlzT3J0aG9ncmFwaGljICkge1xyXG5cclxuXHRcdFx0Y2FtZXJhVG9WZXJ0ZXggPSBub3JtYWxpemUoIHZlYzMoIC0gdmlld01hdHJpeFsgMCBdWyAyIF0sIC0gdmlld01hdHJpeFsgMSBdWyAyIF0sIC0gdmlld01hdHJpeFsgMiBdWyAyIF0gKSApO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRjYW1lcmFUb1ZlcnRleCA9IG5vcm1hbGl6ZSggd29ybGRQb3NpdGlvbi54eXogLSBjYW1lcmFQb3NpdGlvbiApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHR2ZWMzIHdvcmxkTm9ybWFsID0gaW52ZXJzZVRyYW5zZm9ybURpcmVjdGlvbiggdHJhbnNmb3JtZWROb3JtYWwsIHZpZXdNYXRyaXggKTtcclxuXHJcblx0XHQjaWZkZWYgRU5WTUFQX01PREVfUkVGTEVDVElPTlxyXG5cclxuXHRcdFx0dlJlZmxlY3QgPSByZWZsZWN0KCBjYW1lcmFUb1ZlcnRleCwgd29ybGROb3JtYWwgKTtcclxuXHJcblx0XHQjZWxzZVxyXG5cclxuXHRcdFx0dlJlZmxlY3QgPSByZWZyYWN0KCBjYW1lcmFUb1ZlcnRleCwgd29ybGROb3JtYWwsIHJlZnJhY3Rpb25SYXRpbyApO1xyXG5cclxuXHRcdCNlbmRpZlxyXG5cclxuXHQjZW5kaWZcclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWZkZWYgVVNFX0ZPR1xyXG5cclxuXHR2Rm9nRGVwdGggPSAtIG12UG9zaXRpb24uejtcclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWZkZWYgVVNFX0ZPR1xyXG5cclxuXHR2YXJ5aW5nIGZsb2F0IHZGb2dEZXB0aDtcclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWZkZWYgVVNFX0ZPR1xyXG5cclxuXHQjaWZkZWYgRk9HX0VYUDJcclxuXHJcblx0XHRmbG9hdCBmb2dGYWN0b3IgPSAxLjAgLSBleHAoIC0gZm9nRGVuc2l0eSAqIGZvZ0RlbnNpdHkgKiB2Rm9nRGVwdGggKiB2Rm9nRGVwdGggKTtcclxuXHJcblx0I2Vsc2VcclxuXHJcblx0XHRmbG9hdCBmb2dGYWN0b3IgPSBzbW9vdGhzdGVwKCBmb2dOZWFyLCBmb2dGYXIsIHZGb2dEZXB0aCApO1xyXG5cclxuXHQjZW5kaWZcclxuXHJcblx0Z2xfRnJhZ0NvbG9yLnJnYiA9IG1peCggZ2xfRnJhZ0NvbG9yLnJnYiwgZm9nQ29sb3IsIGZvZ0ZhY3RvciApO1xyXG5cclxuI2VuZGlmXHJcbmA7XHJcbiIsImV4cG9ydCBkZWZhdWx0IC8qIGdsc2wgKi9gXHJcbiNpZmRlZiBVU0VfRk9HXHJcblxyXG5cdHVuaWZvcm0gdmVjMyBmb2dDb2xvcjtcclxuXHR2YXJ5aW5nIGZsb2F0IHZGb2dEZXB0aDtcclxuXHJcblx0I2lmZGVmIEZPR19FWFAyXHJcblxyXG5cdFx0dW5pZm9ybSBmbG9hdCBmb2dEZW5zaXR5O1xyXG5cclxuXHQjZWxzZVxyXG5cclxuXHRcdHVuaWZvcm0gZmxvYXQgZm9nTmVhcjtcclxuXHRcdHVuaWZvcm0gZmxvYXQgZm9nRmFyO1xyXG5cclxuXHQjZW5kaWZcclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG5cclxuI2lmZGVmIFVTRV9HUkFESUVOVE1BUFxyXG5cclxuXHR1bmlmb3JtIHNhbXBsZXIyRCBncmFkaWVudE1hcDtcclxuXHJcbiNlbmRpZlxyXG5cclxudmVjMyBnZXRHcmFkaWVudElycmFkaWFuY2UoIHZlYzMgbm9ybWFsLCB2ZWMzIGxpZ2h0RGlyZWN0aW9uICkge1xyXG5cclxuXHQvLyBkb3ROTCB3aWxsIGJlIGZyb20gLTEuMCB0byAxLjBcclxuXHRmbG9hdCBkb3ROTCA9IGRvdCggbm9ybWFsLCBsaWdodERpcmVjdGlvbiApO1xyXG5cdHZlYzIgY29vcmQgPSB2ZWMyKCBkb3ROTCAqIDAuNSArIDAuNSwgMC4wICk7XHJcblxyXG5cdCNpZmRlZiBVU0VfR1JBRElFTlRNQVBcclxuXHJcblx0XHRyZXR1cm4gdmVjMyggdGV4dHVyZTJEKCBncmFkaWVudE1hcCwgY29vcmQgKS5yICk7XHJcblxyXG5cdCNlbHNlXHJcblxyXG5cdFx0dmVjMiBmdyA9IGZ3aWR0aCggY29vcmQgKSAqIDAuNTtcclxuXHRcdHJldHVybiBtaXgoIHZlYzMoIDAuNyApLCB2ZWMzKCAxLjAgKSwgc21vb3Roc3RlcCggMC43IC0gZncueCwgMC43ICsgZncueCwgY29vcmQueCApICk7XHJcblxyXG5cdCNlbmRpZlxyXG5cclxufVxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWZkZWYgVVNFX0xJR0hUTUFQXHJcblxyXG5cdHZlYzQgbGlnaHRNYXBUZXhlbCA9IHRleHR1cmUyRCggbGlnaHRNYXAsIHZMaWdodE1hcFV2ICk7XHJcblx0dmVjMyBsaWdodE1hcElycmFkaWFuY2UgPSBsaWdodE1hcFRleGVsLnJnYiAqIGxpZ2h0TWFwSW50ZW5zaXR5O1xyXG5cclxuXHRyZWZsZWN0ZWRMaWdodC5pbmRpcmVjdERpZmZ1c2UgKz0gbGlnaHRNYXBJcnJhZGlhbmNlO1xyXG5cclxuI2VuZGlmXHJcbmA7XHJcbiIsImV4cG9ydCBkZWZhdWx0IC8qIGdsc2wgKi9gXHJcbiNpZmRlZiBVU0VfTElHSFRNQVBcclxuXHJcblx0dW5pZm9ybSBzYW1wbGVyMkQgbGlnaHRNYXA7XHJcblx0dW5pZm9ybSBmbG9hdCBsaWdodE1hcEludGVuc2l0eTtcclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG5MYW1iZXJ0TWF0ZXJpYWwgbWF0ZXJpYWw7XHJcbm1hdGVyaWFsLmRpZmZ1c2VDb2xvciA9IGRpZmZ1c2VDb2xvci5yZ2I7XHJcbm1hdGVyaWFsLnNwZWN1bGFyU3RyZW5ndGggPSBzcGVjdWxhclN0cmVuZ3RoO1xyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG52YXJ5aW5nIHZlYzMgdlZpZXdQb3NpdGlvbjtcclxuXHJcbnN0cnVjdCBMYW1iZXJ0TWF0ZXJpYWwge1xyXG5cclxuXHR2ZWMzIGRpZmZ1c2VDb2xvcjtcclxuXHRmbG9hdCBzcGVjdWxhclN0cmVuZ3RoO1xyXG5cclxufTtcclxuXHJcbnZvaWQgUkVfRGlyZWN0X0xhbWJlcnQoIGNvbnN0IGluIEluY2lkZW50TGlnaHQgZGlyZWN0TGlnaHQsIGNvbnN0IGluIHZlYzMgZ2VvbWV0cnlQb3NpdGlvbiwgY29uc3QgaW4gdmVjMyBnZW9tZXRyeU5vcm1hbCwgY29uc3QgaW4gdmVjMyBnZW9tZXRyeVZpZXdEaXIsIGNvbnN0IGluIHZlYzMgZ2VvbWV0cnlDbGVhcmNvYXROb3JtYWwsIGNvbnN0IGluIExhbWJlcnRNYXRlcmlhbCBtYXRlcmlhbCwgaW5vdXQgUmVmbGVjdGVkTGlnaHQgcmVmbGVjdGVkTGlnaHQgKSB7XHJcblxyXG5cdGZsb2F0IGRvdE5MID0gc2F0dXJhdGUoIGRvdCggZ2VvbWV0cnlOb3JtYWwsIGRpcmVjdExpZ2h0LmRpcmVjdGlvbiApICk7XHJcblx0dmVjMyBpcnJhZGlhbmNlID0gZG90TkwgKiBkaXJlY3RMaWdodC5jb2xvcjtcclxuXHJcblx0cmVmbGVjdGVkTGlnaHQuZGlyZWN0RGlmZnVzZSArPSBpcnJhZGlhbmNlICogQlJERl9MYW1iZXJ0KCBtYXRlcmlhbC5kaWZmdXNlQ29sb3IgKTtcclxuXHJcbn1cclxuXHJcbnZvaWQgUkVfSW5kaXJlY3REaWZmdXNlX0xhbWJlcnQoIGNvbnN0IGluIHZlYzMgaXJyYWRpYW5jZSwgY29uc3QgaW4gdmVjMyBnZW9tZXRyeVBvc2l0aW9uLCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5Tm9ybWFsLCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5Vmlld0RpciwgY29uc3QgaW4gdmVjMyBnZW9tZXRyeUNsZWFyY29hdE5vcm1hbCwgY29uc3QgaW4gTGFtYmVydE1hdGVyaWFsIG1hdGVyaWFsLCBpbm91dCBSZWZsZWN0ZWRMaWdodCByZWZsZWN0ZWRMaWdodCApIHtcclxuXHJcblx0cmVmbGVjdGVkTGlnaHQuaW5kaXJlY3REaWZmdXNlICs9IGlycmFkaWFuY2UgKiBCUkRGX0xhbWJlcnQoIG1hdGVyaWFsLmRpZmZ1c2VDb2xvciApO1xyXG5cclxufVxyXG5cclxuI2RlZmluZSBSRV9EaXJlY3RcdFx0XHRcdFJFX0RpcmVjdF9MYW1iZXJ0XHJcbiNkZWZpbmUgUkVfSW5kaXJlY3REaWZmdXNlXHRcdFJFX0luZGlyZWN0RGlmZnVzZV9MYW1iZXJ0XHJcbmA7XHJcbiIsImV4cG9ydCBkZWZhdWx0IC8qIGdsc2wgKi9gXHJcbnVuaWZvcm0gYm9vbCByZWNlaXZlU2hhZG93O1xyXG51bmlmb3JtIHZlYzMgYW1iaWVudExpZ2h0Q29sb3I7XHJcblxyXG4jaWYgZGVmaW5lZCggVVNFX0xJR0hUX1BST0JFUyApXHJcblxyXG5cdHVuaWZvcm0gdmVjMyBsaWdodFByb2JlWyA5IF07XHJcblxyXG4jZW5kaWZcclxuXHJcbi8vIGdldCB0aGUgaXJyYWRpYW5jZSAocmFkaWFuY2UgY29udm9sdmVkIHdpdGggY29zaW5lIGxvYmUpIGF0IHRoZSBwb2ludCAnbm9ybWFsJyBvbiB0aGUgdW5pdCBzcGhlcmVcclxuLy8gc291cmNlOiBodHRwczovL2dyYXBoaWNzLnN0YW5mb3JkLmVkdS9wYXBlcnMvZW52bWFwL2Vudm1hcC5wZGZcclxudmVjMyBzaEdldElycmFkaWFuY2VBdCggaW4gdmVjMyBub3JtYWwsIGluIHZlYzMgc2hDb2VmZmljaWVudHNbIDkgXSApIHtcclxuXHJcblx0Ly8gbm9ybWFsIGlzIGFzc3VtZWQgdG8gaGF2ZSB1bml0IGxlbmd0aFxyXG5cclxuXHRmbG9hdCB4ID0gbm9ybWFsLngsIHkgPSBub3JtYWwueSwgeiA9IG5vcm1hbC56O1xyXG5cclxuXHQvLyBiYW5kIDBcclxuXHR2ZWMzIHJlc3VsdCA9IHNoQ29lZmZpY2llbnRzWyAwIF0gKiAwLjg4NjIyNztcclxuXHJcblx0Ly8gYmFuZCAxXHJcblx0cmVzdWx0ICs9IHNoQ29lZmZpY2llbnRzWyAxIF0gKiAyLjAgKiAwLjUxMTY2NCAqIHk7XHJcblx0cmVzdWx0ICs9IHNoQ29lZmZpY2llbnRzWyAyIF0gKiAyLjAgKiAwLjUxMTY2NCAqIHo7XHJcblx0cmVzdWx0ICs9IHNoQ29lZmZpY2llbnRzWyAzIF0gKiAyLjAgKiAwLjUxMTY2NCAqIHg7XHJcblxyXG5cdC8vIGJhbmQgMlxyXG5cdHJlc3VsdCArPSBzaENvZWZmaWNpZW50c1sgNCBdICogMi4wICogMC40MjkwNDMgKiB4ICogeTtcclxuXHRyZXN1bHQgKz0gc2hDb2VmZmljaWVudHNbIDUgXSAqIDIuMCAqIDAuNDI5MDQzICogeSAqIHo7XHJcblx0cmVzdWx0ICs9IHNoQ29lZmZpY2llbnRzWyA2IF0gKiAoIDAuNzQzMTI1ICogeiAqIHogLSAwLjI0NzcwOCApO1xyXG5cdHJlc3VsdCArPSBzaENvZWZmaWNpZW50c1sgNyBdICogMi4wICogMC40MjkwNDMgKiB4ICogejtcclxuXHRyZXN1bHQgKz0gc2hDb2VmZmljaWVudHNbIDggXSAqIDAuNDI5MDQzICogKCB4ICogeCAtIHkgKiB5ICk7XHJcblxyXG5cdHJldHVybiByZXN1bHQ7XHJcblxyXG59XHJcblxyXG52ZWMzIGdldExpZ2h0UHJvYmVJcnJhZGlhbmNlKCBjb25zdCBpbiB2ZWMzIGxpZ2h0UHJvYmVbIDkgXSwgY29uc3QgaW4gdmVjMyBub3JtYWwgKSB7XHJcblxyXG5cdHZlYzMgd29ybGROb3JtYWwgPSBpbnZlcnNlVHJhbnNmb3JtRGlyZWN0aW9uKCBub3JtYWwsIHZpZXdNYXRyaXggKTtcclxuXHJcblx0dmVjMyBpcnJhZGlhbmNlID0gc2hHZXRJcnJhZGlhbmNlQXQoIHdvcmxkTm9ybWFsLCBsaWdodFByb2JlICk7XHJcblxyXG5cdHJldHVybiBpcnJhZGlhbmNlO1xyXG5cclxufVxyXG5cclxudmVjMyBnZXRBbWJpZW50TGlnaHRJcnJhZGlhbmNlKCBjb25zdCBpbiB2ZWMzIGFtYmllbnRMaWdodENvbG9yICkge1xyXG5cclxuXHR2ZWMzIGlycmFkaWFuY2UgPSBhbWJpZW50TGlnaHRDb2xvcjtcclxuXHJcblx0cmV0dXJuIGlycmFkaWFuY2U7XHJcblxyXG59XHJcblxyXG5mbG9hdCBnZXREaXN0YW5jZUF0dGVudWF0aW9uKCBjb25zdCBpbiBmbG9hdCBsaWdodERpc3RhbmNlLCBjb25zdCBpbiBmbG9hdCBjdXRvZmZEaXN0YW5jZSwgY29uc3QgaW4gZmxvYXQgZGVjYXlFeHBvbmVudCApIHtcclxuXHJcblx0I2lmIGRlZmluZWQgKCBMRUdBQ1lfTElHSFRTIClcclxuXHJcblx0XHRpZiAoIGN1dG9mZkRpc3RhbmNlID4gMC4wICYmIGRlY2F5RXhwb25lbnQgPiAwLjAgKSB7XHJcblxyXG5cdFx0XHRyZXR1cm4gcG93KCBzYXR1cmF0ZSggLSBsaWdodERpc3RhbmNlIC8gY3V0b2ZmRGlzdGFuY2UgKyAxLjAgKSwgZGVjYXlFeHBvbmVudCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gMS4wO1xyXG5cclxuXHQjZWxzZVxyXG5cclxuXHRcdC8vIGJhc2VkIHVwb24gRnJvc3RiaXRlIDMgTW92aW5nIHRvIFBoeXNpY2FsbHktYmFzZWQgUmVuZGVyaW5nXHJcblx0XHQvLyBwYWdlIDMyLCBlcXVhdGlvbiAyNjogRVt3aW5kb3cxXVxyXG5cdFx0Ly8gaHR0cHM6Ly9zZWJsYWdhcmRlLmZpbGVzLndvcmRwcmVzcy5jb20vMjAxNS8wNy9jb3Vyc2Vfbm90ZXNfbW92aW5nX2Zyb3N0Yml0ZV90b19wYnJfdjMyLnBkZlxyXG5cdFx0ZmxvYXQgZGlzdGFuY2VGYWxsb2ZmID0gMS4wIC8gbWF4KCBwb3coIGxpZ2h0RGlzdGFuY2UsIGRlY2F5RXhwb25lbnQgKSwgMC4wMSApO1xyXG5cclxuXHRcdGlmICggY3V0b2ZmRGlzdGFuY2UgPiAwLjAgKSB7XHJcblxyXG5cdFx0XHRkaXN0YW5jZUZhbGxvZmYgKj0gcG93Miggc2F0dXJhdGUoIDEuMCAtIHBvdzQoIGxpZ2h0RGlzdGFuY2UgLyBjdXRvZmZEaXN0YW5jZSApICkgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIGRpc3RhbmNlRmFsbG9mZjtcclxuXHJcblx0I2VuZGlmXHJcblxyXG59XHJcblxyXG5mbG9hdCBnZXRTcG90QXR0ZW51YXRpb24oIGNvbnN0IGluIGZsb2F0IGNvbmVDb3NpbmUsIGNvbnN0IGluIGZsb2F0IHBlbnVtYnJhQ29zaW5lLCBjb25zdCBpbiBmbG9hdCBhbmdsZUNvc2luZSApIHtcclxuXHJcblx0cmV0dXJuIHNtb290aHN0ZXAoIGNvbmVDb3NpbmUsIHBlbnVtYnJhQ29zaW5lLCBhbmdsZUNvc2luZSApO1xyXG5cclxufVxyXG5cclxuI2lmIE5VTV9ESVJfTElHSFRTID4gMFxyXG5cclxuXHRzdHJ1Y3QgRGlyZWN0aW9uYWxMaWdodCB7XHJcblx0XHR2ZWMzIGRpcmVjdGlvbjtcclxuXHRcdHZlYzMgY29sb3I7XHJcblx0fTtcclxuXHJcblx0dW5pZm9ybSBEaXJlY3Rpb25hbExpZ2h0IGRpcmVjdGlvbmFsTGlnaHRzWyBOVU1fRElSX0xJR0hUUyBdO1xyXG5cclxuXHR2b2lkIGdldERpcmVjdGlvbmFsTGlnaHRJbmZvKCBjb25zdCBpbiBEaXJlY3Rpb25hbExpZ2h0IGRpcmVjdGlvbmFsTGlnaHQsIG91dCBJbmNpZGVudExpZ2h0IGxpZ2h0ICkge1xyXG5cclxuXHRcdGxpZ2h0LmNvbG9yID0gZGlyZWN0aW9uYWxMaWdodC5jb2xvcjtcclxuXHRcdGxpZ2h0LmRpcmVjdGlvbiA9IGRpcmVjdGlvbmFsTGlnaHQuZGlyZWN0aW9uO1xyXG5cdFx0bGlnaHQudmlzaWJsZSA9IHRydWU7XHJcblxyXG5cdH1cclxuXHJcbiNlbmRpZlxyXG5cclxuXHJcbiNpZiBOVU1fUE9JTlRfTElHSFRTID4gMFxyXG5cclxuXHRzdHJ1Y3QgUG9pbnRMaWdodCB7XHJcblx0XHR2ZWMzIHBvc2l0aW9uO1xyXG5cdFx0dmVjMyBjb2xvcjtcclxuXHRcdGZsb2F0IGRpc3RhbmNlO1xyXG5cdFx0ZmxvYXQgZGVjYXk7XHJcblx0fTtcclxuXHJcblx0dW5pZm9ybSBQb2ludExpZ2h0IHBvaW50TGlnaHRzWyBOVU1fUE9JTlRfTElHSFRTIF07XHJcblxyXG5cdC8vIGxpZ2h0IGlzIGFuIG91dCBwYXJhbWV0ZXIgYXMgaGF2aW5nIGl0IGFzIGEgcmV0dXJuIHZhbHVlIGNhdXNlZCBjb21waWxlciBlcnJvcnMgb24gc29tZSBkZXZpY2VzXHJcblx0dm9pZCBnZXRQb2ludExpZ2h0SW5mbyggY29uc3QgaW4gUG9pbnRMaWdodCBwb2ludExpZ2h0LCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5UG9zaXRpb24sIG91dCBJbmNpZGVudExpZ2h0IGxpZ2h0ICkge1xyXG5cclxuXHRcdHZlYzMgbFZlY3RvciA9IHBvaW50TGlnaHQucG9zaXRpb24gLSBnZW9tZXRyeVBvc2l0aW9uO1xyXG5cclxuXHRcdGxpZ2h0LmRpcmVjdGlvbiA9IG5vcm1hbGl6ZSggbFZlY3RvciApO1xyXG5cclxuXHRcdGZsb2F0IGxpZ2h0RGlzdGFuY2UgPSBsZW5ndGgoIGxWZWN0b3IgKTtcclxuXHJcblx0XHRsaWdodC5jb2xvciA9IHBvaW50TGlnaHQuY29sb3I7XHJcblx0XHRsaWdodC5jb2xvciAqPSBnZXREaXN0YW5jZUF0dGVudWF0aW9uKCBsaWdodERpc3RhbmNlLCBwb2ludExpZ2h0LmRpc3RhbmNlLCBwb2ludExpZ2h0LmRlY2F5ICk7XHJcblx0XHRsaWdodC52aXNpYmxlID0gKCBsaWdodC5jb2xvciAhPSB2ZWMzKCAwLjAgKSApO1xyXG5cclxuXHR9XHJcblxyXG4jZW5kaWZcclxuXHJcblxyXG4jaWYgTlVNX1NQT1RfTElHSFRTID4gMFxyXG5cclxuXHRzdHJ1Y3QgU3BvdExpZ2h0IHtcclxuXHRcdHZlYzMgcG9zaXRpb247XHJcblx0XHR2ZWMzIGRpcmVjdGlvbjtcclxuXHRcdHZlYzMgY29sb3I7XHJcblx0XHRmbG9hdCBkaXN0YW5jZTtcclxuXHRcdGZsb2F0IGRlY2F5O1xyXG5cdFx0ZmxvYXQgY29uZUNvcztcclxuXHRcdGZsb2F0IHBlbnVtYnJhQ29zO1xyXG5cdH07XHJcblxyXG5cdHVuaWZvcm0gU3BvdExpZ2h0IHNwb3RMaWdodHNbIE5VTV9TUE9UX0xJR0hUUyBdO1xyXG5cclxuXHQvLyBsaWdodCBpcyBhbiBvdXQgcGFyYW1ldGVyIGFzIGhhdmluZyBpdCBhcyBhIHJldHVybiB2YWx1ZSBjYXVzZWQgY29tcGlsZXIgZXJyb3JzIG9uIHNvbWUgZGV2aWNlc1xyXG5cdHZvaWQgZ2V0U3BvdExpZ2h0SW5mbyggY29uc3QgaW4gU3BvdExpZ2h0IHNwb3RMaWdodCwgY29uc3QgaW4gdmVjMyBnZW9tZXRyeVBvc2l0aW9uLCBvdXQgSW5jaWRlbnRMaWdodCBsaWdodCApIHtcclxuXHJcblx0XHR2ZWMzIGxWZWN0b3IgPSBzcG90TGlnaHQucG9zaXRpb24gLSBnZW9tZXRyeVBvc2l0aW9uO1xyXG5cclxuXHRcdGxpZ2h0LmRpcmVjdGlvbiA9IG5vcm1hbGl6ZSggbFZlY3RvciApO1xyXG5cclxuXHRcdGZsb2F0IGFuZ2xlQ29zID0gZG90KCBsaWdodC5kaXJlY3Rpb24sIHNwb3RMaWdodC5kaXJlY3Rpb24gKTtcclxuXHJcblx0XHRmbG9hdCBzcG90QXR0ZW51YXRpb24gPSBnZXRTcG90QXR0ZW51YXRpb24oIHNwb3RMaWdodC5jb25lQ29zLCBzcG90TGlnaHQucGVudW1icmFDb3MsIGFuZ2xlQ29zICk7XHJcblxyXG5cdFx0aWYgKCBzcG90QXR0ZW51YXRpb24gPiAwLjAgKSB7XHJcblxyXG5cdFx0XHRmbG9hdCBsaWdodERpc3RhbmNlID0gbGVuZ3RoKCBsVmVjdG9yICk7XHJcblxyXG5cdFx0XHRsaWdodC5jb2xvciA9IHNwb3RMaWdodC5jb2xvciAqIHNwb3RBdHRlbnVhdGlvbjtcclxuXHRcdFx0bGlnaHQuY29sb3IgKj0gZ2V0RGlzdGFuY2VBdHRlbnVhdGlvbiggbGlnaHREaXN0YW5jZSwgc3BvdExpZ2h0LmRpc3RhbmNlLCBzcG90TGlnaHQuZGVjYXkgKTtcclxuXHRcdFx0bGlnaHQudmlzaWJsZSA9ICggbGlnaHQuY29sb3IgIT0gdmVjMyggMC4wICkgKTtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0bGlnaHQuY29sb3IgPSB2ZWMzKCAwLjAgKTtcclxuXHRcdFx0bGlnaHQudmlzaWJsZSA9IGZhbHNlO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuI2VuZGlmXHJcblxyXG5cclxuI2lmIE5VTV9SRUNUX0FSRUFfTElHSFRTID4gMFxyXG5cclxuXHRzdHJ1Y3QgUmVjdEFyZWFMaWdodCB7XHJcblx0XHR2ZWMzIGNvbG9yO1xyXG5cdFx0dmVjMyBwb3NpdGlvbjtcclxuXHRcdHZlYzMgaGFsZldpZHRoO1xyXG5cdFx0dmVjMyBoYWxmSGVpZ2h0O1xyXG5cdH07XHJcblxyXG5cdC8vIFByZS1jb21wdXRlZCB2YWx1ZXMgb2YgTGluZWFyVHJhbnNmb3JtZWRDb3NpbmUgYXBwcm94aW1hdGlvbiBvZiBCUkRGXHJcblx0Ly8gQlJERiBhcHByb3hpbWF0aW9uIFRleHR1cmUgaXMgNjR4NjRcclxuXHR1bmlmb3JtIHNhbXBsZXIyRCBsdGNfMTsgLy8gUkdCQSBGbG9hdFxyXG5cdHVuaWZvcm0gc2FtcGxlcjJEIGx0Y18yOyAvLyBSR0JBIEZsb2F0XHJcblxyXG5cdHVuaWZvcm0gUmVjdEFyZWFMaWdodCByZWN0QXJlYUxpZ2h0c1sgTlVNX1JFQ1RfQVJFQV9MSUdIVFMgXTtcclxuXHJcbiNlbmRpZlxyXG5cclxuXHJcbiNpZiBOVU1fSEVNSV9MSUdIVFMgPiAwXHJcblxyXG5cdHN0cnVjdCBIZW1pc3BoZXJlTGlnaHQge1xyXG5cdFx0dmVjMyBkaXJlY3Rpb247XHJcblx0XHR2ZWMzIHNreUNvbG9yO1xyXG5cdFx0dmVjMyBncm91bmRDb2xvcjtcclxuXHR9O1xyXG5cclxuXHR1bmlmb3JtIEhlbWlzcGhlcmVMaWdodCBoZW1pc3BoZXJlTGlnaHRzWyBOVU1fSEVNSV9MSUdIVFMgXTtcclxuXHJcblx0dmVjMyBnZXRIZW1pc3BoZXJlTGlnaHRJcnJhZGlhbmNlKCBjb25zdCBpbiBIZW1pc3BoZXJlTGlnaHQgaGVtaUxpZ2h0LCBjb25zdCBpbiB2ZWMzIG5vcm1hbCApIHtcclxuXHJcblx0XHRmbG9hdCBkb3ROTCA9IGRvdCggbm9ybWFsLCBoZW1pTGlnaHQuZGlyZWN0aW9uICk7XHJcblx0XHRmbG9hdCBoZW1pRGlmZnVzZVdlaWdodCA9IDAuNSAqIGRvdE5MICsgMC41O1xyXG5cclxuXHRcdHZlYzMgaXJyYWRpYW5jZSA9IG1peCggaGVtaUxpZ2h0Lmdyb3VuZENvbG9yLCBoZW1pTGlnaHQuc2t5Q29sb3IsIGhlbWlEaWZmdXNlV2VpZ2h0ICk7XHJcblxyXG5cdFx0cmV0dXJuIGlycmFkaWFuY2U7XHJcblxyXG5cdH1cclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWZkZWYgVVNFX0VOVk1BUFxyXG5cclxuXHR2ZWMzIGdldElCTElycmFkaWFuY2UoIGNvbnN0IGluIHZlYzMgbm9ybWFsICkge1xyXG5cclxuXHRcdCNpZmRlZiBFTlZNQVBfVFlQRV9DVUJFX1VWXHJcblxyXG5cdFx0XHR2ZWMzIHdvcmxkTm9ybWFsID0gaW52ZXJzZVRyYW5zZm9ybURpcmVjdGlvbiggbm9ybWFsLCB2aWV3TWF0cml4ICk7XHJcblxyXG5cdFx0XHR2ZWM0IGVudk1hcENvbG9yID0gdGV4dHVyZUN1YmVVViggZW52TWFwLCB3b3JsZE5vcm1hbCwgMS4wICk7XHJcblxyXG5cdFx0XHRyZXR1cm4gUEkgKiBlbnZNYXBDb2xvci5yZ2IgKiBlbnZNYXBJbnRlbnNpdHk7XHJcblxyXG5cdFx0I2Vsc2VcclxuXHJcblx0XHRcdHJldHVybiB2ZWMzKCAwLjAgKTtcclxuXHJcblx0XHQjZW5kaWZcclxuXHJcblx0fVxyXG5cclxuXHR2ZWMzIGdldElCTFJhZGlhbmNlKCBjb25zdCBpbiB2ZWMzIHZpZXdEaXIsIGNvbnN0IGluIHZlYzMgbm9ybWFsLCBjb25zdCBpbiBmbG9hdCByb3VnaG5lc3MgKSB7XHJcblxyXG5cdFx0I2lmZGVmIEVOVk1BUF9UWVBFX0NVQkVfVVZcclxuXHJcblx0XHRcdHZlYzMgcmVmbGVjdFZlYyA9IHJlZmxlY3QoIC0gdmlld0Rpciwgbm9ybWFsICk7XHJcblxyXG5cdFx0XHQvLyBNaXhpbmcgdGhlIHJlZmxlY3Rpb24gd2l0aCB0aGUgbm9ybWFsIGlzIG1vcmUgYWNjdXJhdGUgYW5kIGtlZXBzIHJvdWdoIG9iamVjdHMgZnJvbSBnYXRoZXJpbmcgbGlnaHQgZnJvbSBiZWhpbmQgdGhlaXIgdGFuZ2VudCBwbGFuZS5cclxuXHRcdFx0cmVmbGVjdFZlYyA9IG5vcm1hbGl6ZSggbWl4KCByZWZsZWN0VmVjLCBub3JtYWwsIHJvdWdobmVzcyAqIHJvdWdobmVzcykgKTtcclxuXHJcblx0XHRcdHJlZmxlY3RWZWMgPSBpbnZlcnNlVHJhbnNmb3JtRGlyZWN0aW9uKCByZWZsZWN0VmVjLCB2aWV3TWF0cml4ICk7XHJcblxyXG5cdFx0XHR2ZWM0IGVudk1hcENvbG9yID0gdGV4dHVyZUN1YmVVViggZW52TWFwLCByZWZsZWN0VmVjLCByb3VnaG5lc3MgKTtcclxuXHJcblx0XHRcdHJldHVybiBlbnZNYXBDb2xvci5yZ2IgKiBlbnZNYXBJbnRlbnNpdHk7XHJcblxyXG5cdFx0I2Vsc2VcclxuXHJcblx0XHRcdHJldHVybiB2ZWMzKCAwLjAgKTtcclxuXHJcblx0XHQjZW5kaWZcclxuXHJcblx0fVxyXG5cclxuXHQjaWZkZWYgVVNFX0FOSVNPVFJPUFlcclxuXHJcblx0XHR2ZWMzIGdldElCTEFuaXNvdHJvcHlSYWRpYW5jZSggY29uc3QgaW4gdmVjMyB2aWV3RGlyLCBjb25zdCBpbiB2ZWMzIG5vcm1hbCwgY29uc3QgaW4gZmxvYXQgcm91Z2huZXNzLCBjb25zdCBpbiB2ZWMzIGJpdGFuZ2VudCwgY29uc3QgaW4gZmxvYXQgYW5pc290cm9weSApIHtcclxuXHJcblx0XHRcdCNpZmRlZiBFTlZNQVBfVFlQRV9DVUJFX1VWXHJcblxyXG5cdFx0XHQgIC8vIGh0dHBzOi8vZ29vZ2xlLmdpdGh1Yi5pby9maWxhbWVudC9GaWxhbWVudC5tZC5odG1sI2xpZ2h0aW5nL2ltYWdlYmFzZWRsaWdodHMvYW5pc290cm9weVxyXG5cdFx0XHRcdHZlYzMgYmVudE5vcm1hbCA9IGNyb3NzKCBiaXRhbmdlbnQsIHZpZXdEaXIgKTtcclxuXHRcdFx0XHRiZW50Tm9ybWFsID0gbm9ybWFsaXplKCBjcm9zcyggYmVudE5vcm1hbCwgYml0YW5nZW50ICkgKTtcclxuXHRcdFx0XHRiZW50Tm9ybWFsID0gbm9ybWFsaXplKCBtaXgoIGJlbnROb3JtYWwsIG5vcm1hbCwgcG93MiggcG93MiggMS4wIC0gYW5pc290cm9weSAqICggMS4wIC0gcm91Z2huZXNzICkgKSApICkgKTtcclxuXHJcblx0XHRcdFx0cmV0dXJuIGdldElCTFJhZGlhbmNlKCB2aWV3RGlyLCBiZW50Tm9ybWFsLCByb3VnaG5lc3MgKTtcclxuXHJcblx0XHRcdCNlbHNlXHJcblxyXG5cdFx0XHRcdHJldHVybiB2ZWMzKCAwLjAgKTtcclxuXHJcblx0XHRcdCNlbmRpZlxyXG5cclxuXHRcdH1cclxuXHJcblx0I2VuZGlmXHJcblxyXG4jZW5kaWZcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuVG9vbk1hdGVyaWFsIG1hdGVyaWFsO1xyXG5tYXRlcmlhbC5kaWZmdXNlQ29sb3IgPSBkaWZmdXNlQ29sb3IucmdiO1xyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG52YXJ5aW5nIHZlYzMgdlZpZXdQb3NpdGlvbjtcclxuXHJcbnN0cnVjdCBUb29uTWF0ZXJpYWwge1xyXG5cclxuXHR2ZWMzIGRpZmZ1c2VDb2xvcjtcclxuXHJcbn07XHJcblxyXG52b2lkIFJFX0RpcmVjdF9Ub29uKCBjb25zdCBpbiBJbmNpZGVudExpZ2h0IGRpcmVjdExpZ2h0LCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5UG9zaXRpb24sIGNvbnN0IGluIHZlYzMgZ2VvbWV0cnlOb3JtYWwsIGNvbnN0IGluIHZlYzMgZ2VvbWV0cnlWaWV3RGlyLCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5Q2xlYXJjb2F0Tm9ybWFsLCBjb25zdCBpbiBUb29uTWF0ZXJpYWwgbWF0ZXJpYWwsIGlub3V0IFJlZmxlY3RlZExpZ2h0IHJlZmxlY3RlZExpZ2h0ICkge1xyXG5cclxuXHR2ZWMzIGlycmFkaWFuY2UgPSBnZXRHcmFkaWVudElycmFkaWFuY2UoIGdlb21ldHJ5Tm9ybWFsLCBkaXJlY3RMaWdodC5kaXJlY3Rpb24gKSAqIGRpcmVjdExpZ2h0LmNvbG9yO1xyXG5cclxuXHRyZWZsZWN0ZWRMaWdodC5kaXJlY3REaWZmdXNlICs9IGlycmFkaWFuY2UgKiBCUkRGX0xhbWJlcnQoIG1hdGVyaWFsLmRpZmZ1c2VDb2xvciApO1xyXG5cclxufVxyXG5cclxudm9pZCBSRV9JbmRpcmVjdERpZmZ1c2VfVG9vbiggY29uc3QgaW4gdmVjMyBpcnJhZGlhbmNlLCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5UG9zaXRpb24sIGNvbnN0IGluIHZlYzMgZ2VvbWV0cnlOb3JtYWwsIGNvbnN0IGluIHZlYzMgZ2VvbWV0cnlWaWV3RGlyLCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5Q2xlYXJjb2F0Tm9ybWFsLCBjb25zdCBpbiBUb29uTWF0ZXJpYWwgbWF0ZXJpYWwsIGlub3V0IFJlZmxlY3RlZExpZ2h0IHJlZmxlY3RlZExpZ2h0ICkge1xyXG5cclxuXHRyZWZsZWN0ZWRMaWdodC5pbmRpcmVjdERpZmZ1c2UgKz0gaXJyYWRpYW5jZSAqIEJSREZfTGFtYmVydCggbWF0ZXJpYWwuZGlmZnVzZUNvbG9yICk7XHJcblxyXG59XHJcblxyXG4jZGVmaW5lIFJFX0RpcmVjdFx0XHRcdFx0UkVfRGlyZWN0X1Rvb25cclxuI2RlZmluZSBSRV9JbmRpcmVjdERpZmZ1c2VcdFx0UkVfSW5kaXJlY3REaWZmdXNlX1Rvb25cclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuQmxpbm5QaG9uZ01hdGVyaWFsIG1hdGVyaWFsO1xyXG5tYXRlcmlhbC5kaWZmdXNlQ29sb3IgPSBkaWZmdXNlQ29sb3IucmdiO1xyXG5tYXRlcmlhbC5zcGVjdWxhckNvbG9yID0gc3BlY3VsYXI7XHJcbm1hdGVyaWFsLnNwZWN1bGFyU2hpbmluZXNzID0gc2hpbmluZXNzO1xyXG5tYXRlcmlhbC5zcGVjdWxhclN0cmVuZ3RoID0gc3BlY3VsYXJTdHJlbmd0aDtcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxudmFyeWluZyB2ZWMzIHZWaWV3UG9zaXRpb247XHJcblxyXG5zdHJ1Y3QgQmxpbm5QaG9uZ01hdGVyaWFsIHtcclxuXHJcblx0dmVjMyBkaWZmdXNlQ29sb3I7XHJcblx0dmVjMyBzcGVjdWxhckNvbG9yO1xyXG5cdGZsb2F0IHNwZWN1bGFyU2hpbmluZXNzO1xyXG5cdGZsb2F0IHNwZWN1bGFyU3RyZW5ndGg7XHJcblxyXG59O1xyXG5cclxudm9pZCBSRV9EaXJlY3RfQmxpbm5QaG9uZyggY29uc3QgaW4gSW5jaWRlbnRMaWdodCBkaXJlY3RMaWdodCwgY29uc3QgaW4gdmVjMyBnZW9tZXRyeVBvc2l0aW9uLCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5Tm9ybWFsLCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5Vmlld0RpciwgY29uc3QgaW4gdmVjMyBnZW9tZXRyeUNsZWFyY29hdE5vcm1hbCwgY29uc3QgaW4gQmxpbm5QaG9uZ01hdGVyaWFsIG1hdGVyaWFsLCBpbm91dCBSZWZsZWN0ZWRMaWdodCByZWZsZWN0ZWRMaWdodCApIHtcclxuXHJcblx0ZmxvYXQgZG90TkwgPSBzYXR1cmF0ZSggZG90KCBnZW9tZXRyeU5vcm1hbCwgZGlyZWN0TGlnaHQuZGlyZWN0aW9uICkgKTtcclxuXHR2ZWMzIGlycmFkaWFuY2UgPSBkb3ROTCAqIGRpcmVjdExpZ2h0LmNvbG9yO1xyXG5cclxuXHRyZWZsZWN0ZWRMaWdodC5kaXJlY3REaWZmdXNlICs9IGlycmFkaWFuY2UgKiBCUkRGX0xhbWJlcnQoIG1hdGVyaWFsLmRpZmZ1c2VDb2xvciApO1xyXG5cclxuXHRyZWZsZWN0ZWRMaWdodC5kaXJlY3RTcGVjdWxhciArPSBpcnJhZGlhbmNlICogQlJERl9CbGlublBob25nKCBkaXJlY3RMaWdodC5kaXJlY3Rpb24sIGdlb21ldHJ5Vmlld0RpciwgZ2VvbWV0cnlOb3JtYWwsIG1hdGVyaWFsLnNwZWN1bGFyQ29sb3IsIG1hdGVyaWFsLnNwZWN1bGFyU2hpbmluZXNzICkgKiBtYXRlcmlhbC5zcGVjdWxhclN0cmVuZ3RoO1xyXG5cclxufVxyXG5cclxudm9pZCBSRV9JbmRpcmVjdERpZmZ1c2VfQmxpbm5QaG9uZyggY29uc3QgaW4gdmVjMyBpcnJhZGlhbmNlLCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5UG9zaXRpb24sIGNvbnN0IGluIHZlYzMgZ2VvbWV0cnlOb3JtYWwsIGNvbnN0IGluIHZlYzMgZ2VvbWV0cnlWaWV3RGlyLCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5Q2xlYXJjb2F0Tm9ybWFsLCBjb25zdCBpbiBCbGlublBob25nTWF0ZXJpYWwgbWF0ZXJpYWwsIGlub3V0IFJlZmxlY3RlZExpZ2h0IHJlZmxlY3RlZExpZ2h0ICkge1xyXG5cclxuXHRyZWZsZWN0ZWRMaWdodC5pbmRpcmVjdERpZmZ1c2UgKz0gaXJyYWRpYW5jZSAqIEJSREZfTGFtYmVydCggbWF0ZXJpYWwuZGlmZnVzZUNvbG9yICk7XHJcblxyXG59XHJcblxyXG4jZGVmaW5lIFJFX0RpcmVjdFx0XHRcdFx0UkVfRGlyZWN0X0JsaW5uUGhvbmdcclxuI2RlZmluZSBSRV9JbmRpcmVjdERpZmZ1c2VcdFx0UkVfSW5kaXJlY3REaWZmdXNlX0JsaW5uUGhvbmdcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuUGh5c2ljYWxNYXRlcmlhbCBtYXRlcmlhbDtcclxubWF0ZXJpYWwuZGlmZnVzZUNvbG9yID0gZGlmZnVzZUNvbG9yLnJnYiAqICggMS4wIC0gbWV0YWxuZXNzRmFjdG9yICk7XHJcblxyXG52ZWMzIGR4eSA9IG1heCggYWJzKCBkRmR4KCBub25QZXJ0dXJiZWROb3JtYWwgKSApLCBhYnMoIGRGZHkoIG5vblBlcnR1cmJlZE5vcm1hbCApICkgKTtcclxuZmxvYXQgZ2VvbWV0cnlSb3VnaG5lc3MgPSBtYXgoIG1heCggZHh5LngsIGR4eS55ICksIGR4eS56ICk7XHJcblxyXG5tYXRlcmlhbC5yb3VnaG5lc3MgPSBtYXgoIHJvdWdobmVzc0ZhY3RvciwgMC4wNTI1ICk7Ly8gMC4wNTI1IGNvcnJlc3BvbmRzIHRvIHRoZSBiYXNlIG1pcCBvZiBhIDI1NiBjdWJlbWFwLlxyXG5tYXRlcmlhbC5yb3VnaG5lc3MgKz0gZ2VvbWV0cnlSb3VnaG5lc3M7XHJcbm1hdGVyaWFsLnJvdWdobmVzcyA9IG1pbiggbWF0ZXJpYWwucm91Z2huZXNzLCAxLjAgKTtcclxuXHJcbiNpZmRlZiBJT1JcclxuXHJcblx0bWF0ZXJpYWwuaW9yID0gaW9yO1xyXG5cclxuXHQjaWZkZWYgVVNFX1NQRUNVTEFSXHJcblxyXG5cdFx0ZmxvYXQgc3BlY3VsYXJJbnRlbnNpdHlGYWN0b3IgPSBzcGVjdWxhckludGVuc2l0eTtcclxuXHRcdHZlYzMgc3BlY3VsYXJDb2xvckZhY3RvciA9IHNwZWN1bGFyQ29sb3I7XHJcblxyXG5cdFx0I2lmZGVmIFVTRV9TUEVDVUxBUl9DT0xPUk1BUFxyXG5cclxuXHRcdFx0c3BlY3VsYXJDb2xvckZhY3RvciAqPSB0ZXh0dXJlMkQoIHNwZWN1bGFyQ29sb3JNYXAsIHZTcGVjdWxhckNvbG9yTWFwVXYgKS5yZ2I7XHJcblxyXG5cdFx0I2VuZGlmXHJcblxyXG5cdFx0I2lmZGVmIFVTRV9TUEVDVUxBUl9JTlRFTlNJVFlNQVBcclxuXHJcblx0XHRcdHNwZWN1bGFySW50ZW5zaXR5RmFjdG9yICo9IHRleHR1cmUyRCggc3BlY3VsYXJJbnRlbnNpdHlNYXAsIHZTcGVjdWxhckludGVuc2l0eU1hcFV2ICkuYTtcclxuXHJcblx0XHQjZW5kaWZcclxuXHJcblx0XHRtYXRlcmlhbC5zcGVjdWxhckY5MCA9IG1peCggc3BlY3VsYXJJbnRlbnNpdHlGYWN0b3IsIDEuMCwgbWV0YWxuZXNzRmFjdG9yICk7XHJcblxyXG5cdCNlbHNlXHJcblxyXG5cdFx0ZmxvYXQgc3BlY3VsYXJJbnRlbnNpdHlGYWN0b3IgPSAxLjA7XHJcblx0XHR2ZWMzIHNwZWN1bGFyQ29sb3JGYWN0b3IgPSB2ZWMzKCAxLjAgKTtcclxuXHRcdG1hdGVyaWFsLnNwZWN1bGFyRjkwID0gMS4wO1xyXG5cclxuXHQjZW5kaWZcclxuXHJcblx0bWF0ZXJpYWwuc3BlY3VsYXJDb2xvciA9IG1peCggbWluKCBwb3cyKCAoIG1hdGVyaWFsLmlvciAtIDEuMCApIC8gKCBtYXRlcmlhbC5pb3IgKyAxLjAgKSApICogc3BlY3VsYXJDb2xvckZhY3RvciwgdmVjMyggMS4wICkgKSAqIHNwZWN1bGFySW50ZW5zaXR5RmFjdG9yLCBkaWZmdXNlQ29sb3IucmdiLCBtZXRhbG5lc3NGYWN0b3IgKTtcclxuXHJcbiNlbHNlXHJcblxyXG5cdG1hdGVyaWFsLnNwZWN1bGFyQ29sb3IgPSBtaXgoIHZlYzMoIDAuMDQgKSwgZGlmZnVzZUNvbG9yLnJnYiwgbWV0YWxuZXNzRmFjdG9yICk7XHJcblx0bWF0ZXJpYWwuc3BlY3VsYXJGOTAgPSAxLjA7XHJcblxyXG4jZW5kaWZcclxuXHJcbiNpZmRlZiBVU0VfQ0xFQVJDT0FUXHJcblxyXG5cdG1hdGVyaWFsLmNsZWFyY29hdCA9IGNsZWFyY29hdDtcclxuXHRtYXRlcmlhbC5jbGVhcmNvYXRSb3VnaG5lc3MgPSBjbGVhcmNvYXRSb3VnaG5lc3M7XHJcblx0bWF0ZXJpYWwuY2xlYXJjb2F0RjAgPSB2ZWMzKCAwLjA0ICk7XHJcblx0bWF0ZXJpYWwuY2xlYXJjb2F0RjkwID0gMS4wO1xyXG5cclxuXHQjaWZkZWYgVVNFX0NMRUFSQ09BVE1BUFxyXG5cclxuXHRcdG1hdGVyaWFsLmNsZWFyY29hdCAqPSB0ZXh0dXJlMkQoIGNsZWFyY29hdE1hcCwgdkNsZWFyY29hdE1hcFV2ICkueDtcclxuXHJcblx0I2VuZGlmXHJcblxyXG5cdCNpZmRlZiBVU0VfQ0xFQVJDT0FUX1JPVUdITkVTU01BUFxyXG5cclxuXHRcdG1hdGVyaWFsLmNsZWFyY29hdFJvdWdobmVzcyAqPSB0ZXh0dXJlMkQoIGNsZWFyY29hdFJvdWdobmVzc01hcCwgdkNsZWFyY29hdFJvdWdobmVzc01hcFV2ICkueTtcclxuXHJcblx0I2VuZGlmXHJcblxyXG5cdG1hdGVyaWFsLmNsZWFyY29hdCA9IHNhdHVyYXRlKCBtYXRlcmlhbC5jbGVhcmNvYXQgKTsgLy8gQnVybGV5IGNsZWFyY29hdCBtb2RlbFxyXG5cdG1hdGVyaWFsLmNsZWFyY29hdFJvdWdobmVzcyA9IG1heCggbWF0ZXJpYWwuY2xlYXJjb2F0Um91Z2huZXNzLCAwLjA1MjUgKTtcclxuXHRtYXRlcmlhbC5jbGVhcmNvYXRSb3VnaG5lc3MgKz0gZ2VvbWV0cnlSb3VnaG5lc3M7XHJcblx0bWF0ZXJpYWwuY2xlYXJjb2F0Um91Z2huZXNzID0gbWluKCBtYXRlcmlhbC5jbGVhcmNvYXRSb3VnaG5lc3MsIDEuMCApO1xyXG5cclxuI2VuZGlmXHJcblxyXG4jaWZkZWYgVVNFX0lSSURFU0NFTkNFXHJcblxyXG5cdG1hdGVyaWFsLmlyaWRlc2NlbmNlID0gaXJpZGVzY2VuY2U7XHJcblx0bWF0ZXJpYWwuaXJpZGVzY2VuY2VJT1IgPSBpcmlkZXNjZW5jZUlPUjtcclxuXHJcblx0I2lmZGVmIFVTRV9JUklERVNDRU5DRU1BUFxyXG5cclxuXHRcdG1hdGVyaWFsLmlyaWRlc2NlbmNlICo9IHRleHR1cmUyRCggaXJpZGVzY2VuY2VNYXAsIHZJcmlkZXNjZW5jZU1hcFV2ICkucjtcclxuXHJcblx0I2VuZGlmXHJcblxyXG5cdCNpZmRlZiBVU0VfSVJJREVTQ0VOQ0VfVEhJQ0tORVNTTUFQXHJcblxyXG5cdFx0bWF0ZXJpYWwuaXJpZGVzY2VuY2VUaGlja25lc3MgPSAoaXJpZGVzY2VuY2VUaGlja25lc3NNYXhpbXVtIC0gaXJpZGVzY2VuY2VUaGlja25lc3NNaW5pbXVtKSAqIHRleHR1cmUyRCggaXJpZGVzY2VuY2VUaGlja25lc3NNYXAsIHZJcmlkZXNjZW5jZVRoaWNrbmVzc01hcFV2ICkuZyArIGlyaWRlc2NlbmNlVGhpY2tuZXNzTWluaW11bTtcclxuXHJcblx0I2Vsc2VcclxuXHJcblx0XHRtYXRlcmlhbC5pcmlkZXNjZW5jZVRoaWNrbmVzcyA9IGlyaWRlc2NlbmNlVGhpY2tuZXNzTWF4aW11bTtcclxuXHJcblx0I2VuZGlmXHJcblxyXG4jZW5kaWZcclxuXHJcbiNpZmRlZiBVU0VfU0hFRU5cclxuXHJcblx0bWF0ZXJpYWwuc2hlZW5Db2xvciA9IHNoZWVuQ29sb3I7XHJcblxyXG5cdCNpZmRlZiBVU0VfU0hFRU5fQ09MT1JNQVBcclxuXHJcblx0XHRtYXRlcmlhbC5zaGVlbkNvbG9yICo9IHRleHR1cmUyRCggc2hlZW5Db2xvck1hcCwgdlNoZWVuQ29sb3JNYXBVdiApLnJnYjtcclxuXHJcblx0I2VuZGlmXHJcblxyXG5cdG1hdGVyaWFsLnNoZWVuUm91Z2huZXNzID0gY2xhbXAoIHNoZWVuUm91Z2huZXNzLCAwLjA3LCAxLjAgKTtcclxuXHJcblx0I2lmZGVmIFVTRV9TSEVFTl9ST1VHSE5FU1NNQVBcclxuXHJcblx0XHRtYXRlcmlhbC5zaGVlblJvdWdobmVzcyAqPSB0ZXh0dXJlMkQoIHNoZWVuUm91Z2huZXNzTWFwLCB2U2hlZW5Sb3VnaG5lc3NNYXBVdiApLmE7XHJcblxyXG5cdCNlbmRpZlxyXG5cclxuI2VuZGlmXHJcblxyXG4jaWZkZWYgVVNFX0FOSVNPVFJPUFlcclxuXHJcblx0I2lmZGVmIFVTRV9BTklTT1RST1BZTUFQXHJcblxyXG5cdFx0bWF0MiBhbmlzb3Ryb3B5TWF0ID0gbWF0MiggYW5pc290cm9weVZlY3Rvci54LCBhbmlzb3Ryb3B5VmVjdG9yLnksIC0gYW5pc290cm9weVZlY3Rvci55LCBhbmlzb3Ryb3B5VmVjdG9yLnggKTtcclxuXHRcdHZlYzMgYW5pc290cm9weVBvbGFyID0gdGV4dHVyZTJEKCBhbmlzb3Ryb3B5TWFwLCB2QW5pc290cm9weU1hcFV2ICkucmdiO1xyXG5cdFx0dmVjMiBhbmlzb3Ryb3B5ViA9IGFuaXNvdHJvcHlNYXQgKiBub3JtYWxpemUoIDIuMCAqIGFuaXNvdHJvcHlQb2xhci5yZyAtIHZlYzIoIDEuMCApICkgKiBhbmlzb3Ryb3B5UG9sYXIuYjtcclxuXHJcblx0I2Vsc2VcclxuXHJcblx0XHR2ZWMyIGFuaXNvdHJvcHlWID0gYW5pc290cm9weVZlY3RvcjtcclxuXHJcblx0I2VuZGlmXHJcblxyXG5cdG1hdGVyaWFsLmFuaXNvdHJvcHkgPSBsZW5ndGgoIGFuaXNvdHJvcHlWICk7XHJcblxyXG5cdGlmKCBtYXRlcmlhbC5hbmlzb3Ryb3B5ID09IDAuMCApIHtcclxuXHRcdGFuaXNvdHJvcHlWID0gdmVjMiggMS4wLCAwLjAgKTtcclxuXHR9IGVsc2Uge1xyXG5cdFx0YW5pc290cm9weVYgLz0gbWF0ZXJpYWwuYW5pc290cm9weTtcclxuXHRcdG1hdGVyaWFsLmFuaXNvdHJvcHkgPSBzYXR1cmF0ZSggbWF0ZXJpYWwuYW5pc290cm9weSApO1xyXG5cdH1cclxuXHJcblx0Ly8gUm91Z2huZXNzIGFsb25nIHRoZSBhbmlzb3Ryb3B5IGJpdGFuZ2VudCBpcyB0aGUgbWF0ZXJpYWwgcm91Z2huZXNzLCB3aGlsZSB0aGUgdGFuZ2VudCByb3VnaG5lc3MgaW5jcmVhc2VzIHdpdGggYW5pc290cm9weS5cclxuXHRtYXRlcmlhbC5hbHBoYVQgPSBtaXgoIHBvdzIoIG1hdGVyaWFsLnJvdWdobmVzcyApLCAxLjAsIHBvdzIoIG1hdGVyaWFsLmFuaXNvdHJvcHkgKSApO1xyXG5cclxuXHRtYXRlcmlhbC5hbmlzb3Ryb3B5VCA9IHRiblsgMCBdICogYW5pc290cm9weVYueCArIHRiblsgMSBdICogYW5pc290cm9weVYueTtcclxuXHRtYXRlcmlhbC5hbmlzb3Ryb3B5QiA9IHRiblsgMSBdICogYW5pc290cm9weVYueCAtIHRiblsgMCBdICogYW5pc290cm9weVYueTtcclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG5cclxuc3RydWN0IFBoeXNpY2FsTWF0ZXJpYWwge1xyXG5cclxuXHR2ZWMzIGRpZmZ1c2VDb2xvcjtcclxuXHRmbG9hdCByb3VnaG5lc3M7XHJcblx0dmVjMyBzcGVjdWxhckNvbG9yO1xyXG5cdGZsb2F0IHNwZWN1bGFyRjkwO1xyXG5cclxuXHQjaWZkZWYgVVNFX0NMRUFSQ09BVFxyXG5cdFx0ZmxvYXQgY2xlYXJjb2F0O1xyXG5cdFx0ZmxvYXQgY2xlYXJjb2F0Um91Z2huZXNzO1xyXG5cdFx0dmVjMyBjbGVhcmNvYXRGMDtcclxuXHRcdGZsb2F0IGNsZWFyY29hdEY5MDtcclxuXHQjZW5kaWZcclxuXHJcblx0I2lmZGVmIFVTRV9JUklERVNDRU5DRVxyXG5cdFx0ZmxvYXQgaXJpZGVzY2VuY2U7XHJcblx0XHRmbG9hdCBpcmlkZXNjZW5jZUlPUjtcclxuXHRcdGZsb2F0IGlyaWRlc2NlbmNlVGhpY2tuZXNzO1xyXG5cdFx0dmVjMyBpcmlkZXNjZW5jZUZyZXNuZWw7XHJcblx0XHR2ZWMzIGlyaWRlc2NlbmNlRjA7XHJcblx0I2VuZGlmXHJcblxyXG5cdCNpZmRlZiBVU0VfU0hFRU5cclxuXHRcdHZlYzMgc2hlZW5Db2xvcjtcclxuXHRcdGZsb2F0IHNoZWVuUm91Z2huZXNzO1xyXG5cdCNlbmRpZlxyXG5cclxuXHQjaWZkZWYgSU9SXHJcblx0XHRmbG9hdCBpb3I7XHJcblx0I2VuZGlmXHJcblxyXG5cdCNpZmRlZiBVU0VfVFJBTlNNSVNTSU9OXHJcblx0XHRmbG9hdCB0cmFuc21pc3Npb247XHJcblx0XHRmbG9hdCB0cmFuc21pc3Npb25BbHBoYTtcclxuXHRcdGZsb2F0IHRoaWNrbmVzcztcclxuXHRcdGZsb2F0IGF0dGVudWF0aW9uRGlzdGFuY2U7XHJcblx0XHR2ZWMzIGF0dGVudWF0aW9uQ29sb3I7XHJcblx0I2VuZGlmXHJcblxyXG5cdCNpZmRlZiBVU0VfQU5JU09UUk9QWVxyXG5cdFx0ZmxvYXQgYW5pc290cm9weTtcclxuXHRcdGZsb2F0IGFscGhhVDtcclxuXHRcdHZlYzMgYW5pc290cm9weVQ7XHJcblx0XHR2ZWMzIGFuaXNvdHJvcHlCO1xyXG5cdCNlbmRpZlxyXG5cclxufTtcclxuXHJcbi8vIHRlbXBvcmFyeVxyXG52ZWMzIGNsZWFyY29hdFNwZWN1bGFyRGlyZWN0ID0gdmVjMyggMC4wICk7XHJcbnZlYzMgY2xlYXJjb2F0U3BlY3VsYXJJbmRpcmVjdCA9IHZlYzMoIDAuMCApO1xyXG52ZWMzIHNoZWVuU3BlY3VsYXJEaXJlY3QgPSB2ZWMzKCAwLjAgKTtcclxudmVjMyBzaGVlblNwZWN1bGFySW5kaXJlY3QgPSB2ZWMzKDAuMCApO1xyXG5cclxudmVjMyBTY2hsaWNrX3RvX0YwKCBjb25zdCBpbiB2ZWMzIGYsIGNvbnN0IGluIGZsb2F0IGY5MCwgY29uc3QgaW4gZmxvYXQgZG90VkggKSB7XHJcbiAgICBmbG9hdCB4ID0gY2xhbXAoIDEuMCAtIGRvdFZILCAwLjAsIDEuMCApO1xyXG4gICAgZmxvYXQgeDIgPSB4ICogeDtcclxuICAgIGZsb2F0IHg1ID0gY2xhbXAoIHggKiB4MiAqIHgyLCAwLjAsIDAuOTk5OSApO1xyXG5cclxuICAgIHJldHVybiAoIGYgLSB2ZWMzKCBmOTAgKSAqIHg1ICkgLyAoIDEuMCAtIHg1ICk7XHJcbn1cclxuXHJcbi8vIE1vdmluZyBGcm9zdGJpdGUgdG8gUGh5c2ljYWxseSBCYXNlZCBSZW5kZXJpbmcgMy4wIC0gcGFnZSAxMiwgbGlzdGluZyAyXHJcbi8vIGh0dHBzOi8vc2VibGFnYXJkZS5maWxlcy53b3JkcHJlc3MuY29tLzIwMTUvMDcvY291cnNlX25vdGVzX21vdmluZ19mcm9zdGJpdGVfdG9fcGJyX3YzMi5wZGZcclxuZmxvYXQgVl9HR1hfU21pdGhDb3JyZWxhdGVkKCBjb25zdCBpbiBmbG9hdCBhbHBoYSwgY29uc3QgaW4gZmxvYXQgZG90TkwsIGNvbnN0IGluIGZsb2F0IGRvdE5WICkge1xyXG5cclxuXHRmbG9hdCBhMiA9IHBvdzIoIGFscGhhICk7XHJcblxyXG5cdGZsb2F0IGd2ID0gZG90TkwgKiBzcXJ0KCBhMiArICggMS4wIC0gYTIgKSAqIHBvdzIoIGRvdE5WICkgKTtcclxuXHRmbG9hdCBnbCA9IGRvdE5WICogc3FydCggYTIgKyAoIDEuMCAtIGEyICkgKiBwb3cyKCBkb3ROTCApICk7XHJcblxyXG5cdHJldHVybiAwLjUgLyBtYXgoIGd2ICsgZ2wsIEVQU0lMT04gKTtcclxuXHJcbn1cclxuXHJcbi8vIE1pY3JvZmFjZXQgTW9kZWxzIGZvciBSZWZyYWN0aW9uIHRocm91Z2ggUm91Z2ggU3VyZmFjZXMgLSBlcXVhdGlvbiAoMzMpXHJcbi8vIGh0dHA6Ly9ncmFwaGljcmFudHMuYmxvZ3Nwb3QuY29tLzIwMTMvMDgvc3BlY3VsYXItYnJkZi1yZWZlcmVuY2UuaHRtbFxyXG4vLyBhbHBoYSBpcyBcInJvdWdobmVzcyBzcXVhcmVkXCIgaW4gRGlzbmV54oCZcyByZXBhcmFtZXRlcml6YXRpb25cclxuZmxvYXQgRF9HR1goIGNvbnN0IGluIGZsb2F0IGFscGhhLCBjb25zdCBpbiBmbG9hdCBkb3ROSCApIHtcclxuXHJcblx0ZmxvYXQgYTIgPSBwb3cyKCBhbHBoYSApO1xyXG5cclxuXHRmbG9hdCBkZW5vbSA9IHBvdzIoIGRvdE5IICkgKiAoIGEyIC0gMS4wICkgKyAxLjA7IC8vIGF2b2lkIGFscGhhID0gMCB3aXRoIGRvdE5IID0gMVxyXG5cclxuXHRyZXR1cm4gUkVDSVBST0NBTF9QSSAqIGEyIC8gcG93MiggZGVub20gKTtcclxuXHJcbn1cclxuXHJcbi8vIGh0dHBzOi8vZ29vZ2xlLmdpdGh1Yi5pby9maWxhbWVudC9GaWxhbWVudC5tZC5odG1sI21hdGVyaWFsc3lzdGVtL2FuaXNvdHJvcGljbW9kZWwvYW5pc290cm9waWNzcGVjdWxhcmJyZGZcclxuI2lmZGVmIFVTRV9BTklTT1RST1BZXHJcblxyXG5cdGZsb2F0IFZfR0dYX1NtaXRoQ29ycmVsYXRlZF9Bbmlzb3Ryb3BpYyggY29uc3QgaW4gZmxvYXQgYWxwaGFULCBjb25zdCBpbiBmbG9hdCBhbHBoYUIsIGNvbnN0IGluIGZsb2F0IGRvdFRWLCBjb25zdCBpbiBmbG9hdCBkb3RCViwgY29uc3QgaW4gZmxvYXQgZG90VEwsIGNvbnN0IGluIGZsb2F0IGRvdEJMLCBjb25zdCBpbiBmbG9hdCBkb3ROViwgY29uc3QgaW4gZmxvYXQgZG90TkwgKSB7XHJcblxyXG5cdFx0ZmxvYXQgZ3YgPSBkb3ROTCAqIGxlbmd0aCggdmVjMyggYWxwaGFUICogZG90VFYsIGFscGhhQiAqIGRvdEJWLCBkb3ROViApICk7XHJcblx0XHRmbG9hdCBnbCA9IGRvdE5WICogbGVuZ3RoKCB2ZWMzKCBhbHBoYVQgKiBkb3RUTCwgYWxwaGFCICogZG90QkwsIGRvdE5MICkgKTtcclxuXHRcdGZsb2F0IHYgPSAwLjUgLyAoIGd2ICsgZ2wgKTtcclxuXHJcblx0XHRyZXR1cm4gc2F0dXJhdGUodik7XHJcblxyXG5cdH1cclxuXHJcblx0ZmxvYXQgRF9HR1hfQW5pc290cm9waWMoIGNvbnN0IGluIGZsb2F0IGFscGhhVCwgY29uc3QgaW4gZmxvYXQgYWxwaGFCLCBjb25zdCBpbiBmbG9hdCBkb3ROSCwgY29uc3QgaW4gZmxvYXQgZG90VEgsIGNvbnN0IGluIGZsb2F0IGRvdEJIICkge1xyXG5cclxuXHRcdGZsb2F0IGEyID0gYWxwaGFUICogYWxwaGFCO1xyXG5cdFx0aGlnaHAgdmVjMyB2ID0gdmVjMyggYWxwaGFCICogZG90VEgsIGFscGhhVCAqIGRvdEJILCBhMiAqIGRvdE5IICk7XHJcblx0XHRoaWdocCBmbG9hdCB2MiA9IGRvdCggdiwgdiApO1xyXG5cdFx0ZmxvYXQgdzIgPSBhMiAvIHYyO1xyXG5cclxuXHRcdHJldHVybiBSRUNJUFJPQ0FMX1BJICogYTIgKiBwb3cyICggdzIgKTtcclxuXHJcblx0fVxyXG5cclxuI2VuZGlmXHJcblxyXG4jaWZkZWYgVVNFX0NMRUFSQ09BVFxyXG5cclxuXHQvLyBHR1ggRGlzdHJpYnV0aW9uLCBTY2hsaWNrIEZyZXNuZWwsIEdHWF9TbWl0aENvcnJlbGF0ZWQgVmlzaWJpbGl0eVxyXG5cdHZlYzMgQlJERl9HR1hfQ2xlYXJjb2F0KCBjb25zdCBpbiB2ZWMzIGxpZ2h0RGlyLCBjb25zdCBpbiB2ZWMzIHZpZXdEaXIsIGNvbnN0IGluIHZlYzMgbm9ybWFsLCBjb25zdCBpbiBQaHlzaWNhbE1hdGVyaWFsIG1hdGVyaWFsKSB7XHJcblxyXG5cdFx0dmVjMyBmMCA9IG1hdGVyaWFsLmNsZWFyY29hdEYwO1xyXG5cdFx0ZmxvYXQgZjkwID0gbWF0ZXJpYWwuY2xlYXJjb2F0RjkwO1xyXG5cdFx0ZmxvYXQgcm91Z2huZXNzID0gbWF0ZXJpYWwuY2xlYXJjb2F0Um91Z2huZXNzO1xyXG5cclxuXHRcdGZsb2F0IGFscGhhID0gcG93Miggcm91Z2huZXNzICk7IC8vIFVFNCdzIHJvdWdobmVzc1xyXG5cclxuXHRcdHZlYzMgaGFsZkRpciA9IG5vcm1hbGl6ZSggbGlnaHREaXIgKyB2aWV3RGlyICk7XHJcblxyXG5cdFx0ZmxvYXQgZG90TkwgPSBzYXR1cmF0ZSggZG90KCBub3JtYWwsIGxpZ2h0RGlyICkgKTtcclxuXHRcdGZsb2F0IGRvdE5WID0gc2F0dXJhdGUoIGRvdCggbm9ybWFsLCB2aWV3RGlyICkgKTtcclxuXHRcdGZsb2F0IGRvdE5IID0gc2F0dXJhdGUoIGRvdCggbm9ybWFsLCBoYWxmRGlyICkgKTtcclxuXHRcdGZsb2F0IGRvdFZIID0gc2F0dXJhdGUoIGRvdCggdmlld0RpciwgaGFsZkRpciApICk7XHJcblxyXG5cdFx0dmVjMyBGID0gRl9TY2hsaWNrKCBmMCwgZjkwLCBkb3RWSCApO1xyXG5cclxuXHRcdGZsb2F0IFYgPSBWX0dHWF9TbWl0aENvcnJlbGF0ZWQoIGFscGhhLCBkb3ROTCwgZG90TlYgKTtcclxuXHJcblx0XHRmbG9hdCBEID0gRF9HR1goIGFscGhhLCBkb3ROSCApO1xyXG5cclxuXHRcdHJldHVybiBGICogKCBWICogRCApO1xyXG5cclxuXHR9XHJcblxyXG4jZW5kaWZcclxuXHJcbnZlYzMgQlJERl9HR1goIGNvbnN0IGluIHZlYzMgbGlnaHREaXIsIGNvbnN0IGluIHZlYzMgdmlld0RpciwgY29uc3QgaW4gdmVjMyBub3JtYWwsIGNvbnN0IGluIFBoeXNpY2FsTWF0ZXJpYWwgbWF0ZXJpYWwgKSB7XHJcblxyXG5cdHZlYzMgZjAgPSBtYXRlcmlhbC5zcGVjdWxhckNvbG9yO1xyXG5cdGZsb2F0IGY5MCA9IG1hdGVyaWFsLnNwZWN1bGFyRjkwO1xyXG5cdGZsb2F0IHJvdWdobmVzcyA9IG1hdGVyaWFsLnJvdWdobmVzcztcclxuXHJcblx0ZmxvYXQgYWxwaGEgPSBwb3cyKCByb3VnaG5lc3MgKTsgLy8gVUU0J3Mgcm91Z2huZXNzXHJcblxyXG5cdHZlYzMgaGFsZkRpciA9IG5vcm1hbGl6ZSggbGlnaHREaXIgKyB2aWV3RGlyICk7XHJcblxyXG5cdGZsb2F0IGRvdE5MID0gc2F0dXJhdGUoIGRvdCggbm9ybWFsLCBsaWdodERpciApICk7XHJcblx0ZmxvYXQgZG90TlYgPSBzYXR1cmF0ZSggZG90KCBub3JtYWwsIHZpZXdEaXIgKSApO1xyXG5cdGZsb2F0IGRvdE5IID0gc2F0dXJhdGUoIGRvdCggbm9ybWFsLCBoYWxmRGlyICkgKTtcclxuXHRmbG9hdCBkb3RWSCA9IHNhdHVyYXRlKCBkb3QoIHZpZXdEaXIsIGhhbGZEaXIgKSApO1xyXG5cclxuXHR2ZWMzIEYgPSBGX1NjaGxpY2soIGYwLCBmOTAsIGRvdFZIICk7XHJcblxyXG5cdCNpZmRlZiBVU0VfSVJJREVTQ0VOQ0VcclxuXHJcblx0XHRGID0gbWl4KCBGLCBtYXRlcmlhbC5pcmlkZXNjZW5jZUZyZXNuZWwsIG1hdGVyaWFsLmlyaWRlc2NlbmNlICk7XHJcblxyXG5cdCNlbmRpZlxyXG5cclxuXHQjaWZkZWYgVVNFX0FOSVNPVFJPUFlcclxuXHJcblx0XHRmbG9hdCBkb3RUTCA9IGRvdCggbWF0ZXJpYWwuYW5pc290cm9weVQsIGxpZ2h0RGlyICk7XHJcblx0XHRmbG9hdCBkb3RUViA9IGRvdCggbWF0ZXJpYWwuYW5pc290cm9weVQsIHZpZXdEaXIgKTtcclxuXHRcdGZsb2F0IGRvdFRIID0gZG90KCBtYXRlcmlhbC5hbmlzb3Ryb3B5VCwgaGFsZkRpciApO1xyXG5cdFx0ZmxvYXQgZG90QkwgPSBkb3QoIG1hdGVyaWFsLmFuaXNvdHJvcHlCLCBsaWdodERpciApO1xyXG5cdFx0ZmxvYXQgZG90QlYgPSBkb3QoIG1hdGVyaWFsLmFuaXNvdHJvcHlCLCB2aWV3RGlyICk7XHJcblx0XHRmbG9hdCBkb3RCSCA9IGRvdCggbWF0ZXJpYWwuYW5pc290cm9weUIsIGhhbGZEaXIgKTtcclxuXHJcblx0XHRmbG9hdCBWID0gVl9HR1hfU21pdGhDb3JyZWxhdGVkX0FuaXNvdHJvcGljKCBtYXRlcmlhbC5hbHBoYVQsIGFscGhhLCBkb3RUViwgZG90QlYsIGRvdFRMLCBkb3RCTCwgZG90TlYsIGRvdE5MICk7XHJcblxyXG5cdFx0ZmxvYXQgRCA9IERfR0dYX0FuaXNvdHJvcGljKCBtYXRlcmlhbC5hbHBoYVQsIGFscGhhLCBkb3ROSCwgZG90VEgsIGRvdEJIICk7XHJcblxyXG5cdCNlbHNlXHJcblxyXG5cdFx0ZmxvYXQgViA9IFZfR0dYX1NtaXRoQ29ycmVsYXRlZCggYWxwaGEsIGRvdE5MLCBkb3ROViApO1xyXG5cclxuXHRcdGZsb2F0IEQgPSBEX0dHWCggYWxwaGEsIGRvdE5IICk7XHJcblxyXG5cdCNlbmRpZlxyXG5cclxuXHRyZXR1cm4gRiAqICggViAqIEQgKTtcclxuXHJcbn1cclxuXHJcbi8vIFJlY3QgQXJlYSBMaWdodFxyXG5cclxuLy8gUmVhbC1UaW1lIFBvbHlnb25hbC1MaWdodCBTaGFkaW5nIHdpdGggTGluZWFybHkgVHJhbnNmb3JtZWQgQ29zaW5lc1xyXG4vLyBieSBFcmljIEhlaXR6LCBKb25hdGhhbiBEdXB1eSwgU3RlcGhlbiBIaWxsIGFuZCBEYXZpZCBOZXViZWx0XHJcbi8vIGNvZGU6IGh0dHBzOi8vZ2l0aHViLmNvbS9zZWxmc2hhZG93L2x0Y19jb2RlL1xyXG5cclxudmVjMiBMVENfVXYoIGNvbnN0IGluIHZlYzMgTiwgY29uc3QgaW4gdmVjMyBWLCBjb25zdCBpbiBmbG9hdCByb3VnaG5lc3MgKSB7XHJcblxyXG5cdGNvbnN0IGZsb2F0IExVVF9TSVpFID0gNjQuMDtcclxuXHRjb25zdCBmbG9hdCBMVVRfU0NBTEUgPSAoIExVVF9TSVpFIC0gMS4wICkgLyBMVVRfU0laRTtcclxuXHRjb25zdCBmbG9hdCBMVVRfQklBUyA9IDAuNSAvIExVVF9TSVpFO1xyXG5cclxuXHRmbG9hdCBkb3ROViA9IHNhdHVyYXRlKCBkb3QoIE4sIFYgKSApO1xyXG5cclxuXHQvLyB0ZXh0dXJlIHBhcmFtZXRlcml6ZWQgYnkgc3FydCggR0dYIGFscGhhICkgYW5kIHNxcnQoIDEgLSBjb3MoIHRoZXRhICkgKVxyXG5cdHZlYzIgdXYgPSB2ZWMyKCByb3VnaG5lc3MsIHNxcnQoIDEuMCAtIGRvdE5WICkgKTtcclxuXHJcblx0dXYgPSB1diAqIExVVF9TQ0FMRSArIExVVF9CSUFTO1xyXG5cclxuXHRyZXR1cm4gdXY7XHJcblxyXG59XHJcblxyXG5mbG9hdCBMVENfQ2xpcHBlZFNwaGVyZUZvcm1GYWN0b3IoIGNvbnN0IGluIHZlYzMgZiApIHtcclxuXHJcblx0Ly8gUmVhbC1UaW1lIEFyZWEgTGlnaHRpbmc6IGEgSm91cm5leSBmcm9tIFJlc2VhcmNoIHRvIFByb2R1Y3Rpb24gKHAuMTAyKVxyXG5cdC8vIEFuIGFwcHJveGltYXRpb24gb2YgdGhlIGZvcm0gZmFjdG9yIG9mIGEgaG9yaXpvbi1jbGlwcGVkIHJlY3RhbmdsZS5cclxuXHJcblx0ZmxvYXQgbCA9IGxlbmd0aCggZiApO1xyXG5cclxuXHRyZXR1cm4gbWF4KCAoIGwgKiBsICsgZi56ICkgLyAoIGwgKyAxLjAgKSwgMC4wICk7XHJcblxyXG59XHJcblxyXG52ZWMzIExUQ19FZGdlVmVjdG9yRm9ybUZhY3RvciggY29uc3QgaW4gdmVjMyB2MSwgY29uc3QgaW4gdmVjMyB2MiApIHtcclxuXHJcblx0ZmxvYXQgeCA9IGRvdCggdjEsIHYyICk7XHJcblxyXG5cdGZsb2F0IHkgPSBhYnMoIHggKTtcclxuXHJcblx0Ly8gcmF0aW9uYWwgcG9seW5vbWlhbCBhcHByb3hpbWF0aW9uIHRvIHRoZXRhIC8gc2luKCB0aGV0YSApIC8gMlBJXHJcblx0ZmxvYXQgYSA9IDAuODU0Mzk4NSArICggMC40OTY1MTU1ICsgMC4wMTQ1MjA2ICogeSApICogeTtcclxuXHRmbG9hdCBiID0gMy40MTc1OTQwICsgKCA0LjE2MTY3MjQgKyB5ICkgKiB5O1xyXG5cdGZsb2F0IHYgPSBhIC8gYjtcclxuXHJcblx0ZmxvYXQgdGhldGFfc2ludGhldGEgPSAoIHggPiAwLjAgKSA/IHYgOiAwLjUgKiBpbnZlcnNlc3FydCggbWF4KCAxLjAgLSB4ICogeCwgMWUtNyApICkgLSB2O1xyXG5cclxuXHRyZXR1cm4gY3Jvc3MoIHYxLCB2MiApICogdGhldGFfc2ludGhldGE7XHJcblxyXG59XHJcblxyXG52ZWMzIExUQ19FdmFsdWF0ZSggY29uc3QgaW4gdmVjMyBOLCBjb25zdCBpbiB2ZWMzIFYsIGNvbnN0IGluIHZlYzMgUCwgY29uc3QgaW4gbWF0MyBtSW52LCBjb25zdCBpbiB2ZWMzIHJlY3RDb29yZHNbIDQgXSApIHtcclxuXHJcblx0Ly8gYmFpbCBpZiBwb2ludCBpcyBvbiBiYWNrIHNpZGUgb2YgcGxhbmUgb2YgbGlnaHRcclxuXHQvLyBhc3N1bWVzIGNjdyB3aW5kaW5nIG9yZGVyIG9mIGxpZ2h0IHZlcnRpY2VzXHJcblx0dmVjMyB2MSA9IHJlY3RDb29yZHNbIDEgXSAtIHJlY3RDb29yZHNbIDAgXTtcclxuXHR2ZWMzIHYyID0gcmVjdENvb3Jkc1sgMyBdIC0gcmVjdENvb3Jkc1sgMCBdO1xyXG5cdHZlYzMgbGlnaHROb3JtYWwgPSBjcm9zcyggdjEsIHYyICk7XHJcblxyXG5cdGlmKCBkb3QoIGxpZ2h0Tm9ybWFsLCBQIC0gcmVjdENvb3Jkc1sgMCBdICkgPCAwLjAgKSByZXR1cm4gdmVjMyggMC4wICk7XHJcblxyXG5cdC8vIGNvbnN0cnVjdCBvcnRob25vcm1hbCBiYXNpcyBhcm91bmQgTlxyXG5cdHZlYzMgVDEsIFQyO1xyXG5cdFQxID0gbm9ybWFsaXplKCBWIC0gTiAqIGRvdCggViwgTiApICk7XHJcblx0VDIgPSAtIGNyb3NzKCBOLCBUMSApOyAvLyBuZWdhdGVkIGZyb20gcGFwZXI7IHBvc3NpYmx5IGR1ZSB0byBhIGRpZmZlcmVudCBoYW5kZWRuZXNzIG9mIHdvcmxkIGNvb3JkaW5hdGUgc3lzdGVtXHJcblxyXG5cdC8vIGNvbXB1dGUgdHJhbnNmb3JtXHJcblx0bWF0MyBtYXQgPSBtSW52ICogdHJhbnNwb3NlTWF0MyggbWF0MyggVDEsIFQyLCBOICkgKTtcclxuXHJcblx0Ly8gdHJhbnNmb3JtIHJlY3RcclxuXHR2ZWMzIGNvb3Jkc1sgNCBdO1xyXG5cdGNvb3Jkc1sgMCBdID0gbWF0ICogKCByZWN0Q29vcmRzWyAwIF0gLSBQICk7XHJcblx0Y29vcmRzWyAxIF0gPSBtYXQgKiAoIHJlY3RDb29yZHNbIDEgXSAtIFAgKTtcclxuXHRjb29yZHNbIDIgXSA9IG1hdCAqICggcmVjdENvb3Jkc1sgMiBdIC0gUCApO1xyXG5cdGNvb3Jkc1sgMyBdID0gbWF0ICogKCByZWN0Q29vcmRzWyAzIF0gLSBQICk7XHJcblxyXG5cdC8vIHByb2plY3QgcmVjdCBvbnRvIHNwaGVyZVxyXG5cdGNvb3Jkc1sgMCBdID0gbm9ybWFsaXplKCBjb29yZHNbIDAgXSApO1xyXG5cdGNvb3Jkc1sgMSBdID0gbm9ybWFsaXplKCBjb29yZHNbIDEgXSApO1xyXG5cdGNvb3Jkc1sgMiBdID0gbm9ybWFsaXplKCBjb29yZHNbIDIgXSApO1xyXG5cdGNvb3Jkc1sgMyBdID0gbm9ybWFsaXplKCBjb29yZHNbIDMgXSApO1xyXG5cclxuXHQvLyBjYWxjdWxhdGUgdmVjdG9yIGZvcm0gZmFjdG9yXHJcblx0dmVjMyB2ZWN0b3JGb3JtRmFjdG9yID0gdmVjMyggMC4wICk7XHJcblx0dmVjdG9yRm9ybUZhY3RvciArPSBMVENfRWRnZVZlY3RvckZvcm1GYWN0b3IoIGNvb3Jkc1sgMCBdLCBjb29yZHNbIDEgXSApO1xyXG5cdHZlY3RvckZvcm1GYWN0b3IgKz0gTFRDX0VkZ2VWZWN0b3JGb3JtRmFjdG9yKCBjb29yZHNbIDEgXSwgY29vcmRzWyAyIF0gKTtcclxuXHR2ZWN0b3JGb3JtRmFjdG9yICs9IExUQ19FZGdlVmVjdG9yRm9ybUZhY3RvciggY29vcmRzWyAyIF0sIGNvb3Jkc1sgMyBdICk7XHJcblx0dmVjdG9yRm9ybUZhY3RvciArPSBMVENfRWRnZVZlY3RvckZvcm1GYWN0b3IoIGNvb3Jkc1sgMyBdLCBjb29yZHNbIDAgXSApO1xyXG5cclxuXHQvLyBhZGp1c3QgZm9yIGhvcml6b24gY2xpcHBpbmdcclxuXHRmbG9hdCByZXN1bHQgPSBMVENfQ2xpcHBlZFNwaGVyZUZvcm1GYWN0b3IoIHZlY3RvckZvcm1GYWN0b3IgKTtcclxuXHJcbi8qXHJcblx0Ly8gYWx0ZXJuYXRlIG1ldGhvZCBvZiBhZGp1c3RpbmcgZm9yIGhvcml6b24gY2xpcHBpbmcgKHNlZSByZWZlcmVjZSlcclxuXHQvLyByZWZhY3RvcmluZyByZXF1aXJlZFxyXG5cdGZsb2F0IGxlbiA9IGxlbmd0aCggdmVjdG9yRm9ybUZhY3RvciApO1xyXG5cdGZsb2F0IHogPSB2ZWN0b3JGb3JtRmFjdG9yLnogLyBsZW47XHJcblxyXG5cdGNvbnN0IGZsb2F0IExVVF9TSVpFID0gNjQuMDtcclxuXHRjb25zdCBmbG9hdCBMVVRfU0NBTEUgPSAoIExVVF9TSVpFIC0gMS4wICkgLyBMVVRfU0laRTtcclxuXHRjb25zdCBmbG9hdCBMVVRfQklBUyA9IDAuNSAvIExVVF9TSVpFO1xyXG5cclxuXHQvLyB0YWJ1bGF0ZWQgaG9yaXpvbi1jbGlwcGVkIHNwaGVyZSwgYXBwYXJlbnRseS4uLlxyXG5cdHZlYzIgdXYgPSB2ZWMyKCB6ICogMC41ICsgMC41LCBsZW4gKTtcclxuXHR1diA9IHV2ICogTFVUX1NDQUxFICsgTFVUX0JJQVM7XHJcblxyXG5cdGZsb2F0IHNjYWxlID0gdGV4dHVyZTJEKCBsdGNfMiwgdXYgKS53O1xyXG5cclxuXHRmbG9hdCByZXN1bHQgPSBsZW4gKiBzY2FsZTtcclxuKi9cclxuXHJcblx0cmV0dXJuIHZlYzMoIHJlc3VsdCApO1xyXG5cclxufVxyXG5cclxuLy8gRW5kIFJlY3QgQXJlYSBMaWdodFxyXG5cclxuI2lmIGRlZmluZWQoIFVTRV9TSEVFTiApXHJcblxyXG4vLyBodHRwczovL2dpdGh1Yi5jb20vZ29vZ2xlL2ZpbGFtZW50L2Jsb2IvbWFzdGVyL3NoYWRlcnMvc3JjL2JyZGYuZnNcclxuZmxvYXQgRF9DaGFybGllKCBmbG9hdCByb3VnaG5lc3MsIGZsb2F0IGRvdE5IICkge1xyXG5cclxuXHRmbG9hdCBhbHBoYSA9IHBvdzIoIHJvdWdobmVzcyApO1xyXG5cclxuXHQvLyBFc3RldmV6IGFuZCBLdWxsYSAyMDE3LCBcIlByb2R1Y3Rpb24gRnJpZW5kbHkgTWljcm9mYWNldCBTaGVlbiBCUkRGXCJcclxuXHRmbG9hdCBpbnZBbHBoYSA9IDEuMCAvIGFscGhhO1xyXG5cdGZsb2F0IGNvczJoID0gZG90TkggKiBkb3ROSDtcclxuXHRmbG9hdCBzaW4yaCA9IG1heCggMS4wIC0gY29zMmgsIDAuMDA3ODEyNSApOyAvLyAyXigtMTQvMiksIHNvIHNpbjJoXjIgPiAwIGluIGZwMTZcclxuXHJcblx0cmV0dXJuICggMi4wICsgaW52QWxwaGEgKSAqIHBvdyggc2luMmgsIGludkFscGhhICogMC41ICkgLyAoIDIuMCAqIFBJICk7XHJcblxyXG59XHJcblxyXG4vLyBodHRwczovL2dpdGh1Yi5jb20vZ29vZ2xlL2ZpbGFtZW50L2Jsb2IvbWFzdGVyL3NoYWRlcnMvc3JjL2JyZGYuZnNcclxuZmxvYXQgVl9OZXViZWx0KCBmbG9hdCBkb3ROViwgZmxvYXQgZG90TkwgKSB7XHJcblxyXG5cdC8vIE5ldWJlbHQgYW5kIFBldHRpbmVvIDIwMTMsIFwiQ3JhZnRpbmcgYSBOZXh0LWdlbiBNYXRlcmlhbCBQaXBlbGluZSBmb3IgVGhlIE9yZGVyOiAxODg2XCJcclxuXHRyZXR1cm4gc2F0dXJhdGUoIDEuMCAvICggNC4wICogKCBkb3ROTCArIGRvdE5WIC0gZG90TkwgKiBkb3ROViApICkgKTtcclxuXHJcbn1cclxuXHJcbnZlYzMgQlJERl9TaGVlbiggY29uc3QgaW4gdmVjMyBsaWdodERpciwgY29uc3QgaW4gdmVjMyB2aWV3RGlyLCBjb25zdCBpbiB2ZWMzIG5vcm1hbCwgdmVjMyBzaGVlbkNvbG9yLCBjb25zdCBpbiBmbG9hdCBzaGVlblJvdWdobmVzcyApIHtcclxuXHJcblx0dmVjMyBoYWxmRGlyID0gbm9ybWFsaXplKCBsaWdodERpciArIHZpZXdEaXIgKTtcclxuXHJcblx0ZmxvYXQgZG90TkwgPSBzYXR1cmF0ZSggZG90KCBub3JtYWwsIGxpZ2h0RGlyICkgKTtcclxuXHRmbG9hdCBkb3ROViA9IHNhdHVyYXRlKCBkb3QoIG5vcm1hbCwgdmlld0RpciApICk7XHJcblx0ZmxvYXQgZG90TkggPSBzYXR1cmF0ZSggZG90KCBub3JtYWwsIGhhbGZEaXIgKSApO1xyXG5cclxuXHRmbG9hdCBEID0gRF9DaGFybGllKCBzaGVlblJvdWdobmVzcywgZG90TkggKTtcclxuXHRmbG9hdCBWID0gVl9OZXViZWx0KCBkb3ROViwgZG90TkwgKTtcclxuXHJcblx0cmV0dXJuIHNoZWVuQ29sb3IgKiAoIEQgKiBWICk7XHJcblxyXG59XHJcblxyXG4jZW5kaWZcclxuXHJcbi8vIFRoaXMgaXMgYSBjdXJ2ZS1maXQgYXBwcm94bWF0aW9uIHRvIHRoZSBcIkNoYXJsaWUgc2hlZW5cIiBCUkRGIGludGVncmF0ZWQgb3ZlciB0aGUgaGVtaXNwaGVyZSBmcm9tIFxyXG4vLyBFc3RldmV6IGFuZCBLdWxsYSAyMDE3LCBcIlByb2R1Y3Rpb24gRnJpZW5kbHkgTWljcm9mYWNldCBTaGVlbiBCUkRGXCIuIFRoZSBhbmFseXNpcyBjYW4gYmUgZm91bmRcclxuLy8gaW4gdGhlIFNoZWVuIHNlY3Rpb24gb2YgaHR0cHM6Ly9kcml2ZS5nb29nbGUuY29tL2ZpbGUvZC8xVDBEMVZTeVI0QWxscUlKVFFBcmFFSXpqbGI1aDRGS0gvdmlldz91c3A9c2hhcmluZ1xyXG5mbG9hdCBJQkxTaGVlbkJSREYoIGNvbnN0IGluIHZlYzMgbm9ybWFsLCBjb25zdCBpbiB2ZWMzIHZpZXdEaXIsIGNvbnN0IGluIGZsb2F0IHJvdWdobmVzcyApIHtcclxuXHJcblx0ZmxvYXQgZG90TlYgPSBzYXR1cmF0ZSggZG90KCBub3JtYWwsIHZpZXdEaXIgKSApO1xyXG5cclxuXHRmbG9hdCByMiA9IHJvdWdobmVzcyAqIHJvdWdobmVzcztcclxuXHJcblx0ZmxvYXQgYSA9IHJvdWdobmVzcyA8IDAuMjUgPyAtMzM5LjIgKiByMiArIDE2MS40ICogcm91Z2huZXNzIC0gMjUuOSA6IC04LjQ4ICogcjIgKyAxNC4zICogcm91Z2huZXNzIC0gOS45NTtcclxuXHJcblx0ZmxvYXQgYiA9IHJvdWdobmVzcyA8IDAuMjUgPyA0NC4wICogcjIgLSAyMy43ICogcm91Z2huZXNzICsgMy4yNiA6IDEuOTcgKiByMiAtIDMuMjcgKiByb3VnaG5lc3MgKyAwLjcyO1xyXG5cclxuXHRmbG9hdCBERyA9IGV4cCggYSAqIGRvdE5WICsgYiApICsgKCByb3VnaG5lc3MgPCAwLjI1ID8gMC4wIDogMC4xICogKCByb3VnaG5lc3MgLSAwLjI1ICkgKTtcclxuXHJcblx0cmV0dXJuIHNhdHVyYXRlKCBERyAqIFJFQ0lQUk9DQUxfUEkgKTtcclxuXHJcbn1cclxuXHJcbi8vIEFuYWx5dGljYWwgYXBwcm94aW1hdGlvbiBvZiB0aGUgREZHIExVVCwgb25lIGhhbGYgb2YgdGhlXHJcbi8vIHNwbGl0LXN1bSBhcHByb3hpbWF0aW9uIHVzZWQgaW4gaW5kaXJlY3Qgc3BlY3VsYXIgbGlnaHRpbmcuXHJcbi8vIHZpYSAnZW52aXJvbm1lbnRCUkRGJyBmcm9tIFwiUGh5c2ljYWxseSBCYXNlZCBTaGFkaW5nIG9uIE1vYmlsZVwiXHJcbi8vIGh0dHBzOi8vd3d3LnVucmVhbGVuZ2luZS5jb20vYmxvZy9waHlzaWNhbGx5LWJhc2VkLXNoYWRpbmctb24tbW9iaWxlXHJcbnZlYzIgREZHQXBwcm94KCBjb25zdCBpbiB2ZWMzIG5vcm1hbCwgY29uc3QgaW4gdmVjMyB2aWV3RGlyLCBjb25zdCBpbiBmbG9hdCByb3VnaG5lc3MgKSB7XHJcblxyXG5cdGZsb2F0IGRvdE5WID0gc2F0dXJhdGUoIGRvdCggbm9ybWFsLCB2aWV3RGlyICkgKTtcclxuXHJcblx0Y29uc3QgdmVjNCBjMCA9IHZlYzQoIC0gMSwgLSAwLjAyNzUsIC0gMC41NzIsIDAuMDIyICk7XHJcblxyXG5cdGNvbnN0IHZlYzQgYzEgPSB2ZWM0KCAxLCAwLjA0MjUsIDEuMDQsIC0gMC4wNCApO1xyXG5cclxuXHR2ZWM0IHIgPSByb3VnaG5lc3MgKiBjMCArIGMxO1xyXG5cclxuXHRmbG9hdCBhMDA0ID0gbWluKCByLnggKiByLngsIGV4cDIoIC0gOS4yOCAqIGRvdE5WICkgKSAqIHIueCArIHIueTtcclxuXHJcblx0dmVjMiBmYWIgPSB2ZWMyKCAtIDEuMDQsIDEuMDQgKSAqIGEwMDQgKyByLnp3O1xyXG5cclxuXHRyZXR1cm4gZmFiO1xyXG5cclxufVxyXG5cclxudmVjMyBFbnZpcm9ubWVudEJSREYoIGNvbnN0IGluIHZlYzMgbm9ybWFsLCBjb25zdCBpbiB2ZWMzIHZpZXdEaXIsIGNvbnN0IGluIHZlYzMgc3BlY3VsYXJDb2xvciwgY29uc3QgaW4gZmxvYXQgc3BlY3VsYXJGOTAsIGNvbnN0IGluIGZsb2F0IHJvdWdobmVzcyApIHtcclxuXHJcblx0dmVjMiBmYWIgPSBERkdBcHByb3goIG5vcm1hbCwgdmlld0Rpciwgcm91Z2huZXNzICk7XHJcblxyXG5cdHJldHVybiBzcGVjdWxhckNvbG9yICogZmFiLnggKyBzcGVjdWxhckY5MCAqIGZhYi55O1xyXG5cclxufVxyXG5cclxuLy8gRmRlei1BZ8O8ZXJhJ3MgXCJNdWx0aXBsZS1TY2F0dGVyaW5nIE1pY3JvZmFjZXQgTW9kZWwgZm9yIFJlYWwtVGltZSBJbWFnZSBCYXNlZCBMaWdodGluZ1wiXHJcbi8vIEFwcHJveGltYXRlcyBtdWx0aXNjYXR0ZXJpbmcgaW4gb3JkZXIgdG8gcHJlc2VydmUgZW5lcmd5LlxyXG4vLyBodHRwOi8vd3d3LmpjZ3Qub3JnL3B1Ymxpc2hlZC8wMDA4LzAxLzAzL1xyXG4jaWZkZWYgVVNFX0lSSURFU0NFTkNFXHJcbnZvaWQgY29tcHV0ZU11bHRpc2NhdHRlcmluZ0lyaWRlc2NlbmNlKCBjb25zdCBpbiB2ZWMzIG5vcm1hbCwgY29uc3QgaW4gdmVjMyB2aWV3RGlyLCBjb25zdCBpbiB2ZWMzIHNwZWN1bGFyQ29sb3IsIGNvbnN0IGluIGZsb2F0IHNwZWN1bGFyRjkwLCBjb25zdCBpbiBmbG9hdCBpcmlkZXNjZW5jZSwgY29uc3QgaW4gdmVjMyBpcmlkZXNjZW5jZUYwLCBjb25zdCBpbiBmbG9hdCByb3VnaG5lc3MsIGlub3V0IHZlYzMgc2luZ2xlU2NhdHRlciwgaW5vdXQgdmVjMyBtdWx0aVNjYXR0ZXIgKSB7XHJcbiNlbHNlXHJcbnZvaWQgY29tcHV0ZU11bHRpc2NhdHRlcmluZyggY29uc3QgaW4gdmVjMyBub3JtYWwsIGNvbnN0IGluIHZlYzMgdmlld0RpciwgY29uc3QgaW4gdmVjMyBzcGVjdWxhckNvbG9yLCBjb25zdCBpbiBmbG9hdCBzcGVjdWxhckY5MCwgY29uc3QgaW4gZmxvYXQgcm91Z2huZXNzLCBpbm91dCB2ZWMzIHNpbmdsZVNjYXR0ZXIsIGlub3V0IHZlYzMgbXVsdGlTY2F0dGVyICkge1xyXG4jZW5kaWZcclxuXHJcblx0dmVjMiBmYWIgPSBERkdBcHByb3goIG5vcm1hbCwgdmlld0Rpciwgcm91Z2huZXNzICk7XHJcblxyXG5cdCNpZmRlZiBVU0VfSVJJREVTQ0VOQ0VcclxuXHJcblx0XHR2ZWMzIEZyID0gbWl4KCBzcGVjdWxhckNvbG9yLCBpcmlkZXNjZW5jZUYwLCBpcmlkZXNjZW5jZSApO1xyXG5cclxuXHQjZWxzZVxyXG5cclxuXHRcdHZlYzMgRnIgPSBzcGVjdWxhckNvbG9yO1xyXG5cclxuXHQjZW5kaWZcclxuXHJcblx0dmVjMyBGc3NFc3MgPSBGciAqIGZhYi54ICsgc3BlY3VsYXJGOTAgKiBmYWIueTtcclxuXHJcblx0ZmxvYXQgRXNzID0gZmFiLnggKyBmYWIueTtcclxuXHRmbG9hdCBFbXMgPSAxLjAgLSBFc3M7XHJcblxyXG5cdHZlYzMgRmF2ZyA9IEZyICsgKCAxLjAgLSBGciApICogMC4wNDc2MTk7IC8vIDEvMjFcclxuXHR2ZWMzIEZtcyA9IEZzc0VzcyAqIEZhdmcgLyAoIDEuMCAtIEVtcyAqIEZhdmcgKTtcclxuXHJcblx0c2luZ2xlU2NhdHRlciArPSBGc3NFc3M7XHJcblx0bXVsdGlTY2F0dGVyICs9IEZtcyAqIEVtcztcclxuXHJcbn1cclxuXHJcbiNpZiBOVU1fUkVDVF9BUkVBX0xJR0hUUyA+IDBcclxuXHJcblx0dm9pZCBSRV9EaXJlY3RfUmVjdEFyZWFfUGh5c2ljYWwoIGNvbnN0IGluIFJlY3RBcmVhTGlnaHQgcmVjdEFyZWFMaWdodCwgY29uc3QgaW4gdmVjMyBnZW9tZXRyeVBvc2l0aW9uLCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5Tm9ybWFsLCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5Vmlld0RpciwgY29uc3QgaW4gdmVjMyBnZW9tZXRyeUNsZWFyY29hdE5vcm1hbCwgY29uc3QgaW4gUGh5c2ljYWxNYXRlcmlhbCBtYXRlcmlhbCwgaW5vdXQgUmVmbGVjdGVkTGlnaHQgcmVmbGVjdGVkTGlnaHQgKSB7XHJcblxyXG5cdFx0dmVjMyBub3JtYWwgPSBnZW9tZXRyeU5vcm1hbDtcclxuXHRcdHZlYzMgdmlld0RpciA9IGdlb21ldHJ5Vmlld0RpcjtcclxuXHRcdHZlYzMgcG9zaXRpb24gPSBnZW9tZXRyeVBvc2l0aW9uO1xyXG5cdFx0dmVjMyBsaWdodFBvcyA9IHJlY3RBcmVhTGlnaHQucG9zaXRpb247XHJcblx0XHR2ZWMzIGhhbGZXaWR0aCA9IHJlY3RBcmVhTGlnaHQuaGFsZldpZHRoO1xyXG5cdFx0dmVjMyBoYWxmSGVpZ2h0ID0gcmVjdEFyZWFMaWdodC5oYWxmSGVpZ2h0O1xyXG5cdFx0dmVjMyBsaWdodENvbG9yID0gcmVjdEFyZWFMaWdodC5jb2xvcjtcclxuXHRcdGZsb2F0IHJvdWdobmVzcyA9IG1hdGVyaWFsLnJvdWdobmVzcztcclxuXHJcblx0XHR2ZWMzIHJlY3RDb29yZHNbIDQgXTtcclxuXHRcdHJlY3RDb29yZHNbIDAgXSA9IGxpZ2h0UG9zICsgaGFsZldpZHRoIC0gaGFsZkhlaWdodDsgLy8gY291bnRlcmNsb2Nrd2lzZTsgbGlnaHQgc2hpbmVzIGluIGxvY2FsIG5lZyB6IGRpcmVjdGlvblxyXG5cdFx0cmVjdENvb3Jkc1sgMSBdID0gbGlnaHRQb3MgLSBoYWxmV2lkdGggLSBoYWxmSGVpZ2h0O1xyXG5cdFx0cmVjdENvb3Jkc1sgMiBdID0gbGlnaHRQb3MgLSBoYWxmV2lkdGggKyBoYWxmSGVpZ2h0O1xyXG5cdFx0cmVjdENvb3Jkc1sgMyBdID0gbGlnaHRQb3MgKyBoYWxmV2lkdGggKyBoYWxmSGVpZ2h0O1xyXG5cclxuXHRcdHZlYzIgdXYgPSBMVENfVXYoIG5vcm1hbCwgdmlld0Rpciwgcm91Z2huZXNzICk7XHJcblxyXG5cdFx0dmVjNCB0MSA9IHRleHR1cmUyRCggbHRjXzEsIHV2ICk7XHJcblx0XHR2ZWM0IHQyID0gdGV4dHVyZTJEKCBsdGNfMiwgdXYgKTtcclxuXHJcblx0XHRtYXQzIG1JbnYgPSBtYXQzKFxyXG5cdFx0XHR2ZWMzKCB0MS54LCAwLCB0MS55ICksXHJcblx0XHRcdHZlYzMoICAgIDAsIDEsICAgIDAgKSxcclxuXHRcdFx0dmVjMyggdDEueiwgMCwgdDEudyApXHJcblx0XHQpO1xyXG5cclxuXHRcdC8vIExUQyBGcmVzbmVsIEFwcHJveGltYXRpb24gYnkgU3RlcGhlbiBIaWxsXHJcblx0XHQvLyBodHRwOi8vYmxvZy5zZWxmc2hhZG93LmNvbS9wdWJsaWNhdGlvbnMvczIwMTYtYWR2YW5jZXMvczIwMTZfbHRjX2ZyZXNuZWwucGRmXHJcblx0XHR2ZWMzIGZyZXNuZWwgPSAoIG1hdGVyaWFsLnNwZWN1bGFyQ29sb3IgKiB0Mi54ICsgKCB2ZWMzKCAxLjAgKSAtIG1hdGVyaWFsLnNwZWN1bGFyQ29sb3IgKSAqIHQyLnkgKTtcclxuXHJcblx0XHRyZWZsZWN0ZWRMaWdodC5kaXJlY3RTcGVjdWxhciArPSBsaWdodENvbG9yICogZnJlc25lbCAqIExUQ19FdmFsdWF0ZSggbm9ybWFsLCB2aWV3RGlyLCBwb3NpdGlvbiwgbUludiwgcmVjdENvb3JkcyApO1xyXG5cclxuXHRcdHJlZmxlY3RlZExpZ2h0LmRpcmVjdERpZmZ1c2UgKz0gbGlnaHRDb2xvciAqIG1hdGVyaWFsLmRpZmZ1c2VDb2xvciAqIExUQ19FdmFsdWF0ZSggbm9ybWFsLCB2aWV3RGlyLCBwb3NpdGlvbiwgbWF0MyggMS4wICksIHJlY3RDb29yZHMgKTtcclxuXHJcblx0fVxyXG5cclxuI2VuZGlmXHJcblxyXG52b2lkIFJFX0RpcmVjdF9QaHlzaWNhbCggY29uc3QgaW4gSW5jaWRlbnRMaWdodCBkaXJlY3RMaWdodCwgY29uc3QgaW4gdmVjMyBnZW9tZXRyeVBvc2l0aW9uLCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5Tm9ybWFsLCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5Vmlld0RpciwgY29uc3QgaW4gdmVjMyBnZW9tZXRyeUNsZWFyY29hdE5vcm1hbCwgY29uc3QgaW4gUGh5c2ljYWxNYXRlcmlhbCBtYXRlcmlhbCwgaW5vdXQgUmVmbGVjdGVkTGlnaHQgcmVmbGVjdGVkTGlnaHQgKSB7XHJcblxyXG5cdGZsb2F0IGRvdE5MID0gc2F0dXJhdGUoIGRvdCggZ2VvbWV0cnlOb3JtYWwsIGRpcmVjdExpZ2h0LmRpcmVjdGlvbiApICk7XHJcblxyXG5cdHZlYzMgaXJyYWRpYW5jZSA9IGRvdE5MICogZGlyZWN0TGlnaHQuY29sb3I7XHJcblxyXG5cdCNpZmRlZiBVU0VfQ0xFQVJDT0FUXHJcblxyXG5cdFx0ZmxvYXQgZG90TkxjYyA9IHNhdHVyYXRlKCBkb3QoIGdlb21ldHJ5Q2xlYXJjb2F0Tm9ybWFsLCBkaXJlY3RMaWdodC5kaXJlY3Rpb24gKSApO1xyXG5cclxuXHRcdHZlYzMgY2NJcnJhZGlhbmNlID0gZG90TkxjYyAqIGRpcmVjdExpZ2h0LmNvbG9yO1xyXG5cclxuXHRcdGNsZWFyY29hdFNwZWN1bGFyRGlyZWN0ICs9IGNjSXJyYWRpYW5jZSAqIEJSREZfR0dYX0NsZWFyY29hdCggZGlyZWN0TGlnaHQuZGlyZWN0aW9uLCBnZW9tZXRyeVZpZXdEaXIsIGdlb21ldHJ5Q2xlYXJjb2F0Tm9ybWFsLCBtYXRlcmlhbCApO1xyXG5cclxuXHQjZW5kaWZcclxuXHJcblx0I2lmZGVmIFVTRV9TSEVFTlxyXG5cclxuXHRcdHNoZWVuU3BlY3VsYXJEaXJlY3QgKz0gaXJyYWRpYW5jZSAqIEJSREZfU2hlZW4oIGRpcmVjdExpZ2h0LmRpcmVjdGlvbiwgZ2VvbWV0cnlWaWV3RGlyLCBnZW9tZXRyeU5vcm1hbCwgbWF0ZXJpYWwuc2hlZW5Db2xvciwgbWF0ZXJpYWwuc2hlZW5Sb3VnaG5lc3MgKTtcclxuXHJcblx0I2VuZGlmXHJcblxyXG5cdHJlZmxlY3RlZExpZ2h0LmRpcmVjdFNwZWN1bGFyICs9IGlycmFkaWFuY2UgKiBCUkRGX0dHWCggZGlyZWN0TGlnaHQuZGlyZWN0aW9uLCBnZW9tZXRyeVZpZXdEaXIsIGdlb21ldHJ5Tm9ybWFsLCBtYXRlcmlhbCApO1xyXG5cclxuXHRyZWZsZWN0ZWRMaWdodC5kaXJlY3REaWZmdXNlICs9IGlycmFkaWFuY2UgKiBCUkRGX0xhbWJlcnQoIG1hdGVyaWFsLmRpZmZ1c2VDb2xvciApO1xyXG59XHJcblxyXG52b2lkIFJFX0luZGlyZWN0RGlmZnVzZV9QaHlzaWNhbCggY29uc3QgaW4gdmVjMyBpcnJhZGlhbmNlLCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5UG9zaXRpb24sIGNvbnN0IGluIHZlYzMgZ2VvbWV0cnlOb3JtYWwsIGNvbnN0IGluIHZlYzMgZ2VvbWV0cnlWaWV3RGlyLCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5Q2xlYXJjb2F0Tm9ybWFsLCBjb25zdCBpbiBQaHlzaWNhbE1hdGVyaWFsIG1hdGVyaWFsLCBpbm91dCBSZWZsZWN0ZWRMaWdodCByZWZsZWN0ZWRMaWdodCApIHtcclxuXHJcblx0cmVmbGVjdGVkTGlnaHQuaW5kaXJlY3REaWZmdXNlICs9IGlycmFkaWFuY2UgKiBCUkRGX0xhbWJlcnQoIG1hdGVyaWFsLmRpZmZ1c2VDb2xvciApO1xyXG5cclxufVxyXG5cclxudm9pZCBSRV9JbmRpcmVjdFNwZWN1bGFyX1BoeXNpY2FsKCBjb25zdCBpbiB2ZWMzIHJhZGlhbmNlLCBjb25zdCBpbiB2ZWMzIGlycmFkaWFuY2UsIGNvbnN0IGluIHZlYzMgY2xlYXJjb2F0UmFkaWFuY2UsIGNvbnN0IGluIHZlYzMgZ2VvbWV0cnlQb3NpdGlvbiwgY29uc3QgaW4gdmVjMyBnZW9tZXRyeU5vcm1hbCwgY29uc3QgaW4gdmVjMyBnZW9tZXRyeVZpZXdEaXIsIGNvbnN0IGluIHZlYzMgZ2VvbWV0cnlDbGVhcmNvYXROb3JtYWwsIGNvbnN0IGluIFBoeXNpY2FsTWF0ZXJpYWwgbWF0ZXJpYWwsIGlub3V0IFJlZmxlY3RlZExpZ2h0IHJlZmxlY3RlZExpZ2h0KSB7XHJcblxyXG5cdCNpZmRlZiBVU0VfQ0xFQVJDT0FUXHJcblxyXG5cdFx0Y2xlYXJjb2F0U3BlY3VsYXJJbmRpcmVjdCArPSBjbGVhcmNvYXRSYWRpYW5jZSAqIEVudmlyb25tZW50QlJERiggZ2VvbWV0cnlDbGVhcmNvYXROb3JtYWwsIGdlb21ldHJ5Vmlld0RpciwgbWF0ZXJpYWwuY2xlYXJjb2F0RjAsIG1hdGVyaWFsLmNsZWFyY29hdEY5MCwgbWF0ZXJpYWwuY2xlYXJjb2F0Um91Z2huZXNzICk7XHJcblxyXG5cdCNlbmRpZlxyXG5cclxuXHQjaWZkZWYgVVNFX1NIRUVOXHJcblxyXG5cdFx0c2hlZW5TcGVjdWxhckluZGlyZWN0ICs9IGlycmFkaWFuY2UgKiBtYXRlcmlhbC5zaGVlbkNvbG9yICogSUJMU2hlZW5CUkRGKCBnZW9tZXRyeU5vcm1hbCwgZ2VvbWV0cnlWaWV3RGlyLCBtYXRlcmlhbC5zaGVlblJvdWdobmVzcyApO1xyXG5cclxuXHQjZW5kaWZcclxuXHJcblx0Ly8gQm90aCBpbmRpcmVjdCBzcGVjdWxhciBhbmQgaW5kaXJlY3QgZGlmZnVzZSBsaWdodCBhY2N1bXVsYXRlIGhlcmVcclxuXHJcblx0dmVjMyBzaW5nbGVTY2F0dGVyaW5nID0gdmVjMyggMC4wICk7XHJcblx0dmVjMyBtdWx0aVNjYXR0ZXJpbmcgPSB2ZWMzKCAwLjAgKTtcclxuXHR2ZWMzIGNvc2luZVdlaWdodGVkSXJyYWRpYW5jZSA9IGlycmFkaWFuY2UgKiBSRUNJUFJPQ0FMX1BJO1xyXG5cclxuXHQjaWZkZWYgVVNFX0lSSURFU0NFTkNFXHJcblxyXG5cdFx0Y29tcHV0ZU11bHRpc2NhdHRlcmluZ0lyaWRlc2NlbmNlKCBnZW9tZXRyeU5vcm1hbCwgZ2VvbWV0cnlWaWV3RGlyLCBtYXRlcmlhbC5zcGVjdWxhckNvbG9yLCBtYXRlcmlhbC5zcGVjdWxhckY5MCwgbWF0ZXJpYWwuaXJpZGVzY2VuY2UsIG1hdGVyaWFsLmlyaWRlc2NlbmNlRnJlc25lbCwgbWF0ZXJpYWwucm91Z2huZXNzLCBzaW5nbGVTY2F0dGVyaW5nLCBtdWx0aVNjYXR0ZXJpbmcgKTtcclxuXHJcblx0I2Vsc2VcclxuXHJcblx0XHRjb21wdXRlTXVsdGlzY2F0dGVyaW5nKCBnZW9tZXRyeU5vcm1hbCwgZ2VvbWV0cnlWaWV3RGlyLCBtYXRlcmlhbC5zcGVjdWxhckNvbG9yLCBtYXRlcmlhbC5zcGVjdWxhckY5MCwgbWF0ZXJpYWwucm91Z2huZXNzLCBzaW5nbGVTY2F0dGVyaW5nLCBtdWx0aVNjYXR0ZXJpbmcgKTtcclxuXHJcblx0I2VuZGlmXHJcblxyXG5cdHZlYzMgdG90YWxTY2F0dGVyaW5nID0gc2luZ2xlU2NhdHRlcmluZyArIG11bHRpU2NhdHRlcmluZztcclxuXHR2ZWMzIGRpZmZ1c2UgPSBtYXRlcmlhbC5kaWZmdXNlQ29sb3IgKiAoIDEuMCAtIG1heCggbWF4KCB0b3RhbFNjYXR0ZXJpbmcuciwgdG90YWxTY2F0dGVyaW5nLmcgKSwgdG90YWxTY2F0dGVyaW5nLmIgKSApO1xyXG5cclxuXHRyZWZsZWN0ZWRMaWdodC5pbmRpcmVjdFNwZWN1bGFyICs9IHJhZGlhbmNlICogc2luZ2xlU2NhdHRlcmluZztcclxuXHRyZWZsZWN0ZWRMaWdodC5pbmRpcmVjdFNwZWN1bGFyICs9IG11bHRpU2NhdHRlcmluZyAqIGNvc2luZVdlaWdodGVkSXJyYWRpYW5jZTtcclxuXHJcblx0cmVmbGVjdGVkTGlnaHQuaW5kaXJlY3REaWZmdXNlICs9IGRpZmZ1c2UgKiBjb3NpbmVXZWlnaHRlZElycmFkaWFuY2U7XHJcblxyXG59XHJcblxyXG4jZGVmaW5lIFJFX0RpcmVjdFx0XHRcdFx0UkVfRGlyZWN0X1BoeXNpY2FsXHJcbiNkZWZpbmUgUkVfRGlyZWN0X1JlY3RBcmVhXHRcdFJFX0RpcmVjdF9SZWN0QXJlYV9QaHlzaWNhbFxyXG4jZGVmaW5lIFJFX0luZGlyZWN0RGlmZnVzZVx0XHRSRV9JbmRpcmVjdERpZmZ1c2VfUGh5c2ljYWxcclxuI2RlZmluZSBSRV9JbmRpcmVjdFNwZWN1bGFyXHRcdFJFX0luZGlyZWN0U3BlY3VsYXJfUGh5c2ljYWxcclxuXHJcbi8vIHJlZjogaHR0cHM6Ly9zZWJsYWdhcmRlLmZpbGVzLndvcmRwcmVzcy5jb20vMjAxNS8wNy9jb3Vyc2Vfbm90ZXNfbW92aW5nX2Zyb3N0Yml0ZV90b19wYnJfdjMyLnBkZlxyXG5mbG9hdCBjb21wdXRlU3BlY3VsYXJPY2NsdXNpb24oIGNvbnN0IGluIGZsb2F0IGRvdE5WLCBjb25zdCBpbiBmbG9hdCBhbWJpZW50T2NjbHVzaW9uLCBjb25zdCBpbiBmbG9hdCByb3VnaG5lc3MgKSB7XHJcblxyXG5cdHJldHVybiBzYXR1cmF0ZSggcG93KCBkb3ROViArIGFtYmllbnRPY2NsdXNpb24sIGV4cDIoIC0gMTYuMCAqIHJvdWdobmVzcyAtIDEuMCApICkgLSAxLjAgKyBhbWJpZW50T2NjbHVzaW9uICk7XHJcblxyXG59XHJcbmA7XHJcbiIsImV4cG9ydCBkZWZhdWx0IC8qIGdsc2wgKi9gXHJcbi8qKlxyXG4gKiBUaGlzIGlzIGEgdGVtcGxhdGUgdGhhdCBjYW4gYmUgdXNlZCB0byBsaWdodCBhIG1hdGVyaWFsLCBpdCB1c2VzIHBsdWdnYWJsZVxyXG4gKiBSZW5kZXJFcXVhdGlvbnMgKFJFKWZvciBzcGVjaWZpYyBsaWdodGluZyBzY2VuYXJpb3MuXHJcbiAqXHJcbiAqIEluc3RydWN0aW9ucyBmb3IgdXNlOlxyXG4gKiAtIEVuc3VyZSB0aGF0IGJvdGggUkVfRGlyZWN0LCBSRV9JbmRpcmVjdERpZmZ1c2UgYW5kIFJFX0luZGlyZWN0U3BlY3VsYXIgYXJlIGRlZmluZWRcclxuICogLSBDcmVhdGUgYSBtYXRlcmlhbCBwYXJhbWV0ZXIgdGhhdCBpcyB0byBiZSBwYXNzZWQgYXMgdGhlIHRoaXJkIHBhcmFtZXRlciB0byB5b3VyIGxpZ2h0aW5nIGZ1bmN0aW9ucy5cclxuICpcclxuICogVE9ETzpcclxuICogLSBBZGQgYXJlYSBsaWdodCBzdXBwb3J0LlxyXG4gKiAtIEFkZCBzcGhlcmUgbGlnaHQgc3VwcG9ydC5cclxuICogLSBBZGQgZGlmZnVzZSBsaWdodCBwcm9iZSAoaXJyYWRpYW5jZSBjdWJlbWFwKSBzdXBwb3J0LlxyXG4gKi9cclxuXHJcbnZlYzMgZ2VvbWV0cnlQb3NpdGlvbiA9IC0gdlZpZXdQb3NpdGlvbjtcclxudmVjMyBnZW9tZXRyeU5vcm1hbCA9IG5vcm1hbDtcclxudmVjMyBnZW9tZXRyeVZpZXdEaXIgPSAoIGlzT3J0aG9ncmFwaGljICkgPyB2ZWMzKCAwLCAwLCAxICkgOiBub3JtYWxpemUoIHZWaWV3UG9zaXRpb24gKTtcclxuXHJcbnZlYzMgZ2VvbWV0cnlDbGVhcmNvYXROb3JtYWwgPSB2ZWMzKCAwLjAgKTtcclxuXHJcbiNpZmRlZiBVU0VfQ0xFQVJDT0FUXHJcblxyXG5cdGdlb21ldHJ5Q2xlYXJjb2F0Tm9ybWFsID0gY2xlYXJjb2F0Tm9ybWFsO1xyXG5cclxuI2VuZGlmXHJcblxyXG4jaWZkZWYgVVNFX0lSSURFU0NFTkNFXHJcblxyXG5cdGZsb2F0IGRvdE5WaSA9IHNhdHVyYXRlKCBkb3QoIG5vcm1hbCwgZ2VvbWV0cnlWaWV3RGlyICkgKTtcclxuXHJcblx0aWYgKCBtYXRlcmlhbC5pcmlkZXNjZW5jZVRoaWNrbmVzcyA9PSAwLjAgKSB7XHJcblxyXG5cdFx0bWF0ZXJpYWwuaXJpZGVzY2VuY2UgPSAwLjA7XHJcblxyXG5cdH0gZWxzZSB7XHJcblxyXG5cdFx0bWF0ZXJpYWwuaXJpZGVzY2VuY2UgPSBzYXR1cmF0ZSggbWF0ZXJpYWwuaXJpZGVzY2VuY2UgKTtcclxuXHJcblx0fVxyXG5cclxuXHRpZiAoIG1hdGVyaWFsLmlyaWRlc2NlbmNlID4gMC4wICkge1xyXG5cclxuXHRcdG1hdGVyaWFsLmlyaWRlc2NlbmNlRnJlc25lbCA9IGV2YWxJcmlkZXNjZW5jZSggMS4wLCBtYXRlcmlhbC5pcmlkZXNjZW5jZUlPUiwgZG90TlZpLCBtYXRlcmlhbC5pcmlkZXNjZW5jZVRoaWNrbmVzcywgbWF0ZXJpYWwuc3BlY3VsYXJDb2xvciApO1xyXG5cclxuXHRcdC8vIElyaWRlc2NlbmNlIEYwIGFwcHJveGltYXRpb25cclxuXHRcdG1hdGVyaWFsLmlyaWRlc2NlbmNlRjAgPSBTY2hsaWNrX3RvX0YwKCBtYXRlcmlhbC5pcmlkZXNjZW5jZUZyZXNuZWwsIDEuMCwgZG90TlZpICk7XHJcblxyXG5cdH1cclxuXHJcbiNlbmRpZlxyXG5cclxuSW5jaWRlbnRMaWdodCBkaXJlY3RMaWdodDtcclxuXHJcbiNpZiAoIE5VTV9QT0lOVF9MSUdIVFMgPiAwICkgJiYgZGVmaW5lZCggUkVfRGlyZWN0IClcclxuXHJcblx0UG9pbnRMaWdodCBwb2ludExpZ2h0O1xyXG5cdCNpZiBkZWZpbmVkKCBVU0VfU0hBRE9XTUFQICkgJiYgTlVNX1BPSU5UX0xJR0hUX1NIQURPV1MgPiAwXHJcblx0UG9pbnRMaWdodFNoYWRvdyBwb2ludExpZ2h0U2hhZG93O1xyXG5cdCNlbmRpZlxyXG5cclxuXHQjcHJhZ21hIHVucm9sbF9sb29wX3N0YXJ0XHJcblx0Zm9yICggaW50IGkgPSAwOyBpIDwgTlVNX1BPSU5UX0xJR0hUUzsgaSArKyApIHtcclxuXHJcblx0XHRwb2ludExpZ2h0ID0gcG9pbnRMaWdodHNbIGkgXTtcclxuXHJcblx0XHRnZXRQb2ludExpZ2h0SW5mbyggcG9pbnRMaWdodCwgZ2VvbWV0cnlQb3NpdGlvbiwgZGlyZWN0TGlnaHQgKTtcclxuXHJcblx0XHQjaWYgZGVmaW5lZCggVVNFX1NIQURPV01BUCApICYmICggVU5ST0xMRURfTE9PUF9JTkRFWCA8IE5VTV9QT0lOVF9MSUdIVF9TSEFET1dTIClcclxuXHRcdHBvaW50TGlnaHRTaGFkb3cgPSBwb2ludExpZ2h0U2hhZG93c1sgaSBdO1xyXG5cdFx0ZGlyZWN0TGlnaHQuY29sb3IgKj0gKCBkaXJlY3RMaWdodC52aXNpYmxlICYmIHJlY2VpdmVTaGFkb3cgKSA/IGdldFBvaW50U2hhZG93KCBwb2ludFNoYWRvd01hcFsgaSBdLCBwb2ludExpZ2h0U2hhZG93LnNoYWRvd01hcFNpemUsIHBvaW50TGlnaHRTaGFkb3cuc2hhZG93QmlhcywgcG9pbnRMaWdodFNoYWRvdy5zaGFkb3dSYWRpdXMsIHZQb2ludFNoYWRvd0Nvb3JkWyBpIF0sIHBvaW50TGlnaHRTaGFkb3cuc2hhZG93Q2FtZXJhTmVhciwgcG9pbnRMaWdodFNoYWRvdy5zaGFkb3dDYW1lcmFGYXIgKSA6IDEuMDtcclxuXHRcdCNlbmRpZlxyXG5cclxuXHRcdFJFX0RpcmVjdCggZGlyZWN0TGlnaHQsIGdlb21ldHJ5UG9zaXRpb24sIGdlb21ldHJ5Tm9ybWFsLCBnZW9tZXRyeVZpZXdEaXIsIGdlb21ldHJ5Q2xlYXJjb2F0Tm9ybWFsLCBtYXRlcmlhbCwgcmVmbGVjdGVkTGlnaHQgKTtcclxuXHJcblx0fVxyXG5cdCNwcmFnbWEgdW5yb2xsX2xvb3BfZW5kXHJcblxyXG4jZW5kaWZcclxuXHJcbiNpZiAoIE5VTV9TUE9UX0xJR0hUUyA+IDAgKSAmJiBkZWZpbmVkKCBSRV9EaXJlY3QgKVxyXG5cclxuXHRTcG90TGlnaHQgc3BvdExpZ2h0O1xyXG5cdHZlYzQgc3BvdENvbG9yO1xyXG5cdHZlYzMgc3BvdExpZ2h0Q29vcmQ7XHJcblx0Ym9vbCBpblNwb3RMaWdodE1hcDtcclxuXHJcblx0I2lmIGRlZmluZWQoIFVTRV9TSEFET1dNQVAgKSAmJiBOVU1fU1BPVF9MSUdIVF9TSEFET1dTID4gMFxyXG5cdFNwb3RMaWdodFNoYWRvdyBzcG90TGlnaHRTaGFkb3c7XHJcblx0I2VuZGlmXHJcblxyXG5cdCNwcmFnbWEgdW5yb2xsX2xvb3Bfc3RhcnRcclxuXHRmb3IgKCBpbnQgaSA9IDA7IGkgPCBOVU1fU1BPVF9MSUdIVFM7IGkgKysgKSB7XHJcblxyXG5cdFx0c3BvdExpZ2h0ID0gc3BvdExpZ2h0c1sgaSBdO1xyXG5cclxuXHRcdGdldFNwb3RMaWdodEluZm8oIHNwb3RMaWdodCwgZ2VvbWV0cnlQb3NpdGlvbiwgZGlyZWN0TGlnaHQgKTtcclxuXHJcblx0XHQvLyBzcG90IGxpZ2h0cyBhcmUgb3JkZXJlZCBbc2hhZG93cyB3aXRoIG1hcHMsIHNoYWRvd3Mgd2l0aG91dCBtYXBzLCBtYXBzIHdpdGhvdXQgc2hhZG93cywgbm9uZV1cclxuXHRcdCNpZiAoIFVOUk9MTEVEX0xPT1BfSU5ERVggPCBOVU1fU1BPVF9MSUdIVF9TSEFET1dTX1dJVEhfTUFQUyApXHJcblx0XHQjZGVmaW5lIFNQT1RfTElHSFRfTUFQX0lOREVYIFVOUk9MTEVEX0xPT1BfSU5ERVhcclxuXHRcdCNlbGlmICggVU5ST0xMRURfTE9PUF9JTkRFWCA8IE5VTV9TUE9UX0xJR0hUX1NIQURPV1MgKVxyXG5cdFx0I2RlZmluZSBTUE9UX0xJR0hUX01BUF9JTkRFWCBOVU1fU1BPVF9MSUdIVF9NQVBTXHJcblx0XHQjZWxzZVxyXG5cdFx0I2RlZmluZSBTUE9UX0xJR0hUX01BUF9JTkRFWCAoIFVOUk9MTEVEX0xPT1BfSU5ERVggLSBOVU1fU1BPVF9MSUdIVF9TSEFET1dTICsgTlVNX1NQT1RfTElHSFRfU0hBRE9XU19XSVRIX01BUFMgKVxyXG5cdFx0I2VuZGlmXHJcblxyXG5cdFx0I2lmICggU1BPVF9MSUdIVF9NQVBfSU5ERVggPCBOVU1fU1BPVF9MSUdIVF9NQVBTIClcclxuXHRcdFx0c3BvdExpZ2h0Q29vcmQgPSB2U3BvdExpZ2h0Q29vcmRbIGkgXS54eXogLyB2U3BvdExpZ2h0Q29vcmRbIGkgXS53O1xyXG5cdFx0XHRpblNwb3RMaWdodE1hcCA9IGFsbCggbGVzc1RoYW4oIGFicyggc3BvdExpZ2h0Q29vcmQgKiAyLiAtIDEuICksIHZlYzMoIDEuMCApICkgKTtcclxuXHRcdFx0c3BvdENvbG9yID0gdGV4dHVyZTJEKCBzcG90TGlnaHRNYXBbIFNQT1RfTElHSFRfTUFQX0lOREVYIF0sIHNwb3RMaWdodENvb3JkLnh5ICk7XHJcblx0XHRcdGRpcmVjdExpZ2h0LmNvbG9yID0gaW5TcG90TGlnaHRNYXAgPyBkaXJlY3RMaWdodC5jb2xvciAqIHNwb3RDb2xvci5yZ2IgOiBkaXJlY3RMaWdodC5jb2xvcjtcclxuXHRcdCNlbmRpZlxyXG5cclxuXHRcdCN1bmRlZiBTUE9UX0xJR0hUX01BUF9JTkRFWFxyXG5cclxuXHRcdCNpZiBkZWZpbmVkKCBVU0VfU0hBRE9XTUFQICkgJiYgKCBVTlJPTExFRF9MT09QX0lOREVYIDwgTlVNX1NQT1RfTElHSFRfU0hBRE9XUyApXHJcblx0XHRzcG90TGlnaHRTaGFkb3cgPSBzcG90TGlnaHRTaGFkb3dzWyBpIF07XHJcblx0XHRkaXJlY3RMaWdodC5jb2xvciAqPSAoIGRpcmVjdExpZ2h0LnZpc2libGUgJiYgcmVjZWl2ZVNoYWRvdyApID8gZ2V0U2hhZG93KCBzcG90U2hhZG93TWFwWyBpIF0sIHNwb3RMaWdodFNoYWRvdy5zaGFkb3dNYXBTaXplLCBzcG90TGlnaHRTaGFkb3cuc2hhZG93Qmlhcywgc3BvdExpZ2h0U2hhZG93LnNoYWRvd1JhZGl1cywgdlNwb3RMaWdodENvb3JkWyBpIF0gKSA6IDEuMDtcclxuXHRcdCNlbmRpZlxyXG5cclxuXHRcdFJFX0RpcmVjdCggZGlyZWN0TGlnaHQsIGdlb21ldHJ5UG9zaXRpb24sIGdlb21ldHJ5Tm9ybWFsLCBnZW9tZXRyeVZpZXdEaXIsIGdlb21ldHJ5Q2xlYXJjb2F0Tm9ybWFsLCBtYXRlcmlhbCwgcmVmbGVjdGVkTGlnaHQgKTtcclxuXHJcblx0fVxyXG5cdCNwcmFnbWEgdW5yb2xsX2xvb3BfZW5kXHJcblxyXG4jZW5kaWZcclxuXHJcbiNpZiAoIE5VTV9ESVJfTElHSFRTID4gMCApICYmIGRlZmluZWQoIFJFX0RpcmVjdCApXHJcblxyXG5cdERpcmVjdGlvbmFsTGlnaHQgZGlyZWN0aW9uYWxMaWdodDtcclxuXHQjaWYgZGVmaW5lZCggVVNFX1NIQURPV01BUCApICYmIE5VTV9ESVJfTElHSFRfU0hBRE9XUyA+IDBcclxuXHREaXJlY3Rpb25hbExpZ2h0U2hhZG93IGRpcmVjdGlvbmFsTGlnaHRTaGFkb3c7XHJcblx0I2VuZGlmXHJcblxyXG5cdCNwcmFnbWEgdW5yb2xsX2xvb3Bfc3RhcnRcclxuXHRmb3IgKCBpbnQgaSA9IDA7IGkgPCBOVU1fRElSX0xJR0hUUzsgaSArKyApIHtcclxuXHJcblx0XHRkaXJlY3Rpb25hbExpZ2h0ID0gZGlyZWN0aW9uYWxMaWdodHNbIGkgXTtcclxuXHJcblx0XHRnZXREaXJlY3Rpb25hbExpZ2h0SW5mbyggZGlyZWN0aW9uYWxMaWdodCwgZGlyZWN0TGlnaHQgKTtcclxuXHJcblx0XHQjaWYgZGVmaW5lZCggVVNFX1NIQURPV01BUCApICYmICggVU5ST0xMRURfTE9PUF9JTkRFWCA8IE5VTV9ESVJfTElHSFRfU0hBRE9XUyApXHJcblx0XHRkaXJlY3Rpb25hbExpZ2h0U2hhZG93ID0gZGlyZWN0aW9uYWxMaWdodFNoYWRvd3NbIGkgXTtcclxuXHRcdGRpcmVjdExpZ2h0LmNvbG9yICo9ICggZGlyZWN0TGlnaHQudmlzaWJsZSAmJiByZWNlaXZlU2hhZG93ICkgPyBnZXRTaGFkb3coIGRpcmVjdGlvbmFsU2hhZG93TWFwWyBpIF0sIGRpcmVjdGlvbmFsTGlnaHRTaGFkb3cuc2hhZG93TWFwU2l6ZSwgZGlyZWN0aW9uYWxMaWdodFNoYWRvdy5zaGFkb3dCaWFzLCBkaXJlY3Rpb25hbExpZ2h0U2hhZG93LnNoYWRvd1JhZGl1cywgdkRpcmVjdGlvbmFsU2hhZG93Q29vcmRbIGkgXSApIDogMS4wO1xyXG5cdFx0I2VuZGlmXHJcblxyXG5cdFx0UkVfRGlyZWN0KCBkaXJlY3RMaWdodCwgZ2VvbWV0cnlQb3NpdGlvbiwgZ2VvbWV0cnlOb3JtYWwsIGdlb21ldHJ5Vmlld0RpciwgZ2VvbWV0cnlDbGVhcmNvYXROb3JtYWwsIG1hdGVyaWFsLCByZWZsZWN0ZWRMaWdodCApO1xyXG5cclxuXHR9XHJcblx0I3ByYWdtYSB1bnJvbGxfbG9vcF9lbmRcclxuXHJcbiNlbmRpZlxyXG5cclxuI2lmICggTlVNX1JFQ1RfQVJFQV9MSUdIVFMgPiAwICkgJiYgZGVmaW5lZCggUkVfRGlyZWN0X1JlY3RBcmVhIClcclxuXHJcblx0UmVjdEFyZWFMaWdodCByZWN0QXJlYUxpZ2h0O1xyXG5cclxuXHQjcHJhZ21hIHVucm9sbF9sb29wX3N0YXJ0XHJcblx0Zm9yICggaW50IGkgPSAwOyBpIDwgTlVNX1JFQ1RfQVJFQV9MSUdIVFM7IGkgKysgKSB7XHJcblxyXG5cdFx0cmVjdEFyZWFMaWdodCA9IHJlY3RBcmVhTGlnaHRzWyBpIF07XHJcblx0XHRSRV9EaXJlY3RfUmVjdEFyZWEoIHJlY3RBcmVhTGlnaHQsIGdlb21ldHJ5UG9zaXRpb24sIGdlb21ldHJ5Tm9ybWFsLCBnZW9tZXRyeVZpZXdEaXIsIGdlb21ldHJ5Q2xlYXJjb2F0Tm9ybWFsLCBtYXRlcmlhbCwgcmVmbGVjdGVkTGlnaHQgKTtcclxuXHJcblx0fVxyXG5cdCNwcmFnbWEgdW5yb2xsX2xvb3BfZW5kXHJcblxyXG4jZW5kaWZcclxuXHJcbiNpZiBkZWZpbmVkKCBSRV9JbmRpcmVjdERpZmZ1c2UgKVxyXG5cclxuXHR2ZWMzIGlibElycmFkaWFuY2UgPSB2ZWMzKCAwLjAgKTtcclxuXHJcblx0dmVjMyBpcnJhZGlhbmNlID0gZ2V0QW1iaWVudExpZ2h0SXJyYWRpYW5jZSggYW1iaWVudExpZ2h0Q29sb3IgKTtcclxuXHJcblx0I2lmIGRlZmluZWQoIFVTRV9MSUdIVF9QUk9CRVMgKVxyXG5cclxuXHRcdGlycmFkaWFuY2UgKz0gZ2V0TGlnaHRQcm9iZUlycmFkaWFuY2UoIGxpZ2h0UHJvYmUsIGdlb21ldHJ5Tm9ybWFsICk7XHJcblxyXG5cdCNlbmRpZlxyXG5cclxuXHQjaWYgKCBOVU1fSEVNSV9MSUdIVFMgPiAwIClcclxuXHJcblx0XHQjcHJhZ21hIHVucm9sbF9sb29wX3N0YXJ0XHJcblx0XHRmb3IgKCBpbnQgaSA9IDA7IGkgPCBOVU1fSEVNSV9MSUdIVFM7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRpcnJhZGlhbmNlICs9IGdldEhlbWlzcGhlcmVMaWdodElycmFkaWFuY2UoIGhlbWlzcGhlcmVMaWdodHNbIGkgXSwgZ2VvbWV0cnlOb3JtYWwgKTtcclxuXHJcblx0XHR9XHJcblx0XHQjcHJhZ21hIHVucm9sbF9sb29wX2VuZFxyXG5cclxuXHQjZW5kaWZcclxuXHJcbiNlbmRpZlxyXG5cclxuI2lmIGRlZmluZWQoIFJFX0luZGlyZWN0U3BlY3VsYXIgKVxyXG5cclxuXHR2ZWMzIHJhZGlhbmNlID0gdmVjMyggMC4wICk7XHJcblx0dmVjMyBjbGVhcmNvYXRSYWRpYW5jZSA9IHZlYzMoIDAuMCApO1xyXG5cclxuI2VuZGlmXHJcbmA7XHJcbiIsImV4cG9ydCBkZWZhdWx0IC8qIGdsc2wgKi9gXHJcbiNpZiBkZWZpbmVkKCBSRV9JbmRpcmVjdERpZmZ1c2UgKVxyXG5cclxuXHQjaWZkZWYgVVNFX0xJR0hUTUFQXHJcblxyXG5cdFx0dmVjNCBsaWdodE1hcFRleGVsID0gdGV4dHVyZTJEKCBsaWdodE1hcCwgdkxpZ2h0TWFwVXYgKTtcclxuXHRcdHZlYzMgbGlnaHRNYXBJcnJhZGlhbmNlID0gbGlnaHRNYXBUZXhlbC5yZ2IgKiBsaWdodE1hcEludGVuc2l0eTtcclxuXHJcblx0XHRpcnJhZGlhbmNlICs9IGxpZ2h0TWFwSXJyYWRpYW5jZTtcclxuXHJcblx0I2VuZGlmXHJcblxyXG5cdCNpZiBkZWZpbmVkKCBVU0VfRU5WTUFQICkgJiYgZGVmaW5lZCggU1RBTkRBUkQgKSAmJiBkZWZpbmVkKCBFTlZNQVBfVFlQRV9DVUJFX1VWIClcclxuXHJcblx0XHRpYmxJcnJhZGlhbmNlICs9IGdldElCTElycmFkaWFuY2UoIGdlb21ldHJ5Tm9ybWFsICk7XHJcblxyXG5cdCNlbmRpZlxyXG5cclxuI2VuZGlmXHJcblxyXG4jaWYgZGVmaW5lZCggVVNFX0VOVk1BUCApICYmIGRlZmluZWQoIFJFX0luZGlyZWN0U3BlY3VsYXIgKVxyXG5cclxuXHQjaWZkZWYgVVNFX0FOSVNPVFJPUFlcclxuXHJcblx0XHRyYWRpYW5jZSArPSBnZXRJQkxBbmlzb3Ryb3B5UmFkaWFuY2UoIGdlb21ldHJ5Vmlld0RpciwgZ2VvbWV0cnlOb3JtYWwsIG1hdGVyaWFsLnJvdWdobmVzcywgbWF0ZXJpYWwuYW5pc290cm9weUIsIG1hdGVyaWFsLmFuaXNvdHJvcHkgKTtcclxuXHJcblx0I2Vsc2VcclxuXHJcblx0XHRyYWRpYW5jZSArPSBnZXRJQkxSYWRpYW5jZSggZ2VvbWV0cnlWaWV3RGlyLCBnZW9tZXRyeU5vcm1hbCwgbWF0ZXJpYWwucm91Z2huZXNzICk7XHJcblxyXG5cdCNlbmRpZlxyXG5cclxuXHQjaWZkZWYgVVNFX0NMRUFSQ09BVFxyXG5cclxuXHRcdGNsZWFyY29hdFJhZGlhbmNlICs9IGdldElCTFJhZGlhbmNlKCBnZW9tZXRyeVZpZXdEaXIsIGdlb21ldHJ5Q2xlYXJjb2F0Tm9ybWFsLCBtYXRlcmlhbC5jbGVhcmNvYXRSb3VnaG5lc3MgKTtcclxuXHJcblx0I2VuZGlmXHJcblxyXG4jZW5kaWZcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuI2lmIGRlZmluZWQoIFJFX0luZGlyZWN0RGlmZnVzZSApXHJcblxyXG5cdFJFX0luZGlyZWN0RGlmZnVzZSggaXJyYWRpYW5jZSwgZ2VvbWV0cnlQb3NpdGlvbiwgZ2VvbWV0cnlOb3JtYWwsIGdlb21ldHJ5Vmlld0RpciwgZ2VvbWV0cnlDbGVhcmNvYXROb3JtYWwsIG1hdGVyaWFsLCByZWZsZWN0ZWRMaWdodCApO1xyXG5cclxuI2VuZGlmXHJcblxyXG4jaWYgZGVmaW5lZCggUkVfSW5kaXJlY3RTcGVjdWxhciApXHJcblxyXG5cdFJFX0luZGlyZWN0U3BlY3VsYXIoIHJhZGlhbmNlLCBpYmxJcnJhZGlhbmNlLCBjbGVhcmNvYXRSYWRpYW5jZSwgZ2VvbWV0cnlQb3NpdGlvbiwgZ2VvbWV0cnlOb3JtYWwsIGdlb21ldHJ5Vmlld0RpciwgZ2VvbWV0cnlDbGVhcmNvYXROb3JtYWwsIG1hdGVyaWFsLCByZWZsZWN0ZWRMaWdodCApO1xyXG5cclxuI2VuZGlmXHJcbmA7XHJcbiIsImV4cG9ydCBkZWZhdWx0IC8qIGdsc2wgKi9gXHJcbiNpZiBkZWZpbmVkKCBVU0VfTE9HREVQVEhCVUYgKSAmJiBkZWZpbmVkKCBVU0VfTE9HREVQVEhCVUZfRVhUIClcclxuXHJcblx0Ly8gRG9pbmcgYSBzdHJpY3QgY29tcGFyaXNvbiB3aXRoID09IDEuMCBjYW4gY2F1c2Ugbm9pc2UgYXJ0aWZhY3RzXHJcblx0Ly8gb24gc29tZSBwbGF0Zm9ybXMuIFNlZSBpc3N1ZSAjMTc2MjMuXHJcblx0Z2xfRnJhZ0RlcHRoRVhUID0gdklzUGVyc3BlY3RpdmUgPT0gMC4wID8gZ2xfRnJhZ0Nvb3JkLnogOiBsb2cyKCB2RnJhZ0RlcHRoICkgKiBsb2dEZXB0aEJ1ZkZDICogMC41O1xyXG5cclxuI2VuZGlmXHJcbmA7XHJcbiIsImV4cG9ydCBkZWZhdWx0IC8qIGdsc2wgKi9gXHJcbiNpZiBkZWZpbmVkKCBVU0VfTE9HREVQVEhCVUYgKSAmJiBkZWZpbmVkKCBVU0VfTE9HREVQVEhCVUZfRVhUIClcclxuXHJcblx0dW5pZm9ybSBmbG9hdCBsb2dEZXB0aEJ1ZkZDO1xyXG5cdHZhcnlpbmcgZmxvYXQgdkZyYWdEZXB0aDtcclxuXHR2YXJ5aW5nIGZsb2F0IHZJc1BlcnNwZWN0aXZlO1xyXG5cclxuI2VuZGlmXHJcbmA7XHJcbiIsImV4cG9ydCBkZWZhdWx0IC8qIGdsc2wgKi9gXHJcbiNpZmRlZiBVU0VfTE9HREVQVEhCVUZcclxuXHJcblx0I2lmZGVmIFVTRV9MT0dERVBUSEJVRl9FWFRcclxuXHJcblx0XHR2YXJ5aW5nIGZsb2F0IHZGcmFnRGVwdGg7XHJcblx0XHR2YXJ5aW5nIGZsb2F0IHZJc1BlcnNwZWN0aXZlO1xyXG5cclxuXHQjZWxzZVxyXG5cclxuXHRcdHVuaWZvcm0gZmxvYXQgbG9nRGVwdGhCdWZGQztcclxuXHJcblx0I2VuZGlmXHJcblxyXG4jZW5kaWZcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuI2lmZGVmIFVTRV9MT0dERVBUSEJVRlxyXG5cclxuXHQjaWZkZWYgVVNFX0xPR0RFUFRIQlVGX0VYVFxyXG5cclxuXHRcdHZGcmFnRGVwdGggPSAxLjAgKyBnbF9Qb3NpdGlvbi53O1xyXG5cdFx0dklzUGVyc3BlY3RpdmUgPSBmbG9hdCggaXNQZXJzcGVjdGl2ZU1hdHJpeCggcHJvamVjdGlvbk1hdHJpeCApICk7XHJcblxyXG5cdCNlbHNlXHJcblxyXG5cdFx0aWYgKCBpc1BlcnNwZWN0aXZlTWF0cml4KCBwcm9qZWN0aW9uTWF0cml4ICkgKSB7XHJcblxyXG5cdFx0XHRnbF9Qb3NpdGlvbi56ID0gbG9nMiggbWF4KCBFUFNJTE9OLCBnbF9Qb3NpdGlvbi53ICsgMS4wICkgKSAqIGxvZ0RlcHRoQnVmRkMgLSAxLjA7XHJcblxyXG5cdFx0XHRnbF9Qb3NpdGlvbi56ICo9IGdsX1Bvc2l0aW9uLnc7XHJcblxyXG5cdFx0fVxyXG5cclxuXHQjZW5kaWZcclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWZkZWYgVVNFX01BUFxyXG5cclxuXHR2ZWM0IHNhbXBsZWREaWZmdXNlQ29sb3IgPSB0ZXh0dXJlMkQoIG1hcCwgdk1hcFV2ICk7XHJcblxyXG5cdCNpZmRlZiBERUNPREVfVklERU9fVEVYVFVSRVxyXG5cclxuXHRcdC8vIHVzZSBpbmxpbmUgc1JHQiBkZWNvZGUgdW50aWwgYnJvd3NlcnMgcHJvcGVybHkgc3VwcG9ydCBTUkdCOF9BUExIQTggd2l0aCB2aWRlbyB0ZXh0dXJlc1xyXG5cclxuXHRcdHNhbXBsZWREaWZmdXNlQ29sb3IgPSB2ZWM0KCBtaXgoIHBvdyggc2FtcGxlZERpZmZ1c2VDb2xvci5yZ2IgKiAwLjk0Nzg2NzI5ODYgKyB2ZWMzKCAwLjA1MjEzMjcwMTQgKSwgdmVjMyggMi40ICkgKSwgc2FtcGxlZERpZmZ1c2VDb2xvci5yZ2IgKiAwLjA3NzM5OTM4MDgsIHZlYzMoIGxlc3NUaGFuRXF1YWwoIHNhbXBsZWREaWZmdXNlQ29sb3IucmdiLCB2ZWMzKCAwLjA0MDQ1ICkgKSApICksIHNhbXBsZWREaWZmdXNlQ29sb3IudyApO1xyXG5cdFxyXG5cdCNlbmRpZlxyXG5cclxuXHRkaWZmdXNlQ29sb3IgKj0gc2FtcGxlZERpZmZ1c2VDb2xvcjtcclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWZkZWYgVVNFX01BUFxyXG5cclxuXHR1bmlmb3JtIHNhbXBsZXIyRCBtYXA7XHJcblxyXG4jZW5kaWZcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuI2lmIGRlZmluZWQoIFVTRV9NQVAgKSB8fCBkZWZpbmVkKCBVU0VfQUxQSEFNQVAgKVxyXG5cclxuXHQjaWYgZGVmaW5lZCggVVNFX1BPSU5UU19VViApXHJcblxyXG5cdFx0dmVjMiB1diA9IHZVdjtcclxuXHJcblx0I2Vsc2VcclxuXHJcblx0XHR2ZWMyIHV2ID0gKCB1dlRyYW5zZm9ybSAqIHZlYzMoIGdsX1BvaW50Q29vcmQueCwgMS4wIC0gZ2xfUG9pbnRDb29yZC55LCAxICkgKS54eTtcclxuXHJcblx0I2VuZGlmXHJcblxyXG4jZW5kaWZcclxuXHJcbiNpZmRlZiBVU0VfTUFQXHJcblxyXG5cdGRpZmZ1c2VDb2xvciAqPSB0ZXh0dXJlMkQoIG1hcCwgdXYgKTtcclxuXHJcbiNlbmRpZlxyXG5cclxuI2lmZGVmIFVTRV9BTFBIQU1BUFxyXG5cclxuXHRkaWZmdXNlQ29sb3IuYSAqPSB0ZXh0dXJlMkQoIGFscGhhTWFwLCB1diApLmc7XHJcblxyXG4jZW5kaWZcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuI2lmIGRlZmluZWQoIFVTRV9QT0lOVFNfVVYgKVxyXG5cclxuXHR2YXJ5aW5nIHZlYzIgdlV2O1xyXG5cclxuI2Vsc2VcclxuXHJcblx0I2lmIGRlZmluZWQoIFVTRV9NQVAgKSB8fCBkZWZpbmVkKCBVU0VfQUxQSEFNQVAgKVxyXG5cclxuXHRcdHVuaWZvcm0gbWF0MyB1dlRyYW5zZm9ybTtcclxuXHJcblx0I2VuZGlmXHJcblxyXG4jZW5kaWZcclxuXHJcbiNpZmRlZiBVU0VfTUFQXHJcblxyXG5cdHVuaWZvcm0gc2FtcGxlcjJEIG1hcDtcclxuXHJcbiNlbmRpZlxyXG5cclxuI2lmZGVmIFVTRV9BTFBIQU1BUFxyXG5cclxuXHR1bmlmb3JtIHNhbXBsZXIyRCBhbHBoYU1hcDtcclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG5mbG9hdCBtZXRhbG5lc3NGYWN0b3IgPSBtZXRhbG5lc3M7XHJcblxyXG4jaWZkZWYgVVNFX01FVEFMTkVTU01BUFxyXG5cclxuXHR2ZWM0IHRleGVsTWV0YWxuZXNzID0gdGV4dHVyZTJEKCBtZXRhbG5lc3NNYXAsIHZNZXRhbG5lc3NNYXBVdiApO1xyXG5cclxuXHQvLyByZWFkcyBjaGFubmVsIEIsIGNvbXBhdGlibGUgd2l0aCBhIGNvbWJpbmVkIE9jY2x1c2lvblJvdWdobmVzc01ldGFsbGljIChSR0IpIHRleHR1cmVcclxuXHRtZXRhbG5lc3NGYWN0b3IgKj0gdGV4ZWxNZXRhbG5lc3MuYjtcclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWZkZWYgVVNFX01FVEFMTkVTU01BUFxyXG5cclxuXHR1bmlmb3JtIHNhbXBsZXIyRCBtZXRhbG5lc3NNYXA7XHJcblxyXG4jZW5kaWZcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuI2lmIGRlZmluZWQoIFVTRV9NT1JQSENPTE9SUyApICYmIGRlZmluZWQoIE1PUlBIVEFSR0VUU19URVhUVVJFIClcclxuXHJcblx0Ly8gbW9ycGhUYXJnZXRCYXNlSW5mbHVlbmNlIGlzIHNldCBiYXNlZCBvbiBCdWZmZXJHZW9tZXRyeS5tb3JwaFRhcmdldHNSZWxhdGl2ZSB2YWx1ZTpcclxuXHQvLyBXaGVuIG1vcnBoVGFyZ2V0c1JlbGF0aXZlIGlzIGZhbHNlLCB0aGlzIGlzIHNldCB0byAxIC0gc3VtKGluZmx1ZW5jZXMpOyB0aGlzIHJlc3VsdHMgaW4gbm9ybWFsID0gc3VtKCh0YXJnZXQgLSBiYXNlKSAqIGluZmx1ZW5jZSlcclxuXHQvLyBXaGVuIG1vcnBoVGFyZ2V0c1JlbGF0aXZlIGlzIHRydWUsIHRoaXMgaXMgc2V0IHRvIDE7IGFzIGEgcmVzdWx0LCBhbGwgbW9ycGggdGFyZ2V0cyBhcmUgc2ltcGx5IGFkZGVkIHRvIHRoZSBiYXNlIGFmdGVyIHdlaWdodGluZ1xyXG5cdHZDb2xvciAqPSBtb3JwaFRhcmdldEJhc2VJbmZsdWVuY2U7XHJcblxyXG5cdGZvciAoIGludCBpID0gMDsgaSA8IE1PUlBIVEFSR0VUU19DT1VOVDsgaSArKyApIHtcclxuXHJcblx0XHQjaWYgZGVmaW5lZCggVVNFX0NPTE9SX0FMUEhBIClcclxuXHJcblx0XHRcdGlmICggbW9ycGhUYXJnZXRJbmZsdWVuY2VzWyBpIF0gIT0gMC4wICkgdkNvbG9yICs9IGdldE1vcnBoKCBnbF9WZXJ0ZXhJRCwgaSwgMiApICogbW9ycGhUYXJnZXRJbmZsdWVuY2VzWyBpIF07XHJcblxyXG5cdFx0I2VsaWYgZGVmaW5lZCggVVNFX0NPTE9SIClcclxuXHJcblx0XHRcdGlmICggbW9ycGhUYXJnZXRJbmZsdWVuY2VzWyBpIF0gIT0gMC4wICkgdkNvbG9yICs9IGdldE1vcnBoKCBnbF9WZXJ0ZXhJRCwgaSwgMiApLnJnYiAqIG1vcnBoVGFyZ2V0SW5mbHVlbmNlc1sgaSBdO1xyXG5cclxuXHRcdCNlbmRpZlxyXG5cclxuXHR9XHJcblxyXG4jZW5kaWZcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuI2lmZGVmIFVTRV9NT1JQSE5PUk1BTFNcclxuXHJcblx0Ly8gbW9ycGhUYXJnZXRCYXNlSW5mbHVlbmNlIGlzIHNldCBiYXNlZCBvbiBCdWZmZXJHZW9tZXRyeS5tb3JwaFRhcmdldHNSZWxhdGl2ZSB2YWx1ZTpcclxuXHQvLyBXaGVuIG1vcnBoVGFyZ2V0c1JlbGF0aXZlIGlzIGZhbHNlLCB0aGlzIGlzIHNldCB0byAxIC0gc3VtKGluZmx1ZW5jZXMpOyB0aGlzIHJlc3VsdHMgaW4gbm9ybWFsID0gc3VtKCh0YXJnZXQgLSBiYXNlKSAqIGluZmx1ZW5jZSlcclxuXHQvLyBXaGVuIG1vcnBoVGFyZ2V0c1JlbGF0aXZlIGlzIHRydWUsIHRoaXMgaXMgc2V0IHRvIDE7IGFzIGEgcmVzdWx0LCBhbGwgbW9ycGggdGFyZ2V0cyBhcmUgc2ltcGx5IGFkZGVkIHRvIHRoZSBiYXNlIGFmdGVyIHdlaWdodGluZ1xyXG5cdG9iamVjdE5vcm1hbCAqPSBtb3JwaFRhcmdldEJhc2VJbmZsdWVuY2U7XHJcblxyXG5cdCNpZmRlZiBNT1JQSFRBUkdFVFNfVEVYVFVSRVxyXG5cclxuXHRcdGZvciAoIGludCBpID0gMDsgaSA8IE1PUlBIVEFSR0VUU19DT1VOVDsgaSArKyApIHtcclxuXHJcblx0XHRcdGlmICggbW9ycGhUYXJnZXRJbmZsdWVuY2VzWyBpIF0gIT0gMC4wICkgb2JqZWN0Tm9ybWFsICs9IGdldE1vcnBoKCBnbF9WZXJ0ZXhJRCwgaSwgMSApLnh5eiAqIG1vcnBoVGFyZ2V0SW5mbHVlbmNlc1sgaSBdO1xyXG5cclxuXHRcdH1cclxuXHJcblx0I2Vsc2VcclxuXHJcblx0XHRvYmplY3ROb3JtYWwgKz0gbW9ycGhOb3JtYWwwICogbW9ycGhUYXJnZXRJbmZsdWVuY2VzWyAwIF07XHJcblx0XHRvYmplY3ROb3JtYWwgKz0gbW9ycGhOb3JtYWwxICogbW9ycGhUYXJnZXRJbmZsdWVuY2VzWyAxIF07XHJcblx0XHRvYmplY3ROb3JtYWwgKz0gbW9ycGhOb3JtYWwyICogbW9ycGhUYXJnZXRJbmZsdWVuY2VzWyAyIF07XHJcblx0XHRvYmplY3ROb3JtYWwgKz0gbW9ycGhOb3JtYWwzICogbW9ycGhUYXJnZXRJbmZsdWVuY2VzWyAzIF07XHJcblxyXG5cdCNlbmRpZlxyXG5cclxuI2VuZGlmXHJcbmA7XHJcbiIsImV4cG9ydCBkZWZhdWx0IC8qIGdsc2wgKi9gXHJcbiNpZmRlZiBVU0VfTU9SUEhUQVJHRVRTXHJcblxyXG5cdHVuaWZvcm0gZmxvYXQgbW9ycGhUYXJnZXRCYXNlSW5mbHVlbmNlO1xyXG5cclxuXHQjaWZkZWYgTU9SUEhUQVJHRVRTX1RFWFRVUkVcclxuXHJcblx0XHR1bmlmb3JtIGZsb2F0IG1vcnBoVGFyZ2V0SW5mbHVlbmNlc1sgTU9SUEhUQVJHRVRTX0NPVU5UIF07XHJcblx0XHR1bmlmb3JtIHNhbXBsZXIyREFycmF5IG1vcnBoVGFyZ2V0c1RleHR1cmU7XHJcblx0XHR1bmlmb3JtIGl2ZWMyIG1vcnBoVGFyZ2V0c1RleHR1cmVTaXplO1xyXG5cclxuXHRcdHZlYzQgZ2V0TW9ycGgoIGNvbnN0IGluIGludCB2ZXJ0ZXhJbmRleCwgY29uc3QgaW4gaW50IG1vcnBoVGFyZ2V0SW5kZXgsIGNvbnN0IGluIGludCBvZmZzZXQgKSB7XHJcblxyXG5cdFx0XHRpbnQgdGV4ZWxJbmRleCA9IHZlcnRleEluZGV4ICogTU9SUEhUQVJHRVRTX1RFWFRVUkVfU1RSSURFICsgb2Zmc2V0O1xyXG5cdFx0XHRpbnQgeSA9IHRleGVsSW5kZXggLyBtb3JwaFRhcmdldHNUZXh0dXJlU2l6ZS54O1xyXG5cdFx0XHRpbnQgeCA9IHRleGVsSW5kZXggLSB5ICogbW9ycGhUYXJnZXRzVGV4dHVyZVNpemUueDtcclxuXHJcblx0XHRcdGl2ZWMzIG1vcnBoVVYgPSBpdmVjMyggeCwgeSwgbW9ycGhUYXJnZXRJbmRleCApO1xyXG5cdFx0XHRyZXR1cm4gdGV4ZWxGZXRjaCggbW9ycGhUYXJnZXRzVGV4dHVyZSwgbW9ycGhVViwgMCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0I2Vsc2VcclxuXHJcblx0XHQjaWZuZGVmIFVTRV9NT1JQSE5PUk1BTFNcclxuXHJcblx0XHRcdHVuaWZvcm0gZmxvYXQgbW9ycGhUYXJnZXRJbmZsdWVuY2VzWyA4IF07XHJcblxyXG5cdFx0I2Vsc2VcclxuXHJcblx0XHRcdHVuaWZvcm0gZmxvYXQgbW9ycGhUYXJnZXRJbmZsdWVuY2VzWyA0IF07XHJcblxyXG5cdFx0I2VuZGlmXHJcblxyXG5cdCNlbmRpZlxyXG5cclxuI2VuZGlmXHJcbmA7XHJcbiIsImV4cG9ydCBkZWZhdWx0IC8qIGdsc2wgKi9gXHJcbiNpZmRlZiBVU0VfTU9SUEhUQVJHRVRTXHJcblxyXG5cdC8vIG1vcnBoVGFyZ2V0QmFzZUluZmx1ZW5jZSBpcyBzZXQgYmFzZWQgb24gQnVmZmVyR2VvbWV0cnkubW9ycGhUYXJnZXRzUmVsYXRpdmUgdmFsdWU6XHJcblx0Ly8gV2hlbiBtb3JwaFRhcmdldHNSZWxhdGl2ZSBpcyBmYWxzZSwgdGhpcyBpcyBzZXQgdG8gMSAtIHN1bShpbmZsdWVuY2VzKTsgdGhpcyByZXN1bHRzIGluIHBvc2l0aW9uID0gc3VtKCh0YXJnZXQgLSBiYXNlKSAqIGluZmx1ZW5jZSlcclxuXHQvLyBXaGVuIG1vcnBoVGFyZ2V0c1JlbGF0aXZlIGlzIHRydWUsIHRoaXMgaXMgc2V0IHRvIDE7IGFzIGEgcmVzdWx0LCBhbGwgbW9ycGggdGFyZ2V0cyBhcmUgc2ltcGx5IGFkZGVkIHRvIHRoZSBiYXNlIGFmdGVyIHdlaWdodGluZ1xyXG5cdHRyYW5zZm9ybWVkICo9IG1vcnBoVGFyZ2V0QmFzZUluZmx1ZW5jZTtcclxuXHJcblx0I2lmZGVmIE1PUlBIVEFSR0VUU19URVhUVVJFXHJcblxyXG5cdFx0Zm9yICggaW50IGkgPSAwOyBpIDwgTU9SUEhUQVJHRVRTX0NPVU5UOyBpICsrICkge1xyXG5cclxuXHRcdFx0aWYgKCBtb3JwaFRhcmdldEluZmx1ZW5jZXNbIGkgXSAhPSAwLjAgKSB0cmFuc2Zvcm1lZCArPSBnZXRNb3JwaCggZ2xfVmVydGV4SUQsIGksIDAgKS54eXogKiBtb3JwaFRhcmdldEluZmx1ZW5jZXNbIGkgXTtcclxuXHJcblx0XHR9XHJcblxyXG5cdCNlbHNlXHJcblxyXG5cdFx0dHJhbnNmb3JtZWQgKz0gbW9ycGhUYXJnZXQwICogbW9ycGhUYXJnZXRJbmZsdWVuY2VzWyAwIF07XHJcblx0XHR0cmFuc2Zvcm1lZCArPSBtb3JwaFRhcmdldDEgKiBtb3JwaFRhcmdldEluZmx1ZW5jZXNbIDEgXTtcclxuXHRcdHRyYW5zZm9ybWVkICs9IG1vcnBoVGFyZ2V0MiAqIG1vcnBoVGFyZ2V0SW5mbHVlbmNlc1sgMiBdO1xyXG5cdFx0dHJhbnNmb3JtZWQgKz0gbW9ycGhUYXJnZXQzICogbW9ycGhUYXJnZXRJbmZsdWVuY2VzWyAzIF07XHJcblxyXG5cdFx0I2lmbmRlZiBVU0VfTU9SUEhOT1JNQUxTXHJcblxyXG5cdFx0XHR0cmFuc2Zvcm1lZCArPSBtb3JwaFRhcmdldDQgKiBtb3JwaFRhcmdldEluZmx1ZW5jZXNbIDQgXTtcclxuXHRcdFx0dHJhbnNmb3JtZWQgKz0gbW9ycGhUYXJnZXQ1ICogbW9ycGhUYXJnZXRJbmZsdWVuY2VzWyA1IF07XHJcblx0XHRcdHRyYW5zZm9ybWVkICs9IG1vcnBoVGFyZ2V0NiAqIG1vcnBoVGFyZ2V0SW5mbHVlbmNlc1sgNiBdO1xyXG5cdFx0XHR0cmFuc2Zvcm1lZCArPSBtb3JwaFRhcmdldDcgKiBtb3JwaFRhcmdldEluZmx1ZW5jZXNbIDcgXTtcclxuXHJcblx0XHQjZW5kaWZcclxuXHJcblx0I2VuZGlmXHJcblxyXG4jZW5kaWZcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuZmxvYXQgZmFjZURpcmVjdGlvbiA9IGdsX0Zyb250RmFjaW5nID8gMS4wIDogLSAxLjA7XHJcblxyXG4jaWZkZWYgRkxBVF9TSEFERURcclxuXHJcblx0dmVjMyBmZHggPSBkRmR4KCB2Vmlld1Bvc2l0aW9uICk7XHJcblx0dmVjMyBmZHkgPSBkRmR5KCB2Vmlld1Bvc2l0aW9uICk7XHJcblx0dmVjMyBub3JtYWwgPSBub3JtYWxpemUoIGNyb3NzKCBmZHgsIGZkeSApICk7XHJcblxyXG4jZWxzZVxyXG5cclxuXHR2ZWMzIG5vcm1hbCA9IG5vcm1hbGl6ZSggdk5vcm1hbCApO1xyXG5cclxuXHQjaWZkZWYgRE9VQkxFX1NJREVEXHJcblxyXG5cdFx0bm9ybWFsICo9IGZhY2VEaXJlY3Rpb247XHJcblxyXG5cdCNlbmRpZlxyXG5cclxuI2VuZGlmXHJcblxyXG4jaWYgZGVmaW5lZCggVVNFX05PUk1BTE1BUF9UQU5HRU5UU1BBQ0UgKSB8fCBkZWZpbmVkKCBVU0VfQ0xFQVJDT0FUX05PUk1BTE1BUCApIHx8IGRlZmluZWQoIFVTRV9BTklTT1RST1BZIClcclxuXHJcblx0I2lmZGVmIFVTRV9UQU5HRU5UXHJcblxyXG5cdFx0bWF0MyB0Ym4gPSBtYXQzKCBub3JtYWxpemUoIHZUYW5nZW50ICksIG5vcm1hbGl6ZSggdkJpdGFuZ2VudCApLCBub3JtYWwgKTtcclxuXHJcblx0I2Vsc2VcclxuXHJcblx0XHRtYXQzIHRibiA9IGdldFRhbmdlbnRGcmFtZSggLSB2Vmlld1Bvc2l0aW9uLCBub3JtYWwsXHJcblx0XHQjaWYgZGVmaW5lZCggVVNFX05PUk1BTE1BUCApXHJcblx0XHRcdHZOb3JtYWxNYXBVdlxyXG5cdFx0I2VsaWYgZGVmaW5lZCggVVNFX0NMRUFSQ09BVF9OT1JNQUxNQVAgKVxyXG5cdFx0XHR2Q2xlYXJjb2F0Tm9ybWFsTWFwVXZcclxuXHRcdCNlbHNlXHJcblx0XHRcdHZVdlxyXG5cdFx0I2VuZGlmXHJcblx0XHQpO1xyXG5cclxuXHQjZW5kaWZcclxuXHJcblx0I2lmIGRlZmluZWQoIERPVUJMRV9TSURFRCApICYmICEgZGVmaW5lZCggRkxBVF9TSEFERUQgKVxyXG5cclxuXHRcdHRiblswXSAqPSBmYWNlRGlyZWN0aW9uO1xyXG5cdFx0dGJuWzFdICo9IGZhY2VEaXJlY3Rpb247XHJcblxyXG5cdCNlbmRpZlxyXG5cclxuI2VuZGlmXHJcblxyXG4jaWZkZWYgVVNFX0NMRUFSQ09BVF9OT1JNQUxNQVBcclxuXHJcblx0I2lmZGVmIFVTRV9UQU5HRU5UXHJcblxyXG5cdFx0bWF0MyB0Ym4yID0gbWF0Myggbm9ybWFsaXplKCB2VGFuZ2VudCApLCBub3JtYWxpemUoIHZCaXRhbmdlbnQgKSwgbm9ybWFsICk7XHJcblxyXG5cdCNlbHNlXHJcblxyXG5cdFx0bWF0MyB0Ym4yID0gZ2V0VGFuZ2VudEZyYW1lKCAtIHZWaWV3UG9zaXRpb24sIG5vcm1hbCwgdkNsZWFyY29hdE5vcm1hbE1hcFV2ICk7XHJcblxyXG5cdCNlbmRpZlxyXG5cclxuXHQjaWYgZGVmaW5lZCggRE9VQkxFX1NJREVEICkgJiYgISBkZWZpbmVkKCBGTEFUX1NIQURFRCApXHJcblxyXG5cdFx0dGJuMlswXSAqPSBmYWNlRGlyZWN0aW9uO1xyXG5cdFx0dGJuMlsxXSAqPSBmYWNlRGlyZWN0aW9uO1xyXG5cclxuXHQjZW5kaWZcclxuXHJcbiNlbmRpZlxyXG5cclxuLy8gbm9uIHBlcnR1cmJlZCBub3JtYWwgZm9yIGNsZWFyY29hdCBhbW9uZyBvdGhlcnNcclxuXHJcbnZlYzMgbm9uUGVydHVyYmVkTm9ybWFsID0gbm9ybWFsO1xyXG5cclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuXHJcbiNpZmRlZiBVU0VfTk9STUFMTUFQX09CSkVDVFNQQUNFXHJcblxyXG5cdG5vcm1hbCA9IHRleHR1cmUyRCggbm9ybWFsTWFwLCB2Tm9ybWFsTWFwVXYgKS54eXogKiAyLjAgLSAxLjA7IC8vIG92ZXJyaWRlcyBib3RoIGZsYXRTaGFkaW5nIGFuZCBhdHRyaWJ1dGUgbm9ybWFsc1xyXG5cclxuXHQjaWZkZWYgRkxJUF9TSURFRFxyXG5cclxuXHRcdG5vcm1hbCA9IC0gbm9ybWFsO1xyXG5cclxuXHQjZW5kaWZcclxuXHJcblx0I2lmZGVmIERPVUJMRV9TSURFRFxyXG5cclxuXHRcdG5vcm1hbCA9IG5vcm1hbCAqIGZhY2VEaXJlY3Rpb247XHJcblxyXG5cdCNlbmRpZlxyXG5cclxuXHRub3JtYWwgPSBub3JtYWxpemUoIG5vcm1hbE1hdHJpeCAqIG5vcm1hbCApO1xyXG5cclxuI2VsaWYgZGVmaW5lZCggVVNFX05PUk1BTE1BUF9UQU5HRU5UU1BBQ0UgKVxyXG5cclxuXHR2ZWMzIG1hcE4gPSB0ZXh0dXJlMkQoIG5vcm1hbE1hcCwgdk5vcm1hbE1hcFV2ICkueHl6ICogMi4wIC0gMS4wO1xyXG5cdG1hcE4ueHkgKj0gbm9ybWFsU2NhbGU7XHJcblxyXG5cdG5vcm1hbCA9IG5vcm1hbGl6ZSggdGJuICogbWFwTiApO1xyXG5cclxuI2VsaWYgZGVmaW5lZCggVVNFX0JVTVBNQVAgKVxyXG5cclxuXHRub3JtYWwgPSBwZXJ0dXJiTm9ybWFsQXJiKCAtIHZWaWV3UG9zaXRpb24sIG5vcm1hbCwgZEhkeHlfZndkKCksIGZhY2VEaXJlY3Rpb24gKTtcclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWZuZGVmIEZMQVRfU0hBREVEXHJcblxyXG5cdHZhcnlpbmcgdmVjMyB2Tm9ybWFsO1xyXG5cclxuXHQjaWZkZWYgVVNFX1RBTkdFTlRcclxuXHJcblx0XHR2YXJ5aW5nIHZlYzMgdlRhbmdlbnQ7XHJcblx0XHR2YXJ5aW5nIHZlYzMgdkJpdGFuZ2VudDtcclxuXHJcblx0I2VuZGlmXHJcblxyXG4jZW5kaWZcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuI2lmbmRlZiBGTEFUX1NIQURFRFxyXG5cclxuXHR2YXJ5aW5nIHZlYzMgdk5vcm1hbDtcclxuXHJcblx0I2lmZGVmIFVTRV9UQU5HRU5UXHJcblxyXG5cdFx0dmFyeWluZyB2ZWMzIHZUYW5nZW50O1xyXG5cdFx0dmFyeWluZyB2ZWMzIHZCaXRhbmdlbnQ7XHJcblxyXG5cdCNlbmRpZlxyXG5cclxuI2VuZGlmXHJcbmA7XHJcbiIsImV4cG9ydCBkZWZhdWx0IC8qIGdsc2wgKi9gXHJcbiNpZm5kZWYgRkxBVF9TSEFERUQgLy8gbm9ybWFsIGlzIGNvbXB1dGVkIHdpdGggZGVyaXZhdGl2ZXMgd2hlbiBGTEFUX1NIQURFRFxyXG5cclxuXHR2Tm9ybWFsID0gbm9ybWFsaXplKCB0cmFuc2Zvcm1lZE5vcm1hbCApO1xyXG5cclxuXHQjaWZkZWYgVVNFX1RBTkdFTlRcclxuXHJcblx0XHR2VGFuZ2VudCA9IG5vcm1hbGl6ZSggdHJhbnNmb3JtZWRUYW5nZW50ICk7XHJcblx0XHR2Qml0YW5nZW50ID0gbm9ybWFsaXplKCBjcm9zcyggdk5vcm1hbCwgdlRhbmdlbnQgKSAqIHRhbmdlbnQudyApO1xyXG5cclxuXHQjZW5kaWZcclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWZkZWYgVVNFX05PUk1BTE1BUFxyXG5cclxuXHR1bmlmb3JtIHNhbXBsZXIyRCBub3JtYWxNYXA7XHJcblx0dW5pZm9ybSB2ZWMyIG5vcm1hbFNjYWxlO1xyXG5cclxuI2VuZGlmXHJcblxyXG4jaWZkZWYgVVNFX05PUk1BTE1BUF9PQkpFQ1RTUEFDRVxyXG5cclxuXHR1bmlmb3JtIG1hdDMgbm9ybWFsTWF0cml4O1xyXG5cclxuI2VuZGlmXHJcblxyXG4jaWYgISBkZWZpbmVkICggVVNFX1RBTkdFTlQgKSAmJiAoIGRlZmluZWQgKCBVU0VfTk9STUFMTUFQX1RBTkdFTlRTUEFDRSApIHx8IGRlZmluZWQgKCBVU0VfQ0xFQVJDT0FUX05PUk1BTE1BUCApIHx8IGRlZmluZWQoIFVTRV9BTklTT1RST1BZICkgKVxyXG5cclxuXHQvLyBOb3JtYWwgTWFwcGluZyBXaXRob3V0IFByZWNvbXB1dGVkIFRhbmdlbnRzXHJcblx0Ly8gaHR0cDovL3d3dy50aGV0ZW50aHBsYW5ldC5kZS9hcmNoaXZlcy8xMTgwXHJcblxyXG5cdG1hdDMgZ2V0VGFuZ2VudEZyYW1lKCB2ZWMzIGV5ZV9wb3MsIHZlYzMgc3VyZl9ub3JtLCB2ZWMyIHV2ICkge1xyXG5cclxuXHRcdHZlYzMgcTAgPSBkRmR4KCBleWVfcG9zLnh5eiApO1xyXG5cdFx0dmVjMyBxMSA9IGRGZHkoIGV5ZV9wb3MueHl6ICk7XHJcblx0XHR2ZWMyIHN0MCA9IGRGZHgoIHV2LnN0ICk7XHJcblx0XHR2ZWMyIHN0MSA9IGRGZHkoIHV2LnN0ICk7XHJcblxyXG5cdFx0dmVjMyBOID0gc3VyZl9ub3JtOyAvLyBub3JtYWxpemVkXHJcblxyXG5cdFx0dmVjMyBxMXBlcnAgPSBjcm9zcyggcTEsIE4gKTtcclxuXHRcdHZlYzMgcTBwZXJwID0gY3Jvc3MoIE4sIHEwICk7XHJcblxyXG5cdFx0dmVjMyBUID0gcTFwZXJwICogc3QwLnggKyBxMHBlcnAgKiBzdDEueDtcclxuXHRcdHZlYzMgQiA9IHExcGVycCAqIHN0MC55ICsgcTBwZXJwICogc3QxLnk7XHJcblxyXG5cdFx0ZmxvYXQgZGV0ID0gbWF4KCBkb3QoIFQsIFQgKSwgZG90KCBCLCBCICkgKTtcclxuXHRcdGZsb2F0IHNjYWxlID0gKCBkZXQgPT0gMC4wICkgPyAwLjAgOiBpbnZlcnNlc3FydCggZGV0ICk7XHJcblxyXG5cdFx0cmV0dXJuIG1hdDMoIFQgKiBzY2FsZSwgQiAqIHNjYWxlLCBOICk7XHJcblxyXG5cdH1cclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWZkZWYgVVNFX0NMRUFSQ09BVFxyXG5cclxuXHR2ZWMzIGNsZWFyY29hdE5vcm1hbCA9IG5vblBlcnR1cmJlZE5vcm1hbDtcclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWZkZWYgVVNFX0NMRUFSQ09BVF9OT1JNQUxNQVBcclxuXHJcblx0dmVjMyBjbGVhcmNvYXRNYXBOID0gdGV4dHVyZTJEKCBjbGVhcmNvYXROb3JtYWxNYXAsIHZDbGVhcmNvYXROb3JtYWxNYXBVdiApLnh5eiAqIDIuMCAtIDEuMDtcclxuXHRjbGVhcmNvYXRNYXBOLnh5ICo9IGNsZWFyY29hdE5vcm1hbFNjYWxlO1xyXG5cclxuXHRjbGVhcmNvYXROb3JtYWwgPSBub3JtYWxpemUoIHRibjIgKiBjbGVhcmNvYXRNYXBOICk7XHJcblxyXG4jZW5kaWZcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuXHJcbiNpZmRlZiBVU0VfQ0xFQVJDT0FUTUFQXHJcblxyXG5cdHVuaWZvcm0gc2FtcGxlcjJEIGNsZWFyY29hdE1hcDtcclxuXHJcbiNlbmRpZlxyXG5cclxuI2lmZGVmIFVTRV9DTEVBUkNPQVRfTk9STUFMTUFQXHJcblxyXG5cdHVuaWZvcm0gc2FtcGxlcjJEIGNsZWFyY29hdE5vcm1hbE1hcDtcclxuXHR1bmlmb3JtIHZlYzIgY2xlYXJjb2F0Tm9ybWFsU2NhbGU7XHJcblxyXG4jZW5kaWZcclxuXHJcbiNpZmRlZiBVU0VfQ0xFQVJDT0FUX1JPVUdITkVTU01BUFxyXG5cclxuXHR1bmlmb3JtIHNhbXBsZXIyRCBjbGVhcmNvYXRSb3VnaG5lc3NNYXA7XHJcblxyXG4jZW5kaWZcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuXHJcbiNpZmRlZiBVU0VfSVJJREVTQ0VOQ0VNQVBcclxuXHJcblx0dW5pZm9ybSBzYW1wbGVyMkQgaXJpZGVzY2VuY2VNYXA7XHJcblxyXG4jZW5kaWZcclxuXHJcbiNpZmRlZiBVU0VfSVJJREVTQ0VOQ0VfVEhJQ0tORVNTTUFQXHJcblxyXG5cdHVuaWZvcm0gc2FtcGxlcjJEIGlyaWRlc2NlbmNlVGhpY2tuZXNzTWFwO1xyXG5cclxuI2VuZGlmXHJcbmA7XHJcbiIsImV4cG9ydCBkZWZhdWx0IC8qIGdsc2wgKi9gXHJcbiNpZmRlZiBPUEFRVUVcclxuZGlmZnVzZUNvbG9yLmEgPSAxLjA7XHJcbiNlbmRpZlxyXG5cclxuI2lmZGVmIFVTRV9UUkFOU01JU1NJT05cclxuZGlmZnVzZUNvbG9yLmEgKj0gbWF0ZXJpYWwudHJhbnNtaXNzaW9uQWxwaGE7XHJcbiNlbmRpZlxyXG5cclxuZ2xfRnJhZ0NvbG9yID0gdmVjNCggb3V0Z29pbmdMaWdodCwgZGlmZnVzZUNvbG9yLmEgKTtcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxudmVjMyBwYWNrTm9ybWFsVG9SR0IoIGNvbnN0IGluIHZlYzMgbm9ybWFsICkge1xyXG5cdHJldHVybiBub3JtYWxpemUoIG5vcm1hbCApICogMC41ICsgMC41O1xyXG59XHJcblxyXG52ZWMzIHVucGFja1JHQlRvTm9ybWFsKCBjb25zdCBpbiB2ZWMzIHJnYiApIHtcclxuXHRyZXR1cm4gMi4wICogcmdiLnh5eiAtIDEuMDtcclxufVxyXG5cclxuY29uc3QgZmxvYXQgUGFja1Vwc2NhbGUgPSAyNTYuIC8gMjU1LjsgLy8gZnJhY3Rpb24gLT4gMC4uMSAoaW5jbHVkaW5nIDEpXHJcbmNvbnN0IGZsb2F0IFVucGFja0Rvd25zY2FsZSA9IDI1NS4gLyAyNTYuOyAvLyAwLi4xIC0+IGZyYWN0aW9uIChleGNsdWRpbmcgMSlcclxuXHJcbmNvbnN0IHZlYzMgUGFja0ZhY3RvcnMgPSB2ZWMzKCAyNTYuICogMjU2LiAqIDI1Ni4sIDI1Ni4gKiAyNTYuLCAyNTYuICk7XHJcbmNvbnN0IHZlYzQgVW5wYWNrRmFjdG9ycyA9IFVucGFja0Rvd25zY2FsZSAvIHZlYzQoIFBhY2tGYWN0b3JzLCAxLiApO1xyXG5cclxuY29uc3QgZmxvYXQgU2hpZnRSaWdodDggPSAxLiAvIDI1Ni47XHJcblxyXG52ZWM0IHBhY2tEZXB0aFRvUkdCQSggY29uc3QgaW4gZmxvYXQgdiApIHtcclxuXHR2ZWM0IHIgPSB2ZWM0KCBmcmFjdCggdiAqIFBhY2tGYWN0b3JzICksIHYgKTtcclxuXHRyLnl6dyAtPSByLnh5eiAqIFNoaWZ0UmlnaHQ4OyAvLyB0aWR5IG92ZXJmbG93XHJcblx0cmV0dXJuIHIgKiBQYWNrVXBzY2FsZTtcclxufVxyXG5cclxuZmxvYXQgdW5wYWNrUkdCQVRvRGVwdGgoIGNvbnN0IGluIHZlYzQgdiApIHtcclxuXHRyZXR1cm4gZG90KCB2LCBVbnBhY2tGYWN0b3JzICk7XHJcbn1cclxuXHJcbnZlYzIgcGFja0RlcHRoVG9SRyggaW4gaGlnaHAgZmxvYXQgdiApIHtcclxuXHRyZXR1cm4gcGFja0RlcHRoVG9SR0JBKCB2ICkueXg7XHJcbn1cclxuXHJcbmZsb2F0IHVucGFja1JHVG9EZXB0aCggY29uc3QgaW4gaGlnaHAgdmVjMiB2ICkge1xyXG5cdHJldHVybiB1bnBhY2tSR0JBVG9EZXB0aCggdmVjNCggdi54eSwgMC4wLCAwLjAgKSApO1xyXG59XHJcblxyXG52ZWM0IHBhY2sySGFsZlRvUkdCQSggdmVjMiB2ICkge1xyXG5cdHZlYzQgciA9IHZlYzQoIHYueCwgZnJhY3QoIHYueCAqIDI1NS4wICksIHYueSwgZnJhY3QoIHYueSAqIDI1NS4wICkgKTtcclxuXHRyZXR1cm4gdmVjNCggci54IC0gci55IC8gMjU1LjAsIHIueSwgci56IC0gci53IC8gMjU1LjAsIHIudyApO1xyXG59XHJcblxyXG52ZWMyIHVucGFja1JHQkFUbzJIYWxmKCB2ZWM0IHYgKSB7XHJcblx0cmV0dXJuIHZlYzIoIHYueCArICggdi55IC8gMjU1LjAgKSwgdi56ICsgKCB2LncgLyAyNTUuMCApICk7XHJcbn1cclxuXHJcbi8vIE5PVEU6IHZpZXdaLCB0aGUgei1jb29yZGluYXRlIGluIGNhbWVyYSBzcGFjZSwgaXMgbmVnYXRpdmUgZm9yIHBvaW50cyBpbiBmcm9udCBvZiB0aGUgY2FtZXJhXHJcblxyXG5mbG9hdCB2aWV3WlRvT3J0aG9ncmFwaGljRGVwdGgoIGNvbnN0IGluIGZsb2F0IHZpZXdaLCBjb25zdCBpbiBmbG9hdCBuZWFyLCBjb25zdCBpbiBmbG9hdCBmYXIgKSB7XHJcblx0Ly8gLW5lYXIgbWFwcyB0byAwOyAtZmFyIG1hcHMgdG8gMVxyXG5cdHJldHVybiAoIHZpZXdaICsgbmVhciApIC8gKCBuZWFyIC0gZmFyICk7XHJcbn1cclxuXHJcbmZsb2F0IG9ydGhvZ3JhcGhpY0RlcHRoVG9WaWV3WiggY29uc3QgaW4gZmxvYXQgZGVwdGgsIGNvbnN0IGluIGZsb2F0IG5lYXIsIGNvbnN0IGluIGZsb2F0IGZhciApIHtcclxuXHQvLyBtYXBzIG9ydGhvZ3JhcGhpYyBkZXB0aCBpbiBbIDAsIDEgXSB0byB2aWV3WlxyXG5cdHJldHVybiBkZXB0aCAqICggbmVhciAtIGZhciApIC0gbmVhcjtcclxufVxyXG5cclxuLy8gTk9URTogaHR0cHM6Ly90d2l0dGVyLmNvbS9nb25uYXZpcy9zdGF0dXMvMTM3NzE4Mzc4Njk0OTk1OTY4MlxyXG5cclxuZmxvYXQgdmlld1pUb1BlcnNwZWN0aXZlRGVwdGgoIGNvbnN0IGluIGZsb2F0IHZpZXdaLCBjb25zdCBpbiBmbG9hdCBuZWFyLCBjb25zdCBpbiBmbG9hdCBmYXIgKSB7XHJcblx0Ly8gLW5lYXIgbWFwcyB0byAwOyAtZmFyIG1hcHMgdG8gMVxyXG5cdHJldHVybiAoICggbmVhciArIHZpZXdaICkgKiBmYXIgKSAvICggKCBmYXIgLSBuZWFyICkgKiB2aWV3WiApO1xyXG59XHJcblxyXG5mbG9hdCBwZXJzcGVjdGl2ZURlcHRoVG9WaWV3WiggY29uc3QgaW4gZmxvYXQgZGVwdGgsIGNvbnN0IGluIGZsb2F0IG5lYXIsIGNvbnN0IGluIGZsb2F0IGZhciApIHtcclxuXHQvLyBtYXBzIHBlcnNwZWN0aXZlIGRlcHRoIGluIFsgMCwgMSBdIHRvIHZpZXdaXHJcblx0cmV0dXJuICggbmVhciAqIGZhciApIC8gKCAoIGZhciAtIG5lYXIgKSAqIGRlcHRoIC0gZmFyICk7XHJcbn1cclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuI2lmZGVmIFBSRU1VTFRJUExJRURfQUxQSEFcclxuXHJcblx0Ly8gR2V0IGdldCBub3JtYWwgYmxlbmRpbmcgd2l0aCBwcmVtdWx0aXBsZWQsIHVzZSB3aXRoIEN1c3RvbUJsZW5kaW5nLCBPbmVGYWN0b3IsIE9uZU1pbnVzU3JjQWxwaGFGYWN0b3IsIEFkZEVxdWF0aW9uLlxyXG5cdGdsX0ZyYWdDb2xvci5yZ2IgKj0gZ2xfRnJhZ0NvbG9yLmE7XHJcblxyXG4jZW5kaWZcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxudmVjNCBtdlBvc2l0aW9uID0gdmVjNCggdHJhbnNmb3JtZWQsIDEuMCApO1xyXG5cclxuI2lmZGVmIFVTRV9CQVRDSElOR1xyXG5cclxuXHRtdlBvc2l0aW9uID0gYmF0Y2hpbmdNYXRyaXggKiBtdlBvc2l0aW9uO1xyXG5cclxuI2VuZGlmXHJcblxyXG4jaWZkZWYgVVNFX0lOU1RBTkNJTkdcclxuXHJcblx0bXZQb3NpdGlvbiA9IGluc3RhbmNlTWF0cml4ICogbXZQb3NpdGlvbjtcclxuXHJcbiNlbmRpZlxyXG5cclxubXZQb3NpdGlvbiA9IG1vZGVsVmlld01hdHJpeCAqIG12UG9zaXRpb247XHJcblxyXG5nbF9Qb3NpdGlvbiA9IHByb2plY3Rpb25NYXRyaXggKiBtdlBvc2l0aW9uO1xyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWZkZWYgRElUSEVSSU5HXHJcblxyXG5cdGdsX0ZyYWdDb2xvci5yZ2IgPSBkaXRoZXJpbmcoIGdsX0ZyYWdDb2xvci5yZ2IgKTtcclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWZkZWYgRElUSEVSSU5HXHJcblxyXG5cdC8vIGJhc2VkIG9uIGh0dHBzOi8vd3d3LnNoYWRlcnRveS5jb20vdmlldy9Nc2xHUjhcclxuXHR2ZWMzIGRpdGhlcmluZyggdmVjMyBjb2xvciApIHtcclxuXHRcdC8vQ2FsY3VsYXRlIGdyaWQgcG9zaXRpb25cclxuXHRcdGZsb2F0IGdyaWRfcG9zaXRpb24gPSByYW5kKCBnbF9GcmFnQ29vcmQueHkgKTtcclxuXHJcblx0XHQvL1NoaWZ0IHRoZSBpbmRpdmlkdWFsIGNvbG9ycyBkaWZmZXJlbnRseSwgdGh1cyBtYWtpbmcgaXQgZXZlbiBoYXJkZXIgdG8gc2VlIHRoZSBkaXRoZXJpbmcgcGF0dGVyblxyXG5cdFx0dmVjMyBkaXRoZXJfc2hpZnRfUkdCID0gdmVjMyggMC4yNSAvIDI1NS4wLCAtMC4yNSAvIDI1NS4wLCAwLjI1IC8gMjU1LjAgKTtcclxuXHJcblx0XHQvL21vZGlmeSBzaGlmdCBhY2NvcmRpbmcgdG8gZ3JpZCBwb3NpdGlvbi5cclxuXHRcdGRpdGhlcl9zaGlmdF9SR0IgPSBtaXgoIDIuMCAqIGRpdGhlcl9zaGlmdF9SR0IsIC0yLjAgKiBkaXRoZXJfc2hpZnRfUkdCLCBncmlkX3Bvc2l0aW9uICk7XHJcblxyXG5cdFx0Ly9zaGlmdCB0aGUgY29sb3IgYnkgZGl0aGVyX3NoaWZ0XHJcblx0XHRyZXR1cm4gY29sb3IgKyBkaXRoZXJfc2hpZnRfUkdCO1xyXG5cdH1cclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG5mbG9hdCByb3VnaG5lc3NGYWN0b3IgPSByb3VnaG5lc3M7XHJcblxyXG4jaWZkZWYgVVNFX1JPVUdITkVTU01BUFxyXG5cclxuXHR2ZWM0IHRleGVsUm91Z2huZXNzID0gdGV4dHVyZTJEKCByb3VnaG5lc3NNYXAsIHZSb3VnaG5lc3NNYXBVdiApO1xyXG5cclxuXHQvLyByZWFkcyBjaGFubmVsIEcsIGNvbXBhdGlibGUgd2l0aCBhIGNvbWJpbmVkIE9jY2x1c2lvblJvdWdobmVzc01ldGFsbGljIChSR0IpIHRleHR1cmVcclxuXHRyb3VnaG5lc3NGYWN0b3IgKj0gdGV4ZWxSb3VnaG5lc3MuZztcclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWZkZWYgVVNFX1JPVUdITkVTU01BUFxyXG5cclxuXHR1bmlmb3JtIHNhbXBsZXIyRCByb3VnaG5lc3NNYXA7XHJcblxyXG4jZW5kaWZcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuI2lmIE5VTV9TUE9UX0xJR0hUX0NPT1JEUyA+IDBcclxuXHJcblx0dmFyeWluZyB2ZWM0IHZTcG90TGlnaHRDb29yZFsgTlVNX1NQT1RfTElHSFRfQ09PUkRTIF07XHJcblxyXG4jZW5kaWZcclxuXHJcbiNpZiBOVU1fU1BPVF9MSUdIVF9NQVBTID4gMFxyXG5cclxuXHR1bmlmb3JtIHNhbXBsZXIyRCBzcG90TGlnaHRNYXBbIE5VTV9TUE9UX0xJR0hUX01BUFMgXTtcclxuXHJcbiNlbmRpZlxyXG5cclxuI2lmZGVmIFVTRV9TSEFET1dNQVBcclxuXHJcblx0I2lmIE5VTV9ESVJfTElHSFRfU0hBRE9XUyA+IDBcclxuXHJcblx0XHR1bmlmb3JtIHNhbXBsZXIyRCBkaXJlY3Rpb25hbFNoYWRvd01hcFsgTlVNX0RJUl9MSUdIVF9TSEFET1dTIF07XHJcblx0XHR2YXJ5aW5nIHZlYzQgdkRpcmVjdGlvbmFsU2hhZG93Q29vcmRbIE5VTV9ESVJfTElHSFRfU0hBRE9XUyBdO1xyXG5cclxuXHRcdHN0cnVjdCBEaXJlY3Rpb25hbExpZ2h0U2hhZG93IHtcclxuXHRcdFx0ZmxvYXQgc2hhZG93QmlhcztcclxuXHRcdFx0ZmxvYXQgc2hhZG93Tm9ybWFsQmlhcztcclxuXHRcdFx0ZmxvYXQgc2hhZG93UmFkaXVzO1xyXG5cdFx0XHR2ZWMyIHNoYWRvd01hcFNpemU7XHJcblx0XHR9O1xyXG5cclxuXHRcdHVuaWZvcm0gRGlyZWN0aW9uYWxMaWdodFNoYWRvdyBkaXJlY3Rpb25hbExpZ2h0U2hhZG93c1sgTlVNX0RJUl9MSUdIVF9TSEFET1dTIF07XHJcblxyXG5cdCNlbmRpZlxyXG5cclxuXHQjaWYgTlVNX1NQT1RfTElHSFRfU0hBRE9XUyA+IDBcclxuXHJcblx0XHR1bmlmb3JtIHNhbXBsZXIyRCBzcG90U2hhZG93TWFwWyBOVU1fU1BPVF9MSUdIVF9TSEFET1dTIF07XHJcblxyXG5cdFx0c3RydWN0IFNwb3RMaWdodFNoYWRvdyB7XHJcblx0XHRcdGZsb2F0IHNoYWRvd0JpYXM7XHJcblx0XHRcdGZsb2F0IHNoYWRvd05vcm1hbEJpYXM7XHJcblx0XHRcdGZsb2F0IHNoYWRvd1JhZGl1cztcclxuXHRcdFx0dmVjMiBzaGFkb3dNYXBTaXplO1xyXG5cdFx0fTtcclxuXHJcblx0XHR1bmlmb3JtIFNwb3RMaWdodFNoYWRvdyBzcG90TGlnaHRTaGFkb3dzWyBOVU1fU1BPVF9MSUdIVF9TSEFET1dTIF07XHJcblxyXG5cdCNlbmRpZlxyXG5cclxuXHQjaWYgTlVNX1BPSU5UX0xJR0hUX1NIQURPV1MgPiAwXHJcblxyXG5cdFx0dW5pZm9ybSBzYW1wbGVyMkQgcG9pbnRTaGFkb3dNYXBbIE5VTV9QT0lOVF9MSUdIVF9TSEFET1dTIF07XHJcblx0XHR2YXJ5aW5nIHZlYzQgdlBvaW50U2hhZG93Q29vcmRbIE5VTV9QT0lOVF9MSUdIVF9TSEFET1dTIF07XHJcblxyXG5cdFx0c3RydWN0IFBvaW50TGlnaHRTaGFkb3cge1xyXG5cdFx0XHRmbG9hdCBzaGFkb3dCaWFzO1xyXG5cdFx0XHRmbG9hdCBzaGFkb3dOb3JtYWxCaWFzO1xyXG5cdFx0XHRmbG9hdCBzaGFkb3dSYWRpdXM7XHJcblx0XHRcdHZlYzIgc2hhZG93TWFwU2l6ZTtcclxuXHRcdFx0ZmxvYXQgc2hhZG93Q2FtZXJhTmVhcjtcclxuXHRcdFx0ZmxvYXQgc2hhZG93Q2FtZXJhRmFyO1xyXG5cdFx0fTtcclxuXHJcblx0XHR1bmlmb3JtIFBvaW50TGlnaHRTaGFkb3cgcG9pbnRMaWdodFNoYWRvd3NbIE5VTV9QT0lOVF9MSUdIVF9TSEFET1dTIF07XHJcblxyXG5cdCNlbmRpZlxyXG5cclxuXHQvKlxyXG5cdCNpZiBOVU1fUkVDVF9BUkVBX0xJR0hUUyA+IDBcclxuXHJcblx0XHQvLyBUT0RPIChhYmVsbmF0aW9uKTogY3JlYXRlIHVuaWZvcm1zIGZvciBhcmVhIGxpZ2h0IHNoYWRvd3NcclxuXHJcblx0I2VuZGlmXHJcblx0Ki9cclxuXHJcblx0ZmxvYXQgdGV4dHVyZTJEQ29tcGFyZSggc2FtcGxlcjJEIGRlcHRocywgdmVjMiB1diwgZmxvYXQgY29tcGFyZSApIHtcclxuXHJcblx0XHRyZXR1cm4gc3RlcCggY29tcGFyZSwgdW5wYWNrUkdCQVRvRGVwdGgoIHRleHR1cmUyRCggZGVwdGhzLCB1diApICkgKTtcclxuXHJcblx0fVxyXG5cclxuXHR2ZWMyIHRleHR1cmUyRERpc3RyaWJ1dGlvbiggc2FtcGxlcjJEIHNoYWRvdywgdmVjMiB1diApIHtcclxuXHJcblx0XHRyZXR1cm4gdW5wYWNrUkdCQVRvMkhhbGYoIHRleHR1cmUyRCggc2hhZG93LCB1diApICk7XHJcblxyXG5cdH1cclxuXHJcblx0ZmxvYXQgVlNNU2hhZG93IChzYW1wbGVyMkQgc2hhZG93LCB2ZWMyIHV2LCBmbG9hdCBjb21wYXJlICl7XHJcblxyXG5cdFx0ZmxvYXQgb2NjbHVzaW9uID0gMS4wO1xyXG5cclxuXHRcdHZlYzIgZGlzdHJpYnV0aW9uID0gdGV4dHVyZTJERGlzdHJpYnV0aW9uKCBzaGFkb3csIHV2ICk7XHJcblxyXG5cdFx0ZmxvYXQgaGFyZF9zaGFkb3cgPSBzdGVwKCBjb21wYXJlICwgZGlzdHJpYnV0aW9uLnggKTsgLy8gSGFyZCBTaGFkb3dcclxuXHJcblx0XHRpZiAoaGFyZF9zaGFkb3cgIT0gMS4wICkge1xyXG5cclxuXHRcdFx0ZmxvYXQgZGlzdGFuY2UgPSBjb21wYXJlIC0gZGlzdHJpYnV0aW9uLnggO1xyXG5cdFx0XHRmbG9hdCB2YXJpYW5jZSA9IG1heCggMC4wMDAwMCwgZGlzdHJpYnV0aW9uLnkgKiBkaXN0cmlidXRpb24ueSApO1xyXG5cdFx0XHRmbG9hdCBzb2Z0bmVzc19wcm9iYWJpbGl0eSA9IHZhcmlhbmNlIC8gKHZhcmlhbmNlICsgZGlzdGFuY2UgKiBkaXN0YW5jZSApOyAvLyBDaGViZXlzaGV2cyBpbmVxdWFsaXR5XHJcblx0XHRcdHNvZnRuZXNzX3Byb2JhYmlsaXR5ID0gY2xhbXAoICggc29mdG5lc3NfcHJvYmFiaWxpdHkgLSAwLjMgKSAvICggMC45NSAtIDAuMyApLCAwLjAsIDEuMCApOyAvLyAwLjMgcmVkdWNlcyBsaWdodCBibGVlZFxyXG5cdFx0XHRvY2NsdXNpb24gPSBjbGFtcCggbWF4KCBoYXJkX3NoYWRvdywgc29mdG5lc3NfcHJvYmFiaWxpdHkgKSwgMC4wLCAxLjAgKTtcclxuXHJcblx0XHR9XHJcblx0XHRyZXR1cm4gb2NjbHVzaW9uO1xyXG5cclxuXHR9XHJcblxyXG5cdGZsb2F0IGdldFNoYWRvdyggc2FtcGxlcjJEIHNoYWRvd01hcCwgdmVjMiBzaGFkb3dNYXBTaXplLCBmbG9hdCBzaGFkb3dCaWFzLCBmbG9hdCBzaGFkb3dSYWRpdXMsIHZlYzQgc2hhZG93Q29vcmQgKSB7XHJcblxyXG5cdFx0ZmxvYXQgc2hhZG93ID0gMS4wO1xyXG5cclxuXHRcdHNoYWRvd0Nvb3JkLnh5eiAvPSBzaGFkb3dDb29yZC53O1xyXG5cdFx0c2hhZG93Q29vcmQueiArPSBzaGFkb3dCaWFzO1xyXG5cclxuXHRcdGJvb2wgaW5GcnVzdHVtID0gc2hhZG93Q29vcmQueCA+PSAwLjAgJiYgc2hhZG93Q29vcmQueCA8PSAxLjAgJiYgc2hhZG93Q29vcmQueSA+PSAwLjAgJiYgc2hhZG93Q29vcmQueSA8PSAxLjA7XHJcblx0XHRib29sIGZydXN0dW1UZXN0ID0gaW5GcnVzdHVtICYmIHNoYWRvd0Nvb3JkLnogPD0gMS4wO1xyXG5cclxuXHRcdGlmICggZnJ1c3R1bVRlc3QgKSB7XHJcblxyXG5cdFx0I2lmIGRlZmluZWQoIFNIQURPV01BUF9UWVBFX1BDRiApXHJcblxyXG5cdFx0XHR2ZWMyIHRleGVsU2l6ZSA9IHZlYzIoIDEuMCApIC8gc2hhZG93TWFwU2l6ZTtcclxuXHJcblx0XHRcdGZsb2F0IGR4MCA9IC0gdGV4ZWxTaXplLnggKiBzaGFkb3dSYWRpdXM7XHJcblx0XHRcdGZsb2F0IGR5MCA9IC0gdGV4ZWxTaXplLnkgKiBzaGFkb3dSYWRpdXM7XHJcblx0XHRcdGZsb2F0IGR4MSA9ICsgdGV4ZWxTaXplLnggKiBzaGFkb3dSYWRpdXM7XHJcblx0XHRcdGZsb2F0IGR5MSA9ICsgdGV4ZWxTaXplLnkgKiBzaGFkb3dSYWRpdXM7XHJcblx0XHRcdGZsb2F0IGR4MiA9IGR4MCAvIDIuMDtcclxuXHRcdFx0ZmxvYXQgZHkyID0gZHkwIC8gMi4wO1xyXG5cdFx0XHRmbG9hdCBkeDMgPSBkeDEgLyAyLjA7XHJcblx0XHRcdGZsb2F0IGR5MyA9IGR5MSAvIDIuMDtcclxuXHJcblx0XHRcdHNoYWRvdyA9IChcclxuXHRcdFx0XHR0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIHNoYWRvd0Nvb3JkLnh5ICsgdmVjMiggZHgwLCBkeTAgKSwgc2hhZG93Q29vcmQueiApICtcclxuXHRcdFx0XHR0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIHNoYWRvd0Nvb3JkLnh5ICsgdmVjMiggMC4wLCBkeTAgKSwgc2hhZG93Q29vcmQueiApICtcclxuXHRcdFx0XHR0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIHNoYWRvd0Nvb3JkLnh5ICsgdmVjMiggZHgxLCBkeTAgKSwgc2hhZG93Q29vcmQueiApICtcclxuXHRcdFx0XHR0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIHNoYWRvd0Nvb3JkLnh5ICsgdmVjMiggZHgyLCBkeTIgKSwgc2hhZG93Q29vcmQueiApICtcclxuXHRcdFx0XHR0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIHNoYWRvd0Nvb3JkLnh5ICsgdmVjMiggMC4wLCBkeTIgKSwgc2hhZG93Q29vcmQueiApICtcclxuXHRcdFx0XHR0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIHNoYWRvd0Nvb3JkLnh5ICsgdmVjMiggZHgzLCBkeTIgKSwgc2hhZG93Q29vcmQueiApICtcclxuXHRcdFx0XHR0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIHNoYWRvd0Nvb3JkLnh5ICsgdmVjMiggZHgwLCAwLjAgKSwgc2hhZG93Q29vcmQueiApICtcclxuXHRcdFx0XHR0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIHNoYWRvd0Nvb3JkLnh5ICsgdmVjMiggZHgyLCAwLjAgKSwgc2hhZG93Q29vcmQueiApICtcclxuXHRcdFx0XHR0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIHNoYWRvd0Nvb3JkLnh5LCBzaGFkb3dDb29yZC56ICkgK1xyXG5cdFx0XHRcdHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgc2hhZG93Q29vcmQueHkgKyB2ZWMyKCBkeDMsIDAuMCApLCBzaGFkb3dDb29yZC56ICkgK1xyXG5cdFx0XHRcdHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgc2hhZG93Q29vcmQueHkgKyB2ZWMyKCBkeDEsIDAuMCApLCBzaGFkb3dDb29yZC56ICkgK1xyXG5cdFx0XHRcdHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgc2hhZG93Q29vcmQueHkgKyB2ZWMyKCBkeDIsIGR5MyApLCBzaGFkb3dDb29yZC56ICkgK1xyXG5cdFx0XHRcdHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgc2hhZG93Q29vcmQueHkgKyB2ZWMyKCAwLjAsIGR5MyApLCBzaGFkb3dDb29yZC56ICkgK1xyXG5cdFx0XHRcdHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgc2hhZG93Q29vcmQueHkgKyB2ZWMyKCBkeDMsIGR5MyApLCBzaGFkb3dDb29yZC56ICkgK1xyXG5cdFx0XHRcdHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgc2hhZG93Q29vcmQueHkgKyB2ZWMyKCBkeDAsIGR5MSApLCBzaGFkb3dDb29yZC56ICkgK1xyXG5cdFx0XHRcdHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgc2hhZG93Q29vcmQueHkgKyB2ZWMyKCAwLjAsIGR5MSApLCBzaGFkb3dDb29yZC56ICkgK1xyXG5cdFx0XHRcdHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgc2hhZG93Q29vcmQueHkgKyB2ZWMyKCBkeDEsIGR5MSApLCBzaGFkb3dDb29yZC56IClcclxuXHRcdFx0KSAqICggMS4wIC8gMTcuMCApO1xyXG5cclxuXHRcdCNlbGlmIGRlZmluZWQoIFNIQURPV01BUF9UWVBFX1BDRl9TT0ZUIClcclxuXHJcblx0XHRcdHZlYzIgdGV4ZWxTaXplID0gdmVjMiggMS4wICkgLyBzaGFkb3dNYXBTaXplO1xyXG5cdFx0XHRmbG9hdCBkeCA9IHRleGVsU2l6ZS54O1xyXG5cdFx0XHRmbG9hdCBkeSA9IHRleGVsU2l6ZS55O1xyXG5cclxuXHRcdFx0dmVjMiB1diA9IHNoYWRvd0Nvb3JkLnh5O1xyXG5cdFx0XHR2ZWMyIGYgPSBmcmFjdCggdXYgKiBzaGFkb3dNYXBTaXplICsgMC41ICk7XHJcblx0XHRcdHV2IC09IGYgKiB0ZXhlbFNpemU7XHJcblxyXG5cdFx0XHRzaGFkb3cgPSAoXHJcblx0XHRcdFx0dGV4dHVyZTJEQ29tcGFyZSggc2hhZG93TWFwLCB1diwgc2hhZG93Q29vcmQueiApICtcclxuXHRcdFx0XHR0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIHV2ICsgdmVjMiggZHgsIDAuMCApLCBzaGFkb3dDb29yZC56ICkgK1xyXG5cdFx0XHRcdHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgdXYgKyB2ZWMyKCAwLjAsIGR5ICksIHNoYWRvd0Nvb3JkLnogKSArXHJcblx0XHRcdFx0dGV4dHVyZTJEQ29tcGFyZSggc2hhZG93TWFwLCB1diArIHRleGVsU2l6ZSwgc2hhZG93Q29vcmQueiApICtcclxuXHRcdFx0XHRtaXgoIHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgdXYgKyB2ZWMyKCAtZHgsIDAuMCApLCBzaGFkb3dDb29yZC56ICksXHJcblx0XHRcdFx0XHQgdGV4dHVyZTJEQ29tcGFyZSggc2hhZG93TWFwLCB1diArIHZlYzIoIDIuMCAqIGR4LCAwLjAgKSwgc2hhZG93Q29vcmQueiApLFxyXG5cdFx0XHRcdFx0IGYueCApICtcclxuXHRcdFx0XHRtaXgoIHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgdXYgKyB2ZWMyKCAtZHgsIGR5ICksIHNoYWRvd0Nvb3JkLnogKSxcclxuXHRcdFx0XHRcdCB0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIHV2ICsgdmVjMiggMi4wICogZHgsIGR5ICksIHNoYWRvd0Nvb3JkLnogKSxcclxuXHRcdFx0XHRcdCBmLnggKSArXHJcblx0XHRcdFx0bWl4KCB0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIHV2ICsgdmVjMiggMC4wLCAtZHkgKSwgc2hhZG93Q29vcmQueiApLFxyXG5cdFx0XHRcdFx0IHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgdXYgKyB2ZWMyKCAwLjAsIDIuMCAqIGR5ICksIHNoYWRvd0Nvb3JkLnogKSxcclxuXHRcdFx0XHRcdCBmLnkgKSArXHJcblx0XHRcdFx0bWl4KCB0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIHV2ICsgdmVjMiggZHgsIC1keSApLCBzaGFkb3dDb29yZC56ICksXHJcblx0XHRcdFx0XHQgdGV4dHVyZTJEQ29tcGFyZSggc2hhZG93TWFwLCB1diArIHZlYzIoIGR4LCAyLjAgKiBkeSApLCBzaGFkb3dDb29yZC56ICksXHJcblx0XHRcdFx0XHQgZi55ICkgK1xyXG5cdFx0XHRcdG1peCggbWl4KCB0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIHV2ICsgdmVjMiggLWR4LCAtZHkgKSwgc2hhZG93Q29vcmQueiApLFxyXG5cdFx0XHRcdFx0XHQgIHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgdXYgKyB2ZWMyKCAyLjAgKiBkeCwgLWR5ICksIHNoYWRvd0Nvb3JkLnogKSxcclxuXHRcdFx0XHRcdFx0ICBmLnggKSxcclxuXHRcdFx0XHRcdCBtaXgoIHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgdXYgKyB2ZWMyKCAtZHgsIDIuMCAqIGR5ICksIHNoYWRvd0Nvb3JkLnogKSxcclxuXHRcdFx0XHRcdFx0ICB0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIHV2ICsgdmVjMiggMi4wICogZHgsIDIuMCAqIGR5ICksIHNoYWRvd0Nvb3JkLnogKSxcclxuXHRcdFx0XHRcdFx0ICBmLnggKSxcclxuXHRcdFx0XHRcdCBmLnkgKVxyXG5cdFx0XHQpICogKCAxLjAgLyA5LjAgKTtcclxuXHJcblx0XHQjZWxpZiBkZWZpbmVkKCBTSEFET1dNQVBfVFlQRV9WU00gKVxyXG5cclxuXHRcdFx0c2hhZG93ID0gVlNNU2hhZG93KCBzaGFkb3dNYXAsIHNoYWRvd0Nvb3JkLnh5LCBzaGFkb3dDb29yZC56ICk7XHJcblxyXG5cdFx0I2Vsc2UgLy8gbm8gcGVyY2VudGFnZS1jbG9zZXIgZmlsdGVyaW5nOlxyXG5cclxuXHRcdFx0c2hhZG93ID0gdGV4dHVyZTJEQ29tcGFyZSggc2hhZG93TWFwLCBzaGFkb3dDb29yZC54eSwgc2hhZG93Q29vcmQueiApO1xyXG5cclxuXHRcdCNlbmRpZlxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gc2hhZG93O1xyXG5cclxuXHR9XHJcblxyXG5cdC8vIGN1YmVUb1VWKCkgbWFwcyBhIDNEIGRpcmVjdGlvbiB2ZWN0b3Igc3VpdGFibGUgZm9yIGN1YmUgdGV4dHVyZSBtYXBwaW5nIHRvIGEgMkRcclxuXHQvLyB2ZWN0b3Igc3VpdGFibGUgZm9yIDJEIHRleHR1cmUgbWFwcGluZy4gVGhpcyBjb2RlIHVzZXMgdGhlIGZvbGxvd2luZyBsYXlvdXQgZm9yIHRoZVxyXG5cdC8vIDJEIHRleHR1cmU6XHJcblx0Ly9cclxuXHQvLyB4elhaXHJcblx0Ly8gIHkgWVxyXG5cdC8vXHJcblx0Ly8gWSAtIFBvc2l0aXZlIHkgZGlyZWN0aW9uXHJcblx0Ly8geSAtIE5lZ2F0aXZlIHkgZGlyZWN0aW9uXHJcblx0Ly8gWCAtIFBvc2l0aXZlIHggZGlyZWN0aW9uXHJcblx0Ly8geCAtIE5lZ2F0aXZlIHggZGlyZWN0aW9uXHJcblx0Ly8gWiAtIFBvc2l0aXZlIHogZGlyZWN0aW9uXHJcblx0Ly8geiAtIE5lZ2F0aXZlIHogZGlyZWN0aW9uXHJcblx0Ly9cclxuXHQvLyBTb3VyY2UgYW5kIHRlc3QgYmVkOlxyXG5cdC8vIGh0dHBzOi8vZ2lzdC5naXRodWIuY29tL3RzY2h3L2RhMTBjNDNjNDY3Y2U4YWZkMGM0XHJcblxyXG5cdHZlYzIgY3ViZVRvVVYoIHZlYzMgdiwgZmxvYXQgdGV4ZWxTaXplWSApIHtcclxuXHJcblx0XHQvLyBOdW1iZXIgb2YgdGV4ZWxzIHRvIGF2b2lkIGF0IHRoZSBlZGdlIG9mIGVhY2ggc3F1YXJlXHJcblxyXG5cdFx0dmVjMyBhYnNWID0gYWJzKCB2ICk7XHJcblxyXG5cdFx0Ly8gSW50ZXJzZWN0IHVuaXQgY3ViZVxyXG5cclxuXHRcdGZsb2F0IHNjYWxlVG9DdWJlID0gMS4wIC8gbWF4KCBhYnNWLngsIG1heCggYWJzVi55LCBhYnNWLnogKSApO1xyXG5cdFx0YWJzViAqPSBzY2FsZVRvQ3ViZTtcclxuXHJcblx0XHQvLyBBcHBseSBzY2FsZSB0byBhdm9pZCBzZWFtc1xyXG5cclxuXHRcdC8vIHR3byB0ZXhlbHMgbGVzcyBwZXIgc3F1YXJlIChvbmUgdGV4ZWwgd2lsbCBkbyBmb3IgTkVBUkVTVClcclxuXHRcdHYgKj0gc2NhbGVUb0N1YmUgKiAoIDEuMCAtIDIuMCAqIHRleGVsU2l6ZVkgKTtcclxuXHJcblx0XHQvLyBVbndyYXBcclxuXHJcblx0XHQvLyBzcGFjZTogLTEgLi4uIDEgcmFuZ2UgZm9yIGVhY2ggc3F1YXJlXHJcblx0XHQvL1xyXG5cdFx0Ly8gI1gjI1x0XHRkaW0gICAgOj0gKCA0ICwgMiApXHJcblx0XHQvLyAgIyAjXHRcdGNlbnRlciA6PSAoIDEgLCAxIClcclxuXHJcblx0XHR2ZWMyIHBsYW5hciA9IHYueHk7XHJcblxyXG5cdFx0ZmxvYXQgYWxtb3N0QVRleGVsID0gMS41ICogdGV4ZWxTaXplWTtcclxuXHRcdGZsb2F0IGFsbW9zdE9uZSA9IDEuMCAtIGFsbW9zdEFUZXhlbDtcclxuXHJcblx0XHRpZiAoIGFic1YueiA+PSBhbG1vc3RPbmUgKSB7XHJcblxyXG5cdFx0XHRpZiAoIHYueiA+IDAuMCApXHJcblx0XHRcdFx0cGxhbmFyLnggPSA0LjAgLSB2Lng7XHJcblxyXG5cdFx0fSBlbHNlIGlmICggYWJzVi54ID49IGFsbW9zdE9uZSApIHtcclxuXHJcblx0XHRcdGZsb2F0IHNpZ25YID0gc2lnbiggdi54ICk7XHJcblx0XHRcdHBsYW5hci54ID0gdi56ICogc2lnblggKyAyLjAgKiBzaWduWDtcclxuXHJcblx0XHR9IGVsc2UgaWYgKCBhYnNWLnkgPj0gYWxtb3N0T25lICkge1xyXG5cclxuXHRcdFx0ZmxvYXQgc2lnblkgPSBzaWduKCB2LnkgKTtcclxuXHRcdFx0cGxhbmFyLnggPSB2LnggKyAyLjAgKiBzaWduWSArIDIuMDtcclxuXHRcdFx0cGxhbmFyLnkgPSB2LnogKiBzaWduWSAtIDIuMDtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gVHJhbnNmb3JtIHRvIFVWIHNwYWNlXHJcblxyXG5cdFx0Ly8gc2NhbGUgOj0gMC41IC8gZGltXHJcblx0XHQvLyB0cmFuc2xhdGUgOj0gKCBjZW50ZXIgKyAwLjUgKSAvIGRpbVxyXG5cdFx0cmV0dXJuIHZlYzIoIDAuMTI1LCAwLjI1ICkgKiBwbGFuYXIgKyB2ZWMyKCAwLjM3NSwgMC43NSApO1xyXG5cclxuXHR9XHJcblxyXG5cdGZsb2F0IGdldFBvaW50U2hhZG93KCBzYW1wbGVyMkQgc2hhZG93TWFwLCB2ZWMyIHNoYWRvd01hcFNpemUsIGZsb2F0IHNoYWRvd0JpYXMsIGZsb2F0IHNoYWRvd1JhZGl1cywgdmVjNCBzaGFkb3dDb29yZCwgZmxvYXQgc2hhZG93Q2FtZXJhTmVhciwgZmxvYXQgc2hhZG93Q2FtZXJhRmFyICkge1xyXG5cclxuXHRcdHZlYzIgdGV4ZWxTaXplID0gdmVjMiggMS4wICkgLyAoIHNoYWRvd01hcFNpemUgKiB2ZWMyKCA0LjAsIDIuMCApICk7XHJcblxyXG5cdFx0Ly8gZm9yIHBvaW50IGxpZ2h0cywgdGhlIHVuaWZvcm0gQHZTaGFkb3dDb29yZCBpcyByZS1wdXJwb3NlZCB0byBob2xkXHJcblx0XHQvLyB0aGUgdmVjdG9yIGZyb20gdGhlIGxpZ2h0IHRvIHRoZSB3b3JsZC1zcGFjZSBwb3NpdGlvbiBvZiB0aGUgZnJhZ21lbnQuXHJcblx0XHR2ZWMzIGxpZ2h0VG9Qb3NpdGlvbiA9IHNoYWRvd0Nvb3JkLnh5ejtcclxuXHJcblx0XHQvLyBkcCA9IG5vcm1hbGl6ZWQgZGlzdGFuY2UgZnJvbSBsaWdodCB0byBmcmFnbWVudCBwb3NpdGlvblxyXG5cdFx0ZmxvYXQgZHAgPSAoIGxlbmd0aCggbGlnaHRUb1Bvc2l0aW9uICkgLSBzaGFkb3dDYW1lcmFOZWFyICkgLyAoIHNoYWRvd0NhbWVyYUZhciAtIHNoYWRvd0NhbWVyYU5lYXIgKTsgLy8gbmVlZCB0byBjbGFtcD9cclxuXHRcdGRwICs9IHNoYWRvd0JpYXM7XHJcblxyXG5cdFx0Ly8gYmQzRCA9IGJhc2UgZGlyZWN0aW9uIDNEXHJcblx0XHR2ZWMzIGJkM0QgPSBub3JtYWxpemUoIGxpZ2h0VG9Qb3NpdGlvbiApO1xyXG5cclxuXHRcdCNpZiBkZWZpbmVkKCBTSEFET1dNQVBfVFlQRV9QQ0YgKSB8fCBkZWZpbmVkKCBTSEFET1dNQVBfVFlQRV9QQ0ZfU09GVCApIHx8IGRlZmluZWQoIFNIQURPV01BUF9UWVBFX1ZTTSApXHJcblxyXG5cdFx0XHR2ZWMyIG9mZnNldCA9IHZlYzIoIC0gMSwgMSApICogc2hhZG93UmFkaXVzICogdGV4ZWxTaXplLnk7XHJcblxyXG5cdFx0XHRyZXR1cm4gKFxyXG5cdFx0XHRcdHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgY3ViZVRvVVYoIGJkM0QgKyBvZmZzZXQueHl5LCB0ZXhlbFNpemUueSApLCBkcCApICtcclxuXHRcdFx0XHR0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIGN1YmVUb1VWKCBiZDNEICsgb2Zmc2V0Lnl5eSwgdGV4ZWxTaXplLnkgKSwgZHAgKSArXHJcblx0XHRcdFx0dGV4dHVyZTJEQ29tcGFyZSggc2hhZG93TWFwLCBjdWJlVG9VViggYmQzRCArIG9mZnNldC54eXgsIHRleGVsU2l6ZS55ICksIGRwICkgK1xyXG5cdFx0XHRcdHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgY3ViZVRvVVYoIGJkM0QgKyBvZmZzZXQueXl4LCB0ZXhlbFNpemUueSApLCBkcCApICtcclxuXHRcdFx0XHR0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIGN1YmVUb1VWKCBiZDNELCB0ZXhlbFNpemUueSApLCBkcCApICtcclxuXHRcdFx0XHR0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIGN1YmVUb1VWKCBiZDNEICsgb2Zmc2V0Lnh4eSwgdGV4ZWxTaXplLnkgKSwgZHAgKSArXHJcblx0XHRcdFx0dGV4dHVyZTJEQ29tcGFyZSggc2hhZG93TWFwLCBjdWJlVG9VViggYmQzRCArIG9mZnNldC55eHksIHRleGVsU2l6ZS55ICksIGRwICkgK1xyXG5cdFx0XHRcdHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgY3ViZVRvVVYoIGJkM0QgKyBvZmZzZXQueHh4LCB0ZXhlbFNpemUueSApLCBkcCApICtcclxuXHRcdFx0XHR0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIGN1YmVUb1VWKCBiZDNEICsgb2Zmc2V0Lnl4eCwgdGV4ZWxTaXplLnkgKSwgZHAgKVxyXG5cdFx0XHQpICogKCAxLjAgLyA5LjAgKTtcclxuXHJcblx0XHQjZWxzZSAvLyBubyBwZXJjZW50YWdlLWNsb3NlciBmaWx0ZXJpbmdcclxuXHJcblx0XHRcdHJldHVybiB0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIGN1YmVUb1VWKCBiZDNELCB0ZXhlbFNpemUueSApLCBkcCApO1xyXG5cclxuXHRcdCNlbmRpZlxyXG5cclxuXHR9XHJcblxyXG4jZW5kaWZcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuXHJcbiNpZiBOVU1fU1BPVF9MSUdIVF9DT09SRFMgPiAwXHJcblxyXG5cdHVuaWZvcm0gbWF0NCBzcG90TGlnaHRNYXRyaXhbIE5VTV9TUE9UX0xJR0hUX0NPT1JEUyBdO1xyXG5cdHZhcnlpbmcgdmVjNCB2U3BvdExpZ2h0Q29vcmRbIE5VTV9TUE9UX0xJR0hUX0NPT1JEUyBdO1xyXG5cclxuI2VuZGlmXHJcblxyXG4jaWZkZWYgVVNFX1NIQURPV01BUFxyXG5cclxuXHQjaWYgTlVNX0RJUl9MSUdIVF9TSEFET1dTID4gMFxyXG5cclxuXHRcdHVuaWZvcm0gbWF0NCBkaXJlY3Rpb25hbFNoYWRvd01hdHJpeFsgTlVNX0RJUl9MSUdIVF9TSEFET1dTIF07XHJcblx0XHR2YXJ5aW5nIHZlYzQgdkRpcmVjdGlvbmFsU2hhZG93Q29vcmRbIE5VTV9ESVJfTElHSFRfU0hBRE9XUyBdO1xyXG5cclxuXHRcdHN0cnVjdCBEaXJlY3Rpb25hbExpZ2h0U2hhZG93IHtcclxuXHRcdFx0ZmxvYXQgc2hhZG93QmlhcztcclxuXHRcdFx0ZmxvYXQgc2hhZG93Tm9ybWFsQmlhcztcclxuXHRcdFx0ZmxvYXQgc2hhZG93UmFkaXVzO1xyXG5cdFx0XHR2ZWMyIHNoYWRvd01hcFNpemU7XHJcblx0XHR9O1xyXG5cclxuXHRcdHVuaWZvcm0gRGlyZWN0aW9uYWxMaWdodFNoYWRvdyBkaXJlY3Rpb25hbExpZ2h0U2hhZG93c1sgTlVNX0RJUl9MSUdIVF9TSEFET1dTIF07XHJcblxyXG5cdCNlbmRpZlxyXG5cclxuXHQjaWYgTlVNX1NQT1RfTElHSFRfU0hBRE9XUyA+IDBcclxuXHJcblx0XHRzdHJ1Y3QgU3BvdExpZ2h0U2hhZG93IHtcclxuXHRcdFx0ZmxvYXQgc2hhZG93QmlhcztcclxuXHRcdFx0ZmxvYXQgc2hhZG93Tm9ybWFsQmlhcztcclxuXHRcdFx0ZmxvYXQgc2hhZG93UmFkaXVzO1xyXG5cdFx0XHR2ZWMyIHNoYWRvd01hcFNpemU7XHJcblx0XHR9O1xyXG5cclxuXHRcdHVuaWZvcm0gU3BvdExpZ2h0U2hhZG93IHNwb3RMaWdodFNoYWRvd3NbIE5VTV9TUE9UX0xJR0hUX1NIQURPV1MgXTtcclxuXHJcblx0I2VuZGlmXHJcblxyXG5cdCNpZiBOVU1fUE9JTlRfTElHSFRfU0hBRE9XUyA+IDBcclxuXHJcblx0XHR1bmlmb3JtIG1hdDQgcG9pbnRTaGFkb3dNYXRyaXhbIE5VTV9QT0lOVF9MSUdIVF9TSEFET1dTIF07XHJcblx0XHR2YXJ5aW5nIHZlYzQgdlBvaW50U2hhZG93Q29vcmRbIE5VTV9QT0lOVF9MSUdIVF9TSEFET1dTIF07XHJcblxyXG5cdFx0c3RydWN0IFBvaW50TGlnaHRTaGFkb3cge1xyXG5cdFx0XHRmbG9hdCBzaGFkb3dCaWFzO1xyXG5cdFx0XHRmbG9hdCBzaGFkb3dOb3JtYWxCaWFzO1xyXG5cdFx0XHRmbG9hdCBzaGFkb3dSYWRpdXM7XHJcblx0XHRcdHZlYzIgc2hhZG93TWFwU2l6ZTtcclxuXHRcdFx0ZmxvYXQgc2hhZG93Q2FtZXJhTmVhcjtcclxuXHRcdFx0ZmxvYXQgc2hhZG93Q2FtZXJhRmFyO1xyXG5cdFx0fTtcclxuXHJcblx0XHR1bmlmb3JtIFBvaW50TGlnaHRTaGFkb3cgcG9pbnRMaWdodFNoYWRvd3NbIE5VTV9QT0lOVF9MSUdIVF9TSEFET1dTIF07XHJcblxyXG5cdCNlbmRpZlxyXG5cclxuXHQvKlxyXG5cdCNpZiBOVU1fUkVDVF9BUkVBX0xJR0hUUyA+IDBcclxuXHJcblx0XHQvLyBUT0RPIChhYmVsbmF0aW9uKTogdW5pZm9ybXMgZm9yIGFyZWEgbGlnaHQgc2hhZG93c1xyXG5cclxuXHQjZW5kaWZcclxuXHQqL1xyXG5cclxuI2VuZGlmXHJcbmA7XHJcbiIsImV4cG9ydCBkZWZhdWx0IC8qIGdsc2wgKi9gXHJcblxyXG4jaWYgKCBkZWZpbmVkKCBVU0VfU0hBRE9XTUFQICkgJiYgKCBOVU1fRElSX0xJR0hUX1NIQURPV1MgPiAwIHx8IE5VTV9QT0lOVF9MSUdIVF9TSEFET1dTID4gMCApICkgfHwgKCBOVU1fU1BPVF9MSUdIVF9DT09SRFMgPiAwIClcclxuXHJcblx0Ly8gT2Zmc2V0dGluZyB0aGUgcG9zaXRpb24gdXNlZCBmb3IgcXVlcnlpbmcgb2NjbHVzaW9uIGFsb25nIHRoZSB3b3JsZCBub3JtYWwgY2FuIGJlIHVzZWQgdG8gcmVkdWNlIHNoYWRvdyBhY25lLlxyXG5cdHZlYzMgc2hhZG93V29ybGROb3JtYWwgPSBpbnZlcnNlVHJhbnNmb3JtRGlyZWN0aW9uKCB0cmFuc2Zvcm1lZE5vcm1hbCwgdmlld01hdHJpeCApO1xyXG5cdHZlYzQgc2hhZG93V29ybGRQb3NpdGlvbjtcclxuXHJcbiNlbmRpZlxyXG5cclxuI2lmIGRlZmluZWQoIFVTRV9TSEFET1dNQVAgKVxyXG5cclxuXHQjaWYgTlVNX0RJUl9MSUdIVF9TSEFET1dTID4gMFxyXG5cclxuXHRcdCNwcmFnbWEgdW5yb2xsX2xvb3Bfc3RhcnRcclxuXHRcdGZvciAoIGludCBpID0gMDsgaSA8IE5VTV9ESVJfTElHSFRfU0hBRE9XUzsgaSArKyApIHtcclxuXHJcblx0XHRcdHNoYWRvd1dvcmxkUG9zaXRpb24gPSB3b3JsZFBvc2l0aW9uICsgdmVjNCggc2hhZG93V29ybGROb3JtYWwgKiBkaXJlY3Rpb25hbExpZ2h0U2hhZG93c1sgaSBdLnNoYWRvd05vcm1hbEJpYXMsIDAgKTtcclxuXHRcdFx0dkRpcmVjdGlvbmFsU2hhZG93Q29vcmRbIGkgXSA9IGRpcmVjdGlvbmFsU2hhZG93TWF0cml4WyBpIF0gKiBzaGFkb3dXb3JsZFBvc2l0aW9uO1xyXG5cclxuXHRcdH1cclxuXHRcdCNwcmFnbWEgdW5yb2xsX2xvb3BfZW5kXHJcblxyXG5cdCNlbmRpZlxyXG5cclxuXHQjaWYgTlVNX1BPSU5UX0xJR0hUX1NIQURPV1MgPiAwXHJcblxyXG5cdFx0I3ByYWdtYSB1bnJvbGxfbG9vcF9zdGFydFxyXG5cdFx0Zm9yICggaW50IGkgPSAwOyBpIDwgTlVNX1BPSU5UX0xJR0hUX1NIQURPV1M7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRzaGFkb3dXb3JsZFBvc2l0aW9uID0gd29ybGRQb3NpdGlvbiArIHZlYzQoIHNoYWRvd1dvcmxkTm9ybWFsICogcG9pbnRMaWdodFNoYWRvd3NbIGkgXS5zaGFkb3dOb3JtYWxCaWFzLCAwICk7XHJcblx0XHRcdHZQb2ludFNoYWRvd0Nvb3JkWyBpIF0gPSBwb2ludFNoYWRvd01hdHJpeFsgaSBdICogc2hhZG93V29ybGRQb3NpdGlvbjtcclxuXHJcblx0XHR9XHJcblx0XHQjcHJhZ21hIHVucm9sbF9sb29wX2VuZFxyXG5cclxuXHQjZW5kaWZcclxuXHJcblx0LypcclxuXHQjaWYgTlVNX1JFQ1RfQVJFQV9MSUdIVFMgPiAwXHJcblxyXG5cdFx0Ly8gVE9ETyAoYWJlbG5hdGlvbik6IHVwZGF0ZSB2QXJlYVNoYWRvd0Nvb3JkIHdpdGggYXJlYSBsaWdodCBpbmZvXHJcblxyXG5cdCNlbmRpZlxyXG5cdCovXHJcblxyXG4jZW5kaWZcclxuXHJcbi8vIHNwb3QgbGlnaHRzIGNhbiBiZSBldmFsdWF0ZWQgd2l0aG91dCBhY3RpdmUgc2hhZG93IG1hcHBpbmcgKHdoZW4gU3BvdExpZ2h0Lm1hcCBpcyB1c2VkKVxyXG5cclxuI2lmIE5VTV9TUE9UX0xJR0hUX0NPT1JEUyA+IDBcclxuXHJcblx0I3ByYWdtYSB1bnJvbGxfbG9vcF9zdGFydFxyXG5cdGZvciAoIGludCBpID0gMDsgaSA8IE5VTV9TUE9UX0xJR0hUX0NPT1JEUzsgaSArKyApIHtcclxuXHJcblx0XHRzaGFkb3dXb3JsZFBvc2l0aW9uID0gd29ybGRQb3NpdGlvbjtcclxuXHRcdCNpZiAoIGRlZmluZWQoIFVTRV9TSEFET1dNQVAgKSAmJiBVTlJPTExFRF9MT09QX0lOREVYIDwgTlVNX1NQT1RfTElHSFRfU0hBRE9XUyApXHJcblx0XHRcdHNoYWRvd1dvcmxkUG9zaXRpb24ueHl6ICs9IHNoYWRvd1dvcmxkTm9ybWFsICogc3BvdExpZ2h0U2hhZG93c1sgaSBdLnNoYWRvd05vcm1hbEJpYXM7XHJcblx0XHQjZW5kaWZcclxuXHRcdHZTcG90TGlnaHRDb29yZFsgaSBdID0gc3BvdExpZ2h0TWF0cml4WyBpIF0gKiBzaGFkb3dXb3JsZFBvc2l0aW9uO1xyXG5cclxuXHR9XHJcblx0I3ByYWdtYSB1bnJvbGxfbG9vcF9lbmRcclxuXHJcbiNlbmRpZlxyXG5cclxuXHJcbmA7XHJcbiIsImV4cG9ydCBkZWZhdWx0IC8qIGdsc2wgKi9gXHJcbmZsb2F0IGdldFNoYWRvd01hc2soKSB7XHJcblxyXG5cdGZsb2F0IHNoYWRvdyA9IDEuMDtcclxuXHJcblx0I2lmZGVmIFVTRV9TSEFET1dNQVBcclxuXHJcblx0I2lmIE5VTV9ESVJfTElHSFRfU0hBRE9XUyA+IDBcclxuXHJcblx0RGlyZWN0aW9uYWxMaWdodFNoYWRvdyBkaXJlY3Rpb25hbExpZ2h0O1xyXG5cclxuXHQjcHJhZ21hIHVucm9sbF9sb29wX3N0YXJ0XHJcblx0Zm9yICggaW50IGkgPSAwOyBpIDwgTlVNX0RJUl9MSUdIVF9TSEFET1dTOyBpICsrICkge1xyXG5cclxuXHRcdGRpcmVjdGlvbmFsTGlnaHQgPSBkaXJlY3Rpb25hbExpZ2h0U2hhZG93c1sgaSBdO1xyXG5cdFx0c2hhZG93ICo9IHJlY2VpdmVTaGFkb3cgPyBnZXRTaGFkb3coIGRpcmVjdGlvbmFsU2hhZG93TWFwWyBpIF0sIGRpcmVjdGlvbmFsTGlnaHQuc2hhZG93TWFwU2l6ZSwgZGlyZWN0aW9uYWxMaWdodC5zaGFkb3dCaWFzLCBkaXJlY3Rpb25hbExpZ2h0LnNoYWRvd1JhZGl1cywgdkRpcmVjdGlvbmFsU2hhZG93Q29vcmRbIGkgXSApIDogMS4wO1xyXG5cclxuXHR9XHJcblx0I3ByYWdtYSB1bnJvbGxfbG9vcF9lbmRcclxuXHJcblx0I2VuZGlmXHJcblxyXG5cdCNpZiBOVU1fU1BPVF9MSUdIVF9TSEFET1dTID4gMFxyXG5cclxuXHRTcG90TGlnaHRTaGFkb3cgc3BvdExpZ2h0O1xyXG5cclxuXHQjcHJhZ21hIHVucm9sbF9sb29wX3N0YXJ0XHJcblx0Zm9yICggaW50IGkgPSAwOyBpIDwgTlVNX1NQT1RfTElHSFRfU0hBRE9XUzsgaSArKyApIHtcclxuXHJcblx0XHRzcG90TGlnaHQgPSBzcG90TGlnaHRTaGFkb3dzWyBpIF07XHJcblx0XHRzaGFkb3cgKj0gcmVjZWl2ZVNoYWRvdyA/IGdldFNoYWRvdyggc3BvdFNoYWRvd01hcFsgaSBdLCBzcG90TGlnaHQuc2hhZG93TWFwU2l6ZSwgc3BvdExpZ2h0LnNoYWRvd0JpYXMsIHNwb3RMaWdodC5zaGFkb3dSYWRpdXMsIHZTcG90TGlnaHRDb29yZFsgaSBdICkgOiAxLjA7XHJcblxyXG5cdH1cclxuXHQjcHJhZ21hIHVucm9sbF9sb29wX2VuZFxyXG5cclxuXHQjZW5kaWZcclxuXHJcblx0I2lmIE5VTV9QT0lOVF9MSUdIVF9TSEFET1dTID4gMFxyXG5cclxuXHRQb2ludExpZ2h0U2hhZG93IHBvaW50TGlnaHQ7XHJcblxyXG5cdCNwcmFnbWEgdW5yb2xsX2xvb3Bfc3RhcnRcclxuXHRmb3IgKCBpbnQgaSA9IDA7IGkgPCBOVU1fUE9JTlRfTElHSFRfU0hBRE9XUzsgaSArKyApIHtcclxuXHJcblx0XHRwb2ludExpZ2h0ID0gcG9pbnRMaWdodFNoYWRvd3NbIGkgXTtcclxuXHRcdHNoYWRvdyAqPSByZWNlaXZlU2hhZG93ID8gZ2V0UG9pbnRTaGFkb3coIHBvaW50U2hhZG93TWFwWyBpIF0sIHBvaW50TGlnaHQuc2hhZG93TWFwU2l6ZSwgcG9pbnRMaWdodC5zaGFkb3dCaWFzLCBwb2ludExpZ2h0LnNoYWRvd1JhZGl1cywgdlBvaW50U2hhZG93Q29vcmRbIGkgXSwgcG9pbnRMaWdodC5zaGFkb3dDYW1lcmFOZWFyLCBwb2ludExpZ2h0LnNoYWRvd0NhbWVyYUZhciApIDogMS4wO1xyXG5cclxuXHR9XHJcblx0I3ByYWdtYSB1bnJvbGxfbG9vcF9lbmRcclxuXHJcblx0I2VuZGlmXHJcblxyXG5cdC8qXHJcblx0I2lmIE5VTV9SRUNUX0FSRUFfTElHSFRTID4gMFxyXG5cclxuXHRcdC8vIFRPRE8gKGFiZWxuYXRpb24pOiB1cGRhdGUgc2hhZG93IGZvciBBcmVhIGxpZ2h0XHJcblxyXG5cdCNlbmRpZlxyXG5cdCovXHJcblxyXG5cdCNlbmRpZlxyXG5cclxuXHRyZXR1cm4gc2hhZG93O1xyXG5cclxufVxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWZkZWYgVVNFX1NLSU5OSU5HXHJcblxyXG5cdG1hdDQgYm9uZU1hdFggPSBnZXRCb25lTWF0cml4KCBza2luSW5kZXgueCApO1xyXG5cdG1hdDQgYm9uZU1hdFkgPSBnZXRCb25lTWF0cml4KCBza2luSW5kZXgueSApO1xyXG5cdG1hdDQgYm9uZU1hdFogPSBnZXRCb25lTWF0cml4KCBza2luSW5kZXgueiApO1xyXG5cdG1hdDQgYm9uZU1hdFcgPSBnZXRCb25lTWF0cml4KCBza2luSW5kZXgudyApO1xyXG5cclxuI2VuZGlmXHJcbmA7XHJcbiIsImV4cG9ydCBkZWZhdWx0IC8qIGdsc2wgKi9gXHJcbiNpZmRlZiBVU0VfU0tJTk5JTkdcclxuXHJcblx0dW5pZm9ybSBtYXQ0IGJpbmRNYXRyaXg7XHJcblx0dW5pZm9ybSBtYXQ0IGJpbmRNYXRyaXhJbnZlcnNlO1xyXG5cclxuXHR1bmlmb3JtIGhpZ2hwIHNhbXBsZXIyRCBib25lVGV4dHVyZTtcclxuXHJcblx0bWF0NCBnZXRCb25lTWF0cml4KCBjb25zdCBpbiBmbG9hdCBpICkge1xyXG5cclxuXHRcdGludCBzaXplID0gdGV4dHVyZVNpemUoIGJvbmVUZXh0dXJlLCAwICkueDtcclxuXHRcdGludCBqID0gaW50KCBpICkgKiA0O1xyXG5cdFx0aW50IHggPSBqICUgc2l6ZTtcclxuXHRcdGludCB5ID0gaiAvIHNpemU7XHJcblx0XHR2ZWM0IHYxID0gdGV4ZWxGZXRjaCggYm9uZVRleHR1cmUsIGl2ZWMyKCB4LCB5ICksIDAgKTtcclxuXHRcdHZlYzQgdjIgPSB0ZXhlbEZldGNoKCBib25lVGV4dHVyZSwgaXZlYzIoIHggKyAxLCB5ICksIDAgKTtcclxuXHRcdHZlYzQgdjMgPSB0ZXhlbEZldGNoKCBib25lVGV4dHVyZSwgaXZlYzIoIHggKyAyLCB5ICksIDAgKTtcclxuXHRcdHZlYzQgdjQgPSB0ZXhlbEZldGNoKCBib25lVGV4dHVyZSwgaXZlYzIoIHggKyAzLCB5ICksIDAgKTtcclxuXHJcblx0XHRyZXR1cm4gbWF0NCggdjEsIHYyLCB2MywgdjQgKTtcclxuXHJcblx0fVxyXG5cclxuI2VuZGlmXHJcbmA7XHJcbiIsImV4cG9ydCBkZWZhdWx0IC8qIGdsc2wgKi9gXHJcbiNpZmRlZiBVU0VfU0tJTk5JTkdcclxuXHJcblx0dmVjNCBza2luVmVydGV4ID0gYmluZE1hdHJpeCAqIHZlYzQoIHRyYW5zZm9ybWVkLCAxLjAgKTtcclxuXHJcblx0dmVjNCBza2lubmVkID0gdmVjNCggMC4wICk7XHJcblx0c2tpbm5lZCArPSBib25lTWF0WCAqIHNraW5WZXJ0ZXggKiBza2luV2VpZ2h0Lng7XHJcblx0c2tpbm5lZCArPSBib25lTWF0WSAqIHNraW5WZXJ0ZXggKiBza2luV2VpZ2h0Lnk7XHJcblx0c2tpbm5lZCArPSBib25lTWF0WiAqIHNraW5WZXJ0ZXggKiBza2luV2VpZ2h0Lno7XHJcblx0c2tpbm5lZCArPSBib25lTWF0VyAqIHNraW5WZXJ0ZXggKiBza2luV2VpZ2h0Lnc7XHJcblxyXG5cdHRyYW5zZm9ybWVkID0gKCBiaW5kTWF0cml4SW52ZXJzZSAqIHNraW5uZWQgKS54eXo7XHJcblxyXG4jZW5kaWZcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuI2lmZGVmIFVTRV9TS0lOTklOR1xyXG5cclxuXHRtYXQ0IHNraW5NYXRyaXggPSBtYXQ0KCAwLjAgKTtcclxuXHRza2luTWF0cml4ICs9IHNraW5XZWlnaHQueCAqIGJvbmVNYXRYO1xyXG5cdHNraW5NYXRyaXggKz0gc2tpbldlaWdodC55ICogYm9uZU1hdFk7XHJcblx0c2tpbk1hdHJpeCArPSBza2luV2VpZ2h0LnogKiBib25lTWF0WjtcclxuXHRza2luTWF0cml4ICs9IHNraW5XZWlnaHQudyAqIGJvbmVNYXRXO1xyXG5cdHNraW5NYXRyaXggPSBiaW5kTWF0cml4SW52ZXJzZSAqIHNraW5NYXRyaXggKiBiaW5kTWF0cml4O1xyXG5cclxuXHRvYmplY3ROb3JtYWwgPSB2ZWM0KCBza2luTWF0cml4ICogdmVjNCggb2JqZWN0Tm9ybWFsLCAwLjAgKSApLnh5ejtcclxuXHJcblx0I2lmZGVmIFVTRV9UQU5HRU5UXHJcblxyXG5cdFx0b2JqZWN0VGFuZ2VudCA9IHZlYzQoIHNraW5NYXRyaXggKiB2ZWM0KCBvYmplY3RUYW5nZW50LCAwLjAgKSApLnh5ejtcclxuXHJcblx0I2VuZGlmXHJcblxyXG4jZW5kaWZcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuZmxvYXQgc3BlY3VsYXJTdHJlbmd0aDtcclxuXHJcbiNpZmRlZiBVU0VfU1BFQ1VMQVJNQVBcclxuXHJcblx0dmVjNCB0ZXhlbFNwZWN1bGFyID0gdGV4dHVyZTJEKCBzcGVjdWxhck1hcCwgdlNwZWN1bGFyTWFwVXYgKTtcclxuXHRzcGVjdWxhclN0cmVuZ3RoID0gdGV4ZWxTcGVjdWxhci5yO1xyXG5cclxuI2Vsc2VcclxuXHJcblx0c3BlY3VsYXJTdHJlbmd0aCA9IDEuMDtcclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWZkZWYgVVNFX1NQRUNVTEFSTUFQXHJcblxyXG5cdHVuaWZvcm0gc2FtcGxlcjJEIHNwZWN1bGFyTWFwO1xyXG5cclxuI2VuZGlmXHJcbmA7XHJcbiIsImV4cG9ydCBkZWZhdWx0IC8qIGdsc2wgKi9gXHJcbiNpZiBkZWZpbmVkKCBUT05FX01BUFBJTkcgKVxyXG5cclxuXHRnbF9GcmFnQ29sb3IucmdiID0gdG9uZU1hcHBpbmcoIGdsX0ZyYWdDb2xvci5yZ2IgKTtcclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWZuZGVmIHNhdHVyYXRlXHJcbi8vIDxjb21tb24+IG1heSBoYXZlIGRlZmluZWQgc2F0dXJhdGUoKSBhbHJlYWR5XHJcbiNkZWZpbmUgc2F0dXJhdGUoIGEgKSBjbGFtcCggYSwgMC4wLCAxLjAgKVxyXG4jZW5kaWZcclxuXHJcbnVuaWZvcm0gZmxvYXQgdG9uZU1hcHBpbmdFeHBvc3VyZTtcclxuXHJcbi8vIGV4cG9zdXJlIG9ubHlcclxudmVjMyBMaW5lYXJUb25lTWFwcGluZyggdmVjMyBjb2xvciApIHtcclxuXHJcblx0cmV0dXJuIHNhdHVyYXRlKCB0b25lTWFwcGluZ0V4cG9zdXJlICogY29sb3IgKTtcclxuXHJcbn1cclxuXHJcbi8vIHNvdXJjZTogaHR0cHM6Ly93d3cuY3MudXRhaC5lZHUvZG9jcy90ZWNocmVwb3J0cy8yMDAyL3BkZi9VVUNTLTAyLTAwMS5wZGZcclxudmVjMyBSZWluaGFyZFRvbmVNYXBwaW5nKCB2ZWMzIGNvbG9yICkge1xyXG5cclxuXHRjb2xvciAqPSB0b25lTWFwcGluZ0V4cG9zdXJlO1xyXG5cdHJldHVybiBzYXR1cmF0ZSggY29sb3IgLyAoIHZlYzMoIDEuMCApICsgY29sb3IgKSApO1xyXG5cclxufVxyXG5cclxuLy8gc291cmNlOiBodHRwOi8vZmlsbWljd29ybGRzLmNvbS9ibG9nL2ZpbG1pYy10b25lbWFwcGluZy1vcGVyYXRvcnMvXHJcbnZlYzMgT3B0aW1pemVkQ2luZW9uVG9uZU1hcHBpbmcoIHZlYzMgY29sb3IgKSB7XHJcblxyXG5cdC8vIG9wdGltaXplZCBmaWxtaWMgb3BlcmF0b3IgYnkgSmltIEhlamwgYW5kIFJpY2hhcmQgQnVyZ2Vzcy1EYXdzb25cclxuXHRjb2xvciAqPSB0b25lTWFwcGluZ0V4cG9zdXJlO1xyXG5cdGNvbG9yID0gbWF4KCB2ZWMzKCAwLjAgKSwgY29sb3IgLSAwLjAwNCApO1xyXG5cdHJldHVybiBwb3coICggY29sb3IgKiAoIDYuMiAqIGNvbG9yICsgMC41ICkgKSAvICggY29sb3IgKiAoIDYuMiAqIGNvbG9yICsgMS43ICkgKyAwLjA2ICksIHZlYzMoIDIuMiApICk7XHJcblxyXG59XHJcblxyXG4vLyBzb3VyY2U6IGh0dHBzOi8vZ2l0aHViLmNvbS9zZWxmc2hhZG93L2x0Y19jb2RlL2Jsb2IvbWFzdGVyL3dlYmdsL3NoYWRlcnMvbHRjL2x0Y19ibGl0LmZzXHJcbnZlYzMgUlJUQW5kT0RURml0KCB2ZWMzIHYgKSB7XHJcblxyXG5cdHZlYzMgYSA9IHYgKiAoIHYgKyAwLjAyNDU3ODYgKSAtIDAuMDAwMDkwNTM3O1xyXG5cdHZlYzMgYiA9IHYgKiAoIDAuOTgzNzI5ICogdiArIDAuNDMyOTUxMCApICsgMC4yMzgwODE7XHJcblx0cmV0dXJuIGEgLyBiO1xyXG5cclxufVxyXG5cclxuLy8gdGhpcyBpbXBsZW1lbnRhdGlvbiBvZiBBQ0VTIGlzIG1vZGlmaWVkIHRvIGFjY29tbW9kYXRlIGEgYnJpZ2h0ZXIgdmlld2luZyBlbnZpcm9ubWVudC5cclxuLy8gdGhlIHNjYWxlIGZhY3RvciBvZiAxLzAuNiBpcyBzdWJqZWN0aXZlLiBzZWUgZGlzY3Vzc2lvbiBpbiAjMTk2MjEuXHJcblxyXG52ZWMzIEFDRVNGaWxtaWNUb25lTWFwcGluZyggdmVjMyBjb2xvciApIHtcclxuXHJcblx0Ly8gc1JHQiA9PiBYWVogPT4gRDY1XzJfRDYwID0+IEFQMSA9PiBSUlRfU0FUXHJcblx0Y29uc3QgbWF0MyBBQ0VTSW5wdXRNYXQgPSBtYXQzKFxyXG5cdFx0dmVjMyggMC41OTcxOSwgMC4wNzYwMCwgMC4wMjg0MCApLCAvLyB0cmFuc3Bvc2VkIGZyb20gc291cmNlXHJcblx0XHR2ZWMzKCAwLjM1NDU4LCAwLjkwODM0LCAwLjEzMzgzICksXHJcblx0XHR2ZWMzKCAwLjA0ODIzLCAwLjAxNTY2LCAwLjgzNzc3IClcclxuXHQpO1xyXG5cclxuXHQvLyBPRFRfU0FUID0+IFhZWiA9PiBENjBfMl9ENjUgPT4gc1JHQlxyXG5cdGNvbnN0IG1hdDMgQUNFU091dHB1dE1hdCA9IG1hdDMoXHJcblx0XHR2ZWMzKCAgMS42MDQ3NSwgLTAuMTAyMDgsIC0wLjAwMzI3ICksIC8vIHRyYW5zcG9zZWQgZnJvbSBzb3VyY2VcclxuXHRcdHZlYzMoIC0wLjUzMTA4LCAgMS4xMDgxMywgLTAuMDcyNzYgKSxcclxuXHRcdHZlYzMoIC0wLjA3MzY3LCAtMC4wMDYwNSwgIDEuMDc2MDIgKVxyXG5cdCk7XHJcblxyXG5cdGNvbG9yICo9IHRvbmVNYXBwaW5nRXhwb3N1cmUgLyAwLjY7XHJcblxyXG5cdGNvbG9yID0gQUNFU0lucHV0TWF0ICogY29sb3I7XHJcblxyXG5cdC8vIEFwcGx5IFJSVCBhbmQgT0RUXHJcblx0Y29sb3IgPSBSUlRBbmRPRFRGaXQoIGNvbG9yICk7XHJcblxyXG5cdGNvbG9yID0gQUNFU091dHB1dE1hdCAqIGNvbG9yO1xyXG5cclxuXHQvLyBDbGFtcCB0byBbMCwgMV1cclxuXHRyZXR1cm4gc2F0dXJhdGUoIGNvbG9yICk7XHJcblxyXG59XHJcblxyXG4vLyBNYXRyaWNlcyBmb3IgcmVjIDIwMjAgPD4gcmVjIDcwOSBjb2xvciBzcGFjZSBjb252ZXJzaW9uXHJcbi8vIG1hdHJpeCBwcm92aWRlZCBpbiByb3ctbWFqb3Igb3JkZXIgc28gaXQgaGFzIGJlZW4gdHJhbnNwb3NlZFxyXG4vLyBodHRwczovL3d3dy5pdHUuaW50L3B1Yi9SLVJFUC1CVC4yNDA3LTIwMTdcclxuY29uc3QgbWF0MyBMSU5FQVJfUkVDMjAyMF9UT19MSU5FQVJfU1JHQiA9IG1hdDMoXHJcblx0dmVjMyggMS42NjA1LCAtIDAuMTI0NiwgLSAwLjAxODIgKSxcclxuXHR2ZWMzKCAtIDAuNTg3NiwgMS4xMzI5LCAtIDAuMTAwNiApLFxyXG5cdHZlYzMoIC0gMC4wNzI4LCAtIDAuMDA4MywgMS4xMTg3IClcclxuKTtcclxuXHJcbmNvbnN0IG1hdDMgTElORUFSX1NSR0JfVE9fTElORUFSX1JFQzIwMjAgPSBtYXQzKFxyXG5cdHZlYzMoIDAuNjI3NCwgMC4wNjkxLCAwLjAxNjQgKSxcclxuXHR2ZWMzKCAwLjMyOTMsIDAuOTE5NSwgMC4wODgwICksXHJcblx0dmVjMyggMC4wNDMzLCAwLjAxMTMsIDAuODk1NiApXHJcbik7XHJcblxyXG4vLyBodHRwczovL2lvbGl0ZS1lbmdpbmUuY29tL2Jsb2dfcG9zdHMvbWluaW1hbF9hZ3hfaW1wbGVtZW50YXRpb25cclxuLy8gTWVhbiBlcnJvcl4yOiAzLjY3MDUxNDFlLTA2XHJcbnZlYzMgYWd4RGVmYXVsdENvbnRyYXN0QXBwcm94KCB2ZWMzIHggKSB7XHJcblxyXG5cdHZlYzMgeDIgPSB4ICogeDtcclxuXHR2ZWMzIHg0ID0geDIgKiB4MjtcclxuXHJcblx0cmV0dXJuICsgMTUuNSAqIHg0ICogeDJcclxuXHRcdC0gNDAuMTQgKiB4NCAqIHhcclxuXHRcdCsgMzEuOTYgKiB4NFxyXG5cdFx0LSA2Ljg2OCAqIHgyICogeFxyXG5cdFx0KyAwLjQyOTggKiB4MlxyXG5cdFx0KyAwLjExOTEgKiB4XHJcblx0XHQtIDAuMDAyMzI7XHJcblxyXG59XHJcblxyXG4vLyBBZ1ggVG9uZSBNYXBwaW5nIGltcGxlbWVudGF0aW9uIGJhc2VkIG9uIEZpbGFtZW50LCB3aGljaCBpbiB0dXJuIGlzIGJhc2VkXHJcbi8vIG9uIEJsZW5kZXIncyBpbXBsZW1lbnRhdGlvbiB1c2luZyByZWMgMjAyMCBwcmltYXJpZXNcclxuLy8gaHR0cHM6Ly9naXRodWIuY29tL2dvb2dsZS9maWxhbWVudC9wdWxsLzcyMzZcclxuLy8gSW5wdXRzIGFuZCBvdXRwdXRzIGFyZSBlbmNvZGVkIGFzIExpbmVhci1zUkdCLlxyXG5cclxudmVjMyBBZ1hUb25lTWFwcGluZyggdmVjMyBjb2xvciApIHtcclxuXHJcblx0Ly8gQWdYIGNvbnN0YW50c1xyXG5cdGNvbnN0IG1hdDMgQWdYSW5zZXRNYXRyaXggPSBtYXQzKFxyXG5cdFx0dmVjMyggMC44NTY2MjcxNTMzMTU5ODMsIDAuMTM3MzE4OTcyOTI5ODQ3LCAwLjExMTg5ODIxMjk5OTk1ICksXHJcblx0XHR2ZWMzKCAwLjA5NTEyMTI0MDUzODE1ODgsIDAuNzYxMjQxOTkwNjAyNTkxLCAwLjA3Njc5OTQxODYwMzE5MDMgKSxcclxuXHRcdHZlYzMoIDAuMDQ4MjUxNjA2MTQ1ODU4MywgMC4xMDE0MzkwMzY0Njc1NjIsIDAuODExMzAyMzY4Mzk2ODU5IClcclxuXHQpO1xyXG5cclxuXHQvLyBleHBsaWNpdCBBZ1hPdXRzZXRNYXRyaXggZ2VuZXJhdGVkIGZyb20gRmlsYW1lbnRzIEFnWE91dHNldE1hdHJpeEludlxyXG5cdGNvbnN0IG1hdDMgQWdYT3V0c2V0TWF0cml4ID0gbWF0MyhcclxuXHRcdHZlYzMoIDEuMTI3MTAwNTgxODE0NDM2OCwgLSAwLjE0MTMyOTc2MzQ5ODQzODMsIC0gMC4xNDEzMjk3NjM0OTg0MzgyNiApLFxyXG5cdFx0dmVjMyggLSAwLjExMDYwNjY0MzA5NjYwMzIzLCAxLjE1NzgyMzcwMjIxNjI3MiwgLSAwLjExMDYwNjY0MzA5NjYwMjk0ICksXHJcblx0XHR2ZWMzKCAtIDAuMDE2NDkzOTM4NzE3ODM0NTczLCAtIDAuMDE2NDkzOTM4NzE3ODM0MjU3LCAxLjI1MTkzNjQwNjU5NTA0MDUgKVxyXG5cdCk7XHJcblxyXG5cdC8vIExPRzJfTUlOICAgICAgPSAtMTAuMFxyXG5cdC8vIExPRzJfTUFYICAgICAgPSAgKzYuNVxyXG5cdC8vIE1JRERMRV9HUkFZICAgPSAgMC4xOFxyXG5cdGNvbnN0IGZsb2F0IEFneE1pbkV2ID0gLSAxMi40NzM5MzsgIC8vIGxvZzIoIHBvdyggMiwgTE9HMl9NSU4gKSAqIE1JRERMRV9HUkFZIClcclxuXHRjb25zdCBmbG9hdCBBZ3hNYXhFdiA9IDQuMDI2MDY5OyAgICAvLyBsb2cyKCBwb3coIDIsIExPRzJfTUFYICkgKiBNSURETEVfR1JBWSApXHJcblxyXG5cdGNvbG9yICo9IHRvbmVNYXBwaW5nRXhwb3N1cmU7XHJcblxyXG5cdGNvbG9yID0gTElORUFSX1NSR0JfVE9fTElORUFSX1JFQzIwMjAgKiBjb2xvcjtcclxuXHJcblx0Y29sb3IgPSBBZ1hJbnNldE1hdHJpeCAqIGNvbG9yO1xyXG5cclxuXHQvLyBMb2cyIGVuY29kaW5nXHJcblx0Y29sb3IgPSBtYXgoIGNvbG9yLCAxZS0xMCApOyAvLyBhdm9pZCAwIG9yIG5lZ2F0aXZlIG51bWJlcnMgZm9yIGxvZzJcclxuXHRjb2xvciA9IGxvZzIoIGNvbG9yICk7XHJcblx0Y29sb3IgPSAoIGNvbG9yIC0gQWd4TWluRXYgKSAvICggQWd4TWF4RXYgLSBBZ3hNaW5FdiApO1xyXG5cclxuXHRjb2xvciA9IGNsYW1wKCBjb2xvciwgMC4wLCAxLjAgKTtcclxuXHJcblx0Ly8gQXBwbHkgc2lnbW9pZFxyXG5cdGNvbG9yID0gYWd4RGVmYXVsdENvbnRyYXN0QXBwcm94KCBjb2xvciApO1xyXG5cclxuXHQvLyBBcHBseSBBZ1ggbG9va1xyXG5cdC8vIHYgPSBhZ3hMb29rKHYsIGxvb2spO1xyXG5cclxuXHRjb2xvciA9IEFnWE91dHNldE1hdHJpeCAqIGNvbG9yO1xyXG5cclxuXHQvLyBMaW5lYXJpemVcclxuXHRjb2xvciA9IHBvdyggbWF4KCB2ZWMzKCAwLjAgKSwgY29sb3IgKSwgdmVjMyggMi4yICkgKTtcclxuXHJcblx0Y29sb3IgPSBMSU5FQVJfUkVDMjAyMF9UT19MSU5FQVJfU1JHQiAqIGNvbG9yO1xyXG5cclxuXHQvLyBHYW11dCBtYXBwaW5nLiBTaW1wbGUgY2xhbXAgZm9yIG5vdy5cclxuXHRjb2xvciA9IGNsYW1wKCBjb2xvciwgMC4wLCAxLjAgKTtcclxuXHJcblx0cmV0dXJuIGNvbG9yO1xyXG5cclxufVxyXG5cclxudmVjMyBDdXN0b21Ub25lTWFwcGluZyggdmVjMyBjb2xvciApIHsgcmV0dXJuIGNvbG9yOyB9XHJcbmA7XHJcbiIsImV4cG9ydCBkZWZhdWx0IC8qIGdsc2wgKi9gXHJcbiNpZmRlZiBVU0VfVFJBTlNNSVNTSU9OXHJcblxyXG5cdG1hdGVyaWFsLnRyYW5zbWlzc2lvbiA9IHRyYW5zbWlzc2lvbjtcclxuXHRtYXRlcmlhbC50cmFuc21pc3Npb25BbHBoYSA9IDEuMDtcclxuXHRtYXRlcmlhbC50aGlja25lc3MgPSB0aGlja25lc3M7XHJcblx0bWF0ZXJpYWwuYXR0ZW51YXRpb25EaXN0YW5jZSA9IGF0dGVudWF0aW9uRGlzdGFuY2U7XHJcblx0bWF0ZXJpYWwuYXR0ZW51YXRpb25Db2xvciA9IGF0dGVudWF0aW9uQ29sb3I7XHJcblxyXG5cdCNpZmRlZiBVU0VfVFJBTlNNSVNTSU9OTUFQXHJcblxyXG5cdFx0bWF0ZXJpYWwudHJhbnNtaXNzaW9uICo9IHRleHR1cmUyRCggdHJhbnNtaXNzaW9uTWFwLCB2VHJhbnNtaXNzaW9uTWFwVXYgKS5yO1xyXG5cclxuXHQjZW5kaWZcclxuXHJcblx0I2lmZGVmIFVTRV9USElDS05FU1NNQVBcclxuXHJcblx0XHRtYXRlcmlhbC50aGlja25lc3MgKj0gdGV4dHVyZTJEKCB0aGlja25lc3NNYXAsIHZUaGlja25lc3NNYXBVdiApLmc7XHJcblxyXG5cdCNlbmRpZlxyXG5cclxuXHR2ZWMzIHBvcyA9IHZXb3JsZFBvc2l0aW9uO1xyXG5cdHZlYzMgdiA9IG5vcm1hbGl6ZSggY2FtZXJhUG9zaXRpb24gLSBwb3MgKTtcclxuXHR2ZWMzIG4gPSBpbnZlcnNlVHJhbnNmb3JtRGlyZWN0aW9uKCBub3JtYWwsIHZpZXdNYXRyaXggKTtcclxuXHJcblx0dmVjNCB0cmFuc21pdHRlZCA9IGdldElCTFZvbHVtZVJlZnJhY3Rpb24oXHJcblx0XHRuLCB2LCBtYXRlcmlhbC5yb3VnaG5lc3MsIG1hdGVyaWFsLmRpZmZ1c2VDb2xvciwgbWF0ZXJpYWwuc3BlY3VsYXJDb2xvciwgbWF0ZXJpYWwuc3BlY3VsYXJGOTAsXHJcblx0XHRwb3MsIG1vZGVsTWF0cml4LCB2aWV3TWF0cml4LCBwcm9qZWN0aW9uTWF0cml4LCBtYXRlcmlhbC5pb3IsIG1hdGVyaWFsLnRoaWNrbmVzcyxcclxuXHRcdG1hdGVyaWFsLmF0dGVudWF0aW9uQ29sb3IsIG1hdGVyaWFsLmF0dGVudWF0aW9uRGlzdGFuY2UgKTtcclxuXHJcblx0bWF0ZXJpYWwudHJhbnNtaXNzaW9uQWxwaGEgPSBtaXgoIG1hdGVyaWFsLnRyYW5zbWlzc2lvbkFscGhhLCB0cmFuc21pdHRlZC5hLCBtYXRlcmlhbC50cmFuc21pc3Npb24gKTtcclxuXHJcblx0dG90YWxEaWZmdXNlID0gbWl4KCB0b3RhbERpZmZ1c2UsIHRyYW5zbWl0dGVkLnJnYiwgbWF0ZXJpYWwudHJhbnNtaXNzaW9uICk7XHJcblxyXG4jZW5kaWZcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuI2lmZGVmIFVTRV9UUkFOU01JU1NJT05cclxuXHJcblx0Ly8gVHJhbnNtaXNzaW9uIGNvZGUgaXMgYmFzZWQgb24gZ2xURi1TYW1wbGVyLVZpZXdlclxyXG5cdC8vIGh0dHBzOi8vZ2l0aHViLmNvbS9LaHJvbm9zR3JvdXAvZ2xURi1TYW1wbGUtVmlld2VyXHJcblxyXG5cdHVuaWZvcm0gZmxvYXQgdHJhbnNtaXNzaW9uO1xyXG5cdHVuaWZvcm0gZmxvYXQgdGhpY2tuZXNzO1xyXG5cdHVuaWZvcm0gZmxvYXQgYXR0ZW51YXRpb25EaXN0YW5jZTtcclxuXHR1bmlmb3JtIHZlYzMgYXR0ZW51YXRpb25Db2xvcjtcclxuXHJcblx0I2lmZGVmIFVTRV9UUkFOU01JU1NJT05NQVBcclxuXHJcblx0XHR1bmlmb3JtIHNhbXBsZXIyRCB0cmFuc21pc3Npb25NYXA7XHJcblxyXG5cdCNlbmRpZlxyXG5cclxuXHQjaWZkZWYgVVNFX1RISUNLTkVTU01BUFxyXG5cclxuXHRcdHVuaWZvcm0gc2FtcGxlcjJEIHRoaWNrbmVzc01hcDtcclxuXHJcblx0I2VuZGlmXHJcblxyXG5cdHVuaWZvcm0gdmVjMiB0cmFuc21pc3Npb25TYW1wbGVyU2l6ZTtcclxuXHR1bmlmb3JtIHNhbXBsZXIyRCB0cmFuc21pc3Npb25TYW1wbGVyTWFwO1xyXG5cclxuXHR1bmlmb3JtIG1hdDQgbW9kZWxNYXRyaXg7XHJcblx0dW5pZm9ybSBtYXQ0IHByb2plY3Rpb25NYXRyaXg7XHJcblxyXG5cdHZhcnlpbmcgdmVjMyB2V29ybGRQb3NpdGlvbjtcclxuXHJcblx0Ly8gTWlwcGVkIEJpY3ViaWMgVGV4dHVyZSBGaWx0ZXJpbmcgYnkgTjhcclxuXHQvLyBodHRwczovL3d3dy5zaGFkZXJ0b3kuY29tL3ZpZXcvRGwyU0RXXHJcblxyXG5cdGZsb2F0IHcwKCBmbG9hdCBhICkge1xyXG5cclxuXHRcdHJldHVybiAoIDEuMCAvIDYuMCApICogKCBhICogKCBhICogKCAtIGEgKyAzLjAgKSAtIDMuMCApICsgMS4wICk7XHJcblxyXG5cdH1cclxuXHJcblx0ZmxvYXQgdzEoIGZsb2F0IGEgKSB7XHJcblxyXG5cdFx0cmV0dXJuICggMS4wIC8gNi4wICkgKiAoIGEgKiAgYSAqICggMy4wICogYSAtIDYuMCApICsgNC4wICk7XHJcblxyXG5cdH1cclxuXHJcblx0ZmxvYXQgdzIoIGZsb2F0IGEgKXtcclxuXHJcblx0XHRyZXR1cm4gKCAxLjAgLyA2LjAgKSAqICggYSAqICggYSAqICggLSAzLjAgKiBhICsgMy4wICkgKyAzLjAgKSArIDEuMCApO1xyXG5cclxuXHR9XHJcblxyXG5cdGZsb2F0IHczKCBmbG9hdCBhICkge1xyXG5cclxuXHRcdHJldHVybiAoIDEuMCAvIDYuMCApICogKCBhICogYSAqIGEgKTtcclxuXHJcblx0fVxyXG5cclxuXHQvLyBnMCBhbmQgZzEgYXJlIHRoZSB0d28gYW1wbGl0dWRlIGZ1bmN0aW9uc1xyXG5cdGZsb2F0IGcwKCBmbG9hdCBhICkge1xyXG5cclxuXHRcdHJldHVybiB3MCggYSApICsgdzEoIGEgKTtcclxuXHJcblx0fVxyXG5cclxuXHRmbG9hdCBnMSggZmxvYXQgYSApIHtcclxuXHJcblx0XHRyZXR1cm4gdzIoIGEgKSArIHczKCBhICk7XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gaDAgYW5kIGgxIGFyZSB0aGUgdHdvIG9mZnNldCBmdW5jdGlvbnNcclxuXHRmbG9hdCBoMCggZmxvYXQgYSApIHtcclxuXHJcblx0XHRyZXR1cm4gLSAxLjAgKyB3MSggYSApIC8gKCB3MCggYSApICsgdzEoIGEgKSApO1xyXG5cclxuXHR9XHJcblxyXG5cdGZsb2F0IGgxKCBmbG9hdCBhICkge1xyXG5cclxuXHRcdHJldHVybiAxLjAgKyB3MyggYSApIC8gKCB3MiggYSApICsgdzMoIGEgKSApO1xyXG5cclxuXHR9XHJcblxyXG5cdHZlYzQgYmljdWJpYyggc2FtcGxlcjJEIHRleCwgdmVjMiB1diwgdmVjNCB0ZXhlbFNpemUsIGZsb2F0IGxvZCApIHtcclxuXHJcblx0XHR1diA9IHV2ICogdGV4ZWxTaXplLnp3ICsgMC41O1xyXG5cclxuXHRcdHZlYzIgaXV2ID0gZmxvb3IoIHV2ICk7XHJcblx0XHR2ZWMyIGZ1diA9IGZyYWN0KCB1diApO1xyXG5cclxuXHRcdGZsb2F0IGcweCA9IGcwKCBmdXYueCApO1xyXG5cdFx0ZmxvYXQgZzF4ID0gZzEoIGZ1di54ICk7XHJcblx0XHRmbG9hdCBoMHggPSBoMCggZnV2LnggKTtcclxuXHRcdGZsb2F0IGgxeCA9IGgxKCBmdXYueCApO1xyXG5cdFx0ZmxvYXQgaDB5ID0gaDAoIGZ1di55ICk7XHJcblx0XHRmbG9hdCBoMXkgPSBoMSggZnV2LnkgKTtcclxuXHJcblx0XHR2ZWMyIHAwID0gKCB2ZWMyKCBpdXYueCArIGgweCwgaXV2LnkgKyBoMHkgKSAtIDAuNSApICogdGV4ZWxTaXplLnh5O1xyXG5cdFx0dmVjMiBwMSA9ICggdmVjMiggaXV2LnggKyBoMXgsIGl1di55ICsgaDB5ICkgLSAwLjUgKSAqIHRleGVsU2l6ZS54eTtcclxuXHRcdHZlYzIgcDIgPSAoIHZlYzIoIGl1di54ICsgaDB4LCBpdXYueSArIGgxeSApIC0gMC41ICkgKiB0ZXhlbFNpemUueHk7XHJcblx0XHR2ZWMyIHAzID0gKCB2ZWMyKCBpdXYueCArIGgxeCwgaXV2LnkgKyBoMXkgKSAtIDAuNSApICogdGV4ZWxTaXplLnh5O1xyXG5cclxuXHRcdHJldHVybiBnMCggZnV2LnkgKSAqICggZzB4ICogdGV4dHVyZUxvZCggdGV4LCBwMCwgbG9kICkgKyBnMXggKiB0ZXh0dXJlTG9kKCB0ZXgsIHAxLCBsb2QgKSApICtcclxuXHRcdFx0ZzEoIGZ1di55ICkgKiAoIGcweCAqIHRleHR1cmVMb2QoIHRleCwgcDIsIGxvZCApICsgZzF4ICogdGV4dHVyZUxvZCggdGV4LCBwMywgbG9kICkgKTtcclxuXHJcblx0fVxyXG5cclxuXHR2ZWM0IHRleHR1cmVCaWN1YmljKCBzYW1wbGVyMkQgc2FtcGxlciwgdmVjMiB1diwgZmxvYXQgbG9kICkge1xyXG5cclxuXHRcdHZlYzIgZkxvZFNpemUgPSB2ZWMyKCB0ZXh0dXJlU2l6ZSggc2FtcGxlciwgaW50KCBsb2QgKSApICk7XHJcblx0XHR2ZWMyIGNMb2RTaXplID0gdmVjMiggdGV4dHVyZVNpemUoIHNhbXBsZXIsIGludCggbG9kICsgMS4wICkgKSApO1xyXG5cdFx0dmVjMiBmTG9kU2l6ZUludiA9IDEuMCAvIGZMb2RTaXplO1xyXG5cdFx0dmVjMiBjTG9kU2l6ZUludiA9IDEuMCAvIGNMb2RTaXplO1xyXG5cdFx0dmVjNCBmU2FtcGxlID0gYmljdWJpYyggc2FtcGxlciwgdXYsIHZlYzQoIGZMb2RTaXplSW52LCBmTG9kU2l6ZSApLCBmbG9vciggbG9kICkgKTtcclxuXHRcdHZlYzQgY1NhbXBsZSA9IGJpY3ViaWMoIHNhbXBsZXIsIHV2LCB2ZWM0KCBjTG9kU2l6ZUludiwgY0xvZFNpemUgKSwgY2VpbCggbG9kICkgKTtcclxuXHRcdHJldHVybiBtaXgoIGZTYW1wbGUsIGNTYW1wbGUsIGZyYWN0KCBsb2QgKSApO1xyXG5cclxuXHR9XHJcblxyXG5cdHZlYzMgZ2V0Vm9sdW1lVHJhbnNtaXNzaW9uUmF5KCBjb25zdCBpbiB2ZWMzIG4sIGNvbnN0IGluIHZlYzMgdiwgY29uc3QgaW4gZmxvYXQgdGhpY2tuZXNzLCBjb25zdCBpbiBmbG9hdCBpb3IsIGNvbnN0IGluIG1hdDQgbW9kZWxNYXRyaXggKSB7XHJcblxyXG5cdFx0Ly8gRGlyZWN0aW9uIG9mIHJlZnJhY3RlZCBsaWdodC5cclxuXHRcdHZlYzMgcmVmcmFjdGlvblZlY3RvciA9IHJlZnJhY3QoIC0gdiwgbm9ybWFsaXplKCBuICksIDEuMCAvIGlvciApO1xyXG5cclxuXHRcdC8vIENvbXB1dGUgcm90YXRpb24taW5kZXBlbmRhbnQgc2NhbGluZyBvZiB0aGUgbW9kZWwgbWF0cml4LlxyXG5cdFx0dmVjMyBtb2RlbFNjYWxlO1xyXG5cdFx0bW9kZWxTY2FsZS54ID0gbGVuZ3RoKCB2ZWMzKCBtb2RlbE1hdHJpeFsgMCBdLnh5eiApICk7XHJcblx0XHRtb2RlbFNjYWxlLnkgPSBsZW5ndGgoIHZlYzMoIG1vZGVsTWF0cml4WyAxIF0ueHl6ICkgKTtcclxuXHRcdG1vZGVsU2NhbGUueiA9IGxlbmd0aCggdmVjMyggbW9kZWxNYXRyaXhbIDIgXS54eXogKSApO1xyXG5cclxuXHRcdC8vIFRoZSB0aGlja25lc3MgaXMgc3BlY2lmaWVkIGluIGxvY2FsIHNwYWNlLlxyXG5cdFx0cmV0dXJuIG5vcm1hbGl6ZSggcmVmcmFjdGlvblZlY3RvciApICogdGhpY2tuZXNzICogbW9kZWxTY2FsZTtcclxuXHJcblx0fVxyXG5cclxuXHRmbG9hdCBhcHBseUlvclRvUm91Z2huZXNzKCBjb25zdCBpbiBmbG9hdCByb3VnaG5lc3MsIGNvbnN0IGluIGZsb2F0IGlvciApIHtcclxuXHJcblx0XHQvLyBTY2FsZSByb3VnaG5lc3Mgd2l0aCBJT1Igc28gdGhhdCBhbiBJT1Igb2YgMS4wIHJlc3VsdHMgaW4gbm8gbWljcm9mYWNldCByZWZyYWN0aW9uIGFuZFxyXG5cdFx0Ly8gYW4gSU9SIG9mIDEuNSByZXN1bHRzIGluIHRoZSBkZWZhdWx0IGFtb3VudCBvZiBtaWNyb2ZhY2V0IHJlZnJhY3Rpb24uXHJcblx0XHRyZXR1cm4gcm91Z2huZXNzICogY2xhbXAoIGlvciAqIDIuMCAtIDIuMCwgMC4wLCAxLjAgKTtcclxuXHJcblx0fVxyXG5cclxuXHR2ZWM0IGdldFRyYW5zbWlzc2lvblNhbXBsZSggY29uc3QgaW4gdmVjMiBmcmFnQ29vcmQsIGNvbnN0IGluIGZsb2F0IHJvdWdobmVzcywgY29uc3QgaW4gZmxvYXQgaW9yICkge1xyXG5cclxuXHRcdGZsb2F0IGxvZCA9IGxvZzIoIHRyYW5zbWlzc2lvblNhbXBsZXJTaXplLnggKSAqIGFwcGx5SW9yVG9Sb3VnaG5lc3MoIHJvdWdobmVzcywgaW9yICk7XHJcblx0XHRyZXR1cm4gdGV4dHVyZUJpY3ViaWMoIHRyYW5zbWlzc2lvblNhbXBsZXJNYXAsIGZyYWdDb29yZC54eSwgbG9kICk7XHJcblxyXG5cdH1cclxuXHJcblx0dmVjMyB2b2x1bWVBdHRlbnVhdGlvbiggY29uc3QgaW4gZmxvYXQgdHJhbnNtaXNzaW9uRGlzdGFuY2UsIGNvbnN0IGluIHZlYzMgYXR0ZW51YXRpb25Db2xvciwgY29uc3QgaW4gZmxvYXQgYXR0ZW51YXRpb25EaXN0YW5jZSApIHtcclxuXHJcblx0XHRpZiAoIGlzaW5mKCBhdHRlbnVhdGlvbkRpc3RhbmNlICkgKSB7XHJcblxyXG5cdFx0XHQvLyBBdHRlbnVhdGlvbiBkaXN0YW5jZSBpcyAr4oieLCBpLmUuIHRoZSB0cmFuc21pdHRlZCBjb2xvciBpcyBub3QgYXR0ZW51YXRlZCBhdCBhbGwuXHJcblx0XHRcdHJldHVybiB2ZWMzKCAxLjAgKTtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0Ly8gQ29tcHV0ZSBsaWdodCBhdHRlbnVhdGlvbiB1c2luZyBCZWVyJ3MgbGF3LlxyXG5cdFx0XHR2ZWMzIGF0dGVudWF0aW9uQ29lZmZpY2llbnQgPSAtbG9nKCBhdHRlbnVhdGlvbkNvbG9yICkgLyBhdHRlbnVhdGlvbkRpc3RhbmNlO1xyXG5cdFx0XHR2ZWMzIHRyYW5zbWl0dGFuY2UgPSBleHAoIC0gYXR0ZW51YXRpb25Db2VmZmljaWVudCAqIHRyYW5zbWlzc2lvbkRpc3RhbmNlICk7IC8vIEJlZXIncyBsYXdcclxuXHRcdFx0cmV0dXJuIHRyYW5zbWl0dGFuY2U7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdHZlYzQgZ2V0SUJMVm9sdW1lUmVmcmFjdGlvbiggY29uc3QgaW4gdmVjMyBuLCBjb25zdCBpbiB2ZWMzIHYsIGNvbnN0IGluIGZsb2F0IHJvdWdobmVzcywgY29uc3QgaW4gdmVjMyBkaWZmdXNlQ29sb3IsXHJcblx0XHRjb25zdCBpbiB2ZWMzIHNwZWN1bGFyQ29sb3IsIGNvbnN0IGluIGZsb2F0IHNwZWN1bGFyRjkwLCBjb25zdCBpbiB2ZWMzIHBvc2l0aW9uLCBjb25zdCBpbiBtYXQ0IG1vZGVsTWF0cml4LFxyXG5cdFx0Y29uc3QgaW4gbWF0NCB2aWV3TWF0cml4LCBjb25zdCBpbiBtYXQ0IHByb2pNYXRyaXgsIGNvbnN0IGluIGZsb2F0IGlvciwgY29uc3QgaW4gZmxvYXQgdGhpY2tuZXNzLFxyXG5cdFx0Y29uc3QgaW4gdmVjMyBhdHRlbnVhdGlvbkNvbG9yLCBjb25zdCBpbiBmbG9hdCBhdHRlbnVhdGlvbkRpc3RhbmNlICkge1xyXG5cclxuXHRcdHZlYzMgdHJhbnNtaXNzaW9uUmF5ID0gZ2V0Vm9sdW1lVHJhbnNtaXNzaW9uUmF5KCBuLCB2LCB0aGlja25lc3MsIGlvciwgbW9kZWxNYXRyaXggKTtcclxuXHRcdHZlYzMgcmVmcmFjdGVkUmF5RXhpdCA9IHBvc2l0aW9uICsgdHJhbnNtaXNzaW9uUmF5O1xyXG5cclxuXHRcdC8vIFByb2plY3QgcmVmcmFjdGVkIHZlY3RvciBvbiB0aGUgZnJhbWVidWZmZXIsIHdoaWxlIG1hcHBpbmcgdG8gbm9ybWFsaXplZCBkZXZpY2UgY29vcmRpbmF0ZXMuXHJcblx0XHR2ZWM0IG5kY1BvcyA9IHByb2pNYXRyaXggKiB2aWV3TWF0cml4ICogdmVjNCggcmVmcmFjdGVkUmF5RXhpdCwgMS4wICk7XHJcblx0XHR2ZWMyIHJlZnJhY3Rpb25Db29yZHMgPSBuZGNQb3MueHkgLyBuZGNQb3MudztcclxuXHRcdHJlZnJhY3Rpb25Db29yZHMgKz0gMS4wO1xyXG5cdFx0cmVmcmFjdGlvbkNvb3JkcyAvPSAyLjA7XHJcblxyXG5cdFx0Ly8gU2FtcGxlIGZyYW1lYnVmZmVyIHRvIGdldCBwaXhlbCB0aGUgcmVmcmFjdGVkIHJheSBoaXRzLlxyXG5cdFx0dmVjNCB0cmFuc21pdHRlZExpZ2h0ID0gZ2V0VHJhbnNtaXNzaW9uU2FtcGxlKCByZWZyYWN0aW9uQ29vcmRzLCByb3VnaG5lc3MsIGlvciApO1xyXG5cclxuXHRcdHZlYzMgdHJhbnNtaXR0YW5jZSA9IGRpZmZ1c2VDb2xvciAqIHZvbHVtZUF0dGVudWF0aW9uKCBsZW5ndGgoIHRyYW5zbWlzc2lvblJheSApLCBhdHRlbnVhdGlvbkNvbG9yLCBhdHRlbnVhdGlvbkRpc3RhbmNlICk7XHJcblx0XHR2ZWMzIGF0dGVudWF0ZWRDb2xvciA9IHRyYW5zbWl0dGFuY2UgKiB0cmFuc21pdHRlZExpZ2h0LnJnYjtcclxuXHJcblx0XHQvLyBHZXQgdGhlIHNwZWN1bGFyIGNvbXBvbmVudC5cclxuXHRcdHZlYzMgRiA9IEVudmlyb25tZW50QlJERiggbiwgdiwgc3BlY3VsYXJDb2xvciwgc3BlY3VsYXJGOTAsIHJvdWdobmVzcyApO1xyXG5cclxuXHRcdC8vIEFzIGxlc3MgbGlnaHQgaXMgdHJhbnNtaXR0ZWQsIHRoZSBvcGFjaXR5IHNob3VsZCBiZSBpbmNyZWFzZWQuIFRoaXMgc2ltcGxlIGFwcHJveGltYXRpb24gZG9lcyBhIGRlY2VudCBqb2IgXHJcblx0XHQvLyBvZiBtb2R1bGF0aW5nIGEgQ1NTIGJhY2tncm91bmQsIGFuZCBoYXMgbm8gZWZmZWN0IHdoZW4gdGhlIGJ1ZmZlciBpcyBvcGFxdWUsIGR1ZSB0byBhIHNvbGlkIG9iamVjdCBvciBjbGVhciBjb2xvci5cclxuXHRcdGZsb2F0IHRyYW5zbWl0dGFuY2VGYWN0b3IgPSAoIHRyYW5zbWl0dGFuY2UuciArIHRyYW5zbWl0dGFuY2UuZyArIHRyYW5zbWl0dGFuY2UuYiApIC8gMy4wO1xyXG5cclxuXHRcdHJldHVybiB2ZWM0KCAoIDEuMCAtIEYgKSAqIGF0dGVudWF0ZWRDb2xvciwgMS4wIC0gKCAxLjAgLSB0cmFuc21pdHRlZExpZ2h0LmEgKSAqIHRyYW5zbWl0dGFuY2VGYWN0b3IgKTtcclxuXHJcblx0fVxyXG4jZW5kaWZcclxuYDtcclxuIiwiZXhwb3J0IGRlZmF1bHQgLyogZ2xzbCAqL2BcclxuI2lmIGRlZmluZWQoIFVTRV9VViApIHx8IGRlZmluZWQoIFVTRV9BTklTT1RST1BZIClcclxuXHJcblx0dmFyeWluZyB2ZWMyIHZVdjtcclxuXHJcbiNlbmRpZlxyXG4jaWZkZWYgVVNFX01BUFxyXG5cclxuXHR2YXJ5aW5nIHZlYzIgdk1hcFV2O1xyXG5cclxuI2VuZGlmXHJcbiNpZmRlZiBVU0VfQUxQSEFNQVBcclxuXHJcblx0dmFyeWluZyB2ZWMyIHZBbHBoYU1hcFV2O1xyXG5cclxuI2VuZGlmXHJcbiNpZmRlZiBVU0VfTElHSFRNQVBcclxuXHJcblx0dmFyeWluZyB2ZWMyIHZMaWdodE1hcFV2O1xyXG5cclxuI2VuZGlmXHJcbiNpZmRlZiBVU0VfQU9NQVBcclxuXHJcblx0dmFyeWluZyB2ZWMyIHZBb01hcFV2O1xyXG5cclxuI2VuZGlmXHJcbiNpZmRlZiBVU0VfQlVNUE1BUFxyXG5cclxuXHR2YXJ5aW5nIHZlYzIgdkJ1bXBNYXBVdjtcclxuXHJcbiNlbmRpZlxyXG4jaWZkZWYgVVNFX05PUk1BTE1BUFxyXG5cclxuXHR2YXJ5aW5nIHZlYzIgdk5vcm1hbE1hcFV2O1xyXG5cclxuI2VuZGlmXHJcbiNpZmRlZiBVU0VfRU1JU1NJVkVNQVBcclxuXHJcblx0dmFyeWluZyB2ZWMyIHZFbWlzc2l2ZU1hcFV2O1xyXG5cclxuI2VuZGlmXHJcbiNpZmRlZiBVU0VfTUVUQUxORVNTTUFQXHJcblxyXG5cdHZhcnlpbmcgdmVjMiB2TWV0YWxuZXNzTWFwVXY7XHJcblxyXG4jZW5kaWZcclxuI2lmZGVmIFVTRV9ST1VHSE5FU1NNQVBcclxuXHJcblx0dmFyeWluZyB2ZWMyIHZSb3VnaG5lc3NNYXBVdjtcclxuXHJcbiNlbmRpZlxyXG4jaWZkZWYgVVNFX0FOSVNPVFJPUFlNQVBcclxuXHJcblx0dmFyeWluZyB2ZWMyIHZBbmlzb3Ryb3B5TWFwVXY7XHJcblxyXG4jZW5kaWZcclxuI2lmZGVmIFVTRV9DTEVBUkNPQVRNQVBcclxuXHJcblx0dmFyeWluZyB2ZWMyIHZDbGVhcmNvYXRNYXBVdjtcclxuXHJcbiNlbmRpZlxyXG4jaWZkZWYgVVNFX0NMRUFSQ09BVF9OT1JNQUxNQVBcclxuXHJcblx0dmFyeWluZyB2ZWMyIHZDbGVhcmNvYXROb3JtYWxNYXBVdjtcclxuXHJcbiNlbmRpZlxyXG4jaWZkZWYgVVNFX0NMRUFSQ09BVF9ST1VHSE5FU1NNQVBcclxuXHJcblx0dmFyeWluZyB2ZWMyIHZDbGVhcmNvYXRSb3VnaG5lc3NNYXBVdjtcclxuXHJcbiNlbmRpZlxyXG4jaWZkZWYgVVNFX0lSSURFU0NFTkNFTUFQXHJcblxyXG5cdHZhcnlpbmcgdmVjMiB2SXJpZGVzY2VuY2VNYXBVdjtcclxuXHJcbiNlbmRpZlxyXG4jaWZkZWYgVVNFX0lSSURFU0NFTkNFX1RISUNLTkVTU01BUFxyXG5cclxuXHR2YXJ5aW5nIHZlYzIgdklyaWRlc2NlbmNlVGhpY2tuZXNzTWFwVXY7XHJcblxyXG4jZW5kaWZcclxuI2lmZGVmIFVTRV9TSEVFTl9DT0xPUk1BUFxyXG5cclxuXHR2YXJ5aW5nIHZlYzIgdlNoZWVuQ29sb3JNYXBVdjtcclxuXHJcbiNlbmRpZlxyXG4jaWZkZWYgVVNFX1NIRUVOX1JPVUdITkVTU01BUFxyXG5cclxuXHR2YXJ5aW5nIHZlYzIgdlNoZWVuUm91Z2huZXNzTWFwVXY7XHJcblxyXG4jZW5kaWZcclxuI2lmZGVmIFVTRV9TUEVDVUxBUk1BUFxyXG5cclxuXHR2YXJ5aW5nIHZlYzIgdlNwZWN1bGFyTWFwVXY7XHJcblxyXG4jZW5kaWZcclxuI2lmZGVmIFVTRV9TUEVDVUxBUl9DT0xPUk1BUFxyXG5cclxuXHR2YXJ5aW5nIHZlYzIgdlNwZWN1bGFyQ29sb3JNYXBVdjtcclxuXHJcbiNlbmRpZlxyXG4jaWZkZWYgVVNFX1NQRUNVTEFSX0lOVEVOU0lUWU1BUFxyXG5cclxuXHR2YXJ5aW5nIHZlYzIgdlNwZWN1bGFySW50ZW5zaXR5TWFwVXY7XHJcblxyXG4jZW5kaWZcclxuI2lmZGVmIFVTRV9UUkFOU01JU1NJT05NQVBcclxuXHJcblx0dW5pZm9ybSBtYXQzIHRyYW5zbWlzc2lvbk1hcFRyYW5zZm9ybTtcclxuXHR2YXJ5aW5nIHZlYzIgdlRyYW5zbWlzc2lvbk1hcFV2O1xyXG5cclxuI2VuZGlmXHJcbiNpZmRlZiBVU0VfVEhJQ0tORVNTTUFQXHJcblxyXG5cdHVuaWZvcm0gbWF0MyB0aGlja25lc3NNYXBUcmFuc2Zvcm07XHJcblx0dmFyeWluZyB2ZWMyIHZUaGlja25lc3NNYXBVdjtcclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWYgZGVmaW5lZCggVVNFX1VWICkgfHwgZGVmaW5lZCggVVNFX0FOSVNPVFJPUFkgKVxyXG5cclxuXHR2YXJ5aW5nIHZlYzIgdlV2O1xyXG5cclxuI2VuZGlmXHJcbiNpZmRlZiBVU0VfTUFQXHJcblxyXG5cdHVuaWZvcm0gbWF0MyBtYXBUcmFuc2Zvcm07XHJcblx0dmFyeWluZyB2ZWMyIHZNYXBVdjtcclxuXHJcbiNlbmRpZlxyXG4jaWZkZWYgVVNFX0FMUEhBTUFQXHJcblxyXG5cdHVuaWZvcm0gbWF0MyBhbHBoYU1hcFRyYW5zZm9ybTtcclxuXHR2YXJ5aW5nIHZlYzIgdkFscGhhTWFwVXY7XHJcblxyXG4jZW5kaWZcclxuI2lmZGVmIFVTRV9MSUdIVE1BUFxyXG5cclxuXHR1bmlmb3JtIG1hdDMgbGlnaHRNYXBUcmFuc2Zvcm07XHJcblx0dmFyeWluZyB2ZWMyIHZMaWdodE1hcFV2O1xyXG5cclxuI2VuZGlmXHJcbiNpZmRlZiBVU0VfQU9NQVBcclxuXHJcblx0dW5pZm9ybSBtYXQzIGFvTWFwVHJhbnNmb3JtO1xyXG5cdHZhcnlpbmcgdmVjMiB2QW9NYXBVdjtcclxuXHJcbiNlbmRpZlxyXG4jaWZkZWYgVVNFX0JVTVBNQVBcclxuXHJcblx0dW5pZm9ybSBtYXQzIGJ1bXBNYXBUcmFuc2Zvcm07XHJcblx0dmFyeWluZyB2ZWMyIHZCdW1wTWFwVXY7XHJcblxyXG4jZW5kaWZcclxuI2lmZGVmIFVTRV9OT1JNQUxNQVBcclxuXHJcblx0dW5pZm9ybSBtYXQzIG5vcm1hbE1hcFRyYW5zZm9ybTtcclxuXHR2YXJ5aW5nIHZlYzIgdk5vcm1hbE1hcFV2O1xyXG5cclxuI2VuZGlmXHJcbiNpZmRlZiBVU0VfRElTUExBQ0VNRU5UTUFQXHJcblxyXG5cdHVuaWZvcm0gbWF0MyBkaXNwbGFjZW1lbnRNYXBUcmFuc2Zvcm07XHJcblx0dmFyeWluZyB2ZWMyIHZEaXNwbGFjZW1lbnRNYXBVdjtcclxuXHJcbiNlbmRpZlxyXG4jaWZkZWYgVVNFX0VNSVNTSVZFTUFQXHJcblxyXG5cdHVuaWZvcm0gbWF0MyBlbWlzc2l2ZU1hcFRyYW5zZm9ybTtcclxuXHR2YXJ5aW5nIHZlYzIgdkVtaXNzaXZlTWFwVXY7XHJcblxyXG4jZW5kaWZcclxuI2lmZGVmIFVTRV9NRVRBTE5FU1NNQVBcclxuXHJcblx0dW5pZm9ybSBtYXQzIG1ldGFsbmVzc01hcFRyYW5zZm9ybTtcclxuXHR2YXJ5aW5nIHZlYzIgdk1ldGFsbmVzc01hcFV2O1xyXG5cclxuI2VuZGlmXHJcbiNpZmRlZiBVU0VfUk9VR0hORVNTTUFQXHJcblxyXG5cdHVuaWZvcm0gbWF0MyByb3VnaG5lc3NNYXBUcmFuc2Zvcm07XHJcblx0dmFyeWluZyB2ZWMyIHZSb3VnaG5lc3NNYXBVdjtcclxuXHJcbiNlbmRpZlxyXG4jaWZkZWYgVVNFX0FOSVNPVFJPUFlNQVBcclxuXHJcblx0dW5pZm9ybSBtYXQzIGFuaXNvdHJvcHlNYXBUcmFuc2Zvcm07XHJcblx0dmFyeWluZyB2ZWMyIHZBbmlzb3Ryb3B5TWFwVXY7XHJcblxyXG4jZW5kaWZcclxuI2lmZGVmIFVTRV9DTEVBUkNPQVRNQVBcclxuXHJcblx0dW5pZm9ybSBtYXQzIGNsZWFyY29hdE1hcFRyYW5zZm9ybTtcclxuXHR2YXJ5aW5nIHZlYzIgdkNsZWFyY29hdE1hcFV2O1xyXG5cclxuI2VuZGlmXHJcbiNpZmRlZiBVU0VfQ0xFQVJDT0FUX05PUk1BTE1BUFxyXG5cclxuXHR1bmlmb3JtIG1hdDMgY2xlYXJjb2F0Tm9ybWFsTWFwVHJhbnNmb3JtO1xyXG5cdHZhcnlpbmcgdmVjMiB2Q2xlYXJjb2F0Tm9ybWFsTWFwVXY7XHJcblxyXG4jZW5kaWZcclxuI2lmZGVmIFVTRV9DTEVBUkNPQVRfUk9VR0hORVNTTUFQXHJcblxyXG5cdHVuaWZvcm0gbWF0MyBjbGVhcmNvYXRSb3VnaG5lc3NNYXBUcmFuc2Zvcm07XHJcblx0dmFyeWluZyB2ZWMyIHZDbGVhcmNvYXRSb3VnaG5lc3NNYXBVdjtcclxuXHJcbiNlbmRpZlxyXG4jaWZkZWYgVVNFX1NIRUVOX0NPTE9STUFQXHJcblxyXG5cdHVuaWZvcm0gbWF0MyBzaGVlbkNvbG9yTWFwVHJhbnNmb3JtO1xyXG5cdHZhcnlpbmcgdmVjMiB2U2hlZW5Db2xvck1hcFV2O1xyXG5cclxuI2VuZGlmXHJcbiNpZmRlZiBVU0VfU0hFRU5fUk9VR0hORVNTTUFQXHJcblxyXG5cdHVuaWZvcm0gbWF0MyBzaGVlblJvdWdobmVzc01hcFRyYW5zZm9ybTtcclxuXHR2YXJ5aW5nIHZlYzIgdlNoZWVuUm91Z2huZXNzTWFwVXY7XHJcblxyXG4jZW5kaWZcclxuI2lmZGVmIFVTRV9JUklERVNDRU5DRU1BUFxyXG5cclxuXHR1bmlmb3JtIG1hdDMgaXJpZGVzY2VuY2VNYXBUcmFuc2Zvcm07XHJcblx0dmFyeWluZyB2ZWMyIHZJcmlkZXNjZW5jZU1hcFV2O1xyXG5cclxuI2VuZGlmXHJcbiNpZmRlZiBVU0VfSVJJREVTQ0VOQ0VfVEhJQ0tORVNTTUFQXHJcblxyXG5cdHVuaWZvcm0gbWF0MyBpcmlkZXNjZW5jZVRoaWNrbmVzc01hcFRyYW5zZm9ybTtcclxuXHR2YXJ5aW5nIHZlYzIgdklyaWRlc2NlbmNlVGhpY2tuZXNzTWFwVXY7XHJcblxyXG4jZW5kaWZcclxuI2lmZGVmIFVTRV9TUEVDVUxBUk1BUFxyXG5cclxuXHR1bmlmb3JtIG1hdDMgc3BlY3VsYXJNYXBUcmFuc2Zvcm07XHJcblx0dmFyeWluZyB2ZWMyIHZTcGVjdWxhck1hcFV2O1xyXG5cclxuI2VuZGlmXHJcbiNpZmRlZiBVU0VfU1BFQ1VMQVJfQ09MT1JNQVBcclxuXHJcblx0dW5pZm9ybSBtYXQzIHNwZWN1bGFyQ29sb3JNYXBUcmFuc2Zvcm07XHJcblx0dmFyeWluZyB2ZWMyIHZTcGVjdWxhckNvbG9yTWFwVXY7XHJcblxyXG4jZW5kaWZcclxuI2lmZGVmIFVTRV9TUEVDVUxBUl9JTlRFTlNJVFlNQVBcclxuXHJcblx0dW5pZm9ybSBtYXQzIHNwZWN1bGFySW50ZW5zaXR5TWFwVHJhbnNmb3JtO1xyXG5cdHZhcnlpbmcgdmVjMiB2U3BlY3VsYXJJbnRlbnNpdHlNYXBVdjtcclxuXHJcbiNlbmRpZlxyXG4jaWZkZWYgVVNFX1RSQU5TTUlTU0lPTk1BUFxyXG5cclxuXHR1bmlmb3JtIG1hdDMgdHJhbnNtaXNzaW9uTWFwVHJhbnNmb3JtO1xyXG5cdHZhcnlpbmcgdmVjMiB2VHJhbnNtaXNzaW9uTWFwVXY7XHJcblxyXG4jZW5kaWZcclxuI2lmZGVmIFVTRV9USElDS05FU1NNQVBcclxuXHJcblx0dW5pZm9ybSBtYXQzIHRoaWNrbmVzc01hcFRyYW5zZm9ybTtcclxuXHR2YXJ5aW5nIHZlYzIgdlRoaWNrbmVzc01hcFV2O1xyXG5cclxuI2VuZGlmXHJcbmA7XHJcbiIsImV4cG9ydCBkZWZhdWx0IC8qIGdsc2wgKi9gXHJcbiNpZiBkZWZpbmVkKCBVU0VfVVYgKSB8fCBkZWZpbmVkKCBVU0VfQU5JU09UUk9QWSApXHJcblxyXG5cdHZVdiA9IHZlYzMoIHV2LCAxICkueHk7XHJcblxyXG4jZW5kaWZcclxuI2lmZGVmIFVTRV9NQVBcclxuXHJcblx0dk1hcFV2ID0gKCBtYXBUcmFuc2Zvcm0gKiB2ZWMzKCBNQVBfVVYsIDEgKSApLnh5O1xyXG5cclxuI2VuZGlmXHJcbiNpZmRlZiBVU0VfQUxQSEFNQVBcclxuXHJcblx0dkFscGhhTWFwVXYgPSAoIGFscGhhTWFwVHJhbnNmb3JtICogdmVjMyggQUxQSEFNQVBfVVYsIDEgKSApLnh5O1xyXG5cclxuI2VuZGlmXHJcbiNpZmRlZiBVU0VfTElHSFRNQVBcclxuXHJcblx0dkxpZ2h0TWFwVXYgPSAoIGxpZ2h0TWFwVHJhbnNmb3JtICogdmVjMyggTElHSFRNQVBfVVYsIDEgKSApLnh5O1xyXG5cclxuI2VuZGlmXHJcbiNpZmRlZiBVU0VfQU9NQVBcclxuXHJcblx0dkFvTWFwVXYgPSAoIGFvTWFwVHJhbnNmb3JtICogdmVjMyggQU9NQVBfVVYsIDEgKSApLnh5O1xyXG5cclxuI2VuZGlmXHJcbiNpZmRlZiBVU0VfQlVNUE1BUFxyXG5cclxuXHR2QnVtcE1hcFV2ID0gKCBidW1wTWFwVHJhbnNmb3JtICogdmVjMyggQlVNUE1BUF9VViwgMSApICkueHk7XHJcblxyXG4jZW5kaWZcclxuI2lmZGVmIFVTRV9OT1JNQUxNQVBcclxuXHJcblx0dk5vcm1hbE1hcFV2ID0gKCBub3JtYWxNYXBUcmFuc2Zvcm0gKiB2ZWMzKCBOT1JNQUxNQVBfVVYsIDEgKSApLnh5O1xyXG5cclxuI2VuZGlmXHJcbiNpZmRlZiBVU0VfRElTUExBQ0VNRU5UTUFQXHJcblxyXG5cdHZEaXNwbGFjZW1lbnRNYXBVdiA9ICggZGlzcGxhY2VtZW50TWFwVHJhbnNmb3JtICogdmVjMyggRElTUExBQ0VNRU5UTUFQX1VWLCAxICkgKS54eTtcclxuXHJcbiNlbmRpZlxyXG4jaWZkZWYgVVNFX0VNSVNTSVZFTUFQXHJcblxyXG5cdHZFbWlzc2l2ZU1hcFV2ID0gKCBlbWlzc2l2ZU1hcFRyYW5zZm9ybSAqIHZlYzMoIEVNSVNTSVZFTUFQX1VWLCAxICkgKS54eTtcclxuXHJcbiNlbmRpZlxyXG4jaWZkZWYgVVNFX01FVEFMTkVTU01BUFxyXG5cclxuXHR2TWV0YWxuZXNzTWFwVXYgPSAoIG1ldGFsbmVzc01hcFRyYW5zZm9ybSAqIHZlYzMoIE1FVEFMTkVTU01BUF9VViwgMSApICkueHk7XHJcblxyXG4jZW5kaWZcclxuI2lmZGVmIFVTRV9ST1VHSE5FU1NNQVBcclxuXHJcblx0dlJvdWdobmVzc01hcFV2ID0gKCByb3VnaG5lc3NNYXBUcmFuc2Zvcm0gKiB2ZWMzKCBST1VHSE5FU1NNQVBfVVYsIDEgKSApLnh5O1xyXG5cclxuI2VuZGlmXHJcbiNpZmRlZiBVU0VfQU5JU09UUk9QWU1BUFxyXG5cclxuXHR2QW5pc290cm9weU1hcFV2ID0gKCBhbmlzb3Ryb3B5TWFwVHJhbnNmb3JtICogdmVjMyggQU5JU09UUk9QWU1BUF9VViwgMSApICkueHk7XHJcblxyXG4jZW5kaWZcclxuI2lmZGVmIFVTRV9DTEVBUkNPQVRNQVBcclxuXHJcblx0dkNsZWFyY29hdE1hcFV2ID0gKCBjbGVhcmNvYXRNYXBUcmFuc2Zvcm0gKiB2ZWMzKCBDTEVBUkNPQVRNQVBfVVYsIDEgKSApLnh5O1xyXG5cclxuI2VuZGlmXHJcbiNpZmRlZiBVU0VfQ0xFQVJDT0FUX05PUk1BTE1BUFxyXG5cclxuXHR2Q2xlYXJjb2F0Tm9ybWFsTWFwVXYgPSAoIGNsZWFyY29hdE5vcm1hbE1hcFRyYW5zZm9ybSAqIHZlYzMoIENMRUFSQ09BVF9OT1JNQUxNQVBfVVYsIDEgKSApLnh5O1xyXG5cclxuI2VuZGlmXHJcbiNpZmRlZiBVU0VfQ0xFQVJDT0FUX1JPVUdITkVTU01BUFxyXG5cclxuXHR2Q2xlYXJjb2F0Um91Z2huZXNzTWFwVXYgPSAoIGNsZWFyY29hdFJvdWdobmVzc01hcFRyYW5zZm9ybSAqIHZlYzMoIENMRUFSQ09BVF9ST1VHSE5FU1NNQVBfVVYsIDEgKSApLnh5O1xyXG5cclxuI2VuZGlmXHJcbiNpZmRlZiBVU0VfSVJJREVTQ0VOQ0VNQVBcclxuXHJcblx0dklyaWRlc2NlbmNlTWFwVXYgPSAoIGlyaWRlc2NlbmNlTWFwVHJhbnNmb3JtICogdmVjMyggSVJJREVTQ0VOQ0VNQVBfVVYsIDEgKSApLnh5O1xyXG5cclxuI2VuZGlmXHJcbiNpZmRlZiBVU0VfSVJJREVTQ0VOQ0VfVEhJQ0tORVNTTUFQXHJcblxyXG5cdHZJcmlkZXNjZW5jZVRoaWNrbmVzc01hcFV2ID0gKCBpcmlkZXNjZW5jZVRoaWNrbmVzc01hcFRyYW5zZm9ybSAqIHZlYzMoIElSSURFU0NFTkNFX1RISUNLTkVTU01BUF9VViwgMSApICkueHk7XHJcblxyXG4jZW5kaWZcclxuI2lmZGVmIFVTRV9TSEVFTl9DT0xPUk1BUFxyXG5cclxuXHR2U2hlZW5Db2xvck1hcFV2ID0gKCBzaGVlbkNvbG9yTWFwVHJhbnNmb3JtICogdmVjMyggU0hFRU5fQ09MT1JNQVBfVVYsIDEgKSApLnh5O1xyXG5cclxuI2VuZGlmXHJcbiNpZmRlZiBVU0VfU0hFRU5fUk9VR0hORVNTTUFQXHJcblxyXG5cdHZTaGVlblJvdWdobmVzc01hcFV2ID0gKCBzaGVlblJvdWdobmVzc01hcFRyYW5zZm9ybSAqIHZlYzMoIFNIRUVOX1JPVUdITkVTU01BUF9VViwgMSApICkueHk7XHJcblxyXG4jZW5kaWZcclxuI2lmZGVmIFVTRV9TUEVDVUxBUk1BUFxyXG5cclxuXHR2U3BlY3VsYXJNYXBVdiA9ICggc3BlY3VsYXJNYXBUcmFuc2Zvcm0gKiB2ZWMzKCBTUEVDVUxBUk1BUF9VViwgMSApICkueHk7XHJcblxyXG4jZW5kaWZcclxuI2lmZGVmIFVTRV9TUEVDVUxBUl9DT0xPUk1BUFxyXG5cclxuXHR2U3BlY3VsYXJDb2xvck1hcFV2ID0gKCBzcGVjdWxhckNvbG9yTWFwVHJhbnNmb3JtICogdmVjMyggU1BFQ1VMQVJfQ09MT1JNQVBfVVYsIDEgKSApLnh5O1xyXG5cclxuI2VuZGlmXHJcbiNpZmRlZiBVU0VfU1BFQ1VMQVJfSU5URU5TSVRZTUFQXHJcblxyXG5cdHZTcGVjdWxhckludGVuc2l0eU1hcFV2ID0gKCBzcGVjdWxhckludGVuc2l0eU1hcFRyYW5zZm9ybSAqIHZlYzMoIFNQRUNVTEFSX0lOVEVOU0lUWU1BUF9VViwgMSApICkueHk7XHJcblxyXG4jZW5kaWZcclxuI2lmZGVmIFVTRV9UUkFOU01JU1NJT05NQVBcclxuXHJcblx0dlRyYW5zbWlzc2lvbk1hcFV2ID0gKCB0cmFuc21pc3Npb25NYXBUcmFuc2Zvcm0gKiB2ZWMzKCBUUkFOU01JU1NJT05NQVBfVVYsIDEgKSApLnh5O1xyXG5cclxuI2VuZGlmXHJcbiNpZmRlZiBVU0VfVEhJQ0tORVNTTUFQXHJcblxyXG5cdHZUaGlja25lc3NNYXBVdiA9ICggdGhpY2tuZXNzTWFwVHJhbnNmb3JtICogdmVjMyggVEhJQ0tORVNTTUFQX1VWLCAxICkgKS54eTtcclxuXHJcbiNlbmRpZlxyXG5gO1xyXG4iLCJleHBvcnQgZGVmYXVsdCAvKiBnbHNsICovYFxyXG4jaWYgZGVmaW5lZCggVVNFX0VOVk1BUCApIHx8IGRlZmluZWQoIERJU1RBTkNFICkgfHwgZGVmaW5lZCAoIFVTRV9TSEFET1dNQVAgKSB8fCBkZWZpbmVkICggVVNFX1RSQU5TTUlTU0lPTiApIHx8IE5VTV9TUE9UX0xJR0hUX0NPT1JEUyA+IDBcclxuXHJcblx0dmVjNCB3b3JsZFBvc2l0aW9uID0gdmVjNCggdHJhbnNmb3JtZWQsIDEuMCApO1xyXG5cclxuXHQjaWZkZWYgVVNFX0JBVENISU5HXHJcblxyXG5cdFx0d29ybGRQb3NpdGlvbiA9IGJhdGNoaW5nTWF0cml4ICogd29ybGRQb3NpdGlvbjtcclxuXHJcblx0I2VuZGlmXHJcblxyXG5cdCNpZmRlZiBVU0VfSU5TVEFOQ0lOR1xyXG5cclxuXHRcdHdvcmxkUG9zaXRpb24gPSBpbnN0YW5jZU1hdHJpeCAqIHdvcmxkUG9zaXRpb247XHJcblxyXG5cdCNlbmRpZlxyXG5cclxuXHR3b3JsZFBvc2l0aW9uID0gbW9kZWxNYXRyaXggKiB3b3JsZFBvc2l0aW9uO1xyXG5cclxuI2VuZGlmXHJcbmA7XHJcbiIsImV4cG9ydCBjb25zdCB2ZXJ0ZXggPSAvKiBnbHNsICovYFxyXG52YXJ5aW5nIHZlYzIgdlV2O1xyXG51bmlmb3JtIG1hdDMgdXZUcmFuc2Zvcm07XHJcblxyXG52b2lkIG1haW4oKSB7XHJcblxyXG5cdHZVdiA9ICggdXZUcmFuc2Zvcm0gKiB2ZWMzKCB1diwgMSApICkueHk7XHJcblxyXG5cdGdsX1Bvc2l0aW9uID0gdmVjNCggcG9zaXRpb24ueHksIDEuMCwgMS4wICk7XHJcblxyXG59XHJcbmA7XHJcblxyXG5leHBvcnQgY29uc3QgZnJhZ21lbnQgPSAvKiBnbHNsICovYFxyXG51bmlmb3JtIHNhbXBsZXIyRCB0MkQ7XHJcbnVuaWZvcm0gZmxvYXQgYmFja2dyb3VuZEludGVuc2l0eTtcclxuXHJcbnZhcnlpbmcgdmVjMiB2VXY7XHJcblxyXG52b2lkIG1haW4oKSB7XHJcblxyXG5cdHZlYzQgdGV4Q29sb3IgPSB0ZXh0dXJlMkQoIHQyRCwgdlV2ICk7XHJcblxyXG5cdCNpZmRlZiBERUNPREVfVklERU9fVEVYVFVSRVxyXG5cclxuXHRcdC8vIHVzZSBpbmxpbmUgc1JHQiBkZWNvZGUgdW50aWwgYnJvd3NlcnMgcHJvcGVybHkgc3VwcG9ydCBTUkdCOF9BUExIQTggd2l0aCB2aWRlbyB0ZXh0dXJlc1xyXG5cclxuXHRcdHRleENvbG9yID0gdmVjNCggbWl4KCBwb3coIHRleENvbG9yLnJnYiAqIDAuOTQ3ODY3Mjk4NiArIHZlYzMoIDAuMDUyMTMyNzAxNCApLCB2ZWMzKCAyLjQgKSApLCB0ZXhDb2xvci5yZ2IgKiAwLjA3NzM5OTM4MDgsIHZlYzMoIGxlc3NUaGFuRXF1YWwoIHRleENvbG9yLnJnYiwgdmVjMyggMC4wNDA0NSApICkgKSApLCB0ZXhDb2xvci53ICk7XHJcblxyXG5cdCNlbmRpZlxyXG5cclxuXHR0ZXhDb2xvci5yZ2IgKj0gYmFja2dyb3VuZEludGVuc2l0eTtcclxuXHJcblx0Z2xfRnJhZ0NvbG9yID0gdGV4Q29sb3I7XHJcblxyXG5cdCNpbmNsdWRlIDx0b25lbWFwcGluZ19mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8Y29sb3JzcGFjZV9mcmFnbWVudD5cclxuXHJcbn1cclxuYDtcclxuIiwiZXhwb3J0IGNvbnN0IHZlcnRleCA9IC8qIGdsc2wgKi9gXHJcbnZhcnlpbmcgdmVjMyB2V29ybGREaXJlY3Rpb247XHJcblxyXG4jaW5jbHVkZSA8Y29tbW9uPlxyXG5cclxudm9pZCBtYWluKCkge1xyXG5cclxuXHR2V29ybGREaXJlY3Rpb24gPSB0cmFuc2Zvcm1EaXJlY3Rpb24oIHBvc2l0aW9uLCBtb2RlbE1hdHJpeCApO1xyXG5cclxuXHQjaW5jbHVkZSA8YmVnaW5fdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxwcm9qZWN0X3ZlcnRleD5cclxuXHJcblx0Z2xfUG9zaXRpb24ueiA9IGdsX1Bvc2l0aW9uLnc7IC8vIHNldCB6IHRvIGNhbWVyYS5mYXJcclxuXHJcbn1cclxuYDtcclxuXHJcbmV4cG9ydCBjb25zdCBmcmFnbWVudCA9IC8qIGdsc2wgKi9gXHJcblxyXG4jaWZkZWYgRU5WTUFQX1RZUEVfQ1VCRVxyXG5cclxuXHR1bmlmb3JtIHNhbXBsZXJDdWJlIGVudk1hcDtcclxuXHJcbiNlbGlmIGRlZmluZWQoIEVOVk1BUF9UWVBFX0NVQkVfVVYgKVxyXG5cclxuXHR1bmlmb3JtIHNhbXBsZXIyRCBlbnZNYXA7XHJcblxyXG4jZW5kaWZcclxuXHJcbnVuaWZvcm0gZmxvYXQgZmxpcEVudk1hcDtcclxudW5pZm9ybSBmbG9hdCBiYWNrZ3JvdW5kQmx1cnJpbmVzcztcclxudW5pZm9ybSBmbG9hdCBiYWNrZ3JvdW5kSW50ZW5zaXR5O1xyXG5cclxudmFyeWluZyB2ZWMzIHZXb3JsZERpcmVjdGlvbjtcclxuXHJcbiNpbmNsdWRlIDxjdWJlX3V2X3JlZmxlY3Rpb25fZnJhZ21lbnQ+XHJcblxyXG52b2lkIG1haW4oKSB7XHJcblxyXG5cdCNpZmRlZiBFTlZNQVBfVFlQRV9DVUJFXHJcblxyXG5cdFx0dmVjNCB0ZXhDb2xvciA9IHRleHR1cmVDdWJlKCBlbnZNYXAsIHZlYzMoIGZsaXBFbnZNYXAgKiB2V29ybGREaXJlY3Rpb24ueCwgdldvcmxkRGlyZWN0aW9uLnl6ICkgKTtcclxuXHJcblx0I2VsaWYgZGVmaW5lZCggRU5WTUFQX1RZUEVfQ1VCRV9VViApXHJcblxyXG5cdFx0dmVjNCB0ZXhDb2xvciA9IHRleHR1cmVDdWJlVVYoIGVudk1hcCwgdldvcmxkRGlyZWN0aW9uLCBiYWNrZ3JvdW5kQmx1cnJpbmVzcyApO1xyXG5cclxuXHQjZWxzZVxyXG5cclxuXHRcdHZlYzQgdGV4Q29sb3IgPSB2ZWM0KCAwLjAsIDAuMCwgMC4wLCAxLjAgKTtcclxuXHJcblx0I2VuZGlmXHJcblxyXG5cdHRleENvbG9yLnJnYiAqPSBiYWNrZ3JvdW5kSW50ZW5zaXR5O1xyXG5cclxuXHRnbF9GcmFnQ29sb3IgPSB0ZXhDb2xvcjtcclxuXHJcblx0I2luY2x1ZGUgPHRvbmVtYXBwaW5nX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxjb2xvcnNwYWNlX2ZyYWdtZW50PlxyXG5cclxufVxyXG5gO1xyXG4iLCJleHBvcnQgY29uc3QgdmVydGV4ID0gLyogZ2xzbCAqL2BcclxudmFyeWluZyB2ZWMzIHZXb3JsZERpcmVjdGlvbjtcclxuXHJcbiNpbmNsdWRlIDxjb21tb24+XHJcblxyXG52b2lkIG1haW4oKSB7XHJcblxyXG5cdHZXb3JsZERpcmVjdGlvbiA9IHRyYW5zZm9ybURpcmVjdGlvbiggcG9zaXRpb24sIG1vZGVsTWF0cml4ICk7XHJcblxyXG5cdCNpbmNsdWRlIDxiZWdpbl92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPHByb2plY3RfdmVydGV4PlxyXG5cclxuXHRnbF9Qb3NpdGlvbi56ID0gZ2xfUG9zaXRpb24udzsgLy8gc2V0IHogdG8gY2FtZXJhLmZhclxyXG5cclxufVxyXG5gO1xyXG5cclxuZXhwb3J0IGNvbnN0IGZyYWdtZW50ID0gLyogZ2xzbCAqL2BcclxudW5pZm9ybSBzYW1wbGVyQ3ViZSB0Q3ViZTtcclxudW5pZm9ybSBmbG9hdCB0RmxpcDtcclxudW5pZm9ybSBmbG9hdCBvcGFjaXR5O1xyXG5cclxudmFyeWluZyB2ZWMzIHZXb3JsZERpcmVjdGlvbjtcclxuXHJcbnZvaWQgbWFpbigpIHtcclxuXHJcblx0dmVjNCB0ZXhDb2xvciA9IHRleHR1cmVDdWJlKCB0Q3ViZSwgdmVjMyggdEZsaXAgKiB2V29ybGREaXJlY3Rpb24ueCwgdldvcmxkRGlyZWN0aW9uLnl6ICkgKTtcclxuXHJcblx0Z2xfRnJhZ0NvbG9yID0gdGV4Q29sb3I7XHJcblx0Z2xfRnJhZ0NvbG9yLmEgKj0gb3BhY2l0eTtcclxuXHJcblx0I2luY2x1ZGUgPHRvbmVtYXBwaW5nX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxjb2xvcnNwYWNlX2ZyYWdtZW50PlxyXG5cclxufVxyXG5gO1xyXG4iLCJleHBvcnQgY29uc3QgdmVydGV4ID0gLyogZ2xzbCAqL2BcclxuI2luY2x1ZGUgPGNvbW1vbj5cclxuI2luY2x1ZGUgPGJhdGNoaW5nX3BhcnNfdmVydGV4PlxyXG4jaW5jbHVkZSA8dXZfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxkaXNwbGFjZW1lbnRtYXBfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxtb3JwaHRhcmdldF9wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPHNraW5uaW5nX3BhcnNfdmVydGV4PlxyXG4jaW5jbHVkZSA8bG9nZGVwdGhidWZfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxjbGlwcGluZ19wbGFuZXNfcGFyc192ZXJ0ZXg+XHJcblxyXG4vLyBUaGlzIGlzIHVzZWQgZm9yIGNvbXB1dGluZyBhbiBlcXVpdmFsZW50IG9mIGdsX0ZyYWdDb29yZC56IHRoYXQgaXMgYXMgaGlnaCBwcmVjaXNpb24gYXMgcG9zc2libGUuXHJcbi8vIFNvbWUgcGxhdGZvcm1zIGNvbXB1dGUgZ2xfRnJhZ0Nvb3JkIGF0IGEgbG93ZXIgcHJlY2lzaW9uIHdoaWNoIG1ha2VzIHRoZSBtYW51YWxseSBjb21wdXRlZCB2YWx1ZSBiZXR0ZXIgZm9yXHJcbi8vIGRlcHRoLWJhc2VkIHBvc3Rwcm9jZXNzaW5nIGVmZmVjdHMuIFJlcHJvZHVjZWQgb24gaVBhZCB3aXRoIEExMCBwcm9jZXNzb3IgLyBpUGFkT1MgMTMuMy4xLlxyXG52YXJ5aW5nIHZlYzIgdkhpZ2hQcmVjaXNpb25aVztcclxuXHJcbnZvaWQgbWFpbigpIHtcclxuXHJcblx0I2luY2x1ZGUgPHV2X3ZlcnRleD5cclxuXHJcblx0I2luY2x1ZGUgPGJhdGNoaW5nX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8c2tpbmJhc2VfdmVydGV4PlxyXG5cclxuXHQjaWZkZWYgVVNFX0RJU1BMQUNFTUVOVE1BUFxyXG5cclxuXHRcdCNpbmNsdWRlIDxiZWdpbm5vcm1hbF92ZXJ0ZXg+XHJcblx0XHQjaW5jbHVkZSA8bW9ycGhub3JtYWxfdmVydGV4PlxyXG5cdFx0I2luY2x1ZGUgPHNraW5ub3JtYWxfdmVydGV4PlxyXG5cclxuXHQjZW5kaWZcclxuXHJcblx0I2luY2x1ZGUgPGJlZ2luX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8bW9ycGh0YXJnZXRfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxza2lubmluZ192ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPGRpc3BsYWNlbWVudG1hcF92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPHByb2plY3RfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc192ZXJ0ZXg+XHJcblxyXG5cdHZIaWdoUHJlY2lzaW9uWlcgPSBnbF9Qb3NpdGlvbi56dztcclxuXHJcbn1cclxuYDtcclxuXHJcbmV4cG9ydCBjb25zdCBmcmFnbWVudCA9IC8qIGdsc2wgKi9gXHJcbiNpZiBERVBUSF9QQUNLSU5HID09IDMyMDBcclxuXHJcblx0dW5pZm9ybSBmbG9hdCBvcGFjaXR5O1xyXG5cclxuI2VuZGlmXHJcblxyXG4jaW5jbHVkZSA8Y29tbW9uPlxyXG4jaW5jbHVkZSA8cGFja2luZz5cclxuI2luY2x1ZGUgPHV2X3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxtYXBfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGFscGhhbWFwX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxhbHBoYXRlc3RfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGFscGhhaGFzaF9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8bG9nZGVwdGhidWZfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc19wYXJzX2ZyYWdtZW50PlxyXG5cclxudmFyeWluZyB2ZWMyIHZIaWdoUHJlY2lzaW9uWlc7XHJcblxyXG52b2lkIG1haW4oKSB7XHJcblxyXG5cdHZlYzQgZGlmZnVzZUNvbG9yID0gdmVjNCggMS4wICk7XHJcblx0I2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc19mcmFnbWVudD5cclxuXHJcblx0I2lmIERFUFRIX1BBQ0tJTkcgPT0gMzIwMFxyXG5cclxuXHRcdGRpZmZ1c2VDb2xvci5hID0gb3BhY2l0eTtcclxuXHJcblx0I2VuZGlmXHJcblxyXG5cdCNpbmNsdWRlIDxtYXBfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPGFscGhhbWFwX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxhbHBoYXRlc3RfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPGFscGhhaGFzaF9mcmFnbWVudD5cclxuXHJcblx0I2luY2x1ZGUgPGxvZ2RlcHRoYnVmX2ZyYWdtZW50PlxyXG5cclxuXHQvLyBIaWdoZXIgcHJlY2lzaW9uIGVxdWl2YWxlbnQgb2YgZ2xfRnJhZ0Nvb3JkLnouIFRoaXMgYXNzdW1lcyBkZXB0aFJhbmdlIGhhcyBiZWVuIGxlZnQgdG8gaXRzIGRlZmF1bHQgdmFsdWVzLlxyXG5cdGZsb2F0IGZyYWdDb29yZFogPSAwLjUgKiB2SGlnaFByZWNpc2lvblpXWzBdIC8gdkhpZ2hQcmVjaXNpb25aV1sxXSArIDAuNTtcclxuXHJcblx0I2lmIERFUFRIX1BBQ0tJTkcgPT0gMzIwMFxyXG5cclxuXHRcdGdsX0ZyYWdDb2xvciA9IHZlYzQoIHZlYzMoIDEuMCAtIGZyYWdDb29yZFogKSwgb3BhY2l0eSApO1xyXG5cclxuXHQjZWxpZiBERVBUSF9QQUNLSU5HID09IDMyMDFcclxuXHJcblx0XHRnbF9GcmFnQ29sb3IgPSBwYWNrRGVwdGhUb1JHQkEoIGZyYWdDb29yZFogKTtcclxuXHJcblx0I2VuZGlmXHJcblxyXG59XHJcbmA7XHJcbiIsImV4cG9ydCBjb25zdCB2ZXJ0ZXggPSAvKiBnbHNsICovYFxyXG4jZGVmaW5lIERJU1RBTkNFXHJcblxyXG52YXJ5aW5nIHZlYzMgdldvcmxkUG9zaXRpb247XHJcblxyXG4jaW5jbHVkZSA8Y29tbW9uPlxyXG4jaW5jbHVkZSA8YmF0Y2hpbmdfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDx1dl9wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPGRpc3BsYWNlbWVudG1hcF9wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPG1vcnBodGFyZ2V0X3BhcnNfdmVydGV4PlxyXG4jaW5jbHVkZSA8c2tpbm5pbmdfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxjbGlwcGluZ19wbGFuZXNfcGFyc192ZXJ0ZXg+XHJcblxyXG52b2lkIG1haW4oKSB7XHJcblxyXG5cdCNpbmNsdWRlIDx1dl92ZXJ0ZXg+XHJcblxyXG5cdCNpbmNsdWRlIDxiYXRjaGluZ192ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPHNraW5iYXNlX3ZlcnRleD5cclxuXHJcblx0I2lmZGVmIFVTRV9ESVNQTEFDRU1FTlRNQVBcclxuXHJcblx0XHQjaW5jbHVkZSA8YmVnaW5ub3JtYWxfdmVydGV4PlxyXG5cdFx0I2luY2x1ZGUgPG1vcnBobm9ybWFsX3ZlcnRleD5cclxuXHRcdCNpbmNsdWRlIDxza2lubm9ybWFsX3ZlcnRleD5cclxuXHJcblx0I2VuZGlmXHJcblxyXG5cdCNpbmNsdWRlIDxiZWdpbl92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPG1vcnBodGFyZ2V0X3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8c2tpbm5pbmdfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxkaXNwbGFjZW1lbnRtYXBfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxwcm9qZWN0X3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8d29ybGRwb3NfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxjbGlwcGluZ19wbGFuZXNfdmVydGV4PlxyXG5cclxuXHR2V29ybGRQb3NpdGlvbiA9IHdvcmxkUG9zaXRpb24ueHl6O1xyXG5cclxufVxyXG5gO1xyXG5cclxuZXhwb3J0IGNvbnN0IGZyYWdtZW50ID0gLyogZ2xzbCAqL2BcclxuI2RlZmluZSBESVNUQU5DRVxyXG5cclxudW5pZm9ybSB2ZWMzIHJlZmVyZW5jZVBvc2l0aW9uO1xyXG51bmlmb3JtIGZsb2F0IG5lYXJEaXN0YW5jZTtcclxudW5pZm9ybSBmbG9hdCBmYXJEaXN0YW5jZTtcclxudmFyeWluZyB2ZWMzIHZXb3JsZFBvc2l0aW9uO1xyXG5cclxuI2luY2x1ZGUgPGNvbW1vbj5cclxuI2luY2x1ZGUgPHBhY2tpbmc+XHJcbiNpbmNsdWRlIDx1dl9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8bWFwX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxhbHBoYW1hcF9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8YWxwaGF0ZXN0X3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxhbHBoYWhhc2hfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc19wYXJzX2ZyYWdtZW50PlxyXG5cclxudm9pZCBtYWluICgpIHtcclxuXHJcblx0dmVjNCBkaWZmdXNlQ29sb3IgPSB2ZWM0KCAxLjAgKTtcclxuXHQjaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX2ZyYWdtZW50PlxyXG5cclxuXHQjaW5jbHVkZSA8bWFwX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxhbHBoYW1hcF9mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8YWxwaGF0ZXN0X2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxhbHBoYWhhc2hfZnJhZ21lbnQ+XHJcblxyXG5cdGZsb2F0IGRpc3QgPSBsZW5ndGgoIHZXb3JsZFBvc2l0aW9uIC0gcmVmZXJlbmNlUG9zaXRpb24gKTtcclxuXHRkaXN0ID0gKCBkaXN0IC0gbmVhckRpc3RhbmNlICkgLyAoIGZhckRpc3RhbmNlIC0gbmVhckRpc3RhbmNlICk7XHJcblx0ZGlzdCA9IHNhdHVyYXRlKCBkaXN0ICk7IC8vIGNsYW1wIHRvIFsgMCwgMSBdXHJcblxyXG5cdGdsX0ZyYWdDb2xvciA9IHBhY2tEZXB0aFRvUkdCQSggZGlzdCApO1xyXG5cclxufVxyXG5gO1xyXG4iLCJleHBvcnQgY29uc3QgdmVydGV4ID0gLyogZ2xzbCAqL2BcclxudmFyeWluZyB2ZWMzIHZXb3JsZERpcmVjdGlvbjtcclxuXHJcbiNpbmNsdWRlIDxjb21tb24+XHJcblxyXG52b2lkIG1haW4oKSB7XHJcblxyXG5cdHZXb3JsZERpcmVjdGlvbiA9IHRyYW5zZm9ybURpcmVjdGlvbiggcG9zaXRpb24sIG1vZGVsTWF0cml4ICk7XHJcblxyXG5cdCNpbmNsdWRlIDxiZWdpbl92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPHByb2plY3RfdmVydGV4PlxyXG5cclxufVxyXG5gO1xyXG5cclxuZXhwb3J0IGNvbnN0IGZyYWdtZW50ID0gLyogZ2xzbCAqL2BcclxudW5pZm9ybSBzYW1wbGVyMkQgdEVxdWlyZWN0O1xyXG5cclxudmFyeWluZyB2ZWMzIHZXb3JsZERpcmVjdGlvbjtcclxuXHJcbiNpbmNsdWRlIDxjb21tb24+XHJcblxyXG52b2lkIG1haW4oKSB7XHJcblxyXG5cdHZlYzMgZGlyZWN0aW9uID0gbm9ybWFsaXplKCB2V29ybGREaXJlY3Rpb24gKTtcclxuXHJcblx0dmVjMiBzYW1wbGVVViA9IGVxdWlyZWN0VXYoIGRpcmVjdGlvbiApO1xyXG5cclxuXHRnbF9GcmFnQ29sb3IgPSB0ZXh0dXJlMkQoIHRFcXVpcmVjdCwgc2FtcGxlVVYgKTtcclxuXHJcblx0I2luY2x1ZGUgPHRvbmVtYXBwaW5nX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxjb2xvcnNwYWNlX2ZyYWdtZW50PlxyXG5cclxufVxyXG5gO1xyXG4iLCJleHBvcnQgY29uc3QgdmVydGV4ID0gLyogZ2xzbCAqL2BcclxudW5pZm9ybSBmbG9hdCBzY2FsZTtcclxuYXR0cmlidXRlIGZsb2F0IGxpbmVEaXN0YW5jZTtcclxuXHJcbnZhcnlpbmcgZmxvYXQgdkxpbmVEaXN0YW5jZTtcclxuXHJcbiNpbmNsdWRlIDxjb21tb24+XHJcbiNpbmNsdWRlIDx1dl9wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPGNvbG9yX3BhcnNfdmVydGV4PlxyXG4jaW5jbHVkZSA8Zm9nX3BhcnNfdmVydGV4PlxyXG4jaW5jbHVkZSA8bW9ycGh0YXJnZXRfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl9wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc19wYXJzX3ZlcnRleD5cclxuXHJcbnZvaWQgbWFpbigpIHtcclxuXHJcblx0dkxpbmVEaXN0YW5jZSA9IHNjYWxlICogbGluZURpc3RhbmNlO1xyXG5cclxuXHQjaW5jbHVkZSA8dXZfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxjb2xvcl92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPG1vcnBoY29sb3JfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxiZWdpbl92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPG1vcnBodGFyZ2V0X3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8cHJvamVjdF92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPGxvZ2RlcHRoYnVmX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8Zm9nX3ZlcnRleD5cclxuXHJcbn1cclxuYDtcclxuXHJcbmV4cG9ydCBjb25zdCBmcmFnbWVudCA9IC8qIGdsc2wgKi9gXHJcbnVuaWZvcm0gdmVjMyBkaWZmdXNlO1xyXG51bmlmb3JtIGZsb2F0IG9wYWNpdHk7XHJcblxyXG51bmlmb3JtIGZsb2F0IGRhc2hTaXplO1xyXG51bmlmb3JtIGZsb2F0IHRvdGFsU2l6ZTtcclxuXHJcbnZhcnlpbmcgZmxvYXQgdkxpbmVEaXN0YW5jZTtcclxuXHJcbiNpbmNsdWRlIDxjb21tb24+XHJcbiNpbmNsdWRlIDxjb2xvcl9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8dXZfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPG1hcF9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8Zm9nX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX3BhcnNfZnJhZ21lbnQ+XHJcblxyXG52b2lkIG1haW4oKSB7XHJcblxyXG5cdHZlYzQgZGlmZnVzZUNvbG9yID0gdmVjNCggZGlmZnVzZSwgb3BhY2l0eSApO1xyXG5cdCNpbmNsdWRlIDxjbGlwcGluZ19wbGFuZXNfZnJhZ21lbnQ+XHJcblxyXG5cdGlmICggbW9kKCB2TGluZURpc3RhbmNlLCB0b3RhbFNpemUgKSA+IGRhc2hTaXplICkge1xyXG5cclxuXHRcdGRpc2NhcmQ7XHJcblxyXG5cdH1cclxuXHJcblx0dmVjMyBvdXRnb2luZ0xpZ2h0ID0gdmVjMyggMC4wICk7XHJcblxyXG5cdCNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl9mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8bWFwX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxjb2xvcl9mcmFnbWVudD5cclxuXHJcblx0b3V0Z29pbmdMaWdodCA9IGRpZmZ1c2VDb2xvci5yZ2I7IC8vIHNpbXBsZSBzaGFkZXJcclxuXHJcblx0I2luY2x1ZGUgPG9wYXF1ZV9mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8dG9uZW1hcHBpbmdfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPGNvbG9yc3BhY2VfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPGZvZ19mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8cHJlbXVsdGlwbGllZF9hbHBoYV9mcmFnbWVudD5cclxuXHJcbn1cclxuYDtcclxuIiwiZXhwb3J0IGNvbnN0IHZlcnRleCA9IC8qIGdsc2wgKi9gXHJcbiNpbmNsdWRlIDxjb21tb24+XHJcbiNpbmNsdWRlIDxiYXRjaGluZ19wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPHV2X3BhcnNfdmVydGV4PlxyXG4jaW5jbHVkZSA8ZW52bWFwX3BhcnNfdmVydGV4PlxyXG4jaW5jbHVkZSA8Y29sb3JfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxmb2dfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxtb3JwaHRhcmdldF9wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPHNraW5uaW5nX3BhcnNfdmVydGV4PlxyXG4jaW5jbHVkZSA8bG9nZGVwdGhidWZfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxjbGlwcGluZ19wbGFuZXNfcGFyc192ZXJ0ZXg+XHJcblxyXG52b2lkIG1haW4oKSB7XHJcblxyXG5cdCNpbmNsdWRlIDx1dl92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPGNvbG9yX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8bW9ycGhjb2xvcl92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPGJhdGNoaW5nX3ZlcnRleD5cclxuXHJcblx0I2lmIGRlZmluZWQgKCBVU0VfRU5WTUFQICkgfHwgZGVmaW5lZCAoIFVTRV9TS0lOTklORyApXHJcblxyXG5cdFx0I2luY2x1ZGUgPGJlZ2lubm9ybWFsX3ZlcnRleD5cclxuXHRcdCNpbmNsdWRlIDxtb3JwaG5vcm1hbF92ZXJ0ZXg+XHJcblx0XHQjaW5jbHVkZSA8c2tpbmJhc2VfdmVydGV4PlxyXG5cdFx0I2luY2x1ZGUgPHNraW5ub3JtYWxfdmVydGV4PlxyXG5cdFx0I2luY2x1ZGUgPGRlZmF1bHRub3JtYWxfdmVydGV4PlxyXG5cclxuXHQjZW5kaWZcclxuXHJcblx0I2luY2x1ZGUgPGJlZ2luX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8bW9ycGh0YXJnZXRfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxza2lubmluZ192ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPHByb2plY3RfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc192ZXJ0ZXg+XHJcblxyXG5cdCNpbmNsdWRlIDx3b3JsZHBvc192ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPGVudm1hcF92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPGZvZ192ZXJ0ZXg+XHJcblxyXG59XHJcbmA7XHJcblxyXG5leHBvcnQgY29uc3QgZnJhZ21lbnQgPSAvKiBnbHNsICovYFxyXG51bmlmb3JtIHZlYzMgZGlmZnVzZTtcclxudW5pZm9ybSBmbG9hdCBvcGFjaXR5O1xyXG5cclxuI2lmbmRlZiBGTEFUX1NIQURFRFxyXG5cclxuXHR2YXJ5aW5nIHZlYzMgdk5vcm1hbDtcclxuXHJcbiNlbmRpZlxyXG5cclxuI2luY2x1ZGUgPGNvbW1vbj5cclxuI2luY2x1ZGUgPGRpdGhlcmluZ19wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8Y29sb3JfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPHV2X3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxtYXBfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGFscGhhbWFwX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxhbHBoYXRlc3RfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGFscGhhaGFzaF9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8YW9tYXBfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGxpZ2h0bWFwX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxlbnZtYXBfY29tbW9uX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxlbnZtYXBfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGZvZ19wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8c3BlY3VsYXJtYXBfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGxvZ2RlcHRoYnVmX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxjbGlwcGluZ19wbGFuZXNfcGFyc19mcmFnbWVudD5cclxuXHJcbnZvaWQgbWFpbigpIHtcclxuXHJcblx0dmVjNCBkaWZmdXNlQ29sb3IgPSB2ZWM0KCBkaWZmdXNlLCBvcGFjaXR5ICk7XHJcblx0I2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc19mcmFnbWVudD5cclxuXHJcblx0I2luY2x1ZGUgPGxvZ2RlcHRoYnVmX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxtYXBfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPGNvbG9yX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxhbHBoYW1hcF9mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8YWxwaGF0ZXN0X2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxhbHBoYWhhc2hfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPHNwZWN1bGFybWFwX2ZyYWdtZW50PlxyXG5cclxuXHRSZWZsZWN0ZWRMaWdodCByZWZsZWN0ZWRMaWdodCA9IFJlZmxlY3RlZExpZ2h0KCB2ZWMzKCAwLjAgKSwgdmVjMyggMC4wICksIHZlYzMoIDAuMCApLCB2ZWMzKCAwLjAgKSApO1xyXG5cclxuXHQvLyBhY2N1bXVsYXRpb24gKGJha2VkIGluZGlyZWN0IGxpZ2h0aW5nIG9ubHkpXHJcblx0I2lmZGVmIFVTRV9MSUdIVE1BUFxyXG5cclxuXHRcdHZlYzQgbGlnaHRNYXBUZXhlbCA9IHRleHR1cmUyRCggbGlnaHRNYXAsIHZMaWdodE1hcFV2ICk7XHJcblx0XHRyZWZsZWN0ZWRMaWdodC5pbmRpcmVjdERpZmZ1c2UgKz0gbGlnaHRNYXBUZXhlbC5yZ2IgKiBsaWdodE1hcEludGVuc2l0eSAqIFJFQ0lQUk9DQUxfUEk7XHJcblxyXG5cdCNlbHNlXHJcblxyXG5cdFx0cmVmbGVjdGVkTGlnaHQuaW5kaXJlY3REaWZmdXNlICs9IHZlYzMoIDEuMCApO1xyXG5cclxuXHQjZW5kaWZcclxuXHJcblx0Ly8gbW9kdWxhdGlvblxyXG5cdCNpbmNsdWRlIDxhb21hcF9mcmFnbWVudD5cclxuXHJcblx0cmVmbGVjdGVkTGlnaHQuaW5kaXJlY3REaWZmdXNlICo9IGRpZmZ1c2VDb2xvci5yZ2I7XHJcblxyXG5cdHZlYzMgb3V0Z29pbmdMaWdodCA9IHJlZmxlY3RlZExpZ2h0LmluZGlyZWN0RGlmZnVzZTtcclxuXHJcblx0I2luY2x1ZGUgPGVudm1hcF9mcmFnbWVudD5cclxuXHJcblx0I2luY2x1ZGUgPG9wYXF1ZV9mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8dG9uZW1hcHBpbmdfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPGNvbG9yc3BhY2VfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPGZvZ19mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8cHJlbXVsdGlwbGllZF9hbHBoYV9mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8ZGl0aGVyaW5nX2ZyYWdtZW50PlxyXG5cclxufVxyXG5gO1xyXG4iLCJleHBvcnQgY29uc3QgdmVydGV4ID0gLyogZ2xzbCAqL2BcclxuI2RlZmluZSBMQU1CRVJUXHJcblxyXG52YXJ5aW5nIHZlYzMgdlZpZXdQb3NpdGlvbjtcclxuXHJcbiNpbmNsdWRlIDxjb21tb24+XHJcbiNpbmNsdWRlIDxiYXRjaGluZ19wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPHV2X3BhcnNfdmVydGV4PlxyXG4jaW5jbHVkZSA8ZGlzcGxhY2VtZW50bWFwX3BhcnNfdmVydGV4PlxyXG4jaW5jbHVkZSA8ZW52bWFwX3BhcnNfdmVydGV4PlxyXG4jaW5jbHVkZSA8Y29sb3JfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxmb2dfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxub3JtYWxfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxtb3JwaHRhcmdldF9wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPHNraW5uaW5nX3BhcnNfdmVydGV4PlxyXG4jaW5jbHVkZSA8c2hhZG93bWFwX3BhcnNfdmVydGV4PlxyXG4jaW5jbHVkZSA8bG9nZGVwdGhidWZfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxjbGlwcGluZ19wbGFuZXNfcGFyc192ZXJ0ZXg+XHJcblxyXG52b2lkIG1haW4oKSB7XHJcblxyXG5cdCNpbmNsdWRlIDx1dl92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPGNvbG9yX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8bW9ycGhjb2xvcl92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPGJhdGNoaW5nX3ZlcnRleD5cclxuXHJcblx0I2luY2x1ZGUgPGJlZ2lubm9ybWFsX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8bW9ycGhub3JtYWxfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxza2luYmFzZV92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPHNraW5ub3JtYWxfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxkZWZhdWx0bm9ybWFsX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8bm9ybWFsX3ZlcnRleD5cclxuXHJcblx0I2luY2x1ZGUgPGJlZ2luX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8bW9ycGh0YXJnZXRfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxza2lubmluZ192ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPGRpc3BsYWNlbWVudG1hcF92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPHByb2plY3RfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc192ZXJ0ZXg+XHJcblxyXG5cdHZWaWV3UG9zaXRpb24gPSAtIG12UG9zaXRpb24ueHl6O1xyXG5cclxuXHQjaW5jbHVkZSA8d29ybGRwb3NfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxlbnZtYXBfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxzaGFkb3dtYXBfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxmb2dfdmVydGV4PlxyXG5cclxufVxyXG5gO1xyXG5cclxuZXhwb3J0IGNvbnN0IGZyYWdtZW50ID0gLyogZ2xzbCAqL2BcclxuI2RlZmluZSBMQU1CRVJUXHJcblxyXG51bmlmb3JtIHZlYzMgZGlmZnVzZTtcclxudW5pZm9ybSB2ZWMzIGVtaXNzaXZlO1xyXG51bmlmb3JtIGZsb2F0IG9wYWNpdHk7XHJcblxyXG4jaW5jbHVkZSA8Y29tbW9uPlxyXG4jaW5jbHVkZSA8cGFja2luZz5cclxuI2luY2x1ZGUgPGRpdGhlcmluZ19wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8Y29sb3JfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPHV2X3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxtYXBfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGFscGhhbWFwX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxhbHBoYXRlc3RfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGFscGhhaGFzaF9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8YW9tYXBfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGxpZ2h0bWFwX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxlbWlzc2l2ZW1hcF9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8ZW52bWFwX2NvbW1vbl9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8ZW52bWFwX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxmb2dfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGJzZGZzPlxyXG4jaW5jbHVkZSA8bGlnaHRzX3BhcnNfYmVnaW4+XHJcbiNpbmNsdWRlIDxub3JtYWxfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGxpZ2h0c19sYW1iZXJ0X3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxzaGFkb3dtYXBfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGJ1bXBtYXBfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPG5vcm1hbG1hcF9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8c3BlY3VsYXJtYXBfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGxvZ2RlcHRoYnVmX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxjbGlwcGluZ19wbGFuZXNfcGFyc19mcmFnbWVudD5cclxuXHJcbnZvaWQgbWFpbigpIHtcclxuXHJcblx0dmVjNCBkaWZmdXNlQ29sb3IgPSB2ZWM0KCBkaWZmdXNlLCBvcGFjaXR5ICk7XHJcblx0I2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc19mcmFnbWVudD5cclxuXHJcblx0UmVmbGVjdGVkTGlnaHQgcmVmbGVjdGVkTGlnaHQgPSBSZWZsZWN0ZWRMaWdodCggdmVjMyggMC4wICksIHZlYzMoIDAuMCApLCB2ZWMzKCAwLjAgKSwgdmVjMyggMC4wICkgKTtcclxuXHR2ZWMzIHRvdGFsRW1pc3NpdmVSYWRpYW5jZSA9IGVtaXNzaXZlO1xyXG5cclxuXHQjaW5jbHVkZSA8bG9nZGVwdGhidWZfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPG1hcF9mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8Y29sb3JfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPGFscGhhbWFwX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxhbHBoYXRlc3RfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPGFscGhhaGFzaF9mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8c3BlY3VsYXJtYXBfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPG5vcm1hbF9mcmFnbWVudF9iZWdpbj5cclxuXHQjaW5jbHVkZSA8bm9ybWFsX2ZyYWdtZW50X21hcHM+XHJcblx0I2luY2x1ZGUgPGVtaXNzaXZlbWFwX2ZyYWdtZW50PlxyXG5cclxuXHQvLyBhY2N1bXVsYXRpb25cclxuXHQjaW5jbHVkZSA8bGlnaHRzX2xhbWJlcnRfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPGxpZ2h0c19mcmFnbWVudF9iZWdpbj5cclxuXHQjaW5jbHVkZSA8bGlnaHRzX2ZyYWdtZW50X21hcHM+XHJcblx0I2luY2x1ZGUgPGxpZ2h0c19mcmFnbWVudF9lbmQ+XHJcblxyXG5cdC8vIG1vZHVsYXRpb25cclxuXHQjaW5jbHVkZSA8YW9tYXBfZnJhZ21lbnQ+XHJcblxyXG5cdHZlYzMgb3V0Z29pbmdMaWdodCA9IHJlZmxlY3RlZExpZ2h0LmRpcmVjdERpZmZ1c2UgKyByZWZsZWN0ZWRMaWdodC5pbmRpcmVjdERpZmZ1c2UgKyB0b3RhbEVtaXNzaXZlUmFkaWFuY2U7XHJcblxyXG5cdCNpbmNsdWRlIDxlbnZtYXBfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPG9wYXF1ZV9mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8dG9uZW1hcHBpbmdfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPGNvbG9yc3BhY2VfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPGZvZ19mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8cHJlbXVsdGlwbGllZF9hbHBoYV9mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8ZGl0aGVyaW5nX2ZyYWdtZW50PlxyXG5cclxufVxyXG5gO1xyXG4iLCJleHBvcnQgY29uc3QgdmVydGV4ID0gLyogZ2xzbCAqL2BcclxuI2RlZmluZSBNQVRDQVBcclxuXHJcbnZhcnlpbmcgdmVjMyB2Vmlld1Bvc2l0aW9uO1xyXG5cclxuI2luY2x1ZGUgPGNvbW1vbj5cclxuI2luY2x1ZGUgPGJhdGNoaW5nX3BhcnNfdmVydGV4PlxyXG4jaW5jbHVkZSA8dXZfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxjb2xvcl9wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPGRpc3BsYWNlbWVudG1hcF9wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPGZvZ19wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPG5vcm1hbF9wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPG1vcnBodGFyZ2V0X3BhcnNfdmVydGV4PlxyXG4jaW5jbHVkZSA8c2tpbm5pbmdfcGFyc192ZXJ0ZXg+XHJcblxyXG4jaW5jbHVkZSA8bG9nZGVwdGhidWZfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxjbGlwcGluZ19wbGFuZXNfcGFyc192ZXJ0ZXg+XHJcblxyXG52b2lkIG1haW4oKSB7XHJcblxyXG5cdCNpbmNsdWRlIDx1dl92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPGNvbG9yX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8bW9ycGhjb2xvcl92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPGJhdGNoaW5nX3ZlcnRleD5cclxuXHJcblx0I2luY2x1ZGUgPGJlZ2lubm9ybWFsX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8bW9ycGhub3JtYWxfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxza2luYmFzZV92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPHNraW5ub3JtYWxfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxkZWZhdWx0bm9ybWFsX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8bm9ybWFsX3ZlcnRleD5cclxuXHJcblx0I2luY2x1ZGUgPGJlZ2luX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8bW9ycGh0YXJnZXRfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxza2lubmluZ192ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPGRpc3BsYWNlbWVudG1hcF92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPHByb2plY3RfdmVydGV4PlxyXG5cclxuXHQjaW5jbHVkZSA8bG9nZGVwdGhidWZfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxjbGlwcGluZ19wbGFuZXNfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxmb2dfdmVydGV4PlxyXG5cclxuXHR2Vmlld1Bvc2l0aW9uID0gLSBtdlBvc2l0aW9uLnh5ejtcclxuXHJcbn1cclxuYDtcclxuXHJcbmV4cG9ydCBjb25zdCBmcmFnbWVudCA9IC8qIGdsc2wgKi9gXHJcbiNkZWZpbmUgTUFUQ0FQXHJcblxyXG51bmlmb3JtIHZlYzMgZGlmZnVzZTtcclxudW5pZm9ybSBmbG9hdCBvcGFjaXR5O1xyXG51bmlmb3JtIHNhbXBsZXIyRCBtYXRjYXA7XHJcblxyXG52YXJ5aW5nIHZlYzMgdlZpZXdQb3NpdGlvbjtcclxuXHJcbiNpbmNsdWRlIDxjb21tb24+XHJcbiNpbmNsdWRlIDxkaXRoZXJpbmdfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGNvbG9yX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDx1dl9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8bWFwX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxhbHBoYW1hcF9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8YWxwaGF0ZXN0X3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxhbHBoYWhhc2hfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGZvZ19wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8bm9ybWFsX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxidW1wbWFwX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxub3JtYWxtYXBfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGxvZ2RlcHRoYnVmX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxjbGlwcGluZ19wbGFuZXNfcGFyc19mcmFnbWVudD5cclxuXHJcbnZvaWQgbWFpbigpIHtcclxuXHJcblx0dmVjNCBkaWZmdXNlQ29sb3IgPSB2ZWM0KCBkaWZmdXNlLCBvcGFjaXR5ICk7XHJcblx0I2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc19mcmFnbWVudD5cclxuXHJcblx0I2luY2x1ZGUgPGxvZ2RlcHRoYnVmX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxtYXBfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPGNvbG9yX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxhbHBoYW1hcF9mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8YWxwaGF0ZXN0X2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxhbHBoYWhhc2hfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPG5vcm1hbF9mcmFnbWVudF9iZWdpbj5cclxuXHQjaW5jbHVkZSA8bm9ybWFsX2ZyYWdtZW50X21hcHM+XHJcblxyXG5cdHZlYzMgdmlld0RpciA9IG5vcm1hbGl6ZSggdlZpZXdQb3NpdGlvbiApO1xyXG5cdHZlYzMgeCA9IG5vcm1hbGl6ZSggdmVjMyggdmlld0Rpci56LCAwLjAsIC0gdmlld0Rpci54ICkgKTtcclxuXHR2ZWMzIHkgPSBjcm9zcyggdmlld0RpciwgeCApO1xyXG5cdHZlYzIgdXYgPSB2ZWMyKCBkb3QoIHgsIG5vcm1hbCApLCBkb3QoIHksIG5vcm1hbCApICkgKiAwLjQ5NSArIDAuNTsgLy8gMC40OTUgdG8gcmVtb3ZlIGFydGlmYWN0cyBjYXVzZWQgYnkgdW5kZXJzaXplZCBtYXRjYXAgZGlza3NcclxuXHJcblx0I2lmZGVmIFVTRV9NQVRDQVBcclxuXHJcblx0XHR2ZWM0IG1hdGNhcENvbG9yID0gdGV4dHVyZTJEKCBtYXRjYXAsIHV2ICk7XHJcblxyXG5cdCNlbHNlXHJcblxyXG5cdFx0dmVjNCBtYXRjYXBDb2xvciA9IHZlYzQoIHZlYzMoIG1peCggMC4yLCAwLjgsIHV2LnkgKSApLCAxLjAgKTsgLy8gZGVmYXVsdCBpZiBtYXRjYXAgaXMgbWlzc2luZ1xyXG5cclxuXHQjZW5kaWZcclxuXHJcblx0dmVjMyBvdXRnb2luZ0xpZ2h0ID0gZGlmZnVzZUNvbG9yLnJnYiAqIG1hdGNhcENvbG9yLnJnYjtcclxuXHJcblx0I2luY2x1ZGUgPG9wYXF1ZV9mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8dG9uZW1hcHBpbmdfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPGNvbG9yc3BhY2VfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPGZvZ19mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8cHJlbXVsdGlwbGllZF9hbHBoYV9mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8ZGl0aGVyaW5nX2ZyYWdtZW50PlxyXG5cclxufVxyXG5gO1xyXG4iLCJleHBvcnQgY29uc3QgdmVydGV4ID0gLyogZ2xzbCAqL2BcclxuI2RlZmluZSBOT1JNQUxcclxuXHJcbiNpZiBkZWZpbmVkKCBGTEFUX1NIQURFRCApIHx8IGRlZmluZWQoIFVTRV9CVU1QTUFQICkgfHwgZGVmaW5lZCggVVNFX05PUk1BTE1BUF9UQU5HRU5UU1BBQ0UgKVxyXG5cclxuXHR2YXJ5aW5nIHZlYzMgdlZpZXdQb3NpdGlvbjtcclxuXHJcbiNlbmRpZlxyXG5cclxuI2luY2x1ZGUgPGNvbW1vbj5cclxuI2luY2x1ZGUgPGJhdGNoaW5nX3BhcnNfdmVydGV4PlxyXG4jaW5jbHVkZSA8dXZfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxkaXNwbGFjZW1lbnRtYXBfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxub3JtYWxfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxtb3JwaHRhcmdldF9wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPHNraW5uaW5nX3BhcnNfdmVydGV4PlxyXG4jaW5jbHVkZSA8bG9nZGVwdGhidWZfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxjbGlwcGluZ19wbGFuZXNfcGFyc192ZXJ0ZXg+XHJcblxyXG52b2lkIG1haW4oKSB7XHJcblxyXG5cdCNpbmNsdWRlIDx1dl92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPGJhdGNoaW5nX3ZlcnRleD5cclxuXHJcblx0I2luY2x1ZGUgPGJlZ2lubm9ybWFsX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8bW9ycGhub3JtYWxfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxza2luYmFzZV92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPHNraW5ub3JtYWxfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxkZWZhdWx0bm9ybWFsX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8bm9ybWFsX3ZlcnRleD5cclxuXHJcblx0I2luY2x1ZGUgPGJlZ2luX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8bW9ycGh0YXJnZXRfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxza2lubmluZ192ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPGRpc3BsYWNlbWVudG1hcF92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPHByb2plY3RfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc192ZXJ0ZXg+XHJcblxyXG4jaWYgZGVmaW5lZCggRkxBVF9TSEFERUQgKSB8fCBkZWZpbmVkKCBVU0VfQlVNUE1BUCApIHx8IGRlZmluZWQoIFVTRV9OT1JNQUxNQVBfVEFOR0VOVFNQQUNFIClcclxuXHJcblx0dlZpZXdQb3NpdGlvbiA9IC0gbXZQb3NpdGlvbi54eXo7XHJcblxyXG4jZW5kaWZcclxuXHJcbn1cclxuYDtcclxuXHJcbmV4cG9ydCBjb25zdCBmcmFnbWVudCA9IC8qIGdsc2wgKi9gXHJcbiNkZWZpbmUgTk9STUFMXHJcblxyXG51bmlmb3JtIGZsb2F0IG9wYWNpdHk7XHJcblxyXG4jaWYgZGVmaW5lZCggRkxBVF9TSEFERUQgKSB8fCBkZWZpbmVkKCBVU0VfQlVNUE1BUCApIHx8IGRlZmluZWQoIFVTRV9OT1JNQUxNQVBfVEFOR0VOVFNQQUNFIClcclxuXHJcblx0dmFyeWluZyB2ZWMzIHZWaWV3UG9zaXRpb247XHJcblxyXG4jZW5kaWZcclxuXHJcbiNpbmNsdWRlIDxwYWNraW5nPlxyXG4jaW5jbHVkZSA8dXZfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPG5vcm1hbF9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8YnVtcG1hcF9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8bm9ybWFsbWFwX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX3BhcnNfZnJhZ21lbnQ+XHJcblxyXG52b2lkIG1haW4oKSB7XHJcblxyXG5cdHZlYzQgZGlmZnVzZUNvbG9yID0gdmVjNCggMC4wLCAwLjAsIDAuMCwgb3BhY2l0eSApO1xyXG5cclxuXHQjaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl9mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8bm9ybWFsX2ZyYWdtZW50X2JlZ2luPlxyXG5cdCNpbmNsdWRlIDxub3JtYWxfZnJhZ21lbnRfbWFwcz5cclxuXHJcblx0Z2xfRnJhZ0NvbG9yID0gdmVjNCggcGFja05vcm1hbFRvUkdCKCBub3JtYWwgKSwgZGlmZnVzZUNvbG9yLmEgKTtcclxuXHJcblx0I2lmZGVmIE9QQVFVRVxyXG5cclxuXHRcdGdsX0ZyYWdDb2xvci5hID0gMS4wO1xyXG5cclxuXHQjZW5kaWZcclxuXHJcbn1cclxuYDtcclxuIiwiZXhwb3J0IGNvbnN0IHZlcnRleCA9IC8qIGdsc2wgKi9gXHJcbiNkZWZpbmUgUEhPTkdcclxuXHJcbnZhcnlpbmcgdmVjMyB2Vmlld1Bvc2l0aW9uO1xyXG5cclxuI2luY2x1ZGUgPGNvbW1vbj5cclxuI2luY2x1ZGUgPGJhdGNoaW5nX3BhcnNfdmVydGV4PlxyXG4jaW5jbHVkZSA8dXZfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxkaXNwbGFjZW1lbnRtYXBfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxlbnZtYXBfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxjb2xvcl9wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPGZvZ19wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPG5vcm1hbF9wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPG1vcnBodGFyZ2V0X3BhcnNfdmVydGV4PlxyXG4jaW5jbHVkZSA8c2tpbm5pbmdfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxzaGFkb3dtYXBfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl9wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc19wYXJzX3ZlcnRleD5cclxuXHJcbnZvaWQgbWFpbigpIHtcclxuXHJcblx0I2luY2x1ZGUgPHV2X3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8Y29sb3JfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxtb3JwaGNvbG9yX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8YmF0Y2hpbmdfdmVydGV4PlxyXG5cclxuXHQjaW5jbHVkZSA8YmVnaW5ub3JtYWxfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxtb3JwaG5vcm1hbF92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPHNraW5iYXNlX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8c2tpbm5vcm1hbF92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPGRlZmF1bHRub3JtYWxfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxub3JtYWxfdmVydGV4PlxyXG5cclxuXHQjaW5jbHVkZSA8YmVnaW5fdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxtb3JwaHRhcmdldF92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPHNraW5uaW5nX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8ZGlzcGxhY2VtZW50bWFwX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8cHJvamVjdF92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPGxvZ2RlcHRoYnVmX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX3ZlcnRleD5cclxuXHJcblx0dlZpZXdQb3NpdGlvbiA9IC0gbXZQb3NpdGlvbi54eXo7XHJcblxyXG5cdCNpbmNsdWRlIDx3b3JsZHBvc192ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPGVudm1hcF92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPHNoYWRvd21hcF92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPGZvZ192ZXJ0ZXg+XHJcblxyXG59XHJcbmA7XHJcblxyXG5leHBvcnQgY29uc3QgZnJhZ21lbnQgPSAvKiBnbHNsICovYFxyXG4jZGVmaW5lIFBIT05HXHJcblxyXG51bmlmb3JtIHZlYzMgZGlmZnVzZTtcclxudW5pZm9ybSB2ZWMzIGVtaXNzaXZlO1xyXG51bmlmb3JtIHZlYzMgc3BlY3VsYXI7XHJcbnVuaWZvcm0gZmxvYXQgc2hpbmluZXNzO1xyXG51bmlmb3JtIGZsb2F0IG9wYWNpdHk7XHJcblxyXG4jaW5jbHVkZSA8Y29tbW9uPlxyXG4jaW5jbHVkZSA8cGFja2luZz5cclxuI2luY2x1ZGUgPGRpdGhlcmluZ19wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8Y29sb3JfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPHV2X3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxtYXBfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGFscGhhbWFwX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxhbHBoYXRlc3RfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGFscGhhaGFzaF9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8YW9tYXBfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGxpZ2h0bWFwX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxlbWlzc2l2ZW1hcF9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8ZW52bWFwX2NvbW1vbl9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8ZW52bWFwX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxmb2dfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGJzZGZzPlxyXG4jaW5jbHVkZSA8bGlnaHRzX3BhcnNfYmVnaW4+XHJcbiNpbmNsdWRlIDxub3JtYWxfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGxpZ2h0c19waG9uZ19wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8c2hhZG93bWFwX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxidW1wbWFwX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxub3JtYWxtYXBfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPHNwZWN1bGFybWFwX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX3BhcnNfZnJhZ21lbnQ+XHJcblxyXG52b2lkIG1haW4oKSB7XHJcblxyXG5cdHZlYzQgZGlmZnVzZUNvbG9yID0gdmVjNCggZGlmZnVzZSwgb3BhY2l0eSApO1xyXG5cdCNpbmNsdWRlIDxjbGlwcGluZ19wbGFuZXNfZnJhZ21lbnQ+XHJcblxyXG5cdFJlZmxlY3RlZExpZ2h0IHJlZmxlY3RlZExpZ2h0ID0gUmVmbGVjdGVkTGlnaHQoIHZlYzMoIDAuMCApLCB2ZWMzKCAwLjAgKSwgdmVjMyggMC4wICksIHZlYzMoIDAuMCApICk7XHJcblx0dmVjMyB0b3RhbEVtaXNzaXZlUmFkaWFuY2UgPSBlbWlzc2l2ZTtcclxuXHJcblx0I2luY2x1ZGUgPGxvZ2RlcHRoYnVmX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxtYXBfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPGNvbG9yX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxhbHBoYW1hcF9mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8YWxwaGF0ZXN0X2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxhbHBoYWhhc2hfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPHNwZWN1bGFybWFwX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxub3JtYWxfZnJhZ21lbnRfYmVnaW4+XHJcblx0I2luY2x1ZGUgPG5vcm1hbF9mcmFnbWVudF9tYXBzPlxyXG5cdCNpbmNsdWRlIDxlbWlzc2l2ZW1hcF9mcmFnbWVudD5cclxuXHJcblx0Ly8gYWNjdW11bGF0aW9uXHJcblx0I2luY2x1ZGUgPGxpZ2h0c19waG9uZ19mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8bGlnaHRzX2ZyYWdtZW50X2JlZ2luPlxyXG5cdCNpbmNsdWRlIDxsaWdodHNfZnJhZ21lbnRfbWFwcz5cclxuXHQjaW5jbHVkZSA8bGlnaHRzX2ZyYWdtZW50X2VuZD5cclxuXHJcblx0Ly8gbW9kdWxhdGlvblxyXG5cdCNpbmNsdWRlIDxhb21hcF9mcmFnbWVudD5cclxuXHJcblx0dmVjMyBvdXRnb2luZ0xpZ2h0ID0gcmVmbGVjdGVkTGlnaHQuZGlyZWN0RGlmZnVzZSArIHJlZmxlY3RlZExpZ2h0LmluZGlyZWN0RGlmZnVzZSArIHJlZmxlY3RlZExpZ2h0LmRpcmVjdFNwZWN1bGFyICsgcmVmbGVjdGVkTGlnaHQuaW5kaXJlY3RTcGVjdWxhciArIHRvdGFsRW1pc3NpdmVSYWRpYW5jZTtcclxuXHJcblx0I2luY2x1ZGUgPGVudm1hcF9mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8b3BhcXVlX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDx0b25lbWFwcGluZ19mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8Y29sb3JzcGFjZV9mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8Zm9nX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxwcmVtdWx0aXBsaWVkX2FscGhhX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxkaXRoZXJpbmdfZnJhZ21lbnQ+XHJcblxyXG59XHJcbmA7XHJcbiIsImV4cG9ydCBjb25zdCB2ZXJ0ZXggPSAvKiBnbHNsICovYFxyXG4jZGVmaW5lIFNUQU5EQVJEXHJcblxyXG52YXJ5aW5nIHZlYzMgdlZpZXdQb3NpdGlvbjtcclxuXHJcbiNpZmRlZiBVU0VfVFJBTlNNSVNTSU9OXHJcblxyXG5cdHZhcnlpbmcgdmVjMyB2V29ybGRQb3NpdGlvbjtcclxuXHJcbiNlbmRpZlxyXG5cclxuI2luY2x1ZGUgPGNvbW1vbj5cclxuI2luY2x1ZGUgPGJhdGNoaW5nX3BhcnNfdmVydGV4PlxyXG4jaW5jbHVkZSA8dXZfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxkaXNwbGFjZW1lbnRtYXBfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxjb2xvcl9wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPGZvZ19wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPG5vcm1hbF9wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPG1vcnBodGFyZ2V0X3BhcnNfdmVydGV4PlxyXG4jaW5jbHVkZSA8c2tpbm5pbmdfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxzaGFkb3dtYXBfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl9wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc19wYXJzX3ZlcnRleD5cclxuXHJcbnZvaWQgbWFpbigpIHtcclxuXHJcblx0I2luY2x1ZGUgPHV2X3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8Y29sb3JfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxtb3JwaGNvbG9yX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8YmF0Y2hpbmdfdmVydGV4PlxyXG5cclxuXHQjaW5jbHVkZSA8YmVnaW5ub3JtYWxfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxtb3JwaG5vcm1hbF92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPHNraW5iYXNlX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8c2tpbm5vcm1hbF92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPGRlZmF1bHRub3JtYWxfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxub3JtYWxfdmVydGV4PlxyXG5cclxuXHQjaW5jbHVkZSA8YmVnaW5fdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxtb3JwaHRhcmdldF92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPHNraW5uaW5nX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8ZGlzcGxhY2VtZW50bWFwX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8cHJvamVjdF92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPGxvZ2RlcHRoYnVmX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX3ZlcnRleD5cclxuXHJcblx0dlZpZXdQb3NpdGlvbiA9IC0gbXZQb3NpdGlvbi54eXo7XHJcblxyXG5cdCNpbmNsdWRlIDx3b3JsZHBvc192ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPHNoYWRvd21hcF92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPGZvZ192ZXJ0ZXg+XHJcblxyXG4jaWZkZWYgVVNFX1RSQU5TTUlTU0lPTlxyXG5cclxuXHR2V29ybGRQb3NpdGlvbiA9IHdvcmxkUG9zaXRpb24ueHl6O1xyXG5cclxuI2VuZGlmXHJcbn1cclxuYDtcclxuXHJcbmV4cG9ydCBjb25zdCBmcmFnbWVudCA9IC8qIGdsc2wgKi9gXHJcbiNkZWZpbmUgU1RBTkRBUkRcclxuXHJcbiNpZmRlZiBQSFlTSUNBTFxyXG5cdCNkZWZpbmUgSU9SXHJcblx0I2RlZmluZSBVU0VfU1BFQ1VMQVJcclxuI2VuZGlmXHJcblxyXG51bmlmb3JtIHZlYzMgZGlmZnVzZTtcclxudW5pZm9ybSB2ZWMzIGVtaXNzaXZlO1xyXG51bmlmb3JtIGZsb2F0IHJvdWdobmVzcztcclxudW5pZm9ybSBmbG9hdCBtZXRhbG5lc3M7XHJcbnVuaWZvcm0gZmxvYXQgb3BhY2l0eTtcclxuXHJcbiNpZmRlZiBJT1JcclxuXHR1bmlmb3JtIGZsb2F0IGlvcjtcclxuI2VuZGlmXHJcblxyXG4jaWZkZWYgVVNFX1NQRUNVTEFSXHJcblx0dW5pZm9ybSBmbG9hdCBzcGVjdWxhckludGVuc2l0eTtcclxuXHR1bmlmb3JtIHZlYzMgc3BlY3VsYXJDb2xvcjtcclxuXHJcblx0I2lmZGVmIFVTRV9TUEVDVUxBUl9DT0xPUk1BUFxyXG5cdFx0dW5pZm9ybSBzYW1wbGVyMkQgc3BlY3VsYXJDb2xvck1hcDtcclxuXHQjZW5kaWZcclxuXHJcblx0I2lmZGVmIFVTRV9TUEVDVUxBUl9JTlRFTlNJVFlNQVBcclxuXHRcdHVuaWZvcm0gc2FtcGxlcjJEIHNwZWN1bGFySW50ZW5zaXR5TWFwO1xyXG5cdCNlbmRpZlxyXG4jZW5kaWZcclxuXHJcbiNpZmRlZiBVU0VfQ0xFQVJDT0FUXHJcblx0dW5pZm9ybSBmbG9hdCBjbGVhcmNvYXQ7XHJcblx0dW5pZm9ybSBmbG9hdCBjbGVhcmNvYXRSb3VnaG5lc3M7XHJcbiNlbmRpZlxyXG5cclxuI2lmZGVmIFVTRV9JUklERVNDRU5DRVxyXG5cdHVuaWZvcm0gZmxvYXQgaXJpZGVzY2VuY2U7XHJcblx0dW5pZm9ybSBmbG9hdCBpcmlkZXNjZW5jZUlPUjtcclxuXHR1bmlmb3JtIGZsb2F0IGlyaWRlc2NlbmNlVGhpY2tuZXNzTWluaW11bTtcclxuXHR1bmlmb3JtIGZsb2F0IGlyaWRlc2NlbmNlVGhpY2tuZXNzTWF4aW11bTtcclxuI2VuZGlmXHJcblxyXG4jaWZkZWYgVVNFX1NIRUVOXHJcblx0dW5pZm9ybSB2ZWMzIHNoZWVuQ29sb3I7XHJcblx0dW5pZm9ybSBmbG9hdCBzaGVlblJvdWdobmVzcztcclxuXHJcblx0I2lmZGVmIFVTRV9TSEVFTl9DT0xPUk1BUFxyXG5cdFx0dW5pZm9ybSBzYW1wbGVyMkQgc2hlZW5Db2xvck1hcDtcclxuXHQjZW5kaWZcclxuXHJcblx0I2lmZGVmIFVTRV9TSEVFTl9ST1VHSE5FU1NNQVBcclxuXHRcdHVuaWZvcm0gc2FtcGxlcjJEIHNoZWVuUm91Z2huZXNzTWFwO1xyXG5cdCNlbmRpZlxyXG4jZW5kaWZcclxuXHJcbiNpZmRlZiBVU0VfQU5JU09UUk9QWVxyXG5cdHVuaWZvcm0gdmVjMiBhbmlzb3Ryb3B5VmVjdG9yO1xyXG5cclxuXHQjaWZkZWYgVVNFX0FOSVNPVFJPUFlNQVBcclxuXHRcdHVuaWZvcm0gc2FtcGxlcjJEIGFuaXNvdHJvcHlNYXA7XHJcblx0I2VuZGlmXHJcbiNlbmRpZlxyXG5cclxudmFyeWluZyB2ZWMzIHZWaWV3UG9zaXRpb247XHJcblxyXG4jaW5jbHVkZSA8Y29tbW9uPlxyXG4jaW5jbHVkZSA8cGFja2luZz5cclxuI2luY2x1ZGUgPGRpdGhlcmluZ19wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8Y29sb3JfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPHV2X3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxtYXBfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGFscGhhbWFwX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxhbHBoYXRlc3RfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGFscGhhaGFzaF9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8YW9tYXBfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGxpZ2h0bWFwX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxlbWlzc2l2ZW1hcF9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8aXJpZGVzY2VuY2VfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxjdWJlX3V2X3JlZmxlY3Rpb25fZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxlbnZtYXBfY29tbW9uX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxlbnZtYXBfcGh5c2ljYWxfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGZvZ19wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8bGlnaHRzX3BhcnNfYmVnaW4+XHJcbiNpbmNsdWRlIDxub3JtYWxfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGxpZ2h0c19waHlzaWNhbF9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8dHJhbnNtaXNzaW9uX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxzaGFkb3dtYXBfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGJ1bXBtYXBfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPG5vcm1hbG1hcF9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8Y2xlYXJjb2F0X3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxpcmlkZXNjZW5jZV9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8cm91Z2huZXNzbWFwX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxtZXRhbG5lc3NtYXBfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGxvZ2RlcHRoYnVmX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxjbGlwcGluZ19wbGFuZXNfcGFyc19mcmFnbWVudD5cclxuXHJcbnZvaWQgbWFpbigpIHtcclxuXHJcblx0dmVjNCBkaWZmdXNlQ29sb3IgPSB2ZWM0KCBkaWZmdXNlLCBvcGFjaXR5ICk7XHJcblx0I2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc19mcmFnbWVudD5cclxuXHJcblx0UmVmbGVjdGVkTGlnaHQgcmVmbGVjdGVkTGlnaHQgPSBSZWZsZWN0ZWRMaWdodCggdmVjMyggMC4wICksIHZlYzMoIDAuMCApLCB2ZWMzKCAwLjAgKSwgdmVjMyggMC4wICkgKTtcclxuXHR2ZWMzIHRvdGFsRW1pc3NpdmVSYWRpYW5jZSA9IGVtaXNzaXZlO1xyXG5cclxuXHQjaW5jbHVkZSA8bG9nZGVwdGhidWZfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPG1hcF9mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8Y29sb3JfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPGFscGhhbWFwX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxhbHBoYXRlc3RfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPGFscGhhaGFzaF9mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8cm91Z2huZXNzbWFwX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxtZXRhbG5lc3NtYXBfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPG5vcm1hbF9mcmFnbWVudF9iZWdpbj5cclxuXHQjaW5jbHVkZSA8bm9ybWFsX2ZyYWdtZW50X21hcHM+XHJcblx0I2luY2x1ZGUgPGNsZWFyY29hdF9ub3JtYWxfZnJhZ21lbnRfYmVnaW4+XHJcblx0I2luY2x1ZGUgPGNsZWFyY29hdF9ub3JtYWxfZnJhZ21lbnRfbWFwcz5cclxuXHQjaW5jbHVkZSA8ZW1pc3NpdmVtYXBfZnJhZ21lbnQ+XHJcblxyXG5cdC8vIGFjY3VtdWxhdGlvblxyXG5cdCNpbmNsdWRlIDxsaWdodHNfcGh5c2ljYWxfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPGxpZ2h0c19mcmFnbWVudF9iZWdpbj5cclxuXHQjaW5jbHVkZSA8bGlnaHRzX2ZyYWdtZW50X21hcHM+XHJcblx0I2luY2x1ZGUgPGxpZ2h0c19mcmFnbWVudF9lbmQ+XHJcblxyXG5cdC8vIG1vZHVsYXRpb25cclxuXHQjaW5jbHVkZSA8YW9tYXBfZnJhZ21lbnQ+XHJcblxyXG5cdHZlYzMgdG90YWxEaWZmdXNlID0gcmVmbGVjdGVkTGlnaHQuZGlyZWN0RGlmZnVzZSArIHJlZmxlY3RlZExpZ2h0LmluZGlyZWN0RGlmZnVzZTtcclxuXHR2ZWMzIHRvdGFsU3BlY3VsYXIgPSByZWZsZWN0ZWRMaWdodC5kaXJlY3RTcGVjdWxhciArIHJlZmxlY3RlZExpZ2h0LmluZGlyZWN0U3BlY3VsYXI7XHJcblxyXG5cdCNpbmNsdWRlIDx0cmFuc21pc3Npb25fZnJhZ21lbnQ+XHJcblxyXG5cdHZlYzMgb3V0Z29pbmdMaWdodCA9IHRvdGFsRGlmZnVzZSArIHRvdGFsU3BlY3VsYXIgKyB0b3RhbEVtaXNzaXZlUmFkaWFuY2U7XHJcblxyXG5cdCNpZmRlZiBVU0VfU0hFRU5cclxuXHJcblx0XHQvLyBTaGVlbiBlbmVyZ3kgY29tcGVuc2F0aW9uIGFwcHJveGltYXRpb24gY2FsY3VsYXRpb24gY2FuIGJlIGZvdW5kIGF0IHRoZSBlbmQgb2ZcclxuXHRcdC8vIGh0dHBzOi8vZHJpdmUuZ29vZ2xlLmNvbS9maWxlL2QvMVQwRDFWU3lSNEFsbHFJSlRRQXJhRUl6amxiNWg0RktIL3ZpZXc/dXNwPXNoYXJpbmdcclxuXHRcdGZsb2F0IHNoZWVuRW5lcmd5Q29tcCA9IDEuMCAtIDAuMTU3ICogbWF4MyggbWF0ZXJpYWwuc2hlZW5Db2xvciApO1xyXG5cclxuXHRcdG91dGdvaW5nTGlnaHQgPSBvdXRnb2luZ0xpZ2h0ICogc2hlZW5FbmVyZ3lDb21wICsgc2hlZW5TcGVjdWxhckRpcmVjdCArIHNoZWVuU3BlY3VsYXJJbmRpcmVjdDtcclxuXHJcblx0I2VuZGlmXHJcblxyXG5cdCNpZmRlZiBVU0VfQ0xFQVJDT0FUXHJcblxyXG5cdFx0ZmxvYXQgZG90TlZjYyA9IHNhdHVyYXRlKCBkb3QoIGdlb21ldHJ5Q2xlYXJjb2F0Tm9ybWFsLCBnZW9tZXRyeVZpZXdEaXIgKSApO1xyXG5cclxuXHRcdHZlYzMgRmNjID0gRl9TY2hsaWNrKCBtYXRlcmlhbC5jbGVhcmNvYXRGMCwgbWF0ZXJpYWwuY2xlYXJjb2F0RjkwLCBkb3ROVmNjICk7XHJcblxyXG5cdFx0b3V0Z29pbmdMaWdodCA9IG91dGdvaW5nTGlnaHQgKiAoIDEuMCAtIG1hdGVyaWFsLmNsZWFyY29hdCAqIEZjYyApICsgKCBjbGVhcmNvYXRTcGVjdWxhckRpcmVjdCArIGNsZWFyY29hdFNwZWN1bGFySW5kaXJlY3QgKSAqIG1hdGVyaWFsLmNsZWFyY29hdDtcclxuXHJcblx0I2VuZGlmXHJcblxyXG5cdCNpbmNsdWRlIDxvcGFxdWVfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPHRvbmVtYXBwaW5nX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxjb2xvcnNwYWNlX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxmb2dfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPHByZW11bHRpcGxpZWRfYWxwaGFfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPGRpdGhlcmluZ19mcmFnbWVudD5cclxuXHJcbn1cclxuYDtcclxuIiwiZXhwb3J0IGNvbnN0IHZlcnRleCA9IC8qIGdsc2wgKi9gXHJcbiNkZWZpbmUgVE9PTlxyXG5cclxudmFyeWluZyB2ZWMzIHZWaWV3UG9zaXRpb247XHJcblxyXG4jaW5jbHVkZSA8Y29tbW9uPlxyXG4jaW5jbHVkZSA8YmF0Y2hpbmdfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDx1dl9wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPGRpc3BsYWNlbWVudG1hcF9wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPGNvbG9yX3BhcnNfdmVydGV4PlxyXG4jaW5jbHVkZSA8Zm9nX3BhcnNfdmVydGV4PlxyXG4jaW5jbHVkZSA8bm9ybWFsX3BhcnNfdmVydGV4PlxyXG4jaW5jbHVkZSA8bW9ycGh0YXJnZXRfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxza2lubmluZ19wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPHNoYWRvd21hcF9wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPGxvZ2RlcHRoYnVmX3BhcnNfdmVydGV4PlxyXG4jaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX3BhcnNfdmVydGV4PlxyXG5cclxudm9pZCBtYWluKCkge1xyXG5cclxuXHQjaW5jbHVkZSA8dXZfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxjb2xvcl92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPG1vcnBoY29sb3JfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxiYXRjaGluZ192ZXJ0ZXg+XHJcblxyXG5cdCNpbmNsdWRlIDxiZWdpbm5vcm1hbF92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPG1vcnBobm9ybWFsX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8c2tpbmJhc2VfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxza2lubm9ybWFsX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8ZGVmYXVsdG5vcm1hbF92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPG5vcm1hbF92ZXJ0ZXg+XHJcblxyXG5cdCNpbmNsdWRlIDxiZWdpbl92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPG1vcnBodGFyZ2V0X3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8c2tpbm5pbmdfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxkaXNwbGFjZW1lbnRtYXBfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxwcm9qZWN0X3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8bG9nZGVwdGhidWZfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxjbGlwcGluZ19wbGFuZXNfdmVydGV4PlxyXG5cclxuXHR2Vmlld1Bvc2l0aW9uID0gLSBtdlBvc2l0aW9uLnh5ejtcclxuXHJcblx0I2luY2x1ZGUgPHdvcmxkcG9zX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8c2hhZG93bWFwX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8Zm9nX3ZlcnRleD5cclxuXHJcbn1cclxuYDtcclxuXHJcbmV4cG9ydCBjb25zdCBmcmFnbWVudCA9IC8qIGdsc2wgKi9gXHJcbiNkZWZpbmUgVE9PTlxyXG5cclxudW5pZm9ybSB2ZWMzIGRpZmZ1c2U7XHJcbnVuaWZvcm0gdmVjMyBlbWlzc2l2ZTtcclxudW5pZm9ybSBmbG9hdCBvcGFjaXR5O1xyXG5cclxuI2luY2x1ZGUgPGNvbW1vbj5cclxuI2luY2x1ZGUgPHBhY2tpbmc+XHJcbiNpbmNsdWRlIDxkaXRoZXJpbmdfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGNvbG9yX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDx1dl9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8bWFwX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxhbHBoYW1hcF9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8YWxwaGF0ZXN0X3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxhbHBoYWhhc2hfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGFvbWFwX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxsaWdodG1hcF9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8ZW1pc3NpdmVtYXBfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGdyYWRpZW50bWFwX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxmb2dfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGJzZGZzPlxyXG4jaW5jbHVkZSA8bGlnaHRzX3BhcnNfYmVnaW4+XHJcbiNpbmNsdWRlIDxub3JtYWxfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGxpZ2h0c190b29uX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxzaGFkb3dtYXBfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGJ1bXBtYXBfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPG5vcm1hbG1hcF9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8bG9nZGVwdGhidWZfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc19wYXJzX2ZyYWdtZW50PlxyXG5cclxudm9pZCBtYWluKCkge1xyXG5cclxuXHR2ZWM0IGRpZmZ1c2VDb2xvciA9IHZlYzQoIGRpZmZ1c2UsIG9wYWNpdHkgKTtcclxuXHQjaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX2ZyYWdtZW50PlxyXG5cclxuXHRSZWZsZWN0ZWRMaWdodCByZWZsZWN0ZWRMaWdodCA9IFJlZmxlY3RlZExpZ2h0KCB2ZWMzKCAwLjAgKSwgdmVjMyggMC4wICksIHZlYzMoIDAuMCApLCB2ZWMzKCAwLjAgKSApO1xyXG5cdHZlYzMgdG90YWxFbWlzc2l2ZVJhZGlhbmNlID0gZW1pc3NpdmU7XHJcblxyXG5cdCNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl9mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8bWFwX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxjb2xvcl9mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8YWxwaGFtYXBfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPGFscGhhdGVzdF9mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8YWxwaGFoYXNoX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxub3JtYWxfZnJhZ21lbnRfYmVnaW4+XHJcblx0I2luY2x1ZGUgPG5vcm1hbF9mcmFnbWVudF9tYXBzPlxyXG5cdCNpbmNsdWRlIDxlbWlzc2l2ZW1hcF9mcmFnbWVudD5cclxuXHJcblx0Ly8gYWNjdW11bGF0aW9uXHJcblx0I2luY2x1ZGUgPGxpZ2h0c190b29uX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxsaWdodHNfZnJhZ21lbnRfYmVnaW4+XHJcblx0I2luY2x1ZGUgPGxpZ2h0c19mcmFnbWVudF9tYXBzPlxyXG5cdCNpbmNsdWRlIDxsaWdodHNfZnJhZ21lbnRfZW5kPlxyXG5cclxuXHQvLyBtb2R1bGF0aW9uXHJcblx0I2luY2x1ZGUgPGFvbWFwX2ZyYWdtZW50PlxyXG5cclxuXHR2ZWMzIG91dGdvaW5nTGlnaHQgPSByZWZsZWN0ZWRMaWdodC5kaXJlY3REaWZmdXNlICsgcmVmbGVjdGVkTGlnaHQuaW5kaXJlY3REaWZmdXNlICsgdG90YWxFbWlzc2l2ZVJhZGlhbmNlO1xyXG5cclxuXHQjaW5jbHVkZSA8b3BhcXVlX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDx0b25lbWFwcGluZ19mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8Y29sb3JzcGFjZV9mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8Zm9nX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxwcmVtdWx0aXBsaWVkX2FscGhhX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxkaXRoZXJpbmdfZnJhZ21lbnQ+XHJcblxyXG59XHJcbmA7XHJcbiIsImV4cG9ydCBjb25zdCB2ZXJ0ZXggPSAvKiBnbHNsICovYFxyXG51bmlmb3JtIGZsb2F0IHNpemU7XHJcbnVuaWZvcm0gZmxvYXQgc2NhbGU7XHJcblxyXG4jaW5jbHVkZSA8Y29tbW9uPlxyXG4jaW5jbHVkZSA8Y29sb3JfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxmb2dfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxtb3JwaHRhcmdldF9wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPGxvZ2RlcHRoYnVmX3BhcnNfdmVydGV4PlxyXG4jaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX3BhcnNfdmVydGV4PlxyXG5cclxuI2lmZGVmIFVTRV9QT0lOVFNfVVZcclxuXHJcblx0dmFyeWluZyB2ZWMyIHZVdjtcclxuXHR1bmlmb3JtIG1hdDMgdXZUcmFuc2Zvcm07XHJcblxyXG4jZW5kaWZcclxuXHJcbnZvaWQgbWFpbigpIHtcclxuXHJcblx0I2lmZGVmIFVTRV9QT0lOVFNfVVZcclxuXHJcblx0XHR2VXYgPSAoIHV2VHJhbnNmb3JtICogdmVjMyggdXYsIDEgKSApLnh5O1xyXG5cclxuXHQjZW5kaWZcclxuXHJcblx0I2luY2x1ZGUgPGNvbG9yX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8bW9ycGhjb2xvcl92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPGJlZ2luX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8bW9ycGh0YXJnZXRfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxwcm9qZWN0X3ZlcnRleD5cclxuXHJcblx0Z2xfUG9pbnRTaXplID0gc2l6ZTtcclxuXHJcblx0I2lmZGVmIFVTRV9TSVpFQVRURU5VQVRJT05cclxuXHJcblx0XHRib29sIGlzUGVyc3BlY3RpdmUgPSBpc1BlcnNwZWN0aXZlTWF0cml4KCBwcm9qZWN0aW9uTWF0cml4ICk7XHJcblxyXG5cdFx0aWYgKCBpc1BlcnNwZWN0aXZlICkgZ2xfUG9pbnRTaXplICo9ICggc2NhbGUgLyAtIG12UG9zaXRpb24ueiApO1xyXG5cclxuXHQjZW5kaWZcclxuXHJcblx0I2luY2x1ZGUgPGxvZ2RlcHRoYnVmX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8d29ybGRwb3NfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxmb2dfdmVydGV4PlxyXG5cclxufVxyXG5gO1xyXG5cclxuZXhwb3J0IGNvbnN0IGZyYWdtZW50ID0gLyogZ2xzbCAqL2BcclxudW5pZm9ybSB2ZWMzIGRpZmZ1c2U7XHJcbnVuaWZvcm0gZmxvYXQgb3BhY2l0eTtcclxuXHJcbiNpbmNsdWRlIDxjb21tb24+XHJcbiNpbmNsdWRlIDxjb2xvcl9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8bWFwX3BhcnRpY2xlX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxhbHBoYXRlc3RfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGFscGhhaGFzaF9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8Zm9nX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX3BhcnNfZnJhZ21lbnQ+XHJcblxyXG52b2lkIG1haW4oKSB7XHJcblxyXG5cdHZlYzQgZGlmZnVzZUNvbG9yID0gdmVjNCggZGlmZnVzZSwgb3BhY2l0eSApO1xyXG5cdCNpbmNsdWRlIDxjbGlwcGluZ19wbGFuZXNfZnJhZ21lbnQ+XHJcblxyXG5cdHZlYzMgb3V0Z29pbmdMaWdodCA9IHZlYzMoIDAuMCApO1xyXG5cclxuXHQjaW5jbHVkZSA8bG9nZGVwdGhidWZfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPG1hcF9wYXJ0aWNsZV9mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8Y29sb3JfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPGFscGhhdGVzdF9mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8YWxwaGFoYXNoX2ZyYWdtZW50PlxyXG5cclxuXHRvdXRnb2luZ0xpZ2h0ID0gZGlmZnVzZUNvbG9yLnJnYjtcclxuXHJcblx0I2luY2x1ZGUgPG9wYXF1ZV9mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8dG9uZW1hcHBpbmdfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPGNvbG9yc3BhY2VfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPGZvZ19mcmFnbWVudD5cclxuXHQjaW5jbHVkZSA8cHJlbXVsdGlwbGllZF9hbHBoYV9mcmFnbWVudD5cclxuXHJcbn1cclxuYDtcclxuIiwiZXhwb3J0IGNvbnN0IHZlcnRleCA9IC8qIGdsc2wgKi9gXHJcbiNpbmNsdWRlIDxjb21tb24+XHJcbiNpbmNsdWRlIDxiYXRjaGluZ19wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPGZvZ19wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPG1vcnBodGFyZ2V0X3BhcnNfdmVydGV4PlxyXG4jaW5jbHVkZSA8c2tpbm5pbmdfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl9wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPHNoYWRvd21hcF9wYXJzX3ZlcnRleD5cclxuXHJcbnZvaWQgbWFpbigpIHtcclxuXHJcblx0I2luY2x1ZGUgPGJhdGNoaW5nX3ZlcnRleD5cclxuXHJcblx0I2luY2x1ZGUgPGJlZ2lubm9ybWFsX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8bW9ycGhub3JtYWxfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxza2luYmFzZV92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPHNraW5ub3JtYWxfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxkZWZhdWx0bm9ybWFsX3ZlcnRleD5cclxuXHJcblx0I2luY2x1ZGUgPGJlZ2luX3ZlcnRleD5cclxuXHQjaW5jbHVkZSA8bW9ycGh0YXJnZXRfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxza2lubmluZ192ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPHByb2plY3RfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl92ZXJ0ZXg+XHJcblxyXG5cdCNpbmNsdWRlIDx3b3JsZHBvc192ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPHNoYWRvd21hcF92ZXJ0ZXg+XHJcblx0I2luY2x1ZGUgPGZvZ192ZXJ0ZXg+XHJcblxyXG59XHJcbmA7XHJcblxyXG5leHBvcnQgY29uc3QgZnJhZ21lbnQgPSAvKiBnbHNsICovYFxyXG51bmlmb3JtIHZlYzMgY29sb3I7XHJcbnVuaWZvcm0gZmxvYXQgb3BhY2l0eTtcclxuXHJcbiNpbmNsdWRlIDxjb21tb24+XHJcbiNpbmNsdWRlIDxwYWNraW5nPlxyXG4jaW5jbHVkZSA8Zm9nX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxic2Rmcz5cclxuI2luY2x1ZGUgPGxpZ2h0c19wYXJzX2JlZ2luPlxyXG4jaW5jbHVkZSA8bG9nZGVwdGhidWZfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPHNoYWRvd21hcF9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8c2hhZG93bWFza19wYXJzX2ZyYWdtZW50PlxyXG5cclxudm9pZCBtYWluKCkge1xyXG5cclxuXHQjaW5jbHVkZSA8bG9nZGVwdGhidWZfZnJhZ21lbnQ+XHJcblxyXG5cdGdsX0ZyYWdDb2xvciA9IHZlYzQoIGNvbG9yLCBvcGFjaXR5ICogKCAxLjAgLSBnZXRTaGFkb3dNYXNrKCkgKSApO1xyXG5cclxuXHQjaW5jbHVkZSA8dG9uZW1hcHBpbmdfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPGNvbG9yc3BhY2VfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPGZvZ19mcmFnbWVudD5cclxuXHJcbn1cclxuYDtcclxuIiwiZXhwb3J0IGNvbnN0IHZlcnRleCA9IC8qIGdsc2wgKi9gXHJcbnVuaWZvcm0gZmxvYXQgcm90YXRpb247XHJcbnVuaWZvcm0gdmVjMiBjZW50ZXI7XHJcblxyXG4jaW5jbHVkZSA8Y29tbW9uPlxyXG4jaW5jbHVkZSA8dXZfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxmb2dfcGFyc192ZXJ0ZXg+XHJcbiNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl9wYXJzX3ZlcnRleD5cclxuI2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc19wYXJzX3ZlcnRleD5cclxuXHJcbnZvaWQgbWFpbigpIHtcclxuXHJcblx0I2luY2x1ZGUgPHV2X3ZlcnRleD5cclxuXHJcblx0dmVjNCBtdlBvc2l0aW9uID0gbW9kZWxWaWV3TWF0cml4ICogdmVjNCggMC4wLCAwLjAsIDAuMCwgMS4wICk7XHJcblxyXG5cdHZlYzIgc2NhbGU7XHJcblx0c2NhbGUueCA9IGxlbmd0aCggdmVjMyggbW9kZWxNYXRyaXhbIDAgXS54LCBtb2RlbE1hdHJpeFsgMCBdLnksIG1vZGVsTWF0cml4WyAwIF0ueiApICk7XHJcblx0c2NhbGUueSA9IGxlbmd0aCggdmVjMyggbW9kZWxNYXRyaXhbIDEgXS54LCBtb2RlbE1hdHJpeFsgMSBdLnksIG1vZGVsTWF0cml4WyAxIF0ueiApICk7XHJcblxyXG5cdCNpZm5kZWYgVVNFX1NJWkVBVFRFTlVBVElPTlxyXG5cclxuXHRcdGJvb2wgaXNQZXJzcGVjdGl2ZSA9IGlzUGVyc3BlY3RpdmVNYXRyaXgoIHByb2plY3Rpb25NYXRyaXggKTtcclxuXHJcblx0XHRpZiAoIGlzUGVyc3BlY3RpdmUgKSBzY2FsZSAqPSAtIG12UG9zaXRpb24uejtcclxuXHJcblx0I2VuZGlmXHJcblxyXG5cdHZlYzIgYWxpZ25lZFBvc2l0aW9uID0gKCBwb3NpdGlvbi54eSAtICggY2VudGVyIC0gdmVjMiggMC41ICkgKSApICogc2NhbGU7XHJcblxyXG5cdHZlYzIgcm90YXRlZFBvc2l0aW9uO1xyXG5cdHJvdGF0ZWRQb3NpdGlvbi54ID0gY29zKCByb3RhdGlvbiApICogYWxpZ25lZFBvc2l0aW9uLnggLSBzaW4oIHJvdGF0aW9uICkgKiBhbGlnbmVkUG9zaXRpb24ueTtcclxuXHRyb3RhdGVkUG9zaXRpb24ueSA9IHNpbiggcm90YXRpb24gKSAqIGFsaWduZWRQb3NpdGlvbi54ICsgY29zKCByb3RhdGlvbiApICogYWxpZ25lZFBvc2l0aW9uLnk7XHJcblxyXG5cdG12UG9zaXRpb24ueHkgKz0gcm90YXRlZFBvc2l0aW9uO1xyXG5cclxuXHRnbF9Qb3NpdGlvbiA9IHByb2plY3Rpb25NYXRyaXggKiBtdlBvc2l0aW9uO1xyXG5cclxuXHQjaW5jbHVkZSA8bG9nZGVwdGhidWZfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxjbGlwcGluZ19wbGFuZXNfdmVydGV4PlxyXG5cdCNpbmNsdWRlIDxmb2dfdmVydGV4PlxyXG5cclxufVxyXG5gO1xyXG5cclxuZXhwb3J0IGNvbnN0IGZyYWdtZW50ID0gLyogZ2xzbCAqL2BcclxudW5pZm9ybSB2ZWMzIGRpZmZ1c2U7XHJcbnVuaWZvcm0gZmxvYXQgb3BhY2l0eTtcclxuXHJcbiNpbmNsdWRlIDxjb21tb24+XHJcbiNpbmNsdWRlIDx1dl9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8bWFwX3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxhbHBoYW1hcF9wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8YWxwaGF0ZXN0X3BhcnNfZnJhZ21lbnQ+XHJcbiNpbmNsdWRlIDxhbHBoYWhhc2hfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGZvZ19wYXJzX2ZyYWdtZW50PlxyXG4jaW5jbHVkZSA8bG9nZGVwdGhidWZfcGFyc19mcmFnbWVudD5cclxuI2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc19wYXJzX2ZyYWdtZW50PlxyXG5cclxudm9pZCBtYWluKCkge1xyXG5cclxuXHR2ZWM0IGRpZmZ1c2VDb2xvciA9IHZlYzQoIGRpZmZ1c2UsIG9wYWNpdHkgKTtcclxuXHQjaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX2ZyYWdtZW50PlxyXG5cclxuXHR2ZWMzIG91dGdvaW5nTGlnaHQgPSB2ZWMzKCAwLjAgKTtcclxuXHJcblx0I2luY2x1ZGUgPGxvZ2RlcHRoYnVmX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxtYXBfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPGFscGhhbWFwX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxhbHBoYXRlc3RfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPGFscGhhaGFzaF9mcmFnbWVudD5cclxuXHJcblx0b3V0Z29pbmdMaWdodCA9IGRpZmZ1c2VDb2xvci5yZ2I7XHJcblxyXG5cdCNpbmNsdWRlIDxvcGFxdWVfZnJhZ21lbnQ+XHJcblx0I2luY2x1ZGUgPHRvbmVtYXBwaW5nX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxjb2xvcnNwYWNlX2ZyYWdtZW50PlxyXG5cdCNpbmNsdWRlIDxmb2dfZnJhZ21lbnQ+XHJcblxyXG59XHJcbmA7XHJcbiIsImltcG9ydCBhbHBoYWhhc2hfZnJhZ21lbnQgZnJvbSAnLi9TaGFkZXJDaHVuay9hbHBoYWhhc2hfZnJhZ21lbnQuZ2xzbC5qcyc7XHJcbmltcG9ydCBhbHBoYWhhc2hfcGFyc19mcmFnbWVudCBmcm9tICcuL1NoYWRlckNodW5rL2FscGhhaGFzaF9wYXJzX2ZyYWdtZW50Lmdsc2wuanMnO1xyXG5pbXBvcnQgYWxwaGFtYXBfZnJhZ21lbnQgZnJvbSAnLi9TaGFkZXJDaHVuay9hbHBoYW1hcF9mcmFnbWVudC5nbHNsLmpzJztcclxuaW1wb3J0IGFscGhhbWFwX3BhcnNfZnJhZ21lbnQgZnJvbSAnLi9TaGFkZXJDaHVuay9hbHBoYW1hcF9wYXJzX2ZyYWdtZW50Lmdsc2wuanMnO1xyXG5pbXBvcnQgYWxwaGF0ZXN0X2ZyYWdtZW50IGZyb20gJy4vU2hhZGVyQ2h1bmsvYWxwaGF0ZXN0X2ZyYWdtZW50Lmdsc2wuanMnO1xyXG5pbXBvcnQgYWxwaGF0ZXN0X3BhcnNfZnJhZ21lbnQgZnJvbSAnLi9TaGFkZXJDaHVuay9hbHBoYXRlc3RfcGFyc19mcmFnbWVudC5nbHNsLmpzJztcclxuaW1wb3J0IGFvbWFwX2ZyYWdtZW50IGZyb20gJy4vU2hhZGVyQ2h1bmsvYW9tYXBfZnJhZ21lbnQuZ2xzbC5qcyc7XHJcbmltcG9ydCBhb21hcF9wYXJzX2ZyYWdtZW50IGZyb20gJy4vU2hhZGVyQ2h1bmsvYW9tYXBfcGFyc19mcmFnbWVudC5nbHNsLmpzJztcclxuaW1wb3J0IGJhdGNoaW5nX3BhcnNfdmVydGV4IGZyb20gJy4vU2hhZGVyQ2h1bmsvYmF0Y2hpbmdfcGFyc192ZXJ0ZXguZ2xzbC5qcyc7XHJcbmltcG9ydCBiYXRjaGluZ192ZXJ0ZXggZnJvbSAnLi9TaGFkZXJDaHVuay9iYXRjaGluZ192ZXJ0ZXguZ2xzbC5qcyc7XHJcbmltcG9ydCBiZWdpbl92ZXJ0ZXggZnJvbSAnLi9TaGFkZXJDaHVuay9iZWdpbl92ZXJ0ZXguZ2xzbC5qcyc7XHJcbmltcG9ydCBiZWdpbm5vcm1hbF92ZXJ0ZXggZnJvbSAnLi9TaGFkZXJDaHVuay9iZWdpbm5vcm1hbF92ZXJ0ZXguZ2xzbC5qcyc7XHJcbmltcG9ydCBic2RmcyBmcm9tICcuL1NoYWRlckNodW5rL2JzZGZzLmdsc2wuanMnO1xyXG5pbXBvcnQgaXJpZGVzY2VuY2VfZnJhZ21lbnQgZnJvbSAnLi9TaGFkZXJDaHVuay9pcmlkZXNjZW5jZV9mcmFnbWVudC5nbHNsLmpzJztcclxuaW1wb3J0IGJ1bXBtYXBfcGFyc19mcmFnbWVudCBmcm9tICcuL1NoYWRlckNodW5rL2J1bXBtYXBfcGFyc19mcmFnbWVudC5nbHNsLmpzJztcclxuaW1wb3J0IGNsaXBwaW5nX3BsYW5lc19mcmFnbWVudCBmcm9tICcuL1NoYWRlckNodW5rL2NsaXBwaW5nX3BsYW5lc19mcmFnbWVudC5nbHNsLmpzJztcclxuaW1wb3J0IGNsaXBwaW5nX3BsYW5lc19wYXJzX2ZyYWdtZW50IGZyb20gJy4vU2hhZGVyQ2h1bmsvY2xpcHBpbmdfcGxhbmVzX3BhcnNfZnJhZ21lbnQuZ2xzbC5qcyc7XHJcbmltcG9ydCBjbGlwcGluZ19wbGFuZXNfcGFyc192ZXJ0ZXggZnJvbSAnLi9TaGFkZXJDaHVuay9jbGlwcGluZ19wbGFuZXNfcGFyc192ZXJ0ZXguZ2xzbC5qcyc7XHJcbmltcG9ydCBjbGlwcGluZ19wbGFuZXNfdmVydGV4IGZyb20gJy4vU2hhZGVyQ2h1bmsvY2xpcHBpbmdfcGxhbmVzX3ZlcnRleC5nbHNsLmpzJztcclxuaW1wb3J0IGNvbG9yX2ZyYWdtZW50IGZyb20gJy4vU2hhZGVyQ2h1bmsvY29sb3JfZnJhZ21lbnQuZ2xzbC5qcyc7XHJcbmltcG9ydCBjb2xvcl9wYXJzX2ZyYWdtZW50IGZyb20gJy4vU2hhZGVyQ2h1bmsvY29sb3JfcGFyc19mcmFnbWVudC5nbHNsLmpzJztcclxuaW1wb3J0IGNvbG9yX3BhcnNfdmVydGV4IGZyb20gJy4vU2hhZGVyQ2h1bmsvY29sb3JfcGFyc192ZXJ0ZXguZ2xzbC5qcyc7XHJcbmltcG9ydCBjb2xvcl92ZXJ0ZXggZnJvbSAnLi9TaGFkZXJDaHVuay9jb2xvcl92ZXJ0ZXguZ2xzbC5qcyc7XHJcbmltcG9ydCBjb21tb24gZnJvbSAnLi9TaGFkZXJDaHVuay9jb21tb24uZ2xzbC5qcyc7XHJcbmltcG9ydCBjdWJlX3V2X3JlZmxlY3Rpb25fZnJhZ21lbnQgZnJvbSAnLi9TaGFkZXJDaHVuay9jdWJlX3V2X3JlZmxlY3Rpb25fZnJhZ21lbnQuZ2xzbC5qcyc7XHJcbmltcG9ydCBkZWZhdWx0bm9ybWFsX3ZlcnRleCBmcm9tICcuL1NoYWRlckNodW5rL2RlZmF1bHRub3JtYWxfdmVydGV4Lmdsc2wuanMnO1xyXG5pbXBvcnQgZGlzcGxhY2VtZW50bWFwX3BhcnNfdmVydGV4IGZyb20gJy4vU2hhZGVyQ2h1bmsvZGlzcGxhY2VtZW50bWFwX3BhcnNfdmVydGV4Lmdsc2wuanMnO1xyXG5pbXBvcnQgZGlzcGxhY2VtZW50bWFwX3ZlcnRleCBmcm9tICcuL1NoYWRlckNodW5rL2Rpc3BsYWNlbWVudG1hcF92ZXJ0ZXguZ2xzbC5qcyc7XHJcbmltcG9ydCBlbWlzc2l2ZW1hcF9mcmFnbWVudCBmcm9tICcuL1NoYWRlckNodW5rL2VtaXNzaXZlbWFwX2ZyYWdtZW50Lmdsc2wuanMnO1xyXG5pbXBvcnQgZW1pc3NpdmVtYXBfcGFyc19mcmFnbWVudCBmcm9tICcuL1NoYWRlckNodW5rL2VtaXNzaXZlbWFwX3BhcnNfZnJhZ21lbnQuZ2xzbC5qcyc7XHJcbmltcG9ydCBjb2xvcnNwYWNlX2ZyYWdtZW50IGZyb20gJy4vU2hhZGVyQ2h1bmsvY29sb3JzcGFjZV9mcmFnbWVudC5nbHNsLmpzJztcclxuaW1wb3J0IGNvbG9yc3BhY2VfcGFyc19mcmFnbWVudCBmcm9tICcuL1NoYWRlckNodW5rL2NvbG9yc3BhY2VfcGFyc19mcmFnbWVudC5nbHNsLmpzJztcclxuaW1wb3J0IGVudm1hcF9mcmFnbWVudCBmcm9tICcuL1NoYWRlckNodW5rL2Vudm1hcF9mcmFnbWVudC5nbHNsLmpzJztcclxuaW1wb3J0IGVudm1hcF9jb21tb25fcGFyc19mcmFnbWVudCBmcm9tICcuL1NoYWRlckNodW5rL2Vudm1hcF9jb21tb25fcGFyc19mcmFnbWVudC5nbHNsLmpzJztcclxuaW1wb3J0IGVudm1hcF9wYXJzX2ZyYWdtZW50IGZyb20gJy4vU2hhZGVyQ2h1bmsvZW52bWFwX3BhcnNfZnJhZ21lbnQuZ2xzbC5qcyc7XHJcbmltcG9ydCBlbnZtYXBfcGFyc192ZXJ0ZXggZnJvbSAnLi9TaGFkZXJDaHVuay9lbnZtYXBfcGFyc192ZXJ0ZXguZ2xzbC5qcyc7XHJcbmltcG9ydCBlbnZtYXBfdmVydGV4IGZyb20gJy4vU2hhZGVyQ2h1bmsvZW52bWFwX3ZlcnRleC5nbHNsLmpzJztcclxuaW1wb3J0IGZvZ192ZXJ0ZXggZnJvbSAnLi9TaGFkZXJDaHVuay9mb2dfdmVydGV4Lmdsc2wuanMnO1xyXG5pbXBvcnQgZm9nX3BhcnNfdmVydGV4IGZyb20gJy4vU2hhZGVyQ2h1bmsvZm9nX3BhcnNfdmVydGV4Lmdsc2wuanMnO1xyXG5pbXBvcnQgZm9nX2ZyYWdtZW50IGZyb20gJy4vU2hhZGVyQ2h1bmsvZm9nX2ZyYWdtZW50Lmdsc2wuanMnO1xyXG5pbXBvcnQgZm9nX3BhcnNfZnJhZ21lbnQgZnJvbSAnLi9TaGFkZXJDaHVuay9mb2dfcGFyc19mcmFnbWVudC5nbHNsLmpzJztcclxuaW1wb3J0IGdyYWRpZW50bWFwX3BhcnNfZnJhZ21lbnQgZnJvbSAnLi9TaGFkZXJDaHVuay9ncmFkaWVudG1hcF9wYXJzX2ZyYWdtZW50Lmdsc2wuanMnO1xyXG5pbXBvcnQgbGlnaHRtYXBfZnJhZ21lbnQgZnJvbSAnLi9TaGFkZXJDaHVuay9saWdodG1hcF9mcmFnbWVudC5nbHNsLmpzJztcclxuaW1wb3J0IGxpZ2h0bWFwX3BhcnNfZnJhZ21lbnQgZnJvbSAnLi9TaGFkZXJDaHVuay9saWdodG1hcF9wYXJzX2ZyYWdtZW50Lmdsc2wuanMnO1xyXG5pbXBvcnQgbGlnaHRzX2xhbWJlcnRfZnJhZ21lbnQgZnJvbSAnLi9TaGFkZXJDaHVuay9saWdodHNfbGFtYmVydF9mcmFnbWVudC5nbHNsLmpzJztcclxuaW1wb3J0IGxpZ2h0c19sYW1iZXJ0X3BhcnNfZnJhZ21lbnQgZnJvbSAnLi9TaGFkZXJDaHVuay9saWdodHNfbGFtYmVydF9wYXJzX2ZyYWdtZW50Lmdsc2wuanMnO1xyXG5pbXBvcnQgbGlnaHRzX3BhcnNfYmVnaW4gZnJvbSAnLi9TaGFkZXJDaHVuay9saWdodHNfcGFyc19iZWdpbi5nbHNsLmpzJztcclxuaW1wb3J0IGVudm1hcF9waHlzaWNhbF9wYXJzX2ZyYWdtZW50IGZyb20gJy4vU2hhZGVyQ2h1bmsvZW52bWFwX3BoeXNpY2FsX3BhcnNfZnJhZ21lbnQuZ2xzbC5qcyc7XHJcbmltcG9ydCBsaWdodHNfdG9vbl9mcmFnbWVudCBmcm9tICcuL1NoYWRlckNodW5rL2xpZ2h0c190b29uX2ZyYWdtZW50Lmdsc2wuanMnO1xyXG5pbXBvcnQgbGlnaHRzX3Rvb25fcGFyc19mcmFnbWVudCBmcm9tICcuL1NoYWRlckNodW5rL2xpZ2h0c190b29uX3BhcnNfZnJhZ21lbnQuZ2xzbC5qcyc7XHJcbmltcG9ydCBsaWdodHNfcGhvbmdfZnJhZ21lbnQgZnJvbSAnLi9TaGFkZXJDaHVuay9saWdodHNfcGhvbmdfZnJhZ21lbnQuZ2xzbC5qcyc7XHJcbmltcG9ydCBsaWdodHNfcGhvbmdfcGFyc19mcmFnbWVudCBmcm9tICcuL1NoYWRlckNodW5rL2xpZ2h0c19waG9uZ19wYXJzX2ZyYWdtZW50Lmdsc2wuanMnO1xyXG5pbXBvcnQgbGlnaHRzX3BoeXNpY2FsX2ZyYWdtZW50IGZyb20gJy4vU2hhZGVyQ2h1bmsvbGlnaHRzX3BoeXNpY2FsX2ZyYWdtZW50Lmdsc2wuanMnO1xyXG5pbXBvcnQgbGlnaHRzX3BoeXNpY2FsX3BhcnNfZnJhZ21lbnQgZnJvbSAnLi9TaGFkZXJDaHVuay9saWdodHNfcGh5c2ljYWxfcGFyc19mcmFnbWVudC5nbHNsLmpzJztcclxuaW1wb3J0IGxpZ2h0c19mcmFnbWVudF9iZWdpbiBmcm9tICcuL1NoYWRlckNodW5rL2xpZ2h0c19mcmFnbWVudF9iZWdpbi5nbHNsLmpzJztcclxuaW1wb3J0IGxpZ2h0c19mcmFnbWVudF9tYXBzIGZyb20gJy4vU2hhZGVyQ2h1bmsvbGlnaHRzX2ZyYWdtZW50X21hcHMuZ2xzbC5qcyc7XHJcbmltcG9ydCBsaWdodHNfZnJhZ21lbnRfZW5kIGZyb20gJy4vU2hhZGVyQ2h1bmsvbGlnaHRzX2ZyYWdtZW50X2VuZC5nbHNsLmpzJztcclxuaW1wb3J0IGxvZ2RlcHRoYnVmX2ZyYWdtZW50IGZyb20gJy4vU2hhZGVyQ2h1bmsvbG9nZGVwdGhidWZfZnJhZ21lbnQuZ2xzbC5qcyc7XHJcbmltcG9ydCBsb2dkZXB0aGJ1Zl9wYXJzX2ZyYWdtZW50IGZyb20gJy4vU2hhZGVyQ2h1bmsvbG9nZGVwdGhidWZfcGFyc19mcmFnbWVudC5nbHNsLmpzJztcclxuaW1wb3J0IGxvZ2RlcHRoYnVmX3BhcnNfdmVydGV4IGZyb20gJy4vU2hhZGVyQ2h1bmsvbG9nZGVwdGhidWZfcGFyc192ZXJ0ZXguZ2xzbC5qcyc7XHJcbmltcG9ydCBsb2dkZXB0aGJ1Zl92ZXJ0ZXggZnJvbSAnLi9TaGFkZXJDaHVuay9sb2dkZXB0aGJ1Zl92ZXJ0ZXguZ2xzbC5qcyc7XHJcbmltcG9ydCBtYXBfZnJhZ21lbnQgZnJvbSAnLi9TaGFkZXJDaHVuay9tYXBfZnJhZ21lbnQuZ2xzbC5qcyc7XHJcbmltcG9ydCBtYXBfcGFyc19mcmFnbWVudCBmcm9tICcuL1NoYWRlckNodW5rL21hcF9wYXJzX2ZyYWdtZW50Lmdsc2wuanMnO1xyXG5pbXBvcnQgbWFwX3BhcnRpY2xlX2ZyYWdtZW50IGZyb20gJy4vU2hhZGVyQ2h1bmsvbWFwX3BhcnRpY2xlX2ZyYWdtZW50Lmdsc2wuanMnO1xyXG5pbXBvcnQgbWFwX3BhcnRpY2xlX3BhcnNfZnJhZ21lbnQgZnJvbSAnLi9TaGFkZXJDaHVuay9tYXBfcGFydGljbGVfcGFyc19mcmFnbWVudC5nbHNsLmpzJztcclxuaW1wb3J0IG1ldGFsbmVzc21hcF9mcmFnbWVudCBmcm9tICcuL1NoYWRlckNodW5rL21ldGFsbmVzc21hcF9mcmFnbWVudC5nbHNsLmpzJztcclxuaW1wb3J0IG1ldGFsbmVzc21hcF9wYXJzX2ZyYWdtZW50IGZyb20gJy4vU2hhZGVyQ2h1bmsvbWV0YWxuZXNzbWFwX3BhcnNfZnJhZ21lbnQuZ2xzbC5qcyc7XHJcbmltcG9ydCBtb3JwaGNvbG9yX3ZlcnRleCBmcm9tICcuL1NoYWRlckNodW5rL21vcnBoY29sb3JfdmVydGV4Lmdsc2wuanMnO1xyXG5pbXBvcnQgbW9ycGhub3JtYWxfdmVydGV4IGZyb20gJy4vU2hhZGVyQ2h1bmsvbW9ycGhub3JtYWxfdmVydGV4Lmdsc2wuanMnO1xyXG5pbXBvcnQgbW9ycGh0YXJnZXRfcGFyc192ZXJ0ZXggZnJvbSAnLi9TaGFkZXJDaHVuay9tb3JwaHRhcmdldF9wYXJzX3ZlcnRleC5nbHNsLmpzJztcclxuaW1wb3J0IG1vcnBodGFyZ2V0X3ZlcnRleCBmcm9tICcuL1NoYWRlckNodW5rL21vcnBodGFyZ2V0X3ZlcnRleC5nbHNsLmpzJztcclxuaW1wb3J0IG5vcm1hbF9mcmFnbWVudF9iZWdpbiBmcm9tICcuL1NoYWRlckNodW5rL25vcm1hbF9mcmFnbWVudF9iZWdpbi5nbHNsLmpzJztcclxuaW1wb3J0IG5vcm1hbF9mcmFnbWVudF9tYXBzIGZyb20gJy4vU2hhZGVyQ2h1bmsvbm9ybWFsX2ZyYWdtZW50X21hcHMuZ2xzbC5qcyc7XHJcbmltcG9ydCBub3JtYWxfcGFyc19mcmFnbWVudCBmcm9tICcuL1NoYWRlckNodW5rL25vcm1hbF9wYXJzX2ZyYWdtZW50Lmdsc2wuanMnO1xyXG5pbXBvcnQgbm9ybWFsX3BhcnNfdmVydGV4IGZyb20gJy4vU2hhZGVyQ2h1bmsvbm9ybWFsX3BhcnNfdmVydGV4Lmdsc2wuanMnO1xyXG5pbXBvcnQgbm9ybWFsX3ZlcnRleCBmcm9tICcuL1NoYWRlckNodW5rL25vcm1hbF92ZXJ0ZXguZ2xzbC5qcyc7XHJcbmltcG9ydCBub3JtYWxtYXBfcGFyc19mcmFnbWVudCBmcm9tICcuL1NoYWRlckNodW5rL25vcm1hbG1hcF9wYXJzX2ZyYWdtZW50Lmdsc2wuanMnO1xyXG5pbXBvcnQgY2xlYXJjb2F0X25vcm1hbF9mcmFnbWVudF9iZWdpbiBmcm9tICcuL1NoYWRlckNodW5rL2NsZWFyY29hdF9ub3JtYWxfZnJhZ21lbnRfYmVnaW4uZ2xzbC5qcyc7XHJcbmltcG9ydCBjbGVhcmNvYXRfbm9ybWFsX2ZyYWdtZW50X21hcHMgZnJvbSAnLi9TaGFkZXJDaHVuay9jbGVhcmNvYXRfbm9ybWFsX2ZyYWdtZW50X21hcHMuZ2xzbC5qcyc7XHJcbmltcG9ydCBjbGVhcmNvYXRfcGFyc19mcmFnbWVudCBmcm9tICcuL1NoYWRlckNodW5rL2NsZWFyY29hdF9wYXJzX2ZyYWdtZW50Lmdsc2wuanMnO1xyXG5pbXBvcnQgaXJpZGVzY2VuY2VfcGFyc19mcmFnbWVudCBmcm9tICcuL1NoYWRlckNodW5rL2lyaWRlc2NlbmNlX3BhcnNfZnJhZ21lbnQuZ2xzbC5qcyc7XHJcbmltcG9ydCBvcGFxdWVfZnJhZ21lbnQgZnJvbSAnLi9TaGFkZXJDaHVuay9vcGFxdWVfZnJhZ21lbnQuZ2xzbC5qcyc7XHJcbmltcG9ydCBwYWNraW5nIGZyb20gJy4vU2hhZGVyQ2h1bmsvcGFja2luZy5nbHNsLmpzJztcclxuaW1wb3J0IHByZW11bHRpcGxpZWRfYWxwaGFfZnJhZ21lbnQgZnJvbSAnLi9TaGFkZXJDaHVuay9wcmVtdWx0aXBsaWVkX2FscGhhX2ZyYWdtZW50Lmdsc2wuanMnO1xyXG5pbXBvcnQgcHJvamVjdF92ZXJ0ZXggZnJvbSAnLi9TaGFkZXJDaHVuay9wcm9qZWN0X3ZlcnRleC5nbHNsLmpzJztcclxuaW1wb3J0IGRpdGhlcmluZ19mcmFnbWVudCBmcm9tICcuL1NoYWRlckNodW5rL2RpdGhlcmluZ19mcmFnbWVudC5nbHNsLmpzJztcclxuaW1wb3J0IGRpdGhlcmluZ19wYXJzX2ZyYWdtZW50IGZyb20gJy4vU2hhZGVyQ2h1bmsvZGl0aGVyaW5nX3BhcnNfZnJhZ21lbnQuZ2xzbC5qcyc7XHJcbmltcG9ydCByb3VnaG5lc3NtYXBfZnJhZ21lbnQgZnJvbSAnLi9TaGFkZXJDaHVuay9yb3VnaG5lc3NtYXBfZnJhZ21lbnQuZ2xzbC5qcyc7XHJcbmltcG9ydCByb3VnaG5lc3NtYXBfcGFyc19mcmFnbWVudCBmcm9tICcuL1NoYWRlckNodW5rL3JvdWdobmVzc21hcF9wYXJzX2ZyYWdtZW50Lmdsc2wuanMnO1xyXG5pbXBvcnQgc2hhZG93bWFwX3BhcnNfZnJhZ21lbnQgZnJvbSAnLi9TaGFkZXJDaHVuay9zaGFkb3dtYXBfcGFyc19mcmFnbWVudC5nbHNsLmpzJztcclxuaW1wb3J0IHNoYWRvd21hcF9wYXJzX3ZlcnRleCBmcm9tICcuL1NoYWRlckNodW5rL3NoYWRvd21hcF9wYXJzX3ZlcnRleC5nbHNsLmpzJztcclxuaW1wb3J0IHNoYWRvd21hcF92ZXJ0ZXggZnJvbSAnLi9TaGFkZXJDaHVuay9zaGFkb3dtYXBfdmVydGV4Lmdsc2wuanMnO1xyXG5pbXBvcnQgc2hhZG93bWFza19wYXJzX2ZyYWdtZW50IGZyb20gJy4vU2hhZGVyQ2h1bmsvc2hhZG93bWFza19wYXJzX2ZyYWdtZW50Lmdsc2wuanMnO1xyXG5pbXBvcnQgc2tpbmJhc2VfdmVydGV4IGZyb20gJy4vU2hhZGVyQ2h1bmsvc2tpbmJhc2VfdmVydGV4Lmdsc2wuanMnO1xyXG5pbXBvcnQgc2tpbm5pbmdfcGFyc192ZXJ0ZXggZnJvbSAnLi9TaGFkZXJDaHVuay9za2lubmluZ19wYXJzX3ZlcnRleC5nbHNsLmpzJztcclxuaW1wb3J0IHNraW5uaW5nX3ZlcnRleCBmcm9tICcuL1NoYWRlckNodW5rL3NraW5uaW5nX3ZlcnRleC5nbHNsLmpzJztcclxuaW1wb3J0IHNraW5ub3JtYWxfdmVydGV4IGZyb20gJy4vU2hhZGVyQ2h1bmsvc2tpbm5vcm1hbF92ZXJ0ZXguZ2xzbC5qcyc7XHJcbmltcG9ydCBzcGVjdWxhcm1hcF9mcmFnbWVudCBmcm9tICcuL1NoYWRlckNodW5rL3NwZWN1bGFybWFwX2ZyYWdtZW50Lmdsc2wuanMnO1xyXG5pbXBvcnQgc3BlY3VsYXJtYXBfcGFyc19mcmFnbWVudCBmcm9tICcuL1NoYWRlckNodW5rL3NwZWN1bGFybWFwX3BhcnNfZnJhZ21lbnQuZ2xzbC5qcyc7XHJcbmltcG9ydCB0b25lbWFwcGluZ19mcmFnbWVudCBmcm9tICcuL1NoYWRlckNodW5rL3RvbmVtYXBwaW5nX2ZyYWdtZW50Lmdsc2wuanMnO1xyXG5pbXBvcnQgdG9uZW1hcHBpbmdfcGFyc19mcmFnbWVudCBmcm9tICcuL1NoYWRlckNodW5rL3RvbmVtYXBwaW5nX3BhcnNfZnJhZ21lbnQuZ2xzbC5qcyc7XHJcbmltcG9ydCB0cmFuc21pc3Npb25fZnJhZ21lbnQgZnJvbSAnLi9TaGFkZXJDaHVuay90cmFuc21pc3Npb25fZnJhZ21lbnQuZ2xzbC5qcyc7XHJcbmltcG9ydCB0cmFuc21pc3Npb25fcGFyc19mcmFnbWVudCBmcm9tICcuL1NoYWRlckNodW5rL3RyYW5zbWlzc2lvbl9wYXJzX2ZyYWdtZW50Lmdsc2wuanMnO1xyXG5pbXBvcnQgdXZfcGFyc19mcmFnbWVudCBmcm9tICcuL1NoYWRlckNodW5rL3V2X3BhcnNfZnJhZ21lbnQuZ2xzbC5qcyc7XHJcbmltcG9ydCB1dl9wYXJzX3ZlcnRleCBmcm9tICcuL1NoYWRlckNodW5rL3V2X3BhcnNfdmVydGV4Lmdsc2wuanMnO1xyXG5pbXBvcnQgdXZfdmVydGV4IGZyb20gJy4vU2hhZGVyQ2h1bmsvdXZfdmVydGV4Lmdsc2wuanMnO1xyXG5pbXBvcnQgd29ybGRwb3NfdmVydGV4IGZyb20gJy4vU2hhZGVyQ2h1bmsvd29ybGRwb3NfdmVydGV4Lmdsc2wuanMnO1xyXG5cclxuaW1wb3J0ICogYXMgYmFja2dyb3VuZCBmcm9tICcuL1NoYWRlckxpYi9iYWNrZ3JvdW5kLmdsc2wuanMnO1xyXG5pbXBvcnQgKiBhcyBiYWNrZ3JvdW5kQ3ViZSBmcm9tICcuL1NoYWRlckxpYi9iYWNrZ3JvdW5kQ3ViZS5nbHNsLmpzJztcclxuaW1wb3J0ICogYXMgY3ViZSBmcm9tICcuL1NoYWRlckxpYi9jdWJlLmdsc2wuanMnO1xyXG5pbXBvcnQgKiBhcyBkZXB0aCBmcm9tICcuL1NoYWRlckxpYi9kZXB0aC5nbHNsLmpzJztcclxuaW1wb3J0ICogYXMgZGlzdGFuY2VSR0JBIGZyb20gJy4vU2hhZGVyTGliL2Rpc3RhbmNlUkdCQS5nbHNsLmpzJztcclxuaW1wb3J0ICogYXMgZXF1aXJlY3QgZnJvbSAnLi9TaGFkZXJMaWIvZXF1aXJlY3QuZ2xzbC5qcyc7XHJcbmltcG9ydCAqIGFzIGxpbmVkYXNoZWQgZnJvbSAnLi9TaGFkZXJMaWIvbGluZWRhc2hlZC5nbHNsLmpzJztcclxuaW1wb3J0ICogYXMgbWVzaGJhc2ljIGZyb20gJy4vU2hhZGVyTGliL21lc2hiYXNpYy5nbHNsLmpzJztcclxuaW1wb3J0ICogYXMgbWVzaGxhbWJlcnQgZnJvbSAnLi9TaGFkZXJMaWIvbWVzaGxhbWJlcnQuZ2xzbC5qcyc7XHJcbmltcG9ydCAqIGFzIG1lc2htYXRjYXAgZnJvbSAnLi9TaGFkZXJMaWIvbWVzaG1hdGNhcC5nbHNsLmpzJztcclxuaW1wb3J0ICogYXMgbWVzaG5vcm1hbCBmcm9tICcuL1NoYWRlckxpYi9tZXNobm9ybWFsLmdsc2wuanMnO1xyXG5pbXBvcnQgKiBhcyBtZXNocGhvbmcgZnJvbSAnLi9TaGFkZXJMaWIvbWVzaHBob25nLmdsc2wuanMnO1xyXG5pbXBvcnQgKiBhcyBtZXNocGh5c2ljYWwgZnJvbSAnLi9TaGFkZXJMaWIvbWVzaHBoeXNpY2FsLmdsc2wuanMnO1xyXG5pbXBvcnQgKiBhcyBtZXNodG9vbiBmcm9tICcuL1NoYWRlckxpYi9tZXNodG9vbi5nbHNsLmpzJztcclxuaW1wb3J0ICogYXMgcG9pbnRzIGZyb20gJy4vU2hhZGVyTGliL3BvaW50cy5nbHNsLmpzJztcclxuaW1wb3J0ICogYXMgc2hhZG93IGZyb20gJy4vU2hhZGVyTGliL3NoYWRvdy5nbHNsLmpzJztcclxuaW1wb3J0ICogYXMgc3ByaXRlIGZyb20gJy4vU2hhZGVyTGliL3Nwcml0ZS5nbHNsLmpzJztcclxuXHJcbmV4cG9ydCBjb25zdCBTaGFkZXJDaHVuayA9IHtcclxuXHRhbHBoYWhhc2hfZnJhZ21lbnQ6IGFscGhhaGFzaF9mcmFnbWVudCxcclxuXHRhbHBoYWhhc2hfcGFyc19mcmFnbWVudDogYWxwaGFoYXNoX3BhcnNfZnJhZ21lbnQsXHJcblx0YWxwaGFtYXBfZnJhZ21lbnQ6IGFscGhhbWFwX2ZyYWdtZW50LFxyXG5cdGFscGhhbWFwX3BhcnNfZnJhZ21lbnQ6IGFscGhhbWFwX3BhcnNfZnJhZ21lbnQsXHJcblx0YWxwaGF0ZXN0X2ZyYWdtZW50OiBhbHBoYXRlc3RfZnJhZ21lbnQsXHJcblx0YWxwaGF0ZXN0X3BhcnNfZnJhZ21lbnQ6IGFscGhhdGVzdF9wYXJzX2ZyYWdtZW50LFxyXG5cdGFvbWFwX2ZyYWdtZW50OiBhb21hcF9mcmFnbWVudCxcclxuXHRhb21hcF9wYXJzX2ZyYWdtZW50OiBhb21hcF9wYXJzX2ZyYWdtZW50LFxyXG5cdGJhdGNoaW5nX3BhcnNfdmVydGV4OiBiYXRjaGluZ19wYXJzX3ZlcnRleCxcclxuXHRiYXRjaGluZ192ZXJ0ZXg6IGJhdGNoaW5nX3ZlcnRleCxcclxuXHRiZWdpbl92ZXJ0ZXg6IGJlZ2luX3ZlcnRleCxcclxuXHRiZWdpbm5vcm1hbF92ZXJ0ZXg6IGJlZ2lubm9ybWFsX3ZlcnRleCxcclxuXHRic2RmczogYnNkZnMsXHJcblx0aXJpZGVzY2VuY2VfZnJhZ21lbnQ6IGlyaWRlc2NlbmNlX2ZyYWdtZW50LFxyXG5cdGJ1bXBtYXBfcGFyc19mcmFnbWVudDogYnVtcG1hcF9wYXJzX2ZyYWdtZW50LFxyXG5cdGNsaXBwaW5nX3BsYW5lc19mcmFnbWVudDogY2xpcHBpbmdfcGxhbmVzX2ZyYWdtZW50LFxyXG5cdGNsaXBwaW5nX3BsYW5lc19wYXJzX2ZyYWdtZW50OiBjbGlwcGluZ19wbGFuZXNfcGFyc19mcmFnbWVudCxcclxuXHRjbGlwcGluZ19wbGFuZXNfcGFyc192ZXJ0ZXg6IGNsaXBwaW5nX3BsYW5lc19wYXJzX3ZlcnRleCxcclxuXHRjbGlwcGluZ19wbGFuZXNfdmVydGV4OiBjbGlwcGluZ19wbGFuZXNfdmVydGV4LFxyXG5cdGNvbG9yX2ZyYWdtZW50OiBjb2xvcl9mcmFnbWVudCxcclxuXHRjb2xvcl9wYXJzX2ZyYWdtZW50OiBjb2xvcl9wYXJzX2ZyYWdtZW50LFxyXG5cdGNvbG9yX3BhcnNfdmVydGV4OiBjb2xvcl9wYXJzX3ZlcnRleCxcclxuXHRjb2xvcl92ZXJ0ZXg6IGNvbG9yX3ZlcnRleCxcclxuXHRjb21tb246IGNvbW1vbixcclxuXHRjdWJlX3V2X3JlZmxlY3Rpb25fZnJhZ21lbnQ6IGN1YmVfdXZfcmVmbGVjdGlvbl9mcmFnbWVudCxcclxuXHRkZWZhdWx0bm9ybWFsX3ZlcnRleDogZGVmYXVsdG5vcm1hbF92ZXJ0ZXgsXHJcblx0ZGlzcGxhY2VtZW50bWFwX3BhcnNfdmVydGV4OiBkaXNwbGFjZW1lbnRtYXBfcGFyc192ZXJ0ZXgsXHJcblx0ZGlzcGxhY2VtZW50bWFwX3ZlcnRleDogZGlzcGxhY2VtZW50bWFwX3ZlcnRleCxcclxuXHRlbWlzc2l2ZW1hcF9mcmFnbWVudDogZW1pc3NpdmVtYXBfZnJhZ21lbnQsXHJcblx0ZW1pc3NpdmVtYXBfcGFyc19mcmFnbWVudDogZW1pc3NpdmVtYXBfcGFyc19mcmFnbWVudCxcclxuXHRjb2xvcnNwYWNlX2ZyYWdtZW50OiBjb2xvcnNwYWNlX2ZyYWdtZW50LFxyXG5cdGNvbG9yc3BhY2VfcGFyc19mcmFnbWVudDogY29sb3JzcGFjZV9wYXJzX2ZyYWdtZW50LFxyXG5cdGVudm1hcF9mcmFnbWVudDogZW52bWFwX2ZyYWdtZW50LFxyXG5cdGVudm1hcF9jb21tb25fcGFyc19mcmFnbWVudDogZW52bWFwX2NvbW1vbl9wYXJzX2ZyYWdtZW50LFxyXG5cdGVudm1hcF9wYXJzX2ZyYWdtZW50OiBlbnZtYXBfcGFyc19mcmFnbWVudCxcclxuXHRlbnZtYXBfcGFyc192ZXJ0ZXg6IGVudm1hcF9wYXJzX3ZlcnRleCxcclxuXHRlbnZtYXBfcGh5c2ljYWxfcGFyc19mcmFnbWVudDogZW52bWFwX3BoeXNpY2FsX3BhcnNfZnJhZ21lbnQsXHJcblx0ZW52bWFwX3ZlcnRleDogZW52bWFwX3ZlcnRleCxcclxuXHRmb2dfdmVydGV4OiBmb2dfdmVydGV4LFxyXG5cdGZvZ19wYXJzX3ZlcnRleDogZm9nX3BhcnNfdmVydGV4LFxyXG5cdGZvZ19mcmFnbWVudDogZm9nX2ZyYWdtZW50LFxyXG5cdGZvZ19wYXJzX2ZyYWdtZW50OiBmb2dfcGFyc19mcmFnbWVudCxcclxuXHRncmFkaWVudG1hcF9wYXJzX2ZyYWdtZW50OiBncmFkaWVudG1hcF9wYXJzX2ZyYWdtZW50LFxyXG5cdGxpZ2h0bWFwX2ZyYWdtZW50OiBsaWdodG1hcF9mcmFnbWVudCxcclxuXHRsaWdodG1hcF9wYXJzX2ZyYWdtZW50OiBsaWdodG1hcF9wYXJzX2ZyYWdtZW50LFxyXG5cdGxpZ2h0c19sYW1iZXJ0X2ZyYWdtZW50OiBsaWdodHNfbGFtYmVydF9mcmFnbWVudCxcclxuXHRsaWdodHNfbGFtYmVydF9wYXJzX2ZyYWdtZW50OiBsaWdodHNfbGFtYmVydF9wYXJzX2ZyYWdtZW50LFxyXG5cdGxpZ2h0c19wYXJzX2JlZ2luOiBsaWdodHNfcGFyc19iZWdpbixcclxuXHRsaWdodHNfdG9vbl9mcmFnbWVudDogbGlnaHRzX3Rvb25fZnJhZ21lbnQsXHJcblx0bGlnaHRzX3Rvb25fcGFyc19mcmFnbWVudDogbGlnaHRzX3Rvb25fcGFyc19mcmFnbWVudCxcclxuXHRsaWdodHNfcGhvbmdfZnJhZ21lbnQ6IGxpZ2h0c19waG9uZ19mcmFnbWVudCxcclxuXHRsaWdodHNfcGhvbmdfcGFyc19mcmFnbWVudDogbGlnaHRzX3Bob25nX3BhcnNfZnJhZ21lbnQsXHJcblx0bGlnaHRzX3BoeXNpY2FsX2ZyYWdtZW50OiBsaWdodHNfcGh5c2ljYWxfZnJhZ21lbnQsXHJcblx0bGlnaHRzX3BoeXNpY2FsX3BhcnNfZnJhZ21lbnQ6IGxpZ2h0c19waHlzaWNhbF9wYXJzX2ZyYWdtZW50LFxyXG5cdGxpZ2h0c19mcmFnbWVudF9iZWdpbjogbGlnaHRzX2ZyYWdtZW50X2JlZ2luLFxyXG5cdGxpZ2h0c19mcmFnbWVudF9tYXBzOiBsaWdodHNfZnJhZ21lbnRfbWFwcyxcclxuXHRsaWdodHNfZnJhZ21lbnRfZW5kOiBsaWdodHNfZnJhZ21lbnRfZW5kLFxyXG5cdGxvZ2RlcHRoYnVmX2ZyYWdtZW50OiBsb2dkZXB0aGJ1Zl9mcmFnbWVudCxcclxuXHRsb2dkZXB0aGJ1Zl9wYXJzX2ZyYWdtZW50OiBsb2dkZXB0aGJ1Zl9wYXJzX2ZyYWdtZW50LFxyXG5cdGxvZ2RlcHRoYnVmX3BhcnNfdmVydGV4OiBsb2dkZXB0aGJ1Zl9wYXJzX3ZlcnRleCxcclxuXHRsb2dkZXB0aGJ1Zl92ZXJ0ZXg6IGxvZ2RlcHRoYnVmX3ZlcnRleCxcclxuXHRtYXBfZnJhZ21lbnQ6IG1hcF9mcmFnbWVudCxcclxuXHRtYXBfcGFyc19mcmFnbWVudDogbWFwX3BhcnNfZnJhZ21lbnQsXHJcblx0bWFwX3BhcnRpY2xlX2ZyYWdtZW50OiBtYXBfcGFydGljbGVfZnJhZ21lbnQsXHJcblx0bWFwX3BhcnRpY2xlX3BhcnNfZnJhZ21lbnQ6IG1hcF9wYXJ0aWNsZV9wYXJzX2ZyYWdtZW50LFxyXG5cdG1ldGFsbmVzc21hcF9mcmFnbWVudDogbWV0YWxuZXNzbWFwX2ZyYWdtZW50LFxyXG5cdG1ldGFsbmVzc21hcF9wYXJzX2ZyYWdtZW50OiBtZXRhbG5lc3NtYXBfcGFyc19mcmFnbWVudCxcclxuXHRtb3JwaGNvbG9yX3ZlcnRleDogbW9ycGhjb2xvcl92ZXJ0ZXgsXHJcblx0bW9ycGhub3JtYWxfdmVydGV4OiBtb3JwaG5vcm1hbF92ZXJ0ZXgsXHJcblx0bW9ycGh0YXJnZXRfcGFyc192ZXJ0ZXg6IG1vcnBodGFyZ2V0X3BhcnNfdmVydGV4LFxyXG5cdG1vcnBodGFyZ2V0X3ZlcnRleDogbW9ycGh0YXJnZXRfdmVydGV4LFxyXG5cdG5vcm1hbF9mcmFnbWVudF9iZWdpbjogbm9ybWFsX2ZyYWdtZW50X2JlZ2luLFxyXG5cdG5vcm1hbF9mcmFnbWVudF9tYXBzOiBub3JtYWxfZnJhZ21lbnRfbWFwcyxcclxuXHRub3JtYWxfcGFyc19mcmFnbWVudDogbm9ybWFsX3BhcnNfZnJhZ21lbnQsXHJcblx0bm9ybWFsX3BhcnNfdmVydGV4OiBub3JtYWxfcGFyc192ZXJ0ZXgsXHJcblx0bm9ybWFsX3ZlcnRleDogbm9ybWFsX3ZlcnRleCxcclxuXHRub3JtYWxtYXBfcGFyc19mcmFnbWVudDogbm9ybWFsbWFwX3BhcnNfZnJhZ21lbnQsXHJcblx0Y2xlYXJjb2F0X25vcm1hbF9mcmFnbWVudF9iZWdpbjogY2xlYXJjb2F0X25vcm1hbF9mcmFnbWVudF9iZWdpbixcclxuXHRjbGVhcmNvYXRfbm9ybWFsX2ZyYWdtZW50X21hcHM6IGNsZWFyY29hdF9ub3JtYWxfZnJhZ21lbnRfbWFwcyxcclxuXHRjbGVhcmNvYXRfcGFyc19mcmFnbWVudDogY2xlYXJjb2F0X3BhcnNfZnJhZ21lbnQsXHJcblx0aXJpZGVzY2VuY2VfcGFyc19mcmFnbWVudDogaXJpZGVzY2VuY2VfcGFyc19mcmFnbWVudCxcclxuXHRvcGFxdWVfZnJhZ21lbnQ6IG9wYXF1ZV9mcmFnbWVudCxcclxuXHRwYWNraW5nOiBwYWNraW5nLFxyXG5cdHByZW11bHRpcGxpZWRfYWxwaGFfZnJhZ21lbnQ6IHByZW11bHRpcGxpZWRfYWxwaGFfZnJhZ21lbnQsXHJcblx0cHJvamVjdF92ZXJ0ZXg6IHByb2plY3RfdmVydGV4LFxyXG5cdGRpdGhlcmluZ19mcmFnbWVudDogZGl0aGVyaW5nX2ZyYWdtZW50LFxyXG5cdGRpdGhlcmluZ19wYXJzX2ZyYWdtZW50OiBkaXRoZXJpbmdfcGFyc19mcmFnbWVudCxcclxuXHRyb3VnaG5lc3NtYXBfZnJhZ21lbnQ6IHJvdWdobmVzc21hcF9mcmFnbWVudCxcclxuXHRyb3VnaG5lc3NtYXBfcGFyc19mcmFnbWVudDogcm91Z2huZXNzbWFwX3BhcnNfZnJhZ21lbnQsXHJcblx0c2hhZG93bWFwX3BhcnNfZnJhZ21lbnQ6IHNoYWRvd21hcF9wYXJzX2ZyYWdtZW50LFxyXG5cdHNoYWRvd21hcF9wYXJzX3ZlcnRleDogc2hhZG93bWFwX3BhcnNfdmVydGV4LFxyXG5cdHNoYWRvd21hcF92ZXJ0ZXg6IHNoYWRvd21hcF92ZXJ0ZXgsXHJcblx0c2hhZG93bWFza19wYXJzX2ZyYWdtZW50OiBzaGFkb3dtYXNrX3BhcnNfZnJhZ21lbnQsXHJcblx0c2tpbmJhc2VfdmVydGV4OiBza2luYmFzZV92ZXJ0ZXgsXHJcblx0c2tpbm5pbmdfcGFyc192ZXJ0ZXg6IHNraW5uaW5nX3BhcnNfdmVydGV4LFxyXG5cdHNraW5uaW5nX3ZlcnRleDogc2tpbm5pbmdfdmVydGV4LFxyXG5cdHNraW5ub3JtYWxfdmVydGV4OiBza2lubm9ybWFsX3ZlcnRleCxcclxuXHRzcGVjdWxhcm1hcF9mcmFnbWVudDogc3BlY3VsYXJtYXBfZnJhZ21lbnQsXHJcblx0c3BlY3VsYXJtYXBfcGFyc19mcmFnbWVudDogc3BlY3VsYXJtYXBfcGFyc19mcmFnbWVudCxcclxuXHR0b25lbWFwcGluZ19mcmFnbWVudDogdG9uZW1hcHBpbmdfZnJhZ21lbnQsXHJcblx0dG9uZW1hcHBpbmdfcGFyc19mcmFnbWVudDogdG9uZW1hcHBpbmdfcGFyc19mcmFnbWVudCxcclxuXHR0cmFuc21pc3Npb25fZnJhZ21lbnQ6IHRyYW5zbWlzc2lvbl9mcmFnbWVudCxcclxuXHR0cmFuc21pc3Npb25fcGFyc19mcmFnbWVudDogdHJhbnNtaXNzaW9uX3BhcnNfZnJhZ21lbnQsXHJcblx0dXZfcGFyc19mcmFnbWVudDogdXZfcGFyc19mcmFnbWVudCxcclxuXHR1dl9wYXJzX3ZlcnRleDogdXZfcGFyc192ZXJ0ZXgsXHJcblx0dXZfdmVydGV4OiB1dl92ZXJ0ZXgsXHJcblx0d29ybGRwb3NfdmVydGV4OiB3b3JsZHBvc192ZXJ0ZXgsXHJcblxyXG5cdGJhY2tncm91bmRfdmVydDogYmFja2dyb3VuZC52ZXJ0ZXgsXHJcblx0YmFja2dyb3VuZF9mcmFnOiBiYWNrZ3JvdW5kLmZyYWdtZW50LFxyXG5cdGJhY2tncm91bmRDdWJlX3ZlcnQ6IGJhY2tncm91bmRDdWJlLnZlcnRleCxcclxuXHRiYWNrZ3JvdW5kQ3ViZV9mcmFnOiBiYWNrZ3JvdW5kQ3ViZS5mcmFnbWVudCxcclxuXHRjdWJlX3ZlcnQ6IGN1YmUudmVydGV4LFxyXG5cdGN1YmVfZnJhZzogY3ViZS5mcmFnbWVudCxcclxuXHRkZXB0aF92ZXJ0OiBkZXB0aC52ZXJ0ZXgsXHJcblx0ZGVwdGhfZnJhZzogZGVwdGguZnJhZ21lbnQsXHJcblx0ZGlzdGFuY2VSR0JBX3ZlcnQ6IGRpc3RhbmNlUkdCQS52ZXJ0ZXgsXHJcblx0ZGlzdGFuY2VSR0JBX2ZyYWc6IGRpc3RhbmNlUkdCQS5mcmFnbWVudCxcclxuXHRlcXVpcmVjdF92ZXJ0OiBlcXVpcmVjdC52ZXJ0ZXgsXHJcblx0ZXF1aXJlY3RfZnJhZzogZXF1aXJlY3QuZnJhZ21lbnQsXHJcblx0bGluZWRhc2hlZF92ZXJ0OiBsaW5lZGFzaGVkLnZlcnRleCxcclxuXHRsaW5lZGFzaGVkX2ZyYWc6IGxpbmVkYXNoZWQuZnJhZ21lbnQsXHJcblx0bWVzaGJhc2ljX3ZlcnQ6IG1lc2hiYXNpYy52ZXJ0ZXgsXHJcblx0bWVzaGJhc2ljX2ZyYWc6IG1lc2hiYXNpYy5mcmFnbWVudCxcclxuXHRtZXNobGFtYmVydF92ZXJ0OiBtZXNobGFtYmVydC52ZXJ0ZXgsXHJcblx0bWVzaGxhbWJlcnRfZnJhZzogbWVzaGxhbWJlcnQuZnJhZ21lbnQsXHJcblx0bWVzaG1hdGNhcF92ZXJ0OiBtZXNobWF0Y2FwLnZlcnRleCxcclxuXHRtZXNobWF0Y2FwX2ZyYWc6IG1lc2htYXRjYXAuZnJhZ21lbnQsXHJcblx0bWVzaG5vcm1hbF92ZXJ0OiBtZXNobm9ybWFsLnZlcnRleCxcclxuXHRtZXNobm9ybWFsX2ZyYWc6IG1lc2hub3JtYWwuZnJhZ21lbnQsXHJcblx0bWVzaHBob25nX3ZlcnQ6IG1lc2hwaG9uZy52ZXJ0ZXgsXHJcblx0bWVzaHBob25nX2ZyYWc6IG1lc2hwaG9uZy5mcmFnbWVudCxcclxuXHRtZXNocGh5c2ljYWxfdmVydDogbWVzaHBoeXNpY2FsLnZlcnRleCxcclxuXHRtZXNocGh5c2ljYWxfZnJhZzogbWVzaHBoeXNpY2FsLmZyYWdtZW50LFxyXG5cdG1lc2h0b29uX3ZlcnQ6IG1lc2h0b29uLnZlcnRleCxcclxuXHRtZXNodG9vbl9mcmFnOiBtZXNodG9vbi5mcmFnbWVudCxcclxuXHRwb2ludHNfdmVydDogcG9pbnRzLnZlcnRleCxcclxuXHRwb2ludHNfZnJhZzogcG9pbnRzLmZyYWdtZW50LFxyXG5cdHNoYWRvd192ZXJ0OiBzaGFkb3cudmVydGV4LFxyXG5cdHNoYWRvd19mcmFnOiBzaGFkb3cuZnJhZ21lbnQsXHJcblx0c3ByaXRlX3ZlcnQ6IHNwcml0ZS52ZXJ0ZXgsXHJcblx0c3ByaXRlX2ZyYWc6IHNwcml0ZS5mcmFnbWVudFxyXG59O1xyXG4iLCJpbXBvcnQgeyBDb2xvciB9IGZyb20gJy4uLy4uL21hdGgvQ29sb3IuanMnO1xyXG5pbXBvcnQgeyBWZWN0b3IyIH0gZnJvbSAnLi4vLi4vbWF0aC9WZWN0b3IyLmpzJztcclxuaW1wb3J0IHsgTWF0cml4MyB9IGZyb20gJy4uLy4uL21hdGgvTWF0cml4My5qcyc7XHJcblxyXG4vKipcclxuICogVW5pZm9ybXMgbGlicmFyeSBmb3Igc2hhcmVkIHdlYmdsIHNoYWRlcnNcclxuICovXHJcblxyXG5jb25zdCBVbmlmb3Jtc0xpYiA9IHtcclxuXHJcblx0Y29tbW9uOiB7XHJcblxyXG5cdFx0ZGlmZnVzZTogeyB2YWx1ZTogLypAX19QVVJFX18qLyBuZXcgQ29sb3IoIDB4ZmZmZmZmICkgfSxcclxuXHRcdG9wYWNpdHk6IHsgdmFsdWU6IDEuMCB9LFxyXG5cclxuXHRcdG1hcDogeyB2YWx1ZTogbnVsbCB9LFxyXG5cdFx0bWFwVHJhbnNmb3JtOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXgzKCkgfSxcclxuXHJcblx0XHRhbHBoYU1hcDogeyB2YWx1ZTogbnVsbCB9LFxyXG5cdFx0YWxwaGFNYXBUcmFuc2Zvcm06IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDMoKSB9LFxyXG5cclxuXHRcdGFscGhhVGVzdDogeyB2YWx1ZTogMCB9XHJcblxyXG5cdH0sXHJcblxyXG5cdHNwZWN1bGFybWFwOiB7XHJcblxyXG5cdFx0c3BlY3VsYXJNYXA6IHsgdmFsdWU6IG51bGwgfSxcclxuXHRcdHNwZWN1bGFyTWFwVHJhbnNmb3JtOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXgzKCkgfVxyXG5cclxuXHR9LFxyXG5cclxuXHRlbnZtYXA6IHtcclxuXHJcblx0XHRlbnZNYXA6IHsgdmFsdWU6IG51bGwgfSxcclxuXHRcdGZsaXBFbnZNYXA6IHsgdmFsdWU6IC0gMSB9LFxyXG5cdFx0cmVmbGVjdGl2aXR5OiB7IHZhbHVlOiAxLjAgfSwgLy8gYmFzaWMsIGxhbWJlcnQsIHBob25nXHJcblx0XHRpb3I6IHsgdmFsdWU6IDEuNSB9LCAvLyBwaHlzaWNhbFxyXG5cdFx0cmVmcmFjdGlvblJhdGlvOiB7IHZhbHVlOiAwLjk4IH0sIC8vIGJhc2ljLCBsYW1iZXJ0LCBwaG9uZ1xyXG5cclxuXHR9LFxyXG5cclxuXHRhb21hcDoge1xyXG5cclxuXHRcdGFvTWFwOiB7IHZhbHVlOiBudWxsIH0sXHJcblx0XHRhb01hcEludGVuc2l0eTogeyB2YWx1ZTogMSB9LFxyXG5cdFx0YW9NYXBUcmFuc2Zvcm06IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDMoKSB9XHJcblxyXG5cdH0sXHJcblxyXG5cdGxpZ2h0bWFwOiB7XHJcblxyXG5cdFx0bGlnaHRNYXA6IHsgdmFsdWU6IG51bGwgfSxcclxuXHRcdGxpZ2h0TWFwSW50ZW5zaXR5OiB7IHZhbHVlOiAxIH0sXHJcblx0XHRsaWdodE1hcFRyYW5zZm9ybTogeyB2YWx1ZTogLypAX19QVVJFX18qLyBuZXcgTWF0cml4MygpIH1cclxuXHJcblx0fSxcclxuXHJcblx0YnVtcG1hcDoge1xyXG5cclxuXHRcdGJ1bXBNYXA6IHsgdmFsdWU6IG51bGwgfSxcclxuXHRcdGJ1bXBNYXBUcmFuc2Zvcm06IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDMoKSB9LFxyXG5cdFx0YnVtcFNjYWxlOiB7IHZhbHVlOiAxIH1cclxuXHJcblx0fSxcclxuXHJcblx0bm9ybWFsbWFwOiB7XHJcblxyXG5cdFx0bm9ybWFsTWFwOiB7IHZhbHVlOiBudWxsIH0sXHJcblx0XHRub3JtYWxNYXBUcmFuc2Zvcm06IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDMoKSB9LFxyXG5cdFx0bm9ybWFsU2NhbGU6IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjIoIDEsIDEgKSB9XHJcblxyXG5cdH0sXHJcblxyXG5cdGRpc3BsYWNlbWVudG1hcDoge1xyXG5cclxuXHRcdGRpc3BsYWNlbWVudE1hcDogeyB2YWx1ZTogbnVsbCB9LFxyXG5cdFx0ZGlzcGxhY2VtZW50TWFwVHJhbnNmb3JtOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXgzKCkgfSxcclxuXHRcdGRpc3BsYWNlbWVudFNjYWxlOiB7IHZhbHVlOiAxIH0sXHJcblx0XHRkaXNwbGFjZW1lbnRCaWFzOiB7IHZhbHVlOiAwIH1cclxuXHJcblx0fSxcclxuXHJcblx0ZW1pc3NpdmVtYXA6IHtcclxuXHJcblx0XHRlbWlzc2l2ZU1hcDogeyB2YWx1ZTogbnVsbCB9LFxyXG5cdFx0ZW1pc3NpdmVNYXBUcmFuc2Zvcm06IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDMoKSB9XHJcblxyXG5cdH0sXHJcblxyXG5cdG1ldGFsbmVzc21hcDoge1xyXG5cclxuXHRcdG1ldGFsbmVzc01hcDogeyB2YWx1ZTogbnVsbCB9LFxyXG5cdFx0bWV0YWxuZXNzTWFwVHJhbnNmb3JtOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXgzKCkgfVxyXG5cclxuXHR9LFxyXG5cclxuXHRyb3VnaG5lc3NtYXA6IHtcclxuXHJcblx0XHRyb3VnaG5lc3NNYXA6IHsgdmFsdWU6IG51bGwgfSxcclxuXHRcdHJvdWdobmVzc01hcFRyYW5zZm9ybTogeyB2YWx1ZTogLypAX19QVVJFX18qLyBuZXcgTWF0cml4MygpIH1cclxuXHJcblx0fSxcclxuXHJcblx0Z3JhZGllbnRtYXA6IHtcclxuXHJcblx0XHRncmFkaWVudE1hcDogeyB2YWx1ZTogbnVsbCB9XHJcblxyXG5cdH0sXHJcblxyXG5cdGZvZzoge1xyXG5cclxuXHRcdGZvZ0RlbnNpdHk6IHsgdmFsdWU6IDAuMDAwMjUgfSxcclxuXHRcdGZvZ05lYXI6IHsgdmFsdWU6IDEgfSxcclxuXHRcdGZvZ0ZhcjogeyB2YWx1ZTogMjAwMCB9LFxyXG5cdFx0Zm9nQ29sb3I6IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IENvbG9yKCAweGZmZmZmZiApIH1cclxuXHJcblx0fSxcclxuXHJcblx0bGlnaHRzOiB7XHJcblxyXG5cdFx0YW1iaWVudExpZ2h0Q29sb3I6IHsgdmFsdWU6IFtdIH0sXHJcblxyXG5cdFx0bGlnaHRQcm9iZTogeyB2YWx1ZTogW10gfSxcclxuXHJcblx0XHRkaXJlY3Rpb25hbExpZ2h0czogeyB2YWx1ZTogW10sIHByb3BlcnRpZXM6IHtcclxuXHRcdFx0ZGlyZWN0aW9uOiB7fSxcclxuXHRcdFx0Y29sb3I6IHt9XHJcblx0XHR9IH0sXHJcblxyXG5cdFx0ZGlyZWN0aW9uYWxMaWdodFNoYWRvd3M6IHsgdmFsdWU6IFtdLCBwcm9wZXJ0aWVzOiB7XHJcblx0XHRcdHNoYWRvd0JpYXM6IHt9LFxyXG5cdFx0XHRzaGFkb3dOb3JtYWxCaWFzOiB7fSxcclxuXHRcdFx0c2hhZG93UmFkaXVzOiB7fSxcclxuXHRcdFx0c2hhZG93TWFwU2l6ZToge31cclxuXHRcdH0gfSxcclxuXHJcblx0XHRkaXJlY3Rpb25hbFNoYWRvd01hcDogeyB2YWx1ZTogW10gfSxcclxuXHRcdGRpcmVjdGlvbmFsU2hhZG93TWF0cml4OiB7IHZhbHVlOiBbXSB9LFxyXG5cclxuXHRcdHNwb3RMaWdodHM6IHsgdmFsdWU6IFtdLCBwcm9wZXJ0aWVzOiB7XHJcblx0XHRcdGNvbG9yOiB7fSxcclxuXHRcdFx0cG9zaXRpb246IHt9LFxyXG5cdFx0XHRkaXJlY3Rpb246IHt9LFxyXG5cdFx0XHRkaXN0YW5jZToge30sXHJcblx0XHRcdGNvbmVDb3M6IHt9LFxyXG5cdFx0XHRwZW51bWJyYUNvczoge30sXHJcblx0XHRcdGRlY2F5OiB7fVxyXG5cdFx0fSB9LFxyXG5cclxuXHRcdHNwb3RMaWdodFNoYWRvd3M6IHsgdmFsdWU6IFtdLCBwcm9wZXJ0aWVzOiB7XHJcblx0XHRcdHNoYWRvd0JpYXM6IHt9LFxyXG5cdFx0XHRzaGFkb3dOb3JtYWxCaWFzOiB7fSxcclxuXHRcdFx0c2hhZG93UmFkaXVzOiB7fSxcclxuXHRcdFx0c2hhZG93TWFwU2l6ZToge31cclxuXHRcdH0gfSxcclxuXHJcblx0XHRzcG90TGlnaHRNYXA6IHsgdmFsdWU6IFtdIH0sXHJcblx0XHRzcG90U2hhZG93TWFwOiB7IHZhbHVlOiBbXSB9LFxyXG5cdFx0c3BvdExpZ2h0TWF0cml4OiB7IHZhbHVlOiBbXSB9LFxyXG5cclxuXHRcdHBvaW50TGlnaHRzOiB7IHZhbHVlOiBbXSwgcHJvcGVydGllczoge1xyXG5cdFx0XHRjb2xvcjoge30sXHJcblx0XHRcdHBvc2l0aW9uOiB7fSxcclxuXHRcdFx0ZGVjYXk6IHt9LFxyXG5cdFx0XHRkaXN0YW5jZToge31cclxuXHRcdH0gfSxcclxuXHJcblx0XHRwb2ludExpZ2h0U2hhZG93czogeyB2YWx1ZTogW10sIHByb3BlcnRpZXM6IHtcclxuXHRcdFx0c2hhZG93Qmlhczoge30sXHJcblx0XHRcdHNoYWRvd05vcm1hbEJpYXM6IHt9LFxyXG5cdFx0XHRzaGFkb3dSYWRpdXM6IHt9LFxyXG5cdFx0XHRzaGFkb3dNYXBTaXplOiB7fSxcclxuXHRcdFx0c2hhZG93Q2FtZXJhTmVhcjoge30sXHJcblx0XHRcdHNoYWRvd0NhbWVyYUZhcjoge31cclxuXHRcdH0gfSxcclxuXHJcblx0XHRwb2ludFNoYWRvd01hcDogeyB2YWx1ZTogW10gfSxcclxuXHRcdHBvaW50U2hhZG93TWF0cml4OiB7IHZhbHVlOiBbXSB9LFxyXG5cclxuXHRcdGhlbWlzcGhlcmVMaWdodHM6IHsgdmFsdWU6IFtdLCBwcm9wZXJ0aWVzOiB7XHJcblx0XHRcdGRpcmVjdGlvbjoge30sXHJcblx0XHRcdHNreUNvbG9yOiB7fSxcclxuXHRcdFx0Z3JvdW5kQ29sb3I6IHt9XHJcblx0XHR9IH0sXHJcblxyXG5cdFx0Ly8gVE9ETyAoYWJlbG5hdGlvbik6IFJlY3RBcmVhTGlnaHQgQlJERiBkYXRhIG5lZWRzIHRvIGJlIG1vdmVkIGZyb20gZXhhbXBsZSB0byBtYWluIHNyY1xyXG5cdFx0cmVjdEFyZWFMaWdodHM6IHsgdmFsdWU6IFtdLCBwcm9wZXJ0aWVzOiB7XHJcblx0XHRcdGNvbG9yOiB7fSxcclxuXHRcdFx0cG9zaXRpb246IHt9LFxyXG5cdFx0XHR3aWR0aDoge30sXHJcblx0XHRcdGhlaWdodDoge31cclxuXHRcdH0gfSxcclxuXHJcblx0XHRsdGNfMTogeyB2YWx1ZTogbnVsbCB9LFxyXG5cdFx0bHRjXzI6IHsgdmFsdWU6IG51bGwgfVxyXG5cclxuXHR9LFxyXG5cclxuXHRwb2ludHM6IHtcclxuXHJcblx0XHRkaWZmdXNlOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBDb2xvciggMHhmZmZmZmYgKSB9LFxyXG5cdFx0b3BhY2l0eTogeyB2YWx1ZTogMS4wIH0sXHJcblx0XHRzaXplOiB7IHZhbHVlOiAxLjAgfSxcclxuXHRcdHNjYWxlOiB7IHZhbHVlOiAxLjAgfSxcclxuXHRcdG1hcDogeyB2YWx1ZTogbnVsbCB9LFxyXG5cdFx0YWxwaGFNYXA6IHsgdmFsdWU6IG51bGwgfSxcclxuXHRcdGFscGhhTWFwVHJhbnNmb3JtOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXgzKCkgfSxcclxuXHRcdGFscGhhVGVzdDogeyB2YWx1ZTogMCB9LFxyXG5cdFx0dXZUcmFuc2Zvcm06IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDMoKSB9XHJcblxyXG5cdH0sXHJcblxyXG5cdHNwcml0ZToge1xyXG5cclxuXHRcdGRpZmZ1c2U6IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IENvbG9yKCAweGZmZmZmZiApIH0sXHJcblx0XHRvcGFjaXR5OiB7IHZhbHVlOiAxLjAgfSxcclxuXHRcdGNlbnRlcjogeyB2YWx1ZTogLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMiggMC41LCAwLjUgKSB9LFxyXG5cdFx0cm90YXRpb246IHsgdmFsdWU6IDAuMCB9LFxyXG5cdFx0bWFwOiB7IHZhbHVlOiBudWxsIH0sXHJcblx0XHRtYXBUcmFuc2Zvcm06IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDMoKSB9LFxyXG5cdFx0YWxwaGFNYXA6IHsgdmFsdWU6IG51bGwgfSxcclxuXHRcdGFscGhhTWFwVHJhbnNmb3JtOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXgzKCkgfSxcclxuXHRcdGFscGhhVGVzdDogeyB2YWx1ZTogMCB9XHJcblxyXG5cdH1cclxuXHJcbn07XHJcblxyXG5leHBvcnQgeyBVbmlmb3Jtc0xpYiB9O1xyXG4iLCJpbXBvcnQgeyBTaGFkZXJDaHVuayB9IGZyb20gJy4vU2hhZGVyQ2h1bmsuanMnO1xyXG5pbXBvcnQgeyBtZXJnZVVuaWZvcm1zIH0gZnJvbSAnLi9Vbmlmb3Jtc1V0aWxzLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yMiB9IGZyb20gJy4uLy4uL21hdGgvVmVjdG9yMi5qcyc7XHJcbmltcG9ydCB7IFZlY3RvcjMgfSBmcm9tICcuLi8uLi9tYXRoL1ZlY3RvcjMuanMnO1xyXG5pbXBvcnQgeyBVbmlmb3Jtc0xpYiB9IGZyb20gJy4vVW5pZm9ybXNMaWIuanMnO1xyXG5pbXBvcnQgeyBDb2xvciB9IGZyb20gJy4uLy4uL21hdGgvQ29sb3IuanMnO1xyXG5pbXBvcnQgeyBNYXRyaXgzIH0gZnJvbSAnLi4vLi4vbWF0aC9NYXRyaXgzLmpzJztcclxuXHJcbmNvbnN0IFNoYWRlckxpYiA9IHtcclxuXHJcblx0YmFzaWM6IHtcclxuXHJcblx0XHR1bmlmb3JtczogLypAX19QVVJFX18qLyBtZXJnZVVuaWZvcm1zKCBbXHJcblx0XHRcdFVuaWZvcm1zTGliLmNvbW1vbixcclxuXHRcdFx0VW5pZm9ybXNMaWIuc3BlY3VsYXJtYXAsXHJcblx0XHRcdFVuaWZvcm1zTGliLmVudm1hcCxcclxuXHRcdFx0VW5pZm9ybXNMaWIuYW9tYXAsXHJcblx0XHRcdFVuaWZvcm1zTGliLmxpZ2h0bWFwLFxyXG5cdFx0XHRVbmlmb3Jtc0xpYi5mb2dcclxuXHRcdF0gKSxcclxuXHJcblx0XHR2ZXJ0ZXhTaGFkZXI6IFNoYWRlckNodW5rLm1lc2hiYXNpY192ZXJ0LFxyXG5cdFx0ZnJhZ21lbnRTaGFkZXI6IFNoYWRlckNodW5rLm1lc2hiYXNpY19mcmFnXHJcblxyXG5cdH0sXHJcblxyXG5cdGxhbWJlcnQ6IHtcclxuXHJcblx0XHR1bmlmb3JtczogLypAX19QVVJFX18qLyBtZXJnZVVuaWZvcm1zKCBbXHJcblx0XHRcdFVuaWZvcm1zTGliLmNvbW1vbixcclxuXHRcdFx0VW5pZm9ybXNMaWIuc3BlY3VsYXJtYXAsXHJcblx0XHRcdFVuaWZvcm1zTGliLmVudm1hcCxcclxuXHRcdFx0VW5pZm9ybXNMaWIuYW9tYXAsXHJcblx0XHRcdFVuaWZvcm1zTGliLmxpZ2h0bWFwLFxyXG5cdFx0XHRVbmlmb3Jtc0xpYi5lbWlzc2l2ZW1hcCxcclxuXHRcdFx0VW5pZm9ybXNMaWIuYnVtcG1hcCxcclxuXHRcdFx0VW5pZm9ybXNMaWIubm9ybWFsbWFwLFxyXG5cdFx0XHRVbmlmb3Jtc0xpYi5kaXNwbGFjZW1lbnRtYXAsXHJcblx0XHRcdFVuaWZvcm1zTGliLmZvZyxcclxuXHRcdFx0VW5pZm9ybXNMaWIubGlnaHRzLFxyXG5cdFx0XHR7XHJcblx0XHRcdFx0ZW1pc3NpdmU6IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IENvbG9yKCAweDAwMDAwMCApIH1cclxuXHRcdFx0fVxyXG5cdFx0XSApLFxyXG5cclxuXHRcdHZlcnRleFNoYWRlcjogU2hhZGVyQ2h1bmsubWVzaGxhbWJlcnRfdmVydCxcclxuXHRcdGZyYWdtZW50U2hhZGVyOiBTaGFkZXJDaHVuay5tZXNobGFtYmVydF9mcmFnXHJcblxyXG5cdH0sXHJcblxyXG5cdHBob25nOiB7XHJcblxyXG5cdFx0dW5pZm9ybXM6IC8qQF9fUFVSRV9fKi8gbWVyZ2VVbmlmb3JtcyggW1xyXG5cdFx0XHRVbmlmb3Jtc0xpYi5jb21tb24sXHJcblx0XHRcdFVuaWZvcm1zTGliLnNwZWN1bGFybWFwLFxyXG5cdFx0XHRVbmlmb3Jtc0xpYi5lbnZtYXAsXHJcblx0XHRcdFVuaWZvcm1zTGliLmFvbWFwLFxyXG5cdFx0XHRVbmlmb3Jtc0xpYi5saWdodG1hcCxcclxuXHRcdFx0VW5pZm9ybXNMaWIuZW1pc3NpdmVtYXAsXHJcblx0XHRcdFVuaWZvcm1zTGliLmJ1bXBtYXAsXHJcblx0XHRcdFVuaWZvcm1zTGliLm5vcm1hbG1hcCxcclxuXHRcdFx0VW5pZm9ybXNMaWIuZGlzcGxhY2VtZW50bWFwLFxyXG5cdFx0XHRVbmlmb3Jtc0xpYi5mb2csXHJcblx0XHRcdFVuaWZvcm1zTGliLmxpZ2h0cyxcclxuXHRcdFx0e1xyXG5cdFx0XHRcdGVtaXNzaXZlOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBDb2xvciggMHgwMDAwMDAgKSB9LFxyXG5cdFx0XHRcdHNwZWN1bGFyOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBDb2xvciggMHgxMTExMTEgKSB9LFxyXG5cdFx0XHRcdHNoaW5pbmVzczogeyB2YWx1ZTogMzAgfVxyXG5cdFx0XHR9XHJcblx0XHRdICksXHJcblxyXG5cdFx0dmVydGV4U2hhZGVyOiBTaGFkZXJDaHVuay5tZXNocGhvbmdfdmVydCxcclxuXHRcdGZyYWdtZW50U2hhZGVyOiBTaGFkZXJDaHVuay5tZXNocGhvbmdfZnJhZ1xyXG5cclxuXHR9LFxyXG5cclxuXHRzdGFuZGFyZDoge1xyXG5cclxuXHRcdHVuaWZvcm1zOiAvKkBfX1BVUkVfXyovIG1lcmdlVW5pZm9ybXMoIFtcclxuXHRcdFx0VW5pZm9ybXNMaWIuY29tbW9uLFxyXG5cdFx0XHRVbmlmb3Jtc0xpYi5lbnZtYXAsXHJcblx0XHRcdFVuaWZvcm1zTGliLmFvbWFwLFxyXG5cdFx0XHRVbmlmb3Jtc0xpYi5saWdodG1hcCxcclxuXHRcdFx0VW5pZm9ybXNMaWIuZW1pc3NpdmVtYXAsXHJcblx0XHRcdFVuaWZvcm1zTGliLmJ1bXBtYXAsXHJcblx0XHRcdFVuaWZvcm1zTGliLm5vcm1hbG1hcCxcclxuXHRcdFx0VW5pZm9ybXNMaWIuZGlzcGxhY2VtZW50bWFwLFxyXG5cdFx0XHRVbmlmb3Jtc0xpYi5yb3VnaG5lc3NtYXAsXHJcblx0XHRcdFVuaWZvcm1zTGliLm1ldGFsbmVzc21hcCxcclxuXHRcdFx0VW5pZm9ybXNMaWIuZm9nLFxyXG5cdFx0XHRVbmlmb3Jtc0xpYi5saWdodHMsXHJcblx0XHRcdHtcclxuXHRcdFx0XHRlbWlzc2l2ZTogeyB2YWx1ZTogLypAX19QVVJFX18qLyBuZXcgQ29sb3IoIDB4MDAwMDAwICkgfSxcclxuXHRcdFx0XHRyb3VnaG5lc3M6IHsgdmFsdWU6IDEuMCB9LFxyXG5cdFx0XHRcdG1ldGFsbmVzczogeyB2YWx1ZTogMC4wIH0sXHJcblx0XHRcdFx0ZW52TWFwSW50ZW5zaXR5OiB7IHZhbHVlOiAxIH0gLy8gdGVtcG9yYXJ5XHJcblx0XHRcdH1cclxuXHRcdF0gKSxcclxuXHJcblx0XHR2ZXJ0ZXhTaGFkZXI6IFNoYWRlckNodW5rLm1lc2hwaHlzaWNhbF92ZXJ0LFxyXG5cdFx0ZnJhZ21lbnRTaGFkZXI6IFNoYWRlckNodW5rLm1lc2hwaHlzaWNhbF9mcmFnXHJcblxyXG5cdH0sXHJcblxyXG5cdHRvb246IHtcclxuXHJcblx0XHR1bmlmb3JtczogLypAX19QVVJFX18qLyBtZXJnZVVuaWZvcm1zKCBbXHJcblx0XHRcdFVuaWZvcm1zTGliLmNvbW1vbixcclxuXHRcdFx0VW5pZm9ybXNMaWIuYW9tYXAsXHJcblx0XHRcdFVuaWZvcm1zTGliLmxpZ2h0bWFwLFxyXG5cdFx0XHRVbmlmb3Jtc0xpYi5lbWlzc2l2ZW1hcCxcclxuXHRcdFx0VW5pZm9ybXNMaWIuYnVtcG1hcCxcclxuXHRcdFx0VW5pZm9ybXNMaWIubm9ybWFsbWFwLFxyXG5cdFx0XHRVbmlmb3Jtc0xpYi5kaXNwbGFjZW1lbnRtYXAsXHJcblx0XHRcdFVuaWZvcm1zTGliLmdyYWRpZW50bWFwLFxyXG5cdFx0XHRVbmlmb3Jtc0xpYi5mb2csXHJcblx0XHRcdFVuaWZvcm1zTGliLmxpZ2h0cyxcclxuXHRcdFx0e1xyXG5cdFx0XHRcdGVtaXNzaXZlOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBDb2xvciggMHgwMDAwMDAgKSB9XHJcblx0XHRcdH1cclxuXHRcdF0gKSxcclxuXHJcblx0XHR2ZXJ0ZXhTaGFkZXI6IFNoYWRlckNodW5rLm1lc2h0b29uX3ZlcnQsXHJcblx0XHRmcmFnbWVudFNoYWRlcjogU2hhZGVyQ2h1bmsubWVzaHRvb25fZnJhZ1xyXG5cclxuXHR9LFxyXG5cclxuXHRtYXRjYXA6IHtcclxuXHJcblx0XHR1bmlmb3JtczogLypAX19QVVJFX18qLyBtZXJnZVVuaWZvcm1zKCBbXHJcblx0XHRcdFVuaWZvcm1zTGliLmNvbW1vbixcclxuXHRcdFx0VW5pZm9ybXNMaWIuYnVtcG1hcCxcclxuXHRcdFx0VW5pZm9ybXNMaWIubm9ybWFsbWFwLFxyXG5cdFx0XHRVbmlmb3Jtc0xpYi5kaXNwbGFjZW1lbnRtYXAsXHJcblx0XHRcdFVuaWZvcm1zTGliLmZvZyxcclxuXHRcdFx0e1xyXG5cdFx0XHRcdG1hdGNhcDogeyB2YWx1ZTogbnVsbCB9XHJcblx0XHRcdH1cclxuXHRcdF0gKSxcclxuXHJcblx0XHR2ZXJ0ZXhTaGFkZXI6IFNoYWRlckNodW5rLm1lc2htYXRjYXBfdmVydCxcclxuXHRcdGZyYWdtZW50U2hhZGVyOiBTaGFkZXJDaHVuay5tZXNobWF0Y2FwX2ZyYWdcclxuXHJcblx0fSxcclxuXHJcblx0cG9pbnRzOiB7XHJcblxyXG5cdFx0dW5pZm9ybXM6IC8qQF9fUFVSRV9fKi8gbWVyZ2VVbmlmb3JtcyggW1xyXG5cdFx0XHRVbmlmb3Jtc0xpYi5wb2ludHMsXHJcblx0XHRcdFVuaWZvcm1zTGliLmZvZ1xyXG5cdFx0XSApLFxyXG5cclxuXHRcdHZlcnRleFNoYWRlcjogU2hhZGVyQ2h1bmsucG9pbnRzX3ZlcnQsXHJcblx0XHRmcmFnbWVudFNoYWRlcjogU2hhZGVyQ2h1bmsucG9pbnRzX2ZyYWdcclxuXHJcblx0fSxcclxuXHJcblx0ZGFzaGVkOiB7XHJcblxyXG5cdFx0dW5pZm9ybXM6IC8qQF9fUFVSRV9fKi8gbWVyZ2VVbmlmb3JtcyggW1xyXG5cdFx0XHRVbmlmb3Jtc0xpYi5jb21tb24sXHJcblx0XHRcdFVuaWZvcm1zTGliLmZvZyxcclxuXHRcdFx0e1xyXG5cdFx0XHRcdHNjYWxlOiB7IHZhbHVlOiAxIH0sXHJcblx0XHRcdFx0ZGFzaFNpemU6IHsgdmFsdWU6IDEgfSxcclxuXHRcdFx0XHR0b3RhbFNpemU6IHsgdmFsdWU6IDIgfVxyXG5cdFx0XHR9XHJcblx0XHRdICksXHJcblxyXG5cdFx0dmVydGV4U2hhZGVyOiBTaGFkZXJDaHVuay5saW5lZGFzaGVkX3ZlcnQsXHJcblx0XHRmcmFnbWVudFNoYWRlcjogU2hhZGVyQ2h1bmsubGluZWRhc2hlZF9mcmFnXHJcblxyXG5cdH0sXHJcblxyXG5cdGRlcHRoOiB7XHJcblxyXG5cdFx0dW5pZm9ybXM6IC8qQF9fUFVSRV9fKi8gbWVyZ2VVbmlmb3JtcyggW1xyXG5cdFx0XHRVbmlmb3Jtc0xpYi5jb21tb24sXHJcblx0XHRcdFVuaWZvcm1zTGliLmRpc3BsYWNlbWVudG1hcFxyXG5cdFx0XSApLFxyXG5cclxuXHRcdHZlcnRleFNoYWRlcjogU2hhZGVyQ2h1bmsuZGVwdGhfdmVydCxcclxuXHRcdGZyYWdtZW50U2hhZGVyOiBTaGFkZXJDaHVuay5kZXB0aF9mcmFnXHJcblxyXG5cdH0sXHJcblxyXG5cdG5vcm1hbDoge1xyXG5cclxuXHRcdHVuaWZvcm1zOiAvKkBfX1BVUkVfXyovIG1lcmdlVW5pZm9ybXMoIFtcclxuXHRcdFx0VW5pZm9ybXNMaWIuY29tbW9uLFxyXG5cdFx0XHRVbmlmb3Jtc0xpYi5idW1wbWFwLFxyXG5cdFx0XHRVbmlmb3Jtc0xpYi5ub3JtYWxtYXAsXHJcblx0XHRcdFVuaWZvcm1zTGliLmRpc3BsYWNlbWVudG1hcCxcclxuXHRcdFx0e1xyXG5cdFx0XHRcdG9wYWNpdHk6IHsgdmFsdWU6IDEuMCB9XHJcblx0XHRcdH1cclxuXHRcdF0gKSxcclxuXHJcblx0XHR2ZXJ0ZXhTaGFkZXI6IFNoYWRlckNodW5rLm1lc2hub3JtYWxfdmVydCxcclxuXHRcdGZyYWdtZW50U2hhZGVyOiBTaGFkZXJDaHVuay5tZXNobm9ybWFsX2ZyYWdcclxuXHJcblx0fSxcclxuXHJcblx0c3ByaXRlOiB7XHJcblxyXG5cdFx0dW5pZm9ybXM6IC8qQF9fUFVSRV9fKi8gbWVyZ2VVbmlmb3JtcyggW1xyXG5cdFx0XHRVbmlmb3Jtc0xpYi5zcHJpdGUsXHJcblx0XHRcdFVuaWZvcm1zTGliLmZvZ1xyXG5cdFx0XSApLFxyXG5cclxuXHRcdHZlcnRleFNoYWRlcjogU2hhZGVyQ2h1bmsuc3ByaXRlX3ZlcnQsXHJcblx0XHRmcmFnbWVudFNoYWRlcjogU2hhZGVyQ2h1bmsuc3ByaXRlX2ZyYWdcclxuXHJcblx0fSxcclxuXHJcblx0YmFja2dyb3VuZDoge1xyXG5cclxuXHRcdHVuaWZvcm1zOiB7XHJcblx0XHRcdHV2VHJhbnNmb3JtOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXgzKCkgfSxcclxuXHRcdFx0dDJEOiB7IHZhbHVlOiBudWxsIH0sXHJcblx0XHRcdGJhY2tncm91bmRJbnRlbnNpdHk6IHsgdmFsdWU6IDEgfVxyXG5cdFx0fSxcclxuXHJcblx0XHR2ZXJ0ZXhTaGFkZXI6IFNoYWRlckNodW5rLmJhY2tncm91bmRfdmVydCxcclxuXHRcdGZyYWdtZW50U2hhZGVyOiBTaGFkZXJDaHVuay5iYWNrZ3JvdW5kX2ZyYWdcclxuXHJcblx0fSxcclxuXHJcblx0YmFja2dyb3VuZEN1YmU6IHtcclxuXHJcblx0XHR1bmlmb3Jtczoge1xyXG5cdFx0XHRlbnZNYXA6IHsgdmFsdWU6IG51bGwgfSxcclxuXHRcdFx0ZmxpcEVudk1hcDogeyB2YWx1ZTogLSAxIH0sXHJcblx0XHRcdGJhY2tncm91bmRCbHVycmluZXNzOiB7IHZhbHVlOiAwIH0sXHJcblx0XHRcdGJhY2tncm91bmRJbnRlbnNpdHk6IHsgdmFsdWU6IDEgfVxyXG5cdFx0fSxcclxuXHJcblx0XHR2ZXJ0ZXhTaGFkZXI6IFNoYWRlckNodW5rLmJhY2tncm91bmRDdWJlX3ZlcnQsXHJcblx0XHRmcmFnbWVudFNoYWRlcjogU2hhZGVyQ2h1bmsuYmFja2dyb3VuZEN1YmVfZnJhZ1xyXG5cclxuXHR9LFxyXG5cclxuXHRjdWJlOiB7XHJcblxyXG5cdFx0dW5pZm9ybXM6IHtcclxuXHRcdFx0dEN1YmU6IHsgdmFsdWU6IG51bGwgfSxcclxuXHRcdFx0dEZsaXA6IHsgdmFsdWU6IC0gMSB9LFxyXG5cdFx0XHRvcGFjaXR5OiB7IHZhbHVlOiAxLjAgfVxyXG5cdFx0fSxcclxuXHJcblx0XHR2ZXJ0ZXhTaGFkZXI6IFNoYWRlckNodW5rLmN1YmVfdmVydCxcclxuXHRcdGZyYWdtZW50U2hhZGVyOiBTaGFkZXJDaHVuay5jdWJlX2ZyYWdcclxuXHJcblx0fSxcclxuXHJcblx0ZXF1aXJlY3Q6IHtcclxuXHJcblx0XHR1bmlmb3Jtczoge1xyXG5cdFx0XHR0RXF1aXJlY3Q6IHsgdmFsdWU6IG51bGwgfSxcclxuXHRcdH0sXHJcblxyXG5cdFx0dmVydGV4U2hhZGVyOiBTaGFkZXJDaHVuay5lcXVpcmVjdF92ZXJ0LFxyXG5cdFx0ZnJhZ21lbnRTaGFkZXI6IFNoYWRlckNodW5rLmVxdWlyZWN0X2ZyYWdcclxuXHJcblx0fSxcclxuXHJcblx0ZGlzdGFuY2VSR0JBOiB7XHJcblxyXG5cdFx0dW5pZm9ybXM6IC8qQF9fUFVSRV9fKi8gbWVyZ2VVbmlmb3JtcyggW1xyXG5cdFx0XHRVbmlmb3Jtc0xpYi5jb21tb24sXHJcblx0XHRcdFVuaWZvcm1zTGliLmRpc3BsYWNlbWVudG1hcCxcclxuXHRcdFx0e1xyXG5cdFx0XHRcdHJlZmVyZW5jZVBvc2l0aW9uOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCkgfSxcclxuXHRcdFx0XHRuZWFyRGlzdGFuY2U6IHsgdmFsdWU6IDEgfSxcclxuXHRcdFx0XHRmYXJEaXN0YW5jZTogeyB2YWx1ZTogMTAwMCB9XHJcblx0XHRcdH1cclxuXHRcdF0gKSxcclxuXHJcblx0XHR2ZXJ0ZXhTaGFkZXI6IFNoYWRlckNodW5rLmRpc3RhbmNlUkdCQV92ZXJ0LFxyXG5cdFx0ZnJhZ21lbnRTaGFkZXI6IFNoYWRlckNodW5rLmRpc3RhbmNlUkdCQV9mcmFnXHJcblxyXG5cdH0sXHJcblxyXG5cdHNoYWRvdzoge1xyXG5cclxuXHRcdHVuaWZvcm1zOiAvKkBfX1BVUkVfXyovIG1lcmdlVW5pZm9ybXMoIFtcclxuXHRcdFx0VW5pZm9ybXNMaWIubGlnaHRzLFxyXG5cdFx0XHRVbmlmb3Jtc0xpYi5mb2csXHJcblx0XHRcdHtcclxuXHRcdFx0XHRjb2xvcjogeyB2YWx1ZTogLypAX19QVVJFX18qLyBuZXcgQ29sb3IoIDB4MDAwMDAgKSB9LFxyXG5cdFx0XHRcdG9wYWNpdHk6IHsgdmFsdWU6IDEuMCB9XHJcblx0XHRcdH0sXHJcblx0XHRdICksXHJcblxyXG5cdFx0dmVydGV4U2hhZGVyOiBTaGFkZXJDaHVuay5zaGFkb3dfdmVydCxcclxuXHRcdGZyYWdtZW50U2hhZGVyOiBTaGFkZXJDaHVuay5zaGFkb3dfZnJhZ1xyXG5cclxuXHR9XHJcblxyXG59O1xyXG5cclxuU2hhZGVyTGliLnBoeXNpY2FsID0ge1xyXG5cclxuXHR1bmlmb3JtczogLypAX19QVVJFX18qLyBtZXJnZVVuaWZvcm1zKCBbXHJcblx0XHRTaGFkZXJMaWIuc3RhbmRhcmQudW5pZm9ybXMsXHJcblx0XHR7XHJcblx0XHRcdGNsZWFyY29hdDogeyB2YWx1ZTogMCB9LFxyXG5cdFx0XHRjbGVhcmNvYXRNYXA6IHsgdmFsdWU6IG51bGwgfSxcclxuXHRcdFx0Y2xlYXJjb2F0TWFwVHJhbnNmb3JtOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXgzKCkgfSxcclxuXHRcdFx0Y2xlYXJjb2F0Tm9ybWFsTWFwOiB7IHZhbHVlOiBudWxsIH0sXHJcblx0XHRcdGNsZWFyY29hdE5vcm1hbE1hcFRyYW5zZm9ybTogeyB2YWx1ZTogLypAX19QVVJFX18qLyBuZXcgTWF0cml4MygpIH0sXHJcblx0XHRcdGNsZWFyY29hdE5vcm1hbFNjYWxlOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IyKCAxLCAxICkgfSxcclxuXHRcdFx0Y2xlYXJjb2F0Um91Z2huZXNzOiB7IHZhbHVlOiAwIH0sXHJcblx0XHRcdGNsZWFyY29hdFJvdWdobmVzc01hcDogeyB2YWx1ZTogbnVsbCB9LFxyXG5cdFx0XHRjbGVhcmNvYXRSb3VnaG5lc3NNYXBUcmFuc2Zvcm06IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDMoKSB9LFxyXG5cdFx0XHRpcmlkZXNjZW5jZTogeyB2YWx1ZTogMCB9LFxyXG5cdFx0XHRpcmlkZXNjZW5jZU1hcDogeyB2YWx1ZTogbnVsbCB9LFxyXG5cdFx0XHRpcmlkZXNjZW5jZU1hcFRyYW5zZm9ybTogeyB2YWx1ZTogLypAX19QVVJFX18qLyBuZXcgTWF0cml4MygpIH0sXHJcblx0XHRcdGlyaWRlc2NlbmNlSU9SOiB7IHZhbHVlOiAxLjMgfSxcclxuXHRcdFx0aXJpZGVzY2VuY2VUaGlja25lc3NNaW5pbXVtOiB7IHZhbHVlOiAxMDAgfSxcclxuXHRcdFx0aXJpZGVzY2VuY2VUaGlja25lc3NNYXhpbXVtOiB7IHZhbHVlOiA0MDAgfSxcclxuXHRcdFx0aXJpZGVzY2VuY2VUaGlja25lc3NNYXA6IHsgdmFsdWU6IG51bGwgfSxcclxuXHRcdFx0aXJpZGVzY2VuY2VUaGlja25lc3NNYXBUcmFuc2Zvcm06IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDMoKSB9LFxyXG5cdFx0XHRzaGVlbjogeyB2YWx1ZTogMCB9LFxyXG5cdFx0XHRzaGVlbkNvbG9yOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBDb2xvciggMHgwMDAwMDAgKSB9LFxyXG5cdFx0XHRzaGVlbkNvbG9yTWFwOiB7IHZhbHVlOiBudWxsIH0sXHJcblx0XHRcdHNoZWVuQ29sb3JNYXBUcmFuc2Zvcm06IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDMoKSB9LFxyXG5cdFx0XHRzaGVlblJvdWdobmVzczogeyB2YWx1ZTogMSB9LFxyXG5cdFx0XHRzaGVlblJvdWdobmVzc01hcDogeyB2YWx1ZTogbnVsbCB9LFxyXG5cdFx0XHRzaGVlblJvdWdobmVzc01hcFRyYW5zZm9ybTogeyB2YWx1ZTogLypAX19QVVJFX18qLyBuZXcgTWF0cml4MygpIH0sXHJcblx0XHRcdHRyYW5zbWlzc2lvbjogeyB2YWx1ZTogMCB9LFxyXG5cdFx0XHR0cmFuc21pc3Npb25NYXA6IHsgdmFsdWU6IG51bGwgfSxcclxuXHRcdFx0dHJhbnNtaXNzaW9uTWFwVHJhbnNmb3JtOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXgzKCkgfSxcclxuXHRcdFx0dHJhbnNtaXNzaW9uU2FtcGxlclNpemU6IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjIoKSB9LFxyXG5cdFx0XHR0cmFuc21pc3Npb25TYW1wbGVyTWFwOiB7IHZhbHVlOiBudWxsIH0sXHJcblx0XHRcdHRoaWNrbmVzczogeyB2YWx1ZTogMCB9LFxyXG5cdFx0XHR0aGlja25lc3NNYXA6IHsgdmFsdWU6IG51bGwgfSxcclxuXHRcdFx0dGhpY2tuZXNzTWFwVHJhbnNmb3JtOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXgzKCkgfSxcclxuXHRcdFx0YXR0ZW51YXRpb25EaXN0YW5jZTogeyB2YWx1ZTogMCB9LFxyXG5cdFx0XHRhdHRlbnVhdGlvbkNvbG9yOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBDb2xvciggMHgwMDAwMDAgKSB9LFxyXG5cdFx0XHRzcGVjdWxhckNvbG9yOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBDb2xvciggMSwgMSwgMSApIH0sXHJcblx0XHRcdHNwZWN1bGFyQ29sb3JNYXA6IHsgdmFsdWU6IG51bGwgfSxcclxuXHRcdFx0c3BlY3VsYXJDb2xvck1hcFRyYW5zZm9ybTogeyB2YWx1ZTogLypAX19QVVJFX18qLyBuZXcgTWF0cml4MygpIH0sXHJcblx0XHRcdHNwZWN1bGFySW50ZW5zaXR5OiB7IHZhbHVlOiAxIH0sXHJcblx0XHRcdHNwZWN1bGFySW50ZW5zaXR5TWFwOiB7IHZhbHVlOiBudWxsIH0sXHJcblx0XHRcdHNwZWN1bGFySW50ZW5zaXR5TWFwVHJhbnNmb3JtOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXgzKCkgfSxcclxuXHRcdFx0YW5pc290cm9weVZlY3RvcjogeyB2YWx1ZTogLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMigpIH0sXHJcblx0XHRcdGFuaXNvdHJvcHlNYXA6IHsgdmFsdWU6IG51bGwgfSxcclxuXHRcdFx0YW5pc290cm9weU1hcFRyYW5zZm9ybTogeyB2YWx1ZTogLypAX19QVVJFX18qLyBuZXcgTWF0cml4MygpIH0sXHJcblx0XHR9XHJcblx0XSApLFxyXG5cclxuXHR2ZXJ0ZXhTaGFkZXI6IFNoYWRlckNodW5rLm1lc2hwaHlzaWNhbF92ZXJ0LFxyXG5cdGZyYWdtZW50U2hhZGVyOiBTaGFkZXJDaHVuay5tZXNocGh5c2ljYWxfZnJhZ1xyXG5cclxufTtcclxuXHJcblxyXG5leHBvcnQgeyBTaGFkZXJMaWIgfTtcclxuIiwiaW1wb3J0IHsgQmFja1NpZGUsIEZyb250U2lkZSwgQ3ViZVVWUmVmbGVjdGlvbk1hcHBpbmcsIFNSR0JUcmFuc2ZlciB9IGZyb20gJy4uLy4uL2NvbnN0YW50cy5qcyc7XHJcbmltcG9ydCB7IEJveEdlb21ldHJ5IH0gZnJvbSAnLi4vLi4vZ2VvbWV0cmllcy9Cb3hHZW9tZXRyeS5qcyc7XHJcbmltcG9ydCB7IFBsYW5lR2VvbWV0cnkgfSBmcm9tICcuLi8uLi9nZW9tZXRyaWVzL1BsYW5lR2VvbWV0cnkuanMnO1xyXG5pbXBvcnQgeyBTaGFkZXJNYXRlcmlhbCB9IGZyb20gJy4uLy4uL21hdGVyaWFscy9TaGFkZXJNYXRlcmlhbC5qcyc7XHJcbmltcG9ydCB7IENvbG9yIH0gZnJvbSAnLi4vLi4vbWF0aC9Db2xvci5qcyc7XHJcbmltcG9ydCB7IENvbG9yTWFuYWdlbWVudCB9IGZyb20gJy4uLy4uL21hdGgvQ29sb3JNYW5hZ2VtZW50LmpzJztcclxuaW1wb3J0IHsgTWVzaCB9IGZyb20gJy4uLy4uL29iamVjdHMvTWVzaC5qcyc7XHJcbmltcG9ydCB7IFNoYWRlckxpYiB9IGZyb20gJy4uL3NoYWRlcnMvU2hhZGVyTGliLmpzJztcclxuaW1wb3J0IHsgY2xvbmVVbmlmb3JtcywgZ2V0VW5saXRVbmlmb3JtQ29sb3JTcGFjZSB9IGZyb20gJy4uL3NoYWRlcnMvVW5pZm9ybXNVdGlscy5qcyc7XHJcblxyXG5jb25zdCBfcmdiID0geyByOiAwLCBiOiAwLCBnOiAwIH07XHJcblxyXG5mdW5jdGlvbiBXZWJHTEJhY2tncm91bmQoIHJlbmRlcmVyLCBjdWJlbWFwcywgY3ViZXV2bWFwcywgc3RhdGUsIG9iamVjdHMsIGFscGhhLCBwcmVtdWx0aXBsaWVkQWxwaGEgKSB7XHJcblxyXG5cdGNvbnN0IGNsZWFyQ29sb3IgPSBuZXcgQ29sb3IoIDB4MDAwMDAwICk7XHJcblx0bGV0IGNsZWFyQWxwaGEgPSBhbHBoYSA9PT0gdHJ1ZSA/IDAgOiAxO1xyXG5cclxuXHRsZXQgcGxhbmVNZXNoO1xyXG5cdGxldCBib3hNZXNoO1xyXG5cclxuXHRsZXQgY3VycmVudEJhY2tncm91bmQgPSBudWxsO1xyXG5cdGxldCBjdXJyZW50QmFja2dyb3VuZFZlcnNpb24gPSAwO1xyXG5cdGxldCBjdXJyZW50VG9uZW1hcHBpbmcgPSBudWxsO1xyXG5cclxuXHRmdW5jdGlvbiByZW5kZXIoIHJlbmRlckxpc3QsIHNjZW5lICkge1xyXG5cclxuXHRcdGxldCBmb3JjZUNsZWFyID0gZmFsc2U7XHJcblx0XHRsZXQgYmFja2dyb3VuZCA9IHNjZW5lLmlzU2NlbmUgPT09IHRydWUgPyBzY2VuZS5iYWNrZ3JvdW5kIDogbnVsbDtcclxuXHJcblx0XHRpZiAoIGJhY2tncm91bmQgJiYgYmFja2dyb3VuZC5pc1RleHR1cmUgKSB7XHJcblxyXG5cdFx0XHRjb25zdCB1c2VQTVJFTSA9IHNjZW5lLmJhY2tncm91bmRCbHVycmluZXNzID4gMDsgLy8gdXNlIFBNUkVNIGlmIHRoZSB1c2VyIHdhbnRzIHRvIGJsdXIgdGhlIGJhY2tncm91bmRcclxuXHRcdFx0YmFja2dyb3VuZCA9ICggdXNlUE1SRU0gPyBjdWJldXZtYXBzIDogY3ViZW1hcHMgKS5nZXQoIGJhY2tncm91bmQgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBiYWNrZ3JvdW5kID09PSBudWxsICkge1xyXG5cclxuXHRcdFx0c2V0Q2xlYXIoIGNsZWFyQ29sb3IsIGNsZWFyQWxwaGEgKTtcclxuXHJcblx0XHR9IGVsc2UgaWYgKCBiYWNrZ3JvdW5kICYmIGJhY2tncm91bmQuaXNDb2xvciApIHtcclxuXHJcblx0XHRcdHNldENsZWFyKCBiYWNrZ3JvdW5kLCAxICk7XHJcblx0XHRcdGZvcmNlQ2xlYXIgPSB0cnVlO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCBlbnZpcm9ubWVudEJsZW5kTW9kZSA9IHJlbmRlcmVyLnhyLmdldEVudmlyb25tZW50QmxlbmRNb2RlKCk7XHJcblxyXG5cdFx0aWYgKCBlbnZpcm9ubWVudEJsZW5kTW9kZSA9PT0gJ2FkZGl0aXZlJyApIHtcclxuXHJcblx0XHRcdHN0YXRlLmJ1ZmZlcnMuY29sb3Iuc2V0Q2xlYXIoIDAsIDAsIDAsIDEsIHByZW11bHRpcGxpZWRBbHBoYSApO1xyXG5cclxuXHRcdH0gZWxzZSBpZiAoIGVudmlyb25tZW50QmxlbmRNb2RlID09PSAnYWxwaGEtYmxlbmQnICkge1xyXG5cclxuXHRcdFx0c3RhdGUuYnVmZmVycy5jb2xvci5zZXRDbGVhciggMCwgMCwgMCwgMCwgcHJlbXVsdGlwbGllZEFscGhhICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggcmVuZGVyZXIuYXV0b0NsZWFyIHx8IGZvcmNlQ2xlYXIgKSB7XHJcblxyXG5cdFx0XHRyZW5kZXJlci5jbGVhciggcmVuZGVyZXIuYXV0b0NsZWFyQ29sb3IsIHJlbmRlcmVyLmF1dG9DbGVhckRlcHRoLCByZW5kZXJlci5hdXRvQ2xlYXJTdGVuY2lsICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggYmFja2dyb3VuZCAmJiAoIGJhY2tncm91bmQuaXNDdWJlVGV4dHVyZSB8fCBiYWNrZ3JvdW5kLm1hcHBpbmcgPT09IEN1YmVVVlJlZmxlY3Rpb25NYXBwaW5nICkgKSB7XHJcblxyXG5cdFx0XHRpZiAoIGJveE1lc2ggPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0Ym94TWVzaCA9IG5ldyBNZXNoKFxyXG5cdFx0XHRcdFx0bmV3IEJveEdlb21ldHJ5KCAxLCAxLCAxICksXHJcblx0XHRcdFx0XHRuZXcgU2hhZGVyTWF0ZXJpYWwoIHtcclxuXHRcdFx0XHRcdFx0bmFtZTogJ0JhY2tncm91bmRDdWJlTWF0ZXJpYWwnLFxyXG5cdFx0XHRcdFx0XHR1bmlmb3JtczogY2xvbmVVbmlmb3JtcyggU2hhZGVyTGliLmJhY2tncm91bmRDdWJlLnVuaWZvcm1zICksXHJcblx0XHRcdFx0XHRcdHZlcnRleFNoYWRlcjogU2hhZGVyTGliLmJhY2tncm91bmRDdWJlLnZlcnRleFNoYWRlcixcclxuXHRcdFx0XHRcdFx0ZnJhZ21lbnRTaGFkZXI6IFNoYWRlckxpYi5iYWNrZ3JvdW5kQ3ViZS5mcmFnbWVudFNoYWRlcixcclxuXHRcdFx0XHRcdFx0c2lkZTogQmFja1NpZGUsXHJcblx0XHRcdFx0XHRcdGRlcHRoVGVzdDogZmFsc2UsXHJcblx0XHRcdFx0XHRcdGRlcHRoV3JpdGU6IGZhbHNlLFxyXG5cdFx0XHRcdFx0XHRmb2c6IGZhbHNlXHJcblx0XHRcdFx0XHR9IClcclxuXHRcdFx0XHQpO1xyXG5cclxuXHRcdFx0XHRib3hNZXNoLmdlb21ldHJ5LmRlbGV0ZUF0dHJpYnV0ZSggJ25vcm1hbCcgKTtcclxuXHRcdFx0XHRib3hNZXNoLmdlb21ldHJ5LmRlbGV0ZUF0dHJpYnV0ZSggJ3V2JyApO1xyXG5cclxuXHRcdFx0XHRib3hNZXNoLm9uQmVmb3JlUmVuZGVyID0gZnVuY3Rpb24gKCByZW5kZXJlciwgc2NlbmUsIGNhbWVyYSApIHtcclxuXHJcblx0XHRcdFx0XHR0aGlzLm1hdHJpeFdvcmxkLmNvcHlQb3NpdGlvbiggY2FtZXJhLm1hdHJpeFdvcmxkICk7XHJcblxyXG5cdFx0XHRcdH07XHJcblxyXG5cdFx0XHRcdC8vIGFkZCBcImVudk1hcFwiIG1hdGVyaWFsIHByb3BlcnR5IHNvIHRoZSByZW5kZXJlciBjYW4gZXZhbHVhdGUgaXQgbGlrZSBmb3IgYnVpbHQtaW4gbWF0ZXJpYWxzXHJcblx0XHRcdFx0T2JqZWN0LmRlZmluZVByb3BlcnR5KCBib3hNZXNoLm1hdGVyaWFsLCAnZW52TWFwJywge1xyXG5cclxuXHRcdFx0XHRcdGdldDogZnVuY3Rpb24gKCkge1xyXG5cclxuXHRcdFx0XHRcdFx0cmV0dXJuIHRoaXMudW5pZm9ybXMuZW52TWFwLnZhbHVlO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fSApO1xyXG5cclxuXHRcdFx0XHRvYmplY3RzLnVwZGF0ZSggYm94TWVzaCApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Ym94TWVzaC5tYXRlcmlhbC51bmlmb3Jtcy5lbnZNYXAudmFsdWUgPSBiYWNrZ3JvdW5kO1xyXG5cdFx0XHRib3hNZXNoLm1hdGVyaWFsLnVuaWZvcm1zLmZsaXBFbnZNYXAudmFsdWUgPSAoIGJhY2tncm91bmQuaXNDdWJlVGV4dHVyZSAmJiBiYWNrZ3JvdW5kLmlzUmVuZGVyVGFyZ2V0VGV4dHVyZSA9PT0gZmFsc2UgKSA/IC0gMSA6IDE7XHJcblx0XHRcdGJveE1lc2gubWF0ZXJpYWwudW5pZm9ybXMuYmFja2dyb3VuZEJsdXJyaW5lc3MudmFsdWUgPSBzY2VuZS5iYWNrZ3JvdW5kQmx1cnJpbmVzcztcclxuXHRcdFx0Ym94TWVzaC5tYXRlcmlhbC51bmlmb3Jtcy5iYWNrZ3JvdW5kSW50ZW5zaXR5LnZhbHVlID0gc2NlbmUuYmFja2dyb3VuZEludGVuc2l0eTtcclxuXHRcdFx0Ym94TWVzaC5tYXRlcmlhbC50b25lTWFwcGVkID0gQ29sb3JNYW5hZ2VtZW50LmdldFRyYW5zZmVyKCBiYWNrZ3JvdW5kLmNvbG9yU3BhY2UgKSAhPT0gU1JHQlRyYW5zZmVyO1xyXG5cclxuXHRcdFx0aWYgKCBjdXJyZW50QmFja2dyb3VuZCAhPT0gYmFja2dyb3VuZCB8fFxyXG5cdFx0XHRcdGN1cnJlbnRCYWNrZ3JvdW5kVmVyc2lvbiAhPT0gYmFja2dyb3VuZC52ZXJzaW9uIHx8XHJcblx0XHRcdFx0Y3VycmVudFRvbmVtYXBwaW5nICE9PSByZW5kZXJlci50b25lTWFwcGluZyApIHtcclxuXHJcblx0XHRcdFx0Ym94TWVzaC5tYXRlcmlhbC5uZWVkc1VwZGF0ZSA9IHRydWU7XHJcblxyXG5cdFx0XHRcdGN1cnJlbnRCYWNrZ3JvdW5kID0gYmFja2dyb3VuZDtcclxuXHRcdFx0XHRjdXJyZW50QmFja2dyb3VuZFZlcnNpb24gPSBiYWNrZ3JvdW5kLnZlcnNpb247XHJcblx0XHRcdFx0Y3VycmVudFRvbmVtYXBwaW5nID0gcmVuZGVyZXIudG9uZU1hcHBpbmc7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRib3hNZXNoLmxheWVycy5lbmFibGVBbGwoKTtcclxuXHJcblx0XHRcdC8vIHB1c2ggdG8gdGhlIHByZS1zb3J0ZWQgb3BhcXVlIHJlbmRlciBsaXN0XHJcblx0XHRcdHJlbmRlckxpc3QudW5zaGlmdCggYm94TWVzaCwgYm94TWVzaC5nZW9tZXRyeSwgYm94TWVzaC5tYXRlcmlhbCwgMCwgMCwgbnVsbCApO1xyXG5cclxuXHRcdH0gZWxzZSBpZiAoIGJhY2tncm91bmQgJiYgYmFja2dyb3VuZC5pc1RleHR1cmUgKSB7XHJcblxyXG5cdFx0XHRpZiAoIHBsYW5lTWVzaCA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHRwbGFuZU1lc2ggPSBuZXcgTWVzaChcclxuXHRcdFx0XHRcdG5ldyBQbGFuZUdlb21ldHJ5KCAyLCAyICksXHJcblx0XHRcdFx0XHRuZXcgU2hhZGVyTWF0ZXJpYWwoIHtcclxuXHRcdFx0XHRcdFx0bmFtZTogJ0JhY2tncm91bmRNYXRlcmlhbCcsXHJcblx0XHRcdFx0XHRcdHVuaWZvcm1zOiBjbG9uZVVuaWZvcm1zKCBTaGFkZXJMaWIuYmFja2dyb3VuZC51bmlmb3JtcyApLFxyXG5cdFx0XHRcdFx0XHR2ZXJ0ZXhTaGFkZXI6IFNoYWRlckxpYi5iYWNrZ3JvdW5kLnZlcnRleFNoYWRlcixcclxuXHRcdFx0XHRcdFx0ZnJhZ21lbnRTaGFkZXI6IFNoYWRlckxpYi5iYWNrZ3JvdW5kLmZyYWdtZW50U2hhZGVyLFxyXG5cdFx0XHRcdFx0XHRzaWRlOiBGcm9udFNpZGUsXHJcblx0XHRcdFx0XHRcdGRlcHRoVGVzdDogZmFsc2UsXHJcblx0XHRcdFx0XHRcdGRlcHRoV3JpdGU6IGZhbHNlLFxyXG5cdFx0XHRcdFx0XHRmb2c6IGZhbHNlXHJcblx0XHRcdFx0XHR9IClcclxuXHRcdFx0XHQpO1xyXG5cclxuXHRcdFx0XHRwbGFuZU1lc2guZ2VvbWV0cnkuZGVsZXRlQXR0cmlidXRlKCAnbm9ybWFsJyApO1xyXG5cclxuXHRcdFx0XHQvLyBhZGQgXCJtYXBcIiBtYXRlcmlhbCBwcm9wZXJ0eSBzbyB0aGUgcmVuZGVyZXIgY2FuIGV2YWx1YXRlIGl0IGxpa2UgZm9yIGJ1aWx0LWluIG1hdGVyaWFsc1xyXG5cdFx0XHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eSggcGxhbmVNZXNoLm1hdGVyaWFsLCAnbWFwJywge1xyXG5cclxuXHRcdFx0XHRcdGdldDogZnVuY3Rpb24gKCkge1xyXG5cclxuXHRcdFx0XHRcdFx0cmV0dXJuIHRoaXMudW5pZm9ybXMudDJELnZhbHVlO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fSApO1xyXG5cclxuXHRcdFx0XHRvYmplY3RzLnVwZGF0ZSggcGxhbmVNZXNoICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRwbGFuZU1lc2gubWF0ZXJpYWwudW5pZm9ybXMudDJELnZhbHVlID0gYmFja2dyb3VuZDtcclxuXHRcdFx0cGxhbmVNZXNoLm1hdGVyaWFsLnVuaWZvcm1zLmJhY2tncm91bmRJbnRlbnNpdHkudmFsdWUgPSBzY2VuZS5iYWNrZ3JvdW5kSW50ZW5zaXR5O1xyXG5cdFx0XHRwbGFuZU1lc2gubWF0ZXJpYWwudG9uZU1hcHBlZCA9IENvbG9yTWFuYWdlbWVudC5nZXRUcmFuc2ZlciggYmFja2dyb3VuZC5jb2xvclNwYWNlICkgIT09IFNSR0JUcmFuc2ZlcjtcclxuXHJcblx0XHRcdGlmICggYmFja2dyb3VuZC5tYXRyaXhBdXRvVXBkYXRlID09PSB0cnVlICkge1xyXG5cclxuXHRcdFx0XHRiYWNrZ3JvdW5kLnVwZGF0ZU1hdHJpeCgpO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0cGxhbmVNZXNoLm1hdGVyaWFsLnVuaWZvcm1zLnV2VHJhbnNmb3JtLnZhbHVlLmNvcHkoIGJhY2tncm91bmQubWF0cml4ICk7XHJcblxyXG5cdFx0XHRpZiAoIGN1cnJlbnRCYWNrZ3JvdW5kICE9PSBiYWNrZ3JvdW5kIHx8XHJcblx0XHRcdFx0Y3VycmVudEJhY2tncm91bmRWZXJzaW9uICE9PSBiYWNrZ3JvdW5kLnZlcnNpb24gfHxcclxuXHRcdFx0XHRjdXJyZW50VG9uZW1hcHBpbmcgIT09IHJlbmRlcmVyLnRvbmVNYXBwaW5nICkge1xyXG5cclxuXHRcdFx0XHRwbGFuZU1lc2gubWF0ZXJpYWwubmVlZHNVcGRhdGUgPSB0cnVlO1xyXG5cclxuXHRcdFx0XHRjdXJyZW50QmFja2dyb3VuZCA9IGJhY2tncm91bmQ7XHJcblx0XHRcdFx0Y3VycmVudEJhY2tncm91bmRWZXJzaW9uID0gYmFja2dyb3VuZC52ZXJzaW9uO1xyXG5cdFx0XHRcdGN1cnJlbnRUb25lbWFwcGluZyA9IHJlbmRlcmVyLnRvbmVNYXBwaW5nO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0cGxhbmVNZXNoLmxheWVycy5lbmFibGVBbGwoKTtcclxuXHJcblx0XHRcdC8vIHB1c2ggdG8gdGhlIHByZS1zb3J0ZWQgb3BhcXVlIHJlbmRlciBsaXN0XHJcblx0XHRcdHJlbmRlckxpc3QudW5zaGlmdCggcGxhbmVNZXNoLCBwbGFuZU1lc2guZ2VvbWV0cnksIHBsYW5lTWVzaC5tYXRlcmlhbCwgMCwgMCwgbnVsbCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBzZXRDbGVhciggY29sb3IsIGFscGhhICkge1xyXG5cclxuXHRcdGNvbG9yLmdldFJHQiggX3JnYiwgZ2V0VW5saXRVbmlmb3JtQ29sb3JTcGFjZSggcmVuZGVyZXIgKSApO1xyXG5cclxuXHRcdHN0YXRlLmJ1ZmZlcnMuY29sb3Iuc2V0Q2xlYXIoIF9yZ2IuciwgX3JnYi5nLCBfcmdiLmIsIGFscGhhLCBwcmVtdWx0aXBsaWVkQWxwaGEgKTtcclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4ge1xyXG5cclxuXHRcdGdldENsZWFyQ29sb3I6IGZ1bmN0aW9uICgpIHtcclxuXHJcblx0XHRcdHJldHVybiBjbGVhckNvbG9yO1xyXG5cclxuXHRcdH0sXHJcblx0XHRzZXRDbGVhckNvbG9yOiBmdW5jdGlvbiAoIGNvbG9yLCBhbHBoYSA9IDEgKSB7XHJcblxyXG5cdFx0XHRjbGVhckNvbG9yLnNldCggY29sb3IgKTtcclxuXHRcdFx0Y2xlYXJBbHBoYSA9IGFscGhhO1xyXG5cdFx0XHRzZXRDbGVhciggY2xlYXJDb2xvciwgY2xlYXJBbHBoYSApO1xyXG5cclxuXHRcdH0sXHJcblx0XHRnZXRDbGVhckFscGhhOiBmdW5jdGlvbiAoKSB7XHJcblxyXG5cdFx0XHRyZXR1cm4gY2xlYXJBbHBoYTtcclxuXHJcblx0XHR9LFxyXG5cdFx0c2V0Q2xlYXJBbHBoYTogZnVuY3Rpb24gKCBhbHBoYSApIHtcclxuXHJcblx0XHRcdGNsZWFyQWxwaGEgPSBhbHBoYTtcclxuXHRcdFx0c2V0Q2xlYXIoIGNsZWFyQ29sb3IsIGNsZWFyQWxwaGEgKTtcclxuXHJcblx0XHR9LFxyXG5cdFx0cmVuZGVyOiByZW5kZXJcclxuXHJcblx0fTtcclxuXHJcbn1cclxuXHJcblxyXG5leHBvcnQgeyBXZWJHTEJhY2tncm91bmQgfTtcclxuIiwiaW1wb3J0IHsgSW50VHlwZSB9IGZyb20gJy4uLy4uL2NvbnN0YW50cy5qcyc7XHJcblxyXG5mdW5jdGlvbiBXZWJHTEJpbmRpbmdTdGF0ZXMoIGdsLCBleHRlbnNpb25zLCBhdHRyaWJ1dGVzLCBjYXBhYmlsaXRpZXMgKSB7XHJcblxyXG5cdGNvbnN0IG1heFZlcnRleEF0dHJpYnV0ZXMgPSBnbC5nZXRQYXJhbWV0ZXIoIGdsLk1BWF9WRVJURVhfQVRUUklCUyApO1xyXG5cclxuXHRjb25zdCBleHRlbnNpb24gPSBjYXBhYmlsaXRpZXMuaXNXZWJHTDIgPyBudWxsIDogZXh0ZW5zaW9ucy5nZXQoICdPRVNfdmVydGV4X2FycmF5X29iamVjdCcgKTtcclxuXHRjb25zdCB2YW9BdmFpbGFibGUgPSBjYXBhYmlsaXRpZXMuaXNXZWJHTDIgfHwgZXh0ZW5zaW9uICE9PSBudWxsO1xyXG5cclxuXHRjb25zdCBiaW5kaW5nU3RhdGVzID0ge307XHJcblxyXG5cdGNvbnN0IGRlZmF1bHRTdGF0ZSA9IGNyZWF0ZUJpbmRpbmdTdGF0ZSggbnVsbCApO1xyXG5cdGxldCBjdXJyZW50U3RhdGUgPSBkZWZhdWx0U3RhdGU7XHJcblx0bGV0IGZvcmNlVXBkYXRlID0gZmFsc2U7XHJcblxyXG5cdGZ1bmN0aW9uIHNldHVwKCBvYmplY3QsIG1hdGVyaWFsLCBwcm9ncmFtLCBnZW9tZXRyeSwgaW5kZXggKSB7XHJcblxyXG5cdFx0bGV0IHVwZGF0ZUJ1ZmZlcnMgPSBmYWxzZTtcclxuXHJcblx0XHRpZiAoIHZhb0F2YWlsYWJsZSApIHtcclxuXHJcblx0XHRcdGNvbnN0IHN0YXRlID0gZ2V0QmluZGluZ1N0YXRlKCBnZW9tZXRyeSwgcHJvZ3JhbSwgbWF0ZXJpYWwgKTtcclxuXHJcblx0XHRcdGlmICggY3VycmVudFN0YXRlICE9PSBzdGF0ZSApIHtcclxuXHJcblx0XHRcdFx0Y3VycmVudFN0YXRlID0gc3RhdGU7XHJcblx0XHRcdFx0YmluZFZlcnRleEFycmF5T2JqZWN0KCBjdXJyZW50U3RhdGUub2JqZWN0ICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHR1cGRhdGVCdWZmZXJzID0gbmVlZHNVcGRhdGUoIG9iamVjdCwgZ2VvbWV0cnksIHByb2dyYW0sIGluZGV4ICk7XHJcblxyXG5cdFx0XHRpZiAoIHVwZGF0ZUJ1ZmZlcnMgKSBzYXZlQ2FjaGUoIG9iamVjdCwgZ2VvbWV0cnksIHByb2dyYW0sIGluZGV4ICk7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdGNvbnN0IHdpcmVmcmFtZSA9ICggbWF0ZXJpYWwud2lyZWZyYW1lID09PSB0cnVlICk7XHJcblxyXG5cdFx0XHRpZiAoIGN1cnJlbnRTdGF0ZS5nZW9tZXRyeSAhPT0gZ2VvbWV0cnkuaWQgfHxcclxuXHRcdFx0XHRjdXJyZW50U3RhdGUucHJvZ3JhbSAhPT0gcHJvZ3JhbS5pZCB8fFxyXG5cdFx0XHRcdGN1cnJlbnRTdGF0ZS53aXJlZnJhbWUgIT09IHdpcmVmcmFtZSApIHtcclxuXHJcblx0XHRcdFx0Y3VycmVudFN0YXRlLmdlb21ldHJ5ID0gZ2VvbWV0cnkuaWQ7XHJcblx0XHRcdFx0Y3VycmVudFN0YXRlLnByb2dyYW0gPSBwcm9ncmFtLmlkO1xyXG5cdFx0XHRcdGN1cnJlbnRTdGF0ZS53aXJlZnJhbWUgPSB3aXJlZnJhbWU7XHJcblxyXG5cdFx0XHRcdHVwZGF0ZUJ1ZmZlcnMgPSB0cnVlO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIGluZGV4ICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0YXR0cmlidXRlcy51cGRhdGUoIGluZGV4LCBnbC5FTEVNRU5UX0FSUkFZX0JVRkZFUiApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHVwZGF0ZUJ1ZmZlcnMgfHwgZm9yY2VVcGRhdGUgKSB7XHJcblxyXG5cdFx0XHRmb3JjZVVwZGF0ZSA9IGZhbHNlO1xyXG5cclxuXHRcdFx0c2V0dXBWZXJ0ZXhBdHRyaWJ1dGVzKCBvYmplY3QsIG1hdGVyaWFsLCBwcm9ncmFtLCBnZW9tZXRyeSApO1xyXG5cclxuXHRcdFx0aWYgKCBpbmRleCAhPT0gbnVsbCApIHtcclxuXHJcblx0XHRcdFx0Z2wuYmluZEJ1ZmZlciggZ2wuRUxFTUVOVF9BUlJBWV9CVUZGRVIsIGF0dHJpYnV0ZXMuZ2V0KCBpbmRleCApLmJ1ZmZlciApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBjcmVhdGVWZXJ0ZXhBcnJheU9iamVjdCgpIHtcclxuXHJcblx0XHRpZiAoIGNhcGFiaWxpdGllcy5pc1dlYkdMMiApIHJldHVybiBnbC5jcmVhdGVWZXJ0ZXhBcnJheSgpO1xyXG5cclxuXHRcdHJldHVybiBleHRlbnNpb24uY3JlYXRlVmVydGV4QXJyYXlPRVMoKTtcclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBiaW5kVmVydGV4QXJyYXlPYmplY3QoIHZhbyApIHtcclxuXHJcblx0XHRpZiAoIGNhcGFiaWxpdGllcy5pc1dlYkdMMiApIHJldHVybiBnbC5iaW5kVmVydGV4QXJyYXkoIHZhbyApO1xyXG5cclxuXHRcdHJldHVybiBleHRlbnNpb24uYmluZFZlcnRleEFycmF5T0VTKCB2YW8gKTtcclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBkZWxldGVWZXJ0ZXhBcnJheU9iamVjdCggdmFvICkge1xyXG5cclxuXHRcdGlmICggY2FwYWJpbGl0aWVzLmlzV2ViR0wyICkgcmV0dXJuIGdsLmRlbGV0ZVZlcnRleEFycmF5KCB2YW8gKTtcclxuXHJcblx0XHRyZXR1cm4gZXh0ZW5zaW9uLmRlbGV0ZVZlcnRleEFycmF5T0VTKCB2YW8gKTtcclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBnZXRCaW5kaW5nU3RhdGUoIGdlb21ldHJ5LCBwcm9ncmFtLCBtYXRlcmlhbCApIHtcclxuXHJcblx0XHRjb25zdCB3aXJlZnJhbWUgPSAoIG1hdGVyaWFsLndpcmVmcmFtZSA9PT0gdHJ1ZSApO1xyXG5cclxuXHRcdGxldCBwcm9ncmFtTWFwID0gYmluZGluZ1N0YXRlc1sgZ2VvbWV0cnkuaWQgXTtcclxuXHJcblx0XHRpZiAoIHByb2dyYW1NYXAgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdHByb2dyYW1NYXAgPSB7fTtcclxuXHRcdFx0YmluZGluZ1N0YXRlc1sgZ2VvbWV0cnkuaWQgXSA9IHByb2dyYW1NYXA7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGxldCBzdGF0ZU1hcCA9IHByb2dyYW1NYXBbIHByb2dyYW0uaWQgXTtcclxuXHJcblx0XHRpZiAoIHN0YXRlTWFwID09PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRzdGF0ZU1hcCA9IHt9O1xyXG5cdFx0XHRwcm9ncmFtTWFwWyBwcm9ncmFtLmlkIF0gPSBzdGF0ZU1hcDtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0bGV0IHN0YXRlID0gc3RhdGVNYXBbIHdpcmVmcmFtZSBdO1xyXG5cclxuXHRcdGlmICggc3RhdGUgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdHN0YXRlID0gY3JlYXRlQmluZGluZ1N0YXRlKCBjcmVhdGVWZXJ0ZXhBcnJheU9iamVjdCgpICk7XHJcblx0XHRcdHN0YXRlTWFwWyB3aXJlZnJhbWUgXSA9IHN0YXRlO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gc3RhdGU7XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gY3JlYXRlQmluZGluZ1N0YXRlKCB2YW8gKSB7XHJcblxyXG5cdFx0Y29uc3QgbmV3QXR0cmlidXRlcyA9IFtdO1xyXG5cdFx0Y29uc3QgZW5hYmxlZEF0dHJpYnV0ZXMgPSBbXTtcclxuXHRcdGNvbnN0IGF0dHJpYnV0ZURpdmlzb3JzID0gW107XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgbWF4VmVydGV4QXR0cmlidXRlczsgaSArKyApIHtcclxuXHJcblx0XHRcdG5ld0F0dHJpYnV0ZXNbIGkgXSA9IDA7XHJcblx0XHRcdGVuYWJsZWRBdHRyaWJ1dGVzWyBpIF0gPSAwO1xyXG5cdFx0XHRhdHRyaWJ1dGVEaXZpc29yc1sgaSBdID0gMDtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHtcclxuXHJcblx0XHRcdC8vIGZvciBiYWNrd2FyZCBjb21wYXRpYmlsaXR5IG9uIG5vbi1WQU8gc3VwcG9ydCBicm93c2VyXHJcblx0XHRcdGdlb21ldHJ5OiBudWxsLFxyXG5cdFx0XHRwcm9ncmFtOiBudWxsLFxyXG5cdFx0XHR3aXJlZnJhbWU6IGZhbHNlLFxyXG5cclxuXHRcdFx0bmV3QXR0cmlidXRlczogbmV3QXR0cmlidXRlcyxcclxuXHRcdFx0ZW5hYmxlZEF0dHJpYnV0ZXM6IGVuYWJsZWRBdHRyaWJ1dGVzLFxyXG5cdFx0XHRhdHRyaWJ1dGVEaXZpc29yczogYXR0cmlidXRlRGl2aXNvcnMsXHJcblx0XHRcdG9iamVjdDogdmFvLFxyXG5cdFx0XHRhdHRyaWJ1dGVzOiB7fSxcclxuXHRcdFx0aW5kZXg6IG51bGxcclxuXHJcblx0XHR9O1xyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIG5lZWRzVXBkYXRlKCBvYmplY3QsIGdlb21ldHJ5LCBwcm9ncmFtLCBpbmRleCApIHtcclxuXHJcblx0XHRjb25zdCBjYWNoZWRBdHRyaWJ1dGVzID0gY3VycmVudFN0YXRlLmF0dHJpYnV0ZXM7XHJcblx0XHRjb25zdCBnZW9tZXRyeUF0dHJpYnV0ZXMgPSBnZW9tZXRyeS5hdHRyaWJ1dGVzO1xyXG5cclxuXHRcdGxldCBhdHRyaWJ1dGVzTnVtID0gMDtcclxuXHJcblx0XHRjb25zdCBwcm9ncmFtQXR0cmlidXRlcyA9IHByb2dyYW0uZ2V0QXR0cmlidXRlcygpO1xyXG5cclxuXHRcdGZvciAoIGNvbnN0IG5hbWUgaW4gcHJvZ3JhbUF0dHJpYnV0ZXMgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBwcm9ncmFtQXR0cmlidXRlID0gcHJvZ3JhbUF0dHJpYnV0ZXNbIG5hbWUgXTtcclxuXHJcblx0XHRcdGlmICggcHJvZ3JhbUF0dHJpYnV0ZS5sb2NhdGlvbiA+PSAwICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBjYWNoZWRBdHRyaWJ1dGUgPSBjYWNoZWRBdHRyaWJ1dGVzWyBuYW1lIF07XHJcblx0XHRcdFx0bGV0IGdlb21ldHJ5QXR0cmlidXRlID0gZ2VvbWV0cnlBdHRyaWJ1dGVzWyBuYW1lIF07XHJcblxyXG5cdFx0XHRcdGlmICggZ2VvbWV0cnlBdHRyaWJ1dGUgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0XHRpZiAoIG5hbWUgPT09ICdpbnN0YW5jZU1hdHJpeCcgJiYgb2JqZWN0Lmluc3RhbmNlTWF0cml4ICkgZ2VvbWV0cnlBdHRyaWJ1dGUgPSBvYmplY3QuaW5zdGFuY2VNYXRyaXg7XHJcblx0XHRcdFx0XHRpZiAoIG5hbWUgPT09ICdpbnN0YW5jZUNvbG9yJyAmJiBvYmplY3QuaW5zdGFuY2VDb2xvciApIGdlb21ldHJ5QXR0cmlidXRlID0gb2JqZWN0Lmluc3RhbmNlQ29sb3I7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0aWYgKCBjYWNoZWRBdHRyaWJ1dGUgPT09IHVuZGVmaW5lZCApIHJldHVybiB0cnVlO1xyXG5cclxuXHRcdFx0XHRpZiAoIGNhY2hlZEF0dHJpYnV0ZS5hdHRyaWJ1dGUgIT09IGdlb21ldHJ5QXR0cmlidXRlICkgcmV0dXJuIHRydWU7XHJcblxyXG5cdFx0XHRcdGlmICggZ2VvbWV0cnlBdHRyaWJ1dGUgJiYgY2FjaGVkQXR0cmlidXRlLmRhdGEgIT09IGdlb21ldHJ5QXR0cmlidXRlLmRhdGEgKSByZXR1cm4gdHJ1ZTtcclxuXHJcblx0XHRcdFx0YXR0cmlidXRlc051bSArKztcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBjdXJyZW50U3RhdGUuYXR0cmlidXRlc051bSAhPT0gYXR0cmlidXRlc051bSApIHJldHVybiB0cnVlO1xyXG5cclxuXHRcdGlmICggY3VycmVudFN0YXRlLmluZGV4ICE9PSBpbmRleCApIHJldHVybiB0cnVlO1xyXG5cclxuXHRcdHJldHVybiBmYWxzZTtcclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBzYXZlQ2FjaGUoIG9iamVjdCwgZ2VvbWV0cnksIHByb2dyYW0sIGluZGV4ICkge1xyXG5cclxuXHRcdGNvbnN0IGNhY2hlID0ge307XHJcblx0XHRjb25zdCBhdHRyaWJ1dGVzID0gZ2VvbWV0cnkuYXR0cmlidXRlcztcclxuXHRcdGxldCBhdHRyaWJ1dGVzTnVtID0gMDtcclxuXHJcblx0XHRjb25zdCBwcm9ncmFtQXR0cmlidXRlcyA9IHByb2dyYW0uZ2V0QXR0cmlidXRlcygpO1xyXG5cclxuXHRcdGZvciAoIGNvbnN0IG5hbWUgaW4gcHJvZ3JhbUF0dHJpYnV0ZXMgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBwcm9ncmFtQXR0cmlidXRlID0gcHJvZ3JhbUF0dHJpYnV0ZXNbIG5hbWUgXTtcclxuXHJcblx0XHRcdGlmICggcHJvZ3JhbUF0dHJpYnV0ZS5sb2NhdGlvbiA+PSAwICkge1xyXG5cclxuXHRcdFx0XHRsZXQgYXR0cmlidXRlID0gYXR0cmlidXRlc1sgbmFtZSBdO1xyXG5cclxuXHRcdFx0XHRpZiAoIGF0dHJpYnV0ZSA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHRcdGlmICggbmFtZSA9PT0gJ2luc3RhbmNlTWF0cml4JyAmJiBvYmplY3QuaW5zdGFuY2VNYXRyaXggKSBhdHRyaWJ1dGUgPSBvYmplY3QuaW5zdGFuY2VNYXRyaXg7XHJcblx0XHRcdFx0XHRpZiAoIG5hbWUgPT09ICdpbnN0YW5jZUNvbG9yJyAmJiBvYmplY3QuaW5zdGFuY2VDb2xvciApIGF0dHJpYnV0ZSA9IG9iamVjdC5pbnN0YW5jZUNvbG9yO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdGNvbnN0IGRhdGEgPSB7fTtcclxuXHRcdFx0XHRkYXRhLmF0dHJpYnV0ZSA9IGF0dHJpYnV0ZTtcclxuXHJcblx0XHRcdFx0aWYgKCBhdHRyaWJ1dGUgJiYgYXR0cmlidXRlLmRhdGEgKSB7XHJcblxyXG5cdFx0XHRcdFx0ZGF0YS5kYXRhID0gYXR0cmlidXRlLmRhdGE7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0Y2FjaGVbIG5hbWUgXSA9IGRhdGE7XHJcblxyXG5cdFx0XHRcdGF0dHJpYnV0ZXNOdW0gKys7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGN1cnJlbnRTdGF0ZS5hdHRyaWJ1dGVzID0gY2FjaGU7XHJcblx0XHRjdXJyZW50U3RhdGUuYXR0cmlidXRlc051bSA9IGF0dHJpYnV0ZXNOdW07XHJcblxyXG5cdFx0Y3VycmVudFN0YXRlLmluZGV4ID0gaW5kZXg7XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gaW5pdEF0dHJpYnV0ZXMoKSB7XHJcblxyXG5cdFx0Y29uc3QgbmV3QXR0cmlidXRlcyA9IGN1cnJlbnRTdGF0ZS5uZXdBdHRyaWJ1dGVzO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSBuZXdBdHRyaWJ1dGVzLmxlbmd0aDsgaSA8IGlsOyBpICsrICkge1xyXG5cclxuXHRcdFx0bmV3QXR0cmlidXRlc1sgaSBdID0gMDtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gZW5hYmxlQXR0cmlidXRlKCBhdHRyaWJ1dGUgKSB7XHJcblxyXG5cdFx0ZW5hYmxlQXR0cmlidXRlQW5kRGl2aXNvciggYXR0cmlidXRlLCAwICk7XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gZW5hYmxlQXR0cmlidXRlQW5kRGl2aXNvciggYXR0cmlidXRlLCBtZXNoUGVyQXR0cmlidXRlICkge1xyXG5cclxuXHRcdGNvbnN0IG5ld0F0dHJpYnV0ZXMgPSBjdXJyZW50U3RhdGUubmV3QXR0cmlidXRlcztcclxuXHRcdGNvbnN0IGVuYWJsZWRBdHRyaWJ1dGVzID0gY3VycmVudFN0YXRlLmVuYWJsZWRBdHRyaWJ1dGVzO1xyXG5cdFx0Y29uc3QgYXR0cmlidXRlRGl2aXNvcnMgPSBjdXJyZW50U3RhdGUuYXR0cmlidXRlRGl2aXNvcnM7XHJcblxyXG5cdFx0bmV3QXR0cmlidXRlc1sgYXR0cmlidXRlIF0gPSAxO1xyXG5cclxuXHRcdGlmICggZW5hYmxlZEF0dHJpYnV0ZXNbIGF0dHJpYnV0ZSBdID09PSAwICkge1xyXG5cclxuXHRcdFx0Z2wuZW5hYmxlVmVydGV4QXR0cmliQXJyYXkoIGF0dHJpYnV0ZSApO1xyXG5cdFx0XHRlbmFibGVkQXR0cmlidXRlc1sgYXR0cmlidXRlIF0gPSAxO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIGF0dHJpYnV0ZURpdmlzb3JzWyBhdHRyaWJ1dGUgXSAhPT0gbWVzaFBlckF0dHJpYnV0ZSApIHtcclxuXHJcblx0XHRcdGNvbnN0IGV4dGVuc2lvbiA9IGNhcGFiaWxpdGllcy5pc1dlYkdMMiA/IGdsIDogZXh0ZW5zaW9ucy5nZXQoICdBTkdMRV9pbnN0YW5jZWRfYXJyYXlzJyApO1xyXG5cclxuXHRcdFx0ZXh0ZW5zaW9uWyBjYXBhYmlsaXRpZXMuaXNXZWJHTDIgPyAndmVydGV4QXR0cmliRGl2aXNvcicgOiAndmVydGV4QXR0cmliRGl2aXNvckFOR0xFJyBdKCBhdHRyaWJ1dGUsIG1lc2hQZXJBdHRyaWJ1dGUgKTtcclxuXHRcdFx0YXR0cmlidXRlRGl2aXNvcnNbIGF0dHJpYnV0ZSBdID0gbWVzaFBlckF0dHJpYnV0ZTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gZGlzYWJsZVVudXNlZEF0dHJpYnV0ZXMoKSB7XHJcblxyXG5cdFx0Y29uc3QgbmV3QXR0cmlidXRlcyA9IGN1cnJlbnRTdGF0ZS5uZXdBdHRyaWJ1dGVzO1xyXG5cdFx0Y29uc3QgZW5hYmxlZEF0dHJpYnV0ZXMgPSBjdXJyZW50U3RhdGUuZW5hYmxlZEF0dHJpYnV0ZXM7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBpbCA9IGVuYWJsZWRBdHRyaWJ1dGVzLmxlbmd0aDsgaSA8IGlsOyBpICsrICkge1xyXG5cclxuXHRcdFx0aWYgKCBlbmFibGVkQXR0cmlidXRlc1sgaSBdICE9PSBuZXdBdHRyaWJ1dGVzWyBpIF0gKSB7XHJcblxyXG5cdFx0XHRcdGdsLmRpc2FibGVWZXJ0ZXhBdHRyaWJBcnJheSggaSApO1xyXG5cdFx0XHRcdGVuYWJsZWRBdHRyaWJ1dGVzWyBpIF0gPSAwO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiB2ZXJ0ZXhBdHRyaWJQb2ludGVyKCBpbmRleCwgc2l6ZSwgdHlwZSwgbm9ybWFsaXplZCwgc3RyaWRlLCBvZmZzZXQsIGludGVnZXIgKSB7XHJcblxyXG5cdFx0aWYgKCBpbnRlZ2VyID09PSB0cnVlICkge1xyXG5cclxuXHRcdFx0Z2wudmVydGV4QXR0cmliSVBvaW50ZXIoIGluZGV4LCBzaXplLCB0eXBlLCBzdHJpZGUsIG9mZnNldCApO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRnbC52ZXJ0ZXhBdHRyaWJQb2ludGVyKCBpbmRleCwgc2l6ZSwgdHlwZSwgbm9ybWFsaXplZCwgc3RyaWRlLCBvZmZzZXQgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gc2V0dXBWZXJ0ZXhBdHRyaWJ1dGVzKCBvYmplY3QsIG1hdGVyaWFsLCBwcm9ncmFtLCBnZW9tZXRyeSApIHtcclxuXHJcblx0XHRpZiAoIGNhcGFiaWxpdGllcy5pc1dlYkdMMiA9PT0gZmFsc2UgJiYgKCBvYmplY3QuaXNJbnN0YW5jZWRNZXNoIHx8IGdlb21ldHJ5LmlzSW5zdGFuY2VkQnVmZmVyR2VvbWV0cnkgKSApIHtcclxuXHJcblx0XHRcdGlmICggZXh0ZW5zaW9ucy5nZXQoICdBTkdMRV9pbnN0YW5jZWRfYXJyYXlzJyApID09PSBudWxsICkgcmV0dXJuO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpbml0QXR0cmlidXRlcygpO1xyXG5cclxuXHRcdGNvbnN0IGdlb21ldHJ5QXR0cmlidXRlcyA9IGdlb21ldHJ5LmF0dHJpYnV0ZXM7XHJcblxyXG5cdFx0Y29uc3QgcHJvZ3JhbUF0dHJpYnV0ZXMgPSBwcm9ncmFtLmdldEF0dHJpYnV0ZXMoKTtcclxuXHJcblx0XHRjb25zdCBtYXRlcmlhbERlZmF1bHRBdHRyaWJ1dGVWYWx1ZXMgPSBtYXRlcmlhbC5kZWZhdWx0QXR0cmlidXRlVmFsdWVzO1xyXG5cclxuXHRcdGZvciAoIGNvbnN0IG5hbWUgaW4gcHJvZ3JhbUF0dHJpYnV0ZXMgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBwcm9ncmFtQXR0cmlidXRlID0gcHJvZ3JhbUF0dHJpYnV0ZXNbIG5hbWUgXTtcclxuXHJcblx0XHRcdGlmICggcHJvZ3JhbUF0dHJpYnV0ZS5sb2NhdGlvbiA+PSAwICkge1xyXG5cclxuXHRcdFx0XHRsZXQgZ2VvbWV0cnlBdHRyaWJ1dGUgPSBnZW9tZXRyeUF0dHJpYnV0ZXNbIG5hbWUgXTtcclxuXHJcblx0XHRcdFx0aWYgKCBnZW9tZXRyeUF0dHJpYnV0ZSA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHRcdGlmICggbmFtZSA9PT0gJ2luc3RhbmNlTWF0cml4JyAmJiBvYmplY3QuaW5zdGFuY2VNYXRyaXggKSBnZW9tZXRyeUF0dHJpYnV0ZSA9IG9iamVjdC5pbnN0YW5jZU1hdHJpeDtcclxuXHRcdFx0XHRcdGlmICggbmFtZSA9PT0gJ2luc3RhbmNlQ29sb3InICYmIG9iamVjdC5pbnN0YW5jZUNvbG9yICkgZ2VvbWV0cnlBdHRyaWJ1dGUgPSBvYmplY3QuaW5zdGFuY2VDb2xvcjtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRpZiAoIGdlb21ldHJ5QXR0cmlidXRlICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y29uc3Qgbm9ybWFsaXplZCA9IGdlb21ldHJ5QXR0cmlidXRlLm5vcm1hbGl6ZWQ7XHJcblx0XHRcdFx0XHRjb25zdCBzaXplID0gZ2VvbWV0cnlBdHRyaWJ1dGUuaXRlbVNpemU7XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgYXR0cmlidXRlID0gYXR0cmlidXRlcy5nZXQoIGdlb21ldHJ5QXR0cmlidXRlICk7XHJcblxyXG5cdFx0XHRcdFx0Ly8gVE9ETyBBdHRyaWJ1dGUgbWF5IG5vdCBiZSBhdmFpbGFibGUgb24gY29udGV4dCByZXN0b3JlXHJcblxyXG5cdFx0XHRcdFx0aWYgKCBhdHRyaWJ1dGUgPT09IHVuZGVmaW5lZCApIGNvbnRpbnVlO1xyXG5cclxuXHRcdFx0XHRcdGNvbnN0IGJ1ZmZlciA9IGF0dHJpYnV0ZS5idWZmZXI7XHJcblx0XHRcdFx0XHRjb25zdCB0eXBlID0gYXR0cmlidXRlLnR5cGU7XHJcblx0XHRcdFx0XHRjb25zdCBieXRlc1BlckVsZW1lbnQgPSBhdHRyaWJ1dGUuYnl0ZXNQZXJFbGVtZW50O1xyXG5cclxuXHRcdFx0XHRcdC8vIGNoZWNrIGZvciBpbnRlZ2VyIGF0dHJpYnV0ZXMgKFdlYkdMIDIgb25seSlcclxuXHJcblx0XHRcdFx0XHRjb25zdCBpbnRlZ2VyID0gKCBjYXBhYmlsaXRpZXMuaXNXZWJHTDIgPT09IHRydWUgJiYgKCB0eXBlID09PSBnbC5JTlQgfHwgdHlwZSA9PT0gZ2wuVU5TSUdORURfSU5UIHx8IGdlb21ldHJ5QXR0cmlidXRlLmdwdVR5cGUgPT09IEludFR5cGUgKSApO1xyXG5cclxuXHRcdFx0XHRcdGlmICggZ2VvbWV0cnlBdHRyaWJ1dGUuaXNJbnRlcmxlYXZlZEJ1ZmZlckF0dHJpYnV0ZSApIHtcclxuXHJcblx0XHRcdFx0XHRcdGNvbnN0IGRhdGEgPSBnZW9tZXRyeUF0dHJpYnV0ZS5kYXRhO1xyXG5cdFx0XHRcdFx0XHRjb25zdCBzdHJpZGUgPSBkYXRhLnN0cmlkZTtcclxuXHRcdFx0XHRcdFx0Y29uc3Qgb2Zmc2V0ID0gZ2VvbWV0cnlBdHRyaWJ1dGUub2Zmc2V0O1xyXG5cclxuXHRcdFx0XHRcdFx0aWYgKCBkYXRhLmlzSW5zdGFuY2VkSW50ZXJsZWF2ZWRCdWZmZXIgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHByb2dyYW1BdHRyaWJ1dGUubG9jYXRpb25TaXplOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRcdGVuYWJsZUF0dHJpYnV0ZUFuZERpdmlzb3IoIHByb2dyYW1BdHRyaWJ1dGUubG9jYXRpb24gKyBpLCBkYXRhLm1lc2hQZXJBdHRyaWJ1dGUgKTtcclxuXHJcblx0XHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdFx0XHRpZiAoIG9iamVjdC5pc0luc3RhbmNlZE1lc2ggIT09IHRydWUgJiYgZ2VvbWV0cnkuX21heEluc3RhbmNlQ291bnQgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHRnZW9tZXRyeS5fbWF4SW5zdGFuY2VDb3VudCA9IGRhdGEubWVzaFBlckF0dHJpYnV0ZSAqIGRhdGEuY291bnQ7XHJcblxyXG5cdFx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHByb2dyYW1BdHRyaWJ1dGUubG9jYXRpb25TaXplOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRcdGVuYWJsZUF0dHJpYnV0ZSggcHJvZ3JhbUF0dHJpYnV0ZS5sb2NhdGlvbiArIGkgKTtcclxuXHJcblx0XHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdFx0Z2wuYmluZEJ1ZmZlciggZ2wuQVJSQVlfQlVGRkVSLCBidWZmZXIgKTtcclxuXHJcblx0XHRcdFx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHByb2dyYW1BdHRyaWJ1dGUubG9jYXRpb25TaXplOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHR2ZXJ0ZXhBdHRyaWJQb2ludGVyKFxyXG5cdFx0XHRcdFx0XHRcdFx0cHJvZ3JhbUF0dHJpYnV0ZS5sb2NhdGlvbiArIGksXHJcblx0XHRcdFx0XHRcdFx0XHRzaXplIC8gcHJvZ3JhbUF0dHJpYnV0ZS5sb2NhdGlvblNpemUsXHJcblx0XHRcdFx0XHRcdFx0XHR0eXBlLFxyXG5cdFx0XHRcdFx0XHRcdFx0bm9ybWFsaXplZCxcclxuXHRcdFx0XHRcdFx0XHRcdHN0cmlkZSAqIGJ5dGVzUGVyRWxlbWVudCxcclxuXHRcdFx0XHRcdFx0XHRcdCggb2Zmc2V0ICsgKCBzaXplIC8gcHJvZ3JhbUF0dHJpYnV0ZS5sb2NhdGlvblNpemUgKSAqIGkgKSAqIGJ5dGVzUGVyRWxlbWVudCxcclxuXHRcdFx0XHRcdFx0XHRcdGludGVnZXJcclxuXHRcdFx0XHRcdFx0XHQpO1xyXG5cclxuXHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHRpZiAoIGdlb21ldHJ5QXR0cmlidXRlLmlzSW5zdGFuY2VkQnVmZmVyQXR0cmlidXRlICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBwcm9ncmFtQXR0cmlidXRlLmxvY2F0aW9uU2l6ZTsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHRlbmFibGVBdHRyaWJ1dGVBbmREaXZpc29yKCBwcm9ncmFtQXR0cmlidXRlLmxvY2F0aW9uICsgaSwgZ2VvbWV0cnlBdHRyaWJ1dGUubWVzaFBlckF0dHJpYnV0ZSApO1xyXG5cclxuXHRcdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0XHRcdGlmICggb2JqZWN0LmlzSW5zdGFuY2VkTWVzaCAhPT0gdHJ1ZSAmJiBnZW9tZXRyeS5fbWF4SW5zdGFuY2VDb3VudCA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRcdGdlb21ldHJ5Ll9tYXhJbnN0YW5jZUNvdW50ID0gZ2VvbWV0cnlBdHRyaWJ1dGUubWVzaFBlckF0dHJpYnV0ZSAqIGdlb21ldHJ5QXR0cmlidXRlLmNvdW50O1xyXG5cclxuXHRcdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBwcm9ncmFtQXR0cmlidXRlLmxvY2F0aW9uU2l6ZTsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHRlbmFibGVBdHRyaWJ1dGUoIHByb2dyYW1BdHRyaWJ1dGUubG9jYXRpb24gKyBpICk7XHJcblxyXG5cdFx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRcdGdsLmJpbmRCdWZmZXIoIGdsLkFSUkFZX0JVRkZFUiwgYnVmZmVyICk7XHJcblxyXG5cdFx0XHRcdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBwcm9ncmFtQXR0cmlidXRlLmxvY2F0aW9uU2l6ZTsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0dmVydGV4QXR0cmliUG9pbnRlcihcclxuXHRcdFx0XHRcdFx0XHRcdHByb2dyYW1BdHRyaWJ1dGUubG9jYXRpb24gKyBpLFxyXG5cdFx0XHRcdFx0XHRcdFx0c2l6ZSAvIHByb2dyYW1BdHRyaWJ1dGUubG9jYXRpb25TaXplLFxyXG5cdFx0XHRcdFx0XHRcdFx0dHlwZSxcclxuXHRcdFx0XHRcdFx0XHRcdG5vcm1hbGl6ZWQsXHJcblx0XHRcdFx0XHRcdFx0XHRzaXplICogYnl0ZXNQZXJFbGVtZW50LFxyXG5cdFx0XHRcdFx0XHRcdFx0KCBzaXplIC8gcHJvZ3JhbUF0dHJpYnV0ZS5sb2NhdGlvblNpemUgKSAqIGkgKiBieXRlc1BlckVsZW1lbnQsXHJcblx0XHRcdFx0XHRcdFx0XHRpbnRlZ2VyXHJcblx0XHRcdFx0XHRcdFx0KTtcclxuXHJcblx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH0gZWxzZSBpZiAoIG1hdGVyaWFsRGVmYXVsdEF0dHJpYnV0ZVZhbHVlcyAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHRcdGNvbnN0IHZhbHVlID0gbWF0ZXJpYWxEZWZhdWx0QXR0cmlidXRlVmFsdWVzWyBuYW1lIF07XHJcblxyXG5cdFx0XHRcdFx0aWYgKCB2YWx1ZSAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHRcdFx0c3dpdGNoICggdmFsdWUubGVuZ3RoICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRjYXNlIDI6XHJcblx0XHRcdFx0XHRcdFx0XHRnbC52ZXJ0ZXhBdHRyaWIyZnYoIHByb2dyYW1BdHRyaWJ1dGUubG9jYXRpb24sIHZhbHVlICk7XHJcblx0XHRcdFx0XHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdFx0XHRcdFx0Y2FzZSAzOlxyXG5cdFx0XHRcdFx0XHRcdFx0Z2wudmVydGV4QXR0cmliM2Z2KCBwcm9ncmFtQXR0cmlidXRlLmxvY2F0aW9uLCB2YWx1ZSApO1xyXG5cdFx0XHRcdFx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRcdFx0XHRcdGNhc2UgNDpcclxuXHRcdFx0XHRcdFx0XHRcdGdsLnZlcnRleEF0dHJpYjRmdiggcHJvZ3JhbUF0dHJpYnV0ZS5sb2NhdGlvbiwgdmFsdWUgKTtcclxuXHRcdFx0XHRcdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0XHRcdFx0XHRkZWZhdWx0OlxyXG5cdFx0XHRcdFx0XHRcdFx0Z2wudmVydGV4QXR0cmliMWZ2KCBwcm9ncmFtQXR0cmlidXRlLmxvY2F0aW9uLCB2YWx1ZSApO1xyXG5cclxuXHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRkaXNhYmxlVW51c2VkQXR0cmlidXRlcygpO1xyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIGRpc3Bvc2UoKSB7XHJcblxyXG5cdFx0cmVzZXQoKTtcclxuXHJcblx0XHRmb3IgKCBjb25zdCBnZW9tZXRyeUlkIGluIGJpbmRpbmdTdGF0ZXMgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBwcm9ncmFtTWFwID0gYmluZGluZ1N0YXRlc1sgZ2VvbWV0cnlJZCBdO1xyXG5cclxuXHRcdFx0Zm9yICggY29uc3QgcHJvZ3JhbUlkIGluIHByb2dyYW1NYXAgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IHN0YXRlTWFwID0gcHJvZ3JhbU1hcFsgcHJvZ3JhbUlkIF07XHJcblxyXG5cdFx0XHRcdGZvciAoIGNvbnN0IHdpcmVmcmFtZSBpbiBzdGF0ZU1hcCApIHtcclxuXHJcblx0XHRcdFx0XHRkZWxldGVWZXJ0ZXhBcnJheU9iamVjdCggc3RhdGVNYXBbIHdpcmVmcmFtZSBdLm9iamVjdCApO1xyXG5cclxuXHRcdFx0XHRcdGRlbGV0ZSBzdGF0ZU1hcFsgd2lyZWZyYW1lIF07XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0ZGVsZXRlIHByb2dyYW1NYXBbIHByb2dyYW1JZCBdO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0ZGVsZXRlIGJpbmRpbmdTdGF0ZXNbIGdlb21ldHJ5SWQgXTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gcmVsZWFzZVN0YXRlc09mR2VvbWV0cnkoIGdlb21ldHJ5ICkge1xyXG5cclxuXHRcdGlmICggYmluZGluZ1N0YXRlc1sgZ2VvbWV0cnkuaWQgXSA9PT0gdW5kZWZpbmVkICkgcmV0dXJuO1xyXG5cclxuXHRcdGNvbnN0IHByb2dyYW1NYXAgPSBiaW5kaW5nU3RhdGVzWyBnZW9tZXRyeS5pZCBdO1xyXG5cclxuXHRcdGZvciAoIGNvbnN0IHByb2dyYW1JZCBpbiBwcm9ncmFtTWFwICkge1xyXG5cclxuXHRcdFx0Y29uc3Qgc3RhdGVNYXAgPSBwcm9ncmFtTWFwWyBwcm9ncmFtSWQgXTtcclxuXHJcblx0XHRcdGZvciAoIGNvbnN0IHdpcmVmcmFtZSBpbiBzdGF0ZU1hcCApIHtcclxuXHJcblx0XHRcdFx0ZGVsZXRlVmVydGV4QXJyYXlPYmplY3QoIHN0YXRlTWFwWyB3aXJlZnJhbWUgXS5vYmplY3QgKTtcclxuXHJcblx0XHRcdFx0ZGVsZXRlIHN0YXRlTWFwWyB3aXJlZnJhbWUgXTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGRlbGV0ZSBwcm9ncmFtTWFwWyBwcm9ncmFtSWQgXTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0ZGVsZXRlIGJpbmRpbmdTdGF0ZXNbIGdlb21ldHJ5LmlkIF07XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gcmVsZWFzZVN0YXRlc09mUHJvZ3JhbSggcHJvZ3JhbSApIHtcclxuXHJcblx0XHRmb3IgKCBjb25zdCBnZW9tZXRyeUlkIGluIGJpbmRpbmdTdGF0ZXMgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBwcm9ncmFtTWFwID0gYmluZGluZ1N0YXRlc1sgZ2VvbWV0cnlJZCBdO1xyXG5cclxuXHRcdFx0aWYgKCBwcm9ncmFtTWFwWyBwcm9ncmFtLmlkIF0gPT09IHVuZGVmaW5lZCApIGNvbnRpbnVlO1xyXG5cclxuXHRcdFx0Y29uc3Qgc3RhdGVNYXAgPSBwcm9ncmFtTWFwWyBwcm9ncmFtLmlkIF07XHJcblxyXG5cdFx0XHRmb3IgKCBjb25zdCB3aXJlZnJhbWUgaW4gc3RhdGVNYXAgKSB7XHJcblxyXG5cdFx0XHRcdGRlbGV0ZVZlcnRleEFycmF5T2JqZWN0KCBzdGF0ZU1hcFsgd2lyZWZyYW1lIF0ub2JqZWN0ICk7XHJcblxyXG5cdFx0XHRcdGRlbGV0ZSBzdGF0ZU1hcFsgd2lyZWZyYW1lIF07XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRkZWxldGUgcHJvZ3JhbU1hcFsgcHJvZ3JhbS5pZCBdO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiByZXNldCgpIHtcclxuXHJcblx0XHRyZXNldERlZmF1bHRTdGF0ZSgpO1xyXG5cdFx0Zm9yY2VVcGRhdGUgPSB0cnVlO1xyXG5cclxuXHRcdGlmICggY3VycmVudFN0YXRlID09PSBkZWZhdWx0U3RhdGUgKSByZXR1cm47XHJcblxyXG5cdFx0Y3VycmVudFN0YXRlID0gZGVmYXVsdFN0YXRlO1xyXG5cdFx0YmluZFZlcnRleEFycmF5T2JqZWN0KCBjdXJyZW50U3RhdGUub2JqZWN0ICk7XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gZm9yIGJhY2t3YXJkLWNvbXBhdGliaWxpdHlcclxuXHJcblx0ZnVuY3Rpb24gcmVzZXREZWZhdWx0U3RhdGUoKSB7XHJcblxyXG5cdFx0ZGVmYXVsdFN0YXRlLmdlb21ldHJ5ID0gbnVsbDtcclxuXHRcdGRlZmF1bHRTdGF0ZS5wcm9ncmFtID0gbnVsbDtcclxuXHRcdGRlZmF1bHRTdGF0ZS53aXJlZnJhbWUgPSBmYWxzZTtcclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4ge1xyXG5cclxuXHRcdHNldHVwOiBzZXR1cCxcclxuXHRcdHJlc2V0OiByZXNldCxcclxuXHRcdHJlc2V0RGVmYXVsdFN0YXRlOiByZXNldERlZmF1bHRTdGF0ZSxcclxuXHRcdGRpc3Bvc2U6IGRpc3Bvc2UsXHJcblx0XHRyZWxlYXNlU3RhdGVzT2ZHZW9tZXRyeTogcmVsZWFzZVN0YXRlc09mR2VvbWV0cnksXHJcblx0XHRyZWxlYXNlU3RhdGVzT2ZQcm9ncmFtOiByZWxlYXNlU3RhdGVzT2ZQcm9ncmFtLFxyXG5cclxuXHRcdGluaXRBdHRyaWJ1dGVzOiBpbml0QXR0cmlidXRlcyxcclxuXHRcdGVuYWJsZUF0dHJpYnV0ZTogZW5hYmxlQXR0cmlidXRlLFxyXG5cdFx0ZGlzYWJsZVVudXNlZEF0dHJpYnV0ZXM6IGRpc2FibGVVbnVzZWRBdHRyaWJ1dGVzXHJcblxyXG5cdH07XHJcblxyXG59XHJcblxyXG5cclxuZXhwb3J0IHsgV2ViR0xCaW5kaW5nU3RhdGVzIH07XHJcbiIsImZ1bmN0aW9uIFdlYkdMQnVmZmVyUmVuZGVyZXIoIGdsLCBleHRlbnNpb25zLCBpbmZvLCBjYXBhYmlsaXRpZXMgKSB7XHJcblxyXG5cdGNvbnN0IGlzV2ViR0wyID0gY2FwYWJpbGl0aWVzLmlzV2ViR0wyO1xyXG5cclxuXHRsZXQgbW9kZTtcclxuXHJcblx0ZnVuY3Rpb24gc2V0TW9kZSggdmFsdWUgKSB7XHJcblxyXG5cdFx0bW9kZSA9IHZhbHVlO1xyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHJlbmRlciggc3RhcnQsIGNvdW50ICkge1xyXG5cclxuXHRcdGdsLmRyYXdBcnJheXMoIG1vZGUsIHN0YXJ0LCBjb3VudCApO1xyXG5cclxuXHRcdGluZm8udXBkYXRlKCBjb3VudCwgbW9kZSwgMSApO1xyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHJlbmRlckluc3RhbmNlcyggc3RhcnQsIGNvdW50LCBwcmltY291bnQgKSB7XHJcblxyXG5cdFx0aWYgKCBwcmltY291bnQgPT09IDAgKSByZXR1cm47XHJcblxyXG5cdFx0bGV0IGV4dGVuc2lvbiwgbWV0aG9kTmFtZTtcclxuXHJcblx0XHRpZiAoIGlzV2ViR0wyICkge1xyXG5cclxuXHRcdFx0ZXh0ZW5zaW9uID0gZ2w7XHJcblx0XHRcdG1ldGhvZE5hbWUgPSAnZHJhd0FycmF5c0luc3RhbmNlZCc7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdGV4dGVuc2lvbiA9IGV4dGVuc2lvbnMuZ2V0KCAnQU5HTEVfaW5zdGFuY2VkX2FycmF5cycgKTtcclxuXHRcdFx0bWV0aG9kTmFtZSA9ICdkcmF3QXJyYXlzSW5zdGFuY2VkQU5HTEUnO1xyXG5cclxuXHRcdFx0aWYgKCBleHRlbnNpb24gPT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5XZWJHTEJ1ZmZlclJlbmRlcmVyOiB1c2luZyBUSFJFRS5JbnN0YW5jZWRCdWZmZXJHZW9tZXRyeSBidXQgaGFyZHdhcmUgZG9lcyBub3Qgc3VwcG9ydCBleHRlbnNpb24gQU5HTEVfaW5zdGFuY2VkX2FycmF5cy4nICk7XHJcblx0XHRcdFx0cmV0dXJuO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRleHRlbnNpb25bIG1ldGhvZE5hbWUgXSggbW9kZSwgc3RhcnQsIGNvdW50LCBwcmltY291bnQgKTtcclxuXHJcblx0XHRpbmZvLnVwZGF0ZSggY291bnQsIG1vZGUsIHByaW1jb3VudCApO1xyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHJlbmRlck11bHRpRHJhdyggc3RhcnRzLCBjb3VudHMsIGRyYXdDb3VudCApIHtcclxuXHJcblx0XHRpZiAoIGRyYXdDb3VudCA9PT0gMCApIHJldHVybjtcclxuXHJcblx0XHRjb25zdCBleHRlbnNpb24gPSBleHRlbnNpb25zLmdldCggJ1dFQkdMX211bHRpX2RyYXcnICk7XHJcblx0XHRpZiAoIGV4dGVuc2lvbiA9PT0gbnVsbCApIHtcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IGRyYXdDb3VudDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0dGhpcy5yZW5kZXIoIHN0YXJ0c1sgaSBdLCBjb3VudHNbIGkgXSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRleHRlbnNpb24ubXVsdGlEcmF3QXJyYXlzV0VCR0woIG1vZGUsIHN0YXJ0cywgMCwgY291bnRzLCAwLCBkcmF3Q291bnQgKTtcclxuXHJcblx0XHRcdGxldCBlbGVtZW50Q291bnQgPSAwO1xyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBkcmF3Q291bnQ7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdGVsZW1lbnRDb3VudCArPSBjb3VudHNbIGkgXTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGluZm8udXBkYXRlKCBlbGVtZW50Q291bnQsIG1vZGUsIDEgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0Ly9cclxuXHJcblx0dGhpcy5zZXRNb2RlID0gc2V0TW9kZTtcclxuXHR0aGlzLnJlbmRlciA9IHJlbmRlcjtcclxuXHR0aGlzLnJlbmRlckluc3RhbmNlcyA9IHJlbmRlckluc3RhbmNlcztcclxuXHR0aGlzLnJlbmRlck11bHRpRHJhdyA9IHJlbmRlck11bHRpRHJhdztcclxuXHJcbn1cclxuXHJcblxyXG5leHBvcnQgeyBXZWJHTEJ1ZmZlclJlbmRlcmVyIH07XHJcbiIsImZ1bmN0aW9uIFdlYkdMQ2FwYWJpbGl0aWVzKCBnbCwgZXh0ZW5zaW9ucywgcGFyYW1ldGVycyApIHtcclxuXHJcblx0bGV0IG1heEFuaXNvdHJvcHk7XHJcblxyXG5cdGZ1bmN0aW9uIGdldE1heEFuaXNvdHJvcHkoKSB7XHJcblxyXG5cdFx0aWYgKCBtYXhBbmlzb3Ryb3B5ICE9PSB1bmRlZmluZWQgKSByZXR1cm4gbWF4QW5pc290cm9weTtcclxuXHJcblx0XHRpZiAoIGV4dGVuc2lvbnMuaGFzKCAnRVhUX3RleHR1cmVfZmlsdGVyX2FuaXNvdHJvcGljJyApID09PSB0cnVlICkge1xyXG5cclxuXHRcdFx0Y29uc3QgZXh0ZW5zaW9uID0gZXh0ZW5zaW9ucy5nZXQoICdFWFRfdGV4dHVyZV9maWx0ZXJfYW5pc290cm9waWMnICk7XHJcblxyXG5cdFx0XHRtYXhBbmlzb3Ryb3B5ID0gZ2wuZ2V0UGFyYW1ldGVyKCBleHRlbnNpb24uTUFYX1RFWFRVUkVfTUFYX0FOSVNPVFJPUFlfRVhUICk7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdG1heEFuaXNvdHJvcHkgPSAwO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gbWF4QW5pc290cm9weTtcclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBnZXRNYXhQcmVjaXNpb24oIHByZWNpc2lvbiApIHtcclxuXHJcblx0XHRpZiAoIHByZWNpc2lvbiA9PT0gJ2hpZ2hwJyApIHtcclxuXHJcblx0XHRcdGlmICggZ2wuZ2V0U2hhZGVyUHJlY2lzaW9uRm9ybWF0KCBnbC5WRVJURVhfU0hBREVSLCBnbC5ISUdIX0ZMT0FUICkucHJlY2lzaW9uID4gMCAmJlxyXG5cdFx0XHRcdGdsLmdldFNoYWRlclByZWNpc2lvbkZvcm1hdCggZ2wuRlJBR01FTlRfU0hBREVSLCBnbC5ISUdIX0ZMT0FUICkucHJlY2lzaW9uID4gMCApIHtcclxuXHJcblx0XHRcdFx0cmV0dXJuICdoaWdocCc7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRwcmVjaXNpb24gPSAnbWVkaXVtcCc7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggcHJlY2lzaW9uID09PSAnbWVkaXVtcCcgKSB7XHJcblxyXG5cdFx0XHRpZiAoIGdsLmdldFNoYWRlclByZWNpc2lvbkZvcm1hdCggZ2wuVkVSVEVYX1NIQURFUiwgZ2wuTUVESVVNX0ZMT0FUICkucHJlY2lzaW9uID4gMCAmJlxyXG5cdFx0XHRcdGdsLmdldFNoYWRlclByZWNpc2lvbkZvcm1hdCggZ2wuRlJBR01FTlRfU0hBREVSLCBnbC5NRURJVU1fRkxPQVQgKS5wcmVjaXNpb24gPiAwICkge1xyXG5cclxuXHRcdFx0XHRyZXR1cm4gJ21lZGl1bXAnO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gJ2xvd3AnO1xyXG5cclxuXHR9XHJcblxyXG5cdGNvbnN0IGlzV2ViR0wyID0gdHlwZW9mIFdlYkdMMlJlbmRlcmluZ0NvbnRleHQgIT09ICd1bmRlZmluZWQnICYmIGdsLmNvbnN0cnVjdG9yLm5hbWUgPT09ICdXZWJHTDJSZW5kZXJpbmdDb250ZXh0JztcclxuXHJcblx0bGV0IHByZWNpc2lvbiA9IHBhcmFtZXRlcnMucHJlY2lzaW9uICE9PSB1bmRlZmluZWQgPyBwYXJhbWV0ZXJzLnByZWNpc2lvbiA6ICdoaWdocCc7XHJcblx0Y29uc3QgbWF4UHJlY2lzaW9uID0gZ2V0TWF4UHJlY2lzaW9uKCBwcmVjaXNpb24gKTtcclxuXHJcblx0aWYgKCBtYXhQcmVjaXNpb24gIT09IHByZWNpc2lvbiApIHtcclxuXHJcblx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5XZWJHTFJlbmRlcmVyOicsIHByZWNpc2lvbiwgJ25vdCBzdXBwb3J0ZWQsIHVzaW5nJywgbWF4UHJlY2lzaW9uLCAnaW5zdGVhZC4nICk7XHJcblx0XHRwcmVjaXNpb24gPSBtYXhQcmVjaXNpb247XHJcblxyXG5cdH1cclxuXHJcblx0Y29uc3QgZHJhd0J1ZmZlcnMgPSBpc1dlYkdMMiB8fCBleHRlbnNpb25zLmhhcyggJ1dFQkdMX2RyYXdfYnVmZmVycycgKTtcclxuXHJcblx0Y29uc3QgbG9nYXJpdGhtaWNEZXB0aEJ1ZmZlciA9IHBhcmFtZXRlcnMubG9nYXJpdGhtaWNEZXB0aEJ1ZmZlciA9PT0gdHJ1ZTtcclxuXHJcblx0Y29uc3QgbWF4VGV4dHVyZXMgPSBnbC5nZXRQYXJhbWV0ZXIoIGdsLk1BWF9URVhUVVJFX0lNQUdFX1VOSVRTICk7XHJcblx0Y29uc3QgbWF4VmVydGV4VGV4dHVyZXMgPSBnbC5nZXRQYXJhbWV0ZXIoIGdsLk1BWF9WRVJURVhfVEVYVFVSRV9JTUFHRV9VTklUUyApO1xyXG5cdGNvbnN0IG1heFRleHR1cmVTaXplID0gZ2wuZ2V0UGFyYW1ldGVyKCBnbC5NQVhfVEVYVFVSRV9TSVpFICk7XHJcblx0Y29uc3QgbWF4Q3ViZW1hcFNpemUgPSBnbC5nZXRQYXJhbWV0ZXIoIGdsLk1BWF9DVUJFX01BUF9URVhUVVJFX1NJWkUgKTtcclxuXHJcblx0Y29uc3QgbWF4QXR0cmlidXRlcyA9IGdsLmdldFBhcmFtZXRlciggZ2wuTUFYX1ZFUlRFWF9BVFRSSUJTICk7XHJcblx0Y29uc3QgbWF4VmVydGV4VW5pZm9ybXMgPSBnbC5nZXRQYXJhbWV0ZXIoIGdsLk1BWF9WRVJURVhfVU5JRk9STV9WRUNUT1JTICk7XHJcblx0Y29uc3QgbWF4VmFyeWluZ3MgPSBnbC5nZXRQYXJhbWV0ZXIoIGdsLk1BWF9WQVJZSU5HX1ZFQ1RPUlMgKTtcclxuXHRjb25zdCBtYXhGcmFnbWVudFVuaWZvcm1zID0gZ2wuZ2V0UGFyYW1ldGVyKCBnbC5NQVhfRlJBR01FTlRfVU5JRk9STV9WRUNUT1JTICk7XHJcblxyXG5cdGNvbnN0IHZlcnRleFRleHR1cmVzID0gbWF4VmVydGV4VGV4dHVyZXMgPiAwO1xyXG5cdGNvbnN0IGZsb2F0RnJhZ21lbnRUZXh0dXJlcyA9IGlzV2ViR0wyIHx8IGV4dGVuc2lvbnMuaGFzKCAnT0VTX3RleHR1cmVfZmxvYXQnICk7XHJcblx0Y29uc3QgZmxvYXRWZXJ0ZXhUZXh0dXJlcyA9IHZlcnRleFRleHR1cmVzICYmIGZsb2F0RnJhZ21lbnRUZXh0dXJlcztcclxuXHJcblx0Y29uc3QgbWF4U2FtcGxlcyA9IGlzV2ViR0wyID8gZ2wuZ2V0UGFyYW1ldGVyKCBnbC5NQVhfU0FNUExFUyApIDogMDtcclxuXHJcblx0cmV0dXJuIHtcclxuXHJcblx0XHRpc1dlYkdMMjogaXNXZWJHTDIsXHJcblxyXG5cdFx0ZHJhd0J1ZmZlcnM6IGRyYXdCdWZmZXJzLFxyXG5cclxuXHRcdGdldE1heEFuaXNvdHJvcHk6IGdldE1heEFuaXNvdHJvcHksXHJcblx0XHRnZXRNYXhQcmVjaXNpb246IGdldE1heFByZWNpc2lvbixcclxuXHJcblx0XHRwcmVjaXNpb246IHByZWNpc2lvbixcclxuXHRcdGxvZ2FyaXRobWljRGVwdGhCdWZmZXI6IGxvZ2FyaXRobWljRGVwdGhCdWZmZXIsXHJcblxyXG5cdFx0bWF4VGV4dHVyZXM6IG1heFRleHR1cmVzLFxyXG5cdFx0bWF4VmVydGV4VGV4dHVyZXM6IG1heFZlcnRleFRleHR1cmVzLFxyXG5cdFx0bWF4VGV4dHVyZVNpemU6IG1heFRleHR1cmVTaXplLFxyXG5cdFx0bWF4Q3ViZW1hcFNpemU6IG1heEN1YmVtYXBTaXplLFxyXG5cclxuXHRcdG1heEF0dHJpYnV0ZXM6IG1heEF0dHJpYnV0ZXMsXHJcblx0XHRtYXhWZXJ0ZXhVbmlmb3JtczogbWF4VmVydGV4VW5pZm9ybXMsXHJcblx0XHRtYXhWYXJ5aW5nczogbWF4VmFyeWluZ3MsXHJcblx0XHRtYXhGcmFnbWVudFVuaWZvcm1zOiBtYXhGcmFnbWVudFVuaWZvcm1zLFxyXG5cclxuXHRcdHZlcnRleFRleHR1cmVzOiB2ZXJ0ZXhUZXh0dXJlcyxcclxuXHRcdGZsb2F0RnJhZ21lbnRUZXh0dXJlczogZmxvYXRGcmFnbWVudFRleHR1cmVzLFxyXG5cdFx0ZmxvYXRWZXJ0ZXhUZXh0dXJlczogZmxvYXRWZXJ0ZXhUZXh0dXJlcyxcclxuXHJcblx0XHRtYXhTYW1wbGVzOiBtYXhTYW1wbGVzXHJcblxyXG5cdH07XHJcblxyXG59XHJcblxyXG5cclxuZXhwb3J0IHsgV2ViR0xDYXBhYmlsaXRpZXMgfTtcclxuIiwiaW1wb3J0IHsgTWF0cml4MyB9IGZyb20gJy4uLy4uL21hdGgvTWF0cml4My5qcyc7XHJcbmltcG9ydCB7IFBsYW5lIH0gZnJvbSAnLi4vLi4vbWF0aC9QbGFuZS5qcyc7XHJcblxyXG5mdW5jdGlvbiBXZWJHTENsaXBwaW5nKCBwcm9wZXJ0aWVzICkge1xyXG5cclxuXHRjb25zdCBzY29wZSA9IHRoaXM7XHJcblxyXG5cdGxldCBnbG9iYWxTdGF0ZSA9IG51bGwsXHJcblx0XHRudW1HbG9iYWxQbGFuZXMgPSAwLFxyXG5cdFx0bG9jYWxDbGlwcGluZ0VuYWJsZWQgPSBmYWxzZSxcclxuXHRcdHJlbmRlcmluZ1NoYWRvd3MgPSBmYWxzZTtcclxuXHJcblx0Y29uc3QgcGxhbmUgPSBuZXcgUGxhbmUoKSxcclxuXHRcdHZpZXdOb3JtYWxNYXRyaXggPSBuZXcgTWF0cml4MygpLFxyXG5cclxuXHRcdHVuaWZvcm0gPSB7IHZhbHVlOiBudWxsLCBuZWVkc1VwZGF0ZTogZmFsc2UgfTtcclxuXHJcblx0dGhpcy51bmlmb3JtID0gdW5pZm9ybTtcclxuXHR0aGlzLm51bVBsYW5lcyA9IDA7XHJcblx0dGhpcy5udW1JbnRlcnNlY3Rpb24gPSAwO1xyXG5cclxuXHR0aGlzLmluaXQgPSBmdW5jdGlvbiAoIHBsYW5lcywgZW5hYmxlTG9jYWxDbGlwcGluZyApIHtcclxuXHJcblx0XHRjb25zdCBlbmFibGVkID1cclxuXHRcdFx0cGxhbmVzLmxlbmd0aCAhPT0gMCB8fFxyXG5cdFx0XHRlbmFibGVMb2NhbENsaXBwaW5nIHx8XHJcblx0XHRcdC8vIGVuYWJsZSBzdGF0ZSBvZiBwcmV2aW91cyBmcmFtZSAtIHRoZSBjbGlwcGluZyBjb2RlIGhhcyB0b1xyXG5cdFx0XHQvLyBydW4gYW5vdGhlciBmcmFtZSBpbiBvcmRlciB0byByZXNldCB0aGUgc3RhdGU6XHJcblx0XHRcdG51bUdsb2JhbFBsYW5lcyAhPT0gMCB8fFxyXG5cdFx0XHRsb2NhbENsaXBwaW5nRW5hYmxlZDtcclxuXHJcblx0XHRsb2NhbENsaXBwaW5nRW5hYmxlZCA9IGVuYWJsZUxvY2FsQ2xpcHBpbmc7XHJcblxyXG5cdFx0bnVtR2xvYmFsUGxhbmVzID0gcGxhbmVzLmxlbmd0aDtcclxuXHJcblx0XHRyZXR1cm4gZW5hYmxlZDtcclxuXHJcblx0fTtcclxuXHJcblx0dGhpcy5iZWdpblNoYWRvd3MgPSBmdW5jdGlvbiAoKSB7XHJcblxyXG5cdFx0cmVuZGVyaW5nU2hhZG93cyA9IHRydWU7XHJcblx0XHRwcm9qZWN0UGxhbmVzKCBudWxsICk7XHJcblxyXG5cdH07XHJcblxyXG5cdHRoaXMuZW5kU2hhZG93cyA9IGZ1bmN0aW9uICgpIHtcclxuXHJcblx0XHRyZW5kZXJpbmdTaGFkb3dzID0gZmFsc2U7XHJcblxyXG5cdH07XHJcblxyXG5cdHRoaXMuc2V0R2xvYmFsU3RhdGUgPSBmdW5jdGlvbiAoIHBsYW5lcywgY2FtZXJhICkge1xyXG5cclxuXHRcdGdsb2JhbFN0YXRlID0gcHJvamVjdFBsYW5lcyggcGxhbmVzLCBjYW1lcmEsIDAgKTtcclxuXHJcblx0fTtcclxuXHJcblx0dGhpcy5zZXRTdGF0ZSA9IGZ1bmN0aW9uICggbWF0ZXJpYWwsIGNhbWVyYSwgdXNlQ2FjaGUgKSB7XHJcblxyXG5cdFx0Y29uc3QgcGxhbmVzID0gbWF0ZXJpYWwuY2xpcHBpbmdQbGFuZXMsXHJcblx0XHRcdGNsaXBJbnRlcnNlY3Rpb24gPSBtYXRlcmlhbC5jbGlwSW50ZXJzZWN0aW9uLFxyXG5cdFx0XHRjbGlwU2hhZG93cyA9IG1hdGVyaWFsLmNsaXBTaGFkb3dzO1xyXG5cclxuXHRcdGNvbnN0IG1hdGVyaWFsUHJvcGVydGllcyA9IHByb3BlcnRpZXMuZ2V0KCBtYXRlcmlhbCApO1xyXG5cclxuXHRcdGlmICggISBsb2NhbENsaXBwaW5nRW5hYmxlZCB8fCBwbGFuZXMgPT09IG51bGwgfHwgcGxhbmVzLmxlbmd0aCA9PT0gMCB8fCByZW5kZXJpbmdTaGFkb3dzICYmICEgY2xpcFNoYWRvd3MgKSB7XHJcblxyXG5cdFx0XHQvLyB0aGVyZSdzIG5vIGxvY2FsIGNsaXBwaW5nXHJcblxyXG5cdFx0XHRpZiAoIHJlbmRlcmluZ1NoYWRvd3MgKSB7XHJcblxyXG5cdFx0XHRcdC8vIHRoZXJlJ3Mgbm8gZ2xvYmFsIGNsaXBwaW5nXHJcblxyXG5cdFx0XHRcdHByb2plY3RQbGFuZXMoIG51bGwgKTtcclxuXHJcblx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdHJlc2V0R2xvYmFsU3RhdGUoKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0Y29uc3Qgbkdsb2JhbCA9IHJlbmRlcmluZ1NoYWRvd3MgPyAwIDogbnVtR2xvYmFsUGxhbmVzLFxyXG5cdFx0XHRcdGxHbG9iYWwgPSBuR2xvYmFsICogNDtcclxuXHJcblx0XHRcdGxldCBkc3RBcnJheSA9IG1hdGVyaWFsUHJvcGVydGllcy5jbGlwcGluZ1N0YXRlIHx8IG51bGw7XHJcblxyXG5cdFx0XHR1bmlmb3JtLnZhbHVlID0gZHN0QXJyYXk7IC8vIGVuc3VyZSB1bmlxdWUgc3RhdGVcclxuXHJcblx0XHRcdGRzdEFycmF5ID0gcHJvamVjdFBsYW5lcyggcGxhbmVzLCBjYW1lcmEsIGxHbG9iYWwsIHVzZUNhY2hlICk7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgIT09IGxHbG9iYWw7ICsrIGkgKSB7XHJcblxyXG5cdFx0XHRcdGRzdEFycmF5WyBpIF0gPSBnbG9iYWxTdGF0ZVsgaSBdO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0bWF0ZXJpYWxQcm9wZXJ0aWVzLmNsaXBwaW5nU3RhdGUgPSBkc3RBcnJheTtcclxuXHRcdFx0dGhpcy5udW1JbnRlcnNlY3Rpb24gPSBjbGlwSW50ZXJzZWN0aW9uID8gdGhpcy5udW1QbGFuZXMgOiAwO1xyXG5cdFx0XHR0aGlzLm51bVBsYW5lcyArPSBuR2xvYmFsO1xyXG5cclxuXHRcdH1cclxuXHJcblxyXG5cdH07XHJcblxyXG5cdGZ1bmN0aW9uIHJlc2V0R2xvYmFsU3RhdGUoKSB7XHJcblxyXG5cdFx0aWYgKCB1bmlmb3JtLnZhbHVlICE9PSBnbG9iYWxTdGF0ZSApIHtcclxuXHJcblx0XHRcdHVuaWZvcm0udmFsdWUgPSBnbG9iYWxTdGF0ZTtcclxuXHRcdFx0dW5pZm9ybS5uZWVkc1VwZGF0ZSA9IG51bUdsb2JhbFBsYW5lcyA+IDA7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHNjb3BlLm51bVBsYW5lcyA9IG51bUdsb2JhbFBsYW5lcztcclxuXHRcdHNjb3BlLm51bUludGVyc2VjdGlvbiA9IDA7XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gcHJvamVjdFBsYW5lcyggcGxhbmVzLCBjYW1lcmEsIGRzdE9mZnNldCwgc2tpcFRyYW5zZm9ybSApIHtcclxuXHJcblx0XHRjb25zdCBuUGxhbmVzID0gcGxhbmVzICE9PSBudWxsID8gcGxhbmVzLmxlbmd0aCA6IDA7XHJcblx0XHRsZXQgZHN0QXJyYXkgPSBudWxsO1xyXG5cclxuXHRcdGlmICggblBsYW5lcyAhPT0gMCApIHtcclxuXHJcblx0XHRcdGRzdEFycmF5ID0gdW5pZm9ybS52YWx1ZTtcclxuXHJcblx0XHRcdGlmICggc2tpcFRyYW5zZm9ybSAhPT0gdHJ1ZSB8fCBkc3RBcnJheSA9PT0gbnVsbCApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgZmxhdFNpemUgPSBkc3RPZmZzZXQgKyBuUGxhbmVzICogNCxcclxuXHRcdFx0XHRcdHZpZXdNYXRyaXggPSBjYW1lcmEubWF0cml4V29ybGRJbnZlcnNlO1xyXG5cclxuXHRcdFx0XHR2aWV3Tm9ybWFsTWF0cml4LmdldE5vcm1hbE1hdHJpeCggdmlld01hdHJpeCApO1xyXG5cclxuXHRcdFx0XHRpZiAoIGRzdEFycmF5ID09PSBudWxsIHx8IGRzdEFycmF5Lmxlbmd0aCA8IGZsYXRTaXplICkge1xyXG5cclxuXHRcdFx0XHRcdGRzdEFycmF5ID0gbmV3IEZsb2F0MzJBcnJheSggZmxhdFNpemUgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGk0ID0gZHN0T2Zmc2V0OyBpICE9PSBuUGxhbmVzOyArKyBpLCBpNCArPSA0ICkge1xyXG5cclxuXHRcdFx0XHRcdHBsYW5lLmNvcHkoIHBsYW5lc1sgaSBdICkuYXBwbHlNYXRyaXg0KCB2aWV3TWF0cml4LCB2aWV3Tm9ybWFsTWF0cml4ICk7XHJcblxyXG5cdFx0XHRcdFx0cGxhbmUubm9ybWFsLnRvQXJyYXkoIGRzdEFycmF5LCBpNCApO1xyXG5cdFx0XHRcdFx0ZHN0QXJyYXlbIGk0ICsgMyBdID0gcGxhbmUuY29uc3RhbnQ7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHVuaWZvcm0udmFsdWUgPSBkc3RBcnJheTtcclxuXHRcdFx0dW5pZm9ybS5uZWVkc1VwZGF0ZSA9IHRydWU7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHNjb3BlLm51bVBsYW5lcyA9IG5QbGFuZXM7XHJcblx0XHRzY29wZS5udW1JbnRlcnNlY3Rpb24gPSAwO1xyXG5cclxuXHRcdHJldHVybiBkc3RBcnJheTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuXHJcbmV4cG9ydCB7IFdlYkdMQ2xpcHBpbmcgfTtcclxuIiwiaW1wb3J0IHsgQ3ViZVJlZmxlY3Rpb25NYXBwaW5nLCBDdWJlUmVmcmFjdGlvbk1hcHBpbmcsIEVxdWlyZWN0YW5ndWxhclJlZmxlY3Rpb25NYXBwaW5nLCBFcXVpcmVjdGFuZ3VsYXJSZWZyYWN0aW9uTWFwcGluZyB9IGZyb20gJy4uLy4uL2NvbnN0YW50cy5qcyc7XHJcbmltcG9ydCB7IFdlYkdMQ3ViZVJlbmRlclRhcmdldCB9IGZyb20gJy4uL1dlYkdMQ3ViZVJlbmRlclRhcmdldC5qcyc7XHJcblxyXG5mdW5jdGlvbiBXZWJHTEN1YmVNYXBzKCByZW5kZXJlciApIHtcclxuXHJcblx0bGV0IGN1YmVtYXBzID0gbmV3IFdlYWtNYXAoKTtcclxuXHJcblx0ZnVuY3Rpb24gbWFwVGV4dHVyZU1hcHBpbmcoIHRleHR1cmUsIG1hcHBpbmcgKSB7XHJcblxyXG5cdFx0aWYgKCBtYXBwaW5nID09PSBFcXVpcmVjdGFuZ3VsYXJSZWZsZWN0aW9uTWFwcGluZyApIHtcclxuXHJcblx0XHRcdHRleHR1cmUubWFwcGluZyA9IEN1YmVSZWZsZWN0aW9uTWFwcGluZztcclxuXHJcblx0XHR9IGVsc2UgaWYgKCBtYXBwaW5nID09PSBFcXVpcmVjdGFuZ3VsYXJSZWZyYWN0aW9uTWFwcGluZyApIHtcclxuXHJcblx0XHRcdHRleHR1cmUubWFwcGluZyA9IEN1YmVSZWZyYWN0aW9uTWFwcGluZztcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRleHR1cmU7XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gZ2V0KCB0ZXh0dXJlICkge1xyXG5cclxuXHRcdGlmICggdGV4dHVyZSAmJiB0ZXh0dXJlLmlzVGV4dHVyZSApIHtcclxuXHJcblx0XHRcdGNvbnN0IG1hcHBpbmcgPSB0ZXh0dXJlLm1hcHBpbmc7XHJcblxyXG5cdFx0XHRpZiAoIG1hcHBpbmcgPT09IEVxdWlyZWN0YW5ndWxhclJlZmxlY3Rpb25NYXBwaW5nIHx8IG1hcHBpbmcgPT09IEVxdWlyZWN0YW5ndWxhclJlZnJhY3Rpb25NYXBwaW5nICkge1xyXG5cclxuXHRcdFx0XHRpZiAoIGN1YmVtYXBzLmhhcyggdGV4dHVyZSApICkge1xyXG5cclxuXHRcdFx0XHRcdGNvbnN0IGN1YmVtYXAgPSBjdWJlbWFwcy5nZXQoIHRleHR1cmUgKS50ZXh0dXJlO1xyXG5cdFx0XHRcdFx0cmV0dXJuIG1hcFRleHR1cmVNYXBwaW5nKCBjdWJlbWFwLCB0ZXh0dXJlLm1hcHBpbmcgKTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRjb25zdCBpbWFnZSA9IHRleHR1cmUuaW1hZ2U7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCBpbWFnZSAmJiBpbWFnZS5oZWlnaHQgPiAwICkge1xyXG5cclxuXHRcdFx0XHRcdFx0Y29uc3QgcmVuZGVyVGFyZ2V0ID0gbmV3IFdlYkdMQ3ViZVJlbmRlclRhcmdldCggaW1hZ2UuaGVpZ2h0ICk7XHJcblx0XHRcdFx0XHRcdHJlbmRlclRhcmdldC5mcm9tRXF1aXJlY3Rhbmd1bGFyVGV4dHVyZSggcmVuZGVyZXIsIHRleHR1cmUgKTtcclxuXHRcdFx0XHRcdFx0Y3ViZW1hcHMuc2V0KCB0ZXh0dXJlLCByZW5kZXJUYXJnZXQgKTtcclxuXHJcblx0XHRcdFx0XHRcdHRleHR1cmUuYWRkRXZlbnRMaXN0ZW5lciggJ2Rpc3Bvc2UnLCBvblRleHR1cmVEaXNwb3NlICk7XHJcblxyXG5cdFx0XHRcdFx0XHRyZXR1cm4gbWFwVGV4dHVyZU1hcHBpbmcoIHJlbmRlclRhcmdldC50ZXh0dXJlLCB0ZXh0dXJlLm1hcHBpbmcgKTtcclxuXHJcblx0XHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdFx0Ly8gaW1hZ2Ugbm90IHlldCByZWFkeS4gdHJ5IHRoZSBjb252ZXJzaW9uIG5leHQgZnJhbWVcclxuXHJcblx0XHRcdFx0XHRcdHJldHVybiBudWxsO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGV4dHVyZTtcclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBvblRleHR1cmVEaXNwb3NlKCBldmVudCApIHtcclxuXHJcblx0XHRjb25zdCB0ZXh0dXJlID0gZXZlbnQudGFyZ2V0O1xyXG5cclxuXHRcdHRleHR1cmUucmVtb3ZlRXZlbnRMaXN0ZW5lciggJ2Rpc3Bvc2UnLCBvblRleHR1cmVEaXNwb3NlICk7XHJcblxyXG5cdFx0Y29uc3QgY3ViZW1hcCA9IGN1YmVtYXBzLmdldCggdGV4dHVyZSApO1xyXG5cclxuXHRcdGlmICggY3ViZW1hcCAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0Y3ViZW1hcHMuZGVsZXRlKCB0ZXh0dXJlICk7XHJcblx0XHRcdGN1YmVtYXAuZGlzcG9zZSgpO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBkaXNwb3NlKCkge1xyXG5cclxuXHRcdGN1YmVtYXBzID0gbmV3IFdlYWtNYXAoKTtcclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4ge1xyXG5cdFx0Z2V0OiBnZXQsXHJcblx0XHRkaXNwb3NlOiBkaXNwb3NlXHJcblx0fTtcclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IFdlYkdMQ3ViZU1hcHMgfTtcclxuIiwiaW1wb3J0IHsgQ2FtZXJhIH0gZnJvbSAnLi9DYW1lcmEuanMnO1xyXG5cclxuY2xhc3MgT3J0aG9ncmFwaGljQ2FtZXJhIGV4dGVuZHMgQ2FtZXJhIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIGxlZnQgPSAtIDEsIHJpZ2h0ID0gMSwgdG9wID0gMSwgYm90dG9tID0gLSAxLCBuZWFyID0gMC4xLCBmYXIgPSAyMDAwICkge1xyXG5cclxuXHRcdHN1cGVyKCk7XHJcblxyXG5cdFx0dGhpcy5pc09ydGhvZ3JhcGhpY0NhbWVyYSA9IHRydWU7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ09ydGhvZ3JhcGhpY0NhbWVyYSc7XHJcblxyXG5cdFx0dGhpcy56b29tID0gMTtcclxuXHRcdHRoaXMudmlldyA9IG51bGw7XHJcblxyXG5cdFx0dGhpcy5sZWZ0ID0gbGVmdDtcclxuXHRcdHRoaXMucmlnaHQgPSByaWdodDtcclxuXHRcdHRoaXMudG9wID0gdG9wO1xyXG5cdFx0dGhpcy5ib3R0b20gPSBib3R0b207XHJcblxyXG5cdFx0dGhpcy5uZWFyID0gbmVhcjtcclxuXHRcdHRoaXMuZmFyID0gZmFyO1xyXG5cclxuXHRcdHRoaXMudXBkYXRlUHJvamVjdGlvbk1hdHJpeCgpO1xyXG5cclxuXHR9XHJcblxyXG5cdGNvcHkoIHNvdXJjZSwgcmVjdXJzaXZlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSwgcmVjdXJzaXZlICk7XHJcblxyXG5cdFx0dGhpcy5sZWZ0ID0gc291cmNlLmxlZnQ7XHJcblx0XHR0aGlzLnJpZ2h0ID0gc291cmNlLnJpZ2h0O1xyXG5cdFx0dGhpcy50b3AgPSBzb3VyY2UudG9wO1xyXG5cdFx0dGhpcy5ib3R0b20gPSBzb3VyY2UuYm90dG9tO1xyXG5cdFx0dGhpcy5uZWFyID0gc291cmNlLm5lYXI7XHJcblx0XHR0aGlzLmZhciA9IHNvdXJjZS5mYXI7XHJcblxyXG5cdFx0dGhpcy56b29tID0gc291cmNlLnpvb207XHJcblx0XHR0aGlzLnZpZXcgPSBzb3VyY2UudmlldyA9PT0gbnVsbCA/IG51bGwgOiBPYmplY3QuYXNzaWduKCB7fSwgc291cmNlLnZpZXcgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRWaWV3T2Zmc2V0KCBmdWxsV2lkdGgsIGZ1bGxIZWlnaHQsIHgsIHksIHdpZHRoLCBoZWlnaHQgKSB7XHJcblxyXG5cdFx0aWYgKCB0aGlzLnZpZXcgPT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHR0aGlzLnZpZXcgPSB7XHJcblx0XHRcdFx0ZW5hYmxlZDogdHJ1ZSxcclxuXHRcdFx0XHRmdWxsV2lkdGg6IDEsXHJcblx0XHRcdFx0ZnVsbEhlaWdodDogMSxcclxuXHRcdFx0XHRvZmZzZXRYOiAwLFxyXG5cdFx0XHRcdG9mZnNldFk6IDAsXHJcblx0XHRcdFx0d2lkdGg6IDEsXHJcblx0XHRcdFx0aGVpZ2h0OiAxXHJcblx0XHRcdH07XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMudmlldy5lbmFibGVkID0gdHJ1ZTtcclxuXHRcdHRoaXMudmlldy5mdWxsV2lkdGggPSBmdWxsV2lkdGg7XHJcblx0XHR0aGlzLnZpZXcuZnVsbEhlaWdodCA9IGZ1bGxIZWlnaHQ7XHJcblx0XHR0aGlzLnZpZXcub2Zmc2V0WCA9IHg7XHJcblx0XHR0aGlzLnZpZXcub2Zmc2V0WSA9IHk7XHJcblx0XHR0aGlzLnZpZXcud2lkdGggPSB3aWR0aDtcclxuXHRcdHRoaXMudmlldy5oZWlnaHQgPSBoZWlnaHQ7XHJcblxyXG5cdFx0dGhpcy51cGRhdGVQcm9qZWN0aW9uTWF0cml4KCk7XHJcblxyXG5cdH1cclxuXHJcblx0Y2xlYXJWaWV3T2Zmc2V0KCkge1xyXG5cclxuXHRcdGlmICggdGhpcy52aWV3ICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0dGhpcy52aWV3LmVuYWJsZWQgPSBmYWxzZTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy51cGRhdGVQcm9qZWN0aW9uTWF0cml4KCk7XHJcblxyXG5cdH1cclxuXHJcblx0dXBkYXRlUHJvamVjdGlvbk1hdHJpeCgpIHtcclxuXHJcblx0XHRjb25zdCBkeCA9ICggdGhpcy5yaWdodCAtIHRoaXMubGVmdCApIC8gKCAyICogdGhpcy56b29tICk7XHJcblx0XHRjb25zdCBkeSA9ICggdGhpcy50b3AgLSB0aGlzLmJvdHRvbSApIC8gKCAyICogdGhpcy56b29tICk7XHJcblx0XHRjb25zdCBjeCA9ICggdGhpcy5yaWdodCArIHRoaXMubGVmdCApIC8gMjtcclxuXHRcdGNvbnN0IGN5ID0gKCB0aGlzLnRvcCArIHRoaXMuYm90dG9tICkgLyAyO1xyXG5cclxuXHRcdGxldCBsZWZ0ID0gY3ggLSBkeDtcclxuXHRcdGxldCByaWdodCA9IGN4ICsgZHg7XHJcblx0XHRsZXQgdG9wID0gY3kgKyBkeTtcclxuXHRcdGxldCBib3R0b20gPSBjeSAtIGR5O1xyXG5cclxuXHRcdGlmICggdGhpcy52aWV3ICE9PSBudWxsICYmIHRoaXMudmlldy5lbmFibGVkICkge1xyXG5cclxuXHRcdFx0Y29uc3Qgc2NhbGVXID0gKCB0aGlzLnJpZ2h0IC0gdGhpcy5sZWZ0ICkgLyB0aGlzLnZpZXcuZnVsbFdpZHRoIC8gdGhpcy56b29tO1xyXG5cdFx0XHRjb25zdCBzY2FsZUggPSAoIHRoaXMudG9wIC0gdGhpcy5ib3R0b20gKSAvIHRoaXMudmlldy5mdWxsSGVpZ2h0IC8gdGhpcy56b29tO1xyXG5cclxuXHRcdFx0bGVmdCArPSBzY2FsZVcgKiB0aGlzLnZpZXcub2Zmc2V0WDtcclxuXHRcdFx0cmlnaHQgPSBsZWZ0ICsgc2NhbGVXICogdGhpcy52aWV3LndpZHRoO1xyXG5cdFx0XHR0b3AgLT0gc2NhbGVIICogdGhpcy52aWV3Lm9mZnNldFk7XHJcblx0XHRcdGJvdHRvbSA9IHRvcCAtIHNjYWxlSCAqIHRoaXMudmlldy5oZWlnaHQ7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMucHJvamVjdGlvbk1hdHJpeC5tYWtlT3J0aG9ncmFwaGljKCBsZWZ0LCByaWdodCwgdG9wLCBib3R0b20sIHRoaXMubmVhciwgdGhpcy5mYXIsIHRoaXMuY29vcmRpbmF0ZVN5c3RlbSApO1xyXG5cclxuXHRcdHRoaXMucHJvamVjdGlvbk1hdHJpeEludmVyc2UuY29weSggdGhpcy5wcm9qZWN0aW9uTWF0cml4ICkuaW52ZXJ0KCk7XHJcblxyXG5cdH1cclxuXHJcblx0dG9KU09OKCBtZXRhICkge1xyXG5cclxuXHRcdGNvbnN0IGRhdGEgPSBzdXBlci50b0pTT04oIG1ldGEgKTtcclxuXHJcblx0XHRkYXRhLm9iamVjdC56b29tID0gdGhpcy56b29tO1xyXG5cdFx0ZGF0YS5vYmplY3QubGVmdCA9IHRoaXMubGVmdDtcclxuXHRcdGRhdGEub2JqZWN0LnJpZ2h0ID0gdGhpcy5yaWdodDtcclxuXHRcdGRhdGEub2JqZWN0LnRvcCA9IHRoaXMudG9wO1xyXG5cdFx0ZGF0YS5vYmplY3QuYm90dG9tID0gdGhpcy5ib3R0b207XHJcblx0XHRkYXRhLm9iamVjdC5uZWFyID0gdGhpcy5uZWFyO1xyXG5cdFx0ZGF0YS5vYmplY3QuZmFyID0gdGhpcy5mYXI7XHJcblxyXG5cdFx0aWYgKCB0aGlzLnZpZXcgIT09IG51bGwgKSBkYXRhLm9iamVjdC52aWV3ID0gT2JqZWN0LmFzc2lnbigge30sIHRoaXMudmlldyApO1xyXG5cclxuXHRcdHJldHVybiBkYXRhO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBPcnRob2dyYXBoaWNDYW1lcmEgfTtcclxuIiwiaW1wb3J0IHtcclxuXHRDdWJlUmVmbGVjdGlvbk1hcHBpbmcsXHJcblx0Q3ViZVJlZnJhY3Rpb25NYXBwaW5nLFxyXG5cdEN1YmVVVlJlZmxlY3Rpb25NYXBwaW5nLFxyXG5cdExpbmVhckZpbHRlcixcclxuXHROb1RvbmVNYXBwaW5nLFxyXG5cdE5vQmxlbmRpbmcsXHJcblx0UkdCQUZvcm1hdCxcclxuXHRIYWxmRmxvYXRUeXBlLFxyXG5cdEJhY2tTaWRlLFxyXG5cdExpbmVhclNSR0JDb2xvclNwYWNlXHJcbn0gZnJvbSAnLi4vY29uc3RhbnRzLmpzJztcclxuXHJcbmltcG9ydCB7IEJ1ZmZlckF0dHJpYnV0ZSB9IGZyb20gJy4uL2NvcmUvQnVmZmVyQXR0cmlidXRlLmpzJztcclxuaW1wb3J0IHsgQnVmZmVyR2VvbWV0cnkgfSBmcm9tICcuLi9jb3JlL0J1ZmZlckdlb21ldHJ5LmpzJztcclxuaW1wb3J0IHsgTWVzaCB9IGZyb20gJy4uL29iamVjdHMvTWVzaC5qcyc7XHJcbmltcG9ydCB7IE9ydGhvZ3JhcGhpY0NhbWVyYSB9IGZyb20gJy4uL2NhbWVyYXMvT3J0aG9ncmFwaGljQ2FtZXJhLmpzJztcclxuaW1wb3J0IHsgUGVyc3BlY3RpdmVDYW1lcmEgfSBmcm9tICcuLi9jYW1lcmFzL1BlcnNwZWN0aXZlQ2FtZXJhLmpzJztcclxuaW1wb3J0IHsgU2hhZGVyTWF0ZXJpYWwgfSBmcm9tICcuLi9tYXRlcmlhbHMvU2hhZGVyTWF0ZXJpYWwuanMnO1xyXG5pbXBvcnQgeyBWZWN0b3IzIH0gZnJvbSAnLi4vbWF0aC9WZWN0b3IzLmpzJztcclxuaW1wb3J0IHsgQ29sb3IgfSBmcm9tICcuLi9tYXRoL0NvbG9yLmpzJztcclxuaW1wb3J0IHsgV2ViR0xSZW5kZXJUYXJnZXQgfSBmcm9tICcuLi9yZW5kZXJlcnMvV2ViR0xSZW5kZXJUYXJnZXQuanMnO1xyXG5pbXBvcnQgeyBNZXNoQmFzaWNNYXRlcmlhbCB9IGZyb20gJy4uL21hdGVyaWFscy9NZXNoQmFzaWNNYXRlcmlhbC5qcyc7XHJcbmltcG9ydCB7IEJveEdlb21ldHJ5IH0gZnJvbSAnLi4vZ2VvbWV0cmllcy9Cb3hHZW9tZXRyeS5qcyc7XHJcblxyXG5jb25zdCBMT0RfTUlOID0gNDtcclxuXHJcbi8vIFRoZSBzdGFuZGFyZCBkZXZpYXRpb25zIChyYWRpYW5zKSBhc3NvY2lhdGVkIHdpdGggdGhlIGV4dHJhIG1pcHMuIFRoZXNlIGFyZVxyXG4vLyBjaG9zZW4gdG8gYXBwcm94aW1hdGUgYSBUcm93YnJpZGdlLVJlaXR6IGRpc3RyaWJ1dGlvbiBmdW5jdGlvbiB0aW1lcyB0aGVcclxuLy8gZ2VvbWV0cmljIHNoYWRvd2luZyBmdW5jdGlvbi4gVGhlc2Ugc2lnbWEgdmFsdWVzIHNxdWFyZWQgbXVzdCBtYXRjaCB0aGVcclxuLy8gdmFyaWFuY2UgI2RlZmluZXMgaW4gY3ViZV91dl9yZWZsZWN0aW9uX2ZyYWdtZW50Lmdsc2wuanMuXHJcbmNvbnN0IEVYVFJBX0xPRF9TSUdNQSA9IFsgMC4xMjUsIDAuMjE1LCAwLjM1LCAwLjQ0NiwgMC41MjYsIDAuNTgyIF07XHJcblxyXG4vLyBUaGUgbWF4aW11bSBsZW5ndGggb2YgdGhlIGJsdXIgZm9yIGxvb3AuIFNtYWxsZXIgc2lnbWFzIHdpbGwgdXNlIGZld2VyXHJcbi8vIHNhbXBsZXMgYW5kIGV4aXQgZWFybHksIGJ1dCBub3QgcmVjb21waWxlIHRoZSBzaGFkZXIuXHJcbmNvbnN0IE1BWF9TQU1QTEVTID0gMjA7XHJcblxyXG5jb25zdCBfZmxhdENhbWVyYSA9IC8qQF9fUFVSRV9fKi8gbmV3IE9ydGhvZ3JhcGhpY0NhbWVyYSgpO1xyXG5jb25zdCBfY2xlYXJDb2xvciA9IC8qQF9fUFVSRV9fKi8gbmV3IENvbG9yKCk7XHJcbmxldCBfb2xkVGFyZ2V0ID0gbnVsbDtcclxubGV0IF9vbGRBY3RpdmVDdWJlRmFjZSA9IDA7XHJcbmxldCBfb2xkQWN0aXZlTWlwbWFwTGV2ZWwgPSAwO1xyXG5cclxuLy8gR29sZGVuIFJhdGlvXHJcbmNvbnN0IFBISSA9ICggMSArIE1hdGguc3FydCggNSApICkgLyAyO1xyXG5jb25zdCBJTlZfUEhJID0gMSAvIFBISTtcclxuXHJcbi8vIFZlcnRpY2VzIG9mIGEgZG9kZWNhaGVkcm9uIChleGNlcHQgdGhlIG9wcG9zaXRlcywgd2hpY2ggcmVwcmVzZW50IHRoZVxyXG4vLyBzYW1lIGF4aXMpLCB1c2VkIGFzIGF4aXMgZGlyZWN0aW9ucyBldmVubHkgc3ByZWFkIG9uIGEgc3BoZXJlLlxyXG5jb25zdCBfYXhpc0RpcmVjdGlvbnMgPSBbXHJcblx0LypAX19QVVJFX18qLyBuZXcgVmVjdG9yMyggMSwgMSwgMSApLFxyXG5cdC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoIC0gMSwgMSwgMSApLFxyXG5cdC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoIDEsIDEsIC0gMSApLFxyXG5cdC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoIC0gMSwgMSwgLSAxICksXHJcblx0LypAX19QVVJFX18qLyBuZXcgVmVjdG9yMyggMCwgUEhJLCBJTlZfUEhJICksXHJcblx0LypAX19QVVJFX18qLyBuZXcgVmVjdG9yMyggMCwgUEhJLCAtIElOVl9QSEkgKSxcclxuXHQvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCBJTlZfUEhJLCAwLCBQSEkgKSxcclxuXHQvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCAtIElOVl9QSEksIDAsIFBISSApLFxyXG5cdC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoIFBISSwgSU5WX1BISSwgMCApLFxyXG5cdC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoIC0gUEhJLCBJTlZfUEhJLCAwICkgXTtcclxuXHJcbi8qKlxyXG4gKiBUaGlzIGNsYXNzIGdlbmVyYXRlcyBhIFByZWZpbHRlcmVkLCBNaXBtYXBwZWQgUmFkaWFuY2UgRW52aXJvbm1lbnQgTWFwXHJcbiAqIChQTVJFTSkgZnJvbSBhIGN1YmVNYXAgZW52aXJvbm1lbnQgdGV4dHVyZS4gVGhpcyBhbGxvd3MgZGlmZmVyZW50IGxldmVscyBvZlxyXG4gKiBibHVyIHRvIGJlIHF1aWNrbHkgYWNjZXNzZWQgYmFzZWQgb24gbWF0ZXJpYWwgcm91Z2huZXNzLiBJdCBpcyBwYWNrZWQgaW50byBhXHJcbiAqIHNwZWNpYWwgQ3ViZVVWIGZvcm1hdCB0aGF0IGFsbG93cyB1cyB0byBwZXJmb3JtIGN1c3RvbSBpbnRlcnBvbGF0aW9uIHNvIHRoYXRcclxuICogd2UgY2FuIHN1cHBvcnQgbm9ubGluZWFyIGZvcm1hdHMgc3VjaCBhcyBSR0JFLiBVbmxpa2UgYSB0cmFkaXRpb25hbCBtaXBtYXBcclxuICogY2hhaW4sIGl0IG9ubHkgZ29lcyBkb3duIHRvIHRoZSBMT0RfTUlOIGxldmVsIChhYm92ZSksIGFuZCB0aGVuIGNyZWF0ZXMgZXh0cmFcclxuICogZXZlbiBtb3JlIGZpbHRlcmVkICdtaXBzJyBhdCB0aGUgc2FtZSBMT0RfTUlOIHJlc29sdXRpb24sIGFzc29jaWF0ZWQgd2l0aFxyXG4gKiBoaWdoZXIgcm91Z2huZXNzIGxldmVscy4gSW4gdGhpcyB3YXkgd2UgbWFpbnRhaW4gcmVzb2x1dGlvbiB0byBzbW9vdGhseVxyXG4gKiBpbnRlcnBvbGF0ZSBkaWZmdXNlIGxpZ2h0aW5nIHdoaWxlIGxpbWl0aW5nIHNhbXBsaW5nIGNvbXB1dGF0aW9uLlxyXG4gKlxyXG4gKiBQYXBlcjogRmFzdCwgQWNjdXJhdGUgSW1hZ2UtQmFzZWQgTGlnaHRpbmdcclxuICogaHR0cHM6Ly9kcml2ZS5nb29nbGUuY29tL2ZpbGUvZC8xNXk4cl9VcEtsVTlTdlY0SUxiMEMzcUNQZWNTOHB2THovdmlld1xyXG4qL1xyXG5cclxuY2xhc3MgUE1SRU1HZW5lcmF0b3Ige1xyXG5cclxuXHRjb25zdHJ1Y3RvciggcmVuZGVyZXIgKSB7XHJcblxyXG5cdFx0dGhpcy5fcmVuZGVyZXIgPSByZW5kZXJlcjtcclxuXHRcdHRoaXMuX3BpbmdQb25nUmVuZGVyVGFyZ2V0ID0gbnVsbDtcclxuXHJcblx0XHR0aGlzLl9sb2RNYXggPSAwO1xyXG5cdFx0dGhpcy5fY3ViZVNpemUgPSAwO1xyXG5cdFx0dGhpcy5fbG9kUGxhbmVzID0gW107XHJcblx0XHR0aGlzLl9zaXplTG9kcyA9IFtdO1xyXG5cdFx0dGhpcy5fc2lnbWFzID0gW107XHJcblxyXG5cdFx0dGhpcy5fYmx1ck1hdGVyaWFsID0gbnVsbDtcclxuXHRcdHRoaXMuX2N1YmVtYXBNYXRlcmlhbCA9IG51bGw7XHJcblx0XHR0aGlzLl9lcXVpcmVjdE1hdGVyaWFsID0gbnVsbDtcclxuXHJcblx0XHR0aGlzLl9jb21waWxlTWF0ZXJpYWwoIHRoaXMuX2JsdXJNYXRlcmlhbCApO1xyXG5cclxuXHR9XHJcblxyXG5cdC8qKlxyXG5cdCAqIEdlbmVyYXRlcyBhIFBNUkVNIGZyb20gYSBzdXBwbGllZCBTY2VuZSwgd2hpY2ggY2FuIGJlIGZhc3RlciB0aGFuIHVzaW5nIGFuXHJcblx0ICogaW1hZ2UgaWYgbmV0d29ya2luZyBiYW5kd2lkdGggaXMgbG93LiBPcHRpb25hbCBzaWdtYSBzcGVjaWZpZXMgYSBibHVyIHJhZGl1c1xyXG5cdCAqIGluIHJhZGlhbnMgdG8gYmUgYXBwbGllZCB0byB0aGUgc2NlbmUgYmVmb3JlIFBNUkVNIGdlbmVyYXRpb24uIE9wdGlvbmFsIG5lYXJcclxuXHQgKiBhbmQgZmFyIHBsYW5lcyBlbnN1cmUgdGhlIHNjZW5lIGlzIHJlbmRlcmVkIGluIGl0cyBlbnRpcmV0eSAodGhlIGN1YmVDYW1lcmFcclxuXHQgKiBpcyBwbGFjZWQgYXQgdGhlIG9yaWdpbikuXHJcblx0ICovXHJcblx0ZnJvbVNjZW5lKCBzY2VuZSwgc2lnbWEgPSAwLCBuZWFyID0gMC4xLCBmYXIgPSAxMDAgKSB7XHJcblxyXG5cdFx0X29sZFRhcmdldCA9IHRoaXMuX3JlbmRlcmVyLmdldFJlbmRlclRhcmdldCgpO1xyXG5cdFx0X29sZEFjdGl2ZUN1YmVGYWNlID0gdGhpcy5fcmVuZGVyZXIuZ2V0QWN0aXZlQ3ViZUZhY2UoKTtcclxuXHRcdF9vbGRBY3RpdmVNaXBtYXBMZXZlbCA9IHRoaXMuX3JlbmRlcmVyLmdldEFjdGl2ZU1pcG1hcExldmVsKCk7XHJcblxyXG5cdFx0dGhpcy5fc2V0U2l6ZSggMjU2ICk7XHJcblxyXG5cdFx0Y29uc3QgY3ViZVVWUmVuZGVyVGFyZ2V0ID0gdGhpcy5fYWxsb2NhdGVUYXJnZXRzKCk7XHJcblx0XHRjdWJlVVZSZW5kZXJUYXJnZXQuZGVwdGhCdWZmZXIgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMuX3NjZW5lVG9DdWJlVVYoIHNjZW5lLCBuZWFyLCBmYXIsIGN1YmVVVlJlbmRlclRhcmdldCApO1xyXG5cclxuXHRcdGlmICggc2lnbWEgPiAwICkge1xyXG5cclxuXHRcdFx0dGhpcy5fYmx1ciggY3ViZVVWUmVuZGVyVGFyZ2V0LCAwLCAwLCBzaWdtYSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLl9hcHBseVBNUkVNKCBjdWJlVVZSZW5kZXJUYXJnZXQgKTtcclxuXHRcdHRoaXMuX2NsZWFudXAoIGN1YmVVVlJlbmRlclRhcmdldCApO1xyXG5cclxuXHRcdHJldHVybiBjdWJlVVZSZW5kZXJUYXJnZXQ7XHJcblxyXG5cdH1cclxuXHJcblx0LyoqXHJcblx0ICogR2VuZXJhdGVzIGEgUE1SRU0gZnJvbSBhbiBlcXVpcmVjdGFuZ3VsYXIgdGV4dHVyZSwgd2hpY2ggY2FuIGJlIGVpdGhlciBMRFJcclxuXHQgKiBvciBIRFIuIFRoZSBpZGVhbCBpbnB1dCBpbWFnZSBzaXplIGlzIDFrICgxMDI0IHggNTEyKSxcclxuXHQgKiBhcyB0aGlzIG1hdGNoZXMgYmVzdCB3aXRoIHRoZSAyNTYgeCAyNTYgY3ViZW1hcCBvdXRwdXQuXHJcblx0ICovXHJcblx0ZnJvbUVxdWlyZWN0YW5ndWxhciggZXF1aXJlY3Rhbmd1bGFyLCByZW5kZXJUYXJnZXQgPSBudWxsICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLl9mcm9tVGV4dHVyZSggZXF1aXJlY3Rhbmd1bGFyLCByZW5kZXJUYXJnZXQgKTtcclxuXHJcblx0fVxyXG5cclxuXHQvKipcclxuXHQgKiBHZW5lcmF0ZXMgYSBQTVJFTSBmcm9tIGFuIGN1YmVtYXAgdGV4dHVyZSwgd2hpY2ggY2FuIGJlIGVpdGhlciBMRFJcclxuXHQgKiBvciBIRFIuIFRoZSBpZGVhbCBpbnB1dCBjdWJlIHNpemUgaXMgMjU2IHggMjU2LFxyXG5cdCAqIGFzIHRoaXMgbWF0Y2hlcyBiZXN0IHdpdGggdGhlIDI1NiB4IDI1NiBjdWJlbWFwIG91dHB1dC5cclxuXHQgKi9cclxuXHRmcm9tQ3ViZW1hcCggY3ViZW1hcCwgcmVuZGVyVGFyZ2V0ID0gbnVsbCApIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5fZnJvbVRleHR1cmUoIGN1YmVtYXAsIHJlbmRlclRhcmdldCApO1xyXG5cclxuXHR9XHJcblxyXG5cdC8qKlxyXG5cdCAqIFByZS1jb21waWxlcyB0aGUgY3ViZW1hcCBzaGFkZXIuIFlvdSBjYW4gZ2V0IGZhc3RlciBzdGFydC11cCBieSBpbnZva2luZyB0aGlzIG1ldGhvZCBkdXJpbmdcclxuXHQgKiB5b3VyIHRleHR1cmUncyBuZXR3b3JrIGZldGNoIGZvciBpbmNyZWFzZWQgY29uY3VycmVuY3kuXHJcblx0ICovXHJcblx0Y29tcGlsZUN1YmVtYXBTaGFkZXIoKSB7XHJcblxyXG5cdFx0aWYgKCB0aGlzLl9jdWJlbWFwTWF0ZXJpYWwgPT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHR0aGlzLl9jdWJlbWFwTWF0ZXJpYWwgPSBfZ2V0Q3ViZW1hcE1hdGVyaWFsKCk7XHJcblx0XHRcdHRoaXMuX2NvbXBpbGVNYXRlcmlhbCggdGhpcy5fY3ViZW1hcE1hdGVyaWFsICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdC8qKlxyXG5cdCAqIFByZS1jb21waWxlcyB0aGUgZXF1aXJlY3Rhbmd1bGFyIHNoYWRlci4gWW91IGNhbiBnZXQgZmFzdGVyIHN0YXJ0LXVwIGJ5IGludm9raW5nIHRoaXMgbWV0aG9kIGR1cmluZ1xyXG5cdCAqIHlvdXIgdGV4dHVyZSdzIG5ldHdvcmsgZmV0Y2ggZm9yIGluY3JlYXNlZCBjb25jdXJyZW5jeS5cclxuXHQgKi9cclxuXHRjb21waWxlRXF1aXJlY3Rhbmd1bGFyU2hhZGVyKCkge1xyXG5cclxuXHRcdGlmICggdGhpcy5fZXF1aXJlY3RNYXRlcmlhbCA9PT0gbnVsbCApIHtcclxuXHJcblx0XHRcdHRoaXMuX2VxdWlyZWN0TWF0ZXJpYWwgPSBfZ2V0RXF1aXJlY3RNYXRlcmlhbCgpO1xyXG5cdFx0XHR0aGlzLl9jb21waWxlTWF0ZXJpYWwoIHRoaXMuX2VxdWlyZWN0TWF0ZXJpYWwgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0LyoqXHJcblx0ICogRGlzcG9zZXMgb2YgdGhlIFBNUkVNR2VuZXJhdG9yJ3MgaW50ZXJuYWwgbWVtb3J5LiBOb3RlIHRoYXQgUE1SRU1HZW5lcmF0b3IgaXMgYSBzdGF0aWMgY2xhc3MsXHJcblx0ICogc28geW91IHNob3VsZCBub3QgbmVlZCBtb3JlIHRoYW4gb25lIFBNUkVNR2VuZXJhdG9yIG9iamVjdC4gSWYgeW91IGRvLCBjYWxsaW5nIGRpc3Bvc2UoKSBvblxyXG5cdCAqIG9uZSBvZiB0aGVtIHdpbGwgY2F1c2UgYW55IG90aGVycyB0byBhbHNvIGJlY29tZSB1bnVzYWJsZS5cclxuXHQgKi9cclxuXHRkaXNwb3NlKCkge1xyXG5cclxuXHRcdHRoaXMuX2Rpc3Bvc2UoKTtcclxuXHJcblx0XHRpZiAoIHRoaXMuX2N1YmVtYXBNYXRlcmlhbCAhPT0gbnVsbCApIHRoaXMuX2N1YmVtYXBNYXRlcmlhbC5kaXNwb3NlKCk7XHJcblx0XHRpZiAoIHRoaXMuX2VxdWlyZWN0TWF0ZXJpYWwgIT09IG51bGwgKSB0aGlzLl9lcXVpcmVjdE1hdGVyaWFsLmRpc3Bvc2UoKTtcclxuXHJcblx0fVxyXG5cclxuXHQvLyBwcml2YXRlIGludGVyZmFjZVxyXG5cclxuXHRfc2V0U2l6ZSggY3ViZVNpemUgKSB7XHJcblxyXG5cdFx0dGhpcy5fbG9kTWF4ID0gTWF0aC5mbG9vciggTWF0aC5sb2cyKCBjdWJlU2l6ZSApICk7XHJcblx0XHR0aGlzLl9jdWJlU2l6ZSA9IE1hdGgucG93KCAyLCB0aGlzLl9sb2RNYXggKTtcclxuXHJcblx0fVxyXG5cclxuXHRfZGlzcG9zZSgpIHtcclxuXHJcblx0XHRpZiAoIHRoaXMuX2JsdXJNYXRlcmlhbCAhPT0gbnVsbCApIHRoaXMuX2JsdXJNYXRlcmlhbC5kaXNwb3NlKCk7XHJcblxyXG5cdFx0aWYgKCB0aGlzLl9waW5nUG9uZ1JlbmRlclRhcmdldCAhPT0gbnVsbCApIHRoaXMuX3BpbmdQb25nUmVuZGVyVGFyZ2V0LmRpc3Bvc2UoKTtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCB0aGlzLl9sb2RQbGFuZXMubGVuZ3RoOyBpICsrICkge1xyXG5cclxuXHRcdFx0dGhpcy5fbG9kUGxhbmVzWyBpIF0uZGlzcG9zZSgpO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRfY2xlYW51cCggb3V0cHV0VGFyZ2V0ICkge1xyXG5cclxuXHRcdHRoaXMuX3JlbmRlcmVyLnNldFJlbmRlclRhcmdldCggX29sZFRhcmdldCwgX29sZEFjdGl2ZUN1YmVGYWNlLCBfb2xkQWN0aXZlTWlwbWFwTGV2ZWwgKTtcclxuXHRcdG91dHB1dFRhcmdldC5zY2lzc29yVGVzdCA9IGZhbHNlO1xyXG5cdFx0X3NldFZpZXdwb3J0KCBvdXRwdXRUYXJnZXQsIDAsIDAsIG91dHB1dFRhcmdldC53aWR0aCwgb3V0cHV0VGFyZ2V0LmhlaWdodCApO1xyXG5cclxuXHR9XHJcblxyXG5cdF9mcm9tVGV4dHVyZSggdGV4dHVyZSwgcmVuZGVyVGFyZ2V0ICkge1xyXG5cclxuXHRcdGlmICggdGV4dHVyZS5tYXBwaW5nID09PSBDdWJlUmVmbGVjdGlvbk1hcHBpbmcgfHwgdGV4dHVyZS5tYXBwaW5nID09PSBDdWJlUmVmcmFjdGlvbk1hcHBpbmcgKSB7XHJcblxyXG5cdFx0XHR0aGlzLl9zZXRTaXplKCB0ZXh0dXJlLmltYWdlLmxlbmd0aCA9PT0gMCA/IDE2IDogKCB0ZXh0dXJlLmltYWdlWyAwIF0ud2lkdGggfHwgdGV4dHVyZS5pbWFnZVsgMCBdLmltYWdlLndpZHRoICkgKTtcclxuXHJcblx0XHR9IGVsc2UgeyAvLyBFcXVpcmVjdGFuZ3VsYXJcclxuXHJcblx0XHRcdHRoaXMuX3NldFNpemUoIHRleHR1cmUuaW1hZ2Uud2lkdGggLyA0ICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdF9vbGRUYXJnZXQgPSB0aGlzLl9yZW5kZXJlci5nZXRSZW5kZXJUYXJnZXQoKTtcclxuXHRcdF9vbGRBY3RpdmVDdWJlRmFjZSA9IHRoaXMuX3JlbmRlcmVyLmdldEFjdGl2ZUN1YmVGYWNlKCk7XHJcblx0XHRfb2xkQWN0aXZlTWlwbWFwTGV2ZWwgPSB0aGlzLl9yZW5kZXJlci5nZXRBY3RpdmVNaXBtYXBMZXZlbCgpO1xyXG5cclxuXHRcdGNvbnN0IGN1YmVVVlJlbmRlclRhcmdldCA9IHJlbmRlclRhcmdldCB8fCB0aGlzLl9hbGxvY2F0ZVRhcmdldHMoKTtcclxuXHRcdHRoaXMuX3RleHR1cmVUb0N1YmVVViggdGV4dHVyZSwgY3ViZVVWUmVuZGVyVGFyZ2V0ICk7XHJcblx0XHR0aGlzLl9hcHBseVBNUkVNKCBjdWJlVVZSZW5kZXJUYXJnZXQgKTtcclxuXHRcdHRoaXMuX2NsZWFudXAoIGN1YmVVVlJlbmRlclRhcmdldCApO1xyXG5cclxuXHRcdHJldHVybiBjdWJlVVZSZW5kZXJUYXJnZXQ7XHJcblxyXG5cdH1cclxuXHJcblx0X2FsbG9jYXRlVGFyZ2V0cygpIHtcclxuXHJcblx0XHRjb25zdCB3aWR0aCA9IDMgKiBNYXRoLm1heCggdGhpcy5fY3ViZVNpemUsIDE2ICogNyApO1xyXG5cdFx0Y29uc3QgaGVpZ2h0ID0gNCAqIHRoaXMuX2N1YmVTaXplO1xyXG5cclxuXHRcdGNvbnN0IHBhcmFtcyA9IHtcclxuXHRcdFx0bWFnRmlsdGVyOiBMaW5lYXJGaWx0ZXIsXHJcblx0XHRcdG1pbkZpbHRlcjogTGluZWFyRmlsdGVyLFxyXG5cdFx0XHRnZW5lcmF0ZU1pcG1hcHM6IGZhbHNlLFxyXG5cdFx0XHR0eXBlOiBIYWxmRmxvYXRUeXBlLFxyXG5cdFx0XHRmb3JtYXQ6IFJHQkFGb3JtYXQsXHJcblx0XHRcdGNvbG9yU3BhY2U6IExpbmVhclNSR0JDb2xvclNwYWNlLFxyXG5cdFx0XHRkZXB0aEJ1ZmZlcjogZmFsc2VcclxuXHRcdH07XHJcblxyXG5cdFx0Y29uc3QgY3ViZVVWUmVuZGVyVGFyZ2V0ID0gX2NyZWF0ZVJlbmRlclRhcmdldCggd2lkdGgsIGhlaWdodCwgcGFyYW1zICk7XHJcblxyXG5cdFx0aWYgKCB0aGlzLl9waW5nUG9uZ1JlbmRlclRhcmdldCA9PT0gbnVsbCB8fCB0aGlzLl9waW5nUG9uZ1JlbmRlclRhcmdldC53aWR0aCAhPT0gd2lkdGggfHwgdGhpcy5fcGluZ1BvbmdSZW5kZXJUYXJnZXQuaGVpZ2h0ICE9PSBoZWlnaHQgKSB7XHJcblxyXG5cdFx0XHRpZiAoIHRoaXMuX3BpbmdQb25nUmVuZGVyVGFyZ2V0ICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0XHR0aGlzLl9kaXNwb3NlKCk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHR0aGlzLl9waW5nUG9uZ1JlbmRlclRhcmdldCA9IF9jcmVhdGVSZW5kZXJUYXJnZXQoIHdpZHRoLCBoZWlnaHQsIHBhcmFtcyApO1xyXG5cclxuXHRcdFx0Y29uc3QgeyBfbG9kTWF4IH0gPSB0aGlzO1xyXG5cdFx0XHQoIHsgc2l6ZUxvZHM6IHRoaXMuX3NpemVMb2RzLCBsb2RQbGFuZXM6IHRoaXMuX2xvZFBsYW5lcywgc2lnbWFzOiB0aGlzLl9zaWdtYXMgfSA9IF9jcmVhdGVQbGFuZXMoIF9sb2RNYXggKSApO1xyXG5cclxuXHRcdFx0dGhpcy5fYmx1ck1hdGVyaWFsID0gX2dldEJsdXJTaGFkZXIoIF9sb2RNYXgsIHdpZHRoLCBoZWlnaHQgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIGN1YmVVVlJlbmRlclRhcmdldDtcclxuXHJcblx0fVxyXG5cclxuXHRfY29tcGlsZU1hdGVyaWFsKCBtYXRlcmlhbCApIHtcclxuXHJcblx0XHRjb25zdCB0bXBNZXNoID0gbmV3IE1lc2goIHRoaXMuX2xvZFBsYW5lc1sgMCBdLCBtYXRlcmlhbCApO1xyXG5cdFx0dGhpcy5fcmVuZGVyZXIuY29tcGlsZSggdG1wTWVzaCwgX2ZsYXRDYW1lcmEgKTtcclxuXHJcblx0fVxyXG5cclxuXHRfc2NlbmVUb0N1YmVVViggc2NlbmUsIG5lYXIsIGZhciwgY3ViZVVWUmVuZGVyVGFyZ2V0ICkge1xyXG5cclxuXHRcdGNvbnN0IGZvdiA9IDkwO1xyXG5cdFx0Y29uc3QgYXNwZWN0ID0gMTtcclxuXHRcdGNvbnN0IGN1YmVDYW1lcmEgPSBuZXcgUGVyc3BlY3RpdmVDYW1lcmEoIGZvdiwgYXNwZWN0LCBuZWFyLCBmYXIgKTtcclxuXHRcdGNvbnN0IHVwU2lnbiA9IFsgMSwgLSAxLCAxLCAxLCAxLCAxIF07XHJcblx0XHRjb25zdCBmb3J3YXJkU2lnbiA9IFsgMSwgMSwgMSwgLSAxLCAtIDEsIC0gMSBdO1xyXG5cdFx0Y29uc3QgcmVuZGVyZXIgPSB0aGlzLl9yZW5kZXJlcjtcclxuXHJcblx0XHRjb25zdCBvcmlnaW5hbEF1dG9DbGVhciA9IHJlbmRlcmVyLmF1dG9DbGVhcjtcclxuXHRcdGNvbnN0IHRvbmVNYXBwaW5nID0gcmVuZGVyZXIudG9uZU1hcHBpbmc7XHJcblx0XHRyZW5kZXJlci5nZXRDbGVhckNvbG9yKCBfY2xlYXJDb2xvciApO1xyXG5cclxuXHRcdHJlbmRlcmVyLnRvbmVNYXBwaW5nID0gTm9Ub25lTWFwcGluZztcclxuXHRcdHJlbmRlcmVyLmF1dG9DbGVhciA9IGZhbHNlO1xyXG5cclxuXHRcdGNvbnN0IGJhY2tncm91bmRNYXRlcmlhbCA9IG5ldyBNZXNoQmFzaWNNYXRlcmlhbCgge1xyXG5cdFx0XHRuYW1lOiAnUE1SRU0uQmFja2dyb3VuZCcsXHJcblx0XHRcdHNpZGU6IEJhY2tTaWRlLFxyXG5cdFx0XHRkZXB0aFdyaXRlOiBmYWxzZSxcclxuXHRcdFx0ZGVwdGhUZXN0OiBmYWxzZSxcclxuXHRcdH0gKTtcclxuXHJcblx0XHRjb25zdCBiYWNrZ3JvdW5kQm94ID0gbmV3IE1lc2goIG5ldyBCb3hHZW9tZXRyeSgpLCBiYWNrZ3JvdW5kTWF0ZXJpYWwgKTtcclxuXHJcblx0XHRsZXQgdXNlU29saWRDb2xvciA9IGZhbHNlO1xyXG5cdFx0Y29uc3QgYmFja2dyb3VuZCA9IHNjZW5lLmJhY2tncm91bmQ7XHJcblxyXG5cdFx0aWYgKCBiYWNrZ3JvdW5kICkge1xyXG5cclxuXHRcdFx0aWYgKCBiYWNrZ3JvdW5kLmlzQ29sb3IgKSB7XHJcblxyXG5cdFx0XHRcdGJhY2tncm91bmRNYXRlcmlhbC5jb2xvci5jb3B5KCBiYWNrZ3JvdW5kICk7XHJcblx0XHRcdFx0c2NlbmUuYmFja2dyb3VuZCA9IG51bGw7XHJcblx0XHRcdFx0dXNlU29saWRDb2xvciA9IHRydWU7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdGJhY2tncm91bmRNYXRlcmlhbC5jb2xvci5jb3B5KCBfY2xlYXJDb2xvciApO1xyXG5cdFx0XHR1c2VTb2xpZENvbG9yID0gdHJ1ZTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgNjsgaSArKyApIHtcclxuXHJcblx0XHRcdGNvbnN0IGNvbCA9IGkgJSAzO1xyXG5cclxuXHRcdFx0aWYgKCBjb2wgPT09IDAgKSB7XHJcblxyXG5cdFx0XHRcdGN1YmVDYW1lcmEudXAuc2V0KCAwLCB1cFNpZ25bIGkgXSwgMCApO1xyXG5cdFx0XHRcdGN1YmVDYW1lcmEubG9va0F0KCBmb3J3YXJkU2lnblsgaSBdLCAwLCAwICk7XHJcblxyXG5cdFx0XHR9IGVsc2UgaWYgKCBjb2wgPT09IDEgKSB7XHJcblxyXG5cdFx0XHRcdGN1YmVDYW1lcmEudXAuc2V0KCAwLCAwLCB1cFNpZ25bIGkgXSApO1xyXG5cdFx0XHRcdGN1YmVDYW1lcmEubG9va0F0KCAwLCBmb3J3YXJkU2lnblsgaSBdLCAwICk7XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRjdWJlQ2FtZXJhLnVwLnNldCggMCwgdXBTaWduWyBpIF0sIDAgKTtcclxuXHRcdFx0XHRjdWJlQ2FtZXJhLmxvb2tBdCggMCwgMCwgZm9yd2FyZFNpZ25bIGkgXSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Y29uc3Qgc2l6ZSA9IHRoaXMuX2N1YmVTaXplO1xyXG5cclxuXHRcdFx0X3NldFZpZXdwb3J0KCBjdWJlVVZSZW5kZXJUYXJnZXQsIGNvbCAqIHNpemUsIGkgPiAyID8gc2l6ZSA6IDAsIHNpemUsIHNpemUgKTtcclxuXHJcblx0XHRcdHJlbmRlcmVyLnNldFJlbmRlclRhcmdldCggY3ViZVVWUmVuZGVyVGFyZ2V0ICk7XHJcblxyXG5cdFx0XHRpZiAoIHVzZVNvbGlkQ29sb3IgKSB7XHJcblxyXG5cdFx0XHRcdHJlbmRlcmVyLnJlbmRlciggYmFja2dyb3VuZEJveCwgY3ViZUNhbWVyYSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0cmVuZGVyZXIucmVuZGVyKCBzY2VuZSwgY3ViZUNhbWVyYSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRiYWNrZ3JvdW5kQm94Lmdlb21ldHJ5LmRpc3Bvc2UoKTtcclxuXHRcdGJhY2tncm91bmRCb3gubWF0ZXJpYWwuZGlzcG9zZSgpO1xyXG5cclxuXHRcdHJlbmRlcmVyLnRvbmVNYXBwaW5nID0gdG9uZU1hcHBpbmc7XHJcblx0XHRyZW5kZXJlci5hdXRvQ2xlYXIgPSBvcmlnaW5hbEF1dG9DbGVhcjtcclxuXHRcdHNjZW5lLmJhY2tncm91bmQgPSBiYWNrZ3JvdW5kO1xyXG5cclxuXHR9XHJcblxyXG5cdF90ZXh0dXJlVG9DdWJlVVYoIHRleHR1cmUsIGN1YmVVVlJlbmRlclRhcmdldCApIHtcclxuXHJcblx0XHRjb25zdCByZW5kZXJlciA9IHRoaXMuX3JlbmRlcmVyO1xyXG5cclxuXHRcdGNvbnN0IGlzQ3ViZVRleHR1cmUgPSAoIHRleHR1cmUubWFwcGluZyA9PT0gQ3ViZVJlZmxlY3Rpb25NYXBwaW5nIHx8IHRleHR1cmUubWFwcGluZyA9PT0gQ3ViZVJlZnJhY3Rpb25NYXBwaW5nICk7XHJcblxyXG5cdFx0aWYgKCBpc0N1YmVUZXh0dXJlICkge1xyXG5cclxuXHRcdFx0aWYgKCB0aGlzLl9jdWJlbWFwTWF0ZXJpYWwgPT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdHRoaXMuX2N1YmVtYXBNYXRlcmlhbCA9IF9nZXRDdWJlbWFwTWF0ZXJpYWwoKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHRoaXMuX2N1YmVtYXBNYXRlcmlhbC51bmlmb3Jtcy5mbGlwRW52TWFwLnZhbHVlID0gKCB0ZXh0dXJlLmlzUmVuZGVyVGFyZ2V0VGV4dHVyZSA9PT0gZmFsc2UgKSA/IC0gMSA6IDE7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdGlmICggdGhpcy5fZXF1aXJlY3RNYXRlcmlhbCA9PT0gbnVsbCApIHtcclxuXHJcblx0XHRcdFx0dGhpcy5fZXF1aXJlY3RNYXRlcmlhbCA9IF9nZXRFcXVpcmVjdE1hdGVyaWFsKCk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGNvbnN0IG1hdGVyaWFsID0gaXNDdWJlVGV4dHVyZSA/IHRoaXMuX2N1YmVtYXBNYXRlcmlhbCA6IHRoaXMuX2VxdWlyZWN0TWF0ZXJpYWw7XHJcblx0XHRjb25zdCBtZXNoID0gbmV3IE1lc2goIHRoaXMuX2xvZFBsYW5lc1sgMCBdLCBtYXRlcmlhbCApO1xyXG5cclxuXHRcdGNvbnN0IHVuaWZvcm1zID0gbWF0ZXJpYWwudW5pZm9ybXM7XHJcblxyXG5cdFx0dW5pZm9ybXNbICdlbnZNYXAnIF0udmFsdWUgPSB0ZXh0dXJlO1xyXG5cclxuXHRcdGNvbnN0IHNpemUgPSB0aGlzLl9jdWJlU2l6ZTtcclxuXHJcblx0XHRfc2V0Vmlld3BvcnQoIGN1YmVVVlJlbmRlclRhcmdldCwgMCwgMCwgMyAqIHNpemUsIDIgKiBzaXplICk7XHJcblxyXG5cdFx0cmVuZGVyZXIuc2V0UmVuZGVyVGFyZ2V0KCBjdWJlVVZSZW5kZXJUYXJnZXQgKTtcclxuXHRcdHJlbmRlcmVyLnJlbmRlciggbWVzaCwgX2ZsYXRDYW1lcmEgKTtcclxuXHJcblx0fVxyXG5cclxuXHRfYXBwbHlQTVJFTSggY3ViZVVWUmVuZGVyVGFyZ2V0ICkge1xyXG5cclxuXHRcdGNvbnN0IHJlbmRlcmVyID0gdGhpcy5fcmVuZGVyZXI7XHJcblx0XHRjb25zdCBhdXRvQ2xlYXIgPSByZW5kZXJlci5hdXRvQ2xlYXI7XHJcblx0XHRyZW5kZXJlci5hdXRvQ2xlYXIgPSBmYWxzZTtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDE7IGkgPCB0aGlzLl9sb2RQbGFuZXMubGVuZ3RoOyBpICsrICkge1xyXG5cclxuXHRcdFx0Y29uc3Qgc2lnbWEgPSBNYXRoLnNxcnQoIHRoaXMuX3NpZ21hc1sgaSBdICogdGhpcy5fc2lnbWFzWyBpIF0gLSB0aGlzLl9zaWdtYXNbIGkgLSAxIF0gKiB0aGlzLl9zaWdtYXNbIGkgLSAxIF0gKTtcclxuXHJcblx0XHRcdGNvbnN0IHBvbGVBeGlzID0gX2F4aXNEaXJlY3Rpb25zWyAoIGkgLSAxICkgJSBfYXhpc0RpcmVjdGlvbnMubGVuZ3RoIF07XHJcblxyXG5cdFx0XHR0aGlzLl9ibHVyKCBjdWJlVVZSZW5kZXJUYXJnZXQsIGkgLSAxLCBpLCBzaWdtYSwgcG9sZUF4aXMgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmVuZGVyZXIuYXV0b0NsZWFyID0gYXV0b0NsZWFyO1xyXG5cclxuXHR9XHJcblxyXG5cdC8qKlxyXG5cdCAqIFRoaXMgaXMgYSB0d28tcGFzcyBHYXVzc2lhbiBibHVyIGZvciBhIGN1YmVtYXAuIE5vcm1hbGx5IHRoaXMgaXMgZG9uZVxyXG5cdCAqIHZlcnRpY2FsbHkgYW5kIGhvcml6b250YWxseSwgYnV0IHRoaXMgYnJlYWtzIGRvd24gb24gYSBjdWJlLiBIZXJlIHdlIGFwcGx5XHJcblx0ICogdGhlIGJsdXIgbGF0aXR1ZGluYWxseSAoYXJvdW5kIHRoZSBwb2xlcyksIGFuZCB0aGVuIGxvbmdpdHVkaW5hbGx5ICh0b3dhcmRzXHJcblx0ICogdGhlIHBvbGVzKSB0byBhcHByb3hpbWF0ZSB0aGUgb3J0aG9nb25hbGx5LXNlcGFyYWJsZSBibHVyLiBJdCBpcyBsZWFzdFxyXG5cdCAqIGFjY3VyYXRlIGF0IHRoZSBwb2xlcywgYnV0IHN0aWxsIGRvZXMgYSBkZWNlbnQgam9iLlxyXG5cdCAqL1xyXG5cdF9ibHVyKCBjdWJlVVZSZW5kZXJUYXJnZXQsIGxvZEluLCBsb2RPdXQsIHNpZ21hLCBwb2xlQXhpcyApIHtcclxuXHJcblx0XHRjb25zdCBwaW5nUG9uZ1JlbmRlclRhcmdldCA9IHRoaXMuX3BpbmdQb25nUmVuZGVyVGFyZ2V0O1xyXG5cclxuXHRcdHRoaXMuX2hhbGZCbHVyKFxyXG5cdFx0XHRjdWJlVVZSZW5kZXJUYXJnZXQsXHJcblx0XHRcdHBpbmdQb25nUmVuZGVyVGFyZ2V0LFxyXG5cdFx0XHRsb2RJbixcclxuXHRcdFx0bG9kT3V0LFxyXG5cdFx0XHRzaWdtYSxcclxuXHRcdFx0J2xhdGl0dWRpbmFsJyxcclxuXHRcdFx0cG9sZUF4aXMgKTtcclxuXHJcblx0XHR0aGlzLl9oYWxmQmx1cihcclxuXHRcdFx0cGluZ1BvbmdSZW5kZXJUYXJnZXQsXHJcblx0XHRcdGN1YmVVVlJlbmRlclRhcmdldCxcclxuXHRcdFx0bG9kT3V0LFxyXG5cdFx0XHRsb2RPdXQsXHJcblx0XHRcdHNpZ21hLFxyXG5cdFx0XHQnbG9uZ2l0dWRpbmFsJyxcclxuXHRcdFx0cG9sZUF4aXMgKTtcclxuXHJcblx0fVxyXG5cclxuXHRfaGFsZkJsdXIoIHRhcmdldEluLCB0YXJnZXRPdXQsIGxvZEluLCBsb2RPdXQsIHNpZ21hUmFkaWFucywgZGlyZWN0aW9uLCBwb2xlQXhpcyApIHtcclxuXHJcblx0XHRjb25zdCByZW5kZXJlciA9IHRoaXMuX3JlbmRlcmVyO1xyXG5cdFx0Y29uc3QgYmx1ck1hdGVyaWFsID0gdGhpcy5fYmx1ck1hdGVyaWFsO1xyXG5cclxuXHRcdGlmICggZGlyZWN0aW9uICE9PSAnbGF0aXR1ZGluYWwnICYmIGRpcmVjdGlvbiAhPT0gJ2xvbmdpdHVkaW5hbCcgKSB7XHJcblxyXG5cdFx0XHRjb25zb2xlLmVycm9yKFxyXG5cdFx0XHRcdCdibHVyIGRpcmVjdGlvbiBtdXN0IGJlIGVpdGhlciBsYXRpdHVkaW5hbCBvciBsb25naXR1ZGluYWwhJyApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvLyBOdW1iZXIgb2Ygc3RhbmRhcmQgZGV2aWF0aW9ucyBhdCB3aGljaCB0byBjdXQgb2ZmIHRoZSBkaXNjcmV0ZSBhcHByb3hpbWF0aW9uLlxyXG5cdFx0Y29uc3QgU1RBTkRBUkRfREVWSUFUSU9OUyA9IDM7XHJcblxyXG5cdFx0Y29uc3QgYmx1ck1lc2ggPSBuZXcgTWVzaCggdGhpcy5fbG9kUGxhbmVzWyBsb2RPdXQgXSwgYmx1ck1hdGVyaWFsICk7XHJcblx0XHRjb25zdCBibHVyVW5pZm9ybXMgPSBibHVyTWF0ZXJpYWwudW5pZm9ybXM7XHJcblxyXG5cdFx0Y29uc3QgcGl4ZWxzID0gdGhpcy5fc2l6ZUxvZHNbIGxvZEluIF0gLSAxO1xyXG5cdFx0Y29uc3QgcmFkaWFuc1BlclBpeGVsID0gaXNGaW5pdGUoIHNpZ21hUmFkaWFucyApID8gTWF0aC5QSSAvICggMiAqIHBpeGVscyApIDogMiAqIE1hdGguUEkgLyAoIDIgKiBNQVhfU0FNUExFUyAtIDEgKTtcclxuXHRcdGNvbnN0IHNpZ21hUGl4ZWxzID0gc2lnbWFSYWRpYW5zIC8gcmFkaWFuc1BlclBpeGVsO1xyXG5cdFx0Y29uc3Qgc2FtcGxlcyA9IGlzRmluaXRlKCBzaWdtYVJhZGlhbnMgKSA/IDEgKyBNYXRoLmZsb29yKCBTVEFOREFSRF9ERVZJQVRJT05TICogc2lnbWFQaXhlbHMgKSA6IE1BWF9TQU1QTEVTO1xyXG5cclxuXHRcdGlmICggc2FtcGxlcyA+IE1BWF9TQU1QTEVTICkge1xyXG5cclxuXHRcdFx0Y29uc29sZS53YXJuKCBgc2lnbWFSYWRpYW5zLCAke1xyXG5cdFx0XHRcdHNpZ21hUmFkaWFuc30sIGlzIHRvbyBsYXJnZSBhbmQgd2lsbCBjbGlwLCBhcyBpdCByZXF1ZXN0ZWQgJHtcclxuXHRcdFx0XHRzYW1wbGVzfSBzYW1wbGVzIHdoZW4gdGhlIG1heGltdW0gaXMgc2V0IHRvICR7TUFYX1NBTVBMRVN9YCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCB3ZWlnaHRzID0gW107XHJcblx0XHRsZXQgc3VtID0gMDtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBNQVhfU0FNUExFUzsgKysgaSApIHtcclxuXHJcblx0XHRcdGNvbnN0IHggPSBpIC8gc2lnbWFQaXhlbHM7XHJcblx0XHRcdGNvbnN0IHdlaWdodCA9IE1hdGguZXhwKCAtIHggKiB4IC8gMiApO1xyXG5cdFx0XHR3ZWlnaHRzLnB1c2goIHdlaWdodCApO1xyXG5cclxuXHRcdFx0aWYgKCBpID09PSAwICkge1xyXG5cclxuXHRcdFx0XHRzdW0gKz0gd2VpZ2h0O1xyXG5cclxuXHRcdFx0fSBlbHNlIGlmICggaSA8IHNhbXBsZXMgKSB7XHJcblxyXG5cdFx0XHRcdHN1bSArPSAyICogd2VpZ2h0O1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCB3ZWlnaHRzLmxlbmd0aDsgaSArKyApIHtcclxuXHJcblx0XHRcdHdlaWdodHNbIGkgXSA9IHdlaWdodHNbIGkgXSAvIHN1bTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ymx1clVuaWZvcm1zWyAnZW52TWFwJyBdLnZhbHVlID0gdGFyZ2V0SW4udGV4dHVyZTtcclxuXHRcdGJsdXJVbmlmb3Jtc1sgJ3NhbXBsZXMnIF0udmFsdWUgPSBzYW1wbGVzO1xyXG5cdFx0Ymx1clVuaWZvcm1zWyAnd2VpZ2h0cycgXS52YWx1ZSA9IHdlaWdodHM7XHJcblx0XHRibHVyVW5pZm9ybXNbICdsYXRpdHVkaW5hbCcgXS52YWx1ZSA9IGRpcmVjdGlvbiA9PT0gJ2xhdGl0dWRpbmFsJztcclxuXHJcblx0XHRpZiAoIHBvbGVBeGlzICkge1xyXG5cclxuXHRcdFx0Ymx1clVuaWZvcm1zWyAncG9sZUF4aXMnIF0udmFsdWUgPSBwb2xlQXhpcztcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Y29uc3QgeyBfbG9kTWF4IH0gPSB0aGlzO1xyXG5cdFx0Ymx1clVuaWZvcm1zWyAnZFRoZXRhJyBdLnZhbHVlID0gcmFkaWFuc1BlclBpeGVsO1xyXG5cdFx0Ymx1clVuaWZvcm1zWyAnbWlwSW50JyBdLnZhbHVlID0gX2xvZE1heCAtIGxvZEluO1xyXG5cclxuXHRcdGNvbnN0IG91dHB1dFNpemUgPSB0aGlzLl9zaXplTG9kc1sgbG9kT3V0IF07XHJcblx0XHRjb25zdCB4ID0gMyAqIG91dHB1dFNpemUgKiAoIGxvZE91dCA+IF9sb2RNYXggLSBMT0RfTUlOID8gbG9kT3V0IC0gX2xvZE1heCArIExPRF9NSU4gOiAwICk7XHJcblx0XHRjb25zdCB5ID0gNCAqICggdGhpcy5fY3ViZVNpemUgLSBvdXRwdXRTaXplICk7XHJcblxyXG5cdFx0X3NldFZpZXdwb3J0KCB0YXJnZXRPdXQsIHgsIHksIDMgKiBvdXRwdXRTaXplLCAyICogb3V0cHV0U2l6ZSApO1xyXG5cdFx0cmVuZGVyZXIuc2V0UmVuZGVyVGFyZ2V0KCB0YXJnZXRPdXQgKTtcclxuXHRcdHJlbmRlcmVyLnJlbmRlciggYmx1ck1lc2gsIF9mbGF0Q2FtZXJhICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcblxyXG5cclxuZnVuY3Rpb24gX2NyZWF0ZVBsYW5lcyggbG9kTWF4ICkge1xyXG5cclxuXHRjb25zdCBsb2RQbGFuZXMgPSBbXTtcclxuXHRjb25zdCBzaXplTG9kcyA9IFtdO1xyXG5cdGNvbnN0IHNpZ21hcyA9IFtdO1xyXG5cclxuXHRsZXQgbG9kID0gbG9kTWF4O1xyXG5cclxuXHRjb25zdCB0b3RhbExvZHMgPSBsb2RNYXggLSBMT0RfTUlOICsgMSArIEVYVFJBX0xPRF9TSUdNQS5sZW5ndGg7XHJcblxyXG5cdGZvciAoIGxldCBpID0gMDsgaSA8IHRvdGFsTG9kczsgaSArKyApIHtcclxuXHJcblx0XHRjb25zdCBzaXplTG9kID0gTWF0aC5wb3coIDIsIGxvZCApO1xyXG5cdFx0c2l6ZUxvZHMucHVzaCggc2l6ZUxvZCApO1xyXG5cdFx0bGV0IHNpZ21hID0gMS4wIC8gc2l6ZUxvZDtcclxuXHJcblx0XHRpZiAoIGkgPiBsb2RNYXggLSBMT0RfTUlOICkge1xyXG5cclxuXHRcdFx0c2lnbWEgPSBFWFRSQV9MT0RfU0lHTUFbIGkgLSBsb2RNYXggKyBMT0RfTUlOIC0gMSBdO1xyXG5cclxuXHRcdH0gZWxzZSBpZiAoIGkgPT09IDAgKSB7XHJcblxyXG5cdFx0XHRzaWdtYSA9IDA7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHNpZ21hcy5wdXNoKCBzaWdtYSApO1xyXG5cclxuXHRcdGNvbnN0IHRleGVsU2l6ZSA9IDEuMCAvICggc2l6ZUxvZCAtIDIgKTtcclxuXHRcdGNvbnN0IG1pbiA9IC0gdGV4ZWxTaXplO1xyXG5cdFx0Y29uc3QgbWF4ID0gMSArIHRleGVsU2l6ZTtcclxuXHRcdGNvbnN0IHV2MSA9IFsgbWluLCBtaW4sIG1heCwgbWluLCBtYXgsIG1heCwgbWluLCBtaW4sIG1heCwgbWF4LCBtaW4sIG1heCBdO1xyXG5cclxuXHRcdGNvbnN0IGN1YmVGYWNlcyA9IDY7XHJcblx0XHRjb25zdCB2ZXJ0aWNlcyA9IDY7XHJcblx0XHRjb25zdCBwb3NpdGlvblNpemUgPSAzO1xyXG5cdFx0Y29uc3QgdXZTaXplID0gMjtcclxuXHRcdGNvbnN0IGZhY2VJbmRleFNpemUgPSAxO1xyXG5cclxuXHRcdGNvbnN0IHBvc2l0aW9uID0gbmV3IEZsb2F0MzJBcnJheSggcG9zaXRpb25TaXplICogdmVydGljZXMgKiBjdWJlRmFjZXMgKTtcclxuXHRcdGNvbnN0IHV2ID0gbmV3IEZsb2F0MzJBcnJheSggdXZTaXplICogdmVydGljZXMgKiBjdWJlRmFjZXMgKTtcclxuXHRcdGNvbnN0IGZhY2VJbmRleCA9IG5ldyBGbG9hdDMyQXJyYXkoIGZhY2VJbmRleFNpemUgKiB2ZXJ0aWNlcyAqIGN1YmVGYWNlcyApO1xyXG5cclxuXHRcdGZvciAoIGxldCBmYWNlID0gMDsgZmFjZSA8IGN1YmVGYWNlczsgZmFjZSArKyApIHtcclxuXHJcblx0XHRcdGNvbnN0IHggPSAoIGZhY2UgJSAzICkgKiAyIC8gMyAtIDE7XHJcblx0XHRcdGNvbnN0IHkgPSBmYWNlID4gMiA/IDAgOiAtIDE7XHJcblx0XHRcdGNvbnN0IGNvb3JkaW5hdGVzID0gW1xyXG5cdFx0XHRcdHgsIHksIDAsXHJcblx0XHRcdFx0eCArIDIgLyAzLCB5LCAwLFxyXG5cdFx0XHRcdHggKyAyIC8gMywgeSArIDEsIDAsXHJcblx0XHRcdFx0eCwgeSwgMCxcclxuXHRcdFx0XHR4ICsgMiAvIDMsIHkgKyAxLCAwLFxyXG5cdFx0XHRcdHgsIHkgKyAxLCAwXHJcblx0XHRcdF07XHJcblx0XHRcdHBvc2l0aW9uLnNldCggY29vcmRpbmF0ZXMsIHBvc2l0aW9uU2l6ZSAqIHZlcnRpY2VzICogZmFjZSApO1xyXG5cdFx0XHR1di5zZXQoIHV2MSwgdXZTaXplICogdmVydGljZXMgKiBmYWNlICk7XHJcblx0XHRcdGNvbnN0IGZpbGwgPSBbIGZhY2UsIGZhY2UsIGZhY2UsIGZhY2UsIGZhY2UsIGZhY2UgXTtcclxuXHRcdFx0ZmFjZUluZGV4LnNldCggZmlsbCwgZmFjZUluZGV4U2l6ZSAqIHZlcnRpY2VzICogZmFjZSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCBwbGFuZXMgPSBuZXcgQnVmZmVyR2VvbWV0cnkoKTtcclxuXHRcdHBsYW5lcy5zZXRBdHRyaWJ1dGUoICdwb3NpdGlvbicsIG5ldyBCdWZmZXJBdHRyaWJ1dGUoIHBvc2l0aW9uLCBwb3NpdGlvblNpemUgKSApO1xyXG5cdFx0cGxhbmVzLnNldEF0dHJpYnV0ZSggJ3V2JywgbmV3IEJ1ZmZlckF0dHJpYnV0ZSggdXYsIHV2U2l6ZSApICk7XHJcblx0XHRwbGFuZXMuc2V0QXR0cmlidXRlKCAnZmFjZUluZGV4JywgbmV3IEJ1ZmZlckF0dHJpYnV0ZSggZmFjZUluZGV4LCBmYWNlSW5kZXhTaXplICkgKTtcclxuXHRcdGxvZFBsYW5lcy5wdXNoKCBwbGFuZXMgKTtcclxuXHJcblx0XHRpZiAoIGxvZCA+IExPRF9NSU4gKSB7XHJcblxyXG5cdFx0XHRsb2QgLS07XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdHJldHVybiB7IGxvZFBsYW5lcywgc2l6ZUxvZHMsIHNpZ21hcyB9O1xyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gX2NyZWF0ZVJlbmRlclRhcmdldCggd2lkdGgsIGhlaWdodCwgcGFyYW1zICkge1xyXG5cclxuXHRjb25zdCBjdWJlVVZSZW5kZXJUYXJnZXQgPSBuZXcgV2ViR0xSZW5kZXJUYXJnZXQoIHdpZHRoLCBoZWlnaHQsIHBhcmFtcyApO1xyXG5cdGN1YmVVVlJlbmRlclRhcmdldC50ZXh0dXJlLm1hcHBpbmcgPSBDdWJlVVZSZWZsZWN0aW9uTWFwcGluZztcclxuXHRjdWJlVVZSZW5kZXJUYXJnZXQudGV4dHVyZS5uYW1lID0gJ1BNUkVNLmN1YmVVdic7XHJcblx0Y3ViZVVWUmVuZGVyVGFyZ2V0LnNjaXNzb3JUZXN0ID0gdHJ1ZTtcclxuXHRyZXR1cm4gY3ViZVVWUmVuZGVyVGFyZ2V0O1xyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gX3NldFZpZXdwb3J0KCB0YXJnZXQsIHgsIHksIHdpZHRoLCBoZWlnaHQgKSB7XHJcblxyXG5cdHRhcmdldC52aWV3cG9ydC5zZXQoIHgsIHksIHdpZHRoLCBoZWlnaHQgKTtcclxuXHR0YXJnZXQuc2Npc3Nvci5zZXQoIHgsIHksIHdpZHRoLCBoZWlnaHQgKTtcclxuXHJcbn1cclxuXHJcbmZ1bmN0aW9uIF9nZXRCbHVyU2hhZGVyKCBsb2RNYXgsIHdpZHRoLCBoZWlnaHQgKSB7XHJcblxyXG5cdGNvbnN0IHdlaWdodHMgPSBuZXcgRmxvYXQzMkFycmF5KCBNQVhfU0FNUExFUyApO1xyXG5cdGNvbnN0IHBvbGVBeGlzID0gbmV3IFZlY3RvcjMoIDAsIDEsIDAgKTtcclxuXHRjb25zdCBzaGFkZXJNYXRlcmlhbCA9IG5ldyBTaGFkZXJNYXRlcmlhbCgge1xyXG5cclxuXHRcdG5hbWU6ICdTcGhlcmljYWxHYXVzc2lhbkJsdXInLFxyXG5cclxuXHRcdGRlZmluZXM6IHtcclxuXHRcdFx0J24nOiBNQVhfU0FNUExFUyxcclxuXHRcdFx0J0NVQkVVVl9URVhFTF9XSURUSCc6IDEuMCAvIHdpZHRoLFxyXG5cdFx0XHQnQ1VCRVVWX1RFWEVMX0hFSUdIVCc6IDEuMCAvIGhlaWdodCxcclxuXHRcdFx0J0NVQkVVVl9NQVhfTUlQJzogYCR7bG9kTWF4fS4wYCxcclxuXHRcdH0sXHJcblxyXG5cdFx0dW5pZm9ybXM6IHtcclxuXHRcdFx0J2Vudk1hcCc6IHsgdmFsdWU6IG51bGwgfSxcclxuXHRcdFx0J3NhbXBsZXMnOiB7IHZhbHVlOiAxIH0sXHJcblx0XHRcdCd3ZWlnaHRzJzogeyB2YWx1ZTogd2VpZ2h0cyB9LFxyXG5cdFx0XHQnbGF0aXR1ZGluYWwnOiB7IHZhbHVlOiBmYWxzZSB9LFxyXG5cdFx0XHQnZFRoZXRhJzogeyB2YWx1ZTogMCB9LFxyXG5cdFx0XHQnbWlwSW50JzogeyB2YWx1ZTogMCB9LFxyXG5cdFx0XHQncG9sZUF4aXMnOiB7IHZhbHVlOiBwb2xlQXhpcyB9XHJcblx0XHR9LFxyXG5cclxuXHRcdHZlcnRleFNoYWRlcjogX2dldENvbW1vblZlcnRleFNoYWRlcigpLFxyXG5cclxuXHRcdGZyYWdtZW50U2hhZGVyOiAvKiBnbHNsICovYFxyXG5cclxuXHRcdFx0cHJlY2lzaW9uIG1lZGl1bXAgZmxvYXQ7XHJcblx0XHRcdHByZWNpc2lvbiBtZWRpdW1wIGludDtcclxuXHJcblx0XHRcdHZhcnlpbmcgdmVjMyB2T3V0cHV0RGlyZWN0aW9uO1xyXG5cclxuXHRcdFx0dW5pZm9ybSBzYW1wbGVyMkQgZW52TWFwO1xyXG5cdFx0XHR1bmlmb3JtIGludCBzYW1wbGVzO1xyXG5cdFx0XHR1bmlmb3JtIGZsb2F0IHdlaWdodHNbIG4gXTtcclxuXHRcdFx0dW5pZm9ybSBib29sIGxhdGl0dWRpbmFsO1xyXG5cdFx0XHR1bmlmb3JtIGZsb2F0IGRUaGV0YTtcclxuXHRcdFx0dW5pZm9ybSBmbG9hdCBtaXBJbnQ7XHJcblx0XHRcdHVuaWZvcm0gdmVjMyBwb2xlQXhpcztcclxuXHJcblx0XHRcdCNkZWZpbmUgRU5WTUFQX1RZUEVfQ1VCRV9VVlxyXG5cdFx0XHQjaW5jbHVkZSA8Y3ViZV91dl9yZWZsZWN0aW9uX2ZyYWdtZW50PlxyXG5cclxuXHRcdFx0dmVjMyBnZXRTYW1wbGUoIGZsb2F0IHRoZXRhLCB2ZWMzIGF4aXMgKSB7XHJcblxyXG5cdFx0XHRcdGZsb2F0IGNvc1RoZXRhID0gY29zKCB0aGV0YSApO1xyXG5cdFx0XHRcdC8vIFJvZHJpZ3VlcycgYXhpcy1hbmdsZSByb3RhdGlvblxyXG5cdFx0XHRcdHZlYzMgc2FtcGxlRGlyZWN0aW9uID0gdk91dHB1dERpcmVjdGlvbiAqIGNvc1RoZXRhXHJcblx0XHRcdFx0XHQrIGNyb3NzKCBheGlzLCB2T3V0cHV0RGlyZWN0aW9uICkgKiBzaW4oIHRoZXRhIClcclxuXHRcdFx0XHRcdCsgYXhpcyAqIGRvdCggYXhpcywgdk91dHB1dERpcmVjdGlvbiApICogKCAxLjAgLSBjb3NUaGV0YSApO1xyXG5cclxuXHRcdFx0XHRyZXR1cm4gYmlsaW5lYXJDdWJlVVYoIGVudk1hcCwgc2FtcGxlRGlyZWN0aW9uLCBtaXBJbnQgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHZvaWQgbWFpbigpIHtcclxuXHJcblx0XHRcdFx0dmVjMyBheGlzID0gbGF0aXR1ZGluYWwgPyBwb2xlQXhpcyA6IGNyb3NzKCBwb2xlQXhpcywgdk91dHB1dERpcmVjdGlvbiApO1xyXG5cclxuXHRcdFx0XHRpZiAoIGFsbCggZXF1YWwoIGF4aXMsIHZlYzMoIDAuMCApICkgKSApIHtcclxuXHJcblx0XHRcdFx0XHRheGlzID0gdmVjMyggdk91dHB1dERpcmVjdGlvbi56LCAwLjAsIC0gdk91dHB1dERpcmVjdGlvbi54ICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0YXhpcyA9IG5vcm1hbGl6ZSggYXhpcyApO1xyXG5cclxuXHRcdFx0XHRnbF9GcmFnQ29sb3IgPSB2ZWM0KCAwLjAsIDAuMCwgMC4wLCAxLjAgKTtcclxuXHRcdFx0XHRnbF9GcmFnQ29sb3IucmdiICs9IHdlaWdodHNbIDAgXSAqIGdldFNhbXBsZSggMC4wLCBheGlzICk7XHJcblxyXG5cdFx0XHRcdGZvciAoIGludCBpID0gMTsgaSA8IG47IGkrKyApIHtcclxuXHJcblx0XHRcdFx0XHRpZiAoIGkgPj0gc2FtcGxlcyApIHtcclxuXHJcblx0XHRcdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRmbG9hdCB0aGV0YSA9IGRUaGV0YSAqIGZsb2F0KCBpICk7XHJcblx0XHRcdFx0XHRnbF9GcmFnQ29sb3IucmdiICs9IHdlaWdodHNbIGkgXSAqIGdldFNhbXBsZSggLTEuMCAqIHRoZXRhLCBheGlzICk7XHJcblx0XHRcdFx0XHRnbF9GcmFnQ29sb3IucmdiICs9IHdlaWdodHNbIGkgXSAqIGdldFNhbXBsZSggdGhldGEsIGF4aXMgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cdFx0YCxcclxuXHJcblx0XHRibGVuZGluZzogTm9CbGVuZGluZyxcclxuXHRcdGRlcHRoVGVzdDogZmFsc2UsXHJcblx0XHRkZXB0aFdyaXRlOiBmYWxzZVxyXG5cclxuXHR9ICk7XHJcblxyXG5cdHJldHVybiBzaGFkZXJNYXRlcmlhbDtcclxuXHJcbn1cclxuXHJcbmZ1bmN0aW9uIF9nZXRFcXVpcmVjdE1hdGVyaWFsKCkge1xyXG5cclxuXHRyZXR1cm4gbmV3IFNoYWRlck1hdGVyaWFsKCB7XHJcblxyXG5cdFx0bmFtZTogJ0VxdWlyZWN0YW5ndWxhclRvQ3ViZVVWJyxcclxuXHJcblx0XHR1bmlmb3Jtczoge1xyXG5cdFx0XHQnZW52TWFwJzogeyB2YWx1ZTogbnVsbCB9XHJcblx0XHR9LFxyXG5cclxuXHRcdHZlcnRleFNoYWRlcjogX2dldENvbW1vblZlcnRleFNoYWRlcigpLFxyXG5cclxuXHRcdGZyYWdtZW50U2hhZGVyOiAvKiBnbHNsICovYFxyXG5cclxuXHRcdFx0cHJlY2lzaW9uIG1lZGl1bXAgZmxvYXQ7XHJcblx0XHRcdHByZWNpc2lvbiBtZWRpdW1wIGludDtcclxuXHJcblx0XHRcdHZhcnlpbmcgdmVjMyB2T3V0cHV0RGlyZWN0aW9uO1xyXG5cclxuXHRcdFx0dW5pZm9ybSBzYW1wbGVyMkQgZW52TWFwO1xyXG5cclxuXHRcdFx0I2luY2x1ZGUgPGNvbW1vbj5cclxuXHJcblx0XHRcdHZvaWQgbWFpbigpIHtcclxuXHJcblx0XHRcdFx0dmVjMyBvdXRwdXREaXJlY3Rpb24gPSBub3JtYWxpemUoIHZPdXRwdXREaXJlY3Rpb24gKTtcclxuXHRcdFx0XHR2ZWMyIHV2ID0gZXF1aXJlY3RVdiggb3V0cHV0RGlyZWN0aW9uICk7XHJcblxyXG5cdFx0XHRcdGdsX0ZyYWdDb2xvciA9IHZlYzQoIHRleHR1cmUyRCAoIGVudk1hcCwgdXYgKS5yZ2IsIDEuMCApO1xyXG5cclxuXHRcdFx0fVxyXG5cdFx0YCxcclxuXHJcblx0XHRibGVuZGluZzogTm9CbGVuZGluZyxcclxuXHRcdGRlcHRoVGVzdDogZmFsc2UsXHJcblx0XHRkZXB0aFdyaXRlOiBmYWxzZVxyXG5cclxuXHR9ICk7XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiBfZ2V0Q3ViZW1hcE1hdGVyaWFsKCkge1xyXG5cclxuXHRyZXR1cm4gbmV3IFNoYWRlck1hdGVyaWFsKCB7XHJcblxyXG5cdFx0bmFtZTogJ0N1YmVtYXBUb0N1YmVVVicsXHJcblxyXG5cdFx0dW5pZm9ybXM6IHtcclxuXHRcdFx0J2Vudk1hcCc6IHsgdmFsdWU6IG51bGwgfSxcclxuXHRcdFx0J2ZsaXBFbnZNYXAnOiB7IHZhbHVlOiAtIDEgfVxyXG5cdFx0fSxcclxuXHJcblx0XHR2ZXJ0ZXhTaGFkZXI6IF9nZXRDb21tb25WZXJ0ZXhTaGFkZXIoKSxcclxuXHJcblx0XHRmcmFnbWVudFNoYWRlcjogLyogZ2xzbCAqL2BcclxuXHJcblx0XHRcdHByZWNpc2lvbiBtZWRpdW1wIGZsb2F0O1xyXG5cdFx0XHRwcmVjaXNpb24gbWVkaXVtcCBpbnQ7XHJcblxyXG5cdFx0XHR1bmlmb3JtIGZsb2F0IGZsaXBFbnZNYXA7XHJcblxyXG5cdFx0XHR2YXJ5aW5nIHZlYzMgdk91dHB1dERpcmVjdGlvbjtcclxuXHJcblx0XHRcdHVuaWZvcm0gc2FtcGxlckN1YmUgZW52TWFwO1xyXG5cclxuXHRcdFx0dm9pZCBtYWluKCkge1xyXG5cclxuXHRcdFx0XHRnbF9GcmFnQ29sb3IgPSB0ZXh0dXJlQ3ViZSggZW52TWFwLCB2ZWMzKCBmbGlwRW52TWFwICogdk91dHB1dERpcmVjdGlvbi54LCB2T3V0cHV0RGlyZWN0aW9uLnl6ICkgKTtcclxuXHJcblx0XHRcdH1cclxuXHRcdGAsXHJcblxyXG5cdFx0YmxlbmRpbmc6IE5vQmxlbmRpbmcsXHJcblx0XHRkZXB0aFRlc3Q6IGZhbHNlLFxyXG5cdFx0ZGVwdGhXcml0ZTogZmFsc2VcclxuXHJcblx0fSApO1xyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gX2dldENvbW1vblZlcnRleFNoYWRlcigpIHtcclxuXHJcblx0cmV0dXJuIC8qIGdsc2wgKi9gXHJcblxyXG5cdFx0cHJlY2lzaW9uIG1lZGl1bXAgZmxvYXQ7XHJcblx0XHRwcmVjaXNpb24gbWVkaXVtcCBpbnQ7XHJcblxyXG5cdFx0YXR0cmlidXRlIGZsb2F0IGZhY2VJbmRleDtcclxuXHJcblx0XHR2YXJ5aW5nIHZlYzMgdk91dHB1dERpcmVjdGlvbjtcclxuXHJcblx0XHQvLyBSSCBjb29yZGluYXRlIHN5c3RlbTsgUE1SRU0gZmFjZS1pbmRleGluZyBjb252ZW50aW9uXHJcblx0XHR2ZWMzIGdldERpcmVjdGlvbiggdmVjMiB1diwgZmxvYXQgZmFjZSApIHtcclxuXHJcblx0XHRcdHV2ID0gMi4wICogdXYgLSAxLjA7XHJcblxyXG5cdFx0XHR2ZWMzIGRpcmVjdGlvbiA9IHZlYzMoIHV2LCAxLjAgKTtcclxuXHJcblx0XHRcdGlmICggZmFjZSA9PSAwLjAgKSB7XHJcblxyXG5cdFx0XHRcdGRpcmVjdGlvbiA9IGRpcmVjdGlvbi56eXg7IC8vICggMSwgdiwgdSApIHBvcyB4XHJcblxyXG5cdFx0XHR9IGVsc2UgaWYgKCBmYWNlID09IDEuMCApIHtcclxuXHJcblx0XHRcdFx0ZGlyZWN0aW9uID0gZGlyZWN0aW9uLnh6eTtcclxuXHRcdFx0XHRkaXJlY3Rpb24ueHogKj0gLTEuMDsgLy8gKCAtdSwgMSwgLXYgKSBwb3MgeVxyXG5cclxuXHRcdFx0fSBlbHNlIGlmICggZmFjZSA9PSAyLjAgKSB7XHJcblxyXG5cdFx0XHRcdGRpcmVjdGlvbi54ICo9IC0xLjA7IC8vICggLXUsIHYsIDEgKSBwb3MgelxyXG5cclxuXHRcdFx0fSBlbHNlIGlmICggZmFjZSA9PSAzLjAgKSB7XHJcblxyXG5cdFx0XHRcdGRpcmVjdGlvbiA9IGRpcmVjdGlvbi56eXg7XHJcblx0XHRcdFx0ZGlyZWN0aW9uLnh6ICo9IC0xLjA7IC8vICggLTEsIHYsIC11ICkgbmVnIHhcclxuXHJcblx0XHRcdH0gZWxzZSBpZiAoIGZhY2UgPT0gNC4wICkge1xyXG5cclxuXHRcdFx0XHRkaXJlY3Rpb24gPSBkaXJlY3Rpb24ueHp5O1xyXG5cdFx0XHRcdGRpcmVjdGlvbi54eSAqPSAtMS4wOyAvLyAoIC11LCAtMSwgdiApIG5lZyB5XHJcblxyXG5cdFx0XHR9IGVsc2UgaWYgKCBmYWNlID09IDUuMCApIHtcclxuXHJcblx0XHRcdFx0ZGlyZWN0aW9uLnogKj0gLTEuMDsgLy8gKCB1LCB2LCAtMSApIG5lZyB6XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRyZXR1cm4gZGlyZWN0aW9uO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHR2b2lkIG1haW4oKSB7XHJcblxyXG5cdFx0XHR2T3V0cHV0RGlyZWN0aW9uID0gZ2V0RGlyZWN0aW9uKCB1diwgZmFjZUluZGV4ICk7XHJcblx0XHRcdGdsX1Bvc2l0aW9uID0gdmVjNCggcG9zaXRpb24sIDEuMCApO1xyXG5cclxuXHRcdH1cclxuXHRgO1xyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgUE1SRU1HZW5lcmF0b3IgfTtcclxuIiwiaW1wb3J0IHsgQ3ViZVJlZmxlY3Rpb25NYXBwaW5nLCBDdWJlUmVmcmFjdGlvbk1hcHBpbmcsIEVxdWlyZWN0YW5ndWxhclJlZmxlY3Rpb25NYXBwaW5nLCBFcXVpcmVjdGFuZ3VsYXJSZWZyYWN0aW9uTWFwcGluZyB9IGZyb20gJy4uLy4uL2NvbnN0YW50cy5qcyc7XHJcbmltcG9ydCB7IFBNUkVNR2VuZXJhdG9yIH0gZnJvbSAnLi4vLi4vZXh0cmFzL1BNUkVNR2VuZXJhdG9yLmpzJztcclxuXHJcbmZ1bmN0aW9uIFdlYkdMQ3ViZVVWTWFwcyggcmVuZGVyZXIgKSB7XHJcblxyXG5cdGxldCBjdWJlVVZtYXBzID0gbmV3IFdlYWtNYXAoKTtcclxuXHJcblx0bGV0IHBtcmVtR2VuZXJhdG9yID0gbnVsbDtcclxuXHJcblx0ZnVuY3Rpb24gZ2V0KCB0ZXh0dXJlICkge1xyXG5cclxuXHRcdGlmICggdGV4dHVyZSAmJiB0ZXh0dXJlLmlzVGV4dHVyZSApIHtcclxuXHJcblx0XHRcdGNvbnN0IG1hcHBpbmcgPSB0ZXh0dXJlLm1hcHBpbmc7XHJcblxyXG5cdFx0XHRjb25zdCBpc0VxdWlyZWN0TWFwID0gKCBtYXBwaW5nID09PSBFcXVpcmVjdGFuZ3VsYXJSZWZsZWN0aW9uTWFwcGluZyB8fCBtYXBwaW5nID09PSBFcXVpcmVjdGFuZ3VsYXJSZWZyYWN0aW9uTWFwcGluZyApO1xyXG5cdFx0XHRjb25zdCBpc0N1YmVNYXAgPSAoIG1hcHBpbmcgPT09IEN1YmVSZWZsZWN0aW9uTWFwcGluZyB8fCBtYXBwaW5nID09PSBDdWJlUmVmcmFjdGlvbk1hcHBpbmcgKTtcclxuXHJcblx0XHRcdC8vIGVxdWlyZWN0L2N1YmUgbWFwIHRvIGN1YmVVViBjb252ZXJzaW9uXHJcblxyXG5cdFx0XHRpZiAoIGlzRXF1aXJlY3RNYXAgfHwgaXNDdWJlTWFwICkge1xyXG5cclxuXHRcdFx0XHRpZiAoIHRleHR1cmUuaXNSZW5kZXJUYXJnZXRUZXh0dXJlICYmIHRleHR1cmUubmVlZHNQTVJFTVVwZGF0ZSA9PT0gdHJ1ZSApIHtcclxuXHJcblx0XHRcdFx0XHR0ZXh0dXJlLm5lZWRzUE1SRU1VcGRhdGUgPSBmYWxzZTtcclxuXHJcblx0XHRcdFx0XHRsZXQgcmVuZGVyVGFyZ2V0ID0gY3ViZVVWbWFwcy5nZXQoIHRleHR1cmUgKTtcclxuXHJcblx0XHRcdFx0XHRpZiAoIHBtcmVtR2VuZXJhdG9yID09PSBudWxsICkgcG1yZW1HZW5lcmF0b3IgPSBuZXcgUE1SRU1HZW5lcmF0b3IoIHJlbmRlcmVyICk7XHJcblxyXG5cdFx0XHRcdFx0cmVuZGVyVGFyZ2V0ID0gaXNFcXVpcmVjdE1hcCA/IHBtcmVtR2VuZXJhdG9yLmZyb21FcXVpcmVjdGFuZ3VsYXIoIHRleHR1cmUsIHJlbmRlclRhcmdldCApIDogcG1yZW1HZW5lcmF0b3IuZnJvbUN1YmVtYXAoIHRleHR1cmUsIHJlbmRlclRhcmdldCApO1xyXG5cdFx0XHRcdFx0Y3ViZVVWbWFwcy5zZXQoIHRleHR1cmUsIHJlbmRlclRhcmdldCApO1xyXG5cclxuXHRcdFx0XHRcdHJldHVybiByZW5kZXJUYXJnZXQudGV4dHVyZTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRpZiAoIGN1YmVVVm1hcHMuaGFzKCB0ZXh0dXJlICkgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRyZXR1cm4gY3ViZVVWbWFwcy5nZXQoIHRleHR1cmUgKS50ZXh0dXJlO1xyXG5cclxuXHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHRjb25zdCBpbWFnZSA9IHRleHR1cmUuaW1hZ2U7XHJcblxyXG5cdFx0XHRcdFx0XHRpZiAoICggaXNFcXVpcmVjdE1hcCAmJiBpbWFnZSAmJiBpbWFnZS5oZWlnaHQgPiAwICkgfHwgKCBpc0N1YmVNYXAgJiYgaW1hZ2UgJiYgaXNDdWJlVGV4dHVyZUNvbXBsZXRlKCBpbWFnZSApICkgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdGlmICggcG1yZW1HZW5lcmF0b3IgPT09IG51bGwgKSBwbXJlbUdlbmVyYXRvciA9IG5ldyBQTVJFTUdlbmVyYXRvciggcmVuZGVyZXIgKTtcclxuXHJcblx0XHRcdFx0XHRcdFx0Y29uc3QgcmVuZGVyVGFyZ2V0ID0gaXNFcXVpcmVjdE1hcCA/IHBtcmVtR2VuZXJhdG9yLmZyb21FcXVpcmVjdGFuZ3VsYXIoIHRleHR1cmUgKSA6IHBtcmVtR2VuZXJhdG9yLmZyb21DdWJlbWFwKCB0ZXh0dXJlICk7XHJcblx0XHRcdFx0XHRcdFx0Y3ViZVVWbWFwcy5zZXQoIHRleHR1cmUsIHJlbmRlclRhcmdldCApO1xyXG5cclxuXHRcdFx0XHRcdFx0XHR0ZXh0dXJlLmFkZEV2ZW50TGlzdGVuZXIoICdkaXNwb3NlJywgb25UZXh0dXJlRGlzcG9zZSApO1xyXG5cclxuXHRcdFx0XHRcdFx0XHRyZXR1cm4gcmVuZGVyVGFyZ2V0LnRleHR1cmU7XHJcblxyXG5cdFx0XHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdFx0XHQvLyBpbWFnZSBub3QgeWV0IHJlYWR5LiB0cnkgdGhlIGNvbnZlcnNpb24gbmV4dCBmcmFtZVxyXG5cclxuXHRcdFx0XHRcdFx0XHRyZXR1cm4gbnVsbDtcclxuXHJcblx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRleHR1cmU7XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gaXNDdWJlVGV4dHVyZUNvbXBsZXRlKCBpbWFnZSApIHtcclxuXHJcblx0XHRsZXQgY291bnQgPSAwO1xyXG5cdFx0Y29uc3QgbGVuZ3RoID0gNjtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBsZW5ndGg7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRpZiAoIGltYWdlWyBpIF0gIT09IHVuZGVmaW5lZCApIGNvdW50ICsrO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gY291bnQgPT09IGxlbmd0aDtcclxuXHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gb25UZXh0dXJlRGlzcG9zZSggZXZlbnQgKSB7XHJcblxyXG5cdFx0Y29uc3QgdGV4dHVyZSA9IGV2ZW50LnRhcmdldDtcclxuXHJcblx0XHR0ZXh0dXJlLnJlbW92ZUV2ZW50TGlzdGVuZXIoICdkaXNwb3NlJywgb25UZXh0dXJlRGlzcG9zZSApO1xyXG5cclxuXHRcdGNvbnN0IGN1YmVtYXBVViA9IGN1YmVVVm1hcHMuZ2V0KCB0ZXh0dXJlICk7XHJcblxyXG5cdFx0aWYgKCBjdWJlbWFwVVYgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdGN1YmVVVm1hcHMuZGVsZXRlKCB0ZXh0dXJlICk7XHJcblx0XHRcdGN1YmVtYXBVVi5kaXNwb3NlKCk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIGRpc3Bvc2UoKSB7XHJcblxyXG5cdFx0Y3ViZVVWbWFwcyA9IG5ldyBXZWFrTWFwKCk7XHJcblxyXG5cdFx0aWYgKCBwbXJlbUdlbmVyYXRvciAhPT0gbnVsbCApIHtcclxuXHJcblx0XHRcdHBtcmVtR2VuZXJhdG9yLmRpc3Bvc2UoKTtcclxuXHRcdFx0cG1yZW1HZW5lcmF0b3IgPSBudWxsO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4ge1xyXG5cdFx0Z2V0OiBnZXQsXHJcblx0XHRkaXNwb3NlOiBkaXNwb3NlXHJcblx0fTtcclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IFdlYkdMQ3ViZVVWTWFwcyB9O1xyXG4iLCJmdW5jdGlvbiBXZWJHTEV4dGVuc2lvbnMoIGdsICkge1xyXG5cclxuXHRjb25zdCBleHRlbnNpb25zID0ge307XHJcblxyXG5cdGZ1bmN0aW9uIGdldEV4dGVuc2lvbiggbmFtZSApIHtcclxuXHJcblx0XHRpZiAoIGV4dGVuc2lvbnNbIG5hbWUgXSAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0cmV0dXJuIGV4dGVuc2lvbnNbIG5hbWUgXTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0bGV0IGV4dGVuc2lvbjtcclxuXHJcblx0XHRzd2l0Y2ggKCBuYW1lICkge1xyXG5cclxuXHRcdFx0Y2FzZSAnV0VCR0xfZGVwdGhfdGV4dHVyZSc6XHJcblx0XHRcdFx0ZXh0ZW5zaW9uID0gZ2wuZ2V0RXh0ZW5zaW9uKCAnV0VCR0xfZGVwdGhfdGV4dHVyZScgKSB8fCBnbC5nZXRFeHRlbnNpb24oICdNT1pfV0VCR0xfZGVwdGhfdGV4dHVyZScgKSB8fCBnbC5nZXRFeHRlbnNpb24oICdXRUJLSVRfV0VCR0xfZGVwdGhfdGV4dHVyZScgKTtcclxuXHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdGNhc2UgJ0VYVF90ZXh0dXJlX2ZpbHRlcl9hbmlzb3Ryb3BpYyc6XHJcblx0XHRcdFx0ZXh0ZW5zaW9uID0gZ2wuZ2V0RXh0ZW5zaW9uKCAnRVhUX3RleHR1cmVfZmlsdGVyX2FuaXNvdHJvcGljJyApIHx8IGdsLmdldEV4dGVuc2lvbiggJ01PWl9FWFRfdGV4dHVyZV9maWx0ZXJfYW5pc290cm9waWMnICkgfHwgZ2wuZ2V0RXh0ZW5zaW9uKCAnV0VCS0lUX0VYVF90ZXh0dXJlX2ZpbHRlcl9hbmlzb3Ryb3BpYycgKTtcclxuXHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdGNhc2UgJ1dFQkdMX2NvbXByZXNzZWRfdGV4dHVyZV9zM3RjJzpcclxuXHRcdFx0XHRleHRlbnNpb24gPSBnbC5nZXRFeHRlbnNpb24oICdXRUJHTF9jb21wcmVzc2VkX3RleHR1cmVfczN0YycgKSB8fCBnbC5nZXRFeHRlbnNpb24oICdNT1pfV0VCR0xfY29tcHJlc3NlZF90ZXh0dXJlX3MzdGMnICkgfHwgZ2wuZ2V0RXh0ZW5zaW9uKCAnV0VCS0lUX1dFQkdMX2NvbXByZXNzZWRfdGV4dHVyZV9zM3RjJyApO1xyXG5cdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0Y2FzZSAnV0VCR0xfY29tcHJlc3NlZF90ZXh0dXJlX3B2cnRjJzpcclxuXHRcdFx0XHRleHRlbnNpb24gPSBnbC5nZXRFeHRlbnNpb24oICdXRUJHTF9jb21wcmVzc2VkX3RleHR1cmVfcHZydGMnICkgfHwgZ2wuZ2V0RXh0ZW5zaW9uKCAnV0VCS0lUX1dFQkdMX2NvbXByZXNzZWRfdGV4dHVyZV9wdnJ0YycgKTtcclxuXHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdGRlZmF1bHQ6XHJcblx0XHRcdFx0ZXh0ZW5zaW9uID0gZ2wuZ2V0RXh0ZW5zaW9uKCBuYW1lICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGV4dGVuc2lvbnNbIG5hbWUgXSA9IGV4dGVuc2lvbjtcclxuXHJcblx0XHRyZXR1cm4gZXh0ZW5zaW9uO1xyXG5cclxuXHR9XHJcblxyXG5cdHJldHVybiB7XHJcblxyXG5cdFx0aGFzOiBmdW5jdGlvbiAoIG5hbWUgKSB7XHJcblxyXG5cdFx0XHRyZXR1cm4gZ2V0RXh0ZW5zaW9uKCBuYW1lICkgIT09IG51bGw7XHJcblxyXG5cdFx0fSxcclxuXHJcblx0XHRpbml0OiBmdW5jdGlvbiAoIGNhcGFiaWxpdGllcyApIHtcclxuXHJcblx0XHRcdGlmICggY2FwYWJpbGl0aWVzLmlzV2ViR0wyICkge1xyXG5cclxuXHRcdFx0XHRnZXRFeHRlbnNpb24oICdFWFRfY29sb3JfYnVmZmVyX2Zsb2F0JyApO1xyXG5cdFx0XHRcdGdldEV4dGVuc2lvbiggJ1dFQkdMX2NsaXBfY3VsbF9kaXN0YW5jZScgKTtcclxuXHJcblx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdGdldEV4dGVuc2lvbiggJ1dFQkdMX2RlcHRoX3RleHR1cmUnICk7XHJcblx0XHRcdFx0Z2V0RXh0ZW5zaW9uKCAnT0VTX3RleHR1cmVfZmxvYXQnICk7XHJcblx0XHRcdFx0Z2V0RXh0ZW5zaW9uKCAnT0VTX3RleHR1cmVfaGFsZl9mbG9hdCcgKTtcclxuXHRcdFx0XHRnZXRFeHRlbnNpb24oICdPRVNfdGV4dHVyZV9oYWxmX2Zsb2F0X2xpbmVhcicgKTtcclxuXHRcdFx0XHRnZXRFeHRlbnNpb24oICdPRVNfc3RhbmRhcmRfZGVyaXZhdGl2ZXMnICk7XHJcblx0XHRcdFx0Z2V0RXh0ZW5zaW9uKCAnT0VTX2VsZW1lbnRfaW5kZXhfdWludCcgKTtcclxuXHRcdFx0XHRnZXRFeHRlbnNpb24oICdPRVNfdmVydGV4X2FycmF5X29iamVjdCcgKTtcclxuXHRcdFx0XHRnZXRFeHRlbnNpb24oICdBTkdMRV9pbnN0YW5jZWRfYXJyYXlzJyApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Z2V0RXh0ZW5zaW9uKCAnT0VTX3RleHR1cmVfZmxvYXRfbGluZWFyJyApO1xyXG5cdFx0XHRnZXRFeHRlbnNpb24oICdFWFRfY29sb3JfYnVmZmVyX2hhbGZfZmxvYXQnICk7XHJcblx0XHRcdGdldEV4dGVuc2lvbiggJ1dFQkdMX211bHRpc2FtcGxlZF9yZW5kZXJfdG9fdGV4dHVyZScgKTtcclxuXHJcblx0XHR9LFxyXG5cclxuXHRcdGdldDogZnVuY3Rpb24gKCBuYW1lICkge1xyXG5cclxuXHRcdFx0Y29uc3QgZXh0ZW5zaW9uID0gZ2V0RXh0ZW5zaW9uKCBuYW1lICk7XHJcblxyXG5cdFx0XHRpZiAoIGV4dGVuc2lvbiA9PT0gbnVsbCApIHtcclxuXHJcblx0XHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuV2ViR0xSZW5kZXJlcjogJyArIG5hbWUgKyAnIGV4dGVuc2lvbiBub3Qgc3VwcG9ydGVkLicgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHJldHVybiBleHRlbnNpb247XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9O1xyXG5cclxufVxyXG5cclxuXHJcbmV4cG9ydCB7IFdlYkdMRXh0ZW5zaW9ucyB9O1xyXG4iLCJpbXBvcnQgeyBVaW50MTZCdWZmZXJBdHRyaWJ1dGUsIFVpbnQzMkJ1ZmZlckF0dHJpYnV0ZSB9IGZyb20gJy4uLy4uL2NvcmUvQnVmZmVyQXR0cmlidXRlLmpzJztcclxuaW1wb3J0IHsgYXJyYXlOZWVkc1VpbnQzMiB9IGZyb20gJy4uLy4uL3V0aWxzLmpzJztcclxuXHJcbmZ1bmN0aW9uIFdlYkdMR2VvbWV0cmllcyggZ2wsIGF0dHJpYnV0ZXMsIGluZm8sIGJpbmRpbmdTdGF0ZXMgKSB7XHJcblxyXG5cdGNvbnN0IGdlb21ldHJpZXMgPSB7fTtcclxuXHRjb25zdCB3aXJlZnJhbWVBdHRyaWJ1dGVzID0gbmV3IFdlYWtNYXAoKTtcclxuXHJcblx0ZnVuY3Rpb24gb25HZW9tZXRyeURpc3Bvc2UoIGV2ZW50ICkge1xyXG5cclxuXHRcdGNvbnN0IGdlb21ldHJ5ID0gZXZlbnQudGFyZ2V0O1xyXG5cclxuXHRcdGlmICggZ2VvbWV0cnkuaW5kZXggIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRhdHRyaWJ1dGVzLnJlbW92ZSggZ2VvbWV0cnkuaW5kZXggKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Zm9yICggY29uc3QgbmFtZSBpbiBnZW9tZXRyeS5hdHRyaWJ1dGVzICkge1xyXG5cclxuXHRcdFx0YXR0cmlidXRlcy5yZW1vdmUoIGdlb21ldHJ5LmF0dHJpYnV0ZXNbIG5hbWUgXSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRmb3IgKCBjb25zdCBuYW1lIGluIGdlb21ldHJ5Lm1vcnBoQXR0cmlidXRlcyApIHtcclxuXHJcblx0XHRcdGNvbnN0IGFycmF5ID0gZ2VvbWV0cnkubW9ycGhBdHRyaWJ1dGVzWyBuYW1lIF07XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBhcnJheS5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRhdHRyaWJ1dGVzLnJlbW92ZSggYXJyYXlbIGkgXSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRnZW9tZXRyeS5yZW1vdmVFdmVudExpc3RlbmVyKCAnZGlzcG9zZScsIG9uR2VvbWV0cnlEaXNwb3NlICk7XHJcblxyXG5cdFx0ZGVsZXRlIGdlb21ldHJpZXNbIGdlb21ldHJ5LmlkIF07XHJcblxyXG5cdFx0Y29uc3QgYXR0cmlidXRlID0gd2lyZWZyYW1lQXR0cmlidXRlcy5nZXQoIGdlb21ldHJ5ICk7XHJcblxyXG5cdFx0aWYgKCBhdHRyaWJ1dGUgKSB7XHJcblxyXG5cdFx0XHRhdHRyaWJ1dGVzLnJlbW92ZSggYXR0cmlidXRlICk7XHJcblx0XHRcdHdpcmVmcmFtZUF0dHJpYnV0ZXMuZGVsZXRlKCBnZW9tZXRyeSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRiaW5kaW5nU3RhdGVzLnJlbGVhc2VTdGF0ZXNPZkdlb21ldHJ5KCBnZW9tZXRyeSApO1xyXG5cclxuXHRcdGlmICggZ2VvbWV0cnkuaXNJbnN0YW5jZWRCdWZmZXJHZW9tZXRyeSA9PT0gdHJ1ZSApIHtcclxuXHJcblx0XHRcdGRlbGV0ZSBnZW9tZXRyeS5fbWF4SW5zdGFuY2VDb3VudDtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly9cclxuXHJcblx0XHRpbmZvLm1lbW9yeS5nZW9tZXRyaWVzIC0tO1xyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIGdldCggb2JqZWN0LCBnZW9tZXRyeSApIHtcclxuXHJcblx0XHRpZiAoIGdlb21ldHJpZXNbIGdlb21ldHJ5LmlkIF0gPT09IHRydWUgKSByZXR1cm4gZ2VvbWV0cnk7XHJcblxyXG5cdFx0Z2VvbWV0cnkuYWRkRXZlbnRMaXN0ZW5lciggJ2Rpc3Bvc2UnLCBvbkdlb21ldHJ5RGlzcG9zZSApO1xyXG5cclxuXHRcdGdlb21ldHJpZXNbIGdlb21ldHJ5LmlkIF0gPSB0cnVlO1xyXG5cclxuXHRcdGluZm8ubWVtb3J5Lmdlb21ldHJpZXMgKys7XHJcblxyXG5cdFx0cmV0dXJuIGdlb21ldHJ5O1xyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHVwZGF0ZSggZ2VvbWV0cnkgKSB7XHJcblxyXG5cdFx0Y29uc3QgZ2VvbWV0cnlBdHRyaWJ1dGVzID0gZ2VvbWV0cnkuYXR0cmlidXRlcztcclxuXHJcblx0XHQvLyBVcGRhdGluZyBpbmRleCBidWZmZXIgaW4gVkFPIG5vdy4gU2VlIFdlYkdMQmluZGluZ1N0YXRlcy5cclxuXHJcblx0XHRmb3IgKCBjb25zdCBuYW1lIGluIGdlb21ldHJ5QXR0cmlidXRlcyApIHtcclxuXHJcblx0XHRcdGF0dHJpYnV0ZXMudXBkYXRlKCBnZW9tZXRyeUF0dHJpYnV0ZXNbIG5hbWUgXSwgZ2wuQVJSQVlfQlVGRkVSICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIG1vcnBoIHRhcmdldHNcclxuXHJcblx0XHRjb25zdCBtb3JwaEF0dHJpYnV0ZXMgPSBnZW9tZXRyeS5tb3JwaEF0dHJpYnV0ZXM7XHJcblxyXG5cdFx0Zm9yICggY29uc3QgbmFtZSBpbiBtb3JwaEF0dHJpYnV0ZXMgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBhcnJheSA9IG1vcnBoQXR0cmlidXRlc1sgbmFtZSBdO1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gYXJyYXkubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0YXR0cmlidXRlcy51cGRhdGUoIGFycmF5WyBpIF0sIGdsLkFSUkFZX0JVRkZFUiApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiB1cGRhdGVXaXJlZnJhbWVBdHRyaWJ1dGUoIGdlb21ldHJ5ICkge1xyXG5cclxuXHRcdGNvbnN0IGluZGljZXMgPSBbXTtcclxuXHJcblx0XHRjb25zdCBnZW9tZXRyeUluZGV4ID0gZ2VvbWV0cnkuaW5kZXg7XHJcblx0XHRjb25zdCBnZW9tZXRyeVBvc2l0aW9uID0gZ2VvbWV0cnkuYXR0cmlidXRlcy5wb3NpdGlvbjtcclxuXHRcdGxldCB2ZXJzaW9uID0gMDtcclxuXHJcblx0XHRpZiAoIGdlb21ldHJ5SW5kZXggIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBhcnJheSA9IGdlb21ldHJ5SW5kZXguYXJyYXk7XHJcblx0XHRcdHZlcnNpb24gPSBnZW9tZXRyeUluZGV4LnZlcnNpb247XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBhcnJheS5sZW5ndGg7IGkgPCBsOyBpICs9IDMgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IGEgPSBhcnJheVsgaSArIDAgXTtcclxuXHRcdFx0XHRjb25zdCBiID0gYXJyYXlbIGkgKyAxIF07XHJcblx0XHRcdFx0Y29uc3QgYyA9IGFycmF5WyBpICsgMiBdO1xyXG5cclxuXHRcdFx0XHRpbmRpY2VzLnB1c2goIGEsIGIsIGIsIGMsIGMsIGEgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9IGVsc2UgaWYgKCBnZW9tZXRyeVBvc2l0aW9uICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBhcnJheSA9IGdlb21ldHJ5UG9zaXRpb24uYXJyYXk7XHJcblx0XHRcdHZlcnNpb24gPSBnZW9tZXRyeVBvc2l0aW9uLnZlcnNpb247XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSAoIGFycmF5Lmxlbmd0aCAvIDMgKSAtIDE7IGkgPCBsOyBpICs9IDMgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IGEgPSBpICsgMDtcclxuXHRcdFx0XHRjb25zdCBiID0gaSArIDE7XHJcblx0XHRcdFx0Y29uc3QgYyA9IGkgKyAyO1xyXG5cclxuXHRcdFx0XHRpbmRpY2VzLnB1c2goIGEsIGIsIGIsIGMsIGMsIGEgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0cmV0dXJuO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCBhdHRyaWJ1dGUgPSBuZXcgKCBhcnJheU5lZWRzVWludDMyKCBpbmRpY2VzICkgPyBVaW50MzJCdWZmZXJBdHRyaWJ1dGUgOiBVaW50MTZCdWZmZXJBdHRyaWJ1dGUgKSggaW5kaWNlcywgMSApO1xyXG5cdFx0YXR0cmlidXRlLnZlcnNpb24gPSB2ZXJzaW9uO1xyXG5cclxuXHRcdC8vIFVwZGF0aW5nIGluZGV4IGJ1ZmZlciBpbiBWQU8gbm93LiBTZWUgV2ViR0xCaW5kaW5nU3RhdGVzXHJcblxyXG5cdFx0Ly9cclxuXHJcblx0XHRjb25zdCBwcmV2aW91c0F0dHJpYnV0ZSA9IHdpcmVmcmFtZUF0dHJpYnV0ZXMuZ2V0KCBnZW9tZXRyeSApO1xyXG5cclxuXHRcdGlmICggcHJldmlvdXNBdHRyaWJ1dGUgKSBhdHRyaWJ1dGVzLnJlbW92ZSggcHJldmlvdXNBdHRyaWJ1dGUgKTtcclxuXHJcblx0XHQvL1xyXG5cclxuXHRcdHdpcmVmcmFtZUF0dHJpYnV0ZXMuc2V0KCBnZW9tZXRyeSwgYXR0cmlidXRlICk7XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gZ2V0V2lyZWZyYW1lQXR0cmlidXRlKCBnZW9tZXRyeSApIHtcclxuXHJcblx0XHRjb25zdCBjdXJyZW50QXR0cmlidXRlID0gd2lyZWZyYW1lQXR0cmlidXRlcy5nZXQoIGdlb21ldHJ5ICk7XHJcblxyXG5cdFx0aWYgKCBjdXJyZW50QXR0cmlidXRlICkge1xyXG5cclxuXHRcdFx0Y29uc3QgZ2VvbWV0cnlJbmRleCA9IGdlb21ldHJ5LmluZGV4O1xyXG5cclxuXHRcdFx0aWYgKCBnZW9tZXRyeUluZGV4ICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0XHQvLyBpZiB0aGUgYXR0cmlidXRlIGlzIG9ic29sZXRlLCBjcmVhdGUgYSBuZXcgb25lXHJcblxyXG5cdFx0XHRcdGlmICggY3VycmVudEF0dHJpYnV0ZS52ZXJzaW9uIDwgZ2VvbWV0cnlJbmRleC52ZXJzaW9uICkge1xyXG5cclxuXHRcdFx0XHRcdHVwZGF0ZVdpcmVmcmFtZUF0dHJpYnV0ZSggZ2VvbWV0cnkgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHR1cGRhdGVXaXJlZnJhbWVBdHRyaWJ1dGUoIGdlb21ldHJ5ICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB3aXJlZnJhbWVBdHRyaWJ1dGVzLmdldCggZ2VvbWV0cnkgKTtcclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4ge1xyXG5cclxuXHRcdGdldDogZ2V0LFxyXG5cdFx0dXBkYXRlOiB1cGRhdGUsXHJcblxyXG5cdFx0Z2V0V2lyZWZyYW1lQXR0cmlidXRlOiBnZXRXaXJlZnJhbWVBdHRyaWJ1dGVcclxuXHJcblx0fTtcclxuXHJcbn1cclxuXHJcblxyXG5leHBvcnQgeyBXZWJHTEdlb21ldHJpZXMgfTtcclxuIiwiZnVuY3Rpb24gV2ViR0xJbmRleGVkQnVmZmVyUmVuZGVyZXIoIGdsLCBleHRlbnNpb25zLCBpbmZvLCBjYXBhYmlsaXRpZXMgKSB7XHJcblxyXG5cdGNvbnN0IGlzV2ViR0wyID0gY2FwYWJpbGl0aWVzLmlzV2ViR0wyO1xyXG5cclxuXHRsZXQgbW9kZTtcclxuXHJcblx0ZnVuY3Rpb24gc2V0TW9kZSggdmFsdWUgKSB7XHJcblxyXG5cdFx0bW9kZSA9IHZhbHVlO1xyXG5cclxuXHR9XHJcblxyXG5cdGxldCB0eXBlLCBieXRlc1BlckVsZW1lbnQ7XHJcblxyXG5cdGZ1bmN0aW9uIHNldEluZGV4KCB2YWx1ZSApIHtcclxuXHJcblx0XHR0eXBlID0gdmFsdWUudHlwZTtcclxuXHRcdGJ5dGVzUGVyRWxlbWVudCA9IHZhbHVlLmJ5dGVzUGVyRWxlbWVudDtcclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiByZW5kZXIoIHN0YXJ0LCBjb3VudCApIHtcclxuXHJcblx0XHRnbC5kcmF3RWxlbWVudHMoIG1vZGUsIGNvdW50LCB0eXBlLCBzdGFydCAqIGJ5dGVzUGVyRWxlbWVudCApO1xyXG5cclxuXHRcdGluZm8udXBkYXRlKCBjb3VudCwgbW9kZSwgMSApO1xyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHJlbmRlckluc3RhbmNlcyggc3RhcnQsIGNvdW50LCBwcmltY291bnQgKSB7XHJcblxyXG5cdFx0aWYgKCBwcmltY291bnQgPT09IDAgKSByZXR1cm47XHJcblxyXG5cdFx0bGV0IGV4dGVuc2lvbiwgbWV0aG9kTmFtZTtcclxuXHJcblx0XHRpZiAoIGlzV2ViR0wyICkge1xyXG5cclxuXHRcdFx0ZXh0ZW5zaW9uID0gZ2w7XHJcblx0XHRcdG1ldGhvZE5hbWUgPSAnZHJhd0VsZW1lbnRzSW5zdGFuY2VkJztcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0ZXh0ZW5zaW9uID0gZXh0ZW5zaW9ucy5nZXQoICdBTkdMRV9pbnN0YW5jZWRfYXJyYXlzJyApO1xyXG5cdFx0XHRtZXRob2ROYW1lID0gJ2RyYXdFbGVtZW50c0luc3RhbmNlZEFOR0xFJztcclxuXHJcblx0XHRcdGlmICggZXh0ZW5zaW9uID09PSBudWxsICkge1xyXG5cclxuXHRcdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuV2ViR0xJbmRleGVkQnVmZmVyUmVuZGVyZXI6IHVzaW5nIFRIUkVFLkluc3RhbmNlZEJ1ZmZlckdlb21ldHJ5IGJ1dCBoYXJkd2FyZSBkb2VzIG5vdCBzdXBwb3J0IGV4dGVuc2lvbiBBTkdMRV9pbnN0YW5jZWRfYXJyYXlzLicgKTtcclxuXHRcdFx0XHRyZXR1cm47XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGV4dGVuc2lvblsgbWV0aG9kTmFtZSBdKCBtb2RlLCBjb3VudCwgdHlwZSwgc3RhcnQgKiBieXRlc1BlckVsZW1lbnQsIHByaW1jb3VudCApO1xyXG5cclxuXHRcdGluZm8udXBkYXRlKCBjb3VudCwgbW9kZSwgcHJpbWNvdW50ICk7XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gcmVuZGVyTXVsdGlEcmF3KCBzdGFydHMsIGNvdW50cywgZHJhd0NvdW50ICkge1xyXG5cclxuXHRcdGlmICggZHJhd0NvdW50ID09PSAwICkgcmV0dXJuO1xyXG5cclxuXHRcdGNvbnN0IGV4dGVuc2lvbiA9IGV4dGVuc2lvbnMuZ2V0KCAnV0VCR0xfbXVsdGlfZHJhdycgKTtcclxuXHRcdGlmICggZXh0ZW5zaW9uID09PSBudWxsICkge1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgZHJhd0NvdW50OyBpICsrICkge1xyXG5cclxuXHRcdFx0XHR0aGlzLnJlbmRlciggc3RhcnRzWyBpIF0gLyBieXRlc1BlckVsZW1lbnQsIGNvdW50c1sgaSBdICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdGV4dGVuc2lvbi5tdWx0aURyYXdFbGVtZW50c1dFQkdMKCBtb2RlLCBjb3VudHMsIDAsIHR5cGUsIHN0YXJ0cywgMCwgZHJhd0NvdW50ICk7XHJcblxyXG5cdFx0XHRsZXQgZWxlbWVudENvdW50ID0gMDtcclxuXHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgZHJhd0NvdW50OyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRlbGVtZW50Q291bnQgKz0gY291bnRzWyBpIF07XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRpbmZvLnVwZGF0ZSggZWxlbWVudENvdW50LCBtb2RlLCAxICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdC8vXHJcblxyXG5cdHRoaXMuc2V0TW9kZSA9IHNldE1vZGU7XHJcblx0dGhpcy5zZXRJbmRleCA9IHNldEluZGV4O1xyXG5cdHRoaXMucmVuZGVyID0gcmVuZGVyO1xyXG5cdHRoaXMucmVuZGVySW5zdGFuY2VzID0gcmVuZGVySW5zdGFuY2VzO1xyXG5cdHRoaXMucmVuZGVyTXVsdGlEcmF3ID0gcmVuZGVyTXVsdGlEcmF3O1xyXG5cclxufVxyXG5cclxuXHJcbmV4cG9ydCB7IFdlYkdMSW5kZXhlZEJ1ZmZlclJlbmRlcmVyIH07XHJcbiIsImZ1bmN0aW9uIFdlYkdMSW5mbyggZ2wgKSB7XHJcblxyXG5cdGNvbnN0IG1lbW9yeSA9IHtcclxuXHRcdGdlb21ldHJpZXM6IDAsXHJcblx0XHR0ZXh0dXJlczogMFxyXG5cdH07XHJcblxyXG5cdGNvbnN0IHJlbmRlciA9IHtcclxuXHRcdGZyYW1lOiAwLFxyXG5cdFx0Y2FsbHM6IDAsXHJcblx0XHR0cmlhbmdsZXM6IDAsXHJcblx0XHRwb2ludHM6IDAsXHJcblx0XHRsaW5lczogMFxyXG5cdH07XHJcblxyXG5cdGZ1bmN0aW9uIHVwZGF0ZSggY291bnQsIG1vZGUsIGluc3RhbmNlQ291bnQgKSB7XHJcblxyXG5cdFx0cmVuZGVyLmNhbGxzICsrO1xyXG5cclxuXHRcdHN3aXRjaCAoIG1vZGUgKSB7XHJcblxyXG5cdFx0XHRjYXNlIGdsLlRSSUFOR0xFUzpcclxuXHRcdFx0XHRyZW5kZXIudHJpYW5nbGVzICs9IGluc3RhbmNlQ291bnQgKiAoIGNvdW50IC8gMyApO1xyXG5cdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0Y2FzZSBnbC5MSU5FUzpcclxuXHRcdFx0XHRyZW5kZXIubGluZXMgKz0gaW5zdGFuY2VDb3VudCAqICggY291bnQgLyAyICk7XHJcblx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRjYXNlIGdsLkxJTkVfU1RSSVA6XHJcblx0XHRcdFx0cmVuZGVyLmxpbmVzICs9IGluc3RhbmNlQ291bnQgKiAoIGNvdW50IC0gMSApO1xyXG5cdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0Y2FzZSBnbC5MSU5FX0xPT1A6XHJcblx0XHRcdFx0cmVuZGVyLmxpbmVzICs9IGluc3RhbmNlQ291bnQgKiBjb3VudDtcclxuXHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdGNhc2UgZ2wuUE9JTlRTOlxyXG5cdFx0XHRcdHJlbmRlci5wb2ludHMgKz0gaW5zdGFuY2VDb3VudCAqIGNvdW50O1xyXG5cdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0ZGVmYXVsdDpcclxuXHRcdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuV2ViR0xJbmZvOiBVbmtub3duIGRyYXcgbW9kZTonLCBtb2RlICk7XHJcblx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHJlc2V0KCkge1xyXG5cclxuXHRcdHJlbmRlci5jYWxscyA9IDA7XHJcblx0XHRyZW5kZXIudHJpYW5nbGVzID0gMDtcclxuXHRcdHJlbmRlci5wb2ludHMgPSAwO1xyXG5cdFx0cmVuZGVyLmxpbmVzID0gMDtcclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4ge1xyXG5cdFx0bWVtb3J5OiBtZW1vcnksXHJcblx0XHRyZW5kZXI6IHJlbmRlcixcclxuXHRcdHByb2dyYW1zOiBudWxsLFxyXG5cdFx0YXV0b1Jlc2V0OiB0cnVlLFxyXG5cdFx0cmVzZXQ6IHJlc2V0LFxyXG5cdFx0dXBkYXRlOiB1cGRhdGVcclxuXHR9O1xyXG5cclxufVxyXG5cclxuXHJcbmV4cG9ydCB7IFdlYkdMSW5mbyB9O1xyXG4iLCJpbXBvcnQgeyBGbG9hdFR5cGUgfSBmcm9tICcuLi8uLi9jb25zdGFudHMuanMnO1xyXG5pbXBvcnQgeyBEYXRhQXJyYXlUZXh0dXJlIH0gZnJvbSAnLi4vLi4vdGV4dHVyZXMvRGF0YUFycmF5VGV4dHVyZS5qcyc7XHJcbmltcG9ydCB7IFZlY3RvcjQgfSBmcm9tICcuLi8uLi9tYXRoL1ZlY3RvcjQuanMnO1xyXG5pbXBvcnQgeyBWZWN0b3IyIH0gZnJvbSAnLi4vLi4vbWF0aC9WZWN0b3IyLmpzJztcclxuXHJcbmZ1bmN0aW9uIG51bWVyaWNhbFNvcnQoIGEsIGIgKSB7XHJcblxyXG5cdHJldHVybiBhWyAwIF0gLSBiWyAwIF07XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiBhYnNOdW1lcmljYWxTb3J0KCBhLCBiICkge1xyXG5cclxuXHRyZXR1cm4gTWF0aC5hYnMoIGJbIDEgXSApIC0gTWF0aC5hYnMoIGFbIDEgXSApO1xyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gV2ViR0xNb3JwaHRhcmdldHMoIGdsLCBjYXBhYmlsaXRpZXMsIHRleHR1cmVzICkge1xyXG5cclxuXHRjb25zdCBpbmZsdWVuY2VzTGlzdCA9IHt9O1xyXG5cdGNvbnN0IG1vcnBoSW5mbHVlbmNlcyA9IG5ldyBGbG9hdDMyQXJyYXkoIDggKTtcclxuXHRjb25zdCBtb3JwaFRleHR1cmVzID0gbmV3IFdlYWtNYXAoKTtcclxuXHRjb25zdCBtb3JwaCA9IG5ldyBWZWN0b3I0KCk7XHJcblxyXG5cdGNvbnN0IHdvcmtJbmZsdWVuY2VzID0gW107XHJcblxyXG5cdGZvciAoIGxldCBpID0gMDsgaSA8IDg7IGkgKysgKSB7XHJcblxyXG5cdFx0d29ya0luZmx1ZW5jZXNbIGkgXSA9IFsgaSwgMCBdO1xyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHVwZGF0ZSggb2JqZWN0LCBnZW9tZXRyeSwgcHJvZ3JhbSApIHtcclxuXHJcblx0XHRjb25zdCBvYmplY3RJbmZsdWVuY2VzID0gb2JqZWN0Lm1vcnBoVGFyZ2V0SW5mbHVlbmNlcztcclxuXHJcblx0XHRpZiAoIGNhcGFiaWxpdGllcy5pc1dlYkdMMiA9PT0gdHJ1ZSApIHtcclxuXHJcblx0XHRcdC8vIGluc3RlYWQgb2YgdXNpbmcgYXR0cmlidXRlcywgdGhlIFdlYkdMIDIgY29kZSBwYXRoIGVuY29kZXMgbW9ycGggdGFyZ2V0c1xyXG5cdFx0XHQvLyBpbnRvIGFuIGFycmF5IG9mIGRhdGEgdGV4dHVyZXMuIEVhY2ggbGF5ZXIgcmVwcmVzZW50cyBhIHNpbmdsZSBtb3JwaCB0YXJnZXQuXHJcblxyXG5cdFx0XHRjb25zdCBtb3JwaEF0dHJpYnV0ZSA9IGdlb21ldHJ5Lm1vcnBoQXR0cmlidXRlcy5wb3NpdGlvbiB8fCBnZW9tZXRyeS5tb3JwaEF0dHJpYnV0ZXMubm9ybWFsIHx8IGdlb21ldHJ5Lm1vcnBoQXR0cmlidXRlcy5jb2xvcjtcclxuXHRcdFx0Y29uc3QgbW9ycGhUYXJnZXRzQ291bnQgPSAoIG1vcnBoQXR0cmlidXRlICE9PSB1bmRlZmluZWQgKSA/IG1vcnBoQXR0cmlidXRlLmxlbmd0aCA6IDA7XHJcblxyXG5cdFx0XHRsZXQgZW50cnkgPSBtb3JwaFRleHR1cmVzLmdldCggZ2VvbWV0cnkgKTtcclxuXHJcblx0XHRcdGlmICggZW50cnkgPT09IHVuZGVmaW5lZCB8fCBlbnRyeS5jb3VudCAhPT0gbW9ycGhUYXJnZXRzQ291bnQgKSB7XHJcblxyXG5cdFx0XHRcdGlmICggZW50cnkgIT09IHVuZGVmaW5lZCApIGVudHJ5LnRleHR1cmUuZGlzcG9zZSgpO1xyXG5cclxuXHRcdFx0XHRjb25zdCBoYXNNb3JwaFBvc2l0aW9uID0gZ2VvbWV0cnkubW9ycGhBdHRyaWJ1dGVzLnBvc2l0aW9uICE9PSB1bmRlZmluZWQ7XHJcblx0XHRcdFx0Y29uc3QgaGFzTW9ycGhOb3JtYWxzID0gZ2VvbWV0cnkubW9ycGhBdHRyaWJ1dGVzLm5vcm1hbCAhPT0gdW5kZWZpbmVkO1xyXG5cdFx0XHRcdGNvbnN0IGhhc01vcnBoQ29sb3JzID0gZ2VvbWV0cnkubW9ycGhBdHRyaWJ1dGVzLmNvbG9yICE9PSB1bmRlZmluZWQ7XHJcblxyXG5cdFx0XHRcdGNvbnN0IG1vcnBoVGFyZ2V0cyA9IGdlb21ldHJ5Lm1vcnBoQXR0cmlidXRlcy5wb3NpdGlvbiB8fCBbXTtcclxuXHRcdFx0XHRjb25zdCBtb3JwaE5vcm1hbHMgPSBnZW9tZXRyeS5tb3JwaEF0dHJpYnV0ZXMubm9ybWFsIHx8IFtdO1xyXG5cdFx0XHRcdGNvbnN0IG1vcnBoQ29sb3JzID0gZ2VvbWV0cnkubW9ycGhBdHRyaWJ1dGVzLmNvbG9yIHx8IFtdO1xyXG5cclxuXHRcdFx0XHRsZXQgdmVydGV4RGF0YUNvdW50ID0gMDtcclxuXHJcblx0XHRcdFx0aWYgKCBoYXNNb3JwaFBvc2l0aW9uID09PSB0cnVlICkgdmVydGV4RGF0YUNvdW50ID0gMTtcclxuXHRcdFx0XHRpZiAoIGhhc01vcnBoTm9ybWFscyA9PT0gdHJ1ZSApIHZlcnRleERhdGFDb3VudCA9IDI7XHJcblx0XHRcdFx0aWYgKCBoYXNNb3JwaENvbG9ycyA9PT0gdHJ1ZSApIHZlcnRleERhdGFDb3VudCA9IDM7XHJcblxyXG5cdFx0XHRcdGxldCB3aWR0aCA9IGdlb21ldHJ5LmF0dHJpYnV0ZXMucG9zaXRpb24uY291bnQgKiB2ZXJ0ZXhEYXRhQ291bnQ7XHJcblx0XHRcdFx0bGV0IGhlaWdodCA9IDE7XHJcblxyXG5cdFx0XHRcdGlmICggd2lkdGggPiBjYXBhYmlsaXRpZXMubWF4VGV4dHVyZVNpemUgKSB7XHJcblxyXG5cdFx0XHRcdFx0aGVpZ2h0ID0gTWF0aC5jZWlsKCB3aWR0aCAvIGNhcGFiaWxpdGllcy5tYXhUZXh0dXJlU2l6ZSApO1xyXG5cdFx0XHRcdFx0d2lkdGggPSBjYXBhYmlsaXRpZXMubWF4VGV4dHVyZVNpemU7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0Y29uc3QgYnVmZmVyID0gbmV3IEZsb2F0MzJBcnJheSggd2lkdGggKiBoZWlnaHQgKiA0ICogbW9ycGhUYXJnZXRzQ291bnQgKTtcclxuXHJcblx0XHRcdFx0Y29uc3QgdGV4dHVyZSA9IG5ldyBEYXRhQXJyYXlUZXh0dXJlKCBidWZmZXIsIHdpZHRoLCBoZWlnaHQsIG1vcnBoVGFyZ2V0c0NvdW50ICk7XHJcblx0XHRcdFx0dGV4dHVyZS50eXBlID0gRmxvYXRUeXBlO1xyXG5cdFx0XHRcdHRleHR1cmUubmVlZHNVcGRhdGUgPSB0cnVlO1xyXG5cclxuXHRcdFx0XHQvLyBmaWxsIGJ1ZmZlclxyXG5cclxuXHRcdFx0XHRjb25zdCB2ZXJ0ZXhEYXRhU3RyaWRlID0gdmVydGV4RGF0YUNvdW50ICogNDtcclxuXHJcblx0XHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgbW9ycGhUYXJnZXRzQ291bnQ7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgbW9ycGhUYXJnZXQgPSBtb3JwaFRhcmdldHNbIGkgXTtcclxuXHRcdFx0XHRcdGNvbnN0IG1vcnBoTm9ybWFsID0gbW9ycGhOb3JtYWxzWyBpIF07XHJcblx0XHRcdFx0XHRjb25zdCBtb3JwaENvbG9yID0gbW9ycGhDb2xvcnNbIGkgXTtcclxuXHJcblx0XHRcdFx0XHRjb25zdCBvZmZzZXQgPSB3aWR0aCAqIGhlaWdodCAqIDQgKiBpO1xyXG5cclxuXHRcdFx0XHRcdGZvciAoIGxldCBqID0gMDsgaiA8IG1vcnBoVGFyZ2V0LmNvdW50OyBqICsrICkge1xyXG5cclxuXHRcdFx0XHRcdFx0Y29uc3Qgc3RyaWRlID0gaiAqIHZlcnRleERhdGFTdHJpZGU7XHJcblxyXG5cdFx0XHRcdFx0XHRpZiAoIGhhc01vcnBoUG9zaXRpb24gPT09IHRydWUgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdG1vcnBoLmZyb21CdWZmZXJBdHRyaWJ1dGUoIG1vcnBoVGFyZ2V0LCBqICk7XHJcblxyXG5cdFx0XHRcdFx0XHRcdGJ1ZmZlclsgb2Zmc2V0ICsgc3RyaWRlICsgMCBdID0gbW9ycGgueDtcclxuXHRcdFx0XHRcdFx0XHRidWZmZXJbIG9mZnNldCArIHN0cmlkZSArIDEgXSA9IG1vcnBoLnk7XHJcblx0XHRcdFx0XHRcdFx0YnVmZmVyWyBvZmZzZXQgKyBzdHJpZGUgKyAyIF0gPSBtb3JwaC56O1xyXG5cdFx0XHRcdFx0XHRcdGJ1ZmZlclsgb2Zmc2V0ICsgc3RyaWRlICsgMyBdID0gMDtcclxuXHJcblx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRcdGlmICggaGFzTW9ycGhOb3JtYWxzID09PSB0cnVlICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRtb3JwaC5mcm9tQnVmZmVyQXR0cmlidXRlKCBtb3JwaE5vcm1hbCwgaiApO1xyXG5cclxuXHRcdFx0XHRcdFx0XHRidWZmZXJbIG9mZnNldCArIHN0cmlkZSArIDQgXSA9IG1vcnBoLng7XHJcblx0XHRcdFx0XHRcdFx0YnVmZmVyWyBvZmZzZXQgKyBzdHJpZGUgKyA1IF0gPSBtb3JwaC55O1xyXG5cdFx0XHRcdFx0XHRcdGJ1ZmZlclsgb2Zmc2V0ICsgc3RyaWRlICsgNiBdID0gbW9ycGguejtcclxuXHRcdFx0XHRcdFx0XHRidWZmZXJbIG9mZnNldCArIHN0cmlkZSArIDcgXSA9IDA7XHJcblxyXG5cdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0XHRpZiAoIGhhc01vcnBoQ29sb3JzID09PSB0cnVlICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRtb3JwaC5mcm9tQnVmZmVyQXR0cmlidXRlKCBtb3JwaENvbG9yLCBqICk7XHJcblxyXG5cdFx0XHRcdFx0XHRcdGJ1ZmZlclsgb2Zmc2V0ICsgc3RyaWRlICsgOCBdID0gbW9ycGgueDtcclxuXHRcdFx0XHRcdFx0XHRidWZmZXJbIG9mZnNldCArIHN0cmlkZSArIDkgXSA9IG1vcnBoLnk7XHJcblx0XHRcdFx0XHRcdFx0YnVmZmVyWyBvZmZzZXQgKyBzdHJpZGUgKyAxMCBdID0gbW9ycGguejtcclxuXHRcdFx0XHRcdFx0XHRidWZmZXJbIG9mZnNldCArIHN0cmlkZSArIDExIF0gPSAoIG1vcnBoQ29sb3IuaXRlbVNpemUgPT09IDQgKSA/IG1vcnBoLncgOiAxO1xyXG5cclxuXHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRlbnRyeSA9IHtcclxuXHRcdFx0XHRcdGNvdW50OiBtb3JwaFRhcmdldHNDb3VudCxcclxuXHRcdFx0XHRcdHRleHR1cmU6IHRleHR1cmUsXHJcblx0XHRcdFx0XHRzaXplOiBuZXcgVmVjdG9yMiggd2lkdGgsIGhlaWdodCApXHJcblx0XHRcdFx0fTtcclxuXHJcblx0XHRcdFx0bW9ycGhUZXh0dXJlcy5zZXQoIGdlb21ldHJ5LCBlbnRyeSApO1xyXG5cclxuXHRcdFx0XHRmdW5jdGlvbiBkaXNwb3NlVGV4dHVyZSgpIHtcclxuXHJcblx0XHRcdFx0XHR0ZXh0dXJlLmRpc3Bvc2UoKTtcclxuXHJcblx0XHRcdFx0XHRtb3JwaFRleHR1cmVzLmRlbGV0ZSggZ2VvbWV0cnkgKTtcclxuXHJcblx0XHRcdFx0XHRnZW9tZXRyeS5yZW1vdmVFdmVudExpc3RlbmVyKCAnZGlzcG9zZScsIGRpc3Bvc2VUZXh0dXJlICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0Z2VvbWV0cnkuYWRkRXZlbnRMaXN0ZW5lciggJ2Rpc3Bvc2UnLCBkaXNwb3NlVGV4dHVyZSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Ly9cclxuXHJcblx0XHRcdGxldCBtb3JwaEluZmx1ZW5jZXNTdW0gPSAwO1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgb2JqZWN0SW5mbHVlbmNlcy5sZW5ndGg7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdG1vcnBoSW5mbHVlbmNlc1N1bSArPSBvYmplY3RJbmZsdWVuY2VzWyBpIF07XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRjb25zdCBtb3JwaEJhc2VJbmZsdWVuY2UgPSBnZW9tZXRyeS5tb3JwaFRhcmdldHNSZWxhdGl2ZSA/IDEgOiAxIC0gbW9ycGhJbmZsdWVuY2VzU3VtO1xyXG5cclxuXHRcdFx0cHJvZ3JhbS5nZXRVbmlmb3JtcygpLnNldFZhbHVlKCBnbCwgJ21vcnBoVGFyZ2V0QmFzZUluZmx1ZW5jZScsIG1vcnBoQmFzZUluZmx1ZW5jZSApO1xyXG5cdFx0XHRwcm9ncmFtLmdldFVuaWZvcm1zKCkuc2V0VmFsdWUoIGdsLCAnbW9ycGhUYXJnZXRJbmZsdWVuY2VzJywgb2JqZWN0SW5mbHVlbmNlcyApO1xyXG5cclxuXHRcdFx0cHJvZ3JhbS5nZXRVbmlmb3JtcygpLnNldFZhbHVlKCBnbCwgJ21vcnBoVGFyZ2V0c1RleHR1cmUnLCBlbnRyeS50ZXh0dXJlLCB0ZXh0dXJlcyApO1xyXG5cdFx0XHRwcm9ncmFtLmdldFVuaWZvcm1zKCkuc2V0VmFsdWUoIGdsLCAnbW9ycGhUYXJnZXRzVGV4dHVyZVNpemUnLCBlbnRyeS5zaXplICk7XHJcblxyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHQvLyBXaGVuIG9iamVjdCBkb2Vzbid0IGhhdmUgbW9ycGggdGFyZ2V0IGluZmx1ZW5jZXMgZGVmaW5lZCwgd2UgdHJlYXQgaXQgYXMgYSAwLWxlbmd0aCBhcnJheVxyXG5cdFx0XHQvLyBUaGlzIGlzIGltcG9ydGFudCB0byBtYWtlIHN1cmUgd2Ugc2V0IHVwIG1vcnBoVGFyZ2V0QmFzZUluZmx1ZW5jZSAvIG1vcnBoVGFyZ2V0SW5mbHVlbmNlc1xyXG5cclxuXHRcdFx0Y29uc3QgbGVuZ3RoID0gb2JqZWN0SW5mbHVlbmNlcyA9PT0gdW5kZWZpbmVkID8gMCA6IG9iamVjdEluZmx1ZW5jZXMubGVuZ3RoO1xyXG5cclxuXHRcdFx0bGV0IGluZmx1ZW5jZXMgPSBpbmZsdWVuY2VzTGlzdFsgZ2VvbWV0cnkuaWQgXTtcclxuXHJcblx0XHRcdGlmICggaW5mbHVlbmNlcyA9PT0gdW5kZWZpbmVkIHx8IGluZmx1ZW5jZXMubGVuZ3RoICE9PSBsZW5ndGggKSB7XHJcblxyXG5cdFx0XHRcdC8vIGluaXRpYWxpc2UgbGlzdFxyXG5cclxuXHRcdFx0XHRpbmZsdWVuY2VzID0gW107XHJcblxyXG5cdFx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IGxlbmd0aDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0XHRpbmZsdWVuY2VzWyBpIF0gPSBbIGksIDAgXTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRpbmZsdWVuY2VzTGlzdFsgZ2VvbWV0cnkuaWQgXSA9IGluZmx1ZW5jZXM7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyBDb2xsZWN0IGluZmx1ZW5jZXNcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IGxlbmd0aDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgaW5mbHVlbmNlID0gaW5mbHVlbmNlc1sgaSBdO1xyXG5cclxuXHRcdFx0XHRpbmZsdWVuY2VbIDAgXSA9IGk7XHJcblx0XHRcdFx0aW5mbHVlbmNlWyAxIF0gPSBvYmplY3RJbmZsdWVuY2VzWyBpIF07XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRpbmZsdWVuY2VzLnNvcnQoIGFic051bWVyaWNhbFNvcnQgKTtcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IDg7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdGlmICggaSA8IGxlbmd0aCAmJiBpbmZsdWVuY2VzWyBpIF1bIDEgXSApIHtcclxuXHJcblx0XHRcdFx0XHR3b3JrSW5mbHVlbmNlc1sgaSBdWyAwIF0gPSBpbmZsdWVuY2VzWyBpIF1bIDAgXTtcclxuXHRcdFx0XHRcdHdvcmtJbmZsdWVuY2VzWyBpIF1bIDEgXSA9IGluZmx1ZW5jZXNbIGkgXVsgMSBdO1xyXG5cclxuXHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdHdvcmtJbmZsdWVuY2VzWyBpIF1bIDAgXSA9IE51bWJlci5NQVhfU0FGRV9JTlRFR0VSO1xyXG5cdFx0XHRcdFx0d29ya0luZmx1ZW5jZXNbIGkgXVsgMSBdID0gMDtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0d29ya0luZmx1ZW5jZXMuc29ydCggbnVtZXJpY2FsU29ydCApO1xyXG5cclxuXHRcdFx0Y29uc3QgbW9ycGhUYXJnZXRzID0gZ2VvbWV0cnkubW9ycGhBdHRyaWJ1dGVzLnBvc2l0aW9uO1xyXG5cdFx0XHRjb25zdCBtb3JwaE5vcm1hbHMgPSBnZW9tZXRyeS5tb3JwaEF0dHJpYnV0ZXMubm9ybWFsO1xyXG5cclxuXHRcdFx0bGV0IG1vcnBoSW5mbHVlbmNlc1N1bSA9IDA7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCA4OyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBpbmZsdWVuY2UgPSB3b3JrSW5mbHVlbmNlc1sgaSBdO1xyXG5cdFx0XHRcdGNvbnN0IGluZGV4ID0gaW5mbHVlbmNlWyAwIF07XHJcblx0XHRcdFx0Y29uc3QgdmFsdWUgPSBpbmZsdWVuY2VbIDEgXTtcclxuXHJcblx0XHRcdFx0aWYgKCBpbmRleCAhPT0gTnVtYmVyLk1BWF9TQUZFX0lOVEVHRVIgJiYgdmFsdWUgKSB7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCBtb3JwaFRhcmdldHMgJiYgZ2VvbWV0cnkuZ2V0QXR0cmlidXRlKCAnbW9ycGhUYXJnZXQnICsgaSApICE9PSBtb3JwaFRhcmdldHNbIGluZGV4IF0gKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRnZW9tZXRyeS5zZXRBdHRyaWJ1dGUoICdtb3JwaFRhcmdldCcgKyBpLCBtb3JwaFRhcmdldHNbIGluZGV4IF0gKTtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0aWYgKCBtb3JwaE5vcm1hbHMgJiYgZ2VvbWV0cnkuZ2V0QXR0cmlidXRlKCAnbW9ycGhOb3JtYWwnICsgaSApICE9PSBtb3JwaE5vcm1hbHNbIGluZGV4IF0gKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRnZW9tZXRyeS5zZXRBdHRyaWJ1dGUoICdtb3JwaE5vcm1hbCcgKyBpLCBtb3JwaE5vcm1hbHNbIGluZGV4IF0gKTtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0bW9ycGhJbmZsdWVuY2VzWyBpIF0gPSB2YWx1ZTtcclxuXHRcdFx0XHRcdG1vcnBoSW5mbHVlbmNlc1N1bSArPSB2YWx1ZTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRpZiAoIG1vcnBoVGFyZ2V0cyAmJiBnZW9tZXRyeS5oYXNBdHRyaWJ1dGUoICdtb3JwaFRhcmdldCcgKyBpICkgPT09IHRydWUgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRnZW9tZXRyeS5kZWxldGVBdHRyaWJ1dGUoICdtb3JwaFRhcmdldCcgKyBpICk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdGlmICggbW9ycGhOb3JtYWxzICYmIGdlb21ldHJ5Lmhhc0F0dHJpYnV0ZSggJ21vcnBoTm9ybWFsJyArIGkgKSA9PT0gdHJ1ZSApIHtcclxuXHJcblx0XHRcdFx0XHRcdGdlb21ldHJ5LmRlbGV0ZUF0dHJpYnV0ZSggJ21vcnBoTm9ybWFsJyArIGkgKTtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0bW9ycGhJbmZsdWVuY2VzWyBpIF0gPSAwO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyBHTFNMIHNoYWRlciB1c2VzIGZvcm11bGEgYmFzZWluZmx1ZW5jZSAqIGJhc2UgKyBzdW0odGFyZ2V0ICogaW5mbHVlbmNlKVxyXG5cdFx0XHQvLyBUaGlzIGFsbG93cyB1cyB0byBzd2l0Y2ggYmV0d2VlbiBhYnNvbHV0ZSBtb3JwaHMgYW5kIHJlbGF0aXZlIG1vcnBocyB3aXRob3V0IGNoYW5naW5nIHNoYWRlciBjb2RlXHJcblx0XHRcdC8vIFdoZW4gYmFzZWluZmx1ZW5jZSA9IDEgLSBzdW0oaW5mbHVlbmNlKSwgdGhlIGFib3ZlIGlzIGVxdWl2YWxlbnQgdG8gc3VtKCh0YXJnZXQgLSBiYXNlKSAqIGluZmx1ZW5jZSlcclxuXHRcdFx0Y29uc3QgbW9ycGhCYXNlSW5mbHVlbmNlID0gZ2VvbWV0cnkubW9ycGhUYXJnZXRzUmVsYXRpdmUgPyAxIDogMSAtIG1vcnBoSW5mbHVlbmNlc1N1bTtcclxuXHJcblx0XHRcdHByb2dyYW0uZ2V0VW5pZm9ybXMoKS5zZXRWYWx1ZSggZ2wsICdtb3JwaFRhcmdldEJhc2VJbmZsdWVuY2UnLCBtb3JwaEJhc2VJbmZsdWVuY2UgKTtcclxuXHRcdFx0cHJvZ3JhbS5nZXRVbmlmb3JtcygpLnNldFZhbHVlKCBnbCwgJ21vcnBoVGFyZ2V0SW5mbHVlbmNlcycsIG1vcnBoSW5mbHVlbmNlcyApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4ge1xyXG5cclxuXHRcdHVwZGF0ZTogdXBkYXRlXHJcblxyXG5cdH07XHJcblxyXG59XHJcblxyXG5cclxuZXhwb3J0IHsgV2ViR0xNb3JwaHRhcmdldHMgfTtcclxuIiwiZnVuY3Rpb24gV2ViR0xPYmplY3RzKCBnbCwgZ2VvbWV0cmllcywgYXR0cmlidXRlcywgaW5mbyApIHtcclxuXHJcblx0bGV0IHVwZGF0ZU1hcCA9IG5ldyBXZWFrTWFwKCk7XHJcblxyXG5cdGZ1bmN0aW9uIHVwZGF0ZSggb2JqZWN0ICkge1xyXG5cclxuXHRcdGNvbnN0IGZyYW1lID0gaW5mby5yZW5kZXIuZnJhbWU7XHJcblxyXG5cdFx0Y29uc3QgZ2VvbWV0cnkgPSBvYmplY3QuZ2VvbWV0cnk7XHJcblx0XHRjb25zdCBidWZmZXJnZW9tZXRyeSA9IGdlb21ldHJpZXMuZ2V0KCBvYmplY3QsIGdlb21ldHJ5ICk7XHJcblxyXG5cdFx0Ly8gVXBkYXRlIG9uY2UgcGVyIGZyYW1lXHJcblxyXG5cdFx0aWYgKCB1cGRhdGVNYXAuZ2V0KCBidWZmZXJnZW9tZXRyeSApICE9PSBmcmFtZSApIHtcclxuXHJcblx0XHRcdGdlb21ldHJpZXMudXBkYXRlKCBidWZmZXJnZW9tZXRyeSApO1xyXG5cclxuXHRcdFx0dXBkYXRlTWFwLnNldCggYnVmZmVyZ2VvbWV0cnksIGZyYW1lICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggb2JqZWN0LmlzSW5zdGFuY2VkTWVzaCApIHtcclxuXHJcblx0XHRcdGlmICggb2JqZWN0Lmhhc0V2ZW50TGlzdGVuZXIoICdkaXNwb3NlJywgb25JbnN0YW5jZWRNZXNoRGlzcG9zZSApID09PSBmYWxzZSApIHtcclxuXHJcblx0XHRcdFx0b2JqZWN0LmFkZEV2ZW50TGlzdGVuZXIoICdkaXNwb3NlJywgb25JbnN0YW5jZWRNZXNoRGlzcG9zZSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0aWYgKCB1cGRhdGVNYXAuZ2V0KCBvYmplY3QgKSAhPT0gZnJhbWUgKSB7XHJcblxyXG5cdFx0XHRcdGF0dHJpYnV0ZXMudXBkYXRlKCBvYmplY3QuaW5zdGFuY2VNYXRyaXgsIGdsLkFSUkFZX0JVRkZFUiApO1xyXG5cclxuXHRcdFx0XHRpZiAoIG9iamVjdC5pbnN0YW5jZUNvbG9yICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0XHRcdGF0dHJpYnV0ZXMudXBkYXRlKCBvYmplY3QuaW5zdGFuY2VDb2xvciwgZ2wuQVJSQVlfQlVGRkVSICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0dXBkYXRlTWFwLnNldCggb2JqZWN0LCBmcmFtZSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIG9iamVjdC5pc1NraW5uZWRNZXNoICkge1xyXG5cclxuXHRcdFx0Y29uc3Qgc2tlbGV0b24gPSBvYmplY3Quc2tlbGV0b247XHJcblxyXG5cdFx0XHRpZiAoIHVwZGF0ZU1hcC5nZXQoIHNrZWxldG9uICkgIT09IGZyYW1lICkge1xyXG5cclxuXHRcdFx0XHRza2VsZXRvbi51cGRhdGUoKTtcclxuXHJcblx0XHRcdFx0dXBkYXRlTWFwLnNldCggc2tlbGV0b24sIGZyYW1lICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiBidWZmZXJnZW9tZXRyeTtcclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBkaXNwb3NlKCkge1xyXG5cclxuXHRcdHVwZGF0ZU1hcCA9IG5ldyBXZWFrTWFwKCk7XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gb25JbnN0YW5jZWRNZXNoRGlzcG9zZSggZXZlbnQgKSB7XHJcblxyXG5cdFx0Y29uc3QgaW5zdGFuY2VkTWVzaCA9IGV2ZW50LnRhcmdldDtcclxuXHJcblx0XHRpbnN0YW5jZWRNZXNoLnJlbW92ZUV2ZW50TGlzdGVuZXIoICdkaXNwb3NlJywgb25JbnN0YW5jZWRNZXNoRGlzcG9zZSApO1xyXG5cclxuXHRcdGF0dHJpYnV0ZXMucmVtb3ZlKCBpbnN0YW5jZWRNZXNoLmluc3RhbmNlTWF0cml4ICk7XHJcblxyXG5cdFx0aWYgKCBpbnN0YW5jZWRNZXNoLmluc3RhbmNlQ29sb3IgIT09IG51bGwgKSBhdHRyaWJ1dGVzLnJlbW92ZSggaW5zdGFuY2VkTWVzaC5pbnN0YW5jZUNvbG9yICk7XHJcblxyXG5cdH1cclxuXHJcblx0cmV0dXJuIHtcclxuXHJcblx0XHR1cGRhdGU6IHVwZGF0ZSxcclxuXHRcdGRpc3Bvc2U6IGRpc3Bvc2VcclxuXHJcblx0fTtcclxuXHJcbn1cclxuXHJcblxyXG5leHBvcnQgeyBXZWJHTE9iamVjdHMgfTtcclxuIiwiaW1wb3J0IHsgVGV4dHVyZSB9IGZyb20gJy4vVGV4dHVyZS5qcyc7XHJcbmltcG9ydCB7IE5lYXJlc3RGaWx0ZXIsIFVuc2lnbmVkSW50VHlwZSwgVW5zaWduZWRJbnQyNDhUeXBlLCBEZXB0aEZvcm1hdCwgRGVwdGhTdGVuY2lsRm9ybWF0IH0gZnJvbSAnLi4vY29uc3RhbnRzLmpzJztcclxuXHJcbmNsYXNzIERlcHRoVGV4dHVyZSBleHRlbmRzIFRleHR1cmUge1xyXG5cclxuXHRjb25zdHJ1Y3Rvciggd2lkdGgsIGhlaWdodCwgdHlwZSwgbWFwcGluZywgd3JhcFMsIHdyYXBULCBtYWdGaWx0ZXIsIG1pbkZpbHRlciwgYW5pc290cm9weSwgZm9ybWF0ICkge1xyXG5cclxuXHRcdGZvcm1hdCA9IGZvcm1hdCAhPT0gdW5kZWZpbmVkID8gZm9ybWF0IDogRGVwdGhGb3JtYXQ7XHJcblxyXG5cdFx0aWYgKCBmb3JtYXQgIT09IERlcHRoRm9ybWF0ICYmIGZvcm1hdCAhPT0gRGVwdGhTdGVuY2lsRm9ybWF0ICkge1xyXG5cclxuXHRcdFx0dGhyb3cgbmV3IEVycm9yKCAnRGVwdGhUZXh0dXJlIGZvcm1hdCBtdXN0IGJlIGVpdGhlciBUSFJFRS5EZXB0aEZvcm1hdCBvciBUSFJFRS5EZXB0aFN0ZW5jaWxGb3JtYXQnICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggdHlwZSA9PT0gdW5kZWZpbmVkICYmIGZvcm1hdCA9PT0gRGVwdGhGb3JtYXQgKSB0eXBlID0gVW5zaWduZWRJbnRUeXBlO1xyXG5cdFx0aWYgKCB0eXBlID09PSB1bmRlZmluZWQgJiYgZm9ybWF0ID09PSBEZXB0aFN0ZW5jaWxGb3JtYXQgKSB0eXBlID0gVW5zaWduZWRJbnQyNDhUeXBlO1xyXG5cclxuXHRcdHN1cGVyKCBudWxsLCBtYXBwaW5nLCB3cmFwUywgd3JhcFQsIG1hZ0ZpbHRlciwgbWluRmlsdGVyLCBmb3JtYXQsIHR5cGUsIGFuaXNvdHJvcHkgKTtcclxuXHJcblx0XHR0aGlzLmlzRGVwdGhUZXh0dXJlID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLmltYWdlID0geyB3aWR0aDogd2lkdGgsIGhlaWdodDogaGVpZ2h0IH07XHJcblxyXG5cdFx0dGhpcy5tYWdGaWx0ZXIgPSBtYWdGaWx0ZXIgIT09IHVuZGVmaW5lZCA/IG1hZ0ZpbHRlciA6IE5lYXJlc3RGaWx0ZXI7XHJcblx0XHR0aGlzLm1pbkZpbHRlciA9IG1pbkZpbHRlciAhPT0gdW5kZWZpbmVkID8gbWluRmlsdGVyIDogTmVhcmVzdEZpbHRlcjtcclxuXHJcblx0XHR0aGlzLmZsaXBZID0gZmFsc2U7XHJcblx0XHR0aGlzLmdlbmVyYXRlTWlwbWFwcyA9IGZhbHNlO1xyXG5cclxuXHRcdHRoaXMuY29tcGFyZUZ1bmN0aW9uID0gbnVsbDtcclxuXHJcblx0fVxyXG5cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xyXG5cclxuXHRcdHRoaXMuY29tcGFyZUZ1bmN0aW9uID0gc291cmNlLmNvbXBhcmVGdW5jdGlvbjtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHR0b0pTT04oIG1ldGEgKSB7XHJcblxyXG5cdFx0Y29uc3QgZGF0YSA9IHN1cGVyLnRvSlNPTiggbWV0YSApO1xyXG5cclxuXHRcdGlmICggdGhpcy5jb21wYXJlRnVuY3Rpb24gIT09IG51bGwgKSBkYXRhLmNvbXBhcmVGdW5jdGlvbiA9IHRoaXMuY29tcGFyZUZ1bmN0aW9uO1xyXG5cclxuXHRcdHJldHVybiBkYXRhO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBEZXB0aFRleHR1cmUgfTtcclxuIiwiLyoqXHJcbiAqIFVuaWZvcm1zIG9mIGEgcHJvZ3JhbS5cclxuICogVGhvc2UgZm9ybSBhIHRyZWUgc3RydWN0dXJlIHdpdGggYSBzcGVjaWFsIHRvcC1sZXZlbCBjb250YWluZXIgZm9yIHRoZSByb290LFxyXG4gKiB3aGljaCB5b3UgZ2V0IGJ5IGNhbGxpbmcgJ25ldyBXZWJHTFVuaWZvcm1zKCBnbCwgcHJvZ3JhbSApJy5cclxuICpcclxuICpcclxuICogUHJvcGVydGllcyBvZiBpbm5lciBub2RlcyBpbmNsdWRpbmcgdGhlIHRvcC1sZXZlbCBjb250YWluZXI6XHJcbiAqXHJcbiAqIC5zZXEgLSBhcnJheSBvZiBuZXN0ZWQgdW5pZm9ybXNcclxuICogLm1hcCAtIG5lc3RlZCB1bmlmb3JtcyBieSBuYW1lXHJcbiAqXHJcbiAqXHJcbiAqIE1ldGhvZHMgb2YgYWxsIG5vZGVzIGV4Y2VwdCB0aGUgdG9wLWxldmVsIGNvbnRhaW5lcjpcclxuICpcclxuICogLnNldFZhbHVlKCBnbCwgdmFsdWUsIFt0ZXh0dXJlc10gKVxyXG4gKlxyXG4gKiBcdFx0dXBsb2FkcyBhIHVuaWZvcm0gdmFsdWUocylcclxuICogIFx0dGhlICd0ZXh0dXJlcycgcGFyYW1ldGVyIGlzIG5lZWRlZCBmb3Igc2FtcGxlciB1bmlmb3Jtc1xyXG4gKlxyXG4gKlxyXG4gKiBTdGF0aWMgbWV0aG9kcyBvZiB0aGUgdG9wLWxldmVsIGNvbnRhaW5lciAodGV4dHVyZXMgZmFjdG9yaXphdGlvbnMpOlxyXG4gKlxyXG4gKiAudXBsb2FkKCBnbCwgc2VxLCB2YWx1ZXMsIHRleHR1cmVzIClcclxuICpcclxuICogXHRcdHNldHMgdW5pZm9ybXMgaW4gJ3NlcScgdG8gJ3ZhbHVlc1tpZF0udmFsdWUnXHJcbiAqXHJcbiAqIC5zZXFXaXRoVmFsdWUoIHNlcSwgdmFsdWVzICkgOiBmaWx0ZXJlZFNlcVxyXG4gKlxyXG4gKiBcdFx0ZmlsdGVycyAnc2VxJyBlbnRyaWVzIHdpdGggY29ycmVzcG9uZGluZyBlbnRyeSBpbiB2YWx1ZXNcclxuICpcclxuICpcclxuICogTWV0aG9kcyBvZiB0aGUgdG9wLWxldmVsIGNvbnRhaW5lciAodGV4dHVyZXMgZmFjdG9yaXphdGlvbnMpOlxyXG4gKlxyXG4gKiAuc2V0VmFsdWUoIGdsLCBuYW1lLCB2YWx1ZSwgdGV4dHVyZXMgKVxyXG4gKlxyXG4gKiBcdFx0c2V0cyB1bmlmb3JtIHdpdGggIG5hbWUgJ25hbWUnIHRvICd2YWx1ZSdcclxuICpcclxuICogLnNldE9wdGlvbmFsKCBnbCwgb2JqLCBwcm9wIClcclxuICpcclxuICogXHRcdGxpa2UgLnNldCBmb3IgYW4gb3B0aW9uYWwgcHJvcGVydHkgb2YgdGhlIG9iamVjdFxyXG4gKlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IEN1YmVUZXh0dXJlIH0gZnJvbSAnLi4vLi4vdGV4dHVyZXMvQ3ViZVRleHR1cmUuanMnO1xyXG5pbXBvcnQgeyBUZXh0dXJlIH0gZnJvbSAnLi4vLi4vdGV4dHVyZXMvVGV4dHVyZS5qcyc7XHJcbmltcG9ydCB7IERhdGFBcnJheVRleHR1cmUgfSBmcm9tICcuLi8uLi90ZXh0dXJlcy9EYXRhQXJyYXlUZXh0dXJlLmpzJztcclxuaW1wb3J0IHsgRGF0YTNEVGV4dHVyZSB9IGZyb20gJy4uLy4uL3RleHR1cmVzL0RhdGEzRFRleHR1cmUuanMnO1xyXG5pbXBvcnQgeyBEZXB0aFRleHR1cmUgfSBmcm9tICcuLi8uLi90ZXh0dXJlcy9EZXB0aFRleHR1cmUuanMnO1xyXG5pbXBvcnQgeyBMZXNzRXF1YWxDb21wYXJlIH0gZnJvbSAnLi4vLi4vY29uc3RhbnRzLmpzJztcclxuXHJcbmNvbnN0IGVtcHR5VGV4dHVyZSA9IC8qQF9fUFVSRV9fKi8gbmV3IFRleHR1cmUoKTtcclxuXHJcbmNvbnN0IGVtcHR5U2hhZG93VGV4dHVyZSA9IC8qQF9fUFVSRV9fKi8gbmV3IERlcHRoVGV4dHVyZSggMSwgMSApO1xyXG5lbXB0eVNoYWRvd1RleHR1cmUuY29tcGFyZUZ1bmN0aW9uID0gTGVzc0VxdWFsQ29tcGFyZTtcclxuXHJcbmNvbnN0IGVtcHR5QXJyYXlUZXh0dXJlID0gLypAX19QVVJFX18qLyBuZXcgRGF0YUFycmF5VGV4dHVyZSgpO1xyXG5jb25zdCBlbXB0eTNkVGV4dHVyZSA9IC8qQF9fUFVSRV9fKi8gbmV3IERhdGEzRFRleHR1cmUoKTtcclxuY29uc3QgZW1wdHlDdWJlVGV4dHVyZSA9IC8qQF9fUFVSRV9fKi8gbmV3IEN1YmVUZXh0dXJlKCk7XHJcblxyXG4vLyAtLS0gVXRpbGl0aWVzIC0tLVxyXG5cclxuLy8gQXJyYXkgQ2FjaGVzIChwcm92aWRlIHR5cGVkIGFycmF5cyBmb3IgdGVtcG9yYXJ5IGJ5IHNpemUpXHJcblxyXG5jb25zdCBhcnJheUNhY2hlRjMyID0gW107XHJcbmNvbnN0IGFycmF5Q2FjaGVJMzIgPSBbXTtcclxuXHJcbi8vIEZsb2F0MzJBcnJheSBjYWNoZXMgdXNlZCBmb3IgdXBsb2FkaW5nIE1hdHJpeCB1bmlmb3Jtc1xyXG5cclxuY29uc3QgbWF0NGFycmF5ID0gbmV3IEZsb2F0MzJBcnJheSggMTYgKTtcclxuY29uc3QgbWF0M2FycmF5ID0gbmV3IEZsb2F0MzJBcnJheSggOSApO1xyXG5jb25zdCBtYXQyYXJyYXkgPSBuZXcgRmxvYXQzMkFycmF5KCA0ICk7XHJcblxyXG4vLyBGbGF0dGVuaW5nIGZvciBhcnJheXMgb2YgdmVjdG9ycyBhbmQgbWF0cmljZXNcclxuXHJcbmZ1bmN0aW9uIGZsYXR0ZW4oIGFycmF5LCBuQmxvY2tzLCBibG9ja1NpemUgKSB7XHJcblxyXG5cdGNvbnN0IGZpcnN0RWxlbSA9IGFycmF5WyAwIF07XHJcblxyXG5cdGlmICggZmlyc3RFbGVtIDw9IDAgfHwgZmlyc3RFbGVtID4gMCApIHJldHVybiBhcnJheTtcclxuXHQvLyB1bm9wdGltaXplZDogISBpc05hTiggZmlyc3RFbGVtIClcclxuXHQvLyBzZWUgaHR0cDovL2phY2tzb25kdW5zdGFuLmNvbS9hcnRpY2xlcy85ODNcclxuXHJcblx0Y29uc3QgbiA9IG5CbG9ja3MgKiBibG9ja1NpemU7XHJcblx0bGV0IHIgPSBhcnJheUNhY2hlRjMyWyBuIF07XHJcblxyXG5cdGlmICggciA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdHIgPSBuZXcgRmxvYXQzMkFycmF5KCBuICk7XHJcblx0XHRhcnJheUNhY2hlRjMyWyBuIF0gPSByO1xyXG5cclxuXHR9XHJcblxyXG5cdGlmICggbkJsb2NrcyAhPT0gMCApIHtcclxuXHJcblx0XHRmaXJzdEVsZW0udG9BcnJheSggciwgMCApO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMSwgb2Zmc2V0ID0gMDsgaSAhPT0gbkJsb2NrczsgKysgaSApIHtcclxuXHJcblx0XHRcdG9mZnNldCArPSBibG9ja1NpemU7XHJcblx0XHRcdGFycmF5WyBpIF0udG9BcnJheSggciwgb2Zmc2V0ICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdHJldHVybiByO1xyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gYXJyYXlzRXF1YWwoIGEsIGIgKSB7XHJcblxyXG5cdGlmICggYS5sZW5ndGggIT09IGIubGVuZ3RoICkgcmV0dXJuIGZhbHNlO1xyXG5cclxuXHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBhLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0aWYgKCBhWyBpIF0gIT09IGJbIGkgXSApIHJldHVybiBmYWxzZTtcclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4gdHJ1ZTtcclxuXHJcbn1cclxuXHJcbmZ1bmN0aW9uIGNvcHlBcnJheSggYSwgYiApIHtcclxuXHJcblx0Zm9yICggbGV0IGkgPSAwLCBsID0gYi5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdGFbIGkgXSA9IGJbIGkgXTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuLy8gVGV4dHVyZSB1bml0IGFsbG9jYXRpb25cclxuXHJcbmZ1bmN0aW9uIGFsbG9jVGV4VW5pdHMoIHRleHR1cmVzLCBuICkge1xyXG5cclxuXHRsZXQgciA9IGFycmF5Q2FjaGVJMzJbIG4gXTtcclxuXHJcblx0aWYgKCByID09PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0ciA9IG5ldyBJbnQzMkFycmF5KCBuICk7XHJcblx0XHRhcnJheUNhY2hlSTMyWyBuIF0gPSByO1xyXG5cclxuXHR9XHJcblxyXG5cdGZvciAoIGxldCBpID0gMDsgaSAhPT0gbjsgKysgaSApIHtcclxuXHJcblx0XHRyWyBpIF0gPSB0ZXh0dXJlcy5hbGxvY2F0ZVRleHR1cmVVbml0KCk7XHJcblxyXG5cdH1cclxuXHJcblx0cmV0dXJuIHI7XHJcblxyXG59XHJcblxyXG4vLyAtLS0gU2V0dGVycyAtLS1cclxuXHJcbi8vIE5vdGU6IERlZmluaW5nIHRoZXNlIG1ldGhvZHMgZXh0ZXJuYWxseSwgYmVjYXVzZSB0aGV5IGNvbWUgaW4gYSBidW5jaFxyXG4vLyBhbmQgdGhpcyB3YXkgdGhlaXIgbmFtZXMgbWluaWZ5LlxyXG5cclxuLy8gU2luZ2xlIHNjYWxhclxyXG5cclxuZnVuY3Rpb24gc2V0VmFsdWVWMWYoIGdsLCB2ICkge1xyXG5cclxuXHRjb25zdCBjYWNoZSA9IHRoaXMuY2FjaGU7XHJcblxyXG5cdGlmICggY2FjaGVbIDAgXSA9PT0gdiApIHJldHVybjtcclxuXHJcblx0Z2wudW5pZm9ybTFmKCB0aGlzLmFkZHIsIHYgKTtcclxuXHJcblx0Y2FjaGVbIDAgXSA9IHY7XHJcblxyXG59XHJcblxyXG4vLyBTaW5nbGUgZmxvYXQgdmVjdG9yIChmcm9tIGZsYXQgYXJyYXkgb3IgVEhSRUUuVmVjdG9yTilcclxuXHJcbmZ1bmN0aW9uIHNldFZhbHVlVjJmKCBnbCwgdiApIHtcclxuXHJcblx0Y29uc3QgY2FjaGUgPSB0aGlzLmNhY2hlO1xyXG5cclxuXHRpZiAoIHYueCAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdGlmICggY2FjaGVbIDAgXSAhPT0gdi54IHx8IGNhY2hlWyAxIF0gIT09IHYueSApIHtcclxuXHJcblx0XHRcdGdsLnVuaWZvcm0yZiggdGhpcy5hZGRyLCB2LngsIHYueSApO1xyXG5cclxuXHRcdFx0Y2FjaGVbIDAgXSA9IHYueDtcclxuXHRcdFx0Y2FjaGVbIDEgXSA9IHYueTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH0gZWxzZSB7XHJcblxyXG5cdFx0aWYgKCBhcnJheXNFcXVhbCggY2FjaGUsIHYgKSApIHJldHVybjtcclxuXHJcblx0XHRnbC51bmlmb3JtMmZ2KCB0aGlzLmFkZHIsIHYgKTtcclxuXHJcblx0XHRjb3B5QXJyYXkoIGNhY2hlLCB2ICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmZ1bmN0aW9uIHNldFZhbHVlVjNmKCBnbCwgdiApIHtcclxuXHJcblx0Y29uc3QgY2FjaGUgPSB0aGlzLmNhY2hlO1xyXG5cclxuXHRpZiAoIHYueCAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdGlmICggY2FjaGVbIDAgXSAhPT0gdi54IHx8IGNhY2hlWyAxIF0gIT09IHYueSB8fCBjYWNoZVsgMiBdICE9PSB2LnogKSB7XHJcblxyXG5cdFx0XHRnbC51bmlmb3JtM2YoIHRoaXMuYWRkciwgdi54LCB2LnksIHYueiApO1xyXG5cclxuXHRcdFx0Y2FjaGVbIDAgXSA9IHYueDtcclxuXHRcdFx0Y2FjaGVbIDEgXSA9IHYueTtcclxuXHRcdFx0Y2FjaGVbIDIgXSA9IHYuejtcclxuXHJcblx0XHR9XHJcblxyXG5cdH0gZWxzZSBpZiAoIHYuciAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdGlmICggY2FjaGVbIDAgXSAhPT0gdi5yIHx8IGNhY2hlWyAxIF0gIT09IHYuZyB8fCBjYWNoZVsgMiBdICE9PSB2LmIgKSB7XHJcblxyXG5cdFx0XHRnbC51bmlmb3JtM2YoIHRoaXMuYWRkciwgdi5yLCB2LmcsIHYuYiApO1xyXG5cclxuXHRcdFx0Y2FjaGVbIDAgXSA9IHYucjtcclxuXHRcdFx0Y2FjaGVbIDEgXSA9IHYuZztcclxuXHRcdFx0Y2FjaGVbIDIgXSA9IHYuYjtcclxuXHJcblx0XHR9XHJcblxyXG5cdH0gZWxzZSB7XHJcblxyXG5cdFx0aWYgKCBhcnJheXNFcXVhbCggY2FjaGUsIHYgKSApIHJldHVybjtcclxuXHJcblx0XHRnbC51bmlmb3JtM2Z2KCB0aGlzLmFkZHIsIHYgKTtcclxuXHJcblx0XHRjb3B5QXJyYXkoIGNhY2hlLCB2ICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmZ1bmN0aW9uIHNldFZhbHVlVjRmKCBnbCwgdiApIHtcclxuXHJcblx0Y29uc3QgY2FjaGUgPSB0aGlzLmNhY2hlO1xyXG5cclxuXHRpZiAoIHYueCAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdGlmICggY2FjaGVbIDAgXSAhPT0gdi54IHx8IGNhY2hlWyAxIF0gIT09IHYueSB8fCBjYWNoZVsgMiBdICE9PSB2LnogfHwgY2FjaGVbIDMgXSAhPT0gdi53ICkge1xyXG5cclxuXHRcdFx0Z2wudW5pZm9ybTRmKCB0aGlzLmFkZHIsIHYueCwgdi55LCB2LnosIHYudyApO1xyXG5cclxuXHRcdFx0Y2FjaGVbIDAgXSA9IHYueDtcclxuXHRcdFx0Y2FjaGVbIDEgXSA9IHYueTtcclxuXHRcdFx0Y2FjaGVbIDIgXSA9IHYuejtcclxuXHRcdFx0Y2FjaGVbIDMgXSA9IHYudztcclxuXHJcblx0XHR9XHJcblxyXG5cdH0gZWxzZSB7XHJcblxyXG5cdFx0aWYgKCBhcnJheXNFcXVhbCggY2FjaGUsIHYgKSApIHJldHVybjtcclxuXHJcblx0XHRnbC51bmlmb3JtNGZ2KCB0aGlzLmFkZHIsIHYgKTtcclxuXHJcblx0XHRjb3B5QXJyYXkoIGNhY2hlLCB2ICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbi8vIFNpbmdsZSBtYXRyaXggKGZyb20gZmxhdCBhcnJheSBvciBUSFJFRS5NYXRyaXhOKVxyXG5cclxuZnVuY3Rpb24gc2V0VmFsdWVNMiggZ2wsIHYgKSB7XHJcblxyXG5cdGNvbnN0IGNhY2hlID0gdGhpcy5jYWNoZTtcclxuXHRjb25zdCBlbGVtZW50cyA9IHYuZWxlbWVudHM7XHJcblxyXG5cdGlmICggZWxlbWVudHMgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRpZiAoIGFycmF5c0VxdWFsKCBjYWNoZSwgdiApICkgcmV0dXJuO1xyXG5cclxuXHRcdGdsLnVuaWZvcm1NYXRyaXgyZnYoIHRoaXMuYWRkciwgZmFsc2UsIHYgKTtcclxuXHJcblx0XHRjb3B5QXJyYXkoIGNhY2hlLCB2ICk7XHJcblxyXG5cdH0gZWxzZSB7XHJcblxyXG5cdFx0aWYgKCBhcnJheXNFcXVhbCggY2FjaGUsIGVsZW1lbnRzICkgKSByZXR1cm47XHJcblxyXG5cdFx0bWF0MmFycmF5LnNldCggZWxlbWVudHMgKTtcclxuXHJcblx0XHRnbC51bmlmb3JtTWF0cml4MmZ2KCB0aGlzLmFkZHIsIGZhbHNlLCBtYXQyYXJyYXkgKTtcclxuXHJcblx0XHRjb3B5QXJyYXkoIGNhY2hlLCBlbGVtZW50cyApO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiBzZXRWYWx1ZU0zKCBnbCwgdiApIHtcclxuXHJcblx0Y29uc3QgY2FjaGUgPSB0aGlzLmNhY2hlO1xyXG5cdGNvbnN0IGVsZW1lbnRzID0gdi5lbGVtZW50cztcclxuXHJcblx0aWYgKCBlbGVtZW50cyA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdGlmICggYXJyYXlzRXF1YWwoIGNhY2hlLCB2ICkgKSByZXR1cm47XHJcblxyXG5cdFx0Z2wudW5pZm9ybU1hdHJpeDNmdiggdGhpcy5hZGRyLCBmYWxzZSwgdiApO1xyXG5cclxuXHRcdGNvcHlBcnJheSggY2FjaGUsIHYgKTtcclxuXHJcblx0fSBlbHNlIHtcclxuXHJcblx0XHRpZiAoIGFycmF5c0VxdWFsKCBjYWNoZSwgZWxlbWVudHMgKSApIHJldHVybjtcclxuXHJcblx0XHRtYXQzYXJyYXkuc2V0KCBlbGVtZW50cyApO1xyXG5cclxuXHRcdGdsLnVuaWZvcm1NYXRyaXgzZnYoIHRoaXMuYWRkciwgZmFsc2UsIG1hdDNhcnJheSApO1xyXG5cclxuXHRcdGNvcHlBcnJheSggY2FjaGUsIGVsZW1lbnRzICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmZ1bmN0aW9uIHNldFZhbHVlTTQoIGdsLCB2ICkge1xyXG5cclxuXHRjb25zdCBjYWNoZSA9IHRoaXMuY2FjaGU7XHJcblx0Y29uc3QgZWxlbWVudHMgPSB2LmVsZW1lbnRzO1xyXG5cclxuXHRpZiAoIGVsZW1lbnRzID09PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0aWYgKCBhcnJheXNFcXVhbCggY2FjaGUsIHYgKSApIHJldHVybjtcclxuXHJcblx0XHRnbC51bmlmb3JtTWF0cml4NGZ2KCB0aGlzLmFkZHIsIGZhbHNlLCB2ICk7XHJcblxyXG5cdFx0Y29weUFycmF5KCBjYWNoZSwgdiApO1xyXG5cclxuXHR9IGVsc2Uge1xyXG5cclxuXHRcdGlmICggYXJyYXlzRXF1YWwoIGNhY2hlLCBlbGVtZW50cyApICkgcmV0dXJuO1xyXG5cclxuXHRcdG1hdDRhcnJheS5zZXQoIGVsZW1lbnRzICk7XHJcblxyXG5cdFx0Z2wudW5pZm9ybU1hdHJpeDRmdiggdGhpcy5hZGRyLCBmYWxzZSwgbWF0NGFycmF5ICk7XHJcblxyXG5cdFx0Y29weUFycmF5KCBjYWNoZSwgZWxlbWVudHMgKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuLy8gU2luZ2xlIGludGVnZXIgLyBib29sZWFuXHJcblxyXG5mdW5jdGlvbiBzZXRWYWx1ZVYxaSggZ2wsIHYgKSB7XHJcblxyXG5cdGNvbnN0IGNhY2hlID0gdGhpcy5jYWNoZTtcclxuXHJcblx0aWYgKCBjYWNoZVsgMCBdID09PSB2ICkgcmV0dXJuO1xyXG5cclxuXHRnbC51bmlmb3JtMWkoIHRoaXMuYWRkciwgdiApO1xyXG5cclxuXHRjYWNoZVsgMCBdID0gdjtcclxuXHJcbn1cclxuXHJcbi8vIFNpbmdsZSBpbnRlZ2VyIC8gYm9vbGVhbiB2ZWN0b3IgKGZyb20gZmxhdCBhcnJheSBvciBUSFJFRS5WZWN0b3JOKVxyXG5cclxuZnVuY3Rpb24gc2V0VmFsdWVWMmkoIGdsLCB2ICkge1xyXG5cclxuXHRjb25zdCBjYWNoZSA9IHRoaXMuY2FjaGU7XHJcblxyXG5cdGlmICggdi54ICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0aWYgKCBjYWNoZVsgMCBdICE9PSB2LnggfHwgY2FjaGVbIDEgXSAhPT0gdi55ICkge1xyXG5cclxuXHRcdFx0Z2wudW5pZm9ybTJpKCB0aGlzLmFkZHIsIHYueCwgdi55ICk7XHJcblxyXG5cdFx0XHRjYWNoZVsgMCBdID0gdi54O1xyXG5cdFx0XHRjYWNoZVsgMSBdID0gdi55O1xyXG5cclxuXHRcdH1cclxuXHJcblx0fSBlbHNlIHtcclxuXHJcblx0XHRpZiAoIGFycmF5c0VxdWFsKCBjYWNoZSwgdiApICkgcmV0dXJuO1xyXG5cclxuXHRcdGdsLnVuaWZvcm0yaXYoIHRoaXMuYWRkciwgdiApO1xyXG5cclxuXHRcdGNvcHlBcnJheSggY2FjaGUsIHYgKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gc2V0VmFsdWVWM2koIGdsLCB2ICkge1xyXG5cclxuXHRjb25zdCBjYWNoZSA9IHRoaXMuY2FjaGU7XHJcblxyXG5cdGlmICggdi54ICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0aWYgKCBjYWNoZVsgMCBdICE9PSB2LnggfHwgY2FjaGVbIDEgXSAhPT0gdi55IHx8IGNhY2hlWyAyIF0gIT09IHYueiApIHtcclxuXHJcblx0XHRcdGdsLnVuaWZvcm0zaSggdGhpcy5hZGRyLCB2LngsIHYueSwgdi56ICk7XHJcblxyXG5cdFx0XHRjYWNoZVsgMCBdID0gdi54O1xyXG5cdFx0XHRjYWNoZVsgMSBdID0gdi55O1xyXG5cdFx0XHRjYWNoZVsgMiBdID0gdi56O1xyXG5cclxuXHRcdH1cclxuXHJcblx0fSBlbHNlIHtcclxuXHJcblx0XHRpZiAoIGFycmF5c0VxdWFsKCBjYWNoZSwgdiApICkgcmV0dXJuO1xyXG5cclxuXHRcdGdsLnVuaWZvcm0zaXYoIHRoaXMuYWRkciwgdiApO1xyXG5cclxuXHRcdGNvcHlBcnJheSggY2FjaGUsIHYgKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gc2V0VmFsdWVWNGkoIGdsLCB2ICkge1xyXG5cclxuXHRjb25zdCBjYWNoZSA9IHRoaXMuY2FjaGU7XHJcblxyXG5cdGlmICggdi54ICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0aWYgKCBjYWNoZVsgMCBdICE9PSB2LnggfHwgY2FjaGVbIDEgXSAhPT0gdi55IHx8IGNhY2hlWyAyIF0gIT09IHYueiB8fCBjYWNoZVsgMyBdICE9PSB2LncgKSB7XHJcblxyXG5cdFx0XHRnbC51bmlmb3JtNGkoIHRoaXMuYWRkciwgdi54LCB2LnksIHYueiwgdi53ICk7XHJcblxyXG5cdFx0XHRjYWNoZVsgMCBdID0gdi54O1xyXG5cdFx0XHRjYWNoZVsgMSBdID0gdi55O1xyXG5cdFx0XHRjYWNoZVsgMiBdID0gdi56O1xyXG5cdFx0XHRjYWNoZVsgMyBdID0gdi53O1xyXG5cclxuXHRcdH1cclxuXHJcblx0fSBlbHNlIHtcclxuXHJcblx0XHRpZiAoIGFycmF5c0VxdWFsKCBjYWNoZSwgdiApICkgcmV0dXJuO1xyXG5cclxuXHRcdGdsLnVuaWZvcm00aXYoIHRoaXMuYWRkciwgdiApO1xyXG5cclxuXHRcdGNvcHlBcnJheSggY2FjaGUsIHYgKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuLy8gU2luZ2xlIHVuc2lnbmVkIGludGVnZXJcclxuXHJcbmZ1bmN0aW9uIHNldFZhbHVlVjF1aSggZ2wsIHYgKSB7XHJcblxyXG5cdGNvbnN0IGNhY2hlID0gdGhpcy5jYWNoZTtcclxuXHJcblx0aWYgKCBjYWNoZVsgMCBdID09PSB2ICkgcmV0dXJuO1xyXG5cclxuXHRnbC51bmlmb3JtMXVpKCB0aGlzLmFkZHIsIHYgKTtcclxuXHJcblx0Y2FjaGVbIDAgXSA9IHY7XHJcblxyXG59XHJcblxyXG4vLyBTaW5nbGUgdW5zaWduZWQgaW50ZWdlciB2ZWN0b3IgKGZyb20gZmxhdCBhcnJheSBvciBUSFJFRS5WZWN0b3JOKVxyXG5cclxuZnVuY3Rpb24gc2V0VmFsdWVWMnVpKCBnbCwgdiApIHtcclxuXHJcblx0Y29uc3QgY2FjaGUgPSB0aGlzLmNhY2hlO1xyXG5cclxuXHRpZiAoIHYueCAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdGlmICggY2FjaGVbIDAgXSAhPT0gdi54IHx8IGNhY2hlWyAxIF0gIT09IHYueSApIHtcclxuXHJcblx0XHRcdGdsLnVuaWZvcm0ydWkoIHRoaXMuYWRkciwgdi54LCB2LnkgKTtcclxuXHJcblx0XHRcdGNhY2hlWyAwIF0gPSB2Lng7XHJcblx0XHRcdGNhY2hlWyAxIF0gPSB2Lnk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9IGVsc2Uge1xyXG5cclxuXHRcdGlmICggYXJyYXlzRXF1YWwoIGNhY2hlLCB2ICkgKSByZXR1cm47XHJcblxyXG5cdFx0Z2wudW5pZm9ybTJ1aXYoIHRoaXMuYWRkciwgdiApO1xyXG5cclxuXHRcdGNvcHlBcnJheSggY2FjaGUsIHYgKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gc2V0VmFsdWVWM3VpKCBnbCwgdiApIHtcclxuXHJcblx0Y29uc3QgY2FjaGUgPSB0aGlzLmNhY2hlO1xyXG5cclxuXHRpZiAoIHYueCAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdGlmICggY2FjaGVbIDAgXSAhPT0gdi54IHx8IGNhY2hlWyAxIF0gIT09IHYueSB8fCBjYWNoZVsgMiBdICE9PSB2LnogKSB7XHJcblxyXG5cdFx0XHRnbC51bmlmb3JtM3VpKCB0aGlzLmFkZHIsIHYueCwgdi55LCB2LnogKTtcclxuXHJcblx0XHRcdGNhY2hlWyAwIF0gPSB2Lng7XHJcblx0XHRcdGNhY2hlWyAxIF0gPSB2Lnk7XHJcblx0XHRcdGNhY2hlWyAyIF0gPSB2Lno7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9IGVsc2Uge1xyXG5cclxuXHRcdGlmICggYXJyYXlzRXF1YWwoIGNhY2hlLCB2ICkgKSByZXR1cm47XHJcblxyXG5cdFx0Z2wudW5pZm9ybTN1aXYoIHRoaXMuYWRkciwgdiApO1xyXG5cclxuXHRcdGNvcHlBcnJheSggY2FjaGUsIHYgKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gc2V0VmFsdWVWNHVpKCBnbCwgdiApIHtcclxuXHJcblx0Y29uc3QgY2FjaGUgPSB0aGlzLmNhY2hlO1xyXG5cclxuXHRpZiAoIHYueCAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdGlmICggY2FjaGVbIDAgXSAhPT0gdi54IHx8IGNhY2hlWyAxIF0gIT09IHYueSB8fCBjYWNoZVsgMiBdICE9PSB2LnogfHwgY2FjaGVbIDMgXSAhPT0gdi53ICkge1xyXG5cclxuXHRcdFx0Z2wudW5pZm9ybTR1aSggdGhpcy5hZGRyLCB2LngsIHYueSwgdi56LCB2LncgKTtcclxuXHJcblx0XHRcdGNhY2hlWyAwIF0gPSB2Lng7XHJcblx0XHRcdGNhY2hlWyAxIF0gPSB2Lnk7XHJcblx0XHRcdGNhY2hlWyAyIF0gPSB2Lno7XHJcblx0XHRcdGNhY2hlWyAzIF0gPSB2Lnc7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9IGVsc2Uge1xyXG5cclxuXHRcdGlmICggYXJyYXlzRXF1YWwoIGNhY2hlLCB2ICkgKSByZXR1cm47XHJcblxyXG5cdFx0Z2wudW5pZm9ybTR1aXYoIHRoaXMuYWRkciwgdiApO1xyXG5cclxuXHRcdGNvcHlBcnJheSggY2FjaGUsIHYgKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuXHJcbi8vIFNpbmdsZSB0ZXh0dXJlICgyRCAvIEN1YmUpXHJcblxyXG5mdW5jdGlvbiBzZXRWYWx1ZVQxKCBnbCwgdiwgdGV4dHVyZXMgKSB7XHJcblxyXG5cdGNvbnN0IGNhY2hlID0gdGhpcy5jYWNoZTtcclxuXHRjb25zdCB1bml0ID0gdGV4dHVyZXMuYWxsb2NhdGVUZXh0dXJlVW5pdCgpO1xyXG5cclxuXHRpZiAoIGNhY2hlWyAwIF0gIT09IHVuaXQgKSB7XHJcblxyXG5cdFx0Z2wudW5pZm9ybTFpKCB0aGlzLmFkZHIsIHVuaXQgKTtcclxuXHRcdGNhY2hlWyAwIF0gPSB1bml0O1xyXG5cclxuXHR9XHJcblxyXG5cdGNvbnN0IGVtcHR5VGV4dHVyZTJEID0gKCB0aGlzLnR5cGUgPT09IGdsLlNBTVBMRVJfMkRfU0hBRE9XICkgPyBlbXB0eVNoYWRvd1RleHR1cmUgOiBlbXB0eVRleHR1cmU7XHJcblxyXG5cdHRleHR1cmVzLnNldFRleHR1cmUyRCggdiB8fCBlbXB0eVRleHR1cmUyRCwgdW5pdCApO1xyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gc2V0VmFsdWVUM0QxKCBnbCwgdiwgdGV4dHVyZXMgKSB7XHJcblxyXG5cdGNvbnN0IGNhY2hlID0gdGhpcy5jYWNoZTtcclxuXHRjb25zdCB1bml0ID0gdGV4dHVyZXMuYWxsb2NhdGVUZXh0dXJlVW5pdCgpO1xyXG5cclxuXHRpZiAoIGNhY2hlWyAwIF0gIT09IHVuaXQgKSB7XHJcblxyXG5cdFx0Z2wudW5pZm9ybTFpKCB0aGlzLmFkZHIsIHVuaXQgKTtcclxuXHRcdGNhY2hlWyAwIF0gPSB1bml0O1xyXG5cclxuXHR9XHJcblxyXG5cdHRleHR1cmVzLnNldFRleHR1cmUzRCggdiB8fCBlbXB0eTNkVGV4dHVyZSwgdW5pdCApO1xyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gc2V0VmFsdWVUNiggZ2wsIHYsIHRleHR1cmVzICkge1xyXG5cclxuXHRjb25zdCBjYWNoZSA9IHRoaXMuY2FjaGU7XHJcblx0Y29uc3QgdW5pdCA9IHRleHR1cmVzLmFsbG9jYXRlVGV4dHVyZVVuaXQoKTtcclxuXHJcblx0aWYgKCBjYWNoZVsgMCBdICE9PSB1bml0ICkge1xyXG5cclxuXHRcdGdsLnVuaWZvcm0xaSggdGhpcy5hZGRyLCB1bml0ICk7XHJcblx0XHRjYWNoZVsgMCBdID0gdW5pdDtcclxuXHJcblx0fVxyXG5cclxuXHR0ZXh0dXJlcy5zZXRUZXh0dXJlQ3ViZSggdiB8fCBlbXB0eUN1YmVUZXh0dXJlLCB1bml0ICk7XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiBzZXRWYWx1ZVQyREFycmF5MSggZ2wsIHYsIHRleHR1cmVzICkge1xyXG5cclxuXHRjb25zdCBjYWNoZSA9IHRoaXMuY2FjaGU7XHJcblx0Y29uc3QgdW5pdCA9IHRleHR1cmVzLmFsbG9jYXRlVGV4dHVyZVVuaXQoKTtcclxuXHJcblx0aWYgKCBjYWNoZVsgMCBdICE9PSB1bml0ICkge1xyXG5cclxuXHRcdGdsLnVuaWZvcm0xaSggdGhpcy5hZGRyLCB1bml0ICk7XHJcblx0XHRjYWNoZVsgMCBdID0gdW5pdDtcclxuXHJcblx0fVxyXG5cclxuXHR0ZXh0dXJlcy5zZXRUZXh0dXJlMkRBcnJheSggdiB8fCBlbXB0eUFycmF5VGV4dHVyZSwgdW5pdCApO1xyXG5cclxufVxyXG5cclxuLy8gSGVscGVyIHRvIHBpY2sgdGhlIHJpZ2h0IHNldHRlciBmb3IgdGhlIHNpbmd1bGFyIGNhc2VcclxuXHJcbmZ1bmN0aW9uIGdldFNpbmd1bGFyU2V0dGVyKCB0eXBlICkge1xyXG5cclxuXHRzd2l0Y2ggKCB0eXBlICkge1xyXG5cclxuXHRcdGNhc2UgMHgxNDA2OiByZXR1cm4gc2V0VmFsdWVWMWY7IC8vIEZMT0FUXHJcblx0XHRjYXNlIDB4OGI1MDogcmV0dXJuIHNldFZhbHVlVjJmOyAvLyBfVkVDMlxyXG5cdFx0Y2FzZSAweDhiNTE6IHJldHVybiBzZXRWYWx1ZVYzZjsgLy8gX1ZFQzNcclxuXHRcdGNhc2UgMHg4YjUyOiByZXR1cm4gc2V0VmFsdWVWNGY7IC8vIF9WRUM0XHJcblxyXG5cdFx0Y2FzZSAweDhiNWE6IHJldHVybiBzZXRWYWx1ZU0yOyAvLyBfTUFUMlxyXG5cdFx0Y2FzZSAweDhiNWI6IHJldHVybiBzZXRWYWx1ZU0zOyAvLyBfTUFUM1xyXG5cdFx0Y2FzZSAweDhiNWM6IHJldHVybiBzZXRWYWx1ZU00OyAvLyBfTUFUNFxyXG5cclxuXHRcdGNhc2UgMHgxNDA0OiBjYXNlIDB4OGI1NjogcmV0dXJuIHNldFZhbHVlVjFpOyAvLyBJTlQsIEJPT0xcclxuXHRcdGNhc2UgMHg4YjUzOiBjYXNlIDB4OGI1NzogcmV0dXJuIHNldFZhbHVlVjJpOyAvLyBfVkVDMlxyXG5cdFx0Y2FzZSAweDhiNTQ6IGNhc2UgMHg4YjU4OiByZXR1cm4gc2V0VmFsdWVWM2k7IC8vIF9WRUMzXHJcblx0XHRjYXNlIDB4OGI1NTogY2FzZSAweDhiNTk6IHJldHVybiBzZXRWYWx1ZVY0aTsgLy8gX1ZFQzRcclxuXHJcblx0XHRjYXNlIDB4MTQwNTogcmV0dXJuIHNldFZhbHVlVjF1aTsgLy8gVUlOVFxyXG5cdFx0Y2FzZSAweDhkYzY6IHJldHVybiBzZXRWYWx1ZVYydWk7IC8vIF9WRUMyXHJcblx0XHRjYXNlIDB4OGRjNzogcmV0dXJuIHNldFZhbHVlVjN1aTsgLy8gX1ZFQzNcclxuXHRcdGNhc2UgMHg4ZGM4OiByZXR1cm4gc2V0VmFsdWVWNHVpOyAvLyBfVkVDNFxyXG5cclxuXHRcdGNhc2UgMHg4YjVlOiAvLyBTQU1QTEVSXzJEXHJcblx0XHRjYXNlIDB4OGQ2NjogLy8gU0FNUExFUl9FWFRFUk5BTF9PRVNcclxuXHRcdGNhc2UgMHg4ZGNhOiAvLyBJTlRfU0FNUExFUl8yRFxyXG5cdFx0Y2FzZSAweDhkZDI6IC8vIFVOU0lHTkVEX0lOVF9TQU1QTEVSXzJEXHJcblx0XHRjYXNlIDB4OGI2MjogLy8gU0FNUExFUl8yRF9TSEFET1dcclxuXHRcdFx0cmV0dXJuIHNldFZhbHVlVDE7XHJcblxyXG5cdFx0Y2FzZSAweDhiNWY6IC8vIFNBTVBMRVJfM0RcclxuXHRcdGNhc2UgMHg4ZGNiOiAvLyBJTlRfU0FNUExFUl8zRFxyXG5cdFx0Y2FzZSAweDhkZDM6IC8vIFVOU0lHTkVEX0lOVF9TQU1QTEVSXzNEXHJcblx0XHRcdHJldHVybiBzZXRWYWx1ZVQzRDE7XHJcblxyXG5cdFx0Y2FzZSAweDhiNjA6IC8vIFNBTVBMRVJfQ1VCRVxyXG5cdFx0Y2FzZSAweDhkY2M6IC8vIElOVF9TQU1QTEVSX0NVQkVcclxuXHRcdGNhc2UgMHg4ZGQ0OiAvLyBVTlNJR05FRF9JTlRfU0FNUExFUl9DVUJFXHJcblx0XHRjYXNlIDB4OGRjNTogLy8gU0FNUExFUl9DVUJFX1NIQURPV1xyXG5cdFx0XHRyZXR1cm4gc2V0VmFsdWVUNjtcclxuXHJcblx0XHRjYXNlIDB4OGRjMTogLy8gU0FNUExFUl8yRF9BUlJBWVxyXG5cdFx0Y2FzZSAweDhkY2Y6IC8vIElOVF9TQU1QTEVSXzJEX0FSUkFZXHJcblx0XHRjYXNlIDB4OGRkNzogLy8gVU5TSUdORURfSU5UX1NBTVBMRVJfMkRfQVJSQVlcclxuXHRcdGNhc2UgMHg4ZGM0OiAvLyBTQU1QTEVSXzJEX0FSUkFZX1NIQURPV1xyXG5cdFx0XHRyZXR1cm4gc2V0VmFsdWVUMkRBcnJheTE7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcblxyXG4vLyBBcnJheSBvZiBzY2FsYXJzXHJcblxyXG5mdW5jdGlvbiBzZXRWYWx1ZVYxZkFycmF5KCBnbCwgdiApIHtcclxuXHJcblx0Z2wudW5pZm9ybTFmdiggdGhpcy5hZGRyLCB2ICk7XHJcblxyXG59XHJcblxyXG4vLyBBcnJheSBvZiB2ZWN0b3JzIChmcm9tIGZsYXQgYXJyYXkgb3IgYXJyYXkgb2YgVEhSRUUuVmVjdG9yTilcclxuXHJcbmZ1bmN0aW9uIHNldFZhbHVlVjJmQXJyYXkoIGdsLCB2ICkge1xyXG5cclxuXHRjb25zdCBkYXRhID0gZmxhdHRlbiggdiwgdGhpcy5zaXplLCAyICk7XHJcblxyXG5cdGdsLnVuaWZvcm0yZnYoIHRoaXMuYWRkciwgZGF0YSApO1xyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gc2V0VmFsdWVWM2ZBcnJheSggZ2wsIHYgKSB7XHJcblxyXG5cdGNvbnN0IGRhdGEgPSBmbGF0dGVuKCB2LCB0aGlzLnNpemUsIDMgKTtcclxuXHJcblx0Z2wudW5pZm9ybTNmdiggdGhpcy5hZGRyLCBkYXRhICk7XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiBzZXRWYWx1ZVY0ZkFycmF5KCBnbCwgdiApIHtcclxuXHJcblx0Y29uc3QgZGF0YSA9IGZsYXR0ZW4oIHYsIHRoaXMuc2l6ZSwgNCApO1xyXG5cclxuXHRnbC51bmlmb3JtNGZ2KCB0aGlzLmFkZHIsIGRhdGEgKTtcclxuXHJcbn1cclxuXHJcbi8vIEFycmF5IG9mIG1hdHJpY2VzIChmcm9tIGZsYXQgYXJyYXkgb3IgYXJyYXkgb2YgVEhSRUUuTWF0cml4TilcclxuXHJcbmZ1bmN0aW9uIHNldFZhbHVlTTJBcnJheSggZ2wsIHYgKSB7XHJcblxyXG5cdGNvbnN0IGRhdGEgPSBmbGF0dGVuKCB2LCB0aGlzLnNpemUsIDQgKTtcclxuXHJcblx0Z2wudW5pZm9ybU1hdHJpeDJmdiggdGhpcy5hZGRyLCBmYWxzZSwgZGF0YSApO1xyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gc2V0VmFsdWVNM0FycmF5KCBnbCwgdiApIHtcclxuXHJcblx0Y29uc3QgZGF0YSA9IGZsYXR0ZW4oIHYsIHRoaXMuc2l6ZSwgOSApO1xyXG5cclxuXHRnbC51bmlmb3JtTWF0cml4M2Z2KCB0aGlzLmFkZHIsIGZhbHNlLCBkYXRhICk7XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiBzZXRWYWx1ZU00QXJyYXkoIGdsLCB2ICkge1xyXG5cclxuXHRjb25zdCBkYXRhID0gZmxhdHRlbiggdiwgdGhpcy5zaXplLCAxNiApO1xyXG5cclxuXHRnbC51bmlmb3JtTWF0cml4NGZ2KCB0aGlzLmFkZHIsIGZhbHNlLCBkYXRhICk7XHJcblxyXG59XHJcblxyXG4vLyBBcnJheSBvZiBpbnRlZ2VyIC8gYm9vbGVhblxyXG5cclxuZnVuY3Rpb24gc2V0VmFsdWVWMWlBcnJheSggZ2wsIHYgKSB7XHJcblxyXG5cdGdsLnVuaWZvcm0xaXYoIHRoaXMuYWRkciwgdiApO1xyXG5cclxufVxyXG5cclxuLy8gQXJyYXkgb2YgaW50ZWdlciAvIGJvb2xlYW4gdmVjdG9ycyAoZnJvbSBmbGF0IGFycmF5KVxyXG5cclxuZnVuY3Rpb24gc2V0VmFsdWVWMmlBcnJheSggZ2wsIHYgKSB7XHJcblxyXG5cdGdsLnVuaWZvcm0yaXYoIHRoaXMuYWRkciwgdiApO1xyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gc2V0VmFsdWVWM2lBcnJheSggZ2wsIHYgKSB7XHJcblxyXG5cdGdsLnVuaWZvcm0zaXYoIHRoaXMuYWRkciwgdiApO1xyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gc2V0VmFsdWVWNGlBcnJheSggZ2wsIHYgKSB7XHJcblxyXG5cdGdsLnVuaWZvcm00aXYoIHRoaXMuYWRkciwgdiApO1xyXG5cclxufVxyXG5cclxuLy8gQXJyYXkgb2YgdW5zaWduZWQgaW50ZWdlclxyXG5cclxuZnVuY3Rpb24gc2V0VmFsdWVWMXVpQXJyYXkoIGdsLCB2ICkge1xyXG5cclxuXHRnbC51bmlmb3JtMXVpdiggdGhpcy5hZGRyLCB2ICk7XHJcblxyXG59XHJcblxyXG4vLyBBcnJheSBvZiB1bnNpZ25lZCBpbnRlZ2VyIHZlY3RvcnMgKGZyb20gZmxhdCBhcnJheSlcclxuXHJcbmZ1bmN0aW9uIHNldFZhbHVlVjJ1aUFycmF5KCBnbCwgdiApIHtcclxuXHJcblx0Z2wudW5pZm9ybTJ1aXYoIHRoaXMuYWRkciwgdiApO1xyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gc2V0VmFsdWVWM3VpQXJyYXkoIGdsLCB2ICkge1xyXG5cclxuXHRnbC51bmlmb3JtM3VpdiggdGhpcy5hZGRyLCB2ICk7XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiBzZXRWYWx1ZVY0dWlBcnJheSggZ2wsIHYgKSB7XHJcblxyXG5cdGdsLnVuaWZvcm00dWl2KCB0aGlzLmFkZHIsIHYgKTtcclxuXHJcbn1cclxuXHJcblxyXG4vLyBBcnJheSBvZiB0ZXh0dXJlcyAoMkQgLyAzRCAvIEN1YmUgLyAyREFycmF5KVxyXG5cclxuZnVuY3Rpb24gc2V0VmFsdWVUMUFycmF5KCBnbCwgdiwgdGV4dHVyZXMgKSB7XHJcblxyXG5cdGNvbnN0IGNhY2hlID0gdGhpcy5jYWNoZTtcclxuXHJcblx0Y29uc3QgbiA9IHYubGVuZ3RoO1xyXG5cclxuXHRjb25zdCB1bml0cyA9IGFsbG9jVGV4VW5pdHMoIHRleHR1cmVzLCBuICk7XHJcblxyXG5cdGlmICggISBhcnJheXNFcXVhbCggY2FjaGUsIHVuaXRzICkgKSB7XHJcblxyXG5cdFx0Z2wudW5pZm9ybTFpdiggdGhpcy5hZGRyLCB1bml0cyApO1xyXG5cclxuXHRcdGNvcHlBcnJheSggY2FjaGUsIHVuaXRzICk7XHJcblxyXG5cdH1cclxuXHJcblx0Zm9yICggbGV0IGkgPSAwOyBpICE9PSBuOyArKyBpICkge1xyXG5cclxuXHRcdHRleHR1cmVzLnNldFRleHR1cmUyRCggdlsgaSBdIHx8IGVtcHR5VGV4dHVyZSwgdW5pdHNbIGkgXSApO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiBzZXRWYWx1ZVQzREFycmF5KCBnbCwgdiwgdGV4dHVyZXMgKSB7XHJcblxyXG5cdGNvbnN0IGNhY2hlID0gdGhpcy5jYWNoZTtcclxuXHJcblx0Y29uc3QgbiA9IHYubGVuZ3RoO1xyXG5cclxuXHRjb25zdCB1bml0cyA9IGFsbG9jVGV4VW5pdHMoIHRleHR1cmVzLCBuICk7XHJcblxyXG5cdGlmICggISBhcnJheXNFcXVhbCggY2FjaGUsIHVuaXRzICkgKSB7XHJcblxyXG5cdFx0Z2wudW5pZm9ybTFpdiggdGhpcy5hZGRyLCB1bml0cyApO1xyXG5cclxuXHRcdGNvcHlBcnJheSggY2FjaGUsIHVuaXRzICk7XHJcblxyXG5cdH1cclxuXHJcblx0Zm9yICggbGV0IGkgPSAwOyBpICE9PSBuOyArKyBpICkge1xyXG5cclxuXHRcdHRleHR1cmVzLnNldFRleHR1cmUzRCggdlsgaSBdIHx8IGVtcHR5M2RUZXh0dXJlLCB1bml0c1sgaSBdICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmZ1bmN0aW9uIHNldFZhbHVlVDZBcnJheSggZ2wsIHYsIHRleHR1cmVzICkge1xyXG5cclxuXHRjb25zdCBjYWNoZSA9IHRoaXMuY2FjaGU7XHJcblxyXG5cdGNvbnN0IG4gPSB2Lmxlbmd0aDtcclxuXHJcblx0Y29uc3QgdW5pdHMgPSBhbGxvY1RleFVuaXRzKCB0ZXh0dXJlcywgbiApO1xyXG5cclxuXHRpZiAoICEgYXJyYXlzRXF1YWwoIGNhY2hlLCB1bml0cyApICkge1xyXG5cclxuXHRcdGdsLnVuaWZvcm0xaXYoIHRoaXMuYWRkciwgdW5pdHMgKTtcclxuXHJcblx0XHRjb3B5QXJyYXkoIGNhY2hlLCB1bml0cyApO1xyXG5cclxuXHR9XHJcblxyXG5cdGZvciAoIGxldCBpID0gMDsgaSAhPT0gbjsgKysgaSApIHtcclxuXHJcblx0XHR0ZXh0dXJlcy5zZXRUZXh0dXJlQ3ViZSggdlsgaSBdIHx8IGVtcHR5Q3ViZVRleHR1cmUsIHVuaXRzWyBpIF0gKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gc2V0VmFsdWVUMkRBcnJheUFycmF5KCBnbCwgdiwgdGV4dHVyZXMgKSB7XHJcblxyXG5cdGNvbnN0IGNhY2hlID0gdGhpcy5jYWNoZTtcclxuXHJcblx0Y29uc3QgbiA9IHYubGVuZ3RoO1xyXG5cclxuXHRjb25zdCB1bml0cyA9IGFsbG9jVGV4VW5pdHMoIHRleHR1cmVzLCBuICk7XHJcblxyXG5cdGlmICggISBhcnJheXNFcXVhbCggY2FjaGUsIHVuaXRzICkgKSB7XHJcblxyXG5cdFx0Z2wudW5pZm9ybTFpdiggdGhpcy5hZGRyLCB1bml0cyApO1xyXG5cclxuXHRcdGNvcHlBcnJheSggY2FjaGUsIHVuaXRzICk7XHJcblxyXG5cdH1cclxuXHJcblx0Zm9yICggbGV0IGkgPSAwOyBpICE9PSBuOyArKyBpICkge1xyXG5cclxuXHRcdHRleHR1cmVzLnNldFRleHR1cmUyREFycmF5KCB2WyBpIF0gfHwgZW1wdHlBcnJheVRleHR1cmUsIHVuaXRzWyBpIF0gKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuXHJcbi8vIEhlbHBlciB0byBwaWNrIHRoZSByaWdodCBzZXR0ZXIgZm9yIGEgcHVyZSAoYm90dG9tLWxldmVsKSBhcnJheVxyXG5cclxuZnVuY3Rpb24gZ2V0UHVyZUFycmF5U2V0dGVyKCB0eXBlICkge1xyXG5cclxuXHRzd2l0Y2ggKCB0eXBlICkge1xyXG5cclxuXHRcdGNhc2UgMHgxNDA2OiByZXR1cm4gc2V0VmFsdWVWMWZBcnJheTsgLy8gRkxPQVRcclxuXHRcdGNhc2UgMHg4YjUwOiByZXR1cm4gc2V0VmFsdWVWMmZBcnJheTsgLy8gX1ZFQzJcclxuXHRcdGNhc2UgMHg4YjUxOiByZXR1cm4gc2V0VmFsdWVWM2ZBcnJheTsgLy8gX1ZFQzNcclxuXHRcdGNhc2UgMHg4YjUyOiByZXR1cm4gc2V0VmFsdWVWNGZBcnJheTsgLy8gX1ZFQzRcclxuXHJcblx0XHRjYXNlIDB4OGI1YTogcmV0dXJuIHNldFZhbHVlTTJBcnJheTsgLy8gX01BVDJcclxuXHRcdGNhc2UgMHg4YjViOiByZXR1cm4gc2V0VmFsdWVNM0FycmF5OyAvLyBfTUFUM1xyXG5cdFx0Y2FzZSAweDhiNWM6IHJldHVybiBzZXRWYWx1ZU00QXJyYXk7IC8vIF9NQVQ0XHJcblxyXG5cdFx0Y2FzZSAweDE0MDQ6IGNhc2UgMHg4YjU2OiByZXR1cm4gc2V0VmFsdWVWMWlBcnJheTsgLy8gSU5ULCBCT09MXHJcblx0XHRjYXNlIDB4OGI1MzogY2FzZSAweDhiNTc6IHJldHVybiBzZXRWYWx1ZVYyaUFycmF5OyAvLyBfVkVDMlxyXG5cdFx0Y2FzZSAweDhiNTQ6IGNhc2UgMHg4YjU4OiByZXR1cm4gc2V0VmFsdWVWM2lBcnJheTsgLy8gX1ZFQzNcclxuXHRcdGNhc2UgMHg4YjU1OiBjYXNlIDB4OGI1OTogcmV0dXJuIHNldFZhbHVlVjRpQXJyYXk7IC8vIF9WRUM0XHJcblxyXG5cdFx0Y2FzZSAweDE0MDU6IHJldHVybiBzZXRWYWx1ZVYxdWlBcnJheTsgLy8gVUlOVFxyXG5cdFx0Y2FzZSAweDhkYzY6IHJldHVybiBzZXRWYWx1ZVYydWlBcnJheTsgLy8gX1ZFQzJcclxuXHRcdGNhc2UgMHg4ZGM3OiByZXR1cm4gc2V0VmFsdWVWM3VpQXJyYXk7IC8vIF9WRUMzXHJcblx0XHRjYXNlIDB4OGRjODogcmV0dXJuIHNldFZhbHVlVjR1aUFycmF5OyAvLyBfVkVDNFxyXG5cclxuXHRcdGNhc2UgMHg4YjVlOiAvLyBTQU1QTEVSXzJEXHJcblx0XHRjYXNlIDB4OGQ2NjogLy8gU0FNUExFUl9FWFRFUk5BTF9PRVNcclxuXHRcdGNhc2UgMHg4ZGNhOiAvLyBJTlRfU0FNUExFUl8yRFxyXG5cdFx0Y2FzZSAweDhkZDI6IC8vIFVOU0lHTkVEX0lOVF9TQU1QTEVSXzJEXHJcblx0XHRjYXNlIDB4OGI2MjogLy8gU0FNUExFUl8yRF9TSEFET1dcclxuXHRcdFx0cmV0dXJuIHNldFZhbHVlVDFBcnJheTtcclxuXHJcblx0XHRjYXNlIDB4OGI1ZjogLy8gU0FNUExFUl8zRFxyXG5cdFx0Y2FzZSAweDhkY2I6IC8vIElOVF9TQU1QTEVSXzNEXHJcblx0XHRjYXNlIDB4OGRkMzogLy8gVU5TSUdORURfSU5UX1NBTVBMRVJfM0RcclxuXHRcdFx0cmV0dXJuIHNldFZhbHVlVDNEQXJyYXk7XHJcblxyXG5cdFx0Y2FzZSAweDhiNjA6IC8vIFNBTVBMRVJfQ1VCRVxyXG5cdFx0Y2FzZSAweDhkY2M6IC8vIElOVF9TQU1QTEVSX0NVQkVcclxuXHRcdGNhc2UgMHg4ZGQ0OiAvLyBVTlNJR05FRF9JTlRfU0FNUExFUl9DVUJFXHJcblx0XHRjYXNlIDB4OGRjNTogLy8gU0FNUExFUl9DVUJFX1NIQURPV1xyXG5cdFx0XHRyZXR1cm4gc2V0VmFsdWVUNkFycmF5O1xyXG5cclxuXHRcdGNhc2UgMHg4ZGMxOiAvLyBTQU1QTEVSXzJEX0FSUkFZXHJcblx0XHRjYXNlIDB4OGRjZjogLy8gSU5UX1NBTVBMRVJfMkRfQVJSQVlcclxuXHRcdGNhc2UgMHg4ZGQ3OiAvLyBVTlNJR05FRF9JTlRfU0FNUExFUl8yRF9BUlJBWVxyXG5cdFx0Y2FzZSAweDhkYzQ6IC8vIFNBTVBMRVJfMkRfQVJSQVlfU0hBRE9XXHJcblx0XHRcdHJldHVybiBzZXRWYWx1ZVQyREFycmF5QXJyYXk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbi8vIC0tLSBVbmlmb3JtIENsYXNzZXMgLS0tXHJcblxyXG5jbGFzcyBTaW5nbGVVbmlmb3JtIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIGlkLCBhY3RpdmVJbmZvLCBhZGRyICkge1xyXG5cclxuXHRcdHRoaXMuaWQgPSBpZDtcclxuXHRcdHRoaXMuYWRkciA9IGFkZHI7XHJcblx0XHR0aGlzLmNhY2hlID0gW107XHJcblx0XHR0aGlzLnR5cGUgPSBhY3RpdmVJbmZvLnR5cGU7XHJcblx0XHR0aGlzLnNldFZhbHVlID0gZ2V0U2luZ3VsYXJTZXR0ZXIoIGFjdGl2ZUluZm8udHlwZSApO1xyXG5cclxuXHRcdC8vIHRoaXMucGF0aCA9IGFjdGl2ZUluZm8ubmFtZTsgLy8gREVCVUdcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuY2xhc3MgUHVyZUFycmF5VW5pZm9ybSB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBpZCwgYWN0aXZlSW5mbywgYWRkciApIHtcclxuXHJcblx0XHR0aGlzLmlkID0gaWQ7XHJcblx0XHR0aGlzLmFkZHIgPSBhZGRyO1xyXG5cdFx0dGhpcy5jYWNoZSA9IFtdO1xyXG5cdFx0dGhpcy50eXBlID0gYWN0aXZlSW5mby50eXBlO1xyXG5cdFx0dGhpcy5zaXplID0gYWN0aXZlSW5mby5zaXplO1xyXG5cdFx0dGhpcy5zZXRWYWx1ZSA9IGdldFB1cmVBcnJheVNldHRlciggYWN0aXZlSW5mby50eXBlICk7XHJcblxyXG5cdFx0Ly8gdGhpcy5wYXRoID0gYWN0aXZlSW5mby5uYW1lOyAvLyBERUJVR1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5jbGFzcyBTdHJ1Y3R1cmVkVW5pZm9ybSB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBpZCApIHtcclxuXHJcblx0XHR0aGlzLmlkID0gaWQ7XHJcblxyXG5cdFx0dGhpcy5zZXEgPSBbXTtcclxuXHRcdHRoaXMubWFwID0ge307XHJcblxyXG5cdH1cclxuXHJcblx0c2V0VmFsdWUoIGdsLCB2YWx1ZSwgdGV4dHVyZXMgKSB7XHJcblxyXG5cdFx0Y29uc3Qgc2VxID0gdGhpcy5zZXE7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBuID0gc2VxLmxlbmd0aDsgaSAhPT0gbjsgKysgaSApIHtcclxuXHJcblx0XHRcdGNvbnN0IHUgPSBzZXFbIGkgXTtcclxuXHRcdFx0dS5zZXRWYWx1ZSggZ2wsIHZhbHVlWyB1LmlkIF0sIHRleHR1cmVzICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG4vLyAtLS0gVG9wLWxldmVsIC0tLVxyXG5cclxuLy8gUGFyc2VyIC0gYnVpbGRzIHVwIHRoZSBwcm9wZXJ0eSB0cmVlIGZyb20gdGhlIHBhdGggc3RyaW5nc1xyXG5cclxuY29uc3QgUmVQYXRoUGFydCA9IC8oXFx3KykoXFxdKT8oXFxbfFxcLik/L2c7XHJcblxyXG4vLyBleHRyYWN0c1xyXG4vLyBcdC0gdGhlIGlkZW50aWZpZXIgKG1lbWJlciBuYW1lIG9yIGFycmF5IGluZGV4KVxyXG4vLyAgLSBmb2xsb3dlZCBieSBhbiBvcHRpb25hbCByaWdodCBicmFja2V0IChmb3VuZCB3aGVuIGFycmF5IGluZGV4KVxyXG4vLyAgLSBmb2xsb3dlZCBieSBhbiBvcHRpb25hbCBsZWZ0IGJyYWNrZXQgb3IgZG90ICh0eXBlIG9mIHN1YnNjcmlwdClcclxuLy9cclxuLy8gTm90ZTogVGhlc2UgcG9ydGlvbnMgY2FuIGJlIHJlYWQgaW4gYSBub24tb3ZlcmxhcHBpbmcgZmFzaGlvbiBhbmRcclxuLy8gYWxsb3cgc3RyYWlnaHRmb3J3YXJkIHBhcnNpbmcgb2YgdGhlIGhpZXJhcmNoeSB0aGF0IFdlYkdMIGVuY29kZXNcclxuLy8gaW4gdGhlIHVuaWZvcm0gbmFtZXMuXHJcblxyXG5mdW5jdGlvbiBhZGRVbmlmb3JtKCBjb250YWluZXIsIHVuaWZvcm1PYmplY3QgKSB7XHJcblxyXG5cdGNvbnRhaW5lci5zZXEucHVzaCggdW5pZm9ybU9iamVjdCApO1xyXG5cdGNvbnRhaW5lci5tYXBbIHVuaWZvcm1PYmplY3QuaWQgXSA9IHVuaWZvcm1PYmplY3Q7XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiBwYXJzZVVuaWZvcm0oIGFjdGl2ZUluZm8sIGFkZHIsIGNvbnRhaW5lciApIHtcclxuXHJcblx0Y29uc3QgcGF0aCA9IGFjdGl2ZUluZm8ubmFtZSxcclxuXHRcdHBhdGhMZW5ndGggPSBwYXRoLmxlbmd0aDtcclxuXHJcblx0Ly8gcmVzZXQgUmVnRXhwIG9iamVjdCwgYmVjYXVzZSBvZiB0aGUgZWFybHkgZXhpdCBvZiBhIHByZXZpb3VzIHJ1blxyXG5cdFJlUGF0aFBhcnQubGFzdEluZGV4ID0gMDtcclxuXHJcblx0d2hpbGUgKCB0cnVlICkge1xyXG5cclxuXHRcdGNvbnN0IG1hdGNoID0gUmVQYXRoUGFydC5leGVjKCBwYXRoICksXHJcblx0XHRcdG1hdGNoRW5kID0gUmVQYXRoUGFydC5sYXN0SW5kZXg7XHJcblxyXG5cdFx0bGV0IGlkID0gbWF0Y2hbIDEgXTtcclxuXHRcdGNvbnN0IGlkSXNJbmRleCA9IG1hdGNoWyAyIF0gPT09ICddJyxcclxuXHRcdFx0c3Vic2NyaXB0ID0gbWF0Y2hbIDMgXTtcclxuXHJcblx0XHRpZiAoIGlkSXNJbmRleCApIGlkID0gaWQgfCAwOyAvLyBjb252ZXJ0IHRvIGludGVnZXJcclxuXHJcblx0XHRpZiAoIHN1YnNjcmlwdCA9PT0gdW5kZWZpbmVkIHx8IHN1YnNjcmlwdCA9PT0gJ1snICYmIG1hdGNoRW5kICsgMiA9PT0gcGF0aExlbmd0aCApIHtcclxuXHJcblx0XHRcdC8vIGJhcmUgbmFtZSBvciBcInB1cmVcIiBib3R0b20tbGV2ZWwgYXJyYXkgXCJbMF1cIiBzdWZmaXhcclxuXHJcblx0XHRcdGFkZFVuaWZvcm0oIGNvbnRhaW5lciwgc3Vic2NyaXB0ID09PSB1bmRlZmluZWQgP1xyXG5cdFx0XHRcdG5ldyBTaW5nbGVVbmlmb3JtKCBpZCwgYWN0aXZlSW5mbywgYWRkciApIDpcclxuXHRcdFx0XHRuZXcgUHVyZUFycmF5VW5pZm9ybSggaWQsIGFjdGl2ZUluZm8sIGFkZHIgKSApO1xyXG5cclxuXHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdC8vIHN0ZXAgaW50byBpbm5lciBub2RlIC8gY3JlYXRlIGl0IGluIGNhc2UgaXQgZG9lc24ndCBleGlzdFxyXG5cclxuXHRcdFx0Y29uc3QgbWFwID0gY29udGFpbmVyLm1hcDtcclxuXHRcdFx0bGV0IG5leHQgPSBtYXBbIGlkIF07XHJcblxyXG5cdFx0XHRpZiAoIG5leHQgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0bmV4dCA9IG5ldyBTdHJ1Y3R1cmVkVW5pZm9ybSggaWQgKTtcclxuXHRcdFx0XHRhZGRVbmlmb3JtKCBjb250YWluZXIsIG5leHQgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGNvbnRhaW5lciA9IG5leHQ7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG4vLyBSb290IENvbnRhaW5lclxyXG5cclxuY2xhc3MgV2ViR0xVbmlmb3JtcyB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBnbCwgcHJvZ3JhbSApIHtcclxuXHJcblx0XHR0aGlzLnNlcSA9IFtdO1xyXG5cdFx0dGhpcy5tYXAgPSB7fTtcclxuXHJcblx0XHRjb25zdCBuID0gZ2wuZ2V0UHJvZ3JhbVBhcmFtZXRlciggcHJvZ3JhbSwgZ2wuQUNUSVZFX1VOSUZPUk1TICk7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgbjsgKysgaSApIHtcclxuXHJcblx0XHRcdGNvbnN0IGluZm8gPSBnbC5nZXRBY3RpdmVVbmlmb3JtKCBwcm9ncmFtLCBpICksXHJcblx0XHRcdFx0YWRkciA9IGdsLmdldFVuaWZvcm1Mb2NhdGlvbiggcHJvZ3JhbSwgaW5mby5uYW1lICk7XHJcblxyXG5cdFx0XHRwYXJzZVVuaWZvcm0oIGluZm8sIGFkZHIsIHRoaXMgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0c2V0VmFsdWUoIGdsLCBuYW1lLCB2YWx1ZSwgdGV4dHVyZXMgKSB7XHJcblxyXG5cdFx0Y29uc3QgdSA9IHRoaXMubWFwWyBuYW1lIF07XHJcblxyXG5cdFx0aWYgKCB1ICE9PSB1bmRlZmluZWQgKSB1LnNldFZhbHVlKCBnbCwgdmFsdWUsIHRleHR1cmVzICk7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0T3B0aW9uYWwoIGdsLCBvYmplY3QsIG5hbWUgKSB7XHJcblxyXG5cdFx0Y29uc3QgdiA9IG9iamVjdFsgbmFtZSBdO1xyXG5cclxuXHRcdGlmICggdiAhPT0gdW5kZWZpbmVkICkgdGhpcy5zZXRWYWx1ZSggZ2wsIG5hbWUsIHYgKTtcclxuXHJcblx0fVxyXG5cclxuXHRzdGF0aWMgdXBsb2FkKCBnbCwgc2VxLCB2YWx1ZXMsIHRleHR1cmVzICkge1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMCwgbiA9IHNlcS5sZW5ndGg7IGkgIT09IG47ICsrIGkgKSB7XHJcblxyXG5cdFx0XHRjb25zdCB1ID0gc2VxWyBpIF0sXHJcblx0XHRcdFx0diA9IHZhbHVlc1sgdS5pZCBdO1xyXG5cclxuXHRcdFx0aWYgKCB2Lm5lZWRzVXBkYXRlICE9PSBmYWxzZSApIHtcclxuXHJcblx0XHRcdFx0Ly8gbm90ZTogYWx3YXlzIHVwZGF0aW5nIHdoZW4gLm5lZWRzVXBkYXRlIGlzIHVuZGVmaW5lZFxyXG5cdFx0XHRcdHUuc2V0VmFsdWUoIGdsLCB2LnZhbHVlLCB0ZXh0dXJlcyApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRzdGF0aWMgc2VxV2l0aFZhbHVlKCBzZXEsIHZhbHVlcyApIHtcclxuXHJcblx0XHRjb25zdCByID0gW107XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBuID0gc2VxLmxlbmd0aDsgaSAhPT0gbjsgKysgaSApIHtcclxuXHJcblx0XHRcdGNvbnN0IHUgPSBzZXFbIGkgXTtcclxuXHRcdFx0aWYgKCB1LmlkIGluIHZhbHVlcyApIHIucHVzaCggdSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gcjtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgV2ViR0xVbmlmb3JtcyB9O1xyXG4iLCJmdW5jdGlvbiBXZWJHTFNoYWRlciggZ2wsIHR5cGUsIHN0cmluZyApIHtcclxuXHJcblx0Y29uc3Qgc2hhZGVyID0gZ2wuY3JlYXRlU2hhZGVyKCB0eXBlICk7XHJcblxyXG5cdGdsLnNoYWRlclNvdXJjZSggc2hhZGVyLCBzdHJpbmcgKTtcclxuXHRnbC5jb21waWxlU2hhZGVyKCBzaGFkZXIgKTtcclxuXHJcblx0cmV0dXJuIHNoYWRlcjtcclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IFdlYkdMU2hhZGVyIH07XHJcbiIsImltcG9ydCB7IFdlYkdMVW5pZm9ybXMgfSBmcm9tICcuL1dlYkdMVW5pZm9ybXMuanMnO1xyXG5pbXBvcnQgeyBXZWJHTFNoYWRlciB9IGZyb20gJy4vV2ViR0xTaGFkZXIuanMnO1xyXG5pbXBvcnQgeyBTaGFkZXJDaHVuayB9IGZyb20gJy4uL3NoYWRlcnMvU2hhZGVyQ2h1bmsuanMnO1xyXG5pbXBvcnQgeyBOb1RvbmVNYXBwaW5nLCBBZGRPcGVyYXRpb24sIE1peE9wZXJhdGlvbiwgTXVsdGlwbHlPcGVyYXRpb24sIEN1YmVSZWZyYWN0aW9uTWFwcGluZywgQ3ViZVVWUmVmbGVjdGlvbk1hcHBpbmcsIEN1YmVSZWZsZWN0aW9uTWFwcGluZywgUENGU29mdFNoYWRvd01hcCwgUENGU2hhZG93TWFwLCBWU01TaGFkb3dNYXAsIEFnWFRvbmVNYXBwaW5nLCBBQ0VTRmlsbWljVG9uZU1hcHBpbmcsIENpbmVvblRvbmVNYXBwaW5nLCBDdXN0b21Ub25lTWFwcGluZywgUmVpbmhhcmRUb25lTWFwcGluZywgTGluZWFyVG9uZU1hcHBpbmcsIEdMU0wzLCBMaW5lYXJTUkdCQ29sb3JTcGFjZSwgU1JHQkNvbG9yU3BhY2UsIExpbmVhckRpc3BsYXlQM0NvbG9yU3BhY2UsIERpc3BsYXlQM0NvbG9yU3BhY2UsIFAzUHJpbWFyaWVzLCBSZWM3MDlQcmltYXJpZXMgfSBmcm9tICcuLi8uLi9jb25zdGFudHMuanMnO1xyXG5pbXBvcnQgeyBDb2xvck1hbmFnZW1lbnQgfSBmcm9tICcuLi8uLi9tYXRoL0NvbG9yTWFuYWdlbWVudC5qcyc7XHJcblxyXG4vLyBGcm9tIGh0dHBzOi8vd3d3Lmtocm9ub3Mub3JnL3JlZ2lzdHJ5L3dlYmdsL2V4dGVuc2lvbnMvS0hSX3BhcmFsbGVsX3NoYWRlcl9jb21waWxlL1xyXG5jb25zdCBDT01QTEVUSU9OX1NUQVRVU19LSFIgPSAweDkxQjE7XHJcblxyXG5sZXQgcHJvZ3JhbUlkQ291bnQgPSAwO1xyXG5cclxuZnVuY3Rpb24gaGFuZGxlU291cmNlKCBzdHJpbmcsIGVycm9yTGluZSApIHtcclxuXHJcblx0Y29uc3QgbGluZXMgPSBzdHJpbmcuc3BsaXQoICdcXG4nICk7XHJcblx0Y29uc3QgbGluZXMyID0gW107XHJcblxyXG5cdGNvbnN0IGZyb20gPSBNYXRoLm1heCggZXJyb3JMaW5lIC0gNiwgMCApO1xyXG5cdGNvbnN0IHRvID0gTWF0aC5taW4oIGVycm9yTGluZSArIDYsIGxpbmVzLmxlbmd0aCApO1xyXG5cclxuXHRmb3IgKCBsZXQgaSA9IGZyb207IGkgPCB0bzsgaSArKyApIHtcclxuXHJcblx0XHRjb25zdCBsaW5lID0gaSArIDE7XHJcblx0XHRsaW5lczIucHVzaCggYCR7bGluZSA9PT0gZXJyb3JMaW5lID8gJz4nIDogJyAnfSAke2xpbmV9OiAke2xpbmVzWyBpIF19YCApO1xyXG5cclxuXHR9XHJcblxyXG5cdHJldHVybiBsaW5lczIuam9pbiggJ1xcbicgKTtcclxuXHJcbn1cclxuXHJcbmZ1bmN0aW9uIGdldEVuY29kaW5nQ29tcG9uZW50cyggY29sb3JTcGFjZSApIHtcclxuXHJcblx0Y29uc3Qgd29ya2luZ1ByaW1hcmllcyA9IENvbG9yTWFuYWdlbWVudC5nZXRQcmltYXJpZXMoIENvbG9yTWFuYWdlbWVudC53b3JraW5nQ29sb3JTcGFjZSApO1xyXG5cdGNvbnN0IGVuY29kaW5nUHJpbWFyaWVzID0gQ29sb3JNYW5hZ2VtZW50LmdldFByaW1hcmllcyggY29sb3JTcGFjZSApO1xyXG5cclxuXHRsZXQgZ2FtdXRNYXBwaW5nO1xyXG5cclxuXHRpZiAoIHdvcmtpbmdQcmltYXJpZXMgPT09IGVuY29kaW5nUHJpbWFyaWVzICkge1xyXG5cclxuXHRcdGdhbXV0TWFwcGluZyA9ICcnO1xyXG5cclxuXHR9IGVsc2UgaWYgKCB3b3JraW5nUHJpbWFyaWVzID09PSBQM1ByaW1hcmllcyAmJiBlbmNvZGluZ1ByaW1hcmllcyA9PT0gUmVjNzA5UHJpbWFyaWVzICkge1xyXG5cclxuXHRcdGdhbXV0TWFwcGluZyA9ICdMaW5lYXJEaXNwbGF5UDNUb0xpbmVhclNSR0InO1xyXG5cclxuXHR9IGVsc2UgaWYgKCB3b3JraW5nUHJpbWFyaWVzID09PSBSZWM3MDlQcmltYXJpZXMgJiYgZW5jb2RpbmdQcmltYXJpZXMgPT09IFAzUHJpbWFyaWVzICkge1xyXG5cclxuXHRcdGdhbXV0TWFwcGluZyA9ICdMaW5lYXJTUkdCVG9MaW5lYXJEaXNwbGF5UDMnO1xyXG5cclxuXHR9XHJcblxyXG5cdHN3aXRjaCAoIGNvbG9yU3BhY2UgKSB7XHJcblxyXG5cdFx0Y2FzZSBMaW5lYXJTUkdCQ29sb3JTcGFjZTpcclxuXHRcdGNhc2UgTGluZWFyRGlzcGxheVAzQ29sb3JTcGFjZTpcclxuXHRcdFx0cmV0dXJuIFsgZ2FtdXRNYXBwaW5nLCAnTGluZWFyVHJhbnNmZXJPRVRGJyBdO1xyXG5cclxuXHRcdGNhc2UgU1JHQkNvbG9yU3BhY2U6XHJcblx0XHRjYXNlIERpc3BsYXlQM0NvbG9yU3BhY2U6XHJcblx0XHRcdHJldHVybiBbIGdhbXV0TWFwcGluZywgJ3NSR0JUcmFuc2Zlck9FVEYnIF07XHJcblxyXG5cdFx0ZGVmYXVsdDpcclxuXHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuV2ViR0xQcm9ncmFtOiBVbnN1cHBvcnRlZCBjb2xvciBzcGFjZTonLCBjb2xvclNwYWNlICk7XHJcblx0XHRcdHJldHVybiBbIGdhbXV0TWFwcGluZywgJ0xpbmVhclRyYW5zZmVyT0VURicgXTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gZ2V0U2hhZGVyRXJyb3JzKCBnbCwgc2hhZGVyLCB0eXBlICkge1xyXG5cclxuXHRjb25zdCBzdGF0dXMgPSBnbC5nZXRTaGFkZXJQYXJhbWV0ZXIoIHNoYWRlciwgZ2wuQ09NUElMRV9TVEFUVVMgKTtcclxuXHRjb25zdCBlcnJvcnMgPSBnbC5nZXRTaGFkZXJJbmZvTG9nKCBzaGFkZXIgKS50cmltKCk7XHJcblxyXG5cdGlmICggc3RhdHVzICYmIGVycm9ycyA9PT0gJycgKSByZXR1cm4gJyc7XHJcblxyXG5cdGNvbnN0IGVycm9yTWF0Y2hlcyA9IC9FUlJPUjogMDooXFxkKykvLmV4ZWMoIGVycm9ycyApO1xyXG5cdGlmICggZXJyb3JNYXRjaGVzICkge1xyXG5cclxuXHRcdC8vIC0tZW5hYmxlLXByaXZpbGVnZWQtd2ViZ2wtZXh0ZW5zaW9uXHJcblx0XHQvLyBjb25zb2xlLmxvZyggJyoqJyArIHR5cGUgKyAnKionLCBnbC5nZXRFeHRlbnNpb24oICdXRUJHTF9kZWJ1Z19zaGFkZXJzJyApLmdldFRyYW5zbGF0ZWRTaGFkZXJTb3VyY2UoIHNoYWRlciApICk7XHJcblxyXG5cdFx0Y29uc3QgZXJyb3JMaW5lID0gcGFyc2VJbnQoIGVycm9yTWF0Y2hlc1sgMSBdICk7XHJcblx0XHRyZXR1cm4gdHlwZS50b1VwcGVyQ2FzZSgpICsgJ1xcblxcbicgKyBlcnJvcnMgKyAnXFxuXFxuJyArIGhhbmRsZVNvdXJjZSggZ2wuZ2V0U2hhZGVyU291cmNlKCBzaGFkZXIgKSwgZXJyb3JMaW5lICk7XHJcblxyXG5cdH0gZWxzZSB7XHJcblxyXG5cdFx0cmV0dXJuIGVycm9ycztcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gZ2V0VGV4ZWxFbmNvZGluZ0Z1bmN0aW9uKCBmdW5jdGlvbk5hbWUsIGNvbG9yU3BhY2UgKSB7XHJcblxyXG5cdGNvbnN0IGNvbXBvbmVudHMgPSBnZXRFbmNvZGluZ0NvbXBvbmVudHMoIGNvbG9yU3BhY2UgKTtcclxuXHRyZXR1cm4gYHZlYzQgJHtmdW5jdGlvbk5hbWV9KCB2ZWM0IHZhbHVlICkgeyByZXR1cm4gJHtjb21wb25lbnRzWyAwIF19KCAke2NvbXBvbmVudHNbIDEgXX0oIHZhbHVlICkgKTsgfWA7XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiBnZXRUb25lTWFwcGluZ0Z1bmN0aW9uKCBmdW5jdGlvbk5hbWUsIHRvbmVNYXBwaW5nICkge1xyXG5cclxuXHRsZXQgdG9uZU1hcHBpbmdOYW1lO1xyXG5cclxuXHRzd2l0Y2ggKCB0b25lTWFwcGluZyApIHtcclxuXHJcblx0XHRjYXNlIExpbmVhclRvbmVNYXBwaW5nOlxyXG5cdFx0XHR0b25lTWFwcGluZ05hbWUgPSAnTGluZWFyJztcclxuXHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0Y2FzZSBSZWluaGFyZFRvbmVNYXBwaW5nOlxyXG5cdFx0XHR0b25lTWFwcGluZ05hbWUgPSAnUmVpbmhhcmQnO1xyXG5cdFx0XHRicmVhaztcclxuXHJcblx0XHRjYXNlIENpbmVvblRvbmVNYXBwaW5nOlxyXG5cdFx0XHR0b25lTWFwcGluZ05hbWUgPSAnT3B0aW1pemVkQ2luZW9uJztcclxuXHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0Y2FzZSBBQ0VTRmlsbWljVG9uZU1hcHBpbmc6XHJcblx0XHRcdHRvbmVNYXBwaW5nTmFtZSA9ICdBQ0VTRmlsbWljJztcclxuXHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0Y2FzZSBBZ1hUb25lTWFwcGluZzpcclxuXHRcdFx0dG9uZU1hcHBpbmdOYW1lID0gJ0FnWCc7XHJcblx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdGNhc2UgQ3VzdG9tVG9uZU1hcHBpbmc6XHJcblx0XHRcdHRvbmVNYXBwaW5nTmFtZSA9ICdDdXN0b20nO1xyXG5cdFx0XHRicmVhaztcclxuXHJcblx0XHRkZWZhdWx0OlxyXG5cdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5XZWJHTFByb2dyYW06IFVuc3VwcG9ydGVkIHRvbmVNYXBwaW5nOicsIHRvbmVNYXBwaW5nICk7XHJcblx0XHRcdHRvbmVNYXBwaW5nTmFtZSA9ICdMaW5lYXInO1xyXG5cclxuXHR9XHJcblxyXG5cdHJldHVybiAndmVjMyAnICsgZnVuY3Rpb25OYW1lICsgJyggdmVjMyBjb2xvciApIHsgcmV0dXJuICcgKyB0b25lTWFwcGluZ05hbWUgKyAnVG9uZU1hcHBpbmcoIGNvbG9yICk7IH0nO1xyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gZ2VuZXJhdGVFeHRlbnNpb25zKCBwYXJhbWV0ZXJzICkge1xyXG5cclxuXHRjb25zdCBjaHVua3MgPSBbXHJcblx0XHQoIHBhcmFtZXRlcnMuZXh0ZW5zaW9uRGVyaXZhdGl2ZXMgfHwgISEgcGFyYW1ldGVycy5lbnZNYXBDdWJlVVZIZWlnaHQgfHwgcGFyYW1ldGVycy5idW1wTWFwIHx8IHBhcmFtZXRlcnMubm9ybWFsTWFwVGFuZ2VudFNwYWNlIHx8IHBhcmFtZXRlcnMuY2xlYXJjb2F0Tm9ybWFsTWFwIHx8IHBhcmFtZXRlcnMuZmxhdFNoYWRpbmcgfHwgcGFyYW1ldGVycy5hbHBoYVRvQ292ZXJhZ2UgfHwgcGFyYW1ldGVycy5zaGFkZXJJRCA9PT0gJ3BoeXNpY2FsJyApID8gJyNleHRlbnNpb24gR0xfT0VTX3N0YW5kYXJkX2Rlcml2YXRpdmVzIDogZW5hYmxlJyA6ICcnLFxyXG5cdFx0KCBwYXJhbWV0ZXJzLmV4dGVuc2lvbkZyYWdEZXB0aCB8fCBwYXJhbWV0ZXJzLmxvZ2FyaXRobWljRGVwdGhCdWZmZXIgKSAmJiBwYXJhbWV0ZXJzLnJlbmRlcmVyRXh0ZW5zaW9uRnJhZ0RlcHRoID8gJyNleHRlbnNpb24gR0xfRVhUX2ZyYWdfZGVwdGggOiBlbmFibGUnIDogJycsXHJcblx0XHQoIHBhcmFtZXRlcnMuZXh0ZW5zaW9uRHJhd0J1ZmZlcnMgJiYgcGFyYW1ldGVycy5yZW5kZXJlckV4dGVuc2lvbkRyYXdCdWZmZXJzICkgPyAnI2V4dGVuc2lvbiBHTF9FWFRfZHJhd19idWZmZXJzIDogcmVxdWlyZScgOiAnJyxcclxuXHRcdCggcGFyYW1ldGVycy5leHRlbnNpb25TaGFkZXJUZXh0dXJlTE9EIHx8IHBhcmFtZXRlcnMuZW52TWFwIHx8IHBhcmFtZXRlcnMudHJhbnNtaXNzaW9uICkgJiYgcGFyYW1ldGVycy5yZW5kZXJlckV4dGVuc2lvblNoYWRlclRleHR1cmVMb2QgPyAnI2V4dGVuc2lvbiBHTF9FWFRfc2hhZGVyX3RleHR1cmVfbG9kIDogZW5hYmxlJyA6ICcnXHJcblx0XTtcclxuXHJcblx0cmV0dXJuIGNodW5rcy5maWx0ZXIoIGZpbHRlckVtcHR5TGluZSApLmpvaW4oICdcXG4nICk7XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiBnZW5lcmF0ZVZlcnRleEV4dGVuc2lvbnMoIHBhcmFtZXRlcnMgKSB7XHJcblxyXG5cdGNvbnN0IGNodW5rcyA9IFtcclxuXHRcdHBhcmFtZXRlcnMuZXh0ZW5zaW9uQ2xpcEN1bGxEaXN0YW5jZSA/ICcjZXh0ZW5zaW9uIEdMX0FOR0xFX2NsaXBfY3VsbF9kaXN0YW5jZSA6IHJlcXVpcmUnIDogJycsXHJcblx0XHRwYXJhbWV0ZXJzLmV4dGVuc2lvbk11bHRpRHJhdyA/ICcjZXh0ZW5zaW9uIEdMX0FOR0xFX211bHRpX2RyYXcgOiByZXF1aXJlJyA6ICcnLFxyXG5cdF07XHJcblxyXG5cdHJldHVybiBjaHVua3MuZmlsdGVyKCBmaWx0ZXJFbXB0eUxpbmUgKS5qb2luKCAnXFxuJyApO1xyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gZ2VuZXJhdGVEZWZpbmVzKCBkZWZpbmVzICkge1xyXG5cclxuXHRjb25zdCBjaHVua3MgPSBbXTtcclxuXHJcblx0Zm9yICggY29uc3QgbmFtZSBpbiBkZWZpbmVzICkge1xyXG5cclxuXHRcdGNvbnN0IHZhbHVlID0gZGVmaW5lc1sgbmFtZSBdO1xyXG5cclxuXHRcdGlmICggdmFsdWUgPT09IGZhbHNlICkgY29udGludWU7XHJcblxyXG5cdFx0Y2h1bmtzLnB1c2goICcjZGVmaW5lICcgKyBuYW1lICsgJyAnICsgdmFsdWUgKTtcclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4gY2h1bmtzLmpvaW4oICdcXG4nICk7XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiBmZXRjaEF0dHJpYnV0ZUxvY2F0aW9ucyggZ2wsIHByb2dyYW0gKSB7XHJcblxyXG5cdGNvbnN0IGF0dHJpYnV0ZXMgPSB7fTtcclxuXHJcblx0Y29uc3QgbiA9IGdsLmdldFByb2dyYW1QYXJhbWV0ZXIoIHByb2dyYW0sIGdsLkFDVElWRV9BVFRSSUJVVEVTICk7XHJcblxyXG5cdGZvciAoIGxldCBpID0gMDsgaSA8IG47IGkgKysgKSB7XHJcblxyXG5cdFx0Y29uc3QgaW5mbyA9IGdsLmdldEFjdGl2ZUF0dHJpYiggcHJvZ3JhbSwgaSApO1xyXG5cdFx0Y29uc3QgbmFtZSA9IGluZm8ubmFtZTtcclxuXHJcblx0XHRsZXQgbG9jYXRpb25TaXplID0gMTtcclxuXHRcdGlmICggaW5mby50eXBlID09PSBnbC5GTE9BVF9NQVQyICkgbG9jYXRpb25TaXplID0gMjtcclxuXHRcdGlmICggaW5mby50eXBlID09PSBnbC5GTE9BVF9NQVQzICkgbG9jYXRpb25TaXplID0gMztcclxuXHRcdGlmICggaW5mby50eXBlID09PSBnbC5GTE9BVF9NQVQ0ICkgbG9jYXRpb25TaXplID0gNDtcclxuXHJcblx0XHQvLyBjb25zb2xlLmxvZyggJ1RIUkVFLldlYkdMUHJvZ3JhbTogQUNUSVZFIFZFUlRFWCBBVFRSSUJVVEU6JywgbmFtZSwgaSApO1xyXG5cclxuXHRcdGF0dHJpYnV0ZXNbIG5hbWUgXSA9IHtcclxuXHRcdFx0dHlwZTogaW5mby50eXBlLFxyXG5cdFx0XHRsb2NhdGlvbjogZ2wuZ2V0QXR0cmliTG9jYXRpb24oIHByb2dyYW0sIG5hbWUgKSxcclxuXHRcdFx0bG9jYXRpb25TaXplOiBsb2NhdGlvblNpemVcclxuXHRcdH07XHJcblxyXG5cdH1cclxuXHJcblx0cmV0dXJuIGF0dHJpYnV0ZXM7XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiBmaWx0ZXJFbXB0eUxpbmUoIHN0cmluZyApIHtcclxuXHJcblx0cmV0dXJuIHN0cmluZyAhPT0gJyc7XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiByZXBsYWNlTGlnaHROdW1zKCBzdHJpbmcsIHBhcmFtZXRlcnMgKSB7XHJcblxyXG5cdGNvbnN0IG51bVNwb3RMaWdodENvb3JkcyA9IHBhcmFtZXRlcnMubnVtU3BvdExpZ2h0U2hhZG93cyArIHBhcmFtZXRlcnMubnVtU3BvdExpZ2h0TWFwcyAtIHBhcmFtZXRlcnMubnVtU3BvdExpZ2h0U2hhZG93c1dpdGhNYXBzO1xyXG5cclxuXHRyZXR1cm4gc3RyaW5nXHJcblx0XHQucmVwbGFjZSggL05VTV9ESVJfTElHSFRTL2csIHBhcmFtZXRlcnMubnVtRGlyTGlnaHRzIClcclxuXHRcdC5yZXBsYWNlKCAvTlVNX1NQT1RfTElHSFRTL2csIHBhcmFtZXRlcnMubnVtU3BvdExpZ2h0cyApXHJcblx0XHQucmVwbGFjZSggL05VTV9TUE9UX0xJR0hUX01BUFMvZywgcGFyYW1ldGVycy5udW1TcG90TGlnaHRNYXBzIClcclxuXHRcdC5yZXBsYWNlKCAvTlVNX1NQT1RfTElHSFRfQ09PUkRTL2csIG51bVNwb3RMaWdodENvb3JkcyApXHJcblx0XHQucmVwbGFjZSggL05VTV9SRUNUX0FSRUFfTElHSFRTL2csIHBhcmFtZXRlcnMubnVtUmVjdEFyZWFMaWdodHMgKVxyXG5cdFx0LnJlcGxhY2UoIC9OVU1fUE9JTlRfTElHSFRTL2csIHBhcmFtZXRlcnMubnVtUG9pbnRMaWdodHMgKVxyXG5cdFx0LnJlcGxhY2UoIC9OVU1fSEVNSV9MSUdIVFMvZywgcGFyYW1ldGVycy5udW1IZW1pTGlnaHRzIClcclxuXHRcdC5yZXBsYWNlKCAvTlVNX0RJUl9MSUdIVF9TSEFET1dTL2csIHBhcmFtZXRlcnMubnVtRGlyTGlnaHRTaGFkb3dzIClcclxuXHRcdC5yZXBsYWNlKCAvTlVNX1NQT1RfTElHSFRfU0hBRE9XU19XSVRIX01BUFMvZywgcGFyYW1ldGVycy5udW1TcG90TGlnaHRTaGFkb3dzV2l0aE1hcHMgKVxyXG5cdFx0LnJlcGxhY2UoIC9OVU1fU1BPVF9MSUdIVF9TSEFET1dTL2csIHBhcmFtZXRlcnMubnVtU3BvdExpZ2h0U2hhZG93cyApXHJcblx0XHQucmVwbGFjZSggL05VTV9QT0lOVF9MSUdIVF9TSEFET1dTL2csIHBhcmFtZXRlcnMubnVtUG9pbnRMaWdodFNoYWRvd3MgKTtcclxuXHJcbn1cclxuXHJcbmZ1bmN0aW9uIHJlcGxhY2VDbGlwcGluZ1BsYW5lTnVtcyggc3RyaW5nLCBwYXJhbWV0ZXJzICkge1xyXG5cclxuXHRyZXR1cm4gc3RyaW5nXHJcblx0XHQucmVwbGFjZSggL05VTV9DTElQUElOR19QTEFORVMvZywgcGFyYW1ldGVycy5udW1DbGlwcGluZ1BsYW5lcyApXHJcblx0XHQucmVwbGFjZSggL1VOSU9OX0NMSVBQSU5HX1BMQU5FUy9nLCAoIHBhcmFtZXRlcnMubnVtQ2xpcHBpbmdQbGFuZXMgLSBwYXJhbWV0ZXJzLm51bUNsaXBJbnRlcnNlY3Rpb24gKSApO1xyXG5cclxufVxyXG5cclxuLy8gUmVzb2x2ZSBJbmNsdWRlc1xyXG5cclxuY29uc3QgaW5jbHVkZVBhdHRlcm4gPSAvXlsgXFx0XSojaW5jbHVkZSArPChbXFx3XFxkLi9dKyk+L2dtO1xyXG5cclxuZnVuY3Rpb24gcmVzb2x2ZUluY2x1ZGVzKCBzdHJpbmcgKSB7XHJcblxyXG5cdHJldHVybiBzdHJpbmcucmVwbGFjZSggaW5jbHVkZVBhdHRlcm4sIGluY2x1ZGVSZXBsYWNlciApO1xyXG5cclxufVxyXG5cclxuY29uc3Qgc2hhZGVyQ2h1bmtNYXAgPSBuZXcgTWFwKCBbXHJcblx0WyAnZW5jb2RpbmdzX2ZyYWdtZW50JywgJ2NvbG9yc3BhY2VfZnJhZ21lbnQnIF0sIC8vIEBkZXByZWNhdGVkLCByMTU0XHJcblx0WyAnZW5jb2RpbmdzX3BhcnNfZnJhZ21lbnQnLCAnY29sb3JzcGFjZV9wYXJzX2ZyYWdtZW50JyBdLCAvLyBAZGVwcmVjYXRlZCwgcjE1NFxyXG5cdFsgJ291dHB1dF9mcmFnbWVudCcsICdvcGFxdWVfZnJhZ21lbnQnIF0sIC8vIEBkZXByZWNhdGVkLCByMTU0XHJcbl0gKTtcclxuXHJcbmZ1bmN0aW9uIGluY2x1ZGVSZXBsYWNlciggbWF0Y2gsIGluY2x1ZGUgKSB7XHJcblxyXG5cdGxldCBzdHJpbmcgPSBTaGFkZXJDaHVua1sgaW5jbHVkZSBdO1xyXG5cclxuXHRpZiAoIHN0cmluZyA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdGNvbnN0IG5ld0luY2x1ZGUgPSBzaGFkZXJDaHVua01hcC5nZXQoIGluY2x1ZGUgKTtcclxuXHJcblx0XHRpZiAoIG5ld0luY2x1ZGUgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdHN0cmluZyA9IFNoYWRlckNodW5rWyBuZXdJbmNsdWRlIF07XHJcblx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLldlYkdMUmVuZGVyZXI6IFNoYWRlciBjaHVuayBcIiVzXCIgaGFzIGJlZW4gZGVwcmVjYXRlZC4gVXNlIFwiJXNcIiBpbnN0ZWFkLicsIGluY2x1ZGUsIG5ld0luY2x1ZGUgKTtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0dGhyb3cgbmV3IEVycm9yKCAnQ2FuIG5vdCByZXNvbHZlICNpbmNsdWRlIDwnICsgaW5jbHVkZSArICc+JyApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4gcmVzb2x2ZUluY2x1ZGVzKCBzdHJpbmcgKTtcclxuXHJcbn1cclxuXHJcbi8vIFVucm9sbCBMb29wc1xyXG5cclxuY29uc3QgdW5yb2xsTG9vcFBhdHRlcm4gPSAvI3ByYWdtYSB1bnJvbGxfbG9vcF9zdGFydFxccytmb3JcXHMqXFwoXFxzKmludFxccytpXFxzKj1cXHMqKFxcZCspXFxzKjtcXHMqaVxccyo8XFxzKihcXGQrKVxccyo7XFxzKmlcXHMqXFwrXFwrXFxzKlxcKVxccyp7KFtcXHNcXFNdKz8pfVxccysjcHJhZ21hIHVucm9sbF9sb29wX2VuZC9nO1xyXG5cclxuZnVuY3Rpb24gdW5yb2xsTG9vcHMoIHN0cmluZyApIHtcclxuXHJcblx0cmV0dXJuIHN0cmluZy5yZXBsYWNlKCB1bnJvbGxMb29wUGF0dGVybiwgbG9vcFJlcGxhY2VyICk7XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiBsb29wUmVwbGFjZXIoIG1hdGNoLCBzdGFydCwgZW5kLCBzbmlwcGV0ICkge1xyXG5cclxuXHRsZXQgc3RyaW5nID0gJyc7XHJcblxyXG5cdGZvciAoIGxldCBpID0gcGFyc2VJbnQoIHN0YXJ0ICk7IGkgPCBwYXJzZUludCggZW5kICk7IGkgKysgKSB7XHJcblxyXG5cdFx0c3RyaW5nICs9IHNuaXBwZXRcclxuXHRcdFx0LnJlcGxhY2UoIC9cXFtcXHMqaVxccypcXF0vZywgJ1sgJyArIGkgKyAnIF0nIClcclxuXHRcdFx0LnJlcGxhY2UoIC9VTlJPTExFRF9MT09QX0lOREVYL2csIGkgKTtcclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4gc3RyaW5nO1xyXG5cclxufVxyXG5cclxuLy9cclxuXHJcbmZ1bmN0aW9uIGdlbmVyYXRlUHJlY2lzaW9uKCBwYXJhbWV0ZXJzICkge1xyXG5cclxuXHRsZXQgcHJlY2lzaW9uc3RyaW5nID0gYHByZWNpc2lvbiAke3BhcmFtZXRlcnMucHJlY2lzaW9ufSBmbG9hdDtcclxuXHRwcmVjaXNpb24gJHtwYXJhbWV0ZXJzLnByZWNpc2lvbn0gaW50O1xyXG5cdHByZWNpc2lvbiAke3BhcmFtZXRlcnMucHJlY2lzaW9ufSBzYW1wbGVyMkQ7XHJcblx0cHJlY2lzaW9uICR7cGFyYW1ldGVycy5wcmVjaXNpb259IHNhbXBsZXJDdWJlO1xyXG5cdGA7XHJcblxyXG5cdGlmICggcGFyYW1ldGVycy5pc1dlYkdMMiApIHtcclxuXHJcblx0XHRwcmVjaXNpb25zdHJpbmcgKz0gYHByZWNpc2lvbiAke3BhcmFtZXRlcnMucHJlY2lzaW9ufSBzYW1wbGVyM0Q7XHJcblx0XHRwcmVjaXNpb24gJHtwYXJhbWV0ZXJzLnByZWNpc2lvbn0gc2FtcGxlcjJEQXJyYXk7XHJcblx0XHRwcmVjaXNpb24gJHtwYXJhbWV0ZXJzLnByZWNpc2lvbn0gc2FtcGxlcjJEU2hhZG93O1xyXG5cdFx0cHJlY2lzaW9uICR7cGFyYW1ldGVycy5wcmVjaXNpb259IHNhbXBsZXJDdWJlU2hhZG93O1xyXG5cdFx0cHJlY2lzaW9uICR7cGFyYW1ldGVycy5wcmVjaXNpb259IHNhbXBsZXIyREFycmF5U2hhZG93O1xyXG5cdFx0cHJlY2lzaW9uICR7cGFyYW1ldGVycy5wcmVjaXNpb259IGlzYW1wbGVyMkQ7XHJcblx0XHRwcmVjaXNpb24gJHtwYXJhbWV0ZXJzLnByZWNpc2lvbn0gaXNhbXBsZXIzRDtcclxuXHRcdHByZWNpc2lvbiAke3BhcmFtZXRlcnMucHJlY2lzaW9ufSBpc2FtcGxlckN1YmU7XHJcblx0XHRwcmVjaXNpb24gJHtwYXJhbWV0ZXJzLnByZWNpc2lvbn0gaXNhbXBsZXIyREFycmF5O1xyXG5cdFx0cHJlY2lzaW9uICR7cGFyYW1ldGVycy5wcmVjaXNpb259IHVzYW1wbGVyMkQ7XHJcblx0XHRwcmVjaXNpb24gJHtwYXJhbWV0ZXJzLnByZWNpc2lvbn0gdXNhbXBsZXIzRDtcclxuXHRcdHByZWNpc2lvbiAke3BhcmFtZXRlcnMucHJlY2lzaW9ufSB1c2FtcGxlckN1YmU7XHJcblx0XHRwcmVjaXNpb24gJHtwYXJhbWV0ZXJzLnByZWNpc2lvbn0gdXNhbXBsZXIyREFycmF5O1xyXG5cdFx0YDtcclxuXHJcblx0fVxyXG5cclxuXHRpZiAoIHBhcmFtZXRlcnMucHJlY2lzaW9uID09PSAnaGlnaHAnICkge1xyXG5cclxuXHRcdHByZWNpc2lvbnN0cmluZyArPSAnXFxuI2RlZmluZSBISUdIX1BSRUNJU0lPTic7XHJcblxyXG5cdH0gZWxzZSBpZiAoIHBhcmFtZXRlcnMucHJlY2lzaW9uID09PSAnbWVkaXVtcCcgKSB7XHJcblxyXG5cdFx0cHJlY2lzaW9uc3RyaW5nICs9ICdcXG4jZGVmaW5lIE1FRElVTV9QUkVDSVNJT04nO1xyXG5cclxuXHR9IGVsc2UgaWYgKCBwYXJhbWV0ZXJzLnByZWNpc2lvbiA9PT0gJ2xvd3AnICkge1xyXG5cclxuXHRcdHByZWNpc2lvbnN0cmluZyArPSAnXFxuI2RlZmluZSBMT1dfUFJFQ0lTSU9OJztcclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4gcHJlY2lzaW9uc3RyaW5nO1xyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gZ2VuZXJhdGVTaGFkb3dNYXBUeXBlRGVmaW5lKCBwYXJhbWV0ZXJzICkge1xyXG5cclxuXHRsZXQgc2hhZG93TWFwVHlwZURlZmluZSA9ICdTSEFET1dNQVBfVFlQRV9CQVNJQyc7XHJcblxyXG5cdGlmICggcGFyYW1ldGVycy5zaGFkb3dNYXBUeXBlID09PSBQQ0ZTaGFkb3dNYXAgKSB7XHJcblxyXG5cdFx0c2hhZG93TWFwVHlwZURlZmluZSA9ICdTSEFET1dNQVBfVFlQRV9QQ0YnO1xyXG5cclxuXHR9IGVsc2UgaWYgKCBwYXJhbWV0ZXJzLnNoYWRvd01hcFR5cGUgPT09IFBDRlNvZnRTaGFkb3dNYXAgKSB7XHJcblxyXG5cdFx0c2hhZG93TWFwVHlwZURlZmluZSA9ICdTSEFET1dNQVBfVFlQRV9QQ0ZfU09GVCc7XHJcblxyXG5cdH0gZWxzZSBpZiAoIHBhcmFtZXRlcnMuc2hhZG93TWFwVHlwZSA9PT0gVlNNU2hhZG93TWFwICkge1xyXG5cclxuXHRcdHNoYWRvd01hcFR5cGVEZWZpbmUgPSAnU0hBRE9XTUFQX1RZUEVfVlNNJztcclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4gc2hhZG93TWFwVHlwZURlZmluZTtcclxuXHJcbn1cclxuXHJcbmZ1bmN0aW9uIGdlbmVyYXRlRW52TWFwVHlwZURlZmluZSggcGFyYW1ldGVycyApIHtcclxuXHJcblx0bGV0IGVudk1hcFR5cGVEZWZpbmUgPSAnRU5WTUFQX1RZUEVfQ1VCRSc7XHJcblxyXG5cdGlmICggcGFyYW1ldGVycy5lbnZNYXAgKSB7XHJcblxyXG5cdFx0c3dpdGNoICggcGFyYW1ldGVycy5lbnZNYXBNb2RlICkge1xyXG5cclxuXHRcdFx0Y2FzZSBDdWJlUmVmbGVjdGlvbk1hcHBpbmc6XHJcblx0XHRcdGNhc2UgQ3ViZVJlZnJhY3Rpb25NYXBwaW5nOlxyXG5cdFx0XHRcdGVudk1hcFR5cGVEZWZpbmUgPSAnRU5WTUFQX1RZUEVfQ1VCRSc7XHJcblx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRjYXNlIEN1YmVVVlJlZmxlY3Rpb25NYXBwaW5nOlxyXG5cdFx0XHRcdGVudk1hcFR5cGVEZWZpbmUgPSAnRU5WTUFQX1RZUEVfQ1VCRV9VVic7XHJcblx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdHJldHVybiBlbnZNYXBUeXBlRGVmaW5lO1xyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gZ2VuZXJhdGVFbnZNYXBNb2RlRGVmaW5lKCBwYXJhbWV0ZXJzICkge1xyXG5cclxuXHRsZXQgZW52TWFwTW9kZURlZmluZSA9ICdFTlZNQVBfTU9ERV9SRUZMRUNUSU9OJztcclxuXHJcblx0aWYgKCBwYXJhbWV0ZXJzLmVudk1hcCApIHtcclxuXHJcblx0XHRzd2l0Y2ggKCBwYXJhbWV0ZXJzLmVudk1hcE1vZGUgKSB7XHJcblxyXG5cdFx0XHRjYXNlIEN1YmVSZWZyYWN0aW9uTWFwcGluZzpcclxuXHJcblx0XHRcdFx0ZW52TWFwTW9kZURlZmluZSA9ICdFTlZNQVBfTU9ERV9SRUZSQUNUSU9OJztcclxuXHRcdFx0XHRicmVhaztcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0cmV0dXJuIGVudk1hcE1vZGVEZWZpbmU7XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiBnZW5lcmF0ZUVudk1hcEJsZW5kaW5nRGVmaW5lKCBwYXJhbWV0ZXJzICkge1xyXG5cclxuXHRsZXQgZW52TWFwQmxlbmRpbmdEZWZpbmUgPSAnRU5WTUFQX0JMRU5ESU5HX05PTkUnO1xyXG5cclxuXHRpZiAoIHBhcmFtZXRlcnMuZW52TWFwICkge1xyXG5cclxuXHRcdHN3aXRjaCAoIHBhcmFtZXRlcnMuY29tYmluZSApIHtcclxuXHJcblx0XHRcdGNhc2UgTXVsdGlwbHlPcGVyYXRpb246XHJcblx0XHRcdFx0ZW52TWFwQmxlbmRpbmdEZWZpbmUgPSAnRU5WTUFQX0JMRU5ESU5HX01VTFRJUExZJztcclxuXHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdGNhc2UgTWl4T3BlcmF0aW9uOlxyXG5cdFx0XHRcdGVudk1hcEJsZW5kaW5nRGVmaW5lID0gJ0VOVk1BUF9CTEVORElOR19NSVgnO1xyXG5cdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0Y2FzZSBBZGRPcGVyYXRpb246XHJcblx0XHRcdFx0ZW52TWFwQmxlbmRpbmdEZWZpbmUgPSAnRU5WTUFQX0JMRU5ESU5HX0FERCc7XHJcblx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdHJldHVybiBlbnZNYXBCbGVuZGluZ0RlZmluZTtcclxuXHJcbn1cclxuXHJcbmZ1bmN0aW9uIGdlbmVyYXRlQ3ViZVVWU2l6ZSggcGFyYW1ldGVycyApIHtcclxuXHJcblx0Y29uc3QgaW1hZ2VIZWlnaHQgPSBwYXJhbWV0ZXJzLmVudk1hcEN1YmVVVkhlaWdodDtcclxuXHJcblx0aWYgKCBpbWFnZUhlaWdodCA9PT0gbnVsbCApIHJldHVybiBudWxsO1xyXG5cclxuXHRjb25zdCBtYXhNaXAgPSBNYXRoLmxvZzIoIGltYWdlSGVpZ2h0ICkgLSAyO1xyXG5cclxuXHRjb25zdCB0ZXhlbEhlaWdodCA9IDEuMCAvIGltYWdlSGVpZ2h0O1xyXG5cclxuXHRjb25zdCB0ZXhlbFdpZHRoID0gMS4wIC8gKCAzICogTWF0aC5tYXgoIE1hdGgucG93KCAyLCBtYXhNaXAgKSwgNyAqIDE2ICkgKTtcclxuXHJcblx0cmV0dXJuIHsgdGV4ZWxXaWR0aCwgdGV4ZWxIZWlnaHQsIG1heE1pcCB9O1xyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gV2ViR0xQcm9ncmFtKCByZW5kZXJlciwgY2FjaGVLZXksIHBhcmFtZXRlcnMsIGJpbmRpbmdTdGF0ZXMgKSB7XHJcblxyXG5cdC8vIFRPRE8gU2VuZCB0aGlzIGV2ZW50IHRvIFRocmVlLmpzIERldlRvb2xzXHJcblx0Ly8gY29uc29sZS5sb2coICdXZWJHTFByb2dyYW0nLCBjYWNoZUtleSApO1xyXG5cclxuXHRjb25zdCBnbCA9IHJlbmRlcmVyLmdldENvbnRleHQoKTtcclxuXHJcblx0Y29uc3QgZGVmaW5lcyA9IHBhcmFtZXRlcnMuZGVmaW5lcztcclxuXHJcblx0bGV0IHZlcnRleFNoYWRlciA9IHBhcmFtZXRlcnMudmVydGV4U2hhZGVyO1xyXG5cdGxldCBmcmFnbWVudFNoYWRlciA9IHBhcmFtZXRlcnMuZnJhZ21lbnRTaGFkZXI7XHJcblxyXG5cdGNvbnN0IHNoYWRvd01hcFR5cGVEZWZpbmUgPSBnZW5lcmF0ZVNoYWRvd01hcFR5cGVEZWZpbmUoIHBhcmFtZXRlcnMgKTtcclxuXHRjb25zdCBlbnZNYXBUeXBlRGVmaW5lID0gZ2VuZXJhdGVFbnZNYXBUeXBlRGVmaW5lKCBwYXJhbWV0ZXJzICk7XHJcblx0Y29uc3QgZW52TWFwTW9kZURlZmluZSA9IGdlbmVyYXRlRW52TWFwTW9kZURlZmluZSggcGFyYW1ldGVycyApO1xyXG5cdGNvbnN0IGVudk1hcEJsZW5kaW5nRGVmaW5lID0gZ2VuZXJhdGVFbnZNYXBCbGVuZGluZ0RlZmluZSggcGFyYW1ldGVycyApO1xyXG5cdGNvbnN0IGVudk1hcEN1YmVVVlNpemUgPSBnZW5lcmF0ZUN1YmVVVlNpemUoIHBhcmFtZXRlcnMgKTtcclxuXHJcblx0Y29uc3QgY3VzdG9tRXh0ZW5zaW9ucyA9IHBhcmFtZXRlcnMuaXNXZWJHTDIgPyAnJyA6IGdlbmVyYXRlRXh0ZW5zaW9ucyggcGFyYW1ldGVycyApO1xyXG5cclxuXHRjb25zdCBjdXN0b21WZXJ0ZXhFeHRlbnNpb25zID0gZ2VuZXJhdGVWZXJ0ZXhFeHRlbnNpb25zKCBwYXJhbWV0ZXJzICk7XHJcblxyXG5cdGNvbnN0IGN1c3RvbURlZmluZXMgPSBnZW5lcmF0ZURlZmluZXMoIGRlZmluZXMgKTtcclxuXHJcblx0Y29uc3QgcHJvZ3JhbSA9IGdsLmNyZWF0ZVByb2dyYW0oKTtcclxuXHJcblx0bGV0IHByZWZpeFZlcnRleCwgcHJlZml4RnJhZ21lbnQ7XHJcblx0bGV0IHZlcnNpb25TdHJpbmcgPSBwYXJhbWV0ZXJzLmdsc2xWZXJzaW9uID8gJyN2ZXJzaW9uICcgKyBwYXJhbWV0ZXJzLmdsc2xWZXJzaW9uICsgJ1xcbicgOiAnJztcclxuXHJcblx0aWYgKCBwYXJhbWV0ZXJzLmlzUmF3U2hhZGVyTWF0ZXJpYWwgKSB7XHJcblxyXG5cdFx0cHJlZml4VmVydGV4ID0gW1xyXG5cclxuXHRcdFx0JyNkZWZpbmUgU0hBREVSX1RZUEUgJyArIHBhcmFtZXRlcnMuc2hhZGVyVHlwZSxcclxuXHRcdFx0JyNkZWZpbmUgU0hBREVSX05BTUUgJyArIHBhcmFtZXRlcnMuc2hhZGVyTmFtZSxcclxuXHJcblx0XHRcdGN1c3RvbURlZmluZXNcclxuXHJcblx0XHRdLmZpbHRlciggZmlsdGVyRW1wdHlMaW5lICkuam9pbiggJ1xcbicgKTtcclxuXHJcblx0XHRpZiAoIHByZWZpeFZlcnRleC5sZW5ndGggPiAwICkge1xyXG5cclxuXHRcdFx0cHJlZml4VmVydGV4ICs9ICdcXG4nO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRwcmVmaXhGcmFnbWVudCA9IFtcclxuXHJcblx0XHRcdGN1c3RvbUV4dGVuc2lvbnMsXHJcblxyXG5cdFx0XHQnI2RlZmluZSBTSEFERVJfVFlQRSAnICsgcGFyYW1ldGVycy5zaGFkZXJUeXBlLFxyXG5cdFx0XHQnI2RlZmluZSBTSEFERVJfTkFNRSAnICsgcGFyYW1ldGVycy5zaGFkZXJOYW1lLFxyXG5cclxuXHRcdFx0Y3VzdG9tRGVmaW5lc1xyXG5cclxuXHRcdF0uZmlsdGVyKCBmaWx0ZXJFbXB0eUxpbmUgKS5qb2luKCAnXFxuJyApO1xyXG5cclxuXHRcdGlmICggcHJlZml4RnJhZ21lbnQubGVuZ3RoID4gMCApIHtcclxuXHJcblx0XHRcdHByZWZpeEZyYWdtZW50ICs9ICdcXG4nO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fSBlbHNlIHtcclxuXHJcblx0XHRwcmVmaXhWZXJ0ZXggPSBbXHJcblxyXG5cdFx0XHRnZW5lcmF0ZVByZWNpc2lvbiggcGFyYW1ldGVycyApLFxyXG5cclxuXHRcdFx0JyNkZWZpbmUgU0hBREVSX1RZUEUgJyArIHBhcmFtZXRlcnMuc2hhZGVyVHlwZSxcclxuXHRcdFx0JyNkZWZpbmUgU0hBREVSX05BTUUgJyArIHBhcmFtZXRlcnMuc2hhZGVyTmFtZSxcclxuXHJcblx0XHRcdGN1c3RvbURlZmluZXMsXHJcblxyXG5cdFx0XHRwYXJhbWV0ZXJzLmV4dGVuc2lvbkNsaXBDdWxsRGlzdGFuY2UgPyAnI2RlZmluZSBVU0VfQ0xJUF9ESVNUQU5DRScgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy5iYXRjaGluZyA/ICcjZGVmaW5lIFVTRV9CQVRDSElORycgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy5pbnN0YW5jaW5nID8gJyNkZWZpbmUgVVNFX0lOU1RBTkNJTkcnIDogJycsXHJcblx0XHRcdHBhcmFtZXRlcnMuaW5zdGFuY2luZ0NvbG9yID8gJyNkZWZpbmUgVVNFX0lOU1RBTkNJTkdfQ09MT1InIDogJycsXHJcblxyXG5cdFx0XHRwYXJhbWV0ZXJzLnVzZUZvZyAmJiBwYXJhbWV0ZXJzLmZvZyA/ICcjZGVmaW5lIFVTRV9GT0cnIDogJycsXHJcblx0XHRcdHBhcmFtZXRlcnMudXNlRm9nICYmIHBhcmFtZXRlcnMuZm9nRXhwMiA/ICcjZGVmaW5lIEZPR19FWFAyJyA6ICcnLFxyXG5cclxuXHRcdFx0cGFyYW1ldGVycy5tYXAgPyAnI2RlZmluZSBVU0VfTUFQJyA6ICcnLFxyXG5cdFx0XHRwYXJhbWV0ZXJzLmVudk1hcCA/ICcjZGVmaW5lIFVTRV9FTlZNQVAnIDogJycsXHJcblx0XHRcdHBhcmFtZXRlcnMuZW52TWFwID8gJyNkZWZpbmUgJyArIGVudk1hcE1vZGVEZWZpbmUgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy5saWdodE1hcCA/ICcjZGVmaW5lIFVTRV9MSUdIVE1BUCcgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy5hb01hcCA/ICcjZGVmaW5lIFVTRV9BT01BUCcgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy5idW1wTWFwID8gJyNkZWZpbmUgVVNFX0JVTVBNQVAnIDogJycsXHJcblx0XHRcdHBhcmFtZXRlcnMubm9ybWFsTWFwID8gJyNkZWZpbmUgVVNFX05PUk1BTE1BUCcgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy5ub3JtYWxNYXBPYmplY3RTcGFjZSA/ICcjZGVmaW5lIFVTRV9OT1JNQUxNQVBfT0JKRUNUU1BBQ0UnIDogJycsXHJcblx0XHRcdHBhcmFtZXRlcnMubm9ybWFsTWFwVGFuZ2VudFNwYWNlID8gJyNkZWZpbmUgVVNFX05PUk1BTE1BUF9UQU5HRU5UU1BBQ0UnIDogJycsXHJcblx0XHRcdHBhcmFtZXRlcnMuZGlzcGxhY2VtZW50TWFwID8gJyNkZWZpbmUgVVNFX0RJU1BMQUNFTUVOVE1BUCcgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy5lbWlzc2l2ZU1hcCA/ICcjZGVmaW5lIFVTRV9FTUlTU0lWRU1BUCcgOiAnJyxcclxuXHJcblx0XHRcdHBhcmFtZXRlcnMuYW5pc290cm9weSA/ICcjZGVmaW5lIFVTRV9BTklTT1RST1BZJyA6ICcnLFxyXG5cdFx0XHRwYXJhbWV0ZXJzLmFuaXNvdHJvcHlNYXAgPyAnI2RlZmluZSBVU0VfQU5JU09UUk9QWU1BUCcgOiAnJyxcclxuXHJcblx0XHRcdHBhcmFtZXRlcnMuY2xlYXJjb2F0TWFwID8gJyNkZWZpbmUgVVNFX0NMRUFSQ09BVE1BUCcgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy5jbGVhcmNvYXRSb3VnaG5lc3NNYXAgPyAnI2RlZmluZSBVU0VfQ0xFQVJDT0FUX1JPVUdITkVTU01BUCcgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy5jbGVhcmNvYXROb3JtYWxNYXAgPyAnI2RlZmluZSBVU0VfQ0xFQVJDT0FUX05PUk1BTE1BUCcgOiAnJyxcclxuXHJcblx0XHRcdHBhcmFtZXRlcnMuaXJpZGVzY2VuY2VNYXAgPyAnI2RlZmluZSBVU0VfSVJJREVTQ0VOQ0VNQVAnIDogJycsXHJcblx0XHRcdHBhcmFtZXRlcnMuaXJpZGVzY2VuY2VUaGlja25lc3NNYXAgPyAnI2RlZmluZSBVU0VfSVJJREVTQ0VOQ0VfVEhJQ0tORVNTTUFQJyA6ICcnLFxyXG5cclxuXHRcdFx0cGFyYW1ldGVycy5zcGVjdWxhck1hcCA/ICcjZGVmaW5lIFVTRV9TUEVDVUxBUk1BUCcgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy5zcGVjdWxhckNvbG9yTWFwID8gJyNkZWZpbmUgVVNFX1NQRUNVTEFSX0NPTE9STUFQJyA6ICcnLFxyXG5cdFx0XHRwYXJhbWV0ZXJzLnNwZWN1bGFySW50ZW5zaXR5TWFwID8gJyNkZWZpbmUgVVNFX1NQRUNVTEFSX0lOVEVOU0lUWU1BUCcgOiAnJyxcclxuXHJcblx0XHRcdHBhcmFtZXRlcnMucm91Z2huZXNzTWFwID8gJyNkZWZpbmUgVVNFX1JPVUdITkVTU01BUCcgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy5tZXRhbG5lc3NNYXAgPyAnI2RlZmluZSBVU0VfTUVUQUxORVNTTUFQJyA6ICcnLFxyXG5cdFx0XHRwYXJhbWV0ZXJzLmFscGhhTWFwID8gJyNkZWZpbmUgVVNFX0FMUEhBTUFQJyA6ICcnLFxyXG5cdFx0XHRwYXJhbWV0ZXJzLmFscGhhSGFzaCA/ICcjZGVmaW5lIFVTRV9BTFBIQUhBU0gnIDogJycsXHJcblxyXG5cdFx0XHRwYXJhbWV0ZXJzLnRyYW5zbWlzc2lvbiA/ICcjZGVmaW5lIFVTRV9UUkFOU01JU1NJT04nIDogJycsXHJcblx0XHRcdHBhcmFtZXRlcnMudHJhbnNtaXNzaW9uTWFwID8gJyNkZWZpbmUgVVNFX1RSQU5TTUlTU0lPTk1BUCcgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy50aGlja25lc3NNYXAgPyAnI2RlZmluZSBVU0VfVEhJQ0tORVNTTUFQJyA6ICcnLFxyXG5cclxuXHRcdFx0cGFyYW1ldGVycy5zaGVlbkNvbG9yTWFwID8gJyNkZWZpbmUgVVNFX1NIRUVOX0NPTE9STUFQJyA6ICcnLFxyXG5cdFx0XHRwYXJhbWV0ZXJzLnNoZWVuUm91Z2huZXNzTWFwID8gJyNkZWZpbmUgVVNFX1NIRUVOX1JPVUdITkVTU01BUCcgOiAnJyxcclxuXHJcblx0XHRcdC8vXHJcblxyXG5cdFx0XHRwYXJhbWV0ZXJzLm1hcFV2ID8gJyNkZWZpbmUgTUFQX1VWICcgKyBwYXJhbWV0ZXJzLm1hcFV2IDogJycsXHJcblx0XHRcdHBhcmFtZXRlcnMuYWxwaGFNYXBVdiA/ICcjZGVmaW5lIEFMUEhBTUFQX1VWICcgKyBwYXJhbWV0ZXJzLmFscGhhTWFwVXYgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy5saWdodE1hcFV2ID8gJyNkZWZpbmUgTElHSFRNQVBfVVYgJyArIHBhcmFtZXRlcnMubGlnaHRNYXBVdiA6ICcnLFxyXG5cdFx0XHRwYXJhbWV0ZXJzLmFvTWFwVXYgPyAnI2RlZmluZSBBT01BUF9VViAnICsgcGFyYW1ldGVycy5hb01hcFV2IDogJycsXHJcblx0XHRcdHBhcmFtZXRlcnMuZW1pc3NpdmVNYXBVdiA/ICcjZGVmaW5lIEVNSVNTSVZFTUFQX1VWICcgKyBwYXJhbWV0ZXJzLmVtaXNzaXZlTWFwVXYgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy5idW1wTWFwVXYgPyAnI2RlZmluZSBCVU1QTUFQX1VWICcgKyBwYXJhbWV0ZXJzLmJ1bXBNYXBVdiA6ICcnLFxyXG5cdFx0XHRwYXJhbWV0ZXJzLm5vcm1hbE1hcFV2ID8gJyNkZWZpbmUgTk9STUFMTUFQX1VWICcgKyBwYXJhbWV0ZXJzLm5vcm1hbE1hcFV2IDogJycsXHJcblx0XHRcdHBhcmFtZXRlcnMuZGlzcGxhY2VtZW50TWFwVXYgPyAnI2RlZmluZSBESVNQTEFDRU1FTlRNQVBfVVYgJyArIHBhcmFtZXRlcnMuZGlzcGxhY2VtZW50TWFwVXYgOiAnJyxcclxuXHJcblx0XHRcdHBhcmFtZXRlcnMubWV0YWxuZXNzTWFwVXYgPyAnI2RlZmluZSBNRVRBTE5FU1NNQVBfVVYgJyArIHBhcmFtZXRlcnMubWV0YWxuZXNzTWFwVXYgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy5yb3VnaG5lc3NNYXBVdiA/ICcjZGVmaW5lIFJPVUdITkVTU01BUF9VViAnICsgcGFyYW1ldGVycy5yb3VnaG5lc3NNYXBVdiA6ICcnLFxyXG5cclxuXHRcdFx0cGFyYW1ldGVycy5hbmlzb3Ryb3B5TWFwVXYgPyAnI2RlZmluZSBBTklTT1RST1BZTUFQX1VWICcgKyBwYXJhbWV0ZXJzLmFuaXNvdHJvcHlNYXBVdiA6ICcnLFxyXG5cclxuXHRcdFx0cGFyYW1ldGVycy5jbGVhcmNvYXRNYXBVdiA/ICcjZGVmaW5lIENMRUFSQ09BVE1BUF9VViAnICsgcGFyYW1ldGVycy5jbGVhcmNvYXRNYXBVdiA6ICcnLFxyXG5cdFx0XHRwYXJhbWV0ZXJzLmNsZWFyY29hdE5vcm1hbE1hcFV2ID8gJyNkZWZpbmUgQ0xFQVJDT0FUX05PUk1BTE1BUF9VViAnICsgcGFyYW1ldGVycy5jbGVhcmNvYXROb3JtYWxNYXBVdiA6ICcnLFxyXG5cdFx0XHRwYXJhbWV0ZXJzLmNsZWFyY29hdFJvdWdobmVzc01hcFV2ID8gJyNkZWZpbmUgQ0xFQVJDT0FUX1JPVUdITkVTU01BUF9VViAnICsgcGFyYW1ldGVycy5jbGVhcmNvYXRSb3VnaG5lc3NNYXBVdiA6ICcnLFxyXG5cclxuXHRcdFx0cGFyYW1ldGVycy5pcmlkZXNjZW5jZU1hcFV2ID8gJyNkZWZpbmUgSVJJREVTQ0VOQ0VNQVBfVVYgJyArIHBhcmFtZXRlcnMuaXJpZGVzY2VuY2VNYXBVdiA6ICcnLFxyXG5cdFx0XHRwYXJhbWV0ZXJzLmlyaWRlc2NlbmNlVGhpY2tuZXNzTWFwVXYgPyAnI2RlZmluZSBJUklERVNDRU5DRV9USElDS05FU1NNQVBfVVYgJyArIHBhcmFtZXRlcnMuaXJpZGVzY2VuY2VUaGlja25lc3NNYXBVdiA6ICcnLFxyXG5cclxuXHRcdFx0cGFyYW1ldGVycy5zaGVlbkNvbG9yTWFwVXYgPyAnI2RlZmluZSBTSEVFTl9DT0xPUk1BUF9VViAnICsgcGFyYW1ldGVycy5zaGVlbkNvbG9yTWFwVXYgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy5zaGVlblJvdWdobmVzc01hcFV2ID8gJyNkZWZpbmUgU0hFRU5fUk9VR0hORVNTTUFQX1VWICcgKyBwYXJhbWV0ZXJzLnNoZWVuUm91Z2huZXNzTWFwVXYgOiAnJyxcclxuXHJcblx0XHRcdHBhcmFtZXRlcnMuc3BlY3VsYXJNYXBVdiA/ICcjZGVmaW5lIFNQRUNVTEFSTUFQX1VWICcgKyBwYXJhbWV0ZXJzLnNwZWN1bGFyTWFwVXYgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy5zcGVjdWxhckNvbG9yTWFwVXYgPyAnI2RlZmluZSBTUEVDVUxBUl9DT0xPUk1BUF9VViAnICsgcGFyYW1ldGVycy5zcGVjdWxhckNvbG9yTWFwVXYgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy5zcGVjdWxhckludGVuc2l0eU1hcFV2ID8gJyNkZWZpbmUgU1BFQ1VMQVJfSU5URU5TSVRZTUFQX1VWICcgKyBwYXJhbWV0ZXJzLnNwZWN1bGFySW50ZW5zaXR5TWFwVXYgOiAnJyxcclxuXHJcblx0XHRcdHBhcmFtZXRlcnMudHJhbnNtaXNzaW9uTWFwVXYgPyAnI2RlZmluZSBUUkFOU01JU1NJT05NQVBfVVYgJyArIHBhcmFtZXRlcnMudHJhbnNtaXNzaW9uTWFwVXYgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy50aGlja25lc3NNYXBVdiA/ICcjZGVmaW5lIFRISUNLTkVTU01BUF9VViAnICsgcGFyYW1ldGVycy50aGlja25lc3NNYXBVdiA6ICcnLFxyXG5cclxuXHRcdFx0Ly9cclxuXHJcblx0XHRcdHBhcmFtZXRlcnMudmVydGV4VGFuZ2VudHMgJiYgcGFyYW1ldGVycy5mbGF0U2hhZGluZyA9PT0gZmFsc2UgPyAnI2RlZmluZSBVU0VfVEFOR0VOVCcgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy52ZXJ0ZXhDb2xvcnMgPyAnI2RlZmluZSBVU0VfQ09MT1InIDogJycsXHJcblx0XHRcdHBhcmFtZXRlcnMudmVydGV4QWxwaGFzID8gJyNkZWZpbmUgVVNFX0NPTE9SX0FMUEhBJyA6ICcnLFxyXG5cdFx0XHRwYXJhbWV0ZXJzLnZlcnRleFV2MXMgPyAnI2RlZmluZSBVU0VfVVYxJyA6ICcnLFxyXG5cdFx0XHRwYXJhbWV0ZXJzLnZlcnRleFV2MnMgPyAnI2RlZmluZSBVU0VfVVYyJyA6ICcnLFxyXG5cdFx0XHRwYXJhbWV0ZXJzLnZlcnRleFV2M3MgPyAnI2RlZmluZSBVU0VfVVYzJyA6ICcnLFxyXG5cclxuXHRcdFx0cGFyYW1ldGVycy5wb2ludHNVdnMgPyAnI2RlZmluZSBVU0VfUE9JTlRTX1VWJyA6ICcnLFxyXG5cclxuXHRcdFx0cGFyYW1ldGVycy5mbGF0U2hhZGluZyA/ICcjZGVmaW5lIEZMQVRfU0hBREVEJyA6ICcnLFxyXG5cclxuXHRcdFx0cGFyYW1ldGVycy5za2lubmluZyA/ICcjZGVmaW5lIFVTRV9TS0lOTklORycgOiAnJyxcclxuXHJcblx0XHRcdHBhcmFtZXRlcnMubW9ycGhUYXJnZXRzID8gJyNkZWZpbmUgVVNFX01PUlBIVEFSR0VUUycgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy5tb3JwaE5vcm1hbHMgJiYgcGFyYW1ldGVycy5mbGF0U2hhZGluZyA9PT0gZmFsc2UgPyAnI2RlZmluZSBVU0VfTU9SUEhOT1JNQUxTJyA6ICcnLFxyXG5cdFx0XHQoIHBhcmFtZXRlcnMubW9ycGhDb2xvcnMgJiYgcGFyYW1ldGVycy5pc1dlYkdMMiApID8gJyNkZWZpbmUgVVNFX01PUlBIQ09MT1JTJyA6ICcnLFxyXG5cdFx0XHQoIHBhcmFtZXRlcnMubW9ycGhUYXJnZXRzQ291bnQgPiAwICYmIHBhcmFtZXRlcnMuaXNXZWJHTDIgKSA/ICcjZGVmaW5lIE1PUlBIVEFSR0VUU19URVhUVVJFJyA6ICcnLFxyXG5cdFx0XHQoIHBhcmFtZXRlcnMubW9ycGhUYXJnZXRzQ291bnQgPiAwICYmIHBhcmFtZXRlcnMuaXNXZWJHTDIgKSA/ICcjZGVmaW5lIE1PUlBIVEFSR0VUU19URVhUVVJFX1NUUklERSAnICsgcGFyYW1ldGVycy5tb3JwaFRleHR1cmVTdHJpZGUgOiAnJyxcclxuXHRcdFx0KCBwYXJhbWV0ZXJzLm1vcnBoVGFyZ2V0c0NvdW50ID4gMCAmJiBwYXJhbWV0ZXJzLmlzV2ViR0wyICkgPyAnI2RlZmluZSBNT1JQSFRBUkdFVFNfQ09VTlQgJyArIHBhcmFtZXRlcnMubW9ycGhUYXJnZXRzQ291bnQgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy5kb3VibGVTaWRlZCA/ICcjZGVmaW5lIERPVUJMRV9TSURFRCcgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy5mbGlwU2lkZWQgPyAnI2RlZmluZSBGTElQX1NJREVEJyA6ICcnLFxyXG5cclxuXHRcdFx0cGFyYW1ldGVycy5zaGFkb3dNYXBFbmFibGVkID8gJyNkZWZpbmUgVVNFX1NIQURPV01BUCcgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy5zaGFkb3dNYXBFbmFibGVkID8gJyNkZWZpbmUgJyArIHNoYWRvd01hcFR5cGVEZWZpbmUgOiAnJyxcclxuXHJcblx0XHRcdHBhcmFtZXRlcnMuc2l6ZUF0dGVudWF0aW9uID8gJyNkZWZpbmUgVVNFX1NJWkVBVFRFTlVBVElPTicgOiAnJyxcclxuXHJcblx0XHRcdHBhcmFtZXRlcnMubnVtTGlnaHRQcm9iZXMgPiAwID8gJyNkZWZpbmUgVVNFX0xJR0hUX1BST0JFUycgOiAnJyxcclxuXHJcblx0XHRcdHBhcmFtZXRlcnMudXNlTGVnYWN5TGlnaHRzID8gJyNkZWZpbmUgTEVHQUNZX0xJR0hUUycgOiAnJyxcclxuXHJcblx0XHRcdHBhcmFtZXRlcnMubG9nYXJpdGhtaWNEZXB0aEJ1ZmZlciA/ICcjZGVmaW5lIFVTRV9MT0dERVBUSEJVRicgOiAnJyxcclxuXHRcdFx0KCBwYXJhbWV0ZXJzLmxvZ2FyaXRobWljRGVwdGhCdWZmZXIgJiYgcGFyYW1ldGVycy5yZW5kZXJlckV4dGVuc2lvbkZyYWdEZXB0aCApID8gJyNkZWZpbmUgVVNFX0xPR0RFUFRIQlVGX0VYVCcgOiAnJyxcclxuXHJcblx0XHRcdCd1bmlmb3JtIG1hdDQgbW9kZWxNYXRyaXg7JyxcclxuXHRcdFx0J3VuaWZvcm0gbWF0NCBtb2RlbFZpZXdNYXRyaXg7JyxcclxuXHRcdFx0J3VuaWZvcm0gbWF0NCBwcm9qZWN0aW9uTWF0cml4OycsXHJcblx0XHRcdCd1bmlmb3JtIG1hdDQgdmlld01hdHJpeDsnLFxyXG5cdFx0XHQndW5pZm9ybSBtYXQzIG5vcm1hbE1hdHJpeDsnLFxyXG5cdFx0XHQndW5pZm9ybSB2ZWMzIGNhbWVyYVBvc2l0aW9uOycsXHJcblx0XHRcdCd1bmlmb3JtIGJvb2wgaXNPcnRob2dyYXBoaWM7JyxcclxuXHJcblx0XHRcdCcjaWZkZWYgVVNFX0lOU1RBTkNJTkcnLFxyXG5cclxuXHRcdFx0J1x0YXR0cmlidXRlIG1hdDQgaW5zdGFuY2VNYXRyaXg7JyxcclxuXHJcblx0XHRcdCcjZW5kaWYnLFxyXG5cclxuXHRcdFx0JyNpZmRlZiBVU0VfSU5TVEFOQ0lOR19DT0xPUicsXHJcblxyXG5cdFx0XHQnXHRhdHRyaWJ1dGUgdmVjMyBpbnN0YW5jZUNvbG9yOycsXHJcblxyXG5cdFx0XHQnI2VuZGlmJyxcclxuXHJcblx0XHRcdCdhdHRyaWJ1dGUgdmVjMyBwb3NpdGlvbjsnLFxyXG5cdFx0XHQnYXR0cmlidXRlIHZlYzMgbm9ybWFsOycsXHJcblx0XHRcdCdhdHRyaWJ1dGUgdmVjMiB1djsnLFxyXG5cclxuXHRcdFx0JyNpZmRlZiBVU0VfVVYxJyxcclxuXHJcblx0XHRcdCdcdGF0dHJpYnV0ZSB2ZWMyIHV2MTsnLFxyXG5cclxuXHRcdFx0JyNlbmRpZicsXHJcblxyXG5cdFx0XHQnI2lmZGVmIFVTRV9VVjInLFxyXG5cclxuXHRcdFx0J1x0YXR0cmlidXRlIHZlYzIgdXYyOycsXHJcblxyXG5cdFx0XHQnI2VuZGlmJyxcclxuXHJcblx0XHRcdCcjaWZkZWYgVVNFX1VWMycsXHJcblxyXG5cdFx0XHQnXHRhdHRyaWJ1dGUgdmVjMiB1djM7JyxcclxuXHJcblx0XHRcdCcjZW5kaWYnLFxyXG5cclxuXHRcdFx0JyNpZmRlZiBVU0VfVEFOR0VOVCcsXHJcblxyXG5cdFx0XHQnXHRhdHRyaWJ1dGUgdmVjNCB0YW5nZW50OycsXHJcblxyXG5cdFx0XHQnI2VuZGlmJyxcclxuXHJcblx0XHRcdCcjaWYgZGVmaW5lZCggVVNFX0NPTE9SX0FMUEhBICknLFxyXG5cclxuXHRcdFx0J1x0YXR0cmlidXRlIHZlYzQgY29sb3I7JyxcclxuXHJcblx0XHRcdCcjZWxpZiBkZWZpbmVkKCBVU0VfQ09MT1IgKScsXHJcblxyXG5cdFx0XHQnXHRhdHRyaWJ1dGUgdmVjMyBjb2xvcjsnLFxyXG5cclxuXHRcdFx0JyNlbmRpZicsXHJcblxyXG5cdFx0XHQnI2lmICggZGVmaW5lZCggVVNFX01PUlBIVEFSR0VUUyApICYmICEgZGVmaW5lZCggTU9SUEhUQVJHRVRTX1RFWFRVUkUgKSApJyxcclxuXHJcblx0XHRcdCdcdGF0dHJpYnV0ZSB2ZWMzIG1vcnBoVGFyZ2V0MDsnLFxyXG5cdFx0XHQnXHRhdHRyaWJ1dGUgdmVjMyBtb3JwaFRhcmdldDE7JyxcclxuXHRcdFx0J1x0YXR0cmlidXRlIHZlYzMgbW9ycGhUYXJnZXQyOycsXHJcblx0XHRcdCdcdGF0dHJpYnV0ZSB2ZWMzIG1vcnBoVGFyZ2V0MzsnLFxyXG5cclxuXHRcdFx0J1x0I2lmZGVmIFVTRV9NT1JQSE5PUk1BTFMnLFxyXG5cclxuXHRcdFx0J1x0XHRhdHRyaWJ1dGUgdmVjMyBtb3JwaE5vcm1hbDA7JyxcclxuXHRcdFx0J1x0XHRhdHRyaWJ1dGUgdmVjMyBtb3JwaE5vcm1hbDE7JyxcclxuXHRcdFx0J1x0XHRhdHRyaWJ1dGUgdmVjMyBtb3JwaE5vcm1hbDI7JyxcclxuXHRcdFx0J1x0XHRhdHRyaWJ1dGUgdmVjMyBtb3JwaE5vcm1hbDM7JyxcclxuXHJcblx0XHRcdCdcdCNlbHNlJyxcclxuXHJcblx0XHRcdCdcdFx0YXR0cmlidXRlIHZlYzMgbW9ycGhUYXJnZXQ0OycsXHJcblx0XHRcdCdcdFx0YXR0cmlidXRlIHZlYzMgbW9ycGhUYXJnZXQ1OycsXHJcblx0XHRcdCdcdFx0YXR0cmlidXRlIHZlYzMgbW9ycGhUYXJnZXQ2OycsXHJcblx0XHRcdCdcdFx0YXR0cmlidXRlIHZlYzMgbW9ycGhUYXJnZXQ3OycsXHJcblxyXG5cdFx0XHQnXHQjZW5kaWYnLFxyXG5cclxuXHRcdFx0JyNlbmRpZicsXHJcblxyXG5cdFx0XHQnI2lmZGVmIFVTRV9TS0lOTklORycsXHJcblxyXG5cdFx0XHQnXHRhdHRyaWJ1dGUgdmVjNCBza2luSW5kZXg7JyxcclxuXHRcdFx0J1x0YXR0cmlidXRlIHZlYzQgc2tpbldlaWdodDsnLFxyXG5cclxuXHRcdFx0JyNlbmRpZicsXHJcblxyXG5cdFx0XHQnXFxuJ1xyXG5cclxuXHRcdF0uZmlsdGVyKCBmaWx0ZXJFbXB0eUxpbmUgKS5qb2luKCAnXFxuJyApO1xyXG5cclxuXHRcdHByZWZpeEZyYWdtZW50ID0gW1xyXG5cclxuXHRcdFx0Y3VzdG9tRXh0ZW5zaW9ucyxcclxuXHJcblx0XHRcdGdlbmVyYXRlUHJlY2lzaW9uKCBwYXJhbWV0ZXJzICksXHJcblxyXG5cdFx0XHQnI2RlZmluZSBTSEFERVJfVFlQRSAnICsgcGFyYW1ldGVycy5zaGFkZXJUeXBlLFxyXG5cdFx0XHQnI2RlZmluZSBTSEFERVJfTkFNRSAnICsgcGFyYW1ldGVycy5zaGFkZXJOYW1lLFxyXG5cclxuXHRcdFx0Y3VzdG9tRGVmaW5lcyxcclxuXHJcblx0XHRcdHBhcmFtZXRlcnMudXNlRm9nICYmIHBhcmFtZXRlcnMuZm9nID8gJyNkZWZpbmUgVVNFX0ZPRycgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy51c2VGb2cgJiYgcGFyYW1ldGVycy5mb2dFeHAyID8gJyNkZWZpbmUgRk9HX0VYUDInIDogJycsXHJcblxyXG5cdFx0XHRwYXJhbWV0ZXJzLmFscGhhVG9Db3ZlcmFnZSA/ICcjZGVmaW5lIEFMUEhBX1RPX0NPVkVSQUdFJyA6ICcnLFxyXG5cdFx0XHRwYXJhbWV0ZXJzLm1hcCA/ICcjZGVmaW5lIFVTRV9NQVAnIDogJycsXHJcblx0XHRcdHBhcmFtZXRlcnMubWF0Y2FwID8gJyNkZWZpbmUgVVNFX01BVENBUCcgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy5lbnZNYXAgPyAnI2RlZmluZSBVU0VfRU5WTUFQJyA6ICcnLFxyXG5cdFx0XHRwYXJhbWV0ZXJzLmVudk1hcCA/ICcjZGVmaW5lICcgKyBlbnZNYXBUeXBlRGVmaW5lIDogJycsXHJcblx0XHRcdHBhcmFtZXRlcnMuZW52TWFwID8gJyNkZWZpbmUgJyArIGVudk1hcE1vZGVEZWZpbmUgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy5lbnZNYXAgPyAnI2RlZmluZSAnICsgZW52TWFwQmxlbmRpbmdEZWZpbmUgOiAnJyxcclxuXHRcdFx0ZW52TWFwQ3ViZVVWU2l6ZSA/ICcjZGVmaW5lIENVQkVVVl9URVhFTF9XSURUSCAnICsgZW52TWFwQ3ViZVVWU2l6ZS50ZXhlbFdpZHRoIDogJycsXHJcblx0XHRcdGVudk1hcEN1YmVVVlNpemUgPyAnI2RlZmluZSBDVUJFVVZfVEVYRUxfSEVJR0hUICcgKyBlbnZNYXBDdWJlVVZTaXplLnRleGVsSGVpZ2h0IDogJycsXHJcblx0XHRcdGVudk1hcEN1YmVVVlNpemUgPyAnI2RlZmluZSBDVUJFVVZfTUFYX01JUCAnICsgZW52TWFwQ3ViZVVWU2l6ZS5tYXhNaXAgKyAnLjAnIDogJycsXHJcblx0XHRcdHBhcmFtZXRlcnMubGlnaHRNYXAgPyAnI2RlZmluZSBVU0VfTElHSFRNQVAnIDogJycsXHJcblx0XHRcdHBhcmFtZXRlcnMuYW9NYXAgPyAnI2RlZmluZSBVU0VfQU9NQVAnIDogJycsXHJcblx0XHRcdHBhcmFtZXRlcnMuYnVtcE1hcCA/ICcjZGVmaW5lIFVTRV9CVU1QTUFQJyA6ICcnLFxyXG5cdFx0XHRwYXJhbWV0ZXJzLm5vcm1hbE1hcCA/ICcjZGVmaW5lIFVTRV9OT1JNQUxNQVAnIDogJycsXHJcblx0XHRcdHBhcmFtZXRlcnMubm9ybWFsTWFwT2JqZWN0U3BhY2UgPyAnI2RlZmluZSBVU0VfTk9STUFMTUFQX09CSkVDVFNQQUNFJyA6ICcnLFxyXG5cdFx0XHRwYXJhbWV0ZXJzLm5vcm1hbE1hcFRhbmdlbnRTcGFjZSA/ICcjZGVmaW5lIFVTRV9OT1JNQUxNQVBfVEFOR0VOVFNQQUNFJyA6ICcnLFxyXG5cdFx0XHRwYXJhbWV0ZXJzLmVtaXNzaXZlTWFwID8gJyNkZWZpbmUgVVNFX0VNSVNTSVZFTUFQJyA6ICcnLFxyXG5cclxuXHRcdFx0cGFyYW1ldGVycy5hbmlzb3Ryb3B5ID8gJyNkZWZpbmUgVVNFX0FOSVNPVFJPUFknIDogJycsXHJcblx0XHRcdHBhcmFtZXRlcnMuYW5pc290cm9weU1hcCA/ICcjZGVmaW5lIFVTRV9BTklTT1RST1BZTUFQJyA6ICcnLFxyXG5cclxuXHRcdFx0cGFyYW1ldGVycy5jbGVhcmNvYXQgPyAnI2RlZmluZSBVU0VfQ0xFQVJDT0FUJyA6ICcnLFxyXG5cdFx0XHRwYXJhbWV0ZXJzLmNsZWFyY29hdE1hcCA/ICcjZGVmaW5lIFVTRV9DTEVBUkNPQVRNQVAnIDogJycsXHJcblx0XHRcdHBhcmFtZXRlcnMuY2xlYXJjb2F0Um91Z2huZXNzTWFwID8gJyNkZWZpbmUgVVNFX0NMRUFSQ09BVF9ST1VHSE5FU1NNQVAnIDogJycsXHJcblx0XHRcdHBhcmFtZXRlcnMuY2xlYXJjb2F0Tm9ybWFsTWFwID8gJyNkZWZpbmUgVVNFX0NMRUFSQ09BVF9OT1JNQUxNQVAnIDogJycsXHJcblxyXG5cdFx0XHRwYXJhbWV0ZXJzLmlyaWRlc2NlbmNlID8gJyNkZWZpbmUgVVNFX0lSSURFU0NFTkNFJyA6ICcnLFxyXG5cdFx0XHRwYXJhbWV0ZXJzLmlyaWRlc2NlbmNlTWFwID8gJyNkZWZpbmUgVVNFX0lSSURFU0NFTkNFTUFQJyA6ICcnLFxyXG5cdFx0XHRwYXJhbWV0ZXJzLmlyaWRlc2NlbmNlVGhpY2tuZXNzTWFwID8gJyNkZWZpbmUgVVNFX0lSSURFU0NFTkNFX1RISUNLTkVTU01BUCcgOiAnJyxcclxuXHJcblx0XHRcdHBhcmFtZXRlcnMuc3BlY3VsYXJNYXAgPyAnI2RlZmluZSBVU0VfU1BFQ1VMQVJNQVAnIDogJycsXHJcblx0XHRcdHBhcmFtZXRlcnMuc3BlY3VsYXJDb2xvck1hcCA/ICcjZGVmaW5lIFVTRV9TUEVDVUxBUl9DT0xPUk1BUCcgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy5zcGVjdWxhckludGVuc2l0eU1hcCA/ICcjZGVmaW5lIFVTRV9TUEVDVUxBUl9JTlRFTlNJVFlNQVAnIDogJycsXHJcblxyXG5cdFx0XHRwYXJhbWV0ZXJzLnJvdWdobmVzc01hcCA/ICcjZGVmaW5lIFVTRV9ST1VHSE5FU1NNQVAnIDogJycsXHJcblx0XHRcdHBhcmFtZXRlcnMubWV0YWxuZXNzTWFwID8gJyNkZWZpbmUgVVNFX01FVEFMTkVTU01BUCcgOiAnJyxcclxuXHJcblx0XHRcdHBhcmFtZXRlcnMuYWxwaGFNYXAgPyAnI2RlZmluZSBVU0VfQUxQSEFNQVAnIDogJycsXHJcblx0XHRcdHBhcmFtZXRlcnMuYWxwaGFUZXN0ID8gJyNkZWZpbmUgVVNFX0FMUEhBVEVTVCcgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy5hbHBoYUhhc2ggPyAnI2RlZmluZSBVU0VfQUxQSEFIQVNIJyA6ICcnLFxyXG5cclxuXHRcdFx0cGFyYW1ldGVycy5zaGVlbiA/ICcjZGVmaW5lIFVTRV9TSEVFTicgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy5zaGVlbkNvbG9yTWFwID8gJyNkZWZpbmUgVVNFX1NIRUVOX0NPTE9STUFQJyA6ICcnLFxyXG5cdFx0XHRwYXJhbWV0ZXJzLnNoZWVuUm91Z2huZXNzTWFwID8gJyNkZWZpbmUgVVNFX1NIRUVOX1JPVUdITkVTU01BUCcgOiAnJyxcclxuXHJcblx0XHRcdHBhcmFtZXRlcnMudHJhbnNtaXNzaW9uID8gJyNkZWZpbmUgVVNFX1RSQU5TTUlTU0lPTicgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy50cmFuc21pc3Npb25NYXAgPyAnI2RlZmluZSBVU0VfVFJBTlNNSVNTSU9OTUFQJyA6ICcnLFxyXG5cdFx0XHRwYXJhbWV0ZXJzLnRoaWNrbmVzc01hcCA/ICcjZGVmaW5lIFVTRV9USElDS05FU1NNQVAnIDogJycsXHJcblxyXG5cdFx0XHRwYXJhbWV0ZXJzLnZlcnRleFRhbmdlbnRzICYmIHBhcmFtZXRlcnMuZmxhdFNoYWRpbmcgPT09IGZhbHNlID8gJyNkZWZpbmUgVVNFX1RBTkdFTlQnIDogJycsXHJcblx0XHRcdHBhcmFtZXRlcnMudmVydGV4Q29sb3JzIHx8IHBhcmFtZXRlcnMuaW5zdGFuY2luZ0NvbG9yID8gJyNkZWZpbmUgVVNFX0NPTE9SJyA6ICcnLFxyXG5cdFx0XHRwYXJhbWV0ZXJzLnZlcnRleEFscGhhcyA/ICcjZGVmaW5lIFVTRV9DT0xPUl9BTFBIQScgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy52ZXJ0ZXhVdjFzID8gJyNkZWZpbmUgVVNFX1VWMScgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy52ZXJ0ZXhVdjJzID8gJyNkZWZpbmUgVVNFX1VWMicgOiAnJyxcclxuXHRcdFx0cGFyYW1ldGVycy52ZXJ0ZXhVdjNzID8gJyNkZWZpbmUgVVNFX1VWMycgOiAnJyxcclxuXHJcblx0XHRcdHBhcmFtZXRlcnMucG9pbnRzVXZzID8gJyNkZWZpbmUgVVNFX1BPSU5UU19VVicgOiAnJyxcclxuXHJcblx0XHRcdHBhcmFtZXRlcnMuZ3JhZGllbnRNYXAgPyAnI2RlZmluZSBVU0VfR1JBRElFTlRNQVAnIDogJycsXHJcblxyXG5cdFx0XHRwYXJhbWV0ZXJzLmZsYXRTaGFkaW5nID8gJyNkZWZpbmUgRkxBVF9TSEFERUQnIDogJycsXHJcblxyXG5cdFx0XHRwYXJhbWV0ZXJzLmRvdWJsZVNpZGVkID8gJyNkZWZpbmUgRE9VQkxFX1NJREVEJyA6ICcnLFxyXG5cdFx0XHRwYXJhbWV0ZXJzLmZsaXBTaWRlZCA/ICcjZGVmaW5lIEZMSVBfU0lERUQnIDogJycsXHJcblxyXG5cdFx0XHRwYXJhbWV0ZXJzLnNoYWRvd01hcEVuYWJsZWQgPyAnI2RlZmluZSBVU0VfU0hBRE9XTUFQJyA6ICcnLFxyXG5cdFx0XHRwYXJhbWV0ZXJzLnNoYWRvd01hcEVuYWJsZWQgPyAnI2RlZmluZSAnICsgc2hhZG93TWFwVHlwZURlZmluZSA6ICcnLFxyXG5cclxuXHRcdFx0cGFyYW1ldGVycy5wcmVtdWx0aXBsaWVkQWxwaGEgPyAnI2RlZmluZSBQUkVNVUxUSVBMSUVEX0FMUEhBJyA6ICcnLFxyXG5cclxuXHRcdFx0cGFyYW1ldGVycy5udW1MaWdodFByb2JlcyA+IDAgPyAnI2RlZmluZSBVU0VfTElHSFRfUFJPQkVTJyA6ICcnLFxyXG5cclxuXHRcdFx0cGFyYW1ldGVycy51c2VMZWdhY3lMaWdodHMgPyAnI2RlZmluZSBMRUdBQ1lfTElHSFRTJyA6ICcnLFxyXG5cclxuXHRcdFx0cGFyYW1ldGVycy5kZWNvZGVWaWRlb1RleHR1cmUgPyAnI2RlZmluZSBERUNPREVfVklERU9fVEVYVFVSRScgOiAnJyxcclxuXHJcblx0XHRcdHBhcmFtZXRlcnMubG9nYXJpdGhtaWNEZXB0aEJ1ZmZlciA/ICcjZGVmaW5lIFVTRV9MT0dERVBUSEJVRicgOiAnJyxcclxuXHRcdFx0KCBwYXJhbWV0ZXJzLmxvZ2FyaXRobWljRGVwdGhCdWZmZXIgJiYgcGFyYW1ldGVycy5yZW5kZXJlckV4dGVuc2lvbkZyYWdEZXB0aCApID8gJyNkZWZpbmUgVVNFX0xPR0RFUFRIQlVGX0VYVCcgOiAnJyxcclxuXHJcblx0XHRcdCd1bmlmb3JtIG1hdDQgdmlld01hdHJpeDsnLFxyXG5cdFx0XHQndW5pZm9ybSB2ZWMzIGNhbWVyYVBvc2l0aW9uOycsXHJcblx0XHRcdCd1bmlmb3JtIGJvb2wgaXNPcnRob2dyYXBoaWM7JyxcclxuXHJcblx0XHRcdCggcGFyYW1ldGVycy50b25lTWFwcGluZyAhPT0gTm9Ub25lTWFwcGluZyApID8gJyNkZWZpbmUgVE9ORV9NQVBQSU5HJyA6ICcnLFxyXG5cdFx0XHQoIHBhcmFtZXRlcnMudG9uZU1hcHBpbmcgIT09IE5vVG9uZU1hcHBpbmcgKSA/IFNoYWRlckNodW5rWyAndG9uZW1hcHBpbmdfcGFyc19mcmFnbWVudCcgXSA6ICcnLCAvLyB0aGlzIGNvZGUgaXMgcmVxdWlyZWQgaGVyZSBiZWNhdXNlIGl0IGlzIHVzZWQgYnkgdGhlIHRvbmVNYXBwaW5nKCkgZnVuY3Rpb24gZGVmaW5lZCBiZWxvd1xyXG5cdFx0XHQoIHBhcmFtZXRlcnMudG9uZU1hcHBpbmcgIT09IE5vVG9uZU1hcHBpbmcgKSA/IGdldFRvbmVNYXBwaW5nRnVuY3Rpb24oICd0b25lTWFwcGluZycsIHBhcmFtZXRlcnMudG9uZU1hcHBpbmcgKSA6ICcnLFxyXG5cclxuXHRcdFx0cGFyYW1ldGVycy5kaXRoZXJpbmcgPyAnI2RlZmluZSBESVRIRVJJTkcnIDogJycsXHJcblx0XHRcdHBhcmFtZXRlcnMub3BhcXVlID8gJyNkZWZpbmUgT1BBUVVFJyA6ICcnLFxyXG5cclxuXHRcdFx0U2hhZGVyQ2h1bmtbICdjb2xvcnNwYWNlX3BhcnNfZnJhZ21lbnQnIF0sIC8vIHRoaXMgY29kZSBpcyByZXF1aXJlZCBoZXJlIGJlY2F1c2UgaXQgaXMgdXNlZCBieSB0aGUgdmFyaW91cyBlbmNvZGluZy9kZWNvZGluZyBmdW5jdGlvbiBkZWZpbmVkIGJlbG93XHJcblx0XHRcdGdldFRleGVsRW5jb2RpbmdGdW5jdGlvbiggJ2xpbmVhclRvT3V0cHV0VGV4ZWwnLCBwYXJhbWV0ZXJzLm91dHB1dENvbG9yU3BhY2UgKSxcclxuXHJcblx0XHRcdHBhcmFtZXRlcnMudXNlRGVwdGhQYWNraW5nID8gJyNkZWZpbmUgREVQVEhfUEFDS0lORyAnICsgcGFyYW1ldGVycy5kZXB0aFBhY2tpbmcgOiAnJyxcclxuXHJcblx0XHRcdCdcXG4nXHJcblxyXG5cdFx0XS5maWx0ZXIoIGZpbHRlckVtcHR5TGluZSApLmpvaW4oICdcXG4nICk7XHJcblxyXG5cdH1cclxuXHJcblx0dmVydGV4U2hhZGVyID0gcmVzb2x2ZUluY2x1ZGVzKCB2ZXJ0ZXhTaGFkZXIgKTtcclxuXHR2ZXJ0ZXhTaGFkZXIgPSByZXBsYWNlTGlnaHROdW1zKCB2ZXJ0ZXhTaGFkZXIsIHBhcmFtZXRlcnMgKTtcclxuXHR2ZXJ0ZXhTaGFkZXIgPSByZXBsYWNlQ2xpcHBpbmdQbGFuZU51bXMoIHZlcnRleFNoYWRlciwgcGFyYW1ldGVycyApO1xyXG5cclxuXHRmcmFnbWVudFNoYWRlciA9IHJlc29sdmVJbmNsdWRlcyggZnJhZ21lbnRTaGFkZXIgKTtcclxuXHRmcmFnbWVudFNoYWRlciA9IHJlcGxhY2VMaWdodE51bXMoIGZyYWdtZW50U2hhZGVyLCBwYXJhbWV0ZXJzICk7XHJcblx0ZnJhZ21lbnRTaGFkZXIgPSByZXBsYWNlQ2xpcHBpbmdQbGFuZU51bXMoIGZyYWdtZW50U2hhZGVyLCBwYXJhbWV0ZXJzICk7XHJcblxyXG5cdHZlcnRleFNoYWRlciA9IHVucm9sbExvb3BzKCB2ZXJ0ZXhTaGFkZXIgKTtcclxuXHRmcmFnbWVudFNoYWRlciA9IHVucm9sbExvb3BzKCBmcmFnbWVudFNoYWRlciApO1xyXG5cclxuXHRpZiAoIHBhcmFtZXRlcnMuaXNXZWJHTDIgJiYgcGFyYW1ldGVycy5pc1Jhd1NoYWRlck1hdGVyaWFsICE9PSB0cnVlICkge1xyXG5cclxuXHRcdC8vIEdMU0wgMy4wIGNvbnZlcnNpb24gZm9yIGJ1aWx0LWluIG1hdGVyaWFscyBhbmQgU2hhZGVyTWF0ZXJpYWxcclxuXHJcblx0XHR2ZXJzaW9uU3RyaW5nID0gJyN2ZXJzaW9uIDMwMCBlc1xcbic7XHJcblxyXG5cdFx0cHJlZml4VmVydGV4ID0gW1xyXG5cdFx0XHRjdXN0b21WZXJ0ZXhFeHRlbnNpb25zLFxyXG5cdFx0XHQncHJlY2lzaW9uIG1lZGl1bXAgc2FtcGxlcjJEQXJyYXk7JyxcclxuXHRcdFx0JyNkZWZpbmUgYXR0cmlidXRlIGluJyxcclxuXHRcdFx0JyNkZWZpbmUgdmFyeWluZyBvdXQnLFxyXG5cdFx0XHQnI2RlZmluZSB0ZXh0dXJlMkQgdGV4dHVyZSdcclxuXHRcdF0uam9pbiggJ1xcbicgKSArICdcXG4nICsgcHJlZml4VmVydGV4O1xyXG5cclxuXHRcdHByZWZpeEZyYWdtZW50ID0gW1xyXG5cdFx0XHQncHJlY2lzaW9uIG1lZGl1bXAgc2FtcGxlcjJEQXJyYXk7JyxcclxuXHRcdFx0JyNkZWZpbmUgdmFyeWluZyBpbicsXHJcblx0XHRcdCggcGFyYW1ldGVycy5nbHNsVmVyc2lvbiA9PT0gR0xTTDMgKSA/ICcnIDogJ2xheW91dChsb2NhdGlvbiA9IDApIG91dCBoaWdocCB2ZWM0IHBjX2ZyYWdDb2xvcjsnLFxyXG5cdFx0XHQoIHBhcmFtZXRlcnMuZ2xzbFZlcnNpb24gPT09IEdMU0wzICkgPyAnJyA6ICcjZGVmaW5lIGdsX0ZyYWdDb2xvciBwY19mcmFnQ29sb3InLFxyXG5cdFx0XHQnI2RlZmluZSBnbF9GcmFnRGVwdGhFWFQgZ2xfRnJhZ0RlcHRoJyxcclxuXHRcdFx0JyNkZWZpbmUgdGV4dHVyZTJEIHRleHR1cmUnLFxyXG5cdFx0XHQnI2RlZmluZSB0ZXh0dXJlQ3ViZSB0ZXh0dXJlJyxcclxuXHRcdFx0JyNkZWZpbmUgdGV4dHVyZTJEUHJvaiB0ZXh0dXJlUHJvaicsXHJcblx0XHRcdCcjZGVmaW5lIHRleHR1cmUyRExvZEVYVCB0ZXh0dXJlTG9kJyxcclxuXHRcdFx0JyNkZWZpbmUgdGV4dHVyZTJEUHJvakxvZEVYVCB0ZXh0dXJlUHJvakxvZCcsXHJcblx0XHRcdCcjZGVmaW5lIHRleHR1cmVDdWJlTG9kRVhUIHRleHR1cmVMb2QnLFxyXG5cdFx0XHQnI2RlZmluZSB0ZXh0dXJlMkRHcmFkRVhUIHRleHR1cmVHcmFkJyxcclxuXHRcdFx0JyNkZWZpbmUgdGV4dHVyZTJEUHJvakdyYWRFWFQgdGV4dHVyZVByb2pHcmFkJyxcclxuXHRcdFx0JyNkZWZpbmUgdGV4dHVyZUN1YmVHcmFkRVhUIHRleHR1cmVHcmFkJ1xyXG5cdFx0XS5qb2luKCAnXFxuJyApICsgJ1xcbicgKyBwcmVmaXhGcmFnbWVudDtcclxuXHJcblx0fVxyXG5cclxuXHRjb25zdCB2ZXJ0ZXhHbHNsID0gdmVyc2lvblN0cmluZyArIHByZWZpeFZlcnRleCArIHZlcnRleFNoYWRlcjtcclxuXHRjb25zdCBmcmFnbWVudEdsc2wgPSB2ZXJzaW9uU3RyaW5nICsgcHJlZml4RnJhZ21lbnQgKyBmcmFnbWVudFNoYWRlcjtcclxuXHJcblx0Ly8gY29uc29sZS5sb2coICcqVkVSVEVYKicsIHZlcnRleEdsc2wgKTtcclxuXHQvLyBjb25zb2xlLmxvZyggJypGUkFHTUVOVConLCBmcmFnbWVudEdsc2wgKTtcclxuXHJcblx0Y29uc3QgZ2xWZXJ0ZXhTaGFkZXIgPSBXZWJHTFNoYWRlciggZ2wsIGdsLlZFUlRFWF9TSEFERVIsIHZlcnRleEdsc2wgKTtcclxuXHRjb25zdCBnbEZyYWdtZW50U2hhZGVyID0gV2ViR0xTaGFkZXIoIGdsLCBnbC5GUkFHTUVOVF9TSEFERVIsIGZyYWdtZW50R2xzbCApO1xyXG5cclxuXHRnbC5hdHRhY2hTaGFkZXIoIHByb2dyYW0sIGdsVmVydGV4U2hhZGVyICk7XHJcblx0Z2wuYXR0YWNoU2hhZGVyKCBwcm9ncmFtLCBnbEZyYWdtZW50U2hhZGVyICk7XHJcblxyXG5cdC8vIEZvcmNlIGEgcGFydGljdWxhciBhdHRyaWJ1dGUgdG8gaW5kZXggMC5cclxuXHJcblx0aWYgKCBwYXJhbWV0ZXJzLmluZGV4MEF0dHJpYnV0ZU5hbWUgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRnbC5iaW5kQXR0cmliTG9jYXRpb24oIHByb2dyYW0sIDAsIHBhcmFtZXRlcnMuaW5kZXgwQXR0cmlidXRlTmFtZSApO1xyXG5cclxuXHR9IGVsc2UgaWYgKCBwYXJhbWV0ZXJzLm1vcnBoVGFyZ2V0cyA9PT0gdHJ1ZSApIHtcclxuXHJcblx0XHQvLyBwcm9ncmFtcyB3aXRoIG1vcnBoVGFyZ2V0cyBkaXNwbGFjZSBwb3NpdGlvbiBvdXQgb2YgYXR0cmlidXRlIDBcclxuXHRcdGdsLmJpbmRBdHRyaWJMb2NhdGlvbiggcHJvZ3JhbSwgMCwgJ3Bvc2l0aW9uJyApO1xyXG5cclxuXHR9XHJcblxyXG5cdGdsLmxpbmtQcm9ncmFtKCBwcm9ncmFtICk7XHJcblxyXG5cdGZ1bmN0aW9uIG9uRmlyc3RVc2UoIHNlbGYgKSB7XHJcblxyXG5cdFx0Ly8gY2hlY2sgZm9yIGxpbmsgZXJyb3JzXHJcblx0XHRpZiAoIHJlbmRlcmVyLmRlYnVnLmNoZWNrU2hhZGVyRXJyb3JzICkge1xyXG5cclxuXHRcdFx0Y29uc3QgcHJvZ3JhbUxvZyA9IGdsLmdldFByb2dyYW1JbmZvTG9nKCBwcm9ncmFtICkudHJpbSgpO1xyXG5cdFx0XHRjb25zdCB2ZXJ0ZXhMb2cgPSBnbC5nZXRTaGFkZXJJbmZvTG9nKCBnbFZlcnRleFNoYWRlciApLnRyaW0oKTtcclxuXHRcdFx0Y29uc3QgZnJhZ21lbnRMb2cgPSBnbC5nZXRTaGFkZXJJbmZvTG9nKCBnbEZyYWdtZW50U2hhZGVyICkudHJpbSgpO1xyXG5cclxuXHRcdFx0bGV0IHJ1bm5hYmxlID0gdHJ1ZTtcclxuXHRcdFx0bGV0IGhhdmVEaWFnbm9zdGljcyA9IHRydWU7XHJcblxyXG5cdFx0XHRpZiAoIGdsLmdldFByb2dyYW1QYXJhbWV0ZXIoIHByb2dyYW0sIGdsLkxJTktfU1RBVFVTICkgPT09IGZhbHNlICkge1xyXG5cclxuXHRcdFx0XHRydW5uYWJsZSA9IGZhbHNlO1xyXG5cclxuXHRcdFx0XHRpZiAoIHR5cGVvZiByZW5kZXJlci5kZWJ1Zy5vblNoYWRlckVycm9yID09PSAnZnVuY3Rpb24nICkge1xyXG5cclxuXHRcdFx0XHRcdHJlbmRlcmVyLmRlYnVnLm9uU2hhZGVyRXJyb3IoIGdsLCBwcm9ncmFtLCBnbFZlcnRleFNoYWRlciwgZ2xGcmFnbWVudFNoYWRlciApO1xyXG5cclxuXHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdC8vIGRlZmF1bHQgZXJyb3IgcmVwb3J0aW5nXHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgdmVydGV4RXJyb3JzID0gZ2V0U2hhZGVyRXJyb3JzKCBnbCwgZ2xWZXJ0ZXhTaGFkZXIsICd2ZXJ0ZXgnICk7XHJcblx0XHRcdFx0XHRjb25zdCBmcmFnbWVudEVycm9ycyA9IGdldFNoYWRlckVycm9ycyggZ2wsIGdsRnJhZ21lbnRTaGFkZXIsICdmcmFnbWVudCcgKTtcclxuXHJcblx0XHRcdFx0XHRjb25zb2xlLmVycm9yKFxyXG5cdFx0XHRcdFx0XHQnVEhSRUUuV2ViR0xQcm9ncmFtOiBTaGFkZXIgRXJyb3IgJyArIGdsLmdldEVycm9yKCkgKyAnIC0gJyArXHJcblx0XHRcdFx0XHRcdCdWQUxJREFURV9TVEFUVVMgJyArIGdsLmdldFByb2dyYW1QYXJhbWV0ZXIoIHByb2dyYW0sIGdsLlZBTElEQVRFX1NUQVRVUyApICsgJ1xcblxcbicgK1xyXG5cdFx0XHRcdFx0XHQnTWF0ZXJpYWwgTmFtZTogJyArIHNlbGYubmFtZSArICdcXG4nICtcclxuXHRcdFx0XHRcdFx0J01hdGVyaWFsIFR5cGU6ICcgKyBzZWxmLnR5cGUgKyAnXFxuXFxuJyArXHJcblx0XHRcdFx0XHRcdCdQcm9ncmFtIEluZm8gTG9nOiAnICsgcHJvZ3JhbUxvZyArICdcXG4nICtcclxuXHRcdFx0XHRcdFx0dmVydGV4RXJyb3JzICsgJ1xcbicgK1xyXG5cdFx0XHRcdFx0XHRmcmFnbWVudEVycm9yc1xyXG5cdFx0XHRcdFx0KTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fSBlbHNlIGlmICggcHJvZ3JhbUxvZyAhPT0gJycgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLldlYkdMUHJvZ3JhbTogUHJvZ3JhbSBJbmZvIExvZzonLCBwcm9ncmFtTG9nICk7XHJcblxyXG5cdFx0XHR9IGVsc2UgaWYgKCB2ZXJ0ZXhMb2cgPT09ICcnIHx8IGZyYWdtZW50TG9nID09PSAnJyApIHtcclxuXHJcblx0XHRcdFx0aGF2ZURpYWdub3N0aWNzID0gZmFsc2U7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRpZiAoIGhhdmVEaWFnbm9zdGljcyApIHtcclxuXHJcblx0XHRcdFx0c2VsZi5kaWFnbm9zdGljcyA9IHtcclxuXHJcblx0XHRcdFx0XHRydW5uYWJsZTogcnVubmFibGUsXHJcblxyXG5cdFx0XHRcdFx0cHJvZ3JhbUxvZzogcHJvZ3JhbUxvZyxcclxuXHJcblx0XHRcdFx0XHR2ZXJ0ZXhTaGFkZXI6IHtcclxuXHJcblx0XHRcdFx0XHRcdGxvZzogdmVydGV4TG9nLFxyXG5cdFx0XHRcdFx0XHRwcmVmaXg6IHByZWZpeFZlcnRleFxyXG5cclxuXHRcdFx0XHRcdH0sXHJcblxyXG5cdFx0XHRcdFx0ZnJhZ21lbnRTaGFkZXI6IHtcclxuXHJcblx0XHRcdFx0XHRcdGxvZzogZnJhZ21lbnRMb2csXHJcblx0XHRcdFx0XHRcdHByZWZpeDogcHJlZml4RnJhZ21lbnRcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH07XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIENsZWFuIHVwXHJcblxyXG5cdFx0Ly8gQ3Jhc2hlcyBpbiBpT1M5IGFuZCBpT1MxMC4gIzE4NDAyXHJcblx0XHQvLyBnbC5kZXRhY2hTaGFkZXIoIHByb2dyYW0sIGdsVmVydGV4U2hhZGVyICk7XHJcblx0XHQvLyBnbC5kZXRhY2hTaGFkZXIoIHByb2dyYW0sIGdsRnJhZ21lbnRTaGFkZXIgKTtcclxuXHJcblx0XHRnbC5kZWxldGVTaGFkZXIoIGdsVmVydGV4U2hhZGVyICk7XHJcblx0XHRnbC5kZWxldGVTaGFkZXIoIGdsRnJhZ21lbnRTaGFkZXIgKTtcclxuXHJcblx0XHRjYWNoZWRVbmlmb3JtcyA9IG5ldyBXZWJHTFVuaWZvcm1zKCBnbCwgcHJvZ3JhbSApO1xyXG5cdFx0Y2FjaGVkQXR0cmlidXRlcyA9IGZldGNoQXR0cmlidXRlTG9jYXRpb25zKCBnbCwgcHJvZ3JhbSApO1xyXG5cclxuXHR9XHJcblxyXG5cdC8vIHNldCB1cCBjYWNoaW5nIGZvciB1bmlmb3JtIGxvY2F0aW9uc1xyXG5cclxuXHRsZXQgY2FjaGVkVW5pZm9ybXM7XHJcblxyXG5cdHRoaXMuZ2V0VW5pZm9ybXMgPSBmdW5jdGlvbiAoKSB7XHJcblxyXG5cdFx0aWYgKCBjYWNoZWRVbmlmb3JtcyA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0Ly8gUG9wdWxhdGVzIGNhY2hlZFVuaWZvcm1zIGFuZCBjYWNoZWRBdHRyaWJ1dGVzXHJcblx0XHRcdG9uRmlyc3RVc2UoIHRoaXMgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIGNhY2hlZFVuaWZvcm1zO1xyXG5cclxuXHR9O1xyXG5cclxuXHQvLyBzZXQgdXAgY2FjaGluZyBmb3IgYXR0cmlidXRlIGxvY2F0aW9uc1xyXG5cclxuXHRsZXQgY2FjaGVkQXR0cmlidXRlcztcclxuXHJcblx0dGhpcy5nZXRBdHRyaWJ1dGVzID0gZnVuY3Rpb24gKCkge1xyXG5cclxuXHRcdGlmICggY2FjaGVkQXR0cmlidXRlcyA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0Ly8gUG9wdWxhdGVzIGNhY2hlZEF0dHJpYnV0ZXMgYW5kIGNhY2hlZFVuaWZvcm1zXHJcblx0XHRcdG9uRmlyc3RVc2UoIHRoaXMgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIGNhY2hlZEF0dHJpYnV0ZXM7XHJcblxyXG5cdH07XHJcblxyXG5cdC8vIGluZGljYXRlIHdoZW4gdGhlIHByb2dyYW0gaXMgcmVhZHkgdG8gYmUgdXNlZC4gaWYgdGhlIEtIUl9wYXJhbGxlbF9zaGFkZXJfY29tcGlsZSBleHRlbnNpb24gaXNuJ3Qgc3VwcG9ydGVkLFxyXG5cdC8vIGZsYWcgdGhlIHByb2dyYW0gYXMgcmVhZHkgaW1tZWRpYXRlbHkuIEl0IG1heSBjYXVzZSBhIHN0YWxsIHdoZW4gaXQncyBmaXJzdCB1c2VkLlxyXG5cclxuXHRsZXQgcHJvZ3JhbVJlYWR5ID0gKCBwYXJhbWV0ZXJzLnJlbmRlcmVyRXh0ZW5zaW9uUGFyYWxsZWxTaGFkZXJDb21waWxlID09PSBmYWxzZSApO1xyXG5cclxuXHR0aGlzLmlzUmVhZHkgPSBmdW5jdGlvbiAoKSB7XHJcblxyXG5cdFx0aWYgKCBwcm9ncmFtUmVhZHkgPT09IGZhbHNlICkge1xyXG5cclxuXHRcdFx0cHJvZ3JhbVJlYWR5ID0gZ2wuZ2V0UHJvZ3JhbVBhcmFtZXRlciggcHJvZ3JhbSwgQ09NUExFVElPTl9TVEFUVVNfS0hSICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiBwcm9ncmFtUmVhZHk7XHJcblxyXG5cdH07XHJcblxyXG5cdC8vIGZyZWUgcmVzb3VyY2VcclxuXHJcblx0dGhpcy5kZXN0cm95ID0gZnVuY3Rpb24gKCkge1xyXG5cclxuXHRcdGJpbmRpbmdTdGF0ZXMucmVsZWFzZVN0YXRlc09mUHJvZ3JhbSggdGhpcyApO1xyXG5cclxuXHRcdGdsLmRlbGV0ZVByb2dyYW0oIHByb2dyYW0gKTtcclxuXHRcdHRoaXMucHJvZ3JhbSA9IHVuZGVmaW5lZDtcclxuXHJcblx0fTtcclxuXHJcblx0Ly9cclxuXHJcblx0dGhpcy50eXBlID0gcGFyYW1ldGVycy5zaGFkZXJUeXBlO1xyXG5cdHRoaXMubmFtZSA9IHBhcmFtZXRlcnMuc2hhZGVyTmFtZTtcclxuXHR0aGlzLmlkID0gcHJvZ3JhbUlkQ291bnQgKys7XHJcblx0dGhpcy5jYWNoZUtleSA9IGNhY2hlS2V5O1xyXG5cdHRoaXMudXNlZFRpbWVzID0gMTtcclxuXHR0aGlzLnByb2dyYW0gPSBwcm9ncmFtO1xyXG5cdHRoaXMudmVydGV4U2hhZGVyID0gZ2xWZXJ0ZXhTaGFkZXI7XHJcblx0dGhpcy5mcmFnbWVudFNoYWRlciA9IGdsRnJhZ21lbnRTaGFkZXI7XHJcblxyXG5cdHJldHVybiB0aGlzO1xyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgV2ViR0xQcm9ncmFtIH07XHJcbiIsImxldCBfaWQgPSAwO1xyXG5cclxuY2xhc3MgV2ViR0xTaGFkZXJDYWNoZSB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCkge1xyXG5cclxuXHRcdHRoaXMuc2hhZGVyQ2FjaGUgPSBuZXcgTWFwKCk7XHJcblx0XHR0aGlzLm1hdGVyaWFsQ2FjaGUgPSBuZXcgTWFwKCk7XHJcblxyXG5cdH1cclxuXHJcblx0dXBkYXRlKCBtYXRlcmlhbCApIHtcclxuXHJcblx0XHRjb25zdCB2ZXJ0ZXhTaGFkZXIgPSBtYXRlcmlhbC52ZXJ0ZXhTaGFkZXI7XHJcblx0XHRjb25zdCBmcmFnbWVudFNoYWRlciA9IG1hdGVyaWFsLmZyYWdtZW50U2hhZGVyO1xyXG5cclxuXHRcdGNvbnN0IHZlcnRleFNoYWRlclN0YWdlID0gdGhpcy5fZ2V0U2hhZGVyU3RhZ2UoIHZlcnRleFNoYWRlciApO1xyXG5cdFx0Y29uc3QgZnJhZ21lbnRTaGFkZXJTdGFnZSA9IHRoaXMuX2dldFNoYWRlclN0YWdlKCBmcmFnbWVudFNoYWRlciApO1xyXG5cclxuXHRcdGNvbnN0IG1hdGVyaWFsU2hhZGVycyA9IHRoaXMuX2dldFNoYWRlckNhY2hlRm9yTWF0ZXJpYWwoIG1hdGVyaWFsICk7XHJcblxyXG5cdFx0aWYgKCBtYXRlcmlhbFNoYWRlcnMuaGFzKCB2ZXJ0ZXhTaGFkZXJTdGFnZSApID09PSBmYWxzZSApIHtcclxuXHJcblx0XHRcdG1hdGVyaWFsU2hhZGVycy5hZGQoIHZlcnRleFNoYWRlclN0YWdlICk7XHJcblx0XHRcdHZlcnRleFNoYWRlclN0YWdlLnVzZWRUaW1lcyArKztcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBtYXRlcmlhbFNoYWRlcnMuaGFzKCBmcmFnbWVudFNoYWRlclN0YWdlICkgPT09IGZhbHNlICkge1xyXG5cclxuXHRcdFx0bWF0ZXJpYWxTaGFkZXJzLmFkZCggZnJhZ21lbnRTaGFkZXJTdGFnZSApO1xyXG5cdFx0XHRmcmFnbWVudFNoYWRlclN0YWdlLnVzZWRUaW1lcyArKztcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0cmVtb3ZlKCBtYXRlcmlhbCApIHtcclxuXHJcblx0XHRjb25zdCBtYXRlcmlhbFNoYWRlcnMgPSB0aGlzLm1hdGVyaWFsQ2FjaGUuZ2V0KCBtYXRlcmlhbCApO1xyXG5cclxuXHRcdGZvciAoIGNvbnN0IHNoYWRlclN0YWdlIG9mIG1hdGVyaWFsU2hhZGVycyApIHtcclxuXHJcblx0XHRcdHNoYWRlclN0YWdlLnVzZWRUaW1lcyAtLTtcclxuXHJcblx0XHRcdGlmICggc2hhZGVyU3RhZ2UudXNlZFRpbWVzID09PSAwICkgdGhpcy5zaGFkZXJDYWNoZS5kZWxldGUoIHNoYWRlclN0YWdlLmNvZGUgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5tYXRlcmlhbENhY2hlLmRlbGV0ZSggbWF0ZXJpYWwgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRnZXRWZXJ0ZXhTaGFkZXJJRCggbWF0ZXJpYWwgKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuX2dldFNoYWRlclN0YWdlKCBtYXRlcmlhbC52ZXJ0ZXhTaGFkZXIgKS5pZDtcclxuXHJcblx0fVxyXG5cclxuXHRnZXRGcmFnbWVudFNoYWRlcklEKCBtYXRlcmlhbCApIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5fZ2V0U2hhZGVyU3RhZ2UoIG1hdGVyaWFsLmZyYWdtZW50U2hhZGVyICkuaWQ7XHJcblxyXG5cdH1cclxuXHJcblx0ZGlzcG9zZSgpIHtcclxuXHJcblx0XHR0aGlzLnNoYWRlckNhY2hlLmNsZWFyKCk7XHJcblx0XHR0aGlzLm1hdGVyaWFsQ2FjaGUuY2xlYXIoKTtcclxuXHJcblx0fVxyXG5cclxuXHRfZ2V0U2hhZGVyQ2FjaGVGb3JNYXRlcmlhbCggbWF0ZXJpYWwgKSB7XHJcblxyXG5cdFx0Y29uc3QgY2FjaGUgPSB0aGlzLm1hdGVyaWFsQ2FjaGU7XHJcblx0XHRsZXQgc2V0ID0gY2FjaGUuZ2V0KCBtYXRlcmlhbCApO1xyXG5cclxuXHRcdGlmICggc2V0ID09PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRzZXQgPSBuZXcgU2V0KCk7XHJcblx0XHRcdGNhY2hlLnNldCggbWF0ZXJpYWwsIHNldCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gc2V0O1xyXG5cclxuXHR9XHJcblxyXG5cdF9nZXRTaGFkZXJTdGFnZSggY29kZSApIHtcclxuXHJcblx0XHRjb25zdCBjYWNoZSA9IHRoaXMuc2hhZGVyQ2FjaGU7XHJcblx0XHRsZXQgc3RhZ2UgPSBjYWNoZS5nZXQoIGNvZGUgKTtcclxuXHJcblx0XHRpZiAoIHN0YWdlID09PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRzdGFnZSA9IG5ldyBXZWJHTFNoYWRlclN0YWdlKCBjb2RlICk7XHJcblx0XHRcdGNhY2hlLnNldCggY29kZSwgc3RhZ2UgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHN0YWdlO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5jbGFzcyBXZWJHTFNoYWRlclN0YWdlIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIGNvZGUgKSB7XHJcblxyXG5cdFx0dGhpcy5pZCA9IF9pZCArKztcclxuXHJcblx0XHR0aGlzLmNvZGUgPSBjb2RlO1xyXG5cdFx0dGhpcy51c2VkVGltZXMgPSAwO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBXZWJHTFNoYWRlckNhY2hlIH07XHJcbiIsImltcG9ydCB7IEJhY2tTaWRlLCBEb3VibGVTaWRlLCBDdWJlVVZSZWZsZWN0aW9uTWFwcGluZywgT2JqZWN0U3BhY2VOb3JtYWxNYXAsIFRhbmdlbnRTcGFjZU5vcm1hbE1hcCwgTm9Ub25lTWFwcGluZywgTm9ybWFsQmxlbmRpbmcsIExpbmVhclNSR0JDb2xvclNwYWNlLCBTUkdCVHJhbnNmZXIgfSBmcm9tICcuLi8uLi9jb25zdGFudHMuanMnO1xyXG5pbXBvcnQgeyBMYXllcnMgfSBmcm9tICcuLi8uLi9jb3JlL0xheWVycy5qcyc7XHJcbmltcG9ydCB7IFdlYkdMUHJvZ3JhbSB9IGZyb20gJy4vV2ViR0xQcm9ncmFtLmpzJztcclxuaW1wb3J0IHsgV2ViR0xTaGFkZXJDYWNoZSB9IGZyb20gJy4vV2ViR0xTaGFkZXJDYWNoZS5qcyc7XHJcbmltcG9ydCB7IFNoYWRlckxpYiB9IGZyb20gJy4uL3NoYWRlcnMvU2hhZGVyTGliLmpzJztcclxuaW1wb3J0IHsgVW5pZm9ybXNVdGlscyB9IGZyb20gJy4uL3NoYWRlcnMvVW5pZm9ybXNVdGlscy5qcyc7XHJcbmltcG9ydCB7IENvbG9yTWFuYWdlbWVudCB9IGZyb20gJy4uLy4uL21hdGgvQ29sb3JNYW5hZ2VtZW50LmpzJztcclxuXHJcbmZ1bmN0aW9uIFdlYkdMUHJvZ3JhbXMoIHJlbmRlcmVyLCBjdWJlbWFwcywgY3ViZXV2bWFwcywgZXh0ZW5zaW9ucywgY2FwYWJpbGl0aWVzLCBiaW5kaW5nU3RhdGVzLCBjbGlwcGluZyApIHtcclxuXHJcblx0Y29uc3QgX3Byb2dyYW1MYXllcnMgPSBuZXcgTGF5ZXJzKCk7XHJcblx0Y29uc3QgX2N1c3RvbVNoYWRlcnMgPSBuZXcgV2ViR0xTaGFkZXJDYWNoZSgpO1xyXG5cdGNvbnN0IF9hY3RpdmVDaGFubmVscyA9IG5ldyBTZXQoKTtcclxuXHRjb25zdCBwcm9ncmFtcyA9IFtdO1xyXG5cclxuXHRjb25zdCBJU19XRUJHTDIgPSBjYXBhYmlsaXRpZXMuaXNXZWJHTDI7XHJcblx0Y29uc3QgbG9nYXJpdGhtaWNEZXB0aEJ1ZmZlciA9IGNhcGFiaWxpdGllcy5sb2dhcml0aG1pY0RlcHRoQnVmZmVyO1xyXG5cdGNvbnN0IFNVUFBPUlRTX1ZFUlRFWF9URVhUVVJFUyA9IGNhcGFiaWxpdGllcy52ZXJ0ZXhUZXh0dXJlcztcclxuXHJcblx0bGV0IHByZWNpc2lvbiA9IGNhcGFiaWxpdGllcy5wcmVjaXNpb247XHJcblxyXG5cdGNvbnN0IHNoYWRlcklEcyA9IHtcclxuXHRcdE1lc2hEZXB0aE1hdGVyaWFsOiAnZGVwdGgnLFxyXG5cdFx0TWVzaERpc3RhbmNlTWF0ZXJpYWw6ICdkaXN0YW5jZVJHQkEnLFxyXG5cdFx0TWVzaE5vcm1hbE1hdGVyaWFsOiAnbm9ybWFsJyxcclxuXHRcdE1lc2hCYXNpY01hdGVyaWFsOiAnYmFzaWMnLFxyXG5cdFx0TWVzaExhbWJlcnRNYXRlcmlhbDogJ2xhbWJlcnQnLFxyXG5cdFx0TWVzaFBob25nTWF0ZXJpYWw6ICdwaG9uZycsXHJcblx0XHRNZXNoVG9vbk1hdGVyaWFsOiAndG9vbicsXHJcblx0XHRNZXNoU3RhbmRhcmRNYXRlcmlhbDogJ3BoeXNpY2FsJyxcclxuXHRcdE1lc2hQaHlzaWNhbE1hdGVyaWFsOiAncGh5c2ljYWwnLFxyXG5cdFx0TWVzaE1hdGNhcE1hdGVyaWFsOiAnbWF0Y2FwJyxcclxuXHRcdExpbmVCYXNpY01hdGVyaWFsOiAnYmFzaWMnLFxyXG5cdFx0TGluZURhc2hlZE1hdGVyaWFsOiAnZGFzaGVkJyxcclxuXHRcdFBvaW50c01hdGVyaWFsOiAncG9pbnRzJyxcclxuXHRcdFNoYWRvd01hdGVyaWFsOiAnc2hhZG93JyxcclxuXHRcdFNwcml0ZU1hdGVyaWFsOiAnc3ByaXRlJ1xyXG5cdH07XHJcblxyXG5cdGZ1bmN0aW9uIGdldENoYW5uZWwoIHZhbHVlICkge1xyXG5cclxuXHRcdF9hY3RpdmVDaGFubmVscy5hZGQoIHZhbHVlICk7XHJcblxyXG5cdFx0aWYgKCB2YWx1ZSA9PT0gMCApIHJldHVybiAndXYnO1xyXG5cclxuXHRcdHJldHVybiBgdXYkeyB2YWx1ZSB9YDtcclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBnZXRQYXJhbWV0ZXJzKCBtYXRlcmlhbCwgbGlnaHRzLCBzaGFkb3dzLCBzY2VuZSwgb2JqZWN0ICkge1xyXG5cclxuXHRcdGNvbnN0IGZvZyA9IHNjZW5lLmZvZztcclxuXHRcdGNvbnN0IGdlb21ldHJ5ID0gb2JqZWN0Lmdlb21ldHJ5O1xyXG5cdFx0Y29uc3QgZW52aXJvbm1lbnQgPSBtYXRlcmlhbC5pc01lc2hTdGFuZGFyZE1hdGVyaWFsID8gc2NlbmUuZW52aXJvbm1lbnQgOiBudWxsO1xyXG5cclxuXHRcdGNvbnN0IGVudk1hcCA9ICggbWF0ZXJpYWwuaXNNZXNoU3RhbmRhcmRNYXRlcmlhbCA/IGN1YmV1dm1hcHMgOiBjdWJlbWFwcyApLmdldCggbWF0ZXJpYWwuZW52TWFwIHx8IGVudmlyb25tZW50ICk7XHJcblx0XHRjb25zdCBlbnZNYXBDdWJlVVZIZWlnaHQgPSAoICEhIGVudk1hcCApICYmICggZW52TWFwLm1hcHBpbmcgPT09IEN1YmVVVlJlZmxlY3Rpb25NYXBwaW5nICkgPyBlbnZNYXAuaW1hZ2UuaGVpZ2h0IDogbnVsbDtcclxuXHJcblx0XHRjb25zdCBzaGFkZXJJRCA9IHNoYWRlcklEc1sgbWF0ZXJpYWwudHlwZSBdO1xyXG5cclxuXHRcdC8vIGhldXJpc3RpY3MgdG8gY3JlYXRlIHNoYWRlciBwYXJhbWV0ZXJzIGFjY29yZGluZyB0byBsaWdodHMgaW4gdGhlIHNjZW5lXHJcblx0XHQvLyAobm90IHRvIGJsb3cgb3ZlciBtYXhMaWdodHMgYnVkZ2V0KVxyXG5cclxuXHRcdGlmICggbWF0ZXJpYWwucHJlY2lzaW9uICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0cHJlY2lzaW9uID0gY2FwYWJpbGl0aWVzLmdldE1heFByZWNpc2lvbiggbWF0ZXJpYWwucHJlY2lzaW9uICk7XHJcblxyXG5cdFx0XHRpZiAoIHByZWNpc2lvbiAhPT0gbWF0ZXJpYWwucHJlY2lzaW9uICkge1xyXG5cclxuXHRcdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5XZWJHTFByb2dyYW0uZ2V0UGFyYW1ldGVyczonLCBtYXRlcmlhbC5wcmVjaXNpb24sICdub3Qgc3VwcG9ydGVkLCB1c2luZycsIHByZWNpc2lvbiwgJ2luc3RlYWQuJyApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvL1xyXG5cclxuXHRcdGNvbnN0IG1vcnBoQXR0cmlidXRlID0gZ2VvbWV0cnkubW9ycGhBdHRyaWJ1dGVzLnBvc2l0aW9uIHx8IGdlb21ldHJ5Lm1vcnBoQXR0cmlidXRlcy5ub3JtYWwgfHwgZ2VvbWV0cnkubW9ycGhBdHRyaWJ1dGVzLmNvbG9yO1xyXG5cdFx0Y29uc3QgbW9ycGhUYXJnZXRzQ291bnQgPSAoIG1vcnBoQXR0cmlidXRlICE9PSB1bmRlZmluZWQgKSA/IG1vcnBoQXR0cmlidXRlLmxlbmd0aCA6IDA7XHJcblxyXG5cdFx0bGV0IG1vcnBoVGV4dHVyZVN0cmlkZSA9IDA7XHJcblxyXG5cdFx0aWYgKCBnZW9tZXRyeS5tb3JwaEF0dHJpYnV0ZXMucG9zaXRpb24gIT09IHVuZGVmaW5lZCApIG1vcnBoVGV4dHVyZVN0cmlkZSA9IDE7XHJcblx0XHRpZiAoIGdlb21ldHJ5Lm1vcnBoQXR0cmlidXRlcy5ub3JtYWwgIT09IHVuZGVmaW5lZCApIG1vcnBoVGV4dHVyZVN0cmlkZSA9IDI7XHJcblx0XHRpZiAoIGdlb21ldHJ5Lm1vcnBoQXR0cmlidXRlcy5jb2xvciAhPT0gdW5kZWZpbmVkICkgbW9ycGhUZXh0dXJlU3RyaWRlID0gMztcclxuXHJcblx0XHQvL1xyXG5cclxuXHRcdGxldCB2ZXJ0ZXhTaGFkZXIsIGZyYWdtZW50U2hhZGVyO1xyXG5cdFx0bGV0IGN1c3RvbVZlcnRleFNoYWRlcklELCBjdXN0b21GcmFnbWVudFNoYWRlcklEO1xyXG5cclxuXHRcdGlmICggc2hhZGVySUQgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBzaGFkZXIgPSBTaGFkZXJMaWJbIHNoYWRlcklEIF07XHJcblxyXG5cdFx0XHR2ZXJ0ZXhTaGFkZXIgPSBzaGFkZXIudmVydGV4U2hhZGVyO1xyXG5cdFx0XHRmcmFnbWVudFNoYWRlciA9IHNoYWRlci5mcmFnbWVudFNoYWRlcjtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0dmVydGV4U2hhZGVyID0gbWF0ZXJpYWwudmVydGV4U2hhZGVyO1xyXG5cdFx0XHRmcmFnbWVudFNoYWRlciA9IG1hdGVyaWFsLmZyYWdtZW50U2hhZGVyO1xyXG5cclxuXHRcdFx0X2N1c3RvbVNoYWRlcnMudXBkYXRlKCBtYXRlcmlhbCApO1xyXG5cclxuXHRcdFx0Y3VzdG9tVmVydGV4U2hhZGVySUQgPSBfY3VzdG9tU2hhZGVycy5nZXRWZXJ0ZXhTaGFkZXJJRCggbWF0ZXJpYWwgKTtcclxuXHRcdFx0Y3VzdG9tRnJhZ21lbnRTaGFkZXJJRCA9IF9jdXN0b21TaGFkZXJzLmdldEZyYWdtZW50U2hhZGVySUQoIG1hdGVyaWFsICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGNvbnN0IGN1cnJlbnRSZW5kZXJUYXJnZXQgPSByZW5kZXJlci5nZXRSZW5kZXJUYXJnZXQoKTtcclxuXHJcblx0XHRjb25zdCBJU19JTlNUQU5DRURNRVNIID0gb2JqZWN0LmlzSW5zdGFuY2VkTWVzaCA9PT0gdHJ1ZTtcclxuXHRcdGNvbnN0IElTX0JBVENIRURNRVNIID0gb2JqZWN0LmlzQmF0Y2hlZE1lc2ggPT09IHRydWU7XHJcblxyXG5cdFx0Y29uc3QgSEFTX01BUCA9ICEhIG1hdGVyaWFsLm1hcDtcclxuXHRcdGNvbnN0IEhBU19NQVRDQVAgPSAhISBtYXRlcmlhbC5tYXRjYXA7XHJcblx0XHRjb25zdCBIQVNfRU5WTUFQID0gISEgZW52TWFwO1xyXG5cdFx0Y29uc3QgSEFTX0FPTUFQID0gISEgbWF0ZXJpYWwuYW9NYXA7XHJcblx0XHRjb25zdCBIQVNfTElHSFRNQVAgPSAhISBtYXRlcmlhbC5saWdodE1hcDtcclxuXHRcdGNvbnN0IEhBU19CVU1QTUFQID0gISEgbWF0ZXJpYWwuYnVtcE1hcDtcclxuXHRcdGNvbnN0IEhBU19OT1JNQUxNQVAgPSAhISBtYXRlcmlhbC5ub3JtYWxNYXA7XHJcblx0XHRjb25zdCBIQVNfRElTUExBQ0VNRU5UTUFQID0gISEgbWF0ZXJpYWwuZGlzcGxhY2VtZW50TWFwO1xyXG5cdFx0Y29uc3QgSEFTX0VNSVNTSVZFTUFQID0gISEgbWF0ZXJpYWwuZW1pc3NpdmVNYXA7XHJcblxyXG5cdFx0Y29uc3QgSEFTX01FVEFMTkVTU01BUCA9ICEhIG1hdGVyaWFsLm1ldGFsbmVzc01hcDtcclxuXHRcdGNvbnN0IEhBU19ST1VHSE5FU1NNQVAgPSAhISBtYXRlcmlhbC5yb3VnaG5lc3NNYXA7XHJcblxyXG5cdFx0Y29uc3QgSEFTX0FOSVNPVFJPUFkgPSBtYXRlcmlhbC5hbmlzb3Ryb3B5ID4gMDtcclxuXHRcdGNvbnN0IEhBU19DTEVBUkNPQVQgPSBtYXRlcmlhbC5jbGVhcmNvYXQgPiAwO1xyXG5cdFx0Y29uc3QgSEFTX0lSSURFU0NFTkNFID0gbWF0ZXJpYWwuaXJpZGVzY2VuY2UgPiAwO1xyXG5cdFx0Y29uc3QgSEFTX1NIRUVOID0gbWF0ZXJpYWwuc2hlZW4gPiAwO1xyXG5cdFx0Y29uc3QgSEFTX1RSQU5TTUlTU0lPTiA9IG1hdGVyaWFsLnRyYW5zbWlzc2lvbiA+IDA7XHJcblxyXG5cdFx0Y29uc3QgSEFTX0FOSVNPVFJPUFlNQVAgPSBIQVNfQU5JU09UUk9QWSAmJiAhISBtYXRlcmlhbC5hbmlzb3Ryb3B5TWFwO1xyXG5cclxuXHRcdGNvbnN0IEhBU19DTEVBUkNPQVRNQVAgPSBIQVNfQ0xFQVJDT0FUICYmICEhIG1hdGVyaWFsLmNsZWFyY29hdE1hcDtcclxuXHRcdGNvbnN0IEhBU19DTEVBUkNPQVRfTk9STUFMTUFQID0gSEFTX0NMRUFSQ09BVCAmJiAhISBtYXRlcmlhbC5jbGVhcmNvYXROb3JtYWxNYXA7XHJcblx0XHRjb25zdCBIQVNfQ0xFQVJDT0FUX1JPVUdITkVTU01BUCA9IEhBU19DTEVBUkNPQVQgJiYgISEgbWF0ZXJpYWwuY2xlYXJjb2F0Um91Z2huZXNzTWFwO1xyXG5cclxuXHRcdGNvbnN0IEhBU19JUklERVNDRU5DRU1BUCA9IEhBU19JUklERVNDRU5DRSAmJiAhISBtYXRlcmlhbC5pcmlkZXNjZW5jZU1hcDtcclxuXHRcdGNvbnN0IEhBU19JUklERVNDRU5DRV9USElDS05FU1NNQVAgPSBIQVNfSVJJREVTQ0VOQ0UgJiYgISEgbWF0ZXJpYWwuaXJpZGVzY2VuY2VUaGlja25lc3NNYXA7XHJcblxyXG5cdFx0Y29uc3QgSEFTX1NIRUVOX0NPTE9STUFQID0gSEFTX1NIRUVOICYmICEhIG1hdGVyaWFsLnNoZWVuQ29sb3JNYXA7XHJcblx0XHRjb25zdCBIQVNfU0hFRU5fUk9VR0hORVNTTUFQID0gSEFTX1NIRUVOICYmICEhIG1hdGVyaWFsLnNoZWVuUm91Z2huZXNzTWFwO1xyXG5cclxuXHRcdGNvbnN0IEhBU19TUEVDVUxBUk1BUCA9ICEhIG1hdGVyaWFsLnNwZWN1bGFyTWFwO1xyXG5cdFx0Y29uc3QgSEFTX1NQRUNVTEFSX0NPTE9STUFQID0gISEgbWF0ZXJpYWwuc3BlY3VsYXJDb2xvck1hcDtcclxuXHRcdGNvbnN0IEhBU19TUEVDVUxBUl9JTlRFTlNJVFlNQVAgPSAhISBtYXRlcmlhbC5zcGVjdWxhckludGVuc2l0eU1hcDtcclxuXHJcblx0XHRjb25zdCBIQVNfVFJBTlNNSVNTSU9OTUFQID0gSEFTX1RSQU5TTUlTU0lPTiAmJiAhISBtYXRlcmlhbC50cmFuc21pc3Npb25NYXA7XHJcblx0XHRjb25zdCBIQVNfVEhJQ0tORVNTTUFQID0gSEFTX1RSQU5TTUlTU0lPTiAmJiAhISBtYXRlcmlhbC50aGlja25lc3NNYXA7XHJcblxyXG5cdFx0Y29uc3QgSEFTX0dSQURJRU5UTUFQID0gISEgbWF0ZXJpYWwuZ3JhZGllbnRNYXA7XHJcblxyXG5cdFx0Y29uc3QgSEFTX0FMUEhBTUFQID0gISEgbWF0ZXJpYWwuYWxwaGFNYXA7XHJcblxyXG5cdFx0Y29uc3QgSEFTX0FMUEhBVEVTVCA9IG1hdGVyaWFsLmFscGhhVGVzdCA+IDA7XHJcblxyXG5cdFx0Y29uc3QgSEFTX0FMUEhBSEFTSCA9ICEhIG1hdGVyaWFsLmFscGhhSGFzaDtcclxuXHJcblx0XHRjb25zdCBIQVNfRVhURU5TSU9OUyA9ICEhIG1hdGVyaWFsLmV4dGVuc2lvbnM7XHJcblxyXG5cdFx0bGV0IHRvbmVNYXBwaW5nID0gTm9Ub25lTWFwcGluZztcclxuXHJcblx0XHRpZiAoIG1hdGVyaWFsLnRvbmVNYXBwZWQgKSB7XHJcblxyXG5cdFx0XHRpZiAoIGN1cnJlbnRSZW5kZXJUYXJnZXQgPT09IG51bGwgfHwgY3VycmVudFJlbmRlclRhcmdldC5pc1hSUmVuZGVyVGFyZ2V0ID09PSB0cnVlICkge1xyXG5cclxuXHRcdFx0XHR0b25lTWFwcGluZyA9IHJlbmRlcmVyLnRvbmVNYXBwaW5nO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCBwYXJhbWV0ZXJzID0ge1xyXG5cclxuXHRcdFx0aXNXZWJHTDI6IElTX1dFQkdMMixcclxuXHJcblx0XHRcdHNoYWRlcklEOiBzaGFkZXJJRCxcclxuXHRcdFx0c2hhZGVyVHlwZTogbWF0ZXJpYWwudHlwZSxcclxuXHRcdFx0c2hhZGVyTmFtZTogbWF0ZXJpYWwubmFtZSxcclxuXHJcblx0XHRcdHZlcnRleFNoYWRlcjogdmVydGV4U2hhZGVyLFxyXG5cdFx0XHRmcmFnbWVudFNoYWRlcjogZnJhZ21lbnRTaGFkZXIsXHJcblx0XHRcdGRlZmluZXM6IG1hdGVyaWFsLmRlZmluZXMsXHJcblxyXG5cdFx0XHRjdXN0b21WZXJ0ZXhTaGFkZXJJRDogY3VzdG9tVmVydGV4U2hhZGVySUQsXHJcblx0XHRcdGN1c3RvbUZyYWdtZW50U2hhZGVySUQ6IGN1c3RvbUZyYWdtZW50U2hhZGVySUQsXHJcblxyXG5cdFx0XHRpc1Jhd1NoYWRlck1hdGVyaWFsOiBtYXRlcmlhbC5pc1Jhd1NoYWRlck1hdGVyaWFsID09PSB0cnVlLFxyXG5cdFx0XHRnbHNsVmVyc2lvbjogbWF0ZXJpYWwuZ2xzbFZlcnNpb24sXHJcblxyXG5cdFx0XHRwcmVjaXNpb246IHByZWNpc2lvbixcclxuXHJcblx0XHRcdGJhdGNoaW5nOiBJU19CQVRDSEVETUVTSCxcclxuXHRcdFx0aW5zdGFuY2luZzogSVNfSU5TVEFOQ0VETUVTSCxcclxuXHRcdFx0aW5zdGFuY2luZ0NvbG9yOiBJU19JTlNUQU5DRURNRVNIICYmIG9iamVjdC5pbnN0YW5jZUNvbG9yICE9PSBudWxsLFxyXG5cclxuXHRcdFx0c3VwcG9ydHNWZXJ0ZXhUZXh0dXJlczogU1VQUE9SVFNfVkVSVEVYX1RFWFRVUkVTLFxyXG5cdFx0XHRvdXRwdXRDb2xvclNwYWNlOiAoIGN1cnJlbnRSZW5kZXJUYXJnZXQgPT09IG51bGwgKSA/IHJlbmRlcmVyLm91dHB1dENvbG9yU3BhY2UgOiAoIGN1cnJlbnRSZW5kZXJUYXJnZXQuaXNYUlJlbmRlclRhcmdldCA9PT0gdHJ1ZSA/IGN1cnJlbnRSZW5kZXJUYXJnZXQudGV4dHVyZS5jb2xvclNwYWNlIDogTGluZWFyU1JHQkNvbG9yU3BhY2UgKSxcclxuXHRcdFx0YWxwaGFUb0NvdmVyYWdlOiAhISBtYXRlcmlhbC5hbHBoYVRvQ292ZXJhZ2UsXHJcblxyXG5cdFx0XHRtYXA6IEhBU19NQVAsXHJcblx0XHRcdG1hdGNhcDogSEFTX01BVENBUCxcclxuXHRcdFx0ZW52TWFwOiBIQVNfRU5WTUFQLFxyXG5cdFx0XHRlbnZNYXBNb2RlOiBIQVNfRU5WTUFQICYmIGVudk1hcC5tYXBwaW5nLFxyXG5cdFx0XHRlbnZNYXBDdWJlVVZIZWlnaHQ6IGVudk1hcEN1YmVVVkhlaWdodCxcclxuXHRcdFx0YW9NYXA6IEhBU19BT01BUCxcclxuXHRcdFx0bGlnaHRNYXA6IEhBU19MSUdIVE1BUCxcclxuXHRcdFx0YnVtcE1hcDogSEFTX0JVTVBNQVAsXHJcblx0XHRcdG5vcm1hbE1hcDogSEFTX05PUk1BTE1BUCxcclxuXHRcdFx0ZGlzcGxhY2VtZW50TWFwOiBTVVBQT1JUU19WRVJURVhfVEVYVFVSRVMgJiYgSEFTX0RJU1BMQUNFTUVOVE1BUCxcclxuXHRcdFx0ZW1pc3NpdmVNYXA6IEhBU19FTUlTU0lWRU1BUCxcclxuXHJcblx0XHRcdG5vcm1hbE1hcE9iamVjdFNwYWNlOiBIQVNfTk9STUFMTUFQICYmIG1hdGVyaWFsLm5vcm1hbE1hcFR5cGUgPT09IE9iamVjdFNwYWNlTm9ybWFsTWFwLFxyXG5cdFx0XHRub3JtYWxNYXBUYW5nZW50U3BhY2U6IEhBU19OT1JNQUxNQVAgJiYgbWF0ZXJpYWwubm9ybWFsTWFwVHlwZSA9PT0gVGFuZ2VudFNwYWNlTm9ybWFsTWFwLFxyXG5cclxuXHRcdFx0bWV0YWxuZXNzTWFwOiBIQVNfTUVUQUxORVNTTUFQLFxyXG5cdFx0XHRyb3VnaG5lc3NNYXA6IEhBU19ST1VHSE5FU1NNQVAsXHJcblxyXG5cdFx0XHRhbmlzb3Ryb3B5OiBIQVNfQU5JU09UUk9QWSxcclxuXHRcdFx0YW5pc290cm9weU1hcDogSEFTX0FOSVNPVFJPUFlNQVAsXHJcblxyXG5cdFx0XHRjbGVhcmNvYXQ6IEhBU19DTEVBUkNPQVQsXHJcblx0XHRcdGNsZWFyY29hdE1hcDogSEFTX0NMRUFSQ09BVE1BUCxcclxuXHRcdFx0Y2xlYXJjb2F0Tm9ybWFsTWFwOiBIQVNfQ0xFQVJDT0FUX05PUk1BTE1BUCxcclxuXHRcdFx0Y2xlYXJjb2F0Um91Z2huZXNzTWFwOiBIQVNfQ0xFQVJDT0FUX1JPVUdITkVTU01BUCxcclxuXHJcblx0XHRcdGlyaWRlc2NlbmNlOiBIQVNfSVJJREVTQ0VOQ0UsXHJcblx0XHRcdGlyaWRlc2NlbmNlTWFwOiBIQVNfSVJJREVTQ0VOQ0VNQVAsXHJcblx0XHRcdGlyaWRlc2NlbmNlVGhpY2tuZXNzTWFwOiBIQVNfSVJJREVTQ0VOQ0VfVEhJQ0tORVNTTUFQLFxyXG5cclxuXHRcdFx0c2hlZW46IEhBU19TSEVFTixcclxuXHRcdFx0c2hlZW5Db2xvck1hcDogSEFTX1NIRUVOX0NPTE9STUFQLFxyXG5cdFx0XHRzaGVlblJvdWdobmVzc01hcDogSEFTX1NIRUVOX1JPVUdITkVTU01BUCxcclxuXHJcblx0XHRcdHNwZWN1bGFyTWFwOiBIQVNfU1BFQ1VMQVJNQVAsXHJcblx0XHRcdHNwZWN1bGFyQ29sb3JNYXA6IEhBU19TUEVDVUxBUl9DT0xPUk1BUCxcclxuXHRcdFx0c3BlY3VsYXJJbnRlbnNpdHlNYXA6IEhBU19TUEVDVUxBUl9JTlRFTlNJVFlNQVAsXHJcblxyXG5cdFx0XHR0cmFuc21pc3Npb246IEhBU19UUkFOU01JU1NJT04sXHJcblx0XHRcdHRyYW5zbWlzc2lvbk1hcDogSEFTX1RSQU5TTUlTU0lPTk1BUCxcclxuXHRcdFx0dGhpY2tuZXNzTWFwOiBIQVNfVEhJQ0tORVNTTUFQLFxyXG5cclxuXHRcdFx0Z3JhZGllbnRNYXA6IEhBU19HUkFESUVOVE1BUCxcclxuXHJcblx0XHRcdG9wYXF1ZTogbWF0ZXJpYWwudHJhbnNwYXJlbnQgPT09IGZhbHNlICYmIG1hdGVyaWFsLmJsZW5kaW5nID09PSBOb3JtYWxCbGVuZGluZyAmJiBtYXRlcmlhbC5hbHBoYVRvQ292ZXJhZ2UgPT09IGZhbHNlLFxyXG5cclxuXHRcdFx0YWxwaGFNYXA6IEhBU19BTFBIQU1BUCxcclxuXHRcdFx0YWxwaGFUZXN0OiBIQVNfQUxQSEFURVNULFxyXG5cdFx0XHRhbHBoYUhhc2g6IEhBU19BTFBIQUhBU0gsXHJcblxyXG5cdFx0XHRjb21iaW5lOiBtYXRlcmlhbC5jb21iaW5lLFxyXG5cclxuXHRcdFx0Ly9cclxuXHJcblx0XHRcdG1hcFV2OiBIQVNfTUFQICYmIGdldENoYW5uZWwoIG1hdGVyaWFsLm1hcC5jaGFubmVsICksXHJcblx0XHRcdGFvTWFwVXY6IEhBU19BT01BUCAmJiBnZXRDaGFubmVsKCBtYXRlcmlhbC5hb01hcC5jaGFubmVsICksXHJcblx0XHRcdGxpZ2h0TWFwVXY6IEhBU19MSUdIVE1BUCAmJiBnZXRDaGFubmVsKCBtYXRlcmlhbC5saWdodE1hcC5jaGFubmVsICksXHJcblx0XHRcdGJ1bXBNYXBVdjogSEFTX0JVTVBNQVAgJiYgZ2V0Q2hhbm5lbCggbWF0ZXJpYWwuYnVtcE1hcC5jaGFubmVsICksXHJcblx0XHRcdG5vcm1hbE1hcFV2OiBIQVNfTk9STUFMTUFQICYmIGdldENoYW5uZWwoIG1hdGVyaWFsLm5vcm1hbE1hcC5jaGFubmVsICksXHJcblx0XHRcdGRpc3BsYWNlbWVudE1hcFV2OiBIQVNfRElTUExBQ0VNRU5UTUFQICYmIGdldENoYW5uZWwoIG1hdGVyaWFsLmRpc3BsYWNlbWVudE1hcC5jaGFubmVsICksXHJcblx0XHRcdGVtaXNzaXZlTWFwVXY6IEhBU19FTUlTU0lWRU1BUCAmJiBnZXRDaGFubmVsKCBtYXRlcmlhbC5lbWlzc2l2ZU1hcC5jaGFubmVsICksXHJcblxyXG5cdFx0XHRtZXRhbG5lc3NNYXBVdjogSEFTX01FVEFMTkVTU01BUCAmJiBnZXRDaGFubmVsKCBtYXRlcmlhbC5tZXRhbG5lc3NNYXAuY2hhbm5lbCApLFxyXG5cdFx0XHRyb3VnaG5lc3NNYXBVdjogSEFTX1JPVUdITkVTU01BUCAmJiBnZXRDaGFubmVsKCBtYXRlcmlhbC5yb3VnaG5lc3NNYXAuY2hhbm5lbCApLFxyXG5cclxuXHRcdFx0YW5pc290cm9weU1hcFV2OiBIQVNfQU5JU09UUk9QWU1BUCAmJiBnZXRDaGFubmVsKCBtYXRlcmlhbC5hbmlzb3Ryb3B5TWFwLmNoYW5uZWwgKSxcclxuXHJcblx0XHRcdGNsZWFyY29hdE1hcFV2OiBIQVNfQ0xFQVJDT0FUTUFQICYmIGdldENoYW5uZWwoIG1hdGVyaWFsLmNsZWFyY29hdE1hcC5jaGFubmVsICksXHJcblx0XHRcdGNsZWFyY29hdE5vcm1hbE1hcFV2OiBIQVNfQ0xFQVJDT0FUX05PUk1BTE1BUCAmJiBnZXRDaGFubmVsKCBtYXRlcmlhbC5jbGVhcmNvYXROb3JtYWxNYXAuY2hhbm5lbCApLFxyXG5cdFx0XHRjbGVhcmNvYXRSb3VnaG5lc3NNYXBVdjogSEFTX0NMRUFSQ09BVF9ST1VHSE5FU1NNQVAgJiYgZ2V0Q2hhbm5lbCggbWF0ZXJpYWwuY2xlYXJjb2F0Um91Z2huZXNzTWFwLmNoYW5uZWwgKSxcclxuXHJcblx0XHRcdGlyaWRlc2NlbmNlTWFwVXY6IEhBU19JUklERVNDRU5DRU1BUCAmJiBnZXRDaGFubmVsKCBtYXRlcmlhbC5pcmlkZXNjZW5jZU1hcC5jaGFubmVsICksXHJcblx0XHRcdGlyaWRlc2NlbmNlVGhpY2tuZXNzTWFwVXY6IEhBU19JUklERVNDRU5DRV9USElDS05FU1NNQVAgJiYgZ2V0Q2hhbm5lbCggbWF0ZXJpYWwuaXJpZGVzY2VuY2VUaGlja25lc3NNYXAuY2hhbm5lbCApLFxyXG5cclxuXHRcdFx0c2hlZW5Db2xvck1hcFV2OiBIQVNfU0hFRU5fQ09MT1JNQVAgJiYgZ2V0Q2hhbm5lbCggbWF0ZXJpYWwuc2hlZW5Db2xvck1hcC5jaGFubmVsICksXHJcblx0XHRcdHNoZWVuUm91Z2huZXNzTWFwVXY6IEhBU19TSEVFTl9ST1VHSE5FU1NNQVAgJiYgZ2V0Q2hhbm5lbCggbWF0ZXJpYWwuc2hlZW5Sb3VnaG5lc3NNYXAuY2hhbm5lbCApLFxyXG5cclxuXHRcdFx0c3BlY3VsYXJNYXBVdjogSEFTX1NQRUNVTEFSTUFQICYmIGdldENoYW5uZWwoIG1hdGVyaWFsLnNwZWN1bGFyTWFwLmNoYW5uZWwgKSxcclxuXHRcdFx0c3BlY3VsYXJDb2xvck1hcFV2OiBIQVNfU1BFQ1VMQVJfQ09MT1JNQVAgJiYgZ2V0Q2hhbm5lbCggbWF0ZXJpYWwuc3BlY3VsYXJDb2xvck1hcC5jaGFubmVsICksXHJcblx0XHRcdHNwZWN1bGFySW50ZW5zaXR5TWFwVXY6IEhBU19TUEVDVUxBUl9JTlRFTlNJVFlNQVAgJiYgZ2V0Q2hhbm5lbCggbWF0ZXJpYWwuc3BlY3VsYXJJbnRlbnNpdHlNYXAuY2hhbm5lbCApLFxyXG5cclxuXHRcdFx0dHJhbnNtaXNzaW9uTWFwVXY6IEhBU19UUkFOU01JU1NJT05NQVAgJiYgZ2V0Q2hhbm5lbCggbWF0ZXJpYWwudHJhbnNtaXNzaW9uTWFwLmNoYW5uZWwgKSxcclxuXHRcdFx0dGhpY2tuZXNzTWFwVXY6IEhBU19USElDS05FU1NNQVAgJiYgZ2V0Q2hhbm5lbCggbWF0ZXJpYWwudGhpY2tuZXNzTWFwLmNoYW5uZWwgKSxcclxuXHJcblx0XHRcdGFscGhhTWFwVXY6IEhBU19BTFBIQU1BUCAmJiBnZXRDaGFubmVsKCBtYXRlcmlhbC5hbHBoYU1hcC5jaGFubmVsICksXHJcblxyXG5cdFx0XHQvL1xyXG5cclxuXHRcdFx0dmVydGV4VGFuZ2VudHM6ICEhIGdlb21ldHJ5LmF0dHJpYnV0ZXMudGFuZ2VudCAmJiAoIEhBU19OT1JNQUxNQVAgfHwgSEFTX0FOSVNPVFJPUFkgKSxcclxuXHRcdFx0dmVydGV4Q29sb3JzOiBtYXRlcmlhbC52ZXJ0ZXhDb2xvcnMsXHJcblx0XHRcdHZlcnRleEFscGhhczogbWF0ZXJpYWwudmVydGV4Q29sb3JzID09PSB0cnVlICYmICEhIGdlb21ldHJ5LmF0dHJpYnV0ZXMuY29sb3IgJiYgZ2VvbWV0cnkuYXR0cmlidXRlcy5jb2xvci5pdGVtU2l6ZSA9PT0gNCxcclxuXHJcblx0XHRcdHBvaW50c1V2czogb2JqZWN0LmlzUG9pbnRzID09PSB0cnVlICYmICEhIGdlb21ldHJ5LmF0dHJpYnV0ZXMudXYgJiYgKCBIQVNfTUFQIHx8IEhBU19BTFBIQU1BUCApLFxyXG5cclxuXHRcdFx0Zm9nOiAhISBmb2csXHJcblx0XHRcdHVzZUZvZzogbWF0ZXJpYWwuZm9nID09PSB0cnVlLFxyXG5cdFx0XHRmb2dFeHAyOiAoICEhIGZvZyAmJiBmb2cuaXNGb2dFeHAyICksXHJcblxyXG5cdFx0XHRmbGF0U2hhZGluZzogbWF0ZXJpYWwuZmxhdFNoYWRpbmcgPT09IHRydWUsXHJcblxyXG5cdFx0XHRzaXplQXR0ZW51YXRpb246IG1hdGVyaWFsLnNpemVBdHRlbnVhdGlvbiA9PT0gdHJ1ZSxcclxuXHRcdFx0bG9nYXJpdGhtaWNEZXB0aEJ1ZmZlcjogbG9nYXJpdGhtaWNEZXB0aEJ1ZmZlcixcclxuXHJcblx0XHRcdHNraW5uaW5nOiBvYmplY3QuaXNTa2lubmVkTWVzaCA9PT0gdHJ1ZSxcclxuXHJcblx0XHRcdG1vcnBoVGFyZ2V0czogZ2VvbWV0cnkubW9ycGhBdHRyaWJ1dGVzLnBvc2l0aW9uICE9PSB1bmRlZmluZWQsXHJcblx0XHRcdG1vcnBoTm9ybWFsczogZ2VvbWV0cnkubW9ycGhBdHRyaWJ1dGVzLm5vcm1hbCAhPT0gdW5kZWZpbmVkLFxyXG5cdFx0XHRtb3JwaENvbG9yczogZ2VvbWV0cnkubW9ycGhBdHRyaWJ1dGVzLmNvbG9yICE9PSB1bmRlZmluZWQsXHJcblx0XHRcdG1vcnBoVGFyZ2V0c0NvdW50OiBtb3JwaFRhcmdldHNDb3VudCxcclxuXHRcdFx0bW9ycGhUZXh0dXJlU3RyaWRlOiBtb3JwaFRleHR1cmVTdHJpZGUsXHJcblxyXG5cdFx0XHRudW1EaXJMaWdodHM6IGxpZ2h0cy5kaXJlY3Rpb25hbC5sZW5ndGgsXHJcblx0XHRcdG51bVBvaW50TGlnaHRzOiBsaWdodHMucG9pbnQubGVuZ3RoLFxyXG5cdFx0XHRudW1TcG90TGlnaHRzOiBsaWdodHMuc3BvdC5sZW5ndGgsXHJcblx0XHRcdG51bVNwb3RMaWdodE1hcHM6IGxpZ2h0cy5zcG90TGlnaHRNYXAubGVuZ3RoLFxyXG5cdFx0XHRudW1SZWN0QXJlYUxpZ2h0czogbGlnaHRzLnJlY3RBcmVhLmxlbmd0aCxcclxuXHRcdFx0bnVtSGVtaUxpZ2h0czogbGlnaHRzLmhlbWkubGVuZ3RoLFxyXG5cclxuXHRcdFx0bnVtRGlyTGlnaHRTaGFkb3dzOiBsaWdodHMuZGlyZWN0aW9uYWxTaGFkb3dNYXAubGVuZ3RoLFxyXG5cdFx0XHRudW1Qb2ludExpZ2h0U2hhZG93czogbGlnaHRzLnBvaW50U2hhZG93TWFwLmxlbmd0aCxcclxuXHRcdFx0bnVtU3BvdExpZ2h0U2hhZG93czogbGlnaHRzLnNwb3RTaGFkb3dNYXAubGVuZ3RoLFxyXG5cdFx0XHRudW1TcG90TGlnaHRTaGFkb3dzV2l0aE1hcHM6IGxpZ2h0cy5udW1TcG90TGlnaHRTaGFkb3dzV2l0aE1hcHMsXHJcblxyXG5cdFx0XHRudW1MaWdodFByb2JlczogbGlnaHRzLm51bUxpZ2h0UHJvYmVzLFxyXG5cclxuXHRcdFx0bnVtQ2xpcHBpbmdQbGFuZXM6IGNsaXBwaW5nLm51bVBsYW5lcyxcclxuXHRcdFx0bnVtQ2xpcEludGVyc2VjdGlvbjogY2xpcHBpbmcubnVtSW50ZXJzZWN0aW9uLFxyXG5cclxuXHRcdFx0ZGl0aGVyaW5nOiBtYXRlcmlhbC5kaXRoZXJpbmcsXHJcblxyXG5cdFx0XHRzaGFkb3dNYXBFbmFibGVkOiByZW5kZXJlci5zaGFkb3dNYXAuZW5hYmxlZCAmJiBzaGFkb3dzLmxlbmd0aCA+IDAsXHJcblx0XHRcdHNoYWRvd01hcFR5cGU6IHJlbmRlcmVyLnNoYWRvd01hcC50eXBlLFxyXG5cclxuXHRcdFx0dG9uZU1hcHBpbmc6IHRvbmVNYXBwaW5nLFxyXG5cdFx0XHR1c2VMZWdhY3lMaWdodHM6IHJlbmRlcmVyLl91c2VMZWdhY3lMaWdodHMsXHJcblxyXG5cdFx0XHRkZWNvZGVWaWRlb1RleHR1cmU6IEhBU19NQVAgJiYgKCBtYXRlcmlhbC5tYXAuaXNWaWRlb1RleHR1cmUgPT09IHRydWUgKSAmJiAoIENvbG9yTWFuYWdlbWVudC5nZXRUcmFuc2ZlciggbWF0ZXJpYWwubWFwLmNvbG9yU3BhY2UgKSA9PT0gU1JHQlRyYW5zZmVyICksXHJcblxyXG5cdFx0XHRwcmVtdWx0aXBsaWVkQWxwaGE6IG1hdGVyaWFsLnByZW11bHRpcGxpZWRBbHBoYSxcclxuXHJcblx0XHRcdGRvdWJsZVNpZGVkOiBtYXRlcmlhbC5zaWRlID09PSBEb3VibGVTaWRlLFxyXG5cdFx0XHRmbGlwU2lkZWQ6IG1hdGVyaWFsLnNpZGUgPT09IEJhY2tTaWRlLFxyXG5cclxuXHRcdFx0dXNlRGVwdGhQYWNraW5nOiBtYXRlcmlhbC5kZXB0aFBhY2tpbmcgPj0gMCxcclxuXHRcdFx0ZGVwdGhQYWNraW5nOiBtYXRlcmlhbC5kZXB0aFBhY2tpbmcgfHwgMCxcclxuXHJcblx0XHRcdGluZGV4MEF0dHJpYnV0ZU5hbWU6IG1hdGVyaWFsLmluZGV4MEF0dHJpYnV0ZU5hbWUsXHJcblxyXG5cdFx0XHRleHRlbnNpb25EZXJpdmF0aXZlczogSEFTX0VYVEVOU0lPTlMgJiYgbWF0ZXJpYWwuZXh0ZW5zaW9ucy5kZXJpdmF0aXZlcyA9PT0gdHJ1ZSxcclxuXHRcdFx0ZXh0ZW5zaW9uRnJhZ0RlcHRoOiBIQVNfRVhURU5TSU9OUyAmJiBtYXRlcmlhbC5leHRlbnNpb25zLmZyYWdEZXB0aCA9PT0gdHJ1ZSxcclxuXHRcdFx0ZXh0ZW5zaW9uRHJhd0J1ZmZlcnM6IEhBU19FWFRFTlNJT05TICYmIG1hdGVyaWFsLmV4dGVuc2lvbnMuZHJhd0J1ZmZlcnMgPT09IHRydWUsXHJcblx0XHRcdGV4dGVuc2lvblNoYWRlclRleHR1cmVMT0Q6IEhBU19FWFRFTlNJT05TICYmIG1hdGVyaWFsLmV4dGVuc2lvbnMuc2hhZGVyVGV4dHVyZUxPRCA9PT0gdHJ1ZSxcclxuXHRcdFx0ZXh0ZW5zaW9uQ2xpcEN1bGxEaXN0YW5jZTogSEFTX0VYVEVOU0lPTlMgJiYgbWF0ZXJpYWwuZXh0ZW5zaW9ucy5jbGlwQ3VsbERpc3RhbmNlID09PSB0cnVlICYmIGV4dGVuc2lvbnMuaGFzKCAnV0VCR0xfY2xpcF9jdWxsX2Rpc3RhbmNlJyApLFxyXG5cdFx0XHRleHRlbnNpb25NdWx0aURyYXc6IEhBU19FWFRFTlNJT05TICYmIG1hdGVyaWFsLmV4dGVuc2lvbnMubXVsdGlEcmF3ID09PSB0cnVlICYmIGV4dGVuc2lvbnMuaGFzKCAnV0VCR0xfbXVsdGlfZHJhdycgKSxcclxuXHJcblx0XHRcdHJlbmRlcmVyRXh0ZW5zaW9uRnJhZ0RlcHRoOiBJU19XRUJHTDIgfHwgZXh0ZW5zaW9ucy5oYXMoICdFWFRfZnJhZ19kZXB0aCcgKSxcclxuXHRcdFx0cmVuZGVyZXJFeHRlbnNpb25EcmF3QnVmZmVyczogSVNfV0VCR0wyIHx8IGV4dGVuc2lvbnMuaGFzKCAnV0VCR0xfZHJhd19idWZmZXJzJyApLFxyXG5cdFx0XHRyZW5kZXJlckV4dGVuc2lvblNoYWRlclRleHR1cmVMb2Q6IElTX1dFQkdMMiB8fCBleHRlbnNpb25zLmhhcyggJ0VYVF9zaGFkZXJfdGV4dHVyZV9sb2QnICksXHJcblx0XHRcdHJlbmRlcmVyRXh0ZW5zaW9uUGFyYWxsZWxTaGFkZXJDb21waWxlOiBleHRlbnNpb25zLmhhcyggJ0tIUl9wYXJhbGxlbF9zaGFkZXJfY29tcGlsZScgKSxcclxuXHJcblx0XHRcdGN1c3RvbVByb2dyYW1DYWNoZUtleTogbWF0ZXJpYWwuY3VzdG9tUHJvZ3JhbUNhY2hlS2V5KClcclxuXHJcblx0XHR9O1xyXG5cclxuXHRcdC8vIHRoZSB1c2FnZSBvZiBnZXRDaGFubmVsKCkgZGV0ZXJtaW5lcyB0aGUgYWN0aXZlIHRleHR1cmUgY2hhbm5lbHMgZm9yIHRoaXMgc2hhZGVyXHJcblxyXG5cdFx0cGFyYW1ldGVycy52ZXJ0ZXhVdjFzID0gX2FjdGl2ZUNoYW5uZWxzLmhhcyggMSApO1xyXG5cdFx0cGFyYW1ldGVycy52ZXJ0ZXhVdjJzID0gX2FjdGl2ZUNoYW5uZWxzLmhhcyggMiApO1xyXG5cdFx0cGFyYW1ldGVycy52ZXJ0ZXhVdjNzID0gX2FjdGl2ZUNoYW5uZWxzLmhhcyggMyApO1xyXG5cclxuXHRcdF9hY3RpdmVDaGFubmVscy5jbGVhcigpO1xyXG5cclxuXHRcdHJldHVybiBwYXJhbWV0ZXJzO1xyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIGdldFByb2dyYW1DYWNoZUtleSggcGFyYW1ldGVycyApIHtcclxuXHJcblx0XHRjb25zdCBhcnJheSA9IFtdO1xyXG5cclxuXHRcdGlmICggcGFyYW1ldGVycy5zaGFkZXJJRCApIHtcclxuXHJcblx0XHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMuc2hhZGVySUQgKTtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0YXJyYXkucHVzaCggcGFyYW1ldGVycy5jdXN0b21WZXJ0ZXhTaGFkZXJJRCApO1xyXG5cdFx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLmN1c3RvbUZyYWdtZW50U2hhZGVySUQgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBwYXJhbWV0ZXJzLmRlZmluZXMgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdGZvciAoIGNvbnN0IG5hbWUgaW4gcGFyYW1ldGVycy5kZWZpbmVzICkge1xyXG5cclxuXHRcdFx0XHRhcnJheS5wdXNoKCBuYW1lICk7XHJcblx0XHRcdFx0YXJyYXkucHVzaCggcGFyYW1ldGVycy5kZWZpbmVzWyBuYW1lIF0gKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBwYXJhbWV0ZXJzLmlzUmF3U2hhZGVyTWF0ZXJpYWwgPT09IGZhbHNlICkge1xyXG5cclxuXHRcdFx0Z2V0UHJvZ3JhbUNhY2hlS2V5UGFyYW1ldGVycyggYXJyYXksIHBhcmFtZXRlcnMgKTtcclxuXHRcdFx0Z2V0UHJvZ3JhbUNhY2hlS2V5Qm9vbGVhbnMoIGFycmF5LCBwYXJhbWV0ZXJzICk7XHJcblx0XHRcdGFycmF5LnB1c2goIHJlbmRlcmVyLm91dHB1dENvbG9yU3BhY2UgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0YXJyYXkucHVzaCggcGFyYW1ldGVycy5jdXN0b21Qcm9ncmFtQ2FjaGVLZXkgKTtcclxuXHJcblx0XHRyZXR1cm4gYXJyYXkuam9pbigpO1xyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIGdldFByb2dyYW1DYWNoZUtleVBhcmFtZXRlcnMoIGFycmF5LCBwYXJhbWV0ZXJzICkge1xyXG5cclxuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMucHJlY2lzaW9uICk7XHJcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLm91dHB1dENvbG9yU3BhY2UgKTtcclxuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMuZW52TWFwTW9kZSApO1xyXG5cdFx0YXJyYXkucHVzaCggcGFyYW1ldGVycy5lbnZNYXBDdWJlVVZIZWlnaHQgKTtcclxuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMubWFwVXYgKTtcclxuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMuYWxwaGFNYXBVdiApO1xyXG5cdFx0YXJyYXkucHVzaCggcGFyYW1ldGVycy5saWdodE1hcFV2ICk7XHJcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLmFvTWFwVXYgKTtcclxuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMuYnVtcE1hcFV2ICk7XHJcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLm5vcm1hbE1hcFV2ICk7XHJcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLmRpc3BsYWNlbWVudE1hcFV2ICk7XHJcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLmVtaXNzaXZlTWFwVXYgKTtcclxuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMubWV0YWxuZXNzTWFwVXYgKTtcclxuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMucm91Z2huZXNzTWFwVXYgKTtcclxuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMuYW5pc290cm9weU1hcFV2ICk7XHJcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLmNsZWFyY29hdE1hcFV2ICk7XHJcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLmNsZWFyY29hdE5vcm1hbE1hcFV2ICk7XHJcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLmNsZWFyY29hdFJvdWdobmVzc01hcFV2ICk7XHJcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLmlyaWRlc2NlbmNlTWFwVXYgKTtcclxuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMuaXJpZGVzY2VuY2VUaGlja25lc3NNYXBVdiApO1xyXG5cdFx0YXJyYXkucHVzaCggcGFyYW1ldGVycy5zaGVlbkNvbG9yTWFwVXYgKTtcclxuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMuc2hlZW5Sb3VnaG5lc3NNYXBVdiApO1xyXG5cdFx0YXJyYXkucHVzaCggcGFyYW1ldGVycy5zcGVjdWxhck1hcFV2ICk7XHJcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLnNwZWN1bGFyQ29sb3JNYXBVdiApO1xyXG5cdFx0YXJyYXkucHVzaCggcGFyYW1ldGVycy5zcGVjdWxhckludGVuc2l0eU1hcFV2ICk7XHJcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLnRyYW5zbWlzc2lvbk1hcFV2ICk7XHJcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLnRoaWNrbmVzc01hcFV2ICk7XHJcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLmNvbWJpbmUgKTtcclxuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMuZm9nRXhwMiApO1xyXG5cdFx0YXJyYXkucHVzaCggcGFyYW1ldGVycy5zaXplQXR0ZW51YXRpb24gKTtcclxuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMubW9ycGhUYXJnZXRzQ291bnQgKTtcclxuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMubW9ycGhBdHRyaWJ1dGVDb3VudCApO1xyXG5cdFx0YXJyYXkucHVzaCggcGFyYW1ldGVycy5udW1EaXJMaWdodHMgKTtcclxuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMubnVtUG9pbnRMaWdodHMgKTtcclxuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMubnVtU3BvdExpZ2h0cyApO1xyXG5cdFx0YXJyYXkucHVzaCggcGFyYW1ldGVycy5udW1TcG90TGlnaHRNYXBzICk7XHJcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLm51bUhlbWlMaWdodHMgKTtcclxuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMubnVtUmVjdEFyZWFMaWdodHMgKTtcclxuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMubnVtRGlyTGlnaHRTaGFkb3dzICk7XHJcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLm51bVBvaW50TGlnaHRTaGFkb3dzICk7XHJcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLm51bVNwb3RMaWdodFNoYWRvd3MgKTtcclxuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMubnVtU3BvdExpZ2h0U2hhZG93c1dpdGhNYXBzICk7XHJcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLm51bUxpZ2h0UHJvYmVzICk7XHJcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLnNoYWRvd01hcFR5cGUgKTtcclxuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMudG9uZU1hcHBpbmcgKTtcclxuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMubnVtQ2xpcHBpbmdQbGFuZXMgKTtcclxuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMubnVtQ2xpcEludGVyc2VjdGlvbiApO1xyXG5cdFx0YXJyYXkucHVzaCggcGFyYW1ldGVycy5kZXB0aFBhY2tpbmcgKTtcclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBnZXRQcm9ncmFtQ2FjaGVLZXlCb29sZWFucyggYXJyYXksIHBhcmFtZXRlcnMgKSB7XHJcblxyXG5cdFx0X3Byb2dyYW1MYXllcnMuZGlzYWJsZUFsbCgpO1xyXG5cclxuXHRcdGlmICggcGFyYW1ldGVycy5pc1dlYkdMMiApXHJcblx0XHRcdF9wcm9ncmFtTGF5ZXJzLmVuYWJsZSggMCApO1xyXG5cdFx0aWYgKCBwYXJhbWV0ZXJzLnN1cHBvcnRzVmVydGV4VGV4dHVyZXMgKVxyXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDEgKTtcclxuXHRcdGlmICggcGFyYW1ldGVycy5pbnN0YW5jaW5nIClcclxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCAyICk7XHJcblx0XHRpZiAoIHBhcmFtZXRlcnMuaW5zdGFuY2luZ0NvbG9yIClcclxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCAzICk7XHJcblx0XHRpZiAoIHBhcmFtZXRlcnMubWF0Y2FwIClcclxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCA0ICk7XHJcblx0XHRpZiAoIHBhcmFtZXRlcnMuZW52TWFwIClcclxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCA1ICk7XHJcblx0XHRpZiAoIHBhcmFtZXRlcnMubm9ybWFsTWFwT2JqZWN0U3BhY2UgKVxyXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDYgKTtcclxuXHRcdGlmICggcGFyYW1ldGVycy5ub3JtYWxNYXBUYW5nZW50U3BhY2UgKVxyXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDcgKTtcclxuXHRcdGlmICggcGFyYW1ldGVycy5jbGVhcmNvYXQgKVxyXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDggKTtcclxuXHRcdGlmICggcGFyYW1ldGVycy5pcmlkZXNjZW5jZSApXHJcblx0XHRcdF9wcm9ncmFtTGF5ZXJzLmVuYWJsZSggOSApO1xyXG5cdFx0aWYgKCBwYXJhbWV0ZXJzLmFscGhhVGVzdCApXHJcblx0XHRcdF9wcm9ncmFtTGF5ZXJzLmVuYWJsZSggMTAgKTtcclxuXHRcdGlmICggcGFyYW1ldGVycy52ZXJ0ZXhDb2xvcnMgKVxyXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDExICk7XHJcblx0XHRpZiAoIHBhcmFtZXRlcnMudmVydGV4QWxwaGFzIClcclxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCAxMiApO1xyXG5cdFx0aWYgKCBwYXJhbWV0ZXJzLnZlcnRleFV2MXMgKVxyXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDEzICk7XHJcblx0XHRpZiAoIHBhcmFtZXRlcnMudmVydGV4VXYycyApXHJcblx0XHRcdF9wcm9ncmFtTGF5ZXJzLmVuYWJsZSggMTQgKTtcclxuXHRcdGlmICggcGFyYW1ldGVycy52ZXJ0ZXhVdjNzIClcclxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCAxNSApO1xyXG5cdFx0aWYgKCBwYXJhbWV0ZXJzLnZlcnRleFRhbmdlbnRzIClcclxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCAxNiApO1xyXG5cdFx0aWYgKCBwYXJhbWV0ZXJzLmFuaXNvdHJvcHkgKVxyXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDE3ICk7XHJcblx0XHRpZiAoIHBhcmFtZXRlcnMuYWxwaGFIYXNoIClcclxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCAxOCApO1xyXG5cdFx0aWYgKCBwYXJhbWV0ZXJzLmJhdGNoaW5nIClcclxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCAxOSApO1xyXG5cclxuXHRcdGFycmF5LnB1c2goIF9wcm9ncmFtTGF5ZXJzLm1hc2sgKTtcclxuXHRcdF9wcm9ncmFtTGF5ZXJzLmRpc2FibGVBbGwoKTtcclxuXHJcblx0XHRpZiAoIHBhcmFtZXRlcnMuZm9nIClcclxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCAwICk7XHJcblx0XHRpZiAoIHBhcmFtZXRlcnMudXNlRm9nIClcclxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCAxICk7XHJcblx0XHRpZiAoIHBhcmFtZXRlcnMuZmxhdFNoYWRpbmcgKVxyXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDIgKTtcclxuXHRcdGlmICggcGFyYW1ldGVycy5sb2dhcml0aG1pY0RlcHRoQnVmZmVyIClcclxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCAzICk7XHJcblx0XHRpZiAoIHBhcmFtZXRlcnMuc2tpbm5pbmcgKVxyXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDQgKTtcclxuXHRcdGlmICggcGFyYW1ldGVycy5tb3JwaFRhcmdldHMgKVxyXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDUgKTtcclxuXHRcdGlmICggcGFyYW1ldGVycy5tb3JwaE5vcm1hbHMgKVxyXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDYgKTtcclxuXHRcdGlmICggcGFyYW1ldGVycy5tb3JwaENvbG9ycyApXHJcblx0XHRcdF9wcm9ncmFtTGF5ZXJzLmVuYWJsZSggNyApO1xyXG5cdFx0aWYgKCBwYXJhbWV0ZXJzLnByZW11bHRpcGxpZWRBbHBoYSApXHJcblx0XHRcdF9wcm9ncmFtTGF5ZXJzLmVuYWJsZSggOCApO1xyXG5cdFx0aWYgKCBwYXJhbWV0ZXJzLnNoYWRvd01hcEVuYWJsZWQgKVxyXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDkgKTtcclxuXHRcdGlmICggcGFyYW1ldGVycy51c2VMZWdhY3lMaWdodHMgKVxyXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDEwICk7XHJcblx0XHRpZiAoIHBhcmFtZXRlcnMuZG91YmxlU2lkZWQgKVxyXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDExICk7XHJcblx0XHRpZiAoIHBhcmFtZXRlcnMuZmxpcFNpZGVkIClcclxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCAxMiApO1xyXG5cdFx0aWYgKCBwYXJhbWV0ZXJzLnVzZURlcHRoUGFja2luZyApXHJcblx0XHRcdF9wcm9ncmFtTGF5ZXJzLmVuYWJsZSggMTMgKTtcclxuXHRcdGlmICggcGFyYW1ldGVycy5kaXRoZXJpbmcgKVxyXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDE0ICk7XHJcblx0XHRpZiAoIHBhcmFtZXRlcnMudHJhbnNtaXNzaW9uIClcclxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCAxNSApO1xyXG5cdFx0aWYgKCBwYXJhbWV0ZXJzLnNoZWVuIClcclxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCAxNiApO1xyXG5cdFx0aWYgKCBwYXJhbWV0ZXJzLm9wYXF1ZSApXHJcblx0XHRcdF9wcm9ncmFtTGF5ZXJzLmVuYWJsZSggMTcgKTtcclxuXHRcdGlmICggcGFyYW1ldGVycy5wb2ludHNVdnMgKVxyXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDE4ICk7XHJcblx0XHRpZiAoIHBhcmFtZXRlcnMuZGVjb2RlVmlkZW9UZXh0dXJlIClcclxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCAxOSApO1xyXG5cdFx0aWYgKCBwYXJhbWV0ZXJzLmFscGhhVG9Db3ZlcmFnZSApXHJcblx0XHRcdF9wcm9ncmFtTGF5ZXJzLmVuYWJsZSggMjAgKTtcclxuXHJcblx0XHRhcnJheS5wdXNoKCBfcHJvZ3JhbUxheWVycy5tYXNrICk7XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gZ2V0VW5pZm9ybXMoIG1hdGVyaWFsICkge1xyXG5cclxuXHRcdGNvbnN0IHNoYWRlcklEID0gc2hhZGVySURzWyBtYXRlcmlhbC50eXBlIF07XHJcblx0XHRsZXQgdW5pZm9ybXM7XHJcblxyXG5cdFx0aWYgKCBzaGFkZXJJRCApIHtcclxuXHJcblx0XHRcdGNvbnN0IHNoYWRlciA9IFNoYWRlckxpYlsgc2hhZGVySUQgXTtcclxuXHRcdFx0dW5pZm9ybXMgPSBVbmlmb3Jtc1V0aWxzLmNsb25lKCBzaGFkZXIudW5pZm9ybXMgKTtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0dW5pZm9ybXMgPSBtYXRlcmlhbC51bmlmb3JtcztcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHVuaWZvcm1zO1xyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIGFjcXVpcmVQcm9ncmFtKCBwYXJhbWV0ZXJzLCBjYWNoZUtleSApIHtcclxuXHJcblx0XHRsZXQgcHJvZ3JhbTtcclxuXHJcblx0XHQvLyBDaGVjayBpZiBjb2RlIGhhcyBiZWVuIGFscmVhZHkgY29tcGlsZWRcclxuXHRcdGZvciAoIGxldCBwID0gMCwgcGwgPSBwcm9ncmFtcy5sZW5ndGg7IHAgPCBwbDsgcCArKyApIHtcclxuXHJcblx0XHRcdGNvbnN0IHByZWV4aXN0aW5nUHJvZ3JhbSA9IHByb2dyYW1zWyBwIF07XHJcblxyXG5cdFx0XHRpZiAoIHByZWV4aXN0aW5nUHJvZ3JhbS5jYWNoZUtleSA9PT0gY2FjaGVLZXkgKSB7XHJcblxyXG5cdFx0XHRcdHByb2dyYW0gPSBwcmVleGlzdGluZ1Byb2dyYW07XHJcblx0XHRcdFx0KysgcHJvZ3JhbS51c2VkVGltZXM7XHJcblxyXG5cdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHByb2dyYW0gPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdHByb2dyYW0gPSBuZXcgV2ViR0xQcm9ncmFtKCByZW5kZXJlciwgY2FjaGVLZXksIHBhcmFtZXRlcnMsIGJpbmRpbmdTdGF0ZXMgKTtcclxuXHRcdFx0cHJvZ3JhbXMucHVzaCggcHJvZ3JhbSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gcHJvZ3JhbTtcclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiByZWxlYXNlUHJvZ3JhbSggcHJvZ3JhbSApIHtcclxuXHJcblx0XHRpZiAoIC0tIHByb2dyYW0udXNlZFRpbWVzID09PSAwICkge1xyXG5cclxuXHRcdFx0Ly8gUmVtb3ZlIGZyb20gdW5vcmRlcmVkIHNldFxyXG5cdFx0XHRjb25zdCBpID0gcHJvZ3JhbXMuaW5kZXhPZiggcHJvZ3JhbSApO1xyXG5cdFx0XHRwcm9ncmFtc1sgaSBdID0gcHJvZ3JhbXNbIHByb2dyYW1zLmxlbmd0aCAtIDEgXTtcclxuXHRcdFx0cHJvZ3JhbXMucG9wKCk7XHJcblxyXG5cdFx0XHQvLyBGcmVlIFdlYkdMIHJlc291cmNlc1xyXG5cdFx0XHRwcm9ncmFtLmRlc3Ryb3koKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gcmVsZWFzZVNoYWRlckNhY2hlKCBtYXRlcmlhbCApIHtcclxuXHJcblx0XHRfY3VzdG9tU2hhZGVycy5yZW1vdmUoIG1hdGVyaWFsICk7XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gZGlzcG9zZSgpIHtcclxuXHJcblx0XHRfY3VzdG9tU2hhZGVycy5kaXNwb3NlKCk7XHJcblxyXG5cdH1cclxuXHJcblx0cmV0dXJuIHtcclxuXHRcdGdldFBhcmFtZXRlcnM6IGdldFBhcmFtZXRlcnMsXHJcblx0XHRnZXRQcm9ncmFtQ2FjaGVLZXk6IGdldFByb2dyYW1DYWNoZUtleSxcclxuXHRcdGdldFVuaWZvcm1zOiBnZXRVbmlmb3JtcyxcclxuXHRcdGFjcXVpcmVQcm9ncmFtOiBhY3F1aXJlUHJvZ3JhbSxcclxuXHRcdHJlbGVhc2VQcm9ncmFtOiByZWxlYXNlUHJvZ3JhbSxcclxuXHRcdHJlbGVhc2VTaGFkZXJDYWNoZTogcmVsZWFzZVNoYWRlckNhY2hlLFxyXG5cdFx0Ly8gRXhwb3NlZCBmb3IgcmVzb3VyY2UgbW9uaXRvcmluZyAmIGVycm9yIGZlZWRiYWNrIHZpYSByZW5kZXJlci5pbmZvOlxyXG5cdFx0cHJvZ3JhbXM6IHByb2dyYW1zLFxyXG5cdFx0ZGlzcG9zZTogZGlzcG9zZVxyXG5cdH07XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBXZWJHTFByb2dyYW1zIH07XHJcbiIsImZ1bmN0aW9uIFdlYkdMUHJvcGVydGllcygpIHtcclxuXHJcblx0bGV0IHByb3BlcnRpZXMgPSBuZXcgV2Vha01hcCgpO1xyXG5cclxuXHRmdW5jdGlvbiBnZXQoIG9iamVjdCApIHtcclxuXHJcblx0XHRsZXQgbWFwID0gcHJvcGVydGllcy5nZXQoIG9iamVjdCApO1xyXG5cclxuXHRcdGlmICggbWFwID09PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRtYXAgPSB7fTtcclxuXHRcdFx0cHJvcGVydGllcy5zZXQoIG9iamVjdCwgbWFwICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiBtYXA7XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gcmVtb3ZlKCBvYmplY3QgKSB7XHJcblxyXG5cdFx0cHJvcGVydGllcy5kZWxldGUoIG9iamVjdCApO1xyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHVwZGF0ZSggb2JqZWN0LCBrZXksIHZhbHVlICkge1xyXG5cclxuXHRcdHByb3BlcnRpZXMuZ2V0KCBvYmplY3QgKVsga2V5IF0gPSB2YWx1ZTtcclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBkaXNwb3NlKCkge1xyXG5cclxuXHRcdHByb3BlcnRpZXMgPSBuZXcgV2Vha01hcCgpO1xyXG5cclxuXHR9XHJcblxyXG5cdHJldHVybiB7XHJcblx0XHRnZXQ6IGdldCxcclxuXHRcdHJlbW92ZTogcmVtb3ZlLFxyXG5cdFx0dXBkYXRlOiB1cGRhdGUsXHJcblx0XHRkaXNwb3NlOiBkaXNwb3NlXHJcblx0fTtcclxuXHJcbn1cclxuXHJcblxyXG5leHBvcnQgeyBXZWJHTFByb3BlcnRpZXMgfTtcclxuIiwiZnVuY3Rpb24gcGFpbnRlclNvcnRTdGFibGUoIGEsIGIgKSB7XHJcblxyXG5cdGlmICggYS5ncm91cE9yZGVyICE9PSBiLmdyb3VwT3JkZXIgKSB7XHJcblxyXG5cdFx0cmV0dXJuIGEuZ3JvdXBPcmRlciAtIGIuZ3JvdXBPcmRlcjtcclxuXHJcblx0fSBlbHNlIGlmICggYS5yZW5kZXJPcmRlciAhPT0gYi5yZW5kZXJPcmRlciApIHtcclxuXHJcblx0XHRyZXR1cm4gYS5yZW5kZXJPcmRlciAtIGIucmVuZGVyT3JkZXI7XHJcblxyXG5cdH0gZWxzZSBpZiAoIGEubWF0ZXJpYWwuaWQgIT09IGIubWF0ZXJpYWwuaWQgKSB7XHJcblxyXG5cdFx0cmV0dXJuIGEubWF0ZXJpYWwuaWQgLSBiLm1hdGVyaWFsLmlkO1xyXG5cclxuXHR9IGVsc2UgaWYgKCBhLnogIT09IGIueiApIHtcclxuXHJcblx0XHRyZXR1cm4gYS56IC0gYi56O1xyXG5cclxuXHR9IGVsc2Uge1xyXG5cclxuXHRcdHJldHVybiBhLmlkIC0gYi5pZDtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gcmV2ZXJzZVBhaW50ZXJTb3J0U3RhYmxlKCBhLCBiICkge1xyXG5cclxuXHRpZiAoIGEuZ3JvdXBPcmRlciAhPT0gYi5ncm91cE9yZGVyICkge1xyXG5cclxuXHRcdHJldHVybiBhLmdyb3VwT3JkZXIgLSBiLmdyb3VwT3JkZXI7XHJcblxyXG5cdH0gZWxzZSBpZiAoIGEucmVuZGVyT3JkZXIgIT09IGIucmVuZGVyT3JkZXIgKSB7XHJcblxyXG5cdFx0cmV0dXJuIGEucmVuZGVyT3JkZXIgLSBiLnJlbmRlck9yZGVyO1xyXG5cclxuXHR9IGVsc2UgaWYgKCBhLnogIT09IGIueiApIHtcclxuXHJcblx0XHRyZXR1cm4gYi56IC0gYS56O1xyXG5cclxuXHR9IGVsc2Uge1xyXG5cclxuXHRcdHJldHVybiBhLmlkIC0gYi5pZDtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuXHJcbmZ1bmN0aW9uIFdlYkdMUmVuZGVyTGlzdCgpIHtcclxuXHJcblx0Y29uc3QgcmVuZGVySXRlbXMgPSBbXTtcclxuXHRsZXQgcmVuZGVySXRlbXNJbmRleCA9IDA7XHJcblxyXG5cdGNvbnN0IG9wYXF1ZSA9IFtdO1xyXG5cdGNvbnN0IHRyYW5zbWlzc2l2ZSA9IFtdO1xyXG5cdGNvbnN0IHRyYW5zcGFyZW50ID0gW107XHJcblxyXG5cdGZ1bmN0aW9uIGluaXQoKSB7XHJcblxyXG5cdFx0cmVuZGVySXRlbXNJbmRleCA9IDA7XHJcblxyXG5cdFx0b3BhcXVlLmxlbmd0aCA9IDA7XHJcblx0XHR0cmFuc21pc3NpdmUubGVuZ3RoID0gMDtcclxuXHRcdHRyYW5zcGFyZW50Lmxlbmd0aCA9IDA7XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gZ2V0TmV4dFJlbmRlckl0ZW0oIG9iamVjdCwgZ2VvbWV0cnksIG1hdGVyaWFsLCBncm91cE9yZGVyLCB6LCBncm91cCApIHtcclxuXHJcblx0XHRsZXQgcmVuZGVySXRlbSA9IHJlbmRlckl0ZW1zWyByZW5kZXJJdGVtc0luZGV4IF07XHJcblxyXG5cdFx0aWYgKCByZW5kZXJJdGVtID09PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRyZW5kZXJJdGVtID0ge1xyXG5cdFx0XHRcdGlkOiBvYmplY3QuaWQsXHJcblx0XHRcdFx0b2JqZWN0OiBvYmplY3QsXHJcblx0XHRcdFx0Z2VvbWV0cnk6IGdlb21ldHJ5LFxyXG5cdFx0XHRcdG1hdGVyaWFsOiBtYXRlcmlhbCxcclxuXHRcdFx0XHRncm91cE9yZGVyOiBncm91cE9yZGVyLFxyXG5cdFx0XHRcdHJlbmRlck9yZGVyOiBvYmplY3QucmVuZGVyT3JkZXIsXHJcblx0XHRcdFx0ejogeixcclxuXHRcdFx0XHRncm91cDogZ3JvdXBcclxuXHRcdFx0fTtcclxuXHJcblx0XHRcdHJlbmRlckl0ZW1zWyByZW5kZXJJdGVtc0luZGV4IF0gPSByZW5kZXJJdGVtO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRyZW5kZXJJdGVtLmlkID0gb2JqZWN0LmlkO1xyXG5cdFx0XHRyZW5kZXJJdGVtLm9iamVjdCA9IG9iamVjdDtcclxuXHRcdFx0cmVuZGVySXRlbS5nZW9tZXRyeSA9IGdlb21ldHJ5O1xyXG5cdFx0XHRyZW5kZXJJdGVtLm1hdGVyaWFsID0gbWF0ZXJpYWw7XHJcblx0XHRcdHJlbmRlckl0ZW0uZ3JvdXBPcmRlciA9IGdyb3VwT3JkZXI7XHJcblx0XHRcdHJlbmRlckl0ZW0ucmVuZGVyT3JkZXIgPSBvYmplY3QucmVuZGVyT3JkZXI7XHJcblx0XHRcdHJlbmRlckl0ZW0ueiA9IHo7XHJcblx0XHRcdHJlbmRlckl0ZW0uZ3JvdXAgPSBncm91cDtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmVuZGVySXRlbXNJbmRleCArKztcclxuXHJcblx0XHRyZXR1cm4gcmVuZGVySXRlbTtcclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBwdXNoKCBvYmplY3QsIGdlb21ldHJ5LCBtYXRlcmlhbCwgZ3JvdXBPcmRlciwgeiwgZ3JvdXAgKSB7XHJcblxyXG5cdFx0Y29uc3QgcmVuZGVySXRlbSA9IGdldE5leHRSZW5kZXJJdGVtKCBvYmplY3QsIGdlb21ldHJ5LCBtYXRlcmlhbCwgZ3JvdXBPcmRlciwgeiwgZ3JvdXAgKTtcclxuXHJcblx0XHRpZiAoIG1hdGVyaWFsLnRyYW5zbWlzc2lvbiA+IDAuMCApIHtcclxuXHJcblx0XHRcdHRyYW5zbWlzc2l2ZS5wdXNoKCByZW5kZXJJdGVtICk7XHJcblxyXG5cdFx0fSBlbHNlIGlmICggbWF0ZXJpYWwudHJhbnNwYXJlbnQgPT09IHRydWUgKSB7XHJcblxyXG5cdFx0XHR0cmFuc3BhcmVudC5wdXNoKCByZW5kZXJJdGVtICk7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdG9wYXF1ZS5wdXNoKCByZW5kZXJJdGVtICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHVuc2hpZnQoIG9iamVjdCwgZ2VvbWV0cnksIG1hdGVyaWFsLCBncm91cE9yZGVyLCB6LCBncm91cCApIHtcclxuXHJcblx0XHRjb25zdCByZW5kZXJJdGVtID0gZ2V0TmV4dFJlbmRlckl0ZW0oIG9iamVjdCwgZ2VvbWV0cnksIG1hdGVyaWFsLCBncm91cE9yZGVyLCB6LCBncm91cCApO1xyXG5cclxuXHRcdGlmICggbWF0ZXJpYWwudHJhbnNtaXNzaW9uID4gMC4wICkge1xyXG5cclxuXHRcdFx0dHJhbnNtaXNzaXZlLnVuc2hpZnQoIHJlbmRlckl0ZW0gKTtcclxuXHJcblx0XHR9IGVsc2UgaWYgKCBtYXRlcmlhbC50cmFuc3BhcmVudCA9PT0gdHJ1ZSApIHtcclxuXHJcblx0XHRcdHRyYW5zcGFyZW50LnVuc2hpZnQoIHJlbmRlckl0ZW0gKTtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0b3BhcXVlLnVuc2hpZnQoIHJlbmRlckl0ZW0gKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gc29ydCggY3VzdG9tT3BhcXVlU29ydCwgY3VzdG9tVHJhbnNwYXJlbnRTb3J0ICkge1xyXG5cclxuXHRcdGlmICggb3BhcXVlLmxlbmd0aCA+IDEgKSBvcGFxdWUuc29ydCggY3VzdG9tT3BhcXVlU29ydCB8fCBwYWludGVyU29ydFN0YWJsZSApO1xyXG5cdFx0aWYgKCB0cmFuc21pc3NpdmUubGVuZ3RoID4gMSApIHRyYW5zbWlzc2l2ZS5zb3J0KCBjdXN0b21UcmFuc3BhcmVudFNvcnQgfHwgcmV2ZXJzZVBhaW50ZXJTb3J0U3RhYmxlICk7XHJcblx0XHRpZiAoIHRyYW5zcGFyZW50Lmxlbmd0aCA+IDEgKSB0cmFuc3BhcmVudC5zb3J0KCBjdXN0b21UcmFuc3BhcmVudFNvcnQgfHwgcmV2ZXJzZVBhaW50ZXJTb3J0U3RhYmxlICk7XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gZmluaXNoKCkge1xyXG5cclxuXHRcdC8vIENsZWFyIHJlZmVyZW5jZXMgZnJvbSBpbmFjdGl2ZSByZW5kZXJJdGVtcyBpbiB0aGUgbGlzdFxyXG5cclxuXHRcdGZvciAoIGxldCBpID0gcmVuZGVySXRlbXNJbmRleCwgaWwgPSByZW5kZXJJdGVtcy5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcclxuXHJcblx0XHRcdGNvbnN0IHJlbmRlckl0ZW0gPSByZW5kZXJJdGVtc1sgaSBdO1xyXG5cclxuXHRcdFx0aWYgKCByZW5kZXJJdGVtLmlkID09PSBudWxsICkgYnJlYWs7XHJcblxyXG5cdFx0XHRyZW5kZXJJdGVtLmlkID0gbnVsbDtcclxuXHRcdFx0cmVuZGVySXRlbS5vYmplY3QgPSBudWxsO1xyXG5cdFx0XHRyZW5kZXJJdGVtLmdlb21ldHJ5ID0gbnVsbDtcclxuXHRcdFx0cmVuZGVySXRlbS5tYXRlcmlhbCA9IG51bGw7XHJcblx0XHRcdHJlbmRlckl0ZW0uZ3JvdXAgPSBudWxsO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4ge1xyXG5cclxuXHRcdG9wYXF1ZTogb3BhcXVlLFxyXG5cdFx0dHJhbnNtaXNzaXZlOiB0cmFuc21pc3NpdmUsXHJcblx0XHR0cmFuc3BhcmVudDogdHJhbnNwYXJlbnQsXHJcblxyXG5cdFx0aW5pdDogaW5pdCxcclxuXHRcdHB1c2g6IHB1c2gsXHJcblx0XHR1bnNoaWZ0OiB1bnNoaWZ0LFxyXG5cdFx0ZmluaXNoOiBmaW5pc2gsXHJcblxyXG5cdFx0c29ydDogc29ydFxyXG5cdH07XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiBXZWJHTFJlbmRlckxpc3RzKCkge1xyXG5cclxuXHRsZXQgbGlzdHMgPSBuZXcgV2Vha01hcCgpO1xyXG5cclxuXHRmdW5jdGlvbiBnZXQoIHNjZW5lLCByZW5kZXJDYWxsRGVwdGggKSB7XHJcblxyXG5cdFx0Y29uc3QgbGlzdEFycmF5ID0gbGlzdHMuZ2V0KCBzY2VuZSApO1xyXG5cdFx0bGV0IGxpc3Q7XHJcblxyXG5cdFx0aWYgKCBsaXN0QXJyYXkgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdGxpc3QgPSBuZXcgV2ViR0xSZW5kZXJMaXN0KCk7XHJcblx0XHRcdGxpc3RzLnNldCggc2NlbmUsIFsgbGlzdCBdICk7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdGlmICggcmVuZGVyQ2FsbERlcHRoID49IGxpc3RBcnJheS5sZW5ndGggKSB7XHJcblxyXG5cdFx0XHRcdGxpc3QgPSBuZXcgV2ViR0xSZW5kZXJMaXN0KCk7XHJcblx0XHRcdFx0bGlzdEFycmF5LnB1c2goIGxpc3QgKTtcclxuXHJcblx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdGxpc3QgPSBsaXN0QXJyYXlbIHJlbmRlckNhbGxEZXB0aCBdO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gbGlzdDtcclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBkaXNwb3NlKCkge1xyXG5cclxuXHRcdGxpc3RzID0gbmV3IFdlYWtNYXAoKTtcclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4ge1xyXG5cdFx0Z2V0OiBnZXQsXHJcblx0XHRkaXNwb3NlOiBkaXNwb3NlXHJcblx0fTtcclxuXHJcbn1cclxuXHJcblxyXG5leHBvcnQgeyBXZWJHTFJlbmRlckxpc3RzLCBXZWJHTFJlbmRlckxpc3QgfTtcclxuIiwiaW1wb3J0IHsgQ29sb3IgfSBmcm9tICcuLi8uLi9tYXRoL0NvbG9yLmpzJztcclxuaW1wb3J0IHsgTWF0cml4NCB9IGZyb20gJy4uLy4uL21hdGgvTWF0cml4NC5qcyc7XHJcbmltcG9ydCB7IFZlY3RvcjIgfSBmcm9tICcuLi8uLi9tYXRoL1ZlY3RvcjIuanMnO1xyXG5pbXBvcnQgeyBWZWN0b3IzIH0gZnJvbSAnLi4vLi4vbWF0aC9WZWN0b3IzLmpzJztcclxuaW1wb3J0IHsgVW5pZm9ybXNMaWIgfSBmcm9tICcuLi9zaGFkZXJzL1VuaWZvcm1zTGliLmpzJztcclxuXHJcbmZ1bmN0aW9uIFVuaWZvcm1zQ2FjaGUoKSB7XHJcblxyXG5cdGNvbnN0IGxpZ2h0cyA9IHt9O1xyXG5cclxuXHRyZXR1cm4ge1xyXG5cclxuXHRcdGdldDogZnVuY3Rpb24gKCBsaWdodCApIHtcclxuXHJcblx0XHRcdGlmICggbGlnaHRzWyBsaWdodC5pZCBdICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRcdHJldHVybiBsaWdodHNbIGxpZ2h0LmlkIF07XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRsZXQgdW5pZm9ybXM7XHJcblxyXG5cdFx0XHRzd2l0Y2ggKCBsaWdodC50eXBlICkge1xyXG5cclxuXHRcdFx0XHRjYXNlICdEaXJlY3Rpb25hbExpZ2h0JzpcclxuXHRcdFx0XHRcdHVuaWZvcm1zID0ge1xyXG5cdFx0XHRcdFx0XHRkaXJlY3Rpb246IG5ldyBWZWN0b3IzKCksXHJcblx0XHRcdFx0XHRcdGNvbG9yOiBuZXcgQ29sb3IoKVxyXG5cdFx0XHRcdFx0fTtcclxuXHRcdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0XHRjYXNlICdTcG90TGlnaHQnOlxyXG5cdFx0XHRcdFx0dW5pZm9ybXMgPSB7XHJcblx0XHRcdFx0XHRcdHBvc2l0aW9uOiBuZXcgVmVjdG9yMygpLFxyXG5cdFx0XHRcdFx0XHRkaXJlY3Rpb246IG5ldyBWZWN0b3IzKCksXHJcblx0XHRcdFx0XHRcdGNvbG9yOiBuZXcgQ29sb3IoKSxcclxuXHRcdFx0XHRcdFx0ZGlzdGFuY2U6IDAsXHJcblx0XHRcdFx0XHRcdGNvbmVDb3M6IDAsXHJcblx0XHRcdFx0XHRcdHBlbnVtYnJhQ29zOiAwLFxyXG5cdFx0XHRcdFx0XHRkZWNheTogMFxyXG5cdFx0XHRcdFx0fTtcclxuXHRcdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0XHRjYXNlICdQb2ludExpZ2h0JzpcclxuXHRcdFx0XHRcdHVuaWZvcm1zID0ge1xyXG5cdFx0XHRcdFx0XHRwb3NpdGlvbjogbmV3IFZlY3RvcjMoKSxcclxuXHRcdFx0XHRcdFx0Y29sb3I6IG5ldyBDb2xvcigpLFxyXG5cdFx0XHRcdFx0XHRkaXN0YW5jZTogMCxcclxuXHRcdFx0XHRcdFx0ZGVjYXk6IDBcclxuXHRcdFx0XHRcdH07XHJcblx0XHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdFx0Y2FzZSAnSGVtaXNwaGVyZUxpZ2h0JzpcclxuXHRcdFx0XHRcdHVuaWZvcm1zID0ge1xyXG5cdFx0XHRcdFx0XHRkaXJlY3Rpb246IG5ldyBWZWN0b3IzKCksXHJcblx0XHRcdFx0XHRcdHNreUNvbG9yOiBuZXcgQ29sb3IoKSxcclxuXHRcdFx0XHRcdFx0Z3JvdW5kQ29sb3I6IG5ldyBDb2xvcigpXHJcblx0XHRcdFx0XHR9O1xyXG5cdFx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRcdGNhc2UgJ1JlY3RBcmVhTGlnaHQnOlxyXG5cdFx0XHRcdFx0dW5pZm9ybXMgPSB7XHJcblx0XHRcdFx0XHRcdGNvbG9yOiBuZXcgQ29sb3IoKSxcclxuXHRcdFx0XHRcdFx0cG9zaXRpb246IG5ldyBWZWN0b3IzKCksXHJcblx0XHRcdFx0XHRcdGhhbGZXaWR0aDogbmV3IFZlY3RvcjMoKSxcclxuXHRcdFx0XHRcdFx0aGFsZkhlaWdodDogbmV3IFZlY3RvcjMoKVxyXG5cdFx0XHRcdFx0fTtcclxuXHRcdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0bGlnaHRzWyBsaWdodC5pZCBdID0gdW5pZm9ybXM7XHJcblxyXG5cdFx0XHRyZXR1cm4gdW5pZm9ybXM7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9O1xyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gU2hhZG93VW5pZm9ybXNDYWNoZSgpIHtcclxuXHJcblx0Y29uc3QgbGlnaHRzID0ge307XHJcblxyXG5cdHJldHVybiB7XHJcblxyXG5cdFx0Z2V0OiBmdW5jdGlvbiAoIGxpZ2h0ICkge1xyXG5cclxuXHRcdFx0aWYgKCBsaWdodHNbIGxpZ2h0LmlkIF0gIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0cmV0dXJuIGxpZ2h0c1sgbGlnaHQuaWQgXTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGxldCB1bmlmb3JtcztcclxuXHJcblx0XHRcdHN3aXRjaCAoIGxpZ2h0LnR5cGUgKSB7XHJcblxyXG5cdFx0XHRcdGNhc2UgJ0RpcmVjdGlvbmFsTGlnaHQnOlxyXG5cdFx0XHRcdFx0dW5pZm9ybXMgPSB7XHJcblx0XHRcdFx0XHRcdHNoYWRvd0JpYXM6IDAsXHJcblx0XHRcdFx0XHRcdHNoYWRvd05vcm1hbEJpYXM6IDAsXHJcblx0XHRcdFx0XHRcdHNoYWRvd1JhZGl1czogMSxcclxuXHRcdFx0XHRcdFx0c2hhZG93TWFwU2l6ZTogbmV3IFZlY3RvcjIoKVxyXG5cdFx0XHRcdFx0fTtcclxuXHRcdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0XHRjYXNlICdTcG90TGlnaHQnOlxyXG5cdFx0XHRcdFx0dW5pZm9ybXMgPSB7XHJcblx0XHRcdFx0XHRcdHNoYWRvd0JpYXM6IDAsXHJcblx0XHRcdFx0XHRcdHNoYWRvd05vcm1hbEJpYXM6IDAsXHJcblx0XHRcdFx0XHRcdHNoYWRvd1JhZGl1czogMSxcclxuXHRcdFx0XHRcdFx0c2hhZG93TWFwU2l6ZTogbmV3IFZlY3RvcjIoKVxyXG5cdFx0XHRcdFx0fTtcclxuXHRcdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0XHRjYXNlICdQb2ludExpZ2h0JzpcclxuXHRcdFx0XHRcdHVuaWZvcm1zID0ge1xyXG5cdFx0XHRcdFx0XHRzaGFkb3dCaWFzOiAwLFxyXG5cdFx0XHRcdFx0XHRzaGFkb3dOb3JtYWxCaWFzOiAwLFxyXG5cdFx0XHRcdFx0XHRzaGFkb3dSYWRpdXM6IDEsXHJcblx0XHRcdFx0XHRcdHNoYWRvd01hcFNpemU6IG5ldyBWZWN0b3IyKCksXHJcblx0XHRcdFx0XHRcdHNoYWRvd0NhbWVyYU5lYXI6IDEsXHJcblx0XHRcdFx0XHRcdHNoYWRvd0NhbWVyYUZhcjogMTAwMFxyXG5cdFx0XHRcdFx0fTtcclxuXHRcdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0XHQvLyBUT0RPIChhYmVsbmF0aW9uKTogc2V0IFJlY3RBcmVhTGlnaHQgc2hhZG93IHVuaWZvcm1zXHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRsaWdodHNbIGxpZ2h0LmlkIF0gPSB1bmlmb3JtcztcclxuXHJcblx0XHRcdHJldHVybiB1bmlmb3JtcztcclxuXHJcblx0XHR9XHJcblxyXG5cdH07XHJcblxyXG59XHJcblxyXG5cclxuXHJcbmxldCBuZXh0VmVyc2lvbiA9IDA7XHJcblxyXG5mdW5jdGlvbiBzaGFkb3dDYXN0aW5nQW5kVGV4dHVyaW5nTGlnaHRzRmlyc3QoIGxpZ2h0QSwgbGlnaHRCICkge1xyXG5cclxuXHRyZXR1cm4gKCBsaWdodEIuY2FzdFNoYWRvdyA/IDIgOiAwICkgLSAoIGxpZ2h0QS5jYXN0U2hhZG93ID8gMiA6IDAgKSArICggbGlnaHRCLm1hcCA/IDEgOiAwICkgLSAoIGxpZ2h0QS5tYXAgPyAxIDogMCApO1xyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gV2ViR0xMaWdodHMoIGV4dGVuc2lvbnMsIGNhcGFiaWxpdGllcyApIHtcclxuXHJcblx0Y29uc3QgY2FjaGUgPSBuZXcgVW5pZm9ybXNDYWNoZSgpO1xyXG5cclxuXHRjb25zdCBzaGFkb3dDYWNoZSA9IFNoYWRvd1VuaWZvcm1zQ2FjaGUoKTtcclxuXHJcblx0Y29uc3Qgc3RhdGUgPSB7XHJcblxyXG5cdFx0dmVyc2lvbjogMCxcclxuXHJcblx0XHRoYXNoOiB7XHJcblx0XHRcdGRpcmVjdGlvbmFsTGVuZ3RoOiAtIDEsXHJcblx0XHRcdHBvaW50TGVuZ3RoOiAtIDEsXHJcblx0XHRcdHNwb3RMZW5ndGg6IC0gMSxcclxuXHRcdFx0cmVjdEFyZWFMZW5ndGg6IC0gMSxcclxuXHRcdFx0aGVtaUxlbmd0aDogLSAxLFxyXG5cclxuXHRcdFx0bnVtRGlyZWN0aW9uYWxTaGFkb3dzOiAtIDEsXHJcblx0XHRcdG51bVBvaW50U2hhZG93czogLSAxLFxyXG5cdFx0XHRudW1TcG90U2hhZG93czogLSAxLFxyXG5cdFx0XHRudW1TcG90TWFwczogLSAxLFxyXG5cclxuXHRcdFx0bnVtTGlnaHRQcm9iZXM6IC0gMVxyXG5cdFx0fSxcclxuXHJcblx0XHRhbWJpZW50OiBbIDAsIDAsIDAgXSxcclxuXHRcdHByb2JlOiBbXSxcclxuXHRcdGRpcmVjdGlvbmFsOiBbXSxcclxuXHRcdGRpcmVjdGlvbmFsU2hhZG93OiBbXSxcclxuXHRcdGRpcmVjdGlvbmFsU2hhZG93TWFwOiBbXSxcclxuXHRcdGRpcmVjdGlvbmFsU2hhZG93TWF0cml4OiBbXSxcclxuXHRcdHNwb3Q6IFtdLFxyXG5cdFx0c3BvdExpZ2h0TWFwOiBbXSxcclxuXHRcdHNwb3RTaGFkb3c6IFtdLFxyXG5cdFx0c3BvdFNoYWRvd01hcDogW10sXHJcblx0XHRzcG90TGlnaHRNYXRyaXg6IFtdLFxyXG5cdFx0cmVjdEFyZWE6IFtdLFxyXG5cdFx0cmVjdEFyZWFMVEMxOiBudWxsLFxyXG5cdFx0cmVjdEFyZWFMVEMyOiBudWxsLFxyXG5cdFx0cG9pbnQ6IFtdLFxyXG5cdFx0cG9pbnRTaGFkb3c6IFtdLFxyXG5cdFx0cG9pbnRTaGFkb3dNYXA6IFtdLFxyXG5cdFx0cG9pbnRTaGFkb3dNYXRyaXg6IFtdLFxyXG5cdFx0aGVtaTogW10sXHJcblx0XHRudW1TcG90TGlnaHRTaGFkb3dzV2l0aE1hcHM6IDAsXHJcblx0XHRudW1MaWdodFByb2JlczogMFxyXG5cclxuXHR9O1xyXG5cclxuXHRmb3IgKCBsZXQgaSA9IDA7IGkgPCA5OyBpICsrICkgc3RhdGUucHJvYmUucHVzaCggbmV3IFZlY3RvcjMoKSApO1xyXG5cclxuXHRjb25zdCB2ZWN0b3IzID0gbmV3IFZlY3RvcjMoKTtcclxuXHRjb25zdCBtYXRyaXg0ID0gbmV3IE1hdHJpeDQoKTtcclxuXHRjb25zdCBtYXRyaXg0MiA9IG5ldyBNYXRyaXg0KCk7XHJcblxyXG5cdGZ1bmN0aW9uIHNldHVwKCBsaWdodHMsIHVzZUxlZ2FjeUxpZ2h0cyApIHtcclxuXHJcblx0XHRsZXQgciA9IDAsIGcgPSAwLCBiID0gMDtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCA5OyBpICsrICkgc3RhdGUucHJvYmVbIGkgXS5zZXQoIDAsIDAsIDAgKTtcclxuXHJcblx0XHRsZXQgZGlyZWN0aW9uYWxMZW5ndGggPSAwO1xyXG5cdFx0bGV0IHBvaW50TGVuZ3RoID0gMDtcclxuXHRcdGxldCBzcG90TGVuZ3RoID0gMDtcclxuXHRcdGxldCByZWN0QXJlYUxlbmd0aCA9IDA7XHJcblx0XHRsZXQgaGVtaUxlbmd0aCA9IDA7XHJcblxyXG5cdFx0bGV0IG51bURpcmVjdGlvbmFsU2hhZG93cyA9IDA7XHJcblx0XHRsZXQgbnVtUG9pbnRTaGFkb3dzID0gMDtcclxuXHRcdGxldCBudW1TcG90U2hhZG93cyA9IDA7XHJcblx0XHRsZXQgbnVtU3BvdE1hcHMgPSAwO1xyXG5cdFx0bGV0IG51bVNwb3RTaGFkb3dzV2l0aE1hcHMgPSAwO1xyXG5cclxuXHRcdGxldCBudW1MaWdodFByb2JlcyA9IDA7XHJcblxyXG5cdFx0Ly8gb3JkZXJpbmcgOiBbc2hhZG93IGNhc3RpbmcgKyBtYXAgdGV4dHVyaW5nLCBtYXAgdGV4dHVyaW5nLCBzaGFkb3cgY2FzdGluZywgbm9uZSBdXHJcblx0XHRsaWdodHMuc29ydCggc2hhZG93Q2FzdGluZ0FuZFRleHR1cmluZ0xpZ2h0c0ZpcnN0ICk7XHJcblxyXG5cdFx0Ly8gYXJ0aXN0LWZyaWVuZGx5IGxpZ2h0IGludGVuc2l0eSBzY2FsaW5nIGZhY3RvclxyXG5cdFx0Y29uc3Qgc2NhbGVGYWN0b3IgPSAoIHVzZUxlZ2FjeUxpZ2h0cyA9PT0gdHJ1ZSApID8gTWF0aC5QSSA6IDE7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gbGlnaHRzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBsaWdodCA9IGxpZ2h0c1sgaSBdO1xyXG5cclxuXHRcdFx0Y29uc3QgY29sb3IgPSBsaWdodC5jb2xvcjtcclxuXHRcdFx0Y29uc3QgaW50ZW5zaXR5ID0gbGlnaHQuaW50ZW5zaXR5O1xyXG5cdFx0XHRjb25zdCBkaXN0YW5jZSA9IGxpZ2h0LmRpc3RhbmNlO1xyXG5cclxuXHRcdFx0Y29uc3Qgc2hhZG93TWFwID0gKCBsaWdodC5zaGFkb3cgJiYgbGlnaHQuc2hhZG93Lm1hcCApID8gbGlnaHQuc2hhZG93Lm1hcC50ZXh0dXJlIDogbnVsbDtcclxuXHJcblx0XHRcdGlmICggbGlnaHQuaXNBbWJpZW50TGlnaHQgKSB7XHJcblxyXG5cdFx0XHRcdHIgKz0gY29sb3IuciAqIGludGVuc2l0eSAqIHNjYWxlRmFjdG9yO1xyXG5cdFx0XHRcdGcgKz0gY29sb3IuZyAqIGludGVuc2l0eSAqIHNjYWxlRmFjdG9yO1xyXG5cdFx0XHRcdGIgKz0gY29sb3IuYiAqIGludGVuc2l0eSAqIHNjYWxlRmFjdG9yO1xyXG5cclxuXHRcdFx0fSBlbHNlIGlmICggbGlnaHQuaXNMaWdodFByb2JlICkge1xyXG5cclxuXHRcdFx0XHRmb3IgKCBsZXQgaiA9IDA7IGogPCA5OyBqICsrICkge1xyXG5cclxuXHRcdFx0XHRcdHN0YXRlLnByb2JlWyBqIF0uYWRkU2NhbGVkVmVjdG9yKCBsaWdodC5zaC5jb2VmZmljaWVudHNbIGogXSwgaW50ZW5zaXR5ICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0bnVtTGlnaHRQcm9iZXMgKys7XHJcblxyXG5cdFx0XHR9IGVsc2UgaWYgKCBsaWdodC5pc0RpcmVjdGlvbmFsTGlnaHQgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IHVuaWZvcm1zID0gY2FjaGUuZ2V0KCBsaWdodCApO1xyXG5cclxuXHRcdFx0XHR1bmlmb3Jtcy5jb2xvci5jb3B5KCBsaWdodC5jb2xvciApLm11bHRpcGx5U2NhbGFyKCBsaWdodC5pbnRlbnNpdHkgKiBzY2FsZUZhY3RvciApO1xyXG5cclxuXHRcdFx0XHRpZiAoIGxpZ2h0LmNhc3RTaGFkb3cgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y29uc3Qgc2hhZG93ID0gbGlnaHQuc2hhZG93O1xyXG5cclxuXHRcdFx0XHRcdGNvbnN0IHNoYWRvd1VuaWZvcm1zID0gc2hhZG93Q2FjaGUuZ2V0KCBsaWdodCApO1xyXG5cclxuXHRcdFx0XHRcdHNoYWRvd1VuaWZvcm1zLnNoYWRvd0JpYXMgPSBzaGFkb3cuYmlhcztcclxuXHRcdFx0XHRcdHNoYWRvd1VuaWZvcm1zLnNoYWRvd05vcm1hbEJpYXMgPSBzaGFkb3cubm9ybWFsQmlhcztcclxuXHRcdFx0XHRcdHNoYWRvd1VuaWZvcm1zLnNoYWRvd1JhZGl1cyA9IHNoYWRvdy5yYWRpdXM7XHJcblx0XHRcdFx0XHRzaGFkb3dVbmlmb3Jtcy5zaGFkb3dNYXBTaXplID0gc2hhZG93Lm1hcFNpemU7XHJcblxyXG5cdFx0XHRcdFx0c3RhdGUuZGlyZWN0aW9uYWxTaGFkb3dbIGRpcmVjdGlvbmFsTGVuZ3RoIF0gPSBzaGFkb3dVbmlmb3JtcztcclxuXHRcdFx0XHRcdHN0YXRlLmRpcmVjdGlvbmFsU2hhZG93TWFwWyBkaXJlY3Rpb25hbExlbmd0aCBdID0gc2hhZG93TWFwO1xyXG5cdFx0XHRcdFx0c3RhdGUuZGlyZWN0aW9uYWxTaGFkb3dNYXRyaXhbIGRpcmVjdGlvbmFsTGVuZ3RoIF0gPSBsaWdodC5zaGFkb3cubWF0cml4O1xyXG5cclxuXHRcdFx0XHRcdG51bURpcmVjdGlvbmFsU2hhZG93cyArKztcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRzdGF0ZS5kaXJlY3Rpb25hbFsgZGlyZWN0aW9uYWxMZW5ndGggXSA9IHVuaWZvcm1zO1xyXG5cclxuXHRcdFx0XHRkaXJlY3Rpb25hbExlbmd0aCArKztcclxuXHJcblx0XHRcdH0gZWxzZSBpZiAoIGxpZ2h0LmlzU3BvdExpZ2h0ICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCB1bmlmb3JtcyA9IGNhY2hlLmdldCggbGlnaHQgKTtcclxuXHJcblx0XHRcdFx0dW5pZm9ybXMucG9zaXRpb24uc2V0RnJvbU1hdHJpeFBvc2l0aW9uKCBsaWdodC5tYXRyaXhXb3JsZCApO1xyXG5cclxuXHRcdFx0XHR1bmlmb3Jtcy5jb2xvci5jb3B5KCBjb2xvciApLm11bHRpcGx5U2NhbGFyKCBpbnRlbnNpdHkgKiBzY2FsZUZhY3RvciApO1xyXG5cdFx0XHRcdHVuaWZvcm1zLmRpc3RhbmNlID0gZGlzdGFuY2U7XHJcblxyXG5cdFx0XHRcdHVuaWZvcm1zLmNvbmVDb3MgPSBNYXRoLmNvcyggbGlnaHQuYW5nbGUgKTtcclxuXHRcdFx0XHR1bmlmb3Jtcy5wZW51bWJyYUNvcyA9IE1hdGguY29zKCBsaWdodC5hbmdsZSAqICggMSAtIGxpZ2h0LnBlbnVtYnJhICkgKTtcclxuXHRcdFx0XHR1bmlmb3Jtcy5kZWNheSA9IGxpZ2h0LmRlY2F5O1xyXG5cclxuXHRcdFx0XHRzdGF0ZS5zcG90WyBzcG90TGVuZ3RoIF0gPSB1bmlmb3JtcztcclxuXHJcblx0XHRcdFx0Y29uc3Qgc2hhZG93ID0gbGlnaHQuc2hhZG93O1xyXG5cclxuXHRcdFx0XHRpZiAoIGxpZ2h0Lm1hcCApIHtcclxuXHJcblx0XHRcdFx0XHRzdGF0ZS5zcG90TGlnaHRNYXBbIG51bVNwb3RNYXBzIF0gPSBsaWdodC5tYXA7XHJcblx0XHRcdFx0XHRudW1TcG90TWFwcyArKztcclxuXHJcblx0XHRcdFx0XHQvLyBtYWtlIHN1cmUgdGhlIGxpZ2h0TWF0cml4IGlzIHVwIHRvIGRhdGVcclxuXHRcdFx0XHRcdC8vIFRPRE8gOiBkbyBpdCBpZiByZXF1aXJlZCBvbmx5XHJcblx0XHRcdFx0XHRzaGFkb3cudXBkYXRlTWF0cmljZXMoIGxpZ2h0ICk7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCBsaWdodC5jYXN0U2hhZG93ICkgbnVtU3BvdFNoYWRvd3NXaXRoTWFwcyArKztcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRzdGF0ZS5zcG90TGlnaHRNYXRyaXhbIHNwb3RMZW5ndGggXSA9IHNoYWRvdy5tYXRyaXg7XHJcblxyXG5cdFx0XHRcdGlmICggbGlnaHQuY2FzdFNoYWRvdyApIHtcclxuXHJcblx0XHRcdFx0XHRjb25zdCBzaGFkb3dVbmlmb3JtcyA9IHNoYWRvd0NhY2hlLmdldCggbGlnaHQgKTtcclxuXHJcblx0XHRcdFx0XHRzaGFkb3dVbmlmb3Jtcy5zaGFkb3dCaWFzID0gc2hhZG93LmJpYXM7XHJcblx0XHRcdFx0XHRzaGFkb3dVbmlmb3Jtcy5zaGFkb3dOb3JtYWxCaWFzID0gc2hhZG93Lm5vcm1hbEJpYXM7XHJcblx0XHRcdFx0XHRzaGFkb3dVbmlmb3Jtcy5zaGFkb3dSYWRpdXMgPSBzaGFkb3cucmFkaXVzO1xyXG5cdFx0XHRcdFx0c2hhZG93VW5pZm9ybXMuc2hhZG93TWFwU2l6ZSA9IHNoYWRvdy5tYXBTaXplO1xyXG5cclxuXHRcdFx0XHRcdHN0YXRlLnNwb3RTaGFkb3dbIHNwb3RMZW5ndGggXSA9IHNoYWRvd1VuaWZvcm1zO1xyXG5cdFx0XHRcdFx0c3RhdGUuc3BvdFNoYWRvd01hcFsgc3BvdExlbmd0aCBdID0gc2hhZG93TWFwO1xyXG5cclxuXHRcdFx0XHRcdG51bVNwb3RTaGFkb3dzICsrO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdHNwb3RMZW5ndGggKys7XHJcblxyXG5cdFx0XHR9IGVsc2UgaWYgKCBsaWdodC5pc1JlY3RBcmVhTGlnaHQgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IHVuaWZvcm1zID0gY2FjaGUuZ2V0KCBsaWdodCApO1xyXG5cclxuXHRcdFx0XHR1bmlmb3Jtcy5jb2xvci5jb3B5KCBjb2xvciApLm11bHRpcGx5U2NhbGFyKCBpbnRlbnNpdHkgKTtcclxuXHJcblx0XHRcdFx0dW5pZm9ybXMuaGFsZldpZHRoLnNldCggbGlnaHQud2lkdGggKiAwLjUsIDAuMCwgMC4wICk7XHJcblx0XHRcdFx0dW5pZm9ybXMuaGFsZkhlaWdodC5zZXQoIDAuMCwgbGlnaHQuaGVpZ2h0ICogMC41LCAwLjAgKTtcclxuXHJcblx0XHRcdFx0c3RhdGUucmVjdEFyZWFbIHJlY3RBcmVhTGVuZ3RoIF0gPSB1bmlmb3JtcztcclxuXHJcblx0XHRcdFx0cmVjdEFyZWFMZW5ndGggKys7XHJcblxyXG5cdFx0XHR9IGVsc2UgaWYgKCBsaWdodC5pc1BvaW50TGlnaHQgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IHVuaWZvcm1zID0gY2FjaGUuZ2V0KCBsaWdodCApO1xyXG5cclxuXHRcdFx0XHR1bmlmb3Jtcy5jb2xvci5jb3B5KCBsaWdodC5jb2xvciApLm11bHRpcGx5U2NhbGFyKCBsaWdodC5pbnRlbnNpdHkgKiBzY2FsZUZhY3RvciApO1xyXG5cdFx0XHRcdHVuaWZvcm1zLmRpc3RhbmNlID0gbGlnaHQuZGlzdGFuY2U7XHJcblx0XHRcdFx0dW5pZm9ybXMuZGVjYXkgPSBsaWdodC5kZWNheTtcclxuXHJcblx0XHRcdFx0aWYgKCBsaWdodC5jYXN0U2hhZG93ICkge1xyXG5cclxuXHRcdFx0XHRcdGNvbnN0IHNoYWRvdyA9IGxpZ2h0LnNoYWRvdztcclxuXHJcblx0XHRcdFx0XHRjb25zdCBzaGFkb3dVbmlmb3JtcyA9IHNoYWRvd0NhY2hlLmdldCggbGlnaHQgKTtcclxuXHJcblx0XHRcdFx0XHRzaGFkb3dVbmlmb3Jtcy5zaGFkb3dCaWFzID0gc2hhZG93LmJpYXM7XHJcblx0XHRcdFx0XHRzaGFkb3dVbmlmb3Jtcy5zaGFkb3dOb3JtYWxCaWFzID0gc2hhZG93Lm5vcm1hbEJpYXM7XHJcblx0XHRcdFx0XHRzaGFkb3dVbmlmb3Jtcy5zaGFkb3dSYWRpdXMgPSBzaGFkb3cucmFkaXVzO1xyXG5cdFx0XHRcdFx0c2hhZG93VW5pZm9ybXMuc2hhZG93TWFwU2l6ZSA9IHNoYWRvdy5tYXBTaXplO1xyXG5cdFx0XHRcdFx0c2hhZG93VW5pZm9ybXMuc2hhZG93Q2FtZXJhTmVhciA9IHNoYWRvdy5jYW1lcmEubmVhcjtcclxuXHRcdFx0XHRcdHNoYWRvd1VuaWZvcm1zLnNoYWRvd0NhbWVyYUZhciA9IHNoYWRvdy5jYW1lcmEuZmFyO1xyXG5cclxuXHRcdFx0XHRcdHN0YXRlLnBvaW50U2hhZG93WyBwb2ludExlbmd0aCBdID0gc2hhZG93VW5pZm9ybXM7XHJcblx0XHRcdFx0XHRzdGF0ZS5wb2ludFNoYWRvd01hcFsgcG9pbnRMZW5ndGggXSA9IHNoYWRvd01hcDtcclxuXHRcdFx0XHRcdHN0YXRlLnBvaW50U2hhZG93TWF0cml4WyBwb2ludExlbmd0aCBdID0gbGlnaHQuc2hhZG93Lm1hdHJpeDtcclxuXHJcblx0XHRcdFx0XHRudW1Qb2ludFNoYWRvd3MgKys7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0c3RhdGUucG9pbnRbIHBvaW50TGVuZ3RoIF0gPSB1bmlmb3JtcztcclxuXHJcblx0XHRcdFx0cG9pbnRMZW5ndGggKys7XHJcblxyXG5cdFx0XHR9IGVsc2UgaWYgKCBsaWdodC5pc0hlbWlzcGhlcmVMaWdodCApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgdW5pZm9ybXMgPSBjYWNoZS5nZXQoIGxpZ2h0ICk7XHJcblxyXG5cdFx0XHRcdHVuaWZvcm1zLnNreUNvbG9yLmNvcHkoIGxpZ2h0LmNvbG9yICkubXVsdGlwbHlTY2FsYXIoIGludGVuc2l0eSAqIHNjYWxlRmFjdG9yICk7XHJcblx0XHRcdFx0dW5pZm9ybXMuZ3JvdW5kQ29sb3IuY29weSggbGlnaHQuZ3JvdW5kQ29sb3IgKS5tdWx0aXBseVNjYWxhciggaW50ZW5zaXR5ICogc2NhbGVGYWN0b3IgKTtcclxuXHJcblx0XHRcdFx0c3RhdGUuaGVtaVsgaGVtaUxlbmd0aCBdID0gdW5pZm9ybXM7XHJcblxyXG5cdFx0XHRcdGhlbWlMZW5ndGggKys7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggcmVjdEFyZWFMZW5ndGggPiAwICkge1xyXG5cclxuXHRcdFx0aWYgKCBjYXBhYmlsaXRpZXMuaXNXZWJHTDIgKSB7XHJcblxyXG5cdFx0XHRcdC8vIFdlYkdMIDJcclxuXHJcblx0XHRcdFx0aWYgKCBleHRlbnNpb25zLmhhcyggJ09FU190ZXh0dXJlX2Zsb2F0X2xpbmVhcicgKSA9PT0gdHJ1ZSApIHtcclxuXHJcblx0XHRcdFx0XHRzdGF0ZS5yZWN0QXJlYUxUQzEgPSBVbmlmb3Jtc0xpYi5MVENfRkxPQVRfMTtcclxuXHRcdFx0XHRcdHN0YXRlLnJlY3RBcmVhTFRDMiA9IFVuaWZvcm1zTGliLkxUQ19GTE9BVF8yO1xyXG5cclxuXHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdHN0YXRlLnJlY3RBcmVhTFRDMSA9IFVuaWZvcm1zTGliLkxUQ19IQUxGXzE7XHJcblx0XHRcdFx0XHRzdGF0ZS5yZWN0QXJlYUxUQzIgPSBVbmlmb3Jtc0xpYi5MVENfSEFMRl8yO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHQvLyBXZWJHTCAxXHJcblxyXG5cdFx0XHRcdGlmICggZXh0ZW5zaW9ucy5oYXMoICdPRVNfdGV4dHVyZV9mbG9hdF9saW5lYXInICkgPT09IHRydWUgKSB7XHJcblxyXG5cdFx0XHRcdFx0c3RhdGUucmVjdEFyZWFMVEMxID0gVW5pZm9ybXNMaWIuTFRDX0ZMT0FUXzE7XHJcblx0XHRcdFx0XHRzdGF0ZS5yZWN0QXJlYUxUQzIgPSBVbmlmb3Jtc0xpYi5MVENfRkxPQVRfMjtcclxuXHJcblx0XHRcdFx0fSBlbHNlIGlmICggZXh0ZW5zaW9ucy5oYXMoICdPRVNfdGV4dHVyZV9oYWxmX2Zsb2F0X2xpbmVhcicgKSA9PT0gdHJ1ZSApIHtcclxuXHJcblx0XHRcdFx0XHRzdGF0ZS5yZWN0QXJlYUxUQzEgPSBVbmlmb3Jtc0xpYi5MVENfSEFMRl8xO1xyXG5cdFx0XHRcdFx0c3RhdGUucmVjdEFyZWFMVEMyID0gVW5pZm9ybXNMaWIuTFRDX0hBTEZfMjtcclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuV2ViR0xSZW5kZXJlcjogVW5hYmxlIHRvIHVzZSBSZWN0QXJlYUxpZ2h0LiBNaXNzaW5nIFdlYkdMIGV4dGVuc2lvbnMuJyApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHN0YXRlLmFtYmllbnRbIDAgXSA9IHI7XHJcblx0XHRzdGF0ZS5hbWJpZW50WyAxIF0gPSBnO1xyXG5cdFx0c3RhdGUuYW1iaWVudFsgMiBdID0gYjtcclxuXHJcblx0XHRjb25zdCBoYXNoID0gc3RhdGUuaGFzaDtcclxuXHJcblx0XHRpZiAoIGhhc2guZGlyZWN0aW9uYWxMZW5ndGggIT09IGRpcmVjdGlvbmFsTGVuZ3RoIHx8XHJcblx0XHRcdGhhc2gucG9pbnRMZW5ndGggIT09IHBvaW50TGVuZ3RoIHx8XHJcblx0XHRcdGhhc2guc3BvdExlbmd0aCAhPT0gc3BvdExlbmd0aCB8fFxyXG5cdFx0XHRoYXNoLnJlY3RBcmVhTGVuZ3RoICE9PSByZWN0QXJlYUxlbmd0aCB8fFxyXG5cdFx0XHRoYXNoLmhlbWlMZW5ndGggIT09IGhlbWlMZW5ndGggfHxcclxuXHRcdFx0aGFzaC5udW1EaXJlY3Rpb25hbFNoYWRvd3MgIT09IG51bURpcmVjdGlvbmFsU2hhZG93cyB8fFxyXG5cdFx0XHRoYXNoLm51bVBvaW50U2hhZG93cyAhPT0gbnVtUG9pbnRTaGFkb3dzIHx8XHJcblx0XHRcdGhhc2gubnVtU3BvdFNoYWRvd3MgIT09IG51bVNwb3RTaGFkb3dzIHx8XHJcblx0XHRcdGhhc2gubnVtU3BvdE1hcHMgIT09IG51bVNwb3RNYXBzIHx8XHJcblx0XHRcdGhhc2gubnVtTGlnaHRQcm9iZXMgIT09IG51bUxpZ2h0UHJvYmVzICkge1xyXG5cclxuXHRcdFx0c3RhdGUuZGlyZWN0aW9uYWwubGVuZ3RoID0gZGlyZWN0aW9uYWxMZW5ndGg7XHJcblx0XHRcdHN0YXRlLnNwb3QubGVuZ3RoID0gc3BvdExlbmd0aDtcclxuXHRcdFx0c3RhdGUucmVjdEFyZWEubGVuZ3RoID0gcmVjdEFyZWFMZW5ndGg7XHJcblx0XHRcdHN0YXRlLnBvaW50Lmxlbmd0aCA9IHBvaW50TGVuZ3RoO1xyXG5cdFx0XHRzdGF0ZS5oZW1pLmxlbmd0aCA9IGhlbWlMZW5ndGg7XHJcblxyXG5cdFx0XHRzdGF0ZS5kaXJlY3Rpb25hbFNoYWRvdy5sZW5ndGggPSBudW1EaXJlY3Rpb25hbFNoYWRvd3M7XHJcblx0XHRcdHN0YXRlLmRpcmVjdGlvbmFsU2hhZG93TWFwLmxlbmd0aCA9IG51bURpcmVjdGlvbmFsU2hhZG93cztcclxuXHRcdFx0c3RhdGUucG9pbnRTaGFkb3cubGVuZ3RoID0gbnVtUG9pbnRTaGFkb3dzO1xyXG5cdFx0XHRzdGF0ZS5wb2ludFNoYWRvd01hcC5sZW5ndGggPSBudW1Qb2ludFNoYWRvd3M7XHJcblx0XHRcdHN0YXRlLnNwb3RTaGFkb3cubGVuZ3RoID0gbnVtU3BvdFNoYWRvd3M7XHJcblx0XHRcdHN0YXRlLnNwb3RTaGFkb3dNYXAubGVuZ3RoID0gbnVtU3BvdFNoYWRvd3M7XHJcblx0XHRcdHN0YXRlLmRpcmVjdGlvbmFsU2hhZG93TWF0cml4Lmxlbmd0aCA9IG51bURpcmVjdGlvbmFsU2hhZG93cztcclxuXHRcdFx0c3RhdGUucG9pbnRTaGFkb3dNYXRyaXgubGVuZ3RoID0gbnVtUG9pbnRTaGFkb3dzO1xyXG5cdFx0XHRzdGF0ZS5zcG90TGlnaHRNYXRyaXgubGVuZ3RoID0gbnVtU3BvdFNoYWRvd3MgKyBudW1TcG90TWFwcyAtIG51bVNwb3RTaGFkb3dzV2l0aE1hcHM7XHJcblx0XHRcdHN0YXRlLnNwb3RMaWdodE1hcC5sZW5ndGggPSBudW1TcG90TWFwcztcclxuXHRcdFx0c3RhdGUubnVtU3BvdExpZ2h0U2hhZG93c1dpdGhNYXBzID0gbnVtU3BvdFNoYWRvd3NXaXRoTWFwcztcclxuXHRcdFx0c3RhdGUubnVtTGlnaHRQcm9iZXMgPSBudW1MaWdodFByb2JlcztcclxuXHJcblx0XHRcdGhhc2guZGlyZWN0aW9uYWxMZW5ndGggPSBkaXJlY3Rpb25hbExlbmd0aDtcclxuXHRcdFx0aGFzaC5wb2ludExlbmd0aCA9IHBvaW50TGVuZ3RoO1xyXG5cdFx0XHRoYXNoLnNwb3RMZW5ndGggPSBzcG90TGVuZ3RoO1xyXG5cdFx0XHRoYXNoLnJlY3RBcmVhTGVuZ3RoID0gcmVjdEFyZWFMZW5ndGg7XHJcblx0XHRcdGhhc2guaGVtaUxlbmd0aCA9IGhlbWlMZW5ndGg7XHJcblxyXG5cdFx0XHRoYXNoLm51bURpcmVjdGlvbmFsU2hhZG93cyA9IG51bURpcmVjdGlvbmFsU2hhZG93cztcclxuXHRcdFx0aGFzaC5udW1Qb2ludFNoYWRvd3MgPSBudW1Qb2ludFNoYWRvd3M7XHJcblx0XHRcdGhhc2gubnVtU3BvdFNoYWRvd3MgPSBudW1TcG90U2hhZG93cztcclxuXHRcdFx0aGFzaC5udW1TcG90TWFwcyA9IG51bVNwb3RNYXBzO1xyXG5cclxuXHRcdFx0aGFzaC5udW1MaWdodFByb2JlcyA9IG51bUxpZ2h0UHJvYmVzO1xyXG5cclxuXHRcdFx0c3RhdGUudmVyc2lvbiA9IG5leHRWZXJzaW9uICsrO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBzZXR1cFZpZXcoIGxpZ2h0cywgY2FtZXJhICkge1xyXG5cclxuXHRcdGxldCBkaXJlY3Rpb25hbExlbmd0aCA9IDA7XHJcblx0XHRsZXQgcG9pbnRMZW5ndGggPSAwO1xyXG5cdFx0bGV0IHNwb3RMZW5ndGggPSAwO1xyXG5cdFx0bGV0IHJlY3RBcmVhTGVuZ3RoID0gMDtcclxuXHRcdGxldCBoZW1pTGVuZ3RoID0gMDtcclxuXHJcblx0XHRjb25zdCB2aWV3TWF0cml4ID0gY2FtZXJhLm1hdHJpeFdvcmxkSW52ZXJzZTtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBsaWdodHMubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdGNvbnN0IGxpZ2h0ID0gbGlnaHRzWyBpIF07XHJcblxyXG5cdFx0XHRpZiAoIGxpZ2h0LmlzRGlyZWN0aW9uYWxMaWdodCApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgdW5pZm9ybXMgPSBzdGF0ZS5kaXJlY3Rpb25hbFsgZGlyZWN0aW9uYWxMZW5ndGggXTtcclxuXHJcblx0XHRcdFx0dW5pZm9ybXMuZGlyZWN0aW9uLnNldEZyb21NYXRyaXhQb3NpdGlvbiggbGlnaHQubWF0cml4V29ybGQgKTtcclxuXHRcdFx0XHR2ZWN0b3IzLnNldEZyb21NYXRyaXhQb3NpdGlvbiggbGlnaHQudGFyZ2V0Lm1hdHJpeFdvcmxkICk7XHJcblx0XHRcdFx0dW5pZm9ybXMuZGlyZWN0aW9uLnN1YiggdmVjdG9yMyApO1xyXG5cdFx0XHRcdHVuaWZvcm1zLmRpcmVjdGlvbi50cmFuc2Zvcm1EaXJlY3Rpb24oIHZpZXdNYXRyaXggKTtcclxuXHJcblx0XHRcdFx0ZGlyZWN0aW9uYWxMZW5ndGggKys7XHJcblxyXG5cdFx0XHR9IGVsc2UgaWYgKCBsaWdodC5pc1Nwb3RMaWdodCApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgdW5pZm9ybXMgPSBzdGF0ZS5zcG90WyBzcG90TGVuZ3RoIF07XHJcblxyXG5cdFx0XHRcdHVuaWZvcm1zLnBvc2l0aW9uLnNldEZyb21NYXRyaXhQb3NpdGlvbiggbGlnaHQubWF0cml4V29ybGQgKTtcclxuXHRcdFx0XHR1bmlmb3Jtcy5wb3NpdGlvbi5hcHBseU1hdHJpeDQoIHZpZXdNYXRyaXggKTtcclxuXHJcblx0XHRcdFx0dW5pZm9ybXMuZGlyZWN0aW9uLnNldEZyb21NYXRyaXhQb3NpdGlvbiggbGlnaHQubWF0cml4V29ybGQgKTtcclxuXHRcdFx0XHR2ZWN0b3IzLnNldEZyb21NYXRyaXhQb3NpdGlvbiggbGlnaHQudGFyZ2V0Lm1hdHJpeFdvcmxkICk7XHJcblx0XHRcdFx0dW5pZm9ybXMuZGlyZWN0aW9uLnN1YiggdmVjdG9yMyApO1xyXG5cdFx0XHRcdHVuaWZvcm1zLmRpcmVjdGlvbi50cmFuc2Zvcm1EaXJlY3Rpb24oIHZpZXdNYXRyaXggKTtcclxuXHJcblx0XHRcdFx0c3BvdExlbmd0aCArKztcclxuXHJcblx0XHRcdH0gZWxzZSBpZiAoIGxpZ2h0LmlzUmVjdEFyZWFMaWdodCApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgdW5pZm9ybXMgPSBzdGF0ZS5yZWN0QXJlYVsgcmVjdEFyZWFMZW5ndGggXTtcclxuXHJcblx0XHRcdFx0dW5pZm9ybXMucG9zaXRpb24uc2V0RnJvbU1hdHJpeFBvc2l0aW9uKCBsaWdodC5tYXRyaXhXb3JsZCApO1xyXG5cdFx0XHRcdHVuaWZvcm1zLnBvc2l0aW9uLmFwcGx5TWF0cml4NCggdmlld01hdHJpeCApO1xyXG5cclxuXHRcdFx0XHQvLyBleHRyYWN0IGxvY2FsIHJvdGF0aW9uIG9mIGxpZ2h0IHRvIGRlcml2ZSB3aWR0aC9oZWlnaHQgaGFsZiB2ZWN0b3JzXHJcblx0XHRcdFx0bWF0cml4NDIuaWRlbnRpdHkoKTtcclxuXHRcdFx0XHRtYXRyaXg0LmNvcHkoIGxpZ2h0Lm1hdHJpeFdvcmxkICk7XHJcblx0XHRcdFx0bWF0cml4NC5wcmVtdWx0aXBseSggdmlld01hdHJpeCApO1xyXG5cdFx0XHRcdG1hdHJpeDQyLmV4dHJhY3RSb3RhdGlvbiggbWF0cml4NCApO1xyXG5cclxuXHRcdFx0XHR1bmlmb3Jtcy5oYWxmV2lkdGguc2V0KCBsaWdodC53aWR0aCAqIDAuNSwgMC4wLCAwLjAgKTtcclxuXHRcdFx0XHR1bmlmb3Jtcy5oYWxmSGVpZ2h0LnNldCggMC4wLCBsaWdodC5oZWlnaHQgKiAwLjUsIDAuMCApO1xyXG5cclxuXHRcdFx0XHR1bmlmb3Jtcy5oYWxmV2lkdGguYXBwbHlNYXRyaXg0KCBtYXRyaXg0MiApO1xyXG5cdFx0XHRcdHVuaWZvcm1zLmhhbGZIZWlnaHQuYXBwbHlNYXRyaXg0KCBtYXRyaXg0MiApO1xyXG5cclxuXHRcdFx0XHRyZWN0QXJlYUxlbmd0aCArKztcclxuXHJcblx0XHRcdH0gZWxzZSBpZiAoIGxpZ2h0LmlzUG9pbnRMaWdodCApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgdW5pZm9ybXMgPSBzdGF0ZS5wb2ludFsgcG9pbnRMZW5ndGggXTtcclxuXHJcblx0XHRcdFx0dW5pZm9ybXMucG9zaXRpb24uc2V0RnJvbU1hdHJpeFBvc2l0aW9uKCBsaWdodC5tYXRyaXhXb3JsZCApO1xyXG5cdFx0XHRcdHVuaWZvcm1zLnBvc2l0aW9uLmFwcGx5TWF0cml4NCggdmlld01hdHJpeCApO1xyXG5cclxuXHRcdFx0XHRwb2ludExlbmd0aCArKztcclxuXHJcblx0XHRcdH0gZWxzZSBpZiAoIGxpZ2h0LmlzSGVtaXNwaGVyZUxpZ2h0ICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCB1bmlmb3JtcyA9IHN0YXRlLmhlbWlbIGhlbWlMZW5ndGggXTtcclxuXHJcblx0XHRcdFx0dW5pZm9ybXMuZGlyZWN0aW9uLnNldEZyb21NYXRyaXhQb3NpdGlvbiggbGlnaHQubWF0cml4V29ybGQgKTtcclxuXHRcdFx0XHR1bmlmb3Jtcy5kaXJlY3Rpb24udHJhbnNmb3JtRGlyZWN0aW9uKCB2aWV3TWF0cml4ICk7XHJcblxyXG5cdFx0XHRcdGhlbWlMZW5ndGggKys7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdHJldHVybiB7XHJcblx0XHRzZXR1cDogc2V0dXAsXHJcblx0XHRzZXR1cFZpZXc6IHNldHVwVmlldyxcclxuXHRcdHN0YXRlOiBzdGF0ZVxyXG5cdH07XHJcblxyXG59XHJcblxyXG5cclxuZXhwb3J0IHsgV2ViR0xMaWdodHMgfTtcclxuIiwiaW1wb3J0IHsgV2ViR0xMaWdodHMgfSBmcm9tICcuL1dlYkdMTGlnaHRzLmpzJztcclxuXHJcbmZ1bmN0aW9uIFdlYkdMUmVuZGVyU3RhdGUoIGV4dGVuc2lvbnMsIGNhcGFiaWxpdGllcyApIHtcclxuXHJcblx0Y29uc3QgbGlnaHRzID0gbmV3IFdlYkdMTGlnaHRzKCBleHRlbnNpb25zLCBjYXBhYmlsaXRpZXMgKTtcclxuXHJcblx0Y29uc3QgbGlnaHRzQXJyYXkgPSBbXTtcclxuXHRjb25zdCBzaGFkb3dzQXJyYXkgPSBbXTtcclxuXHJcblx0ZnVuY3Rpb24gaW5pdCgpIHtcclxuXHJcblx0XHRsaWdodHNBcnJheS5sZW5ndGggPSAwO1xyXG5cdFx0c2hhZG93c0FycmF5Lmxlbmd0aCA9IDA7XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gcHVzaExpZ2h0KCBsaWdodCApIHtcclxuXHJcblx0XHRsaWdodHNBcnJheS5wdXNoKCBsaWdodCApO1xyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHB1c2hTaGFkb3coIHNoYWRvd0xpZ2h0ICkge1xyXG5cclxuXHRcdHNoYWRvd3NBcnJheS5wdXNoKCBzaGFkb3dMaWdodCApO1xyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHNldHVwTGlnaHRzKCB1c2VMZWdhY3lMaWdodHMgKSB7XHJcblxyXG5cdFx0bGlnaHRzLnNldHVwKCBsaWdodHNBcnJheSwgdXNlTGVnYWN5TGlnaHRzICk7XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gc2V0dXBMaWdodHNWaWV3KCBjYW1lcmEgKSB7XHJcblxyXG5cdFx0bGlnaHRzLnNldHVwVmlldyggbGlnaHRzQXJyYXksIGNhbWVyYSApO1xyXG5cclxuXHR9XHJcblxyXG5cdGNvbnN0IHN0YXRlID0ge1xyXG5cdFx0bGlnaHRzQXJyYXk6IGxpZ2h0c0FycmF5LFxyXG5cdFx0c2hhZG93c0FycmF5OiBzaGFkb3dzQXJyYXksXHJcblxyXG5cdFx0bGlnaHRzOiBsaWdodHNcclxuXHR9O1xyXG5cclxuXHRyZXR1cm4ge1xyXG5cdFx0aW5pdDogaW5pdCxcclxuXHRcdHN0YXRlOiBzdGF0ZSxcclxuXHRcdHNldHVwTGlnaHRzOiBzZXR1cExpZ2h0cyxcclxuXHRcdHNldHVwTGlnaHRzVmlldzogc2V0dXBMaWdodHNWaWV3LFxyXG5cclxuXHRcdHB1c2hMaWdodDogcHVzaExpZ2h0LFxyXG5cdFx0cHVzaFNoYWRvdzogcHVzaFNoYWRvd1xyXG5cdH07XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiBXZWJHTFJlbmRlclN0YXRlcyggZXh0ZW5zaW9ucywgY2FwYWJpbGl0aWVzICkge1xyXG5cclxuXHRsZXQgcmVuZGVyU3RhdGVzID0gbmV3IFdlYWtNYXAoKTtcclxuXHJcblx0ZnVuY3Rpb24gZ2V0KCBzY2VuZSwgcmVuZGVyQ2FsbERlcHRoID0gMCApIHtcclxuXHJcblx0XHRjb25zdCByZW5kZXJTdGF0ZUFycmF5ID0gcmVuZGVyU3RhdGVzLmdldCggc2NlbmUgKTtcclxuXHRcdGxldCByZW5kZXJTdGF0ZTtcclxuXHJcblx0XHRpZiAoIHJlbmRlclN0YXRlQXJyYXkgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdHJlbmRlclN0YXRlID0gbmV3IFdlYkdMUmVuZGVyU3RhdGUoIGV4dGVuc2lvbnMsIGNhcGFiaWxpdGllcyApO1xyXG5cdFx0XHRyZW5kZXJTdGF0ZXMuc2V0KCBzY2VuZSwgWyByZW5kZXJTdGF0ZSBdICk7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdGlmICggcmVuZGVyQ2FsbERlcHRoID49IHJlbmRlclN0YXRlQXJyYXkubGVuZ3RoICkge1xyXG5cclxuXHRcdFx0XHRyZW5kZXJTdGF0ZSA9IG5ldyBXZWJHTFJlbmRlclN0YXRlKCBleHRlbnNpb25zLCBjYXBhYmlsaXRpZXMgKTtcclxuXHRcdFx0XHRyZW5kZXJTdGF0ZUFycmF5LnB1c2goIHJlbmRlclN0YXRlICk7XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRyZW5kZXJTdGF0ZSA9IHJlbmRlclN0YXRlQXJyYXlbIHJlbmRlckNhbGxEZXB0aCBdO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gcmVuZGVyU3RhdGU7XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gZGlzcG9zZSgpIHtcclxuXHJcblx0XHRyZW5kZXJTdGF0ZXMgPSBuZXcgV2Vha01hcCgpO1xyXG5cclxuXHR9XHJcblxyXG5cdHJldHVybiB7XHJcblx0XHRnZXQ6IGdldCxcclxuXHRcdGRpc3Bvc2U6IGRpc3Bvc2VcclxuXHR9O1xyXG5cclxufVxyXG5cclxuXHJcbmV4cG9ydCB7IFdlYkdMUmVuZGVyU3RhdGVzIH07XHJcbiIsImltcG9ydCB7IE1hdGVyaWFsIH0gZnJvbSAnLi9NYXRlcmlhbC5qcyc7XHJcbmltcG9ydCB7IEJhc2ljRGVwdGhQYWNraW5nIH0gZnJvbSAnLi4vY29uc3RhbnRzLmpzJztcclxuXHJcbmNsYXNzIE1lc2hEZXB0aE1hdGVyaWFsIGV4dGVuZHMgTWF0ZXJpYWwge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggcGFyYW1ldGVycyApIHtcclxuXHJcblx0XHRzdXBlcigpO1xyXG5cclxuXHRcdHRoaXMuaXNNZXNoRGVwdGhNYXRlcmlhbCA9IHRydWU7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ01lc2hEZXB0aE1hdGVyaWFsJztcclxuXHJcblx0XHR0aGlzLmRlcHRoUGFja2luZyA9IEJhc2ljRGVwdGhQYWNraW5nO1xyXG5cclxuXHRcdHRoaXMubWFwID0gbnVsbDtcclxuXHJcblx0XHR0aGlzLmFscGhhTWFwID0gbnVsbDtcclxuXHJcblx0XHR0aGlzLmRpc3BsYWNlbWVudE1hcCA9IG51bGw7XHJcblx0XHR0aGlzLmRpc3BsYWNlbWVudFNjYWxlID0gMTtcclxuXHRcdHRoaXMuZGlzcGxhY2VtZW50QmlhcyA9IDA7XHJcblxyXG5cdFx0dGhpcy53aXJlZnJhbWUgPSBmYWxzZTtcclxuXHRcdHRoaXMud2lyZWZyYW1lTGluZXdpZHRoID0gMTtcclxuXHJcblx0XHR0aGlzLnNldFZhbHVlcyggcGFyYW1ldGVycyApO1xyXG5cclxuXHR9XHJcblxyXG5cdGNvcHkoIHNvdXJjZSApIHtcclxuXHJcblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcclxuXHJcblx0XHR0aGlzLmRlcHRoUGFja2luZyA9IHNvdXJjZS5kZXB0aFBhY2tpbmc7XHJcblxyXG5cdFx0dGhpcy5tYXAgPSBzb3VyY2UubWFwO1xyXG5cclxuXHRcdHRoaXMuYWxwaGFNYXAgPSBzb3VyY2UuYWxwaGFNYXA7XHJcblxyXG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRNYXAgPSBzb3VyY2UuZGlzcGxhY2VtZW50TWFwO1xyXG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRTY2FsZSA9IHNvdXJjZS5kaXNwbGFjZW1lbnRTY2FsZTtcclxuXHRcdHRoaXMuZGlzcGxhY2VtZW50QmlhcyA9IHNvdXJjZS5kaXNwbGFjZW1lbnRCaWFzO1xyXG5cclxuXHRcdHRoaXMud2lyZWZyYW1lID0gc291cmNlLndpcmVmcmFtZTtcclxuXHRcdHRoaXMud2lyZWZyYW1lTGluZXdpZHRoID0gc291cmNlLndpcmVmcmFtZUxpbmV3aWR0aDtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgTWVzaERlcHRoTWF0ZXJpYWwgfTtcclxuIiwiaW1wb3J0IHsgTWF0ZXJpYWwgfSBmcm9tICcuL01hdGVyaWFsLmpzJztcclxuXHJcbmNsYXNzIE1lc2hEaXN0YW5jZU1hdGVyaWFsIGV4dGVuZHMgTWF0ZXJpYWwge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggcGFyYW1ldGVycyApIHtcclxuXHJcblx0XHRzdXBlcigpO1xyXG5cclxuXHRcdHRoaXMuaXNNZXNoRGlzdGFuY2VNYXRlcmlhbCA9IHRydWU7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ01lc2hEaXN0YW5jZU1hdGVyaWFsJztcclxuXHJcblx0XHR0aGlzLm1hcCA9IG51bGw7XHJcblxyXG5cdFx0dGhpcy5hbHBoYU1hcCA9IG51bGw7XHJcblxyXG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRNYXAgPSBudWxsO1xyXG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRTY2FsZSA9IDE7XHJcblx0XHR0aGlzLmRpc3BsYWNlbWVudEJpYXMgPSAwO1xyXG5cclxuXHRcdHRoaXMuc2V0VmFsdWVzKCBwYXJhbWV0ZXJzICk7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xyXG5cclxuXHRcdHRoaXMubWFwID0gc291cmNlLm1hcDtcclxuXHJcblx0XHR0aGlzLmFscGhhTWFwID0gc291cmNlLmFscGhhTWFwO1xyXG5cclxuXHRcdHRoaXMuZGlzcGxhY2VtZW50TWFwID0gc291cmNlLmRpc3BsYWNlbWVudE1hcDtcclxuXHRcdHRoaXMuZGlzcGxhY2VtZW50U2NhbGUgPSBzb3VyY2UuZGlzcGxhY2VtZW50U2NhbGU7XHJcblx0XHR0aGlzLmRpc3BsYWNlbWVudEJpYXMgPSBzb3VyY2UuZGlzcGxhY2VtZW50QmlhcztcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgTWVzaERpc3RhbmNlTWF0ZXJpYWwgfTtcclxuIiwiZXhwb3J0IGNvbnN0IHZlcnRleCA9IC8qIGdsc2wgKi9gXHJcbnZvaWQgbWFpbigpIHtcclxuXHJcblx0Z2xfUG9zaXRpb24gPSB2ZWM0KCBwb3NpdGlvbiwgMS4wICk7XHJcblxyXG59XHJcbmA7XHJcblxyXG5leHBvcnQgY29uc3QgZnJhZ21lbnQgPSAvKiBnbHNsICovYFxyXG51bmlmb3JtIHNhbXBsZXIyRCBzaGFkb3dfcGFzcztcclxudW5pZm9ybSB2ZWMyIHJlc29sdXRpb247XHJcbnVuaWZvcm0gZmxvYXQgcmFkaXVzO1xyXG5cclxuI2luY2x1ZGUgPHBhY2tpbmc+XHJcblxyXG52b2lkIG1haW4oKSB7XHJcblxyXG5cdGNvbnN0IGZsb2F0IHNhbXBsZXMgPSBmbG9hdCggVlNNX1NBTVBMRVMgKTtcclxuXHJcblx0ZmxvYXQgbWVhbiA9IDAuMDtcclxuXHRmbG9hdCBzcXVhcmVkX21lYW4gPSAwLjA7XHJcblxyXG5cdGZsb2F0IHV2U3RyaWRlID0gc2FtcGxlcyA8PSAxLjAgPyAwLjAgOiAyLjAgLyAoIHNhbXBsZXMgLSAxLjAgKTtcclxuXHRmbG9hdCB1dlN0YXJ0ID0gc2FtcGxlcyA8PSAxLjAgPyAwLjAgOiAtIDEuMDtcclxuXHRmb3IgKCBmbG9hdCBpID0gMC4wOyBpIDwgc2FtcGxlczsgaSArKyApIHtcclxuXHJcblx0XHRmbG9hdCB1dk9mZnNldCA9IHV2U3RhcnQgKyBpICogdXZTdHJpZGU7XHJcblxyXG5cdFx0I2lmZGVmIEhPUklaT05UQUxfUEFTU1xyXG5cclxuXHRcdFx0dmVjMiBkaXN0cmlidXRpb24gPSB1bnBhY2tSR0JBVG8ySGFsZiggdGV4dHVyZTJEKCBzaGFkb3dfcGFzcywgKCBnbF9GcmFnQ29vcmQueHkgKyB2ZWMyKCB1dk9mZnNldCwgMC4wICkgKiByYWRpdXMgKSAvIHJlc29sdXRpb24gKSApO1xyXG5cdFx0XHRtZWFuICs9IGRpc3RyaWJ1dGlvbi54O1xyXG5cdFx0XHRzcXVhcmVkX21lYW4gKz0gZGlzdHJpYnV0aW9uLnkgKiBkaXN0cmlidXRpb24ueSArIGRpc3RyaWJ1dGlvbi54ICogZGlzdHJpYnV0aW9uLng7XHJcblxyXG5cdFx0I2Vsc2VcclxuXHJcblx0XHRcdGZsb2F0IGRlcHRoID0gdW5wYWNrUkdCQVRvRGVwdGgoIHRleHR1cmUyRCggc2hhZG93X3Bhc3MsICggZ2xfRnJhZ0Nvb3JkLnh5ICsgdmVjMiggMC4wLCB1dk9mZnNldCApICogcmFkaXVzICkgLyByZXNvbHV0aW9uICkgKTtcclxuXHRcdFx0bWVhbiArPSBkZXB0aDtcclxuXHRcdFx0c3F1YXJlZF9tZWFuICs9IGRlcHRoICogZGVwdGg7XHJcblxyXG5cdFx0I2VuZGlmXHJcblxyXG5cdH1cclxuXHJcblx0bWVhbiA9IG1lYW4gLyBzYW1wbGVzO1xyXG5cdHNxdWFyZWRfbWVhbiA9IHNxdWFyZWRfbWVhbiAvIHNhbXBsZXM7XHJcblxyXG5cdGZsb2F0IHN0ZF9kZXYgPSBzcXJ0KCBzcXVhcmVkX21lYW4gLSBtZWFuICogbWVhbiApO1xyXG5cclxuXHRnbF9GcmFnQ29sb3IgPSBwYWNrMkhhbGZUb1JHQkEoIHZlYzIoIG1lYW4sIHN0ZF9kZXYgKSApO1xyXG5cclxufVxyXG5gO1xyXG4iLCJpbXBvcnQgeyBGcm9udFNpZGUsIEJhY2tTaWRlLCBEb3VibGVTaWRlLCBOZWFyZXN0RmlsdGVyLCBQQ0ZTaGFkb3dNYXAsIFZTTVNoYWRvd01hcCwgUkdCQURlcHRoUGFja2luZywgTm9CbGVuZGluZyB9IGZyb20gJy4uLy4uL2NvbnN0YW50cy5qcyc7XHJcbmltcG9ydCB7IFdlYkdMUmVuZGVyVGFyZ2V0IH0gZnJvbSAnLi4vV2ViR0xSZW5kZXJUYXJnZXQuanMnO1xyXG5pbXBvcnQgeyBNZXNoRGVwdGhNYXRlcmlhbCB9IGZyb20gJy4uLy4uL21hdGVyaWFscy9NZXNoRGVwdGhNYXRlcmlhbC5qcyc7XHJcbmltcG9ydCB7IE1lc2hEaXN0YW5jZU1hdGVyaWFsIH0gZnJvbSAnLi4vLi4vbWF0ZXJpYWxzL01lc2hEaXN0YW5jZU1hdGVyaWFsLmpzJztcclxuaW1wb3J0IHsgU2hhZGVyTWF0ZXJpYWwgfSBmcm9tICcuLi8uLi9tYXRlcmlhbHMvU2hhZGVyTWF0ZXJpYWwuanMnO1xyXG5pbXBvcnQgeyBCdWZmZXJBdHRyaWJ1dGUgfSBmcm9tICcuLi8uLi9jb3JlL0J1ZmZlckF0dHJpYnV0ZS5qcyc7XHJcbmltcG9ydCB7IEJ1ZmZlckdlb21ldHJ5IH0gZnJvbSAnLi4vLi4vY29yZS9CdWZmZXJHZW9tZXRyeS5qcyc7XHJcbmltcG9ydCB7IE1lc2ggfSBmcm9tICcuLi8uLi9vYmplY3RzL01lc2guanMnO1xyXG5pbXBvcnQgeyBWZWN0b3I0IH0gZnJvbSAnLi4vLi4vbWF0aC9WZWN0b3I0LmpzJztcclxuaW1wb3J0IHsgVmVjdG9yMiB9IGZyb20gJy4uLy4uL21hdGgvVmVjdG9yMi5qcyc7XHJcbmltcG9ydCB7IEZydXN0dW0gfSBmcm9tICcuLi8uLi9tYXRoL0ZydXN0dW0uanMnO1xyXG5cclxuaW1wb3J0ICogYXMgdnNtIGZyb20gJy4uL3NoYWRlcnMvU2hhZGVyTGliL3ZzbS5nbHNsLmpzJztcclxuXHJcbmZ1bmN0aW9uIFdlYkdMU2hhZG93TWFwKCBfcmVuZGVyZXIsIF9vYmplY3RzLCBfY2FwYWJpbGl0aWVzICkge1xyXG5cclxuXHRsZXQgX2ZydXN0dW0gPSBuZXcgRnJ1c3R1bSgpO1xyXG5cclxuXHRjb25zdCBfc2hhZG93TWFwU2l6ZSA9IG5ldyBWZWN0b3IyKCksXHJcblx0XHRfdmlld3BvcnRTaXplID0gbmV3IFZlY3RvcjIoKSxcclxuXHJcblx0XHRfdmlld3BvcnQgPSBuZXcgVmVjdG9yNCgpLFxyXG5cclxuXHRcdF9kZXB0aE1hdGVyaWFsID0gbmV3IE1lc2hEZXB0aE1hdGVyaWFsKCB7IGRlcHRoUGFja2luZzogUkdCQURlcHRoUGFja2luZyB9ICksXHJcblx0XHRfZGlzdGFuY2VNYXRlcmlhbCA9IG5ldyBNZXNoRGlzdGFuY2VNYXRlcmlhbCgpLFxyXG5cclxuXHRcdF9tYXRlcmlhbENhY2hlID0ge30sXHJcblxyXG5cdFx0X21heFRleHR1cmVTaXplID0gX2NhcGFiaWxpdGllcy5tYXhUZXh0dXJlU2l6ZTtcclxuXHJcblx0Y29uc3Qgc2hhZG93U2lkZSA9IHsgWyBGcm9udFNpZGUgXTogQmFja1NpZGUsIFsgQmFja1NpZGUgXTogRnJvbnRTaWRlLCBbIERvdWJsZVNpZGUgXTogRG91YmxlU2lkZSB9O1xyXG5cclxuXHRjb25zdCBzaGFkb3dNYXRlcmlhbFZlcnRpY2FsID0gbmV3IFNoYWRlck1hdGVyaWFsKCB7XHJcblx0XHRkZWZpbmVzOiB7XHJcblx0XHRcdFZTTV9TQU1QTEVTOiA4XHJcblx0XHR9LFxyXG5cdFx0dW5pZm9ybXM6IHtcclxuXHRcdFx0c2hhZG93X3Bhc3M6IHsgdmFsdWU6IG51bGwgfSxcclxuXHRcdFx0cmVzb2x1dGlvbjogeyB2YWx1ZTogbmV3IFZlY3RvcjIoKSB9LFxyXG5cdFx0XHRyYWRpdXM6IHsgdmFsdWU6IDQuMCB9XHJcblx0XHR9LFxyXG5cclxuXHRcdHZlcnRleFNoYWRlcjogdnNtLnZlcnRleCxcclxuXHRcdGZyYWdtZW50U2hhZGVyOiB2c20uZnJhZ21lbnRcclxuXHJcblx0fSApO1xyXG5cclxuXHRjb25zdCBzaGFkb3dNYXRlcmlhbEhvcml6b250YWwgPSBzaGFkb3dNYXRlcmlhbFZlcnRpY2FsLmNsb25lKCk7XHJcblx0c2hhZG93TWF0ZXJpYWxIb3Jpem9udGFsLmRlZmluZXMuSE9SSVpPTlRBTF9QQVNTID0gMTtcclxuXHJcblx0Y29uc3QgZnVsbFNjcmVlblRyaSA9IG5ldyBCdWZmZXJHZW9tZXRyeSgpO1xyXG5cdGZ1bGxTY3JlZW5Ucmkuc2V0QXR0cmlidXRlKFxyXG5cdFx0J3Bvc2l0aW9uJyxcclxuXHRcdG5ldyBCdWZmZXJBdHRyaWJ1dGUoXHJcblx0XHRcdG5ldyBGbG9hdDMyQXJyYXkoIFsgLSAxLCAtIDEsIDAuNSwgMywgLSAxLCAwLjUsIC0gMSwgMywgMC41IF0gKSxcclxuXHRcdFx0M1xyXG5cdFx0KVxyXG5cdCk7XHJcblxyXG5cdGNvbnN0IGZ1bGxTY3JlZW5NZXNoID0gbmV3IE1lc2goIGZ1bGxTY3JlZW5UcmksIHNoYWRvd01hdGVyaWFsVmVydGljYWwgKTtcclxuXHJcblx0Y29uc3Qgc2NvcGUgPSB0aGlzO1xyXG5cclxuXHR0aGlzLmVuYWJsZWQgPSBmYWxzZTtcclxuXHJcblx0dGhpcy5hdXRvVXBkYXRlID0gdHJ1ZTtcclxuXHR0aGlzLm5lZWRzVXBkYXRlID0gZmFsc2U7XHJcblxyXG5cdHRoaXMudHlwZSA9IFBDRlNoYWRvd01hcDtcclxuXHRsZXQgX3ByZXZpb3VzVHlwZSA9IHRoaXMudHlwZTtcclxuXHJcblx0dGhpcy5yZW5kZXIgPSBmdW5jdGlvbiAoIGxpZ2h0cywgc2NlbmUsIGNhbWVyYSApIHtcclxuXHJcblx0XHRpZiAoIHNjb3BlLmVuYWJsZWQgPT09IGZhbHNlICkgcmV0dXJuO1xyXG5cdFx0aWYgKCBzY29wZS5hdXRvVXBkYXRlID09PSBmYWxzZSAmJiBzY29wZS5uZWVkc1VwZGF0ZSA9PT0gZmFsc2UgKSByZXR1cm47XHJcblxyXG5cdFx0aWYgKCBsaWdodHMubGVuZ3RoID09PSAwICkgcmV0dXJuO1xyXG5cclxuXHRcdGNvbnN0IGN1cnJlbnRSZW5kZXJUYXJnZXQgPSBfcmVuZGVyZXIuZ2V0UmVuZGVyVGFyZ2V0KCk7XHJcblx0XHRjb25zdCBhY3RpdmVDdWJlRmFjZSA9IF9yZW5kZXJlci5nZXRBY3RpdmVDdWJlRmFjZSgpO1xyXG5cdFx0Y29uc3QgYWN0aXZlTWlwbWFwTGV2ZWwgPSBfcmVuZGVyZXIuZ2V0QWN0aXZlTWlwbWFwTGV2ZWwoKTtcclxuXHJcblx0XHRjb25zdCBfc3RhdGUgPSBfcmVuZGVyZXIuc3RhdGU7XHJcblxyXG5cdFx0Ly8gU2V0IEdMIHN0YXRlIGZvciBkZXB0aCBtYXAuXHJcblx0XHRfc3RhdGUuc2V0QmxlbmRpbmcoIE5vQmxlbmRpbmcgKTtcclxuXHRcdF9zdGF0ZS5idWZmZXJzLmNvbG9yLnNldENsZWFyKCAxLCAxLCAxLCAxICk7XHJcblx0XHRfc3RhdGUuYnVmZmVycy5kZXB0aC5zZXRUZXN0KCB0cnVlICk7XHJcblx0XHRfc3RhdGUuc2V0U2Npc3NvclRlc3QoIGZhbHNlICk7XHJcblxyXG5cdFx0Ly8gY2hlY2sgZm9yIHNoYWRvdyBtYXAgdHlwZSBjaGFuZ2VzXHJcblxyXG5cdFx0Y29uc3QgdG9WU00gPSAoIF9wcmV2aW91c1R5cGUgIT09IFZTTVNoYWRvd01hcCAmJiB0aGlzLnR5cGUgPT09IFZTTVNoYWRvd01hcCApO1xyXG5cdFx0Y29uc3QgZnJvbVZTTSA9ICggX3ByZXZpb3VzVHlwZSA9PT0gVlNNU2hhZG93TWFwICYmIHRoaXMudHlwZSAhPT0gVlNNU2hhZG93TWFwICk7XHJcblxyXG5cdFx0Ly8gcmVuZGVyIGRlcHRoIG1hcFxyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSBsaWdodHMubGVuZ3RoOyBpIDwgaWw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBsaWdodCA9IGxpZ2h0c1sgaSBdO1xyXG5cdFx0XHRjb25zdCBzaGFkb3cgPSBsaWdodC5zaGFkb3c7XHJcblxyXG5cdFx0XHRpZiAoIHNoYWRvdyA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5XZWJHTFNoYWRvd01hcDonLCBsaWdodCwgJ2hhcyBubyBzaGFkb3cuJyApO1xyXG5cdFx0XHRcdGNvbnRpbnVlO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0aWYgKCBzaGFkb3cuYXV0b1VwZGF0ZSA9PT0gZmFsc2UgJiYgc2hhZG93Lm5lZWRzVXBkYXRlID09PSBmYWxzZSApIGNvbnRpbnVlO1xyXG5cclxuXHRcdFx0X3NoYWRvd01hcFNpemUuY29weSggc2hhZG93Lm1hcFNpemUgKTtcclxuXHJcblx0XHRcdGNvbnN0IHNoYWRvd0ZyYW1lRXh0ZW50cyA9IHNoYWRvdy5nZXRGcmFtZUV4dGVudHMoKTtcclxuXHJcblx0XHRcdF9zaGFkb3dNYXBTaXplLm11bHRpcGx5KCBzaGFkb3dGcmFtZUV4dGVudHMgKTtcclxuXHJcblx0XHRcdF92aWV3cG9ydFNpemUuY29weSggc2hhZG93Lm1hcFNpemUgKTtcclxuXHJcblx0XHRcdGlmICggX3NoYWRvd01hcFNpemUueCA+IF9tYXhUZXh0dXJlU2l6ZSB8fCBfc2hhZG93TWFwU2l6ZS55ID4gX21heFRleHR1cmVTaXplICkge1xyXG5cclxuXHRcdFx0XHRpZiAoIF9zaGFkb3dNYXBTaXplLnggPiBfbWF4VGV4dHVyZVNpemUgKSB7XHJcblxyXG5cdFx0XHRcdFx0X3ZpZXdwb3J0U2l6ZS54ID0gTWF0aC5mbG9vciggX21heFRleHR1cmVTaXplIC8gc2hhZG93RnJhbWVFeHRlbnRzLnggKTtcclxuXHRcdFx0XHRcdF9zaGFkb3dNYXBTaXplLnggPSBfdmlld3BvcnRTaXplLnggKiBzaGFkb3dGcmFtZUV4dGVudHMueDtcclxuXHRcdFx0XHRcdHNoYWRvdy5tYXBTaXplLnggPSBfdmlld3BvcnRTaXplLng7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0aWYgKCBfc2hhZG93TWFwU2l6ZS55ID4gX21heFRleHR1cmVTaXplICkge1xyXG5cclxuXHRcdFx0XHRcdF92aWV3cG9ydFNpemUueSA9IE1hdGguZmxvb3IoIF9tYXhUZXh0dXJlU2l6ZSAvIHNoYWRvd0ZyYW1lRXh0ZW50cy55ICk7XHJcblx0XHRcdFx0XHRfc2hhZG93TWFwU2l6ZS55ID0gX3ZpZXdwb3J0U2l6ZS55ICogc2hhZG93RnJhbWVFeHRlbnRzLnk7XHJcblx0XHRcdFx0XHRzaGFkb3cubWFwU2l6ZS55ID0gX3ZpZXdwb3J0U2l6ZS55O1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRpZiAoIHNoYWRvdy5tYXAgPT09IG51bGwgfHwgdG9WU00gPT09IHRydWUgfHwgZnJvbVZTTSA9PT0gdHJ1ZSApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgcGFycyA9ICggdGhpcy50eXBlICE9PSBWU01TaGFkb3dNYXAgKSA/IHsgbWluRmlsdGVyOiBOZWFyZXN0RmlsdGVyLCBtYWdGaWx0ZXI6IE5lYXJlc3RGaWx0ZXIgfSA6IHt9O1xyXG5cclxuXHRcdFx0XHRpZiAoIHNoYWRvdy5tYXAgIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdFx0c2hhZG93Lm1hcC5kaXNwb3NlKCk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0c2hhZG93Lm1hcCA9IG5ldyBXZWJHTFJlbmRlclRhcmdldCggX3NoYWRvd01hcFNpemUueCwgX3NoYWRvd01hcFNpemUueSwgcGFycyApO1xyXG5cdFx0XHRcdHNoYWRvdy5tYXAudGV4dHVyZS5uYW1lID0gbGlnaHQubmFtZSArICcuc2hhZG93TWFwJztcclxuXHJcblx0XHRcdFx0c2hhZG93LmNhbWVyYS51cGRhdGVQcm9qZWN0aW9uTWF0cml4KCk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRfcmVuZGVyZXIuc2V0UmVuZGVyVGFyZ2V0KCBzaGFkb3cubWFwICk7XHJcblx0XHRcdF9yZW5kZXJlci5jbGVhcigpO1xyXG5cclxuXHRcdFx0Y29uc3Qgdmlld3BvcnRDb3VudCA9IHNoYWRvdy5nZXRWaWV3cG9ydENvdW50KCk7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgdnAgPSAwOyB2cCA8IHZpZXdwb3J0Q291bnQ7IHZwICsrICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCB2aWV3cG9ydCA9IHNoYWRvdy5nZXRWaWV3cG9ydCggdnAgKTtcclxuXHJcblx0XHRcdFx0X3ZpZXdwb3J0LnNldChcclxuXHRcdFx0XHRcdF92aWV3cG9ydFNpemUueCAqIHZpZXdwb3J0LngsXHJcblx0XHRcdFx0XHRfdmlld3BvcnRTaXplLnkgKiB2aWV3cG9ydC55LFxyXG5cdFx0XHRcdFx0X3ZpZXdwb3J0U2l6ZS54ICogdmlld3BvcnQueixcclxuXHRcdFx0XHRcdF92aWV3cG9ydFNpemUueSAqIHZpZXdwb3J0LndcclxuXHRcdFx0XHQpO1xyXG5cclxuXHRcdFx0XHRfc3RhdGUudmlld3BvcnQoIF92aWV3cG9ydCApO1xyXG5cclxuXHRcdFx0XHRzaGFkb3cudXBkYXRlTWF0cmljZXMoIGxpZ2h0LCB2cCApO1xyXG5cclxuXHRcdFx0XHRfZnJ1c3R1bSA9IHNoYWRvdy5nZXRGcnVzdHVtKCk7XHJcblxyXG5cdFx0XHRcdHJlbmRlck9iamVjdCggc2NlbmUsIGNhbWVyYSwgc2hhZG93LmNhbWVyYSwgbGlnaHQsIHRoaXMudHlwZSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Ly8gZG8gYmx1ciBwYXNzIGZvciBWU01cclxuXHJcblx0XHRcdGlmICggc2hhZG93LmlzUG9pbnRMaWdodFNoYWRvdyAhPT0gdHJ1ZSAmJiB0aGlzLnR5cGUgPT09IFZTTVNoYWRvd01hcCApIHtcclxuXHJcblx0XHRcdFx0VlNNUGFzcyggc2hhZG93LCBjYW1lcmEgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHNoYWRvdy5uZWVkc1VwZGF0ZSA9IGZhbHNlO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRfcHJldmlvdXNUeXBlID0gdGhpcy50eXBlO1xyXG5cclxuXHRcdHNjb3BlLm5lZWRzVXBkYXRlID0gZmFsc2U7XHJcblxyXG5cdFx0X3JlbmRlcmVyLnNldFJlbmRlclRhcmdldCggY3VycmVudFJlbmRlclRhcmdldCwgYWN0aXZlQ3ViZUZhY2UsIGFjdGl2ZU1pcG1hcExldmVsICk7XHJcblxyXG5cdH07XHJcblxyXG5cdGZ1bmN0aW9uIFZTTVBhc3MoIHNoYWRvdywgY2FtZXJhICkge1xyXG5cclxuXHRcdGNvbnN0IGdlb21ldHJ5ID0gX29iamVjdHMudXBkYXRlKCBmdWxsU2NyZWVuTWVzaCApO1xyXG5cclxuXHRcdGlmICggc2hhZG93TWF0ZXJpYWxWZXJ0aWNhbC5kZWZpbmVzLlZTTV9TQU1QTEVTICE9PSBzaGFkb3cuYmx1clNhbXBsZXMgKSB7XHJcblxyXG5cdFx0XHRzaGFkb3dNYXRlcmlhbFZlcnRpY2FsLmRlZmluZXMuVlNNX1NBTVBMRVMgPSBzaGFkb3cuYmx1clNhbXBsZXM7XHJcblx0XHRcdHNoYWRvd01hdGVyaWFsSG9yaXpvbnRhbC5kZWZpbmVzLlZTTV9TQU1QTEVTID0gc2hhZG93LmJsdXJTYW1wbGVzO1xyXG5cclxuXHRcdFx0c2hhZG93TWF0ZXJpYWxWZXJ0aWNhbC5uZWVkc1VwZGF0ZSA9IHRydWU7XHJcblx0XHRcdHNoYWRvd01hdGVyaWFsSG9yaXpvbnRhbC5uZWVkc1VwZGF0ZSA9IHRydWU7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggc2hhZG93Lm1hcFBhc3MgPT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRzaGFkb3cubWFwUGFzcyA9IG5ldyBXZWJHTFJlbmRlclRhcmdldCggX3NoYWRvd01hcFNpemUueCwgX3NoYWRvd01hcFNpemUueSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvLyB2ZXJ0aWNhbCBwYXNzXHJcblxyXG5cdFx0c2hhZG93TWF0ZXJpYWxWZXJ0aWNhbC51bmlmb3Jtcy5zaGFkb3dfcGFzcy52YWx1ZSA9IHNoYWRvdy5tYXAudGV4dHVyZTtcclxuXHRcdHNoYWRvd01hdGVyaWFsVmVydGljYWwudW5pZm9ybXMucmVzb2x1dGlvbi52YWx1ZSA9IHNoYWRvdy5tYXBTaXplO1xyXG5cdFx0c2hhZG93TWF0ZXJpYWxWZXJ0aWNhbC51bmlmb3Jtcy5yYWRpdXMudmFsdWUgPSBzaGFkb3cucmFkaXVzO1xyXG5cdFx0X3JlbmRlcmVyLnNldFJlbmRlclRhcmdldCggc2hhZG93Lm1hcFBhc3MgKTtcclxuXHRcdF9yZW5kZXJlci5jbGVhcigpO1xyXG5cdFx0X3JlbmRlcmVyLnJlbmRlckJ1ZmZlckRpcmVjdCggY2FtZXJhLCBudWxsLCBnZW9tZXRyeSwgc2hhZG93TWF0ZXJpYWxWZXJ0aWNhbCwgZnVsbFNjcmVlbk1lc2gsIG51bGwgKTtcclxuXHJcblx0XHQvLyBob3Jpem9udGFsIHBhc3NcclxuXHJcblx0XHRzaGFkb3dNYXRlcmlhbEhvcml6b250YWwudW5pZm9ybXMuc2hhZG93X3Bhc3MudmFsdWUgPSBzaGFkb3cubWFwUGFzcy50ZXh0dXJlO1xyXG5cdFx0c2hhZG93TWF0ZXJpYWxIb3Jpem9udGFsLnVuaWZvcm1zLnJlc29sdXRpb24udmFsdWUgPSBzaGFkb3cubWFwU2l6ZTtcclxuXHRcdHNoYWRvd01hdGVyaWFsSG9yaXpvbnRhbC51bmlmb3Jtcy5yYWRpdXMudmFsdWUgPSBzaGFkb3cucmFkaXVzO1xyXG5cdFx0X3JlbmRlcmVyLnNldFJlbmRlclRhcmdldCggc2hhZG93Lm1hcCApO1xyXG5cdFx0X3JlbmRlcmVyLmNsZWFyKCk7XHJcblx0XHRfcmVuZGVyZXIucmVuZGVyQnVmZmVyRGlyZWN0KCBjYW1lcmEsIG51bGwsIGdlb21ldHJ5LCBzaGFkb3dNYXRlcmlhbEhvcml6b250YWwsIGZ1bGxTY3JlZW5NZXNoLCBudWxsICk7XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gZ2V0RGVwdGhNYXRlcmlhbCggb2JqZWN0LCBtYXRlcmlhbCwgbGlnaHQsIHR5cGUgKSB7XHJcblxyXG5cdFx0bGV0IHJlc3VsdCA9IG51bGw7XHJcblxyXG5cdFx0Y29uc3QgY3VzdG9tTWF0ZXJpYWwgPSAoIGxpZ2h0LmlzUG9pbnRMaWdodCA9PT0gdHJ1ZSApID8gb2JqZWN0LmN1c3RvbURpc3RhbmNlTWF0ZXJpYWwgOiBvYmplY3QuY3VzdG9tRGVwdGhNYXRlcmlhbDtcclxuXHJcblx0XHRpZiAoIGN1c3RvbU1hdGVyaWFsICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRyZXN1bHQgPSBjdXN0b21NYXRlcmlhbDtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0cmVzdWx0ID0gKCBsaWdodC5pc1BvaW50TGlnaHQgPT09IHRydWUgKSA/IF9kaXN0YW5jZU1hdGVyaWFsIDogX2RlcHRoTWF0ZXJpYWw7XHJcblxyXG5cdFx0XHRpZiAoICggX3JlbmRlcmVyLmxvY2FsQ2xpcHBpbmdFbmFibGVkICYmIG1hdGVyaWFsLmNsaXBTaGFkb3dzID09PSB0cnVlICYmIEFycmF5LmlzQXJyYXkoIG1hdGVyaWFsLmNsaXBwaW5nUGxhbmVzICkgJiYgbWF0ZXJpYWwuY2xpcHBpbmdQbGFuZXMubGVuZ3RoICE9PSAwICkgfHxcclxuXHRcdFx0XHQoIG1hdGVyaWFsLmRpc3BsYWNlbWVudE1hcCAmJiBtYXRlcmlhbC5kaXNwbGFjZW1lbnRTY2FsZSAhPT0gMCApIHx8XHJcblx0XHRcdFx0KCBtYXRlcmlhbC5hbHBoYU1hcCAmJiBtYXRlcmlhbC5hbHBoYVRlc3QgPiAwICkgfHxcclxuXHRcdFx0XHQoIG1hdGVyaWFsLm1hcCAmJiBtYXRlcmlhbC5hbHBoYVRlc3QgPiAwICkgKSB7XHJcblxyXG5cdFx0XHRcdC8vIGluIHRoaXMgY2FzZSB3ZSBuZWVkIGEgdW5pcXVlIG1hdGVyaWFsIGluc3RhbmNlIHJlZmxlY3RpbmcgdGhlXHJcblx0XHRcdFx0Ly8gYXBwcm9wcmlhdGUgc3RhdGVcclxuXHJcblx0XHRcdFx0Y29uc3Qga2V5QSA9IHJlc3VsdC51dWlkLCBrZXlCID0gbWF0ZXJpYWwudXVpZDtcclxuXHJcblx0XHRcdFx0bGV0IG1hdGVyaWFsc0ZvclZhcmlhbnQgPSBfbWF0ZXJpYWxDYWNoZVsga2V5QSBdO1xyXG5cclxuXHRcdFx0XHRpZiAoIG1hdGVyaWFsc0ZvclZhcmlhbnQgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0XHRtYXRlcmlhbHNGb3JWYXJpYW50ID0ge307XHJcblx0XHRcdFx0XHRfbWF0ZXJpYWxDYWNoZVsga2V5QSBdID0gbWF0ZXJpYWxzRm9yVmFyaWFudDtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRsZXQgY2FjaGVkTWF0ZXJpYWwgPSBtYXRlcmlhbHNGb3JWYXJpYW50WyBrZXlCIF07XHJcblxyXG5cdFx0XHRcdGlmICggY2FjaGVkTWF0ZXJpYWwgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0XHRjYWNoZWRNYXRlcmlhbCA9IHJlc3VsdC5jbG9uZSgpO1xyXG5cdFx0XHRcdFx0bWF0ZXJpYWxzRm9yVmFyaWFudFsga2V5QiBdID0gY2FjaGVkTWF0ZXJpYWw7XHJcblx0XHRcdFx0XHRtYXRlcmlhbC5hZGRFdmVudExpc3RlbmVyKCAnZGlzcG9zZScsIG9uTWF0ZXJpYWxEaXNwb3NlICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0cmVzdWx0ID0gY2FjaGVkTWF0ZXJpYWw7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJlc3VsdC52aXNpYmxlID0gbWF0ZXJpYWwudmlzaWJsZTtcclxuXHRcdHJlc3VsdC53aXJlZnJhbWUgPSBtYXRlcmlhbC53aXJlZnJhbWU7XHJcblxyXG5cdFx0aWYgKCB0eXBlID09PSBWU01TaGFkb3dNYXAgKSB7XHJcblxyXG5cdFx0XHRyZXN1bHQuc2lkZSA9ICggbWF0ZXJpYWwuc2hhZG93U2lkZSAhPT0gbnVsbCApID8gbWF0ZXJpYWwuc2hhZG93U2lkZSA6IG1hdGVyaWFsLnNpZGU7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdHJlc3VsdC5zaWRlID0gKCBtYXRlcmlhbC5zaGFkb3dTaWRlICE9PSBudWxsICkgPyBtYXRlcmlhbC5zaGFkb3dTaWRlIDogc2hhZG93U2lkZVsgbWF0ZXJpYWwuc2lkZSBdO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXN1bHQuYWxwaGFNYXAgPSBtYXRlcmlhbC5hbHBoYU1hcDtcclxuXHRcdHJlc3VsdC5hbHBoYVRlc3QgPSBtYXRlcmlhbC5hbHBoYVRlc3Q7XHJcblx0XHRyZXN1bHQubWFwID0gbWF0ZXJpYWwubWFwO1xyXG5cclxuXHRcdHJlc3VsdC5jbGlwU2hhZG93cyA9IG1hdGVyaWFsLmNsaXBTaGFkb3dzO1xyXG5cdFx0cmVzdWx0LmNsaXBwaW5nUGxhbmVzID0gbWF0ZXJpYWwuY2xpcHBpbmdQbGFuZXM7XHJcblx0XHRyZXN1bHQuY2xpcEludGVyc2VjdGlvbiA9IG1hdGVyaWFsLmNsaXBJbnRlcnNlY3Rpb247XHJcblxyXG5cdFx0cmVzdWx0LmRpc3BsYWNlbWVudE1hcCA9IG1hdGVyaWFsLmRpc3BsYWNlbWVudE1hcDtcclxuXHRcdHJlc3VsdC5kaXNwbGFjZW1lbnRTY2FsZSA9IG1hdGVyaWFsLmRpc3BsYWNlbWVudFNjYWxlO1xyXG5cdFx0cmVzdWx0LmRpc3BsYWNlbWVudEJpYXMgPSBtYXRlcmlhbC5kaXNwbGFjZW1lbnRCaWFzO1xyXG5cclxuXHRcdHJlc3VsdC53aXJlZnJhbWVMaW5ld2lkdGggPSBtYXRlcmlhbC53aXJlZnJhbWVMaW5ld2lkdGg7XHJcblx0XHRyZXN1bHQubGluZXdpZHRoID0gbWF0ZXJpYWwubGluZXdpZHRoO1xyXG5cclxuXHRcdGlmICggbGlnaHQuaXNQb2ludExpZ2h0ID09PSB0cnVlICYmIHJlc3VsdC5pc01lc2hEaXN0YW5jZU1hdGVyaWFsID09PSB0cnVlICkge1xyXG5cclxuXHRcdFx0Y29uc3QgbWF0ZXJpYWxQcm9wZXJ0aWVzID0gX3JlbmRlcmVyLnByb3BlcnRpZXMuZ2V0KCByZXN1bHQgKTtcclxuXHRcdFx0bWF0ZXJpYWxQcm9wZXJ0aWVzLmxpZ2h0ID0gbGlnaHQ7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiByZXN1bHQ7XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gcmVuZGVyT2JqZWN0KCBvYmplY3QsIGNhbWVyYSwgc2hhZG93Q2FtZXJhLCBsaWdodCwgdHlwZSApIHtcclxuXHJcblx0XHRpZiAoIG9iamVjdC52aXNpYmxlID09PSBmYWxzZSApIHJldHVybjtcclxuXHJcblx0XHRjb25zdCB2aXNpYmxlID0gb2JqZWN0LmxheWVycy50ZXN0KCBjYW1lcmEubGF5ZXJzICk7XHJcblxyXG5cdFx0aWYgKCB2aXNpYmxlICYmICggb2JqZWN0LmlzTWVzaCB8fCBvYmplY3QuaXNMaW5lIHx8IG9iamVjdC5pc1BvaW50cyApICkge1xyXG5cclxuXHRcdFx0aWYgKCAoIG9iamVjdC5jYXN0U2hhZG93IHx8ICggb2JqZWN0LnJlY2VpdmVTaGFkb3cgJiYgdHlwZSA9PT0gVlNNU2hhZG93TWFwICkgKSAmJiAoICEgb2JqZWN0LmZydXN0dW1DdWxsZWQgfHwgX2ZydXN0dW0uaW50ZXJzZWN0c09iamVjdCggb2JqZWN0ICkgKSApIHtcclxuXHJcblx0XHRcdFx0b2JqZWN0Lm1vZGVsVmlld01hdHJpeC5tdWx0aXBseU1hdHJpY2VzKCBzaGFkb3dDYW1lcmEubWF0cml4V29ybGRJbnZlcnNlLCBvYmplY3QubWF0cml4V29ybGQgKTtcclxuXHJcblx0XHRcdFx0Y29uc3QgZ2VvbWV0cnkgPSBfb2JqZWN0cy51cGRhdGUoIG9iamVjdCApO1xyXG5cdFx0XHRcdGNvbnN0IG1hdGVyaWFsID0gb2JqZWN0Lm1hdGVyaWFsO1xyXG5cclxuXHRcdFx0XHRpZiAoIEFycmF5LmlzQXJyYXkoIG1hdGVyaWFsICkgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgZ3JvdXBzID0gZ2VvbWV0cnkuZ3JvdXBzO1xyXG5cclxuXHRcdFx0XHRcdGZvciAoIGxldCBrID0gMCwga2wgPSBncm91cHMubGVuZ3RoOyBrIDwga2w7IGsgKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRjb25zdCBncm91cCA9IGdyb3Vwc1sgayBdO1xyXG5cdFx0XHRcdFx0XHRjb25zdCBncm91cE1hdGVyaWFsID0gbWF0ZXJpYWxbIGdyb3VwLm1hdGVyaWFsSW5kZXggXTtcclxuXHJcblx0XHRcdFx0XHRcdGlmICggZ3JvdXBNYXRlcmlhbCAmJiBncm91cE1hdGVyaWFsLnZpc2libGUgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdGNvbnN0IGRlcHRoTWF0ZXJpYWwgPSBnZXREZXB0aE1hdGVyaWFsKCBvYmplY3QsIGdyb3VwTWF0ZXJpYWwsIGxpZ2h0LCB0eXBlICk7XHJcblxyXG5cdFx0XHRcdFx0XHRcdG9iamVjdC5vbkJlZm9yZVNoYWRvdyggX3JlbmRlcmVyLCBvYmplY3QsIGNhbWVyYSwgc2hhZG93Q2FtZXJhLCBnZW9tZXRyeSwgZGVwdGhNYXRlcmlhbCwgZ3JvdXAgKTtcclxuXHJcblx0XHRcdFx0XHRcdFx0X3JlbmRlcmVyLnJlbmRlckJ1ZmZlckRpcmVjdCggc2hhZG93Q2FtZXJhLCBudWxsLCBnZW9tZXRyeSwgZGVwdGhNYXRlcmlhbCwgb2JqZWN0LCBncm91cCApO1xyXG5cclxuXHRcdFx0XHRcdFx0XHRvYmplY3Qub25BZnRlclNoYWRvdyggX3JlbmRlcmVyLCBvYmplY3QsIGNhbWVyYSwgc2hhZG93Q2FtZXJhLCBnZW9tZXRyeSwgZGVwdGhNYXRlcmlhbCwgZ3JvdXAgKTtcclxuXHJcblx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH0gZWxzZSBpZiAoIG1hdGVyaWFsLnZpc2libGUgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgZGVwdGhNYXRlcmlhbCA9IGdldERlcHRoTWF0ZXJpYWwoIG9iamVjdCwgbWF0ZXJpYWwsIGxpZ2h0LCB0eXBlICk7XHJcblxyXG5cdFx0XHRcdFx0b2JqZWN0Lm9uQmVmb3JlU2hhZG93KCBfcmVuZGVyZXIsIG9iamVjdCwgY2FtZXJhLCBzaGFkb3dDYW1lcmEsIGdlb21ldHJ5LCBkZXB0aE1hdGVyaWFsLCBudWxsICk7XHJcblxyXG5cdFx0XHRcdFx0X3JlbmRlcmVyLnJlbmRlckJ1ZmZlckRpcmVjdCggc2hhZG93Q2FtZXJhLCBudWxsLCBnZW9tZXRyeSwgZGVwdGhNYXRlcmlhbCwgb2JqZWN0LCBudWxsICk7XHJcblxyXG5cdFx0XHRcdFx0b2JqZWN0Lm9uQWZ0ZXJTaGFkb3coIF9yZW5kZXJlciwgb2JqZWN0LCBjYW1lcmEsIHNoYWRvd0NhbWVyYSwgZ2VvbWV0cnksIGRlcHRoTWF0ZXJpYWwsIG51bGwgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCBjaGlsZHJlbiA9IG9iamVjdC5jaGlsZHJlbjtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBjaGlsZHJlbi5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0cmVuZGVyT2JqZWN0KCBjaGlsZHJlblsgaSBdLCBjYW1lcmEsIHNoYWRvd0NhbWVyYSwgbGlnaHQsIHR5cGUgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gb25NYXRlcmlhbERpc3Bvc2UoIGV2ZW50ICkge1xyXG5cclxuXHRcdGNvbnN0IG1hdGVyaWFsID0gZXZlbnQudGFyZ2V0O1xyXG5cclxuXHRcdG1hdGVyaWFsLnJlbW92ZUV2ZW50TGlzdGVuZXIoICdkaXNwb3NlJywgb25NYXRlcmlhbERpc3Bvc2UgKTtcclxuXHJcblx0XHQvLyBtYWtlIHN1cmUgdG8gcmVtb3ZlIHRoZSB1bmlxdWUgZGlzdGFuY2UvZGVwdGggbWF0ZXJpYWxzIHVzZWQgZm9yIHNoYWRvdyBtYXAgcmVuZGVyaW5nXHJcblxyXG5cdFx0Zm9yICggY29uc3QgaWQgaW4gX21hdGVyaWFsQ2FjaGUgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBjYWNoZSA9IF9tYXRlcmlhbENhY2hlWyBpZCBdO1xyXG5cclxuXHRcdFx0Y29uc3QgdXVpZCA9IGV2ZW50LnRhcmdldC51dWlkO1xyXG5cclxuXHRcdFx0aWYgKCB1dWlkIGluIGNhY2hlICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBzaGFkb3dNYXRlcmlhbCA9IGNhY2hlWyB1dWlkIF07XHJcblx0XHRcdFx0c2hhZG93TWF0ZXJpYWwuZGlzcG9zZSgpO1xyXG5cdFx0XHRcdGRlbGV0ZSBjYWNoZVsgdXVpZCBdO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuXHJcbmV4cG9ydCB7IFdlYkdMU2hhZG93TWFwIH07XHJcbiIsImltcG9ydCB7IE5vdEVxdWFsRGVwdGgsIEdyZWF0ZXJEZXB0aCwgR3JlYXRlckVxdWFsRGVwdGgsIEVxdWFsRGVwdGgsIExlc3NFcXVhbERlcHRoLCBMZXNzRGVwdGgsIEFsd2F5c0RlcHRoLCBOZXZlckRlcHRoLCBDdWxsRmFjZUZyb250LCBDdWxsRmFjZUJhY2ssIEN1bGxGYWNlTm9uZSwgRG91YmxlU2lkZSwgQmFja1NpZGUsIEN1c3RvbUJsZW5kaW5nLCBNdWx0aXBseUJsZW5kaW5nLCBTdWJ0cmFjdGl2ZUJsZW5kaW5nLCBBZGRpdGl2ZUJsZW5kaW5nLCBOb0JsZW5kaW5nLCBOb3JtYWxCbGVuZGluZywgQWRkRXF1YXRpb24sIFN1YnRyYWN0RXF1YXRpb24sIFJldmVyc2VTdWJ0cmFjdEVxdWF0aW9uLCBNaW5FcXVhdGlvbiwgTWF4RXF1YXRpb24sIFplcm9GYWN0b3IsIE9uZUZhY3RvciwgU3JjQ29sb3JGYWN0b3IsIFNyY0FscGhhRmFjdG9yLCBTcmNBbHBoYVNhdHVyYXRlRmFjdG9yLCBEc3RDb2xvckZhY3RvciwgRHN0QWxwaGFGYWN0b3IsIE9uZU1pbnVzU3JjQ29sb3JGYWN0b3IsIE9uZU1pbnVzU3JjQWxwaGFGYWN0b3IsIE9uZU1pbnVzRHN0Q29sb3JGYWN0b3IsIE9uZU1pbnVzRHN0QWxwaGFGYWN0b3IsIENvbnN0YW50Q29sb3JGYWN0b3IsIE9uZU1pbnVzQ29uc3RhbnRDb2xvckZhY3RvciwgQ29uc3RhbnRBbHBoYUZhY3RvciwgT25lTWludXNDb25zdGFudEFscGhhRmFjdG9yIH0gZnJvbSAnLi4vLi4vY29uc3RhbnRzLmpzJztcclxuaW1wb3J0IHsgQ29sb3IgfSBmcm9tICcuLi8uLi9tYXRoL0NvbG9yLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yNCB9IGZyb20gJy4uLy4uL21hdGgvVmVjdG9yNC5qcyc7XHJcblxyXG5mdW5jdGlvbiBXZWJHTFN0YXRlKCBnbCwgZXh0ZW5zaW9ucywgY2FwYWJpbGl0aWVzICkge1xyXG5cclxuXHRjb25zdCBpc1dlYkdMMiA9IGNhcGFiaWxpdGllcy5pc1dlYkdMMjtcclxuXHJcblx0ZnVuY3Rpb24gQ29sb3JCdWZmZXIoKSB7XHJcblxyXG5cdFx0bGV0IGxvY2tlZCA9IGZhbHNlO1xyXG5cclxuXHRcdGNvbnN0IGNvbG9yID0gbmV3IFZlY3RvcjQoKTtcclxuXHRcdGxldCBjdXJyZW50Q29sb3JNYXNrID0gbnVsbDtcclxuXHRcdGNvbnN0IGN1cnJlbnRDb2xvckNsZWFyID0gbmV3IFZlY3RvcjQoIDAsIDAsIDAsIDAgKTtcclxuXHJcblx0XHRyZXR1cm4ge1xyXG5cclxuXHRcdFx0c2V0TWFzazogZnVuY3Rpb24gKCBjb2xvck1hc2sgKSB7XHJcblxyXG5cdFx0XHRcdGlmICggY3VycmVudENvbG9yTWFzayAhPT0gY29sb3JNYXNrICYmICEgbG9ja2VkICkge1xyXG5cclxuXHRcdFx0XHRcdGdsLmNvbG9yTWFzayggY29sb3JNYXNrLCBjb2xvck1hc2ssIGNvbG9yTWFzaywgY29sb3JNYXNrICk7XHJcblx0XHRcdFx0XHRjdXJyZW50Q29sb3JNYXNrID0gY29sb3JNYXNrO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9LFxyXG5cclxuXHRcdFx0c2V0TG9ja2VkOiBmdW5jdGlvbiAoIGxvY2sgKSB7XHJcblxyXG5cdFx0XHRcdGxvY2tlZCA9IGxvY2s7XHJcblxyXG5cdFx0XHR9LFxyXG5cclxuXHRcdFx0c2V0Q2xlYXI6IGZ1bmN0aW9uICggciwgZywgYiwgYSwgcHJlbXVsdGlwbGllZEFscGhhICkge1xyXG5cclxuXHRcdFx0XHRpZiAoIHByZW11bHRpcGxpZWRBbHBoYSA9PT0gdHJ1ZSApIHtcclxuXHJcblx0XHRcdFx0XHRyICo9IGE7IGcgKj0gYTsgYiAqPSBhO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdGNvbG9yLnNldCggciwgZywgYiwgYSApO1xyXG5cclxuXHRcdFx0XHRpZiAoIGN1cnJlbnRDb2xvckNsZWFyLmVxdWFscyggY29sb3IgKSA9PT0gZmFsc2UgKSB7XHJcblxyXG5cdFx0XHRcdFx0Z2wuY2xlYXJDb2xvciggciwgZywgYiwgYSApO1xyXG5cdFx0XHRcdFx0Y3VycmVudENvbG9yQ2xlYXIuY29weSggY29sb3IgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fSxcclxuXHJcblx0XHRcdHJlc2V0OiBmdW5jdGlvbiAoKSB7XHJcblxyXG5cdFx0XHRcdGxvY2tlZCA9IGZhbHNlO1xyXG5cclxuXHRcdFx0XHRjdXJyZW50Q29sb3JNYXNrID0gbnVsbDtcclxuXHRcdFx0XHRjdXJyZW50Q29sb3JDbGVhci5zZXQoIC0gMSwgMCwgMCwgMCApOyAvLyBzZXQgdG8gaW52YWxpZCBzdGF0ZVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH07XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gRGVwdGhCdWZmZXIoKSB7XHJcblxyXG5cdFx0bGV0IGxvY2tlZCA9IGZhbHNlO1xyXG5cclxuXHRcdGxldCBjdXJyZW50RGVwdGhNYXNrID0gbnVsbDtcclxuXHRcdGxldCBjdXJyZW50RGVwdGhGdW5jID0gbnVsbDtcclxuXHRcdGxldCBjdXJyZW50RGVwdGhDbGVhciA9IG51bGw7XHJcblxyXG5cdFx0cmV0dXJuIHtcclxuXHJcblx0XHRcdHNldFRlc3Q6IGZ1bmN0aW9uICggZGVwdGhUZXN0ICkge1xyXG5cclxuXHRcdFx0XHRpZiAoIGRlcHRoVGVzdCApIHtcclxuXHJcblx0XHRcdFx0XHRlbmFibGUoIGdsLkRFUFRIX1RFU1QgKTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRkaXNhYmxlKCBnbC5ERVBUSF9URVNUICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH0sXHJcblxyXG5cdFx0XHRzZXRNYXNrOiBmdW5jdGlvbiAoIGRlcHRoTWFzayApIHtcclxuXHJcblx0XHRcdFx0aWYgKCBjdXJyZW50RGVwdGhNYXNrICE9PSBkZXB0aE1hc2sgJiYgISBsb2NrZWQgKSB7XHJcblxyXG5cdFx0XHRcdFx0Z2wuZGVwdGhNYXNrKCBkZXB0aE1hc2sgKTtcclxuXHRcdFx0XHRcdGN1cnJlbnREZXB0aE1hc2sgPSBkZXB0aE1hc2s7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH0sXHJcblxyXG5cdFx0XHRzZXRGdW5jOiBmdW5jdGlvbiAoIGRlcHRoRnVuYyApIHtcclxuXHJcblx0XHRcdFx0aWYgKCBjdXJyZW50RGVwdGhGdW5jICE9PSBkZXB0aEZ1bmMgKSB7XHJcblxyXG5cdFx0XHRcdFx0c3dpdGNoICggZGVwdGhGdW5jICkge1xyXG5cclxuXHRcdFx0XHRcdFx0Y2FzZSBOZXZlckRlcHRoOlxyXG5cclxuXHRcdFx0XHRcdFx0XHRnbC5kZXB0aEZ1bmMoIGdsLk5FVkVSICk7XHJcblx0XHRcdFx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRcdFx0XHRjYXNlIEFsd2F5c0RlcHRoOlxyXG5cclxuXHRcdFx0XHRcdFx0XHRnbC5kZXB0aEZ1bmMoIGdsLkFMV0FZUyApO1xyXG5cdFx0XHRcdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0XHRcdFx0Y2FzZSBMZXNzRGVwdGg6XHJcblxyXG5cdFx0XHRcdFx0XHRcdGdsLmRlcHRoRnVuYyggZ2wuTEVTUyApO1xyXG5cdFx0XHRcdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0XHRcdFx0Y2FzZSBMZXNzRXF1YWxEZXB0aDpcclxuXHJcblx0XHRcdFx0XHRcdFx0Z2wuZGVwdGhGdW5jKCBnbC5MRVFVQUwgKTtcclxuXHRcdFx0XHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdFx0XHRcdGNhc2UgRXF1YWxEZXB0aDpcclxuXHJcblx0XHRcdFx0XHRcdFx0Z2wuZGVwdGhGdW5jKCBnbC5FUVVBTCApO1xyXG5cdFx0XHRcdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0XHRcdFx0Y2FzZSBHcmVhdGVyRXF1YWxEZXB0aDpcclxuXHJcblx0XHRcdFx0XHRcdFx0Z2wuZGVwdGhGdW5jKCBnbC5HRVFVQUwgKTtcclxuXHRcdFx0XHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdFx0XHRcdGNhc2UgR3JlYXRlckRlcHRoOlxyXG5cclxuXHRcdFx0XHRcdFx0XHRnbC5kZXB0aEZ1bmMoIGdsLkdSRUFURVIgKTtcclxuXHRcdFx0XHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdFx0XHRcdGNhc2UgTm90RXF1YWxEZXB0aDpcclxuXHJcblx0XHRcdFx0XHRcdFx0Z2wuZGVwdGhGdW5jKCBnbC5OT1RFUVVBTCApO1xyXG5cdFx0XHRcdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0XHRcdFx0ZGVmYXVsdDpcclxuXHJcblx0XHRcdFx0XHRcdFx0Z2wuZGVwdGhGdW5jKCBnbC5MRVFVQUwgKTtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0Y3VycmVudERlcHRoRnVuYyA9IGRlcHRoRnVuYztcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fSxcclxuXHJcblx0XHRcdHNldExvY2tlZDogZnVuY3Rpb24gKCBsb2NrICkge1xyXG5cclxuXHRcdFx0XHRsb2NrZWQgPSBsb2NrO1xyXG5cclxuXHRcdFx0fSxcclxuXHJcblx0XHRcdHNldENsZWFyOiBmdW5jdGlvbiAoIGRlcHRoICkge1xyXG5cclxuXHRcdFx0XHRpZiAoIGN1cnJlbnREZXB0aENsZWFyICE9PSBkZXB0aCApIHtcclxuXHJcblx0XHRcdFx0XHRnbC5jbGVhckRlcHRoKCBkZXB0aCApO1xyXG5cdFx0XHRcdFx0Y3VycmVudERlcHRoQ2xlYXIgPSBkZXB0aDtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fSxcclxuXHJcblx0XHRcdHJlc2V0OiBmdW5jdGlvbiAoKSB7XHJcblxyXG5cdFx0XHRcdGxvY2tlZCA9IGZhbHNlO1xyXG5cclxuXHRcdFx0XHRjdXJyZW50RGVwdGhNYXNrID0gbnVsbDtcclxuXHRcdFx0XHRjdXJyZW50RGVwdGhGdW5jID0gbnVsbDtcclxuXHRcdFx0XHRjdXJyZW50RGVwdGhDbGVhciA9IG51bGw7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fTtcclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBTdGVuY2lsQnVmZmVyKCkge1xyXG5cclxuXHRcdGxldCBsb2NrZWQgPSBmYWxzZTtcclxuXHJcblx0XHRsZXQgY3VycmVudFN0ZW5jaWxNYXNrID0gbnVsbDtcclxuXHRcdGxldCBjdXJyZW50U3RlbmNpbEZ1bmMgPSBudWxsO1xyXG5cdFx0bGV0IGN1cnJlbnRTdGVuY2lsUmVmID0gbnVsbDtcclxuXHRcdGxldCBjdXJyZW50U3RlbmNpbEZ1bmNNYXNrID0gbnVsbDtcclxuXHRcdGxldCBjdXJyZW50U3RlbmNpbEZhaWwgPSBudWxsO1xyXG5cdFx0bGV0IGN1cnJlbnRTdGVuY2lsWkZhaWwgPSBudWxsO1xyXG5cdFx0bGV0IGN1cnJlbnRTdGVuY2lsWlBhc3MgPSBudWxsO1xyXG5cdFx0bGV0IGN1cnJlbnRTdGVuY2lsQ2xlYXIgPSBudWxsO1xyXG5cclxuXHRcdHJldHVybiB7XHJcblxyXG5cdFx0XHRzZXRUZXN0OiBmdW5jdGlvbiAoIHN0ZW5jaWxUZXN0ICkge1xyXG5cclxuXHRcdFx0XHRpZiAoICEgbG9ja2VkICkge1xyXG5cclxuXHRcdFx0XHRcdGlmICggc3RlbmNpbFRlc3QgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRlbmFibGUoIGdsLlNURU5DSUxfVEVTVCApO1xyXG5cclxuXHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHRkaXNhYmxlKCBnbC5TVEVOQ0lMX1RFU1QgKTtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH0sXHJcblxyXG5cdFx0XHRzZXRNYXNrOiBmdW5jdGlvbiAoIHN0ZW5jaWxNYXNrICkge1xyXG5cclxuXHRcdFx0XHRpZiAoIGN1cnJlbnRTdGVuY2lsTWFzayAhPT0gc3RlbmNpbE1hc2sgJiYgISBsb2NrZWQgKSB7XHJcblxyXG5cdFx0XHRcdFx0Z2wuc3RlbmNpbE1hc2soIHN0ZW5jaWxNYXNrICk7XHJcblx0XHRcdFx0XHRjdXJyZW50U3RlbmNpbE1hc2sgPSBzdGVuY2lsTWFzaztcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fSxcclxuXHJcblx0XHRcdHNldEZ1bmM6IGZ1bmN0aW9uICggc3RlbmNpbEZ1bmMsIHN0ZW5jaWxSZWYsIHN0ZW5jaWxNYXNrICkge1xyXG5cclxuXHRcdFx0XHRpZiAoIGN1cnJlbnRTdGVuY2lsRnVuYyAhPT0gc3RlbmNpbEZ1bmMgfHxcclxuXHRcdFx0XHQgICAgIGN1cnJlbnRTdGVuY2lsUmVmICE9PSBzdGVuY2lsUmVmIHx8XHJcblx0XHRcdFx0ICAgICBjdXJyZW50U3RlbmNpbEZ1bmNNYXNrICE9PSBzdGVuY2lsTWFzayApIHtcclxuXHJcblx0XHRcdFx0XHRnbC5zdGVuY2lsRnVuYyggc3RlbmNpbEZ1bmMsIHN0ZW5jaWxSZWYsIHN0ZW5jaWxNYXNrICk7XHJcblxyXG5cdFx0XHRcdFx0Y3VycmVudFN0ZW5jaWxGdW5jID0gc3RlbmNpbEZ1bmM7XHJcblx0XHRcdFx0XHRjdXJyZW50U3RlbmNpbFJlZiA9IHN0ZW5jaWxSZWY7XHJcblx0XHRcdFx0XHRjdXJyZW50U3RlbmNpbEZ1bmNNYXNrID0gc3RlbmNpbE1hc2s7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH0sXHJcblxyXG5cdFx0XHRzZXRPcDogZnVuY3Rpb24gKCBzdGVuY2lsRmFpbCwgc3RlbmNpbFpGYWlsLCBzdGVuY2lsWlBhc3MgKSB7XHJcblxyXG5cdFx0XHRcdGlmICggY3VycmVudFN0ZW5jaWxGYWlsICE9PSBzdGVuY2lsRmFpbCB8fFxyXG5cdFx0XHRcdCAgICAgY3VycmVudFN0ZW5jaWxaRmFpbCAhPT0gc3RlbmNpbFpGYWlsIHx8XHJcblx0XHRcdFx0ICAgICBjdXJyZW50U3RlbmNpbFpQYXNzICE9PSBzdGVuY2lsWlBhc3MgKSB7XHJcblxyXG5cdFx0XHRcdFx0Z2wuc3RlbmNpbE9wKCBzdGVuY2lsRmFpbCwgc3RlbmNpbFpGYWlsLCBzdGVuY2lsWlBhc3MgKTtcclxuXHJcblx0XHRcdFx0XHRjdXJyZW50U3RlbmNpbEZhaWwgPSBzdGVuY2lsRmFpbDtcclxuXHRcdFx0XHRcdGN1cnJlbnRTdGVuY2lsWkZhaWwgPSBzdGVuY2lsWkZhaWw7XHJcblx0XHRcdFx0XHRjdXJyZW50U3RlbmNpbFpQYXNzID0gc3RlbmNpbFpQYXNzO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9LFxyXG5cclxuXHRcdFx0c2V0TG9ja2VkOiBmdW5jdGlvbiAoIGxvY2sgKSB7XHJcblxyXG5cdFx0XHRcdGxvY2tlZCA9IGxvY2s7XHJcblxyXG5cdFx0XHR9LFxyXG5cclxuXHRcdFx0c2V0Q2xlYXI6IGZ1bmN0aW9uICggc3RlbmNpbCApIHtcclxuXHJcblx0XHRcdFx0aWYgKCBjdXJyZW50U3RlbmNpbENsZWFyICE9PSBzdGVuY2lsICkge1xyXG5cclxuXHRcdFx0XHRcdGdsLmNsZWFyU3RlbmNpbCggc3RlbmNpbCApO1xyXG5cdFx0XHRcdFx0Y3VycmVudFN0ZW5jaWxDbGVhciA9IHN0ZW5jaWw7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH0sXHJcblxyXG5cdFx0XHRyZXNldDogZnVuY3Rpb24gKCkge1xyXG5cclxuXHRcdFx0XHRsb2NrZWQgPSBmYWxzZTtcclxuXHJcblx0XHRcdFx0Y3VycmVudFN0ZW5jaWxNYXNrID0gbnVsbDtcclxuXHRcdFx0XHRjdXJyZW50U3RlbmNpbEZ1bmMgPSBudWxsO1xyXG5cdFx0XHRcdGN1cnJlbnRTdGVuY2lsUmVmID0gbnVsbDtcclxuXHRcdFx0XHRjdXJyZW50U3RlbmNpbEZ1bmNNYXNrID0gbnVsbDtcclxuXHRcdFx0XHRjdXJyZW50U3RlbmNpbEZhaWwgPSBudWxsO1xyXG5cdFx0XHRcdGN1cnJlbnRTdGVuY2lsWkZhaWwgPSBudWxsO1xyXG5cdFx0XHRcdGN1cnJlbnRTdGVuY2lsWlBhc3MgPSBudWxsO1xyXG5cdFx0XHRcdGN1cnJlbnRTdGVuY2lsQ2xlYXIgPSBudWxsO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH07XHJcblxyXG5cdH1cclxuXHJcblx0Ly9cclxuXHJcblx0Y29uc3QgY29sb3JCdWZmZXIgPSBuZXcgQ29sb3JCdWZmZXIoKTtcclxuXHRjb25zdCBkZXB0aEJ1ZmZlciA9IG5ldyBEZXB0aEJ1ZmZlcigpO1xyXG5cdGNvbnN0IHN0ZW5jaWxCdWZmZXIgPSBuZXcgU3RlbmNpbEJ1ZmZlcigpO1xyXG5cclxuXHRjb25zdCB1Ym9CaW5kaW5ncyA9IG5ldyBXZWFrTWFwKCk7XHJcblx0Y29uc3QgdWJvUHJvZ3JhbU1hcCA9IG5ldyBXZWFrTWFwKCk7XHJcblxyXG5cdGxldCBlbmFibGVkQ2FwYWJpbGl0aWVzID0ge307XHJcblxyXG5cdGxldCBjdXJyZW50Qm91bmRGcmFtZWJ1ZmZlcnMgPSB7fTtcclxuXHRsZXQgY3VycmVudERyYXdidWZmZXJzID0gbmV3IFdlYWtNYXAoKTtcclxuXHRsZXQgZGVmYXVsdERyYXdidWZmZXJzID0gW107XHJcblxyXG5cdGxldCBjdXJyZW50UHJvZ3JhbSA9IG51bGw7XHJcblxyXG5cdGxldCBjdXJyZW50QmxlbmRpbmdFbmFibGVkID0gZmFsc2U7XHJcblx0bGV0IGN1cnJlbnRCbGVuZGluZyA9IG51bGw7XHJcblx0bGV0IGN1cnJlbnRCbGVuZEVxdWF0aW9uID0gbnVsbDtcclxuXHRsZXQgY3VycmVudEJsZW5kU3JjID0gbnVsbDtcclxuXHRsZXQgY3VycmVudEJsZW5kRHN0ID0gbnVsbDtcclxuXHRsZXQgY3VycmVudEJsZW5kRXF1YXRpb25BbHBoYSA9IG51bGw7XHJcblx0bGV0IGN1cnJlbnRCbGVuZFNyY0FscGhhID0gbnVsbDtcclxuXHRsZXQgY3VycmVudEJsZW5kRHN0QWxwaGEgPSBudWxsO1xyXG5cdGxldCBjdXJyZW50QmxlbmRDb2xvciA9IG5ldyBDb2xvciggMCwgMCwgMCApO1xyXG5cdGxldCBjdXJyZW50QmxlbmRBbHBoYSA9IDA7XHJcblx0bGV0IGN1cnJlbnRQcmVtdWx0aXBsZWRBbHBoYSA9IGZhbHNlO1xyXG5cclxuXHRsZXQgY3VycmVudEZsaXBTaWRlZCA9IG51bGw7XHJcblx0bGV0IGN1cnJlbnRDdWxsRmFjZSA9IG51bGw7XHJcblxyXG5cdGxldCBjdXJyZW50TGluZVdpZHRoID0gbnVsbDtcclxuXHJcblx0bGV0IGN1cnJlbnRQb2x5Z29uT2Zmc2V0RmFjdG9yID0gbnVsbDtcclxuXHRsZXQgY3VycmVudFBvbHlnb25PZmZzZXRVbml0cyA9IG51bGw7XHJcblxyXG5cdGNvbnN0IG1heFRleHR1cmVzID0gZ2wuZ2V0UGFyYW1ldGVyKCBnbC5NQVhfQ09NQklORURfVEVYVFVSRV9JTUFHRV9VTklUUyApO1xyXG5cclxuXHRsZXQgbGluZVdpZHRoQXZhaWxhYmxlID0gZmFsc2U7XHJcblx0bGV0IHZlcnNpb24gPSAwO1xyXG5cdGNvbnN0IGdsVmVyc2lvbiA9IGdsLmdldFBhcmFtZXRlciggZ2wuVkVSU0lPTiApO1xyXG5cclxuXHRpZiAoIGdsVmVyc2lvbi5pbmRleE9mKCAnV2ViR0wnICkgIT09IC0gMSApIHtcclxuXHJcblx0XHR2ZXJzaW9uID0gcGFyc2VGbG9hdCggL15XZWJHTCAoXFxkKS8uZXhlYyggZ2xWZXJzaW9uIClbIDEgXSApO1xyXG5cdFx0bGluZVdpZHRoQXZhaWxhYmxlID0gKCB2ZXJzaW9uID49IDEuMCApO1xyXG5cclxuXHR9IGVsc2UgaWYgKCBnbFZlcnNpb24uaW5kZXhPZiggJ09wZW5HTCBFUycgKSAhPT0gLSAxICkge1xyXG5cclxuXHRcdHZlcnNpb24gPSBwYXJzZUZsb2F0KCAvXk9wZW5HTCBFUyAoXFxkKS8uZXhlYyggZ2xWZXJzaW9uIClbIDEgXSApO1xyXG5cdFx0bGluZVdpZHRoQXZhaWxhYmxlID0gKCB2ZXJzaW9uID49IDIuMCApO1xyXG5cclxuXHR9XHJcblxyXG5cdGxldCBjdXJyZW50VGV4dHVyZVNsb3QgPSBudWxsO1xyXG5cdGxldCBjdXJyZW50Qm91bmRUZXh0dXJlcyA9IHt9O1xyXG5cclxuXHRjb25zdCBzY2lzc29yUGFyYW0gPSBnbC5nZXRQYXJhbWV0ZXIoIGdsLlNDSVNTT1JfQk9YICk7XHJcblx0Y29uc3Qgdmlld3BvcnRQYXJhbSA9IGdsLmdldFBhcmFtZXRlciggZ2wuVklFV1BPUlQgKTtcclxuXHJcblx0Y29uc3QgY3VycmVudFNjaXNzb3IgPSBuZXcgVmVjdG9yNCgpLmZyb21BcnJheSggc2Npc3NvclBhcmFtICk7XHJcblx0Y29uc3QgY3VycmVudFZpZXdwb3J0ID0gbmV3IFZlY3RvcjQoKS5mcm9tQXJyYXkoIHZpZXdwb3J0UGFyYW0gKTtcclxuXHJcblx0ZnVuY3Rpb24gY3JlYXRlVGV4dHVyZSggdHlwZSwgdGFyZ2V0LCBjb3VudCwgZGltZW5zaW9ucyApIHtcclxuXHJcblx0XHRjb25zdCBkYXRhID0gbmV3IFVpbnQ4QXJyYXkoIDQgKTsgLy8gNCBpcyByZXF1aXJlZCB0byBtYXRjaCBkZWZhdWx0IHVucGFjayBhbGlnbm1lbnQgb2YgNC5cclxuXHRcdGNvbnN0IHRleHR1cmUgPSBnbC5jcmVhdGVUZXh0dXJlKCk7XHJcblxyXG5cdFx0Z2wuYmluZFRleHR1cmUoIHR5cGUsIHRleHR1cmUgKTtcclxuXHRcdGdsLnRleFBhcmFtZXRlcmkoIHR5cGUsIGdsLlRFWFRVUkVfTUlOX0ZJTFRFUiwgZ2wuTkVBUkVTVCApO1xyXG5cdFx0Z2wudGV4UGFyYW1ldGVyaSggdHlwZSwgZ2wuVEVYVFVSRV9NQUdfRklMVEVSLCBnbC5ORUFSRVNUICk7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgY291bnQ7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRpZiAoIGlzV2ViR0wyICYmICggdHlwZSA9PT0gZ2wuVEVYVFVSRV8zRCB8fCB0eXBlID09PSBnbC5URVhUVVJFXzJEX0FSUkFZICkgKSB7XHJcblxyXG5cdFx0XHRcdGdsLnRleEltYWdlM0QoIHRhcmdldCwgMCwgZ2wuUkdCQSwgMSwgMSwgZGltZW5zaW9ucywgMCwgZ2wuUkdCQSwgZ2wuVU5TSUdORURfQllURSwgZGF0YSApO1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0Z2wudGV4SW1hZ2UyRCggdGFyZ2V0ICsgaSwgMCwgZ2wuUkdCQSwgMSwgMSwgMCwgZ2wuUkdCQSwgZ2wuVU5TSUdORURfQllURSwgZGF0YSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGV4dHVyZTtcclxuXHJcblx0fVxyXG5cclxuXHRjb25zdCBlbXB0eVRleHR1cmVzID0ge307XHJcblx0ZW1wdHlUZXh0dXJlc1sgZ2wuVEVYVFVSRV8yRCBdID0gY3JlYXRlVGV4dHVyZSggZ2wuVEVYVFVSRV8yRCwgZ2wuVEVYVFVSRV8yRCwgMSApO1xyXG5cdGVtcHR5VGV4dHVyZXNbIGdsLlRFWFRVUkVfQ1VCRV9NQVAgXSA9IGNyZWF0ZVRleHR1cmUoIGdsLlRFWFRVUkVfQ1VCRV9NQVAsIGdsLlRFWFRVUkVfQ1VCRV9NQVBfUE9TSVRJVkVfWCwgNiApO1xyXG5cclxuXHRpZiAoIGlzV2ViR0wyICkge1xyXG5cclxuXHRcdGVtcHR5VGV4dHVyZXNbIGdsLlRFWFRVUkVfMkRfQVJSQVkgXSA9IGNyZWF0ZVRleHR1cmUoIGdsLlRFWFRVUkVfMkRfQVJSQVksIGdsLlRFWFRVUkVfMkRfQVJSQVksIDEsIDEgKTtcclxuXHRcdGVtcHR5VGV4dHVyZXNbIGdsLlRFWFRVUkVfM0QgXSA9IGNyZWF0ZVRleHR1cmUoIGdsLlRFWFRVUkVfM0QsIGdsLlRFWFRVUkVfM0QsIDEsIDEgKTtcclxuXHJcblx0fVxyXG5cclxuXHQvLyBpbml0XHJcblxyXG5cdGNvbG9yQnVmZmVyLnNldENsZWFyKCAwLCAwLCAwLCAxICk7XHJcblx0ZGVwdGhCdWZmZXIuc2V0Q2xlYXIoIDEgKTtcclxuXHRzdGVuY2lsQnVmZmVyLnNldENsZWFyKCAwICk7XHJcblxyXG5cdGVuYWJsZSggZ2wuREVQVEhfVEVTVCApO1xyXG5cdGRlcHRoQnVmZmVyLnNldEZ1bmMoIExlc3NFcXVhbERlcHRoICk7XHJcblxyXG5cdHNldEZsaXBTaWRlZCggZmFsc2UgKTtcclxuXHRzZXRDdWxsRmFjZSggQ3VsbEZhY2VCYWNrICk7XHJcblx0ZW5hYmxlKCBnbC5DVUxMX0ZBQ0UgKTtcclxuXHJcblx0c2V0QmxlbmRpbmcoIE5vQmxlbmRpbmcgKTtcclxuXHJcblx0Ly9cclxuXHJcblx0ZnVuY3Rpb24gZW5hYmxlKCBpZCApIHtcclxuXHJcblx0XHRpZiAoIGVuYWJsZWRDYXBhYmlsaXRpZXNbIGlkIF0gIT09IHRydWUgKSB7XHJcblxyXG5cdFx0XHRnbC5lbmFibGUoIGlkICk7XHJcblx0XHRcdGVuYWJsZWRDYXBhYmlsaXRpZXNbIGlkIF0gPSB0cnVlO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBkaXNhYmxlKCBpZCApIHtcclxuXHJcblx0XHRpZiAoIGVuYWJsZWRDYXBhYmlsaXRpZXNbIGlkIF0gIT09IGZhbHNlICkge1xyXG5cclxuXHRcdFx0Z2wuZGlzYWJsZSggaWQgKTtcclxuXHRcdFx0ZW5hYmxlZENhcGFiaWxpdGllc1sgaWQgXSA9IGZhbHNlO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBiaW5kRnJhbWVidWZmZXIoIHRhcmdldCwgZnJhbWVidWZmZXIgKSB7XHJcblxyXG5cdFx0aWYgKCBjdXJyZW50Qm91bmRGcmFtZWJ1ZmZlcnNbIHRhcmdldCBdICE9PSBmcmFtZWJ1ZmZlciApIHtcclxuXHJcblx0XHRcdGdsLmJpbmRGcmFtZWJ1ZmZlciggdGFyZ2V0LCBmcmFtZWJ1ZmZlciApO1xyXG5cclxuXHRcdFx0Y3VycmVudEJvdW5kRnJhbWVidWZmZXJzWyB0YXJnZXQgXSA9IGZyYW1lYnVmZmVyO1xyXG5cclxuXHRcdFx0aWYgKCBpc1dlYkdMMiApIHtcclxuXHJcblx0XHRcdFx0Ly8gZ2wuRFJBV19GUkFNRUJVRkZFUiBpcyBlcXVpdmFsZW50IHRvIGdsLkZSQU1FQlVGRkVSXHJcblxyXG5cdFx0XHRcdGlmICggdGFyZ2V0ID09PSBnbC5EUkFXX0ZSQU1FQlVGRkVSICkge1xyXG5cclxuXHRcdFx0XHRcdGN1cnJlbnRCb3VuZEZyYW1lYnVmZmVyc1sgZ2wuRlJBTUVCVUZGRVIgXSA9IGZyYW1lYnVmZmVyO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdGlmICggdGFyZ2V0ID09PSBnbC5GUkFNRUJVRkZFUiApIHtcclxuXHJcblx0XHRcdFx0XHRjdXJyZW50Qm91bmRGcmFtZWJ1ZmZlcnNbIGdsLkRSQVdfRlJBTUVCVUZGRVIgXSA9IGZyYW1lYnVmZmVyO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRyZXR1cm4gdHJ1ZTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIGZhbHNlO1xyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIGRyYXdCdWZmZXJzKCByZW5kZXJUYXJnZXQsIGZyYW1lYnVmZmVyICkge1xyXG5cclxuXHRcdGxldCBkcmF3QnVmZmVycyA9IGRlZmF1bHREcmF3YnVmZmVycztcclxuXHJcblx0XHRsZXQgbmVlZHNVcGRhdGUgPSBmYWxzZTtcclxuXHJcblx0XHRpZiAoIHJlbmRlclRhcmdldCApIHtcclxuXHJcblx0XHRcdGRyYXdCdWZmZXJzID0gY3VycmVudERyYXdidWZmZXJzLmdldCggZnJhbWVidWZmZXIgKTtcclxuXHJcblx0XHRcdGlmICggZHJhd0J1ZmZlcnMgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0ZHJhd0J1ZmZlcnMgPSBbXTtcclxuXHRcdFx0XHRjdXJyZW50RHJhd2J1ZmZlcnMuc2V0KCBmcmFtZWJ1ZmZlciwgZHJhd0J1ZmZlcnMgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGlmICggcmVuZGVyVGFyZ2V0LmlzV2ViR0xNdWx0aXBsZVJlbmRlclRhcmdldHMgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IHRleHR1cmVzID0gcmVuZGVyVGFyZ2V0LnRleHR1cmU7XHJcblxyXG5cdFx0XHRcdGlmICggZHJhd0J1ZmZlcnMubGVuZ3RoICE9PSB0ZXh0dXJlcy5sZW5ndGggfHwgZHJhd0J1ZmZlcnNbIDAgXSAhPT0gZ2wuQ09MT1JfQVRUQUNITUVOVDAgKSB7XHJcblxyXG5cdFx0XHRcdFx0Zm9yICggbGV0IGkgPSAwLCBpbCA9IHRleHR1cmVzLmxlbmd0aDsgaSA8IGlsOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRcdFx0ZHJhd0J1ZmZlcnNbIGkgXSA9IGdsLkNPTE9SX0FUVEFDSE1FTlQwICsgaTtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0ZHJhd0J1ZmZlcnMubGVuZ3RoID0gdGV4dHVyZXMubGVuZ3RoO1xyXG5cclxuXHRcdFx0XHRcdG5lZWRzVXBkYXRlID0gdHJ1ZTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0aWYgKCBkcmF3QnVmZmVyc1sgMCBdICE9PSBnbC5DT0xPUl9BVFRBQ0hNRU5UMCApIHtcclxuXHJcblx0XHRcdFx0XHRkcmF3QnVmZmVyc1sgMCBdID0gZ2wuQ09MT1JfQVRUQUNITUVOVDA7XHJcblxyXG5cdFx0XHRcdFx0bmVlZHNVcGRhdGUgPSB0cnVlO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdGlmICggZHJhd0J1ZmZlcnNbIDAgXSAhPT0gZ2wuQkFDSyApIHtcclxuXHJcblx0XHRcdFx0ZHJhd0J1ZmZlcnNbIDAgXSA9IGdsLkJBQ0s7XHJcblxyXG5cdFx0XHRcdG5lZWRzVXBkYXRlID0gdHJ1ZTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBuZWVkc1VwZGF0ZSApIHtcclxuXHJcblx0XHRcdGlmICggY2FwYWJpbGl0aWVzLmlzV2ViR0wyICkge1xyXG5cclxuXHRcdFx0XHRnbC5kcmF3QnVmZmVycyggZHJhd0J1ZmZlcnMgKTtcclxuXHJcblx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdGV4dGVuc2lvbnMuZ2V0KCAnV0VCR0xfZHJhd19idWZmZXJzJyApLmRyYXdCdWZmZXJzV0VCR0woIGRyYXdCdWZmZXJzICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiB1c2VQcm9ncmFtKCBwcm9ncmFtICkge1xyXG5cclxuXHRcdGlmICggY3VycmVudFByb2dyYW0gIT09IHByb2dyYW0gKSB7XHJcblxyXG5cdFx0XHRnbC51c2VQcm9ncmFtKCBwcm9ncmFtICk7XHJcblxyXG5cdFx0XHRjdXJyZW50UHJvZ3JhbSA9IHByb2dyYW07XHJcblxyXG5cdFx0XHRyZXR1cm4gdHJ1ZTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIGZhbHNlO1xyXG5cclxuXHR9XHJcblxyXG5cdGNvbnN0IGVxdWF0aW9uVG9HTCA9IHtcclxuXHRcdFsgQWRkRXF1YXRpb24gXTogZ2wuRlVOQ19BREQsXHJcblx0XHRbIFN1YnRyYWN0RXF1YXRpb24gXTogZ2wuRlVOQ19TVUJUUkFDVCxcclxuXHRcdFsgUmV2ZXJzZVN1YnRyYWN0RXF1YXRpb24gXTogZ2wuRlVOQ19SRVZFUlNFX1NVQlRSQUNUXHJcblx0fTtcclxuXHJcblx0aWYgKCBpc1dlYkdMMiApIHtcclxuXHJcblx0XHRlcXVhdGlvblRvR0xbIE1pbkVxdWF0aW9uIF0gPSBnbC5NSU47XHJcblx0XHRlcXVhdGlvblRvR0xbIE1heEVxdWF0aW9uIF0gPSBnbC5NQVg7XHJcblxyXG5cdH0gZWxzZSB7XHJcblxyXG5cdFx0Y29uc3QgZXh0ZW5zaW9uID0gZXh0ZW5zaW9ucy5nZXQoICdFWFRfYmxlbmRfbWlubWF4JyApO1xyXG5cclxuXHRcdGlmICggZXh0ZW5zaW9uICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0ZXF1YXRpb25Ub0dMWyBNaW5FcXVhdGlvbiBdID0gZXh0ZW5zaW9uLk1JTl9FWFQ7XHJcblx0XHRcdGVxdWF0aW9uVG9HTFsgTWF4RXF1YXRpb24gXSA9IGV4dGVuc2lvbi5NQVhfRVhUO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRjb25zdCBmYWN0b3JUb0dMID0ge1xyXG5cdFx0WyBaZXJvRmFjdG9yIF06IGdsLlpFUk8sXHJcblx0XHRbIE9uZUZhY3RvciBdOiBnbC5PTkUsXHJcblx0XHRbIFNyY0NvbG9yRmFjdG9yIF06IGdsLlNSQ19DT0xPUixcclxuXHRcdFsgU3JjQWxwaGFGYWN0b3IgXTogZ2wuU1JDX0FMUEhBLFxyXG5cdFx0WyBTcmNBbHBoYVNhdHVyYXRlRmFjdG9yIF06IGdsLlNSQ19BTFBIQV9TQVRVUkFURSxcclxuXHRcdFsgRHN0Q29sb3JGYWN0b3IgXTogZ2wuRFNUX0NPTE9SLFxyXG5cdFx0WyBEc3RBbHBoYUZhY3RvciBdOiBnbC5EU1RfQUxQSEEsXHJcblx0XHRbIE9uZU1pbnVzU3JjQ29sb3JGYWN0b3IgXTogZ2wuT05FX01JTlVTX1NSQ19DT0xPUixcclxuXHRcdFsgT25lTWludXNTcmNBbHBoYUZhY3RvciBdOiBnbC5PTkVfTUlOVVNfU1JDX0FMUEhBLFxyXG5cdFx0WyBPbmVNaW51c0RzdENvbG9yRmFjdG9yIF06IGdsLk9ORV9NSU5VU19EU1RfQ09MT1IsXHJcblx0XHRbIE9uZU1pbnVzRHN0QWxwaGFGYWN0b3IgXTogZ2wuT05FX01JTlVTX0RTVF9BTFBIQSxcclxuXHRcdFsgQ29uc3RhbnRDb2xvckZhY3RvciBdOiBnbC5DT05TVEFOVF9DT0xPUixcclxuXHRcdFsgT25lTWludXNDb25zdGFudENvbG9yRmFjdG9yIF06IGdsLk9ORV9NSU5VU19DT05TVEFOVF9DT0xPUixcclxuXHRcdFsgQ29uc3RhbnRBbHBoYUZhY3RvciBdOiBnbC5DT05TVEFOVF9BTFBIQSxcclxuXHRcdFsgT25lTWludXNDb25zdGFudEFscGhhRmFjdG9yIF06IGdsLk9ORV9NSU5VU19DT05TVEFOVF9BTFBIQVxyXG5cdH07XHJcblxyXG5cdGZ1bmN0aW9uIHNldEJsZW5kaW5nKCBibGVuZGluZywgYmxlbmRFcXVhdGlvbiwgYmxlbmRTcmMsIGJsZW5kRHN0LCBibGVuZEVxdWF0aW9uQWxwaGEsIGJsZW5kU3JjQWxwaGEsIGJsZW5kRHN0QWxwaGEsIGJsZW5kQ29sb3IsIGJsZW5kQWxwaGEsIHByZW11bHRpcGxpZWRBbHBoYSApIHtcclxuXHJcblx0XHRpZiAoIGJsZW5kaW5nID09PSBOb0JsZW5kaW5nICkge1xyXG5cclxuXHRcdFx0aWYgKCBjdXJyZW50QmxlbmRpbmdFbmFibGVkID09PSB0cnVlICkge1xyXG5cclxuXHRcdFx0XHRkaXNhYmxlKCBnbC5CTEVORCApO1xyXG5cdFx0XHRcdGN1cnJlbnRCbGVuZGluZ0VuYWJsZWQgPSBmYWxzZTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHJldHVybjtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBjdXJyZW50QmxlbmRpbmdFbmFibGVkID09PSBmYWxzZSApIHtcclxuXHJcblx0XHRcdGVuYWJsZSggZ2wuQkxFTkQgKTtcclxuXHRcdFx0Y3VycmVudEJsZW5kaW5nRW5hYmxlZCA9IHRydWU7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggYmxlbmRpbmcgIT09IEN1c3RvbUJsZW5kaW5nICkge1xyXG5cclxuXHRcdFx0aWYgKCBibGVuZGluZyAhPT0gY3VycmVudEJsZW5kaW5nIHx8IHByZW11bHRpcGxpZWRBbHBoYSAhPT0gY3VycmVudFByZW11bHRpcGxlZEFscGhhICkge1xyXG5cclxuXHRcdFx0XHRpZiAoIGN1cnJlbnRCbGVuZEVxdWF0aW9uICE9PSBBZGRFcXVhdGlvbiB8fCBjdXJyZW50QmxlbmRFcXVhdGlvbkFscGhhICE9PSBBZGRFcXVhdGlvbiApIHtcclxuXHJcblx0XHRcdFx0XHRnbC5ibGVuZEVxdWF0aW9uKCBnbC5GVU5DX0FERCApO1xyXG5cclxuXHRcdFx0XHRcdGN1cnJlbnRCbGVuZEVxdWF0aW9uID0gQWRkRXF1YXRpb247XHJcblx0XHRcdFx0XHRjdXJyZW50QmxlbmRFcXVhdGlvbkFscGhhID0gQWRkRXF1YXRpb247XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0aWYgKCBwcmVtdWx0aXBsaWVkQWxwaGEgKSB7XHJcblxyXG5cdFx0XHRcdFx0c3dpdGNoICggYmxlbmRpbmcgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRjYXNlIE5vcm1hbEJsZW5kaW5nOlxyXG5cdFx0XHRcdFx0XHRcdGdsLmJsZW5kRnVuY1NlcGFyYXRlKCBnbC5PTkUsIGdsLk9ORV9NSU5VU19TUkNfQUxQSEEsIGdsLk9ORSwgZ2wuT05FX01JTlVTX1NSQ19BTFBIQSApO1xyXG5cdFx0XHRcdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0XHRcdFx0Y2FzZSBBZGRpdGl2ZUJsZW5kaW5nOlxyXG5cdFx0XHRcdFx0XHRcdGdsLmJsZW5kRnVuYyggZ2wuT05FLCBnbC5PTkUgKTtcclxuXHRcdFx0XHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdFx0XHRcdGNhc2UgU3VidHJhY3RpdmVCbGVuZGluZzpcclxuXHRcdFx0XHRcdFx0XHRnbC5ibGVuZEZ1bmNTZXBhcmF0ZSggZ2wuWkVSTywgZ2wuT05FX01JTlVTX1NSQ19DT0xPUiwgZ2wuWkVSTywgZ2wuT05FICk7XHJcblx0XHRcdFx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRcdFx0XHRjYXNlIE11bHRpcGx5QmxlbmRpbmc6XHJcblx0XHRcdFx0XHRcdFx0Z2wuYmxlbmRGdW5jU2VwYXJhdGUoIGdsLlpFUk8sIGdsLlNSQ19DT0xPUiwgZ2wuWkVSTywgZ2wuU1JDX0FMUEhBICk7XHJcblx0XHRcdFx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRcdFx0XHRkZWZhdWx0OlxyXG5cdFx0XHRcdFx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5XZWJHTFN0YXRlOiBJbnZhbGlkIGJsZW5kaW5nOiAnLCBibGVuZGluZyApO1xyXG5cdFx0XHRcdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRzd2l0Y2ggKCBibGVuZGluZyApIHtcclxuXHJcblx0XHRcdFx0XHRcdGNhc2UgTm9ybWFsQmxlbmRpbmc6XHJcblx0XHRcdFx0XHRcdFx0Z2wuYmxlbmRGdW5jU2VwYXJhdGUoIGdsLlNSQ19BTFBIQSwgZ2wuT05FX01JTlVTX1NSQ19BTFBIQSwgZ2wuT05FLCBnbC5PTkVfTUlOVVNfU1JDX0FMUEhBICk7XHJcblx0XHRcdFx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRcdFx0XHRjYXNlIEFkZGl0aXZlQmxlbmRpbmc6XHJcblx0XHRcdFx0XHRcdFx0Z2wuYmxlbmRGdW5jKCBnbC5TUkNfQUxQSEEsIGdsLk9ORSApO1xyXG5cdFx0XHRcdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0XHRcdFx0Y2FzZSBTdWJ0cmFjdGl2ZUJsZW5kaW5nOlxyXG5cdFx0XHRcdFx0XHRcdGdsLmJsZW5kRnVuY1NlcGFyYXRlKCBnbC5aRVJPLCBnbC5PTkVfTUlOVVNfU1JDX0NPTE9SLCBnbC5aRVJPLCBnbC5PTkUgKTtcclxuXHRcdFx0XHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdFx0XHRcdGNhc2UgTXVsdGlwbHlCbGVuZGluZzpcclxuXHRcdFx0XHRcdFx0XHRnbC5ibGVuZEZ1bmMoIGdsLlpFUk8sIGdsLlNSQ19DT0xPUiApO1xyXG5cdFx0XHRcdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0XHRcdFx0ZGVmYXVsdDpcclxuXHRcdFx0XHRcdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuV2ViR0xTdGF0ZTogSW52YWxpZCBibGVuZGluZzogJywgYmxlbmRpbmcgKTtcclxuXHRcdFx0XHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0Y3VycmVudEJsZW5kU3JjID0gbnVsbDtcclxuXHRcdFx0XHRjdXJyZW50QmxlbmREc3QgPSBudWxsO1xyXG5cdFx0XHRcdGN1cnJlbnRCbGVuZFNyY0FscGhhID0gbnVsbDtcclxuXHRcdFx0XHRjdXJyZW50QmxlbmREc3RBbHBoYSA9IG51bGw7XHJcblx0XHRcdFx0Y3VycmVudEJsZW5kQ29sb3Iuc2V0KCAwLCAwLCAwICk7XHJcblx0XHRcdFx0Y3VycmVudEJsZW5kQWxwaGEgPSAwO1xyXG5cclxuXHRcdFx0XHRjdXJyZW50QmxlbmRpbmcgPSBibGVuZGluZztcclxuXHRcdFx0XHRjdXJyZW50UHJlbXVsdGlwbGVkQWxwaGEgPSBwcmVtdWx0aXBsaWVkQWxwaGE7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRyZXR1cm47XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIGN1c3RvbSBibGVuZGluZ1xyXG5cclxuXHRcdGJsZW5kRXF1YXRpb25BbHBoYSA9IGJsZW5kRXF1YXRpb25BbHBoYSB8fCBibGVuZEVxdWF0aW9uO1xyXG5cdFx0YmxlbmRTcmNBbHBoYSA9IGJsZW5kU3JjQWxwaGEgfHwgYmxlbmRTcmM7XHJcblx0XHRibGVuZERzdEFscGhhID0gYmxlbmREc3RBbHBoYSB8fCBibGVuZERzdDtcclxuXHJcblx0XHRpZiAoIGJsZW5kRXF1YXRpb24gIT09IGN1cnJlbnRCbGVuZEVxdWF0aW9uIHx8IGJsZW5kRXF1YXRpb25BbHBoYSAhPT0gY3VycmVudEJsZW5kRXF1YXRpb25BbHBoYSApIHtcclxuXHJcblx0XHRcdGdsLmJsZW5kRXF1YXRpb25TZXBhcmF0ZSggZXF1YXRpb25Ub0dMWyBibGVuZEVxdWF0aW9uIF0sIGVxdWF0aW9uVG9HTFsgYmxlbmRFcXVhdGlvbkFscGhhIF0gKTtcclxuXHJcblx0XHRcdGN1cnJlbnRCbGVuZEVxdWF0aW9uID0gYmxlbmRFcXVhdGlvbjtcclxuXHRcdFx0Y3VycmVudEJsZW5kRXF1YXRpb25BbHBoYSA9IGJsZW5kRXF1YXRpb25BbHBoYTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBibGVuZFNyYyAhPT0gY3VycmVudEJsZW5kU3JjIHx8IGJsZW5kRHN0ICE9PSBjdXJyZW50QmxlbmREc3QgfHwgYmxlbmRTcmNBbHBoYSAhPT0gY3VycmVudEJsZW5kU3JjQWxwaGEgfHwgYmxlbmREc3RBbHBoYSAhPT0gY3VycmVudEJsZW5kRHN0QWxwaGEgKSB7XHJcblxyXG5cdFx0XHRnbC5ibGVuZEZ1bmNTZXBhcmF0ZSggZmFjdG9yVG9HTFsgYmxlbmRTcmMgXSwgZmFjdG9yVG9HTFsgYmxlbmREc3QgXSwgZmFjdG9yVG9HTFsgYmxlbmRTcmNBbHBoYSBdLCBmYWN0b3JUb0dMWyBibGVuZERzdEFscGhhIF0gKTtcclxuXHJcblx0XHRcdGN1cnJlbnRCbGVuZFNyYyA9IGJsZW5kU3JjO1xyXG5cdFx0XHRjdXJyZW50QmxlbmREc3QgPSBibGVuZERzdDtcclxuXHRcdFx0Y3VycmVudEJsZW5kU3JjQWxwaGEgPSBibGVuZFNyY0FscGhhO1xyXG5cdFx0XHRjdXJyZW50QmxlbmREc3RBbHBoYSA9IGJsZW5kRHN0QWxwaGE7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggYmxlbmRDb2xvci5lcXVhbHMoIGN1cnJlbnRCbGVuZENvbG9yICkgPT09IGZhbHNlIHx8IGJsZW5kQWxwaGEgIT09IGN1cnJlbnRCbGVuZEFscGhhICkge1xyXG5cclxuXHRcdFx0Z2wuYmxlbmRDb2xvciggYmxlbmRDb2xvci5yLCBibGVuZENvbG9yLmcsIGJsZW5kQ29sb3IuYiwgYmxlbmRBbHBoYSApO1xyXG5cclxuXHRcdFx0Y3VycmVudEJsZW5kQ29sb3IuY29weSggYmxlbmRDb2xvciApO1xyXG5cdFx0XHRjdXJyZW50QmxlbmRBbHBoYSA9IGJsZW5kQWxwaGE7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGN1cnJlbnRCbGVuZGluZyA9IGJsZW5kaW5nO1xyXG5cdFx0Y3VycmVudFByZW11bHRpcGxlZEFscGhhID0gZmFsc2U7XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gc2V0TWF0ZXJpYWwoIG1hdGVyaWFsLCBmcm9udEZhY2VDVyApIHtcclxuXHJcblx0XHRtYXRlcmlhbC5zaWRlID09PSBEb3VibGVTaWRlXHJcblx0XHRcdD8gZGlzYWJsZSggZ2wuQ1VMTF9GQUNFIClcclxuXHRcdFx0OiBlbmFibGUoIGdsLkNVTExfRkFDRSApO1xyXG5cclxuXHRcdGxldCBmbGlwU2lkZWQgPSAoIG1hdGVyaWFsLnNpZGUgPT09IEJhY2tTaWRlICk7XHJcblx0XHRpZiAoIGZyb250RmFjZUNXICkgZmxpcFNpZGVkID0gISBmbGlwU2lkZWQ7XHJcblxyXG5cdFx0c2V0RmxpcFNpZGVkKCBmbGlwU2lkZWQgKTtcclxuXHJcblx0XHQoIG1hdGVyaWFsLmJsZW5kaW5nID09PSBOb3JtYWxCbGVuZGluZyAmJiBtYXRlcmlhbC50cmFuc3BhcmVudCA9PT0gZmFsc2UgKVxyXG5cdFx0XHQ/IHNldEJsZW5kaW5nKCBOb0JsZW5kaW5nIClcclxuXHRcdFx0OiBzZXRCbGVuZGluZyggbWF0ZXJpYWwuYmxlbmRpbmcsIG1hdGVyaWFsLmJsZW5kRXF1YXRpb24sIG1hdGVyaWFsLmJsZW5kU3JjLCBtYXRlcmlhbC5ibGVuZERzdCwgbWF0ZXJpYWwuYmxlbmRFcXVhdGlvbkFscGhhLCBtYXRlcmlhbC5ibGVuZFNyY0FscGhhLCBtYXRlcmlhbC5ibGVuZERzdEFscGhhLCBtYXRlcmlhbC5ibGVuZENvbG9yLCBtYXRlcmlhbC5ibGVuZEFscGhhLCBtYXRlcmlhbC5wcmVtdWx0aXBsaWVkQWxwaGEgKTtcclxuXHJcblx0XHRkZXB0aEJ1ZmZlci5zZXRGdW5jKCBtYXRlcmlhbC5kZXB0aEZ1bmMgKTtcclxuXHRcdGRlcHRoQnVmZmVyLnNldFRlc3QoIG1hdGVyaWFsLmRlcHRoVGVzdCApO1xyXG5cdFx0ZGVwdGhCdWZmZXIuc2V0TWFzayggbWF0ZXJpYWwuZGVwdGhXcml0ZSApO1xyXG5cdFx0Y29sb3JCdWZmZXIuc2V0TWFzayggbWF0ZXJpYWwuY29sb3JXcml0ZSApO1xyXG5cclxuXHRcdGNvbnN0IHN0ZW5jaWxXcml0ZSA9IG1hdGVyaWFsLnN0ZW5jaWxXcml0ZTtcclxuXHRcdHN0ZW5jaWxCdWZmZXIuc2V0VGVzdCggc3RlbmNpbFdyaXRlICk7XHJcblx0XHRpZiAoIHN0ZW5jaWxXcml0ZSApIHtcclxuXHJcblx0XHRcdHN0ZW5jaWxCdWZmZXIuc2V0TWFzayggbWF0ZXJpYWwuc3RlbmNpbFdyaXRlTWFzayApO1xyXG5cdFx0XHRzdGVuY2lsQnVmZmVyLnNldEZ1bmMoIG1hdGVyaWFsLnN0ZW5jaWxGdW5jLCBtYXRlcmlhbC5zdGVuY2lsUmVmLCBtYXRlcmlhbC5zdGVuY2lsRnVuY01hc2sgKTtcclxuXHRcdFx0c3RlbmNpbEJ1ZmZlci5zZXRPcCggbWF0ZXJpYWwuc3RlbmNpbEZhaWwsIG1hdGVyaWFsLnN0ZW5jaWxaRmFpbCwgbWF0ZXJpYWwuc3RlbmNpbFpQYXNzICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHNldFBvbHlnb25PZmZzZXQoIG1hdGVyaWFsLnBvbHlnb25PZmZzZXQsIG1hdGVyaWFsLnBvbHlnb25PZmZzZXRGYWN0b3IsIG1hdGVyaWFsLnBvbHlnb25PZmZzZXRVbml0cyApO1xyXG5cclxuXHRcdG1hdGVyaWFsLmFscGhhVG9Db3ZlcmFnZSA9PT0gdHJ1ZVxyXG5cdFx0XHQ/IGVuYWJsZSggZ2wuU0FNUExFX0FMUEhBX1RPX0NPVkVSQUdFIClcclxuXHRcdFx0OiBkaXNhYmxlKCBnbC5TQU1QTEVfQUxQSEFfVE9fQ09WRVJBR0UgKTtcclxuXHJcblx0fVxyXG5cclxuXHQvL1xyXG5cclxuXHRmdW5jdGlvbiBzZXRGbGlwU2lkZWQoIGZsaXBTaWRlZCApIHtcclxuXHJcblx0XHRpZiAoIGN1cnJlbnRGbGlwU2lkZWQgIT09IGZsaXBTaWRlZCApIHtcclxuXHJcblx0XHRcdGlmICggZmxpcFNpZGVkICkge1xyXG5cclxuXHRcdFx0XHRnbC5mcm9udEZhY2UoIGdsLkNXICk7XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRnbC5mcm9udEZhY2UoIGdsLkNDVyApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Y3VycmVudEZsaXBTaWRlZCA9IGZsaXBTaWRlZDtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gc2V0Q3VsbEZhY2UoIGN1bGxGYWNlICkge1xyXG5cclxuXHRcdGlmICggY3VsbEZhY2UgIT09IEN1bGxGYWNlTm9uZSApIHtcclxuXHJcblx0XHRcdGVuYWJsZSggZ2wuQ1VMTF9GQUNFICk7XHJcblxyXG5cdFx0XHRpZiAoIGN1bGxGYWNlICE9PSBjdXJyZW50Q3VsbEZhY2UgKSB7XHJcblxyXG5cdFx0XHRcdGlmICggY3VsbEZhY2UgPT09IEN1bGxGYWNlQmFjayApIHtcclxuXHJcblx0XHRcdFx0XHRnbC5jdWxsRmFjZSggZ2wuQkFDSyApO1xyXG5cclxuXHRcdFx0XHR9IGVsc2UgaWYgKCBjdWxsRmFjZSA9PT0gQ3VsbEZhY2VGcm9udCApIHtcclxuXHJcblx0XHRcdFx0XHRnbC5jdWxsRmFjZSggZ2wuRlJPTlQgKTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRnbC5jdWxsRmFjZSggZ2wuRlJPTlRfQU5EX0JBQ0sgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRkaXNhYmxlKCBnbC5DVUxMX0ZBQ0UgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Y3VycmVudEN1bGxGYWNlID0gY3VsbEZhY2U7XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gc2V0TGluZVdpZHRoKCB3aWR0aCApIHtcclxuXHJcblx0XHRpZiAoIHdpZHRoICE9PSBjdXJyZW50TGluZVdpZHRoICkge1xyXG5cclxuXHRcdFx0aWYgKCBsaW5lV2lkdGhBdmFpbGFibGUgKSBnbC5saW5lV2lkdGgoIHdpZHRoICk7XHJcblxyXG5cdFx0XHRjdXJyZW50TGluZVdpZHRoID0gd2lkdGg7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHNldFBvbHlnb25PZmZzZXQoIHBvbHlnb25PZmZzZXQsIGZhY3RvciwgdW5pdHMgKSB7XHJcblxyXG5cdFx0aWYgKCBwb2x5Z29uT2Zmc2V0ICkge1xyXG5cclxuXHRcdFx0ZW5hYmxlKCBnbC5QT0xZR09OX09GRlNFVF9GSUxMICk7XHJcblxyXG5cdFx0XHRpZiAoIGN1cnJlbnRQb2x5Z29uT2Zmc2V0RmFjdG9yICE9PSBmYWN0b3IgfHwgY3VycmVudFBvbHlnb25PZmZzZXRVbml0cyAhPT0gdW5pdHMgKSB7XHJcblxyXG5cdFx0XHRcdGdsLnBvbHlnb25PZmZzZXQoIGZhY3RvciwgdW5pdHMgKTtcclxuXHJcblx0XHRcdFx0Y3VycmVudFBvbHlnb25PZmZzZXRGYWN0b3IgPSBmYWN0b3I7XHJcblx0XHRcdFx0Y3VycmVudFBvbHlnb25PZmZzZXRVbml0cyA9IHVuaXRzO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRkaXNhYmxlKCBnbC5QT0xZR09OX09GRlNFVF9GSUxMICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHNldFNjaXNzb3JUZXN0KCBzY2lzc29yVGVzdCApIHtcclxuXHJcblx0XHRpZiAoIHNjaXNzb3JUZXN0ICkge1xyXG5cclxuXHRcdFx0ZW5hYmxlKCBnbC5TQ0lTU09SX1RFU1QgKTtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0ZGlzYWJsZSggZ2wuU0NJU1NPUl9URVNUICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdC8vIHRleHR1cmVcclxuXHJcblx0ZnVuY3Rpb24gYWN0aXZlVGV4dHVyZSggd2ViZ2xTbG90ICkge1xyXG5cclxuXHRcdGlmICggd2ViZ2xTbG90ID09PSB1bmRlZmluZWQgKSB3ZWJnbFNsb3QgPSBnbC5URVhUVVJFMCArIG1heFRleHR1cmVzIC0gMTtcclxuXHJcblx0XHRpZiAoIGN1cnJlbnRUZXh0dXJlU2xvdCAhPT0gd2ViZ2xTbG90ICkge1xyXG5cclxuXHRcdFx0Z2wuYWN0aXZlVGV4dHVyZSggd2ViZ2xTbG90ICk7XHJcblx0XHRcdGN1cnJlbnRUZXh0dXJlU2xvdCA9IHdlYmdsU2xvdDtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gYmluZFRleHR1cmUoIHdlYmdsVHlwZSwgd2ViZ2xUZXh0dXJlLCB3ZWJnbFNsb3QgKSB7XHJcblxyXG5cdFx0aWYgKCB3ZWJnbFNsb3QgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdGlmICggY3VycmVudFRleHR1cmVTbG90ID09PSBudWxsICkge1xyXG5cclxuXHRcdFx0XHR3ZWJnbFNsb3QgPSBnbC5URVhUVVJFMCArIG1heFRleHR1cmVzIC0gMTtcclxuXHJcblx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdHdlYmdsU2xvdCA9IGN1cnJlbnRUZXh0dXJlU2xvdDtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0bGV0IGJvdW5kVGV4dHVyZSA9IGN1cnJlbnRCb3VuZFRleHR1cmVzWyB3ZWJnbFNsb3QgXTtcclxuXHJcblx0XHRpZiAoIGJvdW5kVGV4dHVyZSA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0Ym91bmRUZXh0dXJlID0geyB0eXBlOiB1bmRlZmluZWQsIHRleHR1cmU6IHVuZGVmaW5lZCB9O1xyXG5cdFx0XHRjdXJyZW50Qm91bmRUZXh0dXJlc1sgd2ViZ2xTbG90IF0gPSBib3VuZFRleHR1cmU7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggYm91bmRUZXh0dXJlLnR5cGUgIT09IHdlYmdsVHlwZSB8fCBib3VuZFRleHR1cmUudGV4dHVyZSAhPT0gd2ViZ2xUZXh0dXJlICkge1xyXG5cclxuXHRcdFx0aWYgKCBjdXJyZW50VGV4dHVyZVNsb3QgIT09IHdlYmdsU2xvdCApIHtcclxuXHJcblx0XHRcdFx0Z2wuYWN0aXZlVGV4dHVyZSggd2ViZ2xTbG90ICk7XHJcblx0XHRcdFx0Y3VycmVudFRleHR1cmVTbG90ID0gd2ViZ2xTbG90O1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Z2wuYmluZFRleHR1cmUoIHdlYmdsVHlwZSwgd2ViZ2xUZXh0dXJlIHx8IGVtcHR5VGV4dHVyZXNbIHdlYmdsVHlwZSBdICk7XHJcblxyXG5cdFx0XHRib3VuZFRleHR1cmUudHlwZSA9IHdlYmdsVHlwZTtcclxuXHRcdFx0Ym91bmRUZXh0dXJlLnRleHR1cmUgPSB3ZWJnbFRleHR1cmU7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHVuYmluZFRleHR1cmUoKSB7XHJcblxyXG5cdFx0Y29uc3QgYm91bmRUZXh0dXJlID0gY3VycmVudEJvdW5kVGV4dHVyZXNbIGN1cnJlbnRUZXh0dXJlU2xvdCBdO1xyXG5cclxuXHRcdGlmICggYm91bmRUZXh0dXJlICE9PSB1bmRlZmluZWQgJiYgYm91bmRUZXh0dXJlLnR5cGUgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdGdsLmJpbmRUZXh0dXJlKCBib3VuZFRleHR1cmUudHlwZSwgbnVsbCApO1xyXG5cclxuXHRcdFx0Ym91bmRUZXh0dXJlLnR5cGUgPSB1bmRlZmluZWQ7XHJcblx0XHRcdGJvdW5kVGV4dHVyZS50ZXh0dXJlID0gdW5kZWZpbmVkO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBjb21wcmVzc2VkVGV4SW1hZ2UyRCgpIHtcclxuXHJcblx0XHR0cnkge1xyXG5cclxuXHRcdFx0Z2wuY29tcHJlc3NlZFRleEltYWdlMkQuYXBwbHkoIGdsLCBhcmd1bWVudHMgKTtcclxuXHJcblx0XHR9IGNhdGNoICggZXJyb3IgKSB7XHJcblxyXG5cdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuV2ViR0xTdGF0ZTonLCBlcnJvciApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBjb21wcmVzc2VkVGV4SW1hZ2UzRCgpIHtcclxuXHJcblx0XHR0cnkge1xyXG5cclxuXHRcdFx0Z2wuY29tcHJlc3NlZFRleEltYWdlM0QuYXBwbHkoIGdsLCBhcmd1bWVudHMgKTtcclxuXHJcblx0XHR9IGNhdGNoICggZXJyb3IgKSB7XHJcblxyXG5cdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuV2ViR0xTdGF0ZTonLCBlcnJvciApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiB0ZXhTdWJJbWFnZTJEKCkge1xyXG5cclxuXHRcdHRyeSB7XHJcblxyXG5cdFx0XHRnbC50ZXhTdWJJbWFnZTJELmFwcGx5KCBnbCwgYXJndW1lbnRzICk7XHJcblxyXG5cdFx0fSBjYXRjaCAoIGVycm9yICkge1xyXG5cclxuXHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLldlYkdMU3RhdGU6JywgZXJyb3IgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gdGV4U3ViSW1hZ2UzRCgpIHtcclxuXHJcblx0XHR0cnkge1xyXG5cclxuXHRcdFx0Z2wudGV4U3ViSW1hZ2UzRC5hcHBseSggZ2wsIGFyZ3VtZW50cyApO1xyXG5cclxuXHRcdH0gY2F0Y2ggKCBlcnJvciApIHtcclxuXHJcblx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5XZWJHTFN0YXRlOicsIGVycm9yICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIGNvbXByZXNzZWRUZXhTdWJJbWFnZTJEKCkge1xyXG5cclxuXHRcdHRyeSB7XHJcblxyXG5cdFx0XHRnbC5jb21wcmVzc2VkVGV4U3ViSW1hZ2UyRC5hcHBseSggZ2wsIGFyZ3VtZW50cyApO1xyXG5cclxuXHRcdH0gY2F0Y2ggKCBlcnJvciApIHtcclxuXHJcblx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5XZWJHTFN0YXRlOicsIGVycm9yICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIGNvbXByZXNzZWRUZXhTdWJJbWFnZTNEKCkge1xyXG5cclxuXHRcdHRyeSB7XHJcblxyXG5cdFx0XHRnbC5jb21wcmVzc2VkVGV4U3ViSW1hZ2UzRC5hcHBseSggZ2wsIGFyZ3VtZW50cyApO1xyXG5cclxuXHRcdH0gY2F0Y2ggKCBlcnJvciApIHtcclxuXHJcblx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5XZWJHTFN0YXRlOicsIGVycm9yICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHRleFN0b3JhZ2UyRCgpIHtcclxuXHJcblx0XHR0cnkge1xyXG5cclxuXHRcdFx0Z2wudGV4U3RvcmFnZTJELmFwcGx5KCBnbCwgYXJndW1lbnRzICk7XHJcblxyXG5cdFx0fSBjYXRjaCAoIGVycm9yICkge1xyXG5cclxuXHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLldlYkdMU3RhdGU6JywgZXJyb3IgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gdGV4U3RvcmFnZTNEKCkge1xyXG5cclxuXHRcdHRyeSB7XHJcblxyXG5cdFx0XHRnbC50ZXhTdG9yYWdlM0QuYXBwbHkoIGdsLCBhcmd1bWVudHMgKTtcclxuXHJcblx0XHR9IGNhdGNoICggZXJyb3IgKSB7XHJcblxyXG5cdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuV2ViR0xTdGF0ZTonLCBlcnJvciApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiB0ZXhJbWFnZTJEKCkge1xyXG5cclxuXHRcdHRyeSB7XHJcblxyXG5cdFx0XHRnbC50ZXhJbWFnZTJELmFwcGx5KCBnbCwgYXJndW1lbnRzICk7XHJcblxyXG5cdFx0fSBjYXRjaCAoIGVycm9yICkge1xyXG5cclxuXHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLldlYkdMU3RhdGU6JywgZXJyb3IgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gdGV4SW1hZ2UzRCgpIHtcclxuXHJcblx0XHR0cnkge1xyXG5cclxuXHRcdFx0Z2wudGV4SW1hZ2UzRC5hcHBseSggZ2wsIGFyZ3VtZW50cyApO1xyXG5cclxuXHRcdH0gY2F0Y2ggKCBlcnJvciApIHtcclxuXHJcblx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5XZWJHTFN0YXRlOicsIGVycm9yICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdC8vXHJcblxyXG5cdGZ1bmN0aW9uIHNjaXNzb3IoIHNjaXNzb3IgKSB7XHJcblxyXG5cdFx0aWYgKCBjdXJyZW50U2Npc3Nvci5lcXVhbHMoIHNjaXNzb3IgKSA9PT0gZmFsc2UgKSB7XHJcblxyXG5cdFx0XHRnbC5zY2lzc29yKCBzY2lzc29yLngsIHNjaXNzb3IueSwgc2Npc3Nvci56LCBzY2lzc29yLncgKTtcclxuXHRcdFx0Y3VycmVudFNjaXNzb3IuY29weSggc2Npc3NvciApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiB2aWV3cG9ydCggdmlld3BvcnQgKSB7XHJcblxyXG5cdFx0aWYgKCBjdXJyZW50Vmlld3BvcnQuZXF1YWxzKCB2aWV3cG9ydCApID09PSBmYWxzZSApIHtcclxuXHJcblx0XHRcdGdsLnZpZXdwb3J0KCB2aWV3cG9ydC54LCB2aWV3cG9ydC55LCB2aWV3cG9ydC56LCB2aWV3cG9ydC53ICk7XHJcblx0XHRcdGN1cnJlbnRWaWV3cG9ydC5jb3B5KCB2aWV3cG9ydCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiB1cGRhdGVVQk9NYXBwaW5nKCB1bmlmb3Jtc0dyb3VwLCBwcm9ncmFtICkge1xyXG5cclxuXHRcdGxldCBtYXBwaW5nID0gdWJvUHJvZ3JhbU1hcC5nZXQoIHByb2dyYW0gKTtcclxuXHJcblx0XHRpZiAoIG1hcHBpbmcgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdG1hcHBpbmcgPSBuZXcgV2Vha01hcCgpO1xyXG5cclxuXHRcdFx0dWJvUHJvZ3JhbU1hcC5zZXQoIHByb2dyYW0sIG1hcHBpbmcgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0bGV0IGJsb2NrSW5kZXggPSBtYXBwaW5nLmdldCggdW5pZm9ybXNHcm91cCApO1xyXG5cclxuXHRcdGlmICggYmxvY2tJbmRleCA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0YmxvY2tJbmRleCA9IGdsLmdldFVuaWZvcm1CbG9ja0luZGV4KCBwcm9ncmFtLCB1bmlmb3Jtc0dyb3VwLm5hbWUgKTtcclxuXHJcblx0XHRcdG1hcHBpbmcuc2V0KCB1bmlmb3Jtc0dyb3VwLCBibG9ja0luZGV4ICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHVuaWZvcm1CbG9ja0JpbmRpbmcoIHVuaWZvcm1zR3JvdXAsIHByb2dyYW0gKSB7XHJcblxyXG5cdFx0Y29uc3QgbWFwcGluZyA9IHVib1Byb2dyYW1NYXAuZ2V0KCBwcm9ncmFtICk7XHJcblx0XHRjb25zdCBibG9ja0luZGV4ID0gbWFwcGluZy5nZXQoIHVuaWZvcm1zR3JvdXAgKTtcclxuXHJcblx0XHRpZiAoIHVib0JpbmRpbmdzLmdldCggcHJvZ3JhbSApICE9PSBibG9ja0luZGV4ICkge1xyXG5cclxuXHRcdFx0Ly8gYmluZCBzaGFkZXIgc3BlY2lmaWMgYmxvY2sgaW5kZXggdG8gZ2xvYmFsIGJsb2NrIHBvaW50XHJcblx0XHRcdGdsLnVuaWZvcm1CbG9ja0JpbmRpbmcoIHByb2dyYW0sIGJsb2NrSW5kZXgsIHVuaWZvcm1zR3JvdXAuX19iaW5kaW5nUG9pbnRJbmRleCApO1xyXG5cclxuXHRcdFx0dWJvQmluZGluZ3Muc2V0KCBwcm9ncmFtLCBibG9ja0luZGV4ICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdC8vXHJcblxyXG5cdGZ1bmN0aW9uIHJlc2V0KCkge1xyXG5cclxuXHRcdC8vIHJlc2V0IHN0YXRlXHJcblxyXG5cdFx0Z2wuZGlzYWJsZSggZ2wuQkxFTkQgKTtcclxuXHRcdGdsLmRpc2FibGUoIGdsLkNVTExfRkFDRSApO1xyXG5cdFx0Z2wuZGlzYWJsZSggZ2wuREVQVEhfVEVTVCApO1xyXG5cdFx0Z2wuZGlzYWJsZSggZ2wuUE9MWUdPTl9PRkZTRVRfRklMTCApO1xyXG5cdFx0Z2wuZGlzYWJsZSggZ2wuU0NJU1NPUl9URVNUICk7XHJcblx0XHRnbC5kaXNhYmxlKCBnbC5TVEVOQ0lMX1RFU1QgKTtcclxuXHRcdGdsLmRpc2FibGUoIGdsLlNBTVBMRV9BTFBIQV9UT19DT1ZFUkFHRSApO1xyXG5cclxuXHRcdGdsLmJsZW5kRXF1YXRpb24oIGdsLkZVTkNfQUREICk7XHJcblx0XHRnbC5ibGVuZEZ1bmMoIGdsLk9ORSwgZ2wuWkVSTyApO1xyXG5cdFx0Z2wuYmxlbmRGdW5jU2VwYXJhdGUoIGdsLk9ORSwgZ2wuWkVSTywgZ2wuT05FLCBnbC5aRVJPICk7XHJcblx0XHRnbC5ibGVuZENvbG9yKCAwLCAwLCAwLCAwICk7XHJcblxyXG5cdFx0Z2wuY29sb3JNYXNrKCB0cnVlLCB0cnVlLCB0cnVlLCB0cnVlICk7XHJcblx0XHRnbC5jbGVhckNvbG9yKCAwLCAwLCAwLCAwICk7XHJcblxyXG5cdFx0Z2wuZGVwdGhNYXNrKCB0cnVlICk7XHJcblx0XHRnbC5kZXB0aEZ1bmMoIGdsLkxFU1MgKTtcclxuXHRcdGdsLmNsZWFyRGVwdGgoIDEgKTtcclxuXHJcblx0XHRnbC5zdGVuY2lsTWFzayggMHhmZmZmZmZmZiApO1xyXG5cdFx0Z2wuc3RlbmNpbEZ1bmMoIGdsLkFMV0FZUywgMCwgMHhmZmZmZmZmZiApO1xyXG5cdFx0Z2wuc3RlbmNpbE9wKCBnbC5LRUVQLCBnbC5LRUVQLCBnbC5LRUVQICk7XHJcblx0XHRnbC5jbGVhclN0ZW5jaWwoIDAgKTtcclxuXHJcblx0XHRnbC5jdWxsRmFjZSggZ2wuQkFDSyApO1xyXG5cdFx0Z2wuZnJvbnRGYWNlKCBnbC5DQ1cgKTtcclxuXHJcblx0XHRnbC5wb2x5Z29uT2Zmc2V0KCAwLCAwICk7XHJcblxyXG5cdFx0Z2wuYWN0aXZlVGV4dHVyZSggZ2wuVEVYVFVSRTAgKTtcclxuXHJcblx0XHRnbC5iaW5kRnJhbWVidWZmZXIoIGdsLkZSQU1FQlVGRkVSLCBudWxsICk7XHJcblxyXG5cdFx0aWYgKCBpc1dlYkdMMiA9PT0gdHJ1ZSApIHtcclxuXHJcblx0XHRcdGdsLmJpbmRGcmFtZWJ1ZmZlciggZ2wuRFJBV19GUkFNRUJVRkZFUiwgbnVsbCApO1xyXG5cdFx0XHRnbC5iaW5kRnJhbWVidWZmZXIoIGdsLlJFQURfRlJBTUVCVUZGRVIsIG51bGwgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Z2wudXNlUHJvZ3JhbSggbnVsbCApO1xyXG5cclxuXHRcdGdsLmxpbmVXaWR0aCggMSApO1xyXG5cclxuXHRcdGdsLnNjaXNzb3IoIDAsIDAsIGdsLmNhbnZhcy53aWR0aCwgZ2wuY2FudmFzLmhlaWdodCApO1xyXG5cdFx0Z2wudmlld3BvcnQoIDAsIDAsIGdsLmNhbnZhcy53aWR0aCwgZ2wuY2FudmFzLmhlaWdodCApO1xyXG5cclxuXHRcdC8vIHJlc2V0IGludGVybmFsc1xyXG5cclxuXHRcdGVuYWJsZWRDYXBhYmlsaXRpZXMgPSB7fTtcclxuXHJcblx0XHRjdXJyZW50VGV4dHVyZVNsb3QgPSBudWxsO1xyXG5cdFx0Y3VycmVudEJvdW5kVGV4dHVyZXMgPSB7fTtcclxuXHJcblx0XHRjdXJyZW50Qm91bmRGcmFtZWJ1ZmZlcnMgPSB7fTtcclxuXHRcdGN1cnJlbnREcmF3YnVmZmVycyA9IG5ldyBXZWFrTWFwKCk7XHJcblx0XHRkZWZhdWx0RHJhd2J1ZmZlcnMgPSBbXTtcclxuXHJcblx0XHRjdXJyZW50UHJvZ3JhbSA9IG51bGw7XHJcblxyXG5cdFx0Y3VycmVudEJsZW5kaW5nRW5hYmxlZCA9IGZhbHNlO1xyXG5cdFx0Y3VycmVudEJsZW5kaW5nID0gbnVsbDtcclxuXHRcdGN1cnJlbnRCbGVuZEVxdWF0aW9uID0gbnVsbDtcclxuXHRcdGN1cnJlbnRCbGVuZFNyYyA9IG51bGw7XHJcblx0XHRjdXJyZW50QmxlbmREc3QgPSBudWxsO1xyXG5cdFx0Y3VycmVudEJsZW5kRXF1YXRpb25BbHBoYSA9IG51bGw7XHJcblx0XHRjdXJyZW50QmxlbmRTcmNBbHBoYSA9IG51bGw7XHJcblx0XHRjdXJyZW50QmxlbmREc3RBbHBoYSA9IG51bGw7XHJcblx0XHRjdXJyZW50QmxlbmRDb2xvciA9IG5ldyBDb2xvciggMCwgMCwgMCApO1xyXG5cdFx0Y3VycmVudEJsZW5kQWxwaGEgPSAwO1xyXG5cdFx0Y3VycmVudFByZW11bHRpcGxlZEFscGhhID0gZmFsc2U7XHJcblxyXG5cdFx0Y3VycmVudEZsaXBTaWRlZCA9IG51bGw7XHJcblx0XHRjdXJyZW50Q3VsbEZhY2UgPSBudWxsO1xyXG5cclxuXHRcdGN1cnJlbnRMaW5lV2lkdGggPSBudWxsO1xyXG5cclxuXHRcdGN1cnJlbnRQb2x5Z29uT2Zmc2V0RmFjdG9yID0gbnVsbDtcclxuXHRcdGN1cnJlbnRQb2x5Z29uT2Zmc2V0VW5pdHMgPSBudWxsO1xyXG5cclxuXHRcdGN1cnJlbnRTY2lzc29yLnNldCggMCwgMCwgZ2wuY2FudmFzLndpZHRoLCBnbC5jYW52YXMuaGVpZ2h0ICk7XHJcblx0XHRjdXJyZW50Vmlld3BvcnQuc2V0KCAwLCAwLCBnbC5jYW52YXMud2lkdGgsIGdsLmNhbnZhcy5oZWlnaHQgKTtcclxuXHJcblx0XHRjb2xvckJ1ZmZlci5yZXNldCgpO1xyXG5cdFx0ZGVwdGhCdWZmZXIucmVzZXQoKTtcclxuXHRcdHN0ZW5jaWxCdWZmZXIucmVzZXQoKTtcclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4ge1xyXG5cclxuXHRcdGJ1ZmZlcnM6IHtcclxuXHRcdFx0Y29sb3I6IGNvbG9yQnVmZmVyLFxyXG5cdFx0XHRkZXB0aDogZGVwdGhCdWZmZXIsXHJcblx0XHRcdHN0ZW5jaWw6IHN0ZW5jaWxCdWZmZXJcclxuXHRcdH0sXHJcblxyXG5cdFx0ZW5hYmxlOiBlbmFibGUsXHJcblx0XHRkaXNhYmxlOiBkaXNhYmxlLFxyXG5cclxuXHRcdGJpbmRGcmFtZWJ1ZmZlcjogYmluZEZyYW1lYnVmZmVyLFxyXG5cdFx0ZHJhd0J1ZmZlcnM6IGRyYXdCdWZmZXJzLFxyXG5cclxuXHRcdHVzZVByb2dyYW06IHVzZVByb2dyYW0sXHJcblxyXG5cdFx0c2V0QmxlbmRpbmc6IHNldEJsZW5kaW5nLFxyXG5cdFx0c2V0TWF0ZXJpYWw6IHNldE1hdGVyaWFsLFxyXG5cclxuXHRcdHNldEZsaXBTaWRlZDogc2V0RmxpcFNpZGVkLFxyXG5cdFx0c2V0Q3VsbEZhY2U6IHNldEN1bGxGYWNlLFxyXG5cclxuXHRcdHNldExpbmVXaWR0aDogc2V0TGluZVdpZHRoLFxyXG5cdFx0c2V0UG9seWdvbk9mZnNldDogc2V0UG9seWdvbk9mZnNldCxcclxuXHJcblx0XHRzZXRTY2lzc29yVGVzdDogc2V0U2Npc3NvclRlc3QsXHJcblxyXG5cdFx0YWN0aXZlVGV4dHVyZTogYWN0aXZlVGV4dHVyZSxcclxuXHRcdGJpbmRUZXh0dXJlOiBiaW5kVGV4dHVyZSxcclxuXHRcdHVuYmluZFRleHR1cmU6IHVuYmluZFRleHR1cmUsXHJcblx0XHRjb21wcmVzc2VkVGV4SW1hZ2UyRDogY29tcHJlc3NlZFRleEltYWdlMkQsXHJcblx0XHRjb21wcmVzc2VkVGV4SW1hZ2UzRDogY29tcHJlc3NlZFRleEltYWdlM0QsXHJcblx0XHR0ZXhJbWFnZTJEOiB0ZXhJbWFnZTJELFxyXG5cdFx0dGV4SW1hZ2UzRDogdGV4SW1hZ2UzRCxcclxuXHJcblx0XHR1cGRhdGVVQk9NYXBwaW5nOiB1cGRhdGVVQk9NYXBwaW5nLFxyXG5cdFx0dW5pZm9ybUJsb2NrQmluZGluZzogdW5pZm9ybUJsb2NrQmluZGluZyxcclxuXHJcblx0XHR0ZXhTdG9yYWdlMkQ6IHRleFN0b3JhZ2UyRCxcclxuXHRcdHRleFN0b3JhZ2UzRDogdGV4U3RvcmFnZTNELFxyXG5cdFx0dGV4U3ViSW1hZ2UyRDogdGV4U3ViSW1hZ2UyRCxcclxuXHRcdHRleFN1YkltYWdlM0Q6IHRleFN1YkltYWdlM0QsXHJcblx0XHRjb21wcmVzc2VkVGV4U3ViSW1hZ2UyRDogY29tcHJlc3NlZFRleFN1YkltYWdlMkQsXHJcblx0XHRjb21wcmVzc2VkVGV4U3ViSW1hZ2UzRDogY29tcHJlc3NlZFRleFN1YkltYWdlM0QsXHJcblxyXG5cdFx0c2Npc3Nvcjogc2Npc3NvcixcclxuXHRcdHZpZXdwb3J0OiB2aWV3cG9ydCxcclxuXHJcblx0XHRyZXNldDogcmVzZXRcclxuXHJcblx0fTtcclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IFdlYkdMU3RhdGUgfTtcclxuIiwiaW1wb3J0IHsgTGluZWFyRmlsdGVyLCBMaW5lYXJNaXBtYXBMaW5lYXJGaWx0ZXIsIExpbmVhck1pcG1hcE5lYXJlc3RGaWx0ZXIsIE5lYXJlc3RGaWx0ZXIsIE5lYXJlc3RNaXBtYXBMaW5lYXJGaWx0ZXIsIE5lYXJlc3RNaXBtYXBOZWFyZXN0RmlsdGVyLCBSR0JBRm9ybWF0LCBSR0JfRVRDMV9Gb3JtYXQsIERlcHRoRm9ybWF0LCBEZXB0aFN0ZW5jaWxGb3JtYXQsIFVuc2lnbmVkU2hvcnRUeXBlLCBVbnNpZ25lZEludFR5cGUsIFVuc2lnbmVkSW50MjQ4VHlwZSwgRmxvYXRUeXBlLCBIYWxmRmxvYXRUeXBlLCBNaXJyb3JlZFJlcGVhdFdyYXBwaW5nLCBDbGFtcFRvRWRnZVdyYXBwaW5nLCBSZXBlYXRXcmFwcGluZywgVW5zaWduZWRCeXRlVHlwZSwgX1NSR0JBRm9ybWF0LCBOb0NvbG9yU3BhY2UsIExpbmVhclNSR0JDb2xvclNwYWNlLCBOZXZlckNvbXBhcmUsIEFsd2F5c0NvbXBhcmUsIExlc3NDb21wYXJlLCBMZXNzRXF1YWxDb21wYXJlLCBFcXVhbENvbXBhcmUsIEdyZWF0ZXJFcXVhbENvbXBhcmUsIEdyZWF0ZXJDb21wYXJlLCBOb3RFcXVhbENvbXBhcmUsIFNSR0JUcmFuc2ZlciwgTGluZWFyVHJhbnNmZXIgfSBmcm9tICcuLi8uLi9jb25zdGFudHMuanMnO1xyXG5pbXBvcnQgKiBhcyBNYXRoVXRpbHMgZnJvbSAnLi4vLi4vbWF0aC9NYXRoVXRpbHMuanMnO1xyXG5pbXBvcnQgeyBJbWFnZVV0aWxzIH0gZnJvbSAnLi4vLi4vZXh0cmFzL0ltYWdlVXRpbHMuanMnO1xyXG5pbXBvcnQgeyBjcmVhdGVFbGVtZW50TlMgfSBmcm9tICcuLi8uLi91dGlscy5qcyc7XHJcbmltcG9ydCB7IENvbG9yTWFuYWdlbWVudCB9IGZyb20gJy4uLy4uL21hdGgvQ29sb3JNYW5hZ2VtZW50LmpzJztcclxuXHJcbmZ1bmN0aW9uIFdlYkdMVGV4dHVyZXMoIF9nbCwgZXh0ZW5zaW9ucywgc3RhdGUsIHByb3BlcnRpZXMsIGNhcGFiaWxpdGllcywgdXRpbHMsIGluZm8gKSB7XHJcblxyXG5cdGNvbnN0IGlzV2ViR0wyID0gY2FwYWJpbGl0aWVzLmlzV2ViR0wyO1xyXG5cdGNvbnN0IG11bHRpc2FtcGxlZFJUVEV4dCA9IGV4dGVuc2lvbnMuaGFzKCAnV0VCR0xfbXVsdGlzYW1wbGVkX3JlbmRlcl90b190ZXh0dXJlJyApID8gZXh0ZW5zaW9ucy5nZXQoICdXRUJHTF9tdWx0aXNhbXBsZWRfcmVuZGVyX3RvX3RleHR1cmUnICkgOiBudWxsO1xyXG5cdGNvbnN0IHN1cHBvcnRzSW52YWxpZGF0ZUZyYW1lYnVmZmVyID0gdHlwZW9mIG5hdmlnYXRvciA9PT0gJ3VuZGVmaW5lZCcgPyBmYWxzZSA6IC9PY3VsdXNCcm93c2VyL2cudGVzdCggbmF2aWdhdG9yLnVzZXJBZ2VudCApO1xyXG5cclxuXHRjb25zdCBfdmlkZW9UZXh0dXJlcyA9IG5ldyBXZWFrTWFwKCk7XHJcblx0bGV0IF9jYW52YXM7XHJcblxyXG5cdGNvbnN0IF9zb3VyY2VzID0gbmV3IFdlYWtNYXAoKTsgLy8gbWFwcyBXZWJnbFRleHR1cmUgb2JqZWN0cyB0byBpbnN0YW5jZXMgb2YgU291cmNlXHJcblxyXG5cdC8vIGNvcmRvdmEgaU9TIChhcyBvZiA1LjApIHN0aWxsIHVzZXMgVUlXZWJWaWV3LCB3aGljaCBwcm92aWRlcyBPZmZzY3JlZW5DYW52YXMsXHJcblx0Ly8gYWxzbyBPZmZzY3JlZW5DYW52YXMuZ2V0Q29udGV4dChcIndlYmdsXCIpLCBidXQgbm90IE9mZnNjcmVlbkNhbnZhcy5nZXRDb250ZXh0KFwiMmRcIikhXHJcblx0Ly8gU29tZSBpbXBsZW1lbnRhdGlvbnMgbWF5IG9ubHkgaW1wbGVtZW50IE9mZnNjcmVlbkNhbnZhcyBwYXJ0aWFsbHkgKGUuZy4gbGFja2luZyAyZCkuXHJcblxyXG5cdGxldCB1c2VPZmZzY3JlZW5DYW52YXMgPSBmYWxzZTtcclxuXHJcblx0dHJ5IHtcclxuXHJcblx0XHR1c2VPZmZzY3JlZW5DYW52YXMgPSB0eXBlb2YgT2Zmc2NyZWVuQ2FudmFzICE9PSAndW5kZWZpbmVkJ1xyXG5cdFx0XHQvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgY29tcGF0L2NvbXBhdFxyXG5cdFx0XHQmJiAoIG5ldyBPZmZzY3JlZW5DYW52YXMoIDEsIDEgKS5nZXRDb250ZXh0KCAnMmQnICkgKSAhPT0gbnVsbDtcclxuXHJcblx0fSBjYXRjaCAoIGVyciApIHtcclxuXHJcblx0XHQvLyBJZ25vcmUgYW55IGVycm9yc1xyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIGNyZWF0ZUNhbnZhcyggd2lkdGgsIGhlaWdodCApIHtcclxuXHJcblx0XHQvLyBVc2UgT2Zmc2NyZWVuQ2FudmFzIHdoZW4gYXZhaWxhYmxlLiBTcGVjaWFsbHkgbmVlZGVkIGluIHdlYiB3b3JrZXJzXHJcblxyXG5cdFx0cmV0dXJuIHVzZU9mZnNjcmVlbkNhbnZhcyA/XHJcblx0XHRcdC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBjb21wYXQvY29tcGF0XHJcblx0XHRcdG5ldyBPZmZzY3JlZW5DYW52YXMoIHdpZHRoLCBoZWlnaHQgKSA6IGNyZWF0ZUVsZW1lbnROUyggJ2NhbnZhcycgKTtcclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiByZXNpemVJbWFnZSggaW1hZ2UsIG5lZWRzUG93ZXJPZlR3bywgbmVlZHNOZXdDYW52YXMsIG1heFNpemUgKSB7XHJcblxyXG5cdFx0bGV0IHNjYWxlID0gMTtcclxuXHJcblx0XHQvLyBoYW5kbGUgY2FzZSBpZiB0ZXh0dXJlIGV4Y2VlZHMgbWF4IHNpemVcclxuXHJcblx0XHRpZiAoIGltYWdlLndpZHRoID4gbWF4U2l6ZSB8fCBpbWFnZS5oZWlnaHQgPiBtYXhTaXplICkge1xyXG5cclxuXHRcdFx0c2NhbGUgPSBtYXhTaXplIC8gTWF0aC5tYXgoIGltYWdlLndpZHRoLCBpbWFnZS5oZWlnaHQgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gb25seSBwZXJmb3JtIHJlc2l6ZSBpZiBuZWNlc3NhcnlcclxuXHJcblx0XHRpZiAoIHNjYWxlIDwgMSB8fCBuZWVkc1Bvd2VyT2ZUd28gPT09IHRydWUgKSB7XHJcblxyXG5cdFx0XHQvLyBvbmx5IHBlcmZvcm0gcmVzaXplIGZvciBjZXJ0YWluIGltYWdlIHR5cGVzXHJcblxyXG5cdFx0XHRpZiAoICggdHlwZW9mIEhUTUxJbWFnZUVsZW1lbnQgIT09ICd1bmRlZmluZWQnICYmIGltYWdlIGluc3RhbmNlb2YgSFRNTEltYWdlRWxlbWVudCApIHx8XHJcblx0XHRcdFx0KCB0eXBlb2YgSFRNTENhbnZhc0VsZW1lbnQgIT09ICd1bmRlZmluZWQnICYmIGltYWdlIGluc3RhbmNlb2YgSFRNTENhbnZhc0VsZW1lbnQgKSB8fFxyXG5cdFx0XHRcdCggdHlwZW9mIEltYWdlQml0bWFwICE9PSAndW5kZWZpbmVkJyAmJiBpbWFnZSBpbnN0YW5jZW9mIEltYWdlQml0bWFwICkgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IGZsb29yID0gbmVlZHNQb3dlck9mVHdvID8gTWF0aFV0aWxzLmZsb29yUG93ZXJPZlR3byA6IE1hdGguZmxvb3I7XHJcblxyXG5cdFx0XHRcdGNvbnN0IHdpZHRoID0gZmxvb3IoIHNjYWxlICogaW1hZ2Uud2lkdGggKTtcclxuXHRcdFx0XHRjb25zdCBoZWlnaHQgPSBmbG9vciggc2NhbGUgKiBpbWFnZS5oZWlnaHQgKTtcclxuXHJcblx0XHRcdFx0aWYgKCBfY2FudmFzID09PSB1bmRlZmluZWQgKSBfY2FudmFzID0gY3JlYXRlQ2FudmFzKCB3aWR0aCwgaGVpZ2h0ICk7XHJcblxyXG5cdFx0XHRcdC8vIGN1YmUgdGV4dHVyZXMgY2FuJ3QgcmV1c2UgdGhlIHNhbWUgY2FudmFzXHJcblxyXG5cdFx0XHRcdGNvbnN0IGNhbnZhcyA9IG5lZWRzTmV3Q2FudmFzID8gY3JlYXRlQ2FudmFzKCB3aWR0aCwgaGVpZ2h0ICkgOiBfY2FudmFzO1xyXG5cclxuXHRcdFx0XHRjYW52YXMud2lkdGggPSB3aWR0aDtcclxuXHRcdFx0XHRjYW52YXMuaGVpZ2h0ID0gaGVpZ2h0O1xyXG5cclxuXHRcdFx0XHRjb25zdCBjb250ZXh0ID0gY2FudmFzLmdldENvbnRleHQoICcyZCcgKTtcclxuXHRcdFx0XHRjb250ZXh0LmRyYXdJbWFnZSggaW1hZ2UsIDAsIDAsIHdpZHRoLCBoZWlnaHQgKTtcclxuXHJcblx0XHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuV2ViR0xSZW5kZXJlcjogVGV4dHVyZSBoYXMgYmVlbiByZXNpemVkIGZyb20gKCcgKyBpbWFnZS53aWR0aCArICd4JyArIGltYWdlLmhlaWdodCArICcpIHRvICgnICsgd2lkdGggKyAneCcgKyBoZWlnaHQgKyAnKS4nICk7XHJcblxyXG5cdFx0XHRcdHJldHVybiBjYW52YXM7XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRpZiAoICdkYXRhJyBpbiBpbWFnZSApIHtcclxuXHJcblx0XHRcdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5XZWJHTFJlbmRlcmVyOiBJbWFnZSBpbiBEYXRhVGV4dHVyZSBpcyB0b28gYmlnICgnICsgaW1hZ2Uud2lkdGggKyAneCcgKyBpbWFnZS5oZWlnaHQgKyAnKS4nICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0cmV0dXJuIGltYWdlO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gaW1hZ2U7XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gaXNQb3dlck9mVHdvKCBpbWFnZSApIHtcclxuXHJcblx0XHRyZXR1cm4gTWF0aFV0aWxzLmlzUG93ZXJPZlR3byggaW1hZ2Uud2lkdGggKSAmJiBNYXRoVXRpbHMuaXNQb3dlck9mVHdvKCBpbWFnZS5oZWlnaHQgKTtcclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiB0ZXh0dXJlTmVlZHNQb3dlck9mVHdvKCB0ZXh0dXJlICkge1xyXG5cclxuXHRcdGlmICggaXNXZWJHTDIgKSByZXR1cm4gZmFsc2U7XHJcblxyXG5cdFx0cmV0dXJuICggdGV4dHVyZS53cmFwUyAhPT0gQ2xhbXBUb0VkZ2VXcmFwcGluZyB8fCB0ZXh0dXJlLndyYXBUICE9PSBDbGFtcFRvRWRnZVdyYXBwaW5nICkgfHxcclxuXHRcdFx0KCB0ZXh0dXJlLm1pbkZpbHRlciAhPT0gTmVhcmVzdEZpbHRlciAmJiB0ZXh0dXJlLm1pbkZpbHRlciAhPT0gTGluZWFyRmlsdGVyICk7XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gdGV4dHVyZU5lZWRzR2VuZXJhdGVNaXBtYXBzKCB0ZXh0dXJlLCBzdXBwb3J0c01pcHMgKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRleHR1cmUuZ2VuZXJhdGVNaXBtYXBzICYmIHN1cHBvcnRzTWlwcyAmJlxyXG5cdFx0XHR0ZXh0dXJlLm1pbkZpbHRlciAhPT0gTmVhcmVzdEZpbHRlciAmJiB0ZXh0dXJlLm1pbkZpbHRlciAhPT0gTGluZWFyRmlsdGVyO1xyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIGdlbmVyYXRlTWlwbWFwKCB0YXJnZXQgKSB7XHJcblxyXG5cdFx0X2dsLmdlbmVyYXRlTWlwbWFwKCB0YXJnZXQgKTtcclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBnZXRJbnRlcm5hbEZvcm1hdCggaW50ZXJuYWxGb3JtYXROYW1lLCBnbEZvcm1hdCwgZ2xUeXBlLCBjb2xvclNwYWNlLCBmb3JjZUxpbmVhclRyYW5zZmVyID0gZmFsc2UgKSB7XHJcblxyXG5cdFx0aWYgKCBpc1dlYkdMMiA9PT0gZmFsc2UgKSByZXR1cm4gZ2xGb3JtYXQ7XHJcblxyXG5cdFx0aWYgKCBpbnRlcm5hbEZvcm1hdE5hbWUgIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRpZiAoIF9nbFsgaW50ZXJuYWxGb3JtYXROYW1lIF0gIT09IHVuZGVmaW5lZCApIHJldHVybiBfZ2xbIGludGVybmFsRm9ybWF0TmFtZSBdO1xyXG5cclxuXHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuV2ViR0xSZW5kZXJlcjogQXR0ZW1wdCB0byB1c2Ugbm9uLWV4aXN0aW5nIFdlYkdMIGludGVybmFsIGZvcm1hdCBcXCcnICsgaW50ZXJuYWxGb3JtYXROYW1lICsgJ1xcJycgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0bGV0IGludGVybmFsRm9ybWF0ID0gZ2xGb3JtYXQ7XHJcblxyXG5cdFx0aWYgKCBnbEZvcm1hdCA9PT0gX2dsLlJFRCApIHtcclxuXHJcblx0XHRcdGlmICggZ2xUeXBlID09PSBfZ2wuRkxPQVQgKSBpbnRlcm5hbEZvcm1hdCA9IF9nbC5SMzJGO1xyXG5cdFx0XHRpZiAoIGdsVHlwZSA9PT0gX2dsLkhBTEZfRkxPQVQgKSBpbnRlcm5hbEZvcm1hdCA9IF9nbC5SMTZGO1xyXG5cdFx0XHRpZiAoIGdsVHlwZSA9PT0gX2dsLlVOU0lHTkVEX0JZVEUgKSBpbnRlcm5hbEZvcm1hdCA9IF9nbC5SODtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBnbEZvcm1hdCA9PT0gX2dsLlJFRF9JTlRFR0VSICkge1xyXG5cclxuXHRcdFx0aWYgKCBnbFR5cGUgPT09IF9nbC5VTlNJR05FRF9CWVRFICkgaW50ZXJuYWxGb3JtYXQgPSBfZ2wuUjhVSTtcclxuXHRcdFx0aWYgKCBnbFR5cGUgPT09IF9nbC5VTlNJR05FRF9TSE9SVCApIGludGVybmFsRm9ybWF0ID0gX2dsLlIxNlVJO1xyXG5cdFx0XHRpZiAoIGdsVHlwZSA9PT0gX2dsLlVOU0lHTkVEX0lOVCApIGludGVybmFsRm9ybWF0ID0gX2dsLlIzMlVJO1xyXG5cdFx0XHRpZiAoIGdsVHlwZSA9PT0gX2dsLkJZVEUgKSBpbnRlcm5hbEZvcm1hdCA9IF9nbC5SOEk7XHJcblx0XHRcdGlmICggZ2xUeXBlID09PSBfZ2wuU0hPUlQgKSBpbnRlcm5hbEZvcm1hdCA9IF9nbC5SMTZJO1xyXG5cdFx0XHRpZiAoIGdsVHlwZSA9PT0gX2dsLklOVCApIGludGVybmFsRm9ybWF0ID0gX2dsLlIzMkk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggZ2xGb3JtYXQgPT09IF9nbC5SRyApIHtcclxuXHJcblx0XHRcdGlmICggZ2xUeXBlID09PSBfZ2wuRkxPQVQgKSBpbnRlcm5hbEZvcm1hdCA9IF9nbC5SRzMyRjtcclxuXHRcdFx0aWYgKCBnbFR5cGUgPT09IF9nbC5IQUxGX0ZMT0FUICkgaW50ZXJuYWxGb3JtYXQgPSBfZ2wuUkcxNkY7XHJcblx0XHRcdGlmICggZ2xUeXBlID09PSBfZ2wuVU5TSUdORURfQllURSApIGludGVybmFsRm9ybWF0ID0gX2dsLlJHODtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBnbEZvcm1hdCA9PT0gX2dsLlJHQkEgKSB7XHJcblxyXG5cdFx0XHRjb25zdCB0cmFuc2ZlciA9IGZvcmNlTGluZWFyVHJhbnNmZXIgPyBMaW5lYXJUcmFuc2ZlciA6IENvbG9yTWFuYWdlbWVudC5nZXRUcmFuc2ZlciggY29sb3JTcGFjZSApO1xyXG5cclxuXHRcdFx0aWYgKCBnbFR5cGUgPT09IF9nbC5GTE9BVCApIGludGVybmFsRm9ybWF0ID0gX2dsLlJHQkEzMkY7XHJcblx0XHRcdGlmICggZ2xUeXBlID09PSBfZ2wuSEFMRl9GTE9BVCApIGludGVybmFsRm9ybWF0ID0gX2dsLlJHQkExNkY7XHJcblx0XHRcdGlmICggZ2xUeXBlID09PSBfZ2wuVU5TSUdORURfQllURSApIGludGVybmFsRm9ybWF0ID0gKCB0cmFuc2ZlciA9PT0gU1JHQlRyYW5zZmVyICkgPyBfZ2wuU1JHQjhfQUxQSEE4IDogX2dsLlJHQkE4O1xyXG5cdFx0XHRpZiAoIGdsVHlwZSA9PT0gX2dsLlVOU0lHTkVEX1NIT1JUXzRfNF80XzQgKSBpbnRlcm5hbEZvcm1hdCA9IF9nbC5SR0JBNDtcclxuXHRcdFx0aWYgKCBnbFR5cGUgPT09IF9nbC5VTlNJR05FRF9TSE9SVF81XzVfNV8xICkgaW50ZXJuYWxGb3JtYXQgPSBfZ2wuUkdCNV9BMTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBpbnRlcm5hbEZvcm1hdCA9PT0gX2dsLlIxNkYgfHwgaW50ZXJuYWxGb3JtYXQgPT09IF9nbC5SMzJGIHx8XHJcblx0XHRcdGludGVybmFsRm9ybWF0ID09PSBfZ2wuUkcxNkYgfHwgaW50ZXJuYWxGb3JtYXQgPT09IF9nbC5SRzMyRiB8fFxyXG5cdFx0XHRpbnRlcm5hbEZvcm1hdCA9PT0gX2dsLlJHQkExNkYgfHwgaW50ZXJuYWxGb3JtYXQgPT09IF9nbC5SR0JBMzJGICkge1xyXG5cclxuXHRcdFx0ZXh0ZW5zaW9ucy5nZXQoICdFWFRfY29sb3JfYnVmZmVyX2Zsb2F0JyApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gaW50ZXJuYWxGb3JtYXQ7XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gZ2V0TWlwTGV2ZWxzKCB0ZXh0dXJlLCBpbWFnZSwgc3VwcG9ydHNNaXBzICkge1xyXG5cclxuXHRcdGlmICggdGV4dHVyZU5lZWRzR2VuZXJhdGVNaXBtYXBzKCB0ZXh0dXJlLCBzdXBwb3J0c01pcHMgKSA9PT0gdHJ1ZSB8fCAoIHRleHR1cmUuaXNGcmFtZWJ1ZmZlclRleHR1cmUgJiYgdGV4dHVyZS5taW5GaWx0ZXIgIT09IE5lYXJlc3RGaWx0ZXIgJiYgdGV4dHVyZS5taW5GaWx0ZXIgIT09IExpbmVhckZpbHRlciApICkge1xyXG5cclxuXHRcdFx0cmV0dXJuIE1hdGgubG9nMiggTWF0aC5tYXgoIGltYWdlLndpZHRoLCBpbWFnZS5oZWlnaHQgKSApICsgMTtcclxuXHJcblx0XHR9IGVsc2UgaWYgKCB0ZXh0dXJlLm1pcG1hcHMgIT09IHVuZGVmaW5lZCAmJiB0ZXh0dXJlLm1pcG1hcHMubGVuZ3RoID4gMCApIHtcclxuXHJcblx0XHRcdC8vIHVzZXItZGVmaW5lZCBtaXBtYXBzXHJcblxyXG5cdFx0XHRyZXR1cm4gdGV4dHVyZS5taXBtYXBzLmxlbmd0aDtcclxuXHJcblx0XHR9IGVsc2UgaWYgKCB0ZXh0dXJlLmlzQ29tcHJlc3NlZFRleHR1cmUgJiYgQXJyYXkuaXNBcnJheSggdGV4dHVyZS5pbWFnZSApICkge1xyXG5cclxuXHRcdFx0cmV0dXJuIGltYWdlLm1pcG1hcHMubGVuZ3RoO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHQvLyB0ZXh0dXJlIHdpdGhvdXQgbWlwbWFwcyAob25seSBiYXNlIGxldmVsKVxyXG5cclxuXHRcdFx0cmV0dXJuIDE7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdC8vIEZhbGxiYWNrIGZpbHRlcnMgZm9yIG5vbi1wb3dlci1vZi0yIHRleHR1cmVzXHJcblxyXG5cdGZ1bmN0aW9uIGZpbHRlckZhbGxiYWNrKCBmICkge1xyXG5cclxuXHRcdGlmICggZiA9PT0gTmVhcmVzdEZpbHRlciB8fCBmID09PSBOZWFyZXN0TWlwbWFwTmVhcmVzdEZpbHRlciB8fCBmID09PSBOZWFyZXN0TWlwbWFwTGluZWFyRmlsdGVyICkge1xyXG5cclxuXHRcdFx0cmV0dXJuIF9nbC5ORUFSRVNUO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gX2dsLkxJTkVBUjtcclxuXHJcblx0fVxyXG5cclxuXHQvL1xyXG5cclxuXHRmdW5jdGlvbiBvblRleHR1cmVEaXNwb3NlKCBldmVudCApIHtcclxuXHJcblx0XHRjb25zdCB0ZXh0dXJlID0gZXZlbnQudGFyZ2V0O1xyXG5cclxuXHRcdHRleHR1cmUucmVtb3ZlRXZlbnRMaXN0ZW5lciggJ2Rpc3Bvc2UnLCBvblRleHR1cmVEaXNwb3NlICk7XHJcblxyXG5cdFx0ZGVhbGxvY2F0ZVRleHR1cmUoIHRleHR1cmUgKTtcclxuXHJcblx0XHRpZiAoIHRleHR1cmUuaXNWaWRlb1RleHR1cmUgKSB7XHJcblxyXG5cdFx0XHRfdmlkZW9UZXh0dXJlcy5kZWxldGUoIHRleHR1cmUgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gb25SZW5kZXJUYXJnZXREaXNwb3NlKCBldmVudCApIHtcclxuXHJcblx0XHRjb25zdCByZW5kZXJUYXJnZXQgPSBldmVudC50YXJnZXQ7XHJcblxyXG5cdFx0cmVuZGVyVGFyZ2V0LnJlbW92ZUV2ZW50TGlzdGVuZXIoICdkaXNwb3NlJywgb25SZW5kZXJUYXJnZXREaXNwb3NlICk7XHJcblxyXG5cdFx0ZGVhbGxvY2F0ZVJlbmRlclRhcmdldCggcmVuZGVyVGFyZ2V0ICk7XHJcblxyXG5cdH1cclxuXHJcblx0Ly9cclxuXHJcblx0ZnVuY3Rpb24gZGVhbGxvY2F0ZVRleHR1cmUoIHRleHR1cmUgKSB7XHJcblxyXG5cdFx0Y29uc3QgdGV4dHVyZVByb3BlcnRpZXMgPSBwcm9wZXJ0aWVzLmdldCggdGV4dHVyZSApO1xyXG5cclxuXHRcdGlmICggdGV4dHVyZVByb3BlcnRpZXMuX193ZWJnbEluaXQgPT09IHVuZGVmaW5lZCApIHJldHVybjtcclxuXHJcblx0XHQvLyBjaGVjayBpZiBpdCdzIG5lY2Vzc2FyeSB0byByZW1vdmUgdGhlIFdlYkdMVGV4dHVyZSBvYmplY3RcclxuXHJcblx0XHRjb25zdCBzb3VyY2UgPSB0ZXh0dXJlLnNvdXJjZTtcclxuXHRcdGNvbnN0IHdlYmdsVGV4dHVyZXMgPSBfc291cmNlcy5nZXQoIHNvdXJjZSApO1xyXG5cclxuXHRcdGlmICggd2ViZ2xUZXh0dXJlcyApIHtcclxuXHJcblx0XHRcdGNvbnN0IHdlYmdsVGV4dHVyZSA9IHdlYmdsVGV4dHVyZXNbIHRleHR1cmVQcm9wZXJ0aWVzLl9fY2FjaGVLZXkgXTtcclxuXHRcdFx0d2ViZ2xUZXh0dXJlLnVzZWRUaW1lcyAtLTtcclxuXHJcblx0XHRcdC8vIHRoZSBXZWJHTFRleHR1cmUgb2JqZWN0IGlzIG5vdCB1c2VkIGFueW1vcmUsIHJlbW92ZSBpdFxyXG5cclxuXHRcdFx0aWYgKCB3ZWJnbFRleHR1cmUudXNlZFRpbWVzID09PSAwICkge1xyXG5cclxuXHRcdFx0XHRkZWxldGVUZXh0dXJlKCB0ZXh0dXJlICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyByZW1vdmUgdGhlIHdlYWsgbWFwIGVudHJ5IGlmIG5vIFdlYkdMVGV4dHVyZSB1c2VzIHRoZSBzb3VyY2UgYW55bW9yZVxyXG5cclxuXHRcdFx0aWYgKCBPYmplY3Qua2V5cyggd2ViZ2xUZXh0dXJlcyApLmxlbmd0aCA9PT0gMCApIHtcclxuXHJcblx0XHRcdFx0X3NvdXJjZXMuZGVsZXRlKCBzb3VyY2UgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cHJvcGVydGllcy5yZW1vdmUoIHRleHR1cmUgKTtcclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBkZWxldGVUZXh0dXJlKCB0ZXh0dXJlICkge1xyXG5cclxuXHRcdGNvbnN0IHRleHR1cmVQcm9wZXJ0aWVzID0gcHJvcGVydGllcy5nZXQoIHRleHR1cmUgKTtcclxuXHRcdF9nbC5kZWxldGVUZXh0dXJlKCB0ZXh0dXJlUHJvcGVydGllcy5fX3dlYmdsVGV4dHVyZSApO1xyXG5cclxuXHRcdGNvbnN0IHNvdXJjZSA9IHRleHR1cmUuc291cmNlO1xyXG5cdFx0Y29uc3Qgd2ViZ2xUZXh0dXJlcyA9IF9zb3VyY2VzLmdldCggc291cmNlICk7XHJcblx0XHRkZWxldGUgd2ViZ2xUZXh0dXJlc1sgdGV4dHVyZVByb3BlcnRpZXMuX19jYWNoZUtleSBdO1xyXG5cclxuXHRcdGluZm8ubWVtb3J5LnRleHR1cmVzIC0tO1xyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIGRlYWxsb2NhdGVSZW5kZXJUYXJnZXQoIHJlbmRlclRhcmdldCApIHtcclxuXHJcblx0XHRjb25zdCB0ZXh0dXJlID0gcmVuZGVyVGFyZ2V0LnRleHR1cmU7XHJcblxyXG5cdFx0Y29uc3QgcmVuZGVyVGFyZ2V0UHJvcGVydGllcyA9IHByb3BlcnRpZXMuZ2V0KCByZW5kZXJUYXJnZXQgKTtcclxuXHRcdGNvbnN0IHRleHR1cmVQcm9wZXJ0aWVzID0gcHJvcGVydGllcy5nZXQoIHRleHR1cmUgKTtcclxuXHJcblx0XHRpZiAoIHRleHR1cmVQcm9wZXJ0aWVzLl9fd2ViZ2xUZXh0dXJlICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRfZ2wuZGVsZXRlVGV4dHVyZSggdGV4dHVyZVByb3BlcnRpZXMuX193ZWJnbFRleHR1cmUgKTtcclxuXHJcblx0XHRcdGluZm8ubWVtb3J5LnRleHR1cmVzIC0tO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHJlbmRlclRhcmdldC5kZXB0aFRleHR1cmUgKSB7XHJcblxyXG5cdFx0XHRyZW5kZXJUYXJnZXQuZGVwdGhUZXh0dXJlLmRpc3Bvc2UoKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCByZW5kZXJUYXJnZXQuaXNXZWJHTEN1YmVSZW5kZXJUYXJnZXQgKSB7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCA2OyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRpZiAoIEFycmF5LmlzQXJyYXkoIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbEZyYW1lYnVmZmVyWyBpIF0gKSApIHtcclxuXHJcblx0XHRcdFx0XHRmb3IgKCBsZXQgbGV2ZWwgPSAwOyBsZXZlbCA8IHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbEZyYW1lYnVmZmVyWyBpIF0ubGVuZ3RoOyBsZXZlbCArKyApIF9nbC5kZWxldGVGcmFtZWJ1ZmZlciggcmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX3dlYmdsRnJhbWVidWZmZXJbIGkgXVsgbGV2ZWwgXSApO1xyXG5cclxuXHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdF9nbC5kZWxldGVGcmFtZWJ1ZmZlciggcmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX3dlYmdsRnJhbWVidWZmZXJbIGkgXSApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdGlmICggcmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX3dlYmdsRGVwdGhidWZmZXIgKSBfZ2wuZGVsZXRlUmVuZGVyYnVmZmVyKCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xEZXB0aGJ1ZmZlclsgaSBdICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdGlmICggQXJyYXkuaXNBcnJheSggcmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX3dlYmdsRnJhbWVidWZmZXIgKSApIHtcclxuXHJcblx0XHRcdFx0Zm9yICggbGV0IGxldmVsID0gMDsgbGV2ZWwgPCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xGcmFtZWJ1ZmZlci5sZW5ndGg7IGxldmVsICsrICkgX2dsLmRlbGV0ZUZyYW1lYnVmZmVyKCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xGcmFtZWJ1ZmZlclsgbGV2ZWwgXSApO1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0X2dsLmRlbGV0ZUZyYW1lYnVmZmVyKCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xGcmFtZWJ1ZmZlciApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0aWYgKCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xEZXB0aGJ1ZmZlciApIF9nbC5kZWxldGVSZW5kZXJidWZmZXIoIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbERlcHRoYnVmZmVyICk7XHJcblx0XHRcdGlmICggcmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX3dlYmdsTXVsdGlzYW1wbGVkRnJhbWVidWZmZXIgKSBfZ2wuZGVsZXRlRnJhbWVidWZmZXIoIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbE11bHRpc2FtcGxlZEZyYW1lYnVmZmVyICk7XHJcblxyXG5cdFx0XHRpZiAoIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbENvbG9yUmVuZGVyYnVmZmVyICkge1xyXG5cclxuXHRcdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xDb2xvclJlbmRlcmJ1ZmZlci5sZW5ndGg7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xDb2xvclJlbmRlcmJ1ZmZlclsgaSBdICkgX2dsLmRlbGV0ZVJlbmRlcmJ1ZmZlciggcmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX3dlYmdsQ29sb3JSZW5kZXJidWZmZXJbIGkgXSApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRpZiAoIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbERlcHRoUmVuZGVyYnVmZmVyICkgX2dsLmRlbGV0ZVJlbmRlcmJ1ZmZlciggcmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX3dlYmdsRGVwdGhSZW5kZXJidWZmZXIgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCByZW5kZXJUYXJnZXQuaXNXZWJHTE11bHRpcGxlUmVuZGVyVGFyZ2V0cyApIHtcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSB0ZXh0dXJlLmxlbmd0aDsgaSA8IGlsOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBhdHRhY2htZW50UHJvcGVydGllcyA9IHByb3BlcnRpZXMuZ2V0KCB0ZXh0dXJlWyBpIF0gKTtcclxuXHJcblx0XHRcdFx0aWYgKCBhdHRhY2htZW50UHJvcGVydGllcy5fX3dlYmdsVGV4dHVyZSApIHtcclxuXHJcblx0XHRcdFx0XHRfZ2wuZGVsZXRlVGV4dHVyZSggYXR0YWNobWVudFByb3BlcnRpZXMuX193ZWJnbFRleHR1cmUgKTtcclxuXHJcblx0XHRcdFx0XHRpbmZvLm1lbW9yeS50ZXh0dXJlcyAtLTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRwcm9wZXJ0aWVzLnJlbW92ZSggdGV4dHVyZVsgaSBdICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHByb3BlcnRpZXMucmVtb3ZlKCB0ZXh0dXJlICk7XHJcblx0XHRwcm9wZXJ0aWVzLnJlbW92ZSggcmVuZGVyVGFyZ2V0ICk7XHJcblxyXG5cdH1cclxuXHJcblx0Ly9cclxuXHJcblx0bGV0IHRleHR1cmVVbml0cyA9IDA7XHJcblxyXG5cdGZ1bmN0aW9uIHJlc2V0VGV4dHVyZVVuaXRzKCkge1xyXG5cclxuXHRcdHRleHR1cmVVbml0cyA9IDA7XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gYWxsb2NhdGVUZXh0dXJlVW5pdCgpIHtcclxuXHJcblx0XHRjb25zdCB0ZXh0dXJlVW5pdCA9IHRleHR1cmVVbml0cztcclxuXHJcblx0XHRpZiAoIHRleHR1cmVVbml0ID49IGNhcGFiaWxpdGllcy5tYXhUZXh0dXJlcyApIHtcclxuXHJcblx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLldlYkdMVGV4dHVyZXM6IFRyeWluZyB0byB1c2UgJyArIHRleHR1cmVVbml0ICsgJyB0ZXh0dXJlIHVuaXRzIHdoaWxlIHRoaXMgR1BVIHN1cHBvcnRzIG9ubHkgJyArIGNhcGFiaWxpdGllcy5tYXhUZXh0dXJlcyApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHR0ZXh0dXJlVW5pdHMgKz0gMTtcclxuXHJcblx0XHRyZXR1cm4gdGV4dHVyZVVuaXQ7XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gZ2V0VGV4dHVyZUNhY2hlS2V5KCB0ZXh0dXJlICkge1xyXG5cclxuXHRcdGNvbnN0IGFycmF5ID0gW107XHJcblxyXG5cdFx0YXJyYXkucHVzaCggdGV4dHVyZS53cmFwUyApO1xyXG5cdFx0YXJyYXkucHVzaCggdGV4dHVyZS53cmFwVCApO1xyXG5cdFx0YXJyYXkucHVzaCggdGV4dHVyZS53cmFwUiB8fCAwICk7XHJcblx0XHRhcnJheS5wdXNoKCB0ZXh0dXJlLm1hZ0ZpbHRlciApO1xyXG5cdFx0YXJyYXkucHVzaCggdGV4dHVyZS5taW5GaWx0ZXIgKTtcclxuXHRcdGFycmF5LnB1c2goIHRleHR1cmUuYW5pc290cm9weSApO1xyXG5cdFx0YXJyYXkucHVzaCggdGV4dHVyZS5pbnRlcm5hbEZvcm1hdCApO1xyXG5cdFx0YXJyYXkucHVzaCggdGV4dHVyZS5mb3JtYXQgKTtcclxuXHRcdGFycmF5LnB1c2goIHRleHR1cmUudHlwZSApO1xyXG5cdFx0YXJyYXkucHVzaCggdGV4dHVyZS5nZW5lcmF0ZU1pcG1hcHMgKTtcclxuXHRcdGFycmF5LnB1c2goIHRleHR1cmUucHJlbXVsdGlwbHlBbHBoYSApO1xyXG5cdFx0YXJyYXkucHVzaCggdGV4dHVyZS5mbGlwWSApO1xyXG5cdFx0YXJyYXkucHVzaCggdGV4dHVyZS51bnBhY2tBbGlnbm1lbnQgKTtcclxuXHRcdGFycmF5LnB1c2goIHRleHR1cmUuY29sb3JTcGFjZSApO1xyXG5cclxuXHRcdHJldHVybiBhcnJheS5qb2luKCk7XHJcblxyXG5cdH1cclxuXHJcblx0Ly9cclxuXHJcblx0ZnVuY3Rpb24gc2V0VGV4dHVyZTJEKCB0ZXh0dXJlLCBzbG90ICkge1xyXG5cclxuXHRcdGNvbnN0IHRleHR1cmVQcm9wZXJ0aWVzID0gcHJvcGVydGllcy5nZXQoIHRleHR1cmUgKTtcclxuXHJcblx0XHRpZiAoIHRleHR1cmUuaXNWaWRlb1RleHR1cmUgKSB1cGRhdGVWaWRlb1RleHR1cmUoIHRleHR1cmUgKTtcclxuXHJcblx0XHRpZiAoIHRleHR1cmUuaXNSZW5kZXJUYXJnZXRUZXh0dXJlID09PSBmYWxzZSAmJiB0ZXh0dXJlLnZlcnNpb24gPiAwICYmIHRleHR1cmVQcm9wZXJ0aWVzLl9fdmVyc2lvbiAhPT0gdGV4dHVyZS52ZXJzaW9uICkge1xyXG5cclxuXHRcdFx0Y29uc3QgaW1hZ2UgPSB0ZXh0dXJlLmltYWdlO1xyXG5cclxuXHRcdFx0aWYgKCBpbWFnZSA9PT0gbnVsbCApIHtcclxuXHJcblx0XHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuV2ViR0xSZW5kZXJlcjogVGV4dHVyZSBtYXJrZWQgZm9yIHVwZGF0ZSBidXQgbm8gaW1hZ2UgZGF0YSBmb3VuZC4nICk7XHJcblxyXG5cdFx0XHR9IGVsc2UgaWYgKCBpbWFnZS5jb21wbGV0ZSA9PT0gZmFsc2UgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLldlYkdMUmVuZGVyZXI6IFRleHR1cmUgbWFya2VkIGZvciB1cGRhdGUgYnV0IGltYWdlIGlzIGluY29tcGxldGUnICk7XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHR1cGxvYWRUZXh0dXJlKCB0ZXh0dXJlUHJvcGVydGllcywgdGV4dHVyZSwgc2xvdCApO1xyXG5cdFx0XHRcdHJldHVybjtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0c3RhdGUuYmluZFRleHR1cmUoIF9nbC5URVhUVVJFXzJELCB0ZXh0dXJlUHJvcGVydGllcy5fX3dlYmdsVGV4dHVyZSwgX2dsLlRFWFRVUkUwICsgc2xvdCApO1xyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHNldFRleHR1cmUyREFycmF5KCB0ZXh0dXJlLCBzbG90ICkge1xyXG5cclxuXHRcdGNvbnN0IHRleHR1cmVQcm9wZXJ0aWVzID0gcHJvcGVydGllcy5nZXQoIHRleHR1cmUgKTtcclxuXHJcblx0XHRpZiAoIHRleHR1cmUudmVyc2lvbiA+IDAgJiYgdGV4dHVyZVByb3BlcnRpZXMuX192ZXJzaW9uICE9PSB0ZXh0dXJlLnZlcnNpb24gKSB7XHJcblxyXG5cdFx0XHR1cGxvYWRUZXh0dXJlKCB0ZXh0dXJlUHJvcGVydGllcywgdGV4dHVyZSwgc2xvdCApO1xyXG5cdFx0XHRyZXR1cm47XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHN0YXRlLmJpbmRUZXh0dXJlKCBfZ2wuVEVYVFVSRV8yRF9BUlJBWSwgdGV4dHVyZVByb3BlcnRpZXMuX193ZWJnbFRleHR1cmUsIF9nbC5URVhUVVJFMCArIHNsb3QgKTtcclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBzZXRUZXh0dXJlM0QoIHRleHR1cmUsIHNsb3QgKSB7XHJcblxyXG5cdFx0Y29uc3QgdGV4dHVyZVByb3BlcnRpZXMgPSBwcm9wZXJ0aWVzLmdldCggdGV4dHVyZSApO1xyXG5cclxuXHRcdGlmICggdGV4dHVyZS52ZXJzaW9uID4gMCAmJiB0ZXh0dXJlUHJvcGVydGllcy5fX3ZlcnNpb24gIT09IHRleHR1cmUudmVyc2lvbiApIHtcclxuXHJcblx0XHRcdHVwbG9hZFRleHR1cmUoIHRleHR1cmVQcm9wZXJ0aWVzLCB0ZXh0dXJlLCBzbG90ICk7XHJcblx0XHRcdHJldHVybjtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0c3RhdGUuYmluZFRleHR1cmUoIF9nbC5URVhUVVJFXzNELCB0ZXh0dXJlUHJvcGVydGllcy5fX3dlYmdsVGV4dHVyZSwgX2dsLlRFWFRVUkUwICsgc2xvdCApO1xyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHNldFRleHR1cmVDdWJlKCB0ZXh0dXJlLCBzbG90ICkge1xyXG5cclxuXHRcdGNvbnN0IHRleHR1cmVQcm9wZXJ0aWVzID0gcHJvcGVydGllcy5nZXQoIHRleHR1cmUgKTtcclxuXHJcblx0XHRpZiAoIHRleHR1cmUudmVyc2lvbiA+IDAgJiYgdGV4dHVyZVByb3BlcnRpZXMuX192ZXJzaW9uICE9PSB0ZXh0dXJlLnZlcnNpb24gKSB7XHJcblxyXG5cdFx0XHR1cGxvYWRDdWJlVGV4dHVyZSggdGV4dHVyZVByb3BlcnRpZXMsIHRleHR1cmUsIHNsb3QgKTtcclxuXHRcdFx0cmV0dXJuO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRzdGF0ZS5iaW5kVGV4dHVyZSggX2dsLlRFWFRVUkVfQ1VCRV9NQVAsIHRleHR1cmVQcm9wZXJ0aWVzLl9fd2ViZ2xUZXh0dXJlLCBfZ2wuVEVYVFVSRTAgKyBzbG90ICk7XHJcblxyXG5cdH1cclxuXHJcblx0Y29uc3Qgd3JhcHBpbmdUb0dMID0ge1xyXG5cdFx0WyBSZXBlYXRXcmFwcGluZyBdOiBfZ2wuUkVQRUFULFxyXG5cdFx0WyBDbGFtcFRvRWRnZVdyYXBwaW5nIF06IF9nbC5DTEFNUF9UT19FREdFLFxyXG5cdFx0WyBNaXJyb3JlZFJlcGVhdFdyYXBwaW5nIF06IF9nbC5NSVJST1JFRF9SRVBFQVRcclxuXHR9O1xyXG5cclxuXHRjb25zdCBmaWx0ZXJUb0dMID0ge1xyXG5cdFx0WyBOZWFyZXN0RmlsdGVyIF06IF9nbC5ORUFSRVNULFxyXG5cdFx0WyBOZWFyZXN0TWlwbWFwTmVhcmVzdEZpbHRlciBdOiBfZ2wuTkVBUkVTVF9NSVBNQVBfTkVBUkVTVCxcclxuXHRcdFsgTmVhcmVzdE1pcG1hcExpbmVhckZpbHRlciBdOiBfZ2wuTkVBUkVTVF9NSVBNQVBfTElORUFSLFxyXG5cclxuXHRcdFsgTGluZWFyRmlsdGVyIF06IF9nbC5MSU5FQVIsXHJcblx0XHRbIExpbmVhck1pcG1hcE5lYXJlc3RGaWx0ZXIgXTogX2dsLkxJTkVBUl9NSVBNQVBfTkVBUkVTVCxcclxuXHRcdFsgTGluZWFyTWlwbWFwTGluZWFyRmlsdGVyIF06IF9nbC5MSU5FQVJfTUlQTUFQX0xJTkVBUlxyXG5cdH07XHJcblxyXG5cdGNvbnN0IGNvbXBhcmVUb0dMID0ge1xyXG5cdFx0WyBOZXZlckNvbXBhcmUgXTogX2dsLk5FVkVSLFxyXG5cdFx0WyBBbHdheXNDb21wYXJlIF06IF9nbC5BTFdBWVMsXHJcblx0XHRbIExlc3NDb21wYXJlIF06IF9nbC5MRVNTLFxyXG5cdFx0WyBMZXNzRXF1YWxDb21wYXJlIF06IF9nbC5MRVFVQUwsXHJcblx0XHRbIEVxdWFsQ29tcGFyZSBdOiBfZ2wuRVFVQUwsXHJcblx0XHRbIEdyZWF0ZXJFcXVhbENvbXBhcmUgXTogX2dsLkdFUVVBTCxcclxuXHRcdFsgR3JlYXRlckNvbXBhcmUgXTogX2dsLkdSRUFURVIsXHJcblx0XHRbIE5vdEVxdWFsQ29tcGFyZSBdOiBfZ2wuTk9URVFVQUxcclxuXHR9O1xyXG5cclxuXHRmdW5jdGlvbiBzZXRUZXh0dXJlUGFyYW1ldGVycyggdGV4dHVyZVR5cGUsIHRleHR1cmUsIHN1cHBvcnRzTWlwcyApIHtcclxuXHJcblx0XHRpZiAoIHRleHR1cmUudHlwZSA9PT0gRmxvYXRUeXBlICYmIGV4dGVuc2lvbnMuaGFzKCAnT0VTX3RleHR1cmVfZmxvYXRfbGluZWFyJyApID09PSBmYWxzZSAmJlxyXG5cdFx0XHQoIHRleHR1cmUubWFnRmlsdGVyID09PSBMaW5lYXJGaWx0ZXIgfHwgdGV4dHVyZS5tYWdGaWx0ZXIgPT09IExpbmVhck1pcG1hcE5lYXJlc3RGaWx0ZXIgfHwgdGV4dHVyZS5tYWdGaWx0ZXIgPT09IE5lYXJlc3RNaXBtYXBMaW5lYXJGaWx0ZXIgfHwgdGV4dHVyZS5tYWdGaWx0ZXIgPT09IExpbmVhck1pcG1hcExpbmVhckZpbHRlciB8fFxyXG5cdFx0XHR0ZXh0dXJlLm1pbkZpbHRlciA9PT0gTGluZWFyRmlsdGVyIHx8IHRleHR1cmUubWluRmlsdGVyID09PSBMaW5lYXJNaXBtYXBOZWFyZXN0RmlsdGVyIHx8IHRleHR1cmUubWluRmlsdGVyID09PSBOZWFyZXN0TWlwbWFwTGluZWFyRmlsdGVyIHx8IHRleHR1cmUubWluRmlsdGVyID09PSBMaW5lYXJNaXBtYXBMaW5lYXJGaWx0ZXIgKSApIHtcclxuXHJcblx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLldlYkdMUmVuZGVyZXI6IFVuYWJsZSB0byB1c2UgbGluZWFyIGZpbHRlcmluZyB3aXRoIGZsb2F0aW5nIHBvaW50IHRleHR1cmVzLiBPRVNfdGV4dHVyZV9mbG9hdF9saW5lYXIgbm90IHN1cHBvcnRlZCBvbiB0aGlzIGRldmljZS4nICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggc3VwcG9ydHNNaXBzICkge1xyXG5cclxuXHRcdFx0X2dsLnRleFBhcmFtZXRlcmkoIHRleHR1cmVUeXBlLCBfZ2wuVEVYVFVSRV9XUkFQX1MsIHdyYXBwaW5nVG9HTFsgdGV4dHVyZS53cmFwUyBdICk7XHJcblx0XHRcdF9nbC50ZXhQYXJhbWV0ZXJpKCB0ZXh0dXJlVHlwZSwgX2dsLlRFWFRVUkVfV1JBUF9ULCB3cmFwcGluZ1RvR0xbIHRleHR1cmUud3JhcFQgXSApO1xyXG5cclxuXHRcdFx0aWYgKCB0ZXh0dXJlVHlwZSA9PT0gX2dsLlRFWFRVUkVfM0QgfHwgdGV4dHVyZVR5cGUgPT09IF9nbC5URVhUVVJFXzJEX0FSUkFZICkge1xyXG5cclxuXHRcdFx0XHRfZ2wudGV4UGFyYW1ldGVyaSggdGV4dHVyZVR5cGUsIF9nbC5URVhUVVJFX1dSQVBfUiwgd3JhcHBpbmdUb0dMWyB0ZXh0dXJlLndyYXBSIF0gKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdF9nbC50ZXhQYXJhbWV0ZXJpKCB0ZXh0dXJlVHlwZSwgX2dsLlRFWFRVUkVfTUFHX0ZJTFRFUiwgZmlsdGVyVG9HTFsgdGV4dHVyZS5tYWdGaWx0ZXIgXSApO1xyXG5cdFx0XHRfZ2wudGV4UGFyYW1ldGVyaSggdGV4dHVyZVR5cGUsIF9nbC5URVhUVVJFX01JTl9GSUxURVIsIGZpbHRlclRvR0xbIHRleHR1cmUubWluRmlsdGVyIF0gKTtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0X2dsLnRleFBhcmFtZXRlcmkoIHRleHR1cmVUeXBlLCBfZ2wuVEVYVFVSRV9XUkFQX1MsIF9nbC5DTEFNUF9UT19FREdFICk7XHJcblx0XHRcdF9nbC50ZXhQYXJhbWV0ZXJpKCB0ZXh0dXJlVHlwZSwgX2dsLlRFWFRVUkVfV1JBUF9ULCBfZ2wuQ0xBTVBfVE9fRURHRSApO1xyXG5cclxuXHRcdFx0aWYgKCB0ZXh0dXJlVHlwZSA9PT0gX2dsLlRFWFRVUkVfM0QgfHwgdGV4dHVyZVR5cGUgPT09IF9nbC5URVhUVVJFXzJEX0FSUkFZICkge1xyXG5cclxuXHRcdFx0XHRfZ2wudGV4UGFyYW1ldGVyaSggdGV4dHVyZVR5cGUsIF9nbC5URVhUVVJFX1dSQVBfUiwgX2dsLkNMQU1QX1RPX0VER0UgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGlmICggdGV4dHVyZS53cmFwUyAhPT0gQ2xhbXBUb0VkZ2VXcmFwcGluZyB8fCB0ZXh0dXJlLndyYXBUICE9PSBDbGFtcFRvRWRnZVdyYXBwaW5nICkge1xyXG5cclxuXHRcdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5XZWJHTFJlbmRlcmVyOiBUZXh0dXJlIGlzIG5vdCBwb3dlciBvZiB0d28uIFRleHR1cmUud3JhcFMgYW5kIFRleHR1cmUud3JhcFQgc2hvdWxkIGJlIHNldCB0byBUSFJFRS5DbGFtcFRvRWRnZVdyYXBwaW5nLicgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdF9nbC50ZXhQYXJhbWV0ZXJpKCB0ZXh0dXJlVHlwZSwgX2dsLlRFWFRVUkVfTUFHX0ZJTFRFUiwgZmlsdGVyRmFsbGJhY2soIHRleHR1cmUubWFnRmlsdGVyICkgKTtcclxuXHRcdFx0X2dsLnRleFBhcmFtZXRlcmkoIHRleHR1cmVUeXBlLCBfZ2wuVEVYVFVSRV9NSU5fRklMVEVSLCBmaWx0ZXJGYWxsYmFjayggdGV4dHVyZS5taW5GaWx0ZXIgKSApO1xyXG5cclxuXHRcdFx0aWYgKCB0ZXh0dXJlLm1pbkZpbHRlciAhPT0gTmVhcmVzdEZpbHRlciAmJiB0ZXh0dXJlLm1pbkZpbHRlciAhPT0gTGluZWFyRmlsdGVyICkge1xyXG5cclxuXHRcdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5XZWJHTFJlbmRlcmVyOiBUZXh0dXJlIGlzIG5vdCBwb3dlciBvZiB0d28uIFRleHR1cmUubWluRmlsdGVyIHNob3VsZCBiZSBzZXQgdG8gVEhSRUUuTmVhcmVzdEZpbHRlciBvciBUSFJFRS5MaW5lYXJGaWx0ZXIuJyApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHRleHR1cmUuY29tcGFyZUZ1bmN0aW9uICkge1xyXG5cclxuXHRcdFx0X2dsLnRleFBhcmFtZXRlcmkoIHRleHR1cmVUeXBlLCBfZ2wuVEVYVFVSRV9DT01QQVJFX01PREUsIF9nbC5DT01QQVJFX1JFRl9UT19URVhUVVJFICk7XHJcblx0XHRcdF9nbC50ZXhQYXJhbWV0ZXJpKCB0ZXh0dXJlVHlwZSwgX2dsLlRFWFRVUkVfQ09NUEFSRV9GVU5DLCBjb21wYXJlVG9HTFsgdGV4dHVyZS5jb21wYXJlRnVuY3Rpb24gXSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIGV4dGVuc2lvbnMuaGFzKCAnRVhUX3RleHR1cmVfZmlsdGVyX2FuaXNvdHJvcGljJyApID09PSB0cnVlICkge1xyXG5cclxuXHRcdFx0Y29uc3QgZXh0ZW5zaW9uID0gZXh0ZW5zaW9ucy5nZXQoICdFWFRfdGV4dHVyZV9maWx0ZXJfYW5pc290cm9waWMnICk7XHJcblxyXG5cdFx0XHRpZiAoIHRleHR1cmUubWFnRmlsdGVyID09PSBOZWFyZXN0RmlsdGVyICkgcmV0dXJuO1xyXG5cdFx0XHRpZiAoIHRleHR1cmUubWluRmlsdGVyICE9PSBOZWFyZXN0TWlwbWFwTGluZWFyRmlsdGVyICYmIHRleHR1cmUubWluRmlsdGVyICE9PSBMaW5lYXJNaXBtYXBMaW5lYXJGaWx0ZXIgKSByZXR1cm47XHJcblx0XHRcdGlmICggdGV4dHVyZS50eXBlID09PSBGbG9hdFR5cGUgJiYgZXh0ZW5zaW9ucy5oYXMoICdPRVNfdGV4dHVyZV9mbG9hdF9saW5lYXInICkgPT09IGZhbHNlICkgcmV0dXJuOyAvLyB2ZXJpZnkgZXh0ZW5zaW9uIGZvciBXZWJHTCAxIGFuZCBXZWJHTCAyXHJcblx0XHRcdGlmICggaXNXZWJHTDIgPT09IGZhbHNlICYmICggdGV4dHVyZS50eXBlID09PSBIYWxmRmxvYXRUeXBlICYmIGV4dGVuc2lvbnMuaGFzKCAnT0VTX3RleHR1cmVfaGFsZl9mbG9hdF9saW5lYXInICkgPT09IGZhbHNlICkgKSByZXR1cm47IC8vIHZlcmlmeSBleHRlbnNpb24gZm9yIFdlYkdMIDEgb25seVxyXG5cclxuXHRcdFx0aWYgKCB0ZXh0dXJlLmFuaXNvdHJvcHkgPiAxIHx8IHByb3BlcnRpZXMuZ2V0KCB0ZXh0dXJlICkuX19jdXJyZW50QW5pc290cm9weSApIHtcclxuXHJcblx0XHRcdFx0X2dsLnRleFBhcmFtZXRlcmYoIHRleHR1cmVUeXBlLCBleHRlbnNpb24uVEVYVFVSRV9NQVhfQU5JU09UUk9QWV9FWFQsIE1hdGgubWluKCB0ZXh0dXJlLmFuaXNvdHJvcHksIGNhcGFiaWxpdGllcy5nZXRNYXhBbmlzb3Ryb3B5KCkgKSApO1xyXG5cdFx0XHRcdHByb3BlcnRpZXMuZ2V0KCB0ZXh0dXJlICkuX19jdXJyZW50QW5pc290cm9weSA9IHRleHR1cmUuYW5pc290cm9weTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gaW5pdFRleHR1cmUoIHRleHR1cmVQcm9wZXJ0aWVzLCB0ZXh0dXJlICkge1xyXG5cclxuXHRcdGxldCBmb3JjZVVwbG9hZCA9IGZhbHNlO1xyXG5cclxuXHRcdGlmICggdGV4dHVyZVByb3BlcnRpZXMuX193ZWJnbEluaXQgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdHRleHR1cmVQcm9wZXJ0aWVzLl9fd2ViZ2xJbml0ID0gdHJ1ZTtcclxuXHJcblx0XHRcdHRleHR1cmUuYWRkRXZlbnRMaXN0ZW5lciggJ2Rpc3Bvc2UnLCBvblRleHR1cmVEaXNwb3NlICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIGNyZWF0ZSBTb3VyY2UgPC0+IFdlYkdMVGV4dHVyZXMgbWFwcGluZyBpZiBuZWNlc3NhcnlcclxuXHJcblx0XHRjb25zdCBzb3VyY2UgPSB0ZXh0dXJlLnNvdXJjZTtcclxuXHRcdGxldCB3ZWJnbFRleHR1cmVzID0gX3NvdXJjZXMuZ2V0KCBzb3VyY2UgKTtcclxuXHJcblx0XHRpZiAoIHdlYmdsVGV4dHVyZXMgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdHdlYmdsVGV4dHVyZXMgPSB7fTtcclxuXHRcdFx0X3NvdXJjZXMuc2V0KCBzb3VyY2UsIHdlYmdsVGV4dHVyZXMgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gY2hlY2sgaWYgdGhlcmUgaXMgYWxyZWFkeSBhIFdlYkdMVGV4dHVyZSBvYmplY3QgZm9yIHRoZSBnaXZlbiB0ZXh0dXJlIHBhcmFtZXRlcnNcclxuXHJcblx0XHRjb25zdCB0ZXh0dXJlQ2FjaGVLZXkgPSBnZXRUZXh0dXJlQ2FjaGVLZXkoIHRleHR1cmUgKTtcclxuXHJcblx0XHRpZiAoIHRleHR1cmVDYWNoZUtleSAhPT0gdGV4dHVyZVByb3BlcnRpZXMuX19jYWNoZUtleSApIHtcclxuXHJcblx0XHRcdC8vIGlmIG5vdCwgY3JlYXRlIGEgbmV3IGluc3RhbmNlIG9mIFdlYkdMVGV4dHVyZVxyXG5cclxuXHRcdFx0aWYgKCB3ZWJnbFRleHR1cmVzWyB0ZXh0dXJlQ2FjaGVLZXkgXSA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHQvLyBjcmVhdGUgbmV3IGVudHJ5XHJcblxyXG5cdFx0XHRcdHdlYmdsVGV4dHVyZXNbIHRleHR1cmVDYWNoZUtleSBdID0ge1xyXG5cdFx0XHRcdFx0dGV4dHVyZTogX2dsLmNyZWF0ZVRleHR1cmUoKSxcclxuXHRcdFx0XHRcdHVzZWRUaW1lczogMFxyXG5cdFx0XHRcdH07XHJcblxyXG5cdFx0XHRcdGluZm8ubWVtb3J5LnRleHR1cmVzICsrO1xyXG5cclxuXHRcdFx0XHQvLyB3aGVuIGEgbmV3IGluc3RhbmNlIG9mIFdlYkdMVGV4dHVyZSB3YXMgY3JlYXRlZCwgYSB0ZXh0dXJlIHVwbG9hZCBpcyByZXF1aXJlZFxyXG5cdFx0XHRcdC8vIGV2ZW4gaWYgdGhlIGltYWdlIGNvbnRlbnRzIGFyZSBpZGVudGljYWxcclxuXHJcblx0XHRcdFx0Zm9yY2VVcGxvYWQgPSB0cnVlO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0d2ViZ2xUZXh0dXJlc1sgdGV4dHVyZUNhY2hlS2V5IF0udXNlZFRpbWVzICsrO1xyXG5cclxuXHRcdFx0Ly8gZXZlcnkgdGltZSB0aGUgdGV4dHVyZSBjYWNoZSBrZXkgY2hhbmdlcywgaXQncyBuZWNlc3NhcnkgdG8gY2hlY2sgaWYgYW4gaW5zdGFuY2Ugb2ZcclxuXHRcdFx0Ly8gV2ViR0xUZXh0dXJlIGNhbiBiZSBkZWxldGVkIGluIG9yZGVyIHRvIGF2b2lkIGEgbWVtb3J5IGxlYWsuXHJcblxyXG5cdFx0XHRjb25zdCB3ZWJnbFRleHR1cmUgPSB3ZWJnbFRleHR1cmVzWyB0ZXh0dXJlUHJvcGVydGllcy5fX2NhY2hlS2V5IF07XHJcblxyXG5cdFx0XHRpZiAoIHdlYmdsVGV4dHVyZSAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHR3ZWJnbFRleHR1cmVzWyB0ZXh0dXJlUHJvcGVydGllcy5fX2NhY2hlS2V5IF0udXNlZFRpbWVzIC0tO1xyXG5cclxuXHRcdFx0XHRpZiAoIHdlYmdsVGV4dHVyZS51c2VkVGltZXMgPT09IDAgKSB7XHJcblxyXG5cdFx0XHRcdFx0ZGVsZXRlVGV4dHVyZSggdGV4dHVyZSApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyBzdG9yZSByZWZlcmVuY2VzIHRvIGNhY2hlIGtleSBhbmQgV2ViR0xUZXh0dXJlIG9iamVjdFxyXG5cclxuXHRcdFx0dGV4dHVyZVByb3BlcnRpZXMuX19jYWNoZUtleSA9IHRleHR1cmVDYWNoZUtleTtcclxuXHRcdFx0dGV4dHVyZVByb3BlcnRpZXMuX193ZWJnbFRleHR1cmUgPSB3ZWJnbFRleHR1cmVzWyB0ZXh0dXJlQ2FjaGVLZXkgXS50ZXh0dXJlO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gZm9yY2VVcGxvYWQ7XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gdXBsb2FkVGV4dHVyZSggdGV4dHVyZVByb3BlcnRpZXMsIHRleHR1cmUsIHNsb3QgKSB7XHJcblxyXG5cdFx0bGV0IHRleHR1cmVUeXBlID0gX2dsLlRFWFRVUkVfMkQ7XHJcblxyXG5cdFx0aWYgKCB0ZXh0dXJlLmlzRGF0YUFycmF5VGV4dHVyZSB8fCB0ZXh0dXJlLmlzQ29tcHJlc3NlZEFycmF5VGV4dHVyZSApIHRleHR1cmVUeXBlID0gX2dsLlRFWFRVUkVfMkRfQVJSQVk7XHJcblx0XHRpZiAoIHRleHR1cmUuaXNEYXRhM0RUZXh0dXJlICkgdGV4dHVyZVR5cGUgPSBfZ2wuVEVYVFVSRV8zRDtcclxuXHJcblx0XHRjb25zdCBmb3JjZVVwbG9hZCA9IGluaXRUZXh0dXJlKCB0ZXh0dXJlUHJvcGVydGllcywgdGV4dHVyZSApO1xyXG5cdFx0Y29uc3Qgc291cmNlID0gdGV4dHVyZS5zb3VyY2U7XHJcblxyXG5cdFx0c3RhdGUuYmluZFRleHR1cmUoIHRleHR1cmVUeXBlLCB0ZXh0dXJlUHJvcGVydGllcy5fX3dlYmdsVGV4dHVyZSwgX2dsLlRFWFRVUkUwICsgc2xvdCApO1xyXG5cclxuXHRcdGNvbnN0IHNvdXJjZVByb3BlcnRpZXMgPSBwcm9wZXJ0aWVzLmdldCggc291cmNlICk7XHJcblxyXG5cdFx0aWYgKCBzb3VyY2UudmVyc2lvbiAhPT0gc291cmNlUHJvcGVydGllcy5fX3ZlcnNpb24gfHwgZm9yY2VVcGxvYWQgPT09IHRydWUgKSB7XHJcblxyXG5cdFx0XHRzdGF0ZS5hY3RpdmVUZXh0dXJlKCBfZ2wuVEVYVFVSRTAgKyBzbG90ICk7XHJcblxyXG5cdFx0XHRjb25zdCB3b3JraW5nUHJpbWFyaWVzID0gQ29sb3JNYW5hZ2VtZW50LmdldFByaW1hcmllcyggQ29sb3JNYW5hZ2VtZW50LndvcmtpbmdDb2xvclNwYWNlICk7XHJcblx0XHRcdGNvbnN0IHRleHR1cmVQcmltYXJpZXMgPSB0ZXh0dXJlLmNvbG9yU3BhY2UgPT09IE5vQ29sb3JTcGFjZSA/IG51bGwgOiBDb2xvck1hbmFnZW1lbnQuZ2V0UHJpbWFyaWVzKCB0ZXh0dXJlLmNvbG9yU3BhY2UgKTtcclxuXHRcdFx0Y29uc3QgdW5wYWNrQ29udmVyc2lvbiA9IHRleHR1cmUuY29sb3JTcGFjZSA9PT0gTm9Db2xvclNwYWNlIHx8IHdvcmtpbmdQcmltYXJpZXMgPT09IHRleHR1cmVQcmltYXJpZXMgPyBfZ2wuTk9ORSA6IF9nbC5CUk9XU0VSX0RFRkFVTFRfV0VCR0w7XHJcblxyXG5cdFx0XHRfZ2wucGl4ZWxTdG9yZWkoIF9nbC5VTlBBQ0tfRkxJUF9ZX1dFQkdMLCB0ZXh0dXJlLmZsaXBZICk7XHJcblx0XHRcdF9nbC5waXhlbFN0b3JlaSggX2dsLlVOUEFDS19QUkVNVUxUSVBMWV9BTFBIQV9XRUJHTCwgdGV4dHVyZS5wcmVtdWx0aXBseUFscGhhICk7XHJcblx0XHRcdF9nbC5waXhlbFN0b3JlaSggX2dsLlVOUEFDS19BTElHTk1FTlQsIHRleHR1cmUudW5wYWNrQWxpZ25tZW50ICk7XHJcblx0XHRcdF9nbC5waXhlbFN0b3JlaSggX2dsLlVOUEFDS19DT0xPUlNQQUNFX0NPTlZFUlNJT05fV0VCR0wsIHVucGFja0NvbnZlcnNpb24gKTtcclxuXHJcblx0XHRcdGNvbnN0IG5lZWRzUG93ZXJPZlR3byA9IHRleHR1cmVOZWVkc1Bvd2VyT2ZUd28oIHRleHR1cmUgKSAmJiBpc1Bvd2VyT2ZUd28oIHRleHR1cmUuaW1hZ2UgKSA9PT0gZmFsc2U7XHJcblx0XHRcdGxldCBpbWFnZSA9IHJlc2l6ZUltYWdlKCB0ZXh0dXJlLmltYWdlLCBuZWVkc1Bvd2VyT2ZUd28sIGZhbHNlLCBjYXBhYmlsaXRpZXMubWF4VGV4dHVyZVNpemUgKTtcclxuXHRcdFx0aW1hZ2UgPSB2ZXJpZnlDb2xvclNwYWNlKCB0ZXh0dXJlLCBpbWFnZSApO1xyXG5cclxuXHRcdFx0Y29uc3Qgc3VwcG9ydHNNaXBzID0gaXNQb3dlck9mVHdvKCBpbWFnZSApIHx8IGlzV2ViR0wyLFxyXG5cdFx0XHRcdGdsRm9ybWF0ID0gdXRpbHMuY29udmVydCggdGV4dHVyZS5mb3JtYXQsIHRleHR1cmUuY29sb3JTcGFjZSApO1xyXG5cclxuXHRcdFx0bGV0IGdsVHlwZSA9IHV0aWxzLmNvbnZlcnQoIHRleHR1cmUudHlwZSApLFxyXG5cdFx0XHRcdGdsSW50ZXJuYWxGb3JtYXQgPSBnZXRJbnRlcm5hbEZvcm1hdCggdGV4dHVyZS5pbnRlcm5hbEZvcm1hdCwgZ2xGb3JtYXQsIGdsVHlwZSwgdGV4dHVyZS5jb2xvclNwYWNlLCB0ZXh0dXJlLmlzVmlkZW9UZXh0dXJlICk7XHJcblxyXG5cdFx0XHRzZXRUZXh0dXJlUGFyYW1ldGVycyggdGV4dHVyZVR5cGUsIHRleHR1cmUsIHN1cHBvcnRzTWlwcyApO1xyXG5cclxuXHRcdFx0bGV0IG1pcG1hcDtcclxuXHRcdFx0Y29uc3QgbWlwbWFwcyA9IHRleHR1cmUubWlwbWFwcztcclxuXHJcblx0XHRcdGNvbnN0IHVzZVRleFN0b3JhZ2UgPSAoIGlzV2ViR0wyICYmIHRleHR1cmUuaXNWaWRlb1RleHR1cmUgIT09IHRydWUgJiYgZ2xJbnRlcm5hbEZvcm1hdCAhPT0gUkdCX0VUQzFfRm9ybWF0ICk7XHJcblx0XHRcdGNvbnN0IGFsbG9jYXRlTWVtb3J5ID0gKCBzb3VyY2VQcm9wZXJ0aWVzLl9fdmVyc2lvbiA9PT0gdW5kZWZpbmVkICkgfHwgKCBmb3JjZVVwbG9hZCA9PT0gdHJ1ZSApO1xyXG5cdFx0XHRjb25zdCBkYXRhUmVhZHkgPSBzb3VyY2UuZGF0YVJlYWR5O1xyXG5cdFx0XHRjb25zdCBsZXZlbHMgPSBnZXRNaXBMZXZlbHMoIHRleHR1cmUsIGltYWdlLCBzdXBwb3J0c01pcHMgKTtcclxuXHJcblx0XHRcdGlmICggdGV4dHVyZS5pc0RlcHRoVGV4dHVyZSApIHtcclxuXHJcblx0XHRcdFx0Ly8gcG9wdWxhdGUgZGVwdGggdGV4dHVyZSB3aXRoIGR1bW15IGRhdGFcclxuXHJcblx0XHRcdFx0Z2xJbnRlcm5hbEZvcm1hdCA9IF9nbC5ERVBUSF9DT01QT05FTlQ7XHJcblxyXG5cdFx0XHRcdGlmICggaXNXZWJHTDIgKSB7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCB0ZXh0dXJlLnR5cGUgPT09IEZsb2F0VHlwZSApIHtcclxuXHJcblx0XHRcdFx0XHRcdGdsSW50ZXJuYWxGb3JtYXQgPSBfZ2wuREVQVEhfQ09NUE9ORU5UMzJGO1xyXG5cclxuXHRcdFx0XHRcdH0gZWxzZSBpZiAoIHRleHR1cmUudHlwZSA9PT0gVW5zaWduZWRJbnRUeXBlICkge1xyXG5cclxuXHRcdFx0XHRcdFx0Z2xJbnRlcm5hbEZvcm1hdCA9IF9nbC5ERVBUSF9DT01QT05FTlQyNDtcclxuXHJcblx0XHRcdFx0XHR9IGVsc2UgaWYgKCB0ZXh0dXJlLnR5cGUgPT09IFVuc2lnbmVkSW50MjQ4VHlwZSApIHtcclxuXHJcblx0XHRcdFx0XHRcdGdsSW50ZXJuYWxGb3JtYXQgPSBfZ2wuREVQVEgyNF9TVEVOQ0lMODtcclxuXHJcblx0XHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdFx0Z2xJbnRlcm5hbEZvcm1hdCA9IF9nbC5ERVBUSF9DT01QT05FTlQxNjsgLy8gV2ViR0wyIHJlcXVpcmVzIHNpemVkIGludGVybmFsZm9ybWF0IGZvciBnbFRleEltYWdlMkRcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCB0ZXh0dXJlLnR5cGUgPT09IEZsb2F0VHlwZSApIHtcclxuXHJcblx0XHRcdFx0XHRcdGNvbnNvbGUuZXJyb3IoICdXZWJHTFJlbmRlcmVyOiBGbG9hdGluZyBwb2ludCBkZXB0aCB0ZXh0dXJlIHJlcXVpcmVzIFdlYkdMMi4nICk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdC8vIHZhbGlkYXRpb24gY2hlY2tzIGZvciBXZWJHTCAxXHJcblxyXG5cdFx0XHRcdGlmICggdGV4dHVyZS5mb3JtYXQgPT09IERlcHRoRm9ybWF0ICYmIGdsSW50ZXJuYWxGb3JtYXQgPT09IF9nbC5ERVBUSF9DT01QT05FTlQgKSB7XHJcblxyXG5cdFx0XHRcdFx0Ly8gVGhlIGVycm9yIElOVkFMSURfT1BFUkFUSU9OIGlzIGdlbmVyYXRlZCBieSB0ZXhJbWFnZTJEIGlmIGZvcm1hdCBhbmQgaW50ZXJuYWxmb3JtYXQgYXJlXHJcblx0XHRcdFx0XHQvLyBERVBUSF9DT01QT05FTlQgYW5kIHR5cGUgaXMgbm90IFVOU0lHTkVEX1NIT1JUIG9yIFVOU0lHTkVEX0lOVFxyXG5cdFx0XHRcdFx0Ly8gKGh0dHBzOi8vd3d3Lmtocm9ub3Mub3JnL3JlZ2lzdHJ5L3dlYmdsL2V4dGVuc2lvbnMvV0VCR0xfZGVwdGhfdGV4dHVyZS8pXHJcblx0XHRcdFx0XHRpZiAoIHRleHR1cmUudHlwZSAhPT0gVW5zaWduZWRTaG9ydFR5cGUgJiYgdGV4dHVyZS50eXBlICE9PSBVbnNpZ25lZEludFR5cGUgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5XZWJHTFJlbmRlcmVyOiBVc2UgVW5zaWduZWRTaG9ydFR5cGUgb3IgVW5zaWduZWRJbnRUeXBlIGZvciBEZXB0aEZvcm1hdCBEZXB0aFRleHR1cmUuJyApO1xyXG5cclxuXHRcdFx0XHRcdFx0dGV4dHVyZS50eXBlID0gVW5zaWduZWRJbnRUeXBlO1xyXG5cdFx0XHRcdFx0XHRnbFR5cGUgPSB1dGlscy5jb252ZXJ0KCB0ZXh0dXJlLnR5cGUgKTtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0aWYgKCB0ZXh0dXJlLmZvcm1hdCA9PT0gRGVwdGhTdGVuY2lsRm9ybWF0ICYmIGdsSW50ZXJuYWxGb3JtYXQgPT09IF9nbC5ERVBUSF9DT01QT05FTlQgKSB7XHJcblxyXG5cdFx0XHRcdFx0Ly8gRGVwdGggc3RlbmNpbCB0ZXh0dXJlcyBuZWVkIHRoZSBERVBUSF9TVEVOQ0lMIGludGVybmFsIGZvcm1hdFxyXG5cdFx0XHRcdFx0Ly8gKGh0dHBzOi8vd3d3Lmtocm9ub3Mub3JnL3JlZ2lzdHJ5L3dlYmdsL2V4dGVuc2lvbnMvV0VCR0xfZGVwdGhfdGV4dHVyZS8pXHJcblx0XHRcdFx0XHRnbEludGVybmFsRm9ybWF0ID0gX2dsLkRFUFRIX1NURU5DSUw7XHJcblxyXG5cdFx0XHRcdFx0Ly8gVGhlIGVycm9yIElOVkFMSURfT1BFUkFUSU9OIGlzIGdlbmVyYXRlZCBieSB0ZXhJbWFnZTJEIGlmIGZvcm1hdCBhbmQgaW50ZXJuYWxmb3JtYXQgYXJlXHJcblx0XHRcdFx0XHQvLyBERVBUSF9TVEVOQ0lMIGFuZCB0eXBlIGlzIG5vdCBVTlNJR05FRF9JTlRfMjRfOF9XRUJHTC5cclxuXHRcdFx0XHRcdC8vIChodHRwczovL3d3dy5raHJvbm9zLm9yZy9yZWdpc3RyeS93ZWJnbC9leHRlbnNpb25zL1dFQkdMX2RlcHRoX3RleHR1cmUvKVxyXG5cdFx0XHRcdFx0aWYgKCB0ZXh0dXJlLnR5cGUgIT09IFVuc2lnbmVkSW50MjQ4VHlwZSApIHtcclxuXHJcblx0XHRcdFx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLldlYkdMUmVuZGVyZXI6IFVzZSBVbnNpZ25lZEludDI0OFR5cGUgZm9yIERlcHRoU3RlbmNpbEZvcm1hdCBEZXB0aFRleHR1cmUuJyApO1xyXG5cclxuXHRcdFx0XHRcdFx0dGV4dHVyZS50eXBlID0gVW5zaWduZWRJbnQyNDhUeXBlO1xyXG5cdFx0XHRcdFx0XHRnbFR5cGUgPSB1dGlscy5jb252ZXJ0KCB0ZXh0dXJlLnR5cGUgKTtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0Ly9cclxuXHJcblx0XHRcdFx0aWYgKCBhbGxvY2F0ZU1lbW9yeSApIHtcclxuXHJcblx0XHRcdFx0XHRpZiAoIHVzZVRleFN0b3JhZ2UgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRzdGF0ZS50ZXhTdG9yYWdlMkQoIF9nbC5URVhUVVJFXzJELCAxLCBnbEludGVybmFsRm9ybWF0LCBpbWFnZS53aWR0aCwgaW1hZ2UuaGVpZ2h0ICk7XHJcblxyXG5cdFx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRcdHN0YXRlLnRleEltYWdlMkQoIF9nbC5URVhUVVJFXzJELCAwLCBnbEludGVybmFsRm9ybWF0LCBpbWFnZS53aWR0aCwgaW1hZ2UuaGVpZ2h0LCAwLCBnbEZvcm1hdCwgZ2xUeXBlLCBudWxsICk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9IGVsc2UgaWYgKCB0ZXh0dXJlLmlzRGF0YVRleHR1cmUgKSB7XHJcblxyXG5cdFx0XHRcdC8vIHVzZSBtYW51YWxseSBjcmVhdGVkIG1pcG1hcHMgaWYgYXZhaWxhYmxlXHJcblx0XHRcdFx0Ly8gaWYgdGhlcmUgYXJlIG5vIG1hbnVhbCBtaXBtYXBzXHJcblx0XHRcdFx0Ly8gc2V0IDAgbGV2ZWwgbWlwbWFwIGFuZCB0aGVuIHVzZSBHTCB0byBnZW5lcmF0ZSBvdGhlciBtaXBtYXAgbGV2ZWxzXHJcblxyXG5cdFx0XHRcdGlmICggbWlwbWFwcy5sZW5ndGggPiAwICYmIHN1cHBvcnRzTWlwcyApIHtcclxuXHJcblx0XHRcdFx0XHRpZiAoIHVzZVRleFN0b3JhZ2UgJiYgYWxsb2NhdGVNZW1vcnkgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRzdGF0ZS50ZXhTdG9yYWdlMkQoIF9nbC5URVhUVVJFXzJELCBsZXZlbHMsIGdsSW50ZXJuYWxGb3JtYXQsIG1pcG1hcHNbIDAgXS53aWR0aCwgbWlwbWFwc1sgMCBdLmhlaWdodCApO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gbWlwbWFwcy5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0XHRcdG1pcG1hcCA9IG1pcG1hcHNbIGkgXTtcclxuXHJcblx0XHRcdFx0XHRcdGlmICggdXNlVGV4U3RvcmFnZSApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0aWYgKCBkYXRhUmVhZHkgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0c3RhdGUudGV4U3ViSW1hZ2UyRCggX2dsLlRFWFRVUkVfMkQsIGksIDAsIDAsIG1pcG1hcC53aWR0aCwgbWlwbWFwLmhlaWdodCwgZ2xGb3JtYXQsIGdsVHlwZSwgbWlwbWFwLmRhdGEgKTtcclxuXHJcblx0XHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0c3RhdGUudGV4SW1hZ2UyRCggX2dsLlRFWFRVUkVfMkQsIGksIGdsSW50ZXJuYWxGb3JtYXQsIG1pcG1hcC53aWR0aCwgbWlwbWFwLmhlaWdodCwgMCwgZ2xGb3JtYXQsIGdsVHlwZSwgbWlwbWFwLmRhdGEgKTtcclxuXHJcblx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0dGV4dHVyZS5nZW5lcmF0ZU1pcG1hcHMgPSBmYWxzZTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRpZiAoIHVzZVRleFN0b3JhZ2UgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRpZiAoIGFsbG9jYXRlTWVtb3J5ICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRzdGF0ZS50ZXhTdG9yYWdlMkQoIF9nbC5URVhUVVJFXzJELCBsZXZlbHMsIGdsSW50ZXJuYWxGb3JtYXQsIGltYWdlLndpZHRoLCBpbWFnZS5oZWlnaHQgKTtcclxuXHJcblx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRcdGlmICggZGF0YVJlYWR5ICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRzdGF0ZS50ZXhTdWJJbWFnZTJEKCBfZ2wuVEVYVFVSRV8yRCwgMCwgMCwgMCwgaW1hZ2Uud2lkdGgsIGltYWdlLmhlaWdodCwgZ2xGb3JtYXQsIGdsVHlwZSwgaW1hZ2UuZGF0YSApO1xyXG5cclxuXHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHRzdGF0ZS50ZXhJbWFnZTJEKCBfZ2wuVEVYVFVSRV8yRCwgMCwgZ2xJbnRlcm5hbEZvcm1hdCwgaW1hZ2Uud2lkdGgsIGltYWdlLmhlaWdodCwgMCwgZ2xGb3JtYXQsIGdsVHlwZSwgaW1hZ2UuZGF0YSApO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fSBlbHNlIGlmICggdGV4dHVyZS5pc0NvbXByZXNzZWRUZXh0dXJlICkge1xyXG5cclxuXHRcdFx0XHRpZiAoIHRleHR1cmUuaXNDb21wcmVzc2VkQXJyYXlUZXh0dXJlICkge1xyXG5cclxuXHRcdFx0XHRcdGlmICggdXNlVGV4U3RvcmFnZSAmJiBhbGxvY2F0ZU1lbW9yeSApIHtcclxuXHJcblx0XHRcdFx0XHRcdHN0YXRlLnRleFN0b3JhZ2UzRCggX2dsLlRFWFRVUkVfMkRfQVJSQVksIGxldmVscywgZ2xJbnRlcm5hbEZvcm1hdCwgbWlwbWFwc1sgMCBdLndpZHRoLCBtaXBtYXBzWyAwIF0uaGVpZ2h0LCBpbWFnZS5kZXB0aCApO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gbWlwbWFwcy5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0XHRcdG1pcG1hcCA9IG1pcG1hcHNbIGkgXTtcclxuXHJcblx0XHRcdFx0XHRcdGlmICggdGV4dHVyZS5mb3JtYXQgIT09IFJHQkFGb3JtYXQgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdGlmICggZ2xGb3JtYXQgIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0aWYgKCB1c2VUZXhTdG9yYWdlICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRcdFx0aWYgKCBkYXRhUmVhZHkgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdHN0YXRlLmNvbXByZXNzZWRUZXhTdWJJbWFnZTNEKCBfZ2wuVEVYVFVSRV8yRF9BUlJBWSwgaSwgMCwgMCwgMCwgbWlwbWFwLndpZHRoLCBtaXBtYXAuaGVpZ2h0LCBpbWFnZS5kZXB0aCwgZ2xGb3JtYXQsIG1pcG1hcC5kYXRhLCAwLCAwICk7XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHRcdHN0YXRlLmNvbXByZXNzZWRUZXhJbWFnZTNEKCBfZ2wuVEVYVFVSRV8yRF9BUlJBWSwgaSwgZ2xJbnRlcm5hbEZvcm1hdCwgbWlwbWFwLndpZHRoLCBtaXBtYXAuaGVpZ2h0LCBpbWFnZS5kZXB0aCwgMCwgbWlwbWFwLmRhdGEsIDAsIDAgKTtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuV2ViR0xSZW5kZXJlcjogQXR0ZW1wdCB0byBsb2FkIHVuc3VwcG9ydGVkIGNvbXByZXNzZWQgdGV4dHVyZSBmb3JtYXQgaW4gLnVwbG9hZFRleHR1cmUoKScgKTtcclxuXHJcblx0XHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0aWYgKCB1c2VUZXhTdG9yYWdlICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRcdGlmICggZGF0YVJlYWR5ICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRcdFx0c3RhdGUudGV4U3ViSW1hZ2UzRCggX2dsLlRFWFRVUkVfMkRfQVJSQVksIGksIDAsIDAsIDAsIG1pcG1hcC53aWR0aCwgbWlwbWFwLmhlaWdodCwgaW1hZ2UuZGVwdGgsIGdsRm9ybWF0LCBnbFR5cGUsIG1pcG1hcC5kYXRhICk7XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRcdHN0YXRlLnRleEltYWdlM0QoIF9nbC5URVhUVVJFXzJEX0FSUkFZLCBpLCBnbEludGVybmFsRm9ybWF0LCBtaXBtYXAud2lkdGgsIG1pcG1hcC5oZWlnaHQsIGltYWdlLmRlcHRoLCAwLCBnbEZvcm1hdCwgZ2xUeXBlLCBtaXBtYXAuZGF0YSApO1xyXG5cclxuXHRcdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdGlmICggdXNlVGV4U3RvcmFnZSAmJiBhbGxvY2F0ZU1lbW9yeSApIHtcclxuXHJcblx0XHRcdFx0XHRcdHN0YXRlLnRleFN0b3JhZ2UyRCggX2dsLlRFWFRVUkVfMkQsIGxldmVscywgZ2xJbnRlcm5hbEZvcm1hdCwgbWlwbWFwc1sgMCBdLndpZHRoLCBtaXBtYXBzWyAwIF0uaGVpZ2h0ICk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSBtaXBtYXBzLmxlbmd0aDsgaSA8IGlsOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRcdFx0bWlwbWFwID0gbWlwbWFwc1sgaSBdO1xyXG5cclxuXHRcdFx0XHRcdFx0aWYgKCB0ZXh0dXJlLmZvcm1hdCAhPT0gUkdCQUZvcm1hdCApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0aWYgKCBnbEZvcm1hdCAhPT0gbnVsbCApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHRpZiAoIHVzZVRleFN0b3JhZ2UgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0XHRpZiAoIGRhdGFSZWFkeSApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0c3RhdGUuY29tcHJlc3NlZFRleFN1YkltYWdlMkQoIF9nbC5URVhUVVJFXzJELCBpLCAwLCAwLCBtaXBtYXAud2lkdGgsIG1pcG1hcC5oZWlnaHQsIGdsRm9ybWF0LCBtaXBtYXAuZGF0YSApO1xyXG5cclxuXHRcdFx0XHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0XHRzdGF0ZS5jb21wcmVzc2VkVGV4SW1hZ2UyRCggX2dsLlRFWFRVUkVfMkQsIGksIGdsSW50ZXJuYWxGb3JtYXQsIG1pcG1hcC53aWR0aCwgbWlwbWFwLmhlaWdodCwgMCwgbWlwbWFwLmRhdGEgKTtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuV2ViR0xSZW5kZXJlcjogQXR0ZW1wdCB0byBsb2FkIHVuc3VwcG9ydGVkIGNvbXByZXNzZWQgdGV4dHVyZSBmb3JtYXQgaW4gLnVwbG9hZFRleHR1cmUoKScgKTtcclxuXHJcblx0XHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0aWYgKCB1c2VUZXhTdG9yYWdlICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRcdGlmICggZGF0YVJlYWR5ICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRcdFx0c3RhdGUudGV4U3ViSW1hZ2UyRCggX2dsLlRFWFRVUkVfMkQsIGksIDAsIDAsIG1pcG1hcC53aWR0aCwgbWlwbWFwLmhlaWdodCwgZ2xGb3JtYXQsIGdsVHlwZSwgbWlwbWFwLmRhdGEgKTtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0c3RhdGUudGV4SW1hZ2UyRCggX2dsLlRFWFRVUkVfMkQsIGksIGdsSW50ZXJuYWxGb3JtYXQsIG1pcG1hcC53aWR0aCwgbWlwbWFwLmhlaWdodCwgMCwgZ2xGb3JtYXQsIGdsVHlwZSwgbWlwbWFwLmRhdGEgKTtcclxuXHJcblx0XHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fSBlbHNlIGlmICggdGV4dHVyZS5pc0RhdGFBcnJheVRleHR1cmUgKSB7XHJcblxyXG5cdFx0XHRcdGlmICggdXNlVGV4U3RvcmFnZSApIHtcclxuXHJcblx0XHRcdFx0XHRpZiAoIGFsbG9jYXRlTWVtb3J5ICkge1xyXG5cclxuXHRcdFx0XHRcdFx0c3RhdGUudGV4U3RvcmFnZTNEKCBfZ2wuVEVYVFVSRV8yRF9BUlJBWSwgbGV2ZWxzLCBnbEludGVybmFsRm9ybWF0LCBpbWFnZS53aWR0aCwgaW1hZ2UuaGVpZ2h0LCBpbWFnZS5kZXB0aCApO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRpZiAoIGRhdGFSZWFkeSApIHtcclxuXHJcblx0XHRcdFx0XHRcdHN0YXRlLnRleFN1YkltYWdlM0QoIF9nbC5URVhUVVJFXzJEX0FSUkFZLCAwLCAwLCAwLCAwLCBpbWFnZS53aWR0aCwgaW1hZ2UuaGVpZ2h0LCBpbWFnZS5kZXB0aCwgZ2xGb3JtYXQsIGdsVHlwZSwgaW1hZ2UuZGF0YSApO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRzdGF0ZS50ZXhJbWFnZTNEKCBfZ2wuVEVYVFVSRV8yRF9BUlJBWSwgMCwgZ2xJbnRlcm5hbEZvcm1hdCwgaW1hZ2Uud2lkdGgsIGltYWdlLmhlaWdodCwgaW1hZ2UuZGVwdGgsIDAsIGdsRm9ybWF0LCBnbFR5cGUsIGltYWdlLmRhdGEgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fSBlbHNlIGlmICggdGV4dHVyZS5pc0RhdGEzRFRleHR1cmUgKSB7XHJcblxyXG5cdFx0XHRcdGlmICggdXNlVGV4U3RvcmFnZSApIHtcclxuXHJcblx0XHRcdFx0XHRpZiAoIGFsbG9jYXRlTWVtb3J5ICkge1xyXG5cclxuXHRcdFx0XHRcdFx0c3RhdGUudGV4U3RvcmFnZTNEKCBfZ2wuVEVYVFVSRV8zRCwgbGV2ZWxzLCBnbEludGVybmFsRm9ybWF0LCBpbWFnZS53aWR0aCwgaW1hZ2UuaGVpZ2h0LCBpbWFnZS5kZXB0aCApO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRpZiAoIGRhdGFSZWFkeSApIHtcclxuXHJcblx0XHRcdFx0XHRcdHN0YXRlLnRleFN1YkltYWdlM0QoIF9nbC5URVhUVVJFXzNELCAwLCAwLCAwLCAwLCBpbWFnZS53aWR0aCwgaW1hZ2UuaGVpZ2h0LCBpbWFnZS5kZXB0aCwgZ2xGb3JtYXQsIGdsVHlwZSwgaW1hZ2UuZGF0YSApO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRzdGF0ZS50ZXhJbWFnZTNEKCBfZ2wuVEVYVFVSRV8zRCwgMCwgZ2xJbnRlcm5hbEZvcm1hdCwgaW1hZ2Uud2lkdGgsIGltYWdlLmhlaWdodCwgaW1hZ2UuZGVwdGgsIDAsIGdsRm9ybWF0LCBnbFR5cGUsIGltYWdlLmRhdGEgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fSBlbHNlIGlmICggdGV4dHVyZS5pc0ZyYW1lYnVmZmVyVGV4dHVyZSApIHtcclxuXHJcblx0XHRcdFx0aWYgKCBhbGxvY2F0ZU1lbW9yeSApIHtcclxuXHJcblx0XHRcdFx0XHRpZiAoIHVzZVRleFN0b3JhZ2UgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRzdGF0ZS50ZXhTdG9yYWdlMkQoIF9nbC5URVhUVVJFXzJELCBsZXZlbHMsIGdsSW50ZXJuYWxGb3JtYXQsIGltYWdlLndpZHRoLCBpbWFnZS5oZWlnaHQgKTtcclxuXHJcblx0XHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdFx0bGV0IHdpZHRoID0gaW1hZ2Uud2lkdGgsIGhlaWdodCA9IGltYWdlLmhlaWdodDtcclxuXHJcblx0XHRcdFx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IGxldmVsczsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0c3RhdGUudGV4SW1hZ2UyRCggX2dsLlRFWFRVUkVfMkQsIGksIGdsSW50ZXJuYWxGb3JtYXQsIHdpZHRoLCBoZWlnaHQsIDAsIGdsRm9ybWF0LCBnbFR5cGUsIG51bGwgKTtcclxuXHJcblx0XHRcdFx0XHRcdFx0d2lkdGggPj49IDE7XHJcblx0XHRcdFx0XHRcdFx0aGVpZ2h0ID4+PSAxO1xyXG5cclxuXHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0Ly8gcmVndWxhciBUZXh0dXJlIChpbWFnZSwgdmlkZW8sIGNhbnZhcylcclxuXHJcblx0XHRcdFx0Ly8gdXNlIG1hbnVhbGx5IGNyZWF0ZWQgbWlwbWFwcyBpZiBhdmFpbGFibGVcclxuXHRcdFx0XHQvLyBpZiB0aGVyZSBhcmUgbm8gbWFudWFsIG1pcG1hcHNcclxuXHRcdFx0XHQvLyBzZXQgMCBsZXZlbCBtaXBtYXAgYW5kIHRoZW4gdXNlIEdMIHRvIGdlbmVyYXRlIG90aGVyIG1pcG1hcCBsZXZlbHNcclxuXHJcblx0XHRcdFx0aWYgKCBtaXBtYXBzLmxlbmd0aCA+IDAgJiYgc3VwcG9ydHNNaXBzICkge1xyXG5cclxuXHRcdFx0XHRcdGlmICggdXNlVGV4U3RvcmFnZSAmJiBhbGxvY2F0ZU1lbW9yeSApIHtcclxuXHJcblx0XHRcdFx0XHRcdHN0YXRlLnRleFN0b3JhZ2UyRCggX2dsLlRFWFRVUkVfMkQsIGxldmVscywgZ2xJbnRlcm5hbEZvcm1hdCwgbWlwbWFwc1sgMCBdLndpZHRoLCBtaXBtYXBzWyAwIF0uaGVpZ2h0ICk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSBtaXBtYXBzLmxlbmd0aDsgaSA8IGlsOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRcdFx0bWlwbWFwID0gbWlwbWFwc1sgaSBdO1xyXG5cclxuXHRcdFx0XHRcdFx0aWYgKCB1c2VUZXhTdG9yYWdlICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRpZiAoIGRhdGFSZWFkeSApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHRzdGF0ZS50ZXhTdWJJbWFnZTJEKCBfZ2wuVEVYVFVSRV8yRCwgaSwgMCwgMCwgZ2xGb3JtYXQsIGdsVHlwZSwgbWlwbWFwICk7XHJcblxyXG5cdFx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdHN0YXRlLnRleEltYWdlMkQoIF9nbC5URVhUVVJFXzJELCBpLCBnbEludGVybmFsRm9ybWF0LCBnbEZvcm1hdCwgZ2xUeXBlLCBtaXBtYXAgKTtcclxuXHJcblx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0dGV4dHVyZS5nZW5lcmF0ZU1pcG1hcHMgPSBmYWxzZTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRpZiAoIHVzZVRleFN0b3JhZ2UgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRpZiAoIGFsbG9jYXRlTWVtb3J5ICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRzdGF0ZS50ZXhTdG9yYWdlMkQoIF9nbC5URVhUVVJFXzJELCBsZXZlbHMsIGdsSW50ZXJuYWxGb3JtYXQsIGltYWdlLndpZHRoLCBpbWFnZS5oZWlnaHQgKTtcclxuXHJcblx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRcdGlmICggZGF0YVJlYWR5ICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRzdGF0ZS50ZXhTdWJJbWFnZTJEKCBfZ2wuVEVYVFVSRV8yRCwgMCwgMCwgMCwgZ2xGb3JtYXQsIGdsVHlwZSwgaW1hZ2UgKTtcclxuXHJcblx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdFx0c3RhdGUudGV4SW1hZ2UyRCggX2dsLlRFWFRVUkVfMkQsIDAsIGdsSW50ZXJuYWxGb3JtYXQsIGdsRm9ybWF0LCBnbFR5cGUsIGltYWdlICk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRpZiAoIHRleHR1cmVOZWVkc0dlbmVyYXRlTWlwbWFwcyggdGV4dHVyZSwgc3VwcG9ydHNNaXBzICkgKSB7XHJcblxyXG5cdFx0XHRcdGdlbmVyYXRlTWlwbWFwKCB0ZXh0dXJlVHlwZSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0c291cmNlUHJvcGVydGllcy5fX3ZlcnNpb24gPSBzb3VyY2UudmVyc2lvbjtcclxuXHJcblx0XHRcdGlmICggdGV4dHVyZS5vblVwZGF0ZSApIHRleHR1cmUub25VcGRhdGUoIHRleHR1cmUgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGV4dHVyZVByb3BlcnRpZXMuX192ZXJzaW9uID0gdGV4dHVyZS52ZXJzaW9uO1xyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHVwbG9hZEN1YmVUZXh0dXJlKCB0ZXh0dXJlUHJvcGVydGllcywgdGV4dHVyZSwgc2xvdCApIHtcclxuXHJcblx0XHRpZiAoIHRleHR1cmUuaW1hZ2UubGVuZ3RoICE9PSA2ICkgcmV0dXJuO1xyXG5cclxuXHRcdGNvbnN0IGZvcmNlVXBsb2FkID0gaW5pdFRleHR1cmUoIHRleHR1cmVQcm9wZXJ0aWVzLCB0ZXh0dXJlICk7XHJcblx0XHRjb25zdCBzb3VyY2UgPSB0ZXh0dXJlLnNvdXJjZTtcclxuXHJcblx0XHRzdGF0ZS5iaW5kVGV4dHVyZSggX2dsLlRFWFRVUkVfQ1VCRV9NQVAsIHRleHR1cmVQcm9wZXJ0aWVzLl9fd2ViZ2xUZXh0dXJlLCBfZ2wuVEVYVFVSRTAgKyBzbG90ICk7XHJcblxyXG5cdFx0Y29uc3Qgc291cmNlUHJvcGVydGllcyA9IHByb3BlcnRpZXMuZ2V0KCBzb3VyY2UgKTtcclxuXHJcblx0XHRpZiAoIHNvdXJjZS52ZXJzaW9uICE9PSBzb3VyY2VQcm9wZXJ0aWVzLl9fdmVyc2lvbiB8fCBmb3JjZVVwbG9hZCA9PT0gdHJ1ZSApIHtcclxuXHJcblx0XHRcdHN0YXRlLmFjdGl2ZVRleHR1cmUoIF9nbC5URVhUVVJFMCArIHNsb3QgKTtcclxuXHJcblx0XHRcdGNvbnN0IHdvcmtpbmdQcmltYXJpZXMgPSBDb2xvck1hbmFnZW1lbnQuZ2V0UHJpbWFyaWVzKCBDb2xvck1hbmFnZW1lbnQud29ya2luZ0NvbG9yU3BhY2UgKTtcclxuXHRcdFx0Y29uc3QgdGV4dHVyZVByaW1hcmllcyA9IHRleHR1cmUuY29sb3JTcGFjZSA9PT0gTm9Db2xvclNwYWNlID8gbnVsbCA6IENvbG9yTWFuYWdlbWVudC5nZXRQcmltYXJpZXMoIHRleHR1cmUuY29sb3JTcGFjZSApO1xyXG5cdFx0XHRjb25zdCB1bnBhY2tDb252ZXJzaW9uID0gdGV4dHVyZS5jb2xvclNwYWNlID09PSBOb0NvbG9yU3BhY2UgfHwgd29ya2luZ1ByaW1hcmllcyA9PT0gdGV4dHVyZVByaW1hcmllcyA/IF9nbC5OT05FIDogX2dsLkJST1dTRVJfREVGQVVMVF9XRUJHTDtcclxuXHJcblx0XHRcdF9nbC5waXhlbFN0b3JlaSggX2dsLlVOUEFDS19GTElQX1lfV0VCR0wsIHRleHR1cmUuZmxpcFkgKTtcclxuXHRcdFx0X2dsLnBpeGVsU3RvcmVpKCBfZ2wuVU5QQUNLX1BSRU1VTFRJUExZX0FMUEhBX1dFQkdMLCB0ZXh0dXJlLnByZW11bHRpcGx5QWxwaGEgKTtcclxuXHRcdFx0X2dsLnBpeGVsU3RvcmVpKCBfZ2wuVU5QQUNLX0FMSUdOTUVOVCwgdGV4dHVyZS51bnBhY2tBbGlnbm1lbnQgKTtcclxuXHRcdFx0X2dsLnBpeGVsU3RvcmVpKCBfZ2wuVU5QQUNLX0NPTE9SU1BBQ0VfQ09OVkVSU0lPTl9XRUJHTCwgdW5wYWNrQ29udmVyc2lvbiApO1xyXG5cclxuXHRcdFx0Y29uc3QgaXNDb21wcmVzc2VkID0gKCB0ZXh0dXJlLmlzQ29tcHJlc3NlZFRleHR1cmUgfHwgdGV4dHVyZS5pbWFnZVsgMCBdLmlzQ29tcHJlc3NlZFRleHR1cmUgKTtcclxuXHRcdFx0Y29uc3QgaXNEYXRhVGV4dHVyZSA9ICggdGV4dHVyZS5pbWFnZVsgMCBdICYmIHRleHR1cmUuaW1hZ2VbIDAgXS5pc0RhdGFUZXh0dXJlICk7XHJcblxyXG5cdFx0XHRjb25zdCBjdWJlSW1hZ2UgPSBbXTtcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IDY7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdGlmICggISBpc0NvbXByZXNzZWQgJiYgISBpc0RhdGFUZXh0dXJlICkge1xyXG5cclxuXHRcdFx0XHRcdGN1YmVJbWFnZVsgaSBdID0gcmVzaXplSW1hZ2UoIHRleHR1cmUuaW1hZ2VbIGkgXSwgZmFsc2UsIHRydWUsIGNhcGFiaWxpdGllcy5tYXhDdWJlbWFwU2l6ZSApO1xyXG5cclxuXHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdGN1YmVJbWFnZVsgaSBdID0gaXNEYXRhVGV4dHVyZSA/IHRleHR1cmUuaW1hZ2VbIGkgXS5pbWFnZSA6IHRleHR1cmUuaW1hZ2VbIGkgXTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRjdWJlSW1hZ2VbIGkgXSA9IHZlcmlmeUNvbG9yU3BhY2UoIHRleHR1cmUsIGN1YmVJbWFnZVsgaSBdICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRjb25zdCBpbWFnZSA9IGN1YmVJbWFnZVsgMCBdLFxyXG5cdFx0XHRcdHN1cHBvcnRzTWlwcyA9IGlzUG93ZXJPZlR3byggaW1hZ2UgKSB8fCBpc1dlYkdMMixcclxuXHRcdFx0XHRnbEZvcm1hdCA9IHV0aWxzLmNvbnZlcnQoIHRleHR1cmUuZm9ybWF0LCB0ZXh0dXJlLmNvbG9yU3BhY2UgKSxcclxuXHRcdFx0XHRnbFR5cGUgPSB1dGlscy5jb252ZXJ0KCB0ZXh0dXJlLnR5cGUgKSxcclxuXHRcdFx0XHRnbEludGVybmFsRm9ybWF0ID0gZ2V0SW50ZXJuYWxGb3JtYXQoIHRleHR1cmUuaW50ZXJuYWxGb3JtYXQsIGdsRm9ybWF0LCBnbFR5cGUsIHRleHR1cmUuY29sb3JTcGFjZSApO1xyXG5cclxuXHRcdFx0Y29uc3QgdXNlVGV4U3RvcmFnZSA9ICggaXNXZWJHTDIgJiYgdGV4dHVyZS5pc1ZpZGVvVGV4dHVyZSAhPT0gdHJ1ZSApO1xyXG5cdFx0XHRjb25zdCBhbGxvY2F0ZU1lbW9yeSA9ICggc291cmNlUHJvcGVydGllcy5fX3ZlcnNpb24gPT09IHVuZGVmaW5lZCApIHx8ICggZm9yY2VVcGxvYWQgPT09IHRydWUgKTtcclxuXHRcdFx0Y29uc3QgZGF0YVJlYWR5ID0gc291cmNlLmRhdGFSZWFkeTtcclxuXHRcdFx0bGV0IGxldmVscyA9IGdldE1pcExldmVscyggdGV4dHVyZSwgaW1hZ2UsIHN1cHBvcnRzTWlwcyApO1xyXG5cclxuXHRcdFx0c2V0VGV4dHVyZVBhcmFtZXRlcnMoIF9nbC5URVhUVVJFX0NVQkVfTUFQLCB0ZXh0dXJlLCBzdXBwb3J0c01pcHMgKTtcclxuXHJcblx0XHRcdGxldCBtaXBtYXBzO1xyXG5cclxuXHRcdFx0aWYgKCBpc0NvbXByZXNzZWQgKSB7XHJcblxyXG5cdFx0XHRcdGlmICggdXNlVGV4U3RvcmFnZSAmJiBhbGxvY2F0ZU1lbW9yeSApIHtcclxuXHJcblx0XHRcdFx0XHRzdGF0ZS50ZXhTdG9yYWdlMkQoIF9nbC5URVhUVVJFX0NVQkVfTUFQLCBsZXZlbHMsIGdsSW50ZXJuYWxGb3JtYXQsIGltYWdlLndpZHRoLCBpbWFnZS5oZWlnaHQgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCA2OyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRcdG1pcG1hcHMgPSBjdWJlSW1hZ2VbIGkgXS5taXBtYXBzO1xyXG5cclxuXHRcdFx0XHRcdGZvciAoIGxldCBqID0gMDsgaiA8IG1pcG1hcHMubGVuZ3RoOyBqICsrICkge1xyXG5cclxuXHRcdFx0XHRcdFx0Y29uc3QgbWlwbWFwID0gbWlwbWFwc1sgaiBdO1xyXG5cclxuXHRcdFx0XHRcdFx0aWYgKCB0ZXh0dXJlLmZvcm1hdCAhPT0gUkdCQUZvcm1hdCApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0aWYgKCBnbEZvcm1hdCAhPT0gbnVsbCApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHRpZiAoIHVzZVRleFN0b3JhZ2UgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0XHRpZiAoIGRhdGFSZWFkeSApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0c3RhdGUuY29tcHJlc3NlZFRleFN1YkltYWdlMkQoIF9nbC5URVhUVVJFX0NVQkVfTUFQX1BPU0lUSVZFX1ggKyBpLCBqLCAwLCAwLCBtaXBtYXAud2lkdGgsIG1pcG1hcC5oZWlnaHQsIGdsRm9ybWF0LCBtaXBtYXAuZGF0YSApO1xyXG5cclxuXHRcdFx0XHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0XHRzdGF0ZS5jb21wcmVzc2VkVGV4SW1hZ2UyRCggX2dsLlRFWFRVUkVfQ1VCRV9NQVBfUE9TSVRJVkVfWCArIGksIGosIGdsSW50ZXJuYWxGb3JtYXQsIG1pcG1hcC53aWR0aCwgbWlwbWFwLmhlaWdodCwgMCwgbWlwbWFwLmRhdGEgKTtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuV2ViR0xSZW5kZXJlcjogQXR0ZW1wdCB0byBsb2FkIHVuc3VwcG9ydGVkIGNvbXByZXNzZWQgdGV4dHVyZSBmb3JtYXQgaW4gLnNldFRleHR1cmVDdWJlKCknICk7XHJcblxyXG5cdFx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdGlmICggdXNlVGV4U3RvcmFnZSApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHRpZiAoIGRhdGFSZWFkeSApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHRcdHN0YXRlLnRleFN1YkltYWdlMkQoIF9nbC5URVhUVVJFX0NVQkVfTUFQX1BPU0lUSVZFX1ggKyBpLCBqLCAwLCAwLCBtaXBtYXAud2lkdGgsIG1pcG1hcC5oZWlnaHQsIGdsRm9ybWF0LCBnbFR5cGUsIG1pcG1hcC5kYXRhICk7XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRcdHN0YXRlLnRleEltYWdlMkQoIF9nbC5URVhUVVJFX0NVQkVfTUFQX1BPU0lUSVZFX1ggKyBpLCBqLCBnbEludGVybmFsRm9ybWF0LCBtaXBtYXAud2lkdGgsIG1pcG1hcC5oZWlnaHQsIDAsIGdsRm9ybWF0LCBnbFR5cGUsIG1pcG1hcC5kYXRhICk7XHJcblxyXG5cdFx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdG1pcG1hcHMgPSB0ZXh0dXJlLm1pcG1hcHM7XHJcblxyXG5cdFx0XHRcdGlmICggdXNlVGV4U3RvcmFnZSAmJiBhbGxvY2F0ZU1lbW9yeSApIHtcclxuXHJcblx0XHRcdFx0XHQvLyBUT0RPOiBVbmlmb3JtbHkgaGFuZGxlIG1pcG1hcCBkZWZpbml0aW9uc1xyXG5cdFx0XHRcdFx0Ly8gTm9ybWFsIHRleHR1cmVzIGFuZCBjb21wcmVzc2VkIGN1YmUgdGV4dHVyZXMgZGVmaW5lIGJhc2UgbGV2ZWwgKyBtaXBzIHdpdGggdGhlaXIgbWlwbWFwIGFycmF5XHJcblx0XHRcdFx0XHQvLyBVbmNvbXByZXNzZWQgY3ViZSB0ZXh0dXJlcyB1c2UgdGhlaXIgbWlwbWFwIGFycmF5IG9ubHkgZm9yIG1pcHMgKG5vIGJhc2UgbGV2ZWwpXHJcblxyXG5cdFx0XHRcdFx0aWYgKCBtaXBtYXBzLmxlbmd0aCA+IDAgKSBsZXZlbHMgKys7XHJcblxyXG5cdFx0XHRcdFx0c3RhdGUudGV4U3RvcmFnZTJEKCBfZ2wuVEVYVFVSRV9DVUJFX01BUCwgbGV2ZWxzLCBnbEludGVybmFsRm9ybWF0LCBjdWJlSW1hZ2VbIDAgXS53aWR0aCwgY3ViZUltYWdlWyAwIF0uaGVpZ2h0ICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgNjsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0XHRpZiAoIGlzRGF0YVRleHR1cmUgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRpZiAoIHVzZVRleFN0b3JhZ2UgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdGlmICggZGF0YVJlYWR5ICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRcdHN0YXRlLnRleFN1YkltYWdlMkQoIF9nbC5URVhUVVJFX0NVQkVfTUFQX1BPU0lUSVZFX1ggKyBpLCAwLCAwLCAwLCBjdWJlSW1hZ2VbIGkgXS53aWR0aCwgY3ViZUltYWdlWyBpIF0uaGVpZ2h0LCBnbEZvcm1hdCwgZ2xUeXBlLCBjdWJlSW1hZ2VbIGkgXS5kYXRhICk7XHJcblxyXG5cdFx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdHN0YXRlLnRleEltYWdlMkQoIF9nbC5URVhUVVJFX0NVQkVfTUFQX1BPU0lUSVZFX1ggKyBpLCAwLCBnbEludGVybmFsRm9ybWF0LCBjdWJlSW1hZ2VbIGkgXS53aWR0aCwgY3ViZUltYWdlWyBpIF0uaGVpZ2h0LCAwLCBnbEZvcm1hdCwgZ2xUeXBlLCBjdWJlSW1hZ2VbIGkgXS5kYXRhICk7XHJcblxyXG5cdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0XHRmb3IgKCBsZXQgaiA9IDA7IGogPCBtaXBtYXBzLmxlbmd0aDsgaiArKyApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0Y29uc3QgbWlwbWFwID0gbWlwbWFwc1sgaiBdO1xyXG5cdFx0XHRcdFx0XHRcdGNvbnN0IG1pcG1hcEltYWdlID0gbWlwbWFwLmltYWdlWyBpIF0uaW1hZ2U7XHJcblxyXG5cdFx0XHRcdFx0XHRcdGlmICggdXNlVGV4U3RvcmFnZSApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHRpZiAoIGRhdGFSZWFkeSApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHRcdHN0YXRlLnRleFN1YkltYWdlMkQoIF9nbC5URVhUVVJFX0NVQkVfTUFQX1BPU0lUSVZFX1ggKyBpLCBqICsgMSwgMCwgMCwgbWlwbWFwSW1hZ2Uud2lkdGgsIG1pcG1hcEltYWdlLmhlaWdodCwgZ2xGb3JtYXQsIGdsVHlwZSwgbWlwbWFwSW1hZ2UuZGF0YSApO1xyXG5cclxuXHRcdFx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHRzdGF0ZS50ZXhJbWFnZTJEKCBfZ2wuVEVYVFVSRV9DVUJFX01BUF9QT1NJVElWRV9YICsgaSwgaiArIDEsIGdsSW50ZXJuYWxGb3JtYXQsIG1pcG1hcEltYWdlLndpZHRoLCBtaXBtYXBJbWFnZS5oZWlnaHQsIDAsIGdsRm9ybWF0LCBnbFR5cGUsIG1pcG1hcEltYWdlLmRhdGEgKTtcclxuXHJcblx0XHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHRpZiAoIHVzZVRleFN0b3JhZ2UgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdGlmICggZGF0YVJlYWR5ICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRcdHN0YXRlLnRleFN1YkltYWdlMkQoIF9nbC5URVhUVVJFX0NVQkVfTUFQX1BPU0lUSVZFX1ggKyBpLCAwLCAwLCAwLCBnbEZvcm1hdCwgZ2xUeXBlLCBjdWJlSW1hZ2VbIGkgXSApO1xyXG5cclxuXHRcdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRzdGF0ZS50ZXhJbWFnZTJEKCBfZ2wuVEVYVFVSRV9DVUJFX01BUF9QT1NJVElWRV9YICsgaSwgMCwgZ2xJbnRlcm5hbEZvcm1hdCwgZ2xGb3JtYXQsIGdsVHlwZSwgY3ViZUltYWdlWyBpIF0gKTtcclxuXHJcblx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRcdGZvciAoIGxldCBqID0gMDsgaiA8IG1pcG1hcHMubGVuZ3RoOyBqICsrICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRjb25zdCBtaXBtYXAgPSBtaXBtYXBzWyBqIF07XHJcblxyXG5cdFx0XHRcdFx0XHRcdGlmICggdXNlVGV4U3RvcmFnZSApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHRpZiAoIGRhdGFSZWFkeSApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHRcdHN0YXRlLnRleFN1YkltYWdlMkQoIF9nbC5URVhUVVJFX0NVQkVfTUFQX1BPU0lUSVZFX1ggKyBpLCBqICsgMSwgMCwgMCwgZ2xGb3JtYXQsIGdsVHlwZSwgbWlwbWFwLmltYWdlWyBpIF0gKTtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0c3RhdGUudGV4SW1hZ2UyRCggX2dsLlRFWFRVUkVfQ1VCRV9NQVBfUE9TSVRJVkVfWCArIGksIGogKyAxLCBnbEludGVybmFsRm9ybWF0LCBnbEZvcm1hdCwgZ2xUeXBlLCBtaXBtYXAuaW1hZ2VbIGkgXSApO1xyXG5cclxuXHRcdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRpZiAoIHRleHR1cmVOZWVkc0dlbmVyYXRlTWlwbWFwcyggdGV4dHVyZSwgc3VwcG9ydHNNaXBzICkgKSB7XHJcblxyXG5cdFx0XHRcdC8vIFdlIGFzc3VtZSBpbWFnZXMgZm9yIGN1YmUgbWFwIGhhdmUgdGhlIHNhbWUgc2l6ZS5cclxuXHRcdFx0XHRnZW5lcmF0ZU1pcG1hcCggX2dsLlRFWFRVUkVfQ1VCRV9NQVAgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHNvdXJjZVByb3BlcnRpZXMuX192ZXJzaW9uID0gc291cmNlLnZlcnNpb247XHJcblxyXG5cdFx0XHRpZiAoIHRleHR1cmUub25VcGRhdGUgKSB0ZXh0dXJlLm9uVXBkYXRlKCB0ZXh0dXJlICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRleHR1cmVQcm9wZXJ0aWVzLl9fdmVyc2lvbiA9IHRleHR1cmUudmVyc2lvbjtcclxuXHJcblx0fVxyXG5cclxuXHQvLyBSZW5kZXIgdGFyZ2V0c1xyXG5cclxuXHQvLyBTZXR1cCBzdG9yYWdlIGZvciB0YXJnZXQgdGV4dHVyZSBhbmQgYmluZCBpdCB0byBjb3JyZWN0IGZyYW1lYnVmZmVyXHJcblx0ZnVuY3Rpb24gc2V0dXBGcmFtZUJ1ZmZlclRleHR1cmUoIGZyYW1lYnVmZmVyLCByZW5kZXJUYXJnZXQsIHRleHR1cmUsIGF0dGFjaG1lbnQsIHRleHR1cmVUYXJnZXQsIGxldmVsICkge1xyXG5cclxuXHRcdGNvbnN0IGdsRm9ybWF0ID0gdXRpbHMuY29udmVydCggdGV4dHVyZS5mb3JtYXQsIHRleHR1cmUuY29sb3JTcGFjZSApO1xyXG5cdFx0Y29uc3QgZ2xUeXBlID0gdXRpbHMuY29udmVydCggdGV4dHVyZS50eXBlICk7XHJcblx0XHRjb25zdCBnbEludGVybmFsRm9ybWF0ID0gZ2V0SW50ZXJuYWxGb3JtYXQoIHRleHR1cmUuaW50ZXJuYWxGb3JtYXQsIGdsRm9ybWF0LCBnbFR5cGUsIHRleHR1cmUuY29sb3JTcGFjZSApO1xyXG5cdFx0Y29uc3QgcmVuZGVyVGFyZ2V0UHJvcGVydGllcyA9IHByb3BlcnRpZXMuZ2V0KCByZW5kZXJUYXJnZXQgKTtcclxuXHJcblx0XHRpZiAoICEgcmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX2hhc0V4dGVybmFsVGV4dHVyZXMgKSB7XHJcblxyXG5cdFx0XHRjb25zdCB3aWR0aCA9IE1hdGgubWF4KCAxLCByZW5kZXJUYXJnZXQud2lkdGggPj4gbGV2ZWwgKTtcclxuXHRcdFx0Y29uc3QgaGVpZ2h0ID0gTWF0aC5tYXgoIDEsIHJlbmRlclRhcmdldC5oZWlnaHQgPj4gbGV2ZWwgKTtcclxuXHJcblx0XHRcdGlmICggdGV4dHVyZVRhcmdldCA9PT0gX2dsLlRFWFRVUkVfM0QgfHwgdGV4dHVyZVRhcmdldCA9PT0gX2dsLlRFWFRVUkVfMkRfQVJSQVkgKSB7XHJcblxyXG5cdFx0XHRcdHN0YXRlLnRleEltYWdlM0QoIHRleHR1cmVUYXJnZXQsIGxldmVsLCBnbEludGVybmFsRm9ybWF0LCB3aWR0aCwgaGVpZ2h0LCByZW5kZXJUYXJnZXQuZGVwdGgsIDAsIGdsRm9ybWF0LCBnbFR5cGUsIG51bGwgKTtcclxuXHJcblx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdHN0YXRlLnRleEltYWdlMkQoIHRleHR1cmVUYXJnZXQsIGxldmVsLCBnbEludGVybmFsRm9ybWF0LCB3aWR0aCwgaGVpZ2h0LCAwLCBnbEZvcm1hdCwgZ2xUeXBlLCBudWxsICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHN0YXRlLmJpbmRGcmFtZWJ1ZmZlciggX2dsLkZSQU1FQlVGRkVSLCBmcmFtZWJ1ZmZlciApO1xyXG5cclxuXHRcdGlmICggdXNlTXVsdGlzYW1wbGVkUlRUKCByZW5kZXJUYXJnZXQgKSApIHtcclxuXHJcblx0XHRcdG11bHRpc2FtcGxlZFJUVEV4dC5mcmFtZWJ1ZmZlclRleHR1cmUyRE11bHRpc2FtcGxlRVhUKCBfZ2wuRlJBTUVCVUZGRVIsIGF0dGFjaG1lbnQsIHRleHR1cmVUYXJnZXQsIHByb3BlcnRpZXMuZ2V0KCB0ZXh0dXJlICkuX193ZWJnbFRleHR1cmUsIDAsIGdldFJlbmRlclRhcmdldFNhbXBsZXMoIHJlbmRlclRhcmdldCApICk7XHJcblxyXG5cdFx0fSBlbHNlIGlmICggdGV4dHVyZVRhcmdldCA9PT0gX2dsLlRFWFRVUkVfMkQgfHwgKCB0ZXh0dXJlVGFyZ2V0ID49IF9nbC5URVhUVVJFX0NVQkVfTUFQX1BPU0lUSVZFX1ggJiYgdGV4dHVyZVRhcmdldCA8PSBfZ2wuVEVYVFVSRV9DVUJFX01BUF9ORUdBVElWRV9aICkgKSB7IC8vIHNlZSAjMjQ3NTNcclxuXHJcblx0XHRcdF9nbC5mcmFtZWJ1ZmZlclRleHR1cmUyRCggX2dsLkZSQU1FQlVGRkVSLCBhdHRhY2htZW50LCB0ZXh0dXJlVGFyZ2V0LCBwcm9wZXJ0aWVzLmdldCggdGV4dHVyZSApLl9fd2ViZ2xUZXh0dXJlLCBsZXZlbCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRzdGF0ZS5iaW5kRnJhbWVidWZmZXIoIF9nbC5GUkFNRUJVRkZFUiwgbnVsbCApO1xyXG5cclxuXHR9XHJcblxyXG5cclxuXHQvLyBTZXR1cCBzdG9yYWdlIGZvciBpbnRlcm5hbCBkZXB0aC9zdGVuY2lsIGJ1ZmZlcnMgYW5kIGJpbmQgdG8gY29ycmVjdCBmcmFtZWJ1ZmZlclxyXG5cdGZ1bmN0aW9uIHNldHVwUmVuZGVyQnVmZmVyU3RvcmFnZSggcmVuZGVyYnVmZmVyLCByZW5kZXJUYXJnZXQsIGlzTXVsdGlzYW1wbGUgKSB7XHJcblxyXG5cdFx0X2dsLmJpbmRSZW5kZXJidWZmZXIoIF9nbC5SRU5ERVJCVUZGRVIsIHJlbmRlcmJ1ZmZlciApO1xyXG5cclxuXHRcdGlmICggcmVuZGVyVGFyZ2V0LmRlcHRoQnVmZmVyICYmICEgcmVuZGVyVGFyZ2V0LnN0ZW5jaWxCdWZmZXIgKSB7XHJcblxyXG5cdFx0XHRsZXQgZ2xJbnRlcm5hbEZvcm1hdCA9ICggaXNXZWJHTDIgPT09IHRydWUgKSA/IF9nbC5ERVBUSF9DT01QT05FTlQyNCA6IF9nbC5ERVBUSF9DT01QT05FTlQxNjtcclxuXHJcblx0XHRcdGlmICggaXNNdWx0aXNhbXBsZSB8fCB1c2VNdWx0aXNhbXBsZWRSVFQoIHJlbmRlclRhcmdldCApICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBkZXB0aFRleHR1cmUgPSByZW5kZXJUYXJnZXQuZGVwdGhUZXh0dXJlO1xyXG5cclxuXHRcdFx0XHRpZiAoIGRlcHRoVGV4dHVyZSAmJiBkZXB0aFRleHR1cmUuaXNEZXB0aFRleHR1cmUgKSB7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCBkZXB0aFRleHR1cmUudHlwZSA9PT0gRmxvYXRUeXBlICkge1xyXG5cclxuXHRcdFx0XHRcdFx0Z2xJbnRlcm5hbEZvcm1hdCA9IF9nbC5ERVBUSF9DT01QT05FTlQzMkY7XHJcblxyXG5cdFx0XHRcdFx0fSBlbHNlIGlmICggZGVwdGhUZXh0dXJlLnR5cGUgPT09IFVuc2lnbmVkSW50VHlwZSApIHtcclxuXHJcblx0XHRcdFx0XHRcdGdsSW50ZXJuYWxGb3JtYXQgPSBfZ2wuREVQVEhfQ09NUE9ORU5UMjQ7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdGNvbnN0IHNhbXBsZXMgPSBnZXRSZW5kZXJUYXJnZXRTYW1wbGVzKCByZW5kZXJUYXJnZXQgKTtcclxuXHJcblx0XHRcdFx0aWYgKCB1c2VNdWx0aXNhbXBsZWRSVFQoIHJlbmRlclRhcmdldCApICkge1xyXG5cclxuXHRcdFx0XHRcdG11bHRpc2FtcGxlZFJUVEV4dC5yZW5kZXJidWZmZXJTdG9yYWdlTXVsdGlzYW1wbGVFWFQoIF9nbC5SRU5ERVJCVUZGRVIsIHNhbXBsZXMsIGdsSW50ZXJuYWxGb3JtYXQsIHJlbmRlclRhcmdldC53aWR0aCwgcmVuZGVyVGFyZ2V0LmhlaWdodCApO1xyXG5cclxuXHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdF9nbC5yZW5kZXJidWZmZXJTdG9yYWdlTXVsdGlzYW1wbGUoIF9nbC5SRU5ERVJCVUZGRVIsIHNhbXBsZXMsIGdsSW50ZXJuYWxGb3JtYXQsIHJlbmRlclRhcmdldC53aWR0aCwgcmVuZGVyVGFyZ2V0LmhlaWdodCApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRfZ2wucmVuZGVyYnVmZmVyU3RvcmFnZSggX2dsLlJFTkRFUkJVRkZFUiwgZ2xJbnRlcm5hbEZvcm1hdCwgcmVuZGVyVGFyZ2V0LndpZHRoLCByZW5kZXJUYXJnZXQuaGVpZ2h0ICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRfZ2wuZnJhbWVidWZmZXJSZW5kZXJidWZmZXIoIF9nbC5GUkFNRUJVRkZFUiwgX2dsLkRFUFRIX0FUVEFDSE1FTlQsIF9nbC5SRU5ERVJCVUZGRVIsIHJlbmRlcmJ1ZmZlciApO1xyXG5cclxuXHRcdH0gZWxzZSBpZiAoIHJlbmRlclRhcmdldC5kZXB0aEJ1ZmZlciAmJiByZW5kZXJUYXJnZXQuc3RlbmNpbEJ1ZmZlciApIHtcclxuXHJcblx0XHRcdGNvbnN0IHNhbXBsZXMgPSBnZXRSZW5kZXJUYXJnZXRTYW1wbGVzKCByZW5kZXJUYXJnZXQgKTtcclxuXHJcblx0XHRcdGlmICggaXNNdWx0aXNhbXBsZSAmJiB1c2VNdWx0aXNhbXBsZWRSVFQoIHJlbmRlclRhcmdldCApID09PSBmYWxzZSApIHtcclxuXHJcblx0XHRcdFx0X2dsLnJlbmRlcmJ1ZmZlclN0b3JhZ2VNdWx0aXNhbXBsZSggX2dsLlJFTkRFUkJVRkZFUiwgc2FtcGxlcywgX2dsLkRFUFRIMjRfU1RFTkNJTDgsIHJlbmRlclRhcmdldC53aWR0aCwgcmVuZGVyVGFyZ2V0LmhlaWdodCApO1xyXG5cclxuXHRcdFx0fSBlbHNlIGlmICggdXNlTXVsdGlzYW1wbGVkUlRUKCByZW5kZXJUYXJnZXQgKSApIHtcclxuXHJcblx0XHRcdFx0bXVsdGlzYW1wbGVkUlRURXh0LnJlbmRlcmJ1ZmZlclN0b3JhZ2VNdWx0aXNhbXBsZUVYVCggX2dsLlJFTkRFUkJVRkZFUiwgc2FtcGxlcywgX2dsLkRFUFRIMjRfU1RFTkNJTDgsIHJlbmRlclRhcmdldC53aWR0aCwgcmVuZGVyVGFyZ2V0LmhlaWdodCApO1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0X2dsLnJlbmRlcmJ1ZmZlclN0b3JhZ2UoIF9nbC5SRU5ERVJCVUZGRVIsIF9nbC5ERVBUSF9TVEVOQ0lMLCByZW5kZXJUYXJnZXQud2lkdGgsIHJlbmRlclRhcmdldC5oZWlnaHQgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblxyXG5cdFx0XHRfZ2wuZnJhbWVidWZmZXJSZW5kZXJidWZmZXIoIF9nbC5GUkFNRUJVRkZFUiwgX2dsLkRFUFRIX1NURU5DSUxfQVRUQUNITUVOVCwgX2dsLlJFTkRFUkJVRkZFUiwgcmVuZGVyYnVmZmVyICk7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdGNvbnN0IHRleHR1cmVzID0gcmVuZGVyVGFyZ2V0LmlzV2ViR0xNdWx0aXBsZVJlbmRlclRhcmdldHMgPT09IHRydWUgPyByZW5kZXJUYXJnZXQudGV4dHVyZSA6IFsgcmVuZGVyVGFyZ2V0LnRleHR1cmUgXTtcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHRleHR1cmVzLmxlbmd0aDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgdGV4dHVyZSA9IHRleHR1cmVzWyBpIF07XHJcblxyXG5cdFx0XHRcdGNvbnN0IGdsRm9ybWF0ID0gdXRpbHMuY29udmVydCggdGV4dHVyZS5mb3JtYXQsIHRleHR1cmUuY29sb3JTcGFjZSApO1xyXG5cdFx0XHRcdGNvbnN0IGdsVHlwZSA9IHV0aWxzLmNvbnZlcnQoIHRleHR1cmUudHlwZSApO1xyXG5cdFx0XHRcdGNvbnN0IGdsSW50ZXJuYWxGb3JtYXQgPSBnZXRJbnRlcm5hbEZvcm1hdCggdGV4dHVyZS5pbnRlcm5hbEZvcm1hdCwgZ2xGb3JtYXQsIGdsVHlwZSwgdGV4dHVyZS5jb2xvclNwYWNlICk7XHJcblx0XHRcdFx0Y29uc3Qgc2FtcGxlcyA9IGdldFJlbmRlclRhcmdldFNhbXBsZXMoIHJlbmRlclRhcmdldCApO1xyXG5cclxuXHRcdFx0XHRpZiAoIGlzTXVsdGlzYW1wbGUgJiYgdXNlTXVsdGlzYW1wbGVkUlRUKCByZW5kZXJUYXJnZXQgKSA9PT0gZmFsc2UgKSB7XHJcblxyXG5cdFx0XHRcdFx0X2dsLnJlbmRlcmJ1ZmZlclN0b3JhZ2VNdWx0aXNhbXBsZSggX2dsLlJFTkRFUkJVRkZFUiwgc2FtcGxlcywgZ2xJbnRlcm5hbEZvcm1hdCwgcmVuZGVyVGFyZ2V0LndpZHRoLCByZW5kZXJUYXJnZXQuaGVpZ2h0ICk7XHJcblxyXG5cdFx0XHRcdH0gZWxzZSBpZiAoIHVzZU11bHRpc2FtcGxlZFJUVCggcmVuZGVyVGFyZ2V0ICkgKSB7XHJcblxyXG5cdFx0XHRcdFx0bXVsdGlzYW1wbGVkUlRURXh0LnJlbmRlcmJ1ZmZlclN0b3JhZ2VNdWx0aXNhbXBsZUVYVCggX2dsLlJFTkRFUkJVRkZFUiwgc2FtcGxlcywgZ2xJbnRlcm5hbEZvcm1hdCwgcmVuZGVyVGFyZ2V0LndpZHRoLCByZW5kZXJUYXJnZXQuaGVpZ2h0ICk7XHJcblxyXG5cdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0X2dsLnJlbmRlcmJ1ZmZlclN0b3JhZ2UoIF9nbC5SRU5ERVJCVUZGRVIsIGdsSW50ZXJuYWxGb3JtYXQsIHJlbmRlclRhcmdldC53aWR0aCwgcmVuZGVyVGFyZ2V0LmhlaWdodCApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdF9nbC5iaW5kUmVuZGVyYnVmZmVyKCBfZ2wuUkVOREVSQlVGRkVSLCBudWxsICk7XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gU2V0dXAgcmVzb3VyY2VzIGZvciBhIERlcHRoIFRleHR1cmUgZm9yIGEgRkJPIChuZWVkcyBhbiBleHRlbnNpb24pXHJcblx0ZnVuY3Rpb24gc2V0dXBEZXB0aFRleHR1cmUoIGZyYW1lYnVmZmVyLCByZW5kZXJUYXJnZXQgKSB7XHJcblxyXG5cdFx0Y29uc3QgaXNDdWJlID0gKCByZW5kZXJUYXJnZXQgJiYgcmVuZGVyVGFyZ2V0LmlzV2ViR0xDdWJlUmVuZGVyVGFyZ2V0ICk7XHJcblx0XHRpZiAoIGlzQ3ViZSApIHRocm93IG5ldyBFcnJvciggJ0RlcHRoIFRleHR1cmUgd2l0aCBjdWJlIHJlbmRlciB0YXJnZXRzIGlzIG5vdCBzdXBwb3J0ZWQnICk7XHJcblxyXG5cdFx0c3RhdGUuYmluZEZyYW1lYnVmZmVyKCBfZ2wuRlJBTUVCVUZGRVIsIGZyYW1lYnVmZmVyICk7XHJcblxyXG5cdFx0aWYgKCAhICggcmVuZGVyVGFyZ2V0LmRlcHRoVGV4dHVyZSAmJiByZW5kZXJUYXJnZXQuZGVwdGhUZXh0dXJlLmlzRGVwdGhUZXh0dXJlICkgKSB7XHJcblxyXG5cdFx0XHR0aHJvdyBuZXcgRXJyb3IoICdyZW5kZXJUYXJnZXQuZGVwdGhUZXh0dXJlIG11c3QgYmUgYW4gaW5zdGFuY2Ugb2YgVEhSRUUuRGVwdGhUZXh0dXJlJyApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvLyB1cGxvYWQgYW4gZW1wdHkgZGVwdGggdGV4dHVyZSB3aXRoIGZyYW1lYnVmZmVyIHNpemVcclxuXHRcdGlmICggISBwcm9wZXJ0aWVzLmdldCggcmVuZGVyVGFyZ2V0LmRlcHRoVGV4dHVyZSApLl9fd2ViZ2xUZXh0dXJlIHx8XHJcblx0XHRcdFx0cmVuZGVyVGFyZ2V0LmRlcHRoVGV4dHVyZS5pbWFnZS53aWR0aCAhPT0gcmVuZGVyVGFyZ2V0LndpZHRoIHx8XHJcblx0XHRcdFx0cmVuZGVyVGFyZ2V0LmRlcHRoVGV4dHVyZS5pbWFnZS5oZWlnaHQgIT09IHJlbmRlclRhcmdldC5oZWlnaHQgKSB7XHJcblxyXG5cdFx0XHRyZW5kZXJUYXJnZXQuZGVwdGhUZXh0dXJlLmltYWdlLndpZHRoID0gcmVuZGVyVGFyZ2V0LndpZHRoO1xyXG5cdFx0XHRyZW5kZXJUYXJnZXQuZGVwdGhUZXh0dXJlLmltYWdlLmhlaWdodCA9IHJlbmRlclRhcmdldC5oZWlnaHQ7XHJcblx0XHRcdHJlbmRlclRhcmdldC5kZXB0aFRleHR1cmUubmVlZHNVcGRhdGUgPSB0cnVlO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRzZXRUZXh0dXJlMkQoIHJlbmRlclRhcmdldC5kZXB0aFRleHR1cmUsIDAgKTtcclxuXHJcblx0XHRjb25zdCB3ZWJnbERlcHRoVGV4dHVyZSA9IHByb3BlcnRpZXMuZ2V0KCByZW5kZXJUYXJnZXQuZGVwdGhUZXh0dXJlICkuX193ZWJnbFRleHR1cmU7XHJcblx0XHRjb25zdCBzYW1wbGVzID0gZ2V0UmVuZGVyVGFyZ2V0U2FtcGxlcyggcmVuZGVyVGFyZ2V0ICk7XHJcblxyXG5cdFx0aWYgKCByZW5kZXJUYXJnZXQuZGVwdGhUZXh0dXJlLmZvcm1hdCA9PT0gRGVwdGhGb3JtYXQgKSB7XHJcblxyXG5cdFx0XHRpZiAoIHVzZU11bHRpc2FtcGxlZFJUVCggcmVuZGVyVGFyZ2V0ICkgKSB7XHJcblxyXG5cdFx0XHRcdG11bHRpc2FtcGxlZFJUVEV4dC5mcmFtZWJ1ZmZlclRleHR1cmUyRE11bHRpc2FtcGxlRVhUKCBfZ2wuRlJBTUVCVUZGRVIsIF9nbC5ERVBUSF9BVFRBQ0hNRU5ULCBfZ2wuVEVYVFVSRV8yRCwgd2ViZ2xEZXB0aFRleHR1cmUsIDAsIHNhbXBsZXMgKTtcclxuXHJcblx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdF9nbC5mcmFtZWJ1ZmZlclRleHR1cmUyRCggX2dsLkZSQU1FQlVGRkVSLCBfZ2wuREVQVEhfQVRUQUNITUVOVCwgX2dsLlRFWFRVUkVfMkQsIHdlYmdsRGVwdGhUZXh0dXJlLCAwICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fSBlbHNlIGlmICggcmVuZGVyVGFyZ2V0LmRlcHRoVGV4dHVyZS5mb3JtYXQgPT09IERlcHRoU3RlbmNpbEZvcm1hdCApIHtcclxuXHJcblx0XHRcdGlmICggdXNlTXVsdGlzYW1wbGVkUlRUKCByZW5kZXJUYXJnZXQgKSApIHtcclxuXHJcblx0XHRcdFx0bXVsdGlzYW1wbGVkUlRURXh0LmZyYW1lYnVmZmVyVGV4dHVyZTJETXVsdGlzYW1wbGVFWFQoIF9nbC5GUkFNRUJVRkZFUiwgX2dsLkRFUFRIX1NURU5DSUxfQVRUQUNITUVOVCwgX2dsLlRFWFRVUkVfMkQsIHdlYmdsRGVwdGhUZXh0dXJlLCAwLCBzYW1wbGVzICk7XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRfZ2wuZnJhbWVidWZmZXJUZXh0dXJlMkQoIF9nbC5GUkFNRUJVRkZFUiwgX2dsLkRFUFRIX1NURU5DSUxfQVRUQUNITUVOVCwgX2dsLlRFWFRVUkVfMkQsIHdlYmdsRGVwdGhUZXh0dXJlLCAwICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdHRocm93IG5ldyBFcnJvciggJ1Vua25vd24gZGVwdGhUZXh0dXJlIGZvcm1hdCcgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gU2V0dXAgR0wgcmVzb3VyY2VzIGZvciBhIG5vbi10ZXh0dXJlIGRlcHRoIGJ1ZmZlclxyXG5cdGZ1bmN0aW9uIHNldHVwRGVwdGhSZW5kZXJidWZmZXIoIHJlbmRlclRhcmdldCApIHtcclxuXHJcblx0XHRjb25zdCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzID0gcHJvcGVydGllcy5nZXQoIHJlbmRlclRhcmdldCApO1xyXG5cdFx0Y29uc3QgaXNDdWJlID0gKCByZW5kZXJUYXJnZXQuaXNXZWJHTEN1YmVSZW5kZXJUYXJnZXQgPT09IHRydWUgKTtcclxuXHJcblx0XHRpZiAoIHJlbmRlclRhcmdldC5kZXB0aFRleHR1cmUgJiYgISByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fYXV0b0FsbG9jYXRlRGVwdGhCdWZmZXIgKSB7XHJcblxyXG5cdFx0XHRpZiAoIGlzQ3ViZSApIHRocm93IG5ldyBFcnJvciggJ3RhcmdldC5kZXB0aFRleHR1cmUgbm90IHN1cHBvcnRlZCBpbiBDdWJlIHJlbmRlciB0YXJnZXRzJyApO1xyXG5cclxuXHRcdFx0c2V0dXBEZXB0aFRleHR1cmUoIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbEZyYW1lYnVmZmVyLCByZW5kZXJUYXJnZXQgKTtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0aWYgKCBpc0N1YmUgKSB7XHJcblxyXG5cdFx0XHRcdHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbERlcHRoYnVmZmVyID0gW107XHJcblxyXG5cdFx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IDY7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0c3RhdGUuYmluZEZyYW1lYnVmZmVyKCBfZ2wuRlJBTUVCVUZGRVIsIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbEZyYW1lYnVmZmVyWyBpIF0gKTtcclxuXHRcdFx0XHRcdHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbERlcHRoYnVmZmVyWyBpIF0gPSBfZ2wuY3JlYXRlUmVuZGVyYnVmZmVyKCk7XHJcblx0XHRcdFx0XHRzZXR1cFJlbmRlckJ1ZmZlclN0b3JhZ2UoIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbERlcHRoYnVmZmVyWyBpIF0sIHJlbmRlclRhcmdldCwgZmFsc2UgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0c3RhdGUuYmluZEZyYW1lYnVmZmVyKCBfZ2wuRlJBTUVCVUZGRVIsIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbEZyYW1lYnVmZmVyICk7XHJcblx0XHRcdFx0cmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX3dlYmdsRGVwdGhidWZmZXIgPSBfZ2wuY3JlYXRlUmVuZGVyYnVmZmVyKCk7XHJcblx0XHRcdFx0c2V0dXBSZW5kZXJCdWZmZXJTdG9yYWdlKCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xEZXB0aGJ1ZmZlciwgcmVuZGVyVGFyZ2V0LCBmYWxzZSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRzdGF0ZS5iaW5kRnJhbWVidWZmZXIoIF9nbC5GUkFNRUJVRkZFUiwgbnVsbCApO1xyXG5cclxuXHR9XHJcblxyXG5cdC8vIHJlYmluZCBmcmFtZWJ1ZmZlciB3aXRoIGV4dGVybmFsIHRleHR1cmVzXHJcblx0ZnVuY3Rpb24gcmViaW5kVGV4dHVyZXMoIHJlbmRlclRhcmdldCwgY29sb3JUZXh0dXJlLCBkZXB0aFRleHR1cmUgKSB7XHJcblxyXG5cdFx0Y29uc3QgcmVuZGVyVGFyZ2V0UHJvcGVydGllcyA9IHByb3BlcnRpZXMuZ2V0KCByZW5kZXJUYXJnZXQgKTtcclxuXHJcblx0XHRpZiAoIGNvbG9yVGV4dHVyZSAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0c2V0dXBGcmFtZUJ1ZmZlclRleHR1cmUoIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbEZyYW1lYnVmZmVyLCByZW5kZXJUYXJnZXQsIHJlbmRlclRhcmdldC50ZXh0dXJlLCBfZ2wuQ09MT1JfQVRUQUNITUVOVDAsIF9nbC5URVhUVVJFXzJELCAwICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggZGVwdGhUZXh0dXJlICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRzZXR1cERlcHRoUmVuZGVyYnVmZmVyKCByZW5kZXJUYXJnZXQgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gU2V0IHVwIEdMIHJlc291cmNlcyBmb3IgdGhlIHJlbmRlciB0YXJnZXRcclxuXHRmdW5jdGlvbiBzZXR1cFJlbmRlclRhcmdldCggcmVuZGVyVGFyZ2V0ICkge1xyXG5cclxuXHRcdGNvbnN0IHRleHR1cmUgPSByZW5kZXJUYXJnZXQudGV4dHVyZTtcclxuXHJcblx0XHRjb25zdCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzID0gcHJvcGVydGllcy5nZXQoIHJlbmRlclRhcmdldCApO1xyXG5cdFx0Y29uc3QgdGV4dHVyZVByb3BlcnRpZXMgPSBwcm9wZXJ0aWVzLmdldCggdGV4dHVyZSApO1xyXG5cclxuXHRcdHJlbmRlclRhcmdldC5hZGRFdmVudExpc3RlbmVyKCAnZGlzcG9zZScsIG9uUmVuZGVyVGFyZ2V0RGlzcG9zZSApO1xyXG5cclxuXHRcdGlmICggcmVuZGVyVGFyZ2V0LmlzV2ViR0xNdWx0aXBsZVJlbmRlclRhcmdldHMgIT09IHRydWUgKSB7XHJcblxyXG5cdFx0XHRpZiAoIHRleHR1cmVQcm9wZXJ0aWVzLl9fd2ViZ2xUZXh0dXJlID09PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRcdHRleHR1cmVQcm9wZXJ0aWVzLl9fd2ViZ2xUZXh0dXJlID0gX2dsLmNyZWF0ZVRleHR1cmUoKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHRleHR1cmVQcm9wZXJ0aWVzLl9fdmVyc2lvbiA9IHRleHR1cmUudmVyc2lvbjtcclxuXHRcdFx0aW5mby5tZW1vcnkudGV4dHVyZXMgKys7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGNvbnN0IGlzQ3ViZSA9ICggcmVuZGVyVGFyZ2V0LmlzV2ViR0xDdWJlUmVuZGVyVGFyZ2V0ID09PSB0cnVlICk7XHJcblx0XHRjb25zdCBpc011bHRpcGxlUmVuZGVyVGFyZ2V0cyA9ICggcmVuZGVyVGFyZ2V0LmlzV2ViR0xNdWx0aXBsZVJlbmRlclRhcmdldHMgPT09IHRydWUgKTtcclxuXHRcdGNvbnN0IHN1cHBvcnRzTWlwcyA9IGlzUG93ZXJPZlR3byggcmVuZGVyVGFyZ2V0ICkgfHwgaXNXZWJHTDI7XHJcblxyXG5cdFx0Ly8gU2V0dXAgZnJhbWVidWZmZXJcclxuXHJcblx0XHRpZiAoIGlzQ3ViZSApIHtcclxuXHJcblx0XHRcdHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbEZyYW1lYnVmZmVyID0gW107XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCA2OyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRpZiAoIGlzV2ViR0wyICYmIHRleHR1cmUubWlwbWFwcyAmJiB0ZXh0dXJlLm1pcG1hcHMubGVuZ3RoID4gMCApIHtcclxuXHJcblx0XHRcdFx0XHRyZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xGcmFtZWJ1ZmZlclsgaSBdID0gW107XHJcblxyXG5cdFx0XHRcdFx0Zm9yICggbGV0IGxldmVsID0gMDsgbGV2ZWwgPCB0ZXh0dXJlLm1pcG1hcHMubGVuZ3RoOyBsZXZlbCArKyApIHtcclxuXHJcblx0XHRcdFx0XHRcdHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbEZyYW1lYnVmZmVyWyBpIF1bIGxldmVsIF0gPSBfZ2wuY3JlYXRlRnJhbWVidWZmZXIoKTtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0cmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX3dlYmdsRnJhbWVidWZmZXJbIGkgXSA9IF9nbC5jcmVhdGVGcmFtZWJ1ZmZlcigpO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdGlmICggaXNXZWJHTDIgJiYgdGV4dHVyZS5taXBtYXBzICYmIHRleHR1cmUubWlwbWFwcy5sZW5ndGggPiAwICkge1xyXG5cclxuXHRcdFx0XHRyZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xGcmFtZWJ1ZmZlciA9IFtdO1xyXG5cclxuXHRcdFx0XHRmb3IgKCBsZXQgbGV2ZWwgPSAwOyBsZXZlbCA8IHRleHR1cmUubWlwbWFwcy5sZW5ndGg7IGxldmVsICsrICkge1xyXG5cclxuXHRcdFx0XHRcdHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbEZyYW1lYnVmZmVyWyBsZXZlbCBdID0gX2dsLmNyZWF0ZUZyYW1lYnVmZmVyKCk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbEZyYW1lYnVmZmVyID0gX2dsLmNyZWF0ZUZyYW1lYnVmZmVyKCk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRpZiAoIGlzTXVsdGlwbGVSZW5kZXJUYXJnZXRzICkge1xyXG5cclxuXHRcdFx0XHRpZiAoIGNhcGFiaWxpdGllcy5kcmF3QnVmZmVycyApIHtcclxuXHJcblx0XHRcdFx0XHRjb25zdCB0ZXh0dXJlcyA9IHJlbmRlclRhcmdldC50ZXh0dXJlO1xyXG5cclxuXHRcdFx0XHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSB0ZXh0dXJlcy5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0XHRcdGNvbnN0IGF0dGFjaG1lbnRQcm9wZXJ0aWVzID0gcHJvcGVydGllcy5nZXQoIHRleHR1cmVzWyBpIF0gKTtcclxuXHJcblx0XHRcdFx0XHRcdGlmICggYXR0YWNobWVudFByb3BlcnRpZXMuX193ZWJnbFRleHR1cmUgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0YXR0YWNobWVudFByb3BlcnRpZXMuX193ZWJnbFRleHR1cmUgPSBfZ2wuY3JlYXRlVGV4dHVyZSgpO1xyXG5cclxuXHRcdFx0XHRcdFx0XHRpbmZvLm1lbW9yeS50ZXh0dXJlcyArKztcclxuXHJcblx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuV2ViR0xSZW5kZXJlcjogV2ViR0xNdWx0aXBsZVJlbmRlclRhcmdldHMgY2FuIG9ubHkgYmUgdXNlZCB3aXRoIFdlYkdMMiBvciBXRUJHTF9kcmF3X2J1ZmZlcnMgZXh0ZW5zaW9uLicgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0aWYgKCAoIGlzV2ViR0wyICYmIHJlbmRlclRhcmdldC5zYW1wbGVzID4gMCApICYmIHVzZU11bHRpc2FtcGxlZFJUVCggcmVuZGVyVGFyZ2V0ICkgPT09IGZhbHNlICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCB0ZXh0dXJlcyA9IGlzTXVsdGlwbGVSZW5kZXJUYXJnZXRzID8gdGV4dHVyZSA6IFsgdGV4dHVyZSBdO1xyXG5cclxuXHRcdFx0XHRyZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xNdWx0aXNhbXBsZWRGcmFtZWJ1ZmZlciA9IF9nbC5jcmVhdGVGcmFtZWJ1ZmZlcigpO1xyXG5cdFx0XHRcdHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbENvbG9yUmVuZGVyYnVmZmVyID0gW107XHJcblxyXG5cdFx0XHRcdHN0YXRlLmJpbmRGcmFtZWJ1ZmZlciggX2dsLkZSQU1FQlVGRkVSLCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xNdWx0aXNhbXBsZWRGcmFtZWJ1ZmZlciApO1xyXG5cclxuXHRcdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCB0ZXh0dXJlcy5sZW5ndGg7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgdGV4dHVyZSA9IHRleHR1cmVzWyBpIF07XHJcblx0XHRcdFx0XHRyZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xDb2xvclJlbmRlcmJ1ZmZlclsgaSBdID0gX2dsLmNyZWF0ZVJlbmRlcmJ1ZmZlcigpO1xyXG5cclxuXHRcdFx0XHRcdF9nbC5iaW5kUmVuZGVyYnVmZmVyKCBfZ2wuUkVOREVSQlVGRkVSLCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xDb2xvclJlbmRlcmJ1ZmZlclsgaSBdICk7XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgZ2xGb3JtYXQgPSB1dGlscy5jb252ZXJ0KCB0ZXh0dXJlLmZvcm1hdCwgdGV4dHVyZS5jb2xvclNwYWNlICk7XHJcblx0XHRcdFx0XHRjb25zdCBnbFR5cGUgPSB1dGlscy5jb252ZXJ0KCB0ZXh0dXJlLnR5cGUgKTtcclxuXHRcdFx0XHRcdGNvbnN0IGdsSW50ZXJuYWxGb3JtYXQgPSBnZXRJbnRlcm5hbEZvcm1hdCggdGV4dHVyZS5pbnRlcm5hbEZvcm1hdCwgZ2xGb3JtYXQsIGdsVHlwZSwgdGV4dHVyZS5jb2xvclNwYWNlLCByZW5kZXJUYXJnZXQuaXNYUlJlbmRlclRhcmdldCA9PT0gdHJ1ZSApO1xyXG5cdFx0XHRcdFx0Y29uc3Qgc2FtcGxlcyA9IGdldFJlbmRlclRhcmdldFNhbXBsZXMoIHJlbmRlclRhcmdldCApO1xyXG5cdFx0XHRcdFx0X2dsLnJlbmRlcmJ1ZmZlclN0b3JhZ2VNdWx0aXNhbXBsZSggX2dsLlJFTkRFUkJVRkZFUiwgc2FtcGxlcywgZ2xJbnRlcm5hbEZvcm1hdCwgcmVuZGVyVGFyZ2V0LndpZHRoLCByZW5kZXJUYXJnZXQuaGVpZ2h0ICk7XHJcblxyXG5cdFx0XHRcdFx0X2dsLmZyYW1lYnVmZmVyUmVuZGVyYnVmZmVyKCBfZ2wuRlJBTUVCVUZGRVIsIF9nbC5DT0xPUl9BVFRBQ0hNRU5UMCArIGksIF9nbC5SRU5ERVJCVUZGRVIsIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbENvbG9yUmVuZGVyYnVmZmVyWyBpIF0gKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRfZ2wuYmluZFJlbmRlcmJ1ZmZlciggX2dsLlJFTkRFUkJVRkZFUiwgbnVsbCApO1xyXG5cclxuXHRcdFx0XHRpZiAoIHJlbmRlclRhcmdldC5kZXB0aEJ1ZmZlciApIHtcclxuXHJcblx0XHRcdFx0XHRyZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xEZXB0aFJlbmRlcmJ1ZmZlciA9IF9nbC5jcmVhdGVSZW5kZXJidWZmZXIoKTtcclxuXHRcdFx0XHRcdHNldHVwUmVuZGVyQnVmZmVyU3RvcmFnZSggcmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX3dlYmdsRGVwdGhSZW5kZXJidWZmZXIsIHJlbmRlclRhcmdldCwgdHJ1ZSApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdHN0YXRlLmJpbmRGcmFtZWJ1ZmZlciggX2dsLkZSQU1FQlVGRkVSLCBudWxsICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIFNldHVwIGNvbG9yIGJ1ZmZlclxyXG5cclxuXHRcdGlmICggaXNDdWJlICkge1xyXG5cclxuXHRcdFx0c3RhdGUuYmluZFRleHR1cmUoIF9nbC5URVhUVVJFX0NVQkVfTUFQLCB0ZXh0dXJlUHJvcGVydGllcy5fX3dlYmdsVGV4dHVyZSApO1xyXG5cdFx0XHRzZXRUZXh0dXJlUGFyYW1ldGVycyggX2dsLlRFWFRVUkVfQ1VCRV9NQVAsIHRleHR1cmUsIHN1cHBvcnRzTWlwcyApO1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgNjsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0aWYgKCBpc1dlYkdMMiAmJiB0ZXh0dXJlLm1pcG1hcHMgJiYgdGV4dHVyZS5taXBtYXBzLmxlbmd0aCA+IDAgKSB7XHJcblxyXG5cdFx0XHRcdFx0Zm9yICggbGV0IGxldmVsID0gMDsgbGV2ZWwgPCB0ZXh0dXJlLm1pcG1hcHMubGVuZ3RoOyBsZXZlbCArKyApIHtcclxuXHJcblx0XHRcdFx0XHRcdHNldHVwRnJhbWVCdWZmZXJUZXh0dXJlKCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xGcmFtZWJ1ZmZlclsgaSBdWyBsZXZlbCBdLCByZW5kZXJUYXJnZXQsIHRleHR1cmUsIF9nbC5DT0xPUl9BVFRBQ0hNRU5UMCwgX2dsLlRFWFRVUkVfQ1VCRV9NQVBfUE9TSVRJVkVfWCArIGksIGxldmVsICk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdHNldHVwRnJhbWVCdWZmZXJUZXh0dXJlKCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xGcmFtZWJ1ZmZlclsgaSBdLCByZW5kZXJUYXJnZXQsIHRleHR1cmUsIF9nbC5DT0xPUl9BVFRBQ0hNRU5UMCwgX2dsLlRFWFRVUkVfQ1VCRV9NQVBfUE9TSVRJVkVfWCArIGksIDAgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0aWYgKCB0ZXh0dXJlTmVlZHNHZW5lcmF0ZU1pcG1hcHMoIHRleHR1cmUsIHN1cHBvcnRzTWlwcyApICkge1xyXG5cclxuXHRcdFx0XHRnZW5lcmF0ZU1pcG1hcCggX2dsLlRFWFRVUkVfQ1VCRV9NQVAgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHN0YXRlLnVuYmluZFRleHR1cmUoKTtcclxuXHJcblx0XHR9IGVsc2UgaWYgKCBpc011bHRpcGxlUmVuZGVyVGFyZ2V0cyApIHtcclxuXHJcblx0XHRcdGNvbnN0IHRleHR1cmVzID0gcmVuZGVyVGFyZ2V0LnRleHR1cmU7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gdGV4dHVyZXMubGVuZ3RoOyBpIDwgaWw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IGF0dGFjaG1lbnQgPSB0ZXh0dXJlc1sgaSBdO1xyXG5cdFx0XHRcdGNvbnN0IGF0dGFjaG1lbnRQcm9wZXJ0aWVzID0gcHJvcGVydGllcy5nZXQoIGF0dGFjaG1lbnQgKTtcclxuXHJcblx0XHRcdFx0c3RhdGUuYmluZFRleHR1cmUoIF9nbC5URVhUVVJFXzJELCBhdHRhY2htZW50UHJvcGVydGllcy5fX3dlYmdsVGV4dHVyZSApO1xyXG5cdFx0XHRcdHNldFRleHR1cmVQYXJhbWV0ZXJzKCBfZ2wuVEVYVFVSRV8yRCwgYXR0YWNobWVudCwgc3VwcG9ydHNNaXBzICk7XHJcblx0XHRcdFx0c2V0dXBGcmFtZUJ1ZmZlclRleHR1cmUoIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbEZyYW1lYnVmZmVyLCByZW5kZXJUYXJnZXQsIGF0dGFjaG1lbnQsIF9nbC5DT0xPUl9BVFRBQ0hNRU5UMCArIGksIF9nbC5URVhUVVJFXzJELCAwICk7XHJcblxyXG5cdFx0XHRcdGlmICggdGV4dHVyZU5lZWRzR2VuZXJhdGVNaXBtYXBzKCBhdHRhY2htZW50LCBzdXBwb3J0c01pcHMgKSApIHtcclxuXHJcblx0XHRcdFx0XHRnZW5lcmF0ZU1pcG1hcCggX2dsLlRFWFRVUkVfMkQgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0c3RhdGUudW5iaW5kVGV4dHVyZSgpO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRsZXQgZ2xUZXh0dXJlVHlwZSA9IF9nbC5URVhUVVJFXzJEO1xyXG5cclxuXHRcdFx0aWYgKCByZW5kZXJUYXJnZXQuaXNXZWJHTDNEUmVuZGVyVGFyZ2V0IHx8IHJlbmRlclRhcmdldC5pc1dlYkdMQXJyYXlSZW5kZXJUYXJnZXQgKSB7XHJcblxyXG5cdFx0XHRcdGlmICggaXNXZWJHTDIgKSB7XHJcblxyXG5cdFx0XHRcdFx0Z2xUZXh0dXJlVHlwZSA9IHJlbmRlclRhcmdldC5pc1dlYkdMM0RSZW5kZXJUYXJnZXQgPyBfZ2wuVEVYVFVSRV8zRCA6IF9nbC5URVhUVVJFXzJEX0FSUkFZO1xyXG5cclxuXHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5XZWJHTFRleHR1cmVzOiBUSFJFRS5EYXRhM0RUZXh0dXJlIGFuZCBUSFJFRS5EYXRhQXJyYXlUZXh0dXJlIG9ubHkgc3VwcG9ydGVkIHdpdGggV2ViR0wyLicgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0c3RhdGUuYmluZFRleHR1cmUoIGdsVGV4dHVyZVR5cGUsIHRleHR1cmVQcm9wZXJ0aWVzLl9fd2ViZ2xUZXh0dXJlICk7XHJcblx0XHRcdHNldFRleHR1cmVQYXJhbWV0ZXJzKCBnbFRleHR1cmVUeXBlLCB0ZXh0dXJlLCBzdXBwb3J0c01pcHMgKTtcclxuXHJcblx0XHRcdGlmICggaXNXZWJHTDIgJiYgdGV4dHVyZS5taXBtYXBzICYmIHRleHR1cmUubWlwbWFwcy5sZW5ndGggPiAwICkge1xyXG5cclxuXHRcdFx0XHRmb3IgKCBsZXQgbGV2ZWwgPSAwOyBsZXZlbCA8IHRleHR1cmUubWlwbWFwcy5sZW5ndGg7IGxldmVsICsrICkge1xyXG5cclxuXHRcdFx0XHRcdHNldHVwRnJhbWVCdWZmZXJUZXh0dXJlKCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xGcmFtZWJ1ZmZlclsgbGV2ZWwgXSwgcmVuZGVyVGFyZ2V0LCB0ZXh0dXJlLCBfZ2wuQ09MT1JfQVRUQUNITUVOVDAsIGdsVGV4dHVyZVR5cGUsIGxldmVsICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdHNldHVwRnJhbWVCdWZmZXJUZXh0dXJlKCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xGcmFtZWJ1ZmZlciwgcmVuZGVyVGFyZ2V0LCB0ZXh0dXJlLCBfZ2wuQ09MT1JfQVRUQUNITUVOVDAsIGdsVGV4dHVyZVR5cGUsIDAgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGlmICggdGV4dHVyZU5lZWRzR2VuZXJhdGVNaXBtYXBzKCB0ZXh0dXJlLCBzdXBwb3J0c01pcHMgKSApIHtcclxuXHJcblx0XHRcdFx0Z2VuZXJhdGVNaXBtYXAoIGdsVGV4dHVyZVR5cGUgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHN0YXRlLnVuYmluZFRleHR1cmUoKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gU2V0dXAgZGVwdGggYW5kIHN0ZW5jaWwgYnVmZmVyc1xyXG5cclxuXHRcdGlmICggcmVuZGVyVGFyZ2V0LmRlcHRoQnVmZmVyICkge1xyXG5cclxuXHRcdFx0c2V0dXBEZXB0aFJlbmRlcmJ1ZmZlciggcmVuZGVyVGFyZ2V0ICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHVwZGF0ZVJlbmRlclRhcmdldE1pcG1hcCggcmVuZGVyVGFyZ2V0ICkge1xyXG5cclxuXHRcdGNvbnN0IHN1cHBvcnRzTWlwcyA9IGlzUG93ZXJPZlR3byggcmVuZGVyVGFyZ2V0ICkgfHwgaXNXZWJHTDI7XHJcblxyXG5cdFx0Y29uc3QgdGV4dHVyZXMgPSByZW5kZXJUYXJnZXQuaXNXZWJHTE11bHRpcGxlUmVuZGVyVGFyZ2V0cyA9PT0gdHJ1ZSA/IHJlbmRlclRhcmdldC50ZXh0dXJlIDogWyByZW5kZXJUYXJnZXQudGV4dHVyZSBdO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSB0ZXh0dXJlcy5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcclxuXHJcblx0XHRcdGNvbnN0IHRleHR1cmUgPSB0ZXh0dXJlc1sgaSBdO1xyXG5cclxuXHRcdFx0aWYgKCB0ZXh0dXJlTmVlZHNHZW5lcmF0ZU1pcG1hcHMoIHRleHR1cmUsIHN1cHBvcnRzTWlwcyApICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCB0YXJnZXQgPSByZW5kZXJUYXJnZXQuaXNXZWJHTEN1YmVSZW5kZXJUYXJnZXQgPyBfZ2wuVEVYVFVSRV9DVUJFX01BUCA6IF9nbC5URVhUVVJFXzJEO1xyXG5cdFx0XHRcdGNvbnN0IHdlYmdsVGV4dHVyZSA9IHByb3BlcnRpZXMuZ2V0KCB0ZXh0dXJlICkuX193ZWJnbFRleHR1cmU7XHJcblxyXG5cdFx0XHRcdHN0YXRlLmJpbmRUZXh0dXJlKCB0YXJnZXQsIHdlYmdsVGV4dHVyZSApO1xyXG5cdFx0XHRcdGdlbmVyYXRlTWlwbWFwKCB0YXJnZXQgKTtcclxuXHRcdFx0XHRzdGF0ZS51bmJpbmRUZXh0dXJlKCk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHVwZGF0ZU11bHRpc2FtcGxlUmVuZGVyVGFyZ2V0KCByZW5kZXJUYXJnZXQgKSB7XHJcblxyXG5cdFx0aWYgKCAoIGlzV2ViR0wyICYmIHJlbmRlclRhcmdldC5zYW1wbGVzID4gMCApICYmIHVzZU11bHRpc2FtcGxlZFJUVCggcmVuZGVyVGFyZ2V0ICkgPT09IGZhbHNlICkge1xyXG5cclxuXHRcdFx0Y29uc3QgdGV4dHVyZXMgPSByZW5kZXJUYXJnZXQuaXNXZWJHTE11bHRpcGxlUmVuZGVyVGFyZ2V0cyA/IHJlbmRlclRhcmdldC50ZXh0dXJlIDogWyByZW5kZXJUYXJnZXQudGV4dHVyZSBdO1xyXG5cdFx0XHRjb25zdCB3aWR0aCA9IHJlbmRlclRhcmdldC53aWR0aDtcclxuXHRcdFx0Y29uc3QgaGVpZ2h0ID0gcmVuZGVyVGFyZ2V0LmhlaWdodDtcclxuXHRcdFx0bGV0IG1hc2sgPSBfZ2wuQ09MT1JfQlVGRkVSX0JJVDtcclxuXHRcdFx0Y29uc3QgaW52YWxpZGF0aW9uQXJyYXkgPSBbXTtcclxuXHRcdFx0Y29uc3QgZGVwdGhTdHlsZSA9IHJlbmRlclRhcmdldC5zdGVuY2lsQnVmZmVyID8gX2dsLkRFUFRIX1NURU5DSUxfQVRUQUNITUVOVCA6IF9nbC5ERVBUSF9BVFRBQ0hNRU5UO1xyXG5cdFx0XHRjb25zdCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzID0gcHJvcGVydGllcy5nZXQoIHJlbmRlclRhcmdldCApO1xyXG5cdFx0XHRjb25zdCBpc011bHRpcGxlUmVuZGVyVGFyZ2V0cyA9ICggcmVuZGVyVGFyZ2V0LmlzV2ViR0xNdWx0aXBsZVJlbmRlclRhcmdldHMgPT09IHRydWUgKTtcclxuXHJcblx0XHRcdC8vIElmIE1SVCB3ZSBuZWVkIHRvIHJlbW92ZSBGQk8gYXR0YWNobWVudHNcclxuXHRcdFx0aWYgKCBpc011bHRpcGxlUmVuZGVyVGFyZ2V0cyApIHtcclxuXHJcblx0XHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgdGV4dHVyZXMubGVuZ3RoOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRcdHN0YXRlLmJpbmRGcmFtZWJ1ZmZlciggX2dsLkZSQU1FQlVGRkVSLCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xNdWx0aXNhbXBsZWRGcmFtZWJ1ZmZlciApO1xyXG5cdFx0XHRcdFx0X2dsLmZyYW1lYnVmZmVyUmVuZGVyYnVmZmVyKCBfZ2wuRlJBTUVCVUZGRVIsIF9nbC5DT0xPUl9BVFRBQ0hNRU5UMCArIGksIF9nbC5SRU5ERVJCVUZGRVIsIG51bGwgKTtcclxuXHJcblx0XHRcdFx0XHRzdGF0ZS5iaW5kRnJhbWVidWZmZXIoIF9nbC5GUkFNRUJVRkZFUiwgcmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX3dlYmdsRnJhbWVidWZmZXIgKTtcclxuXHRcdFx0XHRcdF9nbC5mcmFtZWJ1ZmZlclRleHR1cmUyRCggX2dsLkRSQVdfRlJBTUVCVUZGRVIsIF9nbC5DT0xPUl9BVFRBQ0hNRU5UMCArIGksIF9nbC5URVhUVVJFXzJELCBudWxsLCAwICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHN0YXRlLmJpbmRGcmFtZWJ1ZmZlciggX2dsLlJFQURfRlJBTUVCVUZGRVIsIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbE11bHRpc2FtcGxlZEZyYW1lYnVmZmVyICk7XHJcblx0XHRcdHN0YXRlLmJpbmRGcmFtZWJ1ZmZlciggX2dsLkRSQVdfRlJBTUVCVUZGRVIsIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbEZyYW1lYnVmZmVyICk7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCB0ZXh0dXJlcy5sZW5ndGg7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdGludmFsaWRhdGlvbkFycmF5LnB1c2goIF9nbC5DT0xPUl9BVFRBQ0hNRU5UMCArIGkgKTtcclxuXHJcblx0XHRcdFx0aWYgKCByZW5kZXJUYXJnZXQuZGVwdGhCdWZmZXIgKSB7XHJcblxyXG5cdFx0XHRcdFx0aW52YWxpZGF0aW9uQXJyYXkucHVzaCggZGVwdGhTdHlsZSApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdGNvbnN0IGlnbm9yZURlcHRoVmFsdWVzID0gKCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9faWdub3JlRGVwdGhWYWx1ZXMgIT09IHVuZGVmaW5lZCApID8gcmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX2lnbm9yZURlcHRoVmFsdWVzIDogZmFsc2U7XHJcblxyXG5cdFx0XHRcdGlmICggaWdub3JlRGVwdGhWYWx1ZXMgPT09IGZhbHNlICkge1xyXG5cclxuXHRcdFx0XHRcdGlmICggcmVuZGVyVGFyZ2V0LmRlcHRoQnVmZmVyICkgbWFzayB8PSBfZ2wuREVQVEhfQlVGRkVSX0JJVDtcclxuXHRcdFx0XHRcdGlmICggcmVuZGVyVGFyZ2V0LnN0ZW5jaWxCdWZmZXIgKSBtYXNrIHw9IF9nbC5TVEVOQ0lMX0JVRkZFUl9CSVQ7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0aWYgKCBpc011bHRpcGxlUmVuZGVyVGFyZ2V0cyApIHtcclxuXHJcblx0XHRcdFx0XHRfZ2wuZnJhbWVidWZmZXJSZW5kZXJidWZmZXIoIF9nbC5SRUFEX0ZSQU1FQlVGRkVSLCBfZ2wuQ09MT1JfQVRUQUNITUVOVDAsIF9nbC5SRU5ERVJCVUZGRVIsIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbENvbG9yUmVuZGVyYnVmZmVyWyBpIF0gKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRpZiAoIGlnbm9yZURlcHRoVmFsdWVzID09PSB0cnVlICkge1xyXG5cclxuXHRcdFx0XHRcdF9nbC5pbnZhbGlkYXRlRnJhbWVidWZmZXIoIF9nbC5SRUFEX0ZSQU1FQlVGRkVSLCBbIGRlcHRoU3R5bGUgXSApO1xyXG5cdFx0XHRcdFx0X2dsLmludmFsaWRhdGVGcmFtZWJ1ZmZlciggX2dsLkRSQVdfRlJBTUVCVUZGRVIsIFsgZGVwdGhTdHlsZSBdICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0aWYgKCBpc011bHRpcGxlUmVuZGVyVGFyZ2V0cyApIHtcclxuXHJcblx0XHRcdFx0XHRjb25zdCB3ZWJnbFRleHR1cmUgPSBwcm9wZXJ0aWVzLmdldCggdGV4dHVyZXNbIGkgXSApLl9fd2ViZ2xUZXh0dXJlO1xyXG5cdFx0XHRcdFx0X2dsLmZyYW1lYnVmZmVyVGV4dHVyZTJEKCBfZ2wuRFJBV19GUkFNRUJVRkZFUiwgX2dsLkNPTE9SX0FUVEFDSE1FTlQwLCBfZ2wuVEVYVFVSRV8yRCwgd2ViZ2xUZXh0dXJlLCAwICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0X2dsLmJsaXRGcmFtZWJ1ZmZlciggMCwgMCwgd2lkdGgsIGhlaWdodCwgMCwgMCwgd2lkdGgsIGhlaWdodCwgbWFzaywgX2dsLk5FQVJFU1QgKTtcclxuXHJcblx0XHRcdFx0aWYgKCBzdXBwb3J0c0ludmFsaWRhdGVGcmFtZWJ1ZmZlciApIHtcclxuXHJcblx0XHRcdFx0XHRfZ2wuaW52YWxpZGF0ZUZyYW1lYnVmZmVyKCBfZ2wuUkVBRF9GUkFNRUJVRkZFUiwgaW52YWxpZGF0aW9uQXJyYXkgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHN0YXRlLmJpbmRGcmFtZWJ1ZmZlciggX2dsLlJFQURfRlJBTUVCVUZGRVIsIG51bGwgKTtcclxuXHRcdFx0c3RhdGUuYmluZEZyYW1lYnVmZmVyKCBfZ2wuRFJBV19GUkFNRUJVRkZFUiwgbnVsbCApO1xyXG5cclxuXHRcdFx0Ly8gSWYgTVJUIHNpbmNlIHByZS1ibGl0IHdlIHJlbW92ZWQgdGhlIEZCTyB3ZSBuZWVkIHRvIHJlY29uc3RydWN0IHRoZSBhdHRhY2htZW50c1xyXG5cdFx0XHRpZiAoIGlzTXVsdGlwbGVSZW5kZXJUYXJnZXRzICkge1xyXG5cclxuXHRcdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCB0ZXh0dXJlcy5sZW5ndGg7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0c3RhdGUuYmluZEZyYW1lYnVmZmVyKCBfZ2wuRlJBTUVCVUZGRVIsIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbE11bHRpc2FtcGxlZEZyYW1lYnVmZmVyICk7XHJcblx0XHRcdFx0XHRfZ2wuZnJhbWVidWZmZXJSZW5kZXJidWZmZXIoIF9nbC5GUkFNRUJVRkZFUiwgX2dsLkNPTE9SX0FUVEFDSE1FTlQwICsgaSwgX2dsLlJFTkRFUkJVRkZFUiwgcmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX3dlYmdsQ29sb3JSZW5kZXJidWZmZXJbIGkgXSApO1xyXG5cclxuXHRcdFx0XHRcdGNvbnN0IHdlYmdsVGV4dHVyZSA9IHByb3BlcnRpZXMuZ2V0KCB0ZXh0dXJlc1sgaSBdICkuX193ZWJnbFRleHR1cmU7XHJcblxyXG5cdFx0XHRcdFx0c3RhdGUuYmluZEZyYW1lYnVmZmVyKCBfZ2wuRlJBTUVCVUZGRVIsIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbEZyYW1lYnVmZmVyICk7XHJcblx0XHRcdFx0XHRfZ2wuZnJhbWVidWZmZXJUZXh0dXJlMkQoIF9nbC5EUkFXX0ZSQU1FQlVGRkVSLCBfZ2wuQ09MT1JfQVRUQUNITUVOVDAgKyBpLCBfZ2wuVEVYVFVSRV8yRCwgd2ViZ2xUZXh0dXJlLCAwICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHN0YXRlLmJpbmRGcmFtZWJ1ZmZlciggX2dsLkRSQVdfRlJBTUVCVUZGRVIsIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbE11bHRpc2FtcGxlZEZyYW1lYnVmZmVyICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIGdldFJlbmRlclRhcmdldFNhbXBsZXMoIHJlbmRlclRhcmdldCApIHtcclxuXHJcblx0XHRyZXR1cm4gTWF0aC5taW4oIGNhcGFiaWxpdGllcy5tYXhTYW1wbGVzLCByZW5kZXJUYXJnZXQuc2FtcGxlcyApO1xyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHVzZU11bHRpc2FtcGxlZFJUVCggcmVuZGVyVGFyZ2V0ICkge1xyXG5cclxuXHRcdGNvbnN0IHJlbmRlclRhcmdldFByb3BlcnRpZXMgPSBwcm9wZXJ0aWVzLmdldCggcmVuZGVyVGFyZ2V0ICk7XHJcblxyXG5cdFx0cmV0dXJuIGlzV2ViR0wyICYmIHJlbmRlclRhcmdldC5zYW1wbGVzID4gMCAmJiBleHRlbnNpb25zLmhhcyggJ1dFQkdMX211bHRpc2FtcGxlZF9yZW5kZXJfdG9fdGV4dHVyZScgKSA9PT0gdHJ1ZSAmJiByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fdXNlUmVuZGVyVG9UZXh0dXJlICE9PSBmYWxzZTtcclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiB1cGRhdGVWaWRlb1RleHR1cmUoIHRleHR1cmUgKSB7XHJcblxyXG5cdFx0Y29uc3QgZnJhbWUgPSBpbmZvLnJlbmRlci5mcmFtZTtcclxuXHJcblx0XHQvLyBDaGVjayB0aGUgbGFzdCBmcmFtZSB3ZSB1cGRhdGVkIHRoZSBWaWRlb1RleHR1cmVcclxuXHJcblx0XHRpZiAoIF92aWRlb1RleHR1cmVzLmdldCggdGV4dHVyZSApICE9PSBmcmFtZSApIHtcclxuXHJcblx0XHRcdF92aWRlb1RleHR1cmVzLnNldCggdGV4dHVyZSwgZnJhbWUgKTtcclxuXHRcdFx0dGV4dHVyZS51cGRhdGUoKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gdmVyaWZ5Q29sb3JTcGFjZSggdGV4dHVyZSwgaW1hZ2UgKSB7XHJcblxyXG5cdFx0Y29uc3QgY29sb3JTcGFjZSA9IHRleHR1cmUuY29sb3JTcGFjZTtcclxuXHRcdGNvbnN0IGZvcm1hdCA9IHRleHR1cmUuZm9ybWF0O1xyXG5cdFx0Y29uc3QgdHlwZSA9IHRleHR1cmUudHlwZTtcclxuXHJcblx0XHRpZiAoIHRleHR1cmUuaXNDb21wcmVzc2VkVGV4dHVyZSA9PT0gdHJ1ZSB8fCB0ZXh0dXJlLmlzVmlkZW9UZXh0dXJlID09PSB0cnVlIHx8IHRleHR1cmUuZm9ybWF0ID09PSBfU1JHQkFGb3JtYXQgKSByZXR1cm4gaW1hZ2U7XHJcblxyXG5cdFx0aWYgKCBjb2xvclNwYWNlICE9PSBMaW5lYXJTUkdCQ29sb3JTcGFjZSAmJiBjb2xvclNwYWNlICE9PSBOb0NvbG9yU3BhY2UgKSB7XHJcblxyXG5cdFx0XHQvLyBzUkdCXHJcblxyXG5cdFx0XHRpZiAoIENvbG9yTWFuYWdlbWVudC5nZXRUcmFuc2ZlciggY29sb3JTcGFjZSApID09PSBTUkdCVHJhbnNmZXIgKSB7XHJcblxyXG5cdFx0XHRcdGlmICggaXNXZWJHTDIgPT09IGZhbHNlICkge1xyXG5cclxuXHRcdFx0XHRcdC8vIGluIFdlYkdMIDEsIHRyeSB0byB1c2UgRVhUX3NSR0IgZXh0ZW5zaW9uIGFuZCB1bnNpemVkIGZvcm1hdHNcclxuXHJcblx0XHRcdFx0XHRpZiAoIGV4dGVuc2lvbnMuaGFzKCAnRVhUX3NSR0InICkgPT09IHRydWUgJiYgZm9ybWF0ID09PSBSR0JBRm9ybWF0ICkge1xyXG5cclxuXHRcdFx0XHRcdFx0dGV4dHVyZS5mb3JtYXQgPSBfU1JHQkFGb3JtYXQ7XHJcblxyXG5cdFx0XHRcdFx0XHQvLyBpdCdzIG5vdCBwb3NzaWJsZSB0byBnZW5lcmF0ZSBtaXBzIGluIFdlYkdMIDEgd2l0aCB0aGlzIGV4dGVuc2lvblxyXG5cclxuXHRcdFx0XHRcdFx0dGV4dHVyZS5taW5GaWx0ZXIgPSBMaW5lYXJGaWx0ZXI7XHJcblx0XHRcdFx0XHRcdHRleHR1cmUuZ2VuZXJhdGVNaXBtYXBzID0gZmFsc2U7XHJcblxyXG5cdFx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRcdC8vIHNsb3cgZmFsbGJhY2sgKENQVSBkZWNvZGUpXHJcblxyXG5cdFx0XHRcdFx0XHRpbWFnZSA9IEltYWdlVXRpbHMuc1JHQlRvTGluZWFyKCBpbWFnZSApO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHQvLyBpbiBXZWJHTCAyIHVuY29tcHJlc3NlZCB0ZXh0dXJlcyBjYW4gb25seSBiZSBzUkdCIGVuY29kZWQgaWYgdGhleSBoYXZlIHRoZSBSR0JBOCBmb3JtYXRcclxuXHJcblx0XHRcdFx0XHRpZiAoIGZvcm1hdCAhPT0gUkdCQUZvcm1hdCB8fCB0eXBlICE9PSBVbnNpZ25lZEJ5dGVUeXBlICkge1xyXG5cclxuXHRcdFx0XHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuV2ViR0xUZXh0dXJlczogc1JHQiBlbmNvZGVkIHRleHR1cmVzIGhhdmUgdG8gdXNlIFJHQkFGb3JtYXQgYW5kIFVuc2lnbmVkQnl0ZVR5cGUuJyApO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLldlYkdMVGV4dHVyZXM6IFVuc3VwcG9ydGVkIHRleHR1cmUgY29sb3Igc3BhY2U6JywgY29sb3JTcGFjZSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gaW1hZ2U7XHJcblxyXG5cdH1cclxuXHJcblx0Ly9cclxuXHJcblx0dGhpcy5hbGxvY2F0ZVRleHR1cmVVbml0ID0gYWxsb2NhdGVUZXh0dXJlVW5pdDtcclxuXHR0aGlzLnJlc2V0VGV4dHVyZVVuaXRzID0gcmVzZXRUZXh0dXJlVW5pdHM7XHJcblxyXG5cdHRoaXMuc2V0VGV4dHVyZTJEID0gc2V0VGV4dHVyZTJEO1xyXG5cdHRoaXMuc2V0VGV4dHVyZTJEQXJyYXkgPSBzZXRUZXh0dXJlMkRBcnJheTtcclxuXHR0aGlzLnNldFRleHR1cmUzRCA9IHNldFRleHR1cmUzRDtcclxuXHR0aGlzLnNldFRleHR1cmVDdWJlID0gc2V0VGV4dHVyZUN1YmU7XHJcblx0dGhpcy5yZWJpbmRUZXh0dXJlcyA9IHJlYmluZFRleHR1cmVzO1xyXG5cdHRoaXMuc2V0dXBSZW5kZXJUYXJnZXQgPSBzZXR1cFJlbmRlclRhcmdldDtcclxuXHR0aGlzLnVwZGF0ZVJlbmRlclRhcmdldE1pcG1hcCA9IHVwZGF0ZVJlbmRlclRhcmdldE1pcG1hcDtcclxuXHR0aGlzLnVwZGF0ZU11bHRpc2FtcGxlUmVuZGVyVGFyZ2V0ID0gdXBkYXRlTXVsdGlzYW1wbGVSZW5kZXJUYXJnZXQ7XHJcblx0dGhpcy5zZXR1cERlcHRoUmVuZGVyYnVmZmVyID0gc2V0dXBEZXB0aFJlbmRlcmJ1ZmZlcjtcclxuXHR0aGlzLnNldHVwRnJhbWVCdWZmZXJUZXh0dXJlID0gc2V0dXBGcmFtZUJ1ZmZlclRleHR1cmU7XHJcblx0dGhpcy51c2VNdWx0aXNhbXBsZWRSVFQgPSB1c2VNdWx0aXNhbXBsZWRSVFQ7XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBXZWJHTFRleHR1cmVzIH07XHJcbiIsImltcG9ydCB7IFJHQkFfQVNUQ180eDRfRm9ybWF0LCBSR0JBX0FTVENfNXg0X0Zvcm1hdCwgUkdCQV9BU1RDXzV4NV9Gb3JtYXQsIFJHQkFfQVNUQ182eDVfRm9ybWF0LCBSR0JBX0FTVENfNng2X0Zvcm1hdCwgUkdCQV9BU1RDXzh4NV9Gb3JtYXQsIFJHQkFfQVNUQ184eDZfRm9ybWF0LCBSR0JBX0FTVENfOHg4X0Zvcm1hdCwgUkdCQV9BU1RDXzEweDVfRm9ybWF0LCBSR0JBX0FTVENfMTB4Nl9Gb3JtYXQsIFJHQkFfQVNUQ18xMHg4X0Zvcm1hdCwgUkdCQV9BU1RDXzEweDEwX0Zvcm1hdCwgUkdCQV9BU1RDXzEyeDEwX0Zvcm1hdCwgUkdCQV9BU1RDXzEyeDEyX0Zvcm1hdCwgUkdCX0VUQzFfRm9ybWF0LCBSR0JfRVRDMl9Gb3JtYXQsIFJHQkFfRVRDMl9FQUNfRm9ybWF0LCBSR0JBX1BWUlRDXzJCUFBWMV9Gb3JtYXQsIFJHQkFfUFZSVENfNEJQUFYxX0Zvcm1hdCwgUkdCX1BWUlRDXzJCUFBWMV9Gb3JtYXQsIFJHQl9QVlJUQ180QlBQVjFfRm9ybWF0LCBSR0JBX1MzVENfRFhUNV9Gb3JtYXQsIFJHQkFfUzNUQ19EWFQzX0Zvcm1hdCwgUkdCQV9TM1RDX0RYVDFfRm9ybWF0LCBSR0JfUzNUQ19EWFQxX0Zvcm1hdCwgRGVwdGhGb3JtYXQsIERlcHRoU3RlbmNpbEZvcm1hdCwgTHVtaW5hbmNlQWxwaGFGb3JtYXQsIEx1bWluYW5jZUZvcm1hdCwgUmVkRm9ybWF0LCBSR0JBRm9ybWF0LCBBbHBoYUZvcm1hdCwgUmVkSW50ZWdlckZvcm1hdCwgUkdGb3JtYXQsIFJHSW50ZWdlckZvcm1hdCwgUkdCQUludGVnZXJGb3JtYXQsIEhhbGZGbG9hdFR5cGUsIEZsb2F0VHlwZSwgVW5zaWduZWRJbnRUeXBlLCBJbnRUeXBlLCBVbnNpZ25lZFNob3J0VHlwZSwgU2hvcnRUeXBlLCBCeXRlVHlwZSwgVW5zaWduZWRJbnQyNDhUeXBlLCBVbnNpZ25lZFNob3J0NTU1MVR5cGUsIFVuc2lnbmVkU2hvcnQ0NDQ0VHlwZSwgVW5zaWduZWRCeXRlVHlwZSwgUkdCQV9CUFRDX0Zvcm1hdCwgUkdCX0JQVENfU0lHTkVEX0Zvcm1hdCwgUkdCX0JQVENfVU5TSUdORURfRm9ybWF0LCBfU1JHQkFGb3JtYXQsIFJFRF9SR1RDMV9Gb3JtYXQsIFNJR05FRF9SRURfUkdUQzFfRm9ybWF0LCBSRURfR1JFRU5fUkdUQzJfRm9ybWF0LCBTSUdORURfUkVEX0dSRUVOX1JHVEMyX0Zvcm1hdCwgTm9Db2xvclNwYWNlLCBTUkdCVHJhbnNmZXIgfSBmcm9tICcuLi8uLi9jb25zdGFudHMuanMnO1xyXG5pbXBvcnQgeyBDb2xvck1hbmFnZW1lbnQgfSBmcm9tICcuLi8uLi9tYXRoL0NvbG9yTWFuYWdlbWVudC5qcyc7XHJcblxyXG5mdW5jdGlvbiBXZWJHTFV0aWxzKCBnbCwgZXh0ZW5zaW9ucywgY2FwYWJpbGl0aWVzICkge1xyXG5cclxuXHRjb25zdCBpc1dlYkdMMiA9IGNhcGFiaWxpdGllcy5pc1dlYkdMMjtcclxuXHJcblx0ZnVuY3Rpb24gY29udmVydCggcCwgY29sb3JTcGFjZSA9IE5vQ29sb3JTcGFjZSApIHtcclxuXHJcblx0XHRsZXQgZXh0ZW5zaW9uO1xyXG5cclxuXHRcdGNvbnN0IHRyYW5zZmVyID0gQ29sb3JNYW5hZ2VtZW50LmdldFRyYW5zZmVyKCBjb2xvclNwYWNlICk7XHJcblxyXG5cdFx0aWYgKCBwID09PSBVbnNpZ25lZEJ5dGVUeXBlICkgcmV0dXJuIGdsLlVOU0lHTkVEX0JZVEU7XHJcblx0XHRpZiAoIHAgPT09IFVuc2lnbmVkU2hvcnQ0NDQ0VHlwZSApIHJldHVybiBnbC5VTlNJR05FRF9TSE9SVF80XzRfNF80O1xyXG5cdFx0aWYgKCBwID09PSBVbnNpZ25lZFNob3J0NTU1MVR5cGUgKSByZXR1cm4gZ2wuVU5TSUdORURfU0hPUlRfNV81XzVfMTtcclxuXHJcblx0XHRpZiAoIHAgPT09IEJ5dGVUeXBlICkgcmV0dXJuIGdsLkJZVEU7XHJcblx0XHRpZiAoIHAgPT09IFNob3J0VHlwZSApIHJldHVybiBnbC5TSE9SVDtcclxuXHRcdGlmICggcCA9PT0gVW5zaWduZWRTaG9ydFR5cGUgKSByZXR1cm4gZ2wuVU5TSUdORURfU0hPUlQ7XHJcblx0XHRpZiAoIHAgPT09IEludFR5cGUgKSByZXR1cm4gZ2wuSU5UO1xyXG5cdFx0aWYgKCBwID09PSBVbnNpZ25lZEludFR5cGUgKSByZXR1cm4gZ2wuVU5TSUdORURfSU5UO1xyXG5cdFx0aWYgKCBwID09PSBGbG9hdFR5cGUgKSByZXR1cm4gZ2wuRkxPQVQ7XHJcblxyXG5cdFx0aWYgKCBwID09PSBIYWxmRmxvYXRUeXBlICkge1xyXG5cclxuXHRcdFx0aWYgKCBpc1dlYkdMMiApIHJldHVybiBnbC5IQUxGX0ZMT0FUO1xyXG5cclxuXHRcdFx0ZXh0ZW5zaW9uID0gZXh0ZW5zaW9ucy5nZXQoICdPRVNfdGV4dHVyZV9oYWxmX2Zsb2F0JyApO1xyXG5cclxuXHRcdFx0aWYgKCBleHRlbnNpb24gIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdHJldHVybiBleHRlbnNpb24uSEFMRl9GTE9BVF9PRVM7XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRyZXR1cm4gbnVsbDtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBwID09PSBBbHBoYUZvcm1hdCApIHJldHVybiBnbC5BTFBIQTtcclxuXHRcdGlmICggcCA9PT0gUkdCQUZvcm1hdCApIHJldHVybiBnbC5SR0JBO1xyXG5cdFx0aWYgKCBwID09PSBMdW1pbmFuY2VGb3JtYXQgKSByZXR1cm4gZ2wuTFVNSU5BTkNFO1xyXG5cdFx0aWYgKCBwID09PSBMdW1pbmFuY2VBbHBoYUZvcm1hdCApIHJldHVybiBnbC5MVU1JTkFOQ0VfQUxQSEE7XHJcblx0XHRpZiAoIHAgPT09IERlcHRoRm9ybWF0ICkgcmV0dXJuIGdsLkRFUFRIX0NPTVBPTkVOVDtcclxuXHRcdGlmICggcCA9PT0gRGVwdGhTdGVuY2lsRm9ybWF0ICkgcmV0dXJuIGdsLkRFUFRIX1NURU5DSUw7XHJcblxyXG5cdFx0Ly8gV2ViR0wgMSBzUkdCIGZhbGxiYWNrXHJcblxyXG5cdFx0aWYgKCBwID09PSBfU1JHQkFGb3JtYXQgKSB7XHJcblxyXG5cdFx0XHRleHRlbnNpb24gPSBleHRlbnNpb25zLmdldCggJ0VYVF9zUkdCJyApO1xyXG5cclxuXHRcdFx0aWYgKCBleHRlbnNpb24gIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdHJldHVybiBleHRlbnNpb24uU1JHQl9BTFBIQV9FWFQ7XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRyZXR1cm4gbnVsbDtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gV2ViR0wyIGZvcm1hdHMuXHJcblxyXG5cdFx0aWYgKCBwID09PSBSZWRGb3JtYXQgKSByZXR1cm4gZ2wuUkVEO1xyXG5cdFx0aWYgKCBwID09PSBSZWRJbnRlZ2VyRm9ybWF0ICkgcmV0dXJuIGdsLlJFRF9JTlRFR0VSO1xyXG5cdFx0aWYgKCBwID09PSBSR0Zvcm1hdCApIHJldHVybiBnbC5SRztcclxuXHRcdGlmICggcCA9PT0gUkdJbnRlZ2VyRm9ybWF0ICkgcmV0dXJuIGdsLlJHX0lOVEVHRVI7XHJcblx0XHRpZiAoIHAgPT09IFJHQkFJbnRlZ2VyRm9ybWF0ICkgcmV0dXJuIGdsLlJHQkFfSU5URUdFUjtcclxuXHJcblx0XHQvLyBTM1RDXHJcblxyXG5cdFx0aWYgKCBwID09PSBSR0JfUzNUQ19EWFQxX0Zvcm1hdCB8fCBwID09PSBSR0JBX1MzVENfRFhUMV9Gb3JtYXQgfHwgcCA9PT0gUkdCQV9TM1RDX0RYVDNfRm9ybWF0IHx8IHAgPT09IFJHQkFfUzNUQ19EWFQ1X0Zvcm1hdCApIHtcclxuXHJcblx0XHRcdGlmICggdHJhbnNmZXIgPT09IFNSR0JUcmFuc2ZlciApIHtcclxuXHJcblx0XHRcdFx0ZXh0ZW5zaW9uID0gZXh0ZW5zaW9ucy5nZXQoICdXRUJHTF9jb21wcmVzc2VkX3RleHR1cmVfczN0Y19zcmdiJyApO1xyXG5cclxuXHRcdFx0XHRpZiAoIGV4dGVuc2lvbiAhPT0gbnVsbCApIHtcclxuXHJcblx0XHRcdFx0XHRpZiAoIHAgPT09IFJHQl9TM1RDX0RYVDFfRm9ybWF0ICkgcmV0dXJuIGV4dGVuc2lvbi5DT01QUkVTU0VEX1NSR0JfUzNUQ19EWFQxX0VYVDtcclxuXHRcdFx0XHRcdGlmICggcCA9PT0gUkdCQV9TM1RDX0RYVDFfRm9ybWF0ICkgcmV0dXJuIGV4dGVuc2lvbi5DT01QUkVTU0VEX1NSR0JfQUxQSEFfUzNUQ19EWFQxX0VYVDtcclxuXHRcdFx0XHRcdGlmICggcCA9PT0gUkdCQV9TM1RDX0RYVDNfRm9ybWF0ICkgcmV0dXJuIGV4dGVuc2lvbi5DT01QUkVTU0VEX1NSR0JfQUxQSEFfUzNUQ19EWFQzX0VYVDtcclxuXHRcdFx0XHRcdGlmICggcCA9PT0gUkdCQV9TM1RDX0RYVDVfRm9ybWF0ICkgcmV0dXJuIGV4dGVuc2lvbi5DT01QUkVTU0VEX1NSR0JfQUxQSEFfUzNUQ19EWFQ1X0VYVDtcclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRyZXR1cm4gbnVsbDtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0ZXh0ZW5zaW9uID0gZXh0ZW5zaW9ucy5nZXQoICdXRUJHTF9jb21wcmVzc2VkX3RleHR1cmVfczN0YycgKTtcclxuXHJcblx0XHRcdFx0aWYgKCBleHRlbnNpb24gIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCBwID09PSBSR0JfUzNUQ19EWFQxX0Zvcm1hdCApIHJldHVybiBleHRlbnNpb24uQ09NUFJFU1NFRF9SR0JfUzNUQ19EWFQxX0VYVDtcclxuXHRcdFx0XHRcdGlmICggcCA9PT0gUkdCQV9TM1RDX0RYVDFfRm9ybWF0ICkgcmV0dXJuIGV4dGVuc2lvbi5DT01QUkVTU0VEX1JHQkFfUzNUQ19EWFQxX0VYVDtcclxuXHRcdFx0XHRcdGlmICggcCA9PT0gUkdCQV9TM1RDX0RYVDNfRm9ybWF0ICkgcmV0dXJuIGV4dGVuc2lvbi5DT01QUkVTU0VEX1JHQkFfUzNUQ19EWFQzX0VYVDtcclxuXHRcdFx0XHRcdGlmICggcCA9PT0gUkdCQV9TM1RDX0RYVDVfRm9ybWF0ICkgcmV0dXJuIGV4dGVuc2lvbi5DT01QUkVTU0VEX1JHQkFfUzNUQ19EWFQ1X0VYVDtcclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRyZXR1cm4gbnVsbDtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvLyBQVlJUQ1xyXG5cclxuXHRcdGlmICggcCA9PT0gUkdCX1BWUlRDXzRCUFBWMV9Gb3JtYXQgfHwgcCA9PT0gUkdCX1BWUlRDXzJCUFBWMV9Gb3JtYXQgfHwgcCA9PT0gUkdCQV9QVlJUQ180QlBQVjFfRm9ybWF0IHx8IHAgPT09IFJHQkFfUFZSVENfMkJQUFYxX0Zvcm1hdCApIHtcclxuXHJcblx0XHRcdGV4dGVuc2lvbiA9IGV4dGVuc2lvbnMuZ2V0KCAnV0VCR0xfY29tcHJlc3NlZF90ZXh0dXJlX3B2cnRjJyApO1xyXG5cclxuXHRcdFx0aWYgKCBleHRlbnNpb24gIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdGlmICggcCA9PT0gUkdCX1BWUlRDXzRCUFBWMV9Gb3JtYXQgKSByZXR1cm4gZXh0ZW5zaW9uLkNPTVBSRVNTRURfUkdCX1BWUlRDXzRCUFBWMV9JTUc7XHJcblx0XHRcdFx0aWYgKCBwID09PSBSR0JfUFZSVENfMkJQUFYxX0Zvcm1hdCApIHJldHVybiBleHRlbnNpb24uQ09NUFJFU1NFRF9SR0JfUFZSVENfMkJQUFYxX0lNRztcclxuXHRcdFx0XHRpZiAoIHAgPT09IFJHQkFfUFZSVENfNEJQUFYxX0Zvcm1hdCApIHJldHVybiBleHRlbnNpb24uQ09NUFJFU1NFRF9SR0JBX1BWUlRDXzRCUFBWMV9JTUc7XHJcblx0XHRcdFx0aWYgKCBwID09PSBSR0JBX1BWUlRDXzJCUFBWMV9Gb3JtYXQgKSByZXR1cm4gZXh0ZW5zaW9uLkNPTVBSRVNTRURfUkdCQV9QVlJUQ18yQlBQVjFfSU1HO1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0cmV0dXJuIG51bGw7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIEVUQzFcclxuXHJcblx0XHRpZiAoIHAgPT09IFJHQl9FVEMxX0Zvcm1hdCApIHtcclxuXHJcblx0XHRcdGV4dGVuc2lvbiA9IGV4dGVuc2lvbnMuZ2V0KCAnV0VCR0xfY29tcHJlc3NlZF90ZXh0dXJlX2V0YzEnICk7XHJcblxyXG5cdFx0XHRpZiAoIGV4dGVuc2lvbiAhPT0gbnVsbCApIHtcclxuXHJcblx0XHRcdFx0cmV0dXJuIGV4dGVuc2lvbi5DT01QUkVTU0VEX1JHQl9FVEMxX1dFQkdMO1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0cmV0dXJuIG51bGw7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIEVUQzJcclxuXHJcblx0XHRpZiAoIHAgPT09IFJHQl9FVEMyX0Zvcm1hdCB8fCBwID09PSBSR0JBX0VUQzJfRUFDX0Zvcm1hdCApIHtcclxuXHJcblx0XHRcdGV4dGVuc2lvbiA9IGV4dGVuc2lvbnMuZ2V0KCAnV0VCR0xfY29tcHJlc3NlZF90ZXh0dXJlX2V0YycgKTtcclxuXHJcblx0XHRcdGlmICggZXh0ZW5zaW9uICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0XHRpZiAoIHAgPT09IFJHQl9FVEMyX0Zvcm1hdCApIHJldHVybiAoIHRyYW5zZmVyID09PSBTUkdCVHJhbnNmZXIgKSA/IGV4dGVuc2lvbi5DT01QUkVTU0VEX1NSR0I4X0VUQzIgOiBleHRlbnNpb24uQ09NUFJFU1NFRF9SR0I4X0VUQzI7XHJcblx0XHRcdFx0aWYgKCBwID09PSBSR0JBX0VUQzJfRUFDX0Zvcm1hdCApIHJldHVybiAoIHRyYW5zZmVyID09PSBTUkdCVHJhbnNmZXIgKSA/IGV4dGVuc2lvbi5DT01QUkVTU0VEX1NSR0I4X0FMUEhBOF9FVEMyX0VBQyA6IGV4dGVuc2lvbi5DT01QUkVTU0VEX1JHQkE4X0VUQzJfRUFDO1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0cmV0dXJuIG51bGw7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIEFTVENcclxuXHJcblx0XHRpZiAoIHAgPT09IFJHQkFfQVNUQ180eDRfRm9ybWF0IHx8IHAgPT09IFJHQkFfQVNUQ181eDRfRm9ybWF0IHx8IHAgPT09IFJHQkFfQVNUQ181eDVfRm9ybWF0IHx8XHJcblx0XHRcdHAgPT09IFJHQkFfQVNUQ182eDVfRm9ybWF0IHx8IHAgPT09IFJHQkFfQVNUQ182eDZfRm9ybWF0IHx8IHAgPT09IFJHQkFfQVNUQ184eDVfRm9ybWF0IHx8XHJcblx0XHRcdHAgPT09IFJHQkFfQVNUQ184eDZfRm9ybWF0IHx8IHAgPT09IFJHQkFfQVNUQ184eDhfRm9ybWF0IHx8IHAgPT09IFJHQkFfQVNUQ18xMHg1X0Zvcm1hdCB8fFxyXG5cdFx0XHRwID09PSBSR0JBX0FTVENfMTB4Nl9Gb3JtYXQgfHwgcCA9PT0gUkdCQV9BU1RDXzEweDhfRm9ybWF0IHx8IHAgPT09IFJHQkFfQVNUQ18xMHgxMF9Gb3JtYXQgfHxcclxuXHRcdFx0cCA9PT0gUkdCQV9BU1RDXzEyeDEwX0Zvcm1hdCB8fCBwID09PSBSR0JBX0FTVENfMTJ4MTJfRm9ybWF0ICkge1xyXG5cclxuXHRcdFx0ZXh0ZW5zaW9uID0gZXh0ZW5zaW9ucy5nZXQoICdXRUJHTF9jb21wcmVzc2VkX3RleHR1cmVfYXN0YycgKTtcclxuXHJcblx0XHRcdGlmICggZXh0ZW5zaW9uICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0XHRpZiAoIHAgPT09IFJHQkFfQVNUQ180eDRfRm9ybWF0ICkgcmV0dXJuICggdHJhbnNmZXIgPT09IFNSR0JUcmFuc2ZlciApID8gZXh0ZW5zaW9uLkNPTVBSRVNTRURfU1JHQjhfQUxQSEE4X0FTVENfNHg0X0tIUiA6IGV4dGVuc2lvbi5DT01QUkVTU0VEX1JHQkFfQVNUQ180eDRfS0hSO1xyXG5cdFx0XHRcdGlmICggcCA9PT0gUkdCQV9BU1RDXzV4NF9Gb3JtYXQgKSByZXR1cm4gKCB0cmFuc2ZlciA9PT0gU1JHQlRyYW5zZmVyICkgPyBleHRlbnNpb24uQ09NUFJFU1NFRF9TUkdCOF9BTFBIQThfQVNUQ181eDRfS0hSIDogZXh0ZW5zaW9uLkNPTVBSRVNTRURfUkdCQV9BU1RDXzV4NF9LSFI7XHJcblx0XHRcdFx0aWYgKCBwID09PSBSR0JBX0FTVENfNXg1X0Zvcm1hdCApIHJldHVybiAoIHRyYW5zZmVyID09PSBTUkdCVHJhbnNmZXIgKSA/IGV4dGVuc2lvbi5DT01QUkVTU0VEX1NSR0I4X0FMUEhBOF9BU1RDXzV4NV9LSFIgOiBleHRlbnNpb24uQ09NUFJFU1NFRF9SR0JBX0FTVENfNXg1X0tIUjtcclxuXHRcdFx0XHRpZiAoIHAgPT09IFJHQkFfQVNUQ182eDVfRm9ybWF0ICkgcmV0dXJuICggdHJhbnNmZXIgPT09IFNSR0JUcmFuc2ZlciApID8gZXh0ZW5zaW9uLkNPTVBSRVNTRURfU1JHQjhfQUxQSEE4X0FTVENfNng1X0tIUiA6IGV4dGVuc2lvbi5DT01QUkVTU0VEX1JHQkFfQVNUQ182eDVfS0hSO1xyXG5cdFx0XHRcdGlmICggcCA9PT0gUkdCQV9BU1RDXzZ4Nl9Gb3JtYXQgKSByZXR1cm4gKCB0cmFuc2ZlciA9PT0gU1JHQlRyYW5zZmVyICkgPyBleHRlbnNpb24uQ09NUFJFU1NFRF9TUkdCOF9BTFBIQThfQVNUQ182eDZfS0hSIDogZXh0ZW5zaW9uLkNPTVBSRVNTRURfUkdCQV9BU1RDXzZ4Nl9LSFI7XHJcblx0XHRcdFx0aWYgKCBwID09PSBSR0JBX0FTVENfOHg1X0Zvcm1hdCApIHJldHVybiAoIHRyYW5zZmVyID09PSBTUkdCVHJhbnNmZXIgKSA/IGV4dGVuc2lvbi5DT01QUkVTU0VEX1NSR0I4X0FMUEhBOF9BU1RDXzh4NV9LSFIgOiBleHRlbnNpb24uQ09NUFJFU1NFRF9SR0JBX0FTVENfOHg1X0tIUjtcclxuXHRcdFx0XHRpZiAoIHAgPT09IFJHQkFfQVNUQ184eDZfRm9ybWF0ICkgcmV0dXJuICggdHJhbnNmZXIgPT09IFNSR0JUcmFuc2ZlciApID8gZXh0ZW5zaW9uLkNPTVBSRVNTRURfU1JHQjhfQUxQSEE4X0FTVENfOHg2X0tIUiA6IGV4dGVuc2lvbi5DT01QUkVTU0VEX1JHQkFfQVNUQ184eDZfS0hSO1xyXG5cdFx0XHRcdGlmICggcCA9PT0gUkdCQV9BU1RDXzh4OF9Gb3JtYXQgKSByZXR1cm4gKCB0cmFuc2ZlciA9PT0gU1JHQlRyYW5zZmVyICkgPyBleHRlbnNpb24uQ09NUFJFU1NFRF9TUkdCOF9BTFBIQThfQVNUQ184eDhfS0hSIDogZXh0ZW5zaW9uLkNPTVBSRVNTRURfUkdCQV9BU1RDXzh4OF9LSFI7XHJcblx0XHRcdFx0aWYgKCBwID09PSBSR0JBX0FTVENfMTB4NV9Gb3JtYXQgKSByZXR1cm4gKCB0cmFuc2ZlciA9PT0gU1JHQlRyYW5zZmVyICkgPyBleHRlbnNpb24uQ09NUFJFU1NFRF9TUkdCOF9BTFBIQThfQVNUQ18xMHg1X0tIUiA6IGV4dGVuc2lvbi5DT01QUkVTU0VEX1JHQkFfQVNUQ18xMHg1X0tIUjtcclxuXHRcdFx0XHRpZiAoIHAgPT09IFJHQkFfQVNUQ18xMHg2X0Zvcm1hdCApIHJldHVybiAoIHRyYW5zZmVyID09PSBTUkdCVHJhbnNmZXIgKSA/IGV4dGVuc2lvbi5DT01QUkVTU0VEX1NSR0I4X0FMUEhBOF9BU1RDXzEweDZfS0hSIDogZXh0ZW5zaW9uLkNPTVBSRVNTRURfUkdCQV9BU1RDXzEweDZfS0hSO1xyXG5cdFx0XHRcdGlmICggcCA9PT0gUkdCQV9BU1RDXzEweDhfRm9ybWF0ICkgcmV0dXJuICggdHJhbnNmZXIgPT09IFNSR0JUcmFuc2ZlciApID8gZXh0ZW5zaW9uLkNPTVBSRVNTRURfU1JHQjhfQUxQSEE4X0FTVENfMTB4OF9LSFIgOiBleHRlbnNpb24uQ09NUFJFU1NFRF9SR0JBX0FTVENfMTB4OF9LSFI7XHJcblx0XHRcdFx0aWYgKCBwID09PSBSR0JBX0FTVENfMTB4MTBfRm9ybWF0ICkgcmV0dXJuICggdHJhbnNmZXIgPT09IFNSR0JUcmFuc2ZlciApID8gZXh0ZW5zaW9uLkNPTVBSRVNTRURfU1JHQjhfQUxQSEE4X0FTVENfMTB4MTBfS0hSIDogZXh0ZW5zaW9uLkNPTVBSRVNTRURfUkdCQV9BU1RDXzEweDEwX0tIUjtcclxuXHRcdFx0XHRpZiAoIHAgPT09IFJHQkFfQVNUQ18xMngxMF9Gb3JtYXQgKSByZXR1cm4gKCB0cmFuc2ZlciA9PT0gU1JHQlRyYW5zZmVyICkgPyBleHRlbnNpb24uQ09NUFJFU1NFRF9TUkdCOF9BTFBIQThfQVNUQ18xMngxMF9LSFIgOiBleHRlbnNpb24uQ09NUFJFU1NFRF9SR0JBX0FTVENfMTJ4MTBfS0hSO1xyXG5cdFx0XHRcdGlmICggcCA9PT0gUkdCQV9BU1RDXzEyeDEyX0Zvcm1hdCApIHJldHVybiAoIHRyYW5zZmVyID09PSBTUkdCVHJhbnNmZXIgKSA/IGV4dGVuc2lvbi5DT01QUkVTU0VEX1NSR0I4X0FMUEhBOF9BU1RDXzEyeDEyX0tIUiA6IGV4dGVuc2lvbi5DT01QUkVTU0VEX1JHQkFfQVNUQ18xMngxMl9LSFI7XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRyZXR1cm4gbnVsbDtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gQlBUQ1xyXG5cclxuXHRcdGlmICggcCA9PT0gUkdCQV9CUFRDX0Zvcm1hdCB8fCBwID09PSBSR0JfQlBUQ19TSUdORURfRm9ybWF0IHx8IHAgPT09IFJHQl9CUFRDX1VOU0lHTkVEX0Zvcm1hdCApIHtcclxuXHJcblx0XHRcdGV4dGVuc2lvbiA9IGV4dGVuc2lvbnMuZ2V0KCAnRVhUX3RleHR1cmVfY29tcHJlc3Npb25fYnB0YycgKTtcclxuXHJcblx0XHRcdGlmICggZXh0ZW5zaW9uICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0XHRpZiAoIHAgPT09IFJHQkFfQlBUQ19Gb3JtYXQgKSByZXR1cm4gKCB0cmFuc2ZlciA9PT0gU1JHQlRyYW5zZmVyICkgPyBleHRlbnNpb24uQ09NUFJFU1NFRF9TUkdCX0FMUEhBX0JQVENfVU5PUk1fRVhUIDogZXh0ZW5zaW9uLkNPTVBSRVNTRURfUkdCQV9CUFRDX1VOT1JNX0VYVDtcclxuXHRcdFx0XHRpZiAoIHAgPT09IFJHQl9CUFRDX1NJR05FRF9Gb3JtYXQgKSByZXR1cm4gZXh0ZW5zaW9uLkNPTVBSRVNTRURfUkdCX0JQVENfU0lHTkVEX0ZMT0FUX0VYVDtcclxuXHRcdFx0XHRpZiAoIHAgPT09IFJHQl9CUFRDX1VOU0lHTkVEX0Zvcm1hdCApIHJldHVybiBleHRlbnNpb24uQ09NUFJFU1NFRF9SR0JfQlBUQ19VTlNJR05FRF9GTE9BVF9FWFQ7XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRyZXR1cm4gbnVsbDtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gUkdUQ1xyXG5cclxuXHRcdGlmICggcCA9PT0gUkVEX1JHVEMxX0Zvcm1hdCB8fCBwID09PSBTSUdORURfUkVEX1JHVEMxX0Zvcm1hdCB8fCBwID09PSBSRURfR1JFRU5fUkdUQzJfRm9ybWF0IHx8IHAgPT09IFNJR05FRF9SRURfR1JFRU5fUkdUQzJfRm9ybWF0ICkge1xyXG5cclxuXHRcdFx0ZXh0ZW5zaW9uID0gZXh0ZW5zaW9ucy5nZXQoICdFWFRfdGV4dHVyZV9jb21wcmVzc2lvbl9yZ3RjJyApO1xyXG5cclxuXHRcdFx0aWYgKCBleHRlbnNpb24gIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdGlmICggcCA9PT0gUkdCQV9CUFRDX0Zvcm1hdCApIHJldHVybiBleHRlbnNpb24uQ09NUFJFU1NFRF9SRURfUkdUQzFfRVhUO1xyXG5cdFx0XHRcdGlmICggcCA9PT0gU0lHTkVEX1JFRF9SR1RDMV9Gb3JtYXQgKSByZXR1cm4gZXh0ZW5zaW9uLkNPTVBSRVNTRURfU0lHTkVEX1JFRF9SR1RDMV9FWFQ7XHJcblx0XHRcdFx0aWYgKCBwID09PSBSRURfR1JFRU5fUkdUQzJfRm9ybWF0ICkgcmV0dXJuIGV4dGVuc2lvbi5DT01QUkVTU0VEX1JFRF9HUkVFTl9SR1RDMl9FWFQ7XHJcblx0XHRcdFx0aWYgKCBwID09PSBTSUdORURfUkVEX0dSRUVOX1JHVEMyX0Zvcm1hdCApIHJldHVybiBleHRlbnNpb24uQ09NUFJFU1NFRF9TSUdORURfUkVEX0dSRUVOX1JHVEMyX0VYVDtcclxuXHJcblx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdHJldHVybiBudWxsO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvL1xyXG5cclxuXHRcdGlmICggcCA9PT0gVW5zaWduZWRJbnQyNDhUeXBlICkge1xyXG5cclxuXHRcdFx0aWYgKCBpc1dlYkdMMiApIHJldHVybiBnbC5VTlNJR05FRF9JTlRfMjRfODtcclxuXHJcblx0XHRcdGV4dGVuc2lvbiA9IGV4dGVuc2lvbnMuZ2V0KCAnV0VCR0xfZGVwdGhfdGV4dHVyZScgKTtcclxuXHJcblx0XHRcdGlmICggZXh0ZW5zaW9uICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0XHRyZXR1cm4gZXh0ZW5zaW9uLlVOU0lHTkVEX0lOVF8yNF84X1dFQkdMO1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0cmV0dXJuIG51bGw7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIGlmIFwicFwiIGNhbid0IGJlIHJlc29sdmVkLCBhc3N1bWUgdGhlIHVzZXIgZGVmaW5lcyBhIFdlYkdMIGNvbnN0YW50IGFzIGEgc3RyaW5nIChmYWxsYmFjay93b3JrYXJvdW5kIGZvciBwYWNrZWQgUkdCIGZvcm1hdHMpXHJcblxyXG5cdFx0cmV0dXJuICggZ2xbIHAgXSAhPT0gdW5kZWZpbmVkICkgPyBnbFsgcCBdIDogbnVsbDtcclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4geyBjb252ZXJ0OiBjb252ZXJ0IH07XHJcblxyXG59XHJcblxyXG5cclxuZXhwb3J0IHsgV2ViR0xVdGlscyB9O1xyXG4iLCJpbXBvcnQgeyBQZXJzcGVjdGl2ZUNhbWVyYSB9IGZyb20gJy4vUGVyc3BlY3RpdmVDYW1lcmEuanMnO1xyXG5cclxuY2xhc3MgQXJyYXlDYW1lcmEgZXh0ZW5kcyBQZXJzcGVjdGl2ZUNhbWVyYSB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBhcnJheSA9IFtdICkge1xyXG5cclxuXHRcdHN1cGVyKCk7XHJcblxyXG5cdFx0dGhpcy5pc0FycmF5Q2FtZXJhID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLmNhbWVyYXMgPSBhcnJheTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgQXJyYXlDYW1lcmEgfTtcclxuIiwiaW1wb3J0IHsgT2JqZWN0M0QgfSBmcm9tICcuLi9jb3JlL09iamVjdDNELmpzJztcclxuXHJcbmNsYXNzIEdyb3VwIGV4dGVuZHMgT2JqZWN0M0Qge1xyXG5cclxuXHRjb25zdHJ1Y3RvcigpIHtcclxuXHJcblx0XHRzdXBlcigpO1xyXG5cclxuXHRcdHRoaXMuaXNHcm91cCA9IHRydWU7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ0dyb3VwJztcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgR3JvdXAgfTtcclxuIiwiaW1wb3J0IHsgVmVjdG9yMyB9IGZyb20gJy4uLy4uL21hdGgvVmVjdG9yMy5qcyc7XHJcbmltcG9ydCB7IEdyb3VwIH0gZnJvbSAnLi4vLi4vb2JqZWN0cy9Hcm91cC5qcyc7XHJcblxyXG5jb25zdCBfbW92ZUV2ZW50ID0geyB0eXBlOiAnbW92ZScgfTtcclxuXHJcbmNsYXNzIFdlYlhSQ29udHJvbGxlciB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCkge1xyXG5cclxuXHRcdHRoaXMuX3RhcmdldFJheSA9IG51bGw7XHJcblx0XHR0aGlzLl9ncmlwID0gbnVsbDtcclxuXHRcdHRoaXMuX2hhbmQgPSBudWxsO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldEhhbmRTcGFjZSgpIHtcclxuXHJcblx0XHRpZiAoIHRoaXMuX2hhbmQgPT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHR0aGlzLl9oYW5kID0gbmV3IEdyb3VwKCk7XHJcblx0XHRcdHRoaXMuX2hhbmQubWF0cml4QXV0b1VwZGF0ZSA9IGZhbHNlO1xyXG5cdFx0XHR0aGlzLl9oYW5kLnZpc2libGUgPSBmYWxzZTtcclxuXHJcblx0XHRcdHRoaXMuX2hhbmQuam9pbnRzID0ge307XHJcblx0XHRcdHRoaXMuX2hhbmQuaW5wdXRTdGF0ZSA9IHsgcGluY2hpbmc6IGZhbHNlIH07XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzLl9oYW5kO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldFRhcmdldFJheVNwYWNlKCkge1xyXG5cclxuXHRcdGlmICggdGhpcy5fdGFyZ2V0UmF5ID09PSBudWxsICkge1xyXG5cclxuXHRcdFx0dGhpcy5fdGFyZ2V0UmF5ID0gbmV3IEdyb3VwKCk7XHJcblx0XHRcdHRoaXMuX3RhcmdldFJheS5tYXRyaXhBdXRvVXBkYXRlID0gZmFsc2U7XHJcblx0XHRcdHRoaXMuX3RhcmdldFJheS52aXNpYmxlID0gZmFsc2U7XHJcblx0XHRcdHRoaXMuX3RhcmdldFJheS5oYXNMaW5lYXJWZWxvY2l0eSA9IGZhbHNlO1xyXG5cdFx0XHR0aGlzLl90YXJnZXRSYXkubGluZWFyVmVsb2NpdHkgPSBuZXcgVmVjdG9yMygpO1xyXG5cdFx0XHR0aGlzLl90YXJnZXRSYXkuaGFzQW5ndWxhclZlbG9jaXR5ID0gZmFsc2U7XHJcblx0XHRcdHRoaXMuX3RhcmdldFJheS5hbmd1bGFyVmVsb2NpdHkgPSBuZXcgVmVjdG9yMygpO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcy5fdGFyZ2V0UmF5O1xyXG5cclxuXHR9XHJcblxyXG5cdGdldEdyaXBTcGFjZSgpIHtcclxuXHJcblx0XHRpZiAoIHRoaXMuX2dyaXAgPT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHR0aGlzLl9ncmlwID0gbmV3IEdyb3VwKCk7XHJcblx0XHRcdHRoaXMuX2dyaXAubWF0cml4QXV0b1VwZGF0ZSA9IGZhbHNlO1xyXG5cdFx0XHR0aGlzLl9ncmlwLnZpc2libGUgPSBmYWxzZTtcclxuXHRcdFx0dGhpcy5fZ3JpcC5oYXNMaW5lYXJWZWxvY2l0eSA9IGZhbHNlO1xyXG5cdFx0XHR0aGlzLl9ncmlwLmxpbmVhclZlbG9jaXR5ID0gbmV3IFZlY3RvcjMoKTtcclxuXHRcdFx0dGhpcy5fZ3JpcC5oYXNBbmd1bGFyVmVsb2NpdHkgPSBmYWxzZTtcclxuXHRcdFx0dGhpcy5fZ3JpcC5hbmd1bGFyVmVsb2NpdHkgPSBuZXcgVmVjdG9yMygpO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcy5fZ3JpcDtcclxuXHJcblx0fVxyXG5cclxuXHRkaXNwYXRjaEV2ZW50KCBldmVudCApIHtcclxuXHJcblx0XHRpZiAoIHRoaXMuX3RhcmdldFJheSAhPT0gbnVsbCApIHtcclxuXHJcblx0XHRcdHRoaXMuX3RhcmdldFJheS5kaXNwYXRjaEV2ZW50KCBldmVudCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHRoaXMuX2dyaXAgIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHR0aGlzLl9ncmlwLmRpc3BhdGNoRXZlbnQoIGV2ZW50ICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggdGhpcy5faGFuZCAhPT0gbnVsbCApIHtcclxuXHJcblx0XHRcdHRoaXMuX2hhbmQuZGlzcGF0Y2hFdmVudCggZXZlbnQgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Y29ubmVjdCggaW5wdXRTb3VyY2UgKSB7XHJcblxyXG5cdFx0aWYgKCBpbnB1dFNvdXJjZSAmJiBpbnB1dFNvdXJjZS5oYW5kICkge1xyXG5cclxuXHRcdFx0Y29uc3QgaGFuZCA9IHRoaXMuX2hhbmQ7XHJcblxyXG5cdFx0XHRpZiAoIGhhbmQgKSB7XHJcblxyXG5cdFx0XHRcdGZvciAoIGNvbnN0IGlucHV0am9pbnQgb2YgaW5wdXRTb3VyY2UuaGFuZC52YWx1ZXMoKSApIHtcclxuXHJcblx0XHRcdFx0XHQvLyBJbml0aWFsaXplIGhhbmQgd2l0aCBqb2ludHMgd2hlbiBjb25uZWN0ZWRcclxuXHRcdFx0XHRcdHRoaXMuX2dldEhhbmRKb2ludCggaGFuZCwgaW5wdXRqb2ludCApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMuZGlzcGF0Y2hFdmVudCggeyB0eXBlOiAnY29ubmVjdGVkJywgZGF0YTogaW5wdXRTb3VyY2UgfSApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGRpc2Nvbm5lY3QoIGlucHV0U291cmNlICkge1xyXG5cclxuXHRcdHRoaXMuZGlzcGF0Y2hFdmVudCggeyB0eXBlOiAnZGlzY29ubmVjdGVkJywgZGF0YTogaW5wdXRTb3VyY2UgfSApO1xyXG5cclxuXHRcdGlmICggdGhpcy5fdGFyZ2V0UmF5ICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0dGhpcy5fdGFyZ2V0UmF5LnZpc2libGUgPSBmYWxzZTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCB0aGlzLl9ncmlwICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0dGhpcy5fZ3JpcC52aXNpYmxlID0gZmFsc2U7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggdGhpcy5faGFuZCAhPT0gbnVsbCApIHtcclxuXHJcblx0XHRcdHRoaXMuX2hhbmQudmlzaWJsZSA9IGZhbHNlO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHR1cGRhdGUoIGlucHV0U291cmNlLCBmcmFtZSwgcmVmZXJlbmNlU3BhY2UgKSB7XHJcblxyXG5cdFx0bGV0IGlucHV0UG9zZSA9IG51bGw7XHJcblx0XHRsZXQgZ3JpcFBvc2UgPSBudWxsO1xyXG5cdFx0bGV0IGhhbmRQb3NlID0gbnVsbDtcclxuXHJcblx0XHRjb25zdCB0YXJnZXRSYXkgPSB0aGlzLl90YXJnZXRSYXk7XHJcblx0XHRjb25zdCBncmlwID0gdGhpcy5fZ3JpcDtcclxuXHRcdGNvbnN0IGhhbmQgPSB0aGlzLl9oYW5kO1xyXG5cclxuXHRcdGlmICggaW5wdXRTb3VyY2UgJiYgZnJhbWUuc2Vzc2lvbi52aXNpYmlsaXR5U3RhdGUgIT09ICd2aXNpYmxlLWJsdXJyZWQnICkge1xyXG5cclxuXHRcdFx0aWYgKCBoYW5kICYmIGlucHV0U291cmNlLmhhbmQgKSB7XHJcblxyXG5cdFx0XHRcdGhhbmRQb3NlID0gdHJ1ZTtcclxuXHJcblx0XHRcdFx0Zm9yICggY29uc3QgaW5wdXRqb2ludCBvZiBpbnB1dFNvdXJjZS5oYW5kLnZhbHVlcygpICkge1xyXG5cclxuXHRcdFx0XHRcdC8vIFVwZGF0ZSB0aGUgam9pbnRzIGdyb3VwcyB3aXRoIHRoZSBYUkpvaW50IHBvc2VzXHJcblx0XHRcdFx0XHRjb25zdCBqb2ludFBvc2UgPSBmcmFtZS5nZXRKb2ludFBvc2UoIGlucHV0am9pbnQsIHJlZmVyZW5jZVNwYWNlICk7XHJcblxyXG5cdFx0XHRcdFx0Ly8gVGhlIHRyYW5zZm9ybSBvZiB0aGlzIGpvaW50IHdpbGwgYmUgdXBkYXRlZCB3aXRoIHRoZSBqb2ludCBwb3NlIG9uIGVhY2ggZnJhbWVcclxuXHRcdFx0XHRcdGNvbnN0IGpvaW50ID0gdGhpcy5fZ2V0SGFuZEpvaW50KCBoYW5kLCBpbnB1dGpvaW50ICk7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCBqb2ludFBvc2UgIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRqb2ludC5tYXRyaXguZnJvbUFycmF5KCBqb2ludFBvc2UudHJhbnNmb3JtLm1hdHJpeCApO1xyXG5cdFx0XHRcdFx0XHRqb2ludC5tYXRyaXguZGVjb21wb3NlKCBqb2ludC5wb3NpdGlvbiwgam9pbnQucm90YXRpb24sIGpvaW50LnNjYWxlICk7XHJcblx0XHRcdFx0XHRcdGpvaW50Lm1hdHJpeFdvcmxkTmVlZHNVcGRhdGUgPSB0cnVlO1xyXG5cdFx0XHRcdFx0XHRqb2ludC5qb2ludFJhZGl1cyA9IGpvaW50UG9zZS5yYWRpdXM7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdGpvaW50LnZpc2libGUgPSBqb2ludFBvc2UgIT09IG51bGw7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0Ly8gQ3VzdG9tIGV2ZW50c1xyXG5cclxuXHRcdFx0XHQvLyBDaGVjayBwaW5jaHpcclxuXHRcdFx0XHRjb25zdCBpbmRleFRpcCA9IGhhbmQuam9pbnRzWyAnaW5kZXgtZmluZ2VyLXRpcCcgXTtcclxuXHRcdFx0XHRjb25zdCB0aHVtYlRpcCA9IGhhbmQuam9pbnRzWyAndGh1bWItdGlwJyBdO1xyXG5cdFx0XHRcdGNvbnN0IGRpc3RhbmNlID0gaW5kZXhUaXAucG9zaXRpb24uZGlzdGFuY2VUbyggdGh1bWJUaXAucG9zaXRpb24gKTtcclxuXHJcblx0XHRcdFx0Y29uc3QgZGlzdGFuY2VUb1BpbmNoID0gMC4wMjtcclxuXHRcdFx0XHRjb25zdCB0aHJlc2hvbGQgPSAwLjAwNTtcclxuXHJcblx0XHRcdFx0aWYgKCBoYW5kLmlucHV0U3RhdGUucGluY2hpbmcgJiYgZGlzdGFuY2UgPiBkaXN0YW5jZVRvUGluY2ggKyB0aHJlc2hvbGQgKSB7XHJcblxyXG5cdFx0XHRcdFx0aGFuZC5pbnB1dFN0YXRlLnBpbmNoaW5nID0gZmFsc2U7XHJcblx0XHRcdFx0XHR0aGlzLmRpc3BhdGNoRXZlbnQoIHtcclxuXHRcdFx0XHRcdFx0dHlwZTogJ3BpbmNoZW5kJyxcclxuXHRcdFx0XHRcdFx0aGFuZGVkbmVzczogaW5wdXRTb3VyY2UuaGFuZGVkbmVzcyxcclxuXHRcdFx0XHRcdFx0dGFyZ2V0OiB0aGlzXHJcblx0XHRcdFx0XHR9ICk7XHJcblxyXG5cdFx0XHRcdH0gZWxzZSBpZiAoICEgaGFuZC5pbnB1dFN0YXRlLnBpbmNoaW5nICYmIGRpc3RhbmNlIDw9IGRpc3RhbmNlVG9QaW5jaCAtIHRocmVzaG9sZCApIHtcclxuXHJcblx0XHRcdFx0XHRoYW5kLmlucHV0U3RhdGUucGluY2hpbmcgPSB0cnVlO1xyXG5cdFx0XHRcdFx0dGhpcy5kaXNwYXRjaEV2ZW50KCB7XHJcblx0XHRcdFx0XHRcdHR5cGU6ICdwaW5jaHN0YXJ0JyxcclxuXHRcdFx0XHRcdFx0aGFuZGVkbmVzczogaW5wdXRTb3VyY2UuaGFuZGVkbmVzcyxcclxuXHRcdFx0XHRcdFx0dGFyZ2V0OiB0aGlzXHJcblx0XHRcdFx0XHR9ICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdGlmICggZ3JpcCAhPT0gbnVsbCAmJiBpbnB1dFNvdXJjZS5ncmlwU3BhY2UgKSB7XHJcblxyXG5cdFx0XHRcdFx0Z3JpcFBvc2UgPSBmcmFtZS5nZXRQb3NlKCBpbnB1dFNvdXJjZS5ncmlwU3BhY2UsIHJlZmVyZW5jZVNwYWNlICk7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCBncmlwUG9zZSAhPT0gbnVsbCApIHtcclxuXHJcblx0XHRcdFx0XHRcdGdyaXAubWF0cml4LmZyb21BcnJheSggZ3JpcFBvc2UudHJhbnNmb3JtLm1hdHJpeCApO1xyXG5cdFx0XHRcdFx0XHRncmlwLm1hdHJpeC5kZWNvbXBvc2UoIGdyaXAucG9zaXRpb24sIGdyaXAucm90YXRpb24sIGdyaXAuc2NhbGUgKTtcclxuXHRcdFx0XHRcdFx0Z3JpcC5tYXRyaXhXb3JsZE5lZWRzVXBkYXRlID0gdHJ1ZTtcclxuXHJcblx0XHRcdFx0XHRcdGlmICggZ3JpcFBvc2UubGluZWFyVmVsb2NpdHkgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdGdyaXAuaGFzTGluZWFyVmVsb2NpdHkgPSB0cnVlO1xyXG5cdFx0XHRcdFx0XHRcdGdyaXAubGluZWFyVmVsb2NpdHkuY29weSggZ3JpcFBvc2UubGluZWFyVmVsb2NpdHkgKTtcclxuXHJcblx0XHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdGdyaXAuaGFzTGluZWFyVmVsb2NpdHkgPSBmYWxzZTtcclxuXHJcblx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRcdGlmICggZ3JpcFBvc2UuYW5ndWxhclZlbG9jaXR5ICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRncmlwLmhhc0FuZ3VsYXJWZWxvY2l0eSA9IHRydWU7XHJcblx0XHRcdFx0XHRcdFx0Z3JpcC5hbmd1bGFyVmVsb2NpdHkuY29weSggZ3JpcFBvc2UuYW5ndWxhclZlbG9jaXR5ICk7XHJcblxyXG5cdFx0XHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRncmlwLmhhc0FuZ3VsYXJWZWxvY2l0eSA9IGZhbHNlO1xyXG5cclxuXHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0aWYgKCB0YXJnZXRSYXkgIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdGlucHV0UG9zZSA9IGZyYW1lLmdldFBvc2UoIGlucHV0U291cmNlLnRhcmdldFJheVNwYWNlLCByZWZlcmVuY2VTcGFjZSApO1xyXG5cclxuXHRcdFx0XHQvLyBTb21lIHJ1bnRpbWVzIChuYW1lbHkgVml2ZSBDb3Ntb3Mgd2l0aCBWaXZlIE9wZW5YUiBSdW50aW1lKSBoYXZlIG9ubHkgZ3JpcCBzcGFjZSBhbmQgcmF5IHNwYWNlIGlzIGVxdWFsIHRvIGl0XHJcblx0XHRcdFx0aWYgKCBpbnB1dFBvc2UgPT09IG51bGwgJiYgZ3JpcFBvc2UgIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdFx0aW5wdXRQb3NlID0gZ3JpcFBvc2U7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0aWYgKCBpbnB1dFBvc2UgIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdFx0dGFyZ2V0UmF5Lm1hdHJpeC5mcm9tQXJyYXkoIGlucHV0UG9zZS50cmFuc2Zvcm0ubWF0cml4ICk7XHJcblx0XHRcdFx0XHR0YXJnZXRSYXkubWF0cml4LmRlY29tcG9zZSggdGFyZ2V0UmF5LnBvc2l0aW9uLCB0YXJnZXRSYXkucm90YXRpb24sIHRhcmdldFJheS5zY2FsZSApO1xyXG5cdFx0XHRcdFx0dGFyZ2V0UmF5Lm1hdHJpeFdvcmxkTmVlZHNVcGRhdGUgPSB0cnVlO1xyXG5cclxuXHRcdFx0XHRcdGlmICggaW5wdXRQb3NlLmxpbmVhclZlbG9jaXR5ICkge1xyXG5cclxuXHRcdFx0XHRcdFx0dGFyZ2V0UmF5Lmhhc0xpbmVhclZlbG9jaXR5ID0gdHJ1ZTtcclxuXHRcdFx0XHRcdFx0dGFyZ2V0UmF5LmxpbmVhclZlbG9jaXR5LmNvcHkoIGlucHV0UG9zZS5saW5lYXJWZWxvY2l0eSApO1xyXG5cclxuXHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHR0YXJnZXRSYXkuaGFzTGluZWFyVmVsb2NpdHkgPSBmYWxzZTtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0aWYgKCBpbnB1dFBvc2UuYW5ndWxhclZlbG9jaXR5ICkge1xyXG5cclxuXHRcdFx0XHRcdFx0dGFyZ2V0UmF5Lmhhc0FuZ3VsYXJWZWxvY2l0eSA9IHRydWU7XHJcblx0XHRcdFx0XHRcdHRhcmdldFJheS5hbmd1bGFyVmVsb2NpdHkuY29weSggaW5wdXRQb3NlLmFuZ3VsYXJWZWxvY2l0eSApO1xyXG5cclxuXHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHR0YXJnZXRSYXkuaGFzQW5ndWxhclZlbG9jaXR5ID0gZmFsc2U7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdHRoaXMuZGlzcGF0Y2hFdmVudCggX21vdmVFdmVudCApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHRhcmdldFJheSAhPT0gbnVsbCApIHtcclxuXHJcblx0XHRcdHRhcmdldFJheS52aXNpYmxlID0gKCBpbnB1dFBvc2UgIT09IG51bGwgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBncmlwICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0Z3JpcC52aXNpYmxlID0gKCBncmlwUG9zZSAhPT0gbnVsbCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIGhhbmQgIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRoYW5kLnZpc2libGUgPSAoIGhhbmRQb3NlICE9PSBudWxsICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdC8vIHByaXZhdGUgbWV0aG9kXHJcblxyXG5cdF9nZXRIYW5kSm9pbnQoIGhhbmQsIGlucHV0am9pbnQgKSB7XHJcblxyXG5cdFx0aWYgKCBoYW5kLmpvaW50c1sgaW5wdXRqb2ludC5qb2ludE5hbWUgXSA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0Y29uc3Qgam9pbnQgPSBuZXcgR3JvdXAoKTtcclxuXHRcdFx0am9pbnQubWF0cml4QXV0b1VwZGF0ZSA9IGZhbHNlO1xyXG5cdFx0XHRqb2ludC52aXNpYmxlID0gZmFsc2U7XHJcblx0XHRcdGhhbmQuam9pbnRzWyBpbnB1dGpvaW50LmpvaW50TmFtZSBdID0gam9pbnQ7XHJcblxyXG5cdFx0XHRoYW5kLmFkZCggam9pbnQgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIGhhbmQuam9pbnRzWyBpbnB1dGpvaW50LmpvaW50TmFtZSBdO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5cclxuZXhwb3J0IHsgV2ViWFJDb250cm9sbGVyIH07XHJcbiIsImltcG9ydCB7IFBsYW5lR2VvbWV0cnkgfSBmcm9tICcuLi8uLi9nZW9tZXRyaWVzL1BsYW5lR2VvbWV0cnkuanMnO1xyXG5pbXBvcnQgeyBTaGFkZXJNYXRlcmlhbCB9IGZyb20gJy4uLy4uL21hdGVyaWFscy9TaGFkZXJNYXRlcmlhbC5qcyc7XHJcbmltcG9ydCB7IE1lc2ggfSBmcm9tICcuLi8uLi9vYmplY3RzL01lc2guanMnO1xyXG5pbXBvcnQgeyBUZXh0dXJlIH0gZnJvbSAnLi4vLi4vdGV4dHVyZXMvVGV4dHVyZS5qcyc7XHJcblxyXG5jb25zdCBfb2NjbHVzaW9uX3ZlcnRleCA9IGBcclxudm9pZCBtYWluKCkge1xyXG5cclxuXHRnbF9Qb3NpdGlvbiA9IHZlYzQoIHBvc2l0aW9uLCAxLjAgKTtcclxuXHJcbn1gO1xyXG5cclxuY29uc3QgX29jY2x1c2lvbl9mcmFnbWVudCA9IGBcclxudW5pZm9ybSBzYW1wbGVyMkRBcnJheSBkZXB0aENvbG9yO1xyXG51bmlmb3JtIGZsb2F0IGRlcHRoV2lkdGg7XHJcbnVuaWZvcm0gZmxvYXQgZGVwdGhIZWlnaHQ7XHJcblxyXG52b2lkIG1haW4oKSB7XHJcblxyXG5cdHZlYzIgY29vcmQgPSB2ZWMyKCBnbF9GcmFnQ29vcmQueCAvIGRlcHRoV2lkdGgsIGdsX0ZyYWdDb29yZC55IC8gZGVwdGhIZWlnaHQgKTtcclxuXHJcblx0aWYgKCBjb29yZC54ID49IDEuMCApIHtcclxuXHJcblx0XHRnbF9GcmFnRGVwdGhFWFQgPSB0ZXh0dXJlKCBkZXB0aENvbG9yLCB2ZWMzKCBjb29yZC54IC0gMS4wLCBjb29yZC55LCAxICkgKS5yO1xyXG5cclxuXHR9IGVsc2Uge1xyXG5cclxuXHRcdGdsX0ZyYWdEZXB0aEVYVCA9IHRleHR1cmUoIGRlcHRoQ29sb3IsIHZlYzMoIGNvb3JkLngsIGNvb3JkLnksIDAgKSApLnI7XHJcblxyXG5cdH1cclxuXHJcbn1gO1xyXG5cclxuY2xhc3MgV2ViWFJEZXB0aFNlbnNpbmcge1xyXG5cclxuXHRjb25zdHJ1Y3RvcigpIHtcclxuXHJcblx0XHR0aGlzLnRleHR1cmUgPSBudWxsO1xyXG5cdFx0dGhpcy5tZXNoID0gbnVsbDtcclxuXHJcblx0XHR0aGlzLmRlcHRoTmVhciA9IDA7XHJcblx0XHR0aGlzLmRlcHRoRmFyID0gMDtcclxuXHJcblx0fVxyXG5cclxuXHRpbml0KCByZW5kZXJlciwgZGVwdGhEYXRhLCByZW5kZXJTdGF0ZSApIHtcclxuXHJcblx0XHRpZiAoIHRoaXMudGV4dHVyZSA9PT0gbnVsbCApIHtcclxuXHJcblx0XHRcdGNvbnN0IHRleHR1cmUgPSBuZXcgVGV4dHVyZSgpO1xyXG5cclxuXHRcdFx0Y29uc3QgdGV4UHJvcHMgPSByZW5kZXJlci5wcm9wZXJ0aWVzLmdldCggdGV4dHVyZSApO1xyXG5cdFx0XHR0ZXhQcm9wcy5fX3dlYmdsVGV4dHVyZSA9IGRlcHRoRGF0YS50ZXh0dXJlO1xyXG5cclxuXHRcdFx0aWYgKCAoIGRlcHRoRGF0YS5kZXB0aE5lYXIgIT0gcmVuZGVyU3RhdGUuZGVwdGhOZWFyICkgfHwgKCBkZXB0aERhdGEuZGVwdGhGYXIgIT0gcmVuZGVyU3RhdGUuZGVwdGhGYXIgKSApIHtcclxuXHJcblx0XHRcdFx0dGhpcy5kZXB0aE5lYXIgPSBkZXB0aERhdGEuZGVwdGhOZWFyO1xyXG5cdFx0XHRcdHRoaXMuZGVwdGhGYXIgPSBkZXB0aERhdGEuZGVwdGhGYXI7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHR0aGlzLnRleHR1cmUgPSB0ZXh0dXJlO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRyZW5kZXIoIHJlbmRlcmVyLCBjYW1lcmFYUiApIHtcclxuXHJcblx0XHRpZiAoIHRoaXMudGV4dHVyZSAhPT0gbnVsbCApIHtcclxuXHJcblx0XHRcdGlmICggdGhpcy5tZXNoID09PSBudWxsICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCB2aWV3cG9ydCA9IGNhbWVyYVhSLmNhbWVyYXNbIDAgXS52aWV3cG9ydDtcclxuXHRcdFx0XHRjb25zdCBtYXRlcmlhbCA9IG5ldyBTaGFkZXJNYXRlcmlhbCgge1xyXG5cdFx0XHRcdFx0ZXh0ZW5zaW9uczogeyBmcmFnRGVwdGg6IHRydWUgfSxcclxuXHRcdFx0XHRcdHZlcnRleFNoYWRlcjogX29jY2x1c2lvbl92ZXJ0ZXgsXHJcblx0XHRcdFx0XHRmcmFnbWVudFNoYWRlcjogX29jY2x1c2lvbl9mcmFnbWVudCxcclxuXHRcdFx0XHRcdHVuaWZvcm1zOiB7XHJcblx0XHRcdFx0XHRcdGRlcHRoQ29sb3I6IHsgdmFsdWU6IHRoaXMudGV4dHVyZSB9LFxyXG5cdFx0XHRcdFx0XHRkZXB0aFdpZHRoOiB7IHZhbHVlOiB2aWV3cG9ydC56IH0sXHJcblx0XHRcdFx0XHRcdGRlcHRoSGVpZ2h0OiB7IHZhbHVlOiB2aWV3cG9ydC53IH1cclxuXHRcdFx0XHRcdH1cclxuXHRcdFx0XHR9ICk7XHJcblxyXG5cdFx0XHRcdHRoaXMubWVzaCA9IG5ldyBNZXNoKCBuZXcgUGxhbmVHZW9tZXRyeSggMjAsIDIwICksIG1hdGVyaWFsICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRyZW5kZXJlci5yZW5kZXIoIHRoaXMubWVzaCwgY2FtZXJhWFIgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0cmVzZXQoKSB7XHJcblxyXG5cdFx0dGhpcy50ZXh0dXJlID0gbnVsbDtcclxuXHRcdHRoaXMubWVzaCA9IG51bGw7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IFdlYlhSRGVwdGhTZW5zaW5nIH07XHJcbiIsImltcG9ydCB7IEFycmF5Q2FtZXJhIH0gZnJvbSAnLi4vLi4vY2FtZXJhcy9BcnJheUNhbWVyYS5qcyc7XHJcbmltcG9ydCB7IEV2ZW50RGlzcGF0Y2hlciB9IGZyb20gJy4uLy4uL2NvcmUvRXZlbnREaXNwYXRjaGVyLmpzJztcclxuaW1wb3J0IHsgUGVyc3BlY3RpdmVDYW1lcmEgfSBmcm9tICcuLi8uLi9jYW1lcmFzL1BlcnNwZWN0aXZlQ2FtZXJhLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yMiB9IGZyb20gJy4uLy4uL21hdGgvVmVjdG9yMi5qcyc7XHJcbmltcG9ydCB7IFZlY3RvcjMgfSBmcm9tICcuLi8uLi9tYXRoL1ZlY3RvcjMuanMnO1xyXG5pbXBvcnQgeyBWZWN0b3I0IH0gZnJvbSAnLi4vLi4vbWF0aC9WZWN0b3I0LmpzJztcclxuaW1wb3J0IHsgUkFEMkRFRyB9IGZyb20gJy4uLy4uL21hdGgvTWF0aFV0aWxzLmpzJztcclxuaW1wb3J0IHsgV2ViR0xBbmltYXRpb24gfSBmcm9tICcuLi93ZWJnbC9XZWJHTEFuaW1hdGlvbi5qcyc7XHJcbmltcG9ydCB7IFdlYkdMUmVuZGVyVGFyZ2V0IH0gZnJvbSAnLi4vV2ViR0xSZW5kZXJUYXJnZXQuanMnO1xyXG5pbXBvcnQgeyBXZWJYUkNvbnRyb2xsZXIgfSBmcm9tICcuL1dlYlhSQ29udHJvbGxlci5qcyc7XHJcbmltcG9ydCB7IERlcHRoVGV4dHVyZSB9IGZyb20gJy4uLy4uL3RleHR1cmVzL0RlcHRoVGV4dHVyZS5qcyc7XHJcbmltcG9ydCB7IERlcHRoRm9ybWF0LCBEZXB0aFN0ZW5jaWxGb3JtYXQsIFJHQkFGb3JtYXQsIFVuc2lnbmVkQnl0ZVR5cGUsIFVuc2lnbmVkSW50VHlwZSwgVW5zaWduZWRJbnQyNDhUeXBlIH0gZnJvbSAnLi4vLi4vY29uc3RhbnRzLmpzJztcclxuaW1wb3J0IHsgV2ViWFJEZXB0aFNlbnNpbmcgfSBmcm9tICcuL1dlYlhSRGVwdGhTZW5zaW5nLmpzJztcclxuXHJcbmNsYXNzIFdlYlhSTWFuYWdlciBleHRlbmRzIEV2ZW50RGlzcGF0Y2hlciB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCByZW5kZXJlciwgZ2wgKSB7XHJcblxyXG5cdFx0c3VwZXIoKTtcclxuXHJcblx0XHRjb25zdCBzY29wZSA9IHRoaXM7XHJcblxyXG5cdFx0bGV0IHNlc3Npb24gPSBudWxsO1xyXG5cclxuXHRcdGxldCBmcmFtZWJ1ZmZlclNjYWxlRmFjdG9yID0gMS4wO1xyXG5cclxuXHRcdGxldCByZWZlcmVuY2VTcGFjZSA9IG51bGw7XHJcblx0XHRsZXQgcmVmZXJlbmNlU3BhY2VUeXBlID0gJ2xvY2FsLWZsb29yJztcclxuXHRcdC8vIFNldCBkZWZhdWx0IGZvdmVhdGlvbiB0byBtYXhpbXVtLlxyXG5cdFx0bGV0IGZvdmVhdGlvbiA9IDEuMDtcclxuXHRcdGxldCBjdXN0b21SZWZlcmVuY2VTcGFjZSA9IG51bGw7XHJcblxyXG5cdFx0bGV0IHBvc2UgPSBudWxsO1xyXG5cdFx0bGV0IGdsQmluZGluZyA9IG51bGw7XHJcblx0XHRsZXQgZ2xQcm9qTGF5ZXIgPSBudWxsO1xyXG5cdFx0bGV0IGdsQmFzZUxheWVyID0gbnVsbDtcclxuXHRcdGxldCB4ckZyYW1lID0gbnVsbDtcclxuXHJcblx0XHRjb25zdCBkZXB0aFNlbnNpbmcgPSBuZXcgV2ViWFJEZXB0aFNlbnNpbmcoKTtcclxuXHRcdGNvbnN0IGF0dHJpYnV0ZXMgPSBnbC5nZXRDb250ZXh0QXR0cmlidXRlcygpO1xyXG5cclxuXHRcdGxldCBpbml0aWFsUmVuZGVyVGFyZ2V0ID0gbnVsbDtcclxuXHRcdGxldCBuZXdSZW5kZXJUYXJnZXQgPSBudWxsO1xyXG5cclxuXHRcdGNvbnN0IGNvbnRyb2xsZXJzID0gW107XHJcblx0XHRjb25zdCBjb250cm9sbGVySW5wdXRTb3VyY2VzID0gW107XHJcblxyXG5cdFx0Y29uc3QgY3VycmVudFNpemUgPSBuZXcgVmVjdG9yMigpO1xyXG5cdFx0bGV0IGN1cnJlbnRQaXhlbFJhdGlvID0gbnVsbDtcclxuXHJcblx0XHQvL1xyXG5cclxuXHRcdGNvbnN0IGNhbWVyYUwgPSBuZXcgUGVyc3BlY3RpdmVDYW1lcmEoKTtcclxuXHRcdGNhbWVyYUwubGF5ZXJzLmVuYWJsZSggMSApO1xyXG5cdFx0Y2FtZXJhTC52aWV3cG9ydCA9IG5ldyBWZWN0b3I0KCk7XHJcblxyXG5cdFx0Y29uc3QgY2FtZXJhUiA9IG5ldyBQZXJzcGVjdGl2ZUNhbWVyYSgpO1xyXG5cdFx0Y2FtZXJhUi5sYXllcnMuZW5hYmxlKCAyICk7XHJcblx0XHRjYW1lcmFSLnZpZXdwb3J0ID0gbmV3IFZlY3RvcjQoKTtcclxuXHJcblx0XHRjb25zdCBjYW1lcmFzID0gWyBjYW1lcmFMLCBjYW1lcmFSIF07XHJcblxyXG5cdFx0Y29uc3QgY2FtZXJhWFIgPSBuZXcgQXJyYXlDYW1lcmEoKTtcclxuXHRcdGNhbWVyYVhSLmxheWVycy5lbmFibGUoIDEgKTtcclxuXHRcdGNhbWVyYVhSLmxheWVycy5lbmFibGUoIDIgKTtcclxuXHJcblx0XHRsZXQgX2N1cnJlbnREZXB0aE5lYXIgPSBudWxsO1xyXG5cdFx0bGV0IF9jdXJyZW50RGVwdGhGYXIgPSBudWxsO1xyXG5cclxuXHRcdC8vXHJcblxyXG5cdFx0dGhpcy5jYW1lcmFBdXRvVXBkYXRlID0gdHJ1ZTtcclxuXHRcdHRoaXMuZW5hYmxlZCA9IGZhbHNlO1xyXG5cclxuXHRcdHRoaXMuaXNQcmVzZW50aW5nID0gZmFsc2U7XHJcblxyXG5cdFx0dGhpcy5nZXRDb250cm9sbGVyID0gZnVuY3Rpb24gKCBpbmRleCApIHtcclxuXHJcblx0XHRcdGxldCBjb250cm9sbGVyID0gY29udHJvbGxlcnNbIGluZGV4IF07XHJcblxyXG5cdFx0XHRpZiAoIGNvbnRyb2xsZXIgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0Y29udHJvbGxlciA9IG5ldyBXZWJYUkNvbnRyb2xsZXIoKTtcclxuXHRcdFx0XHRjb250cm9sbGVyc1sgaW5kZXggXSA9IGNvbnRyb2xsZXI7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRyZXR1cm4gY29udHJvbGxlci5nZXRUYXJnZXRSYXlTcGFjZSgpO1xyXG5cclxuXHRcdH07XHJcblxyXG5cdFx0dGhpcy5nZXRDb250cm9sbGVyR3JpcCA9IGZ1bmN0aW9uICggaW5kZXggKSB7XHJcblxyXG5cdFx0XHRsZXQgY29udHJvbGxlciA9IGNvbnRyb2xsZXJzWyBpbmRleCBdO1xyXG5cclxuXHRcdFx0aWYgKCBjb250cm9sbGVyID09PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnRyb2xsZXIgPSBuZXcgV2ViWFJDb250cm9sbGVyKCk7XHJcblx0XHRcdFx0Y29udHJvbGxlcnNbIGluZGV4IF0gPSBjb250cm9sbGVyO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0cmV0dXJuIGNvbnRyb2xsZXIuZ2V0R3JpcFNwYWNlKCk7XHJcblxyXG5cdFx0fTtcclxuXHJcblx0XHR0aGlzLmdldEhhbmQgPSBmdW5jdGlvbiAoIGluZGV4ICkge1xyXG5cclxuXHRcdFx0bGV0IGNvbnRyb2xsZXIgPSBjb250cm9sbGVyc1sgaW5kZXggXTtcclxuXHJcblx0XHRcdGlmICggY29udHJvbGxlciA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHRjb250cm9sbGVyID0gbmV3IFdlYlhSQ29udHJvbGxlcigpO1xyXG5cdFx0XHRcdGNvbnRyb2xsZXJzWyBpbmRleCBdID0gY29udHJvbGxlcjtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHJldHVybiBjb250cm9sbGVyLmdldEhhbmRTcGFjZSgpO1xyXG5cclxuXHRcdH07XHJcblxyXG5cdFx0Ly9cclxuXHJcblx0XHRmdW5jdGlvbiBvblNlc3Npb25FdmVudCggZXZlbnQgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBjb250cm9sbGVySW5kZXggPSBjb250cm9sbGVySW5wdXRTb3VyY2VzLmluZGV4T2YoIGV2ZW50LmlucHV0U291cmNlICk7XHJcblxyXG5cdFx0XHRpZiAoIGNvbnRyb2xsZXJJbmRleCA9PT0gLSAxICkge1xyXG5cclxuXHRcdFx0XHRyZXR1cm47XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRjb25zdCBjb250cm9sbGVyID0gY29udHJvbGxlcnNbIGNvbnRyb2xsZXJJbmRleCBdO1xyXG5cclxuXHRcdFx0aWYgKCBjb250cm9sbGVyICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnRyb2xsZXIudXBkYXRlKCBldmVudC5pbnB1dFNvdXJjZSwgZXZlbnQuZnJhbWUsIGN1c3RvbVJlZmVyZW5jZVNwYWNlIHx8IHJlZmVyZW5jZVNwYWNlICk7XHJcblx0XHRcdFx0Y29udHJvbGxlci5kaXNwYXRjaEV2ZW50KCB7IHR5cGU6IGV2ZW50LnR5cGUsIGRhdGE6IGV2ZW50LmlucHV0U291cmNlIH0gKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0ZnVuY3Rpb24gb25TZXNzaW9uRW5kKCkge1xyXG5cclxuXHRcdFx0c2Vzc2lvbi5yZW1vdmVFdmVudExpc3RlbmVyKCAnc2VsZWN0Jywgb25TZXNzaW9uRXZlbnQgKTtcclxuXHRcdFx0c2Vzc2lvbi5yZW1vdmVFdmVudExpc3RlbmVyKCAnc2VsZWN0c3RhcnQnLCBvblNlc3Npb25FdmVudCApO1xyXG5cdFx0XHRzZXNzaW9uLnJlbW92ZUV2ZW50TGlzdGVuZXIoICdzZWxlY3RlbmQnLCBvblNlc3Npb25FdmVudCApO1xyXG5cdFx0XHRzZXNzaW9uLnJlbW92ZUV2ZW50TGlzdGVuZXIoICdzcXVlZXplJywgb25TZXNzaW9uRXZlbnQgKTtcclxuXHRcdFx0c2Vzc2lvbi5yZW1vdmVFdmVudExpc3RlbmVyKCAnc3F1ZWV6ZXN0YXJ0Jywgb25TZXNzaW9uRXZlbnQgKTtcclxuXHRcdFx0c2Vzc2lvbi5yZW1vdmVFdmVudExpc3RlbmVyKCAnc3F1ZWV6ZWVuZCcsIG9uU2Vzc2lvbkV2ZW50ICk7XHJcblx0XHRcdHNlc3Npb24ucmVtb3ZlRXZlbnRMaXN0ZW5lciggJ2VuZCcsIG9uU2Vzc2lvbkVuZCApO1xyXG5cdFx0XHRzZXNzaW9uLnJlbW92ZUV2ZW50TGlzdGVuZXIoICdpbnB1dHNvdXJjZXNjaGFuZ2UnLCBvbklucHV0U291cmNlc0NoYW5nZSApO1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgY29udHJvbGxlcnMubGVuZ3RoOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBpbnB1dFNvdXJjZSA9IGNvbnRyb2xsZXJJbnB1dFNvdXJjZXNbIGkgXTtcclxuXHJcblx0XHRcdFx0aWYgKCBpbnB1dFNvdXJjZSA9PT0gbnVsbCApIGNvbnRpbnVlO1xyXG5cclxuXHRcdFx0XHRjb250cm9sbGVySW5wdXRTb3VyY2VzWyBpIF0gPSBudWxsO1xyXG5cclxuXHRcdFx0XHRjb250cm9sbGVyc1sgaSBdLmRpc2Nvbm5lY3QoIGlucHV0U291cmNlICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRfY3VycmVudERlcHRoTmVhciA9IG51bGw7XHJcblx0XHRcdF9jdXJyZW50RGVwdGhGYXIgPSBudWxsO1xyXG5cclxuXHRcdFx0ZGVwdGhTZW5zaW5nLnJlc2V0KCk7XHJcblxyXG5cdFx0XHQvLyByZXN0b3JlIGZyYW1lYnVmZmVyL3JlbmRlcmluZyBzdGF0ZVxyXG5cclxuXHRcdFx0cmVuZGVyZXIuc2V0UmVuZGVyVGFyZ2V0KCBpbml0aWFsUmVuZGVyVGFyZ2V0ICk7XHJcblxyXG5cdFx0XHRnbEJhc2VMYXllciA9IG51bGw7XHJcblx0XHRcdGdsUHJvakxheWVyID0gbnVsbDtcclxuXHRcdFx0Z2xCaW5kaW5nID0gbnVsbDtcclxuXHRcdFx0c2Vzc2lvbiA9IG51bGw7XHJcblx0XHRcdG5ld1JlbmRlclRhcmdldCA9IG51bGw7XHJcblxyXG5cdFx0XHQvL1xyXG5cclxuXHRcdFx0YW5pbWF0aW9uLnN0b3AoKTtcclxuXHJcblx0XHRcdHNjb3BlLmlzUHJlc2VudGluZyA9IGZhbHNlO1xyXG5cclxuXHRcdFx0cmVuZGVyZXIuc2V0UGl4ZWxSYXRpbyggY3VycmVudFBpeGVsUmF0aW8gKTtcclxuXHRcdFx0cmVuZGVyZXIuc2V0U2l6ZSggY3VycmVudFNpemUud2lkdGgsIGN1cnJlbnRTaXplLmhlaWdodCwgZmFsc2UgKTtcclxuXHJcblx0XHRcdHNjb3BlLmRpc3BhdGNoRXZlbnQoIHsgdHlwZTogJ3Nlc3Npb25lbmQnIH0gKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5zZXRGcmFtZWJ1ZmZlclNjYWxlRmFjdG9yID0gZnVuY3Rpb24gKCB2YWx1ZSApIHtcclxuXHJcblx0XHRcdGZyYW1lYnVmZmVyU2NhbGVGYWN0b3IgPSB2YWx1ZTtcclxuXHJcblx0XHRcdGlmICggc2NvcGUuaXNQcmVzZW50aW5nID09PSB0cnVlICkge1xyXG5cclxuXHRcdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5XZWJYUk1hbmFnZXI6IENhbm5vdCBjaGFuZ2UgZnJhbWVidWZmZXIgc2NhbGUgd2hpbGUgcHJlc2VudGluZy4nICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fTtcclxuXHJcblx0XHR0aGlzLnNldFJlZmVyZW5jZVNwYWNlVHlwZSA9IGZ1bmN0aW9uICggdmFsdWUgKSB7XHJcblxyXG5cdFx0XHRyZWZlcmVuY2VTcGFjZVR5cGUgPSB2YWx1ZTtcclxuXHJcblx0XHRcdGlmICggc2NvcGUuaXNQcmVzZW50aW5nID09PSB0cnVlICkge1xyXG5cclxuXHRcdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5XZWJYUk1hbmFnZXI6IENhbm5vdCBjaGFuZ2UgcmVmZXJlbmNlIHNwYWNlIHR5cGUgd2hpbGUgcHJlc2VudGluZy4nICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fTtcclxuXHJcblx0XHR0aGlzLmdldFJlZmVyZW5jZVNwYWNlID0gZnVuY3Rpb24gKCkge1xyXG5cclxuXHRcdFx0cmV0dXJuIGN1c3RvbVJlZmVyZW5jZVNwYWNlIHx8IHJlZmVyZW5jZVNwYWNlO1xyXG5cclxuXHRcdH07XHJcblxyXG5cdFx0dGhpcy5zZXRSZWZlcmVuY2VTcGFjZSA9IGZ1bmN0aW9uICggc3BhY2UgKSB7XHJcblxyXG5cdFx0XHRjdXN0b21SZWZlcmVuY2VTcGFjZSA9IHNwYWNlO1xyXG5cclxuXHRcdH07XHJcblxyXG5cdFx0dGhpcy5nZXRCYXNlTGF5ZXIgPSBmdW5jdGlvbiAoKSB7XHJcblxyXG5cdFx0XHRyZXR1cm4gZ2xQcm9qTGF5ZXIgIT09IG51bGwgPyBnbFByb2pMYXllciA6IGdsQmFzZUxheWVyO1xyXG5cclxuXHRcdH07XHJcblxyXG5cdFx0dGhpcy5nZXRCaW5kaW5nID0gZnVuY3Rpb24gKCkge1xyXG5cclxuXHRcdFx0cmV0dXJuIGdsQmluZGluZztcclxuXHJcblx0XHR9O1xyXG5cclxuXHRcdHRoaXMuZ2V0RnJhbWUgPSBmdW5jdGlvbiAoKSB7XHJcblxyXG5cdFx0XHRyZXR1cm4geHJGcmFtZTtcclxuXHJcblx0XHR9O1xyXG5cclxuXHRcdHRoaXMuZ2V0U2Vzc2lvbiA9IGZ1bmN0aW9uICgpIHtcclxuXHJcblx0XHRcdHJldHVybiBzZXNzaW9uO1xyXG5cclxuXHRcdH07XHJcblxyXG5cdFx0dGhpcy5zZXRTZXNzaW9uID0gYXN5bmMgZnVuY3Rpb24gKCB2YWx1ZSApIHtcclxuXHJcblx0XHRcdHNlc3Npb24gPSB2YWx1ZTtcclxuXHJcblx0XHRcdGlmICggc2Vzc2lvbiAhPT0gbnVsbCApIHtcclxuXHJcblx0XHRcdFx0aW5pdGlhbFJlbmRlclRhcmdldCA9IHJlbmRlcmVyLmdldFJlbmRlclRhcmdldCgpO1xyXG5cclxuXHRcdFx0XHRzZXNzaW9uLmFkZEV2ZW50TGlzdGVuZXIoICdzZWxlY3QnLCBvblNlc3Npb25FdmVudCApO1xyXG5cdFx0XHRcdHNlc3Npb24uYWRkRXZlbnRMaXN0ZW5lciggJ3NlbGVjdHN0YXJ0Jywgb25TZXNzaW9uRXZlbnQgKTtcclxuXHRcdFx0XHRzZXNzaW9uLmFkZEV2ZW50TGlzdGVuZXIoICdzZWxlY3RlbmQnLCBvblNlc3Npb25FdmVudCApO1xyXG5cdFx0XHRcdHNlc3Npb24uYWRkRXZlbnRMaXN0ZW5lciggJ3NxdWVlemUnLCBvblNlc3Npb25FdmVudCApO1xyXG5cdFx0XHRcdHNlc3Npb24uYWRkRXZlbnRMaXN0ZW5lciggJ3NxdWVlemVzdGFydCcsIG9uU2Vzc2lvbkV2ZW50ICk7XHJcblx0XHRcdFx0c2Vzc2lvbi5hZGRFdmVudExpc3RlbmVyKCAnc3F1ZWV6ZWVuZCcsIG9uU2Vzc2lvbkV2ZW50ICk7XHJcblx0XHRcdFx0c2Vzc2lvbi5hZGRFdmVudExpc3RlbmVyKCAnZW5kJywgb25TZXNzaW9uRW5kICk7XHJcblx0XHRcdFx0c2Vzc2lvbi5hZGRFdmVudExpc3RlbmVyKCAnaW5wdXRzb3VyY2VzY2hhbmdlJywgb25JbnB1dFNvdXJjZXNDaGFuZ2UgKTtcclxuXHJcblx0XHRcdFx0aWYgKCBhdHRyaWJ1dGVzLnhyQ29tcGF0aWJsZSAhPT0gdHJ1ZSApIHtcclxuXHJcblx0XHRcdFx0XHRhd2FpdCBnbC5tYWtlWFJDb21wYXRpYmxlKCk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0Y3VycmVudFBpeGVsUmF0aW8gPSByZW5kZXJlci5nZXRQaXhlbFJhdGlvKCk7XHJcblx0XHRcdFx0cmVuZGVyZXIuZ2V0U2l6ZSggY3VycmVudFNpemUgKTtcclxuXHJcblx0XHRcdFx0aWYgKCAoIHNlc3Npb24ucmVuZGVyU3RhdGUubGF5ZXJzID09PSB1bmRlZmluZWQgKSB8fCAoIHJlbmRlcmVyLmNhcGFiaWxpdGllcy5pc1dlYkdMMiA9PT0gZmFsc2UgKSApIHtcclxuXHJcblx0XHRcdFx0XHRjb25zdCBsYXllckluaXQgPSB7XHJcblx0XHRcdFx0XHRcdGFudGlhbGlhczogKCBzZXNzaW9uLnJlbmRlclN0YXRlLmxheWVycyA9PT0gdW5kZWZpbmVkICkgPyBhdHRyaWJ1dGVzLmFudGlhbGlhcyA6IHRydWUsXHJcblx0XHRcdFx0XHRcdGFscGhhOiB0cnVlLFxyXG5cdFx0XHRcdFx0XHRkZXB0aDogYXR0cmlidXRlcy5kZXB0aCxcclxuXHRcdFx0XHRcdFx0c3RlbmNpbDogYXR0cmlidXRlcy5zdGVuY2lsLFxyXG5cdFx0XHRcdFx0XHRmcmFtZWJ1ZmZlclNjYWxlRmFjdG9yOiBmcmFtZWJ1ZmZlclNjYWxlRmFjdG9yXHJcblx0XHRcdFx0XHR9O1xyXG5cclxuXHRcdFx0XHRcdGdsQmFzZUxheWVyID0gbmV3IFhSV2ViR0xMYXllciggc2Vzc2lvbiwgZ2wsIGxheWVySW5pdCApO1xyXG5cclxuXHRcdFx0XHRcdHNlc3Npb24udXBkYXRlUmVuZGVyU3RhdGUoIHsgYmFzZUxheWVyOiBnbEJhc2VMYXllciB9ICk7XHJcblxyXG5cdFx0XHRcdFx0cmVuZGVyZXIuc2V0UGl4ZWxSYXRpbyggMSApO1xyXG5cdFx0XHRcdFx0cmVuZGVyZXIuc2V0U2l6ZSggZ2xCYXNlTGF5ZXIuZnJhbWVidWZmZXJXaWR0aCwgZ2xCYXNlTGF5ZXIuZnJhbWVidWZmZXJIZWlnaHQsIGZhbHNlICk7XHJcblxyXG5cdFx0XHRcdFx0bmV3UmVuZGVyVGFyZ2V0ID0gbmV3IFdlYkdMUmVuZGVyVGFyZ2V0KFxyXG5cdFx0XHRcdFx0XHRnbEJhc2VMYXllci5mcmFtZWJ1ZmZlcldpZHRoLFxyXG5cdFx0XHRcdFx0XHRnbEJhc2VMYXllci5mcmFtZWJ1ZmZlckhlaWdodCxcclxuXHRcdFx0XHRcdFx0e1xyXG5cdFx0XHRcdFx0XHRcdGZvcm1hdDogUkdCQUZvcm1hdCxcclxuXHRcdFx0XHRcdFx0XHR0eXBlOiBVbnNpZ25lZEJ5dGVUeXBlLFxyXG5cdFx0XHRcdFx0XHRcdGNvbG9yU3BhY2U6IHJlbmRlcmVyLm91dHB1dENvbG9yU3BhY2UsXHJcblx0XHRcdFx0XHRcdFx0c3RlbmNpbEJ1ZmZlcjogYXR0cmlidXRlcy5zdGVuY2lsXHJcblx0XHRcdFx0XHRcdH1cclxuXHRcdFx0XHRcdCk7XHJcblxyXG5cdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0bGV0IGRlcHRoRm9ybWF0ID0gbnVsbDtcclxuXHRcdFx0XHRcdGxldCBkZXB0aFR5cGUgPSBudWxsO1xyXG5cdFx0XHRcdFx0bGV0IGdsRGVwdGhGb3JtYXQgPSBudWxsO1xyXG5cclxuXHRcdFx0XHRcdGlmICggYXR0cmlidXRlcy5kZXB0aCApIHtcclxuXHJcblx0XHRcdFx0XHRcdGdsRGVwdGhGb3JtYXQgPSBhdHRyaWJ1dGVzLnN0ZW5jaWwgPyBnbC5ERVBUSDI0X1NURU5DSUw4IDogZ2wuREVQVEhfQ09NUE9ORU5UMjQ7XHJcblx0XHRcdFx0XHRcdGRlcHRoRm9ybWF0ID0gYXR0cmlidXRlcy5zdGVuY2lsID8gRGVwdGhTdGVuY2lsRm9ybWF0IDogRGVwdGhGb3JtYXQ7XHJcblx0XHRcdFx0XHRcdGRlcHRoVHlwZSA9IGF0dHJpYnV0ZXMuc3RlbmNpbCA/IFVuc2lnbmVkSW50MjQ4VHlwZSA6IFVuc2lnbmVkSW50VHlwZTtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgcHJvamVjdGlvbmxheWVySW5pdCA9IHtcclxuXHRcdFx0XHRcdFx0Y29sb3JGb3JtYXQ6IGdsLlJHQkE4LFxyXG5cdFx0XHRcdFx0XHRkZXB0aEZvcm1hdDogZ2xEZXB0aEZvcm1hdCxcclxuXHRcdFx0XHRcdFx0c2NhbGVGYWN0b3I6IGZyYW1lYnVmZmVyU2NhbGVGYWN0b3JcclxuXHRcdFx0XHRcdH07XHJcblxyXG5cdFx0XHRcdFx0Z2xCaW5kaW5nID0gbmV3IFhSV2ViR0xCaW5kaW5nKCBzZXNzaW9uLCBnbCApO1xyXG5cclxuXHRcdFx0XHRcdGdsUHJvakxheWVyID0gZ2xCaW5kaW5nLmNyZWF0ZVByb2plY3Rpb25MYXllciggcHJvamVjdGlvbmxheWVySW5pdCApO1xyXG5cclxuXHRcdFx0XHRcdHNlc3Npb24udXBkYXRlUmVuZGVyU3RhdGUoIHsgbGF5ZXJzOiBbIGdsUHJvakxheWVyIF0gfSApO1xyXG5cclxuXHRcdFx0XHRcdHJlbmRlcmVyLnNldFBpeGVsUmF0aW8oIDEgKTtcclxuXHRcdFx0XHRcdHJlbmRlcmVyLnNldFNpemUoIGdsUHJvakxheWVyLnRleHR1cmVXaWR0aCwgZ2xQcm9qTGF5ZXIudGV4dHVyZUhlaWdodCwgZmFsc2UgKTtcclxuXHJcblx0XHRcdFx0XHRuZXdSZW5kZXJUYXJnZXQgPSBuZXcgV2ViR0xSZW5kZXJUYXJnZXQoXHJcblx0XHRcdFx0XHRcdGdsUHJvakxheWVyLnRleHR1cmVXaWR0aCxcclxuXHRcdFx0XHRcdFx0Z2xQcm9qTGF5ZXIudGV4dHVyZUhlaWdodCxcclxuXHRcdFx0XHRcdFx0e1xyXG5cdFx0XHRcdFx0XHRcdGZvcm1hdDogUkdCQUZvcm1hdCxcclxuXHRcdFx0XHRcdFx0XHR0eXBlOiBVbnNpZ25lZEJ5dGVUeXBlLFxyXG5cdFx0XHRcdFx0XHRcdGRlcHRoVGV4dHVyZTogbmV3IERlcHRoVGV4dHVyZSggZ2xQcm9qTGF5ZXIudGV4dHVyZVdpZHRoLCBnbFByb2pMYXllci50ZXh0dXJlSGVpZ2h0LCBkZXB0aFR5cGUsIHVuZGVmaW5lZCwgdW5kZWZpbmVkLCB1bmRlZmluZWQsIHVuZGVmaW5lZCwgdW5kZWZpbmVkLCB1bmRlZmluZWQsIGRlcHRoRm9ybWF0ICksXHJcblx0XHRcdFx0XHRcdFx0c3RlbmNpbEJ1ZmZlcjogYXR0cmlidXRlcy5zdGVuY2lsLFxyXG5cdFx0XHRcdFx0XHRcdGNvbG9yU3BhY2U6IHJlbmRlcmVyLm91dHB1dENvbG9yU3BhY2UsXHJcblx0XHRcdFx0XHRcdFx0c2FtcGxlczogYXR0cmlidXRlcy5hbnRpYWxpYXMgPyA0IDogMFxyXG5cdFx0XHRcdFx0XHR9ICk7XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgcmVuZGVyVGFyZ2V0UHJvcGVydGllcyA9IHJlbmRlcmVyLnByb3BlcnRpZXMuZ2V0KCBuZXdSZW5kZXJUYXJnZXQgKTtcclxuXHRcdFx0XHRcdHJlbmRlclRhcmdldFByb3BlcnRpZXMuX19pZ25vcmVEZXB0aFZhbHVlcyA9IGdsUHJvakxheWVyLmlnbm9yZURlcHRoVmFsdWVzO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdG5ld1JlbmRlclRhcmdldC5pc1hSUmVuZGVyVGFyZ2V0ID0gdHJ1ZTsgLy8gVE9ETyBSZW1vdmUgdGhpcyB3aGVuIHBvc3NpYmxlLCBzZWUgIzIzMjc4XHJcblxyXG5cdFx0XHRcdHRoaXMuc2V0Rm92ZWF0aW9uKCBmb3ZlYXRpb24gKTtcclxuXHJcblx0XHRcdFx0Y3VzdG9tUmVmZXJlbmNlU3BhY2UgPSBudWxsO1xyXG5cdFx0XHRcdHJlZmVyZW5jZVNwYWNlID0gYXdhaXQgc2Vzc2lvbi5yZXF1ZXN0UmVmZXJlbmNlU3BhY2UoIHJlZmVyZW5jZVNwYWNlVHlwZSApO1xyXG5cclxuXHRcdFx0XHRhbmltYXRpb24uc2V0Q29udGV4dCggc2Vzc2lvbiApO1xyXG5cdFx0XHRcdGFuaW1hdGlvbi5zdGFydCgpO1xyXG5cclxuXHRcdFx0XHRzY29wZS5pc1ByZXNlbnRpbmcgPSB0cnVlO1xyXG5cclxuXHRcdFx0XHRzY29wZS5kaXNwYXRjaEV2ZW50KCB7IHR5cGU6ICdzZXNzaW9uc3RhcnQnIH0gKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9O1xyXG5cclxuXHRcdHRoaXMuZ2V0RW52aXJvbm1lbnRCbGVuZE1vZGUgPSBmdW5jdGlvbiAoKSB7XHJcblxyXG5cdFx0XHRpZiAoIHNlc3Npb24gIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdHJldHVybiBzZXNzaW9uLmVudmlyb25tZW50QmxlbmRNb2RlO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH07XHJcblxyXG5cdFx0ZnVuY3Rpb24gb25JbnB1dFNvdXJjZXNDaGFuZ2UoIGV2ZW50ICkge1xyXG5cclxuXHRcdFx0Ly8gTm90aWZ5IGRpc2Nvbm5lY3RlZFxyXG5cclxuXHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgZXZlbnQucmVtb3ZlZC5sZW5ndGg7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IGlucHV0U291cmNlID0gZXZlbnQucmVtb3ZlZFsgaSBdO1xyXG5cdFx0XHRcdGNvbnN0IGluZGV4ID0gY29udHJvbGxlcklucHV0U291cmNlcy5pbmRleE9mKCBpbnB1dFNvdXJjZSApO1xyXG5cclxuXHRcdFx0XHRpZiAoIGluZGV4ID49IDAgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y29udHJvbGxlcklucHV0U291cmNlc1sgaW5kZXggXSA9IG51bGw7XHJcblx0XHRcdFx0XHRjb250cm9sbGVyc1sgaW5kZXggXS5kaXNjb25uZWN0KCBpbnB1dFNvdXJjZSApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyBOb3RpZnkgY29ubmVjdGVkXHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBldmVudC5hZGRlZC5sZW5ndGg7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IGlucHV0U291cmNlID0gZXZlbnQuYWRkZWRbIGkgXTtcclxuXHJcblx0XHRcdFx0bGV0IGNvbnRyb2xsZXJJbmRleCA9IGNvbnRyb2xsZXJJbnB1dFNvdXJjZXMuaW5kZXhPZiggaW5wdXRTb3VyY2UgKTtcclxuXHJcblx0XHRcdFx0aWYgKCBjb250cm9sbGVySW5kZXggPT09IC0gMSApIHtcclxuXHJcblx0XHRcdFx0XHQvLyBBc3NpZ24gaW5wdXQgc291cmNlIGEgY29udHJvbGxlciB0aGF0IGN1cnJlbnRseSBoYXMgbm8gaW5wdXQgc291cmNlXHJcblxyXG5cdFx0XHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgY29udHJvbGxlcnMubGVuZ3RoOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRcdFx0aWYgKCBpID49IGNvbnRyb2xsZXJJbnB1dFNvdXJjZXMubGVuZ3RoICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRjb250cm9sbGVySW5wdXRTb3VyY2VzLnB1c2goIGlucHV0U291cmNlICk7XHJcblx0XHRcdFx0XHRcdFx0Y29udHJvbGxlckluZGV4ID0gaTtcclxuXHRcdFx0XHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdFx0XHRcdH0gZWxzZSBpZiAoIGNvbnRyb2xsZXJJbnB1dFNvdXJjZXNbIGkgXSA9PT0gbnVsbCApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0Y29udHJvbGxlcklucHV0U291cmNlc1sgaSBdID0gaW5wdXRTb3VyY2U7XHJcblx0XHRcdFx0XHRcdFx0Y29udHJvbGxlckluZGV4ID0gaTtcclxuXHRcdFx0XHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0Ly8gSWYgYWxsIGNvbnRyb2xsZXJzIGRvIGN1cnJlbnRseSByZWNlaXZlIGlucHV0IHdlIGlnbm9yZSBuZXcgb25lc1xyXG5cclxuXHRcdFx0XHRcdGlmICggY29udHJvbGxlckluZGV4ID09PSAtIDEgKSBicmVhaztcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRjb25zdCBjb250cm9sbGVyID0gY29udHJvbGxlcnNbIGNvbnRyb2xsZXJJbmRleCBdO1xyXG5cclxuXHRcdFx0XHRpZiAoIGNvbnRyb2xsZXIgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y29udHJvbGxlci5jb25uZWN0KCBpbnB1dFNvdXJjZSApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vXHJcblxyXG5cdFx0Y29uc3QgY2FtZXJhTFBvcyA9IG5ldyBWZWN0b3IzKCk7XHJcblx0XHRjb25zdCBjYW1lcmFSUG9zID0gbmV3IFZlY3RvcjMoKTtcclxuXHJcblx0XHQvKipcclxuXHRcdCAqIEFzc3VtZXMgMiBjYW1lcmFzIHRoYXQgYXJlIHBhcmFsbGVsIGFuZCBzaGFyZSBhbiBYLWF4aXMsIGFuZCB0aGF0XHJcblx0XHQgKiB0aGUgY2FtZXJhcycgcHJvamVjdGlvbiBhbmQgd29ybGQgbWF0cmljZXMgaGF2ZSBhbHJlYWR5IGJlZW4gc2V0LlxyXG5cdFx0ICogQW5kIHRoYXQgbmVhciBhbmQgZmFyIHBsYW5lcyBhcmUgaWRlbnRpY2FsIGZvciBib3RoIGNhbWVyYXMuXHJcblx0XHQgKiBWaXN1YWxpemF0aW9uIG9mIHRoaXMgdGVjaG5pcXVlOiBodHRwczovL2NvbXB1dGVyZ3JhcGhpY3Muc3RhY2tleGNoYW5nZS5jb20vYS80NzY1XHJcblx0XHQgKi9cclxuXHRcdGZ1bmN0aW9uIHNldFByb2plY3Rpb25Gcm9tVW5pb24oIGNhbWVyYSwgY2FtZXJhTCwgY2FtZXJhUiApIHtcclxuXHJcblx0XHRcdGNhbWVyYUxQb3Muc2V0RnJvbU1hdHJpeFBvc2l0aW9uKCBjYW1lcmFMLm1hdHJpeFdvcmxkICk7XHJcblx0XHRcdGNhbWVyYVJQb3Muc2V0RnJvbU1hdHJpeFBvc2l0aW9uKCBjYW1lcmFSLm1hdHJpeFdvcmxkICk7XHJcblxyXG5cdFx0XHRjb25zdCBpcGQgPSBjYW1lcmFMUG9zLmRpc3RhbmNlVG8oIGNhbWVyYVJQb3MgKTtcclxuXHJcblx0XHRcdGNvbnN0IHByb2pMID0gY2FtZXJhTC5wcm9qZWN0aW9uTWF0cml4LmVsZW1lbnRzO1xyXG5cdFx0XHRjb25zdCBwcm9qUiA9IGNhbWVyYVIucHJvamVjdGlvbk1hdHJpeC5lbGVtZW50cztcclxuXHJcblx0XHRcdC8vIFZSIHN5c3RlbXMgd2lsbCBoYXZlIGlkZW50aWNhbCBmYXIgYW5kIG5lYXIgcGxhbmVzLCBhbmRcclxuXHRcdFx0Ly8gbW9zdCBsaWtlbHkgaWRlbnRpY2FsIHRvcCBhbmQgYm90dG9tIGZydXN0dW0gZXh0ZW50cy5cclxuXHRcdFx0Ly8gVXNlIHRoZSBsZWZ0IGNhbWVyYSBmb3IgdGhlc2UgdmFsdWVzLlxyXG5cdFx0XHRjb25zdCBuZWFyID0gcHJvakxbIDE0IF0gLyAoIHByb2pMWyAxMCBdIC0gMSApO1xyXG5cdFx0XHRjb25zdCBmYXIgPSBwcm9qTFsgMTQgXSAvICggcHJvakxbIDEwIF0gKyAxICk7XHJcblx0XHRcdGNvbnN0IHRvcEZvdiA9ICggcHJvakxbIDkgXSArIDEgKSAvIHByb2pMWyA1IF07XHJcblx0XHRcdGNvbnN0IGJvdHRvbUZvdiA9ICggcHJvakxbIDkgXSAtIDEgKSAvIHByb2pMWyA1IF07XHJcblxyXG5cdFx0XHRjb25zdCBsZWZ0Rm92ID0gKCBwcm9qTFsgOCBdIC0gMSApIC8gcHJvakxbIDAgXTtcclxuXHRcdFx0Y29uc3QgcmlnaHRGb3YgPSAoIHByb2pSWyA4IF0gKyAxICkgLyBwcm9qUlsgMCBdO1xyXG5cdFx0XHRjb25zdCBsZWZ0ID0gbmVhciAqIGxlZnRGb3Y7XHJcblx0XHRcdGNvbnN0IHJpZ2h0ID0gbmVhciAqIHJpZ2h0Rm92O1xyXG5cclxuXHRcdFx0Ly8gQ2FsY3VsYXRlIHRoZSBuZXcgY2FtZXJhJ3MgcG9zaXRpb24gb2Zmc2V0IGZyb20gdGhlXHJcblx0XHRcdC8vIGxlZnQgY2FtZXJhLiB4T2Zmc2V0IHNob3VsZCBiZSByb3VnaGx5IGhhbGYgYGlwZGAuXHJcblx0XHRcdGNvbnN0IHpPZmZzZXQgPSBpcGQgLyAoIC0gbGVmdEZvdiArIHJpZ2h0Rm92ICk7XHJcblx0XHRcdGNvbnN0IHhPZmZzZXQgPSB6T2Zmc2V0ICogLSBsZWZ0Rm92O1xyXG5cclxuXHRcdFx0Ly8gVE9ETzogQmV0dGVyIHdheSB0byBhcHBseSB0aGlzIG9mZnNldD9cclxuXHRcdFx0Y2FtZXJhTC5tYXRyaXhXb3JsZC5kZWNvbXBvc2UoIGNhbWVyYS5wb3NpdGlvbiwgY2FtZXJhLnF1YXRlcm5pb24sIGNhbWVyYS5zY2FsZSApO1xyXG5cdFx0XHRjYW1lcmEudHJhbnNsYXRlWCggeE9mZnNldCApO1xyXG5cdFx0XHRjYW1lcmEudHJhbnNsYXRlWiggek9mZnNldCApO1xyXG5cdFx0XHRjYW1lcmEubWF0cml4V29ybGQuY29tcG9zZSggY2FtZXJhLnBvc2l0aW9uLCBjYW1lcmEucXVhdGVybmlvbiwgY2FtZXJhLnNjYWxlICk7XHJcblx0XHRcdGNhbWVyYS5tYXRyaXhXb3JsZEludmVyc2UuY29weSggY2FtZXJhLm1hdHJpeFdvcmxkICkuaW52ZXJ0KCk7XHJcblxyXG5cdFx0XHQvLyBGaW5kIHRoZSB1bmlvbiBvZiB0aGUgZnJ1c3R1bSB2YWx1ZXMgb2YgdGhlIGNhbWVyYXMgYW5kIHNjYWxlXHJcblx0XHRcdC8vIHRoZSB2YWx1ZXMgc28gdGhhdCB0aGUgbmVhciBwbGFuZSdzIHBvc2l0aW9uIGRvZXMgbm90IGNoYW5nZSBpbiB3b3JsZCBzcGFjZSxcclxuXHRcdFx0Ly8gYWx0aG91Z2ggbXVzdCBub3cgYmUgcmVsYXRpdmUgdG8gdGhlIG5ldyB1bmlvbiBjYW1lcmEuXHJcblx0XHRcdGNvbnN0IG5lYXIyID0gbmVhciArIHpPZmZzZXQ7XHJcblx0XHRcdGNvbnN0IGZhcjIgPSBmYXIgKyB6T2Zmc2V0O1xyXG5cdFx0XHRjb25zdCBsZWZ0MiA9IGxlZnQgLSB4T2Zmc2V0O1xyXG5cdFx0XHRjb25zdCByaWdodDIgPSByaWdodCArICggaXBkIC0geE9mZnNldCApO1xyXG5cdFx0XHRjb25zdCB0b3AyID0gdG9wRm92ICogZmFyIC8gZmFyMiAqIG5lYXIyO1xyXG5cdFx0XHRjb25zdCBib3R0b20yID0gYm90dG9tRm92ICogZmFyIC8gZmFyMiAqIG5lYXIyO1xyXG5cclxuXHRcdFx0Y2FtZXJhLnByb2plY3Rpb25NYXRyaXgubWFrZVBlcnNwZWN0aXZlKCBsZWZ0MiwgcmlnaHQyLCB0b3AyLCBib3R0b20yLCBuZWFyMiwgZmFyMiApO1xyXG5cdFx0XHRjYW1lcmEucHJvamVjdGlvbk1hdHJpeEludmVyc2UuY29weSggY2FtZXJhLnByb2plY3Rpb25NYXRyaXggKS5pbnZlcnQoKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0ZnVuY3Rpb24gdXBkYXRlQ2FtZXJhKCBjYW1lcmEsIHBhcmVudCApIHtcclxuXHJcblx0XHRcdGlmICggcGFyZW50ID09PSBudWxsICkge1xyXG5cclxuXHRcdFx0XHRjYW1lcmEubWF0cml4V29ybGQuY29weSggY2FtZXJhLm1hdHJpeCApO1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0Y2FtZXJhLm1hdHJpeFdvcmxkLm11bHRpcGx5TWF0cmljZXMoIHBhcmVudC5tYXRyaXhXb3JsZCwgY2FtZXJhLm1hdHJpeCApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Y2FtZXJhLm1hdHJpeFdvcmxkSW52ZXJzZS5jb3B5KCBjYW1lcmEubWF0cml4V29ybGQgKS5pbnZlcnQoKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy51cGRhdGVDYW1lcmEgPSBmdW5jdGlvbiAoIGNhbWVyYSApIHtcclxuXHJcblx0XHRcdGlmICggc2Vzc2lvbiA9PT0gbnVsbCApIHJldHVybjtcclxuXHJcblx0XHRcdGlmICggZGVwdGhTZW5zaW5nLnRleHR1cmUgIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdGNhbWVyYS5uZWFyID0gZGVwdGhTZW5zaW5nLmRlcHRoTmVhcjtcclxuXHRcdFx0XHRjYW1lcmEuZmFyID0gZGVwdGhTZW5zaW5nLmRlcHRoRmFyO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Y2FtZXJhWFIubmVhciA9IGNhbWVyYVIubmVhciA9IGNhbWVyYUwubmVhciA9IGNhbWVyYS5uZWFyO1xyXG5cdFx0XHRjYW1lcmFYUi5mYXIgPSBjYW1lcmFSLmZhciA9IGNhbWVyYUwuZmFyID0gY2FtZXJhLmZhcjtcclxuXHJcblx0XHRcdGlmICggX2N1cnJlbnREZXB0aE5lYXIgIT09IGNhbWVyYVhSLm5lYXIgfHwgX2N1cnJlbnREZXB0aEZhciAhPT0gY2FtZXJhWFIuZmFyICkge1xyXG5cclxuXHRcdFx0XHQvLyBOb3RlIHRoYXQgdGhlIG5ldyByZW5kZXJTdGF0ZSB3b24ndCBhcHBseSB1bnRpbCB0aGUgbmV4dCBmcmFtZS4gU2VlICMxODMyMFxyXG5cclxuXHRcdFx0XHRzZXNzaW9uLnVwZGF0ZVJlbmRlclN0YXRlKCB7XHJcblx0XHRcdFx0XHRkZXB0aE5lYXI6IGNhbWVyYVhSLm5lYXIsXHJcblx0XHRcdFx0XHRkZXB0aEZhcjogY2FtZXJhWFIuZmFyXHJcblx0XHRcdFx0fSApO1xyXG5cclxuXHRcdFx0XHRfY3VycmVudERlcHRoTmVhciA9IGNhbWVyYVhSLm5lYXI7XHJcblx0XHRcdFx0X2N1cnJlbnREZXB0aEZhciA9IGNhbWVyYVhSLmZhcjtcclxuXHJcblx0XHRcdFx0Y2FtZXJhTC5uZWFyID0gX2N1cnJlbnREZXB0aE5lYXI7XHJcblx0XHRcdFx0Y2FtZXJhTC5mYXIgPSBfY3VycmVudERlcHRoRmFyO1xyXG5cdFx0XHRcdGNhbWVyYVIubmVhciA9IF9jdXJyZW50RGVwdGhOZWFyO1xyXG5cdFx0XHRcdGNhbWVyYVIuZmFyID0gX2N1cnJlbnREZXB0aEZhcjtcclxuXHJcblx0XHRcdFx0Y2FtZXJhTC51cGRhdGVQcm9qZWN0aW9uTWF0cml4KCk7XHJcblx0XHRcdFx0Y2FtZXJhUi51cGRhdGVQcm9qZWN0aW9uTWF0cml4KCk7XHJcblx0XHRcdFx0Y2FtZXJhLnVwZGF0ZVByb2plY3Rpb25NYXRyaXgoKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGNvbnN0IHBhcmVudCA9IGNhbWVyYS5wYXJlbnQ7XHJcblx0XHRcdGNvbnN0IGNhbWVyYXMgPSBjYW1lcmFYUi5jYW1lcmFzO1xyXG5cclxuXHRcdFx0dXBkYXRlQ2FtZXJhKCBjYW1lcmFYUiwgcGFyZW50ICk7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBjYW1lcmFzLmxlbmd0aDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0dXBkYXRlQ2FtZXJhKCBjYW1lcmFzWyBpIF0sIHBhcmVudCApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Ly8gdXBkYXRlIHByb2plY3Rpb24gbWF0cml4IGZvciBwcm9wZXIgdmlldyBmcnVzdHVtIGN1bGxpbmdcclxuXHJcblx0XHRcdGlmICggY2FtZXJhcy5sZW5ndGggPT09IDIgKSB7XHJcblxyXG5cdFx0XHRcdHNldFByb2plY3Rpb25Gcm9tVW5pb24oIGNhbWVyYVhSLCBjYW1lcmFMLCBjYW1lcmFSICk7XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHQvLyBhc3N1bWUgc2luZ2xlIGNhbWVyYSBzZXR1cCAoQVIpXHJcblxyXG5cdFx0XHRcdGNhbWVyYVhSLnByb2plY3Rpb25NYXRyaXguY29weSggY2FtZXJhTC5wcm9qZWN0aW9uTWF0cml4ICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyB1cGRhdGUgdXNlciBjYW1lcmEgYW5kIGl0cyBjaGlsZHJlblxyXG5cclxuXHRcdFx0dXBkYXRlVXNlckNhbWVyYSggY2FtZXJhLCBjYW1lcmFYUiwgcGFyZW50ICk7XHJcblxyXG5cdFx0fTtcclxuXHJcblx0XHRmdW5jdGlvbiB1cGRhdGVVc2VyQ2FtZXJhKCBjYW1lcmEsIGNhbWVyYVhSLCBwYXJlbnQgKSB7XHJcblxyXG5cdFx0XHRpZiAoIHBhcmVudCA9PT0gbnVsbCApIHtcclxuXHJcblx0XHRcdFx0Y2FtZXJhLm1hdHJpeC5jb3B5KCBjYW1lcmFYUi5tYXRyaXhXb3JsZCApO1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0Y2FtZXJhLm1hdHJpeC5jb3B5KCBwYXJlbnQubWF0cml4V29ybGQgKTtcclxuXHRcdFx0XHRjYW1lcmEubWF0cml4LmludmVydCgpO1xyXG5cdFx0XHRcdGNhbWVyYS5tYXRyaXgubXVsdGlwbHkoIGNhbWVyYVhSLm1hdHJpeFdvcmxkICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRjYW1lcmEubWF0cml4LmRlY29tcG9zZSggY2FtZXJhLnBvc2l0aW9uLCBjYW1lcmEucXVhdGVybmlvbiwgY2FtZXJhLnNjYWxlICk7XHJcblx0XHRcdGNhbWVyYS51cGRhdGVNYXRyaXhXb3JsZCggdHJ1ZSApO1xyXG5cclxuXHRcdFx0Y2FtZXJhLnByb2plY3Rpb25NYXRyaXguY29weSggY2FtZXJhWFIucHJvamVjdGlvbk1hdHJpeCApO1xyXG5cdFx0XHRjYW1lcmEucHJvamVjdGlvbk1hdHJpeEludmVyc2UuY29weSggY2FtZXJhWFIucHJvamVjdGlvbk1hdHJpeEludmVyc2UgKTtcclxuXHJcblx0XHRcdGlmICggY2FtZXJhLmlzUGVyc3BlY3RpdmVDYW1lcmEgKSB7XHJcblxyXG5cdFx0XHRcdGNhbWVyYS5mb3YgPSBSQUQyREVHICogMiAqIE1hdGguYXRhbiggMSAvIGNhbWVyYS5wcm9qZWN0aW9uTWF0cml4LmVsZW1lbnRzWyA1IF0gKTtcclxuXHRcdFx0XHRjYW1lcmEuem9vbSA9IDE7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMuZ2V0Q2FtZXJhID0gZnVuY3Rpb24gKCkge1xyXG5cclxuXHRcdFx0cmV0dXJuIGNhbWVyYVhSO1xyXG5cclxuXHRcdH07XHJcblxyXG5cdFx0dGhpcy5nZXRGb3ZlYXRpb24gPSBmdW5jdGlvbiAoKSB7XHJcblxyXG5cdFx0XHRpZiAoIGdsUHJvakxheWVyID09PSBudWxsICYmIGdsQmFzZUxheWVyID09PSBudWxsICkge1xyXG5cclxuXHRcdFx0XHRyZXR1cm4gdW5kZWZpbmVkO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0cmV0dXJuIGZvdmVhdGlvbjtcclxuXHJcblx0XHR9O1xyXG5cclxuXHRcdHRoaXMuc2V0Rm92ZWF0aW9uID0gZnVuY3Rpb24gKCB2YWx1ZSApIHtcclxuXHJcblx0XHRcdC8vIDAgPSBubyBmb3ZlYXRpb24gPSBmdWxsIHJlc29sdXRpb25cclxuXHRcdFx0Ly8gMSA9IG1heGltdW0gZm92ZWF0aW9uID0gdGhlIGVkZ2VzIHJlbmRlciBhdCBsb3dlciByZXNvbHV0aW9uXHJcblxyXG5cdFx0XHRmb3ZlYXRpb24gPSB2YWx1ZTtcclxuXHJcblx0XHRcdGlmICggZ2xQcm9qTGF5ZXIgIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdGdsUHJvakxheWVyLmZpeGVkRm92ZWF0aW9uID0gdmFsdWU7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRpZiAoIGdsQmFzZUxheWVyICE9PSBudWxsICYmIGdsQmFzZUxheWVyLmZpeGVkRm92ZWF0aW9uICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRcdGdsQmFzZUxheWVyLmZpeGVkRm92ZWF0aW9uID0gdmFsdWU7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fTtcclxuXHJcblx0XHR0aGlzLmhhc0RlcHRoU2Vuc2luZyA9IGZ1bmN0aW9uICgpIHtcclxuXHJcblx0XHRcdHJldHVybiBkZXB0aFNlbnNpbmcudGV4dHVyZSAhPT0gbnVsbDtcclxuXHJcblx0XHR9O1xyXG5cclxuXHRcdC8vIEFuaW1hdGlvbiBMb29wXHJcblxyXG5cdFx0bGV0IG9uQW5pbWF0aW9uRnJhbWVDYWxsYmFjayA9IG51bGw7XHJcblxyXG5cdFx0ZnVuY3Rpb24gb25BbmltYXRpb25GcmFtZSggdGltZSwgZnJhbWUgKSB7XHJcblxyXG5cdFx0XHRwb3NlID0gZnJhbWUuZ2V0Vmlld2VyUG9zZSggY3VzdG9tUmVmZXJlbmNlU3BhY2UgfHwgcmVmZXJlbmNlU3BhY2UgKTtcclxuXHRcdFx0eHJGcmFtZSA9IGZyYW1lO1xyXG5cclxuXHRcdFx0aWYgKCBwb3NlICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCB2aWV3cyA9IHBvc2Uudmlld3M7XHJcblxyXG5cdFx0XHRcdGlmICggZ2xCYXNlTGF5ZXIgIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdFx0cmVuZGVyZXIuc2V0UmVuZGVyVGFyZ2V0RnJhbWVidWZmZXIoIG5ld1JlbmRlclRhcmdldCwgZ2xCYXNlTGF5ZXIuZnJhbWVidWZmZXIgKTtcclxuXHRcdFx0XHRcdHJlbmRlcmVyLnNldFJlbmRlclRhcmdldCggbmV3UmVuZGVyVGFyZ2V0ICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0bGV0IGNhbWVyYVhSTmVlZHNVcGRhdGUgPSBmYWxzZTtcclxuXHJcblx0XHRcdFx0Ly8gY2hlY2sgaWYgaXQncyBuZWNlc3NhcnkgdG8gcmVidWlsZCBjYW1lcmFYUidzIGNhbWVyYSBsaXN0XHJcblxyXG5cdFx0XHRcdGlmICggdmlld3MubGVuZ3RoICE9PSBjYW1lcmFYUi5jYW1lcmFzLmxlbmd0aCApIHtcclxuXHJcblx0XHRcdFx0XHRjYW1lcmFYUi5jYW1lcmFzLmxlbmd0aCA9IDA7XHJcblx0XHRcdFx0XHRjYW1lcmFYUk5lZWRzVXBkYXRlID0gdHJ1ZTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCB2aWV3cy5sZW5ndGg7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgdmlldyA9IHZpZXdzWyBpIF07XHJcblxyXG5cdFx0XHRcdFx0bGV0IHZpZXdwb3J0ID0gbnVsbDtcclxuXHJcblx0XHRcdFx0XHRpZiAoIGdsQmFzZUxheWVyICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0XHRcdFx0dmlld3BvcnQgPSBnbEJhc2VMYXllci5nZXRWaWV3cG9ydCggdmlldyApO1xyXG5cclxuXHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHRjb25zdCBnbFN1YkltYWdlID0gZ2xCaW5kaW5nLmdldFZpZXdTdWJJbWFnZSggZ2xQcm9qTGF5ZXIsIHZpZXcgKTtcclxuXHRcdFx0XHRcdFx0dmlld3BvcnQgPSBnbFN1YkltYWdlLnZpZXdwb3J0O1xyXG5cclxuXHRcdFx0XHRcdFx0Ly8gRm9yIHNpZGUtYnktc2lkZSBwcm9qZWN0aW9uLCB3ZSBvbmx5IHByb2R1Y2UgYSBzaW5nbGUgdGV4dHVyZSBmb3IgYm90aCBleWVzLlxyXG5cdFx0XHRcdFx0XHRpZiAoIGkgPT09IDAgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdHJlbmRlcmVyLnNldFJlbmRlclRhcmdldFRleHR1cmVzKFxyXG5cdFx0XHRcdFx0XHRcdFx0bmV3UmVuZGVyVGFyZ2V0LFxyXG5cdFx0XHRcdFx0XHRcdFx0Z2xTdWJJbWFnZS5jb2xvclRleHR1cmUsXHJcblx0XHRcdFx0XHRcdFx0XHRnbFByb2pMYXllci5pZ25vcmVEZXB0aFZhbHVlcyA/IHVuZGVmaW5lZCA6IGdsU3ViSW1hZ2UuZGVwdGhTdGVuY2lsVGV4dHVyZSApO1xyXG5cclxuXHRcdFx0XHRcdFx0XHRyZW5kZXJlci5zZXRSZW5kZXJUYXJnZXQoIG5ld1JlbmRlclRhcmdldCApO1xyXG5cclxuXHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRsZXQgY2FtZXJhID0gY2FtZXJhc1sgaSBdO1xyXG5cclxuXHRcdFx0XHRcdGlmICggY2FtZXJhID09PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRjYW1lcmEgPSBuZXcgUGVyc3BlY3RpdmVDYW1lcmEoKTtcclxuXHRcdFx0XHRcdFx0Y2FtZXJhLmxheWVycy5lbmFibGUoIGkgKTtcclxuXHRcdFx0XHRcdFx0Y2FtZXJhLnZpZXdwb3J0ID0gbmV3IFZlY3RvcjQoKTtcclxuXHRcdFx0XHRcdFx0Y2FtZXJhc1sgaSBdID0gY2FtZXJhO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRjYW1lcmEubWF0cml4LmZyb21BcnJheSggdmlldy50cmFuc2Zvcm0ubWF0cml4ICk7XHJcblx0XHRcdFx0XHRjYW1lcmEubWF0cml4LmRlY29tcG9zZSggY2FtZXJhLnBvc2l0aW9uLCBjYW1lcmEucXVhdGVybmlvbiwgY2FtZXJhLnNjYWxlICk7XHJcblx0XHRcdFx0XHRjYW1lcmEucHJvamVjdGlvbk1hdHJpeC5mcm9tQXJyYXkoIHZpZXcucHJvamVjdGlvbk1hdHJpeCApO1xyXG5cdFx0XHRcdFx0Y2FtZXJhLnByb2plY3Rpb25NYXRyaXhJbnZlcnNlLmNvcHkoIGNhbWVyYS5wcm9qZWN0aW9uTWF0cml4ICkuaW52ZXJ0KCk7XHJcblx0XHRcdFx0XHRjYW1lcmEudmlld3BvcnQuc2V0KCB2aWV3cG9ydC54LCB2aWV3cG9ydC55LCB2aWV3cG9ydC53aWR0aCwgdmlld3BvcnQuaGVpZ2h0ICk7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCBpID09PSAwICkge1xyXG5cclxuXHRcdFx0XHRcdFx0Y2FtZXJhWFIubWF0cml4LmNvcHkoIGNhbWVyYS5tYXRyaXggKTtcclxuXHRcdFx0XHRcdFx0Y2FtZXJhWFIubWF0cml4LmRlY29tcG9zZSggY2FtZXJhWFIucG9zaXRpb24sIGNhbWVyYVhSLnF1YXRlcm5pb24sIGNhbWVyYVhSLnNjYWxlICk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdGlmICggY2FtZXJhWFJOZWVkc1VwZGF0ZSA9PT0gdHJ1ZSApIHtcclxuXHJcblx0XHRcdFx0XHRcdGNhbWVyYVhSLmNhbWVyYXMucHVzaCggY2FtZXJhICk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdC8vXHJcblxyXG5cdFx0XHRcdGNvbnN0IGVuYWJsZWRGZWF0dXJlcyA9IHNlc3Npb24uZW5hYmxlZEZlYXR1cmVzO1xyXG5cclxuXHRcdFx0XHRpZiAoIGVuYWJsZWRGZWF0dXJlcyAmJiBlbmFibGVkRmVhdHVyZXMuaW5jbHVkZXMoICdkZXB0aC1zZW5zaW5nJyApICkge1xyXG5cclxuXHRcdFx0XHRcdGNvbnN0IGRlcHRoRGF0YSA9IGdsQmluZGluZy5nZXREZXB0aEluZm9ybWF0aW9uKCB2aWV3c1sgMCBdICk7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCBkZXB0aERhdGEgJiYgZGVwdGhEYXRhLmlzVmFsaWQgJiYgZGVwdGhEYXRhLnRleHR1cmUgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRkZXB0aFNlbnNpbmcuaW5pdCggcmVuZGVyZXIsIGRlcHRoRGF0YSwgc2Vzc2lvbi5yZW5kZXJTdGF0ZSApO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Ly9cclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IGNvbnRyb2xsZXJzLmxlbmd0aDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgaW5wdXRTb3VyY2UgPSBjb250cm9sbGVySW5wdXRTb3VyY2VzWyBpIF07XHJcblx0XHRcdFx0Y29uc3QgY29udHJvbGxlciA9IGNvbnRyb2xsZXJzWyBpIF07XHJcblxyXG5cdFx0XHRcdGlmICggaW5wdXRTb3VyY2UgIT09IG51bGwgJiYgY29udHJvbGxlciAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHRcdGNvbnRyb2xsZXIudXBkYXRlKCBpbnB1dFNvdXJjZSwgZnJhbWUsIGN1c3RvbVJlZmVyZW5jZVNwYWNlIHx8IHJlZmVyZW5jZVNwYWNlICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGRlcHRoU2Vuc2luZy5yZW5kZXIoIHJlbmRlcmVyLCBjYW1lcmFYUiApO1xyXG5cclxuXHRcdFx0aWYgKCBvbkFuaW1hdGlvbkZyYW1lQ2FsbGJhY2sgKSBvbkFuaW1hdGlvbkZyYW1lQ2FsbGJhY2soIHRpbWUsIGZyYW1lICk7XHJcblxyXG5cdFx0XHRpZiAoIGZyYW1lLmRldGVjdGVkUGxhbmVzICkge1xyXG5cclxuXHRcdFx0XHRzY29wZS5kaXNwYXRjaEV2ZW50KCB7IHR5cGU6ICdwbGFuZXNkZXRlY3RlZCcsIGRhdGE6IGZyYW1lIH0gKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHhyRnJhbWUgPSBudWxsO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCBhbmltYXRpb24gPSBuZXcgV2ViR0xBbmltYXRpb24oKTtcclxuXHJcblx0XHRhbmltYXRpb24uc2V0QW5pbWF0aW9uTG9vcCggb25BbmltYXRpb25GcmFtZSApO1xyXG5cclxuXHRcdHRoaXMuc2V0QW5pbWF0aW9uTG9vcCA9IGZ1bmN0aW9uICggY2FsbGJhY2sgKSB7XHJcblxyXG5cdFx0XHRvbkFuaW1hdGlvbkZyYW1lQ2FsbGJhY2sgPSBjYWxsYmFjaztcclxuXHJcblx0XHR9O1xyXG5cclxuXHRcdHRoaXMuZGlzcG9zZSA9IGZ1bmN0aW9uICgpIHt9O1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBXZWJYUk1hbmFnZXIgfTtcclxuIiwiaW1wb3J0IHsgQmFja1NpZGUgfSBmcm9tICcuLi8uLi9jb25zdGFudHMuanMnO1xyXG5pbXBvcnQgeyBnZXRVbmxpdFVuaWZvcm1Db2xvclNwYWNlIH0gZnJvbSAnLi4vc2hhZGVycy9Vbmlmb3Jtc1V0aWxzLmpzJztcclxuXHJcbmZ1bmN0aW9uIFdlYkdMTWF0ZXJpYWxzKCByZW5kZXJlciwgcHJvcGVydGllcyApIHtcclxuXHJcblx0ZnVuY3Rpb24gcmVmcmVzaFRyYW5zZm9ybVVuaWZvcm0oIG1hcCwgdW5pZm9ybSApIHtcclxuXHJcblx0XHRpZiAoIG1hcC5tYXRyaXhBdXRvVXBkYXRlID09PSB0cnVlICkge1xyXG5cclxuXHRcdFx0bWFwLnVwZGF0ZU1hdHJpeCgpO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHR1bmlmb3JtLnZhbHVlLmNvcHkoIG1hcC5tYXRyaXggKTtcclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiByZWZyZXNoRm9nVW5pZm9ybXMoIHVuaWZvcm1zLCBmb2cgKSB7XHJcblxyXG5cdFx0Zm9nLmNvbG9yLmdldFJHQiggdW5pZm9ybXMuZm9nQ29sb3IudmFsdWUsIGdldFVubGl0VW5pZm9ybUNvbG9yU3BhY2UoIHJlbmRlcmVyICkgKTtcclxuXHJcblx0XHRpZiAoIGZvZy5pc0ZvZyApIHtcclxuXHJcblx0XHRcdHVuaWZvcm1zLmZvZ05lYXIudmFsdWUgPSBmb2cubmVhcjtcclxuXHRcdFx0dW5pZm9ybXMuZm9nRmFyLnZhbHVlID0gZm9nLmZhcjtcclxuXHJcblx0XHR9IGVsc2UgaWYgKCBmb2cuaXNGb2dFeHAyICkge1xyXG5cclxuXHRcdFx0dW5pZm9ybXMuZm9nRGVuc2l0eS52YWx1ZSA9IGZvZy5kZW5zaXR5O1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiByZWZyZXNoTWF0ZXJpYWxVbmlmb3JtcyggdW5pZm9ybXMsIG1hdGVyaWFsLCBwaXhlbFJhdGlvLCBoZWlnaHQsIHRyYW5zbWlzc2lvblJlbmRlclRhcmdldCApIHtcclxuXHJcblx0XHRpZiAoIG1hdGVyaWFsLmlzTWVzaEJhc2ljTWF0ZXJpYWwgKSB7XHJcblxyXG5cdFx0XHRyZWZyZXNoVW5pZm9ybXNDb21tb24oIHVuaWZvcm1zLCBtYXRlcmlhbCApO1xyXG5cclxuXHRcdH0gZWxzZSBpZiAoIG1hdGVyaWFsLmlzTWVzaExhbWJlcnRNYXRlcmlhbCApIHtcclxuXHJcblx0XHRcdHJlZnJlc2hVbmlmb3Jtc0NvbW1vbiggdW5pZm9ybXMsIG1hdGVyaWFsICk7XHJcblxyXG5cdFx0fSBlbHNlIGlmICggbWF0ZXJpYWwuaXNNZXNoVG9vbk1hdGVyaWFsICkge1xyXG5cclxuXHRcdFx0cmVmcmVzaFVuaWZvcm1zQ29tbW9uKCB1bmlmb3JtcywgbWF0ZXJpYWwgKTtcclxuXHRcdFx0cmVmcmVzaFVuaWZvcm1zVG9vbiggdW5pZm9ybXMsIG1hdGVyaWFsICk7XHJcblxyXG5cdFx0fSBlbHNlIGlmICggbWF0ZXJpYWwuaXNNZXNoUGhvbmdNYXRlcmlhbCApIHtcclxuXHJcblx0XHRcdHJlZnJlc2hVbmlmb3Jtc0NvbW1vbiggdW5pZm9ybXMsIG1hdGVyaWFsICk7XHJcblx0XHRcdHJlZnJlc2hVbmlmb3Jtc1Bob25nKCB1bmlmb3JtcywgbWF0ZXJpYWwgKTtcclxuXHJcblx0XHR9IGVsc2UgaWYgKCBtYXRlcmlhbC5pc01lc2hTdGFuZGFyZE1hdGVyaWFsICkge1xyXG5cclxuXHRcdFx0cmVmcmVzaFVuaWZvcm1zQ29tbW9uKCB1bmlmb3JtcywgbWF0ZXJpYWwgKTtcclxuXHRcdFx0cmVmcmVzaFVuaWZvcm1zU3RhbmRhcmQoIHVuaWZvcm1zLCBtYXRlcmlhbCApO1xyXG5cclxuXHRcdFx0aWYgKCBtYXRlcmlhbC5pc01lc2hQaHlzaWNhbE1hdGVyaWFsICkge1xyXG5cclxuXHRcdFx0XHRyZWZyZXNoVW5pZm9ybXNQaHlzaWNhbCggdW5pZm9ybXMsIG1hdGVyaWFsLCB0cmFuc21pc3Npb25SZW5kZXJUYXJnZXQgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9IGVsc2UgaWYgKCBtYXRlcmlhbC5pc01lc2hNYXRjYXBNYXRlcmlhbCApIHtcclxuXHJcblx0XHRcdHJlZnJlc2hVbmlmb3Jtc0NvbW1vbiggdW5pZm9ybXMsIG1hdGVyaWFsICk7XHJcblx0XHRcdHJlZnJlc2hVbmlmb3Jtc01hdGNhcCggdW5pZm9ybXMsIG1hdGVyaWFsICk7XHJcblxyXG5cdFx0fSBlbHNlIGlmICggbWF0ZXJpYWwuaXNNZXNoRGVwdGhNYXRlcmlhbCApIHtcclxuXHJcblx0XHRcdHJlZnJlc2hVbmlmb3Jtc0NvbW1vbiggdW5pZm9ybXMsIG1hdGVyaWFsICk7XHJcblxyXG5cdFx0fSBlbHNlIGlmICggbWF0ZXJpYWwuaXNNZXNoRGlzdGFuY2VNYXRlcmlhbCApIHtcclxuXHJcblx0XHRcdHJlZnJlc2hVbmlmb3Jtc0NvbW1vbiggdW5pZm9ybXMsIG1hdGVyaWFsICk7XHJcblx0XHRcdHJlZnJlc2hVbmlmb3Jtc0Rpc3RhbmNlKCB1bmlmb3JtcywgbWF0ZXJpYWwgKTtcclxuXHJcblx0XHR9IGVsc2UgaWYgKCBtYXRlcmlhbC5pc01lc2hOb3JtYWxNYXRlcmlhbCApIHtcclxuXHJcblx0XHRcdHJlZnJlc2hVbmlmb3Jtc0NvbW1vbiggdW5pZm9ybXMsIG1hdGVyaWFsICk7XHJcblxyXG5cdFx0fSBlbHNlIGlmICggbWF0ZXJpYWwuaXNMaW5lQmFzaWNNYXRlcmlhbCApIHtcclxuXHJcblx0XHRcdHJlZnJlc2hVbmlmb3Jtc0xpbmUoIHVuaWZvcm1zLCBtYXRlcmlhbCApO1xyXG5cclxuXHRcdFx0aWYgKCBtYXRlcmlhbC5pc0xpbmVEYXNoZWRNYXRlcmlhbCApIHtcclxuXHJcblx0XHRcdFx0cmVmcmVzaFVuaWZvcm1zRGFzaCggdW5pZm9ybXMsIG1hdGVyaWFsICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fSBlbHNlIGlmICggbWF0ZXJpYWwuaXNQb2ludHNNYXRlcmlhbCApIHtcclxuXHJcblx0XHRcdHJlZnJlc2hVbmlmb3Jtc1BvaW50cyggdW5pZm9ybXMsIG1hdGVyaWFsLCBwaXhlbFJhdGlvLCBoZWlnaHQgKTtcclxuXHJcblx0XHR9IGVsc2UgaWYgKCBtYXRlcmlhbC5pc1Nwcml0ZU1hdGVyaWFsICkge1xyXG5cclxuXHRcdFx0cmVmcmVzaFVuaWZvcm1zU3ByaXRlcyggdW5pZm9ybXMsIG1hdGVyaWFsICk7XHJcblxyXG5cdFx0fSBlbHNlIGlmICggbWF0ZXJpYWwuaXNTaGFkb3dNYXRlcmlhbCApIHtcclxuXHJcblx0XHRcdHVuaWZvcm1zLmNvbG9yLnZhbHVlLmNvcHkoIG1hdGVyaWFsLmNvbG9yICk7XHJcblx0XHRcdHVuaWZvcm1zLm9wYWNpdHkudmFsdWUgPSBtYXRlcmlhbC5vcGFjaXR5O1xyXG5cclxuXHRcdH0gZWxzZSBpZiAoIG1hdGVyaWFsLmlzU2hhZGVyTWF0ZXJpYWwgKSB7XHJcblxyXG5cdFx0XHRtYXRlcmlhbC51bmlmb3Jtc05lZWRVcGRhdGUgPSBmYWxzZTsgLy8gIzE1NTgxXHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHJlZnJlc2hVbmlmb3Jtc0NvbW1vbiggdW5pZm9ybXMsIG1hdGVyaWFsICkge1xyXG5cclxuXHRcdHVuaWZvcm1zLm9wYWNpdHkudmFsdWUgPSBtYXRlcmlhbC5vcGFjaXR5O1xyXG5cclxuXHRcdGlmICggbWF0ZXJpYWwuY29sb3IgKSB7XHJcblxyXG5cdFx0XHR1bmlmb3Jtcy5kaWZmdXNlLnZhbHVlLmNvcHkoIG1hdGVyaWFsLmNvbG9yICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggbWF0ZXJpYWwuZW1pc3NpdmUgKSB7XHJcblxyXG5cdFx0XHR1bmlmb3Jtcy5lbWlzc2l2ZS52YWx1ZS5jb3B5KCBtYXRlcmlhbC5lbWlzc2l2ZSApLm11bHRpcGx5U2NhbGFyKCBtYXRlcmlhbC5lbWlzc2l2ZUludGVuc2l0eSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIG1hdGVyaWFsLm1hcCApIHtcclxuXHJcblx0XHRcdHVuaWZvcm1zLm1hcC52YWx1ZSA9IG1hdGVyaWFsLm1hcDtcclxuXHJcblx0XHRcdHJlZnJlc2hUcmFuc2Zvcm1Vbmlmb3JtKCBtYXRlcmlhbC5tYXAsIHVuaWZvcm1zLm1hcFRyYW5zZm9ybSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIG1hdGVyaWFsLmFscGhhTWFwICkge1xyXG5cclxuXHRcdFx0dW5pZm9ybXMuYWxwaGFNYXAudmFsdWUgPSBtYXRlcmlhbC5hbHBoYU1hcDtcclxuXHJcblx0XHRcdHJlZnJlc2hUcmFuc2Zvcm1Vbmlmb3JtKCBtYXRlcmlhbC5hbHBoYU1hcCwgdW5pZm9ybXMuYWxwaGFNYXBUcmFuc2Zvcm0gKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBtYXRlcmlhbC5idW1wTWFwICkge1xyXG5cclxuXHRcdFx0dW5pZm9ybXMuYnVtcE1hcC52YWx1ZSA9IG1hdGVyaWFsLmJ1bXBNYXA7XHJcblxyXG5cdFx0XHRyZWZyZXNoVHJhbnNmb3JtVW5pZm9ybSggbWF0ZXJpYWwuYnVtcE1hcCwgdW5pZm9ybXMuYnVtcE1hcFRyYW5zZm9ybSApO1xyXG5cclxuXHRcdFx0dW5pZm9ybXMuYnVtcFNjYWxlLnZhbHVlID0gbWF0ZXJpYWwuYnVtcFNjYWxlO1xyXG5cclxuXHRcdFx0aWYgKCBtYXRlcmlhbC5zaWRlID09PSBCYWNrU2lkZSApIHtcclxuXHJcblx0XHRcdFx0dW5pZm9ybXMuYnVtcFNjYWxlLnZhbHVlICo9IC0gMTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBtYXRlcmlhbC5ub3JtYWxNYXAgKSB7XHJcblxyXG5cdFx0XHR1bmlmb3Jtcy5ub3JtYWxNYXAudmFsdWUgPSBtYXRlcmlhbC5ub3JtYWxNYXA7XHJcblxyXG5cdFx0XHRyZWZyZXNoVHJhbnNmb3JtVW5pZm9ybSggbWF0ZXJpYWwubm9ybWFsTWFwLCB1bmlmb3Jtcy5ub3JtYWxNYXBUcmFuc2Zvcm0gKTtcclxuXHJcblx0XHRcdHVuaWZvcm1zLm5vcm1hbFNjYWxlLnZhbHVlLmNvcHkoIG1hdGVyaWFsLm5vcm1hbFNjYWxlICk7XHJcblxyXG5cdFx0XHRpZiAoIG1hdGVyaWFsLnNpZGUgPT09IEJhY2tTaWRlICkge1xyXG5cclxuXHRcdFx0XHR1bmlmb3Jtcy5ub3JtYWxTY2FsZS52YWx1ZS5uZWdhdGUoKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBtYXRlcmlhbC5kaXNwbGFjZW1lbnRNYXAgKSB7XHJcblxyXG5cdFx0XHR1bmlmb3Jtcy5kaXNwbGFjZW1lbnRNYXAudmFsdWUgPSBtYXRlcmlhbC5kaXNwbGFjZW1lbnRNYXA7XHJcblxyXG5cdFx0XHRyZWZyZXNoVHJhbnNmb3JtVW5pZm9ybSggbWF0ZXJpYWwuZGlzcGxhY2VtZW50TWFwLCB1bmlmb3Jtcy5kaXNwbGFjZW1lbnRNYXBUcmFuc2Zvcm0gKTtcclxuXHJcblx0XHRcdHVuaWZvcm1zLmRpc3BsYWNlbWVudFNjYWxlLnZhbHVlID0gbWF0ZXJpYWwuZGlzcGxhY2VtZW50U2NhbGU7XHJcblx0XHRcdHVuaWZvcm1zLmRpc3BsYWNlbWVudEJpYXMudmFsdWUgPSBtYXRlcmlhbC5kaXNwbGFjZW1lbnRCaWFzO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIG1hdGVyaWFsLmVtaXNzaXZlTWFwICkge1xyXG5cclxuXHRcdFx0dW5pZm9ybXMuZW1pc3NpdmVNYXAudmFsdWUgPSBtYXRlcmlhbC5lbWlzc2l2ZU1hcDtcclxuXHJcblx0XHRcdHJlZnJlc2hUcmFuc2Zvcm1Vbmlmb3JtKCBtYXRlcmlhbC5lbWlzc2l2ZU1hcCwgdW5pZm9ybXMuZW1pc3NpdmVNYXBUcmFuc2Zvcm0gKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBtYXRlcmlhbC5zcGVjdWxhck1hcCApIHtcclxuXHJcblx0XHRcdHVuaWZvcm1zLnNwZWN1bGFyTWFwLnZhbHVlID0gbWF0ZXJpYWwuc3BlY3VsYXJNYXA7XHJcblxyXG5cdFx0XHRyZWZyZXNoVHJhbnNmb3JtVW5pZm9ybSggbWF0ZXJpYWwuc3BlY3VsYXJNYXAsIHVuaWZvcm1zLnNwZWN1bGFyTWFwVHJhbnNmb3JtICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggbWF0ZXJpYWwuYWxwaGFUZXN0ID4gMCApIHtcclxuXHJcblx0XHRcdHVuaWZvcm1zLmFscGhhVGVzdC52YWx1ZSA9IG1hdGVyaWFsLmFscGhhVGVzdDtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Y29uc3QgZW52TWFwID0gcHJvcGVydGllcy5nZXQoIG1hdGVyaWFsICkuZW52TWFwO1xyXG5cclxuXHRcdGlmICggZW52TWFwICkge1xyXG5cclxuXHRcdFx0dW5pZm9ybXMuZW52TWFwLnZhbHVlID0gZW52TWFwO1xyXG5cclxuXHRcdFx0dW5pZm9ybXMuZmxpcEVudk1hcC52YWx1ZSA9ICggZW52TWFwLmlzQ3ViZVRleHR1cmUgJiYgZW52TWFwLmlzUmVuZGVyVGFyZ2V0VGV4dHVyZSA9PT0gZmFsc2UgKSA/IC0gMSA6IDE7XHJcblxyXG5cdFx0XHR1bmlmb3Jtcy5yZWZsZWN0aXZpdHkudmFsdWUgPSBtYXRlcmlhbC5yZWZsZWN0aXZpdHk7XHJcblx0XHRcdHVuaWZvcm1zLmlvci52YWx1ZSA9IG1hdGVyaWFsLmlvcjtcclxuXHRcdFx0dW5pZm9ybXMucmVmcmFjdGlvblJhdGlvLnZhbHVlID0gbWF0ZXJpYWwucmVmcmFjdGlvblJhdGlvO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIG1hdGVyaWFsLmxpZ2h0TWFwICkge1xyXG5cclxuXHRcdFx0dW5pZm9ybXMubGlnaHRNYXAudmFsdWUgPSBtYXRlcmlhbC5saWdodE1hcDtcclxuXHJcblx0XHRcdC8vIGFydGlzdC1mcmllbmRseSBsaWdodCBpbnRlbnNpdHkgc2NhbGluZyBmYWN0b3JcclxuXHRcdFx0Y29uc3Qgc2NhbGVGYWN0b3IgPSAoIHJlbmRlcmVyLl91c2VMZWdhY3lMaWdodHMgPT09IHRydWUgKSA/IE1hdGguUEkgOiAxO1xyXG5cclxuXHRcdFx0dW5pZm9ybXMubGlnaHRNYXBJbnRlbnNpdHkudmFsdWUgPSBtYXRlcmlhbC5saWdodE1hcEludGVuc2l0eSAqIHNjYWxlRmFjdG9yO1xyXG5cclxuXHRcdFx0cmVmcmVzaFRyYW5zZm9ybVVuaWZvcm0oIG1hdGVyaWFsLmxpZ2h0TWFwLCB1bmlmb3Jtcy5saWdodE1hcFRyYW5zZm9ybSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIG1hdGVyaWFsLmFvTWFwICkge1xyXG5cclxuXHRcdFx0dW5pZm9ybXMuYW9NYXAudmFsdWUgPSBtYXRlcmlhbC5hb01hcDtcclxuXHRcdFx0dW5pZm9ybXMuYW9NYXBJbnRlbnNpdHkudmFsdWUgPSBtYXRlcmlhbC5hb01hcEludGVuc2l0eTtcclxuXHJcblx0XHRcdHJlZnJlc2hUcmFuc2Zvcm1Vbmlmb3JtKCBtYXRlcmlhbC5hb01hcCwgdW5pZm9ybXMuYW9NYXBUcmFuc2Zvcm0gKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gcmVmcmVzaFVuaWZvcm1zTGluZSggdW5pZm9ybXMsIG1hdGVyaWFsICkge1xyXG5cclxuXHRcdHVuaWZvcm1zLmRpZmZ1c2UudmFsdWUuY29weSggbWF0ZXJpYWwuY29sb3IgKTtcclxuXHRcdHVuaWZvcm1zLm9wYWNpdHkudmFsdWUgPSBtYXRlcmlhbC5vcGFjaXR5O1xyXG5cclxuXHRcdGlmICggbWF0ZXJpYWwubWFwICkge1xyXG5cclxuXHRcdFx0dW5pZm9ybXMubWFwLnZhbHVlID0gbWF0ZXJpYWwubWFwO1xyXG5cclxuXHRcdFx0cmVmcmVzaFRyYW5zZm9ybVVuaWZvcm0oIG1hdGVyaWFsLm1hcCwgdW5pZm9ybXMubWFwVHJhbnNmb3JtICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHJlZnJlc2hVbmlmb3Jtc0Rhc2goIHVuaWZvcm1zLCBtYXRlcmlhbCApIHtcclxuXHJcblx0XHR1bmlmb3Jtcy5kYXNoU2l6ZS52YWx1ZSA9IG1hdGVyaWFsLmRhc2hTaXplO1xyXG5cdFx0dW5pZm9ybXMudG90YWxTaXplLnZhbHVlID0gbWF0ZXJpYWwuZGFzaFNpemUgKyBtYXRlcmlhbC5nYXBTaXplO1xyXG5cdFx0dW5pZm9ybXMuc2NhbGUudmFsdWUgPSBtYXRlcmlhbC5zY2FsZTtcclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiByZWZyZXNoVW5pZm9ybXNQb2ludHMoIHVuaWZvcm1zLCBtYXRlcmlhbCwgcGl4ZWxSYXRpbywgaGVpZ2h0ICkge1xyXG5cclxuXHRcdHVuaWZvcm1zLmRpZmZ1c2UudmFsdWUuY29weSggbWF0ZXJpYWwuY29sb3IgKTtcclxuXHRcdHVuaWZvcm1zLm9wYWNpdHkudmFsdWUgPSBtYXRlcmlhbC5vcGFjaXR5O1xyXG5cdFx0dW5pZm9ybXMuc2l6ZS52YWx1ZSA9IG1hdGVyaWFsLnNpemUgKiBwaXhlbFJhdGlvO1xyXG5cdFx0dW5pZm9ybXMuc2NhbGUudmFsdWUgPSBoZWlnaHQgKiAwLjU7XHJcblxyXG5cdFx0aWYgKCBtYXRlcmlhbC5tYXAgKSB7XHJcblxyXG5cdFx0XHR1bmlmb3Jtcy5tYXAudmFsdWUgPSBtYXRlcmlhbC5tYXA7XHJcblxyXG5cdFx0XHRyZWZyZXNoVHJhbnNmb3JtVW5pZm9ybSggbWF0ZXJpYWwubWFwLCB1bmlmb3Jtcy51dlRyYW5zZm9ybSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIG1hdGVyaWFsLmFscGhhTWFwICkge1xyXG5cclxuXHRcdFx0dW5pZm9ybXMuYWxwaGFNYXAudmFsdWUgPSBtYXRlcmlhbC5hbHBoYU1hcDtcclxuXHJcblx0XHRcdHJlZnJlc2hUcmFuc2Zvcm1Vbmlmb3JtKCBtYXRlcmlhbC5hbHBoYU1hcCwgdW5pZm9ybXMuYWxwaGFNYXBUcmFuc2Zvcm0gKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBtYXRlcmlhbC5hbHBoYVRlc3QgPiAwICkge1xyXG5cclxuXHRcdFx0dW5pZm9ybXMuYWxwaGFUZXN0LnZhbHVlID0gbWF0ZXJpYWwuYWxwaGFUZXN0O1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiByZWZyZXNoVW5pZm9ybXNTcHJpdGVzKCB1bmlmb3JtcywgbWF0ZXJpYWwgKSB7XHJcblxyXG5cdFx0dW5pZm9ybXMuZGlmZnVzZS52YWx1ZS5jb3B5KCBtYXRlcmlhbC5jb2xvciApO1xyXG5cdFx0dW5pZm9ybXMub3BhY2l0eS52YWx1ZSA9IG1hdGVyaWFsLm9wYWNpdHk7XHJcblx0XHR1bmlmb3Jtcy5yb3RhdGlvbi52YWx1ZSA9IG1hdGVyaWFsLnJvdGF0aW9uO1xyXG5cclxuXHRcdGlmICggbWF0ZXJpYWwubWFwICkge1xyXG5cclxuXHRcdFx0dW5pZm9ybXMubWFwLnZhbHVlID0gbWF0ZXJpYWwubWFwO1xyXG5cclxuXHRcdFx0cmVmcmVzaFRyYW5zZm9ybVVuaWZvcm0oIG1hdGVyaWFsLm1hcCwgdW5pZm9ybXMubWFwVHJhbnNmb3JtICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggbWF0ZXJpYWwuYWxwaGFNYXAgKSB7XHJcblxyXG5cdFx0XHR1bmlmb3Jtcy5hbHBoYU1hcC52YWx1ZSA9IG1hdGVyaWFsLmFscGhhTWFwO1xyXG5cclxuXHRcdFx0cmVmcmVzaFRyYW5zZm9ybVVuaWZvcm0oIG1hdGVyaWFsLmFscGhhTWFwLCB1bmlmb3Jtcy5hbHBoYU1hcFRyYW5zZm9ybSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIG1hdGVyaWFsLmFscGhhVGVzdCA+IDAgKSB7XHJcblxyXG5cdFx0XHR1bmlmb3Jtcy5hbHBoYVRlc3QudmFsdWUgPSBtYXRlcmlhbC5hbHBoYVRlc3Q7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHJlZnJlc2hVbmlmb3Jtc1Bob25nKCB1bmlmb3JtcywgbWF0ZXJpYWwgKSB7XHJcblxyXG5cdFx0dW5pZm9ybXMuc3BlY3VsYXIudmFsdWUuY29weSggbWF0ZXJpYWwuc3BlY3VsYXIgKTtcclxuXHRcdHVuaWZvcm1zLnNoaW5pbmVzcy52YWx1ZSA9IE1hdGgubWF4KCBtYXRlcmlhbC5zaGluaW5lc3MsIDFlLTQgKTsgLy8gdG8gcHJldmVudCBwb3coIDAuMCwgMC4wIClcclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiByZWZyZXNoVW5pZm9ybXNUb29uKCB1bmlmb3JtcywgbWF0ZXJpYWwgKSB7XHJcblxyXG5cdFx0aWYgKCBtYXRlcmlhbC5ncmFkaWVudE1hcCApIHtcclxuXHJcblx0XHRcdHVuaWZvcm1zLmdyYWRpZW50TWFwLnZhbHVlID0gbWF0ZXJpYWwuZ3JhZGllbnRNYXA7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHJlZnJlc2hVbmlmb3Jtc1N0YW5kYXJkKCB1bmlmb3JtcywgbWF0ZXJpYWwgKSB7XHJcblxyXG5cdFx0dW5pZm9ybXMubWV0YWxuZXNzLnZhbHVlID0gbWF0ZXJpYWwubWV0YWxuZXNzO1xyXG5cclxuXHRcdGlmICggbWF0ZXJpYWwubWV0YWxuZXNzTWFwICkge1xyXG5cclxuXHRcdFx0dW5pZm9ybXMubWV0YWxuZXNzTWFwLnZhbHVlID0gbWF0ZXJpYWwubWV0YWxuZXNzTWFwO1xyXG5cclxuXHRcdFx0cmVmcmVzaFRyYW5zZm9ybVVuaWZvcm0oIG1hdGVyaWFsLm1ldGFsbmVzc01hcCwgdW5pZm9ybXMubWV0YWxuZXNzTWFwVHJhbnNmb3JtICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHVuaWZvcm1zLnJvdWdobmVzcy52YWx1ZSA9IG1hdGVyaWFsLnJvdWdobmVzcztcclxuXHJcblx0XHRpZiAoIG1hdGVyaWFsLnJvdWdobmVzc01hcCApIHtcclxuXHJcblx0XHRcdHVuaWZvcm1zLnJvdWdobmVzc01hcC52YWx1ZSA9IG1hdGVyaWFsLnJvdWdobmVzc01hcDtcclxuXHJcblx0XHRcdHJlZnJlc2hUcmFuc2Zvcm1Vbmlmb3JtKCBtYXRlcmlhbC5yb3VnaG5lc3NNYXAsIHVuaWZvcm1zLnJvdWdobmVzc01hcFRyYW5zZm9ybSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCBlbnZNYXAgPSBwcm9wZXJ0aWVzLmdldCggbWF0ZXJpYWwgKS5lbnZNYXA7XHJcblxyXG5cdFx0aWYgKCBlbnZNYXAgKSB7XHJcblxyXG5cdFx0XHQvL3VuaWZvcm1zLmVudk1hcC52YWx1ZSA9IG1hdGVyaWFsLmVudk1hcDsgLy8gcGFydCBvZiB1bmlmb3JtcyBjb21tb25cclxuXHRcdFx0dW5pZm9ybXMuZW52TWFwSW50ZW5zaXR5LnZhbHVlID0gbWF0ZXJpYWwuZW52TWFwSW50ZW5zaXR5O1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiByZWZyZXNoVW5pZm9ybXNQaHlzaWNhbCggdW5pZm9ybXMsIG1hdGVyaWFsLCB0cmFuc21pc3Npb25SZW5kZXJUYXJnZXQgKSB7XHJcblxyXG5cdFx0dW5pZm9ybXMuaW9yLnZhbHVlID0gbWF0ZXJpYWwuaW9yOyAvLyBhbHNvIHBhcnQgb2YgdW5pZm9ybXMgY29tbW9uXHJcblxyXG5cdFx0aWYgKCBtYXRlcmlhbC5zaGVlbiA+IDAgKSB7XHJcblxyXG5cdFx0XHR1bmlmb3Jtcy5zaGVlbkNvbG9yLnZhbHVlLmNvcHkoIG1hdGVyaWFsLnNoZWVuQ29sb3IgKS5tdWx0aXBseVNjYWxhciggbWF0ZXJpYWwuc2hlZW4gKTtcclxuXHJcblx0XHRcdHVuaWZvcm1zLnNoZWVuUm91Z2huZXNzLnZhbHVlID0gbWF0ZXJpYWwuc2hlZW5Sb3VnaG5lc3M7XHJcblxyXG5cdFx0XHRpZiAoIG1hdGVyaWFsLnNoZWVuQ29sb3JNYXAgKSB7XHJcblxyXG5cdFx0XHRcdHVuaWZvcm1zLnNoZWVuQ29sb3JNYXAudmFsdWUgPSBtYXRlcmlhbC5zaGVlbkNvbG9yTWFwO1xyXG5cclxuXHRcdFx0XHRyZWZyZXNoVHJhbnNmb3JtVW5pZm9ybSggbWF0ZXJpYWwuc2hlZW5Db2xvck1hcCwgdW5pZm9ybXMuc2hlZW5Db2xvck1hcFRyYW5zZm9ybSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0aWYgKCBtYXRlcmlhbC5zaGVlblJvdWdobmVzc01hcCApIHtcclxuXHJcblx0XHRcdFx0dW5pZm9ybXMuc2hlZW5Sb3VnaG5lc3NNYXAudmFsdWUgPSBtYXRlcmlhbC5zaGVlblJvdWdobmVzc01hcDtcclxuXHJcblx0XHRcdFx0cmVmcmVzaFRyYW5zZm9ybVVuaWZvcm0oIG1hdGVyaWFsLnNoZWVuUm91Z2huZXNzTWFwLCB1bmlmb3Jtcy5zaGVlblJvdWdobmVzc01hcFRyYW5zZm9ybSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIG1hdGVyaWFsLmNsZWFyY29hdCA+IDAgKSB7XHJcblxyXG5cdFx0XHR1bmlmb3Jtcy5jbGVhcmNvYXQudmFsdWUgPSBtYXRlcmlhbC5jbGVhcmNvYXQ7XHJcblx0XHRcdHVuaWZvcm1zLmNsZWFyY29hdFJvdWdobmVzcy52YWx1ZSA9IG1hdGVyaWFsLmNsZWFyY29hdFJvdWdobmVzcztcclxuXHJcblx0XHRcdGlmICggbWF0ZXJpYWwuY2xlYXJjb2F0TWFwICkge1xyXG5cclxuXHRcdFx0XHR1bmlmb3Jtcy5jbGVhcmNvYXRNYXAudmFsdWUgPSBtYXRlcmlhbC5jbGVhcmNvYXRNYXA7XHJcblxyXG5cdFx0XHRcdHJlZnJlc2hUcmFuc2Zvcm1Vbmlmb3JtKCBtYXRlcmlhbC5jbGVhcmNvYXRNYXAsIHVuaWZvcm1zLmNsZWFyY29hdE1hcFRyYW5zZm9ybSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0aWYgKCBtYXRlcmlhbC5jbGVhcmNvYXRSb3VnaG5lc3NNYXAgKSB7XHJcblxyXG5cdFx0XHRcdHVuaWZvcm1zLmNsZWFyY29hdFJvdWdobmVzc01hcC52YWx1ZSA9IG1hdGVyaWFsLmNsZWFyY29hdFJvdWdobmVzc01hcDtcclxuXHJcblx0XHRcdFx0cmVmcmVzaFRyYW5zZm9ybVVuaWZvcm0oIG1hdGVyaWFsLmNsZWFyY29hdFJvdWdobmVzc01hcCwgdW5pZm9ybXMuY2xlYXJjb2F0Um91Z2huZXNzTWFwVHJhbnNmb3JtICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRpZiAoIG1hdGVyaWFsLmNsZWFyY29hdE5vcm1hbE1hcCApIHtcclxuXHJcblx0XHRcdFx0dW5pZm9ybXMuY2xlYXJjb2F0Tm9ybWFsTWFwLnZhbHVlID0gbWF0ZXJpYWwuY2xlYXJjb2F0Tm9ybWFsTWFwO1xyXG5cclxuXHRcdFx0XHRyZWZyZXNoVHJhbnNmb3JtVW5pZm9ybSggbWF0ZXJpYWwuY2xlYXJjb2F0Tm9ybWFsTWFwLCB1bmlmb3Jtcy5jbGVhcmNvYXROb3JtYWxNYXBUcmFuc2Zvcm0gKTtcclxuXHJcblx0XHRcdFx0dW5pZm9ybXMuY2xlYXJjb2F0Tm9ybWFsU2NhbGUudmFsdWUuY29weSggbWF0ZXJpYWwuY2xlYXJjb2F0Tm9ybWFsU2NhbGUgKTtcclxuXHJcblx0XHRcdFx0aWYgKCBtYXRlcmlhbC5zaWRlID09PSBCYWNrU2lkZSApIHtcclxuXHJcblx0XHRcdFx0XHR1bmlmb3Jtcy5jbGVhcmNvYXROb3JtYWxTY2FsZS52YWx1ZS5uZWdhdGUoKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIG1hdGVyaWFsLmlyaWRlc2NlbmNlID4gMCApIHtcclxuXHJcblx0XHRcdHVuaWZvcm1zLmlyaWRlc2NlbmNlLnZhbHVlID0gbWF0ZXJpYWwuaXJpZGVzY2VuY2U7XHJcblx0XHRcdHVuaWZvcm1zLmlyaWRlc2NlbmNlSU9SLnZhbHVlID0gbWF0ZXJpYWwuaXJpZGVzY2VuY2VJT1I7XHJcblx0XHRcdHVuaWZvcm1zLmlyaWRlc2NlbmNlVGhpY2tuZXNzTWluaW11bS52YWx1ZSA9IG1hdGVyaWFsLmlyaWRlc2NlbmNlVGhpY2tuZXNzUmFuZ2VbIDAgXTtcclxuXHRcdFx0dW5pZm9ybXMuaXJpZGVzY2VuY2VUaGlja25lc3NNYXhpbXVtLnZhbHVlID0gbWF0ZXJpYWwuaXJpZGVzY2VuY2VUaGlja25lc3NSYW5nZVsgMSBdO1xyXG5cclxuXHRcdFx0aWYgKCBtYXRlcmlhbC5pcmlkZXNjZW5jZU1hcCApIHtcclxuXHJcblx0XHRcdFx0dW5pZm9ybXMuaXJpZGVzY2VuY2VNYXAudmFsdWUgPSBtYXRlcmlhbC5pcmlkZXNjZW5jZU1hcDtcclxuXHJcblx0XHRcdFx0cmVmcmVzaFRyYW5zZm9ybVVuaWZvcm0oIG1hdGVyaWFsLmlyaWRlc2NlbmNlTWFwLCB1bmlmb3Jtcy5pcmlkZXNjZW5jZU1hcFRyYW5zZm9ybSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0aWYgKCBtYXRlcmlhbC5pcmlkZXNjZW5jZVRoaWNrbmVzc01hcCApIHtcclxuXHJcblx0XHRcdFx0dW5pZm9ybXMuaXJpZGVzY2VuY2VUaGlja25lc3NNYXAudmFsdWUgPSBtYXRlcmlhbC5pcmlkZXNjZW5jZVRoaWNrbmVzc01hcDtcclxuXHJcblx0XHRcdFx0cmVmcmVzaFRyYW5zZm9ybVVuaWZvcm0oIG1hdGVyaWFsLmlyaWRlc2NlbmNlVGhpY2tuZXNzTWFwLCB1bmlmb3Jtcy5pcmlkZXNjZW5jZVRoaWNrbmVzc01hcFRyYW5zZm9ybSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIG1hdGVyaWFsLnRyYW5zbWlzc2lvbiA+IDAgKSB7XHJcblxyXG5cdFx0XHR1bmlmb3Jtcy50cmFuc21pc3Npb24udmFsdWUgPSBtYXRlcmlhbC50cmFuc21pc3Npb247XHJcblx0XHRcdHVuaWZvcm1zLnRyYW5zbWlzc2lvblNhbXBsZXJNYXAudmFsdWUgPSB0cmFuc21pc3Npb25SZW5kZXJUYXJnZXQudGV4dHVyZTtcclxuXHRcdFx0dW5pZm9ybXMudHJhbnNtaXNzaW9uU2FtcGxlclNpemUudmFsdWUuc2V0KCB0cmFuc21pc3Npb25SZW5kZXJUYXJnZXQud2lkdGgsIHRyYW5zbWlzc2lvblJlbmRlclRhcmdldC5oZWlnaHQgKTtcclxuXHJcblx0XHRcdGlmICggbWF0ZXJpYWwudHJhbnNtaXNzaW9uTWFwICkge1xyXG5cclxuXHRcdFx0XHR1bmlmb3Jtcy50cmFuc21pc3Npb25NYXAudmFsdWUgPSBtYXRlcmlhbC50cmFuc21pc3Npb25NYXA7XHJcblxyXG5cdFx0XHRcdHJlZnJlc2hUcmFuc2Zvcm1Vbmlmb3JtKCBtYXRlcmlhbC50cmFuc21pc3Npb25NYXAsIHVuaWZvcm1zLnRyYW5zbWlzc2lvbk1hcFRyYW5zZm9ybSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0dW5pZm9ybXMudGhpY2tuZXNzLnZhbHVlID0gbWF0ZXJpYWwudGhpY2tuZXNzO1xyXG5cclxuXHRcdFx0aWYgKCBtYXRlcmlhbC50aGlja25lc3NNYXAgKSB7XHJcblxyXG5cdFx0XHRcdHVuaWZvcm1zLnRoaWNrbmVzc01hcC52YWx1ZSA9IG1hdGVyaWFsLnRoaWNrbmVzc01hcDtcclxuXHJcblx0XHRcdFx0cmVmcmVzaFRyYW5zZm9ybVVuaWZvcm0oIG1hdGVyaWFsLnRoaWNrbmVzc01hcCwgdW5pZm9ybXMudGhpY2tuZXNzTWFwVHJhbnNmb3JtICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHR1bmlmb3Jtcy5hdHRlbnVhdGlvbkRpc3RhbmNlLnZhbHVlID0gbWF0ZXJpYWwuYXR0ZW51YXRpb25EaXN0YW5jZTtcclxuXHRcdFx0dW5pZm9ybXMuYXR0ZW51YXRpb25Db2xvci52YWx1ZS5jb3B5KCBtYXRlcmlhbC5hdHRlbnVhdGlvbkNvbG9yICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggbWF0ZXJpYWwuYW5pc290cm9weSA+IDAgKSB7XHJcblxyXG5cdFx0XHR1bmlmb3Jtcy5hbmlzb3Ryb3B5VmVjdG9yLnZhbHVlLnNldCggbWF0ZXJpYWwuYW5pc290cm9weSAqIE1hdGguY29zKCBtYXRlcmlhbC5hbmlzb3Ryb3B5Um90YXRpb24gKSwgbWF0ZXJpYWwuYW5pc290cm9weSAqIE1hdGguc2luKCBtYXRlcmlhbC5hbmlzb3Ryb3B5Um90YXRpb24gKSApO1xyXG5cclxuXHRcdFx0aWYgKCBtYXRlcmlhbC5hbmlzb3Ryb3B5TWFwICkge1xyXG5cclxuXHRcdFx0XHR1bmlmb3Jtcy5hbmlzb3Ryb3B5TWFwLnZhbHVlID0gbWF0ZXJpYWwuYW5pc290cm9weU1hcDtcclxuXHJcblx0XHRcdFx0cmVmcmVzaFRyYW5zZm9ybVVuaWZvcm0oIG1hdGVyaWFsLmFuaXNvdHJvcHlNYXAsIHVuaWZvcm1zLmFuaXNvdHJvcHlNYXBUcmFuc2Zvcm0gKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dW5pZm9ybXMuc3BlY3VsYXJJbnRlbnNpdHkudmFsdWUgPSBtYXRlcmlhbC5zcGVjdWxhckludGVuc2l0eTtcclxuXHRcdHVuaWZvcm1zLnNwZWN1bGFyQ29sb3IudmFsdWUuY29weSggbWF0ZXJpYWwuc3BlY3VsYXJDb2xvciApO1xyXG5cclxuXHRcdGlmICggbWF0ZXJpYWwuc3BlY3VsYXJDb2xvck1hcCApIHtcclxuXHJcblx0XHRcdHVuaWZvcm1zLnNwZWN1bGFyQ29sb3JNYXAudmFsdWUgPSBtYXRlcmlhbC5zcGVjdWxhckNvbG9yTWFwO1xyXG5cclxuXHRcdFx0cmVmcmVzaFRyYW5zZm9ybVVuaWZvcm0oIG1hdGVyaWFsLnNwZWN1bGFyQ29sb3JNYXAsIHVuaWZvcm1zLnNwZWN1bGFyQ29sb3JNYXBUcmFuc2Zvcm0gKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBtYXRlcmlhbC5zcGVjdWxhckludGVuc2l0eU1hcCApIHtcclxuXHJcblx0XHRcdHVuaWZvcm1zLnNwZWN1bGFySW50ZW5zaXR5TWFwLnZhbHVlID0gbWF0ZXJpYWwuc3BlY3VsYXJJbnRlbnNpdHlNYXA7XHJcblxyXG5cdFx0XHRyZWZyZXNoVHJhbnNmb3JtVW5pZm9ybSggbWF0ZXJpYWwuc3BlY3VsYXJJbnRlbnNpdHlNYXAsIHVuaWZvcm1zLnNwZWN1bGFySW50ZW5zaXR5TWFwVHJhbnNmb3JtICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHJlZnJlc2hVbmlmb3Jtc01hdGNhcCggdW5pZm9ybXMsIG1hdGVyaWFsICkge1xyXG5cclxuXHRcdGlmICggbWF0ZXJpYWwubWF0Y2FwICkge1xyXG5cclxuXHRcdFx0dW5pZm9ybXMubWF0Y2FwLnZhbHVlID0gbWF0ZXJpYWwubWF0Y2FwO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiByZWZyZXNoVW5pZm9ybXNEaXN0YW5jZSggdW5pZm9ybXMsIG1hdGVyaWFsICkge1xyXG5cclxuXHRcdGNvbnN0IGxpZ2h0ID0gcHJvcGVydGllcy5nZXQoIG1hdGVyaWFsICkubGlnaHQ7XHJcblxyXG5cdFx0dW5pZm9ybXMucmVmZXJlbmNlUG9zaXRpb24udmFsdWUuc2V0RnJvbU1hdHJpeFBvc2l0aW9uKCBsaWdodC5tYXRyaXhXb3JsZCApO1xyXG5cdFx0dW5pZm9ybXMubmVhckRpc3RhbmNlLnZhbHVlID0gbGlnaHQuc2hhZG93LmNhbWVyYS5uZWFyO1xyXG5cdFx0dW5pZm9ybXMuZmFyRGlzdGFuY2UudmFsdWUgPSBsaWdodC5zaGFkb3cuY2FtZXJhLmZhcjtcclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4ge1xyXG5cdFx0cmVmcmVzaEZvZ1VuaWZvcm1zOiByZWZyZXNoRm9nVW5pZm9ybXMsXHJcblx0XHRyZWZyZXNoTWF0ZXJpYWxVbmlmb3JtczogcmVmcmVzaE1hdGVyaWFsVW5pZm9ybXNcclxuXHR9O1xyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgV2ViR0xNYXRlcmlhbHMgfTtcclxuIiwiZnVuY3Rpb24gV2ViR0xVbmlmb3Jtc0dyb3VwcyggZ2wsIGluZm8sIGNhcGFiaWxpdGllcywgc3RhdGUgKSB7XHJcblxyXG5cdGxldCBidWZmZXJzID0ge307XHJcblx0bGV0IHVwZGF0ZUxpc3QgPSB7fTtcclxuXHRsZXQgYWxsb2NhdGVkQmluZGluZ1BvaW50cyA9IFtdO1xyXG5cclxuXHRjb25zdCBtYXhCaW5kaW5nUG9pbnRzID0gKCBjYXBhYmlsaXRpZXMuaXNXZWJHTDIgKSA/IGdsLmdldFBhcmFtZXRlciggZ2wuTUFYX1VOSUZPUk1fQlVGRkVSX0JJTkRJTkdTICkgOiAwOyAvLyBiaW5kaW5nIHBvaW50cyBhcmUgZ2xvYmFsIHdoZXJlYXMgYmxvY2sgaW5kaWNlcyBhcmUgcGVyIHNoYWRlciBwcm9ncmFtXHJcblxyXG5cdGZ1bmN0aW9uIGJpbmQoIHVuaWZvcm1zR3JvdXAsIHByb2dyYW0gKSB7XHJcblxyXG5cdFx0Y29uc3Qgd2ViZ2xQcm9ncmFtID0gcHJvZ3JhbS5wcm9ncmFtO1xyXG5cdFx0c3RhdGUudW5pZm9ybUJsb2NrQmluZGluZyggdW5pZm9ybXNHcm91cCwgd2ViZ2xQcm9ncmFtICk7XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gdXBkYXRlKCB1bmlmb3Jtc0dyb3VwLCBwcm9ncmFtICkge1xyXG5cclxuXHRcdGxldCBidWZmZXIgPSBidWZmZXJzWyB1bmlmb3Jtc0dyb3VwLmlkIF07XHJcblxyXG5cdFx0aWYgKCBidWZmZXIgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdHByZXBhcmVVbmlmb3Jtc0dyb3VwKCB1bmlmb3Jtc0dyb3VwICk7XHJcblxyXG5cdFx0XHRidWZmZXIgPSBjcmVhdGVCdWZmZXIoIHVuaWZvcm1zR3JvdXAgKTtcclxuXHRcdFx0YnVmZmVyc1sgdW5pZm9ybXNHcm91cC5pZCBdID0gYnVmZmVyO1xyXG5cclxuXHRcdFx0dW5pZm9ybXNHcm91cC5hZGRFdmVudExpc3RlbmVyKCAnZGlzcG9zZScsIG9uVW5pZm9ybXNHcm91cHNEaXNwb3NlICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIGVuc3VyZSB0byB1cGRhdGUgdGhlIGJpbmRpbmcgcG9pbnRzL2Jsb2NrIGluZGljZXMgbWFwcGluZyBmb3IgdGhpcyBwcm9ncmFtXHJcblxyXG5cdFx0Y29uc3Qgd2ViZ2xQcm9ncmFtID0gcHJvZ3JhbS5wcm9ncmFtO1xyXG5cdFx0c3RhdGUudXBkYXRlVUJPTWFwcGluZyggdW5pZm9ybXNHcm91cCwgd2ViZ2xQcm9ncmFtICk7XHJcblxyXG5cdFx0Ly8gdXBkYXRlIFVCTyBvbmNlIHBlciBmcmFtZVxyXG5cclxuXHRcdGNvbnN0IGZyYW1lID0gaW5mby5yZW5kZXIuZnJhbWU7XHJcblxyXG5cdFx0aWYgKCB1cGRhdGVMaXN0WyB1bmlmb3Jtc0dyb3VwLmlkIF0gIT09IGZyYW1lICkge1xyXG5cclxuXHRcdFx0dXBkYXRlQnVmZmVyRGF0YSggdW5pZm9ybXNHcm91cCApO1xyXG5cclxuXHRcdFx0dXBkYXRlTGlzdFsgdW5pZm9ybXNHcm91cC5pZCBdID0gZnJhbWU7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIGNyZWF0ZUJ1ZmZlciggdW5pZm9ybXNHcm91cCApIHtcclxuXHJcblx0XHQvLyB0aGUgc2V0dXAgb2YgYW4gVUJPIGlzIGluZGVwZW5kZW50IG9mIGEgcGFydGljdWxhciBzaGFkZXIgcHJvZ3JhbSBidXQgZ2xvYmFsXHJcblxyXG5cdFx0Y29uc3QgYmluZGluZ1BvaW50SW5kZXggPSBhbGxvY2F0ZUJpbmRpbmdQb2ludEluZGV4KCk7XHJcblx0XHR1bmlmb3Jtc0dyb3VwLl9fYmluZGluZ1BvaW50SW5kZXggPSBiaW5kaW5nUG9pbnRJbmRleDtcclxuXHJcblx0XHRjb25zdCBidWZmZXIgPSBnbC5jcmVhdGVCdWZmZXIoKTtcclxuXHRcdGNvbnN0IHNpemUgPSB1bmlmb3Jtc0dyb3VwLl9fc2l6ZTtcclxuXHRcdGNvbnN0IHVzYWdlID0gdW5pZm9ybXNHcm91cC51c2FnZTtcclxuXHJcblx0XHRnbC5iaW5kQnVmZmVyKCBnbC5VTklGT1JNX0JVRkZFUiwgYnVmZmVyICk7XHJcblx0XHRnbC5idWZmZXJEYXRhKCBnbC5VTklGT1JNX0JVRkZFUiwgc2l6ZSwgdXNhZ2UgKTtcclxuXHRcdGdsLmJpbmRCdWZmZXIoIGdsLlVOSUZPUk1fQlVGRkVSLCBudWxsICk7XHJcblx0XHRnbC5iaW5kQnVmZmVyQmFzZSggZ2wuVU5JRk9STV9CVUZGRVIsIGJpbmRpbmdQb2ludEluZGV4LCBidWZmZXIgKTtcclxuXHJcblx0XHRyZXR1cm4gYnVmZmVyO1xyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIGFsbG9jYXRlQmluZGluZ1BvaW50SW5kZXgoKSB7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgbWF4QmluZGluZ1BvaW50czsgaSArKyApIHtcclxuXHJcblx0XHRcdGlmICggYWxsb2NhdGVkQmluZGluZ1BvaW50cy5pbmRleE9mKCBpICkgPT09IC0gMSApIHtcclxuXHJcblx0XHRcdFx0YWxsb2NhdGVkQmluZGluZ1BvaW50cy5wdXNoKCBpICk7XHJcblx0XHRcdFx0cmV0dXJuIGk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5XZWJHTFJlbmRlcmVyOiBNYXhpbXVtIG51bWJlciBvZiBzaW11bHRhbmVvdXNseSB1c2FibGUgdW5pZm9ybXMgZ3JvdXBzIHJlYWNoZWQuJyApO1xyXG5cclxuXHRcdHJldHVybiAwO1xyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHVwZGF0ZUJ1ZmZlckRhdGEoIHVuaWZvcm1zR3JvdXAgKSB7XHJcblxyXG5cdFx0Y29uc3QgYnVmZmVyID0gYnVmZmVyc1sgdW5pZm9ybXNHcm91cC5pZCBdO1xyXG5cdFx0Y29uc3QgdW5pZm9ybXMgPSB1bmlmb3Jtc0dyb3VwLnVuaWZvcm1zO1xyXG5cdFx0Y29uc3QgY2FjaGUgPSB1bmlmb3Jtc0dyb3VwLl9fY2FjaGU7XHJcblxyXG5cdFx0Z2wuYmluZEJ1ZmZlciggZ2wuVU5JRk9STV9CVUZGRVIsIGJ1ZmZlciApO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSB1bmlmb3Jtcy5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcclxuXHJcblx0XHRcdGNvbnN0IHVuaWZvcm1BcnJheSA9IEFycmF5LmlzQXJyYXkoIHVuaWZvcm1zWyBpIF0gKSA/IHVuaWZvcm1zWyBpIF0gOiBbIHVuaWZvcm1zWyBpIF0gXTtcclxuXHJcblx0XHRcdGZvciAoIGxldCBqID0gMCwgamwgPSB1bmlmb3JtQXJyYXkubGVuZ3RoOyBqIDwgamw7IGogKysgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IHVuaWZvcm0gPSB1bmlmb3JtQXJyYXlbIGogXTtcclxuXHJcblx0XHRcdFx0aWYgKCBoYXNVbmlmb3JtQ2hhbmdlZCggdW5pZm9ybSwgaSwgaiwgY2FjaGUgKSA9PT0gdHJ1ZSApIHtcclxuXHJcblx0XHRcdFx0XHRjb25zdCBvZmZzZXQgPSB1bmlmb3JtLl9fb2Zmc2V0O1xyXG5cclxuXHRcdFx0XHRcdGNvbnN0IHZhbHVlcyA9IEFycmF5LmlzQXJyYXkoIHVuaWZvcm0udmFsdWUgKSA/IHVuaWZvcm0udmFsdWUgOiBbIHVuaWZvcm0udmFsdWUgXTtcclxuXHJcblx0XHRcdFx0XHRsZXQgYXJyYXlPZmZzZXQgPSAwO1xyXG5cclxuXHRcdFx0XHRcdGZvciAoIGxldCBrID0gMDsgayA8IHZhbHVlcy5sZW5ndGg7IGsgKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRjb25zdCB2YWx1ZSA9IHZhbHVlc1sgayBdO1xyXG5cclxuXHRcdFx0XHRcdFx0Y29uc3QgaW5mbyA9IGdldFVuaWZvcm1TaXplKCB2YWx1ZSApO1xyXG5cclxuXHRcdFx0XHRcdFx0Ly8gVE9ETyBhZGQgaW50ZWdlciBhbmQgc3RydWN0IHN1cHBvcnRcclxuXHRcdFx0XHRcdFx0aWYgKCB0eXBlb2YgdmFsdWUgPT09ICdudW1iZXInIHx8IHR5cGVvZiB2YWx1ZSA9PT0gJ2Jvb2xlYW4nICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHR1bmlmb3JtLl9fZGF0YVsgMCBdID0gdmFsdWU7XHJcblx0XHRcdFx0XHRcdFx0Z2wuYnVmZmVyU3ViRGF0YSggZ2wuVU5JRk9STV9CVUZGRVIsIG9mZnNldCArIGFycmF5T2Zmc2V0LCB1bmlmb3JtLl9fZGF0YSApO1xyXG5cclxuXHRcdFx0XHRcdFx0fSBlbHNlIGlmICggdmFsdWUuaXNNYXRyaXgzICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHQvLyBtYW51YWxseSBjb252ZXJ0aW5nIDN4MyB0byAzeDRcclxuXHJcblx0XHRcdFx0XHRcdFx0dW5pZm9ybS5fX2RhdGFbIDAgXSA9IHZhbHVlLmVsZW1lbnRzWyAwIF07XHJcblx0XHRcdFx0XHRcdFx0dW5pZm9ybS5fX2RhdGFbIDEgXSA9IHZhbHVlLmVsZW1lbnRzWyAxIF07XHJcblx0XHRcdFx0XHRcdFx0dW5pZm9ybS5fX2RhdGFbIDIgXSA9IHZhbHVlLmVsZW1lbnRzWyAyIF07XHJcblx0XHRcdFx0XHRcdFx0dW5pZm9ybS5fX2RhdGFbIDMgXSA9IDA7XHJcblx0XHRcdFx0XHRcdFx0dW5pZm9ybS5fX2RhdGFbIDQgXSA9IHZhbHVlLmVsZW1lbnRzWyAzIF07XHJcblx0XHRcdFx0XHRcdFx0dW5pZm9ybS5fX2RhdGFbIDUgXSA9IHZhbHVlLmVsZW1lbnRzWyA0IF07XHJcblx0XHRcdFx0XHRcdFx0dW5pZm9ybS5fX2RhdGFbIDYgXSA9IHZhbHVlLmVsZW1lbnRzWyA1IF07XHJcblx0XHRcdFx0XHRcdFx0dW5pZm9ybS5fX2RhdGFbIDcgXSA9IDA7XHJcblx0XHRcdFx0XHRcdFx0dW5pZm9ybS5fX2RhdGFbIDggXSA9IHZhbHVlLmVsZW1lbnRzWyA2IF07XHJcblx0XHRcdFx0XHRcdFx0dW5pZm9ybS5fX2RhdGFbIDkgXSA9IHZhbHVlLmVsZW1lbnRzWyA3IF07XHJcblx0XHRcdFx0XHRcdFx0dW5pZm9ybS5fX2RhdGFbIDEwIF0gPSB2YWx1ZS5lbGVtZW50c1sgOCBdO1xyXG5cdFx0XHRcdFx0XHRcdHVuaWZvcm0uX19kYXRhWyAxMSBdID0gMDtcclxuXHJcblx0XHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdHZhbHVlLnRvQXJyYXkoIHVuaWZvcm0uX19kYXRhLCBhcnJheU9mZnNldCApO1xyXG5cclxuXHRcdFx0XHRcdFx0XHRhcnJheU9mZnNldCArPSBpbmZvLnN0b3JhZ2UgLyBGbG9hdDMyQXJyYXkuQllURVNfUEVSX0VMRU1FTlQ7XHJcblxyXG5cdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdGdsLmJ1ZmZlclN1YkRhdGEoIGdsLlVOSUZPUk1fQlVGRkVSLCBvZmZzZXQsIHVuaWZvcm0uX19kYXRhICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Z2wuYmluZEJ1ZmZlciggZ2wuVU5JRk9STV9CVUZGRVIsIG51bGwgKTtcclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBoYXNVbmlmb3JtQ2hhbmdlZCggdW5pZm9ybSwgaW5kZXgsIGluZGV4QXJyYXksIGNhY2hlICkge1xyXG5cclxuXHRcdGNvbnN0IHZhbHVlID0gdW5pZm9ybS52YWx1ZTtcclxuXHRcdGNvbnN0IGluZGV4U3RyaW5nID0gaW5kZXggKyAnXycgKyBpbmRleEFycmF5O1xyXG5cclxuXHRcdGlmICggY2FjaGVbIGluZGV4U3RyaW5nIF0gPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdC8vIGNhY2hlIGVudHJ5IGRvZXMgbm90IGV4aXN0IHNvIGZhclxyXG5cclxuXHRcdFx0aWYgKCB0eXBlb2YgdmFsdWUgPT09ICdudW1iZXInIHx8IHR5cGVvZiB2YWx1ZSA9PT0gJ2Jvb2xlYW4nICkge1xyXG5cclxuXHRcdFx0XHRjYWNoZVsgaW5kZXhTdHJpbmcgXSA9IHZhbHVlO1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0Y2FjaGVbIGluZGV4U3RyaW5nIF0gPSB2YWx1ZS5jbG9uZSgpO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0cmV0dXJuIHRydWU7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdGNvbnN0IGNhY2hlZE9iamVjdCA9IGNhY2hlWyBpbmRleFN0cmluZyBdO1xyXG5cclxuXHRcdFx0Ly8gY29tcGFyZSBjdXJyZW50IHZhbHVlIHdpdGggY2FjaGVkIGVudHJ5XHJcblxyXG5cdFx0XHRpZiAoIHR5cGVvZiB2YWx1ZSA9PT0gJ251bWJlcicgfHwgdHlwZW9mIHZhbHVlID09PSAnYm9vbGVhbicgKSB7XHJcblxyXG5cdFx0XHRcdGlmICggY2FjaGVkT2JqZWN0ICE9PSB2YWx1ZSApIHtcclxuXHJcblx0XHRcdFx0XHRjYWNoZVsgaW5kZXhTdHJpbmcgXSA9IHZhbHVlO1xyXG5cdFx0XHRcdFx0cmV0dXJuIHRydWU7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdGlmICggY2FjaGVkT2JqZWN0LmVxdWFscyggdmFsdWUgKSA9PT0gZmFsc2UgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y2FjaGVkT2JqZWN0LmNvcHkoIHZhbHVlICk7XHJcblx0XHRcdFx0XHRyZXR1cm4gdHJ1ZTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gZmFsc2U7XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gcHJlcGFyZVVuaWZvcm1zR3JvdXAoIHVuaWZvcm1zR3JvdXAgKSB7XHJcblxyXG5cdFx0Ly8gZGV0ZXJtaW5lIHRvdGFsIGJ1ZmZlciBzaXplIGFjY29yZGluZyB0byB0aGUgU1REMTQwIGxheW91dFxyXG5cdFx0Ly8gSGludDogU1REMTQwIGlzIHRoZSBvbmx5IHN1cHBvcnRlZCBsYXlvdXQgaW4gV2ViR0wgMlxyXG5cclxuXHRcdGNvbnN0IHVuaWZvcm1zID0gdW5pZm9ybXNHcm91cC51bmlmb3JtcztcclxuXHJcblx0XHRsZXQgb2Zmc2V0ID0gMDsgLy8gZ2xvYmFsIGJ1ZmZlciBvZmZzZXQgaW4gYnl0ZXNcclxuXHRcdGNvbnN0IGNodW5rU2l6ZSA9IDE2OyAvLyBzaXplIG9mIGEgY2h1bmsgaW4gYnl0ZXNcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSB1bmlmb3Jtcy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0Y29uc3QgdW5pZm9ybUFycmF5ID0gQXJyYXkuaXNBcnJheSggdW5pZm9ybXNbIGkgXSApID8gdW5pZm9ybXNbIGkgXSA6IFsgdW5pZm9ybXNbIGkgXSBdO1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGogPSAwLCBqbCA9IHVuaWZvcm1BcnJheS5sZW5ndGg7IGogPCBqbDsgaiArKyApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgdW5pZm9ybSA9IHVuaWZvcm1BcnJheVsgaiBdO1xyXG5cclxuXHRcdFx0XHRjb25zdCB2YWx1ZXMgPSBBcnJheS5pc0FycmF5KCB1bmlmb3JtLnZhbHVlICkgPyB1bmlmb3JtLnZhbHVlIDogWyB1bmlmb3JtLnZhbHVlIF07XHJcblxyXG5cdFx0XHRcdGZvciAoIGxldCBrID0gMCwga2wgPSB2YWx1ZXMubGVuZ3RoOyBrIDwga2w7IGsgKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgdmFsdWUgPSB2YWx1ZXNbIGsgXTtcclxuXHJcblx0XHRcdFx0XHRjb25zdCBpbmZvID0gZ2V0VW5pZm9ybVNpemUoIHZhbHVlICk7XHJcblxyXG5cdFx0XHRcdFx0Ly8gQ2FsY3VsYXRlIHRoZSBjaHVuayBvZmZzZXRcclxuXHRcdFx0XHRcdGNvbnN0IGNodW5rT2Zmc2V0VW5pZm9ybSA9IG9mZnNldCAlIGNodW5rU2l6ZTtcclxuXHJcblx0XHRcdFx0XHQvLyBDaGVjayBmb3IgY2h1bmsgb3ZlcmZsb3dcclxuXHRcdFx0XHRcdGlmICggY2h1bmtPZmZzZXRVbmlmb3JtICE9PSAwICYmICggY2h1bmtTaXplIC0gY2h1bmtPZmZzZXRVbmlmb3JtICkgPCBpbmZvLmJvdW5kYXJ5ICkge1xyXG5cclxuXHRcdFx0XHRcdFx0Ly8gQWRkIHBhZGRpbmcgYW5kIGFkanVzdCBvZmZzZXRcclxuXHRcdFx0XHRcdFx0b2Zmc2V0ICs9ICggY2h1bmtTaXplIC0gY2h1bmtPZmZzZXRVbmlmb3JtICk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdC8vIHRoZSBmb2xsb3dpbmcgdHdvIHByb3BlcnRpZXMgd2lsbCBiZSB1c2VkIGZvciBwYXJ0aWFsIGJ1ZmZlciB1cGRhdGVzXHJcblxyXG5cdFx0XHRcdFx0dW5pZm9ybS5fX2RhdGEgPSBuZXcgRmxvYXQzMkFycmF5KCBpbmZvLnN0b3JhZ2UgLyBGbG9hdDMyQXJyYXkuQllURVNfUEVSX0VMRU1FTlQgKTtcclxuXHRcdFx0XHRcdHVuaWZvcm0uX19vZmZzZXQgPSBvZmZzZXQ7XHJcblxyXG5cclxuXHRcdFx0XHRcdC8vIFVwZGF0ZSB0aGUgZ2xvYmFsIG9mZnNldFxyXG5cdFx0XHRcdFx0b2Zmc2V0ICs9IGluZm8uc3RvcmFnZTtcclxuXHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gZW5zdXJlIGNvcnJlY3QgZmluYWwgcGFkZGluZ1xyXG5cclxuXHRcdGNvbnN0IGNodW5rT2Zmc2V0ID0gb2Zmc2V0ICUgY2h1bmtTaXplO1xyXG5cclxuXHRcdGlmICggY2h1bmtPZmZzZXQgPiAwICkgb2Zmc2V0ICs9ICggY2h1bmtTaXplIC0gY2h1bmtPZmZzZXQgKTtcclxuXHJcblx0XHQvL1xyXG5cclxuXHRcdHVuaWZvcm1zR3JvdXAuX19zaXplID0gb2Zmc2V0O1xyXG5cdFx0dW5pZm9ybXNHcm91cC5fX2NhY2hlID0ge307XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gZ2V0VW5pZm9ybVNpemUoIHZhbHVlICkge1xyXG5cclxuXHRcdGNvbnN0IGluZm8gPSB7XHJcblx0XHRcdGJvdW5kYXJ5OiAwLCAvLyBieXRlc1xyXG5cdFx0XHRzdG9yYWdlOiAwIC8vIGJ5dGVzXHJcblx0XHR9O1xyXG5cclxuXHRcdC8vIGRldGVybWluZSBzaXplcyBhY2NvcmRpbmcgdG8gU1REMTQwXHJcblxyXG5cdFx0aWYgKCB0eXBlb2YgdmFsdWUgPT09ICdudW1iZXInIHx8IHR5cGVvZiB2YWx1ZSA9PT0gJ2Jvb2xlYW4nICkge1xyXG5cclxuXHRcdFx0Ly8gZmxvYXQvaW50L2Jvb2xcclxuXHJcblx0XHRcdGluZm8uYm91bmRhcnkgPSA0O1xyXG5cdFx0XHRpbmZvLnN0b3JhZ2UgPSA0O1xyXG5cclxuXHRcdH0gZWxzZSBpZiAoIHZhbHVlLmlzVmVjdG9yMiApIHtcclxuXHJcblx0XHRcdC8vIHZlYzJcclxuXHJcblx0XHRcdGluZm8uYm91bmRhcnkgPSA4O1xyXG5cdFx0XHRpbmZvLnN0b3JhZ2UgPSA4O1xyXG5cclxuXHRcdH0gZWxzZSBpZiAoIHZhbHVlLmlzVmVjdG9yMyB8fCB2YWx1ZS5pc0NvbG9yICkge1xyXG5cclxuXHRcdFx0Ly8gdmVjM1xyXG5cclxuXHRcdFx0aW5mby5ib3VuZGFyeSA9IDE2O1xyXG5cdFx0XHRpbmZvLnN0b3JhZ2UgPSAxMjsgLy8gZXZpbDogdmVjMyBtdXN0IHN0YXJ0IG9uIGEgMTYtYnl0ZSBib3VuZGFyeSBidXQgaXQgb25seSBjb25zdW1lcyAxMiBieXRlc1xyXG5cclxuXHRcdH0gZWxzZSBpZiAoIHZhbHVlLmlzVmVjdG9yNCApIHtcclxuXHJcblx0XHRcdC8vIHZlYzRcclxuXHJcblx0XHRcdGluZm8uYm91bmRhcnkgPSAxNjtcclxuXHRcdFx0aW5mby5zdG9yYWdlID0gMTY7XHJcblxyXG5cdFx0fSBlbHNlIGlmICggdmFsdWUuaXNNYXRyaXgzICkge1xyXG5cclxuXHRcdFx0Ly8gbWF0MyAoaW4gU1REMTQwIGEgM3gzIG1hdHJpeCBpcyByZXByZXNlbnRlZCBhcyAzeDQpXHJcblxyXG5cdFx0XHRpbmZvLmJvdW5kYXJ5ID0gNDg7XHJcblx0XHRcdGluZm8uc3RvcmFnZSA9IDQ4O1xyXG5cclxuXHRcdH0gZWxzZSBpZiAoIHZhbHVlLmlzTWF0cml4NCApIHtcclxuXHJcblx0XHRcdC8vIG1hdDRcclxuXHJcblx0XHRcdGluZm8uYm91bmRhcnkgPSA2NDtcclxuXHRcdFx0aW5mby5zdG9yYWdlID0gNjQ7XHJcblxyXG5cdFx0fSBlbHNlIGlmICggdmFsdWUuaXNUZXh0dXJlICkge1xyXG5cclxuXHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuV2ViR0xSZW5kZXJlcjogVGV4dHVyZSBzYW1wbGVycyBjYW4gbm90IGJlIHBhcnQgb2YgYW4gdW5pZm9ybXMgZ3JvdXAuJyApO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5XZWJHTFJlbmRlcmVyOiBVbnN1cHBvcnRlZCB1bmlmb3JtIHZhbHVlIHR5cGUuJywgdmFsdWUgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIGluZm87XHJcblxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gb25Vbmlmb3Jtc0dyb3Vwc0Rpc3Bvc2UoIGV2ZW50ICkge1xyXG5cclxuXHRcdGNvbnN0IHVuaWZvcm1zR3JvdXAgPSBldmVudC50YXJnZXQ7XHJcblxyXG5cdFx0dW5pZm9ybXNHcm91cC5yZW1vdmVFdmVudExpc3RlbmVyKCAnZGlzcG9zZScsIG9uVW5pZm9ybXNHcm91cHNEaXNwb3NlICk7XHJcblxyXG5cdFx0Y29uc3QgaW5kZXggPSBhbGxvY2F0ZWRCaW5kaW5nUG9pbnRzLmluZGV4T2YoIHVuaWZvcm1zR3JvdXAuX19iaW5kaW5nUG9pbnRJbmRleCApO1xyXG5cdFx0YWxsb2NhdGVkQmluZGluZ1BvaW50cy5zcGxpY2UoIGluZGV4LCAxICk7XHJcblxyXG5cdFx0Z2wuZGVsZXRlQnVmZmVyKCBidWZmZXJzWyB1bmlmb3Jtc0dyb3VwLmlkIF0gKTtcclxuXHJcblx0XHRkZWxldGUgYnVmZmVyc1sgdW5pZm9ybXNHcm91cC5pZCBdO1xyXG5cdFx0ZGVsZXRlIHVwZGF0ZUxpc3RbIHVuaWZvcm1zR3JvdXAuaWQgXTtcclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBkaXNwb3NlKCkge1xyXG5cclxuXHRcdGZvciAoIGNvbnN0IGlkIGluIGJ1ZmZlcnMgKSB7XHJcblxyXG5cdFx0XHRnbC5kZWxldGVCdWZmZXIoIGJ1ZmZlcnNbIGlkIF0gKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0YWxsb2NhdGVkQmluZGluZ1BvaW50cyA9IFtdO1xyXG5cdFx0YnVmZmVycyA9IHt9O1xyXG5cdFx0dXBkYXRlTGlzdCA9IHt9O1xyXG5cclxuXHR9XHJcblxyXG5cdHJldHVybiB7XHJcblxyXG5cdFx0YmluZDogYmluZCxcclxuXHRcdHVwZGF0ZTogdXBkYXRlLFxyXG5cclxuXHRcdGRpc3Bvc2U6IGRpc3Bvc2VcclxuXHJcblx0fTtcclxuXHJcbn1cclxuXHJcblxyXG5leHBvcnQgeyBXZWJHTFVuaWZvcm1zR3JvdXBzIH07XHJcbiIsImltcG9ydCB7XHJcblx0UkVWSVNJT04sXHJcblx0QmFja1NpZGUsXHJcblx0RnJvbnRTaWRlLFxyXG5cdERvdWJsZVNpZGUsXHJcblx0UkdCQUZvcm1hdCxcclxuXHRIYWxmRmxvYXRUeXBlLFxyXG5cdEZsb2F0VHlwZSxcclxuXHRVbnNpZ25lZEJ5dGVUeXBlLFxyXG5cdE5vVG9uZU1hcHBpbmcsXHJcblx0TGluZWFyTWlwbWFwTGluZWFyRmlsdGVyLFxyXG5cdFNSR0JDb2xvclNwYWNlLFxyXG5cdExpbmVhclNSR0JDb2xvclNwYWNlLFxyXG5cdFJHQkFJbnRlZ2VyRm9ybWF0LFxyXG5cdFJHSW50ZWdlckZvcm1hdCxcclxuXHRSZWRJbnRlZ2VyRm9ybWF0LFxyXG5cdFVuc2lnbmVkSW50VHlwZSxcclxuXHRVbnNpZ25lZFNob3J0VHlwZSxcclxuXHRVbnNpZ25lZEludDI0OFR5cGUsXHJcblx0VW5zaWduZWRTaG9ydDQ0NDRUeXBlLFxyXG5cdFVuc2lnbmVkU2hvcnQ1NTUxVHlwZSxcclxuXHRXZWJHTENvb3JkaW5hdGVTeXN0ZW0sXHJcblx0RGlzcGxheVAzQ29sb3JTcGFjZSxcclxuXHRMaW5lYXJEaXNwbGF5UDNDb2xvclNwYWNlXHJcbn0gZnJvbSAnLi4vY29uc3RhbnRzLmpzJztcclxuaW1wb3J0IHsgQ29sb3IgfSBmcm9tICcuLi9tYXRoL0NvbG9yLmpzJztcclxuaW1wb3J0IHsgRnJ1c3R1bSB9IGZyb20gJy4uL21hdGgvRnJ1c3R1bS5qcyc7XHJcbmltcG9ydCB7IE1hdHJpeDQgfSBmcm9tICcuLi9tYXRoL01hdHJpeDQuanMnO1xyXG5pbXBvcnQgeyBWZWN0b3IyIH0gZnJvbSAnLi4vbWF0aC9WZWN0b3IyLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yMyB9IGZyb20gJy4uL21hdGgvVmVjdG9yMy5qcyc7XHJcbmltcG9ydCB7IFZlY3RvcjQgfSBmcm9tICcuLi9tYXRoL1ZlY3RvcjQuanMnO1xyXG5pbXBvcnQgeyBmbG9vclBvd2VyT2ZUd28gfSBmcm9tICcuLi9tYXRoL01hdGhVdGlscy5qcyc7XHJcbmltcG9ydCB7IFdlYkdMQW5pbWF0aW9uIH0gZnJvbSAnLi93ZWJnbC9XZWJHTEFuaW1hdGlvbi5qcyc7XHJcbmltcG9ydCB7IFdlYkdMQXR0cmlidXRlcyB9IGZyb20gJy4vd2ViZ2wvV2ViR0xBdHRyaWJ1dGVzLmpzJztcclxuaW1wb3J0IHsgV2ViR0xCYWNrZ3JvdW5kIH0gZnJvbSAnLi93ZWJnbC9XZWJHTEJhY2tncm91bmQuanMnO1xyXG5pbXBvcnQgeyBXZWJHTEJpbmRpbmdTdGF0ZXMgfSBmcm9tICcuL3dlYmdsL1dlYkdMQmluZGluZ1N0YXRlcy5qcyc7XHJcbmltcG9ydCB7IFdlYkdMQnVmZmVyUmVuZGVyZXIgfSBmcm9tICcuL3dlYmdsL1dlYkdMQnVmZmVyUmVuZGVyZXIuanMnO1xyXG5pbXBvcnQgeyBXZWJHTENhcGFiaWxpdGllcyB9IGZyb20gJy4vd2ViZ2wvV2ViR0xDYXBhYmlsaXRpZXMuanMnO1xyXG5pbXBvcnQgeyBXZWJHTENsaXBwaW5nIH0gZnJvbSAnLi93ZWJnbC9XZWJHTENsaXBwaW5nLmpzJztcclxuaW1wb3J0IHsgV2ViR0xDdWJlTWFwcyB9IGZyb20gJy4vd2ViZ2wvV2ViR0xDdWJlTWFwcy5qcyc7XHJcbmltcG9ydCB7IFdlYkdMQ3ViZVVWTWFwcyB9IGZyb20gJy4vd2ViZ2wvV2ViR0xDdWJlVVZNYXBzLmpzJztcclxuaW1wb3J0IHsgV2ViR0xFeHRlbnNpb25zIH0gZnJvbSAnLi93ZWJnbC9XZWJHTEV4dGVuc2lvbnMuanMnO1xyXG5pbXBvcnQgeyBXZWJHTEdlb21ldHJpZXMgfSBmcm9tICcuL3dlYmdsL1dlYkdMR2VvbWV0cmllcy5qcyc7XHJcbmltcG9ydCB7IFdlYkdMSW5kZXhlZEJ1ZmZlclJlbmRlcmVyIH0gZnJvbSAnLi93ZWJnbC9XZWJHTEluZGV4ZWRCdWZmZXJSZW5kZXJlci5qcyc7XHJcbmltcG9ydCB7IFdlYkdMSW5mbyB9IGZyb20gJy4vd2ViZ2wvV2ViR0xJbmZvLmpzJztcclxuaW1wb3J0IHsgV2ViR0xNb3JwaHRhcmdldHMgfSBmcm9tICcuL3dlYmdsL1dlYkdMTW9ycGh0YXJnZXRzLmpzJztcclxuaW1wb3J0IHsgV2ViR0xPYmplY3RzIH0gZnJvbSAnLi93ZWJnbC9XZWJHTE9iamVjdHMuanMnO1xyXG5pbXBvcnQgeyBXZWJHTFByb2dyYW1zIH0gZnJvbSAnLi93ZWJnbC9XZWJHTFByb2dyYW1zLmpzJztcclxuaW1wb3J0IHsgV2ViR0xQcm9wZXJ0aWVzIH0gZnJvbSAnLi93ZWJnbC9XZWJHTFByb3BlcnRpZXMuanMnO1xyXG5pbXBvcnQgeyBXZWJHTFJlbmRlckxpc3RzIH0gZnJvbSAnLi93ZWJnbC9XZWJHTFJlbmRlckxpc3RzLmpzJztcclxuaW1wb3J0IHsgV2ViR0xSZW5kZXJTdGF0ZXMgfSBmcm9tICcuL3dlYmdsL1dlYkdMUmVuZGVyU3RhdGVzLmpzJztcclxuaW1wb3J0IHsgV2ViR0xSZW5kZXJUYXJnZXQgfSBmcm9tICcuL1dlYkdMUmVuZGVyVGFyZ2V0LmpzJztcclxuaW1wb3J0IHsgV2ViR0xTaGFkb3dNYXAgfSBmcm9tICcuL3dlYmdsL1dlYkdMU2hhZG93TWFwLmpzJztcclxuaW1wb3J0IHsgV2ViR0xTdGF0ZSB9IGZyb20gJy4vd2ViZ2wvV2ViR0xTdGF0ZS5qcyc7XHJcbmltcG9ydCB7IFdlYkdMVGV4dHVyZXMgfSBmcm9tICcuL3dlYmdsL1dlYkdMVGV4dHVyZXMuanMnO1xyXG5pbXBvcnQgeyBXZWJHTFVuaWZvcm1zIH0gZnJvbSAnLi93ZWJnbC9XZWJHTFVuaWZvcm1zLmpzJztcclxuaW1wb3J0IHsgV2ViR0xVdGlscyB9IGZyb20gJy4vd2ViZ2wvV2ViR0xVdGlscy5qcyc7XHJcbmltcG9ydCB7IFdlYlhSTWFuYWdlciB9IGZyb20gJy4vd2VieHIvV2ViWFJNYW5hZ2VyLmpzJztcclxuaW1wb3J0IHsgV2ViR0xNYXRlcmlhbHMgfSBmcm9tICcuL3dlYmdsL1dlYkdMTWF0ZXJpYWxzLmpzJztcclxuaW1wb3J0IHsgV2ViR0xVbmlmb3Jtc0dyb3VwcyB9IGZyb20gJy4vd2ViZ2wvV2ViR0xVbmlmb3Jtc0dyb3Vwcy5qcyc7XHJcbmltcG9ydCB7IGNyZWF0ZUNhbnZhc0VsZW1lbnQgfSBmcm9tICcuLi91dGlscy5qcyc7XHJcbmltcG9ydCB7IENvbG9yTWFuYWdlbWVudCB9IGZyb20gJy4uL21hdGgvQ29sb3JNYW5hZ2VtZW50LmpzJztcclxuXHJcbmNsYXNzIFdlYkdMUmVuZGVyZXIge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggcGFyYW1ldGVycyA9IHt9ICkge1xyXG5cclxuXHRcdGNvbnN0IHtcclxuXHRcdFx0Y2FudmFzID0gY3JlYXRlQ2FudmFzRWxlbWVudCgpLFxyXG5cdFx0XHRjb250ZXh0ID0gbnVsbCxcclxuXHRcdFx0ZGVwdGggPSB0cnVlLFxyXG5cdFx0XHRzdGVuY2lsID0gdHJ1ZSxcclxuXHRcdFx0YWxwaGEgPSBmYWxzZSxcclxuXHRcdFx0YW50aWFsaWFzID0gZmFsc2UsXHJcblx0XHRcdHByZW11bHRpcGxpZWRBbHBoYSA9IHRydWUsXHJcblx0XHRcdHByZXNlcnZlRHJhd2luZ0J1ZmZlciA9IGZhbHNlLFxyXG5cdFx0XHRwb3dlclByZWZlcmVuY2UgPSAnZGVmYXVsdCcsXHJcblx0XHRcdGZhaWxJZk1ham9yUGVyZm9ybWFuY2VDYXZlYXQgPSBmYWxzZSxcclxuXHRcdH0gPSBwYXJhbWV0ZXJzO1xyXG5cclxuXHRcdHRoaXMuaXNXZWJHTFJlbmRlcmVyID0gdHJ1ZTtcclxuXHJcblx0XHRsZXQgX2FscGhhO1xyXG5cclxuXHRcdGlmICggY29udGV4dCAhPT0gbnVsbCApIHtcclxuXHJcblx0XHRcdF9hbHBoYSA9IGNvbnRleHQuZ2V0Q29udGV4dEF0dHJpYnV0ZXMoKS5hbHBoYTtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0X2FscGhhID0gYWxwaGE7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGNvbnN0IHVpbnRDbGVhckNvbG9yID0gbmV3IFVpbnQzMkFycmF5KCA0ICk7XHJcblx0XHRjb25zdCBpbnRDbGVhckNvbG9yID0gbmV3IEludDMyQXJyYXkoIDQgKTtcclxuXHJcblx0XHRsZXQgY3VycmVudFJlbmRlckxpc3QgPSBudWxsO1xyXG5cdFx0bGV0IGN1cnJlbnRSZW5kZXJTdGF0ZSA9IG51bGw7XHJcblxyXG5cdFx0Ly8gcmVuZGVyKCkgY2FuIGJlIGNhbGxlZCBmcm9tIHdpdGhpbiBhIGNhbGxiYWNrIHRyaWdnZXJlZCBieSBhbm90aGVyIHJlbmRlci5cclxuXHRcdC8vIFdlIHRyYWNrIHRoaXMgc28gdGhhdCB0aGUgbmVzdGVkIHJlbmRlciBjYWxsIGdldHMgaXRzIGxpc3QgYW5kIHN0YXRlIGlzb2xhdGVkIGZyb20gdGhlIHBhcmVudCByZW5kZXIgY2FsbC5cclxuXHJcblx0XHRjb25zdCByZW5kZXJMaXN0U3RhY2sgPSBbXTtcclxuXHRcdGNvbnN0IHJlbmRlclN0YXRlU3RhY2sgPSBbXTtcclxuXHJcblx0XHQvLyBwdWJsaWMgcHJvcGVydGllc1xyXG5cclxuXHRcdHRoaXMuZG9tRWxlbWVudCA9IGNhbnZhcztcclxuXHJcblx0XHQvLyBEZWJ1ZyBjb25maWd1cmF0aW9uIGNvbnRhaW5lclxyXG5cdFx0dGhpcy5kZWJ1ZyA9IHtcclxuXHJcblx0XHRcdC8qKlxyXG5cdFx0XHQgKiBFbmFibGVzIGVycm9yIGNoZWNraW5nIGFuZCByZXBvcnRpbmcgd2hlbiBzaGFkZXIgcHJvZ3JhbXMgYXJlIGJlaW5nIGNvbXBpbGVkXHJcblx0XHRcdCAqIEB0eXBlIHtib29sZWFufVxyXG5cdFx0XHQgKi9cclxuXHRcdFx0Y2hlY2tTaGFkZXJFcnJvcnM6IHRydWUsXHJcblx0XHRcdC8qKlxyXG5cdFx0XHQgKiBDYWxsYmFjayBmb3IgY3VzdG9tIGVycm9yIHJlcG9ydGluZy5cclxuXHRcdFx0ICogQHR5cGUgez9GdW5jdGlvbn1cclxuXHRcdFx0ICovXHJcblx0XHRcdG9uU2hhZGVyRXJyb3I6IG51bGxcclxuXHRcdH07XHJcblxyXG5cdFx0Ly8gY2xlYXJpbmdcclxuXHJcblx0XHR0aGlzLmF1dG9DbGVhciA9IHRydWU7XHJcblx0XHR0aGlzLmF1dG9DbGVhckNvbG9yID0gdHJ1ZTtcclxuXHRcdHRoaXMuYXV0b0NsZWFyRGVwdGggPSB0cnVlO1xyXG5cdFx0dGhpcy5hdXRvQ2xlYXJTdGVuY2lsID0gdHJ1ZTtcclxuXHJcblx0XHQvLyBzY2VuZSBncmFwaFxyXG5cclxuXHRcdHRoaXMuc29ydE9iamVjdHMgPSB0cnVlO1xyXG5cclxuXHRcdC8vIHVzZXItZGVmaW5lZCBjbGlwcGluZ1xyXG5cclxuXHRcdHRoaXMuY2xpcHBpbmdQbGFuZXMgPSBbXTtcclxuXHRcdHRoaXMubG9jYWxDbGlwcGluZ0VuYWJsZWQgPSBmYWxzZTtcclxuXHJcblx0XHQvLyBwaHlzaWNhbGx5IGJhc2VkIHNoYWRpbmdcclxuXHJcblx0XHR0aGlzLl9vdXRwdXRDb2xvclNwYWNlID0gU1JHQkNvbG9yU3BhY2U7XHJcblxyXG5cdFx0Ly8gcGh5c2ljYWwgbGlnaHRzXHJcblxyXG5cdFx0dGhpcy5fdXNlTGVnYWN5TGlnaHRzID0gZmFsc2U7XHJcblxyXG5cdFx0Ly8gdG9uZSBtYXBwaW5nXHJcblxyXG5cdFx0dGhpcy50b25lTWFwcGluZyA9IE5vVG9uZU1hcHBpbmc7XHJcblx0XHR0aGlzLnRvbmVNYXBwaW5nRXhwb3N1cmUgPSAxLjA7XHJcblxyXG5cdFx0Ly8gaW50ZXJuYWwgcHJvcGVydGllc1xyXG5cclxuXHRcdGNvbnN0IF90aGlzID0gdGhpcztcclxuXHJcblx0XHRsZXQgX2lzQ29udGV4dExvc3QgPSBmYWxzZTtcclxuXHJcblx0XHQvLyBpbnRlcm5hbCBzdGF0ZSBjYWNoZVxyXG5cclxuXHRcdGxldCBfY3VycmVudEFjdGl2ZUN1YmVGYWNlID0gMDtcclxuXHRcdGxldCBfY3VycmVudEFjdGl2ZU1pcG1hcExldmVsID0gMDtcclxuXHRcdGxldCBfY3VycmVudFJlbmRlclRhcmdldCA9IG51bGw7XHJcblx0XHRsZXQgX2N1cnJlbnRNYXRlcmlhbElkID0gLSAxO1xyXG5cclxuXHRcdGxldCBfY3VycmVudENhbWVyYSA9IG51bGw7XHJcblxyXG5cdFx0Y29uc3QgX2N1cnJlbnRWaWV3cG9ydCA9IG5ldyBWZWN0b3I0KCk7XHJcblx0XHRjb25zdCBfY3VycmVudFNjaXNzb3IgPSBuZXcgVmVjdG9yNCgpO1xyXG5cdFx0bGV0IF9jdXJyZW50U2Npc3NvclRlc3QgPSBudWxsO1xyXG5cclxuXHRcdGNvbnN0IF9jdXJyZW50Q2xlYXJDb2xvciA9IG5ldyBDb2xvciggMHgwMDAwMDAgKTtcclxuXHRcdGxldCBfY3VycmVudENsZWFyQWxwaGEgPSAwO1xyXG5cclxuXHRcdC8vXHJcblxyXG5cdFx0bGV0IF93aWR0aCA9IGNhbnZhcy53aWR0aDtcclxuXHRcdGxldCBfaGVpZ2h0ID0gY2FudmFzLmhlaWdodDtcclxuXHJcblx0XHRsZXQgX3BpeGVsUmF0aW8gPSAxO1xyXG5cdFx0bGV0IF9vcGFxdWVTb3J0ID0gbnVsbDtcclxuXHRcdGxldCBfdHJhbnNwYXJlbnRTb3J0ID0gbnVsbDtcclxuXHJcblx0XHRjb25zdCBfdmlld3BvcnQgPSBuZXcgVmVjdG9yNCggMCwgMCwgX3dpZHRoLCBfaGVpZ2h0ICk7XHJcblx0XHRjb25zdCBfc2Npc3NvciA9IG5ldyBWZWN0b3I0KCAwLCAwLCBfd2lkdGgsIF9oZWlnaHQgKTtcclxuXHRcdGxldCBfc2Npc3NvclRlc3QgPSBmYWxzZTtcclxuXHJcblx0XHQvLyBmcnVzdHVtXHJcblxyXG5cdFx0Y29uc3QgX2ZydXN0dW0gPSBuZXcgRnJ1c3R1bSgpO1xyXG5cclxuXHRcdC8vIGNsaXBwaW5nXHJcblxyXG5cdFx0bGV0IF9jbGlwcGluZ0VuYWJsZWQgPSBmYWxzZTtcclxuXHRcdGxldCBfbG9jYWxDbGlwcGluZ0VuYWJsZWQgPSBmYWxzZTtcclxuXHJcblx0XHQvLyB0cmFuc21pc3Npb25cclxuXHJcblx0XHRsZXQgX3RyYW5zbWlzc2lvblJlbmRlclRhcmdldCA9IG51bGw7XHJcblxyXG5cdFx0Ly8gY2FtZXJhIG1hdHJpY2VzIGNhY2hlXHJcblxyXG5cdFx0Y29uc3QgX3Byb2pTY3JlZW5NYXRyaXggPSBuZXcgTWF0cml4NCgpO1xyXG5cclxuXHRcdGNvbnN0IF92ZWN0b3IyID0gbmV3IFZlY3RvcjIoKTtcclxuXHRcdGNvbnN0IF92ZWN0b3IzID0gbmV3IFZlY3RvcjMoKTtcclxuXHJcblx0XHRjb25zdCBfZW1wdHlTY2VuZSA9IHsgYmFja2dyb3VuZDogbnVsbCwgZm9nOiBudWxsLCBlbnZpcm9ubWVudDogbnVsbCwgb3ZlcnJpZGVNYXRlcmlhbDogbnVsbCwgaXNTY2VuZTogdHJ1ZSB9O1xyXG5cclxuXHRcdGZ1bmN0aW9uIGdldFRhcmdldFBpeGVsUmF0aW8oKSB7XHJcblxyXG5cdFx0XHRyZXR1cm4gX2N1cnJlbnRSZW5kZXJUYXJnZXQgPT09IG51bGwgPyBfcGl4ZWxSYXRpbyA6IDE7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIGluaXRpYWxpemVcclxuXHJcblx0XHRsZXQgX2dsID0gY29udGV4dDtcclxuXHJcblx0XHRmdW5jdGlvbiBnZXRDb250ZXh0KCBjb250ZXh0TmFtZXMsIGNvbnRleHRBdHRyaWJ1dGVzICkge1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgY29udGV4dE5hbWVzLmxlbmd0aDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgY29udGV4dE5hbWUgPSBjb250ZXh0TmFtZXNbIGkgXTtcclxuXHRcdFx0XHRjb25zdCBjb250ZXh0ID0gY2FudmFzLmdldENvbnRleHQoIGNvbnRleHROYW1lLCBjb250ZXh0QXR0cmlidXRlcyApO1xyXG5cdFx0XHRcdGlmICggY29udGV4dCAhPT0gbnVsbCApIHJldHVybiBjb250ZXh0O1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0cmV0dXJuIG51bGw7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRyeSB7XHJcblxyXG5cdFx0XHRjb25zdCBjb250ZXh0QXR0cmlidXRlcyA9IHtcclxuXHRcdFx0XHRhbHBoYTogdHJ1ZSxcclxuXHRcdFx0XHRkZXB0aCxcclxuXHRcdFx0XHRzdGVuY2lsLFxyXG5cdFx0XHRcdGFudGlhbGlhcyxcclxuXHRcdFx0XHRwcmVtdWx0aXBsaWVkQWxwaGEsXHJcblx0XHRcdFx0cHJlc2VydmVEcmF3aW5nQnVmZmVyLFxyXG5cdFx0XHRcdHBvd2VyUHJlZmVyZW5jZSxcclxuXHRcdFx0XHRmYWlsSWZNYWpvclBlcmZvcm1hbmNlQ2F2ZWF0LFxyXG5cdFx0XHR9O1xyXG5cclxuXHRcdFx0Ly8gT2Zmc2NyZWVuQ2FudmFzIGRvZXMgbm90IGhhdmUgc2V0QXR0cmlidXRlLCBzZWUgIzIyODExXHJcblx0XHRcdGlmICggJ3NldEF0dHJpYnV0ZScgaW4gY2FudmFzICkgY2FudmFzLnNldEF0dHJpYnV0ZSggJ2RhdGEtZW5naW5lJywgYHRocmVlLmpzIHIke1JFVklTSU9OfWAgKTtcclxuXHJcblx0XHRcdC8vIGV2ZW50IGxpc3RlbmVycyBtdXN0IGJlIHJlZ2lzdGVyZWQgYmVmb3JlIFdlYkdMIGNvbnRleHQgaXMgY3JlYXRlZCwgc2VlICMxMjc1M1xyXG5cdFx0XHRjYW52YXMuYWRkRXZlbnRMaXN0ZW5lciggJ3dlYmdsY29udGV4dGxvc3QnLCBvbkNvbnRleHRMb3N0LCBmYWxzZSApO1xyXG5cdFx0XHRjYW52YXMuYWRkRXZlbnRMaXN0ZW5lciggJ3dlYmdsY29udGV4dHJlc3RvcmVkJywgb25Db250ZXh0UmVzdG9yZSwgZmFsc2UgKTtcclxuXHRcdFx0Y2FudmFzLmFkZEV2ZW50TGlzdGVuZXIoICd3ZWJnbGNvbnRleHRjcmVhdGlvbmVycm9yJywgb25Db250ZXh0Q3JlYXRpb25FcnJvciwgZmFsc2UgKTtcclxuXHJcblx0XHRcdGlmICggX2dsID09PSBudWxsICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBjb250ZXh0TmFtZXMgPSBbICd3ZWJnbDInLCAnd2ViZ2wnLCAnZXhwZXJpbWVudGFsLXdlYmdsJyBdO1xyXG5cclxuXHRcdFx0XHRpZiAoIF90aGlzLmlzV2ViR0wxUmVuZGVyZXIgPT09IHRydWUgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y29udGV4dE5hbWVzLnNoaWZ0KCk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0X2dsID0gZ2V0Q29udGV4dCggY29udGV4dE5hbWVzLCBjb250ZXh0QXR0cmlidXRlcyApO1xyXG5cclxuXHRcdFx0XHRpZiAoIF9nbCA9PT0gbnVsbCApIHtcclxuXHJcblx0XHRcdFx0XHRpZiAoIGdldENvbnRleHQoIGNvbnRleHROYW1lcyApICkge1xyXG5cclxuXHRcdFx0XHRcdFx0dGhyb3cgbmV3IEVycm9yKCAnRXJyb3IgY3JlYXRpbmcgV2ViR0wgY29udGV4dCB3aXRoIHlvdXIgc2VsZWN0ZWQgYXR0cmlidXRlcy4nICk7XHJcblxyXG5cdFx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRcdHRocm93IG5ldyBFcnJvciggJ0Vycm9yIGNyZWF0aW5nIFdlYkdMIGNvbnRleHQuJyApO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0aWYgKCB0eXBlb2YgV2ViR0xSZW5kZXJpbmdDb250ZXh0ICE9PSAndW5kZWZpbmVkJyAmJiBfZ2wgaW5zdGFuY2VvZiBXZWJHTFJlbmRlcmluZ0NvbnRleHQgKSB7IC8vIEBkZXByZWNhdGVkLCByMTUzXHJcblxyXG5cdFx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLldlYkdMUmVuZGVyZXI6IFdlYkdMIDEgc3VwcG9ydCB3YXMgZGVwcmVjYXRlZCBpbiByMTUzIGFuZCB3aWxsIGJlIHJlbW92ZWQgaW4gcjE2My4nICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyBTb21lIGV4cGVyaW1lbnRhbC13ZWJnbCBpbXBsZW1lbnRhdGlvbnMgZG8gbm90IGhhdmUgZ2V0U2hhZGVyUHJlY2lzaW9uRm9ybWF0XHJcblxyXG5cdFx0XHRpZiAoIF9nbC5nZXRTaGFkZXJQcmVjaXNpb25Gb3JtYXQgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0X2dsLmdldFNoYWRlclByZWNpc2lvbkZvcm1hdCA9IGZ1bmN0aW9uICgpIHtcclxuXHJcblx0XHRcdFx0XHRyZXR1cm4geyAncmFuZ2VNaW4nOiAxLCAncmFuZ2VNYXgnOiAxLCAncHJlY2lzaW9uJzogMSB9O1xyXG5cclxuXHRcdFx0XHR9O1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH0gY2F0Y2ggKCBlcnJvciApIHtcclxuXHJcblx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5XZWJHTFJlbmRlcmVyOiAnICsgZXJyb3IubWVzc2FnZSApO1xyXG5cdFx0XHR0aHJvdyBlcnJvcjtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0bGV0IGV4dGVuc2lvbnMsIGNhcGFiaWxpdGllcywgc3RhdGUsIGluZm87XHJcblx0XHRsZXQgcHJvcGVydGllcywgdGV4dHVyZXMsIGN1YmVtYXBzLCBjdWJldXZtYXBzLCBhdHRyaWJ1dGVzLCBnZW9tZXRyaWVzLCBvYmplY3RzO1xyXG5cdFx0bGV0IHByb2dyYW1DYWNoZSwgbWF0ZXJpYWxzLCByZW5kZXJMaXN0cywgcmVuZGVyU3RhdGVzLCBjbGlwcGluZywgc2hhZG93TWFwO1xyXG5cclxuXHRcdGxldCBiYWNrZ3JvdW5kLCBtb3JwaHRhcmdldHMsIGJ1ZmZlclJlbmRlcmVyLCBpbmRleGVkQnVmZmVyUmVuZGVyZXI7XHJcblxyXG5cdFx0bGV0IHV0aWxzLCBiaW5kaW5nU3RhdGVzLCB1bmlmb3Jtc0dyb3VwcztcclxuXHJcblx0XHRmdW5jdGlvbiBpbml0R0xDb250ZXh0KCkge1xyXG5cclxuXHRcdFx0ZXh0ZW5zaW9ucyA9IG5ldyBXZWJHTEV4dGVuc2lvbnMoIF9nbCApO1xyXG5cclxuXHRcdFx0Y2FwYWJpbGl0aWVzID0gbmV3IFdlYkdMQ2FwYWJpbGl0aWVzKCBfZ2wsIGV4dGVuc2lvbnMsIHBhcmFtZXRlcnMgKTtcclxuXHJcblx0XHRcdGV4dGVuc2lvbnMuaW5pdCggY2FwYWJpbGl0aWVzICk7XHJcblxyXG5cdFx0XHR1dGlscyA9IG5ldyBXZWJHTFV0aWxzKCBfZ2wsIGV4dGVuc2lvbnMsIGNhcGFiaWxpdGllcyApO1xyXG5cclxuXHRcdFx0c3RhdGUgPSBuZXcgV2ViR0xTdGF0ZSggX2dsLCBleHRlbnNpb25zLCBjYXBhYmlsaXRpZXMgKTtcclxuXHJcblx0XHRcdGluZm8gPSBuZXcgV2ViR0xJbmZvKCBfZ2wgKTtcclxuXHRcdFx0cHJvcGVydGllcyA9IG5ldyBXZWJHTFByb3BlcnRpZXMoKTtcclxuXHRcdFx0dGV4dHVyZXMgPSBuZXcgV2ViR0xUZXh0dXJlcyggX2dsLCBleHRlbnNpb25zLCBzdGF0ZSwgcHJvcGVydGllcywgY2FwYWJpbGl0aWVzLCB1dGlscywgaW5mbyApO1xyXG5cdFx0XHRjdWJlbWFwcyA9IG5ldyBXZWJHTEN1YmVNYXBzKCBfdGhpcyApO1xyXG5cdFx0XHRjdWJldXZtYXBzID0gbmV3IFdlYkdMQ3ViZVVWTWFwcyggX3RoaXMgKTtcclxuXHRcdFx0YXR0cmlidXRlcyA9IG5ldyBXZWJHTEF0dHJpYnV0ZXMoIF9nbCwgY2FwYWJpbGl0aWVzICk7XHJcblx0XHRcdGJpbmRpbmdTdGF0ZXMgPSBuZXcgV2ViR0xCaW5kaW5nU3RhdGVzKCBfZ2wsIGV4dGVuc2lvbnMsIGF0dHJpYnV0ZXMsIGNhcGFiaWxpdGllcyApO1xyXG5cdFx0XHRnZW9tZXRyaWVzID0gbmV3IFdlYkdMR2VvbWV0cmllcyggX2dsLCBhdHRyaWJ1dGVzLCBpbmZvLCBiaW5kaW5nU3RhdGVzICk7XHJcblx0XHRcdG9iamVjdHMgPSBuZXcgV2ViR0xPYmplY3RzKCBfZ2wsIGdlb21ldHJpZXMsIGF0dHJpYnV0ZXMsIGluZm8gKTtcclxuXHRcdFx0bW9ycGh0YXJnZXRzID0gbmV3IFdlYkdMTW9ycGh0YXJnZXRzKCBfZ2wsIGNhcGFiaWxpdGllcywgdGV4dHVyZXMgKTtcclxuXHRcdFx0Y2xpcHBpbmcgPSBuZXcgV2ViR0xDbGlwcGluZyggcHJvcGVydGllcyApO1xyXG5cdFx0XHRwcm9ncmFtQ2FjaGUgPSBuZXcgV2ViR0xQcm9ncmFtcyggX3RoaXMsIGN1YmVtYXBzLCBjdWJldXZtYXBzLCBleHRlbnNpb25zLCBjYXBhYmlsaXRpZXMsIGJpbmRpbmdTdGF0ZXMsIGNsaXBwaW5nICk7XHJcblx0XHRcdG1hdGVyaWFscyA9IG5ldyBXZWJHTE1hdGVyaWFscyggX3RoaXMsIHByb3BlcnRpZXMgKTtcclxuXHRcdFx0cmVuZGVyTGlzdHMgPSBuZXcgV2ViR0xSZW5kZXJMaXN0cygpO1xyXG5cdFx0XHRyZW5kZXJTdGF0ZXMgPSBuZXcgV2ViR0xSZW5kZXJTdGF0ZXMoIGV4dGVuc2lvbnMsIGNhcGFiaWxpdGllcyApO1xyXG5cdFx0XHRiYWNrZ3JvdW5kID0gbmV3IFdlYkdMQmFja2dyb3VuZCggX3RoaXMsIGN1YmVtYXBzLCBjdWJldXZtYXBzLCBzdGF0ZSwgb2JqZWN0cywgX2FscGhhLCBwcmVtdWx0aXBsaWVkQWxwaGEgKTtcclxuXHRcdFx0c2hhZG93TWFwID0gbmV3IFdlYkdMU2hhZG93TWFwKCBfdGhpcywgb2JqZWN0cywgY2FwYWJpbGl0aWVzICk7XHJcblx0XHRcdHVuaWZvcm1zR3JvdXBzID0gbmV3IFdlYkdMVW5pZm9ybXNHcm91cHMoIF9nbCwgaW5mbywgY2FwYWJpbGl0aWVzLCBzdGF0ZSApO1xyXG5cclxuXHRcdFx0YnVmZmVyUmVuZGVyZXIgPSBuZXcgV2ViR0xCdWZmZXJSZW5kZXJlciggX2dsLCBleHRlbnNpb25zLCBpbmZvLCBjYXBhYmlsaXRpZXMgKTtcclxuXHRcdFx0aW5kZXhlZEJ1ZmZlclJlbmRlcmVyID0gbmV3IFdlYkdMSW5kZXhlZEJ1ZmZlclJlbmRlcmVyKCBfZ2wsIGV4dGVuc2lvbnMsIGluZm8sIGNhcGFiaWxpdGllcyApO1xyXG5cclxuXHRcdFx0aW5mby5wcm9ncmFtcyA9IHByb2dyYW1DYWNoZS5wcm9ncmFtcztcclxuXHJcblx0XHRcdF90aGlzLmNhcGFiaWxpdGllcyA9IGNhcGFiaWxpdGllcztcclxuXHRcdFx0X3RoaXMuZXh0ZW5zaW9ucyA9IGV4dGVuc2lvbnM7XHJcblx0XHRcdF90aGlzLnByb3BlcnRpZXMgPSBwcm9wZXJ0aWVzO1xyXG5cdFx0XHRfdGhpcy5yZW5kZXJMaXN0cyA9IHJlbmRlckxpc3RzO1xyXG5cdFx0XHRfdGhpcy5zaGFkb3dNYXAgPSBzaGFkb3dNYXA7XHJcblx0XHRcdF90aGlzLnN0YXRlID0gc3RhdGU7XHJcblx0XHRcdF90aGlzLmluZm8gPSBpbmZvO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpbml0R0xDb250ZXh0KCk7XHJcblxyXG5cdFx0Ly8geHJcclxuXHJcblx0XHRjb25zdCB4ciA9IG5ldyBXZWJYUk1hbmFnZXIoIF90aGlzLCBfZ2wgKTtcclxuXHJcblx0XHR0aGlzLnhyID0geHI7XHJcblxyXG5cdFx0Ly8gQVBJXHJcblxyXG5cdFx0dGhpcy5nZXRDb250ZXh0ID0gZnVuY3Rpb24gKCkge1xyXG5cclxuXHRcdFx0cmV0dXJuIF9nbDtcclxuXHJcblx0XHR9O1xyXG5cclxuXHRcdHRoaXMuZ2V0Q29udGV4dEF0dHJpYnV0ZXMgPSBmdW5jdGlvbiAoKSB7XHJcblxyXG5cdFx0XHRyZXR1cm4gX2dsLmdldENvbnRleHRBdHRyaWJ1dGVzKCk7XHJcblxyXG5cdFx0fTtcclxuXHJcblx0XHR0aGlzLmZvcmNlQ29udGV4dExvc3MgPSBmdW5jdGlvbiAoKSB7XHJcblxyXG5cdFx0XHRjb25zdCBleHRlbnNpb24gPSBleHRlbnNpb25zLmdldCggJ1dFQkdMX2xvc2VfY29udGV4dCcgKTtcclxuXHRcdFx0aWYgKCBleHRlbnNpb24gKSBleHRlbnNpb24ubG9zZUNvbnRleHQoKTtcclxuXHJcblx0XHR9O1xyXG5cclxuXHRcdHRoaXMuZm9yY2VDb250ZXh0UmVzdG9yZSA9IGZ1bmN0aW9uICgpIHtcclxuXHJcblx0XHRcdGNvbnN0IGV4dGVuc2lvbiA9IGV4dGVuc2lvbnMuZ2V0KCAnV0VCR0xfbG9zZV9jb250ZXh0JyApO1xyXG5cdFx0XHRpZiAoIGV4dGVuc2lvbiApIGV4dGVuc2lvbi5yZXN0b3JlQ29udGV4dCgpO1xyXG5cclxuXHRcdH07XHJcblxyXG5cdFx0dGhpcy5nZXRQaXhlbFJhdGlvID0gZnVuY3Rpb24gKCkge1xyXG5cclxuXHRcdFx0cmV0dXJuIF9waXhlbFJhdGlvO1xyXG5cclxuXHRcdH07XHJcblxyXG5cdFx0dGhpcy5zZXRQaXhlbFJhdGlvID0gZnVuY3Rpb24gKCB2YWx1ZSApIHtcclxuXHJcblx0XHRcdGlmICggdmFsdWUgPT09IHVuZGVmaW5lZCApIHJldHVybjtcclxuXHJcblx0XHRcdF9waXhlbFJhdGlvID0gdmFsdWU7XHJcblxyXG5cdFx0XHR0aGlzLnNldFNpemUoIF93aWR0aCwgX2hlaWdodCwgZmFsc2UgKTtcclxuXHJcblx0XHR9O1xyXG5cclxuXHRcdHRoaXMuZ2V0U2l6ZSA9IGZ1bmN0aW9uICggdGFyZ2V0ICkge1xyXG5cclxuXHRcdFx0cmV0dXJuIHRhcmdldC5zZXQoIF93aWR0aCwgX2hlaWdodCApO1xyXG5cclxuXHRcdH07XHJcblxyXG5cdFx0dGhpcy5zZXRTaXplID0gZnVuY3Rpb24gKCB3aWR0aCwgaGVpZ2h0LCB1cGRhdGVTdHlsZSA9IHRydWUgKSB7XHJcblxyXG5cdFx0XHRpZiAoIHhyLmlzUHJlc2VudGluZyApIHtcclxuXHJcblx0XHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuV2ViR0xSZW5kZXJlcjogQ2FuXFwndCBjaGFuZ2Ugc2l6ZSB3aGlsZSBWUiBkZXZpY2UgaXMgcHJlc2VudGluZy4nICk7XHJcblx0XHRcdFx0cmV0dXJuO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0X3dpZHRoID0gd2lkdGg7XHJcblx0XHRcdF9oZWlnaHQgPSBoZWlnaHQ7XHJcblxyXG5cdFx0XHRjYW52YXMud2lkdGggPSBNYXRoLmZsb29yKCB3aWR0aCAqIF9waXhlbFJhdGlvICk7XHJcblx0XHRcdGNhbnZhcy5oZWlnaHQgPSBNYXRoLmZsb29yKCBoZWlnaHQgKiBfcGl4ZWxSYXRpbyApO1xyXG5cclxuXHRcdFx0aWYgKCB1cGRhdGVTdHlsZSA9PT0gdHJ1ZSApIHtcclxuXHJcblx0XHRcdFx0Y2FudmFzLnN0eWxlLndpZHRoID0gd2lkdGggKyAncHgnO1xyXG5cdFx0XHRcdGNhbnZhcy5zdHlsZS5oZWlnaHQgPSBoZWlnaHQgKyAncHgnO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0dGhpcy5zZXRWaWV3cG9ydCggMCwgMCwgd2lkdGgsIGhlaWdodCApO1xyXG5cclxuXHRcdH07XHJcblxyXG5cdFx0dGhpcy5nZXREcmF3aW5nQnVmZmVyU2l6ZSA9IGZ1bmN0aW9uICggdGFyZ2V0ICkge1xyXG5cclxuXHRcdFx0cmV0dXJuIHRhcmdldC5zZXQoIF93aWR0aCAqIF9waXhlbFJhdGlvLCBfaGVpZ2h0ICogX3BpeGVsUmF0aW8gKS5mbG9vcigpO1xyXG5cclxuXHRcdH07XHJcblxyXG5cdFx0dGhpcy5zZXREcmF3aW5nQnVmZmVyU2l6ZSA9IGZ1bmN0aW9uICggd2lkdGgsIGhlaWdodCwgcGl4ZWxSYXRpbyApIHtcclxuXHJcblx0XHRcdF93aWR0aCA9IHdpZHRoO1xyXG5cdFx0XHRfaGVpZ2h0ID0gaGVpZ2h0O1xyXG5cclxuXHRcdFx0X3BpeGVsUmF0aW8gPSBwaXhlbFJhdGlvO1xyXG5cclxuXHRcdFx0Y2FudmFzLndpZHRoID0gTWF0aC5mbG9vciggd2lkdGggKiBwaXhlbFJhdGlvICk7XHJcblx0XHRcdGNhbnZhcy5oZWlnaHQgPSBNYXRoLmZsb29yKCBoZWlnaHQgKiBwaXhlbFJhdGlvICk7XHJcblxyXG5cdFx0XHR0aGlzLnNldFZpZXdwb3J0KCAwLCAwLCB3aWR0aCwgaGVpZ2h0ICk7XHJcblxyXG5cdFx0fTtcclxuXHJcblx0XHR0aGlzLmdldEN1cnJlbnRWaWV3cG9ydCA9IGZ1bmN0aW9uICggdGFyZ2V0ICkge1xyXG5cclxuXHRcdFx0cmV0dXJuIHRhcmdldC5jb3B5KCBfY3VycmVudFZpZXdwb3J0ICk7XHJcblxyXG5cdFx0fTtcclxuXHJcblx0XHR0aGlzLmdldFZpZXdwb3J0ID0gZnVuY3Rpb24gKCB0YXJnZXQgKSB7XHJcblxyXG5cdFx0XHRyZXR1cm4gdGFyZ2V0LmNvcHkoIF92aWV3cG9ydCApO1xyXG5cclxuXHRcdH07XHJcblxyXG5cdFx0dGhpcy5zZXRWaWV3cG9ydCA9IGZ1bmN0aW9uICggeCwgeSwgd2lkdGgsIGhlaWdodCApIHtcclxuXHJcblx0XHRcdGlmICggeC5pc1ZlY3RvcjQgKSB7XHJcblxyXG5cdFx0XHRcdF92aWV3cG9ydC5zZXQoIHgueCwgeC55LCB4LnosIHgudyApO1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0X3ZpZXdwb3J0LnNldCggeCwgeSwgd2lkdGgsIGhlaWdodCApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0c3RhdGUudmlld3BvcnQoIF9jdXJyZW50Vmlld3BvcnQuY29weSggX3ZpZXdwb3J0ICkubXVsdGlwbHlTY2FsYXIoIF9waXhlbFJhdGlvICkuZmxvb3IoKSApO1xyXG5cclxuXHRcdH07XHJcblxyXG5cdFx0dGhpcy5nZXRTY2lzc29yID0gZnVuY3Rpb24gKCB0YXJnZXQgKSB7XHJcblxyXG5cdFx0XHRyZXR1cm4gdGFyZ2V0LmNvcHkoIF9zY2lzc29yICk7XHJcblxyXG5cdFx0fTtcclxuXHJcblx0XHR0aGlzLnNldFNjaXNzb3IgPSBmdW5jdGlvbiAoIHgsIHksIHdpZHRoLCBoZWlnaHQgKSB7XHJcblxyXG5cdFx0XHRpZiAoIHguaXNWZWN0b3I0ICkge1xyXG5cclxuXHRcdFx0XHRfc2Npc3Nvci5zZXQoIHgueCwgeC55LCB4LnosIHgudyApO1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0X3NjaXNzb3Iuc2V0KCB4LCB5LCB3aWR0aCwgaGVpZ2h0ICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRzdGF0ZS5zY2lzc29yKCBfY3VycmVudFNjaXNzb3IuY29weSggX3NjaXNzb3IgKS5tdWx0aXBseVNjYWxhciggX3BpeGVsUmF0aW8gKS5mbG9vcigpICk7XHJcblxyXG5cdFx0fTtcclxuXHJcblx0XHR0aGlzLmdldFNjaXNzb3JUZXN0ID0gZnVuY3Rpb24gKCkge1xyXG5cclxuXHRcdFx0cmV0dXJuIF9zY2lzc29yVGVzdDtcclxuXHJcblx0XHR9O1xyXG5cclxuXHRcdHRoaXMuc2V0U2Npc3NvclRlc3QgPSBmdW5jdGlvbiAoIGJvb2xlYW4gKSB7XHJcblxyXG5cdFx0XHRzdGF0ZS5zZXRTY2lzc29yVGVzdCggX3NjaXNzb3JUZXN0ID0gYm9vbGVhbiApO1xyXG5cclxuXHRcdH07XHJcblxyXG5cdFx0dGhpcy5zZXRPcGFxdWVTb3J0ID0gZnVuY3Rpb24gKCBtZXRob2QgKSB7XHJcblxyXG5cdFx0XHRfb3BhcXVlU29ydCA9IG1ldGhvZDtcclxuXHJcblx0XHR9O1xyXG5cclxuXHRcdHRoaXMuc2V0VHJhbnNwYXJlbnRTb3J0ID0gZnVuY3Rpb24gKCBtZXRob2QgKSB7XHJcblxyXG5cdFx0XHRfdHJhbnNwYXJlbnRTb3J0ID0gbWV0aG9kO1xyXG5cclxuXHRcdH07XHJcblxyXG5cdFx0Ly8gQ2xlYXJpbmdcclxuXHJcblx0XHR0aGlzLmdldENsZWFyQ29sb3IgPSBmdW5jdGlvbiAoIHRhcmdldCApIHtcclxuXHJcblx0XHRcdHJldHVybiB0YXJnZXQuY29weSggYmFja2dyb3VuZC5nZXRDbGVhckNvbG9yKCkgKTtcclxuXHJcblx0XHR9O1xyXG5cclxuXHRcdHRoaXMuc2V0Q2xlYXJDb2xvciA9IGZ1bmN0aW9uICgpIHtcclxuXHJcblx0XHRcdGJhY2tncm91bmQuc2V0Q2xlYXJDb2xvci5hcHBseSggYmFja2dyb3VuZCwgYXJndW1lbnRzICk7XHJcblxyXG5cdFx0fTtcclxuXHJcblx0XHR0aGlzLmdldENsZWFyQWxwaGEgPSBmdW5jdGlvbiAoKSB7XHJcblxyXG5cdFx0XHRyZXR1cm4gYmFja2dyb3VuZC5nZXRDbGVhckFscGhhKCk7XHJcblxyXG5cdFx0fTtcclxuXHJcblx0XHR0aGlzLnNldENsZWFyQWxwaGEgPSBmdW5jdGlvbiAoKSB7XHJcblxyXG5cdFx0XHRiYWNrZ3JvdW5kLnNldENsZWFyQWxwaGEuYXBwbHkoIGJhY2tncm91bmQsIGFyZ3VtZW50cyApO1xyXG5cclxuXHRcdH07XHJcblxyXG5cdFx0dGhpcy5jbGVhciA9IGZ1bmN0aW9uICggY29sb3IgPSB0cnVlLCBkZXB0aCA9IHRydWUsIHN0ZW5jaWwgPSB0cnVlICkge1xyXG5cclxuXHRcdFx0bGV0IGJpdHMgPSAwO1xyXG5cclxuXHRcdFx0aWYgKCBjb2xvciApIHtcclxuXHJcblx0XHRcdFx0Ly8gY2hlY2sgaWYgd2UncmUgdHJ5aW5nIHRvIGNsZWFyIGFuIGludGVnZXIgdGFyZ2V0XHJcblx0XHRcdFx0bGV0IGlzSW50ZWdlckZvcm1hdCA9IGZhbHNlO1xyXG5cdFx0XHRcdGlmICggX2N1cnJlbnRSZW5kZXJUYXJnZXQgIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgdGFyZ2V0Rm9ybWF0ID0gX2N1cnJlbnRSZW5kZXJUYXJnZXQudGV4dHVyZS5mb3JtYXQ7XHJcblx0XHRcdFx0XHRpc0ludGVnZXJGb3JtYXQgPSB0YXJnZXRGb3JtYXQgPT09IFJHQkFJbnRlZ2VyRm9ybWF0IHx8XHJcblx0XHRcdFx0XHRcdHRhcmdldEZvcm1hdCA9PT0gUkdJbnRlZ2VyRm9ybWF0IHx8XHJcblx0XHRcdFx0XHRcdHRhcmdldEZvcm1hdCA9PT0gUmVkSW50ZWdlckZvcm1hdDtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHQvLyB1c2UgdGhlIGFwcHJvcHJpYXRlIGNsZWFyIGZ1bmN0aW9ucyB0byBjbGVhciB0aGUgdGFyZ2V0IGlmIGl0J3MgYSBzaWduZWRcclxuXHRcdFx0XHQvLyBvciB1bnNpZ25lZCBpbnRlZ2VyIHRhcmdldFxyXG5cdFx0XHRcdGlmICggaXNJbnRlZ2VyRm9ybWF0ICkge1xyXG5cclxuXHRcdFx0XHRcdGNvbnN0IHRhcmdldFR5cGUgPSBfY3VycmVudFJlbmRlclRhcmdldC50ZXh0dXJlLnR5cGU7XHJcblx0XHRcdFx0XHRjb25zdCBpc1Vuc2lnbmVkVHlwZSA9IHRhcmdldFR5cGUgPT09IFVuc2lnbmVkQnl0ZVR5cGUgfHxcclxuXHRcdFx0XHRcdFx0dGFyZ2V0VHlwZSA9PT0gVW5zaWduZWRJbnRUeXBlIHx8XHJcblx0XHRcdFx0XHRcdHRhcmdldFR5cGUgPT09IFVuc2lnbmVkU2hvcnRUeXBlIHx8XHJcblx0XHRcdFx0XHRcdHRhcmdldFR5cGUgPT09IFVuc2lnbmVkSW50MjQ4VHlwZSB8fFxyXG5cdFx0XHRcdFx0XHR0YXJnZXRUeXBlID09PSBVbnNpZ25lZFNob3J0NDQ0NFR5cGUgfHxcclxuXHRcdFx0XHRcdFx0dGFyZ2V0VHlwZSA9PT0gVW5zaWduZWRTaG9ydDU1NTFUeXBlO1xyXG5cclxuXHRcdFx0XHRcdGNvbnN0IGNsZWFyQ29sb3IgPSBiYWNrZ3JvdW5kLmdldENsZWFyQ29sb3IoKTtcclxuXHRcdFx0XHRcdGNvbnN0IGEgPSBiYWNrZ3JvdW5kLmdldENsZWFyQWxwaGEoKTtcclxuXHRcdFx0XHRcdGNvbnN0IHIgPSBjbGVhckNvbG9yLnI7XHJcblx0XHRcdFx0XHRjb25zdCBnID0gY2xlYXJDb2xvci5nO1xyXG5cdFx0XHRcdFx0Y29uc3QgYiA9IGNsZWFyQ29sb3IuYjtcclxuXHJcblx0XHRcdFx0XHRpZiAoIGlzVW5zaWduZWRUeXBlICkge1xyXG5cclxuXHRcdFx0XHRcdFx0dWludENsZWFyQ29sb3JbIDAgXSA9IHI7XHJcblx0XHRcdFx0XHRcdHVpbnRDbGVhckNvbG9yWyAxIF0gPSBnO1xyXG5cdFx0XHRcdFx0XHR1aW50Q2xlYXJDb2xvclsgMiBdID0gYjtcclxuXHRcdFx0XHRcdFx0dWludENsZWFyQ29sb3JbIDMgXSA9IGE7XHJcblx0XHRcdFx0XHRcdF9nbC5jbGVhckJ1ZmZlcnVpdiggX2dsLkNPTE9SLCAwLCB1aW50Q2xlYXJDb2xvciApO1xyXG5cclxuXHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHRpbnRDbGVhckNvbG9yWyAwIF0gPSByO1xyXG5cdFx0XHRcdFx0XHRpbnRDbGVhckNvbG9yWyAxIF0gPSBnO1xyXG5cdFx0XHRcdFx0XHRpbnRDbGVhckNvbG9yWyAyIF0gPSBiO1xyXG5cdFx0XHRcdFx0XHRpbnRDbGVhckNvbG9yWyAzIF0gPSBhO1xyXG5cdFx0XHRcdFx0XHRfZ2wuY2xlYXJCdWZmZXJpdiggX2dsLkNPTE9SLCAwLCBpbnRDbGVhckNvbG9yICk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdGJpdHMgfD0gX2dsLkNPTE9SX0JVRkZFUl9CSVQ7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGlmICggZGVwdGggKSBiaXRzIHw9IF9nbC5ERVBUSF9CVUZGRVJfQklUO1xyXG5cdFx0XHRpZiAoIHN0ZW5jaWwgKSB7XHJcblxyXG5cdFx0XHRcdGJpdHMgfD0gX2dsLlNURU5DSUxfQlVGRkVSX0JJVDtcclxuXHRcdFx0XHR0aGlzLnN0YXRlLmJ1ZmZlcnMuc3RlbmNpbC5zZXRNYXNrKCAweGZmZmZmZmZmICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRfZ2wuY2xlYXIoIGJpdHMgKTtcclxuXHJcblx0XHR9O1xyXG5cclxuXHRcdHRoaXMuY2xlYXJDb2xvciA9IGZ1bmN0aW9uICgpIHtcclxuXHJcblx0XHRcdHRoaXMuY2xlYXIoIHRydWUsIGZhbHNlLCBmYWxzZSApO1xyXG5cclxuXHRcdH07XHJcblxyXG5cdFx0dGhpcy5jbGVhckRlcHRoID0gZnVuY3Rpb24gKCkge1xyXG5cclxuXHRcdFx0dGhpcy5jbGVhciggZmFsc2UsIHRydWUsIGZhbHNlICk7XHJcblxyXG5cdFx0fTtcclxuXHJcblx0XHR0aGlzLmNsZWFyU3RlbmNpbCA9IGZ1bmN0aW9uICgpIHtcclxuXHJcblx0XHRcdHRoaXMuY2xlYXIoIGZhbHNlLCBmYWxzZSwgdHJ1ZSApO1xyXG5cclxuXHRcdH07XHJcblxyXG5cdFx0Ly9cclxuXHJcblx0XHR0aGlzLmRpc3Bvc2UgPSBmdW5jdGlvbiAoKSB7XHJcblxyXG5cdFx0XHRjYW52YXMucmVtb3ZlRXZlbnRMaXN0ZW5lciggJ3dlYmdsY29udGV4dGxvc3QnLCBvbkNvbnRleHRMb3N0LCBmYWxzZSApO1xyXG5cdFx0XHRjYW52YXMucmVtb3ZlRXZlbnRMaXN0ZW5lciggJ3dlYmdsY29udGV4dHJlc3RvcmVkJywgb25Db250ZXh0UmVzdG9yZSwgZmFsc2UgKTtcclxuXHRcdFx0Y2FudmFzLnJlbW92ZUV2ZW50TGlzdGVuZXIoICd3ZWJnbGNvbnRleHRjcmVhdGlvbmVycm9yJywgb25Db250ZXh0Q3JlYXRpb25FcnJvciwgZmFsc2UgKTtcclxuXHJcblx0XHRcdHJlbmRlckxpc3RzLmRpc3Bvc2UoKTtcclxuXHRcdFx0cmVuZGVyU3RhdGVzLmRpc3Bvc2UoKTtcclxuXHRcdFx0cHJvcGVydGllcy5kaXNwb3NlKCk7XHJcblx0XHRcdGN1YmVtYXBzLmRpc3Bvc2UoKTtcclxuXHRcdFx0Y3ViZXV2bWFwcy5kaXNwb3NlKCk7XHJcblx0XHRcdG9iamVjdHMuZGlzcG9zZSgpO1xyXG5cdFx0XHRiaW5kaW5nU3RhdGVzLmRpc3Bvc2UoKTtcclxuXHRcdFx0dW5pZm9ybXNHcm91cHMuZGlzcG9zZSgpO1xyXG5cdFx0XHRwcm9ncmFtQ2FjaGUuZGlzcG9zZSgpO1xyXG5cclxuXHRcdFx0eHIuZGlzcG9zZSgpO1xyXG5cclxuXHRcdFx0eHIucmVtb3ZlRXZlbnRMaXN0ZW5lciggJ3Nlc3Npb25zdGFydCcsIG9uWFJTZXNzaW9uU3RhcnQgKTtcclxuXHRcdFx0eHIucmVtb3ZlRXZlbnRMaXN0ZW5lciggJ3Nlc3Npb25lbmQnLCBvblhSU2Vzc2lvbkVuZCApO1xyXG5cclxuXHRcdFx0aWYgKCBfdHJhbnNtaXNzaW9uUmVuZGVyVGFyZ2V0ICkge1xyXG5cclxuXHRcdFx0XHRfdHJhbnNtaXNzaW9uUmVuZGVyVGFyZ2V0LmRpc3Bvc2UoKTtcclxuXHRcdFx0XHRfdHJhbnNtaXNzaW9uUmVuZGVyVGFyZ2V0ID0gbnVsbDtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGFuaW1hdGlvbi5zdG9wKCk7XHJcblxyXG5cdFx0fTtcclxuXHJcblx0XHQvLyBFdmVudHNcclxuXHJcblx0XHRmdW5jdGlvbiBvbkNvbnRleHRMb3N0KCBldmVudCApIHtcclxuXHJcblx0XHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XHJcblxyXG5cdFx0XHRjb25zb2xlLmxvZyggJ1RIUkVFLldlYkdMUmVuZGVyZXI6IENvbnRleHQgTG9zdC4nICk7XHJcblxyXG5cdFx0XHRfaXNDb250ZXh0TG9zdCA9IHRydWU7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGZ1bmN0aW9uIG9uQ29udGV4dFJlc3RvcmUoIC8qIGV2ZW50ICovICkge1xyXG5cclxuXHRcdFx0Y29uc29sZS5sb2coICdUSFJFRS5XZWJHTFJlbmRlcmVyOiBDb250ZXh0IFJlc3RvcmVkLicgKTtcclxuXHJcblx0XHRcdF9pc0NvbnRleHRMb3N0ID0gZmFsc2U7XHJcblxyXG5cdFx0XHRjb25zdCBpbmZvQXV0b1Jlc2V0ID0gaW5mby5hdXRvUmVzZXQ7XHJcblx0XHRcdGNvbnN0IHNoYWRvd01hcEVuYWJsZWQgPSBzaGFkb3dNYXAuZW5hYmxlZDtcclxuXHRcdFx0Y29uc3Qgc2hhZG93TWFwQXV0b1VwZGF0ZSA9IHNoYWRvd01hcC5hdXRvVXBkYXRlO1xyXG5cdFx0XHRjb25zdCBzaGFkb3dNYXBOZWVkc1VwZGF0ZSA9IHNoYWRvd01hcC5uZWVkc1VwZGF0ZTtcclxuXHRcdFx0Y29uc3Qgc2hhZG93TWFwVHlwZSA9IHNoYWRvd01hcC50eXBlO1xyXG5cclxuXHRcdFx0aW5pdEdMQ29udGV4dCgpO1xyXG5cclxuXHRcdFx0aW5mby5hdXRvUmVzZXQgPSBpbmZvQXV0b1Jlc2V0O1xyXG5cdFx0XHRzaGFkb3dNYXAuZW5hYmxlZCA9IHNoYWRvd01hcEVuYWJsZWQ7XHJcblx0XHRcdHNoYWRvd01hcC5hdXRvVXBkYXRlID0gc2hhZG93TWFwQXV0b1VwZGF0ZTtcclxuXHRcdFx0c2hhZG93TWFwLm5lZWRzVXBkYXRlID0gc2hhZG93TWFwTmVlZHNVcGRhdGU7XHJcblx0XHRcdHNoYWRvd01hcC50eXBlID0gc2hhZG93TWFwVHlwZTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0ZnVuY3Rpb24gb25Db250ZXh0Q3JlYXRpb25FcnJvciggZXZlbnQgKSB7XHJcblxyXG5cdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuV2ViR0xSZW5kZXJlcjogQSBXZWJHTCBjb250ZXh0IGNvdWxkIG5vdCBiZSBjcmVhdGVkLiBSZWFzb246ICcsIGV2ZW50LnN0YXR1c01lc3NhZ2UgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0ZnVuY3Rpb24gb25NYXRlcmlhbERpc3Bvc2UoIGV2ZW50ICkge1xyXG5cclxuXHRcdFx0Y29uc3QgbWF0ZXJpYWwgPSBldmVudC50YXJnZXQ7XHJcblxyXG5cdFx0XHRtYXRlcmlhbC5yZW1vdmVFdmVudExpc3RlbmVyKCAnZGlzcG9zZScsIG9uTWF0ZXJpYWxEaXNwb3NlICk7XHJcblxyXG5cdFx0XHRkZWFsbG9jYXRlTWF0ZXJpYWwoIG1hdGVyaWFsICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIEJ1ZmZlciBkZWFsbG9jYXRpb25cclxuXHJcblx0XHRmdW5jdGlvbiBkZWFsbG9jYXRlTWF0ZXJpYWwoIG1hdGVyaWFsICkge1xyXG5cclxuXHRcdFx0cmVsZWFzZU1hdGVyaWFsUHJvZ3JhbVJlZmVyZW5jZXMoIG1hdGVyaWFsICk7XHJcblxyXG5cdFx0XHRwcm9wZXJ0aWVzLnJlbW92ZSggbWF0ZXJpYWwgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cclxuXHRcdGZ1bmN0aW9uIHJlbGVhc2VNYXRlcmlhbFByb2dyYW1SZWZlcmVuY2VzKCBtYXRlcmlhbCApIHtcclxuXHJcblx0XHRcdGNvbnN0IHByb2dyYW1zID0gcHJvcGVydGllcy5nZXQoIG1hdGVyaWFsICkucHJvZ3JhbXM7XHJcblxyXG5cdFx0XHRpZiAoIHByb2dyYW1zICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRcdHByb2dyYW1zLmZvckVhY2goIGZ1bmN0aW9uICggcHJvZ3JhbSApIHtcclxuXHJcblx0XHRcdFx0XHRwcm9ncmFtQ2FjaGUucmVsZWFzZVByb2dyYW0oIHByb2dyYW0gKTtcclxuXHJcblx0XHRcdFx0fSApO1xyXG5cclxuXHRcdFx0XHRpZiAoIG1hdGVyaWFsLmlzU2hhZGVyTWF0ZXJpYWwgKSB7XHJcblxyXG5cdFx0XHRcdFx0cHJvZ3JhbUNhY2hlLnJlbGVhc2VTaGFkZXJDYWNoZSggbWF0ZXJpYWwgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvLyBCdWZmZXIgcmVuZGVyaW5nXHJcblxyXG5cdFx0dGhpcy5yZW5kZXJCdWZmZXJEaXJlY3QgPSBmdW5jdGlvbiAoIGNhbWVyYSwgc2NlbmUsIGdlb21ldHJ5LCBtYXRlcmlhbCwgb2JqZWN0LCBncm91cCApIHtcclxuXHJcblx0XHRcdGlmICggc2NlbmUgPT09IG51bGwgKSBzY2VuZSA9IF9lbXB0eVNjZW5lOyAvLyByZW5kZXJCdWZmZXJEaXJlY3Qgc2Vjb25kIHBhcmFtZXRlciB1c2VkIHRvIGJlIGZvZyAoY291bGQgYmUgbnVsbClcclxuXHJcblx0XHRcdGNvbnN0IGZyb250RmFjZUNXID0gKCBvYmplY3QuaXNNZXNoICYmIG9iamVjdC5tYXRyaXhXb3JsZC5kZXRlcm1pbmFudCgpIDwgMCApO1xyXG5cclxuXHRcdFx0Y29uc3QgcHJvZ3JhbSA9IHNldFByb2dyYW0oIGNhbWVyYSwgc2NlbmUsIGdlb21ldHJ5LCBtYXRlcmlhbCwgb2JqZWN0ICk7XHJcblxyXG5cdFx0XHRzdGF0ZS5zZXRNYXRlcmlhbCggbWF0ZXJpYWwsIGZyb250RmFjZUNXICk7XHJcblxyXG5cdFx0XHQvL1xyXG5cclxuXHRcdFx0bGV0IGluZGV4ID0gZ2VvbWV0cnkuaW5kZXg7XHJcblx0XHRcdGxldCByYW5nZUZhY3RvciA9IDE7XHJcblxyXG5cdFx0XHRpZiAoIG1hdGVyaWFsLndpcmVmcmFtZSA9PT0gdHJ1ZSApIHtcclxuXHJcblx0XHRcdFx0aW5kZXggPSBnZW9tZXRyaWVzLmdldFdpcmVmcmFtZUF0dHJpYnV0ZSggZ2VvbWV0cnkgKTtcclxuXHJcblx0XHRcdFx0aWYgKCBpbmRleCA9PT0gdW5kZWZpbmVkICkgcmV0dXJuO1xyXG5cclxuXHRcdFx0XHRyYW5nZUZhY3RvciA9IDI7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvL1xyXG5cclxuXHRcdFx0Y29uc3QgZHJhd1JhbmdlID0gZ2VvbWV0cnkuZHJhd1JhbmdlO1xyXG5cdFx0XHRjb25zdCBwb3NpdGlvbiA9IGdlb21ldHJ5LmF0dHJpYnV0ZXMucG9zaXRpb247XHJcblxyXG5cdFx0XHRsZXQgZHJhd1N0YXJ0ID0gZHJhd1JhbmdlLnN0YXJ0ICogcmFuZ2VGYWN0b3I7XHJcblx0XHRcdGxldCBkcmF3RW5kID0gKCBkcmF3UmFuZ2Uuc3RhcnQgKyBkcmF3UmFuZ2UuY291bnQgKSAqIHJhbmdlRmFjdG9yO1xyXG5cclxuXHRcdFx0aWYgKCBncm91cCAhPT0gbnVsbCApIHtcclxuXHJcblx0XHRcdFx0ZHJhd1N0YXJ0ID0gTWF0aC5tYXgoIGRyYXdTdGFydCwgZ3JvdXAuc3RhcnQgKiByYW5nZUZhY3RvciApO1xyXG5cdFx0XHRcdGRyYXdFbmQgPSBNYXRoLm1pbiggZHJhd0VuZCwgKCBncm91cC5zdGFydCArIGdyb3VwLmNvdW50ICkgKiByYW5nZUZhY3RvciApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0aWYgKCBpbmRleCAhPT0gbnVsbCApIHtcclxuXHJcblx0XHRcdFx0ZHJhd1N0YXJ0ID0gTWF0aC5tYXgoIGRyYXdTdGFydCwgMCApO1xyXG5cdFx0XHRcdGRyYXdFbmQgPSBNYXRoLm1pbiggZHJhd0VuZCwgaW5kZXguY291bnQgKTtcclxuXHJcblx0XHRcdH0gZWxzZSBpZiAoIHBvc2l0aW9uICE9PSB1bmRlZmluZWQgJiYgcG9zaXRpb24gIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdGRyYXdTdGFydCA9IE1hdGgubWF4KCBkcmF3U3RhcnQsIDAgKTtcclxuXHRcdFx0XHRkcmF3RW5kID0gTWF0aC5taW4oIGRyYXdFbmQsIHBvc2l0aW9uLmNvdW50ICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRjb25zdCBkcmF3Q291bnQgPSBkcmF3RW5kIC0gZHJhd1N0YXJ0O1xyXG5cclxuXHRcdFx0aWYgKCBkcmF3Q291bnQgPCAwIHx8IGRyYXdDb3VudCA9PT0gSW5maW5pdHkgKSByZXR1cm47XHJcblxyXG5cdFx0XHQvL1xyXG5cclxuXHRcdFx0YmluZGluZ1N0YXRlcy5zZXR1cCggb2JqZWN0LCBtYXRlcmlhbCwgcHJvZ3JhbSwgZ2VvbWV0cnksIGluZGV4ICk7XHJcblxyXG5cdFx0XHRsZXQgYXR0cmlidXRlO1xyXG5cdFx0XHRsZXQgcmVuZGVyZXIgPSBidWZmZXJSZW5kZXJlcjtcclxuXHJcblx0XHRcdGlmICggaW5kZXggIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdGF0dHJpYnV0ZSA9IGF0dHJpYnV0ZXMuZ2V0KCBpbmRleCApO1xyXG5cclxuXHRcdFx0XHRyZW5kZXJlciA9IGluZGV4ZWRCdWZmZXJSZW5kZXJlcjtcclxuXHRcdFx0XHRyZW5kZXJlci5zZXRJbmRleCggYXR0cmlidXRlICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvL1xyXG5cclxuXHRcdFx0aWYgKCBvYmplY3QuaXNNZXNoICkge1xyXG5cclxuXHRcdFx0XHRpZiAoIG1hdGVyaWFsLndpcmVmcmFtZSA9PT0gdHJ1ZSApIHtcclxuXHJcblx0XHRcdFx0XHRzdGF0ZS5zZXRMaW5lV2lkdGgoIG1hdGVyaWFsLndpcmVmcmFtZUxpbmV3aWR0aCAqIGdldFRhcmdldFBpeGVsUmF0aW8oKSApO1xyXG5cdFx0XHRcdFx0cmVuZGVyZXIuc2V0TW9kZSggX2dsLkxJTkVTICk7XHJcblxyXG5cdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0cmVuZGVyZXIuc2V0TW9kZSggX2dsLlRSSUFOR0xFUyApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9IGVsc2UgaWYgKCBvYmplY3QuaXNMaW5lICkge1xyXG5cclxuXHRcdFx0XHRsZXQgbGluZVdpZHRoID0gbWF0ZXJpYWwubGluZXdpZHRoO1xyXG5cclxuXHRcdFx0XHRpZiAoIGxpbmVXaWR0aCA9PT0gdW5kZWZpbmVkICkgbGluZVdpZHRoID0gMTsgLy8gTm90IHVzaW5nIExpbmUqTWF0ZXJpYWxcclxuXHJcblx0XHRcdFx0c3RhdGUuc2V0TGluZVdpZHRoKCBsaW5lV2lkdGggKiBnZXRUYXJnZXRQaXhlbFJhdGlvKCkgKTtcclxuXHJcblx0XHRcdFx0aWYgKCBvYmplY3QuaXNMaW5lU2VnbWVudHMgKSB7XHJcblxyXG5cdFx0XHRcdFx0cmVuZGVyZXIuc2V0TW9kZSggX2dsLkxJTkVTICk7XHJcblxyXG5cdFx0XHRcdH0gZWxzZSBpZiAoIG9iamVjdC5pc0xpbmVMb29wICkge1xyXG5cclxuXHRcdFx0XHRcdHJlbmRlcmVyLnNldE1vZGUoIF9nbC5MSU5FX0xPT1AgKTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRyZW5kZXJlci5zZXRNb2RlKCBfZ2wuTElORV9TVFJJUCApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9IGVsc2UgaWYgKCBvYmplY3QuaXNQb2ludHMgKSB7XHJcblxyXG5cdFx0XHRcdHJlbmRlcmVyLnNldE1vZGUoIF9nbC5QT0lOVFMgKTtcclxuXHJcblx0XHRcdH0gZWxzZSBpZiAoIG9iamVjdC5pc1Nwcml0ZSApIHtcclxuXHJcblx0XHRcdFx0cmVuZGVyZXIuc2V0TW9kZSggX2dsLlRSSUFOR0xFUyApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0aWYgKCBvYmplY3QuaXNCYXRjaGVkTWVzaCApIHtcclxuXHJcblx0XHRcdFx0cmVuZGVyZXIucmVuZGVyTXVsdGlEcmF3KCBvYmplY3QuX211bHRpRHJhd1N0YXJ0cywgb2JqZWN0Ll9tdWx0aURyYXdDb3VudHMsIG9iamVjdC5fbXVsdGlEcmF3Q291bnQgKTtcclxuXHJcblx0XHRcdH0gZWxzZSBpZiAoIG9iamVjdC5pc0luc3RhbmNlZE1lc2ggKSB7XHJcblxyXG5cdFx0XHRcdHJlbmRlcmVyLnJlbmRlckluc3RhbmNlcyggZHJhd1N0YXJ0LCBkcmF3Q291bnQsIG9iamVjdC5jb3VudCApO1xyXG5cclxuXHRcdFx0fSBlbHNlIGlmICggZ2VvbWV0cnkuaXNJbnN0YW5jZWRCdWZmZXJHZW9tZXRyeSApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgbWF4SW5zdGFuY2VDb3VudCA9IGdlb21ldHJ5Ll9tYXhJbnN0YW5jZUNvdW50ICE9PSB1bmRlZmluZWQgPyBnZW9tZXRyeS5fbWF4SW5zdGFuY2VDb3VudCA6IEluZmluaXR5O1xyXG5cdFx0XHRcdGNvbnN0IGluc3RhbmNlQ291bnQgPSBNYXRoLm1pbiggZ2VvbWV0cnkuaW5zdGFuY2VDb3VudCwgbWF4SW5zdGFuY2VDb3VudCApO1xyXG5cclxuXHRcdFx0XHRyZW5kZXJlci5yZW5kZXJJbnN0YW5jZXMoIGRyYXdTdGFydCwgZHJhd0NvdW50LCBpbnN0YW5jZUNvdW50ICk7XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRyZW5kZXJlci5yZW5kZXIoIGRyYXdTdGFydCwgZHJhd0NvdW50ICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fTtcclxuXHJcblx0XHQvLyBDb21waWxlXHJcblxyXG5cdFx0ZnVuY3Rpb24gcHJlcGFyZU1hdGVyaWFsKCBtYXRlcmlhbCwgc2NlbmUsIG9iamVjdCApIHtcclxuXHJcblx0XHRcdGlmICggbWF0ZXJpYWwudHJhbnNwYXJlbnQgPT09IHRydWUgJiYgbWF0ZXJpYWwuc2lkZSA9PT0gRG91YmxlU2lkZSAmJiBtYXRlcmlhbC5mb3JjZVNpbmdsZVBhc3MgPT09IGZhbHNlICkge1xyXG5cclxuXHRcdFx0XHRtYXRlcmlhbC5zaWRlID0gQmFja1NpZGU7XHJcblx0XHRcdFx0bWF0ZXJpYWwubmVlZHNVcGRhdGUgPSB0cnVlO1xyXG5cdFx0XHRcdGdldFByb2dyYW0oIG1hdGVyaWFsLCBzY2VuZSwgb2JqZWN0ICk7XHJcblxyXG5cdFx0XHRcdG1hdGVyaWFsLnNpZGUgPSBGcm9udFNpZGU7XHJcblx0XHRcdFx0bWF0ZXJpYWwubmVlZHNVcGRhdGUgPSB0cnVlO1xyXG5cdFx0XHRcdGdldFByb2dyYW0oIG1hdGVyaWFsLCBzY2VuZSwgb2JqZWN0ICk7XHJcblxyXG5cdFx0XHRcdG1hdGVyaWFsLnNpZGUgPSBEb3VibGVTaWRlO1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0Z2V0UHJvZ3JhbSggbWF0ZXJpYWwsIHNjZW5lLCBvYmplY3QgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5jb21waWxlID0gZnVuY3Rpb24gKCBzY2VuZSwgY2FtZXJhLCB0YXJnZXRTY2VuZSA9IG51bGwgKSB7XHJcblxyXG5cdFx0XHRpZiAoIHRhcmdldFNjZW5lID09PSBudWxsICkgdGFyZ2V0U2NlbmUgPSBzY2VuZTtcclxuXHJcblx0XHRcdGN1cnJlbnRSZW5kZXJTdGF0ZSA9IHJlbmRlclN0YXRlcy5nZXQoIHRhcmdldFNjZW5lICk7XHJcblx0XHRcdGN1cnJlbnRSZW5kZXJTdGF0ZS5pbml0KCk7XHJcblxyXG5cdFx0XHRyZW5kZXJTdGF0ZVN0YWNrLnB1c2goIGN1cnJlbnRSZW5kZXJTdGF0ZSApO1xyXG5cclxuXHRcdFx0Ly8gZ2F0aGVyIGxpZ2h0cyBmcm9tIGJvdGggdGhlIHRhcmdldCBzY2VuZSBhbmQgdGhlIG5ldyBvYmplY3QgdGhhdCB3aWxsIGJlIGFkZGVkIHRvIHRoZSBzY2VuZS5cclxuXHJcblx0XHRcdHRhcmdldFNjZW5lLnRyYXZlcnNlVmlzaWJsZSggZnVuY3Rpb24gKCBvYmplY3QgKSB7XHJcblxyXG5cdFx0XHRcdGlmICggb2JqZWN0LmlzTGlnaHQgJiYgb2JqZWN0LmxheWVycy50ZXN0KCBjYW1lcmEubGF5ZXJzICkgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y3VycmVudFJlbmRlclN0YXRlLnB1c2hMaWdodCggb2JqZWN0ICk7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCBvYmplY3QuY2FzdFNoYWRvdyApIHtcclxuXHJcblx0XHRcdFx0XHRcdGN1cnJlbnRSZW5kZXJTdGF0ZS5wdXNoU2hhZG93KCBvYmplY3QgKTtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH0gKTtcclxuXHJcblx0XHRcdGlmICggc2NlbmUgIT09IHRhcmdldFNjZW5lICkge1xyXG5cclxuXHRcdFx0XHRzY2VuZS50cmF2ZXJzZVZpc2libGUoIGZ1bmN0aW9uICggb2JqZWN0ICkge1xyXG5cclxuXHRcdFx0XHRcdGlmICggb2JqZWN0LmlzTGlnaHQgJiYgb2JqZWN0LmxheWVycy50ZXN0KCBjYW1lcmEubGF5ZXJzICkgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRjdXJyZW50UmVuZGVyU3RhdGUucHVzaExpZ2h0KCBvYmplY3QgKTtcclxuXHJcblx0XHRcdFx0XHRcdGlmICggb2JqZWN0LmNhc3RTaGFkb3cgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdGN1cnJlbnRSZW5kZXJTdGF0ZS5wdXNoU2hhZG93KCBvYmplY3QgKTtcclxuXHJcblx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH0gKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGN1cnJlbnRSZW5kZXJTdGF0ZS5zZXR1cExpZ2h0cyggX3RoaXMuX3VzZUxlZ2FjeUxpZ2h0cyApO1xyXG5cclxuXHRcdFx0Ly8gT25seSBpbml0aWFsaXplIG1hdGVyaWFscyBpbiB0aGUgbmV3IHNjZW5lLCBub3QgdGhlIHRhcmdldFNjZW5lLlxyXG5cclxuXHRcdFx0Y29uc3QgbWF0ZXJpYWxzID0gbmV3IFNldCgpO1xyXG5cclxuXHRcdFx0c2NlbmUudHJhdmVyc2UoIGZ1bmN0aW9uICggb2JqZWN0ICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBtYXRlcmlhbCA9IG9iamVjdC5tYXRlcmlhbDtcclxuXHJcblx0XHRcdFx0aWYgKCBtYXRlcmlhbCApIHtcclxuXHJcblx0XHRcdFx0XHRpZiAoIEFycmF5LmlzQXJyYXkoIG1hdGVyaWFsICkgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBtYXRlcmlhbC5sZW5ndGg7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdGNvbnN0IG1hdGVyaWFsMiA9IG1hdGVyaWFsWyBpIF07XHJcblxyXG5cdFx0XHRcdFx0XHRcdHByZXBhcmVNYXRlcmlhbCggbWF0ZXJpYWwyLCB0YXJnZXRTY2VuZSwgb2JqZWN0ICk7XHJcblx0XHRcdFx0XHRcdFx0bWF0ZXJpYWxzLmFkZCggbWF0ZXJpYWwyICk7XHJcblxyXG5cdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRcdHByZXBhcmVNYXRlcmlhbCggbWF0ZXJpYWwsIHRhcmdldFNjZW5lLCBvYmplY3QgKTtcclxuXHRcdFx0XHRcdFx0bWF0ZXJpYWxzLmFkZCggbWF0ZXJpYWwgKTtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH0gKTtcclxuXHJcblx0XHRcdHJlbmRlclN0YXRlU3RhY2sucG9wKCk7XHJcblx0XHRcdGN1cnJlbnRSZW5kZXJTdGF0ZSA9IG51bGw7XHJcblxyXG5cdFx0XHRyZXR1cm4gbWF0ZXJpYWxzO1xyXG5cclxuXHRcdH07XHJcblxyXG5cdFx0Ly8gY29tcGlsZUFzeW5jXHJcblxyXG5cdFx0dGhpcy5jb21waWxlQXN5bmMgPSBmdW5jdGlvbiAoIHNjZW5lLCBjYW1lcmEsIHRhcmdldFNjZW5lID0gbnVsbCApIHtcclxuXHJcblx0XHRcdGNvbnN0IG1hdGVyaWFscyA9IHRoaXMuY29tcGlsZSggc2NlbmUsIGNhbWVyYSwgdGFyZ2V0U2NlbmUgKTtcclxuXHJcblx0XHRcdC8vIFdhaXQgZm9yIGFsbCB0aGUgbWF0ZXJpYWxzIGluIHRoZSBuZXcgb2JqZWN0IHRvIGluZGljYXRlIHRoYXQgdGhleSdyZVxyXG5cdFx0XHQvLyByZWFkeSB0byBiZSB1c2VkIGJlZm9yZSByZXNvbHZpbmcgdGhlIHByb21pc2UuXHJcblxyXG5cdFx0XHRyZXR1cm4gbmV3IFByb21pc2UoICggcmVzb2x2ZSApID0+IHtcclxuXHJcblx0XHRcdFx0ZnVuY3Rpb24gY2hlY2tNYXRlcmlhbHNSZWFkeSgpIHtcclxuXHJcblx0XHRcdFx0XHRtYXRlcmlhbHMuZm9yRWFjaCggZnVuY3Rpb24gKCBtYXRlcmlhbCApIHtcclxuXHJcblx0XHRcdFx0XHRcdGNvbnN0IG1hdGVyaWFsUHJvcGVydGllcyA9IHByb3BlcnRpZXMuZ2V0KCBtYXRlcmlhbCApO1xyXG5cdFx0XHRcdFx0XHRjb25zdCBwcm9ncmFtID0gbWF0ZXJpYWxQcm9wZXJ0aWVzLmN1cnJlbnRQcm9ncmFtO1xyXG5cclxuXHRcdFx0XHRcdFx0aWYgKCBwcm9ncmFtLmlzUmVhZHkoKSApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0Ly8gcmVtb3ZlIGFueSBwcm9ncmFtcyB0aGF0IHJlcG9ydCB0aGV5J3JlIHJlYWR5IHRvIHVzZSBmcm9tIHRoZSBsaXN0XHJcblx0XHRcdFx0XHRcdFx0bWF0ZXJpYWxzLmRlbGV0ZSggbWF0ZXJpYWwgKTtcclxuXHJcblx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHR9ICk7XHJcblxyXG5cdFx0XHRcdFx0Ly8gb25jZSB0aGUgbGlzdCBvZiBjb21waWxpbmcgbWF0ZXJpYWxzIGlzIGVtcHR5LCBjYWxsIHRoZSBjYWxsYmFja1xyXG5cclxuXHRcdFx0XHRcdGlmICggbWF0ZXJpYWxzLnNpemUgPT09IDAgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRyZXNvbHZlKCBzY2VuZSApO1xyXG5cdFx0XHRcdFx0XHRyZXR1cm47XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdC8vIGlmIHNvbWUgbWF0ZXJpYWxzIGFyZSBzdGlsbCBub3QgcmVhZHksIHdhaXQgYSBiaXQgYW5kIGNoZWNrIGFnYWluXHJcblxyXG5cdFx0XHRcdFx0c2V0VGltZW91dCggY2hlY2tNYXRlcmlhbHNSZWFkeSwgMTAgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRpZiAoIGV4dGVuc2lvbnMuZ2V0KCAnS0hSX3BhcmFsbGVsX3NoYWRlcl9jb21waWxlJyApICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0XHRcdC8vIElmIHdlIGNhbiBjaGVjayB0aGUgY29tcGlsYXRpb24gc3RhdHVzIG9mIHRoZSBtYXRlcmlhbHMgd2l0aG91dFxyXG5cdFx0XHRcdFx0Ly8gYmxvY2tpbmcgdGhlbiBkbyBzbyByaWdodCBhd2F5LlxyXG5cclxuXHRcdFx0XHRcdGNoZWNrTWF0ZXJpYWxzUmVhZHkoKTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHQvLyBPdGhlcndpc2Ugc3RhcnQgYnkgd2FpdGluZyBhIGJpdCB0byBnaXZlIHRoZSBtYXRlcmlhbHMgd2UganVzdFxyXG5cdFx0XHRcdFx0Ly8gaW5pdGlhbGl6ZWQgYSBjaGFuY2UgdG8gZmluaXNoLlxyXG5cclxuXHRcdFx0XHRcdHNldFRpbWVvdXQoIGNoZWNrTWF0ZXJpYWxzUmVhZHksIDEwICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH0gKTtcclxuXHJcblx0XHR9O1xyXG5cclxuXHRcdC8vIEFuaW1hdGlvbiBMb29wXHJcblxyXG5cdFx0bGV0IG9uQW5pbWF0aW9uRnJhbWVDYWxsYmFjayA9IG51bGw7XHJcblxyXG5cdFx0ZnVuY3Rpb24gb25BbmltYXRpb25GcmFtZSggdGltZSApIHtcclxuXHJcblx0XHRcdGlmICggb25BbmltYXRpb25GcmFtZUNhbGxiYWNrICkgb25BbmltYXRpb25GcmFtZUNhbGxiYWNrKCB0aW1lICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGZ1bmN0aW9uIG9uWFJTZXNzaW9uU3RhcnQoKSB7XHJcblxyXG5cdFx0XHRhbmltYXRpb24uc3RvcCgpO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRmdW5jdGlvbiBvblhSU2Vzc2lvbkVuZCgpIHtcclxuXHJcblx0XHRcdGFuaW1hdGlvbi5zdGFydCgpO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCBhbmltYXRpb24gPSBuZXcgV2ViR0xBbmltYXRpb24oKTtcclxuXHRcdGFuaW1hdGlvbi5zZXRBbmltYXRpb25Mb29wKCBvbkFuaW1hdGlvbkZyYW1lICk7XHJcblxyXG5cdFx0aWYgKCB0eXBlb2Ygc2VsZiAhPT0gJ3VuZGVmaW5lZCcgKSBhbmltYXRpb24uc2V0Q29udGV4dCggc2VsZiApO1xyXG5cclxuXHRcdHRoaXMuc2V0QW5pbWF0aW9uTG9vcCA9IGZ1bmN0aW9uICggY2FsbGJhY2sgKSB7XHJcblxyXG5cdFx0XHRvbkFuaW1hdGlvbkZyYW1lQ2FsbGJhY2sgPSBjYWxsYmFjaztcclxuXHRcdFx0eHIuc2V0QW5pbWF0aW9uTG9vcCggY2FsbGJhY2sgKTtcclxuXHJcblx0XHRcdCggY2FsbGJhY2sgPT09IG51bGwgKSA/IGFuaW1hdGlvbi5zdG9wKCkgOiBhbmltYXRpb24uc3RhcnQoKTtcclxuXHJcblx0XHR9O1xyXG5cclxuXHRcdHhyLmFkZEV2ZW50TGlzdGVuZXIoICdzZXNzaW9uc3RhcnQnLCBvblhSU2Vzc2lvblN0YXJ0ICk7XHJcblx0XHR4ci5hZGRFdmVudExpc3RlbmVyKCAnc2Vzc2lvbmVuZCcsIG9uWFJTZXNzaW9uRW5kICk7XHJcblxyXG5cdFx0Ly8gUmVuZGVyaW5nXHJcblxyXG5cdFx0dGhpcy5yZW5kZXIgPSBmdW5jdGlvbiAoIHNjZW5lLCBjYW1lcmEgKSB7XHJcblxyXG5cdFx0XHRpZiAoIGNhbWVyYSAhPT0gdW5kZWZpbmVkICYmIGNhbWVyYS5pc0NhbWVyYSAhPT0gdHJ1ZSApIHtcclxuXHJcblx0XHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLldlYkdMUmVuZGVyZXIucmVuZGVyOiBjYW1lcmEgaXMgbm90IGFuIGluc3RhbmNlIG9mIFRIUkVFLkNhbWVyYS4nICk7XHJcblx0XHRcdFx0cmV0dXJuO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0aWYgKCBfaXNDb250ZXh0TG9zdCA9PT0gdHJ1ZSApIHJldHVybjtcclxuXHJcblx0XHRcdC8vIHVwZGF0ZSBzY2VuZSBncmFwaFxyXG5cclxuXHRcdFx0aWYgKCBzY2VuZS5tYXRyaXhXb3JsZEF1dG9VcGRhdGUgPT09IHRydWUgKSBzY2VuZS51cGRhdGVNYXRyaXhXb3JsZCgpO1xyXG5cclxuXHRcdFx0Ly8gdXBkYXRlIGNhbWVyYSBtYXRyaWNlcyBhbmQgZnJ1c3R1bVxyXG5cclxuXHRcdFx0aWYgKCBjYW1lcmEucGFyZW50ID09PSBudWxsICYmIGNhbWVyYS5tYXRyaXhXb3JsZEF1dG9VcGRhdGUgPT09IHRydWUgKSBjYW1lcmEudXBkYXRlTWF0cml4V29ybGQoKTtcclxuXHJcblx0XHRcdGlmICggeHIuZW5hYmxlZCA9PT0gdHJ1ZSAmJiB4ci5pc1ByZXNlbnRpbmcgPT09IHRydWUgKSB7XHJcblxyXG5cdFx0XHRcdGlmICggeHIuY2FtZXJhQXV0b1VwZGF0ZSA9PT0gdHJ1ZSApIHhyLnVwZGF0ZUNhbWVyYSggY2FtZXJhICk7XHJcblxyXG5cdFx0XHRcdGNhbWVyYSA9IHhyLmdldENhbWVyYSgpOyAvLyB1c2UgWFIgY2FtZXJhIGZvciByZW5kZXJpbmdcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdC8vXHJcblx0XHRcdGlmICggc2NlbmUuaXNTY2VuZSA9PT0gdHJ1ZSApIHNjZW5lLm9uQmVmb3JlUmVuZGVyKCBfdGhpcywgc2NlbmUsIGNhbWVyYSwgX2N1cnJlbnRSZW5kZXJUYXJnZXQgKTtcclxuXHJcblx0XHRcdGN1cnJlbnRSZW5kZXJTdGF0ZSA9IHJlbmRlclN0YXRlcy5nZXQoIHNjZW5lLCByZW5kZXJTdGF0ZVN0YWNrLmxlbmd0aCApO1xyXG5cdFx0XHRjdXJyZW50UmVuZGVyU3RhdGUuaW5pdCgpO1xyXG5cclxuXHRcdFx0cmVuZGVyU3RhdGVTdGFjay5wdXNoKCBjdXJyZW50UmVuZGVyU3RhdGUgKTtcclxuXHJcblx0XHRcdF9wcm9qU2NyZWVuTWF0cml4Lm11bHRpcGx5TWF0cmljZXMoIGNhbWVyYS5wcm9qZWN0aW9uTWF0cml4LCBjYW1lcmEubWF0cml4V29ybGRJbnZlcnNlICk7XHJcblx0XHRcdF9mcnVzdHVtLnNldEZyb21Qcm9qZWN0aW9uTWF0cml4KCBfcHJvalNjcmVlbk1hdHJpeCApO1xyXG5cclxuXHRcdFx0X2xvY2FsQ2xpcHBpbmdFbmFibGVkID0gdGhpcy5sb2NhbENsaXBwaW5nRW5hYmxlZDtcclxuXHRcdFx0X2NsaXBwaW5nRW5hYmxlZCA9IGNsaXBwaW5nLmluaXQoIHRoaXMuY2xpcHBpbmdQbGFuZXMsIF9sb2NhbENsaXBwaW5nRW5hYmxlZCApO1xyXG5cclxuXHRcdFx0Y3VycmVudFJlbmRlckxpc3QgPSByZW5kZXJMaXN0cy5nZXQoIHNjZW5lLCByZW5kZXJMaXN0U3RhY2subGVuZ3RoICk7XHJcblx0XHRcdGN1cnJlbnRSZW5kZXJMaXN0LmluaXQoKTtcclxuXHJcblx0XHRcdHJlbmRlckxpc3RTdGFjay5wdXNoKCBjdXJyZW50UmVuZGVyTGlzdCApO1xyXG5cclxuXHRcdFx0cHJvamVjdE9iamVjdCggc2NlbmUsIGNhbWVyYSwgMCwgX3RoaXMuc29ydE9iamVjdHMgKTtcclxuXHJcblx0XHRcdGN1cnJlbnRSZW5kZXJMaXN0LmZpbmlzaCgpO1xyXG5cclxuXHRcdFx0aWYgKCBfdGhpcy5zb3J0T2JqZWN0cyA9PT0gdHJ1ZSApIHtcclxuXHJcblx0XHRcdFx0Y3VycmVudFJlbmRlckxpc3Quc29ydCggX29wYXF1ZVNvcnQsIF90cmFuc3BhcmVudFNvcnQgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdC8vXHJcblxyXG5cdFx0XHR0aGlzLmluZm8ucmVuZGVyLmZyYW1lICsrO1xyXG5cclxuXHRcdFx0aWYgKCBfY2xpcHBpbmdFbmFibGVkID09PSB0cnVlICkgY2xpcHBpbmcuYmVnaW5TaGFkb3dzKCk7XHJcblxyXG5cdFx0XHRjb25zdCBzaGFkb3dzQXJyYXkgPSBjdXJyZW50UmVuZGVyU3RhdGUuc3RhdGUuc2hhZG93c0FycmF5O1xyXG5cclxuXHRcdFx0c2hhZG93TWFwLnJlbmRlciggc2hhZG93c0FycmF5LCBzY2VuZSwgY2FtZXJhICk7XHJcblxyXG5cdFx0XHRpZiAoIF9jbGlwcGluZ0VuYWJsZWQgPT09IHRydWUgKSBjbGlwcGluZy5lbmRTaGFkb3dzKCk7XHJcblxyXG5cdFx0XHQvL1xyXG5cclxuXHRcdFx0aWYgKCB0aGlzLmluZm8uYXV0b1Jlc2V0ID09PSB0cnVlICkgdGhpcy5pbmZvLnJlc2V0KCk7XHJcblxyXG5cclxuXHRcdFx0Ly9cclxuXHJcblx0XHRcdGlmICggeHIuZW5hYmxlZCA9PT0gZmFsc2UgfHwgeHIuaXNQcmVzZW50aW5nID09PSBmYWxzZSB8fCB4ci5oYXNEZXB0aFNlbnNpbmcoKSA9PT0gZmFsc2UgKSB7XHJcblxyXG5cdFx0XHRcdGJhY2tncm91bmQucmVuZGVyKCBjdXJyZW50UmVuZGVyTGlzdCwgc2NlbmUgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdC8vIHJlbmRlciBzY2VuZVxyXG5cclxuXHRcdFx0Y3VycmVudFJlbmRlclN0YXRlLnNldHVwTGlnaHRzKCBfdGhpcy5fdXNlTGVnYWN5TGlnaHRzICk7XHJcblxyXG5cdFx0XHRpZiAoIGNhbWVyYS5pc0FycmF5Q2FtZXJhICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBjYW1lcmFzID0gY2FtZXJhLmNhbWVyYXM7XHJcblxyXG5cdFx0XHRcdGZvciAoIGxldCBpID0gMCwgbCA9IGNhbWVyYXMubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0XHRjb25zdCBjYW1lcmEyID0gY2FtZXJhc1sgaSBdO1xyXG5cclxuXHRcdFx0XHRcdHJlbmRlclNjZW5lKCBjdXJyZW50UmVuZGVyTGlzdCwgc2NlbmUsIGNhbWVyYTIsIGNhbWVyYTIudmlld3BvcnQgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0cmVuZGVyU2NlbmUoIGN1cnJlbnRSZW5kZXJMaXN0LCBzY2VuZSwgY2FtZXJhICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvL1xyXG5cclxuXHRcdFx0aWYgKCBfY3VycmVudFJlbmRlclRhcmdldCAhPT0gbnVsbCApIHtcclxuXHJcblx0XHRcdFx0Ly8gcmVzb2x2ZSBtdWx0aXNhbXBsZSByZW5kZXJidWZmZXJzIHRvIGEgc2luZ2xlLXNhbXBsZSB0ZXh0dXJlIGlmIG5lY2Vzc2FyeVxyXG5cclxuXHRcdFx0XHR0ZXh0dXJlcy51cGRhdGVNdWx0aXNhbXBsZVJlbmRlclRhcmdldCggX2N1cnJlbnRSZW5kZXJUYXJnZXQgKTtcclxuXHJcblx0XHRcdFx0Ly8gR2VuZXJhdGUgbWlwbWFwIGlmIHdlJ3JlIHVzaW5nIGFueSBraW5kIG9mIG1pcG1hcCBmaWx0ZXJpbmdcclxuXHJcblx0XHRcdFx0dGV4dHVyZXMudXBkYXRlUmVuZGVyVGFyZ2V0TWlwbWFwKCBfY3VycmVudFJlbmRlclRhcmdldCApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Ly9cclxuXHJcblx0XHRcdGlmICggc2NlbmUuaXNTY2VuZSA9PT0gdHJ1ZSApIHNjZW5lLm9uQWZ0ZXJSZW5kZXIoIF90aGlzLCBzY2VuZSwgY2FtZXJhICk7XHJcblxyXG5cdFx0XHQvLyBfZ2wuZmluaXNoKCk7XHJcblxyXG5cdFx0XHRiaW5kaW5nU3RhdGVzLnJlc2V0RGVmYXVsdFN0YXRlKCk7XHJcblx0XHRcdF9jdXJyZW50TWF0ZXJpYWxJZCA9IC0gMTtcclxuXHRcdFx0X2N1cnJlbnRDYW1lcmEgPSBudWxsO1xyXG5cclxuXHRcdFx0cmVuZGVyU3RhdGVTdGFjay5wb3AoKTtcclxuXHJcblx0XHRcdGlmICggcmVuZGVyU3RhdGVTdGFjay5sZW5ndGggPiAwICkge1xyXG5cclxuXHRcdFx0XHRjdXJyZW50UmVuZGVyU3RhdGUgPSByZW5kZXJTdGF0ZVN0YWNrWyByZW5kZXJTdGF0ZVN0YWNrLmxlbmd0aCAtIDEgXTtcclxuXHJcblx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdGN1cnJlbnRSZW5kZXJTdGF0ZSA9IG51bGw7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRyZW5kZXJMaXN0U3RhY2sucG9wKCk7XHJcblxyXG5cdFx0XHRpZiAoIHJlbmRlckxpc3RTdGFjay5sZW5ndGggPiAwICkge1xyXG5cclxuXHRcdFx0XHRjdXJyZW50UmVuZGVyTGlzdCA9IHJlbmRlckxpc3RTdGFja1sgcmVuZGVyTGlzdFN0YWNrLmxlbmd0aCAtIDEgXTtcclxuXHJcblx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdGN1cnJlbnRSZW5kZXJMaXN0ID0gbnVsbDtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9O1xyXG5cclxuXHRcdGZ1bmN0aW9uIHByb2plY3RPYmplY3QoIG9iamVjdCwgY2FtZXJhLCBncm91cE9yZGVyLCBzb3J0T2JqZWN0cyApIHtcclxuXHJcblx0XHRcdGlmICggb2JqZWN0LnZpc2libGUgPT09IGZhbHNlICkgcmV0dXJuO1xyXG5cclxuXHRcdFx0Y29uc3QgdmlzaWJsZSA9IG9iamVjdC5sYXllcnMudGVzdCggY2FtZXJhLmxheWVycyApO1xyXG5cclxuXHRcdFx0aWYgKCB2aXNpYmxlICkge1xyXG5cclxuXHRcdFx0XHRpZiAoIG9iamVjdC5pc0dyb3VwICkge1xyXG5cclxuXHRcdFx0XHRcdGdyb3VwT3JkZXIgPSBvYmplY3QucmVuZGVyT3JkZXI7XHJcblxyXG5cdFx0XHRcdH0gZWxzZSBpZiAoIG9iamVjdC5pc0xPRCApIHtcclxuXHJcblx0XHRcdFx0XHRpZiAoIG9iamVjdC5hdXRvVXBkYXRlID09PSB0cnVlICkgb2JqZWN0LnVwZGF0ZSggY2FtZXJhICk7XHJcblxyXG5cdFx0XHRcdH0gZWxzZSBpZiAoIG9iamVjdC5pc0xpZ2h0ICkge1xyXG5cclxuXHRcdFx0XHRcdGN1cnJlbnRSZW5kZXJTdGF0ZS5wdXNoTGlnaHQoIG9iamVjdCApO1xyXG5cclxuXHRcdFx0XHRcdGlmICggb2JqZWN0LmNhc3RTaGFkb3cgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRjdXJyZW50UmVuZGVyU3RhdGUucHVzaFNoYWRvdyggb2JqZWN0ICk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR9IGVsc2UgaWYgKCBvYmplY3QuaXNTcHJpdGUgKSB7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCAhIG9iamVjdC5mcnVzdHVtQ3VsbGVkIHx8IF9mcnVzdHVtLmludGVyc2VjdHNTcHJpdGUoIG9iamVjdCApICkge1xyXG5cclxuXHRcdFx0XHRcdFx0aWYgKCBzb3J0T2JqZWN0cyApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0X3ZlY3RvcjMuc2V0RnJvbU1hdHJpeFBvc2l0aW9uKCBvYmplY3QubWF0cml4V29ybGQgKVxyXG5cdFx0XHRcdFx0XHRcdFx0LmFwcGx5TWF0cml4NCggX3Byb2pTY3JlZW5NYXRyaXggKTtcclxuXHJcblx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRcdGNvbnN0IGdlb21ldHJ5ID0gb2JqZWN0cy51cGRhdGUoIG9iamVjdCApO1xyXG5cdFx0XHRcdFx0XHRjb25zdCBtYXRlcmlhbCA9IG9iamVjdC5tYXRlcmlhbDtcclxuXHJcblx0XHRcdFx0XHRcdGlmICggbWF0ZXJpYWwudmlzaWJsZSApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0Y3VycmVudFJlbmRlckxpc3QucHVzaCggb2JqZWN0LCBnZW9tZXRyeSwgbWF0ZXJpYWwsIGdyb3VwT3JkZXIsIF92ZWN0b3IzLnosIG51bGwgKTtcclxuXHJcblx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH0gZWxzZSBpZiAoIG9iamVjdC5pc01lc2ggfHwgb2JqZWN0LmlzTGluZSB8fCBvYmplY3QuaXNQb2ludHMgKSB7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCAhIG9iamVjdC5mcnVzdHVtQ3VsbGVkIHx8IF9mcnVzdHVtLmludGVyc2VjdHNPYmplY3QoIG9iamVjdCApICkge1xyXG5cclxuXHRcdFx0XHRcdFx0Y29uc3QgZ2VvbWV0cnkgPSBvYmplY3RzLnVwZGF0ZSggb2JqZWN0ICk7XHJcblx0XHRcdFx0XHRcdGNvbnN0IG1hdGVyaWFsID0gb2JqZWN0Lm1hdGVyaWFsO1xyXG5cclxuXHRcdFx0XHRcdFx0aWYgKCBzb3J0T2JqZWN0cyApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0aWYgKCBvYmplY3QuYm91bmRpbmdTcGhlcmUgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHRpZiAoIG9iamVjdC5ib3VuZGluZ1NwaGVyZSA9PT0gbnVsbCApIG9iamVjdC5jb21wdXRlQm91bmRpbmdTcGhlcmUoKTtcclxuXHRcdFx0XHRcdFx0XHRcdF92ZWN0b3IzLmNvcHkoIG9iamVjdC5ib3VuZGluZ1NwaGVyZS5jZW50ZXIgKTtcclxuXHJcblx0XHRcdFx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHRpZiAoIGdlb21ldHJ5LmJvdW5kaW5nU3BoZXJlID09PSBudWxsICkgZ2VvbWV0cnkuY29tcHV0ZUJvdW5kaW5nU3BoZXJlKCk7XHJcblx0XHRcdFx0XHRcdFx0XHRfdmVjdG9yMy5jb3B5KCBnZW9tZXRyeS5ib3VuZGluZ1NwaGVyZS5jZW50ZXIgKTtcclxuXHJcblx0XHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdFx0XHRfdmVjdG9yM1xyXG5cdFx0XHRcdFx0XHRcdFx0LmFwcGx5TWF0cml4NCggb2JqZWN0Lm1hdHJpeFdvcmxkIClcclxuXHRcdFx0XHRcdFx0XHRcdC5hcHBseU1hdHJpeDQoIF9wcm9qU2NyZWVuTWF0cml4ICk7XHJcblxyXG5cdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0XHRpZiAoIEFycmF5LmlzQXJyYXkoIG1hdGVyaWFsICkgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdGNvbnN0IGdyb3VwcyA9IGdlb21ldHJ5Lmdyb3VwcztcclxuXHJcblx0XHRcdFx0XHRcdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gZ3JvdXBzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0Y29uc3QgZ3JvdXAgPSBncm91cHNbIGkgXTtcclxuXHRcdFx0XHRcdFx0XHRcdGNvbnN0IGdyb3VwTWF0ZXJpYWwgPSBtYXRlcmlhbFsgZ3JvdXAubWF0ZXJpYWxJbmRleCBdO1xyXG5cclxuXHRcdFx0XHRcdFx0XHRcdGlmICggZ3JvdXBNYXRlcmlhbCAmJiBncm91cE1hdGVyaWFsLnZpc2libGUgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0XHRjdXJyZW50UmVuZGVyTGlzdC5wdXNoKCBvYmplY3QsIGdlb21ldHJ5LCBncm91cE1hdGVyaWFsLCBncm91cE9yZGVyLCBfdmVjdG9yMy56LCBncm91cCApO1xyXG5cclxuXHRcdFx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdFx0fSBlbHNlIGlmICggbWF0ZXJpYWwudmlzaWJsZSApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0Y3VycmVudFJlbmRlckxpc3QucHVzaCggb2JqZWN0LCBnZW9tZXRyeSwgbWF0ZXJpYWwsIGdyb3VwT3JkZXIsIF92ZWN0b3IzLnosIG51bGwgKTtcclxuXHJcblx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGNvbnN0IGNoaWxkcmVuID0gb2JqZWN0LmNoaWxkcmVuO1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gY2hpbGRyZW4ubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0cHJvamVjdE9iamVjdCggY2hpbGRyZW5bIGkgXSwgY2FtZXJhLCBncm91cE9yZGVyLCBzb3J0T2JqZWN0cyApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRmdW5jdGlvbiByZW5kZXJTY2VuZSggY3VycmVudFJlbmRlckxpc3QsIHNjZW5lLCBjYW1lcmEsIHZpZXdwb3J0ICkge1xyXG5cclxuXHRcdFx0Y29uc3Qgb3BhcXVlT2JqZWN0cyA9IGN1cnJlbnRSZW5kZXJMaXN0Lm9wYXF1ZTtcclxuXHRcdFx0Y29uc3QgdHJhbnNtaXNzaXZlT2JqZWN0cyA9IGN1cnJlbnRSZW5kZXJMaXN0LnRyYW5zbWlzc2l2ZTtcclxuXHRcdFx0Y29uc3QgdHJhbnNwYXJlbnRPYmplY3RzID0gY3VycmVudFJlbmRlckxpc3QudHJhbnNwYXJlbnQ7XHJcblxyXG5cdFx0XHRjdXJyZW50UmVuZGVyU3RhdGUuc2V0dXBMaWdodHNWaWV3KCBjYW1lcmEgKTtcclxuXHJcblx0XHRcdGlmICggX2NsaXBwaW5nRW5hYmxlZCA9PT0gdHJ1ZSApIGNsaXBwaW5nLnNldEdsb2JhbFN0YXRlKCBfdGhpcy5jbGlwcGluZ1BsYW5lcywgY2FtZXJhICk7XHJcblxyXG5cdFx0XHRpZiAoIHRyYW5zbWlzc2l2ZU9iamVjdHMubGVuZ3RoID4gMCApIHJlbmRlclRyYW5zbWlzc2lvblBhc3MoIG9wYXF1ZU9iamVjdHMsIHRyYW5zbWlzc2l2ZU9iamVjdHMsIHNjZW5lLCBjYW1lcmEgKTtcclxuXHJcblx0XHRcdGlmICggdmlld3BvcnQgKSBzdGF0ZS52aWV3cG9ydCggX2N1cnJlbnRWaWV3cG9ydC5jb3B5KCB2aWV3cG9ydCApICk7XHJcblxyXG5cdFx0XHRpZiAoIG9wYXF1ZU9iamVjdHMubGVuZ3RoID4gMCApIHJlbmRlck9iamVjdHMoIG9wYXF1ZU9iamVjdHMsIHNjZW5lLCBjYW1lcmEgKTtcclxuXHRcdFx0aWYgKCB0cmFuc21pc3NpdmVPYmplY3RzLmxlbmd0aCA+IDAgKSByZW5kZXJPYmplY3RzKCB0cmFuc21pc3NpdmVPYmplY3RzLCBzY2VuZSwgY2FtZXJhICk7XHJcblx0XHRcdGlmICggdHJhbnNwYXJlbnRPYmplY3RzLmxlbmd0aCA+IDAgKSByZW5kZXJPYmplY3RzKCB0cmFuc3BhcmVudE9iamVjdHMsIHNjZW5lLCBjYW1lcmEgKTtcclxuXHJcblx0XHRcdC8vIEVuc3VyZSBkZXB0aCBidWZmZXIgd3JpdGluZyBpcyBlbmFibGVkIHNvIGl0IGNhbiBiZSBjbGVhcmVkIG9uIG5leHQgcmVuZGVyXHJcblxyXG5cdFx0XHRzdGF0ZS5idWZmZXJzLmRlcHRoLnNldFRlc3QoIHRydWUgKTtcclxuXHRcdFx0c3RhdGUuYnVmZmVycy5kZXB0aC5zZXRNYXNrKCB0cnVlICk7XHJcblx0XHRcdHN0YXRlLmJ1ZmZlcnMuY29sb3Iuc2V0TWFzayggdHJ1ZSApO1xyXG5cclxuXHRcdFx0c3RhdGUuc2V0UG9seWdvbk9mZnNldCggZmFsc2UgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0ZnVuY3Rpb24gcmVuZGVyVHJhbnNtaXNzaW9uUGFzcyggb3BhcXVlT2JqZWN0cywgdHJhbnNtaXNzaXZlT2JqZWN0cywgc2NlbmUsIGNhbWVyYSApIHtcclxuXHJcblx0XHRcdGNvbnN0IG92ZXJyaWRlTWF0ZXJpYWwgPSBzY2VuZS5pc1NjZW5lID09PSB0cnVlID8gc2NlbmUub3ZlcnJpZGVNYXRlcmlhbCA6IG51bGw7XHJcblxyXG5cdFx0XHRpZiAoIG92ZXJyaWRlTWF0ZXJpYWwgIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdHJldHVybjtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGNvbnN0IGlzV2ViR0wyID0gY2FwYWJpbGl0aWVzLmlzV2ViR0wyO1xyXG5cclxuXHRcdFx0aWYgKCBfdHJhbnNtaXNzaW9uUmVuZGVyVGFyZ2V0ID09PSBudWxsICkge1xyXG5cclxuXHRcdFx0XHRfdHJhbnNtaXNzaW9uUmVuZGVyVGFyZ2V0ID0gbmV3IFdlYkdMUmVuZGVyVGFyZ2V0KCAxLCAxLCB7XHJcblx0XHRcdFx0XHRnZW5lcmF0ZU1pcG1hcHM6IHRydWUsXHJcblx0XHRcdFx0XHR0eXBlOiBleHRlbnNpb25zLmhhcyggJ0VYVF9jb2xvcl9idWZmZXJfaGFsZl9mbG9hdCcgKSA/IEhhbGZGbG9hdFR5cGUgOiBVbnNpZ25lZEJ5dGVUeXBlLFxyXG5cdFx0XHRcdFx0bWluRmlsdGVyOiBMaW5lYXJNaXBtYXBMaW5lYXJGaWx0ZXIsXHJcblx0XHRcdFx0XHRzYW1wbGVzOiAoIGlzV2ViR0wyICkgPyA0IDogMFxyXG5cdFx0XHRcdH0gKTtcclxuXHJcblx0XHRcdFx0Ly8gZGVidWdcclxuXHJcblx0XHRcdFx0LypcclxuXHRcdFx0XHRjb25zdCBnZW9tZXRyeSA9IG5ldyBQbGFuZUdlb21ldHJ5KCk7XHJcblx0XHRcdFx0Y29uc3QgbWF0ZXJpYWwgPSBuZXcgTWVzaEJhc2ljTWF0ZXJpYWwoIHsgbWFwOiBfdHJhbnNtaXNzaW9uUmVuZGVyVGFyZ2V0LnRleHR1cmUgfSApO1xyXG5cclxuXHRcdFx0XHRjb25zdCBtZXNoID0gbmV3IE1lc2goIGdlb21ldHJ5LCBtYXRlcmlhbCApO1xyXG5cdFx0XHRcdHNjZW5lLmFkZCggbWVzaCApO1xyXG5cdFx0XHRcdCovXHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRfdGhpcy5nZXREcmF3aW5nQnVmZmVyU2l6ZSggX3ZlY3RvcjIgKTtcclxuXHJcblx0XHRcdGlmICggaXNXZWJHTDIgKSB7XHJcblxyXG5cdFx0XHRcdF90cmFuc21pc3Npb25SZW5kZXJUYXJnZXQuc2V0U2l6ZSggX3ZlY3RvcjIueCwgX3ZlY3RvcjIueSApO1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0X3RyYW5zbWlzc2lvblJlbmRlclRhcmdldC5zZXRTaXplKCBmbG9vclBvd2VyT2ZUd28oIF92ZWN0b3IyLnggKSwgZmxvb3JQb3dlck9mVHdvKCBfdmVjdG9yMi55ICkgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdC8vXHJcblxyXG5cdFx0XHRjb25zdCBjdXJyZW50UmVuZGVyVGFyZ2V0ID0gX3RoaXMuZ2V0UmVuZGVyVGFyZ2V0KCk7XHJcblx0XHRcdF90aGlzLnNldFJlbmRlclRhcmdldCggX3RyYW5zbWlzc2lvblJlbmRlclRhcmdldCApO1xyXG5cclxuXHRcdFx0X3RoaXMuZ2V0Q2xlYXJDb2xvciggX2N1cnJlbnRDbGVhckNvbG9yICk7XHJcblx0XHRcdF9jdXJyZW50Q2xlYXJBbHBoYSA9IF90aGlzLmdldENsZWFyQWxwaGEoKTtcclxuXHRcdFx0aWYgKCBfY3VycmVudENsZWFyQWxwaGEgPCAxICkgX3RoaXMuc2V0Q2xlYXJDb2xvciggMHhmZmZmZmYsIDAuNSApO1xyXG5cclxuXHRcdFx0X3RoaXMuY2xlYXIoKTtcclxuXHJcblx0XHRcdC8vIFR1cm4gb2ZmIHRoZSBmZWF0dXJlcyB3aGljaCBjYW4gYWZmZWN0IHRoZSBmcmFnIGNvbG9yIGZvciBvcGFxdWUgb2JqZWN0cyBwYXNzLlxyXG5cdFx0XHQvLyBPdGhlcndpc2UgdGhleSBhcmUgYXBwbGllZCB0d2ljZSBpbiBvcGFxdWUgb2JqZWN0cyBwYXNzIGFuZCB0cmFuc21pc3Npb24gb2JqZWN0cyBwYXNzLlxyXG5cdFx0XHRjb25zdCBjdXJyZW50VG9uZU1hcHBpbmcgPSBfdGhpcy50b25lTWFwcGluZztcclxuXHRcdFx0X3RoaXMudG9uZU1hcHBpbmcgPSBOb1RvbmVNYXBwaW5nO1xyXG5cclxuXHRcdFx0cmVuZGVyT2JqZWN0cyggb3BhcXVlT2JqZWN0cywgc2NlbmUsIGNhbWVyYSApO1xyXG5cclxuXHRcdFx0dGV4dHVyZXMudXBkYXRlTXVsdGlzYW1wbGVSZW5kZXJUYXJnZXQoIF90cmFuc21pc3Npb25SZW5kZXJUYXJnZXQgKTtcclxuXHRcdFx0dGV4dHVyZXMudXBkYXRlUmVuZGVyVGFyZ2V0TWlwbWFwKCBfdHJhbnNtaXNzaW9uUmVuZGVyVGFyZ2V0ICk7XHJcblxyXG5cdFx0XHRsZXQgcmVuZGVyVGFyZ2V0TmVlZHNVcGRhdGUgPSBmYWxzZTtcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMCwgbCA9IHRyYW5zbWlzc2l2ZU9iamVjdHMubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgcmVuZGVySXRlbSA9IHRyYW5zbWlzc2l2ZU9iamVjdHNbIGkgXTtcclxuXHJcblx0XHRcdFx0Y29uc3Qgb2JqZWN0ID0gcmVuZGVySXRlbS5vYmplY3Q7XHJcblx0XHRcdFx0Y29uc3QgZ2VvbWV0cnkgPSByZW5kZXJJdGVtLmdlb21ldHJ5O1xyXG5cdFx0XHRcdGNvbnN0IG1hdGVyaWFsID0gcmVuZGVySXRlbS5tYXRlcmlhbDtcclxuXHRcdFx0XHRjb25zdCBncm91cCA9IHJlbmRlckl0ZW0uZ3JvdXA7XHJcblxyXG5cdFx0XHRcdGlmICggbWF0ZXJpYWwuc2lkZSA9PT0gRG91YmxlU2lkZSAmJiBvYmplY3QubGF5ZXJzLnRlc3QoIGNhbWVyYS5sYXllcnMgKSApIHtcclxuXHJcblx0XHRcdFx0XHRjb25zdCBjdXJyZW50U2lkZSA9IG1hdGVyaWFsLnNpZGU7XHJcblxyXG5cdFx0XHRcdFx0bWF0ZXJpYWwuc2lkZSA9IEJhY2tTaWRlO1xyXG5cdFx0XHRcdFx0bWF0ZXJpYWwubmVlZHNVcGRhdGUgPSB0cnVlO1xyXG5cclxuXHRcdFx0XHRcdHJlbmRlck9iamVjdCggb2JqZWN0LCBzY2VuZSwgY2FtZXJhLCBnZW9tZXRyeSwgbWF0ZXJpYWwsIGdyb3VwICk7XHJcblxyXG5cdFx0XHRcdFx0bWF0ZXJpYWwuc2lkZSA9IGN1cnJlbnRTaWRlO1xyXG5cdFx0XHRcdFx0bWF0ZXJpYWwubmVlZHNVcGRhdGUgPSB0cnVlO1xyXG5cclxuXHRcdFx0XHRcdHJlbmRlclRhcmdldE5lZWRzVXBkYXRlID0gdHJ1ZTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0aWYgKCByZW5kZXJUYXJnZXROZWVkc1VwZGF0ZSA9PT0gdHJ1ZSApIHtcclxuXHJcblx0XHRcdFx0dGV4dHVyZXMudXBkYXRlTXVsdGlzYW1wbGVSZW5kZXJUYXJnZXQoIF90cmFuc21pc3Npb25SZW5kZXJUYXJnZXQgKTtcclxuXHRcdFx0XHR0ZXh0dXJlcy51cGRhdGVSZW5kZXJUYXJnZXRNaXBtYXAoIF90cmFuc21pc3Npb25SZW5kZXJUYXJnZXQgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdF90aGlzLnNldFJlbmRlclRhcmdldCggY3VycmVudFJlbmRlclRhcmdldCApO1xyXG5cclxuXHRcdFx0X3RoaXMuc2V0Q2xlYXJDb2xvciggX2N1cnJlbnRDbGVhckNvbG9yLCBfY3VycmVudENsZWFyQWxwaGEgKTtcclxuXHJcblx0XHRcdF90aGlzLnRvbmVNYXBwaW5nID0gY3VycmVudFRvbmVNYXBwaW5nO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRmdW5jdGlvbiByZW5kZXJPYmplY3RzKCByZW5kZXJMaXN0LCBzY2VuZSwgY2FtZXJhICkge1xyXG5cclxuXHRcdFx0Y29uc3Qgb3ZlcnJpZGVNYXRlcmlhbCA9IHNjZW5lLmlzU2NlbmUgPT09IHRydWUgPyBzY2VuZS5vdmVycmlkZU1hdGVyaWFsIDogbnVsbDtcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMCwgbCA9IHJlbmRlckxpc3QubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgcmVuZGVySXRlbSA9IHJlbmRlckxpc3RbIGkgXTtcclxuXHJcblx0XHRcdFx0Y29uc3Qgb2JqZWN0ID0gcmVuZGVySXRlbS5vYmplY3Q7XHJcblx0XHRcdFx0Y29uc3QgZ2VvbWV0cnkgPSByZW5kZXJJdGVtLmdlb21ldHJ5O1xyXG5cdFx0XHRcdGNvbnN0IG1hdGVyaWFsID0gb3ZlcnJpZGVNYXRlcmlhbCA9PT0gbnVsbCA/IHJlbmRlckl0ZW0ubWF0ZXJpYWwgOiBvdmVycmlkZU1hdGVyaWFsO1xyXG5cdFx0XHRcdGNvbnN0IGdyb3VwID0gcmVuZGVySXRlbS5ncm91cDtcclxuXHJcblx0XHRcdFx0aWYgKCBvYmplY3QubGF5ZXJzLnRlc3QoIGNhbWVyYS5sYXllcnMgKSApIHtcclxuXHJcblx0XHRcdFx0XHRyZW5kZXJPYmplY3QoIG9iamVjdCwgc2NlbmUsIGNhbWVyYSwgZ2VvbWV0cnksIG1hdGVyaWFsLCBncm91cCApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGZ1bmN0aW9uIHJlbmRlck9iamVjdCggb2JqZWN0LCBzY2VuZSwgY2FtZXJhLCBnZW9tZXRyeSwgbWF0ZXJpYWwsIGdyb3VwICkge1xyXG5cclxuXHRcdFx0b2JqZWN0Lm9uQmVmb3JlUmVuZGVyKCBfdGhpcywgc2NlbmUsIGNhbWVyYSwgZ2VvbWV0cnksIG1hdGVyaWFsLCBncm91cCApO1xyXG5cclxuXHRcdFx0b2JqZWN0Lm1vZGVsVmlld01hdHJpeC5tdWx0aXBseU1hdHJpY2VzKCBjYW1lcmEubWF0cml4V29ybGRJbnZlcnNlLCBvYmplY3QubWF0cml4V29ybGQgKTtcclxuXHRcdFx0b2JqZWN0Lm5vcm1hbE1hdHJpeC5nZXROb3JtYWxNYXRyaXgoIG9iamVjdC5tb2RlbFZpZXdNYXRyaXggKTtcclxuXHJcblx0XHRcdG1hdGVyaWFsLm9uQmVmb3JlUmVuZGVyKCBfdGhpcywgc2NlbmUsIGNhbWVyYSwgZ2VvbWV0cnksIG9iamVjdCwgZ3JvdXAgKTtcclxuXHJcblx0XHRcdGlmICggbWF0ZXJpYWwudHJhbnNwYXJlbnQgPT09IHRydWUgJiYgbWF0ZXJpYWwuc2lkZSA9PT0gRG91YmxlU2lkZSAmJiBtYXRlcmlhbC5mb3JjZVNpbmdsZVBhc3MgPT09IGZhbHNlICkge1xyXG5cclxuXHRcdFx0XHRtYXRlcmlhbC5zaWRlID0gQmFja1NpZGU7XHJcblx0XHRcdFx0bWF0ZXJpYWwubmVlZHNVcGRhdGUgPSB0cnVlO1xyXG5cdFx0XHRcdF90aGlzLnJlbmRlckJ1ZmZlckRpcmVjdCggY2FtZXJhLCBzY2VuZSwgZ2VvbWV0cnksIG1hdGVyaWFsLCBvYmplY3QsIGdyb3VwICk7XHJcblxyXG5cdFx0XHRcdG1hdGVyaWFsLnNpZGUgPSBGcm9udFNpZGU7XHJcblx0XHRcdFx0bWF0ZXJpYWwubmVlZHNVcGRhdGUgPSB0cnVlO1xyXG5cdFx0XHRcdF90aGlzLnJlbmRlckJ1ZmZlckRpcmVjdCggY2FtZXJhLCBzY2VuZSwgZ2VvbWV0cnksIG1hdGVyaWFsLCBvYmplY3QsIGdyb3VwICk7XHJcblxyXG5cdFx0XHRcdG1hdGVyaWFsLnNpZGUgPSBEb3VibGVTaWRlO1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0X3RoaXMucmVuZGVyQnVmZmVyRGlyZWN0KCBjYW1lcmEsIHNjZW5lLCBnZW9tZXRyeSwgbWF0ZXJpYWwsIG9iamVjdCwgZ3JvdXAgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdG9iamVjdC5vbkFmdGVyUmVuZGVyKCBfdGhpcywgc2NlbmUsIGNhbWVyYSwgZ2VvbWV0cnksIG1hdGVyaWFsLCBncm91cCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRmdW5jdGlvbiBnZXRQcm9ncmFtKCBtYXRlcmlhbCwgc2NlbmUsIG9iamVjdCApIHtcclxuXHJcblx0XHRcdGlmICggc2NlbmUuaXNTY2VuZSAhPT0gdHJ1ZSApIHNjZW5lID0gX2VtcHR5U2NlbmU7IC8vIHNjZW5lIGNvdWxkIGJlIGEgTWVzaCwgTGluZSwgUG9pbnRzLCAuLi5cclxuXHJcblx0XHRcdGNvbnN0IG1hdGVyaWFsUHJvcGVydGllcyA9IHByb3BlcnRpZXMuZ2V0KCBtYXRlcmlhbCApO1xyXG5cclxuXHRcdFx0Y29uc3QgbGlnaHRzID0gY3VycmVudFJlbmRlclN0YXRlLnN0YXRlLmxpZ2h0cztcclxuXHRcdFx0Y29uc3Qgc2hhZG93c0FycmF5ID0gY3VycmVudFJlbmRlclN0YXRlLnN0YXRlLnNoYWRvd3NBcnJheTtcclxuXHJcblx0XHRcdGNvbnN0IGxpZ2h0c1N0YXRlVmVyc2lvbiA9IGxpZ2h0cy5zdGF0ZS52ZXJzaW9uO1xyXG5cclxuXHRcdFx0Y29uc3QgcGFyYW1ldGVycyA9IHByb2dyYW1DYWNoZS5nZXRQYXJhbWV0ZXJzKCBtYXRlcmlhbCwgbGlnaHRzLnN0YXRlLCBzaGFkb3dzQXJyYXksIHNjZW5lLCBvYmplY3QgKTtcclxuXHRcdFx0Y29uc3QgcHJvZ3JhbUNhY2hlS2V5ID0gcHJvZ3JhbUNhY2hlLmdldFByb2dyYW1DYWNoZUtleSggcGFyYW1ldGVycyApO1xyXG5cclxuXHRcdFx0bGV0IHByb2dyYW1zID0gbWF0ZXJpYWxQcm9wZXJ0aWVzLnByb2dyYW1zO1xyXG5cclxuXHRcdFx0Ly8gYWx3YXlzIHVwZGF0ZSBlbnZpcm9ubWVudCBhbmQgZm9nIC0gY2hhbmdpbmcgdGhlc2UgdHJpZ2dlciBhbiBnZXRQcm9ncmFtIGNhbGwsIGJ1dCBpdCdzIHBvc3NpYmxlIHRoYXQgdGhlIHByb2dyYW0gZG9lc24ndCBjaGFuZ2VcclxuXHJcblx0XHRcdG1hdGVyaWFsUHJvcGVydGllcy5lbnZpcm9ubWVudCA9IG1hdGVyaWFsLmlzTWVzaFN0YW5kYXJkTWF0ZXJpYWwgPyBzY2VuZS5lbnZpcm9ubWVudCA6IG51bGw7XHJcblx0XHRcdG1hdGVyaWFsUHJvcGVydGllcy5mb2cgPSBzY2VuZS5mb2c7XHJcblx0XHRcdG1hdGVyaWFsUHJvcGVydGllcy5lbnZNYXAgPSAoIG1hdGVyaWFsLmlzTWVzaFN0YW5kYXJkTWF0ZXJpYWwgPyBjdWJldXZtYXBzIDogY3ViZW1hcHMgKS5nZXQoIG1hdGVyaWFsLmVudk1hcCB8fCBtYXRlcmlhbFByb3BlcnRpZXMuZW52aXJvbm1lbnQgKTtcclxuXHJcblx0XHRcdGlmICggcHJvZ3JhbXMgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0Ly8gbmV3IG1hdGVyaWFsXHJcblxyXG5cdFx0XHRcdG1hdGVyaWFsLmFkZEV2ZW50TGlzdGVuZXIoICdkaXNwb3NlJywgb25NYXRlcmlhbERpc3Bvc2UgKTtcclxuXHJcblx0XHRcdFx0cHJvZ3JhbXMgPSBuZXcgTWFwKCk7XHJcblx0XHRcdFx0bWF0ZXJpYWxQcm9wZXJ0aWVzLnByb2dyYW1zID0gcHJvZ3JhbXM7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRsZXQgcHJvZ3JhbSA9IHByb2dyYW1zLmdldCggcHJvZ3JhbUNhY2hlS2V5ICk7XHJcblxyXG5cdFx0XHRpZiAoIHByb2dyYW0gIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0Ly8gZWFybHkgb3V0IGlmIHByb2dyYW0gYW5kIGxpZ2h0IHN0YXRlIGlzIGlkZW50aWNhbFxyXG5cclxuXHRcdFx0XHRpZiAoIG1hdGVyaWFsUHJvcGVydGllcy5jdXJyZW50UHJvZ3JhbSA9PT0gcHJvZ3JhbSAmJiBtYXRlcmlhbFByb3BlcnRpZXMubGlnaHRzU3RhdGVWZXJzaW9uID09PSBsaWdodHNTdGF0ZVZlcnNpb24gKSB7XHJcblxyXG5cdFx0XHRcdFx0dXBkYXRlQ29tbW9uTWF0ZXJpYWxQcm9wZXJ0aWVzKCBtYXRlcmlhbCwgcGFyYW1ldGVycyApO1xyXG5cclxuXHRcdFx0XHRcdHJldHVybiBwcm9ncmFtO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRwYXJhbWV0ZXJzLnVuaWZvcm1zID0gcHJvZ3JhbUNhY2hlLmdldFVuaWZvcm1zKCBtYXRlcmlhbCApO1xyXG5cclxuXHRcdFx0XHRtYXRlcmlhbC5vbkJ1aWxkKCBvYmplY3QsIHBhcmFtZXRlcnMsIF90aGlzICk7XHJcblxyXG5cdFx0XHRcdG1hdGVyaWFsLm9uQmVmb3JlQ29tcGlsZSggcGFyYW1ldGVycywgX3RoaXMgKTtcclxuXHJcblx0XHRcdFx0cHJvZ3JhbSA9IHByb2dyYW1DYWNoZS5hY3F1aXJlUHJvZ3JhbSggcGFyYW1ldGVycywgcHJvZ3JhbUNhY2hlS2V5ICk7XHJcblx0XHRcdFx0cHJvZ3JhbXMuc2V0KCBwcm9ncmFtQ2FjaGVLZXksIHByb2dyYW0gKTtcclxuXHJcblx0XHRcdFx0bWF0ZXJpYWxQcm9wZXJ0aWVzLnVuaWZvcm1zID0gcGFyYW1ldGVycy51bmlmb3JtcztcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGNvbnN0IHVuaWZvcm1zID0gbWF0ZXJpYWxQcm9wZXJ0aWVzLnVuaWZvcm1zO1xyXG5cclxuXHRcdFx0aWYgKCAoICEgbWF0ZXJpYWwuaXNTaGFkZXJNYXRlcmlhbCAmJiAhIG1hdGVyaWFsLmlzUmF3U2hhZGVyTWF0ZXJpYWwgKSB8fCBtYXRlcmlhbC5jbGlwcGluZyA9PT0gdHJ1ZSApIHtcclxuXHJcblx0XHRcdFx0dW5pZm9ybXMuY2xpcHBpbmdQbGFuZXMgPSBjbGlwcGluZy51bmlmb3JtO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0dXBkYXRlQ29tbW9uTWF0ZXJpYWxQcm9wZXJ0aWVzKCBtYXRlcmlhbCwgcGFyYW1ldGVycyApO1xyXG5cclxuXHRcdFx0Ly8gc3RvcmUgdGhlIGxpZ2h0IHNldHVwIGl0IHdhcyBjcmVhdGVkIGZvclxyXG5cclxuXHRcdFx0bWF0ZXJpYWxQcm9wZXJ0aWVzLm5lZWRzTGlnaHRzID0gbWF0ZXJpYWxOZWVkc0xpZ2h0cyggbWF0ZXJpYWwgKTtcclxuXHRcdFx0bWF0ZXJpYWxQcm9wZXJ0aWVzLmxpZ2h0c1N0YXRlVmVyc2lvbiA9IGxpZ2h0c1N0YXRlVmVyc2lvbjtcclxuXHJcblx0XHRcdGlmICggbWF0ZXJpYWxQcm9wZXJ0aWVzLm5lZWRzTGlnaHRzICkge1xyXG5cclxuXHRcdFx0XHQvLyB3aXJlIHVwIHRoZSBtYXRlcmlhbCB0byB0aGlzIHJlbmRlcmVyJ3MgbGlnaHRpbmcgc3RhdGVcclxuXHJcblx0XHRcdFx0dW5pZm9ybXMuYW1iaWVudExpZ2h0Q29sb3IudmFsdWUgPSBsaWdodHMuc3RhdGUuYW1iaWVudDtcclxuXHRcdFx0XHR1bmlmb3Jtcy5saWdodFByb2JlLnZhbHVlID0gbGlnaHRzLnN0YXRlLnByb2JlO1xyXG5cdFx0XHRcdHVuaWZvcm1zLmRpcmVjdGlvbmFsTGlnaHRzLnZhbHVlID0gbGlnaHRzLnN0YXRlLmRpcmVjdGlvbmFsO1xyXG5cdFx0XHRcdHVuaWZvcm1zLmRpcmVjdGlvbmFsTGlnaHRTaGFkb3dzLnZhbHVlID0gbGlnaHRzLnN0YXRlLmRpcmVjdGlvbmFsU2hhZG93O1xyXG5cdFx0XHRcdHVuaWZvcm1zLnNwb3RMaWdodHMudmFsdWUgPSBsaWdodHMuc3RhdGUuc3BvdDtcclxuXHRcdFx0XHR1bmlmb3Jtcy5zcG90TGlnaHRTaGFkb3dzLnZhbHVlID0gbGlnaHRzLnN0YXRlLnNwb3RTaGFkb3c7XHJcblx0XHRcdFx0dW5pZm9ybXMucmVjdEFyZWFMaWdodHMudmFsdWUgPSBsaWdodHMuc3RhdGUucmVjdEFyZWE7XHJcblx0XHRcdFx0dW5pZm9ybXMubHRjXzEudmFsdWUgPSBsaWdodHMuc3RhdGUucmVjdEFyZWFMVEMxO1xyXG5cdFx0XHRcdHVuaWZvcm1zLmx0Y18yLnZhbHVlID0gbGlnaHRzLnN0YXRlLnJlY3RBcmVhTFRDMjtcclxuXHRcdFx0XHR1bmlmb3Jtcy5wb2ludExpZ2h0cy52YWx1ZSA9IGxpZ2h0cy5zdGF0ZS5wb2ludDtcclxuXHRcdFx0XHR1bmlmb3Jtcy5wb2ludExpZ2h0U2hhZG93cy52YWx1ZSA9IGxpZ2h0cy5zdGF0ZS5wb2ludFNoYWRvdztcclxuXHRcdFx0XHR1bmlmb3Jtcy5oZW1pc3BoZXJlTGlnaHRzLnZhbHVlID0gbGlnaHRzLnN0YXRlLmhlbWk7XHJcblxyXG5cdFx0XHRcdHVuaWZvcm1zLmRpcmVjdGlvbmFsU2hhZG93TWFwLnZhbHVlID0gbGlnaHRzLnN0YXRlLmRpcmVjdGlvbmFsU2hhZG93TWFwO1xyXG5cdFx0XHRcdHVuaWZvcm1zLmRpcmVjdGlvbmFsU2hhZG93TWF0cml4LnZhbHVlID0gbGlnaHRzLnN0YXRlLmRpcmVjdGlvbmFsU2hhZG93TWF0cml4O1xyXG5cdFx0XHRcdHVuaWZvcm1zLnNwb3RTaGFkb3dNYXAudmFsdWUgPSBsaWdodHMuc3RhdGUuc3BvdFNoYWRvd01hcDtcclxuXHRcdFx0XHR1bmlmb3Jtcy5zcG90TGlnaHRNYXRyaXgudmFsdWUgPSBsaWdodHMuc3RhdGUuc3BvdExpZ2h0TWF0cml4O1xyXG5cdFx0XHRcdHVuaWZvcm1zLnNwb3RMaWdodE1hcC52YWx1ZSA9IGxpZ2h0cy5zdGF0ZS5zcG90TGlnaHRNYXA7XHJcblx0XHRcdFx0dW5pZm9ybXMucG9pbnRTaGFkb3dNYXAudmFsdWUgPSBsaWdodHMuc3RhdGUucG9pbnRTaGFkb3dNYXA7XHJcblx0XHRcdFx0dW5pZm9ybXMucG9pbnRTaGFkb3dNYXRyaXgudmFsdWUgPSBsaWdodHMuc3RhdGUucG9pbnRTaGFkb3dNYXRyaXg7XHJcblx0XHRcdFx0Ly8gVE9ETyAoYWJlbG5hdGlvbik6IGFkZCBhcmVhIGxpZ2h0cyBzaGFkb3cgaW5mbyB0byB1bmlmb3Jtc1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0bWF0ZXJpYWxQcm9wZXJ0aWVzLmN1cnJlbnRQcm9ncmFtID0gcHJvZ3JhbTtcclxuXHRcdFx0bWF0ZXJpYWxQcm9wZXJ0aWVzLnVuaWZvcm1zTGlzdCA9IG51bGw7XHJcblxyXG5cdFx0XHRyZXR1cm4gcHJvZ3JhbTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0ZnVuY3Rpb24gZ2V0VW5pZm9ybUxpc3QoIG1hdGVyaWFsUHJvcGVydGllcyApIHtcclxuXHJcblx0XHRcdGlmICggbWF0ZXJpYWxQcm9wZXJ0aWVzLnVuaWZvcm1zTGlzdCA9PT0gbnVsbCApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgcHJvZ1VuaWZvcm1zID0gbWF0ZXJpYWxQcm9wZXJ0aWVzLmN1cnJlbnRQcm9ncmFtLmdldFVuaWZvcm1zKCk7XHJcblx0XHRcdFx0bWF0ZXJpYWxQcm9wZXJ0aWVzLnVuaWZvcm1zTGlzdCA9IFdlYkdMVW5pZm9ybXMuc2VxV2l0aFZhbHVlKCBwcm9nVW5pZm9ybXMuc2VxLCBtYXRlcmlhbFByb3BlcnRpZXMudW5pZm9ybXMgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHJldHVybiBtYXRlcmlhbFByb3BlcnRpZXMudW5pZm9ybXNMaXN0O1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRmdW5jdGlvbiB1cGRhdGVDb21tb25NYXRlcmlhbFByb3BlcnRpZXMoIG1hdGVyaWFsLCBwYXJhbWV0ZXJzICkge1xyXG5cclxuXHRcdFx0Y29uc3QgbWF0ZXJpYWxQcm9wZXJ0aWVzID0gcHJvcGVydGllcy5nZXQoIG1hdGVyaWFsICk7XHJcblxyXG5cdFx0XHRtYXRlcmlhbFByb3BlcnRpZXMub3V0cHV0Q29sb3JTcGFjZSA9IHBhcmFtZXRlcnMub3V0cHV0Q29sb3JTcGFjZTtcclxuXHRcdFx0bWF0ZXJpYWxQcm9wZXJ0aWVzLmJhdGNoaW5nID0gcGFyYW1ldGVycy5iYXRjaGluZztcclxuXHRcdFx0bWF0ZXJpYWxQcm9wZXJ0aWVzLmluc3RhbmNpbmcgPSBwYXJhbWV0ZXJzLmluc3RhbmNpbmc7XHJcblx0XHRcdG1hdGVyaWFsUHJvcGVydGllcy5pbnN0YW5jaW5nQ29sb3IgPSBwYXJhbWV0ZXJzLmluc3RhbmNpbmdDb2xvcjtcclxuXHRcdFx0bWF0ZXJpYWxQcm9wZXJ0aWVzLnNraW5uaW5nID0gcGFyYW1ldGVycy5za2lubmluZztcclxuXHRcdFx0bWF0ZXJpYWxQcm9wZXJ0aWVzLm1vcnBoVGFyZ2V0cyA9IHBhcmFtZXRlcnMubW9ycGhUYXJnZXRzO1xyXG5cdFx0XHRtYXRlcmlhbFByb3BlcnRpZXMubW9ycGhOb3JtYWxzID0gcGFyYW1ldGVycy5tb3JwaE5vcm1hbHM7XHJcblx0XHRcdG1hdGVyaWFsUHJvcGVydGllcy5tb3JwaENvbG9ycyA9IHBhcmFtZXRlcnMubW9ycGhDb2xvcnM7XHJcblx0XHRcdG1hdGVyaWFsUHJvcGVydGllcy5tb3JwaFRhcmdldHNDb3VudCA9IHBhcmFtZXRlcnMubW9ycGhUYXJnZXRzQ291bnQ7XHJcblx0XHRcdG1hdGVyaWFsUHJvcGVydGllcy5udW1DbGlwcGluZ1BsYW5lcyA9IHBhcmFtZXRlcnMubnVtQ2xpcHBpbmdQbGFuZXM7XHJcblx0XHRcdG1hdGVyaWFsUHJvcGVydGllcy5udW1JbnRlcnNlY3Rpb24gPSBwYXJhbWV0ZXJzLm51bUNsaXBJbnRlcnNlY3Rpb247XHJcblx0XHRcdG1hdGVyaWFsUHJvcGVydGllcy52ZXJ0ZXhBbHBoYXMgPSBwYXJhbWV0ZXJzLnZlcnRleEFscGhhcztcclxuXHRcdFx0bWF0ZXJpYWxQcm9wZXJ0aWVzLnZlcnRleFRhbmdlbnRzID0gcGFyYW1ldGVycy52ZXJ0ZXhUYW5nZW50cztcclxuXHRcdFx0bWF0ZXJpYWxQcm9wZXJ0aWVzLnRvbmVNYXBwaW5nID0gcGFyYW1ldGVycy50b25lTWFwcGluZztcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0ZnVuY3Rpb24gc2V0UHJvZ3JhbSggY2FtZXJhLCBzY2VuZSwgZ2VvbWV0cnksIG1hdGVyaWFsLCBvYmplY3QgKSB7XHJcblxyXG5cdFx0XHRpZiAoIHNjZW5lLmlzU2NlbmUgIT09IHRydWUgKSBzY2VuZSA9IF9lbXB0eVNjZW5lOyAvLyBzY2VuZSBjb3VsZCBiZSBhIE1lc2gsIExpbmUsIFBvaW50cywgLi4uXHJcblxyXG5cdFx0XHR0ZXh0dXJlcy5yZXNldFRleHR1cmVVbml0cygpO1xyXG5cclxuXHRcdFx0Y29uc3QgZm9nID0gc2NlbmUuZm9nO1xyXG5cdFx0XHRjb25zdCBlbnZpcm9ubWVudCA9IG1hdGVyaWFsLmlzTWVzaFN0YW5kYXJkTWF0ZXJpYWwgPyBzY2VuZS5lbnZpcm9ubWVudCA6IG51bGw7XHJcblx0XHRcdGNvbnN0IGNvbG9yU3BhY2UgPSAoIF9jdXJyZW50UmVuZGVyVGFyZ2V0ID09PSBudWxsICkgPyBfdGhpcy5vdXRwdXRDb2xvclNwYWNlIDogKCBfY3VycmVudFJlbmRlclRhcmdldC5pc1hSUmVuZGVyVGFyZ2V0ID09PSB0cnVlID8gX2N1cnJlbnRSZW5kZXJUYXJnZXQudGV4dHVyZS5jb2xvclNwYWNlIDogTGluZWFyU1JHQkNvbG9yU3BhY2UgKTtcclxuXHRcdFx0Y29uc3QgZW52TWFwID0gKCBtYXRlcmlhbC5pc01lc2hTdGFuZGFyZE1hdGVyaWFsID8gY3ViZXV2bWFwcyA6IGN1YmVtYXBzICkuZ2V0KCBtYXRlcmlhbC5lbnZNYXAgfHwgZW52aXJvbm1lbnQgKTtcclxuXHRcdFx0Y29uc3QgdmVydGV4QWxwaGFzID0gbWF0ZXJpYWwudmVydGV4Q29sb3JzID09PSB0cnVlICYmICEhIGdlb21ldHJ5LmF0dHJpYnV0ZXMuY29sb3IgJiYgZ2VvbWV0cnkuYXR0cmlidXRlcy5jb2xvci5pdGVtU2l6ZSA9PT0gNDtcclxuXHRcdFx0Y29uc3QgdmVydGV4VGFuZ2VudHMgPSAhISBnZW9tZXRyeS5hdHRyaWJ1dGVzLnRhbmdlbnQgJiYgKCAhISBtYXRlcmlhbC5ub3JtYWxNYXAgfHwgbWF0ZXJpYWwuYW5pc290cm9weSA+IDAgKTtcclxuXHRcdFx0Y29uc3QgbW9ycGhUYXJnZXRzID0gISEgZ2VvbWV0cnkubW9ycGhBdHRyaWJ1dGVzLnBvc2l0aW9uO1xyXG5cdFx0XHRjb25zdCBtb3JwaE5vcm1hbHMgPSAhISBnZW9tZXRyeS5tb3JwaEF0dHJpYnV0ZXMubm9ybWFsO1xyXG5cdFx0XHRjb25zdCBtb3JwaENvbG9ycyA9ICEhIGdlb21ldHJ5Lm1vcnBoQXR0cmlidXRlcy5jb2xvcjtcclxuXHJcblx0XHRcdGxldCB0b25lTWFwcGluZyA9IE5vVG9uZU1hcHBpbmc7XHJcblxyXG5cdFx0XHRpZiAoIG1hdGVyaWFsLnRvbmVNYXBwZWQgKSB7XHJcblxyXG5cdFx0XHRcdGlmICggX2N1cnJlbnRSZW5kZXJUYXJnZXQgPT09IG51bGwgfHwgX2N1cnJlbnRSZW5kZXJUYXJnZXQuaXNYUlJlbmRlclRhcmdldCA9PT0gdHJ1ZSApIHtcclxuXHJcblx0XHRcdFx0XHR0b25lTWFwcGluZyA9IF90aGlzLnRvbmVNYXBwaW5nO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRjb25zdCBtb3JwaEF0dHJpYnV0ZSA9IGdlb21ldHJ5Lm1vcnBoQXR0cmlidXRlcy5wb3NpdGlvbiB8fCBnZW9tZXRyeS5tb3JwaEF0dHJpYnV0ZXMubm9ybWFsIHx8IGdlb21ldHJ5Lm1vcnBoQXR0cmlidXRlcy5jb2xvcjtcclxuXHRcdFx0Y29uc3QgbW9ycGhUYXJnZXRzQ291bnQgPSAoIG1vcnBoQXR0cmlidXRlICE9PSB1bmRlZmluZWQgKSA/IG1vcnBoQXR0cmlidXRlLmxlbmd0aCA6IDA7XHJcblxyXG5cdFx0XHRjb25zdCBtYXRlcmlhbFByb3BlcnRpZXMgPSBwcm9wZXJ0aWVzLmdldCggbWF0ZXJpYWwgKTtcclxuXHRcdFx0Y29uc3QgbGlnaHRzID0gY3VycmVudFJlbmRlclN0YXRlLnN0YXRlLmxpZ2h0cztcclxuXHJcblx0XHRcdGlmICggX2NsaXBwaW5nRW5hYmxlZCA9PT0gdHJ1ZSApIHtcclxuXHJcblx0XHRcdFx0aWYgKCBfbG9jYWxDbGlwcGluZ0VuYWJsZWQgPT09IHRydWUgfHwgY2FtZXJhICE9PSBfY3VycmVudENhbWVyYSApIHtcclxuXHJcblx0XHRcdFx0XHRjb25zdCB1c2VDYWNoZSA9XHJcblx0XHRcdFx0XHRcdGNhbWVyYSA9PT0gX2N1cnJlbnRDYW1lcmEgJiZcclxuXHRcdFx0XHRcdFx0bWF0ZXJpYWwuaWQgPT09IF9jdXJyZW50TWF0ZXJpYWxJZDtcclxuXHJcblx0XHRcdFx0XHQvLyB3ZSBtaWdodCB3YW50IHRvIGNhbGwgdGhpcyBmdW5jdGlvbiB3aXRoIHNvbWUgQ2xpcHBpbmdHcm91cFxyXG5cdFx0XHRcdFx0Ly8gb2JqZWN0IGluc3RlYWQgb2YgdGhlIG1hdGVyaWFsLCBvbmNlIGl0IGJlY29tZXMgZmVhc2libGVcclxuXHRcdFx0XHRcdC8vICgjODQ2NSwgIzgzNzkpXHJcblx0XHRcdFx0XHRjbGlwcGluZy5zZXRTdGF0ZSggbWF0ZXJpYWwsIGNhbWVyYSwgdXNlQ2FjaGUgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Ly9cclxuXHJcblx0XHRcdGxldCBuZWVkc1Byb2dyYW1DaGFuZ2UgPSBmYWxzZTtcclxuXHJcblx0XHRcdGlmICggbWF0ZXJpYWwudmVyc2lvbiA9PT0gbWF0ZXJpYWxQcm9wZXJ0aWVzLl9fdmVyc2lvbiApIHtcclxuXHJcblx0XHRcdFx0aWYgKCBtYXRlcmlhbFByb3BlcnRpZXMubmVlZHNMaWdodHMgJiYgKCBtYXRlcmlhbFByb3BlcnRpZXMubGlnaHRzU3RhdGVWZXJzaW9uICE9PSBsaWdodHMuc3RhdGUudmVyc2lvbiApICkge1xyXG5cclxuXHRcdFx0XHRcdG5lZWRzUHJvZ3JhbUNoYW5nZSA9IHRydWU7XHJcblxyXG5cdFx0XHRcdH0gZWxzZSBpZiAoIG1hdGVyaWFsUHJvcGVydGllcy5vdXRwdXRDb2xvclNwYWNlICE9PSBjb2xvclNwYWNlICkge1xyXG5cclxuXHRcdFx0XHRcdG5lZWRzUHJvZ3JhbUNoYW5nZSA9IHRydWU7XHJcblxyXG5cdFx0XHRcdH0gZWxzZSBpZiAoIG9iamVjdC5pc0JhdGNoZWRNZXNoICYmIG1hdGVyaWFsUHJvcGVydGllcy5iYXRjaGluZyA9PT0gZmFsc2UgKSB7XHJcblxyXG5cdFx0XHRcdFx0bmVlZHNQcm9ncmFtQ2hhbmdlID0gdHJ1ZTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIGlmICggISBvYmplY3QuaXNCYXRjaGVkTWVzaCAmJiBtYXRlcmlhbFByb3BlcnRpZXMuYmF0Y2hpbmcgPT09IHRydWUgKSB7XHJcblxyXG5cdFx0XHRcdFx0bmVlZHNQcm9ncmFtQ2hhbmdlID0gdHJ1ZTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIGlmICggb2JqZWN0LmlzSW5zdGFuY2VkTWVzaCAmJiBtYXRlcmlhbFByb3BlcnRpZXMuaW5zdGFuY2luZyA9PT0gZmFsc2UgKSB7XHJcblxyXG5cdFx0XHRcdFx0bmVlZHNQcm9ncmFtQ2hhbmdlID0gdHJ1ZTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIGlmICggISBvYmplY3QuaXNJbnN0YW5jZWRNZXNoICYmIG1hdGVyaWFsUHJvcGVydGllcy5pbnN0YW5jaW5nID09PSB0cnVlICkge1xyXG5cclxuXHRcdFx0XHRcdG5lZWRzUHJvZ3JhbUNoYW5nZSA9IHRydWU7XHJcblxyXG5cdFx0XHRcdH0gZWxzZSBpZiAoIG9iamVjdC5pc1NraW5uZWRNZXNoICYmIG1hdGVyaWFsUHJvcGVydGllcy5za2lubmluZyA9PT0gZmFsc2UgKSB7XHJcblxyXG5cdFx0XHRcdFx0bmVlZHNQcm9ncmFtQ2hhbmdlID0gdHJ1ZTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIGlmICggISBvYmplY3QuaXNTa2lubmVkTWVzaCAmJiBtYXRlcmlhbFByb3BlcnRpZXMuc2tpbm5pbmcgPT09IHRydWUgKSB7XHJcblxyXG5cdFx0XHRcdFx0bmVlZHNQcm9ncmFtQ2hhbmdlID0gdHJ1ZTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIGlmICggb2JqZWN0LmlzSW5zdGFuY2VkTWVzaCAmJiBtYXRlcmlhbFByb3BlcnRpZXMuaW5zdGFuY2luZ0NvbG9yID09PSB0cnVlICYmIG9iamVjdC5pbnN0YW5jZUNvbG9yID09PSBudWxsICkge1xyXG5cclxuXHRcdFx0XHRcdG5lZWRzUHJvZ3JhbUNoYW5nZSA9IHRydWU7XHJcblxyXG5cdFx0XHRcdH0gZWxzZSBpZiAoIG9iamVjdC5pc0luc3RhbmNlZE1lc2ggJiYgbWF0ZXJpYWxQcm9wZXJ0aWVzLmluc3RhbmNpbmdDb2xvciA9PT0gZmFsc2UgJiYgb2JqZWN0Lmluc3RhbmNlQ29sb3IgIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdFx0bmVlZHNQcm9ncmFtQ2hhbmdlID0gdHJ1ZTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIGlmICggbWF0ZXJpYWxQcm9wZXJ0aWVzLmVudk1hcCAhPT0gZW52TWFwICkge1xyXG5cclxuXHRcdFx0XHRcdG5lZWRzUHJvZ3JhbUNoYW5nZSA9IHRydWU7XHJcblxyXG5cdFx0XHRcdH0gZWxzZSBpZiAoIG1hdGVyaWFsLmZvZyA9PT0gdHJ1ZSAmJiBtYXRlcmlhbFByb3BlcnRpZXMuZm9nICE9PSBmb2cgKSB7XHJcblxyXG5cdFx0XHRcdFx0bmVlZHNQcm9ncmFtQ2hhbmdlID0gdHJ1ZTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIGlmICggbWF0ZXJpYWxQcm9wZXJ0aWVzLm51bUNsaXBwaW5nUGxhbmVzICE9PSB1bmRlZmluZWQgJiZcclxuXHRcdFx0XHRcdCggbWF0ZXJpYWxQcm9wZXJ0aWVzLm51bUNsaXBwaW5nUGxhbmVzICE9PSBjbGlwcGluZy5udW1QbGFuZXMgfHxcclxuXHRcdFx0XHRcdG1hdGVyaWFsUHJvcGVydGllcy5udW1JbnRlcnNlY3Rpb24gIT09IGNsaXBwaW5nLm51bUludGVyc2VjdGlvbiApICkge1xyXG5cclxuXHRcdFx0XHRcdG5lZWRzUHJvZ3JhbUNoYW5nZSA9IHRydWU7XHJcblxyXG5cdFx0XHRcdH0gZWxzZSBpZiAoIG1hdGVyaWFsUHJvcGVydGllcy52ZXJ0ZXhBbHBoYXMgIT09IHZlcnRleEFscGhhcyApIHtcclxuXHJcblx0XHRcdFx0XHRuZWVkc1Byb2dyYW1DaGFuZ2UgPSB0cnVlO1xyXG5cclxuXHRcdFx0XHR9IGVsc2UgaWYgKCBtYXRlcmlhbFByb3BlcnRpZXMudmVydGV4VGFuZ2VudHMgIT09IHZlcnRleFRhbmdlbnRzICkge1xyXG5cclxuXHRcdFx0XHRcdG5lZWRzUHJvZ3JhbUNoYW5nZSA9IHRydWU7XHJcblxyXG5cdFx0XHRcdH0gZWxzZSBpZiAoIG1hdGVyaWFsUHJvcGVydGllcy5tb3JwaFRhcmdldHMgIT09IG1vcnBoVGFyZ2V0cyApIHtcclxuXHJcblx0XHRcdFx0XHRuZWVkc1Byb2dyYW1DaGFuZ2UgPSB0cnVlO1xyXG5cclxuXHRcdFx0XHR9IGVsc2UgaWYgKCBtYXRlcmlhbFByb3BlcnRpZXMubW9ycGhOb3JtYWxzICE9PSBtb3JwaE5vcm1hbHMgKSB7XHJcblxyXG5cdFx0XHRcdFx0bmVlZHNQcm9ncmFtQ2hhbmdlID0gdHJ1ZTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIGlmICggbWF0ZXJpYWxQcm9wZXJ0aWVzLm1vcnBoQ29sb3JzICE9PSBtb3JwaENvbG9ycyApIHtcclxuXHJcblx0XHRcdFx0XHRuZWVkc1Byb2dyYW1DaGFuZ2UgPSB0cnVlO1xyXG5cclxuXHRcdFx0XHR9IGVsc2UgaWYgKCBtYXRlcmlhbFByb3BlcnRpZXMudG9uZU1hcHBpbmcgIT09IHRvbmVNYXBwaW5nICkge1xyXG5cclxuXHRcdFx0XHRcdG5lZWRzUHJvZ3JhbUNoYW5nZSA9IHRydWU7XHJcblxyXG5cdFx0XHRcdH0gZWxzZSBpZiAoIGNhcGFiaWxpdGllcy5pc1dlYkdMMiA9PT0gdHJ1ZSAmJiBtYXRlcmlhbFByb3BlcnRpZXMubW9ycGhUYXJnZXRzQ291bnQgIT09IG1vcnBoVGFyZ2V0c0NvdW50ICkge1xyXG5cclxuXHRcdFx0XHRcdG5lZWRzUHJvZ3JhbUNoYW5nZSA9IHRydWU7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdG5lZWRzUHJvZ3JhbUNoYW5nZSA9IHRydWU7XHJcblx0XHRcdFx0bWF0ZXJpYWxQcm9wZXJ0aWVzLl9fdmVyc2lvbiA9IG1hdGVyaWFsLnZlcnNpb247XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvL1xyXG5cclxuXHRcdFx0bGV0IHByb2dyYW0gPSBtYXRlcmlhbFByb3BlcnRpZXMuY3VycmVudFByb2dyYW07XHJcblxyXG5cdFx0XHRpZiAoIG5lZWRzUHJvZ3JhbUNoYW5nZSA9PT0gdHJ1ZSApIHtcclxuXHJcblx0XHRcdFx0cHJvZ3JhbSA9IGdldFByb2dyYW0oIG1hdGVyaWFsLCBzY2VuZSwgb2JqZWN0ICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRsZXQgcmVmcmVzaFByb2dyYW0gPSBmYWxzZTtcclxuXHRcdFx0bGV0IHJlZnJlc2hNYXRlcmlhbCA9IGZhbHNlO1xyXG5cdFx0XHRsZXQgcmVmcmVzaExpZ2h0cyA9IGZhbHNlO1xyXG5cclxuXHRcdFx0Y29uc3QgcF91bmlmb3JtcyA9IHByb2dyYW0uZ2V0VW5pZm9ybXMoKSxcclxuXHRcdFx0XHRtX3VuaWZvcm1zID0gbWF0ZXJpYWxQcm9wZXJ0aWVzLnVuaWZvcm1zO1xyXG5cclxuXHRcdFx0aWYgKCBzdGF0ZS51c2VQcm9ncmFtKCBwcm9ncmFtLnByb2dyYW0gKSApIHtcclxuXHJcblx0XHRcdFx0cmVmcmVzaFByb2dyYW0gPSB0cnVlO1xyXG5cdFx0XHRcdHJlZnJlc2hNYXRlcmlhbCA9IHRydWU7XHJcblx0XHRcdFx0cmVmcmVzaExpZ2h0cyA9IHRydWU7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRpZiAoIG1hdGVyaWFsLmlkICE9PSBfY3VycmVudE1hdGVyaWFsSWQgKSB7XHJcblxyXG5cdFx0XHRcdF9jdXJyZW50TWF0ZXJpYWxJZCA9IG1hdGVyaWFsLmlkO1xyXG5cclxuXHRcdFx0XHRyZWZyZXNoTWF0ZXJpYWwgPSB0cnVlO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0aWYgKCByZWZyZXNoUHJvZ3JhbSB8fCBfY3VycmVudENhbWVyYSAhPT0gY2FtZXJhICkge1xyXG5cclxuXHRcdFx0XHQvLyBjb21tb24gY2FtZXJhIHVuaWZvcm1zXHJcblxyXG5cdFx0XHRcdHBfdW5pZm9ybXMuc2V0VmFsdWUoIF9nbCwgJ3Byb2plY3Rpb25NYXRyaXgnLCBjYW1lcmEucHJvamVjdGlvbk1hdHJpeCApO1xyXG5cdFx0XHRcdHBfdW5pZm9ybXMuc2V0VmFsdWUoIF9nbCwgJ3ZpZXdNYXRyaXgnLCBjYW1lcmEubWF0cml4V29ybGRJbnZlcnNlICk7XHJcblxyXG5cdFx0XHRcdGNvbnN0IHVDYW1Qb3MgPSBwX3VuaWZvcm1zLm1hcC5jYW1lcmFQb3NpdGlvbjtcclxuXHJcblx0XHRcdFx0aWYgKCB1Q2FtUG9zICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRcdFx0dUNhbVBvcy5zZXRWYWx1ZSggX2dsLCBfdmVjdG9yMy5zZXRGcm9tTWF0cml4UG9zaXRpb24oIGNhbWVyYS5tYXRyaXhXb3JsZCApICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0aWYgKCBjYXBhYmlsaXRpZXMubG9nYXJpdGhtaWNEZXB0aEJ1ZmZlciApIHtcclxuXHJcblx0XHRcdFx0XHRwX3VuaWZvcm1zLnNldFZhbHVlKCBfZ2wsICdsb2dEZXB0aEJ1ZkZDJyxcclxuXHRcdFx0XHRcdFx0Mi4wIC8gKCBNYXRoLmxvZyggY2FtZXJhLmZhciArIDEuMCApIC8gTWF0aC5MTjIgKSApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdC8vIGNvbnNpZGVyIG1vdmluZyBpc09ydGhvZ3JhcGhpYyB0byBVbmlmb3JtTGliIGFuZCBXZWJHTE1hdGVyaWFscywgc2VlIGh0dHBzOi8vZ2l0aHViLmNvbS9tcmRvb2IvdGhyZWUuanMvcHVsbC8yNjQ2NyNpc3N1ZWNvbW1lbnQtMTY0NTE4NTA2N1xyXG5cclxuXHRcdFx0XHRpZiAoIG1hdGVyaWFsLmlzTWVzaFBob25nTWF0ZXJpYWwgfHxcclxuXHRcdFx0XHRcdG1hdGVyaWFsLmlzTWVzaFRvb25NYXRlcmlhbCB8fFxyXG5cdFx0XHRcdFx0bWF0ZXJpYWwuaXNNZXNoTGFtYmVydE1hdGVyaWFsIHx8XHJcblx0XHRcdFx0XHRtYXRlcmlhbC5pc01lc2hCYXNpY01hdGVyaWFsIHx8XHJcblx0XHRcdFx0XHRtYXRlcmlhbC5pc01lc2hTdGFuZGFyZE1hdGVyaWFsIHx8XHJcblx0XHRcdFx0XHRtYXRlcmlhbC5pc1NoYWRlck1hdGVyaWFsICkge1xyXG5cclxuXHRcdFx0XHRcdHBfdW5pZm9ybXMuc2V0VmFsdWUoIF9nbCwgJ2lzT3J0aG9ncmFwaGljJywgY2FtZXJhLmlzT3J0aG9ncmFwaGljQ2FtZXJhID09PSB0cnVlICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0aWYgKCBfY3VycmVudENhbWVyYSAhPT0gY2FtZXJhICkge1xyXG5cclxuXHRcdFx0XHRcdF9jdXJyZW50Q2FtZXJhID0gY2FtZXJhO1xyXG5cclxuXHRcdFx0XHRcdC8vIGxpZ2h0aW5nIHVuaWZvcm1zIGRlcGVuZCBvbiB0aGUgY2FtZXJhIHNvIGVuZm9yY2UgYW4gdXBkYXRlXHJcblx0XHRcdFx0XHQvLyBub3csIGluIGNhc2UgdGhpcyBtYXRlcmlhbCBzdXBwb3J0cyBsaWdodHMgLSBvciBsYXRlciwgd2hlblxyXG5cdFx0XHRcdFx0Ly8gdGhlIG5leHQgbWF0ZXJpYWwgdGhhdCBkb2VzIGdldHMgYWN0aXZhdGVkOlxyXG5cclxuXHRcdFx0XHRcdHJlZnJlc2hNYXRlcmlhbCA9IHRydWU7XHRcdC8vIHNldCB0byB0cnVlIG9uIG1hdGVyaWFsIGNoYW5nZVxyXG5cdFx0XHRcdFx0cmVmcmVzaExpZ2h0cyA9IHRydWU7XHRcdC8vIHJlbWFpbnMgc2V0IHVudGlsIHVwZGF0ZSBkb25lXHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdC8vIHNraW5uaW5nIGFuZCBtb3JwaCB0YXJnZXQgdW5pZm9ybXMgbXVzdCBiZSBzZXQgZXZlbiBpZiBtYXRlcmlhbCBkaWRuJ3QgY2hhbmdlXHJcblx0XHRcdC8vIGF1dG8tc2V0dGluZyBvZiB0ZXh0dXJlIHVuaXQgZm9yIGJvbmUgYW5kIG1vcnBoIHRleHR1cmUgbXVzdCBnbyBiZWZvcmUgb3RoZXIgdGV4dHVyZXNcclxuXHRcdFx0Ly8gb3RoZXJ3aXNlIHRleHR1cmVzIHVzZWQgZm9yIHNraW5uaW5nIGFuZCBtb3JwaGluZyBjYW4gdGFrZSBvdmVyIHRleHR1cmUgdW5pdHMgcmVzZXJ2ZWQgZm9yIG90aGVyIG1hdGVyaWFsIHRleHR1cmVzXHJcblxyXG5cdFx0XHRpZiAoIG9iamVjdC5pc1NraW5uZWRNZXNoICkge1xyXG5cclxuXHRcdFx0XHRwX3VuaWZvcm1zLnNldE9wdGlvbmFsKCBfZ2wsIG9iamVjdCwgJ2JpbmRNYXRyaXgnICk7XHJcblx0XHRcdFx0cF91bmlmb3Jtcy5zZXRPcHRpb25hbCggX2dsLCBvYmplY3QsICdiaW5kTWF0cml4SW52ZXJzZScgKTtcclxuXHJcblx0XHRcdFx0Y29uc3Qgc2tlbGV0b24gPSBvYmplY3Quc2tlbGV0b247XHJcblxyXG5cdFx0XHRcdGlmICggc2tlbGV0b24gKSB7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCBjYXBhYmlsaXRpZXMuZmxvYXRWZXJ0ZXhUZXh0dXJlcyApIHtcclxuXHJcblx0XHRcdFx0XHRcdGlmICggc2tlbGV0b24uYm9uZVRleHR1cmUgPT09IG51bGwgKSBza2VsZXRvbi5jb21wdXRlQm9uZVRleHR1cmUoKTtcclxuXHJcblx0XHRcdFx0XHRcdHBfdW5pZm9ybXMuc2V0VmFsdWUoIF9nbCwgJ2JvbmVUZXh0dXJlJywgc2tlbGV0b24uYm9uZVRleHR1cmUsIHRleHR1cmVzICk7XHJcblxyXG5cdFx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLldlYkdMUmVuZGVyZXI6IFNraW5uZWRNZXNoIGNhbiBvbmx5IGJlIHVzZWQgd2l0aCBXZWJHTCAyLiBXaXRoIFdlYkdMIDEgT0VTX3RleHR1cmVfZmxvYXQgYW5kIHZlcnRleCB0ZXh0dXJlcyBzdXBwb3J0IGlzIHJlcXVpcmVkLicgKTtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGlmICggb2JqZWN0LmlzQmF0Y2hlZE1lc2ggKSB7XHJcblxyXG5cdFx0XHRcdHBfdW5pZm9ybXMuc2V0T3B0aW9uYWwoIF9nbCwgb2JqZWN0LCAnYmF0Y2hpbmdUZXh0dXJlJyApO1xyXG5cdFx0XHRcdHBfdW5pZm9ybXMuc2V0VmFsdWUoIF9nbCwgJ2JhdGNoaW5nVGV4dHVyZScsIG9iamVjdC5fbWF0cmljZXNUZXh0dXJlLCB0ZXh0dXJlcyApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Y29uc3QgbW9ycGhBdHRyaWJ1dGVzID0gZ2VvbWV0cnkubW9ycGhBdHRyaWJ1dGVzO1xyXG5cclxuXHRcdFx0aWYgKCBtb3JwaEF0dHJpYnV0ZXMucG9zaXRpb24gIT09IHVuZGVmaW5lZCB8fCBtb3JwaEF0dHJpYnV0ZXMubm9ybWFsICE9PSB1bmRlZmluZWQgfHwgKCBtb3JwaEF0dHJpYnV0ZXMuY29sb3IgIT09IHVuZGVmaW5lZCAmJiBjYXBhYmlsaXRpZXMuaXNXZWJHTDIgPT09IHRydWUgKSApIHtcclxuXHJcblx0XHRcdFx0bW9ycGh0YXJnZXRzLnVwZGF0ZSggb2JqZWN0LCBnZW9tZXRyeSwgcHJvZ3JhbSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0aWYgKCByZWZyZXNoTWF0ZXJpYWwgfHwgbWF0ZXJpYWxQcm9wZXJ0aWVzLnJlY2VpdmVTaGFkb3cgIT09IG9iamVjdC5yZWNlaXZlU2hhZG93ICkge1xyXG5cclxuXHRcdFx0XHRtYXRlcmlhbFByb3BlcnRpZXMucmVjZWl2ZVNoYWRvdyA9IG9iamVjdC5yZWNlaXZlU2hhZG93O1xyXG5cdFx0XHRcdHBfdW5pZm9ybXMuc2V0VmFsdWUoIF9nbCwgJ3JlY2VpdmVTaGFkb3cnLCBvYmplY3QucmVjZWl2ZVNoYWRvdyApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Ly8gaHR0cHM6Ly9naXRodWIuY29tL21yZG9vYi90aHJlZS5qcy9wdWxsLzI0NDY3I2lzc3VlY29tbWVudC0xMjA5MDMxNTEyXHJcblxyXG5cdFx0XHRpZiAoIG1hdGVyaWFsLmlzTWVzaEdvdXJhdWRNYXRlcmlhbCAmJiBtYXRlcmlhbC5lbnZNYXAgIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdG1fdW5pZm9ybXMuZW52TWFwLnZhbHVlID0gZW52TWFwO1xyXG5cclxuXHRcdFx0XHRtX3VuaWZvcm1zLmZsaXBFbnZNYXAudmFsdWUgPSAoIGVudk1hcC5pc0N1YmVUZXh0dXJlICYmIGVudk1hcC5pc1JlbmRlclRhcmdldFRleHR1cmUgPT09IGZhbHNlICkgPyAtIDEgOiAxO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0aWYgKCByZWZyZXNoTWF0ZXJpYWwgKSB7XHJcblxyXG5cdFx0XHRcdHBfdW5pZm9ybXMuc2V0VmFsdWUoIF9nbCwgJ3RvbmVNYXBwaW5nRXhwb3N1cmUnLCBfdGhpcy50b25lTWFwcGluZ0V4cG9zdXJlICk7XHJcblxyXG5cdFx0XHRcdGlmICggbWF0ZXJpYWxQcm9wZXJ0aWVzLm5lZWRzTGlnaHRzICkge1xyXG5cclxuXHRcdFx0XHRcdC8vIHRoZSBjdXJyZW50IG1hdGVyaWFsIHJlcXVpcmVzIGxpZ2h0aW5nIGluZm9cclxuXHJcblx0XHRcdFx0XHQvLyBub3RlOiBhbGwgbGlnaHRpbmcgdW5pZm9ybXMgYXJlIGFsd2F5cyBzZXQgY29ycmVjdGx5XHJcblx0XHRcdFx0XHQvLyB0aGV5IHNpbXBseSByZWZlcmVuY2UgdGhlIHJlbmRlcmVyJ3Mgc3RhdGUgZm9yIHRoZWlyXHJcblx0XHRcdFx0XHQvLyB2YWx1ZXNcclxuXHRcdFx0XHRcdC8vXHJcblx0XHRcdFx0XHQvLyB1c2UgdGhlIGN1cnJlbnQgbWF0ZXJpYWwncyAubmVlZHNVcGRhdGUgZmxhZ3MgdG8gc2V0XHJcblx0XHRcdFx0XHQvLyB0aGUgR0wgc3RhdGUgd2hlbiByZXF1aXJlZFxyXG5cclxuXHRcdFx0XHRcdG1hcmtVbmlmb3Jtc0xpZ2h0c05lZWRzVXBkYXRlKCBtX3VuaWZvcm1zLCByZWZyZXNoTGlnaHRzICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0Ly8gcmVmcmVzaCB1bmlmb3JtcyBjb21tb24gdG8gc2V2ZXJhbCBtYXRlcmlhbHNcclxuXHJcblx0XHRcdFx0aWYgKCBmb2cgJiYgbWF0ZXJpYWwuZm9nID09PSB0cnVlICkge1xyXG5cclxuXHRcdFx0XHRcdG1hdGVyaWFscy5yZWZyZXNoRm9nVW5pZm9ybXMoIG1fdW5pZm9ybXMsIGZvZyApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdG1hdGVyaWFscy5yZWZyZXNoTWF0ZXJpYWxVbmlmb3JtcyggbV91bmlmb3JtcywgbWF0ZXJpYWwsIF9waXhlbFJhdGlvLCBfaGVpZ2h0LCBfdHJhbnNtaXNzaW9uUmVuZGVyVGFyZ2V0ICk7XHJcblxyXG5cdFx0XHRcdFdlYkdMVW5pZm9ybXMudXBsb2FkKCBfZ2wsIGdldFVuaWZvcm1MaXN0KCBtYXRlcmlhbFByb3BlcnRpZXMgKSwgbV91bmlmb3JtcywgdGV4dHVyZXMgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGlmICggbWF0ZXJpYWwuaXNTaGFkZXJNYXRlcmlhbCAmJiBtYXRlcmlhbC51bmlmb3Jtc05lZWRVcGRhdGUgPT09IHRydWUgKSB7XHJcblxyXG5cdFx0XHRcdFdlYkdMVW5pZm9ybXMudXBsb2FkKCBfZ2wsIGdldFVuaWZvcm1MaXN0KCBtYXRlcmlhbFByb3BlcnRpZXMgKSwgbV91bmlmb3JtcywgdGV4dHVyZXMgKTtcclxuXHRcdFx0XHRtYXRlcmlhbC51bmlmb3Jtc05lZWRVcGRhdGUgPSBmYWxzZTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGlmICggbWF0ZXJpYWwuaXNTcHJpdGVNYXRlcmlhbCApIHtcclxuXHJcblx0XHRcdFx0cF91bmlmb3Jtcy5zZXRWYWx1ZSggX2dsLCAnY2VudGVyJywgb2JqZWN0LmNlbnRlciApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Ly8gY29tbW9uIG1hdHJpY2VzXHJcblxyXG5cdFx0XHRwX3VuaWZvcm1zLnNldFZhbHVlKCBfZ2wsICdtb2RlbFZpZXdNYXRyaXgnLCBvYmplY3QubW9kZWxWaWV3TWF0cml4ICk7XHJcblx0XHRcdHBfdW5pZm9ybXMuc2V0VmFsdWUoIF9nbCwgJ25vcm1hbE1hdHJpeCcsIG9iamVjdC5ub3JtYWxNYXRyaXggKTtcclxuXHRcdFx0cF91bmlmb3Jtcy5zZXRWYWx1ZSggX2dsLCAnbW9kZWxNYXRyaXgnLCBvYmplY3QubWF0cml4V29ybGQgKTtcclxuXHJcblx0XHRcdC8vIFVCT3NcclxuXHJcblx0XHRcdGlmICggbWF0ZXJpYWwuaXNTaGFkZXJNYXRlcmlhbCB8fCBtYXRlcmlhbC5pc1Jhd1NoYWRlck1hdGVyaWFsICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBncm91cHMgPSBtYXRlcmlhbC51bmlmb3Jtc0dyb3VwcztcclxuXHJcblx0XHRcdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gZ3JvdXBzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCBjYXBhYmlsaXRpZXMuaXNXZWJHTDIgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRjb25zdCBncm91cCA9IGdyb3Vwc1sgaSBdO1xyXG5cclxuXHRcdFx0XHRcdFx0dW5pZm9ybXNHcm91cHMudXBkYXRlKCBncm91cCwgcHJvZ3JhbSApO1xyXG5cdFx0XHRcdFx0XHR1bmlmb3Jtc0dyb3Vwcy5iaW5kKCBncm91cCwgcHJvZ3JhbSApO1xyXG5cclxuXHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5XZWJHTFJlbmRlcmVyOiBVbmlmb3JtIEJ1ZmZlciBPYmplY3RzIGNhbiBvbmx5IGJlIHVzZWQgd2l0aCBXZWJHTCAyLicgKTtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHJldHVybiBwcm9ncmFtO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvLyBJZiB1bmlmb3JtcyBhcmUgbWFya2VkIGFzIGNsZWFuLCB0aGV5IGRvbid0IG5lZWQgdG8gYmUgbG9hZGVkIHRvIHRoZSBHUFUuXHJcblxyXG5cdFx0ZnVuY3Rpb24gbWFya1VuaWZvcm1zTGlnaHRzTmVlZHNVcGRhdGUoIHVuaWZvcm1zLCB2YWx1ZSApIHtcclxuXHJcblx0XHRcdHVuaWZvcm1zLmFtYmllbnRMaWdodENvbG9yLm5lZWRzVXBkYXRlID0gdmFsdWU7XHJcblx0XHRcdHVuaWZvcm1zLmxpZ2h0UHJvYmUubmVlZHNVcGRhdGUgPSB2YWx1ZTtcclxuXHJcblx0XHRcdHVuaWZvcm1zLmRpcmVjdGlvbmFsTGlnaHRzLm5lZWRzVXBkYXRlID0gdmFsdWU7XHJcblx0XHRcdHVuaWZvcm1zLmRpcmVjdGlvbmFsTGlnaHRTaGFkb3dzLm5lZWRzVXBkYXRlID0gdmFsdWU7XHJcblx0XHRcdHVuaWZvcm1zLnBvaW50TGlnaHRzLm5lZWRzVXBkYXRlID0gdmFsdWU7XHJcblx0XHRcdHVuaWZvcm1zLnBvaW50TGlnaHRTaGFkb3dzLm5lZWRzVXBkYXRlID0gdmFsdWU7XHJcblx0XHRcdHVuaWZvcm1zLnNwb3RMaWdodHMubmVlZHNVcGRhdGUgPSB2YWx1ZTtcclxuXHRcdFx0dW5pZm9ybXMuc3BvdExpZ2h0U2hhZG93cy5uZWVkc1VwZGF0ZSA9IHZhbHVlO1xyXG5cdFx0XHR1bmlmb3Jtcy5yZWN0QXJlYUxpZ2h0cy5uZWVkc1VwZGF0ZSA9IHZhbHVlO1xyXG5cdFx0XHR1bmlmb3Jtcy5oZW1pc3BoZXJlTGlnaHRzLm5lZWRzVXBkYXRlID0gdmFsdWU7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGZ1bmN0aW9uIG1hdGVyaWFsTmVlZHNMaWdodHMoIG1hdGVyaWFsICkge1xyXG5cclxuXHRcdFx0cmV0dXJuIG1hdGVyaWFsLmlzTWVzaExhbWJlcnRNYXRlcmlhbCB8fCBtYXRlcmlhbC5pc01lc2hUb29uTWF0ZXJpYWwgfHwgbWF0ZXJpYWwuaXNNZXNoUGhvbmdNYXRlcmlhbCB8fFxyXG5cdFx0XHRcdG1hdGVyaWFsLmlzTWVzaFN0YW5kYXJkTWF0ZXJpYWwgfHwgbWF0ZXJpYWwuaXNTaGFkb3dNYXRlcmlhbCB8fFxyXG5cdFx0XHRcdCggbWF0ZXJpYWwuaXNTaGFkZXJNYXRlcmlhbCAmJiBtYXRlcmlhbC5saWdodHMgPT09IHRydWUgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5nZXRBY3RpdmVDdWJlRmFjZSA9IGZ1bmN0aW9uICgpIHtcclxuXHJcblx0XHRcdHJldHVybiBfY3VycmVudEFjdGl2ZUN1YmVGYWNlO1xyXG5cclxuXHRcdH07XHJcblxyXG5cdFx0dGhpcy5nZXRBY3RpdmVNaXBtYXBMZXZlbCA9IGZ1bmN0aW9uICgpIHtcclxuXHJcblx0XHRcdHJldHVybiBfY3VycmVudEFjdGl2ZU1pcG1hcExldmVsO1xyXG5cclxuXHRcdH07XHJcblxyXG5cdFx0dGhpcy5nZXRSZW5kZXJUYXJnZXQgPSBmdW5jdGlvbiAoKSB7XHJcblxyXG5cdFx0XHRyZXR1cm4gX2N1cnJlbnRSZW5kZXJUYXJnZXQ7XHJcblxyXG5cdFx0fTtcclxuXHJcblx0XHR0aGlzLnNldFJlbmRlclRhcmdldFRleHR1cmVzID0gZnVuY3Rpb24gKCByZW5kZXJUYXJnZXQsIGNvbG9yVGV4dHVyZSwgZGVwdGhUZXh0dXJlICkge1xyXG5cclxuXHRcdFx0cHJvcGVydGllcy5nZXQoIHJlbmRlclRhcmdldC50ZXh0dXJlICkuX193ZWJnbFRleHR1cmUgPSBjb2xvclRleHR1cmU7XHJcblx0XHRcdHByb3BlcnRpZXMuZ2V0KCByZW5kZXJUYXJnZXQuZGVwdGhUZXh0dXJlICkuX193ZWJnbFRleHR1cmUgPSBkZXB0aFRleHR1cmU7XHJcblxyXG5cdFx0XHRjb25zdCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzID0gcHJvcGVydGllcy5nZXQoIHJlbmRlclRhcmdldCApO1xyXG5cdFx0XHRyZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9faGFzRXh0ZXJuYWxUZXh0dXJlcyA9IHRydWU7XHJcblxyXG5cdFx0XHRpZiAoIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX19oYXNFeHRlcm5hbFRleHR1cmVzICkge1xyXG5cclxuXHRcdFx0XHRyZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fYXV0b0FsbG9jYXRlRGVwdGhCdWZmZXIgPSBkZXB0aFRleHR1cmUgPT09IHVuZGVmaW5lZDtcclxuXHJcblx0XHRcdFx0aWYgKCAhIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX19hdXRvQWxsb2NhdGVEZXB0aEJ1ZmZlciApIHtcclxuXHJcblx0XHRcdFx0XHQvLyBUaGUgbXVsdGlzYW1wbGVfcmVuZGVyX3RvX3RleHR1cmUgZXh0ZW5zaW9uIGRvZXNuJ3Qgd29yayBwcm9wZXJseSBpZiB0aGVyZVxyXG5cdFx0XHRcdFx0Ly8gYXJlIG1pZGZyYW1lIGZsdXNoZXMgYW5kIGFuIGV4dGVybmFsIGRlcHRoIGJ1ZmZlci4gRGlzYWJsZSB1c2Ugb2YgdGhlIGV4dGVuc2lvbi5cclxuXHRcdFx0XHRcdGlmICggZXh0ZW5zaW9ucy5oYXMoICdXRUJHTF9tdWx0aXNhbXBsZWRfcmVuZGVyX3RvX3RleHR1cmUnICkgPT09IHRydWUgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5XZWJHTFJlbmRlcmVyOiBSZW5kZXItdG8tdGV4dHVyZSBleHRlbnNpb24gd2FzIGRpc2FibGVkIGJlY2F1c2UgYW4gZXh0ZXJuYWwgdGV4dHVyZSB3YXMgcHJvdmlkZWQnICk7XHJcblx0XHRcdFx0XHRcdHJlbmRlclRhcmdldFByb3BlcnRpZXMuX191c2VSZW5kZXJUb1RleHR1cmUgPSBmYWxzZTtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9O1xyXG5cclxuXHRcdHRoaXMuc2V0UmVuZGVyVGFyZ2V0RnJhbWVidWZmZXIgPSBmdW5jdGlvbiAoIHJlbmRlclRhcmdldCwgZGVmYXVsdEZyYW1lYnVmZmVyICkge1xyXG5cclxuXHRcdFx0Y29uc3QgcmVuZGVyVGFyZ2V0UHJvcGVydGllcyA9IHByb3BlcnRpZXMuZ2V0KCByZW5kZXJUYXJnZXQgKTtcclxuXHRcdFx0cmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX3dlYmdsRnJhbWVidWZmZXIgPSBkZWZhdWx0RnJhbWVidWZmZXI7XHJcblx0XHRcdHJlbmRlclRhcmdldFByb3BlcnRpZXMuX191c2VEZWZhdWx0RnJhbWVidWZmZXIgPSBkZWZhdWx0RnJhbWVidWZmZXIgPT09IHVuZGVmaW5lZDtcclxuXHJcblx0XHR9O1xyXG5cclxuXHRcdHRoaXMuc2V0UmVuZGVyVGFyZ2V0ID0gZnVuY3Rpb24gKCByZW5kZXJUYXJnZXQsIGFjdGl2ZUN1YmVGYWNlID0gMCwgYWN0aXZlTWlwbWFwTGV2ZWwgPSAwICkge1xyXG5cclxuXHRcdFx0X2N1cnJlbnRSZW5kZXJUYXJnZXQgPSByZW5kZXJUYXJnZXQ7XHJcblx0XHRcdF9jdXJyZW50QWN0aXZlQ3ViZUZhY2UgPSBhY3RpdmVDdWJlRmFjZTtcclxuXHRcdFx0X2N1cnJlbnRBY3RpdmVNaXBtYXBMZXZlbCA9IGFjdGl2ZU1pcG1hcExldmVsO1xyXG5cclxuXHRcdFx0bGV0IHVzZURlZmF1bHRGcmFtZWJ1ZmZlciA9IHRydWU7XHJcblx0XHRcdGxldCBmcmFtZWJ1ZmZlciA9IG51bGw7XHJcblx0XHRcdGxldCBpc0N1YmUgPSBmYWxzZTtcclxuXHRcdFx0bGV0IGlzUmVuZGVyVGFyZ2V0M0QgPSBmYWxzZTtcclxuXHJcblx0XHRcdGlmICggcmVuZGVyVGFyZ2V0ICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzID0gcHJvcGVydGllcy5nZXQoIHJlbmRlclRhcmdldCApO1xyXG5cclxuXHRcdFx0XHRpZiAoIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX191c2VEZWZhdWx0RnJhbWVidWZmZXIgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0XHQvLyBXZSBuZWVkIHRvIG1ha2Ugc3VyZSB0byByZWJpbmQgdGhlIGZyYW1lYnVmZmVyLlxyXG5cdFx0XHRcdFx0c3RhdGUuYmluZEZyYW1lYnVmZmVyKCBfZ2wuRlJBTUVCVUZGRVIsIG51bGwgKTtcclxuXHRcdFx0XHRcdHVzZURlZmF1bHRGcmFtZWJ1ZmZlciA9IGZhbHNlO1xyXG5cclxuXHRcdFx0XHR9IGVsc2UgaWYgKCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xGcmFtZWJ1ZmZlciA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHRcdHRleHR1cmVzLnNldHVwUmVuZGVyVGFyZ2V0KCByZW5kZXJUYXJnZXQgKTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIGlmICggcmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX2hhc0V4dGVybmFsVGV4dHVyZXMgKSB7XHJcblxyXG5cdFx0XHRcdFx0Ly8gQ29sb3IgYW5kIGRlcHRoIHRleHR1cmUgbXVzdCBiZSByZWJvdW5kIGluIG9yZGVyIGZvciB0aGUgc3dhcGNoYWluIHRvIHVwZGF0ZS5cclxuXHRcdFx0XHRcdHRleHR1cmVzLnJlYmluZFRleHR1cmVzKCByZW5kZXJUYXJnZXQsIHByb3BlcnRpZXMuZ2V0KCByZW5kZXJUYXJnZXQudGV4dHVyZSApLl9fd2ViZ2xUZXh0dXJlLCBwcm9wZXJ0aWVzLmdldCggcmVuZGVyVGFyZ2V0LmRlcHRoVGV4dHVyZSApLl9fd2ViZ2xUZXh0dXJlICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0Y29uc3QgdGV4dHVyZSA9IHJlbmRlclRhcmdldC50ZXh0dXJlO1xyXG5cclxuXHRcdFx0XHRpZiAoIHRleHR1cmUuaXNEYXRhM0RUZXh0dXJlIHx8IHRleHR1cmUuaXNEYXRhQXJyYXlUZXh0dXJlIHx8IHRleHR1cmUuaXNDb21wcmVzc2VkQXJyYXlUZXh0dXJlICkge1xyXG5cclxuXHRcdFx0XHRcdGlzUmVuZGVyVGFyZ2V0M0QgPSB0cnVlO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdGNvbnN0IF9fd2ViZ2xGcmFtZWJ1ZmZlciA9IHByb3BlcnRpZXMuZ2V0KCByZW5kZXJUYXJnZXQgKS5fX3dlYmdsRnJhbWVidWZmZXI7XHJcblxyXG5cdFx0XHRcdGlmICggcmVuZGVyVGFyZ2V0LmlzV2ViR0xDdWJlUmVuZGVyVGFyZ2V0ICkge1xyXG5cclxuXHRcdFx0XHRcdGlmICggQXJyYXkuaXNBcnJheSggX193ZWJnbEZyYW1lYnVmZmVyWyBhY3RpdmVDdWJlRmFjZSBdICkgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRmcmFtZWJ1ZmZlciA9IF9fd2ViZ2xGcmFtZWJ1ZmZlclsgYWN0aXZlQ3ViZUZhY2UgXVsgYWN0aXZlTWlwbWFwTGV2ZWwgXTtcclxuXHJcblx0XHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdFx0ZnJhbWVidWZmZXIgPSBfX3dlYmdsRnJhbWVidWZmZXJbIGFjdGl2ZUN1YmVGYWNlIF07XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdGlzQ3ViZSA9IHRydWU7XHJcblxyXG5cdFx0XHRcdH0gZWxzZSBpZiAoICggY2FwYWJpbGl0aWVzLmlzV2ViR0wyICYmIHJlbmRlclRhcmdldC5zYW1wbGVzID4gMCApICYmIHRleHR1cmVzLnVzZU11bHRpc2FtcGxlZFJUVCggcmVuZGVyVGFyZ2V0ICkgPT09IGZhbHNlICkge1xyXG5cclxuXHRcdFx0XHRcdGZyYW1lYnVmZmVyID0gcHJvcGVydGllcy5nZXQoIHJlbmRlclRhcmdldCApLl9fd2ViZ2xNdWx0aXNhbXBsZWRGcmFtZWJ1ZmZlcjtcclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRpZiAoIEFycmF5LmlzQXJyYXkoIF9fd2ViZ2xGcmFtZWJ1ZmZlciApICkge1xyXG5cclxuXHRcdFx0XHRcdFx0ZnJhbWVidWZmZXIgPSBfX3dlYmdsRnJhbWVidWZmZXJbIGFjdGl2ZU1pcG1hcExldmVsIF07XHJcblxyXG5cdFx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRcdGZyYW1lYnVmZmVyID0gX193ZWJnbEZyYW1lYnVmZmVyO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRfY3VycmVudFZpZXdwb3J0LmNvcHkoIHJlbmRlclRhcmdldC52aWV3cG9ydCApO1xyXG5cdFx0XHRcdF9jdXJyZW50U2Npc3Nvci5jb3B5KCByZW5kZXJUYXJnZXQuc2Npc3NvciApO1xyXG5cdFx0XHRcdF9jdXJyZW50U2Npc3NvclRlc3QgPSByZW5kZXJUYXJnZXQuc2Npc3NvclRlc3Q7XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRfY3VycmVudFZpZXdwb3J0LmNvcHkoIF92aWV3cG9ydCApLm11bHRpcGx5U2NhbGFyKCBfcGl4ZWxSYXRpbyApLmZsb29yKCk7XHJcblx0XHRcdFx0X2N1cnJlbnRTY2lzc29yLmNvcHkoIF9zY2lzc29yICkubXVsdGlwbHlTY2FsYXIoIF9waXhlbFJhdGlvICkuZmxvb3IoKTtcclxuXHRcdFx0XHRfY3VycmVudFNjaXNzb3JUZXN0ID0gX3NjaXNzb3JUZXN0O1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Y29uc3QgZnJhbWVidWZmZXJCb3VuZCA9IHN0YXRlLmJpbmRGcmFtZWJ1ZmZlciggX2dsLkZSQU1FQlVGRkVSLCBmcmFtZWJ1ZmZlciApO1xyXG5cclxuXHRcdFx0aWYgKCBmcmFtZWJ1ZmZlckJvdW5kICYmIGNhcGFiaWxpdGllcy5kcmF3QnVmZmVycyAmJiB1c2VEZWZhdWx0RnJhbWVidWZmZXIgKSB7XHJcblxyXG5cdFx0XHRcdHN0YXRlLmRyYXdCdWZmZXJzKCByZW5kZXJUYXJnZXQsIGZyYW1lYnVmZmVyICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRzdGF0ZS52aWV3cG9ydCggX2N1cnJlbnRWaWV3cG9ydCApO1xyXG5cdFx0XHRzdGF0ZS5zY2lzc29yKCBfY3VycmVudFNjaXNzb3IgKTtcclxuXHRcdFx0c3RhdGUuc2V0U2Npc3NvclRlc3QoIF9jdXJyZW50U2Npc3NvclRlc3QgKTtcclxuXHJcblx0XHRcdGlmICggaXNDdWJlICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCB0ZXh0dXJlUHJvcGVydGllcyA9IHByb3BlcnRpZXMuZ2V0KCByZW5kZXJUYXJnZXQudGV4dHVyZSApO1xyXG5cdFx0XHRcdF9nbC5mcmFtZWJ1ZmZlclRleHR1cmUyRCggX2dsLkZSQU1FQlVGRkVSLCBfZ2wuQ09MT1JfQVRUQUNITUVOVDAsIF9nbC5URVhUVVJFX0NVQkVfTUFQX1BPU0lUSVZFX1ggKyBhY3RpdmVDdWJlRmFjZSwgdGV4dHVyZVByb3BlcnRpZXMuX193ZWJnbFRleHR1cmUsIGFjdGl2ZU1pcG1hcExldmVsICk7XHJcblxyXG5cdFx0XHR9IGVsc2UgaWYgKCBpc1JlbmRlclRhcmdldDNEICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCB0ZXh0dXJlUHJvcGVydGllcyA9IHByb3BlcnRpZXMuZ2V0KCByZW5kZXJUYXJnZXQudGV4dHVyZSApO1xyXG5cdFx0XHRcdGNvbnN0IGxheWVyID0gYWN0aXZlQ3ViZUZhY2UgfHwgMDtcclxuXHRcdFx0XHRfZ2wuZnJhbWVidWZmZXJUZXh0dXJlTGF5ZXIoIF9nbC5GUkFNRUJVRkZFUiwgX2dsLkNPTE9SX0FUVEFDSE1FTlQwLCB0ZXh0dXJlUHJvcGVydGllcy5fX3dlYmdsVGV4dHVyZSwgYWN0aXZlTWlwbWFwTGV2ZWwgfHwgMCwgbGF5ZXIgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdF9jdXJyZW50TWF0ZXJpYWxJZCA9IC0gMTsgLy8gcmVzZXQgY3VycmVudCBtYXRlcmlhbCB0byBlbnN1cmUgY29ycmVjdCB1bmlmb3JtIGJpbmRpbmdzXHJcblxyXG5cdFx0fTtcclxuXHJcblx0XHR0aGlzLnJlYWRSZW5kZXJUYXJnZXRQaXhlbHMgPSBmdW5jdGlvbiAoIHJlbmRlclRhcmdldCwgeCwgeSwgd2lkdGgsIGhlaWdodCwgYnVmZmVyLCBhY3RpdmVDdWJlRmFjZUluZGV4ICkge1xyXG5cclxuXHRcdFx0aWYgKCAhICggcmVuZGVyVGFyZ2V0ICYmIHJlbmRlclRhcmdldC5pc1dlYkdMUmVuZGVyVGFyZ2V0ICkgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5XZWJHTFJlbmRlcmVyLnJlYWRSZW5kZXJUYXJnZXRQaXhlbHM6IHJlbmRlclRhcmdldCBpcyBub3QgVEhSRUUuV2ViR0xSZW5kZXJUYXJnZXQuJyApO1xyXG5cdFx0XHRcdHJldHVybjtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGxldCBmcmFtZWJ1ZmZlciA9IHByb3BlcnRpZXMuZ2V0KCByZW5kZXJUYXJnZXQgKS5fX3dlYmdsRnJhbWVidWZmZXI7XHJcblxyXG5cdFx0XHRpZiAoIHJlbmRlclRhcmdldC5pc1dlYkdMQ3ViZVJlbmRlclRhcmdldCAmJiBhY3RpdmVDdWJlRmFjZUluZGV4ICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRcdGZyYW1lYnVmZmVyID0gZnJhbWVidWZmZXJbIGFjdGl2ZUN1YmVGYWNlSW5kZXggXTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGlmICggZnJhbWVidWZmZXIgKSB7XHJcblxyXG5cdFx0XHRcdHN0YXRlLmJpbmRGcmFtZWJ1ZmZlciggX2dsLkZSQU1FQlVGRkVSLCBmcmFtZWJ1ZmZlciApO1xyXG5cclxuXHRcdFx0XHR0cnkge1xyXG5cclxuXHRcdFx0XHRcdGNvbnN0IHRleHR1cmUgPSByZW5kZXJUYXJnZXQudGV4dHVyZTtcclxuXHRcdFx0XHRcdGNvbnN0IHRleHR1cmVGb3JtYXQgPSB0ZXh0dXJlLmZvcm1hdDtcclxuXHRcdFx0XHRcdGNvbnN0IHRleHR1cmVUeXBlID0gdGV4dHVyZS50eXBlO1xyXG5cclxuXHRcdFx0XHRcdGlmICggdGV4dHVyZUZvcm1hdCAhPT0gUkdCQUZvcm1hdCAmJiB1dGlscy5jb252ZXJ0KCB0ZXh0dXJlRm9ybWF0ICkgIT09IF9nbC5nZXRQYXJhbWV0ZXIoIF9nbC5JTVBMRU1FTlRBVElPTl9DT0xPUl9SRUFEX0ZPUk1BVCApICkge1xyXG5cclxuXHRcdFx0XHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLldlYkdMUmVuZGVyZXIucmVhZFJlbmRlclRhcmdldFBpeGVsczogcmVuZGVyVGFyZ2V0IGlzIG5vdCBpbiBSR0JBIG9yIGltcGxlbWVudGF0aW9uIGRlZmluZWQgZm9ybWF0LicgKTtcclxuXHRcdFx0XHRcdFx0cmV0dXJuO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRjb25zdCBoYWxmRmxvYXRTdXBwb3J0ZWRCeUV4dCA9ICggdGV4dHVyZVR5cGUgPT09IEhhbGZGbG9hdFR5cGUgKSAmJiAoIGV4dGVuc2lvbnMuaGFzKCAnRVhUX2NvbG9yX2J1ZmZlcl9oYWxmX2Zsb2F0JyApIHx8ICggY2FwYWJpbGl0aWVzLmlzV2ViR0wyICYmIGV4dGVuc2lvbnMuaGFzKCAnRVhUX2NvbG9yX2J1ZmZlcl9mbG9hdCcgKSApICk7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCB0ZXh0dXJlVHlwZSAhPT0gVW5zaWduZWRCeXRlVHlwZSAmJiB1dGlscy5jb252ZXJ0KCB0ZXh0dXJlVHlwZSApICE9PSBfZ2wuZ2V0UGFyYW1ldGVyKCBfZ2wuSU1QTEVNRU5UQVRJT05fQ09MT1JfUkVBRF9UWVBFICkgJiYgLy8gRWRnZSBhbmQgQ2hyb21lIE1hYyA8IDUyICgjOTUxMylcclxuXHRcdFx0XHRcdFx0ISAoIHRleHR1cmVUeXBlID09PSBGbG9hdFR5cGUgJiYgKCBjYXBhYmlsaXRpZXMuaXNXZWJHTDIgfHwgZXh0ZW5zaW9ucy5oYXMoICdPRVNfdGV4dHVyZV9mbG9hdCcgKSB8fCBleHRlbnNpb25zLmhhcyggJ1dFQkdMX2NvbG9yX2J1ZmZlcl9mbG9hdCcgKSApICkgJiYgLy8gQ2hyb21lIE1hYyA+PSA1MiBhbmQgRmlyZWZveFxyXG5cdFx0XHRcdFx0XHQhIGhhbGZGbG9hdFN1cHBvcnRlZEJ5RXh0ICkge1xyXG5cclxuXHRcdFx0XHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLldlYkdMUmVuZGVyZXIucmVhZFJlbmRlclRhcmdldFBpeGVsczogcmVuZGVyVGFyZ2V0IGlzIG5vdCBpbiBVbnNpZ25lZEJ5dGVUeXBlIG9yIGltcGxlbWVudGF0aW9uIGRlZmluZWQgdHlwZS4nICk7XHJcblx0XHRcdFx0XHRcdHJldHVybjtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0Ly8gdGhlIGZvbGxvd2luZyBpZiBzdGF0ZW1lbnQgZW5zdXJlcyB2YWxpZCByZWFkIHJlcXVlc3RzIChubyBvdXQtb2YtYm91bmRzIHBpeGVscywgc2VlICM4NjA0KVxyXG5cclxuXHRcdFx0XHRcdGlmICggKCB4ID49IDAgJiYgeCA8PSAoIHJlbmRlclRhcmdldC53aWR0aCAtIHdpZHRoICkgKSAmJiAoIHkgPj0gMCAmJiB5IDw9ICggcmVuZGVyVGFyZ2V0LmhlaWdodCAtIGhlaWdodCApICkgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRfZ2wucmVhZFBpeGVscyggeCwgeSwgd2lkdGgsIGhlaWdodCwgdXRpbHMuY29udmVydCggdGV4dHVyZUZvcm1hdCApLCB1dGlscy5jb252ZXJ0KCB0ZXh0dXJlVHlwZSApLCBidWZmZXIgKTtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH0gZmluYWxseSB7XHJcblxyXG5cdFx0XHRcdFx0Ly8gcmVzdG9yZSBmcmFtZWJ1ZmZlciBvZiBjdXJyZW50IHJlbmRlciB0YXJnZXQgaWYgbmVjZXNzYXJ5XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgZnJhbWVidWZmZXIgPSAoIF9jdXJyZW50UmVuZGVyVGFyZ2V0ICE9PSBudWxsICkgPyBwcm9wZXJ0aWVzLmdldCggX2N1cnJlbnRSZW5kZXJUYXJnZXQgKS5fX3dlYmdsRnJhbWVidWZmZXIgOiBudWxsO1xyXG5cdFx0XHRcdFx0c3RhdGUuYmluZEZyYW1lYnVmZmVyKCBfZ2wuRlJBTUVCVUZGRVIsIGZyYW1lYnVmZmVyICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9O1xyXG5cclxuXHRcdHRoaXMuY29weUZyYW1lYnVmZmVyVG9UZXh0dXJlID0gZnVuY3Rpb24gKCBwb3NpdGlvbiwgdGV4dHVyZSwgbGV2ZWwgPSAwICkge1xyXG5cclxuXHRcdFx0Y29uc3QgbGV2ZWxTY2FsZSA9IE1hdGgucG93KCAyLCAtIGxldmVsICk7XHJcblx0XHRcdGNvbnN0IHdpZHRoID0gTWF0aC5mbG9vciggdGV4dHVyZS5pbWFnZS53aWR0aCAqIGxldmVsU2NhbGUgKTtcclxuXHRcdFx0Y29uc3QgaGVpZ2h0ID0gTWF0aC5mbG9vciggdGV4dHVyZS5pbWFnZS5oZWlnaHQgKiBsZXZlbFNjYWxlICk7XHJcblxyXG5cdFx0XHR0ZXh0dXJlcy5zZXRUZXh0dXJlMkQoIHRleHR1cmUsIDAgKTtcclxuXHJcblx0XHRcdF9nbC5jb3B5VGV4U3ViSW1hZ2UyRCggX2dsLlRFWFRVUkVfMkQsIGxldmVsLCAwLCAwLCBwb3NpdGlvbi54LCBwb3NpdGlvbi55LCB3aWR0aCwgaGVpZ2h0ICk7XHJcblxyXG5cdFx0XHRzdGF0ZS51bmJpbmRUZXh0dXJlKCk7XHJcblxyXG5cdFx0fTtcclxuXHJcblx0XHR0aGlzLmNvcHlUZXh0dXJlVG9UZXh0dXJlID0gZnVuY3Rpb24gKCBwb3NpdGlvbiwgc3JjVGV4dHVyZSwgZHN0VGV4dHVyZSwgbGV2ZWwgPSAwICkge1xyXG5cclxuXHRcdFx0Y29uc3Qgd2lkdGggPSBzcmNUZXh0dXJlLmltYWdlLndpZHRoO1xyXG5cdFx0XHRjb25zdCBoZWlnaHQgPSBzcmNUZXh0dXJlLmltYWdlLmhlaWdodDtcclxuXHRcdFx0Y29uc3QgZ2xGb3JtYXQgPSB1dGlscy5jb252ZXJ0KCBkc3RUZXh0dXJlLmZvcm1hdCApO1xyXG5cdFx0XHRjb25zdCBnbFR5cGUgPSB1dGlscy5jb252ZXJ0KCBkc3RUZXh0dXJlLnR5cGUgKTtcclxuXHJcblx0XHRcdHRleHR1cmVzLnNldFRleHR1cmUyRCggZHN0VGV4dHVyZSwgMCApO1xyXG5cclxuXHRcdFx0Ly8gQXMgYW5vdGhlciB0ZXh0dXJlIHVwbG9hZCBtYXkgaGF2ZSBjaGFuZ2VkIHBpeGVsU3RvcmVpXHJcblx0XHRcdC8vIHBhcmFtZXRlcnMsIG1ha2Ugc3VyZSB0aGV5IGFyZSBjb3JyZWN0IGZvciB0aGUgZHN0VGV4dHVyZVxyXG5cdFx0XHRfZ2wucGl4ZWxTdG9yZWkoIF9nbC5VTlBBQ0tfRkxJUF9ZX1dFQkdMLCBkc3RUZXh0dXJlLmZsaXBZICk7XHJcblx0XHRcdF9nbC5waXhlbFN0b3JlaSggX2dsLlVOUEFDS19QUkVNVUxUSVBMWV9BTFBIQV9XRUJHTCwgZHN0VGV4dHVyZS5wcmVtdWx0aXBseUFscGhhICk7XHJcblx0XHRcdF9nbC5waXhlbFN0b3JlaSggX2dsLlVOUEFDS19BTElHTk1FTlQsIGRzdFRleHR1cmUudW5wYWNrQWxpZ25tZW50ICk7XHJcblxyXG5cdFx0XHRpZiAoIHNyY1RleHR1cmUuaXNEYXRhVGV4dHVyZSApIHtcclxuXHJcblx0XHRcdFx0X2dsLnRleFN1YkltYWdlMkQoIF9nbC5URVhUVVJFXzJELCBsZXZlbCwgcG9zaXRpb24ueCwgcG9zaXRpb24ueSwgd2lkdGgsIGhlaWdodCwgZ2xGb3JtYXQsIGdsVHlwZSwgc3JjVGV4dHVyZS5pbWFnZS5kYXRhICk7XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRpZiAoIHNyY1RleHR1cmUuaXNDb21wcmVzc2VkVGV4dHVyZSApIHtcclxuXHJcblx0XHRcdFx0XHRfZ2wuY29tcHJlc3NlZFRleFN1YkltYWdlMkQoIF9nbC5URVhUVVJFXzJELCBsZXZlbCwgcG9zaXRpb24ueCwgcG9zaXRpb24ueSwgc3JjVGV4dHVyZS5taXBtYXBzWyAwIF0ud2lkdGgsIHNyY1RleHR1cmUubWlwbWFwc1sgMCBdLmhlaWdodCwgZ2xGb3JtYXQsIHNyY1RleHR1cmUubWlwbWFwc1sgMCBdLmRhdGEgKTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRfZ2wudGV4U3ViSW1hZ2UyRCggX2dsLlRFWFRVUkVfMkQsIGxldmVsLCBwb3NpdGlvbi54LCBwb3NpdGlvbi55LCBnbEZvcm1hdCwgZ2xUeXBlLCBzcmNUZXh0dXJlLmltYWdlICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdC8vIEdlbmVyYXRlIG1pcG1hcHMgb25seSB3aGVuIGNvcHlpbmcgbGV2ZWwgMFxyXG5cdFx0XHRpZiAoIGxldmVsID09PSAwICYmIGRzdFRleHR1cmUuZ2VuZXJhdGVNaXBtYXBzICkgX2dsLmdlbmVyYXRlTWlwbWFwKCBfZ2wuVEVYVFVSRV8yRCApO1xyXG5cclxuXHRcdFx0c3RhdGUudW5iaW5kVGV4dHVyZSgpO1xyXG5cclxuXHRcdH07XHJcblxyXG5cdFx0dGhpcy5jb3B5VGV4dHVyZVRvVGV4dHVyZTNEID0gZnVuY3Rpb24gKCBzb3VyY2VCb3gsIHBvc2l0aW9uLCBzcmNUZXh0dXJlLCBkc3RUZXh0dXJlLCBsZXZlbCA9IDAgKSB7XHJcblxyXG5cdFx0XHRpZiAoIF90aGlzLmlzV2ViR0wxUmVuZGVyZXIgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLldlYkdMUmVuZGVyZXIuY29weVRleHR1cmVUb1RleHR1cmUzRDogY2FuIG9ubHkgYmUgdXNlZCB3aXRoIFdlYkdMMi4nICk7XHJcblx0XHRcdFx0cmV0dXJuO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Y29uc3Qgd2lkdGggPSBzb3VyY2VCb3gubWF4LnggLSBzb3VyY2VCb3gubWluLnggKyAxO1xyXG5cdFx0XHRjb25zdCBoZWlnaHQgPSBzb3VyY2VCb3gubWF4LnkgLSBzb3VyY2VCb3gubWluLnkgKyAxO1xyXG5cdFx0XHRjb25zdCBkZXB0aCA9IHNvdXJjZUJveC5tYXgueiAtIHNvdXJjZUJveC5taW4ueiArIDE7XHJcblx0XHRcdGNvbnN0IGdsRm9ybWF0ID0gdXRpbHMuY29udmVydCggZHN0VGV4dHVyZS5mb3JtYXQgKTtcclxuXHRcdFx0Y29uc3QgZ2xUeXBlID0gdXRpbHMuY29udmVydCggZHN0VGV4dHVyZS50eXBlICk7XHJcblx0XHRcdGxldCBnbFRhcmdldDtcclxuXHJcblx0XHRcdGlmICggZHN0VGV4dHVyZS5pc0RhdGEzRFRleHR1cmUgKSB7XHJcblxyXG5cdFx0XHRcdHRleHR1cmVzLnNldFRleHR1cmUzRCggZHN0VGV4dHVyZSwgMCApO1xyXG5cdFx0XHRcdGdsVGFyZ2V0ID0gX2dsLlRFWFRVUkVfM0Q7XHJcblxyXG5cdFx0XHR9IGVsc2UgaWYgKCBkc3RUZXh0dXJlLmlzRGF0YUFycmF5VGV4dHVyZSB8fCBkc3RUZXh0dXJlLmlzQ29tcHJlc3NlZEFycmF5VGV4dHVyZSApIHtcclxuXHJcblx0XHRcdFx0dGV4dHVyZXMuc2V0VGV4dHVyZTJEQXJyYXkoIGRzdFRleHR1cmUsIDAgKTtcclxuXHRcdFx0XHRnbFRhcmdldCA9IF9nbC5URVhUVVJFXzJEX0FSUkFZO1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuV2ViR0xSZW5kZXJlci5jb3B5VGV4dHVyZVRvVGV4dHVyZTNEOiBvbmx5IHN1cHBvcnRzIFRIUkVFLkRhdGFUZXh0dXJlM0QgYW5kIFRIUkVFLkRhdGFUZXh0dXJlMkRBcnJheS4nICk7XHJcblx0XHRcdFx0cmV0dXJuO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0X2dsLnBpeGVsU3RvcmVpKCBfZ2wuVU5QQUNLX0ZMSVBfWV9XRUJHTCwgZHN0VGV4dHVyZS5mbGlwWSApO1xyXG5cdFx0XHRfZ2wucGl4ZWxTdG9yZWkoIF9nbC5VTlBBQ0tfUFJFTVVMVElQTFlfQUxQSEFfV0VCR0wsIGRzdFRleHR1cmUucHJlbXVsdGlwbHlBbHBoYSApO1xyXG5cdFx0XHRfZ2wucGl4ZWxTdG9yZWkoIF9nbC5VTlBBQ0tfQUxJR05NRU5ULCBkc3RUZXh0dXJlLnVucGFja0FsaWdubWVudCApO1xyXG5cclxuXHRcdFx0Y29uc3QgdW5wYWNrUm93TGVuID0gX2dsLmdldFBhcmFtZXRlciggX2dsLlVOUEFDS19ST1dfTEVOR1RIICk7XHJcblx0XHRcdGNvbnN0IHVucGFja0ltYWdlSGVpZ2h0ID0gX2dsLmdldFBhcmFtZXRlciggX2dsLlVOUEFDS19JTUFHRV9IRUlHSFQgKTtcclxuXHRcdFx0Y29uc3QgdW5wYWNrU2tpcFBpeGVscyA9IF9nbC5nZXRQYXJhbWV0ZXIoIF9nbC5VTlBBQ0tfU0tJUF9QSVhFTFMgKTtcclxuXHRcdFx0Y29uc3QgdW5wYWNrU2tpcFJvd3MgPSBfZ2wuZ2V0UGFyYW1ldGVyKCBfZ2wuVU5QQUNLX1NLSVBfUk9XUyApO1xyXG5cdFx0XHRjb25zdCB1bnBhY2tTa2lwSW1hZ2VzID0gX2dsLmdldFBhcmFtZXRlciggX2dsLlVOUEFDS19TS0lQX0lNQUdFUyApO1xyXG5cclxuXHRcdFx0Y29uc3QgaW1hZ2UgPSBzcmNUZXh0dXJlLmlzQ29tcHJlc3NlZFRleHR1cmUgPyBzcmNUZXh0dXJlLm1pcG1hcHNbIGxldmVsIF0gOiBzcmNUZXh0dXJlLmltYWdlO1xyXG5cclxuXHRcdFx0X2dsLnBpeGVsU3RvcmVpKCBfZ2wuVU5QQUNLX1JPV19MRU5HVEgsIGltYWdlLndpZHRoICk7XHJcblx0XHRcdF9nbC5waXhlbFN0b3JlaSggX2dsLlVOUEFDS19JTUFHRV9IRUlHSFQsIGltYWdlLmhlaWdodCApO1xyXG5cdFx0XHRfZ2wucGl4ZWxTdG9yZWkoIF9nbC5VTlBBQ0tfU0tJUF9QSVhFTFMsIHNvdXJjZUJveC5taW4ueCApO1xyXG5cdFx0XHRfZ2wucGl4ZWxTdG9yZWkoIF9nbC5VTlBBQ0tfU0tJUF9ST1dTLCBzb3VyY2VCb3gubWluLnkgKTtcclxuXHRcdFx0X2dsLnBpeGVsU3RvcmVpKCBfZ2wuVU5QQUNLX1NLSVBfSU1BR0VTLCBzb3VyY2VCb3gubWluLnogKTtcclxuXHJcblx0XHRcdGlmICggc3JjVGV4dHVyZS5pc0RhdGFUZXh0dXJlIHx8IHNyY1RleHR1cmUuaXNEYXRhM0RUZXh0dXJlICkge1xyXG5cclxuXHRcdFx0XHRfZ2wudGV4U3ViSW1hZ2UzRCggZ2xUYXJnZXQsIGxldmVsLCBwb3NpdGlvbi54LCBwb3NpdGlvbi55LCBwb3NpdGlvbi56LCB3aWR0aCwgaGVpZ2h0LCBkZXB0aCwgZ2xGb3JtYXQsIGdsVHlwZSwgaW1hZ2UuZGF0YSApO1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0aWYgKCBzcmNUZXh0dXJlLmlzQ29tcHJlc3NlZEFycmF5VGV4dHVyZSApIHtcclxuXHJcblx0XHRcdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5XZWJHTFJlbmRlcmVyLmNvcHlUZXh0dXJlVG9UZXh0dXJlM0Q6IHVudGVzdGVkIHN1cHBvcnQgZm9yIGNvbXByZXNzZWQgc3JjVGV4dHVyZS4nICk7XHJcblx0XHRcdFx0XHRfZ2wuY29tcHJlc3NlZFRleFN1YkltYWdlM0QoIGdsVGFyZ2V0LCBsZXZlbCwgcG9zaXRpb24ueCwgcG9zaXRpb24ueSwgcG9zaXRpb24ueiwgd2lkdGgsIGhlaWdodCwgZGVwdGgsIGdsRm9ybWF0LCBpbWFnZS5kYXRhICk7XHJcblxyXG5cdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0X2dsLnRleFN1YkltYWdlM0QoIGdsVGFyZ2V0LCBsZXZlbCwgcG9zaXRpb24ueCwgcG9zaXRpb24ueSwgcG9zaXRpb24ueiwgd2lkdGgsIGhlaWdodCwgZGVwdGgsIGdsRm9ybWF0LCBnbFR5cGUsIGltYWdlICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdF9nbC5waXhlbFN0b3JlaSggX2dsLlVOUEFDS19ST1dfTEVOR1RILCB1bnBhY2tSb3dMZW4gKTtcclxuXHRcdFx0X2dsLnBpeGVsU3RvcmVpKCBfZ2wuVU5QQUNLX0lNQUdFX0hFSUdIVCwgdW5wYWNrSW1hZ2VIZWlnaHQgKTtcclxuXHRcdFx0X2dsLnBpeGVsU3RvcmVpKCBfZ2wuVU5QQUNLX1NLSVBfUElYRUxTLCB1bnBhY2tTa2lwUGl4ZWxzICk7XHJcblx0XHRcdF9nbC5waXhlbFN0b3JlaSggX2dsLlVOUEFDS19TS0lQX1JPV1MsIHVucGFja1NraXBSb3dzICk7XHJcblx0XHRcdF9nbC5waXhlbFN0b3JlaSggX2dsLlVOUEFDS19TS0lQX0lNQUdFUywgdW5wYWNrU2tpcEltYWdlcyApO1xyXG5cclxuXHRcdFx0Ly8gR2VuZXJhdGUgbWlwbWFwcyBvbmx5IHdoZW4gY29weWluZyBsZXZlbCAwXHJcblx0XHRcdGlmICggbGV2ZWwgPT09IDAgJiYgZHN0VGV4dHVyZS5nZW5lcmF0ZU1pcG1hcHMgKSBfZ2wuZ2VuZXJhdGVNaXBtYXAoIGdsVGFyZ2V0ICk7XHJcblxyXG5cdFx0XHRzdGF0ZS51bmJpbmRUZXh0dXJlKCk7XHJcblxyXG5cdFx0fTtcclxuXHJcblx0XHR0aGlzLmluaXRUZXh0dXJlID0gZnVuY3Rpb24gKCB0ZXh0dXJlICkge1xyXG5cclxuXHRcdFx0aWYgKCB0ZXh0dXJlLmlzQ3ViZVRleHR1cmUgKSB7XHJcblxyXG5cdFx0XHRcdHRleHR1cmVzLnNldFRleHR1cmVDdWJlKCB0ZXh0dXJlLCAwICk7XHJcblxyXG5cdFx0XHR9IGVsc2UgaWYgKCB0ZXh0dXJlLmlzRGF0YTNEVGV4dHVyZSApIHtcclxuXHJcblx0XHRcdFx0dGV4dHVyZXMuc2V0VGV4dHVyZTNEKCB0ZXh0dXJlLCAwICk7XHJcblxyXG5cdFx0XHR9IGVsc2UgaWYgKCB0ZXh0dXJlLmlzRGF0YUFycmF5VGV4dHVyZSB8fCB0ZXh0dXJlLmlzQ29tcHJlc3NlZEFycmF5VGV4dHVyZSApIHtcclxuXHJcblx0XHRcdFx0dGV4dHVyZXMuc2V0VGV4dHVyZTJEQXJyYXkoIHRleHR1cmUsIDAgKTtcclxuXHJcblx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdHRleHR1cmVzLnNldFRleHR1cmUyRCggdGV4dHVyZSwgMCApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0c3RhdGUudW5iaW5kVGV4dHVyZSgpO1xyXG5cclxuXHRcdH07XHJcblxyXG5cdFx0dGhpcy5yZXNldFN0YXRlID0gZnVuY3Rpb24gKCkge1xyXG5cclxuXHRcdFx0X2N1cnJlbnRBY3RpdmVDdWJlRmFjZSA9IDA7XHJcblx0XHRcdF9jdXJyZW50QWN0aXZlTWlwbWFwTGV2ZWwgPSAwO1xyXG5cdFx0XHRfY3VycmVudFJlbmRlclRhcmdldCA9IG51bGw7XHJcblxyXG5cdFx0XHRzdGF0ZS5yZXNldCgpO1xyXG5cdFx0XHRiaW5kaW5nU3RhdGVzLnJlc2V0KCk7XHJcblxyXG5cdFx0fTtcclxuXHJcblx0XHRpZiAoIHR5cGVvZiBfX1RIUkVFX0RFVlRPT0xTX18gIT09ICd1bmRlZmluZWQnICkge1xyXG5cclxuXHRcdFx0X19USFJFRV9ERVZUT09MU19fLmRpc3BhdGNoRXZlbnQoIG5ldyBDdXN0b21FdmVudCggJ29ic2VydmUnLCB7IGRldGFpbDogdGhpcyB9ICkgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0IGNvb3JkaW5hdGVTeXN0ZW0oKSB7XHJcblxyXG5cdFx0cmV0dXJuIFdlYkdMQ29vcmRpbmF0ZVN5c3RlbTtcclxuXHJcblx0fVxyXG5cclxuXHRnZXQgb3V0cHV0Q29sb3JTcGFjZSgpIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5fb3V0cHV0Q29sb3JTcGFjZTtcclxuXHJcblx0fVxyXG5cclxuXHRzZXQgb3V0cHV0Q29sb3JTcGFjZSggY29sb3JTcGFjZSApIHtcclxuXHJcblx0XHR0aGlzLl9vdXRwdXRDb2xvclNwYWNlID0gY29sb3JTcGFjZTtcclxuXHJcblx0XHRjb25zdCBnbCA9IHRoaXMuZ2V0Q29udGV4dCgpO1xyXG5cdFx0Z2wuZHJhd2luZ0J1ZmZlckNvbG9yU3BhY2UgPSBjb2xvclNwYWNlID09PSBEaXNwbGF5UDNDb2xvclNwYWNlID8gJ2Rpc3BsYXktcDMnIDogJ3NyZ2InO1xyXG5cdFx0Z2wudW5wYWNrQ29sb3JTcGFjZSA9IENvbG9yTWFuYWdlbWVudC53b3JraW5nQ29sb3JTcGFjZSA9PT0gTGluZWFyRGlzcGxheVAzQ29sb3JTcGFjZSA/ICdkaXNwbGF5LXAzJyA6ICdzcmdiJztcclxuXHJcblx0fVxyXG5cclxuXHRnZXQgdXNlTGVnYWN5TGlnaHRzKCkgeyAvLyBAZGVwcmVjYXRlZCwgcjE1NVxyXG5cclxuXHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLldlYkdMUmVuZGVyZXI6IFRoZSBwcm9wZXJ0eSAudXNlTGVnYWN5TGlnaHRzIGhhcyBiZWVuIGRlcHJlY2F0ZWQuIE1pZ3JhdGUgeW91ciBsaWdodGluZyBhY2NvcmRpbmcgdG8gdGhlIGZvbGxvd2luZyBndWlkZTogaHR0cHM6Ly9kaXNjb3Vyc2UudGhyZWVqcy5vcmcvdC91cGRhdGVzLXRvLWxpZ2h0aW5nLWluLXRocmVlLWpzLXIxNTUvNTM3MzMuJyApO1xyXG5cdFx0cmV0dXJuIHRoaXMuX3VzZUxlZ2FjeUxpZ2h0cztcclxuXHJcblx0fVxyXG5cclxuXHRzZXQgdXNlTGVnYWN5TGlnaHRzKCB2YWx1ZSApIHsgLy8gQGRlcHJlY2F0ZWQsIHIxNTVcclxuXHJcblx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5XZWJHTFJlbmRlcmVyOiBUaGUgcHJvcGVydHkgLnVzZUxlZ2FjeUxpZ2h0cyBoYXMgYmVlbiBkZXByZWNhdGVkLiBNaWdyYXRlIHlvdXIgbGlnaHRpbmcgYWNjb3JkaW5nIHRvIHRoZSBmb2xsb3dpbmcgZ3VpZGU6IGh0dHBzOi8vZGlzY291cnNlLnRocmVlanMub3JnL3QvdXBkYXRlcy10by1saWdodGluZy1pbi10aHJlZS1qcy1yMTU1LzUzNzMzLicgKTtcclxuXHRcdHRoaXMuX3VzZUxlZ2FjeUxpZ2h0cyA9IHZhbHVlO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5cclxuZXhwb3J0IHsgV2ViR0xSZW5kZXJlciB9O1xyXG4iLCJpbXBvcnQgeyBXZWJHTFJlbmRlcmVyIH0gZnJvbSAnLi9XZWJHTFJlbmRlcmVyLmpzJztcclxuXHJcbmNsYXNzIFdlYkdMMVJlbmRlcmVyIGV4dGVuZHMgV2ViR0xSZW5kZXJlciB7fVxyXG5cclxuV2ViR0wxUmVuZGVyZXIucHJvdG90eXBlLmlzV2ViR0wxUmVuZGVyZXIgPSB0cnVlO1xyXG5cclxuZXhwb3J0IHsgV2ViR0wxUmVuZGVyZXIgfTtcclxuIiwiaW1wb3J0IHsgQ29sb3IgfSBmcm9tICcuLi9tYXRoL0NvbG9yLmpzJztcclxuXHJcbmNsYXNzIEZvZ0V4cDIge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggY29sb3IsIGRlbnNpdHkgPSAwLjAwMDI1ICkge1xyXG5cclxuXHRcdHRoaXMuaXNGb2dFeHAyID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLm5hbWUgPSAnJztcclxuXHJcblx0XHR0aGlzLmNvbG9yID0gbmV3IENvbG9yKCBjb2xvciApO1xyXG5cdFx0dGhpcy5kZW5zaXR5ID0gZGVuc2l0eTtcclxuXHJcblx0fVxyXG5cclxuXHRjbG9uZSgpIHtcclxuXHJcblx0XHRyZXR1cm4gbmV3IEZvZ0V4cDIoIHRoaXMuY29sb3IsIHRoaXMuZGVuc2l0eSApO1xyXG5cclxuXHR9XHJcblxyXG5cdHRvSlNPTiggLyogbWV0YSAqLyApIHtcclxuXHJcblx0XHRyZXR1cm4ge1xyXG5cdFx0XHR0eXBlOiAnRm9nRXhwMicsXHJcblx0XHRcdG5hbWU6IHRoaXMubmFtZSxcclxuXHRcdFx0Y29sb3I6IHRoaXMuY29sb3IuZ2V0SGV4KCksXHJcblx0XHRcdGRlbnNpdHk6IHRoaXMuZGVuc2l0eVxyXG5cdFx0fTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgRm9nRXhwMiB9O1xyXG4iLCJpbXBvcnQgeyBDb2xvciB9IGZyb20gJy4uL21hdGgvQ29sb3IuanMnO1xyXG5cclxuY2xhc3MgRm9nIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIGNvbG9yLCBuZWFyID0gMSwgZmFyID0gMTAwMCApIHtcclxuXHJcblx0XHR0aGlzLmlzRm9nID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLm5hbWUgPSAnJztcclxuXHJcblx0XHR0aGlzLmNvbG9yID0gbmV3IENvbG9yKCBjb2xvciApO1xyXG5cclxuXHRcdHRoaXMubmVhciA9IG5lYXI7XHJcblx0XHR0aGlzLmZhciA9IGZhcjtcclxuXHJcblx0fVxyXG5cclxuXHRjbG9uZSgpIHtcclxuXHJcblx0XHRyZXR1cm4gbmV3IEZvZyggdGhpcy5jb2xvciwgdGhpcy5uZWFyLCB0aGlzLmZhciApO1xyXG5cclxuXHR9XHJcblxyXG5cdHRvSlNPTiggLyogbWV0YSAqLyApIHtcclxuXHJcblx0XHRyZXR1cm4ge1xyXG5cdFx0XHR0eXBlOiAnRm9nJyxcclxuXHRcdFx0bmFtZTogdGhpcy5uYW1lLFxyXG5cdFx0XHRjb2xvcjogdGhpcy5jb2xvci5nZXRIZXgoKSxcclxuXHRcdFx0bmVhcjogdGhpcy5uZWFyLFxyXG5cdFx0XHRmYXI6IHRoaXMuZmFyXHJcblx0XHR9O1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBGb2cgfTtcclxuIiwiaW1wb3J0IHsgT2JqZWN0M0QgfSBmcm9tICcuLi9jb3JlL09iamVjdDNELmpzJztcclxuXHJcbmNsYXNzIFNjZW5lIGV4dGVuZHMgT2JqZWN0M0Qge1xyXG5cclxuXHRjb25zdHJ1Y3RvcigpIHtcclxuXHJcblx0XHRzdXBlcigpO1xyXG5cclxuXHRcdHRoaXMuaXNTY2VuZSA9IHRydWU7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ1NjZW5lJztcclxuXHJcblx0XHR0aGlzLmJhY2tncm91bmQgPSBudWxsO1xyXG5cdFx0dGhpcy5lbnZpcm9ubWVudCA9IG51bGw7XHJcblx0XHR0aGlzLmZvZyA9IG51bGw7XHJcblxyXG5cdFx0dGhpcy5iYWNrZ3JvdW5kQmx1cnJpbmVzcyA9IDA7XHJcblx0XHR0aGlzLmJhY2tncm91bmRJbnRlbnNpdHkgPSAxO1xyXG5cclxuXHRcdHRoaXMub3ZlcnJpZGVNYXRlcmlhbCA9IG51bGw7XHJcblxyXG5cdFx0aWYgKCB0eXBlb2YgX19USFJFRV9ERVZUT09MU19fICE9PSAndW5kZWZpbmVkJyApIHtcclxuXHJcblx0XHRcdF9fVEhSRUVfREVWVE9PTFNfXy5kaXNwYXRjaEV2ZW50KCBuZXcgQ3VzdG9tRXZlbnQoICdvYnNlcnZlJywgeyBkZXRhaWw6IHRoaXMgfSApICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGNvcHkoIHNvdXJjZSwgcmVjdXJzaXZlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSwgcmVjdXJzaXZlICk7XHJcblxyXG5cdFx0aWYgKCBzb3VyY2UuYmFja2dyb3VuZCAhPT0gbnVsbCApIHRoaXMuYmFja2dyb3VuZCA9IHNvdXJjZS5iYWNrZ3JvdW5kLmNsb25lKCk7XHJcblx0XHRpZiAoIHNvdXJjZS5lbnZpcm9ubWVudCAhPT0gbnVsbCApIHRoaXMuZW52aXJvbm1lbnQgPSBzb3VyY2UuZW52aXJvbm1lbnQuY2xvbmUoKTtcclxuXHRcdGlmICggc291cmNlLmZvZyAhPT0gbnVsbCApIHRoaXMuZm9nID0gc291cmNlLmZvZy5jbG9uZSgpO1xyXG5cclxuXHRcdHRoaXMuYmFja2dyb3VuZEJsdXJyaW5lc3MgPSBzb3VyY2UuYmFja2dyb3VuZEJsdXJyaW5lc3M7XHJcblx0XHR0aGlzLmJhY2tncm91bmRJbnRlbnNpdHkgPSBzb3VyY2UuYmFja2dyb3VuZEludGVuc2l0eTtcclxuXHJcblx0XHRpZiAoIHNvdXJjZS5vdmVycmlkZU1hdGVyaWFsICE9PSBudWxsICkgdGhpcy5vdmVycmlkZU1hdGVyaWFsID0gc291cmNlLm92ZXJyaWRlTWF0ZXJpYWwuY2xvbmUoKTtcclxuXHJcblx0XHR0aGlzLm1hdHJpeEF1dG9VcGRhdGUgPSBzb3VyY2UubWF0cml4QXV0b1VwZGF0ZTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHR0b0pTT04oIG1ldGEgKSB7XHJcblxyXG5cdFx0Y29uc3QgZGF0YSA9IHN1cGVyLnRvSlNPTiggbWV0YSApO1xyXG5cclxuXHRcdGlmICggdGhpcy5mb2cgIT09IG51bGwgKSBkYXRhLm9iamVjdC5mb2cgPSB0aGlzLmZvZy50b0pTT04oKTtcclxuXHRcdGlmICggdGhpcy5iYWNrZ3JvdW5kQmx1cnJpbmVzcyA+IDAgKSBkYXRhLm9iamVjdC5iYWNrZ3JvdW5kQmx1cnJpbmVzcyA9IHRoaXMuYmFja2dyb3VuZEJsdXJyaW5lc3M7XHJcblx0XHRpZiAoIHRoaXMuYmFja2dyb3VuZEludGVuc2l0eSAhPT0gMSApIGRhdGEub2JqZWN0LmJhY2tncm91bmRJbnRlbnNpdHkgPSB0aGlzLmJhY2tncm91bmRJbnRlbnNpdHk7XHJcblxyXG5cdFx0cmV0dXJuIGRhdGE7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IFNjZW5lIH07XHJcbiIsImltcG9ydCAqIGFzIE1hdGhVdGlscyBmcm9tICcuLi9tYXRoL01hdGhVdGlscy5qcyc7XHJcbmltcG9ydCB7IFN0YXRpY0RyYXdVc2FnZSB9IGZyb20gJy4uL2NvbnN0YW50cy5qcyc7XHJcbmltcG9ydCB7IHdhcm5PbmNlIH0gZnJvbSAnLi4vdXRpbHMuanMnO1xyXG5cclxuY2xhc3MgSW50ZXJsZWF2ZWRCdWZmZXIge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggYXJyYXksIHN0cmlkZSApIHtcclxuXHJcblx0XHR0aGlzLmlzSW50ZXJsZWF2ZWRCdWZmZXIgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMuYXJyYXkgPSBhcnJheTtcclxuXHRcdHRoaXMuc3RyaWRlID0gc3RyaWRlO1xyXG5cdFx0dGhpcy5jb3VudCA9IGFycmF5ICE9PSB1bmRlZmluZWQgPyBhcnJheS5sZW5ndGggLyBzdHJpZGUgOiAwO1xyXG5cclxuXHRcdHRoaXMudXNhZ2UgPSBTdGF0aWNEcmF3VXNhZ2U7XHJcblx0XHR0aGlzLl91cGRhdGVSYW5nZSA9IHsgb2Zmc2V0OiAwLCBjb3VudDogLSAxIH07XHJcblx0XHR0aGlzLnVwZGF0ZVJhbmdlcyA9IFtdO1xyXG5cclxuXHRcdHRoaXMudmVyc2lvbiA9IDA7XHJcblxyXG5cdFx0dGhpcy51dWlkID0gTWF0aFV0aWxzLmdlbmVyYXRlVVVJRCgpO1xyXG5cclxuXHR9XHJcblxyXG5cdG9uVXBsb2FkQ2FsbGJhY2soKSB7fVxyXG5cclxuXHRzZXQgbmVlZHNVcGRhdGUoIHZhbHVlICkge1xyXG5cclxuXHRcdGlmICggdmFsdWUgPT09IHRydWUgKSB0aGlzLnZlcnNpb24gKys7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0IHVwZGF0ZVJhbmdlKCkge1xyXG5cclxuXHRcdHdhcm5PbmNlKCAnVEhSRUUuSW50ZXJsZWF2ZWRCdWZmZXI6IHVwZGF0ZVJhbmdlKCkgaXMgZGVwcmVjYXRlZCBhbmQgd2lsbCBiZSByZW1vdmVkIGluIHIxNjkuIFVzZSBhZGRVcGRhdGVSYW5nZSgpIGluc3RlYWQuJyApOyAvLyBAZGVwcmVjYXRlZCwgcjE1OVxyXG5cdFx0cmV0dXJuIHRoaXMuX3VwZGF0ZVJhbmdlO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldFVzYWdlKCB2YWx1ZSApIHtcclxuXHJcblx0XHR0aGlzLnVzYWdlID0gdmFsdWU7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0YWRkVXBkYXRlUmFuZ2UoIHN0YXJ0LCBjb3VudCApIHtcclxuXHJcblx0XHR0aGlzLnVwZGF0ZVJhbmdlcy5wdXNoKCB7IHN0YXJ0LCBjb3VudCB9ICk7XHJcblxyXG5cdH1cclxuXHJcblx0Y2xlYXJVcGRhdGVSYW5nZXMoKSB7XHJcblxyXG5cdFx0dGhpcy51cGRhdGVSYW5nZXMubGVuZ3RoID0gMDtcclxuXHJcblx0fVxyXG5cclxuXHRjb3B5KCBzb3VyY2UgKSB7XHJcblxyXG5cdFx0dGhpcy5hcnJheSA9IG5ldyBzb3VyY2UuYXJyYXkuY29uc3RydWN0b3IoIHNvdXJjZS5hcnJheSApO1xyXG5cdFx0dGhpcy5jb3VudCA9IHNvdXJjZS5jb3VudDtcclxuXHRcdHRoaXMuc3RyaWRlID0gc291cmNlLnN0cmlkZTtcclxuXHRcdHRoaXMudXNhZ2UgPSBzb3VyY2UudXNhZ2U7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weUF0KCBpbmRleDEsIGF0dHJpYnV0ZSwgaW5kZXgyICkge1xyXG5cclxuXHRcdGluZGV4MSAqPSB0aGlzLnN0cmlkZTtcclxuXHRcdGluZGV4MiAqPSBhdHRyaWJ1dGUuc3RyaWRlO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IHRoaXMuc3RyaWRlOyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdHRoaXMuYXJyYXlbIGluZGV4MSArIGkgXSA9IGF0dHJpYnV0ZS5hcnJheVsgaW5kZXgyICsgaSBdO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXQoIHZhbHVlLCBvZmZzZXQgPSAwICkge1xyXG5cclxuXHRcdHRoaXMuYXJyYXkuc2V0KCB2YWx1ZSwgb2Zmc2V0ICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Y2xvbmUoIGRhdGEgKSB7XHJcblxyXG5cdFx0aWYgKCBkYXRhLmFycmF5QnVmZmVycyA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0ZGF0YS5hcnJheUJ1ZmZlcnMgPSB7fTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCB0aGlzLmFycmF5LmJ1ZmZlci5fdXVpZCA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0dGhpcy5hcnJheS5idWZmZXIuX3V1aWQgPSBNYXRoVXRpbHMuZ2VuZXJhdGVVVUlEKCk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggZGF0YS5hcnJheUJ1ZmZlcnNbIHRoaXMuYXJyYXkuYnVmZmVyLl91dWlkIF0gPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdGRhdGEuYXJyYXlCdWZmZXJzWyB0aGlzLmFycmF5LmJ1ZmZlci5fdXVpZCBdID0gdGhpcy5hcnJheS5zbGljZSggMCApLmJ1ZmZlcjtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Y29uc3QgYXJyYXkgPSBuZXcgdGhpcy5hcnJheS5jb25zdHJ1Y3RvciggZGF0YS5hcnJheUJ1ZmZlcnNbIHRoaXMuYXJyYXkuYnVmZmVyLl91dWlkIF0gKTtcclxuXHJcblx0XHRjb25zdCBpYiA9IG5ldyB0aGlzLmNvbnN0cnVjdG9yKCBhcnJheSwgdGhpcy5zdHJpZGUgKTtcclxuXHRcdGliLnNldFVzYWdlKCB0aGlzLnVzYWdlICk7XHJcblxyXG5cdFx0cmV0dXJuIGliO1xyXG5cclxuXHR9XHJcblxyXG5cdG9uVXBsb2FkKCBjYWxsYmFjayApIHtcclxuXHJcblx0XHR0aGlzLm9uVXBsb2FkQ2FsbGJhY2sgPSBjYWxsYmFjaztcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHR0b0pTT04oIGRhdGEgKSB7XHJcblxyXG5cdFx0aWYgKCBkYXRhLmFycmF5QnVmZmVycyA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0ZGF0YS5hcnJheUJ1ZmZlcnMgPSB7fTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gZ2VuZXJhdGUgVVVJRCBmb3IgYXJyYXkgYnVmZmVyIGlmIG5lY2Vzc2FyeVxyXG5cclxuXHRcdGlmICggdGhpcy5hcnJheS5idWZmZXIuX3V1aWQgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdHRoaXMuYXJyYXkuYnVmZmVyLl91dWlkID0gTWF0aFV0aWxzLmdlbmVyYXRlVVVJRCgpO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIGRhdGEuYXJyYXlCdWZmZXJzWyB0aGlzLmFycmF5LmJ1ZmZlci5fdXVpZCBdID09PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRkYXRhLmFycmF5QnVmZmVyc1sgdGhpcy5hcnJheS5idWZmZXIuX3V1aWQgXSA9IEFycmF5LmZyb20oIG5ldyBVaW50MzJBcnJheSggdGhpcy5hcnJheS5idWZmZXIgKSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvL1xyXG5cclxuXHRcdHJldHVybiB7XHJcblx0XHRcdHV1aWQ6IHRoaXMudXVpZCxcclxuXHRcdFx0YnVmZmVyOiB0aGlzLmFycmF5LmJ1ZmZlci5fdXVpZCxcclxuXHRcdFx0dHlwZTogdGhpcy5hcnJheS5jb25zdHJ1Y3Rvci5uYW1lLFxyXG5cdFx0XHRzdHJpZGU6IHRoaXMuc3RyaWRlXHJcblx0XHR9O1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBJbnRlcmxlYXZlZEJ1ZmZlciB9O1xyXG4iLCJpbXBvcnQgeyBWZWN0b3IzIH0gZnJvbSAnLi4vbWF0aC9WZWN0b3IzLmpzJztcclxuaW1wb3J0IHsgQnVmZmVyQXR0cmlidXRlIH0gZnJvbSAnLi9CdWZmZXJBdHRyaWJ1dGUuanMnO1xyXG5pbXBvcnQgeyBkZW5vcm1hbGl6ZSwgbm9ybWFsaXplIH0gZnJvbSAnLi4vbWF0aC9NYXRoVXRpbHMuanMnO1xyXG5cclxuY29uc3QgX3ZlY3RvciA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuXHJcbmNsYXNzIEludGVybGVhdmVkQnVmZmVyQXR0cmlidXRlIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIGludGVybGVhdmVkQnVmZmVyLCBpdGVtU2l6ZSwgb2Zmc2V0LCBub3JtYWxpemVkID0gZmFsc2UgKSB7XHJcblxyXG5cdFx0dGhpcy5pc0ludGVybGVhdmVkQnVmZmVyQXR0cmlidXRlID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLm5hbWUgPSAnJztcclxuXHJcblx0XHR0aGlzLmRhdGEgPSBpbnRlcmxlYXZlZEJ1ZmZlcjtcclxuXHRcdHRoaXMuaXRlbVNpemUgPSBpdGVtU2l6ZTtcclxuXHRcdHRoaXMub2Zmc2V0ID0gb2Zmc2V0O1xyXG5cclxuXHRcdHRoaXMubm9ybWFsaXplZCA9IG5vcm1hbGl6ZWQ7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0IGNvdW50KCkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLmRhdGEuY291bnQ7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0IGFycmF5KCkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLmRhdGEuYXJyYXk7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0IG5lZWRzVXBkYXRlKCB2YWx1ZSApIHtcclxuXHJcblx0XHR0aGlzLmRhdGEubmVlZHNVcGRhdGUgPSB2YWx1ZTtcclxuXHJcblx0fVxyXG5cclxuXHRhcHBseU1hdHJpeDQoIG0gKSB7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gdGhpcy5kYXRhLmNvdW50OyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdF92ZWN0b3IuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggdGhpcywgaSApO1xyXG5cclxuXHRcdFx0X3ZlY3Rvci5hcHBseU1hdHJpeDQoIG0gKTtcclxuXHJcblx0XHRcdHRoaXMuc2V0WFlaKCBpLCBfdmVjdG9yLngsIF92ZWN0b3IueSwgX3ZlY3Rvci56ICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGFwcGx5Tm9ybWFsTWF0cml4KCBtICkge1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IHRoaXMuY291bnQ7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0X3ZlY3Rvci5mcm9tQnVmZmVyQXR0cmlidXRlKCB0aGlzLCBpICk7XHJcblxyXG5cdFx0XHRfdmVjdG9yLmFwcGx5Tm9ybWFsTWF0cml4KCBtICk7XHJcblxyXG5cdFx0XHR0aGlzLnNldFhZWiggaSwgX3ZlY3Rvci54LCBfdmVjdG9yLnksIF92ZWN0b3IueiApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHR0cmFuc2Zvcm1EaXJlY3Rpb24oIG0gKSB7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gdGhpcy5jb3VudDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRfdmVjdG9yLmZyb21CdWZmZXJBdHRyaWJ1dGUoIHRoaXMsIGkgKTtcclxuXHJcblx0XHRcdF92ZWN0b3IudHJhbnNmb3JtRGlyZWN0aW9uKCBtICk7XHJcblxyXG5cdFx0XHR0aGlzLnNldFhZWiggaSwgX3ZlY3Rvci54LCBfdmVjdG9yLnksIF92ZWN0b3IueiApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRnZXRDb21wb25lbnQoIGluZGV4LCBjb21wb25lbnQgKSB7XHJcblxyXG5cdFx0bGV0IHZhbHVlID0gdGhpcy5hcnJheVsgaW5kZXggKiB0aGlzLmRhdGEuc3RyaWRlICsgdGhpcy5vZmZzZXQgKyBjb21wb25lbnQgXTtcclxuXHJcblx0XHRpZiAoIHRoaXMubm9ybWFsaXplZCApIHZhbHVlID0gZGVub3JtYWxpemUoIHZhbHVlLCB0aGlzLmFycmF5ICk7XHJcblxyXG5cdFx0cmV0dXJuIHZhbHVlO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldENvbXBvbmVudCggaW5kZXgsIGNvbXBvbmVudCwgdmFsdWUgKSB7XHJcblxyXG5cdFx0aWYgKCB0aGlzLm5vcm1hbGl6ZWQgKSB2YWx1ZSA9IG5vcm1hbGl6ZSggdmFsdWUsIHRoaXMuYXJyYXkgKTtcclxuXHJcblx0XHR0aGlzLmRhdGEuYXJyYXlbIGluZGV4ICogdGhpcy5kYXRhLnN0cmlkZSArIHRoaXMub2Zmc2V0ICsgY29tcG9uZW50IF0gPSB2YWx1ZTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRYKCBpbmRleCwgeCApIHtcclxuXHJcblx0XHRpZiAoIHRoaXMubm9ybWFsaXplZCApIHggPSBub3JtYWxpemUoIHgsIHRoaXMuYXJyYXkgKTtcclxuXHJcblx0XHR0aGlzLmRhdGEuYXJyYXlbIGluZGV4ICogdGhpcy5kYXRhLnN0cmlkZSArIHRoaXMub2Zmc2V0IF0gPSB4O1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldFkoIGluZGV4LCB5ICkge1xyXG5cclxuXHRcdGlmICggdGhpcy5ub3JtYWxpemVkICkgeSA9IG5vcm1hbGl6ZSggeSwgdGhpcy5hcnJheSApO1xyXG5cclxuXHRcdHRoaXMuZGF0YS5hcnJheVsgaW5kZXggKiB0aGlzLmRhdGEuc3RyaWRlICsgdGhpcy5vZmZzZXQgKyAxIF0gPSB5O1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldFooIGluZGV4LCB6ICkge1xyXG5cclxuXHRcdGlmICggdGhpcy5ub3JtYWxpemVkICkgeiA9IG5vcm1hbGl6ZSggeiwgdGhpcy5hcnJheSApO1xyXG5cclxuXHRcdHRoaXMuZGF0YS5hcnJheVsgaW5kZXggKiB0aGlzLmRhdGEuc3RyaWRlICsgdGhpcy5vZmZzZXQgKyAyIF0gPSB6O1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldFcoIGluZGV4LCB3ICkge1xyXG5cclxuXHRcdGlmICggdGhpcy5ub3JtYWxpemVkICkgdyA9IG5vcm1hbGl6ZSggdywgdGhpcy5hcnJheSApO1xyXG5cclxuXHRcdHRoaXMuZGF0YS5hcnJheVsgaW5kZXggKiB0aGlzLmRhdGEuc3RyaWRlICsgdGhpcy5vZmZzZXQgKyAzIF0gPSB3O1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldFgoIGluZGV4ICkge1xyXG5cclxuXHRcdGxldCB4ID0gdGhpcy5kYXRhLmFycmF5WyBpbmRleCAqIHRoaXMuZGF0YS5zdHJpZGUgKyB0aGlzLm9mZnNldCBdO1xyXG5cclxuXHRcdGlmICggdGhpcy5ub3JtYWxpemVkICkgeCA9IGRlbm9ybWFsaXplKCB4LCB0aGlzLmFycmF5ICk7XHJcblxyXG5cdFx0cmV0dXJuIHg7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0WSggaW5kZXggKSB7XHJcblxyXG5cdFx0bGV0IHkgPSB0aGlzLmRhdGEuYXJyYXlbIGluZGV4ICogdGhpcy5kYXRhLnN0cmlkZSArIHRoaXMub2Zmc2V0ICsgMSBdO1xyXG5cclxuXHRcdGlmICggdGhpcy5ub3JtYWxpemVkICkgeSA9IGRlbm9ybWFsaXplKCB5LCB0aGlzLmFycmF5ICk7XHJcblxyXG5cdFx0cmV0dXJuIHk7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0WiggaW5kZXggKSB7XHJcblxyXG5cdFx0bGV0IHogPSB0aGlzLmRhdGEuYXJyYXlbIGluZGV4ICogdGhpcy5kYXRhLnN0cmlkZSArIHRoaXMub2Zmc2V0ICsgMiBdO1xyXG5cclxuXHRcdGlmICggdGhpcy5ub3JtYWxpemVkICkgeiA9IGRlbm9ybWFsaXplKCB6LCB0aGlzLmFycmF5ICk7XHJcblxyXG5cdFx0cmV0dXJuIHo7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0VyggaW5kZXggKSB7XHJcblxyXG5cdFx0bGV0IHcgPSB0aGlzLmRhdGEuYXJyYXlbIGluZGV4ICogdGhpcy5kYXRhLnN0cmlkZSArIHRoaXMub2Zmc2V0ICsgMyBdO1xyXG5cclxuXHRcdGlmICggdGhpcy5ub3JtYWxpemVkICkgdyA9IGRlbm9ybWFsaXplKCB3LCB0aGlzLmFycmF5ICk7XHJcblxyXG5cdFx0cmV0dXJuIHc7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0WFkoIGluZGV4LCB4LCB5ICkge1xyXG5cclxuXHRcdGluZGV4ID0gaW5kZXggKiB0aGlzLmRhdGEuc3RyaWRlICsgdGhpcy5vZmZzZXQ7XHJcblxyXG5cdFx0aWYgKCB0aGlzLm5vcm1hbGl6ZWQgKSB7XHJcblxyXG5cdFx0XHR4ID0gbm9ybWFsaXplKCB4LCB0aGlzLmFycmF5ICk7XHJcblx0XHRcdHkgPSBub3JtYWxpemUoIHksIHRoaXMuYXJyYXkgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5kYXRhLmFycmF5WyBpbmRleCArIDAgXSA9IHg7XHJcblx0XHR0aGlzLmRhdGEuYXJyYXlbIGluZGV4ICsgMSBdID0geTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRYWVooIGluZGV4LCB4LCB5LCB6ICkge1xyXG5cclxuXHRcdGluZGV4ID0gaW5kZXggKiB0aGlzLmRhdGEuc3RyaWRlICsgdGhpcy5vZmZzZXQ7XHJcblxyXG5cdFx0aWYgKCB0aGlzLm5vcm1hbGl6ZWQgKSB7XHJcblxyXG5cdFx0XHR4ID0gbm9ybWFsaXplKCB4LCB0aGlzLmFycmF5ICk7XHJcblx0XHRcdHkgPSBub3JtYWxpemUoIHksIHRoaXMuYXJyYXkgKTtcclxuXHRcdFx0eiA9IG5vcm1hbGl6ZSggeiwgdGhpcy5hcnJheSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLmRhdGEuYXJyYXlbIGluZGV4ICsgMCBdID0geDtcclxuXHRcdHRoaXMuZGF0YS5hcnJheVsgaW5kZXggKyAxIF0gPSB5O1xyXG5cdFx0dGhpcy5kYXRhLmFycmF5WyBpbmRleCArIDIgXSA9IHo7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0WFlaVyggaW5kZXgsIHgsIHksIHosIHcgKSB7XHJcblxyXG5cdFx0aW5kZXggPSBpbmRleCAqIHRoaXMuZGF0YS5zdHJpZGUgKyB0aGlzLm9mZnNldDtcclxuXHJcblx0XHRpZiAoIHRoaXMubm9ybWFsaXplZCApIHtcclxuXHJcblx0XHRcdHggPSBub3JtYWxpemUoIHgsIHRoaXMuYXJyYXkgKTtcclxuXHRcdFx0eSA9IG5vcm1hbGl6ZSggeSwgdGhpcy5hcnJheSApO1xyXG5cdFx0XHR6ID0gbm9ybWFsaXplKCB6LCB0aGlzLmFycmF5ICk7XHJcblx0XHRcdHcgPSBub3JtYWxpemUoIHcsIHRoaXMuYXJyYXkgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5kYXRhLmFycmF5WyBpbmRleCArIDAgXSA9IHg7XHJcblx0XHR0aGlzLmRhdGEuYXJyYXlbIGluZGV4ICsgMSBdID0geTtcclxuXHRcdHRoaXMuZGF0YS5hcnJheVsgaW5kZXggKyAyIF0gPSB6O1xyXG5cdFx0dGhpcy5kYXRhLmFycmF5WyBpbmRleCArIDMgXSA9IHc7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Y2xvbmUoIGRhdGEgKSB7XHJcblxyXG5cdFx0aWYgKCBkYXRhID09PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRjb25zb2xlLmxvZyggJ1RIUkVFLkludGVybGVhdmVkQnVmZmVyQXR0cmlidXRlLmNsb25lKCk6IENsb25pbmcgYW4gaW50ZXJsZWF2ZWQgYnVmZmVyIGF0dHJpYnV0ZSB3aWxsIGRlLWludGVybGVhdmUgYnVmZmVyIGRhdGEuJyApO1xyXG5cclxuXHRcdFx0Y29uc3QgYXJyYXkgPSBbXTtcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHRoaXMuY291bnQ7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IGluZGV4ID0gaSAqIHRoaXMuZGF0YS5zdHJpZGUgKyB0aGlzLm9mZnNldDtcclxuXHJcblx0XHRcdFx0Zm9yICggbGV0IGogPSAwOyBqIDwgdGhpcy5pdGVtU2l6ZTsgaiArKyApIHtcclxuXHJcblx0XHRcdFx0XHRhcnJheS5wdXNoKCB0aGlzLmRhdGEuYXJyYXlbIGluZGV4ICsgaiBdICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHJldHVybiBuZXcgQnVmZmVyQXR0cmlidXRlKCBuZXcgdGhpcy5hcnJheS5jb25zdHJ1Y3RvciggYXJyYXkgKSwgdGhpcy5pdGVtU2l6ZSwgdGhpcy5ub3JtYWxpemVkICk7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdGlmICggZGF0YS5pbnRlcmxlYXZlZEJ1ZmZlcnMgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0ZGF0YS5pbnRlcmxlYXZlZEJ1ZmZlcnMgPSB7fTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGlmICggZGF0YS5pbnRlcmxlYXZlZEJ1ZmZlcnNbIHRoaXMuZGF0YS51dWlkIF0gPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0ZGF0YS5pbnRlcmxlYXZlZEJ1ZmZlcnNbIHRoaXMuZGF0YS51dWlkIF0gPSB0aGlzLmRhdGEuY2xvbmUoIGRhdGEgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHJldHVybiBuZXcgSW50ZXJsZWF2ZWRCdWZmZXJBdHRyaWJ1dGUoIGRhdGEuaW50ZXJsZWF2ZWRCdWZmZXJzWyB0aGlzLmRhdGEudXVpZCBdLCB0aGlzLml0ZW1TaXplLCB0aGlzLm9mZnNldCwgdGhpcy5ub3JtYWxpemVkICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdHRvSlNPTiggZGF0YSApIHtcclxuXHJcblx0XHRpZiAoIGRhdGEgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdGNvbnNvbGUubG9nKCAnVEhSRUUuSW50ZXJsZWF2ZWRCdWZmZXJBdHRyaWJ1dGUudG9KU09OKCk6IFNlcmlhbGl6aW5nIGFuIGludGVybGVhdmVkIGJ1ZmZlciBhdHRyaWJ1dGUgd2lsbCBkZS1pbnRlcmxlYXZlIGJ1ZmZlciBkYXRhLicgKTtcclxuXHJcblx0XHRcdGNvbnN0IGFycmF5ID0gW107XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCB0aGlzLmNvdW50OyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBpbmRleCA9IGkgKiB0aGlzLmRhdGEuc3RyaWRlICsgdGhpcy5vZmZzZXQ7XHJcblxyXG5cdFx0XHRcdGZvciAoIGxldCBqID0gMDsgaiA8IHRoaXMuaXRlbVNpemU7IGogKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0YXJyYXkucHVzaCggdGhpcy5kYXRhLmFycmF5WyBpbmRleCArIGogXSApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyBkZS1pbnRlcmxlYXZlIGRhdGEgYW5kIHNhdmUgaXQgYXMgYW4gb3JkaW5hcnkgYnVmZmVyIGF0dHJpYnV0ZSBmb3Igbm93XHJcblxyXG5cdFx0XHRyZXR1cm4ge1xyXG5cdFx0XHRcdGl0ZW1TaXplOiB0aGlzLml0ZW1TaXplLFxyXG5cdFx0XHRcdHR5cGU6IHRoaXMuYXJyYXkuY29uc3RydWN0b3IubmFtZSxcclxuXHRcdFx0XHRhcnJheTogYXJyYXksXHJcblx0XHRcdFx0bm9ybWFsaXplZDogdGhpcy5ub3JtYWxpemVkXHJcblx0XHRcdH07XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdC8vIHNhdmUgYXMgdHJ1ZSBpbnRlcmxlYXZlZCBhdHRyaWJ1dGVcclxuXHJcblx0XHRcdGlmICggZGF0YS5pbnRlcmxlYXZlZEJ1ZmZlcnMgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0ZGF0YS5pbnRlcmxlYXZlZEJ1ZmZlcnMgPSB7fTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGlmICggZGF0YS5pbnRlcmxlYXZlZEJ1ZmZlcnNbIHRoaXMuZGF0YS51dWlkIF0gPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0ZGF0YS5pbnRlcmxlYXZlZEJ1ZmZlcnNbIHRoaXMuZGF0YS51dWlkIF0gPSB0aGlzLmRhdGEudG9KU09OKCBkYXRhICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRyZXR1cm4ge1xyXG5cdFx0XHRcdGlzSW50ZXJsZWF2ZWRCdWZmZXJBdHRyaWJ1dGU6IHRydWUsXHJcblx0XHRcdFx0aXRlbVNpemU6IHRoaXMuaXRlbVNpemUsXHJcblx0XHRcdFx0ZGF0YTogdGhpcy5kYXRhLnV1aWQsXHJcblx0XHRcdFx0b2Zmc2V0OiB0aGlzLm9mZnNldCxcclxuXHRcdFx0XHRub3JtYWxpemVkOiB0aGlzLm5vcm1hbGl6ZWRcclxuXHRcdFx0fTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcblxyXG5leHBvcnQgeyBJbnRlcmxlYXZlZEJ1ZmZlckF0dHJpYnV0ZSB9O1xyXG4iLCJpbXBvcnQgeyBNYXRlcmlhbCB9IGZyb20gJy4vTWF0ZXJpYWwuanMnO1xyXG5pbXBvcnQgeyBDb2xvciB9IGZyb20gJy4uL21hdGgvQ29sb3IuanMnO1xyXG5cclxuY2xhc3MgU3ByaXRlTWF0ZXJpYWwgZXh0ZW5kcyBNYXRlcmlhbCB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBwYXJhbWV0ZXJzICkge1xyXG5cclxuXHRcdHN1cGVyKCk7XHJcblxyXG5cdFx0dGhpcy5pc1Nwcml0ZU1hdGVyaWFsID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSAnU3ByaXRlTWF0ZXJpYWwnO1xyXG5cclxuXHRcdHRoaXMuY29sb3IgPSBuZXcgQ29sb3IoIDB4ZmZmZmZmICk7XHJcblxyXG5cdFx0dGhpcy5tYXAgPSBudWxsO1xyXG5cclxuXHRcdHRoaXMuYWxwaGFNYXAgPSBudWxsO1xyXG5cclxuXHRcdHRoaXMucm90YXRpb24gPSAwO1xyXG5cclxuXHRcdHRoaXMuc2l6ZUF0dGVudWF0aW9uID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLnRyYW5zcGFyZW50ID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLmZvZyA9IHRydWU7XHJcblxyXG5cdFx0dGhpcy5zZXRWYWx1ZXMoIHBhcmFtZXRlcnMgKTtcclxuXHJcblx0fVxyXG5cclxuXHRjb3B5KCBzb3VyY2UgKSB7XHJcblxyXG5cdFx0c3VwZXIuY29weSggc291cmNlICk7XHJcblxyXG5cdFx0dGhpcy5jb2xvci5jb3B5KCBzb3VyY2UuY29sb3IgKTtcclxuXHJcblx0XHR0aGlzLm1hcCA9IHNvdXJjZS5tYXA7XHJcblxyXG5cdFx0dGhpcy5hbHBoYU1hcCA9IHNvdXJjZS5hbHBoYU1hcDtcclxuXHJcblx0XHR0aGlzLnJvdGF0aW9uID0gc291cmNlLnJvdGF0aW9uO1xyXG5cclxuXHRcdHRoaXMuc2l6ZUF0dGVudWF0aW9uID0gc291cmNlLnNpemVBdHRlbnVhdGlvbjtcclxuXHJcblx0XHR0aGlzLmZvZyA9IHNvdXJjZS5mb2c7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IFNwcml0ZU1hdGVyaWFsIH07XHJcbiIsImltcG9ydCB7IFZlY3RvcjIgfSBmcm9tICcuLi9tYXRoL1ZlY3RvcjIuanMnO1xyXG5pbXBvcnQgeyBWZWN0b3IzIH0gZnJvbSAnLi4vbWF0aC9WZWN0b3IzLmpzJztcclxuaW1wb3J0IHsgTWF0cml4NCB9IGZyb20gJy4uL21hdGgvTWF0cml4NC5qcyc7XHJcbmltcG9ydCB7IFRyaWFuZ2xlIH0gZnJvbSAnLi4vbWF0aC9UcmlhbmdsZS5qcyc7XHJcbmltcG9ydCB7IE9iamVjdDNEIH0gZnJvbSAnLi4vY29yZS9PYmplY3QzRC5qcyc7XHJcbmltcG9ydCB7IEJ1ZmZlckdlb21ldHJ5IH0gZnJvbSAnLi4vY29yZS9CdWZmZXJHZW9tZXRyeS5qcyc7XHJcbmltcG9ydCB7IEludGVybGVhdmVkQnVmZmVyIH0gZnJvbSAnLi4vY29yZS9JbnRlcmxlYXZlZEJ1ZmZlci5qcyc7XHJcbmltcG9ydCB7IEludGVybGVhdmVkQnVmZmVyQXR0cmlidXRlIH0gZnJvbSAnLi4vY29yZS9JbnRlcmxlYXZlZEJ1ZmZlckF0dHJpYnV0ZS5qcyc7XHJcbmltcG9ydCB7IFNwcml0ZU1hdGVyaWFsIH0gZnJvbSAnLi4vbWF0ZXJpYWxzL1Nwcml0ZU1hdGVyaWFsLmpzJztcclxuXHJcbmxldCBfZ2VvbWV0cnk7XHJcblxyXG5jb25zdCBfaW50ZXJzZWN0UG9pbnQgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XHJcbmNvbnN0IF93b3JsZFNjYWxlID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5jb25zdCBfbXZQb3NpdGlvbiA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuXHJcbmNvbnN0IF9hbGlnbmVkUG9zaXRpb24gPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IyKCk7XHJcbmNvbnN0IF9yb3RhdGVkUG9zaXRpb24gPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IyKCk7XHJcbmNvbnN0IF92aWV3V29ybGRNYXRyaXggPSAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXg0KCk7XHJcblxyXG5jb25zdCBfdkEgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XHJcbmNvbnN0IF92QiA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuY29uc3QgX3ZDID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5cclxuY29uc3QgX3V2QSA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjIoKTtcclxuY29uc3QgX3V2QiA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjIoKTtcclxuY29uc3QgX3V2QyA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjIoKTtcclxuXHJcbmNsYXNzIFNwcml0ZSBleHRlbmRzIE9iamVjdDNEIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIG1hdGVyaWFsID0gbmV3IFNwcml0ZU1hdGVyaWFsKCkgKSB7XHJcblxyXG5cdFx0c3VwZXIoKTtcclxuXHJcblx0XHR0aGlzLmlzU3ByaXRlID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSAnU3ByaXRlJztcclxuXHJcblx0XHRpZiAoIF9nZW9tZXRyeSA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0X2dlb21ldHJ5ID0gbmV3IEJ1ZmZlckdlb21ldHJ5KCk7XHJcblxyXG5cdFx0XHRjb25zdCBmbG9hdDMyQXJyYXkgPSBuZXcgRmxvYXQzMkFycmF5KCBbXHJcblx0XHRcdFx0LSAwLjUsIC0gMC41LCAwLCAwLCAwLFxyXG5cdFx0XHRcdDAuNSwgLSAwLjUsIDAsIDEsIDAsXHJcblx0XHRcdFx0MC41LCAwLjUsIDAsIDEsIDEsXHJcblx0XHRcdFx0LSAwLjUsIDAuNSwgMCwgMCwgMVxyXG5cdFx0XHRdICk7XHJcblxyXG5cdFx0XHRjb25zdCBpbnRlcmxlYXZlZEJ1ZmZlciA9IG5ldyBJbnRlcmxlYXZlZEJ1ZmZlciggZmxvYXQzMkFycmF5LCA1ICk7XHJcblxyXG5cdFx0XHRfZ2VvbWV0cnkuc2V0SW5kZXgoIFsgMCwgMSwgMixcdDAsIDIsIDMgXSApO1xyXG5cdFx0XHRfZ2VvbWV0cnkuc2V0QXR0cmlidXRlKCAncG9zaXRpb24nLCBuZXcgSW50ZXJsZWF2ZWRCdWZmZXJBdHRyaWJ1dGUoIGludGVybGVhdmVkQnVmZmVyLCAzLCAwLCBmYWxzZSApICk7XHJcblx0XHRcdF9nZW9tZXRyeS5zZXRBdHRyaWJ1dGUoICd1dicsIG5ldyBJbnRlcmxlYXZlZEJ1ZmZlckF0dHJpYnV0ZSggaW50ZXJsZWF2ZWRCdWZmZXIsIDIsIDMsIGZhbHNlICkgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5nZW9tZXRyeSA9IF9nZW9tZXRyeTtcclxuXHRcdHRoaXMubWF0ZXJpYWwgPSBtYXRlcmlhbDtcclxuXHJcblx0XHR0aGlzLmNlbnRlciA9IG5ldyBWZWN0b3IyKCAwLjUsIDAuNSApO1xyXG5cclxuXHR9XHJcblxyXG5cdHJheWNhc3QoIHJheWNhc3RlciwgaW50ZXJzZWN0cyApIHtcclxuXHJcblx0XHRpZiAoIHJheWNhc3Rlci5jYW1lcmEgPT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuU3ByaXRlOiBcIlJheWNhc3Rlci5jYW1lcmFcIiBuZWVkcyB0byBiZSBzZXQgaW4gb3JkZXIgdG8gcmF5Y2FzdCBhZ2FpbnN0IHNwcml0ZXMuJyApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRfd29ybGRTY2FsZS5zZXRGcm9tTWF0cml4U2NhbGUoIHRoaXMubWF0cml4V29ybGQgKTtcclxuXHJcblx0XHRfdmlld1dvcmxkTWF0cml4LmNvcHkoIHJheWNhc3Rlci5jYW1lcmEubWF0cml4V29ybGQgKTtcclxuXHRcdHRoaXMubW9kZWxWaWV3TWF0cml4Lm11bHRpcGx5TWF0cmljZXMoIHJheWNhc3Rlci5jYW1lcmEubWF0cml4V29ybGRJbnZlcnNlLCB0aGlzLm1hdHJpeFdvcmxkICk7XHJcblxyXG5cdFx0X212UG9zaXRpb24uc2V0RnJvbU1hdHJpeFBvc2l0aW9uKCB0aGlzLm1vZGVsVmlld01hdHJpeCApO1xyXG5cclxuXHRcdGlmICggcmF5Y2FzdGVyLmNhbWVyYS5pc1BlcnNwZWN0aXZlQ2FtZXJhICYmIHRoaXMubWF0ZXJpYWwuc2l6ZUF0dGVudWF0aW9uID09PSBmYWxzZSApIHtcclxuXHJcblx0XHRcdF93b3JsZFNjYWxlLm11bHRpcGx5U2NhbGFyKCAtIF9tdlBvc2l0aW9uLnogKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Y29uc3Qgcm90YXRpb24gPSB0aGlzLm1hdGVyaWFsLnJvdGF0aW9uO1xyXG5cdFx0bGV0IHNpbiwgY29zO1xyXG5cclxuXHRcdGlmICggcm90YXRpb24gIT09IDAgKSB7XHJcblxyXG5cdFx0XHRjb3MgPSBNYXRoLmNvcyggcm90YXRpb24gKTtcclxuXHRcdFx0c2luID0gTWF0aC5zaW4oIHJvdGF0aW9uICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGNvbnN0IGNlbnRlciA9IHRoaXMuY2VudGVyO1xyXG5cclxuXHRcdHRyYW5zZm9ybVZlcnRleCggX3ZBLnNldCggLSAwLjUsIC0gMC41LCAwICksIF9tdlBvc2l0aW9uLCBjZW50ZXIsIF93b3JsZFNjYWxlLCBzaW4sIGNvcyApO1xyXG5cdFx0dHJhbnNmb3JtVmVydGV4KCBfdkIuc2V0KCAwLjUsIC0gMC41LCAwICksIF9tdlBvc2l0aW9uLCBjZW50ZXIsIF93b3JsZFNjYWxlLCBzaW4sIGNvcyApO1xyXG5cdFx0dHJhbnNmb3JtVmVydGV4KCBfdkMuc2V0KCAwLjUsIDAuNSwgMCApLCBfbXZQb3NpdGlvbiwgY2VudGVyLCBfd29ybGRTY2FsZSwgc2luLCBjb3MgKTtcclxuXHJcblx0XHRfdXZBLnNldCggMCwgMCApO1xyXG5cdFx0X3V2Qi5zZXQoIDEsIDAgKTtcclxuXHRcdF91dkMuc2V0KCAxLCAxICk7XHJcblxyXG5cdFx0Ly8gY2hlY2sgZmlyc3QgdHJpYW5nbGVcclxuXHRcdGxldCBpbnRlcnNlY3QgPSByYXljYXN0ZXIucmF5LmludGVyc2VjdFRyaWFuZ2xlKCBfdkEsIF92QiwgX3ZDLCBmYWxzZSwgX2ludGVyc2VjdFBvaW50ICk7XHJcblxyXG5cdFx0aWYgKCBpbnRlcnNlY3QgPT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHQvLyBjaGVjayBzZWNvbmQgdHJpYW5nbGVcclxuXHRcdFx0dHJhbnNmb3JtVmVydGV4KCBfdkIuc2V0KCAtIDAuNSwgMC41LCAwICksIF9tdlBvc2l0aW9uLCBjZW50ZXIsIF93b3JsZFNjYWxlLCBzaW4sIGNvcyApO1xyXG5cdFx0XHRfdXZCLnNldCggMCwgMSApO1xyXG5cclxuXHRcdFx0aW50ZXJzZWN0ID0gcmF5Y2FzdGVyLnJheS5pbnRlcnNlY3RUcmlhbmdsZSggX3ZBLCBfdkMsIF92QiwgZmFsc2UsIF9pbnRlcnNlY3RQb2ludCApO1xyXG5cdFx0XHRpZiAoIGludGVyc2VjdCA9PT0gbnVsbCApIHtcclxuXHJcblx0XHRcdFx0cmV0dXJuO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCBkaXN0YW5jZSA9IHJheWNhc3Rlci5yYXkub3JpZ2luLmRpc3RhbmNlVG8oIF9pbnRlcnNlY3RQb2ludCApO1xyXG5cclxuXHRcdGlmICggZGlzdGFuY2UgPCByYXljYXN0ZXIubmVhciB8fCBkaXN0YW5jZSA+IHJheWNhc3Rlci5mYXIgKSByZXR1cm47XHJcblxyXG5cdFx0aW50ZXJzZWN0cy5wdXNoKCB7XHJcblxyXG5cdFx0XHRkaXN0YW5jZTogZGlzdGFuY2UsXHJcblx0XHRcdHBvaW50OiBfaW50ZXJzZWN0UG9pbnQuY2xvbmUoKSxcclxuXHRcdFx0dXY6IFRyaWFuZ2xlLmdldEludGVycG9sYXRpb24oIF9pbnRlcnNlY3RQb2ludCwgX3ZBLCBfdkIsIF92QywgX3V2QSwgX3V2QiwgX3V2QywgbmV3IFZlY3RvcjIoKSApLFxyXG5cdFx0XHRmYWNlOiBudWxsLFxyXG5cdFx0XHRvYmplY3Q6IHRoaXNcclxuXHJcblx0XHR9ICk7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlLCByZWN1cnNpdmUgKSB7XHJcblxyXG5cdFx0c3VwZXIuY29weSggc291cmNlLCByZWN1cnNpdmUgKTtcclxuXHJcblx0XHRpZiAoIHNvdXJjZS5jZW50ZXIgIT09IHVuZGVmaW5lZCApIHRoaXMuY2VudGVyLmNvcHkoIHNvdXJjZS5jZW50ZXIgKTtcclxuXHJcblx0XHR0aGlzLm1hdGVyaWFsID0gc291cmNlLm1hdGVyaWFsO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiB0cmFuc2Zvcm1WZXJ0ZXgoIHZlcnRleFBvc2l0aW9uLCBtdlBvc2l0aW9uLCBjZW50ZXIsIHNjYWxlLCBzaW4sIGNvcyApIHtcclxuXHJcblx0Ly8gY29tcHV0ZSBwb3NpdGlvbiBpbiBjYW1lcmEgc3BhY2VcclxuXHRfYWxpZ25lZFBvc2l0aW9uLnN1YlZlY3RvcnMoIHZlcnRleFBvc2l0aW9uLCBjZW50ZXIgKS5hZGRTY2FsYXIoIDAuNSApLm11bHRpcGx5KCBzY2FsZSApO1xyXG5cclxuXHQvLyB0byBjaGVjayBpZiByb3RhdGlvbiBpcyBub3QgemVyb1xyXG5cdGlmICggc2luICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0X3JvdGF0ZWRQb3NpdGlvbi54ID0gKCBjb3MgKiBfYWxpZ25lZFBvc2l0aW9uLnggKSAtICggc2luICogX2FsaWduZWRQb3NpdGlvbi55ICk7XHJcblx0XHRfcm90YXRlZFBvc2l0aW9uLnkgPSAoIHNpbiAqIF9hbGlnbmVkUG9zaXRpb24ueCApICsgKCBjb3MgKiBfYWxpZ25lZFBvc2l0aW9uLnkgKTtcclxuXHJcblx0fSBlbHNlIHtcclxuXHJcblx0XHRfcm90YXRlZFBvc2l0aW9uLmNvcHkoIF9hbGlnbmVkUG9zaXRpb24gKTtcclxuXHJcblx0fVxyXG5cclxuXHJcblx0dmVydGV4UG9zaXRpb24uY29weSggbXZQb3NpdGlvbiApO1xyXG5cdHZlcnRleFBvc2l0aW9uLnggKz0gX3JvdGF0ZWRQb3NpdGlvbi54O1xyXG5cdHZlcnRleFBvc2l0aW9uLnkgKz0gX3JvdGF0ZWRQb3NpdGlvbi55O1xyXG5cclxuXHQvLyB0cmFuc2Zvcm0gdG8gd29ybGQgc3BhY2VcclxuXHR2ZXJ0ZXhQb3NpdGlvbi5hcHBseU1hdHJpeDQoIF92aWV3V29ybGRNYXRyaXggKTtcclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IFNwcml0ZSB9O1xyXG4iLCJpbXBvcnQgeyBWZWN0b3IzIH0gZnJvbSAnLi4vbWF0aC9WZWN0b3IzLmpzJztcclxuaW1wb3J0IHsgT2JqZWN0M0QgfSBmcm9tICcuLi9jb3JlL09iamVjdDNELmpzJztcclxuXHJcbmNvbnN0IF92MSA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuY29uc3QgX3YyID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5cclxuY2xhc3MgTE9EIGV4dGVuZHMgT2JqZWN0M0Qge1xyXG5cclxuXHRjb25zdHJ1Y3RvcigpIHtcclxuXHJcblx0XHRzdXBlcigpO1xyXG5cclxuXHRcdHRoaXMuX2N1cnJlbnRMZXZlbCA9IDA7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ0xPRCc7XHJcblxyXG5cdFx0T2JqZWN0LmRlZmluZVByb3BlcnRpZXMoIHRoaXMsIHtcclxuXHRcdFx0bGV2ZWxzOiB7XHJcblx0XHRcdFx0ZW51bWVyYWJsZTogdHJ1ZSxcclxuXHRcdFx0XHR2YWx1ZTogW11cclxuXHRcdFx0fSxcclxuXHRcdFx0aXNMT0Q6IHtcclxuXHRcdFx0XHR2YWx1ZTogdHJ1ZSxcclxuXHRcdFx0fVxyXG5cdFx0fSApO1xyXG5cclxuXHRcdHRoaXMuYXV0b1VwZGF0ZSA9IHRydWU7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSwgZmFsc2UgKTtcclxuXHJcblx0XHRjb25zdCBsZXZlbHMgPSBzb3VyY2UubGV2ZWxzO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IGxldmVscy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0Y29uc3QgbGV2ZWwgPSBsZXZlbHNbIGkgXTtcclxuXHJcblx0XHRcdHRoaXMuYWRkTGV2ZWwoIGxldmVsLm9iamVjdC5jbG9uZSgpLCBsZXZlbC5kaXN0YW5jZSwgbGV2ZWwuaHlzdGVyZXNpcyApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLmF1dG9VcGRhdGUgPSBzb3VyY2UuYXV0b1VwZGF0ZTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRhZGRMZXZlbCggb2JqZWN0LCBkaXN0YW5jZSA9IDAsIGh5c3RlcmVzaXMgPSAwICkge1xyXG5cclxuXHRcdGRpc3RhbmNlID0gTWF0aC5hYnMoIGRpc3RhbmNlICk7XHJcblxyXG5cdFx0Y29uc3QgbGV2ZWxzID0gdGhpcy5sZXZlbHM7XHJcblxyXG5cdFx0bGV0IGw7XHJcblxyXG5cdFx0Zm9yICggbCA9IDA7IGwgPCBsZXZlbHMubGVuZ3RoOyBsICsrICkge1xyXG5cclxuXHRcdFx0aWYgKCBkaXN0YW5jZSA8IGxldmVsc1sgbCBdLmRpc3RhbmNlICkge1xyXG5cclxuXHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0bGV2ZWxzLnNwbGljZSggbCwgMCwgeyBkaXN0YW5jZTogZGlzdGFuY2UsIGh5c3RlcmVzaXM6IGh5c3RlcmVzaXMsIG9iamVjdDogb2JqZWN0IH0gKTtcclxuXHJcblx0XHR0aGlzLmFkZCggb2JqZWN0ICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0Q3VycmVudExldmVsKCkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLl9jdXJyZW50TGV2ZWw7XHJcblxyXG5cdH1cclxuXHJcblxyXG5cclxuXHRnZXRPYmplY3RGb3JEaXN0YW5jZSggZGlzdGFuY2UgKSB7XHJcblxyXG5cdFx0Y29uc3QgbGV2ZWxzID0gdGhpcy5sZXZlbHM7XHJcblxyXG5cdFx0aWYgKCBsZXZlbHMubGVuZ3RoID4gMCApIHtcclxuXHJcblx0XHRcdGxldCBpLCBsO1xyXG5cclxuXHRcdFx0Zm9yICggaSA9IDEsIGwgPSBsZXZlbHMubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0bGV0IGxldmVsRGlzdGFuY2UgPSBsZXZlbHNbIGkgXS5kaXN0YW5jZTtcclxuXHJcblx0XHRcdFx0aWYgKCBsZXZlbHNbIGkgXS5vYmplY3QudmlzaWJsZSApIHtcclxuXHJcblx0XHRcdFx0XHRsZXZlbERpc3RhbmNlIC09IGxldmVsRGlzdGFuY2UgKiBsZXZlbHNbIGkgXS5oeXN0ZXJlc2lzO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdGlmICggZGlzdGFuY2UgPCBsZXZlbERpc3RhbmNlICkge1xyXG5cclxuXHRcdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRyZXR1cm4gbGV2ZWxzWyBpIC0gMSBdLm9iamVjdDtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIG51bGw7XHJcblxyXG5cdH1cclxuXHJcblx0cmF5Y2FzdCggcmF5Y2FzdGVyLCBpbnRlcnNlY3RzICkge1xyXG5cclxuXHRcdGNvbnN0IGxldmVscyA9IHRoaXMubGV2ZWxzO1xyXG5cclxuXHRcdGlmICggbGV2ZWxzLmxlbmd0aCA+IDAgKSB7XHJcblxyXG5cdFx0XHRfdjEuc2V0RnJvbU1hdHJpeFBvc2l0aW9uKCB0aGlzLm1hdHJpeFdvcmxkICk7XHJcblxyXG5cdFx0XHRjb25zdCBkaXN0YW5jZSA9IHJheWNhc3Rlci5yYXkub3JpZ2luLmRpc3RhbmNlVG8oIF92MSApO1xyXG5cclxuXHRcdFx0dGhpcy5nZXRPYmplY3RGb3JEaXN0YW5jZSggZGlzdGFuY2UgKS5yYXljYXN0KCByYXljYXN0ZXIsIGludGVyc2VjdHMgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0dXBkYXRlKCBjYW1lcmEgKSB7XHJcblxyXG5cdFx0Y29uc3QgbGV2ZWxzID0gdGhpcy5sZXZlbHM7XHJcblxyXG5cdFx0aWYgKCBsZXZlbHMubGVuZ3RoID4gMSApIHtcclxuXHJcblx0XHRcdF92MS5zZXRGcm9tTWF0cml4UG9zaXRpb24oIGNhbWVyYS5tYXRyaXhXb3JsZCApO1xyXG5cdFx0XHRfdjIuc2V0RnJvbU1hdHJpeFBvc2l0aW9uKCB0aGlzLm1hdHJpeFdvcmxkICk7XHJcblxyXG5cdFx0XHRjb25zdCBkaXN0YW5jZSA9IF92MS5kaXN0YW5jZVRvKCBfdjIgKSAvIGNhbWVyYS56b29tO1xyXG5cclxuXHRcdFx0bGV2ZWxzWyAwIF0ub2JqZWN0LnZpc2libGUgPSB0cnVlO1xyXG5cclxuXHRcdFx0bGV0IGksIGw7XHJcblxyXG5cdFx0XHRmb3IgKCBpID0gMSwgbCA9IGxldmVscy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRsZXQgbGV2ZWxEaXN0YW5jZSA9IGxldmVsc1sgaSBdLmRpc3RhbmNlO1xyXG5cclxuXHRcdFx0XHRpZiAoIGxldmVsc1sgaSBdLm9iamVjdC52aXNpYmxlICkge1xyXG5cclxuXHRcdFx0XHRcdGxldmVsRGlzdGFuY2UgLT0gbGV2ZWxEaXN0YW5jZSAqIGxldmVsc1sgaSBdLmh5c3RlcmVzaXM7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0aWYgKCBkaXN0YW5jZSA+PSBsZXZlbERpc3RhbmNlICkge1xyXG5cclxuXHRcdFx0XHRcdGxldmVsc1sgaSAtIDEgXS5vYmplY3QudmlzaWJsZSA9IGZhbHNlO1xyXG5cdFx0XHRcdFx0bGV2ZWxzWyBpIF0ub2JqZWN0LnZpc2libGUgPSB0cnVlO1xyXG5cclxuXHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHR0aGlzLl9jdXJyZW50TGV2ZWwgPSBpIC0gMTtcclxuXHJcblx0XHRcdGZvciAoIDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdGxldmVsc1sgaSBdLm9iamVjdC52aXNpYmxlID0gZmFsc2U7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdHRvSlNPTiggbWV0YSApIHtcclxuXHJcblx0XHRjb25zdCBkYXRhID0gc3VwZXIudG9KU09OKCBtZXRhICk7XHJcblxyXG5cdFx0aWYgKCB0aGlzLmF1dG9VcGRhdGUgPT09IGZhbHNlICkgZGF0YS5vYmplY3QuYXV0b1VwZGF0ZSA9IGZhbHNlO1xyXG5cclxuXHRcdGRhdGEub2JqZWN0LmxldmVscyA9IFtdO1xyXG5cclxuXHRcdGNvbnN0IGxldmVscyA9IHRoaXMubGV2ZWxzO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IGxldmVscy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0Y29uc3QgbGV2ZWwgPSBsZXZlbHNbIGkgXTtcclxuXHJcblx0XHRcdGRhdGEub2JqZWN0LmxldmVscy5wdXNoKCB7XHJcblx0XHRcdFx0b2JqZWN0OiBsZXZlbC5vYmplY3QudXVpZCxcclxuXHRcdFx0XHRkaXN0YW5jZTogbGV2ZWwuZGlzdGFuY2UsXHJcblx0XHRcdFx0aHlzdGVyZXNpczogbGV2ZWwuaHlzdGVyZXNpc1xyXG5cdFx0XHR9ICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiBkYXRhO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5cclxuZXhwb3J0IHsgTE9EIH07XHJcbiIsImltcG9ydCB7IE1lc2ggfSBmcm9tICcuL01lc2guanMnO1xyXG5pbXBvcnQgeyBCb3gzIH0gZnJvbSAnLi4vbWF0aC9Cb3gzLmpzJztcclxuaW1wb3J0IHsgTWF0cml4NCB9IGZyb20gJy4uL21hdGgvTWF0cml4NC5qcyc7XHJcbmltcG9ydCB7IFNwaGVyZSB9IGZyb20gJy4uL21hdGgvU3BoZXJlLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yMyB9IGZyb20gJy4uL21hdGgvVmVjdG9yMy5qcyc7XHJcbmltcG9ydCB7IFZlY3RvcjQgfSBmcm9tICcuLi9tYXRoL1ZlY3RvcjQuanMnO1xyXG5pbXBvcnQgeyBSYXkgfSBmcm9tICcuLi9tYXRoL1JheS5qcyc7XHJcbmltcG9ydCB7IEF0dGFjaGVkQmluZE1vZGUsIERldGFjaGVkQmluZE1vZGUgfSBmcm9tICcuLi9jb25zdGFudHMuanMnO1xyXG5cclxuY29uc3QgX2Jhc2VQb3NpdGlvbiA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuXHJcbmNvbnN0IF9za2luSW5kZXggPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3I0KCk7XHJcbmNvbnN0IF9za2luV2VpZ2h0ID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yNCgpO1xyXG5cclxuY29uc3QgX3ZlY3RvcjMgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XHJcbmNvbnN0IF9tYXRyaXg0ID0gLypAX19QVVJFX18qLyBuZXcgTWF0cml4NCgpO1xyXG5jb25zdCBfdmVydGV4ID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5cclxuY29uc3QgX3NwaGVyZSA9IC8qQF9fUFVSRV9fKi8gbmV3IFNwaGVyZSgpO1xyXG5jb25zdCBfaW52ZXJzZU1hdHJpeCA9IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDQoKTtcclxuY29uc3QgX3JheSA9IC8qQF9fUFVSRV9fKi8gbmV3IFJheSgpO1xyXG5cclxuY2xhc3MgU2tpbm5lZE1lc2ggZXh0ZW5kcyBNZXNoIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIGdlb21ldHJ5LCBtYXRlcmlhbCApIHtcclxuXHJcblx0XHRzdXBlciggZ2VvbWV0cnksIG1hdGVyaWFsICk7XHJcblxyXG5cdFx0dGhpcy5pc1NraW5uZWRNZXNoID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSAnU2tpbm5lZE1lc2gnO1xyXG5cclxuXHRcdHRoaXMuYmluZE1vZGUgPSBBdHRhY2hlZEJpbmRNb2RlO1xyXG5cdFx0dGhpcy5iaW5kTWF0cml4ID0gbmV3IE1hdHJpeDQoKTtcclxuXHRcdHRoaXMuYmluZE1hdHJpeEludmVyc2UgPSBuZXcgTWF0cml4NCgpO1xyXG5cclxuXHRcdHRoaXMuYm91bmRpbmdCb3ggPSBudWxsO1xyXG5cdFx0dGhpcy5ib3VuZGluZ1NwaGVyZSA9IG51bGw7XHJcblxyXG5cdH1cclxuXHJcblx0Y29tcHV0ZUJvdW5kaW5nQm94KCkge1xyXG5cclxuXHRcdGNvbnN0IGdlb21ldHJ5ID0gdGhpcy5nZW9tZXRyeTtcclxuXHJcblx0XHRpZiAoIHRoaXMuYm91bmRpbmdCb3ggPT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHR0aGlzLmJvdW5kaW5nQm94ID0gbmV3IEJveDMoKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5ib3VuZGluZ0JveC5tYWtlRW1wdHkoKTtcclxuXHJcblx0XHRjb25zdCBwb3NpdGlvbkF0dHJpYnV0ZSA9IGdlb21ldHJ5LmdldEF0dHJpYnV0ZSggJ3Bvc2l0aW9uJyApO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHBvc2l0aW9uQXR0cmlidXRlLmNvdW50OyBpICsrICkge1xyXG5cclxuXHRcdFx0dGhpcy5nZXRWZXJ0ZXhQb3NpdGlvbiggaSwgX3ZlcnRleCApO1xyXG5cdFx0XHR0aGlzLmJvdW5kaW5nQm94LmV4cGFuZEJ5UG9pbnQoIF92ZXJ0ZXggKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0Y29tcHV0ZUJvdW5kaW5nU3BoZXJlKCkge1xyXG5cclxuXHRcdGNvbnN0IGdlb21ldHJ5ID0gdGhpcy5nZW9tZXRyeTtcclxuXHJcblx0XHRpZiAoIHRoaXMuYm91bmRpbmdTcGhlcmUgPT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHR0aGlzLmJvdW5kaW5nU3BoZXJlID0gbmV3IFNwaGVyZSgpO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLmJvdW5kaW5nU3BoZXJlLm1ha2VFbXB0eSgpO1xyXG5cclxuXHRcdGNvbnN0IHBvc2l0aW9uQXR0cmlidXRlID0gZ2VvbWV0cnkuZ2V0QXR0cmlidXRlKCAncG9zaXRpb24nICk7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgcG9zaXRpb25BdHRyaWJ1dGUuY291bnQ7IGkgKysgKSB7XHJcblxyXG5cdFx0XHR0aGlzLmdldFZlcnRleFBvc2l0aW9uKCBpLCBfdmVydGV4ICk7XHJcblx0XHRcdHRoaXMuYm91bmRpbmdTcGhlcmUuZXhwYW5kQnlQb2ludCggX3ZlcnRleCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRjb3B5KCBzb3VyY2UsIHJlY3Vyc2l2ZSApIHtcclxuXHJcblx0XHRzdXBlci5jb3B5KCBzb3VyY2UsIHJlY3Vyc2l2ZSApO1xyXG5cclxuXHRcdHRoaXMuYmluZE1vZGUgPSBzb3VyY2UuYmluZE1vZGU7XHJcblx0XHR0aGlzLmJpbmRNYXRyaXguY29weSggc291cmNlLmJpbmRNYXRyaXggKTtcclxuXHRcdHRoaXMuYmluZE1hdHJpeEludmVyc2UuY29weSggc291cmNlLmJpbmRNYXRyaXhJbnZlcnNlICk7XHJcblxyXG5cdFx0dGhpcy5za2VsZXRvbiA9IHNvdXJjZS5za2VsZXRvbjtcclxuXHJcblx0XHRpZiAoIHNvdXJjZS5ib3VuZGluZ0JveCAhPT0gbnVsbCApIHRoaXMuYm91bmRpbmdCb3ggPSBzb3VyY2UuYm91bmRpbmdCb3guY2xvbmUoKTtcclxuXHRcdGlmICggc291cmNlLmJvdW5kaW5nU3BoZXJlICE9PSBudWxsICkgdGhpcy5ib3VuZGluZ1NwaGVyZSA9IHNvdXJjZS5ib3VuZGluZ1NwaGVyZS5jbG9uZSgpO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHJheWNhc3QoIHJheWNhc3RlciwgaW50ZXJzZWN0cyApIHtcclxuXHJcblx0XHRjb25zdCBtYXRlcmlhbCA9IHRoaXMubWF0ZXJpYWw7XHJcblx0XHRjb25zdCBtYXRyaXhXb3JsZCA9IHRoaXMubWF0cml4V29ybGQ7XHJcblxyXG5cdFx0aWYgKCBtYXRlcmlhbCA9PT0gdW5kZWZpbmVkICkgcmV0dXJuO1xyXG5cclxuXHRcdC8vIHRlc3Qgd2l0aCBib3VuZGluZyBzcGhlcmUgaW4gd29ybGQgc3BhY2VcclxuXHJcblx0XHRpZiAoIHRoaXMuYm91bmRpbmdTcGhlcmUgPT09IG51bGwgKSB0aGlzLmNvbXB1dGVCb3VuZGluZ1NwaGVyZSgpO1xyXG5cclxuXHRcdF9zcGhlcmUuY29weSggdGhpcy5ib3VuZGluZ1NwaGVyZSApO1xyXG5cdFx0X3NwaGVyZS5hcHBseU1hdHJpeDQoIG1hdHJpeFdvcmxkICk7XHJcblxyXG5cdFx0aWYgKCByYXljYXN0ZXIucmF5LmludGVyc2VjdHNTcGhlcmUoIF9zcGhlcmUgKSA9PT0gZmFsc2UgKSByZXR1cm47XHJcblxyXG5cdFx0Ly8gY29udmVydCByYXkgdG8gbG9jYWwgc3BhY2Ugb2Ygc2tpbm5lZCBtZXNoXHJcblxyXG5cdFx0X2ludmVyc2VNYXRyaXguY29weSggbWF0cml4V29ybGQgKS5pbnZlcnQoKTtcclxuXHRcdF9yYXkuY29weSggcmF5Y2FzdGVyLnJheSApLmFwcGx5TWF0cml4NCggX2ludmVyc2VNYXRyaXggKTtcclxuXHJcblx0XHQvLyB0ZXN0IHdpdGggYm91bmRpbmcgYm94IGluIGxvY2FsIHNwYWNlXHJcblxyXG5cdFx0aWYgKCB0aGlzLmJvdW5kaW5nQm94ICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0aWYgKCBfcmF5LmludGVyc2VjdHNCb3goIHRoaXMuYm91bmRpbmdCb3ggKSA9PT0gZmFsc2UgKSByZXR1cm47XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIHRlc3QgZm9yIGludGVyc2VjdGlvbnMgd2l0aCBnZW9tZXRyeVxyXG5cclxuXHRcdHRoaXMuX2NvbXB1dGVJbnRlcnNlY3Rpb25zKCByYXljYXN0ZXIsIGludGVyc2VjdHMsIF9yYXkgKTtcclxuXHJcblx0fVxyXG5cclxuXHRnZXRWZXJ0ZXhQb3NpdGlvbiggaW5kZXgsIHRhcmdldCApIHtcclxuXHJcblx0XHRzdXBlci5nZXRWZXJ0ZXhQb3NpdGlvbiggaW5kZXgsIHRhcmdldCApO1xyXG5cclxuXHRcdHRoaXMuYXBwbHlCb25lVHJhbnNmb3JtKCBpbmRleCwgdGFyZ2V0ICk7XHJcblxyXG5cdFx0cmV0dXJuIHRhcmdldDtcclxuXHJcblx0fVxyXG5cclxuXHRiaW5kKCBza2VsZXRvbiwgYmluZE1hdHJpeCApIHtcclxuXHJcblx0XHR0aGlzLnNrZWxldG9uID0gc2tlbGV0b247XHJcblxyXG5cdFx0aWYgKCBiaW5kTWF0cml4ID09PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHR0aGlzLnVwZGF0ZU1hdHJpeFdvcmxkKCB0cnVlICk7XHJcblxyXG5cdFx0XHR0aGlzLnNrZWxldG9uLmNhbGN1bGF0ZUludmVyc2VzKCk7XHJcblxyXG5cdFx0XHRiaW5kTWF0cml4ID0gdGhpcy5tYXRyaXhXb3JsZDtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5iaW5kTWF0cml4LmNvcHkoIGJpbmRNYXRyaXggKTtcclxuXHRcdHRoaXMuYmluZE1hdHJpeEludmVyc2UuY29weSggYmluZE1hdHJpeCApLmludmVydCgpO1xyXG5cclxuXHR9XHJcblxyXG5cdHBvc2UoKSB7XHJcblxyXG5cdFx0dGhpcy5za2VsZXRvbi5wb3NlKCk7XHJcblxyXG5cdH1cclxuXHJcblx0bm9ybWFsaXplU2tpbldlaWdodHMoKSB7XHJcblxyXG5cdFx0Y29uc3QgdmVjdG9yID0gbmV3IFZlY3RvcjQoKTtcclxuXHJcblx0XHRjb25zdCBza2luV2VpZ2h0ID0gdGhpcy5nZW9tZXRyeS5hdHRyaWJ1dGVzLnNraW5XZWlnaHQ7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gc2tpbldlaWdodC5jb3VudDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHR2ZWN0b3IuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggc2tpbldlaWdodCwgaSApO1xyXG5cclxuXHRcdFx0Y29uc3Qgc2NhbGUgPSAxLjAgLyB2ZWN0b3IubWFuaGF0dGFuTGVuZ3RoKCk7XHJcblxyXG5cdFx0XHRpZiAoIHNjYWxlICE9PSBJbmZpbml0eSApIHtcclxuXHJcblx0XHRcdFx0dmVjdG9yLm11bHRpcGx5U2NhbGFyKCBzY2FsZSApO1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0dmVjdG9yLnNldCggMSwgMCwgMCwgMCApOyAvLyBkbyBzb21ldGhpbmcgcmVhc29uYWJsZVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0c2tpbldlaWdodC5zZXRYWVpXKCBpLCB2ZWN0b3IueCwgdmVjdG9yLnksIHZlY3Rvci56LCB2ZWN0b3IudyApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHR1cGRhdGVNYXRyaXhXb3JsZCggZm9yY2UgKSB7XHJcblxyXG5cdFx0c3VwZXIudXBkYXRlTWF0cml4V29ybGQoIGZvcmNlICk7XHJcblxyXG5cdFx0aWYgKCB0aGlzLmJpbmRNb2RlID09PSBBdHRhY2hlZEJpbmRNb2RlICkge1xyXG5cclxuXHRcdFx0dGhpcy5iaW5kTWF0cml4SW52ZXJzZS5jb3B5KCB0aGlzLm1hdHJpeFdvcmxkICkuaW52ZXJ0KCk7XHJcblxyXG5cdFx0fSBlbHNlIGlmICggdGhpcy5iaW5kTW9kZSA9PT0gRGV0YWNoZWRCaW5kTW9kZSApIHtcclxuXHJcblx0XHRcdHRoaXMuYmluZE1hdHJpeEludmVyc2UuY29weSggdGhpcy5iaW5kTWF0cml4ICkuaW52ZXJ0KCk7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLlNraW5uZWRNZXNoOiBVbnJlY29nbml6ZWQgYmluZE1vZGU6ICcgKyB0aGlzLmJpbmRNb2RlICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGFwcGx5Qm9uZVRyYW5zZm9ybSggaW5kZXgsIHZlY3RvciApIHtcclxuXHJcblx0XHRjb25zdCBza2VsZXRvbiA9IHRoaXMuc2tlbGV0b247XHJcblx0XHRjb25zdCBnZW9tZXRyeSA9IHRoaXMuZ2VvbWV0cnk7XHJcblxyXG5cdFx0X3NraW5JbmRleC5mcm9tQnVmZmVyQXR0cmlidXRlKCBnZW9tZXRyeS5hdHRyaWJ1dGVzLnNraW5JbmRleCwgaW5kZXggKTtcclxuXHRcdF9za2luV2VpZ2h0LmZyb21CdWZmZXJBdHRyaWJ1dGUoIGdlb21ldHJ5LmF0dHJpYnV0ZXMuc2tpbldlaWdodCwgaW5kZXggKTtcclxuXHJcblx0XHRfYmFzZVBvc2l0aW9uLmNvcHkoIHZlY3RvciApLmFwcGx5TWF0cml4NCggdGhpcy5iaW5kTWF0cml4ICk7XHJcblxyXG5cdFx0dmVjdG9yLnNldCggMCwgMCwgMCApO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IDQ7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRjb25zdCB3ZWlnaHQgPSBfc2tpbldlaWdodC5nZXRDb21wb25lbnQoIGkgKTtcclxuXHJcblx0XHRcdGlmICggd2VpZ2h0ICE9PSAwICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBib25lSW5kZXggPSBfc2tpbkluZGV4LmdldENvbXBvbmVudCggaSApO1xyXG5cclxuXHRcdFx0XHRfbWF0cml4NC5tdWx0aXBseU1hdHJpY2VzKCBza2VsZXRvbi5ib25lc1sgYm9uZUluZGV4IF0ubWF0cml4V29ybGQsIHNrZWxldG9uLmJvbmVJbnZlcnNlc1sgYm9uZUluZGV4IF0gKTtcclxuXHJcblx0XHRcdFx0dmVjdG9yLmFkZFNjYWxlZFZlY3RvciggX3ZlY3RvcjMuY29weSggX2Jhc2VQb3NpdGlvbiApLmFwcGx5TWF0cml4NCggX21hdHJpeDQgKSwgd2VpZ2h0ICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB2ZWN0b3IuYXBwbHlNYXRyaXg0KCB0aGlzLmJpbmRNYXRyaXhJbnZlcnNlICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IFNraW5uZWRNZXNoIH07XHJcbiIsImltcG9ydCB7IE9iamVjdDNEIH0gZnJvbSAnLi4vY29yZS9PYmplY3QzRC5qcyc7XHJcblxyXG5jbGFzcyBCb25lIGV4dGVuZHMgT2JqZWN0M0Qge1xyXG5cclxuXHRjb25zdHJ1Y3RvcigpIHtcclxuXHJcblx0XHRzdXBlcigpO1xyXG5cclxuXHRcdHRoaXMuaXNCb25lID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSAnQm9uZSc7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IEJvbmUgfTtcclxuIiwiaW1wb3J0IHsgVGV4dHVyZSB9IGZyb20gJy4vVGV4dHVyZS5qcyc7XHJcbmltcG9ydCB7IE5lYXJlc3RGaWx0ZXIgfSBmcm9tICcuLi9jb25zdGFudHMuanMnO1xyXG5cclxuY2xhc3MgRGF0YVRleHR1cmUgZXh0ZW5kcyBUZXh0dXJlIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIGRhdGEgPSBudWxsLCB3aWR0aCA9IDEsIGhlaWdodCA9IDEsIGZvcm1hdCwgdHlwZSwgbWFwcGluZywgd3JhcFMsIHdyYXBULCBtYWdGaWx0ZXIgPSBOZWFyZXN0RmlsdGVyLCBtaW5GaWx0ZXIgPSBOZWFyZXN0RmlsdGVyLCBhbmlzb3Ryb3B5LCBjb2xvclNwYWNlICkge1xyXG5cclxuXHRcdHN1cGVyKCBudWxsLCBtYXBwaW5nLCB3cmFwUywgd3JhcFQsIG1hZ0ZpbHRlciwgbWluRmlsdGVyLCBmb3JtYXQsIHR5cGUsIGFuaXNvdHJvcHksIGNvbG9yU3BhY2UgKTtcclxuXHJcblx0XHR0aGlzLmlzRGF0YVRleHR1cmUgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMuaW1hZ2UgPSB7IGRhdGE6IGRhdGEsIHdpZHRoOiB3aWR0aCwgaGVpZ2h0OiBoZWlnaHQgfTtcclxuXHJcblx0XHR0aGlzLmdlbmVyYXRlTWlwbWFwcyA9IGZhbHNlO1xyXG5cdFx0dGhpcy5mbGlwWSA9IGZhbHNlO1xyXG5cdFx0dGhpcy51bnBhY2tBbGlnbm1lbnQgPSAxO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBEYXRhVGV4dHVyZSB9O1xyXG4iLCJpbXBvcnQge1xyXG5cdFJHQkFGb3JtYXQsXHJcblx0RmxvYXRUeXBlXHJcbn0gZnJvbSAnLi4vY29uc3RhbnRzLmpzJztcclxuaW1wb3J0IHsgQm9uZSB9IGZyb20gJy4vQm9uZS5qcyc7XHJcbmltcG9ydCB7IE1hdHJpeDQgfSBmcm9tICcuLi9tYXRoL01hdHJpeDQuanMnO1xyXG5pbXBvcnQgeyBEYXRhVGV4dHVyZSB9IGZyb20gJy4uL3RleHR1cmVzL0RhdGFUZXh0dXJlLmpzJztcclxuaW1wb3J0ICogYXMgTWF0aFV0aWxzIGZyb20gJy4uL21hdGgvTWF0aFV0aWxzLmpzJztcclxuXHJcbmNvbnN0IF9vZmZzZXRNYXRyaXggPSAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXg0KCk7XHJcbmNvbnN0IF9pZGVudGl0eU1hdHJpeCA9IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDQoKTtcclxuXHJcbmNsYXNzIFNrZWxldG9uIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIGJvbmVzID0gW10sIGJvbmVJbnZlcnNlcyA9IFtdICkge1xyXG5cclxuXHRcdHRoaXMudXVpZCA9IE1hdGhVdGlscy5nZW5lcmF0ZVVVSUQoKTtcclxuXHJcblx0XHR0aGlzLmJvbmVzID0gYm9uZXMuc2xpY2UoIDAgKTtcclxuXHRcdHRoaXMuYm9uZUludmVyc2VzID0gYm9uZUludmVyc2VzO1xyXG5cdFx0dGhpcy5ib25lTWF0cmljZXMgPSBudWxsO1xyXG5cclxuXHRcdHRoaXMuYm9uZVRleHR1cmUgPSBudWxsO1xyXG5cclxuXHRcdHRoaXMuaW5pdCgpO1xyXG5cclxuXHR9XHJcblxyXG5cdGluaXQoKSB7XHJcblxyXG5cdFx0Y29uc3QgYm9uZXMgPSB0aGlzLmJvbmVzO1xyXG5cdFx0Y29uc3QgYm9uZUludmVyc2VzID0gdGhpcy5ib25lSW52ZXJzZXM7XHJcblxyXG5cdFx0dGhpcy5ib25lTWF0cmljZXMgPSBuZXcgRmxvYXQzMkFycmF5KCBib25lcy5sZW5ndGggKiAxNiApO1xyXG5cclxuXHRcdC8vIGNhbGN1bGF0ZSBpbnZlcnNlIGJvbmUgbWF0cmljZXMgaWYgbmVjZXNzYXJ5XHJcblxyXG5cdFx0aWYgKCBib25lSW52ZXJzZXMubGVuZ3RoID09PSAwICkge1xyXG5cclxuXHRcdFx0dGhpcy5jYWxjdWxhdGVJbnZlcnNlcygpO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHQvLyBoYW5kbGUgc3BlY2lhbCBjYXNlXHJcblxyXG5cdFx0XHRpZiAoIGJvbmVzLmxlbmd0aCAhPT0gYm9uZUludmVyc2VzLmxlbmd0aCApIHtcclxuXHJcblx0XHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuU2tlbGV0b246IE51bWJlciBvZiBpbnZlcnNlIGJvbmUgbWF0cmljZXMgZG9lcyBub3QgbWF0Y2ggYW1vdW50IG9mIGJvbmVzLicgKTtcclxuXHJcblx0XHRcdFx0dGhpcy5ib25lSW52ZXJzZXMgPSBbXTtcclxuXHJcblx0XHRcdFx0Zm9yICggbGV0IGkgPSAwLCBpbCA9IHRoaXMuYm9uZXMubGVuZ3RoOyBpIDwgaWw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0dGhpcy5ib25lSW52ZXJzZXMucHVzaCggbmV3IE1hdHJpeDQoKSApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGNhbGN1bGF0ZUludmVyc2VzKCkge1xyXG5cclxuXHRcdHRoaXMuYm9uZUludmVyc2VzLmxlbmd0aCA9IDA7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBpbCA9IHRoaXMuYm9uZXMubGVuZ3RoOyBpIDwgaWw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBpbnZlcnNlID0gbmV3IE1hdHJpeDQoKTtcclxuXHJcblx0XHRcdGlmICggdGhpcy5ib25lc1sgaSBdICkge1xyXG5cclxuXHRcdFx0XHRpbnZlcnNlLmNvcHkoIHRoaXMuYm9uZXNbIGkgXS5tYXRyaXhXb3JsZCApLmludmVydCgpO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0dGhpcy5ib25lSW52ZXJzZXMucHVzaCggaW52ZXJzZSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRwb3NlKCkge1xyXG5cclxuXHRcdC8vIHJlY292ZXIgdGhlIGJpbmQtdGltZSB3b3JsZCBtYXRyaWNlc1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSB0aGlzLmJvbmVzLmxlbmd0aDsgaSA8IGlsOyBpICsrICkge1xyXG5cclxuXHRcdFx0Y29uc3QgYm9uZSA9IHRoaXMuYm9uZXNbIGkgXTtcclxuXHJcblx0XHRcdGlmICggYm9uZSApIHtcclxuXHJcblx0XHRcdFx0Ym9uZS5tYXRyaXhXb3JsZC5jb3B5KCB0aGlzLmJvbmVJbnZlcnNlc1sgaSBdICkuaW52ZXJ0KCk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIGNvbXB1dGUgdGhlIGxvY2FsIG1hdHJpY2VzLCBwb3NpdGlvbnMsIHJvdGF0aW9ucyBhbmQgc2NhbGVzXHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBpbCA9IHRoaXMuYm9uZXMubGVuZ3RoOyBpIDwgaWw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBib25lID0gdGhpcy5ib25lc1sgaSBdO1xyXG5cclxuXHRcdFx0aWYgKCBib25lICkge1xyXG5cclxuXHRcdFx0XHRpZiAoIGJvbmUucGFyZW50ICYmIGJvbmUucGFyZW50LmlzQm9uZSApIHtcclxuXHJcblx0XHRcdFx0XHRib25lLm1hdHJpeC5jb3B5KCBib25lLnBhcmVudC5tYXRyaXhXb3JsZCApLmludmVydCgpO1xyXG5cdFx0XHRcdFx0Ym9uZS5tYXRyaXgubXVsdGlwbHkoIGJvbmUubWF0cml4V29ybGQgKTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRib25lLm1hdHJpeC5jb3B5KCBib25lLm1hdHJpeFdvcmxkICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0Ym9uZS5tYXRyaXguZGVjb21wb3NlKCBib25lLnBvc2l0aW9uLCBib25lLnF1YXRlcm5pb24sIGJvbmUuc2NhbGUgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0dXBkYXRlKCkge1xyXG5cclxuXHRcdGNvbnN0IGJvbmVzID0gdGhpcy5ib25lcztcclxuXHRcdGNvbnN0IGJvbmVJbnZlcnNlcyA9IHRoaXMuYm9uZUludmVyc2VzO1xyXG5cdFx0Y29uc3QgYm9uZU1hdHJpY2VzID0gdGhpcy5ib25lTWF0cmljZXM7XHJcblx0XHRjb25zdCBib25lVGV4dHVyZSA9IHRoaXMuYm9uZVRleHR1cmU7XHJcblxyXG5cdFx0Ly8gZmxhdHRlbiBib25lIG1hdHJpY2VzIHRvIGFycmF5XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBpbCA9IGJvbmVzLmxlbmd0aDsgaSA8IGlsOyBpICsrICkge1xyXG5cclxuXHRcdFx0Ly8gY29tcHV0ZSB0aGUgb2Zmc2V0IGJldHdlZW4gdGhlIGN1cnJlbnQgYW5kIHRoZSBvcmlnaW5hbCB0cmFuc2Zvcm1cclxuXHJcblx0XHRcdGNvbnN0IG1hdHJpeCA9IGJvbmVzWyBpIF0gPyBib25lc1sgaSBdLm1hdHJpeFdvcmxkIDogX2lkZW50aXR5TWF0cml4O1xyXG5cclxuXHRcdFx0X29mZnNldE1hdHJpeC5tdWx0aXBseU1hdHJpY2VzKCBtYXRyaXgsIGJvbmVJbnZlcnNlc1sgaSBdICk7XHJcblx0XHRcdF9vZmZzZXRNYXRyaXgudG9BcnJheSggYm9uZU1hdHJpY2VzLCBpICogMTYgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBib25lVGV4dHVyZSAhPT0gbnVsbCApIHtcclxuXHJcblx0XHRcdGJvbmVUZXh0dXJlLm5lZWRzVXBkYXRlID0gdHJ1ZTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0Y2xvbmUoKSB7XHJcblxyXG5cdFx0cmV0dXJuIG5ldyBTa2VsZXRvbiggdGhpcy5ib25lcywgdGhpcy5ib25lSW52ZXJzZXMgKTtcclxuXHJcblx0fVxyXG5cclxuXHRjb21wdXRlQm9uZVRleHR1cmUoKSB7XHJcblxyXG5cdFx0Ly8gbGF5b3V0ICgxIG1hdHJpeCA9IDQgcGl4ZWxzKVxyXG5cdFx0Ly8gICAgICBSR0JBIFJHQkEgUkdCQSBSR0JBICg9PiBjb2x1bW4xLCBjb2x1bW4yLCBjb2x1bW4zLCBjb2x1bW40KVxyXG5cdFx0Ly8gIHdpdGggIDh4OCAgcGl4ZWwgdGV4dHVyZSBtYXggICAxNiBib25lcyAqIDQgcGl4ZWxzID0gICg4ICogOClcclxuXHRcdC8vICAgICAgIDE2eDE2IHBpeGVsIHRleHR1cmUgbWF4ICAgNjQgYm9uZXMgKiA0IHBpeGVscyA9ICgxNiAqIDE2KVxyXG5cdFx0Ly8gICAgICAgMzJ4MzIgcGl4ZWwgdGV4dHVyZSBtYXggIDI1NiBib25lcyAqIDQgcGl4ZWxzID0gKDMyICogMzIpXHJcblx0XHQvLyAgICAgICA2NHg2NCBwaXhlbCB0ZXh0dXJlIG1heCAxMDI0IGJvbmVzICogNCBwaXhlbHMgPSAoNjQgKiA2NClcclxuXHJcblx0XHRsZXQgc2l6ZSA9IE1hdGguc3FydCggdGhpcy5ib25lcy5sZW5ndGggKiA0ICk7IC8vIDQgcGl4ZWxzIG5lZWRlZCBmb3IgMSBtYXRyaXhcclxuXHRcdHNpemUgPSBNYXRoLmNlaWwoIHNpemUgLyA0ICkgKiA0O1xyXG5cdFx0c2l6ZSA9IE1hdGgubWF4KCBzaXplLCA0ICk7XHJcblxyXG5cdFx0Y29uc3QgYm9uZU1hdHJpY2VzID0gbmV3IEZsb2F0MzJBcnJheSggc2l6ZSAqIHNpemUgKiA0ICk7IC8vIDQgZmxvYXRzIHBlciBSR0JBIHBpeGVsXHJcblx0XHRib25lTWF0cmljZXMuc2V0KCB0aGlzLmJvbmVNYXRyaWNlcyApOyAvLyBjb3B5IGN1cnJlbnQgdmFsdWVzXHJcblxyXG5cdFx0Y29uc3QgYm9uZVRleHR1cmUgPSBuZXcgRGF0YVRleHR1cmUoIGJvbmVNYXRyaWNlcywgc2l6ZSwgc2l6ZSwgUkdCQUZvcm1hdCwgRmxvYXRUeXBlICk7XHJcblx0XHRib25lVGV4dHVyZS5uZWVkc1VwZGF0ZSA9IHRydWU7XHJcblxyXG5cdFx0dGhpcy5ib25lTWF0cmljZXMgPSBib25lTWF0cmljZXM7XHJcblx0XHR0aGlzLmJvbmVUZXh0dXJlID0gYm9uZVRleHR1cmU7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0Qm9uZUJ5TmFtZSggbmFtZSApIHtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gdGhpcy5ib25lcy5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcclxuXHJcblx0XHRcdGNvbnN0IGJvbmUgPSB0aGlzLmJvbmVzWyBpIF07XHJcblxyXG5cdFx0XHRpZiAoIGJvbmUubmFtZSA9PT0gbmFtZSApIHtcclxuXHJcblx0XHRcdFx0cmV0dXJuIGJvbmU7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB1bmRlZmluZWQ7XHJcblxyXG5cdH1cclxuXHJcblx0ZGlzcG9zZSggKSB7XHJcblxyXG5cdFx0aWYgKCB0aGlzLmJvbmVUZXh0dXJlICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0dGhpcy5ib25lVGV4dHVyZS5kaXNwb3NlKCk7XHJcblxyXG5cdFx0XHR0aGlzLmJvbmVUZXh0dXJlID0gbnVsbDtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0ZnJvbUpTT04oIGpzb24sIGJvbmVzICkge1xyXG5cclxuXHRcdHRoaXMudXVpZCA9IGpzb24udXVpZDtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBqc29uLmJvbmVzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRjb25zdCB1dWlkID0ganNvbi5ib25lc1sgaSBdO1xyXG5cdFx0XHRsZXQgYm9uZSA9IGJvbmVzWyB1dWlkIF07XHJcblxyXG5cdFx0XHRpZiAoIGJvbmUgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuU2tlbGV0b246IE5vIGJvbmUgZm91bmQgd2l0aCBVVUlEOicsIHV1aWQgKTtcclxuXHRcdFx0XHRib25lID0gbmV3IEJvbmUoKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHRoaXMuYm9uZXMucHVzaCggYm9uZSApO1xyXG5cdFx0XHR0aGlzLmJvbmVJbnZlcnNlcy5wdXNoKCBuZXcgTWF0cml4NCgpLmZyb21BcnJheSgganNvbi5ib25lSW52ZXJzZXNbIGkgXSApICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMuaW5pdCgpO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHRvSlNPTigpIHtcclxuXHJcblx0XHRjb25zdCBkYXRhID0ge1xyXG5cdFx0XHRtZXRhZGF0YToge1xyXG5cdFx0XHRcdHZlcnNpb246IDQuNixcclxuXHRcdFx0XHR0eXBlOiAnU2tlbGV0b24nLFxyXG5cdFx0XHRcdGdlbmVyYXRvcjogJ1NrZWxldG9uLnRvSlNPTidcclxuXHRcdFx0fSxcclxuXHRcdFx0Ym9uZXM6IFtdLFxyXG5cdFx0XHRib25lSW52ZXJzZXM6IFtdXHJcblx0XHR9O1xyXG5cclxuXHRcdGRhdGEudXVpZCA9IHRoaXMudXVpZDtcclxuXHJcblx0XHRjb25zdCBib25lcyA9IHRoaXMuYm9uZXM7XHJcblx0XHRjb25zdCBib25lSW52ZXJzZXMgPSB0aGlzLmJvbmVJbnZlcnNlcztcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBib25lcy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0Y29uc3QgYm9uZSA9IGJvbmVzWyBpIF07XHJcblx0XHRcdGRhdGEuYm9uZXMucHVzaCggYm9uZS51dWlkICk7XHJcblxyXG5cdFx0XHRjb25zdCBib25lSW52ZXJzZSA9IGJvbmVJbnZlcnNlc1sgaSBdO1xyXG5cdFx0XHRkYXRhLmJvbmVJbnZlcnNlcy5wdXNoKCBib25lSW52ZXJzZS50b0FycmF5KCkgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIGRhdGE7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IFNrZWxldG9uIH07XHJcbiIsImltcG9ydCB7IEJ1ZmZlckF0dHJpYnV0ZSB9IGZyb20gJy4vQnVmZmVyQXR0cmlidXRlLmpzJztcclxuXHJcbmNsYXNzIEluc3RhbmNlZEJ1ZmZlckF0dHJpYnV0ZSBleHRlbmRzIEJ1ZmZlckF0dHJpYnV0ZSB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBhcnJheSwgaXRlbVNpemUsIG5vcm1hbGl6ZWQsIG1lc2hQZXJBdHRyaWJ1dGUgPSAxICkge1xyXG5cclxuXHRcdHN1cGVyKCBhcnJheSwgaXRlbVNpemUsIG5vcm1hbGl6ZWQgKTtcclxuXHJcblx0XHR0aGlzLmlzSW5zdGFuY2VkQnVmZmVyQXR0cmlidXRlID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLm1lc2hQZXJBdHRyaWJ1dGUgPSBtZXNoUGVyQXR0cmlidXRlO1xyXG5cclxuXHR9XHJcblxyXG5cdGNvcHkoIHNvdXJjZSApIHtcclxuXHJcblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcclxuXHJcblx0XHR0aGlzLm1lc2hQZXJBdHRyaWJ1dGUgPSBzb3VyY2UubWVzaFBlckF0dHJpYnV0ZTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHR0b0pTT04oKSB7XHJcblxyXG5cdFx0Y29uc3QgZGF0YSA9IHN1cGVyLnRvSlNPTigpO1xyXG5cclxuXHRcdGRhdGEubWVzaFBlckF0dHJpYnV0ZSA9IHRoaXMubWVzaFBlckF0dHJpYnV0ZTtcclxuXHJcblx0XHRkYXRhLmlzSW5zdGFuY2VkQnVmZmVyQXR0cmlidXRlID0gdHJ1ZTtcclxuXHJcblx0XHRyZXR1cm4gZGF0YTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgSW5zdGFuY2VkQnVmZmVyQXR0cmlidXRlIH07XHJcbiIsImltcG9ydCB7IEluc3RhbmNlZEJ1ZmZlckF0dHJpYnV0ZSB9IGZyb20gJy4uL2NvcmUvSW5zdGFuY2VkQnVmZmVyQXR0cmlidXRlLmpzJztcclxuaW1wb3J0IHsgTWVzaCB9IGZyb20gJy4vTWVzaC5qcyc7XHJcbmltcG9ydCB7IEJveDMgfSBmcm9tICcuLi9tYXRoL0JveDMuanMnO1xyXG5pbXBvcnQgeyBNYXRyaXg0IH0gZnJvbSAnLi4vbWF0aC9NYXRyaXg0LmpzJztcclxuaW1wb3J0IHsgU3BoZXJlIH0gZnJvbSAnLi4vbWF0aC9TcGhlcmUuanMnO1xyXG5cclxuY29uc3QgX2luc3RhbmNlTG9jYWxNYXRyaXggPSAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXg0KCk7XHJcbmNvbnN0IF9pbnN0YW5jZVdvcmxkTWF0cml4ID0gLypAX19QVVJFX18qLyBuZXcgTWF0cml4NCgpO1xyXG5cclxuY29uc3QgX2luc3RhbmNlSW50ZXJzZWN0cyA9IFtdO1xyXG5cclxuY29uc3QgX2JveDMgPSAvKkBfX1BVUkVfXyovIG5ldyBCb3gzKCk7XHJcbmNvbnN0IF9pZGVudGl0eSA9IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDQoKTtcclxuY29uc3QgX21lc2ggPSAvKkBfX1BVUkVfXyovIG5ldyBNZXNoKCk7XHJcbmNvbnN0IF9zcGhlcmUgPSAvKkBfX1BVUkVfXyovIG5ldyBTcGhlcmUoKTtcclxuXHJcbmNsYXNzIEluc3RhbmNlZE1lc2ggZXh0ZW5kcyBNZXNoIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIGdlb21ldHJ5LCBtYXRlcmlhbCwgY291bnQgKSB7XHJcblxyXG5cdFx0c3VwZXIoIGdlb21ldHJ5LCBtYXRlcmlhbCApO1xyXG5cclxuXHRcdHRoaXMuaXNJbnN0YW5jZWRNZXNoID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLmluc3RhbmNlTWF0cml4ID0gbmV3IEluc3RhbmNlZEJ1ZmZlckF0dHJpYnV0ZSggbmV3IEZsb2F0MzJBcnJheSggY291bnQgKiAxNiApLCAxNiApO1xyXG5cdFx0dGhpcy5pbnN0YW5jZUNvbG9yID0gbnVsbDtcclxuXHJcblx0XHR0aGlzLmNvdW50ID0gY291bnQ7XHJcblxyXG5cdFx0dGhpcy5ib3VuZGluZ0JveCA9IG51bGw7XHJcblx0XHR0aGlzLmJvdW5kaW5nU3BoZXJlID0gbnVsbDtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBjb3VudDsgaSArKyApIHtcclxuXHJcblx0XHRcdHRoaXMuc2V0TWF0cml4QXQoIGksIF9pZGVudGl0eSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRjb21wdXRlQm91bmRpbmdCb3goKSB7XHJcblxyXG5cdFx0Y29uc3QgZ2VvbWV0cnkgPSB0aGlzLmdlb21ldHJ5O1xyXG5cdFx0Y29uc3QgY291bnQgPSB0aGlzLmNvdW50O1xyXG5cclxuXHRcdGlmICggdGhpcy5ib3VuZGluZ0JveCA9PT0gbnVsbCApIHtcclxuXHJcblx0XHRcdHRoaXMuYm91bmRpbmdCb3ggPSBuZXcgQm94MygpO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIGdlb21ldHJ5LmJvdW5kaW5nQm94ID09PSBudWxsICkge1xyXG5cclxuXHRcdFx0Z2VvbWV0cnkuY29tcHV0ZUJvdW5kaW5nQm94KCk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMuYm91bmRpbmdCb3gubWFrZUVtcHR5KCk7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgY291bnQ7IGkgKysgKSB7XHJcblxyXG5cdFx0XHR0aGlzLmdldE1hdHJpeEF0KCBpLCBfaW5zdGFuY2VMb2NhbE1hdHJpeCApO1xyXG5cclxuXHRcdFx0X2JveDMuY29weSggZ2VvbWV0cnkuYm91bmRpbmdCb3ggKS5hcHBseU1hdHJpeDQoIF9pbnN0YW5jZUxvY2FsTWF0cml4ICk7XHJcblxyXG5cdFx0XHR0aGlzLmJvdW5kaW5nQm94LnVuaW9uKCBfYm94MyApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRjb21wdXRlQm91bmRpbmdTcGhlcmUoKSB7XHJcblxyXG5cdFx0Y29uc3QgZ2VvbWV0cnkgPSB0aGlzLmdlb21ldHJ5O1xyXG5cdFx0Y29uc3QgY291bnQgPSB0aGlzLmNvdW50O1xyXG5cclxuXHRcdGlmICggdGhpcy5ib3VuZGluZ1NwaGVyZSA9PT0gbnVsbCApIHtcclxuXHJcblx0XHRcdHRoaXMuYm91bmRpbmdTcGhlcmUgPSBuZXcgU3BoZXJlKCk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggZ2VvbWV0cnkuYm91bmRpbmdTcGhlcmUgPT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRnZW9tZXRyeS5jb21wdXRlQm91bmRpbmdTcGhlcmUoKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5ib3VuZGluZ1NwaGVyZS5tYWtlRW1wdHkoKTtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBjb3VudDsgaSArKyApIHtcclxuXHJcblx0XHRcdHRoaXMuZ2V0TWF0cml4QXQoIGksIF9pbnN0YW5jZUxvY2FsTWF0cml4ICk7XHJcblxyXG5cdFx0XHRfc3BoZXJlLmNvcHkoIGdlb21ldHJ5LmJvdW5kaW5nU3BoZXJlICkuYXBwbHlNYXRyaXg0KCBfaW5zdGFuY2VMb2NhbE1hdHJpeCApO1xyXG5cclxuXHRcdFx0dGhpcy5ib3VuZGluZ1NwaGVyZS51bmlvbiggX3NwaGVyZSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRjb3B5KCBzb3VyY2UsIHJlY3Vyc2l2ZSApIHtcclxuXHJcblx0XHRzdXBlci5jb3B5KCBzb3VyY2UsIHJlY3Vyc2l2ZSApO1xyXG5cclxuXHRcdHRoaXMuaW5zdGFuY2VNYXRyaXguY29weSggc291cmNlLmluc3RhbmNlTWF0cml4ICk7XHJcblxyXG5cdFx0aWYgKCBzb3VyY2UuaW5zdGFuY2VDb2xvciAhPT0gbnVsbCApIHRoaXMuaW5zdGFuY2VDb2xvciA9IHNvdXJjZS5pbnN0YW5jZUNvbG9yLmNsb25lKCk7XHJcblxyXG5cdFx0dGhpcy5jb3VudCA9IHNvdXJjZS5jb3VudDtcclxuXHJcblx0XHRpZiAoIHNvdXJjZS5ib3VuZGluZ0JveCAhPT0gbnVsbCApIHRoaXMuYm91bmRpbmdCb3ggPSBzb3VyY2UuYm91bmRpbmdCb3guY2xvbmUoKTtcclxuXHRcdGlmICggc291cmNlLmJvdW5kaW5nU3BoZXJlICE9PSBudWxsICkgdGhpcy5ib3VuZGluZ1NwaGVyZSA9IHNvdXJjZS5ib3VuZGluZ1NwaGVyZS5jbG9uZSgpO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldENvbG9yQXQoIGluZGV4LCBjb2xvciApIHtcclxuXHJcblx0XHRjb2xvci5mcm9tQXJyYXkoIHRoaXMuaW5zdGFuY2VDb2xvci5hcnJheSwgaW5kZXggKiAzICk7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0TWF0cml4QXQoIGluZGV4LCBtYXRyaXggKSB7XHJcblxyXG5cdFx0bWF0cml4LmZyb21BcnJheSggdGhpcy5pbnN0YW5jZU1hdHJpeC5hcnJheSwgaW5kZXggKiAxNiApO1xyXG5cclxuXHR9XHJcblxyXG5cdHJheWNhc3QoIHJheWNhc3RlciwgaW50ZXJzZWN0cyApIHtcclxuXHJcblx0XHRjb25zdCBtYXRyaXhXb3JsZCA9IHRoaXMubWF0cml4V29ybGQ7XHJcblx0XHRjb25zdCByYXljYXN0VGltZXMgPSB0aGlzLmNvdW50O1xyXG5cclxuXHRcdF9tZXNoLmdlb21ldHJ5ID0gdGhpcy5nZW9tZXRyeTtcclxuXHRcdF9tZXNoLm1hdGVyaWFsID0gdGhpcy5tYXRlcmlhbDtcclxuXHJcblx0XHRpZiAoIF9tZXNoLm1hdGVyaWFsID09PSB1bmRlZmluZWQgKSByZXR1cm47XHJcblxyXG5cdFx0Ly8gdGVzdCB3aXRoIGJvdW5kaW5nIHNwaGVyZSBmaXJzdFxyXG5cclxuXHRcdGlmICggdGhpcy5ib3VuZGluZ1NwaGVyZSA9PT0gbnVsbCApIHRoaXMuY29tcHV0ZUJvdW5kaW5nU3BoZXJlKCk7XHJcblxyXG5cdFx0X3NwaGVyZS5jb3B5KCB0aGlzLmJvdW5kaW5nU3BoZXJlICk7XHJcblx0XHRfc3BoZXJlLmFwcGx5TWF0cml4NCggbWF0cml4V29ybGQgKTtcclxuXHJcblx0XHRpZiAoIHJheWNhc3Rlci5yYXkuaW50ZXJzZWN0c1NwaGVyZSggX3NwaGVyZSApID09PSBmYWxzZSApIHJldHVybjtcclxuXHJcblx0XHQvLyBub3cgdGVzdCBlYWNoIGluc3RhbmNlXHJcblxyXG5cdFx0Zm9yICggbGV0IGluc3RhbmNlSWQgPSAwOyBpbnN0YW5jZUlkIDwgcmF5Y2FzdFRpbWVzOyBpbnN0YW5jZUlkICsrICkge1xyXG5cclxuXHRcdFx0Ly8gY2FsY3VsYXRlIHRoZSB3b3JsZCBtYXRyaXggZm9yIGVhY2ggaW5zdGFuY2VcclxuXHJcblx0XHRcdHRoaXMuZ2V0TWF0cml4QXQoIGluc3RhbmNlSWQsIF9pbnN0YW5jZUxvY2FsTWF0cml4ICk7XHJcblxyXG5cdFx0XHRfaW5zdGFuY2VXb3JsZE1hdHJpeC5tdWx0aXBseU1hdHJpY2VzKCBtYXRyaXhXb3JsZCwgX2luc3RhbmNlTG9jYWxNYXRyaXggKTtcclxuXHJcblx0XHRcdC8vIHRoZSBtZXNoIHJlcHJlc2VudHMgdGhpcyBzaW5nbGUgaW5zdGFuY2VcclxuXHJcblx0XHRcdF9tZXNoLm1hdHJpeFdvcmxkID0gX2luc3RhbmNlV29ybGRNYXRyaXg7XHJcblxyXG5cdFx0XHRfbWVzaC5yYXljYXN0KCByYXljYXN0ZXIsIF9pbnN0YW5jZUludGVyc2VjdHMgKTtcclxuXHJcblx0XHRcdC8vIHByb2Nlc3MgdGhlIHJlc3VsdCBvZiByYXljYXN0XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBfaW5zdGFuY2VJbnRlcnNlY3RzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IGludGVyc2VjdCA9IF9pbnN0YW5jZUludGVyc2VjdHNbIGkgXTtcclxuXHRcdFx0XHRpbnRlcnNlY3QuaW5zdGFuY2VJZCA9IGluc3RhbmNlSWQ7XHJcblx0XHRcdFx0aW50ZXJzZWN0Lm9iamVjdCA9IHRoaXM7XHJcblx0XHRcdFx0aW50ZXJzZWN0cy5wdXNoKCBpbnRlcnNlY3QgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdF9pbnN0YW5jZUludGVyc2VjdHMubGVuZ3RoID0gMDtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0c2V0Q29sb3JBdCggaW5kZXgsIGNvbG9yICkge1xyXG5cclxuXHRcdGlmICggdGhpcy5pbnN0YW5jZUNvbG9yID09PSBudWxsICkge1xyXG5cclxuXHRcdFx0dGhpcy5pbnN0YW5jZUNvbG9yID0gbmV3IEluc3RhbmNlZEJ1ZmZlckF0dHJpYnV0ZSggbmV3IEZsb2F0MzJBcnJheSggdGhpcy5pbnN0YW5jZU1hdHJpeC5jb3VudCAqIDMgKSwgMyApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb2xvci50b0FycmF5KCB0aGlzLmluc3RhbmNlQ29sb3IuYXJyYXksIGluZGV4ICogMyApO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldE1hdHJpeEF0KCBpbmRleCwgbWF0cml4ICkge1xyXG5cclxuXHRcdG1hdHJpeC50b0FycmF5KCB0aGlzLmluc3RhbmNlTWF0cml4LmFycmF5LCBpbmRleCAqIDE2ICk7XHJcblxyXG5cdH1cclxuXHJcblx0dXBkYXRlTW9ycGhUYXJnZXRzKCkge1xyXG5cclxuXHR9XHJcblxyXG5cdGRpc3Bvc2UoKSB7XHJcblxyXG5cdFx0dGhpcy5kaXNwYXRjaEV2ZW50KCB7IHR5cGU6ICdkaXNwb3NlJyB9ICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IEluc3RhbmNlZE1lc2ggfTtcclxuIiwiaW1wb3J0IHsgQnVmZmVyQXR0cmlidXRlIH0gZnJvbSAnLi4vY29yZS9CdWZmZXJBdHRyaWJ1dGUuanMnO1xyXG5pbXBvcnQgeyBCdWZmZXJHZW9tZXRyeSB9IGZyb20gJy4uL2NvcmUvQnVmZmVyR2VvbWV0cnkuanMnO1xyXG5pbXBvcnQgeyBEYXRhVGV4dHVyZSB9IGZyb20gJy4uL3RleHR1cmVzL0RhdGFUZXh0dXJlLmpzJztcclxuaW1wb3J0IHsgRmxvYXRUeXBlIH0gZnJvbSAnLi4vY29uc3RhbnRzLmpzJztcclxuaW1wb3J0IHsgTWF0cml4NCB9IGZyb20gJy4uL21hdGgvTWF0cml4NC5qcyc7XHJcbmltcG9ydCB7IE1lc2ggfSBmcm9tICcuL01lc2guanMnO1xyXG5pbXBvcnQgeyBSR0JBRm9ybWF0IH0gZnJvbSAnLi4vY29uc3RhbnRzLmpzJztcclxuaW1wb3J0IHsgQm94MyB9IGZyb20gJy4uL21hdGgvQm94My5qcyc7XHJcbmltcG9ydCB7IFNwaGVyZSB9IGZyb20gJy4uL21hdGgvU3BoZXJlLmpzJztcclxuaW1wb3J0IHsgRnJ1c3R1bSB9IGZyb20gJy4uL21hdGgvRnJ1c3R1bS5qcyc7XHJcbmltcG9ydCB7IFZlY3RvcjMgfSBmcm9tICcuLi9tYXRoL1ZlY3RvcjMuanMnO1xyXG5cclxuZnVuY3Rpb24gc29ydE9wYXF1ZSggYSwgYiApIHtcclxuXHJcblx0cmV0dXJuIGEueiAtIGIuejtcclxuXHJcbn1cclxuXHJcbmZ1bmN0aW9uIHNvcnRUcmFuc3BhcmVudCggYSwgYiApIHtcclxuXHJcblx0cmV0dXJuIGIueiAtIGEuejtcclxuXHJcbn1cclxuXHJcbmNsYXNzIE11bHRpRHJhd1JlbmRlckxpc3Qge1xyXG5cclxuXHRjb25zdHJ1Y3RvcigpIHtcclxuXHJcblx0XHR0aGlzLmluZGV4ID0gMDtcclxuXHRcdHRoaXMucG9vbCA9IFtdO1xyXG5cdFx0dGhpcy5saXN0ID0gW107XHJcblxyXG5cdH1cclxuXHJcblx0cHVzaCggZHJhd1JhbmdlLCB6ICkge1xyXG5cclxuXHRcdGNvbnN0IHBvb2wgPSB0aGlzLnBvb2w7XHJcblx0XHRjb25zdCBsaXN0ID0gdGhpcy5saXN0O1xyXG5cdFx0aWYgKCB0aGlzLmluZGV4ID49IHBvb2wubGVuZ3RoICkge1xyXG5cclxuXHRcdFx0cG9vbC5wdXNoKCB7XHJcblxyXG5cdFx0XHRcdHN0YXJ0OiAtIDEsXHJcblx0XHRcdFx0Y291bnQ6IC0gMSxcclxuXHRcdFx0XHR6OiAtIDEsXHJcblxyXG5cdFx0XHR9ICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGNvbnN0IGl0ZW0gPSBwb29sWyB0aGlzLmluZGV4IF07XHJcblx0XHRsaXN0LnB1c2goIGl0ZW0gKTtcclxuXHRcdHRoaXMuaW5kZXggKys7XHJcblxyXG5cdFx0aXRlbS5zdGFydCA9IGRyYXdSYW5nZS5zdGFydDtcclxuXHRcdGl0ZW0uY291bnQgPSBkcmF3UmFuZ2UuY291bnQ7XHJcblx0XHRpdGVtLnogPSB6O1xyXG5cclxuXHR9XHJcblxyXG5cdHJlc2V0KCkge1xyXG5cclxuXHRcdHRoaXMubGlzdC5sZW5ndGggPSAwO1xyXG5cdFx0dGhpcy5pbmRleCA9IDA7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmNvbnN0IElEX0FUVFJfTkFNRSA9ICdiYXRjaElkJztcclxuY29uc3QgX21hdHJpeCA9IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDQoKTtcclxuY29uc3QgX2ludk1hdHJpeFdvcmxkID0gLypAX19QVVJFX18qLyBuZXcgTWF0cml4NCgpO1xyXG5jb25zdCBfaWRlbnRpdHlNYXRyaXggPSAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXg0KCk7XHJcbmNvbnN0IF9wcm9qU2NyZWVuTWF0cml4ID0gLypAX19QVVJFX18qLyBuZXcgTWF0cml4NCgpO1xyXG5jb25zdCBfZnJ1c3R1bSA9IC8qQF9fUFVSRV9fKi8gbmV3IEZydXN0dW0oKTtcclxuY29uc3QgX2JveCA9IC8qQF9fUFVSRV9fKi8gbmV3IEJveDMoKTtcclxuY29uc3QgX3NwaGVyZSA9IC8qQF9fUFVSRV9fKi8gbmV3IFNwaGVyZSgpO1xyXG5jb25zdCBfdmVjdG9yID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5jb25zdCBfcmVuZGVyTGlzdCA9IC8qQF9fUFVSRV9fKi8gbmV3IE11bHRpRHJhd1JlbmRlckxpc3QoKTtcclxuY29uc3QgX21lc2ggPSAvKkBfX1BVUkVfXyovIG5ldyBNZXNoKCk7XHJcbmNvbnN0IF9iYXRjaEludGVyc2VjdHMgPSBbXTtcclxuXHJcbi8vIEBUT0RPOiBTa2lubmVkTWVzaCBzdXBwb3J0P1xyXG4vLyBAVE9ETzogZ2VvbWV0cnkuZ3JvdXBzIHN1cHBvcnQ/XHJcbi8vIEBUT0RPOiBnZW9tZXRyeS5kcmF3UmFuZ2Ugc3VwcG9ydD9cclxuLy8gQFRPRE86IGdlb21ldHJ5Lm1vcnBoQXR0cmlidXRlcyBzdXBwb3J0P1xyXG4vLyBAVE9ETzogU3VwcG9ydCB1bmlmb3JtIHBhcmFtZXRlciBwZXIgZ2VvbWV0cnlcclxuLy8gQFRPRE86IEFkZCBhbiBcIm9wdGltaXplXCIgZnVuY3Rpb24gdG8gcGFjayBnZW9tZXRyeSBhbmQgcmVtb3ZlIGRhdGEgZ2Fwc1xyXG5cclxuLy8gY29waWVzIGRhdGEgZnJvbSBhdHRyaWJ1dGUgXCJzcmNcIiBpbnRvIFwidGFyZ2V0XCIgc3RhcnRpbmcgYXQgXCJ0YXJnZXRPZmZzZXRcIlxyXG5mdW5jdGlvbiBjb3B5QXR0cmlidXRlRGF0YSggc3JjLCB0YXJnZXQsIHRhcmdldE9mZnNldCA9IDAgKSB7XHJcblxyXG5cdGNvbnN0IGl0ZW1TaXplID0gdGFyZ2V0Lml0ZW1TaXplO1xyXG5cdGlmICggc3JjLmlzSW50ZXJsZWF2ZWRCdWZmZXJBdHRyaWJ1dGUgfHwgc3JjLmFycmF5LmNvbnN0cnVjdG9yICE9PSB0YXJnZXQuYXJyYXkuY29uc3RydWN0b3IgKSB7XHJcblxyXG5cdFx0Ly8gdXNlIHRoZSBjb21wb25lbnQgZ2V0dGVycyBhbmQgc2V0dGVycyBpZiB0aGUgYXJyYXkgZGF0YSBjYW5ub3RcclxuXHRcdC8vIGJlIGNvcGllZCBkaXJlY3RseVxyXG5cdFx0Y29uc3QgdmVydGV4Q291bnQgPSBzcmMuY291bnQ7XHJcblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCB2ZXJ0ZXhDb3VudDsgaSArKyApIHtcclxuXHJcblx0XHRcdGZvciAoIGxldCBjID0gMDsgYyA8IGl0ZW1TaXplOyBjICsrICkge1xyXG5cclxuXHRcdFx0XHR0YXJnZXQuc2V0Q29tcG9uZW50KCBpICsgdGFyZ2V0T2Zmc2V0LCBjLCBzcmMuZ2V0Q29tcG9uZW50KCBpLCBjICkgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdH0gZWxzZSB7XHJcblxyXG5cdFx0Ly8gZmFzdGVyIGNvcHkgYXBwcm9hY2ggdXNpbmcgdHlwZWQgYXJyYXkgc2V0IGZ1bmN0aW9uXHJcblx0XHR0YXJnZXQuYXJyYXkuc2V0KCBzcmMuYXJyYXksIHRhcmdldE9mZnNldCAqIGl0ZW1TaXplICk7XHJcblxyXG5cdH1cclxuXHJcblx0dGFyZ2V0Lm5lZWRzVXBkYXRlID0gdHJ1ZTtcclxuXHJcbn1cclxuXHJcbmNsYXNzIEJhdGNoZWRNZXNoIGV4dGVuZHMgTWVzaCB7XHJcblxyXG5cdGdldCBtYXhHZW9tZXRyeUNvdW50KCkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLl9tYXhHZW9tZXRyeUNvdW50O1xyXG5cclxuXHR9XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBtYXhHZW9tZXRyeUNvdW50LCBtYXhWZXJ0ZXhDb3VudCwgbWF4SW5kZXhDb3VudCA9IG1heFZlcnRleENvdW50ICogMiwgbWF0ZXJpYWwgKSB7XHJcblxyXG5cdFx0c3VwZXIoIG5ldyBCdWZmZXJHZW9tZXRyeSgpLCBtYXRlcmlhbCApO1xyXG5cclxuXHRcdHRoaXMuaXNCYXRjaGVkTWVzaCA9IHRydWU7XHJcblx0XHR0aGlzLnBlck9iamVjdEZydXN0dW1DdWxsZWQgPSB0cnVlO1xyXG5cdFx0dGhpcy5zb3J0T2JqZWN0cyA9IHRydWU7XHJcblx0XHR0aGlzLmJvdW5kaW5nQm94ID0gbnVsbDtcclxuXHRcdHRoaXMuYm91bmRpbmdTcGhlcmUgPSBudWxsO1xyXG5cdFx0dGhpcy5jdXN0b21Tb3J0ID0gbnVsbDtcclxuXHJcblx0XHR0aGlzLl9kcmF3UmFuZ2VzID0gW107XHJcblx0XHR0aGlzLl9yZXNlcnZlZFJhbmdlcyA9IFtdO1xyXG5cclxuXHRcdHRoaXMuX3Zpc2liaWxpdHkgPSBbXTtcclxuXHRcdHRoaXMuX2FjdGl2ZSA9IFtdO1xyXG5cdFx0dGhpcy5fYm91bmRzID0gW107XHJcblxyXG5cdFx0dGhpcy5fbWF4R2VvbWV0cnlDb3VudCA9IG1heEdlb21ldHJ5Q291bnQ7XHJcblx0XHR0aGlzLl9tYXhWZXJ0ZXhDb3VudCA9IG1heFZlcnRleENvdW50O1xyXG5cdFx0dGhpcy5fbWF4SW5kZXhDb3VudCA9IG1heEluZGV4Q291bnQ7XHJcblxyXG5cdFx0dGhpcy5fZ2VvbWV0cnlJbml0aWFsaXplZCA9IGZhbHNlO1xyXG5cdFx0dGhpcy5fZ2VvbWV0cnlDb3VudCA9IDA7XHJcblx0XHR0aGlzLl9tdWx0aURyYXdDb3VudHMgPSBuZXcgSW50MzJBcnJheSggbWF4R2VvbWV0cnlDb3VudCApO1xyXG5cdFx0dGhpcy5fbXVsdGlEcmF3U3RhcnRzID0gbmV3IEludDMyQXJyYXkoIG1heEdlb21ldHJ5Q291bnQgKTtcclxuXHRcdHRoaXMuX211bHRpRHJhd0NvdW50ID0gMDtcclxuXHRcdHRoaXMuX3Zpc2liaWxpdHlDaGFuZ2VkID0gdHJ1ZTtcclxuXHJcblx0XHQvLyBMb2NhbCBtYXRyaXggcGVyIGdlb21ldHJ5IGJ5IHVzaW5nIGRhdGEgdGV4dHVyZVxyXG5cdFx0dGhpcy5fbWF0cmljZXNUZXh0dXJlID0gbnVsbDtcclxuXHJcblx0XHR0aGlzLl9pbml0TWF0cmljZXNUZXh0dXJlKCk7XHJcblxyXG5cdH1cclxuXHJcblx0X2luaXRNYXRyaWNlc1RleHR1cmUoKSB7XHJcblxyXG5cdFx0Ly8gbGF5b3V0ICgxIG1hdHJpeCA9IDQgcGl4ZWxzKVxyXG5cdFx0Ly8gICAgICBSR0JBIFJHQkEgUkdCQSBSR0JBICg9PiBjb2x1bW4xLCBjb2x1bW4yLCBjb2x1bW4zLCBjb2x1bW40KVxyXG5cdFx0Ly8gIHdpdGggIDh4OCAgcGl4ZWwgdGV4dHVyZSBtYXggICAxNiBtYXRyaWNlcyAqIDQgcGl4ZWxzID0gICg4ICogOClcclxuXHRcdC8vICAgICAgIDE2eDE2IHBpeGVsIHRleHR1cmUgbWF4ICAgNjQgbWF0cmljZXMgKiA0IHBpeGVscyA9ICgxNiAqIDE2KVxyXG5cdFx0Ly8gICAgICAgMzJ4MzIgcGl4ZWwgdGV4dHVyZSBtYXggIDI1NiBtYXRyaWNlcyAqIDQgcGl4ZWxzID0gKDMyICogMzIpXHJcblx0XHQvLyAgICAgICA2NHg2NCBwaXhlbCB0ZXh0dXJlIG1heCAxMDI0IG1hdHJpY2VzICogNCBwaXhlbHMgPSAoNjQgKiA2NClcclxuXHJcblx0XHRsZXQgc2l6ZSA9IE1hdGguc3FydCggdGhpcy5fbWF4R2VvbWV0cnlDb3VudCAqIDQgKTsgLy8gNCBwaXhlbHMgbmVlZGVkIGZvciAxIG1hdHJpeFxyXG5cdFx0c2l6ZSA9IE1hdGguY2VpbCggc2l6ZSAvIDQgKSAqIDQ7XHJcblx0XHRzaXplID0gTWF0aC5tYXgoIHNpemUsIDQgKTtcclxuXHJcblx0XHRjb25zdCBtYXRyaWNlc0FycmF5ID0gbmV3IEZsb2F0MzJBcnJheSggc2l6ZSAqIHNpemUgKiA0ICk7IC8vIDQgZmxvYXRzIHBlciBSR0JBIHBpeGVsXHJcblx0XHRjb25zdCBtYXRyaWNlc1RleHR1cmUgPSBuZXcgRGF0YVRleHR1cmUoIG1hdHJpY2VzQXJyYXksIHNpemUsIHNpemUsIFJHQkFGb3JtYXQsIEZsb2F0VHlwZSApO1xyXG5cclxuXHRcdHRoaXMuX21hdHJpY2VzVGV4dHVyZSA9IG1hdHJpY2VzVGV4dHVyZTtcclxuXHJcblx0fVxyXG5cclxuXHRfaW5pdGlhbGl6ZUdlb21ldHJ5KCByZWZlcmVuY2UgKSB7XHJcblxyXG5cdFx0Y29uc3QgZ2VvbWV0cnkgPSB0aGlzLmdlb21ldHJ5O1xyXG5cdFx0Y29uc3QgbWF4VmVydGV4Q291bnQgPSB0aGlzLl9tYXhWZXJ0ZXhDb3VudDtcclxuXHRcdGNvbnN0IG1heEdlb21ldHJ5Q291bnQgPSB0aGlzLl9tYXhHZW9tZXRyeUNvdW50O1xyXG5cdFx0Y29uc3QgbWF4SW5kZXhDb3VudCA9IHRoaXMuX21heEluZGV4Q291bnQ7XHJcblx0XHRpZiAoIHRoaXMuX2dlb21ldHJ5SW5pdGlhbGl6ZWQgPT09IGZhbHNlICkge1xyXG5cclxuXHRcdFx0Zm9yICggY29uc3QgYXR0cmlidXRlTmFtZSBpbiByZWZlcmVuY2UuYXR0cmlidXRlcyApIHtcclxuXHJcblx0XHRcdFx0Y29uc3Qgc3JjQXR0cmlidXRlID0gcmVmZXJlbmNlLmdldEF0dHJpYnV0ZSggYXR0cmlidXRlTmFtZSApO1xyXG5cdFx0XHRcdGNvbnN0IHsgYXJyYXksIGl0ZW1TaXplLCBub3JtYWxpemVkIH0gPSBzcmNBdHRyaWJ1dGU7XHJcblxyXG5cdFx0XHRcdGNvbnN0IGRzdEFycmF5ID0gbmV3IGFycmF5LmNvbnN0cnVjdG9yKCBtYXhWZXJ0ZXhDb3VudCAqIGl0ZW1TaXplICk7XHJcblx0XHRcdFx0Y29uc3QgZHN0QXR0cmlidXRlID0gbmV3IHNyY0F0dHJpYnV0ZS5jb25zdHJ1Y3RvciggZHN0QXJyYXksIGl0ZW1TaXplLCBub3JtYWxpemVkICk7XHJcblx0XHRcdFx0ZHN0QXR0cmlidXRlLnNldFVzYWdlKCBzcmNBdHRyaWJ1dGUudXNhZ2UgKTtcclxuXHJcblx0XHRcdFx0Z2VvbWV0cnkuc2V0QXR0cmlidXRlKCBhdHRyaWJ1dGVOYW1lLCBkc3RBdHRyaWJ1dGUgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGlmICggcmVmZXJlbmNlLmdldEluZGV4KCkgIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IGluZGV4QXJyYXkgPSBtYXhWZXJ0ZXhDb3VudCA+IDY1NTM2XHJcblx0XHRcdFx0XHQ/IG5ldyBVaW50MzJBcnJheSggbWF4SW5kZXhDb3VudCApXHJcblx0XHRcdFx0XHQ6IG5ldyBVaW50MTZBcnJheSggbWF4SW5kZXhDb3VudCApO1xyXG5cclxuXHRcdFx0XHRnZW9tZXRyeS5zZXRJbmRleCggbmV3IEJ1ZmZlckF0dHJpYnV0ZSggaW5kZXhBcnJheSwgMSApICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRjb25zdCBpZEFycmF5ID0gbWF4R2VvbWV0cnlDb3VudCA+IDY1NTM2XHJcblx0XHRcdFx0PyBuZXcgVWludDMyQXJyYXkoIG1heFZlcnRleENvdW50IClcclxuXHRcdFx0XHQ6IG5ldyBVaW50MTZBcnJheSggbWF4VmVydGV4Q291bnQgKTtcclxuXHRcdFx0Z2VvbWV0cnkuc2V0QXR0cmlidXRlKCBJRF9BVFRSX05BTUUsIG5ldyBCdWZmZXJBdHRyaWJ1dGUoIGlkQXJyYXksIDEgKSApO1xyXG5cclxuXHRcdFx0dGhpcy5fZ2VvbWV0cnlJbml0aWFsaXplZCA9IHRydWU7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdC8vIE1ha2Ugc3VyZSB0aGUgZ2VvbWV0cnkgaXMgY29tcGF0aWJsZSB3aXRoIHRoZSBleGlzdGluZyBjb21iaW5lZCBnZW9tZXRyeSBhdHJpYnV0ZXNcclxuXHRfdmFsaWRhdGVHZW9tZXRyeSggZ2VvbWV0cnkgKSB7XHJcblxyXG5cdFx0Ly8gY2hlY2sgdGhhdCB0aGUgZ2VvbWV0cnkgZG9lc24ndCBoYXZlIGEgdmVyc2lvbiBvZiBvdXIgcmVzZXJ2ZWQgaWQgYXR0cmlidXRlXHJcblx0XHRpZiAoIGdlb21ldHJ5LmdldEF0dHJpYnV0ZSggSURfQVRUUl9OQU1FICkgKSB7XHJcblxyXG5cdFx0XHR0aHJvdyBuZXcgRXJyb3IoIGBCYXRjaGVkTWVzaDogR2VvbWV0cnkgY2Fubm90IHVzZSBhdHRyaWJ1dGUgXCIkeyBJRF9BVFRSX05BTUUgfVwiYCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvLyBjaGVjayB0byBlbnN1cmUgdGhlIGdlb21ldHJpZXMgYXJlIHVzaW5nIGNvbnNpc3RlbnQgYXR0cmlidXRlcyBhbmQgaW5kaWNlc1xyXG5cdFx0Y29uc3QgYmF0Y2hHZW9tZXRyeSA9IHRoaXMuZ2VvbWV0cnk7XHJcblx0XHRpZiAoIEJvb2xlYW4oIGdlb21ldHJ5LmdldEluZGV4KCkgKSAhPT0gQm9vbGVhbiggYmF0Y2hHZW9tZXRyeS5nZXRJbmRleCgpICkgKSB7XHJcblxyXG5cdFx0XHR0aHJvdyBuZXcgRXJyb3IoICdCYXRjaGVkTWVzaDogQWxsIGdlb21ldHJpZXMgbXVzdCBjb25zaXN0ZW50bHkgaGF2ZSBcImluZGV4XCIuJyApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRmb3IgKCBjb25zdCBhdHRyaWJ1dGVOYW1lIGluIGJhdGNoR2VvbWV0cnkuYXR0cmlidXRlcyApIHtcclxuXHJcblx0XHRcdGlmICggYXR0cmlidXRlTmFtZSA9PT0gSURfQVRUUl9OQU1FICkge1xyXG5cclxuXHRcdFx0XHRjb250aW51ZTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGlmICggISBnZW9tZXRyeS5oYXNBdHRyaWJ1dGUoIGF0dHJpYnV0ZU5hbWUgKSApIHtcclxuXHJcblx0XHRcdFx0dGhyb3cgbmV3IEVycm9yKCBgQmF0Y2hlZE1lc2g6IEFkZGVkIGdlb21ldHJ5IG1pc3NpbmcgXCIkeyBhdHRyaWJ1dGVOYW1lIH1cIi4gQWxsIGdlb21ldHJpZXMgbXVzdCBoYXZlIGNvbnNpc3RlbnQgYXR0cmlidXRlcy5gICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRjb25zdCBzcmNBdHRyaWJ1dGUgPSBnZW9tZXRyeS5nZXRBdHRyaWJ1dGUoIGF0dHJpYnV0ZU5hbWUgKTtcclxuXHRcdFx0Y29uc3QgZHN0QXR0cmlidXRlID0gYmF0Y2hHZW9tZXRyeS5nZXRBdHRyaWJ1dGUoIGF0dHJpYnV0ZU5hbWUgKTtcclxuXHRcdFx0aWYgKCBzcmNBdHRyaWJ1dGUuaXRlbVNpemUgIT09IGRzdEF0dHJpYnV0ZS5pdGVtU2l6ZSB8fCBzcmNBdHRyaWJ1dGUubm9ybWFsaXplZCAhPT0gZHN0QXR0cmlidXRlLm5vcm1hbGl6ZWQgKSB7XHJcblxyXG5cdFx0XHRcdHRocm93IG5ldyBFcnJvciggJ0JhdGNoZWRNZXNoOiBBbGwgYXR0cmlidXRlcyBtdXN0IGhhdmUgYSBjb25zaXN0ZW50IGl0ZW1TaXplIGFuZCBub3JtYWxpemVkIHZhbHVlLicgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0c2V0Q3VzdG9tU29ydCggZnVuYyApIHtcclxuXHJcblx0XHR0aGlzLmN1c3RvbVNvcnQgPSBmdW5jO1xyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Y29tcHV0ZUJvdW5kaW5nQm94KCkge1xyXG5cclxuXHRcdGlmICggdGhpcy5ib3VuZGluZ0JveCA9PT0gbnVsbCApIHtcclxuXHJcblx0XHRcdHRoaXMuYm91bmRpbmdCb3ggPSBuZXcgQm94MygpO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCBnZW9tZXRyeUNvdW50ID0gdGhpcy5fZ2VvbWV0cnlDb3VudDtcclxuXHRcdGNvbnN0IGJvdW5kaW5nQm94ID0gdGhpcy5ib3VuZGluZ0JveDtcclxuXHRcdGNvbnN0IGFjdGl2ZSA9IHRoaXMuX2FjdGl2ZTtcclxuXHJcblx0XHRib3VuZGluZ0JveC5tYWtlRW1wdHkoKTtcclxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IGdlb21ldHJ5Q291bnQ7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRpZiAoIGFjdGl2ZVsgaSBdID09PSBmYWxzZSApIGNvbnRpbnVlO1xyXG5cclxuXHRcdFx0dGhpcy5nZXRNYXRyaXhBdCggaSwgX21hdHJpeCApO1xyXG5cdFx0XHR0aGlzLmdldEJvdW5kaW5nQm94QXQoIGksIF9ib3ggKS5hcHBseU1hdHJpeDQoIF9tYXRyaXggKTtcclxuXHRcdFx0Ym91bmRpbmdCb3gudW5pb24oIF9ib3ggKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0Y29tcHV0ZUJvdW5kaW5nU3BoZXJlKCkge1xyXG5cclxuXHRcdGlmICggdGhpcy5ib3VuZGluZ1NwaGVyZSA9PT0gbnVsbCApIHtcclxuXHJcblx0XHRcdHRoaXMuYm91bmRpbmdTcGhlcmUgPSBuZXcgU3BoZXJlKCk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGNvbnN0IGdlb21ldHJ5Q291bnQgPSB0aGlzLl9nZW9tZXRyeUNvdW50O1xyXG5cdFx0Y29uc3QgYm91bmRpbmdTcGhlcmUgPSB0aGlzLmJvdW5kaW5nU3BoZXJlO1xyXG5cdFx0Y29uc3QgYWN0aXZlID0gdGhpcy5fYWN0aXZlO1xyXG5cclxuXHRcdGJvdW5kaW5nU3BoZXJlLm1ha2VFbXB0eSgpO1xyXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgZ2VvbWV0cnlDb3VudDsgaSArKyApIHtcclxuXHJcblx0XHRcdGlmICggYWN0aXZlWyBpIF0gPT09IGZhbHNlICkgY29udGludWU7XHJcblxyXG5cdFx0XHR0aGlzLmdldE1hdHJpeEF0KCBpLCBfbWF0cml4ICk7XHJcblx0XHRcdHRoaXMuZ2V0Qm91bmRpbmdTcGhlcmVBdCggaSwgX3NwaGVyZSApLmFwcGx5TWF0cml4NCggX21hdHJpeCApO1xyXG5cdFx0XHRib3VuZGluZ1NwaGVyZS51bmlvbiggX3NwaGVyZSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRhZGRHZW9tZXRyeSggZ2VvbWV0cnksIHZlcnRleENvdW50ID0gLSAxLCBpbmRleENvdW50ID0gLSAxICkge1xyXG5cclxuXHRcdHRoaXMuX2luaXRpYWxpemVHZW9tZXRyeSggZ2VvbWV0cnkgKTtcclxuXHJcblx0XHR0aGlzLl92YWxpZGF0ZUdlb21ldHJ5KCBnZW9tZXRyeSApO1xyXG5cclxuXHRcdC8vIGVuc3VyZSB3ZSdyZSBub3Qgb3ZlciBnZW9tZXRyeVxyXG5cdFx0aWYgKCB0aGlzLl9nZW9tZXRyeUNvdW50ID49IHRoaXMuX21heEdlb21ldHJ5Q291bnQgKSB7XHJcblxyXG5cdFx0XHR0aHJvdyBuZXcgRXJyb3IoICdCYXRjaGVkTWVzaDogTWF4aW11bSBnZW9tZXRyeSBjb3VudCByZWFjaGVkLicgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gZ2V0IHRoZSBuZWNlc3NhcnkgcmFuZ2UgZm8gdGhlIGdlb21ldHJ5XHJcblx0XHRjb25zdCByZXNlcnZlZFJhbmdlID0ge1xyXG5cdFx0XHR2ZXJ0ZXhTdGFydDogLSAxLFxyXG5cdFx0XHR2ZXJ0ZXhDb3VudDogLSAxLFxyXG5cdFx0XHRpbmRleFN0YXJ0OiAtIDEsXHJcblx0XHRcdGluZGV4Q291bnQ6IC0gMSxcclxuXHRcdH07XHJcblxyXG5cdFx0bGV0IGxhc3RSYW5nZSA9IG51bGw7XHJcblx0XHRjb25zdCByZXNlcnZlZFJhbmdlcyA9IHRoaXMuX3Jlc2VydmVkUmFuZ2VzO1xyXG5cdFx0Y29uc3QgZHJhd1JhbmdlcyA9IHRoaXMuX2RyYXdSYW5nZXM7XHJcblx0XHRjb25zdCBib3VuZHMgPSB0aGlzLl9ib3VuZHM7XHJcblx0XHRpZiAoIHRoaXMuX2dlb21ldHJ5Q291bnQgIT09IDAgKSB7XHJcblxyXG5cdFx0XHRsYXN0UmFuZ2UgPSByZXNlcnZlZFJhbmdlc1sgcmVzZXJ2ZWRSYW5nZXMubGVuZ3RoIC0gMSBdO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHZlcnRleENvdW50ID09PSAtIDEgKSB7XHJcblxyXG5cdFx0XHRyZXNlcnZlZFJhbmdlLnZlcnRleENvdW50ID0gZ2VvbWV0cnkuZ2V0QXR0cmlidXRlKCAncG9zaXRpb24nICkuY291bnQ7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdHJlc2VydmVkUmFuZ2UudmVydGV4Q291bnQgPSB2ZXJ0ZXhDb3VudDtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBsYXN0UmFuZ2UgPT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRyZXNlcnZlZFJhbmdlLnZlcnRleFN0YXJ0ID0gMDtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0cmVzZXJ2ZWRSYW5nZS52ZXJ0ZXhTdGFydCA9IGxhc3RSYW5nZS52ZXJ0ZXhTdGFydCArIGxhc3RSYW5nZS52ZXJ0ZXhDb3VudDtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Y29uc3QgaW5kZXggPSBnZW9tZXRyeS5nZXRJbmRleCgpO1xyXG5cdFx0Y29uc3QgaGFzSW5kZXggPSBpbmRleCAhPT0gbnVsbDtcclxuXHRcdGlmICggaGFzSW5kZXggKSB7XHJcblxyXG5cdFx0XHRpZiAoIGluZGV4Q291bnRcdD09PSAtIDEgKSB7XHJcblxyXG5cdFx0XHRcdHJlc2VydmVkUmFuZ2UuaW5kZXhDb3VudCA9IGluZGV4LmNvdW50O1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0cmVzZXJ2ZWRSYW5nZS5pbmRleENvdW50ID0gaW5kZXhDb3VudDtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGlmICggbGFzdFJhbmdlID09PSBudWxsICkge1xyXG5cclxuXHRcdFx0XHRyZXNlcnZlZFJhbmdlLmluZGV4U3RhcnQgPSAwO1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0cmVzZXJ2ZWRSYW5nZS5pbmRleFN0YXJ0ID0gbGFzdFJhbmdlLmluZGV4U3RhcnQgKyBsYXN0UmFuZ2UuaW5kZXhDb3VudDtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKFxyXG5cdFx0XHRyZXNlcnZlZFJhbmdlLmluZGV4U3RhcnQgIT09IC0gMSAmJlxyXG5cdFx0XHRyZXNlcnZlZFJhbmdlLmluZGV4U3RhcnQgKyByZXNlcnZlZFJhbmdlLmluZGV4Q291bnQgPiB0aGlzLl9tYXhJbmRleENvdW50IHx8XHJcblx0XHRcdHJlc2VydmVkUmFuZ2UudmVydGV4U3RhcnQgKyByZXNlcnZlZFJhbmdlLnZlcnRleENvdW50ID4gdGhpcy5fbWF4VmVydGV4Q291bnRcclxuXHRcdCkge1xyXG5cclxuXHRcdFx0dGhyb3cgbmV3IEVycm9yKCAnQmF0Y2hlZE1lc2g6IFJlc2VydmVkIHNwYWNlIHJlcXVlc3QgZXhjZWVkcyB0aGUgbWF4aW11bSBidWZmZXIgc2l6ZS4nICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGNvbnN0IHZpc2liaWxpdHkgPSB0aGlzLl92aXNpYmlsaXR5O1xyXG5cdFx0Y29uc3QgYWN0aXZlID0gdGhpcy5fYWN0aXZlO1xyXG5cdFx0Y29uc3QgbWF0cmljZXNUZXh0dXJlID0gdGhpcy5fbWF0cmljZXNUZXh0dXJlO1xyXG5cdFx0Y29uc3QgbWF0cmljZXNBcnJheSA9IHRoaXMuX21hdHJpY2VzVGV4dHVyZS5pbWFnZS5kYXRhO1xyXG5cclxuXHRcdC8vIHB1c2ggbmV3IHZpc2liaWxpdHkgc3RhdGVzXHJcblx0XHR2aXNpYmlsaXR5LnB1c2goIHRydWUgKTtcclxuXHRcdGFjdGl2ZS5wdXNoKCB0cnVlICk7XHJcblxyXG5cdFx0Ly8gdXBkYXRlIGlkXHJcblx0XHRjb25zdCBnZW9tZXRyeUlkID0gdGhpcy5fZ2VvbWV0cnlDb3VudDtcclxuXHRcdHRoaXMuX2dlb21ldHJ5Q291bnQgKys7XHJcblxyXG5cdFx0Ly8gaW5pdGlhbGl6ZSBtYXRyaXggaW5mb3JtYXRpb25cclxuXHRcdF9pZGVudGl0eU1hdHJpeC50b0FycmF5KCBtYXRyaWNlc0FycmF5LCBnZW9tZXRyeUlkICogMTYgKTtcclxuXHRcdG1hdHJpY2VzVGV4dHVyZS5uZWVkc1VwZGF0ZSA9IHRydWU7XHJcblxyXG5cdFx0Ly8gYWRkIHRoZSByZXNlcnZlZCByYW5nZSBhbmQgZHJhdyByYW5nZSBvYmplY3RzXHJcblx0XHRyZXNlcnZlZFJhbmdlcy5wdXNoKCByZXNlcnZlZFJhbmdlICk7XHJcblx0XHRkcmF3UmFuZ2VzLnB1c2goIHtcclxuXHRcdFx0c3RhcnQ6IGhhc0luZGV4ID8gcmVzZXJ2ZWRSYW5nZS5pbmRleFN0YXJ0IDogcmVzZXJ2ZWRSYW5nZS52ZXJ0ZXhTdGFydCxcclxuXHRcdFx0Y291bnQ6IC0gMVxyXG5cdFx0fSApO1xyXG5cdFx0Ym91bmRzLnB1c2goIHtcclxuXHRcdFx0Ym94SW5pdGlhbGl6ZWQ6IGZhbHNlLFxyXG5cdFx0XHRib3g6IG5ldyBCb3gzKCksXHJcblxyXG5cdFx0XHRzcGhlcmVJbml0aWFsaXplZDogZmFsc2UsXHJcblx0XHRcdHNwaGVyZTogbmV3IFNwaGVyZSgpXHJcblx0XHR9ICk7XHJcblxyXG5cdFx0Ly8gc2V0IHRoZSBpZCBmb3IgdGhlIGdlb21ldHJ5XHJcblx0XHRjb25zdCBpZEF0dHJpYnV0ZSA9IHRoaXMuZ2VvbWV0cnkuZ2V0QXR0cmlidXRlKCBJRF9BVFRSX05BTUUgKTtcclxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHJlc2VydmVkUmFuZ2UudmVydGV4Q291bnQ7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRpZEF0dHJpYnV0ZS5zZXRYKCByZXNlcnZlZFJhbmdlLnZlcnRleFN0YXJ0ICsgaSwgZ2VvbWV0cnlJZCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZEF0dHJpYnV0ZS5uZWVkc1VwZGF0ZSA9IHRydWU7XHJcblxyXG5cdFx0Ly8gdXBkYXRlIHRoZSBnZW9tZXRyeVxyXG5cdFx0dGhpcy5zZXRHZW9tZXRyeUF0KCBnZW9tZXRyeUlkLCBnZW9tZXRyeSApO1xyXG5cclxuXHRcdHJldHVybiBnZW9tZXRyeUlkO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldEdlb21ldHJ5QXQoIGlkLCBnZW9tZXRyeSApIHtcclxuXHJcblx0XHRpZiAoIGlkID49IHRoaXMuX2dlb21ldHJ5Q291bnQgKSB7XHJcblxyXG5cdFx0XHR0aHJvdyBuZXcgRXJyb3IoICdCYXRjaGVkTWVzaDogTWF4aW11bSBnZW9tZXRyeSBjb3VudCByZWFjaGVkLicgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5fdmFsaWRhdGVHZW9tZXRyeSggZ2VvbWV0cnkgKTtcclxuXHJcblx0XHRjb25zdCBiYXRjaEdlb21ldHJ5ID0gdGhpcy5nZW9tZXRyeTtcclxuXHRcdGNvbnN0IGhhc0luZGV4ID0gYmF0Y2hHZW9tZXRyeS5nZXRJbmRleCgpICE9PSBudWxsO1xyXG5cdFx0Y29uc3QgZHN0SW5kZXggPSBiYXRjaEdlb21ldHJ5LmdldEluZGV4KCk7XHJcblx0XHRjb25zdCBzcmNJbmRleCA9IGdlb21ldHJ5LmdldEluZGV4KCk7XHJcblx0XHRjb25zdCByZXNlcnZlZFJhbmdlID0gdGhpcy5fcmVzZXJ2ZWRSYW5nZXNbIGlkIF07XHJcblx0XHRpZiAoXHJcblx0XHRcdGhhc0luZGV4ICYmXHJcblx0XHRcdHNyY0luZGV4LmNvdW50ID4gcmVzZXJ2ZWRSYW5nZS5pbmRleENvdW50IHx8XHJcblx0XHRcdGdlb21ldHJ5LmF0dHJpYnV0ZXMucG9zaXRpb24uY291bnQgPiByZXNlcnZlZFJhbmdlLnZlcnRleENvdW50XHJcblx0XHQpIHtcclxuXHJcblx0XHRcdHRocm93IG5ldyBFcnJvciggJ0JhdGNoZWRNZXNoOiBSZXNlcnZlZCBzcGFjZSBub3QgbGFyZ2UgZW5vdWdoIGZvciBwcm92aWRlZCBnZW9tZXRyeS4nICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIGNvcHkgZ2VvbWV0cnkgb3ZlclxyXG5cdFx0Y29uc3QgdmVydGV4U3RhcnQgPSByZXNlcnZlZFJhbmdlLnZlcnRleFN0YXJ0O1xyXG5cdFx0Y29uc3QgdmVydGV4Q291bnQgPSByZXNlcnZlZFJhbmdlLnZlcnRleENvdW50O1xyXG5cdFx0Zm9yICggY29uc3QgYXR0cmlidXRlTmFtZSBpbiBiYXRjaEdlb21ldHJ5LmF0dHJpYnV0ZXMgKSB7XHJcblxyXG5cdFx0XHRpZiAoIGF0dHJpYnV0ZU5hbWUgPT09IElEX0FUVFJfTkFNRSApIHtcclxuXHJcblx0XHRcdFx0Y29udGludWU7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyBjb3B5IGF0dHJpYnV0ZSBkYXRhXHJcblx0XHRcdGNvbnN0IHNyY0F0dHJpYnV0ZSA9IGdlb21ldHJ5LmdldEF0dHJpYnV0ZSggYXR0cmlidXRlTmFtZSApO1xyXG5cdFx0XHRjb25zdCBkc3RBdHRyaWJ1dGUgPSBiYXRjaEdlb21ldHJ5LmdldEF0dHJpYnV0ZSggYXR0cmlidXRlTmFtZSApO1xyXG5cdFx0XHRjb3B5QXR0cmlidXRlRGF0YSggc3JjQXR0cmlidXRlLCBkc3RBdHRyaWJ1dGUsIHZlcnRleFN0YXJ0ICk7XHJcblxyXG5cdFx0XHQvLyBmaWxsIHRoZSByZXN0IGluIHdpdGggemVyb2VzXHJcblx0XHRcdGNvbnN0IGl0ZW1TaXplID0gc3JjQXR0cmlidXRlLml0ZW1TaXplO1xyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IHNyY0F0dHJpYnV0ZS5jb3VudCwgbCA9IHZlcnRleENvdW50OyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgaW5kZXggPSB2ZXJ0ZXhTdGFydCArIGk7XHJcblx0XHRcdFx0Zm9yICggbGV0IGMgPSAwOyBjIDwgaXRlbVNpemU7IGMgKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0ZHN0QXR0cmlidXRlLnNldENvbXBvbmVudCggaW5kZXgsIGMsIDAgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0ZHN0QXR0cmlidXRlLm5lZWRzVXBkYXRlID0gdHJ1ZTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gY29weSBpbmRleFxyXG5cdFx0aWYgKCBoYXNJbmRleCApIHtcclxuXHJcblx0XHRcdGNvbnN0IGluZGV4U3RhcnQgPSByZXNlcnZlZFJhbmdlLmluZGV4U3RhcnQ7XHJcblxyXG5cdFx0XHQvLyBjb3B5IGluZGV4IGRhdGEgb3ZlclxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBzcmNJbmRleC5jb3VudDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0ZHN0SW5kZXguc2V0WCggaW5kZXhTdGFydCArIGksIHZlcnRleFN0YXJ0ICsgc3JjSW5kZXguZ2V0WCggaSApICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyBmaWxsIHRoZSByZXN0IGluIHdpdGggemVyb2VzXHJcblx0XHRcdGZvciAoIGxldCBpID0gc3JjSW5kZXguY291bnQsIGwgPSByZXNlcnZlZFJhbmdlLmluZGV4Q291bnQ7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRkc3RJbmRleC5zZXRYKCBpbmRleFN0YXJ0ICsgaSwgdmVydGV4U3RhcnQgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGRzdEluZGV4Lm5lZWRzVXBkYXRlID0gdHJ1ZTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gc3RvcmUgdGhlIGJvdW5kaW5nIGJveGVzXHJcblx0XHRjb25zdCBib3VuZCA9IHRoaXMuX2JvdW5kc1sgaWQgXTtcclxuXHRcdGlmICggZ2VvbWV0cnkuYm91bmRpbmdCb3ggIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRib3VuZC5ib3guY29weSggZ2VvbWV0cnkuYm91bmRpbmdCb3ggKTtcclxuXHRcdFx0Ym91bmQuYm94SW5pdGlhbGl6ZWQgPSB0cnVlO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRib3VuZC5ib3hJbml0aWFsaXplZCA9IGZhbHNlO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIGdlb21ldHJ5LmJvdW5kaW5nU3BoZXJlICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0Ym91bmQuc3BoZXJlLmNvcHkoIGdlb21ldHJ5LmJvdW5kaW5nU3BoZXJlICk7XHJcblx0XHRcdGJvdW5kLnNwaGVyZUluaXRpYWxpemVkID0gdHJ1ZTtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0Ym91bmQuc3BoZXJlSW5pdGlhbGl6ZWQgPSBmYWxzZTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gc2V0IGRyYXdSYW5nZSBjb3VudFxyXG5cdFx0Y29uc3QgZHJhd1JhbmdlID0gdGhpcy5fZHJhd1Jhbmdlc1sgaWQgXTtcclxuXHRcdGNvbnN0IHBvc0F0dHIgPSBnZW9tZXRyeS5nZXRBdHRyaWJ1dGUoICdwb3NpdGlvbicgKTtcclxuXHRcdGRyYXdSYW5nZS5jb3VudCA9IGhhc0luZGV4ID8gc3JjSW5kZXguY291bnQgOiBwb3NBdHRyLmNvdW50O1xyXG5cdFx0dGhpcy5fdmlzaWJpbGl0eUNoYW5nZWQgPSB0cnVlO1xyXG5cclxuXHRcdHJldHVybiBpZDtcclxuXHJcblx0fVxyXG5cclxuXHRkZWxldGVHZW9tZXRyeSggZ2VvbWV0cnlJZCApIHtcclxuXHJcblx0XHQvLyBOb3RlOiBVc2VyIG5lZWRzIHRvIGNhbGwgb3B0aW1pemUoKSBhZnRlcndhcmQgdG8gcGFjayB0aGUgZGF0YS5cclxuXHJcblx0XHRjb25zdCBhY3RpdmUgPSB0aGlzLl9hY3RpdmU7XHJcblx0XHRpZiAoIGdlb21ldHJ5SWQgPj0gYWN0aXZlLmxlbmd0aCB8fCBhY3RpdmVbIGdlb21ldHJ5SWQgXSA9PT0gZmFsc2UgKSB7XHJcblxyXG5cdFx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0YWN0aXZlWyBnZW9tZXRyeUlkIF0gPSBmYWxzZTtcclxuXHRcdHRoaXMuX3Zpc2liaWxpdHlDaGFuZ2VkID0gdHJ1ZTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHQvLyBnZXQgYm91bmRpbmcgYm94IGFuZCBjb21wdXRlIGl0IGlmIGl0IGRvZXNuJ3QgZXhpc3RcclxuXHRnZXRCb3VuZGluZ0JveEF0KCBpZCwgdGFyZ2V0ICkge1xyXG5cclxuXHRcdGNvbnN0IGFjdGl2ZSA9IHRoaXMuX2FjdGl2ZTtcclxuXHRcdGlmICggYWN0aXZlWyBpZCBdID09PSBmYWxzZSApIHtcclxuXHJcblx0XHRcdHJldHVybiBudWxsO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvLyBjb21wdXRlIGJvdW5kaW5nIGJveFxyXG5cdFx0Y29uc3QgYm91bmQgPSB0aGlzLl9ib3VuZHNbIGlkIF07XHJcblx0XHRjb25zdCBib3ggPSBib3VuZC5ib3g7XHJcblx0XHRjb25zdCBnZW9tZXRyeSA9IHRoaXMuZ2VvbWV0cnk7XHJcblx0XHRpZiAoIGJvdW5kLmJveEluaXRpYWxpemVkID09PSBmYWxzZSApIHtcclxuXHJcblx0XHRcdGJveC5tYWtlRW1wdHkoKTtcclxuXHJcblx0XHRcdGNvbnN0IGluZGV4ID0gZ2VvbWV0cnkuaW5kZXg7XHJcblx0XHRcdGNvbnN0IHBvc2l0aW9uID0gZ2VvbWV0cnkuYXR0cmlidXRlcy5wb3NpdGlvbjtcclxuXHRcdFx0Y29uc3QgZHJhd1JhbmdlID0gdGhpcy5fZHJhd1Jhbmdlc1sgaWQgXTtcclxuXHRcdFx0Zm9yICggbGV0IGkgPSBkcmF3UmFuZ2Uuc3RhcnQsIGwgPSBkcmF3UmFuZ2Uuc3RhcnQgKyBkcmF3UmFuZ2UuY291bnQ7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRsZXQgaXYgPSBpO1xyXG5cdFx0XHRcdGlmICggaW5kZXggKSB7XHJcblxyXG5cdFx0XHRcdFx0aXYgPSBpbmRleC5nZXRYKCBpdiApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdGJveC5leHBhbmRCeVBvaW50KCBfdmVjdG9yLmZyb21CdWZmZXJBdHRyaWJ1dGUoIHBvc2l0aW9uLCBpdiApICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRib3VuZC5ib3hJbml0aWFsaXplZCA9IHRydWU7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRhcmdldC5jb3B5KCBib3ggKTtcclxuXHRcdHJldHVybiB0YXJnZXQ7XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gZ2V0IGJvdW5kaW5nIHNwaGVyZSBhbmQgY29tcHV0ZSBpdCBpZiBpdCBkb2Vzbid0IGV4aXN0XHJcblx0Z2V0Qm91bmRpbmdTcGhlcmVBdCggaWQsIHRhcmdldCApIHtcclxuXHJcblx0XHRjb25zdCBhY3RpdmUgPSB0aGlzLl9hY3RpdmU7XHJcblx0XHRpZiAoIGFjdGl2ZVsgaWQgXSA9PT0gZmFsc2UgKSB7XHJcblxyXG5cdFx0XHRyZXR1cm4gbnVsbDtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gY29tcHV0ZSBib3VuZGluZyBzcGhlcmVcclxuXHRcdGNvbnN0IGJvdW5kID0gdGhpcy5fYm91bmRzWyBpZCBdO1xyXG5cdFx0Y29uc3Qgc3BoZXJlID0gYm91bmQuc3BoZXJlO1xyXG5cdFx0Y29uc3QgZ2VvbWV0cnkgPSB0aGlzLmdlb21ldHJ5O1xyXG5cdFx0aWYgKCBib3VuZC5zcGhlcmVJbml0aWFsaXplZCA9PT0gZmFsc2UgKSB7XHJcblxyXG5cdFx0XHRzcGhlcmUubWFrZUVtcHR5KCk7XHJcblxyXG5cdFx0XHR0aGlzLmdldEJvdW5kaW5nQm94QXQoIGlkLCBfYm94ICk7XHJcblx0XHRcdF9ib3guZ2V0Q2VudGVyKCBzcGhlcmUuY2VudGVyICk7XHJcblxyXG5cdFx0XHRjb25zdCBpbmRleCA9IGdlb21ldHJ5LmluZGV4O1xyXG5cdFx0XHRjb25zdCBwb3NpdGlvbiA9IGdlb21ldHJ5LmF0dHJpYnV0ZXMucG9zaXRpb247XHJcblx0XHRcdGNvbnN0IGRyYXdSYW5nZSA9IHRoaXMuX2RyYXdSYW5nZXNbIGlkIF07XHJcblxyXG5cdFx0XHRsZXQgbWF4UmFkaXVzU3EgPSAwO1xyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IGRyYXdSYW5nZS5zdGFydCwgbCA9IGRyYXdSYW5nZS5zdGFydCArIGRyYXdSYW5nZS5jb3VudDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdGxldCBpdiA9IGk7XHJcblx0XHRcdFx0aWYgKCBpbmRleCApIHtcclxuXHJcblx0XHRcdFx0XHRpdiA9IGluZGV4LmdldFgoIGl2ICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0X3ZlY3Rvci5mcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbiwgaXYgKTtcclxuXHRcdFx0XHRtYXhSYWRpdXNTcSA9IE1hdGgubWF4KCBtYXhSYWRpdXNTcSwgc3BoZXJlLmNlbnRlci5kaXN0YW5jZVRvU3F1YXJlZCggX3ZlY3RvciApICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRzcGhlcmUucmFkaXVzID0gTWF0aC5zcXJ0KCBtYXhSYWRpdXNTcSApO1xyXG5cdFx0XHRib3VuZC5zcGhlcmVJbml0aWFsaXplZCA9IHRydWU7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRhcmdldC5jb3B5KCBzcGhlcmUgKTtcclxuXHRcdHJldHVybiB0YXJnZXQ7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0TWF0cml4QXQoIGdlb21ldHJ5SWQsIG1hdHJpeCApIHtcclxuXHJcblx0XHQvLyBAVE9ETzogTWFwIGdlb21ldHJ5SWQgdG8gaW5kZXggb2YgdGhlIGFycmF5cyBiZWNhdXNlXHJcblx0XHQvLyAgICAgICAgb3B0aW1pemUoKSBjYW4gbWFrZSBnZW9tZXRyeUlkIG1pc21hdGNoIHRoZSBpbmRleFxyXG5cclxuXHRcdGNvbnN0IGFjdGl2ZSA9IHRoaXMuX2FjdGl2ZTtcclxuXHRcdGNvbnN0IG1hdHJpY2VzVGV4dHVyZSA9IHRoaXMuX21hdHJpY2VzVGV4dHVyZTtcclxuXHRcdGNvbnN0IG1hdHJpY2VzQXJyYXkgPSB0aGlzLl9tYXRyaWNlc1RleHR1cmUuaW1hZ2UuZGF0YTtcclxuXHRcdGNvbnN0IGdlb21ldHJ5Q291bnQgPSB0aGlzLl9nZW9tZXRyeUNvdW50O1xyXG5cdFx0aWYgKCBnZW9tZXRyeUlkID49IGdlb21ldHJ5Q291bnQgfHwgYWN0aXZlWyBnZW9tZXRyeUlkIF0gPT09IGZhbHNlICkge1xyXG5cclxuXHRcdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdG1hdHJpeC50b0FycmF5KCBtYXRyaWNlc0FycmF5LCBnZW9tZXRyeUlkICogMTYgKTtcclxuXHRcdG1hdHJpY2VzVGV4dHVyZS5uZWVkc1VwZGF0ZSA9IHRydWU7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0TWF0cml4QXQoIGdlb21ldHJ5SWQsIG1hdHJpeCApIHtcclxuXHJcblx0XHRjb25zdCBhY3RpdmUgPSB0aGlzLl9hY3RpdmU7XHJcblx0XHRjb25zdCBtYXRyaWNlc0FycmF5ID0gdGhpcy5fbWF0cmljZXNUZXh0dXJlLmltYWdlLmRhdGE7XHJcblx0XHRjb25zdCBnZW9tZXRyeUNvdW50ID0gdGhpcy5fZ2VvbWV0cnlDb3VudDtcclxuXHRcdGlmICggZ2VvbWV0cnlJZCA+PSBnZW9tZXRyeUNvdW50IHx8IGFjdGl2ZVsgZ2VvbWV0cnlJZCBdID09PSBmYWxzZSApIHtcclxuXHJcblx0XHRcdHJldHVybiBudWxsO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gbWF0cml4LmZyb21BcnJheSggbWF0cmljZXNBcnJheSwgZ2VvbWV0cnlJZCAqIDE2ICk7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0VmlzaWJsZUF0KCBnZW9tZXRyeUlkLCB2YWx1ZSApIHtcclxuXHJcblx0XHRjb25zdCB2aXNpYmlsaXR5ID0gdGhpcy5fdmlzaWJpbGl0eTtcclxuXHRcdGNvbnN0IGFjdGl2ZSA9IHRoaXMuX2FjdGl2ZTtcclxuXHRcdGNvbnN0IGdlb21ldHJ5Q291bnQgPSB0aGlzLl9nZW9tZXRyeUNvdW50O1xyXG5cclxuXHRcdC8vIGlmIHRoZSBnZW9tZXRyeSBpcyBvdXQgb2YgcmFuZ2UsIG5vdCBhY3RpdmUsIG9yIHZpc2liaWxpdHkgc3RhdGVcclxuXHRcdC8vIGRvZXMgbm90IGNoYW5nZSB0aGVuIHJldHVybiBlYXJseVxyXG5cdFx0aWYgKFxyXG5cdFx0XHRnZW9tZXRyeUlkID49IGdlb21ldHJ5Q291bnQgfHxcclxuXHRcdFx0YWN0aXZlWyBnZW9tZXRyeUlkIF0gPT09IGZhbHNlIHx8XHJcblx0XHRcdHZpc2liaWxpdHlbIGdlb21ldHJ5SWQgXSA9PT0gdmFsdWVcclxuXHRcdCkge1xyXG5cclxuXHRcdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHZpc2liaWxpdHlbIGdlb21ldHJ5SWQgXSA9IHZhbHVlO1xyXG5cdFx0dGhpcy5fdmlzaWJpbGl0eUNoYW5nZWQgPSB0cnVlO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldFZpc2libGVBdCggZ2VvbWV0cnlJZCApIHtcclxuXHJcblx0XHRjb25zdCB2aXNpYmlsaXR5ID0gdGhpcy5fdmlzaWJpbGl0eTtcclxuXHRcdGNvbnN0IGFjdGl2ZSA9IHRoaXMuX2FjdGl2ZTtcclxuXHRcdGNvbnN0IGdlb21ldHJ5Q291bnQgPSB0aGlzLl9nZW9tZXRyeUNvdW50O1xyXG5cclxuXHRcdC8vIHJldHVybiBlYXJseSBpZiB0aGUgZ2VvbWV0cnkgaXMgb3V0IG9mIHJhbmdlIG9yIG5vdCBhY3RpdmVcclxuXHRcdGlmICggZ2VvbWV0cnlJZCA+PSBnZW9tZXRyeUNvdW50IHx8IGFjdGl2ZVsgZ2VvbWV0cnlJZCBdID09PSBmYWxzZSApIHtcclxuXHJcblx0XHRcdHJldHVybiBmYWxzZTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHZpc2liaWxpdHlbIGdlb21ldHJ5SWQgXTtcclxuXHJcblx0fVxyXG5cclxuXHRyYXljYXN0KCByYXljYXN0ZXIsIGludGVyc2VjdHMgKSB7XHJcblxyXG5cdFx0Y29uc3QgdmlzaWJpbGl0eSA9IHRoaXMuX3Zpc2liaWxpdHk7XHJcblx0XHRjb25zdCBhY3RpdmUgPSB0aGlzLl9hY3RpdmU7XHJcblx0XHRjb25zdCBkcmF3UmFuZ2VzID0gdGhpcy5fZHJhd1JhbmdlcztcclxuXHRcdGNvbnN0IGdlb21ldHJ5Q291bnQgPSB0aGlzLl9nZW9tZXRyeUNvdW50O1xyXG5cdFx0Y29uc3QgbWF0cml4V29ybGQgPSB0aGlzLm1hdHJpeFdvcmxkO1xyXG5cdFx0Y29uc3QgYmF0Y2hHZW9tZXRyeSA9IHRoaXMuZ2VvbWV0cnk7XHJcblxyXG5cdFx0Ly8gaXRlcmF0ZSBvdmVyIGVhY2ggZ2VvbWV0cnlcclxuXHRcdF9tZXNoLm1hdGVyaWFsID0gdGhpcy5tYXRlcmlhbDtcclxuXHRcdF9tZXNoLmdlb21ldHJ5LmluZGV4ID0gYmF0Y2hHZW9tZXRyeS5pbmRleDtcclxuXHRcdF9tZXNoLmdlb21ldHJ5LmF0dHJpYnV0ZXMgPSBiYXRjaEdlb21ldHJ5LmF0dHJpYnV0ZXM7XHJcblx0XHRpZiAoIF9tZXNoLmdlb21ldHJ5LmJvdW5kaW5nQm94ID09PSBudWxsICkge1xyXG5cclxuXHRcdFx0X21lc2guZ2VvbWV0cnkuYm91bmRpbmdCb3ggPSBuZXcgQm94MygpO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIF9tZXNoLmdlb21ldHJ5LmJvdW5kaW5nU3BoZXJlID09PSBudWxsICkge1xyXG5cclxuXHRcdFx0X21lc2guZ2VvbWV0cnkuYm91bmRpbmdTcGhlcmUgPSBuZXcgU3BoZXJlKCk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IGdlb21ldHJ5Q291bnQ7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRpZiAoICEgdmlzaWJpbGl0eVsgaSBdIHx8ICEgYWN0aXZlWyBpIF0gKSB7XHJcblxyXG5cdFx0XHRcdGNvbnRpbnVlO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Y29uc3QgZHJhd1JhbmdlID0gZHJhd1Jhbmdlc1sgaSBdO1xyXG5cdFx0XHRfbWVzaC5nZW9tZXRyeS5zZXREcmF3UmFuZ2UoIGRyYXdSYW5nZS5zdGFydCwgZHJhd1JhbmdlLmNvdW50ICk7XHJcblxyXG5cdFx0XHQvLyBnZSB0aGUgaW50ZXJzZWN0c1xyXG5cdFx0XHR0aGlzLmdldE1hdHJpeEF0KCBpLCBfbWVzaC5tYXRyaXhXb3JsZCApLnByZW11bHRpcGx5KCBtYXRyaXhXb3JsZCApO1xyXG5cdFx0XHR0aGlzLmdldEJvdW5kaW5nQm94QXQoIGksIF9tZXNoLmdlb21ldHJ5LmJvdW5kaW5nQm94ICk7XHJcblx0XHRcdHRoaXMuZ2V0Qm91bmRpbmdTcGhlcmVBdCggaSwgX21lc2guZ2VvbWV0cnkuYm91bmRpbmdTcGhlcmUgKTtcclxuXHRcdFx0X21lc2gucmF5Y2FzdCggcmF5Y2FzdGVyLCBfYmF0Y2hJbnRlcnNlY3RzICk7XHJcblxyXG5cdFx0XHQvLyBhZGQgYmF0Y2ggaWQgdG8gdGhlIGludGVyc2VjdHNcclxuXHRcdFx0Zm9yICggbGV0IGogPSAwLCBsID0gX2JhdGNoSW50ZXJzZWN0cy5sZW5ndGg7IGogPCBsOyBqICsrICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBpbnRlcnNlY3QgPSBfYmF0Y2hJbnRlcnNlY3RzWyBqIF07XHJcblx0XHRcdFx0aW50ZXJzZWN0Lm9iamVjdCA9IHRoaXM7XHJcblx0XHRcdFx0aW50ZXJzZWN0LmJhdGNoSWQgPSBpO1xyXG5cdFx0XHRcdGludGVyc2VjdHMucHVzaCggaW50ZXJzZWN0ICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRfYmF0Y2hJbnRlcnNlY3RzLmxlbmd0aCA9IDA7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdF9tZXNoLm1hdGVyaWFsID0gbnVsbDtcclxuXHRcdF9tZXNoLmdlb21ldHJ5LmluZGV4ID0gbnVsbDtcclxuXHRcdF9tZXNoLmdlb21ldHJ5LmF0dHJpYnV0ZXMgPSB7fTtcclxuXHRcdF9tZXNoLmdlb21ldHJ5LnNldERyYXdSYW5nZSggMCwgSW5maW5pdHkgKTtcclxuXHJcblx0fVxyXG5cclxuXHRjb3B5KCBzb3VyY2UgKSB7XHJcblxyXG5cdFx0c3VwZXIuY29weSggc291cmNlICk7XHJcblxyXG5cdFx0dGhpcy5nZW9tZXRyeSA9IHNvdXJjZS5nZW9tZXRyeS5jbG9uZSgpO1xyXG5cdFx0dGhpcy5wZXJPYmplY3RGcnVzdHVtQ3VsbGVkID0gc291cmNlLnBlck9iamVjdEZydXN0dW1DdWxsZWQ7XHJcblx0XHR0aGlzLnNvcnRPYmplY3RzID0gc291cmNlLnNvcnRPYmplY3RzO1xyXG5cdFx0dGhpcy5ib3VuZGluZ0JveCA9IHNvdXJjZS5ib3VuZGluZ0JveCAhPT0gbnVsbCA/IHNvdXJjZS5ib3VuZGluZ0JveC5jbG9uZSgpIDogbnVsbDtcclxuXHRcdHRoaXMuYm91bmRpbmdTcGhlcmUgPSBzb3VyY2UuYm91bmRpbmdTcGhlcmUgIT09IG51bGwgPyBzb3VyY2UuYm91bmRpbmdTcGhlcmUuY2xvbmUoKSA6IG51bGw7XHJcblxyXG5cdFx0dGhpcy5fZHJhd1JhbmdlcyA9IHNvdXJjZS5fZHJhd1Jhbmdlcy5tYXAoIHJhbmdlID0+ICggeyAuLi5yYW5nZSB9ICkgKTtcclxuXHRcdHRoaXMuX3Jlc2VydmVkUmFuZ2VzID0gc291cmNlLl9yZXNlcnZlZFJhbmdlcy5tYXAoIHJhbmdlID0+ICggeyAuLi5yYW5nZSB9ICkgKTtcclxuXHJcblx0XHR0aGlzLl92aXNpYmlsaXR5ID0gc291cmNlLl92aXNpYmlsaXR5LnNsaWNlKCk7XHJcblx0XHR0aGlzLl9hY3RpdmUgPSBzb3VyY2UuX2FjdGl2ZS5zbGljZSgpO1xyXG5cdFx0dGhpcy5fYm91bmRzID0gc291cmNlLl9ib3VuZHMubWFwKCBib3VuZCA9PiAoIHtcclxuXHRcdFx0Ym94SW5pdGlhbGl6ZWQ6IGJvdW5kLmJveEluaXRpYWxpemVkLFxyXG5cdFx0XHRib3g6IGJvdW5kLmJveC5jbG9uZSgpLFxyXG5cclxuXHRcdFx0c3BoZXJlSW5pdGlhbGl6ZWQ6IGJvdW5kLnNwaGVyZUluaXRpYWxpemVkLFxyXG5cdFx0XHRzcGhlcmU6IGJvdW5kLnNwaGVyZS5jbG9uZSgpXHJcblx0XHR9ICkgKTtcclxuXHJcblx0XHR0aGlzLl9tYXhHZW9tZXRyeUNvdW50ID0gc291cmNlLl9tYXhHZW9tZXRyeUNvdW50O1xyXG5cdFx0dGhpcy5fbWF4VmVydGV4Q291bnQgPSBzb3VyY2UuX21heFZlcnRleENvdW50O1xyXG5cdFx0dGhpcy5fbWF4SW5kZXhDb3VudCA9IHNvdXJjZS5fbWF4SW5kZXhDb3VudDtcclxuXHJcblx0XHR0aGlzLl9nZW9tZXRyeUluaXRpYWxpemVkID0gc291cmNlLl9nZW9tZXRyeUluaXRpYWxpemVkO1xyXG5cdFx0dGhpcy5fZ2VvbWV0cnlDb3VudCA9IHNvdXJjZS5fZ2VvbWV0cnlDb3VudDtcclxuXHRcdHRoaXMuX211bHRpRHJhd0NvdW50cyA9IHNvdXJjZS5fbXVsdGlEcmF3Q291bnRzLnNsaWNlKCk7XHJcblx0XHR0aGlzLl9tdWx0aURyYXdTdGFydHMgPSBzb3VyY2UuX211bHRpRHJhd1N0YXJ0cy5zbGljZSgpO1xyXG5cclxuXHRcdHRoaXMuX21hdHJpY2VzVGV4dHVyZSA9IHNvdXJjZS5fbWF0cmljZXNUZXh0dXJlLmNsb25lKCk7XHJcblx0XHR0aGlzLl9tYXRyaWNlc1RleHR1cmUuaW1hZ2UuZGF0YSA9IHRoaXMuX21hdHJpY2VzVGV4dHVyZS5pbWFnZS5zbGljZSgpO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGRpc3Bvc2UoKSB7XHJcblxyXG5cdFx0Ly8gQXNzdW1pbmcgdGhlIGdlb21ldHJ5IGlzIG5vdCBzaGFyZWQgd2l0aCBvdGhlciBtZXNoZXNcclxuXHRcdHRoaXMuZ2VvbWV0cnkuZGlzcG9zZSgpO1xyXG5cclxuXHRcdHRoaXMuX21hdHJpY2VzVGV4dHVyZS5kaXNwb3NlKCk7XHJcblx0XHR0aGlzLl9tYXRyaWNlc1RleHR1cmUgPSBudWxsO1xyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0b25CZWZvcmVSZW5kZXIoIHJlbmRlcmVyLCBzY2VuZSwgY2FtZXJhLCBnZW9tZXRyeSwgbWF0ZXJpYWwvKiwgX2dyb3VwKi8gKSB7XHJcblxyXG5cdFx0Ly8gaWYgdmlzaWJpbGl0eSBoYXMgbm90IGNoYW5nZWQgYW5kIGZydXN0dW0gY3VsbGluZyBhbmQgb2JqZWN0IHNvcnRpbmcgaXMgbm90IHJlcXVpcmVkXHJcblx0XHQvLyB0aGVuIHNraXAgaXRlcmF0aW5nIG92ZXIgYWxsIGl0ZW1zXHJcblx0XHRpZiAoICEgdGhpcy5fdmlzaWJpbGl0eUNoYW5nZWQgJiYgISB0aGlzLnBlck9iamVjdEZydXN0dW1DdWxsZWQgJiYgISB0aGlzLnNvcnRPYmplY3RzICkge1xyXG5cclxuXHRcdFx0cmV0dXJuO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvLyB0aGUgaW5kZXhlZCB2ZXJzaW9uIG9mIHRoZSBtdWx0aSBkcmF3IGZ1bmN0aW9uIHJlcXVpcmVzIHNwZWNpZnlpbmcgdGhlIHN0YXJ0XHJcblx0XHQvLyBvZmZzZXQgaW4gYnl0ZXMuXHJcblx0XHRjb25zdCBpbmRleCA9IGdlb21ldHJ5LmdldEluZGV4KCk7XHJcblx0XHRjb25zdCBieXRlc1BlckVsZW1lbnQgPSBpbmRleCA9PT0gbnVsbCA/IDEgOiBpbmRleC5hcnJheS5CWVRFU19QRVJfRUxFTUVOVDtcclxuXHJcblx0XHRjb25zdCBhY3RpdmUgPSB0aGlzLl9hY3RpdmU7XHJcblx0XHRjb25zdCB2aXNpYmlsaXR5ID0gdGhpcy5fdmlzaWJpbGl0eTtcclxuXHRcdGNvbnN0IG11bHRpRHJhd1N0YXJ0cyA9IHRoaXMuX211bHRpRHJhd1N0YXJ0cztcclxuXHRcdGNvbnN0IG11bHRpRHJhd0NvdW50cyA9IHRoaXMuX211bHRpRHJhd0NvdW50cztcclxuXHRcdGNvbnN0IGRyYXdSYW5nZXMgPSB0aGlzLl9kcmF3UmFuZ2VzO1xyXG5cdFx0Y29uc3QgcGVyT2JqZWN0RnJ1c3R1bUN1bGxlZCA9IHRoaXMucGVyT2JqZWN0RnJ1c3R1bUN1bGxlZDtcclxuXHJcblx0XHQvLyBwcmVwYXJlIHRoZSBmcnVzdHVtIGluIHRoZSBsb2NhbCBmcmFtZVxyXG5cdFx0aWYgKCBwZXJPYmplY3RGcnVzdHVtQ3VsbGVkICkge1xyXG5cclxuXHRcdFx0X3Byb2pTY3JlZW5NYXRyaXhcclxuXHRcdFx0XHQubXVsdGlwbHlNYXRyaWNlcyggY2FtZXJhLnByb2plY3Rpb25NYXRyaXgsIGNhbWVyYS5tYXRyaXhXb3JsZEludmVyc2UgKVxyXG5cdFx0XHRcdC5tdWx0aXBseSggdGhpcy5tYXRyaXhXb3JsZCApO1xyXG5cdFx0XHRfZnJ1c3R1bS5zZXRGcm9tUHJvamVjdGlvbk1hdHJpeChcclxuXHRcdFx0XHRfcHJvalNjcmVlbk1hdHJpeCxcclxuXHRcdFx0XHRyZW5kZXJlci5jb29yZGluYXRlU3lzdGVtXHJcblx0XHRcdCk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGxldCBjb3VudCA9IDA7XHJcblx0XHRpZiAoIHRoaXMuc29ydE9iamVjdHMgKSB7XHJcblxyXG5cdFx0XHQvLyBnZXQgdGhlIGNhbWVyYSBwb3NpdGlvbiBpbiB0aGUgbG9jYWwgZnJhbWVcclxuXHRcdFx0X2ludk1hdHJpeFdvcmxkLmNvcHkoIHRoaXMubWF0cml4V29ybGQgKS5pbnZlcnQoKTtcclxuXHRcdFx0X3ZlY3Rvci5zZXRGcm9tTWF0cml4UG9zaXRpb24oIGNhbWVyYS5tYXRyaXhXb3JsZCApLmFwcGx5TWF0cml4NCggX2ludk1hdHJpeFdvcmxkICk7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSB2aXNpYmlsaXR5Lmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdGlmICggdmlzaWJpbGl0eVsgaSBdICYmIGFjdGl2ZVsgaSBdICkge1xyXG5cclxuXHRcdFx0XHRcdC8vIGdldCB0aGUgYm91bmRzIGluIHdvcmxkIHNwYWNlXHJcblx0XHRcdFx0XHR0aGlzLmdldE1hdHJpeEF0KCBpLCBfbWF0cml4ICk7XHJcblx0XHRcdFx0XHR0aGlzLmdldEJvdW5kaW5nU3BoZXJlQXQoIGksIF9zcGhlcmUgKS5hcHBseU1hdHJpeDQoIF9tYXRyaXggKTtcclxuXHJcblx0XHRcdFx0XHQvLyBkZXRlcm1pbmUgd2hldGhlciB0aGUgYmF0Y2hlZCBnZW9tZXRyeSBpcyB3aXRoaW4gdGhlIGZydXN0dW1cclxuXHRcdFx0XHRcdGxldCBjdWxsZWQgPSBmYWxzZTtcclxuXHRcdFx0XHRcdGlmICggcGVyT2JqZWN0RnJ1c3R1bUN1bGxlZCApIHtcclxuXHJcblx0XHRcdFx0XHRcdGN1bGxlZCA9ICEgX2ZydXN0dW0uaW50ZXJzZWN0c1NwaGVyZSggX3NwaGVyZSApO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRpZiAoICEgY3VsbGVkICkge1xyXG5cclxuXHRcdFx0XHRcdFx0Ly8gZ2V0IHRoZSBkaXN0YW5jZSBmcm9tIGNhbWVyYSB1c2VkIGZvciBzb3J0aW5nXHJcblx0XHRcdFx0XHRcdGNvbnN0IHogPSBfdmVjdG9yLmRpc3RhbmNlVG8oIF9zcGhlcmUuY2VudGVyICk7XHJcblx0XHRcdFx0XHRcdF9yZW5kZXJMaXN0LnB1c2goIGRyYXdSYW5nZXNbIGkgXSwgeiApO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Ly8gU29ydCB0aGUgZHJhdyByYW5nZXMgYW5kIHByZXAgZm9yIHJlbmRlcmluZ1xyXG5cdFx0XHRjb25zdCBsaXN0ID0gX3JlbmRlckxpc3QubGlzdDtcclxuXHRcdFx0Y29uc3QgY3VzdG9tU29ydCA9IHRoaXMuY3VzdG9tU29ydDtcclxuXHRcdFx0aWYgKCBjdXN0b21Tb3J0ID09PSBudWxsICkge1xyXG5cclxuXHRcdFx0XHRsaXN0LnNvcnQoIG1hdGVyaWFsLnRyYW5zcGFyZW50ID8gc29ydFRyYW5zcGFyZW50IDogc29ydE9wYXF1ZSApO1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0Y3VzdG9tU29ydC5jYWxsKCB0aGlzLCBsaXN0LCBjYW1lcmEgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMCwgbCA9IGxpc3QubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgaXRlbSA9IGxpc3RbIGkgXTtcclxuXHRcdFx0XHRtdWx0aURyYXdTdGFydHNbIGNvdW50IF0gPSBpdGVtLnN0YXJ0ICogYnl0ZXNQZXJFbGVtZW50O1xyXG5cdFx0XHRcdG11bHRpRHJhd0NvdW50c1sgY291bnQgXSA9IGl0ZW0uY291bnQ7XHJcblx0XHRcdFx0Y291bnQgKys7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRfcmVuZGVyTGlzdC5yZXNldCgpO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSB2aXNpYmlsaXR5Lmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdGlmICggdmlzaWJpbGl0eVsgaSBdICYmIGFjdGl2ZVsgaSBdICkge1xyXG5cclxuXHRcdFx0XHRcdC8vIGRldGVybWluZSB3aGV0aGVyIHRoZSBiYXRjaGVkIGdlb21ldHJ5IGlzIHdpdGhpbiB0aGUgZnJ1c3R1bVxyXG5cdFx0XHRcdFx0bGV0IGN1bGxlZCA9IGZhbHNlO1xyXG5cdFx0XHRcdFx0aWYgKCBwZXJPYmplY3RGcnVzdHVtQ3VsbGVkICkge1xyXG5cclxuXHRcdFx0XHRcdFx0Ly8gZ2V0IHRoZSBib3VuZHMgaW4gd29ybGQgc3BhY2VcclxuXHRcdFx0XHRcdFx0dGhpcy5nZXRNYXRyaXhBdCggaSwgX21hdHJpeCApO1xyXG5cdFx0XHRcdFx0XHR0aGlzLmdldEJvdW5kaW5nU3BoZXJlQXQoIGksIF9zcGhlcmUgKS5hcHBseU1hdHJpeDQoIF9tYXRyaXggKTtcclxuXHRcdFx0XHRcdFx0Y3VsbGVkID0gISBfZnJ1c3R1bS5pbnRlcnNlY3RzU3BoZXJlKCBfc3BoZXJlICk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdGlmICggISBjdWxsZWQgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRjb25zdCByYW5nZSA9IGRyYXdSYW5nZXNbIGkgXTtcclxuXHRcdFx0XHRcdFx0bXVsdGlEcmF3U3RhcnRzWyBjb3VudCBdID0gcmFuZ2Uuc3RhcnQgKiBieXRlc1BlckVsZW1lbnQ7XHJcblx0XHRcdFx0XHRcdG11bHRpRHJhd0NvdW50c1sgY291bnQgXSA9IHJhbmdlLmNvdW50O1xyXG5cdFx0XHRcdFx0XHRjb3VudCArKztcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5fbXVsdGlEcmF3Q291bnQgPSBjb3VudDtcclxuXHRcdHRoaXMuX3Zpc2liaWxpdHlDaGFuZ2VkID0gZmFsc2U7XHJcblxyXG5cdH1cclxuXHJcblx0b25CZWZvcmVTaGFkb3coIHJlbmRlcmVyLCBvYmplY3QsIGNhbWVyYSwgc2hhZG93Q2FtZXJhLCBnZW9tZXRyeSwgZGVwdGhNYXRlcmlhbC8qICwgZ3JvdXAgKi8gKSB7XHJcblxyXG5cdFx0dGhpcy5vbkJlZm9yZVJlbmRlciggcmVuZGVyZXIsIG51bGwsIHNoYWRvd0NhbWVyYSwgZ2VvbWV0cnksIGRlcHRoTWF0ZXJpYWwgKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgQmF0Y2hlZE1lc2ggfTtcclxuIiwiaW1wb3J0IHsgTWF0ZXJpYWwgfSBmcm9tICcuL01hdGVyaWFsLmpzJztcclxuaW1wb3J0IHsgQ29sb3IgfSBmcm9tICcuLi9tYXRoL0NvbG9yLmpzJztcclxuXHJcbmNsYXNzIExpbmVCYXNpY01hdGVyaWFsIGV4dGVuZHMgTWF0ZXJpYWwge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggcGFyYW1ldGVycyApIHtcclxuXHJcblx0XHRzdXBlcigpO1xyXG5cclxuXHRcdHRoaXMuaXNMaW5lQmFzaWNNYXRlcmlhbCA9IHRydWU7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ0xpbmVCYXNpY01hdGVyaWFsJztcclxuXHJcblx0XHR0aGlzLmNvbG9yID0gbmV3IENvbG9yKCAweGZmZmZmZiApO1xyXG5cclxuXHRcdHRoaXMubWFwID0gbnVsbDtcclxuXHJcblx0XHR0aGlzLmxpbmV3aWR0aCA9IDE7XHJcblx0XHR0aGlzLmxpbmVjYXAgPSAncm91bmQnO1xyXG5cdFx0dGhpcy5saW5lam9pbiA9ICdyb3VuZCc7XHJcblxyXG5cdFx0dGhpcy5mb2cgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMuc2V0VmFsdWVzKCBwYXJhbWV0ZXJzICk7XHJcblxyXG5cdH1cclxuXHJcblxyXG5cdGNvcHkoIHNvdXJjZSApIHtcclxuXHJcblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcclxuXHJcblx0XHR0aGlzLmNvbG9yLmNvcHkoIHNvdXJjZS5jb2xvciApO1xyXG5cclxuXHRcdHRoaXMubWFwID0gc291cmNlLm1hcDtcclxuXHJcblx0XHR0aGlzLmxpbmV3aWR0aCA9IHNvdXJjZS5saW5ld2lkdGg7XHJcblx0XHR0aGlzLmxpbmVjYXAgPSBzb3VyY2UubGluZWNhcDtcclxuXHRcdHRoaXMubGluZWpvaW4gPSBzb3VyY2UubGluZWpvaW47XHJcblxyXG5cdFx0dGhpcy5mb2cgPSBzb3VyY2UuZm9nO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBMaW5lQmFzaWNNYXRlcmlhbCB9O1xyXG4iLCJpbXBvcnQgeyBTcGhlcmUgfSBmcm9tICcuLi9tYXRoL1NwaGVyZS5qcyc7XHJcbmltcG9ydCB7IFJheSB9IGZyb20gJy4uL21hdGgvUmF5LmpzJztcclxuaW1wb3J0IHsgTWF0cml4NCB9IGZyb20gJy4uL21hdGgvTWF0cml4NC5qcyc7XHJcbmltcG9ydCB7IE9iamVjdDNEIH0gZnJvbSAnLi4vY29yZS9PYmplY3QzRC5qcyc7XHJcbmltcG9ydCB7IFZlY3RvcjMgfSBmcm9tICcuLi9tYXRoL1ZlY3RvcjMuanMnO1xyXG5pbXBvcnQgeyBMaW5lQmFzaWNNYXRlcmlhbCB9IGZyb20gJy4uL21hdGVyaWFscy9MaW5lQmFzaWNNYXRlcmlhbC5qcyc7XHJcbmltcG9ydCB7IEJ1ZmZlckdlb21ldHJ5IH0gZnJvbSAnLi4vY29yZS9CdWZmZXJHZW9tZXRyeS5qcyc7XHJcbmltcG9ydCB7IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUgfSBmcm9tICcuLi9jb3JlL0J1ZmZlckF0dHJpYnV0ZS5qcyc7XHJcblxyXG5jb25zdCBfc3RhcnQgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XHJcbmNvbnN0IF9lbmQgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XHJcbmNvbnN0IF9pbnZlcnNlTWF0cml4ID0gLypAX19QVVJFX18qLyBuZXcgTWF0cml4NCgpO1xyXG5jb25zdCBfcmF5ID0gLypAX19QVVJFX18qLyBuZXcgUmF5KCk7XHJcbmNvbnN0IF9zcGhlcmUgPSAvKkBfX1BVUkVfXyovIG5ldyBTcGhlcmUoKTtcclxuXHJcbmNsYXNzIExpbmUgZXh0ZW5kcyBPYmplY3QzRCB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBnZW9tZXRyeSA9IG5ldyBCdWZmZXJHZW9tZXRyeSgpLCBtYXRlcmlhbCA9IG5ldyBMaW5lQmFzaWNNYXRlcmlhbCgpICkge1xyXG5cclxuXHRcdHN1cGVyKCk7XHJcblxyXG5cdFx0dGhpcy5pc0xpbmUgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMudHlwZSA9ICdMaW5lJztcclxuXHJcblx0XHR0aGlzLmdlb21ldHJ5ID0gZ2VvbWV0cnk7XHJcblx0XHR0aGlzLm1hdGVyaWFsID0gbWF0ZXJpYWw7XHJcblxyXG5cdFx0dGhpcy51cGRhdGVNb3JwaFRhcmdldHMoKTtcclxuXHJcblx0fVxyXG5cclxuXHRjb3B5KCBzb3VyY2UsIHJlY3Vyc2l2ZSApIHtcclxuXHJcblx0XHRzdXBlci5jb3B5KCBzb3VyY2UsIHJlY3Vyc2l2ZSApO1xyXG5cclxuXHRcdHRoaXMubWF0ZXJpYWwgPSBBcnJheS5pc0FycmF5KCBzb3VyY2UubWF0ZXJpYWwgKSA/IHNvdXJjZS5tYXRlcmlhbC5zbGljZSgpIDogc291cmNlLm1hdGVyaWFsO1xyXG5cdFx0dGhpcy5nZW9tZXRyeSA9IHNvdXJjZS5nZW9tZXRyeTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRjb21wdXRlTGluZURpc3RhbmNlcygpIHtcclxuXHJcblx0XHRjb25zdCBnZW9tZXRyeSA9IHRoaXMuZ2VvbWV0cnk7XHJcblxyXG5cdFx0Ly8gd2UgYXNzdW1lIG5vbi1pbmRleGVkIGdlb21ldHJ5XHJcblxyXG5cdFx0aWYgKCBnZW9tZXRyeS5pbmRleCA9PT0gbnVsbCApIHtcclxuXHJcblx0XHRcdGNvbnN0IHBvc2l0aW9uQXR0cmlidXRlID0gZ2VvbWV0cnkuYXR0cmlidXRlcy5wb3NpdGlvbjtcclxuXHRcdFx0Y29uc3QgbGluZURpc3RhbmNlcyA9IFsgMCBdO1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGkgPSAxLCBsID0gcG9zaXRpb25BdHRyaWJ1dGUuY291bnQ7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRfc3RhcnQuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggcG9zaXRpb25BdHRyaWJ1dGUsIGkgLSAxICk7XHJcblx0XHRcdFx0X2VuZC5mcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbkF0dHJpYnV0ZSwgaSApO1xyXG5cclxuXHRcdFx0XHRsaW5lRGlzdGFuY2VzWyBpIF0gPSBsaW5lRGlzdGFuY2VzWyBpIC0gMSBdO1xyXG5cdFx0XHRcdGxpbmVEaXN0YW5jZXNbIGkgXSArPSBfc3RhcnQuZGlzdGFuY2VUbyggX2VuZCApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Z2VvbWV0cnkuc2V0QXR0cmlidXRlKCAnbGluZURpc3RhbmNlJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIGxpbmVEaXN0YW5jZXMsIDEgKSApO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5MaW5lLmNvbXB1dGVMaW5lRGlzdGFuY2VzKCk6IENvbXB1dGF0aW9uIG9ubHkgcG9zc2libGUgd2l0aCBub24taW5kZXhlZCBCdWZmZXJHZW9tZXRyeS4nICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHJheWNhc3QoIHJheWNhc3RlciwgaW50ZXJzZWN0cyApIHtcclxuXHJcblx0XHRjb25zdCBnZW9tZXRyeSA9IHRoaXMuZ2VvbWV0cnk7XHJcblx0XHRjb25zdCBtYXRyaXhXb3JsZCA9IHRoaXMubWF0cml4V29ybGQ7XHJcblx0XHRjb25zdCB0aHJlc2hvbGQgPSByYXljYXN0ZXIucGFyYW1zLkxpbmUudGhyZXNob2xkO1xyXG5cdFx0Y29uc3QgZHJhd1JhbmdlID0gZ2VvbWV0cnkuZHJhd1JhbmdlO1xyXG5cclxuXHRcdC8vIENoZWNraW5nIGJvdW5kaW5nU3BoZXJlIGRpc3RhbmNlIHRvIHJheVxyXG5cclxuXHRcdGlmICggZ2VvbWV0cnkuYm91bmRpbmdTcGhlcmUgPT09IG51bGwgKSBnZW9tZXRyeS5jb21wdXRlQm91bmRpbmdTcGhlcmUoKTtcclxuXHJcblx0XHRfc3BoZXJlLmNvcHkoIGdlb21ldHJ5LmJvdW5kaW5nU3BoZXJlICk7XHJcblx0XHRfc3BoZXJlLmFwcGx5TWF0cml4NCggbWF0cml4V29ybGQgKTtcclxuXHRcdF9zcGhlcmUucmFkaXVzICs9IHRocmVzaG9sZDtcclxuXHJcblx0XHRpZiAoIHJheWNhc3Rlci5yYXkuaW50ZXJzZWN0c1NwaGVyZSggX3NwaGVyZSApID09PSBmYWxzZSApIHJldHVybjtcclxuXHJcblx0XHQvL1xyXG5cclxuXHRcdF9pbnZlcnNlTWF0cml4LmNvcHkoIG1hdHJpeFdvcmxkICkuaW52ZXJ0KCk7XHJcblx0XHRfcmF5LmNvcHkoIHJheWNhc3Rlci5yYXkgKS5hcHBseU1hdHJpeDQoIF9pbnZlcnNlTWF0cml4ICk7XHJcblxyXG5cdFx0Y29uc3QgbG9jYWxUaHJlc2hvbGQgPSB0aHJlc2hvbGQgLyAoICggdGhpcy5zY2FsZS54ICsgdGhpcy5zY2FsZS55ICsgdGhpcy5zY2FsZS56ICkgLyAzICk7XHJcblx0XHRjb25zdCBsb2NhbFRocmVzaG9sZFNxID0gbG9jYWxUaHJlc2hvbGQgKiBsb2NhbFRocmVzaG9sZDtcclxuXHJcblx0XHRjb25zdCB2U3RhcnQgPSBuZXcgVmVjdG9yMygpO1xyXG5cdFx0Y29uc3QgdkVuZCA9IG5ldyBWZWN0b3IzKCk7XHJcblx0XHRjb25zdCBpbnRlclNlZ21lbnQgPSBuZXcgVmVjdG9yMygpO1xyXG5cdFx0Y29uc3QgaW50ZXJSYXkgPSBuZXcgVmVjdG9yMygpO1xyXG5cdFx0Y29uc3Qgc3RlcCA9IHRoaXMuaXNMaW5lU2VnbWVudHMgPyAyIDogMTtcclxuXHJcblx0XHRjb25zdCBpbmRleCA9IGdlb21ldHJ5LmluZGV4O1xyXG5cdFx0Y29uc3QgYXR0cmlidXRlcyA9IGdlb21ldHJ5LmF0dHJpYnV0ZXM7XHJcblx0XHRjb25zdCBwb3NpdGlvbkF0dHJpYnV0ZSA9IGF0dHJpYnV0ZXMucG9zaXRpb247XHJcblxyXG5cdFx0aWYgKCBpbmRleCAhPT0gbnVsbCApIHtcclxuXHJcblx0XHRcdGNvbnN0IHN0YXJ0ID0gTWF0aC5tYXgoIDAsIGRyYXdSYW5nZS5zdGFydCApO1xyXG5cdFx0XHRjb25zdCBlbmQgPSBNYXRoLm1pbiggaW5kZXguY291bnQsICggZHJhd1JhbmdlLnN0YXJ0ICsgZHJhd1JhbmdlLmNvdW50ICkgKTtcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gc3RhcnQsIGwgPSBlbmQgLSAxOyBpIDwgbDsgaSArPSBzdGVwICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBhID0gaW5kZXguZ2V0WCggaSApO1xyXG5cdFx0XHRcdGNvbnN0IGIgPSBpbmRleC5nZXRYKCBpICsgMSApO1xyXG5cclxuXHRcdFx0XHR2U3RhcnQuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggcG9zaXRpb25BdHRyaWJ1dGUsIGEgKTtcclxuXHRcdFx0XHR2RW5kLmZyb21CdWZmZXJBdHRyaWJ1dGUoIHBvc2l0aW9uQXR0cmlidXRlLCBiICk7XHJcblxyXG5cdFx0XHRcdGNvbnN0IGRpc3RTcSA9IF9yYXkuZGlzdGFuY2VTcVRvU2VnbWVudCggdlN0YXJ0LCB2RW5kLCBpbnRlclJheSwgaW50ZXJTZWdtZW50ICk7XHJcblxyXG5cdFx0XHRcdGlmICggZGlzdFNxID4gbG9jYWxUaHJlc2hvbGRTcSApIGNvbnRpbnVlO1xyXG5cclxuXHRcdFx0XHRpbnRlclJheS5hcHBseU1hdHJpeDQoIHRoaXMubWF0cml4V29ybGQgKTsgLy9Nb3ZlIGJhY2sgdG8gd29ybGQgc3BhY2UgZm9yIGRpc3RhbmNlIGNhbGN1bGF0aW9uXHJcblxyXG5cdFx0XHRcdGNvbnN0IGRpc3RhbmNlID0gcmF5Y2FzdGVyLnJheS5vcmlnaW4uZGlzdGFuY2VUbyggaW50ZXJSYXkgKTtcclxuXHJcblx0XHRcdFx0aWYgKCBkaXN0YW5jZSA8IHJheWNhc3Rlci5uZWFyIHx8IGRpc3RhbmNlID4gcmF5Y2FzdGVyLmZhciApIGNvbnRpbnVlO1xyXG5cclxuXHRcdFx0XHRpbnRlcnNlY3RzLnB1c2goIHtcclxuXHJcblx0XHRcdFx0XHRkaXN0YW5jZTogZGlzdGFuY2UsXHJcblx0XHRcdFx0XHQvLyBXaGF0IGRvIHdlIHdhbnQ/IGludGVyc2VjdGlvbiBwb2ludCBvbiB0aGUgcmF5IG9yIG9uIHRoZSBzZWdtZW50Pz9cclxuXHRcdFx0XHRcdC8vIHBvaW50OiByYXljYXN0ZXIucmF5LmF0KCBkaXN0YW5jZSApLFxyXG5cdFx0XHRcdFx0cG9pbnQ6IGludGVyU2VnbWVudC5jbG9uZSgpLmFwcGx5TWF0cml4NCggdGhpcy5tYXRyaXhXb3JsZCApLFxyXG5cdFx0XHRcdFx0aW5kZXg6IGksXHJcblx0XHRcdFx0XHRmYWNlOiBudWxsLFxyXG5cdFx0XHRcdFx0ZmFjZUluZGV4OiBudWxsLFxyXG5cdFx0XHRcdFx0b2JqZWN0OiB0aGlzXHJcblxyXG5cdFx0XHRcdH0gKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0Y29uc3Qgc3RhcnQgPSBNYXRoLm1heCggMCwgZHJhd1JhbmdlLnN0YXJ0ICk7XHJcblx0XHRcdGNvbnN0IGVuZCA9IE1hdGgubWluKCBwb3NpdGlvbkF0dHJpYnV0ZS5jb3VudCwgKCBkcmF3UmFuZ2Uuc3RhcnQgKyBkcmF3UmFuZ2UuY291bnQgKSApO1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGkgPSBzdGFydCwgbCA9IGVuZCAtIDE7IGkgPCBsOyBpICs9IHN0ZXAgKSB7XHJcblxyXG5cdFx0XHRcdHZTdGFydC5mcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbkF0dHJpYnV0ZSwgaSApO1xyXG5cdFx0XHRcdHZFbmQuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggcG9zaXRpb25BdHRyaWJ1dGUsIGkgKyAxICk7XHJcblxyXG5cdFx0XHRcdGNvbnN0IGRpc3RTcSA9IF9yYXkuZGlzdGFuY2VTcVRvU2VnbWVudCggdlN0YXJ0LCB2RW5kLCBpbnRlclJheSwgaW50ZXJTZWdtZW50ICk7XHJcblxyXG5cdFx0XHRcdGlmICggZGlzdFNxID4gbG9jYWxUaHJlc2hvbGRTcSApIGNvbnRpbnVlO1xyXG5cclxuXHRcdFx0XHRpbnRlclJheS5hcHBseU1hdHJpeDQoIHRoaXMubWF0cml4V29ybGQgKTsgLy9Nb3ZlIGJhY2sgdG8gd29ybGQgc3BhY2UgZm9yIGRpc3RhbmNlIGNhbGN1bGF0aW9uXHJcblxyXG5cdFx0XHRcdGNvbnN0IGRpc3RhbmNlID0gcmF5Y2FzdGVyLnJheS5vcmlnaW4uZGlzdGFuY2VUbyggaW50ZXJSYXkgKTtcclxuXHJcblx0XHRcdFx0aWYgKCBkaXN0YW5jZSA8IHJheWNhc3Rlci5uZWFyIHx8IGRpc3RhbmNlID4gcmF5Y2FzdGVyLmZhciApIGNvbnRpbnVlO1xyXG5cclxuXHRcdFx0XHRpbnRlcnNlY3RzLnB1c2goIHtcclxuXHJcblx0XHRcdFx0XHRkaXN0YW5jZTogZGlzdGFuY2UsXHJcblx0XHRcdFx0XHQvLyBXaGF0IGRvIHdlIHdhbnQ/IGludGVyc2VjdGlvbiBwb2ludCBvbiB0aGUgcmF5IG9yIG9uIHRoZSBzZWdtZW50Pz9cclxuXHRcdFx0XHRcdC8vIHBvaW50OiByYXljYXN0ZXIucmF5LmF0KCBkaXN0YW5jZSApLFxyXG5cdFx0XHRcdFx0cG9pbnQ6IGludGVyU2VnbWVudC5jbG9uZSgpLmFwcGx5TWF0cml4NCggdGhpcy5tYXRyaXhXb3JsZCApLFxyXG5cdFx0XHRcdFx0aW5kZXg6IGksXHJcblx0XHRcdFx0XHRmYWNlOiBudWxsLFxyXG5cdFx0XHRcdFx0ZmFjZUluZGV4OiBudWxsLFxyXG5cdFx0XHRcdFx0b2JqZWN0OiB0aGlzXHJcblxyXG5cdFx0XHRcdH0gKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0dXBkYXRlTW9ycGhUYXJnZXRzKCkge1xyXG5cclxuXHRcdGNvbnN0IGdlb21ldHJ5ID0gdGhpcy5nZW9tZXRyeTtcclxuXHJcblx0XHRjb25zdCBtb3JwaEF0dHJpYnV0ZXMgPSBnZW9tZXRyeS5tb3JwaEF0dHJpYnV0ZXM7XHJcblx0XHRjb25zdCBrZXlzID0gT2JqZWN0LmtleXMoIG1vcnBoQXR0cmlidXRlcyApO1xyXG5cclxuXHRcdGlmICgga2V5cy5sZW5ndGggPiAwICkge1xyXG5cclxuXHRcdFx0Y29uc3QgbW9ycGhBdHRyaWJ1dGUgPSBtb3JwaEF0dHJpYnV0ZXNbIGtleXNbIDAgXSBdO1xyXG5cclxuXHRcdFx0aWYgKCBtb3JwaEF0dHJpYnV0ZSAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHR0aGlzLm1vcnBoVGFyZ2V0SW5mbHVlbmNlcyA9IFtdO1xyXG5cdFx0XHRcdHRoaXMubW9ycGhUYXJnZXREaWN0aW9uYXJ5ID0ge307XHJcblxyXG5cdFx0XHRcdGZvciAoIGxldCBtID0gMCwgbWwgPSBtb3JwaEF0dHJpYnV0ZS5sZW5ndGg7IG0gPCBtbDsgbSArKyApIHtcclxuXHJcblx0XHRcdFx0XHRjb25zdCBuYW1lID0gbW9ycGhBdHRyaWJ1dGVbIG0gXS5uYW1lIHx8IFN0cmluZyggbSApO1xyXG5cclxuXHRcdFx0XHRcdHRoaXMubW9ycGhUYXJnZXRJbmZsdWVuY2VzLnB1c2goIDAgKTtcclxuXHRcdFx0XHRcdHRoaXMubW9ycGhUYXJnZXREaWN0aW9uYXJ5WyBuYW1lIF0gPSBtO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBMaW5lIH07XHJcbiIsImltcG9ydCB7IExpbmUgfSBmcm9tICcuL0xpbmUuanMnO1xyXG5pbXBvcnQgeyBWZWN0b3IzIH0gZnJvbSAnLi4vbWF0aC9WZWN0b3IzLmpzJztcclxuaW1wb3J0IHsgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSB9IGZyb20gJy4uL2NvcmUvQnVmZmVyQXR0cmlidXRlLmpzJztcclxuXHJcbmNvbnN0IF9zdGFydCA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuY29uc3QgX2VuZCA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuXHJcbmNsYXNzIExpbmVTZWdtZW50cyBleHRlbmRzIExpbmUge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggZ2VvbWV0cnksIG1hdGVyaWFsICkge1xyXG5cclxuXHRcdHN1cGVyKCBnZW9tZXRyeSwgbWF0ZXJpYWwgKTtcclxuXHJcblx0XHR0aGlzLmlzTGluZVNlZ21lbnRzID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSAnTGluZVNlZ21lbnRzJztcclxuXHJcblx0fVxyXG5cclxuXHRjb21wdXRlTGluZURpc3RhbmNlcygpIHtcclxuXHJcblx0XHRjb25zdCBnZW9tZXRyeSA9IHRoaXMuZ2VvbWV0cnk7XHJcblxyXG5cdFx0Ly8gd2UgYXNzdW1lIG5vbi1pbmRleGVkIGdlb21ldHJ5XHJcblxyXG5cdFx0aWYgKCBnZW9tZXRyeS5pbmRleCA9PT0gbnVsbCApIHtcclxuXHJcblx0XHRcdGNvbnN0IHBvc2l0aW9uQXR0cmlidXRlID0gZ2VvbWV0cnkuYXR0cmlidXRlcy5wb3NpdGlvbjtcclxuXHRcdFx0Y29uc3QgbGluZURpc3RhbmNlcyA9IFtdO1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gcG9zaXRpb25BdHRyaWJ1dGUuY291bnQ7IGkgPCBsOyBpICs9IDIgKSB7XHJcblxyXG5cdFx0XHRcdF9zdGFydC5mcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbkF0dHJpYnV0ZSwgaSApO1xyXG5cdFx0XHRcdF9lbmQuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggcG9zaXRpb25BdHRyaWJ1dGUsIGkgKyAxICk7XHJcblxyXG5cdFx0XHRcdGxpbmVEaXN0YW5jZXNbIGkgXSA9ICggaSA9PT0gMCApID8gMCA6IGxpbmVEaXN0YW5jZXNbIGkgLSAxIF07XHJcblx0XHRcdFx0bGluZURpc3RhbmNlc1sgaSArIDEgXSA9IGxpbmVEaXN0YW5jZXNbIGkgXSArIF9zdGFydC5kaXN0YW5jZVRvKCBfZW5kICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRnZW9tZXRyeS5zZXRBdHRyaWJ1dGUoICdsaW5lRGlzdGFuY2UnLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggbGluZURpc3RhbmNlcywgMSApICk7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLkxpbmVTZWdtZW50cy5jb21wdXRlTGluZURpc3RhbmNlcygpOiBDb21wdXRhdGlvbiBvbmx5IHBvc3NpYmxlIHdpdGggbm9uLWluZGV4ZWQgQnVmZmVyR2VvbWV0cnkuJyApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgTGluZVNlZ21lbnRzIH07XHJcbiIsImltcG9ydCB7IExpbmUgfSBmcm9tICcuL0xpbmUuanMnO1xyXG5cclxuY2xhc3MgTGluZUxvb3AgZXh0ZW5kcyBMaW5lIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIGdlb21ldHJ5LCBtYXRlcmlhbCApIHtcclxuXHJcblx0XHRzdXBlciggZ2VvbWV0cnksIG1hdGVyaWFsICk7XHJcblxyXG5cdFx0dGhpcy5pc0xpbmVMb29wID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSAnTGluZUxvb3AnO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBMaW5lTG9vcCB9O1xyXG4iLCJpbXBvcnQgeyBNYXRlcmlhbCB9IGZyb20gJy4vTWF0ZXJpYWwuanMnO1xyXG5pbXBvcnQgeyBDb2xvciB9IGZyb20gJy4uL21hdGgvQ29sb3IuanMnO1xyXG5cclxuY2xhc3MgUG9pbnRzTWF0ZXJpYWwgZXh0ZW5kcyBNYXRlcmlhbCB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBwYXJhbWV0ZXJzICkge1xyXG5cclxuXHRcdHN1cGVyKCk7XHJcblxyXG5cdFx0dGhpcy5pc1BvaW50c01hdGVyaWFsID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSAnUG9pbnRzTWF0ZXJpYWwnO1xyXG5cclxuXHRcdHRoaXMuY29sb3IgPSBuZXcgQ29sb3IoIDB4ZmZmZmZmICk7XHJcblxyXG5cdFx0dGhpcy5tYXAgPSBudWxsO1xyXG5cclxuXHRcdHRoaXMuYWxwaGFNYXAgPSBudWxsO1xyXG5cclxuXHRcdHRoaXMuc2l6ZSA9IDE7XHJcblx0XHR0aGlzLnNpemVBdHRlbnVhdGlvbiA9IHRydWU7XHJcblxyXG5cdFx0dGhpcy5mb2cgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMuc2V0VmFsdWVzKCBwYXJhbWV0ZXJzICk7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xyXG5cclxuXHRcdHRoaXMuY29sb3IuY29weSggc291cmNlLmNvbG9yICk7XHJcblxyXG5cdFx0dGhpcy5tYXAgPSBzb3VyY2UubWFwO1xyXG5cclxuXHRcdHRoaXMuYWxwaGFNYXAgPSBzb3VyY2UuYWxwaGFNYXA7XHJcblxyXG5cdFx0dGhpcy5zaXplID0gc291cmNlLnNpemU7XHJcblx0XHR0aGlzLnNpemVBdHRlbnVhdGlvbiA9IHNvdXJjZS5zaXplQXR0ZW51YXRpb247XHJcblxyXG5cdFx0dGhpcy5mb2cgPSBzb3VyY2UuZm9nO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBQb2ludHNNYXRlcmlhbCB9O1xyXG4iLCJpbXBvcnQgeyBTcGhlcmUgfSBmcm9tICcuLi9tYXRoL1NwaGVyZS5qcyc7XHJcbmltcG9ydCB7IFJheSB9IGZyb20gJy4uL21hdGgvUmF5LmpzJztcclxuaW1wb3J0IHsgTWF0cml4NCB9IGZyb20gJy4uL21hdGgvTWF0cml4NC5qcyc7XHJcbmltcG9ydCB7IE9iamVjdDNEIH0gZnJvbSAnLi4vY29yZS9PYmplY3QzRC5qcyc7XHJcbmltcG9ydCB7IFZlY3RvcjMgfSBmcm9tICcuLi9tYXRoL1ZlY3RvcjMuanMnO1xyXG5pbXBvcnQgeyBQb2ludHNNYXRlcmlhbCB9IGZyb20gJy4uL21hdGVyaWFscy9Qb2ludHNNYXRlcmlhbC5qcyc7XHJcbmltcG9ydCB7IEJ1ZmZlckdlb21ldHJ5IH0gZnJvbSAnLi4vY29yZS9CdWZmZXJHZW9tZXRyeS5qcyc7XHJcblxyXG5jb25zdCBfaW52ZXJzZU1hdHJpeCA9IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDQoKTtcclxuY29uc3QgX3JheSA9IC8qQF9fUFVSRV9fKi8gbmV3IFJheSgpO1xyXG5jb25zdCBfc3BoZXJlID0gLypAX19QVVJFX18qLyBuZXcgU3BoZXJlKCk7XHJcbmNvbnN0IF9wb3NpdGlvbiA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuXHJcbmNsYXNzIFBvaW50cyBleHRlbmRzIE9iamVjdDNEIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIGdlb21ldHJ5ID0gbmV3IEJ1ZmZlckdlb21ldHJ5KCksIG1hdGVyaWFsID0gbmV3IFBvaW50c01hdGVyaWFsKCkgKSB7XHJcblxyXG5cdFx0c3VwZXIoKTtcclxuXHJcblx0XHR0aGlzLmlzUG9pbnRzID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSAnUG9pbnRzJztcclxuXHJcblx0XHR0aGlzLmdlb21ldHJ5ID0gZ2VvbWV0cnk7XHJcblx0XHR0aGlzLm1hdGVyaWFsID0gbWF0ZXJpYWw7XHJcblxyXG5cdFx0dGhpcy51cGRhdGVNb3JwaFRhcmdldHMoKTtcclxuXHJcblx0fVxyXG5cclxuXHRjb3B5KCBzb3VyY2UsIHJlY3Vyc2l2ZSApIHtcclxuXHJcblx0XHRzdXBlci5jb3B5KCBzb3VyY2UsIHJlY3Vyc2l2ZSApO1xyXG5cclxuXHRcdHRoaXMubWF0ZXJpYWwgPSBBcnJheS5pc0FycmF5KCBzb3VyY2UubWF0ZXJpYWwgKSA/IHNvdXJjZS5tYXRlcmlhbC5zbGljZSgpIDogc291cmNlLm1hdGVyaWFsO1xyXG5cdFx0dGhpcy5nZW9tZXRyeSA9IHNvdXJjZS5nZW9tZXRyeTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRyYXljYXN0KCByYXljYXN0ZXIsIGludGVyc2VjdHMgKSB7XHJcblxyXG5cdFx0Y29uc3QgZ2VvbWV0cnkgPSB0aGlzLmdlb21ldHJ5O1xyXG5cdFx0Y29uc3QgbWF0cml4V29ybGQgPSB0aGlzLm1hdHJpeFdvcmxkO1xyXG5cdFx0Y29uc3QgdGhyZXNob2xkID0gcmF5Y2FzdGVyLnBhcmFtcy5Qb2ludHMudGhyZXNob2xkO1xyXG5cdFx0Y29uc3QgZHJhd1JhbmdlID0gZ2VvbWV0cnkuZHJhd1JhbmdlO1xyXG5cclxuXHRcdC8vIENoZWNraW5nIGJvdW5kaW5nU3BoZXJlIGRpc3RhbmNlIHRvIHJheVxyXG5cclxuXHRcdGlmICggZ2VvbWV0cnkuYm91bmRpbmdTcGhlcmUgPT09IG51bGwgKSBnZW9tZXRyeS5jb21wdXRlQm91bmRpbmdTcGhlcmUoKTtcclxuXHJcblx0XHRfc3BoZXJlLmNvcHkoIGdlb21ldHJ5LmJvdW5kaW5nU3BoZXJlICk7XHJcblx0XHRfc3BoZXJlLmFwcGx5TWF0cml4NCggbWF0cml4V29ybGQgKTtcclxuXHRcdF9zcGhlcmUucmFkaXVzICs9IHRocmVzaG9sZDtcclxuXHJcblx0XHRpZiAoIHJheWNhc3Rlci5yYXkuaW50ZXJzZWN0c1NwaGVyZSggX3NwaGVyZSApID09PSBmYWxzZSApIHJldHVybjtcclxuXHJcblx0XHQvL1xyXG5cclxuXHRcdF9pbnZlcnNlTWF0cml4LmNvcHkoIG1hdHJpeFdvcmxkICkuaW52ZXJ0KCk7XHJcblx0XHRfcmF5LmNvcHkoIHJheWNhc3Rlci5yYXkgKS5hcHBseU1hdHJpeDQoIF9pbnZlcnNlTWF0cml4ICk7XHJcblxyXG5cdFx0Y29uc3QgbG9jYWxUaHJlc2hvbGQgPSB0aHJlc2hvbGQgLyAoICggdGhpcy5zY2FsZS54ICsgdGhpcy5zY2FsZS55ICsgdGhpcy5zY2FsZS56ICkgLyAzICk7XHJcblx0XHRjb25zdCBsb2NhbFRocmVzaG9sZFNxID0gbG9jYWxUaHJlc2hvbGQgKiBsb2NhbFRocmVzaG9sZDtcclxuXHJcblx0XHRjb25zdCBpbmRleCA9IGdlb21ldHJ5LmluZGV4O1xyXG5cdFx0Y29uc3QgYXR0cmlidXRlcyA9IGdlb21ldHJ5LmF0dHJpYnV0ZXM7XHJcblx0XHRjb25zdCBwb3NpdGlvbkF0dHJpYnV0ZSA9IGF0dHJpYnV0ZXMucG9zaXRpb247XHJcblxyXG5cdFx0aWYgKCBpbmRleCAhPT0gbnVsbCApIHtcclxuXHJcblx0XHRcdGNvbnN0IHN0YXJ0ID0gTWF0aC5tYXgoIDAsIGRyYXdSYW5nZS5zdGFydCApO1xyXG5cdFx0XHRjb25zdCBlbmQgPSBNYXRoLm1pbiggaW5kZXguY291bnQsICggZHJhd1JhbmdlLnN0YXJ0ICsgZHJhd1JhbmdlLmNvdW50ICkgKTtcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gc3RhcnQsIGlsID0gZW5kOyBpIDwgaWw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IGEgPSBpbmRleC5nZXRYKCBpICk7XHJcblxyXG5cdFx0XHRcdF9wb3NpdGlvbi5mcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbkF0dHJpYnV0ZSwgYSApO1xyXG5cclxuXHRcdFx0XHR0ZXN0UG9pbnQoIF9wb3NpdGlvbiwgYSwgbG9jYWxUaHJlc2hvbGRTcSwgbWF0cml4V29ybGQsIHJheWNhc3RlciwgaW50ZXJzZWN0cywgdGhpcyApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRjb25zdCBzdGFydCA9IE1hdGgubWF4KCAwLCBkcmF3UmFuZ2Uuc3RhcnQgKTtcclxuXHRcdFx0Y29uc3QgZW5kID0gTWF0aC5taW4oIHBvc2l0aW9uQXR0cmlidXRlLmNvdW50LCAoIGRyYXdSYW5nZS5zdGFydCArIGRyYXdSYW5nZS5jb3VudCApICk7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IHN0YXJ0LCBsID0gZW5kOyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0X3Bvc2l0aW9uLmZyb21CdWZmZXJBdHRyaWJ1dGUoIHBvc2l0aW9uQXR0cmlidXRlLCBpICk7XHJcblxyXG5cdFx0XHRcdHRlc3RQb2ludCggX3Bvc2l0aW9uLCBpLCBsb2NhbFRocmVzaG9sZFNxLCBtYXRyaXhXb3JsZCwgcmF5Y2FzdGVyLCBpbnRlcnNlY3RzLCB0aGlzICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdHVwZGF0ZU1vcnBoVGFyZ2V0cygpIHtcclxuXHJcblx0XHRjb25zdCBnZW9tZXRyeSA9IHRoaXMuZ2VvbWV0cnk7XHJcblxyXG5cdFx0Y29uc3QgbW9ycGhBdHRyaWJ1dGVzID0gZ2VvbWV0cnkubW9ycGhBdHRyaWJ1dGVzO1xyXG5cdFx0Y29uc3Qga2V5cyA9IE9iamVjdC5rZXlzKCBtb3JwaEF0dHJpYnV0ZXMgKTtcclxuXHJcblx0XHRpZiAoIGtleXMubGVuZ3RoID4gMCApIHtcclxuXHJcblx0XHRcdGNvbnN0IG1vcnBoQXR0cmlidXRlID0gbW9ycGhBdHRyaWJ1dGVzWyBrZXlzWyAwIF0gXTtcclxuXHJcblx0XHRcdGlmICggbW9ycGhBdHRyaWJ1dGUgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0dGhpcy5tb3JwaFRhcmdldEluZmx1ZW5jZXMgPSBbXTtcclxuXHRcdFx0XHR0aGlzLm1vcnBoVGFyZ2V0RGljdGlvbmFyeSA9IHt9O1xyXG5cclxuXHRcdFx0XHRmb3IgKCBsZXQgbSA9IDAsIG1sID0gbW9ycGhBdHRyaWJ1dGUubGVuZ3RoOyBtIDwgbWw7IG0gKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgbmFtZSA9IG1vcnBoQXR0cmlidXRlWyBtIF0ubmFtZSB8fCBTdHJpbmcoIG0gKTtcclxuXHJcblx0XHRcdFx0XHR0aGlzLm1vcnBoVGFyZ2V0SW5mbHVlbmNlcy5wdXNoKCAwICk7XHJcblx0XHRcdFx0XHR0aGlzLm1vcnBoVGFyZ2V0RGljdGlvbmFyeVsgbmFtZSBdID0gbTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gdGVzdFBvaW50KCBwb2ludCwgaW5kZXgsIGxvY2FsVGhyZXNob2xkU3EsIG1hdHJpeFdvcmxkLCByYXljYXN0ZXIsIGludGVyc2VjdHMsIG9iamVjdCApIHtcclxuXHJcblx0Y29uc3QgcmF5UG9pbnREaXN0YW5jZVNxID0gX3JheS5kaXN0YW5jZVNxVG9Qb2ludCggcG9pbnQgKTtcclxuXHJcblx0aWYgKCByYXlQb2ludERpc3RhbmNlU3EgPCBsb2NhbFRocmVzaG9sZFNxICkge1xyXG5cclxuXHRcdGNvbnN0IGludGVyc2VjdFBvaW50ID0gbmV3IFZlY3RvcjMoKTtcclxuXHJcblx0XHRfcmF5LmNsb3Nlc3RQb2ludFRvUG9pbnQoIHBvaW50LCBpbnRlcnNlY3RQb2ludCApO1xyXG5cdFx0aW50ZXJzZWN0UG9pbnQuYXBwbHlNYXRyaXg0KCBtYXRyaXhXb3JsZCApO1xyXG5cclxuXHRcdGNvbnN0IGRpc3RhbmNlID0gcmF5Y2FzdGVyLnJheS5vcmlnaW4uZGlzdGFuY2VUbyggaW50ZXJzZWN0UG9pbnQgKTtcclxuXHJcblx0XHRpZiAoIGRpc3RhbmNlIDwgcmF5Y2FzdGVyLm5lYXIgfHwgZGlzdGFuY2UgPiByYXljYXN0ZXIuZmFyICkgcmV0dXJuO1xyXG5cclxuXHRcdGludGVyc2VjdHMucHVzaCgge1xyXG5cclxuXHRcdFx0ZGlzdGFuY2U6IGRpc3RhbmNlLFxyXG5cdFx0XHRkaXN0YW5jZVRvUmF5OiBNYXRoLnNxcnQoIHJheVBvaW50RGlzdGFuY2VTcSApLFxyXG5cdFx0XHRwb2ludDogaW50ZXJzZWN0UG9pbnQsXHJcblx0XHRcdGluZGV4OiBpbmRleCxcclxuXHRcdFx0ZmFjZTogbnVsbCxcclxuXHRcdFx0b2JqZWN0OiBvYmplY3RcclxuXHJcblx0XHR9ICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IFBvaW50cyB9O1xyXG4iLCJpbXBvcnQgeyBMaW5lYXJGaWx0ZXIgfSBmcm9tICcuLi9jb25zdGFudHMuanMnO1xyXG5pbXBvcnQgeyBUZXh0dXJlIH0gZnJvbSAnLi9UZXh0dXJlLmpzJztcclxuXHJcbmNsYXNzIFZpZGVvVGV4dHVyZSBleHRlbmRzIFRleHR1cmUge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggdmlkZW8sIG1hcHBpbmcsIHdyYXBTLCB3cmFwVCwgbWFnRmlsdGVyLCBtaW5GaWx0ZXIsIGZvcm1hdCwgdHlwZSwgYW5pc290cm9weSApIHtcclxuXHJcblx0XHRzdXBlciggdmlkZW8sIG1hcHBpbmcsIHdyYXBTLCB3cmFwVCwgbWFnRmlsdGVyLCBtaW5GaWx0ZXIsIGZvcm1hdCwgdHlwZSwgYW5pc290cm9weSApO1xyXG5cclxuXHRcdHRoaXMuaXNWaWRlb1RleHR1cmUgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMubWluRmlsdGVyID0gbWluRmlsdGVyICE9PSB1bmRlZmluZWQgPyBtaW5GaWx0ZXIgOiBMaW5lYXJGaWx0ZXI7XHJcblx0XHR0aGlzLm1hZ0ZpbHRlciA9IG1hZ0ZpbHRlciAhPT0gdW5kZWZpbmVkID8gbWFnRmlsdGVyIDogTGluZWFyRmlsdGVyO1xyXG5cclxuXHRcdHRoaXMuZ2VuZXJhdGVNaXBtYXBzID0gZmFsc2U7XHJcblxyXG5cdFx0Y29uc3Qgc2NvcGUgPSB0aGlzO1xyXG5cclxuXHRcdGZ1bmN0aW9uIHVwZGF0ZVZpZGVvKCkge1xyXG5cclxuXHRcdFx0c2NvcGUubmVlZHNVcGRhdGUgPSB0cnVlO1xyXG5cdFx0XHR2aWRlby5yZXF1ZXN0VmlkZW9GcmFtZUNhbGxiYWNrKCB1cGRhdGVWaWRlbyApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoICdyZXF1ZXN0VmlkZW9GcmFtZUNhbGxiYWNrJyBpbiB2aWRlbyApIHtcclxuXHJcblx0XHRcdHZpZGVvLnJlcXVlc3RWaWRlb0ZyYW1lQ2FsbGJhY2soIHVwZGF0ZVZpZGVvICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGNsb25lKCkge1xyXG5cclxuXHRcdHJldHVybiBuZXcgdGhpcy5jb25zdHJ1Y3RvciggdGhpcy5pbWFnZSApLmNvcHkoIHRoaXMgKTtcclxuXHJcblx0fVxyXG5cclxuXHR1cGRhdGUoKSB7XHJcblxyXG5cdFx0Y29uc3QgdmlkZW8gPSB0aGlzLmltYWdlO1xyXG5cdFx0Y29uc3QgaGFzVmlkZW9GcmFtZUNhbGxiYWNrID0gJ3JlcXVlc3RWaWRlb0ZyYW1lQ2FsbGJhY2snIGluIHZpZGVvO1xyXG5cclxuXHRcdGlmICggaGFzVmlkZW9GcmFtZUNhbGxiYWNrID09PSBmYWxzZSAmJiB2aWRlby5yZWFkeVN0YXRlID49IHZpZGVvLkhBVkVfQ1VSUkVOVF9EQVRBICkge1xyXG5cclxuXHRcdFx0dGhpcy5uZWVkc1VwZGF0ZSA9IHRydWU7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBWaWRlb1RleHR1cmUgfTtcclxuIiwiaW1wb3J0IHsgVGV4dHVyZSB9IGZyb20gJy4vVGV4dHVyZS5qcyc7XHJcbmltcG9ydCB7IE5lYXJlc3RGaWx0ZXIgfSBmcm9tICcuLi9jb25zdGFudHMuanMnO1xyXG5cclxuY2xhc3MgRnJhbWVidWZmZXJUZXh0dXJlIGV4dGVuZHMgVGV4dHVyZSB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCB3aWR0aCwgaGVpZ2h0ICkge1xyXG5cclxuXHRcdHN1cGVyKCB7IHdpZHRoLCBoZWlnaHQgfSApO1xyXG5cclxuXHRcdHRoaXMuaXNGcmFtZWJ1ZmZlclRleHR1cmUgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMubWFnRmlsdGVyID0gTmVhcmVzdEZpbHRlcjtcclxuXHRcdHRoaXMubWluRmlsdGVyID0gTmVhcmVzdEZpbHRlcjtcclxuXHJcblx0XHR0aGlzLmdlbmVyYXRlTWlwbWFwcyA9IGZhbHNlO1xyXG5cclxuXHRcdHRoaXMubmVlZHNVcGRhdGUgPSB0cnVlO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBGcmFtZWJ1ZmZlclRleHR1cmUgfTtcclxuIiwiaW1wb3J0IHsgVGV4dHVyZSB9IGZyb20gJy4vVGV4dHVyZS5qcyc7XHJcblxyXG5jbGFzcyBDb21wcmVzc2VkVGV4dHVyZSBleHRlbmRzIFRleHR1cmUge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggbWlwbWFwcywgd2lkdGgsIGhlaWdodCwgZm9ybWF0LCB0eXBlLCBtYXBwaW5nLCB3cmFwUywgd3JhcFQsIG1hZ0ZpbHRlciwgbWluRmlsdGVyLCBhbmlzb3Ryb3B5LCBjb2xvclNwYWNlICkge1xyXG5cclxuXHRcdHN1cGVyKCBudWxsLCBtYXBwaW5nLCB3cmFwUywgd3JhcFQsIG1hZ0ZpbHRlciwgbWluRmlsdGVyLCBmb3JtYXQsIHR5cGUsIGFuaXNvdHJvcHksIGNvbG9yU3BhY2UgKTtcclxuXHJcblx0XHR0aGlzLmlzQ29tcHJlc3NlZFRleHR1cmUgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMuaW1hZ2UgPSB7IHdpZHRoOiB3aWR0aCwgaGVpZ2h0OiBoZWlnaHQgfTtcclxuXHRcdHRoaXMubWlwbWFwcyA9IG1pcG1hcHM7XHJcblxyXG5cdFx0Ly8gbm8gZmxpcHBpbmcgZm9yIGN1YmUgdGV4dHVyZXNcclxuXHRcdC8vIChhbHNvIGZsaXBwaW5nIGRvZXNuJ3Qgd29yayBmb3IgY29tcHJlc3NlZCB0ZXh0dXJlcyApXHJcblxyXG5cdFx0dGhpcy5mbGlwWSA9IGZhbHNlO1xyXG5cclxuXHRcdC8vIGNhbid0IGdlbmVyYXRlIG1pcG1hcHMgZm9yIGNvbXByZXNzZWQgdGV4dHVyZXNcclxuXHRcdC8vIG1pcHMgbXVzdCBiZSBlbWJlZGRlZCBpbiBERFMgZmlsZXNcclxuXHJcblx0XHR0aGlzLmdlbmVyYXRlTWlwbWFwcyA9IGZhbHNlO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBDb21wcmVzc2VkVGV4dHVyZSB9O1xyXG4iLCJpbXBvcnQgeyBDbGFtcFRvRWRnZVdyYXBwaW5nIH0gZnJvbSAnLi4vY29uc3RhbnRzLmpzJztcclxuaW1wb3J0IHsgQ29tcHJlc3NlZFRleHR1cmUgfSBmcm9tICcuL0NvbXByZXNzZWRUZXh0dXJlLmpzJztcclxuXHJcbmNsYXNzIENvbXByZXNzZWRBcnJheVRleHR1cmUgZXh0ZW5kcyBDb21wcmVzc2VkVGV4dHVyZSB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBtaXBtYXBzLCB3aWR0aCwgaGVpZ2h0LCBkZXB0aCwgZm9ybWF0LCB0eXBlICkge1xyXG5cclxuXHRcdHN1cGVyKCBtaXBtYXBzLCB3aWR0aCwgaGVpZ2h0LCBmb3JtYXQsIHR5cGUgKTtcclxuXHJcblx0XHR0aGlzLmlzQ29tcHJlc3NlZEFycmF5VGV4dHVyZSA9IHRydWU7XHJcblx0XHR0aGlzLmltYWdlLmRlcHRoID0gZGVwdGg7XHJcblx0XHR0aGlzLndyYXBSID0gQ2xhbXBUb0VkZ2VXcmFwcGluZztcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgQ29tcHJlc3NlZEFycmF5VGV4dHVyZSB9O1xyXG4iLCJpbXBvcnQgeyBDdWJlUmVmbGVjdGlvbk1hcHBpbmcgfSBmcm9tICcuLi9jb25zdGFudHMuanMnO1xyXG5pbXBvcnQgeyBDb21wcmVzc2VkVGV4dHVyZSB9IGZyb20gJy4vQ29tcHJlc3NlZFRleHR1cmUuanMnO1xyXG5cclxuY2xhc3MgQ29tcHJlc3NlZEN1YmVUZXh0dXJlIGV4dGVuZHMgQ29tcHJlc3NlZFRleHR1cmUge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggaW1hZ2VzLCBmb3JtYXQsIHR5cGUgKSB7XHJcblxyXG5cdFx0c3VwZXIoIHVuZGVmaW5lZCwgaW1hZ2VzWyAwIF0ud2lkdGgsIGltYWdlc1sgMCBdLmhlaWdodCwgZm9ybWF0LCB0eXBlLCBDdWJlUmVmbGVjdGlvbk1hcHBpbmcgKTtcclxuXHJcblx0XHR0aGlzLmlzQ29tcHJlc3NlZEN1YmVUZXh0dXJlID0gdHJ1ZTtcclxuXHRcdHRoaXMuaXNDdWJlVGV4dHVyZSA9IHRydWU7XHJcblxyXG5cdFx0dGhpcy5pbWFnZSA9IGltYWdlcztcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgQ29tcHJlc3NlZEN1YmVUZXh0dXJlIH07XHJcbiIsImltcG9ydCB7IFRleHR1cmUgfSBmcm9tICcuL1RleHR1cmUuanMnO1xyXG5cclxuY2xhc3MgQ2FudmFzVGV4dHVyZSBleHRlbmRzIFRleHR1cmUge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggY2FudmFzLCBtYXBwaW5nLCB3cmFwUywgd3JhcFQsIG1hZ0ZpbHRlciwgbWluRmlsdGVyLCBmb3JtYXQsIHR5cGUsIGFuaXNvdHJvcHkgKSB7XHJcblxyXG5cdFx0c3VwZXIoIGNhbnZhcywgbWFwcGluZywgd3JhcFMsIHdyYXBULCBtYWdGaWx0ZXIsIG1pbkZpbHRlciwgZm9ybWF0LCB0eXBlLCBhbmlzb3Ryb3B5ICk7XHJcblxyXG5cdFx0dGhpcy5pc0NhbnZhc1RleHR1cmUgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMubmVlZHNVcGRhdGUgPSB0cnVlO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBDYW52YXNUZXh0dXJlIH07XHJcbiIsImltcG9ydCAqIGFzIE1hdGhVdGlscyBmcm9tICcuLi8uLi9tYXRoL01hdGhVdGlscy5qcyc7XHJcbmltcG9ydCB7IFZlY3RvcjIgfSBmcm9tICcuLi8uLi9tYXRoL1ZlY3RvcjIuanMnO1xyXG5pbXBvcnQgeyBWZWN0b3IzIH0gZnJvbSAnLi4vLi4vbWF0aC9WZWN0b3IzLmpzJztcclxuaW1wb3J0IHsgTWF0cml4NCB9IGZyb20gJy4uLy4uL21hdGgvTWF0cml4NC5qcyc7XHJcblxyXG4vKipcclxuICogRXh0ZW5zaWJsZSBjdXJ2ZSBvYmplY3QuXHJcbiAqXHJcbiAqIFNvbWUgY29tbW9uIG9mIGN1cnZlIG1ldGhvZHM6XHJcbiAqIC5nZXRQb2ludCggdCwgb3B0aW9uYWxUYXJnZXQgKSwgLmdldFRhbmdlbnQoIHQsIG9wdGlvbmFsVGFyZ2V0IClcclxuICogLmdldFBvaW50QXQoIHUsIG9wdGlvbmFsVGFyZ2V0ICksIC5nZXRUYW5nZW50QXQoIHUsIG9wdGlvbmFsVGFyZ2V0IClcclxuICogLmdldFBvaW50cygpLCAuZ2V0U3BhY2VkUG9pbnRzKClcclxuICogLmdldExlbmd0aCgpXHJcbiAqIC51cGRhdGVBcmNMZW5ndGhzKClcclxuICpcclxuICogVGhpcyBmb2xsb3dpbmcgY3VydmVzIGluaGVyaXQgZnJvbSBUSFJFRS5DdXJ2ZTpcclxuICpcclxuICogLS0gMkQgY3VydmVzIC0tXHJcbiAqIFRIUkVFLkFyY0N1cnZlXHJcbiAqIFRIUkVFLkN1YmljQmV6aWVyQ3VydmVcclxuICogVEhSRUUuRWxsaXBzZUN1cnZlXHJcbiAqIFRIUkVFLkxpbmVDdXJ2ZVxyXG4gKiBUSFJFRS5RdWFkcmF0aWNCZXppZXJDdXJ2ZVxyXG4gKiBUSFJFRS5TcGxpbmVDdXJ2ZVxyXG4gKlxyXG4gKiAtLSAzRCBjdXJ2ZXMgLS1cclxuICogVEhSRUUuQ2F0bXVsbFJvbUN1cnZlM1xyXG4gKiBUSFJFRS5DdWJpY0JlemllckN1cnZlM1xyXG4gKiBUSFJFRS5MaW5lQ3VydmUzXHJcbiAqIFRIUkVFLlF1YWRyYXRpY0JlemllckN1cnZlM1xyXG4gKlxyXG4gKiBBIHNlcmllcyBvZiBjdXJ2ZXMgY2FuIGJlIHJlcHJlc2VudGVkIGFzIGEgVEhSRUUuQ3VydmVQYXRoLlxyXG4gKlxyXG4gKiovXHJcblxyXG5jbGFzcyBDdXJ2ZSB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCkge1xyXG5cclxuXHRcdHRoaXMudHlwZSA9ICdDdXJ2ZSc7XHJcblxyXG5cdFx0dGhpcy5hcmNMZW5ndGhEaXZpc2lvbnMgPSAyMDA7XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gVmlydHVhbCBiYXNlIGNsYXNzIG1ldGhvZCB0byBvdmVyd3JpdGUgYW5kIGltcGxlbWVudCBpbiBzdWJjbGFzc2VzXHJcblx0Ly9cdC0gdCBbMCAuLiAxXVxyXG5cclxuXHRnZXRQb2ludCggLyogdCwgb3B0aW9uYWxUYXJnZXQgKi8gKSB7XHJcblxyXG5cdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuQ3VydmU6IC5nZXRQb2ludCgpIG5vdCBpbXBsZW1lbnRlZC4nICk7XHJcblx0XHRyZXR1cm4gbnVsbDtcclxuXHJcblx0fVxyXG5cclxuXHQvLyBHZXQgcG9pbnQgYXQgcmVsYXRpdmUgcG9zaXRpb24gaW4gY3VydmUgYWNjb3JkaW5nIHRvIGFyYyBsZW5ndGhcclxuXHQvLyAtIHUgWzAgLi4gMV1cclxuXHJcblx0Z2V0UG9pbnRBdCggdSwgb3B0aW9uYWxUYXJnZXQgKSB7XHJcblxyXG5cdFx0Y29uc3QgdCA9IHRoaXMuZ2V0VXRvVG1hcHBpbmcoIHUgKTtcclxuXHRcdHJldHVybiB0aGlzLmdldFBvaW50KCB0LCBvcHRpb25hbFRhcmdldCApO1xyXG5cclxuXHR9XHJcblxyXG5cdC8vIEdldCBzZXF1ZW5jZSBvZiBwb2ludHMgdXNpbmcgZ2V0UG9pbnQoIHQgKVxyXG5cclxuXHRnZXRQb2ludHMoIGRpdmlzaW9ucyA9IDUgKSB7XHJcblxyXG5cdFx0Y29uc3QgcG9pbnRzID0gW107XHJcblxyXG5cdFx0Zm9yICggbGV0IGQgPSAwOyBkIDw9IGRpdmlzaW9uczsgZCArKyApIHtcclxuXHJcblx0XHRcdHBvaW50cy5wdXNoKCB0aGlzLmdldFBvaW50KCBkIC8gZGl2aXNpb25zICkgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHBvaW50cztcclxuXHJcblx0fVxyXG5cclxuXHQvLyBHZXQgc2VxdWVuY2Ugb2YgcG9pbnRzIHVzaW5nIGdldFBvaW50QXQoIHUgKVxyXG5cclxuXHRnZXRTcGFjZWRQb2ludHMoIGRpdmlzaW9ucyA9IDUgKSB7XHJcblxyXG5cdFx0Y29uc3QgcG9pbnRzID0gW107XHJcblxyXG5cdFx0Zm9yICggbGV0IGQgPSAwOyBkIDw9IGRpdmlzaW9uczsgZCArKyApIHtcclxuXHJcblx0XHRcdHBvaW50cy5wdXNoKCB0aGlzLmdldFBvaW50QXQoIGQgLyBkaXZpc2lvbnMgKSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gcG9pbnRzO1xyXG5cclxuXHR9XHJcblxyXG5cdC8vIEdldCB0b3RhbCBjdXJ2ZSBhcmMgbGVuZ3RoXHJcblxyXG5cdGdldExlbmd0aCgpIHtcclxuXHJcblx0XHRjb25zdCBsZW5ndGhzID0gdGhpcy5nZXRMZW5ndGhzKCk7XHJcblx0XHRyZXR1cm4gbGVuZ3Roc1sgbGVuZ3Rocy5sZW5ndGggLSAxIF07XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gR2V0IGxpc3Qgb2YgY3VtdWxhdGl2ZSBzZWdtZW50IGxlbmd0aHNcclxuXHJcblx0Z2V0TGVuZ3RocyggZGl2aXNpb25zID0gdGhpcy5hcmNMZW5ndGhEaXZpc2lvbnMgKSB7XHJcblxyXG5cdFx0aWYgKCB0aGlzLmNhY2hlQXJjTGVuZ3RocyAmJlxyXG5cdFx0XHQoIHRoaXMuY2FjaGVBcmNMZW5ndGhzLmxlbmd0aCA9PT0gZGl2aXNpb25zICsgMSApICYmXHJcblx0XHRcdCEgdGhpcy5uZWVkc1VwZGF0ZSApIHtcclxuXHJcblx0XHRcdHJldHVybiB0aGlzLmNhY2hlQXJjTGVuZ3RocztcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5uZWVkc1VwZGF0ZSA9IGZhbHNlO1xyXG5cclxuXHRcdGNvbnN0IGNhY2hlID0gW107XHJcblx0XHRsZXQgY3VycmVudCwgbGFzdCA9IHRoaXMuZ2V0UG9pbnQoIDAgKTtcclxuXHRcdGxldCBzdW0gPSAwO1xyXG5cclxuXHRcdGNhY2hlLnB1c2goIDAgKTtcclxuXHJcblx0XHRmb3IgKCBsZXQgcCA9IDE7IHAgPD0gZGl2aXNpb25zOyBwICsrICkge1xyXG5cclxuXHRcdFx0Y3VycmVudCA9IHRoaXMuZ2V0UG9pbnQoIHAgLyBkaXZpc2lvbnMgKTtcclxuXHRcdFx0c3VtICs9IGN1cnJlbnQuZGlzdGFuY2VUbyggbGFzdCApO1xyXG5cdFx0XHRjYWNoZS5wdXNoKCBzdW0gKTtcclxuXHRcdFx0bGFzdCA9IGN1cnJlbnQ7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMuY2FjaGVBcmNMZW5ndGhzID0gY2FjaGU7XHJcblxyXG5cdFx0cmV0dXJuIGNhY2hlOyAvLyB7IHN1bXM6IGNhY2hlLCBzdW06IHN1bSB9OyBTdW0gaXMgaW4gdGhlIGxhc3QgZWxlbWVudC5cclxuXHJcblx0fVxyXG5cclxuXHR1cGRhdGVBcmNMZW5ndGhzKCkge1xyXG5cclxuXHRcdHRoaXMubmVlZHNVcGRhdGUgPSB0cnVlO1xyXG5cdFx0dGhpcy5nZXRMZW5ndGhzKCk7XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gR2l2ZW4gdSAoIDAgLi4gMSApLCBnZXQgYSB0IHRvIGZpbmQgcC4gVGhpcyBnaXZlcyB5b3UgcG9pbnRzIHdoaWNoIGFyZSBlcXVpZGlzdGFudFxyXG5cclxuXHRnZXRVdG9UbWFwcGluZyggdSwgZGlzdGFuY2UgKSB7XHJcblxyXG5cdFx0Y29uc3QgYXJjTGVuZ3RocyA9IHRoaXMuZ2V0TGVuZ3RocygpO1xyXG5cclxuXHRcdGxldCBpID0gMDtcclxuXHRcdGNvbnN0IGlsID0gYXJjTGVuZ3Rocy5sZW5ndGg7XHJcblxyXG5cdFx0bGV0IHRhcmdldEFyY0xlbmd0aDsgLy8gVGhlIHRhcmdldGVkIHUgZGlzdGFuY2UgdmFsdWUgdG8gZ2V0XHJcblxyXG5cdFx0aWYgKCBkaXN0YW5jZSApIHtcclxuXHJcblx0XHRcdHRhcmdldEFyY0xlbmd0aCA9IGRpc3RhbmNlO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHR0YXJnZXRBcmNMZW5ndGggPSB1ICogYXJjTGVuZ3Roc1sgaWwgLSAxIF07XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIGJpbmFyeSBzZWFyY2ggZm9yIHRoZSBpbmRleCB3aXRoIGxhcmdlc3QgdmFsdWUgc21hbGxlciB0aGFuIHRhcmdldCB1IGRpc3RhbmNlXHJcblxyXG5cdFx0bGV0IGxvdyA9IDAsIGhpZ2ggPSBpbCAtIDEsIGNvbXBhcmlzb247XHJcblxyXG5cdFx0d2hpbGUgKCBsb3cgPD0gaGlnaCApIHtcclxuXHJcblx0XHRcdGkgPSBNYXRoLmZsb29yKCBsb3cgKyAoIGhpZ2ggLSBsb3cgKSAvIDIgKTsgLy8gbGVzcyBsaWtlbHkgdG8gb3ZlcmZsb3csIHRob3VnaCBwcm9iYWJseSBub3QgaXNzdWUgaGVyZSwgSlMgZG9lc24ndCByZWFsbHkgaGF2ZSBpbnRlZ2VycywgYWxsIG51bWJlcnMgYXJlIGZsb2F0c1xyXG5cclxuXHRcdFx0Y29tcGFyaXNvbiA9IGFyY0xlbmd0aHNbIGkgXSAtIHRhcmdldEFyY0xlbmd0aDtcclxuXHJcblx0XHRcdGlmICggY29tcGFyaXNvbiA8IDAgKSB7XHJcblxyXG5cdFx0XHRcdGxvdyA9IGkgKyAxO1xyXG5cclxuXHRcdFx0fSBlbHNlIGlmICggY29tcGFyaXNvbiA+IDAgKSB7XHJcblxyXG5cdFx0XHRcdGhpZ2ggPSBpIC0gMTtcclxuXHJcblx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdGhpZ2ggPSBpO1xyXG5cdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0XHQvLyBET05FXHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGkgPSBoaWdoO1xyXG5cclxuXHRcdGlmICggYXJjTGVuZ3Roc1sgaSBdID09PSB0YXJnZXRBcmNMZW5ndGggKSB7XHJcblxyXG5cdFx0XHRyZXR1cm4gaSAvICggaWwgLSAxICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIHdlIGNvdWxkIGdldCBmaW5lciBncmFpbiBhdCBsZW5ndGhzLCBvciB1c2Ugc2ltcGxlIGludGVycG9sYXRpb24gYmV0d2VlbiB0d28gcG9pbnRzXHJcblxyXG5cdFx0Y29uc3QgbGVuZ3RoQmVmb3JlID0gYXJjTGVuZ3Roc1sgaSBdO1xyXG5cdFx0Y29uc3QgbGVuZ3RoQWZ0ZXIgPSBhcmNMZW5ndGhzWyBpICsgMSBdO1xyXG5cclxuXHRcdGNvbnN0IHNlZ21lbnRMZW5ndGggPSBsZW5ndGhBZnRlciAtIGxlbmd0aEJlZm9yZTtcclxuXHJcblx0XHQvLyBkZXRlcm1pbmUgd2hlcmUgd2UgYXJlIGJldHdlZW4gdGhlICdiZWZvcmUnIGFuZCAnYWZ0ZXInIHBvaW50c1xyXG5cclxuXHRcdGNvbnN0IHNlZ21lbnRGcmFjdGlvbiA9ICggdGFyZ2V0QXJjTGVuZ3RoIC0gbGVuZ3RoQmVmb3JlICkgLyBzZWdtZW50TGVuZ3RoO1xyXG5cclxuXHRcdC8vIGFkZCB0aGF0IGZyYWN0aW9uYWwgYW1vdW50IHRvIHRcclxuXHJcblx0XHRjb25zdCB0ID0gKCBpICsgc2VnbWVudEZyYWN0aW9uICkgLyAoIGlsIC0gMSApO1xyXG5cclxuXHRcdHJldHVybiB0O1xyXG5cclxuXHR9XHJcblxyXG5cdC8vIFJldHVybnMgYSB1bml0IHZlY3RvciB0YW5nZW50IGF0IHRcclxuXHQvLyBJbiBjYXNlIGFueSBzdWIgY3VydmUgZG9lcyBub3QgaW1wbGVtZW50IGl0cyB0YW5nZW50IGRlcml2YXRpb24sXHJcblx0Ly8gMiBwb2ludHMgYSBzbWFsbCBkZWx0YSBhcGFydCB3aWxsIGJlIHVzZWQgdG8gZmluZCBpdHMgZ3JhZGllbnRcclxuXHQvLyB3aGljaCBzZWVtcyB0byBnaXZlIGEgcmVhc29uYWJsZSBhcHByb3hpbWF0aW9uXHJcblxyXG5cdGdldFRhbmdlbnQoIHQsIG9wdGlvbmFsVGFyZ2V0ICkge1xyXG5cclxuXHRcdGNvbnN0IGRlbHRhID0gMC4wMDAxO1xyXG5cdFx0bGV0IHQxID0gdCAtIGRlbHRhO1xyXG5cdFx0bGV0IHQyID0gdCArIGRlbHRhO1xyXG5cclxuXHRcdC8vIENhcHBpbmcgaW4gY2FzZSBvZiBkYW5nZXJcclxuXHJcblx0XHRpZiAoIHQxIDwgMCApIHQxID0gMDtcclxuXHRcdGlmICggdDIgPiAxICkgdDIgPSAxO1xyXG5cclxuXHRcdGNvbnN0IHB0MSA9IHRoaXMuZ2V0UG9pbnQoIHQxICk7XHJcblx0XHRjb25zdCBwdDIgPSB0aGlzLmdldFBvaW50KCB0MiApO1xyXG5cclxuXHRcdGNvbnN0IHRhbmdlbnQgPSBvcHRpb25hbFRhcmdldCB8fCAoICggcHQxLmlzVmVjdG9yMiApID8gbmV3IFZlY3RvcjIoKSA6IG5ldyBWZWN0b3IzKCkgKTtcclxuXHJcblx0XHR0YW5nZW50LmNvcHkoIHB0MiApLnN1YiggcHQxICkubm9ybWFsaXplKCk7XHJcblxyXG5cdFx0cmV0dXJuIHRhbmdlbnQ7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0VGFuZ2VudEF0KCB1LCBvcHRpb25hbFRhcmdldCApIHtcclxuXHJcblx0XHRjb25zdCB0ID0gdGhpcy5nZXRVdG9UbWFwcGluZyggdSApO1xyXG5cdFx0cmV0dXJuIHRoaXMuZ2V0VGFuZ2VudCggdCwgb3B0aW9uYWxUYXJnZXQgKTtcclxuXHJcblx0fVxyXG5cclxuXHRjb21wdXRlRnJlbmV0RnJhbWVzKCBzZWdtZW50cywgY2xvc2VkICkge1xyXG5cclxuXHRcdC8vIHNlZSBodHRwOi8vd3d3LmNzLmluZGlhbmEuZWR1L3B1Yi90ZWNocmVwb3J0cy9UUjQyNS5wZGZcclxuXHJcblx0XHRjb25zdCBub3JtYWwgPSBuZXcgVmVjdG9yMygpO1xyXG5cclxuXHRcdGNvbnN0IHRhbmdlbnRzID0gW107XHJcblx0XHRjb25zdCBub3JtYWxzID0gW107XHJcblx0XHRjb25zdCBiaW5vcm1hbHMgPSBbXTtcclxuXHJcblx0XHRjb25zdCB2ZWMgPSBuZXcgVmVjdG9yMygpO1xyXG5cdFx0Y29uc3QgbWF0ID0gbmV3IE1hdHJpeDQoKTtcclxuXHJcblx0XHQvLyBjb21wdXRlIHRoZSB0YW5nZW50IHZlY3RvcnMgZm9yIGVhY2ggc2VnbWVudCBvbiB0aGUgY3VydmVcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPD0gc2VnbWVudHM7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRjb25zdCB1ID0gaSAvIHNlZ21lbnRzO1xyXG5cclxuXHRcdFx0dGFuZ2VudHNbIGkgXSA9IHRoaXMuZ2V0VGFuZ2VudEF0KCB1LCBuZXcgVmVjdG9yMygpICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIHNlbGVjdCBhbiBpbml0aWFsIG5vcm1hbCB2ZWN0b3IgcGVycGVuZGljdWxhciB0byB0aGUgZmlyc3QgdGFuZ2VudCB2ZWN0b3IsXHJcblx0XHQvLyBhbmQgaW4gdGhlIGRpcmVjdGlvbiBvZiB0aGUgbWluaW11bSB0YW5nZW50IHh5eiBjb21wb25lbnRcclxuXHJcblx0XHRub3JtYWxzWyAwIF0gPSBuZXcgVmVjdG9yMygpO1xyXG5cdFx0Ymlub3JtYWxzWyAwIF0gPSBuZXcgVmVjdG9yMygpO1xyXG5cdFx0bGV0IG1pbiA9IE51bWJlci5NQVhfVkFMVUU7XHJcblx0XHRjb25zdCB0eCA9IE1hdGguYWJzKCB0YW5nZW50c1sgMCBdLnggKTtcclxuXHRcdGNvbnN0IHR5ID0gTWF0aC5hYnMoIHRhbmdlbnRzWyAwIF0ueSApO1xyXG5cdFx0Y29uc3QgdHogPSBNYXRoLmFicyggdGFuZ2VudHNbIDAgXS56ICk7XHJcblxyXG5cdFx0aWYgKCB0eCA8PSBtaW4gKSB7XHJcblxyXG5cdFx0XHRtaW4gPSB0eDtcclxuXHRcdFx0bm9ybWFsLnNldCggMSwgMCwgMCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHR5IDw9IG1pbiApIHtcclxuXHJcblx0XHRcdG1pbiA9IHR5O1xyXG5cdFx0XHRub3JtYWwuc2V0KCAwLCAxLCAwICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggdHogPD0gbWluICkge1xyXG5cclxuXHRcdFx0bm9ybWFsLnNldCggMCwgMCwgMSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHR2ZWMuY3Jvc3NWZWN0b3JzKCB0YW5nZW50c1sgMCBdLCBub3JtYWwgKS5ub3JtYWxpemUoKTtcclxuXHJcblx0XHRub3JtYWxzWyAwIF0uY3Jvc3NWZWN0b3JzKCB0YW5nZW50c1sgMCBdLCB2ZWMgKTtcclxuXHRcdGJpbm9ybWFsc1sgMCBdLmNyb3NzVmVjdG9ycyggdGFuZ2VudHNbIDAgXSwgbm9ybWFsc1sgMCBdICk7XHJcblxyXG5cclxuXHRcdC8vIGNvbXB1dGUgdGhlIHNsb3dseS12YXJ5aW5nIG5vcm1hbCBhbmQgYmlub3JtYWwgdmVjdG9ycyBmb3IgZWFjaCBzZWdtZW50IG9uIHRoZSBjdXJ2ZVxyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMTsgaSA8PSBzZWdtZW50czsgaSArKyApIHtcclxuXHJcblx0XHRcdG5vcm1hbHNbIGkgXSA9IG5vcm1hbHNbIGkgLSAxIF0uY2xvbmUoKTtcclxuXHJcblx0XHRcdGJpbm9ybWFsc1sgaSBdID0gYmlub3JtYWxzWyBpIC0gMSBdLmNsb25lKCk7XHJcblxyXG5cdFx0XHR2ZWMuY3Jvc3NWZWN0b3JzKCB0YW5nZW50c1sgaSAtIDEgXSwgdGFuZ2VudHNbIGkgXSApO1xyXG5cclxuXHRcdFx0aWYgKCB2ZWMubGVuZ3RoKCkgPiBOdW1iZXIuRVBTSUxPTiApIHtcclxuXHJcblx0XHRcdFx0dmVjLm5vcm1hbGl6ZSgpO1xyXG5cclxuXHRcdFx0XHRjb25zdCB0aGV0YSA9IE1hdGguYWNvcyggTWF0aFV0aWxzLmNsYW1wKCB0YW5nZW50c1sgaSAtIDEgXS5kb3QoIHRhbmdlbnRzWyBpIF0gKSwgLSAxLCAxICkgKTsgLy8gY2xhbXAgZm9yIGZsb2F0aW5nIHB0IGVycm9yc1xyXG5cclxuXHRcdFx0XHRub3JtYWxzWyBpIF0uYXBwbHlNYXRyaXg0KCBtYXQubWFrZVJvdGF0aW9uQXhpcyggdmVjLCB0aGV0YSApICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRiaW5vcm1hbHNbIGkgXS5jcm9zc1ZlY3RvcnMoIHRhbmdlbnRzWyBpIF0sIG5vcm1hbHNbIGkgXSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvLyBpZiB0aGUgY3VydmUgaXMgY2xvc2VkLCBwb3N0cHJvY2VzcyB0aGUgdmVjdG9ycyBzbyB0aGUgZmlyc3QgYW5kIGxhc3Qgbm9ybWFsIHZlY3RvcnMgYXJlIHRoZSBzYW1lXHJcblxyXG5cdFx0aWYgKCBjbG9zZWQgPT09IHRydWUgKSB7XHJcblxyXG5cdFx0XHRsZXQgdGhldGEgPSBNYXRoLmFjb3MoIE1hdGhVdGlscy5jbGFtcCggbm9ybWFsc1sgMCBdLmRvdCggbm9ybWFsc1sgc2VnbWVudHMgXSApLCAtIDEsIDEgKSApO1xyXG5cdFx0XHR0aGV0YSAvPSBzZWdtZW50cztcclxuXHJcblx0XHRcdGlmICggdGFuZ2VudHNbIDAgXS5kb3QoIHZlYy5jcm9zc1ZlY3RvcnMoIG5vcm1hbHNbIDAgXSwgbm9ybWFsc1sgc2VnbWVudHMgXSApICkgPiAwICkge1xyXG5cclxuXHRcdFx0XHR0aGV0YSA9IC0gdGhldGE7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDE7IGkgPD0gc2VnbWVudHM7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdC8vIHR3aXN0IGEgbGl0dGxlLi4uXHJcblx0XHRcdFx0bm9ybWFsc1sgaSBdLmFwcGx5TWF0cml4NCggbWF0Lm1ha2VSb3RhdGlvbkF4aXMoIHRhbmdlbnRzWyBpIF0sIHRoZXRhICogaSApICk7XHJcblx0XHRcdFx0Ymlub3JtYWxzWyBpIF0uY3Jvc3NWZWN0b3JzKCB0YW5nZW50c1sgaSBdLCBub3JtYWxzWyBpIF0gKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHtcclxuXHRcdFx0dGFuZ2VudHM6IHRhbmdlbnRzLFxyXG5cdFx0XHRub3JtYWxzOiBub3JtYWxzLFxyXG5cdFx0XHRiaW5vcm1hbHM6IGJpbm9ybWFsc1xyXG5cdFx0fTtcclxuXHJcblx0fVxyXG5cclxuXHRjbG9uZSgpIHtcclxuXHJcblx0XHRyZXR1cm4gbmV3IHRoaXMuY29uc3RydWN0b3IoKS5jb3B5KCB0aGlzICk7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHRoaXMuYXJjTGVuZ3RoRGl2aXNpb25zID0gc291cmNlLmFyY0xlbmd0aERpdmlzaW9ucztcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHR0b0pTT04oKSB7XHJcblxyXG5cdFx0Y29uc3QgZGF0YSA9IHtcclxuXHRcdFx0bWV0YWRhdGE6IHtcclxuXHRcdFx0XHR2ZXJzaW9uOiA0LjYsXHJcblx0XHRcdFx0dHlwZTogJ0N1cnZlJyxcclxuXHRcdFx0XHRnZW5lcmF0b3I6ICdDdXJ2ZS50b0pTT04nXHJcblx0XHRcdH1cclxuXHRcdH07XHJcblxyXG5cdFx0ZGF0YS5hcmNMZW5ndGhEaXZpc2lvbnMgPSB0aGlzLmFyY0xlbmd0aERpdmlzaW9ucztcclxuXHRcdGRhdGEudHlwZSA9IHRoaXMudHlwZTtcclxuXHJcblx0XHRyZXR1cm4gZGF0YTtcclxuXHJcblx0fVxyXG5cclxuXHRmcm9tSlNPTigganNvbiApIHtcclxuXHJcblx0XHR0aGlzLmFyY0xlbmd0aERpdmlzaW9ucyA9IGpzb24uYXJjTGVuZ3RoRGl2aXNpb25zO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5cclxuZXhwb3J0IHsgQ3VydmUgfTtcclxuIiwiaW1wb3J0IHsgQ3VydmUgfSBmcm9tICcuLi9jb3JlL0N1cnZlLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yMiB9IGZyb20gJy4uLy4uL21hdGgvVmVjdG9yMi5qcyc7XHJcblxyXG5jbGFzcyBFbGxpcHNlQ3VydmUgZXh0ZW5kcyBDdXJ2ZSB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBhWCA9IDAsIGFZID0gMCwgeFJhZGl1cyA9IDEsIHlSYWRpdXMgPSAxLCBhU3RhcnRBbmdsZSA9IDAsIGFFbmRBbmdsZSA9IE1hdGguUEkgKiAyLCBhQ2xvY2t3aXNlID0gZmFsc2UsIGFSb3RhdGlvbiA9IDAgKSB7XHJcblxyXG5cdFx0c3VwZXIoKTtcclxuXHJcblx0XHR0aGlzLmlzRWxsaXBzZUN1cnZlID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSAnRWxsaXBzZUN1cnZlJztcclxuXHJcblx0XHR0aGlzLmFYID0gYVg7XHJcblx0XHR0aGlzLmFZID0gYVk7XHJcblxyXG5cdFx0dGhpcy54UmFkaXVzID0geFJhZGl1cztcclxuXHRcdHRoaXMueVJhZGl1cyA9IHlSYWRpdXM7XHJcblxyXG5cdFx0dGhpcy5hU3RhcnRBbmdsZSA9IGFTdGFydEFuZ2xlO1xyXG5cdFx0dGhpcy5hRW5kQW5nbGUgPSBhRW5kQW5nbGU7XHJcblxyXG5cdFx0dGhpcy5hQ2xvY2t3aXNlID0gYUNsb2Nrd2lzZTtcclxuXHJcblx0XHR0aGlzLmFSb3RhdGlvbiA9IGFSb3RhdGlvbjtcclxuXHJcblx0fVxyXG5cclxuXHRnZXRQb2ludCggdCwgb3B0aW9uYWxUYXJnZXQgKSB7XHJcblxyXG5cdFx0Y29uc3QgcG9pbnQgPSBvcHRpb25hbFRhcmdldCB8fCBuZXcgVmVjdG9yMigpO1xyXG5cclxuXHRcdGNvbnN0IHR3b1BpID0gTWF0aC5QSSAqIDI7XHJcblx0XHRsZXQgZGVsdGFBbmdsZSA9IHRoaXMuYUVuZEFuZ2xlIC0gdGhpcy5hU3RhcnRBbmdsZTtcclxuXHRcdGNvbnN0IHNhbWVQb2ludHMgPSBNYXRoLmFicyggZGVsdGFBbmdsZSApIDwgTnVtYmVyLkVQU0lMT047XHJcblxyXG5cdFx0Ly8gZW5zdXJlcyB0aGF0IGRlbHRhQW5nbGUgaXMgMCAuLiAyIFBJXHJcblx0XHR3aGlsZSAoIGRlbHRhQW5nbGUgPCAwICkgZGVsdGFBbmdsZSArPSB0d29QaTtcclxuXHRcdHdoaWxlICggZGVsdGFBbmdsZSA+IHR3b1BpICkgZGVsdGFBbmdsZSAtPSB0d29QaTtcclxuXHJcblx0XHRpZiAoIGRlbHRhQW5nbGUgPCBOdW1iZXIuRVBTSUxPTiApIHtcclxuXHJcblx0XHRcdGlmICggc2FtZVBvaW50cyApIHtcclxuXHJcblx0XHRcdFx0ZGVsdGFBbmdsZSA9IDA7XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRkZWx0YUFuZ2xlID0gdHdvUGk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggdGhpcy5hQ2xvY2t3aXNlID09PSB0cnVlICYmICEgc2FtZVBvaW50cyApIHtcclxuXHJcblx0XHRcdGlmICggZGVsdGFBbmdsZSA9PT0gdHdvUGkgKSB7XHJcblxyXG5cdFx0XHRcdGRlbHRhQW5nbGUgPSAtIHR3b1BpO1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0ZGVsdGFBbmdsZSA9IGRlbHRhQW5nbGUgLSB0d29QaTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Y29uc3QgYW5nbGUgPSB0aGlzLmFTdGFydEFuZ2xlICsgdCAqIGRlbHRhQW5nbGU7XHJcblx0XHRsZXQgeCA9IHRoaXMuYVggKyB0aGlzLnhSYWRpdXMgKiBNYXRoLmNvcyggYW5nbGUgKTtcclxuXHRcdGxldCB5ID0gdGhpcy5hWSArIHRoaXMueVJhZGl1cyAqIE1hdGguc2luKCBhbmdsZSApO1xyXG5cclxuXHRcdGlmICggdGhpcy5hUm90YXRpb24gIT09IDAgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBjb3MgPSBNYXRoLmNvcyggdGhpcy5hUm90YXRpb24gKTtcclxuXHRcdFx0Y29uc3Qgc2luID0gTWF0aC5zaW4oIHRoaXMuYVJvdGF0aW9uICk7XHJcblxyXG5cdFx0XHRjb25zdCB0eCA9IHggLSB0aGlzLmFYO1xyXG5cdFx0XHRjb25zdCB0eSA9IHkgLSB0aGlzLmFZO1xyXG5cclxuXHRcdFx0Ly8gUm90YXRlIHRoZSBwb2ludCBhYm91dCB0aGUgY2VudGVyIG9mIHRoZSBlbGxpcHNlLlxyXG5cdFx0XHR4ID0gdHggKiBjb3MgLSB0eSAqIHNpbiArIHRoaXMuYVg7XHJcblx0XHRcdHkgPSB0eCAqIHNpbiArIHR5ICogY29zICsgdGhpcy5hWTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHBvaW50LnNldCggeCwgeSApO1xyXG5cclxuXHR9XHJcblxyXG5cdGNvcHkoIHNvdXJjZSApIHtcclxuXHJcblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcclxuXHJcblx0XHR0aGlzLmFYID0gc291cmNlLmFYO1xyXG5cdFx0dGhpcy5hWSA9IHNvdXJjZS5hWTtcclxuXHJcblx0XHR0aGlzLnhSYWRpdXMgPSBzb3VyY2UueFJhZGl1cztcclxuXHRcdHRoaXMueVJhZGl1cyA9IHNvdXJjZS55UmFkaXVzO1xyXG5cclxuXHRcdHRoaXMuYVN0YXJ0QW5nbGUgPSBzb3VyY2UuYVN0YXJ0QW5nbGU7XHJcblx0XHR0aGlzLmFFbmRBbmdsZSA9IHNvdXJjZS5hRW5kQW5nbGU7XHJcblxyXG5cdFx0dGhpcy5hQ2xvY2t3aXNlID0gc291cmNlLmFDbG9ja3dpc2U7XHJcblxyXG5cdFx0dGhpcy5hUm90YXRpb24gPSBzb3VyY2UuYVJvdGF0aW9uO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHRvSlNPTigpIHtcclxuXHJcblx0XHRjb25zdCBkYXRhID0gc3VwZXIudG9KU09OKCk7XHJcblxyXG5cdFx0ZGF0YS5hWCA9IHRoaXMuYVg7XHJcblx0XHRkYXRhLmFZID0gdGhpcy5hWTtcclxuXHJcblx0XHRkYXRhLnhSYWRpdXMgPSB0aGlzLnhSYWRpdXM7XHJcblx0XHRkYXRhLnlSYWRpdXMgPSB0aGlzLnlSYWRpdXM7XHJcblxyXG5cdFx0ZGF0YS5hU3RhcnRBbmdsZSA9IHRoaXMuYVN0YXJ0QW5nbGU7XHJcblx0XHRkYXRhLmFFbmRBbmdsZSA9IHRoaXMuYUVuZEFuZ2xlO1xyXG5cclxuXHRcdGRhdGEuYUNsb2Nrd2lzZSA9IHRoaXMuYUNsb2Nrd2lzZTtcclxuXHJcblx0XHRkYXRhLmFSb3RhdGlvbiA9IHRoaXMuYVJvdGF0aW9uO1xyXG5cclxuXHRcdHJldHVybiBkYXRhO1xyXG5cclxuXHR9XHJcblxyXG5cdGZyb21KU09OKCBqc29uICkge1xyXG5cclxuXHRcdHN1cGVyLmZyb21KU09OKCBqc29uICk7XHJcblxyXG5cdFx0dGhpcy5hWCA9IGpzb24uYVg7XHJcblx0XHR0aGlzLmFZID0ganNvbi5hWTtcclxuXHJcblx0XHR0aGlzLnhSYWRpdXMgPSBqc29uLnhSYWRpdXM7XHJcblx0XHR0aGlzLnlSYWRpdXMgPSBqc29uLnlSYWRpdXM7XHJcblxyXG5cdFx0dGhpcy5hU3RhcnRBbmdsZSA9IGpzb24uYVN0YXJ0QW5nbGU7XHJcblx0XHR0aGlzLmFFbmRBbmdsZSA9IGpzb24uYUVuZEFuZ2xlO1xyXG5cclxuXHRcdHRoaXMuYUNsb2Nrd2lzZSA9IGpzb24uYUNsb2Nrd2lzZTtcclxuXHJcblx0XHR0aGlzLmFSb3RhdGlvbiA9IGpzb24uYVJvdGF0aW9uO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBFbGxpcHNlQ3VydmUgfTtcclxuIiwiaW1wb3J0IHsgRWxsaXBzZUN1cnZlIH0gZnJvbSAnLi9FbGxpcHNlQ3VydmUuanMnO1xyXG5cclxuY2xhc3MgQXJjQ3VydmUgZXh0ZW5kcyBFbGxpcHNlQ3VydmUge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggYVgsIGFZLCBhUmFkaXVzLCBhU3RhcnRBbmdsZSwgYUVuZEFuZ2xlLCBhQ2xvY2t3aXNlICkge1xyXG5cclxuXHRcdHN1cGVyKCBhWCwgYVksIGFSYWRpdXMsIGFSYWRpdXMsIGFTdGFydEFuZ2xlLCBhRW5kQW5nbGUsIGFDbG9ja3dpc2UgKTtcclxuXHJcblx0XHR0aGlzLmlzQXJjQ3VydmUgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMudHlwZSA9ICdBcmNDdXJ2ZSc7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IEFyY0N1cnZlIH07XHJcbiIsImltcG9ydCB7IFZlY3RvcjMgfSBmcm9tICcuLi8uLi9tYXRoL1ZlY3RvcjMuanMnO1xyXG5pbXBvcnQgeyBDdXJ2ZSB9IGZyb20gJy4uL2NvcmUvQ3VydmUuanMnO1xyXG5cclxuLyoqXHJcbiAqIENlbnRyaXBldGFsIENhdG11bGxSb20gQ3VydmUgLSB3aGljaCBpcyB1c2VmdWwgZm9yIGF2b2lkaW5nXHJcbiAqIGN1c3BzIGFuZCBzZWxmLWludGVyc2VjdGlvbnMgaW4gbm9uLXVuaWZvcm0gY2F0bXVsbCByb20gY3VydmVzLlxyXG4gKiBodHRwOi8vd3d3LmNlbXl1a3NlbC5jb20vcmVzZWFyY2gvY2F0bXVsbHJvbV9wYXJhbS9jYXRtdWxscm9tLnBkZlxyXG4gKlxyXG4gKiBjdXJ2ZS50eXBlIGFjY2VwdHMgY2VudHJpcGV0YWwoZGVmYXVsdCksIGNob3JkYWwgYW5kIGNhdG11bGxyb21cclxuICogY3VydmUudGVuc2lvbiBpcyB1c2VkIGZvciBjYXRtdWxscm9tIHdoaWNoIGRlZmF1bHRzIHRvIDAuNVxyXG4gKi9cclxuXHJcblxyXG4vKlxyXG5CYXNlZCBvbiBhbiBvcHRpbWl6ZWQgYysrIHNvbHV0aW9uIGluXHJcbiAtIGh0dHA6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvOTQ4OTczNi9jYXRtdWxsLXJvbS1jdXJ2ZS13aXRoLW5vLWN1c3BzLWFuZC1uby1zZWxmLWludGVyc2VjdGlvbnMvXHJcbiAtIGh0dHA6Ly9pZGVvbmUuY29tL05vRWJWTVxyXG5cclxuVGhpcyBDdWJpY1BvbHkgY2xhc3MgY291bGQgYmUgdXNlZCBmb3IgcmV1c2luZyBzb21lIHZhcmlhYmxlcyBhbmQgY2FsY3VsYXRpb25zLFxyXG5idXQgZm9yIHRocmVlLmpzIGN1cnZlIHVzZSwgaXQgY291bGQgYmUgcG9zc2libGUgaW5saW5lZCBhbmQgZmxhdHRlbiBpbnRvIGEgc2luZ2xlIGZ1bmN0aW9uIGNhbGxcclxud2hpY2ggY2FuIGJlIHBsYWNlZCBpbiBDdXJ2ZVV0aWxzLlxyXG4qL1xyXG5cclxuZnVuY3Rpb24gQ3ViaWNQb2x5KCkge1xyXG5cclxuXHRsZXQgYzAgPSAwLCBjMSA9IDAsIGMyID0gMCwgYzMgPSAwO1xyXG5cclxuXHQvKlxyXG5cdCAqIENvbXB1dGUgY29lZmZpY2llbnRzIGZvciBhIGN1YmljIHBvbHlub21pYWxcclxuXHQgKiAgIHAocykgPSBjMCArIGMxKnMgKyBjMipzXjIgKyBjMypzXjNcclxuXHQgKiBzdWNoIHRoYXRcclxuXHQgKiAgIHAoMCkgPSB4MCwgcCgxKSA9IHgxXHJcblx0ICogIGFuZFxyXG5cdCAqICAgcCcoMCkgPSB0MCwgcCcoMSkgPSB0MS5cclxuXHQgKi9cclxuXHRmdW5jdGlvbiBpbml0KCB4MCwgeDEsIHQwLCB0MSApIHtcclxuXHJcblx0XHRjMCA9IHgwO1xyXG5cdFx0YzEgPSB0MDtcclxuXHRcdGMyID0gLSAzICogeDAgKyAzICogeDEgLSAyICogdDAgLSB0MTtcclxuXHRcdGMzID0gMiAqIHgwIC0gMiAqIHgxICsgdDAgKyB0MTtcclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4ge1xyXG5cclxuXHRcdGluaXRDYXRtdWxsUm9tOiBmdW5jdGlvbiAoIHgwLCB4MSwgeDIsIHgzLCB0ZW5zaW9uICkge1xyXG5cclxuXHRcdFx0aW5pdCggeDEsIHgyLCB0ZW5zaW9uICogKCB4MiAtIHgwICksIHRlbnNpb24gKiAoIHgzIC0geDEgKSApO1xyXG5cclxuXHRcdH0sXHJcblxyXG5cdFx0aW5pdE5vbnVuaWZvcm1DYXRtdWxsUm9tOiBmdW5jdGlvbiAoIHgwLCB4MSwgeDIsIHgzLCBkdDAsIGR0MSwgZHQyICkge1xyXG5cclxuXHRcdFx0Ly8gY29tcHV0ZSB0YW5nZW50cyB3aGVuIHBhcmFtZXRlcml6ZWQgaW4gW3QxLHQyXVxyXG5cdFx0XHRsZXQgdDEgPSAoIHgxIC0geDAgKSAvIGR0MCAtICggeDIgLSB4MCApIC8gKCBkdDAgKyBkdDEgKSArICggeDIgLSB4MSApIC8gZHQxO1xyXG5cdFx0XHRsZXQgdDIgPSAoIHgyIC0geDEgKSAvIGR0MSAtICggeDMgLSB4MSApIC8gKCBkdDEgKyBkdDIgKSArICggeDMgLSB4MiApIC8gZHQyO1xyXG5cclxuXHRcdFx0Ly8gcmVzY2FsZSB0YW5nZW50cyBmb3IgcGFyYW1ldHJpemF0aW9uIGluIFswLDFdXHJcblx0XHRcdHQxICo9IGR0MTtcclxuXHRcdFx0dDIgKj0gZHQxO1xyXG5cclxuXHRcdFx0aW5pdCggeDEsIHgyLCB0MSwgdDIgKTtcclxuXHJcblx0XHR9LFxyXG5cclxuXHRcdGNhbGM6IGZ1bmN0aW9uICggdCApIHtcclxuXHJcblx0XHRcdGNvbnN0IHQyID0gdCAqIHQ7XHJcblx0XHRcdGNvbnN0IHQzID0gdDIgKiB0O1xyXG5cdFx0XHRyZXR1cm4gYzAgKyBjMSAqIHQgKyBjMiAqIHQyICsgYzMgKiB0MztcclxuXHJcblx0XHR9XHJcblxyXG5cdH07XHJcblxyXG59XHJcblxyXG4vL1xyXG5cclxuY29uc3QgdG1wID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5jb25zdCBweCA9IC8qQF9fUFVSRV9fKi8gbmV3IEN1YmljUG9seSgpO1xyXG5jb25zdCBweSA9IC8qQF9fUFVSRV9fKi8gbmV3IEN1YmljUG9seSgpO1xyXG5jb25zdCBweiA9IC8qQF9fUFVSRV9fKi8gbmV3IEN1YmljUG9seSgpO1xyXG5cclxuY2xhc3MgQ2F0bXVsbFJvbUN1cnZlMyBleHRlbmRzIEN1cnZlIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIHBvaW50cyA9IFtdLCBjbG9zZWQgPSBmYWxzZSwgY3VydmVUeXBlID0gJ2NlbnRyaXBldGFsJywgdGVuc2lvbiA9IDAuNSApIHtcclxuXHJcblx0XHRzdXBlcigpO1xyXG5cclxuXHRcdHRoaXMuaXNDYXRtdWxsUm9tQ3VydmUzID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSAnQ2F0bXVsbFJvbUN1cnZlMyc7XHJcblxyXG5cdFx0dGhpcy5wb2ludHMgPSBwb2ludHM7XHJcblx0XHR0aGlzLmNsb3NlZCA9IGNsb3NlZDtcclxuXHRcdHRoaXMuY3VydmVUeXBlID0gY3VydmVUeXBlO1xyXG5cdFx0dGhpcy50ZW5zaW9uID0gdGVuc2lvbjtcclxuXHJcblx0fVxyXG5cclxuXHRnZXRQb2ludCggdCwgb3B0aW9uYWxUYXJnZXQgPSBuZXcgVmVjdG9yMygpICkge1xyXG5cclxuXHRcdGNvbnN0IHBvaW50ID0gb3B0aW9uYWxUYXJnZXQ7XHJcblxyXG5cdFx0Y29uc3QgcG9pbnRzID0gdGhpcy5wb2ludHM7XHJcblx0XHRjb25zdCBsID0gcG9pbnRzLmxlbmd0aDtcclxuXHJcblx0XHRjb25zdCBwID0gKCBsIC0gKCB0aGlzLmNsb3NlZCA/IDAgOiAxICkgKSAqIHQ7XHJcblx0XHRsZXQgaW50UG9pbnQgPSBNYXRoLmZsb29yKCBwICk7XHJcblx0XHRsZXQgd2VpZ2h0ID0gcCAtIGludFBvaW50O1xyXG5cclxuXHRcdGlmICggdGhpcy5jbG9zZWQgKSB7XHJcblxyXG5cdFx0XHRpbnRQb2ludCArPSBpbnRQb2ludCA+IDAgPyAwIDogKCBNYXRoLmZsb29yKCBNYXRoLmFicyggaW50UG9pbnQgKSAvIGwgKSArIDEgKSAqIGw7XHJcblxyXG5cdFx0fSBlbHNlIGlmICggd2VpZ2h0ID09PSAwICYmIGludFBvaW50ID09PSBsIC0gMSApIHtcclxuXHJcblx0XHRcdGludFBvaW50ID0gbCAtIDI7XHJcblx0XHRcdHdlaWdodCA9IDE7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGxldCBwMCwgcDM7IC8vIDQgcG9pbnRzIChwMSAmIHAyIGRlZmluZWQgYmVsb3cpXHJcblxyXG5cdFx0aWYgKCB0aGlzLmNsb3NlZCB8fCBpbnRQb2ludCA+IDAgKSB7XHJcblxyXG5cdFx0XHRwMCA9IHBvaW50c1sgKCBpbnRQb2ludCAtIDEgKSAlIGwgXTtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0Ly8gZXh0cmFwb2xhdGUgZmlyc3QgcG9pbnRcclxuXHRcdFx0dG1wLnN1YlZlY3RvcnMoIHBvaW50c1sgMCBdLCBwb2ludHNbIDEgXSApLmFkZCggcG9pbnRzWyAwIF0gKTtcclxuXHRcdFx0cDAgPSB0bXA7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGNvbnN0IHAxID0gcG9pbnRzWyBpbnRQb2ludCAlIGwgXTtcclxuXHRcdGNvbnN0IHAyID0gcG9pbnRzWyAoIGludFBvaW50ICsgMSApICUgbCBdO1xyXG5cclxuXHRcdGlmICggdGhpcy5jbG9zZWQgfHwgaW50UG9pbnQgKyAyIDwgbCApIHtcclxuXHJcblx0XHRcdHAzID0gcG9pbnRzWyAoIGludFBvaW50ICsgMiApICUgbCBdO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHQvLyBleHRyYXBvbGF0ZSBsYXN0IHBvaW50XHJcblx0XHRcdHRtcC5zdWJWZWN0b3JzKCBwb2ludHNbIGwgLSAxIF0sIHBvaW50c1sgbCAtIDIgXSApLmFkZCggcG9pbnRzWyBsIC0gMSBdICk7XHJcblx0XHRcdHAzID0gdG1wO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHRoaXMuY3VydmVUeXBlID09PSAnY2VudHJpcGV0YWwnIHx8IHRoaXMuY3VydmVUeXBlID09PSAnY2hvcmRhbCcgKSB7XHJcblxyXG5cdFx0XHQvLyBpbml0IENlbnRyaXBldGFsIC8gQ2hvcmRhbCBDYXRtdWxsLVJvbVxyXG5cdFx0XHRjb25zdCBwb3cgPSB0aGlzLmN1cnZlVHlwZSA9PT0gJ2Nob3JkYWwnID8gMC41IDogMC4yNTtcclxuXHRcdFx0bGV0IGR0MCA9IE1hdGgucG93KCBwMC5kaXN0YW5jZVRvU3F1YXJlZCggcDEgKSwgcG93ICk7XHJcblx0XHRcdGxldCBkdDEgPSBNYXRoLnBvdyggcDEuZGlzdGFuY2VUb1NxdWFyZWQoIHAyICksIHBvdyApO1xyXG5cdFx0XHRsZXQgZHQyID0gTWF0aC5wb3coIHAyLmRpc3RhbmNlVG9TcXVhcmVkKCBwMyApLCBwb3cgKTtcclxuXHJcblx0XHRcdC8vIHNhZmV0eSBjaGVjayBmb3IgcmVwZWF0ZWQgcG9pbnRzXHJcblx0XHRcdGlmICggZHQxIDwgMWUtNCApIGR0MSA9IDEuMDtcclxuXHRcdFx0aWYgKCBkdDAgPCAxZS00ICkgZHQwID0gZHQxO1xyXG5cdFx0XHRpZiAoIGR0MiA8IDFlLTQgKSBkdDIgPSBkdDE7XHJcblxyXG5cdFx0XHRweC5pbml0Tm9udW5pZm9ybUNhdG11bGxSb20oIHAwLngsIHAxLngsIHAyLngsIHAzLngsIGR0MCwgZHQxLCBkdDIgKTtcclxuXHRcdFx0cHkuaW5pdE5vbnVuaWZvcm1DYXRtdWxsUm9tKCBwMC55LCBwMS55LCBwMi55LCBwMy55LCBkdDAsIGR0MSwgZHQyICk7XHJcblx0XHRcdHB6LmluaXROb251bmlmb3JtQ2F0bXVsbFJvbSggcDAueiwgcDEueiwgcDIueiwgcDMueiwgZHQwLCBkdDEsIGR0MiApO1xyXG5cclxuXHRcdH0gZWxzZSBpZiAoIHRoaXMuY3VydmVUeXBlID09PSAnY2F0bXVsbHJvbScgKSB7XHJcblxyXG5cdFx0XHRweC5pbml0Q2F0bXVsbFJvbSggcDAueCwgcDEueCwgcDIueCwgcDMueCwgdGhpcy50ZW5zaW9uICk7XHJcblx0XHRcdHB5LmluaXRDYXRtdWxsUm9tKCBwMC55LCBwMS55LCBwMi55LCBwMy55LCB0aGlzLnRlbnNpb24gKTtcclxuXHRcdFx0cHouaW5pdENhdG11bGxSb20oIHAwLnosIHAxLnosIHAyLnosIHAzLnosIHRoaXMudGVuc2lvbiApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRwb2ludC5zZXQoXHJcblx0XHRcdHB4LmNhbGMoIHdlaWdodCApLFxyXG5cdFx0XHRweS5jYWxjKCB3ZWlnaHQgKSxcclxuXHRcdFx0cHouY2FsYyggd2VpZ2h0IClcclxuXHRcdCk7XHJcblxyXG5cdFx0cmV0dXJuIHBvaW50O1xyXG5cclxuXHR9XHJcblxyXG5cdGNvcHkoIHNvdXJjZSApIHtcclxuXHJcblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcclxuXHJcblx0XHR0aGlzLnBvaW50cyA9IFtdO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IHNvdXJjZS5wb2ludHMubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdGNvbnN0IHBvaW50ID0gc291cmNlLnBvaW50c1sgaSBdO1xyXG5cclxuXHRcdFx0dGhpcy5wb2ludHMucHVzaCggcG9pbnQuY2xvbmUoKSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLmNsb3NlZCA9IHNvdXJjZS5jbG9zZWQ7XHJcblx0XHR0aGlzLmN1cnZlVHlwZSA9IHNvdXJjZS5jdXJ2ZVR5cGU7XHJcblx0XHR0aGlzLnRlbnNpb24gPSBzb3VyY2UudGVuc2lvbjtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHR0b0pTT04oKSB7XHJcblxyXG5cdFx0Y29uc3QgZGF0YSA9IHN1cGVyLnRvSlNPTigpO1xyXG5cclxuXHRcdGRhdGEucG9pbnRzID0gW107XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gdGhpcy5wb2ludHMubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdGNvbnN0IHBvaW50ID0gdGhpcy5wb2ludHNbIGkgXTtcclxuXHRcdFx0ZGF0YS5wb2ludHMucHVzaCggcG9pbnQudG9BcnJheSgpICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGRhdGEuY2xvc2VkID0gdGhpcy5jbG9zZWQ7XHJcblx0XHRkYXRhLmN1cnZlVHlwZSA9IHRoaXMuY3VydmVUeXBlO1xyXG5cdFx0ZGF0YS50ZW5zaW9uID0gdGhpcy50ZW5zaW9uO1xyXG5cclxuXHRcdHJldHVybiBkYXRhO1xyXG5cclxuXHR9XHJcblxyXG5cdGZyb21KU09OKCBqc29uICkge1xyXG5cclxuXHRcdHN1cGVyLmZyb21KU09OKCBqc29uICk7XHJcblxyXG5cdFx0dGhpcy5wb2ludHMgPSBbXTtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBqc29uLnBvaW50cy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0Y29uc3QgcG9pbnQgPSBqc29uLnBvaW50c1sgaSBdO1xyXG5cdFx0XHR0aGlzLnBvaW50cy5wdXNoKCBuZXcgVmVjdG9yMygpLmZyb21BcnJheSggcG9pbnQgKSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLmNsb3NlZCA9IGpzb24uY2xvc2VkO1xyXG5cdFx0dGhpcy5jdXJ2ZVR5cGUgPSBqc29uLmN1cnZlVHlwZTtcclxuXHRcdHRoaXMudGVuc2lvbiA9IGpzb24udGVuc2lvbjtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgQ2F0bXVsbFJvbUN1cnZlMyB9O1xyXG4iLCIvKipcclxuICogQmV6aWVyIEN1cnZlcyBmb3JtdWxhcyBvYnRhaW5lZCBmcm9tXHJcbiAqIGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0IlQzMlQTl6aWVyX2N1cnZlXHJcbiAqL1xyXG5cclxuZnVuY3Rpb24gQ2F0bXVsbFJvbSggdCwgcDAsIHAxLCBwMiwgcDMgKSB7XHJcblxyXG5cdGNvbnN0IHYwID0gKCBwMiAtIHAwICkgKiAwLjU7XHJcblx0Y29uc3QgdjEgPSAoIHAzIC0gcDEgKSAqIDAuNTtcclxuXHRjb25zdCB0MiA9IHQgKiB0O1xyXG5cdGNvbnN0IHQzID0gdCAqIHQyO1xyXG5cdHJldHVybiAoIDIgKiBwMSAtIDIgKiBwMiArIHYwICsgdjEgKSAqIHQzICsgKCAtIDMgKiBwMSArIDMgKiBwMiAtIDIgKiB2MCAtIHYxICkgKiB0MiArIHYwICogdCArIHAxO1xyXG5cclxufVxyXG5cclxuLy9cclxuXHJcbmZ1bmN0aW9uIFF1YWRyYXRpY0JlemllclAwKCB0LCBwICkge1xyXG5cclxuXHRjb25zdCBrID0gMSAtIHQ7XHJcblx0cmV0dXJuIGsgKiBrICogcDtcclxuXHJcbn1cclxuXHJcbmZ1bmN0aW9uIFF1YWRyYXRpY0JlemllclAxKCB0LCBwICkge1xyXG5cclxuXHRyZXR1cm4gMiAqICggMSAtIHQgKSAqIHQgKiBwO1xyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gUXVhZHJhdGljQmV6aWVyUDIoIHQsIHAgKSB7XHJcblxyXG5cdHJldHVybiB0ICogdCAqIHA7XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiBRdWFkcmF0aWNCZXppZXIoIHQsIHAwLCBwMSwgcDIgKSB7XHJcblxyXG5cdHJldHVybiBRdWFkcmF0aWNCZXppZXJQMCggdCwgcDAgKSArIFF1YWRyYXRpY0JlemllclAxKCB0LCBwMSApICtcclxuXHRcdFF1YWRyYXRpY0JlemllclAyKCB0LCBwMiApO1xyXG5cclxufVxyXG5cclxuLy9cclxuXHJcbmZ1bmN0aW9uIEN1YmljQmV6aWVyUDAoIHQsIHAgKSB7XHJcblxyXG5cdGNvbnN0IGsgPSAxIC0gdDtcclxuXHRyZXR1cm4gayAqIGsgKiBrICogcDtcclxuXHJcbn1cclxuXHJcbmZ1bmN0aW9uIEN1YmljQmV6aWVyUDEoIHQsIHAgKSB7XHJcblxyXG5cdGNvbnN0IGsgPSAxIC0gdDtcclxuXHRyZXR1cm4gMyAqIGsgKiBrICogdCAqIHA7XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiBDdWJpY0JlemllclAyKCB0LCBwICkge1xyXG5cclxuXHRyZXR1cm4gMyAqICggMSAtIHQgKSAqIHQgKiB0ICogcDtcclxuXHJcbn1cclxuXHJcbmZ1bmN0aW9uIEN1YmljQmV6aWVyUDMoIHQsIHAgKSB7XHJcblxyXG5cdHJldHVybiB0ICogdCAqIHQgKiBwO1xyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gQ3ViaWNCZXppZXIoIHQsIHAwLCBwMSwgcDIsIHAzICkge1xyXG5cclxuXHRyZXR1cm4gQ3ViaWNCZXppZXJQMCggdCwgcDAgKSArIEN1YmljQmV6aWVyUDEoIHQsIHAxICkgKyBDdWJpY0JlemllclAyKCB0LCBwMiApICtcclxuXHRcdEN1YmljQmV6aWVyUDMoIHQsIHAzICk7XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBDYXRtdWxsUm9tLCBRdWFkcmF0aWNCZXppZXIsIEN1YmljQmV6aWVyIH07XHJcbiIsImltcG9ydCB7IEN1cnZlIH0gZnJvbSAnLi4vY29yZS9DdXJ2ZS5qcyc7XHJcbmltcG9ydCB7IEN1YmljQmV6aWVyIH0gZnJvbSAnLi4vY29yZS9JbnRlcnBvbGF0aW9ucy5qcyc7XHJcbmltcG9ydCB7IFZlY3RvcjIgfSBmcm9tICcuLi8uLi9tYXRoL1ZlY3RvcjIuanMnO1xyXG5cclxuY2xhc3MgQ3ViaWNCZXppZXJDdXJ2ZSBleHRlbmRzIEN1cnZlIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIHYwID0gbmV3IFZlY3RvcjIoKSwgdjEgPSBuZXcgVmVjdG9yMigpLCB2MiA9IG5ldyBWZWN0b3IyKCksIHYzID0gbmV3IFZlY3RvcjIoKSApIHtcclxuXHJcblx0XHRzdXBlcigpO1xyXG5cclxuXHRcdHRoaXMuaXNDdWJpY0JlemllckN1cnZlID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSAnQ3ViaWNCZXppZXJDdXJ2ZSc7XHJcblxyXG5cdFx0dGhpcy52MCA9IHYwO1xyXG5cdFx0dGhpcy52MSA9IHYxO1xyXG5cdFx0dGhpcy52MiA9IHYyO1xyXG5cdFx0dGhpcy52MyA9IHYzO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldFBvaW50KCB0LCBvcHRpb25hbFRhcmdldCA9IG5ldyBWZWN0b3IyKCkgKSB7XHJcblxyXG5cdFx0Y29uc3QgcG9pbnQgPSBvcHRpb25hbFRhcmdldDtcclxuXHJcblx0XHRjb25zdCB2MCA9IHRoaXMudjAsIHYxID0gdGhpcy52MSwgdjIgPSB0aGlzLnYyLCB2MyA9IHRoaXMudjM7XHJcblxyXG5cdFx0cG9pbnQuc2V0KFxyXG5cdFx0XHRDdWJpY0JlemllciggdCwgdjAueCwgdjEueCwgdjIueCwgdjMueCApLFxyXG5cdFx0XHRDdWJpY0JlemllciggdCwgdjAueSwgdjEueSwgdjIueSwgdjMueSApXHJcblx0XHQpO1xyXG5cclxuXHRcdHJldHVybiBwb2ludDtcclxuXHJcblx0fVxyXG5cclxuXHRjb3B5KCBzb3VyY2UgKSB7XHJcblxyXG5cdFx0c3VwZXIuY29weSggc291cmNlICk7XHJcblxyXG5cdFx0dGhpcy52MC5jb3B5KCBzb3VyY2UudjAgKTtcclxuXHRcdHRoaXMudjEuY29weSggc291cmNlLnYxICk7XHJcblx0XHR0aGlzLnYyLmNvcHkoIHNvdXJjZS52MiApO1xyXG5cdFx0dGhpcy52My5jb3B5KCBzb3VyY2UudjMgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHR0b0pTT04oKSB7XHJcblxyXG5cdFx0Y29uc3QgZGF0YSA9IHN1cGVyLnRvSlNPTigpO1xyXG5cclxuXHRcdGRhdGEudjAgPSB0aGlzLnYwLnRvQXJyYXkoKTtcclxuXHRcdGRhdGEudjEgPSB0aGlzLnYxLnRvQXJyYXkoKTtcclxuXHRcdGRhdGEudjIgPSB0aGlzLnYyLnRvQXJyYXkoKTtcclxuXHRcdGRhdGEudjMgPSB0aGlzLnYzLnRvQXJyYXkoKTtcclxuXHJcblx0XHRyZXR1cm4gZGF0YTtcclxuXHJcblx0fVxyXG5cclxuXHRmcm9tSlNPTigganNvbiApIHtcclxuXHJcblx0XHRzdXBlci5mcm9tSlNPTigganNvbiApO1xyXG5cclxuXHRcdHRoaXMudjAuZnJvbUFycmF5KCBqc29uLnYwICk7XHJcblx0XHR0aGlzLnYxLmZyb21BcnJheSgganNvbi52MSApO1xyXG5cdFx0dGhpcy52Mi5mcm9tQXJyYXkoIGpzb24udjIgKTtcclxuXHRcdHRoaXMudjMuZnJvbUFycmF5KCBqc29uLnYzICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IEN1YmljQmV6aWVyQ3VydmUgfTtcclxuIiwiaW1wb3J0IHsgQ3VydmUgfSBmcm9tICcuLi9jb3JlL0N1cnZlLmpzJztcclxuaW1wb3J0IHsgQ3ViaWNCZXppZXIgfSBmcm9tICcuLi9jb3JlL0ludGVycG9sYXRpb25zLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yMyB9IGZyb20gJy4uLy4uL21hdGgvVmVjdG9yMy5qcyc7XHJcblxyXG5jbGFzcyBDdWJpY0JlemllckN1cnZlMyBleHRlbmRzIEN1cnZlIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIHYwID0gbmV3IFZlY3RvcjMoKSwgdjEgPSBuZXcgVmVjdG9yMygpLCB2MiA9IG5ldyBWZWN0b3IzKCksIHYzID0gbmV3IFZlY3RvcjMoKSApIHtcclxuXHJcblx0XHRzdXBlcigpO1xyXG5cclxuXHRcdHRoaXMuaXNDdWJpY0JlemllckN1cnZlMyA9IHRydWU7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ0N1YmljQmV6aWVyQ3VydmUzJztcclxuXHJcblx0XHR0aGlzLnYwID0gdjA7XHJcblx0XHR0aGlzLnYxID0gdjE7XHJcblx0XHR0aGlzLnYyID0gdjI7XHJcblx0XHR0aGlzLnYzID0gdjM7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0UG9pbnQoIHQsIG9wdGlvbmFsVGFyZ2V0ID0gbmV3IFZlY3RvcjMoKSApIHtcclxuXHJcblx0XHRjb25zdCBwb2ludCA9IG9wdGlvbmFsVGFyZ2V0O1xyXG5cclxuXHRcdGNvbnN0IHYwID0gdGhpcy52MCwgdjEgPSB0aGlzLnYxLCB2MiA9IHRoaXMudjIsIHYzID0gdGhpcy52MztcclxuXHJcblx0XHRwb2ludC5zZXQoXHJcblx0XHRcdEN1YmljQmV6aWVyKCB0LCB2MC54LCB2MS54LCB2Mi54LCB2My54ICksXHJcblx0XHRcdEN1YmljQmV6aWVyKCB0LCB2MC55LCB2MS55LCB2Mi55LCB2My55ICksXHJcblx0XHRcdEN1YmljQmV6aWVyKCB0LCB2MC56LCB2MS56LCB2Mi56LCB2My56IClcclxuXHRcdCk7XHJcblxyXG5cdFx0cmV0dXJuIHBvaW50O1xyXG5cclxuXHR9XHJcblxyXG5cdGNvcHkoIHNvdXJjZSApIHtcclxuXHJcblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcclxuXHJcblx0XHR0aGlzLnYwLmNvcHkoIHNvdXJjZS52MCApO1xyXG5cdFx0dGhpcy52MS5jb3B5KCBzb3VyY2UudjEgKTtcclxuXHRcdHRoaXMudjIuY29weSggc291cmNlLnYyICk7XHJcblx0XHR0aGlzLnYzLmNvcHkoIHNvdXJjZS52MyApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHRvSlNPTigpIHtcclxuXHJcblx0XHRjb25zdCBkYXRhID0gc3VwZXIudG9KU09OKCk7XHJcblxyXG5cdFx0ZGF0YS52MCA9IHRoaXMudjAudG9BcnJheSgpO1xyXG5cdFx0ZGF0YS52MSA9IHRoaXMudjEudG9BcnJheSgpO1xyXG5cdFx0ZGF0YS52MiA9IHRoaXMudjIudG9BcnJheSgpO1xyXG5cdFx0ZGF0YS52MyA9IHRoaXMudjMudG9BcnJheSgpO1xyXG5cclxuXHRcdHJldHVybiBkYXRhO1xyXG5cclxuXHR9XHJcblxyXG5cdGZyb21KU09OKCBqc29uICkge1xyXG5cclxuXHRcdHN1cGVyLmZyb21KU09OKCBqc29uICk7XHJcblxyXG5cdFx0dGhpcy52MC5mcm9tQXJyYXkoIGpzb24udjAgKTtcclxuXHRcdHRoaXMudjEuZnJvbUFycmF5KCBqc29uLnYxICk7XHJcblx0XHR0aGlzLnYyLmZyb21BcnJheSgganNvbi52MiApO1xyXG5cdFx0dGhpcy52My5mcm9tQXJyYXkoIGpzb24udjMgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgQ3ViaWNCZXppZXJDdXJ2ZTMgfTtcclxuIiwiaW1wb3J0IHsgVmVjdG9yMiB9IGZyb20gJy4uLy4uL21hdGgvVmVjdG9yMi5qcyc7XHJcbmltcG9ydCB7IEN1cnZlIH0gZnJvbSAnLi4vY29yZS9DdXJ2ZS5qcyc7XHJcblxyXG5jbGFzcyBMaW5lQ3VydmUgZXh0ZW5kcyBDdXJ2ZSB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCB2MSA9IG5ldyBWZWN0b3IyKCksIHYyID0gbmV3IFZlY3RvcjIoKSApIHtcclxuXHJcblx0XHRzdXBlcigpO1xyXG5cclxuXHRcdHRoaXMuaXNMaW5lQ3VydmUgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMudHlwZSA9ICdMaW5lQ3VydmUnO1xyXG5cclxuXHRcdHRoaXMudjEgPSB2MTtcclxuXHRcdHRoaXMudjIgPSB2MjtcclxuXHJcblx0fVxyXG5cclxuXHRnZXRQb2ludCggdCwgb3B0aW9uYWxUYXJnZXQgPSBuZXcgVmVjdG9yMigpICkge1xyXG5cclxuXHRcdGNvbnN0IHBvaW50ID0gb3B0aW9uYWxUYXJnZXQ7XHJcblxyXG5cdFx0aWYgKCB0ID09PSAxICkge1xyXG5cclxuXHRcdFx0cG9pbnQuY29weSggdGhpcy52MiApO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRwb2ludC5jb3B5KCB0aGlzLnYyICkuc3ViKCB0aGlzLnYxICk7XHJcblx0XHRcdHBvaW50Lm11bHRpcGx5U2NhbGFyKCB0ICkuYWRkKCB0aGlzLnYxICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiBwb2ludDtcclxuXHJcblx0fVxyXG5cclxuXHQvLyBMaW5lIGN1cnZlIGlzIGxpbmVhciwgc28gd2UgY2FuIG92ZXJ3cml0ZSBkZWZhdWx0IGdldFBvaW50QXRcclxuXHRnZXRQb2ludEF0KCB1LCBvcHRpb25hbFRhcmdldCApIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5nZXRQb2ludCggdSwgb3B0aW9uYWxUYXJnZXQgKTtcclxuXHJcblx0fVxyXG5cclxuXHRnZXRUYW5nZW50KCB0LCBvcHRpb25hbFRhcmdldCA9IG5ldyBWZWN0b3IyKCkgKSB7XHJcblxyXG5cdFx0cmV0dXJuIG9wdGlvbmFsVGFyZ2V0LnN1YlZlY3RvcnMoIHRoaXMudjIsIHRoaXMudjEgKS5ub3JtYWxpemUoKTtcclxuXHJcblx0fVxyXG5cclxuXHRnZXRUYW5nZW50QXQoIHUsIG9wdGlvbmFsVGFyZ2V0ICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLmdldFRhbmdlbnQoIHUsIG9wdGlvbmFsVGFyZ2V0ICk7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xyXG5cclxuXHRcdHRoaXMudjEuY29weSggc291cmNlLnYxICk7XHJcblx0XHR0aGlzLnYyLmNvcHkoIHNvdXJjZS52MiApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHRvSlNPTigpIHtcclxuXHJcblx0XHRjb25zdCBkYXRhID0gc3VwZXIudG9KU09OKCk7XHJcblxyXG5cdFx0ZGF0YS52MSA9IHRoaXMudjEudG9BcnJheSgpO1xyXG5cdFx0ZGF0YS52MiA9IHRoaXMudjIudG9BcnJheSgpO1xyXG5cclxuXHRcdHJldHVybiBkYXRhO1xyXG5cclxuXHR9XHJcblxyXG5cdGZyb21KU09OKCBqc29uICkge1xyXG5cclxuXHRcdHN1cGVyLmZyb21KU09OKCBqc29uICk7XHJcblxyXG5cdFx0dGhpcy52MS5mcm9tQXJyYXkoIGpzb24udjEgKTtcclxuXHRcdHRoaXMudjIuZnJvbUFycmF5KCBqc29uLnYyICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IExpbmVDdXJ2ZSB9O1xyXG4iLCJpbXBvcnQgeyBWZWN0b3IzIH0gZnJvbSAnLi4vLi4vbWF0aC9WZWN0b3IzLmpzJztcclxuaW1wb3J0IHsgQ3VydmUgfSBmcm9tICcuLi9jb3JlL0N1cnZlLmpzJztcclxuXHJcbmNsYXNzIExpbmVDdXJ2ZTMgZXh0ZW5kcyBDdXJ2ZSB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCB2MSA9IG5ldyBWZWN0b3IzKCksIHYyID0gbmV3IFZlY3RvcjMoKSApIHtcclxuXHJcblx0XHRzdXBlcigpO1xyXG5cclxuXHRcdHRoaXMuaXNMaW5lQ3VydmUzID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSAnTGluZUN1cnZlMyc7XHJcblxyXG5cdFx0dGhpcy52MSA9IHYxO1xyXG5cdFx0dGhpcy52MiA9IHYyO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldFBvaW50KCB0LCBvcHRpb25hbFRhcmdldCA9IG5ldyBWZWN0b3IzKCkgKSB7XHJcblxyXG5cdFx0Y29uc3QgcG9pbnQgPSBvcHRpb25hbFRhcmdldDtcclxuXHJcblx0XHRpZiAoIHQgPT09IDEgKSB7XHJcblxyXG5cdFx0XHRwb2ludC5jb3B5KCB0aGlzLnYyICk7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdHBvaW50LmNvcHkoIHRoaXMudjIgKS5zdWIoIHRoaXMudjEgKTtcclxuXHRcdFx0cG9pbnQubXVsdGlwbHlTY2FsYXIoIHQgKS5hZGQoIHRoaXMudjEgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHBvaW50O1xyXG5cclxuXHR9XHJcblxyXG5cdC8vIExpbmUgY3VydmUgaXMgbGluZWFyLCBzbyB3ZSBjYW4gb3ZlcndyaXRlIGRlZmF1bHQgZ2V0UG9pbnRBdFxyXG5cdGdldFBvaW50QXQoIHUsIG9wdGlvbmFsVGFyZ2V0ICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLmdldFBvaW50KCB1LCBvcHRpb25hbFRhcmdldCApO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldFRhbmdlbnQoIHQsIG9wdGlvbmFsVGFyZ2V0ID0gbmV3IFZlY3RvcjMoKSApIHtcclxuXHJcblx0XHRyZXR1cm4gb3B0aW9uYWxUYXJnZXQuc3ViVmVjdG9ycyggdGhpcy52MiwgdGhpcy52MSApLm5vcm1hbGl6ZSgpO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldFRhbmdlbnRBdCggdSwgb3B0aW9uYWxUYXJnZXQgKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuZ2V0VGFuZ2VudCggdSwgb3B0aW9uYWxUYXJnZXQgKTtcclxuXHJcblx0fVxyXG5cclxuXHRjb3B5KCBzb3VyY2UgKSB7XHJcblxyXG5cdFx0c3VwZXIuY29weSggc291cmNlICk7XHJcblxyXG5cdFx0dGhpcy52MS5jb3B5KCBzb3VyY2UudjEgKTtcclxuXHRcdHRoaXMudjIuY29weSggc291cmNlLnYyICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0dG9KU09OKCkge1xyXG5cclxuXHRcdGNvbnN0IGRhdGEgPSBzdXBlci50b0pTT04oKTtcclxuXHJcblx0XHRkYXRhLnYxID0gdGhpcy52MS50b0FycmF5KCk7XHJcblx0XHRkYXRhLnYyID0gdGhpcy52Mi50b0FycmF5KCk7XHJcblxyXG5cdFx0cmV0dXJuIGRhdGE7XHJcblxyXG5cdH1cclxuXHJcblx0ZnJvbUpTT04oIGpzb24gKSB7XHJcblxyXG5cdFx0c3VwZXIuZnJvbUpTT04oIGpzb24gKTtcclxuXHJcblx0XHR0aGlzLnYxLmZyb21BcnJheSgganNvbi52MSApO1xyXG5cdFx0dGhpcy52Mi5mcm9tQXJyYXkoIGpzb24udjIgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgTGluZUN1cnZlMyB9O1xyXG4iLCJpbXBvcnQgeyBDdXJ2ZSB9IGZyb20gJy4uL2NvcmUvQ3VydmUuanMnO1xyXG5pbXBvcnQgeyBRdWFkcmF0aWNCZXppZXIgfSBmcm9tICcuLi9jb3JlL0ludGVycG9sYXRpb25zLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yMiB9IGZyb20gJy4uLy4uL21hdGgvVmVjdG9yMi5qcyc7XHJcblxyXG5jbGFzcyBRdWFkcmF0aWNCZXppZXJDdXJ2ZSBleHRlbmRzIEN1cnZlIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIHYwID0gbmV3IFZlY3RvcjIoKSwgdjEgPSBuZXcgVmVjdG9yMigpLCB2MiA9IG5ldyBWZWN0b3IyKCkgKSB7XHJcblxyXG5cdFx0c3VwZXIoKTtcclxuXHJcblx0XHR0aGlzLmlzUXVhZHJhdGljQmV6aWVyQ3VydmUgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMudHlwZSA9ICdRdWFkcmF0aWNCZXppZXJDdXJ2ZSc7XHJcblxyXG5cdFx0dGhpcy52MCA9IHYwO1xyXG5cdFx0dGhpcy52MSA9IHYxO1xyXG5cdFx0dGhpcy52MiA9IHYyO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldFBvaW50KCB0LCBvcHRpb25hbFRhcmdldCA9IG5ldyBWZWN0b3IyKCkgKSB7XHJcblxyXG5cdFx0Y29uc3QgcG9pbnQgPSBvcHRpb25hbFRhcmdldDtcclxuXHJcblx0XHRjb25zdCB2MCA9IHRoaXMudjAsIHYxID0gdGhpcy52MSwgdjIgPSB0aGlzLnYyO1xyXG5cclxuXHRcdHBvaW50LnNldChcclxuXHRcdFx0UXVhZHJhdGljQmV6aWVyKCB0LCB2MC54LCB2MS54LCB2Mi54ICksXHJcblx0XHRcdFF1YWRyYXRpY0JlemllciggdCwgdjAueSwgdjEueSwgdjIueSApXHJcblx0XHQpO1xyXG5cclxuXHRcdHJldHVybiBwb2ludDtcclxuXHJcblx0fVxyXG5cclxuXHRjb3B5KCBzb3VyY2UgKSB7XHJcblxyXG5cdFx0c3VwZXIuY29weSggc291cmNlICk7XHJcblxyXG5cdFx0dGhpcy52MC5jb3B5KCBzb3VyY2UudjAgKTtcclxuXHRcdHRoaXMudjEuY29weSggc291cmNlLnYxICk7XHJcblx0XHR0aGlzLnYyLmNvcHkoIHNvdXJjZS52MiApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHRvSlNPTigpIHtcclxuXHJcblx0XHRjb25zdCBkYXRhID0gc3VwZXIudG9KU09OKCk7XHJcblxyXG5cdFx0ZGF0YS52MCA9IHRoaXMudjAudG9BcnJheSgpO1xyXG5cdFx0ZGF0YS52MSA9IHRoaXMudjEudG9BcnJheSgpO1xyXG5cdFx0ZGF0YS52MiA9IHRoaXMudjIudG9BcnJheSgpO1xyXG5cclxuXHRcdHJldHVybiBkYXRhO1xyXG5cclxuXHR9XHJcblxyXG5cdGZyb21KU09OKCBqc29uICkge1xyXG5cclxuXHRcdHN1cGVyLmZyb21KU09OKCBqc29uICk7XHJcblxyXG5cdFx0dGhpcy52MC5mcm9tQXJyYXkoIGpzb24udjAgKTtcclxuXHRcdHRoaXMudjEuZnJvbUFycmF5KCBqc29uLnYxICk7XHJcblx0XHR0aGlzLnYyLmZyb21BcnJheSgganNvbi52MiApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBRdWFkcmF0aWNCZXppZXJDdXJ2ZSB9O1xyXG4iLCJpbXBvcnQgeyBDdXJ2ZSB9IGZyb20gJy4uL2NvcmUvQ3VydmUuanMnO1xyXG5pbXBvcnQgeyBRdWFkcmF0aWNCZXppZXIgfSBmcm9tICcuLi9jb3JlL0ludGVycG9sYXRpb25zLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yMyB9IGZyb20gJy4uLy4uL21hdGgvVmVjdG9yMy5qcyc7XHJcblxyXG5jbGFzcyBRdWFkcmF0aWNCZXppZXJDdXJ2ZTMgZXh0ZW5kcyBDdXJ2ZSB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCB2MCA9IG5ldyBWZWN0b3IzKCksIHYxID0gbmV3IFZlY3RvcjMoKSwgdjIgPSBuZXcgVmVjdG9yMygpICkge1xyXG5cclxuXHRcdHN1cGVyKCk7XHJcblxyXG5cdFx0dGhpcy5pc1F1YWRyYXRpY0JlemllckN1cnZlMyA9IHRydWU7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ1F1YWRyYXRpY0JlemllckN1cnZlMyc7XHJcblxyXG5cdFx0dGhpcy52MCA9IHYwO1xyXG5cdFx0dGhpcy52MSA9IHYxO1xyXG5cdFx0dGhpcy52MiA9IHYyO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldFBvaW50KCB0LCBvcHRpb25hbFRhcmdldCA9IG5ldyBWZWN0b3IzKCkgKSB7XHJcblxyXG5cdFx0Y29uc3QgcG9pbnQgPSBvcHRpb25hbFRhcmdldDtcclxuXHJcblx0XHRjb25zdCB2MCA9IHRoaXMudjAsIHYxID0gdGhpcy52MSwgdjIgPSB0aGlzLnYyO1xyXG5cclxuXHRcdHBvaW50LnNldChcclxuXHRcdFx0UXVhZHJhdGljQmV6aWVyKCB0LCB2MC54LCB2MS54LCB2Mi54ICksXHJcblx0XHRcdFF1YWRyYXRpY0JlemllciggdCwgdjAueSwgdjEueSwgdjIueSApLFxyXG5cdFx0XHRRdWFkcmF0aWNCZXppZXIoIHQsIHYwLnosIHYxLnosIHYyLnogKVxyXG5cdFx0KTtcclxuXHJcblx0XHRyZXR1cm4gcG9pbnQ7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xyXG5cclxuXHRcdHRoaXMudjAuY29weSggc291cmNlLnYwICk7XHJcblx0XHR0aGlzLnYxLmNvcHkoIHNvdXJjZS52MSApO1xyXG5cdFx0dGhpcy52Mi5jb3B5KCBzb3VyY2UudjIgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHR0b0pTT04oKSB7XHJcblxyXG5cdFx0Y29uc3QgZGF0YSA9IHN1cGVyLnRvSlNPTigpO1xyXG5cclxuXHRcdGRhdGEudjAgPSB0aGlzLnYwLnRvQXJyYXkoKTtcclxuXHRcdGRhdGEudjEgPSB0aGlzLnYxLnRvQXJyYXkoKTtcclxuXHRcdGRhdGEudjIgPSB0aGlzLnYyLnRvQXJyYXkoKTtcclxuXHJcblx0XHRyZXR1cm4gZGF0YTtcclxuXHJcblx0fVxyXG5cclxuXHRmcm9tSlNPTigganNvbiApIHtcclxuXHJcblx0XHRzdXBlci5mcm9tSlNPTigganNvbiApO1xyXG5cclxuXHRcdHRoaXMudjAuZnJvbUFycmF5KCBqc29uLnYwICk7XHJcblx0XHR0aGlzLnYxLmZyb21BcnJheSgganNvbi52MSApO1xyXG5cdFx0dGhpcy52Mi5mcm9tQXJyYXkoIGpzb24udjIgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgUXVhZHJhdGljQmV6aWVyQ3VydmUzIH07XHJcbiIsImltcG9ydCB7IEN1cnZlIH0gZnJvbSAnLi4vY29yZS9DdXJ2ZS5qcyc7XHJcbmltcG9ydCB7IENhdG11bGxSb20gfSBmcm9tICcuLi9jb3JlL0ludGVycG9sYXRpb25zLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yMiB9IGZyb20gJy4uLy4uL21hdGgvVmVjdG9yMi5qcyc7XHJcblxyXG5jbGFzcyBTcGxpbmVDdXJ2ZSBleHRlbmRzIEN1cnZlIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIHBvaW50cyA9IFtdICkge1xyXG5cclxuXHRcdHN1cGVyKCk7XHJcblxyXG5cdFx0dGhpcy5pc1NwbGluZUN1cnZlID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSAnU3BsaW5lQ3VydmUnO1xyXG5cclxuXHRcdHRoaXMucG9pbnRzID0gcG9pbnRzO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldFBvaW50KCB0LCBvcHRpb25hbFRhcmdldCA9IG5ldyBWZWN0b3IyKCkgKSB7XHJcblxyXG5cdFx0Y29uc3QgcG9pbnQgPSBvcHRpb25hbFRhcmdldDtcclxuXHJcblx0XHRjb25zdCBwb2ludHMgPSB0aGlzLnBvaW50cztcclxuXHRcdGNvbnN0IHAgPSAoIHBvaW50cy5sZW5ndGggLSAxICkgKiB0O1xyXG5cclxuXHRcdGNvbnN0IGludFBvaW50ID0gTWF0aC5mbG9vciggcCApO1xyXG5cdFx0Y29uc3Qgd2VpZ2h0ID0gcCAtIGludFBvaW50O1xyXG5cclxuXHRcdGNvbnN0IHAwID0gcG9pbnRzWyBpbnRQb2ludCA9PT0gMCA/IGludFBvaW50IDogaW50UG9pbnQgLSAxIF07XHJcblx0XHRjb25zdCBwMSA9IHBvaW50c1sgaW50UG9pbnQgXTtcclxuXHRcdGNvbnN0IHAyID0gcG9pbnRzWyBpbnRQb2ludCA+IHBvaW50cy5sZW5ndGggLSAyID8gcG9pbnRzLmxlbmd0aCAtIDEgOiBpbnRQb2ludCArIDEgXTtcclxuXHRcdGNvbnN0IHAzID0gcG9pbnRzWyBpbnRQb2ludCA+IHBvaW50cy5sZW5ndGggLSAzID8gcG9pbnRzLmxlbmd0aCAtIDEgOiBpbnRQb2ludCArIDIgXTtcclxuXHJcblx0XHRwb2ludC5zZXQoXHJcblx0XHRcdENhdG11bGxSb20oIHdlaWdodCwgcDAueCwgcDEueCwgcDIueCwgcDMueCApLFxyXG5cdFx0XHRDYXRtdWxsUm9tKCB3ZWlnaHQsIHAwLnksIHAxLnksIHAyLnksIHAzLnkgKVxyXG5cdFx0KTtcclxuXHJcblx0XHRyZXR1cm4gcG9pbnQ7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xyXG5cclxuXHRcdHRoaXMucG9pbnRzID0gW107XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gc291cmNlLnBvaW50cy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0Y29uc3QgcG9pbnQgPSBzb3VyY2UucG9pbnRzWyBpIF07XHJcblxyXG5cdFx0XHR0aGlzLnBvaW50cy5wdXNoKCBwb2ludC5jbG9uZSgpICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHRvSlNPTigpIHtcclxuXHJcblx0XHRjb25zdCBkYXRhID0gc3VwZXIudG9KU09OKCk7XHJcblxyXG5cdFx0ZGF0YS5wb2ludHMgPSBbXTtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSB0aGlzLnBvaW50cy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0Y29uc3QgcG9pbnQgPSB0aGlzLnBvaW50c1sgaSBdO1xyXG5cdFx0XHRkYXRhLnBvaW50cy5wdXNoKCBwb2ludC50b0FycmF5KCkgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIGRhdGE7XHJcblxyXG5cdH1cclxuXHJcblx0ZnJvbUpTT04oIGpzb24gKSB7XHJcblxyXG5cdFx0c3VwZXIuZnJvbUpTT04oIGpzb24gKTtcclxuXHJcblx0XHR0aGlzLnBvaW50cyA9IFtdO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IGpzb24ucG9pbnRzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBwb2ludCA9IGpzb24ucG9pbnRzWyBpIF07XHJcblx0XHRcdHRoaXMucG9pbnRzLnB1c2goIG5ldyBWZWN0b3IyKCkuZnJvbUFycmF5KCBwb2ludCApICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBTcGxpbmVDdXJ2ZSB9O1xyXG4iLCJpbXBvcnQgeyBDdXJ2ZSB9IGZyb20gJy4vQ3VydmUuanMnO1xyXG5pbXBvcnQgKiBhcyBDdXJ2ZXMgZnJvbSAnLi4vY3VydmVzL0N1cnZlcy5qcyc7XHJcblxyXG4vKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuICpcdEN1cnZlZCBQYXRoIC0gYSBjdXJ2ZSBwYXRoIGlzIHNpbXBseSBhIGFycmF5IG9mIGNvbm5lY3RlZFxyXG4gKiAgY3VydmVzLCBidXQgcmV0YWlucyB0aGUgYXBpIG9mIGEgY3VydmVcclxuICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuY2xhc3MgQ3VydmVQYXRoIGV4dGVuZHMgQ3VydmUge1xyXG5cclxuXHRjb25zdHJ1Y3RvcigpIHtcclxuXHJcblx0XHRzdXBlcigpO1xyXG5cclxuXHRcdHRoaXMudHlwZSA9ICdDdXJ2ZVBhdGgnO1xyXG5cclxuXHRcdHRoaXMuY3VydmVzID0gW107XHJcblx0XHR0aGlzLmF1dG9DbG9zZSA9IGZhbHNlOyAvLyBBdXRvbWF0aWNhbGx5IGNsb3NlcyB0aGUgcGF0aFxyXG5cclxuXHR9XHJcblxyXG5cdGFkZCggY3VydmUgKSB7XHJcblxyXG5cdFx0dGhpcy5jdXJ2ZXMucHVzaCggY3VydmUgKTtcclxuXHJcblx0fVxyXG5cclxuXHRjbG9zZVBhdGgoKSB7XHJcblxyXG5cdFx0Ly8gQWRkIGEgbGluZSBjdXJ2ZSBpZiBzdGFydCBhbmQgZW5kIG9mIGxpbmVzIGFyZSBub3QgY29ubmVjdGVkXHJcblx0XHRjb25zdCBzdGFydFBvaW50ID0gdGhpcy5jdXJ2ZXNbIDAgXS5nZXRQb2ludCggMCApO1xyXG5cdFx0Y29uc3QgZW5kUG9pbnQgPSB0aGlzLmN1cnZlc1sgdGhpcy5jdXJ2ZXMubGVuZ3RoIC0gMSBdLmdldFBvaW50KCAxICk7XHJcblxyXG5cdFx0aWYgKCAhIHN0YXJ0UG9pbnQuZXF1YWxzKCBlbmRQb2ludCApICkge1xyXG5cclxuXHRcdFx0Y29uc3QgbGluZVR5cGUgPSAoIHN0YXJ0UG9pbnQuaXNWZWN0b3IyID09PSB0cnVlICkgPyAnTGluZUN1cnZlJyA6ICdMaW5lQ3VydmUzJztcclxuXHRcdFx0dGhpcy5jdXJ2ZXMucHVzaCggbmV3IEN1cnZlc1sgbGluZVR5cGUgXSggZW5kUG9pbnQsIHN0YXJ0UG9pbnQgKSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHQvLyBUbyBnZXQgYWNjdXJhdGUgcG9pbnQgd2l0aCByZWZlcmVuY2UgdG9cclxuXHQvLyBlbnRpcmUgcGF0aCBkaXN0YW5jZSBhdCB0aW1lIHQsXHJcblx0Ly8gZm9sbG93aW5nIGhhcyB0byBiZSBkb25lOlxyXG5cclxuXHQvLyAxLiBMZW5ndGggb2YgZWFjaCBzdWIgcGF0aCBoYXZlIHRvIGJlIGtub3duXHJcblx0Ly8gMi4gTG9jYXRlIGFuZCBpZGVudGlmeSB0eXBlIG9mIGN1cnZlXHJcblx0Ly8gMy4gR2V0IHQgZm9yIHRoZSBjdXJ2ZVxyXG5cdC8vIDQuIFJldHVybiBjdXJ2ZS5nZXRQb2ludEF0KHQnKVxyXG5cclxuXHRnZXRQb2ludCggdCwgb3B0aW9uYWxUYXJnZXQgKSB7XHJcblxyXG5cdFx0Y29uc3QgZCA9IHQgKiB0aGlzLmdldExlbmd0aCgpO1xyXG5cdFx0Y29uc3QgY3VydmVMZW5ndGhzID0gdGhpcy5nZXRDdXJ2ZUxlbmd0aHMoKTtcclxuXHRcdGxldCBpID0gMDtcclxuXHJcblx0XHQvLyBUbyB0aGluayBhYm91dCBib3VuZGFyaWVzIHBvaW50cy5cclxuXHJcblx0XHR3aGlsZSAoIGkgPCBjdXJ2ZUxlbmd0aHMubGVuZ3RoICkge1xyXG5cclxuXHRcdFx0aWYgKCBjdXJ2ZUxlbmd0aHNbIGkgXSA+PSBkICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBkaWZmID0gY3VydmVMZW5ndGhzWyBpIF0gLSBkO1xyXG5cdFx0XHRcdGNvbnN0IGN1cnZlID0gdGhpcy5jdXJ2ZXNbIGkgXTtcclxuXHJcblx0XHRcdFx0Y29uc3Qgc2VnbWVudExlbmd0aCA9IGN1cnZlLmdldExlbmd0aCgpO1xyXG5cdFx0XHRcdGNvbnN0IHUgPSBzZWdtZW50TGVuZ3RoID09PSAwID8gMCA6IDEgLSBkaWZmIC8gc2VnbWVudExlbmd0aDtcclxuXHJcblx0XHRcdFx0cmV0dXJuIGN1cnZlLmdldFBvaW50QXQoIHUsIG9wdGlvbmFsVGFyZ2V0ICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRpICsrO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gbnVsbDtcclxuXHJcblx0XHQvLyBsb29wIHdoZXJlIHN1bSAhPSAwLCBzdW0gPiBkICwgc3VtKzEgPGRcclxuXHJcblx0fVxyXG5cclxuXHQvLyBXZSBjYW5ub3QgdXNlIHRoZSBkZWZhdWx0IFRIUkVFLkN1cnZlIGdldFBvaW50KCkgd2l0aCBnZXRMZW5ndGgoKSBiZWNhdXNlIGluXHJcblx0Ly8gVEhSRUUuQ3VydmUsIGdldExlbmd0aCgpIGRlcGVuZHMgb24gZ2V0UG9pbnQoKSBidXQgaW4gVEhSRUUuQ3VydmVQYXRoXHJcblx0Ly8gZ2V0UG9pbnQoKSBkZXBlbmRzIG9uIGdldExlbmd0aFxyXG5cclxuXHRnZXRMZW5ndGgoKSB7XHJcblxyXG5cdFx0Y29uc3QgbGVucyA9IHRoaXMuZ2V0Q3VydmVMZW5ndGhzKCk7XHJcblx0XHRyZXR1cm4gbGVuc1sgbGVucy5sZW5ndGggLSAxIF07XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gY2FjaGVMZW5ndGhzIG11c3QgYmUgcmVjYWxjdWxhdGVkLlxyXG5cdHVwZGF0ZUFyY0xlbmd0aHMoKSB7XHJcblxyXG5cdFx0dGhpcy5uZWVkc1VwZGF0ZSA9IHRydWU7XHJcblx0XHR0aGlzLmNhY2hlTGVuZ3RocyA9IG51bGw7XHJcblx0XHR0aGlzLmdldEN1cnZlTGVuZ3RocygpO1xyXG5cclxuXHR9XHJcblxyXG5cdC8vIENvbXB1dGUgbGVuZ3RocyBhbmQgY2FjaGUgdGhlbVxyXG5cdC8vIFdlIGNhbm5vdCBvdmVyd3JpdGUgZ2V0TGVuZ3RocygpIGJlY2F1c2UgVXRvVCBtYXBwaW5nIHVzZXMgaXQuXHJcblxyXG5cdGdldEN1cnZlTGVuZ3RocygpIHtcclxuXHJcblx0XHQvLyBXZSB1c2UgY2FjaGUgdmFsdWVzIGlmIGN1cnZlcyBhbmQgY2FjaGUgYXJyYXkgYXJlIHNhbWUgbGVuZ3RoXHJcblxyXG5cdFx0aWYgKCB0aGlzLmNhY2hlTGVuZ3RocyAmJiB0aGlzLmNhY2hlTGVuZ3Rocy5sZW5ndGggPT09IHRoaXMuY3VydmVzLmxlbmd0aCApIHtcclxuXHJcblx0XHRcdHJldHVybiB0aGlzLmNhY2hlTGVuZ3RocztcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gR2V0IGxlbmd0aCBvZiBzdWItY3VydmVcclxuXHRcdC8vIFB1c2ggc3VtcyBpbnRvIGNhY2hlZCBhcnJheVxyXG5cclxuXHRcdGNvbnN0IGxlbmd0aHMgPSBbXTtcclxuXHRcdGxldCBzdW1zID0gMDtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSB0aGlzLmN1cnZlcy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0c3VtcyArPSB0aGlzLmN1cnZlc1sgaSBdLmdldExlbmd0aCgpO1xyXG5cdFx0XHRsZW5ndGhzLnB1c2goIHN1bXMgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5jYWNoZUxlbmd0aHMgPSBsZW5ndGhzO1xyXG5cclxuXHRcdHJldHVybiBsZW5ndGhzO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldFNwYWNlZFBvaW50cyggZGl2aXNpb25zID0gNDAgKSB7XHJcblxyXG5cdFx0Y29uc3QgcG9pbnRzID0gW107XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDw9IGRpdmlzaW9uczsgaSArKyApIHtcclxuXHJcblx0XHRcdHBvaW50cy5wdXNoKCB0aGlzLmdldFBvaW50KCBpIC8gZGl2aXNpb25zICkgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCB0aGlzLmF1dG9DbG9zZSApIHtcclxuXHJcblx0XHRcdHBvaW50cy5wdXNoKCBwb2ludHNbIDAgXSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gcG9pbnRzO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldFBvaW50cyggZGl2aXNpb25zID0gMTIgKSB7XHJcblxyXG5cdFx0Y29uc3QgcG9pbnRzID0gW107XHJcblx0XHRsZXQgbGFzdDtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGN1cnZlcyA9IHRoaXMuY3VydmVzOyBpIDwgY3VydmVzLmxlbmd0aDsgaSArKyApIHtcclxuXHJcblx0XHRcdGNvbnN0IGN1cnZlID0gY3VydmVzWyBpIF07XHJcblx0XHRcdGNvbnN0IHJlc29sdXRpb24gPSBjdXJ2ZS5pc0VsbGlwc2VDdXJ2ZSA/IGRpdmlzaW9ucyAqIDJcclxuXHRcdFx0XHQ6ICggY3VydmUuaXNMaW5lQ3VydmUgfHwgY3VydmUuaXNMaW5lQ3VydmUzICkgPyAxXHJcblx0XHRcdFx0XHQ6IGN1cnZlLmlzU3BsaW5lQ3VydmUgPyBkaXZpc2lvbnMgKiBjdXJ2ZS5wb2ludHMubGVuZ3RoXHJcblx0XHRcdFx0XHRcdDogZGl2aXNpb25zO1xyXG5cclxuXHRcdFx0Y29uc3QgcHRzID0gY3VydmUuZ2V0UG9pbnRzKCByZXNvbHV0aW9uICk7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaiA9IDA7IGogPCBwdHMubGVuZ3RoOyBqICsrICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBwb2ludCA9IHB0c1sgaiBdO1xyXG5cclxuXHRcdFx0XHRpZiAoIGxhc3QgJiYgbGFzdC5lcXVhbHMoIHBvaW50ICkgKSBjb250aW51ZTsgLy8gZW5zdXJlcyBubyBjb25zZWN1dGl2ZSBwb2ludHMgYXJlIGR1cGxpY2F0ZXNcclxuXHJcblx0XHRcdFx0cG9pbnRzLnB1c2goIHBvaW50ICk7XHJcblx0XHRcdFx0bGFzdCA9IHBvaW50O1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHRoaXMuYXV0b0Nsb3NlICYmIHBvaW50cy5sZW5ndGggPiAxICYmICEgcG9pbnRzWyBwb2ludHMubGVuZ3RoIC0gMSBdLmVxdWFscyggcG9pbnRzWyAwIF0gKSApIHtcclxuXHJcblx0XHRcdHBvaW50cy5wdXNoKCBwb2ludHNbIDAgXSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gcG9pbnRzO1xyXG5cclxuXHR9XHJcblxyXG5cdGNvcHkoIHNvdXJjZSApIHtcclxuXHJcblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcclxuXHJcblx0XHR0aGlzLmN1cnZlcyA9IFtdO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IHNvdXJjZS5jdXJ2ZXMubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdGNvbnN0IGN1cnZlID0gc291cmNlLmN1cnZlc1sgaSBdO1xyXG5cclxuXHRcdFx0dGhpcy5jdXJ2ZXMucHVzaCggY3VydmUuY2xvbmUoKSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLmF1dG9DbG9zZSA9IHNvdXJjZS5hdXRvQ2xvc2U7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0dG9KU09OKCkge1xyXG5cclxuXHRcdGNvbnN0IGRhdGEgPSBzdXBlci50b0pTT04oKTtcclxuXHJcblx0XHRkYXRhLmF1dG9DbG9zZSA9IHRoaXMuYXV0b0Nsb3NlO1xyXG5cdFx0ZGF0YS5jdXJ2ZXMgPSBbXTtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSB0aGlzLmN1cnZlcy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0Y29uc3QgY3VydmUgPSB0aGlzLmN1cnZlc1sgaSBdO1xyXG5cdFx0XHRkYXRhLmN1cnZlcy5wdXNoKCBjdXJ2ZS50b0pTT04oKSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gZGF0YTtcclxuXHJcblx0fVxyXG5cclxuXHRmcm9tSlNPTigganNvbiApIHtcclxuXHJcblx0XHRzdXBlci5mcm9tSlNPTigganNvbiApO1xyXG5cclxuXHRcdHRoaXMuYXV0b0Nsb3NlID0ganNvbi5hdXRvQ2xvc2U7XHJcblx0XHR0aGlzLmN1cnZlcyA9IFtdO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IGpzb24uY3VydmVzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBjdXJ2ZSA9IGpzb24uY3VydmVzWyBpIF07XHJcblx0XHRcdHRoaXMuY3VydmVzLnB1c2goIG5ldyBDdXJ2ZXNbIGN1cnZlLnR5cGUgXSgpLmZyb21KU09OKCBjdXJ2ZSApICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5cclxuZXhwb3J0IHsgQ3VydmVQYXRoIH07XHJcbiIsImltcG9ydCB7IFZlY3RvcjIgfSBmcm9tICcuLi8uLi9tYXRoL1ZlY3RvcjIuanMnO1xyXG5pbXBvcnQgeyBDdXJ2ZVBhdGggfSBmcm9tICcuL0N1cnZlUGF0aC5qcyc7XHJcbmltcG9ydCB7IEVsbGlwc2VDdXJ2ZSB9IGZyb20gJy4uL2N1cnZlcy9FbGxpcHNlQ3VydmUuanMnO1xyXG5pbXBvcnQgeyBTcGxpbmVDdXJ2ZSB9IGZyb20gJy4uL2N1cnZlcy9TcGxpbmVDdXJ2ZS5qcyc7XHJcbmltcG9ydCB7IEN1YmljQmV6aWVyQ3VydmUgfSBmcm9tICcuLi9jdXJ2ZXMvQ3ViaWNCZXppZXJDdXJ2ZS5qcyc7XHJcbmltcG9ydCB7IFF1YWRyYXRpY0JlemllckN1cnZlIH0gZnJvbSAnLi4vY3VydmVzL1F1YWRyYXRpY0JlemllckN1cnZlLmpzJztcclxuaW1wb3J0IHsgTGluZUN1cnZlIH0gZnJvbSAnLi4vY3VydmVzL0xpbmVDdXJ2ZS5qcyc7XHJcblxyXG5jbGFzcyBQYXRoIGV4dGVuZHMgQ3VydmVQYXRoIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIHBvaW50cyApIHtcclxuXHJcblx0XHRzdXBlcigpO1xyXG5cclxuXHRcdHRoaXMudHlwZSA9ICdQYXRoJztcclxuXHJcblx0XHR0aGlzLmN1cnJlbnRQb2ludCA9IG5ldyBWZWN0b3IyKCk7XHJcblxyXG5cdFx0aWYgKCBwb2ludHMgKSB7XHJcblxyXG5cdFx0XHR0aGlzLnNldEZyb21Qb2ludHMoIHBvaW50cyApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRzZXRGcm9tUG9pbnRzKCBwb2ludHMgKSB7XHJcblxyXG5cdFx0dGhpcy5tb3ZlVG8oIHBvaW50c1sgMCBdLngsIHBvaW50c1sgMCBdLnkgKTtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDEsIGwgPSBwb2ludHMubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdHRoaXMubGluZVRvKCBwb2ludHNbIGkgXS54LCBwb2ludHNbIGkgXS55ICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdG1vdmVUbyggeCwgeSApIHtcclxuXHJcblx0XHR0aGlzLmN1cnJlbnRQb2ludC5zZXQoIHgsIHkgKTsgLy8gVE9ETyBjb25zaWRlciByZWZlcmVuY2luZyB2ZWN0b3JzIGluc3RlYWQgb2YgY29weWluZz9cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRsaW5lVG8oIHgsIHkgKSB7XHJcblxyXG5cdFx0Y29uc3QgY3VydmUgPSBuZXcgTGluZUN1cnZlKCB0aGlzLmN1cnJlbnRQb2ludC5jbG9uZSgpLCBuZXcgVmVjdG9yMiggeCwgeSApICk7XHJcblx0XHR0aGlzLmN1cnZlcy5wdXNoKCBjdXJ2ZSApO1xyXG5cclxuXHRcdHRoaXMuY3VycmVudFBvaW50LnNldCggeCwgeSApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHF1YWRyYXRpY0N1cnZlVG8oIGFDUHgsIGFDUHksIGFYLCBhWSApIHtcclxuXHJcblx0XHRjb25zdCBjdXJ2ZSA9IG5ldyBRdWFkcmF0aWNCZXppZXJDdXJ2ZShcclxuXHRcdFx0dGhpcy5jdXJyZW50UG9pbnQuY2xvbmUoKSxcclxuXHRcdFx0bmV3IFZlY3RvcjIoIGFDUHgsIGFDUHkgKSxcclxuXHRcdFx0bmV3IFZlY3RvcjIoIGFYLCBhWSApXHJcblx0XHQpO1xyXG5cclxuXHRcdHRoaXMuY3VydmVzLnB1c2goIGN1cnZlICk7XHJcblxyXG5cdFx0dGhpcy5jdXJyZW50UG9pbnQuc2V0KCBhWCwgYVkgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRiZXppZXJDdXJ2ZVRvKCBhQ1AxeCwgYUNQMXksIGFDUDJ4LCBhQ1AyeSwgYVgsIGFZICkge1xyXG5cclxuXHRcdGNvbnN0IGN1cnZlID0gbmV3IEN1YmljQmV6aWVyQ3VydmUoXHJcblx0XHRcdHRoaXMuY3VycmVudFBvaW50LmNsb25lKCksXHJcblx0XHRcdG5ldyBWZWN0b3IyKCBhQ1AxeCwgYUNQMXkgKSxcclxuXHRcdFx0bmV3IFZlY3RvcjIoIGFDUDJ4LCBhQ1AyeSApLFxyXG5cdFx0XHRuZXcgVmVjdG9yMiggYVgsIGFZIClcclxuXHRcdCk7XHJcblxyXG5cdFx0dGhpcy5jdXJ2ZXMucHVzaCggY3VydmUgKTtcclxuXHJcblx0XHR0aGlzLmN1cnJlbnRQb2ludC5zZXQoIGFYLCBhWSApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNwbGluZVRocnUoIHB0cyAvKkFycmF5IG9mIFZlY3RvciovICkge1xyXG5cclxuXHRcdGNvbnN0IG5wdHMgPSBbIHRoaXMuY3VycmVudFBvaW50LmNsb25lKCkgXS5jb25jYXQoIHB0cyApO1xyXG5cclxuXHRcdGNvbnN0IGN1cnZlID0gbmV3IFNwbGluZUN1cnZlKCBucHRzICk7XHJcblx0XHR0aGlzLmN1cnZlcy5wdXNoKCBjdXJ2ZSApO1xyXG5cclxuXHRcdHRoaXMuY3VycmVudFBvaW50LmNvcHkoIHB0c1sgcHRzLmxlbmd0aCAtIDEgXSApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGFyYyggYVgsIGFZLCBhUmFkaXVzLCBhU3RhcnRBbmdsZSwgYUVuZEFuZ2xlLCBhQ2xvY2t3aXNlICkge1xyXG5cclxuXHRcdGNvbnN0IHgwID0gdGhpcy5jdXJyZW50UG9pbnQueDtcclxuXHRcdGNvbnN0IHkwID0gdGhpcy5jdXJyZW50UG9pbnQueTtcclxuXHJcblx0XHR0aGlzLmFic2FyYyggYVggKyB4MCwgYVkgKyB5MCwgYVJhZGl1cyxcclxuXHRcdFx0YVN0YXJ0QW5nbGUsIGFFbmRBbmdsZSwgYUNsb2Nrd2lzZSApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGFic2FyYyggYVgsIGFZLCBhUmFkaXVzLCBhU3RhcnRBbmdsZSwgYUVuZEFuZ2xlLCBhQ2xvY2t3aXNlICkge1xyXG5cclxuXHRcdHRoaXMuYWJzZWxsaXBzZSggYVgsIGFZLCBhUmFkaXVzLCBhUmFkaXVzLCBhU3RhcnRBbmdsZSwgYUVuZEFuZ2xlLCBhQ2xvY2t3aXNlICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0ZWxsaXBzZSggYVgsIGFZLCB4UmFkaXVzLCB5UmFkaXVzLCBhU3RhcnRBbmdsZSwgYUVuZEFuZ2xlLCBhQ2xvY2t3aXNlLCBhUm90YXRpb24gKSB7XHJcblxyXG5cdFx0Y29uc3QgeDAgPSB0aGlzLmN1cnJlbnRQb2ludC54O1xyXG5cdFx0Y29uc3QgeTAgPSB0aGlzLmN1cnJlbnRQb2ludC55O1xyXG5cclxuXHRcdHRoaXMuYWJzZWxsaXBzZSggYVggKyB4MCwgYVkgKyB5MCwgeFJhZGl1cywgeVJhZGl1cywgYVN0YXJ0QW5nbGUsIGFFbmRBbmdsZSwgYUNsb2Nrd2lzZSwgYVJvdGF0aW9uICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0YWJzZWxsaXBzZSggYVgsIGFZLCB4UmFkaXVzLCB5UmFkaXVzLCBhU3RhcnRBbmdsZSwgYUVuZEFuZ2xlLCBhQ2xvY2t3aXNlLCBhUm90YXRpb24gKSB7XHJcblxyXG5cdFx0Y29uc3QgY3VydmUgPSBuZXcgRWxsaXBzZUN1cnZlKCBhWCwgYVksIHhSYWRpdXMsIHlSYWRpdXMsIGFTdGFydEFuZ2xlLCBhRW5kQW5nbGUsIGFDbG9ja3dpc2UsIGFSb3RhdGlvbiApO1xyXG5cclxuXHRcdGlmICggdGhpcy5jdXJ2ZXMubGVuZ3RoID4gMCApIHtcclxuXHJcblx0XHRcdC8vIGlmIGEgcHJldmlvdXMgY3VydmUgaXMgcHJlc2VudCwgYXR0ZW1wdCB0byBqb2luXHJcblx0XHRcdGNvbnN0IGZpcnN0UG9pbnQgPSBjdXJ2ZS5nZXRQb2ludCggMCApO1xyXG5cclxuXHRcdFx0aWYgKCAhIGZpcnN0UG9pbnQuZXF1YWxzKCB0aGlzLmN1cnJlbnRQb2ludCApICkge1xyXG5cclxuXHRcdFx0XHR0aGlzLmxpbmVUbyggZmlyc3RQb2ludC54LCBmaXJzdFBvaW50LnkgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5jdXJ2ZXMucHVzaCggY3VydmUgKTtcclxuXHJcblx0XHRjb25zdCBsYXN0UG9pbnQgPSBjdXJ2ZS5nZXRQb2ludCggMSApO1xyXG5cdFx0dGhpcy5jdXJyZW50UG9pbnQuY29weSggbGFzdFBvaW50ICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xyXG5cclxuXHRcdHRoaXMuY3VycmVudFBvaW50LmNvcHkoIHNvdXJjZS5jdXJyZW50UG9pbnQgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHR0b0pTT04oKSB7XHJcblxyXG5cdFx0Y29uc3QgZGF0YSA9IHN1cGVyLnRvSlNPTigpO1xyXG5cclxuXHRcdGRhdGEuY3VycmVudFBvaW50ID0gdGhpcy5jdXJyZW50UG9pbnQudG9BcnJheSgpO1xyXG5cclxuXHRcdHJldHVybiBkYXRhO1xyXG5cclxuXHR9XHJcblxyXG5cdGZyb21KU09OKCBqc29uICkge1xyXG5cclxuXHRcdHN1cGVyLmZyb21KU09OKCBqc29uICk7XHJcblxyXG5cdFx0dGhpcy5jdXJyZW50UG9pbnQuZnJvbUFycmF5KCBqc29uLmN1cnJlbnRQb2ludCApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5cclxuZXhwb3J0IHsgUGF0aCB9O1xyXG4iLCJpbXBvcnQgeyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlIH0gZnJvbSAnLi4vY29yZS9CdWZmZXJBdHRyaWJ1dGUuanMnO1xyXG5pbXBvcnQgeyBCdWZmZXJHZW9tZXRyeSB9IGZyb20gJy4uL2NvcmUvQnVmZmVyR2VvbWV0cnkuanMnO1xyXG5pbXBvcnQgeyBWZWN0b3IzIH0gZnJvbSAnLi4vbWF0aC9WZWN0b3IzLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yMiB9IGZyb20gJy4uL21hdGgvVmVjdG9yMi5qcyc7XHJcbmltcG9ydCAqIGFzIE1hdGhVdGlscyBmcm9tICcuLi9tYXRoL01hdGhVdGlscy5qcyc7XHJcblxyXG5jbGFzcyBMYXRoZUdlb21ldHJ5IGV4dGVuZHMgQnVmZmVyR2VvbWV0cnkge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggcG9pbnRzID0gWyBuZXcgVmVjdG9yMiggMCwgLSAwLjUgKSwgbmV3IFZlY3RvcjIoIDAuNSwgMCApLCBuZXcgVmVjdG9yMiggMCwgMC41ICkgXSwgc2VnbWVudHMgPSAxMiwgcGhpU3RhcnQgPSAwLCBwaGlMZW5ndGggPSBNYXRoLlBJICogMiApIHtcclxuXHJcblx0XHRzdXBlcigpO1xyXG5cclxuXHRcdHRoaXMudHlwZSA9ICdMYXRoZUdlb21ldHJ5JztcclxuXHJcblx0XHR0aGlzLnBhcmFtZXRlcnMgPSB7XHJcblx0XHRcdHBvaW50czogcG9pbnRzLFxyXG5cdFx0XHRzZWdtZW50czogc2VnbWVudHMsXHJcblx0XHRcdHBoaVN0YXJ0OiBwaGlTdGFydCxcclxuXHRcdFx0cGhpTGVuZ3RoOiBwaGlMZW5ndGhcclxuXHRcdH07XHJcblxyXG5cdFx0c2VnbWVudHMgPSBNYXRoLmZsb29yKCBzZWdtZW50cyApO1xyXG5cclxuXHRcdC8vIGNsYW1wIHBoaUxlbmd0aCBzbyBpdCdzIGluIHJhbmdlIG9mIFsgMCwgMlBJIF1cclxuXHJcblx0XHRwaGlMZW5ndGggPSBNYXRoVXRpbHMuY2xhbXAoIHBoaUxlbmd0aCwgMCwgTWF0aC5QSSAqIDIgKTtcclxuXHJcblx0XHQvLyBidWZmZXJzXHJcblxyXG5cdFx0Y29uc3QgaW5kaWNlcyA9IFtdO1xyXG5cdFx0Y29uc3QgdmVydGljZXMgPSBbXTtcclxuXHRcdGNvbnN0IHV2cyA9IFtdO1xyXG5cdFx0Y29uc3QgaW5pdE5vcm1hbHMgPSBbXTtcclxuXHRcdGNvbnN0IG5vcm1hbHMgPSBbXTtcclxuXHJcblx0XHQvLyBoZWxwZXIgdmFyaWFibGVzXHJcblxyXG5cdFx0Y29uc3QgaW52ZXJzZVNlZ21lbnRzID0gMS4wIC8gc2VnbWVudHM7XHJcblx0XHRjb25zdCB2ZXJ0ZXggPSBuZXcgVmVjdG9yMygpO1xyXG5cdFx0Y29uc3QgdXYgPSBuZXcgVmVjdG9yMigpO1xyXG5cdFx0Y29uc3Qgbm9ybWFsID0gbmV3IFZlY3RvcjMoKTtcclxuXHRcdGNvbnN0IGN1ck5vcm1hbCA9IG5ldyBWZWN0b3IzKCk7XHJcblx0XHRjb25zdCBwcmV2Tm9ybWFsID0gbmV3IFZlY3RvcjMoKTtcclxuXHRcdGxldCBkeCA9IDA7XHJcblx0XHRsZXQgZHkgPSAwO1xyXG5cclxuXHRcdC8vIHByZS1jb21wdXRlIG5vcm1hbHMgZm9yIGluaXRpYWwgXCJtZXJpZGlhblwiXHJcblxyXG5cdFx0Zm9yICggbGV0IGogPSAwOyBqIDw9ICggcG9pbnRzLmxlbmd0aCAtIDEgKTsgaiArKyApIHtcclxuXHJcblx0XHRcdHN3aXRjaCAoIGogKSB7XHJcblxyXG5cdFx0XHRcdGNhc2UgMDpcdFx0XHRcdC8vIHNwZWNpYWwgaGFuZGxpbmcgZm9yIDFzdCB2ZXJ0ZXggb24gcGF0aFxyXG5cclxuXHRcdFx0XHRcdGR4ID0gcG9pbnRzWyBqICsgMSBdLnggLSBwb2ludHNbIGogXS54O1xyXG5cdFx0XHRcdFx0ZHkgPSBwb2ludHNbIGogKyAxIF0ueSAtIHBvaW50c1sgaiBdLnk7XHJcblxyXG5cdFx0XHRcdFx0bm9ybWFsLnggPSBkeSAqIDEuMDtcclxuXHRcdFx0XHRcdG5vcm1hbC55ID0gLSBkeDtcclxuXHRcdFx0XHRcdG5vcm1hbC56ID0gZHkgKiAwLjA7XHJcblxyXG5cdFx0XHRcdFx0cHJldk5vcm1hbC5jb3B5KCBub3JtYWwgKTtcclxuXHJcblx0XHRcdFx0XHRub3JtYWwubm9ybWFsaXplKCk7XHJcblxyXG5cdFx0XHRcdFx0aW5pdE5vcm1hbHMucHVzaCggbm9ybWFsLngsIG5vcm1hbC55LCBub3JtYWwueiApO1xyXG5cclxuXHRcdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0XHRjYXNlICggcG9pbnRzLmxlbmd0aCAtIDEgKTpcdC8vIHNwZWNpYWwgaGFuZGxpbmcgZm9yIGxhc3QgVmVydGV4IG9uIHBhdGhcclxuXHJcblx0XHRcdFx0XHRpbml0Tm9ybWFscy5wdXNoKCBwcmV2Tm9ybWFsLngsIHByZXZOb3JtYWwueSwgcHJldk5vcm1hbC56ICk7XHJcblxyXG5cdFx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRcdGRlZmF1bHQ6XHRcdFx0Ly8gZGVmYXVsdCBoYW5kbGluZyBmb3IgYWxsIHZlcnRpY2VzIGluIGJldHdlZW5cclxuXHJcblx0XHRcdFx0XHRkeCA9IHBvaW50c1sgaiArIDEgXS54IC0gcG9pbnRzWyBqIF0ueDtcclxuXHRcdFx0XHRcdGR5ID0gcG9pbnRzWyBqICsgMSBdLnkgLSBwb2ludHNbIGogXS55O1xyXG5cclxuXHRcdFx0XHRcdG5vcm1hbC54ID0gZHkgKiAxLjA7XHJcblx0XHRcdFx0XHRub3JtYWwueSA9IC0gZHg7XHJcblx0XHRcdFx0XHRub3JtYWwueiA9IGR5ICogMC4wO1xyXG5cclxuXHRcdFx0XHRcdGN1ck5vcm1hbC5jb3B5KCBub3JtYWwgKTtcclxuXHJcblx0XHRcdFx0XHRub3JtYWwueCArPSBwcmV2Tm9ybWFsLng7XHJcblx0XHRcdFx0XHRub3JtYWwueSArPSBwcmV2Tm9ybWFsLnk7XHJcblx0XHRcdFx0XHRub3JtYWwueiArPSBwcmV2Tm9ybWFsLno7XHJcblxyXG5cdFx0XHRcdFx0bm9ybWFsLm5vcm1hbGl6ZSgpO1xyXG5cclxuXHRcdFx0XHRcdGluaXROb3JtYWxzLnB1c2goIG5vcm1hbC54LCBub3JtYWwueSwgbm9ybWFsLnogKTtcclxuXHJcblx0XHRcdFx0XHRwcmV2Tm9ybWFsLmNvcHkoIGN1ck5vcm1hbCApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvLyBnZW5lcmF0ZSB2ZXJ0aWNlcywgdXZzIGFuZCBub3JtYWxzXHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDw9IHNlZ21lbnRzOyBpICsrICkge1xyXG5cclxuXHRcdFx0Y29uc3QgcGhpID0gcGhpU3RhcnQgKyBpICogaW52ZXJzZVNlZ21lbnRzICogcGhpTGVuZ3RoO1xyXG5cclxuXHRcdFx0Y29uc3Qgc2luID0gTWF0aC5zaW4oIHBoaSApO1xyXG5cdFx0XHRjb25zdCBjb3MgPSBNYXRoLmNvcyggcGhpICk7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaiA9IDA7IGogPD0gKCBwb2ludHMubGVuZ3RoIC0gMSApOyBqICsrICkge1xyXG5cclxuXHRcdFx0XHQvLyB2ZXJ0ZXhcclxuXHJcblx0XHRcdFx0dmVydGV4LnggPSBwb2ludHNbIGogXS54ICogc2luO1xyXG5cdFx0XHRcdHZlcnRleC55ID0gcG9pbnRzWyBqIF0ueTtcclxuXHRcdFx0XHR2ZXJ0ZXgueiA9IHBvaW50c1sgaiBdLnggKiBjb3M7XHJcblxyXG5cdFx0XHRcdHZlcnRpY2VzLnB1c2goIHZlcnRleC54LCB2ZXJ0ZXgueSwgdmVydGV4LnogKTtcclxuXHJcblx0XHRcdFx0Ly8gdXZcclxuXHJcblx0XHRcdFx0dXYueCA9IGkgLyBzZWdtZW50cztcclxuXHRcdFx0XHR1di55ID0gaiAvICggcG9pbnRzLmxlbmd0aCAtIDEgKTtcclxuXHJcblx0XHRcdFx0dXZzLnB1c2goIHV2LngsIHV2LnkgKTtcclxuXHJcblx0XHRcdFx0Ly8gbm9ybWFsXHJcblxyXG5cdFx0XHRcdGNvbnN0IHggPSBpbml0Tm9ybWFsc1sgMyAqIGogKyAwIF0gKiBzaW47XHJcblx0XHRcdFx0Y29uc3QgeSA9IGluaXROb3JtYWxzWyAzICogaiArIDEgXTtcclxuXHRcdFx0XHRjb25zdCB6ID0gaW5pdE5vcm1hbHNbIDMgKiBqICsgMCBdICogY29zO1xyXG5cclxuXHRcdFx0XHRub3JtYWxzLnB1c2goIHgsIHksIHogKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gaW5kaWNlc1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHNlZ21lbnRzOyBpICsrICkge1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGogPSAwOyBqIDwgKCBwb2ludHMubGVuZ3RoIC0gMSApOyBqICsrICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBiYXNlID0gaiArIGkgKiBwb2ludHMubGVuZ3RoO1xyXG5cclxuXHRcdFx0XHRjb25zdCBhID0gYmFzZTtcclxuXHRcdFx0XHRjb25zdCBiID0gYmFzZSArIHBvaW50cy5sZW5ndGg7XHJcblx0XHRcdFx0Y29uc3QgYyA9IGJhc2UgKyBwb2ludHMubGVuZ3RoICsgMTtcclxuXHRcdFx0XHRjb25zdCBkID0gYmFzZSArIDE7XHJcblxyXG5cdFx0XHRcdC8vIGZhY2VzXHJcblxyXG5cdFx0XHRcdGluZGljZXMucHVzaCggYSwgYiwgZCApO1xyXG5cdFx0XHRcdGluZGljZXMucHVzaCggYywgZCwgYiApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvLyBidWlsZCBnZW9tZXRyeVxyXG5cclxuXHRcdHRoaXMuc2V0SW5kZXgoIGluZGljZXMgKTtcclxuXHRcdHRoaXMuc2V0QXR0cmlidXRlKCAncG9zaXRpb24nLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggdmVydGljZXMsIDMgKSApO1xyXG5cdFx0dGhpcy5zZXRBdHRyaWJ1dGUoICd1dicsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCB1dnMsIDIgKSApO1xyXG5cdFx0dGhpcy5zZXRBdHRyaWJ1dGUoICdub3JtYWwnLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggbm9ybWFscywgMyApICk7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xyXG5cclxuXHRcdHRoaXMucGFyYW1ldGVycyA9IE9iamVjdC5hc3NpZ24oIHt9LCBzb3VyY2UucGFyYW1ldGVycyApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHN0YXRpYyBmcm9tSlNPTiggZGF0YSApIHtcclxuXHJcblx0XHRyZXR1cm4gbmV3IExhdGhlR2VvbWV0cnkoIGRhdGEucG9pbnRzLCBkYXRhLnNlZ21lbnRzLCBkYXRhLnBoaVN0YXJ0LCBkYXRhLnBoaUxlbmd0aCApO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5cclxuZXhwb3J0IHsgTGF0aGVHZW9tZXRyeSB9O1xyXG4iLCJpbXBvcnQgeyBQYXRoIH0gZnJvbSAnLi4vZXh0cmFzL2NvcmUvUGF0aC5qcyc7XHJcbmltcG9ydCB7IExhdGhlR2VvbWV0cnkgfSBmcm9tICcuL0xhdGhlR2VvbWV0cnkuanMnO1xyXG5cclxuY2xhc3MgQ2Fwc3VsZUdlb21ldHJ5IGV4dGVuZHMgTGF0aGVHZW9tZXRyeSB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCByYWRpdXMgPSAxLCBsZW5ndGggPSAxLCBjYXBTZWdtZW50cyA9IDQsIHJhZGlhbFNlZ21lbnRzID0gOCApIHtcclxuXHJcblx0XHRjb25zdCBwYXRoID0gbmV3IFBhdGgoKTtcclxuXHRcdHBhdGguYWJzYXJjKCAwLCAtIGxlbmd0aCAvIDIsIHJhZGl1cywgTWF0aC5QSSAqIDEuNSwgMCApO1xyXG5cdFx0cGF0aC5hYnNhcmMoIDAsIGxlbmd0aCAvIDIsIHJhZGl1cywgMCwgTWF0aC5QSSAqIDAuNSApO1xyXG5cclxuXHRcdHN1cGVyKCBwYXRoLmdldFBvaW50cyggY2FwU2VnbWVudHMgKSwgcmFkaWFsU2VnbWVudHMgKTtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSAnQ2Fwc3VsZUdlb21ldHJ5JztcclxuXHJcblx0XHR0aGlzLnBhcmFtZXRlcnMgPSB7XHJcblx0XHRcdHJhZGl1czogcmFkaXVzLFxyXG5cdFx0XHRsZW5ndGg6IGxlbmd0aCxcclxuXHRcdFx0Y2FwU2VnbWVudHM6IGNhcFNlZ21lbnRzLFxyXG5cdFx0XHRyYWRpYWxTZWdtZW50czogcmFkaWFsU2VnbWVudHMsXHJcblx0XHR9O1xyXG5cclxuXHR9XHJcblxyXG5cdHN0YXRpYyBmcm9tSlNPTiggZGF0YSApIHtcclxuXHJcblx0XHRyZXR1cm4gbmV3IENhcHN1bGVHZW9tZXRyeSggZGF0YS5yYWRpdXMsIGRhdGEubGVuZ3RoLCBkYXRhLmNhcFNlZ21lbnRzLCBkYXRhLnJhZGlhbFNlZ21lbnRzICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IENhcHN1bGVHZW9tZXRyeSB9O1xyXG4iLCJpbXBvcnQgeyBCdWZmZXJHZW9tZXRyeSB9IGZyb20gJy4uL2NvcmUvQnVmZmVyR2VvbWV0cnkuanMnO1xyXG5pbXBvcnQgeyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlIH0gZnJvbSAnLi4vY29yZS9CdWZmZXJBdHRyaWJ1dGUuanMnO1xyXG5pbXBvcnQgeyBWZWN0b3IzIH0gZnJvbSAnLi4vbWF0aC9WZWN0b3IzLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yMiB9IGZyb20gJy4uL21hdGgvVmVjdG9yMi5qcyc7XHJcblxyXG5jbGFzcyBDaXJjbGVHZW9tZXRyeSBleHRlbmRzIEJ1ZmZlckdlb21ldHJ5IHtcclxuXHJcblx0Y29uc3RydWN0b3IoIHJhZGl1cyA9IDEsIHNlZ21lbnRzID0gMzIsIHRoZXRhU3RhcnQgPSAwLCB0aGV0YUxlbmd0aCA9IE1hdGguUEkgKiAyICkge1xyXG5cclxuXHRcdHN1cGVyKCk7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ0NpcmNsZUdlb21ldHJ5JztcclxuXHJcblx0XHR0aGlzLnBhcmFtZXRlcnMgPSB7XHJcblx0XHRcdHJhZGl1czogcmFkaXVzLFxyXG5cdFx0XHRzZWdtZW50czogc2VnbWVudHMsXHJcblx0XHRcdHRoZXRhU3RhcnQ6IHRoZXRhU3RhcnQsXHJcblx0XHRcdHRoZXRhTGVuZ3RoOiB0aGV0YUxlbmd0aFxyXG5cdFx0fTtcclxuXHJcblx0XHRzZWdtZW50cyA9IE1hdGgubWF4KCAzLCBzZWdtZW50cyApO1xyXG5cclxuXHRcdC8vIGJ1ZmZlcnNcclxuXHJcblx0XHRjb25zdCBpbmRpY2VzID0gW107XHJcblx0XHRjb25zdCB2ZXJ0aWNlcyA9IFtdO1xyXG5cdFx0Y29uc3Qgbm9ybWFscyA9IFtdO1xyXG5cdFx0Y29uc3QgdXZzID0gW107XHJcblxyXG5cdFx0Ly8gaGVscGVyIHZhcmlhYmxlc1xyXG5cclxuXHRcdGNvbnN0IHZlcnRleCA9IG5ldyBWZWN0b3IzKCk7XHJcblx0XHRjb25zdCB1diA9IG5ldyBWZWN0b3IyKCk7XHJcblxyXG5cdFx0Ly8gY2VudGVyIHBvaW50XHJcblxyXG5cdFx0dmVydGljZXMucHVzaCggMCwgMCwgMCApO1xyXG5cdFx0bm9ybWFscy5wdXNoKCAwLCAwLCAxICk7XHJcblx0XHR1dnMucHVzaCggMC41LCAwLjUgKTtcclxuXHJcblx0XHRmb3IgKCBsZXQgcyA9IDAsIGkgPSAzOyBzIDw9IHNlZ21lbnRzOyBzICsrLCBpICs9IDMgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBzZWdtZW50ID0gdGhldGFTdGFydCArIHMgLyBzZWdtZW50cyAqIHRoZXRhTGVuZ3RoO1xyXG5cclxuXHRcdFx0Ly8gdmVydGV4XHJcblxyXG5cdFx0XHR2ZXJ0ZXgueCA9IHJhZGl1cyAqIE1hdGguY29zKCBzZWdtZW50ICk7XHJcblx0XHRcdHZlcnRleC55ID0gcmFkaXVzICogTWF0aC5zaW4oIHNlZ21lbnQgKTtcclxuXHJcblx0XHRcdHZlcnRpY2VzLnB1c2goIHZlcnRleC54LCB2ZXJ0ZXgueSwgdmVydGV4LnogKTtcclxuXHJcblx0XHRcdC8vIG5vcm1hbFxyXG5cclxuXHRcdFx0bm9ybWFscy5wdXNoKCAwLCAwLCAxICk7XHJcblxyXG5cdFx0XHQvLyB1dnNcclxuXHJcblx0XHRcdHV2LnggPSAoIHZlcnRpY2VzWyBpIF0gLyByYWRpdXMgKyAxICkgLyAyO1xyXG5cdFx0XHR1di55ID0gKCB2ZXJ0aWNlc1sgaSArIDEgXSAvIHJhZGl1cyArIDEgKSAvIDI7XHJcblxyXG5cdFx0XHR1dnMucHVzaCggdXYueCwgdXYueSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvLyBpbmRpY2VzXHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAxOyBpIDw9IHNlZ21lbnRzOyBpICsrICkge1xyXG5cclxuXHRcdFx0aW5kaWNlcy5wdXNoKCBpLCBpICsgMSwgMCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvLyBidWlsZCBnZW9tZXRyeVxyXG5cclxuXHRcdHRoaXMuc2V0SW5kZXgoIGluZGljZXMgKTtcclxuXHRcdHRoaXMuc2V0QXR0cmlidXRlKCAncG9zaXRpb24nLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggdmVydGljZXMsIDMgKSApO1xyXG5cdFx0dGhpcy5zZXRBdHRyaWJ1dGUoICdub3JtYWwnLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggbm9ybWFscywgMyApICk7XHJcblx0XHR0aGlzLnNldEF0dHJpYnV0ZSggJ3V2JywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIHV2cywgMiApICk7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xyXG5cclxuXHRcdHRoaXMucGFyYW1ldGVycyA9IE9iamVjdC5hc3NpZ24oIHt9LCBzb3VyY2UucGFyYW1ldGVycyApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHN0YXRpYyBmcm9tSlNPTiggZGF0YSApIHtcclxuXHJcblx0XHRyZXR1cm4gbmV3IENpcmNsZUdlb21ldHJ5KCBkYXRhLnJhZGl1cywgZGF0YS5zZWdtZW50cywgZGF0YS50aGV0YVN0YXJ0LCBkYXRhLnRoZXRhTGVuZ3RoICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcblxyXG5leHBvcnQgeyBDaXJjbGVHZW9tZXRyeSB9O1xyXG4iLCJpbXBvcnQgeyBCdWZmZXJHZW9tZXRyeSB9IGZyb20gJy4uL2NvcmUvQnVmZmVyR2VvbWV0cnkuanMnO1xyXG5pbXBvcnQgeyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlIH0gZnJvbSAnLi4vY29yZS9CdWZmZXJBdHRyaWJ1dGUuanMnO1xyXG5pbXBvcnQgeyBWZWN0b3IzIH0gZnJvbSAnLi4vbWF0aC9WZWN0b3IzLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yMiB9IGZyb20gJy4uL21hdGgvVmVjdG9yMi5qcyc7XHJcblxyXG5jbGFzcyBDeWxpbmRlckdlb21ldHJ5IGV4dGVuZHMgQnVmZmVyR2VvbWV0cnkge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggcmFkaXVzVG9wID0gMSwgcmFkaXVzQm90dG9tID0gMSwgaGVpZ2h0ID0gMSwgcmFkaWFsU2VnbWVudHMgPSAzMiwgaGVpZ2h0U2VnbWVudHMgPSAxLCBvcGVuRW5kZWQgPSBmYWxzZSwgdGhldGFTdGFydCA9IDAsIHRoZXRhTGVuZ3RoID0gTWF0aC5QSSAqIDIgKSB7XHJcblxyXG5cdFx0c3VwZXIoKTtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSAnQ3lsaW5kZXJHZW9tZXRyeSc7XHJcblxyXG5cdFx0dGhpcy5wYXJhbWV0ZXJzID0ge1xyXG5cdFx0XHRyYWRpdXNUb3A6IHJhZGl1c1RvcCxcclxuXHRcdFx0cmFkaXVzQm90dG9tOiByYWRpdXNCb3R0b20sXHJcblx0XHRcdGhlaWdodDogaGVpZ2h0LFxyXG5cdFx0XHRyYWRpYWxTZWdtZW50czogcmFkaWFsU2VnbWVudHMsXHJcblx0XHRcdGhlaWdodFNlZ21lbnRzOiBoZWlnaHRTZWdtZW50cyxcclxuXHRcdFx0b3BlbkVuZGVkOiBvcGVuRW5kZWQsXHJcblx0XHRcdHRoZXRhU3RhcnQ6IHRoZXRhU3RhcnQsXHJcblx0XHRcdHRoZXRhTGVuZ3RoOiB0aGV0YUxlbmd0aFxyXG5cdFx0fTtcclxuXHJcblx0XHRjb25zdCBzY29wZSA9IHRoaXM7XHJcblxyXG5cdFx0cmFkaWFsU2VnbWVudHMgPSBNYXRoLmZsb29yKCByYWRpYWxTZWdtZW50cyApO1xyXG5cdFx0aGVpZ2h0U2VnbWVudHMgPSBNYXRoLmZsb29yKCBoZWlnaHRTZWdtZW50cyApO1xyXG5cclxuXHRcdC8vIGJ1ZmZlcnNcclxuXHJcblx0XHRjb25zdCBpbmRpY2VzID0gW107XHJcblx0XHRjb25zdCB2ZXJ0aWNlcyA9IFtdO1xyXG5cdFx0Y29uc3Qgbm9ybWFscyA9IFtdO1xyXG5cdFx0Y29uc3QgdXZzID0gW107XHJcblxyXG5cdFx0Ly8gaGVscGVyIHZhcmlhYmxlc1xyXG5cclxuXHRcdGxldCBpbmRleCA9IDA7XHJcblx0XHRjb25zdCBpbmRleEFycmF5ID0gW107XHJcblx0XHRjb25zdCBoYWxmSGVpZ2h0ID0gaGVpZ2h0IC8gMjtcclxuXHRcdGxldCBncm91cFN0YXJ0ID0gMDtcclxuXHJcblx0XHQvLyBnZW5lcmF0ZSBnZW9tZXRyeVxyXG5cclxuXHRcdGdlbmVyYXRlVG9yc28oKTtcclxuXHJcblx0XHRpZiAoIG9wZW5FbmRlZCA9PT0gZmFsc2UgKSB7XHJcblxyXG5cdFx0XHRpZiAoIHJhZGl1c1RvcCA+IDAgKSBnZW5lcmF0ZUNhcCggdHJ1ZSApO1xyXG5cdFx0XHRpZiAoIHJhZGl1c0JvdHRvbSA+IDAgKSBnZW5lcmF0ZUNhcCggZmFsc2UgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gYnVpbGQgZ2VvbWV0cnlcclxuXHJcblx0XHR0aGlzLnNldEluZGV4KCBpbmRpY2VzICk7XHJcblx0XHR0aGlzLnNldEF0dHJpYnV0ZSggJ3Bvc2l0aW9uJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIHZlcnRpY2VzLCAzICkgKTtcclxuXHRcdHRoaXMuc2V0QXR0cmlidXRlKCAnbm9ybWFsJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIG5vcm1hbHMsIDMgKSApO1xyXG5cdFx0dGhpcy5zZXRBdHRyaWJ1dGUoICd1dicsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCB1dnMsIDIgKSApO1xyXG5cclxuXHRcdGZ1bmN0aW9uIGdlbmVyYXRlVG9yc28oKSB7XHJcblxyXG5cdFx0XHRjb25zdCBub3JtYWwgPSBuZXcgVmVjdG9yMygpO1xyXG5cdFx0XHRjb25zdCB2ZXJ0ZXggPSBuZXcgVmVjdG9yMygpO1xyXG5cclxuXHRcdFx0bGV0IGdyb3VwQ291bnQgPSAwO1xyXG5cclxuXHRcdFx0Ly8gdGhpcyB3aWxsIGJlIHVzZWQgdG8gY2FsY3VsYXRlIHRoZSBub3JtYWxcclxuXHRcdFx0Y29uc3Qgc2xvcGUgPSAoIHJhZGl1c0JvdHRvbSAtIHJhZGl1c1RvcCApIC8gaGVpZ2h0O1xyXG5cclxuXHRcdFx0Ly8gZ2VuZXJhdGUgdmVydGljZXMsIG5vcm1hbHMgYW5kIHV2c1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IHkgPSAwOyB5IDw9IGhlaWdodFNlZ21lbnRzOyB5ICsrICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBpbmRleFJvdyA9IFtdO1xyXG5cclxuXHRcdFx0XHRjb25zdCB2ID0geSAvIGhlaWdodFNlZ21lbnRzO1xyXG5cclxuXHRcdFx0XHQvLyBjYWxjdWxhdGUgdGhlIHJhZGl1cyBvZiB0aGUgY3VycmVudCByb3dcclxuXHJcblx0XHRcdFx0Y29uc3QgcmFkaXVzID0gdiAqICggcmFkaXVzQm90dG9tIC0gcmFkaXVzVG9wICkgKyByYWRpdXNUb3A7XHJcblxyXG5cdFx0XHRcdGZvciAoIGxldCB4ID0gMDsgeCA8PSByYWRpYWxTZWdtZW50czsgeCArKyApIHtcclxuXHJcblx0XHRcdFx0XHRjb25zdCB1ID0geCAvIHJhZGlhbFNlZ21lbnRzO1xyXG5cclxuXHRcdFx0XHRcdGNvbnN0IHRoZXRhID0gdSAqIHRoZXRhTGVuZ3RoICsgdGhldGFTdGFydDtcclxuXHJcblx0XHRcdFx0XHRjb25zdCBzaW5UaGV0YSA9IE1hdGguc2luKCB0aGV0YSApO1xyXG5cdFx0XHRcdFx0Y29uc3QgY29zVGhldGEgPSBNYXRoLmNvcyggdGhldGEgKTtcclxuXHJcblx0XHRcdFx0XHQvLyB2ZXJ0ZXhcclxuXHJcblx0XHRcdFx0XHR2ZXJ0ZXgueCA9IHJhZGl1cyAqIHNpblRoZXRhO1xyXG5cdFx0XHRcdFx0dmVydGV4LnkgPSAtIHYgKiBoZWlnaHQgKyBoYWxmSGVpZ2h0O1xyXG5cdFx0XHRcdFx0dmVydGV4LnogPSByYWRpdXMgKiBjb3NUaGV0YTtcclxuXHRcdFx0XHRcdHZlcnRpY2VzLnB1c2goIHZlcnRleC54LCB2ZXJ0ZXgueSwgdmVydGV4LnogKTtcclxuXHJcblx0XHRcdFx0XHQvLyBub3JtYWxcclxuXHJcblx0XHRcdFx0XHRub3JtYWwuc2V0KCBzaW5UaGV0YSwgc2xvcGUsIGNvc1RoZXRhICkubm9ybWFsaXplKCk7XHJcblx0XHRcdFx0XHRub3JtYWxzLnB1c2goIG5vcm1hbC54LCBub3JtYWwueSwgbm9ybWFsLnogKTtcclxuXHJcblx0XHRcdFx0XHQvLyB1dlxyXG5cclxuXHRcdFx0XHRcdHV2cy5wdXNoKCB1LCAxIC0gdiApO1xyXG5cclxuXHRcdFx0XHRcdC8vIHNhdmUgaW5kZXggb2YgdmVydGV4IGluIHJlc3BlY3RpdmUgcm93XHJcblxyXG5cdFx0XHRcdFx0aW5kZXhSb3cucHVzaCggaW5kZXggKysgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHQvLyBub3cgc2F2ZSB2ZXJ0aWNlcyBvZiB0aGUgcm93IGluIG91ciBpbmRleCBhcnJheVxyXG5cclxuXHRcdFx0XHRpbmRleEFycmF5LnB1c2goIGluZGV4Um93ICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyBnZW5lcmF0ZSBpbmRpY2VzXHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgeCA9IDA7IHggPCByYWRpYWxTZWdtZW50czsgeCArKyApIHtcclxuXHJcblx0XHRcdFx0Zm9yICggbGV0IHkgPSAwOyB5IDwgaGVpZ2h0U2VnbWVudHM7IHkgKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0Ly8gd2UgdXNlIHRoZSBpbmRleCBhcnJheSB0byBhY2Nlc3MgdGhlIGNvcnJlY3QgaW5kaWNlc1xyXG5cclxuXHRcdFx0XHRcdGNvbnN0IGEgPSBpbmRleEFycmF5WyB5IF1bIHggXTtcclxuXHRcdFx0XHRcdGNvbnN0IGIgPSBpbmRleEFycmF5WyB5ICsgMSBdWyB4IF07XHJcblx0XHRcdFx0XHRjb25zdCBjID0gaW5kZXhBcnJheVsgeSArIDEgXVsgeCArIDEgXTtcclxuXHRcdFx0XHRcdGNvbnN0IGQgPSBpbmRleEFycmF5WyB5IF1bIHggKyAxIF07XHJcblxyXG5cdFx0XHRcdFx0Ly8gZmFjZXNcclxuXHJcblx0XHRcdFx0XHRpbmRpY2VzLnB1c2goIGEsIGIsIGQgKTtcclxuXHRcdFx0XHRcdGluZGljZXMucHVzaCggYiwgYywgZCApO1xyXG5cclxuXHRcdFx0XHRcdC8vIHVwZGF0ZSBncm91cCBjb3VudGVyXHJcblxyXG5cdFx0XHRcdFx0Z3JvdXBDb3VudCArPSA2O1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyBhZGQgYSBncm91cCB0byB0aGUgZ2VvbWV0cnkuIHRoaXMgd2lsbCBlbnN1cmUgbXVsdGkgbWF0ZXJpYWwgc3VwcG9ydFxyXG5cclxuXHRcdFx0c2NvcGUuYWRkR3JvdXAoIGdyb3VwU3RhcnQsIGdyb3VwQ291bnQsIDAgKTtcclxuXHJcblx0XHRcdC8vIGNhbGN1bGF0ZSBuZXcgc3RhcnQgdmFsdWUgZm9yIGdyb3Vwc1xyXG5cclxuXHRcdFx0Z3JvdXBTdGFydCArPSBncm91cENvdW50O1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRmdW5jdGlvbiBnZW5lcmF0ZUNhcCggdG9wICkge1xyXG5cclxuXHRcdFx0Ly8gc2F2ZSB0aGUgaW5kZXggb2YgdGhlIGZpcnN0IGNlbnRlciB2ZXJ0ZXhcclxuXHRcdFx0Y29uc3QgY2VudGVySW5kZXhTdGFydCA9IGluZGV4O1xyXG5cclxuXHRcdFx0Y29uc3QgdXYgPSBuZXcgVmVjdG9yMigpO1xyXG5cdFx0XHRjb25zdCB2ZXJ0ZXggPSBuZXcgVmVjdG9yMygpO1xyXG5cclxuXHRcdFx0bGV0IGdyb3VwQ291bnQgPSAwO1xyXG5cclxuXHRcdFx0Y29uc3QgcmFkaXVzID0gKCB0b3AgPT09IHRydWUgKSA/IHJhZGl1c1RvcCA6IHJhZGl1c0JvdHRvbTtcclxuXHRcdFx0Y29uc3Qgc2lnbiA9ICggdG9wID09PSB0cnVlICkgPyAxIDogLSAxO1xyXG5cclxuXHRcdFx0Ly8gZmlyc3Qgd2UgZ2VuZXJhdGUgdGhlIGNlbnRlciB2ZXJ0ZXggZGF0YSBvZiB0aGUgY2FwLlxyXG5cdFx0XHQvLyBiZWNhdXNlIHRoZSBnZW9tZXRyeSBuZWVkcyBvbmUgc2V0IG9mIHV2cyBwZXIgZmFjZSxcclxuXHRcdFx0Ly8gd2UgbXVzdCBnZW5lcmF0ZSBhIGNlbnRlciB2ZXJ0ZXggcGVyIGZhY2Uvc2VnbWVudFxyXG5cclxuXHRcdFx0Zm9yICggbGV0IHggPSAxOyB4IDw9IHJhZGlhbFNlZ21lbnRzOyB4ICsrICkge1xyXG5cclxuXHRcdFx0XHQvLyB2ZXJ0ZXhcclxuXHJcblx0XHRcdFx0dmVydGljZXMucHVzaCggMCwgaGFsZkhlaWdodCAqIHNpZ24sIDAgKTtcclxuXHJcblx0XHRcdFx0Ly8gbm9ybWFsXHJcblxyXG5cdFx0XHRcdG5vcm1hbHMucHVzaCggMCwgc2lnbiwgMCApO1xyXG5cclxuXHRcdFx0XHQvLyB1dlxyXG5cclxuXHRcdFx0XHR1dnMucHVzaCggMC41LCAwLjUgKTtcclxuXHJcblx0XHRcdFx0Ly8gaW5jcmVhc2UgaW5kZXhcclxuXHJcblx0XHRcdFx0aW5kZXggKys7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyBzYXZlIHRoZSBpbmRleCBvZiB0aGUgbGFzdCBjZW50ZXIgdmVydGV4XHJcblx0XHRcdGNvbnN0IGNlbnRlckluZGV4RW5kID0gaW5kZXg7XHJcblxyXG5cdFx0XHQvLyBub3cgd2UgZ2VuZXJhdGUgdGhlIHN1cnJvdW5kaW5nIHZlcnRpY2VzLCBub3JtYWxzIGFuZCB1dnNcclxuXHJcblx0XHRcdGZvciAoIGxldCB4ID0gMDsgeCA8PSByYWRpYWxTZWdtZW50czsgeCArKyApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgdSA9IHggLyByYWRpYWxTZWdtZW50cztcclxuXHRcdFx0XHRjb25zdCB0aGV0YSA9IHUgKiB0aGV0YUxlbmd0aCArIHRoZXRhU3RhcnQ7XHJcblxyXG5cdFx0XHRcdGNvbnN0IGNvc1RoZXRhID0gTWF0aC5jb3MoIHRoZXRhICk7XHJcblx0XHRcdFx0Y29uc3Qgc2luVGhldGEgPSBNYXRoLnNpbiggdGhldGEgKTtcclxuXHJcblx0XHRcdFx0Ly8gdmVydGV4XHJcblxyXG5cdFx0XHRcdHZlcnRleC54ID0gcmFkaXVzICogc2luVGhldGE7XHJcblx0XHRcdFx0dmVydGV4LnkgPSBoYWxmSGVpZ2h0ICogc2lnbjtcclxuXHRcdFx0XHR2ZXJ0ZXgueiA9IHJhZGl1cyAqIGNvc1RoZXRhO1xyXG5cdFx0XHRcdHZlcnRpY2VzLnB1c2goIHZlcnRleC54LCB2ZXJ0ZXgueSwgdmVydGV4LnogKTtcclxuXHJcblx0XHRcdFx0Ly8gbm9ybWFsXHJcblxyXG5cdFx0XHRcdG5vcm1hbHMucHVzaCggMCwgc2lnbiwgMCApO1xyXG5cclxuXHRcdFx0XHQvLyB1dlxyXG5cclxuXHRcdFx0XHR1di54ID0gKCBjb3NUaGV0YSAqIDAuNSApICsgMC41O1xyXG5cdFx0XHRcdHV2LnkgPSAoIHNpblRoZXRhICogMC41ICogc2lnbiApICsgMC41O1xyXG5cdFx0XHRcdHV2cy5wdXNoKCB1di54LCB1di55ICk7XHJcblxyXG5cdFx0XHRcdC8vIGluY3JlYXNlIGluZGV4XHJcblxyXG5cdFx0XHRcdGluZGV4ICsrO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Ly8gZ2VuZXJhdGUgaW5kaWNlc1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IHggPSAwOyB4IDwgcmFkaWFsU2VnbWVudHM7IHggKysgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IGMgPSBjZW50ZXJJbmRleFN0YXJ0ICsgeDtcclxuXHRcdFx0XHRjb25zdCBpID0gY2VudGVySW5kZXhFbmQgKyB4O1xyXG5cclxuXHRcdFx0XHRpZiAoIHRvcCA9PT0gdHJ1ZSApIHtcclxuXHJcblx0XHRcdFx0XHQvLyBmYWNlIHRvcFxyXG5cclxuXHRcdFx0XHRcdGluZGljZXMucHVzaCggaSwgaSArIDEsIGMgKTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHQvLyBmYWNlIGJvdHRvbVxyXG5cclxuXHRcdFx0XHRcdGluZGljZXMucHVzaCggaSArIDEsIGksIGMgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRncm91cENvdW50ICs9IDM7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyBhZGQgYSBncm91cCB0byB0aGUgZ2VvbWV0cnkuIHRoaXMgd2lsbCBlbnN1cmUgbXVsdGkgbWF0ZXJpYWwgc3VwcG9ydFxyXG5cclxuXHRcdFx0c2NvcGUuYWRkR3JvdXAoIGdyb3VwU3RhcnQsIGdyb3VwQ291bnQsIHRvcCA9PT0gdHJ1ZSA/IDEgOiAyICk7XHJcblxyXG5cdFx0XHQvLyBjYWxjdWxhdGUgbmV3IHN0YXJ0IHZhbHVlIGZvciBncm91cHNcclxuXHJcblx0XHRcdGdyb3VwU3RhcnQgKz0gZ3JvdXBDb3VudDtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xyXG5cclxuXHRcdHRoaXMucGFyYW1ldGVycyA9IE9iamVjdC5hc3NpZ24oIHt9LCBzb3VyY2UucGFyYW1ldGVycyApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHN0YXRpYyBmcm9tSlNPTiggZGF0YSApIHtcclxuXHJcblx0XHRyZXR1cm4gbmV3IEN5bGluZGVyR2VvbWV0cnkoIGRhdGEucmFkaXVzVG9wLCBkYXRhLnJhZGl1c0JvdHRvbSwgZGF0YS5oZWlnaHQsIGRhdGEucmFkaWFsU2VnbWVudHMsIGRhdGEuaGVpZ2h0U2VnbWVudHMsIGRhdGEub3BlbkVuZGVkLCBkYXRhLnRoZXRhU3RhcnQsIGRhdGEudGhldGFMZW5ndGggKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuXHJcbmV4cG9ydCB7IEN5bGluZGVyR2VvbWV0cnkgfTtcclxuIiwiaW1wb3J0IHsgQ3lsaW5kZXJHZW9tZXRyeSB9IGZyb20gJy4vQ3lsaW5kZXJHZW9tZXRyeS5qcyc7XHJcblxyXG5jbGFzcyBDb25lR2VvbWV0cnkgZXh0ZW5kcyBDeWxpbmRlckdlb21ldHJ5IHtcclxuXHJcblx0Y29uc3RydWN0b3IoIHJhZGl1cyA9IDEsIGhlaWdodCA9IDEsIHJhZGlhbFNlZ21lbnRzID0gMzIsIGhlaWdodFNlZ21lbnRzID0gMSwgb3BlbkVuZGVkID0gZmFsc2UsIHRoZXRhU3RhcnQgPSAwLCB0aGV0YUxlbmd0aCA9IE1hdGguUEkgKiAyICkge1xyXG5cclxuXHRcdHN1cGVyKCAwLCByYWRpdXMsIGhlaWdodCwgcmFkaWFsU2VnbWVudHMsIGhlaWdodFNlZ21lbnRzLCBvcGVuRW5kZWQsIHRoZXRhU3RhcnQsIHRoZXRhTGVuZ3RoICk7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ0NvbmVHZW9tZXRyeSc7XHJcblxyXG5cdFx0dGhpcy5wYXJhbWV0ZXJzID0ge1xyXG5cdFx0XHRyYWRpdXM6IHJhZGl1cyxcclxuXHRcdFx0aGVpZ2h0OiBoZWlnaHQsXHJcblx0XHRcdHJhZGlhbFNlZ21lbnRzOiByYWRpYWxTZWdtZW50cyxcclxuXHRcdFx0aGVpZ2h0U2VnbWVudHM6IGhlaWdodFNlZ21lbnRzLFxyXG5cdFx0XHRvcGVuRW5kZWQ6IG9wZW5FbmRlZCxcclxuXHRcdFx0dGhldGFTdGFydDogdGhldGFTdGFydCxcclxuXHRcdFx0dGhldGFMZW5ndGg6IHRoZXRhTGVuZ3RoXHJcblx0XHR9O1xyXG5cclxuXHR9XHJcblxyXG5cdHN0YXRpYyBmcm9tSlNPTiggZGF0YSApIHtcclxuXHJcblx0XHRyZXR1cm4gbmV3IENvbmVHZW9tZXRyeSggZGF0YS5yYWRpdXMsIGRhdGEuaGVpZ2h0LCBkYXRhLnJhZGlhbFNlZ21lbnRzLCBkYXRhLmhlaWdodFNlZ21lbnRzLCBkYXRhLm9wZW5FbmRlZCwgZGF0YS50aGV0YVN0YXJ0LCBkYXRhLnRoZXRhTGVuZ3RoICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IENvbmVHZW9tZXRyeSB9O1xyXG4iLCJpbXBvcnQgeyBCdWZmZXJHZW9tZXRyeSB9IGZyb20gJy4uL2NvcmUvQnVmZmVyR2VvbWV0cnkuanMnO1xyXG5pbXBvcnQgeyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlIH0gZnJvbSAnLi4vY29yZS9CdWZmZXJBdHRyaWJ1dGUuanMnO1xyXG5pbXBvcnQgeyBWZWN0b3IzIH0gZnJvbSAnLi4vbWF0aC9WZWN0b3IzLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yMiB9IGZyb20gJy4uL21hdGgvVmVjdG9yMi5qcyc7XHJcblxyXG5jbGFzcyBQb2x5aGVkcm9uR2VvbWV0cnkgZXh0ZW5kcyBCdWZmZXJHZW9tZXRyeSB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCB2ZXJ0aWNlcyA9IFtdLCBpbmRpY2VzID0gW10sIHJhZGl1cyA9IDEsIGRldGFpbCA9IDAgKSB7XHJcblxyXG5cdFx0c3VwZXIoKTtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSAnUG9seWhlZHJvbkdlb21ldHJ5JztcclxuXHJcblx0XHR0aGlzLnBhcmFtZXRlcnMgPSB7XHJcblx0XHRcdHZlcnRpY2VzOiB2ZXJ0aWNlcyxcclxuXHRcdFx0aW5kaWNlczogaW5kaWNlcyxcclxuXHRcdFx0cmFkaXVzOiByYWRpdXMsXHJcblx0XHRcdGRldGFpbDogZGV0YWlsXHJcblx0XHR9O1xyXG5cclxuXHRcdC8vIGRlZmF1bHQgYnVmZmVyIGRhdGFcclxuXHJcblx0XHRjb25zdCB2ZXJ0ZXhCdWZmZXIgPSBbXTtcclxuXHRcdGNvbnN0IHV2QnVmZmVyID0gW107XHJcblxyXG5cdFx0Ly8gdGhlIHN1YmRpdmlzaW9uIGNyZWF0ZXMgdGhlIHZlcnRleCBidWZmZXIgZGF0YVxyXG5cclxuXHRcdHN1YmRpdmlkZSggZGV0YWlsICk7XHJcblxyXG5cdFx0Ly8gYWxsIHZlcnRpY2VzIHNob3VsZCBsaWUgb24gYSBjb25jZXB0dWFsIHNwaGVyZSB3aXRoIGEgZ2l2ZW4gcmFkaXVzXHJcblxyXG5cdFx0YXBwbHlSYWRpdXMoIHJhZGl1cyApO1xyXG5cclxuXHRcdC8vIGZpbmFsbHksIGNyZWF0ZSB0aGUgdXYgZGF0YVxyXG5cclxuXHRcdGdlbmVyYXRlVVZzKCk7XHJcblxyXG5cdFx0Ly8gYnVpbGQgbm9uLWluZGV4ZWQgZ2VvbWV0cnlcclxuXHJcblx0XHR0aGlzLnNldEF0dHJpYnV0ZSggJ3Bvc2l0aW9uJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIHZlcnRleEJ1ZmZlciwgMyApICk7XHJcblx0XHR0aGlzLnNldEF0dHJpYnV0ZSggJ25vcm1hbCcsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCB2ZXJ0ZXhCdWZmZXIuc2xpY2UoKSwgMyApICk7XHJcblx0XHR0aGlzLnNldEF0dHJpYnV0ZSggJ3V2JywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIHV2QnVmZmVyLCAyICkgKTtcclxuXHJcblx0XHRpZiAoIGRldGFpbCA9PT0gMCApIHtcclxuXHJcblx0XHRcdHRoaXMuY29tcHV0ZVZlcnRleE5vcm1hbHMoKTsgLy8gZmxhdCBub3JtYWxzXHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdHRoaXMubm9ybWFsaXplTm9ybWFscygpOyAvLyBzbW9vdGggbm9ybWFsc1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvLyBoZWxwZXIgZnVuY3Rpb25zXHJcblxyXG5cdFx0ZnVuY3Rpb24gc3ViZGl2aWRlKCBkZXRhaWwgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBhID0gbmV3IFZlY3RvcjMoKTtcclxuXHRcdFx0Y29uc3QgYiA9IG5ldyBWZWN0b3IzKCk7XHJcblx0XHRcdGNvbnN0IGMgPSBuZXcgVmVjdG9yMygpO1xyXG5cclxuXHRcdFx0Ly8gaXRlcmF0ZSBvdmVyIGFsbCBmYWNlcyBhbmQgYXBwbHkgYSBzdWJkaXZpc2lvbiB3aXRoIHRoZSBnaXZlbiBkZXRhaWwgdmFsdWVcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IGluZGljZXMubGVuZ3RoOyBpICs9IDMgKSB7XHJcblxyXG5cdFx0XHRcdC8vIGdldCB0aGUgdmVydGljZXMgb2YgdGhlIGZhY2VcclxuXHJcblx0XHRcdFx0Z2V0VmVydGV4QnlJbmRleCggaW5kaWNlc1sgaSArIDAgXSwgYSApO1xyXG5cdFx0XHRcdGdldFZlcnRleEJ5SW5kZXgoIGluZGljZXNbIGkgKyAxIF0sIGIgKTtcclxuXHRcdFx0XHRnZXRWZXJ0ZXhCeUluZGV4KCBpbmRpY2VzWyBpICsgMiBdLCBjICk7XHJcblxyXG5cdFx0XHRcdC8vIHBlcmZvcm0gc3ViZGl2aXNpb25cclxuXHJcblx0XHRcdFx0c3ViZGl2aWRlRmFjZSggYSwgYiwgYywgZGV0YWlsICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGZ1bmN0aW9uIHN1YmRpdmlkZUZhY2UoIGEsIGIsIGMsIGRldGFpbCApIHtcclxuXHJcblx0XHRcdGNvbnN0IGNvbHMgPSBkZXRhaWwgKyAxO1xyXG5cclxuXHRcdFx0Ly8gd2UgdXNlIHRoaXMgbXVsdGlkaW1lbnNpb25hbCBhcnJheSBhcyBhIGRhdGEgc3RydWN0dXJlIGZvciBjcmVhdGluZyB0aGUgc3ViZGl2aXNpb25cclxuXHJcblx0XHRcdGNvbnN0IHYgPSBbXTtcclxuXHJcblx0XHRcdC8vIGNvbnN0cnVjdCBhbGwgb2YgdGhlIHZlcnRpY2VzIGZvciB0aGlzIHN1YmRpdmlzaW9uXHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPD0gY29sczsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0dlsgaSBdID0gW107XHJcblxyXG5cdFx0XHRcdGNvbnN0IGFqID0gYS5jbG9uZSgpLmxlcnAoIGMsIGkgLyBjb2xzICk7XHJcblx0XHRcdFx0Y29uc3QgYmogPSBiLmNsb25lKCkubGVycCggYywgaSAvIGNvbHMgKTtcclxuXHJcblx0XHRcdFx0Y29uc3Qgcm93cyA9IGNvbHMgLSBpO1xyXG5cclxuXHRcdFx0XHRmb3IgKCBsZXQgaiA9IDA7IGogPD0gcm93czsgaiArKyApIHtcclxuXHJcblx0XHRcdFx0XHRpZiAoIGogPT09IDAgJiYgaSA9PT0gY29scyApIHtcclxuXHJcblx0XHRcdFx0XHRcdHZbIGkgXVsgaiBdID0gYWo7XHJcblxyXG5cdFx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRcdHZbIGkgXVsgaiBdID0gYWouY2xvbmUoKS5sZXJwKCBiaiwgaiAvIHJvd3MgKTtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdC8vIGNvbnN0cnVjdCBhbGwgb2YgdGhlIGZhY2VzXHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBjb2xzOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRmb3IgKCBsZXQgaiA9IDA7IGogPCAyICogKCBjb2xzIC0gaSApIC0gMTsgaiArKyApIHtcclxuXHJcblx0XHRcdFx0XHRjb25zdCBrID0gTWF0aC5mbG9vciggaiAvIDIgKTtcclxuXHJcblx0XHRcdFx0XHRpZiAoIGogJSAyID09PSAwICkge1xyXG5cclxuXHRcdFx0XHRcdFx0cHVzaFZlcnRleCggdlsgaSBdWyBrICsgMSBdICk7XHJcblx0XHRcdFx0XHRcdHB1c2hWZXJ0ZXgoIHZbIGkgKyAxIF1bIGsgXSApO1xyXG5cdFx0XHRcdFx0XHRwdXNoVmVydGV4KCB2WyBpIF1bIGsgXSApO1xyXG5cclxuXHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHRwdXNoVmVydGV4KCB2WyBpIF1bIGsgKyAxIF0gKTtcclxuXHRcdFx0XHRcdFx0cHVzaFZlcnRleCggdlsgaSArIDEgXVsgayArIDEgXSApO1xyXG5cdFx0XHRcdFx0XHRwdXNoVmVydGV4KCB2WyBpICsgMSBdWyBrIF0gKTtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0ZnVuY3Rpb24gYXBwbHlSYWRpdXMoIHJhZGl1cyApIHtcclxuXHJcblx0XHRcdGNvbnN0IHZlcnRleCA9IG5ldyBWZWN0b3IzKCk7XHJcblxyXG5cdFx0XHQvLyBpdGVyYXRlIG92ZXIgdGhlIGVudGlyZSBidWZmZXIgYW5kIGFwcGx5IHRoZSByYWRpdXMgdG8gZWFjaCB2ZXJ0ZXhcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHZlcnRleEJ1ZmZlci5sZW5ndGg7IGkgKz0gMyApIHtcclxuXHJcblx0XHRcdFx0dmVydGV4LnggPSB2ZXJ0ZXhCdWZmZXJbIGkgKyAwIF07XHJcblx0XHRcdFx0dmVydGV4LnkgPSB2ZXJ0ZXhCdWZmZXJbIGkgKyAxIF07XHJcblx0XHRcdFx0dmVydGV4LnogPSB2ZXJ0ZXhCdWZmZXJbIGkgKyAyIF07XHJcblxyXG5cdFx0XHRcdHZlcnRleC5ub3JtYWxpemUoKS5tdWx0aXBseVNjYWxhciggcmFkaXVzICk7XHJcblxyXG5cdFx0XHRcdHZlcnRleEJ1ZmZlclsgaSArIDAgXSA9IHZlcnRleC54O1xyXG5cdFx0XHRcdHZlcnRleEJ1ZmZlclsgaSArIDEgXSA9IHZlcnRleC55O1xyXG5cdFx0XHRcdHZlcnRleEJ1ZmZlclsgaSArIDIgXSA9IHZlcnRleC56O1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRmdW5jdGlvbiBnZW5lcmF0ZVVWcygpIHtcclxuXHJcblx0XHRcdGNvbnN0IHZlcnRleCA9IG5ldyBWZWN0b3IzKCk7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCB2ZXJ0ZXhCdWZmZXIubGVuZ3RoOyBpICs9IDMgKSB7XHJcblxyXG5cdFx0XHRcdHZlcnRleC54ID0gdmVydGV4QnVmZmVyWyBpICsgMCBdO1xyXG5cdFx0XHRcdHZlcnRleC55ID0gdmVydGV4QnVmZmVyWyBpICsgMSBdO1xyXG5cdFx0XHRcdHZlcnRleC56ID0gdmVydGV4QnVmZmVyWyBpICsgMiBdO1xyXG5cclxuXHRcdFx0XHRjb25zdCB1ID0gYXppbXV0aCggdmVydGV4ICkgLyAyIC8gTWF0aC5QSSArIDAuNTtcclxuXHRcdFx0XHRjb25zdCB2ID0gaW5jbGluYXRpb24oIHZlcnRleCApIC8gTWF0aC5QSSArIDAuNTtcclxuXHRcdFx0XHR1dkJ1ZmZlci5wdXNoKCB1LCAxIC0gdiApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Y29ycmVjdFVWcygpO1xyXG5cclxuXHRcdFx0Y29ycmVjdFNlYW0oKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0ZnVuY3Rpb24gY29ycmVjdFNlYW0oKSB7XHJcblxyXG5cdFx0XHQvLyBoYW5kbGUgY2FzZSB3aGVuIGZhY2Ugc3RyYWRkbGVzIHRoZSBzZWFtLCBzZWUgIzMyNjlcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHV2QnVmZmVyLmxlbmd0aDsgaSArPSA2ICkge1xyXG5cclxuXHRcdFx0XHQvLyB1diBkYXRhIG9mIGEgc2luZ2xlIGZhY2VcclxuXHJcblx0XHRcdFx0Y29uc3QgeDAgPSB1dkJ1ZmZlclsgaSArIDAgXTtcclxuXHRcdFx0XHRjb25zdCB4MSA9IHV2QnVmZmVyWyBpICsgMiBdO1xyXG5cdFx0XHRcdGNvbnN0IHgyID0gdXZCdWZmZXJbIGkgKyA0IF07XHJcblxyXG5cdFx0XHRcdGNvbnN0IG1heCA9IE1hdGgubWF4KCB4MCwgeDEsIHgyICk7XHJcblx0XHRcdFx0Y29uc3QgbWluID0gTWF0aC5taW4oIHgwLCB4MSwgeDIgKTtcclxuXHJcblx0XHRcdFx0Ly8gMC45IGlzIHNvbWV3aGF0IGFyYml0cmFyeVxyXG5cclxuXHRcdFx0XHRpZiAoIG1heCA+IDAuOSAmJiBtaW4gPCAwLjEgKSB7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCB4MCA8IDAuMiApIHV2QnVmZmVyWyBpICsgMCBdICs9IDE7XHJcblx0XHRcdFx0XHRpZiAoIHgxIDwgMC4yICkgdXZCdWZmZXJbIGkgKyAyIF0gKz0gMTtcclxuXHRcdFx0XHRcdGlmICggeDIgPCAwLjIgKSB1dkJ1ZmZlclsgaSArIDQgXSArPSAxO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGZ1bmN0aW9uIHB1c2hWZXJ0ZXgoIHZlcnRleCApIHtcclxuXHJcblx0XHRcdHZlcnRleEJ1ZmZlci5wdXNoKCB2ZXJ0ZXgueCwgdmVydGV4LnksIHZlcnRleC56ICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGZ1bmN0aW9uIGdldFZlcnRleEJ5SW5kZXgoIGluZGV4LCB2ZXJ0ZXggKSB7XHJcblxyXG5cdFx0XHRjb25zdCBzdHJpZGUgPSBpbmRleCAqIDM7XHJcblxyXG5cdFx0XHR2ZXJ0ZXgueCA9IHZlcnRpY2VzWyBzdHJpZGUgKyAwIF07XHJcblx0XHRcdHZlcnRleC55ID0gdmVydGljZXNbIHN0cmlkZSArIDEgXTtcclxuXHRcdFx0dmVydGV4LnogPSB2ZXJ0aWNlc1sgc3RyaWRlICsgMiBdO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRmdW5jdGlvbiBjb3JyZWN0VVZzKCkge1xyXG5cclxuXHRcdFx0Y29uc3QgYSA9IG5ldyBWZWN0b3IzKCk7XHJcblx0XHRcdGNvbnN0IGIgPSBuZXcgVmVjdG9yMygpO1xyXG5cdFx0XHRjb25zdCBjID0gbmV3IFZlY3RvcjMoKTtcclxuXHJcblx0XHRcdGNvbnN0IGNlbnRyb2lkID0gbmV3IFZlY3RvcjMoKTtcclxuXHJcblx0XHRcdGNvbnN0IHV2QSA9IG5ldyBWZWN0b3IyKCk7XHJcblx0XHRcdGNvbnN0IHV2QiA9IG5ldyBWZWN0b3IyKCk7XHJcblx0XHRcdGNvbnN0IHV2QyA9IG5ldyBWZWN0b3IyKCk7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGogPSAwOyBpIDwgdmVydGV4QnVmZmVyLmxlbmd0aDsgaSArPSA5LCBqICs9IDYgKSB7XHJcblxyXG5cdFx0XHRcdGEuc2V0KCB2ZXJ0ZXhCdWZmZXJbIGkgKyAwIF0sIHZlcnRleEJ1ZmZlclsgaSArIDEgXSwgdmVydGV4QnVmZmVyWyBpICsgMiBdICk7XHJcblx0XHRcdFx0Yi5zZXQoIHZlcnRleEJ1ZmZlclsgaSArIDMgXSwgdmVydGV4QnVmZmVyWyBpICsgNCBdLCB2ZXJ0ZXhCdWZmZXJbIGkgKyA1IF0gKTtcclxuXHRcdFx0XHRjLnNldCggdmVydGV4QnVmZmVyWyBpICsgNiBdLCB2ZXJ0ZXhCdWZmZXJbIGkgKyA3IF0sIHZlcnRleEJ1ZmZlclsgaSArIDggXSApO1xyXG5cclxuXHRcdFx0XHR1dkEuc2V0KCB1dkJ1ZmZlclsgaiArIDAgXSwgdXZCdWZmZXJbIGogKyAxIF0gKTtcclxuXHRcdFx0XHR1dkIuc2V0KCB1dkJ1ZmZlclsgaiArIDIgXSwgdXZCdWZmZXJbIGogKyAzIF0gKTtcclxuXHRcdFx0XHR1dkMuc2V0KCB1dkJ1ZmZlclsgaiArIDQgXSwgdXZCdWZmZXJbIGogKyA1IF0gKTtcclxuXHJcblx0XHRcdFx0Y2VudHJvaWQuY29weSggYSApLmFkZCggYiApLmFkZCggYyApLmRpdmlkZVNjYWxhciggMyApO1xyXG5cclxuXHRcdFx0XHRjb25zdCBhemkgPSBhemltdXRoKCBjZW50cm9pZCApO1xyXG5cclxuXHRcdFx0XHRjb3JyZWN0VVYoIHV2QSwgaiArIDAsIGEsIGF6aSApO1xyXG5cdFx0XHRcdGNvcnJlY3RVViggdXZCLCBqICsgMiwgYiwgYXppICk7XHJcblx0XHRcdFx0Y29ycmVjdFVWKCB1dkMsIGogKyA0LCBjLCBhemkgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0ZnVuY3Rpb24gY29ycmVjdFVWKCB1diwgc3RyaWRlLCB2ZWN0b3IsIGF6aW11dGggKSB7XHJcblxyXG5cdFx0XHRpZiAoICggYXppbXV0aCA8IDAgKSAmJiAoIHV2LnggPT09IDEgKSApIHtcclxuXHJcblx0XHRcdFx0dXZCdWZmZXJbIHN0cmlkZSBdID0gdXYueCAtIDE7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRpZiAoICggdmVjdG9yLnggPT09IDAgKSAmJiAoIHZlY3Rvci56ID09PSAwICkgKSB7XHJcblxyXG5cdFx0XHRcdHV2QnVmZmVyWyBzdHJpZGUgXSA9IGF6aW11dGggLyAyIC8gTWF0aC5QSSArIDAuNTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gQW5nbGUgYXJvdW5kIHRoZSBZIGF4aXMsIGNvdW50ZXItY2xvY2t3aXNlIHdoZW4gbG9va2luZyBmcm9tIGFib3ZlLlxyXG5cclxuXHRcdGZ1bmN0aW9uIGF6aW11dGgoIHZlY3RvciApIHtcclxuXHJcblx0XHRcdHJldHVybiBNYXRoLmF0YW4yKCB2ZWN0b3IueiwgLSB2ZWN0b3IueCApO1xyXG5cclxuXHRcdH1cclxuXHJcblxyXG5cdFx0Ly8gQW5nbGUgYWJvdmUgdGhlIFhaIHBsYW5lLlxyXG5cclxuXHRcdGZ1bmN0aW9uIGluY2xpbmF0aW9uKCB2ZWN0b3IgKSB7XHJcblxyXG5cdFx0XHRyZXR1cm4gTWF0aC5hdGFuMiggLSB2ZWN0b3IueSwgTWF0aC5zcXJ0KCAoIHZlY3Rvci54ICogdmVjdG9yLnggKSArICggdmVjdG9yLnogKiB2ZWN0b3IueiApICkgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xyXG5cclxuXHRcdHRoaXMucGFyYW1ldGVycyA9IE9iamVjdC5hc3NpZ24oIHt9LCBzb3VyY2UucGFyYW1ldGVycyApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHN0YXRpYyBmcm9tSlNPTiggZGF0YSApIHtcclxuXHJcblx0XHRyZXR1cm4gbmV3IFBvbHloZWRyb25HZW9tZXRyeSggZGF0YS52ZXJ0aWNlcywgZGF0YS5pbmRpY2VzLCBkYXRhLnJhZGl1cywgZGF0YS5kZXRhaWxzICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IFBvbHloZWRyb25HZW9tZXRyeSB9O1xyXG4iLCJpbXBvcnQgeyBQb2x5aGVkcm9uR2VvbWV0cnkgfSBmcm9tICcuL1BvbHloZWRyb25HZW9tZXRyeS5qcyc7XHJcblxyXG5jbGFzcyBEb2RlY2FoZWRyb25HZW9tZXRyeSBleHRlbmRzIFBvbHloZWRyb25HZW9tZXRyeSB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCByYWRpdXMgPSAxLCBkZXRhaWwgPSAwICkge1xyXG5cclxuXHRcdGNvbnN0IHQgPSAoIDEgKyBNYXRoLnNxcnQoIDUgKSApIC8gMjtcclxuXHRcdGNvbnN0IHIgPSAxIC8gdDtcclxuXHJcblx0XHRjb25zdCB2ZXJ0aWNlcyA9IFtcclxuXHJcblx0XHRcdC8vICjCsTEsIMKxMSwgwrExKVxyXG5cdFx0XHQtIDEsIC0gMSwgLSAxLFx0LSAxLCAtIDEsIDEsXHJcblx0XHRcdC0gMSwgMSwgLSAxLCAtIDEsIDEsIDEsXHJcblx0XHRcdDEsIC0gMSwgLSAxLCAxLCAtIDEsIDEsXHJcblx0XHRcdDEsIDEsIC0gMSwgMSwgMSwgMSxcclxuXHJcblx0XHRcdC8vICgwLCDCsTEvz4YsIMKxz4YpXHJcblx0XHRcdDAsIC0gciwgLSB0LCAwLCAtIHIsIHQsXHJcblx0XHRcdDAsIHIsIC0gdCwgMCwgciwgdCxcclxuXHJcblx0XHRcdC8vICjCsTEvz4YsIMKxz4YsIDApXHJcblx0XHRcdC0gciwgLSB0LCAwLCAtIHIsIHQsIDAsXHJcblx0XHRcdHIsIC0gdCwgMCwgciwgdCwgMCxcclxuXHJcblx0XHRcdC8vICjCsc+GLCAwLCDCsTEvz4YpXHJcblx0XHRcdC0gdCwgMCwgLSByLCB0LCAwLCAtIHIsXHJcblx0XHRcdC0gdCwgMCwgciwgdCwgMCwgclxyXG5cdFx0XTtcclxuXHJcblx0XHRjb25zdCBpbmRpY2VzID0gW1xyXG5cdFx0XHQzLCAxMSwgNywgXHQzLCA3LCAxNSwgXHQzLCAxNSwgMTMsXHJcblx0XHRcdDcsIDE5LCAxNywgXHQ3LCAxNywgNiwgXHQ3LCA2LCAxNSxcclxuXHRcdFx0MTcsIDQsIDgsIFx0MTcsIDgsIDEwLCBcdDE3LCAxMCwgNixcclxuXHRcdFx0OCwgMCwgMTYsIFx0OCwgMTYsIDIsIFx0OCwgMiwgMTAsXHJcblx0XHRcdDAsIDEyLCAxLCBcdDAsIDEsIDE4LCBcdDAsIDE4LCAxNixcclxuXHRcdFx0NiwgMTAsIDIsIFx0NiwgMiwgMTMsIFx0NiwgMTMsIDE1LFxyXG5cdFx0XHQyLCAxNiwgMTgsIFx0MiwgMTgsIDMsIFx0MiwgMywgMTMsXHJcblx0XHRcdDE4LCAxLCA5LCBcdDE4LCA5LCAxMSwgXHQxOCwgMTEsIDMsXHJcblx0XHRcdDQsIDE0LCAxMiwgXHQ0LCAxMiwgMCwgXHQ0LCAwLCA4LFxyXG5cdFx0XHQxMSwgOSwgNSwgXHQxMSwgNSwgMTksIFx0MTEsIDE5LCA3LFxyXG5cdFx0XHQxOSwgNSwgMTQsIFx0MTksIDE0LCA0LCBcdDE5LCA0LCAxNyxcclxuXHRcdFx0MSwgMTIsIDE0LCBcdDEsIDE0LCA1LCBcdDEsIDUsIDlcclxuXHRcdF07XHJcblxyXG5cdFx0c3VwZXIoIHZlcnRpY2VzLCBpbmRpY2VzLCByYWRpdXMsIGRldGFpbCApO1xyXG5cclxuXHRcdHRoaXMudHlwZSA9ICdEb2RlY2FoZWRyb25HZW9tZXRyeSc7XHJcblxyXG5cdFx0dGhpcy5wYXJhbWV0ZXJzID0ge1xyXG5cdFx0XHRyYWRpdXM6IHJhZGl1cyxcclxuXHRcdFx0ZGV0YWlsOiBkZXRhaWxcclxuXHRcdH07XHJcblxyXG5cdH1cclxuXHJcblx0c3RhdGljIGZyb21KU09OKCBkYXRhICkge1xyXG5cclxuXHRcdHJldHVybiBuZXcgRG9kZWNhaGVkcm9uR2VvbWV0cnkoIGRhdGEucmFkaXVzLCBkYXRhLmRldGFpbCApO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5cclxuZXhwb3J0IHsgRG9kZWNhaGVkcm9uR2VvbWV0cnkgfTtcclxuIiwiaW1wb3J0IHsgQnVmZmVyR2VvbWV0cnkgfSBmcm9tICcuLi9jb3JlL0J1ZmZlckdlb21ldHJ5LmpzJztcclxuaW1wb3J0IHsgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSB9IGZyb20gJy4uL2NvcmUvQnVmZmVyQXR0cmlidXRlLmpzJztcclxuaW1wb3J0ICogYXMgTWF0aFV0aWxzIGZyb20gJy4uL21hdGgvTWF0aFV0aWxzLmpzJztcclxuaW1wb3J0IHsgVHJpYW5nbGUgfSBmcm9tICcuLi9tYXRoL1RyaWFuZ2xlLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yMyB9IGZyb20gJy4uL21hdGgvVmVjdG9yMy5qcyc7XHJcblxyXG5jb25zdCBfdjAgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XHJcbmNvbnN0IF92MSA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuY29uc3QgX25vcm1hbCA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuY29uc3QgX3RyaWFuZ2xlID0gLypAX19QVVJFX18qLyBuZXcgVHJpYW5nbGUoKTtcclxuXHJcbmNsYXNzIEVkZ2VzR2VvbWV0cnkgZXh0ZW5kcyBCdWZmZXJHZW9tZXRyeSB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBnZW9tZXRyeSA9IG51bGwsIHRocmVzaG9sZEFuZ2xlID0gMSApIHtcclxuXHJcblx0XHRzdXBlcigpO1xyXG5cclxuXHRcdHRoaXMudHlwZSA9ICdFZGdlc0dlb21ldHJ5JztcclxuXHJcblx0XHR0aGlzLnBhcmFtZXRlcnMgPSB7XHJcblx0XHRcdGdlb21ldHJ5OiBnZW9tZXRyeSxcclxuXHRcdFx0dGhyZXNob2xkQW5nbGU6IHRocmVzaG9sZEFuZ2xlXHJcblx0XHR9O1xyXG5cclxuXHRcdGlmICggZ2VvbWV0cnkgIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBwcmVjaXNpb25Qb2ludHMgPSA0O1xyXG5cdFx0XHRjb25zdCBwcmVjaXNpb24gPSBNYXRoLnBvdyggMTAsIHByZWNpc2lvblBvaW50cyApO1xyXG5cdFx0XHRjb25zdCB0aHJlc2hvbGREb3QgPSBNYXRoLmNvcyggTWF0aFV0aWxzLkRFRzJSQUQgKiB0aHJlc2hvbGRBbmdsZSApO1xyXG5cclxuXHRcdFx0Y29uc3QgaW5kZXhBdHRyID0gZ2VvbWV0cnkuZ2V0SW5kZXgoKTtcclxuXHRcdFx0Y29uc3QgcG9zaXRpb25BdHRyID0gZ2VvbWV0cnkuZ2V0QXR0cmlidXRlKCAncG9zaXRpb24nICk7XHJcblx0XHRcdGNvbnN0IGluZGV4Q291bnQgPSBpbmRleEF0dHIgPyBpbmRleEF0dHIuY291bnQgOiBwb3NpdGlvbkF0dHIuY291bnQ7XHJcblxyXG5cdFx0XHRjb25zdCBpbmRleEFyciA9IFsgMCwgMCwgMCBdO1xyXG5cdFx0XHRjb25zdCB2ZXJ0S2V5cyA9IFsgJ2EnLCAnYicsICdjJyBdO1xyXG5cdFx0XHRjb25zdCBoYXNoZXMgPSBuZXcgQXJyYXkoIDMgKTtcclxuXHJcblx0XHRcdGNvbnN0IGVkZ2VEYXRhID0ge307XHJcblx0XHRcdGNvbnN0IHZlcnRpY2VzID0gW107XHJcblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IGluZGV4Q291bnQ7IGkgKz0gMyApIHtcclxuXHJcblx0XHRcdFx0aWYgKCBpbmRleEF0dHIgKSB7XHJcblxyXG5cdFx0XHRcdFx0aW5kZXhBcnJbIDAgXSA9IGluZGV4QXR0ci5nZXRYKCBpICk7XHJcblx0XHRcdFx0XHRpbmRleEFyclsgMSBdID0gaW5kZXhBdHRyLmdldFgoIGkgKyAxICk7XHJcblx0XHRcdFx0XHRpbmRleEFyclsgMiBdID0gaW5kZXhBdHRyLmdldFgoIGkgKyAyICk7XHJcblxyXG5cdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0aW5kZXhBcnJbIDAgXSA9IGk7XHJcblx0XHRcdFx0XHRpbmRleEFyclsgMSBdID0gaSArIDE7XHJcblx0XHRcdFx0XHRpbmRleEFyclsgMiBdID0gaSArIDI7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0Y29uc3QgeyBhLCBiLCBjIH0gPSBfdHJpYW5nbGU7XHJcblx0XHRcdFx0YS5mcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbkF0dHIsIGluZGV4QXJyWyAwIF0gKTtcclxuXHRcdFx0XHRiLmZyb21CdWZmZXJBdHRyaWJ1dGUoIHBvc2l0aW9uQXR0ciwgaW5kZXhBcnJbIDEgXSApO1xyXG5cdFx0XHRcdGMuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggcG9zaXRpb25BdHRyLCBpbmRleEFyclsgMiBdICk7XHJcblx0XHRcdFx0X3RyaWFuZ2xlLmdldE5vcm1hbCggX25vcm1hbCApO1xyXG5cclxuXHRcdFx0XHQvLyBjcmVhdGUgaGFzaGVzIGZvciB0aGUgZWRnZSBmcm9tIHRoZSB2ZXJ0aWNlc1xyXG5cdFx0XHRcdGhhc2hlc1sgMCBdID0gYCR7IE1hdGgucm91bmQoIGEueCAqIHByZWNpc2lvbiApIH0sJHsgTWF0aC5yb3VuZCggYS55ICogcHJlY2lzaW9uICkgfSwkeyBNYXRoLnJvdW5kKCBhLnogKiBwcmVjaXNpb24gKSB9YDtcclxuXHRcdFx0XHRoYXNoZXNbIDEgXSA9IGAkeyBNYXRoLnJvdW5kKCBiLnggKiBwcmVjaXNpb24gKSB9LCR7IE1hdGgucm91bmQoIGIueSAqIHByZWNpc2lvbiApIH0sJHsgTWF0aC5yb3VuZCggYi56ICogcHJlY2lzaW9uICkgfWA7XHJcblx0XHRcdFx0aGFzaGVzWyAyIF0gPSBgJHsgTWF0aC5yb3VuZCggYy54ICogcHJlY2lzaW9uICkgfSwkeyBNYXRoLnJvdW5kKCBjLnkgKiBwcmVjaXNpb24gKSB9LCR7IE1hdGgucm91bmQoIGMueiAqIHByZWNpc2lvbiApIH1gO1xyXG5cclxuXHRcdFx0XHQvLyBza2lwIGRlZ2VuZXJhdGUgdHJpYW5nbGVzXHJcblx0XHRcdFx0aWYgKCBoYXNoZXNbIDAgXSA9PT0gaGFzaGVzWyAxIF0gfHwgaGFzaGVzWyAxIF0gPT09IGhhc2hlc1sgMiBdIHx8IGhhc2hlc1sgMiBdID09PSBoYXNoZXNbIDAgXSApIHtcclxuXHJcblx0XHRcdFx0XHRjb250aW51ZTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHQvLyBpdGVyYXRlIG92ZXIgZXZlcnkgZWRnZVxyXG5cdFx0XHRcdGZvciAoIGxldCBqID0gMDsgaiA8IDM7IGogKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0Ly8gZ2V0IHRoZSBmaXJzdCBhbmQgbmV4dCB2ZXJ0ZXggbWFraW5nIHVwIHRoZSBlZGdlXHJcblx0XHRcdFx0XHRjb25zdCBqTmV4dCA9ICggaiArIDEgKSAlIDM7XHJcblx0XHRcdFx0XHRjb25zdCB2ZWNIYXNoMCA9IGhhc2hlc1sgaiBdO1xyXG5cdFx0XHRcdFx0Y29uc3QgdmVjSGFzaDEgPSBoYXNoZXNbIGpOZXh0IF07XHJcblx0XHRcdFx0XHRjb25zdCB2MCA9IF90cmlhbmdsZVsgdmVydEtleXNbIGogXSBdO1xyXG5cdFx0XHRcdFx0Y29uc3QgdjEgPSBfdHJpYW5nbGVbIHZlcnRLZXlzWyBqTmV4dCBdIF07XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgaGFzaCA9IGAkeyB2ZWNIYXNoMCB9XyR7IHZlY0hhc2gxIH1gO1xyXG5cdFx0XHRcdFx0Y29uc3QgcmV2ZXJzZUhhc2ggPSBgJHsgdmVjSGFzaDEgfV8keyB2ZWNIYXNoMCB9YDtcclxuXHJcblx0XHRcdFx0XHRpZiAoIHJldmVyc2VIYXNoIGluIGVkZ2VEYXRhICYmIGVkZ2VEYXRhWyByZXZlcnNlSGFzaCBdICkge1xyXG5cclxuXHRcdFx0XHRcdFx0Ly8gaWYgd2UgZm91bmQgYSBzaWJsaW5nIGVkZ2UgYWRkIGl0IGludG8gdGhlIHZlcnRleCBhcnJheSBpZlxyXG5cdFx0XHRcdFx0XHQvLyBpdCBtZWV0cyB0aGUgYW5nbGUgdGhyZXNob2xkIGFuZCBkZWxldGUgdGhlIGVkZ2UgZnJvbSB0aGUgbWFwLlxyXG5cdFx0XHRcdFx0XHRpZiAoIF9ub3JtYWwuZG90KCBlZGdlRGF0YVsgcmV2ZXJzZUhhc2ggXS5ub3JtYWwgKSA8PSB0aHJlc2hvbGREb3QgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdHZlcnRpY2VzLnB1c2goIHYwLngsIHYwLnksIHYwLnogKTtcclxuXHRcdFx0XHRcdFx0XHR2ZXJ0aWNlcy5wdXNoKCB2MS54LCB2MS55LCB2MS56ICk7XHJcblxyXG5cdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0XHRlZGdlRGF0YVsgcmV2ZXJzZUhhc2ggXSA9IG51bGw7XHJcblxyXG5cdFx0XHRcdFx0fSBlbHNlIGlmICggISAoIGhhc2ggaW4gZWRnZURhdGEgKSApIHtcclxuXHJcblx0XHRcdFx0XHRcdC8vIGlmIHdlJ3ZlIGFscmVhZHkgZ290IGFuIGVkZ2UgaGVyZSB0aGVuIHNraXAgYWRkaW5nIGEgbmV3IG9uZVxyXG5cdFx0XHRcdFx0XHRlZGdlRGF0YVsgaGFzaCBdID0ge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRpbmRleDA6IGluZGV4QXJyWyBqIF0sXHJcblx0XHRcdFx0XHRcdFx0aW5kZXgxOiBpbmRleEFyclsgak5leHQgXSxcclxuXHRcdFx0XHRcdFx0XHRub3JtYWw6IF9ub3JtYWwuY2xvbmUoKSxcclxuXHJcblx0XHRcdFx0XHRcdH07XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyBpdGVyYXRlIG92ZXIgYWxsIHJlbWFpbmluZywgdW5tYXRjaGVkIGVkZ2VzIGFuZCBhZGQgdGhlbSB0byB0aGUgdmVydGV4IGFycmF5XHJcblx0XHRcdGZvciAoIGNvbnN0IGtleSBpbiBlZGdlRGF0YSApIHtcclxuXHJcblx0XHRcdFx0aWYgKCBlZGdlRGF0YVsga2V5IF0gKSB7XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgeyBpbmRleDAsIGluZGV4MSB9ID0gZWRnZURhdGFbIGtleSBdO1xyXG5cdFx0XHRcdFx0X3YwLmZyb21CdWZmZXJBdHRyaWJ1dGUoIHBvc2l0aW9uQXR0ciwgaW5kZXgwICk7XHJcblx0XHRcdFx0XHRfdjEuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggcG9zaXRpb25BdHRyLCBpbmRleDEgKTtcclxuXHJcblx0XHRcdFx0XHR2ZXJ0aWNlcy5wdXNoKCBfdjAueCwgX3YwLnksIF92MC56ICk7XHJcblx0XHRcdFx0XHR2ZXJ0aWNlcy5wdXNoKCBfdjEueCwgX3YxLnksIF92MS56ICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHRoaXMuc2V0QXR0cmlidXRlKCAncG9zaXRpb24nLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggdmVydGljZXMsIDMgKSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRjb3B5KCBzb3VyY2UgKSB7XHJcblxyXG5cdFx0c3VwZXIuY29weSggc291cmNlICk7XHJcblxyXG5cdFx0dGhpcy5wYXJhbWV0ZXJzID0gT2JqZWN0LmFzc2lnbigge30sIHNvdXJjZS5wYXJhbWV0ZXJzICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IEVkZ2VzR2VvbWV0cnkgfTtcclxuIiwiaW1wb3J0IHsgUGF0aCB9IGZyb20gJy4vUGF0aC5qcyc7XHJcbmltcG9ydCAqIGFzIE1hdGhVdGlscyBmcm9tICcuLi8uLi9tYXRoL01hdGhVdGlscy5qcyc7XHJcblxyXG5jbGFzcyBTaGFwZSBleHRlbmRzIFBhdGgge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggcG9pbnRzICkge1xyXG5cclxuXHRcdHN1cGVyKCBwb2ludHMgKTtcclxuXHJcblx0XHR0aGlzLnV1aWQgPSBNYXRoVXRpbHMuZ2VuZXJhdGVVVUlEKCk7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ1NoYXBlJztcclxuXHJcblx0XHR0aGlzLmhvbGVzID0gW107XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0UG9pbnRzSG9sZXMoIGRpdmlzaW9ucyApIHtcclxuXHJcblx0XHRjb25zdCBob2xlc1B0cyA9IFtdO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IHRoaXMuaG9sZXMubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdGhvbGVzUHRzWyBpIF0gPSB0aGlzLmhvbGVzWyBpIF0uZ2V0UG9pbnRzKCBkaXZpc2lvbnMgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIGhvbGVzUHRzO1xyXG5cclxuXHR9XHJcblxyXG5cdC8vIGdldCBwb2ludHMgb2Ygc2hhcGUgYW5kIGhvbGVzIChrZXlwb2ludHMgYmFzZWQgb24gc2VnbWVudHMgcGFyYW1ldGVyKVxyXG5cclxuXHRleHRyYWN0UG9pbnRzKCBkaXZpc2lvbnMgKSB7XHJcblxyXG5cdFx0cmV0dXJuIHtcclxuXHJcblx0XHRcdHNoYXBlOiB0aGlzLmdldFBvaW50cyggZGl2aXNpb25zICksXHJcblx0XHRcdGhvbGVzOiB0aGlzLmdldFBvaW50c0hvbGVzKCBkaXZpc2lvbnMgKVxyXG5cclxuXHRcdH07XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xyXG5cclxuXHRcdHRoaXMuaG9sZXMgPSBbXTtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBzb3VyY2UuaG9sZXMubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdGNvbnN0IGhvbGUgPSBzb3VyY2UuaG9sZXNbIGkgXTtcclxuXHJcblx0XHRcdHRoaXMuaG9sZXMucHVzaCggaG9sZS5jbG9uZSgpICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHRvSlNPTigpIHtcclxuXHJcblx0XHRjb25zdCBkYXRhID0gc3VwZXIudG9KU09OKCk7XHJcblxyXG5cdFx0ZGF0YS51dWlkID0gdGhpcy51dWlkO1xyXG5cdFx0ZGF0YS5ob2xlcyA9IFtdO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IHRoaXMuaG9sZXMubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdGNvbnN0IGhvbGUgPSB0aGlzLmhvbGVzWyBpIF07XHJcblx0XHRcdGRhdGEuaG9sZXMucHVzaCggaG9sZS50b0pTT04oKSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gZGF0YTtcclxuXHJcblx0fVxyXG5cclxuXHRmcm9tSlNPTigganNvbiApIHtcclxuXHJcblx0XHRzdXBlci5mcm9tSlNPTigganNvbiApO1xyXG5cclxuXHRcdHRoaXMudXVpZCA9IGpzb24udXVpZDtcclxuXHRcdHRoaXMuaG9sZXMgPSBbXTtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBqc29uLmhvbGVzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBob2xlID0ganNvbi5ob2xlc1sgaSBdO1xyXG5cdFx0XHR0aGlzLmhvbGVzLnB1c2goIG5ldyBQYXRoKCkuZnJvbUpTT04oIGhvbGUgKSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuXHJcbmV4cG9ydCB7IFNoYXBlIH07XHJcbiIsIi8qKlxyXG4gKiBQb3J0IGZyb20gaHR0cHM6Ly9naXRodWIuY29tL21hcGJveC9lYXJjdXQgKHYyLjIuNClcclxuICovXHJcblxyXG5jb25zdCBFYXJjdXQgPSB7XHJcblxyXG5cdHRyaWFuZ3VsYXRlOiBmdW5jdGlvbiAoIGRhdGEsIGhvbGVJbmRpY2VzLCBkaW0gPSAyICkge1xyXG5cclxuXHRcdGNvbnN0IGhhc0hvbGVzID0gaG9sZUluZGljZXMgJiYgaG9sZUluZGljZXMubGVuZ3RoO1xyXG5cdFx0Y29uc3Qgb3V0ZXJMZW4gPSBoYXNIb2xlcyA/IGhvbGVJbmRpY2VzWyAwIF0gKiBkaW0gOiBkYXRhLmxlbmd0aDtcclxuXHRcdGxldCBvdXRlck5vZGUgPSBsaW5rZWRMaXN0KCBkYXRhLCAwLCBvdXRlckxlbiwgZGltLCB0cnVlICk7XHJcblx0XHRjb25zdCB0cmlhbmdsZXMgPSBbXTtcclxuXHJcblx0XHRpZiAoICEgb3V0ZXJOb2RlIHx8IG91dGVyTm9kZS5uZXh0ID09PSBvdXRlck5vZGUucHJldiApIHJldHVybiB0cmlhbmdsZXM7XHJcblxyXG5cdFx0bGV0IG1pblgsIG1pblksIG1heFgsIG1heFksIHgsIHksIGludlNpemU7XHJcblxyXG5cdFx0aWYgKCBoYXNIb2xlcyApIG91dGVyTm9kZSA9IGVsaW1pbmF0ZUhvbGVzKCBkYXRhLCBob2xlSW5kaWNlcywgb3V0ZXJOb2RlLCBkaW0gKTtcclxuXHJcblx0XHQvLyBpZiB0aGUgc2hhcGUgaXMgbm90IHRvbyBzaW1wbGUsIHdlJ2xsIHVzZSB6LW9yZGVyIGN1cnZlIGhhc2ggbGF0ZXI7IGNhbGN1bGF0ZSBwb2x5Z29uIGJib3hcclxuXHRcdGlmICggZGF0YS5sZW5ndGggPiA4MCAqIGRpbSApIHtcclxuXHJcblx0XHRcdG1pblggPSBtYXhYID0gZGF0YVsgMCBdO1xyXG5cdFx0XHRtaW5ZID0gbWF4WSA9IGRhdGFbIDEgXTtcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gZGltOyBpIDwgb3V0ZXJMZW47IGkgKz0gZGltICkge1xyXG5cclxuXHRcdFx0XHR4ID0gZGF0YVsgaSBdO1xyXG5cdFx0XHRcdHkgPSBkYXRhWyBpICsgMSBdO1xyXG5cdFx0XHRcdGlmICggeCA8IG1pblggKSBtaW5YID0geDtcclxuXHRcdFx0XHRpZiAoIHkgPCBtaW5ZICkgbWluWSA9IHk7XHJcblx0XHRcdFx0aWYgKCB4ID4gbWF4WCApIG1heFggPSB4O1xyXG5cdFx0XHRcdGlmICggeSA+IG1heFkgKSBtYXhZID0geTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdC8vIG1pblgsIG1pblkgYW5kIGludlNpemUgYXJlIGxhdGVyIHVzZWQgdG8gdHJhbnNmb3JtIGNvb3JkcyBpbnRvIGludGVnZXJzIGZvciB6LW9yZGVyIGNhbGN1bGF0aW9uXHJcblx0XHRcdGludlNpemUgPSBNYXRoLm1heCggbWF4WCAtIG1pblgsIG1heFkgLSBtaW5ZICk7XHJcblx0XHRcdGludlNpemUgPSBpbnZTaXplICE9PSAwID8gMzI3NjcgLyBpbnZTaXplIDogMDtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0ZWFyY3V0TGlua2VkKCBvdXRlck5vZGUsIHRyaWFuZ2xlcywgZGltLCBtaW5YLCBtaW5ZLCBpbnZTaXplLCAwICk7XHJcblxyXG5cdFx0cmV0dXJuIHRyaWFuZ2xlcztcclxuXHJcblx0fVxyXG5cclxufTtcclxuXHJcbi8vIGNyZWF0ZSBhIGNpcmN1bGFyIGRvdWJseSBsaW5rZWQgbGlzdCBmcm9tIHBvbHlnb24gcG9pbnRzIGluIHRoZSBzcGVjaWZpZWQgd2luZGluZyBvcmRlclxyXG5mdW5jdGlvbiBsaW5rZWRMaXN0KCBkYXRhLCBzdGFydCwgZW5kLCBkaW0sIGNsb2Nrd2lzZSApIHtcclxuXHJcblx0bGV0IGksIGxhc3Q7XHJcblxyXG5cdGlmICggY2xvY2t3aXNlID09PSAoIHNpZ25lZEFyZWEoIGRhdGEsIHN0YXJ0LCBlbmQsIGRpbSApID4gMCApICkge1xyXG5cclxuXHRcdGZvciAoIGkgPSBzdGFydDsgaSA8IGVuZDsgaSArPSBkaW0gKSBsYXN0ID0gaW5zZXJ0Tm9kZSggaSwgZGF0YVsgaSBdLCBkYXRhWyBpICsgMSBdLCBsYXN0ICk7XHJcblxyXG5cdH0gZWxzZSB7XHJcblxyXG5cdFx0Zm9yICggaSA9IGVuZCAtIGRpbTsgaSA+PSBzdGFydDsgaSAtPSBkaW0gKSBsYXN0ID0gaW5zZXJ0Tm9kZSggaSwgZGF0YVsgaSBdLCBkYXRhWyBpICsgMSBdLCBsYXN0ICk7XHJcblxyXG5cdH1cclxuXHJcblx0aWYgKCBsYXN0ICYmIGVxdWFscyggbGFzdCwgbGFzdC5uZXh0ICkgKSB7XHJcblxyXG5cdFx0cmVtb3ZlTm9kZSggbGFzdCApO1xyXG5cdFx0bGFzdCA9IGxhc3QubmV4dDtcclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4gbGFzdDtcclxuXHJcbn1cclxuXHJcbi8vIGVsaW1pbmF0ZSBjb2xpbmVhciBvciBkdXBsaWNhdGUgcG9pbnRzXHJcbmZ1bmN0aW9uIGZpbHRlclBvaW50cyggc3RhcnQsIGVuZCApIHtcclxuXHJcblx0aWYgKCAhIHN0YXJ0ICkgcmV0dXJuIHN0YXJ0O1xyXG5cdGlmICggISBlbmQgKSBlbmQgPSBzdGFydDtcclxuXHJcblx0bGV0IHAgPSBzdGFydCxcclxuXHRcdGFnYWluO1xyXG5cdGRvIHtcclxuXHJcblx0XHRhZ2FpbiA9IGZhbHNlO1xyXG5cclxuXHRcdGlmICggISBwLnN0ZWluZXIgJiYgKCBlcXVhbHMoIHAsIHAubmV4dCApIHx8IGFyZWEoIHAucHJldiwgcCwgcC5uZXh0ICkgPT09IDAgKSApIHtcclxuXHJcblx0XHRcdHJlbW92ZU5vZGUoIHAgKTtcclxuXHRcdFx0cCA9IGVuZCA9IHAucHJldjtcclxuXHRcdFx0aWYgKCBwID09PSBwLm5leHQgKSBicmVhaztcclxuXHRcdFx0YWdhaW4gPSB0cnVlO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRwID0gcC5uZXh0O1xyXG5cclxuXHRcdH1cclxuXHJcblx0fSB3aGlsZSAoIGFnYWluIHx8IHAgIT09IGVuZCApO1xyXG5cclxuXHRyZXR1cm4gZW5kO1xyXG5cclxufVxyXG5cclxuLy8gbWFpbiBlYXIgc2xpY2luZyBsb29wIHdoaWNoIHRyaWFuZ3VsYXRlcyBhIHBvbHlnb24gKGdpdmVuIGFzIGEgbGlua2VkIGxpc3QpXHJcbmZ1bmN0aW9uIGVhcmN1dExpbmtlZCggZWFyLCB0cmlhbmdsZXMsIGRpbSwgbWluWCwgbWluWSwgaW52U2l6ZSwgcGFzcyApIHtcclxuXHJcblx0aWYgKCAhIGVhciApIHJldHVybjtcclxuXHJcblx0Ly8gaW50ZXJsaW5rIHBvbHlnb24gbm9kZXMgaW4gei1vcmRlclxyXG5cdGlmICggISBwYXNzICYmIGludlNpemUgKSBpbmRleEN1cnZlKCBlYXIsIG1pblgsIG1pblksIGludlNpemUgKTtcclxuXHJcblx0bGV0IHN0b3AgPSBlYXIsXHJcblx0XHRwcmV2LCBuZXh0O1xyXG5cclxuXHQvLyBpdGVyYXRlIHRocm91Z2ggZWFycywgc2xpY2luZyB0aGVtIG9uZSBieSBvbmVcclxuXHR3aGlsZSAoIGVhci5wcmV2ICE9PSBlYXIubmV4dCApIHtcclxuXHJcblx0XHRwcmV2ID0gZWFyLnByZXY7XHJcblx0XHRuZXh0ID0gZWFyLm5leHQ7XHJcblxyXG5cdFx0aWYgKCBpbnZTaXplID8gaXNFYXJIYXNoZWQoIGVhciwgbWluWCwgbWluWSwgaW52U2l6ZSApIDogaXNFYXIoIGVhciApICkge1xyXG5cclxuXHRcdFx0Ly8gY3V0IG9mZiB0aGUgdHJpYW5nbGVcclxuXHRcdFx0dHJpYW5nbGVzLnB1c2goIHByZXYuaSAvIGRpbSB8IDAgKTtcclxuXHRcdFx0dHJpYW5nbGVzLnB1c2goIGVhci5pIC8gZGltIHwgMCApO1xyXG5cdFx0XHR0cmlhbmdsZXMucHVzaCggbmV4dC5pIC8gZGltIHwgMCApO1xyXG5cclxuXHRcdFx0cmVtb3ZlTm9kZSggZWFyICk7XHJcblxyXG5cdFx0XHQvLyBza2lwcGluZyB0aGUgbmV4dCB2ZXJ0ZXggbGVhZHMgdG8gbGVzcyBzbGl2ZXIgdHJpYW5nbGVzXHJcblx0XHRcdGVhciA9IG5leHQubmV4dDtcclxuXHRcdFx0c3RvcCA9IG5leHQubmV4dDtcclxuXHJcblx0XHRcdGNvbnRpbnVlO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRlYXIgPSBuZXh0O1xyXG5cclxuXHRcdC8vIGlmIHdlIGxvb3BlZCB0aHJvdWdoIHRoZSB3aG9sZSByZW1haW5pbmcgcG9seWdvbiBhbmQgY2FuJ3QgZmluZCBhbnkgbW9yZSBlYXJzXHJcblx0XHRpZiAoIGVhciA9PT0gc3RvcCApIHtcclxuXHJcblx0XHRcdC8vIHRyeSBmaWx0ZXJpbmcgcG9pbnRzIGFuZCBzbGljaW5nIGFnYWluXHJcblx0XHRcdGlmICggISBwYXNzICkge1xyXG5cclxuXHRcdFx0XHRlYXJjdXRMaW5rZWQoIGZpbHRlclBvaW50cyggZWFyICksIHRyaWFuZ2xlcywgZGltLCBtaW5YLCBtaW5ZLCBpbnZTaXplLCAxICk7XHJcblxyXG5cdFx0XHRcdC8vIGlmIHRoaXMgZGlkbid0IHdvcmssIHRyeSBjdXJpbmcgYWxsIHNtYWxsIHNlbGYtaW50ZXJzZWN0aW9ucyBsb2NhbGx5XHJcblxyXG5cdFx0XHR9IGVsc2UgaWYgKCBwYXNzID09PSAxICkge1xyXG5cclxuXHRcdFx0XHRlYXIgPSBjdXJlTG9jYWxJbnRlcnNlY3Rpb25zKCBmaWx0ZXJQb2ludHMoIGVhciApLCB0cmlhbmdsZXMsIGRpbSApO1xyXG5cdFx0XHRcdGVhcmN1dExpbmtlZCggZWFyLCB0cmlhbmdsZXMsIGRpbSwgbWluWCwgbWluWSwgaW52U2l6ZSwgMiApO1xyXG5cclxuXHRcdFx0XHQvLyBhcyBhIGxhc3QgcmVzb3J0LCB0cnkgc3BsaXR0aW5nIHRoZSByZW1haW5pbmcgcG9seWdvbiBpbnRvIHR3b1xyXG5cclxuXHRcdFx0fSBlbHNlIGlmICggcGFzcyA9PT0gMiApIHtcclxuXHJcblx0XHRcdFx0c3BsaXRFYXJjdXQoIGVhciwgdHJpYW5nbGVzLCBkaW0sIG1pblgsIG1pblksIGludlNpemUgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuLy8gY2hlY2sgd2hldGhlciBhIHBvbHlnb24gbm9kZSBmb3JtcyBhIHZhbGlkIGVhciB3aXRoIGFkamFjZW50IG5vZGVzXHJcbmZ1bmN0aW9uIGlzRWFyKCBlYXIgKSB7XHJcblxyXG5cdGNvbnN0IGEgPSBlYXIucHJldixcclxuXHRcdGIgPSBlYXIsXHJcblx0XHRjID0gZWFyLm5leHQ7XHJcblxyXG5cdGlmICggYXJlYSggYSwgYiwgYyApID49IDAgKSByZXR1cm4gZmFsc2U7IC8vIHJlZmxleCwgY2FuJ3QgYmUgYW4gZWFyXHJcblxyXG5cdC8vIG5vdyBtYWtlIHN1cmUgd2UgZG9uJ3QgaGF2ZSBvdGhlciBwb2ludHMgaW5zaWRlIHRoZSBwb3RlbnRpYWwgZWFyXHJcblx0Y29uc3QgYXggPSBhLngsIGJ4ID0gYi54LCBjeCA9IGMueCwgYXkgPSBhLnksIGJ5ID0gYi55LCBjeSA9IGMueTtcclxuXHJcblx0Ly8gdHJpYW5nbGUgYmJveDsgbWluICYgbWF4IGFyZSBjYWxjdWxhdGVkIGxpa2UgdGhpcyBmb3Igc3BlZWRcclxuXHRjb25zdCB4MCA9IGF4IDwgYnggPyAoIGF4IDwgY3ggPyBheCA6IGN4ICkgOiAoIGJ4IDwgY3ggPyBieCA6IGN4ICksXHJcblx0XHR5MCA9IGF5IDwgYnkgPyAoIGF5IDwgY3kgPyBheSA6IGN5ICkgOiAoIGJ5IDwgY3kgPyBieSA6IGN5ICksXHJcblx0XHR4MSA9IGF4ID4gYnggPyAoIGF4ID4gY3ggPyBheCA6IGN4ICkgOiAoIGJ4ID4gY3ggPyBieCA6IGN4ICksXHJcblx0XHR5MSA9IGF5ID4gYnkgPyAoIGF5ID4gY3kgPyBheSA6IGN5ICkgOiAoIGJ5ID4gY3kgPyBieSA6IGN5ICk7XHJcblxyXG5cdGxldCBwID0gYy5uZXh0O1xyXG5cdHdoaWxlICggcCAhPT0gYSApIHtcclxuXHJcblx0XHRpZiAoIHAueCA+PSB4MCAmJiBwLnggPD0geDEgJiYgcC55ID49IHkwICYmIHAueSA8PSB5MSAmJlxyXG5cdFx0XHRwb2ludEluVHJpYW5nbGUoIGF4LCBheSwgYngsIGJ5LCBjeCwgY3ksIHAueCwgcC55ICkgJiZcclxuXHRcdFx0YXJlYSggcC5wcmV2LCBwLCBwLm5leHQgKSA+PSAwICkgcmV0dXJuIGZhbHNlO1xyXG5cdFx0cCA9IHAubmV4dDtcclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4gdHJ1ZTtcclxuXHJcbn1cclxuXHJcbmZ1bmN0aW9uIGlzRWFySGFzaGVkKCBlYXIsIG1pblgsIG1pblksIGludlNpemUgKSB7XHJcblxyXG5cdGNvbnN0IGEgPSBlYXIucHJldixcclxuXHRcdGIgPSBlYXIsXHJcblx0XHRjID0gZWFyLm5leHQ7XHJcblxyXG5cdGlmICggYXJlYSggYSwgYiwgYyApID49IDAgKSByZXR1cm4gZmFsc2U7IC8vIHJlZmxleCwgY2FuJ3QgYmUgYW4gZWFyXHJcblxyXG5cdGNvbnN0IGF4ID0gYS54LCBieCA9IGIueCwgY3ggPSBjLngsIGF5ID0gYS55LCBieSA9IGIueSwgY3kgPSBjLnk7XHJcblxyXG5cdC8vIHRyaWFuZ2xlIGJib3g7IG1pbiAmIG1heCBhcmUgY2FsY3VsYXRlZCBsaWtlIHRoaXMgZm9yIHNwZWVkXHJcblx0Y29uc3QgeDAgPSBheCA8IGJ4ID8gKCBheCA8IGN4ID8gYXggOiBjeCApIDogKCBieCA8IGN4ID8gYnggOiBjeCApLFxyXG5cdFx0eTAgPSBheSA8IGJ5ID8gKCBheSA8IGN5ID8gYXkgOiBjeSApIDogKCBieSA8IGN5ID8gYnkgOiBjeSApLFxyXG5cdFx0eDEgPSBheCA+IGJ4ID8gKCBheCA+IGN4ID8gYXggOiBjeCApIDogKCBieCA+IGN4ID8gYnggOiBjeCApLFxyXG5cdFx0eTEgPSBheSA+IGJ5ID8gKCBheSA+IGN5ID8gYXkgOiBjeSApIDogKCBieSA+IGN5ID8gYnkgOiBjeSApO1xyXG5cclxuXHQvLyB6LW9yZGVyIHJhbmdlIGZvciB0aGUgY3VycmVudCB0cmlhbmdsZSBiYm94O1xyXG5cdGNvbnN0IG1pblogPSB6T3JkZXIoIHgwLCB5MCwgbWluWCwgbWluWSwgaW52U2l6ZSApLFxyXG5cdFx0bWF4WiA9IHpPcmRlciggeDEsIHkxLCBtaW5YLCBtaW5ZLCBpbnZTaXplICk7XHJcblxyXG5cdGxldCBwID0gZWFyLnByZXZaLFxyXG5cdFx0biA9IGVhci5uZXh0WjtcclxuXHJcblx0Ly8gbG9vayBmb3IgcG9pbnRzIGluc2lkZSB0aGUgdHJpYW5nbGUgaW4gYm90aCBkaXJlY3Rpb25zXHJcblx0d2hpbGUgKCBwICYmIHAueiA+PSBtaW5aICYmIG4gJiYgbi56IDw9IG1heFogKSB7XHJcblxyXG5cdFx0aWYgKCBwLnggPj0geDAgJiYgcC54IDw9IHgxICYmIHAueSA+PSB5MCAmJiBwLnkgPD0geTEgJiYgcCAhPT0gYSAmJiBwICE9PSBjICYmXHJcblx0XHRcdHBvaW50SW5UcmlhbmdsZSggYXgsIGF5LCBieCwgYnksIGN4LCBjeSwgcC54LCBwLnkgKSAmJiBhcmVhKCBwLnByZXYsIHAsIHAubmV4dCApID49IDAgKSByZXR1cm4gZmFsc2U7XHJcblx0XHRwID0gcC5wcmV2WjtcclxuXHJcblx0XHRpZiAoIG4ueCA+PSB4MCAmJiBuLnggPD0geDEgJiYgbi55ID49IHkwICYmIG4ueSA8PSB5MSAmJiBuICE9PSBhICYmIG4gIT09IGMgJiZcclxuXHRcdFx0cG9pbnRJblRyaWFuZ2xlKCBheCwgYXksIGJ4LCBieSwgY3gsIGN5LCBuLngsIG4ueSApICYmIGFyZWEoIG4ucHJldiwgbiwgbi5uZXh0ICkgPj0gMCApIHJldHVybiBmYWxzZTtcclxuXHRcdG4gPSBuLm5leHRaO1xyXG5cclxuXHR9XHJcblxyXG5cdC8vIGxvb2sgZm9yIHJlbWFpbmluZyBwb2ludHMgaW4gZGVjcmVhc2luZyB6LW9yZGVyXHJcblx0d2hpbGUgKCBwICYmIHAueiA+PSBtaW5aICkge1xyXG5cclxuXHRcdGlmICggcC54ID49IHgwICYmIHAueCA8PSB4MSAmJiBwLnkgPj0geTAgJiYgcC55IDw9IHkxICYmIHAgIT09IGEgJiYgcCAhPT0gYyAmJlxyXG5cdFx0XHRwb2ludEluVHJpYW5nbGUoIGF4LCBheSwgYngsIGJ5LCBjeCwgY3ksIHAueCwgcC55ICkgJiYgYXJlYSggcC5wcmV2LCBwLCBwLm5leHQgKSA+PSAwICkgcmV0dXJuIGZhbHNlO1xyXG5cdFx0cCA9IHAucHJldlo7XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gbG9vayBmb3IgcmVtYWluaW5nIHBvaW50cyBpbiBpbmNyZWFzaW5nIHotb3JkZXJcclxuXHR3aGlsZSAoIG4gJiYgbi56IDw9IG1heFogKSB7XHJcblxyXG5cdFx0aWYgKCBuLnggPj0geDAgJiYgbi54IDw9IHgxICYmIG4ueSA+PSB5MCAmJiBuLnkgPD0geTEgJiYgbiAhPT0gYSAmJiBuICE9PSBjICYmXHJcblx0XHRcdHBvaW50SW5UcmlhbmdsZSggYXgsIGF5LCBieCwgYnksIGN4LCBjeSwgbi54LCBuLnkgKSAmJiBhcmVhKCBuLnByZXYsIG4sIG4ubmV4dCApID49IDAgKSByZXR1cm4gZmFsc2U7XHJcblx0XHRuID0gbi5uZXh0WjtcclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4gdHJ1ZTtcclxuXHJcbn1cclxuXHJcbi8vIGdvIHRocm91Z2ggYWxsIHBvbHlnb24gbm9kZXMgYW5kIGN1cmUgc21hbGwgbG9jYWwgc2VsZi1pbnRlcnNlY3Rpb25zXHJcbmZ1bmN0aW9uIGN1cmVMb2NhbEludGVyc2VjdGlvbnMoIHN0YXJ0LCB0cmlhbmdsZXMsIGRpbSApIHtcclxuXHJcblx0bGV0IHAgPSBzdGFydDtcclxuXHRkbyB7XHJcblxyXG5cdFx0Y29uc3QgYSA9IHAucHJldixcclxuXHRcdFx0YiA9IHAubmV4dC5uZXh0O1xyXG5cclxuXHRcdGlmICggISBlcXVhbHMoIGEsIGIgKSAmJiBpbnRlcnNlY3RzKCBhLCBwLCBwLm5leHQsIGIgKSAmJiBsb2NhbGx5SW5zaWRlKCBhLCBiICkgJiYgbG9jYWxseUluc2lkZSggYiwgYSApICkge1xyXG5cclxuXHRcdFx0dHJpYW5nbGVzLnB1c2goIGEuaSAvIGRpbSB8IDAgKTtcclxuXHRcdFx0dHJpYW5nbGVzLnB1c2goIHAuaSAvIGRpbSB8IDAgKTtcclxuXHRcdFx0dHJpYW5nbGVzLnB1c2goIGIuaSAvIGRpbSB8IDAgKTtcclxuXHJcblx0XHRcdC8vIHJlbW92ZSB0d28gbm9kZXMgaW52b2x2ZWRcclxuXHRcdFx0cmVtb3ZlTm9kZSggcCApO1xyXG5cdFx0XHRyZW1vdmVOb2RlKCBwLm5leHQgKTtcclxuXHJcblx0XHRcdHAgPSBzdGFydCA9IGI7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHAgPSBwLm5leHQ7XHJcblxyXG5cdH0gd2hpbGUgKCBwICE9PSBzdGFydCApO1xyXG5cclxuXHRyZXR1cm4gZmlsdGVyUG9pbnRzKCBwICk7XHJcblxyXG59XHJcblxyXG4vLyB0cnkgc3BsaXR0aW5nIHBvbHlnb24gaW50byB0d28gYW5kIHRyaWFuZ3VsYXRlIHRoZW0gaW5kZXBlbmRlbnRseVxyXG5mdW5jdGlvbiBzcGxpdEVhcmN1dCggc3RhcnQsIHRyaWFuZ2xlcywgZGltLCBtaW5YLCBtaW5ZLCBpbnZTaXplICkge1xyXG5cclxuXHQvLyBsb29rIGZvciBhIHZhbGlkIGRpYWdvbmFsIHRoYXQgZGl2aWRlcyB0aGUgcG9seWdvbiBpbnRvIHR3b1xyXG5cdGxldCBhID0gc3RhcnQ7XHJcblx0ZG8ge1xyXG5cclxuXHRcdGxldCBiID0gYS5uZXh0Lm5leHQ7XHJcblx0XHR3aGlsZSAoIGIgIT09IGEucHJldiApIHtcclxuXHJcblx0XHRcdGlmICggYS5pICE9PSBiLmkgJiYgaXNWYWxpZERpYWdvbmFsKCBhLCBiICkgKSB7XHJcblxyXG5cdFx0XHRcdC8vIHNwbGl0IHRoZSBwb2x5Z29uIGluIHR3byBieSB0aGUgZGlhZ29uYWxcclxuXHRcdFx0XHRsZXQgYyA9IHNwbGl0UG9seWdvbiggYSwgYiApO1xyXG5cclxuXHRcdFx0XHQvLyBmaWx0ZXIgY29saW5lYXIgcG9pbnRzIGFyb3VuZCB0aGUgY3V0c1xyXG5cdFx0XHRcdGEgPSBmaWx0ZXJQb2ludHMoIGEsIGEubmV4dCApO1xyXG5cdFx0XHRcdGMgPSBmaWx0ZXJQb2ludHMoIGMsIGMubmV4dCApO1xyXG5cclxuXHRcdFx0XHQvLyBydW4gZWFyY3V0IG9uIGVhY2ggaGFsZlxyXG5cdFx0XHRcdGVhcmN1dExpbmtlZCggYSwgdHJpYW5nbGVzLCBkaW0sIG1pblgsIG1pblksIGludlNpemUsIDAgKTtcclxuXHRcdFx0XHRlYXJjdXRMaW5rZWQoIGMsIHRyaWFuZ2xlcywgZGltLCBtaW5YLCBtaW5ZLCBpbnZTaXplLCAwICk7XHJcblx0XHRcdFx0cmV0dXJuO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0YiA9IGIubmV4dDtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0YSA9IGEubmV4dDtcclxuXHJcblx0fSB3aGlsZSAoIGEgIT09IHN0YXJ0ICk7XHJcblxyXG59XHJcblxyXG4vLyBsaW5rIGV2ZXJ5IGhvbGUgaW50byB0aGUgb3V0ZXIgbG9vcCwgcHJvZHVjaW5nIGEgc2luZ2xlLXJpbmcgcG9seWdvbiB3aXRob3V0IGhvbGVzXHJcbmZ1bmN0aW9uIGVsaW1pbmF0ZUhvbGVzKCBkYXRhLCBob2xlSW5kaWNlcywgb3V0ZXJOb2RlLCBkaW0gKSB7XHJcblxyXG5cdGNvbnN0IHF1ZXVlID0gW107XHJcblx0bGV0IGksIGxlbiwgc3RhcnQsIGVuZCwgbGlzdDtcclxuXHJcblx0Zm9yICggaSA9IDAsIGxlbiA9IGhvbGVJbmRpY2VzLmxlbmd0aDsgaSA8IGxlbjsgaSArKyApIHtcclxuXHJcblx0XHRzdGFydCA9IGhvbGVJbmRpY2VzWyBpIF0gKiBkaW07XHJcblx0XHRlbmQgPSBpIDwgbGVuIC0gMSA/IGhvbGVJbmRpY2VzWyBpICsgMSBdICogZGltIDogZGF0YS5sZW5ndGg7XHJcblx0XHRsaXN0ID0gbGlua2VkTGlzdCggZGF0YSwgc3RhcnQsIGVuZCwgZGltLCBmYWxzZSApO1xyXG5cdFx0aWYgKCBsaXN0ID09PSBsaXN0Lm5leHQgKSBsaXN0LnN0ZWluZXIgPSB0cnVlO1xyXG5cdFx0cXVldWUucHVzaCggZ2V0TGVmdG1vc3QoIGxpc3QgKSApO1xyXG5cclxuXHR9XHJcblxyXG5cdHF1ZXVlLnNvcnQoIGNvbXBhcmVYICk7XHJcblxyXG5cdC8vIHByb2Nlc3MgaG9sZXMgZnJvbSBsZWZ0IHRvIHJpZ2h0XHJcblx0Zm9yICggaSA9IDA7IGkgPCBxdWV1ZS5sZW5ndGg7IGkgKysgKSB7XHJcblxyXG5cdFx0b3V0ZXJOb2RlID0gZWxpbWluYXRlSG9sZSggcXVldWVbIGkgXSwgb3V0ZXJOb2RlICk7XHJcblxyXG5cdH1cclxuXHJcblx0cmV0dXJuIG91dGVyTm9kZTtcclxuXHJcbn1cclxuXHJcbmZ1bmN0aW9uIGNvbXBhcmVYKCBhLCBiICkge1xyXG5cclxuXHRyZXR1cm4gYS54IC0gYi54O1xyXG5cclxufVxyXG5cclxuLy8gZmluZCBhIGJyaWRnZSBiZXR3ZWVuIHZlcnRpY2VzIHRoYXQgY29ubmVjdHMgaG9sZSB3aXRoIGFuIG91dGVyIHJpbmcgYW5kIGxpbmsgaXRcclxuZnVuY3Rpb24gZWxpbWluYXRlSG9sZSggaG9sZSwgb3V0ZXJOb2RlICkge1xyXG5cclxuXHRjb25zdCBicmlkZ2UgPSBmaW5kSG9sZUJyaWRnZSggaG9sZSwgb3V0ZXJOb2RlICk7XHJcblx0aWYgKCAhIGJyaWRnZSApIHtcclxuXHJcblx0XHRyZXR1cm4gb3V0ZXJOb2RlO1xyXG5cclxuXHR9XHJcblxyXG5cdGNvbnN0IGJyaWRnZVJldmVyc2UgPSBzcGxpdFBvbHlnb24oIGJyaWRnZSwgaG9sZSApO1xyXG5cclxuXHQvLyBmaWx0ZXIgY29sbGluZWFyIHBvaW50cyBhcm91bmQgdGhlIGN1dHNcclxuXHRmaWx0ZXJQb2ludHMoIGJyaWRnZVJldmVyc2UsIGJyaWRnZVJldmVyc2UubmV4dCApO1xyXG5cdHJldHVybiBmaWx0ZXJQb2ludHMoIGJyaWRnZSwgYnJpZGdlLm5leHQgKTtcclxuXHJcbn1cclxuXHJcbi8vIERhdmlkIEViZXJseSdzIGFsZ29yaXRobSBmb3IgZmluZGluZyBhIGJyaWRnZSBiZXR3ZWVuIGhvbGUgYW5kIG91dGVyIHBvbHlnb25cclxuZnVuY3Rpb24gZmluZEhvbGVCcmlkZ2UoIGhvbGUsIG91dGVyTm9kZSApIHtcclxuXHJcblx0bGV0IHAgPSBvdXRlck5vZGUsXHJcblx0XHRxeCA9IC0gSW5maW5pdHksXHJcblx0XHRtO1xyXG5cclxuXHRjb25zdCBoeCA9IGhvbGUueCwgaHkgPSBob2xlLnk7XHJcblxyXG5cdC8vIGZpbmQgYSBzZWdtZW50IGludGVyc2VjdGVkIGJ5IGEgcmF5IGZyb20gdGhlIGhvbGUncyBsZWZ0bW9zdCBwb2ludCB0byB0aGUgbGVmdDtcclxuXHQvLyBzZWdtZW50J3MgZW5kcG9pbnQgd2l0aCBsZXNzZXIgeCB3aWxsIGJlIHBvdGVudGlhbCBjb25uZWN0aW9uIHBvaW50XHJcblx0ZG8ge1xyXG5cclxuXHRcdGlmICggaHkgPD0gcC55ICYmIGh5ID49IHAubmV4dC55ICYmIHAubmV4dC55ICE9PSBwLnkgKSB7XHJcblxyXG5cdFx0XHRjb25zdCB4ID0gcC54ICsgKCBoeSAtIHAueSApICogKCBwLm5leHQueCAtIHAueCApIC8gKCBwLm5leHQueSAtIHAueSApO1xyXG5cdFx0XHRpZiAoIHggPD0gaHggJiYgeCA+IHF4ICkge1xyXG5cclxuXHRcdFx0XHRxeCA9IHg7XHJcblx0XHRcdFx0bSA9IHAueCA8IHAubmV4dC54ID8gcCA6IHAubmV4dDtcclxuXHRcdFx0XHRpZiAoIHggPT09IGh4ICkgcmV0dXJuIG07IC8vIGhvbGUgdG91Y2hlcyBvdXRlciBzZWdtZW50OyBwaWNrIGxlZnRtb3N0IGVuZHBvaW50XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHAgPSBwLm5leHQ7XHJcblxyXG5cdH0gd2hpbGUgKCBwICE9PSBvdXRlck5vZGUgKTtcclxuXHJcblx0aWYgKCAhIG0gKSByZXR1cm4gbnVsbDtcclxuXHJcblx0Ly8gbG9vayBmb3IgcG9pbnRzIGluc2lkZSB0aGUgdHJpYW5nbGUgb2YgaG9sZSBwb2ludCwgc2VnbWVudCBpbnRlcnNlY3Rpb24gYW5kIGVuZHBvaW50O1xyXG5cdC8vIGlmIHRoZXJlIGFyZSBubyBwb2ludHMgZm91bmQsIHdlIGhhdmUgYSB2YWxpZCBjb25uZWN0aW9uO1xyXG5cdC8vIG90aGVyd2lzZSBjaG9vc2UgdGhlIHBvaW50IG9mIHRoZSBtaW5pbXVtIGFuZ2xlIHdpdGggdGhlIHJheSBhcyBjb25uZWN0aW9uIHBvaW50XHJcblxyXG5cdGNvbnN0IHN0b3AgPSBtLFxyXG5cdFx0bXggPSBtLngsXHJcblx0XHRteSA9IG0ueTtcclxuXHRsZXQgdGFuTWluID0gSW5maW5pdHksIHRhbjtcclxuXHJcblx0cCA9IG07XHJcblxyXG5cdGRvIHtcclxuXHJcblx0XHRpZiAoIGh4ID49IHAueCAmJiBwLnggPj0gbXggJiYgaHggIT09IHAueCAmJlxyXG5cdFx0XHRcdHBvaW50SW5UcmlhbmdsZSggaHkgPCBteSA/IGh4IDogcXgsIGh5LCBteCwgbXksIGh5IDwgbXkgPyBxeCA6IGh4LCBoeSwgcC54LCBwLnkgKSApIHtcclxuXHJcblx0XHRcdHRhbiA9IE1hdGguYWJzKCBoeSAtIHAueSApIC8gKCBoeCAtIHAueCApOyAvLyB0YW5nZW50aWFsXHJcblxyXG5cdFx0XHRpZiAoIGxvY2FsbHlJbnNpZGUoIHAsIGhvbGUgKSAmJiAoIHRhbiA8IHRhbk1pbiB8fCAoIHRhbiA9PT0gdGFuTWluICYmICggcC54ID4gbS54IHx8ICggcC54ID09PSBtLnggJiYgc2VjdG9yQ29udGFpbnNTZWN0b3IoIG0sIHAgKSApICkgKSApICkge1xyXG5cclxuXHRcdFx0XHRtID0gcDtcclxuXHRcdFx0XHR0YW5NaW4gPSB0YW47XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHAgPSBwLm5leHQ7XHJcblxyXG5cdH0gd2hpbGUgKCBwICE9PSBzdG9wICk7XHJcblxyXG5cdHJldHVybiBtO1xyXG5cclxufVxyXG5cclxuLy8gd2hldGhlciBzZWN0b3IgaW4gdmVydGV4IG0gY29udGFpbnMgc2VjdG9yIGluIHZlcnRleCBwIGluIHRoZSBzYW1lIGNvb3JkaW5hdGVzXHJcbmZ1bmN0aW9uIHNlY3RvckNvbnRhaW5zU2VjdG9yKCBtLCBwICkge1xyXG5cclxuXHRyZXR1cm4gYXJlYSggbS5wcmV2LCBtLCBwLnByZXYgKSA8IDAgJiYgYXJlYSggcC5uZXh0LCBtLCBtLm5leHQgKSA8IDA7XHJcblxyXG59XHJcblxyXG4vLyBpbnRlcmxpbmsgcG9seWdvbiBub2RlcyBpbiB6LW9yZGVyXHJcbmZ1bmN0aW9uIGluZGV4Q3VydmUoIHN0YXJ0LCBtaW5YLCBtaW5ZLCBpbnZTaXplICkge1xyXG5cclxuXHRsZXQgcCA9IHN0YXJ0O1xyXG5cdGRvIHtcclxuXHJcblx0XHRpZiAoIHAueiA9PT0gMCApIHAueiA9IHpPcmRlciggcC54LCBwLnksIG1pblgsIG1pblksIGludlNpemUgKTtcclxuXHRcdHAucHJldlogPSBwLnByZXY7XHJcblx0XHRwLm5leHRaID0gcC5uZXh0O1xyXG5cdFx0cCA9IHAubmV4dDtcclxuXHJcblx0fSB3aGlsZSAoIHAgIT09IHN0YXJ0ICk7XHJcblxyXG5cdHAucHJldloubmV4dFogPSBudWxsO1xyXG5cdHAucHJldlogPSBudWxsO1xyXG5cclxuXHRzb3J0TGlua2VkKCBwICk7XHJcblxyXG59XHJcblxyXG4vLyBTaW1vbiBUYXRoYW0ncyBsaW5rZWQgbGlzdCBtZXJnZSBzb3J0IGFsZ29yaXRobVxyXG4vLyBodHRwOi8vd3d3LmNoaWFyay5ncmVlbmVuZC5vcmcudWsvfnNndGF0aGFtL2FsZ29yaXRobXMvbGlzdHNvcnQuaHRtbFxyXG5mdW5jdGlvbiBzb3J0TGlua2VkKCBsaXN0ICkge1xyXG5cclxuXHRsZXQgaSwgcCwgcSwgZSwgdGFpbCwgbnVtTWVyZ2VzLCBwU2l6ZSwgcVNpemUsXHJcblx0XHRpblNpemUgPSAxO1xyXG5cclxuXHRkbyB7XHJcblxyXG5cdFx0cCA9IGxpc3Q7XHJcblx0XHRsaXN0ID0gbnVsbDtcclxuXHRcdHRhaWwgPSBudWxsO1xyXG5cdFx0bnVtTWVyZ2VzID0gMDtcclxuXHJcblx0XHR3aGlsZSAoIHAgKSB7XHJcblxyXG5cdFx0XHRudW1NZXJnZXMgKys7XHJcblx0XHRcdHEgPSBwO1xyXG5cdFx0XHRwU2l6ZSA9IDA7XHJcblx0XHRcdGZvciAoIGkgPSAwOyBpIDwgaW5TaXplOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRwU2l6ZSArKztcclxuXHRcdFx0XHRxID0gcS5uZXh0WjtcclxuXHRcdFx0XHRpZiAoICEgcSApIGJyZWFrO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0cVNpemUgPSBpblNpemU7XHJcblxyXG5cdFx0XHR3aGlsZSAoIHBTaXplID4gMCB8fCAoIHFTaXplID4gMCAmJiBxICkgKSB7XHJcblxyXG5cdFx0XHRcdGlmICggcFNpemUgIT09IDAgJiYgKCBxU2l6ZSA9PT0gMCB8fCAhIHEgfHwgcC56IDw9IHEueiApICkge1xyXG5cclxuXHRcdFx0XHRcdGUgPSBwO1xyXG5cdFx0XHRcdFx0cCA9IHAubmV4dFo7XHJcblx0XHRcdFx0XHRwU2l6ZSAtLTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRlID0gcTtcclxuXHRcdFx0XHRcdHEgPSBxLm5leHRaO1xyXG5cdFx0XHRcdFx0cVNpemUgLS07XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0aWYgKCB0YWlsICkgdGFpbC5uZXh0WiA9IGU7XHJcblx0XHRcdFx0ZWxzZSBsaXN0ID0gZTtcclxuXHJcblx0XHRcdFx0ZS5wcmV2WiA9IHRhaWw7XHJcblx0XHRcdFx0dGFpbCA9IGU7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRwID0gcTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGFpbC5uZXh0WiA9IG51bGw7XHJcblx0XHRpblNpemUgKj0gMjtcclxuXHJcblx0fSB3aGlsZSAoIG51bU1lcmdlcyA+IDEgKTtcclxuXHJcblx0cmV0dXJuIGxpc3Q7XHJcblxyXG59XHJcblxyXG4vLyB6LW9yZGVyIG9mIGEgcG9pbnQgZ2l2ZW4gY29vcmRzIGFuZCBpbnZlcnNlIG9mIHRoZSBsb25nZXIgc2lkZSBvZiBkYXRhIGJib3hcclxuZnVuY3Rpb24gek9yZGVyKCB4LCB5LCBtaW5YLCBtaW5ZLCBpbnZTaXplICkge1xyXG5cclxuXHQvLyBjb29yZHMgYXJlIHRyYW5zZm9ybWVkIGludG8gbm9uLW5lZ2F0aXZlIDE1LWJpdCBpbnRlZ2VyIHJhbmdlXHJcblx0eCA9ICggeCAtIG1pblggKSAqIGludlNpemUgfCAwO1xyXG5cdHkgPSAoIHkgLSBtaW5ZICkgKiBpbnZTaXplIHwgMDtcclxuXHJcblx0eCA9ICggeCB8ICggeCA8PCA4ICkgKSAmIDB4MDBGRjAwRkY7XHJcblx0eCA9ICggeCB8ICggeCA8PCA0ICkgKSAmIDB4MEYwRjBGMEY7XHJcblx0eCA9ICggeCB8ICggeCA8PCAyICkgKSAmIDB4MzMzMzMzMzM7XHJcblx0eCA9ICggeCB8ICggeCA8PCAxICkgKSAmIDB4NTU1NTU1NTU7XHJcblxyXG5cdHkgPSAoIHkgfCAoIHkgPDwgOCApICkgJiAweDAwRkYwMEZGO1xyXG5cdHkgPSAoIHkgfCAoIHkgPDwgNCApICkgJiAweDBGMEYwRjBGO1xyXG5cdHkgPSAoIHkgfCAoIHkgPDwgMiApICkgJiAweDMzMzMzMzMzO1xyXG5cdHkgPSAoIHkgfCAoIHkgPDwgMSApICkgJiAweDU1NTU1NTU1O1xyXG5cclxuXHRyZXR1cm4geCB8ICggeSA8PCAxICk7XHJcblxyXG59XHJcblxyXG4vLyBmaW5kIHRoZSBsZWZ0bW9zdCBub2RlIG9mIGEgcG9seWdvbiByaW5nXHJcbmZ1bmN0aW9uIGdldExlZnRtb3N0KCBzdGFydCApIHtcclxuXHJcblx0bGV0IHAgPSBzdGFydCxcclxuXHRcdGxlZnRtb3N0ID0gc3RhcnQ7XHJcblx0ZG8ge1xyXG5cclxuXHRcdGlmICggcC54IDwgbGVmdG1vc3QueCB8fCAoIHAueCA9PT0gbGVmdG1vc3QueCAmJiBwLnkgPCBsZWZ0bW9zdC55ICkgKSBsZWZ0bW9zdCA9IHA7XHJcblx0XHRwID0gcC5uZXh0O1xyXG5cclxuXHR9IHdoaWxlICggcCAhPT0gc3RhcnQgKTtcclxuXHJcblx0cmV0dXJuIGxlZnRtb3N0O1xyXG5cclxufVxyXG5cclxuLy8gY2hlY2sgaWYgYSBwb2ludCBsaWVzIHdpdGhpbiBhIGNvbnZleCB0cmlhbmdsZVxyXG5mdW5jdGlvbiBwb2ludEluVHJpYW5nbGUoIGF4LCBheSwgYngsIGJ5LCBjeCwgY3ksIHB4LCBweSApIHtcclxuXHJcblx0cmV0dXJuICggY3ggLSBweCApICogKCBheSAtIHB5ICkgPj0gKCBheCAtIHB4ICkgKiAoIGN5IC0gcHkgKSAmJlxyXG4gICAgICAgICAgICggYXggLSBweCApICogKCBieSAtIHB5ICkgPj0gKCBieCAtIHB4ICkgKiAoIGF5IC0gcHkgKSAmJlxyXG4gICAgICAgICAgICggYnggLSBweCApICogKCBjeSAtIHB5ICkgPj0gKCBjeCAtIHB4ICkgKiAoIGJ5IC0gcHkgKTtcclxuXHJcbn1cclxuXHJcbi8vIGNoZWNrIGlmIGEgZGlhZ29uYWwgYmV0d2VlbiB0d28gcG9seWdvbiBub2RlcyBpcyB2YWxpZCAobGllcyBpbiBwb2x5Z29uIGludGVyaW9yKVxyXG5mdW5jdGlvbiBpc1ZhbGlkRGlhZ29uYWwoIGEsIGIgKSB7XHJcblxyXG5cdHJldHVybiBhLm5leHQuaSAhPT0gYi5pICYmIGEucHJldi5pICE9PSBiLmkgJiYgISBpbnRlcnNlY3RzUG9seWdvbiggYSwgYiApICYmIC8vIGRvbmVzJ3QgaW50ZXJzZWN0IG90aGVyIGVkZ2VzXHJcbiAgICAgICAgICAgKCBsb2NhbGx5SW5zaWRlKCBhLCBiICkgJiYgbG9jYWxseUluc2lkZSggYiwgYSApICYmIG1pZGRsZUluc2lkZSggYSwgYiApICYmIC8vIGxvY2FsbHkgdmlzaWJsZVxyXG4gICAgICAgICAgICAoIGFyZWEoIGEucHJldiwgYSwgYi5wcmV2ICkgfHwgYXJlYSggYSwgYi5wcmV2LCBiICkgKSB8fCAvLyBkb2VzIG5vdCBjcmVhdGUgb3Bwb3NpdGUtZmFjaW5nIHNlY3RvcnNcclxuICAgICAgICAgICAgZXF1YWxzKCBhLCBiICkgJiYgYXJlYSggYS5wcmV2LCBhLCBhLm5leHQgKSA+IDAgJiYgYXJlYSggYi5wcmV2LCBiLCBiLm5leHQgKSA+IDAgKTsgLy8gc3BlY2lhbCB6ZXJvLWxlbmd0aCBjYXNlXHJcblxyXG59XHJcblxyXG4vLyBzaWduZWQgYXJlYSBvZiBhIHRyaWFuZ2xlXHJcbmZ1bmN0aW9uIGFyZWEoIHAsIHEsIHIgKSB7XHJcblxyXG5cdHJldHVybiAoIHEueSAtIHAueSApICogKCByLnggLSBxLnggKSAtICggcS54IC0gcC54ICkgKiAoIHIueSAtIHEueSApO1xyXG5cclxufVxyXG5cclxuLy8gY2hlY2sgaWYgdHdvIHBvaW50cyBhcmUgZXF1YWxcclxuZnVuY3Rpb24gZXF1YWxzKCBwMSwgcDIgKSB7XHJcblxyXG5cdHJldHVybiBwMS54ID09PSBwMi54ICYmIHAxLnkgPT09IHAyLnk7XHJcblxyXG59XHJcblxyXG4vLyBjaGVjayBpZiB0d28gc2VnbWVudHMgaW50ZXJzZWN0XHJcbmZ1bmN0aW9uIGludGVyc2VjdHMoIHAxLCBxMSwgcDIsIHEyICkge1xyXG5cclxuXHRjb25zdCBvMSA9IHNpZ24oIGFyZWEoIHAxLCBxMSwgcDIgKSApO1xyXG5cdGNvbnN0IG8yID0gc2lnbiggYXJlYSggcDEsIHExLCBxMiApICk7XHJcblx0Y29uc3QgbzMgPSBzaWduKCBhcmVhKCBwMiwgcTIsIHAxICkgKTtcclxuXHRjb25zdCBvNCA9IHNpZ24oIGFyZWEoIHAyLCBxMiwgcTEgKSApO1xyXG5cclxuXHRpZiAoIG8xICE9PSBvMiAmJiBvMyAhPT0gbzQgKSByZXR1cm4gdHJ1ZTsgLy8gZ2VuZXJhbCBjYXNlXHJcblxyXG5cdGlmICggbzEgPT09IDAgJiYgb25TZWdtZW50KCBwMSwgcDIsIHExICkgKSByZXR1cm4gdHJ1ZTsgLy8gcDEsIHExIGFuZCBwMiBhcmUgY29sbGluZWFyIGFuZCBwMiBsaWVzIG9uIHAxcTFcclxuXHRpZiAoIG8yID09PSAwICYmIG9uU2VnbWVudCggcDEsIHEyLCBxMSApICkgcmV0dXJuIHRydWU7IC8vIHAxLCBxMSBhbmQgcTIgYXJlIGNvbGxpbmVhciBhbmQgcTIgbGllcyBvbiBwMXExXHJcblx0aWYgKCBvMyA9PT0gMCAmJiBvblNlZ21lbnQoIHAyLCBwMSwgcTIgKSApIHJldHVybiB0cnVlOyAvLyBwMiwgcTIgYW5kIHAxIGFyZSBjb2xsaW5lYXIgYW5kIHAxIGxpZXMgb24gcDJxMlxyXG5cdGlmICggbzQgPT09IDAgJiYgb25TZWdtZW50KCBwMiwgcTEsIHEyICkgKSByZXR1cm4gdHJ1ZTsgLy8gcDIsIHEyIGFuZCBxMSBhcmUgY29sbGluZWFyIGFuZCBxMSBsaWVzIG9uIHAycTJcclxuXHJcblx0cmV0dXJuIGZhbHNlO1xyXG5cclxufVxyXG5cclxuLy8gZm9yIGNvbGxpbmVhciBwb2ludHMgcCwgcSwgciwgY2hlY2sgaWYgcG9pbnQgcSBsaWVzIG9uIHNlZ21lbnQgcHJcclxuZnVuY3Rpb24gb25TZWdtZW50KCBwLCBxLCByICkge1xyXG5cclxuXHRyZXR1cm4gcS54IDw9IE1hdGgubWF4KCBwLngsIHIueCApICYmIHEueCA+PSBNYXRoLm1pbiggcC54LCByLnggKSAmJiBxLnkgPD0gTWF0aC5tYXgoIHAueSwgci55ICkgJiYgcS55ID49IE1hdGgubWluKCBwLnksIHIueSApO1xyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gc2lnbiggbnVtICkge1xyXG5cclxuXHRyZXR1cm4gbnVtID4gMCA/IDEgOiBudW0gPCAwID8gLSAxIDogMDtcclxuXHJcbn1cclxuXHJcbi8vIGNoZWNrIGlmIGEgcG9seWdvbiBkaWFnb25hbCBpbnRlcnNlY3RzIGFueSBwb2x5Z29uIHNlZ21lbnRzXHJcbmZ1bmN0aW9uIGludGVyc2VjdHNQb2x5Z29uKCBhLCBiICkge1xyXG5cclxuXHRsZXQgcCA9IGE7XHJcblx0ZG8ge1xyXG5cclxuXHRcdGlmICggcC5pICE9PSBhLmkgJiYgcC5uZXh0LmkgIT09IGEuaSAmJiBwLmkgIT09IGIuaSAmJiBwLm5leHQuaSAhPT0gYi5pICYmXHJcblx0XHRcdGludGVyc2VjdHMoIHAsIHAubmV4dCwgYSwgYiApICkgcmV0dXJuIHRydWU7XHJcblx0XHRwID0gcC5uZXh0O1xyXG5cclxuXHR9IHdoaWxlICggcCAhPT0gYSApO1xyXG5cclxuXHRyZXR1cm4gZmFsc2U7XHJcblxyXG59XHJcblxyXG4vLyBjaGVjayBpZiBhIHBvbHlnb24gZGlhZ29uYWwgaXMgbG9jYWxseSBpbnNpZGUgdGhlIHBvbHlnb25cclxuZnVuY3Rpb24gbG9jYWxseUluc2lkZSggYSwgYiApIHtcclxuXHJcblx0cmV0dXJuIGFyZWEoIGEucHJldiwgYSwgYS5uZXh0ICkgPCAwID9cclxuXHRcdGFyZWEoIGEsIGIsIGEubmV4dCApID49IDAgJiYgYXJlYSggYSwgYS5wcmV2LCBiICkgPj0gMCA6XHJcblx0XHRhcmVhKCBhLCBiLCBhLnByZXYgKSA8IDAgfHwgYXJlYSggYSwgYS5uZXh0LCBiICkgPCAwO1xyXG5cclxufVxyXG5cclxuLy8gY2hlY2sgaWYgdGhlIG1pZGRsZSBwb2ludCBvZiBhIHBvbHlnb24gZGlhZ29uYWwgaXMgaW5zaWRlIHRoZSBwb2x5Z29uXHJcbmZ1bmN0aW9uIG1pZGRsZUluc2lkZSggYSwgYiApIHtcclxuXHJcblx0bGV0IHAgPSBhLFxyXG5cdFx0aW5zaWRlID0gZmFsc2U7XHJcblx0Y29uc3QgcHggPSAoIGEueCArIGIueCApIC8gMixcclxuXHRcdHB5ID0gKCBhLnkgKyBiLnkgKSAvIDI7XHJcblx0ZG8ge1xyXG5cclxuXHRcdGlmICggKCAoIHAueSA+IHB5ICkgIT09ICggcC5uZXh0LnkgPiBweSApICkgJiYgcC5uZXh0LnkgIT09IHAueSAmJlxyXG5cdFx0XHQoIHB4IDwgKCBwLm5leHQueCAtIHAueCApICogKCBweSAtIHAueSApIC8gKCBwLm5leHQueSAtIHAueSApICsgcC54ICkgKVxyXG5cdFx0XHRpbnNpZGUgPSAhIGluc2lkZTtcclxuXHRcdHAgPSBwLm5leHQ7XHJcblxyXG5cdH0gd2hpbGUgKCBwICE9PSBhICk7XHJcblxyXG5cdHJldHVybiBpbnNpZGU7XHJcblxyXG59XHJcblxyXG4vLyBsaW5rIHR3byBwb2x5Z29uIHZlcnRpY2VzIHdpdGggYSBicmlkZ2U7IGlmIHRoZSB2ZXJ0aWNlcyBiZWxvbmcgdG8gdGhlIHNhbWUgcmluZywgaXQgc3BsaXRzIHBvbHlnb24gaW50byB0d287XHJcbi8vIGlmIG9uZSBiZWxvbmdzIHRvIHRoZSBvdXRlciByaW5nIGFuZCBhbm90aGVyIHRvIGEgaG9sZSwgaXQgbWVyZ2VzIGl0IGludG8gYSBzaW5nbGUgcmluZ1xyXG5mdW5jdGlvbiBzcGxpdFBvbHlnb24oIGEsIGIgKSB7XHJcblxyXG5cdGNvbnN0IGEyID0gbmV3IE5vZGUoIGEuaSwgYS54LCBhLnkgKSxcclxuXHRcdGIyID0gbmV3IE5vZGUoIGIuaSwgYi54LCBiLnkgKSxcclxuXHRcdGFuID0gYS5uZXh0LFxyXG5cdFx0YnAgPSBiLnByZXY7XHJcblxyXG5cdGEubmV4dCA9IGI7XHJcblx0Yi5wcmV2ID0gYTtcclxuXHJcblx0YTIubmV4dCA9IGFuO1xyXG5cdGFuLnByZXYgPSBhMjtcclxuXHJcblx0YjIubmV4dCA9IGEyO1xyXG5cdGEyLnByZXYgPSBiMjtcclxuXHJcblx0YnAubmV4dCA9IGIyO1xyXG5cdGIyLnByZXYgPSBicDtcclxuXHJcblx0cmV0dXJuIGIyO1xyXG5cclxufVxyXG5cclxuLy8gY3JlYXRlIGEgbm9kZSBhbmQgb3B0aW9uYWxseSBsaW5rIGl0IHdpdGggcHJldmlvdXMgb25lIChpbiBhIGNpcmN1bGFyIGRvdWJseSBsaW5rZWQgbGlzdClcclxuZnVuY3Rpb24gaW5zZXJ0Tm9kZSggaSwgeCwgeSwgbGFzdCApIHtcclxuXHJcblx0Y29uc3QgcCA9IG5ldyBOb2RlKCBpLCB4LCB5ICk7XHJcblxyXG5cdGlmICggISBsYXN0ICkge1xyXG5cclxuXHRcdHAucHJldiA9IHA7XHJcblx0XHRwLm5leHQgPSBwO1xyXG5cclxuXHR9IGVsc2Uge1xyXG5cclxuXHRcdHAubmV4dCA9IGxhc3QubmV4dDtcclxuXHRcdHAucHJldiA9IGxhc3Q7XHJcblx0XHRsYXN0Lm5leHQucHJldiA9IHA7XHJcblx0XHRsYXN0Lm5leHQgPSBwO1xyXG5cclxuXHR9XHJcblxyXG5cdHJldHVybiBwO1xyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gcmVtb3ZlTm9kZSggcCApIHtcclxuXHJcblx0cC5uZXh0LnByZXYgPSBwLnByZXY7XHJcblx0cC5wcmV2Lm5leHQgPSBwLm5leHQ7XHJcblxyXG5cdGlmICggcC5wcmV2WiApIHAucHJldloubmV4dFogPSBwLm5leHRaO1xyXG5cdGlmICggcC5uZXh0WiApIHAubmV4dFoucHJldlogPSBwLnByZXZaO1xyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gTm9kZSggaSwgeCwgeSApIHtcclxuXHJcblx0Ly8gdmVydGV4IGluZGV4IGluIGNvb3JkaW5hdGVzIGFycmF5XHJcblx0dGhpcy5pID0gaTtcclxuXHJcblx0Ly8gdmVydGV4IGNvb3JkaW5hdGVzXHJcblx0dGhpcy54ID0geDtcclxuXHR0aGlzLnkgPSB5O1xyXG5cclxuXHQvLyBwcmV2aW91cyBhbmQgbmV4dCB2ZXJ0ZXggbm9kZXMgaW4gYSBwb2x5Z29uIHJpbmdcclxuXHR0aGlzLnByZXYgPSBudWxsO1xyXG5cdHRoaXMubmV4dCA9IG51bGw7XHJcblxyXG5cdC8vIHotb3JkZXIgY3VydmUgdmFsdWVcclxuXHR0aGlzLnogPSAwO1xyXG5cclxuXHQvLyBwcmV2aW91cyBhbmQgbmV4dCBub2RlcyBpbiB6LW9yZGVyXHJcblx0dGhpcy5wcmV2WiA9IG51bGw7XHJcblx0dGhpcy5uZXh0WiA9IG51bGw7XHJcblxyXG5cdC8vIGluZGljYXRlcyB3aGV0aGVyIHRoaXMgaXMgYSBzdGVpbmVyIHBvaW50XHJcblx0dGhpcy5zdGVpbmVyID0gZmFsc2U7XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiBzaWduZWRBcmVhKCBkYXRhLCBzdGFydCwgZW5kLCBkaW0gKSB7XHJcblxyXG5cdGxldCBzdW0gPSAwO1xyXG5cdGZvciAoIGxldCBpID0gc3RhcnQsIGogPSBlbmQgLSBkaW07IGkgPCBlbmQ7IGkgKz0gZGltICkge1xyXG5cclxuXHRcdHN1bSArPSAoIGRhdGFbIGogXSAtIGRhdGFbIGkgXSApICogKCBkYXRhWyBpICsgMSBdICsgZGF0YVsgaiArIDEgXSApO1xyXG5cdFx0aiA9IGk7XHJcblxyXG5cdH1cclxuXHJcblx0cmV0dXJuIHN1bTtcclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IEVhcmN1dCB9O1xyXG4iLCJpbXBvcnQgeyBFYXJjdXQgfSBmcm9tICcuL0VhcmN1dC5qcyc7XHJcblxyXG5jbGFzcyBTaGFwZVV0aWxzIHtcclxuXHJcblx0Ly8gY2FsY3VsYXRlIGFyZWEgb2YgdGhlIGNvbnRvdXIgcG9seWdvblxyXG5cclxuXHRzdGF0aWMgYXJlYSggY29udG91ciApIHtcclxuXHJcblx0XHRjb25zdCBuID0gY29udG91ci5sZW5ndGg7XHJcblx0XHRsZXQgYSA9IDAuMDtcclxuXHJcblx0XHRmb3IgKCBsZXQgcCA9IG4gLSAxLCBxID0gMDsgcSA8IG47IHAgPSBxICsrICkge1xyXG5cclxuXHRcdFx0YSArPSBjb250b3VyWyBwIF0ueCAqIGNvbnRvdXJbIHEgXS55IC0gY29udG91clsgcSBdLnggKiBjb250b3VyWyBwIF0ueTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIGEgKiAwLjU7XHJcblxyXG5cdH1cclxuXHJcblx0c3RhdGljIGlzQ2xvY2tXaXNlKCBwdHMgKSB7XHJcblxyXG5cdFx0cmV0dXJuIFNoYXBlVXRpbHMuYXJlYSggcHRzICkgPCAwO1xyXG5cclxuXHR9XHJcblxyXG5cdHN0YXRpYyB0cmlhbmd1bGF0ZVNoYXBlKCBjb250b3VyLCBob2xlcyApIHtcclxuXHJcblx0XHRjb25zdCB2ZXJ0aWNlcyA9IFtdOyAvLyBmbGF0IGFycmF5IG9mIHZlcnRpY2VzIGxpa2UgWyB4MCx5MCwgeDEseTEsIHgyLHkyLCAuLi4gXVxyXG5cdFx0Y29uc3QgaG9sZUluZGljZXMgPSBbXTsgLy8gYXJyYXkgb2YgaG9sZSBpbmRpY2VzXHJcblx0XHRjb25zdCBmYWNlcyA9IFtdOyAvLyBmaW5hbCBhcnJheSBvZiB2ZXJ0ZXggaW5kaWNlcyBsaWtlIFsgWyBhLGIsZCBdLCBbIGIsYyxkIF0gXVxyXG5cclxuXHRcdHJlbW92ZUR1cEVuZFB0cyggY29udG91ciApO1xyXG5cdFx0YWRkQ29udG91ciggdmVydGljZXMsIGNvbnRvdXIgKTtcclxuXHJcblx0XHQvL1xyXG5cclxuXHRcdGxldCBob2xlSW5kZXggPSBjb250b3VyLmxlbmd0aDtcclxuXHJcblx0XHRob2xlcy5mb3JFYWNoKCByZW1vdmVEdXBFbmRQdHMgKTtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBob2xlcy5sZW5ndGg7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRob2xlSW5kaWNlcy5wdXNoKCBob2xlSW5kZXggKTtcclxuXHRcdFx0aG9sZUluZGV4ICs9IGhvbGVzWyBpIF0ubGVuZ3RoO1xyXG5cdFx0XHRhZGRDb250b3VyKCB2ZXJ0aWNlcywgaG9sZXNbIGkgXSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvL1xyXG5cclxuXHRcdGNvbnN0IHRyaWFuZ2xlcyA9IEVhcmN1dC50cmlhbmd1bGF0ZSggdmVydGljZXMsIGhvbGVJbmRpY2VzICk7XHJcblxyXG5cdFx0Ly9cclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCB0cmlhbmdsZXMubGVuZ3RoOyBpICs9IDMgKSB7XHJcblxyXG5cdFx0XHRmYWNlcy5wdXNoKCB0cmlhbmdsZXMuc2xpY2UoIGksIGkgKyAzICkgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIGZhY2VzO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiByZW1vdmVEdXBFbmRQdHMoIHBvaW50cyApIHtcclxuXHJcblx0Y29uc3QgbCA9IHBvaW50cy5sZW5ndGg7XHJcblxyXG5cdGlmICggbCA+IDIgJiYgcG9pbnRzWyBsIC0gMSBdLmVxdWFscyggcG9pbnRzWyAwIF0gKSApIHtcclxuXHJcblx0XHRwb2ludHMucG9wKCk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmZ1bmN0aW9uIGFkZENvbnRvdXIoIHZlcnRpY2VzLCBjb250b3VyICkge1xyXG5cclxuXHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBjb250b3VyLmxlbmd0aDsgaSArKyApIHtcclxuXHJcblx0XHR2ZXJ0aWNlcy5wdXNoKCBjb250b3VyWyBpIF0ueCApO1xyXG5cdFx0dmVydGljZXMucHVzaCggY29udG91clsgaSBdLnkgKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgU2hhcGVVdGlscyB9O1xyXG4iLCIvKipcclxuICogQ3JlYXRlcyBleHRydWRlZCBnZW9tZXRyeSBmcm9tIGEgcGF0aCBzaGFwZS5cclxuICpcclxuICogcGFyYW1ldGVycyA9IHtcclxuICpcclxuICogIGN1cnZlU2VnbWVudHM6IDxpbnQ+LCAvLyBudW1iZXIgb2YgcG9pbnRzIG9uIHRoZSBjdXJ2ZXNcclxuICogIHN0ZXBzOiA8aW50PiwgLy8gbnVtYmVyIG9mIHBvaW50cyBmb3Igei1zaWRlIGV4dHJ1c2lvbnMgLyB1c2VkIGZvciBzdWJkaXZpZGluZyBzZWdtZW50cyBvZiBleHRydWRlIHNwbGluZSB0b29cclxuICogIGRlcHRoOiA8ZmxvYXQ+LCAvLyBEZXB0aCB0byBleHRydWRlIHRoZSBzaGFwZVxyXG4gKlxyXG4gKiAgYmV2ZWxFbmFibGVkOiA8Ym9vbD4sIC8vIHR1cm4gb24gYmV2ZWxcclxuICogIGJldmVsVGhpY2tuZXNzOiA8ZmxvYXQ+LCAvLyBob3cgZGVlcCBpbnRvIHRoZSBvcmlnaW5hbCBzaGFwZSBiZXZlbCBnb2VzXHJcbiAqICBiZXZlbFNpemU6IDxmbG9hdD4sIC8vIGhvdyBmYXIgZnJvbSBzaGFwZSBvdXRsaW5lIChpbmNsdWRpbmcgYmV2ZWxPZmZzZXQpIGlzIGJldmVsXHJcbiAqICBiZXZlbE9mZnNldDogPGZsb2F0PiwgLy8gaG93IGZhciBmcm9tIHNoYXBlIG91dGxpbmUgZG9lcyBiZXZlbCBzdGFydFxyXG4gKiAgYmV2ZWxTZWdtZW50czogPGludD4sIC8vIG51bWJlciBvZiBiZXZlbCBsYXllcnNcclxuICpcclxuICogIGV4dHJ1ZGVQYXRoOiA8VEhSRUUuQ3VydmU+IC8vIGN1cnZlIHRvIGV4dHJ1ZGUgc2hhcGUgYWxvbmdcclxuICpcclxuICogIFVWR2VuZXJhdG9yOiA8T2JqZWN0PiAvLyBvYmplY3QgdGhhdCBwcm92aWRlcyBVViBnZW5lcmF0b3IgZnVuY3Rpb25zXHJcbiAqXHJcbiAqIH1cclxuICovXHJcblxyXG5pbXBvcnQgeyBCdWZmZXJHZW9tZXRyeSB9IGZyb20gJy4uL2NvcmUvQnVmZmVyR2VvbWV0cnkuanMnO1xyXG5pbXBvcnQgeyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlIH0gZnJvbSAnLi4vY29yZS9CdWZmZXJBdHRyaWJ1dGUuanMnO1xyXG5pbXBvcnQgKiBhcyBDdXJ2ZXMgZnJvbSAnLi4vZXh0cmFzL2N1cnZlcy9DdXJ2ZXMuanMnO1xyXG5pbXBvcnQgeyBWZWN0b3IyIH0gZnJvbSAnLi4vbWF0aC9WZWN0b3IyLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yMyB9IGZyb20gJy4uL21hdGgvVmVjdG9yMy5qcyc7XHJcbmltcG9ydCB7IFNoYXBlIH0gZnJvbSAnLi4vZXh0cmFzL2NvcmUvU2hhcGUuanMnO1xyXG5pbXBvcnQgeyBTaGFwZVV0aWxzIH0gZnJvbSAnLi4vZXh0cmFzL1NoYXBlVXRpbHMuanMnO1xyXG5cclxuY2xhc3MgRXh0cnVkZUdlb21ldHJ5IGV4dGVuZHMgQnVmZmVyR2VvbWV0cnkge1xyXG5cclxuXHRjb25zdHJ1Y3Rvciggc2hhcGVzID0gbmV3IFNoYXBlKCBbIG5ldyBWZWN0b3IyKCAwLjUsIDAuNSApLCBuZXcgVmVjdG9yMiggLSAwLjUsIDAuNSApLCBuZXcgVmVjdG9yMiggLSAwLjUsIC0gMC41ICksIG5ldyBWZWN0b3IyKCAwLjUsIC0gMC41ICkgXSApLCBvcHRpb25zID0ge30gKSB7XHJcblxyXG5cdFx0c3VwZXIoKTtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSAnRXh0cnVkZUdlb21ldHJ5JztcclxuXHJcblx0XHR0aGlzLnBhcmFtZXRlcnMgPSB7XHJcblx0XHRcdHNoYXBlczogc2hhcGVzLFxyXG5cdFx0XHRvcHRpb25zOiBvcHRpb25zXHJcblx0XHR9O1xyXG5cclxuXHRcdHNoYXBlcyA9IEFycmF5LmlzQXJyYXkoIHNoYXBlcyApID8gc2hhcGVzIDogWyBzaGFwZXMgXTtcclxuXHJcblx0XHRjb25zdCBzY29wZSA9IHRoaXM7XHJcblxyXG5cdFx0Y29uc3QgdmVydGljZXNBcnJheSA9IFtdO1xyXG5cdFx0Y29uc3QgdXZBcnJheSA9IFtdO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IHNoYXBlcy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0Y29uc3Qgc2hhcGUgPSBzaGFwZXNbIGkgXTtcclxuXHRcdFx0YWRkU2hhcGUoIHNoYXBlICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIGJ1aWxkIGdlb21ldHJ5XHJcblxyXG5cdFx0dGhpcy5zZXRBdHRyaWJ1dGUoICdwb3NpdGlvbicsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCB2ZXJ0aWNlc0FycmF5LCAzICkgKTtcclxuXHRcdHRoaXMuc2V0QXR0cmlidXRlKCAndXYnLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggdXZBcnJheSwgMiApICk7XHJcblxyXG5cdFx0dGhpcy5jb21wdXRlVmVydGV4Tm9ybWFscygpO1xyXG5cclxuXHRcdC8vIGZ1bmN0aW9uc1xyXG5cclxuXHRcdGZ1bmN0aW9uIGFkZFNoYXBlKCBzaGFwZSApIHtcclxuXHJcblx0XHRcdGNvbnN0IHBsYWNlaG9sZGVyID0gW107XHJcblxyXG5cdFx0XHQvLyBvcHRpb25zXHJcblxyXG5cdFx0XHRjb25zdCBjdXJ2ZVNlZ21lbnRzID0gb3B0aW9ucy5jdXJ2ZVNlZ21lbnRzICE9PSB1bmRlZmluZWQgPyBvcHRpb25zLmN1cnZlU2VnbWVudHMgOiAxMjtcclxuXHRcdFx0Y29uc3Qgc3RlcHMgPSBvcHRpb25zLnN0ZXBzICE9PSB1bmRlZmluZWQgPyBvcHRpb25zLnN0ZXBzIDogMTtcclxuXHRcdFx0Y29uc3QgZGVwdGggPSBvcHRpb25zLmRlcHRoICE9PSB1bmRlZmluZWQgPyBvcHRpb25zLmRlcHRoIDogMTtcclxuXHJcblx0XHRcdGxldCBiZXZlbEVuYWJsZWQgPSBvcHRpb25zLmJldmVsRW5hYmxlZCAhPT0gdW5kZWZpbmVkID8gb3B0aW9ucy5iZXZlbEVuYWJsZWQgOiB0cnVlO1xyXG5cdFx0XHRsZXQgYmV2ZWxUaGlja25lc3MgPSBvcHRpb25zLmJldmVsVGhpY2tuZXNzICE9PSB1bmRlZmluZWQgPyBvcHRpb25zLmJldmVsVGhpY2tuZXNzIDogMC4yO1xyXG5cdFx0XHRsZXQgYmV2ZWxTaXplID0gb3B0aW9ucy5iZXZlbFNpemUgIT09IHVuZGVmaW5lZCA/IG9wdGlvbnMuYmV2ZWxTaXplIDogYmV2ZWxUaGlja25lc3MgLSAwLjE7XHJcblx0XHRcdGxldCBiZXZlbE9mZnNldCA9IG9wdGlvbnMuYmV2ZWxPZmZzZXQgIT09IHVuZGVmaW5lZCA/IG9wdGlvbnMuYmV2ZWxPZmZzZXQgOiAwO1xyXG5cdFx0XHRsZXQgYmV2ZWxTZWdtZW50cyA9IG9wdGlvbnMuYmV2ZWxTZWdtZW50cyAhPT0gdW5kZWZpbmVkID8gb3B0aW9ucy5iZXZlbFNlZ21lbnRzIDogMztcclxuXHJcblx0XHRcdGNvbnN0IGV4dHJ1ZGVQYXRoID0gb3B0aW9ucy5leHRydWRlUGF0aDtcclxuXHJcblx0XHRcdGNvbnN0IHV2Z2VuID0gb3B0aW9ucy5VVkdlbmVyYXRvciAhPT0gdW5kZWZpbmVkID8gb3B0aW9ucy5VVkdlbmVyYXRvciA6IFdvcmxkVVZHZW5lcmF0b3I7XHJcblxyXG5cdFx0XHQvL1xyXG5cclxuXHRcdFx0bGV0IGV4dHJ1ZGVQdHMsIGV4dHJ1ZGVCeVBhdGggPSBmYWxzZTtcclxuXHRcdFx0bGV0IHNwbGluZVR1YmUsIGJpbm9ybWFsLCBub3JtYWwsIHBvc2l0aW9uMjtcclxuXHJcblx0XHRcdGlmICggZXh0cnVkZVBhdGggKSB7XHJcblxyXG5cdFx0XHRcdGV4dHJ1ZGVQdHMgPSBleHRydWRlUGF0aC5nZXRTcGFjZWRQb2ludHMoIHN0ZXBzICk7XHJcblxyXG5cdFx0XHRcdGV4dHJ1ZGVCeVBhdGggPSB0cnVlO1xyXG5cdFx0XHRcdGJldmVsRW5hYmxlZCA9IGZhbHNlOyAvLyBiZXZlbHMgbm90IHN1cHBvcnRlZCBmb3IgcGF0aCBleHRydXNpb25cclxuXHJcblx0XHRcdFx0Ly8gU0VUVVAgVE5CIHZhcmlhYmxlc1xyXG5cclxuXHRcdFx0XHQvLyBUT0RPMSAtIGhhdmUgYSAuaXNDbG9zZWQgaW4gc3BsaW5lP1xyXG5cclxuXHRcdFx0XHRzcGxpbmVUdWJlID0gZXh0cnVkZVBhdGguY29tcHV0ZUZyZW5ldEZyYW1lcyggc3RlcHMsIGZhbHNlICk7XHJcblxyXG5cdFx0XHRcdC8vIGNvbnNvbGUubG9nKHNwbGluZVR1YmUsICdzcGxpbmVUdWJlJywgc3BsaW5lVHViZS5ub3JtYWxzLmxlbmd0aCwgJ3N0ZXBzJywgc3RlcHMsICdleHRydWRlUHRzJywgZXh0cnVkZVB0cy5sZW5ndGgpO1xyXG5cclxuXHRcdFx0XHRiaW5vcm1hbCA9IG5ldyBWZWN0b3IzKCk7XHJcblx0XHRcdFx0bm9ybWFsID0gbmV3IFZlY3RvcjMoKTtcclxuXHRcdFx0XHRwb3NpdGlvbjIgPSBuZXcgVmVjdG9yMygpO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Ly8gU2FmZWd1YXJkcyBpZiBiZXZlbHMgYXJlIG5vdCBlbmFibGVkXHJcblxyXG5cdFx0XHRpZiAoICEgYmV2ZWxFbmFibGVkICkge1xyXG5cclxuXHRcdFx0XHRiZXZlbFNlZ21lbnRzID0gMDtcclxuXHRcdFx0XHRiZXZlbFRoaWNrbmVzcyA9IDA7XHJcblx0XHRcdFx0YmV2ZWxTaXplID0gMDtcclxuXHRcdFx0XHRiZXZlbE9mZnNldCA9IDA7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyBWYXJpYWJsZXMgaW5pdGlhbGl6YXRpb25cclxuXHJcblx0XHRcdGNvbnN0IHNoYXBlUG9pbnRzID0gc2hhcGUuZXh0cmFjdFBvaW50cyggY3VydmVTZWdtZW50cyApO1xyXG5cclxuXHRcdFx0bGV0IHZlcnRpY2VzID0gc2hhcGVQb2ludHMuc2hhcGU7XHJcblx0XHRcdGNvbnN0IGhvbGVzID0gc2hhcGVQb2ludHMuaG9sZXM7XHJcblxyXG5cdFx0XHRjb25zdCByZXZlcnNlID0gISBTaGFwZVV0aWxzLmlzQ2xvY2tXaXNlKCB2ZXJ0aWNlcyApO1xyXG5cclxuXHRcdFx0aWYgKCByZXZlcnNlICkge1xyXG5cclxuXHRcdFx0XHR2ZXJ0aWNlcyA9IHZlcnRpY2VzLnJldmVyc2UoKTtcclxuXHJcblx0XHRcdFx0Ly8gTWF5YmUgd2Ugc2hvdWxkIGFsc28gY2hlY2sgaWYgaG9sZXMgYXJlIGluIHRoZSBvcHBvc2l0ZSBkaXJlY3Rpb24sIGp1c3QgdG8gYmUgc2FmZSAuLi5cclxuXHJcblx0XHRcdFx0Zm9yICggbGV0IGggPSAwLCBobCA9IGhvbGVzLmxlbmd0aDsgaCA8IGhsOyBoICsrICkge1xyXG5cclxuXHRcdFx0XHRcdGNvbnN0IGFob2xlID0gaG9sZXNbIGggXTtcclxuXHJcblx0XHRcdFx0XHRpZiAoIFNoYXBlVXRpbHMuaXNDbG9ja1dpc2UoIGFob2xlICkgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRob2xlc1sgaCBdID0gYWhvbGUucmV2ZXJzZSgpO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHJcblx0XHRcdGNvbnN0IGZhY2VzID0gU2hhcGVVdGlscy50cmlhbmd1bGF0ZVNoYXBlKCB2ZXJ0aWNlcywgaG9sZXMgKTtcclxuXHJcblx0XHRcdC8qIFZlcnRpY2VzICovXHJcblxyXG5cdFx0XHRjb25zdCBjb250b3VyID0gdmVydGljZXM7IC8vIHZlcnRpY2VzIGhhcyBhbGwgcG9pbnRzIGJ1dCBjb250b3VyIGhhcyBvbmx5IHBvaW50cyBvZiBjaXJjdW1mZXJlbmNlXHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaCA9IDAsIGhsID0gaG9sZXMubGVuZ3RoOyBoIDwgaGw7IGggKysgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IGFob2xlID0gaG9sZXNbIGggXTtcclxuXHJcblx0XHRcdFx0dmVydGljZXMgPSB2ZXJ0aWNlcy5jb25jYXQoIGFob2xlICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cclxuXHRcdFx0ZnVuY3Rpb24gc2NhbGVQdDIoIHB0LCB2ZWMsIHNpemUgKSB7XHJcblxyXG5cdFx0XHRcdGlmICggISB2ZWMgKSBjb25zb2xlLmVycm9yKCAnVEhSRUUuRXh0cnVkZUdlb21ldHJ5OiB2ZWMgZG9lcyBub3QgZXhpc3QnICk7XHJcblxyXG5cdFx0XHRcdHJldHVybiBwdC5jbG9uZSgpLmFkZFNjYWxlZFZlY3RvciggdmVjLCBzaXplICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRjb25zdCB2bGVuID0gdmVydGljZXMubGVuZ3RoLCBmbGVuID0gZmFjZXMubGVuZ3RoO1xyXG5cclxuXHJcblx0XHRcdC8vIEZpbmQgZGlyZWN0aW9ucyBmb3IgcG9pbnQgbW92ZW1lbnRcclxuXHJcblxyXG5cdFx0XHRmdW5jdGlvbiBnZXRCZXZlbFZlYyggaW5QdCwgaW5QcmV2LCBpbk5leHQgKSB7XHJcblxyXG5cdFx0XHRcdC8vIGNvbXB1dGVzIGZvciBpblB0IHRoZSBjb3JyZXNwb25kaW5nIHBvaW50IGluUHQnIG9uIGEgbmV3IGNvbnRvdXJcclxuXHRcdFx0XHQvLyAgIHNoaWZ0ZWQgYnkgMSB1bml0IChsZW5ndGggb2Ygbm9ybWFsaXplZCB2ZWN0b3IpIHRvIHRoZSBsZWZ0XHJcblx0XHRcdFx0Ly8gaWYgd2Ugd2FsayBhbG9uZyBjb250b3VyIGNsb2Nrd2lzZSwgdGhpcyBuZXcgY29udG91ciBpcyBvdXRzaWRlIHRoZSBvbGQgb25lXHJcblx0XHRcdFx0Ly9cclxuXHRcdFx0XHQvLyBpblB0JyBpcyB0aGUgaW50ZXJzZWN0aW9uIG9mIHRoZSB0d28gbGluZXMgcGFyYWxsZWwgdG8gdGhlIHR3b1xyXG5cdFx0XHRcdC8vICBhZGphY2VudCBlZGdlcyBvZiBpblB0IGF0IGEgZGlzdGFuY2Ugb2YgMSB1bml0IG9uIHRoZSBsZWZ0IHNpZGUuXHJcblxyXG5cdFx0XHRcdGxldCB2X3RyYW5zX3gsIHZfdHJhbnNfeSwgc2hyaW5rX2J5OyAvLyByZXN1bHRpbmcgdHJhbnNsYXRpb24gdmVjdG9yIGZvciBpblB0XHJcblxyXG5cdFx0XHRcdC8vIGdvb2QgcmVhZGluZyBmb3IgZ2VvbWV0cnkgYWxnb3JpdGhtcyAoaGVyZTogbGluZS1saW5lIGludGVyc2VjdGlvbilcclxuXHRcdFx0XHQvLyBodHRwOi8vZ2VvbWFsZ29yaXRobXMuY29tL2EwNS1faW50ZXJzZWN0LTEuaHRtbFxyXG5cclxuXHRcdFx0XHRjb25zdCB2X3ByZXZfeCA9IGluUHQueCAtIGluUHJldi54LFxyXG5cdFx0XHRcdFx0dl9wcmV2X3kgPSBpblB0LnkgLSBpblByZXYueTtcclxuXHRcdFx0XHRjb25zdCB2X25leHRfeCA9IGluTmV4dC54IC0gaW5QdC54LFxyXG5cdFx0XHRcdFx0dl9uZXh0X3kgPSBpbk5leHQueSAtIGluUHQueTtcclxuXHJcblx0XHRcdFx0Y29uc3Qgdl9wcmV2X2xlbnNxID0gKCB2X3ByZXZfeCAqIHZfcHJldl94ICsgdl9wcmV2X3kgKiB2X3ByZXZfeSApO1xyXG5cclxuXHRcdFx0XHQvLyBjaGVjayBmb3IgY29sbGluZWFyIGVkZ2VzXHJcblx0XHRcdFx0Y29uc3QgY29sbGluZWFyMCA9ICggdl9wcmV2X3ggKiB2X25leHRfeSAtIHZfcHJldl95ICogdl9uZXh0X3ggKTtcclxuXHJcblx0XHRcdFx0aWYgKCBNYXRoLmFicyggY29sbGluZWFyMCApID4gTnVtYmVyLkVQU0lMT04gKSB7XHJcblxyXG5cdFx0XHRcdFx0Ly8gbm90IGNvbGxpbmVhclxyXG5cclxuXHRcdFx0XHRcdC8vIGxlbmd0aCBvZiB2ZWN0b3JzIGZvciBub3JtYWxpemluZ1xyXG5cclxuXHRcdFx0XHRcdGNvbnN0IHZfcHJldl9sZW4gPSBNYXRoLnNxcnQoIHZfcHJldl9sZW5zcSApO1xyXG5cdFx0XHRcdFx0Y29uc3Qgdl9uZXh0X2xlbiA9IE1hdGguc3FydCggdl9uZXh0X3ggKiB2X25leHRfeCArIHZfbmV4dF95ICogdl9uZXh0X3kgKTtcclxuXHJcblx0XHRcdFx0XHQvLyBzaGlmdCBhZGphY2VudCBwb2ludHMgYnkgdW5pdCB2ZWN0b3JzIHRvIHRoZSBsZWZ0XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgcHRQcmV2U2hpZnRfeCA9ICggaW5QcmV2LnggLSB2X3ByZXZfeSAvIHZfcHJldl9sZW4gKTtcclxuXHRcdFx0XHRcdGNvbnN0IHB0UHJldlNoaWZ0X3kgPSAoIGluUHJldi55ICsgdl9wcmV2X3ggLyB2X3ByZXZfbGVuICk7XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgcHROZXh0U2hpZnRfeCA9ICggaW5OZXh0LnggLSB2X25leHRfeSAvIHZfbmV4dF9sZW4gKTtcclxuXHRcdFx0XHRcdGNvbnN0IHB0TmV4dFNoaWZ0X3kgPSAoIGluTmV4dC55ICsgdl9uZXh0X3ggLyB2X25leHRfbGVuICk7XHJcblxyXG5cdFx0XHRcdFx0Ly8gc2NhbGluZyBmYWN0b3IgZm9yIHZfcHJldiB0byBpbnRlcnNlY3Rpb24gcG9pbnRcclxuXHJcblx0XHRcdFx0XHRjb25zdCBzZiA9ICggKCBwdE5leHRTaGlmdF94IC0gcHRQcmV2U2hpZnRfeCApICogdl9uZXh0X3kgLVxyXG5cdFx0XHRcdFx0XHRcdCggcHROZXh0U2hpZnRfeSAtIHB0UHJldlNoaWZ0X3kgKSAqIHZfbmV4dF94ICkgL1xyXG5cdFx0XHRcdFx0XHQoIHZfcHJldl94ICogdl9uZXh0X3kgLSB2X3ByZXZfeSAqIHZfbmV4dF94ICk7XHJcblxyXG5cdFx0XHRcdFx0Ly8gdmVjdG9yIGZyb20gaW5QdCB0byBpbnRlcnNlY3Rpb24gcG9pbnRcclxuXHJcblx0XHRcdFx0XHR2X3RyYW5zX3ggPSAoIHB0UHJldlNoaWZ0X3ggKyB2X3ByZXZfeCAqIHNmIC0gaW5QdC54ICk7XHJcblx0XHRcdFx0XHR2X3RyYW5zX3kgPSAoIHB0UHJldlNoaWZ0X3kgKyB2X3ByZXZfeSAqIHNmIC0gaW5QdC55ICk7XHJcblxyXG5cdFx0XHRcdFx0Ly8gRG9uJ3Qgbm9ybWFsaXplISwgb3RoZXJ3aXNlIHNoYXJwIGNvcm5lcnMgYmVjb21lIHVnbHlcclxuXHRcdFx0XHRcdC8vICBidXQgcHJldmVudCBjcmF6eSBzcGlrZXNcclxuXHRcdFx0XHRcdGNvbnN0IHZfdHJhbnNfbGVuc3EgPSAoIHZfdHJhbnNfeCAqIHZfdHJhbnNfeCArIHZfdHJhbnNfeSAqIHZfdHJhbnNfeSApO1xyXG5cdFx0XHRcdFx0aWYgKCB2X3RyYW5zX2xlbnNxIDw9IDIgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRyZXR1cm4gbmV3IFZlY3RvcjIoIHZfdHJhbnNfeCwgdl90cmFuc195ICk7XHJcblxyXG5cdFx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRcdHNocmlua19ieSA9IE1hdGguc3FydCggdl90cmFuc19sZW5zcSAvIDIgKTtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0Ly8gaGFuZGxlIHNwZWNpYWwgY2FzZSBvZiBjb2xsaW5lYXIgZWRnZXNcclxuXHJcblx0XHRcdFx0XHRsZXQgZGlyZWN0aW9uX2VxID0gZmFsc2U7IC8vIGFzc3VtZXM6IG9wcG9zaXRlXHJcblxyXG5cdFx0XHRcdFx0aWYgKCB2X3ByZXZfeCA+IE51bWJlci5FUFNJTE9OICkge1xyXG5cclxuXHRcdFx0XHRcdFx0aWYgKCB2X25leHRfeCA+IE51bWJlci5FUFNJTE9OICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRkaXJlY3Rpb25fZXEgPSB0cnVlO1xyXG5cclxuXHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHRpZiAoIHZfcHJldl94IDwgLSBOdW1iZXIuRVBTSUxPTiApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0aWYgKCB2X25leHRfeCA8IC0gTnVtYmVyLkVQU0lMT04gKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0ZGlyZWN0aW9uX2VxID0gdHJ1ZTtcclxuXHJcblx0XHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0aWYgKCBNYXRoLnNpZ24oIHZfcHJldl95ICkgPT09IE1hdGguc2lnbiggdl9uZXh0X3kgKSApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHRkaXJlY3Rpb25fZXEgPSB0cnVlO1xyXG5cclxuXHRcdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdGlmICggZGlyZWN0aW9uX2VxICkge1xyXG5cclxuXHRcdFx0XHRcdFx0Ly8gY29uc29sZS5sb2coXCJXYXJuaW5nOiBsaW5lcyBhcmUgYSBzdHJhaWdodCBzZXF1ZW5jZVwiKTtcclxuXHRcdFx0XHRcdFx0dl90cmFuc194ID0gLSB2X3ByZXZfeTtcclxuXHRcdFx0XHRcdFx0dl90cmFuc195ID0gdl9wcmV2X3g7XHJcblx0XHRcdFx0XHRcdHNocmlua19ieSA9IE1hdGguc3FydCggdl9wcmV2X2xlbnNxICk7XHJcblxyXG5cdFx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRcdC8vIGNvbnNvbGUubG9nKFwiV2FybmluZzogbGluZXMgYXJlIGEgc3RyYWlnaHQgc3Bpa2VcIik7XHJcblx0XHRcdFx0XHRcdHZfdHJhbnNfeCA9IHZfcHJldl94O1xyXG5cdFx0XHRcdFx0XHR2X3RyYW5zX3kgPSB2X3ByZXZfeTtcclxuXHRcdFx0XHRcdFx0c2hyaW5rX2J5ID0gTWF0aC5zcXJ0KCB2X3ByZXZfbGVuc3EgLyAyICk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdHJldHVybiBuZXcgVmVjdG9yMiggdl90cmFuc194IC8gc2hyaW5rX2J5LCB2X3RyYW5zX3kgLyBzaHJpbmtfYnkgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblxyXG5cdFx0XHRjb25zdCBjb250b3VyTW92ZW1lbnRzID0gW107XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gY29udG91ci5sZW5ndGgsIGogPSBpbCAtIDEsIGsgPSBpICsgMTsgaSA8IGlsOyBpICsrLCBqICsrLCBrICsrICkge1xyXG5cclxuXHRcdFx0XHRpZiAoIGogPT09IGlsICkgaiA9IDA7XHJcblx0XHRcdFx0aWYgKCBrID09PSBpbCApIGsgPSAwO1xyXG5cclxuXHRcdFx0XHQvLyAgKGopLS0tKGkpLS0tKGspXHJcblx0XHRcdFx0Ly8gY29uc29sZS5sb2coJ2ksaixrJywgaSwgaiAsIGspXHJcblxyXG5cdFx0XHRcdGNvbnRvdXJNb3ZlbWVudHNbIGkgXSA9IGdldEJldmVsVmVjKCBjb250b3VyWyBpIF0sIGNvbnRvdXJbIGogXSwgY29udG91clsgayBdICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRjb25zdCBob2xlc01vdmVtZW50cyA9IFtdO1xyXG5cdFx0XHRsZXQgb25lSG9sZU1vdmVtZW50cywgdmVydGljZXNNb3ZlbWVudHMgPSBjb250b3VyTW92ZW1lbnRzLmNvbmNhdCgpO1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGggPSAwLCBobCA9IGhvbGVzLmxlbmd0aDsgaCA8IGhsOyBoICsrICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBhaG9sZSA9IGhvbGVzWyBoIF07XHJcblxyXG5cdFx0XHRcdG9uZUhvbGVNb3ZlbWVudHMgPSBbXTtcclxuXHJcblx0XHRcdFx0Zm9yICggbGV0IGkgPSAwLCBpbCA9IGFob2xlLmxlbmd0aCwgaiA9IGlsIC0gMSwgayA9IGkgKyAxOyBpIDwgaWw7IGkgKyssIGogKyssIGsgKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCBqID09PSBpbCApIGogPSAwO1xyXG5cdFx0XHRcdFx0aWYgKCBrID09PSBpbCApIGsgPSAwO1xyXG5cclxuXHRcdFx0XHRcdC8vICAoaiktLS0oaSktLS0oaylcclxuXHRcdFx0XHRcdG9uZUhvbGVNb3ZlbWVudHNbIGkgXSA9IGdldEJldmVsVmVjKCBhaG9sZVsgaSBdLCBhaG9sZVsgaiBdLCBhaG9sZVsgayBdICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0aG9sZXNNb3ZlbWVudHMucHVzaCggb25lSG9sZU1vdmVtZW50cyApO1xyXG5cdFx0XHRcdHZlcnRpY2VzTW92ZW1lbnRzID0gdmVydGljZXNNb3ZlbWVudHMuY29uY2F0KCBvbmVIb2xlTW92ZW1lbnRzICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cclxuXHRcdFx0Ly8gTG9vcCBiZXZlbFNlZ21lbnRzLCAxIGZvciB0aGUgZnJvbnQsIDEgZm9yIHRoZSBiYWNrXHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgYiA9IDA7IGIgPCBiZXZlbFNlZ21lbnRzOyBiICsrICkge1xyXG5cclxuXHRcdFx0XHQvL2ZvciAoIGIgPSBiZXZlbFNlZ21lbnRzOyBiID4gMDsgYiAtLSApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgdCA9IGIgLyBiZXZlbFNlZ21lbnRzO1xyXG5cdFx0XHRcdGNvbnN0IHogPSBiZXZlbFRoaWNrbmVzcyAqIE1hdGguY29zKCB0ICogTWF0aC5QSSAvIDIgKTtcclxuXHRcdFx0XHRjb25zdCBicyA9IGJldmVsU2l6ZSAqIE1hdGguc2luKCB0ICogTWF0aC5QSSAvIDIgKSArIGJldmVsT2Zmc2V0O1xyXG5cclxuXHRcdFx0XHQvLyBjb250cmFjdCBzaGFwZVxyXG5cclxuXHRcdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gY29udG91ci5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0XHRjb25zdCB2ZXJ0ID0gc2NhbGVQdDIoIGNvbnRvdXJbIGkgXSwgY29udG91ck1vdmVtZW50c1sgaSBdLCBicyApO1xyXG5cclxuXHRcdFx0XHRcdHYoIHZlcnQueCwgdmVydC55LCAtIHogKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHQvLyBleHBhbmQgaG9sZXNcclxuXHJcblx0XHRcdFx0Zm9yICggbGV0IGggPSAwLCBobCA9IGhvbGVzLmxlbmd0aDsgaCA8IGhsOyBoICsrICkge1xyXG5cclxuXHRcdFx0XHRcdGNvbnN0IGFob2xlID0gaG9sZXNbIGggXTtcclxuXHRcdFx0XHRcdG9uZUhvbGVNb3ZlbWVudHMgPSBob2xlc01vdmVtZW50c1sgaCBdO1xyXG5cclxuXHRcdFx0XHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSBhaG9sZS5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0XHRcdGNvbnN0IHZlcnQgPSBzY2FsZVB0MiggYWhvbGVbIGkgXSwgb25lSG9sZU1vdmVtZW50c1sgaSBdLCBicyApO1xyXG5cclxuXHRcdFx0XHRcdFx0diggdmVydC54LCB2ZXJ0LnksIC0geiApO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Y29uc3QgYnMgPSBiZXZlbFNpemUgKyBiZXZlbE9mZnNldDtcclxuXHJcblx0XHRcdC8vIEJhY2sgZmFjaW5nIHZlcnRpY2VzXHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCB2bGVuOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCB2ZXJ0ID0gYmV2ZWxFbmFibGVkID8gc2NhbGVQdDIoIHZlcnRpY2VzWyBpIF0sIHZlcnRpY2VzTW92ZW1lbnRzWyBpIF0sIGJzICkgOiB2ZXJ0aWNlc1sgaSBdO1xyXG5cclxuXHRcdFx0XHRpZiAoICEgZXh0cnVkZUJ5UGF0aCApIHtcclxuXHJcblx0XHRcdFx0XHR2KCB2ZXJ0LngsIHZlcnQueSwgMCApO1xyXG5cclxuXHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdC8vIHYoIHZlcnQueCwgdmVydC55ICsgZXh0cnVkZVB0c1sgMCBdLnksIGV4dHJ1ZGVQdHNbIDAgXS54ICk7XHJcblxyXG5cdFx0XHRcdFx0bm9ybWFsLmNvcHkoIHNwbGluZVR1YmUubm9ybWFsc1sgMCBdICkubXVsdGlwbHlTY2FsYXIoIHZlcnQueCApO1xyXG5cdFx0XHRcdFx0Ymlub3JtYWwuY29weSggc3BsaW5lVHViZS5iaW5vcm1hbHNbIDAgXSApLm11bHRpcGx5U2NhbGFyKCB2ZXJ0LnkgKTtcclxuXHJcblx0XHRcdFx0XHRwb3NpdGlvbjIuY29weSggZXh0cnVkZVB0c1sgMCBdICkuYWRkKCBub3JtYWwgKS5hZGQoIGJpbm9ybWFsICk7XHJcblxyXG5cdFx0XHRcdFx0diggcG9zaXRpb24yLngsIHBvc2l0aW9uMi55LCBwb3NpdGlvbjIueiApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyBBZGQgc3RlcHBlZCB2ZXJ0aWNlcy4uLlxyXG5cdFx0XHQvLyBJbmNsdWRpbmcgZnJvbnQgZmFjaW5nIHZlcnRpY2VzXHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgcyA9IDE7IHMgPD0gc3RlcHM7IHMgKysgKSB7XHJcblxyXG5cdFx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHZsZW47IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgdmVydCA9IGJldmVsRW5hYmxlZCA/IHNjYWxlUHQyKCB2ZXJ0aWNlc1sgaSBdLCB2ZXJ0aWNlc01vdmVtZW50c1sgaSBdLCBicyApIDogdmVydGljZXNbIGkgXTtcclxuXHJcblx0XHRcdFx0XHRpZiAoICEgZXh0cnVkZUJ5UGF0aCApIHtcclxuXHJcblx0XHRcdFx0XHRcdHYoIHZlcnQueCwgdmVydC55LCBkZXB0aCAvIHN0ZXBzICogcyApO1xyXG5cclxuXHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHQvLyB2KCB2ZXJ0LngsIHZlcnQueSArIGV4dHJ1ZGVQdHNbIHMgLSAxIF0ueSwgZXh0cnVkZVB0c1sgcyAtIDEgXS54ICk7XHJcblxyXG5cdFx0XHRcdFx0XHRub3JtYWwuY29weSggc3BsaW5lVHViZS5ub3JtYWxzWyBzIF0gKS5tdWx0aXBseVNjYWxhciggdmVydC54ICk7XHJcblx0XHRcdFx0XHRcdGJpbm9ybWFsLmNvcHkoIHNwbGluZVR1YmUuYmlub3JtYWxzWyBzIF0gKS5tdWx0aXBseVNjYWxhciggdmVydC55ICk7XHJcblxyXG5cdFx0XHRcdFx0XHRwb3NpdGlvbjIuY29weSggZXh0cnVkZVB0c1sgcyBdICkuYWRkKCBub3JtYWwgKS5hZGQoIGJpbm9ybWFsICk7XHJcblxyXG5cdFx0XHRcdFx0XHR2KCBwb3NpdGlvbjIueCwgcG9zaXRpb24yLnksIHBvc2l0aW9uMi56ICk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cclxuXHRcdFx0Ly8gQWRkIGJldmVsIHNlZ21lbnRzIHBsYW5lc1xyXG5cclxuXHRcdFx0Ly9mb3IgKCBiID0gMTsgYiA8PSBiZXZlbFNlZ21lbnRzOyBiICsrICkge1xyXG5cdFx0XHRmb3IgKCBsZXQgYiA9IGJldmVsU2VnbWVudHMgLSAxOyBiID49IDA7IGIgLS0gKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IHQgPSBiIC8gYmV2ZWxTZWdtZW50cztcclxuXHRcdFx0XHRjb25zdCB6ID0gYmV2ZWxUaGlja25lc3MgKiBNYXRoLmNvcyggdCAqIE1hdGguUEkgLyAyICk7XHJcblx0XHRcdFx0Y29uc3QgYnMgPSBiZXZlbFNpemUgKiBNYXRoLnNpbiggdCAqIE1hdGguUEkgLyAyICkgKyBiZXZlbE9mZnNldDtcclxuXHJcblx0XHRcdFx0Ly8gY29udHJhY3Qgc2hhcGVcclxuXHJcblx0XHRcdFx0Zm9yICggbGV0IGkgPSAwLCBpbCA9IGNvbnRvdXIubGVuZ3RoOyBpIDwgaWw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgdmVydCA9IHNjYWxlUHQyKCBjb250b3VyWyBpIF0sIGNvbnRvdXJNb3ZlbWVudHNbIGkgXSwgYnMgKTtcclxuXHRcdFx0XHRcdHYoIHZlcnQueCwgdmVydC55LCBkZXB0aCArIHogKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHQvLyBleHBhbmQgaG9sZXNcclxuXHJcblx0XHRcdFx0Zm9yICggbGV0IGggPSAwLCBobCA9IGhvbGVzLmxlbmd0aDsgaCA8IGhsOyBoICsrICkge1xyXG5cclxuXHRcdFx0XHRcdGNvbnN0IGFob2xlID0gaG9sZXNbIGggXTtcclxuXHRcdFx0XHRcdG9uZUhvbGVNb3ZlbWVudHMgPSBob2xlc01vdmVtZW50c1sgaCBdO1xyXG5cclxuXHRcdFx0XHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSBhaG9sZS5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0XHRcdGNvbnN0IHZlcnQgPSBzY2FsZVB0MiggYWhvbGVbIGkgXSwgb25lSG9sZU1vdmVtZW50c1sgaSBdLCBicyApO1xyXG5cclxuXHRcdFx0XHRcdFx0aWYgKCAhIGV4dHJ1ZGVCeVBhdGggKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdHYoIHZlcnQueCwgdmVydC55LCBkZXB0aCArIHogKTtcclxuXHJcblx0XHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdHYoIHZlcnQueCwgdmVydC55ICsgZXh0cnVkZVB0c1sgc3RlcHMgLSAxIF0ueSwgZXh0cnVkZVB0c1sgc3RlcHMgLSAxIF0ueCArIHogKTtcclxuXHJcblx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdC8qIEZhY2VzICovXHJcblxyXG5cdFx0XHQvLyBUb3AgYW5kIGJvdHRvbSBmYWNlc1xyXG5cclxuXHRcdFx0YnVpbGRMaWRGYWNlcygpO1xyXG5cclxuXHRcdFx0Ly8gU2lkZXMgZmFjZXNcclxuXHJcblx0XHRcdGJ1aWxkU2lkZUZhY2VzKCk7XHJcblxyXG5cclxuXHRcdFx0Ly8vLy8gIEludGVybmFsIGZ1bmN0aW9uc1xyXG5cclxuXHRcdFx0ZnVuY3Rpb24gYnVpbGRMaWRGYWNlcygpIHtcclxuXHJcblx0XHRcdFx0Y29uc3Qgc3RhcnQgPSB2ZXJ0aWNlc0FycmF5Lmxlbmd0aCAvIDM7XHJcblxyXG5cdFx0XHRcdGlmICggYmV2ZWxFbmFibGVkICkge1xyXG5cclxuXHRcdFx0XHRcdGxldCBsYXllciA9IDA7IC8vIHN0ZXBzICsgMVxyXG5cdFx0XHRcdFx0bGV0IG9mZnNldCA9IHZsZW4gKiBsYXllcjtcclxuXHJcblx0XHRcdFx0XHQvLyBCb3R0b20gZmFjZXNcclxuXHJcblx0XHRcdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBmbGVuOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRcdFx0Y29uc3QgZmFjZSA9IGZhY2VzWyBpIF07XHJcblx0XHRcdFx0XHRcdGYzKCBmYWNlWyAyIF0gKyBvZmZzZXQsIGZhY2VbIDEgXSArIG9mZnNldCwgZmFjZVsgMCBdICsgb2Zmc2V0ICk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdGxheWVyID0gc3RlcHMgKyBiZXZlbFNlZ21lbnRzICogMjtcclxuXHRcdFx0XHRcdG9mZnNldCA9IHZsZW4gKiBsYXllcjtcclxuXHJcblx0XHRcdFx0XHQvLyBUb3AgZmFjZXNcclxuXHJcblx0XHRcdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBmbGVuOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRcdFx0Y29uc3QgZmFjZSA9IGZhY2VzWyBpIF07XHJcblx0XHRcdFx0XHRcdGYzKCBmYWNlWyAwIF0gKyBvZmZzZXQsIGZhY2VbIDEgXSArIG9mZnNldCwgZmFjZVsgMiBdICsgb2Zmc2V0ICk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdC8vIEJvdHRvbSBmYWNlc1xyXG5cclxuXHRcdFx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IGZsZW47IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRjb25zdCBmYWNlID0gZmFjZXNbIGkgXTtcclxuXHRcdFx0XHRcdFx0ZjMoIGZhY2VbIDIgXSwgZmFjZVsgMSBdLCBmYWNlWyAwIF0gKTtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0Ly8gVG9wIGZhY2VzXHJcblxyXG5cdFx0XHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgZmxlbjsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0XHRcdGNvbnN0IGZhY2UgPSBmYWNlc1sgaSBdO1xyXG5cdFx0XHRcdFx0XHRmMyggZmFjZVsgMCBdICsgdmxlbiAqIHN0ZXBzLCBmYWNlWyAxIF0gKyB2bGVuICogc3RlcHMsIGZhY2VbIDIgXSArIHZsZW4gKiBzdGVwcyApO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRzY29wZS5hZGRHcm91cCggc3RhcnQsIHZlcnRpY2VzQXJyYXkubGVuZ3RoIC8gMyAtIHN0YXJ0LCAwICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyBDcmVhdGUgZmFjZXMgZm9yIHRoZSB6LXNpZGVzIG9mIHRoZSBzaGFwZVxyXG5cclxuXHRcdFx0ZnVuY3Rpb24gYnVpbGRTaWRlRmFjZXMoKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IHN0YXJ0ID0gdmVydGljZXNBcnJheS5sZW5ndGggLyAzO1xyXG5cdFx0XHRcdGxldCBsYXllcm9mZnNldCA9IDA7XHJcblx0XHRcdFx0c2lkZXdhbGxzKCBjb250b3VyLCBsYXllcm9mZnNldCApO1xyXG5cdFx0XHRcdGxheWVyb2Zmc2V0ICs9IGNvbnRvdXIubGVuZ3RoO1xyXG5cclxuXHRcdFx0XHRmb3IgKCBsZXQgaCA9IDAsIGhsID0gaG9sZXMubGVuZ3RoOyBoIDwgaGw7IGggKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgYWhvbGUgPSBob2xlc1sgaCBdO1xyXG5cdFx0XHRcdFx0c2lkZXdhbGxzKCBhaG9sZSwgbGF5ZXJvZmZzZXQgKTtcclxuXHJcblx0XHRcdFx0XHQvLywgdHJ1ZVxyXG5cdFx0XHRcdFx0bGF5ZXJvZmZzZXQgKz0gYWhvbGUubGVuZ3RoO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cclxuXHRcdFx0XHRzY29wZS5hZGRHcm91cCggc3RhcnQsIHZlcnRpY2VzQXJyYXkubGVuZ3RoIC8gMyAtIHN0YXJ0LCAxICk7XHJcblxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0ZnVuY3Rpb24gc2lkZXdhbGxzKCBjb250b3VyLCBsYXllcm9mZnNldCApIHtcclxuXHJcblx0XHRcdFx0bGV0IGkgPSBjb250b3VyLmxlbmd0aDtcclxuXHJcblx0XHRcdFx0d2hpbGUgKCAtLSBpID49IDAgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgaiA9IGk7XHJcblx0XHRcdFx0XHRsZXQgayA9IGkgLSAxO1xyXG5cdFx0XHRcdFx0aWYgKCBrIDwgMCApIGsgPSBjb250b3VyLmxlbmd0aCAtIDE7XHJcblxyXG5cdFx0XHRcdFx0Ly9jb25zb2xlLmxvZygnYicsIGksaiwgaS0xLCBrLHZlcnRpY2VzLmxlbmd0aCk7XHJcblxyXG5cdFx0XHRcdFx0Zm9yICggbGV0IHMgPSAwLCBzbCA9ICggc3RlcHMgKyBiZXZlbFNlZ21lbnRzICogMiApOyBzIDwgc2w7IHMgKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRjb25zdCBzbGVuMSA9IHZsZW4gKiBzO1xyXG5cdFx0XHRcdFx0XHRjb25zdCBzbGVuMiA9IHZsZW4gKiAoIHMgKyAxICk7XHJcblxyXG5cdFx0XHRcdFx0XHRjb25zdCBhID0gbGF5ZXJvZmZzZXQgKyBqICsgc2xlbjEsXHJcblx0XHRcdFx0XHRcdFx0YiA9IGxheWVyb2Zmc2V0ICsgayArIHNsZW4xLFxyXG5cdFx0XHRcdFx0XHRcdGMgPSBsYXllcm9mZnNldCArIGsgKyBzbGVuMixcclxuXHRcdFx0XHRcdFx0XHRkID0gbGF5ZXJvZmZzZXQgKyBqICsgc2xlbjI7XHJcblxyXG5cdFx0XHRcdFx0XHRmNCggYSwgYiwgYywgZCApO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0ZnVuY3Rpb24gdiggeCwgeSwgeiApIHtcclxuXHJcblx0XHRcdFx0cGxhY2Vob2xkZXIucHVzaCggeCApO1xyXG5cdFx0XHRcdHBsYWNlaG9sZGVyLnB1c2goIHkgKTtcclxuXHRcdFx0XHRwbGFjZWhvbGRlci5wdXNoKCB6ICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cclxuXHRcdFx0ZnVuY3Rpb24gZjMoIGEsIGIsIGMgKSB7XHJcblxyXG5cdFx0XHRcdGFkZFZlcnRleCggYSApO1xyXG5cdFx0XHRcdGFkZFZlcnRleCggYiApO1xyXG5cdFx0XHRcdGFkZFZlcnRleCggYyApO1xyXG5cclxuXHRcdFx0XHRjb25zdCBuZXh0SW5kZXggPSB2ZXJ0aWNlc0FycmF5Lmxlbmd0aCAvIDM7XHJcblx0XHRcdFx0Y29uc3QgdXZzID0gdXZnZW4uZ2VuZXJhdGVUb3BVViggc2NvcGUsIHZlcnRpY2VzQXJyYXksIG5leHRJbmRleCAtIDMsIG5leHRJbmRleCAtIDIsIG5leHRJbmRleCAtIDEgKTtcclxuXHJcblx0XHRcdFx0YWRkVVYoIHV2c1sgMCBdICk7XHJcblx0XHRcdFx0YWRkVVYoIHV2c1sgMSBdICk7XHJcblx0XHRcdFx0YWRkVVYoIHV2c1sgMiBdICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRmdW5jdGlvbiBmNCggYSwgYiwgYywgZCApIHtcclxuXHJcblx0XHRcdFx0YWRkVmVydGV4KCBhICk7XHJcblx0XHRcdFx0YWRkVmVydGV4KCBiICk7XHJcblx0XHRcdFx0YWRkVmVydGV4KCBkICk7XHJcblxyXG5cdFx0XHRcdGFkZFZlcnRleCggYiApO1xyXG5cdFx0XHRcdGFkZFZlcnRleCggYyApO1xyXG5cdFx0XHRcdGFkZFZlcnRleCggZCApO1xyXG5cclxuXHJcblx0XHRcdFx0Y29uc3QgbmV4dEluZGV4ID0gdmVydGljZXNBcnJheS5sZW5ndGggLyAzO1xyXG5cdFx0XHRcdGNvbnN0IHV2cyA9IHV2Z2VuLmdlbmVyYXRlU2lkZVdhbGxVViggc2NvcGUsIHZlcnRpY2VzQXJyYXksIG5leHRJbmRleCAtIDYsIG5leHRJbmRleCAtIDMsIG5leHRJbmRleCAtIDIsIG5leHRJbmRleCAtIDEgKTtcclxuXHJcblx0XHRcdFx0YWRkVVYoIHV2c1sgMCBdICk7XHJcblx0XHRcdFx0YWRkVVYoIHV2c1sgMSBdICk7XHJcblx0XHRcdFx0YWRkVVYoIHV2c1sgMyBdICk7XHJcblxyXG5cdFx0XHRcdGFkZFVWKCB1dnNbIDEgXSApO1xyXG5cdFx0XHRcdGFkZFVWKCB1dnNbIDIgXSApO1xyXG5cdFx0XHRcdGFkZFVWKCB1dnNbIDMgXSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0ZnVuY3Rpb24gYWRkVmVydGV4KCBpbmRleCApIHtcclxuXHJcblx0XHRcdFx0dmVydGljZXNBcnJheS5wdXNoKCBwbGFjZWhvbGRlclsgaW5kZXggKiAzICsgMCBdICk7XHJcblx0XHRcdFx0dmVydGljZXNBcnJheS5wdXNoKCBwbGFjZWhvbGRlclsgaW5kZXggKiAzICsgMSBdICk7XHJcblx0XHRcdFx0dmVydGljZXNBcnJheS5wdXNoKCBwbGFjZWhvbGRlclsgaW5kZXggKiAzICsgMiBdICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cclxuXHRcdFx0ZnVuY3Rpb24gYWRkVVYoIHZlY3RvcjIgKSB7XHJcblxyXG5cdFx0XHRcdHV2QXJyYXkucHVzaCggdmVjdG9yMi54ICk7XHJcblx0XHRcdFx0dXZBcnJheS5wdXNoKCB2ZWN0b3IyLnkgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xyXG5cclxuXHRcdHRoaXMucGFyYW1ldGVycyA9IE9iamVjdC5hc3NpZ24oIHt9LCBzb3VyY2UucGFyYW1ldGVycyApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHRvSlNPTigpIHtcclxuXHJcblx0XHRjb25zdCBkYXRhID0gc3VwZXIudG9KU09OKCk7XHJcblxyXG5cdFx0Y29uc3Qgc2hhcGVzID0gdGhpcy5wYXJhbWV0ZXJzLnNoYXBlcztcclxuXHRcdGNvbnN0IG9wdGlvbnMgPSB0aGlzLnBhcmFtZXRlcnMub3B0aW9ucztcclxuXHJcblx0XHRyZXR1cm4gdG9KU09OKCBzaGFwZXMsIG9wdGlvbnMsIGRhdGEgKTtcclxuXHJcblx0fVxyXG5cclxuXHRzdGF0aWMgZnJvbUpTT04oIGRhdGEsIHNoYXBlcyApIHtcclxuXHJcblx0XHRjb25zdCBnZW9tZXRyeVNoYXBlcyA9IFtdO1xyXG5cclxuXHRcdGZvciAoIGxldCBqID0gMCwgamwgPSBkYXRhLnNoYXBlcy5sZW5ndGg7IGogPCBqbDsgaiArKyApIHtcclxuXHJcblx0XHRcdGNvbnN0IHNoYXBlID0gc2hhcGVzWyBkYXRhLnNoYXBlc1sgaiBdIF07XHJcblxyXG5cdFx0XHRnZW9tZXRyeVNoYXBlcy5wdXNoKCBzaGFwZSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCBleHRydWRlUGF0aCA9IGRhdGEub3B0aW9ucy5leHRydWRlUGF0aDtcclxuXHJcblx0XHRpZiAoIGV4dHJ1ZGVQYXRoICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRkYXRhLm9wdGlvbnMuZXh0cnVkZVBhdGggPSBuZXcgQ3VydmVzWyBleHRydWRlUGF0aC50eXBlIF0oKS5mcm9tSlNPTiggZXh0cnVkZVBhdGggKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIG5ldyBFeHRydWRlR2VvbWV0cnkoIGdlb21ldHJ5U2hhcGVzLCBkYXRhLm9wdGlvbnMgKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuY29uc3QgV29ybGRVVkdlbmVyYXRvciA9IHtcclxuXHJcblx0Z2VuZXJhdGVUb3BVVjogZnVuY3Rpb24gKCBnZW9tZXRyeSwgdmVydGljZXMsIGluZGV4QSwgaW5kZXhCLCBpbmRleEMgKSB7XHJcblxyXG5cdFx0Y29uc3QgYV94ID0gdmVydGljZXNbIGluZGV4QSAqIDMgXTtcclxuXHRcdGNvbnN0IGFfeSA9IHZlcnRpY2VzWyBpbmRleEEgKiAzICsgMSBdO1xyXG5cdFx0Y29uc3QgYl94ID0gdmVydGljZXNbIGluZGV4QiAqIDMgXTtcclxuXHRcdGNvbnN0IGJfeSA9IHZlcnRpY2VzWyBpbmRleEIgKiAzICsgMSBdO1xyXG5cdFx0Y29uc3QgY194ID0gdmVydGljZXNbIGluZGV4QyAqIDMgXTtcclxuXHRcdGNvbnN0IGNfeSA9IHZlcnRpY2VzWyBpbmRleEMgKiAzICsgMSBdO1xyXG5cclxuXHRcdHJldHVybiBbXHJcblx0XHRcdG5ldyBWZWN0b3IyKCBhX3gsIGFfeSApLFxyXG5cdFx0XHRuZXcgVmVjdG9yMiggYl94LCBiX3kgKSxcclxuXHRcdFx0bmV3IFZlY3RvcjIoIGNfeCwgY195IClcclxuXHRcdF07XHJcblxyXG5cdH0sXHJcblxyXG5cdGdlbmVyYXRlU2lkZVdhbGxVVjogZnVuY3Rpb24gKCBnZW9tZXRyeSwgdmVydGljZXMsIGluZGV4QSwgaW5kZXhCLCBpbmRleEMsIGluZGV4RCApIHtcclxuXHJcblx0XHRjb25zdCBhX3ggPSB2ZXJ0aWNlc1sgaW5kZXhBICogMyBdO1xyXG5cdFx0Y29uc3QgYV95ID0gdmVydGljZXNbIGluZGV4QSAqIDMgKyAxIF07XHJcblx0XHRjb25zdCBhX3ogPSB2ZXJ0aWNlc1sgaW5kZXhBICogMyArIDIgXTtcclxuXHRcdGNvbnN0IGJfeCA9IHZlcnRpY2VzWyBpbmRleEIgKiAzIF07XHJcblx0XHRjb25zdCBiX3kgPSB2ZXJ0aWNlc1sgaW5kZXhCICogMyArIDEgXTtcclxuXHRcdGNvbnN0IGJfeiA9IHZlcnRpY2VzWyBpbmRleEIgKiAzICsgMiBdO1xyXG5cdFx0Y29uc3QgY194ID0gdmVydGljZXNbIGluZGV4QyAqIDMgXTtcclxuXHRcdGNvbnN0IGNfeSA9IHZlcnRpY2VzWyBpbmRleEMgKiAzICsgMSBdO1xyXG5cdFx0Y29uc3QgY196ID0gdmVydGljZXNbIGluZGV4QyAqIDMgKyAyIF07XHJcblx0XHRjb25zdCBkX3ggPSB2ZXJ0aWNlc1sgaW5kZXhEICogMyBdO1xyXG5cdFx0Y29uc3QgZF95ID0gdmVydGljZXNbIGluZGV4RCAqIDMgKyAxIF07XHJcblx0XHRjb25zdCBkX3ogPSB2ZXJ0aWNlc1sgaW5kZXhEICogMyArIDIgXTtcclxuXHJcblx0XHRpZiAoIE1hdGguYWJzKCBhX3kgLSBiX3kgKSA8IE1hdGguYWJzKCBhX3ggLSBiX3ggKSApIHtcclxuXHJcblx0XHRcdHJldHVybiBbXHJcblx0XHRcdFx0bmV3IFZlY3RvcjIoIGFfeCwgMSAtIGFfeiApLFxyXG5cdFx0XHRcdG5ldyBWZWN0b3IyKCBiX3gsIDEgLSBiX3ogKSxcclxuXHRcdFx0XHRuZXcgVmVjdG9yMiggY194LCAxIC0gY196ICksXHJcblx0XHRcdFx0bmV3IFZlY3RvcjIoIGRfeCwgMSAtIGRfeiApXHJcblx0XHRcdF07XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdHJldHVybiBbXHJcblx0XHRcdFx0bmV3IFZlY3RvcjIoIGFfeSwgMSAtIGFfeiApLFxyXG5cdFx0XHRcdG5ldyBWZWN0b3IyKCBiX3ksIDEgLSBiX3ogKSxcclxuXHRcdFx0XHRuZXcgVmVjdG9yMiggY195LCAxIC0gY196ICksXHJcblx0XHRcdFx0bmV3IFZlY3RvcjIoIGRfeSwgMSAtIGRfeiApXHJcblx0XHRcdF07XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG59O1xyXG5cclxuZnVuY3Rpb24gdG9KU09OKCBzaGFwZXMsIG9wdGlvbnMsIGRhdGEgKSB7XHJcblxyXG5cdGRhdGEuc2hhcGVzID0gW107XHJcblxyXG5cdGlmICggQXJyYXkuaXNBcnJheSggc2hhcGVzICkgKSB7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gc2hhcGVzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBzaGFwZSA9IHNoYXBlc1sgaSBdO1xyXG5cclxuXHRcdFx0ZGF0YS5zaGFwZXMucHVzaCggc2hhcGUudXVpZCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fSBlbHNlIHtcclxuXHJcblx0XHRkYXRhLnNoYXBlcy5wdXNoKCBzaGFwZXMudXVpZCApO1xyXG5cclxuXHR9XHJcblxyXG5cdGRhdGEub3B0aW9ucyA9IE9iamVjdC5hc3NpZ24oIHt9LCBvcHRpb25zICk7XHJcblxyXG5cdGlmICggb3B0aW9ucy5leHRydWRlUGF0aCAhPT0gdW5kZWZpbmVkICkgZGF0YS5vcHRpb25zLmV4dHJ1ZGVQYXRoID0gb3B0aW9ucy5leHRydWRlUGF0aC50b0pTT04oKTtcclxuXHJcblx0cmV0dXJuIGRhdGE7XHJcblxyXG59XHJcblxyXG5cclxuZXhwb3J0IHsgRXh0cnVkZUdlb21ldHJ5IH07XHJcbiIsImltcG9ydCB7IFBvbHloZWRyb25HZW9tZXRyeSB9IGZyb20gJy4vUG9seWhlZHJvbkdlb21ldHJ5LmpzJztcclxuXHJcbmNsYXNzIEljb3NhaGVkcm9uR2VvbWV0cnkgZXh0ZW5kcyBQb2x5aGVkcm9uR2VvbWV0cnkge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggcmFkaXVzID0gMSwgZGV0YWlsID0gMCApIHtcclxuXHJcblx0XHRjb25zdCB0ID0gKCAxICsgTWF0aC5zcXJ0KCA1ICkgKSAvIDI7XHJcblxyXG5cdFx0Y29uc3QgdmVydGljZXMgPSBbXHJcblx0XHRcdC0gMSwgdCwgMCwgXHQxLCB0LCAwLCBcdC0gMSwgLSB0LCAwLCBcdDEsIC0gdCwgMCxcclxuXHRcdFx0MCwgLSAxLCB0LCBcdDAsIDEsIHQsXHQwLCAtIDEsIC0gdCwgXHQwLCAxLCAtIHQsXHJcblx0XHRcdHQsIDAsIC0gMSwgXHR0LCAwLCAxLCBcdC0gdCwgMCwgLSAxLCBcdC0gdCwgMCwgMVxyXG5cdFx0XTtcclxuXHJcblx0XHRjb25zdCBpbmRpY2VzID0gW1xyXG5cdFx0XHQwLCAxMSwgNSwgXHQwLCA1LCAxLCBcdDAsIDEsIDcsIFx0MCwgNywgMTAsIFx0MCwgMTAsIDExLFxyXG5cdFx0XHQxLCA1LCA5LCBcdDUsIDExLCA0LFx0MTEsIDEwLCAyLFx0MTAsIDcsIDYsXHQ3LCAxLCA4LFxyXG5cdFx0XHQzLCA5LCA0LCBcdDMsIDQsIDIsXHQzLCAyLCA2LFx0MywgNiwgOCxcdDMsIDgsIDksXHJcblx0XHRcdDQsIDksIDUsIFx0MiwgNCwgMTEsXHQ2LCAyLCAxMCxcdDgsIDYsIDcsXHQ5LCA4LCAxXHJcblx0XHRdO1xyXG5cclxuXHRcdHN1cGVyKCB2ZXJ0aWNlcywgaW5kaWNlcywgcmFkaXVzLCBkZXRhaWwgKTtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSAnSWNvc2FoZWRyb25HZW9tZXRyeSc7XHJcblxyXG5cdFx0dGhpcy5wYXJhbWV0ZXJzID0ge1xyXG5cdFx0XHRyYWRpdXM6IHJhZGl1cyxcclxuXHRcdFx0ZGV0YWlsOiBkZXRhaWxcclxuXHRcdH07XHJcblxyXG5cdH1cclxuXHJcblx0c3RhdGljIGZyb21KU09OKCBkYXRhICkge1xyXG5cclxuXHRcdHJldHVybiBuZXcgSWNvc2FoZWRyb25HZW9tZXRyeSggZGF0YS5yYWRpdXMsIGRhdGEuZGV0YWlsICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcblxyXG5leHBvcnQgeyBJY29zYWhlZHJvbkdlb21ldHJ5IH07XHJcbiIsImltcG9ydCB7IFBvbHloZWRyb25HZW9tZXRyeSB9IGZyb20gJy4vUG9seWhlZHJvbkdlb21ldHJ5LmpzJztcclxuXHJcbmNsYXNzIE9jdGFoZWRyb25HZW9tZXRyeSBleHRlbmRzIFBvbHloZWRyb25HZW9tZXRyeSB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCByYWRpdXMgPSAxLCBkZXRhaWwgPSAwICkge1xyXG5cclxuXHRcdGNvbnN0IHZlcnRpY2VzID0gW1xyXG5cdFx0XHQxLCAwLCAwLCBcdC0gMSwgMCwgMCxcdDAsIDEsIDAsXHJcblx0XHRcdDAsIC0gMSwgMCwgXHQwLCAwLCAxLFx0MCwgMCwgLSAxXHJcblx0XHRdO1xyXG5cclxuXHRcdGNvbnN0IGluZGljZXMgPSBbXHJcblx0XHRcdDAsIDIsIDQsXHQwLCA0LCAzLFx0MCwgMywgNSxcclxuXHRcdFx0MCwgNSwgMixcdDEsIDIsIDUsXHQxLCA1LCAzLFxyXG5cdFx0XHQxLCAzLCA0LFx0MSwgNCwgMlxyXG5cdFx0XTtcclxuXHJcblx0XHRzdXBlciggdmVydGljZXMsIGluZGljZXMsIHJhZGl1cywgZGV0YWlsICk7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ09jdGFoZWRyb25HZW9tZXRyeSc7XHJcblxyXG5cdFx0dGhpcy5wYXJhbWV0ZXJzID0ge1xyXG5cdFx0XHRyYWRpdXM6IHJhZGl1cyxcclxuXHRcdFx0ZGV0YWlsOiBkZXRhaWxcclxuXHRcdH07XHJcblxyXG5cdH1cclxuXHJcblx0c3RhdGljIGZyb21KU09OKCBkYXRhICkge1xyXG5cclxuXHRcdHJldHVybiBuZXcgT2N0YWhlZHJvbkdlb21ldHJ5KCBkYXRhLnJhZGl1cywgZGF0YS5kZXRhaWwgKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgT2N0YWhlZHJvbkdlb21ldHJ5IH07XHJcbiIsImltcG9ydCB7IEJ1ZmZlckdlb21ldHJ5IH0gZnJvbSAnLi4vY29yZS9CdWZmZXJHZW9tZXRyeS5qcyc7XHJcbmltcG9ydCB7IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUgfSBmcm9tICcuLi9jb3JlL0J1ZmZlckF0dHJpYnV0ZS5qcyc7XHJcbmltcG9ydCB7IFZlY3RvcjIgfSBmcm9tICcuLi9tYXRoL1ZlY3RvcjIuanMnO1xyXG5pbXBvcnQgeyBWZWN0b3IzIH0gZnJvbSAnLi4vbWF0aC9WZWN0b3IzLmpzJztcclxuXHJcbmNsYXNzIFJpbmdHZW9tZXRyeSBleHRlbmRzIEJ1ZmZlckdlb21ldHJ5IHtcclxuXHJcblx0Y29uc3RydWN0b3IoIGlubmVyUmFkaXVzID0gMC41LCBvdXRlclJhZGl1cyA9IDEsIHRoZXRhU2VnbWVudHMgPSAzMiwgcGhpU2VnbWVudHMgPSAxLCB0aGV0YVN0YXJ0ID0gMCwgdGhldGFMZW5ndGggPSBNYXRoLlBJICogMiApIHtcclxuXHJcblx0XHRzdXBlcigpO1xyXG5cclxuXHRcdHRoaXMudHlwZSA9ICdSaW5nR2VvbWV0cnknO1xyXG5cclxuXHRcdHRoaXMucGFyYW1ldGVycyA9IHtcclxuXHRcdFx0aW5uZXJSYWRpdXM6IGlubmVyUmFkaXVzLFxyXG5cdFx0XHRvdXRlclJhZGl1czogb3V0ZXJSYWRpdXMsXHJcblx0XHRcdHRoZXRhU2VnbWVudHM6IHRoZXRhU2VnbWVudHMsXHJcblx0XHRcdHBoaVNlZ21lbnRzOiBwaGlTZWdtZW50cyxcclxuXHRcdFx0dGhldGFTdGFydDogdGhldGFTdGFydCxcclxuXHRcdFx0dGhldGFMZW5ndGg6IHRoZXRhTGVuZ3RoXHJcblx0XHR9O1xyXG5cclxuXHRcdHRoZXRhU2VnbWVudHMgPSBNYXRoLm1heCggMywgdGhldGFTZWdtZW50cyApO1xyXG5cdFx0cGhpU2VnbWVudHMgPSBNYXRoLm1heCggMSwgcGhpU2VnbWVudHMgKTtcclxuXHJcblx0XHQvLyBidWZmZXJzXHJcblxyXG5cdFx0Y29uc3QgaW5kaWNlcyA9IFtdO1xyXG5cdFx0Y29uc3QgdmVydGljZXMgPSBbXTtcclxuXHRcdGNvbnN0IG5vcm1hbHMgPSBbXTtcclxuXHRcdGNvbnN0IHV2cyA9IFtdO1xyXG5cclxuXHRcdC8vIHNvbWUgaGVscGVyIHZhcmlhYmxlc1xyXG5cclxuXHRcdGxldCByYWRpdXMgPSBpbm5lclJhZGl1cztcclxuXHRcdGNvbnN0IHJhZGl1c1N0ZXAgPSAoICggb3V0ZXJSYWRpdXMgLSBpbm5lclJhZGl1cyApIC8gcGhpU2VnbWVudHMgKTtcclxuXHRcdGNvbnN0IHZlcnRleCA9IG5ldyBWZWN0b3IzKCk7XHJcblx0XHRjb25zdCB1diA9IG5ldyBWZWN0b3IyKCk7XHJcblxyXG5cdFx0Ly8gZ2VuZXJhdGUgdmVydGljZXMsIG5vcm1hbHMgYW5kIHV2c1xyXG5cclxuXHRcdGZvciAoIGxldCBqID0gMDsgaiA8PSBwaGlTZWdtZW50czsgaiArKyApIHtcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8PSB0aGV0YVNlZ21lbnRzOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHQvLyB2YWx1ZXMgYXJlIGdlbmVyYXRlIGZyb20gdGhlIGluc2lkZSBvZiB0aGUgcmluZyB0byB0aGUgb3V0c2lkZVxyXG5cclxuXHRcdFx0XHRjb25zdCBzZWdtZW50ID0gdGhldGFTdGFydCArIGkgLyB0aGV0YVNlZ21lbnRzICogdGhldGFMZW5ndGg7XHJcblxyXG5cdFx0XHRcdC8vIHZlcnRleFxyXG5cclxuXHRcdFx0XHR2ZXJ0ZXgueCA9IHJhZGl1cyAqIE1hdGguY29zKCBzZWdtZW50ICk7XHJcblx0XHRcdFx0dmVydGV4LnkgPSByYWRpdXMgKiBNYXRoLnNpbiggc2VnbWVudCApO1xyXG5cclxuXHRcdFx0XHR2ZXJ0aWNlcy5wdXNoKCB2ZXJ0ZXgueCwgdmVydGV4LnksIHZlcnRleC56ICk7XHJcblxyXG5cdFx0XHRcdC8vIG5vcm1hbFxyXG5cclxuXHRcdFx0XHRub3JtYWxzLnB1c2goIDAsIDAsIDEgKTtcclxuXHJcblx0XHRcdFx0Ly8gdXZcclxuXHJcblx0XHRcdFx0dXYueCA9ICggdmVydGV4LnggLyBvdXRlclJhZGl1cyArIDEgKSAvIDI7XHJcblx0XHRcdFx0dXYueSA9ICggdmVydGV4LnkgLyBvdXRlclJhZGl1cyArIDEgKSAvIDI7XHJcblxyXG5cdFx0XHRcdHV2cy5wdXNoKCB1di54LCB1di55ICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyBpbmNyZWFzZSB0aGUgcmFkaXVzIGZvciBuZXh0IHJvdyBvZiB2ZXJ0aWNlc1xyXG5cclxuXHRcdFx0cmFkaXVzICs9IHJhZGl1c1N0ZXA7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIGluZGljZXNcclxuXHJcblx0XHRmb3IgKCBsZXQgaiA9IDA7IGogPCBwaGlTZWdtZW50czsgaiArKyApIHtcclxuXHJcblx0XHRcdGNvbnN0IHRoZXRhU2VnbWVudExldmVsID0gaiAqICggdGhldGFTZWdtZW50cyArIDEgKTtcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHRoZXRhU2VnbWVudHM7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IHNlZ21lbnQgPSBpICsgdGhldGFTZWdtZW50TGV2ZWw7XHJcblxyXG5cdFx0XHRcdGNvbnN0IGEgPSBzZWdtZW50O1xyXG5cdFx0XHRcdGNvbnN0IGIgPSBzZWdtZW50ICsgdGhldGFTZWdtZW50cyArIDE7XHJcblx0XHRcdFx0Y29uc3QgYyA9IHNlZ21lbnQgKyB0aGV0YVNlZ21lbnRzICsgMjtcclxuXHRcdFx0XHRjb25zdCBkID0gc2VnbWVudCArIDE7XHJcblxyXG5cdFx0XHRcdC8vIGZhY2VzXHJcblxyXG5cdFx0XHRcdGluZGljZXMucHVzaCggYSwgYiwgZCApO1xyXG5cdFx0XHRcdGluZGljZXMucHVzaCggYiwgYywgZCApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvLyBidWlsZCBnZW9tZXRyeVxyXG5cclxuXHRcdHRoaXMuc2V0SW5kZXgoIGluZGljZXMgKTtcclxuXHRcdHRoaXMuc2V0QXR0cmlidXRlKCAncG9zaXRpb24nLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggdmVydGljZXMsIDMgKSApO1xyXG5cdFx0dGhpcy5zZXRBdHRyaWJ1dGUoICdub3JtYWwnLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggbm9ybWFscywgMyApICk7XHJcblx0XHR0aGlzLnNldEF0dHJpYnV0ZSggJ3V2JywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIHV2cywgMiApICk7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xyXG5cclxuXHRcdHRoaXMucGFyYW1ldGVycyA9IE9iamVjdC5hc3NpZ24oIHt9LCBzb3VyY2UucGFyYW1ldGVycyApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHN0YXRpYyBmcm9tSlNPTiggZGF0YSApIHtcclxuXHJcblx0XHRyZXR1cm4gbmV3IFJpbmdHZW9tZXRyeSggZGF0YS5pbm5lclJhZGl1cywgZGF0YS5vdXRlclJhZGl1cywgZGF0YS50aGV0YVNlZ21lbnRzLCBkYXRhLnBoaVNlZ21lbnRzLCBkYXRhLnRoZXRhU3RhcnQsIGRhdGEudGhldGFMZW5ndGggKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuXHJcbmV4cG9ydCB7IFJpbmdHZW9tZXRyeSB9O1xyXG4iLCJpbXBvcnQgeyBCdWZmZXJHZW9tZXRyeSB9IGZyb20gJy4uL2NvcmUvQnVmZmVyR2VvbWV0cnkuanMnO1xyXG5pbXBvcnQgeyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlIH0gZnJvbSAnLi4vY29yZS9CdWZmZXJBdHRyaWJ1dGUuanMnO1xyXG5pbXBvcnQgeyBTaGFwZSB9IGZyb20gJy4uL2V4dHJhcy9jb3JlL1NoYXBlLmpzJztcclxuaW1wb3J0IHsgU2hhcGVVdGlscyB9IGZyb20gJy4uL2V4dHJhcy9TaGFwZVV0aWxzLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yMiB9IGZyb20gJy4uL21hdGgvVmVjdG9yMi5qcyc7XHJcblxyXG5jbGFzcyBTaGFwZUdlb21ldHJ5IGV4dGVuZHMgQnVmZmVyR2VvbWV0cnkge1xyXG5cclxuXHRjb25zdHJ1Y3Rvciggc2hhcGVzID0gbmV3IFNoYXBlKCBbIG5ldyBWZWN0b3IyKCAwLCAwLjUgKSwgbmV3IFZlY3RvcjIoIC0gMC41LCAtIDAuNSApLCBuZXcgVmVjdG9yMiggMC41LCAtIDAuNSApIF0gKSwgY3VydmVTZWdtZW50cyA9IDEyICkge1xyXG5cclxuXHRcdHN1cGVyKCk7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ1NoYXBlR2VvbWV0cnknO1xyXG5cclxuXHRcdHRoaXMucGFyYW1ldGVycyA9IHtcclxuXHRcdFx0c2hhcGVzOiBzaGFwZXMsXHJcblx0XHRcdGN1cnZlU2VnbWVudHM6IGN1cnZlU2VnbWVudHNcclxuXHRcdH07XHJcblxyXG5cdFx0Ly8gYnVmZmVyc1xyXG5cclxuXHRcdGNvbnN0IGluZGljZXMgPSBbXTtcclxuXHRcdGNvbnN0IHZlcnRpY2VzID0gW107XHJcblx0XHRjb25zdCBub3JtYWxzID0gW107XHJcblx0XHRjb25zdCB1dnMgPSBbXTtcclxuXHJcblx0XHQvLyBoZWxwZXIgdmFyaWFibGVzXHJcblxyXG5cdFx0bGV0IGdyb3VwU3RhcnQgPSAwO1xyXG5cdFx0bGV0IGdyb3VwQ291bnQgPSAwO1xyXG5cclxuXHRcdC8vIGFsbG93IHNpbmdsZSBhbmQgYXJyYXkgdmFsdWVzIGZvciBcInNoYXBlc1wiIHBhcmFtZXRlclxyXG5cclxuXHRcdGlmICggQXJyYXkuaXNBcnJheSggc2hhcGVzICkgPT09IGZhbHNlICkge1xyXG5cclxuXHRcdFx0YWRkU2hhcGUoIHNoYXBlcyApO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBzaGFwZXMubGVuZ3RoOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRhZGRTaGFwZSggc2hhcGVzWyBpIF0gKTtcclxuXHJcblx0XHRcdFx0dGhpcy5hZGRHcm91cCggZ3JvdXBTdGFydCwgZ3JvdXBDb3VudCwgaSApOyAvLyBlbmFibGVzIE11bHRpTWF0ZXJpYWwgc3VwcG9ydFxyXG5cclxuXHRcdFx0XHRncm91cFN0YXJ0ICs9IGdyb3VwQ291bnQ7XHJcblx0XHRcdFx0Z3JvdXBDb3VudCA9IDA7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIGJ1aWxkIGdlb21ldHJ5XHJcblxyXG5cdFx0dGhpcy5zZXRJbmRleCggaW5kaWNlcyApO1xyXG5cdFx0dGhpcy5zZXRBdHRyaWJ1dGUoICdwb3NpdGlvbicsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCB2ZXJ0aWNlcywgMyApICk7XHJcblx0XHR0aGlzLnNldEF0dHJpYnV0ZSggJ25vcm1hbCcsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCBub3JtYWxzLCAzICkgKTtcclxuXHRcdHRoaXMuc2V0QXR0cmlidXRlKCAndXYnLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggdXZzLCAyICkgKTtcclxuXHJcblxyXG5cdFx0Ly8gaGVscGVyIGZ1bmN0aW9uc1xyXG5cclxuXHRcdGZ1bmN0aW9uIGFkZFNoYXBlKCBzaGFwZSApIHtcclxuXHJcblx0XHRcdGNvbnN0IGluZGV4T2Zmc2V0ID0gdmVydGljZXMubGVuZ3RoIC8gMztcclxuXHRcdFx0Y29uc3QgcG9pbnRzID0gc2hhcGUuZXh0cmFjdFBvaW50cyggY3VydmVTZWdtZW50cyApO1xyXG5cclxuXHRcdFx0bGV0IHNoYXBlVmVydGljZXMgPSBwb2ludHMuc2hhcGU7XHJcblx0XHRcdGNvbnN0IHNoYXBlSG9sZXMgPSBwb2ludHMuaG9sZXM7XHJcblxyXG5cdFx0XHQvLyBjaGVjayBkaXJlY3Rpb24gb2YgdmVydGljZXNcclxuXHJcblx0XHRcdGlmICggU2hhcGVVdGlscy5pc0Nsb2NrV2lzZSggc2hhcGVWZXJ0aWNlcyApID09PSBmYWxzZSApIHtcclxuXHJcblx0XHRcdFx0c2hhcGVWZXJ0aWNlcyA9IHNoYXBlVmVydGljZXMucmV2ZXJzZSgpO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gc2hhcGVIb2xlcy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBzaGFwZUhvbGUgPSBzaGFwZUhvbGVzWyBpIF07XHJcblxyXG5cdFx0XHRcdGlmICggU2hhcGVVdGlscy5pc0Nsb2NrV2lzZSggc2hhcGVIb2xlICkgPT09IHRydWUgKSB7XHJcblxyXG5cdFx0XHRcdFx0c2hhcGVIb2xlc1sgaSBdID0gc2hhcGVIb2xlLnJldmVyc2UoKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Y29uc3QgZmFjZXMgPSBTaGFwZVV0aWxzLnRyaWFuZ3VsYXRlU2hhcGUoIHNoYXBlVmVydGljZXMsIHNoYXBlSG9sZXMgKTtcclxuXHJcblx0XHRcdC8vIGpvaW4gdmVydGljZXMgb2YgaW5uZXIgYW5kIG91dGVyIHBhdGhzIHRvIGEgc2luZ2xlIGFycmF5XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBzaGFwZUhvbGVzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IHNoYXBlSG9sZSA9IHNoYXBlSG9sZXNbIGkgXTtcclxuXHRcdFx0XHRzaGFwZVZlcnRpY2VzID0gc2hhcGVWZXJ0aWNlcy5jb25jYXQoIHNoYXBlSG9sZSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Ly8gdmVydGljZXMsIG5vcm1hbHMsIHV2c1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gc2hhcGVWZXJ0aWNlcy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCB2ZXJ0ZXggPSBzaGFwZVZlcnRpY2VzWyBpIF07XHJcblxyXG5cdFx0XHRcdHZlcnRpY2VzLnB1c2goIHZlcnRleC54LCB2ZXJ0ZXgueSwgMCApO1xyXG5cdFx0XHRcdG5vcm1hbHMucHVzaCggMCwgMCwgMSApO1xyXG5cdFx0XHRcdHV2cy5wdXNoKCB2ZXJ0ZXgueCwgdmVydGV4LnkgKTsgLy8gd29ybGQgdXZzXHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyBpbmRpY2VzXHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBmYWNlcy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBmYWNlID0gZmFjZXNbIGkgXTtcclxuXHJcblx0XHRcdFx0Y29uc3QgYSA9IGZhY2VbIDAgXSArIGluZGV4T2Zmc2V0O1xyXG5cdFx0XHRcdGNvbnN0IGIgPSBmYWNlWyAxIF0gKyBpbmRleE9mZnNldDtcclxuXHRcdFx0XHRjb25zdCBjID0gZmFjZVsgMiBdICsgaW5kZXhPZmZzZXQ7XHJcblxyXG5cdFx0XHRcdGluZGljZXMucHVzaCggYSwgYiwgYyApO1xyXG5cdFx0XHRcdGdyb3VwQ291bnQgKz0gMztcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xyXG5cclxuXHRcdHRoaXMucGFyYW1ldGVycyA9IE9iamVjdC5hc3NpZ24oIHt9LCBzb3VyY2UucGFyYW1ldGVycyApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHRvSlNPTigpIHtcclxuXHJcblx0XHRjb25zdCBkYXRhID0gc3VwZXIudG9KU09OKCk7XHJcblxyXG5cdFx0Y29uc3Qgc2hhcGVzID0gdGhpcy5wYXJhbWV0ZXJzLnNoYXBlcztcclxuXHJcblx0XHRyZXR1cm4gdG9KU09OKCBzaGFwZXMsIGRhdGEgKTtcclxuXHJcblx0fVxyXG5cclxuXHRzdGF0aWMgZnJvbUpTT04oIGRhdGEsIHNoYXBlcyApIHtcclxuXHJcblx0XHRjb25zdCBnZW9tZXRyeVNoYXBlcyA9IFtdO1xyXG5cclxuXHRcdGZvciAoIGxldCBqID0gMCwgamwgPSBkYXRhLnNoYXBlcy5sZW5ndGg7IGogPCBqbDsgaiArKyApIHtcclxuXHJcblx0XHRcdGNvbnN0IHNoYXBlID0gc2hhcGVzWyBkYXRhLnNoYXBlc1sgaiBdIF07XHJcblxyXG5cdFx0XHRnZW9tZXRyeVNoYXBlcy5wdXNoKCBzaGFwZSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gbmV3IFNoYXBlR2VvbWV0cnkoIGdlb21ldHJ5U2hhcGVzLCBkYXRhLmN1cnZlU2VnbWVudHMgKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gdG9KU09OKCBzaGFwZXMsIGRhdGEgKSB7XHJcblxyXG5cdGRhdGEuc2hhcGVzID0gW107XHJcblxyXG5cdGlmICggQXJyYXkuaXNBcnJheSggc2hhcGVzICkgKSB7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gc2hhcGVzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBzaGFwZSA9IHNoYXBlc1sgaSBdO1xyXG5cclxuXHRcdFx0ZGF0YS5zaGFwZXMucHVzaCggc2hhcGUudXVpZCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fSBlbHNlIHtcclxuXHJcblx0XHRkYXRhLnNoYXBlcy5wdXNoKCBzaGFwZXMudXVpZCApO1xyXG5cclxuXHR9XHJcblxyXG5cdHJldHVybiBkYXRhO1xyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgU2hhcGVHZW9tZXRyeSB9O1xyXG4iLCJpbXBvcnQgeyBCdWZmZXJHZW9tZXRyeSB9IGZyb20gJy4uL2NvcmUvQnVmZmVyR2VvbWV0cnkuanMnO1xyXG5pbXBvcnQgeyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlIH0gZnJvbSAnLi4vY29yZS9CdWZmZXJBdHRyaWJ1dGUuanMnO1xyXG5pbXBvcnQgeyBWZWN0b3IzIH0gZnJvbSAnLi4vbWF0aC9WZWN0b3IzLmpzJztcclxuXHJcbmNsYXNzIFNwaGVyZUdlb21ldHJ5IGV4dGVuZHMgQnVmZmVyR2VvbWV0cnkge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggcmFkaXVzID0gMSwgd2lkdGhTZWdtZW50cyA9IDMyLCBoZWlnaHRTZWdtZW50cyA9IDE2LCBwaGlTdGFydCA9IDAsIHBoaUxlbmd0aCA9IE1hdGguUEkgKiAyLCB0aGV0YVN0YXJ0ID0gMCwgdGhldGFMZW5ndGggPSBNYXRoLlBJICkge1xyXG5cclxuXHRcdHN1cGVyKCk7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ1NwaGVyZUdlb21ldHJ5JztcclxuXHJcblx0XHR0aGlzLnBhcmFtZXRlcnMgPSB7XHJcblx0XHRcdHJhZGl1czogcmFkaXVzLFxyXG5cdFx0XHR3aWR0aFNlZ21lbnRzOiB3aWR0aFNlZ21lbnRzLFxyXG5cdFx0XHRoZWlnaHRTZWdtZW50czogaGVpZ2h0U2VnbWVudHMsXHJcblx0XHRcdHBoaVN0YXJ0OiBwaGlTdGFydCxcclxuXHRcdFx0cGhpTGVuZ3RoOiBwaGlMZW5ndGgsXHJcblx0XHRcdHRoZXRhU3RhcnQ6IHRoZXRhU3RhcnQsXHJcblx0XHRcdHRoZXRhTGVuZ3RoOiB0aGV0YUxlbmd0aFxyXG5cdFx0fTtcclxuXHJcblx0XHR3aWR0aFNlZ21lbnRzID0gTWF0aC5tYXgoIDMsIE1hdGguZmxvb3IoIHdpZHRoU2VnbWVudHMgKSApO1xyXG5cdFx0aGVpZ2h0U2VnbWVudHMgPSBNYXRoLm1heCggMiwgTWF0aC5mbG9vciggaGVpZ2h0U2VnbWVudHMgKSApO1xyXG5cclxuXHRcdGNvbnN0IHRoZXRhRW5kID0gTWF0aC5taW4oIHRoZXRhU3RhcnQgKyB0aGV0YUxlbmd0aCwgTWF0aC5QSSApO1xyXG5cclxuXHRcdGxldCBpbmRleCA9IDA7XHJcblx0XHRjb25zdCBncmlkID0gW107XHJcblxyXG5cdFx0Y29uc3QgdmVydGV4ID0gbmV3IFZlY3RvcjMoKTtcclxuXHRcdGNvbnN0IG5vcm1hbCA9IG5ldyBWZWN0b3IzKCk7XHJcblxyXG5cdFx0Ly8gYnVmZmVyc1xyXG5cclxuXHRcdGNvbnN0IGluZGljZXMgPSBbXTtcclxuXHRcdGNvbnN0IHZlcnRpY2VzID0gW107XHJcblx0XHRjb25zdCBub3JtYWxzID0gW107XHJcblx0XHRjb25zdCB1dnMgPSBbXTtcclxuXHJcblx0XHQvLyBnZW5lcmF0ZSB2ZXJ0aWNlcywgbm9ybWFscyBhbmQgdXZzXHJcblxyXG5cdFx0Zm9yICggbGV0IGl5ID0gMDsgaXkgPD0gaGVpZ2h0U2VnbWVudHM7IGl5ICsrICkge1xyXG5cclxuXHRcdFx0Y29uc3QgdmVydGljZXNSb3cgPSBbXTtcclxuXHJcblx0XHRcdGNvbnN0IHYgPSBpeSAvIGhlaWdodFNlZ21lbnRzO1xyXG5cclxuXHRcdFx0Ly8gc3BlY2lhbCBjYXNlIGZvciB0aGUgcG9sZXNcclxuXHJcblx0XHRcdGxldCB1T2Zmc2V0ID0gMDtcclxuXHJcblx0XHRcdGlmICggaXkgPT09IDAgJiYgdGhldGFTdGFydCA9PT0gMCApIHtcclxuXHJcblx0XHRcdFx0dU9mZnNldCA9IDAuNSAvIHdpZHRoU2VnbWVudHM7XHJcblxyXG5cdFx0XHR9IGVsc2UgaWYgKCBpeSA9PT0gaGVpZ2h0U2VnbWVudHMgJiYgdGhldGFFbmQgPT09IE1hdGguUEkgKSB7XHJcblxyXG5cdFx0XHRcdHVPZmZzZXQgPSAtIDAuNSAvIHdpZHRoU2VnbWVudHM7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaXggPSAwOyBpeCA8PSB3aWR0aFNlZ21lbnRzOyBpeCArKyApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgdSA9IGl4IC8gd2lkdGhTZWdtZW50cztcclxuXHJcblx0XHRcdFx0Ly8gdmVydGV4XHJcblxyXG5cdFx0XHRcdHZlcnRleC54ID0gLSByYWRpdXMgKiBNYXRoLmNvcyggcGhpU3RhcnQgKyB1ICogcGhpTGVuZ3RoICkgKiBNYXRoLnNpbiggdGhldGFTdGFydCArIHYgKiB0aGV0YUxlbmd0aCApO1xyXG5cdFx0XHRcdHZlcnRleC55ID0gcmFkaXVzICogTWF0aC5jb3MoIHRoZXRhU3RhcnQgKyB2ICogdGhldGFMZW5ndGggKTtcclxuXHRcdFx0XHR2ZXJ0ZXgueiA9IHJhZGl1cyAqIE1hdGguc2luKCBwaGlTdGFydCArIHUgKiBwaGlMZW5ndGggKSAqIE1hdGguc2luKCB0aGV0YVN0YXJ0ICsgdiAqIHRoZXRhTGVuZ3RoICk7XHJcblxyXG5cdFx0XHRcdHZlcnRpY2VzLnB1c2goIHZlcnRleC54LCB2ZXJ0ZXgueSwgdmVydGV4LnogKTtcclxuXHJcblx0XHRcdFx0Ly8gbm9ybWFsXHJcblxyXG5cdFx0XHRcdG5vcm1hbC5jb3B5KCB2ZXJ0ZXggKS5ub3JtYWxpemUoKTtcclxuXHRcdFx0XHRub3JtYWxzLnB1c2goIG5vcm1hbC54LCBub3JtYWwueSwgbm9ybWFsLnogKTtcclxuXHJcblx0XHRcdFx0Ly8gdXZcclxuXHJcblx0XHRcdFx0dXZzLnB1c2goIHUgKyB1T2Zmc2V0LCAxIC0gdiApO1xyXG5cclxuXHRcdFx0XHR2ZXJ0aWNlc1Jvdy5wdXNoKCBpbmRleCArKyApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Z3JpZC5wdXNoKCB2ZXJ0aWNlc1JvdyApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvLyBpbmRpY2VzXHJcblxyXG5cdFx0Zm9yICggbGV0IGl5ID0gMDsgaXkgPCBoZWlnaHRTZWdtZW50czsgaXkgKysgKSB7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaXggPSAwOyBpeCA8IHdpZHRoU2VnbWVudHM7IGl4ICsrICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBhID0gZ3JpZFsgaXkgXVsgaXggKyAxIF07XHJcblx0XHRcdFx0Y29uc3QgYiA9IGdyaWRbIGl5IF1bIGl4IF07XHJcblx0XHRcdFx0Y29uc3QgYyA9IGdyaWRbIGl5ICsgMSBdWyBpeCBdO1xyXG5cdFx0XHRcdGNvbnN0IGQgPSBncmlkWyBpeSArIDEgXVsgaXggKyAxIF07XHJcblxyXG5cdFx0XHRcdGlmICggaXkgIT09IDAgfHwgdGhldGFTdGFydCA+IDAgKSBpbmRpY2VzLnB1c2goIGEsIGIsIGQgKTtcclxuXHRcdFx0XHRpZiAoIGl5ICE9PSBoZWlnaHRTZWdtZW50cyAtIDEgfHwgdGhldGFFbmQgPCBNYXRoLlBJICkgaW5kaWNlcy5wdXNoKCBiLCBjLCBkICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIGJ1aWxkIGdlb21ldHJ5XHJcblxyXG5cdFx0dGhpcy5zZXRJbmRleCggaW5kaWNlcyApO1xyXG5cdFx0dGhpcy5zZXRBdHRyaWJ1dGUoICdwb3NpdGlvbicsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCB2ZXJ0aWNlcywgMyApICk7XHJcblx0XHR0aGlzLnNldEF0dHJpYnV0ZSggJ25vcm1hbCcsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCBub3JtYWxzLCAzICkgKTtcclxuXHRcdHRoaXMuc2V0QXR0cmlidXRlKCAndXYnLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggdXZzLCAyICkgKTtcclxuXHJcblx0fVxyXG5cclxuXHRjb3B5KCBzb3VyY2UgKSB7XHJcblxyXG5cdFx0c3VwZXIuY29weSggc291cmNlICk7XHJcblxyXG5cdFx0dGhpcy5wYXJhbWV0ZXJzID0gT2JqZWN0LmFzc2lnbigge30sIHNvdXJjZS5wYXJhbWV0ZXJzICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0c3RhdGljIGZyb21KU09OKCBkYXRhICkge1xyXG5cclxuXHRcdHJldHVybiBuZXcgU3BoZXJlR2VvbWV0cnkoIGRhdGEucmFkaXVzLCBkYXRhLndpZHRoU2VnbWVudHMsIGRhdGEuaGVpZ2h0U2VnbWVudHMsIGRhdGEucGhpU3RhcnQsIGRhdGEucGhpTGVuZ3RoLCBkYXRhLnRoZXRhU3RhcnQsIGRhdGEudGhldGFMZW5ndGggKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgU3BoZXJlR2VvbWV0cnkgfTtcclxuIiwiaW1wb3J0IHsgUG9seWhlZHJvbkdlb21ldHJ5IH0gZnJvbSAnLi9Qb2x5aGVkcm9uR2VvbWV0cnkuanMnO1xyXG5cclxuY2xhc3MgVGV0cmFoZWRyb25HZW9tZXRyeSBleHRlbmRzIFBvbHloZWRyb25HZW9tZXRyeSB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCByYWRpdXMgPSAxLCBkZXRhaWwgPSAwICkge1xyXG5cclxuXHRcdGNvbnN0IHZlcnRpY2VzID0gW1xyXG5cdFx0XHQxLCAxLCAxLCBcdC0gMSwgLSAxLCAxLCBcdC0gMSwgMSwgLSAxLCBcdDEsIC0gMSwgLSAxXHJcblx0XHRdO1xyXG5cclxuXHRcdGNvbnN0IGluZGljZXMgPSBbXHJcblx0XHRcdDIsIDEsIDAsIFx0MCwgMywgMixcdDEsIDMsIDAsXHQyLCAzLCAxXHJcblx0XHRdO1xyXG5cclxuXHRcdHN1cGVyKCB2ZXJ0aWNlcywgaW5kaWNlcywgcmFkaXVzLCBkZXRhaWwgKTtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSAnVGV0cmFoZWRyb25HZW9tZXRyeSc7XHJcblxyXG5cdFx0dGhpcy5wYXJhbWV0ZXJzID0ge1xyXG5cdFx0XHRyYWRpdXM6IHJhZGl1cyxcclxuXHRcdFx0ZGV0YWlsOiBkZXRhaWxcclxuXHRcdH07XHJcblxyXG5cdH1cclxuXHJcblx0c3RhdGljIGZyb21KU09OKCBkYXRhICkge1xyXG5cclxuXHRcdHJldHVybiBuZXcgVGV0cmFoZWRyb25HZW9tZXRyeSggZGF0YS5yYWRpdXMsIGRhdGEuZGV0YWlsICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IFRldHJhaGVkcm9uR2VvbWV0cnkgfTtcclxuIiwiaW1wb3J0IHsgQnVmZmVyR2VvbWV0cnkgfSBmcm9tICcuLi9jb3JlL0J1ZmZlckdlb21ldHJ5LmpzJztcclxuaW1wb3J0IHsgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSB9IGZyb20gJy4uL2NvcmUvQnVmZmVyQXR0cmlidXRlLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yMyB9IGZyb20gJy4uL21hdGgvVmVjdG9yMy5qcyc7XHJcblxyXG5jbGFzcyBUb3J1c0dlb21ldHJ5IGV4dGVuZHMgQnVmZmVyR2VvbWV0cnkge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggcmFkaXVzID0gMSwgdHViZSA9IDAuNCwgcmFkaWFsU2VnbWVudHMgPSAxMiwgdHVidWxhclNlZ21lbnRzID0gNDgsIGFyYyA9IE1hdGguUEkgKiAyICkge1xyXG5cclxuXHRcdHN1cGVyKCk7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ1RvcnVzR2VvbWV0cnknO1xyXG5cclxuXHRcdHRoaXMucGFyYW1ldGVycyA9IHtcclxuXHRcdFx0cmFkaXVzOiByYWRpdXMsXHJcblx0XHRcdHR1YmU6IHR1YmUsXHJcblx0XHRcdHJhZGlhbFNlZ21lbnRzOiByYWRpYWxTZWdtZW50cyxcclxuXHRcdFx0dHVidWxhclNlZ21lbnRzOiB0dWJ1bGFyU2VnbWVudHMsXHJcblx0XHRcdGFyYzogYXJjXHJcblx0XHR9O1xyXG5cclxuXHRcdHJhZGlhbFNlZ21lbnRzID0gTWF0aC5mbG9vciggcmFkaWFsU2VnbWVudHMgKTtcclxuXHRcdHR1YnVsYXJTZWdtZW50cyA9IE1hdGguZmxvb3IoIHR1YnVsYXJTZWdtZW50cyApO1xyXG5cclxuXHRcdC8vIGJ1ZmZlcnNcclxuXHJcblx0XHRjb25zdCBpbmRpY2VzID0gW107XHJcblx0XHRjb25zdCB2ZXJ0aWNlcyA9IFtdO1xyXG5cdFx0Y29uc3Qgbm9ybWFscyA9IFtdO1xyXG5cdFx0Y29uc3QgdXZzID0gW107XHJcblxyXG5cdFx0Ly8gaGVscGVyIHZhcmlhYmxlc1xyXG5cclxuXHRcdGNvbnN0IGNlbnRlciA9IG5ldyBWZWN0b3IzKCk7XHJcblx0XHRjb25zdCB2ZXJ0ZXggPSBuZXcgVmVjdG9yMygpO1xyXG5cdFx0Y29uc3Qgbm9ybWFsID0gbmV3IFZlY3RvcjMoKTtcclxuXHJcblx0XHQvLyBnZW5lcmF0ZSB2ZXJ0aWNlcywgbm9ybWFscyBhbmQgdXZzXHJcblxyXG5cdFx0Zm9yICggbGV0IGogPSAwOyBqIDw9IHJhZGlhbFNlZ21lbnRzOyBqICsrICkge1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDw9IHR1YnVsYXJTZWdtZW50czsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgdSA9IGkgLyB0dWJ1bGFyU2VnbWVudHMgKiBhcmM7XHJcblx0XHRcdFx0Y29uc3QgdiA9IGogLyByYWRpYWxTZWdtZW50cyAqIE1hdGguUEkgKiAyO1xyXG5cclxuXHRcdFx0XHQvLyB2ZXJ0ZXhcclxuXHJcblx0XHRcdFx0dmVydGV4LnggPSAoIHJhZGl1cyArIHR1YmUgKiBNYXRoLmNvcyggdiApICkgKiBNYXRoLmNvcyggdSApO1xyXG5cdFx0XHRcdHZlcnRleC55ID0gKCByYWRpdXMgKyB0dWJlICogTWF0aC5jb3MoIHYgKSApICogTWF0aC5zaW4oIHUgKTtcclxuXHRcdFx0XHR2ZXJ0ZXgueiA9IHR1YmUgKiBNYXRoLnNpbiggdiApO1xyXG5cclxuXHRcdFx0XHR2ZXJ0aWNlcy5wdXNoKCB2ZXJ0ZXgueCwgdmVydGV4LnksIHZlcnRleC56ICk7XHJcblxyXG5cdFx0XHRcdC8vIG5vcm1hbFxyXG5cclxuXHRcdFx0XHRjZW50ZXIueCA9IHJhZGl1cyAqIE1hdGguY29zKCB1ICk7XHJcblx0XHRcdFx0Y2VudGVyLnkgPSByYWRpdXMgKiBNYXRoLnNpbiggdSApO1xyXG5cdFx0XHRcdG5vcm1hbC5zdWJWZWN0b3JzKCB2ZXJ0ZXgsIGNlbnRlciApLm5vcm1hbGl6ZSgpO1xyXG5cclxuXHRcdFx0XHRub3JtYWxzLnB1c2goIG5vcm1hbC54LCBub3JtYWwueSwgbm9ybWFsLnogKTtcclxuXHJcblx0XHRcdFx0Ly8gdXZcclxuXHJcblx0XHRcdFx0dXZzLnB1c2goIGkgLyB0dWJ1bGFyU2VnbWVudHMgKTtcclxuXHRcdFx0XHR1dnMucHVzaCggaiAvIHJhZGlhbFNlZ21lbnRzICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIGdlbmVyYXRlIGluZGljZXNcclxuXHJcblx0XHRmb3IgKCBsZXQgaiA9IDE7IGogPD0gcmFkaWFsU2VnbWVudHM7IGogKysgKSB7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDE7IGkgPD0gdHVidWxhclNlZ21lbnRzOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHQvLyBpbmRpY2VzXHJcblxyXG5cdFx0XHRcdGNvbnN0IGEgPSAoIHR1YnVsYXJTZWdtZW50cyArIDEgKSAqIGogKyBpIC0gMTtcclxuXHRcdFx0XHRjb25zdCBiID0gKCB0dWJ1bGFyU2VnbWVudHMgKyAxICkgKiAoIGogLSAxICkgKyBpIC0gMTtcclxuXHRcdFx0XHRjb25zdCBjID0gKCB0dWJ1bGFyU2VnbWVudHMgKyAxICkgKiAoIGogLSAxICkgKyBpO1xyXG5cdFx0XHRcdGNvbnN0IGQgPSAoIHR1YnVsYXJTZWdtZW50cyArIDEgKSAqIGogKyBpO1xyXG5cclxuXHRcdFx0XHQvLyBmYWNlc1xyXG5cclxuXHRcdFx0XHRpbmRpY2VzLnB1c2goIGEsIGIsIGQgKTtcclxuXHRcdFx0XHRpbmRpY2VzLnB1c2goIGIsIGMsIGQgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gYnVpbGQgZ2VvbWV0cnlcclxuXHJcblx0XHR0aGlzLnNldEluZGV4KCBpbmRpY2VzICk7XHJcblx0XHR0aGlzLnNldEF0dHJpYnV0ZSggJ3Bvc2l0aW9uJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIHZlcnRpY2VzLCAzICkgKTtcclxuXHRcdHRoaXMuc2V0QXR0cmlidXRlKCAnbm9ybWFsJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIG5vcm1hbHMsIDMgKSApO1xyXG5cdFx0dGhpcy5zZXRBdHRyaWJ1dGUoICd1dicsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCB1dnMsIDIgKSApO1xyXG5cclxuXHR9XHJcblxyXG5cdGNvcHkoIHNvdXJjZSApIHtcclxuXHJcblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcclxuXHJcblx0XHR0aGlzLnBhcmFtZXRlcnMgPSBPYmplY3QuYXNzaWduKCB7fSwgc291cmNlLnBhcmFtZXRlcnMgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzdGF0aWMgZnJvbUpTT04oIGRhdGEgKSB7XHJcblxyXG5cdFx0cmV0dXJuIG5ldyBUb3J1c0dlb21ldHJ5KCBkYXRhLnJhZGl1cywgZGF0YS50dWJlLCBkYXRhLnJhZGlhbFNlZ21lbnRzLCBkYXRhLnR1YnVsYXJTZWdtZW50cywgZGF0YS5hcmMgKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgVG9ydXNHZW9tZXRyeSB9O1xyXG4iLCJpbXBvcnQgeyBCdWZmZXJHZW9tZXRyeSB9IGZyb20gJy4uL2NvcmUvQnVmZmVyR2VvbWV0cnkuanMnO1xyXG5pbXBvcnQgeyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlIH0gZnJvbSAnLi4vY29yZS9CdWZmZXJBdHRyaWJ1dGUuanMnO1xyXG5pbXBvcnQgeyBWZWN0b3IzIH0gZnJvbSAnLi4vbWF0aC9WZWN0b3IzLmpzJztcclxuXHJcbmNsYXNzIFRvcnVzS25vdEdlb21ldHJ5IGV4dGVuZHMgQnVmZmVyR2VvbWV0cnkge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggcmFkaXVzID0gMSwgdHViZSA9IDAuNCwgdHVidWxhclNlZ21lbnRzID0gNjQsIHJhZGlhbFNlZ21lbnRzID0gOCwgcCA9IDIsIHEgPSAzICkge1xyXG5cclxuXHRcdHN1cGVyKCk7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ1RvcnVzS25vdEdlb21ldHJ5JztcclxuXHJcblx0XHR0aGlzLnBhcmFtZXRlcnMgPSB7XHJcblx0XHRcdHJhZGl1czogcmFkaXVzLFxyXG5cdFx0XHR0dWJlOiB0dWJlLFxyXG5cdFx0XHR0dWJ1bGFyU2VnbWVudHM6IHR1YnVsYXJTZWdtZW50cyxcclxuXHRcdFx0cmFkaWFsU2VnbWVudHM6IHJhZGlhbFNlZ21lbnRzLFxyXG5cdFx0XHRwOiBwLFxyXG5cdFx0XHRxOiBxXHJcblx0XHR9O1xyXG5cclxuXHRcdHR1YnVsYXJTZWdtZW50cyA9IE1hdGguZmxvb3IoIHR1YnVsYXJTZWdtZW50cyApO1xyXG5cdFx0cmFkaWFsU2VnbWVudHMgPSBNYXRoLmZsb29yKCByYWRpYWxTZWdtZW50cyApO1xyXG5cclxuXHRcdC8vIGJ1ZmZlcnNcclxuXHJcblx0XHRjb25zdCBpbmRpY2VzID0gW107XHJcblx0XHRjb25zdCB2ZXJ0aWNlcyA9IFtdO1xyXG5cdFx0Y29uc3Qgbm9ybWFscyA9IFtdO1xyXG5cdFx0Y29uc3QgdXZzID0gW107XHJcblxyXG5cdFx0Ly8gaGVscGVyIHZhcmlhYmxlc1xyXG5cclxuXHRcdGNvbnN0IHZlcnRleCA9IG5ldyBWZWN0b3IzKCk7XHJcblx0XHRjb25zdCBub3JtYWwgPSBuZXcgVmVjdG9yMygpO1xyXG5cclxuXHRcdGNvbnN0IFAxID0gbmV3IFZlY3RvcjMoKTtcclxuXHRcdGNvbnN0IFAyID0gbmV3IFZlY3RvcjMoKTtcclxuXHJcblx0XHRjb25zdCBCID0gbmV3IFZlY3RvcjMoKTtcclxuXHRcdGNvbnN0IFQgPSBuZXcgVmVjdG9yMygpO1xyXG5cdFx0Y29uc3QgTiA9IG5ldyBWZWN0b3IzKCk7XHJcblxyXG5cdFx0Ly8gZ2VuZXJhdGUgdmVydGljZXMsIG5vcm1hbHMgYW5kIHV2c1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8PSB0dWJ1bGFyU2VnbWVudHM7ICsrIGkgKSB7XHJcblxyXG5cdFx0XHQvLyB0aGUgcmFkaWFuIFwidVwiIGlzIHVzZWQgdG8gY2FsY3VsYXRlIHRoZSBwb3NpdGlvbiBvbiB0aGUgdG9ydXMgY3VydmUgb2YgdGhlIGN1cnJlbnQgdHVidWxhciBzZWdtZW50XHJcblxyXG5cdFx0XHRjb25zdCB1ID0gaSAvIHR1YnVsYXJTZWdtZW50cyAqIHAgKiBNYXRoLlBJICogMjtcclxuXHJcblx0XHRcdC8vIG5vdyB3ZSBjYWxjdWxhdGUgdHdvIHBvaW50cy4gUDEgaXMgb3VyIGN1cnJlbnQgcG9zaXRpb24gb24gdGhlIGN1cnZlLCBQMiBpcyBhIGxpdHRsZSBmYXJ0aGVyIGFoZWFkLlxyXG5cdFx0XHQvLyB0aGVzZSBwb2ludHMgYXJlIHVzZWQgdG8gY3JlYXRlIGEgc3BlY2lhbCBcImNvb3JkaW5hdGUgc3BhY2VcIiwgd2hpY2ggaXMgbmVjZXNzYXJ5IHRvIGNhbGN1bGF0ZSB0aGUgY29ycmVjdCB2ZXJ0ZXggcG9zaXRpb25zXHJcblxyXG5cdFx0XHRjYWxjdWxhdGVQb3NpdGlvbk9uQ3VydmUoIHUsIHAsIHEsIHJhZGl1cywgUDEgKTtcclxuXHRcdFx0Y2FsY3VsYXRlUG9zaXRpb25PbkN1cnZlKCB1ICsgMC4wMSwgcCwgcSwgcmFkaXVzLCBQMiApO1xyXG5cclxuXHRcdFx0Ly8gY2FsY3VsYXRlIG9ydGhvbm9ybWFsIGJhc2lzXHJcblxyXG5cdFx0XHRULnN1YlZlY3RvcnMoIFAyLCBQMSApO1xyXG5cdFx0XHROLmFkZFZlY3RvcnMoIFAyLCBQMSApO1xyXG5cdFx0XHRCLmNyb3NzVmVjdG9ycyggVCwgTiApO1xyXG5cdFx0XHROLmNyb3NzVmVjdG9ycyggQiwgVCApO1xyXG5cclxuXHRcdFx0Ly8gbm9ybWFsaXplIEIsIE4uIFQgY2FuIGJlIGlnbm9yZWQsIHdlIGRvbid0IHVzZSBpdFxyXG5cclxuXHRcdFx0Qi5ub3JtYWxpemUoKTtcclxuXHRcdFx0Ti5ub3JtYWxpemUoKTtcclxuXHJcblx0XHRcdGZvciAoIGxldCBqID0gMDsgaiA8PSByYWRpYWxTZWdtZW50czsgKysgaiApIHtcclxuXHJcblx0XHRcdFx0Ly8gbm93IGNhbGN1bGF0ZSB0aGUgdmVydGljZXMuIHRoZXkgYXJlIG5vdGhpbmcgbW9yZSB0aGFuIGFuIGV4dHJ1c2lvbiBvZiB0aGUgdG9ydXMgY3VydmUuXHJcblx0XHRcdFx0Ly8gYmVjYXVzZSB3ZSBleHRydWRlIGEgc2hhcGUgaW4gdGhlIHh5LXBsYW5lLCB0aGVyZSBpcyBubyBuZWVkIHRvIGNhbGN1bGF0ZSBhIHotdmFsdWUuXHJcblxyXG5cdFx0XHRcdGNvbnN0IHYgPSBqIC8gcmFkaWFsU2VnbWVudHMgKiBNYXRoLlBJICogMjtcclxuXHRcdFx0XHRjb25zdCBjeCA9IC0gdHViZSAqIE1hdGguY29zKCB2ICk7XHJcblx0XHRcdFx0Y29uc3QgY3kgPSB0dWJlICogTWF0aC5zaW4oIHYgKTtcclxuXHJcblx0XHRcdFx0Ly8gbm93IGNhbGN1bGF0ZSB0aGUgZmluYWwgdmVydGV4IHBvc2l0aW9uLlxyXG5cdFx0XHRcdC8vIGZpcnN0IHdlIG9yaWVudCB0aGUgZXh0cnVzaW9uIHdpdGggb3VyIGJhc2lzIHZlY3RvcnMsIHRoZW4gd2UgYWRkIGl0IHRvIHRoZSBjdXJyZW50IHBvc2l0aW9uIG9uIHRoZSBjdXJ2ZVxyXG5cclxuXHRcdFx0XHR2ZXJ0ZXgueCA9IFAxLnggKyAoIGN4ICogTi54ICsgY3kgKiBCLnggKTtcclxuXHRcdFx0XHR2ZXJ0ZXgueSA9IFAxLnkgKyAoIGN4ICogTi55ICsgY3kgKiBCLnkgKTtcclxuXHRcdFx0XHR2ZXJ0ZXgueiA9IFAxLnogKyAoIGN4ICogTi56ICsgY3kgKiBCLnogKTtcclxuXHJcblx0XHRcdFx0dmVydGljZXMucHVzaCggdmVydGV4LngsIHZlcnRleC55LCB2ZXJ0ZXgueiApO1xyXG5cclxuXHRcdFx0XHQvLyBub3JtYWwgKFAxIGlzIGFsd2F5cyB0aGUgY2VudGVyL29yaWdpbiBvZiB0aGUgZXh0cnVzaW9uLCB0aHVzIHdlIGNhbiB1c2UgaXQgdG8gY2FsY3VsYXRlIHRoZSBub3JtYWwpXHJcblxyXG5cdFx0XHRcdG5vcm1hbC5zdWJWZWN0b3JzKCB2ZXJ0ZXgsIFAxICkubm9ybWFsaXplKCk7XHJcblxyXG5cdFx0XHRcdG5vcm1hbHMucHVzaCggbm9ybWFsLngsIG5vcm1hbC55LCBub3JtYWwueiApO1xyXG5cclxuXHRcdFx0XHQvLyB1dlxyXG5cclxuXHRcdFx0XHR1dnMucHVzaCggaSAvIHR1YnVsYXJTZWdtZW50cyApO1xyXG5cdFx0XHRcdHV2cy5wdXNoKCBqIC8gcmFkaWFsU2VnbWVudHMgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gZ2VuZXJhdGUgaW5kaWNlc1xyXG5cclxuXHRcdGZvciAoIGxldCBqID0gMTsgaiA8PSB0dWJ1bGFyU2VnbWVudHM7IGogKysgKSB7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDE7IGkgPD0gcmFkaWFsU2VnbWVudHM7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdC8vIGluZGljZXNcclxuXHJcblx0XHRcdFx0Y29uc3QgYSA9ICggcmFkaWFsU2VnbWVudHMgKyAxICkgKiAoIGogLSAxICkgKyAoIGkgLSAxICk7XHJcblx0XHRcdFx0Y29uc3QgYiA9ICggcmFkaWFsU2VnbWVudHMgKyAxICkgKiBqICsgKCBpIC0gMSApO1xyXG5cdFx0XHRcdGNvbnN0IGMgPSAoIHJhZGlhbFNlZ21lbnRzICsgMSApICogaiArIGk7XHJcblx0XHRcdFx0Y29uc3QgZCA9ICggcmFkaWFsU2VnbWVudHMgKyAxICkgKiAoIGogLSAxICkgKyBpO1xyXG5cclxuXHRcdFx0XHQvLyBmYWNlc1xyXG5cclxuXHRcdFx0XHRpbmRpY2VzLnB1c2goIGEsIGIsIGQgKTtcclxuXHRcdFx0XHRpbmRpY2VzLnB1c2goIGIsIGMsIGQgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gYnVpbGQgZ2VvbWV0cnlcclxuXHJcblx0XHR0aGlzLnNldEluZGV4KCBpbmRpY2VzICk7XHJcblx0XHR0aGlzLnNldEF0dHJpYnV0ZSggJ3Bvc2l0aW9uJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIHZlcnRpY2VzLCAzICkgKTtcclxuXHRcdHRoaXMuc2V0QXR0cmlidXRlKCAnbm9ybWFsJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIG5vcm1hbHMsIDMgKSApO1xyXG5cdFx0dGhpcy5zZXRBdHRyaWJ1dGUoICd1dicsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCB1dnMsIDIgKSApO1xyXG5cclxuXHRcdC8vIHRoaXMgZnVuY3Rpb24gY2FsY3VsYXRlcyB0aGUgY3VycmVudCBwb3NpdGlvbiBvbiB0aGUgdG9ydXMgY3VydmVcclxuXHJcblx0XHRmdW5jdGlvbiBjYWxjdWxhdGVQb3NpdGlvbk9uQ3VydmUoIHUsIHAsIHEsIHJhZGl1cywgcG9zaXRpb24gKSB7XHJcblxyXG5cdFx0XHRjb25zdCBjdSA9IE1hdGguY29zKCB1ICk7XHJcblx0XHRcdGNvbnN0IHN1ID0gTWF0aC5zaW4oIHUgKTtcclxuXHRcdFx0Y29uc3QgcXVPdmVyUCA9IHEgLyBwICogdTtcclxuXHRcdFx0Y29uc3QgY3MgPSBNYXRoLmNvcyggcXVPdmVyUCApO1xyXG5cclxuXHRcdFx0cG9zaXRpb24ueCA9IHJhZGl1cyAqICggMiArIGNzICkgKiAwLjUgKiBjdTtcclxuXHRcdFx0cG9zaXRpb24ueSA9IHJhZGl1cyAqICggMiArIGNzICkgKiBzdSAqIDAuNTtcclxuXHRcdFx0cG9zaXRpb24ueiA9IHJhZGl1cyAqIE1hdGguc2luKCBxdU92ZXJQICkgKiAwLjU7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGNvcHkoIHNvdXJjZSApIHtcclxuXHJcblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcclxuXHJcblx0XHR0aGlzLnBhcmFtZXRlcnMgPSBPYmplY3QuYXNzaWduKCB7fSwgc291cmNlLnBhcmFtZXRlcnMgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzdGF0aWMgZnJvbUpTT04oIGRhdGEgKSB7XHJcblxyXG5cdFx0cmV0dXJuIG5ldyBUb3J1c0tub3RHZW9tZXRyeSggZGF0YS5yYWRpdXMsIGRhdGEudHViZSwgZGF0YS50dWJ1bGFyU2VnbWVudHMsIGRhdGEucmFkaWFsU2VnbWVudHMsIGRhdGEucCwgZGF0YS5xICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IFRvcnVzS25vdEdlb21ldHJ5IH07XHJcbiIsImltcG9ydCB7IEJ1ZmZlckdlb21ldHJ5IH0gZnJvbSAnLi4vY29yZS9CdWZmZXJHZW9tZXRyeS5qcyc7XHJcbmltcG9ydCB7IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUgfSBmcm9tICcuLi9jb3JlL0J1ZmZlckF0dHJpYnV0ZS5qcyc7XHJcbmltcG9ydCAqIGFzIEN1cnZlcyBmcm9tICcuLi9leHRyYXMvY3VydmVzL0N1cnZlcy5qcyc7XHJcbmltcG9ydCB7IFZlY3RvcjIgfSBmcm9tICcuLi9tYXRoL1ZlY3RvcjIuanMnO1xyXG5pbXBvcnQgeyBWZWN0b3IzIH0gZnJvbSAnLi4vbWF0aC9WZWN0b3IzLmpzJztcclxuXHJcbmNsYXNzIFR1YmVHZW9tZXRyeSBleHRlbmRzIEJ1ZmZlckdlb21ldHJ5IHtcclxuXHJcblx0Y29uc3RydWN0b3IoIHBhdGggPSBuZXcgQ3VydmVzWyAnUXVhZHJhdGljQmV6aWVyQ3VydmUzJyBdKCBuZXcgVmVjdG9yMyggLSAxLCAtIDEsIDAgKSwgbmV3IFZlY3RvcjMoIC0gMSwgMSwgMCApLCBuZXcgVmVjdG9yMyggMSwgMSwgMCApICksIHR1YnVsYXJTZWdtZW50cyA9IDY0LCByYWRpdXMgPSAxLCByYWRpYWxTZWdtZW50cyA9IDgsIGNsb3NlZCA9IGZhbHNlICkge1xyXG5cclxuXHRcdHN1cGVyKCk7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ1R1YmVHZW9tZXRyeSc7XHJcblxyXG5cdFx0dGhpcy5wYXJhbWV0ZXJzID0ge1xyXG5cdFx0XHRwYXRoOiBwYXRoLFxyXG5cdFx0XHR0dWJ1bGFyU2VnbWVudHM6IHR1YnVsYXJTZWdtZW50cyxcclxuXHRcdFx0cmFkaXVzOiByYWRpdXMsXHJcblx0XHRcdHJhZGlhbFNlZ21lbnRzOiByYWRpYWxTZWdtZW50cyxcclxuXHRcdFx0Y2xvc2VkOiBjbG9zZWRcclxuXHRcdH07XHJcblxyXG5cdFx0Y29uc3QgZnJhbWVzID0gcGF0aC5jb21wdXRlRnJlbmV0RnJhbWVzKCB0dWJ1bGFyU2VnbWVudHMsIGNsb3NlZCApO1xyXG5cclxuXHRcdC8vIGV4cG9zZSBpbnRlcm5hbHNcclxuXHJcblx0XHR0aGlzLnRhbmdlbnRzID0gZnJhbWVzLnRhbmdlbnRzO1xyXG5cdFx0dGhpcy5ub3JtYWxzID0gZnJhbWVzLm5vcm1hbHM7XHJcblx0XHR0aGlzLmJpbm9ybWFscyA9IGZyYW1lcy5iaW5vcm1hbHM7XHJcblxyXG5cdFx0Ly8gaGVscGVyIHZhcmlhYmxlc1xyXG5cclxuXHRcdGNvbnN0IHZlcnRleCA9IG5ldyBWZWN0b3IzKCk7XHJcblx0XHRjb25zdCBub3JtYWwgPSBuZXcgVmVjdG9yMygpO1xyXG5cdFx0Y29uc3QgdXYgPSBuZXcgVmVjdG9yMigpO1xyXG5cdFx0bGV0IFAgPSBuZXcgVmVjdG9yMygpO1xyXG5cclxuXHRcdC8vIGJ1ZmZlclxyXG5cclxuXHRcdGNvbnN0IHZlcnRpY2VzID0gW107XHJcblx0XHRjb25zdCBub3JtYWxzID0gW107XHJcblx0XHRjb25zdCB1dnMgPSBbXTtcclxuXHRcdGNvbnN0IGluZGljZXMgPSBbXTtcclxuXHJcblx0XHQvLyBjcmVhdGUgYnVmZmVyIGRhdGFcclxuXHJcblx0XHRnZW5lcmF0ZUJ1ZmZlckRhdGEoKTtcclxuXHJcblx0XHQvLyBidWlsZCBnZW9tZXRyeVxyXG5cclxuXHRcdHRoaXMuc2V0SW5kZXgoIGluZGljZXMgKTtcclxuXHRcdHRoaXMuc2V0QXR0cmlidXRlKCAncG9zaXRpb24nLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggdmVydGljZXMsIDMgKSApO1xyXG5cdFx0dGhpcy5zZXRBdHRyaWJ1dGUoICdub3JtYWwnLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggbm9ybWFscywgMyApICk7XHJcblx0XHR0aGlzLnNldEF0dHJpYnV0ZSggJ3V2JywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIHV2cywgMiApICk7XHJcblxyXG5cdFx0Ly8gZnVuY3Rpb25zXHJcblxyXG5cdFx0ZnVuY3Rpb24gZ2VuZXJhdGVCdWZmZXJEYXRhKCkge1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgdHVidWxhclNlZ21lbnRzOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRnZW5lcmF0ZVNlZ21lbnQoIGkgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdC8vIGlmIHRoZSBnZW9tZXRyeSBpcyBub3QgY2xvc2VkLCBnZW5lcmF0ZSB0aGUgbGFzdCByb3cgb2YgdmVydGljZXMgYW5kIG5vcm1hbHNcclxuXHRcdFx0Ly8gYXQgdGhlIHJlZ3VsYXIgcG9zaXRpb24gb24gdGhlIGdpdmVuIHBhdGhcclxuXHRcdFx0Ly9cclxuXHRcdFx0Ly8gaWYgdGhlIGdlb21ldHJ5IGlzIGNsb3NlZCwgZHVwbGljYXRlIHRoZSBmaXJzdCByb3cgb2YgdmVydGljZXMgYW5kIG5vcm1hbHMgKHV2cyB3aWxsIGRpZmZlcilcclxuXHJcblx0XHRcdGdlbmVyYXRlU2VnbWVudCggKCBjbG9zZWQgPT09IGZhbHNlICkgPyB0dWJ1bGFyU2VnbWVudHMgOiAwICk7XHJcblxyXG5cdFx0XHQvLyB1dnMgYXJlIGdlbmVyYXRlZCBpbiBhIHNlcGFyYXRlIGZ1bmN0aW9uLlxyXG5cdFx0XHQvLyB0aGlzIG1ha2VzIGl0IGVhc3kgY29tcHV0ZSBjb3JyZWN0IHZhbHVlcyBmb3IgY2xvc2VkIGdlb21ldHJpZXNcclxuXHJcblx0XHRcdGdlbmVyYXRlVVZzKCk7XHJcblxyXG5cdFx0XHQvLyBmaW5hbGx5IGNyZWF0ZSBmYWNlc1xyXG5cclxuXHRcdFx0Z2VuZXJhdGVJbmRpY2VzKCk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGZ1bmN0aW9uIGdlbmVyYXRlU2VnbWVudCggaSApIHtcclxuXHJcblx0XHRcdC8vIHdlIHVzZSBnZXRQb2ludEF0IHRvIHNhbXBsZSBldmVubHkgZGlzdHJpYnV0ZWQgcG9pbnRzIGZyb20gdGhlIGdpdmVuIHBhdGhcclxuXHJcblx0XHRcdFAgPSBwYXRoLmdldFBvaW50QXQoIGkgLyB0dWJ1bGFyU2VnbWVudHMsIFAgKTtcclxuXHJcblx0XHRcdC8vIHJldHJpZXZlIGNvcnJlc3BvbmRpbmcgbm9ybWFsIGFuZCBiaW5vcm1hbFxyXG5cclxuXHRcdFx0Y29uc3QgTiA9IGZyYW1lcy5ub3JtYWxzWyBpIF07XHJcblx0XHRcdGNvbnN0IEIgPSBmcmFtZXMuYmlub3JtYWxzWyBpIF07XHJcblxyXG5cdFx0XHQvLyBnZW5lcmF0ZSBub3JtYWxzIGFuZCB2ZXJ0aWNlcyBmb3IgdGhlIGN1cnJlbnQgc2VnbWVudFxyXG5cclxuXHRcdFx0Zm9yICggbGV0IGogPSAwOyBqIDw9IHJhZGlhbFNlZ21lbnRzOyBqICsrICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCB2ID0gaiAvIHJhZGlhbFNlZ21lbnRzICogTWF0aC5QSSAqIDI7XHJcblxyXG5cdFx0XHRcdGNvbnN0IHNpbiA9IE1hdGguc2luKCB2ICk7XHJcblx0XHRcdFx0Y29uc3QgY29zID0gLSBNYXRoLmNvcyggdiApO1xyXG5cclxuXHRcdFx0XHQvLyBub3JtYWxcclxuXHJcblx0XHRcdFx0bm9ybWFsLnggPSAoIGNvcyAqIE4ueCArIHNpbiAqIEIueCApO1xyXG5cdFx0XHRcdG5vcm1hbC55ID0gKCBjb3MgKiBOLnkgKyBzaW4gKiBCLnkgKTtcclxuXHRcdFx0XHRub3JtYWwueiA9ICggY29zICogTi56ICsgc2luICogQi56ICk7XHJcblx0XHRcdFx0bm9ybWFsLm5vcm1hbGl6ZSgpO1xyXG5cclxuXHRcdFx0XHRub3JtYWxzLnB1c2goIG5vcm1hbC54LCBub3JtYWwueSwgbm9ybWFsLnogKTtcclxuXHJcblx0XHRcdFx0Ly8gdmVydGV4XHJcblxyXG5cdFx0XHRcdHZlcnRleC54ID0gUC54ICsgcmFkaXVzICogbm9ybWFsLng7XHJcblx0XHRcdFx0dmVydGV4LnkgPSBQLnkgKyByYWRpdXMgKiBub3JtYWwueTtcclxuXHRcdFx0XHR2ZXJ0ZXgueiA9IFAueiArIHJhZGl1cyAqIG5vcm1hbC56O1xyXG5cclxuXHRcdFx0XHR2ZXJ0aWNlcy5wdXNoKCB2ZXJ0ZXgueCwgdmVydGV4LnksIHZlcnRleC56ICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGZ1bmN0aW9uIGdlbmVyYXRlSW5kaWNlcygpIHtcclxuXHJcblx0XHRcdGZvciAoIGxldCBqID0gMTsgaiA8PSB0dWJ1bGFyU2VnbWVudHM7IGogKysgKSB7XHJcblxyXG5cdFx0XHRcdGZvciAoIGxldCBpID0gMTsgaSA8PSByYWRpYWxTZWdtZW50czsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0XHRjb25zdCBhID0gKCByYWRpYWxTZWdtZW50cyArIDEgKSAqICggaiAtIDEgKSArICggaSAtIDEgKTtcclxuXHRcdFx0XHRcdGNvbnN0IGIgPSAoIHJhZGlhbFNlZ21lbnRzICsgMSApICogaiArICggaSAtIDEgKTtcclxuXHRcdFx0XHRcdGNvbnN0IGMgPSAoIHJhZGlhbFNlZ21lbnRzICsgMSApICogaiArIGk7XHJcblx0XHRcdFx0XHRjb25zdCBkID0gKCByYWRpYWxTZWdtZW50cyArIDEgKSAqICggaiAtIDEgKSArIGk7XHJcblxyXG5cdFx0XHRcdFx0Ly8gZmFjZXNcclxuXHJcblx0XHRcdFx0XHRpbmRpY2VzLnB1c2goIGEsIGIsIGQgKTtcclxuXHRcdFx0XHRcdGluZGljZXMucHVzaCggYiwgYywgZCApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGZ1bmN0aW9uIGdlbmVyYXRlVVZzKCkge1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDw9IHR1YnVsYXJTZWdtZW50czsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0Zm9yICggbGV0IGogPSAwOyBqIDw9IHJhZGlhbFNlZ21lbnRzOyBqICsrICkge1xyXG5cclxuXHRcdFx0XHRcdHV2LnggPSBpIC8gdHVidWxhclNlZ21lbnRzO1xyXG5cdFx0XHRcdFx0dXYueSA9IGogLyByYWRpYWxTZWdtZW50cztcclxuXHJcblx0XHRcdFx0XHR1dnMucHVzaCggdXYueCwgdXYueSApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGNvcHkoIHNvdXJjZSApIHtcclxuXHJcblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcclxuXHJcblx0XHR0aGlzLnBhcmFtZXRlcnMgPSBPYmplY3QuYXNzaWduKCB7fSwgc291cmNlLnBhcmFtZXRlcnMgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHR0b0pTT04oKSB7XHJcblxyXG5cdFx0Y29uc3QgZGF0YSA9IHN1cGVyLnRvSlNPTigpO1xyXG5cclxuXHRcdGRhdGEucGF0aCA9IHRoaXMucGFyYW1ldGVycy5wYXRoLnRvSlNPTigpO1xyXG5cclxuXHRcdHJldHVybiBkYXRhO1xyXG5cclxuXHR9XHJcblxyXG5cdHN0YXRpYyBmcm9tSlNPTiggZGF0YSApIHtcclxuXHJcblx0XHQvLyBUaGlzIG9ubHkgd29ya3MgZm9yIGJ1aWx0LWluIGN1cnZlcyAoZS5nLiBDYXRtdWxsUm9tQ3VydmUzKS5cclxuXHRcdC8vIFVzZXIgZGVmaW5lZCBjdXJ2ZXMgb3IgaW5zdGFuY2VzIG9mIEN1cnZlUGF0aCB3aWxsIG5vdCBiZSBkZXNlcmlhbGl6ZWQuXHJcblx0XHRyZXR1cm4gbmV3IFR1YmVHZW9tZXRyeShcclxuXHRcdFx0bmV3IEN1cnZlc1sgZGF0YS5wYXRoLnR5cGUgXSgpLmZyb21KU09OKCBkYXRhLnBhdGggKSxcclxuXHRcdFx0ZGF0YS50dWJ1bGFyU2VnbWVudHMsXHJcblx0XHRcdGRhdGEucmFkaXVzLFxyXG5cdFx0XHRkYXRhLnJhZGlhbFNlZ21lbnRzLFxyXG5cdFx0XHRkYXRhLmNsb3NlZFxyXG5cdFx0KTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuXHJcbmV4cG9ydCB7IFR1YmVHZW9tZXRyeSB9O1xyXG4iLCJpbXBvcnQgeyBCdWZmZXJHZW9tZXRyeSB9IGZyb20gJy4uL2NvcmUvQnVmZmVyR2VvbWV0cnkuanMnO1xyXG5pbXBvcnQgeyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlIH0gZnJvbSAnLi4vY29yZS9CdWZmZXJBdHRyaWJ1dGUuanMnO1xyXG5pbXBvcnQgeyBWZWN0b3IzIH0gZnJvbSAnLi4vbWF0aC9WZWN0b3IzLmpzJztcclxuXHJcbmNsYXNzIFdpcmVmcmFtZUdlb21ldHJ5IGV4dGVuZHMgQnVmZmVyR2VvbWV0cnkge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggZ2VvbWV0cnkgPSBudWxsICkge1xyXG5cclxuXHRcdHN1cGVyKCk7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ1dpcmVmcmFtZUdlb21ldHJ5JztcclxuXHJcblx0XHR0aGlzLnBhcmFtZXRlcnMgPSB7XHJcblx0XHRcdGdlb21ldHJ5OiBnZW9tZXRyeVxyXG5cdFx0fTtcclxuXHJcblx0XHRpZiAoIGdlb21ldHJ5ICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0Ly8gYnVmZmVyXHJcblxyXG5cdFx0XHRjb25zdCB2ZXJ0aWNlcyA9IFtdO1xyXG5cdFx0XHRjb25zdCBlZGdlcyA9IG5ldyBTZXQoKTtcclxuXHJcblx0XHRcdC8vIGhlbHBlciB2YXJpYWJsZXNcclxuXHJcblx0XHRcdGNvbnN0IHN0YXJ0ID0gbmV3IFZlY3RvcjMoKTtcclxuXHRcdFx0Y29uc3QgZW5kID0gbmV3IFZlY3RvcjMoKTtcclxuXHJcblx0XHRcdGlmICggZ2VvbWV0cnkuaW5kZXggIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdC8vIGluZGV4ZWQgQnVmZmVyR2VvbWV0cnlcclxuXHJcblx0XHRcdFx0Y29uc3QgcG9zaXRpb24gPSBnZW9tZXRyeS5hdHRyaWJ1dGVzLnBvc2l0aW9uO1xyXG5cdFx0XHRcdGNvbnN0IGluZGljZXMgPSBnZW9tZXRyeS5pbmRleDtcclxuXHRcdFx0XHRsZXQgZ3JvdXBzID0gZ2VvbWV0cnkuZ3JvdXBzO1xyXG5cclxuXHRcdFx0XHRpZiAoIGdyb3Vwcy5sZW5ndGggPT09IDAgKSB7XHJcblxyXG5cdFx0XHRcdFx0Z3JvdXBzID0gWyB7IHN0YXJ0OiAwLCBjb3VudDogaW5kaWNlcy5jb3VudCwgbWF0ZXJpYWxJbmRleDogMCB9IF07XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0Ly8gY3JlYXRlIGEgZGF0YSBzdHJ1Y3R1cmUgdGhhdCBjb250YWlucyBhbGwgZWRnZXMgd2l0aG91dCBkdXBsaWNhdGVzXHJcblxyXG5cdFx0XHRcdGZvciAoIGxldCBvID0gMCwgb2wgPSBncm91cHMubGVuZ3RoOyBvIDwgb2w7ICsrIG8gKSB7XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgZ3JvdXAgPSBncm91cHNbIG8gXTtcclxuXHJcblx0XHRcdFx0XHRjb25zdCBncm91cFN0YXJ0ID0gZ3JvdXAuc3RhcnQ7XHJcblx0XHRcdFx0XHRjb25zdCBncm91cENvdW50ID0gZ3JvdXAuY291bnQ7XHJcblxyXG5cdFx0XHRcdFx0Zm9yICggbGV0IGkgPSBncm91cFN0YXJ0LCBsID0gKCBncm91cFN0YXJ0ICsgZ3JvdXBDb3VudCApOyBpIDwgbDsgaSArPSAzICkge1xyXG5cclxuXHRcdFx0XHRcdFx0Zm9yICggbGV0IGogPSAwOyBqIDwgMzsgaiArKyApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0Y29uc3QgaW5kZXgxID0gaW5kaWNlcy5nZXRYKCBpICsgaiApO1xyXG5cdFx0XHRcdFx0XHRcdGNvbnN0IGluZGV4MiA9IGluZGljZXMuZ2V0WCggaSArICggaiArIDEgKSAlIDMgKTtcclxuXHJcblx0XHRcdFx0XHRcdFx0c3RhcnQuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggcG9zaXRpb24sIGluZGV4MSApO1xyXG5cdFx0XHRcdFx0XHRcdGVuZC5mcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbiwgaW5kZXgyICk7XHJcblxyXG5cdFx0XHRcdFx0XHRcdGlmICggaXNVbmlxdWVFZGdlKCBzdGFydCwgZW5kLCBlZGdlcyApID09PSB0cnVlICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRcdHZlcnRpY2VzLnB1c2goIHN0YXJ0LngsIHN0YXJ0LnksIHN0YXJ0LnogKTtcclxuXHRcdFx0XHRcdFx0XHRcdHZlcnRpY2VzLnB1c2goIGVuZC54LCBlbmQueSwgZW5kLnogKTtcclxuXHJcblx0XHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0Ly8gbm9uLWluZGV4ZWQgQnVmZmVyR2VvbWV0cnlcclxuXHJcblx0XHRcdFx0Y29uc3QgcG9zaXRpb24gPSBnZW9tZXRyeS5hdHRyaWJ1dGVzLnBvc2l0aW9uO1xyXG5cclxuXHRcdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSAoIHBvc2l0aW9uLmNvdW50IC8gMyApOyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0XHRmb3IgKCBsZXQgaiA9IDA7IGogPCAzOyBqICsrICkge1xyXG5cclxuXHRcdFx0XHRcdFx0Ly8gdGhyZWUgZWRnZXMgcGVyIHRyaWFuZ2xlLCBhbiBlZGdlIGlzIHJlcHJlc2VudGVkIGFzIChpbmRleDEsIGluZGV4MilcclxuXHRcdFx0XHRcdFx0Ly8gZS5nLiB0aGUgZmlyc3QgdHJpYW5nbGUgaGFzIHRoZSBmb2xsb3dpbmcgZWRnZXM6ICgwLDEpLCgxLDIpLCgyLDApXHJcblxyXG5cdFx0XHRcdFx0XHRjb25zdCBpbmRleDEgPSAzICogaSArIGo7XHJcblx0XHRcdFx0XHRcdGNvbnN0IGluZGV4MiA9IDMgKiBpICsgKCAoIGogKyAxICkgJSAzICk7XHJcblxyXG5cdFx0XHRcdFx0XHRzdGFydC5mcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbiwgaW5kZXgxICk7XHJcblx0XHRcdFx0XHRcdGVuZC5mcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbiwgaW5kZXgyICk7XHJcblxyXG5cdFx0XHRcdFx0XHRpZiAoIGlzVW5pcXVlRWRnZSggc3RhcnQsIGVuZCwgZWRnZXMgKSA9PT0gdHJ1ZSApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0dmVydGljZXMucHVzaCggc3RhcnQueCwgc3RhcnQueSwgc3RhcnQueiApO1xyXG5cdFx0XHRcdFx0XHRcdHZlcnRpY2VzLnB1c2goIGVuZC54LCBlbmQueSwgZW5kLnogKTtcclxuXHJcblx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdC8vIGJ1aWxkIGdlb21ldHJ5XHJcblxyXG5cdFx0XHR0aGlzLnNldEF0dHJpYnV0ZSggJ3Bvc2l0aW9uJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIHZlcnRpY2VzLCAzICkgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xyXG5cclxuXHRcdHRoaXMucGFyYW1ldGVycyA9IE9iamVjdC5hc3NpZ24oIHt9LCBzb3VyY2UucGFyYW1ldGVycyApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiBpc1VuaXF1ZUVkZ2UoIHN0YXJ0LCBlbmQsIGVkZ2VzICkge1xyXG5cclxuXHRjb25zdCBoYXNoMSA9IGAke3N0YXJ0Lnh9LCR7c3RhcnQueX0sJHtzdGFydC56fS0ke2VuZC54fSwke2VuZC55fSwke2VuZC56fWA7XHJcblx0Y29uc3QgaGFzaDIgPSBgJHtlbmQueH0sJHtlbmQueX0sJHtlbmQuen0tJHtzdGFydC54fSwke3N0YXJ0Lnl9LCR7c3RhcnQuen1gOyAvLyBjb2luY2lkZW50IGVkZ2VcclxuXHJcblx0aWYgKCBlZGdlcy5oYXMoIGhhc2gxICkgPT09IHRydWUgfHwgZWRnZXMuaGFzKCBoYXNoMiApID09PSB0cnVlICkge1xyXG5cclxuXHRcdHJldHVybiBmYWxzZTtcclxuXHJcblx0fSBlbHNlIHtcclxuXHJcblx0XHRlZGdlcy5hZGQoIGhhc2gxICk7XHJcblx0XHRlZGdlcy5hZGQoIGhhc2gyICk7XHJcblx0XHRyZXR1cm4gdHJ1ZTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuXHJcbmV4cG9ydCB7IFdpcmVmcmFtZUdlb21ldHJ5IH07XHJcbiIsImltcG9ydCB7IE1hdGVyaWFsIH0gZnJvbSAnLi9NYXRlcmlhbC5qcyc7XHJcbmltcG9ydCB7IENvbG9yIH0gZnJvbSAnLi4vbWF0aC9Db2xvci5qcyc7XHJcblxyXG5jbGFzcyBTaGFkb3dNYXRlcmlhbCBleHRlbmRzIE1hdGVyaWFsIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIHBhcmFtZXRlcnMgKSB7XHJcblxyXG5cdFx0c3VwZXIoKTtcclxuXHJcblx0XHR0aGlzLmlzU2hhZG93TWF0ZXJpYWwgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMudHlwZSA9ICdTaGFkb3dNYXRlcmlhbCc7XHJcblxyXG5cdFx0dGhpcy5jb2xvciA9IG5ldyBDb2xvciggMHgwMDAwMDAgKTtcclxuXHRcdHRoaXMudHJhbnNwYXJlbnQgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMuZm9nID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLnNldFZhbHVlcyggcGFyYW1ldGVycyApO1xyXG5cclxuXHR9XHJcblxyXG5cdGNvcHkoIHNvdXJjZSApIHtcclxuXHJcblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcclxuXHJcblx0XHR0aGlzLmNvbG9yLmNvcHkoIHNvdXJjZS5jb2xvciApO1xyXG5cclxuXHRcdHRoaXMuZm9nID0gc291cmNlLmZvZztcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgU2hhZG93TWF0ZXJpYWwgfTtcclxuIiwiaW1wb3J0IHsgU2hhZGVyTWF0ZXJpYWwgfSBmcm9tICcuL1NoYWRlck1hdGVyaWFsLmpzJztcclxuXHJcbmNsYXNzIFJhd1NoYWRlck1hdGVyaWFsIGV4dGVuZHMgU2hhZGVyTWF0ZXJpYWwge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggcGFyYW1ldGVycyApIHtcclxuXHJcblx0XHRzdXBlciggcGFyYW1ldGVycyApO1xyXG5cclxuXHRcdHRoaXMuaXNSYXdTaGFkZXJNYXRlcmlhbCA9IHRydWU7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ1Jhd1NoYWRlck1hdGVyaWFsJztcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgUmF3U2hhZGVyTWF0ZXJpYWwgfTtcclxuIiwiaW1wb3J0IHsgVGFuZ2VudFNwYWNlTm9ybWFsTWFwIH0gZnJvbSAnLi4vY29uc3RhbnRzLmpzJztcclxuaW1wb3J0IHsgTWF0ZXJpYWwgfSBmcm9tICcuL01hdGVyaWFsLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yMiB9IGZyb20gJy4uL21hdGgvVmVjdG9yMi5qcyc7XHJcbmltcG9ydCB7IENvbG9yIH0gZnJvbSAnLi4vbWF0aC9Db2xvci5qcyc7XHJcblxyXG5jbGFzcyBNZXNoU3RhbmRhcmRNYXRlcmlhbCBleHRlbmRzIE1hdGVyaWFsIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIHBhcmFtZXRlcnMgKSB7XHJcblxyXG5cdFx0c3VwZXIoKTtcclxuXHJcblx0XHR0aGlzLmlzTWVzaFN0YW5kYXJkTWF0ZXJpYWwgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMuZGVmaW5lcyA9IHsgJ1NUQU5EQVJEJzogJycgfTtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSAnTWVzaFN0YW5kYXJkTWF0ZXJpYWwnO1xyXG5cclxuXHRcdHRoaXMuY29sb3IgPSBuZXcgQ29sb3IoIDB4ZmZmZmZmICk7IC8vIGRpZmZ1c2VcclxuXHRcdHRoaXMucm91Z2huZXNzID0gMS4wO1xyXG5cdFx0dGhpcy5tZXRhbG5lc3MgPSAwLjA7XHJcblxyXG5cdFx0dGhpcy5tYXAgPSBudWxsO1xyXG5cclxuXHRcdHRoaXMubGlnaHRNYXAgPSBudWxsO1xyXG5cdFx0dGhpcy5saWdodE1hcEludGVuc2l0eSA9IDEuMDtcclxuXHJcblx0XHR0aGlzLmFvTWFwID0gbnVsbDtcclxuXHRcdHRoaXMuYW9NYXBJbnRlbnNpdHkgPSAxLjA7XHJcblxyXG5cdFx0dGhpcy5lbWlzc2l2ZSA9IG5ldyBDb2xvciggMHgwMDAwMDAgKTtcclxuXHRcdHRoaXMuZW1pc3NpdmVJbnRlbnNpdHkgPSAxLjA7XHJcblx0XHR0aGlzLmVtaXNzaXZlTWFwID0gbnVsbDtcclxuXHJcblx0XHR0aGlzLmJ1bXBNYXAgPSBudWxsO1xyXG5cdFx0dGhpcy5idW1wU2NhbGUgPSAxO1xyXG5cclxuXHRcdHRoaXMubm9ybWFsTWFwID0gbnVsbDtcclxuXHRcdHRoaXMubm9ybWFsTWFwVHlwZSA9IFRhbmdlbnRTcGFjZU5vcm1hbE1hcDtcclxuXHRcdHRoaXMubm9ybWFsU2NhbGUgPSBuZXcgVmVjdG9yMiggMSwgMSApO1xyXG5cclxuXHRcdHRoaXMuZGlzcGxhY2VtZW50TWFwID0gbnVsbDtcclxuXHRcdHRoaXMuZGlzcGxhY2VtZW50U2NhbGUgPSAxO1xyXG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRCaWFzID0gMDtcclxuXHJcblx0XHR0aGlzLnJvdWdobmVzc01hcCA9IG51bGw7XHJcblxyXG5cdFx0dGhpcy5tZXRhbG5lc3NNYXAgPSBudWxsO1xyXG5cclxuXHRcdHRoaXMuYWxwaGFNYXAgPSBudWxsO1xyXG5cclxuXHRcdHRoaXMuZW52TWFwID0gbnVsbDtcclxuXHRcdHRoaXMuZW52TWFwSW50ZW5zaXR5ID0gMS4wO1xyXG5cclxuXHRcdHRoaXMud2lyZWZyYW1lID0gZmFsc2U7XHJcblx0XHR0aGlzLndpcmVmcmFtZUxpbmV3aWR0aCA9IDE7XHJcblx0XHR0aGlzLndpcmVmcmFtZUxpbmVjYXAgPSAncm91bmQnO1xyXG5cdFx0dGhpcy53aXJlZnJhbWVMaW5lam9pbiA9ICdyb3VuZCc7XHJcblxyXG5cdFx0dGhpcy5mbGF0U2hhZGluZyA9IGZhbHNlO1xyXG5cclxuXHRcdHRoaXMuZm9nID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLnNldFZhbHVlcyggcGFyYW1ldGVycyApO1xyXG5cclxuXHR9XHJcblxyXG5cdGNvcHkoIHNvdXJjZSApIHtcclxuXHJcblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcclxuXHJcblx0XHR0aGlzLmRlZmluZXMgPSB7ICdTVEFOREFSRCc6ICcnIH07XHJcblxyXG5cdFx0dGhpcy5jb2xvci5jb3B5KCBzb3VyY2UuY29sb3IgKTtcclxuXHRcdHRoaXMucm91Z2huZXNzID0gc291cmNlLnJvdWdobmVzcztcclxuXHRcdHRoaXMubWV0YWxuZXNzID0gc291cmNlLm1ldGFsbmVzcztcclxuXHJcblx0XHR0aGlzLm1hcCA9IHNvdXJjZS5tYXA7XHJcblxyXG5cdFx0dGhpcy5saWdodE1hcCA9IHNvdXJjZS5saWdodE1hcDtcclxuXHRcdHRoaXMubGlnaHRNYXBJbnRlbnNpdHkgPSBzb3VyY2UubGlnaHRNYXBJbnRlbnNpdHk7XHJcblxyXG5cdFx0dGhpcy5hb01hcCA9IHNvdXJjZS5hb01hcDtcclxuXHRcdHRoaXMuYW9NYXBJbnRlbnNpdHkgPSBzb3VyY2UuYW9NYXBJbnRlbnNpdHk7XHJcblxyXG5cdFx0dGhpcy5lbWlzc2l2ZS5jb3B5KCBzb3VyY2UuZW1pc3NpdmUgKTtcclxuXHRcdHRoaXMuZW1pc3NpdmVNYXAgPSBzb3VyY2UuZW1pc3NpdmVNYXA7XHJcblx0XHR0aGlzLmVtaXNzaXZlSW50ZW5zaXR5ID0gc291cmNlLmVtaXNzaXZlSW50ZW5zaXR5O1xyXG5cclxuXHRcdHRoaXMuYnVtcE1hcCA9IHNvdXJjZS5idW1wTWFwO1xyXG5cdFx0dGhpcy5idW1wU2NhbGUgPSBzb3VyY2UuYnVtcFNjYWxlO1xyXG5cclxuXHRcdHRoaXMubm9ybWFsTWFwID0gc291cmNlLm5vcm1hbE1hcDtcclxuXHRcdHRoaXMubm9ybWFsTWFwVHlwZSA9IHNvdXJjZS5ub3JtYWxNYXBUeXBlO1xyXG5cdFx0dGhpcy5ub3JtYWxTY2FsZS5jb3B5KCBzb3VyY2Uubm9ybWFsU2NhbGUgKTtcclxuXHJcblx0XHR0aGlzLmRpc3BsYWNlbWVudE1hcCA9IHNvdXJjZS5kaXNwbGFjZW1lbnRNYXA7XHJcblx0XHR0aGlzLmRpc3BsYWNlbWVudFNjYWxlID0gc291cmNlLmRpc3BsYWNlbWVudFNjYWxlO1xyXG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRCaWFzID0gc291cmNlLmRpc3BsYWNlbWVudEJpYXM7XHJcblxyXG5cdFx0dGhpcy5yb3VnaG5lc3NNYXAgPSBzb3VyY2Uucm91Z2huZXNzTWFwO1xyXG5cclxuXHRcdHRoaXMubWV0YWxuZXNzTWFwID0gc291cmNlLm1ldGFsbmVzc01hcDtcclxuXHJcblx0XHR0aGlzLmFscGhhTWFwID0gc291cmNlLmFscGhhTWFwO1xyXG5cclxuXHRcdHRoaXMuZW52TWFwID0gc291cmNlLmVudk1hcDtcclxuXHRcdHRoaXMuZW52TWFwSW50ZW5zaXR5ID0gc291cmNlLmVudk1hcEludGVuc2l0eTtcclxuXHJcblx0XHR0aGlzLndpcmVmcmFtZSA9IHNvdXJjZS53aXJlZnJhbWU7XHJcblx0XHR0aGlzLndpcmVmcmFtZUxpbmV3aWR0aCA9IHNvdXJjZS53aXJlZnJhbWVMaW5ld2lkdGg7XHJcblx0XHR0aGlzLndpcmVmcmFtZUxpbmVjYXAgPSBzb3VyY2Uud2lyZWZyYW1lTGluZWNhcDtcclxuXHRcdHRoaXMud2lyZWZyYW1lTGluZWpvaW4gPSBzb3VyY2Uud2lyZWZyYW1lTGluZWpvaW47XHJcblxyXG5cdFx0dGhpcy5mbGF0U2hhZGluZyA9IHNvdXJjZS5mbGF0U2hhZGluZztcclxuXHJcblx0XHR0aGlzLmZvZyA9IHNvdXJjZS5mb2c7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IE1lc2hTdGFuZGFyZE1hdGVyaWFsIH07XHJcbiIsImltcG9ydCB7IFZlY3RvcjIgfSBmcm9tICcuLi9tYXRoL1ZlY3RvcjIuanMnO1xyXG5pbXBvcnQgeyBNZXNoU3RhbmRhcmRNYXRlcmlhbCB9IGZyb20gJy4vTWVzaFN0YW5kYXJkTWF0ZXJpYWwuanMnO1xyXG5pbXBvcnQgeyBDb2xvciB9IGZyb20gJy4uL21hdGgvQ29sb3IuanMnO1xyXG5pbXBvcnQgKiBhcyBNYXRoVXRpbHMgZnJvbSAnLi4vbWF0aC9NYXRoVXRpbHMuanMnO1xyXG5cclxuY2xhc3MgTWVzaFBoeXNpY2FsTWF0ZXJpYWwgZXh0ZW5kcyBNZXNoU3RhbmRhcmRNYXRlcmlhbCB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBwYXJhbWV0ZXJzICkge1xyXG5cclxuXHRcdHN1cGVyKCk7XHJcblxyXG5cdFx0dGhpcy5pc01lc2hQaHlzaWNhbE1hdGVyaWFsID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLmRlZmluZXMgPSB7XHJcblxyXG5cdFx0XHQnU1RBTkRBUkQnOiAnJyxcclxuXHRcdFx0J1BIWVNJQ0FMJzogJydcclxuXHJcblx0XHR9O1xyXG5cclxuXHRcdHRoaXMudHlwZSA9ICdNZXNoUGh5c2ljYWxNYXRlcmlhbCc7XHJcblxyXG5cdFx0dGhpcy5hbmlzb3Ryb3B5Um90YXRpb24gPSAwO1xyXG5cdFx0dGhpcy5hbmlzb3Ryb3B5TWFwID0gbnVsbDtcclxuXHJcblx0XHR0aGlzLmNsZWFyY29hdE1hcCA9IG51bGw7XHJcblx0XHR0aGlzLmNsZWFyY29hdFJvdWdobmVzcyA9IDAuMDtcclxuXHRcdHRoaXMuY2xlYXJjb2F0Um91Z2huZXNzTWFwID0gbnVsbDtcclxuXHRcdHRoaXMuY2xlYXJjb2F0Tm9ybWFsU2NhbGUgPSBuZXcgVmVjdG9yMiggMSwgMSApO1xyXG5cdFx0dGhpcy5jbGVhcmNvYXROb3JtYWxNYXAgPSBudWxsO1xyXG5cclxuXHRcdHRoaXMuaW9yID0gMS41O1xyXG5cclxuXHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eSggdGhpcywgJ3JlZmxlY3Rpdml0eScsIHtcclxuXHRcdFx0Z2V0OiBmdW5jdGlvbiAoKSB7XHJcblxyXG5cdFx0XHRcdHJldHVybiAoIE1hdGhVdGlscy5jbGFtcCggMi41ICogKCB0aGlzLmlvciAtIDEgKSAvICggdGhpcy5pb3IgKyAxICksIDAsIDEgKSApO1xyXG5cclxuXHRcdFx0fSxcclxuXHRcdFx0c2V0OiBmdW5jdGlvbiAoIHJlZmxlY3Rpdml0eSApIHtcclxuXHJcblx0XHRcdFx0dGhpcy5pb3IgPSAoIDEgKyAwLjQgKiByZWZsZWN0aXZpdHkgKSAvICggMSAtIDAuNCAqIHJlZmxlY3Rpdml0eSApO1xyXG5cclxuXHRcdFx0fVxyXG5cdFx0fSApO1xyXG5cclxuXHRcdHRoaXMuaXJpZGVzY2VuY2VNYXAgPSBudWxsO1xyXG5cdFx0dGhpcy5pcmlkZXNjZW5jZUlPUiA9IDEuMztcclxuXHRcdHRoaXMuaXJpZGVzY2VuY2VUaGlja25lc3NSYW5nZSA9IFsgMTAwLCA0MDAgXTtcclxuXHRcdHRoaXMuaXJpZGVzY2VuY2VUaGlja25lc3NNYXAgPSBudWxsO1xyXG5cclxuXHRcdHRoaXMuc2hlZW5Db2xvciA9IG5ldyBDb2xvciggMHgwMDAwMDAgKTtcclxuXHRcdHRoaXMuc2hlZW5Db2xvck1hcCA9IG51bGw7XHJcblx0XHR0aGlzLnNoZWVuUm91Z2huZXNzID0gMS4wO1xyXG5cdFx0dGhpcy5zaGVlblJvdWdobmVzc01hcCA9IG51bGw7XHJcblxyXG5cdFx0dGhpcy50cmFuc21pc3Npb25NYXAgPSBudWxsO1xyXG5cclxuXHRcdHRoaXMudGhpY2tuZXNzID0gMDtcclxuXHRcdHRoaXMudGhpY2tuZXNzTWFwID0gbnVsbDtcclxuXHRcdHRoaXMuYXR0ZW51YXRpb25EaXN0YW5jZSA9IEluZmluaXR5O1xyXG5cdFx0dGhpcy5hdHRlbnVhdGlvbkNvbG9yID0gbmV3IENvbG9yKCAxLCAxLCAxICk7XHJcblxyXG5cdFx0dGhpcy5zcGVjdWxhckludGVuc2l0eSA9IDEuMDtcclxuXHRcdHRoaXMuc3BlY3VsYXJJbnRlbnNpdHlNYXAgPSBudWxsO1xyXG5cdFx0dGhpcy5zcGVjdWxhckNvbG9yID0gbmV3IENvbG9yKCAxLCAxLCAxICk7XHJcblx0XHR0aGlzLnNwZWN1bGFyQ29sb3JNYXAgPSBudWxsO1xyXG5cclxuXHRcdHRoaXMuX2FuaXNvdHJvcHkgPSAwO1xyXG5cdFx0dGhpcy5fY2xlYXJjb2F0ID0gMDtcclxuXHRcdHRoaXMuX2lyaWRlc2NlbmNlID0gMDtcclxuXHRcdHRoaXMuX3NoZWVuID0gMC4wO1xyXG5cdFx0dGhpcy5fdHJhbnNtaXNzaW9uID0gMDtcclxuXHJcblx0XHR0aGlzLnNldFZhbHVlcyggcGFyYW1ldGVycyApO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldCBhbmlzb3Ryb3B5KCkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLl9hbmlzb3Ryb3B5O1xyXG5cclxuXHR9XHJcblxyXG5cdHNldCBhbmlzb3Ryb3B5KCB2YWx1ZSApIHtcclxuXHJcblx0XHRpZiAoIHRoaXMuX2FuaXNvdHJvcHkgPiAwICE9PSB2YWx1ZSA+IDAgKSB7XHJcblxyXG5cdFx0XHR0aGlzLnZlcnNpb24gKys7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMuX2FuaXNvdHJvcHkgPSB2YWx1ZTtcclxuXHJcblx0fVxyXG5cclxuXHRnZXQgY2xlYXJjb2F0KCkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLl9jbGVhcmNvYXQ7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0IGNsZWFyY29hdCggdmFsdWUgKSB7XHJcblxyXG5cdFx0aWYgKCB0aGlzLl9jbGVhcmNvYXQgPiAwICE9PSB2YWx1ZSA+IDAgKSB7XHJcblxyXG5cdFx0XHR0aGlzLnZlcnNpb24gKys7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMuX2NsZWFyY29hdCA9IHZhbHVlO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldCBpcmlkZXNjZW5jZSgpIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5faXJpZGVzY2VuY2U7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0IGlyaWRlc2NlbmNlKCB2YWx1ZSApIHtcclxuXHJcblx0XHRpZiAoIHRoaXMuX2lyaWRlc2NlbmNlID4gMCAhPT0gdmFsdWUgPiAwICkge1xyXG5cclxuXHRcdFx0dGhpcy52ZXJzaW9uICsrO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLl9pcmlkZXNjZW5jZSA9IHZhbHVlO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldCBzaGVlbigpIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5fc2hlZW47XHJcblxyXG5cdH1cclxuXHJcblx0c2V0IHNoZWVuKCB2YWx1ZSApIHtcclxuXHJcblx0XHRpZiAoIHRoaXMuX3NoZWVuID4gMCAhPT0gdmFsdWUgPiAwICkge1xyXG5cclxuXHRcdFx0dGhpcy52ZXJzaW9uICsrO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLl9zaGVlbiA9IHZhbHVlO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldCB0cmFuc21pc3Npb24oKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuX3RyYW5zbWlzc2lvbjtcclxuXHJcblx0fVxyXG5cclxuXHRzZXQgdHJhbnNtaXNzaW9uKCB2YWx1ZSApIHtcclxuXHJcblx0XHRpZiAoIHRoaXMuX3RyYW5zbWlzc2lvbiA+IDAgIT09IHZhbHVlID4gMCApIHtcclxuXHJcblx0XHRcdHRoaXMudmVyc2lvbiArKztcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5fdHJhbnNtaXNzaW9uID0gdmFsdWU7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xyXG5cclxuXHRcdHRoaXMuZGVmaW5lcyA9IHtcclxuXHJcblx0XHRcdCdTVEFOREFSRCc6ICcnLFxyXG5cdFx0XHQnUEhZU0lDQUwnOiAnJ1xyXG5cclxuXHRcdH07XHJcblxyXG5cdFx0dGhpcy5hbmlzb3Ryb3B5ID0gc291cmNlLmFuaXNvdHJvcHk7XHJcblx0XHR0aGlzLmFuaXNvdHJvcHlSb3RhdGlvbiA9IHNvdXJjZS5hbmlzb3Ryb3B5Um90YXRpb247XHJcblx0XHR0aGlzLmFuaXNvdHJvcHlNYXAgPSBzb3VyY2UuYW5pc290cm9weU1hcDtcclxuXHJcblx0XHR0aGlzLmNsZWFyY29hdCA9IHNvdXJjZS5jbGVhcmNvYXQ7XHJcblx0XHR0aGlzLmNsZWFyY29hdE1hcCA9IHNvdXJjZS5jbGVhcmNvYXRNYXA7XHJcblx0XHR0aGlzLmNsZWFyY29hdFJvdWdobmVzcyA9IHNvdXJjZS5jbGVhcmNvYXRSb3VnaG5lc3M7XHJcblx0XHR0aGlzLmNsZWFyY29hdFJvdWdobmVzc01hcCA9IHNvdXJjZS5jbGVhcmNvYXRSb3VnaG5lc3NNYXA7XHJcblx0XHR0aGlzLmNsZWFyY29hdE5vcm1hbE1hcCA9IHNvdXJjZS5jbGVhcmNvYXROb3JtYWxNYXA7XHJcblx0XHR0aGlzLmNsZWFyY29hdE5vcm1hbFNjYWxlLmNvcHkoIHNvdXJjZS5jbGVhcmNvYXROb3JtYWxTY2FsZSApO1xyXG5cclxuXHRcdHRoaXMuaW9yID0gc291cmNlLmlvcjtcclxuXHJcblx0XHR0aGlzLmlyaWRlc2NlbmNlID0gc291cmNlLmlyaWRlc2NlbmNlO1xyXG5cdFx0dGhpcy5pcmlkZXNjZW5jZU1hcCA9IHNvdXJjZS5pcmlkZXNjZW5jZU1hcDtcclxuXHRcdHRoaXMuaXJpZGVzY2VuY2VJT1IgPSBzb3VyY2UuaXJpZGVzY2VuY2VJT1I7XHJcblx0XHR0aGlzLmlyaWRlc2NlbmNlVGhpY2tuZXNzUmFuZ2UgPSBbIC4uLnNvdXJjZS5pcmlkZXNjZW5jZVRoaWNrbmVzc1JhbmdlIF07XHJcblx0XHR0aGlzLmlyaWRlc2NlbmNlVGhpY2tuZXNzTWFwID0gc291cmNlLmlyaWRlc2NlbmNlVGhpY2tuZXNzTWFwO1xyXG5cclxuXHRcdHRoaXMuc2hlZW4gPSBzb3VyY2Uuc2hlZW47XHJcblx0XHR0aGlzLnNoZWVuQ29sb3IuY29weSggc291cmNlLnNoZWVuQ29sb3IgKTtcclxuXHRcdHRoaXMuc2hlZW5Db2xvck1hcCA9IHNvdXJjZS5zaGVlbkNvbG9yTWFwO1xyXG5cdFx0dGhpcy5zaGVlblJvdWdobmVzcyA9IHNvdXJjZS5zaGVlblJvdWdobmVzcztcclxuXHRcdHRoaXMuc2hlZW5Sb3VnaG5lc3NNYXAgPSBzb3VyY2Uuc2hlZW5Sb3VnaG5lc3NNYXA7XHJcblxyXG5cdFx0dGhpcy50cmFuc21pc3Npb24gPSBzb3VyY2UudHJhbnNtaXNzaW9uO1xyXG5cdFx0dGhpcy50cmFuc21pc3Npb25NYXAgPSBzb3VyY2UudHJhbnNtaXNzaW9uTWFwO1xyXG5cclxuXHRcdHRoaXMudGhpY2tuZXNzID0gc291cmNlLnRoaWNrbmVzcztcclxuXHRcdHRoaXMudGhpY2tuZXNzTWFwID0gc291cmNlLnRoaWNrbmVzc01hcDtcclxuXHRcdHRoaXMuYXR0ZW51YXRpb25EaXN0YW5jZSA9IHNvdXJjZS5hdHRlbnVhdGlvbkRpc3RhbmNlO1xyXG5cdFx0dGhpcy5hdHRlbnVhdGlvbkNvbG9yLmNvcHkoIHNvdXJjZS5hdHRlbnVhdGlvbkNvbG9yICk7XHJcblxyXG5cdFx0dGhpcy5zcGVjdWxhckludGVuc2l0eSA9IHNvdXJjZS5zcGVjdWxhckludGVuc2l0eTtcclxuXHRcdHRoaXMuc3BlY3VsYXJJbnRlbnNpdHlNYXAgPSBzb3VyY2Uuc3BlY3VsYXJJbnRlbnNpdHlNYXA7XHJcblx0XHR0aGlzLnNwZWN1bGFyQ29sb3IuY29weSggc291cmNlLnNwZWN1bGFyQ29sb3IgKTtcclxuXHRcdHRoaXMuc3BlY3VsYXJDb2xvck1hcCA9IHNvdXJjZS5zcGVjdWxhckNvbG9yTWFwO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBNZXNoUGh5c2ljYWxNYXRlcmlhbCB9O1xyXG4iLCJpbXBvcnQgeyBNdWx0aXBseU9wZXJhdGlvbiwgVGFuZ2VudFNwYWNlTm9ybWFsTWFwIH0gZnJvbSAnLi4vY29uc3RhbnRzLmpzJztcclxuaW1wb3J0IHsgTWF0ZXJpYWwgfSBmcm9tICcuL01hdGVyaWFsLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yMiB9IGZyb20gJy4uL21hdGgvVmVjdG9yMi5qcyc7XHJcbmltcG9ydCB7IENvbG9yIH0gZnJvbSAnLi4vbWF0aC9Db2xvci5qcyc7XHJcblxyXG5jbGFzcyBNZXNoUGhvbmdNYXRlcmlhbCBleHRlbmRzIE1hdGVyaWFsIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIHBhcmFtZXRlcnMgKSB7XHJcblxyXG5cdFx0c3VwZXIoKTtcclxuXHJcblx0XHR0aGlzLmlzTWVzaFBob25nTWF0ZXJpYWwgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMudHlwZSA9ICdNZXNoUGhvbmdNYXRlcmlhbCc7XHJcblxyXG5cdFx0dGhpcy5jb2xvciA9IG5ldyBDb2xvciggMHhmZmZmZmYgKTsgLy8gZGlmZnVzZVxyXG5cdFx0dGhpcy5zcGVjdWxhciA9IG5ldyBDb2xvciggMHgxMTExMTEgKTtcclxuXHRcdHRoaXMuc2hpbmluZXNzID0gMzA7XHJcblxyXG5cdFx0dGhpcy5tYXAgPSBudWxsO1xyXG5cclxuXHRcdHRoaXMubGlnaHRNYXAgPSBudWxsO1xyXG5cdFx0dGhpcy5saWdodE1hcEludGVuc2l0eSA9IDEuMDtcclxuXHJcblx0XHR0aGlzLmFvTWFwID0gbnVsbDtcclxuXHRcdHRoaXMuYW9NYXBJbnRlbnNpdHkgPSAxLjA7XHJcblxyXG5cdFx0dGhpcy5lbWlzc2l2ZSA9IG5ldyBDb2xvciggMHgwMDAwMDAgKTtcclxuXHRcdHRoaXMuZW1pc3NpdmVJbnRlbnNpdHkgPSAxLjA7XHJcblx0XHR0aGlzLmVtaXNzaXZlTWFwID0gbnVsbDtcclxuXHJcblx0XHR0aGlzLmJ1bXBNYXAgPSBudWxsO1xyXG5cdFx0dGhpcy5idW1wU2NhbGUgPSAxO1xyXG5cclxuXHRcdHRoaXMubm9ybWFsTWFwID0gbnVsbDtcclxuXHRcdHRoaXMubm9ybWFsTWFwVHlwZSA9IFRhbmdlbnRTcGFjZU5vcm1hbE1hcDtcclxuXHRcdHRoaXMubm9ybWFsU2NhbGUgPSBuZXcgVmVjdG9yMiggMSwgMSApO1xyXG5cclxuXHRcdHRoaXMuZGlzcGxhY2VtZW50TWFwID0gbnVsbDtcclxuXHRcdHRoaXMuZGlzcGxhY2VtZW50U2NhbGUgPSAxO1xyXG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRCaWFzID0gMDtcclxuXHJcblx0XHR0aGlzLnNwZWN1bGFyTWFwID0gbnVsbDtcclxuXHJcblx0XHR0aGlzLmFscGhhTWFwID0gbnVsbDtcclxuXHJcblx0XHR0aGlzLmVudk1hcCA9IG51bGw7XHJcblx0XHR0aGlzLmNvbWJpbmUgPSBNdWx0aXBseU9wZXJhdGlvbjtcclxuXHRcdHRoaXMucmVmbGVjdGl2aXR5ID0gMTtcclxuXHRcdHRoaXMucmVmcmFjdGlvblJhdGlvID0gMC45ODtcclxuXHJcblx0XHR0aGlzLndpcmVmcmFtZSA9IGZhbHNlO1xyXG5cdFx0dGhpcy53aXJlZnJhbWVMaW5ld2lkdGggPSAxO1xyXG5cdFx0dGhpcy53aXJlZnJhbWVMaW5lY2FwID0gJ3JvdW5kJztcclxuXHRcdHRoaXMud2lyZWZyYW1lTGluZWpvaW4gPSAncm91bmQnO1xyXG5cclxuXHRcdHRoaXMuZmxhdFNoYWRpbmcgPSBmYWxzZTtcclxuXHJcblx0XHR0aGlzLmZvZyA9IHRydWU7XHJcblxyXG5cdFx0dGhpcy5zZXRWYWx1ZXMoIHBhcmFtZXRlcnMgKTtcclxuXHJcblx0fVxyXG5cclxuXHRjb3B5KCBzb3VyY2UgKSB7XHJcblxyXG5cdFx0c3VwZXIuY29weSggc291cmNlICk7XHJcblxyXG5cdFx0dGhpcy5jb2xvci5jb3B5KCBzb3VyY2UuY29sb3IgKTtcclxuXHRcdHRoaXMuc3BlY3VsYXIuY29weSggc291cmNlLnNwZWN1bGFyICk7XHJcblx0XHR0aGlzLnNoaW5pbmVzcyA9IHNvdXJjZS5zaGluaW5lc3M7XHJcblxyXG5cdFx0dGhpcy5tYXAgPSBzb3VyY2UubWFwO1xyXG5cclxuXHRcdHRoaXMubGlnaHRNYXAgPSBzb3VyY2UubGlnaHRNYXA7XHJcblx0XHR0aGlzLmxpZ2h0TWFwSW50ZW5zaXR5ID0gc291cmNlLmxpZ2h0TWFwSW50ZW5zaXR5O1xyXG5cclxuXHRcdHRoaXMuYW9NYXAgPSBzb3VyY2UuYW9NYXA7XHJcblx0XHR0aGlzLmFvTWFwSW50ZW5zaXR5ID0gc291cmNlLmFvTWFwSW50ZW5zaXR5O1xyXG5cclxuXHRcdHRoaXMuZW1pc3NpdmUuY29weSggc291cmNlLmVtaXNzaXZlICk7XHJcblx0XHR0aGlzLmVtaXNzaXZlTWFwID0gc291cmNlLmVtaXNzaXZlTWFwO1xyXG5cdFx0dGhpcy5lbWlzc2l2ZUludGVuc2l0eSA9IHNvdXJjZS5lbWlzc2l2ZUludGVuc2l0eTtcclxuXHJcblx0XHR0aGlzLmJ1bXBNYXAgPSBzb3VyY2UuYnVtcE1hcDtcclxuXHRcdHRoaXMuYnVtcFNjYWxlID0gc291cmNlLmJ1bXBTY2FsZTtcclxuXHJcblx0XHR0aGlzLm5vcm1hbE1hcCA9IHNvdXJjZS5ub3JtYWxNYXA7XHJcblx0XHR0aGlzLm5vcm1hbE1hcFR5cGUgPSBzb3VyY2Uubm9ybWFsTWFwVHlwZTtcclxuXHRcdHRoaXMubm9ybWFsU2NhbGUuY29weSggc291cmNlLm5vcm1hbFNjYWxlICk7XHJcblxyXG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRNYXAgPSBzb3VyY2UuZGlzcGxhY2VtZW50TWFwO1xyXG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRTY2FsZSA9IHNvdXJjZS5kaXNwbGFjZW1lbnRTY2FsZTtcclxuXHRcdHRoaXMuZGlzcGxhY2VtZW50QmlhcyA9IHNvdXJjZS5kaXNwbGFjZW1lbnRCaWFzO1xyXG5cclxuXHRcdHRoaXMuc3BlY3VsYXJNYXAgPSBzb3VyY2Uuc3BlY3VsYXJNYXA7XHJcblxyXG5cdFx0dGhpcy5hbHBoYU1hcCA9IHNvdXJjZS5hbHBoYU1hcDtcclxuXHJcblx0XHR0aGlzLmVudk1hcCA9IHNvdXJjZS5lbnZNYXA7XHJcblx0XHR0aGlzLmNvbWJpbmUgPSBzb3VyY2UuY29tYmluZTtcclxuXHRcdHRoaXMucmVmbGVjdGl2aXR5ID0gc291cmNlLnJlZmxlY3Rpdml0eTtcclxuXHRcdHRoaXMucmVmcmFjdGlvblJhdGlvID0gc291cmNlLnJlZnJhY3Rpb25SYXRpbztcclxuXHJcblx0XHR0aGlzLndpcmVmcmFtZSA9IHNvdXJjZS53aXJlZnJhbWU7XHJcblx0XHR0aGlzLndpcmVmcmFtZUxpbmV3aWR0aCA9IHNvdXJjZS53aXJlZnJhbWVMaW5ld2lkdGg7XHJcblx0XHR0aGlzLndpcmVmcmFtZUxpbmVjYXAgPSBzb3VyY2Uud2lyZWZyYW1lTGluZWNhcDtcclxuXHRcdHRoaXMud2lyZWZyYW1lTGluZWpvaW4gPSBzb3VyY2Uud2lyZWZyYW1lTGluZWpvaW47XHJcblxyXG5cdFx0dGhpcy5mbGF0U2hhZGluZyA9IHNvdXJjZS5mbGF0U2hhZGluZztcclxuXHJcblx0XHR0aGlzLmZvZyA9IHNvdXJjZS5mb2c7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IE1lc2hQaG9uZ01hdGVyaWFsIH07XHJcbiIsImltcG9ydCB7IFRhbmdlbnRTcGFjZU5vcm1hbE1hcCB9IGZyb20gJy4uL2NvbnN0YW50cy5qcyc7XHJcbmltcG9ydCB7IE1hdGVyaWFsIH0gZnJvbSAnLi9NYXRlcmlhbC5qcyc7XHJcbmltcG9ydCB7IFZlY3RvcjIgfSBmcm9tICcuLi9tYXRoL1ZlY3RvcjIuanMnO1xyXG5pbXBvcnQgeyBDb2xvciB9IGZyb20gJy4uL21hdGgvQ29sb3IuanMnO1xyXG5cclxuY2xhc3MgTWVzaFRvb25NYXRlcmlhbCBleHRlbmRzIE1hdGVyaWFsIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIHBhcmFtZXRlcnMgKSB7XHJcblxyXG5cdFx0c3VwZXIoKTtcclxuXHJcblx0XHR0aGlzLmlzTWVzaFRvb25NYXRlcmlhbCA9IHRydWU7XHJcblxyXG5cdFx0dGhpcy5kZWZpbmVzID0geyAnVE9PTic6ICcnIH07XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ01lc2hUb29uTWF0ZXJpYWwnO1xyXG5cclxuXHRcdHRoaXMuY29sb3IgPSBuZXcgQ29sb3IoIDB4ZmZmZmZmICk7XHJcblxyXG5cdFx0dGhpcy5tYXAgPSBudWxsO1xyXG5cdFx0dGhpcy5ncmFkaWVudE1hcCA9IG51bGw7XHJcblxyXG5cdFx0dGhpcy5saWdodE1hcCA9IG51bGw7XHJcblx0XHR0aGlzLmxpZ2h0TWFwSW50ZW5zaXR5ID0gMS4wO1xyXG5cclxuXHRcdHRoaXMuYW9NYXAgPSBudWxsO1xyXG5cdFx0dGhpcy5hb01hcEludGVuc2l0eSA9IDEuMDtcclxuXHJcblx0XHR0aGlzLmVtaXNzaXZlID0gbmV3IENvbG9yKCAweDAwMDAwMCApO1xyXG5cdFx0dGhpcy5lbWlzc2l2ZUludGVuc2l0eSA9IDEuMDtcclxuXHRcdHRoaXMuZW1pc3NpdmVNYXAgPSBudWxsO1xyXG5cclxuXHRcdHRoaXMuYnVtcE1hcCA9IG51bGw7XHJcblx0XHR0aGlzLmJ1bXBTY2FsZSA9IDE7XHJcblxyXG5cdFx0dGhpcy5ub3JtYWxNYXAgPSBudWxsO1xyXG5cdFx0dGhpcy5ub3JtYWxNYXBUeXBlID0gVGFuZ2VudFNwYWNlTm9ybWFsTWFwO1xyXG5cdFx0dGhpcy5ub3JtYWxTY2FsZSA9IG5ldyBWZWN0b3IyKCAxLCAxICk7XHJcblxyXG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRNYXAgPSBudWxsO1xyXG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRTY2FsZSA9IDE7XHJcblx0XHR0aGlzLmRpc3BsYWNlbWVudEJpYXMgPSAwO1xyXG5cclxuXHRcdHRoaXMuYWxwaGFNYXAgPSBudWxsO1xyXG5cclxuXHRcdHRoaXMud2lyZWZyYW1lID0gZmFsc2U7XHJcblx0XHR0aGlzLndpcmVmcmFtZUxpbmV3aWR0aCA9IDE7XHJcblx0XHR0aGlzLndpcmVmcmFtZUxpbmVjYXAgPSAncm91bmQnO1xyXG5cdFx0dGhpcy53aXJlZnJhbWVMaW5lam9pbiA9ICdyb3VuZCc7XHJcblxyXG5cdFx0dGhpcy5mb2cgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMuc2V0VmFsdWVzKCBwYXJhbWV0ZXJzICk7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xyXG5cclxuXHRcdHRoaXMuY29sb3IuY29weSggc291cmNlLmNvbG9yICk7XHJcblxyXG5cdFx0dGhpcy5tYXAgPSBzb3VyY2UubWFwO1xyXG5cdFx0dGhpcy5ncmFkaWVudE1hcCA9IHNvdXJjZS5ncmFkaWVudE1hcDtcclxuXHJcblx0XHR0aGlzLmxpZ2h0TWFwID0gc291cmNlLmxpZ2h0TWFwO1xyXG5cdFx0dGhpcy5saWdodE1hcEludGVuc2l0eSA9IHNvdXJjZS5saWdodE1hcEludGVuc2l0eTtcclxuXHJcblx0XHR0aGlzLmFvTWFwID0gc291cmNlLmFvTWFwO1xyXG5cdFx0dGhpcy5hb01hcEludGVuc2l0eSA9IHNvdXJjZS5hb01hcEludGVuc2l0eTtcclxuXHJcblx0XHR0aGlzLmVtaXNzaXZlLmNvcHkoIHNvdXJjZS5lbWlzc2l2ZSApO1xyXG5cdFx0dGhpcy5lbWlzc2l2ZU1hcCA9IHNvdXJjZS5lbWlzc2l2ZU1hcDtcclxuXHRcdHRoaXMuZW1pc3NpdmVJbnRlbnNpdHkgPSBzb3VyY2UuZW1pc3NpdmVJbnRlbnNpdHk7XHJcblxyXG5cdFx0dGhpcy5idW1wTWFwID0gc291cmNlLmJ1bXBNYXA7XHJcblx0XHR0aGlzLmJ1bXBTY2FsZSA9IHNvdXJjZS5idW1wU2NhbGU7XHJcblxyXG5cdFx0dGhpcy5ub3JtYWxNYXAgPSBzb3VyY2Uubm9ybWFsTWFwO1xyXG5cdFx0dGhpcy5ub3JtYWxNYXBUeXBlID0gc291cmNlLm5vcm1hbE1hcFR5cGU7XHJcblx0XHR0aGlzLm5vcm1hbFNjYWxlLmNvcHkoIHNvdXJjZS5ub3JtYWxTY2FsZSApO1xyXG5cclxuXHRcdHRoaXMuZGlzcGxhY2VtZW50TWFwID0gc291cmNlLmRpc3BsYWNlbWVudE1hcDtcclxuXHRcdHRoaXMuZGlzcGxhY2VtZW50U2NhbGUgPSBzb3VyY2UuZGlzcGxhY2VtZW50U2NhbGU7XHJcblx0XHR0aGlzLmRpc3BsYWNlbWVudEJpYXMgPSBzb3VyY2UuZGlzcGxhY2VtZW50QmlhcztcclxuXHJcblx0XHR0aGlzLmFscGhhTWFwID0gc291cmNlLmFscGhhTWFwO1xyXG5cclxuXHRcdHRoaXMud2lyZWZyYW1lID0gc291cmNlLndpcmVmcmFtZTtcclxuXHRcdHRoaXMud2lyZWZyYW1lTGluZXdpZHRoID0gc291cmNlLndpcmVmcmFtZUxpbmV3aWR0aDtcclxuXHRcdHRoaXMud2lyZWZyYW1lTGluZWNhcCA9IHNvdXJjZS53aXJlZnJhbWVMaW5lY2FwO1xyXG5cdFx0dGhpcy53aXJlZnJhbWVMaW5lam9pbiA9IHNvdXJjZS53aXJlZnJhbWVMaW5lam9pbjtcclxuXHJcblx0XHR0aGlzLmZvZyA9IHNvdXJjZS5mb2c7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IE1lc2hUb29uTWF0ZXJpYWwgfTtcclxuIiwiaW1wb3J0IHsgVGFuZ2VudFNwYWNlTm9ybWFsTWFwIH0gZnJvbSAnLi4vY29uc3RhbnRzLmpzJztcclxuaW1wb3J0IHsgTWF0ZXJpYWwgfSBmcm9tICcuL01hdGVyaWFsLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yMiB9IGZyb20gJy4uL21hdGgvVmVjdG9yMi5qcyc7XHJcblxyXG5jbGFzcyBNZXNoTm9ybWFsTWF0ZXJpYWwgZXh0ZW5kcyBNYXRlcmlhbCB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBwYXJhbWV0ZXJzICkge1xyXG5cclxuXHRcdHN1cGVyKCk7XHJcblxyXG5cdFx0dGhpcy5pc01lc2hOb3JtYWxNYXRlcmlhbCA9IHRydWU7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ01lc2hOb3JtYWxNYXRlcmlhbCc7XHJcblxyXG5cdFx0dGhpcy5idW1wTWFwID0gbnVsbDtcclxuXHRcdHRoaXMuYnVtcFNjYWxlID0gMTtcclxuXHJcblx0XHR0aGlzLm5vcm1hbE1hcCA9IG51bGw7XHJcblx0XHR0aGlzLm5vcm1hbE1hcFR5cGUgPSBUYW5nZW50U3BhY2VOb3JtYWxNYXA7XHJcblx0XHR0aGlzLm5vcm1hbFNjYWxlID0gbmV3IFZlY3RvcjIoIDEsIDEgKTtcclxuXHJcblx0XHR0aGlzLmRpc3BsYWNlbWVudE1hcCA9IG51bGw7XHJcblx0XHR0aGlzLmRpc3BsYWNlbWVudFNjYWxlID0gMTtcclxuXHRcdHRoaXMuZGlzcGxhY2VtZW50QmlhcyA9IDA7XHJcblxyXG5cdFx0dGhpcy53aXJlZnJhbWUgPSBmYWxzZTtcclxuXHRcdHRoaXMud2lyZWZyYW1lTGluZXdpZHRoID0gMTtcclxuXHJcblx0XHR0aGlzLmZsYXRTaGFkaW5nID0gZmFsc2U7XHJcblxyXG5cdFx0dGhpcy5zZXRWYWx1ZXMoIHBhcmFtZXRlcnMgKTtcclxuXHJcblx0fVxyXG5cclxuXHRjb3B5KCBzb3VyY2UgKSB7XHJcblxyXG5cdFx0c3VwZXIuY29weSggc291cmNlICk7XHJcblxyXG5cdFx0dGhpcy5idW1wTWFwID0gc291cmNlLmJ1bXBNYXA7XHJcblx0XHR0aGlzLmJ1bXBTY2FsZSA9IHNvdXJjZS5idW1wU2NhbGU7XHJcblxyXG5cdFx0dGhpcy5ub3JtYWxNYXAgPSBzb3VyY2Uubm9ybWFsTWFwO1xyXG5cdFx0dGhpcy5ub3JtYWxNYXBUeXBlID0gc291cmNlLm5vcm1hbE1hcFR5cGU7XHJcblx0XHR0aGlzLm5vcm1hbFNjYWxlLmNvcHkoIHNvdXJjZS5ub3JtYWxTY2FsZSApO1xyXG5cclxuXHRcdHRoaXMuZGlzcGxhY2VtZW50TWFwID0gc291cmNlLmRpc3BsYWNlbWVudE1hcDtcclxuXHRcdHRoaXMuZGlzcGxhY2VtZW50U2NhbGUgPSBzb3VyY2UuZGlzcGxhY2VtZW50U2NhbGU7XHJcblx0XHR0aGlzLmRpc3BsYWNlbWVudEJpYXMgPSBzb3VyY2UuZGlzcGxhY2VtZW50QmlhcztcclxuXHJcblx0XHR0aGlzLndpcmVmcmFtZSA9IHNvdXJjZS53aXJlZnJhbWU7XHJcblx0XHR0aGlzLndpcmVmcmFtZUxpbmV3aWR0aCA9IHNvdXJjZS53aXJlZnJhbWVMaW5ld2lkdGg7XHJcblxyXG5cdFx0dGhpcy5mbGF0U2hhZGluZyA9IHNvdXJjZS5mbGF0U2hhZGluZztcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgTWVzaE5vcm1hbE1hdGVyaWFsIH07XHJcbiIsImltcG9ydCB7IE11bHRpcGx5T3BlcmF0aW9uLCBUYW5nZW50U3BhY2VOb3JtYWxNYXAgfSBmcm9tICcuLi9jb25zdGFudHMuanMnO1xyXG5pbXBvcnQgeyBNYXRlcmlhbCB9IGZyb20gJy4vTWF0ZXJpYWwuanMnO1xyXG5pbXBvcnQgeyBWZWN0b3IyIH0gZnJvbSAnLi4vbWF0aC9WZWN0b3IyLmpzJztcclxuaW1wb3J0IHsgQ29sb3IgfSBmcm9tICcuLi9tYXRoL0NvbG9yLmpzJztcclxuXHJcbmNsYXNzIE1lc2hMYW1iZXJ0TWF0ZXJpYWwgZXh0ZW5kcyBNYXRlcmlhbCB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBwYXJhbWV0ZXJzICkge1xyXG5cclxuXHRcdHN1cGVyKCk7XHJcblxyXG5cdFx0dGhpcy5pc01lc2hMYW1iZXJ0TWF0ZXJpYWwgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMudHlwZSA9ICdNZXNoTGFtYmVydE1hdGVyaWFsJztcclxuXHJcblx0XHR0aGlzLmNvbG9yID0gbmV3IENvbG9yKCAweGZmZmZmZiApOyAvLyBkaWZmdXNlXHJcblxyXG5cdFx0dGhpcy5tYXAgPSBudWxsO1xyXG5cclxuXHRcdHRoaXMubGlnaHRNYXAgPSBudWxsO1xyXG5cdFx0dGhpcy5saWdodE1hcEludGVuc2l0eSA9IDEuMDtcclxuXHJcblx0XHR0aGlzLmFvTWFwID0gbnVsbDtcclxuXHRcdHRoaXMuYW9NYXBJbnRlbnNpdHkgPSAxLjA7XHJcblxyXG5cdFx0dGhpcy5lbWlzc2l2ZSA9IG5ldyBDb2xvciggMHgwMDAwMDAgKTtcclxuXHRcdHRoaXMuZW1pc3NpdmVJbnRlbnNpdHkgPSAxLjA7XHJcblx0XHR0aGlzLmVtaXNzaXZlTWFwID0gbnVsbDtcclxuXHJcblx0XHR0aGlzLmJ1bXBNYXAgPSBudWxsO1xyXG5cdFx0dGhpcy5idW1wU2NhbGUgPSAxO1xyXG5cclxuXHRcdHRoaXMubm9ybWFsTWFwID0gbnVsbDtcclxuXHRcdHRoaXMubm9ybWFsTWFwVHlwZSA9IFRhbmdlbnRTcGFjZU5vcm1hbE1hcDtcclxuXHRcdHRoaXMubm9ybWFsU2NhbGUgPSBuZXcgVmVjdG9yMiggMSwgMSApO1xyXG5cclxuXHRcdHRoaXMuZGlzcGxhY2VtZW50TWFwID0gbnVsbDtcclxuXHRcdHRoaXMuZGlzcGxhY2VtZW50U2NhbGUgPSAxO1xyXG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRCaWFzID0gMDtcclxuXHJcblx0XHR0aGlzLnNwZWN1bGFyTWFwID0gbnVsbDtcclxuXHJcblx0XHR0aGlzLmFscGhhTWFwID0gbnVsbDtcclxuXHJcblx0XHR0aGlzLmVudk1hcCA9IG51bGw7XHJcblx0XHR0aGlzLmNvbWJpbmUgPSBNdWx0aXBseU9wZXJhdGlvbjtcclxuXHRcdHRoaXMucmVmbGVjdGl2aXR5ID0gMTtcclxuXHRcdHRoaXMucmVmcmFjdGlvblJhdGlvID0gMC45ODtcclxuXHJcblx0XHR0aGlzLndpcmVmcmFtZSA9IGZhbHNlO1xyXG5cdFx0dGhpcy53aXJlZnJhbWVMaW5ld2lkdGggPSAxO1xyXG5cdFx0dGhpcy53aXJlZnJhbWVMaW5lY2FwID0gJ3JvdW5kJztcclxuXHRcdHRoaXMud2lyZWZyYW1lTGluZWpvaW4gPSAncm91bmQnO1xyXG5cclxuXHRcdHRoaXMuZmxhdFNoYWRpbmcgPSBmYWxzZTtcclxuXHJcblx0XHR0aGlzLmZvZyA9IHRydWU7XHJcblxyXG5cdFx0dGhpcy5zZXRWYWx1ZXMoIHBhcmFtZXRlcnMgKTtcclxuXHJcblx0fVxyXG5cclxuXHRjb3B5KCBzb3VyY2UgKSB7XHJcblxyXG5cdFx0c3VwZXIuY29weSggc291cmNlICk7XHJcblxyXG5cdFx0dGhpcy5jb2xvci5jb3B5KCBzb3VyY2UuY29sb3IgKTtcclxuXHJcblx0XHR0aGlzLm1hcCA9IHNvdXJjZS5tYXA7XHJcblxyXG5cdFx0dGhpcy5saWdodE1hcCA9IHNvdXJjZS5saWdodE1hcDtcclxuXHRcdHRoaXMubGlnaHRNYXBJbnRlbnNpdHkgPSBzb3VyY2UubGlnaHRNYXBJbnRlbnNpdHk7XHJcblxyXG5cdFx0dGhpcy5hb01hcCA9IHNvdXJjZS5hb01hcDtcclxuXHRcdHRoaXMuYW9NYXBJbnRlbnNpdHkgPSBzb3VyY2UuYW9NYXBJbnRlbnNpdHk7XHJcblxyXG5cdFx0dGhpcy5lbWlzc2l2ZS5jb3B5KCBzb3VyY2UuZW1pc3NpdmUgKTtcclxuXHRcdHRoaXMuZW1pc3NpdmVNYXAgPSBzb3VyY2UuZW1pc3NpdmVNYXA7XHJcblx0XHR0aGlzLmVtaXNzaXZlSW50ZW5zaXR5ID0gc291cmNlLmVtaXNzaXZlSW50ZW5zaXR5O1xyXG5cclxuXHRcdHRoaXMuYnVtcE1hcCA9IHNvdXJjZS5idW1wTWFwO1xyXG5cdFx0dGhpcy5idW1wU2NhbGUgPSBzb3VyY2UuYnVtcFNjYWxlO1xyXG5cclxuXHRcdHRoaXMubm9ybWFsTWFwID0gc291cmNlLm5vcm1hbE1hcDtcclxuXHRcdHRoaXMubm9ybWFsTWFwVHlwZSA9IHNvdXJjZS5ub3JtYWxNYXBUeXBlO1xyXG5cdFx0dGhpcy5ub3JtYWxTY2FsZS5jb3B5KCBzb3VyY2Uubm9ybWFsU2NhbGUgKTtcclxuXHJcblx0XHR0aGlzLmRpc3BsYWNlbWVudE1hcCA9IHNvdXJjZS5kaXNwbGFjZW1lbnRNYXA7XHJcblx0XHR0aGlzLmRpc3BsYWNlbWVudFNjYWxlID0gc291cmNlLmRpc3BsYWNlbWVudFNjYWxlO1xyXG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRCaWFzID0gc291cmNlLmRpc3BsYWNlbWVudEJpYXM7XHJcblxyXG5cdFx0dGhpcy5zcGVjdWxhck1hcCA9IHNvdXJjZS5zcGVjdWxhck1hcDtcclxuXHJcblx0XHR0aGlzLmFscGhhTWFwID0gc291cmNlLmFscGhhTWFwO1xyXG5cclxuXHRcdHRoaXMuZW52TWFwID0gc291cmNlLmVudk1hcDtcclxuXHRcdHRoaXMuY29tYmluZSA9IHNvdXJjZS5jb21iaW5lO1xyXG5cdFx0dGhpcy5yZWZsZWN0aXZpdHkgPSBzb3VyY2UucmVmbGVjdGl2aXR5O1xyXG5cdFx0dGhpcy5yZWZyYWN0aW9uUmF0aW8gPSBzb3VyY2UucmVmcmFjdGlvblJhdGlvO1xyXG5cclxuXHRcdHRoaXMud2lyZWZyYW1lID0gc291cmNlLndpcmVmcmFtZTtcclxuXHRcdHRoaXMud2lyZWZyYW1lTGluZXdpZHRoID0gc291cmNlLndpcmVmcmFtZUxpbmV3aWR0aDtcclxuXHRcdHRoaXMud2lyZWZyYW1lTGluZWNhcCA9IHNvdXJjZS53aXJlZnJhbWVMaW5lY2FwO1xyXG5cdFx0dGhpcy53aXJlZnJhbWVMaW5lam9pbiA9IHNvdXJjZS53aXJlZnJhbWVMaW5lam9pbjtcclxuXHJcblx0XHR0aGlzLmZsYXRTaGFkaW5nID0gc291cmNlLmZsYXRTaGFkaW5nO1xyXG5cclxuXHRcdHRoaXMuZm9nID0gc291cmNlLmZvZztcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgTWVzaExhbWJlcnRNYXRlcmlhbCB9O1xyXG4iLCJpbXBvcnQgeyBUYW5nZW50U3BhY2VOb3JtYWxNYXAgfSBmcm9tICcuLi9jb25zdGFudHMuanMnO1xyXG5pbXBvcnQgeyBNYXRlcmlhbCB9IGZyb20gJy4vTWF0ZXJpYWwuanMnO1xyXG5pbXBvcnQgeyBWZWN0b3IyIH0gZnJvbSAnLi4vbWF0aC9WZWN0b3IyLmpzJztcclxuaW1wb3J0IHsgQ29sb3IgfSBmcm9tICcuLi9tYXRoL0NvbG9yLmpzJztcclxuXHJcbmNsYXNzIE1lc2hNYXRjYXBNYXRlcmlhbCBleHRlbmRzIE1hdGVyaWFsIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIHBhcmFtZXRlcnMgKSB7XHJcblxyXG5cdFx0c3VwZXIoKTtcclxuXHJcblx0XHR0aGlzLmlzTWVzaE1hdGNhcE1hdGVyaWFsID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLmRlZmluZXMgPSB7ICdNQVRDQVAnOiAnJyB9O1xyXG5cclxuXHRcdHRoaXMudHlwZSA9ICdNZXNoTWF0Y2FwTWF0ZXJpYWwnO1xyXG5cclxuXHRcdHRoaXMuY29sb3IgPSBuZXcgQ29sb3IoIDB4ZmZmZmZmICk7IC8vIGRpZmZ1c2VcclxuXHJcblx0XHR0aGlzLm1hdGNhcCA9IG51bGw7XHJcblxyXG5cdFx0dGhpcy5tYXAgPSBudWxsO1xyXG5cclxuXHRcdHRoaXMuYnVtcE1hcCA9IG51bGw7XHJcblx0XHR0aGlzLmJ1bXBTY2FsZSA9IDE7XHJcblxyXG5cdFx0dGhpcy5ub3JtYWxNYXAgPSBudWxsO1xyXG5cdFx0dGhpcy5ub3JtYWxNYXBUeXBlID0gVGFuZ2VudFNwYWNlTm9ybWFsTWFwO1xyXG5cdFx0dGhpcy5ub3JtYWxTY2FsZSA9IG5ldyBWZWN0b3IyKCAxLCAxICk7XHJcblxyXG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRNYXAgPSBudWxsO1xyXG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRTY2FsZSA9IDE7XHJcblx0XHR0aGlzLmRpc3BsYWNlbWVudEJpYXMgPSAwO1xyXG5cclxuXHRcdHRoaXMuYWxwaGFNYXAgPSBudWxsO1xyXG5cclxuXHRcdHRoaXMuZmxhdFNoYWRpbmcgPSBmYWxzZTtcclxuXHJcblx0XHR0aGlzLmZvZyA9IHRydWU7XHJcblxyXG5cdFx0dGhpcy5zZXRWYWx1ZXMoIHBhcmFtZXRlcnMgKTtcclxuXHJcblx0fVxyXG5cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xyXG5cclxuXHRcdHRoaXMuZGVmaW5lcyA9IHsgJ01BVENBUCc6ICcnIH07XHJcblxyXG5cdFx0dGhpcy5jb2xvci5jb3B5KCBzb3VyY2UuY29sb3IgKTtcclxuXHJcblx0XHR0aGlzLm1hdGNhcCA9IHNvdXJjZS5tYXRjYXA7XHJcblxyXG5cdFx0dGhpcy5tYXAgPSBzb3VyY2UubWFwO1xyXG5cclxuXHRcdHRoaXMuYnVtcE1hcCA9IHNvdXJjZS5idW1wTWFwO1xyXG5cdFx0dGhpcy5idW1wU2NhbGUgPSBzb3VyY2UuYnVtcFNjYWxlO1xyXG5cclxuXHRcdHRoaXMubm9ybWFsTWFwID0gc291cmNlLm5vcm1hbE1hcDtcclxuXHRcdHRoaXMubm9ybWFsTWFwVHlwZSA9IHNvdXJjZS5ub3JtYWxNYXBUeXBlO1xyXG5cdFx0dGhpcy5ub3JtYWxTY2FsZS5jb3B5KCBzb3VyY2Uubm9ybWFsU2NhbGUgKTtcclxuXHJcblx0XHR0aGlzLmRpc3BsYWNlbWVudE1hcCA9IHNvdXJjZS5kaXNwbGFjZW1lbnRNYXA7XHJcblx0XHR0aGlzLmRpc3BsYWNlbWVudFNjYWxlID0gc291cmNlLmRpc3BsYWNlbWVudFNjYWxlO1xyXG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRCaWFzID0gc291cmNlLmRpc3BsYWNlbWVudEJpYXM7XHJcblxyXG5cdFx0dGhpcy5hbHBoYU1hcCA9IHNvdXJjZS5hbHBoYU1hcDtcclxuXHJcblx0XHR0aGlzLmZsYXRTaGFkaW5nID0gc291cmNlLmZsYXRTaGFkaW5nO1xyXG5cclxuXHRcdHRoaXMuZm9nID0gc291cmNlLmZvZztcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgTWVzaE1hdGNhcE1hdGVyaWFsIH07XHJcbiIsImltcG9ydCB7IExpbmVCYXNpY01hdGVyaWFsIH0gZnJvbSAnLi9MaW5lQmFzaWNNYXRlcmlhbC5qcyc7XHJcblxyXG5jbGFzcyBMaW5lRGFzaGVkTWF0ZXJpYWwgZXh0ZW5kcyBMaW5lQmFzaWNNYXRlcmlhbCB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBwYXJhbWV0ZXJzICkge1xyXG5cclxuXHRcdHN1cGVyKCk7XHJcblxyXG5cdFx0dGhpcy5pc0xpbmVEYXNoZWRNYXRlcmlhbCA9IHRydWU7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ0xpbmVEYXNoZWRNYXRlcmlhbCc7XHJcblxyXG5cdFx0dGhpcy5zY2FsZSA9IDE7XHJcblx0XHR0aGlzLmRhc2hTaXplID0gMztcclxuXHRcdHRoaXMuZ2FwU2l6ZSA9IDE7XHJcblxyXG5cdFx0dGhpcy5zZXRWYWx1ZXMoIHBhcmFtZXRlcnMgKTtcclxuXHJcblx0fVxyXG5cclxuXHRjb3B5KCBzb3VyY2UgKSB7XHJcblxyXG5cdFx0c3VwZXIuY29weSggc291cmNlICk7XHJcblxyXG5cdFx0dGhpcy5zY2FsZSA9IHNvdXJjZS5zY2FsZTtcclxuXHRcdHRoaXMuZGFzaFNpemUgPSBzb3VyY2UuZGFzaFNpemU7XHJcblx0XHR0aGlzLmdhcFNpemUgPSBzb3VyY2UuZ2FwU2l6ZTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgTGluZURhc2hlZE1hdGVyaWFsIH07XHJcbiIsImltcG9ydCB7IFF1YXRlcm5pb24gfSBmcm9tICcuLi9tYXRoL1F1YXRlcm5pb24uanMnO1xyXG5pbXBvcnQgeyBBZGRpdGl2ZUFuaW1hdGlvbkJsZW5kTW9kZSB9IGZyb20gJy4uL2NvbnN0YW50cy5qcyc7XHJcblxyXG4vLyBjb252ZXJ0cyBhbiBhcnJheSB0byBhIHNwZWNpZmljIHR5cGVcclxuZnVuY3Rpb24gY29udmVydEFycmF5KCBhcnJheSwgdHlwZSwgZm9yY2VDbG9uZSApIHtcclxuXHJcblx0aWYgKCAhIGFycmF5IHx8IC8vIGxldCAndW5kZWZpbmVkJyBhbmQgJ251bGwnIHBhc3NcclxuXHRcdCEgZm9yY2VDbG9uZSAmJiBhcnJheS5jb25zdHJ1Y3RvciA9PT0gdHlwZSApIHJldHVybiBhcnJheTtcclxuXHJcblx0aWYgKCB0eXBlb2YgdHlwZS5CWVRFU19QRVJfRUxFTUVOVCA9PT0gJ251bWJlcicgKSB7XHJcblxyXG5cdFx0cmV0dXJuIG5ldyB0eXBlKCBhcnJheSApOyAvLyBjcmVhdGUgdHlwZWQgYXJyYXlcclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoIGFycmF5ICk7IC8vIGNyZWF0ZSBBcnJheVxyXG5cclxufVxyXG5cclxuZnVuY3Rpb24gaXNUeXBlZEFycmF5KCBvYmplY3QgKSB7XHJcblxyXG5cdHJldHVybiBBcnJheUJ1ZmZlci5pc1ZpZXcoIG9iamVjdCApICYmXHJcblx0XHQhICggb2JqZWN0IGluc3RhbmNlb2YgRGF0YVZpZXcgKTtcclxuXHJcbn1cclxuXHJcbi8vIHJldHVybnMgYW4gYXJyYXkgYnkgd2hpY2ggdGltZXMgYW5kIHZhbHVlcyBjYW4gYmUgc29ydGVkXHJcbmZ1bmN0aW9uIGdldEtleWZyYW1lT3JkZXIoIHRpbWVzICkge1xyXG5cclxuXHRmdW5jdGlvbiBjb21wYXJlVGltZSggaSwgaiApIHtcclxuXHJcblx0XHRyZXR1cm4gdGltZXNbIGkgXSAtIHRpbWVzWyBqIF07XHJcblxyXG5cdH1cclxuXHJcblx0Y29uc3QgbiA9IHRpbWVzLmxlbmd0aDtcclxuXHRjb25zdCByZXN1bHQgPSBuZXcgQXJyYXkoIG4gKTtcclxuXHRmb3IgKCBsZXQgaSA9IDA7IGkgIT09IG47ICsrIGkgKSByZXN1bHRbIGkgXSA9IGk7XHJcblxyXG5cdHJlc3VsdC5zb3J0KCBjb21wYXJlVGltZSApO1xyXG5cclxuXHRyZXR1cm4gcmVzdWx0O1xyXG5cclxufVxyXG5cclxuLy8gdXNlcyB0aGUgYXJyYXkgcHJldmlvdXNseSByZXR1cm5lZCBieSAnZ2V0S2V5ZnJhbWVPcmRlcicgdG8gc29ydCBkYXRhXHJcbmZ1bmN0aW9uIHNvcnRlZEFycmF5KCB2YWx1ZXMsIHN0cmlkZSwgb3JkZXIgKSB7XHJcblxyXG5cdGNvbnN0IG5WYWx1ZXMgPSB2YWx1ZXMubGVuZ3RoO1xyXG5cdGNvbnN0IHJlc3VsdCA9IG5ldyB2YWx1ZXMuY29uc3RydWN0b3IoIG5WYWx1ZXMgKTtcclxuXHJcblx0Zm9yICggbGV0IGkgPSAwLCBkc3RPZmZzZXQgPSAwOyBkc3RPZmZzZXQgIT09IG5WYWx1ZXM7ICsrIGkgKSB7XHJcblxyXG5cdFx0Y29uc3Qgc3JjT2Zmc2V0ID0gb3JkZXJbIGkgXSAqIHN0cmlkZTtcclxuXHJcblx0XHRmb3IgKCBsZXQgaiA9IDA7IGogIT09IHN0cmlkZTsgKysgaiApIHtcclxuXHJcblx0XHRcdHJlc3VsdFsgZHN0T2Zmc2V0ICsrIF0gPSB2YWx1ZXNbIHNyY09mZnNldCArIGogXTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0cmV0dXJuIHJlc3VsdDtcclxuXHJcbn1cclxuXHJcbi8vIGZ1bmN0aW9uIGZvciBwYXJzaW5nIEFPUyBrZXlmcmFtZSBmb3JtYXRzXHJcbmZ1bmN0aW9uIGZsYXR0ZW5KU09OKCBqc29uS2V5cywgdGltZXMsIHZhbHVlcywgdmFsdWVQcm9wZXJ0eU5hbWUgKSB7XHJcblxyXG5cdGxldCBpID0gMSwga2V5ID0ganNvbktleXNbIDAgXTtcclxuXHJcblx0d2hpbGUgKCBrZXkgIT09IHVuZGVmaW5lZCAmJiBrZXlbIHZhbHVlUHJvcGVydHlOYW1lIF0gPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRrZXkgPSBqc29uS2V5c1sgaSArKyBdO1xyXG5cclxuXHR9XHJcblxyXG5cdGlmICgga2V5ID09PSB1bmRlZmluZWQgKSByZXR1cm47IC8vIG5vIGRhdGFcclxuXHJcblx0bGV0IHZhbHVlID0ga2V5WyB2YWx1ZVByb3BlcnR5TmFtZSBdO1xyXG5cdGlmICggdmFsdWUgPT09IHVuZGVmaW5lZCApIHJldHVybjsgLy8gbm8gZGF0YVxyXG5cclxuXHRpZiAoIEFycmF5LmlzQXJyYXkoIHZhbHVlICkgKSB7XHJcblxyXG5cdFx0ZG8ge1xyXG5cclxuXHRcdFx0dmFsdWUgPSBrZXlbIHZhbHVlUHJvcGVydHlOYW1lIF07XHJcblxyXG5cdFx0XHRpZiAoIHZhbHVlICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRcdHRpbWVzLnB1c2goIGtleS50aW1lICk7XHJcblx0XHRcdFx0dmFsdWVzLnB1c2guYXBwbHkoIHZhbHVlcywgdmFsdWUgKTsgLy8gcHVzaCBhbGwgZWxlbWVudHNcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGtleSA9IGpzb25LZXlzWyBpICsrIF07XHJcblxyXG5cdFx0fSB3aGlsZSAoIGtleSAhPT0gdW5kZWZpbmVkICk7XHJcblxyXG5cdH0gZWxzZSBpZiAoIHZhbHVlLnRvQXJyYXkgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHQvLyAuLi5hc3N1bWUgVEhSRUUuTWF0aC1pc2hcclxuXHJcblx0XHRkbyB7XHJcblxyXG5cdFx0XHR2YWx1ZSA9IGtleVsgdmFsdWVQcm9wZXJ0eU5hbWUgXTtcclxuXHJcblx0XHRcdGlmICggdmFsdWUgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0dGltZXMucHVzaCgga2V5LnRpbWUgKTtcclxuXHRcdFx0XHR2YWx1ZS50b0FycmF5KCB2YWx1ZXMsIHZhbHVlcy5sZW5ndGggKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGtleSA9IGpzb25LZXlzWyBpICsrIF07XHJcblxyXG5cdFx0fSB3aGlsZSAoIGtleSAhPT0gdW5kZWZpbmVkICk7XHJcblxyXG5cdH0gZWxzZSB7XHJcblxyXG5cdFx0Ly8gb3RoZXJ3aXNlIHB1c2ggYXMtaXNcclxuXHJcblx0XHRkbyB7XHJcblxyXG5cdFx0XHR2YWx1ZSA9IGtleVsgdmFsdWVQcm9wZXJ0eU5hbWUgXTtcclxuXHJcblx0XHRcdGlmICggdmFsdWUgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0dGltZXMucHVzaCgga2V5LnRpbWUgKTtcclxuXHRcdFx0XHR2YWx1ZXMucHVzaCggdmFsdWUgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGtleSA9IGpzb25LZXlzWyBpICsrIF07XHJcblxyXG5cdFx0fSB3aGlsZSAoIGtleSAhPT0gdW5kZWZpbmVkICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmZ1bmN0aW9uIHN1YmNsaXAoIHNvdXJjZUNsaXAsIG5hbWUsIHN0YXJ0RnJhbWUsIGVuZEZyYW1lLCBmcHMgPSAzMCApIHtcclxuXHJcblx0Y29uc3QgY2xpcCA9IHNvdXJjZUNsaXAuY2xvbmUoKTtcclxuXHJcblx0Y2xpcC5uYW1lID0gbmFtZTtcclxuXHJcblx0Y29uc3QgdHJhY2tzID0gW107XHJcblxyXG5cdGZvciAoIGxldCBpID0gMDsgaSA8IGNsaXAudHJhY2tzLmxlbmd0aDsgKysgaSApIHtcclxuXHJcblx0XHRjb25zdCB0cmFjayA9IGNsaXAudHJhY2tzWyBpIF07XHJcblx0XHRjb25zdCB2YWx1ZVNpemUgPSB0cmFjay5nZXRWYWx1ZVNpemUoKTtcclxuXHJcblx0XHRjb25zdCB0aW1lcyA9IFtdO1xyXG5cdFx0Y29uc3QgdmFsdWVzID0gW107XHJcblxyXG5cdFx0Zm9yICggbGV0IGogPSAwOyBqIDwgdHJhY2sudGltZXMubGVuZ3RoOyArKyBqICkge1xyXG5cclxuXHRcdFx0Y29uc3QgZnJhbWUgPSB0cmFjay50aW1lc1sgaiBdICogZnBzO1xyXG5cclxuXHRcdFx0aWYgKCBmcmFtZSA8IHN0YXJ0RnJhbWUgfHwgZnJhbWUgPj0gZW5kRnJhbWUgKSBjb250aW51ZTtcclxuXHJcblx0XHRcdHRpbWVzLnB1c2goIHRyYWNrLnRpbWVzWyBqIF0gKTtcclxuXHJcblx0XHRcdGZvciAoIGxldCBrID0gMDsgayA8IHZhbHVlU2l6ZTsgKysgayApIHtcclxuXHJcblx0XHRcdFx0dmFsdWVzLnB1c2goIHRyYWNrLnZhbHVlc1sgaiAqIHZhbHVlU2l6ZSArIGsgXSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHRpbWVzLmxlbmd0aCA9PT0gMCApIGNvbnRpbnVlO1xyXG5cclxuXHRcdHRyYWNrLnRpbWVzID0gY29udmVydEFycmF5KCB0aW1lcywgdHJhY2sudGltZXMuY29uc3RydWN0b3IgKTtcclxuXHRcdHRyYWNrLnZhbHVlcyA9IGNvbnZlcnRBcnJheSggdmFsdWVzLCB0cmFjay52YWx1ZXMuY29uc3RydWN0b3IgKTtcclxuXHJcblx0XHR0cmFja3MucHVzaCggdHJhY2sgKTtcclxuXHJcblx0fVxyXG5cclxuXHRjbGlwLnRyYWNrcyA9IHRyYWNrcztcclxuXHJcblx0Ly8gZmluZCBtaW5pbXVtIC50aW1lcyB2YWx1ZSBhY3Jvc3MgYWxsIHRyYWNrcyBpbiB0aGUgdHJpbW1lZCBjbGlwXHJcblxyXG5cdGxldCBtaW5TdGFydFRpbWUgPSBJbmZpbml0eTtcclxuXHJcblx0Zm9yICggbGV0IGkgPSAwOyBpIDwgY2xpcC50cmFja3MubGVuZ3RoOyArKyBpICkge1xyXG5cclxuXHRcdGlmICggbWluU3RhcnRUaW1lID4gY2xpcC50cmFja3NbIGkgXS50aW1lc1sgMCBdICkge1xyXG5cclxuXHRcdFx0bWluU3RhcnRUaW1lID0gY2xpcC50cmFja3NbIGkgXS50aW1lc1sgMCBdO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHQvLyBzaGlmdCBhbGwgdHJhY2tzIHN1Y2ggdGhhdCBjbGlwIGJlZ2lucyBhdCB0PTBcclxuXHJcblx0Zm9yICggbGV0IGkgPSAwOyBpIDwgY2xpcC50cmFja3MubGVuZ3RoOyArKyBpICkge1xyXG5cclxuXHRcdGNsaXAudHJhY2tzWyBpIF0uc2hpZnQoIC0gMSAqIG1pblN0YXJ0VGltZSApO1xyXG5cclxuXHR9XHJcblxyXG5cdGNsaXAucmVzZXREdXJhdGlvbigpO1xyXG5cclxuXHRyZXR1cm4gY2xpcDtcclxuXHJcbn1cclxuXHJcbmZ1bmN0aW9uIG1ha2VDbGlwQWRkaXRpdmUoIHRhcmdldENsaXAsIHJlZmVyZW5jZUZyYW1lID0gMCwgcmVmZXJlbmNlQ2xpcCA9IHRhcmdldENsaXAsIGZwcyA9IDMwICkge1xyXG5cclxuXHRpZiAoIGZwcyA8PSAwICkgZnBzID0gMzA7XHJcblxyXG5cdGNvbnN0IG51bVRyYWNrcyA9IHJlZmVyZW5jZUNsaXAudHJhY2tzLmxlbmd0aDtcclxuXHRjb25zdCByZWZlcmVuY2VUaW1lID0gcmVmZXJlbmNlRnJhbWUgLyBmcHM7XHJcblxyXG5cdC8vIE1ha2UgZWFjaCB0cmFjaydzIHZhbHVlcyByZWxhdGl2ZSB0byB0aGUgdmFsdWVzIGF0IHRoZSByZWZlcmVuY2UgZnJhbWVcclxuXHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBudW1UcmFja3M7ICsrIGkgKSB7XHJcblxyXG5cdFx0Y29uc3QgcmVmZXJlbmNlVHJhY2sgPSByZWZlcmVuY2VDbGlwLnRyYWNrc1sgaSBdO1xyXG5cdFx0Y29uc3QgcmVmZXJlbmNlVHJhY2tUeXBlID0gcmVmZXJlbmNlVHJhY2suVmFsdWVUeXBlTmFtZTtcclxuXHJcblx0XHQvLyBTa2lwIHRoaXMgdHJhY2sgaWYgaXQncyBub24tbnVtZXJpY1xyXG5cdFx0aWYgKCByZWZlcmVuY2VUcmFja1R5cGUgPT09ICdib29sJyB8fCByZWZlcmVuY2VUcmFja1R5cGUgPT09ICdzdHJpbmcnICkgY29udGludWU7XHJcblxyXG5cdFx0Ly8gRmluZCB0aGUgdHJhY2sgaW4gdGhlIHRhcmdldCBjbGlwIHdob3NlIG5hbWUgYW5kIHR5cGUgbWF0Y2hlcyB0aGUgcmVmZXJlbmNlIHRyYWNrXHJcblx0XHRjb25zdCB0YXJnZXRUcmFjayA9IHRhcmdldENsaXAudHJhY2tzLmZpbmQoIGZ1bmN0aW9uICggdHJhY2sgKSB7XHJcblxyXG5cdFx0XHRyZXR1cm4gdHJhY2submFtZSA9PT0gcmVmZXJlbmNlVHJhY2submFtZVxyXG5cdFx0XHRcdCYmIHRyYWNrLlZhbHVlVHlwZU5hbWUgPT09IHJlZmVyZW5jZVRyYWNrVHlwZTtcclxuXHJcblx0XHR9ICk7XHJcblxyXG5cdFx0aWYgKCB0YXJnZXRUcmFjayA9PT0gdW5kZWZpbmVkICkgY29udGludWU7XHJcblxyXG5cdFx0bGV0IHJlZmVyZW5jZU9mZnNldCA9IDA7XHJcblx0XHRjb25zdCByZWZlcmVuY2VWYWx1ZVNpemUgPSByZWZlcmVuY2VUcmFjay5nZXRWYWx1ZVNpemUoKTtcclxuXHJcblx0XHRpZiAoIHJlZmVyZW5jZVRyYWNrLmNyZWF0ZUludGVycG9sYW50LmlzSW50ZXJwb2xhbnRGYWN0b3J5TWV0aG9kR0xURkN1YmljU3BsaW5lICkge1xyXG5cclxuXHRcdFx0cmVmZXJlbmNlT2Zmc2V0ID0gcmVmZXJlbmNlVmFsdWVTaXplIC8gMztcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0bGV0IHRhcmdldE9mZnNldCA9IDA7XHJcblx0XHRjb25zdCB0YXJnZXRWYWx1ZVNpemUgPSB0YXJnZXRUcmFjay5nZXRWYWx1ZVNpemUoKTtcclxuXHJcblx0XHRpZiAoIHRhcmdldFRyYWNrLmNyZWF0ZUludGVycG9sYW50LmlzSW50ZXJwb2xhbnRGYWN0b3J5TWV0aG9kR0xURkN1YmljU3BsaW5lICkge1xyXG5cclxuXHRcdFx0dGFyZ2V0T2Zmc2V0ID0gdGFyZ2V0VmFsdWVTaXplIC8gMztcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Y29uc3QgbGFzdEluZGV4ID0gcmVmZXJlbmNlVHJhY2sudGltZXMubGVuZ3RoIC0gMTtcclxuXHRcdGxldCByZWZlcmVuY2VWYWx1ZTtcclxuXHJcblx0XHQvLyBGaW5kIHRoZSB2YWx1ZSB0byBzdWJ0cmFjdCBvdXQgb2YgdGhlIHRyYWNrXHJcblx0XHRpZiAoIHJlZmVyZW5jZVRpbWUgPD0gcmVmZXJlbmNlVHJhY2sudGltZXNbIDAgXSApIHtcclxuXHJcblx0XHRcdC8vIFJlZmVyZW5jZSBmcmFtZSBpcyBlYXJsaWVyIHRoYW4gdGhlIGZpcnN0IGtleWZyYW1lLCBzbyBqdXN0IHVzZSB0aGUgZmlyc3Qga2V5ZnJhbWVcclxuXHRcdFx0Y29uc3Qgc3RhcnRJbmRleCA9IHJlZmVyZW5jZU9mZnNldDtcclxuXHRcdFx0Y29uc3QgZW5kSW5kZXggPSByZWZlcmVuY2VWYWx1ZVNpemUgLSByZWZlcmVuY2VPZmZzZXQ7XHJcblx0XHRcdHJlZmVyZW5jZVZhbHVlID0gcmVmZXJlbmNlVHJhY2sudmFsdWVzLnNsaWNlKCBzdGFydEluZGV4LCBlbmRJbmRleCApO1xyXG5cclxuXHRcdH0gZWxzZSBpZiAoIHJlZmVyZW5jZVRpbWUgPj0gcmVmZXJlbmNlVHJhY2sudGltZXNbIGxhc3RJbmRleCBdICkge1xyXG5cclxuXHRcdFx0Ly8gUmVmZXJlbmNlIGZyYW1lIGlzIGFmdGVyIHRoZSBsYXN0IGtleWZyYW1lLCBzbyBqdXN0IHVzZSB0aGUgbGFzdCBrZXlmcmFtZVxyXG5cdFx0XHRjb25zdCBzdGFydEluZGV4ID0gbGFzdEluZGV4ICogcmVmZXJlbmNlVmFsdWVTaXplICsgcmVmZXJlbmNlT2Zmc2V0O1xyXG5cdFx0XHRjb25zdCBlbmRJbmRleCA9IHN0YXJ0SW5kZXggKyByZWZlcmVuY2VWYWx1ZVNpemUgLSByZWZlcmVuY2VPZmZzZXQ7XHJcblx0XHRcdHJlZmVyZW5jZVZhbHVlID0gcmVmZXJlbmNlVHJhY2sudmFsdWVzLnNsaWNlKCBzdGFydEluZGV4LCBlbmRJbmRleCApO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHQvLyBJbnRlcnBvbGF0ZSB0byB0aGUgcmVmZXJlbmNlIHZhbHVlXHJcblx0XHRcdGNvbnN0IGludGVycG9sYW50ID0gcmVmZXJlbmNlVHJhY2suY3JlYXRlSW50ZXJwb2xhbnQoKTtcclxuXHRcdFx0Y29uc3Qgc3RhcnRJbmRleCA9IHJlZmVyZW5jZU9mZnNldDtcclxuXHRcdFx0Y29uc3QgZW5kSW5kZXggPSByZWZlcmVuY2VWYWx1ZVNpemUgLSByZWZlcmVuY2VPZmZzZXQ7XHJcblx0XHRcdGludGVycG9sYW50LmV2YWx1YXRlKCByZWZlcmVuY2VUaW1lICk7XHJcblx0XHRcdHJlZmVyZW5jZVZhbHVlID0gaW50ZXJwb2xhbnQucmVzdWx0QnVmZmVyLnNsaWNlKCBzdGFydEluZGV4LCBlbmRJbmRleCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvLyBDb25qdWdhdGUgdGhlIHF1YXRlcm5pb25cclxuXHRcdGlmICggcmVmZXJlbmNlVHJhY2tUeXBlID09PSAncXVhdGVybmlvbicgKSB7XHJcblxyXG5cdFx0XHRjb25zdCByZWZlcmVuY2VRdWF0ID0gbmV3IFF1YXRlcm5pb24oKS5mcm9tQXJyYXkoIHJlZmVyZW5jZVZhbHVlICkubm9ybWFsaXplKCkuY29uanVnYXRlKCk7XHJcblx0XHRcdHJlZmVyZW5jZVF1YXQudG9BcnJheSggcmVmZXJlbmNlVmFsdWUgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gU3VidHJhY3QgdGhlIHJlZmVyZW5jZSB2YWx1ZSBmcm9tIGFsbCBvZiB0aGUgdHJhY2sgdmFsdWVzXHJcblxyXG5cdFx0Y29uc3QgbnVtVGltZXMgPSB0YXJnZXRUcmFjay50aW1lcy5sZW5ndGg7XHJcblx0XHRmb3IgKCBsZXQgaiA9IDA7IGogPCBudW1UaW1lczsgKysgaiApIHtcclxuXHJcblx0XHRcdGNvbnN0IHZhbHVlU3RhcnQgPSBqICogdGFyZ2V0VmFsdWVTaXplICsgdGFyZ2V0T2Zmc2V0O1xyXG5cclxuXHRcdFx0aWYgKCByZWZlcmVuY2VUcmFja1R5cGUgPT09ICdxdWF0ZXJuaW9uJyApIHtcclxuXHJcblx0XHRcdFx0Ly8gTXVsdGlwbHkgdGhlIGNvbmp1Z2F0ZSBmb3IgcXVhdGVybmlvbiB0cmFjayB0eXBlc1xyXG5cdFx0XHRcdFF1YXRlcm5pb24ubXVsdGlwbHlRdWF0ZXJuaW9uc0ZsYXQoXHJcblx0XHRcdFx0XHR0YXJnZXRUcmFjay52YWx1ZXMsXHJcblx0XHRcdFx0XHR2YWx1ZVN0YXJ0LFxyXG5cdFx0XHRcdFx0cmVmZXJlbmNlVmFsdWUsXHJcblx0XHRcdFx0XHQwLFxyXG5cdFx0XHRcdFx0dGFyZ2V0VHJhY2sudmFsdWVzLFxyXG5cdFx0XHRcdFx0dmFsdWVTdGFydFxyXG5cdFx0XHRcdCk7XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRjb25zdCB2YWx1ZUVuZCA9IHRhcmdldFZhbHVlU2l6ZSAtIHRhcmdldE9mZnNldCAqIDI7XHJcblxyXG5cdFx0XHRcdC8vIFN1YnRyYWN0IGVhY2ggdmFsdWUgZm9yIGFsbCBvdGhlciBudW1lcmljIHRyYWNrIHR5cGVzXHJcblx0XHRcdFx0Zm9yICggbGV0IGsgPSAwOyBrIDwgdmFsdWVFbmQ7ICsrIGsgKSB7XHJcblxyXG5cdFx0XHRcdFx0dGFyZ2V0VHJhY2sudmFsdWVzWyB2YWx1ZVN0YXJ0ICsgayBdIC09IHJlZmVyZW5jZVZhbHVlWyBrIF07XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0dGFyZ2V0Q2xpcC5ibGVuZE1vZGUgPSBBZGRpdGl2ZUFuaW1hdGlvbkJsZW5kTW9kZTtcclxuXHJcblx0cmV0dXJuIHRhcmdldENsaXA7XHJcblxyXG59XHJcblxyXG5jb25zdCBBbmltYXRpb25VdGlscyA9IHtcclxuXHRjb252ZXJ0QXJyYXk6IGNvbnZlcnRBcnJheSxcclxuXHRpc1R5cGVkQXJyYXk6IGlzVHlwZWRBcnJheSxcclxuXHRnZXRLZXlmcmFtZU9yZGVyOiBnZXRLZXlmcmFtZU9yZGVyLFxyXG5cdHNvcnRlZEFycmF5OiBzb3J0ZWRBcnJheSxcclxuXHRmbGF0dGVuSlNPTjogZmxhdHRlbkpTT04sXHJcblx0c3ViY2xpcDogc3ViY2xpcCxcclxuXHRtYWtlQ2xpcEFkZGl0aXZlOiBtYWtlQ2xpcEFkZGl0aXZlXHJcbn07XHJcblxyXG5leHBvcnQge1xyXG5cdGNvbnZlcnRBcnJheSxcclxuXHRpc1R5cGVkQXJyYXksXHJcblx0Z2V0S2V5ZnJhbWVPcmRlcixcclxuXHRzb3J0ZWRBcnJheSxcclxuXHRmbGF0dGVuSlNPTixcclxuXHRzdWJjbGlwLFxyXG5cdG1ha2VDbGlwQWRkaXRpdmUsXHJcblx0QW5pbWF0aW9uVXRpbHNcclxufTtcclxuIiwiLyoqXHJcbiAqIEFic3RyYWN0IGJhc2UgY2xhc3Mgb2YgaW50ZXJwb2xhbnRzIG92ZXIgcGFyYW1ldHJpYyBzYW1wbGVzLlxyXG4gKlxyXG4gKiBUaGUgcGFyYW1ldGVyIGRvbWFpbiBpcyBvbmUgZGltZW5zaW9uYWwsIHR5cGljYWxseSB0aGUgdGltZSBvciBhIHBhdGhcclxuICogYWxvbmcgYSBjdXJ2ZSBkZWZpbmVkIGJ5IHRoZSBkYXRhLlxyXG4gKlxyXG4gKiBUaGUgc2FtcGxlIHZhbHVlcyBjYW4gaGF2ZSBhbnkgZGltZW5zaW9uYWxpdHkgYW5kIGRlcml2ZWQgY2xhc3NlcyBtYXlcclxuICogYXBwbHkgc3BlY2lhbCBpbnRlcnByZXRhdGlvbnMgdG8gdGhlIGRhdGEuXHJcbiAqXHJcbiAqIFRoaXMgY2xhc3MgcHJvdmlkZXMgdGhlIGludGVydmFsIHNlZWsgaW4gYSBUZW1wbGF0ZSBNZXRob2QsIGRlZmVycmluZ1xyXG4gKiB0aGUgYWN0dWFsIGludGVycG9sYXRpb24gdG8gZGVyaXZlZCBjbGFzc2VzLlxyXG4gKlxyXG4gKiBUaW1lIGNvbXBsZXhpdHkgaXMgTygxKSBmb3IgbGluZWFyIGFjY2VzcyBjcm9zc2luZyBhdCBtb3N0IHR3byBwb2ludHNcclxuICogYW5kIE8obG9nIE4pIGZvciByYW5kb20gYWNjZXNzLCB3aGVyZSBOIGlzIHRoZSBudW1iZXIgb2YgcG9zaXRpb25zLlxyXG4gKlxyXG4gKiBSZWZlcmVuY2VzOlxyXG4gKlxyXG4gKiBcdFx0aHR0cDovL3d3dy5vb2Rlc2lnbi5jb20vdGVtcGxhdGUtbWV0aG9kLXBhdHRlcm4uaHRtbFxyXG4gKlxyXG4gKi9cclxuXHJcbmNsYXNzIEludGVycG9sYW50IHtcclxuXHJcblx0Y29uc3RydWN0b3IoIHBhcmFtZXRlclBvc2l0aW9ucywgc2FtcGxlVmFsdWVzLCBzYW1wbGVTaXplLCByZXN1bHRCdWZmZXIgKSB7XHJcblxyXG5cdFx0dGhpcy5wYXJhbWV0ZXJQb3NpdGlvbnMgPSBwYXJhbWV0ZXJQb3NpdGlvbnM7XHJcblx0XHR0aGlzLl9jYWNoZWRJbmRleCA9IDA7XHJcblxyXG5cdFx0dGhpcy5yZXN1bHRCdWZmZXIgPSByZXN1bHRCdWZmZXIgIT09IHVuZGVmaW5lZCA/XHJcblx0XHRcdHJlc3VsdEJ1ZmZlciA6IG5ldyBzYW1wbGVWYWx1ZXMuY29uc3RydWN0b3IoIHNhbXBsZVNpemUgKTtcclxuXHRcdHRoaXMuc2FtcGxlVmFsdWVzID0gc2FtcGxlVmFsdWVzO1xyXG5cdFx0dGhpcy52YWx1ZVNpemUgPSBzYW1wbGVTaXplO1xyXG5cclxuXHRcdHRoaXMuc2V0dGluZ3MgPSBudWxsO1xyXG5cdFx0dGhpcy5EZWZhdWx0U2V0dGluZ3NfID0ge307XHJcblxyXG5cdH1cclxuXHJcblx0ZXZhbHVhdGUoIHQgKSB7XHJcblxyXG5cdFx0Y29uc3QgcHAgPSB0aGlzLnBhcmFtZXRlclBvc2l0aW9ucztcclxuXHRcdGxldCBpMSA9IHRoaXMuX2NhY2hlZEluZGV4LFxyXG5cdFx0XHR0MSA9IHBwWyBpMSBdLFxyXG5cdFx0XHR0MCA9IHBwWyBpMSAtIDEgXTtcclxuXHJcblx0XHR2YWxpZGF0ZV9pbnRlcnZhbDoge1xyXG5cclxuXHRcdFx0c2Vlazoge1xyXG5cclxuXHRcdFx0XHRsZXQgcmlnaHQ7XHJcblxyXG5cdFx0XHRcdGxpbmVhcl9zY2FuOiB7XHJcblxyXG5cdFx0XHRcdFx0Ly8tIFNlZSBodHRwOi8vanNwZXJmLmNvbS9jb21wYXJpc29uLXRvLXVuZGVmaW5lZC8zXHJcblx0XHRcdFx0XHQvLy0gc2xvd2VyIGNvZGU6XHJcblx0XHRcdFx0XHQvLy1cclxuXHRcdFx0XHRcdC8vLSBcdFx0XHRcdGlmICggdCA+PSB0MSB8fCB0MSA9PT0gdW5kZWZpbmVkICkge1xyXG5cdFx0XHRcdFx0Zm9yd2FyZF9zY2FuOiBpZiAoICEgKCB0IDwgdDEgKSApIHtcclxuXHJcblx0XHRcdFx0XHRcdGZvciAoIGxldCBnaXZlVXBBdCA9IGkxICsgMjsgOyApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0aWYgKCB0MSA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRcdGlmICggdCA8IHQwICkgYnJlYWsgZm9yd2FyZF9zY2FuO1xyXG5cclxuXHRcdFx0XHRcdFx0XHRcdC8vIGFmdGVyIGVuZFxyXG5cclxuXHRcdFx0XHRcdFx0XHRcdGkxID0gcHAubGVuZ3RoO1xyXG5cdFx0XHRcdFx0XHRcdFx0dGhpcy5fY2FjaGVkSW5kZXggPSBpMTtcclxuXHRcdFx0XHRcdFx0XHRcdHJldHVybiB0aGlzLmNvcHlTYW1wbGVWYWx1ZV8oIGkxIC0gMSApO1xyXG5cclxuXHRcdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0XHRcdGlmICggaTEgPT09IGdpdmVVcEF0ICkgYnJlYWs7IC8vIHRoaXMgbG9vcFxyXG5cclxuXHRcdFx0XHRcdFx0XHR0MCA9IHQxO1xyXG5cdFx0XHRcdFx0XHRcdHQxID0gcHBbICsrIGkxIF07XHJcblxyXG5cdFx0XHRcdFx0XHRcdGlmICggdCA8IHQxICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRcdC8vIHdlIGhhdmUgYXJyaXZlZCBhdCB0aGUgc291Z2h0IGludGVydmFsXHJcblx0XHRcdFx0XHRcdFx0XHRicmVhayBzZWVrO1xyXG5cclxuXHRcdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0XHQvLyBwcmVwYXJlIGJpbmFyeSBzZWFyY2ggb24gdGhlIHJpZ2h0IHNpZGUgb2YgdGhlIGluZGV4XHJcblx0XHRcdFx0XHRcdHJpZ2h0ID0gcHAubGVuZ3RoO1xyXG5cdFx0XHRcdFx0XHRicmVhayBsaW5lYXJfc2NhbjtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0Ly8tIHNsb3dlciBjb2RlOlxyXG5cdFx0XHRcdFx0Ly8tXHRcdFx0XHRcdGlmICggdCA8IHQwIHx8IHQwID09PSB1bmRlZmluZWQgKSB7XHJcblx0XHRcdFx0XHRpZiAoICEgKCB0ID49IHQwICkgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHQvLyBsb29waW5nP1xyXG5cclxuXHRcdFx0XHRcdFx0Y29uc3QgdDFnbG9iYWwgPSBwcFsgMSBdO1xyXG5cclxuXHRcdFx0XHRcdFx0aWYgKCB0IDwgdDFnbG9iYWwgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdGkxID0gMjsgLy8gKyAxLCB1c2luZyB0aGUgc2NhbiBmb3IgdGhlIGRldGFpbHNcclxuXHRcdFx0XHRcdFx0XHR0MCA9IHQxZ2xvYmFsO1xyXG5cclxuXHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdFx0Ly8gbGluZWFyIHJldmVyc2Ugc2NhblxyXG5cclxuXHRcdFx0XHRcdFx0Zm9yICggbGV0IGdpdmVVcEF0ID0gaTEgLSAyOyA7ICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRpZiAoIHQwID09PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0Ly8gYmVmb3JlIHN0YXJ0XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0dGhpcy5fY2FjaGVkSW5kZXggPSAwO1xyXG5cdFx0XHRcdFx0XHRcdFx0cmV0dXJuIHRoaXMuY29weVNhbXBsZVZhbHVlXyggMCApO1xyXG5cclxuXHRcdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0XHRcdGlmICggaTEgPT09IGdpdmVVcEF0ICkgYnJlYWs7IC8vIHRoaXMgbG9vcFxyXG5cclxuXHRcdFx0XHRcdFx0XHR0MSA9IHQwO1xyXG5cdFx0XHRcdFx0XHRcdHQwID0gcHBbIC0tIGkxIC0gMSBdO1xyXG5cclxuXHRcdFx0XHRcdFx0XHRpZiAoIHQgPj0gdDAgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0Ly8gd2UgaGF2ZSBhcnJpdmVkIGF0IHRoZSBzb3VnaHQgaW50ZXJ2YWxcclxuXHRcdFx0XHRcdFx0XHRcdGJyZWFrIHNlZWs7XHJcblxyXG5cdFx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRcdC8vIHByZXBhcmUgYmluYXJ5IHNlYXJjaCBvbiB0aGUgbGVmdCBzaWRlIG9mIHRoZSBpbmRleFxyXG5cdFx0XHRcdFx0XHRyaWdodCA9IGkxO1xyXG5cdFx0XHRcdFx0XHRpMSA9IDA7XHJcblx0XHRcdFx0XHRcdGJyZWFrIGxpbmVhcl9zY2FuO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHQvLyB0aGUgaW50ZXJ2YWwgaXMgdmFsaWRcclxuXHJcblx0XHRcdFx0XHRicmVhayB2YWxpZGF0ZV9pbnRlcnZhbDtcclxuXHJcblx0XHRcdFx0fSAvLyBsaW5lYXIgc2NhblxyXG5cclxuXHRcdFx0XHQvLyBiaW5hcnkgc2VhcmNoXHJcblxyXG5cdFx0XHRcdHdoaWxlICggaTEgPCByaWdodCApIHtcclxuXHJcblx0XHRcdFx0XHRjb25zdCBtaWQgPSAoIGkxICsgcmlnaHQgKSA+Pj4gMTtcclxuXHJcblx0XHRcdFx0XHRpZiAoIHQgPCBwcFsgbWlkIF0gKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRyaWdodCA9IG1pZDtcclxuXHJcblx0XHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdFx0aTEgPSBtaWQgKyAxO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR0MSA9IHBwWyBpMSBdO1xyXG5cdFx0XHRcdHQwID0gcHBbIGkxIC0gMSBdO1xyXG5cclxuXHRcdFx0XHQvLyBjaGVjayBib3VuZGFyeSBjYXNlcywgYWdhaW5cclxuXHJcblx0XHRcdFx0aWYgKCB0MCA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHRcdHRoaXMuX2NhY2hlZEluZGV4ID0gMDtcclxuXHRcdFx0XHRcdHJldHVybiB0aGlzLmNvcHlTYW1wbGVWYWx1ZV8oIDAgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRpZiAoIHQxID09PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRcdFx0aTEgPSBwcC5sZW5ndGg7XHJcblx0XHRcdFx0XHR0aGlzLl9jYWNoZWRJbmRleCA9IGkxO1xyXG5cdFx0XHRcdFx0cmV0dXJuIHRoaXMuY29weVNhbXBsZVZhbHVlXyggaTEgLSAxICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH0gLy8gc2Vla1xyXG5cclxuXHRcdFx0dGhpcy5fY2FjaGVkSW5kZXggPSBpMTtcclxuXHJcblx0XHRcdHRoaXMuaW50ZXJ2YWxDaGFuZ2VkXyggaTEsIHQwLCB0MSApO1xyXG5cclxuXHRcdH0gLy8gdmFsaWRhdGVfaW50ZXJ2YWxcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5pbnRlcnBvbGF0ZV8oIGkxLCB0MCwgdCwgdDEgKTtcclxuXHJcblx0fVxyXG5cclxuXHRnZXRTZXR0aW5nc18oKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuc2V0dGluZ3MgfHwgdGhpcy5EZWZhdWx0U2V0dGluZ3NfO1xyXG5cclxuXHR9XHJcblxyXG5cdGNvcHlTYW1wbGVWYWx1ZV8oIGluZGV4ICkge1xyXG5cclxuXHRcdC8vIGNvcGllcyBhIHNhbXBsZSB2YWx1ZSB0byB0aGUgcmVzdWx0IGJ1ZmZlclxyXG5cclxuXHRcdGNvbnN0IHJlc3VsdCA9IHRoaXMucmVzdWx0QnVmZmVyLFxyXG5cdFx0XHR2YWx1ZXMgPSB0aGlzLnNhbXBsZVZhbHVlcyxcclxuXHRcdFx0c3RyaWRlID0gdGhpcy52YWx1ZVNpemUsXHJcblx0XHRcdG9mZnNldCA9IGluZGV4ICogc3RyaWRlO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMDsgaSAhPT0gc3RyaWRlOyArKyBpICkge1xyXG5cclxuXHRcdFx0cmVzdWx0WyBpIF0gPSB2YWx1ZXNbIG9mZnNldCArIGkgXTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHJlc3VsdDtcclxuXHJcblx0fVxyXG5cclxuXHQvLyBUZW1wbGF0ZSBtZXRob2RzIGZvciBkZXJpdmVkIGNsYXNzZXM6XHJcblxyXG5cdGludGVycG9sYXRlXyggLyogaTEsIHQwLCB0LCB0MSAqLyApIHtcclxuXHJcblx0XHR0aHJvdyBuZXcgRXJyb3IoICdjYWxsIHRvIGFic3RyYWN0IG1ldGhvZCcgKTtcclxuXHRcdC8vIGltcGxlbWVudGF0aW9ucyBzaGFsbCByZXR1cm4gdGhpcy5yZXN1bHRCdWZmZXJcclxuXHJcblx0fVxyXG5cclxuXHRpbnRlcnZhbENoYW5nZWRfKCAvKiBpMSwgdDAsIHQxICovICkge1xyXG5cclxuXHRcdC8vIGVtcHR5XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IEludGVycG9sYW50IH07XHJcbiIsImltcG9ydCB7IFplcm9DdXJ2YXR1cmVFbmRpbmcsIFdyYXBBcm91bmRFbmRpbmcsIFplcm9TbG9wZUVuZGluZyB9IGZyb20gJy4uLy4uL2NvbnN0YW50cy5qcyc7XHJcbmltcG9ydCB7IEludGVycG9sYW50IH0gZnJvbSAnLi4vSW50ZXJwb2xhbnQuanMnO1xyXG5cclxuLyoqXHJcbiAqIEZhc3QgYW5kIHNpbXBsZSBjdWJpYyBzcGxpbmUgaW50ZXJwb2xhbnQuXHJcbiAqXHJcbiAqIEl0IHdhcyBkZXJpdmVkIGZyb20gYSBIZXJtaXRpYW4gY29uc3RydWN0aW9uIHNldHRpbmcgdGhlIGZpcnN0IGRlcml2YXRpdmVcclxuICogYXQgZWFjaCBzYW1wbGUgcG9zaXRpb24gdG8gdGhlIGxpbmVhciBzbG9wZSBiZXR3ZWVuIG5laWdoYm9yaW5nIHBvc2l0aW9uc1xyXG4gKiBvdmVyIHRoZWlyIHBhcmFtZXRlciBpbnRlcnZhbC5cclxuICovXHJcblxyXG5jbGFzcyBDdWJpY0ludGVycG9sYW50IGV4dGVuZHMgSW50ZXJwb2xhbnQge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggcGFyYW1ldGVyUG9zaXRpb25zLCBzYW1wbGVWYWx1ZXMsIHNhbXBsZVNpemUsIHJlc3VsdEJ1ZmZlciApIHtcclxuXHJcblx0XHRzdXBlciggcGFyYW1ldGVyUG9zaXRpb25zLCBzYW1wbGVWYWx1ZXMsIHNhbXBsZVNpemUsIHJlc3VsdEJ1ZmZlciApO1xyXG5cclxuXHRcdHRoaXMuX3dlaWdodFByZXYgPSAtIDA7XHJcblx0XHR0aGlzLl9vZmZzZXRQcmV2ID0gLSAwO1xyXG5cdFx0dGhpcy5fd2VpZ2h0TmV4dCA9IC0gMDtcclxuXHRcdHRoaXMuX29mZnNldE5leHQgPSAtIDA7XHJcblxyXG5cdFx0dGhpcy5EZWZhdWx0U2V0dGluZ3NfID0ge1xyXG5cclxuXHRcdFx0ZW5kaW5nU3RhcnQ6IFplcm9DdXJ2YXR1cmVFbmRpbmcsXHJcblx0XHRcdGVuZGluZ0VuZDogWmVyb0N1cnZhdHVyZUVuZGluZ1xyXG5cclxuXHRcdH07XHJcblxyXG5cdH1cclxuXHJcblx0aW50ZXJ2YWxDaGFuZ2VkXyggaTEsIHQwLCB0MSApIHtcclxuXHJcblx0XHRjb25zdCBwcCA9IHRoaXMucGFyYW1ldGVyUG9zaXRpb25zO1xyXG5cdFx0bGV0IGlQcmV2ID0gaTEgLSAyLFxyXG5cdFx0XHRpTmV4dCA9IGkxICsgMSxcclxuXHJcblx0XHRcdHRQcmV2ID0gcHBbIGlQcmV2IF0sXHJcblx0XHRcdHROZXh0ID0gcHBbIGlOZXh0IF07XHJcblxyXG5cdFx0aWYgKCB0UHJldiA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0c3dpdGNoICggdGhpcy5nZXRTZXR0aW5nc18oKS5lbmRpbmdTdGFydCApIHtcclxuXHJcblx0XHRcdFx0Y2FzZSBaZXJvU2xvcGVFbmRpbmc6XHJcblxyXG5cdFx0XHRcdFx0Ly8gZicodDApID0gMFxyXG5cdFx0XHRcdFx0aVByZXYgPSBpMTtcclxuXHRcdFx0XHRcdHRQcmV2ID0gMiAqIHQwIC0gdDE7XHJcblxyXG5cdFx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRcdGNhc2UgV3JhcEFyb3VuZEVuZGluZzpcclxuXHJcblx0XHRcdFx0XHQvLyB1c2UgdGhlIG90aGVyIGVuZCBvZiB0aGUgY3VydmVcclxuXHRcdFx0XHRcdGlQcmV2ID0gcHAubGVuZ3RoIC0gMjtcclxuXHRcdFx0XHRcdHRQcmV2ID0gdDAgKyBwcFsgaVByZXYgXSAtIHBwWyBpUHJldiArIDEgXTtcclxuXHJcblx0XHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdFx0ZGVmYXVsdDogLy8gWmVyb0N1cnZhdHVyZUVuZGluZ1xyXG5cclxuXHRcdFx0XHRcdC8vIGYnJyh0MCkgPSAwIGEuay5hLiBOYXR1cmFsIFNwbGluZVxyXG5cdFx0XHRcdFx0aVByZXYgPSBpMTtcclxuXHRcdFx0XHRcdHRQcmV2ID0gdDE7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggdE5leHQgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdHN3aXRjaCAoIHRoaXMuZ2V0U2V0dGluZ3NfKCkuZW5kaW5nRW5kICkge1xyXG5cclxuXHRcdFx0XHRjYXNlIFplcm9TbG9wZUVuZGluZzpcclxuXHJcblx0XHRcdFx0XHQvLyBmJyh0TikgPSAwXHJcblx0XHRcdFx0XHRpTmV4dCA9IGkxO1xyXG5cdFx0XHRcdFx0dE5leHQgPSAyICogdDEgLSB0MDtcclxuXHJcblx0XHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdFx0Y2FzZSBXcmFwQXJvdW5kRW5kaW5nOlxyXG5cclxuXHRcdFx0XHRcdC8vIHVzZSB0aGUgb3RoZXIgZW5kIG9mIHRoZSBjdXJ2ZVxyXG5cdFx0XHRcdFx0aU5leHQgPSAxO1xyXG5cdFx0XHRcdFx0dE5leHQgPSB0MSArIHBwWyAxIF0gLSBwcFsgMCBdO1xyXG5cclxuXHRcdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0XHRkZWZhdWx0OiAvLyBaZXJvQ3VydmF0dXJlRW5kaW5nXHJcblxyXG5cdFx0XHRcdFx0Ly8gZicnKHROKSA9IDAsIGEuay5hLiBOYXR1cmFsIFNwbGluZVxyXG5cdFx0XHRcdFx0aU5leHQgPSBpMSAtIDE7XHJcblx0XHRcdFx0XHR0TmV4dCA9IHQwO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCBoYWxmRHQgPSAoIHQxIC0gdDAgKSAqIDAuNSxcclxuXHRcdFx0c3RyaWRlID0gdGhpcy52YWx1ZVNpemU7XHJcblxyXG5cdFx0dGhpcy5fd2VpZ2h0UHJldiA9IGhhbGZEdCAvICggdDAgLSB0UHJldiApO1xyXG5cdFx0dGhpcy5fd2VpZ2h0TmV4dCA9IGhhbGZEdCAvICggdE5leHQgLSB0MSApO1xyXG5cdFx0dGhpcy5fb2Zmc2V0UHJldiA9IGlQcmV2ICogc3RyaWRlO1xyXG5cdFx0dGhpcy5fb2Zmc2V0TmV4dCA9IGlOZXh0ICogc3RyaWRlO1xyXG5cclxuXHR9XHJcblxyXG5cdGludGVycG9sYXRlXyggaTEsIHQwLCB0LCB0MSApIHtcclxuXHJcblx0XHRjb25zdCByZXN1bHQgPSB0aGlzLnJlc3VsdEJ1ZmZlcixcclxuXHRcdFx0dmFsdWVzID0gdGhpcy5zYW1wbGVWYWx1ZXMsXHJcblx0XHRcdHN0cmlkZSA9IHRoaXMudmFsdWVTaXplLFxyXG5cclxuXHRcdFx0bzEgPSBpMSAqIHN0cmlkZSxcdFx0bzAgPSBvMSAtIHN0cmlkZSxcclxuXHRcdFx0b1AgPSB0aGlzLl9vZmZzZXRQcmV2LCBcdG9OID0gdGhpcy5fb2Zmc2V0TmV4dCxcclxuXHRcdFx0d1AgPSB0aGlzLl93ZWlnaHRQcmV2LFx0d04gPSB0aGlzLl93ZWlnaHROZXh0LFxyXG5cclxuXHRcdFx0cCA9ICggdCAtIHQwICkgLyAoIHQxIC0gdDAgKSxcclxuXHRcdFx0cHAgPSBwICogcCxcclxuXHRcdFx0cHBwID0gcHAgKiBwO1xyXG5cclxuXHRcdC8vIGV2YWx1YXRlIHBvbHlub21pYWxzXHJcblxyXG5cdFx0Y29uc3Qgc1AgPSAtIHdQICogcHBwICsgMiAqIHdQICogcHAgLSB3UCAqIHA7XHJcblx0XHRjb25zdCBzMCA9ICggMSArIHdQICkgKiBwcHAgKyAoIC0gMS41IC0gMiAqIHdQICkgKiBwcCArICggLSAwLjUgKyB3UCApICogcCArIDE7XHJcblx0XHRjb25zdCBzMSA9ICggLSAxIC0gd04gKSAqIHBwcCArICggMS41ICsgd04gKSAqIHBwICsgMC41ICogcDtcclxuXHRcdGNvbnN0IHNOID0gd04gKiBwcHAgLSB3TiAqIHBwO1xyXG5cclxuXHRcdC8vIGNvbWJpbmUgZGF0YSBsaW5lYXJseVxyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMDsgaSAhPT0gc3RyaWRlOyArKyBpICkge1xyXG5cclxuXHRcdFx0cmVzdWx0WyBpIF0gPVxyXG5cdFx0XHRcdFx0c1AgKiB2YWx1ZXNbIG9QICsgaSBdICtcclxuXHRcdFx0XHRcdHMwICogdmFsdWVzWyBvMCArIGkgXSArXHJcblx0XHRcdFx0XHRzMSAqIHZhbHVlc1sgbzEgKyBpIF0gK1xyXG5cdFx0XHRcdFx0c04gKiB2YWx1ZXNbIG9OICsgaSBdO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gcmVzdWx0O1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBDdWJpY0ludGVycG9sYW50IH07XHJcbiIsImltcG9ydCB7IEludGVycG9sYW50IH0gZnJvbSAnLi4vSW50ZXJwb2xhbnQuanMnO1xyXG5cclxuY2xhc3MgTGluZWFySW50ZXJwb2xhbnQgZXh0ZW5kcyBJbnRlcnBvbGFudCB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBwYXJhbWV0ZXJQb3NpdGlvbnMsIHNhbXBsZVZhbHVlcywgc2FtcGxlU2l6ZSwgcmVzdWx0QnVmZmVyICkge1xyXG5cclxuXHRcdHN1cGVyKCBwYXJhbWV0ZXJQb3NpdGlvbnMsIHNhbXBsZVZhbHVlcywgc2FtcGxlU2l6ZSwgcmVzdWx0QnVmZmVyICk7XHJcblxyXG5cdH1cclxuXHJcblx0aW50ZXJwb2xhdGVfKCBpMSwgdDAsIHQsIHQxICkge1xyXG5cclxuXHRcdGNvbnN0IHJlc3VsdCA9IHRoaXMucmVzdWx0QnVmZmVyLFxyXG5cdFx0XHR2YWx1ZXMgPSB0aGlzLnNhbXBsZVZhbHVlcyxcclxuXHRcdFx0c3RyaWRlID0gdGhpcy52YWx1ZVNpemUsXHJcblxyXG5cdFx0XHRvZmZzZXQxID0gaTEgKiBzdHJpZGUsXHJcblx0XHRcdG9mZnNldDAgPSBvZmZzZXQxIC0gc3RyaWRlLFxyXG5cclxuXHRcdFx0d2VpZ2h0MSA9ICggdCAtIHQwICkgLyAoIHQxIC0gdDAgKSxcclxuXHRcdFx0d2VpZ2h0MCA9IDEgLSB3ZWlnaHQxO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMDsgaSAhPT0gc3RyaWRlOyArKyBpICkge1xyXG5cclxuXHRcdFx0cmVzdWx0WyBpIF0gPVxyXG5cdFx0XHRcdFx0dmFsdWVzWyBvZmZzZXQwICsgaSBdICogd2VpZ2h0MCArXHJcblx0XHRcdFx0XHR2YWx1ZXNbIG9mZnNldDEgKyBpIF0gKiB3ZWlnaHQxO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gcmVzdWx0O1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5cclxuZXhwb3J0IHsgTGluZWFySW50ZXJwb2xhbnQgfTtcclxuIiwiaW1wb3J0IHsgSW50ZXJwb2xhbnQgfSBmcm9tICcuLi9JbnRlcnBvbGFudC5qcyc7XHJcblxyXG4vKipcclxuICpcclxuICogSW50ZXJwb2xhbnQgdGhhdCBldmFsdWF0ZXMgdG8gdGhlIHNhbXBsZSB2YWx1ZSBhdCB0aGUgcG9zaXRpb24gcHJlY2VkaW5nXHJcbiAqIHRoZSBwYXJhbWV0ZXIuXHJcbiAqL1xyXG5cclxuY2xhc3MgRGlzY3JldGVJbnRlcnBvbGFudCBleHRlbmRzIEludGVycG9sYW50IHtcclxuXHJcblx0Y29uc3RydWN0b3IoIHBhcmFtZXRlclBvc2l0aW9ucywgc2FtcGxlVmFsdWVzLCBzYW1wbGVTaXplLCByZXN1bHRCdWZmZXIgKSB7XHJcblxyXG5cdFx0c3VwZXIoIHBhcmFtZXRlclBvc2l0aW9ucywgc2FtcGxlVmFsdWVzLCBzYW1wbGVTaXplLCByZXN1bHRCdWZmZXIgKTtcclxuXHJcblx0fVxyXG5cclxuXHRpbnRlcnBvbGF0ZV8oIGkxIC8qLCB0MCwgdCwgdDEgKi8gKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuY29weVNhbXBsZVZhbHVlXyggaTEgLSAxICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcblxyXG5leHBvcnQgeyBEaXNjcmV0ZUludGVycG9sYW50IH07XHJcbiIsImltcG9ydCB7XHJcblx0SW50ZXJwb2xhdGVMaW5lYXIsXHJcblx0SW50ZXJwb2xhdGVTbW9vdGgsXHJcblx0SW50ZXJwb2xhdGVEaXNjcmV0ZVxyXG59IGZyb20gJy4uL2NvbnN0YW50cy5qcyc7XHJcbmltcG9ydCB7IEN1YmljSW50ZXJwb2xhbnQgfSBmcm9tICcuLi9tYXRoL2ludGVycG9sYW50cy9DdWJpY0ludGVycG9sYW50LmpzJztcclxuaW1wb3J0IHsgTGluZWFySW50ZXJwb2xhbnQgfSBmcm9tICcuLi9tYXRoL2ludGVycG9sYW50cy9MaW5lYXJJbnRlcnBvbGFudC5qcyc7XHJcbmltcG9ydCB7IERpc2NyZXRlSW50ZXJwb2xhbnQgfSBmcm9tICcuLi9tYXRoL2ludGVycG9sYW50cy9EaXNjcmV0ZUludGVycG9sYW50LmpzJztcclxuaW1wb3J0ICogYXMgQW5pbWF0aW9uVXRpbHMgZnJvbSAnLi9BbmltYXRpb25VdGlscy5qcyc7XHJcblxyXG5jbGFzcyBLZXlmcmFtZVRyYWNrIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIG5hbWUsIHRpbWVzLCB2YWx1ZXMsIGludGVycG9sYXRpb24gKSB7XHJcblxyXG5cdFx0aWYgKCBuYW1lID09PSB1bmRlZmluZWQgKSB0aHJvdyBuZXcgRXJyb3IoICdUSFJFRS5LZXlmcmFtZVRyYWNrOiB0cmFjayBuYW1lIGlzIHVuZGVmaW5lZCcgKTtcclxuXHRcdGlmICggdGltZXMgPT09IHVuZGVmaW5lZCB8fCB0aW1lcy5sZW5ndGggPT09IDAgKSB0aHJvdyBuZXcgRXJyb3IoICdUSFJFRS5LZXlmcmFtZVRyYWNrOiBubyBrZXlmcmFtZXMgaW4gdHJhY2sgbmFtZWQgJyArIG5hbWUgKTtcclxuXHJcblx0XHR0aGlzLm5hbWUgPSBuYW1lO1xyXG5cclxuXHRcdHRoaXMudGltZXMgPSBBbmltYXRpb25VdGlscy5jb252ZXJ0QXJyYXkoIHRpbWVzLCB0aGlzLlRpbWVCdWZmZXJUeXBlICk7XHJcblx0XHR0aGlzLnZhbHVlcyA9IEFuaW1hdGlvblV0aWxzLmNvbnZlcnRBcnJheSggdmFsdWVzLCB0aGlzLlZhbHVlQnVmZmVyVHlwZSApO1xyXG5cclxuXHRcdHRoaXMuc2V0SW50ZXJwb2xhdGlvbiggaW50ZXJwb2xhdGlvbiB8fCB0aGlzLkRlZmF1bHRJbnRlcnBvbGF0aW9uICk7XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gU2VyaWFsaXphdGlvbiAoaW4gc3RhdGljIGNvbnRleHQsIGJlY2F1c2Ugb2YgY29uc3RydWN0b3IgaW52b2NhdGlvblxyXG5cdC8vIGFuZCBhdXRvbWF0aWMgaW52b2NhdGlvbiBvZiAudG9KU09OKTpcclxuXHJcblx0c3RhdGljIHRvSlNPTiggdHJhY2sgKSB7XHJcblxyXG5cdFx0Y29uc3QgdHJhY2tUeXBlID0gdHJhY2suY29uc3RydWN0b3I7XHJcblxyXG5cdFx0bGV0IGpzb247XHJcblxyXG5cdFx0Ly8gZGVyaXZlZCBjbGFzc2VzIGNhbiBkZWZpbmUgYSBzdGF0aWMgdG9KU09OIG1ldGhvZFxyXG5cdFx0aWYgKCB0cmFja1R5cGUudG9KU09OICE9PSB0aGlzLnRvSlNPTiApIHtcclxuXHJcblx0XHRcdGpzb24gPSB0cmFja1R5cGUudG9KU09OKCB0cmFjayApO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHQvLyBieSBkZWZhdWx0LCB3ZSBhc3N1bWUgdGhlIGRhdGEgY2FuIGJlIHNlcmlhbGl6ZWQgYXMtaXNcclxuXHRcdFx0anNvbiA9IHtcclxuXHJcblx0XHRcdFx0J25hbWUnOiB0cmFjay5uYW1lLFxyXG5cdFx0XHRcdCd0aW1lcyc6IEFuaW1hdGlvblV0aWxzLmNvbnZlcnRBcnJheSggdHJhY2sudGltZXMsIEFycmF5ICksXHJcblx0XHRcdFx0J3ZhbHVlcyc6IEFuaW1hdGlvblV0aWxzLmNvbnZlcnRBcnJheSggdHJhY2sudmFsdWVzLCBBcnJheSApXHJcblxyXG5cdFx0XHR9O1xyXG5cclxuXHRcdFx0Y29uc3QgaW50ZXJwb2xhdGlvbiA9IHRyYWNrLmdldEludGVycG9sYXRpb24oKTtcclxuXHJcblx0XHRcdGlmICggaW50ZXJwb2xhdGlvbiAhPT0gdHJhY2suRGVmYXVsdEludGVycG9sYXRpb24gKSB7XHJcblxyXG5cdFx0XHRcdGpzb24uaW50ZXJwb2xhdGlvbiA9IGludGVycG9sYXRpb247XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGpzb24udHlwZSA9IHRyYWNrLlZhbHVlVHlwZU5hbWU7IC8vIG1hbmRhdG9yeVxyXG5cclxuXHRcdHJldHVybiBqc29uO1xyXG5cclxuXHR9XHJcblxyXG5cdEludGVycG9sYW50RmFjdG9yeU1ldGhvZERpc2NyZXRlKCByZXN1bHQgKSB7XHJcblxyXG5cdFx0cmV0dXJuIG5ldyBEaXNjcmV0ZUludGVycG9sYW50KCB0aGlzLnRpbWVzLCB0aGlzLnZhbHVlcywgdGhpcy5nZXRWYWx1ZVNpemUoKSwgcmVzdWx0ICk7XHJcblxyXG5cdH1cclxuXHJcblx0SW50ZXJwb2xhbnRGYWN0b3J5TWV0aG9kTGluZWFyKCByZXN1bHQgKSB7XHJcblxyXG5cdFx0cmV0dXJuIG5ldyBMaW5lYXJJbnRlcnBvbGFudCggdGhpcy50aW1lcywgdGhpcy52YWx1ZXMsIHRoaXMuZ2V0VmFsdWVTaXplKCksIHJlc3VsdCApO1xyXG5cclxuXHR9XHJcblxyXG5cdEludGVycG9sYW50RmFjdG9yeU1ldGhvZFNtb290aCggcmVzdWx0ICkge1xyXG5cclxuXHRcdHJldHVybiBuZXcgQ3ViaWNJbnRlcnBvbGFudCggdGhpcy50aW1lcywgdGhpcy52YWx1ZXMsIHRoaXMuZ2V0VmFsdWVTaXplKCksIHJlc3VsdCApO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldEludGVycG9sYXRpb24oIGludGVycG9sYXRpb24gKSB7XHJcblxyXG5cdFx0bGV0IGZhY3RvcnlNZXRob2Q7XHJcblxyXG5cdFx0c3dpdGNoICggaW50ZXJwb2xhdGlvbiApIHtcclxuXHJcblx0XHRcdGNhc2UgSW50ZXJwb2xhdGVEaXNjcmV0ZTpcclxuXHJcblx0XHRcdFx0ZmFjdG9yeU1ldGhvZCA9IHRoaXMuSW50ZXJwb2xhbnRGYWN0b3J5TWV0aG9kRGlzY3JldGU7XHJcblxyXG5cdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0Y2FzZSBJbnRlcnBvbGF0ZUxpbmVhcjpcclxuXHJcblx0XHRcdFx0ZmFjdG9yeU1ldGhvZCA9IHRoaXMuSW50ZXJwb2xhbnRGYWN0b3J5TWV0aG9kTGluZWFyO1xyXG5cclxuXHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdGNhc2UgSW50ZXJwb2xhdGVTbW9vdGg6XHJcblxyXG5cdFx0XHRcdGZhY3RvcnlNZXRob2QgPSB0aGlzLkludGVycG9sYW50RmFjdG9yeU1ldGhvZFNtb290aDtcclxuXHJcblx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggZmFjdG9yeU1ldGhvZCA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0Y29uc3QgbWVzc2FnZSA9ICd1bnN1cHBvcnRlZCBpbnRlcnBvbGF0aW9uIGZvciAnICtcclxuXHRcdFx0XHR0aGlzLlZhbHVlVHlwZU5hbWUgKyAnIGtleWZyYW1lIHRyYWNrIG5hbWVkICcgKyB0aGlzLm5hbWU7XHJcblxyXG5cdFx0XHRpZiAoIHRoaXMuY3JlYXRlSW50ZXJwb2xhbnQgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0Ly8gZmFsbCBiYWNrIHRvIGRlZmF1bHQsIHVubGVzcyB0aGUgZGVmYXVsdCBpdHNlbGYgaXMgbWVzc2VkIHVwXHJcblx0XHRcdFx0aWYgKCBpbnRlcnBvbGF0aW9uICE9PSB0aGlzLkRlZmF1bHRJbnRlcnBvbGF0aW9uICkge1xyXG5cclxuXHRcdFx0XHRcdHRoaXMuc2V0SW50ZXJwb2xhdGlvbiggdGhpcy5EZWZhdWx0SW50ZXJwb2xhdGlvbiApO1xyXG5cclxuXHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdHRocm93IG5ldyBFcnJvciggbWVzc2FnZSApOyAvLyBmYXRhbCwgaW4gdGhpcyBjYXNlXHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLktleWZyYW1lVHJhY2s6JywgbWVzc2FnZSApO1xyXG5cdFx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5jcmVhdGVJbnRlcnBvbGFudCA9IGZhY3RvcnlNZXRob2Q7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0SW50ZXJwb2xhdGlvbigpIHtcclxuXHJcblx0XHRzd2l0Y2ggKCB0aGlzLmNyZWF0ZUludGVycG9sYW50ICkge1xyXG5cclxuXHRcdFx0Y2FzZSB0aGlzLkludGVycG9sYW50RmFjdG9yeU1ldGhvZERpc2NyZXRlOlxyXG5cclxuXHRcdFx0XHRyZXR1cm4gSW50ZXJwb2xhdGVEaXNjcmV0ZTtcclxuXHJcblx0XHRcdGNhc2UgdGhpcy5JbnRlcnBvbGFudEZhY3RvcnlNZXRob2RMaW5lYXI6XHJcblxyXG5cdFx0XHRcdHJldHVybiBJbnRlcnBvbGF0ZUxpbmVhcjtcclxuXHJcblx0XHRcdGNhc2UgdGhpcy5JbnRlcnBvbGFudEZhY3RvcnlNZXRob2RTbW9vdGg6XHJcblxyXG5cdFx0XHRcdHJldHVybiBJbnRlcnBvbGF0ZVNtb290aDtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0VmFsdWVTaXplKCkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLnZhbHVlcy5sZW5ndGggLyB0aGlzLnRpbWVzLmxlbmd0aDtcclxuXHJcblx0fVxyXG5cclxuXHQvLyBtb3ZlIGFsbCBrZXlmcmFtZXMgZWl0aGVyIGZvcndhcmRzIG9yIGJhY2t3YXJkcyBpbiB0aW1lXHJcblx0c2hpZnQoIHRpbWVPZmZzZXQgKSB7XHJcblxyXG5cdFx0aWYgKCB0aW1lT2Zmc2V0ICE9PSAwLjAgKSB7XHJcblxyXG5cdFx0XHRjb25zdCB0aW1lcyA9IHRoaXMudGltZXM7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIG4gPSB0aW1lcy5sZW5ndGg7IGkgIT09IG47ICsrIGkgKSB7XHJcblxyXG5cdFx0XHRcdHRpbWVzWyBpIF0gKz0gdGltZU9mZnNldDtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gc2NhbGUgYWxsIGtleWZyYW1lIHRpbWVzIGJ5IGEgZmFjdG9yICh1c2VmdWwgZm9yIGZyYW1lIDwtPiBzZWNvbmRzIGNvbnZlcnNpb25zKVxyXG5cdHNjYWxlKCB0aW1lU2NhbGUgKSB7XHJcblxyXG5cdFx0aWYgKCB0aW1lU2NhbGUgIT09IDEuMCApIHtcclxuXHJcblx0XHRcdGNvbnN0IHRpbWVzID0gdGhpcy50aW1lcztcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMCwgbiA9IHRpbWVzLmxlbmd0aDsgaSAhPT0gbjsgKysgaSApIHtcclxuXHJcblx0XHRcdFx0dGltZXNbIGkgXSAqPSB0aW1lU2NhbGU7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdC8vIHJlbW92ZXMga2V5ZnJhbWVzIGJlZm9yZSBhbmQgYWZ0ZXIgYW5pbWF0aW9uIHdpdGhvdXQgY2hhbmdpbmcgYW55IHZhbHVlcyB3aXRoaW4gdGhlIHJhbmdlIFtzdGFydFRpbWUsIGVuZFRpbWVdLlxyXG5cdC8vIElNUE9SVEFOVDogV2UgZG8gbm90IHNoaWZ0IGFyb3VuZCBrZXlzIHRvIHRoZSBzdGFydCBvZiB0aGUgdHJhY2sgdGltZSwgYmVjYXVzZSBmb3IgaW50ZXJwb2xhdGVkIGtleXMgdGhpcyB3aWxsIGNoYW5nZSB0aGVpciB2YWx1ZXNcclxuXHR0cmltKCBzdGFydFRpbWUsIGVuZFRpbWUgKSB7XHJcblxyXG5cdFx0Y29uc3QgdGltZXMgPSB0aGlzLnRpbWVzLFxyXG5cdFx0XHRuS2V5cyA9IHRpbWVzLmxlbmd0aDtcclxuXHJcblx0XHRsZXQgZnJvbSA9IDAsXHJcblx0XHRcdHRvID0gbktleXMgLSAxO1xyXG5cclxuXHRcdHdoaWxlICggZnJvbSAhPT0gbktleXMgJiYgdGltZXNbIGZyb20gXSA8IHN0YXJ0VGltZSApIHtcclxuXHJcblx0XHRcdCsrIGZyb207XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHdoaWxlICggdG8gIT09IC0gMSAmJiB0aW1lc1sgdG8gXSA+IGVuZFRpbWUgKSB7XHJcblxyXG5cdFx0XHQtLSB0bztcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0KysgdG87IC8vIGluY2x1c2l2ZSAtPiBleGNsdXNpdmUgYm91bmRcclxuXHJcblx0XHRpZiAoIGZyb20gIT09IDAgfHwgdG8gIT09IG5LZXlzICkge1xyXG5cclxuXHRcdFx0Ly8gZW1wdHkgdHJhY2tzIGFyZSBmb3JiaWRkZW4sIHNvIGtlZXAgYXQgbGVhc3Qgb25lIGtleWZyYW1lXHJcblx0XHRcdGlmICggZnJvbSA+PSB0byApIHtcclxuXHJcblx0XHRcdFx0dG8gPSBNYXRoLm1heCggdG8sIDEgKTtcclxuXHRcdFx0XHRmcm9tID0gdG8gLSAxO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Y29uc3Qgc3RyaWRlID0gdGhpcy5nZXRWYWx1ZVNpemUoKTtcclxuXHRcdFx0dGhpcy50aW1lcyA9IHRpbWVzLnNsaWNlKCBmcm9tLCB0byApO1xyXG5cdFx0XHR0aGlzLnZhbHVlcyA9IHRoaXMudmFsdWVzLnNsaWNlKCBmcm9tICogc3RyaWRlLCB0byAqIHN0cmlkZSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHQvLyBlbnN1cmUgd2UgZG8gbm90IGdldCBhIEdhcmJhZ2VJbkdhcmJhZ2VPdXQgc2l0dWF0aW9uLCBtYWtlIHN1cmUgdHJhY2tzIGFyZSBhdCBsZWFzdCBtaW5pbWFsbHkgdmlhYmxlXHJcblx0dmFsaWRhdGUoKSB7XHJcblxyXG5cdFx0bGV0IHZhbGlkID0gdHJ1ZTtcclxuXHJcblx0XHRjb25zdCB2YWx1ZVNpemUgPSB0aGlzLmdldFZhbHVlU2l6ZSgpO1xyXG5cdFx0aWYgKCB2YWx1ZVNpemUgLSBNYXRoLmZsb29yKCB2YWx1ZVNpemUgKSAhPT0gMCApIHtcclxuXHJcblx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5LZXlmcmFtZVRyYWNrOiBJbnZhbGlkIHZhbHVlIHNpemUgaW4gdHJhY2suJywgdGhpcyApO1xyXG5cdFx0XHR2YWxpZCA9IGZhbHNlO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCB0aW1lcyA9IHRoaXMudGltZXMsXHJcblx0XHRcdHZhbHVlcyA9IHRoaXMudmFsdWVzLFxyXG5cclxuXHRcdFx0bktleXMgPSB0aW1lcy5sZW5ndGg7XHJcblxyXG5cdFx0aWYgKCBuS2V5cyA9PT0gMCApIHtcclxuXHJcblx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5LZXlmcmFtZVRyYWNrOiBUcmFjayBpcyBlbXB0eS4nLCB0aGlzICk7XHJcblx0XHRcdHZhbGlkID0gZmFsc2U7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGxldCBwcmV2VGltZSA9IG51bGw7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpICE9PSBuS2V5czsgaSArKyApIHtcclxuXHJcblx0XHRcdGNvbnN0IGN1cnJUaW1lID0gdGltZXNbIGkgXTtcclxuXHJcblx0XHRcdGlmICggdHlwZW9mIGN1cnJUaW1lID09PSAnbnVtYmVyJyAmJiBpc05hTiggY3VyclRpbWUgKSApIHtcclxuXHJcblx0XHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLktleWZyYW1lVHJhY2s6IFRpbWUgaXMgbm90IGEgdmFsaWQgbnVtYmVyLicsIHRoaXMsIGksIGN1cnJUaW1lICk7XHJcblx0XHRcdFx0dmFsaWQgPSBmYWxzZTtcclxuXHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGlmICggcHJldlRpbWUgIT09IG51bGwgJiYgcHJldlRpbWUgPiBjdXJyVGltZSApIHtcclxuXHJcblx0XHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLktleWZyYW1lVHJhY2s6IE91dCBvZiBvcmRlciBrZXlzLicsIHRoaXMsIGksIGN1cnJUaW1lLCBwcmV2VGltZSApO1xyXG5cdFx0XHRcdHZhbGlkID0gZmFsc2U7XHJcblx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRwcmV2VGltZSA9IGN1cnJUaW1lO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHZhbHVlcyAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0aWYgKCBBbmltYXRpb25VdGlscy5pc1R5cGVkQXJyYXkoIHZhbHVlcyApICkge1xyXG5cclxuXHRcdFx0XHRmb3IgKCBsZXQgaSA9IDAsIG4gPSB2YWx1ZXMubGVuZ3RoOyBpICE9PSBuOyArKyBpICkge1xyXG5cclxuXHRcdFx0XHRcdGNvbnN0IHZhbHVlID0gdmFsdWVzWyBpIF07XHJcblxyXG5cdFx0XHRcdFx0aWYgKCBpc05hTiggdmFsdWUgKSApIHtcclxuXHJcblx0XHRcdFx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5LZXlmcmFtZVRyYWNrOiBWYWx1ZSBpcyBub3QgYSB2YWxpZCBudW1iZXIuJywgdGhpcywgaSwgdmFsdWUgKTtcclxuXHRcdFx0XHRcdFx0dmFsaWQgPSBmYWxzZTtcclxuXHRcdFx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB2YWxpZDtcclxuXHJcblx0fVxyXG5cclxuXHQvLyByZW1vdmVzIGVxdWl2YWxlbnQgc2VxdWVudGlhbCBrZXlzIGFzIGNvbW1vbiBpbiBtb3JwaCB0YXJnZXQgc2VxdWVuY2VzXHJcblx0Ly8gKDAsMCwwLDAsMSwxLDEsMCwwLDAsMCwwLDAsMCkgLS0+ICgwLDAsMSwxLDAsMClcclxuXHRvcHRpbWl6ZSgpIHtcclxuXHJcblx0XHQvLyB0aW1lcyBvciB2YWx1ZXMgbWF5IGJlIHNoYXJlZCB3aXRoIG90aGVyIHRyYWNrcywgc28gb3ZlcndyaXRpbmcgaXMgdW5zYWZlXHJcblx0XHRjb25zdCB0aW1lcyA9IHRoaXMudGltZXMuc2xpY2UoKSxcclxuXHRcdFx0dmFsdWVzID0gdGhpcy52YWx1ZXMuc2xpY2UoKSxcclxuXHRcdFx0c3RyaWRlID0gdGhpcy5nZXRWYWx1ZVNpemUoKSxcclxuXHJcblx0XHRcdHNtb290aEludGVycG9sYXRpb24gPSB0aGlzLmdldEludGVycG9sYXRpb24oKSA9PT0gSW50ZXJwb2xhdGVTbW9vdGgsXHJcblxyXG5cdFx0XHRsYXN0SW5kZXggPSB0aW1lcy5sZW5ndGggLSAxO1xyXG5cclxuXHRcdGxldCB3cml0ZUluZGV4ID0gMTtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDE7IGkgPCBsYXN0SW5kZXg7ICsrIGkgKSB7XHJcblxyXG5cdFx0XHRsZXQga2VlcCA9IGZhbHNlO1xyXG5cclxuXHRcdFx0Y29uc3QgdGltZSA9IHRpbWVzWyBpIF07XHJcblx0XHRcdGNvbnN0IHRpbWVOZXh0ID0gdGltZXNbIGkgKyAxIF07XHJcblxyXG5cdFx0XHQvLyByZW1vdmUgYWRqYWNlbnQga2V5ZnJhbWVzIHNjaGVkdWxlZCBhdCB0aGUgc2FtZSB0aW1lXHJcblxyXG5cdFx0XHRpZiAoIHRpbWUgIT09IHRpbWVOZXh0ICYmICggaSAhPT0gMSB8fCB0aW1lICE9PSB0aW1lc1sgMCBdICkgKSB7XHJcblxyXG5cdFx0XHRcdGlmICggISBzbW9vdGhJbnRlcnBvbGF0aW9uICkge1xyXG5cclxuXHRcdFx0XHRcdC8vIHJlbW92ZSB1bm5lY2Vzc2FyeSBrZXlmcmFtZXMgc2FtZSBhcyB0aGVpciBuZWlnaGJvcnNcclxuXHJcblx0XHRcdFx0XHRjb25zdCBvZmZzZXQgPSBpICogc3RyaWRlLFxyXG5cdFx0XHRcdFx0XHRvZmZzZXRQID0gb2Zmc2V0IC0gc3RyaWRlLFxyXG5cdFx0XHRcdFx0XHRvZmZzZXROID0gb2Zmc2V0ICsgc3RyaWRlO1xyXG5cclxuXHRcdFx0XHRcdGZvciAoIGxldCBqID0gMDsgaiAhPT0gc3RyaWRlOyArKyBqICkge1xyXG5cclxuXHRcdFx0XHRcdFx0Y29uc3QgdmFsdWUgPSB2YWx1ZXNbIG9mZnNldCArIGogXTtcclxuXHJcblx0XHRcdFx0XHRcdGlmICggdmFsdWUgIT09IHZhbHVlc1sgb2Zmc2V0UCArIGogXSB8fFxyXG5cdFx0XHRcdFx0XHRcdHZhbHVlICE9PSB2YWx1ZXNbIG9mZnNldE4gKyBqIF0gKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdGtlZXAgPSB0cnVlO1xyXG5cdFx0XHRcdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRrZWVwID0gdHJ1ZTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Ly8gaW4tcGxhY2UgY29tcGFjdGlvblxyXG5cclxuXHRcdFx0aWYgKCBrZWVwICkge1xyXG5cclxuXHRcdFx0XHRpZiAoIGkgIT09IHdyaXRlSW5kZXggKSB7XHJcblxyXG5cdFx0XHRcdFx0dGltZXNbIHdyaXRlSW5kZXggXSA9IHRpbWVzWyBpIF07XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgcmVhZE9mZnNldCA9IGkgKiBzdHJpZGUsXHJcblx0XHRcdFx0XHRcdHdyaXRlT2Zmc2V0ID0gd3JpdGVJbmRleCAqIHN0cmlkZTtcclxuXHJcblx0XHRcdFx0XHRmb3IgKCBsZXQgaiA9IDA7IGogIT09IHN0cmlkZTsgKysgaiApIHtcclxuXHJcblx0XHRcdFx0XHRcdHZhbHVlc1sgd3JpdGVPZmZzZXQgKyBqIF0gPSB2YWx1ZXNbIHJlYWRPZmZzZXQgKyBqIF07XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdCsrIHdyaXRlSW5kZXg7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIGZsdXNoIGxhc3Qga2V5ZnJhbWUgKGNvbXBhY3Rpb24gbG9va3MgYWhlYWQpXHJcblxyXG5cdFx0aWYgKCBsYXN0SW5kZXggPiAwICkge1xyXG5cclxuXHRcdFx0dGltZXNbIHdyaXRlSW5kZXggXSA9IHRpbWVzWyBsYXN0SW5kZXggXTtcclxuXHJcblx0XHRcdGZvciAoIGxldCByZWFkT2Zmc2V0ID0gbGFzdEluZGV4ICogc3RyaWRlLCB3cml0ZU9mZnNldCA9IHdyaXRlSW5kZXggKiBzdHJpZGUsIGogPSAwOyBqICE9PSBzdHJpZGU7ICsrIGogKSB7XHJcblxyXG5cdFx0XHRcdHZhbHVlc1sgd3JpdGVPZmZzZXQgKyBqIF0gPSB2YWx1ZXNbIHJlYWRPZmZzZXQgKyBqIF07XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQrKyB3cml0ZUluZGV4O1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHdyaXRlSW5kZXggIT09IHRpbWVzLmxlbmd0aCApIHtcclxuXHJcblx0XHRcdHRoaXMudGltZXMgPSB0aW1lcy5zbGljZSggMCwgd3JpdGVJbmRleCApO1xyXG5cdFx0XHR0aGlzLnZhbHVlcyA9IHZhbHVlcy5zbGljZSggMCwgd3JpdGVJbmRleCAqIHN0cmlkZSApO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHR0aGlzLnRpbWVzID0gdGltZXM7XHJcblx0XHRcdHRoaXMudmFsdWVzID0gdmFsdWVzO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRjbG9uZSgpIHtcclxuXHJcblx0XHRjb25zdCB0aW1lcyA9IHRoaXMudGltZXMuc2xpY2UoKTtcclxuXHRcdGNvbnN0IHZhbHVlcyA9IHRoaXMudmFsdWVzLnNsaWNlKCk7XHJcblxyXG5cdFx0Y29uc3QgVHlwZWRLZXlmcmFtZVRyYWNrID0gdGhpcy5jb25zdHJ1Y3RvcjtcclxuXHRcdGNvbnN0IHRyYWNrID0gbmV3IFR5cGVkS2V5ZnJhbWVUcmFjayggdGhpcy5uYW1lLCB0aW1lcywgdmFsdWVzICk7XHJcblxyXG5cdFx0Ly8gSW50ZXJwb2xhbnQgYXJndW1lbnQgdG8gY29uc3RydWN0b3IgaXMgbm90IHNhdmVkLCBzbyBjb3B5IHRoZSBmYWN0b3J5IG1ldGhvZCBkaXJlY3RseS5cclxuXHRcdHRyYWNrLmNyZWF0ZUludGVycG9sYW50ID0gdGhpcy5jcmVhdGVJbnRlcnBvbGFudDtcclxuXHJcblx0XHRyZXR1cm4gdHJhY2s7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbktleWZyYW1lVHJhY2sucHJvdG90eXBlLlRpbWVCdWZmZXJUeXBlID0gRmxvYXQzMkFycmF5O1xyXG5LZXlmcmFtZVRyYWNrLnByb3RvdHlwZS5WYWx1ZUJ1ZmZlclR5cGUgPSBGbG9hdDMyQXJyYXk7XHJcbktleWZyYW1lVHJhY2sucHJvdG90eXBlLkRlZmF1bHRJbnRlcnBvbGF0aW9uID0gSW50ZXJwb2xhdGVMaW5lYXI7XHJcblxyXG5leHBvcnQgeyBLZXlmcmFtZVRyYWNrIH07XHJcbiIsImltcG9ydCB7IEludGVycG9sYXRlRGlzY3JldGUgfSBmcm9tICcuLi8uLi9jb25zdGFudHMuanMnO1xyXG5pbXBvcnQgeyBLZXlmcmFtZVRyYWNrIH0gZnJvbSAnLi4vS2V5ZnJhbWVUcmFjay5qcyc7XHJcblxyXG4vKipcclxuICogQSBUcmFjayBvZiBCb29sZWFuIGtleWZyYW1lIHZhbHVlcy5cclxuICovXHJcbmNsYXNzIEJvb2xlYW5LZXlmcmFtZVRyYWNrIGV4dGVuZHMgS2V5ZnJhbWVUcmFjayB7fVxyXG5cclxuQm9vbGVhbktleWZyYW1lVHJhY2sucHJvdG90eXBlLlZhbHVlVHlwZU5hbWUgPSAnYm9vbCc7XHJcbkJvb2xlYW5LZXlmcmFtZVRyYWNrLnByb3RvdHlwZS5WYWx1ZUJ1ZmZlclR5cGUgPSBBcnJheTtcclxuQm9vbGVhbktleWZyYW1lVHJhY2sucHJvdG90eXBlLkRlZmF1bHRJbnRlcnBvbGF0aW9uID0gSW50ZXJwb2xhdGVEaXNjcmV0ZTtcclxuQm9vbGVhbktleWZyYW1lVHJhY2sucHJvdG90eXBlLkludGVycG9sYW50RmFjdG9yeU1ldGhvZExpbmVhciA9IHVuZGVmaW5lZDtcclxuQm9vbGVhbktleWZyYW1lVHJhY2sucHJvdG90eXBlLkludGVycG9sYW50RmFjdG9yeU1ldGhvZFNtb290aCA9IHVuZGVmaW5lZDtcclxuXHJcbi8vIE5vdGU6IEFjdHVhbGx5IHRoaXMgdHJhY2sgY291bGQgaGF2ZSBhIG9wdGltaXplZCAvIGNvbXByZXNzZWRcclxuLy8gcmVwcmVzZW50YXRpb24gb2YgYSBzaW5nbGUgdmFsdWUgYW5kIGEgY3VzdG9tIGludGVycG9sYW50IHRoYXRcclxuLy8gY29tcHV0ZXMgXCJmaXJzdFZhbHVlIF4gaXNPZGQoIGluZGV4IClcIi5cclxuXHJcbmV4cG9ydCB7IEJvb2xlYW5LZXlmcmFtZVRyYWNrIH07XHJcbiIsImltcG9ydCB7IEtleWZyYW1lVHJhY2sgfSBmcm9tICcuLi9LZXlmcmFtZVRyYWNrLmpzJztcclxuXHJcbi8qKlxyXG4gKiBBIFRyYWNrIG9mIGtleWZyYW1lIHZhbHVlcyB0aGF0IHJlcHJlc2VudCBjb2xvci5cclxuICovXHJcbmNsYXNzIENvbG9yS2V5ZnJhbWVUcmFjayBleHRlbmRzIEtleWZyYW1lVHJhY2sge31cclxuXHJcbkNvbG9yS2V5ZnJhbWVUcmFjay5wcm90b3R5cGUuVmFsdWVUeXBlTmFtZSA9ICdjb2xvcic7XHJcbi8vIFZhbHVlQnVmZmVyVHlwZSBpcyBpbmhlcml0ZWRcclxuLy8gRGVmYXVsdEludGVycG9sYXRpb24gaXMgaW5oZXJpdGVkXHJcblxyXG4vLyBOb3RlOiBWZXJ5IGJhc2ljIGltcGxlbWVudGF0aW9uIGFuZCBub3RoaW5nIHNwZWNpYWwgeWV0LlxyXG4vLyBIb3dldmVyLCB0aGlzIGlzIHRoZSBwbGFjZSBmb3IgY29sb3Igc3BhY2UgcGFyYW1ldGVyaXphdGlvbi5cclxuXHJcbmV4cG9ydCB7IENvbG9yS2V5ZnJhbWVUcmFjayB9O1xyXG4iLCJpbXBvcnQgeyBLZXlmcmFtZVRyYWNrIH0gZnJvbSAnLi4vS2V5ZnJhbWVUcmFjay5qcyc7XHJcblxyXG4vKipcclxuICogQSBUcmFjayBvZiBudW1lcmljIGtleWZyYW1lIHZhbHVlcy5cclxuICovXHJcbmNsYXNzIE51bWJlcktleWZyYW1lVHJhY2sgZXh0ZW5kcyBLZXlmcmFtZVRyYWNrIHt9XHJcblxyXG5OdW1iZXJLZXlmcmFtZVRyYWNrLnByb3RvdHlwZS5WYWx1ZVR5cGVOYW1lID0gJ251bWJlcic7XHJcbi8vIFZhbHVlQnVmZmVyVHlwZSBpcyBpbmhlcml0ZWRcclxuLy8gRGVmYXVsdEludGVycG9sYXRpb24gaXMgaW5oZXJpdGVkXHJcblxyXG5leHBvcnQgeyBOdW1iZXJLZXlmcmFtZVRyYWNrIH07XHJcbiIsImltcG9ydCB7IEludGVycG9sYW50IH0gZnJvbSAnLi4vSW50ZXJwb2xhbnQuanMnO1xyXG5pbXBvcnQgeyBRdWF0ZXJuaW9uIH0gZnJvbSAnLi4vUXVhdGVybmlvbi5qcyc7XHJcblxyXG4vKipcclxuICogU3BoZXJpY2FsIGxpbmVhciB1bml0IHF1YXRlcm5pb24gaW50ZXJwb2xhbnQuXHJcbiAqL1xyXG5cclxuY2xhc3MgUXVhdGVybmlvbkxpbmVhckludGVycG9sYW50IGV4dGVuZHMgSW50ZXJwb2xhbnQge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggcGFyYW1ldGVyUG9zaXRpb25zLCBzYW1wbGVWYWx1ZXMsIHNhbXBsZVNpemUsIHJlc3VsdEJ1ZmZlciApIHtcclxuXHJcblx0XHRzdXBlciggcGFyYW1ldGVyUG9zaXRpb25zLCBzYW1wbGVWYWx1ZXMsIHNhbXBsZVNpemUsIHJlc3VsdEJ1ZmZlciApO1xyXG5cclxuXHR9XHJcblxyXG5cdGludGVycG9sYXRlXyggaTEsIHQwLCB0LCB0MSApIHtcclxuXHJcblx0XHRjb25zdCByZXN1bHQgPSB0aGlzLnJlc3VsdEJ1ZmZlcixcclxuXHRcdFx0dmFsdWVzID0gdGhpcy5zYW1wbGVWYWx1ZXMsXHJcblx0XHRcdHN0cmlkZSA9IHRoaXMudmFsdWVTaXplLFxyXG5cclxuXHRcdFx0YWxwaGEgPSAoIHQgLSB0MCApIC8gKCB0MSAtIHQwICk7XHJcblxyXG5cdFx0bGV0IG9mZnNldCA9IGkxICogc3RyaWRlO1xyXG5cclxuXHRcdGZvciAoIGxldCBlbmQgPSBvZmZzZXQgKyBzdHJpZGU7IG9mZnNldCAhPT0gZW5kOyBvZmZzZXQgKz0gNCApIHtcclxuXHJcblx0XHRcdFF1YXRlcm5pb24uc2xlcnBGbGF0KCByZXN1bHQsIDAsIHZhbHVlcywgb2Zmc2V0IC0gc3RyaWRlLCB2YWx1ZXMsIG9mZnNldCwgYWxwaGEgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHJlc3VsdDtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuXHJcbmV4cG9ydCB7IFF1YXRlcm5pb25MaW5lYXJJbnRlcnBvbGFudCB9O1xyXG4iLCJpbXBvcnQgeyBJbnRlcnBvbGF0ZUxpbmVhciB9IGZyb20gJy4uLy4uL2NvbnN0YW50cy5qcyc7XHJcbmltcG9ydCB7IEtleWZyYW1lVHJhY2sgfSBmcm9tICcuLi9LZXlmcmFtZVRyYWNrLmpzJztcclxuaW1wb3J0IHsgUXVhdGVybmlvbkxpbmVhckludGVycG9sYW50IH0gZnJvbSAnLi4vLi4vbWF0aC9pbnRlcnBvbGFudHMvUXVhdGVybmlvbkxpbmVhckludGVycG9sYW50LmpzJztcclxuXHJcbi8qKlxyXG4gKiBBIFRyYWNrIG9mIHF1YXRlcm5pb24ga2V5ZnJhbWUgdmFsdWVzLlxyXG4gKi9cclxuY2xhc3MgUXVhdGVybmlvbktleWZyYW1lVHJhY2sgZXh0ZW5kcyBLZXlmcmFtZVRyYWNrIHtcclxuXHJcblx0SW50ZXJwb2xhbnRGYWN0b3J5TWV0aG9kTGluZWFyKCByZXN1bHQgKSB7XHJcblxyXG5cdFx0cmV0dXJuIG5ldyBRdWF0ZXJuaW9uTGluZWFySW50ZXJwb2xhbnQoIHRoaXMudGltZXMsIHRoaXMudmFsdWVzLCB0aGlzLmdldFZhbHVlU2l6ZSgpLCByZXN1bHQgKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuUXVhdGVybmlvbktleWZyYW1lVHJhY2sucHJvdG90eXBlLlZhbHVlVHlwZU5hbWUgPSAncXVhdGVybmlvbic7XHJcbi8vIFZhbHVlQnVmZmVyVHlwZSBpcyBpbmhlcml0ZWRcclxuUXVhdGVybmlvbktleWZyYW1lVHJhY2sucHJvdG90eXBlLkRlZmF1bHRJbnRlcnBvbGF0aW9uID0gSW50ZXJwb2xhdGVMaW5lYXI7XHJcblF1YXRlcm5pb25LZXlmcmFtZVRyYWNrLnByb3RvdHlwZS5JbnRlcnBvbGFudEZhY3RvcnlNZXRob2RTbW9vdGggPSB1bmRlZmluZWQ7XHJcblxyXG5leHBvcnQgeyBRdWF0ZXJuaW9uS2V5ZnJhbWVUcmFjayB9O1xyXG4iLCJpbXBvcnQgeyBJbnRlcnBvbGF0ZURpc2NyZXRlIH0gZnJvbSAnLi4vLi4vY29uc3RhbnRzLmpzJztcclxuaW1wb3J0IHsgS2V5ZnJhbWVUcmFjayB9IGZyb20gJy4uL0tleWZyYW1lVHJhY2suanMnO1xyXG5cclxuLyoqXHJcbiAqIEEgVHJhY2sgdGhhdCBpbnRlcnBvbGF0ZXMgU3RyaW5nc1xyXG4gKi9cclxuY2xhc3MgU3RyaW5nS2V5ZnJhbWVUcmFjayBleHRlbmRzIEtleWZyYW1lVHJhY2sge31cclxuXHJcblN0cmluZ0tleWZyYW1lVHJhY2sucHJvdG90eXBlLlZhbHVlVHlwZU5hbWUgPSAnc3RyaW5nJztcclxuU3RyaW5nS2V5ZnJhbWVUcmFjay5wcm90b3R5cGUuVmFsdWVCdWZmZXJUeXBlID0gQXJyYXk7XHJcblN0cmluZ0tleWZyYW1lVHJhY2sucHJvdG90eXBlLkRlZmF1bHRJbnRlcnBvbGF0aW9uID0gSW50ZXJwb2xhdGVEaXNjcmV0ZTtcclxuU3RyaW5nS2V5ZnJhbWVUcmFjay5wcm90b3R5cGUuSW50ZXJwb2xhbnRGYWN0b3J5TWV0aG9kTGluZWFyID0gdW5kZWZpbmVkO1xyXG5TdHJpbmdLZXlmcmFtZVRyYWNrLnByb3RvdHlwZS5JbnRlcnBvbGFudEZhY3RvcnlNZXRob2RTbW9vdGggPSB1bmRlZmluZWQ7XHJcblxyXG5leHBvcnQgeyBTdHJpbmdLZXlmcmFtZVRyYWNrIH07XHJcbiIsImltcG9ydCB7IEtleWZyYW1lVHJhY2sgfSBmcm9tICcuLi9LZXlmcmFtZVRyYWNrLmpzJztcclxuXHJcbi8qKlxyXG4gKiBBIFRyYWNrIG9mIHZlY3RvcmVkIGtleWZyYW1lIHZhbHVlcy5cclxuICovXHJcbmNsYXNzIFZlY3RvcktleWZyYW1lVHJhY2sgZXh0ZW5kcyBLZXlmcmFtZVRyYWNrIHt9XHJcblxyXG5WZWN0b3JLZXlmcmFtZVRyYWNrLnByb3RvdHlwZS5WYWx1ZVR5cGVOYW1lID0gJ3ZlY3Rvcic7XHJcbi8vIFZhbHVlQnVmZmVyVHlwZSBpcyBpbmhlcml0ZWRcclxuLy8gRGVmYXVsdEludGVycG9sYXRpb24gaXMgaW5oZXJpdGVkXHJcblxyXG5leHBvcnQgeyBWZWN0b3JLZXlmcmFtZVRyYWNrIH07XHJcbiIsImltcG9ydCAqIGFzIEFuaW1hdGlvblV0aWxzIGZyb20gJy4vQW5pbWF0aW9uVXRpbHMuanMnO1xyXG5pbXBvcnQgeyBLZXlmcmFtZVRyYWNrIH0gZnJvbSAnLi9LZXlmcmFtZVRyYWNrLmpzJztcclxuaW1wb3J0IHsgQm9vbGVhbktleWZyYW1lVHJhY2sgfSBmcm9tICcuL3RyYWNrcy9Cb29sZWFuS2V5ZnJhbWVUcmFjay5qcyc7XHJcbmltcG9ydCB7IENvbG9yS2V5ZnJhbWVUcmFjayB9IGZyb20gJy4vdHJhY2tzL0NvbG9yS2V5ZnJhbWVUcmFjay5qcyc7XHJcbmltcG9ydCB7IE51bWJlcktleWZyYW1lVHJhY2sgfSBmcm9tICcuL3RyYWNrcy9OdW1iZXJLZXlmcmFtZVRyYWNrLmpzJztcclxuaW1wb3J0IHsgUXVhdGVybmlvbktleWZyYW1lVHJhY2sgfSBmcm9tICcuL3RyYWNrcy9RdWF0ZXJuaW9uS2V5ZnJhbWVUcmFjay5qcyc7XHJcbmltcG9ydCB7IFN0cmluZ0tleWZyYW1lVHJhY2sgfSBmcm9tICcuL3RyYWNrcy9TdHJpbmdLZXlmcmFtZVRyYWNrLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yS2V5ZnJhbWVUcmFjayB9IGZyb20gJy4vdHJhY2tzL1ZlY3RvcktleWZyYW1lVHJhY2suanMnO1xyXG5pbXBvcnQgKiBhcyBNYXRoVXRpbHMgZnJvbSAnLi4vbWF0aC9NYXRoVXRpbHMuanMnO1xyXG5pbXBvcnQgeyBOb3JtYWxBbmltYXRpb25CbGVuZE1vZGUgfSBmcm9tICcuLi9jb25zdGFudHMuanMnO1xyXG5cclxuY2xhc3MgQW5pbWF0aW9uQ2xpcCB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBuYW1lLCBkdXJhdGlvbiA9IC0gMSwgdHJhY2tzLCBibGVuZE1vZGUgPSBOb3JtYWxBbmltYXRpb25CbGVuZE1vZGUgKSB7XHJcblxyXG5cdFx0dGhpcy5uYW1lID0gbmFtZTtcclxuXHRcdHRoaXMudHJhY2tzID0gdHJhY2tzO1xyXG5cdFx0dGhpcy5kdXJhdGlvbiA9IGR1cmF0aW9uO1xyXG5cdFx0dGhpcy5ibGVuZE1vZGUgPSBibGVuZE1vZGU7XHJcblxyXG5cdFx0dGhpcy51dWlkID0gTWF0aFV0aWxzLmdlbmVyYXRlVVVJRCgpO1xyXG5cclxuXHRcdC8vIHRoaXMgbWVhbnMgaXQgc2hvdWxkIGZpZ3VyZSBvdXQgaXRzIGR1cmF0aW9uIGJ5IHNjYW5uaW5nIHRoZSB0cmFja3NcclxuXHRcdGlmICggdGhpcy5kdXJhdGlvbiA8IDAgKSB7XHJcblxyXG5cdFx0XHR0aGlzLnJlc2V0RHVyYXRpb24oKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblxyXG5cdHN0YXRpYyBwYXJzZSgganNvbiApIHtcclxuXHJcblx0XHRjb25zdCB0cmFja3MgPSBbXSxcclxuXHRcdFx0anNvblRyYWNrcyA9IGpzb24udHJhY2tzLFxyXG5cdFx0XHRmcmFtZVRpbWUgPSAxLjAgLyAoIGpzb24uZnBzIHx8IDEuMCApO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMCwgbiA9IGpzb25UcmFja3MubGVuZ3RoOyBpICE9PSBuOyArKyBpICkge1xyXG5cclxuXHRcdFx0dHJhY2tzLnB1c2goIHBhcnNlS2V5ZnJhbWVUcmFjaygganNvblRyYWNrc1sgaSBdICkuc2NhbGUoIGZyYW1lVGltZSApICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGNvbnN0IGNsaXAgPSBuZXcgdGhpcygganNvbi5uYW1lLCBqc29uLmR1cmF0aW9uLCB0cmFja3MsIGpzb24uYmxlbmRNb2RlICk7XHJcblx0XHRjbGlwLnV1aWQgPSBqc29uLnV1aWQ7XHJcblxyXG5cdFx0cmV0dXJuIGNsaXA7XHJcblxyXG5cdH1cclxuXHJcblx0c3RhdGljIHRvSlNPTiggY2xpcCApIHtcclxuXHJcblx0XHRjb25zdCB0cmFja3MgPSBbXSxcclxuXHRcdFx0Y2xpcFRyYWNrcyA9IGNsaXAudHJhY2tzO1xyXG5cclxuXHRcdGNvbnN0IGpzb24gPSB7XHJcblxyXG5cdFx0XHQnbmFtZSc6IGNsaXAubmFtZSxcclxuXHRcdFx0J2R1cmF0aW9uJzogY2xpcC5kdXJhdGlvbixcclxuXHRcdFx0J3RyYWNrcyc6IHRyYWNrcyxcclxuXHRcdFx0J3V1aWQnOiBjbGlwLnV1aWQsXHJcblx0XHRcdCdibGVuZE1vZGUnOiBjbGlwLmJsZW5kTW9kZVxyXG5cclxuXHRcdH07XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBuID0gY2xpcFRyYWNrcy5sZW5ndGg7IGkgIT09IG47ICsrIGkgKSB7XHJcblxyXG5cdFx0XHR0cmFja3MucHVzaCggS2V5ZnJhbWVUcmFjay50b0pTT04oIGNsaXBUcmFja3NbIGkgXSApICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiBqc29uO1xyXG5cclxuXHR9XHJcblxyXG5cdHN0YXRpYyBDcmVhdGVGcm9tTW9ycGhUYXJnZXRTZXF1ZW5jZSggbmFtZSwgbW9ycGhUYXJnZXRTZXF1ZW5jZSwgZnBzLCBub0xvb3AgKSB7XHJcblxyXG5cdFx0Y29uc3QgbnVtTW9ycGhUYXJnZXRzID0gbW9ycGhUYXJnZXRTZXF1ZW5jZS5sZW5ndGg7XHJcblx0XHRjb25zdCB0cmFja3MgPSBbXTtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBudW1Nb3JwaFRhcmdldHM7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRsZXQgdGltZXMgPSBbXTtcclxuXHRcdFx0bGV0IHZhbHVlcyA9IFtdO1xyXG5cclxuXHRcdFx0dGltZXMucHVzaChcclxuXHRcdFx0XHQoIGkgKyBudW1Nb3JwaFRhcmdldHMgLSAxICkgJSBudW1Nb3JwaFRhcmdldHMsXHJcblx0XHRcdFx0aSxcclxuXHRcdFx0XHQoIGkgKyAxICkgJSBudW1Nb3JwaFRhcmdldHMgKTtcclxuXHJcblx0XHRcdHZhbHVlcy5wdXNoKCAwLCAxLCAwICk7XHJcblxyXG5cdFx0XHRjb25zdCBvcmRlciA9IEFuaW1hdGlvblV0aWxzLmdldEtleWZyYW1lT3JkZXIoIHRpbWVzICk7XHJcblx0XHRcdHRpbWVzID0gQW5pbWF0aW9uVXRpbHMuc29ydGVkQXJyYXkoIHRpbWVzLCAxLCBvcmRlciApO1xyXG5cdFx0XHR2YWx1ZXMgPSBBbmltYXRpb25VdGlscy5zb3J0ZWRBcnJheSggdmFsdWVzLCAxLCBvcmRlciApO1xyXG5cclxuXHRcdFx0Ly8gaWYgdGhlcmUgaXMgYSBrZXkgYXQgdGhlIGZpcnN0IGZyYW1lLCBkdXBsaWNhdGUgaXQgYXMgdGhlXHJcblx0XHRcdC8vIGxhc3QgZnJhbWUgYXMgd2VsbCBmb3IgcGVyZmVjdCBsb29wLlxyXG5cdFx0XHRpZiAoICEgbm9Mb29wICYmIHRpbWVzWyAwIF0gPT09IDAgKSB7XHJcblxyXG5cdFx0XHRcdHRpbWVzLnB1c2goIG51bU1vcnBoVGFyZ2V0cyApO1xyXG5cdFx0XHRcdHZhbHVlcy5wdXNoKCB2YWx1ZXNbIDAgXSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0dHJhY2tzLnB1c2goXHJcblx0XHRcdFx0bmV3IE51bWJlcktleWZyYW1lVHJhY2soXHJcblx0XHRcdFx0XHQnLm1vcnBoVGFyZ2V0SW5mbHVlbmNlc1snICsgbW9ycGhUYXJnZXRTZXF1ZW5jZVsgaSBdLm5hbWUgKyAnXScsXHJcblx0XHRcdFx0XHR0aW1lcywgdmFsdWVzXHJcblx0XHRcdFx0KS5zY2FsZSggMS4wIC8gZnBzICkgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIG5ldyB0aGlzKCBuYW1lLCAtIDEsIHRyYWNrcyApO1xyXG5cclxuXHR9XHJcblxyXG5cdHN0YXRpYyBmaW5kQnlOYW1lKCBvYmplY3RPckNsaXBBcnJheSwgbmFtZSApIHtcclxuXHJcblx0XHRsZXQgY2xpcEFycmF5ID0gb2JqZWN0T3JDbGlwQXJyYXk7XHJcblxyXG5cdFx0aWYgKCAhIEFycmF5LmlzQXJyYXkoIG9iamVjdE9yQ2xpcEFycmF5ICkgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBvID0gb2JqZWN0T3JDbGlwQXJyYXk7XHJcblx0XHRcdGNsaXBBcnJheSA9IG8uZ2VvbWV0cnkgJiYgby5nZW9tZXRyeS5hbmltYXRpb25zIHx8IG8uYW5pbWF0aW9ucztcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgY2xpcEFycmF5Lmxlbmd0aDsgaSArKyApIHtcclxuXHJcblx0XHRcdGlmICggY2xpcEFycmF5WyBpIF0ubmFtZSA9PT0gbmFtZSApIHtcclxuXHJcblx0XHRcdFx0cmV0dXJuIGNsaXBBcnJheVsgaSBdO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gbnVsbDtcclxuXHJcblx0fVxyXG5cclxuXHRzdGF0aWMgQ3JlYXRlQ2xpcHNGcm9tTW9ycGhUYXJnZXRTZXF1ZW5jZXMoIG1vcnBoVGFyZ2V0cywgZnBzLCBub0xvb3AgKSB7XHJcblxyXG5cdFx0Y29uc3QgYW5pbWF0aW9uVG9Nb3JwaFRhcmdldHMgPSB7fTtcclxuXHJcblx0XHQvLyB0ZXN0ZWQgd2l0aCBodHRwczovL3JlZ2V4MTAxLmNvbS8gb24gdHJpY2sgc2VxdWVuY2VzXHJcblx0XHQvLyBzdWNoIGZsYW1pbmdvX2ZseUFfMDAzLCBmbGFtaW5nb19ydW4xXzAwMywgY3JkZWF0aDAwNTlcclxuXHRcdGNvbnN0IHBhdHRlcm4gPSAvXihbXFx3LV0qPykoW1xcZF0rKSQvO1xyXG5cclxuXHRcdC8vIHNvcnQgbW9ycGggdGFyZ2V0IG5hbWVzIGludG8gYW5pbWF0aW9uIGdyb3VwcyBiYXNlZFxyXG5cdFx0Ly8gcGF0dGVybnMgbGlrZSBXYWxrXzAwMSwgV2Fsa18wMDIsIFJ1bl8wMDEsIFJ1bl8wMDJcclxuXHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSBtb3JwaFRhcmdldHMubGVuZ3RoOyBpIDwgaWw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBtb3JwaFRhcmdldCA9IG1vcnBoVGFyZ2V0c1sgaSBdO1xyXG5cdFx0XHRjb25zdCBwYXJ0cyA9IG1vcnBoVGFyZ2V0Lm5hbWUubWF0Y2goIHBhdHRlcm4gKTtcclxuXHJcblx0XHRcdGlmICggcGFydHMgJiYgcGFydHMubGVuZ3RoID4gMSApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgbmFtZSA9IHBhcnRzWyAxIF07XHJcblxyXG5cdFx0XHRcdGxldCBhbmltYXRpb25Nb3JwaFRhcmdldHMgPSBhbmltYXRpb25Ub01vcnBoVGFyZ2V0c1sgbmFtZSBdO1xyXG5cclxuXHRcdFx0XHRpZiAoICEgYW5pbWF0aW9uTW9ycGhUYXJnZXRzICkge1xyXG5cclxuXHRcdFx0XHRcdGFuaW1hdGlvblRvTW9ycGhUYXJnZXRzWyBuYW1lIF0gPSBhbmltYXRpb25Nb3JwaFRhcmdldHMgPSBbXTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRhbmltYXRpb25Nb3JwaFRhcmdldHMucHVzaCggbW9ycGhUYXJnZXQgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Y29uc3QgY2xpcHMgPSBbXTtcclxuXHJcblx0XHRmb3IgKCBjb25zdCBuYW1lIGluIGFuaW1hdGlvblRvTW9ycGhUYXJnZXRzICkge1xyXG5cclxuXHRcdFx0Y2xpcHMucHVzaCggdGhpcy5DcmVhdGVGcm9tTW9ycGhUYXJnZXRTZXF1ZW5jZSggbmFtZSwgYW5pbWF0aW9uVG9Nb3JwaFRhcmdldHNbIG5hbWUgXSwgZnBzLCBub0xvb3AgKSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gY2xpcHM7XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gcGFyc2UgdGhlIGFuaW1hdGlvbi5oaWVyYXJjaHkgZm9ybWF0XHJcblx0c3RhdGljIHBhcnNlQW5pbWF0aW9uKCBhbmltYXRpb24sIGJvbmVzICkge1xyXG5cclxuXHRcdGlmICggISBhbmltYXRpb24gKSB7XHJcblxyXG5cdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuQW5pbWF0aW9uQ2xpcDogTm8gYW5pbWF0aW9uIGluIEpTT05Mb2FkZXIgZGF0YS4nICk7XHJcblx0XHRcdHJldHVybiBudWxsO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCBhZGROb25lbXB0eVRyYWNrID0gZnVuY3Rpb24gKCB0cmFja1R5cGUsIHRyYWNrTmFtZSwgYW5pbWF0aW9uS2V5cywgcHJvcGVydHlOYW1lLCBkZXN0VHJhY2tzICkge1xyXG5cclxuXHRcdFx0Ly8gb25seSByZXR1cm4gdHJhY2sgaWYgdGhlcmUgYXJlIGFjdHVhbGx5IGtleXMuXHJcblx0XHRcdGlmICggYW5pbWF0aW9uS2V5cy5sZW5ndGggIT09IDAgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IHRpbWVzID0gW107XHJcblx0XHRcdFx0Y29uc3QgdmFsdWVzID0gW107XHJcblxyXG5cdFx0XHRcdEFuaW1hdGlvblV0aWxzLmZsYXR0ZW5KU09OKCBhbmltYXRpb25LZXlzLCB0aW1lcywgdmFsdWVzLCBwcm9wZXJ0eU5hbWUgKTtcclxuXHJcblx0XHRcdFx0Ly8gZW1wdHkga2V5cyBhcmUgZmlsdGVyZWQgb3V0LCBzbyBjaGVjayBhZ2FpblxyXG5cdFx0XHRcdGlmICggdGltZXMubGVuZ3RoICE9PSAwICkge1xyXG5cclxuXHRcdFx0XHRcdGRlc3RUcmFja3MucHVzaCggbmV3IHRyYWNrVHlwZSggdHJhY2tOYW1lLCB0aW1lcywgdmFsdWVzICkgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH07XHJcblxyXG5cdFx0Y29uc3QgdHJhY2tzID0gW107XHJcblxyXG5cdFx0Y29uc3QgY2xpcE5hbWUgPSBhbmltYXRpb24ubmFtZSB8fCAnZGVmYXVsdCc7XHJcblx0XHRjb25zdCBmcHMgPSBhbmltYXRpb24uZnBzIHx8IDMwO1xyXG5cdFx0Y29uc3QgYmxlbmRNb2RlID0gYW5pbWF0aW9uLmJsZW5kTW9kZTtcclxuXHJcblx0XHQvLyBhdXRvbWF0aWMgbGVuZ3RoIGRldGVybWluYXRpb24gaW4gQW5pbWF0aW9uQ2xpcC5cclxuXHRcdGxldCBkdXJhdGlvbiA9IGFuaW1hdGlvbi5sZW5ndGggfHwgLSAxO1xyXG5cclxuXHRcdGNvbnN0IGhpZXJhcmNoeVRyYWNrcyA9IGFuaW1hdGlvbi5oaWVyYXJjaHkgfHwgW107XHJcblxyXG5cdFx0Zm9yICggbGV0IGggPSAwOyBoIDwgaGllcmFyY2h5VHJhY2tzLmxlbmd0aDsgaCArKyApIHtcclxuXHJcblx0XHRcdGNvbnN0IGFuaW1hdGlvbktleXMgPSBoaWVyYXJjaHlUcmFja3NbIGggXS5rZXlzO1xyXG5cclxuXHRcdFx0Ly8gc2tpcCBlbXB0eSB0cmFja3NcclxuXHRcdFx0aWYgKCAhIGFuaW1hdGlvbktleXMgfHwgYW5pbWF0aW9uS2V5cy5sZW5ndGggPT09IDAgKSBjb250aW51ZTtcclxuXHJcblx0XHRcdC8vIHByb2Nlc3MgbW9ycGggdGFyZ2V0c1xyXG5cdFx0XHRpZiAoIGFuaW1hdGlvbktleXNbIDAgXS5tb3JwaFRhcmdldHMgKSB7XHJcblxyXG5cdFx0XHRcdC8vIGZpZ3VyZSBvdXQgYWxsIG1vcnBoIHRhcmdldHMgdXNlZCBpbiB0aGlzIHRyYWNrXHJcblx0XHRcdFx0Y29uc3QgbW9ycGhUYXJnZXROYW1lcyA9IHt9O1xyXG5cclxuXHRcdFx0XHRsZXQgaztcclxuXHJcblx0XHRcdFx0Zm9yICggayA9IDA7IGsgPCBhbmltYXRpb25LZXlzLmxlbmd0aDsgayArKyApIHtcclxuXHJcblx0XHRcdFx0XHRpZiAoIGFuaW1hdGlvbktleXNbIGsgXS5tb3JwaFRhcmdldHMgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRmb3IgKCBsZXQgbSA9IDA7IG0gPCBhbmltYXRpb25LZXlzWyBrIF0ubW9ycGhUYXJnZXRzLmxlbmd0aDsgbSArKyApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0bW9ycGhUYXJnZXROYW1lc1sgYW5pbWF0aW9uS2V5c1sgayBdLm1vcnBoVGFyZ2V0c1sgbSBdIF0gPSAtIDE7XHJcblxyXG5cdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdC8vIGNyZWF0ZSBhIHRyYWNrIGZvciBlYWNoIG1vcnBoIHRhcmdldCB3aXRoIGFsbCB6ZXJvXHJcblx0XHRcdFx0Ly8gbW9ycGhUYXJnZXRJbmZsdWVuY2VzIGV4Y2VwdCBmb3IgdGhlIGtleXMgaW4gd2hpY2hcclxuXHRcdFx0XHQvLyB0aGUgbW9ycGhUYXJnZXQgaXMgbmFtZWQuXHJcblx0XHRcdFx0Zm9yICggY29uc3QgbW9ycGhUYXJnZXROYW1lIGluIG1vcnBoVGFyZ2V0TmFtZXMgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgdGltZXMgPSBbXTtcclxuXHRcdFx0XHRcdGNvbnN0IHZhbHVlcyA9IFtdO1xyXG5cclxuXHRcdFx0XHRcdGZvciAoIGxldCBtID0gMDsgbSAhPT0gYW5pbWF0aW9uS2V5c1sgayBdLm1vcnBoVGFyZ2V0cy5sZW5ndGg7ICsrIG0gKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRjb25zdCBhbmltYXRpb25LZXkgPSBhbmltYXRpb25LZXlzWyBrIF07XHJcblxyXG5cdFx0XHRcdFx0XHR0aW1lcy5wdXNoKCBhbmltYXRpb25LZXkudGltZSApO1xyXG5cdFx0XHRcdFx0XHR2YWx1ZXMucHVzaCggKCBhbmltYXRpb25LZXkubW9ycGhUYXJnZXQgPT09IG1vcnBoVGFyZ2V0TmFtZSApID8gMSA6IDAgKTtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0dHJhY2tzLnB1c2goIG5ldyBOdW1iZXJLZXlmcmFtZVRyYWNrKCAnLm1vcnBoVGFyZ2V0SW5mbHVlbmNlWycgKyBtb3JwaFRhcmdldE5hbWUgKyAnXScsIHRpbWVzLCB2YWx1ZXMgKSApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdGR1cmF0aW9uID0gbW9ycGhUYXJnZXROYW1lcy5sZW5ndGggKiBmcHM7XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHQvLyAuLi5hc3N1bWUgc2tlbGV0YWwgYW5pbWF0aW9uXHJcblxyXG5cdFx0XHRcdGNvbnN0IGJvbmVOYW1lID0gJy5ib25lc1snICsgYm9uZXNbIGggXS5uYW1lICsgJ10nO1xyXG5cclxuXHRcdFx0XHRhZGROb25lbXB0eVRyYWNrKFxyXG5cdFx0XHRcdFx0VmVjdG9yS2V5ZnJhbWVUcmFjaywgYm9uZU5hbWUgKyAnLnBvc2l0aW9uJyxcclxuXHRcdFx0XHRcdGFuaW1hdGlvbktleXMsICdwb3MnLCB0cmFja3MgKTtcclxuXHJcblx0XHRcdFx0YWRkTm9uZW1wdHlUcmFjayhcclxuXHRcdFx0XHRcdFF1YXRlcm5pb25LZXlmcmFtZVRyYWNrLCBib25lTmFtZSArICcucXVhdGVybmlvbicsXHJcblx0XHRcdFx0XHRhbmltYXRpb25LZXlzLCAncm90JywgdHJhY2tzICk7XHJcblxyXG5cdFx0XHRcdGFkZE5vbmVtcHR5VHJhY2soXHJcblx0XHRcdFx0XHRWZWN0b3JLZXlmcmFtZVRyYWNrLCBib25lTmFtZSArICcuc2NhbGUnLFxyXG5cdFx0XHRcdFx0YW5pbWF0aW9uS2V5cywgJ3NjbCcsIHRyYWNrcyApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHRyYWNrcy5sZW5ndGggPT09IDAgKSB7XHJcblxyXG5cdFx0XHRyZXR1cm4gbnVsbDtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Y29uc3QgY2xpcCA9IG5ldyB0aGlzKCBjbGlwTmFtZSwgZHVyYXRpb24sIHRyYWNrcywgYmxlbmRNb2RlICk7XHJcblxyXG5cdFx0cmV0dXJuIGNsaXA7XHJcblxyXG5cdH1cclxuXHJcblx0cmVzZXREdXJhdGlvbigpIHtcclxuXHJcblx0XHRjb25zdCB0cmFja3MgPSB0aGlzLnRyYWNrcztcclxuXHRcdGxldCBkdXJhdGlvbiA9IDA7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBuID0gdHJhY2tzLmxlbmd0aDsgaSAhPT0gbjsgKysgaSApIHtcclxuXHJcblx0XHRcdGNvbnN0IHRyYWNrID0gdGhpcy50cmFja3NbIGkgXTtcclxuXHJcblx0XHRcdGR1cmF0aW9uID0gTWF0aC5tYXgoIGR1cmF0aW9uLCB0cmFjay50aW1lc1sgdHJhY2sudGltZXMubGVuZ3RoIC0gMSBdICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMuZHVyYXRpb24gPSBkdXJhdGlvbjtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHR0cmltKCkge1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHRoaXMudHJhY2tzLmxlbmd0aDsgaSArKyApIHtcclxuXHJcblx0XHRcdHRoaXMudHJhY2tzWyBpIF0udHJpbSggMCwgdGhpcy5kdXJhdGlvbiApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHR2YWxpZGF0ZSgpIHtcclxuXHJcblx0XHRsZXQgdmFsaWQgPSB0cnVlO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHRoaXMudHJhY2tzLmxlbmd0aDsgaSArKyApIHtcclxuXHJcblx0XHRcdHZhbGlkID0gdmFsaWQgJiYgdGhpcy50cmFja3NbIGkgXS52YWxpZGF0ZSgpO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdmFsaWQ7XHJcblxyXG5cdH1cclxuXHJcblx0b3B0aW1pemUoKSB7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgdGhpcy50cmFja3MubGVuZ3RoOyBpICsrICkge1xyXG5cclxuXHRcdFx0dGhpcy50cmFja3NbIGkgXS5vcHRpbWl6ZSgpO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRjbG9uZSgpIHtcclxuXHJcblx0XHRjb25zdCB0cmFja3MgPSBbXTtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCB0aGlzLnRyYWNrcy5sZW5ndGg7IGkgKysgKSB7XHJcblxyXG5cdFx0XHR0cmFja3MucHVzaCggdGhpcy50cmFja3NbIGkgXS5jbG9uZSgpICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiBuZXcgdGhpcy5jb25zdHJ1Y3RvciggdGhpcy5uYW1lLCB0aGlzLmR1cmF0aW9uLCB0cmFja3MsIHRoaXMuYmxlbmRNb2RlICk7XHJcblxyXG5cdH1cclxuXHJcblx0dG9KU09OKCkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLmNvbnN0cnVjdG9yLnRvSlNPTiggdGhpcyApO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiBnZXRUcmFja1R5cGVGb3JWYWx1ZVR5cGVOYW1lKCB0eXBlTmFtZSApIHtcclxuXHJcblx0c3dpdGNoICggdHlwZU5hbWUudG9Mb3dlckNhc2UoKSApIHtcclxuXHJcblx0XHRjYXNlICdzY2FsYXInOlxyXG5cdFx0Y2FzZSAnZG91YmxlJzpcclxuXHRcdGNhc2UgJ2Zsb2F0JzpcclxuXHRcdGNhc2UgJ251bWJlcic6XHJcblx0XHRjYXNlICdpbnRlZ2VyJzpcclxuXHJcblx0XHRcdHJldHVybiBOdW1iZXJLZXlmcmFtZVRyYWNrO1xyXG5cclxuXHRcdGNhc2UgJ3ZlY3Rvcic6XHJcblx0XHRjYXNlICd2ZWN0b3IyJzpcclxuXHRcdGNhc2UgJ3ZlY3RvcjMnOlxyXG5cdFx0Y2FzZSAndmVjdG9yNCc6XHJcblxyXG5cdFx0XHRyZXR1cm4gVmVjdG9yS2V5ZnJhbWVUcmFjaztcclxuXHJcblx0XHRjYXNlICdjb2xvcic6XHJcblxyXG5cdFx0XHRyZXR1cm4gQ29sb3JLZXlmcmFtZVRyYWNrO1xyXG5cclxuXHRcdGNhc2UgJ3F1YXRlcm5pb24nOlxyXG5cclxuXHRcdFx0cmV0dXJuIFF1YXRlcm5pb25LZXlmcmFtZVRyYWNrO1xyXG5cclxuXHRcdGNhc2UgJ2Jvb2wnOlxyXG5cdFx0Y2FzZSAnYm9vbGVhbic6XHJcblxyXG5cdFx0XHRyZXR1cm4gQm9vbGVhbktleWZyYW1lVHJhY2s7XHJcblxyXG5cdFx0Y2FzZSAnc3RyaW5nJzpcclxuXHJcblx0XHRcdHJldHVybiBTdHJpbmdLZXlmcmFtZVRyYWNrO1xyXG5cclxuXHR9XHJcblxyXG5cdHRocm93IG5ldyBFcnJvciggJ1RIUkVFLktleWZyYW1lVHJhY2s6IFVuc3VwcG9ydGVkIHR5cGVOYW1lOiAnICsgdHlwZU5hbWUgKTtcclxuXHJcbn1cclxuXHJcbmZ1bmN0aW9uIHBhcnNlS2V5ZnJhbWVUcmFjaygganNvbiApIHtcclxuXHJcblx0aWYgKCBqc29uLnR5cGUgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHR0aHJvdyBuZXcgRXJyb3IoICdUSFJFRS5LZXlmcmFtZVRyYWNrOiB0cmFjayB0eXBlIHVuZGVmaW5lZCwgY2FuIG5vdCBwYXJzZScgKTtcclxuXHJcblx0fVxyXG5cclxuXHRjb25zdCB0cmFja1R5cGUgPSBnZXRUcmFja1R5cGVGb3JWYWx1ZVR5cGVOYW1lKCBqc29uLnR5cGUgKTtcclxuXHJcblx0aWYgKCBqc29uLnRpbWVzID09PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0Y29uc3QgdGltZXMgPSBbXSwgdmFsdWVzID0gW107XHJcblxyXG5cdFx0QW5pbWF0aW9uVXRpbHMuZmxhdHRlbkpTT04oIGpzb24ua2V5cywgdGltZXMsIHZhbHVlcywgJ3ZhbHVlJyApO1xyXG5cclxuXHRcdGpzb24udGltZXMgPSB0aW1lcztcclxuXHRcdGpzb24udmFsdWVzID0gdmFsdWVzO1xyXG5cclxuXHR9XHJcblxyXG5cdC8vIGRlcml2ZWQgY2xhc3NlcyBjYW4gZGVmaW5lIGEgc3RhdGljIHBhcnNlIG1ldGhvZFxyXG5cdGlmICggdHJhY2tUeXBlLnBhcnNlICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRyYWNrVHlwZS5wYXJzZSgganNvbiApO1xyXG5cclxuXHR9IGVsc2Uge1xyXG5cclxuXHRcdC8vIGJ5IGRlZmF1bHQsIHdlIGFzc3VtZSBhIGNvbnN0cnVjdG9yIGNvbXBhdGlibGUgd2l0aCB0aGUgYmFzZVxyXG5cdFx0cmV0dXJuIG5ldyB0cmFja1R5cGUoIGpzb24ubmFtZSwganNvbi50aW1lcywganNvbi52YWx1ZXMsIGpzb24uaW50ZXJwb2xhdGlvbiApO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBBbmltYXRpb25DbGlwIH07XHJcbiIsImNvbnN0IENhY2hlID0ge1xyXG5cclxuXHRlbmFibGVkOiBmYWxzZSxcclxuXHJcblx0ZmlsZXM6IHt9LFxyXG5cclxuXHRhZGQ6IGZ1bmN0aW9uICgga2V5LCBmaWxlICkge1xyXG5cclxuXHRcdGlmICggdGhpcy5lbmFibGVkID09PSBmYWxzZSApIHJldHVybjtcclxuXHJcblx0XHQvLyBjb25zb2xlLmxvZyggJ1RIUkVFLkNhY2hlJywgJ0FkZGluZyBrZXk6Jywga2V5ICk7XHJcblxyXG5cdFx0dGhpcy5maWxlc1sga2V5IF0gPSBmaWxlO1xyXG5cclxuXHR9LFxyXG5cclxuXHRnZXQ6IGZ1bmN0aW9uICgga2V5ICkge1xyXG5cclxuXHRcdGlmICggdGhpcy5lbmFibGVkID09PSBmYWxzZSApIHJldHVybjtcclxuXHJcblx0XHQvLyBjb25zb2xlLmxvZyggJ1RIUkVFLkNhY2hlJywgJ0NoZWNraW5nIGtleTonLCBrZXkgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5maWxlc1sga2V5IF07XHJcblxyXG5cdH0sXHJcblxyXG5cdHJlbW92ZTogZnVuY3Rpb24gKCBrZXkgKSB7XHJcblxyXG5cdFx0ZGVsZXRlIHRoaXMuZmlsZXNbIGtleSBdO1xyXG5cclxuXHR9LFxyXG5cclxuXHRjbGVhcjogZnVuY3Rpb24gKCkge1xyXG5cclxuXHRcdHRoaXMuZmlsZXMgPSB7fTtcclxuXHJcblx0fVxyXG5cclxufTtcclxuXHJcblxyXG5leHBvcnQgeyBDYWNoZSB9O1xyXG4iLCJjbGFzcyBMb2FkaW5nTWFuYWdlciB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBvbkxvYWQsIG9uUHJvZ3Jlc3MsIG9uRXJyb3IgKSB7XHJcblxyXG5cdFx0Y29uc3Qgc2NvcGUgPSB0aGlzO1xyXG5cclxuXHRcdGxldCBpc0xvYWRpbmcgPSBmYWxzZTtcclxuXHRcdGxldCBpdGVtc0xvYWRlZCA9IDA7XHJcblx0XHRsZXQgaXRlbXNUb3RhbCA9IDA7XHJcblx0XHRsZXQgdXJsTW9kaWZpZXIgPSB1bmRlZmluZWQ7XHJcblx0XHRjb25zdCBoYW5kbGVycyA9IFtdO1xyXG5cclxuXHRcdC8vIFJlZmVyIHRvICM1Njg5IGZvciB0aGUgcmVhc29uIHdoeSB3ZSBkb24ndCBzZXQgLm9uU3RhcnRcclxuXHRcdC8vIGluIHRoZSBjb25zdHJ1Y3RvclxyXG5cclxuXHRcdHRoaXMub25TdGFydCA9IHVuZGVmaW5lZDtcclxuXHRcdHRoaXMub25Mb2FkID0gb25Mb2FkO1xyXG5cdFx0dGhpcy5vblByb2dyZXNzID0gb25Qcm9ncmVzcztcclxuXHRcdHRoaXMub25FcnJvciA9IG9uRXJyb3I7XHJcblxyXG5cdFx0dGhpcy5pdGVtU3RhcnQgPSBmdW5jdGlvbiAoIHVybCApIHtcclxuXHJcblx0XHRcdGl0ZW1zVG90YWwgKys7XHJcblxyXG5cdFx0XHRpZiAoIGlzTG9hZGluZyA9PT0gZmFsc2UgKSB7XHJcblxyXG5cdFx0XHRcdGlmICggc2NvcGUub25TdGFydCAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHRcdHNjb3BlLm9uU3RhcnQoIHVybCwgaXRlbXNMb2FkZWQsIGl0ZW1zVG90YWwgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0aXNMb2FkaW5nID0gdHJ1ZTtcclxuXHJcblx0XHR9O1xyXG5cclxuXHRcdHRoaXMuaXRlbUVuZCA9IGZ1bmN0aW9uICggdXJsICkge1xyXG5cclxuXHRcdFx0aXRlbXNMb2FkZWQgKys7XHJcblxyXG5cdFx0XHRpZiAoIHNjb3BlLm9uUHJvZ3Jlc3MgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0c2NvcGUub25Qcm9ncmVzcyggdXJsLCBpdGVtc0xvYWRlZCwgaXRlbXNUb3RhbCApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0aWYgKCBpdGVtc0xvYWRlZCA9PT0gaXRlbXNUb3RhbCApIHtcclxuXHJcblx0XHRcdFx0aXNMb2FkaW5nID0gZmFsc2U7XHJcblxyXG5cdFx0XHRcdGlmICggc2NvcGUub25Mb2FkICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRcdFx0c2NvcGUub25Mb2FkKCk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9O1xyXG5cclxuXHRcdHRoaXMuaXRlbUVycm9yID0gZnVuY3Rpb24gKCB1cmwgKSB7XHJcblxyXG5cdFx0XHRpZiAoIHNjb3BlLm9uRXJyb3IgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0c2NvcGUub25FcnJvciggdXJsICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fTtcclxuXHJcblx0XHR0aGlzLnJlc29sdmVVUkwgPSBmdW5jdGlvbiAoIHVybCApIHtcclxuXHJcblx0XHRcdGlmICggdXJsTW9kaWZpZXIgKSB7XHJcblxyXG5cdFx0XHRcdHJldHVybiB1cmxNb2RpZmllciggdXJsICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRyZXR1cm4gdXJsO1xyXG5cclxuXHRcdH07XHJcblxyXG5cdFx0dGhpcy5zZXRVUkxNb2RpZmllciA9IGZ1bmN0aW9uICggdHJhbnNmb3JtICkge1xyXG5cclxuXHRcdFx0dXJsTW9kaWZpZXIgPSB0cmFuc2Zvcm07XHJcblxyXG5cdFx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0XHR9O1xyXG5cclxuXHRcdHRoaXMuYWRkSGFuZGxlciA9IGZ1bmN0aW9uICggcmVnZXgsIGxvYWRlciApIHtcclxuXHJcblx0XHRcdGhhbmRsZXJzLnB1c2goIHJlZ2V4LCBsb2FkZXIgKTtcclxuXHJcblx0XHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHRcdH07XHJcblxyXG5cdFx0dGhpcy5yZW1vdmVIYW5kbGVyID0gZnVuY3Rpb24gKCByZWdleCApIHtcclxuXHJcblx0XHRcdGNvbnN0IGluZGV4ID0gaGFuZGxlcnMuaW5kZXhPZiggcmVnZXggKTtcclxuXHJcblx0XHRcdGlmICggaW5kZXggIT09IC0gMSApIHtcclxuXHJcblx0XHRcdFx0aGFuZGxlcnMuc3BsaWNlKCBpbmRleCwgMiApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdFx0fTtcclxuXHJcblx0XHR0aGlzLmdldEhhbmRsZXIgPSBmdW5jdGlvbiAoIGZpbGUgKSB7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBoYW5kbGVycy5sZW5ndGg7IGkgPCBsOyBpICs9IDIgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IHJlZ2V4ID0gaGFuZGxlcnNbIGkgXTtcclxuXHRcdFx0XHRjb25zdCBsb2FkZXIgPSBoYW5kbGVyc1sgaSArIDEgXTtcclxuXHJcblx0XHRcdFx0aWYgKCByZWdleC5nbG9iYWwgKSByZWdleC5sYXN0SW5kZXggPSAwOyAvLyBzZWUgIzE3OTIwXHJcblxyXG5cdFx0XHRcdGlmICggcmVnZXgudGVzdCggZmlsZSApICkge1xyXG5cclxuXHRcdFx0XHRcdHJldHVybiBsb2FkZXI7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHJldHVybiBudWxsO1xyXG5cclxuXHRcdH07XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmNvbnN0IERlZmF1bHRMb2FkaW5nTWFuYWdlciA9IC8qQF9fUFVSRV9fKi8gbmV3IExvYWRpbmdNYW5hZ2VyKCk7XHJcblxyXG5leHBvcnQgeyBEZWZhdWx0TG9hZGluZ01hbmFnZXIsIExvYWRpbmdNYW5hZ2VyIH07XHJcbiIsImltcG9ydCB7IERlZmF1bHRMb2FkaW5nTWFuYWdlciB9IGZyb20gJy4vTG9hZGluZ01hbmFnZXIuanMnO1xyXG5cclxuY2xhc3MgTG9hZGVyIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIG1hbmFnZXIgKSB7XHJcblxyXG5cdFx0dGhpcy5tYW5hZ2VyID0gKCBtYW5hZ2VyICE9PSB1bmRlZmluZWQgKSA/IG1hbmFnZXIgOiBEZWZhdWx0TG9hZGluZ01hbmFnZXI7XHJcblxyXG5cdFx0dGhpcy5jcm9zc09yaWdpbiA9ICdhbm9ueW1vdXMnO1xyXG5cdFx0dGhpcy53aXRoQ3JlZGVudGlhbHMgPSBmYWxzZTtcclxuXHRcdHRoaXMucGF0aCA9ICcnO1xyXG5cdFx0dGhpcy5yZXNvdXJjZVBhdGggPSAnJztcclxuXHRcdHRoaXMucmVxdWVzdEhlYWRlciA9IHt9O1xyXG5cclxuXHR9XHJcblxyXG5cdGxvYWQoIC8qIHVybCwgb25Mb2FkLCBvblByb2dyZXNzLCBvbkVycm9yICovICkge31cclxuXHJcblx0bG9hZEFzeW5jKCB1cmwsIG9uUHJvZ3Jlc3MgKSB7XHJcblxyXG5cdFx0Y29uc3Qgc2NvcGUgPSB0aGlzO1xyXG5cclxuXHRcdHJldHVybiBuZXcgUHJvbWlzZSggZnVuY3Rpb24gKCByZXNvbHZlLCByZWplY3QgKSB7XHJcblxyXG5cdFx0XHRzY29wZS5sb2FkKCB1cmwsIHJlc29sdmUsIG9uUHJvZ3Jlc3MsIHJlamVjdCApO1xyXG5cclxuXHRcdH0gKTtcclxuXHJcblx0fVxyXG5cclxuXHRwYXJzZSggLyogZGF0YSAqLyApIHt9XHJcblxyXG5cdHNldENyb3NzT3JpZ2luKCBjcm9zc09yaWdpbiApIHtcclxuXHJcblx0XHR0aGlzLmNyb3NzT3JpZ2luID0gY3Jvc3NPcmlnaW47XHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRXaXRoQ3JlZGVudGlhbHMoIHZhbHVlICkge1xyXG5cclxuXHRcdHRoaXMud2l0aENyZWRlbnRpYWxzID0gdmFsdWU7XHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRQYXRoKCBwYXRoICkge1xyXG5cclxuXHRcdHRoaXMucGF0aCA9IHBhdGg7XHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRSZXNvdXJjZVBhdGgoIHJlc291cmNlUGF0aCApIHtcclxuXHJcblx0XHR0aGlzLnJlc291cmNlUGF0aCA9IHJlc291cmNlUGF0aDtcclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldFJlcXVlc3RIZWFkZXIoIHJlcXVlc3RIZWFkZXIgKSB7XHJcblxyXG5cdFx0dGhpcy5yZXF1ZXN0SGVhZGVyID0gcmVxdWVzdEhlYWRlcjtcclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5Mb2FkZXIuREVGQVVMVF9NQVRFUklBTF9OQU1FID0gJ19fREVGQVVMVCc7XHJcblxyXG5leHBvcnQgeyBMb2FkZXIgfTtcclxuIiwiaW1wb3J0IHsgQ2FjaGUgfSBmcm9tICcuL0NhY2hlLmpzJztcclxuaW1wb3J0IHsgTG9hZGVyIH0gZnJvbSAnLi9Mb2FkZXIuanMnO1xyXG5cclxuY29uc3QgbG9hZGluZyA9IHt9O1xyXG5cclxuY2xhc3MgSHR0cEVycm9yIGV4dGVuZHMgRXJyb3Ige1xyXG5cclxuXHRjb25zdHJ1Y3RvciggbWVzc2FnZSwgcmVzcG9uc2UgKSB7XHJcblxyXG5cdFx0c3VwZXIoIG1lc3NhZ2UgKTtcclxuXHRcdHRoaXMucmVzcG9uc2UgPSByZXNwb25zZTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuY2xhc3MgRmlsZUxvYWRlciBleHRlbmRzIExvYWRlciB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBtYW5hZ2VyICkge1xyXG5cclxuXHRcdHN1cGVyKCBtYW5hZ2VyICk7XHJcblxyXG5cdH1cclxuXHJcblx0bG9hZCggdXJsLCBvbkxvYWQsIG9uUHJvZ3Jlc3MsIG9uRXJyb3IgKSB7XHJcblxyXG5cdFx0aWYgKCB1cmwgPT09IHVuZGVmaW5lZCApIHVybCA9ICcnO1xyXG5cclxuXHRcdGlmICggdGhpcy5wYXRoICE9PSB1bmRlZmluZWQgKSB1cmwgPSB0aGlzLnBhdGggKyB1cmw7XHJcblxyXG5cdFx0dXJsID0gdGhpcy5tYW5hZ2VyLnJlc29sdmVVUkwoIHVybCApO1xyXG5cclxuXHRcdGNvbnN0IGNhY2hlZCA9IENhY2hlLmdldCggdXJsICk7XHJcblxyXG5cdFx0aWYgKCBjYWNoZWQgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdHRoaXMubWFuYWdlci5pdGVtU3RhcnQoIHVybCApO1xyXG5cclxuXHRcdFx0c2V0VGltZW91dCggKCkgPT4ge1xyXG5cclxuXHRcdFx0XHRpZiAoIG9uTG9hZCApIG9uTG9hZCggY2FjaGVkICk7XHJcblxyXG5cdFx0XHRcdHRoaXMubWFuYWdlci5pdGVtRW5kKCB1cmwgKTtcclxuXHJcblx0XHRcdH0sIDAgKTtcclxuXHJcblx0XHRcdHJldHVybiBjYWNoZWQ7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIENoZWNrIGlmIHJlcXVlc3QgaXMgZHVwbGljYXRlXHJcblxyXG5cdFx0aWYgKCBsb2FkaW5nWyB1cmwgXSAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0bG9hZGluZ1sgdXJsIF0ucHVzaCgge1xyXG5cclxuXHRcdFx0XHRvbkxvYWQ6IG9uTG9hZCxcclxuXHRcdFx0XHRvblByb2dyZXNzOiBvblByb2dyZXNzLFxyXG5cdFx0XHRcdG9uRXJyb3I6IG9uRXJyb3JcclxuXHJcblx0XHRcdH0gKTtcclxuXHJcblx0XHRcdHJldHVybjtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gSW5pdGlhbGlzZSBhcnJheSBmb3IgZHVwbGljYXRlIHJlcXVlc3RzXHJcblx0XHRsb2FkaW5nWyB1cmwgXSA9IFtdO1xyXG5cclxuXHRcdGxvYWRpbmdbIHVybCBdLnB1c2goIHtcclxuXHRcdFx0b25Mb2FkOiBvbkxvYWQsXHJcblx0XHRcdG9uUHJvZ3Jlc3M6IG9uUHJvZ3Jlc3MsXHJcblx0XHRcdG9uRXJyb3I6IG9uRXJyb3IsXHJcblx0XHR9ICk7XHJcblxyXG5cdFx0Ly8gY3JlYXRlIHJlcXVlc3RcclxuXHRcdGNvbnN0IHJlcSA9IG5ldyBSZXF1ZXN0KCB1cmwsIHtcclxuXHRcdFx0aGVhZGVyczogbmV3IEhlYWRlcnMoIHRoaXMucmVxdWVzdEhlYWRlciApLFxyXG5cdFx0XHRjcmVkZW50aWFsczogdGhpcy53aXRoQ3JlZGVudGlhbHMgPyAnaW5jbHVkZScgOiAnc2FtZS1vcmlnaW4nLFxyXG5cdFx0XHQvLyBBbiBhYm9ydCBjb250cm9sbGVyIGNvdWxkIGJlIGFkZGVkIHdpdGhpbiBhIGZ1dHVyZSBQUlxyXG5cdFx0fSApO1xyXG5cclxuXHRcdC8vIHJlY29yZCBzdGF0ZXMgKCBhdm9pZCBkYXRhIHJhY2UgKVxyXG5cdFx0Y29uc3QgbWltZVR5cGUgPSB0aGlzLm1pbWVUeXBlO1xyXG5cdFx0Y29uc3QgcmVzcG9uc2VUeXBlID0gdGhpcy5yZXNwb25zZVR5cGU7XHJcblxyXG5cdFx0Ly8gc3RhcnQgdGhlIGZldGNoXHJcblx0XHRmZXRjaCggcmVxIClcclxuXHRcdFx0LnRoZW4oIHJlc3BvbnNlID0+IHtcclxuXHJcblx0XHRcdFx0aWYgKCByZXNwb25zZS5zdGF0dXMgPT09IDIwMCB8fCByZXNwb25zZS5zdGF0dXMgPT09IDAgKSB7XHJcblxyXG5cdFx0XHRcdFx0Ly8gU29tZSBicm93c2VycyByZXR1cm4gSFRUUCBTdGF0dXMgMCB3aGVuIHVzaW5nIG5vbi1odHRwIHByb3RvY29sXHJcblx0XHRcdFx0XHQvLyBlLmcuICdmaWxlOi8vJyBvciAnZGF0YTovLycuIEhhbmRsZSBhcyBzdWNjZXNzLlxyXG5cclxuXHRcdFx0XHRcdGlmICggcmVzcG9uc2Uuc3RhdHVzID09PSAwICkge1xyXG5cclxuXHRcdFx0XHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuRmlsZUxvYWRlcjogSFRUUCBTdGF0dXMgMCByZWNlaXZlZC4nICk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdC8vIFdvcmthcm91bmQ6IENoZWNraW5nIGlmIHJlc3BvbnNlLmJvZHkgPT09IHVuZGVmaW5lZCBmb3IgQWxpcGF5IGJyb3dzZXIgIzIzNTQ4XHJcblxyXG5cdFx0XHRcdFx0aWYgKCB0eXBlb2YgUmVhZGFibGVTdHJlYW0gPT09ICd1bmRlZmluZWQnIHx8IHJlc3BvbnNlLmJvZHkgPT09IHVuZGVmaW5lZCB8fCByZXNwb25zZS5ib2R5LmdldFJlYWRlciA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHRcdFx0cmV0dXJuIHJlc3BvbnNlO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRjb25zdCBjYWxsYmFja3MgPSBsb2FkaW5nWyB1cmwgXTtcclxuXHRcdFx0XHRcdGNvbnN0IHJlYWRlciA9IHJlc3BvbnNlLmJvZHkuZ2V0UmVhZGVyKCk7XHJcblxyXG5cdFx0XHRcdFx0Ly8gTmdpbnggbmVlZHMgWC1GaWxlLVNpemUgY2hlY2tcclxuXHRcdFx0XHRcdC8vIGh0dHBzOi8vc2VydmVyZmF1bHQuY29tL3F1ZXN0aW9ucy80ODI4NzUvd2h5LWRvZXMtbmdpbngtcmVtb3ZlLWNvbnRlbnQtbGVuZ3RoLWhlYWRlci1mb3ItY2h1bmtlZC1jb250ZW50XHJcblx0XHRcdFx0XHRjb25zdCBjb250ZW50TGVuZ3RoID0gcmVzcG9uc2UuaGVhZGVycy5nZXQoICdDb250ZW50LUxlbmd0aCcgKSB8fCByZXNwb25zZS5oZWFkZXJzLmdldCggJ1gtRmlsZS1TaXplJyApO1xyXG5cdFx0XHRcdFx0Y29uc3QgdG90YWwgPSBjb250ZW50TGVuZ3RoID8gcGFyc2VJbnQoIGNvbnRlbnRMZW5ndGggKSA6IDA7XHJcblx0XHRcdFx0XHRjb25zdCBsZW5ndGhDb21wdXRhYmxlID0gdG90YWwgIT09IDA7XHJcblx0XHRcdFx0XHRsZXQgbG9hZGVkID0gMDtcclxuXHJcblx0XHRcdFx0XHQvLyBwZXJpb2RpY2FsbHkgcmVhZCBkYXRhIGludG8gdGhlIG5ldyBzdHJlYW0gdHJhY2tpbmcgd2hpbGUgZG93bmxvYWQgcHJvZ3Jlc3NcclxuXHRcdFx0XHRcdGNvbnN0IHN0cmVhbSA9IG5ldyBSZWFkYWJsZVN0cmVhbSgge1xyXG5cdFx0XHRcdFx0XHRzdGFydCggY29udHJvbGxlciApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0cmVhZERhdGEoKTtcclxuXHJcblx0XHRcdFx0XHRcdFx0ZnVuY3Rpb24gcmVhZERhdGEoKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0cmVhZGVyLnJlYWQoKS50aGVuKCAoIHsgZG9uZSwgdmFsdWUgfSApID0+IHtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHRcdGlmICggZG9uZSApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0Y29udHJvbGxlci5jbG9zZSgpO1xyXG5cclxuXHRcdFx0XHRcdFx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0bG9hZGVkICs9IHZhbHVlLmJ5dGVMZW5ndGg7XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdGNvbnN0IGV2ZW50ID0gbmV3IFByb2dyZXNzRXZlbnQoICdwcm9ncmVzcycsIHsgbGVuZ3RoQ29tcHV0YWJsZSwgbG9hZGVkLCB0b3RhbCB9ICk7XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0Zm9yICggbGV0IGkgPSAwLCBpbCA9IGNhbGxiYWNrcy5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRjb25zdCBjYWxsYmFjayA9IGNhbGxiYWNrc1sgaSBdO1xyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0aWYgKCBjYWxsYmFjay5vblByb2dyZXNzICkgY2FsbGJhY2sub25Qcm9ncmVzcyggZXZlbnQgKTtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRjb250cm9sbGVyLmVucXVldWUoIHZhbHVlICk7XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0cmVhZERhdGEoKTtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRcdFx0XHR9ICk7XHJcblxyXG5cdFx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHR9ICk7XHJcblxyXG5cdFx0XHRcdFx0cmV0dXJuIG5ldyBSZXNwb25zZSggc3RyZWFtICk7XHJcblxyXG5cdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0dGhyb3cgbmV3IEh0dHBFcnJvciggYGZldGNoIGZvciBcIiR7cmVzcG9uc2UudXJsfVwiIHJlc3BvbmRlZCB3aXRoICR7cmVzcG9uc2Uuc3RhdHVzfTogJHtyZXNwb25zZS5zdGF0dXNUZXh0fWAsIHJlc3BvbnNlICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH0gKVxyXG5cdFx0XHQudGhlbiggcmVzcG9uc2UgPT4ge1xyXG5cclxuXHRcdFx0XHRzd2l0Y2ggKCByZXNwb25zZVR5cGUgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y2FzZSAnYXJyYXlidWZmZXInOlxyXG5cclxuXHRcdFx0XHRcdFx0cmV0dXJuIHJlc3BvbnNlLmFycmF5QnVmZmVyKCk7XHJcblxyXG5cdFx0XHRcdFx0Y2FzZSAnYmxvYic6XHJcblxyXG5cdFx0XHRcdFx0XHRyZXR1cm4gcmVzcG9uc2UuYmxvYigpO1xyXG5cclxuXHRcdFx0XHRcdGNhc2UgJ2RvY3VtZW50JzpcclxuXHJcblx0XHRcdFx0XHRcdHJldHVybiByZXNwb25zZS50ZXh0KClcclxuXHRcdFx0XHRcdFx0XHQudGhlbiggdGV4dCA9PiB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0Y29uc3QgcGFyc2VyID0gbmV3IERPTVBhcnNlcigpO1xyXG5cdFx0XHRcdFx0XHRcdFx0cmV0dXJuIHBhcnNlci5wYXJzZUZyb21TdHJpbmcoIHRleHQsIG1pbWVUeXBlICk7XHJcblxyXG5cdFx0XHRcdFx0XHRcdH0gKTtcclxuXHJcblx0XHRcdFx0XHRjYXNlICdqc29uJzpcclxuXHJcblx0XHRcdFx0XHRcdHJldHVybiByZXNwb25zZS5qc29uKCk7XHJcblxyXG5cdFx0XHRcdFx0ZGVmYXVsdDpcclxuXHJcblx0XHRcdFx0XHRcdGlmICggbWltZVR5cGUgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0cmV0dXJuIHJlc3BvbnNlLnRleHQoKTtcclxuXHJcblx0XHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdC8vIHNuaWZmIGVuY29kaW5nXHJcblx0XHRcdFx0XHRcdFx0Y29uc3QgcmUgPSAvY2hhcnNldD1cIj8oW147XCJcXHNdKilcIj8vaTtcclxuXHRcdFx0XHRcdFx0XHRjb25zdCBleGVjID0gcmUuZXhlYyggbWltZVR5cGUgKTtcclxuXHRcdFx0XHRcdFx0XHRjb25zdCBsYWJlbCA9IGV4ZWMgJiYgZXhlY1sgMSBdID8gZXhlY1sgMSBdLnRvTG93ZXJDYXNlKCkgOiB1bmRlZmluZWQ7XHJcblx0XHRcdFx0XHRcdFx0Y29uc3QgZGVjb2RlciA9IG5ldyBUZXh0RGVjb2RlciggbGFiZWwgKTtcclxuXHRcdFx0XHRcdFx0XHRyZXR1cm4gcmVzcG9uc2UuYXJyYXlCdWZmZXIoKS50aGVuKCBhYiA9PiBkZWNvZGVyLmRlY29kZSggYWIgKSApO1xyXG5cclxuXHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9IClcclxuXHRcdFx0LnRoZW4oIGRhdGEgPT4ge1xyXG5cclxuXHRcdFx0XHQvLyBBZGQgdG8gY2FjaGUgb25seSBvbiBIVFRQIHN1Y2Nlc3MsIHNvIHRoYXQgd2UgZG8gbm90IGNhY2hlXHJcblx0XHRcdFx0Ly8gZXJyb3IgcmVzcG9uc2UgYm9kaWVzIGFzIHByb3BlciByZXNwb25zZXMgdG8gcmVxdWVzdHMuXHJcblx0XHRcdFx0Q2FjaGUuYWRkKCB1cmwsIGRhdGEgKTtcclxuXHJcblx0XHRcdFx0Y29uc3QgY2FsbGJhY2tzID0gbG9hZGluZ1sgdXJsIF07XHJcblx0XHRcdFx0ZGVsZXRlIGxvYWRpbmdbIHVybCBdO1xyXG5cclxuXHRcdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gY2FsbGJhY2tzLmxlbmd0aDsgaSA8IGlsOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRcdGNvbnN0IGNhbGxiYWNrID0gY2FsbGJhY2tzWyBpIF07XHJcblx0XHRcdFx0XHRpZiAoIGNhbGxiYWNrLm9uTG9hZCApIGNhbGxiYWNrLm9uTG9hZCggZGF0YSApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9IClcclxuXHRcdFx0LmNhdGNoKCBlcnIgPT4ge1xyXG5cclxuXHRcdFx0XHQvLyBBYm9ydCBlcnJvcnMgYW5kIG90aGVyIGVycm9ycyBhcmUgaGFuZGxlZCB0aGUgc2FtZVxyXG5cclxuXHRcdFx0XHRjb25zdCBjYWxsYmFja3MgPSBsb2FkaW5nWyB1cmwgXTtcclxuXHJcblx0XHRcdFx0aWYgKCBjYWxsYmFja3MgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0XHQvLyBXaGVuIG9uTG9hZCB3YXMgY2FsbGVkIGFuZCB1cmwgd2FzIGRlbGV0ZWQgaW4gYGxvYWRpbmdgXHJcblx0XHRcdFx0XHR0aGlzLm1hbmFnZXIuaXRlbUVycm9yKCB1cmwgKTtcclxuXHRcdFx0XHRcdHRocm93IGVycjtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRkZWxldGUgbG9hZGluZ1sgdXJsIF07XHJcblxyXG5cdFx0XHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSBjYWxsYmFja3MubGVuZ3RoOyBpIDwgaWw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgY2FsbGJhY2sgPSBjYWxsYmFja3NbIGkgXTtcclxuXHRcdFx0XHRcdGlmICggY2FsbGJhY2sub25FcnJvciApIGNhbGxiYWNrLm9uRXJyb3IoIGVyciApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdHRoaXMubWFuYWdlci5pdGVtRXJyb3IoIHVybCApO1xyXG5cclxuXHRcdFx0fSApXHJcblx0XHRcdC5maW5hbGx5KCAoKSA9PiB7XHJcblxyXG5cdFx0XHRcdHRoaXMubWFuYWdlci5pdGVtRW5kKCB1cmwgKTtcclxuXHJcblx0XHRcdH0gKTtcclxuXHJcblx0XHR0aGlzLm1hbmFnZXIuaXRlbVN0YXJ0KCB1cmwgKTtcclxuXHJcblx0fVxyXG5cclxuXHRzZXRSZXNwb25zZVR5cGUoIHZhbHVlICkge1xyXG5cclxuXHRcdHRoaXMucmVzcG9uc2VUeXBlID0gdmFsdWU7XHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRNaW1lVHlwZSggdmFsdWUgKSB7XHJcblxyXG5cdFx0dGhpcy5taW1lVHlwZSA9IHZhbHVlO1xyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcblxyXG5leHBvcnQgeyBGaWxlTG9hZGVyIH07XHJcbiIsImltcG9ydCB7IEFuaW1hdGlvbkNsaXAgfSBmcm9tICcuLi9hbmltYXRpb24vQW5pbWF0aW9uQ2xpcC5qcyc7XHJcbmltcG9ydCB7IEZpbGVMb2FkZXIgfSBmcm9tICcuL0ZpbGVMb2FkZXIuanMnO1xyXG5pbXBvcnQgeyBMb2FkZXIgfSBmcm9tICcuL0xvYWRlci5qcyc7XHJcblxyXG5jbGFzcyBBbmltYXRpb25Mb2FkZXIgZXh0ZW5kcyBMb2FkZXIge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggbWFuYWdlciApIHtcclxuXHJcblx0XHRzdXBlciggbWFuYWdlciApO1xyXG5cclxuXHR9XHJcblxyXG5cdGxvYWQoIHVybCwgb25Mb2FkLCBvblByb2dyZXNzLCBvbkVycm9yICkge1xyXG5cclxuXHRcdGNvbnN0IHNjb3BlID0gdGhpcztcclxuXHJcblx0XHRjb25zdCBsb2FkZXIgPSBuZXcgRmlsZUxvYWRlciggdGhpcy5tYW5hZ2VyICk7XHJcblx0XHRsb2FkZXIuc2V0UGF0aCggdGhpcy5wYXRoICk7XHJcblx0XHRsb2FkZXIuc2V0UmVxdWVzdEhlYWRlciggdGhpcy5yZXF1ZXN0SGVhZGVyICk7XHJcblx0XHRsb2FkZXIuc2V0V2l0aENyZWRlbnRpYWxzKCB0aGlzLndpdGhDcmVkZW50aWFscyApO1xyXG5cdFx0bG9hZGVyLmxvYWQoIHVybCwgZnVuY3Rpb24gKCB0ZXh0ICkge1xyXG5cclxuXHRcdFx0dHJ5IHtcclxuXHJcblx0XHRcdFx0b25Mb2FkKCBzY29wZS5wYXJzZSggSlNPTi5wYXJzZSggdGV4dCApICkgKTtcclxuXHJcblx0XHRcdH0gY2F0Y2ggKCBlICkge1xyXG5cclxuXHRcdFx0XHRpZiAoIG9uRXJyb3IgKSB7XHJcblxyXG5cdFx0XHRcdFx0b25FcnJvciggZSApO1xyXG5cclxuXHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdGNvbnNvbGUuZXJyb3IoIGUgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRzY29wZS5tYW5hZ2VyLml0ZW1FcnJvciggdXJsICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fSwgb25Qcm9ncmVzcywgb25FcnJvciApO1xyXG5cclxuXHR9XHJcblxyXG5cdHBhcnNlKCBqc29uICkge1xyXG5cclxuXHRcdGNvbnN0IGFuaW1hdGlvbnMgPSBbXTtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBqc29uLmxlbmd0aDsgaSArKyApIHtcclxuXHJcblx0XHRcdGNvbnN0IGNsaXAgPSBBbmltYXRpb25DbGlwLnBhcnNlKCBqc29uWyBpIF0gKTtcclxuXHJcblx0XHRcdGFuaW1hdGlvbnMucHVzaCggY2xpcCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gYW5pbWF0aW9ucztcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuXHJcbmV4cG9ydCB7IEFuaW1hdGlvbkxvYWRlciB9O1xyXG4iLCJpbXBvcnQgeyBMaW5lYXJGaWx0ZXIgfSBmcm9tICcuLi9jb25zdGFudHMuanMnO1xyXG5pbXBvcnQgeyBGaWxlTG9hZGVyIH0gZnJvbSAnLi9GaWxlTG9hZGVyLmpzJztcclxuaW1wb3J0IHsgQ29tcHJlc3NlZFRleHR1cmUgfSBmcm9tICcuLi90ZXh0dXJlcy9Db21wcmVzc2VkVGV4dHVyZS5qcyc7XHJcbmltcG9ydCB7IExvYWRlciB9IGZyb20gJy4vTG9hZGVyLmpzJztcclxuXHJcbi8qKlxyXG4gKiBBYnN0cmFjdCBCYXNlIGNsYXNzIHRvIGJsb2NrIGJhc2VkIHRleHR1cmVzIGxvYWRlciAoZGRzLCBwdnIsIC4uLilcclxuICpcclxuICogU3ViIGNsYXNzZXMgaGF2ZSB0byBpbXBsZW1lbnQgdGhlIHBhcnNlKCkgbWV0aG9kIHdoaWNoIHdpbGwgYmUgdXNlZCBpbiBsb2FkKCkuXHJcbiAqL1xyXG5cclxuY2xhc3MgQ29tcHJlc3NlZFRleHR1cmVMb2FkZXIgZXh0ZW5kcyBMb2FkZXIge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggbWFuYWdlciApIHtcclxuXHJcblx0XHRzdXBlciggbWFuYWdlciApO1xyXG5cclxuXHR9XHJcblxyXG5cdGxvYWQoIHVybCwgb25Mb2FkLCBvblByb2dyZXNzLCBvbkVycm9yICkge1xyXG5cclxuXHRcdGNvbnN0IHNjb3BlID0gdGhpcztcclxuXHJcblx0XHRjb25zdCBpbWFnZXMgPSBbXTtcclxuXHJcblx0XHRjb25zdCB0ZXh0dXJlID0gbmV3IENvbXByZXNzZWRUZXh0dXJlKCk7XHJcblxyXG5cdFx0Y29uc3QgbG9hZGVyID0gbmV3IEZpbGVMb2FkZXIoIHRoaXMubWFuYWdlciApO1xyXG5cdFx0bG9hZGVyLnNldFBhdGgoIHRoaXMucGF0aCApO1xyXG5cdFx0bG9hZGVyLnNldFJlc3BvbnNlVHlwZSggJ2FycmF5YnVmZmVyJyApO1xyXG5cdFx0bG9hZGVyLnNldFJlcXVlc3RIZWFkZXIoIHRoaXMucmVxdWVzdEhlYWRlciApO1xyXG5cdFx0bG9hZGVyLnNldFdpdGhDcmVkZW50aWFscyggc2NvcGUud2l0aENyZWRlbnRpYWxzICk7XHJcblxyXG5cdFx0bGV0IGxvYWRlZCA9IDA7XHJcblxyXG5cdFx0ZnVuY3Rpb24gbG9hZFRleHR1cmUoIGkgKSB7XHJcblxyXG5cdFx0XHRsb2FkZXIubG9hZCggdXJsWyBpIF0sIGZ1bmN0aW9uICggYnVmZmVyICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCB0ZXhEYXRhcyA9IHNjb3BlLnBhcnNlKCBidWZmZXIsIHRydWUgKTtcclxuXHJcblx0XHRcdFx0aW1hZ2VzWyBpIF0gPSB7XHJcblx0XHRcdFx0XHR3aWR0aDogdGV4RGF0YXMud2lkdGgsXHJcblx0XHRcdFx0XHRoZWlnaHQ6IHRleERhdGFzLmhlaWdodCxcclxuXHRcdFx0XHRcdGZvcm1hdDogdGV4RGF0YXMuZm9ybWF0LFxyXG5cdFx0XHRcdFx0bWlwbWFwczogdGV4RGF0YXMubWlwbWFwc1xyXG5cdFx0XHRcdH07XHJcblxyXG5cdFx0XHRcdGxvYWRlZCArPSAxO1xyXG5cclxuXHRcdFx0XHRpZiAoIGxvYWRlZCA9PT0gNiApIHtcclxuXHJcblx0XHRcdFx0XHRpZiAoIHRleERhdGFzLm1pcG1hcENvdW50ID09PSAxICkgdGV4dHVyZS5taW5GaWx0ZXIgPSBMaW5lYXJGaWx0ZXI7XHJcblxyXG5cdFx0XHRcdFx0dGV4dHVyZS5pbWFnZSA9IGltYWdlcztcclxuXHRcdFx0XHRcdHRleHR1cmUuZm9ybWF0ID0gdGV4RGF0YXMuZm9ybWF0O1xyXG5cdFx0XHRcdFx0dGV4dHVyZS5uZWVkc1VwZGF0ZSA9IHRydWU7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCBvbkxvYWQgKSBvbkxvYWQoIHRleHR1cmUgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fSwgb25Qcm9ncmVzcywgb25FcnJvciApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIEFycmF5LmlzQXJyYXkoIHVybCApICkge1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGkgPSAwLCBpbCA9IHVybC5sZW5ndGg7IGkgPCBpbDsgKysgaSApIHtcclxuXHJcblx0XHRcdFx0bG9hZFRleHR1cmUoIGkgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0Ly8gY29tcHJlc3NlZCBjdWJlbWFwIHRleHR1cmUgc3RvcmVkIGluIGEgc2luZ2xlIEREUyBmaWxlXHJcblxyXG5cdFx0XHRsb2FkZXIubG9hZCggdXJsLCBmdW5jdGlvbiAoIGJ1ZmZlciApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgdGV4RGF0YXMgPSBzY29wZS5wYXJzZSggYnVmZmVyLCB0cnVlICk7XHJcblxyXG5cdFx0XHRcdGlmICggdGV4RGF0YXMuaXNDdWJlbWFwICkge1xyXG5cclxuXHRcdFx0XHRcdGNvbnN0IGZhY2VzID0gdGV4RGF0YXMubWlwbWFwcy5sZW5ndGggLyB0ZXhEYXRhcy5taXBtYXBDb3VudDtcclxuXHJcblx0XHRcdFx0XHRmb3IgKCBsZXQgZiA9IDA7IGYgPCBmYWNlczsgZiArKyApIHtcclxuXHJcblx0XHRcdFx0XHRcdGltYWdlc1sgZiBdID0geyBtaXBtYXBzOiBbXSB9O1xyXG5cclxuXHRcdFx0XHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgdGV4RGF0YXMubWlwbWFwQ291bnQ7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdGltYWdlc1sgZiBdLm1pcG1hcHMucHVzaCggdGV4RGF0YXMubWlwbWFwc1sgZiAqIHRleERhdGFzLm1pcG1hcENvdW50ICsgaSBdICk7XHJcblx0XHRcdFx0XHRcdFx0aW1hZ2VzWyBmIF0uZm9ybWF0ID0gdGV4RGF0YXMuZm9ybWF0O1xyXG5cdFx0XHRcdFx0XHRcdGltYWdlc1sgZiBdLndpZHRoID0gdGV4RGF0YXMud2lkdGg7XHJcblx0XHRcdFx0XHRcdFx0aW1hZ2VzWyBmIF0uaGVpZ2h0ID0gdGV4RGF0YXMuaGVpZ2h0O1xyXG5cclxuXHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHR0ZXh0dXJlLmltYWdlID0gaW1hZ2VzO1xyXG5cclxuXHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdHRleHR1cmUuaW1hZ2Uud2lkdGggPSB0ZXhEYXRhcy53aWR0aDtcclxuXHRcdFx0XHRcdHRleHR1cmUuaW1hZ2UuaGVpZ2h0ID0gdGV4RGF0YXMuaGVpZ2h0O1xyXG5cdFx0XHRcdFx0dGV4dHVyZS5taXBtYXBzID0gdGV4RGF0YXMubWlwbWFwcztcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRpZiAoIHRleERhdGFzLm1pcG1hcENvdW50ID09PSAxICkge1xyXG5cclxuXHRcdFx0XHRcdHRleHR1cmUubWluRmlsdGVyID0gTGluZWFyRmlsdGVyO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdHRleHR1cmUuZm9ybWF0ID0gdGV4RGF0YXMuZm9ybWF0O1xyXG5cdFx0XHRcdHRleHR1cmUubmVlZHNVcGRhdGUgPSB0cnVlO1xyXG5cclxuXHRcdFx0XHRpZiAoIG9uTG9hZCApIG9uTG9hZCggdGV4dHVyZSApO1xyXG5cclxuXHRcdFx0fSwgb25Qcm9ncmVzcywgb25FcnJvciApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGV4dHVyZTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuXHJcbmV4cG9ydCB7IENvbXByZXNzZWRUZXh0dXJlTG9hZGVyIH07XHJcbiIsImltcG9ydCB7IENhY2hlIH0gZnJvbSAnLi9DYWNoZS5qcyc7XHJcbmltcG9ydCB7IExvYWRlciB9IGZyb20gJy4vTG9hZGVyLmpzJztcclxuaW1wb3J0IHsgY3JlYXRlRWxlbWVudE5TIH0gZnJvbSAnLi4vdXRpbHMuanMnO1xyXG5cclxuY2xhc3MgSW1hZ2VMb2FkZXIgZXh0ZW5kcyBMb2FkZXIge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggbWFuYWdlciApIHtcclxuXHJcblx0XHRzdXBlciggbWFuYWdlciApO1xyXG5cclxuXHR9XHJcblxyXG5cdGxvYWQoIHVybCwgb25Mb2FkLCBvblByb2dyZXNzLCBvbkVycm9yICkge1xyXG5cclxuXHRcdGlmICggdGhpcy5wYXRoICE9PSB1bmRlZmluZWQgKSB1cmwgPSB0aGlzLnBhdGggKyB1cmw7XHJcblxyXG5cdFx0dXJsID0gdGhpcy5tYW5hZ2VyLnJlc29sdmVVUkwoIHVybCApO1xyXG5cclxuXHRcdGNvbnN0IHNjb3BlID0gdGhpcztcclxuXHJcblx0XHRjb25zdCBjYWNoZWQgPSBDYWNoZS5nZXQoIHVybCApO1xyXG5cclxuXHRcdGlmICggY2FjaGVkICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRzY29wZS5tYW5hZ2VyLml0ZW1TdGFydCggdXJsICk7XHJcblxyXG5cdFx0XHRzZXRUaW1lb3V0KCBmdW5jdGlvbiAoKSB7XHJcblxyXG5cdFx0XHRcdGlmICggb25Mb2FkICkgb25Mb2FkKCBjYWNoZWQgKTtcclxuXHJcblx0XHRcdFx0c2NvcGUubWFuYWdlci5pdGVtRW5kKCB1cmwgKTtcclxuXHJcblx0XHRcdH0sIDAgKTtcclxuXHJcblx0XHRcdHJldHVybiBjYWNoZWQ7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGNvbnN0IGltYWdlID0gY3JlYXRlRWxlbWVudE5TKCAnaW1nJyApO1xyXG5cclxuXHRcdGZ1bmN0aW9uIG9uSW1hZ2VMb2FkKCkge1xyXG5cclxuXHRcdFx0cmVtb3ZlRXZlbnRMaXN0ZW5lcnMoKTtcclxuXHJcblx0XHRcdENhY2hlLmFkZCggdXJsLCB0aGlzICk7XHJcblxyXG5cdFx0XHRpZiAoIG9uTG9hZCApIG9uTG9hZCggdGhpcyApO1xyXG5cclxuXHRcdFx0c2NvcGUubWFuYWdlci5pdGVtRW5kKCB1cmwgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0ZnVuY3Rpb24gb25JbWFnZUVycm9yKCBldmVudCApIHtcclxuXHJcblx0XHRcdHJlbW92ZUV2ZW50TGlzdGVuZXJzKCk7XHJcblxyXG5cdFx0XHRpZiAoIG9uRXJyb3IgKSBvbkVycm9yKCBldmVudCApO1xyXG5cclxuXHRcdFx0c2NvcGUubWFuYWdlci5pdGVtRXJyb3IoIHVybCApO1xyXG5cdFx0XHRzY29wZS5tYW5hZ2VyLml0ZW1FbmQoIHVybCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRmdW5jdGlvbiByZW1vdmVFdmVudExpc3RlbmVycygpIHtcclxuXHJcblx0XHRcdGltYWdlLnJlbW92ZUV2ZW50TGlzdGVuZXIoICdsb2FkJywgb25JbWFnZUxvYWQsIGZhbHNlICk7XHJcblx0XHRcdGltYWdlLnJlbW92ZUV2ZW50TGlzdGVuZXIoICdlcnJvcicsIG9uSW1hZ2VFcnJvciwgZmFsc2UgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aW1hZ2UuYWRkRXZlbnRMaXN0ZW5lciggJ2xvYWQnLCBvbkltYWdlTG9hZCwgZmFsc2UgKTtcclxuXHRcdGltYWdlLmFkZEV2ZW50TGlzdGVuZXIoICdlcnJvcicsIG9uSW1hZ2VFcnJvciwgZmFsc2UgKTtcclxuXHJcblx0XHRpZiAoIHVybC5zbGljZSggMCwgNSApICE9PSAnZGF0YTonICkge1xyXG5cclxuXHRcdFx0aWYgKCB0aGlzLmNyb3NzT3JpZ2luICE9PSB1bmRlZmluZWQgKSBpbWFnZS5jcm9zc09yaWdpbiA9IHRoaXMuY3Jvc3NPcmlnaW47XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHNjb3BlLm1hbmFnZXIuaXRlbVN0YXJ0KCB1cmwgKTtcclxuXHJcblx0XHRpbWFnZS5zcmMgPSB1cmw7XHJcblxyXG5cdFx0cmV0dXJuIGltYWdlO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5cclxuZXhwb3J0IHsgSW1hZ2VMb2FkZXIgfTtcclxuIiwiaW1wb3J0IHsgSW1hZ2VMb2FkZXIgfSBmcm9tICcuL0ltYWdlTG9hZGVyLmpzJztcclxuaW1wb3J0IHsgQ3ViZVRleHR1cmUgfSBmcm9tICcuLi90ZXh0dXJlcy9DdWJlVGV4dHVyZS5qcyc7XHJcbmltcG9ydCB7IExvYWRlciB9IGZyb20gJy4vTG9hZGVyLmpzJztcclxuaW1wb3J0IHsgU1JHQkNvbG9yU3BhY2UgfSBmcm9tICcuLi9jb25zdGFudHMuanMnO1xyXG5cclxuY2xhc3MgQ3ViZVRleHR1cmVMb2FkZXIgZXh0ZW5kcyBMb2FkZXIge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggbWFuYWdlciApIHtcclxuXHJcblx0XHRzdXBlciggbWFuYWdlciApO1xyXG5cclxuXHR9XHJcblxyXG5cdGxvYWQoIHVybHMsIG9uTG9hZCwgb25Qcm9ncmVzcywgb25FcnJvciApIHtcclxuXHJcblx0XHRjb25zdCB0ZXh0dXJlID0gbmV3IEN1YmVUZXh0dXJlKCk7XHJcblx0XHR0ZXh0dXJlLmNvbG9yU3BhY2UgPSBTUkdCQ29sb3JTcGFjZTtcclxuXHJcblx0XHRjb25zdCBsb2FkZXIgPSBuZXcgSW1hZ2VMb2FkZXIoIHRoaXMubWFuYWdlciApO1xyXG5cdFx0bG9hZGVyLnNldENyb3NzT3JpZ2luKCB0aGlzLmNyb3NzT3JpZ2luICk7XHJcblx0XHRsb2FkZXIuc2V0UGF0aCggdGhpcy5wYXRoICk7XHJcblxyXG5cdFx0bGV0IGxvYWRlZCA9IDA7XHJcblxyXG5cdFx0ZnVuY3Rpb24gbG9hZFRleHR1cmUoIGkgKSB7XHJcblxyXG5cdFx0XHRsb2FkZXIubG9hZCggdXJsc1sgaSBdLCBmdW5jdGlvbiAoIGltYWdlICkge1xyXG5cclxuXHRcdFx0XHR0ZXh0dXJlLmltYWdlc1sgaSBdID0gaW1hZ2U7XHJcblxyXG5cdFx0XHRcdGxvYWRlZCArKztcclxuXHJcblx0XHRcdFx0aWYgKCBsb2FkZWQgPT09IDYgKSB7XHJcblxyXG5cdFx0XHRcdFx0dGV4dHVyZS5uZWVkc1VwZGF0ZSA9IHRydWU7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCBvbkxvYWQgKSBvbkxvYWQoIHRleHR1cmUgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fSwgdW5kZWZpbmVkLCBvbkVycm9yICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHVybHMubGVuZ3RoOyArKyBpICkge1xyXG5cclxuXHRcdFx0bG9hZFRleHR1cmUoIGkgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRleHR1cmU7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcblxyXG5leHBvcnQgeyBDdWJlVGV4dHVyZUxvYWRlciB9O1xyXG4iLCJpbXBvcnQgeyBMaW5lYXJGaWx0ZXIsIExpbmVhck1pcG1hcExpbmVhckZpbHRlciwgQ2xhbXBUb0VkZ2VXcmFwcGluZyB9IGZyb20gJy4uL2NvbnN0YW50cy5qcyc7XHJcbmltcG9ydCB7IEZpbGVMb2FkZXIgfSBmcm9tICcuL0ZpbGVMb2FkZXIuanMnO1xyXG5pbXBvcnQgeyBEYXRhVGV4dHVyZSB9IGZyb20gJy4uL3RleHR1cmVzL0RhdGFUZXh0dXJlLmpzJztcclxuaW1wb3J0IHsgTG9hZGVyIH0gZnJvbSAnLi9Mb2FkZXIuanMnO1xyXG5cclxuLyoqXHJcbiAqIEFic3RyYWN0IEJhc2UgY2xhc3MgdG8gbG9hZCBnZW5lcmljIGJpbmFyeSB0ZXh0dXJlcyBmb3JtYXRzIChyZ2JlLCBoZHIsIC4uLilcclxuICpcclxuICogU3ViIGNsYXNzZXMgaGF2ZSB0byBpbXBsZW1lbnQgdGhlIHBhcnNlKCkgbWV0aG9kIHdoaWNoIHdpbGwgYmUgdXNlZCBpbiBsb2FkKCkuXHJcbiAqL1xyXG5cclxuY2xhc3MgRGF0YVRleHR1cmVMb2FkZXIgZXh0ZW5kcyBMb2FkZXIge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggbWFuYWdlciApIHtcclxuXHJcblx0XHRzdXBlciggbWFuYWdlciApO1xyXG5cclxuXHR9XHJcblxyXG5cdGxvYWQoIHVybCwgb25Mb2FkLCBvblByb2dyZXNzLCBvbkVycm9yICkge1xyXG5cclxuXHRcdGNvbnN0IHNjb3BlID0gdGhpcztcclxuXHJcblx0XHRjb25zdCB0ZXh0dXJlID0gbmV3IERhdGFUZXh0dXJlKCk7XHJcblxyXG5cdFx0Y29uc3QgbG9hZGVyID0gbmV3IEZpbGVMb2FkZXIoIHRoaXMubWFuYWdlciApO1xyXG5cdFx0bG9hZGVyLnNldFJlc3BvbnNlVHlwZSggJ2FycmF5YnVmZmVyJyApO1xyXG5cdFx0bG9hZGVyLnNldFJlcXVlc3RIZWFkZXIoIHRoaXMucmVxdWVzdEhlYWRlciApO1xyXG5cdFx0bG9hZGVyLnNldFBhdGgoIHRoaXMucGF0aCApO1xyXG5cdFx0bG9hZGVyLnNldFdpdGhDcmVkZW50aWFscyggc2NvcGUud2l0aENyZWRlbnRpYWxzICk7XHJcblx0XHRsb2FkZXIubG9hZCggdXJsLCBmdW5jdGlvbiAoIGJ1ZmZlciApIHtcclxuXHJcblx0XHRcdGxldCB0ZXhEYXRhO1xyXG5cclxuXHRcdFx0dHJ5IHtcclxuXHJcblx0XHRcdFx0dGV4RGF0YSA9IHNjb3BlLnBhcnNlKCBidWZmZXIgKTtcclxuXHJcblx0XHRcdH0gY2F0Y2ggKCBlcnJvciApIHtcclxuXHJcblx0XHRcdFx0aWYgKCBvbkVycm9yICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRcdFx0b25FcnJvciggZXJyb3IgKTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRjb25zb2xlLmVycm9yKCBlcnJvciApO1xyXG5cdFx0XHRcdFx0cmV0dXJuO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRpZiAoIHRleERhdGEuaW1hZ2UgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0dGV4dHVyZS5pbWFnZSA9IHRleERhdGEuaW1hZ2U7XHJcblxyXG5cdFx0XHR9IGVsc2UgaWYgKCB0ZXhEYXRhLmRhdGEgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0dGV4dHVyZS5pbWFnZS53aWR0aCA9IHRleERhdGEud2lkdGg7XHJcblx0XHRcdFx0dGV4dHVyZS5pbWFnZS5oZWlnaHQgPSB0ZXhEYXRhLmhlaWdodDtcclxuXHRcdFx0XHR0ZXh0dXJlLmltYWdlLmRhdGEgPSB0ZXhEYXRhLmRhdGE7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHR0ZXh0dXJlLndyYXBTID0gdGV4RGF0YS53cmFwUyAhPT0gdW5kZWZpbmVkID8gdGV4RGF0YS53cmFwUyA6IENsYW1wVG9FZGdlV3JhcHBpbmc7XHJcblx0XHRcdHRleHR1cmUud3JhcFQgPSB0ZXhEYXRhLndyYXBUICE9PSB1bmRlZmluZWQgPyB0ZXhEYXRhLndyYXBUIDogQ2xhbXBUb0VkZ2VXcmFwcGluZztcclxuXHJcblx0XHRcdHRleHR1cmUubWFnRmlsdGVyID0gdGV4RGF0YS5tYWdGaWx0ZXIgIT09IHVuZGVmaW5lZCA/IHRleERhdGEubWFnRmlsdGVyIDogTGluZWFyRmlsdGVyO1xyXG5cdFx0XHR0ZXh0dXJlLm1pbkZpbHRlciA9IHRleERhdGEubWluRmlsdGVyICE9PSB1bmRlZmluZWQgPyB0ZXhEYXRhLm1pbkZpbHRlciA6IExpbmVhckZpbHRlcjtcclxuXHJcblx0XHRcdHRleHR1cmUuYW5pc290cm9weSA9IHRleERhdGEuYW5pc290cm9weSAhPT0gdW5kZWZpbmVkID8gdGV4RGF0YS5hbmlzb3Ryb3B5IDogMTtcclxuXHJcblx0XHRcdGlmICggdGV4RGF0YS5jb2xvclNwYWNlICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRcdHRleHR1cmUuY29sb3JTcGFjZSA9IHRleERhdGEuY29sb3JTcGFjZTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGlmICggdGV4RGF0YS5mbGlwWSAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHR0ZXh0dXJlLmZsaXBZID0gdGV4RGF0YS5mbGlwWTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGlmICggdGV4RGF0YS5mb3JtYXQgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0dGV4dHVyZS5mb3JtYXQgPSB0ZXhEYXRhLmZvcm1hdDtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGlmICggdGV4RGF0YS50eXBlICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRcdHRleHR1cmUudHlwZSA9IHRleERhdGEudHlwZTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGlmICggdGV4RGF0YS5taXBtYXBzICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRcdHRleHR1cmUubWlwbWFwcyA9IHRleERhdGEubWlwbWFwcztcclxuXHRcdFx0XHR0ZXh0dXJlLm1pbkZpbHRlciA9IExpbmVhck1pcG1hcExpbmVhckZpbHRlcjsgLy8gcHJlc3VtYWJseS4uLlxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0aWYgKCB0ZXhEYXRhLm1pcG1hcENvdW50ID09PSAxICkge1xyXG5cclxuXHRcdFx0XHR0ZXh0dXJlLm1pbkZpbHRlciA9IExpbmVhckZpbHRlcjtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGlmICggdGV4RGF0YS5nZW5lcmF0ZU1pcG1hcHMgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0dGV4dHVyZS5nZW5lcmF0ZU1pcG1hcHMgPSB0ZXhEYXRhLmdlbmVyYXRlTWlwbWFwcztcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHRleHR1cmUubmVlZHNVcGRhdGUgPSB0cnVlO1xyXG5cclxuXHRcdFx0aWYgKCBvbkxvYWQgKSBvbkxvYWQoIHRleHR1cmUsIHRleERhdGEgKTtcclxuXHJcblx0XHR9LCBvblByb2dyZXNzLCBvbkVycm9yICk7XHJcblxyXG5cclxuXHRcdHJldHVybiB0ZXh0dXJlO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5cclxuZXhwb3J0IHsgRGF0YVRleHR1cmVMb2FkZXIgfTtcclxuIiwiaW1wb3J0IHsgSW1hZ2VMb2FkZXIgfSBmcm9tICcuL0ltYWdlTG9hZGVyLmpzJztcclxuaW1wb3J0IHsgVGV4dHVyZSB9IGZyb20gJy4uL3RleHR1cmVzL1RleHR1cmUuanMnO1xyXG5pbXBvcnQgeyBMb2FkZXIgfSBmcm9tICcuL0xvYWRlci5qcyc7XHJcblxyXG5jbGFzcyBUZXh0dXJlTG9hZGVyIGV4dGVuZHMgTG9hZGVyIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIG1hbmFnZXIgKSB7XHJcblxyXG5cdFx0c3VwZXIoIG1hbmFnZXIgKTtcclxuXHJcblx0fVxyXG5cclxuXHRsb2FkKCB1cmwsIG9uTG9hZCwgb25Qcm9ncmVzcywgb25FcnJvciApIHtcclxuXHJcblx0XHRjb25zdCB0ZXh0dXJlID0gbmV3IFRleHR1cmUoKTtcclxuXHJcblx0XHRjb25zdCBsb2FkZXIgPSBuZXcgSW1hZ2VMb2FkZXIoIHRoaXMubWFuYWdlciApO1xyXG5cdFx0bG9hZGVyLnNldENyb3NzT3JpZ2luKCB0aGlzLmNyb3NzT3JpZ2luICk7XHJcblx0XHRsb2FkZXIuc2V0UGF0aCggdGhpcy5wYXRoICk7XHJcblxyXG5cdFx0bG9hZGVyLmxvYWQoIHVybCwgZnVuY3Rpb24gKCBpbWFnZSApIHtcclxuXHJcblx0XHRcdHRleHR1cmUuaW1hZ2UgPSBpbWFnZTtcclxuXHRcdFx0dGV4dHVyZS5uZWVkc1VwZGF0ZSA9IHRydWU7XHJcblxyXG5cdFx0XHRpZiAoIG9uTG9hZCAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHRvbkxvYWQoIHRleHR1cmUgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9LCBvblByb2dyZXNzLCBvbkVycm9yICk7XHJcblxyXG5cdFx0cmV0dXJuIHRleHR1cmU7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcblxyXG5leHBvcnQgeyBUZXh0dXJlTG9hZGVyIH07XHJcbiIsImltcG9ydCB7IE9iamVjdDNEIH0gZnJvbSAnLi4vY29yZS9PYmplY3QzRC5qcyc7XHJcbmltcG9ydCB7IENvbG9yIH0gZnJvbSAnLi4vbWF0aC9Db2xvci5qcyc7XHJcblxyXG5jbGFzcyBMaWdodCBleHRlbmRzIE9iamVjdDNEIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIGNvbG9yLCBpbnRlbnNpdHkgPSAxICkge1xyXG5cclxuXHRcdHN1cGVyKCk7XHJcblxyXG5cdFx0dGhpcy5pc0xpZ2h0ID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSAnTGlnaHQnO1xyXG5cclxuXHRcdHRoaXMuY29sb3IgPSBuZXcgQ29sb3IoIGNvbG9yICk7XHJcblx0XHR0aGlzLmludGVuc2l0eSA9IGludGVuc2l0eTtcclxuXHJcblx0fVxyXG5cclxuXHRkaXNwb3NlKCkge1xyXG5cclxuXHRcdC8vIEVtcHR5IGhlcmUgaW4gYmFzZSBjbGFzczsgc29tZSBzdWJjbGFzc2VzIG92ZXJyaWRlLlxyXG5cclxuXHR9XHJcblxyXG5cdGNvcHkoIHNvdXJjZSwgcmVjdXJzaXZlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSwgcmVjdXJzaXZlICk7XHJcblxyXG5cdFx0dGhpcy5jb2xvci5jb3B5KCBzb3VyY2UuY29sb3IgKTtcclxuXHRcdHRoaXMuaW50ZW5zaXR5ID0gc291cmNlLmludGVuc2l0eTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHR0b0pTT04oIG1ldGEgKSB7XHJcblxyXG5cdFx0Y29uc3QgZGF0YSA9IHN1cGVyLnRvSlNPTiggbWV0YSApO1xyXG5cclxuXHRcdGRhdGEub2JqZWN0LmNvbG9yID0gdGhpcy5jb2xvci5nZXRIZXgoKTtcclxuXHRcdGRhdGEub2JqZWN0LmludGVuc2l0eSA9IHRoaXMuaW50ZW5zaXR5O1xyXG5cclxuXHRcdGlmICggdGhpcy5ncm91bmRDb2xvciAhPT0gdW5kZWZpbmVkICkgZGF0YS5vYmplY3QuZ3JvdW5kQ29sb3IgPSB0aGlzLmdyb3VuZENvbG9yLmdldEhleCgpO1xyXG5cclxuXHRcdGlmICggdGhpcy5kaXN0YW5jZSAhPT0gdW5kZWZpbmVkICkgZGF0YS5vYmplY3QuZGlzdGFuY2UgPSB0aGlzLmRpc3RhbmNlO1xyXG5cdFx0aWYgKCB0aGlzLmFuZ2xlICE9PSB1bmRlZmluZWQgKSBkYXRhLm9iamVjdC5hbmdsZSA9IHRoaXMuYW5nbGU7XHJcblx0XHRpZiAoIHRoaXMuZGVjYXkgIT09IHVuZGVmaW5lZCApIGRhdGEub2JqZWN0LmRlY2F5ID0gdGhpcy5kZWNheTtcclxuXHRcdGlmICggdGhpcy5wZW51bWJyYSAhPT0gdW5kZWZpbmVkICkgZGF0YS5vYmplY3QucGVudW1icmEgPSB0aGlzLnBlbnVtYnJhO1xyXG5cclxuXHRcdGlmICggdGhpcy5zaGFkb3cgIT09IHVuZGVmaW5lZCApIGRhdGEub2JqZWN0LnNoYWRvdyA9IHRoaXMuc2hhZG93LnRvSlNPTigpO1xyXG5cclxuXHRcdHJldHVybiBkYXRhO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBMaWdodCB9O1xyXG4iLCJpbXBvcnQgeyBMaWdodCB9IGZyb20gJy4vTGlnaHQuanMnO1xyXG5pbXBvcnQgeyBDb2xvciB9IGZyb20gJy4uL21hdGgvQ29sb3IuanMnO1xyXG5pbXBvcnQgeyBPYmplY3QzRCB9IGZyb20gJy4uL2NvcmUvT2JqZWN0M0QuanMnO1xyXG5cclxuY2xhc3MgSGVtaXNwaGVyZUxpZ2h0IGV4dGVuZHMgTGlnaHQge1xyXG5cclxuXHRjb25zdHJ1Y3Rvciggc2t5Q29sb3IsIGdyb3VuZENvbG9yLCBpbnRlbnNpdHkgKSB7XHJcblxyXG5cdFx0c3VwZXIoIHNreUNvbG9yLCBpbnRlbnNpdHkgKTtcclxuXHJcblx0XHR0aGlzLmlzSGVtaXNwaGVyZUxpZ2h0ID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSAnSGVtaXNwaGVyZUxpZ2h0JztcclxuXHJcblx0XHR0aGlzLnBvc2l0aW9uLmNvcHkoIE9iamVjdDNELkRFRkFVTFRfVVAgKTtcclxuXHRcdHRoaXMudXBkYXRlTWF0cml4KCk7XHJcblxyXG5cdFx0dGhpcy5ncm91bmRDb2xvciA9IG5ldyBDb2xvciggZ3JvdW5kQ29sb3IgKTtcclxuXHJcblx0fVxyXG5cclxuXHRjb3B5KCBzb3VyY2UsIHJlY3Vyc2l2ZSApIHtcclxuXHJcblx0XHRzdXBlci5jb3B5KCBzb3VyY2UsIHJlY3Vyc2l2ZSApO1xyXG5cclxuXHRcdHRoaXMuZ3JvdW5kQ29sb3IuY29weSggc291cmNlLmdyb3VuZENvbG9yICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IEhlbWlzcGhlcmVMaWdodCB9O1xyXG4iLCJpbXBvcnQgeyBNYXRyaXg0IH0gZnJvbSAnLi4vbWF0aC9NYXRyaXg0LmpzJztcclxuaW1wb3J0IHsgVmVjdG9yMiB9IGZyb20gJy4uL21hdGgvVmVjdG9yMi5qcyc7XHJcbmltcG9ydCB7IFZlY3RvcjMgfSBmcm9tICcuLi9tYXRoL1ZlY3RvcjMuanMnO1xyXG5pbXBvcnQgeyBWZWN0b3I0IH0gZnJvbSAnLi4vbWF0aC9WZWN0b3I0LmpzJztcclxuaW1wb3J0IHsgRnJ1c3R1bSB9IGZyb20gJy4uL21hdGgvRnJ1c3R1bS5qcyc7XHJcblxyXG5jb25zdCBfcHJvalNjcmVlbk1hdHJpeCA9IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDQoKTtcclxuY29uc3QgX2xpZ2h0UG9zaXRpb25Xb3JsZCA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuY29uc3QgX2xvb2tUYXJnZXQgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XHJcblxyXG5jbGFzcyBMaWdodFNoYWRvdyB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBjYW1lcmEgKSB7XHJcblxyXG5cdFx0dGhpcy5jYW1lcmEgPSBjYW1lcmE7XHJcblxyXG5cdFx0dGhpcy5iaWFzID0gMDtcclxuXHRcdHRoaXMubm9ybWFsQmlhcyA9IDA7XHJcblx0XHR0aGlzLnJhZGl1cyA9IDE7XHJcblx0XHR0aGlzLmJsdXJTYW1wbGVzID0gODtcclxuXHJcblx0XHR0aGlzLm1hcFNpemUgPSBuZXcgVmVjdG9yMiggNTEyLCA1MTIgKTtcclxuXHJcblx0XHR0aGlzLm1hcCA9IG51bGw7XHJcblx0XHR0aGlzLm1hcFBhc3MgPSBudWxsO1xyXG5cdFx0dGhpcy5tYXRyaXggPSBuZXcgTWF0cml4NCgpO1xyXG5cclxuXHRcdHRoaXMuYXV0b1VwZGF0ZSA9IHRydWU7XHJcblx0XHR0aGlzLm5lZWRzVXBkYXRlID0gZmFsc2U7XHJcblxyXG5cdFx0dGhpcy5fZnJ1c3R1bSA9IG5ldyBGcnVzdHVtKCk7XHJcblx0XHR0aGlzLl9mcmFtZUV4dGVudHMgPSBuZXcgVmVjdG9yMiggMSwgMSApO1xyXG5cclxuXHRcdHRoaXMuX3ZpZXdwb3J0Q291bnQgPSAxO1xyXG5cclxuXHRcdHRoaXMuX3ZpZXdwb3J0cyA9IFtcclxuXHJcblx0XHRcdG5ldyBWZWN0b3I0KCAwLCAwLCAxLCAxIClcclxuXHJcblx0XHRdO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldFZpZXdwb3J0Q291bnQoKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuX3ZpZXdwb3J0Q291bnQ7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0RnJ1c3R1bSgpIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5fZnJ1c3R1bTtcclxuXHJcblx0fVxyXG5cclxuXHR1cGRhdGVNYXRyaWNlcyggbGlnaHQgKSB7XHJcblxyXG5cdFx0Y29uc3Qgc2hhZG93Q2FtZXJhID0gdGhpcy5jYW1lcmE7XHJcblx0XHRjb25zdCBzaGFkb3dNYXRyaXggPSB0aGlzLm1hdHJpeDtcclxuXHJcblx0XHRfbGlnaHRQb3NpdGlvbldvcmxkLnNldEZyb21NYXRyaXhQb3NpdGlvbiggbGlnaHQubWF0cml4V29ybGQgKTtcclxuXHRcdHNoYWRvd0NhbWVyYS5wb3NpdGlvbi5jb3B5KCBfbGlnaHRQb3NpdGlvbldvcmxkICk7XHJcblxyXG5cdFx0X2xvb2tUYXJnZXQuc2V0RnJvbU1hdHJpeFBvc2l0aW9uKCBsaWdodC50YXJnZXQubWF0cml4V29ybGQgKTtcclxuXHRcdHNoYWRvd0NhbWVyYS5sb29rQXQoIF9sb29rVGFyZ2V0ICk7XHJcblx0XHRzaGFkb3dDYW1lcmEudXBkYXRlTWF0cml4V29ybGQoKTtcclxuXHJcblx0XHRfcHJvalNjcmVlbk1hdHJpeC5tdWx0aXBseU1hdHJpY2VzKCBzaGFkb3dDYW1lcmEucHJvamVjdGlvbk1hdHJpeCwgc2hhZG93Q2FtZXJhLm1hdHJpeFdvcmxkSW52ZXJzZSApO1xyXG5cdFx0dGhpcy5fZnJ1c3R1bS5zZXRGcm9tUHJvamVjdGlvbk1hdHJpeCggX3Byb2pTY3JlZW5NYXRyaXggKTtcclxuXHJcblx0XHRzaGFkb3dNYXRyaXguc2V0KFxyXG5cdFx0XHQwLjUsIDAuMCwgMC4wLCAwLjUsXHJcblx0XHRcdDAuMCwgMC41LCAwLjAsIDAuNSxcclxuXHRcdFx0MC4wLCAwLjAsIDAuNSwgMC41LFxyXG5cdFx0XHQwLjAsIDAuMCwgMC4wLCAxLjBcclxuXHRcdCk7XHJcblxyXG5cdFx0c2hhZG93TWF0cml4Lm11bHRpcGx5KCBfcHJvalNjcmVlbk1hdHJpeCApO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldFZpZXdwb3J0KCB2aWV3cG9ydEluZGV4ICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLl92aWV3cG9ydHNbIHZpZXdwb3J0SW5kZXggXTtcclxuXHJcblx0fVxyXG5cclxuXHRnZXRGcmFtZUV4dGVudHMoKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuX2ZyYW1lRXh0ZW50cztcclxuXHJcblx0fVxyXG5cclxuXHRkaXNwb3NlKCkge1xyXG5cclxuXHRcdGlmICggdGhpcy5tYXAgKSB7XHJcblxyXG5cdFx0XHR0aGlzLm1hcC5kaXNwb3NlKCk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggdGhpcy5tYXBQYXNzICkge1xyXG5cclxuXHRcdFx0dGhpcy5tYXBQYXNzLmRpc3Bvc2UoKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHRoaXMuY2FtZXJhID0gc291cmNlLmNhbWVyYS5jbG9uZSgpO1xyXG5cclxuXHRcdHRoaXMuYmlhcyA9IHNvdXJjZS5iaWFzO1xyXG5cdFx0dGhpcy5yYWRpdXMgPSBzb3VyY2UucmFkaXVzO1xyXG5cclxuXHRcdHRoaXMubWFwU2l6ZS5jb3B5KCBzb3VyY2UubWFwU2l6ZSApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGNsb25lKCkge1xyXG5cclxuXHRcdHJldHVybiBuZXcgdGhpcy5jb25zdHJ1Y3RvcigpLmNvcHkoIHRoaXMgKTtcclxuXHJcblx0fVxyXG5cclxuXHR0b0pTT04oKSB7XHJcblxyXG5cdFx0Y29uc3Qgb2JqZWN0ID0ge307XHJcblxyXG5cdFx0aWYgKCB0aGlzLmJpYXMgIT09IDAgKSBvYmplY3QuYmlhcyA9IHRoaXMuYmlhcztcclxuXHRcdGlmICggdGhpcy5ub3JtYWxCaWFzICE9PSAwICkgb2JqZWN0Lm5vcm1hbEJpYXMgPSB0aGlzLm5vcm1hbEJpYXM7XHJcblx0XHRpZiAoIHRoaXMucmFkaXVzICE9PSAxICkgb2JqZWN0LnJhZGl1cyA9IHRoaXMucmFkaXVzO1xyXG5cdFx0aWYgKCB0aGlzLm1hcFNpemUueCAhPT0gNTEyIHx8IHRoaXMubWFwU2l6ZS55ICE9PSA1MTIgKSBvYmplY3QubWFwU2l6ZSA9IHRoaXMubWFwU2l6ZS50b0FycmF5KCk7XHJcblxyXG5cdFx0b2JqZWN0LmNhbWVyYSA9IHRoaXMuY2FtZXJhLnRvSlNPTiggZmFsc2UgKS5vYmplY3Q7XHJcblx0XHRkZWxldGUgb2JqZWN0LmNhbWVyYS5tYXRyaXg7XHJcblxyXG5cdFx0cmV0dXJuIG9iamVjdDtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgTGlnaHRTaGFkb3cgfTtcclxuIiwiaW1wb3J0IHsgTGlnaHRTaGFkb3cgfSBmcm9tICcuL0xpZ2h0U2hhZG93LmpzJztcclxuaW1wb3J0ICogYXMgTWF0aFV0aWxzIGZyb20gJy4uL21hdGgvTWF0aFV0aWxzLmpzJztcclxuaW1wb3J0IHsgUGVyc3BlY3RpdmVDYW1lcmEgfSBmcm9tICcuLi9jYW1lcmFzL1BlcnNwZWN0aXZlQ2FtZXJhLmpzJztcclxuXHJcbmNsYXNzIFNwb3RMaWdodFNoYWRvdyBleHRlbmRzIExpZ2h0U2hhZG93IHtcclxuXHJcblx0Y29uc3RydWN0b3IoKSB7XHJcblxyXG5cdFx0c3VwZXIoIG5ldyBQZXJzcGVjdGl2ZUNhbWVyYSggNTAsIDEsIDAuNSwgNTAwICkgKTtcclxuXHJcblx0XHR0aGlzLmlzU3BvdExpZ2h0U2hhZG93ID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLmZvY3VzID0gMTtcclxuXHJcblx0fVxyXG5cclxuXHR1cGRhdGVNYXRyaWNlcyggbGlnaHQgKSB7XHJcblxyXG5cdFx0Y29uc3QgY2FtZXJhID0gdGhpcy5jYW1lcmE7XHJcblxyXG5cdFx0Y29uc3QgZm92ID0gTWF0aFV0aWxzLlJBRDJERUcgKiAyICogbGlnaHQuYW5nbGUgKiB0aGlzLmZvY3VzO1xyXG5cdFx0Y29uc3QgYXNwZWN0ID0gdGhpcy5tYXBTaXplLndpZHRoIC8gdGhpcy5tYXBTaXplLmhlaWdodDtcclxuXHRcdGNvbnN0IGZhciA9IGxpZ2h0LmRpc3RhbmNlIHx8IGNhbWVyYS5mYXI7XHJcblxyXG5cdFx0aWYgKCBmb3YgIT09IGNhbWVyYS5mb3YgfHwgYXNwZWN0ICE9PSBjYW1lcmEuYXNwZWN0IHx8IGZhciAhPT0gY2FtZXJhLmZhciApIHtcclxuXHJcblx0XHRcdGNhbWVyYS5mb3YgPSBmb3Y7XHJcblx0XHRcdGNhbWVyYS5hc3BlY3QgPSBhc3BlY3Q7XHJcblx0XHRcdGNhbWVyYS5mYXIgPSBmYXI7XHJcblx0XHRcdGNhbWVyYS51cGRhdGVQcm9qZWN0aW9uTWF0cml4KCk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHN1cGVyLnVwZGF0ZU1hdHJpY2VzKCBsaWdodCApO1xyXG5cclxuXHR9XHJcblxyXG5cdGNvcHkoIHNvdXJjZSApIHtcclxuXHJcblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcclxuXHJcblx0XHR0aGlzLmZvY3VzID0gc291cmNlLmZvY3VzO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBTcG90TGlnaHRTaGFkb3cgfTtcclxuIiwiaW1wb3J0IHsgTGlnaHQgfSBmcm9tICcuL0xpZ2h0LmpzJztcclxuaW1wb3J0IHsgU3BvdExpZ2h0U2hhZG93IH0gZnJvbSAnLi9TcG90TGlnaHRTaGFkb3cuanMnO1xyXG5pbXBvcnQgeyBPYmplY3QzRCB9IGZyb20gJy4uL2NvcmUvT2JqZWN0M0QuanMnO1xyXG5cclxuY2xhc3MgU3BvdExpZ2h0IGV4dGVuZHMgTGlnaHQge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggY29sb3IsIGludGVuc2l0eSwgZGlzdGFuY2UgPSAwLCBhbmdsZSA9IE1hdGguUEkgLyAzLCBwZW51bWJyYSA9IDAsIGRlY2F5ID0gMiApIHtcclxuXHJcblx0XHRzdXBlciggY29sb3IsIGludGVuc2l0eSApO1xyXG5cclxuXHRcdHRoaXMuaXNTcG90TGlnaHQgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMudHlwZSA9ICdTcG90TGlnaHQnO1xyXG5cclxuXHRcdHRoaXMucG9zaXRpb24uY29weSggT2JqZWN0M0QuREVGQVVMVF9VUCApO1xyXG5cdFx0dGhpcy51cGRhdGVNYXRyaXgoKTtcclxuXHJcblx0XHR0aGlzLnRhcmdldCA9IG5ldyBPYmplY3QzRCgpO1xyXG5cclxuXHRcdHRoaXMuZGlzdGFuY2UgPSBkaXN0YW5jZTtcclxuXHRcdHRoaXMuYW5nbGUgPSBhbmdsZTtcclxuXHRcdHRoaXMucGVudW1icmEgPSBwZW51bWJyYTtcclxuXHRcdHRoaXMuZGVjYXkgPSBkZWNheTtcclxuXHJcblx0XHR0aGlzLm1hcCA9IG51bGw7XHJcblxyXG5cdFx0dGhpcy5zaGFkb3cgPSBuZXcgU3BvdExpZ2h0U2hhZG93KCk7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0IHBvd2VyKCkge1xyXG5cclxuXHRcdC8vIGNvbXB1dGUgdGhlIGxpZ2h0J3MgbHVtaW5vdXMgcG93ZXIgKGluIGx1bWVucykgZnJvbSBpdHMgaW50ZW5zaXR5IChpbiBjYW5kZWxhKVxyXG5cdFx0Ly8gYnkgY29udmVudGlvbiBmb3IgYSBzcG90bGlnaHQsIGx1bWlub3VzIHBvd2VyIChsbSkgPSDPgCAqIGx1bWlub3VzIGludGVuc2l0eSAoY2QpXHJcblx0XHRyZXR1cm4gdGhpcy5pbnRlbnNpdHkgKiBNYXRoLlBJO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldCBwb3dlciggcG93ZXIgKSB7XHJcblxyXG5cdFx0Ly8gc2V0IHRoZSBsaWdodCdzIGludGVuc2l0eSAoaW4gY2FuZGVsYSkgZnJvbSB0aGUgZGVzaXJlZCBsdW1pbm91cyBwb3dlciAoaW4gbHVtZW5zKVxyXG5cdFx0dGhpcy5pbnRlbnNpdHkgPSBwb3dlciAvIE1hdGguUEk7XHJcblxyXG5cdH1cclxuXHJcblx0ZGlzcG9zZSgpIHtcclxuXHJcblx0XHR0aGlzLnNoYWRvdy5kaXNwb3NlKCk7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlLCByZWN1cnNpdmUgKSB7XHJcblxyXG5cdFx0c3VwZXIuY29weSggc291cmNlLCByZWN1cnNpdmUgKTtcclxuXHJcblx0XHR0aGlzLmRpc3RhbmNlID0gc291cmNlLmRpc3RhbmNlO1xyXG5cdFx0dGhpcy5hbmdsZSA9IHNvdXJjZS5hbmdsZTtcclxuXHRcdHRoaXMucGVudW1icmEgPSBzb3VyY2UucGVudW1icmE7XHJcblx0XHR0aGlzLmRlY2F5ID0gc291cmNlLmRlY2F5O1xyXG5cclxuXHRcdHRoaXMudGFyZ2V0ID0gc291cmNlLnRhcmdldC5jbG9uZSgpO1xyXG5cclxuXHRcdHRoaXMuc2hhZG93ID0gc291cmNlLnNoYWRvdy5jbG9uZSgpO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBTcG90TGlnaHQgfTtcclxuIiwiaW1wb3J0IHsgTGlnaHRTaGFkb3cgfSBmcm9tICcuL0xpZ2h0U2hhZG93LmpzJztcclxuaW1wb3J0IHsgUGVyc3BlY3RpdmVDYW1lcmEgfSBmcm9tICcuLi9jYW1lcmFzL1BlcnNwZWN0aXZlQ2FtZXJhLmpzJztcclxuaW1wb3J0IHsgTWF0cml4NCB9IGZyb20gJy4uL21hdGgvTWF0cml4NC5qcyc7XHJcbmltcG9ydCB7IFZlY3RvcjIgfSBmcm9tICcuLi9tYXRoL1ZlY3RvcjIuanMnO1xyXG5pbXBvcnQgeyBWZWN0b3IzIH0gZnJvbSAnLi4vbWF0aC9WZWN0b3IzLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yNCB9IGZyb20gJy4uL21hdGgvVmVjdG9yNC5qcyc7XHJcblxyXG5jb25zdCBfcHJvalNjcmVlbk1hdHJpeCA9IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDQoKTtcclxuY29uc3QgX2xpZ2h0UG9zaXRpb25Xb3JsZCA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuY29uc3QgX2xvb2tUYXJnZXQgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XHJcblxyXG5jbGFzcyBQb2ludExpZ2h0U2hhZG93IGV4dGVuZHMgTGlnaHRTaGFkb3cge1xyXG5cclxuXHRjb25zdHJ1Y3RvcigpIHtcclxuXHJcblx0XHRzdXBlciggbmV3IFBlcnNwZWN0aXZlQ2FtZXJhKCA5MCwgMSwgMC41LCA1MDAgKSApO1xyXG5cclxuXHRcdHRoaXMuaXNQb2ludExpZ2h0U2hhZG93ID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLl9mcmFtZUV4dGVudHMgPSBuZXcgVmVjdG9yMiggNCwgMiApO1xyXG5cclxuXHRcdHRoaXMuX3ZpZXdwb3J0Q291bnQgPSA2O1xyXG5cclxuXHRcdHRoaXMuX3ZpZXdwb3J0cyA9IFtcclxuXHRcdFx0Ly8gVGhlc2Ugdmlld3BvcnRzIG1hcCBhIGN1YmUtbWFwIG9udG8gYSAyRCB0ZXh0dXJlIHdpdGggdGhlXHJcblx0XHRcdC8vIGZvbGxvd2luZyBvcmllbnRhdGlvbjpcclxuXHRcdFx0Ly9cclxuXHRcdFx0Ly8gIHh6WFpcclxuXHRcdFx0Ly8gICB5IFlcclxuXHRcdFx0Ly9cclxuXHRcdFx0Ly8gWCAtIFBvc2l0aXZlIHggZGlyZWN0aW9uXHJcblx0XHRcdC8vIHggLSBOZWdhdGl2ZSB4IGRpcmVjdGlvblxyXG5cdFx0XHQvLyBZIC0gUG9zaXRpdmUgeSBkaXJlY3Rpb25cclxuXHRcdFx0Ly8geSAtIE5lZ2F0aXZlIHkgZGlyZWN0aW9uXHJcblx0XHRcdC8vIFogLSBQb3NpdGl2ZSB6IGRpcmVjdGlvblxyXG5cdFx0XHQvLyB6IC0gTmVnYXRpdmUgeiBkaXJlY3Rpb25cclxuXHJcblx0XHRcdC8vIHBvc2l0aXZlIFhcclxuXHRcdFx0bmV3IFZlY3RvcjQoIDIsIDEsIDEsIDEgKSxcclxuXHRcdFx0Ly8gbmVnYXRpdmUgWFxyXG5cdFx0XHRuZXcgVmVjdG9yNCggMCwgMSwgMSwgMSApLFxyXG5cdFx0XHQvLyBwb3NpdGl2ZSBaXHJcblx0XHRcdG5ldyBWZWN0b3I0KCAzLCAxLCAxLCAxICksXHJcblx0XHRcdC8vIG5lZ2F0aXZlIFpcclxuXHRcdFx0bmV3IFZlY3RvcjQoIDEsIDEsIDEsIDEgKSxcclxuXHRcdFx0Ly8gcG9zaXRpdmUgWVxyXG5cdFx0XHRuZXcgVmVjdG9yNCggMywgMCwgMSwgMSApLFxyXG5cdFx0XHQvLyBuZWdhdGl2ZSBZXHJcblx0XHRcdG5ldyBWZWN0b3I0KCAxLCAwLCAxLCAxIClcclxuXHRcdF07XHJcblxyXG5cdFx0dGhpcy5fY3ViZURpcmVjdGlvbnMgPSBbXHJcblx0XHRcdG5ldyBWZWN0b3IzKCAxLCAwLCAwICksIG5ldyBWZWN0b3IzKCAtIDEsIDAsIDAgKSwgbmV3IFZlY3RvcjMoIDAsIDAsIDEgKSxcclxuXHRcdFx0bmV3IFZlY3RvcjMoIDAsIDAsIC0gMSApLCBuZXcgVmVjdG9yMyggMCwgMSwgMCApLCBuZXcgVmVjdG9yMyggMCwgLSAxLCAwIClcclxuXHRcdF07XHJcblxyXG5cdFx0dGhpcy5fY3ViZVVwcyA9IFtcclxuXHRcdFx0bmV3IFZlY3RvcjMoIDAsIDEsIDAgKSwgbmV3IFZlY3RvcjMoIDAsIDEsIDAgKSwgbmV3IFZlY3RvcjMoIDAsIDEsIDAgKSxcclxuXHRcdFx0bmV3IFZlY3RvcjMoIDAsIDEsIDAgKSwgbmV3IFZlY3RvcjMoIDAsIDAsIDEgKSxcdG5ldyBWZWN0b3IzKCAwLCAwLCAtIDEgKVxyXG5cdFx0XTtcclxuXHJcblx0fVxyXG5cclxuXHR1cGRhdGVNYXRyaWNlcyggbGlnaHQsIHZpZXdwb3J0SW5kZXggPSAwICkge1xyXG5cclxuXHRcdGNvbnN0IGNhbWVyYSA9IHRoaXMuY2FtZXJhO1xyXG5cdFx0Y29uc3Qgc2hhZG93TWF0cml4ID0gdGhpcy5tYXRyaXg7XHJcblxyXG5cdFx0Y29uc3QgZmFyID0gbGlnaHQuZGlzdGFuY2UgfHwgY2FtZXJhLmZhcjtcclxuXHJcblx0XHRpZiAoIGZhciAhPT0gY2FtZXJhLmZhciApIHtcclxuXHJcblx0XHRcdGNhbWVyYS5mYXIgPSBmYXI7XHJcblx0XHRcdGNhbWVyYS51cGRhdGVQcm9qZWN0aW9uTWF0cml4KCk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdF9saWdodFBvc2l0aW9uV29ybGQuc2V0RnJvbU1hdHJpeFBvc2l0aW9uKCBsaWdodC5tYXRyaXhXb3JsZCApO1xyXG5cdFx0Y2FtZXJhLnBvc2l0aW9uLmNvcHkoIF9saWdodFBvc2l0aW9uV29ybGQgKTtcclxuXHJcblx0XHRfbG9va1RhcmdldC5jb3B5KCBjYW1lcmEucG9zaXRpb24gKTtcclxuXHRcdF9sb29rVGFyZ2V0LmFkZCggdGhpcy5fY3ViZURpcmVjdGlvbnNbIHZpZXdwb3J0SW5kZXggXSApO1xyXG5cdFx0Y2FtZXJhLnVwLmNvcHkoIHRoaXMuX2N1YmVVcHNbIHZpZXdwb3J0SW5kZXggXSApO1xyXG5cdFx0Y2FtZXJhLmxvb2tBdCggX2xvb2tUYXJnZXQgKTtcclxuXHRcdGNhbWVyYS51cGRhdGVNYXRyaXhXb3JsZCgpO1xyXG5cclxuXHRcdHNoYWRvd01hdHJpeC5tYWtlVHJhbnNsYXRpb24oIC0gX2xpZ2h0UG9zaXRpb25Xb3JsZC54LCAtIF9saWdodFBvc2l0aW9uV29ybGQueSwgLSBfbGlnaHRQb3NpdGlvbldvcmxkLnogKTtcclxuXHJcblx0XHRfcHJvalNjcmVlbk1hdHJpeC5tdWx0aXBseU1hdHJpY2VzKCBjYW1lcmEucHJvamVjdGlvbk1hdHJpeCwgY2FtZXJhLm1hdHJpeFdvcmxkSW52ZXJzZSApO1xyXG5cdFx0dGhpcy5fZnJ1c3R1bS5zZXRGcm9tUHJvamVjdGlvbk1hdHJpeCggX3Byb2pTY3JlZW5NYXRyaXggKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgUG9pbnRMaWdodFNoYWRvdyB9O1xyXG4iLCJpbXBvcnQgeyBMaWdodCB9IGZyb20gJy4vTGlnaHQuanMnO1xyXG5pbXBvcnQgeyBQb2ludExpZ2h0U2hhZG93IH0gZnJvbSAnLi9Qb2ludExpZ2h0U2hhZG93LmpzJztcclxuXHJcbmNsYXNzIFBvaW50TGlnaHQgZXh0ZW5kcyBMaWdodCB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBjb2xvciwgaW50ZW5zaXR5LCBkaXN0YW5jZSA9IDAsIGRlY2F5ID0gMiApIHtcclxuXHJcblx0XHRzdXBlciggY29sb3IsIGludGVuc2l0eSApO1xyXG5cclxuXHRcdHRoaXMuaXNQb2ludExpZ2h0ID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSAnUG9pbnRMaWdodCc7XHJcblxyXG5cdFx0dGhpcy5kaXN0YW5jZSA9IGRpc3RhbmNlO1xyXG5cdFx0dGhpcy5kZWNheSA9IGRlY2F5O1xyXG5cclxuXHRcdHRoaXMuc2hhZG93ID0gbmV3IFBvaW50TGlnaHRTaGFkb3coKTtcclxuXHJcblx0fVxyXG5cclxuXHRnZXQgcG93ZXIoKSB7XHJcblxyXG5cdFx0Ly8gY29tcHV0ZSB0aGUgbGlnaHQncyBsdW1pbm91cyBwb3dlciAoaW4gbHVtZW5zKSBmcm9tIGl0cyBpbnRlbnNpdHkgKGluIGNhbmRlbGEpXHJcblx0XHQvLyBmb3IgYW4gaXNvdHJvcGljIGxpZ2h0IHNvdXJjZSwgbHVtaW5vdXMgcG93ZXIgKGxtKSA9IDQgz4AgbHVtaW5vdXMgaW50ZW5zaXR5IChjZClcclxuXHRcdHJldHVybiB0aGlzLmludGVuc2l0eSAqIDQgKiBNYXRoLlBJO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldCBwb3dlciggcG93ZXIgKSB7XHJcblxyXG5cdFx0Ly8gc2V0IHRoZSBsaWdodCdzIGludGVuc2l0eSAoaW4gY2FuZGVsYSkgZnJvbSB0aGUgZGVzaXJlZCBsdW1pbm91cyBwb3dlciAoaW4gbHVtZW5zKVxyXG5cdFx0dGhpcy5pbnRlbnNpdHkgPSBwb3dlciAvICggNCAqIE1hdGguUEkgKTtcclxuXHJcblx0fVxyXG5cclxuXHRkaXNwb3NlKCkge1xyXG5cclxuXHRcdHRoaXMuc2hhZG93LmRpc3Bvc2UoKTtcclxuXHJcblx0fVxyXG5cclxuXHRjb3B5KCBzb3VyY2UsIHJlY3Vyc2l2ZSApIHtcclxuXHJcblx0XHRzdXBlci5jb3B5KCBzb3VyY2UsIHJlY3Vyc2l2ZSApO1xyXG5cclxuXHRcdHRoaXMuZGlzdGFuY2UgPSBzb3VyY2UuZGlzdGFuY2U7XHJcblx0XHR0aGlzLmRlY2F5ID0gc291cmNlLmRlY2F5O1xyXG5cclxuXHRcdHRoaXMuc2hhZG93ID0gc291cmNlLnNoYWRvdy5jbG9uZSgpO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBQb2ludExpZ2h0IH07XHJcbiIsImltcG9ydCB7IExpZ2h0U2hhZG93IH0gZnJvbSAnLi9MaWdodFNoYWRvdy5qcyc7XHJcbmltcG9ydCB7IE9ydGhvZ3JhcGhpY0NhbWVyYSB9IGZyb20gJy4uL2NhbWVyYXMvT3J0aG9ncmFwaGljQ2FtZXJhLmpzJztcclxuXHJcbmNsYXNzIERpcmVjdGlvbmFsTGlnaHRTaGFkb3cgZXh0ZW5kcyBMaWdodFNoYWRvdyB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCkge1xyXG5cclxuXHRcdHN1cGVyKCBuZXcgT3J0aG9ncmFwaGljQ2FtZXJhKCAtIDUsIDUsIDUsIC0gNSwgMC41LCA1MDAgKSApO1xyXG5cclxuXHRcdHRoaXMuaXNEaXJlY3Rpb25hbExpZ2h0U2hhZG93ID0gdHJ1ZTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgRGlyZWN0aW9uYWxMaWdodFNoYWRvdyB9O1xyXG4iLCJpbXBvcnQgeyBMaWdodCB9IGZyb20gJy4vTGlnaHQuanMnO1xyXG5pbXBvcnQgeyBEaXJlY3Rpb25hbExpZ2h0U2hhZG93IH0gZnJvbSAnLi9EaXJlY3Rpb25hbExpZ2h0U2hhZG93LmpzJztcclxuaW1wb3J0IHsgT2JqZWN0M0QgfSBmcm9tICcuLi9jb3JlL09iamVjdDNELmpzJztcclxuXHJcbmNsYXNzIERpcmVjdGlvbmFsTGlnaHQgZXh0ZW5kcyBMaWdodCB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBjb2xvciwgaW50ZW5zaXR5ICkge1xyXG5cclxuXHRcdHN1cGVyKCBjb2xvciwgaW50ZW5zaXR5ICk7XHJcblxyXG5cdFx0dGhpcy5pc0RpcmVjdGlvbmFsTGlnaHQgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMudHlwZSA9ICdEaXJlY3Rpb25hbExpZ2h0JztcclxuXHJcblx0XHR0aGlzLnBvc2l0aW9uLmNvcHkoIE9iamVjdDNELkRFRkFVTFRfVVAgKTtcclxuXHRcdHRoaXMudXBkYXRlTWF0cml4KCk7XHJcblxyXG5cdFx0dGhpcy50YXJnZXQgPSBuZXcgT2JqZWN0M0QoKTtcclxuXHJcblx0XHR0aGlzLnNoYWRvdyA9IG5ldyBEaXJlY3Rpb25hbExpZ2h0U2hhZG93KCk7XHJcblxyXG5cdH1cclxuXHJcblx0ZGlzcG9zZSgpIHtcclxuXHJcblx0XHR0aGlzLnNoYWRvdy5kaXNwb3NlKCk7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xyXG5cclxuXHRcdHRoaXMudGFyZ2V0ID0gc291cmNlLnRhcmdldC5jbG9uZSgpO1xyXG5cdFx0dGhpcy5zaGFkb3cgPSBzb3VyY2Uuc2hhZG93LmNsb25lKCk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IERpcmVjdGlvbmFsTGlnaHQgfTtcclxuIiwiaW1wb3J0IHsgTGlnaHQgfSBmcm9tICcuL0xpZ2h0LmpzJztcclxuXHJcbmNsYXNzIEFtYmllbnRMaWdodCBleHRlbmRzIExpZ2h0IHtcclxuXHJcblx0Y29uc3RydWN0b3IoIGNvbG9yLCBpbnRlbnNpdHkgKSB7XHJcblxyXG5cdFx0c3VwZXIoIGNvbG9yLCBpbnRlbnNpdHkgKTtcclxuXHJcblx0XHR0aGlzLmlzQW1iaWVudExpZ2h0ID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSAnQW1iaWVudExpZ2h0JztcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgQW1iaWVudExpZ2h0IH07XHJcbiIsImltcG9ydCB7IExpZ2h0IH0gZnJvbSAnLi9MaWdodC5qcyc7XHJcblxyXG5jbGFzcyBSZWN0QXJlYUxpZ2h0IGV4dGVuZHMgTGlnaHQge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggY29sb3IsIGludGVuc2l0eSwgd2lkdGggPSAxMCwgaGVpZ2h0ID0gMTAgKSB7XHJcblxyXG5cdFx0c3VwZXIoIGNvbG9yLCBpbnRlbnNpdHkgKTtcclxuXHJcblx0XHR0aGlzLmlzUmVjdEFyZWFMaWdodCA9IHRydWU7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ1JlY3RBcmVhTGlnaHQnO1xyXG5cclxuXHRcdHRoaXMud2lkdGggPSB3aWR0aDtcclxuXHRcdHRoaXMuaGVpZ2h0ID0gaGVpZ2h0O1xyXG5cclxuXHR9XHJcblxyXG5cdGdldCBwb3dlcigpIHtcclxuXHJcblx0XHQvLyBjb21wdXRlIHRoZSBsaWdodCdzIGx1bWlub3VzIHBvd2VyIChpbiBsdW1lbnMpIGZyb20gaXRzIGludGVuc2l0eSAoaW4gbml0cylcclxuXHRcdHJldHVybiB0aGlzLmludGVuc2l0eSAqIHRoaXMud2lkdGggKiB0aGlzLmhlaWdodCAqIE1hdGguUEk7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0IHBvd2VyKCBwb3dlciApIHtcclxuXHJcblx0XHQvLyBzZXQgdGhlIGxpZ2h0J3MgaW50ZW5zaXR5IChpbiBuaXRzKSBmcm9tIHRoZSBkZXNpcmVkIGx1bWlub3VzIHBvd2VyIChpbiBsdW1lbnMpXHJcblx0XHR0aGlzLmludGVuc2l0eSA9IHBvd2VyIC8gKCB0aGlzLndpZHRoICogdGhpcy5oZWlnaHQgKiBNYXRoLlBJICk7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xyXG5cclxuXHRcdHRoaXMud2lkdGggPSBzb3VyY2Uud2lkdGg7XHJcblx0XHR0aGlzLmhlaWdodCA9IHNvdXJjZS5oZWlnaHQ7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0dG9KU09OKCBtZXRhICkge1xyXG5cclxuXHRcdGNvbnN0IGRhdGEgPSBzdXBlci50b0pTT04oIG1ldGEgKTtcclxuXHJcblx0XHRkYXRhLm9iamVjdC53aWR0aCA9IHRoaXMud2lkdGg7XHJcblx0XHRkYXRhLm9iamVjdC5oZWlnaHQgPSB0aGlzLmhlaWdodDtcclxuXHJcblx0XHRyZXR1cm4gZGF0YTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgUmVjdEFyZWFMaWdodCB9O1xyXG4iLCJpbXBvcnQgeyBWZWN0b3IzIH0gZnJvbSAnLi9WZWN0b3IzLmpzJztcclxuXHJcbi8qKlxyXG4gKiBQcmltYXJ5IHJlZmVyZW5jZTpcclxuICogICBodHRwczovL2dyYXBoaWNzLnN0YW5mb3JkLmVkdS9wYXBlcnMvZW52bWFwL2Vudm1hcC5wZGZcclxuICpcclxuICogU2Vjb25kYXJ5IHJlZmVyZW5jZTpcclxuICogICBodHRwczovL3d3dy5wcHNsb2FuLm9yZy9wdWJsaWNhdGlvbnMvU3R1cGlkU0gzNi5wZGZcclxuICovXHJcblxyXG4vLyAzLWJhbmQgU0ggZGVmaW5lZCBieSA5IGNvZWZmaWNpZW50c1xyXG5cclxuY2xhc3MgU3BoZXJpY2FsSGFybW9uaWNzMyB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCkge1xyXG5cclxuXHRcdHRoaXMuaXNTcGhlcmljYWxIYXJtb25pY3MzID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLmNvZWZmaWNpZW50cyA9IFtdO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IDk7IGkgKysgKSB7XHJcblxyXG5cdFx0XHR0aGlzLmNvZWZmaWNpZW50cy5wdXNoKCBuZXcgVmVjdG9yMygpICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdHNldCggY29lZmZpY2llbnRzICkge1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IDk7IGkgKysgKSB7XHJcblxyXG5cdFx0XHR0aGlzLmNvZWZmaWNpZW50c1sgaSBdLmNvcHkoIGNvZWZmaWNpZW50c1sgaSBdICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHplcm8oKSB7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgOTsgaSArKyApIHtcclxuXHJcblx0XHRcdHRoaXMuY29lZmZpY2llbnRzWyBpIF0uc2V0KCAwLCAwLCAwICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdC8vIGdldCB0aGUgcmFkaWFuY2UgaW4gdGhlIGRpcmVjdGlvbiBvZiB0aGUgbm9ybWFsXHJcblx0Ly8gdGFyZ2V0IGlzIGEgVmVjdG9yM1xyXG5cdGdldEF0KCBub3JtYWwsIHRhcmdldCApIHtcclxuXHJcblx0XHQvLyBub3JtYWwgaXMgYXNzdW1lZCB0byBiZSB1bml0IGxlbmd0aFxyXG5cclxuXHRcdGNvbnN0IHggPSBub3JtYWwueCwgeSA9IG5vcm1hbC55LCB6ID0gbm9ybWFsLno7XHJcblxyXG5cdFx0Y29uc3QgY29lZmYgPSB0aGlzLmNvZWZmaWNpZW50cztcclxuXHJcblx0XHQvLyBiYW5kIDBcclxuXHRcdHRhcmdldC5jb3B5KCBjb2VmZlsgMCBdICkubXVsdGlwbHlTY2FsYXIoIDAuMjgyMDk1ICk7XHJcblxyXG5cdFx0Ly8gYmFuZCAxXHJcblx0XHR0YXJnZXQuYWRkU2NhbGVkVmVjdG9yKCBjb2VmZlsgMSBdLCAwLjQ4ODYwMyAqIHkgKTtcclxuXHRcdHRhcmdldC5hZGRTY2FsZWRWZWN0b3IoIGNvZWZmWyAyIF0sIDAuNDg4NjAzICogeiApO1xyXG5cdFx0dGFyZ2V0LmFkZFNjYWxlZFZlY3RvciggY29lZmZbIDMgXSwgMC40ODg2MDMgKiB4ICk7XHJcblxyXG5cdFx0Ly8gYmFuZCAyXHJcblx0XHR0YXJnZXQuYWRkU2NhbGVkVmVjdG9yKCBjb2VmZlsgNCBdLCAxLjA5MjU0OCAqICggeCAqIHkgKSApO1xyXG5cdFx0dGFyZ2V0LmFkZFNjYWxlZFZlY3RvciggY29lZmZbIDUgXSwgMS4wOTI1NDggKiAoIHkgKiB6ICkgKTtcclxuXHRcdHRhcmdldC5hZGRTY2FsZWRWZWN0b3IoIGNvZWZmWyA2IF0sIDAuMzE1MzkyICogKCAzLjAgKiB6ICogeiAtIDEuMCApICk7XHJcblx0XHR0YXJnZXQuYWRkU2NhbGVkVmVjdG9yKCBjb2VmZlsgNyBdLCAxLjA5MjU0OCAqICggeCAqIHogKSApO1xyXG5cdFx0dGFyZ2V0LmFkZFNjYWxlZFZlY3RvciggY29lZmZbIDggXSwgMC41NDYyNzQgKiAoIHggKiB4IC0geSAqIHkgKSApO1xyXG5cclxuXHRcdHJldHVybiB0YXJnZXQ7XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gZ2V0IHRoZSBpcnJhZGlhbmNlIChyYWRpYW5jZSBjb252b2x2ZWQgd2l0aCBjb3NpbmUgbG9iZSkgaW4gdGhlIGRpcmVjdGlvbiBvZiB0aGUgbm9ybWFsXHJcblx0Ly8gdGFyZ2V0IGlzIGEgVmVjdG9yM1xyXG5cdC8vIGh0dHBzOi8vZ3JhcGhpY3Muc3RhbmZvcmQuZWR1L3BhcGVycy9lbnZtYXAvZW52bWFwLnBkZlxyXG5cdGdldElycmFkaWFuY2VBdCggbm9ybWFsLCB0YXJnZXQgKSB7XHJcblxyXG5cdFx0Ly8gbm9ybWFsIGlzIGFzc3VtZWQgdG8gYmUgdW5pdCBsZW5ndGhcclxuXHJcblx0XHRjb25zdCB4ID0gbm9ybWFsLngsIHkgPSBub3JtYWwueSwgeiA9IG5vcm1hbC56O1xyXG5cclxuXHRcdGNvbnN0IGNvZWZmID0gdGhpcy5jb2VmZmljaWVudHM7XHJcblxyXG5cdFx0Ly8gYmFuZCAwXHJcblx0XHR0YXJnZXQuY29weSggY29lZmZbIDAgXSApLm11bHRpcGx5U2NhbGFyKCAwLjg4NjIyNyApOyAvLyDPgCAqIDAuMjgyMDk1XHJcblxyXG5cdFx0Ly8gYmFuZCAxXHJcblx0XHR0YXJnZXQuYWRkU2NhbGVkVmVjdG9yKCBjb2VmZlsgMSBdLCAyLjAgKiAwLjUxMTY2NCAqIHkgKTsgLy8gKCAyICogz4AgLyAzICkgKiAwLjQ4ODYwM1xyXG5cdFx0dGFyZ2V0LmFkZFNjYWxlZFZlY3RvciggY29lZmZbIDIgXSwgMi4wICogMC41MTE2NjQgKiB6ICk7XHJcblx0XHR0YXJnZXQuYWRkU2NhbGVkVmVjdG9yKCBjb2VmZlsgMyBdLCAyLjAgKiAwLjUxMTY2NCAqIHggKTtcclxuXHJcblx0XHQvLyBiYW5kIDJcclxuXHRcdHRhcmdldC5hZGRTY2FsZWRWZWN0b3IoIGNvZWZmWyA0IF0sIDIuMCAqIDAuNDI5MDQzICogeCAqIHkgKTsgLy8gKCDPgCAvIDQgKSAqIDEuMDkyNTQ4XHJcblx0XHR0YXJnZXQuYWRkU2NhbGVkVmVjdG9yKCBjb2VmZlsgNSBdLCAyLjAgKiAwLjQyOTA0MyAqIHkgKiB6ICk7XHJcblx0XHR0YXJnZXQuYWRkU2NhbGVkVmVjdG9yKCBjb2VmZlsgNiBdLCAwLjc0MzEyNSAqIHogKiB6IC0gMC4yNDc3MDggKTsgLy8gKCDPgCAvIDQgKSAqIDAuMzE1MzkyICogM1xyXG5cdFx0dGFyZ2V0LmFkZFNjYWxlZFZlY3RvciggY29lZmZbIDcgXSwgMi4wICogMC40MjkwNDMgKiB4ICogeiApO1xyXG5cdFx0dGFyZ2V0LmFkZFNjYWxlZFZlY3RvciggY29lZmZbIDggXSwgMC40MjkwNDMgKiAoIHggKiB4IC0geSAqIHkgKSApOyAvLyAoIM+AIC8gNCApICogMC41NDYyNzRcclxuXHJcblx0XHRyZXR1cm4gdGFyZ2V0O1xyXG5cclxuXHR9XHJcblxyXG5cdGFkZCggc2ggKSB7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgOTsgaSArKyApIHtcclxuXHJcblx0XHRcdHRoaXMuY29lZmZpY2llbnRzWyBpIF0uYWRkKCBzaC5jb2VmZmljaWVudHNbIGkgXSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRhZGRTY2FsZWRTSCggc2gsIHMgKSB7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgOTsgaSArKyApIHtcclxuXHJcblx0XHRcdHRoaXMuY29lZmZpY2llbnRzWyBpIF0uYWRkU2NhbGVkVmVjdG9yKCBzaC5jb2VmZmljaWVudHNbIGkgXSwgcyApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzY2FsZSggcyApIHtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCA5OyBpICsrICkge1xyXG5cclxuXHRcdFx0dGhpcy5jb2VmZmljaWVudHNbIGkgXS5tdWx0aXBseVNjYWxhciggcyApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRsZXJwKCBzaCwgYWxwaGEgKSB7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgOTsgaSArKyApIHtcclxuXHJcblx0XHRcdHRoaXMuY29lZmZpY2llbnRzWyBpIF0ubGVycCggc2guY29lZmZpY2llbnRzWyBpIF0sIGFscGhhICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGVxdWFscyggc2ggKSB7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgOTsgaSArKyApIHtcclxuXHJcblx0XHRcdGlmICggISB0aGlzLmNvZWZmaWNpZW50c1sgaSBdLmVxdWFscyggc2guY29lZmZpY2llbnRzWyBpIF0gKSApIHtcclxuXHJcblx0XHRcdFx0cmV0dXJuIGZhbHNlO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdHJ1ZTtcclxuXHJcblx0fVxyXG5cclxuXHRjb3B5KCBzaCApIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5zZXQoIHNoLmNvZWZmaWNpZW50cyApO1xyXG5cclxuXHR9XHJcblxyXG5cdGNsb25lKCkge1xyXG5cclxuXHRcdHJldHVybiBuZXcgdGhpcy5jb25zdHJ1Y3RvcigpLmNvcHkoIHRoaXMgKTtcclxuXHJcblx0fVxyXG5cclxuXHRmcm9tQXJyYXkoIGFycmF5LCBvZmZzZXQgPSAwICkge1xyXG5cclxuXHRcdGNvbnN0IGNvZWZmaWNpZW50cyA9IHRoaXMuY29lZmZpY2llbnRzO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IDk7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRjb2VmZmljaWVudHNbIGkgXS5mcm9tQXJyYXkoIGFycmF5LCBvZmZzZXQgKyAoIGkgKiAzICkgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0dG9BcnJheSggYXJyYXkgPSBbXSwgb2Zmc2V0ID0gMCApIHtcclxuXHJcblx0XHRjb25zdCBjb2VmZmljaWVudHMgPSB0aGlzLmNvZWZmaWNpZW50cztcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCA5OyBpICsrICkge1xyXG5cclxuXHRcdFx0Y29lZmZpY2llbnRzWyBpIF0udG9BcnJheSggYXJyYXksIG9mZnNldCArICggaSAqIDMgKSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gYXJyYXk7XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gZXZhbHVhdGUgdGhlIGJhc2lzIGZ1bmN0aW9uc1xyXG5cdC8vIHNoQmFzaXMgaXMgYW4gQXJyYXlbIDkgXVxyXG5cdHN0YXRpYyBnZXRCYXNpc0F0KCBub3JtYWwsIHNoQmFzaXMgKSB7XHJcblxyXG5cdFx0Ly8gbm9ybWFsIGlzIGFzc3VtZWQgdG8gYmUgdW5pdCBsZW5ndGhcclxuXHJcblx0XHRjb25zdCB4ID0gbm9ybWFsLngsIHkgPSBub3JtYWwueSwgeiA9IG5vcm1hbC56O1xyXG5cclxuXHRcdC8vIGJhbmQgMFxyXG5cdFx0c2hCYXNpc1sgMCBdID0gMC4yODIwOTU7XHJcblxyXG5cdFx0Ly8gYmFuZCAxXHJcblx0XHRzaEJhc2lzWyAxIF0gPSAwLjQ4ODYwMyAqIHk7XHJcblx0XHRzaEJhc2lzWyAyIF0gPSAwLjQ4ODYwMyAqIHo7XHJcblx0XHRzaEJhc2lzWyAzIF0gPSAwLjQ4ODYwMyAqIHg7XHJcblxyXG5cdFx0Ly8gYmFuZCAyXHJcblx0XHRzaEJhc2lzWyA0IF0gPSAxLjA5MjU0OCAqIHggKiB5O1xyXG5cdFx0c2hCYXNpc1sgNSBdID0gMS4wOTI1NDggKiB5ICogejtcclxuXHRcdHNoQmFzaXNbIDYgXSA9IDAuMzE1MzkyICogKCAzICogeiAqIHogLSAxICk7XHJcblx0XHRzaEJhc2lzWyA3IF0gPSAxLjA5MjU0OCAqIHggKiB6O1xyXG5cdFx0c2hCYXNpc1sgOCBdID0gMC41NDYyNzQgKiAoIHggKiB4IC0geSAqIHkgKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgU3BoZXJpY2FsSGFybW9uaWNzMyB9O1xyXG4iLCJpbXBvcnQgeyBTcGhlcmljYWxIYXJtb25pY3MzIH0gZnJvbSAnLi4vbWF0aC9TcGhlcmljYWxIYXJtb25pY3MzLmpzJztcclxuaW1wb3J0IHsgTGlnaHQgfSBmcm9tICcuL0xpZ2h0LmpzJztcclxuXHJcbmNsYXNzIExpZ2h0UHJvYmUgZXh0ZW5kcyBMaWdodCB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBzaCA9IG5ldyBTcGhlcmljYWxIYXJtb25pY3MzKCksIGludGVuc2l0eSA9IDEgKSB7XHJcblxyXG5cdFx0c3VwZXIoIHVuZGVmaW5lZCwgaW50ZW5zaXR5ICk7XHJcblxyXG5cdFx0dGhpcy5pc0xpZ2h0UHJvYmUgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMuc2ggPSBzaDtcclxuXHJcblx0fVxyXG5cclxuXHRjb3B5KCBzb3VyY2UgKSB7XHJcblxyXG5cdFx0c3VwZXIuY29weSggc291cmNlICk7XHJcblxyXG5cdFx0dGhpcy5zaC5jb3B5KCBzb3VyY2Uuc2ggKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRmcm9tSlNPTigganNvbiApIHtcclxuXHJcblx0XHR0aGlzLmludGVuc2l0eSA9IGpzb24uaW50ZW5zaXR5OyAvLyBUT0RPOiBNb3ZlIHRoaXMgYml0IHRvIExpZ2h0LmZyb21KU09OKCk7XHJcblx0XHR0aGlzLnNoLmZyb21BcnJheSgganNvbi5zaCApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHRvSlNPTiggbWV0YSApIHtcclxuXHJcblx0XHRjb25zdCBkYXRhID0gc3VwZXIudG9KU09OKCBtZXRhICk7XHJcblxyXG5cdFx0ZGF0YS5vYmplY3Quc2ggPSB0aGlzLnNoLnRvQXJyYXkoKTtcclxuXHJcblx0XHRyZXR1cm4gZGF0YTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgTGlnaHRQcm9iZSB9O1xyXG4iLCJpbXBvcnQgeyBDb2xvciB9IGZyb20gJy4uL21hdGgvQ29sb3IuanMnO1xyXG5pbXBvcnQgeyBWZWN0b3IyIH0gZnJvbSAnLi4vbWF0aC9WZWN0b3IyLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yMyB9IGZyb20gJy4uL21hdGgvVmVjdG9yMy5qcyc7XHJcbmltcG9ydCB7IFZlY3RvcjQgfSBmcm9tICcuLi9tYXRoL1ZlY3RvcjQuanMnO1xyXG5pbXBvcnQgeyBNYXRyaXgzIH0gZnJvbSAnLi4vbWF0aC9NYXRyaXgzLmpzJztcclxuaW1wb3J0IHsgTWF0cml4NCB9IGZyb20gJy4uL21hdGgvTWF0cml4NC5qcyc7XHJcbmltcG9ydCB7IEZpbGVMb2FkZXIgfSBmcm9tICcuL0ZpbGVMb2FkZXIuanMnO1xyXG5pbXBvcnQgeyBMb2FkZXIgfSBmcm9tICcuL0xvYWRlci5qcyc7XHJcbmltcG9ydCB7XHJcblx0U2hhZG93TWF0ZXJpYWwsXHJcblx0U3ByaXRlTWF0ZXJpYWwsXHJcblx0UmF3U2hhZGVyTWF0ZXJpYWwsXHJcblx0U2hhZGVyTWF0ZXJpYWwsXHJcblx0UG9pbnRzTWF0ZXJpYWwsXHJcblx0TWVzaFBoeXNpY2FsTWF0ZXJpYWwsXHJcblx0TWVzaFN0YW5kYXJkTWF0ZXJpYWwsXHJcblx0TWVzaFBob25nTWF0ZXJpYWwsXHJcblx0TWVzaFRvb25NYXRlcmlhbCxcclxuXHRNZXNoTm9ybWFsTWF0ZXJpYWwsXHJcblx0TWVzaExhbWJlcnRNYXRlcmlhbCxcclxuXHRNZXNoRGVwdGhNYXRlcmlhbCxcclxuXHRNZXNoRGlzdGFuY2VNYXRlcmlhbCxcclxuXHRNZXNoQmFzaWNNYXRlcmlhbCxcclxuXHRNZXNoTWF0Y2FwTWF0ZXJpYWwsXHJcblx0TGluZURhc2hlZE1hdGVyaWFsLFxyXG5cdExpbmVCYXNpY01hdGVyaWFsLFxyXG5cdE1hdGVyaWFsLFxyXG59IGZyb20gJy4uL21hdGVyaWFscy9NYXRlcmlhbHMuanMnO1xyXG5cclxuY2xhc3MgTWF0ZXJpYWxMb2FkZXIgZXh0ZW5kcyBMb2FkZXIge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggbWFuYWdlciApIHtcclxuXHJcblx0XHRzdXBlciggbWFuYWdlciApO1xyXG5cdFx0dGhpcy50ZXh0dXJlcyA9IHt9O1xyXG5cclxuXHR9XHJcblxyXG5cdGxvYWQoIHVybCwgb25Mb2FkLCBvblByb2dyZXNzLCBvbkVycm9yICkge1xyXG5cclxuXHRcdGNvbnN0IHNjb3BlID0gdGhpcztcclxuXHJcblx0XHRjb25zdCBsb2FkZXIgPSBuZXcgRmlsZUxvYWRlciggc2NvcGUubWFuYWdlciApO1xyXG5cdFx0bG9hZGVyLnNldFBhdGgoIHNjb3BlLnBhdGggKTtcclxuXHRcdGxvYWRlci5zZXRSZXF1ZXN0SGVhZGVyKCBzY29wZS5yZXF1ZXN0SGVhZGVyICk7XHJcblx0XHRsb2FkZXIuc2V0V2l0aENyZWRlbnRpYWxzKCBzY29wZS53aXRoQ3JlZGVudGlhbHMgKTtcclxuXHRcdGxvYWRlci5sb2FkKCB1cmwsIGZ1bmN0aW9uICggdGV4dCApIHtcclxuXHJcblx0XHRcdHRyeSB7XHJcblxyXG5cdFx0XHRcdG9uTG9hZCggc2NvcGUucGFyc2UoIEpTT04ucGFyc2UoIHRleHQgKSApICk7XHJcblxyXG5cdFx0XHR9IGNhdGNoICggZSApIHtcclxuXHJcblx0XHRcdFx0aWYgKCBvbkVycm9yICkge1xyXG5cclxuXHRcdFx0XHRcdG9uRXJyb3IoIGUgKTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRjb25zb2xlLmVycm9yKCBlICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0c2NvcGUubWFuYWdlci5pdGVtRXJyb3IoIHVybCApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH0sIG9uUHJvZ3Jlc3MsIG9uRXJyb3IgKTtcclxuXHJcblx0fVxyXG5cclxuXHRwYXJzZSgganNvbiApIHtcclxuXHJcblx0XHRjb25zdCB0ZXh0dXJlcyA9IHRoaXMudGV4dHVyZXM7XHJcblxyXG5cdFx0ZnVuY3Rpb24gZ2V0VGV4dHVyZSggbmFtZSApIHtcclxuXHJcblx0XHRcdGlmICggdGV4dHVyZXNbIG5hbWUgXSA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5NYXRlcmlhbExvYWRlcjogVW5kZWZpbmVkIHRleHR1cmUnLCBuYW1lICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRyZXR1cm4gdGV4dHVyZXNbIG5hbWUgXTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Y29uc3QgbWF0ZXJpYWwgPSBNYXRlcmlhbExvYWRlci5jcmVhdGVNYXRlcmlhbEZyb21UeXBlKCBqc29uLnR5cGUgKTtcclxuXHJcblx0XHRpZiAoIGpzb24udXVpZCAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwudXVpZCA9IGpzb24udXVpZDtcclxuXHRcdGlmICgganNvbi5uYW1lICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5uYW1lID0ganNvbi5uYW1lO1xyXG5cdFx0aWYgKCBqc29uLmNvbG9yICE9PSB1bmRlZmluZWQgJiYgbWF0ZXJpYWwuY29sb3IgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmNvbG9yLnNldEhleCgganNvbi5jb2xvciApO1xyXG5cdFx0aWYgKCBqc29uLnJvdWdobmVzcyAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwucm91Z2huZXNzID0ganNvbi5yb3VnaG5lc3M7XHJcblx0XHRpZiAoIGpzb24ubWV0YWxuZXNzICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5tZXRhbG5lc3MgPSBqc29uLm1ldGFsbmVzcztcclxuXHRcdGlmICgganNvbi5zaGVlbiAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuc2hlZW4gPSBqc29uLnNoZWVuO1xyXG5cdFx0aWYgKCBqc29uLnNoZWVuQ29sb3IgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnNoZWVuQ29sb3IgPSBuZXcgQ29sb3IoKS5zZXRIZXgoIGpzb24uc2hlZW5Db2xvciApO1xyXG5cdFx0aWYgKCBqc29uLnNoZWVuUm91Z2huZXNzICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5zaGVlblJvdWdobmVzcyA9IGpzb24uc2hlZW5Sb3VnaG5lc3M7XHJcblx0XHRpZiAoIGpzb24uZW1pc3NpdmUgIT09IHVuZGVmaW5lZCAmJiBtYXRlcmlhbC5lbWlzc2l2ZSAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuZW1pc3NpdmUuc2V0SGV4KCBqc29uLmVtaXNzaXZlICk7XHJcblx0XHRpZiAoIGpzb24uc3BlY3VsYXIgIT09IHVuZGVmaW5lZCAmJiBtYXRlcmlhbC5zcGVjdWxhciAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuc3BlY3VsYXIuc2V0SGV4KCBqc29uLnNwZWN1bGFyICk7XHJcblx0XHRpZiAoIGpzb24uc3BlY3VsYXJJbnRlbnNpdHkgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnNwZWN1bGFySW50ZW5zaXR5ID0ganNvbi5zcGVjdWxhckludGVuc2l0eTtcclxuXHRcdGlmICgganNvbi5zcGVjdWxhckNvbG9yICE9PSB1bmRlZmluZWQgJiYgbWF0ZXJpYWwuc3BlY3VsYXJDb2xvciAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuc3BlY3VsYXJDb2xvci5zZXRIZXgoIGpzb24uc3BlY3VsYXJDb2xvciApO1xyXG5cdFx0aWYgKCBqc29uLnNoaW5pbmVzcyAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuc2hpbmluZXNzID0ganNvbi5zaGluaW5lc3M7XHJcblx0XHRpZiAoIGpzb24uY2xlYXJjb2F0ICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5jbGVhcmNvYXQgPSBqc29uLmNsZWFyY29hdDtcclxuXHRcdGlmICgganNvbi5jbGVhcmNvYXRSb3VnaG5lc3MgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmNsZWFyY29hdFJvdWdobmVzcyA9IGpzb24uY2xlYXJjb2F0Um91Z2huZXNzO1xyXG5cdFx0aWYgKCBqc29uLmlyaWRlc2NlbmNlICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5pcmlkZXNjZW5jZSA9IGpzb24uaXJpZGVzY2VuY2U7XHJcblx0XHRpZiAoIGpzb24uaXJpZGVzY2VuY2VJT1IgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmlyaWRlc2NlbmNlSU9SID0ganNvbi5pcmlkZXNjZW5jZUlPUjtcclxuXHRcdGlmICgganNvbi5pcmlkZXNjZW5jZVRoaWNrbmVzc1JhbmdlICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5pcmlkZXNjZW5jZVRoaWNrbmVzc1JhbmdlID0ganNvbi5pcmlkZXNjZW5jZVRoaWNrbmVzc1JhbmdlO1xyXG5cdFx0aWYgKCBqc29uLnRyYW5zbWlzc2lvbiAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwudHJhbnNtaXNzaW9uID0ganNvbi50cmFuc21pc3Npb247XHJcblx0XHRpZiAoIGpzb24udGhpY2tuZXNzICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC50aGlja25lc3MgPSBqc29uLnRoaWNrbmVzcztcclxuXHRcdGlmICgganNvbi5hdHRlbnVhdGlvbkRpc3RhbmNlICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5hdHRlbnVhdGlvbkRpc3RhbmNlID0ganNvbi5hdHRlbnVhdGlvbkRpc3RhbmNlO1xyXG5cdFx0aWYgKCBqc29uLmF0dGVudWF0aW9uQ29sb3IgIT09IHVuZGVmaW5lZCAmJiBtYXRlcmlhbC5hdHRlbnVhdGlvbkNvbG9yICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5hdHRlbnVhdGlvbkNvbG9yLnNldEhleCgganNvbi5hdHRlbnVhdGlvbkNvbG9yICk7XHJcblx0XHRpZiAoIGpzb24uYW5pc290cm9weSAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuYW5pc290cm9weSA9IGpzb24uYW5pc290cm9weTtcclxuXHRcdGlmICgganNvbi5hbmlzb3Ryb3B5Um90YXRpb24gIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmFuaXNvdHJvcHlSb3RhdGlvbiA9IGpzb24uYW5pc290cm9weVJvdGF0aW9uO1xyXG5cdFx0aWYgKCBqc29uLmZvZyAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuZm9nID0ganNvbi5mb2c7XHJcblx0XHRpZiAoIGpzb24uZmxhdFNoYWRpbmcgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmZsYXRTaGFkaW5nID0ganNvbi5mbGF0U2hhZGluZztcclxuXHRcdGlmICgganNvbi5ibGVuZGluZyAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuYmxlbmRpbmcgPSBqc29uLmJsZW5kaW5nO1xyXG5cdFx0aWYgKCBqc29uLmNvbWJpbmUgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmNvbWJpbmUgPSBqc29uLmNvbWJpbmU7XHJcblx0XHRpZiAoIGpzb24uc2lkZSAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuc2lkZSA9IGpzb24uc2lkZTtcclxuXHRcdGlmICgganNvbi5zaGFkb3dTaWRlICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5zaGFkb3dTaWRlID0ganNvbi5zaGFkb3dTaWRlO1xyXG5cdFx0aWYgKCBqc29uLm9wYWNpdHkgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLm9wYWNpdHkgPSBqc29uLm9wYWNpdHk7XHJcblx0XHRpZiAoIGpzb24udHJhbnNwYXJlbnQgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnRyYW5zcGFyZW50ID0ganNvbi50cmFuc3BhcmVudDtcclxuXHRcdGlmICgganNvbi5hbHBoYVRlc3QgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmFscGhhVGVzdCA9IGpzb24uYWxwaGFUZXN0O1xyXG5cdFx0aWYgKCBqc29uLmFscGhhSGFzaCAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuYWxwaGFIYXNoID0ganNvbi5hbHBoYUhhc2g7XHJcblx0XHRpZiAoIGpzb24uZGVwdGhGdW5jICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5kZXB0aEZ1bmMgPSBqc29uLmRlcHRoRnVuYztcclxuXHRcdGlmICgganNvbi5kZXB0aFRlc3QgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmRlcHRoVGVzdCA9IGpzb24uZGVwdGhUZXN0O1xyXG5cdFx0aWYgKCBqc29uLmRlcHRoV3JpdGUgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmRlcHRoV3JpdGUgPSBqc29uLmRlcHRoV3JpdGU7XHJcblx0XHRpZiAoIGpzb24uY29sb3JXcml0ZSAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuY29sb3JXcml0ZSA9IGpzb24uY29sb3JXcml0ZTtcclxuXHRcdGlmICgganNvbi5ibGVuZFNyYyAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuYmxlbmRTcmMgPSBqc29uLmJsZW5kU3JjO1xyXG5cdFx0aWYgKCBqc29uLmJsZW5kRHN0ICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5ibGVuZERzdCA9IGpzb24uYmxlbmREc3Q7XHJcblx0XHRpZiAoIGpzb24uYmxlbmRFcXVhdGlvbiAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuYmxlbmRFcXVhdGlvbiA9IGpzb24uYmxlbmRFcXVhdGlvbjtcclxuXHRcdGlmICgganNvbi5ibGVuZFNyY0FscGhhICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5ibGVuZFNyY0FscGhhID0ganNvbi5ibGVuZFNyY0FscGhhO1xyXG5cdFx0aWYgKCBqc29uLmJsZW5kRHN0QWxwaGEgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmJsZW5kRHN0QWxwaGEgPSBqc29uLmJsZW5kRHN0QWxwaGE7XHJcblx0XHRpZiAoIGpzb24uYmxlbmRFcXVhdGlvbkFscGhhICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5ibGVuZEVxdWF0aW9uQWxwaGEgPSBqc29uLmJsZW5kRXF1YXRpb25BbHBoYTtcclxuXHRcdGlmICgganNvbi5ibGVuZENvbG9yICE9PSB1bmRlZmluZWQgJiYgbWF0ZXJpYWwuYmxlbmRDb2xvciAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuYmxlbmRDb2xvci5zZXRIZXgoIGpzb24uYmxlbmRDb2xvciApO1xyXG5cdFx0aWYgKCBqc29uLmJsZW5kQWxwaGEgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmJsZW5kQWxwaGEgPSBqc29uLmJsZW5kQWxwaGE7XHJcblx0XHRpZiAoIGpzb24uc3RlbmNpbFdyaXRlTWFzayAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuc3RlbmNpbFdyaXRlTWFzayA9IGpzb24uc3RlbmNpbFdyaXRlTWFzaztcclxuXHRcdGlmICgganNvbi5zdGVuY2lsRnVuYyAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuc3RlbmNpbEZ1bmMgPSBqc29uLnN0ZW5jaWxGdW5jO1xyXG5cdFx0aWYgKCBqc29uLnN0ZW5jaWxSZWYgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnN0ZW5jaWxSZWYgPSBqc29uLnN0ZW5jaWxSZWY7XHJcblx0XHRpZiAoIGpzb24uc3RlbmNpbEZ1bmNNYXNrICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5zdGVuY2lsRnVuY01hc2sgPSBqc29uLnN0ZW5jaWxGdW5jTWFzaztcclxuXHRcdGlmICgganNvbi5zdGVuY2lsRmFpbCAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuc3RlbmNpbEZhaWwgPSBqc29uLnN0ZW5jaWxGYWlsO1xyXG5cdFx0aWYgKCBqc29uLnN0ZW5jaWxaRmFpbCAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuc3RlbmNpbFpGYWlsID0ganNvbi5zdGVuY2lsWkZhaWw7XHJcblx0XHRpZiAoIGpzb24uc3RlbmNpbFpQYXNzICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5zdGVuY2lsWlBhc3MgPSBqc29uLnN0ZW5jaWxaUGFzcztcclxuXHRcdGlmICgganNvbi5zdGVuY2lsV3JpdGUgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnN0ZW5jaWxXcml0ZSA9IGpzb24uc3RlbmNpbFdyaXRlO1xyXG5cclxuXHRcdGlmICgganNvbi53aXJlZnJhbWUgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLndpcmVmcmFtZSA9IGpzb24ud2lyZWZyYW1lO1xyXG5cdFx0aWYgKCBqc29uLndpcmVmcmFtZUxpbmV3aWR0aCAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwud2lyZWZyYW1lTGluZXdpZHRoID0ganNvbi53aXJlZnJhbWVMaW5ld2lkdGg7XHJcblx0XHRpZiAoIGpzb24ud2lyZWZyYW1lTGluZWNhcCAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwud2lyZWZyYW1lTGluZWNhcCA9IGpzb24ud2lyZWZyYW1lTGluZWNhcDtcclxuXHRcdGlmICgganNvbi53aXJlZnJhbWVMaW5lam9pbiAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwud2lyZWZyYW1lTGluZWpvaW4gPSBqc29uLndpcmVmcmFtZUxpbmVqb2luO1xyXG5cclxuXHRcdGlmICgganNvbi5yb3RhdGlvbiAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwucm90YXRpb24gPSBqc29uLnJvdGF0aW9uO1xyXG5cclxuXHRcdGlmICgganNvbi5saW5ld2lkdGggIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmxpbmV3aWR0aCA9IGpzb24ubGluZXdpZHRoO1xyXG5cdFx0aWYgKCBqc29uLmRhc2hTaXplICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5kYXNoU2l6ZSA9IGpzb24uZGFzaFNpemU7XHJcblx0XHRpZiAoIGpzb24uZ2FwU2l6ZSAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuZ2FwU2l6ZSA9IGpzb24uZ2FwU2l6ZTtcclxuXHRcdGlmICgganNvbi5zY2FsZSAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuc2NhbGUgPSBqc29uLnNjYWxlO1xyXG5cclxuXHRcdGlmICgganNvbi5wb2x5Z29uT2Zmc2V0ICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5wb2x5Z29uT2Zmc2V0ID0ganNvbi5wb2x5Z29uT2Zmc2V0O1xyXG5cdFx0aWYgKCBqc29uLnBvbHlnb25PZmZzZXRGYWN0b3IgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnBvbHlnb25PZmZzZXRGYWN0b3IgPSBqc29uLnBvbHlnb25PZmZzZXRGYWN0b3I7XHJcblx0XHRpZiAoIGpzb24ucG9seWdvbk9mZnNldFVuaXRzICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5wb2x5Z29uT2Zmc2V0VW5pdHMgPSBqc29uLnBvbHlnb25PZmZzZXRVbml0cztcclxuXHJcblx0XHRpZiAoIGpzb24uZGl0aGVyaW5nICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5kaXRoZXJpbmcgPSBqc29uLmRpdGhlcmluZztcclxuXHJcblx0XHRpZiAoIGpzb24uYWxwaGFUb0NvdmVyYWdlICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5hbHBoYVRvQ292ZXJhZ2UgPSBqc29uLmFscGhhVG9Db3ZlcmFnZTtcclxuXHRcdGlmICgganNvbi5wcmVtdWx0aXBsaWVkQWxwaGEgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnByZW11bHRpcGxpZWRBbHBoYSA9IGpzb24ucHJlbXVsdGlwbGllZEFscGhhO1xyXG5cdFx0aWYgKCBqc29uLmZvcmNlU2luZ2xlUGFzcyAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuZm9yY2VTaW5nbGVQYXNzID0ganNvbi5mb3JjZVNpbmdsZVBhc3M7XHJcblxyXG5cdFx0aWYgKCBqc29uLnZpc2libGUgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnZpc2libGUgPSBqc29uLnZpc2libGU7XHJcblxyXG5cdFx0aWYgKCBqc29uLnRvbmVNYXBwZWQgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnRvbmVNYXBwZWQgPSBqc29uLnRvbmVNYXBwZWQ7XHJcblxyXG5cdFx0aWYgKCBqc29uLnVzZXJEYXRhICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC51c2VyRGF0YSA9IGpzb24udXNlckRhdGE7XHJcblxyXG5cdFx0aWYgKCBqc29uLnZlcnRleENvbG9ycyAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0aWYgKCB0eXBlb2YganNvbi52ZXJ0ZXhDb2xvcnMgPT09ICdudW1iZXInICkge1xyXG5cclxuXHRcdFx0XHRtYXRlcmlhbC52ZXJ0ZXhDb2xvcnMgPSAoIGpzb24udmVydGV4Q29sb3JzID4gMCApID8gdHJ1ZSA6IGZhbHNlO1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0bWF0ZXJpYWwudmVydGV4Q29sb3JzID0ganNvbi52ZXJ0ZXhDb2xvcnM7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIFNoYWRlciBNYXRlcmlhbFxyXG5cclxuXHRcdGlmICgganNvbi51bmlmb3JtcyAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0Zm9yICggY29uc3QgbmFtZSBpbiBqc29uLnVuaWZvcm1zICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCB1bmlmb3JtID0ganNvbi51bmlmb3Jtc1sgbmFtZSBdO1xyXG5cclxuXHRcdFx0XHRtYXRlcmlhbC51bmlmb3Jtc1sgbmFtZSBdID0ge307XHJcblxyXG5cdFx0XHRcdHN3aXRjaCAoIHVuaWZvcm0udHlwZSApIHtcclxuXHJcblx0XHRcdFx0XHRjYXNlICd0JzpcclxuXHRcdFx0XHRcdFx0bWF0ZXJpYWwudW5pZm9ybXNbIG5hbWUgXS52YWx1ZSA9IGdldFRleHR1cmUoIHVuaWZvcm0udmFsdWUgKTtcclxuXHRcdFx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRcdFx0Y2FzZSAnYyc6XHJcblx0XHRcdFx0XHRcdG1hdGVyaWFsLnVuaWZvcm1zWyBuYW1lIF0udmFsdWUgPSBuZXcgQ29sb3IoKS5zZXRIZXgoIHVuaWZvcm0udmFsdWUgKTtcclxuXHRcdFx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRcdFx0Y2FzZSAndjInOlxyXG5cdFx0XHRcdFx0XHRtYXRlcmlhbC51bmlmb3Jtc1sgbmFtZSBdLnZhbHVlID0gbmV3IFZlY3RvcjIoKS5mcm9tQXJyYXkoIHVuaWZvcm0udmFsdWUgKTtcclxuXHRcdFx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRcdFx0Y2FzZSAndjMnOlxyXG5cdFx0XHRcdFx0XHRtYXRlcmlhbC51bmlmb3Jtc1sgbmFtZSBdLnZhbHVlID0gbmV3IFZlY3RvcjMoKS5mcm9tQXJyYXkoIHVuaWZvcm0udmFsdWUgKTtcclxuXHRcdFx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRcdFx0Y2FzZSAndjQnOlxyXG5cdFx0XHRcdFx0XHRtYXRlcmlhbC51bmlmb3Jtc1sgbmFtZSBdLnZhbHVlID0gbmV3IFZlY3RvcjQoKS5mcm9tQXJyYXkoIHVuaWZvcm0udmFsdWUgKTtcclxuXHRcdFx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRcdFx0Y2FzZSAnbTMnOlxyXG5cdFx0XHRcdFx0XHRtYXRlcmlhbC51bmlmb3Jtc1sgbmFtZSBdLnZhbHVlID0gbmV3IE1hdHJpeDMoKS5mcm9tQXJyYXkoIHVuaWZvcm0udmFsdWUgKTtcclxuXHRcdFx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRcdFx0Y2FzZSAnbTQnOlxyXG5cdFx0XHRcdFx0XHRtYXRlcmlhbC51bmlmb3Jtc1sgbmFtZSBdLnZhbHVlID0gbmV3IE1hdHJpeDQoKS5mcm9tQXJyYXkoIHVuaWZvcm0udmFsdWUgKTtcclxuXHRcdFx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRcdFx0ZGVmYXVsdDpcclxuXHRcdFx0XHRcdFx0bWF0ZXJpYWwudW5pZm9ybXNbIG5hbWUgXS52YWx1ZSA9IHVuaWZvcm0udmFsdWU7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBqc29uLmRlZmluZXMgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmRlZmluZXMgPSBqc29uLmRlZmluZXM7XHJcblx0XHRpZiAoIGpzb24udmVydGV4U2hhZGVyICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC52ZXJ0ZXhTaGFkZXIgPSBqc29uLnZlcnRleFNoYWRlcjtcclxuXHRcdGlmICgganNvbi5mcmFnbWVudFNoYWRlciAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuZnJhZ21lbnRTaGFkZXIgPSBqc29uLmZyYWdtZW50U2hhZGVyO1xyXG5cdFx0aWYgKCBqc29uLmdsc2xWZXJzaW9uICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5nbHNsVmVyc2lvbiA9IGpzb24uZ2xzbFZlcnNpb247XHJcblxyXG5cdFx0aWYgKCBqc29uLmV4dGVuc2lvbnMgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdGZvciAoIGNvbnN0IGtleSBpbiBqc29uLmV4dGVuc2lvbnMgKSB7XHJcblxyXG5cdFx0XHRcdG1hdGVyaWFsLmV4dGVuc2lvbnNbIGtleSBdID0ganNvbi5leHRlbnNpb25zWyBrZXkgXTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBqc29uLmxpZ2h0cyAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwubGlnaHRzID0ganNvbi5saWdodHM7XHJcblx0XHRpZiAoIGpzb24uY2xpcHBpbmcgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmNsaXBwaW5nID0ganNvbi5jbGlwcGluZztcclxuXHJcblx0XHQvLyBmb3IgUG9pbnRzTWF0ZXJpYWxcclxuXHJcblx0XHRpZiAoIGpzb24uc2l6ZSAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuc2l6ZSA9IGpzb24uc2l6ZTtcclxuXHRcdGlmICgganNvbi5zaXplQXR0ZW51YXRpb24gIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnNpemVBdHRlbnVhdGlvbiA9IGpzb24uc2l6ZUF0dGVudWF0aW9uO1xyXG5cclxuXHRcdC8vIG1hcHNcclxuXHJcblx0XHRpZiAoIGpzb24ubWFwICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5tYXAgPSBnZXRUZXh0dXJlKCBqc29uLm1hcCApO1xyXG5cdFx0aWYgKCBqc29uLm1hdGNhcCAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwubWF0Y2FwID0gZ2V0VGV4dHVyZSgganNvbi5tYXRjYXAgKTtcclxuXHJcblx0XHRpZiAoIGpzb24uYWxwaGFNYXAgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmFscGhhTWFwID0gZ2V0VGV4dHVyZSgganNvbi5hbHBoYU1hcCApO1xyXG5cclxuXHRcdGlmICgganNvbi5idW1wTWFwICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5idW1wTWFwID0gZ2V0VGV4dHVyZSgganNvbi5idW1wTWFwICk7XHJcblx0XHRpZiAoIGpzb24uYnVtcFNjYWxlICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5idW1wU2NhbGUgPSBqc29uLmJ1bXBTY2FsZTtcclxuXHJcblx0XHRpZiAoIGpzb24ubm9ybWFsTWFwICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5ub3JtYWxNYXAgPSBnZXRUZXh0dXJlKCBqc29uLm5vcm1hbE1hcCApO1xyXG5cdFx0aWYgKCBqc29uLm5vcm1hbE1hcFR5cGUgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLm5vcm1hbE1hcFR5cGUgPSBqc29uLm5vcm1hbE1hcFR5cGU7XHJcblx0XHRpZiAoIGpzb24ubm9ybWFsU2NhbGUgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdGxldCBub3JtYWxTY2FsZSA9IGpzb24ubm9ybWFsU2NhbGU7XHJcblxyXG5cdFx0XHRpZiAoIEFycmF5LmlzQXJyYXkoIG5vcm1hbFNjYWxlICkgPT09IGZhbHNlICkge1xyXG5cclxuXHRcdFx0XHQvLyBCbGVuZGVyIGV4cG9ydGVyIHVzZWQgdG8gZXhwb3J0IGEgc2NhbGFyLiBTZWUgIzc0NTlcclxuXHJcblx0XHRcdFx0bm9ybWFsU2NhbGUgPSBbIG5vcm1hbFNjYWxlLCBub3JtYWxTY2FsZSBdO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0bWF0ZXJpYWwubm9ybWFsU2NhbGUgPSBuZXcgVmVjdG9yMigpLmZyb21BcnJheSggbm9ybWFsU2NhbGUgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBqc29uLmRpc3BsYWNlbWVudE1hcCAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuZGlzcGxhY2VtZW50TWFwID0gZ2V0VGV4dHVyZSgganNvbi5kaXNwbGFjZW1lbnRNYXAgKTtcclxuXHRcdGlmICgganNvbi5kaXNwbGFjZW1lbnRTY2FsZSAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuZGlzcGxhY2VtZW50U2NhbGUgPSBqc29uLmRpc3BsYWNlbWVudFNjYWxlO1xyXG5cdFx0aWYgKCBqc29uLmRpc3BsYWNlbWVudEJpYXMgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmRpc3BsYWNlbWVudEJpYXMgPSBqc29uLmRpc3BsYWNlbWVudEJpYXM7XHJcblxyXG5cdFx0aWYgKCBqc29uLnJvdWdobmVzc01hcCAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwucm91Z2huZXNzTWFwID0gZ2V0VGV4dHVyZSgganNvbi5yb3VnaG5lc3NNYXAgKTtcclxuXHRcdGlmICgganNvbi5tZXRhbG5lc3NNYXAgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLm1ldGFsbmVzc01hcCA9IGdldFRleHR1cmUoIGpzb24ubWV0YWxuZXNzTWFwICk7XHJcblxyXG5cdFx0aWYgKCBqc29uLmVtaXNzaXZlTWFwICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5lbWlzc2l2ZU1hcCA9IGdldFRleHR1cmUoIGpzb24uZW1pc3NpdmVNYXAgKTtcclxuXHRcdGlmICgganNvbi5lbWlzc2l2ZUludGVuc2l0eSAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuZW1pc3NpdmVJbnRlbnNpdHkgPSBqc29uLmVtaXNzaXZlSW50ZW5zaXR5O1xyXG5cclxuXHRcdGlmICgganNvbi5zcGVjdWxhck1hcCAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuc3BlY3VsYXJNYXAgPSBnZXRUZXh0dXJlKCBqc29uLnNwZWN1bGFyTWFwICk7XHJcblx0XHRpZiAoIGpzb24uc3BlY3VsYXJJbnRlbnNpdHlNYXAgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnNwZWN1bGFySW50ZW5zaXR5TWFwID0gZ2V0VGV4dHVyZSgganNvbi5zcGVjdWxhckludGVuc2l0eU1hcCApO1xyXG5cdFx0aWYgKCBqc29uLnNwZWN1bGFyQ29sb3JNYXAgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnNwZWN1bGFyQ29sb3JNYXAgPSBnZXRUZXh0dXJlKCBqc29uLnNwZWN1bGFyQ29sb3JNYXAgKTtcclxuXHJcblx0XHRpZiAoIGpzb24uZW52TWFwICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5lbnZNYXAgPSBnZXRUZXh0dXJlKCBqc29uLmVudk1hcCApO1xyXG5cdFx0aWYgKCBqc29uLmVudk1hcEludGVuc2l0eSAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuZW52TWFwSW50ZW5zaXR5ID0ganNvbi5lbnZNYXBJbnRlbnNpdHk7XHJcblxyXG5cdFx0aWYgKCBqc29uLnJlZmxlY3Rpdml0eSAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwucmVmbGVjdGl2aXR5ID0ganNvbi5yZWZsZWN0aXZpdHk7XHJcblx0XHRpZiAoIGpzb24ucmVmcmFjdGlvblJhdGlvICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5yZWZyYWN0aW9uUmF0aW8gPSBqc29uLnJlZnJhY3Rpb25SYXRpbztcclxuXHJcblx0XHRpZiAoIGpzb24ubGlnaHRNYXAgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmxpZ2h0TWFwID0gZ2V0VGV4dHVyZSgganNvbi5saWdodE1hcCApO1xyXG5cdFx0aWYgKCBqc29uLmxpZ2h0TWFwSW50ZW5zaXR5ICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5saWdodE1hcEludGVuc2l0eSA9IGpzb24ubGlnaHRNYXBJbnRlbnNpdHk7XHJcblxyXG5cdFx0aWYgKCBqc29uLmFvTWFwICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5hb01hcCA9IGdldFRleHR1cmUoIGpzb24uYW9NYXAgKTtcclxuXHRcdGlmICgganNvbi5hb01hcEludGVuc2l0eSAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuYW9NYXBJbnRlbnNpdHkgPSBqc29uLmFvTWFwSW50ZW5zaXR5O1xyXG5cclxuXHRcdGlmICgganNvbi5ncmFkaWVudE1hcCAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuZ3JhZGllbnRNYXAgPSBnZXRUZXh0dXJlKCBqc29uLmdyYWRpZW50TWFwICk7XHJcblxyXG5cdFx0aWYgKCBqc29uLmNsZWFyY29hdE1hcCAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuY2xlYXJjb2F0TWFwID0gZ2V0VGV4dHVyZSgganNvbi5jbGVhcmNvYXRNYXAgKTtcclxuXHRcdGlmICgganNvbi5jbGVhcmNvYXRSb3VnaG5lc3NNYXAgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmNsZWFyY29hdFJvdWdobmVzc01hcCA9IGdldFRleHR1cmUoIGpzb24uY2xlYXJjb2F0Um91Z2huZXNzTWFwICk7XHJcblx0XHRpZiAoIGpzb24uY2xlYXJjb2F0Tm9ybWFsTWFwICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5jbGVhcmNvYXROb3JtYWxNYXAgPSBnZXRUZXh0dXJlKCBqc29uLmNsZWFyY29hdE5vcm1hbE1hcCApO1xyXG5cdFx0aWYgKCBqc29uLmNsZWFyY29hdE5vcm1hbFNjYWxlICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5jbGVhcmNvYXROb3JtYWxTY2FsZSA9IG5ldyBWZWN0b3IyKCkuZnJvbUFycmF5KCBqc29uLmNsZWFyY29hdE5vcm1hbFNjYWxlICk7XHJcblxyXG5cdFx0aWYgKCBqc29uLmlyaWRlc2NlbmNlTWFwICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5pcmlkZXNjZW5jZU1hcCA9IGdldFRleHR1cmUoIGpzb24uaXJpZGVzY2VuY2VNYXAgKTtcclxuXHRcdGlmICgganNvbi5pcmlkZXNjZW5jZVRoaWNrbmVzc01hcCAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuaXJpZGVzY2VuY2VUaGlja25lc3NNYXAgPSBnZXRUZXh0dXJlKCBqc29uLmlyaWRlc2NlbmNlVGhpY2tuZXNzTWFwICk7XHJcblxyXG5cdFx0aWYgKCBqc29uLnRyYW5zbWlzc2lvbk1hcCAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwudHJhbnNtaXNzaW9uTWFwID0gZ2V0VGV4dHVyZSgganNvbi50cmFuc21pc3Npb25NYXAgKTtcclxuXHRcdGlmICgganNvbi50aGlja25lc3NNYXAgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnRoaWNrbmVzc01hcCA9IGdldFRleHR1cmUoIGpzb24udGhpY2tuZXNzTWFwICk7XHJcblxyXG5cdFx0aWYgKCBqc29uLmFuaXNvdHJvcHlNYXAgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmFuaXNvdHJvcHlNYXAgPSBnZXRUZXh0dXJlKCBqc29uLmFuaXNvdHJvcHlNYXAgKTtcclxuXHJcblx0XHRpZiAoIGpzb24uc2hlZW5Db2xvck1hcCAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuc2hlZW5Db2xvck1hcCA9IGdldFRleHR1cmUoIGpzb24uc2hlZW5Db2xvck1hcCApO1xyXG5cdFx0aWYgKCBqc29uLnNoZWVuUm91Z2huZXNzTWFwICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5zaGVlblJvdWdobmVzc01hcCA9IGdldFRleHR1cmUoIGpzb24uc2hlZW5Sb3VnaG5lc3NNYXAgKTtcclxuXHJcblx0XHRyZXR1cm4gbWF0ZXJpYWw7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0VGV4dHVyZXMoIHZhbHVlICkge1xyXG5cclxuXHRcdHRoaXMudGV4dHVyZXMgPSB2YWx1ZTtcclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHN0YXRpYyBjcmVhdGVNYXRlcmlhbEZyb21UeXBlKCB0eXBlICkge1xyXG5cclxuXHRcdGNvbnN0IG1hdGVyaWFsTGliID0ge1xyXG5cdFx0XHRTaGFkb3dNYXRlcmlhbCxcclxuXHRcdFx0U3ByaXRlTWF0ZXJpYWwsXHJcblx0XHRcdFJhd1NoYWRlck1hdGVyaWFsLFxyXG5cdFx0XHRTaGFkZXJNYXRlcmlhbCxcclxuXHRcdFx0UG9pbnRzTWF0ZXJpYWwsXHJcblx0XHRcdE1lc2hQaHlzaWNhbE1hdGVyaWFsLFxyXG5cdFx0XHRNZXNoU3RhbmRhcmRNYXRlcmlhbCxcclxuXHRcdFx0TWVzaFBob25nTWF0ZXJpYWwsXHJcblx0XHRcdE1lc2hUb29uTWF0ZXJpYWwsXHJcblx0XHRcdE1lc2hOb3JtYWxNYXRlcmlhbCxcclxuXHRcdFx0TWVzaExhbWJlcnRNYXRlcmlhbCxcclxuXHRcdFx0TWVzaERlcHRoTWF0ZXJpYWwsXHJcblx0XHRcdE1lc2hEaXN0YW5jZU1hdGVyaWFsLFxyXG5cdFx0XHRNZXNoQmFzaWNNYXRlcmlhbCxcclxuXHRcdFx0TWVzaE1hdGNhcE1hdGVyaWFsLFxyXG5cdFx0XHRMaW5lRGFzaGVkTWF0ZXJpYWwsXHJcblx0XHRcdExpbmVCYXNpY01hdGVyaWFsLFxyXG5cdFx0XHRNYXRlcmlhbFxyXG5cdFx0fTtcclxuXHJcblx0XHRyZXR1cm4gbmV3IG1hdGVyaWFsTGliWyB0eXBlIF0oKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgTWF0ZXJpYWxMb2FkZXIgfTtcclxuIiwiY2xhc3MgTG9hZGVyVXRpbHMge1xyXG5cclxuXHRzdGF0aWMgZGVjb2RlVGV4dCggYXJyYXkgKSB7XHJcblxyXG5cdFx0aWYgKCB0eXBlb2YgVGV4dERlY29kZXIgIT09ICd1bmRlZmluZWQnICkge1xyXG5cclxuXHRcdFx0cmV0dXJuIG5ldyBUZXh0RGVjb2RlcigpLmRlY29kZSggYXJyYXkgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gQXZvaWQgdGhlIFN0cmluZy5mcm9tQ2hhckNvZGUuYXBwbHkobnVsbCwgYXJyYXkpIHNob3J0Y3V0LCB3aGljaFxyXG5cdFx0Ly8gdGhyb3dzIGEgXCJtYXhpbXVtIGNhbGwgc3RhY2sgc2l6ZSBleGNlZWRlZFwiIGVycm9yIGZvciBsYXJnZSBhcnJheXMuXHJcblxyXG5cdFx0bGV0IHMgPSAnJztcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gYXJyYXkubGVuZ3RoOyBpIDwgaWw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHQvLyBJbXBsaWNpdGx5IGFzc3VtZXMgbGl0dGxlLWVuZGlhbi5cclxuXHRcdFx0cyArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKCBhcnJheVsgaSBdICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRyeSB7XHJcblxyXG5cdFx0XHQvLyBtZXJnZXMgbXVsdGktYnl0ZSB1dGYtOCBjaGFyYWN0ZXJzLlxyXG5cclxuXHRcdFx0cmV0dXJuIGRlY29kZVVSSUNvbXBvbmVudCggZXNjYXBlKCBzICkgKTtcclxuXHJcblx0XHR9IGNhdGNoICggZSApIHsgLy8gc2VlICMxNjM1OFxyXG5cclxuXHRcdFx0cmV0dXJuIHM7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdHN0YXRpYyBleHRyYWN0VXJsQmFzZSggdXJsICkge1xyXG5cclxuXHRcdGNvbnN0IGluZGV4ID0gdXJsLmxhc3RJbmRleE9mKCAnLycgKTtcclxuXHJcblx0XHRpZiAoIGluZGV4ID09PSAtIDEgKSByZXR1cm4gJy4vJztcclxuXHJcblx0XHRyZXR1cm4gdXJsLnNsaWNlKCAwLCBpbmRleCArIDEgKTtcclxuXHJcblx0fVxyXG5cclxuXHRzdGF0aWMgcmVzb2x2ZVVSTCggdXJsLCBwYXRoICkge1xyXG5cclxuXHRcdC8vIEludmFsaWQgVVJMXHJcblx0XHRpZiAoIHR5cGVvZiB1cmwgIT09ICdzdHJpbmcnIHx8IHVybCA9PT0gJycgKSByZXR1cm4gJyc7XHJcblxyXG5cdFx0Ly8gSG9zdCBSZWxhdGl2ZSBVUkxcclxuXHRcdGlmICggL15odHRwcz86XFwvXFwvL2kudGVzdCggcGF0aCApICYmIC9eXFwvLy50ZXN0KCB1cmwgKSApIHtcclxuXHJcblx0XHRcdHBhdGggPSBwYXRoLnJlcGxhY2UoIC8oXmh0dHBzPzpcXC9cXC9bXlxcL10rKS4qL2ksICckMScgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gQWJzb2x1dGUgVVJMIGh0dHA6Ly8saHR0cHM6Ly8sLy9cclxuXHRcdGlmICggL14oaHR0cHM/Oik/XFwvXFwvL2kudGVzdCggdXJsICkgKSByZXR1cm4gdXJsO1xyXG5cclxuXHRcdC8vIERhdGEgVVJJXHJcblx0XHRpZiAoIC9eZGF0YTouKiwuKiQvaS50ZXN0KCB1cmwgKSApIHJldHVybiB1cmw7XHJcblxyXG5cdFx0Ly8gQmxvYiBVUkxcclxuXHRcdGlmICggL15ibG9iOi4qJC9pLnRlc3QoIHVybCApICkgcmV0dXJuIHVybDtcclxuXHJcblx0XHQvLyBSZWxhdGl2ZSBVUkxcclxuXHRcdHJldHVybiBwYXRoICsgdXJsO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBMb2FkZXJVdGlscyB9O1xyXG4iLCJpbXBvcnQgeyBCdWZmZXJHZW9tZXRyeSB9IGZyb20gJy4vQnVmZmVyR2VvbWV0cnkuanMnO1xyXG5cclxuY2xhc3MgSW5zdGFuY2VkQnVmZmVyR2VvbWV0cnkgZXh0ZW5kcyBCdWZmZXJHZW9tZXRyeSB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCkge1xyXG5cclxuXHRcdHN1cGVyKCk7XHJcblxyXG5cdFx0dGhpcy5pc0luc3RhbmNlZEJ1ZmZlckdlb21ldHJ5ID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSAnSW5zdGFuY2VkQnVmZmVyR2VvbWV0cnknO1xyXG5cdFx0dGhpcy5pbnN0YW5jZUNvdW50ID0gSW5maW5pdHk7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xyXG5cclxuXHRcdHRoaXMuaW5zdGFuY2VDb3VudCA9IHNvdXJjZS5pbnN0YW5jZUNvdW50O1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHRvSlNPTigpIHtcclxuXHJcblx0XHRjb25zdCBkYXRhID0gc3VwZXIudG9KU09OKCk7XHJcblxyXG5cdFx0ZGF0YS5pbnN0YW5jZUNvdW50ID0gdGhpcy5pbnN0YW5jZUNvdW50O1xyXG5cclxuXHRcdGRhdGEuaXNJbnN0YW5jZWRCdWZmZXJHZW9tZXRyeSA9IHRydWU7XHJcblxyXG5cdFx0cmV0dXJuIGRhdGE7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IEluc3RhbmNlZEJ1ZmZlckdlb21ldHJ5IH07XHJcbiIsImltcG9ydCB7IFNwaGVyZSB9IGZyb20gJy4uL21hdGgvU3BoZXJlLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yMyB9IGZyb20gJy4uL21hdGgvVmVjdG9yMy5qcyc7XHJcbmltcG9ydCB7IEJ1ZmZlckF0dHJpYnV0ZSB9IGZyb20gJy4uL2NvcmUvQnVmZmVyQXR0cmlidXRlLmpzJztcclxuaW1wb3J0IHsgQnVmZmVyR2VvbWV0cnkgfSBmcm9tICcuLi9jb3JlL0J1ZmZlckdlb21ldHJ5LmpzJztcclxuaW1wb3J0IHsgRmlsZUxvYWRlciB9IGZyb20gJy4vRmlsZUxvYWRlci5qcyc7XHJcbmltcG9ydCB7IExvYWRlciB9IGZyb20gJy4vTG9hZGVyLmpzJztcclxuaW1wb3J0IHsgSW5zdGFuY2VkQnVmZmVyR2VvbWV0cnkgfSBmcm9tICcuLi9jb3JlL0luc3RhbmNlZEJ1ZmZlckdlb21ldHJ5LmpzJztcclxuaW1wb3J0IHsgSW5zdGFuY2VkQnVmZmVyQXR0cmlidXRlIH0gZnJvbSAnLi4vY29yZS9JbnN0YW5jZWRCdWZmZXJBdHRyaWJ1dGUuanMnO1xyXG5pbXBvcnQgeyBJbnRlcmxlYXZlZEJ1ZmZlckF0dHJpYnV0ZSB9IGZyb20gJy4uL2NvcmUvSW50ZXJsZWF2ZWRCdWZmZXJBdHRyaWJ1dGUuanMnO1xyXG5pbXBvcnQgeyBJbnRlcmxlYXZlZEJ1ZmZlciB9IGZyb20gJy4uL2NvcmUvSW50ZXJsZWF2ZWRCdWZmZXIuanMnO1xyXG5pbXBvcnQgeyBnZXRUeXBlZEFycmF5IH0gZnJvbSAnLi4vdXRpbHMuanMnO1xyXG5cclxuY2xhc3MgQnVmZmVyR2VvbWV0cnlMb2FkZXIgZXh0ZW5kcyBMb2FkZXIge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggbWFuYWdlciApIHtcclxuXHJcblx0XHRzdXBlciggbWFuYWdlciApO1xyXG5cclxuXHR9XHJcblxyXG5cdGxvYWQoIHVybCwgb25Mb2FkLCBvblByb2dyZXNzLCBvbkVycm9yICkge1xyXG5cclxuXHRcdGNvbnN0IHNjb3BlID0gdGhpcztcclxuXHJcblx0XHRjb25zdCBsb2FkZXIgPSBuZXcgRmlsZUxvYWRlciggc2NvcGUubWFuYWdlciApO1xyXG5cdFx0bG9hZGVyLnNldFBhdGgoIHNjb3BlLnBhdGggKTtcclxuXHRcdGxvYWRlci5zZXRSZXF1ZXN0SGVhZGVyKCBzY29wZS5yZXF1ZXN0SGVhZGVyICk7XHJcblx0XHRsb2FkZXIuc2V0V2l0aENyZWRlbnRpYWxzKCBzY29wZS53aXRoQ3JlZGVudGlhbHMgKTtcclxuXHRcdGxvYWRlci5sb2FkKCB1cmwsIGZ1bmN0aW9uICggdGV4dCApIHtcclxuXHJcblx0XHRcdHRyeSB7XHJcblxyXG5cdFx0XHRcdG9uTG9hZCggc2NvcGUucGFyc2UoIEpTT04ucGFyc2UoIHRleHQgKSApICk7XHJcblxyXG5cdFx0XHR9IGNhdGNoICggZSApIHtcclxuXHJcblx0XHRcdFx0aWYgKCBvbkVycm9yICkge1xyXG5cclxuXHRcdFx0XHRcdG9uRXJyb3IoIGUgKTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRjb25zb2xlLmVycm9yKCBlICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0c2NvcGUubWFuYWdlci5pdGVtRXJyb3IoIHVybCApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH0sIG9uUHJvZ3Jlc3MsIG9uRXJyb3IgKTtcclxuXHJcblx0fVxyXG5cclxuXHRwYXJzZSgganNvbiApIHtcclxuXHJcblx0XHRjb25zdCBpbnRlcmxlYXZlZEJ1ZmZlck1hcCA9IHt9O1xyXG5cdFx0Y29uc3QgYXJyYXlCdWZmZXJNYXAgPSB7fTtcclxuXHJcblx0XHRmdW5jdGlvbiBnZXRJbnRlcmxlYXZlZEJ1ZmZlcigganNvbiwgdXVpZCApIHtcclxuXHJcblx0XHRcdGlmICggaW50ZXJsZWF2ZWRCdWZmZXJNYXBbIHV1aWQgXSAhPT0gdW5kZWZpbmVkICkgcmV0dXJuIGludGVybGVhdmVkQnVmZmVyTWFwWyB1dWlkIF07XHJcblxyXG5cdFx0XHRjb25zdCBpbnRlcmxlYXZlZEJ1ZmZlcnMgPSBqc29uLmludGVybGVhdmVkQnVmZmVycztcclxuXHRcdFx0Y29uc3QgaW50ZXJsZWF2ZWRCdWZmZXIgPSBpbnRlcmxlYXZlZEJ1ZmZlcnNbIHV1aWQgXTtcclxuXHJcblx0XHRcdGNvbnN0IGJ1ZmZlciA9IGdldEFycmF5QnVmZmVyKCBqc29uLCBpbnRlcmxlYXZlZEJ1ZmZlci5idWZmZXIgKTtcclxuXHJcblx0XHRcdGNvbnN0IGFycmF5ID0gZ2V0VHlwZWRBcnJheSggaW50ZXJsZWF2ZWRCdWZmZXIudHlwZSwgYnVmZmVyICk7XHJcblx0XHRcdGNvbnN0IGliID0gbmV3IEludGVybGVhdmVkQnVmZmVyKCBhcnJheSwgaW50ZXJsZWF2ZWRCdWZmZXIuc3RyaWRlICk7XHJcblx0XHRcdGliLnV1aWQgPSBpbnRlcmxlYXZlZEJ1ZmZlci51dWlkO1xyXG5cclxuXHRcdFx0aW50ZXJsZWF2ZWRCdWZmZXJNYXBbIHV1aWQgXSA9IGliO1xyXG5cclxuXHRcdFx0cmV0dXJuIGliO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRmdW5jdGlvbiBnZXRBcnJheUJ1ZmZlcigganNvbiwgdXVpZCApIHtcclxuXHJcblx0XHRcdGlmICggYXJyYXlCdWZmZXJNYXBbIHV1aWQgXSAhPT0gdW5kZWZpbmVkICkgcmV0dXJuIGFycmF5QnVmZmVyTWFwWyB1dWlkIF07XHJcblxyXG5cdFx0XHRjb25zdCBhcnJheUJ1ZmZlcnMgPSBqc29uLmFycmF5QnVmZmVycztcclxuXHRcdFx0Y29uc3QgYXJyYXlCdWZmZXIgPSBhcnJheUJ1ZmZlcnNbIHV1aWQgXTtcclxuXHJcblx0XHRcdGNvbnN0IGFiID0gbmV3IFVpbnQzMkFycmF5KCBhcnJheUJ1ZmZlciApLmJ1ZmZlcjtcclxuXHJcblx0XHRcdGFycmF5QnVmZmVyTWFwWyB1dWlkIF0gPSBhYjtcclxuXHJcblx0XHRcdHJldHVybiBhYjtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Y29uc3QgZ2VvbWV0cnkgPSBqc29uLmlzSW5zdGFuY2VkQnVmZmVyR2VvbWV0cnkgPyBuZXcgSW5zdGFuY2VkQnVmZmVyR2VvbWV0cnkoKSA6IG5ldyBCdWZmZXJHZW9tZXRyeSgpO1xyXG5cclxuXHRcdGNvbnN0IGluZGV4ID0ganNvbi5kYXRhLmluZGV4O1xyXG5cclxuXHRcdGlmICggaW5kZXggIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdGNvbnN0IHR5cGVkQXJyYXkgPSBnZXRUeXBlZEFycmF5KCBpbmRleC50eXBlLCBpbmRleC5hcnJheSApO1xyXG5cdFx0XHRnZW9tZXRyeS5zZXRJbmRleCggbmV3IEJ1ZmZlckF0dHJpYnV0ZSggdHlwZWRBcnJheSwgMSApICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGNvbnN0IGF0dHJpYnV0ZXMgPSBqc29uLmRhdGEuYXR0cmlidXRlcztcclxuXHJcblx0XHRmb3IgKCBjb25zdCBrZXkgaW4gYXR0cmlidXRlcyApIHtcclxuXHJcblx0XHRcdGNvbnN0IGF0dHJpYnV0ZSA9IGF0dHJpYnV0ZXNbIGtleSBdO1xyXG5cdFx0XHRsZXQgYnVmZmVyQXR0cmlidXRlO1xyXG5cclxuXHRcdFx0aWYgKCBhdHRyaWJ1dGUuaXNJbnRlcmxlYXZlZEJ1ZmZlckF0dHJpYnV0ZSApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgaW50ZXJsZWF2ZWRCdWZmZXIgPSBnZXRJbnRlcmxlYXZlZEJ1ZmZlcigganNvbi5kYXRhLCBhdHRyaWJ1dGUuZGF0YSApO1xyXG5cdFx0XHRcdGJ1ZmZlckF0dHJpYnV0ZSA9IG5ldyBJbnRlcmxlYXZlZEJ1ZmZlckF0dHJpYnV0ZSggaW50ZXJsZWF2ZWRCdWZmZXIsIGF0dHJpYnV0ZS5pdGVtU2l6ZSwgYXR0cmlidXRlLm9mZnNldCwgYXR0cmlidXRlLm5vcm1hbGl6ZWQgKTtcclxuXHJcblx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IHR5cGVkQXJyYXkgPSBnZXRUeXBlZEFycmF5KCBhdHRyaWJ1dGUudHlwZSwgYXR0cmlidXRlLmFycmF5ICk7XHJcblx0XHRcdFx0Y29uc3QgYnVmZmVyQXR0cmlidXRlQ29uc3RyID0gYXR0cmlidXRlLmlzSW5zdGFuY2VkQnVmZmVyQXR0cmlidXRlID8gSW5zdGFuY2VkQnVmZmVyQXR0cmlidXRlIDogQnVmZmVyQXR0cmlidXRlO1xyXG5cdFx0XHRcdGJ1ZmZlckF0dHJpYnV0ZSA9IG5ldyBidWZmZXJBdHRyaWJ1dGVDb25zdHIoIHR5cGVkQXJyYXksIGF0dHJpYnV0ZS5pdGVtU2l6ZSwgYXR0cmlidXRlLm5vcm1hbGl6ZWQgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGlmICggYXR0cmlidXRlLm5hbWUgIT09IHVuZGVmaW5lZCApIGJ1ZmZlckF0dHJpYnV0ZS5uYW1lID0gYXR0cmlidXRlLm5hbWU7XHJcblx0XHRcdGlmICggYXR0cmlidXRlLnVzYWdlICE9PSB1bmRlZmluZWQgKSBidWZmZXJBdHRyaWJ1dGUuc2V0VXNhZ2UoIGF0dHJpYnV0ZS51c2FnZSApO1xyXG5cclxuXHRcdFx0Z2VvbWV0cnkuc2V0QXR0cmlidXRlKCBrZXksIGJ1ZmZlckF0dHJpYnV0ZSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCBtb3JwaEF0dHJpYnV0ZXMgPSBqc29uLmRhdGEubW9ycGhBdHRyaWJ1dGVzO1xyXG5cclxuXHRcdGlmICggbW9ycGhBdHRyaWJ1dGVzICkge1xyXG5cclxuXHRcdFx0Zm9yICggY29uc3Qga2V5IGluIG1vcnBoQXR0cmlidXRlcyApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgYXR0cmlidXRlQXJyYXkgPSBtb3JwaEF0dHJpYnV0ZXNbIGtleSBdO1xyXG5cclxuXHRcdFx0XHRjb25zdCBhcnJheSA9IFtdO1xyXG5cclxuXHRcdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gYXR0cmlidXRlQXJyYXkubGVuZ3RoOyBpIDwgaWw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgYXR0cmlidXRlID0gYXR0cmlidXRlQXJyYXlbIGkgXTtcclxuXHRcdFx0XHRcdGxldCBidWZmZXJBdHRyaWJ1dGU7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCBhdHRyaWJ1dGUuaXNJbnRlcmxlYXZlZEJ1ZmZlckF0dHJpYnV0ZSApIHtcclxuXHJcblx0XHRcdFx0XHRcdGNvbnN0IGludGVybGVhdmVkQnVmZmVyID0gZ2V0SW50ZXJsZWF2ZWRCdWZmZXIoIGpzb24uZGF0YSwgYXR0cmlidXRlLmRhdGEgKTtcclxuXHRcdFx0XHRcdFx0YnVmZmVyQXR0cmlidXRlID0gbmV3IEludGVybGVhdmVkQnVmZmVyQXR0cmlidXRlKCBpbnRlcmxlYXZlZEJ1ZmZlciwgYXR0cmlidXRlLml0ZW1TaXplLCBhdHRyaWJ1dGUub2Zmc2V0LCBhdHRyaWJ1dGUubm9ybWFsaXplZCApO1xyXG5cclxuXHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHRjb25zdCB0eXBlZEFycmF5ID0gZ2V0VHlwZWRBcnJheSggYXR0cmlidXRlLnR5cGUsIGF0dHJpYnV0ZS5hcnJheSApO1xyXG5cdFx0XHRcdFx0XHRidWZmZXJBdHRyaWJ1dGUgPSBuZXcgQnVmZmVyQXR0cmlidXRlKCB0eXBlZEFycmF5LCBhdHRyaWJ1dGUuaXRlbVNpemUsIGF0dHJpYnV0ZS5ub3JtYWxpemVkICk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdGlmICggYXR0cmlidXRlLm5hbWUgIT09IHVuZGVmaW5lZCApIGJ1ZmZlckF0dHJpYnV0ZS5uYW1lID0gYXR0cmlidXRlLm5hbWU7XHJcblx0XHRcdFx0XHRhcnJheS5wdXNoKCBidWZmZXJBdHRyaWJ1dGUgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRnZW9tZXRyeS5tb3JwaEF0dHJpYnV0ZXNbIGtleSBdID0gYXJyYXk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGNvbnN0IG1vcnBoVGFyZ2V0c1JlbGF0aXZlID0ganNvbi5kYXRhLm1vcnBoVGFyZ2V0c1JlbGF0aXZlO1xyXG5cclxuXHRcdGlmICggbW9ycGhUYXJnZXRzUmVsYXRpdmUgKSB7XHJcblxyXG5cdFx0XHRnZW9tZXRyeS5tb3JwaFRhcmdldHNSZWxhdGl2ZSA9IHRydWU7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGNvbnN0IGdyb3VwcyA9IGpzb24uZGF0YS5ncm91cHMgfHwganNvbi5kYXRhLmRyYXdjYWxscyB8fCBqc29uLmRhdGEub2Zmc2V0cztcclxuXHJcblx0XHRpZiAoIGdyb3VwcyAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGkgPSAwLCBuID0gZ3JvdXBzLmxlbmd0aDsgaSAhPT0gbjsgKysgaSApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgZ3JvdXAgPSBncm91cHNbIGkgXTtcclxuXHJcblx0XHRcdFx0Z2VvbWV0cnkuYWRkR3JvdXAoIGdyb3VwLnN0YXJ0LCBncm91cC5jb3VudCwgZ3JvdXAubWF0ZXJpYWxJbmRleCApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCBib3VuZGluZ1NwaGVyZSA9IGpzb24uZGF0YS5ib3VuZGluZ1NwaGVyZTtcclxuXHJcblx0XHRpZiAoIGJvdW5kaW5nU3BoZXJlICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBjZW50ZXIgPSBuZXcgVmVjdG9yMygpO1xyXG5cclxuXHRcdFx0aWYgKCBib3VuZGluZ1NwaGVyZS5jZW50ZXIgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0Y2VudGVyLmZyb21BcnJheSggYm91bmRpbmdTcGhlcmUuY2VudGVyICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRnZW9tZXRyeS5ib3VuZGluZ1NwaGVyZSA9IG5ldyBTcGhlcmUoIGNlbnRlciwgYm91bmRpbmdTcGhlcmUucmFkaXVzICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICgganNvbi5uYW1lICkgZ2VvbWV0cnkubmFtZSA9IGpzb24ubmFtZTtcclxuXHRcdGlmICgganNvbi51c2VyRGF0YSApIGdlb21ldHJ5LnVzZXJEYXRhID0ganNvbi51c2VyRGF0YTtcclxuXHJcblx0XHRyZXR1cm4gZ2VvbWV0cnk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IEJ1ZmZlckdlb21ldHJ5TG9hZGVyIH07XHJcbiIsImltcG9ydCB7XHJcblx0VVZNYXBwaW5nLFxyXG5cdEN1YmVSZWZsZWN0aW9uTWFwcGluZyxcclxuXHRDdWJlUmVmcmFjdGlvbk1hcHBpbmcsXHJcblx0RXF1aXJlY3Rhbmd1bGFyUmVmbGVjdGlvbk1hcHBpbmcsXHJcblx0RXF1aXJlY3Rhbmd1bGFyUmVmcmFjdGlvbk1hcHBpbmcsXHJcblx0Q3ViZVVWUmVmbGVjdGlvbk1hcHBpbmcsXHJcblxyXG5cdFJlcGVhdFdyYXBwaW5nLFxyXG5cdENsYW1wVG9FZGdlV3JhcHBpbmcsXHJcblx0TWlycm9yZWRSZXBlYXRXcmFwcGluZyxcclxuXHJcblx0TmVhcmVzdEZpbHRlcixcclxuXHROZWFyZXN0TWlwbWFwTmVhcmVzdEZpbHRlcixcclxuXHROZWFyZXN0TWlwbWFwTGluZWFyRmlsdGVyLFxyXG5cdExpbmVhckZpbHRlcixcclxuXHRMaW5lYXJNaXBtYXBOZWFyZXN0RmlsdGVyLFxyXG5cdExpbmVhck1pcG1hcExpbmVhckZpbHRlclxyXG59IGZyb20gJy4uL2NvbnN0YW50cy5qcyc7XHJcbmltcG9ydCB7IEluc3RhbmNlZEJ1ZmZlckF0dHJpYnV0ZSB9IGZyb20gJy4uL2NvcmUvSW5zdGFuY2VkQnVmZmVyQXR0cmlidXRlLmpzJztcclxuaW1wb3J0IHsgQ29sb3IgfSBmcm9tICcuLi9tYXRoL0NvbG9yLmpzJztcclxuaW1wb3J0IHsgT2JqZWN0M0QgfSBmcm9tICcuLi9jb3JlL09iamVjdDNELmpzJztcclxuaW1wb3J0IHsgR3JvdXAgfSBmcm9tICcuLi9vYmplY3RzL0dyb3VwLmpzJztcclxuaW1wb3J0IHsgSW5zdGFuY2VkTWVzaCB9IGZyb20gJy4uL29iamVjdHMvSW5zdGFuY2VkTWVzaC5qcyc7XHJcbmltcG9ydCB7IEJhdGNoZWRNZXNoIH0gZnJvbSAnLi4vb2JqZWN0cy9CYXRjaGVkTWVzaC5qcyc7XHJcbmltcG9ydCB7IFNwcml0ZSB9IGZyb20gJy4uL29iamVjdHMvU3ByaXRlLmpzJztcclxuaW1wb3J0IHsgUG9pbnRzIH0gZnJvbSAnLi4vb2JqZWN0cy9Qb2ludHMuanMnO1xyXG5pbXBvcnQgeyBMaW5lIH0gZnJvbSAnLi4vb2JqZWN0cy9MaW5lLmpzJztcclxuaW1wb3J0IHsgTGluZUxvb3AgfSBmcm9tICcuLi9vYmplY3RzL0xpbmVMb29wLmpzJztcclxuaW1wb3J0IHsgTGluZVNlZ21lbnRzIH0gZnJvbSAnLi4vb2JqZWN0cy9MaW5lU2VnbWVudHMuanMnO1xyXG5pbXBvcnQgeyBMT0QgfSBmcm9tICcuLi9vYmplY3RzL0xPRC5qcyc7XHJcbmltcG9ydCB7IE1lc2ggfSBmcm9tICcuLi9vYmplY3RzL01lc2guanMnO1xyXG5pbXBvcnQgeyBTa2lubmVkTWVzaCB9IGZyb20gJy4uL29iamVjdHMvU2tpbm5lZE1lc2guanMnO1xyXG5pbXBvcnQgeyBCb25lIH0gZnJvbSAnLi4vb2JqZWN0cy9Cb25lLmpzJztcclxuaW1wb3J0IHsgU2tlbGV0b24gfSBmcm9tICcuLi9vYmplY3RzL1NrZWxldG9uLmpzJztcclxuaW1wb3J0IHsgU2hhcGUgfSBmcm9tICcuLi9leHRyYXMvY29yZS9TaGFwZS5qcyc7XHJcbmltcG9ydCB7IEZvZyB9IGZyb20gJy4uL3NjZW5lcy9Gb2cuanMnO1xyXG5pbXBvcnQgeyBGb2dFeHAyIH0gZnJvbSAnLi4vc2NlbmVzL0ZvZ0V4cDIuanMnO1xyXG5pbXBvcnQgeyBIZW1pc3BoZXJlTGlnaHQgfSBmcm9tICcuLi9saWdodHMvSGVtaXNwaGVyZUxpZ2h0LmpzJztcclxuaW1wb3J0IHsgU3BvdExpZ2h0IH0gZnJvbSAnLi4vbGlnaHRzL1Nwb3RMaWdodC5qcyc7XHJcbmltcG9ydCB7IFBvaW50TGlnaHQgfSBmcm9tICcuLi9saWdodHMvUG9pbnRMaWdodC5qcyc7XHJcbmltcG9ydCB7IERpcmVjdGlvbmFsTGlnaHQgfSBmcm9tICcuLi9saWdodHMvRGlyZWN0aW9uYWxMaWdodC5qcyc7XHJcbmltcG9ydCB7IEFtYmllbnRMaWdodCB9IGZyb20gJy4uL2xpZ2h0cy9BbWJpZW50TGlnaHQuanMnO1xyXG5pbXBvcnQgeyBSZWN0QXJlYUxpZ2h0IH0gZnJvbSAnLi4vbGlnaHRzL1JlY3RBcmVhTGlnaHQuanMnO1xyXG5pbXBvcnQgeyBMaWdodFByb2JlIH0gZnJvbSAnLi4vbGlnaHRzL0xpZ2h0UHJvYmUuanMnO1xyXG5pbXBvcnQgeyBPcnRob2dyYXBoaWNDYW1lcmEgfSBmcm9tICcuLi9jYW1lcmFzL09ydGhvZ3JhcGhpY0NhbWVyYS5qcyc7XHJcbmltcG9ydCB7IFBlcnNwZWN0aXZlQ2FtZXJhIH0gZnJvbSAnLi4vY2FtZXJhcy9QZXJzcGVjdGl2ZUNhbWVyYS5qcyc7XHJcbmltcG9ydCB7IFNjZW5lIH0gZnJvbSAnLi4vc2NlbmVzL1NjZW5lLmpzJztcclxuaW1wb3J0IHsgQ3ViZVRleHR1cmUgfSBmcm9tICcuLi90ZXh0dXJlcy9DdWJlVGV4dHVyZS5qcyc7XHJcbmltcG9ydCB7IFRleHR1cmUgfSBmcm9tICcuLi90ZXh0dXJlcy9UZXh0dXJlLmpzJztcclxuaW1wb3J0IHsgU291cmNlIH0gZnJvbSAnLi4vdGV4dHVyZXMvU291cmNlLmpzJztcclxuaW1wb3J0IHsgRGF0YVRleHR1cmUgfSBmcm9tICcuLi90ZXh0dXJlcy9EYXRhVGV4dHVyZS5qcyc7XHJcbmltcG9ydCB7IEltYWdlTG9hZGVyIH0gZnJvbSAnLi9JbWFnZUxvYWRlci5qcyc7XHJcbmltcG9ydCB7IExvYWRpbmdNYW5hZ2VyIH0gZnJvbSAnLi9Mb2FkaW5nTWFuYWdlci5qcyc7XHJcbmltcG9ydCB7IEFuaW1hdGlvbkNsaXAgfSBmcm9tICcuLi9hbmltYXRpb24vQW5pbWF0aW9uQ2xpcC5qcyc7XHJcbmltcG9ydCB7IE1hdGVyaWFsTG9hZGVyIH0gZnJvbSAnLi9NYXRlcmlhbExvYWRlci5qcyc7XHJcbmltcG9ydCB7IExvYWRlclV0aWxzIH0gZnJvbSAnLi9Mb2FkZXJVdGlscy5qcyc7XHJcbmltcG9ydCB7IEJ1ZmZlckdlb21ldHJ5TG9hZGVyIH0gZnJvbSAnLi9CdWZmZXJHZW9tZXRyeUxvYWRlci5qcyc7XHJcbmltcG9ydCB7IExvYWRlciB9IGZyb20gJy4vTG9hZGVyLmpzJztcclxuaW1wb3J0IHsgRmlsZUxvYWRlciB9IGZyb20gJy4vRmlsZUxvYWRlci5qcyc7XHJcbmltcG9ydCAqIGFzIEdlb21ldHJpZXMgZnJvbSAnLi4vZ2VvbWV0cmllcy9HZW9tZXRyaWVzLmpzJztcclxuaW1wb3J0IHsgZ2V0VHlwZWRBcnJheSB9IGZyb20gJy4uL3V0aWxzLmpzJztcclxuaW1wb3J0IHsgQm94MyB9IGZyb20gJy4uL21hdGgvQm94My5qcyc7XHJcbmltcG9ydCB7IFNwaGVyZSB9IGZyb20gJy4uL21hdGgvU3BoZXJlLmpzJztcclxuXHJcbmNsYXNzIE9iamVjdExvYWRlciBleHRlbmRzIExvYWRlciB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBtYW5hZ2VyICkge1xyXG5cclxuXHRcdHN1cGVyKCBtYW5hZ2VyICk7XHJcblxyXG5cdH1cclxuXHJcblx0bG9hZCggdXJsLCBvbkxvYWQsIG9uUHJvZ3Jlc3MsIG9uRXJyb3IgKSB7XHJcblxyXG5cdFx0Y29uc3Qgc2NvcGUgPSB0aGlzO1xyXG5cclxuXHRcdGNvbnN0IHBhdGggPSAoIHRoaXMucGF0aCA9PT0gJycgKSA/IExvYWRlclV0aWxzLmV4dHJhY3RVcmxCYXNlKCB1cmwgKSA6IHRoaXMucGF0aDtcclxuXHRcdHRoaXMucmVzb3VyY2VQYXRoID0gdGhpcy5yZXNvdXJjZVBhdGggfHwgcGF0aDtcclxuXHJcblx0XHRjb25zdCBsb2FkZXIgPSBuZXcgRmlsZUxvYWRlciggdGhpcy5tYW5hZ2VyICk7XHJcblx0XHRsb2FkZXIuc2V0UGF0aCggdGhpcy5wYXRoICk7XHJcblx0XHRsb2FkZXIuc2V0UmVxdWVzdEhlYWRlciggdGhpcy5yZXF1ZXN0SGVhZGVyICk7XHJcblx0XHRsb2FkZXIuc2V0V2l0aENyZWRlbnRpYWxzKCB0aGlzLndpdGhDcmVkZW50aWFscyApO1xyXG5cdFx0bG9hZGVyLmxvYWQoIHVybCwgZnVuY3Rpb24gKCB0ZXh0ICkge1xyXG5cclxuXHRcdFx0bGV0IGpzb24gPSBudWxsO1xyXG5cclxuXHRcdFx0dHJ5IHtcclxuXHJcblx0XHRcdFx0anNvbiA9IEpTT04ucGFyc2UoIHRleHQgKTtcclxuXHJcblx0XHRcdH0gY2F0Y2ggKCBlcnJvciApIHtcclxuXHJcblx0XHRcdFx0aWYgKCBvbkVycm9yICE9PSB1bmRlZmluZWQgKSBvbkVycm9yKCBlcnJvciApO1xyXG5cclxuXHRcdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUU6T2JqZWN0TG9hZGVyOiBDYW5cXCd0IHBhcnNlICcgKyB1cmwgKyAnLicsIGVycm9yLm1lc3NhZ2UgKTtcclxuXHJcblx0XHRcdFx0cmV0dXJuO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Y29uc3QgbWV0YWRhdGEgPSBqc29uLm1ldGFkYXRhO1xyXG5cclxuXHRcdFx0aWYgKCBtZXRhZGF0YSA9PT0gdW5kZWZpbmVkIHx8IG1ldGFkYXRhLnR5cGUgPT09IHVuZGVmaW5lZCB8fCBtZXRhZGF0YS50eXBlLnRvTG93ZXJDYXNlKCkgPT09ICdnZW9tZXRyeScgKSB7XHJcblxyXG5cdFx0XHRcdGlmICggb25FcnJvciAhPT0gdW5kZWZpbmVkICkgb25FcnJvciggbmV3IEVycm9yKCAnVEhSRUUuT2JqZWN0TG9hZGVyOiBDYW5cXCd0IGxvYWQgJyArIHVybCApICk7XHJcblxyXG5cdFx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5PYmplY3RMb2FkZXI6IENhblxcJ3QgbG9hZCAnICsgdXJsICk7XHJcblx0XHRcdFx0cmV0dXJuO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0c2NvcGUucGFyc2UoIGpzb24sIG9uTG9hZCApO1xyXG5cclxuXHRcdH0sIG9uUHJvZ3Jlc3MsIG9uRXJyb3IgKTtcclxuXHJcblx0fVxyXG5cclxuXHRhc3luYyBsb2FkQXN5bmMoIHVybCwgb25Qcm9ncmVzcyApIHtcclxuXHJcblx0XHRjb25zdCBzY29wZSA9IHRoaXM7XHJcblxyXG5cdFx0Y29uc3QgcGF0aCA9ICggdGhpcy5wYXRoID09PSAnJyApID8gTG9hZGVyVXRpbHMuZXh0cmFjdFVybEJhc2UoIHVybCApIDogdGhpcy5wYXRoO1xyXG5cdFx0dGhpcy5yZXNvdXJjZVBhdGggPSB0aGlzLnJlc291cmNlUGF0aCB8fCBwYXRoO1xyXG5cclxuXHRcdGNvbnN0IGxvYWRlciA9IG5ldyBGaWxlTG9hZGVyKCB0aGlzLm1hbmFnZXIgKTtcclxuXHRcdGxvYWRlci5zZXRQYXRoKCB0aGlzLnBhdGggKTtcclxuXHRcdGxvYWRlci5zZXRSZXF1ZXN0SGVhZGVyKCB0aGlzLnJlcXVlc3RIZWFkZXIgKTtcclxuXHRcdGxvYWRlci5zZXRXaXRoQ3JlZGVudGlhbHMoIHRoaXMud2l0aENyZWRlbnRpYWxzICk7XHJcblxyXG5cdFx0Y29uc3QgdGV4dCA9IGF3YWl0IGxvYWRlci5sb2FkQXN5bmMoIHVybCwgb25Qcm9ncmVzcyApO1xyXG5cclxuXHRcdGNvbnN0IGpzb24gPSBKU09OLnBhcnNlKCB0ZXh0ICk7XHJcblxyXG5cdFx0Y29uc3QgbWV0YWRhdGEgPSBqc29uLm1ldGFkYXRhO1xyXG5cclxuXHRcdGlmICggbWV0YWRhdGEgPT09IHVuZGVmaW5lZCB8fCBtZXRhZGF0YS50eXBlID09PSB1bmRlZmluZWQgfHwgbWV0YWRhdGEudHlwZS50b0xvd2VyQ2FzZSgpID09PSAnZ2VvbWV0cnknICkge1xyXG5cclxuXHRcdFx0dGhyb3cgbmV3IEVycm9yKCAnVEhSRUUuT2JqZWN0TG9hZGVyOiBDYW5cXCd0IGxvYWQgJyArIHVybCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gYXdhaXQgc2NvcGUucGFyc2VBc3luYygganNvbiApO1xyXG5cclxuXHR9XHJcblxyXG5cdHBhcnNlKCBqc29uLCBvbkxvYWQgKSB7XHJcblxyXG5cdFx0Y29uc3QgYW5pbWF0aW9ucyA9IHRoaXMucGFyc2VBbmltYXRpb25zKCBqc29uLmFuaW1hdGlvbnMgKTtcclxuXHRcdGNvbnN0IHNoYXBlcyA9IHRoaXMucGFyc2VTaGFwZXMoIGpzb24uc2hhcGVzICk7XHJcblx0XHRjb25zdCBnZW9tZXRyaWVzID0gdGhpcy5wYXJzZUdlb21ldHJpZXMoIGpzb24uZ2VvbWV0cmllcywgc2hhcGVzICk7XHJcblxyXG5cdFx0Y29uc3QgaW1hZ2VzID0gdGhpcy5wYXJzZUltYWdlcygganNvbi5pbWFnZXMsIGZ1bmN0aW9uICgpIHtcclxuXHJcblx0XHRcdGlmICggb25Mb2FkICE9PSB1bmRlZmluZWQgKSBvbkxvYWQoIG9iamVjdCApO1xyXG5cclxuXHRcdH0gKTtcclxuXHJcblx0XHRjb25zdCB0ZXh0dXJlcyA9IHRoaXMucGFyc2VUZXh0dXJlcygganNvbi50ZXh0dXJlcywgaW1hZ2VzICk7XHJcblx0XHRjb25zdCBtYXRlcmlhbHMgPSB0aGlzLnBhcnNlTWF0ZXJpYWxzKCBqc29uLm1hdGVyaWFscywgdGV4dHVyZXMgKTtcclxuXHJcblx0XHRjb25zdCBvYmplY3QgPSB0aGlzLnBhcnNlT2JqZWN0KCBqc29uLm9iamVjdCwgZ2VvbWV0cmllcywgbWF0ZXJpYWxzLCB0ZXh0dXJlcywgYW5pbWF0aW9ucyApO1xyXG5cdFx0Y29uc3Qgc2tlbGV0b25zID0gdGhpcy5wYXJzZVNrZWxldG9ucygganNvbi5za2VsZXRvbnMsIG9iamVjdCApO1xyXG5cclxuXHRcdHRoaXMuYmluZFNrZWxldG9ucyggb2JqZWN0LCBza2VsZXRvbnMgKTtcclxuXHJcblx0XHQvL1xyXG5cclxuXHRcdGlmICggb25Mb2FkICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRsZXQgaGFzSW1hZ2VzID0gZmFsc2U7XHJcblxyXG5cdFx0XHRmb3IgKCBjb25zdCB1dWlkIGluIGltYWdlcyApIHtcclxuXHJcblx0XHRcdFx0aWYgKCBpbWFnZXNbIHV1aWQgXS5kYXRhIGluc3RhbmNlb2YgSFRNTEltYWdlRWxlbWVudCApIHtcclxuXHJcblx0XHRcdFx0XHRoYXNJbWFnZXMgPSB0cnVlO1xyXG5cdFx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGlmICggaGFzSW1hZ2VzID09PSBmYWxzZSApIG9uTG9hZCggb2JqZWN0ICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiBvYmplY3Q7XHJcblxyXG5cdH1cclxuXHJcblx0YXN5bmMgcGFyc2VBc3luYygganNvbiApIHtcclxuXHJcblx0XHRjb25zdCBhbmltYXRpb25zID0gdGhpcy5wYXJzZUFuaW1hdGlvbnMoIGpzb24uYW5pbWF0aW9ucyApO1xyXG5cdFx0Y29uc3Qgc2hhcGVzID0gdGhpcy5wYXJzZVNoYXBlcygganNvbi5zaGFwZXMgKTtcclxuXHRcdGNvbnN0IGdlb21ldHJpZXMgPSB0aGlzLnBhcnNlR2VvbWV0cmllcygganNvbi5nZW9tZXRyaWVzLCBzaGFwZXMgKTtcclxuXHJcblx0XHRjb25zdCBpbWFnZXMgPSBhd2FpdCB0aGlzLnBhcnNlSW1hZ2VzQXN5bmMoIGpzb24uaW1hZ2VzICk7XHJcblxyXG5cdFx0Y29uc3QgdGV4dHVyZXMgPSB0aGlzLnBhcnNlVGV4dHVyZXMoIGpzb24udGV4dHVyZXMsIGltYWdlcyApO1xyXG5cdFx0Y29uc3QgbWF0ZXJpYWxzID0gdGhpcy5wYXJzZU1hdGVyaWFscygganNvbi5tYXRlcmlhbHMsIHRleHR1cmVzICk7XHJcblxyXG5cdFx0Y29uc3Qgb2JqZWN0ID0gdGhpcy5wYXJzZU9iamVjdCgganNvbi5vYmplY3QsIGdlb21ldHJpZXMsIG1hdGVyaWFscywgdGV4dHVyZXMsIGFuaW1hdGlvbnMgKTtcclxuXHRcdGNvbnN0IHNrZWxldG9ucyA9IHRoaXMucGFyc2VTa2VsZXRvbnMoIGpzb24uc2tlbGV0b25zLCBvYmplY3QgKTtcclxuXHJcblx0XHR0aGlzLmJpbmRTa2VsZXRvbnMoIG9iamVjdCwgc2tlbGV0b25zICk7XHJcblxyXG5cdFx0cmV0dXJuIG9iamVjdDtcclxuXHJcblx0fVxyXG5cclxuXHRwYXJzZVNoYXBlcygganNvbiApIHtcclxuXHJcblx0XHRjb25zdCBzaGFwZXMgPSB7fTtcclxuXHJcblx0XHRpZiAoIGpzb24gIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMCwgbCA9IGpzb24ubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0Y29uc3Qgc2hhcGUgPSBuZXcgU2hhcGUoKS5mcm9tSlNPTigganNvblsgaSBdICk7XHJcblxyXG5cdFx0XHRcdHNoYXBlc1sgc2hhcGUudXVpZCBdID0gc2hhcGU7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiBzaGFwZXM7XHJcblxyXG5cdH1cclxuXHJcblx0cGFyc2VTa2VsZXRvbnMoIGpzb24sIG9iamVjdCApIHtcclxuXHJcblx0XHRjb25zdCBza2VsZXRvbnMgPSB7fTtcclxuXHRcdGNvbnN0IGJvbmVzID0ge307XHJcblxyXG5cdFx0Ly8gZ2VuZXJhdGUgYm9uZSBsb29rdXAgdGFibGVcclxuXHJcblx0XHRvYmplY3QudHJhdmVyc2UoIGZ1bmN0aW9uICggY2hpbGQgKSB7XHJcblxyXG5cdFx0XHRpZiAoIGNoaWxkLmlzQm9uZSApIGJvbmVzWyBjaGlsZC51dWlkIF0gPSBjaGlsZDtcclxuXHJcblx0XHR9ICk7XHJcblxyXG5cdFx0Ly8gY3JlYXRlIHNrZWxldG9uc1xyXG5cclxuXHRcdGlmICgganNvbiAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGkgPSAwLCBsID0ganNvbi5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBza2VsZXRvbiA9IG5ldyBTa2VsZXRvbigpLmZyb21KU09OKCBqc29uWyBpIF0sIGJvbmVzICk7XHJcblxyXG5cdFx0XHRcdHNrZWxldG9uc1sgc2tlbGV0b24udXVpZCBdID0gc2tlbGV0b247XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiBza2VsZXRvbnM7XHJcblxyXG5cdH1cclxuXHJcblx0cGFyc2VHZW9tZXRyaWVzKCBqc29uLCBzaGFwZXMgKSB7XHJcblxyXG5cdFx0Y29uc3QgZ2VvbWV0cmllcyA9IHt9O1xyXG5cclxuXHRcdGlmICgganNvbiAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0Y29uc3QgYnVmZmVyR2VvbWV0cnlMb2FkZXIgPSBuZXcgQnVmZmVyR2VvbWV0cnlMb2FkZXIoKTtcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMCwgbCA9IGpzb24ubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0bGV0IGdlb21ldHJ5O1xyXG5cdFx0XHRcdGNvbnN0IGRhdGEgPSBqc29uWyBpIF07XHJcblxyXG5cdFx0XHRcdHN3aXRjaCAoIGRhdGEudHlwZSApIHtcclxuXHJcblx0XHRcdFx0XHRjYXNlICdCdWZmZXJHZW9tZXRyeSc6XHJcblx0XHRcdFx0XHRjYXNlICdJbnN0YW5jZWRCdWZmZXJHZW9tZXRyeSc6XHJcblxyXG5cdFx0XHRcdFx0XHRnZW9tZXRyeSA9IGJ1ZmZlckdlb21ldHJ5TG9hZGVyLnBhcnNlKCBkYXRhICk7XHJcblx0XHRcdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0XHRcdGRlZmF1bHQ6XHJcblxyXG5cdFx0XHRcdFx0XHRpZiAoIGRhdGEudHlwZSBpbiBHZW9tZXRyaWVzICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRnZW9tZXRyeSA9IEdlb21ldHJpZXNbIGRhdGEudHlwZSBdLmZyb21KU09OKCBkYXRhLCBzaGFwZXMgKTtcclxuXHJcblx0XHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdGNvbnNvbGUud2FybiggYFRIUkVFLk9iamVjdExvYWRlcjogVW5zdXBwb3J0ZWQgZ2VvbWV0cnkgdHlwZSBcIiR7IGRhdGEudHlwZSB9XCJgICk7XHJcblxyXG5cdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0Z2VvbWV0cnkudXVpZCA9IGRhdGEudXVpZDtcclxuXHJcblx0XHRcdFx0aWYgKCBkYXRhLm5hbWUgIT09IHVuZGVmaW5lZCApIGdlb21ldHJ5Lm5hbWUgPSBkYXRhLm5hbWU7XHJcblx0XHRcdFx0aWYgKCBkYXRhLnVzZXJEYXRhICE9PSB1bmRlZmluZWQgKSBnZW9tZXRyeS51c2VyRGF0YSA9IGRhdGEudXNlckRhdGE7XHJcblxyXG5cdFx0XHRcdGdlb21ldHJpZXNbIGRhdGEudXVpZCBdID0gZ2VvbWV0cnk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiBnZW9tZXRyaWVzO1xyXG5cclxuXHR9XHJcblxyXG5cdHBhcnNlTWF0ZXJpYWxzKCBqc29uLCB0ZXh0dXJlcyApIHtcclxuXHJcblx0XHRjb25zdCBjYWNoZSA9IHt9OyAvLyBNdWx0aU1hdGVyaWFsXHJcblx0XHRjb25zdCBtYXRlcmlhbHMgPSB7fTtcclxuXHJcblx0XHRpZiAoIGpzb24gIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdGNvbnN0IGxvYWRlciA9IG5ldyBNYXRlcmlhbExvYWRlcigpO1xyXG5cdFx0XHRsb2FkZXIuc2V0VGV4dHVyZXMoIHRleHR1cmVzICk7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBqc29uLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IGRhdGEgPSBqc29uWyBpIF07XHJcblxyXG5cdFx0XHRcdGlmICggY2FjaGVbIGRhdGEudXVpZCBdID09PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y2FjaGVbIGRhdGEudXVpZCBdID0gbG9hZGVyLnBhcnNlKCBkYXRhICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0bWF0ZXJpYWxzWyBkYXRhLnV1aWQgXSA9IGNhY2hlWyBkYXRhLnV1aWQgXTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIG1hdGVyaWFscztcclxuXHJcblx0fVxyXG5cclxuXHRwYXJzZUFuaW1hdGlvbnMoIGpzb24gKSB7XHJcblxyXG5cdFx0Y29uc3QgYW5pbWF0aW9ucyA9IHt9O1xyXG5cclxuXHRcdGlmICgganNvbiAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwganNvbi5sZW5ndGg7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IGRhdGEgPSBqc29uWyBpIF07XHJcblxyXG5cdFx0XHRcdGNvbnN0IGNsaXAgPSBBbmltYXRpb25DbGlwLnBhcnNlKCBkYXRhICk7XHJcblxyXG5cdFx0XHRcdGFuaW1hdGlvbnNbIGNsaXAudXVpZCBdID0gY2xpcDtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIGFuaW1hdGlvbnM7XHJcblxyXG5cdH1cclxuXHJcblx0cGFyc2VJbWFnZXMoIGpzb24sIG9uTG9hZCApIHtcclxuXHJcblx0XHRjb25zdCBzY29wZSA9IHRoaXM7XHJcblx0XHRjb25zdCBpbWFnZXMgPSB7fTtcclxuXHJcblx0XHRsZXQgbG9hZGVyO1xyXG5cclxuXHRcdGZ1bmN0aW9uIGxvYWRJbWFnZSggdXJsICkge1xyXG5cclxuXHRcdFx0c2NvcGUubWFuYWdlci5pdGVtU3RhcnQoIHVybCApO1xyXG5cclxuXHRcdFx0cmV0dXJuIGxvYWRlci5sb2FkKCB1cmwsIGZ1bmN0aW9uICgpIHtcclxuXHJcblx0XHRcdFx0c2NvcGUubWFuYWdlci5pdGVtRW5kKCB1cmwgKTtcclxuXHJcblx0XHRcdH0sIHVuZGVmaW5lZCwgZnVuY3Rpb24gKCkge1xyXG5cclxuXHRcdFx0XHRzY29wZS5tYW5hZ2VyLml0ZW1FcnJvciggdXJsICk7XHJcblx0XHRcdFx0c2NvcGUubWFuYWdlci5pdGVtRW5kKCB1cmwgKTtcclxuXHJcblx0XHRcdH0gKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0ZnVuY3Rpb24gZGVzZXJpYWxpemVJbWFnZSggaW1hZ2UgKSB7XHJcblxyXG5cdFx0XHRpZiAoIHR5cGVvZiBpbWFnZSA9PT0gJ3N0cmluZycgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IHVybCA9IGltYWdlO1xyXG5cclxuXHRcdFx0XHRjb25zdCBwYXRoID0gL14oXFwvXFwvKXwoW2Etel0rOihcXC9cXC8pPykvaS50ZXN0KCB1cmwgKSA/IHVybCA6IHNjb3BlLnJlc291cmNlUGF0aCArIHVybDtcclxuXHJcblx0XHRcdFx0cmV0dXJuIGxvYWRJbWFnZSggcGF0aCApO1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0aWYgKCBpbWFnZS5kYXRhICkge1xyXG5cclxuXHRcdFx0XHRcdHJldHVybiB7XHJcblx0XHRcdFx0XHRcdGRhdGE6IGdldFR5cGVkQXJyYXkoIGltYWdlLnR5cGUsIGltYWdlLmRhdGEgKSxcclxuXHRcdFx0XHRcdFx0d2lkdGg6IGltYWdlLndpZHRoLFxyXG5cdFx0XHRcdFx0XHRoZWlnaHQ6IGltYWdlLmhlaWdodFxyXG5cdFx0XHRcdFx0fTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRyZXR1cm4gbnVsbDtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIGpzb24gIT09IHVuZGVmaW5lZCAmJiBqc29uLmxlbmd0aCA+IDAgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBtYW5hZ2VyID0gbmV3IExvYWRpbmdNYW5hZ2VyKCBvbkxvYWQgKTtcclxuXHJcblx0XHRcdGxvYWRlciA9IG5ldyBJbWFnZUxvYWRlciggbWFuYWdlciApO1xyXG5cdFx0XHRsb2FkZXIuc2V0Q3Jvc3NPcmlnaW4oIHRoaXMuY3Jvc3NPcmlnaW4gKTtcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSBqc29uLmxlbmd0aDsgaSA8IGlsOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBpbWFnZSA9IGpzb25bIGkgXTtcclxuXHRcdFx0XHRjb25zdCB1cmwgPSBpbWFnZS51cmw7XHJcblxyXG5cdFx0XHRcdGlmICggQXJyYXkuaXNBcnJheSggdXJsICkgKSB7XHJcblxyXG5cdFx0XHRcdFx0Ly8gbG9hZCBhcnJheSBvZiBpbWFnZXMgZS5nIEN1YmVUZXh0dXJlXHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgaW1hZ2VBcnJheSA9IFtdO1xyXG5cclxuXHRcdFx0XHRcdGZvciAoIGxldCBqID0gMCwgamwgPSB1cmwubGVuZ3RoOyBqIDwgamw7IGogKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRjb25zdCBjdXJyZW50VXJsID0gdXJsWyBqIF07XHJcblxyXG5cdFx0XHRcdFx0XHRjb25zdCBkZXNlcmlhbGl6ZWRJbWFnZSA9IGRlc2VyaWFsaXplSW1hZ2UoIGN1cnJlbnRVcmwgKTtcclxuXHJcblx0XHRcdFx0XHRcdGlmICggZGVzZXJpYWxpemVkSW1hZ2UgIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdGlmICggZGVzZXJpYWxpemVkSW1hZ2UgaW5zdGFuY2VvZiBIVE1MSW1hZ2VFbGVtZW50ICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRcdGltYWdlQXJyYXkucHVzaCggZGVzZXJpYWxpemVkSW1hZ2UgKTtcclxuXHJcblx0XHRcdFx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHQvLyBzcGVjaWFsIGNhc2U6IGhhbmRsZSBhcnJheSBvZiBkYXRhIHRleHR1cmVzIGZvciBjdWJlIHRleHR1cmVzXHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0aW1hZ2VBcnJheS5wdXNoKCBuZXcgRGF0YVRleHR1cmUoIGRlc2VyaWFsaXplZEltYWdlLmRhdGEsIGRlc2VyaWFsaXplZEltYWdlLndpZHRoLCBkZXNlcmlhbGl6ZWRJbWFnZS5oZWlnaHQgKSApO1xyXG5cclxuXHRcdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdGltYWdlc1sgaW1hZ2UudXVpZCBdID0gbmV3IFNvdXJjZSggaW1hZ2VBcnJheSApO1xyXG5cclxuXHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdC8vIGxvYWQgc2luZ2xlIGltYWdlXHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgZGVzZXJpYWxpemVkSW1hZ2UgPSBkZXNlcmlhbGl6ZUltYWdlKCBpbWFnZS51cmwgKTtcclxuXHRcdFx0XHRcdGltYWdlc1sgaW1hZ2UudXVpZCBdID0gbmV3IFNvdXJjZSggZGVzZXJpYWxpemVkSW1hZ2UgKTtcclxuXHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIGltYWdlcztcclxuXHJcblx0fVxyXG5cclxuXHRhc3luYyBwYXJzZUltYWdlc0FzeW5jKCBqc29uICkge1xyXG5cclxuXHRcdGNvbnN0IHNjb3BlID0gdGhpcztcclxuXHRcdGNvbnN0IGltYWdlcyA9IHt9O1xyXG5cclxuXHRcdGxldCBsb2FkZXI7XHJcblxyXG5cdFx0YXN5bmMgZnVuY3Rpb24gZGVzZXJpYWxpemVJbWFnZSggaW1hZ2UgKSB7XHJcblxyXG5cdFx0XHRpZiAoIHR5cGVvZiBpbWFnZSA9PT0gJ3N0cmluZycgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IHVybCA9IGltYWdlO1xyXG5cclxuXHRcdFx0XHRjb25zdCBwYXRoID0gL14oXFwvXFwvKXwoW2Etel0rOihcXC9cXC8pPykvaS50ZXN0KCB1cmwgKSA/IHVybCA6IHNjb3BlLnJlc291cmNlUGF0aCArIHVybDtcclxuXHJcblx0XHRcdFx0cmV0dXJuIGF3YWl0IGxvYWRlci5sb2FkQXN5bmMoIHBhdGggKTtcclxuXHJcblx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdGlmICggaW1hZ2UuZGF0YSApIHtcclxuXHJcblx0XHRcdFx0XHRyZXR1cm4ge1xyXG5cdFx0XHRcdFx0XHRkYXRhOiBnZXRUeXBlZEFycmF5KCBpbWFnZS50eXBlLCBpbWFnZS5kYXRhICksXHJcblx0XHRcdFx0XHRcdHdpZHRoOiBpbWFnZS53aWR0aCxcclxuXHRcdFx0XHRcdFx0aGVpZ2h0OiBpbWFnZS5oZWlnaHRcclxuXHRcdFx0XHRcdH07XHJcblxyXG5cdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0cmV0dXJuIG51bGw7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBqc29uICE9PSB1bmRlZmluZWQgJiYganNvbi5sZW5ndGggPiAwICkge1xyXG5cclxuXHRcdFx0bG9hZGVyID0gbmV3IEltYWdlTG9hZGVyKCB0aGlzLm1hbmFnZXIgKTtcclxuXHRcdFx0bG9hZGVyLnNldENyb3NzT3JpZ2luKCB0aGlzLmNyb3NzT3JpZ2luICk7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0ganNvbi5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgaW1hZ2UgPSBqc29uWyBpIF07XHJcblx0XHRcdFx0Y29uc3QgdXJsID0gaW1hZ2UudXJsO1xyXG5cclxuXHRcdFx0XHRpZiAoIEFycmF5LmlzQXJyYXkoIHVybCApICkge1xyXG5cclxuXHRcdFx0XHRcdC8vIGxvYWQgYXJyYXkgb2YgaW1hZ2VzIGUuZyBDdWJlVGV4dHVyZVxyXG5cclxuXHRcdFx0XHRcdGNvbnN0IGltYWdlQXJyYXkgPSBbXTtcclxuXHJcblx0XHRcdFx0XHRmb3IgKCBsZXQgaiA9IDAsIGpsID0gdXJsLmxlbmd0aDsgaiA8IGpsOyBqICsrICkge1xyXG5cclxuXHRcdFx0XHRcdFx0Y29uc3QgY3VycmVudFVybCA9IHVybFsgaiBdO1xyXG5cclxuXHRcdFx0XHRcdFx0Y29uc3QgZGVzZXJpYWxpemVkSW1hZ2UgPSBhd2FpdCBkZXNlcmlhbGl6ZUltYWdlKCBjdXJyZW50VXJsICk7XHJcblxyXG5cdFx0XHRcdFx0XHRpZiAoIGRlc2VyaWFsaXplZEltYWdlICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRpZiAoIGRlc2VyaWFsaXplZEltYWdlIGluc3RhbmNlb2YgSFRNTEltYWdlRWxlbWVudCApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHRpbWFnZUFycmF5LnB1c2goIGRlc2VyaWFsaXplZEltYWdlICk7XHJcblxyXG5cdFx0XHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0Ly8gc3BlY2lhbCBjYXNlOiBoYW5kbGUgYXJyYXkgb2YgZGF0YSB0ZXh0dXJlcyBmb3IgY3ViZSB0ZXh0dXJlc1xyXG5cclxuXHRcdFx0XHRcdFx0XHRcdGltYWdlQXJyYXkucHVzaCggbmV3IERhdGFUZXh0dXJlKCBkZXNlcmlhbGl6ZWRJbWFnZS5kYXRhLCBkZXNlcmlhbGl6ZWRJbWFnZS53aWR0aCwgZGVzZXJpYWxpemVkSW1hZ2UuaGVpZ2h0ICkgKTtcclxuXHJcblx0XHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRpbWFnZXNbIGltYWdlLnV1aWQgXSA9IG5ldyBTb3VyY2UoIGltYWdlQXJyYXkgKTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHQvLyBsb2FkIHNpbmdsZSBpbWFnZVxyXG5cclxuXHRcdFx0XHRcdGNvbnN0IGRlc2VyaWFsaXplZEltYWdlID0gYXdhaXQgZGVzZXJpYWxpemVJbWFnZSggaW1hZ2UudXJsICk7XHJcblx0XHRcdFx0XHRpbWFnZXNbIGltYWdlLnV1aWQgXSA9IG5ldyBTb3VyY2UoIGRlc2VyaWFsaXplZEltYWdlICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIGltYWdlcztcclxuXHJcblx0fVxyXG5cclxuXHRwYXJzZVRleHR1cmVzKCBqc29uLCBpbWFnZXMgKSB7XHJcblxyXG5cdFx0ZnVuY3Rpb24gcGFyc2VDb25zdGFudCggdmFsdWUsIHR5cGUgKSB7XHJcblxyXG5cdFx0XHRpZiAoIHR5cGVvZiB2YWx1ZSA9PT0gJ251bWJlcicgKSByZXR1cm4gdmFsdWU7XHJcblxyXG5cdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5PYmplY3RMb2FkZXIucGFyc2VUZXh0dXJlOiBDb25zdGFudCBzaG91bGQgYmUgaW4gbnVtZXJpYyBmb3JtLicsIHZhbHVlICk7XHJcblxyXG5cdFx0XHRyZXR1cm4gdHlwZVsgdmFsdWUgXTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Y29uc3QgdGV4dHVyZXMgPSB7fTtcclxuXHJcblx0XHRpZiAoIGpzb24gIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMCwgbCA9IGpzb24ubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgZGF0YSA9IGpzb25bIGkgXTtcclxuXHJcblx0XHRcdFx0aWYgKCBkYXRhLmltYWdlID09PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuT2JqZWN0TG9hZGVyOiBObyBcImltYWdlXCIgc3BlY2lmaWVkIGZvcicsIGRhdGEudXVpZCApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdGlmICggaW1hZ2VzWyBkYXRhLmltYWdlIF0gPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5PYmplY3RMb2FkZXI6IFVuZGVmaW5lZCBpbWFnZScsIGRhdGEuaW1hZ2UgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRjb25zdCBzb3VyY2UgPSBpbWFnZXNbIGRhdGEuaW1hZ2UgXTtcclxuXHRcdFx0XHRjb25zdCBpbWFnZSA9IHNvdXJjZS5kYXRhO1xyXG5cclxuXHRcdFx0XHRsZXQgdGV4dHVyZTtcclxuXHJcblx0XHRcdFx0aWYgKCBBcnJheS5pc0FycmF5KCBpbWFnZSApICkge1xyXG5cclxuXHRcdFx0XHRcdHRleHR1cmUgPSBuZXcgQ3ViZVRleHR1cmUoKTtcclxuXHJcblx0XHRcdFx0XHRpZiAoIGltYWdlLmxlbmd0aCA9PT0gNiApIHRleHR1cmUubmVlZHNVcGRhdGUgPSB0cnVlO1xyXG5cclxuXHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdGlmICggaW1hZ2UgJiYgaW1hZ2UuZGF0YSApIHtcclxuXHJcblx0XHRcdFx0XHRcdHRleHR1cmUgPSBuZXcgRGF0YVRleHR1cmUoKTtcclxuXHJcblx0XHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdFx0dGV4dHVyZSA9IG5ldyBUZXh0dXJlKCk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdGlmICggaW1hZ2UgKSB0ZXh0dXJlLm5lZWRzVXBkYXRlID0gdHJ1ZTsgLy8gdGV4dHVyZXMgY2FuIGhhdmUgdW5kZWZpbmVkIGltYWdlIGRhdGFcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR0ZXh0dXJlLnNvdXJjZSA9IHNvdXJjZTtcclxuXHJcblx0XHRcdFx0dGV4dHVyZS51dWlkID0gZGF0YS51dWlkO1xyXG5cclxuXHRcdFx0XHRpZiAoIGRhdGEubmFtZSAhPT0gdW5kZWZpbmVkICkgdGV4dHVyZS5uYW1lID0gZGF0YS5uYW1lO1xyXG5cclxuXHRcdFx0XHRpZiAoIGRhdGEubWFwcGluZyAhPT0gdW5kZWZpbmVkICkgdGV4dHVyZS5tYXBwaW5nID0gcGFyc2VDb25zdGFudCggZGF0YS5tYXBwaW5nLCBURVhUVVJFX01BUFBJTkcgKTtcclxuXHRcdFx0XHRpZiAoIGRhdGEuY2hhbm5lbCAhPT0gdW5kZWZpbmVkICkgdGV4dHVyZS5jaGFubmVsID0gZGF0YS5jaGFubmVsO1xyXG5cclxuXHRcdFx0XHRpZiAoIGRhdGEub2Zmc2V0ICE9PSB1bmRlZmluZWQgKSB0ZXh0dXJlLm9mZnNldC5mcm9tQXJyYXkoIGRhdGEub2Zmc2V0ICk7XHJcblx0XHRcdFx0aWYgKCBkYXRhLnJlcGVhdCAhPT0gdW5kZWZpbmVkICkgdGV4dHVyZS5yZXBlYXQuZnJvbUFycmF5KCBkYXRhLnJlcGVhdCApO1xyXG5cdFx0XHRcdGlmICggZGF0YS5jZW50ZXIgIT09IHVuZGVmaW5lZCApIHRleHR1cmUuY2VudGVyLmZyb21BcnJheSggZGF0YS5jZW50ZXIgKTtcclxuXHRcdFx0XHRpZiAoIGRhdGEucm90YXRpb24gIT09IHVuZGVmaW5lZCApIHRleHR1cmUucm90YXRpb24gPSBkYXRhLnJvdGF0aW9uO1xyXG5cclxuXHRcdFx0XHRpZiAoIGRhdGEud3JhcCAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHRcdHRleHR1cmUud3JhcFMgPSBwYXJzZUNvbnN0YW50KCBkYXRhLndyYXBbIDAgXSwgVEVYVFVSRV9XUkFQUElORyApO1xyXG5cdFx0XHRcdFx0dGV4dHVyZS53cmFwVCA9IHBhcnNlQ29uc3RhbnQoIGRhdGEud3JhcFsgMSBdLCBURVhUVVJFX1dSQVBQSU5HICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0aWYgKCBkYXRhLmZvcm1hdCAhPT0gdW5kZWZpbmVkICkgdGV4dHVyZS5mb3JtYXQgPSBkYXRhLmZvcm1hdDtcclxuXHRcdFx0XHRpZiAoIGRhdGEuaW50ZXJuYWxGb3JtYXQgIT09IHVuZGVmaW5lZCApIHRleHR1cmUuaW50ZXJuYWxGb3JtYXQgPSBkYXRhLmludGVybmFsRm9ybWF0O1xyXG5cdFx0XHRcdGlmICggZGF0YS50eXBlICE9PSB1bmRlZmluZWQgKSB0ZXh0dXJlLnR5cGUgPSBkYXRhLnR5cGU7XHJcblx0XHRcdFx0aWYgKCBkYXRhLmNvbG9yU3BhY2UgIT09IHVuZGVmaW5lZCApIHRleHR1cmUuY29sb3JTcGFjZSA9IGRhdGEuY29sb3JTcGFjZTtcclxuXHJcblx0XHRcdFx0aWYgKCBkYXRhLm1pbkZpbHRlciAhPT0gdW5kZWZpbmVkICkgdGV4dHVyZS5taW5GaWx0ZXIgPSBwYXJzZUNvbnN0YW50KCBkYXRhLm1pbkZpbHRlciwgVEVYVFVSRV9GSUxURVIgKTtcclxuXHRcdFx0XHRpZiAoIGRhdGEubWFnRmlsdGVyICE9PSB1bmRlZmluZWQgKSB0ZXh0dXJlLm1hZ0ZpbHRlciA9IHBhcnNlQ29uc3RhbnQoIGRhdGEubWFnRmlsdGVyLCBURVhUVVJFX0ZJTFRFUiApO1xyXG5cdFx0XHRcdGlmICggZGF0YS5hbmlzb3Ryb3B5ICE9PSB1bmRlZmluZWQgKSB0ZXh0dXJlLmFuaXNvdHJvcHkgPSBkYXRhLmFuaXNvdHJvcHk7XHJcblxyXG5cdFx0XHRcdGlmICggZGF0YS5mbGlwWSAhPT0gdW5kZWZpbmVkICkgdGV4dHVyZS5mbGlwWSA9IGRhdGEuZmxpcFk7XHJcblxyXG5cdFx0XHRcdGlmICggZGF0YS5nZW5lcmF0ZU1pcG1hcHMgIT09IHVuZGVmaW5lZCApIHRleHR1cmUuZ2VuZXJhdGVNaXBtYXBzID0gZGF0YS5nZW5lcmF0ZU1pcG1hcHM7XHJcblx0XHRcdFx0aWYgKCBkYXRhLnByZW11bHRpcGx5QWxwaGEgIT09IHVuZGVmaW5lZCApIHRleHR1cmUucHJlbXVsdGlwbHlBbHBoYSA9IGRhdGEucHJlbXVsdGlwbHlBbHBoYTtcclxuXHRcdFx0XHRpZiAoIGRhdGEudW5wYWNrQWxpZ25tZW50ICE9PSB1bmRlZmluZWQgKSB0ZXh0dXJlLnVucGFja0FsaWdubWVudCA9IGRhdGEudW5wYWNrQWxpZ25tZW50O1xyXG5cdFx0XHRcdGlmICggZGF0YS5jb21wYXJlRnVuY3Rpb24gIT09IHVuZGVmaW5lZCApIHRleHR1cmUuY29tcGFyZUZ1bmN0aW9uID0gZGF0YS5jb21wYXJlRnVuY3Rpb247XHJcblxyXG5cdFx0XHRcdGlmICggZGF0YS51c2VyRGF0YSAhPT0gdW5kZWZpbmVkICkgdGV4dHVyZS51c2VyRGF0YSA9IGRhdGEudXNlckRhdGE7XHJcblxyXG5cdFx0XHRcdHRleHR1cmVzWyBkYXRhLnV1aWQgXSA9IHRleHR1cmU7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0ZXh0dXJlcztcclxuXHJcblx0fVxyXG5cclxuXHRwYXJzZU9iamVjdCggZGF0YSwgZ2VvbWV0cmllcywgbWF0ZXJpYWxzLCB0ZXh0dXJlcywgYW5pbWF0aW9ucyApIHtcclxuXHJcblx0XHRsZXQgb2JqZWN0O1xyXG5cclxuXHRcdGZ1bmN0aW9uIGdldEdlb21ldHJ5KCBuYW1lICkge1xyXG5cclxuXHRcdFx0aWYgKCBnZW9tZXRyaWVzWyBuYW1lIF0gPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuT2JqZWN0TG9hZGVyOiBVbmRlZmluZWQgZ2VvbWV0cnknLCBuYW1lICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRyZXR1cm4gZ2VvbWV0cmllc1sgbmFtZSBdO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRmdW5jdGlvbiBnZXRNYXRlcmlhbCggbmFtZSApIHtcclxuXHJcblx0XHRcdGlmICggbmFtZSA9PT0gdW5kZWZpbmVkICkgcmV0dXJuIHVuZGVmaW5lZDtcclxuXHJcblx0XHRcdGlmICggQXJyYXkuaXNBcnJheSggbmFtZSApICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBhcnJheSA9IFtdO1xyXG5cclxuXHRcdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBuYW1lLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgdXVpZCA9IG5hbWVbIGkgXTtcclxuXHJcblx0XHRcdFx0XHRpZiAoIG1hdGVyaWFsc1sgdXVpZCBdID09PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5PYmplY3RMb2FkZXI6IFVuZGVmaW5lZCBtYXRlcmlhbCcsIHV1aWQgKTtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0YXJyYXkucHVzaCggbWF0ZXJpYWxzWyB1dWlkIF0gKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRyZXR1cm4gYXJyYXk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRpZiAoIG1hdGVyaWFsc1sgbmFtZSBdID09PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLk9iamVjdExvYWRlcjogVW5kZWZpbmVkIG1hdGVyaWFsJywgbmFtZSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0cmV0dXJuIG1hdGVyaWFsc1sgbmFtZSBdO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRmdW5jdGlvbiBnZXRUZXh0dXJlKCB1dWlkICkge1xyXG5cclxuXHRcdFx0aWYgKCB0ZXh0dXJlc1sgdXVpZCBdID09PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLk9iamVjdExvYWRlcjogVW5kZWZpbmVkIHRleHR1cmUnLCB1dWlkICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRyZXR1cm4gdGV4dHVyZXNbIHV1aWQgXTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0bGV0IGdlb21ldHJ5LCBtYXRlcmlhbDtcclxuXHJcblx0XHRzd2l0Y2ggKCBkYXRhLnR5cGUgKSB7XHJcblxyXG5cdFx0XHRjYXNlICdTY2VuZSc6XHJcblxyXG5cdFx0XHRcdG9iamVjdCA9IG5ldyBTY2VuZSgpO1xyXG5cclxuXHRcdFx0XHRpZiAoIGRhdGEuYmFja2dyb3VuZCAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHRcdGlmICggTnVtYmVyLmlzSW50ZWdlciggZGF0YS5iYWNrZ3JvdW5kICkgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRvYmplY3QuYmFja2dyb3VuZCA9IG5ldyBDb2xvciggZGF0YS5iYWNrZ3JvdW5kICk7XHJcblxyXG5cdFx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRcdG9iamVjdC5iYWNrZ3JvdW5kID0gZ2V0VGV4dHVyZSggZGF0YS5iYWNrZ3JvdW5kICk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdGlmICggZGF0YS5lbnZpcm9ubWVudCAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHRcdG9iamVjdC5lbnZpcm9ubWVudCA9IGdldFRleHR1cmUoIGRhdGEuZW52aXJvbm1lbnQgKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRpZiAoIGRhdGEuZm9nICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCBkYXRhLmZvZy50eXBlID09PSAnRm9nJyApIHtcclxuXHJcblx0XHRcdFx0XHRcdG9iamVjdC5mb2cgPSBuZXcgRm9nKCBkYXRhLmZvZy5jb2xvciwgZGF0YS5mb2cubmVhciwgZGF0YS5mb2cuZmFyICk7XHJcblxyXG5cdFx0XHRcdFx0fSBlbHNlIGlmICggZGF0YS5mb2cudHlwZSA9PT0gJ0ZvZ0V4cDInICkge1xyXG5cclxuXHRcdFx0XHRcdFx0b2JqZWN0LmZvZyA9IG5ldyBGb2dFeHAyKCBkYXRhLmZvZy5jb2xvciwgZGF0YS5mb2cuZGVuc2l0eSApO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRpZiAoIGRhdGEuZm9nLm5hbWUgIT09ICcnICkge1xyXG5cclxuXHRcdFx0XHRcdFx0b2JqZWN0LmZvZy5uYW1lID0gZGF0YS5mb2cubmFtZTtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0aWYgKCBkYXRhLmJhY2tncm91bmRCbHVycmluZXNzICE9PSB1bmRlZmluZWQgKSBvYmplY3QuYmFja2dyb3VuZEJsdXJyaW5lc3MgPSBkYXRhLmJhY2tncm91bmRCbHVycmluZXNzO1xyXG5cdFx0XHRcdGlmICggZGF0YS5iYWNrZ3JvdW5kSW50ZW5zaXR5ICE9PSB1bmRlZmluZWQgKSBvYmplY3QuYmFja2dyb3VuZEludGVuc2l0eSA9IGRhdGEuYmFja2dyb3VuZEludGVuc2l0eTtcclxuXHJcblx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRjYXNlICdQZXJzcGVjdGl2ZUNhbWVyYSc6XHJcblxyXG5cdFx0XHRcdG9iamVjdCA9IG5ldyBQZXJzcGVjdGl2ZUNhbWVyYSggZGF0YS5mb3YsIGRhdGEuYXNwZWN0LCBkYXRhLm5lYXIsIGRhdGEuZmFyICk7XHJcblxyXG5cdFx0XHRcdGlmICggZGF0YS5mb2N1cyAhPT0gdW5kZWZpbmVkICkgb2JqZWN0LmZvY3VzID0gZGF0YS5mb2N1cztcclxuXHRcdFx0XHRpZiAoIGRhdGEuem9vbSAhPT0gdW5kZWZpbmVkICkgb2JqZWN0Lnpvb20gPSBkYXRhLnpvb207XHJcblx0XHRcdFx0aWYgKCBkYXRhLmZpbG1HYXVnZSAhPT0gdW5kZWZpbmVkICkgb2JqZWN0LmZpbG1HYXVnZSA9IGRhdGEuZmlsbUdhdWdlO1xyXG5cdFx0XHRcdGlmICggZGF0YS5maWxtT2Zmc2V0ICE9PSB1bmRlZmluZWQgKSBvYmplY3QuZmlsbU9mZnNldCA9IGRhdGEuZmlsbU9mZnNldDtcclxuXHRcdFx0XHRpZiAoIGRhdGEudmlldyAhPT0gdW5kZWZpbmVkICkgb2JqZWN0LnZpZXcgPSBPYmplY3QuYXNzaWduKCB7fSwgZGF0YS52aWV3ICk7XHJcblxyXG5cdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0Y2FzZSAnT3J0aG9ncmFwaGljQ2FtZXJhJzpcclxuXHJcblx0XHRcdFx0b2JqZWN0ID0gbmV3IE9ydGhvZ3JhcGhpY0NhbWVyYSggZGF0YS5sZWZ0LCBkYXRhLnJpZ2h0LCBkYXRhLnRvcCwgZGF0YS5ib3R0b20sIGRhdGEubmVhciwgZGF0YS5mYXIgKTtcclxuXHJcblx0XHRcdFx0aWYgKCBkYXRhLnpvb20gIT09IHVuZGVmaW5lZCApIG9iamVjdC56b29tID0gZGF0YS56b29tO1xyXG5cdFx0XHRcdGlmICggZGF0YS52aWV3ICE9PSB1bmRlZmluZWQgKSBvYmplY3QudmlldyA9IE9iamVjdC5hc3NpZ24oIHt9LCBkYXRhLnZpZXcgKTtcclxuXHJcblx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRjYXNlICdBbWJpZW50TGlnaHQnOlxyXG5cclxuXHRcdFx0XHRvYmplY3QgPSBuZXcgQW1iaWVudExpZ2h0KCBkYXRhLmNvbG9yLCBkYXRhLmludGVuc2l0eSApO1xyXG5cclxuXHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdGNhc2UgJ0RpcmVjdGlvbmFsTGlnaHQnOlxyXG5cclxuXHRcdFx0XHRvYmplY3QgPSBuZXcgRGlyZWN0aW9uYWxMaWdodCggZGF0YS5jb2xvciwgZGF0YS5pbnRlbnNpdHkgKTtcclxuXHJcblx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRjYXNlICdQb2ludExpZ2h0JzpcclxuXHJcblx0XHRcdFx0b2JqZWN0ID0gbmV3IFBvaW50TGlnaHQoIGRhdGEuY29sb3IsIGRhdGEuaW50ZW5zaXR5LCBkYXRhLmRpc3RhbmNlLCBkYXRhLmRlY2F5ICk7XHJcblxyXG5cdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0Y2FzZSAnUmVjdEFyZWFMaWdodCc6XHJcblxyXG5cdFx0XHRcdG9iamVjdCA9IG5ldyBSZWN0QXJlYUxpZ2h0KCBkYXRhLmNvbG9yLCBkYXRhLmludGVuc2l0eSwgZGF0YS53aWR0aCwgZGF0YS5oZWlnaHQgKTtcclxuXHJcblx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRjYXNlICdTcG90TGlnaHQnOlxyXG5cclxuXHRcdFx0XHRvYmplY3QgPSBuZXcgU3BvdExpZ2h0KCBkYXRhLmNvbG9yLCBkYXRhLmludGVuc2l0eSwgZGF0YS5kaXN0YW5jZSwgZGF0YS5hbmdsZSwgZGF0YS5wZW51bWJyYSwgZGF0YS5kZWNheSApO1xyXG5cclxuXHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdGNhc2UgJ0hlbWlzcGhlcmVMaWdodCc6XHJcblxyXG5cdFx0XHRcdG9iamVjdCA9IG5ldyBIZW1pc3BoZXJlTGlnaHQoIGRhdGEuY29sb3IsIGRhdGEuZ3JvdW5kQ29sb3IsIGRhdGEuaW50ZW5zaXR5ICk7XHJcblxyXG5cdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0Y2FzZSAnTGlnaHRQcm9iZSc6XHJcblxyXG5cdFx0XHRcdG9iamVjdCA9IG5ldyBMaWdodFByb2JlKCkuZnJvbUpTT04oIGRhdGEgKTtcclxuXHJcblx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRjYXNlICdTa2lubmVkTWVzaCc6XHJcblxyXG5cdFx0XHRcdGdlb21ldHJ5ID0gZ2V0R2VvbWV0cnkoIGRhdGEuZ2VvbWV0cnkgKTtcclxuXHRcdFx0IFx0bWF0ZXJpYWwgPSBnZXRNYXRlcmlhbCggZGF0YS5tYXRlcmlhbCApO1xyXG5cclxuXHRcdFx0XHRvYmplY3QgPSBuZXcgU2tpbm5lZE1lc2goIGdlb21ldHJ5LCBtYXRlcmlhbCApO1xyXG5cclxuXHRcdFx0XHRpZiAoIGRhdGEuYmluZE1vZGUgIT09IHVuZGVmaW5lZCApIG9iamVjdC5iaW5kTW9kZSA9IGRhdGEuYmluZE1vZGU7XHJcblx0XHRcdFx0aWYgKCBkYXRhLmJpbmRNYXRyaXggIT09IHVuZGVmaW5lZCApIG9iamVjdC5iaW5kTWF0cml4LmZyb21BcnJheSggZGF0YS5iaW5kTWF0cml4ICk7XHJcblx0XHRcdFx0aWYgKCBkYXRhLnNrZWxldG9uICE9PSB1bmRlZmluZWQgKSBvYmplY3Quc2tlbGV0b24gPSBkYXRhLnNrZWxldG9uO1xyXG5cclxuXHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdGNhc2UgJ01lc2gnOlxyXG5cclxuXHRcdFx0XHRnZW9tZXRyeSA9IGdldEdlb21ldHJ5KCBkYXRhLmdlb21ldHJ5ICk7XHJcblx0XHRcdFx0bWF0ZXJpYWwgPSBnZXRNYXRlcmlhbCggZGF0YS5tYXRlcmlhbCApO1xyXG5cclxuXHRcdFx0XHRvYmplY3QgPSBuZXcgTWVzaCggZ2VvbWV0cnksIG1hdGVyaWFsICk7XHJcblxyXG5cdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0Y2FzZSAnSW5zdGFuY2VkTWVzaCc6XHJcblxyXG5cdFx0XHRcdGdlb21ldHJ5ID0gZ2V0R2VvbWV0cnkoIGRhdGEuZ2VvbWV0cnkgKTtcclxuXHRcdFx0XHRtYXRlcmlhbCA9IGdldE1hdGVyaWFsKCBkYXRhLm1hdGVyaWFsICk7XHJcblx0XHRcdFx0Y29uc3QgY291bnQgPSBkYXRhLmNvdW50O1xyXG5cdFx0XHRcdGNvbnN0IGluc3RhbmNlTWF0cml4ID0gZGF0YS5pbnN0YW5jZU1hdHJpeDtcclxuXHRcdFx0XHRjb25zdCBpbnN0YW5jZUNvbG9yID0gZGF0YS5pbnN0YW5jZUNvbG9yO1xyXG5cclxuXHRcdFx0XHRvYmplY3QgPSBuZXcgSW5zdGFuY2VkTWVzaCggZ2VvbWV0cnksIG1hdGVyaWFsLCBjb3VudCApO1xyXG5cdFx0XHRcdG9iamVjdC5pbnN0YW5jZU1hdHJpeCA9IG5ldyBJbnN0YW5jZWRCdWZmZXJBdHRyaWJ1dGUoIG5ldyBGbG9hdDMyQXJyYXkoIGluc3RhbmNlTWF0cml4LmFycmF5ICksIDE2ICk7XHJcblx0XHRcdFx0aWYgKCBpbnN0YW5jZUNvbG9yICE9PSB1bmRlZmluZWQgKSBvYmplY3QuaW5zdGFuY2VDb2xvciA9IG5ldyBJbnN0YW5jZWRCdWZmZXJBdHRyaWJ1dGUoIG5ldyBGbG9hdDMyQXJyYXkoIGluc3RhbmNlQ29sb3IuYXJyYXkgKSwgaW5zdGFuY2VDb2xvci5pdGVtU2l6ZSApO1xyXG5cclxuXHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdGNhc2UgJ0JhdGNoZWRNZXNoJzpcclxuXHJcblx0XHRcdFx0Z2VvbWV0cnkgPSBnZXRHZW9tZXRyeSggZGF0YS5nZW9tZXRyeSApO1xyXG5cdFx0XHRcdG1hdGVyaWFsID0gZ2V0TWF0ZXJpYWwoIGRhdGEubWF0ZXJpYWwgKTtcclxuXHJcblx0XHRcdFx0b2JqZWN0ID0gbmV3IEJhdGNoZWRNZXNoKCBkYXRhLm1heEdlb21ldHJ5Q291bnQsIGRhdGEubWF4VmVydGV4Q291bnQsIGRhdGEubWF4SW5kZXhDb3VudCwgbWF0ZXJpYWwgKTtcclxuXHRcdFx0XHRvYmplY3QuZ2VvbWV0cnkgPSBnZW9tZXRyeTtcclxuXHRcdFx0XHRvYmplY3QucGVyT2JqZWN0RnJ1c3R1bUN1bGxlZCA9IGRhdGEucGVyT2JqZWN0RnJ1c3R1bUN1bGxlZDtcclxuXHRcdFx0XHRvYmplY3Quc29ydE9iamVjdHMgPSBkYXRhLnNvcnRPYmplY3RzO1xyXG5cclxuXHRcdFx0XHRvYmplY3QuX2RyYXdSYW5nZXMgPSBkYXRhLmRyYXdSYW5nZXM7XHJcblx0XHRcdFx0b2JqZWN0Ll9yZXNlcnZlZFJhbmdlcyA9IGRhdGEucmVzZXJ2ZWRSYW5nZXM7XHJcblxyXG5cdFx0XHRcdG9iamVjdC5fdmlzaWJpbGl0eSA9IGRhdGEudmlzaWJpbGl0eTtcclxuXHRcdFx0XHRvYmplY3QuX2FjdGl2ZSA9IGRhdGEuYWN0aXZlO1xyXG5cdFx0XHRcdG9iamVjdC5fYm91bmRzID0gZGF0YS5ib3VuZHMubWFwKCBib3VuZCA9PiB7XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgYm94ID0gbmV3IEJveDMoKTtcclxuXHRcdFx0XHRcdGJveC5taW4uZnJvbUFycmF5KCBib3VuZC5ib3hNaW4gKTtcclxuXHRcdFx0XHRcdGJveC5tYXguZnJvbUFycmF5KCBib3VuZC5ib3hNYXggKTtcclxuXHJcblx0XHRcdFx0XHRjb25zdCBzcGhlcmUgPSBuZXcgU3BoZXJlKCk7XHJcblx0XHRcdFx0XHRzcGhlcmUucmFkaXVzID0gYm91bmQuc3BoZXJlUmFkaXVzO1xyXG5cdFx0XHRcdFx0c3BoZXJlLmNlbnRlci5mcm9tQXJyYXkoIGJvdW5kLnNwaGVyZUNlbnRlciApO1xyXG5cclxuXHRcdFx0XHRcdHJldHVybiB7XHJcblx0XHRcdFx0XHRcdGJveEluaXRpYWxpemVkOiBib3VuZC5ib3hJbml0aWFsaXplZCxcclxuXHRcdFx0XHRcdFx0Ym94OiBib3gsXHJcblxyXG5cdFx0XHRcdFx0XHRzcGhlcmVJbml0aWFsaXplZDogYm91bmQuc3BoZXJlSW5pdGlhbGl6ZWQsXHJcblx0XHRcdFx0XHRcdHNwaGVyZTogc3BoZXJlXHJcblx0XHRcdFx0XHR9O1xyXG5cclxuXHRcdFx0XHR9ICk7XHJcblxyXG5cdFx0XHRcdG9iamVjdC5fbWF4R2VvbWV0cnlDb3VudCA9IGRhdGEubWF4R2VvbWV0cnlDb3VudDtcclxuXHRcdFx0XHRvYmplY3QuX21heFZlcnRleENvdW50ID0gZGF0YS5tYXhWZXJ0ZXhDb3VudDtcclxuXHRcdFx0XHRvYmplY3QuX21heEluZGV4Q291bnQgPSBkYXRhLm1heEluZGV4Q291bnQ7XHJcblxyXG5cdFx0XHRcdG9iamVjdC5fZ2VvbWV0cnlJbml0aWFsaXplZCA9IGRhdGEuZ2VvbWV0cnlJbml0aWFsaXplZDtcclxuXHRcdFx0XHRvYmplY3QuX2dlb21ldHJ5Q291bnQgPSBkYXRhLmdlb21ldHJ5Q291bnQ7XHJcblxyXG5cdFx0XHRcdG9iamVjdC5fbWF0cmljZXNUZXh0dXJlID0gZ2V0VGV4dHVyZSggZGF0YS5tYXRyaWNlc1RleHR1cmUudXVpZCApO1xyXG5cclxuXHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdGNhc2UgJ0xPRCc6XHJcblxyXG5cdFx0XHRcdG9iamVjdCA9IG5ldyBMT0QoKTtcclxuXHJcblx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRjYXNlICdMaW5lJzpcclxuXHJcblx0XHRcdFx0b2JqZWN0ID0gbmV3IExpbmUoIGdldEdlb21ldHJ5KCBkYXRhLmdlb21ldHJ5ICksIGdldE1hdGVyaWFsKCBkYXRhLm1hdGVyaWFsICkgKTtcclxuXHJcblx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRjYXNlICdMaW5lTG9vcCc6XHJcblxyXG5cdFx0XHRcdG9iamVjdCA9IG5ldyBMaW5lTG9vcCggZ2V0R2VvbWV0cnkoIGRhdGEuZ2VvbWV0cnkgKSwgZ2V0TWF0ZXJpYWwoIGRhdGEubWF0ZXJpYWwgKSApO1xyXG5cclxuXHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdGNhc2UgJ0xpbmVTZWdtZW50cyc6XHJcblxyXG5cdFx0XHRcdG9iamVjdCA9IG5ldyBMaW5lU2VnbWVudHMoIGdldEdlb21ldHJ5KCBkYXRhLmdlb21ldHJ5ICksIGdldE1hdGVyaWFsKCBkYXRhLm1hdGVyaWFsICkgKTtcclxuXHJcblx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRjYXNlICdQb2ludENsb3VkJzpcclxuXHRcdFx0Y2FzZSAnUG9pbnRzJzpcclxuXHJcblx0XHRcdFx0b2JqZWN0ID0gbmV3IFBvaW50cyggZ2V0R2VvbWV0cnkoIGRhdGEuZ2VvbWV0cnkgKSwgZ2V0TWF0ZXJpYWwoIGRhdGEubWF0ZXJpYWwgKSApO1xyXG5cclxuXHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdGNhc2UgJ1Nwcml0ZSc6XHJcblxyXG5cdFx0XHRcdG9iamVjdCA9IG5ldyBTcHJpdGUoIGdldE1hdGVyaWFsKCBkYXRhLm1hdGVyaWFsICkgKTtcclxuXHJcblx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRjYXNlICdHcm91cCc6XHJcblxyXG5cdFx0XHRcdG9iamVjdCA9IG5ldyBHcm91cCgpO1xyXG5cclxuXHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdGNhc2UgJ0JvbmUnOlxyXG5cclxuXHRcdFx0XHRvYmplY3QgPSBuZXcgQm9uZSgpO1xyXG5cclxuXHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdGRlZmF1bHQ6XHJcblxyXG5cdFx0XHRcdG9iamVjdCA9IG5ldyBPYmplY3QzRCgpO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRvYmplY3QudXVpZCA9IGRhdGEudXVpZDtcclxuXHJcblx0XHRpZiAoIGRhdGEubmFtZSAhPT0gdW5kZWZpbmVkICkgb2JqZWN0Lm5hbWUgPSBkYXRhLm5hbWU7XHJcblxyXG5cdFx0aWYgKCBkYXRhLm1hdHJpeCAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0b2JqZWN0Lm1hdHJpeC5mcm9tQXJyYXkoIGRhdGEubWF0cml4ICk7XHJcblxyXG5cdFx0XHRpZiAoIGRhdGEubWF0cml4QXV0b1VwZGF0ZSAhPT0gdW5kZWZpbmVkICkgb2JqZWN0Lm1hdHJpeEF1dG9VcGRhdGUgPSBkYXRhLm1hdHJpeEF1dG9VcGRhdGU7XHJcblx0XHRcdGlmICggb2JqZWN0Lm1hdHJpeEF1dG9VcGRhdGUgKSBvYmplY3QubWF0cml4LmRlY29tcG9zZSggb2JqZWN0LnBvc2l0aW9uLCBvYmplY3QucXVhdGVybmlvbiwgb2JqZWN0LnNjYWxlICk7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdGlmICggZGF0YS5wb3NpdGlvbiAhPT0gdW5kZWZpbmVkICkgb2JqZWN0LnBvc2l0aW9uLmZyb21BcnJheSggZGF0YS5wb3NpdGlvbiApO1xyXG5cdFx0XHRpZiAoIGRhdGEucm90YXRpb24gIT09IHVuZGVmaW5lZCApIG9iamVjdC5yb3RhdGlvbi5mcm9tQXJyYXkoIGRhdGEucm90YXRpb24gKTtcclxuXHRcdFx0aWYgKCBkYXRhLnF1YXRlcm5pb24gIT09IHVuZGVmaW5lZCApIG9iamVjdC5xdWF0ZXJuaW9uLmZyb21BcnJheSggZGF0YS5xdWF0ZXJuaW9uICk7XHJcblx0XHRcdGlmICggZGF0YS5zY2FsZSAhPT0gdW5kZWZpbmVkICkgb2JqZWN0LnNjYWxlLmZyb21BcnJheSggZGF0YS5zY2FsZSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIGRhdGEudXAgIT09IHVuZGVmaW5lZCApIG9iamVjdC51cC5mcm9tQXJyYXkoIGRhdGEudXAgKTtcclxuXHJcblx0XHRpZiAoIGRhdGEuY2FzdFNoYWRvdyAhPT0gdW5kZWZpbmVkICkgb2JqZWN0LmNhc3RTaGFkb3cgPSBkYXRhLmNhc3RTaGFkb3c7XHJcblx0XHRpZiAoIGRhdGEucmVjZWl2ZVNoYWRvdyAhPT0gdW5kZWZpbmVkICkgb2JqZWN0LnJlY2VpdmVTaGFkb3cgPSBkYXRhLnJlY2VpdmVTaGFkb3c7XHJcblxyXG5cdFx0aWYgKCBkYXRhLnNoYWRvdyApIHtcclxuXHJcblx0XHRcdGlmICggZGF0YS5zaGFkb3cuYmlhcyAhPT0gdW5kZWZpbmVkICkgb2JqZWN0LnNoYWRvdy5iaWFzID0gZGF0YS5zaGFkb3cuYmlhcztcclxuXHRcdFx0aWYgKCBkYXRhLnNoYWRvdy5ub3JtYWxCaWFzICE9PSB1bmRlZmluZWQgKSBvYmplY3Quc2hhZG93Lm5vcm1hbEJpYXMgPSBkYXRhLnNoYWRvdy5ub3JtYWxCaWFzO1xyXG5cdFx0XHRpZiAoIGRhdGEuc2hhZG93LnJhZGl1cyAhPT0gdW5kZWZpbmVkICkgb2JqZWN0LnNoYWRvdy5yYWRpdXMgPSBkYXRhLnNoYWRvdy5yYWRpdXM7XHJcblx0XHRcdGlmICggZGF0YS5zaGFkb3cubWFwU2l6ZSAhPT0gdW5kZWZpbmVkICkgb2JqZWN0LnNoYWRvdy5tYXBTaXplLmZyb21BcnJheSggZGF0YS5zaGFkb3cubWFwU2l6ZSApO1xyXG5cdFx0XHRpZiAoIGRhdGEuc2hhZG93LmNhbWVyYSAhPT0gdW5kZWZpbmVkICkgb2JqZWN0LnNoYWRvdy5jYW1lcmEgPSB0aGlzLnBhcnNlT2JqZWN0KCBkYXRhLnNoYWRvdy5jYW1lcmEgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBkYXRhLnZpc2libGUgIT09IHVuZGVmaW5lZCApIG9iamVjdC52aXNpYmxlID0gZGF0YS52aXNpYmxlO1xyXG5cdFx0aWYgKCBkYXRhLmZydXN0dW1DdWxsZWQgIT09IHVuZGVmaW5lZCApIG9iamVjdC5mcnVzdHVtQ3VsbGVkID0gZGF0YS5mcnVzdHVtQ3VsbGVkO1xyXG5cdFx0aWYgKCBkYXRhLnJlbmRlck9yZGVyICE9PSB1bmRlZmluZWQgKSBvYmplY3QucmVuZGVyT3JkZXIgPSBkYXRhLnJlbmRlck9yZGVyO1xyXG5cdFx0aWYgKCBkYXRhLnVzZXJEYXRhICE9PSB1bmRlZmluZWQgKSBvYmplY3QudXNlckRhdGEgPSBkYXRhLnVzZXJEYXRhO1xyXG5cdFx0aWYgKCBkYXRhLmxheWVycyAhPT0gdW5kZWZpbmVkICkgb2JqZWN0LmxheWVycy5tYXNrID0gZGF0YS5sYXllcnM7XHJcblxyXG5cdFx0aWYgKCBkYXRhLmNoaWxkcmVuICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBjaGlsZHJlbiA9IGRhdGEuY2hpbGRyZW47XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBjaGlsZHJlbi5sZW5ndGg7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdG9iamVjdC5hZGQoIHRoaXMucGFyc2VPYmplY3QoIGNoaWxkcmVuWyBpIF0sIGdlb21ldHJpZXMsIG1hdGVyaWFscywgdGV4dHVyZXMsIGFuaW1hdGlvbnMgKSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIGRhdGEuYW5pbWF0aW9ucyAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0Y29uc3Qgb2JqZWN0QW5pbWF0aW9ucyA9IGRhdGEuYW5pbWF0aW9ucztcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IG9iamVjdEFuaW1hdGlvbnMubGVuZ3RoOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCB1dWlkID0gb2JqZWN0QW5pbWF0aW9uc1sgaSBdO1xyXG5cclxuXHRcdFx0XHRvYmplY3QuYW5pbWF0aW9ucy5wdXNoKCBhbmltYXRpb25zWyB1dWlkIF0gKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBkYXRhLnR5cGUgPT09ICdMT0QnICkge1xyXG5cclxuXHRcdFx0aWYgKCBkYXRhLmF1dG9VcGRhdGUgIT09IHVuZGVmaW5lZCApIG9iamVjdC5hdXRvVXBkYXRlID0gZGF0YS5hdXRvVXBkYXRlO1xyXG5cclxuXHRcdFx0Y29uc3QgbGV2ZWxzID0gZGF0YS5sZXZlbHM7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgbCA9IDA7IGwgPCBsZXZlbHMubGVuZ3RoOyBsICsrICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBsZXZlbCA9IGxldmVsc1sgbCBdO1xyXG5cdFx0XHRcdGNvbnN0IGNoaWxkID0gb2JqZWN0LmdldE9iamVjdEJ5UHJvcGVydHkoICd1dWlkJywgbGV2ZWwub2JqZWN0ICk7XHJcblxyXG5cdFx0XHRcdGlmICggY2hpbGQgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0XHRvYmplY3QuYWRkTGV2ZWwoIGNoaWxkLCBsZXZlbC5kaXN0YW5jZSwgbGV2ZWwuaHlzdGVyZXNpcyApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiBvYmplY3Q7XHJcblxyXG5cdH1cclxuXHJcblx0YmluZFNrZWxldG9ucyggb2JqZWN0LCBza2VsZXRvbnMgKSB7XHJcblxyXG5cdFx0aWYgKCBPYmplY3Qua2V5cyggc2tlbGV0b25zICkubGVuZ3RoID09PSAwICkgcmV0dXJuO1xyXG5cclxuXHRcdG9iamVjdC50cmF2ZXJzZSggZnVuY3Rpb24gKCBjaGlsZCApIHtcclxuXHJcblx0XHRcdGlmICggY2hpbGQuaXNTa2lubmVkTWVzaCA9PT0gdHJ1ZSAmJiBjaGlsZC5za2VsZXRvbiAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBza2VsZXRvbiA9IHNrZWxldG9uc1sgY2hpbGQuc2tlbGV0b24gXTtcclxuXHJcblx0XHRcdFx0aWYgKCBza2VsZXRvbiA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLk9iamVjdExvYWRlcjogTm8gc2tlbGV0b24gZm91bmQgd2l0aCBVVUlEOicsIGNoaWxkLnNrZWxldG9uICk7XHJcblxyXG5cdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0Y2hpbGQuYmluZCggc2tlbGV0b24sIGNoaWxkLmJpbmRNYXRyaXggKTtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH0gKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuY29uc3QgVEVYVFVSRV9NQVBQSU5HID0ge1xyXG5cdFVWTWFwcGluZzogVVZNYXBwaW5nLFxyXG5cdEN1YmVSZWZsZWN0aW9uTWFwcGluZzogQ3ViZVJlZmxlY3Rpb25NYXBwaW5nLFxyXG5cdEN1YmVSZWZyYWN0aW9uTWFwcGluZzogQ3ViZVJlZnJhY3Rpb25NYXBwaW5nLFxyXG5cdEVxdWlyZWN0YW5ndWxhclJlZmxlY3Rpb25NYXBwaW5nOiBFcXVpcmVjdGFuZ3VsYXJSZWZsZWN0aW9uTWFwcGluZyxcclxuXHRFcXVpcmVjdGFuZ3VsYXJSZWZyYWN0aW9uTWFwcGluZzogRXF1aXJlY3Rhbmd1bGFyUmVmcmFjdGlvbk1hcHBpbmcsXHJcblx0Q3ViZVVWUmVmbGVjdGlvbk1hcHBpbmc6IEN1YmVVVlJlZmxlY3Rpb25NYXBwaW5nXHJcbn07XHJcblxyXG5jb25zdCBURVhUVVJFX1dSQVBQSU5HID0ge1xyXG5cdFJlcGVhdFdyYXBwaW5nOiBSZXBlYXRXcmFwcGluZyxcclxuXHRDbGFtcFRvRWRnZVdyYXBwaW5nOiBDbGFtcFRvRWRnZVdyYXBwaW5nLFxyXG5cdE1pcnJvcmVkUmVwZWF0V3JhcHBpbmc6IE1pcnJvcmVkUmVwZWF0V3JhcHBpbmdcclxufTtcclxuXHJcbmNvbnN0IFRFWFRVUkVfRklMVEVSID0ge1xyXG5cdE5lYXJlc3RGaWx0ZXI6IE5lYXJlc3RGaWx0ZXIsXHJcblx0TmVhcmVzdE1pcG1hcE5lYXJlc3RGaWx0ZXI6IE5lYXJlc3RNaXBtYXBOZWFyZXN0RmlsdGVyLFxyXG5cdE5lYXJlc3RNaXBtYXBMaW5lYXJGaWx0ZXI6IE5lYXJlc3RNaXBtYXBMaW5lYXJGaWx0ZXIsXHJcblx0TGluZWFyRmlsdGVyOiBMaW5lYXJGaWx0ZXIsXHJcblx0TGluZWFyTWlwbWFwTmVhcmVzdEZpbHRlcjogTGluZWFyTWlwbWFwTmVhcmVzdEZpbHRlcixcclxuXHRMaW5lYXJNaXBtYXBMaW5lYXJGaWx0ZXI6IExpbmVhck1pcG1hcExpbmVhckZpbHRlclxyXG59O1xyXG5cclxuZXhwb3J0IHsgT2JqZWN0TG9hZGVyIH07XHJcbiIsImltcG9ydCB7IENhY2hlIH0gZnJvbSAnLi9DYWNoZS5qcyc7XHJcbmltcG9ydCB7IExvYWRlciB9IGZyb20gJy4vTG9hZGVyLmpzJztcclxuXHJcbmNsYXNzIEltYWdlQml0bWFwTG9hZGVyIGV4dGVuZHMgTG9hZGVyIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIG1hbmFnZXIgKSB7XHJcblxyXG5cdFx0c3VwZXIoIG1hbmFnZXIgKTtcclxuXHJcblx0XHR0aGlzLmlzSW1hZ2VCaXRtYXBMb2FkZXIgPSB0cnVlO1xyXG5cclxuXHRcdGlmICggdHlwZW9mIGNyZWF0ZUltYWdlQml0bWFwID09PSAndW5kZWZpbmVkJyApIHtcclxuXHJcblx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLkltYWdlQml0bWFwTG9hZGVyOiBjcmVhdGVJbWFnZUJpdG1hcCgpIG5vdCBzdXBwb3J0ZWQuJyApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHR5cGVvZiBmZXRjaCA9PT0gJ3VuZGVmaW5lZCcgKSB7XHJcblxyXG5cdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5JbWFnZUJpdG1hcExvYWRlcjogZmV0Y2goKSBub3Qgc3VwcG9ydGVkLicgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5vcHRpb25zID0geyBwcmVtdWx0aXBseUFscGhhOiAnbm9uZScgfTtcclxuXHJcblx0fVxyXG5cclxuXHRzZXRPcHRpb25zKCBvcHRpb25zICkge1xyXG5cclxuXHRcdHRoaXMub3B0aW9ucyA9IG9wdGlvbnM7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0bG9hZCggdXJsLCBvbkxvYWQsIG9uUHJvZ3Jlc3MsIG9uRXJyb3IgKSB7XHJcblxyXG5cdFx0aWYgKCB1cmwgPT09IHVuZGVmaW5lZCApIHVybCA9ICcnO1xyXG5cclxuXHRcdGlmICggdGhpcy5wYXRoICE9PSB1bmRlZmluZWQgKSB1cmwgPSB0aGlzLnBhdGggKyB1cmw7XHJcblxyXG5cdFx0dXJsID0gdGhpcy5tYW5hZ2VyLnJlc29sdmVVUkwoIHVybCApO1xyXG5cclxuXHRcdGNvbnN0IHNjb3BlID0gdGhpcztcclxuXHJcblx0XHRjb25zdCBjYWNoZWQgPSBDYWNoZS5nZXQoIHVybCApO1xyXG5cclxuXHRcdGlmICggY2FjaGVkICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRzY29wZS5tYW5hZ2VyLml0ZW1TdGFydCggdXJsICk7XHJcblxyXG5cdFx0XHQvLyBJZiBjYWNoZWQgaXMgYSBwcm9taXNlLCB3YWl0IGZvciBpdCB0byByZXNvbHZlXHJcblx0XHRcdGlmICggY2FjaGVkLnRoZW4gKSB7XHJcblxyXG5cdFx0XHRcdGNhY2hlZC50aGVuKCBpbWFnZUJpdG1hcCA9PiB7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCBvbkxvYWQgKSBvbkxvYWQoIGltYWdlQml0bWFwICk7XHJcblxyXG5cdFx0XHRcdFx0c2NvcGUubWFuYWdlci5pdGVtRW5kKCB1cmwgKTtcclxuXHJcblx0XHRcdFx0fSApLmNhdGNoKCBlID0+IHtcclxuXHJcblx0XHRcdFx0XHRpZiAoIG9uRXJyb3IgKSBvbkVycm9yKCBlICk7XHJcblxyXG5cdFx0XHRcdH0gKTtcclxuXHRcdFx0XHRyZXR1cm47XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyBJZiBjYWNoZWQgaXMgbm90IGEgcHJvbWlzZSAoaS5lLiwgaXQncyBhbHJlYWR5IGFuIGltYWdlQml0bWFwKVxyXG5cdFx0XHRzZXRUaW1lb3V0KCBmdW5jdGlvbiAoKSB7XHJcblxyXG5cdFx0XHRcdGlmICggb25Mb2FkICkgb25Mb2FkKCBjYWNoZWQgKTtcclxuXHJcblx0XHRcdFx0c2NvcGUubWFuYWdlci5pdGVtRW5kKCB1cmwgKTtcclxuXHJcblx0XHRcdH0sIDAgKTtcclxuXHJcblx0XHRcdHJldHVybiBjYWNoZWQ7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGNvbnN0IGZldGNoT3B0aW9ucyA9IHt9O1xyXG5cdFx0ZmV0Y2hPcHRpb25zLmNyZWRlbnRpYWxzID0gKCB0aGlzLmNyb3NzT3JpZ2luID09PSAnYW5vbnltb3VzJyApID8gJ3NhbWUtb3JpZ2luJyA6ICdpbmNsdWRlJztcclxuXHRcdGZldGNoT3B0aW9ucy5oZWFkZXJzID0gdGhpcy5yZXF1ZXN0SGVhZGVyO1xyXG5cclxuXHRcdGNvbnN0IHByb21pc2UgPSBmZXRjaCggdXJsLCBmZXRjaE9wdGlvbnMgKS50aGVuKCBmdW5jdGlvbiAoIHJlcyApIHtcclxuXHJcblx0XHRcdHJldHVybiByZXMuYmxvYigpO1xyXG5cclxuXHRcdH0gKS50aGVuKCBmdW5jdGlvbiAoIGJsb2IgKSB7XHJcblxyXG5cdFx0XHRyZXR1cm4gY3JlYXRlSW1hZ2VCaXRtYXAoIGJsb2IsIE9iamVjdC5hc3NpZ24oIHNjb3BlLm9wdGlvbnMsIHsgY29sb3JTcGFjZUNvbnZlcnNpb246ICdub25lJyB9ICkgKTtcclxuXHJcblx0XHR9ICkudGhlbiggZnVuY3Rpb24gKCBpbWFnZUJpdG1hcCApIHtcclxuXHJcblx0XHRcdENhY2hlLmFkZCggdXJsLCBpbWFnZUJpdG1hcCApO1xyXG5cclxuXHRcdFx0aWYgKCBvbkxvYWQgKSBvbkxvYWQoIGltYWdlQml0bWFwICk7XHJcblxyXG5cdFx0XHRzY29wZS5tYW5hZ2VyLml0ZW1FbmQoIHVybCApO1xyXG5cclxuXHRcdFx0cmV0dXJuIGltYWdlQml0bWFwO1xyXG5cclxuXHRcdH0gKS5jYXRjaCggZnVuY3Rpb24gKCBlICkge1xyXG5cclxuXHRcdFx0aWYgKCBvbkVycm9yICkgb25FcnJvciggZSApO1xyXG5cclxuXHRcdFx0Q2FjaGUucmVtb3ZlKCB1cmwgKTtcclxuXHJcblx0XHRcdHNjb3BlLm1hbmFnZXIuaXRlbUVycm9yKCB1cmwgKTtcclxuXHRcdFx0c2NvcGUubWFuYWdlci5pdGVtRW5kKCB1cmwgKTtcclxuXHJcblx0XHR9ICk7XHJcblxyXG5cdFx0Q2FjaGUuYWRkKCB1cmwsIHByb21pc2UgKTtcclxuXHRcdHNjb3BlLm1hbmFnZXIuaXRlbVN0YXJ0KCB1cmwgKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgSW1hZ2VCaXRtYXBMb2FkZXIgfTtcclxuIiwibGV0IF9jb250ZXh0O1xyXG5cclxuY2xhc3MgQXVkaW9Db250ZXh0IHtcclxuXHJcblx0c3RhdGljIGdldENvbnRleHQoKSB7XHJcblxyXG5cdFx0aWYgKCBfY29udGV4dCA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0X2NvbnRleHQgPSBuZXcgKCB3aW5kb3cuQXVkaW9Db250ZXh0IHx8IHdpbmRvdy53ZWJraXRBdWRpb0NvbnRleHQgKSgpO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gX2NvbnRleHQ7XHJcblxyXG5cdH1cclxuXHJcblx0c3RhdGljIHNldENvbnRleHQoIHZhbHVlICkge1xyXG5cclxuXHRcdF9jb250ZXh0ID0gdmFsdWU7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IEF1ZGlvQ29udGV4dCB9O1xyXG4iLCJpbXBvcnQgeyBBdWRpb0NvbnRleHQgfSBmcm9tICcuLi9hdWRpby9BdWRpb0NvbnRleHQuanMnO1xyXG5pbXBvcnQgeyBGaWxlTG9hZGVyIH0gZnJvbSAnLi9GaWxlTG9hZGVyLmpzJztcclxuaW1wb3J0IHsgTG9hZGVyIH0gZnJvbSAnLi9Mb2FkZXIuanMnO1xyXG5cclxuY2xhc3MgQXVkaW9Mb2FkZXIgZXh0ZW5kcyBMb2FkZXIge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggbWFuYWdlciApIHtcclxuXHJcblx0XHRzdXBlciggbWFuYWdlciApO1xyXG5cclxuXHR9XHJcblxyXG5cdGxvYWQoIHVybCwgb25Mb2FkLCBvblByb2dyZXNzLCBvbkVycm9yICkge1xyXG5cclxuXHRcdGNvbnN0IHNjb3BlID0gdGhpcztcclxuXHJcblx0XHRjb25zdCBsb2FkZXIgPSBuZXcgRmlsZUxvYWRlciggdGhpcy5tYW5hZ2VyICk7XHJcblx0XHRsb2FkZXIuc2V0UmVzcG9uc2VUeXBlKCAnYXJyYXlidWZmZXInICk7XHJcblx0XHRsb2FkZXIuc2V0UGF0aCggdGhpcy5wYXRoICk7XHJcblx0XHRsb2FkZXIuc2V0UmVxdWVzdEhlYWRlciggdGhpcy5yZXF1ZXN0SGVhZGVyICk7XHJcblx0XHRsb2FkZXIuc2V0V2l0aENyZWRlbnRpYWxzKCB0aGlzLndpdGhDcmVkZW50aWFscyApO1xyXG5cdFx0bG9hZGVyLmxvYWQoIHVybCwgZnVuY3Rpb24gKCBidWZmZXIgKSB7XHJcblxyXG5cdFx0XHR0cnkge1xyXG5cclxuXHRcdFx0XHQvLyBDcmVhdGUgYSBjb3B5IG9mIHRoZSBidWZmZXIuIFRoZSBgZGVjb2RlQXVkaW9EYXRhYCBtZXRob2RcclxuXHRcdFx0XHQvLyBkZXRhY2hlcyB0aGUgYnVmZmVyIHdoZW4gY29tcGxldGUsIHByZXZlbnRpbmcgcmV1c2UuXHJcblx0XHRcdFx0Y29uc3QgYnVmZmVyQ29weSA9IGJ1ZmZlci5zbGljZSggMCApO1xyXG5cclxuXHRcdFx0XHRjb25zdCBjb250ZXh0ID0gQXVkaW9Db250ZXh0LmdldENvbnRleHQoKTtcclxuXHRcdFx0XHRjb250ZXh0LmRlY29kZUF1ZGlvRGF0YSggYnVmZmVyQ29weSwgZnVuY3Rpb24gKCBhdWRpb0J1ZmZlciApIHtcclxuXHJcblx0XHRcdFx0XHRvbkxvYWQoIGF1ZGlvQnVmZmVyICk7XHJcblxyXG5cdFx0XHRcdH0gKS5jYXRjaCggaGFuZGxlRXJyb3IgKTtcclxuXHJcblx0XHRcdH0gY2F0Y2ggKCBlICkge1xyXG5cclxuXHRcdFx0XHRoYW5kbGVFcnJvciggZSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH0sIG9uUHJvZ3Jlc3MsIG9uRXJyb3IgKTtcclxuXHJcblx0XHRmdW5jdGlvbiBoYW5kbGVFcnJvciggZSApIHtcclxuXHJcblx0XHRcdGlmICggb25FcnJvciApIHtcclxuXHJcblx0XHRcdFx0b25FcnJvciggZSApO1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0Y29uc29sZS5lcnJvciggZSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0c2NvcGUubWFuYWdlci5pdGVtRXJyb3IoIHVybCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuXHJcbmV4cG9ydCB7IEF1ZGlvTG9hZGVyIH07XHJcbiIsImltcG9ydCB7IE1hdHJpeDQgfSBmcm9tICcuLi9tYXRoL01hdHJpeDQuanMnO1xyXG5pbXBvcnQgKiBhcyBNYXRoVXRpbHMgZnJvbSAnLi4vbWF0aC9NYXRoVXRpbHMuanMnO1xyXG5pbXBvcnQgeyBQZXJzcGVjdGl2ZUNhbWVyYSB9IGZyb20gJy4vUGVyc3BlY3RpdmVDYW1lcmEuanMnO1xyXG5cclxuY29uc3QgX2V5ZVJpZ2h0ID0gLypAX19QVVJFX18qLyBuZXcgTWF0cml4NCgpO1xyXG5jb25zdCBfZXllTGVmdCA9IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDQoKTtcclxuY29uc3QgX3Byb2plY3Rpb25NYXRyaXggPSAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXg0KCk7XHJcblxyXG5jbGFzcyBTdGVyZW9DYW1lcmEge1xyXG5cclxuXHRjb25zdHJ1Y3RvcigpIHtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSAnU3RlcmVvQ2FtZXJhJztcclxuXHJcblx0XHR0aGlzLmFzcGVjdCA9IDE7XHJcblxyXG5cdFx0dGhpcy5leWVTZXAgPSAwLjA2NDtcclxuXHJcblx0XHR0aGlzLmNhbWVyYUwgPSBuZXcgUGVyc3BlY3RpdmVDYW1lcmEoKTtcclxuXHRcdHRoaXMuY2FtZXJhTC5sYXllcnMuZW5hYmxlKCAxICk7XHJcblx0XHR0aGlzLmNhbWVyYUwubWF0cml4QXV0b1VwZGF0ZSA9IGZhbHNlO1xyXG5cclxuXHRcdHRoaXMuY2FtZXJhUiA9IG5ldyBQZXJzcGVjdGl2ZUNhbWVyYSgpO1xyXG5cdFx0dGhpcy5jYW1lcmFSLmxheWVycy5lbmFibGUoIDIgKTtcclxuXHRcdHRoaXMuY2FtZXJhUi5tYXRyaXhBdXRvVXBkYXRlID0gZmFsc2U7XHJcblxyXG5cdFx0dGhpcy5fY2FjaGUgPSB7XHJcblx0XHRcdGZvY3VzOiBudWxsLFxyXG5cdFx0XHRmb3Y6IG51bGwsXHJcblx0XHRcdGFzcGVjdDogbnVsbCxcclxuXHRcdFx0bmVhcjogbnVsbCxcclxuXHRcdFx0ZmFyOiBudWxsLFxyXG5cdFx0XHR6b29tOiBudWxsLFxyXG5cdFx0XHRleWVTZXA6IG51bGxcclxuXHRcdH07XHJcblxyXG5cdH1cclxuXHJcblx0dXBkYXRlKCBjYW1lcmEgKSB7XHJcblxyXG5cdFx0Y29uc3QgY2FjaGUgPSB0aGlzLl9jYWNoZTtcclxuXHJcblx0XHRjb25zdCBuZWVkc1VwZGF0ZSA9IGNhY2hlLmZvY3VzICE9PSBjYW1lcmEuZm9jdXMgfHwgY2FjaGUuZm92ICE9PSBjYW1lcmEuZm92IHx8XHJcblx0XHRcdGNhY2hlLmFzcGVjdCAhPT0gY2FtZXJhLmFzcGVjdCAqIHRoaXMuYXNwZWN0IHx8IGNhY2hlLm5lYXIgIT09IGNhbWVyYS5uZWFyIHx8XHJcblx0XHRcdGNhY2hlLmZhciAhPT0gY2FtZXJhLmZhciB8fCBjYWNoZS56b29tICE9PSBjYW1lcmEuem9vbSB8fCBjYWNoZS5leWVTZXAgIT09IHRoaXMuZXllU2VwO1xyXG5cclxuXHRcdGlmICggbmVlZHNVcGRhdGUgKSB7XHJcblxyXG5cdFx0XHRjYWNoZS5mb2N1cyA9IGNhbWVyYS5mb2N1cztcclxuXHRcdFx0Y2FjaGUuZm92ID0gY2FtZXJhLmZvdjtcclxuXHRcdFx0Y2FjaGUuYXNwZWN0ID0gY2FtZXJhLmFzcGVjdCAqIHRoaXMuYXNwZWN0O1xyXG5cdFx0XHRjYWNoZS5uZWFyID0gY2FtZXJhLm5lYXI7XHJcblx0XHRcdGNhY2hlLmZhciA9IGNhbWVyYS5mYXI7XHJcblx0XHRcdGNhY2hlLnpvb20gPSBjYW1lcmEuem9vbTtcclxuXHRcdFx0Y2FjaGUuZXllU2VwID0gdGhpcy5leWVTZXA7XHJcblxyXG5cdFx0XHQvLyBPZmYtYXhpcyBzdGVyZW9zY29waWMgZWZmZWN0IGJhc2VkIG9uXHJcblx0XHRcdC8vIGh0dHA6Ly9wYXVsYm91cmtlLm5ldC9zdGVyZW9ncmFwaGljcy9zdGVyZW9yZW5kZXIvXHJcblxyXG5cdFx0XHRfcHJvamVjdGlvbk1hdHJpeC5jb3B5KCBjYW1lcmEucHJvamVjdGlvbk1hdHJpeCApO1xyXG5cdFx0XHRjb25zdCBleWVTZXBIYWxmID0gY2FjaGUuZXllU2VwIC8gMjtcclxuXHRcdFx0Y29uc3QgZXllU2VwT25Qcm9qZWN0aW9uID0gZXllU2VwSGFsZiAqIGNhY2hlLm5lYXIgLyBjYWNoZS5mb2N1cztcclxuXHRcdFx0Y29uc3QgeW1heCA9ICggY2FjaGUubmVhciAqIE1hdGgudGFuKCBNYXRoVXRpbHMuREVHMlJBRCAqIGNhY2hlLmZvdiAqIDAuNSApICkgLyBjYWNoZS56b29tO1xyXG5cdFx0XHRsZXQgeG1pbiwgeG1heDtcclxuXHJcblx0XHRcdC8vIHRyYW5zbGF0ZSB4T2Zmc2V0XHJcblxyXG5cdFx0XHRfZXllTGVmdC5lbGVtZW50c1sgMTIgXSA9IC0gZXllU2VwSGFsZjtcclxuXHRcdFx0X2V5ZVJpZ2h0LmVsZW1lbnRzWyAxMiBdID0gZXllU2VwSGFsZjtcclxuXHJcblx0XHRcdC8vIGZvciBsZWZ0IGV5ZVxyXG5cclxuXHRcdFx0eG1pbiA9IC0geW1heCAqIGNhY2hlLmFzcGVjdCArIGV5ZVNlcE9uUHJvamVjdGlvbjtcclxuXHRcdFx0eG1heCA9IHltYXggKiBjYWNoZS5hc3BlY3QgKyBleWVTZXBPblByb2plY3Rpb247XHJcblxyXG5cdFx0XHRfcHJvamVjdGlvbk1hdHJpeC5lbGVtZW50c1sgMCBdID0gMiAqIGNhY2hlLm5lYXIgLyAoIHhtYXggLSB4bWluICk7XHJcblx0XHRcdF9wcm9qZWN0aW9uTWF0cml4LmVsZW1lbnRzWyA4IF0gPSAoIHhtYXggKyB4bWluICkgLyAoIHhtYXggLSB4bWluICk7XHJcblxyXG5cdFx0XHR0aGlzLmNhbWVyYUwucHJvamVjdGlvbk1hdHJpeC5jb3B5KCBfcHJvamVjdGlvbk1hdHJpeCApO1xyXG5cclxuXHRcdFx0Ly8gZm9yIHJpZ2h0IGV5ZVxyXG5cclxuXHRcdFx0eG1pbiA9IC0geW1heCAqIGNhY2hlLmFzcGVjdCAtIGV5ZVNlcE9uUHJvamVjdGlvbjtcclxuXHRcdFx0eG1heCA9IHltYXggKiBjYWNoZS5hc3BlY3QgLSBleWVTZXBPblByb2plY3Rpb247XHJcblxyXG5cdFx0XHRfcHJvamVjdGlvbk1hdHJpeC5lbGVtZW50c1sgMCBdID0gMiAqIGNhY2hlLm5lYXIgLyAoIHhtYXggLSB4bWluICk7XHJcblx0XHRcdF9wcm9qZWN0aW9uTWF0cml4LmVsZW1lbnRzWyA4IF0gPSAoIHhtYXggKyB4bWluICkgLyAoIHhtYXggLSB4bWluICk7XHJcblxyXG5cdFx0XHR0aGlzLmNhbWVyYVIucHJvamVjdGlvbk1hdHJpeC5jb3B5KCBfcHJvamVjdGlvbk1hdHJpeCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLmNhbWVyYUwubWF0cml4V29ybGQuY29weSggY2FtZXJhLm1hdHJpeFdvcmxkICkubXVsdGlwbHkoIF9leWVMZWZ0ICk7XHJcblx0XHR0aGlzLmNhbWVyYVIubWF0cml4V29ybGQuY29weSggY2FtZXJhLm1hdHJpeFdvcmxkICkubXVsdGlwbHkoIF9leWVSaWdodCApO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBTdGVyZW9DYW1lcmEgfTtcclxuIiwiY2xhc3MgQ2xvY2sge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggYXV0b1N0YXJ0ID0gdHJ1ZSApIHtcclxuXHJcblx0XHR0aGlzLmF1dG9TdGFydCA9IGF1dG9TdGFydDtcclxuXHJcblx0XHR0aGlzLnN0YXJ0VGltZSA9IDA7XHJcblx0XHR0aGlzLm9sZFRpbWUgPSAwO1xyXG5cdFx0dGhpcy5lbGFwc2VkVGltZSA9IDA7XHJcblxyXG5cdFx0dGhpcy5ydW5uaW5nID0gZmFsc2U7XHJcblxyXG5cdH1cclxuXHJcblx0c3RhcnQoKSB7XHJcblxyXG5cdFx0dGhpcy5zdGFydFRpbWUgPSBub3coKTtcclxuXHJcblx0XHR0aGlzLm9sZFRpbWUgPSB0aGlzLnN0YXJ0VGltZTtcclxuXHRcdHRoaXMuZWxhcHNlZFRpbWUgPSAwO1xyXG5cdFx0dGhpcy5ydW5uaW5nID0gdHJ1ZTtcclxuXHJcblx0fVxyXG5cclxuXHRzdG9wKCkge1xyXG5cclxuXHRcdHRoaXMuZ2V0RWxhcHNlZFRpbWUoKTtcclxuXHRcdHRoaXMucnVubmluZyA9IGZhbHNlO1xyXG5cdFx0dGhpcy5hdXRvU3RhcnQgPSBmYWxzZTtcclxuXHJcblx0fVxyXG5cclxuXHRnZXRFbGFwc2VkVGltZSgpIHtcclxuXHJcblx0XHR0aGlzLmdldERlbHRhKCk7XHJcblx0XHRyZXR1cm4gdGhpcy5lbGFwc2VkVGltZTtcclxuXHJcblx0fVxyXG5cclxuXHRnZXREZWx0YSgpIHtcclxuXHJcblx0XHRsZXQgZGlmZiA9IDA7XHJcblxyXG5cdFx0aWYgKCB0aGlzLmF1dG9TdGFydCAmJiAhIHRoaXMucnVubmluZyApIHtcclxuXHJcblx0XHRcdHRoaXMuc3RhcnQoKTtcclxuXHRcdFx0cmV0dXJuIDA7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggdGhpcy5ydW5uaW5nICkge1xyXG5cclxuXHRcdFx0Y29uc3QgbmV3VGltZSA9IG5vdygpO1xyXG5cclxuXHRcdFx0ZGlmZiA9ICggbmV3VGltZSAtIHRoaXMub2xkVGltZSApIC8gMTAwMDtcclxuXHRcdFx0dGhpcy5vbGRUaW1lID0gbmV3VGltZTtcclxuXHJcblx0XHRcdHRoaXMuZWxhcHNlZFRpbWUgKz0gZGlmZjtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIGRpZmY7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmZ1bmN0aW9uIG5vdygpIHtcclxuXHJcblx0cmV0dXJuICggdHlwZW9mIHBlcmZvcm1hbmNlID09PSAndW5kZWZpbmVkJyA/IERhdGUgOiBwZXJmb3JtYW5jZSApLm5vdygpOyAvLyBzZWUgIzEwNzMyXHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBDbG9jayB9O1xyXG4iLCJpbXBvcnQgeyBWZWN0b3IzIH0gZnJvbSAnLi4vbWF0aC9WZWN0b3IzLmpzJztcclxuaW1wb3J0IHsgUXVhdGVybmlvbiB9IGZyb20gJy4uL21hdGgvUXVhdGVybmlvbi5qcyc7XHJcbmltcG9ydCB7IENsb2NrIH0gZnJvbSAnLi4vY29yZS9DbG9jay5qcyc7XHJcbmltcG9ydCB7IE9iamVjdDNEIH0gZnJvbSAnLi4vY29yZS9PYmplY3QzRC5qcyc7XHJcbmltcG9ydCB7IEF1ZGlvQ29udGV4dCB9IGZyb20gJy4vQXVkaW9Db250ZXh0LmpzJztcclxuXHJcbmNvbnN0IF9wb3NpdGlvbiA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuY29uc3QgX3F1YXRlcm5pb24gPSAvKkBfX1BVUkVfXyovIG5ldyBRdWF0ZXJuaW9uKCk7XHJcbmNvbnN0IF9zY2FsZSA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuY29uc3QgX29yaWVudGF0aW9uID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5cclxuY2xhc3MgQXVkaW9MaXN0ZW5lciBleHRlbmRzIE9iamVjdDNEIHtcclxuXHJcblx0Y29uc3RydWN0b3IoKSB7XHJcblxyXG5cdFx0c3VwZXIoKTtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSAnQXVkaW9MaXN0ZW5lcic7XHJcblxyXG5cdFx0dGhpcy5jb250ZXh0ID0gQXVkaW9Db250ZXh0LmdldENvbnRleHQoKTtcclxuXHJcblx0XHR0aGlzLmdhaW4gPSB0aGlzLmNvbnRleHQuY3JlYXRlR2FpbigpO1xyXG5cdFx0dGhpcy5nYWluLmNvbm5lY3QoIHRoaXMuY29udGV4dC5kZXN0aW5hdGlvbiApO1xyXG5cclxuXHRcdHRoaXMuZmlsdGVyID0gbnVsbDtcclxuXHJcblx0XHR0aGlzLnRpbWVEZWx0YSA9IDA7XHJcblxyXG5cdFx0Ly8gcHJpdmF0ZVxyXG5cclxuXHRcdHRoaXMuX2Nsb2NrID0gbmV3IENsb2NrKCk7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0SW5wdXQoKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuZ2FpbjtcclxuXHJcblx0fVxyXG5cclxuXHRyZW1vdmVGaWx0ZXIoKSB7XHJcblxyXG5cdFx0aWYgKCB0aGlzLmZpbHRlciAhPT0gbnVsbCApIHtcclxuXHJcblx0XHRcdHRoaXMuZ2Fpbi5kaXNjb25uZWN0KCB0aGlzLmZpbHRlciApO1xyXG5cdFx0XHR0aGlzLmZpbHRlci5kaXNjb25uZWN0KCB0aGlzLmNvbnRleHQuZGVzdGluYXRpb24gKTtcclxuXHRcdFx0dGhpcy5nYWluLmNvbm5lY3QoIHRoaXMuY29udGV4dC5kZXN0aW5hdGlvbiApO1xyXG5cdFx0XHR0aGlzLmZpbHRlciA9IG51bGw7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldEZpbHRlcigpIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5maWx0ZXI7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0RmlsdGVyKCB2YWx1ZSApIHtcclxuXHJcblx0XHRpZiAoIHRoaXMuZmlsdGVyICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0dGhpcy5nYWluLmRpc2Nvbm5lY3QoIHRoaXMuZmlsdGVyICk7XHJcblx0XHRcdHRoaXMuZmlsdGVyLmRpc2Nvbm5lY3QoIHRoaXMuY29udGV4dC5kZXN0aW5hdGlvbiApO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHR0aGlzLmdhaW4uZGlzY29ubmVjdCggdGhpcy5jb250ZXh0LmRlc3RpbmF0aW9uICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMuZmlsdGVyID0gdmFsdWU7XHJcblx0XHR0aGlzLmdhaW4uY29ubmVjdCggdGhpcy5maWx0ZXIgKTtcclxuXHRcdHRoaXMuZmlsdGVyLmNvbm5lY3QoIHRoaXMuY29udGV4dC5kZXN0aW5hdGlvbiApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldE1hc3RlclZvbHVtZSgpIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5nYWluLmdhaW4udmFsdWU7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0TWFzdGVyVm9sdW1lKCB2YWx1ZSApIHtcclxuXHJcblx0XHR0aGlzLmdhaW4uZ2Fpbi5zZXRUYXJnZXRBdFRpbWUoIHZhbHVlLCB0aGlzLmNvbnRleHQuY3VycmVudFRpbWUsIDAuMDEgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHR1cGRhdGVNYXRyaXhXb3JsZCggZm9yY2UgKSB7XHJcblxyXG5cdFx0c3VwZXIudXBkYXRlTWF0cml4V29ybGQoIGZvcmNlICk7XHJcblxyXG5cdFx0Y29uc3QgbGlzdGVuZXIgPSB0aGlzLmNvbnRleHQubGlzdGVuZXI7XHJcblx0XHRjb25zdCB1cCA9IHRoaXMudXA7XHJcblxyXG5cdFx0dGhpcy50aW1lRGVsdGEgPSB0aGlzLl9jbG9jay5nZXREZWx0YSgpO1xyXG5cclxuXHRcdHRoaXMubWF0cml4V29ybGQuZGVjb21wb3NlKCBfcG9zaXRpb24sIF9xdWF0ZXJuaW9uLCBfc2NhbGUgKTtcclxuXHJcblx0XHRfb3JpZW50YXRpb24uc2V0KCAwLCAwLCAtIDEgKS5hcHBseVF1YXRlcm5pb24oIF9xdWF0ZXJuaW9uICk7XHJcblxyXG5cdFx0aWYgKCBsaXN0ZW5lci5wb3NpdGlvblggKSB7XHJcblxyXG5cdFx0XHQvLyBjb2RlIHBhdGggZm9yIENocm9tZSAoc2VlICMxNDM5MylcclxuXHJcblx0XHRcdGNvbnN0IGVuZFRpbWUgPSB0aGlzLmNvbnRleHQuY3VycmVudFRpbWUgKyB0aGlzLnRpbWVEZWx0YTtcclxuXHJcblx0XHRcdGxpc3RlbmVyLnBvc2l0aW9uWC5saW5lYXJSYW1wVG9WYWx1ZUF0VGltZSggX3Bvc2l0aW9uLngsIGVuZFRpbWUgKTtcclxuXHRcdFx0bGlzdGVuZXIucG9zaXRpb25ZLmxpbmVhclJhbXBUb1ZhbHVlQXRUaW1lKCBfcG9zaXRpb24ueSwgZW5kVGltZSApO1xyXG5cdFx0XHRsaXN0ZW5lci5wb3NpdGlvbloubGluZWFyUmFtcFRvVmFsdWVBdFRpbWUoIF9wb3NpdGlvbi56LCBlbmRUaW1lICk7XHJcblx0XHRcdGxpc3RlbmVyLmZvcndhcmRYLmxpbmVhclJhbXBUb1ZhbHVlQXRUaW1lKCBfb3JpZW50YXRpb24ueCwgZW5kVGltZSApO1xyXG5cdFx0XHRsaXN0ZW5lci5mb3J3YXJkWS5saW5lYXJSYW1wVG9WYWx1ZUF0VGltZSggX29yaWVudGF0aW9uLnksIGVuZFRpbWUgKTtcclxuXHRcdFx0bGlzdGVuZXIuZm9yd2FyZFoubGluZWFyUmFtcFRvVmFsdWVBdFRpbWUoIF9vcmllbnRhdGlvbi56LCBlbmRUaW1lICk7XHJcblx0XHRcdGxpc3RlbmVyLnVwWC5saW5lYXJSYW1wVG9WYWx1ZUF0VGltZSggdXAueCwgZW5kVGltZSApO1xyXG5cdFx0XHRsaXN0ZW5lci51cFkubGluZWFyUmFtcFRvVmFsdWVBdFRpbWUoIHVwLnksIGVuZFRpbWUgKTtcclxuXHRcdFx0bGlzdGVuZXIudXBaLmxpbmVhclJhbXBUb1ZhbHVlQXRUaW1lKCB1cC56LCBlbmRUaW1lICk7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdGxpc3RlbmVyLnNldFBvc2l0aW9uKCBfcG9zaXRpb24ueCwgX3Bvc2l0aW9uLnksIF9wb3NpdGlvbi56ICk7XHJcblx0XHRcdGxpc3RlbmVyLnNldE9yaWVudGF0aW9uKCBfb3JpZW50YXRpb24ueCwgX29yaWVudGF0aW9uLnksIF9vcmllbnRhdGlvbi56LCB1cC54LCB1cC55LCB1cC56ICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBBdWRpb0xpc3RlbmVyIH07XHJcbiIsImltcG9ydCB7IE9iamVjdDNEIH0gZnJvbSAnLi4vY29yZS9PYmplY3QzRC5qcyc7XHJcblxyXG5jbGFzcyBBdWRpbyBleHRlbmRzIE9iamVjdDNEIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIGxpc3RlbmVyICkge1xyXG5cclxuXHRcdHN1cGVyKCk7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ0F1ZGlvJztcclxuXHJcblx0XHR0aGlzLmxpc3RlbmVyID0gbGlzdGVuZXI7XHJcblx0XHR0aGlzLmNvbnRleHQgPSBsaXN0ZW5lci5jb250ZXh0O1xyXG5cclxuXHRcdHRoaXMuZ2FpbiA9IHRoaXMuY29udGV4dC5jcmVhdGVHYWluKCk7XHJcblx0XHR0aGlzLmdhaW4uY29ubmVjdCggbGlzdGVuZXIuZ2V0SW5wdXQoKSApO1xyXG5cclxuXHRcdHRoaXMuYXV0b3BsYXkgPSBmYWxzZTtcclxuXHJcblx0XHR0aGlzLmJ1ZmZlciA9IG51bGw7XHJcblx0XHR0aGlzLmRldHVuZSA9IDA7XHJcblx0XHR0aGlzLmxvb3AgPSBmYWxzZTtcclxuXHRcdHRoaXMubG9vcFN0YXJ0ID0gMDtcclxuXHRcdHRoaXMubG9vcEVuZCA9IDA7XHJcblx0XHR0aGlzLm9mZnNldCA9IDA7XHJcblx0XHR0aGlzLmR1cmF0aW9uID0gdW5kZWZpbmVkO1xyXG5cdFx0dGhpcy5wbGF5YmFja1JhdGUgPSAxO1xyXG5cdFx0dGhpcy5pc1BsYXlpbmcgPSBmYWxzZTtcclxuXHRcdHRoaXMuaGFzUGxheWJhY2tDb250cm9sID0gdHJ1ZTtcclxuXHRcdHRoaXMuc291cmNlID0gbnVsbDtcclxuXHRcdHRoaXMuc291cmNlVHlwZSA9ICdlbXB0eSc7XHJcblxyXG5cdFx0dGhpcy5fc3RhcnRlZEF0ID0gMDtcclxuXHRcdHRoaXMuX3Byb2dyZXNzID0gMDtcclxuXHRcdHRoaXMuX2Nvbm5lY3RlZCA9IGZhbHNlO1xyXG5cclxuXHRcdHRoaXMuZmlsdGVycyA9IFtdO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldE91dHB1dCgpIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5nYWluO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldE5vZGVTb3VyY2UoIGF1ZGlvTm9kZSApIHtcclxuXHJcblx0XHR0aGlzLmhhc1BsYXliYWNrQ29udHJvbCA9IGZhbHNlO1xyXG5cdFx0dGhpcy5zb3VyY2VUeXBlID0gJ2F1ZGlvTm9kZSc7XHJcblx0XHR0aGlzLnNvdXJjZSA9IGF1ZGlvTm9kZTtcclxuXHRcdHRoaXMuY29ubmVjdCgpO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldE1lZGlhRWxlbWVudFNvdXJjZSggbWVkaWFFbGVtZW50ICkge1xyXG5cclxuXHRcdHRoaXMuaGFzUGxheWJhY2tDb250cm9sID0gZmFsc2U7XHJcblx0XHR0aGlzLnNvdXJjZVR5cGUgPSAnbWVkaWFOb2RlJztcclxuXHRcdHRoaXMuc291cmNlID0gdGhpcy5jb250ZXh0LmNyZWF0ZU1lZGlhRWxlbWVudFNvdXJjZSggbWVkaWFFbGVtZW50ICk7XHJcblx0XHR0aGlzLmNvbm5lY3QoKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRNZWRpYVN0cmVhbVNvdXJjZSggbWVkaWFTdHJlYW0gKSB7XHJcblxyXG5cdFx0dGhpcy5oYXNQbGF5YmFja0NvbnRyb2wgPSBmYWxzZTtcclxuXHRcdHRoaXMuc291cmNlVHlwZSA9ICdtZWRpYVN0cmVhbU5vZGUnO1xyXG5cdFx0dGhpcy5zb3VyY2UgPSB0aGlzLmNvbnRleHQuY3JlYXRlTWVkaWFTdHJlYW1Tb3VyY2UoIG1lZGlhU3RyZWFtICk7XHJcblx0XHR0aGlzLmNvbm5lY3QoKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRCdWZmZXIoIGF1ZGlvQnVmZmVyICkge1xyXG5cclxuXHRcdHRoaXMuYnVmZmVyID0gYXVkaW9CdWZmZXI7XHJcblx0XHR0aGlzLnNvdXJjZVR5cGUgPSAnYnVmZmVyJztcclxuXHJcblx0XHRpZiAoIHRoaXMuYXV0b3BsYXkgKSB0aGlzLnBsYXkoKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRwbGF5KCBkZWxheSA9IDAgKSB7XHJcblxyXG5cdFx0aWYgKCB0aGlzLmlzUGxheWluZyA9PT0gdHJ1ZSApIHtcclxuXHJcblx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLkF1ZGlvOiBBdWRpbyBpcyBhbHJlYWR5IHBsYXlpbmcuJyApO1xyXG5cdFx0XHRyZXR1cm47XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggdGhpcy5oYXNQbGF5YmFja0NvbnRyb2wgPT09IGZhbHNlICkge1xyXG5cclxuXHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuQXVkaW86IHRoaXMgQXVkaW8gaGFzIG5vIHBsYXliYWNrIGNvbnRyb2wuJyApO1xyXG5cdFx0XHRyZXR1cm47XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMuX3N0YXJ0ZWRBdCA9IHRoaXMuY29udGV4dC5jdXJyZW50VGltZSArIGRlbGF5O1xyXG5cclxuXHRcdGNvbnN0IHNvdXJjZSA9IHRoaXMuY29udGV4dC5jcmVhdGVCdWZmZXJTb3VyY2UoKTtcclxuXHRcdHNvdXJjZS5idWZmZXIgPSB0aGlzLmJ1ZmZlcjtcclxuXHRcdHNvdXJjZS5sb29wID0gdGhpcy5sb29wO1xyXG5cdFx0c291cmNlLmxvb3BTdGFydCA9IHRoaXMubG9vcFN0YXJ0O1xyXG5cdFx0c291cmNlLmxvb3BFbmQgPSB0aGlzLmxvb3BFbmQ7XHJcblx0XHRzb3VyY2Uub25lbmRlZCA9IHRoaXMub25FbmRlZC5iaW5kKCB0aGlzICk7XHJcblx0XHRzb3VyY2Uuc3RhcnQoIHRoaXMuX3N0YXJ0ZWRBdCwgdGhpcy5fcHJvZ3Jlc3MgKyB0aGlzLm9mZnNldCwgdGhpcy5kdXJhdGlvbiApO1xyXG5cclxuXHRcdHRoaXMuaXNQbGF5aW5nID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLnNvdXJjZSA9IHNvdXJjZTtcclxuXHJcblx0XHR0aGlzLnNldERldHVuZSggdGhpcy5kZXR1bmUgKTtcclxuXHRcdHRoaXMuc2V0UGxheWJhY2tSYXRlKCB0aGlzLnBsYXliYWNrUmF0ZSApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzLmNvbm5lY3QoKTtcclxuXHJcblx0fVxyXG5cclxuXHRwYXVzZSgpIHtcclxuXHJcblx0XHRpZiAoIHRoaXMuaGFzUGxheWJhY2tDb250cm9sID09PSBmYWxzZSApIHtcclxuXHJcblx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLkF1ZGlvOiB0aGlzIEF1ZGlvIGhhcyBubyBwbGF5YmFjayBjb250cm9sLicgKTtcclxuXHRcdFx0cmV0dXJuO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHRoaXMuaXNQbGF5aW5nID09PSB0cnVlICkge1xyXG5cclxuXHRcdFx0Ly8gdXBkYXRlIGN1cnJlbnQgcHJvZ3Jlc3NcclxuXHJcblx0XHRcdHRoaXMuX3Byb2dyZXNzICs9IE1hdGgubWF4KCB0aGlzLmNvbnRleHQuY3VycmVudFRpbWUgLSB0aGlzLl9zdGFydGVkQXQsIDAgKSAqIHRoaXMucGxheWJhY2tSYXRlO1xyXG5cclxuXHRcdFx0aWYgKCB0aGlzLmxvb3AgPT09IHRydWUgKSB7XHJcblxyXG5cdFx0XHRcdC8vIGVuc3VyZSBfcHJvZ3Jlc3MgZG9lcyBub3QgZXhjZWVkIGR1cmF0aW9uIHdpdGggbG9vcGVkIGF1ZGlvc1xyXG5cclxuXHRcdFx0XHR0aGlzLl9wcm9ncmVzcyA9IHRoaXMuX3Byb2dyZXNzICUgKCB0aGlzLmR1cmF0aW9uIHx8IHRoaXMuYnVmZmVyLmR1cmF0aW9uICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHR0aGlzLnNvdXJjZS5zdG9wKCk7XHJcblx0XHRcdHRoaXMuc291cmNlLm9uZW5kZWQgPSBudWxsO1xyXG5cclxuXHRcdFx0dGhpcy5pc1BsYXlpbmcgPSBmYWxzZTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0c3RvcCgpIHtcclxuXHJcblx0XHRpZiAoIHRoaXMuaGFzUGxheWJhY2tDb250cm9sID09PSBmYWxzZSApIHtcclxuXHJcblx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLkF1ZGlvOiB0aGlzIEF1ZGlvIGhhcyBubyBwbGF5YmFjayBjb250cm9sLicgKTtcclxuXHRcdFx0cmV0dXJuO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLl9wcm9ncmVzcyA9IDA7XHJcblxyXG5cdFx0aWYgKCB0aGlzLnNvdXJjZSAhPT0gbnVsbCApIHtcclxuXHJcblx0XHRcdHRoaXMuc291cmNlLnN0b3AoKTtcclxuXHRcdFx0dGhpcy5zb3VyY2Uub25lbmRlZCA9IG51bGw7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMuaXNQbGF5aW5nID0gZmFsc2U7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Y29ubmVjdCgpIHtcclxuXHJcblx0XHRpZiAoIHRoaXMuZmlsdGVycy5sZW5ndGggPiAwICkge1xyXG5cclxuXHRcdFx0dGhpcy5zb3VyY2UuY29ubmVjdCggdGhpcy5maWx0ZXJzWyAwIF0gKTtcclxuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMSwgbCA9IHRoaXMuZmlsdGVycy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHR0aGlzLmZpbHRlcnNbIGkgLSAxIF0uY29ubmVjdCggdGhpcy5maWx0ZXJzWyBpIF0gKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHRoaXMuZmlsdGVyc1sgdGhpcy5maWx0ZXJzLmxlbmd0aCAtIDEgXS5jb25uZWN0KCB0aGlzLmdldE91dHB1dCgpICk7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdHRoaXMuc291cmNlLmNvbm5lY3QoIHRoaXMuZ2V0T3V0cHV0KCkgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5fY29ubmVjdGVkID0gdHJ1ZTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRkaXNjb25uZWN0KCkge1xyXG5cclxuXHRcdGlmICggdGhpcy5fY29ubmVjdGVkID09PSBmYWxzZSApIHtcclxuXHJcblx0XHRcdHJldHVybjtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCB0aGlzLmZpbHRlcnMubGVuZ3RoID4gMCApIHtcclxuXHJcblx0XHRcdHRoaXMuc291cmNlLmRpc2Nvbm5lY3QoIHRoaXMuZmlsdGVyc1sgMCBdICk7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDEsIGwgPSB0aGlzLmZpbHRlcnMubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0dGhpcy5maWx0ZXJzWyBpIC0gMSBdLmRpc2Nvbm5lY3QoIHRoaXMuZmlsdGVyc1sgaSBdICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHR0aGlzLmZpbHRlcnNbIHRoaXMuZmlsdGVycy5sZW5ndGggLSAxIF0uZGlzY29ubmVjdCggdGhpcy5nZXRPdXRwdXQoKSApO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHR0aGlzLnNvdXJjZS5kaXNjb25uZWN0KCB0aGlzLmdldE91dHB1dCgpICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMuX2Nvbm5lY3RlZCA9IGZhbHNlO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldEZpbHRlcnMoKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuZmlsdGVycztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRGaWx0ZXJzKCB2YWx1ZSApIHtcclxuXHJcblx0XHRpZiAoICEgdmFsdWUgKSB2YWx1ZSA9IFtdO1xyXG5cclxuXHRcdGlmICggdGhpcy5fY29ubmVjdGVkID09PSB0cnVlICkge1xyXG5cclxuXHRcdFx0dGhpcy5kaXNjb25uZWN0KCk7XHJcblx0XHRcdHRoaXMuZmlsdGVycyA9IHZhbHVlLnNsaWNlKCk7XHJcblx0XHRcdHRoaXMuY29ubmVjdCgpO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHR0aGlzLmZpbHRlcnMgPSB2YWx1ZS5zbGljZSgpO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXREZXR1bmUoIHZhbHVlICkge1xyXG5cclxuXHRcdHRoaXMuZGV0dW5lID0gdmFsdWU7XHJcblxyXG5cdFx0aWYgKCB0aGlzLmlzUGxheWluZyA9PT0gdHJ1ZSAmJiB0aGlzLnNvdXJjZS5kZXR1bmUgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdHRoaXMuc291cmNlLmRldHVuZS5zZXRUYXJnZXRBdFRpbWUoIHRoaXMuZGV0dW5lLCB0aGlzLmNvbnRleHQuY3VycmVudFRpbWUsIDAuMDEgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0RGV0dW5lKCkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLmRldHVuZTtcclxuXHJcblx0fVxyXG5cclxuXHRnZXRGaWx0ZXIoKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuZ2V0RmlsdGVycygpWyAwIF07XHJcblxyXG5cdH1cclxuXHJcblx0c2V0RmlsdGVyKCBmaWx0ZXIgKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuc2V0RmlsdGVycyggZmlsdGVyID8gWyBmaWx0ZXIgXSA6IFtdICk7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0UGxheWJhY2tSYXRlKCB2YWx1ZSApIHtcclxuXHJcblx0XHRpZiAoIHRoaXMuaGFzUGxheWJhY2tDb250cm9sID09PSBmYWxzZSApIHtcclxuXHJcblx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLkF1ZGlvOiB0aGlzIEF1ZGlvIGhhcyBubyBwbGF5YmFjayBjb250cm9sLicgKTtcclxuXHRcdFx0cmV0dXJuO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLnBsYXliYWNrUmF0ZSA9IHZhbHVlO1xyXG5cclxuXHRcdGlmICggdGhpcy5pc1BsYXlpbmcgPT09IHRydWUgKSB7XHJcblxyXG5cdFx0XHR0aGlzLnNvdXJjZS5wbGF5YmFja1JhdGUuc2V0VGFyZ2V0QXRUaW1lKCB0aGlzLnBsYXliYWNrUmF0ZSwgdGhpcy5jb250ZXh0LmN1cnJlbnRUaW1lLCAwLjAxICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldFBsYXliYWNrUmF0ZSgpIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5wbGF5YmFja1JhdGU7XHJcblxyXG5cdH1cclxuXHJcblx0b25FbmRlZCgpIHtcclxuXHJcblx0XHR0aGlzLmlzUGxheWluZyA9IGZhbHNlO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldExvb3AoKSB7XHJcblxyXG5cdFx0aWYgKCB0aGlzLmhhc1BsYXliYWNrQ29udHJvbCA9PT0gZmFsc2UgKSB7XHJcblxyXG5cdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5BdWRpbzogdGhpcyBBdWRpbyBoYXMgbm8gcGxheWJhY2sgY29udHJvbC4nICk7XHJcblx0XHRcdHJldHVybiBmYWxzZTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMubG9vcDtcclxuXHJcblx0fVxyXG5cclxuXHRzZXRMb29wKCB2YWx1ZSApIHtcclxuXHJcblx0XHRpZiAoIHRoaXMuaGFzUGxheWJhY2tDb250cm9sID09PSBmYWxzZSApIHtcclxuXHJcblx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLkF1ZGlvOiB0aGlzIEF1ZGlvIGhhcyBubyBwbGF5YmFjayBjb250cm9sLicgKTtcclxuXHRcdFx0cmV0dXJuO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLmxvb3AgPSB2YWx1ZTtcclxuXHJcblx0XHRpZiAoIHRoaXMuaXNQbGF5aW5nID09PSB0cnVlICkge1xyXG5cclxuXHRcdFx0dGhpcy5zb3VyY2UubG9vcCA9IHRoaXMubG9vcDtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0TG9vcFN0YXJ0KCB2YWx1ZSApIHtcclxuXHJcblx0XHR0aGlzLmxvb3BTdGFydCA9IHZhbHVlO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldExvb3BFbmQoIHZhbHVlICkge1xyXG5cclxuXHRcdHRoaXMubG9vcEVuZCA9IHZhbHVlO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldFZvbHVtZSgpIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5nYWluLmdhaW4udmFsdWU7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0Vm9sdW1lKCB2YWx1ZSApIHtcclxuXHJcblx0XHR0aGlzLmdhaW4uZ2Fpbi5zZXRUYXJnZXRBdFRpbWUoIHZhbHVlLCB0aGlzLmNvbnRleHQuY3VycmVudFRpbWUsIDAuMDEgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgQXVkaW8gfTtcclxuIiwiaW1wb3J0IHsgVmVjdG9yMyB9IGZyb20gJy4uL21hdGgvVmVjdG9yMy5qcyc7XHJcbmltcG9ydCB7IFF1YXRlcm5pb24gfSBmcm9tICcuLi9tYXRoL1F1YXRlcm5pb24uanMnO1xyXG5pbXBvcnQgeyBBdWRpbyB9IGZyb20gJy4vQXVkaW8uanMnO1xyXG5cclxuY29uc3QgX3Bvc2l0aW9uID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5jb25zdCBfcXVhdGVybmlvbiA9IC8qQF9fUFVSRV9fKi8gbmV3IFF1YXRlcm5pb24oKTtcclxuY29uc3QgX3NjYWxlID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5jb25zdCBfb3JpZW50YXRpb24gPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XHJcblxyXG5jbGFzcyBQb3NpdGlvbmFsQXVkaW8gZXh0ZW5kcyBBdWRpbyB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBsaXN0ZW5lciApIHtcclxuXHJcblx0XHRzdXBlciggbGlzdGVuZXIgKTtcclxuXHJcblx0XHR0aGlzLnBhbm5lciA9IHRoaXMuY29udGV4dC5jcmVhdGVQYW5uZXIoKTtcclxuXHRcdHRoaXMucGFubmVyLnBhbm5pbmdNb2RlbCA9ICdIUlRGJztcclxuXHRcdHRoaXMucGFubmVyLmNvbm5lY3QoIHRoaXMuZ2FpbiApO1xyXG5cclxuXHR9XHJcblxyXG5cdGNvbm5lY3QoKSB7XHJcblxyXG5cdFx0c3VwZXIuY29ubmVjdCgpO1xyXG5cclxuXHRcdHRoaXMucGFubmVyLmNvbm5lY3QoIHRoaXMuZ2FpbiApO1xyXG5cclxuXHR9XHJcblxyXG5cdGRpc2Nvbm5lY3QoKSB7XHJcblxyXG5cdFx0c3VwZXIuZGlzY29ubmVjdCgpO1xyXG5cclxuXHRcdHRoaXMucGFubmVyLmRpc2Nvbm5lY3QoIHRoaXMuZ2FpbiApO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldE91dHB1dCgpIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5wYW5uZXI7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0UmVmRGlzdGFuY2UoKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMucGFubmVyLnJlZkRpc3RhbmNlO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldFJlZkRpc3RhbmNlKCB2YWx1ZSApIHtcclxuXHJcblx0XHR0aGlzLnBhbm5lci5yZWZEaXN0YW5jZSA9IHZhbHVlO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldFJvbGxvZmZGYWN0b3IoKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMucGFubmVyLnJvbGxvZmZGYWN0b3I7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0Um9sbG9mZkZhY3RvciggdmFsdWUgKSB7XHJcblxyXG5cdFx0dGhpcy5wYW5uZXIucm9sbG9mZkZhY3RvciA9IHZhbHVlO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldERpc3RhbmNlTW9kZWwoKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMucGFubmVyLmRpc3RhbmNlTW9kZWw7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0RGlzdGFuY2VNb2RlbCggdmFsdWUgKSB7XHJcblxyXG5cdFx0dGhpcy5wYW5uZXIuZGlzdGFuY2VNb2RlbCA9IHZhbHVlO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldE1heERpc3RhbmNlKCkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLnBhbm5lci5tYXhEaXN0YW5jZTtcclxuXHJcblx0fVxyXG5cclxuXHRzZXRNYXhEaXN0YW5jZSggdmFsdWUgKSB7XHJcblxyXG5cdFx0dGhpcy5wYW5uZXIubWF4RGlzdGFuY2UgPSB2YWx1ZTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXREaXJlY3Rpb25hbENvbmUoIGNvbmVJbm5lckFuZ2xlLCBjb25lT3V0ZXJBbmdsZSwgY29uZU91dGVyR2FpbiApIHtcclxuXHJcblx0XHR0aGlzLnBhbm5lci5jb25lSW5uZXJBbmdsZSA9IGNvbmVJbm5lckFuZ2xlO1xyXG5cdFx0dGhpcy5wYW5uZXIuY29uZU91dGVyQW5nbGUgPSBjb25lT3V0ZXJBbmdsZTtcclxuXHRcdHRoaXMucGFubmVyLmNvbmVPdXRlckdhaW4gPSBjb25lT3V0ZXJHYWluO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHVwZGF0ZU1hdHJpeFdvcmxkKCBmb3JjZSApIHtcclxuXHJcblx0XHRzdXBlci51cGRhdGVNYXRyaXhXb3JsZCggZm9yY2UgKTtcclxuXHJcblx0XHRpZiAoIHRoaXMuaGFzUGxheWJhY2tDb250cm9sID09PSB0cnVlICYmIHRoaXMuaXNQbGF5aW5nID09PSBmYWxzZSApIHJldHVybjtcclxuXHJcblx0XHR0aGlzLm1hdHJpeFdvcmxkLmRlY29tcG9zZSggX3Bvc2l0aW9uLCBfcXVhdGVybmlvbiwgX3NjYWxlICk7XHJcblxyXG5cdFx0X29yaWVudGF0aW9uLnNldCggMCwgMCwgMSApLmFwcGx5UXVhdGVybmlvbiggX3F1YXRlcm5pb24gKTtcclxuXHJcblx0XHRjb25zdCBwYW5uZXIgPSB0aGlzLnBhbm5lcjtcclxuXHJcblx0XHRpZiAoIHBhbm5lci5wb3NpdGlvblggKSB7XHJcblxyXG5cdFx0XHQvLyBjb2RlIHBhdGggZm9yIENocm9tZSBhbmQgRmlyZWZveCAoc2VlICMxNDM5MylcclxuXHJcblx0XHRcdGNvbnN0IGVuZFRpbWUgPSB0aGlzLmNvbnRleHQuY3VycmVudFRpbWUgKyB0aGlzLmxpc3RlbmVyLnRpbWVEZWx0YTtcclxuXHJcblx0XHRcdHBhbm5lci5wb3NpdGlvblgubGluZWFyUmFtcFRvVmFsdWVBdFRpbWUoIF9wb3NpdGlvbi54LCBlbmRUaW1lICk7XHJcblx0XHRcdHBhbm5lci5wb3NpdGlvblkubGluZWFyUmFtcFRvVmFsdWVBdFRpbWUoIF9wb3NpdGlvbi55LCBlbmRUaW1lICk7XHJcblx0XHRcdHBhbm5lci5wb3NpdGlvbloubGluZWFyUmFtcFRvVmFsdWVBdFRpbWUoIF9wb3NpdGlvbi56LCBlbmRUaW1lICk7XHJcblx0XHRcdHBhbm5lci5vcmllbnRhdGlvblgubGluZWFyUmFtcFRvVmFsdWVBdFRpbWUoIF9vcmllbnRhdGlvbi54LCBlbmRUaW1lICk7XHJcblx0XHRcdHBhbm5lci5vcmllbnRhdGlvblkubGluZWFyUmFtcFRvVmFsdWVBdFRpbWUoIF9vcmllbnRhdGlvbi55LCBlbmRUaW1lICk7XHJcblx0XHRcdHBhbm5lci5vcmllbnRhdGlvbloubGluZWFyUmFtcFRvVmFsdWVBdFRpbWUoIF9vcmllbnRhdGlvbi56LCBlbmRUaW1lICk7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdHBhbm5lci5zZXRQb3NpdGlvbiggX3Bvc2l0aW9uLngsIF9wb3NpdGlvbi55LCBfcG9zaXRpb24ueiApO1xyXG5cdFx0XHRwYW5uZXIuc2V0T3JpZW50YXRpb24oIF9vcmllbnRhdGlvbi54LCBfb3JpZW50YXRpb24ueSwgX29yaWVudGF0aW9uLnogKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IFBvc2l0aW9uYWxBdWRpbyB9O1xyXG4iLCJjbGFzcyBBdWRpb0FuYWx5c2VyIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIGF1ZGlvLCBmZnRTaXplID0gMjA0OCApIHtcclxuXHJcblx0XHR0aGlzLmFuYWx5c2VyID0gYXVkaW8uY29udGV4dC5jcmVhdGVBbmFseXNlcigpO1xyXG5cdFx0dGhpcy5hbmFseXNlci5mZnRTaXplID0gZmZ0U2l6ZTtcclxuXHJcblx0XHR0aGlzLmRhdGEgPSBuZXcgVWludDhBcnJheSggdGhpcy5hbmFseXNlci5mcmVxdWVuY3lCaW5Db3VudCApO1xyXG5cclxuXHRcdGF1ZGlvLmdldE91dHB1dCgpLmNvbm5lY3QoIHRoaXMuYW5hbHlzZXIgKTtcclxuXHJcblx0fVxyXG5cclxuXHJcblx0Z2V0RnJlcXVlbmN5RGF0YSgpIHtcclxuXHJcblx0XHR0aGlzLmFuYWx5c2VyLmdldEJ5dGVGcmVxdWVuY3lEYXRhKCB0aGlzLmRhdGEgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5kYXRhO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldEF2ZXJhZ2VGcmVxdWVuY3koKSB7XHJcblxyXG5cdFx0bGV0IHZhbHVlID0gMDtcclxuXHRcdGNvbnN0IGRhdGEgPSB0aGlzLmdldEZyZXF1ZW5jeURhdGEoKTtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBkYXRhLmxlbmd0aDsgaSArKyApIHtcclxuXHJcblx0XHRcdHZhbHVlICs9IGRhdGFbIGkgXTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHZhbHVlIC8gZGF0YS5sZW5ndGg7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IEF1ZGlvQW5hbHlzZXIgfTtcclxuIiwiaW1wb3J0IHsgUXVhdGVybmlvbiB9IGZyb20gJy4uL21hdGgvUXVhdGVybmlvbi5qcyc7XHJcblxyXG5jbGFzcyBQcm9wZXJ0eU1peGVyIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIGJpbmRpbmcsIHR5cGVOYW1lLCB2YWx1ZVNpemUgKSB7XHJcblxyXG5cdFx0dGhpcy5iaW5kaW5nID0gYmluZGluZztcclxuXHRcdHRoaXMudmFsdWVTaXplID0gdmFsdWVTaXplO1xyXG5cclxuXHRcdGxldCBtaXhGdW5jdGlvbixcclxuXHRcdFx0bWl4RnVuY3Rpb25BZGRpdGl2ZSxcclxuXHRcdFx0c2V0SWRlbnRpdHk7XHJcblxyXG5cdFx0Ly8gYnVmZmVyIGxheW91dDogWyBpbmNvbWluZyB8IGFjY3UwIHwgYWNjdTEgfCBvcmlnIHwgYWRkQWNjdSB8IChvcHRpb25hbCB3b3JrKSBdXHJcblx0XHQvL1xyXG5cdFx0Ly8gaW50ZXJwb2xhdG9ycyBjYW4gdXNlIC5idWZmZXIgYXMgdGhlaXIgLnJlc3VsdFxyXG5cdFx0Ly8gdGhlIGRhdGEgdGhlbiBnb2VzIHRvICdpbmNvbWluZydcclxuXHRcdC8vXHJcblx0XHQvLyAnYWNjdTAnIGFuZCAnYWNjdTEnIGFyZSB1c2VkIGZyYW1lLWludGVybGVhdmVkIGZvclxyXG5cdFx0Ly8gdGhlIGN1bXVsYXRpdmUgcmVzdWx0IGFuZCBhcmUgY29tcGFyZWQgdG8gZGV0ZWN0XHJcblx0XHQvLyBjaGFuZ2VzXHJcblx0XHQvL1xyXG5cdFx0Ly8gJ29yaWcnIHN0b3JlcyB0aGUgb3JpZ2luYWwgc3RhdGUgb2YgdGhlIHByb3BlcnR5XHJcblx0XHQvL1xyXG5cdFx0Ly8gJ2FkZCcgaXMgdXNlZCBmb3IgYWRkaXRpdmUgY3VtdWxhdGl2ZSByZXN1bHRzXHJcblx0XHQvL1xyXG5cdFx0Ly8gJ3dvcmsnIGlzIG9wdGlvbmFsIGFuZCBpcyBvbmx5IHByZXNlbnQgZm9yIHF1YXRlcm5pb24gdHlwZXMuIEl0IGlzIHVzZWRcclxuXHRcdC8vIHRvIHN0b3JlIGludGVybWVkaWF0ZSBxdWF0ZXJuaW9uIG11bHRpcGxpY2F0aW9uIHJlc3VsdHNcclxuXHJcblx0XHRzd2l0Y2ggKCB0eXBlTmFtZSApIHtcclxuXHJcblx0XHRcdGNhc2UgJ3F1YXRlcm5pb24nOlxyXG5cdFx0XHRcdG1peEZ1bmN0aW9uID0gdGhpcy5fc2xlcnA7XHJcblx0XHRcdFx0bWl4RnVuY3Rpb25BZGRpdGl2ZSA9IHRoaXMuX3NsZXJwQWRkaXRpdmU7XHJcblx0XHRcdFx0c2V0SWRlbnRpdHkgPSB0aGlzLl9zZXRBZGRpdGl2ZUlkZW50aXR5UXVhdGVybmlvbjtcclxuXHJcblx0XHRcdFx0dGhpcy5idWZmZXIgPSBuZXcgRmxvYXQ2NEFycmF5KCB2YWx1ZVNpemUgKiA2ICk7XHJcblx0XHRcdFx0dGhpcy5fd29ya0luZGV4ID0gNTtcclxuXHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdGNhc2UgJ3N0cmluZyc6XHJcblx0XHRcdGNhc2UgJ2Jvb2wnOlxyXG5cdFx0XHRcdG1peEZ1bmN0aW9uID0gdGhpcy5fc2VsZWN0O1xyXG5cclxuXHRcdFx0XHQvLyBVc2UgdGhlIHJlZ3VsYXIgbWl4IGZ1bmN0aW9uIGFuZCBmb3IgYWRkaXRpdmUgb24gdGhlc2UgdHlwZXMsXHJcblx0XHRcdFx0Ly8gYWRkaXRpdmUgaXMgbm90IHJlbGV2YW50IGZvciBub24tbnVtZXJpYyB0eXBlc1xyXG5cdFx0XHRcdG1peEZ1bmN0aW9uQWRkaXRpdmUgPSB0aGlzLl9zZWxlY3Q7XHJcblxyXG5cdFx0XHRcdHNldElkZW50aXR5ID0gdGhpcy5fc2V0QWRkaXRpdmVJZGVudGl0eU90aGVyO1xyXG5cclxuXHRcdFx0XHR0aGlzLmJ1ZmZlciA9IG5ldyBBcnJheSggdmFsdWVTaXplICogNSApO1xyXG5cdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0ZGVmYXVsdDpcclxuXHRcdFx0XHRtaXhGdW5jdGlvbiA9IHRoaXMuX2xlcnA7XHJcblx0XHRcdFx0bWl4RnVuY3Rpb25BZGRpdGl2ZSA9IHRoaXMuX2xlcnBBZGRpdGl2ZTtcclxuXHRcdFx0XHRzZXRJZGVudGl0eSA9IHRoaXMuX3NldEFkZGl0aXZlSWRlbnRpdHlOdW1lcmljO1xyXG5cclxuXHRcdFx0XHR0aGlzLmJ1ZmZlciA9IG5ldyBGbG9hdDY0QXJyYXkoIHZhbHVlU2l6ZSAqIDUgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5fbWl4QnVmZmVyUmVnaW9uID0gbWl4RnVuY3Rpb247XHJcblx0XHR0aGlzLl9taXhCdWZmZXJSZWdpb25BZGRpdGl2ZSA9IG1peEZ1bmN0aW9uQWRkaXRpdmU7XHJcblx0XHR0aGlzLl9zZXRJZGVudGl0eSA9IHNldElkZW50aXR5O1xyXG5cdFx0dGhpcy5fb3JpZ0luZGV4ID0gMztcclxuXHRcdHRoaXMuX2FkZEluZGV4ID0gNDtcclxuXHJcblx0XHR0aGlzLmN1bXVsYXRpdmVXZWlnaHQgPSAwO1xyXG5cdFx0dGhpcy5jdW11bGF0aXZlV2VpZ2h0QWRkaXRpdmUgPSAwO1xyXG5cclxuXHRcdHRoaXMudXNlQ291bnQgPSAwO1xyXG5cdFx0dGhpcy5yZWZlcmVuY2VDb3VudCA9IDA7XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gYWNjdW11bGF0ZSBkYXRhIGluIHRoZSAnaW5jb21pbmcnIHJlZ2lvbiBpbnRvICdhY2N1PGk+J1xyXG5cdGFjY3VtdWxhdGUoIGFjY3VJbmRleCwgd2VpZ2h0ICkge1xyXG5cclxuXHRcdC8vIG5vdGU6IGhhcHBpbHkgYWNjdW11bGF0aW5nIG5vdGhpbmcgd2hlbiB3ZWlnaHQgPSAwLCB0aGUgY2FsbGVyIGtub3dzXHJcblx0XHQvLyB0aGUgd2VpZ2h0IGFuZCBzaG91bGRuJ3QgaGF2ZSBtYWRlIHRoZSBjYWxsIGluIHRoZSBmaXJzdCBwbGFjZVxyXG5cclxuXHRcdGNvbnN0IGJ1ZmZlciA9IHRoaXMuYnVmZmVyLFxyXG5cdFx0XHRzdHJpZGUgPSB0aGlzLnZhbHVlU2l6ZSxcclxuXHRcdFx0b2Zmc2V0ID0gYWNjdUluZGV4ICogc3RyaWRlICsgc3RyaWRlO1xyXG5cclxuXHRcdGxldCBjdXJyZW50V2VpZ2h0ID0gdGhpcy5jdW11bGF0aXZlV2VpZ2h0O1xyXG5cclxuXHRcdGlmICggY3VycmVudFdlaWdodCA9PT0gMCApIHtcclxuXHJcblx0XHRcdC8vIGFjY3VOIDo9IGluY29taW5nICogd2VpZ2h0XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgIT09IHN0cmlkZTsgKysgaSApIHtcclxuXHJcblx0XHRcdFx0YnVmZmVyWyBvZmZzZXQgKyBpIF0gPSBidWZmZXJbIGkgXTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGN1cnJlbnRXZWlnaHQgPSB3ZWlnaHQ7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdC8vIGFjY3VOIDo9IGFjY3VOICsgaW5jb21pbmcgKiB3ZWlnaHRcclxuXHJcblx0XHRcdGN1cnJlbnRXZWlnaHQgKz0gd2VpZ2h0O1xyXG5cdFx0XHRjb25zdCBtaXggPSB3ZWlnaHQgLyBjdXJyZW50V2VpZ2h0O1xyXG5cdFx0XHR0aGlzLl9taXhCdWZmZXJSZWdpb24oIGJ1ZmZlciwgb2Zmc2V0LCAwLCBtaXgsIHN0cmlkZSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLmN1bXVsYXRpdmVXZWlnaHQgPSBjdXJyZW50V2VpZ2h0O1xyXG5cclxuXHR9XHJcblxyXG5cdC8vIGFjY3VtdWxhdGUgZGF0YSBpbiB0aGUgJ2luY29taW5nJyByZWdpb24gaW50byAnYWRkJ1xyXG5cdGFjY3VtdWxhdGVBZGRpdGl2ZSggd2VpZ2h0ICkge1xyXG5cclxuXHRcdGNvbnN0IGJ1ZmZlciA9IHRoaXMuYnVmZmVyLFxyXG5cdFx0XHRzdHJpZGUgPSB0aGlzLnZhbHVlU2l6ZSxcclxuXHRcdFx0b2Zmc2V0ID0gc3RyaWRlICogdGhpcy5fYWRkSW5kZXg7XHJcblxyXG5cdFx0aWYgKCB0aGlzLmN1bXVsYXRpdmVXZWlnaHRBZGRpdGl2ZSA9PT0gMCApIHtcclxuXHJcblx0XHRcdC8vIGFkZCA9IGlkZW50aXR5XHJcblxyXG5cdFx0XHR0aGlzLl9zZXRJZGVudGl0eSgpO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvLyBhZGQgOj0gYWRkICsgaW5jb21pbmcgKiB3ZWlnaHRcclxuXHJcblx0XHR0aGlzLl9taXhCdWZmZXJSZWdpb25BZGRpdGl2ZSggYnVmZmVyLCBvZmZzZXQsIDAsIHdlaWdodCwgc3RyaWRlICk7XHJcblx0XHR0aGlzLmN1bXVsYXRpdmVXZWlnaHRBZGRpdGl2ZSArPSB3ZWlnaHQ7XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gYXBwbHkgdGhlIHN0YXRlIG9mICdhY2N1PGk+JyB0byB0aGUgYmluZGluZyB3aGVuIGFjY3VzIGRpZmZlclxyXG5cdGFwcGx5KCBhY2N1SW5kZXggKSB7XHJcblxyXG5cdFx0Y29uc3Qgc3RyaWRlID0gdGhpcy52YWx1ZVNpemUsXHJcblx0XHRcdGJ1ZmZlciA9IHRoaXMuYnVmZmVyLFxyXG5cdFx0XHRvZmZzZXQgPSBhY2N1SW5kZXggKiBzdHJpZGUgKyBzdHJpZGUsXHJcblxyXG5cdFx0XHR3ZWlnaHQgPSB0aGlzLmN1bXVsYXRpdmVXZWlnaHQsXHJcblx0XHRcdHdlaWdodEFkZGl0aXZlID0gdGhpcy5jdW11bGF0aXZlV2VpZ2h0QWRkaXRpdmUsXHJcblxyXG5cdFx0XHRiaW5kaW5nID0gdGhpcy5iaW5kaW5nO1xyXG5cclxuXHRcdHRoaXMuY3VtdWxhdGl2ZVdlaWdodCA9IDA7XHJcblx0XHR0aGlzLmN1bXVsYXRpdmVXZWlnaHRBZGRpdGl2ZSA9IDA7XHJcblxyXG5cdFx0aWYgKCB3ZWlnaHQgPCAxICkge1xyXG5cclxuXHRcdFx0Ly8gYWNjdU4gOj0gYWNjdU4gKyBvcmlnaW5hbCAqICggMSAtIGN1bXVsYXRpdmVXZWlnaHQgKVxyXG5cclxuXHRcdFx0Y29uc3Qgb3JpZ2luYWxWYWx1ZU9mZnNldCA9IHN0cmlkZSAqIHRoaXMuX29yaWdJbmRleDtcclxuXHJcblx0XHRcdHRoaXMuX21peEJ1ZmZlclJlZ2lvbihcclxuXHRcdFx0XHRidWZmZXIsIG9mZnNldCwgb3JpZ2luYWxWYWx1ZU9mZnNldCwgMSAtIHdlaWdodCwgc3RyaWRlICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggd2VpZ2h0QWRkaXRpdmUgPiAwICkge1xyXG5cclxuXHRcdFx0Ly8gYWNjdU4gOj0gYWNjdU4gKyBhZGRpdGl2ZSBhY2N1TlxyXG5cclxuXHRcdFx0dGhpcy5fbWl4QnVmZmVyUmVnaW9uQWRkaXRpdmUoIGJ1ZmZlciwgb2Zmc2V0LCB0aGlzLl9hZGRJbmRleCAqIHN0cmlkZSwgMSwgc3RyaWRlICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGZvciAoIGxldCBpID0gc3RyaWRlLCBlID0gc3RyaWRlICsgc3RyaWRlOyBpICE9PSBlOyArKyBpICkge1xyXG5cclxuXHRcdFx0aWYgKCBidWZmZXJbIGkgXSAhPT0gYnVmZmVyWyBpICsgc3RyaWRlIF0gKSB7XHJcblxyXG5cdFx0XHRcdC8vIHZhbHVlIGhhcyBjaGFuZ2VkIC0+IHVwZGF0ZSBzY2VuZSBncmFwaFxyXG5cclxuXHRcdFx0XHRiaW5kaW5nLnNldFZhbHVlKCBidWZmZXIsIG9mZnNldCApO1xyXG5cdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHQvLyByZW1lbWJlciB0aGUgc3RhdGUgb2YgdGhlIGJvdW5kIHByb3BlcnR5IGFuZCBjb3B5IGl0IHRvIGJvdGggYWNjdXNcclxuXHRzYXZlT3JpZ2luYWxTdGF0ZSgpIHtcclxuXHJcblx0XHRjb25zdCBiaW5kaW5nID0gdGhpcy5iaW5kaW5nO1xyXG5cclxuXHRcdGNvbnN0IGJ1ZmZlciA9IHRoaXMuYnVmZmVyLFxyXG5cdFx0XHRzdHJpZGUgPSB0aGlzLnZhbHVlU2l6ZSxcclxuXHJcblx0XHRcdG9yaWdpbmFsVmFsdWVPZmZzZXQgPSBzdHJpZGUgKiB0aGlzLl9vcmlnSW5kZXg7XHJcblxyXG5cdFx0YmluZGluZy5nZXRWYWx1ZSggYnVmZmVyLCBvcmlnaW5hbFZhbHVlT2Zmc2V0ICk7XHJcblxyXG5cdFx0Ly8gYWNjdVswLi4xXSA6PSBvcmlnIC0tIGluaXRpYWxseSBkZXRlY3QgY2hhbmdlcyBhZ2FpbnN0IHRoZSBvcmlnaW5hbFxyXG5cdFx0Zm9yICggbGV0IGkgPSBzdHJpZGUsIGUgPSBvcmlnaW5hbFZhbHVlT2Zmc2V0OyBpICE9PSBlOyArKyBpICkge1xyXG5cclxuXHRcdFx0YnVmZmVyWyBpIF0gPSBidWZmZXJbIG9yaWdpbmFsVmFsdWVPZmZzZXQgKyAoIGkgJSBzdHJpZGUgKSBdO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvLyBBZGQgdG8gaWRlbnRpdHkgZm9yIGFkZGl0aXZlXHJcblx0XHR0aGlzLl9zZXRJZGVudGl0eSgpO1xyXG5cclxuXHRcdHRoaXMuY3VtdWxhdGl2ZVdlaWdodCA9IDA7XHJcblx0XHR0aGlzLmN1bXVsYXRpdmVXZWlnaHRBZGRpdGl2ZSA9IDA7XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gYXBwbHkgdGhlIHN0YXRlIHByZXZpb3VzbHkgdGFrZW4gdmlhICdzYXZlT3JpZ2luYWxTdGF0ZScgdG8gdGhlIGJpbmRpbmdcclxuXHRyZXN0b3JlT3JpZ2luYWxTdGF0ZSgpIHtcclxuXHJcblx0XHRjb25zdCBvcmlnaW5hbFZhbHVlT2Zmc2V0ID0gdGhpcy52YWx1ZVNpemUgKiAzO1xyXG5cdFx0dGhpcy5iaW5kaW5nLnNldFZhbHVlKCB0aGlzLmJ1ZmZlciwgb3JpZ2luYWxWYWx1ZU9mZnNldCApO1xyXG5cclxuXHR9XHJcblxyXG5cdF9zZXRBZGRpdGl2ZUlkZW50aXR5TnVtZXJpYygpIHtcclxuXHJcblx0XHRjb25zdCBzdGFydEluZGV4ID0gdGhpcy5fYWRkSW5kZXggKiB0aGlzLnZhbHVlU2l6ZTtcclxuXHRcdGNvbnN0IGVuZEluZGV4ID0gc3RhcnRJbmRleCArIHRoaXMudmFsdWVTaXplO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gc3RhcnRJbmRleDsgaSA8IGVuZEluZGV4OyBpICsrICkge1xyXG5cclxuXHRcdFx0dGhpcy5idWZmZXJbIGkgXSA9IDA7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdF9zZXRBZGRpdGl2ZUlkZW50aXR5UXVhdGVybmlvbigpIHtcclxuXHJcblx0XHR0aGlzLl9zZXRBZGRpdGl2ZUlkZW50aXR5TnVtZXJpYygpO1xyXG5cdFx0dGhpcy5idWZmZXJbIHRoaXMuX2FkZEluZGV4ICogdGhpcy52YWx1ZVNpemUgKyAzIF0gPSAxO1xyXG5cclxuXHR9XHJcblxyXG5cdF9zZXRBZGRpdGl2ZUlkZW50aXR5T3RoZXIoKSB7XHJcblxyXG5cdFx0Y29uc3Qgc3RhcnRJbmRleCA9IHRoaXMuX29yaWdJbmRleCAqIHRoaXMudmFsdWVTaXplO1xyXG5cdFx0Y29uc3QgdGFyZ2V0SW5kZXggPSB0aGlzLl9hZGRJbmRleCAqIHRoaXMudmFsdWVTaXplO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHRoaXMudmFsdWVTaXplOyBpICsrICkge1xyXG5cclxuXHRcdFx0dGhpcy5idWZmZXJbIHRhcmdldEluZGV4ICsgaSBdID0gdGhpcy5idWZmZXJbIHN0YXJ0SW5kZXggKyBpIF07XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cclxuXHQvLyBtaXggZnVuY3Rpb25zXHJcblxyXG5cdF9zZWxlY3QoIGJ1ZmZlciwgZHN0T2Zmc2V0LCBzcmNPZmZzZXQsIHQsIHN0cmlkZSApIHtcclxuXHJcblx0XHRpZiAoIHQgPj0gMC41ICkge1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpICE9PSBzdHJpZGU7ICsrIGkgKSB7XHJcblxyXG5cdFx0XHRcdGJ1ZmZlclsgZHN0T2Zmc2V0ICsgaSBdID0gYnVmZmVyWyBzcmNPZmZzZXQgKyBpIF07XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdF9zbGVycCggYnVmZmVyLCBkc3RPZmZzZXQsIHNyY09mZnNldCwgdCApIHtcclxuXHJcblx0XHRRdWF0ZXJuaW9uLnNsZXJwRmxhdCggYnVmZmVyLCBkc3RPZmZzZXQsIGJ1ZmZlciwgZHN0T2Zmc2V0LCBidWZmZXIsIHNyY09mZnNldCwgdCApO1xyXG5cclxuXHR9XHJcblxyXG5cdF9zbGVycEFkZGl0aXZlKCBidWZmZXIsIGRzdE9mZnNldCwgc3JjT2Zmc2V0LCB0LCBzdHJpZGUgKSB7XHJcblxyXG5cdFx0Y29uc3Qgd29ya09mZnNldCA9IHRoaXMuX3dvcmtJbmRleCAqIHN0cmlkZTtcclxuXHJcblx0XHQvLyBTdG9yZSByZXN1bHQgaW4gaW50ZXJtZWRpYXRlIGJ1ZmZlciBvZmZzZXRcclxuXHRcdFF1YXRlcm5pb24ubXVsdGlwbHlRdWF0ZXJuaW9uc0ZsYXQoIGJ1ZmZlciwgd29ya09mZnNldCwgYnVmZmVyLCBkc3RPZmZzZXQsIGJ1ZmZlciwgc3JjT2Zmc2V0ICk7XHJcblxyXG5cdFx0Ly8gU2xlcnAgdG8gdGhlIGludGVybWVkaWF0ZSByZXN1bHRcclxuXHRcdFF1YXRlcm5pb24uc2xlcnBGbGF0KCBidWZmZXIsIGRzdE9mZnNldCwgYnVmZmVyLCBkc3RPZmZzZXQsIGJ1ZmZlciwgd29ya09mZnNldCwgdCApO1xyXG5cclxuXHR9XHJcblxyXG5cdF9sZXJwKCBidWZmZXIsIGRzdE9mZnNldCwgc3JjT2Zmc2V0LCB0LCBzdHJpZGUgKSB7XHJcblxyXG5cdFx0Y29uc3QgcyA9IDEgLSB0O1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMDsgaSAhPT0gc3RyaWRlOyArKyBpICkge1xyXG5cclxuXHRcdFx0Y29uc3QgaiA9IGRzdE9mZnNldCArIGk7XHJcblxyXG5cdFx0XHRidWZmZXJbIGogXSA9IGJ1ZmZlclsgaiBdICogcyArIGJ1ZmZlclsgc3JjT2Zmc2V0ICsgaSBdICogdDtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0X2xlcnBBZGRpdGl2ZSggYnVmZmVyLCBkc3RPZmZzZXQsIHNyY09mZnNldCwgdCwgc3RyaWRlICkge1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMDsgaSAhPT0gc3RyaWRlOyArKyBpICkge1xyXG5cclxuXHRcdFx0Y29uc3QgaiA9IGRzdE9mZnNldCArIGk7XHJcblxyXG5cdFx0XHRidWZmZXJbIGogXSA9IGJ1ZmZlclsgaiBdICsgYnVmZmVyWyBzcmNPZmZzZXQgKyBpIF0gKiB0O1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuXHJcbmV4cG9ydCB7IFByb3BlcnR5TWl4ZXIgfTtcclxuIiwiLy8gQ2hhcmFjdGVycyBbXS46LyBhcmUgcmVzZXJ2ZWQgZm9yIHRyYWNrIGJpbmRpbmcgc3ludGF4LlxyXG5jb25zdCBfUkVTRVJWRURfQ0hBUlNfUkUgPSAnXFxcXFtcXFxcXVxcXFwuOlxcXFwvJztcclxuY29uc3QgX3Jlc2VydmVkUmUgPSBuZXcgUmVnRXhwKCAnWycgKyBfUkVTRVJWRURfQ0hBUlNfUkUgKyAnXScsICdnJyApO1xyXG5cclxuLy8gQXR0ZW1wdHMgdG8gYWxsb3cgbm9kZSBuYW1lcyBmcm9tIGFueSBsYW5ndWFnZS4gRVM1J3MgYFxcd2AgcmVnZXhwIG1hdGNoZXNcclxuLy8gb25seSBsYXRpbiBjaGFyYWN0ZXJzLCBhbmQgdGhlIHVuaWNvZGUgXFxwe0x9IGlzIG5vdCB5ZXQgc3VwcG9ydGVkLiBTb1xyXG4vLyBpbnN0ZWFkLCB3ZSBleGNsdWRlIHJlc2VydmVkIGNoYXJhY3RlcnMgYW5kIG1hdGNoIGV2ZXJ5dGhpbmcgZWxzZS5cclxuY29uc3QgX3dvcmRDaGFyID0gJ1teJyArIF9SRVNFUlZFRF9DSEFSU19SRSArICddJztcclxuY29uc3QgX3dvcmRDaGFyT3JEb3QgPSAnW14nICsgX1JFU0VSVkVEX0NIQVJTX1JFLnJlcGxhY2UoICdcXFxcLicsICcnICkgKyAnXSc7XHJcblxyXG4vLyBQYXJlbnQgZGlyZWN0b3JpZXMsIGRlbGltaXRlZCBieSAnLycgb3IgJzonLiBDdXJyZW50bHkgdW51c2VkLCBidXQgbXVzdFxyXG4vLyBiZSBtYXRjaGVkIHRvIHBhcnNlIHRoZSByZXN0IG9mIHRoZSB0cmFjayBuYW1lLlxyXG5jb25zdCBfZGlyZWN0b3J5UmUgPSAvKkBfX1BVUkVfXyovIC8oKD86V0MrW1xcLzpdKSopLy5zb3VyY2UucmVwbGFjZSggJ1dDJywgX3dvcmRDaGFyICk7XHJcblxyXG4vLyBUYXJnZXQgbm9kZS4gTWF5IGNvbnRhaW4gd29yZCBjaGFyYWN0ZXJzIChhLXpBLVowLTlfKSBhbmQgJy4nIG9yICctJy5cclxuY29uc3QgX25vZGVSZSA9IC8qQF9fUFVSRV9fKi8gLyhXQ09EKyk/Ly5zb3VyY2UucmVwbGFjZSggJ1dDT0QnLCBfd29yZENoYXJPckRvdCApO1xyXG5cclxuLy8gT2JqZWN0IG9uIHRhcmdldCBub2RlLCBhbmQgYWNjZXNzb3IuIE1heSBub3QgY29udGFpbiByZXNlcnZlZFxyXG4vLyBjaGFyYWN0ZXJzLiBBY2Nlc3NvciBtYXkgY29udGFpbiBhbnkgY2hhcmFjdGVyIGV4Y2VwdCBjbG9zaW5nIGJyYWNrZXQuXHJcbmNvbnN0IF9vYmplY3RSZSA9IC8qQF9fUFVSRV9fKi8gLyg/OlxcLihXQyspKD86XFxbKC4rKVxcXSk/KT8vLnNvdXJjZS5yZXBsYWNlKCAnV0MnLCBfd29yZENoYXIgKTtcclxuXHJcbi8vIFByb3BlcnR5IGFuZCBhY2Nlc3Nvci4gTWF5IG5vdCBjb250YWluIHJlc2VydmVkIGNoYXJhY3RlcnMuIEFjY2Vzc29yIG1heVxyXG4vLyBjb250YWluIGFueSBub24tYnJhY2tldCBjaGFyYWN0ZXJzLlxyXG5jb25zdCBfcHJvcGVydHlSZSA9IC8qQF9fUFVSRV9fKi8gL1xcLihXQyspKD86XFxbKC4rKVxcXSk/Ly5zb3VyY2UucmVwbGFjZSggJ1dDJywgX3dvcmRDaGFyICk7XHJcblxyXG5jb25zdCBfdHJhY2tSZSA9IG5ldyBSZWdFeHAoICcnXHJcblx0KyAnXidcclxuXHQrIF9kaXJlY3RvcnlSZVxyXG5cdCsgX25vZGVSZVxyXG5cdCsgX29iamVjdFJlXHJcblx0KyBfcHJvcGVydHlSZVxyXG5cdCsgJyQnXHJcbik7XHJcblxyXG5jb25zdCBfc3VwcG9ydGVkT2JqZWN0TmFtZXMgPSBbICdtYXRlcmlhbCcsICdtYXRlcmlhbHMnLCAnYm9uZXMnLCAnbWFwJyBdO1xyXG5cclxuY2xhc3MgQ29tcG9zaXRlIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIHRhcmdldEdyb3VwLCBwYXRoLCBvcHRpb25hbFBhcnNlZFBhdGggKSB7XHJcblxyXG5cdFx0Y29uc3QgcGFyc2VkUGF0aCA9IG9wdGlvbmFsUGFyc2VkUGF0aCB8fCBQcm9wZXJ0eUJpbmRpbmcucGFyc2VUcmFja05hbWUoIHBhdGggKTtcclxuXHJcblx0XHR0aGlzLl90YXJnZXRHcm91cCA9IHRhcmdldEdyb3VwO1xyXG5cdFx0dGhpcy5fYmluZGluZ3MgPSB0YXJnZXRHcm91cC5zdWJzY3JpYmVfKCBwYXRoLCBwYXJzZWRQYXRoICk7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0VmFsdWUoIGFycmF5LCBvZmZzZXQgKSB7XHJcblxyXG5cdFx0dGhpcy5iaW5kKCk7IC8vIGJpbmQgYWxsIGJpbmRpbmdcclxuXHJcblx0XHRjb25zdCBmaXJzdFZhbGlkSW5kZXggPSB0aGlzLl90YXJnZXRHcm91cC5uQ2FjaGVkT2JqZWN0c18sXHJcblx0XHRcdGJpbmRpbmcgPSB0aGlzLl9iaW5kaW5nc1sgZmlyc3RWYWxpZEluZGV4IF07XHJcblxyXG5cdFx0Ly8gYW5kIG9ubHkgY2FsbCAuZ2V0VmFsdWUgb24gdGhlIGZpcnN0XHJcblx0XHRpZiAoIGJpbmRpbmcgIT09IHVuZGVmaW5lZCApIGJpbmRpbmcuZ2V0VmFsdWUoIGFycmF5LCBvZmZzZXQgKTtcclxuXHJcblx0fVxyXG5cclxuXHRzZXRWYWx1ZSggYXJyYXksIG9mZnNldCApIHtcclxuXHJcblx0XHRjb25zdCBiaW5kaW5ncyA9IHRoaXMuX2JpbmRpbmdzO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gdGhpcy5fdGFyZ2V0R3JvdXAubkNhY2hlZE9iamVjdHNfLCBuID0gYmluZGluZ3MubGVuZ3RoOyBpICE9PSBuOyArKyBpICkge1xyXG5cclxuXHRcdFx0YmluZGluZ3NbIGkgXS5zZXRWYWx1ZSggYXJyYXksIG9mZnNldCApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRiaW5kKCkge1xyXG5cclxuXHRcdGNvbnN0IGJpbmRpbmdzID0gdGhpcy5fYmluZGluZ3M7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSB0aGlzLl90YXJnZXRHcm91cC5uQ2FjaGVkT2JqZWN0c18sIG4gPSBiaW5kaW5ncy5sZW5ndGg7IGkgIT09IG47ICsrIGkgKSB7XHJcblxyXG5cdFx0XHRiaW5kaW5nc1sgaSBdLmJpbmQoKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0dW5iaW5kKCkge1xyXG5cclxuXHRcdGNvbnN0IGJpbmRpbmdzID0gdGhpcy5fYmluZGluZ3M7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSB0aGlzLl90YXJnZXRHcm91cC5uQ2FjaGVkT2JqZWN0c18sIG4gPSBiaW5kaW5ncy5sZW5ndGg7IGkgIT09IG47ICsrIGkgKSB7XHJcblxyXG5cdFx0XHRiaW5kaW5nc1sgaSBdLnVuYmluZCgpO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuLy8gTm90ZTogVGhpcyBjbGFzcyB1c2VzIGEgU3RhdGUgcGF0dGVybiBvbiBhIHBlci1tZXRob2QgYmFzaXM6XHJcbi8vICdiaW5kJyBzZXRzICd0aGlzLmdldFZhbHVlJyAvICdzZXRWYWx1ZScgYW5kIHNoYWRvd3MgdGhlXHJcbi8vIHByb3RvdHlwZSB2ZXJzaW9uIG9mIHRoZXNlIG1ldGhvZHMgd2l0aCBvbmUgdGhhdCByZXByZXNlbnRzXHJcbi8vIHRoZSBib3VuZCBzdGF0ZS4gV2hlbiB0aGUgcHJvcGVydHkgaXMgbm90IGZvdW5kLCB0aGUgbWV0aG9kc1xyXG4vLyBiZWNvbWUgbm8tb3BzLlxyXG5jbGFzcyBQcm9wZXJ0eUJpbmRpbmcge1xyXG5cclxuXHRjb25zdHJ1Y3Rvciggcm9vdE5vZGUsIHBhdGgsIHBhcnNlZFBhdGggKSB7XHJcblxyXG5cdFx0dGhpcy5wYXRoID0gcGF0aDtcclxuXHRcdHRoaXMucGFyc2VkUGF0aCA9IHBhcnNlZFBhdGggfHwgUHJvcGVydHlCaW5kaW5nLnBhcnNlVHJhY2tOYW1lKCBwYXRoICk7XHJcblxyXG5cdFx0dGhpcy5ub2RlID0gUHJvcGVydHlCaW5kaW5nLmZpbmROb2RlKCByb290Tm9kZSwgdGhpcy5wYXJzZWRQYXRoLm5vZGVOYW1lICk7XHJcblxyXG5cdFx0dGhpcy5yb290Tm9kZSA9IHJvb3ROb2RlO1xyXG5cclxuXHRcdC8vIGluaXRpYWwgc3RhdGUgb2YgdGhlc2UgbWV0aG9kcyB0aGF0IGNhbGxzICdiaW5kJ1xyXG5cdFx0dGhpcy5nZXRWYWx1ZSA9IHRoaXMuX2dldFZhbHVlX3VuYm91bmQ7XHJcblx0XHR0aGlzLnNldFZhbHVlID0gdGhpcy5fc2V0VmFsdWVfdW5ib3VuZDtcclxuXHJcblx0fVxyXG5cclxuXHJcblx0c3RhdGljIGNyZWF0ZSggcm9vdCwgcGF0aCwgcGFyc2VkUGF0aCApIHtcclxuXHJcblx0XHRpZiAoICEgKCByb290ICYmIHJvb3QuaXNBbmltYXRpb25PYmplY3RHcm91cCApICkge1xyXG5cclxuXHRcdFx0cmV0dXJuIG5ldyBQcm9wZXJ0eUJpbmRpbmcoIHJvb3QsIHBhdGgsIHBhcnNlZFBhdGggKTtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0cmV0dXJuIG5ldyBQcm9wZXJ0eUJpbmRpbmcuQ29tcG9zaXRlKCByb290LCBwYXRoLCBwYXJzZWRQYXRoICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdC8qKlxyXG5cdCAqIFJlcGxhY2VzIHNwYWNlcyB3aXRoIHVuZGVyc2NvcmVzIGFuZCByZW1vdmVzIHVuc3VwcG9ydGVkIGNoYXJhY3RlcnMgZnJvbVxyXG5cdCAqIG5vZGUgbmFtZXMsIHRvIGVuc3VyZSBjb21wYXRpYmlsaXR5IHdpdGggcGFyc2VUcmFja05hbWUoKS5cclxuXHQgKlxyXG5cdCAqIEBwYXJhbSB7c3RyaW5nfSBuYW1lIE5vZGUgbmFtZSB0byBiZSBzYW5pdGl6ZWQuXHJcblx0ICogQHJldHVybiB7c3RyaW5nfVxyXG5cdCAqL1xyXG5cdHN0YXRpYyBzYW5pdGl6ZU5vZGVOYW1lKCBuYW1lICkge1xyXG5cclxuXHRcdHJldHVybiBuYW1lLnJlcGxhY2UoIC9cXHMvZywgJ18nICkucmVwbGFjZSggX3Jlc2VydmVkUmUsICcnICk7XHJcblxyXG5cdH1cclxuXHJcblx0c3RhdGljIHBhcnNlVHJhY2tOYW1lKCB0cmFja05hbWUgKSB7XHJcblxyXG5cdFx0Y29uc3QgbWF0Y2hlcyA9IF90cmFja1JlLmV4ZWMoIHRyYWNrTmFtZSApO1xyXG5cclxuXHRcdGlmICggbWF0Y2hlcyA9PT0gbnVsbCApIHtcclxuXHJcblx0XHRcdHRocm93IG5ldyBFcnJvciggJ1Byb3BlcnR5QmluZGluZzogQ2Fubm90IHBhcnNlIHRyYWNrTmFtZTogJyArIHRyYWNrTmFtZSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCByZXN1bHRzID0ge1xyXG5cdFx0XHQvLyBkaXJlY3RvcnlOYW1lOiBtYXRjaGVzWyAxIF0sIC8vICh0c2NodykgY3VycmVudGx5IHVudXNlZFxyXG5cdFx0XHRub2RlTmFtZTogbWF0Y2hlc1sgMiBdLFxyXG5cdFx0XHRvYmplY3ROYW1lOiBtYXRjaGVzWyAzIF0sXHJcblx0XHRcdG9iamVjdEluZGV4OiBtYXRjaGVzWyA0IF0sXHJcblx0XHRcdHByb3BlcnR5TmFtZTogbWF0Y2hlc1sgNSBdLCAvLyByZXF1aXJlZFxyXG5cdFx0XHRwcm9wZXJ0eUluZGV4OiBtYXRjaGVzWyA2IF1cclxuXHRcdH07XHJcblxyXG5cdFx0Y29uc3QgbGFzdERvdCA9IHJlc3VsdHMubm9kZU5hbWUgJiYgcmVzdWx0cy5ub2RlTmFtZS5sYXN0SW5kZXhPZiggJy4nICk7XHJcblxyXG5cdFx0aWYgKCBsYXN0RG90ICE9PSB1bmRlZmluZWQgJiYgbGFzdERvdCAhPT0gLSAxICkge1xyXG5cclxuXHRcdFx0Y29uc3Qgb2JqZWN0TmFtZSA9IHJlc3VsdHMubm9kZU5hbWUuc3Vic3RyaW5nKCBsYXN0RG90ICsgMSApO1xyXG5cclxuXHRcdFx0Ly8gT2JqZWN0IG5hbWVzIG11c3QgYmUgY2hlY2tlZCBhZ2FpbnN0IGFuIGFsbG93bGlzdC4gT3RoZXJ3aXNlLCB0aGVyZVxyXG5cdFx0XHQvLyBpcyBubyB3YXkgdG8gcGFyc2UgJ2Zvby5iYXIuYmF6JzogJ2JheicgbXVzdCBiZSBhIHByb3BlcnR5LCBidXRcclxuXHRcdFx0Ly8gJ2JhcicgY291bGQgYmUgdGhlIG9iamVjdE5hbWUsIG9yIHBhcnQgb2YgYSBub2RlTmFtZSAod2hpY2ggY2FuXHJcblx0XHRcdC8vIGluY2x1ZGUgJy4nIGNoYXJhY3RlcnMpLlxyXG5cdFx0XHRpZiAoIF9zdXBwb3J0ZWRPYmplY3ROYW1lcy5pbmRleE9mKCBvYmplY3ROYW1lICkgIT09IC0gMSApIHtcclxuXHJcblx0XHRcdFx0cmVzdWx0cy5ub2RlTmFtZSA9IHJlc3VsdHMubm9kZU5hbWUuc3Vic3RyaW5nKCAwLCBsYXN0RG90ICk7XHJcblx0XHRcdFx0cmVzdWx0cy5vYmplY3ROYW1lID0gb2JqZWN0TmFtZTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCByZXN1bHRzLnByb3BlcnR5TmFtZSA9PT0gbnVsbCB8fCByZXN1bHRzLnByb3BlcnR5TmFtZS5sZW5ndGggPT09IDAgKSB7XHJcblxyXG5cdFx0XHR0aHJvdyBuZXcgRXJyb3IoICdQcm9wZXJ0eUJpbmRpbmc6IGNhbiBub3QgcGFyc2UgcHJvcGVydHlOYW1lIGZyb20gdHJhY2tOYW1lOiAnICsgdHJhY2tOYW1lICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiByZXN1bHRzO1xyXG5cclxuXHR9XHJcblxyXG5cdHN0YXRpYyBmaW5kTm9kZSggcm9vdCwgbm9kZU5hbWUgKSB7XHJcblxyXG5cdFx0aWYgKCBub2RlTmFtZSA9PT0gdW5kZWZpbmVkIHx8IG5vZGVOYW1lID09PSAnJyB8fCBub2RlTmFtZSA9PT0gJy4nIHx8IG5vZGVOYW1lID09PSAtIDEgfHwgbm9kZU5hbWUgPT09IHJvb3QubmFtZSB8fCBub2RlTmFtZSA9PT0gcm9vdC51dWlkICkge1xyXG5cclxuXHRcdFx0cmV0dXJuIHJvb3Q7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIHNlYXJjaCBpbnRvIHNrZWxldG9uIGJvbmVzLlxyXG5cdFx0aWYgKCByb290LnNrZWxldG9uICkge1xyXG5cclxuXHRcdFx0Y29uc3QgYm9uZSA9IHJvb3Quc2tlbGV0b24uZ2V0Qm9uZUJ5TmFtZSggbm9kZU5hbWUgKTtcclxuXHJcblx0XHRcdGlmICggYm9uZSAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHRyZXR1cm4gYm9uZTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gc2VhcmNoIGludG8gbm9kZSBzdWJ0cmVlLlxyXG5cdFx0aWYgKCByb290LmNoaWxkcmVuICkge1xyXG5cclxuXHRcdFx0Y29uc3Qgc2VhcmNoTm9kZVN1YnRyZWUgPSBmdW5jdGlvbiAoIGNoaWxkcmVuICkge1xyXG5cclxuXHRcdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBjaGlsZHJlbi5sZW5ndGg7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgY2hpbGROb2RlID0gY2hpbGRyZW5bIGkgXTtcclxuXHJcblx0XHRcdFx0XHRpZiAoIGNoaWxkTm9kZS5uYW1lID09PSBub2RlTmFtZSB8fCBjaGlsZE5vZGUudXVpZCA9PT0gbm9kZU5hbWUgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRyZXR1cm4gY2hpbGROb2RlO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRjb25zdCByZXN1bHQgPSBzZWFyY2hOb2RlU3VidHJlZSggY2hpbGROb2RlLmNoaWxkcmVuICk7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCByZXN1bHQgKSByZXR1cm4gcmVzdWx0O1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdHJldHVybiBudWxsO1xyXG5cclxuXHRcdFx0fTtcclxuXHJcblx0XHRcdGNvbnN0IHN1YlRyZWVOb2RlID0gc2VhcmNoTm9kZVN1YnRyZWUoIHJvb3QuY2hpbGRyZW4gKTtcclxuXHJcblx0XHRcdGlmICggc3ViVHJlZU5vZGUgKSB7XHJcblxyXG5cdFx0XHRcdHJldHVybiBzdWJUcmVlTm9kZTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIG51bGw7XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gdGhlc2UgYXJlIHVzZWQgdG8gXCJiaW5kXCIgYSBub25leGlzdGVudCBwcm9wZXJ0eVxyXG5cdF9nZXRWYWx1ZV91bmF2YWlsYWJsZSgpIHt9XHJcblx0X3NldFZhbHVlX3VuYXZhaWxhYmxlKCkge31cclxuXHJcblx0Ly8gR2V0dGVyc1xyXG5cclxuXHRfZ2V0VmFsdWVfZGlyZWN0KCBidWZmZXIsIG9mZnNldCApIHtcclxuXHJcblx0XHRidWZmZXJbIG9mZnNldCBdID0gdGhpcy50YXJnZXRPYmplY3RbIHRoaXMucHJvcGVydHlOYW1lIF07XHJcblxyXG5cdH1cclxuXHJcblx0X2dldFZhbHVlX2FycmF5KCBidWZmZXIsIG9mZnNldCApIHtcclxuXHJcblx0XHRjb25zdCBzb3VyY2UgPSB0aGlzLnJlc29sdmVkUHJvcGVydHk7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBuID0gc291cmNlLmxlbmd0aDsgaSAhPT0gbjsgKysgaSApIHtcclxuXHJcblx0XHRcdGJ1ZmZlclsgb2Zmc2V0ICsrIF0gPSBzb3VyY2VbIGkgXTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0X2dldFZhbHVlX2FycmF5RWxlbWVudCggYnVmZmVyLCBvZmZzZXQgKSB7XHJcblxyXG5cdFx0YnVmZmVyWyBvZmZzZXQgXSA9IHRoaXMucmVzb2x2ZWRQcm9wZXJ0eVsgdGhpcy5wcm9wZXJ0eUluZGV4IF07XHJcblxyXG5cdH1cclxuXHJcblx0X2dldFZhbHVlX3RvQXJyYXkoIGJ1ZmZlciwgb2Zmc2V0ICkge1xyXG5cclxuXHRcdHRoaXMucmVzb2x2ZWRQcm9wZXJ0eS50b0FycmF5KCBidWZmZXIsIG9mZnNldCApO1xyXG5cclxuXHR9XHJcblxyXG5cdC8vIERpcmVjdFxyXG5cclxuXHRfc2V0VmFsdWVfZGlyZWN0KCBidWZmZXIsIG9mZnNldCApIHtcclxuXHJcblx0XHR0aGlzLnRhcmdldE9iamVjdFsgdGhpcy5wcm9wZXJ0eU5hbWUgXSA9IGJ1ZmZlclsgb2Zmc2V0IF07XHJcblxyXG5cdH1cclxuXHJcblx0X3NldFZhbHVlX2RpcmVjdF9zZXROZWVkc1VwZGF0ZSggYnVmZmVyLCBvZmZzZXQgKSB7XHJcblxyXG5cdFx0dGhpcy50YXJnZXRPYmplY3RbIHRoaXMucHJvcGVydHlOYW1lIF0gPSBidWZmZXJbIG9mZnNldCBdO1xyXG5cdFx0dGhpcy50YXJnZXRPYmplY3QubmVlZHNVcGRhdGUgPSB0cnVlO1xyXG5cclxuXHR9XHJcblxyXG5cdF9zZXRWYWx1ZV9kaXJlY3Rfc2V0TWF0cml4V29ybGROZWVkc1VwZGF0ZSggYnVmZmVyLCBvZmZzZXQgKSB7XHJcblxyXG5cdFx0dGhpcy50YXJnZXRPYmplY3RbIHRoaXMucHJvcGVydHlOYW1lIF0gPSBidWZmZXJbIG9mZnNldCBdO1xyXG5cdFx0dGhpcy50YXJnZXRPYmplY3QubWF0cml4V29ybGROZWVkc1VwZGF0ZSA9IHRydWU7XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gRW50aXJlQXJyYXlcclxuXHJcblx0X3NldFZhbHVlX2FycmF5KCBidWZmZXIsIG9mZnNldCApIHtcclxuXHJcblx0XHRjb25zdCBkZXN0ID0gdGhpcy5yZXNvbHZlZFByb3BlcnR5O1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMCwgbiA9IGRlc3QubGVuZ3RoOyBpICE9PSBuOyArKyBpICkge1xyXG5cclxuXHRcdFx0ZGVzdFsgaSBdID0gYnVmZmVyWyBvZmZzZXQgKysgXTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0X3NldFZhbHVlX2FycmF5X3NldE5lZWRzVXBkYXRlKCBidWZmZXIsIG9mZnNldCApIHtcclxuXHJcblx0XHRjb25zdCBkZXN0ID0gdGhpcy5yZXNvbHZlZFByb3BlcnR5O1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMCwgbiA9IGRlc3QubGVuZ3RoOyBpICE9PSBuOyArKyBpICkge1xyXG5cclxuXHRcdFx0ZGVzdFsgaSBdID0gYnVmZmVyWyBvZmZzZXQgKysgXTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy50YXJnZXRPYmplY3QubmVlZHNVcGRhdGUgPSB0cnVlO1xyXG5cclxuXHR9XHJcblxyXG5cdF9zZXRWYWx1ZV9hcnJheV9zZXRNYXRyaXhXb3JsZE5lZWRzVXBkYXRlKCBidWZmZXIsIG9mZnNldCApIHtcclxuXHJcblx0XHRjb25zdCBkZXN0ID0gdGhpcy5yZXNvbHZlZFByb3BlcnR5O1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMCwgbiA9IGRlc3QubGVuZ3RoOyBpICE9PSBuOyArKyBpICkge1xyXG5cclxuXHRcdFx0ZGVzdFsgaSBdID0gYnVmZmVyWyBvZmZzZXQgKysgXTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy50YXJnZXRPYmplY3QubWF0cml4V29ybGROZWVkc1VwZGF0ZSA9IHRydWU7XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gQXJyYXlFbGVtZW50XHJcblxyXG5cdF9zZXRWYWx1ZV9hcnJheUVsZW1lbnQoIGJ1ZmZlciwgb2Zmc2V0ICkge1xyXG5cclxuXHRcdHRoaXMucmVzb2x2ZWRQcm9wZXJ0eVsgdGhpcy5wcm9wZXJ0eUluZGV4IF0gPSBidWZmZXJbIG9mZnNldCBdO1xyXG5cclxuXHR9XHJcblxyXG5cdF9zZXRWYWx1ZV9hcnJheUVsZW1lbnRfc2V0TmVlZHNVcGRhdGUoIGJ1ZmZlciwgb2Zmc2V0ICkge1xyXG5cclxuXHRcdHRoaXMucmVzb2x2ZWRQcm9wZXJ0eVsgdGhpcy5wcm9wZXJ0eUluZGV4IF0gPSBidWZmZXJbIG9mZnNldCBdO1xyXG5cdFx0dGhpcy50YXJnZXRPYmplY3QubmVlZHNVcGRhdGUgPSB0cnVlO1xyXG5cclxuXHR9XHJcblxyXG5cdF9zZXRWYWx1ZV9hcnJheUVsZW1lbnRfc2V0TWF0cml4V29ybGROZWVkc1VwZGF0ZSggYnVmZmVyLCBvZmZzZXQgKSB7XHJcblxyXG5cdFx0dGhpcy5yZXNvbHZlZFByb3BlcnR5WyB0aGlzLnByb3BlcnR5SW5kZXggXSA9IGJ1ZmZlclsgb2Zmc2V0IF07XHJcblx0XHR0aGlzLnRhcmdldE9iamVjdC5tYXRyaXhXb3JsZE5lZWRzVXBkYXRlID0gdHJ1ZTtcclxuXHJcblx0fVxyXG5cclxuXHQvLyBIYXNUb0Zyb21BcnJheVxyXG5cclxuXHRfc2V0VmFsdWVfZnJvbUFycmF5KCBidWZmZXIsIG9mZnNldCApIHtcclxuXHJcblx0XHR0aGlzLnJlc29sdmVkUHJvcGVydHkuZnJvbUFycmF5KCBidWZmZXIsIG9mZnNldCApO1xyXG5cclxuXHR9XHJcblxyXG5cdF9zZXRWYWx1ZV9mcm9tQXJyYXlfc2V0TmVlZHNVcGRhdGUoIGJ1ZmZlciwgb2Zmc2V0ICkge1xyXG5cclxuXHRcdHRoaXMucmVzb2x2ZWRQcm9wZXJ0eS5mcm9tQXJyYXkoIGJ1ZmZlciwgb2Zmc2V0ICk7XHJcblx0XHR0aGlzLnRhcmdldE9iamVjdC5uZWVkc1VwZGF0ZSA9IHRydWU7XHJcblxyXG5cdH1cclxuXHJcblx0X3NldFZhbHVlX2Zyb21BcnJheV9zZXRNYXRyaXhXb3JsZE5lZWRzVXBkYXRlKCBidWZmZXIsIG9mZnNldCApIHtcclxuXHJcblx0XHR0aGlzLnJlc29sdmVkUHJvcGVydHkuZnJvbUFycmF5KCBidWZmZXIsIG9mZnNldCApO1xyXG5cdFx0dGhpcy50YXJnZXRPYmplY3QubWF0cml4V29ybGROZWVkc1VwZGF0ZSA9IHRydWU7XHJcblxyXG5cdH1cclxuXHJcblx0X2dldFZhbHVlX3VuYm91bmQoIHRhcmdldEFycmF5LCBvZmZzZXQgKSB7XHJcblxyXG5cdFx0dGhpcy5iaW5kKCk7XHJcblx0XHR0aGlzLmdldFZhbHVlKCB0YXJnZXRBcnJheSwgb2Zmc2V0ICk7XHJcblxyXG5cdH1cclxuXHJcblx0X3NldFZhbHVlX3VuYm91bmQoIHNvdXJjZUFycmF5LCBvZmZzZXQgKSB7XHJcblxyXG5cdFx0dGhpcy5iaW5kKCk7XHJcblx0XHR0aGlzLnNldFZhbHVlKCBzb3VyY2VBcnJheSwgb2Zmc2V0ICk7XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gY3JlYXRlIGdldHRlciAvIHNldHRlciBwYWlyIGZvciBhIHByb3BlcnR5IGluIHRoZSBzY2VuZSBncmFwaFxyXG5cdGJpbmQoKSB7XHJcblxyXG5cdFx0bGV0IHRhcmdldE9iamVjdCA9IHRoaXMubm9kZTtcclxuXHRcdGNvbnN0IHBhcnNlZFBhdGggPSB0aGlzLnBhcnNlZFBhdGg7XHJcblxyXG5cdFx0Y29uc3Qgb2JqZWN0TmFtZSA9IHBhcnNlZFBhdGgub2JqZWN0TmFtZTtcclxuXHRcdGNvbnN0IHByb3BlcnR5TmFtZSA9IHBhcnNlZFBhdGgucHJvcGVydHlOYW1lO1xyXG5cdFx0bGV0IHByb3BlcnR5SW5kZXggPSBwYXJzZWRQYXRoLnByb3BlcnR5SW5kZXg7XHJcblxyXG5cdFx0aWYgKCAhIHRhcmdldE9iamVjdCApIHtcclxuXHJcblx0XHRcdHRhcmdldE9iamVjdCA9IFByb3BlcnR5QmluZGluZy5maW5kTm9kZSggdGhpcy5yb290Tm9kZSwgcGFyc2VkUGF0aC5ub2RlTmFtZSApO1xyXG5cclxuXHRcdFx0dGhpcy5ub2RlID0gdGFyZ2V0T2JqZWN0O1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvLyBzZXQgZmFpbCBzdGF0ZSBzbyB3ZSBjYW4ganVzdCAncmV0dXJuJyBvbiBlcnJvclxyXG5cdFx0dGhpcy5nZXRWYWx1ZSA9IHRoaXMuX2dldFZhbHVlX3VuYXZhaWxhYmxlO1xyXG5cdFx0dGhpcy5zZXRWYWx1ZSA9IHRoaXMuX3NldFZhbHVlX3VuYXZhaWxhYmxlO1xyXG5cclxuXHRcdC8vIGVuc3VyZSB0aGVyZSBpcyBhIHZhbHVlIG5vZGVcclxuXHRcdGlmICggISB0YXJnZXRPYmplY3QgKSB7XHJcblxyXG5cdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5Qcm9wZXJ0eUJpbmRpbmc6IE5vIHRhcmdldCBub2RlIGZvdW5kIGZvciB0cmFjazogJyArIHRoaXMucGF0aCArICcuJyApO1xyXG5cdFx0XHRyZXR1cm47XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggb2JqZWN0TmFtZSApIHtcclxuXHJcblx0XHRcdGxldCBvYmplY3RJbmRleCA9IHBhcnNlZFBhdGgub2JqZWN0SW5kZXg7XHJcblxyXG5cdFx0XHQvLyBzcGVjaWFsIGNhc2VzIHdlcmUgd2UgbmVlZCB0byByZWFjaCBkZWVwZXIgaW50byB0aGUgaGllcmFyY2h5IHRvIGdldCB0aGUgZmFjZSBtYXRlcmlhbHMuLi4uXHJcblx0XHRcdHN3aXRjaCAoIG9iamVjdE5hbWUgKSB7XHJcblxyXG5cdFx0XHRcdGNhc2UgJ21hdGVyaWFscyc6XHJcblxyXG5cdFx0XHRcdFx0aWYgKCAhIHRhcmdldE9iamVjdC5tYXRlcmlhbCApIHtcclxuXHJcblx0XHRcdFx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5Qcm9wZXJ0eUJpbmRpbmc6IENhbiBub3QgYmluZCB0byBtYXRlcmlhbCBhcyBub2RlIGRvZXMgbm90IGhhdmUgYSBtYXRlcmlhbC4nLCB0aGlzICk7XHJcblx0XHRcdFx0XHRcdHJldHVybjtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0aWYgKCAhIHRhcmdldE9iamVjdC5tYXRlcmlhbC5tYXRlcmlhbHMgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuUHJvcGVydHlCaW5kaW5nOiBDYW4gbm90IGJpbmQgdG8gbWF0ZXJpYWwubWF0ZXJpYWxzIGFzIG5vZGUubWF0ZXJpYWwgZG9lcyBub3QgaGF2ZSBhIG1hdGVyaWFscyBhcnJheS4nLCB0aGlzICk7XHJcblx0XHRcdFx0XHRcdHJldHVybjtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0dGFyZ2V0T2JqZWN0ID0gdGFyZ2V0T2JqZWN0Lm1hdGVyaWFsLm1hdGVyaWFscztcclxuXHJcblx0XHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdFx0Y2FzZSAnYm9uZXMnOlxyXG5cclxuXHRcdFx0XHRcdGlmICggISB0YXJnZXRPYmplY3Quc2tlbGV0b24gKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuUHJvcGVydHlCaW5kaW5nOiBDYW4gbm90IGJpbmQgdG8gYm9uZXMgYXMgbm9kZSBkb2VzIG5vdCBoYXZlIGEgc2tlbGV0b24uJywgdGhpcyApO1xyXG5cdFx0XHRcdFx0XHRyZXR1cm47XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdC8vIHBvdGVudGlhbCBmdXR1cmUgb3B0aW1pemF0aW9uOiBza2lwIHRoaXMgaWYgcHJvcGVydHlJbmRleCBpcyBhbHJlYWR5IGFuIGludGVnZXJcclxuXHRcdFx0XHRcdC8vIGFuZCBjb252ZXJ0IHRoZSBpbnRlZ2VyIHN0cmluZyB0byBhIHRydWUgaW50ZWdlci5cclxuXHJcblx0XHRcdFx0XHR0YXJnZXRPYmplY3QgPSB0YXJnZXRPYmplY3Quc2tlbGV0b24uYm9uZXM7XHJcblxyXG5cdFx0XHRcdFx0Ly8gc3VwcG9ydCByZXNvbHZpbmcgbW9ycGhUYXJnZXQgbmFtZXMgaW50byBpbmRpY2VzLlxyXG5cdFx0XHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgdGFyZ2V0T2JqZWN0Lmxlbmd0aDsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0XHRcdGlmICggdGFyZ2V0T2JqZWN0WyBpIF0ubmFtZSA9PT0gb2JqZWN0SW5kZXggKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdG9iamVjdEluZGV4ID0gaTtcclxuXHRcdFx0XHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRcdGNhc2UgJ21hcCc6XHJcblxyXG5cdFx0XHRcdFx0aWYgKCAnbWFwJyBpbiB0YXJnZXRPYmplY3QgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHR0YXJnZXRPYmplY3QgPSB0YXJnZXRPYmplY3QubWFwO1xyXG5cdFx0XHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0aWYgKCAhIHRhcmdldE9iamVjdC5tYXRlcmlhbCApIHtcclxuXHJcblx0XHRcdFx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5Qcm9wZXJ0eUJpbmRpbmc6IENhbiBub3QgYmluZCB0byBtYXRlcmlhbCBhcyBub2RlIGRvZXMgbm90IGhhdmUgYSBtYXRlcmlhbC4nLCB0aGlzICk7XHJcblx0XHRcdFx0XHRcdHJldHVybjtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0aWYgKCAhIHRhcmdldE9iamVjdC5tYXRlcmlhbC5tYXAgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuUHJvcGVydHlCaW5kaW5nOiBDYW4gbm90IGJpbmQgdG8gbWF0ZXJpYWwubWFwIGFzIG5vZGUubWF0ZXJpYWwgZG9lcyBub3QgaGF2ZSBhIG1hcC4nLCB0aGlzICk7XHJcblx0XHRcdFx0XHRcdHJldHVybjtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0dGFyZ2V0T2JqZWN0ID0gdGFyZ2V0T2JqZWN0Lm1hdGVyaWFsLm1hcDtcclxuXHRcdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0XHRkZWZhdWx0OlxyXG5cclxuXHRcdFx0XHRcdGlmICggdGFyZ2V0T2JqZWN0WyBvYmplY3ROYW1lIF0gPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5Qcm9wZXJ0eUJpbmRpbmc6IENhbiBub3QgYmluZCB0byBvYmplY3ROYW1lIG9mIG5vZGUgdW5kZWZpbmVkLicsIHRoaXMgKTtcclxuXHRcdFx0XHRcdFx0cmV0dXJuO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHR0YXJnZXRPYmplY3QgPSB0YXJnZXRPYmplY3RbIG9iamVjdE5hbWUgXTtcclxuXHJcblx0XHRcdH1cclxuXHJcblxyXG5cdFx0XHRpZiAoIG9iamVjdEluZGV4ICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRcdGlmICggdGFyZ2V0T2JqZWN0WyBvYmplY3RJbmRleCBdID09PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLlByb3BlcnR5QmluZGluZzogVHJ5aW5nIHRvIGJpbmQgdG8gb2JqZWN0SW5kZXggb2Ygb2JqZWN0TmFtZSwgYnV0IGlzIHVuZGVmaW5lZC4nLCB0aGlzLCB0YXJnZXRPYmplY3QgKTtcclxuXHRcdFx0XHRcdHJldHVybjtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR0YXJnZXRPYmplY3QgPSB0YXJnZXRPYmplY3RbIG9iamVjdEluZGV4IF07XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIHJlc29sdmUgcHJvcGVydHlcclxuXHRcdGNvbnN0IG5vZGVQcm9wZXJ0eSA9IHRhcmdldE9iamVjdFsgcHJvcGVydHlOYW1lIF07XHJcblxyXG5cdFx0aWYgKCBub2RlUHJvcGVydHkgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdGNvbnN0IG5vZGVOYW1lID0gcGFyc2VkUGF0aC5ub2RlTmFtZTtcclxuXHJcblx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5Qcm9wZXJ0eUJpbmRpbmc6IFRyeWluZyB0byB1cGRhdGUgcHJvcGVydHkgZm9yIHRyYWNrOiAnICsgbm9kZU5hbWUgK1xyXG5cdFx0XHRcdCcuJyArIHByb3BlcnR5TmFtZSArICcgYnV0IGl0IHdhc25cXCd0IGZvdW5kLicsIHRhcmdldE9iamVjdCApO1xyXG5cdFx0XHRyZXR1cm47XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIGRldGVybWluZSB2ZXJzaW9uaW5nIHNjaGVtZVxyXG5cdFx0bGV0IHZlcnNpb25pbmcgPSB0aGlzLlZlcnNpb25pbmcuTm9uZTtcclxuXHJcblx0XHR0aGlzLnRhcmdldE9iamVjdCA9IHRhcmdldE9iamVjdDtcclxuXHJcblx0XHRpZiAoIHRhcmdldE9iamVjdC5uZWVkc1VwZGF0ZSAhPT0gdW5kZWZpbmVkICkgeyAvLyBtYXRlcmlhbFxyXG5cclxuXHRcdFx0dmVyc2lvbmluZyA9IHRoaXMuVmVyc2lvbmluZy5OZWVkc1VwZGF0ZTtcclxuXHJcblx0XHR9IGVsc2UgaWYgKCB0YXJnZXRPYmplY3QubWF0cml4V29ybGROZWVkc1VwZGF0ZSAhPT0gdW5kZWZpbmVkICkgeyAvLyBub2RlIHRyYW5zZm9ybVxyXG5cclxuXHRcdFx0dmVyc2lvbmluZyA9IHRoaXMuVmVyc2lvbmluZy5NYXRyaXhXb3JsZE5lZWRzVXBkYXRlO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvLyBkZXRlcm1pbmUgaG93IHRoZSBwcm9wZXJ0eSBnZXRzIGJvdW5kXHJcblx0XHRsZXQgYmluZGluZ1R5cGUgPSB0aGlzLkJpbmRpbmdUeXBlLkRpcmVjdDtcclxuXHJcblx0XHRpZiAoIHByb3BlcnR5SW5kZXggIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdC8vIGFjY2VzcyBhIHN1YiBlbGVtZW50IG9mIHRoZSBwcm9wZXJ0eSBhcnJheSAob25seSBwcmltaXRpdmVzIGFyZSBzdXBwb3J0ZWQgcmlnaHQgbm93KVxyXG5cclxuXHRcdFx0aWYgKCBwcm9wZXJ0eU5hbWUgPT09ICdtb3JwaFRhcmdldEluZmx1ZW5jZXMnICkge1xyXG5cclxuXHRcdFx0XHQvLyBwb3RlbnRpYWwgb3B0aW1pemF0aW9uLCBza2lwIHRoaXMgaWYgcHJvcGVydHlJbmRleCBpcyBhbHJlYWR5IGFuIGludGVnZXIsIGFuZCBjb252ZXJ0IHRoZSBpbnRlZ2VyIHN0cmluZyB0byBhIHRydWUgaW50ZWdlci5cclxuXHJcblx0XHRcdFx0Ly8gc3VwcG9ydCByZXNvbHZpbmcgbW9ycGhUYXJnZXQgbmFtZXMgaW50byBpbmRpY2VzLlxyXG5cdFx0XHRcdGlmICggISB0YXJnZXRPYmplY3QuZ2VvbWV0cnkgKSB7XHJcblxyXG5cdFx0XHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLlByb3BlcnR5QmluZGluZzogQ2FuIG5vdCBiaW5kIHRvIG1vcnBoVGFyZ2V0SW5mbHVlbmNlcyBiZWNhdXNlIG5vZGUgZG9lcyBub3QgaGF2ZSBhIGdlb21ldHJ5LicsIHRoaXMgKTtcclxuXHRcdFx0XHRcdHJldHVybjtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRpZiAoICEgdGFyZ2V0T2JqZWN0Lmdlb21ldHJ5Lm1vcnBoQXR0cmlidXRlcyApIHtcclxuXHJcblx0XHRcdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuUHJvcGVydHlCaW5kaW5nOiBDYW4gbm90IGJpbmQgdG8gbW9ycGhUYXJnZXRJbmZsdWVuY2VzIGJlY2F1c2Ugbm9kZSBkb2VzIG5vdCBoYXZlIGEgZ2VvbWV0cnkubW9ycGhBdHRyaWJ1dGVzLicsIHRoaXMgKTtcclxuXHRcdFx0XHRcdHJldHVybjtcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRpZiAoIHRhcmdldE9iamVjdC5tb3JwaFRhcmdldERpY3Rpb25hcnlbIHByb3BlcnR5SW5kZXggXSAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHRcdHByb3BlcnR5SW5kZXggPSB0YXJnZXRPYmplY3QubW9ycGhUYXJnZXREaWN0aW9uYXJ5WyBwcm9wZXJ0eUluZGV4IF07XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGJpbmRpbmdUeXBlID0gdGhpcy5CaW5kaW5nVHlwZS5BcnJheUVsZW1lbnQ7XHJcblxyXG5cdFx0XHR0aGlzLnJlc29sdmVkUHJvcGVydHkgPSBub2RlUHJvcGVydHk7XHJcblx0XHRcdHRoaXMucHJvcGVydHlJbmRleCA9IHByb3BlcnR5SW5kZXg7XHJcblxyXG5cdFx0fSBlbHNlIGlmICggbm9kZVByb3BlcnR5LmZyb21BcnJheSAhPT0gdW5kZWZpbmVkICYmIG5vZGVQcm9wZXJ0eS50b0FycmF5ICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHQvLyBtdXN0IHVzZSBjb3B5IGZvciBPYmplY3QzRC5FdWxlci9RdWF0ZXJuaW9uXHJcblxyXG5cdFx0XHRiaW5kaW5nVHlwZSA9IHRoaXMuQmluZGluZ1R5cGUuSGFzRnJvbVRvQXJyYXk7XHJcblxyXG5cdFx0XHR0aGlzLnJlc29sdmVkUHJvcGVydHkgPSBub2RlUHJvcGVydHk7XHJcblxyXG5cdFx0fSBlbHNlIGlmICggQXJyYXkuaXNBcnJheSggbm9kZVByb3BlcnR5ICkgKSB7XHJcblxyXG5cdFx0XHRiaW5kaW5nVHlwZSA9IHRoaXMuQmluZGluZ1R5cGUuRW50aXJlQXJyYXk7XHJcblxyXG5cdFx0XHR0aGlzLnJlc29sdmVkUHJvcGVydHkgPSBub2RlUHJvcGVydHk7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdHRoaXMucHJvcGVydHlOYW1lID0gcHJvcGVydHlOYW1lO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvLyBzZWxlY3QgZ2V0dGVyIC8gc2V0dGVyXHJcblx0XHR0aGlzLmdldFZhbHVlID0gdGhpcy5HZXR0ZXJCeUJpbmRpbmdUeXBlWyBiaW5kaW5nVHlwZSBdO1xyXG5cdFx0dGhpcy5zZXRWYWx1ZSA9IHRoaXMuU2V0dGVyQnlCaW5kaW5nVHlwZUFuZFZlcnNpb25pbmdbIGJpbmRpbmdUeXBlIF1bIHZlcnNpb25pbmcgXTtcclxuXHJcblx0fVxyXG5cclxuXHR1bmJpbmQoKSB7XHJcblxyXG5cdFx0dGhpcy5ub2RlID0gbnVsbDtcclxuXHJcblx0XHQvLyBiYWNrIHRvIHRoZSBwcm90b3R5cGUgdmVyc2lvbiBvZiBnZXRWYWx1ZSAvIHNldFZhbHVlXHJcblx0XHQvLyBub3RlOiBhdm9pZGluZyB0byBtdXRhdGUgdGhlIHNoYXBlIG9mICd0aGlzJyB2aWEgJ2RlbGV0ZSdcclxuXHRcdHRoaXMuZ2V0VmFsdWUgPSB0aGlzLl9nZXRWYWx1ZV91bmJvdW5kO1xyXG5cdFx0dGhpcy5zZXRWYWx1ZSA9IHRoaXMuX3NldFZhbHVlX3VuYm91bmQ7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcblByb3BlcnR5QmluZGluZy5Db21wb3NpdGUgPSBDb21wb3NpdGU7XHJcblxyXG5Qcm9wZXJ0eUJpbmRpbmcucHJvdG90eXBlLkJpbmRpbmdUeXBlID0ge1xyXG5cdERpcmVjdDogMCxcclxuXHRFbnRpcmVBcnJheTogMSxcclxuXHRBcnJheUVsZW1lbnQ6IDIsXHJcblx0SGFzRnJvbVRvQXJyYXk6IDNcclxufTtcclxuXHJcblByb3BlcnR5QmluZGluZy5wcm90b3R5cGUuVmVyc2lvbmluZyA9IHtcclxuXHROb25lOiAwLFxyXG5cdE5lZWRzVXBkYXRlOiAxLFxyXG5cdE1hdHJpeFdvcmxkTmVlZHNVcGRhdGU6IDJcclxufTtcclxuXHJcblByb3BlcnR5QmluZGluZy5wcm90b3R5cGUuR2V0dGVyQnlCaW5kaW5nVHlwZSA9IFtcclxuXHJcblx0UHJvcGVydHlCaW5kaW5nLnByb3RvdHlwZS5fZ2V0VmFsdWVfZGlyZWN0LFxyXG5cdFByb3BlcnR5QmluZGluZy5wcm90b3R5cGUuX2dldFZhbHVlX2FycmF5LFxyXG5cdFByb3BlcnR5QmluZGluZy5wcm90b3R5cGUuX2dldFZhbHVlX2FycmF5RWxlbWVudCxcclxuXHRQcm9wZXJ0eUJpbmRpbmcucHJvdG90eXBlLl9nZXRWYWx1ZV90b0FycmF5LFxyXG5cclxuXTtcclxuXHJcblByb3BlcnR5QmluZGluZy5wcm90b3R5cGUuU2V0dGVyQnlCaW5kaW5nVHlwZUFuZFZlcnNpb25pbmcgPSBbXHJcblxyXG5cdFtcclxuXHRcdC8vIERpcmVjdFxyXG5cdFx0UHJvcGVydHlCaW5kaW5nLnByb3RvdHlwZS5fc2V0VmFsdWVfZGlyZWN0LFxyXG5cdFx0UHJvcGVydHlCaW5kaW5nLnByb3RvdHlwZS5fc2V0VmFsdWVfZGlyZWN0X3NldE5lZWRzVXBkYXRlLFxyXG5cdFx0UHJvcGVydHlCaW5kaW5nLnByb3RvdHlwZS5fc2V0VmFsdWVfZGlyZWN0X3NldE1hdHJpeFdvcmxkTmVlZHNVcGRhdGUsXHJcblxyXG5cdF0sIFtcclxuXHJcblx0XHQvLyBFbnRpcmVBcnJheVxyXG5cclxuXHRcdFByb3BlcnR5QmluZGluZy5wcm90b3R5cGUuX3NldFZhbHVlX2FycmF5LFxyXG5cdFx0UHJvcGVydHlCaW5kaW5nLnByb3RvdHlwZS5fc2V0VmFsdWVfYXJyYXlfc2V0TmVlZHNVcGRhdGUsXHJcblx0XHRQcm9wZXJ0eUJpbmRpbmcucHJvdG90eXBlLl9zZXRWYWx1ZV9hcnJheV9zZXRNYXRyaXhXb3JsZE5lZWRzVXBkYXRlLFxyXG5cclxuXHRdLCBbXHJcblxyXG5cdFx0Ly8gQXJyYXlFbGVtZW50XHJcblx0XHRQcm9wZXJ0eUJpbmRpbmcucHJvdG90eXBlLl9zZXRWYWx1ZV9hcnJheUVsZW1lbnQsXHJcblx0XHRQcm9wZXJ0eUJpbmRpbmcucHJvdG90eXBlLl9zZXRWYWx1ZV9hcnJheUVsZW1lbnRfc2V0TmVlZHNVcGRhdGUsXHJcblx0XHRQcm9wZXJ0eUJpbmRpbmcucHJvdG90eXBlLl9zZXRWYWx1ZV9hcnJheUVsZW1lbnRfc2V0TWF0cml4V29ybGROZWVkc1VwZGF0ZSxcclxuXHJcblx0XSwgW1xyXG5cclxuXHRcdC8vIEhhc1RvRnJvbUFycmF5XHJcblx0XHRQcm9wZXJ0eUJpbmRpbmcucHJvdG90eXBlLl9zZXRWYWx1ZV9mcm9tQXJyYXksXHJcblx0XHRQcm9wZXJ0eUJpbmRpbmcucHJvdG90eXBlLl9zZXRWYWx1ZV9mcm9tQXJyYXlfc2V0TmVlZHNVcGRhdGUsXHJcblx0XHRQcm9wZXJ0eUJpbmRpbmcucHJvdG90eXBlLl9zZXRWYWx1ZV9mcm9tQXJyYXlfc2V0TWF0cml4V29ybGROZWVkc1VwZGF0ZSxcclxuXHJcblx0XVxyXG5cclxuXTtcclxuXHJcblxyXG5leHBvcnQgeyBQcm9wZXJ0eUJpbmRpbmcgfTtcclxuIiwiaW1wb3J0IHsgUHJvcGVydHlCaW5kaW5nIH0gZnJvbSAnLi9Qcm9wZXJ0eUJpbmRpbmcuanMnO1xyXG5pbXBvcnQgKiBhcyBNYXRoVXRpbHMgZnJvbSAnLi4vbWF0aC9NYXRoVXRpbHMuanMnO1xyXG5cclxuLyoqXHJcbiAqXHJcbiAqIEEgZ3JvdXAgb2Ygb2JqZWN0cyB0aGF0IHJlY2VpdmVzIGEgc2hhcmVkIGFuaW1hdGlvbiBzdGF0ZS5cclxuICpcclxuICogVXNhZ2U6XHJcbiAqXHJcbiAqICAtIEFkZCBvYmplY3RzIHlvdSB3b3VsZCBvdGhlcndpc2UgcGFzcyBhcyAncm9vdCcgdG8gdGhlXHJcbiAqICAgIGNvbnN0cnVjdG9yIG9yIHRoZSAuY2xpcEFjdGlvbiBtZXRob2Qgb2YgQW5pbWF0aW9uTWl4ZXIuXHJcbiAqXHJcbiAqICAtIEluc3RlYWQgcGFzcyB0aGlzIG9iamVjdCBhcyAncm9vdCcuXHJcbiAqXHJcbiAqICAtIFlvdSBjYW4gYWxzbyBhZGQgYW5kIHJlbW92ZSBvYmplY3RzIGxhdGVyIHdoZW4gdGhlIG1peGVyXHJcbiAqICAgIGlzIHJ1bm5pbmcuXHJcbiAqXHJcbiAqIE5vdGU6XHJcbiAqXHJcbiAqICAgIE9iamVjdHMgb2YgdGhpcyBjbGFzcyBhcHBlYXIgYXMgb25lIG9iamVjdCB0byB0aGUgbWl4ZXIsXHJcbiAqICAgIHNvIGNhY2hlIGNvbnRyb2wgb2YgdGhlIGluZGl2aWR1YWwgb2JqZWN0cyBtdXN0IGJlIGRvbmVcclxuICogICAgb24gdGhlIGdyb3VwLlxyXG4gKlxyXG4gKiBMaW1pdGF0aW9uOlxyXG4gKlxyXG4gKiAgLSBUaGUgYW5pbWF0ZWQgcHJvcGVydGllcyBtdXN0IGJlIGNvbXBhdGlibGUgYW1vbmcgdGhlXHJcbiAqICAgIGFsbCBvYmplY3RzIGluIHRoZSBncm91cC5cclxuICpcclxuICogIC0gQSBzaW5nbGUgcHJvcGVydHkgY2FuIGVpdGhlciBiZSBjb250cm9sbGVkIHRocm91Z2ggYVxyXG4gKiAgICB0YXJnZXQgZ3JvdXAgb3IgZGlyZWN0bHksIGJ1dCBub3QgYm90aC5cclxuICovXHJcblxyXG5jbGFzcyBBbmltYXRpb25PYmplY3RHcm91cCB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCkge1xyXG5cclxuXHRcdHRoaXMuaXNBbmltYXRpb25PYmplY3RHcm91cCA9IHRydWU7XHJcblxyXG5cdFx0dGhpcy51dWlkID0gTWF0aFV0aWxzLmdlbmVyYXRlVVVJRCgpO1xyXG5cclxuXHRcdC8vIGNhY2hlZCBvYmplY3RzIGZvbGxvd2VkIGJ5IHRoZSBhY3RpdmUgb25lc1xyXG5cdFx0dGhpcy5fb2JqZWN0cyA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKCBhcmd1bWVudHMgKTtcclxuXHJcblx0XHR0aGlzLm5DYWNoZWRPYmplY3RzXyA9IDA7IC8vIHRocmVzaG9sZFxyXG5cdFx0Ly8gbm90ZTogcmVhZCBieSBQcm9wZXJ0eUJpbmRpbmcuQ29tcG9zaXRlXHJcblxyXG5cdFx0Y29uc3QgaW5kaWNlcyA9IHt9O1xyXG5cdFx0dGhpcy5faW5kaWNlc0J5VVVJRCA9IGluZGljZXM7IC8vIGZvciBib29ra2VlcGluZ1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMCwgbiA9IGFyZ3VtZW50cy5sZW5ndGg7IGkgIT09IG47ICsrIGkgKSB7XHJcblxyXG5cdFx0XHRpbmRpY2VzWyBhcmd1bWVudHNbIGkgXS51dWlkIF0gPSBpO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLl9wYXRocyA9IFtdOyAvLyBpbnNpZGU6IHN0cmluZ1xyXG5cdFx0dGhpcy5fcGFyc2VkUGF0aHMgPSBbXTsgLy8gaW5zaWRlOiB7IHdlIGRvbid0IGNhcmUsIGhlcmUgfVxyXG5cdFx0dGhpcy5fYmluZGluZ3MgPSBbXTsgLy8gaW5zaWRlOiBBcnJheTwgUHJvcGVydHlCaW5kaW5nID5cclxuXHRcdHRoaXMuX2JpbmRpbmdzSW5kaWNlc0J5UGF0aCA9IHt9OyAvLyBpbnNpZGU6IGluZGljZXMgaW4gdGhlc2UgYXJyYXlzXHJcblxyXG5cdFx0Y29uc3Qgc2NvcGUgPSB0aGlzO1xyXG5cclxuXHRcdHRoaXMuc3RhdHMgPSB7XHJcblxyXG5cdFx0XHRvYmplY3RzOiB7XHJcblx0XHRcdFx0Z2V0IHRvdGFsKCkge1xyXG5cclxuXHRcdFx0XHRcdHJldHVybiBzY29wZS5fb2JqZWN0cy5sZW5ndGg7XHJcblxyXG5cdFx0XHRcdH0sXHJcblx0XHRcdFx0Z2V0IGluVXNlKCkge1xyXG5cclxuXHRcdFx0XHRcdHJldHVybiB0aGlzLnRvdGFsIC0gc2NvcGUubkNhY2hlZE9iamVjdHNfO1xyXG5cclxuXHRcdFx0XHR9XHJcblx0XHRcdH0sXHJcblx0XHRcdGdldCBiaW5kaW5nc1Blck9iamVjdCgpIHtcclxuXHJcblx0XHRcdFx0cmV0dXJuIHNjb3BlLl9iaW5kaW5ncy5sZW5ndGg7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fTtcclxuXHJcblx0fVxyXG5cclxuXHRhZGQoKSB7XHJcblxyXG5cdFx0Y29uc3Qgb2JqZWN0cyA9IHRoaXMuX29iamVjdHMsXHJcblx0XHRcdGluZGljZXNCeVVVSUQgPSB0aGlzLl9pbmRpY2VzQnlVVUlELFxyXG5cdFx0XHRwYXRocyA9IHRoaXMuX3BhdGhzLFxyXG5cdFx0XHRwYXJzZWRQYXRocyA9IHRoaXMuX3BhcnNlZFBhdGhzLFxyXG5cdFx0XHRiaW5kaW5ncyA9IHRoaXMuX2JpbmRpbmdzLFxyXG5cdFx0XHRuQmluZGluZ3MgPSBiaW5kaW5ncy5sZW5ndGg7XHJcblxyXG5cdFx0bGV0IGtub3duT2JqZWN0ID0gdW5kZWZpbmVkLFxyXG5cdFx0XHRuT2JqZWN0cyA9IG9iamVjdHMubGVuZ3RoLFxyXG5cdFx0XHRuQ2FjaGVkT2JqZWN0cyA9IHRoaXMubkNhY2hlZE9iamVjdHNfO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMCwgbiA9IGFyZ3VtZW50cy5sZW5ndGg7IGkgIT09IG47ICsrIGkgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBvYmplY3QgPSBhcmd1bWVudHNbIGkgXSxcclxuXHRcdFx0XHR1dWlkID0gb2JqZWN0LnV1aWQ7XHJcblx0XHRcdGxldCBpbmRleCA9IGluZGljZXNCeVVVSURbIHV1aWQgXTtcclxuXHJcblx0XHRcdGlmICggaW5kZXggPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0Ly8gdW5rbm93biBvYmplY3QgLT4gYWRkIGl0IHRvIHRoZSBBQ1RJVkUgcmVnaW9uXHJcblxyXG5cdFx0XHRcdGluZGV4ID0gbk9iamVjdHMgKys7XHJcblx0XHRcdFx0aW5kaWNlc0J5VVVJRFsgdXVpZCBdID0gaW5kZXg7XHJcblx0XHRcdFx0b2JqZWN0cy5wdXNoKCBvYmplY3QgKTtcclxuXHJcblx0XHRcdFx0Ly8gYWNjb3VudGluZyBpcyBkb25lLCBub3cgZG8gdGhlIHNhbWUgZm9yIGFsbCBiaW5kaW5nc1xyXG5cclxuXHRcdFx0XHRmb3IgKCBsZXQgaiA9IDAsIG0gPSBuQmluZGluZ3M7IGogIT09IG07ICsrIGogKSB7XHJcblxyXG5cdFx0XHRcdFx0YmluZGluZ3NbIGogXS5wdXNoKCBuZXcgUHJvcGVydHlCaW5kaW5nKCBvYmplY3QsIHBhdGhzWyBqIF0sIHBhcnNlZFBhdGhzWyBqIF0gKSApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9IGVsc2UgaWYgKCBpbmRleCA8IG5DYWNoZWRPYmplY3RzICkge1xyXG5cclxuXHRcdFx0XHRrbm93bk9iamVjdCA9IG9iamVjdHNbIGluZGV4IF07XHJcblxyXG5cdFx0XHRcdC8vIG1vdmUgZXhpc3Rpbmcgb2JqZWN0IHRvIHRoZSBBQ1RJVkUgcmVnaW9uXHJcblxyXG5cdFx0XHRcdGNvbnN0IGZpcnN0QWN0aXZlSW5kZXggPSAtLSBuQ2FjaGVkT2JqZWN0cyxcclxuXHRcdFx0XHRcdGxhc3RDYWNoZWRPYmplY3QgPSBvYmplY3RzWyBmaXJzdEFjdGl2ZUluZGV4IF07XHJcblxyXG5cdFx0XHRcdGluZGljZXNCeVVVSURbIGxhc3RDYWNoZWRPYmplY3QudXVpZCBdID0gaW5kZXg7XHJcblx0XHRcdFx0b2JqZWN0c1sgaW5kZXggXSA9IGxhc3RDYWNoZWRPYmplY3Q7XHJcblxyXG5cdFx0XHRcdGluZGljZXNCeVVVSURbIHV1aWQgXSA9IGZpcnN0QWN0aXZlSW5kZXg7XHJcblx0XHRcdFx0b2JqZWN0c1sgZmlyc3RBY3RpdmVJbmRleCBdID0gb2JqZWN0O1xyXG5cclxuXHRcdFx0XHQvLyBhY2NvdW50aW5nIGlzIGRvbmUsIG5vdyBkbyB0aGUgc2FtZSBmb3IgYWxsIGJpbmRpbmdzXHJcblxyXG5cdFx0XHRcdGZvciAoIGxldCBqID0gMCwgbSA9IG5CaW5kaW5nczsgaiAhPT0gbTsgKysgaiApIHtcclxuXHJcblx0XHRcdFx0XHRjb25zdCBiaW5kaW5nc0ZvclBhdGggPSBiaW5kaW5nc1sgaiBdLFxyXG5cdFx0XHRcdFx0XHRsYXN0Q2FjaGVkID0gYmluZGluZ3NGb3JQYXRoWyBmaXJzdEFjdGl2ZUluZGV4IF07XHJcblxyXG5cdFx0XHRcdFx0bGV0IGJpbmRpbmcgPSBiaW5kaW5nc0ZvclBhdGhbIGluZGV4IF07XHJcblxyXG5cdFx0XHRcdFx0YmluZGluZ3NGb3JQYXRoWyBpbmRleCBdID0gbGFzdENhY2hlZDtcclxuXHJcblx0XHRcdFx0XHRpZiAoIGJpbmRpbmcgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0XHRcdC8vIHNpbmNlIHdlIGRvIG5vdCBib3RoZXIgdG8gY3JlYXRlIG5ldyBiaW5kaW5nc1xyXG5cdFx0XHRcdFx0XHQvLyBmb3Igb2JqZWN0cyB0aGF0IGFyZSBjYWNoZWQsIHRoZSBiaW5kaW5nIG1heVxyXG5cdFx0XHRcdFx0XHQvLyBvciBtYXkgbm90IGV4aXN0XHJcblxyXG5cdFx0XHRcdFx0XHRiaW5kaW5nID0gbmV3IFByb3BlcnR5QmluZGluZyggb2JqZWN0LCBwYXRoc1sgaiBdLCBwYXJzZWRQYXRoc1sgaiBdICk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdGJpbmRpbmdzRm9yUGF0aFsgZmlyc3RBY3RpdmVJbmRleCBdID0gYmluZGluZztcclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fSBlbHNlIGlmICggb2JqZWN0c1sgaW5kZXggXSAhPT0ga25vd25PYmplY3QgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5BbmltYXRpb25PYmplY3RHcm91cDogRGlmZmVyZW50IG9iamVjdHMgd2l0aCB0aGUgc2FtZSBVVUlEICcgK1xyXG5cdFx0XHRcdFx0J2RldGVjdGVkLiBDbGVhbiB0aGUgY2FjaGVzIG9yIHJlY3JlYXRlIHlvdXIgaW5mcmFzdHJ1Y3R1cmUgd2hlbiByZWxvYWRpbmcgc2NlbmVzLicgKTtcclxuXHJcblx0XHRcdH0gLy8gZWxzZSB0aGUgb2JqZWN0IGlzIGFscmVhZHkgd2hlcmUgd2Ugd2FudCBpdCB0byBiZVxyXG5cclxuXHRcdH0gLy8gZm9yIGFyZ3VtZW50c1xyXG5cclxuXHRcdHRoaXMubkNhY2hlZE9iamVjdHNfID0gbkNhY2hlZE9iamVjdHM7XHJcblxyXG5cdH1cclxuXHJcblx0cmVtb3ZlKCkge1xyXG5cclxuXHRcdGNvbnN0IG9iamVjdHMgPSB0aGlzLl9vYmplY3RzLFxyXG5cdFx0XHRpbmRpY2VzQnlVVUlEID0gdGhpcy5faW5kaWNlc0J5VVVJRCxcclxuXHRcdFx0YmluZGluZ3MgPSB0aGlzLl9iaW5kaW5ncyxcclxuXHRcdFx0bkJpbmRpbmdzID0gYmluZGluZ3MubGVuZ3RoO1xyXG5cclxuXHRcdGxldCBuQ2FjaGVkT2JqZWN0cyA9IHRoaXMubkNhY2hlZE9iamVjdHNfO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMCwgbiA9IGFyZ3VtZW50cy5sZW5ndGg7IGkgIT09IG47ICsrIGkgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBvYmplY3QgPSBhcmd1bWVudHNbIGkgXSxcclxuXHRcdFx0XHR1dWlkID0gb2JqZWN0LnV1aWQsXHJcblx0XHRcdFx0aW5kZXggPSBpbmRpY2VzQnlVVUlEWyB1dWlkIF07XHJcblxyXG5cdFx0XHRpZiAoIGluZGV4ICE9PSB1bmRlZmluZWQgJiYgaW5kZXggPj0gbkNhY2hlZE9iamVjdHMgKSB7XHJcblxyXG5cdFx0XHRcdC8vIG1vdmUgZXhpc3Rpbmcgb2JqZWN0IGludG8gdGhlIENBQ0hFRCByZWdpb25cclxuXHJcblx0XHRcdFx0Y29uc3QgbGFzdENhY2hlZEluZGV4ID0gbkNhY2hlZE9iamVjdHMgKyssXHJcblx0XHRcdFx0XHRmaXJzdEFjdGl2ZU9iamVjdCA9IG9iamVjdHNbIGxhc3RDYWNoZWRJbmRleCBdO1xyXG5cclxuXHRcdFx0XHRpbmRpY2VzQnlVVUlEWyBmaXJzdEFjdGl2ZU9iamVjdC51dWlkIF0gPSBpbmRleDtcclxuXHRcdFx0XHRvYmplY3RzWyBpbmRleCBdID0gZmlyc3RBY3RpdmVPYmplY3Q7XHJcblxyXG5cdFx0XHRcdGluZGljZXNCeVVVSURbIHV1aWQgXSA9IGxhc3RDYWNoZWRJbmRleDtcclxuXHRcdFx0XHRvYmplY3RzWyBsYXN0Q2FjaGVkSW5kZXggXSA9IG9iamVjdDtcclxuXHJcblx0XHRcdFx0Ly8gYWNjb3VudGluZyBpcyBkb25lLCBub3cgZG8gdGhlIHNhbWUgZm9yIGFsbCBiaW5kaW5nc1xyXG5cclxuXHRcdFx0XHRmb3IgKCBsZXQgaiA9IDAsIG0gPSBuQmluZGluZ3M7IGogIT09IG07ICsrIGogKSB7XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgYmluZGluZ3NGb3JQYXRoID0gYmluZGluZ3NbIGogXSxcclxuXHRcdFx0XHRcdFx0Zmlyc3RBY3RpdmUgPSBiaW5kaW5nc0ZvclBhdGhbIGxhc3RDYWNoZWRJbmRleCBdLFxyXG5cdFx0XHRcdFx0XHRiaW5kaW5nID0gYmluZGluZ3NGb3JQYXRoWyBpbmRleCBdO1xyXG5cclxuXHRcdFx0XHRcdGJpbmRpbmdzRm9yUGF0aFsgaW5kZXggXSA9IGZpcnN0QWN0aXZlO1xyXG5cdFx0XHRcdFx0YmluZGluZ3NGb3JQYXRoWyBsYXN0Q2FjaGVkSW5kZXggXSA9IGJpbmRpbmc7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9IC8vIGZvciBhcmd1bWVudHNcclxuXHJcblx0XHR0aGlzLm5DYWNoZWRPYmplY3RzXyA9IG5DYWNoZWRPYmplY3RzO1xyXG5cclxuXHR9XHJcblxyXG5cdC8vIHJlbW92ZSAmIGZvcmdldFxyXG5cdHVuY2FjaGUoKSB7XHJcblxyXG5cdFx0Y29uc3Qgb2JqZWN0cyA9IHRoaXMuX29iamVjdHMsXHJcblx0XHRcdGluZGljZXNCeVVVSUQgPSB0aGlzLl9pbmRpY2VzQnlVVUlELFxyXG5cdFx0XHRiaW5kaW5ncyA9IHRoaXMuX2JpbmRpbmdzLFxyXG5cdFx0XHRuQmluZGluZ3MgPSBiaW5kaW5ncy5sZW5ndGg7XHJcblxyXG5cdFx0bGV0IG5DYWNoZWRPYmplY3RzID0gdGhpcy5uQ2FjaGVkT2JqZWN0c18sXHJcblx0XHRcdG5PYmplY3RzID0gb2JqZWN0cy5sZW5ndGg7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBuID0gYXJndW1lbnRzLmxlbmd0aDsgaSAhPT0gbjsgKysgaSApIHtcclxuXHJcblx0XHRcdGNvbnN0IG9iamVjdCA9IGFyZ3VtZW50c1sgaSBdLFxyXG5cdFx0XHRcdHV1aWQgPSBvYmplY3QudXVpZCxcclxuXHRcdFx0XHRpbmRleCA9IGluZGljZXNCeVVVSURbIHV1aWQgXTtcclxuXHJcblx0XHRcdGlmICggaW5kZXggIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0ZGVsZXRlIGluZGljZXNCeVVVSURbIHV1aWQgXTtcclxuXHJcblx0XHRcdFx0aWYgKCBpbmRleCA8IG5DYWNoZWRPYmplY3RzICkge1xyXG5cclxuXHRcdFx0XHRcdC8vIG9iamVjdCBpcyBjYWNoZWQsIHNocmluayB0aGUgQ0FDSEVEIHJlZ2lvblxyXG5cclxuXHRcdFx0XHRcdGNvbnN0IGZpcnN0QWN0aXZlSW5kZXggPSAtLSBuQ2FjaGVkT2JqZWN0cyxcclxuXHRcdFx0XHRcdFx0bGFzdENhY2hlZE9iamVjdCA9IG9iamVjdHNbIGZpcnN0QWN0aXZlSW5kZXggXSxcclxuXHRcdFx0XHRcdFx0bGFzdEluZGV4ID0gLS0gbk9iamVjdHMsXHJcblx0XHRcdFx0XHRcdGxhc3RPYmplY3QgPSBvYmplY3RzWyBsYXN0SW5kZXggXTtcclxuXHJcblx0XHRcdFx0XHQvLyBsYXN0IGNhY2hlZCBvYmplY3QgdGFrZXMgdGhpcyBvYmplY3QncyBwbGFjZVxyXG5cdFx0XHRcdFx0aW5kaWNlc0J5VVVJRFsgbGFzdENhY2hlZE9iamVjdC51dWlkIF0gPSBpbmRleDtcclxuXHRcdFx0XHRcdG9iamVjdHNbIGluZGV4IF0gPSBsYXN0Q2FjaGVkT2JqZWN0O1xyXG5cclxuXHRcdFx0XHRcdC8vIGxhc3Qgb2JqZWN0IGdvZXMgdG8gdGhlIGFjdGl2YXRlZCBzbG90IGFuZCBwb3BcclxuXHRcdFx0XHRcdGluZGljZXNCeVVVSURbIGxhc3RPYmplY3QudXVpZCBdID0gZmlyc3RBY3RpdmVJbmRleDtcclxuXHRcdFx0XHRcdG9iamVjdHNbIGZpcnN0QWN0aXZlSW5kZXggXSA9IGxhc3RPYmplY3Q7XHJcblx0XHRcdFx0XHRvYmplY3RzLnBvcCgpO1xyXG5cclxuXHRcdFx0XHRcdC8vIGFjY291bnRpbmcgaXMgZG9uZSwgbm93IGRvIHRoZSBzYW1lIGZvciBhbGwgYmluZGluZ3NcclxuXHJcblx0XHRcdFx0XHRmb3IgKCBsZXQgaiA9IDAsIG0gPSBuQmluZGluZ3M7IGogIT09IG07ICsrIGogKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRjb25zdCBiaW5kaW5nc0ZvclBhdGggPSBiaW5kaW5nc1sgaiBdLFxyXG5cdFx0XHRcdFx0XHRcdGxhc3RDYWNoZWQgPSBiaW5kaW5nc0ZvclBhdGhbIGZpcnN0QWN0aXZlSW5kZXggXSxcclxuXHRcdFx0XHRcdFx0XHRsYXN0ID0gYmluZGluZ3NGb3JQYXRoWyBsYXN0SW5kZXggXTtcclxuXHJcblx0XHRcdFx0XHRcdGJpbmRpbmdzRm9yUGF0aFsgaW5kZXggXSA9IGxhc3RDYWNoZWQ7XHJcblx0XHRcdFx0XHRcdGJpbmRpbmdzRm9yUGF0aFsgZmlyc3RBY3RpdmVJbmRleCBdID0gbGFzdDtcclxuXHRcdFx0XHRcdFx0YmluZGluZ3NGb3JQYXRoLnBvcCgpO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHQvLyBvYmplY3QgaXMgYWN0aXZlLCBqdXN0IHN3YXAgd2l0aCB0aGUgbGFzdCBhbmQgcG9wXHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgbGFzdEluZGV4ID0gLS0gbk9iamVjdHMsXHJcblx0XHRcdFx0XHRcdGxhc3RPYmplY3QgPSBvYmplY3RzWyBsYXN0SW5kZXggXTtcclxuXHJcblx0XHRcdFx0XHRpZiAoIGxhc3RJbmRleCA+IDAgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRpbmRpY2VzQnlVVUlEWyBsYXN0T2JqZWN0LnV1aWQgXSA9IGluZGV4O1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRvYmplY3RzWyBpbmRleCBdID0gbGFzdE9iamVjdDtcclxuXHRcdFx0XHRcdG9iamVjdHMucG9wKCk7XHJcblxyXG5cdFx0XHRcdFx0Ly8gYWNjb3VudGluZyBpcyBkb25lLCBub3cgZG8gdGhlIHNhbWUgZm9yIGFsbCBiaW5kaW5nc1xyXG5cclxuXHRcdFx0XHRcdGZvciAoIGxldCBqID0gMCwgbSA9IG5CaW5kaW5nczsgaiAhPT0gbTsgKysgaiApIHtcclxuXHJcblx0XHRcdFx0XHRcdGNvbnN0IGJpbmRpbmdzRm9yUGF0aCA9IGJpbmRpbmdzWyBqIF07XHJcblxyXG5cdFx0XHRcdFx0XHRiaW5kaW5nc0ZvclBhdGhbIGluZGV4IF0gPSBiaW5kaW5nc0ZvclBhdGhbIGxhc3RJbmRleCBdO1xyXG5cdFx0XHRcdFx0XHRiaW5kaW5nc0ZvclBhdGgucG9wKCk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR9IC8vIGNhY2hlZCBvciBhY3RpdmVcclxuXHJcblx0XHRcdH0gLy8gaWYgb2JqZWN0IGlzIGtub3duXHJcblxyXG5cdFx0fSAvLyBmb3IgYXJndW1lbnRzXHJcblxyXG5cdFx0dGhpcy5uQ2FjaGVkT2JqZWN0c18gPSBuQ2FjaGVkT2JqZWN0cztcclxuXHJcblx0fVxyXG5cclxuXHQvLyBJbnRlcm5hbCBpbnRlcmZhY2UgdXNlZCBieSBiZWZyaWVuZGVkIFByb3BlcnR5QmluZGluZy5Db21wb3NpdGU6XHJcblxyXG5cdHN1YnNjcmliZV8oIHBhdGgsIHBhcnNlZFBhdGggKSB7XHJcblxyXG5cdFx0Ly8gcmV0dXJucyBhbiBhcnJheSBvZiBiaW5kaW5ncyBmb3IgdGhlIGdpdmVuIHBhdGggdGhhdCBpcyBjaGFuZ2VkXHJcblx0XHQvLyBhY2NvcmRpbmcgdG8gdGhlIGNvbnRhaW5lZCBvYmplY3RzIGluIHRoZSBncm91cFxyXG5cclxuXHRcdGNvbnN0IGluZGljZXNCeVBhdGggPSB0aGlzLl9iaW5kaW5nc0luZGljZXNCeVBhdGg7XHJcblx0XHRsZXQgaW5kZXggPSBpbmRpY2VzQnlQYXRoWyBwYXRoIF07XHJcblx0XHRjb25zdCBiaW5kaW5ncyA9IHRoaXMuX2JpbmRpbmdzO1xyXG5cclxuXHRcdGlmICggaW5kZXggIT09IHVuZGVmaW5lZCApIHJldHVybiBiaW5kaW5nc1sgaW5kZXggXTtcclxuXHJcblx0XHRjb25zdCBwYXRocyA9IHRoaXMuX3BhdGhzLFxyXG5cdFx0XHRwYXJzZWRQYXRocyA9IHRoaXMuX3BhcnNlZFBhdGhzLFxyXG5cdFx0XHRvYmplY3RzID0gdGhpcy5fb2JqZWN0cyxcclxuXHRcdFx0bk9iamVjdHMgPSBvYmplY3RzLmxlbmd0aCxcclxuXHRcdFx0bkNhY2hlZE9iamVjdHMgPSB0aGlzLm5DYWNoZWRPYmplY3RzXyxcclxuXHRcdFx0YmluZGluZ3NGb3JQYXRoID0gbmV3IEFycmF5KCBuT2JqZWN0cyApO1xyXG5cclxuXHRcdGluZGV4ID0gYmluZGluZ3MubGVuZ3RoO1xyXG5cclxuXHRcdGluZGljZXNCeVBhdGhbIHBhdGggXSA9IGluZGV4O1xyXG5cclxuXHRcdHBhdGhzLnB1c2goIHBhdGggKTtcclxuXHRcdHBhcnNlZFBhdGhzLnB1c2goIHBhcnNlZFBhdGggKTtcclxuXHRcdGJpbmRpbmdzLnB1c2goIGJpbmRpbmdzRm9yUGF0aCApO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gbkNhY2hlZE9iamVjdHMsIG4gPSBvYmplY3RzLmxlbmd0aDsgaSAhPT0gbjsgKysgaSApIHtcclxuXHJcblx0XHRcdGNvbnN0IG9iamVjdCA9IG9iamVjdHNbIGkgXTtcclxuXHRcdFx0YmluZGluZ3NGb3JQYXRoWyBpIF0gPSBuZXcgUHJvcGVydHlCaW5kaW5nKCBvYmplY3QsIHBhdGgsIHBhcnNlZFBhdGggKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIGJpbmRpbmdzRm9yUGF0aDtcclxuXHJcblx0fVxyXG5cclxuXHR1bnN1YnNjcmliZV8oIHBhdGggKSB7XHJcblxyXG5cdFx0Ly8gdGVsbHMgdGhlIGdyb3VwIHRvIGZvcmdldCBhYm91dCBhIHByb3BlcnR5IHBhdGggYW5kIG5vIGxvbmdlclxyXG5cdFx0Ly8gdXBkYXRlIHRoZSBhcnJheSBwcmV2aW91c2x5IG9idGFpbmVkIHdpdGggJ3N1YnNjcmliZV8nXHJcblxyXG5cdFx0Y29uc3QgaW5kaWNlc0J5UGF0aCA9IHRoaXMuX2JpbmRpbmdzSW5kaWNlc0J5UGF0aCxcclxuXHRcdFx0aW5kZXggPSBpbmRpY2VzQnlQYXRoWyBwYXRoIF07XHJcblxyXG5cdFx0aWYgKCBpbmRleCAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0Y29uc3QgcGF0aHMgPSB0aGlzLl9wYXRocyxcclxuXHRcdFx0XHRwYXJzZWRQYXRocyA9IHRoaXMuX3BhcnNlZFBhdGhzLFxyXG5cdFx0XHRcdGJpbmRpbmdzID0gdGhpcy5fYmluZGluZ3MsXHJcblx0XHRcdFx0bGFzdEJpbmRpbmdzSW5kZXggPSBiaW5kaW5ncy5sZW5ndGggLSAxLFxyXG5cdFx0XHRcdGxhc3RCaW5kaW5ncyA9IGJpbmRpbmdzWyBsYXN0QmluZGluZ3NJbmRleCBdLFxyXG5cdFx0XHRcdGxhc3RCaW5kaW5nc1BhdGggPSBwYXRoWyBsYXN0QmluZGluZ3NJbmRleCBdO1xyXG5cclxuXHRcdFx0aW5kaWNlc0J5UGF0aFsgbGFzdEJpbmRpbmdzUGF0aCBdID0gaW5kZXg7XHJcblxyXG5cdFx0XHRiaW5kaW5nc1sgaW5kZXggXSA9IGxhc3RCaW5kaW5ncztcclxuXHRcdFx0YmluZGluZ3MucG9wKCk7XHJcblxyXG5cdFx0XHRwYXJzZWRQYXRoc1sgaW5kZXggXSA9IHBhcnNlZFBhdGhzWyBsYXN0QmluZGluZ3NJbmRleCBdO1xyXG5cdFx0XHRwYXJzZWRQYXRocy5wb3AoKTtcclxuXHJcblx0XHRcdHBhdGhzWyBpbmRleCBdID0gcGF0aHNbIGxhc3RCaW5kaW5nc0luZGV4IF07XHJcblx0XHRcdHBhdGhzLnBvcCgpO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgQW5pbWF0aW9uT2JqZWN0R3JvdXAgfTtcclxuIiwiaW1wb3J0IHsgV3JhcEFyb3VuZEVuZGluZywgWmVyb0N1cnZhdHVyZUVuZGluZywgWmVyb1Nsb3BlRW5kaW5nLCBMb29wUGluZ1BvbmcsIExvb3BPbmNlLCBMb29wUmVwZWF0LCBOb3JtYWxBbmltYXRpb25CbGVuZE1vZGUsIEFkZGl0aXZlQW5pbWF0aW9uQmxlbmRNb2RlIH0gZnJvbSAnLi4vY29uc3RhbnRzLmpzJztcclxuXHJcblxyXG5jbGFzcyBBbmltYXRpb25BY3Rpb24ge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggbWl4ZXIsIGNsaXAsIGxvY2FsUm9vdCA9IG51bGwsIGJsZW5kTW9kZSA9IGNsaXAuYmxlbmRNb2RlICkge1xyXG5cclxuXHRcdHRoaXMuX21peGVyID0gbWl4ZXI7XHJcblx0XHR0aGlzLl9jbGlwID0gY2xpcDtcclxuXHRcdHRoaXMuX2xvY2FsUm9vdCA9IGxvY2FsUm9vdDtcclxuXHRcdHRoaXMuYmxlbmRNb2RlID0gYmxlbmRNb2RlO1xyXG5cclxuXHRcdGNvbnN0IHRyYWNrcyA9IGNsaXAudHJhY2tzLFxyXG5cdFx0XHRuVHJhY2tzID0gdHJhY2tzLmxlbmd0aCxcclxuXHRcdFx0aW50ZXJwb2xhbnRzID0gbmV3IEFycmF5KCBuVHJhY2tzICk7XHJcblxyXG5cdFx0Y29uc3QgaW50ZXJwb2xhbnRTZXR0aW5ncyA9IHtcclxuXHRcdFx0ZW5kaW5nU3RhcnQ6IFplcm9DdXJ2YXR1cmVFbmRpbmcsXHJcblx0XHRcdGVuZGluZ0VuZDogWmVyb0N1cnZhdHVyZUVuZGluZ1xyXG5cdFx0fTtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgIT09IG5UcmFja3M7ICsrIGkgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBpbnRlcnBvbGFudCA9IHRyYWNrc1sgaSBdLmNyZWF0ZUludGVycG9sYW50KCBudWxsICk7XHJcblx0XHRcdGludGVycG9sYW50c1sgaSBdID0gaW50ZXJwb2xhbnQ7XHJcblx0XHRcdGludGVycG9sYW50LnNldHRpbmdzID0gaW50ZXJwb2xhbnRTZXR0aW5ncztcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5faW50ZXJwb2xhbnRTZXR0aW5ncyA9IGludGVycG9sYW50U2V0dGluZ3M7XHJcblxyXG5cdFx0dGhpcy5faW50ZXJwb2xhbnRzID0gaW50ZXJwb2xhbnRzOyAvLyBib3VuZCBieSB0aGUgbWl4ZXJcclxuXHJcblx0XHQvLyBpbnNpZGU6IFByb3BlcnR5TWl4ZXIgKG1hbmFnZWQgYnkgdGhlIG1peGVyKVxyXG5cdFx0dGhpcy5fcHJvcGVydHlCaW5kaW5ncyA9IG5ldyBBcnJheSggblRyYWNrcyApO1xyXG5cclxuXHRcdHRoaXMuX2NhY2hlSW5kZXggPSBudWxsOyAvLyBmb3IgdGhlIG1lbW9yeSBtYW5hZ2VyXHJcblx0XHR0aGlzLl9ieUNsaXBDYWNoZUluZGV4ID0gbnVsbDsgLy8gZm9yIHRoZSBtZW1vcnkgbWFuYWdlclxyXG5cclxuXHRcdHRoaXMuX3RpbWVTY2FsZUludGVycG9sYW50ID0gbnVsbDtcclxuXHRcdHRoaXMuX3dlaWdodEludGVycG9sYW50ID0gbnVsbDtcclxuXHJcblx0XHR0aGlzLmxvb3AgPSBMb29wUmVwZWF0O1xyXG5cdFx0dGhpcy5fbG9vcENvdW50ID0gLSAxO1xyXG5cclxuXHRcdC8vIGdsb2JhbCBtaXhlciB0aW1lIHdoZW4gdGhlIGFjdGlvbiBpcyB0byBiZSBzdGFydGVkXHJcblx0XHQvLyBpdCdzIHNldCBiYWNrIHRvICdudWxsJyB1cG9uIHN0YXJ0IG9mIHRoZSBhY3Rpb25cclxuXHRcdHRoaXMuX3N0YXJ0VGltZSA9IG51bGw7XHJcblxyXG5cdFx0Ly8gc2NhbGVkIGxvY2FsIHRpbWUgb2YgdGhlIGFjdGlvblxyXG5cdFx0Ly8gZ2V0cyBjbGFtcGVkIG9yIHdyYXBwZWQgdG8gMC4uY2xpcC5kdXJhdGlvbiBhY2NvcmRpbmcgdG8gbG9vcFxyXG5cdFx0dGhpcy50aW1lID0gMDtcclxuXHJcblx0XHR0aGlzLnRpbWVTY2FsZSA9IDE7XHJcblx0XHR0aGlzLl9lZmZlY3RpdmVUaW1lU2NhbGUgPSAxO1xyXG5cclxuXHRcdHRoaXMud2VpZ2h0ID0gMTtcclxuXHRcdHRoaXMuX2VmZmVjdGl2ZVdlaWdodCA9IDE7XHJcblxyXG5cdFx0dGhpcy5yZXBldGl0aW9ucyA9IEluZmluaXR5OyAvLyBuby4gb2YgcmVwZXRpdGlvbnMgd2hlbiBsb29waW5nXHJcblxyXG5cdFx0dGhpcy5wYXVzZWQgPSBmYWxzZTsgLy8gdHJ1ZSAtPiB6ZXJvIGVmZmVjdGl2ZSB0aW1lIHNjYWxlXHJcblx0XHR0aGlzLmVuYWJsZWQgPSB0cnVlOyAvLyBmYWxzZSAtPiB6ZXJvIGVmZmVjdGl2ZSB3ZWlnaHRcclxuXHJcblx0XHR0aGlzLmNsYW1wV2hlbkZpbmlzaGVkID0gZmFsc2U7Ly8ga2VlcCBmZWVkaW5nIHRoZSBsYXN0IGZyYW1lP1xyXG5cclxuXHRcdHRoaXMuemVyb1Nsb3BlQXRTdGFydCA9IHRydWU7Ly8gZm9yIHNtb290aCBpbnRlcnBvbGF0aW9uIHcvbyBzZXBhcmF0ZVxyXG5cdFx0dGhpcy56ZXJvU2xvcGVBdEVuZCA9IHRydWU7Ly8gY2xpcHMgZm9yIHN0YXJ0LCBsb29wIGFuZCBlbmRcclxuXHJcblx0fVxyXG5cclxuXHQvLyBTdGF0ZSAmIFNjaGVkdWxpbmdcclxuXHJcblx0cGxheSgpIHtcclxuXHJcblx0XHR0aGlzLl9taXhlci5fYWN0aXZhdGVBY3Rpb24oIHRoaXMgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzdG9wKCkge1xyXG5cclxuXHRcdHRoaXMuX21peGVyLl9kZWFjdGl2YXRlQWN0aW9uKCB0aGlzICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMucmVzZXQoKTtcclxuXHJcblx0fVxyXG5cclxuXHRyZXNldCgpIHtcclxuXHJcblx0XHR0aGlzLnBhdXNlZCA9IGZhbHNlO1xyXG5cdFx0dGhpcy5lbmFibGVkID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLnRpbWUgPSAwOyAvLyByZXN0YXJ0IGNsaXBcclxuXHRcdHRoaXMuX2xvb3BDb3VudCA9IC0gMTsvLyBmb3JnZXQgcHJldmlvdXMgbG9vcHNcclxuXHRcdHRoaXMuX3N0YXJ0VGltZSA9IG51bGw7Ly8gZm9yZ2V0IHNjaGVkdWxpbmdcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5zdG9wRmFkaW5nKCkuc3RvcFdhcnBpbmcoKTtcclxuXHJcblx0fVxyXG5cclxuXHRpc1J1bm5pbmcoKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuZW5hYmxlZCAmJiAhIHRoaXMucGF1c2VkICYmIHRoaXMudGltZVNjYWxlICE9PSAwICYmXHJcblx0XHRcdHRoaXMuX3N0YXJ0VGltZSA9PT0gbnVsbCAmJiB0aGlzLl9taXhlci5faXNBY3RpdmVBY3Rpb24oIHRoaXMgKTtcclxuXHJcblx0fVxyXG5cclxuXHQvLyByZXR1cm4gdHJ1ZSB3aGVuIHBsYXkgaGFzIGJlZW4gY2FsbGVkXHJcblx0aXNTY2hlZHVsZWQoKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuX21peGVyLl9pc0FjdGl2ZUFjdGlvbiggdGhpcyApO1xyXG5cclxuXHR9XHJcblxyXG5cdHN0YXJ0QXQoIHRpbWUgKSB7XHJcblxyXG5cdFx0dGhpcy5fc3RhcnRUaW1lID0gdGltZTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRMb29wKCBtb2RlLCByZXBldGl0aW9ucyApIHtcclxuXHJcblx0XHR0aGlzLmxvb3AgPSBtb2RlO1xyXG5cdFx0dGhpcy5yZXBldGl0aW9ucyA9IHJlcGV0aXRpb25zO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdC8vIFdlaWdodFxyXG5cclxuXHQvLyBzZXQgdGhlIHdlaWdodCBzdG9wcGluZyBhbnkgc2NoZWR1bGVkIGZhZGluZ1xyXG5cdC8vIGFsdGhvdWdoIC5lbmFibGVkID0gZmFsc2UgeWllbGRzIGFuIGVmZmVjdGl2ZSB3ZWlnaHQgb2YgemVybywgdGhpc1xyXG5cdC8vIG1ldGhvZCBkb2VzICpub3QqIGNoYW5nZSAuZW5hYmxlZCwgYmVjYXVzZSBpdCB3b3VsZCBiZSBjb25mdXNpbmdcclxuXHRzZXRFZmZlY3RpdmVXZWlnaHQoIHdlaWdodCApIHtcclxuXHJcblx0XHR0aGlzLndlaWdodCA9IHdlaWdodDtcclxuXHJcblx0XHQvLyBub3RlOiBzYW1lIGxvZ2ljIGFzIHdoZW4gdXBkYXRlZCBhdCBydW50aW1lXHJcblx0XHR0aGlzLl9lZmZlY3RpdmVXZWlnaHQgPSB0aGlzLmVuYWJsZWQgPyB3ZWlnaHQgOiAwO1xyXG5cclxuXHRcdHJldHVybiB0aGlzLnN0b3BGYWRpbmcoKTtcclxuXHJcblx0fVxyXG5cclxuXHQvLyByZXR1cm4gdGhlIHdlaWdodCBjb25zaWRlcmluZyBmYWRpbmcgYW5kIC5lbmFibGVkXHJcblx0Z2V0RWZmZWN0aXZlV2VpZ2h0KCkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLl9lZmZlY3RpdmVXZWlnaHQ7XHJcblxyXG5cdH1cclxuXHJcblx0ZmFkZUluKCBkdXJhdGlvbiApIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5fc2NoZWR1bGVGYWRpbmcoIGR1cmF0aW9uLCAwLCAxICk7XHJcblxyXG5cdH1cclxuXHJcblx0ZmFkZU91dCggZHVyYXRpb24gKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuX3NjaGVkdWxlRmFkaW5nKCBkdXJhdGlvbiwgMSwgMCApO1xyXG5cclxuXHR9XHJcblxyXG5cdGNyb3NzRmFkZUZyb20oIGZhZGVPdXRBY3Rpb24sIGR1cmF0aW9uLCB3YXJwICkge1xyXG5cclxuXHRcdGZhZGVPdXRBY3Rpb24uZmFkZU91dCggZHVyYXRpb24gKTtcclxuXHRcdHRoaXMuZmFkZUluKCBkdXJhdGlvbiApO1xyXG5cclxuXHRcdGlmICggd2FycCApIHtcclxuXHJcblx0XHRcdGNvbnN0IGZhZGVJbkR1cmF0aW9uID0gdGhpcy5fY2xpcC5kdXJhdGlvbixcclxuXHRcdFx0XHRmYWRlT3V0RHVyYXRpb24gPSBmYWRlT3V0QWN0aW9uLl9jbGlwLmR1cmF0aW9uLFxyXG5cclxuXHRcdFx0XHRzdGFydEVuZFJhdGlvID0gZmFkZU91dER1cmF0aW9uIC8gZmFkZUluRHVyYXRpb24sXHJcblx0XHRcdFx0ZW5kU3RhcnRSYXRpbyA9IGZhZGVJbkR1cmF0aW9uIC8gZmFkZU91dER1cmF0aW9uO1xyXG5cclxuXHRcdFx0ZmFkZU91dEFjdGlvbi53YXJwKCAxLjAsIHN0YXJ0RW5kUmF0aW8sIGR1cmF0aW9uICk7XHJcblx0XHRcdHRoaXMud2FycCggZW5kU3RhcnRSYXRpbywgMS4wLCBkdXJhdGlvbiApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRjcm9zc0ZhZGVUbyggZmFkZUluQWN0aW9uLCBkdXJhdGlvbiwgd2FycCApIHtcclxuXHJcblx0XHRyZXR1cm4gZmFkZUluQWN0aW9uLmNyb3NzRmFkZUZyb20oIHRoaXMsIGR1cmF0aW9uLCB3YXJwICk7XHJcblxyXG5cdH1cclxuXHJcblx0c3RvcEZhZGluZygpIHtcclxuXHJcblx0XHRjb25zdCB3ZWlnaHRJbnRlcnBvbGFudCA9IHRoaXMuX3dlaWdodEludGVycG9sYW50O1xyXG5cclxuXHRcdGlmICggd2VpZ2h0SW50ZXJwb2xhbnQgIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHR0aGlzLl93ZWlnaHRJbnRlcnBvbGFudCA9IG51bGw7XHJcblx0XHRcdHRoaXMuX21peGVyLl90YWtlQmFja0NvbnRyb2xJbnRlcnBvbGFudCggd2VpZ2h0SW50ZXJwb2xhbnQgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gVGltZSBTY2FsZSBDb250cm9sXHJcblxyXG5cdC8vIHNldCB0aGUgdGltZSBzY2FsZSBzdG9wcGluZyBhbnkgc2NoZWR1bGVkIHdhcnBpbmdcclxuXHQvLyBhbHRob3VnaCAucGF1c2VkID0gdHJ1ZSB5aWVsZHMgYW4gZWZmZWN0aXZlIHRpbWUgc2NhbGUgb2YgemVybywgdGhpc1xyXG5cdC8vIG1ldGhvZCBkb2VzICpub3QqIGNoYW5nZSAucGF1c2VkLCBiZWNhdXNlIGl0IHdvdWxkIGJlIGNvbmZ1c2luZ1xyXG5cdHNldEVmZmVjdGl2ZVRpbWVTY2FsZSggdGltZVNjYWxlICkge1xyXG5cclxuXHRcdHRoaXMudGltZVNjYWxlID0gdGltZVNjYWxlO1xyXG5cdFx0dGhpcy5fZWZmZWN0aXZlVGltZVNjYWxlID0gdGhpcy5wYXVzZWQgPyAwIDogdGltZVNjYWxlO1xyXG5cclxuXHRcdHJldHVybiB0aGlzLnN0b3BXYXJwaW5nKCk7XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gcmV0dXJuIHRoZSB0aW1lIHNjYWxlIGNvbnNpZGVyaW5nIHdhcnBpbmcgYW5kIC5wYXVzZWRcclxuXHRnZXRFZmZlY3RpdmVUaW1lU2NhbGUoKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuX2VmZmVjdGl2ZVRpbWVTY2FsZTtcclxuXHJcblx0fVxyXG5cclxuXHRzZXREdXJhdGlvbiggZHVyYXRpb24gKSB7XHJcblxyXG5cdFx0dGhpcy50aW1lU2NhbGUgPSB0aGlzLl9jbGlwLmR1cmF0aW9uIC8gZHVyYXRpb247XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuc3RvcFdhcnBpbmcoKTtcclxuXHJcblx0fVxyXG5cclxuXHRzeW5jV2l0aCggYWN0aW9uICkge1xyXG5cclxuXHRcdHRoaXMudGltZSA9IGFjdGlvbi50aW1lO1xyXG5cdFx0dGhpcy50aW1lU2NhbGUgPSBhY3Rpb24udGltZVNjYWxlO1xyXG5cclxuXHRcdHJldHVybiB0aGlzLnN0b3BXYXJwaW5nKCk7XHJcblxyXG5cdH1cclxuXHJcblx0aGFsdCggZHVyYXRpb24gKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMud2FycCggdGhpcy5fZWZmZWN0aXZlVGltZVNjYWxlLCAwLCBkdXJhdGlvbiApO1xyXG5cclxuXHR9XHJcblxyXG5cdHdhcnAoIHN0YXJ0VGltZVNjYWxlLCBlbmRUaW1lU2NhbGUsIGR1cmF0aW9uICkge1xyXG5cclxuXHRcdGNvbnN0IG1peGVyID0gdGhpcy5fbWl4ZXIsXHJcblx0XHRcdG5vdyA9IG1peGVyLnRpbWUsXHJcblx0XHRcdHRpbWVTY2FsZSA9IHRoaXMudGltZVNjYWxlO1xyXG5cclxuXHRcdGxldCBpbnRlcnBvbGFudCA9IHRoaXMuX3RpbWVTY2FsZUludGVycG9sYW50O1xyXG5cclxuXHRcdGlmICggaW50ZXJwb2xhbnQgPT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRpbnRlcnBvbGFudCA9IG1peGVyLl9sZW5kQ29udHJvbEludGVycG9sYW50KCk7XHJcblx0XHRcdHRoaXMuX3RpbWVTY2FsZUludGVycG9sYW50ID0gaW50ZXJwb2xhbnQ7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGNvbnN0IHRpbWVzID0gaW50ZXJwb2xhbnQucGFyYW1ldGVyUG9zaXRpb25zLFxyXG5cdFx0XHR2YWx1ZXMgPSBpbnRlcnBvbGFudC5zYW1wbGVWYWx1ZXM7XHJcblxyXG5cdFx0dGltZXNbIDAgXSA9IG5vdztcclxuXHRcdHRpbWVzWyAxIF0gPSBub3cgKyBkdXJhdGlvbjtcclxuXHJcblx0XHR2YWx1ZXNbIDAgXSA9IHN0YXJ0VGltZVNjYWxlIC8gdGltZVNjYWxlO1xyXG5cdFx0dmFsdWVzWyAxIF0gPSBlbmRUaW1lU2NhbGUgLyB0aW1lU2NhbGU7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0c3RvcFdhcnBpbmcoKSB7XHJcblxyXG5cdFx0Y29uc3QgdGltZVNjYWxlSW50ZXJwb2xhbnQgPSB0aGlzLl90aW1lU2NhbGVJbnRlcnBvbGFudDtcclxuXHJcblx0XHRpZiAoIHRpbWVTY2FsZUludGVycG9sYW50ICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0dGhpcy5fdGltZVNjYWxlSW50ZXJwb2xhbnQgPSBudWxsO1xyXG5cdFx0XHR0aGlzLl9taXhlci5fdGFrZUJhY2tDb250cm9sSW50ZXJwb2xhbnQoIHRpbWVTY2FsZUludGVycG9sYW50ICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdC8vIE9iamVjdCBBY2Nlc3NvcnNcclxuXHJcblx0Z2V0TWl4ZXIoKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuX21peGVyO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldENsaXAoKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuX2NsaXA7XHJcblxyXG5cdH1cclxuXHJcblx0Z2V0Um9vdCgpIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5fbG9jYWxSb290IHx8IHRoaXMuX21peGVyLl9yb290O1xyXG5cclxuXHR9XHJcblxyXG5cdC8vIEludGVybmFcclxuXHJcblx0X3VwZGF0ZSggdGltZSwgZGVsdGFUaW1lLCB0aW1lRGlyZWN0aW9uLCBhY2N1SW5kZXggKSB7XHJcblxyXG5cdFx0Ly8gY2FsbGVkIGJ5IHRoZSBtaXhlclxyXG5cclxuXHRcdGlmICggISB0aGlzLmVuYWJsZWQgKSB7XHJcblxyXG5cdFx0XHQvLyBjYWxsIC5fdXBkYXRlV2VpZ2h0KCkgdG8gdXBkYXRlIC5fZWZmZWN0aXZlV2VpZ2h0XHJcblxyXG5cdFx0XHR0aGlzLl91cGRhdGVXZWlnaHQoIHRpbWUgKTtcclxuXHRcdFx0cmV0dXJuO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCBzdGFydFRpbWUgPSB0aGlzLl9zdGFydFRpbWU7XHJcblxyXG5cdFx0aWYgKCBzdGFydFRpbWUgIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHQvLyBjaGVjayBmb3Igc2NoZWR1bGVkIHN0YXJ0IG9mIGFjdGlvblxyXG5cclxuXHRcdFx0Y29uc3QgdGltZVJ1bm5pbmcgPSAoIHRpbWUgLSBzdGFydFRpbWUgKSAqIHRpbWVEaXJlY3Rpb247XHJcblx0XHRcdGlmICggdGltZVJ1bm5pbmcgPCAwIHx8IHRpbWVEaXJlY3Rpb24gPT09IDAgKSB7XHJcblxyXG5cdFx0XHRcdGRlbHRhVGltZSA9IDA7XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHJcblx0XHRcdFx0dGhpcy5fc3RhcnRUaW1lID0gbnVsbDsgLy8gdW5zY2hlZHVsZVxyXG5cdFx0XHRcdGRlbHRhVGltZSA9IHRpbWVEaXJlY3Rpb24gKiB0aW1lUnVubmluZztcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gYXBwbHkgdGltZSBzY2FsZSBhbmQgYWR2YW5jZSB0aW1lXHJcblxyXG5cdFx0ZGVsdGFUaW1lICo9IHRoaXMuX3VwZGF0ZVRpbWVTY2FsZSggdGltZSApO1xyXG5cdFx0Y29uc3QgY2xpcFRpbWUgPSB0aGlzLl91cGRhdGVUaW1lKCBkZWx0YVRpbWUgKTtcclxuXHJcblx0XHQvLyBub3RlOiBfdXBkYXRlVGltZSBtYXkgZGlzYWJsZSB0aGUgYWN0aW9uIHJlc3VsdGluZyBpblxyXG5cdFx0Ly8gYW4gZWZmZWN0aXZlIHdlaWdodCBvZiAwXHJcblxyXG5cdFx0Y29uc3Qgd2VpZ2h0ID0gdGhpcy5fdXBkYXRlV2VpZ2h0KCB0aW1lICk7XHJcblxyXG5cdFx0aWYgKCB3ZWlnaHQgPiAwICkge1xyXG5cclxuXHRcdFx0Y29uc3QgaW50ZXJwb2xhbnRzID0gdGhpcy5faW50ZXJwb2xhbnRzO1xyXG5cdFx0XHRjb25zdCBwcm9wZXJ0eU1peGVycyA9IHRoaXMuX3Byb3BlcnR5QmluZGluZ3M7XHJcblxyXG5cdFx0XHRzd2l0Y2ggKCB0aGlzLmJsZW5kTW9kZSApIHtcclxuXHJcblx0XHRcdFx0Y2FzZSBBZGRpdGl2ZUFuaW1hdGlvbkJsZW5kTW9kZTpcclxuXHJcblx0XHRcdFx0XHRmb3IgKCBsZXQgaiA9IDAsIG0gPSBpbnRlcnBvbGFudHMubGVuZ3RoOyBqICE9PSBtOyArKyBqICkge1xyXG5cclxuXHRcdFx0XHRcdFx0aW50ZXJwb2xhbnRzWyBqIF0uZXZhbHVhdGUoIGNsaXBUaW1lICk7XHJcblx0XHRcdFx0XHRcdHByb3BlcnR5TWl4ZXJzWyBqIF0uYWNjdW11bGF0ZUFkZGl0aXZlKCB3ZWlnaHQgKTtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRcdGNhc2UgTm9ybWFsQW5pbWF0aW9uQmxlbmRNb2RlOlxyXG5cdFx0XHRcdGRlZmF1bHQ6XHJcblxyXG5cdFx0XHRcdFx0Zm9yICggbGV0IGogPSAwLCBtID0gaW50ZXJwb2xhbnRzLmxlbmd0aDsgaiAhPT0gbTsgKysgaiApIHtcclxuXHJcblx0XHRcdFx0XHRcdGludGVycG9sYW50c1sgaiBdLmV2YWx1YXRlKCBjbGlwVGltZSApO1xyXG5cdFx0XHRcdFx0XHRwcm9wZXJ0eU1peGVyc1sgaiBdLmFjY3VtdWxhdGUoIGFjY3VJbmRleCwgd2VpZ2h0ICk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRfdXBkYXRlV2VpZ2h0KCB0aW1lICkge1xyXG5cclxuXHRcdGxldCB3ZWlnaHQgPSAwO1xyXG5cclxuXHRcdGlmICggdGhpcy5lbmFibGVkICkge1xyXG5cclxuXHRcdFx0d2VpZ2h0ID0gdGhpcy53ZWlnaHQ7XHJcblx0XHRcdGNvbnN0IGludGVycG9sYW50ID0gdGhpcy5fd2VpZ2h0SW50ZXJwb2xhbnQ7XHJcblxyXG5cdFx0XHRpZiAoIGludGVycG9sYW50ICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBpbnRlcnBvbGFudFZhbHVlID0gaW50ZXJwb2xhbnQuZXZhbHVhdGUoIHRpbWUgKVsgMCBdO1xyXG5cclxuXHRcdFx0XHR3ZWlnaHQgKj0gaW50ZXJwb2xhbnRWYWx1ZTtcclxuXHJcblx0XHRcdFx0aWYgKCB0aW1lID4gaW50ZXJwb2xhbnQucGFyYW1ldGVyUG9zaXRpb25zWyAxIF0gKSB7XHJcblxyXG5cdFx0XHRcdFx0dGhpcy5zdG9wRmFkaW5nKCk7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCBpbnRlcnBvbGFudFZhbHVlID09PSAwICkge1xyXG5cclxuXHRcdFx0XHRcdFx0Ly8gZmFkZWQgb3V0LCBkaXNhYmxlXHJcblx0XHRcdFx0XHRcdHRoaXMuZW5hYmxlZCA9IGZhbHNlO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLl9lZmZlY3RpdmVXZWlnaHQgPSB3ZWlnaHQ7XHJcblx0XHRyZXR1cm4gd2VpZ2h0O1xyXG5cclxuXHR9XHJcblxyXG5cdF91cGRhdGVUaW1lU2NhbGUoIHRpbWUgKSB7XHJcblxyXG5cdFx0bGV0IHRpbWVTY2FsZSA9IDA7XHJcblxyXG5cdFx0aWYgKCAhIHRoaXMucGF1c2VkICkge1xyXG5cclxuXHRcdFx0dGltZVNjYWxlID0gdGhpcy50aW1lU2NhbGU7XHJcblxyXG5cdFx0XHRjb25zdCBpbnRlcnBvbGFudCA9IHRoaXMuX3RpbWVTY2FsZUludGVycG9sYW50O1xyXG5cclxuXHRcdFx0aWYgKCBpbnRlcnBvbGFudCAhPT0gbnVsbCApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgaW50ZXJwb2xhbnRWYWx1ZSA9IGludGVycG9sYW50LmV2YWx1YXRlKCB0aW1lIClbIDAgXTtcclxuXHJcblx0XHRcdFx0dGltZVNjYWxlICo9IGludGVycG9sYW50VmFsdWU7XHJcblxyXG5cdFx0XHRcdGlmICggdGltZSA+IGludGVycG9sYW50LnBhcmFtZXRlclBvc2l0aW9uc1sgMSBdICkge1xyXG5cclxuXHRcdFx0XHRcdHRoaXMuc3RvcFdhcnBpbmcoKTtcclxuXHJcblx0XHRcdFx0XHRpZiAoIHRpbWVTY2FsZSA9PT0gMCApIHtcclxuXHJcblx0XHRcdFx0XHRcdC8vIG1vdGlvbiBoYXMgaGFsdGVkLCBwYXVzZVxyXG5cdFx0XHRcdFx0XHR0aGlzLnBhdXNlZCA9IHRydWU7XHJcblxyXG5cdFx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHRcdC8vIHdhcnAgZG9uZSAtIGFwcGx5IGZpbmFsIHRpbWUgc2NhbGVcclxuXHRcdFx0XHRcdFx0dGhpcy50aW1lU2NhbGUgPSB0aW1lU2NhbGU7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMuX2VmZmVjdGl2ZVRpbWVTY2FsZSA9IHRpbWVTY2FsZTtcclxuXHRcdHJldHVybiB0aW1lU2NhbGU7XHJcblxyXG5cdH1cclxuXHJcblx0X3VwZGF0ZVRpbWUoIGRlbHRhVGltZSApIHtcclxuXHJcblx0XHRjb25zdCBkdXJhdGlvbiA9IHRoaXMuX2NsaXAuZHVyYXRpb247XHJcblx0XHRjb25zdCBsb29wID0gdGhpcy5sb29wO1xyXG5cclxuXHRcdGxldCB0aW1lID0gdGhpcy50aW1lICsgZGVsdGFUaW1lO1xyXG5cdFx0bGV0IGxvb3BDb3VudCA9IHRoaXMuX2xvb3BDb3VudDtcclxuXHJcblx0XHRjb25zdCBwaW5nUG9uZyA9ICggbG9vcCA9PT0gTG9vcFBpbmdQb25nICk7XHJcblxyXG5cdFx0aWYgKCBkZWx0YVRpbWUgPT09IDAgKSB7XHJcblxyXG5cdFx0XHRpZiAoIGxvb3BDb3VudCA9PT0gLSAxICkgcmV0dXJuIHRpbWU7XHJcblxyXG5cdFx0XHRyZXR1cm4gKCBwaW5nUG9uZyAmJiAoIGxvb3BDb3VudCAmIDEgKSA9PT0gMSApID8gZHVyYXRpb24gLSB0aW1lIDogdGltZTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBsb29wID09PSBMb29wT25jZSApIHtcclxuXHJcblx0XHRcdGlmICggbG9vcENvdW50ID09PSAtIDEgKSB7XHJcblxyXG5cdFx0XHRcdC8vIGp1c3Qgc3RhcnRlZFxyXG5cclxuXHRcdFx0XHR0aGlzLl9sb29wQ291bnQgPSAwO1xyXG5cdFx0XHRcdHRoaXMuX3NldEVuZGluZ3MoIHRydWUsIHRydWUsIGZhbHNlICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRoYW5kbGVfc3RvcDoge1xyXG5cclxuXHRcdFx0XHRpZiAoIHRpbWUgPj0gZHVyYXRpb24gKSB7XHJcblxyXG5cdFx0XHRcdFx0dGltZSA9IGR1cmF0aW9uO1xyXG5cclxuXHRcdFx0XHR9IGVsc2UgaWYgKCB0aW1lIDwgMCApIHtcclxuXHJcblx0XHRcdFx0XHR0aW1lID0gMDtcclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHR0aGlzLnRpbWUgPSB0aW1lO1xyXG5cclxuXHRcdFx0XHRcdGJyZWFrIGhhbmRsZV9zdG9wO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdGlmICggdGhpcy5jbGFtcFdoZW5GaW5pc2hlZCApIHRoaXMucGF1c2VkID0gdHJ1ZTtcclxuXHRcdFx0XHRlbHNlIHRoaXMuZW5hYmxlZCA9IGZhbHNlO1xyXG5cclxuXHRcdFx0XHR0aGlzLnRpbWUgPSB0aW1lO1xyXG5cclxuXHRcdFx0XHR0aGlzLl9taXhlci5kaXNwYXRjaEV2ZW50KCB7XHJcblx0XHRcdFx0XHR0eXBlOiAnZmluaXNoZWQnLCBhY3Rpb246IHRoaXMsXHJcblx0XHRcdFx0XHRkaXJlY3Rpb246IGRlbHRhVGltZSA8IDAgPyAtIDEgOiAxXHJcblx0XHRcdFx0fSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH0gZWxzZSB7IC8vIHJlcGV0aXRpdmUgUmVwZWF0IG9yIFBpbmdQb25nXHJcblxyXG5cdFx0XHRpZiAoIGxvb3BDb3VudCA9PT0gLSAxICkge1xyXG5cclxuXHRcdFx0XHQvLyBqdXN0IHN0YXJ0ZWRcclxuXHJcblx0XHRcdFx0aWYgKCBkZWx0YVRpbWUgPj0gMCApIHtcclxuXHJcblx0XHRcdFx0XHRsb29wQ291bnQgPSAwO1xyXG5cclxuXHRcdFx0XHRcdHRoaXMuX3NldEVuZGluZ3MoIHRydWUsIHRoaXMucmVwZXRpdGlvbnMgPT09IDAsIHBpbmdQb25nICk7XHJcblxyXG5cdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0Ly8gd2hlbiBsb29waW5nIGluIHJldmVyc2UgZGlyZWN0aW9uLCB0aGUgaW5pdGlhbFxyXG5cdFx0XHRcdFx0Ly8gdHJhbnNpdGlvbiB0aHJvdWdoIHplcm8gY291bnRzIGFzIGEgcmVwZXRpdGlvbixcclxuXHRcdFx0XHRcdC8vIHNvIGxlYXZlIGxvb3BDb3VudCBhdCAtMVxyXG5cclxuXHRcdFx0XHRcdHRoaXMuX3NldEVuZGluZ3MoIHRoaXMucmVwZXRpdGlvbnMgPT09IDAsIHRydWUsIHBpbmdQb25nICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGlmICggdGltZSA+PSBkdXJhdGlvbiB8fCB0aW1lIDwgMCApIHtcclxuXHJcblx0XHRcdFx0Ly8gd3JhcCBhcm91bmRcclxuXHJcblx0XHRcdFx0Y29uc3QgbG9vcERlbHRhID0gTWF0aC5mbG9vciggdGltZSAvIGR1cmF0aW9uICk7IC8vIHNpZ25lZFxyXG5cdFx0XHRcdHRpbWUgLT0gZHVyYXRpb24gKiBsb29wRGVsdGE7XHJcblxyXG5cdFx0XHRcdGxvb3BDb3VudCArPSBNYXRoLmFicyggbG9vcERlbHRhICk7XHJcblxyXG5cdFx0XHRcdGNvbnN0IHBlbmRpbmcgPSB0aGlzLnJlcGV0aXRpb25zIC0gbG9vcENvdW50O1xyXG5cclxuXHRcdFx0XHRpZiAoIHBlbmRpbmcgPD0gMCApIHtcclxuXHJcblx0XHRcdFx0XHQvLyBoYXZlIHRvIHN0b3AgKHN3aXRjaCBzdGF0ZSwgY2xhbXAgdGltZSwgZmlyZSBldmVudClcclxuXHJcblx0XHRcdFx0XHRpZiAoIHRoaXMuY2xhbXBXaGVuRmluaXNoZWQgKSB0aGlzLnBhdXNlZCA9IHRydWU7XHJcblx0XHRcdFx0XHRlbHNlIHRoaXMuZW5hYmxlZCA9IGZhbHNlO1xyXG5cclxuXHRcdFx0XHRcdHRpbWUgPSBkZWx0YVRpbWUgPiAwID8gZHVyYXRpb24gOiAwO1xyXG5cclxuXHRcdFx0XHRcdHRoaXMudGltZSA9IHRpbWU7XHJcblxyXG5cdFx0XHRcdFx0dGhpcy5fbWl4ZXIuZGlzcGF0Y2hFdmVudCgge1xyXG5cdFx0XHRcdFx0XHR0eXBlOiAnZmluaXNoZWQnLCBhY3Rpb246IHRoaXMsXHJcblx0XHRcdFx0XHRcdGRpcmVjdGlvbjogZGVsdGFUaW1lID4gMCA/IDEgOiAtIDFcclxuXHRcdFx0XHRcdH0gKTtcclxuXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHQvLyBrZWVwIHJ1bm5pbmdcclxuXHJcblx0XHRcdFx0XHRpZiAoIHBlbmRpbmcgPT09IDEgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHQvLyBlbnRlcmluZyB0aGUgbGFzdCByb3VuZFxyXG5cclxuXHRcdFx0XHRcdFx0Y29uc3QgYXRTdGFydCA9IGRlbHRhVGltZSA8IDA7XHJcblx0XHRcdFx0XHRcdHRoaXMuX3NldEVuZGluZ3MoIGF0U3RhcnQsICEgYXRTdGFydCwgcGluZ1BvbmcgKTtcclxuXHJcblx0XHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdFx0dGhpcy5fc2V0RW5kaW5ncyggZmFsc2UsIGZhbHNlLCBwaW5nUG9uZyApO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHR0aGlzLl9sb29wQ291bnQgPSBsb29wQ291bnQ7XHJcblxyXG5cdFx0XHRcdFx0dGhpcy50aW1lID0gdGltZTtcclxuXHJcblx0XHRcdFx0XHR0aGlzLl9taXhlci5kaXNwYXRjaEV2ZW50KCB7XHJcblx0XHRcdFx0XHRcdHR5cGU6ICdsb29wJywgYWN0aW9uOiB0aGlzLCBsb29wRGVsdGE6IGxvb3BEZWx0YVxyXG5cdFx0XHRcdFx0fSApO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHR0aGlzLnRpbWUgPSB0aW1lO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0aWYgKCBwaW5nUG9uZyAmJiAoIGxvb3BDb3VudCAmIDEgKSA9PT0gMSApIHtcclxuXHJcblx0XHRcdFx0Ly8gaW52ZXJ0IHRpbWUgZm9yIHRoZSBcInBvbmcgcm91bmRcIlxyXG5cclxuXHRcdFx0XHRyZXR1cm4gZHVyYXRpb24gLSB0aW1lO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGltZTtcclxuXHJcblx0fVxyXG5cclxuXHRfc2V0RW5kaW5ncyggYXRTdGFydCwgYXRFbmQsIHBpbmdQb25nICkge1xyXG5cclxuXHRcdGNvbnN0IHNldHRpbmdzID0gdGhpcy5faW50ZXJwb2xhbnRTZXR0aW5ncztcclxuXHJcblx0XHRpZiAoIHBpbmdQb25nICkge1xyXG5cclxuXHRcdFx0c2V0dGluZ3MuZW5kaW5nU3RhcnQgPSBaZXJvU2xvcGVFbmRpbmc7XHJcblx0XHRcdHNldHRpbmdzLmVuZGluZ0VuZCA9IFplcm9TbG9wZUVuZGluZztcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0Ly8gYXNzdW1pbmcgZm9yIExvb3BPbmNlIGF0U3RhcnQgPT0gYXRFbmQgPT0gdHJ1ZVxyXG5cclxuXHRcdFx0aWYgKCBhdFN0YXJ0ICkge1xyXG5cclxuXHRcdFx0XHRzZXR0aW5ncy5lbmRpbmdTdGFydCA9IHRoaXMuemVyb1Nsb3BlQXRTdGFydCA/IFplcm9TbG9wZUVuZGluZyA6IFplcm9DdXJ2YXR1cmVFbmRpbmc7XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRzZXR0aW5ncy5lbmRpbmdTdGFydCA9IFdyYXBBcm91bmRFbmRpbmc7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRpZiAoIGF0RW5kICkge1xyXG5cclxuXHRcdFx0XHRzZXR0aW5ncy5lbmRpbmdFbmQgPSB0aGlzLnplcm9TbG9wZUF0RW5kID8gWmVyb1Nsb3BlRW5kaW5nIDogWmVyb0N1cnZhdHVyZUVuZGluZztcclxuXHJcblx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdHNldHRpbmdzLmVuZGluZ0VuZCBcdCA9IFdyYXBBcm91bmRFbmRpbmc7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdF9zY2hlZHVsZUZhZGluZyggZHVyYXRpb24sIHdlaWdodE5vdywgd2VpZ2h0VGhlbiApIHtcclxuXHJcblx0XHRjb25zdCBtaXhlciA9IHRoaXMuX21peGVyLCBub3cgPSBtaXhlci50aW1lO1xyXG5cdFx0bGV0IGludGVycG9sYW50ID0gdGhpcy5fd2VpZ2h0SW50ZXJwb2xhbnQ7XHJcblxyXG5cdFx0aWYgKCBpbnRlcnBvbGFudCA9PT0gbnVsbCApIHtcclxuXHJcblx0XHRcdGludGVycG9sYW50ID0gbWl4ZXIuX2xlbmRDb250cm9sSW50ZXJwb2xhbnQoKTtcclxuXHRcdFx0dGhpcy5fd2VpZ2h0SW50ZXJwb2xhbnQgPSBpbnRlcnBvbGFudDtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Y29uc3QgdGltZXMgPSBpbnRlcnBvbGFudC5wYXJhbWV0ZXJQb3NpdGlvbnMsXHJcblx0XHRcdHZhbHVlcyA9IGludGVycG9sYW50LnNhbXBsZVZhbHVlcztcclxuXHJcblx0XHR0aW1lc1sgMCBdID0gbm93O1xyXG5cdFx0dmFsdWVzWyAwIF0gPSB3ZWlnaHROb3c7XHJcblx0XHR0aW1lc1sgMSBdID0gbm93ICsgZHVyYXRpb247XHJcblx0XHR2YWx1ZXNbIDEgXSA9IHdlaWdodFRoZW47XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcblxyXG5leHBvcnQgeyBBbmltYXRpb25BY3Rpb24gfTtcclxuIiwiaW1wb3J0IHsgQW5pbWF0aW9uQWN0aW9uIH0gZnJvbSAnLi9BbmltYXRpb25BY3Rpb24uanMnO1xyXG5pbXBvcnQgeyBFdmVudERpc3BhdGNoZXIgfSBmcm9tICcuLi9jb3JlL0V2ZW50RGlzcGF0Y2hlci5qcyc7XHJcbmltcG9ydCB7IExpbmVhckludGVycG9sYW50IH0gZnJvbSAnLi4vbWF0aC9pbnRlcnBvbGFudHMvTGluZWFySW50ZXJwb2xhbnQuanMnO1xyXG5pbXBvcnQgeyBQcm9wZXJ0eUJpbmRpbmcgfSBmcm9tICcuL1Byb3BlcnR5QmluZGluZy5qcyc7XHJcbmltcG9ydCB7IFByb3BlcnR5TWl4ZXIgfSBmcm9tICcuL1Byb3BlcnR5TWl4ZXIuanMnO1xyXG5pbXBvcnQgeyBBbmltYXRpb25DbGlwIH0gZnJvbSAnLi9BbmltYXRpb25DbGlwLmpzJztcclxuaW1wb3J0IHsgTm9ybWFsQW5pbWF0aW9uQmxlbmRNb2RlIH0gZnJvbSAnLi4vY29uc3RhbnRzLmpzJztcclxuXHJcblxyXG5jb25zdCBfY29udHJvbEludGVycG9sYW50c1Jlc3VsdEJ1ZmZlciA9IG5ldyBGbG9hdDMyQXJyYXkoIDEgKTtcclxuXHJcblxyXG5jbGFzcyBBbmltYXRpb25NaXhlciBleHRlbmRzIEV2ZW50RGlzcGF0Y2hlciB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCByb290ICkge1xyXG5cclxuXHRcdHN1cGVyKCk7XHJcblxyXG5cdFx0dGhpcy5fcm9vdCA9IHJvb3Q7XHJcblx0XHR0aGlzLl9pbml0TWVtb3J5TWFuYWdlcigpO1xyXG5cdFx0dGhpcy5fYWNjdUluZGV4ID0gMDtcclxuXHRcdHRoaXMudGltZSA9IDA7XHJcblx0XHR0aGlzLnRpbWVTY2FsZSA9IDEuMDtcclxuXHJcblx0fVxyXG5cclxuXHRfYmluZEFjdGlvbiggYWN0aW9uLCBwcm90b3R5cGVBY3Rpb24gKSB7XHJcblxyXG5cdFx0Y29uc3Qgcm9vdCA9IGFjdGlvbi5fbG9jYWxSb290IHx8IHRoaXMuX3Jvb3QsXHJcblx0XHRcdHRyYWNrcyA9IGFjdGlvbi5fY2xpcC50cmFja3MsXHJcblx0XHRcdG5UcmFja3MgPSB0cmFja3MubGVuZ3RoLFxyXG5cdFx0XHRiaW5kaW5ncyA9IGFjdGlvbi5fcHJvcGVydHlCaW5kaW5ncyxcclxuXHRcdFx0aW50ZXJwb2xhbnRzID0gYWN0aW9uLl9pbnRlcnBvbGFudHMsXHJcblx0XHRcdHJvb3RVdWlkID0gcm9vdC51dWlkLFxyXG5cdFx0XHRiaW5kaW5nc0J5Um9vdCA9IHRoaXMuX2JpbmRpbmdzQnlSb290QW5kTmFtZTtcclxuXHJcblx0XHRsZXQgYmluZGluZ3NCeU5hbWUgPSBiaW5kaW5nc0J5Um9vdFsgcm9vdFV1aWQgXTtcclxuXHJcblx0XHRpZiAoIGJpbmRpbmdzQnlOYW1lID09PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRiaW5kaW5nc0J5TmFtZSA9IHt9O1xyXG5cdFx0XHRiaW5kaW5nc0J5Um9vdFsgcm9vdFV1aWQgXSA9IGJpbmRpbmdzQnlOYW1lO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgIT09IG5UcmFja3M7ICsrIGkgKSB7XHJcblxyXG5cdFx0XHRjb25zdCB0cmFjayA9IHRyYWNrc1sgaSBdLFxyXG5cdFx0XHRcdHRyYWNrTmFtZSA9IHRyYWNrLm5hbWU7XHJcblxyXG5cdFx0XHRsZXQgYmluZGluZyA9IGJpbmRpbmdzQnlOYW1lWyB0cmFja05hbWUgXTtcclxuXHJcblx0XHRcdGlmICggYmluZGluZyAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHQrKyBiaW5kaW5nLnJlZmVyZW5jZUNvdW50O1xyXG5cdFx0XHRcdGJpbmRpbmdzWyBpIF0gPSBiaW5kaW5nO1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0YmluZGluZyA9IGJpbmRpbmdzWyBpIF07XHJcblxyXG5cdFx0XHRcdGlmICggYmluZGluZyAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHRcdC8vIGV4aXN0aW5nIGJpbmRpbmcsIG1ha2Ugc3VyZSB0aGUgY2FjaGUga25vd3NcclxuXHJcblx0XHRcdFx0XHRpZiAoIGJpbmRpbmcuX2NhY2hlSW5kZXggPT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHQrKyBiaW5kaW5nLnJlZmVyZW5jZUNvdW50O1xyXG5cdFx0XHRcdFx0XHR0aGlzLl9hZGRJbmFjdGl2ZUJpbmRpbmcoIGJpbmRpbmcsIHJvb3RVdWlkLCB0cmFja05hbWUgKTtcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0Y29udGludWU7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0Y29uc3QgcGF0aCA9IHByb3RvdHlwZUFjdGlvbiAmJiBwcm90b3R5cGVBY3Rpb24uXHJcblx0XHRcdFx0XHRfcHJvcGVydHlCaW5kaW5nc1sgaSBdLmJpbmRpbmcucGFyc2VkUGF0aDtcclxuXHJcblx0XHRcdFx0YmluZGluZyA9IG5ldyBQcm9wZXJ0eU1peGVyKFxyXG5cdFx0XHRcdFx0UHJvcGVydHlCaW5kaW5nLmNyZWF0ZSggcm9vdCwgdHJhY2tOYW1lLCBwYXRoICksXHJcblx0XHRcdFx0XHR0cmFjay5WYWx1ZVR5cGVOYW1lLCB0cmFjay5nZXRWYWx1ZVNpemUoKSApO1xyXG5cclxuXHRcdFx0XHQrKyBiaW5kaW5nLnJlZmVyZW5jZUNvdW50O1xyXG5cdFx0XHRcdHRoaXMuX2FkZEluYWN0aXZlQmluZGluZyggYmluZGluZywgcm9vdFV1aWQsIHRyYWNrTmFtZSApO1xyXG5cclxuXHRcdFx0XHRiaW5kaW5nc1sgaSBdID0gYmluZGluZztcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGludGVycG9sYW50c1sgaSBdLnJlc3VsdEJ1ZmZlciA9IGJpbmRpbmcuYnVmZmVyO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHRfYWN0aXZhdGVBY3Rpb24oIGFjdGlvbiApIHtcclxuXHJcblx0XHRpZiAoICEgdGhpcy5faXNBY3RpdmVBY3Rpb24oIGFjdGlvbiApICkge1xyXG5cclxuXHRcdFx0aWYgKCBhY3Rpb24uX2NhY2hlSW5kZXggPT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdC8vIHRoaXMgYWN0aW9uIGhhcyBiZWVuIGZvcmdvdHRlbiBieSB0aGUgY2FjaGUsIGJ1dCB0aGUgdXNlclxyXG5cdFx0XHRcdC8vIGFwcGVhcnMgdG8gYmUgc3RpbGwgdXNpbmcgaXQgLT4gcmViaW5kXHJcblxyXG5cdFx0XHRcdGNvbnN0IHJvb3RVdWlkID0gKCBhY3Rpb24uX2xvY2FsUm9vdCB8fCB0aGlzLl9yb290ICkudXVpZCxcclxuXHRcdFx0XHRcdGNsaXBVdWlkID0gYWN0aW9uLl9jbGlwLnV1aWQsXHJcblx0XHRcdFx0XHRhY3Rpb25zRm9yQ2xpcCA9IHRoaXMuX2FjdGlvbnNCeUNsaXBbIGNsaXBVdWlkIF07XHJcblxyXG5cdFx0XHRcdHRoaXMuX2JpbmRBY3Rpb24oIGFjdGlvbixcclxuXHRcdFx0XHRcdGFjdGlvbnNGb3JDbGlwICYmIGFjdGlvbnNGb3JDbGlwLmtub3duQWN0aW9uc1sgMCBdICk7XHJcblxyXG5cdFx0XHRcdHRoaXMuX2FkZEluYWN0aXZlQWN0aW9uKCBhY3Rpb24sIGNsaXBVdWlkLCByb290VXVpZCApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Y29uc3QgYmluZGluZ3MgPSBhY3Rpb24uX3Byb3BlcnR5QmluZGluZ3M7XHJcblxyXG5cdFx0XHQvLyBpbmNyZW1lbnQgcmVmZXJlbmNlIGNvdW50cyAvIHNvcnQgb3V0IHN0YXRlXHJcblx0XHRcdGZvciAoIGxldCBpID0gMCwgbiA9IGJpbmRpbmdzLmxlbmd0aDsgaSAhPT0gbjsgKysgaSApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgYmluZGluZyA9IGJpbmRpbmdzWyBpIF07XHJcblxyXG5cdFx0XHRcdGlmICggYmluZGluZy51c2VDb3VudCArKyA9PT0gMCApIHtcclxuXHJcblx0XHRcdFx0XHR0aGlzLl9sZW5kQmluZGluZyggYmluZGluZyApO1xyXG5cdFx0XHRcdFx0YmluZGluZy5zYXZlT3JpZ2luYWxTdGF0ZSgpO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHR0aGlzLl9sZW5kQWN0aW9uKCBhY3Rpb24gKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0X2RlYWN0aXZhdGVBY3Rpb24oIGFjdGlvbiApIHtcclxuXHJcblx0XHRpZiAoIHRoaXMuX2lzQWN0aXZlQWN0aW9uKCBhY3Rpb24gKSApIHtcclxuXHJcblx0XHRcdGNvbnN0IGJpbmRpbmdzID0gYWN0aW9uLl9wcm9wZXJ0eUJpbmRpbmdzO1xyXG5cclxuXHRcdFx0Ly8gZGVjcmVtZW50IHJlZmVyZW5jZSBjb3VudHMgLyBzb3J0IG91dCBzdGF0ZVxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIG4gPSBiaW5kaW5ncy5sZW5ndGg7IGkgIT09IG47ICsrIGkgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IGJpbmRpbmcgPSBiaW5kaW5nc1sgaSBdO1xyXG5cclxuXHRcdFx0XHRpZiAoIC0tIGJpbmRpbmcudXNlQ291bnQgPT09IDAgKSB7XHJcblxyXG5cdFx0XHRcdFx0YmluZGluZy5yZXN0b3JlT3JpZ2luYWxTdGF0ZSgpO1xyXG5cdFx0XHRcdFx0dGhpcy5fdGFrZUJhY2tCaW5kaW5nKCBiaW5kaW5nICk7XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHRoaXMuX3Rha2VCYWNrQWN0aW9uKCBhY3Rpb24gKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gTWVtb3J5IG1hbmFnZXJcclxuXHJcblx0X2luaXRNZW1vcnlNYW5hZ2VyKCkge1xyXG5cclxuXHRcdHRoaXMuX2FjdGlvbnMgPSBbXTsgLy8gJ25BY3RpdmVBY3Rpb25zJyBmb2xsb3dlZCBieSBpbmFjdGl2ZSBvbmVzXHJcblx0XHR0aGlzLl9uQWN0aXZlQWN0aW9ucyA9IDA7XHJcblxyXG5cdFx0dGhpcy5fYWN0aW9uc0J5Q2xpcCA9IHt9O1xyXG5cdFx0Ly8gaW5zaWRlOlxyXG5cdFx0Ly8ge1xyXG5cdFx0Ly8gXHRrbm93bkFjdGlvbnM6IEFycmF5PCBBbmltYXRpb25BY3Rpb24gPiAtIHVzZWQgYXMgcHJvdG90eXBlc1xyXG5cdFx0Ly8gXHRhY3Rpb25CeVJvb3Q6IEFuaW1hdGlvbkFjdGlvbiAtIGxvb2t1cFxyXG5cdFx0Ly8gfVxyXG5cclxuXHJcblx0XHR0aGlzLl9iaW5kaW5ncyA9IFtdOyAvLyAnbkFjdGl2ZUJpbmRpbmdzJyBmb2xsb3dlZCBieSBpbmFjdGl2ZSBvbmVzXHJcblx0XHR0aGlzLl9uQWN0aXZlQmluZGluZ3MgPSAwO1xyXG5cclxuXHRcdHRoaXMuX2JpbmRpbmdzQnlSb290QW5kTmFtZSA9IHt9OyAvLyBpbnNpZGU6IE1hcDwgbmFtZSwgUHJvcGVydHlNaXhlciA+XHJcblxyXG5cclxuXHRcdHRoaXMuX2NvbnRyb2xJbnRlcnBvbGFudHMgPSBbXTsgLy8gc2FtZSBnYW1lIGFzIGFib3ZlXHJcblx0XHR0aGlzLl9uQWN0aXZlQ29udHJvbEludGVycG9sYW50cyA9IDA7XHJcblxyXG5cdFx0Y29uc3Qgc2NvcGUgPSB0aGlzO1xyXG5cclxuXHRcdHRoaXMuc3RhdHMgPSB7XHJcblxyXG5cdFx0XHRhY3Rpb25zOiB7XHJcblx0XHRcdFx0Z2V0IHRvdGFsKCkge1xyXG5cclxuXHRcdFx0XHRcdHJldHVybiBzY29wZS5fYWN0aW9ucy5sZW5ndGg7XHJcblxyXG5cdFx0XHRcdH0sXHJcblx0XHRcdFx0Z2V0IGluVXNlKCkge1xyXG5cclxuXHRcdFx0XHRcdHJldHVybiBzY29wZS5fbkFjdGl2ZUFjdGlvbnM7XHJcblxyXG5cdFx0XHRcdH1cclxuXHRcdFx0fSxcclxuXHRcdFx0YmluZGluZ3M6IHtcclxuXHRcdFx0XHRnZXQgdG90YWwoKSB7XHJcblxyXG5cdFx0XHRcdFx0cmV0dXJuIHNjb3BlLl9iaW5kaW5ncy5sZW5ndGg7XHJcblxyXG5cdFx0XHRcdH0sXHJcblx0XHRcdFx0Z2V0IGluVXNlKCkge1xyXG5cclxuXHRcdFx0XHRcdHJldHVybiBzY29wZS5fbkFjdGl2ZUJpbmRpbmdzO1xyXG5cclxuXHRcdFx0XHR9XHJcblx0XHRcdH0sXHJcblx0XHRcdGNvbnRyb2xJbnRlcnBvbGFudHM6IHtcclxuXHRcdFx0XHRnZXQgdG90YWwoKSB7XHJcblxyXG5cdFx0XHRcdFx0cmV0dXJuIHNjb3BlLl9jb250cm9sSW50ZXJwb2xhbnRzLmxlbmd0aDtcclxuXHJcblx0XHRcdFx0fSxcclxuXHRcdFx0XHRnZXQgaW5Vc2UoKSB7XHJcblxyXG5cdFx0XHRcdFx0cmV0dXJuIHNjb3BlLl9uQWN0aXZlQ29udHJvbEludGVycG9sYW50cztcclxuXHJcblx0XHRcdFx0fVxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fTtcclxuXHJcblx0fVxyXG5cclxuXHQvLyBNZW1vcnkgbWFuYWdlbWVudCBmb3IgQW5pbWF0aW9uQWN0aW9uIG9iamVjdHNcclxuXHJcblx0X2lzQWN0aXZlQWN0aW9uKCBhY3Rpb24gKSB7XHJcblxyXG5cdFx0Y29uc3QgaW5kZXggPSBhY3Rpb24uX2NhY2hlSW5kZXg7XHJcblx0XHRyZXR1cm4gaW5kZXggIT09IG51bGwgJiYgaW5kZXggPCB0aGlzLl9uQWN0aXZlQWN0aW9ucztcclxuXHJcblx0fVxyXG5cclxuXHRfYWRkSW5hY3RpdmVBY3Rpb24oIGFjdGlvbiwgY2xpcFV1aWQsIHJvb3RVdWlkICkge1xyXG5cclxuXHRcdGNvbnN0IGFjdGlvbnMgPSB0aGlzLl9hY3Rpb25zLFxyXG5cdFx0XHRhY3Rpb25zQnlDbGlwID0gdGhpcy5fYWN0aW9uc0J5Q2xpcDtcclxuXHJcblx0XHRsZXQgYWN0aW9uc0ZvckNsaXAgPSBhY3Rpb25zQnlDbGlwWyBjbGlwVXVpZCBdO1xyXG5cclxuXHRcdGlmICggYWN0aW9uc0ZvckNsaXAgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdGFjdGlvbnNGb3JDbGlwID0ge1xyXG5cclxuXHRcdFx0XHRrbm93bkFjdGlvbnM6IFsgYWN0aW9uIF0sXHJcblx0XHRcdFx0YWN0aW9uQnlSb290OiB7fVxyXG5cclxuXHRcdFx0fTtcclxuXHJcblx0XHRcdGFjdGlvbi5fYnlDbGlwQ2FjaGVJbmRleCA9IDA7XHJcblxyXG5cdFx0XHRhY3Rpb25zQnlDbGlwWyBjbGlwVXVpZCBdID0gYWN0aW9uc0ZvckNsaXA7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdGNvbnN0IGtub3duQWN0aW9ucyA9IGFjdGlvbnNGb3JDbGlwLmtub3duQWN0aW9ucztcclxuXHJcblx0XHRcdGFjdGlvbi5fYnlDbGlwQ2FjaGVJbmRleCA9IGtub3duQWN0aW9ucy5sZW5ndGg7XHJcblx0XHRcdGtub3duQWN0aW9ucy5wdXNoKCBhY3Rpb24gKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0YWN0aW9uLl9jYWNoZUluZGV4ID0gYWN0aW9ucy5sZW5ndGg7XHJcblx0XHRhY3Rpb25zLnB1c2goIGFjdGlvbiApO1xyXG5cclxuXHRcdGFjdGlvbnNGb3JDbGlwLmFjdGlvbkJ5Um9vdFsgcm9vdFV1aWQgXSA9IGFjdGlvbjtcclxuXHJcblx0fVxyXG5cclxuXHRfcmVtb3ZlSW5hY3RpdmVBY3Rpb24oIGFjdGlvbiApIHtcclxuXHJcblx0XHRjb25zdCBhY3Rpb25zID0gdGhpcy5fYWN0aW9ucyxcclxuXHRcdFx0bGFzdEluYWN0aXZlQWN0aW9uID0gYWN0aW9uc1sgYWN0aW9ucy5sZW5ndGggLSAxIF0sXHJcblx0XHRcdGNhY2hlSW5kZXggPSBhY3Rpb24uX2NhY2hlSW5kZXg7XHJcblxyXG5cdFx0bGFzdEluYWN0aXZlQWN0aW9uLl9jYWNoZUluZGV4ID0gY2FjaGVJbmRleDtcclxuXHRcdGFjdGlvbnNbIGNhY2hlSW5kZXggXSA9IGxhc3RJbmFjdGl2ZUFjdGlvbjtcclxuXHRcdGFjdGlvbnMucG9wKCk7XHJcblxyXG5cdFx0YWN0aW9uLl9jYWNoZUluZGV4ID0gbnVsbDtcclxuXHJcblxyXG5cdFx0Y29uc3QgY2xpcFV1aWQgPSBhY3Rpb24uX2NsaXAudXVpZCxcclxuXHRcdFx0YWN0aW9uc0J5Q2xpcCA9IHRoaXMuX2FjdGlvbnNCeUNsaXAsXHJcblx0XHRcdGFjdGlvbnNGb3JDbGlwID0gYWN0aW9uc0J5Q2xpcFsgY2xpcFV1aWQgXSxcclxuXHRcdFx0a25vd25BY3Rpb25zRm9yQ2xpcCA9IGFjdGlvbnNGb3JDbGlwLmtub3duQWN0aW9ucyxcclxuXHJcblx0XHRcdGxhc3RLbm93bkFjdGlvbiA9XHJcblx0XHRcdFx0a25vd25BY3Rpb25zRm9yQ2xpcFsga25vd25BY3Rpb25zRm9yQ2xpcC5sZW5ndGggLSAxIF0sXHJcblxyXG5cdFx0XHRieUNsaXBDYWNoZUluZGV4ID0gYWN0aW9uLl9ieUNsaXBDYWNoZUluZGV4O1xyXG5cclxuXHRcdGxhc3RLbm93bkFjdGlvbi5fYnlDbGlwQ2FjaGVJbmRleCA9IGJ5Q2xpcENhY2hlSW5kZXg7XHJcblx0XHRrbm93bkFjdGlvbnNGb3JDbGlwWyBieUNsaXBDYWNoZUluZGV4IF0gPSBsYXN0S25vd25BY3Rpb247XHJcblx0XHRrbm93bkFjdGlvbnNGb3JDbGlwLnBvcCgpO1xyXG5cclxuXHRcdGFjdGlvbi5fYnlDbGlwQ2FjaGVJbmRleCA9IG51bGw7XHJcblxyXG5cclxuXHRcdGNvbnN0IGFjdGlvbkJ5Um9vdCA9IGFjdGlvbnNGb3JDbGlwLmFjdGlvbkJ5Um9vdCxcclxuXHRcdFx0cm9vdFV1aWQgPSAoIGFjdGlvbi5fbG9jYWxSb290IHx8IHRoaXMuX3Jvb3QgKS51dWlkO1xyXG5cclxuXHRcdGRlbGV0ZSBhY3Rpb25CeVJvb3RbIHJvb3RVdWlkIF07XHJcblxyXG5cdFx0aWYgKCBrbm93bkFjdGlvbnNGb3JDbGlwLmxlbmd0aCA9PT0gMCApIHtcclxuXHJcblx0XHRcdGRlbGV0ZSBhY3Rpb25zQnlDbGlwWyBjbGlwVXVpZCBdO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLl9yZW1vdmVJbmFjdGl2ZUJpbmRpbmdzRm9yQWN0aW9uKCBhY3Rpb24gKTtcclxuXHJcblx0fVxyXG5cclxuXHRfcmVtb3ZlSW5hY3RpdmVCaW5kaW5nc0ZvckFjdGlvbiggYWN0aW9uICkge1xyXG5cclxuXHRcdGNvbnN0IGJpbmRpbmdzID0gYWN0aW9uLl9wcm9wZXJ0eUJpbmRpbmdzO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMCwgbiA9IGJpbmRpbmdzLmxlbmd0aDsgaSAhPT0gbjsgKysgaSApIHtcclxuXHJcblx0XHRcdGNvbnN0IGJpbmRpbmcgPSBiaW5kaW5nc1sgaSBdO1xyXG5cclxuXHRcdFx0aWYgKCAtLSBiaW5kaW5nLnJlZmVyZW5jZUNvdW50ID09PSAwICkge1xyXG5cclxuXHRcdFx0XHR0aGlzLl9yZW1vdmVJbmFjdGl2ZUJpbmRpbmcoIGJpbmRpbmcgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcblx0X2xlbmRBY3Rpb24oIGFjdGlvbiApIHtcclxuXHJcblx0XHQvLyBbIGFjdGl2ZSBhY3Rpb25zIHwgIGluYWN0aXZlIGFjdGlvbnMgIF1cclxuXHRcdC8vIFsgIGFjdGl2ZSBhY3Rpb25zID58IGluYWN0aXZlIGFjdGlvbnMgXVxyXG5cdFx0Ly8gICAgICAgICAgICAgICAgIHMgICAgICAgIGFcclxuXHRcdC8vICAgICAgICAgICAgICAgICAgPC1zd2FwLT5cclxuXHRcdC8vICAgICAgICAgICAgICAgICBhICAgICAgICBzXHJcblxyXG5cdFx0Y29uc3QgYWN0aW9ucyA9IHRoaXMuX2FjdGlvbnMsXHJcblx0XHRcdHByZXZJbmRleCA9IGFjdGlvbi5fY2FjaGVJbmRleCxcclxuXHJcblx0XHRcdGxhc3RBY3RpdmVJbmRleCA9IHRoaXMuX25BY3RpdmVBY3Rpb25zICsrLFxyXG5cclxuXHRcdFx0Zmlyc3RJbmFjdGl2ZUFjdGlvbiA9IGFjdGlvbnNbIGxhc3RBY3RpdmVJbmRleCBdO1xyXG5cclxuXHRcdGFjdGlvbi5fY2FjaGVJbmRleCA9IGxhc3RBY3RpdmVJbmRleDtcclxuXHRcdGFjdGlvbnNbIGxhc3RBY3RpdmVJbmRleCBdID0gYWN0aW9uO1xyXG5cclxuXHRcdGZpcnN0SW5hY3RpdmVBY3Rpb24uX2NhY2hlSW5kZXggPSBwcmV2SW5kZXg7XHJcblx0XHRhY3Rpb25zWyBwcmV2SW5kZXggXSA9IGZpcnN0SW5hY3RpdmVBY3Rpb247XHJcblxyXG5cdH1cclxuXHJcblx0X3Rha2VCYWNrQWN0aW9uKCBhY3Rpb24gKSB7XHJcblxyXG5cdFx0Ly8gWyAgYWN0aXZlIGFjdGlvbnMgIHwgaW5hY3RpdmUgYWN0aW9ucyBdXHJcblx0XHQvLyBbIGFjdGl2ZSBhY3Rpb25zIHw8IGluYWN0aXZlIGFjdGlvbnMgIF1cclxuXHRcdC8vICAgICAgICBhICAgICAgICBzXHJcblx0XHQvLyAgICAgICAgIDwtc3dhcC0+XHJcblx0XHQvLyAgICAgICAgcyAgICAgICAgYVxyXG5cclxuXHRcdGNvbnN0IGFjdGlvbnMgPSB0aGlzLl9hY3Rpb25zLFxyXG5cdFx0XHRwcmV2SW5kZXggPSBhY3Rpb24uX2NhY2hlSW5kZXgsXHJcblxyXG5cdFx0XHRmaXJzdEluYWN0aXZlSW5kZXggPSAtLSB0aGlzLl9uQWN0aXZlQWN0aW9ucyxcclxuXHJcblx0XHRcdGxhc3RBY3RpdmVBY3Rpb24gPSBhY3Rpb25zWyBmaXJzdEluYWN0aXZlSW5kZXggXTtcclxuXHJcblx0XHRhY3Rpb24uX2NhY2hlSW5kZXggPSBmaXJzdEluYWN0aXZlSW5kZXg7XHJcblx0XHRhY3Rpb25zWyBmaXJzdEluYWN0aXZlSW5kZXggXSA9IGFjdGlvbjtcclxuXHJcblx0XHRsYXN0QWN0aXZlQWN0aW9uLl9jYWNoZUluZGV4ID0gcHJldkluZGV4O1xyXG5cdFx0YWN0aW9uc1sgcHJldkluZGV4IF0gPSBsYXN0QWN0aXZlQWN0aW9uO1xyXG5cclxuXHR9XHJcblxyXG5cdC8vIE1lbW9yeSBtYW5hZ2VtZW50IGZvciBQcm9wZXJ0eU1peGVyIG9iamVjdHNcclxuXHJcblx0X2FkZEluYWN0aXZlQmluZGluZyggYmluZGluZywgcm9vdFV1aWQsIHRyYWNrTmFtZSApIHtcclxuXHJcblx0XHRjb25zdCBiaW5kaW5nc0J5Um9vdCA9IHRoaXMuX2JpbmRpbmdzQnlSb290QW5kTmFtZSxcclxuXHRcdFx0YmluZGluZ3MgPSB0aGlzLl9iaW5kaW5ncztcclxuXHJcblx0XHRsZXQgYmluZGluZ0J5TmFtZSA9IGJpbmRpbmdzQnlSb290WyByb290VXVpZCBdO1xyXG5cclxuXHRcdGlmICggYmluZGluZ0J5TmFtZSA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0YmluZGluZ0J5TmFtZSA9IHt9O1xyXG5cdFx0XHRiaW5kaW5nc0J5Um9vdFsgcm9vdFV1aWQgXSA9IGJpbmRpbmdCeU5hbWU7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGJpbmRpbmdCeU5hbWVbIHRyYWNrTmFtZSBdID0gYmluZGluZztcclxuXHJcblx0XHRiaW5kaW5nLl9jYWNoZUluZGV4ID0gYmluZGluZ3MubGVuZ3RoO1xyXG5cdFx0YmluZGluZ3MucHVzaCggYmluZGluZyApO1xyXG5cclxuXHR9XHJcblxyXG5cdF9yZW1vdmVJbmFjdGl2ZUJpbmRpbmcoIGJpbmRpbmcgKSB7XHJcblxyXG5cdFx0Y29uc3QgYmluZGluZ3MgPSB0aGlzLl9iaW5kaW5ncyxcclxuXHRcdFx0cHJvcEJpbmRpbmcgPSBiaW5kaW5nLmJpbmRpbmcsXHJcblx0XHRcdHJvb3RVdWlkID0gcHJvcEJpbmRpbmcucm9vdE5vZGUudXVpZCxcclxuXHRcdFx0dHJhY2tOYW1lID0gcHJvcEJpbmRpbmcucGF0aCxcclxuXHRcdFx0YmluZGluZ3NCeVJvb3QgPSB0aGlzLl9iaW5kaW5nc0J5Um9vdEFuZE5hbWUsXHJcblx0XHRcdGJpbmRpbmdCeU5hbWUgPSBiaW5kaW5nc0J5Um9vdFsgcm9vdFV1aWQgXSxcclxuXHJcblx0XHRcdGxhc3RJbmFjdGl2ZUJpbmRpbmcgPSBiaW5kaW5nc1sgYmluZGluZ3MubGVuZ3RoIC0gMSBdLFxyXG5cdFx0XHRjYWNoZUluZGV4ID0gYmluZGluZy5fY2FjaGVJbmRleDtcclxuXHJcblx0XHRsYXN0SW5hY3RpdmVCaW5kaW5nLl9jYWNoZUluZGV4ID0gY2FjaGVJbmRleDtcclxuXHRcdGJpbmRpbmdzWyBjYWNoZUluZGV4IF0gPSBsYXN0SW5hY3RpdmVCaW5kaW5nO1xyXG5cdFx0YmluZGluZ3MucG9wKCk7XHJcblxyXG5cdFx0ZGVsZXRlIGJpbmRpbmdCeU5hbWVbIHRyYWNrTmFtZSBdO1xyXG5cclxuXHRcdGlmICggT2JqZWN0LmtleXMoIGJpbmRpbmdCeU5hbWUgKS5sZW5ndGggPT09IDAgKSB7XHJcblxyXG5cdFx0XHRkZWxldGUgYmluZGluZ3NCeVJvb3RbIHJvb3RVdWlkIF07XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdF9sZW5kQmluZGluZyggYmluZGluZyApIHtcclxuXHJcblx0XHRjb25zdCBiaW5kaW5ncyA9IHRoaXMuX2JpbmRpbmdzLFxyXG5cdFx0XHRwcmV2SW5kZXggPSBiaW5kaW5nLl9jYWNoZUluZGV4LFxyXG5cclxuXHRcdFx0bGFzdEFjdGl2ZUluZGV4ID0gdGhpcy5fbkFjdGl2ZUJpbmRpbmdzICsrLFxyXG5cclxuXHRcdFx0Zmlyc3RJbmFjdGl2ZUJpbmRpbmcgPSBiaW5kaW5nc1sgbGFzdEFjdGl2ZUluZGV4IF07XHJcblxyXG5cdFx0YmluZGluZy5fY2FjaGVJbmRleCA9IGxhc3RBY3RpdmVJbmRleDtcclxuXHRcdGJpbmRpbmdzWyBsYXN0QWN0aXZlSW5kZXggXSA9IGJpbmRpbmc7XHJcblxyXG5cdFx0Zmlyc3RJbmFjdGl2ZUJpbmRpbmcuX2NhY2hlSW5kZXggPSBwcmV2SW5kZXg7XHJcblx0XHRiaW5kaW5nc1sgcHJldkluZGV4IF0gPSBmaXJzdEluYWN0aXZlQmluZGluZztcclxuXHJcblx0fVxyXG5cclxuXHRfdGFrZUJhY2tCaW5kaW5nKCBiaW5kaW5nICkge1xyXG5cclxuXHRcdGNvbnN0IGJpbmRpbmdzID0gdGhpcy5fYmluZGluZ3MsXHJcblx0XHRcdHByZXZJbmRleCA9IGJpbmRpbmcuX2NhY2hlSW5kZXgsXHJcblxyXG5cdFx0XHRmaXJzdEluYWN0aXZlSW5kZXggPSAtLSB0aGlzLl9uQWN0aXZlQmluZGluZ3MsXHJcblxyXG5cdFx0XHRsYXN0QWN0aXZlQmluZGluZyA9IGJpbmRpbmdzWyBmaXJzdEluYWN0aXZlSW5kZXggXTtcclxuXHJcblx0XHRiaW5kaW5nLl9jYWNoZUluZGV4ID0gZmlyc3RJbmFjdGl2ZUluZGV4O1xyXG5cdFx0YmluZGluZ3NbIGZpcnN0SW5hY3RpdmVJbmRleCBdID0gYmluZGluZztcclxuXHJcblx0XHRsYXN0QWN0aXZlQmluZGluZy5fY2FjaGVJbmRleCA9IHByZXZJbmRleDtcclxuXHRcdGJpbmRpbmdzWyBwcmV2SW5kZXggXSA9IGxhc3RBY3RpdmVCaW5kaW5nO1xyXG5cclxuXHR9XHJcblxyXG5cclxuXHQvLyBNZW1vcnkgbWFuYWdlbWVudCBvZiBJbnRlcnBvbGFudHMgZm9yIHdlaWdodCBhbmQgdGltZSBzY2FsZVxyXG5cclxuXHRfbGVuZENvbnRyb2xJbnRlcnBvbGFudCgpIHtcclxuXHJcblx0XHRjb25zdCBpbnRlcnBvbGFudHMgPSB0aGlzLl9jb250cm9sSW50ZXJwb2xhbnRzLFxyXG5cdFx0XHRsYXN0QWN0aXZlSW5kZXggPSB0aGlzLl9uQWN0aXZlQ29udHJvbEludGVycG9sYW50cyArKztcclxuXHJcblx0XHRsZXQgaW50ZXJwb2xhbnQgPSBpbnRlcnBvbGFudHNbIGxhc3RBY3RpdmVJbmRleCBdO1xyXG5cclxuXHRcdGlmICggaW50ZXJwb2xhbnQgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdGludGVycG9sYW50ID0gbmV3IExpbmVhckludGVycG9sYW50KFxyXG5cdFx0XHRcdG5ldyBGbG9hdDMyQXJyYXkoIDIgKSwgbmV3IEZsb2F0MzJBcnJheSggMiApLFxyXG5cdFx0XHRcdDEsIF9jb250cm9sSW50ZXJwb2xhbnRzUmVzdWx0QnVmZmVyICk7XHJcblxyXG5cdFx0XHRpbnRlcnBvbGFudC5fX2NhY2hlSW5kZXggPSBsYXN0QWN0aXZlSW5kZXg7XHJcblx0XHRcdGludGVycG9sYW50c1sgbGFzdEFjdGl2ZUluZGV4IF0gPSBpbnRlcnBvbGFudDtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIGludGVycG9sYW50O1xyXG5cclxuXHR9XHJcblxyXG5cdF90YWtlQmFja0NvbnRyb2xJbnRlcnBvbGFudCggaW50ZXJwb2xhbnQgKSB7XHJcblxyXG5cdFx0Y29uc3QgaW50ZXJwb2xhbnRzID0gdGhpcy5fY29udHJvbEludGVycG9sYW50cyxcclxuXHRcdFx0cHJldkluZGV4ID0gaW50ZXJwb2xhbnQuX19jYWNoZUluZGV4LFxyXG5cclxuXHRcdFx0Zmlyc3RJbmFjdGl2ZUluZGV4ID0gLS0gdGhpcy5fbkFjdGl2ZUNvbnRyb2xJbnRlcnBvbGFudHMsXHJcblxyXG5cdFx0XHRsYXN0QWN0aXZlSW50ZXJwb2xhbnQgPSBpbnRlcnBvbGFudHNbIGZpcnN0SW5hY3RpdmVJbmRleCBdO1xyXG5cclxuXHRcdGludGVycG9sYW50Ll9fY2FjaGVJbmRleCA9IGZpcnN0SW5hY3RpdmVJbmRleDtcclxuXHRcdGludGVycG9sYW50c1sgZmlyc3RJbmFjdGl2ZUluZGV4IF0gPSBpbnRlcnBvbGFudDtcclxuXHJcblx0XHRsYXN0QWN0aXZlSW50ZXJwb2xhbnQuX19jYWNoZUluZGV4ID0gcHJldkluZGV4O1xyXG5cdFx0aW50ZXJwb2xhbnRzWyBwcmV2SW5kZXggXSA9IGxhc3RBY3RpdmVJbnRlcnBvbGFudDtcclxuXHJcblx0fVxyXG5cclxuXHQvLyByZXR1cm4gYW4gYWN0aW9uIGZvciBhIGNsaXAgb3B0aW9uYWxseSB1c2luZyBhIGN1c3RvbSByb290IHRhcmdldFxyXG5cdC8vIG9iamVjdCAodGhpcyBtZXRob2QgYWxsb2NhdGVzIGEgbG90IG9mIGR5bmFtaWMgbWVtb3J5IGluIGNhc2UgYVxyXG5cdC8vIHByZXZpb3VzbHkgdW5rbm93biBjbGlwL3Jvb3QgY29tYmluYXRpb24gaXMgc3BlY2lmaWVkKVxyXG5cdGNsaXBBY3Rpb24oIGNsaXAsIG9wdGlvbmFsUm9vdCwgYmxlbmRNb2RlICkge1xyXG5cclxuXHRcdGNvbnN0IHJvb3QgPSBvcHRpb25hbFJvb3QgfHwgdGhpcy5fcm9vdCxcclxuXHRcdFx0cm9vdFV1aWQgPSByb290LnV1aWQ7XHJcblxyXG5cdFx0bGV0IGNsaXBPYmplY3QgPSB0eXBlb2YgY2xpcCA9PT0gJ3N0cmluZycgPyBBbmltYXRpb25DbGlwLmZpbmRCeU5hbWUoIHJvb3QsIGNsaXAgKSA6IGNsaXA7XHJcblxyXG5cdFx0Y29uc3QgY2xpcFV1aWQgPSBjbGlwT2JqZWN0ICE9PSBudWxsID8gY2xpcE9iamVjdC51dWlkIDogY2xpcDtcclxuXHJcblx0XHRjb25zdCBhY3Rpb25zRm9yQ2xpcCA9IHRoaXMuX2FjdGlvbnNCeUNsaXBbIGNsaXBVdWlkIF07XHJcblx0XHRsZXQgcHJvdG90eXBlQWN0aW9uID0gbnVsbDtcclxuXHJcblx0XHRpZiAoIGJsZW5kTW9kZSA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0aWYgKCBjbGlwT2JqZWN0ICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0XHRibGVuZE1vZGUgPSBjbGlwT2JqZWN0LmJsZW5kTW9kZTtcclxuXHJcblx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdGJsZW5kTW9kZSA9IE5vcm1hbEFuaW1hdGlvbkJsZW5kTW9kZTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBhY3Rpb25zRm9yQ2xpcCAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0Y29uc3QgZXhpc3RpbmdBY3Rpb24gPSBhY3Rpb25zRm9yQ2xpcC5hY3Rpb25CeVJvb3RbIHJvb3RVdWlkIF07XHJcblxyXG5cdFx0XHRpZiAoIGV4aXN0aW5nQWN0aW9uICE9PSB1bmRlZmluZWQgJiYgZXhpc3RpbmdBY3Rpb24uYmxlbmRNb2RlID09PSBibGVuZE1vZGUgKSB7XHJcblxyXG5cdFx0XHRcdHJldHVybiBleGlzdGluZ0FjdGlvbjtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdC8vIHdlIGtub3cgdGhlIGNsaXAsIHNvIHdlIGRvbid0IGhhdmUgdG8gcGFyc2UgYWxsXHJcblx0XHRcdC8vIHRoZSBiaW5kaW5ncyBhZ2FpbiBidXQgY2FuIGp1c3QgY29weVxyXG5cdFx0XHRwcm90b3R5cGVBY3Rpb24gPSBhY3Rpb25zRm9yQ2xpcC5rbm93bkFjdGlvbnNbIDAgXTtcclxuXHJcblx0XHRcdC8vIGFsc28sIHRha2UgdGhlIGNsaXAgZnJvbSB0aGUgcHJvdG90eXBlIGFjdGlvblxyXG5cdFx0XHRpZiAoIGNsaXBPYmplY3QgPT09IG51bGwgKVxyXG5cdFx0XHRcdGNsaXBPYmplY3QgPSBwcm90b3R5cGVBY3Rpb24uX2NsaXA7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIGNsaXAgbXVzdCBiZSBrbm93biB3aGVuIHNwZWNpZmllZCB2aWEgc3RyaW5nXHJcblx0XHRpZiAoIGNsaXBPYmplY3QgPT09IG51bGwgKSByZXR1cm4gbnVsbDtcclxuXHJcblx0XHQvLyBhbGxvY2F0ZSBhbGwgcmVzb3VyY2VzIHJlcXVpcmVkIHRvIHJ1biBpdFxyXG5cdFx0Y29uc3QgbmV3QWN0aW9uID0gbmV3IEFuaW1hdGlvbkFjdGlvbiggdGhpcywgY2xpcE9iamVjdCwgb3B0aW9uYWxSb290LCBibGVuZE1vZGUgKTtcclxuXHJcblx0XHR0aGlzLl9iaW5kQWN0aW9uKCBuZXdBY3Rpb24sIHByb3RvdHlwZUFjdGlvbiApO1xyXG5cclxuXHRcdC8vIGFuZCBtYWtlIHRoZSBhY3Rpb24ga25vd24gdG8gdGhlIG1lbW9yeSBtYW5hZ2VyXHJcblx0XHR0aGlzLl9hZGRJbmFjdGl2ZUFjdGlvbiggbmV3QWN0aW9uLCBjbGlwVXVpZCwgcm9vdFV1aWQgKTtcclxuXHJcblx0XHRyZXR1cm4gbmV3QWN0aW9uO1xyXG5cclxuXHR9XHJcblxyXG5cdC8vIGdldCBhbiBleGlzdGluZyBhY3Rpb25cclxuXHRleGlzdGluZ0FjdGlvbiggY2xpcCwgb3B0aW9uYWxSb290ICkge1xyXG5cclxuXHRcdGNvbnN0IHJvb3QgPSBvcHRpb25hbFJvb3QgfHwgdGhpcy5fcm9vdCxcclxuXHRcdFx0cm9vdFV1aWQgPSByb290LnV1aWQsXHJcblxyXG5cdFx0XHRjbGlwT2JqZWN0ID0gdHlwZW9mIGNsaXAgPT09ICdzdHJpbmcnID9cclxuXHRcdFx0XHRBbmltYXRpb25DbGlwLmZpbmRCeU5hbWUoIHJvb3QsIGNsaXAgKSA6IGNsaXAsXHJcblxyXG5cdFx0XHRjbGlwVXVpZCA9IGNsaXBPYmplY3QgPyBjbGlwT2JqZWN0LnV1aWQgOiBjbGlwLFxyXG5cclxuXHRcdFx0YWN0aW9uc0ZvckNsaXAgPSB0aGlzLl9hY3Rpb25zQnlDbGlwWyBjbGlwVXVpZCBdO1xyXG5cclxuXHRcdGlmICggYWN0aW9uc0ZvckNsaXAgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdHJldHVybiBhY3Rpb25zRm9yQ2xpcC5hY3Rpb25CeVJvb3RbIHJvb3RVdWlkIF0gfHwgbnVsbDtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIG51bGw7XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gZGVhY3RpdmF0ZXMgYWxsIHByZXZpb3VzbHkgc2NoZWR1bGVkIGFjdGlvbnNcclxuXHRzdG9wQWxsQWN0aW9uKCkge1xyXG5cclxuXHRcdGNvbnN0IGFjdGlvbnMgPSB0aGlzLl9hY3Rpb25zLFxyXG5cdFx0XHRuQWN0aW9ucyA9IHRoaXMuX25BY3RpdmVBY3Rpb25zO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gbkFjdGlvbnMgLSAxOyBpID49IDA7IC0tIGkgKSB7XHJcblxyXG5cdFx0XHRhY3Rpb25zWyBpIF0uc3RvcCgpO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHQvLyBhZHZhbmNlIHRoZSB0aW1lIGFuZCB1cGRhdGUgYXBwbHkgdGhlIGFuaW1hdGlvblxyXG5cdHVwZGF0ZSggZGVsdGFUaW1lICkge1xyXG5cclxuXHRcdGRlbHRhVGltZSAqPSB0aGlzLnRpbWVTY2FsZTtcclxuXHJcblx0XHRjb25zdCBhY3Rpb25zID0gdGhpcy5fYWN0aW9ucyxcclxuXHRcdFx0bkFjdGlvbnMgPSB0aGlzLl9uQWN0aXZlQWN0aW9ucyxcclxuXHJcblx0XHRcdHRpbWUgPSB0aGlzLnRpbWUgKz0gZGVsdGFUaW1lLFxyXG5cdFx0XHR0aW1lRGlyZWN0aW9uID0gTWF0aC5zaWduKCBkZWx0YVRpbWUgKSxcclxuXHJcblx0XHRcdGFjY3VJbmRleCA9IHRoaXMuX2FjY3VJbmRleCBePSAxO1xyXG5cclxuXHRcdC8vIHJ1biBhY3RpdmUgYWN0aW9uc1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMDsgaSAhPT0gbkFjdGlvbnM7ICsrIGkgKSB7XHJcblxyXG5cdFx0XHRjb25zdCBhY3Rpb24gPSBhY3Rpb25zWyBpIF07XHJcblxyXG5cdFx0XHRhY3Rpb24uX3VwZGF0ZSggdGltZSwgZGVsdGFUaW1lLCB0aW1lRGlyZWN0aW9uLCBhY2N1SW5kZXggKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gdXBkYXRlIHNjZW5lIGdyYXBoXHJcblxyXG5cdFx0Y29uc3QgYmluZGluZ3MgPSB0aGlzLl9iaW5kaW5ncyxcclxuXHRcdFx0bkJpbmRpbmdzID0gdGhpcy5fbkFjdGl2ZUJpbmRpbmdzO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMDsgaSAhPT0gbkJpbmRpbmdzOyArKyBpICkge1xyXG5cclxuXHRcdFx0YmluZGluZ3NbIGkgXS5hcHBseSggYWNjdUluZGV4ICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdC8vIEFsbG93cyB5b3UgdG8gc2VlayB0byBhIHNwZWNpZmljIHRpbWUgaW4gYW4gYW5pbWF0aW9uLlxyXG5cdHNldFRpbWUoIHRpbWVJblNlY29uZHMgKSB7XHJcblxyXG5cdFx0dGhpcy50aW1lID0gMDsgLy8gWmVybyBvdXQgdGltZSBhdHRyaWJ1dGUgZm9yIEFuaW1hdGlvbk1peGVyIG9iamVjdDtcclxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHRoaXMuX2FjdGlvbnMubGVuZ3RoOyBpICsrICkge1xyXG5cclxuXHRcdFx0dGhpcy5fYWN0aW9uc1sgaSBdLnRpbWUgPSAwOyAvLyBaZXJvIG91dCB0aW1lIGF0dHJpYnV0ZSBmb3IgYWxsIGFzc29jaWF0ZWQgQW5pbWF0aW9uQWN0aW9uIG9iamVjdHMuXHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzLnVwZGF0ZSggdGltZUluU2Vjb25kcyApOyAvLyBVcGRhdGUgdXNlZCB0byBzZXQgZXhhY3QgdGltZS4gUmV0dXJucyBcInRoaXNcIiBBbmltYXRpb25NaXhlciBvYmplY3QuXHJcblxyXG5cdH1cclxuXHJcblx0Ly8gcmV0dXJuIHRoaXMgbWl4ZXIncyByb290IHRhcmdldCBvYmplY3RcclxuXHRnZXRSb290KCkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLl9yb290O1xyXG5cclxuXHR9XHJcblxyXG5cdC8vIGZyZWUgYWxsIHJlc291cmNlcyBzcGVjaWZpYyB0byBhIHBhcnRpY3VsYXIgY2xpcFxyXG5cdHVuY2FjaGVDbGlwKCBjbGlwICkge1xyXG5cclxuXHRcdGNvbnN0IGFjdGlvbnMgPSB0aGlzLl9hY3Rpb25zLFxyXG5cdFx0XHRjbGlwVXVpZCA9IGNsaXAudXVpZCxcclxuXHRcdFx0YWN0aW9uc0J5Q2xpcCA9IHRoaXMuX2FjdGlvbnNCeUNsaXAsXHJcblx0XHRcdGFjdGlvbnNGb3JDbGlwID0gYWN0aW9uc0J5Q2xpcFsgY2xpcFV1aWQgXTtcclxuXHJcblx0XHRpZiAoIGFjdGlvbnNGb3JDbGlwICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHQvLyBub3RlOiBqdXN0IGNhbGxpbmcgX3JlbW92ZUluYWN0aXZlQWN0aW9uIHdvdWxkIG1lc3MgdXAgdGhlXHJcblx0XHRcdC8vIGl0ZXJhdGlvbiBzdGF0ZSBhbmQgYWxzbyByZXF1aXJlIHVwZGF0aW5nIHRoZSBzdGF0ZSB3ZSBjYW5cclxuXHRcdFx0Ly8ganVzdCB0aHJvdyBhd2F5XHJcblxyXG5cdFx0XHRjb25zdCBhY3Rpb25zVG9SZW1vdmUgPSBhY3Rpb25zRm9yQ2xpcC5rbm93bkFjdGlvbnM7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIG4gPSBhY3Rpb25zVG9SZW1vdmUubGVuZ3RoOyBpICE9PSBuOyArKyBpICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBhY3Rpb24gPSBhY3Rpb25zVG9SZW1vdmVbIGkgXTtcclxuXHJcblx0XHRcdFx0dGhpcy5fZGVhY3RpdmF0ZUFjdGlvbiggYWN0aW9uICk7XHJcblxyXG5cdFx0XHRcdGNvbnN0IGNhY2hlSW5kZXggPSBhY3Rpb24uX2NhY2hlSW5kZXgsXHJcblx0XHRcdFx0XHRsYXN0SW5hY3RpdmVBY3Rpb24gPSBhY3Rpb25zWyBhY3Rpb25zLmxlbmd0aCAtIDEgXTtcclxuXHJcblx0XHRcdFx0YWN0aW9uLl9jYWNoZUluZGV4ID0gbnVsbDtcclxuXHRcdFx0XHRhY3Rpb24uX2J5Q2xpcENhY2hlSW5kZXggPSBudWxsO1xyXG5cclxuXHRcdFx0XHRsYXN0SW5hY3RpdmVBY3Rpb24uX2NhY2hlSW5kZXggPSBjYWNoZUluZGV4O1xyXG5cdFx0XHRcdGFjdGlvbnNbIGNhY2hlSW5kZXggXSA9IGxhc3RJbmFjdGl2ZUFjdGlvbjtcclxuXHRcdFx0XHRhY3Rpb25zLnBvcCgpO1xyXG5cclxuXHRcdFx0XHR0aGlzLl9yZW1vdmVJbmFjdGl2ZUJpbmRpbmdzRm9yQWN0aW9uKCBhY3Rpb24gKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGRlbGV0ZSBhY3Rpb25zQnlDbGlwWyBjbGlwVXVpZCBdO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHQvLyBmcmVlIGFsbCByZXNvdXJjZXMgc3BlY2lmaWMgdG8gYSBwYXJ0aWN1bGFyIHJvb3QgdGFyZ2V0IG9iamVjdFxyXG5cdHVuY2FjaGVSb290KCByb290ICkge1xyXG5cclxuXHRcdGNvbnN0IHJvb3RVdWlkID0gcm9vdC51dWlkLFxyXG5cdFx0XHRhY3Rpb25zQnlDbGlwID0gdGhpcy5fYWN0aW9uc0J5Q2xpcDtcclxuXHJcblx0XHRmb3IgKCBjb25zdCBjbGlwVXVpZCBpbiBhY3Rpb25zQnlDbGlwICkge1xyXG5cclxuXHRcdFx0Y29uc3QgYWN0aW9uQnlSb290ID0gYWN0aW9uc0J5Q2xpcFsgY2xpcFV1aWQgXS5hY3Rpb25CeVJvb3QsXHJcblx0XHRcdFx0YWN0aW9uID0gYWN0aW9uQnlSb290WyByb290VXVpZCBdO1xyXG5cclxuXHRcdFx0aWYgKCBhY3Rpb24gIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdFx0dGhpcy5fZGVhY3RpdmF0ZUFjdGlvbiggYWN0aW9uICk7XHJcblx0XHRcdFx0dGhpcy5fcmVtb3ZlSW5hY3RpdmVBY3Rpb24oIGFjdGlvbiApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCBiaW5kaW5nc0J5Um9vdCA9IHRoaXMuX2JpbmRpbmdzQnlSb290QW5kTmFtZSxcclxuXHRcdFx0YmluZGluZ0J5TmFtZSA9IGJpbmRpbmdzQnlSb290WyByb290VXVpZCBdO1xyXG5cclxuXHRcdGlmICggYmluZGluZ0J5TmFtZSAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0Zm9yICggY29uc3QgdHJhY2tOYW1lIGluIGJpbmRpbmdCeU5hbWUgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IGJpbmRpbmcgPSBiaW5kaW5nQnlOYW1lWyB0cmFja05hbWUgXTtcclxuXHRcdFx0XHRiaW5kaW5nLnJlc3RvcmVPcmlnaW5hbFN0YXRlKCk7XHJcblx0XHRcdFx0dGhpcy5fcmVtb3ZlSW5hY3RpdmVCaW5kaW5nKCBiaW5kaW5nICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdC8vIHJlbW92ZSBhIHRhcmdldGVkIGNsaXAgZnJvbSB0aGUgY2FjaGVcclxuXHR1bmNhY2hlQWN0aW9uKCBjbGlwLCBvcHRpb25hbFJvb3QgKSB7XHJcblxyXG5cdFx0Y29uc3QgYWN0aW9uID0gdGhpcy5leGlzdGluZ0FjdGlvbiggY2xpcCwgb3B0aW9uYWxSb290ICk7XHJcblxyXG5cdFx0aWYgKCBhY3Rpb24gIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHR0aGlzLl9kZWFjdGl2YXRlQWN0aW9uKCBhY3Rpb24gKTtcclxuXHRcdFx0dGhpcy5fcmVtb3ZlSW5hY3RpdmVBY3Rpb24oIGFjdGlvbiApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgQW5pbWF0aW9uTWl4ZXIgfTtcclxuIiwiY2xhc3MgVW5pZm9ybSB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCB2YWx1ZSApIHtcclxuXHJcblx0XHR0aGlzLnZhbHVlID0gdmFsdWU7XHJcblxyXG5cdH1cclxuXHJcblx0Y2xvbmUoKSB7XHJcblxyXG5cdFx0cmV0dXJuIG5ldyBVbmlmb3JtKCB0aGlzLnZhbHVlLmNsb25lID09PSB1bmRlZmluZWQgPyB0aGlzLnZhbHVlIDogdGhpcy52YWx1ZS5jbG9uZSgpICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IFVuaWZvcm0gfTtcclxuIiwiaW1wb3J0IHsgRXZlbnREaXNwYXRjaGVyIH0gZnJvbSAnLi9FdmVudERpc3BhdGNoZXIuanMnO1xyXG5pbXBvcnQgeyBTdGF0aWNEcmF3VXNhZ2UgfSBmcm9tICcuLi9jb25zdGFudHMuanMnO1xyXG5cclxubGV0IF9pZCA9IDA7XHJcblxyXG5jbGFzcyBVbmlmb3Jtc0dyb3VwIGV4dGVuZHMgRXZlbnREaXNwYXRjaGVyIHtcclxuXHJcblx0Y29uc3RydWN0b3IoKSB7XHJcblxyXG5cdFx0c3VwZXIoKTtcclxuXHJcblx0XHR0aGlzLmlzVW5pZm9ybXNHcm91cCA9IHRydWU7XHJcblxyXG5cdFx0T2JqZWN0LmRlZmluZVByb3BlcnR5KCB0aGlzLCAnaWQnLCB7IHZhbHVlOiBfaWQgKysgfSApO1xyXG5cclxuXHRcdHRoaXMubmFtZSA9ICcnO1xyXG5cclxuXHRcdHRoaXMudXNhZ2UgPSBTdGF0aWNEcmF3VXNhZ2U7XHJcblx0XHR0aGlzLnVuaWZvcm1zID0gW107XHJcblxyXG5cdH1cclxuXHJcblx0YWRkKCB1bmlmb3JtICkge1xyXG5cclxuXHRcdHRoaXMudW5pZm9ybXMucHVzaCggdW5pZm9ybSApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHJlbW92ZSggdW5pZm9ybSApIHtcclxuXHJcblx0XHRjb25zdCBpbmRleCA9IHRoaXMudW5pZm9ybXMuaW5kZXhPZiggdW5pZm9ybSApO1xyXG5cclxuXHRcdGlmICggaW5kZXggIT09IC0gMSApIHRoaXMudW5pZm9ybXMuc3BsaWNlKCBpbmRleCwgMSApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldE5hbWUoIG5hbWUgKSB7XHJcblxyXG5cdFx0dGhpcy5uYW1lID0gbmFtZTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRVc2FnZSggdmFsdWUgKSB7XHJcblxyXG5cdFx0dGhpcy51c2FnZSA9IHZhbHVlO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGRpc3Bvc2UoKSB7XHJcblxyXG5cdFx0dGhpcy5kaXNwYXRjaEV2ZW50KCB7IHR5cGU6ICdkaXNwb3NlJyB9ICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHRoaXMubmFtZSA9IHNvdXJjZS5uYW1lO1xyXG5cdFx0dGhpcy51c2FnZSA9IHNvdXJjZS51c2FnZTtcclxuXHJcblx0XHRjb25zdCB1bmlmb3Jtc1NvdXJjZSA9IHNvdXJjZS51bmlmb3JtcztcclxuXHJcblx0XHR0aGlzLnVuaWZvcm1zLmxlbmd0aCA9IDA7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gdW5pZm9ybXNTb3VyY2UubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcclxuXHJcblx0XHRcdGNvbnN0IHVuaWZvcm1zID0gQXJyYXkuaXNBcnJheSggdW5pZm9ybXNTb3VyY2VbIGkgXSApID8gdW5pZm9ybXNTb3VyY2VbIGkgXSA6IFsgdW5pZm9ybXNTb3VyY2VbIGkgXSBdO1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGogPSAwOyBqIDwgdW5pZm9ybXMubGVuZ3RoOyBqICsrICkge1xyXG5cclxuXHRcdFx0XHR0aGlzLnVuaWZvcm1zLnB1c2goIHVuaWZvcm1zWyBqIF0uY2xvbmUoKSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRjbG9uZSgpIHtcclxuXHJcblx0XHRyZXR1cm4gbmV3IHRoaXMuY29uc3RydWN0b3IoKS5jb3B5KCB0aGlzICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IFVuaWZvcm1zR3JvdXAgfTtcclxuIiwiaW1wb3J0IHsgSW50ZXJsZWF2ZWRCdWZmZXIgfSBmcm9tICcuL0ludGVybGVhdmVkQnVmZmVyLmpzJztcclxuXHJcbmNsYXNzIEluc3RhbmNlZEludGVybGVhdmVkQnVmZmVyIGV4dGVuZHMgSW50ZXJsZWF2ZWRCdWZmZXIge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggYXJyYXksIHN0cmlkZSwgbWVzaFBlckF0dHJpYnV0ZSA9IDEgKSB7XHJcblxyXG5cdFx0c3VwZXIoIGFycmF5LCBzdHJpZGUgKTtcclxuXHJcblx0XHR0aGlzLmlzSW5zdGFuY2VkSW50ZXJsZWF2ZWRCdWZmZXIgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMubWVzaFBlckF0dHJpYnV0ZSA9IG1lc2hQZXJBdHRyaWJ1dGU7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggc291cmNlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xyXG5cclxuXHRcdHRoaXMubWVzaFBlckF0dHJpYnV0ZSA9IHNvdXJjZS5tZXNoUGVyQXR0cmlidXRlO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGNsb25lKCBkYXRhICkge1xyXG5cclxuXHRcdGNvbnN0IGliID0gc3VwZXIuY2xvbmUoIGRhdGEgKTtcclxuXHJcblx0XHRpYi5tZXNoUGVyQXR0cmlidXRlID0gdGhpcy5tZXNoUGVyQXR0cmlidXRlO1xyXG5cclxuXHRcdHJldHVybiBpYjtcclxuXHJcblx0fVxyXG5cclxuXHR0b0pTT04oIGRhdGEgKSB7XHJcblxyXG5cdFx0Y29uc3QganNvbiA9IHN1cGVyLnRvSlNPTiggZGF0YSApO1xyXG5cclxuXHRcdGpzb24uaXNJbnN0YW5jZWRJbnRlcmxlYXZlZEJ1ZmZlciA9IHRydWU7XHJcblx0XHRqc29uLm1lc2hQZXJBdHRyaWJ1dGUgPSB0aGlzLm1lc2hQZXJBdHRyaWJ1dGU7XHJcblxyXG5cdFx0cmV0dXJuIGpzb247XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IEluc3RhbmNlZEludGVybGVhdmVkQnVmZmVyIH07XHJcbiIsImNsYXNzIEdMQnVmZmVyQXR0cmlidXRlIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIGJ1ZmZlciwgdHlwZSwgaXRlbVNpemUsIGVsZW1lbnRTaXplLCBjb3VudCApIHtcclxuXHJcblx0XHR0aGlzLmlzR0xCdWZmZXJBdHRyaWJ1dGUgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMubmFtZSA9ICcnO1xyXG5cclxuXHRcdHRoaXMuYnVmZmVyID0gYnVmZmVyO1xyXG5cdFx0dGhpcy50eXBlID0gdHlwZTtcclxuXHRcdHRoaXMuaXRlbVNpemUgPSBpdGVtU2l6ZTtcclxuXHRcdHRoaXMuZWxlbWVudFNpemUgPSBlbGVtZW50U2l6ZTtcclxuXHRcdHRoaXMuY291bnQgPSBjb3VudDtcclxuXHJcblx0XHR0aGlzLnZlcnNpb24gPSAwO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldCBuZWVkc1VwZGF0ZSggdmFsdWUgKSB7XHJcblxyXG5cdFx0aWYgKCB2YWx1ZSA9PT0gdHJ1ZSApIHRoaXMudmVyc2lvbiArKztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRCdWZmZXIoIGJ1ZmZlciApIHtcclxuXHJcblx0XHR0aGlzLmJ1ZmZlciA9IGJ1ZmZlcjtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzZXRUeXBlKCB0eXBlLCBlbGVtZW50U2l6ZSApIHtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSB0eXBlO1xyXG5cdFx0dGhpcy5lbGVtZW50U2l6ZSA9IGVsZW1lbnRTaXplO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldEl0ZW1TaXplKCBpdGVtU2l6ZSApIHtcclxuXHJcblx0XHR0aGlzLml0ZW1TaXplID0gaXRlbVNpemU7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0Q291bnQoIGNvdW50ICkge1xyXG5cclxuXHRcdHRoaXMuY291bnQgPSBjb3VudDtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgR0xCdWZmZXJBdHRyaWJ1dGUgfTtcclxuIiwiaW1wb3J0IHsgUmF5IH0gZnJvbSAnLi4vbWF0aC9SYXkuanMnO1xyXG5pbXBvcnQgeyBMYXllcnMgfSBmcm9tICcuL0xheWVycy5qcyc7XHJcblxyXG5jbGFzcyBSYXljYXN0ZXIge1xyXG5cclxuXHRjb25zdHJ1Y3Rvciggb3JpZ2luLCBkaXJlY3Rpb24sIG5lYXIgPSAwLCBmYXIgPSBJbmZpbml0eSApIHtcclxuXHJcblx0XHR0aGlzLnJheSA9IG5ldyBSYXkoIG9yaWdpbiwgZGlyZWN0aW9uICk7XHJcblx0XHQvLyBkaXJlY3Rpb24gaXMgYXNzdW1lZCB0byBiZSBub3JtYWxpemVkIChmb3IgYWNjdXJhdGUgZGlzdGFuY2UgY2FsY3VsYXRpb25zKVxyXG5cclxuXHRcdHRoaXMubmVhciA9IG5lYXI7XHJcblx0XHR0aGlzLmZhciA9IGZhcjtcclxuXHRcdHRoaXMuY2FtZXJhID0gbnVsbDtcclxuXHRcdHRoaXMubGF5ZXJzID0gbmV3IExheWVycygpO1xyXG5cclxuXHRcdHRoaXMucGFyYW1zID0ge1xyXG5cdFx0XHRNZXNoOiB7fSxcclxuXHRcdFx0TGluZTogeyB0aHJlc2hvbGQ6IDEgfSxcclxuXHRcdFx0TE9EOiB7fSxcclxuXHRcdFx0UG9pbnRzOiB7IHRocmVzaG9sZDogMSB9LFxyXG5cdFx0XHRTcHJpdGU6IHt9XHJcblx0XHR9O1xyXG5cclxuXHR9XHJcblxyXG5cdHNldCggb3JpZ2luLCBkaXJlY3Rpb24gKSB7XHJcblxyXG5cdFx0Ly8gZGlyZWN0aW9uIGlzIGFzc3VtZWQgdG8gYmUgbm9ybWFsaXplZCAoZm9yIGFjY3VyYXRlIGRpc3RhbmNlIGNhbGN1bGF0aW9ucylcclxuXHJcblx0XHR0aGlzLnJheS5zZXQoIG9yaWdpbiwgZGlyZWN0aW9uICk7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0RnJvbUNhbWVyYSggY29vcmRzLCBjYW1lcmEgKSB7XHJcblxyXG5cdFx0aWYgKCBjYW1lcmEuaXNQZXJzcGVjdGl2ZUNhbWVyYSApIHtcclxuXHJcblx0XHRcdHRoaXMucmF5Lm9yaWdpbi5zZXRGcm9tTWF0cml4UG9zaXRpb24oIGNhbWVyYS5tYXRyaXhXb3JsZCApO1xyXG5cdFx0XHR0aGlzLnJheS5kaXJlY3Rpb24uc2V0KCBjb29yZHMueCwgY29vcmRzLnksIDAuNSApLnVucHJvamVjdCggY2FtZXJhICkuc3ViKCB0aGlzLnJheS5vcmlnaW4gKS5ub3JtYWxpemUoKTtcclxuXHRcdFx0dGhpcy5jYW1lcmEgPSBjYW1lcmE7XHJcblxyXG5cdFx0fSBlbHNlIGlmICggY2FtZXJhLmlzT3J0aG9ncmFwaGljQ2FtZXJhICkge1xyXG5cclxuXHRcdFx0dGhpcy5yYXkub3JpZ2luLnNldCggY29vcmRzLngsIGNvb3Jkcy55LCAoIGNhbWVyYS5uZWFyICsgY2FtZXJhLmZhciApIC8gKCBjYW1lcmEubmVhciAtIGNhbWVyYS5mYXIgKSApLnVucHJvamVjdCggY2FtZXJhICk7IC8vIHNldCBvcmlnaW4gaW4gcGxhbmUgb2YgY2FtZXJhXHJcblx0XHRcdHRoaXMucmF5LmRpcmVjdGlvbi5zZXQoIDAsIDAsIC0gMSApLnRyYW5zZm9ybURpcmVjdGlvbiggY2FtZXJhLm1hdHJpeFdvcmxkICk7XHJcblx0XHRcdHRoaXMuY2FtZXJhID0gY2FtZXJhO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuUmF5Y2FzdGVyOiBVbnN1cHBvcnRlZCBjYW1lcmEgdHlwZTogJyArIGNhbWVyYS50eXBlICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdGludGVyc2VjdE9iamVjdCggb2JqZWN0LCByZWN1cnNpdmUgPSB0cnVlLCBpbnRlcnNlY3RzID0gW10gKSB7XHJcblxyXG5cdFx0aW50ZXJzZWN0T2JqZWN0KCBvYmplY3QsIHRoaXMsIGludGVyc2VjdHMsIHJlY3Vyc2l2ZSApO1xyXG5cclxuXHRcdGludGVyc2VjdHMuc29ydCggYXNjU29ydCApO1xyXG5cclxuXHRcdHJldHVybiBpbnRlcnNlY3RzO1xyXG5cclxuXHR9XHJcblxyXG5cdGludGVyc2VjdE9iamVjdHMoIG9iamVjdHMsIHJlY3Vyc2l2ZSA9IHRydWUsIGludGVyc2VjdHMgPSBbXSApIHtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBvYmplY3RzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRpbnRlcnNlY3RPYmplY3QoIG9iamVjdHNbIGkgXSwgdGhpcywgaW50ZXJzZWN0cywgcmVjdXJzaXZlICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGludGVyc2VjdHMuc29ydCggYXNjU29ydCApO1xyXG5cclxuXHRcdHJldHVybiBpbnRlcnNlY3RzO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiBhc2NTb3J0KCBhLCBiICkge1xyXG5cclxuXHRyZXR1cm4gYS5kaXN0YW5jZSAtIGIuZGlzdGFuY2U7XHJcblxyXG59XHJcblxyXG5mdW5jdGlvbiBpbnRlcnNlY3RPYmplY3QoIG9iamVjdCwgcmF5Y2FzdGVyLCBpbnRlcnNlY3RzLCByZWN1cnNpdmUgKSB7XHJcblxyXG5cdGlmICggb2JqZWN0LmxheWVycy50ZXN0KCByYXljYXN0ZXIubGF5ZXJzICkgKSB7XHJcblxyXG5cdFx0b2JqZWN0LnJheWNhc3QoIHJheWNhc3RlciwgaW50ZXJzZWN0cyApO1xyXG5cclxuXHR9XHJcblxyXG5cdGlmICggcmVjdXJzaXZlID09PSB0cnVlICkge1xyXG5cclxuXHRcdGNvbnN0IGNoaWxkcmVuID0gb2JqZWN0LmNoaWxkcmVuO1xyXG5cclxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IGNoaWxkcmVuLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRpbnRlcnNlY3RPYmplY3QoIGNoaWxkcmVuWyBpIF0sIHJheWNhc3RlciwgaW50ZXJzZWN0cywgdHJ1ZSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuZXhwb3J0IHsgUmF5Y2FzdGVyIH07XHJcbiIsIi8qKlxyXG4gKiBSZWY6IGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL1NwaGVyaWNhbF9jb29yZGluYXRlX3N5c3RlbVxyXG4gKlxyXG4gKiBUaGUgcG9sYXIgYW5nbGUgKHBoaSkgaXMgbWVhc3VyZWQgZnJvbSB0aGUgcG9zaXRpdmUgeS1heGlzLiBUaGUgcG9zaXRpdmUgeS1heGlzIGlzIHVwLlxyXG4gKiBUaGUgYXppbXV0aGFsIGFuZ2xlICh0aGV0YSkgaXMgbWVhc3VyZWQgZnJvbSB0aGUgcG9zaXRpdmUgei1heGlzLlxyXG4gKi9cclxuXHJcbmltcG9ydCAqIGFzIE1hdGhVdGlscyBmcm9tICcuL01hdGhVdGlscy5qcyc7XHJcblxyXG5jbGFzcyBTcGhlcmljYWwge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggcmFkaXVzID0gMSwgcGhpID0gMCwgdGhldGEgPSAwICkge1xyXG5cclxuXHRcdHRoaXMucmFkaXVzID0gcmFkaXVzO1xyXG5cdFx0dGhpcy5waGkgPSBwaGk7IC8vIHBvbGFyIGFuZ2xlXHJcblx0XHR0aGlzLnRoZXRhID0gdGhldGE7IC8vIGF6aW11dGhhbCBhbmdsZVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldCggcmFkaXVzLCBwaGksIHRoZXRhICkge1xyXG5cclxuXHRcdHRoaXMucmFkaXVzID0gcmFkaXVzO1xyXG5cdFx0dGhpcy5waGkgPSBwaGk7XHJcblx0XHR0aGlzLnRoZXRhID0gdGhldGE7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggb3RoZXIgKSB7XHJcblxyXG5cdFx0dGhpcy5yYWRpdXMgPSBvdGhlci5yYWRpdXM7XHJcblx0XHR0aGlzLnBoaSA9IG90aGVyLnBoaTtcclxuXHRcdHRoaXMudGhldGEgPSBvdGhlci50aGV0YTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHQvLyByZXN0cmljdCBwaGkgdG8gYmUgYmV0d2VlbiBFUFMgYW5kIFBJLUVQU1xyXG5cdG1ha2VTYWZlKCkge1xyXG5cclxuXHRcdGNvbnN0IEVQUyA9IDAuMDAwMDAxO1xyXG5cdFx0dGhpcy5waGkgPSBNYXRoLm1heCggRVBTLCBNYXRoLm1pbiggTWF0aC5QSSAtIEVQUywgdGhpcy5waGkgKSApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldEZyb21WZWN0b3IzKCB2ICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLnNldEZyb21DYXJ0ZXNpYW5Db29yZHMoIHYueCwgdi55LCB2LnogKTtcclxuXHJcblx0fVxyXG5cclxuXHRzZXRGcm9tQ2FydGVzaWFuQ29vcmRzKCB4LCB5LCB6ICkge1xyXG5cclxuXHRcdHRoaXMucmFkaXVzID0gTWF0aC5zcXJ0KCB4ICogeCArIHkgKiB5ICsgeiAqIHogKTtcclxuXHJcblx0XHRpZiAoIHRoaXMucmFkaXVzID09PSAwICkge1xyXG5cclxuXHRcdFx0dGhpcy50aGV0YSA9IDA7XHJcblx0XHRcdHRoaXMucGhpID0gMDtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0dGhpcy50aGV0YSA9IE1hdGguYXRhbjIoIHgsIHogKTtcclxuXHRcdFx0dGhpcy5waGkgPSBNYXRoLmFjb3MoIE1hdGhVdGlscy5jbGFtcCggeSAvIHRoaXMucmFkaXVzLCAtIDEsIDEgKSApO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRjbG9uZSgpIHtcclxuXHJcblx0XHRyZXR1cm4gbmV3IHRoaXMuY29uc3RydWN0b3IoKS5jb3B5KCB0aGlzICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IFNwaGVyaWNhbCB9O1xyXG4iLCIvKipcclxuICogUmVmOiBodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9DeWxpbmRyaWNhbF9jb29yZGluYXRlX3N5c3RlbVxyXG4gKi9cclxuXHJcbmNsYXNzIEN5bGluZHJpY2FsIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIHJhZGl1cyA9IDEsIHRoZXRhID0gMCwgeSA9IDAgKSB7XHJcblxyXG5cdFx0dGhpcy5yYWRpdXMgPSByYWRpdXM7IC8vIGRpc3RhbmNlIGZyb20gdGhlIG9yaWdpbiB0byBhIHBvaW50IGluIHRoZSB4LXogcGxhbmVcclxuXHRcdHRoaXMudGhldGEgPSB0aGV0YTsgLy8gY291bnRlcmNsb2Nrd2lzZSBhbmdsZSBpbiB0aGUgeC16IHBsYW5lIG1lYXN1cmVkIGluIHJhZGlhbnMgZnJvbSB0aGUgcG9zaXRpdmUgei1heGlzXHJcblx0XHR0aGlzLnkgPSB5OyAvLyBoZWlnaHQgYWJvdmUgdGhlIHgteiBwbGFuZVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldCggcmFkaXVzLCB0aGV0YSwgeSApIHtcclxuXHJcblx0XHR0aGlzLnJhZGl1cyA9IHJhZGl1cztcclxuXHRcdHRoaXMudGhldGEgPSB0aGV0YTtcclxuXHRcdHRoaXMueSA9IHk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggb3RoZXIgKSB7XHJcblxyXG5cdFx0dGhpcy5yYWRpdXMgPSBvdGhlci5yYWRpdXM7XHJcblx0XHR0aGlzLnRoZXRhID0gb3RoZXIudGhldGE7XHJcblx0XHR0aGlzLnkgPSBvdGhlci55O1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldEZyb21WZWN0b3IzKCB2ICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLnNldEZyb21DYXJ0ZXNpYW5Db29yZHMoIHYueCwgdi55LCB2LnogKTtcclxuXHJcblx0fVxyXG5cclxuXHRzZXRGcm9tQ2FydGVzaWFuQ29vcmRzKCB4LCB5LCB6ICkge1xyXG5cclxuXHRcdHRoaXMucmFkaXVzID0gTWF0aC5zcXJ0KCB4ICogeCArIHogKiB6ICk7XHJcblx0XHR0aGlzLnRoZXRhID0gTWF0aC5hdGFuMiggeCwgeiApO1xyXG5cdFx0dGhpcy55ID0geTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRjbG9uZSgpIHtcclxuXHJcblx0XHRyZXR1cm4gbmV3IHRoaXMuY29uc3RydWN0b3IoKS5jb3B5KCB0aGlzICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IEN5bGluZHJpY2FsIH07XHJcbiIsImltcG9ydCB7IFZlY3RvcjIgfSBmcm9tICcuL1ZlY3RvcjIuanMnO1xyXG5cclxuY29uc3QgX3ZlY3RvciA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjIoKTtcclxuXHJcbmNsYXNzIEJveDIge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggbWluID0gbmV3IFZlY3RvcjIoICsgSW5maW5pdHksICsgSW5maW5pdHkgKSwgbWF4ID0gbmV3IFZlY3RvcjIoIC0gSW5maW5pdHksIC0gSW5maW5pdHkgKSApIHtcclxuXHJcblx0XHR0aGlzLmlzQm94MiA9IHRydWU7XHJcblxyXG5cdFx0dGhpcy5taW4gPSBtaW47XHJcblx0XHR0aGlzLm1heCA9IG1heDtcclxuXHJcblx0fVxyXG5cclxuXHRzZXQoIG1pbiwgbWF4ICkge1xyXG5cclxuXHRcdHRoaXMubWluLmNvcHkoIG1pbiApO1xyXG5cdFx0dGhpcy5tYXguY29weSggbWF4ICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0RnJvbVBvaW50cyggcG9pbnRzICkge1xyXG5cclxuXHRcdHRoaXMubWFrZUVtcHR5KCk7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBpbCA9IHBvaW50cy5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcclxuXHJcblx0XHRcdHRoaXMuZXhwYW5kQnlQb2ludCggcG9pbnRzWyBpIF0gKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0RnJvbUNlbnRlckFuZFNpemUoIGNlbnRlciwgc2l6ZSApIHtcclxuXHJcblx0XHRjb25zdCBoYWxmU2l6ZSA9IF92ZWN0b3IuY29weSggc2l6ZSApLm11bHRpcGx5U2NhbGFyKCAwLjUgKTtcclxuXHRcdHRoaXMubWluLmNvcHkoIGNlbnRlciApLnN1YiggaGFsZlNpemUgKTtcclxuXHRcdHRoaXMubWF4LmNvcHkoIGNlbnRlciApLmFkZCggaGFsZlNpemUgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRjbG9uZSgpIHtcclxuXHJcblx0XHRyZXR1cm4gbmV3IHRoaXMuY29uc3RydWN0b3IoKS5jb3B5KCB0aGlzICk7XHJcblxyXG5cdH1cclxuXHJcblx0Y29weSggYm94ICkge1xyXG5cclxuXHRcdHRoaXMubWluLmNvcHkoIGJveC5taW4gKTtcclxuXHRcdHRoaXMubWF4LmNvcHkoIGJveC5tYXggKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRtYWtlRW1wdHkoKSB7XHJcblxyXG5cdFx0dGhpcy5taW4ueCA9IHRoaXMubWluLnkgPSArIEluZmluaXR5O1xyXG5cdFx0dGhpcy5tYXgueCA9IHRoaXMubWF4LnkgPSAtIEluZmluaXR5O1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGlzRW1wdHkoKSB7XHJcblxyXG5cdFx0Ly8gdGhpcyBpcyBhIG1vcmUgcm9idXN0IGNoZWNrIGZvciBlbXB0eSB0aGFuICggdm9sdW1lIDw9IDAgKSBiZWNhdXNlIHZvbHVtZSBjYW4gZ2V0IHBvc2l0aXZlIHdpdGggdHdvIG5lZ2F0aXZlIGF4ZXNcclxuXHJcblx0XHRyZXR1cm4gKCB0aGlzLm1heC54IDwgdGhpcy5taW4ueCApIHx8ICggdGhpcy5tYXgueSA8IHRoaXMubWluLnkgKTtcclxuXHJcblx0fVxyXG5cclxuXHRnZXRDZW50ZXIoIHRhcmdldCApIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5pc0VtcHR5KCkgPyB0YXJnZXQuc2V0KCAwLCAwICkgOiB0YXJnZXQuYWRkVmVjdG9ycyggdGhpcy5taW4sIHRoaXMubWF4ICkubXVsdGlwbHlTY2FsYXIoIDAuNSApO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldFNpemUoIHRhcmdldCApIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5pc0VtcHR5KCkgPyB0YXJnZXQuc2V0KCAwLCAwICkgOiB0YXJnZXQuc3ViVmVjdG9ycyggdGhpcy5tYXgsIHRoaXMubWluICk7XHJcblxyXG5cdH1cclxuXHJcblx0ZXhwYW5kQnlQb2ludCggcG9pbnQgKSB7XHJcblxyXG5cdFx0dGhpcy5taW4ubWluKCBwb2ludCApO1xyXG5cdFx0dGhpcy5tYXgubWF4KCBwb2ludCApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGV4cGFuZEJ5VmVjdG9yKCB2ZWN0b3IgKSB7XHJcblxyXG5cdFx0dGhpcy5taW4uc3ViKCB2ZWN0b3IgKTtcclxuXHRcdHRoaXMubWF4LmFkZCggdmVjdG9yICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0ZXhwYW5kQnlTY2FsYXIoIHNjYWxhciApIHtcclxuXHJcblx0XHR0aGlzLm1pbi5hZGRTY2FsYXIoIC0gc2NhbGFyICk7XHJcblx0XHR0aGlzLm1heC5hZGRTY2FsYXIoIHNjYWxhciApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGNvbnRhaW5zUG9pbnQoIHBvaW50ICkge1xyXG5cclxuXHRcdHJldHVybiBwb2ludC54IDwgdGhpcy5taW4ueCB8fCBwb2ludC54ID4gdGhpcy5tYXgueCB8fFxyXG5cdFx0XHRwb2ludC55IDwgdGhpcy5taW4ueSB8fCBwb2ludC55ID4gdGhpcy5tYXgueSA/IGZhbHNlIDogdHJ1ZTtcclxuXHJcblx0fVxyXG5cclxuXHRjb250YWluc0JveCggYm94ICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLm1pbi54IDw9IGJveC5taW4ueCAmJiBib3gubWF4LnggPD0gdGhpcy5tYXgueCAmJlxyXG5cdFx0XHR0aGlzLm1pbi55IDw9IGJveC5taW4ueSAmJiBib3gubWF4LnkgPD0gdGhpcy5tYXgueTtcclxuXHJcblx0fVxyXG5cclxuXHRnZXRQYXJhbWV0ZXIoIHBvaW50LCB0YXJnZXQgKSB7XHJcblxyXG5cdFx0Ly8gVGhpcyBjYW4gcG90ZW50aWFsbHkgaGF2ZSBhIGRpdmlkZSBieSB6ZXJvIGlmIHRoZSBib3hcclxuXHRcdC8vIGhhcyBhIHNpemUgZGltZW5zaW9uIG9mIDAuXHJcblxyXG5cdFx0cmV0dXJuIHRhcmdldC5zZXQoXHJcblx0XHRcdCggcG9pbnQueCAtIHRoaXMubWluLnggKSAvICggdGhpcy5tYXgueCAtIHRoaXMubWluLnggKSxcclxuXHRcdFx0KCBwb2ludC55IC0gdGhpcy5taW4ueSApIC8gKCB0aGlzLm1heC55IC0gdGhpcy5taW4ueSApXHJcblx0XHQpO1xyXG5cclxuXHR9XHJcblxyXG5cdGludGVyc2VjdHNCb3goIGJveCApIHtcclxuXHJcblx0XHQvLyB1c2luZyA0IHNwbGl0dGluZyBwbGFuZXMgdG8gcnVsZSBvdXQgaW50ZXJzZWN0aW9uc1xyXG5cclxuXHRcdHJldHVybiBib3gubWF4LnggPCB0aGlzLm1pbi54IHx8IGJveC5taW4ueCA+IHRoaXMubWF4LnggfHxcclxuXHRcdFx0Ym94Lm1heC55IDwgdGhpcy5taW4ueSB8fCBib3gubWluLnkgPiB0aGlzLm1heC55ID8gZmFsc2UgOiB0cnVlO1xyXG5cclxuXHR9XHJcblxyXG5cdGNsYW1wUG9pbnQoIHBvaW50LCB0YXJnZXQgKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRhcmdldC5jb3B5KCBwb2ludCApLmNsYW1wKCB0aGlzLm1pbiwgdGhpcy5tYXggKTtcclxuXHJcblx0fVxyXG5cclxuXHRkaXN0YW5jZVRvUG9pbnQoIHBvaW50ICkge1xyXG5cclxuXHRcdHJldHVybiB0aGlzLmNsYW1wUG9pbnQoIHBvaW50LCBfdmVjdG9yICkuZGlzdGFuY2VUbyggcG9pbnQgKTtcclxuXHJcblx0fVxyXG5cclxuXHRpbnRlcnNlY3QoIGJveCApIHtcclxuXHJcblx0XHR0aGlzLm1pbi5tYXgoIGJveC5taW4gKTtcclxuXHRcdHRoaXMubWF4Lm1pbiggYm94Lm1heCApO1xyXG5cclxuXHRcdGlmICggdGhpcy5pc0VtcHR5KCkgKSB0aGlzLm1ha2VFbXB0eSgpO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdHVuaW9uKCBib3ggKSB7XHJcblxyXG5cdFx0dGhpcy5taW4ubWluKCBib3gubWluICk7XHJcblx0XHR0aGlzLm1heC5tYXgoIGJveC5tYXggKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHR0cmFuc2xhdGUoIG9mZnNldCApIHtcclxuXHJcblx0XHR0aGlzLm1pbi5hZGQoIG9mZnNldCApO1xyXG5cdFx0dGhpcy5tYXguYWRkKCBvZmZzZXQgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRlcXVhbHMoIGJveCApIHtcclxuXHJcblx0XHRyZXR1cm4gYm94Lm1pbi5lcXVhbHMoIHRoaXMubWluICkgJiYgYm94Lm1heC5lcXVhbHMoIHRoaXMubWF4ICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IEJveDIgfTtcclxuIiwiaW1wb3J0IHsgVmVjdG9yMyB9IGZyb20gJy4vVmVjdG9yMy5qcyc7XHJcbmltcG9ydCAqIGFzIE1hdGhVdGlscyBmcm9tICcuL01hdGhVdGlscy5qcyc7XHJcblxyXG5jb25zdCBfc3RhcnRQID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5jb25zdCBfc3RhcnRFbmQgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XHJcblxyXG5jbGFzcyBMaW5lMyB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBzdGFydCA9IG5ldyBWZWN0b3IzKCksIGVuZCA9IG5ldyBWZWN0b3IzKCkgKSB7XHJcblxyXG5cdFx0dGhpcy5zdGFydCA9IHN0YXJ0O1xyXG5cdFx0dGhpcy5lbmQgPSBlbmQ7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0KCBzdGFydCwgZW5kICkge1xyXG5cclxuXHRcdHRoaXMuc3RhcnQuY29weSggc3RhcnQgKTtcclxuXHRcdHRoaXMuZW5kLmNvcHkoIGVuZCApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGNvcHkoIGxpbmUgKSB7XHJcblxyXG5cdFx0dGhpcy5zdGFydC5jb3B5KCBsaW5lLnN0YXJ0ICk7XHJcblx0XHR0aGlzLmVuZC5jb3B5KCBsaW5lLmVuZCApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGdldENlbnRlciggdGFyZ2V0ICkge1xyXG5cclxuXHRcdHJldHVybiB0YXJnZXQuYWRkVmVjdG9ycyggdGhpcy5zdGFydCwgdGhpcy5lbmQgKS5tdWx0aXBseVNjYWxhciggMC41ICk7XHJcblxyXG5cdH1cclxuXHJcblx0ZGVsdGEoIHRhcmdldCApIHtcclxuXHJcblx0XHRyZXR1cm4gdGFyZ2V0LnN1YlZlY3RvcnMoIHRoaXMuZW5kLCB0aGlzLnN0YXJ0ICk7XHJcblxyXG5cdH1cclxuXHJcblx0ZGlzdGFuY2VTcSgpIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5zdGFydC5kaXN0YW5jZVRvU3F1YXJlZCggdGhpcy5lbmQgKTtcclxuXHJcblx0fVxyXG5cclxuXHRkaXN0YW5jZSgpIHtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5zdGFydC5kaXN0YW5jZVRvKCB0aGlzLmVuZCApO1xyXG5cclxuXHR9XHJcblxyXG5cdGF0KCB0LCB0YXJnZXQgKSB7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuZGVsdGEoIHRhcmdldCApLm11bHRpcGx5U2NhbGFyKCB0ICkuYWRkKCB0aGlzLnN0YXJ0ICk7XHJcblxyXG5cdH1cclxuXHJcblx0Y2xvc2VzdFBvaW50VG9Qb2ludFBhcmFtZXRlciggcG9pbnQsIGNsYW1wVG9MaW5lICkge1xyXG5cclxuXHRcdF9zdGFydFAuc3ViVmVjdG9ycyggcG9pbnQsIHRoaXMuc3RhcnQgKTtcclxuXHRcdF9zdGFydEVuZC5zdWJWZWN0b3JzKCB0aGlzLmVuZCwgdGhpcy5zdGFydCApO1xyXG5cclxuXHRcdGNvbnN0IHN0YXJ0RW5kMiA9IF9zdGFydEVuZC5kb3QoIF9zdGFydEVuZCApO1xyXG5cdFx0Y29uc3Qgc3RhcnRFbmRfc3RhcnRQID0gX3N0YXJ0RW5kLmRvdCggX3N0YXJ0UCApO1xyXG5cclxuXHRcdGxldCB0ID0gc3RhcnRFbmRfc3RhcnRQIC8gc3RhcnRFbmQyO1xyXG5cclxuXHRcdGlmICggY2xhbXBUb0xpbmUgKSB7XHJcblxyXG5cdFx0XHR0ID0gTWF0aFV0aWxzLmNsYW1wKCB0LCAwLCAxICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0O1xyXG5cclxuXHR9XHJcblxyXG5cdGNsb3Nlc3RQb2ludFRvUG9pbnQoIHBvaW50LCBjbGFtcFRvTGluZSwgdGFyZ2V0ICkge1xyXG5cclxuXHRcdGNvbnN0IHQgPSB0aGlzLmNsb3Nlc3RQb2ludFRvUG9pbnRQYXJhbWV0ZXIoIHBvaW50LCBjbGFtcFRvTGluZSApO1xyXG5cclxuXHRcdHJldHVybiB0aGlzLmRlbHRhKCB0YXJnZXQgKS5tdWx0aXBseVNjYWxhciggdCApLmFkZCggdGhpcy5zdGFydCApO1xyXG5cclxuXHR9XHJcblxyXG5cdGFwcGx5TWF0cml4NCggbWF0cml4ICkge1xyXG5cclxuXHRcdHRoaXMuc3RhcnQuYXBwbHlNYXRyaXg0KCBtYXRyaXggKTtcclxuXHRcdHRoaXMuZW5kLmFwcGx5TWF0cml4NCggbWF0cml4ICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0ZXF1YWxzKCBsaW5lICkge1xyXG5cclxuXHRcdHJldHVybiBsaW5lLnN0YXJ0LmVxdWFscyggdGhpcy5zdGFydCApICYmIGxpbmUuZW5kLmVxdWFscyggdGhpcy5lbmQgKTtcclxuXHJcblx0fVxyXG5cclxuXHRjbG9uZSgpIHtcclxuXHJcblx0XHRyZXR1cm4gbmV3IHRoaXMuY29uc3RydWN0b3IoKS5jb3B5KCB0aGlzICk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IExpbmUzIH07XHJcbiIsImltcG9ydCB7IFZlY3RvcjMgfSBmcm9tICcuLi9tYXRoL1ZlY3RvcjMuanMnO1xyXG5pbXBvcnQgeyBPYmplY3QzRCB9IGZyb20gJy4uL2NvcmUvT2JqZWN0M0QuanMnO1xyXG5pbXBvcnQgeyBMaW5lU2VnbWVudHMgfSBmcm9tICcuLi9vYmplY3RzL0xpbmVTZWdtZW50cy5qcyc7XHJcbmltcG9ydCB7IExpbmVCYXNpY01hdGVyaWFsIH0gZnJvbSAnLi4vbWF0ZXJpYWxzL0xpbmVCYXNpY01hdGVyaWFsLmpzJztcclxuaW1wb3J0IHsgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSB9IGZyb20gJy4uL2NvcmUvQnVmZmVyQXR0cmlidXRlLmpzJztcclxuaW1wb3J0IHsgQnVmZmVyR2VvbWV0cnkgfSBmcm9tICcuLi9jb3JlL0J1ZmZlckdlb21ldHJ5LmpzJztcclxuXHJcbmNvbnN0IF92ZWN0b3IgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XHJcblxyXG5jbGFzcyBTcG90TGlnaHRIZWxwZXIgZXh0ZW5kcyBPYmplY3QzRCB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBsaWdodCwgY29sb3IgKSB7XHJcblxyXG5cdFx0c3VwZXIoKTtcclxuXHJcblx0XHR0aGlzLmxpZ2h0ID0gbGlnaHQ7XHJcblxyXG5cdFx0dGhpcy5tYXRyaXggPSBsaWdodC5tYXRyaXhXb3JsZDtcclxuXHRcdHRoaXMubWF0cml4QXV0b1VwZGF0ZSA9IGZhbHNlO1xyXG5cclxuXHRcdHRoaXMuY29sb3IgPSBjb2xvcjtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSAnU3BvdExpZ2h0SGVscGVyJztcclxuXHJcblx0XHRjb25zdCBnZW9tZXRyeSA9IG5ldyBCdWZmZXJHZW9tZXRyeSgpO1xyXG5cclxuXHRcdGNvbnN0IHBvc2l0aW9ucyA9IFtcclxuXHRcdFx0MCwgMCwgMCwgXHQwLCAwLCAxLFxyXG5cdFx0XHQwLCAwLCAwLCBcdDEsIDAsIDEsXHJcblx0XHRcdDAsIDAsIDAsXHQtIDEsIDAsIDEsXHJcblx0XHRcdDAsIDAsIDAsIFx0MCwgMSwgMSxcclxuXHRcdFx0MCwgMCwgMCwgXHQwLCAtIDEsIDFcclxuXHRcdF07XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBqID0gMSwgbCA9IDMyOyBpIDwgbDsgaSArKywgaiArKyApIHtcclxuXHJcblx0XHRcdGNvbnN0IHAxID0gKCBpIC8gbCApICogTWF0aC5QSSAqIDI7XHJcblx0XHRcdGNvbnN0IHAyID0gKCBqIC8gbCApICogTWF0aC5QSSAqIDI7XHJcblxyXG5cdFx0XHRwb3NpdGlvbnMucHVzaChcclxuXHRcdFx0XHRNYXRoLmNvcyggcDEgKSwgTWF0aC5zaW4oIHAxICksIDEsXHJcblx0XHRcdFx0TWF0aC5jb3MoIHAyICksIE1hdGguc2luKCBwMiApLCAxXHJcblx0XHRcdCk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGdlb21ldHJ5LnNldEF0dHJpYnV0ZSggJ3Bvc2l0aW9uJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIHBvc2l0aW9ucywgMyApICk7XHJcblxyXG5cdFx0Y29uc3QgbWF0ZXJpYWwgPSBuZXcgTGluZUJhc2ljTWF0ZXJpYWwoIHsgZm9nOiBmYWxzZSwgdG9uZU1hcHBlZDogZmFsc2UgfSApO1xyXG5cclxuXHRcdHRoaXMuY29uZSA9IG5ldyBMaW5lU2VnbWVudHMoIGdlb21ldHJ5LCBtYXRlcmlhbCApO1xyXG5cdFx0dGhpcy5hZGQoIHRoaXMuY29uZSApO1xyXG5cclxuXHRcdHRoaXMudXBkYXRlKCk7XHJcblxyXG5cdH1cclxuXHJcblx0ZGlzcG9zZSgpIHtcclxuXHJcblx0XHR0aGlzLmNvbmUuZ2VvbWV0cnkuZGlzcG9zZSgpO1xyXG5cdFx0dGhpcy5jb25lLm1hdGVyaWFsLmRpc3Bvc2UoKTtcclxuXHJcblx0fVxyXG5cclxuXHR1cGRhdGUoKSB7XHJcblxyXG5cdFx0dGhpcy5saWdodC51cGRhdGVXb3JsZE1hdHJpeCggdHJ1ZSwgZmFsc2UgKTtcclxuXHRcdHRoaXMubGlnaHQudGFyZ2V0LnVwZGF0ZVdvcmxkTWF0cml4KCB0cnVlLCBmYWxzZSApO1xyXG5cclxuXHRcdGNvbnN0IGNvbmVMZW5ndGggPSB0aGlzLmxpZ2h0LmRpc3RhbmNlID8gdGhpcy5saWdodC5kaXN0YW5jZSA6IDEwMDA7XHJcblx0XHRjb25zdCBjb25lV2lkdGggPSBjb25lTGVuZ3RoICogTWF0aC50YW4oIHRoaXMubGlnaHQuYW5nbGUgKTtcclxuXHJcblx0XHR0aGlzLmNvbmUuc2NhbGUuc2V0KCBjb25lV2lkdGgsIGNvbmVXaWR0aCwgY29uZUxlbmd0aCApO1xyXG5cclxuXHRcdF92ZWN0b3Iuc2V0RnJvbU1hdHJpeFBvc2l0aW9uKCB0aGlzLmxpZ2h0LnRhcmdldC5tYXRyaXhXb3JsZCApO1xyXG5cclxuXHRcdHRoaXMuY29uZS5sb29rQXQoIF92ZWN0b3IgKTtcclxuXHJcblx0XHRpZiAoIHRoaXMuY29sb3IgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdHRoaXMuY29uZS5tYXRlcmlhbC5jb2xvci5zZXQoIHRoaXMuY29sb3IgKTtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0dGhpcy5jb25lLm1hdGVyaWFsLmNvbG9yLmNvcHkoIHRoaXMubGlnaHQuY29sb3IgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcblxyXG5leHBvcnQgeyBTcG90TGlnaHRIZWxwZXIgfTtcclxuIiwiaW1wb3J0IHsgTGluZVNlZ21lbnRzIH0gZnJvbSAnLi4vb2JqZWN0cy9MaW5lU2VnbWVudHMuanMnO1xyXG5pbXBvcnQgeyBNYXRyaXg0IH0gZnJvbSAnLi4vbWF0aC9NYXRyaXg0LmpzJztcclxuaW1wb3J0IHsgTGluZUJhc2ljTWF0ZXJpYWwgfSBmcm9tICcuLi9tYXRlcmlhbHMvTGluZUJhc2ljTWF0ZXJpYWwuanMnO1xyXG5pbXBvcnQgeyBDb2xvciB9IGZyb20gJy4uL21hdGgvQ29sb3IuanMnO1xyXG5pbXBvcnQgeyBWZWN0b3IzIH0gZnJvbSAnLi4vbWF0aC9WZWN0b3IzLmpzJztcclxuaW1wb3J0IHsgQnVmZmVyR2VvbWV0cnkgfSBmcm9tICcuLi9jb3JlL0J1ZmZlckdlb21ldHJ5LmpzJztcclxuaW1wb3J0IHsgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSB9IGZyb20gJy4uL2NvcmUvQnVmZmVyQXR0cmlidXRlLmpzJztcclxuXHJcbmNvbnN0IF92ZWN0b3IgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XHJcbmNvbnN0IF9ib25lTWF0cml4ID0gLypAX19QVVJFX18qLyBuZXcgTWF0cml4NCgpO1xyXG5jb25zdCBfbWF0cml4V29ybGRJbnYgPSAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXg0KCk7XHJcblxyXG5cclxuY2xhc3MgU2tlbGV0b25IZWxwZXIgZXh0ZW5kcyBMaW5lU2VnbWVudHMge1xyXG5cclxuXHRjb25zdHJ1Y3Rvciggb2JqZWN0ICkge1xyXG5cclxuXHRcdGNvbnN0IGJvbmVzID0gZ2V0Qm9uZUxpc3QoIG9iamVjdCApO1xyXG5cclxuXHRcdGNvbnN0IGdlb21ldHJ5ID0gbmV3IEJ1ZmZlckdlb21ldHJ5KCk7XHJcblxyXG5cdFx0Y29uc3QgdmVydGljZXMgPSBbXTtcclxuXHRcdGNvbnN0IGNvbG9ycyA9IFtdO1xyXG5cclxuXHRcdGNvbnN0IGNvbG9yMSA9IG5ldyBDb2xvciggMCwgMCwgMSApO1xyXG5cdFx0Y29uc3QgY29sb3IyID0gbmV3IENvbG9yKCAwLCAxLCAwICk7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgYm9uZXMubGVuZ3RoOyBpICsrICkge1xyXG5cclxuXHRcdFx0Y29uc3QgYm9uZSA9IGJvbmVzWyBpIF07XHJcblxyXG5cdFx0XHRpZiAoIGJvbmUucGFyZW50ICYmIGJvbmUucGFyZW50LmlzQm9uZSApIHtcclxuXHJcblx0XHRcdFx0dmVydGljZXMucHVzaCggMCwgMCwgMCApO1xyXG5cdFx0XHRcdHZlcnRpY2VzLnB1c2goIDAsIDAsIDAgKTtcclxuXHRcdFx0XHRjb2xvcnMucHVzaCggY29sb3IxLnIsIGNvbG9yMS5nLCBjb2xvcjEuYiApO1xyXG5cdFx0XHRcdGNvbG9ycy5wdXNoKCBjb2xvcjIuciwgY29sb3IyLmcsIGNvbG9yMi5iICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGdlb21ldHJ5LnNldEF0dHJpYnV0ZSggJ3Bvc2l0aW9uJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIHZlcnRpY2VzLCAzICkgKTtcclxuXHRcdGdlb21ldHJ5LnNldEF0dHJpYnV0ZSggJ2NvbG9yJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIGNvbG9ycywgMyApICk7XHJcblxyXG5cdFx0Y29uc3QgbWF0ZXJpYWwgPSBuZXcgTGluZUJhc2ljTWF0ZXJpYWwoIHsgdmVydGV4Q29sb3JzOiB0cnVlLCBkZXB0aFRlc3Q6IGZhbHNlLCBkZXB0aFdyaXRlOiBmYWxzZSwgdG9uZU1hcHBlZDogZmFsc2UsIHRyYW5zcGFyZW50OiB0cnVlIH0gKTtcclxuXHJcblx0XHRzdXBlciggZ2VvbWV0cnksIG1hdGVyaWFsICk7XHJcblxyXG5cdFx0dGhpcy5pc1NrZWxldG9uSGVscGVyID0gdHJ1ZTtcclxuXHJcblx0XHR0aGlzLnR5cGUgPSAnU2tlbGV0b25IZWxwZXInO1xyXG5cclxuXHRcdHRoaXMucm9vdCA9IG9iamVjdDtcclxuXHRcdHRoaXMuYm9uZXMgPSBib25lcztcclxuXHJcblx0XHR0aGlzLm1hdHJpeCA9IG9iamVjdC5tYXRyaXhXb3JsZDtcclxuXHRcdHRoaXMubWF0cml4QXV0b1VwZGF0ZSA9IGZhbHNlO1xyXG5cclxuXHR9XHJcblxyXG5cdHVwZGF0ZU1hdHJpeFdvcmxkKCBmb3JjZSApIHtcclxuXHJcblx0XHRjb25zdCBib25lcyA9IHRoaXMuYm9uZXM7XHJcblxyXG5cdFx0Y29uc3QgZ2VvbWV0cnkgPSB0aGlzLmdlb21ldHJ5O1xyXG5cdFx0Y29uc3QgcG9zaXRpb24gPSBnZW9tZXRyeS5nZXRBdHRyaWJ1dGUoICdwb3NpdGlvbicgKTtcclxuXHJcblx0XHRfbWF0cml4V29ybGRJbnYuY29weSggdGhpcy5yb290Lm1hdHJpeFdvcmxkICkuaW52ZXJ0KCk7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBqID0gMDsgaSA8IGJvbmVzLmxlbmd0aDsgaSArKyApIHtcclxuXHJcblx0XHRcdGNvbnN0IGJvbmUgPSBib25lc1sgaSBdO1xyXG5cclxuXHRcdFx0aWYgKCBib25lLnBhcmVudCAmJiBib25lLnBhcmVudC5pc0JvbmUgKSB7XHJcblxyXG5cdFx0XHRcdF9ib25lTWF0cml4Lm11bHRpcGx5TWF0cmljZXMoIF9tYXRyaXhXb3JsZEludiwgYm9uZS5tYXRyaXhXb3JsZCApO1xyXG5cdFx0XHRcdF92ZWN0b3Iuc2V0RnJvbU1hdHJpeFBvc2l0aW9uKCBfYm9uZU1hdHJpeCApO1xyXG5cdFx0XHRcdHBvc2l0aW9uLnNldFhZWiggaiwgX3ZlY3Rvci54LCBfdmVjdG9yLnksIF92ZWN0b3IueiApO1xyXG5cclxuXHRcdFx0XHRfYm9uZU1hdHJpeC5tdWx0aXBseU1hdHJpY2VzKCBfbWF0cml4V29ybGRJbnYsIGJvbmUucGFyZW50Lm1hdHJpeFdvcmxkICk7XHJcblx0XHRcdFx0X3ZlY3Rvci5zZXRGcm9tTWF0cml4UG9zaXRpb24oIF9ib25lTWF0cml4ICk7XHJcblx0XHRcdFx0cG9zaXRpb24uc2V0WFlaKCBqICsgMSwgX3ZlY3Rvci54LCBfdmVjdG9yLnksIF92ZWN0b3IueiApO1xyXG5cclxuXHRcdFx0XHRqICs9IDI7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGdlb21ldHJ5LmdldEF0dHJpYnV0ZSggJ3Bvc2l0aW9uJyApLm5lZWRzVXBkYXRlID0gdHJ1ZTtcclxuXHJcblx0XHRzdXBlci51cGRhdGVNYXRyaXhXb3JsZCggZm9yY2UgKTtcclxuXHJcblx0fVxyXG5cclxuXHRkaXNwb3NlKCkge1xyXG5cclxuXHRcdHRoaXMuZ2VvbWV0cnkuZGlzcG9zZSgpO1xyXG5cdFx0dGhpcy5tYXRlcmlhbC5kaXNwb3NlKCk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcblxyXG5mdW5jdGlvbiBnZXRCb25lTGlzdCggb2JqZWN0ICkge1xyXG5cclxuXHRjb25zdCBib25lTGlzdCA9IFtdO1xyXG5cclxuXHRpZiAoIG9iamVjdC5pc0JvbmUgPT09IHRydWUgKSB7XHJcblxyXG5cdFx0Ym9uZUxpc3QucHVzaCggb2JqZWN0ICk7XHJcblxyXG5cdH1cclxuXHJcblx0Zm9yICggbGV0IGkgPSAwOyBpIDwgb2JqZWN0LmNoaWxkcmVuLmxlbmd0aDsgaSArKyApIHtcclxuXHJcblx0XHRib25lTGlzdC5wdXNoLmFwcGx5KCBib25lTGlzdCwgZ2V0Qm9uZUxpc3QoIG9iamVjdC5jaGlsZHJlblsgaSBdICkgKTtcclxuXHJcblx0fVxyXG5cclxuXHRyZXR1cm4gYm9uZUxpc3Q7XHJcblxyXG59XHJcblxyXG5cclxuZXhwb3J0IHsgU2tlbGV0b25IZWxwZXIgfTtcclxuIiwiaW1wb3J0IHsgTWVzaCB9IGZyb20gJy4uL29iamVjdHMvTWVzaC5qcyc7XHJcbmltcG9ydCB7IE1lc2hCYXNpY01hdGVyaWFsIH0gZnJvbSAnLi4vbWF0ZXJpYWxzL01lc2hCYXNpY01hdGVyaWFsLmpzJztcclxuaW1wb3J0IHsgU3BoZXJlR2VvbWV0cnkgfSBmcm9tICcuLi9nZW9tZXRyaWVzL1NwaGVyZUdlb21ldHJ5LmpzJztcclxuXHJcbmNsYXNzIFBvaW50TGlnaHRIZWxwZXIgZXh0ZW5kcyBNZXNoIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIGxpZ2h0LCBzcGhlcmVTaXplLCBjb2xvciApIHtcclxuXHJcblx0XHRjb25zdCBnZW9tZXRyeSA9IG5ldyBTcGhlcmVHZW9tZXRyeSggc3BoZXJlU2l6ZSwgNCwgMiApO1xyXG5cdFx0Y29uc3QgbWF0ZXJpYWwgPSBuZXcgTWVzaEJhc2ljTWF0ZXJpYWwoIHsgd2lyZWZyYW1lOiB0cnVlLCBmb2c6IGZhbHNlLCB0b25lTWFwcGVkOiBmYWxzZSB9ICk7XHJcblxyXG5cdFx0c3VwZXIoIGdlb21ldHJ5LCBtYXRlcmlhbCApO1xyXG5cclxuXHRcdHRoaXMubGlnaHQgPSBsaWdodDtcclxuXHJcblx0XHR0aGlzLmNvbG9yID0gY29sb3I7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ1BvaW50TGlnaHRIZWxwZXInO1xyXG5cclxuXHRcdHRoaXMubWF0cml4ID0gdGhpcy5saWdodC5tYXRyaXhXb3JsZDtcclxuXHRcdHRoaXMubWF0cml4QXV0b1VwZGF0ZSA9IGZhbHNlO1xyXG5cclxuXHRcdHRoaXMudXBkYXRlKCk7XHJcblxyXG5cclxuXHRcdC8qXHJcblx0Ly8gVE9ETzogZGVsZXRlIHRoaXMgY29tbWVudD9cclxuXHRjb25zdCBkaXN0YW5jZUdlb21ldHJ5ID0gbmV3IFRIUkVFLkljb3NhaGVkcm9uR2VvbWV0cnkoIDEsIDIgKTtcclxuXHRjb25zdCBkaXN0YW5jZU1hdGVyaWFsID0gbmV3IFRIUkVFLk1lc2hCYXNpY01hdGVyaWFsKCB7IGNvbG9yOiBoZXhDb2xvciwgZm9nOiBmYWxzZSwgd2lyZWZyYW1lOiB0cnVlLCBvcGFjaXR5OiAwLjEsIHRyYW5zcGFyZW50OiB0cnVlIH0gKTtcclxuXHJcblx0dGhpcy5saWdodFNwaGVyZSA9IG5ldyBUSFJFRS5NZXNoKCBidWxiR2VvbWV0cnksIGJ1bGJNYXRlcmlhbCApO1xyXG5cdHRoaXMubGlnaHREaXN0YW5jZSA9IG5ldyBUSFJFRS5NZXNoKCBkaXN0YW5jZUdlb21ldHJ5LCBkaXN0YW5jZU1hdGVyaWFsICk7XHJcblxyXG5cdGNvbnN0IGQgPSBsaWdodC5kaXN0YW5jZTtcclxuXHJcblx0aWYgKCBkID09PSAwLjAgKSB7XHJcblxyXG5cdFx0dGhpcy5saWdodERpc3RhbmNlLnZpc2libGUgPSBmYWxzZTtcclxuXHJcblx0fSBlbHNlIHtcclxuXHJcblx0XHR0aGlzLmxpZ2h0RGlzdGFuY2Uuc2NhbGUuc2V0KCBkLCBkLCBkICk7XHJcblxyXG5cdH1cclxuXHJcblx0dGhpcy5hZGQoIHRoaXMubGlnaHREaXN0YW5jZSApO1xyXG5cdCovXHJcblxyXG5cdH1cclxuXHJcblx0ZGlzcG9zZSgpIHtcclxuXHJcblx0XHR0aGlzLmdlb21ldHJ5LmRpc3Bvc2UoKTtcclxuXHRcdHRoaXMubWF0ZXJpYWwuZGlzcG9zZSgpO1xyXG5cclxuXHR9XHJcblxyXG5cdHVwZGF0ZSgpIHtcclxuXHJcblx0XHR0aGlzLmxpZ2h0LnVwZGF0ZVdvcmxkTWF0cml4KCB0cnVlLCBmYWxzZSApO1xyXG5cclxuXHRcdGlmICggdGhpcy5jb2xvciAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0dGhpcy5tYXRlcmlhbC5jb2xvci5zZXQoIHRoaXMuY29sb3IgKTtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0dGhpcy5tYXRlcmlhbC5jb2xvci5jb3B5KCB0aGlzLmxpZ2h0LmNvbG9yICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8qXHJcblx0XHRjb25zdCBkID0gdGhpcy5saWdodC5kaXN0YW5jZTtcclxuXHJcblx0XHRpZiAoIGQgPT09IDAuMCApIHtcclxuXHJcblx0XHRcdHRoaXMubGlnaHREaXN0YW5jZS52aXNpYmxlID0gZmFsc2U7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdHRoaXMubGlnaHREaXN0YW5jZS52aXNpYmxlID0gdHJ1ZTtcclxuXHRcdFx0dGhpcy5saWdodERpc3RhbmNlLnNjYWxlLnNldCggZCwgZCwgZCApO1xyXG5cclxuXHRcdH1cclxuXHRcdCovXHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcblxyXG5leHBvcnQgeyBQb2ludExpZ2h0SGVscGVyIH07XHJcbiIsImltcG9ydCB7IFZlY3RvcjMgfSBmcm9tICcuLi9tYXRoL1ZlY3RvcjMuanMnO1xyXG5pbXBvcnQgeyBDb2xvciB9IGZyb20gJy4uL21hdGgvQ29sb3IuanMnO1xyXG5pbXBvcnQgeyBPYmplY3QzRCB9IGZyb20gJy4uL2NvcmUvT2JqZWN0M0QuanMnO1xyXG5pbXBvcnQgeyBNZXNoIH0gZnJvbSAnLi4vb2JqZWN0cy9NZXNoLmpzJztcclxuaW1wb3J0IHsgTWVzaEJhc2ljTWF0ZXJpYWwgfSBmcm9tICcuLi9tYXRlcmlhbHMvTWVzaEJhc2ljTWF0ZXJpYWwuanMnO1xyXG5pbXBvcnQgeyBPY3RhaGVkcm9uR2VvbWV0cnkgfSBmcm9tICcuLi9nZW9tZXRyaWVzL09jdGFoZWRyb25HZW9tZXRyeS5qcyc7XHJcbmltcG9ydCB7IEJ1ZmZlckF0dHJpYnV0ZSB9IGZyb20gJy4uL2NvcmUvQnVmZmVyQXR0cmlidXRlLmpzJztcclxuXHJcbmNvbnN0IF92ZWN0b3IgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XHJcbmNvbnN0IF9jb2xvcjEgPSAvKkBfX1BVUkVfXyovIG5ldyBDb2xvcigpO1xyXG5jb25zdCBfY29sb3IyID0gLypAX19QVVJFX18qLyBuZXcgQ29sb3IoKTtcclxuXHJcbmNsYXNzIEhlbWlzcGhlcmVMaWdodEhlbHBlciBleHRlbmRzIE9iamVjdDNEIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIGxpZ2h0LCBzaXplLCBjb2xvciApIHtcclxuXHJcblx0XHRzdXBlcigpO1xyXG5cclxuXHRcdHRoaXMubGlnaHQgPSBsaWdodDtcclxuXHJcblx0XHR0aGlzLm1hdHJpeCA9IGxpZ2h0Lm1hdHJpeFdvcmxkO1xyXG5cdFx0dGhpcy5tYXRyaXhBdXRvVXBkYXRlID0gZmFsc2U7XHJcblxyXG5cdFx0dGhpcy5jb2xvciA9IGNvbG9yO1xyXG5cclxuXHRcdHRoaXMudHlwZSA9ICdIZW1pc3BoZXJlTGlnaHRIZWxwZXInO1xyXG5cclxuXHRcdGNvbnN0IGdlb21ldHJ5ID0gbmV3IE9jdGFoZWRyb25HZW9tZXRyeSggc2l6ZSApO1xyXG5cdFx0Z2VvbWV0cnkucm90YXRlWSggTWF0aC5QSSAqIDAuNSApO1xyXG5cclxuXHRcdHRoaXMubWF0ZXJpYWwgPSBuZXcgTWVzaEJhc2ljTWF0ZXJpYWwoIHsgd2lyZWZyYW1lOiB0cnVlLCBmb2c6IGZhbHNlLCB0b25lTWFwcGVkOiBmYWxzZSB9ICk7XHJcblx0XHRpZiAoIHRoaXMuY29sb3IgPT09IHVuZGVmaW5lZCApIHRoaXMubWF0ZXJpYWwudmVydGV4Q29sb3JzID0gdHJ1ZTtcclxuXHJcblx0XHRjb25zdCBwb3NpdGlvbiA9IGdlb21ldHJ5LmdldEF0dHJpYnV0ZSggJ3Bvc2l0aW9uJyApO1xyXG5cdFx0Y29uc3QgY29sb3JzID0gbmV3IEZsb2F0MzJBcnJheSggcG9zaXRpb24uY291bnQgKiAzICk7XHJcblxyXG5cdFx0Z2VvbWV0cnkuc2V0QXR0cmlidXRlKCAnY29sb3InLCBuZXcgQnVmZmVyQXR0cmlidXRlKCBjb2xvcnMsIDMgKSApO1xyXG5cclxuXHRcdHRoaXMuYWRkKCBuZXcgTWVzaCggZ2VvbWV0cnksIHRoaXMubWF0ZXJpYWwgKSApO1xyXG5cclxuXHRcdHRoaXMudXBkYXRlKCk7XHJcblxyXG5cdH1cclxuXHJcblx0ZGlzcG9zZSgpIHtcclxuXHJcblx0XHR0aGlzLmNoaWxkcmVuWyAwIF0uZ2VvbWV0cnkuZGlzcG9zZSgpO1xyXG5cdFx0dGhpcy5jaGlsZHJlblsgMCBdLm1hdGVyaWFsLmRpc3Bvc2UoKTtcclxuXHJcblx0fVxyXG5cclxuXHR1cGRhdGUoKSB7XHJcblxyXG5cdFx0Y29uc3QgbWVzaCA9IHRoaXMuY2hpbGRyZW5bIDAgXTtcclxuXHJcblx0XHRpZiAoIHRoaXMuY29sb3IgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdHRoaXMubWF0ZXJpYWwuY29sb3Iuc2V0KCB0aGlzLmNvbG9yICk7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdGNvbnN0IGNvbG9ycyA9IG1lc2guZ2VvbWV0cnkuZ2V0QXR0cmlidXRlKCAnY29sb3InICk7XHJcblxyXG5cdFx0XHRfY29sb3IxLmNvcHkoIHRoaXMubGlnaHQuY29sb3IgKTtcclxuXHRcdFx0X2NvbG9yMi5jb3B5KCB0aGlzLmxpZ2h0Lmdyb3VuZENvbG9yICk7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBjb2xvcnMuY291bnQ7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0XHRjb25zdCBjb2xvciA9ICggaSA8ICggbCAvIDIgKSApID8gX2NvbG9yMSA6IF9jb2xvcjI7XHJcblxyXG5cdFx0XHRcdGNvbG9ycy5zZXRYWVooIGksIGNvbG9yLnIsIGNvbG9yLmcsIGNvbG9yLmIgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGNvbG9ycy5uZWVkc1VwZGF0ZSA9IHRydWU7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMubGlnaHQudXBkYXRlV29ybGRNYXRyaXgoIHRydWUsIGZhbHNlICk7XHJcblxyXG5cdFx0bWVzaC5sb29rQXQoIF92ZWN0b3Iuc2V0RnJvbU1hdHJpeFBvc2l0aW9uKCB0aGlzLmxpZ2h0Lm1hdHJpeFdvcmxkICkubmVnYXRlKCkgKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuXHJcbmV4cG9ydCB7IEhlbWlzcGhlcmVMaWdodEhlbHBlciB9O1xyXG4iLCJpbXBvcnQgeyBMaW5lU2VnbWVudHMgfSBmcm9tICcuLi9vYmplY3RzL0xpbmVTZWdtZW50cy5qcyc7XHJcbmltcG9ydCB7IExpbmVCYXNpY01hdGVyaWFsIH0gZnJvbSAnLi4vbWF0ZXJpYWxzL0xpbmVCYXNpY01hdGVyaWFsLmpzJztcclxuaW1wb3J0IHsgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSB9IGZyb20gJy4uL2NvcmUvQnVmZmVyQXR0cmlidXRlLmpzJztcclxuaW1wb3J0IHsgQnVmZmVyR2VvbWV0cnkgfSBmcm9tICcuLi9jb3JlL0J1ZmZlckdlb21ldHJ5LmpzJztcclxuaW1wb3J0IHsgQ29sb3IgfSBmcm9tICcuLi9tYXRoL0NvbG9yLmpzJztcclxuXHJcbmNsYXNzIEdyaWRIZWxwZXIgZXh0ZW5kcyBMaW5lU2VnbWVudHMge1xyXG5cclxuXHRjb25zdHJ1Y3Rvciggc2l6ZSA9IDEwLCBkaXZpc2lvbnMgPSAxMCwgY29sb3IxID0gMHg0NDQ0NDQsIGNvbG9yMiA9IDB4ODg4ODg4ICkge1xyXG5cclxuXHRcdGNvbG9yMSA9IG5ldyBDb2xvciggY29sb3IxICk7XHJcblx0XHRjb2xvcjIgPSBuZXcgQ29sb3IoIGNvbG9yMiApO1xyXG5cclxuXHRcdGNvbnN0IGNlbnRlciA9IGRpdmlzaW9ucyAvIDI7XHJcblx0XHRjb25zdCBzdGVwID0gc2l6ZSAvIGRpdmlzaW9ucztcclxuXHRcdGNvbnN0IGhhbGZTaXplID0gc2l6ZSAvIDI7XHJcblxyXG5cdFx0Y29uc3QgdmVydGljZXMgPSBbXSwgY29sb3JzID0gW107XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBqID0gMCwgayA9IC0gaGFsZlNpemU7IGkgPD0gZGl2aXNpb25zOyBpICsrLCBrICs9IHN0ZXAgKSB7XHJcblxyXG5cdFx0XHR2ZXJ0aWNlcy5wdXNoKCAtIGhhbGZTaXplLCAwLCBrLCBoYWxmU2l6ZSwgMCwgayApO1xyXG5cdFx0XHR2ZXJ0aWNlcy5wdXNoKCBrLCAwLCAtIGhhbGZTaXplLCBrLCAwLCBoYWxmU2l6ZSApO1xyXG5cclxuXHRcdFx0Y29uc3QgY29sb3IgPSBpID09PSBjZW50ZXIgPyBjb2xvcjEgOiBjb2xvcjI7XHJcblxyXG5cdFx0XHRjb2xvci50b0FycmF5KCBjb2xvcnMsIGogKTsgaiArPSAzO1xyXG5cdFx0XHRjb2xvci50b0FycmF5KCBjb2xvcnMsIGogKTsgaiArPSAzO1xyXG5cdFx0XHRjb2xvci50b0FycmF5KCBjb2xvcnMsIGogKTsgaiArPSAzO1xyXG5cdFx0XHRjb2xvci50b0FycmF5KCBjb2xvcnMsIGogKTsgaiArPSAzO1xyXG5cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCBnZW9tZXRyeSA9IG5ldyBCdWZmZXJHZW9tZXRyeSgpO1xyXG5cdFx0Z2VvbWV0cnkuc2V0QXR0cmlidXRlKCAncG9zaXRpb24nLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggdmVydGljZXMsIDMgKSApO1xyXG5cdFx0Z2VvbWV0cnkuc2V0QXR0cmlidXRlKCAnY29sb3InLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggY29sb3JzLCAzICkgKTtcclxuXHJcblx0XHRjb25zdCBtYXRlcmlhbCA9IG5ldyBMaW5lQmFzaWNNYXRlcmlhbCggeyB2ZXJ0ZXhDb2xvcnM6IHRydWUsIHRvbmVNYXBwZWQ6IGZhbHNlIH0gKTtcclxuXHJcblx0XHRzdXBlciggZ2VvbWV0cnksIG1hdGVyaWFsICk7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ0dyaWRIZWxwZXInO1xyXG5cclxuXHR9XHJcblxyXG5cdGRpc3Bvc2UoKSB7XHJcblxyXG5cdFx0dGhpcy5nZW9tZXRyeS5kaXNwb3NlKCk7XHJcblx0XHR0aGlzLm1hdGVyaWFsLmRpc3Bvc2UoKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuXHJcbmV4cG9ydCB7IEdyaWRIZWxwZXIgfTtcclxuIiwiaW1wb3J0IHsgTGluZVNlZ21lbnRzIH0gZnJvbSAnLi4vb2JqZWN0cy9MaW5lU2VnbWVudHMuanMnO1xyXG5pbXBvcnQgeyBMaW5lQmFzaWNNYXRlcmlhbCB9IGZyb20gJy4uL21hdGVyaWFscy9MaW5lQmFzaWNNYXRlcmlhbC5qcyc7XHJcbmltcG9ydCB7IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUgfSBmcm9tICcuLi9jb3JlL0J1ZmZlckF0dHJpYnV0ZS5qcyc7XHJcbmltcG9ydCB7IEJ1ZmZlckdlb21ldHJ5IH0gZnJvbSAnLi4vY29yZS9CdWZmZXJHZW9tZXRyeS5qcyc7XHJcbmltcG9ydCB7IENvbG9yIH0gZnJvbSAnLi4vbWF0aC9Db2xvci5qcyc7XHJcblxyXG5jbGFzcyBQb2xhckdyaWRIZWxwZXIgZXh0ZW5kcyBMaW5lU2VnbWVudHMge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggcmFkaXVzID0gMTAsIHNlY3RvcnMgPSAxNiwgcmluZ3MgPSA4LCBkaXZpc2lvbnMgPSA2NCwgY29sb3IxID0gMHg0NDQ0NDQsIGNvbG9yMiA9IDB4ODg4ODg4ICkge1xyXG5cclxuXHRcdGNvbG9yMSA9IG5ldyBDb2xvciggY29sb3IxICk7XHJcblx0XHRjb2xvcjIgPSBuZXcgQ29sb3IoIGNvbG9yMiApO1xyXG5cclxuXHRcdGNvbnN0IHZlcnRpY2VzID0gW107XHJcblx0XHRjb25zdCBjb2xvcnMgPSBbXTtcclxuXHJcblx0XHQvLyBjcmVhdGUgdGhlIHNlY3RvcnNcclxuXHJcblx0XHRpZiAoIHNlY3RvcnMgPiAxICkge1xyXG5cclxuXHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgc2VjdG9yczsgaSArKyApIHtcclxuXHJcblx0XHRcdFx0Y29uc3QgdiA9ICggaSAvIHNlY3RvcnMgKSAqICggTWF0aC5QSSAqIDIgKTtcclxuXHJcblx0XHRcdFx0Y29uc3QgeCA9IE1hdGguc2luKCB2ICkgKiByYWRpdXM7XHJcblx0XHRcdFx0Y29uc3QgeiA9IE1hdGguY29zKCB2ICkgKiByYWRpdXM7XHJcblxyXG5cdFx0XHRcdHZlcnRpY2VzLnB1c2goIDAsIDAsIDAgKTtcclxuXHRcdFx0XHR2ZXJ0aWNlcy5wdXNoKCB4LCAwLCB6ICk7XHJcblxyXG5cdFx0XHRcdGNvbnN0IGNvbG9yID0gKCBpICYgMSApID8gY29sb3IxIDogY29sb3IyO1xyXG5cclxuXHRcdFx0XHRjb2xvcnMucHVzaCggY29sb3IuciwgY29sb3IuZywgY29sb3IuYiApO1xyXG5cdFx0XHRcdGNvbG9ycy5wdXNoKCBjb2xvci5yLCBjb2xvci5nLCBjb2xvci5iICk7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIGNyZWF0ZSB0aGUgcmluZ3NcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCByaW5nczsgaSArKyApIHtcclxuXHJcblx0XHRcdGNvbnN0IGNvbG9yID0gKCBpICYgMSApID8gY29sb3IxIDogY29sb3IyO1xyXG5cclxuXHRcdFx0Y29uc3QgciA9IHJhZGl1cyAtICggcmFkaXVzIC8gcmluZ3MgKiBpICk7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaiA9IDA7IGogPCBkaXZpc2lvbnM7IGogKysgKSB7XHJcblxyXG5cdFx0XHRcdC8vIGZpcnN0IHZlcnRleFxyXG5cclxuXHRcdFx0XHRsZXQgdiA9ICggaiAvIGRpdmlzaW9ucyApICogKCBNYXRoLlBJICogMiApO1xyXG5cclxuXHRcdFx0XHRsZXQgeCA9IE1hdGguc2luKCB2ICkgKiByO1xyXG5cdFx0XHRcdGxldCB6ID0gTWF0aC5jb3MoIHYgKSAqIHI7XHJcblxyXG5cdFx0XHRcdHZlcnRpY2VzLnB1c2goIHgsIDAsIHogKTtcclxuXHRcdFx0XHRjb2xvcnMucHVzaCggY29sb3IuciwgY29sb3IuZywgY29sb3IuYiApO1xyXG5cclxuXHRcdFx0XHQvLyBzZWNvbmQgdmVydGV4XHJcblxyXG5cdFx0XHRcdHYgPSAoICggaiArIDEgKSAvIGRpdmlzaW9ucyApICogKCBNYXRoLlBJICogMiApO1xyXG5cclxuXHRcdFx0XHR4ID0gTWF0aC5zaW4oIHYgKSAqIHI7XHJcblx0XHRcdFx0eiA9IE1hdGguY29zKCB2ICkgKiByO1xyXG5cclxuXHRcdFx0XHR2ZXJ0aWNlcy5wdXNoKCB4LCAwLCB6ICk7XHJcblx0XHRcdFx0Y29sb3JzLnB1c2goIGNvbG9yLnIsIGNvbG9yLmcsIGNvbG9yLmIgKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Y29uc3QgZ2VvbWV0cnkgPSBuZXcgQnVmZmVyR2VvbWV0cnkoKTtcclxuXHRcdGdlb21ldHJ5LnNldEF0dHJpYnV0ZSggJ3Bvc2l0aW9uJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIHZlcnRpY2VzLCAzICkgKTtcclxuXHRcdGdlb21ldHJ5LnNldEF0dHJpYnV0ZSggJ2NvbG9yJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIGNvbG9ycywgMyApICk7XHJcblxyXG5cdFx0Y29uc3QgbWF0ZXJpYWwgPSBuZXcgTGluZUJhc2ljTWF0ZXJpYWwoIHsgdmVydGV4Q29sb3JzOiB0cnVlLCB0b25lTWFwcGVkOiBmYWxzZSB9ICk7XHJcblxyXG5cdFx0c3VwZXIoIGdlb21ldHJ5LCBtYXRlcmlhbCApO1xyXG5cclxuXHRcdHRoaXMudHlwZSA9ICdQb2xhckdyaWRIZWxwZXInO1xyXG5cclxuXHR9XHJcblxyXG5cdGRpc3Bvc2UoKSB7XHJcblxyXG5cdFx0dGhpcy5nZW9tZXRyeS5kaXNwb3NlKCk7XHJcblx0XHR0aGlzLm1hdGVyaWFsLmRpc3Bvc2UoKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuXHJcbmV4cG9ydCB7IFBvbGFyR3JpZEhlbHBlciB9O1xyXG4iLCJpbXBvcnQgeyBWZWN0b3IzIH0gZnJvbSAnLi4vbWF0aC9WZWN0b3IzLmpzJztcclxuaW1wb3J0IHsgT2JqZWN0M0QgfSBmcm9tICcuLi9jb3JlL09iamVjdDNELmpzJztcclxuaW1wb3J0IHsgTGluZSB9IGZyb20gJy4uL29iamVjdHMvTGluZS5qcyc7XHJcbmltcG9ydCB7IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUgfSBmcm9tICcuLi9jb3JlL0J1ZmZlckF0dHJpYnV0ZS5qcyc7XHJcbmltcG9ydCB7IEJ1ZmZlckdlb21ldHJ5IH0gZnJvbSAnLi4vY29yZS9CdWZmZXJHZW9tZXRyeS5qcyc7XHJcbmltcG9ydCB7IExpbmVCYXNpY01hdGVyaWFsIH0gZnJvbSAnLi4vbWF0ZXJpYWxzL0xpbmVCYXNpY01hdGVyaWFsLmpzJztcclxuXHJcbmNvbnN0IF92MSA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuY29uc3QgX3YyID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5jb25zdCBfdjMgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XHJcblxyXG5jbGFzcyBEaXJlY3Rpb25hbExpZ2h0SGVscGVyIGV4dGVuZHMgT2JqZWN0M0Qge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggbGlnaHQsIHNpemUsIGNvbG9yICkge1xyXG5cclxuXHRcdHN1cGVyKCk7XHJcblxyXG5cdFx0dGhpcy5saWdodCA9IGxpZ2h0O1xyXG5cclxuXHRcdHRoaXMubWF0cml4ID0gbGlnaHQubWF0cml4V29ybGQ7XHJcblx0XHR0aGlzLm1hdHJpeEF1dG9VcGRhdGUgPSBmYWxzZTtcclxuXHJcblx0XHR0aGlzLmNvbG9yID0gY29sb3I7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ0RpcmVjdGlvbmFsTGlnaHRIZWxwZXInO1xyXG5cclxuXHRcdGlmICggc2l6ZSA9PT0gdW5kZWZpbmVkICkgc2l6ZSA9IDE7XHJcblxyXG5cdFx0bGV0IGdlb21ldHJ5ID0gbmV3IEJ1ZmZlckdlb21ldHJ5KCk7XHJcblx0XHRnZW9tZXRyeS5zZXRBdHRyaWJ1dGUoICdwb3NpdGlvbicsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCBbXHJcblx0XHRcdC0gc2l6ZSwgc2l6ZSwgMCxcclxuXHRcdFx0c2l6ZSwgc2l6ZSwgMCxcclxuXHRcdFx0c2l6ZSwgLSBzaXplLCAwLFxyXG5cdFx0XHQtIHNpemUsIC0gc2l6ZSwgMCxcclxuXHRcdFx0LSBzaXplLCBzaXplLCAwXHJcblx0XHRdLCAzICkgKTtcclxuXHJcblx0XHRjb25zdCBtYXRlcmlhbCA9IG5ldyBMaW5lQmFzaWNNYXRlcmlhbCggeyBmb2c6IGZhbHNlLCB0b25lTWFwcGVkOiBmYWxzZSB9ICk7XHJcblxyXG5cdFx0dGhpcy5saWdodFBsYW5lID0gbmV3IExpbmUoIGdlb21ldHJ5LCBtYXRlcmlhbCApO1xyXG5cdFx0dGhpcy5hZGQoIHRoaXMubGlnaHRQbGFuZSApO1xyXG5cclxuXHRcdGdlb21ldHJ5ID0gbmV3IEJ1ZmZlckdlb21ldHJ5KCk7XHJcblx0XHRnZW9tZXRyeS5zZXRBdHRyaWJ1dGUoICdwb3NpdGlvbicsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCBbIDAsIDAsIDAsIDAsIDAsIDEgXSwgMyApICk7XHJcblxyXG5cdFx0dGhpcy50YXJnZXRMaW5lID0gbmV3IExpbmUoIGdlb21ldHJ5LCBtYXRlcmlhbCApO1xyXG5cdFx0dGhpcy5hZGQoIHRoaXMudGFyZ2V0TGluZSApO1xyXG5cclxuXHRcdHRoaXMudXBkYXRlKCk7XHJcblxyXG5cdH1cclxuXHJcblx0ZGlzcG9zZSgpIHtcclxuXHJcblx0XHR0aGlzLmxpZ2h0UGxhbmUuZ2VvbWV0cnkuZGlzcG9zZSgpO1xyXG5cdFx0dGhpcy5saWdodFBsYW5lLm1hdGVyaWFsLmRpc3Bvc2UoKTtcclxuXHRcdHRoaXMudGFyZ2V0TGluZS5nZW9tZXRyeS5kaXNwb3NlKCk7XHJcblx0XHR0aGlzLnRhcmdldExpbmUubWF0ZXJpYWwuZGlzcG9zZSgpO1xyXG5cclxuXHR9XHJcblxyXG5cdHVwZGF0ZSgpIHtcclxuXHJcblx0XHR0aGlzLmxpZ2h0LnVwZGF0ZVdvcmxkTWF0cml4KCB0cnVlLCBmYWxzZSApO1xyXG5cdFx0dGhpcy5saWdodC50YXJnZXQudXBkYXRlV29ybGRNYXRyaXgoIHRydWUsIGZhbHNlICk7XHJcblxyXG5cdFx0X3YxLnNldEZyb21NYXRyaXhQb3NpdGlvbiggdGhpcy5saWdodC5tYXRyaXhXb3JsZCApO1xyXG5cdFx0X3YyLnNldEZyb21NYXRyaXhQb3NpdGlvbiggdGhpcy5saWdodC50YXJnZXQubWF0cml4V29ybGQgKTtcclxuXHRcdF92My5zdWJWZWN0b3JzKCBfdjIsIF92MSApO1xyXG5cclxuXHRcdHRoaXMubGlnaHRQbGFuZS5sb29rQXQoIF92MiApO1xyXG5cclxuXHRcdGlmICggdGhpcy5jb2xvciAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0dGhpcy5saWdodFBsYW5lLm1hdGVyaWFsLmNvbG9yLnNldCggdGhpcy5jb2xvciApO1xyXG5cdFx0XHR0aGlzLnRhcmdldExpbmUubWF0ZXJpYWwuY29sb3Iuc2V0KCB0aGlzLmNvbG9yICk7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdHRoaXMubGlnaHRQbGFuZS5tYXRlcmlhbC5jb2xvci5jb3B5KCB0aGlzLmxpZ2h0LmNvbG9yICk7XHJcblx0XHRcdHRoaXMudGFyZ2V0TGluZS5tYXRlcmlhbC5jb2xvci5jb3B5KCB0aGlzLmxpZ2h0LmNvbG9yICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMudGFyZ2V0TGluZS5sb29rQXQoIF92MiApO1xyXG5cdFx0dGhpcy50YXJnZXRMaW5lLnNjYWxlLnogPSBfdjMubGVuZ3RoKCk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcblxyXG5leHBvcnQgeyBEaXJlY3Rpb25hbExpZ2h0SGVscGVyIH07XHJcbiIsImltcG9ydCB7IENhbWVyYSB9IGZyb20gJy4uL2NhbWVyYXMvQ2FtZXJhLmpzJztcclxuaW1wb3J0IHsgVmVjdG9yMyB9IGZyb20gJy4uL21hdGgvVmVjdG9yMy5qcyc7XHJcbmltcG9ydCB7IExpbmVTZWdtZW50cyB9IGZyb20gJy4uL29iamVjdHMvTGluZVNlZ21lbnRzLmpzJztcclxuaW1wb3J0IHsgQ29sb3IgfSBmcm9tICcuLi9tYXRoL0NvbG9yLmpzJztcclxuaW1wb3J0IHsgTGluZUJhc2ljTWF0ZXJpYWwgfSBmcm9tICcuLi9tYXRlcmlhbHMvTGluZUJhc2ljTWF0ZXJpYWwuanMnO1xyXG5pbXBvcnQgeyBCdWZmZXJHZW9tZXRyeSB9IGZyb20gJy4uL2NvcmUvQnVmZmVyR2VvbWV0cnkuanMnO1xyXG5pbXBvcnQgeyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlIH0gZnJvbSAnLi4vY29yZS9CdWZmZXJBdHRyaWJ1dGUuanMnO1xyXG5cclxuY29uc3QgX3ZlY3RvciA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcclxuY29uc3QgX2NhbWVyYSA9IC8qQF9fUFVSRV9fKi8gbmV3IENhbWVyYSgpO1xyXG5cclxuLyoqXHJcbiAqXHQtIHNob3dzIGZydXN0dW0sIGxpbmUgb2Ygc2lnaHQgYW5kIHVwIG9mIHRoZSBjYW1lcmFcclxuICpcdC0gc3VpdGFibGUgZm9yIGZhc3QgdXBkYXRlc1xyXG4gKiBcdC0gYmFzZWQgb24gZnJ1c3R1bSB2aXN1YWxpemF0aW9uIGluIGxpZ2h0Z2wuanMgc2hhZG93bWFwIGV4YW1wbGVcclxuICpcdFx0aHR0cHM6Ly9naXRodWIuY29tL2V2YW53L2xpZ2h0Z2wuanMvYmxvYi9tYXN0ZXIvdGVzdHMvc2hhZG93bWFwLmh0bWxcclxuICovXHJcblxyXG5jbGFzcyBDYW1lcmFIZWxwZXIgZXh0ZW5kcyBMaW5lU2VnbWVudHMge1xyXG5cclxuXHRjb25zdHJ1Y3RvciggY2FtZXJhICkge1xyXG5cclxuXHRcdGNvbnN0IGdlb21ldHJ5ID0gbmV3IEJ1ZmZlckdlb21ldHJ5KCk7XHJcblx0XHRjb25zdCBtYXRlcmlhbCA9IG5ldyBMaW5lQmFzaWNNYXRlcmlhbCggeyBjb2xvcjogMHhmZmZmZmYsIHZlcnRleENvbG9yczogdHJ1ZSwgdG9uZU1hcHBlZDogZmFsc2UgfSApO1xyXG5cclxuXHRcdGNvbnN0IHZlcnRpY2VzID0gW107XHJcblx0XHRjb25zdCBjb2xvcnMgPSBbXTtcclxuXHJcblx0XHRjb25zdCBwb2ludE1hcCA9IHt9O1xyXG5cclxuXHRcdC8vIG5lYXJcclxuXHJcblx0XHRhZGRMaW5lKCAnbjEnLCAnbjInICk7XHJcblx0XHRhZGRMaW5lKCAnbjInLCAnbjQnICk7XHJcblx0XHRhZGRMaW5lKCAnbjQnLCAnbjMnICk7XHJcblx0XHRhZGRMaW5lKCAnbjMnLCAnbjEnICk7XHJcblxyXG5cdFx0Ly8gZmFyXHJcblxyXG5cdFx0YWRkTGluZSggJ2YxJywgJ2YyJyApO1xyXG5cdFx0YWRkTGluZSggJ2YyJywgJ2Y0JyApO1xyXG5cdFx0YWRkTGluZSggJ2Y0JywgJ2YzJyApO1xyXG5cdFx0YWRkTGluZSggJ2YzJywgJ2YxJyApO1xyXG5cclxuXHRcdC8vIHNpZGVzXHJcblxyXG5cdFx0YWRkTGluZSggJ24xJywgJ2YxJyApO1xyXG5cdFx0YWRkTGluZSggJ24yJywgJ2YyJyApO1xyXG5cdFx0YWRkTGluZSggJ24zJywgJ2YzJyApO1xyXG5cdFx0YWRkTGluZSggJ240JywgJ2Y0JyApO1xyXG5cclxuXHRcdC8vIGNvbmVcclxuXHJcblx0XHRhZGRMaW5lKCAncCcsICduMScgKTtcclxuXHRcdGFkZExpbmUoICdwJywgJ24yJyApO1xyXG5cdFx0YWRkTGluZSggJ3AnLCAnbjMnICk7XHJcblx0XHRhZGRMaW5lKCAncCcsICduNCcgKTtcclxuXHJcblx0XHQvLyB1cFxyXG5cclxuXHRcdGFkZExpbmUoICd1MScsICd1MicgKTtcclxuXHRcdGFkZExpbmUoICd1MicsICd1MycgKTtcclxuXHRcdGFkZExpbmUoICd1MycsICd1MScgKTtcclxuXHJcblx0XHQvLyB0YXJnZXRcclxuXHJcblx0XHRhZGRMaW5lKCAnYycsICd0JyApO1xyXG5cdFx0YWRkTGluZSggJ3AnLCAnYycgKTtcclxuXHJcblx0XHQvLyBjcm9zc1xyXG5cclxuXHRcdGFkZExpbmUoICdjbjEnLCAnY24yJyApO1xyXG5cdFx0YWRkTGluZSggJ2NuMycsICdjbjQnICk7XHJcblxyXG5cdFx0YWRkTGluZSggJ2NmMScsICdjZjInICk7XHJcblx0XHRhZGRMaW5lKCAnY2YzJywgJ2NmNCcgKTtcclxuXHJcblx0XHRmdW5jdGlvbiBhZGRMaW5lKCBhLCBiICkge1xyXG5cclxuXHRcdFx0YWRkUG9pbnQoIGEgKTtcclxuXHRcdFx0YWRkUG9pbnQoIGIgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0ZnVuY3Rpb24gYWRkUG9pbnQoIGlkICkge1xyXG5cclxuXHRcdFx0dmVydGljZXMucHVzaCggMCwgMCwgMCApO1xyXG5cdFx0XHRjb2xvcnMucHVzaCggMCwgMCwgMCApO1xyXG5cclxuXHRcdFx0aWYgKCBwb2ludE1hcFsgaWQgXSA9PT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdFx0XHRwb2ludE1hcFsgaWQgXSA9IFtdO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0cG9pbnRNYXBbIGlkIF0ucHVzaCggKCB2ZXJ0aWNlcy5sZW5ndGggLyAzICkgLSAxICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGdlb21ldHJ5LnNldEF0dHJpYnV0ZSggJ3Bvc2l0aW9uJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIHZlcnRpY2VzLCAzICkgKTtcclxuXHRcdGdlb21ldHJ5LnNldEF0dHJpYnV0ZSggJ2NvbG9yJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIGNvbG9ycywgMyApICk7XHJcblxyXG5cdFx0c3VwZXIoIGdlb21ldHJ5LCBtYXRlcmlhbCApO1xyXG5cclxuXHRcdHRoaXMudHlwZSA9ICdDYW1lcmFIZWxwZXInO1xyXG5cclxuXHRcdHRoaXMuY2FtZXJhID0gY2FtZXJhO1xyXG5cdFx0aWYgKCB0aGlzLmNhbWVyYS51cGRhdGVQcm9qZWN0aW9uTWF0cml4ICkgdGhpcy5jYW1lcmEudXBkYXRlUHJvamVjdGlvbk1hdHJpeCgpO1xyXG5cclxuXHRcdHRoaXMubWF0cml4ID0gY2FtZXJhLm1hdHJpeFdvcmxkO1xyXG5cdFx0dGhpcy5tYXRyaXhBdXRvVXBkYXRlID0gZmFsc2U7XHJcblxyXG5cdFx0dGhpcy5wb2ludE1hcCA9IHBvaW50TWFwO1xyXG5cclxuXHRcdHRoaXMudXBkYXRlKCk7XHJcblxyXG5cdFx0Ly8gY29sb3JzXHJcblxyXG5cdFx0Y29uc3QgY29sb3JGcnVzdHVtID0gbmV3IENvbG9yKCAweGZmYWEwMCApO1xyXG5cdFx0Y29uc3QgY29sb3JDb25lID0gbmV3IENvbG9yKCAweGZmMDAwMCApO1xyXG5cdFx0Y29uc3QgY29sb3JVcCA9IG5ldyBDb2xvciggMHgwMGFhZmYgKTtcclxuXHRcdGNvbnN0IGNvbG9yVGFyZ2V0ID0gbmV3IENvbG9yKCAweGZmZmZmZiApO1xyXG5cdFx0Y29uc3QgY29sb3JDcm9zcyA9IG5ldyBDb2xvciggMHgzMzMzMzMgKTtcclxuXHJcblx0XHR0aGlzLnNldENvbG9ycyggY29sb3JGcnVzdHVtLCBjb2xvckNvbmUsIGNvbG9yVXAsIGNvbG9yVGFyZ2V0LCBjb2xvckNyb3NzICk7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0Q29sb3JzKCBmcnVzdHVtLCBjb25lLCB1cCwgdGFyZ2V0LCBjcm9zcyApIHtcclxuXHJcblx0XHRjb25zdCBnZW9tZXRyeSA9IHRoaXMuZ2VvbWV0cnk7XHJcblxyXG5cdFx0Y29uc3QgY29sb3JBdHRyaWJ1dGUgPSBnZW9tZXRyeS5nZXRBdHRyaWJ1dGUoICdjb2xvcicgKTtcclxuXHJcblx0XHQvLyBuZWFyXHJcblxyXG5cdFx0Y29sb3JBdHRyaWJ1dGUuc2V0WFlaKCAwLCBmcnVzdHVtLnIsIGZydXN0dW0uZywgZnJ1c3R1bS5iICk7IGNvbG9yQXR0cmlidXRlLnNldFhZWiggMSwgZnJ1c3R1bS5yLCBmcnVzdHVtLmcsIGZydXN0dW0uYiApOyAvLyBuMSwgbjJcclxuXHRcdGNvbG9yQXR0cmlidXRlLnNldFhZWiggMiwgZnJ1c3R1bS5yLCBmcnVzdHVtLmcsIGZydXN0dW0uYiApOyBjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDMsIGZydXN0dW0uciwgZnJ1c3R1bS5nLCBmcnVzdHVtLmIgKTsgLy8gbjIsIG40XHJcblx0XHRjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDQsIGZydXN0dW0uciwgZnJ1c3R1bS5nLCBmcnVzdHVtLmIgKTsgY29sb3JBdHRyaWJ1dGUuc2V0WFlaKCA1LCBmcnVzdHVtLnIsIGZydXN0dW0uZywgZnJ1c3R1bS5iICk7IC8vIG40LCBuM1xyXG5cdFx0Y29sb3JBdHRyaWJ1dGUuc2V0WFlaKCA2LCBmcnVzdHVtLnIsIGZydXN0dW0uZywgZnJ1c3R1bS5iICk7IGNvbG9yQXR0cmlidXRlLnNldFhZWiggNywgZnJ1c3R1bS5yLCBmcnVzdHVtLmcsIGZydXN0dW0uYiApOyAvLyBuMywgbjFcclxuXHJcblx0XHQvLyBmYXJcclxuXHJcblx0XHRjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDgsIGZydXN0dW0uciwgZnJ1c3R1bS5nLCBmcnVzdHVtLmIgKTsgY29sb3JBdHRyaWJ1dGUuc2V0WFlaKCA5LCBmcnVzdHVtLnIsIGZydXN0dW0uZywgZnJ1c3R1bS5iICk7IC8vIGYxLCBmMlxyXG5cdFx0Y29sb3JBdHRyaWJ1dGUuc2V0WFlaKCAxMCwgZnJ1c3R1bS5yLCBmcnVzdHVtLmcsIGZydXN0dW0uYiApOyBjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDExLCBmcnVzdHVtLnIsIGZydXN0dW0uZywgZnJ1c3R1bS5iICk7IC8vIGYyLCBmNFxyXG5cdFx0Y29sb3JBdHRyaWJ1dGUuc2V0WFlaKCAxMiwgZnJ1c3R1bS5yLCBmcnVzdHVtLmcsIGZydXN0dW0uYiApOyBjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDEzLCBmcnVzdHVtLnIsIGZydXN0dW0uZywgZnJ1c3R1bS5iICk7IC8vIGY0LCBmM1xyXG5cdFx0Y29sb3JBdHRyaWJ1dGUuc2V0WFlaKCAxNCwgZnJ1c3R1bS5yLCBmcnVzdHVtLmcsIGZydXN0dW0uYiApOyBjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDE1LCBmcnVzdHVtLnIsIGZydXN0dW0uZywgZnJ1c3R1bS5iICk7IC8vIGYzLCBmMVxyXG5cclxuXHRcdC8vIHNpZGVzXHJcblxyXG5cdFx0Y29sb3JBdHRyaWJ1dGUuc2V0WFlaKCAxNiwgZnJ1c3R1bS5yLCBmcnVzdHVtLmcsIGZydXN0dW0uYiApOyBjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDE3LCBmcnVzdHVtLnIsIGZydXN0dW0uZywgZnJ1c3R1bS5iICk7IC8vIG4xLCBmMVxyXG5cdFx0Y29sb3JBdHRyaWJ1dGUuc2V0WFlaKCAxOCwgZnJ1c3R1bS5yLCBmcnVzdHVtLmcsIGZydXN0dW0uYiApOyBjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDE5LCBmcnVzdHVtLnIsIGZydXN0dW0uZywgZnJ1c3R1bS5iICk7IC8vIG4yLCBmMlxyXG5cdFx0Y29sb3JBdHRyaWJ1dGUuc2V0WFlaKCAyMCwgZnJ1c3R1bS5yLCBmcnVzdHVtLmcsIGZydXN0dW0uYiApOyBjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDIxLCBmcnVzdHVtLnIsIGZydXN0dW0uZywgZnJ1c3R1bS5iICk7IC8vIG4zLCBmM1xyXG5cdFx0Y29sb3JBdHRyaWJ1dGUuc2V0WFlaKCAyMiwgZnJ1c3R1bS5yLCBmcnVzdHVtLmcsIGZydXN0dW0uYiApOyBjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDIzLCBmcnVzdHVtLnIsIGZydXN0dW0uZywgZnJ1c3R1bS5iICk7IC8vIG40LCBmNFxyXG5cclxuXHRcdC8vIGNvbmVcclxuXHJcblx0XHRjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDI0LCBjb25lLnIsIGNvbmUuZywgY29uZS5iICk7IGNvbG9yQXR0cmlidXRlLnNldFhZWiggMjUsIGNvbmUuciwgY29uZS5nLCBjb25lLmIgKTsgLy8gcCwgbjFcclxuXHRcdGNvbG9yQXR0cmlidXRlLnNldFhZWiggMjYsIGNvbmUuciwgY29uZS5nLCBjb25lLmIgKTsgY29sb3JBdHRyaWJ1dGUuc2V0WFlaKCAyNywgY29uZS5yLCBjb25lLmcsIGNvbmUuYiApOyAvLyBwLCBuMlxyXG5cdFx0Y29sb3JBdHRyaWJ1dGUuc2V0WFlaKCAyOCwgY29uZS5yLCBjb25lLmcsIGNvbmUuYiApOyBjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDI5LCBjb25lLnIsIGNvbmUuZywgY29uZS5iICk7IC8vIHAsIG4zXHJcblx0XHRjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDMwLCBjb25lLnIsIGNvbmUuZywgY29uZS5iICk7IGNvbG9yQXR0cmlidXRlLnNldFhZWiggMzEsIGNvbmUuciwgY29uZS5nLCBjb25lLmIgKTsgLy8gcCwgbjRcclxuXHJcblx0XHQvLyB1cFxyXG5cclxuXHRcdGNvbG9yQXR0cmlidXRlLnNldFhZWiggMzIsIHVwLnIsIHVwLmcsIHVwLmIgKTsgY29sb3JBdHRyaWJ1dGUuc2V0WFlaKCAzMywgdXAuciwgdXAuZywgdXAuYiApOyAvLyB1MSwgdTJcclxuXHRcdGNvbG9yQXR0cmlidXRlLnNldFhZWiggMzQsIHVwLnIsIHVwLmcsIHVwLmIgKTsgY29sb3JBdHRyaWJ1dGUuc2V0WFlaKCAzNSwgdXAuciwgdXAuZywgdXAuYiApOyAvLyB1MiwgdTNcclxuXHRcdGNvbG9yQXR0cmlidXRlLnNldFhZWiggMzYsIHVwLnIsIHVwLmcsIHVwLmIgKTsgY29sb3JBdHRyaWJ1dGUuc2V0WFlaKCAzNywgdXAuciwgdXAuZywgdXAuYiApOyAvLyB1MywgdTFcclxuXHJcblx0XHQvLyB0YXJnZXRcclxuXHJcblx0XHRjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDM4LCB0YXJnZXQuciwgdGFyZ2V0LmcsIHRhcmdldC5iICk7IGNvbG9yQXR0cmlidXRlLnNldFhZWiggMzksIHRhcmdldC5yLCB0YXJnZXQuZywgdGFyZ2V0LmIgKTsgLy8gYywgdFxyXG5cdFx0Y29sb3JBdHRyaWJ1dGUuc2V0WFlaKCA0MCwgY3Jvc3MuciwgY3Jvc3MuZywgY3Jvc3MuYiApOyBjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDQxLCBjcm9zcy5yLCBjcm9zcy5nLCBjcm9zcy5iICk7IC8vIHAsIGNcclxuXHJcblx0XHQvLyBjcm9zc1xyXG5cclxuXHRcdGNvbG9yQXR0cmlidXRlLnNldFhZWiggNDIsIGNyb3NzLnIsIGNyb3NzLmcsIGNyb3NzLmIgKTsgY29sb3JBdHRyaWJ1dGUuc2V0WFlaKCA0MywgY3Jvc3MuciwgY3Jvc3MuZywgY3Jvc3MuYiApOyAvLyBjbjEsIGNuMlxyXG5cdFx0Y29sb3JBdHRyaWJ1dGUuc2V0WFlaKCA0NCwgY3Jvc3MuciwgY3Jvc3MuZywgY3Jvc3MuYiApOyBjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDQ1LCBjcm9zcy5yLCBjcm9zcy5nLCBjcm9zcy5iICk7IC8vIGNuMywgY240XHJcblxyXG5cdFx0Y29sb3JBdHRyaWJ1dGUuc2V0WFlaKCA0NiwgY3Jvc3MuciwgY3Jvc3MuZywgY3Jvc3MuYiApOyBjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDQ3LCBjcm9zcy5yLCBjcm9zcy5nLCBjcm9zcy5iICk7IC8vIGNmMSwgY2YyXHJcblx0XHRjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDQ4LCBjcm9zcy5yLCBjcm9zcy5nLCBjcm9zcy5iICk7IGNvbG9yQXR0cmlidXRlLnNldFhZWiggNDksIGNyb3NzLnIsIGNyb3NzLmcsIGNyb3NzLmIgKTsgLy8gY2YzLCBjZjRcclxuXHJcblx0XHRjb2xvckF0dHJpYnV0ZS5uZWVkc1VwZGF0ZSA9IHRydWU7XHJcblxyXG5cdH1cclxuXHJcblx0dXBkYXRlKCkge1xyXG5cclxuXHRcdGNvbnN0IGdlb21ldHJ5ID0gdGhpcy5nZW9tZXRyeTtcclxuXHRcdGNvbnN0IHBvaW50TWFwID0gdGhpcy5wb2ludE1hcDtcclxuXHJcblx0XHRjb25zdCB3ID0gMSwgaCA9IDE7XHJcblxyXG5cdFx0Ly8gd2UgbmVlZCBqdXN0IGNhbWVyYSBwcm9qZWN0aW9uIG1hdHJpeCBpbnZlcnNlXHJcblx0XHQvLyB3b3JsZCBtYXRyaXggbXVzdCBiZSBpZGVudGl0eVxyXG5cclxuXHRcdF9jYW1lcmEucHJvamVjdGlvbk1hdHJpeEludmVyc2UuY29weSggdGhpcy5jYW1lcmEucHJvamVjdGlvbk1hdHJpeEludmVyc2UgKTtcclxuXHJcblx0XHQvLyBjZW50ZXIgLyB0YXJnZXRcclxuXHJcblx0XHRzZXRQb2ludCggJ2MnLCBwb2ludE1hcCwgZ2VvbWV0cnksIF9jYW1lcmEsIDAsIDAsIC0gMSApO1xyXG5cdFx0c2V0UG9pbnQoICd0JywgcG9pbnRNYXAsIGdlb21ldHJ5LCBfY2FtZXJhLCAwLCAwLCAxICk7XHJcblxyXG5cdFx0Ly8gbmVhclxyXG5cclxuXHRcdHNldFBvaW50KCAnbjEnLCBwb2ludE1hcCwgZ2VvbWV0cnksIF9jYW1lcmEsIC0gdywgLSBoLCAtIDEgKTtcclxuXHRcdHNldFBvaW50KCAnbjInLCBwb2ludE1hcCwgZ2VvbWV0cnksIF9jYW1lcmEsIHcsIC0gaCwgLSAxICk7XHJcblx0XHRzZXRQb2ludCggJ24zJywgcG9pbnRNYXAsIGdlb21ldHJ5LCBfY2FtZXJhLCAtIHcsIGgsIC0gMSApO1xyXG5cdFx0c2V0UG9pbnQoICduNCcsIHBvaW50TWFwLCBnZW9tZXRyeSwgX2NhbWVyYSwgdywgaCwgLSAxICk7XHJcblxyXG5cdFx0Ly8gZmFyXHJcblxyXG5cdFx0c2V0UG9pbnQoICdmMScsIHBvaW50TWFwLCBnZW9tZXRyeSwgX2NhbWVyYSwgLSB3LCAtIGgsIDEgKTtcclxuXHRcdHNldFBvaW50KCAnZjInLCBwb2ludE1hcCwgZ2VvbWV0cnksIF9jYW1lcmEsIHcsIC0gaCwgMSApO1xyXG5cdFx0c2V0UG9pbnQoICdmMycsIHBvaW50TWFwLCBnZW9tZXRyeSwgX2NhbWVyYSwgLSB3LCBoLCAxICk7XHJcblx0XHRzZXRQb2ludCggJ2Y0JywgcG9pbnRNYXAsIGdlb21ldHJ5LCBfY2FtZXJhLCB3LCBoLCAxICk7XHJcblxyXG5cdFx0Ly8gdXBcclxuXHJcblx0XHRzZXRQb2ludCggJ3UxJywgcG9pbnRNYXAsIGdlb21ldHJ5LCBfY2FtZXJhLCB3ICogMC43LCBoICogMS4xLCAtIDEgKTtcclxuXHRcdHNldFBvaW50KCAndTInLCBwb2ludE1hcCwgZ2VvbWV0cnksIF9jYW1lcmEsIC0gdyAqIDAuNywgaCAqIDEuMSwgLSAxICk7XHJcblx0XHRzZXRQb2ludCggJ3UzJywgcG9pbnRNYXAsIGdlb21ldHJ5LCBfY2FtZXJhLCAwLCBoICogMiwgLSAxICk7XHJcblxyXG5cdFx0Ly8gY3Jvc3NcclxuXHJcblx0XHRzZXRQb2ludCggJ2NmMScsIHBvaW50TWFwLCBnZW9tZXRyeSwgX2NhbWVyYSwgLSB3LCAwLCAxICk7XHJcblx0XHRzZXRQb2ludCggJ2NmMicsIHBvaW50TWFwLCBnZW9tZXRyeSwgX2NhbWVyYSwgdywgMCwgMSApO1xyXG5cdFx0c2V0UG9pbnQoICdjZjMnLCBwb2ludE1hcCwgZ2VvbWV0cnksIF9jYW1lcmEsIDAsIC0gaCwgMSApO1xyXG5cdFx0c2V0UG9pbnQoICdjZjQnLCBwb2ludE1hcCwgZ2VvbWV0cnksIF9jYW1lcmEsIDAsIGgsIDEgKTtcclxuXHJcblx0XHRzZXRQb2ludCggJ2NuMScsIHBvaW50TWFwLCBnZW9tZXRyeSwgX2NhbWVyYSwgLSB3LCAwLCAtIDEgKTtcclxuXHRcdHNldFBvaW50KCAnY24yJywgcG9pbnRNYXAsIGdlb21ldHJ5LCBfY2FtZXJhLCB3LCAwLCAtIDEgKTtcclxuXHRcdHNldFBvaW50KCAnY24zJywgcG9pbnRNYXAsIGdlb21ldHJ5LCBfY2FtZXJhLCAwLCAtIGgsIC0gMSApO1xyXG5cdFx0c2V0UG9pbnQoICdjbjQnLCBwb2ludE1hcCwgZ2VvbWV0cnksIF9jYW1lcmEsIDAsIGgsIC0gMSApO1xyXG5cclxuXHRcdGdlb21ldHJ5LmdldEF0dHJpYnV0ZSggJ3Bvc2l0aW9uJyApLm5lZWRzVXBkYXRlID0gdHJ1ZTtcclxuXHJcblx0fVxyXG5cclxuXHRkaXNwb3NlKCkge1xyXG5cclxuXHRcdHRoaXMuZ2VvbWV0cnkuZGlzcG9zZSgpO1xyXG5cdFx0dGhpcy5tYXRlcmlhbC5kaXNwb3NlKCk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcblxyXG5mdW5jdGlvbiBzZXRQb2ludCggcG9pbnQsIHBvaW50TWFwLCBnZW9tZXRyeSwgY2FtZXJhLCB4LCB5LCB6ICkge1xyXG5cclxuXHRfdmVjdG9yLnNldCggeCwgeSwgeiApLnVucHJvamVjdCggY2FtZXJhICk7XHJcblxyXG5cdGNvbnN0IHBvaW50cyA9IHBvaW50TWFwWyBwb2ludCBdO1xyXG5cclxuXHRpZiAoIHBvaW50cyAhPT0gdW5kZWZpbmVkICkge1xyXG5cclxuXHRcdGNvbnN0IHBvc2l0aW9uID0gZ2VvbWV0cnkuZ2V0QXR0cmlidXRlKCAncG9zaXRpb24nICk7XHJcblxyXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gcG9pbnRzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRwb3NpdGlvbi5zZXRYWVooIHBvaW50c1sgaSBdLCBfdmVjdG9yLngsIF92ZWN0b3IueSwgX3ZlY3Rvci56ICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5leHBvcnQgeyBDYW1lcmFIZWxwZXIgfTtcclxuIiwiaW1wb3J0IHsgQm94MyB9IGZyb20gJy4uL21hdGgvQm94My5qcyc7XHJcbmltcG9ydCB7IExpbmVTZWdtZW50cyB9IGZyb20gJy4uL29iamVjdHMvTGluZVNlZ21lbnRzLmpzJztcclxuaW1wb3J0IHsgTGluZUJhc2ljTWF0ZXJpYWwgfSBmcm9tICcuLi9tYXRlcmlhbHMvTGluZUJhc2ljTWF0ZXJpYWwuanMnO1xyXG5pbXBvcnQgeyBCdWZmZXJBdHRyaWJ1dGUgfSBmcm9tICcuLi9jb3JlL0J1ZmZlckF0dHJpYnV0ZS5qcyc7XHJcbmltcG9ydCB7IEJ1ZmZlckdlb21ldHJ5IH0gZnJvbSAnLi4vY29yZS9CdWZmZXJHZW9tZXRyeS5qcyc7XHJcblxyXG5jb25zdCBfYm94ID0gLypAX19QVVJFX18qLyBuZXcgQm94MygpO1xyXG5cclxuY2xhc3MgQm94SGVscGVyIGV4dGVuZHMgTGluZVNlZ21lbnRzIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIG9iamVjdCwgY29sb3IgPSAweGZmZmYwMCApIHtcclxuXHJcblx0XHRjb25zdCBpbmRpY2VzID0gbmV3IFVpbnQxNkFycmF5KCBbIDAsIDEsIDEsIDIsIDIsIDMsIDMsIDAsIDQsIDUsIDUsIDYsIDYsIDcsIDcsIDQsIDAsIDQsIDEsIDUsIDIsIDYsIDMsIDcgXSApO1xyXG5cdFx0Y29uc3QgcG9zaXRpb25zID0gbmV3IEZsb2F0MzJBcnJheSggOCAqIDMgKTtcclxuXHJcblx0XHRjb25zdCBnZW9tZXRyeSA9IG5ldyBCdWZmZXJHZW9tZXRyeSgpO1xyXG5cdFx0Z2VvbWV0cnkuc2V0SW5kZXgoIG5ldyBCdWZmZXJBdHRyaWJ1dGUoIGluZGljZXMsIDEgKSApO1xyXG5cdFx0Z2VvbWV0cnkuc2V0QXR0cmlidXRlKCAncG9zaXRpb24nLCBuZXcgQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbnMsIDMgKSApO1xyXG5cclxuXHRcdHN1cGVyKCBnZW9tZXRyeSwgbmV3IExpbmVCYXNpY01hdGVyaWFsKCB7IGNvbG9yOiBjb2xvciwgdG9uZU1hcHBlZDogZmFsc2UgfSApICk7XHJcblxyXG5cdFx0dGhpcy5vYmplY3QgPSBvYmplY3Q7XHJcblx0XHR0aGlzLnR5cGUgPSAnQm94SGVscGVyJztcclxuXHJcblx0XHR0aGlzLm1hdHJpeEF1dG9VcGRhdGUgPSBmYWxzZTtcclxuXHJcblx0XHR0aGlzLnVwZGF0ZSgpO1xyXG5cclxuXHR9XHJcblxyXG5cdHVwZGF0ZSggb2JqZWN0ICkge1xyXG5cclxuXHRcdGlmICggb2JqZWN0ICE9PSB1bmRlZmluZWQgKSB7XHJcblxyXG5cdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5Cb3hIZWxwZXI6IC51cGRhdGUoKSBoYXMgbm8gbG9uZ2VyIGFyZ3VtZW50cy4nICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggdGhpcy5vYmplY3QgIT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdF9ib3guc2V0RnJvbU9iamVjdCggdGhpcy5vYmplY3QgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBfYm94LmlzRW1wdHkoKSApIHJldHVybjtcclxuXHJcblx0XHRjb25zdCBtaW4gPSBfYm94Lm1pbjtcclxuXHRcdGNvbnN0IG1heCA9IF9ib3gubWF4O1xyXG5cclxuXHRcdC8qXHJcblx0XHRcdDVfX19fNFxyXG5cdFx0MS9fX18wL3xcclxuXHRcdHwgNl9ffF83XHJcblx0XHQyL19fXzMvXHJcblxyXG5cdFx0MDogbWF4LngsIG1heC55LCBtYXguelxyXG5cdFx0MTogbWluLngsIG1heC55LCBtYXguelxyXG5cdFx0MjogbWluLngsIG1pbi55LCBtYXguelxyXG5cdFx0MzogbWF4LngsIG1pbi55LCBtYXguelxyXG5cdFx0NDogbWF4LngsIG1heC55LCBtaW4uelxyXG5cdFx0NTogbWluLngsIG1heC55LCBtaW4uelxyXG5cdFx0NjogbWluLngsIG1pbi55LCBtaW4uelxyXG5cdFx0NzogbWF4LngsIG1pbi55LCBtaW4uelxyXG5cdFx0Ki9cclxuXHJcblx0XHRjb25zdCBwb3NpdGlvbiA9IHRoaXMuZ2VvbWV0cnkuYXR0cmlidXRlcy5wb3NpdGlvbjtcclxuXHRcdGNvbnN0IGFycmF5ID0gcG9zaXRpb24uYXJyYXk7XHJcblxyXG5cdFx0YXJyYXlbIDAgXSA9IG1heC54OyBhcnJheVsgMSBdID0gbWF4Lnk7IGFycmF5WyAyIF0gPSBtYXguejtcclxuXHRcdGFycmF5WyAzIF0gPSBtaW4ueDsgYXJyYXlbIDQgXSA9IG1heC55OyBhcnJheVsgNSBdID0gbWF4Lno7XHJcblx0XHRhcnJheVsgNiBdID0gbWluLng7IGFycmF5WyA3IF0gPSBtaW4ueTsgYXJyYXlbIDggXSA9IG1heC56O1xyXG5cdFx0YXJyYXlbIDkgXSA9IG1heC54OyBhcnJheVsgMTAgXSA9IG1pbi55OyBhcnJheVsgMTEgXSA9IG1heC56O1xyXG5cdFx0YXJyYXlbIDEyIF0gPSBtYXgueDsgYXJyYXlbIDEzIF0gPSBtYXgueTsgYXJyYXlbIDE0IF0gPSBtaW4uejtcclxuXHRcdGFycmF5WyAxNSBdID0gbWluLng7IGFycmF5WyAxNiBdID0gbWF4Lnk7IGFycmF5WyAxNyBdID0gbWluLno7XHJcblx0XHRhcnJheVsgMTggXSA9IG1pbi54OyBhcnJheVsgMTkgXSA9IG1pbi55OyBhcnJheVsgMjAgXSA9IG1pbi56O1xyXG5cdFx0YXJyYXlbIDIxIF0gPSBtYXgueDsgYXJyYXlbIDIyIF0gPSBtaW4ueTsgYXJyYXlbIDIzIF0gPSBtaW4uejtcclxuXHJcblx0XHRwb3NpdGlvbi5uZWVkc1VwZGF0ZSA9IHRydWU7XHJcblxyXG5cdFx0dGhpcy5nZW9tZXRyeS5jb21wdXRlQm91bmRpbmdTcGhlcmUoKTtcclxuXHJcblx0fVxyXG5cclxuXHRzZXRGcm9tT2JqZWN0KCBvYmplY3QgKSB7XHJcblxyXG5cdFx0dGhpcy5vYmplY3QgPSBvYmplY3Q7XHJcblx0XHR0aGlzLnVwZGF0ZSgpO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGNvcHkoIHNvdXJjZSwgcmVjdXJzaXZlICkge1xyXG5cclxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSwgcmVjdXJzaXZlICk7XHJcblxyXG5cdFx0dGhpcy5vYmplY3QgPSBzb3VyY2Uub2JqZWN0O1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGRpc3Bvc2UoKSB7XHJcblxyXG5cdFx0dGhpcy5nZW9tZXRyeS5kaXNwb3NlKCk7XHJcblx0XHR0aGlzLm1hdGVyaWFsLmRpc3Bvc2UoKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuXHJcbmV4cG9ydCB7IEJveEhlbHBlciB9O1xyXG4iLCJpbXBvcnQgeyBMaW5lU2VnbWVudHMgfSBmcm9tICcuLi9vYmplY3RzL0xpbmVTZWdtZW50cy5qcyc7XHJcbmltcG9ydCB7IExpbmVCYXNpY01hdGVyaWFsIH0gZnJvbSAnLi4vbWF0ZXJpYWxzL0xpbmVCYXNpY01hdGVyaWFsLmpzJztcclxuaW1wb3J0IHsgQnVmZmVyQXR0cmlidXRlLCBGbG9hdDMyQnVmZmVyQXR0cmlidXRlIH0gZnJvbSAnLi4vY29yZS9CdWZmZXJBdHRyaWJ1dGUuanMnO1xyXG5pbXBvcnQgeyBCdWZmZXJHZW9tZXRyeSB9IGZyb20gJy4uL2NvcmUvQnVmZmVyR2VvbWV0cnkuanMnO1xyXG5cclxuY2xhc3MgQm94M0hlbHBlciBleHRlbmRzIExpbmVTZWdtZW50cyB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBib3gsIGNvbG9yID0gMHhmZmZmMDAgKSB7XHJcblxyXG5cdFx0Y29uc3QgaW5kaWNlcyA9IG5ldyBVaW50MTZBcnJheSggWyAwLCAxLCAxLCAyLCAyLCAzLCAzLCAwLCA0LCA1LCA1LCA2LCA2LCA3LCA3LCA0LCAwLCA0LCAxLCA1LCAyLCA2LCAzLCA3IF0gKTtcclxuXHJcblx0XHRjb25zdCBwb3NpdGlvbnMgPSBbIDEsIDEsIDEsIC0gMSwgMSwgMSwgLSAxLCAtIDEsIDEsIDEsIC0gMSwgMSwgMSwgMSwgLSAxLCAtIDEsIDEsIC0gMSwgLSAxLCAtIDEsIC0gMSwgMSwgLSAxLCAtIDEgXTtcclxuXHJcblx0XHRjb25zdCBnZW9tZXRyeSA9IG5ldyBCdWZmZXJHZW9tZXRyeSgpO1xyXG5cclxuXHRcdGdlb21ldHJ5LnNldEluZGV4KCBuZXcgQnVmZmVyQXR0cmlidXRlKCBpbmRpY2VzLCAxICkgKTtcclxuXHJcblx0XHRnZW9tZXRyeS5zZXRBdHRyaWJ1dGUoICdwb3NpdGlvbicsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbnMsIDMgKSApO1xyXG5cclxuXHRcdHN1cGVyKCBnZW9tZXRyeSwgbmV3IExpbmVCYXNpY01hdGVyaWFsKCB7IGNvbG9yOiBjb2xvciwgdG9uZU1hcHBlZDogZmFsc2UgfSApICk7XHJcblxyXG5cdFx0dGhpcy5ib3ggPSBib3g7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ0JveDNIZWxwZXInO1xyXG5cclxuXHRcdHRoaXMuZ2VvbWV0cnkuY29tcHV0ZUJvdW5kaW5nU3BoZXJlKCk7XHJcblxyXG5cdH1cclxuXHJcblx0dXBkYXRlTWF0cml4V29ybGQoIGZvcmNlICkge1xyXG5cclxuXHRcdGNvbnN0IGJveCA9IHRoaXMuYm94O1xyXG5cclxuXHRcdGlmICggYm94LmlzRW1wdHkoKSApIHJldHVybjtcclxuXHJcblx0XHRib3guZ2V0Q2VudGVyKCB0aGlzLnBvc2l0aW9uICk7XHJcblxyXG5cdFx0Ym94LmdldFNpemUoIHRoaXMuc2NhbGUgKTtcclxuXHJcblx0XHR0aGlzLnNjYWxlLm11bHRpcGx5U2NhbGFyKCAwLjUgKTtcclxuXHJcblx0XHRzdXBlci51cGRhdGVNYXRyaXhXb3JsZCggZm9yY2UgKTtcclxuXHJcblx0fVxyXG5cclxuXHRkaXNwb3NlKCkge1xyXG5cclxuXHRcdHRoaXMuZ2VvbWV0cnkuZGlzcG9zZSgpO1xyXG5cdFx0dGhpcy5tYXRlcmlhbC5kaXNwb3NlKCk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IEJveDNIZWxwZXIgfTtcclxuIiwiaW1wb3J0IHsgTGluZSB9IGZyb20gJy4uL29iamVjdHMvTGluZS5qcyc7XHJcbmltcG9ydCB7IE1lc2ggfSBmcm9tICcuLi9vYmplY3RzL01lc2guanMnO1xyXG5pbXBvcnQgeyBMaW5lQmFzaWNNYXRlcmlhbCB9IGZyb20gJy4uL21hdGVyaWFscy9MaW5lQmFzaWNNYXRlcmlhbC5qcyc7XHJcbmltcG9ydCB7IE1lc2hCYXNpY01hdGVyaWFsIH0gZnJvbSAnLi4vbWF0ZXJpYWxzL01lc2hCYXNpY01hdGVyaWFsLmpzJztcclxuaW1wb3J0IHsgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSB9IGZyb20gJy4uL2NvcmUvQnVmZmVyQXR0cmlidXRlLmpzJztcclxuaW1wb3J0IHsgQnVmZmVyR2VvbWV0cnkgfSBmcm9tICcuLi9jb3JlL0J1ZmZlckdlb21ldHJ5LmpzJztcclxuXHJcbmNsYXNzIFBsYW5lSGVscGVyIGV4dGVuZHMgTGluZSB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCBwbGFuZSwgc2l6ZSA9IDEsIGhleCA9IDB4ZmZmZjAwICkge1xyXG5cclxuXHRcdGNvbnN0IGNvbG9yID0gaGV4O1xyXG5cclxuXHRcdGNvbnN0IHBvc2l0aW9ucyA9IFsgMSwgLSAxLCAwLCAtIDEsIDEsIDAsIC0gMSwgLSAxLCAwLCAxLCAxLCAwLCAtIDEsIDEsIDAsIC0gMSwgLSAxLCAwLCAxLCAtIDEsIDAsIDEsIDEsIDAgXTtcclxuXHJcblx0XHRjb25zdCBnZW9tZXRyeSA9IG5ldyBCdWZmZXJHZW9tZXRyeSgpO1xyXG5cdFx0Z2VvbWV0cnkuc2V0QXR0cmlidXRlKCAncG9zaXRpb24nLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggcG9zaXRpb25zLCAzICkgKTtcclxuXHRcdGdlb21ldHJ5LmNvbXB1dGVCb3VuZGluZ1NwaGVyZSgpO1xyXG5cclxuXHRcdHN1cGVyKCBnZW9tZXRyeSwgbmV3IExpbmVCYXNpY01hdGVyaWFsKCB7IGNvbG9yOiBjb2xvciwgdG9uZU1hcHBlZDogZmFsc2UgfSApICk7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ1BsYW5lSGVscGVyJztcclxuXHJcblx0XHR0aGlzLnBsYW5lID0gcGxhbmU7XHJcblxyXG5cdFx0dGhpcy5zaXplID0gc2l6ZTtcclxuXHJcblx0XHRjb25zdCBwb3NpdGlvbnMyID0gWyAxLCAxLCAwLCAtIDEsIDEsIDAsIC0gMSwgLSAxLCAwLCAxLCAxLCAwLCAtIDEsIC0gMSwgMCwgMSwgLSAxLCAwIF07XHJcblxyXG5cdFx0Y29uc3QgZ2VvbWV0cnkyID0gbmV3IEJ1ZmZlckdlb21ldHJ5KCk7XHJcblx0XHRnZW9tZXRyeTIuc2V0QXR0cmlidXRlKCAncG9zaXRpb24nLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggcG9zaXRpb25zMiwgMyApICk7XHJcblx0XHRnZW9tZXRyeTIuY29tcHV0ZUJvdW5kaW5nU3BoZXJlKCk7XHJcblxyXG5cdFx0dGhpcy5hZGQoIG5ldyBNZXNoKCBnZW9tZXRyeTIsIG5ldyBNZXNoQmFzaWNNYXRlcmlhbCggeyBjb2xvcjogY29sb3IsIG9wYWNpdHk6IDAuMiwgdHJhbnNwYXJlbnQ6IHRydWUsIGRlcHRoV3JpdGU6IGZhbHNlLCB0b25lTWFwcGVkOiBmYWxzZSB9ICkgKSApO1xyXG5cclxuXHR9XHJcblxyXG5cdHVwZGF0ZU1hdHJpeFdvcmxkKCBmb3JjZSApIHtcclxuXHJcblx0XHR0aGlzLnBvc2l0aW9uLnNldCggMCwgMCwgMCApO1xyXG5cclxuXHRcdHRoaXMuc2NhbGUuc2V0KCAwLjUgKiB0aGlzLnNpemUsIDAuNSAqIHRoaXMuc2l6ZSwgMSApO1xyXG5cclxuXHRcdHRoaXMubG9va0F0KCB0aGlzLnBsYW5lLm5vcm1hbCApO1xyXG5cclxuXHRcdHRoaXMudHJhbnNsYXRlWiggLSB0aGlzLnBsYW5lLmNvbnN0YW50ICk7XHJcblxyXG5cdFx0c3VwZXIudXBkYXRlTWF0cml4V29ybGQoIGZvcmNlICk7XHJcblxyXG5cdH1cclxuXHJcblx0ZGlzcG9zZSgpIHtcclxuXHJcblx0XHR0aGlzLmdlb21ldHJ5LmRpc3Bvc2UoKTtcclxuXHRcdHRoaXMubWF0ZXJpYWwuZGlzcG9zZSgpO1xyXG5cdFx0dGhpcy5jaGlsZHJlblsgMCBdLmdlb21ldHJ5LmRpc3Bvc2UoKTtcclxuXHRcdHRoaXMuY2hpbGRyZW5bIDAgXS5tYXRlcmlhbC5kaXNwb3NlKCk7XHJcblxyXG5cdH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCB7IFBsYW5lSGVscGVyIH07XHJcbiIsImltcG9ydCB7IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUgfSBmcm9tICcuLi9jb3JlL0J1ZmZlckF0dHJpYnV0ZS5qcyc7XHJcbmltcG9ydCB7IEJ1ZmZlckdlb21ldHJ5IH0gZnJvbSAnLi4vY29yZS9CdWZmZXJHZW9tZXRyeS5qcyc7XHJcbmltcG9ydCB7IE9iamVjdDNEIH0gZnJvbSAnLi4vY29yZS9PYmplY3QzRC5qcyc7XHJcbmltcG9ydCB7IEN5bGluZGVyR2VvbWV0cnkgfSBmcm9tICcuLi9nZW9tZXRyaWVzL0N5bGluZGVyR2VvbWV0cnkuanMnO1xyXG5pbXBvcnQgeyBNZXNoQmFzaWNNYXRlcmlhbCB9IGZyb20gJy4uL21hdGVyaWFscy9NZXNoQmFzaWNNYXRlcmlhbC5qcyc7XHJcbmltcG9ydCB7IExpbmVCYXNpY01hdGVyaWFsIH0gZnJvbSAnLi4vbWF0ZXJpYWxzL0xpbmVCYXNpY01hdGVyaWFsLmpzJztcclxuaW1wb3J0IHsgTWVzaCB9IGZyb20gJy4uL29iamVjdHMvTWVzaC5qcyc7XHJcbmltcG9ydCB7IExpbmUgfSBmcm9tICcuLi9vYmplY3RzL0xpbmUuanMnO1xyXG5pbXBvcnQgeyBWZWN0b3IzIH0gZnJvbSAnLi4vbWF0aC9WZWN0b3IzLmpzJztcclxuXHJcbmNvbnN0IF9heGlzID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xyXG5sZXQgX2xpbmVHZW9tZXRyeSwgX2NvbmVHZW9tZXRyeTtcclxuXHJcbmNsYXNzIEFycm93SGVscGVyIGV4dGVuZHMgT2JqZWN0M0Qge1xyXG5cclxuXHQvLyBkaXIgaXMgYXNzdW1lZCB0byBiZSBub3JtYWxpemVkXHJcblxyXG5cdGNvbnN0cnVjdG9yKCBkaXIgPSBuZXcgVmVjdG9yMyggMCwgMCwgMSApLCBvcmlnaW4gPSBuZXcgVmVjdG9yMyggMCwgMCwgMCApLCBsZW5ndGggPSAxLCBjb2xvciA9IDB4ZmZmZjAwLCBoZWFkTGVuZ3RoID0gbGVuZ3RoICogMC4yLCBoZWFkV2lkdGggPSBoZWFkTGVuZ3RoICogMC4yICkge1xyXG5cclxuXHRcdHN1cGVyKCk7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ0Fycm93SGVscGVyJztcclxuXHJcblx0XHRpZiAoIF9saW5lR2VvbWV0cnkgPT09IHVuZGVmaW5lZCApIHtcclxuXHJcblx0XHRcdF9saW5lR2VvbWV0cnkgPSBuZXcgQnVmZmVyR2VvbWV0cnkoKTtcclxuXHRcdFx0X2xpbmVHZW9tZXRyeS5zZXRBdHRyaWJ1dGUoICdwb3NpdGlvbicsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCBbIDAsIDAsIDAsIDAsIDEsIDAgXSwgMyApICk7XHJcblxyXG5cdFx0XHRfY29uZUdlb21ldHJ5ID0gbmV3IEN5bGluZGVyR2VvbWV0cnkoIDAsIDAuNSwgMSwgNSwgMSApO1xyXG5cdFx0XHRfY29uZUdlb21ldHJ5LnRyYW5zbGF0ZSggMCwgLSAwLjUsIDAgKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5wb3NpdGlvbi5jb3B5KCBvcmlnaW4gKTtcclxuXHJcblx0XHR0aGlzLmxpbmUgPSBuZXcgTGluZSggX2xpbmVHZW9tZXRyeSwgbmV3IExpbmVCYXNpY01hdGVyaWFsKCB7IGNvbG9yOiBjb2xvciwgdG9uZU1hcHBlZDogZmFsc2UgfSApICk7XHJcblx0XHR0aGlzLmxpbmUubWF0cml4QXV0b1VwZGF0ZSA9IGZhbHNlO1xyXG5cdFx0dGhpcy5hZGQoIHRoaXMubGluZSApO1xyXG5cclxuXHRcdHRoaXMuY29uZSA9IG5ldyBNZXNoKCBfY29uZUdlb21ldHJ5LCBuZXcgTWVzaEJhc2ljTWF0ZXJpYWwoIHsgY29sb3I6IGNvbG9yLCB0b25lTWFwcGVkOiBmYWxzZSB9ICkgKTtcclxuXHRcdHRoaXMuY29uZS5tYXRyaXhBdXRvVXBkYXRlID0gZmFsc2U7XHJcblx0XHR0aGlzLmFkZCggdGhpcy5jb25lICk7XHJcblxyXG5cdFx0dGhpcy5zZXREaXJlY3Rpb24oIGRpciApO1xyXG5cdFx0dGhpcy5zZXRMZW5ndGgoIGxlbmd0aCwgaGVhZExlbmd0aCwgaGVhZFdpZHRoICk7XHJcblxyXG5cdH1cclxuXHJcblx0c2V0RGlyZWN0aW9uKCBkaXIgKSB7XHJcblxyXG5cdFx0Ly8gZGlyIGlzIGFzc3VtZWQgdG8gYmUgbm9ybWFsaXplZFxyXG5cclxuXHRcdGlmICggZGlyLnkgPiAwLjk5OTk5ICkge1xyXG5cclxuXHRcdFx0dGhpcy5xdWF0ZXJuaW9uLnNldCggMCwgMCwgMCwgMSApO1xyXG5cclxuXHRcdH0gZWxzZSBpZiAoIGRpci55IDwgLSAwLjk5OTk5ICkge1xyXG5cclxuXHRcdFx0dGhpcy5xdWF0ZXJuaW9uLnNldCggMSwgMCwgMCwgMCApO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRfYXhpcy5zZXQoIGRpci56LCAwLCAtIGRpci54ICkubm9ybWFsaXplKCk7XHJcblxyXG5cdFx0XHRjb25zdCByYWRpYW5zID0gTWF0aC5hY29zKCBkaXIueSApO1xyXG5cclxuXHRcdFx0dGhpcy5xdWF0ZXJuaW9uLnNldEZyb21BeGlzQW5nbGUoIF9heGlzLCByYWRpYW5zICk7XHJcblxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cdHNldExlbmd0aCggbGVuZ3RoLCBoZWFkTGVuZ3RoID0gbGVuZ3RoICogMC4yLCBoZWFkV2lkdGggPSBoZWFkTGVuZ3RoICogMC4yICkge1xyXG5cclxuXHRcdHRoaXMubGluZS5zY2FsZS5zZXQoIDEsIE1hdGgubWF4KCAwLjAwMDEsIGxlbmd0aCAtIGhlYWRMZW5ndGggKSwgMSApOyAvLyBzZWUgIzE3NDU4XHJcblx0XHR0aGlzLmxpbmUudXBkYXRlTWF0cml4KCk7XHJcblxyXG5cdFx0dGhpcy5jb25lLnNjYWxlLnNldCggaGVhZFdpZHRoLCBoZWFkTGVuZ3RoLCBoZWFkV2lkdGggKTtcclxuXHRcdHRoaXMuY29uZS5wb3NpdGlvbi55ID0gbGVuZ3RoO1xyXG5cdFx0dGhpcy5jb25lLnVwZGF0ZU1hdHJpeCgpO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldENvbG9yKCBjb2xvciApIHtcclxuXHJcblx0XHR0aGlzLmxpbmUubWF0ZXJpYWwuY29sb3Iuc2V0KCBjb2xvciApO1xyXG5cdFx0dGhpcy5jb25lLm1hdGVyaWFsLmNvbG9yLnNldCggY29sb3IgKTtcclxuXHJcblx0fVxyXG5cclxuXHRjb3B5KCBzb3VyY2UgKSB7XHJcblxyXG5cdFx0c3VwZXIuY29weSggc291cmNlLCBmYWxzZSApO1xyXG5cclxuXHRcdHRoaXMubGluZS5jb3B5KCBzb3VyY2UubGluZSApO1xyXG5cdFx0dGhpcy5jb25lLmNvcHkoIHNvdXJjZS5jb25lICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0ZGlzcG9zZSgpIHtcclxuXHJcblx0XHR0aGlzLmxpbmUuZ2VvbWV0cnkuZGlzcG9zZSgpO1xyXG5cdFx0dGhpcy5saW5lLm1hdGVyaWFsLmRpc3Bvc2UoKTtcclxuXHRcdHRoaXMuY29uZS5nZW9tZXRyeS5kaXNwb3NlKCk7XHJcblx0XHR0aGlzLmNvbmUubWF0ZXJpYWwuZGlzcG9zZSgpO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5cclxuZXhwb3J0IHsgQXJyb3dIZWxwZXIgfTtcclxuIiwiaW1wb3J0IHsgTGluZVNlZ21lbnRzIH0gZnJvbSAnLi4vb2JqZWN0cy9MaW5lU2VnbWVudHMuanMnO1xyXG5pbXBvcnQgeyBMaW5lQmFzaWNNYXRlcmlhbCB9IGZyb20gJy4uL21hdGVyaWFscy9MaW5lQmFzaWNNYXRlcmlhbC5qcyc7XHJcbmltcG9ydCB7IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUgfSBmcm9tICcuLi9jb3JlL0J1ZmZlckF0dHJpYnV0ZS5qcyc7XHJcbmltcG9ydCB7IEJ1ZmZlckdlb21ldHJ5IH0gZnJvbSAnLi4vY29yZS9CdWZmZXJHZW9tZXRyeS5qcyc7XHJcbmltcG9ydCB7IENvbG9yIH0gZnJvbSAnLi4vbWF0aC9Db2xvci5qcyc7XHJcblxyXG5jbGFzcyBBeGVzSGVscGVyIGV4dGVuZHMgTGluZVNlZ21lbnRzIHtcclxuXHJcblx0Y29uc3RydWN0b3IoIHNpemUgPSAxICkge1xyXG5cclxuXHRcdGNvbnN0IHZlcnRpY2VzID0gW1xyXG5cdFx0XHQwLCAwLCAwLFx0c2l6ZSwgMCwgMCxcclxuXHRcdFx0MCwgMCwgMCxcdDAsIHNpemUsIDAsXHJcblx0XHRcdDAsIDAsIDAsXHQwLCAwLCBzaXplXHJcblx0XHRdO1xyXG5cclxuXHRcdGNvbnN0IGNvbG9ycyA9IFtcclxuXHRcdFx0MSwgMCwgMCxcdDEsIDAuNiwgMCxcclxuXHRcdFx0MCwgMSwgMCxcdDAuNiwgMSwgMCxcclxuXHRcdFx0MCwgMCwgMSxcdDAsIDAuNiwgMVxyXG5cdFx0XTtcclxuXHJcblx0XHRjb25zdCBnZW9tZXRyeSA9IG5ldyBCdWZmZXJHZW9tZXRyeSgpO1xyXG5cdFx0Z2VvbWV0cnkuc2V0QXR0cmlidXRlKCAncG9zaXRpb24nLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggdmVydGljZXMsIDMgKSApO1xyXG5cdFx0Z2VvbWV0cnkuc2V0QXR0cmlidXRlKCAnY29sb3InLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggY29sb3JzLCAzICkgKTtcclxuXHJcblx0XHRjb25zdCBtYXRlcmlhbCA9IG5ldyBMaW5lQmFzaWNNYXRlcmlhbCggeyB2ZXJ0ZXhDb2xvcnM6IHRydWUsIHRvbmVNYXBwZWQ6IGZhbHNlIH0gKTtcclxuXHJcblx0XHRzdXBlciggZ2VvbWV0cnksIG1hdGVyaWFsICk7XHJcblxyXG5cdFx0dGhpcy50eXBlID0gJ0F4ZXNIZWxwZXInO1xyXG5cclxuXHR9XHJcblxyXG5cdHNldENvbG9ycyggeEF4aXNDb2xvciwgeUF4aXNDb2xvciwgekF4aXNDb2xvciApIHtcclxuXHJcblx0XHRjb25zdCBjb2xvciA9IG5ldyBDb2xvcigpO1xyXG5cdFx0Y29uc3QgYXJyYXkgPSB0aGlzLmdlb21ldHJ5LmF0dHJpYnV0ZXMuY29sb3IuYXJyYXk7XHJcblxyXG5cdFx0Y29sb3Iuc2V0KCB4QXhpc0NvbG9yICk7XHJcblx0XHRjb2xvci50b0FycmF5KCBhcnJheSwgMCApO1xyXG5cdFx0Y29sb3IudG9BcnJheSggYXJyYXksIDMgKTtcclxuXHJcblx0XHRjb2xvci5zZXQoIHlBeGlzQ29sb3IgKTtcclxuXHRcdGNvbG9yLnRvQXJyYXkoIGFycmF5LCA2ICk7XHJcblx0XHRjb2xvci50b0FycmF5KCBhcnJheSwgOSApO1xyXG5cclxuXHRcdGNvbG9yLnNldCggekF4aXNDb2xvciApO1xyXG5cdFx0Y29sb3IudG9BcnJheSggYXJyYXksIDEyICk7XHJcblx0XHRjb2xvci50b0FycmF5KCBhcnJheSwgMTUgKTtcclxuXHJcblx0XHR0aGlzLmdlb21ldHJ5LmF0dHJpYnV0ZXMuY29sb3IubmVlZHNVcGRhdGUgPSB0cnVlO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cclxuXHR9XHJcblxyXG5cdGRpc3Bvc2UoKSB7XHJcblxyXG5cdFx0dGhpcy5nZW9tZXRyeS5kaXNwb3NlKCk7XHJcblx0XHR0aGlzLm1hdGVyaWFsLmRpc3Bvc2UoKTtcclxuXHJcblx0fVxyXG5cclxufVxyXG5cclxuXHJcbmV4cG9ydCB7IEF4ZXNIZWxwZXIgfTtcclxuIiwiaW1wb3J0IHsgQ29sb3IgfSBmcm9tICcuLi8uLi9tYXRoL0NvbG9yLmpzJztcclxuaW1wb3J0IHsgUGF0aCB9IGZyb20gJy4vUGF0aC5qcyc7XHJcbmltcG9ydCB7IFNoYXBlIH0gZnJvbSAnLi9TaGFwZS5qcyc7XHJcbmltcG9ydCB7IFNoYXBlVXRpbHMgfSBmcm9tICcuLi9TaGFwZVV0aWxzLmpzJztcclxuXHJcbmNsYXNzIFNoYXBlUGF0aCB7XHJcblxyXG5cdGNvbnN0cnVjdG9yKCkge1xyXG5cclxuXHRcdHRoaXMudHlwZSA9ICdTaGFwZVBhdGgnO1xyXG5cclxuXHRcdHRoaXMuY29sb3IgPSBuZXcgQ29sb3IoKTtcclxuXHJcblx0XHR0aGlzLnN1YlBhdGhzID0gW107XHJcblx0XHR0aGlzLmN1cnJlbnRQYXRoID0gbnVsbDtcclxuXHJcblx0fVxyXG5cclxuXHRtb3ZlVG8oIHgsIHkgKSB7XHJcblxyXG5cdFx0dGhpcy5jdXJyZW50UGF0aCA9IG5ldyBQYXRoKCk7XHJcblx0XHR0aGlzLnN1YlBhdGhzLnB1c2goIHRoaXMuY3VycmVudFBhdGggKTtcclxuXHRcdHRoaXMuY3VycmVudFBhdGgubW92ZVRvKCB4LCB5ICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0bGluZVRvKCB4LCB5ICkge1xyXG5cclxuXHRcdHRoaXMuY3VycmVudFBhdGgubGluZVRvKCB4LCB5ICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0cXVhZHJhdGljQ3VydmVUbyggYUNQeCwgYUNQeSwgYVgsIGFZICkge1xyXG5cclxuXHRcdHRoaXMuY3VycmVudFBhdGgucXVhZHJhdGljQ3VydmVUbyggYUNQeCwgYUNQeSwgYVgsIGFZICk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblxyXG5cdH1cclxuXHJcblx0YmV6aWVyQ3VydmVUbyggYUNQMXgsIGFDUDF5LCBhQ1AyeCwgYUNQMnksIGFYLCBhWSApIHtcclxuXHJcblx0XHR0aGlzLmN1cnJlbnRQYXRoLmJlemllckN1cnZlVG8oIGFDUDF4LCBhQ1AxeSwgYUNQMngsIGFDUDJ5LCBhWCwgYVkgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHRzcGxpbmVUaHJ1KCBwdHMgKSB7XHJcblxyXG5cdFx0dGhpcy5jdXJyZW50UGF0aC5zcGxpbmVUaHJ1KCBwdHMgKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHJcblx0fVxyXG5cclxuXHR0b1NoYXBlcyggaXNDQ1cgKSB7XHJcblxyXG5cdFx0ZnVuY3Rpb24gdG9TaGFwZXNOb0hvbGVzKCBpblN1YnBhdGhzICkge1xyXG5cclxuXHRcdFx0Y29uc3Qgc2hhcGVzID0gW107XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBpblN1YnBhdGhzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XHJcblxyXG5cdFx0XHRcdGNvbnN0IHRtcFBhdGggPSBpblN1YnBhdGhzWyBpIF07XHJcblxyXG5cdFx0XHRcdGNvbnN0IHRtcFNoYXBlID0gbmV3IFNoYXBlKCk7XHJcblx0XHRcdFx0dG1wU2hhcGUuY3VydmVzID0gdG1wUGF0aC5jdXJ2ZXM7XHJcblxyXG5cdFx0XHRcdHNoYXBlcy5wdXNoKCB0bXBTaGFwZSApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0cmV0dXJuIHNoYXBlcztcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0ZnVuY3Rpb24gaXNQb2ludEluc2lkZVBvbHlnb24oIGluUHQsIGluUG9seWdvbiApIHtcclxuXHJcblx0XHRcdGNvbnN0IHBvbHlMZW4gPSBpblBvbHlnb24ubGVuZ3RoO1xyXG5cclxuXHRcdFx0Ly8gaW5QdCBvbiBwb2x5Z29uIGNvbnRvdXIgPT4gaW1tZWRpYXRlIHN1Y2Nlc3MgICAgb3JcclxuXHRcdFx0Ly8gdG9nZ2xpbmcgb2YgaW5zaWRlL291dHNpZGUgYXQgZXZlcnkgc2luZ2xlISBpbnRlcnNlY3Rpb24gcG9pbnQgb2YgYW4gZWRnZVxyXG5cdFx0XHQvLyAgd2l0aCB0aGUgaG9yaXpvbnRhbCBsaW5lIHRocm91Z2ggaW5QdCwgbGVmdCBvZiBpblB0XHJcblx0XHRcdC8vICBub3QgY291bnRpbmcgbG93ZXJZIGVuZHBvaW50cyBvZiBlZGdlcyBhbmQgd2hvbGUgZWRnZXMgb24gdGhhdCBsaW5lXHJcblx0XHRcdGxldCBpbnNpZGUgPSBmYWxzZTtcclxuXHRcdFx0Zm9yICggbGV0IHAgPSBwb2x5TGVuIC0gMSwgcSA9IDA7IHEgPCBwb2x5TGVuOyBwID0gcSArKyApIHtcclxuXHJcblx0XHRcdFx0bGV0IGVkZ2VMb3dQdCA9IGluUG9seWdvblsgcCBdO1xyXG5cdFx0XHRcdGxldCBlZGdlSGlnaFB0ID0gaW5Qb2x5Z29uWyBxIF07XHJcblxyXG5cdFx0XHRcdGxldCBlZGdlRHggPSBlZGdlSGlnaFB0LnggLSBlZGdlTG93UHQueDtcclxuXHRcdFx0XHRsZXQgZWRnZUR5ID0gZWRnZUhpZ2hQdC55IC0gZWRnZUxvd1B0Lnk7XHJcblxyXG5cdFx0XHRcdGlmICggTWF0aC5hYnMoIGVkZ2VEeSApID4gTnVtYmVyLkVQU0lMT04gKSB7XHJcblxyXG5cdFx0XHRcdFx0Ly8gbm90IHBhcmFsbGVsXHJcblx0XHRcdFx0XHRpZiAoIGVkZ2VEeSA8IDAgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRlZGdlTG93UHQgPSBpblBvbHlnb25bIHEgXTsgZWRnZUR4ID0gLSBlZGdlRHg7XHJcblx0XHRcdFx0XHRcdGVkZ2VIaWdoUHQgPSBpblBvbHlnb25bIHAgXTsgZWRnZUR5ID0gLSBlZGdlRHk7XHJcblxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdGlmICggKCBpblB0LnkgPCBlZGdlTG93UHQueSApIHx8ICggaW5QdC55ID4gZWRnZUhpZ2hQdC55ICkgKSBcdFx0Y29udGludWU7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCBpblB0LnkgPT09IGVkZ2VMb3dQdC55ICkge1xyXG5cclxuXHRcdFx0XHRcdFx0aWYgKCBpblB0LnggPT09IGVkZ2VMb3dQdC54IClcdFx0cmV0dXJuXHR0cnVlO1x0XHQvLyBpblB0IGlzIG9uIGNvbnRvdXIgP1xyXG5cdFx0XHRcdFx0XHQvLyBjb250aW51ZTtcdFx0XHRcdC8vIG5vIGludGVyc2VjdGlvbiBvciBlZGdlTG93UHQgPT4gZG9lc24ndCBjb3VudCAhISFcclxuXHJcblx0XHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdFx0Y29uc3QgcGVycEVkZ2UgPSBlZGdlRHkgKiAoIGluUHQueCAtIGVkZ2VMb3dQdC54ICkgLSBlZGdlRHggKiAoIGluUHQueSAtIGVkZ2VMb3dQdC55ICk7XHJcblx0XHRcdFx0XHRcdGlmICggcGVycEVkZ2UgPT09IDAgKVx0XHRcdFx0cmV0dXJuXHR0cnVlO1x0XHQvLyBpblB0IGlzIG9uIGNvbnRvdXIgP1xyXG5cdFx0XHRcdFx0XHRpZiAoIHBlcnBFZGdlIDwgMCApIFx0XHRcdFx0Y29udGludWU7XHJcblx0XHRcdFx0XHRcdGluc2lkZSA9ICEgaW5zaWRlO1x0XHQvLyB0cnVlIGludGVyc2VjdGlvbiBsZWZ0IG9mIGluUHRcclxuXHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0Ly8gcGFyYWxsZWwgb3IgY29sbGluZWFyXHJcblx0XHRcdFx0XHRpZiAoIGluUHQueSAhPT0gZWRnZUxvd1B0LnkgKSBcdFx0Y29udGludWU7XHRcdFx0Ly8gcGFyYWxsZWxcclxuXHRcdFx0XHRcdC8vIGVkZ2UgbGllcyBvbiB0aGUgc2FtZSBob3Jpem9udGFsIGxpbmUgYXMgaW5QdFxyXG5cdFx0XHRcdFx0aWYgKCAoICggZWRnZUhpZ2hQdC54IDw9IGluUHQueCApICYmICggaW5QdC54IDw9IGVkZ2VMb3dQdC54ICkgKSB8fFxyXG5cdFx0XHRcdFx0XHQgKCAoIGVkZ2VMb3dQdC54IDw9IGluUHQueCApICYmICggaW5QdC54IDw9IGVkZ2VIaWdoUHQueCApICkgKVx0XHRyZXR1cm5cdHRydWU7XHQvLyBpblB0OiBQb2ludCBvbiBjb250b3VyICFcclxuXHRcdFx0XHRcdC8vIGNvbnRpbnVlO1xyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRyZXR1cm5cdGluc2lkZTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Y29uc3QgaXNDbG9ja1dpc2UgPSBTaGFwZVV0aWxzLmlzQ2xvY2tXaXNlO1xyXG5cclxuXHRcdGNvbnN0IHN1YlBhdGhzID0gdGhpcy5zdWJQYXRocztcclxuXHRcdGlmICggc3ViUGF0aHMubGVuZ3RoID09PSAwICkgcmV0dXJuIFtdO1xyXG5cclxuXHRcdGxldCBzb2xpZCwgdG1wUGF0aCwgdG1wU2hhcGU7XHJcblx0XHRjb25zdCBzaGFwZXMgPSBbXTtcclxuXHJcblx0XHRpZiAoIHN1YlBhdGhzLmxlbmd0aCA9PT0gMSApIHtcclxuXHJcblx0XHRcdHRtcFBhdGggPSBzdWJQYXRoc1sgMCBdO1xyXG5cdFx0XHR0bXBTaGFwZSA9IG5ldyBTaGFwZSgpO1xyXG5cdFx0XHR0bXBTaGFwZS5jdXJ2ZXMgPSB0bXBQYXRoLmN1cnZlcztcclxuXHRcdFx0c2hhcGVzLnB1c2goIHRtcFNoYXBlICk7XHJcblx0XHRcdHJldHVybiBzaGFwZXM7XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGxldCBob2xlc0ZpcnN0ID0gISBpc0Nsb2NrV2lzZSggc3ViUGF0aHNbIDAgXS5nZXRQb2ludHMoKSApO1xyXG5cdFx0aG9sZXNGaXJzdCA9IGlzQ0NXID8gISBob2xlc0ZpcnN0IDogaG9sZXNGaXJzdDtcclxuXHJcblx0XHQvLyBjb25zb2xlLmxvZyhcIkhvbGVzIGZpcnN0XCIsIGhvbGVzRmlyc3QpO1xyXG5cclxuXHRcdGNvbnN0IGJldHRlclNoYXBlSG9sZXMgPSBbXTtcclxuXHRcdGNvbnN0IG5ld1NoYXBlcyA9IFtdO1xyXG5cdFx0bGV0IG5ld1NoYXBlSG9sZXMgPSBbXTtcclxuXHRcdGxldCBtYWluSWR4ID0gMDtcclxuXHRcdGxldCB0bXBQb2ludHM7XHJcblxyXG5cdFx0bmV3U2hhcGVzWyBtYWluSWR4IF0gPSB1bmRlZmluZWQ7XHJcblx0XHRuZXdTaGFwZUhvbGVzWyBtYWluSWR4IF0gPSBbXTtcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBzdWJQYXRocy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xyXG5cclxuXHRcdFx0dG1wUGF0aCA9IHN1YlBhdGhzWyBpIF07XHJcblx0XHRcdHRtcFBvaW50cyA9IHRtcFBhdGguZ2V0UG9pbnRzKCk7XHJcblx0XHRcdHNvbGlkID0gaXNDbG9ja1dpc2UoIHRtcFBvaW50cyApO1xyXG5cdFx0XHRzb2xpZCA9IGlzQ0NXID8gISBzb2xpZCA6IHNvbGlkO1xyXG5cclxuXHRcdFx0aWYgKCBzb2xpZCApIHtcclxuXHJcblx0XHRcdFx0aWYgKCAoICEgaG9sZXNGaXJzdCApICYmICggbmV3U2hhcGVzWyBtYWluSWR4IF0gKSApXHRtYWluSWR4ICsrO1xyXG5cclxuXHRcdFx0XHRuZXdTaGFwZXNbIG1haW5JZHggXSA9IHsgczogbmV3IFNoYXBlKCksIHA6IHRtcFBvaW50cyB9O1xyXG5cdFx0XHRcdG5ld1NoYXBlc1sgbWFpbklkeCBdLnMuY3VydmVzID0gdG1wUGF0aC5jdXJ2ZXM7XHJcblxyXG5cdFx0XHRcdGlmICggaG9sZXNGaXJzdCApXHRtYWluSWR4ICsrO1xyXG5cdFx0XHRcdG5ld1NoYXBlSG9sZXNbIG1haW5JZHggXSA9IFtdO1xyXG5cclxuXHRcdFx0XHQvL2NvbnNvbGUubG9nKCdjdycsIGkpO1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0bmV3U2hhcGVIb2xlc1sgbWFpbklkeCBdLnB1c2goIHsgaDogdG1wUGF0aCwgcDogdG1wUG9pbnRzWyAwIF0gfSApO1xyXG5cclxuXHRcdFx0XHQvL2NvbnNvbGUubG9nKCdjY3cnLCBpKTtcclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gb25seSBIb2xlcz8gLT4gcHJvYmFibHkgYWxsIFNoYXBlcyB3aXRoIHdyb25nIG9yaWVudGF0aW9uXHJcblx0XHRpZiAoICEgbmV3U2hhcGVzWyAwIF0gKVx0cmV0dXJuXHR0b1NoYXBlc05vSG9sZXMoIHN1YlBhdGhzICk7XHJcblxyXG5cclxuXHRcdGlmICggbmV3U2hhcGVzLmxlbmd0aCA+IDEgKSB7XHJcblxyXG5cdFx0XHRsZXQgYW1iaWd1b3VzID0gZmFsc2U7XHJcblx0XHRcdGxldCB0b0NoYW5nZSA9IDA7XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgc0lkeCA9IDAsIHNMZW4gPSBuZXdTaGFwZXMubGVuZ3RoOyBzSWR4IDwgc0xlbjsgc0lkeCArKyApIHtcclxuXHJcblx0XHRcdFx0YmV0dGVyU2hhcGVIb2xlc1sgc0lkeCBdID0gW107XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgc0lkeCA9IDAsIHNMZW4gPSBuZXdTaGFwZXMubGVuZ3RoOyBzSWR4IDwgc0xlbjsgc0lkeCArKyApIHtcclxuXHJcblx0XHRcdFx0Y29uc3Qgc2hvID0gbmV3U2hhcGVIb2xlc1sgc0lkeCBdO1xyXG5cclxuXHRcdFx0XHRmb3IgKCBsZXQgaElkeCA9IDA7IGhJZHggPCBzaG8ubGVuZ3RoOyBoSWR4ICsrICkge1xyXG5cclxuXHRcdFx0XHRcdGNvbnN0IGhvID0gc2hvWyBoSWR4IF07XHJcblx0XHRcdFx0XHRsZXQgaG9sZV91bmFzc2lnbmVkID0gdHJ1ZTtcclxuXHJcblx0XHRcdFx0XHRmb3IgKCBsZXQgczJJZHggPSAwOyBzMklkeCA8IG5ld1NoYXBlcy5sZW5ndGg7IHMySWR4ICsrICkge1xyXG5cclxuXHRcdFx0XHRcdFx0aWYgKCBpc1BvaW50SW5zaWRlUG9seWdvbiggaG8ucCwgbmV3U2hhcGVzWyBzMklkeCBdLnAgKSApIHtcclxuXHJcblx0XHRcdFx0XHRcdFx0aWYgKCBzSWR4ICE9PSBzMklkeCApXHR0b0NoYW5nZSArKztcclxuXHJcblx0XHRcdFx0XHRcdFx0aWYgKCBob2xlX3VuYXNzaWduZWQgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0aG9sZV91bmFzc2lnbmVkID0gZmFsc2U7XHJcblx0XHRcdFx0XHRcdFx0XHRiZXR0ZXJTaGFwZUhvbGVzWyBzMklkeCBdLnB1c2goIGhvICk7XHJcblxyXG5cdFx0XHRcdFx0XHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0YW1iaWd1b3VzID0gdHJ1ZTtcclxuXHJcblx0XHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRpZiAoIGhvbGVfdW5hc3NpZ25lZCApIHtcclxuXHJcblx0XHRcdFx0XHRcdGJldHRlclNoYXBlSG9sZXNbIHNJZHggXS5wdXNoKCBobyApO1xyXG5cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0aWYgKCB0b0NoYW5nZSA+IDAgJiYgYW1iaWd1b3VzID09PSBmYWxzZSApIHtcclxuXHJcblx0XHRcdFx0bmV3U2hhcGVIb2xlcyA9IGJldHRlclNoYXBlSG9sZXM7XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdGxldCB0bXBIb2xlcztcclxuXHJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gbmV3U2hhcGVzLmxlbmd0aDsgaSA8IGlsOyBpICsrICkge1xyXG5cclxuXHRcdFx0dG1wU2hhcGUgPSBuZXdTaGFwZXNbIGkgXS5zO1xyXG5cdFx0XHRzaGFwZXMucHVzaCggdG1wU2hhcGUgKTtcclxuXHRcdFx0dG1wSG9sZXMgPSBuZXdTaGFwZUhvbGVzWyBpIF07XHJcblxyXG5cdFx0XHRmb3IgKCBsZXQgaiA9IDAsIGpsID0gdG1wSG9sZXMubGVuZ3RoOyBqIDwgamw7IGogKysgKSB7XHJcblxyXG5cdFx0XHRcdHRtcFNoYXBlLmhvbGVzLnB1c2goIHRtcEhvbGVzWyBqIF0uaCApO1xyXG5cclxuXHRcdFx0fVxyXG5cclxuXHRcdH1cclxuXHJcblx0XHQvL2NvbnNvbGUubG9nKFwic2hhcGVcIiwgc2hhcGVzKTtcclxuXHJcblx0XHRyZXR1cm4gc2hhcGVzO1xyXG5cclxuXHR9XHJcblxyXG59XHJcblxyXG5cclxuZXhwb3J0IHsgU2hhcGVQYXRoIH07XHJcbiIsImltcG9ydCB7IFJFVklTSU9OIH0gZnJvbSAnLi9jb25zdGFudHMuanMnO1xyXG5cclxuZXhwb3J0IHsgV2ViR0xBcnJheVJlbmRlclRhcmdldCB9IGZyb20gJy4vcmVuZGVyZXJzL1dlYkdMQXJyYXlSZW5kZXJUYXJnZXQuanMnO1xyXG5leHBvcnQgeyBXZWJHTDNEUmVuZGVyVGFyZ2V0IH0gZnJvbSAnLi9yZW5kZXJlcnMvV2ViR0wzRFJlbmRlclRhcmdldC5qcyc7XHJcbmV4cG9ydCB7IFdlYkdMTXVsdGlwbGVSZW5kZXJUYXJnZXRzIH0gZnJvbSAnLi9yZW5kZXJlcnMvV2ViR0xNdWx0aXBsZVJlbmRlclRhcmdldHMuanMnO1xyXG5leHBvcnQgeyBXZWJHTEN1YmVSZW5kZXJUYXJnZXQgfSBmcm9tICcuL3JlbmRlcmVycy9XZWJHTEN1YmVSZW5kZXJUYXJnZXQuanMnO1xyXG5leHBvcnQgeyBXZWJHTFJlbmRlclRhcmdldCB9IGZyb20gJy4vcmVuZGVyZXJzL1dlYkdMUmVuZGVyVGFyZ2V0LmpzJztcclxuZXhwb3J0IHsgV2ViR0xSZW5kZXJlciB9IGZyb20gJy4vcmVuZGVyZXJzL1dlYkdMUmVuZGVyZXIuanMnO1xyXG5leHBvcnQgeyBXZWJHTDFSZW5kZXJlciB9IGZyb20gJy4vcmVuZGVyZXJzL1dlYkdMMVJlbmRlcmVyLmpzJztcclxuZXhwb3J0IHsgU2hhZGVyTGliIH0gZnJvbSAnLi9yZW5kZXJlcnMvc2hhZGVycy9TaGFkZXJMaWIuanMnO1xyXG5leHBvcnQgeyBVbmlmb3Jtc0xpYiB9IGZyb20gJy4vcmVuZGVyZXJzL3NoYWRlcnMvVW5pZm9ybXNMaWIuanMnO1xyXG5leHBvcnQgeyBVbmlmb3Jtc1V0aWxzIH0gZnJvbSAnLi9yZW5kZXJlcnMvc2hhZGVycy9Vbmlmb3Jtc1V0aWxzLmpzJztcclxuZXhwb3J0IHsgU2hhZGVyQ2h1bmsgfSBmcm9tICcuL3JlbmRlcmVycy9zaGFkZXJzL1NoYWRlckNodW5rLmpzJztcclxuZXhwb3J0IHsgRm9nRXhwMiB9IGZyb20gJy4vc2NlbmVzL0ZvZ0V4cDIuanMnO1xyXG5leHBvcnQgeyBGb2cgfSBmcm9tICcuL3NjZW5lcy9Gb2cuanMnO1xyXG5leHBvcnQgeyBTY2VuZSB9IGZyb20gJy4vc2NlbmVzL1NjZW5lLmpzJztcclxuZXhwb3J0IHsgU3ByaXRlIH0gZnJvbSAnLi9vYmplY3RzL1Nwcml0ZS5qcyc7XHJcbmV4cG9ydCB7IExPRCB9IGZyb20gJy4vb2JqZWN0cy9MT0QuanMnO1xyXG5leHBvcnQgeyBTa2lubmVkTWVzaCB9IGZyb20gJy4vb2JqZWN0cy9Ta2lubmVkTWVzaC5qcyc7XHJcbmV4cG9ydCB7IFNrZWxldG9uIH0gZnJvbSAnLi9vYmplY3RzL1NrZWxldG9uLmpzJztcclxuZXhwb3J0IHsgQm9uZSB9IGZyb20gJy4vb2JqZWN0cy9Cb25lLmpzJztcclxuZXhwb3J0IHsgTWVzaCB9IGZyb20gJy4vb2JqZWN0cy9NZXNoLmpzJztcclxuZXhwb3J0IHsgSW5zdGFuY2VkTWVzaCB9IGZyb20gJy4vb2JqZWN0cy9JbnN0YW5jZWRNZXNoLmpzJztcclxuZXhwb3J0IHsgQmF0Y2hlZE1lc2ggfSBmcm9tICcuL29iamVjdHMvQmF0Y2hlZE1lc2guanMnO1xyXG5leHBvcnQgeyBMaW5lU2VnbWVudHMgfSBmcm9tICcuL29iamVjdHMvTGluZVNlZ21lbnRzLmpzJztcclxuZXhwb3J0IHsgTGluZUxvb3AgfSBmcm9tICcuL29iamVjdHMvTGluZUxvb3AuanMnO1xyXG5leHBvcnQgeyBMaW5lIH0gZnJvbSAnLi9vYmplY3RzL0xpbmUuanMnO1xyXG5leHBvcnQgeyBQb2ludHMgfSBmcm9tICcuL29iamVjdHMvUG9pbnRzLmpzJztcclxuZXhwb3J0IHsgR3JvdXAgfSBmcm9tICcuL29iamVjdHMvR3JvdXAuanMnO1xyXG5leHBvcnQgeyBWaWRlb1RleHR1cmUgfSBmcm9tICcuL3RleHR1cmVzL1ZpZGVvVGV4dHVyZS5qcyc7XHJcbmV4cG9ydCB7IEZyYW1lYnVmZmVyVGV4dHVyZSB9IGZyb20gJy4vdGV4dHVyZXMvRnJhbWVidWZmZXJUZXh0dXJlLmpzJztcclxuZXhwb3J0IHsgU291cmNlIH0gZnJvbSAnLi90ZXh0dXJlcy9Tb3VyY2UuanMnO1xyXG5leHBvcnQgeyBEYXRhVGV4dHVyZSB9IGZyb20gJy4vdGV4dHVyZXMvRGF0YVRleHR1cmUuanMnO1xyXG5leHBvcnQgeyBEYXRhQXJyYXlUZXh0dXJlIH0gZnJvbSAnLi90ZXh0dXJlcy9EYXRhQXJyYXlUZXh0dXJlLmpzJztcclxuZXhwb3J0IHsgRGF0YTNEVGV4dHVyZSB9IGZyb20gJy4vdGV4dHVyZXMvRGF0YTNEVGV4dHVyZS5qcyc7XHJcbmV4cG9ydCB7IENvbXByZXNzZWRUZXh0dXJlIH0gZnJvbSAnLi90ZXh0dXJlcy9Db21wcmVzc2VkVGV4dHVyZS5qcyc7XHJcbmV4cG9ydCB7IENvbXByZXNzZWRBcnJheVRleHR1cmUgfSBmcm9tICcuL3RleHR1cmVzL0NvbXByZXNzZWRBcnJheVRleHR1cmUuanMnO1xyXG5leHBvcnQgeyBDb21wcmVzc2VkQ3ViZVRleHR1cmUgfSBmcm9tICcuL3RleHR1cmVzL0NvbXByZXNzZWRDdWJlVGV4dHVyZS5qcyc7XHJcbmV4cG9ydCB7IEN1YmVUZXh0dXJlIH0gZnJvbSAnLi90ZXh0dXJlcy9DdWJlVGV4dHVyZS5qcyc7XHJcbmV4cG9ydCB7IENhbnZhc1RleHR1cmUgfSBmcm9tICcuL3RleHR1cmVzL0NhbnZhc1RleHR1cmUuanMnO1xyXG5leHBvcnQgeyBEZXB0aFRleHR1cmUgfSBmcm9tICcuL3RleHR1cmVzL0RlcHRoVGV4dHVyZS5qcyc7XHJcbmV4cG9ydCB7IFRleHR1cmUgfSBmcm9tICcuL3RleHR1cmVzL1RleHR1cmUuanMnO1xyXG5leHBvcnQgKiBmcm9tICcuL2dlb21ldHJpZXMvR2VvbWV0cmllcy5qcyc7XHJcbmV4cG9ydCAqIGZyb20gJy4vbWF0ZXJpYWxzL01hdGVyaWFscy5qcyc7XHJcbmV4cG9ydCB7IEFuaW1hdGlvbkxvYWRlciB9IGZyb20gJy4vbG9hZGVycy9BbmltYXRpb25Mb2FkZXIuanMnO1xyXG5leHBvcnQgeyBDb21wcmVzc2VkVGV4dHVyZUxvYWRlciB9IGZyb20gJy4vbG9hZGVycy9Db21wcmVzc2VkVGV4dHVyZUxvYWRlci5qcyc7XHJcbmV4cG9ydCB7IEN1YmVUZXh0dXJlTG9hZGVyIH0gZnJvbSAnLi9sb2FkZXJzL0N1YmVUZXh0dXJlTG9hZGVyLmpzJztcclxuZXhwb3J0IHsgRGF0YVRleHR1cmVMb2FkZXIgfSBmcm9tICcuL2xvYWRlcnMvRGF0YVRleHR1cmVMb2FkZXIuanMnO1xyXG5leHBvcnQgeyBUZXh0dXJlTG9hZGVyIH0gZnJvbSAnLi9sb2FkZXJzL1RleHR1cmVMb2FkZXIuanMnO1xyXG5leHBvcnQgeyBPYmplY3RMb2FkZXIgfSBmcm9tICcuL2xvYWRlcnMvT2JqZWN0TG9hZGVyLmpzJztcclxuZXhwb3J0IHsgTWF0ZXJpYWxMb2FkZXIgfSBmcm9tICcuL2xvYWRlcnMvTWF0ZXJpYWxMb2FkZXIuanMnO1xyXG5leHBvcnQgeyBCdWZmZXJHZW9tZXRyeUxvYWRlciB9IGZyb20gJy4vbG9hZGVycy9CdWZmZXJHZW9tZXRyeUxvYWRlci5qcyc7XHJcbmV4cG9ydCB7IERlZmF1bHRMb2FkaW5nTWFuYWdlciwgTG9hZGluZ01hbmFnZXIgfSBmcm9tICcuL2xvYWRlcnMvTG9hZGluZ01hbmFnZXIuanMnO1xyXG5leHBvcnQgeyBJbWFnZUxvYWRlciB9IGZyb20gJy4vbG9hZGVycy9JbWFnZUxvYWRlci5qcyc7XHJcbmV4cG9ydCB7IEltYWdlQml0bWFwTG9hZGVyIH0gZnJvbSAnLi9sb2FkZXJzL0ltYWdlQml0bWFwTG9hZGVyLmpzJztcclxuZXhwb3J0IHsgRmlsZUxvYWRlciB9IGZyb20gJy4vbG9hZGVycy9GaWxlTG9hZGVyLmpzJztcclxuZXhwb3J0IHsgTG9hZGVyIH0gZnJvbSAnLi9sb2FkZXJzL0xvYWRlci5qcyc7XHJcbmV4cG9ydCB7IExvYWRlclV0aWxzIH0gZnJvbSAnLi9sb2FkZXJzL0xvYWRlclV0aWxzLmpzJztcclxuZXhwb3J0IHsgQ2FjaGUgfSBmcm9tICcuL2xvYWRlcnMvQ2FjaGUuanMnO1xyXG5leHBvcnQgeyBBdWRpb0xvYWRlciB9IGZyb20gJy4vbG9hZGVycy9BdWRpb0xvYWRlci5qcyc7XHJcbmV4cG9ydCB7IFNwb3RMaWdodCB9IGZyb20gJy4vbGlnaHRzL1Nwb3RMaWdodC5qcyc7XHJcbmV4cG9ydCB7IFBvaW50TGlnaHQgfSBmcm9tICcuL2xpZ2h0cy9Qb2ludExpZ2h0LmpzJztcclxuZXhwb3J0IHsgUmVjdEFyZWFMaWdodCB9IGZyb20gJy4vbGlnaHRzL1JlY3RBcmVhTGlnaHQuanMnO1xyXG5leHBvcnQgeyBIZW1pc3BoZXJlTGlnaHQgfSBmcm9tICcuL2xpZ2h0cy9IZW1pc3BoZXJlTGlnaHQuanMnO1xyXG5leHBvcnQgeyBEaXJlY3Rpb25hbExpZ2h0IH0gZnJvbSAnLi9saWdodHMvRGlyZWN0aW9uYWxMaWdodC5qcyc7XHJcbmV4cG9ydCB7IEFtYmllbnRMaWdodCB9IGZyb20gJy4vbGlnaHRzL0FtYmllbnRMaWdodC5qcyc7XHJcbmV4cG9ydCB7IExpZ2h0IH0gZnJvbSAnLi9saWdodHMvTGlnaHQuanMnO1xyXG5leHBvcnQgeyBMaWdodFByb2JlIH0gZnJvbSAnLi9saWdodHMvTGlnaHRQcm9iZS5qcyc7XHJcbmV4cG9ydCB7IFN0ZXJlb0NhbWVyYSB9IGZyb20gJy4vY2FtZXJhcy9TdGVyZW9DYW1lcmEuanMnO1xyXG5leHBvcnQgeyBQZXJzcGVjdGl2ZUNhbWVyYSB9IGZyb20gJy4vY2FtZXJhcy9QZXJzcGVjdGl2ZUNhbWVyYS5qcyc7XHJcbmV4cG9ydCB7IE9ydGhvZ3JhcGhpY0NhbWVyYSB9IGZyb20gJy4vY2FtZXJhcy9PcnRob2dyYXBoaWNDYW1lcmEuanMnO1xyXG5leHBvcnQgeyBDdWJlQ2FtZXJhIH0gZnJvbSAnLi9jYW1lcmFzL0N1YmVDYW1lcmEuanMnO1xyXG5leHBvcnQgeyBBcnJheUNhbWVyYSB9IGZyb20gJy4vY2FtZXJhcy9BcnJheUNhbWVyYS5qcyc7XHJcbmV4cG9ydCB7IENhbWVyYSB9IGZyb20gJy4vY2FtZXJhcy9DYW1lcmEuanMnO1xyXG5leHBvcnQgeyBBdWRpb0xpc3RlbmVyIH0gZnJvbSAnLi9hdWRpby9BdWRpb0xpc3RlbmVyLmpzJztcclxuZXhwb3J0IHsgUG9zaXRpb25hbEF1ZGlvIH0gZnJvbSAnLi9hdWRpby9Qb3NpdGlvbmFsQXVkaW8uanMnO1xyXG5leHBvcnQgeyBBdWRpb0NvbnRleHQgfSBmcm9tICcuL2F1ZGlvL0F1ZGlvQ29udGV4dC5qcyc7XHJcbmV4cG9ydCB7IEF1ZGlvQW5hbHlzZXIgfSBmcm9tICcuL2F1ZGlvL0F1ZGlvQW5hbHlzZXIuanMnO1xyXG5leHBvcnQgeyBBdWRpbyB9IGZyb20gJy4vYXVkaW8vQXVkaW8uanMnO1xyXG5leHBvcnQgeyBWZWN0b3JLZXlmcmFtZVRyYWNrIH0gZnJvbSAnLi9hbmltYXRpb24vdHJhY2tzL1ZlY3RvcktleWZyYW1lVHJhY2suanMnO1xyXG5leHBvcnQgeyBTdHJpbmdLZXlmcmFtZVRyYWNrIH0gZnJvbSAnLi9hbmltYXRpb24vdHJhY2tzL1N0cmluZ0tleWZyYW1lVHJhY2suanMnO1xyXG5leHBvcnQgeyBRdWF0ZXJuaW9uS2V5ZnJhbWVUcmFjayB9IGZyb20gJy4vYW5pbWF0aW9uL3RyYWNrcy9RdWF0ZXJuaW9uS2V5ZnJhbWVUcmFjay5qcyc7XHJcbmV4cG9ydCB7IE51bWJlcktleWZyYW1lVHJhY2sgfSBmcm9tICcuL2FuaW1hdGlvbi90cmFja3MvTnVtYmVyS2V5ZnJhbWVUcmFjay5qcyc7XHJcbmV4cG9ydCB7IENvbG9yS2V5ZnJhbWVUcmFjayB9IGZyb20gJy4vYW5pbWF0aW9uL3RyYWNrcy9Db2xvcktleWZyYW1lVHJhY2suanMnO1xyXG5leHBvcnQgeyBCb29sZWFuS2V5ZnJhbWVUcmFjayB9IGZyb20gJy4vYW5pbWF0aW9uL3RyYWNrcy9Cb29sZWFuS2V5ZnJhbWVUcmFjay5qcyc7XHJcbmV4cG9ydCB7IFByb3BlcnR5TWl4ZXIgfSBmcm9tICcuL2FuaW1hdGlvbi9Qcm9wZXJ0eU1peGVyLmpzJztcclxuZXhwb3J0IHsgUHJvcGVydHlCaW5kaW5nIH0gZnJvbSAnLi9hbmltYXRpb24vUHJvcGVydHlCaW5kaW5nLmpzJztcclxuZXhwb3J0IHsgS2V5ZnJhbWVUcmFjayB9IGZyb20gJy4vYW5pbWF0aW9uL0tleWZyYW1lVHJhY2suanMnO1xyXG5leHBvcnQgeyBBbmltYXRpb25VdGlscyB9IGZyb20gJy4vYW5pbWF0aW9uL0FuaW1hdGlvblV0aWxzLmpzJztcclxuZXhwb3J0IHsgQW5pbWF0aW9uT2JqZWN0R3JvdXAgfSBmcm9tICcuL2FuaW1hdGlvbi9BbmltYXRpb25PYmplY3RHcm91cC5qcyc7XHJcbmV4cG9ydCB7IEFuaW1hdGlvbk1peGVyIH0gZnJvbSAnLi9hbmltYXRpb24vQW5pbWF0aW9uTWl4ZXIuanMnO1xyXG5leHBvcnQgeyBBbmltYXRpb25DbGlwIH0gZnJvbSAnLi9hbmltYXRpb24vQW5pbWF0aW9uQ2xpcC5qcyc7XHJcbmV4cG9ydCB7IEFuaW1hdGlvbkFjdGlvbiB9IGZyb20gJy4vYW5pbWF0aW9uL0FuaW1hdGlvbkFjdGlvbi5qcyc7XHJcbmV4cG9ydCB7IFJlbmRlclRhcmdldCB9IGZyb20gJy4vY29yZS9SZW5kZXJUYXJnZXQuanMnO1xyXG5leHBvcnQgeyBVbmlmb3JtIH0gZnJvbSAnLi9jb3JlL1VuaWZvcm0uanMnO1xyXG5leHBvcnQgeyBVbmlmb3Jtc0dyb3VwIH0gZnJvbSAnLi9jb3JlL1VuaWZvcm1zR3JvdXAuanMnO1xyXG5leHBvcnQgeyBJbnN0YW5jZWRCdWZmZXJHZW9tZXRyeSB9IGZyb20gJy4vY29yZS9JbnN0YW5jZWRCdWZmZXJHZW9tZXRyeS5qcyc7XHJcbmV4cG9ydCB7IEJ1ZmZlckdlb21ldHJ5IH0gZnJvbSAnLi9jb3JlL0J1ZmZlckdlb21ldHJ5LmpzJztcclxuZXhwb3J0IHsgSW50ZXJsZWF2ZWRCdWZmZXJBdHRyaWJ1dGUgfSBmcm9tICcuL2NvcmUvSW50ZXJsZWF2ZWRCdWZmZXJBdHRyaWJ1dGUuanMnO1xyXG5leHBvcnQgeyBJbnN0YW5jZWRJbnRlcmxlYXZlZEJ1ZmZlciB9IGZyb20gJy4vY29yZS9JbnN0YW5jZWRJbnRlcmxlYXZlZEJ1ZmZlci5qcyc7XHJcbmV4cG9ydCB7IEludGVybGVhdmVkQnVmZmVyIH0gZnJvbSAnLi9jb3JlL0ludGVybGVhdmVkQnVmZmVyLmpzJztcclxuZXhwb3J0IHsgSW5zdGFuY2VkQnVmZmVyQXR0cmlidXRlIH0gZnJvbSAnLi9jb3JlL0luc3RhbmNlZEJ1ZmZlckF0dHJpYnV0ZS5qcyc7XHJcbmV4cG9ydCB7IEdMQnVmZmVyQXR0cmlidXRlIH0gZnJvbSAnLi9jb3JlL0dMQnVmZmVyQXR0cmlidXRlLmpzJztcclxuZXhwb3J0ICogZnJvbSAnLi9jb3JlL0J1ZmZlckF0dHJpYnV0ZS5qcyc7XHJcbmV4cG9ydCB7IE9iamVjdDNEIH0gZnJvbSAnLi9jb3JlL09iamVjdDNELmpzJztcclxuZXhwb3J0IHsgUmF5Y2FzdGVyIH0gZnJvbSAnLi9jb3JlL1JheWNhc3Rlci5qcyc7XHJcbmV4cG9ydCB7IExheWVycyB9IGZyb20gJy4vY29yZS9MYXllcnMuanMnO1xyXG5leHBvcnQgeyBFdmVudERpc3BhdGNoZXIgfSBmcm9tICcuL2NvcmUvRXZlbnREaXNwYXRjaGVyLmpzJztcclxuZXhwb3J0IHsgQ2xvY2sgfSBmcm9tICcuL2NvcmUvQ2xvY2suanMnO1xyXG5leHBvcnQgeyBRdWF0ZXJuaW9uTGluZWFySW50ZXJwb2xhbnQgfSBmcm9tICcuL21hdGgvaW50ZXJwb2xhbnRzL1F1YXRlcm5pb25MaW5lYXJJbnRlcnBvbGFudC5qcyc7XHJcbmV4cG9ydCB7IExpbmVhckludGVycG9sYW50IH0gZnJvbSAnLi9tYXRoL2ludGVycG9sYW50cy9MaW5lYXJJbnRlcnBvbGFudC5qcyc7XHJcbmV4cG9ydCB7IERpc2NyZXRlSW50ZXJwb2xhbnQgfSBmcm9tICcuL21hdGgvaW50ZXJwb2xhbnRzL0Rpc2NyZXRlSW50ZXJwb2xhbnQuanMnO1xyXG5leHBvcnQgeyBDdWJpY0ludGVycG9sYW50IH0gZnJvbSAnLi9tYXRoL2ludGVycG9sYW50cy9DdWJpY0ludGVycG9sYW50LmpzJztcclxuZXhwb3J0IHsgSW50ZXJwb2xhbnQgfSBmcm9tICcuL21hdGgvSW50ZXJwb2xhbnQuanMnO1xyXG5leHBvcnQgeyBUcmlhbmdsZSB9IGZyb20gJy4vbWF0aC9UcmlhbmdsZS5qcyc7XHJcbmV4cG9ydCB7IE1hdGhVdGlscyB9IGZyb20gJy4vbWF0aC9NYXRoVXRpbHMuanMnO1xyXG5leHBvcnQgeyBTcGhlcmljYWwgfSBmcm9tICcuL21hdGgvU3BoZXJpY2FsLmpzJztcclxuZXhwb3J0IHsgQ3lsaW5kcmljYWwgfSBmcm9tICcuL21hdGgvQ3lsaW5kcmljYWwuanMnO1xyXG5leHBvcnQgeyBQbGFuZSB9IGZyb20gJy4vbWF0aC9QbGFuZS5qcyc7XHJcbmV4cG9ydCB7IEZydXN0dW0gfSBmcm9tICcuL21hdGgvRnJ1c3R1bS5qcyc7XHJcbmV4cG9ydCB7IFNwaGVyZSB9IGZyb20gJy4vbWF0aC9TcGhlcmUuanMnO1xyXG5leHBvcnQgeyBSYXkgfSBmcm9tICcuL21hdGgvUmF5LmpzJztcclxuZXhwb3J0IHsgTWF0cml4NCB9IGZyb20gJy4vbWF0aC9NYXRyaXg0LmpzJztcclxuZXhwb3J0IHsgTWF0cml4MyB9IGZyb20gJy4vbWF0aC9NYXRyaXgzLmpzJztcclxuZXhwb3J0IHsgQm94MyB9IGZyb20gJy4vbWF0aC9Cb3gzLmpzJztcclxuZXhwb3J0IHsgQm94MiB9IGZyb20gJy4vbWF0aC9Cb3gyLmpzJztcclxuZXhwb3J0IHsgTGluZTMgfSBmcm9tICcuL21hdGgvTGluZTMuanMnO1xyXG5leHBvcnQgeyBFdWxlciB9IGZyb20gJy4vbWF0aC9FdWxlci5qcyc7XHJcbmV4cG9ydCB7IFZlY3RvcjQgfSBmcm9tICcuL21hdGgvVmVjdG9yNC5qcyc7XHJcbmV4cG9ydCB7IFZlY3RvcjMgfSBmcm9tICcuL21hdGgvVmVjdG9yMy5qcyc7XHJcbmV4cG9ydCB7IFZlY3RvcjIgfSBmcm9tICcuL21hdGgvVmVjdG9yMi5qcyc7XHJcbmV4cG9ydCB7IFF1YXRlcm5pb24gfSBmcm9tICcuL21hdGgvUXVhdGVybmlvbi5qcyc7XHJcbmV4cG9ydCB7IENvbG9yIH0gZnJvbSAnLi9tYXRoL0NvbG9yLmpzJztcclxuZXhwb3J0IHsgQ29sb3JNYW5hZ2VtZW50IH0gZnJvbSAnLi9tYXRoL0NvbG9yTWFuYWdlbWVudC5qcyc7XHJcbmV4cG9ydCB7IFNwaGVyaWNhbEhhcm1vbmljczMgfSBmcm9tICcuL21hdGgvU3BoZXJpY2FsSGFybW9uaWNzMy5qcyc7XHJcbmV4cG9ydCB7IFNwb3RMaWdodEhlbHBlciB9IGZyb20gJy4vaGVscGVycy9TcG90TGlnaHRIZWxwZXIuanMnO1xyXG5leHBvcnQgeyBTa2VsZXRvbkhlbHBlciB9IGZyb20gJy4vaGVscGVycy9Ta2VsZXRvbkhlbHBlci5qcyc7XHJcbmV4cG9ydCB7IFBvaW50TGlnaHRIZWxwZXIgfSBmcm9tICcuL2hlbHBlcnMvUG9pbnRMaWdodEhlbHBlci5qcyc7XHJcbmV4cG9ydCB7IEhlbWlzcGhlcmVMaWdodEhlbHBlciB9IGZyb20gJy4vaGVscGVycy9IZW1pc3BoZXJlTGlnaHRIZWxwZXIuanMnO1xyXG5leHBvcnQgeyBHcmlkSGVscGVyIH0gZnJvbSAnLi9oZWxwZXJzL0dyaWRIZWxwZXIuanMnO1xyXG5leHBvcnQgeyBQb2xhckdyaWRIZWxwZXIgfSBmcm9tICcuL2hlbHBlcnMvUG9sYXJHcmlkSGVscGVyLmpzJztcclxuZXhwb3J0IHsgRGlyZWN0aW9uYWxMaWdodEhlbHBlciB9IGZyb20gJy4vaGVscGVycy9EaXJlY3Rpb25hbExpZ2h0SGVscGVyLmpzJztcclxuZXhwb3J0IHsgQ2FtZXJhSGVscGVyIH0gZnJvbSAnLi9oZWxwZXJzL0NhbWVyYUhlbHBlci5qcyc7XHJcbmV4cG9ydCB7IEJveEhlbHBlciB9IGZyb20gJy4vaGVscGVycy9Cb3hIZWxwZXIuanMnO1xyXG5leHBvcnQgeyBCb3gzSGVscGVyIH0gZnJvbSAnLi9oZWxwZXJzL0JveDNIZWxwZXIuanMnO1xyXG5leHBvcnQgeyBQbGFuZUhlbHBlciB9IGZyb20gJy4vaGVscGVycy9QbGFuZUhlbHBlci5qcyc7XHJcbmV4cG9ydCB7IEFycm93SGVscGVyIH0gZnJvbSAnLi9oZWxwZXJzL0Fycm93SGVscGVyLmpzJztcclxuZXhwb3J0IHsgQXhlc0hlbHBlciB9IGZyb20gJy4vaGVscGVycy9BeGVzSGVscGVyLmpzJztcclxuZXhwb3J0ICogZnJvbSAnLi9leHRyYXMvY3VydmVzL0N1cnZlcy5qcyc7XHJcbmV4cG9ydCB7IFNoYXBlIH0gZnJvbSAnLi9leHRyYXMvY29yZS9TaGFwZS5qcyc7XHJcbmV4cG9ydCB7IFBhdGggfSBmcm9tICcuL2V4dHJhcy9jb3JlL1BhdGguanMnO1xyXG5leHBvcnQgeyBTaGFwZVBhdGggfSBmcm9tICcuL2V4dHJhcy9jb3JlL1NoYXBlUGF0aC5qcyc7XHJcbmV4cG9ydCB7IEN1cnZlUGF0aCB9IGZyb20gJy4vZXh0cmFzL2NvcmUvQ3VydmVQYXRoLmpzJztcclxuZXhwb3J0IHsgQ3VydmUgfSBmcm9tICcuL2V4dHJhcy9jb3JlL0N1cnZlLmpzJztcclxuZXhwb3J0IHsgRGF0YVV0aWxzIH0gZnJvbSAnLi9leHRyYXMvRGF0YVV0aWxzLmpzJztcclxuZXhwb3J0IHsgSW1hZ2VVdGlscyB9IGZyb20gJy4vZXh0cmFzL0ltYWdlVXRpbHMuanMnO1xyXG5leHBvcnQgeyBTaGFwZVV0aWxzIH0gZnJvbSAnLi9leHRyYXMvU2hhcGVVdGlscy5qcyc7XHJcbmV4cG9ydCB7IFBNUkVNR2VuZXJhdG9yIH0gZnJvbSAnLi9leHRyYXMvUE1SRU1HZW5lcmF0b3IuanMnO1xyXG5leHBvcnQgeyBXZWJHTFV0aWxzIH0gZnJvbSAnLi9yZW5kZXJlcnMvd2ViZ2wvV2ViR0xVdGlscy5qcyc7XHJcbmV4cG9ydCB7IGNyZWF0ZUNhbnZhc0VsZW1lbnQgfSBmcm9tICcuL3V0aWxzLmpzJztcclxuZXhwb3J0ICogZnJvbSAnLi9jb25zdGFudHMuanMnO1xyXG5leHBvcnQgKiBmcm9tICcuL1RocmVlLkxlZ2FjeS5qcyc7XHJcblxyXG5pZiAoIHR5cGVvZiBfX1RIUkVFX0RFVlRPT0xTX18gIT09ICd1bmRlZmluZWQnICkge1xyXG5cclxuXHRfX1RIUkVFX0RFVlRPT0xTX18uZGlzcGF0Y2hFdmVudCggbmV3IEN1c3RvbUV2ZW50KCAncmVnaXN0ZXInLCB7IGRldGFpbDoge1xyXG5cdFx0cmV2aXNpb246IFJFVklTSU9OLFxyXG5cdH0gfSApICk7XHJcblxyXG59XHJcblxyXG5pZiAoIHR5cGVvZiB3aW5kb3cgIT09ICd1bmRlZmluZWQnICkge1xyXG5cclxuXHRpZiAoIHdpbmRvdy5fX1RIUkVFX18gKSB7XHJcblxyXG5cdFx0Y29uc29sZS53YXJuKCAnV0FSTklORzogTXVsdGlwbGUgaW5zdGFuY2VzIG9mIFRocmVlLmpzIGJlaW5nIGltcG9ydGVkLicgKTtcclxuXHJcblx0fSBlbHNlIHtcclxuXHJcblx0XHR3aW5kb3cuX19USFJFRV9fID0gUkVWSVNJT047XHJcblxyXG5cdH1cclxuXHJcbn1cclxuIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQVk7QUFDWjtBQUNZO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDWjtBQUNZO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDWjtBQUNZO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDWjtBQUNBO0FBQ1k7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNaO0FBQ1k7QUFDQTtBQUNaO0FBQ1k7QUFDQTtBQUNaO0FBQ1k7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNaO0FBQ1k7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNaO0FBQ1k7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNaO0FBQ1k7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ1o7QUFDWTtBQUNBO0FBQ1o7QUFDWTtBQUNaO0FBQ1k7QUFDQTs7QUNuTlo7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25GQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVVQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzdkQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pXQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDckZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNZO0FBQ1o7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDTztBQUNQO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDTztBQUNQO0FBQ0E7QUFDQTtBQUNBOztBQ3ZJQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzSEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDblRBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzbkJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNySEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNUQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNyQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNoQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzdCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDN0VBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2cUJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDL3NCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hoQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hQQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdmVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzU0QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hUQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDL0NBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzMrQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaFRBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdm1CQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25nQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0s7QUFDTDtBQUNBO0FBQ0E7O0FDbEtBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM3bUJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6aUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JhQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDL0tBO0FBQ0E7QUFDQTtBQUNBO0FBQ087QUFDUDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDTztBQUNQO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ087QUFDUDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNPO0FBQ1A7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNLOztBQ3JHTDs7QUNBQTs7QUNNQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN0TEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzdEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDclFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdktBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNUlBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDck1BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RMQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbERBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzlOQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDL0ZBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBOztBQ0FBO0FBWUE7QUFDQTs7QUNiQTtBQWdCQTtBQUNBOztBQ2pCQTtBQWdCQTtBQUNBOztBQ2pCQTtBQTBDQTtBQUNBOztBQzNDQTtBQXdDQTtBQUNBOztBQ3pDQTtBQWNBO0FBQ0E7O0FDZkE7QUE4QkE7QUFDQTs7QUMvQkE7QUEwQ0E7QUFDQTs7QUMzQ0E7QUFrREE7QUFDQTs7QUNuREE7QUE4Q0E7QUFDQTs7QUMvQ0E7QUErQ0E7QUFDQTs7QUNoREE7QUFrREE7QUFDQTs7QUNuREE7QUEyREE7QUFDQTs7QUM1REE7QUFnREE7QUFDQTs7QUNqREE7QUFpREE7QUFDQTs7QUNsREE7QUErQkE7QUFDQTs7QUNoQ0E7QUE0Q0E7QUFDQTs7QUNpRlk7QUFDWjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pRQTtBQUNBO0FBQ0E7QUFDQTtBQUNLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzNOSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDelZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pPQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25uQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4RkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcEtBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzlGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNUdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwNEJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDL0hBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvTUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzlEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4U0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNyRkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2REE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFPQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqb0NBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ0hBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNsbENBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDakhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNscEJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcE9BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeGtCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcEdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeENBO0FBT0E7QUFDQTs7QUNNQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hhQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3Z5Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pvRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDclJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ1pBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ1hBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzlVQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNsekJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3BqQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNyVUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1aEZBO0FBQ0E7QUFDQTs7QUNGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM5QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDakNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeERBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQy9KQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hWQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDL0tBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pNQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNVBBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ1hBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDVkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNoUkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM5QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2TUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3IvQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNyQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdk5BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNYQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdkNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNoS0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdEJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ1pBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDZEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDVEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3paQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2SkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDWEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNVBBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeEVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2RUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDekVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN0RkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25FQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcEVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7Ozs7Ozs7Ozs7Ozs7O0FDM0ZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNuUEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxTEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RMQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hSQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdkJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxVEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeERBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNsSkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNoeEJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQVFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeHlCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzdCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdEhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVMQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3BJQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM0JBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqSEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM5SkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNuTUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FDNUlBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaENBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ1RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwSEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeE5BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaEhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDL0ZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1R0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1RUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDN0JBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4VkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzT0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDakpBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNoQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ1pBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4Y0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDVkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ0xBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNKQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDL0JBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDakJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ1ZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNJQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN0ZEs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNLOztBQ3pJTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3BSQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDOUhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNsRkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzNIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNsQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNuREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDekJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVJQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzNDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzdEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMUZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25EQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ1RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNaQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNuREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM3T0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2ZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDalhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDekJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDckpBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNybkNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcElBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6WUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvSUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNuQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMVRBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeHNCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM3WEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDL3FCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDL3ZCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDWEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzdGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzdDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN0REE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzNHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25GQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RNQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbEZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4SEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaEZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDOUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDOUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNyRkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqRkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcFFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeEdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM3Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzNEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1SEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzsifQ== diff --git a/build/three.module.min.js b/build/three.module.min.js deleted file mode 100644 index 5bb4e96c9ef981..00000000000000 --- a/build/three.module.min.js +++ /dev/null @@ -1,7 +0,0 @@ -/** - * @license - * Copyright 2010-2023 Three.js Authors - * SPDX-License-Identifier: MIT - */ -const t="162dev",e={LEFT:0,MIDDLE:1,RIGHT:2,ROTATE:0,DOLLY:1,PAN:2},n={ROTATE:0,PAN:1,DOLLY_PAN:2,DOLLY_ROTATE:3},i=0,r=1,s=2,a=3,o=0,l=1,c=2,h=3,u=0,d=1,p=2,m=0,f=1,g=2,_=3,v=4,x=5,y=100,M=101,S=102,b=103,E=104,T=200,w=201,A=202,R=203,C=204,P=205,L=206,I=207,U=208,N=209,D=210,O=211,F=212,B=213,z=214,H=0,V=1,k=2,G=3,W=4,X=5,j=6,q=7,Y=0,Z=1,J=2,K=0,$=1,Q=2,tt=3,et=4,nt=5,it=6,rt="attached",st="detached",at=300,ot=301,lt=302,ct=303,ht=304,ut=306,dt=1e3,pt=1001,mt=1002,ft=1003,gt=1004,_t=1004,vt=1005,xt=1005,yt=1006,Mt=1007,St=1007,bt=1008,Et=1008,Tt=1009,wt=1010,At=1011,Rt=1012,Ct=1013,Pt=1014,Lt=1015,It=1016,Ut=1017,Nt=1018,Dt=1020,Ot=1021,Ft=1023,Bt=1024,zt=1025,Ht=1026,Vt=1027,kt=1028,Gt=1029,Wt=1030,Xt=1031,jt=1033,qt=33776,Yt=33777,Zt=33778,Jt=33779,Kt=35840,$t=35841,Qt=35842,te=35843,ee=36196,ne=37492,ie=37496,re=37808,se=37809,ae=37810,oe=37811,le=37812,ce=37813,he=37814,ue=37815,de=37816,pe=37817,me=37818,fe=37819,ge=37820,_e=37821,ve=36492,xe=36494,ye=36495,Me=36283,Se=36284,be=36285,Ee=36286,Te=2200,we=2201,Ae=2202,Re=2300,Ce=2301,Pe=2302,Le=2400,Ie=2401,Ue=2402,Ne=2500,De=2501,Oe=0,Fe=1,Be=2,ze=3200,He=3201,Ve=0,ke=1,Ge="",We="srgb",Xe="srgb-linear",je="display-p3",qe="display-p3-linear",Ye="linear",Ze="srgb",Je="rec709",Ke="p3",$e=0,Qe=7680,tn=7681,en=7682,nn=7683,rn=34055,sn=34056,an=5386,on=512,ln=513,cn=514,hn=515,un=516,dn=517,pn=518,mn=519,fn=512,gn=513,_n=514,vn=515,xn=516,yn=517,Mn=518,Sn=519,bn=35044,En=35048,Tn=35040,wn=35045,An=35049,Rn=35041,Cn=35046,Pn=35050,Ln=35042,In="100",Un="300 es",Nn=1035,Dn=2e3,On=2001;class Fn{addEventListener(t,e){void 0===this._listeners&&(this._listeners={});const n=this._listeners;void 0===n[t]&&(n[t]=[]),-1===n[t].indexOf(e)&&n[t].push(e)}hasEventListener(t,e){if(void 0===this._listeners)return!1;const n=this._listeners;return void 0!==n[t]&&-1!==n[t].indexOf(e)}removeEventListener(t,e){if(void 0===this._listeners)return;const n=this._listeners[t];if(void 0!==n){const t=n.indexOf(e);-1!==t&&n.splice(t,1)}}dispatchEvent(t){if(void 0===this._listeners)return;const e=this._listeners[t.type];if(void 0!==e){t.target=this;const n=e.slice(0);for(let e=0,i=n.length;e>8&255]+Bn[t>>16&255]+Bn[t>>24&255]+"-"+Bn[255&e]+Bn[e>>8&255]+"-"+Bn[e>>16&15|64]+Bn[e>>24&255]+"-"+Bn[63&n|128]+Bn[n>>8&255]+"-"+Bn[n>>16&255]+Bn[n>>24&255]+Bn[255&i]+Bn[i>>8&255]+Bn[i>>16&255]+Bn[i>>24&255]).toLowerCase()}function Gn(t,e,n){return Math.max(e,Math.min(n,t))}function Wn(t,e){return(t%e+e)%e}function Xn(t,e,n){return(1-n)*t+n*e}function jn(t){return 0==(t&t-1)&&0!==t}function qn(t){return Math.pow(2,Math.floor(Math.log(t)/Math.LN2))}function Yn(t,e){switch(e.constructor){case Float32Array:return t;case Uint32Array:return t/4294967295;case Uint16Array:return t/65535;case Uint8Array:return t/255;case Int32Array:return Math.max(t/2147483647,-1);case Int16Array:return Math.max(t/32767,-1);case Int8Array:return Math.max(t/127,-1);default:throw new Error("Invalid component type.")}}function Zn(t,e){switch(e.constructor){case Float32Array:return t;case Uint32Array:return Math.round(4294967295*t);case Uint16Array:return Math.round(65535*t);case Uint8Array:return Math.round(255*t);case Int32Array:return Math.round(2147483647*t);case Int16Array:return Math.round(32767*t);case Int8Array:return Math.round(127*t);default:throw new Error("Invalid component type.")}}const Jn={DEG2RAD:Hn,RAD2DEG:Vn,generateUUID:kn,clamp:Gn,euclideanModulo:Wn,mapLinear:function(t,e,n,i,r){return i+(t-e)*(r-i)/(n-e)},inverseLerp:function(t,e,n){return t!==e?(n-t)/(e-t):0},lerp:Xn,damp:function(t,e,n,i){return Xn(t,e,1-Math.exp(-n*i))},pingpong:function(t,e=1){return e-Math.abs(Wn(t,2*e)-e)},smoothstep:function(t,e,n){return t<=e?0:t>=n?1:(t=(t-e)/(n-e))*t*(3-2*t)},smootherstep:function(t,e,n){return t<=e?0:t>=n?1:(t=(t-e)/(n-e))*t*t*(t*(6*t-15)+10)},randInt:function(t,e){return t+Math.floor(Math.random()*(e-t+1))},randFloat:function(t,e){return t+Math.random()*(e-t)},randFloatSpread:function(t){return t*(.5-Math.random())},seededRandom:function(t){void 0!==t&&(zn=t);let e=zn+=1831565813;return e=Math.imul(e^e>>>15,1|e),e^=e+Math.imul(e^e>>>7,61|e),((e^e>>>14)>>>0)/4294967296},degToRad:function(t){return t*Hn},radToDeg:function(t){return t*Vn},isPowerOfTwo:jn,ceilPowerOfTwo:function(t){return Math.pow(2,Math.ceil(Math.log(t)/Math.LN2))},floorPowerOfTwo:qn,setQuaternionFromProperEuler:function(t,e,n,i,r){const s=Math.cos,a=Math.sin,o=s(n/2),l=a(n/2),c=s((e+i)/2),h=a((e+i)/2),u=s((e-i)/2),d=a((e-i)/2),p=s((i-e)/2),m=a((i-e)/2);switch(r){case"XYX":t.set(o*h,l*u,l*d,o*c);break;case"YZY":t.set(l*d,o*h,l*u,o*c);break;case"ZXZ":t.set(l*u,l*d,o*h,o*c);break;case"XZX":t.set(o*h,l*m,l*p,o*c);break;case"YXY":t.set(l*p,o*h,l*m,o*c);break;case"ZYZ":t.set(l*m,l*p,o*h,o*c);break;default:console.warn("THREE.MathUtils: .setQuaternionFromProperEuler() encountered an unknown order: "+r)}},normalize:Zn,denormalize:Yn};class Kn{constructor(t=0,e=0){Kn.prototype.isVector2=!0,this.x=t,this.y=e}get width(){return this.x}set width(t){this.x=t}get height(){return this.y}set height(t){this.y=t}set(t,e){return this.x=t,this.y=e,this}setScalar(t){return this.x=t,this.y=t,this}setX(t){return this.x=t,this}setY(t){return this.y=t,this}setComponent(t,e){switch(t){case 0:this.x=e;break;case 1:this.y=e;break;default:throw new Error("index is out of range: "+t)}return this}getComponent(t){switch(t){case 0:return this.x;case 1:return this.y;default:throw new Error("index is out of range: "+t)}}clone(){return new this.constructor(this.x,this.y)}copy(t){return this.x=t.x,this.y=t.y,this}add(t){return this.x+=t.x,this.y+=t.y,this}addScalar(t){return this.x+=t,this.y+=t,this}addVectors(t,e){return this.x=t.x+e.x,this.y=t.y+e.y,this}addScaledVector(t,e){return this.x+=t.x*e,this.y+=t.y*e,this}sub(t){return this.x-=t.x,this.y-=t.y,this}subScalar(t){return this.x-=t,this.y-=t,this}subVectors(t,e){return this.x=t.x-e.x,this.y=t.y-e.y,this}multiply(t){return this.x*=t.x,this.y*=t.y,this}multiplyScalar(t){return this.x*=t,this.y*=t,this}divide(t){return this.x/=t.x,this.y/=t.y,this}divideScalar(t){return this.multiplyScalar(1/t)}applyMatrix3(t){const e=this.x,n=this.y,i=t.elements;return this.x=i[0]*e+i[3]*n+i[6],this.y=i[1]*e+i[4]*n+i[7],this}min(t){return this.x=Math.min(this.x,t.x),this.y=Math.min(this.y,t.y),this}max(t){return this.x=Math.max(this.x,t.x),this.y=Math.max(this.y,t.y),this}clamp(t,e){return this.x=Math.max(t.x,Math.min(e.x,this.x)),this.y=Math.max(t.y,Math.min(e.y,this.y)),this}clampScalar(t,e){return this.x=Math.max(t,Math.min(e,this.x)),this.y=Math.max(t,Math.min(e,this.y)),this}clampLength(t,e){const n=this.length();return this.divideScalar(n||1).multiplyScalar(Math.max(t,Math.min(e,n)))}floor(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this}ceil(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this}round(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this}roundToZero(){return this.x=Math.trunc(this.x),this.y=Math.trunc(this.y),this}negate(){return this.x=-this.x,this.y=-this.y,this}dot(t){return this.x*t.x+this.y*t.y}cross(t){return this.x*t.y-this.y*t.x}lengthSq(){return this.x*this.x+this.y*this.y}length(){return Math.sqrt(this.x*this.x+this.y*this.y)}manhattanLength(){return Math.abs(this.x)+Math.abs(this.y)}normalize(){return this.divideScalar(this.length()||1)}angle(){return Math.atan2(-this.y,-this.x)+Math.PI}angleTo(t){const e=Math.sqrt(this.lengthSq()*t.lengthSq());if(0===e)return Math.PI/2;const n=this.dot(t)/e;return Math.acos(Gn(n,-1,1))}distanceTo(t){return Math.sqrt(this.distanceToSquared(t))}distanceToSquared(t){const e=this.x-t.x,n=this.y-t.y;return e*e+n*n}manhattanDistanceTo(t){return Math.abs(this.x-t.x)+Math.abs(this.y-t.y)}setLength(t){return this.normalize().multiplyScalar(t)}lerp(t,e){return this.x+=(t.x-this.x)*e,this.y+=(t.y-this.y)*e,this}lerpVectors(t,e,n){return this.x=t.x+(e.x-t.x)*n,this.y=t.y+(e.y-t.y)*n,this}equals(t){return t.x===this.x&&t.y===this.y}fromArray(t,e=0){return this.x=t[e],this.y=t[e+1],this}toArray(t=[],e=0){return t[e]=this.x,t[e+1]=this.y,t}fromBufferAttribute(t,e){return this.x=t.getX(e),this.y=t.getY(e),this}rotateAround(t,e){const n=Math.cos(e),i=Math.sin(e),r=this.x-t.x,s=this.y-t.y;return this.x=r*n-s*i+t.x,this.y=r*i+s*n+t.y,this}random(){return this.x=Math.random(),this.y=Math.random(),this}*[Symbol.iterator](){yield this.x,yield this.y}}class $n{constructor(t,e,n,i,r,s,a,o,l){$n.prototype.isMatrix3=!0,this.elements=[1,0,0,0,1,0,0,0,1],void 0!==t&&this.set(t,e,n,i,r,s,a,o,l)}set(t,e,n,i,r,s,a,o,l){const c=this.elements;return c[0]=t,c[1]=i,c[2]=a,c[3]=e,c[4]=r,c[5]=o,c[6]=n,c[7]=s,c[8]=l,this}identity(){return this.set(1,0,0,0,1,0,0,0,1),this}copy(t){const e=this.elements,n=t.elements;return e[0]=n[0],e[1]=n[1],e[2]=n[2],e[3]=n[3],e[4]=n[4],e[5]=n[5],e[6]=n[6],e[7]=n[7],e[8]=n[8],this}extractBasis(t,e,n){return t.setFromMatrix3Column(this,0),e.setFromMatrix3Column(this,1),n.setFromMatrix3Column(this,2),this}setFromMatrix4(t){const e=t.elements;return this.set(e[0],e[4],e[8],e[1],e[5],e[9],e[2],e[6],e[10]),this}multiply(t){return this.multiplyMatrices(this,t)}premultiply(t){return this.multiplyMatrices(t,this)}multiplyMatrices(t,e){const n=t.elements,i=e.elements,r=this.elements,s=n[0],a=n[3],o=n[6],l=n[1],c=n[4],h=n[7],u=n[2],d=n[5],p=n[8],m=i[0],f=i[3],g=i[6],_=i[1],v=i[4],x=i[7],y=i[2],M=i[5],S=i[8];return r[0]=s*m+a*_+o*y,r[3]=s*f+a*v+o*M,r[6]=s*g+a*x+o*S,r[1]=l*m+c*_+h*y,r[4]=l*f+c*v+h*M,r[7]=l*g+c*x+h*S,r[2]=u*m+d*_+p*y,r[5]=u*f+d*v+p*M,r[8]=u*g+d*x+p*S,this}multiplyScalar(t){const e=this.elements;return e[0]*=t,e[3]*=t,e[6]*=t,e[1]*=t,e[4]*=t,e[7]*=t,e[2]*=t,e[5]*=t,e[8]*=t,this}determinant(){const t=this.elements,e=t[0],n=t[1],i=t[2],r=t[3],s=t[4],a=t[5],o=t[6],l=t[7],c=t[8];return e*s*c-e*a*l-n*r*c+n*a*o+i*r*l-i*s*o}invert(){const t=this.elements,e=t[0],n=t[1],i=t[2],r=t[3],s=t[4],a=t[5],o=t[6],l=t[7],c=t[8],h=c*s-a*l,u=a*o-c*r,d=l*r-s*o,p=e*h+n*u+i*d;if(0===p)return this.set(0,0,0,0,0,0,0,0,0);const m=1/p;return t[0]=h*m,t[1]=(i*l-c*n)*m,t[2]=(a*n-i*s)*m,t[3]=u*m,t[4]=(c*e-i*o)*m,t[5]=(i*r-a*e)*m,t[6]=d*m,t[7]=(n*o-l*e)*m,t[8]=(s*e-n*r)*m,this}transpose(){let t;const e=this.elements;return t=e[1],e[1]=e[3],e[3]=t,t=e[2],e[2]=e[6],e[6]=t,t=e[5],e[5]=e[7],e[7]=t,this}getNormalMatrix(t){return this.setFromMatrix4(t).invert().transpose()}transposeIntoArray(t){const e=this.elements;return t[0]=e[0],t[1]=e[3],t[2]=e[6],t[3]=e[1],t[4]=e[4],t[5]=e[7],t[6]=e[2],t[7]=e[5],t[8]=e[8],this}setUvTransform(t,e,n,i,r,s,a){const o=Math.cos(r),l=Math.sin(r);return this.set(n*o,n*l,-n*(o*s+l*a)+s+t,-i*l,i*o,-i*(-l*s+o*a)+a+e,0,0,1),this}scale(t,e){return this.premultiply(Qn.makeScale(t,e)),this}rotate(t){return this.premultiply(Qn.makeRotation(-t)),this}translate(t,e){return this.premultiply(Qn.makeTranslation(t,e)),this}makeTranslation(t,e){return t.isVector2?this.set(1,0,t.x,0,1,t.y,0,0,1):this.set(1,0,t,0,1,e,0,0,1),this}makeRotation(t){const e=Math.cos(t),n=Math.sin(t);return this.set(e,-n,0,n,e,0,0,0,1),this}makeScale(t,e){return this.set(t,0,0,0,e,0,0,0,1),this}equals(t){const e=this.elements,n=t.elements;for(let t=0;t<9;t++)if(e[t]!==n[t])return!1;return!0}fromArray(t,e=0){for(let n=0;n<9;n++)this.elements[n]=t[n+e];return this}toArray(t=[],e=0){const n=this.elements;return t[e]=n[0],t[e+1]=n[1],t[e+2]=n[2],t[e+3]=n[3],t[e+4]=n[4],t[e+5]=n[5],t[e+6]=n[6],t[e+7]=n[7],t[e+8]=n[8],t}clone(){return(new this.constructor).fromArray(this.elements)}}const Qn=new $n;function ti(t){for(let e=t.length-1;e>=0;--e)if(t[e]>=65535)return!0;return!1}const ei={Int8Array:Int8Array,Uint8Array:Uint8Array,Uint8ClampedArray:Uint8ClampedArray,Int16Array:Int16Array,Uint16Array:Uint16Array,Int32Array:Int32Array,Uint32Array:Uint32Array,Float32Array:Float32Array,Float64Array:Float64Array};function ni(t,e){return new ei[t](e)}function ii(t){return document.createElementNS("http://www.w3.org/1999/xhtml",t)}function ri(){const t=ii("canvas");return t.style.display="block",t}const si={};function ai(t){t in si||(si[t]=!0,console.warn(t))}const oi=(new $n).set(.8224621,.177538,0,.0331941,.9668058,0,.0170827,.0723974,.9105199),li=(new $n).set(1.2249401,-.2249404,0,-.0420569,1.0420571,0,-.0196376,-.0786361,1.0982735),ci={[Xe]:{transfer:Ye,primaries:Je,toReference:t=>t,fromReference:t=>t},[We]:{transfer:Ze,primaries:Je,toReference:t=>t.convertSRGBToLinear(),fromReference:t=>t.convertLinearToSRGB()},[qe]:{transfer:Ye,primaries:Ke,toReference:t=>t.applyMatrix3(li),fromReference:t=>t.applyMatrix3(oi)},[je]:{transfer:Ze,primaries:Ke,toReference:t=>t.convertSRGBToLinear().applyMatrix3(li),fromReference:t=>t.applyMatrix3(oi).convertLinearToSRGB()}},hi=new Set([Xe,qe]),ui={enabled:!0,_workingColorSpace:Xe,get workingColorSpace(){return this._workingColorSpace},set workingColorSpace(t){if(!hi.has(t))throw new Error(`Unsupported working color space, "${t}".`);this._workingColorSpace=t},convert:function(t,e,n){if(!1===this.enabled||e===n||!e||!n)return t;const i=ci[e].toReference;return(0,ci[n].fromReference)(i(t))},fromWorkingColorSpace:function(t,e){return this.convert(t,this._workingColorSpace,e)},toWorkingColorSpace:function(t,e){return this.convert(t,e,this._workingColorSpace)},getPrimaries:function(t){return ci[t].primaries},getTransfer:function(t){return t===Ge?Ye:ci[t].transfer}};function di(t){return t<.04045?.0773993808*t:Math.pow(.9478672986*t+.0521327014,2.4)}function pi(t){return t<.0031308?12.92*t:1.055*Math.pow(t,.41666)-.055}let mi;class fi{static getDataURL(t){if(/^data:/i.test(t.src))return t.src;if("undefined"==typeof HTMLCanvasElement)return t.src;let e;if(t instanceof HTMLCanvasElement)e=t;else{void 0===mi&&(mi=ii("canvas")),mi.width=t.width,mi.height=t.height;const n=mi.getContext("2d");t instanceof ImageData?n.putImageData(t,0,0):n.drawImage(t,0,0,t.width,t.height),e=mi}return e.width>2048||e.height>2048?(console.warn("THREE.ImageUtils.getDataURL: Image converted to jpg for performance reasons",t),e.toDataURL("image/jpeg",.6)):e.toDataURL("image/png")}static sRGBToLinear(t){if("undefined"!=typeof HTMLImageElement&&t instanceof HTMLImageElement||"undefined"!=typeof HTMLCanvasElement&&t instanceof HTMLCanvasElement||"undefined"!=typeof ImageBitmap&&t instanceof ImageBitmap){const e=ii("canvas");e.width=t.width,e.height=t.height;const n=e.getContext("2d");n.drawImage(t,0,0,t.width,t.height);const i=n.getImageData(0,0,t.width,t.height),r=i.data;for(let t=0;t0&&(n.userData=this.userData),e||(t.textures[this.uuid]=n),n}dispose(){this.dispatchEvent({type:"dispose"})}transformUv(t){if(this.mapping!==at)return t;if(t.applyMatrix3(this.matrix),t.x<0||t.x>1)switch(this.wrapS){case dt:t.x=t.x-Math.floor(t.x);break;case pt:t.x=t.x<0?0:1;break;case mt:1===Math.abs(Math.floor(t.x)%2)?t.x=Math.ceil(t.x)-t.x:t.x=t.x-Math.floor(t.x)}if(t.y<0||t.y>1)switch(this.wrapT){case dt:t.y=t.y-Math.floor(t.y);break;case pt:t.y=t.y<0?0:1;break;case mt:1===Math.abs(Math.floor(t.y)%2)?t.y=Math.ceil(t.y)-t.y:t.y=t.y-Math.floor(t.y)}return this.flipY&&(t.y=1-t.y),t}set needsUpdate(t){!0===t&&(this.version++,this.source.needsUpdate=!0)}}yi.DEFAULT_IMAGE=null,yi.DEFAULT_MAPPING=at,yi.DEFAULT_ANISOTROPY=1;class Mi{constructor(t=0,e=0,n=0,i=1){Mi.prototype.isVector4=!0,this.x=t,this.y=e,this.z=n,this.w=i}get width(){return this.z}set width(t){this.z=t}get height(){return this.w}set height(t){this.w=t}set(t,e,n,i){return this.x=t,this.y=e,this.z=n,this.w=i,this}setScalar(t){return this.x=t,this.y=t,this.z=t,this.w=t,this}setX(t){return this.x=t,this}setY(t){return this.y=t,this}setZ(t){return this.z=t,this}setW(t){return this.w=t,this}setComponent(t,e){switch(t){case 0:this.x=e;break;case 1:this.y=e;break;case 2:this.z=e;break;case 3:this.w=e;break;default:throw new Error("index is out of range: "+t)}return this}getComponent(t){switch(t){case 0:return this.x;case 1:return this.y;case 2:return this.z;case 3:return this.w;default:throw new Error("index is out of range: "+t)}}clone(){return new this.constructor(this.x,this.y,this.z,this.w)}copy(t){return this.x=t.x,this.y=t.y,this.z=t.z,this.w=void 0!==t.w?t.w:1,this}add(t){return this.x+=t.x,this.y+=t.y,this.z+=t.z,this.w+=t.w,this}addScalar(t){return this.x+=t,this.y+=t,this.z+=t,this.w+=t,this}addVectors(t,e){return this.x=t.x+e.x,this.y=t.y+e.y,this.z=t.z+e.z,this.w=t.w+e.w,this}addScaledVector(t,e){return this.x+=t.x*e,this.y+=t.y*e,this.z+=t.z*e,this.w+=t.w*e,this}sub(t){return this.x-=t.x,this.y-=t.y,this.z-=t.z,this.w-=t.w,this}subScalar(t){return this.x-=t,this.y-=t,this.z-=t,this.w-=t,this}subVectors(t,e){return this.x=t.x-e.x,this.y=t.y-e.y,this.z=t.z-e.z,this.w=t.w-e.w,this}multiply(t){return this.x*=t.x,this.y*=t.y,this.z*=t.z,this.w*=t.w,this}multiplyScalar(t){return this.x*=t,this.y*=t,this.z*=t,this.w*=t,this}applyMatrix4(t){const e=this.x,n=this.y,i=this.z,r=this.w,s=t.elements;return this.x=s[0]*e+s[4]*n+s[8]*i+s[12]*r,this.y=s[1]*e+s[5]*n+s[9]*i+s[13]*r,this.z=s[2]*e+s[6]*n+s[10]*i+s[14]*r,this.w=s[3]*e+s[7]*n+s[11]*i+s[15]*r,this}divideScalar(t){return this.multiplyScalar(1/t)}setAxisAngleFromQuaternion(t){this.w=2*Math.acos(t.w);const e=Math.sqrt(1-t.w*t.w);return e<1e-4?(this.x=1,this.y=0,this.z=0):(this.x=t.x/e,this.y=t.y/e,this.z=t.z/e),this}setAxisAngleFromRotationMatrix(t){let e,n,i,r;const s=.01,a=.1,o=t.elements,l=o[0],c=o[4],h=o[8],u=o[1],d=o[5],p=o[9],m=o[2],f=o[6],g=o[10];if(Math.abs(c-u)o&&t>_?t_?o=0?1:-1,i=1-e*e;if(i>Number.EPSILON){const r=Math.sqrt(i),s=Math.atan2(r,e*n);t=Math.sin(t*s)/r,a=Math.sin(a*s)/r}const r=a*n;if(o=o*t+u*r,l=l*t+d*r,c=c*t+p*r,h=h*t+m*r,t===1-a){const t=1/Math.sqrt(o*o+l*l+c*c+h*h);o*=t,l*=t,c*=t,h*=t}}t[e]=o,t[e+1]=l,t[e+2]=c,t[e+3]=h}static multiplyQuaternionsFlat(t,e,n,i,r,s){const a=n[i],o=n[i+1],l=n[i+2],c=n[i+3],h=r[s],u=r[s+1],d=r[s+2],p=r[s+3];return t[e]=a*p+c*h+o*d-l*u,t[e+1]=o*p+c*u+l*h-a*d,t[e+2]=l*p+c*d+a*u-o*h,t[e+3]=c*p-a*h-o*u-l*d,t}get x(){return this._x}set x(t){this._x=t,this._onChangeCallback()}get y(){return this._y}set y(t){this._y=t,this._onChangeCallback()}get z(){return this._z}set z(t){this._z=t,this._onChangeCallback()}get w(){return this._w}set w(t){this._w=t,this._onChangeCallback()}set(t,e,n,i){return this._x=t,this._y=e,this._z=n,this._w=i,this._onChangeCallback(),this}clone(){return new this.constructor(this._x,this._y,this._z,this._w)}copy(t){return this._x=t.x,this._y=t.y,this._z=t.z,this._w=t.w,this._onChangeCallback(),this}setFromEuler(t,e=!0){const n=t._x,i=t._y,r=t._z,s=t._order,a=Math.cos,o=Math.sin,l=a(n/2),c=a(i/2),h=a(r/2),u=o(n/2),d=o(i/2),p=o(r/2);switch(s){case"XYZ":this._x=u*c*h+l*d*p,this._y=l*d*h-u*c*p,this._z=l*c*p+u*d*h,this._w=l*c*h-u*d*p;break;case"YXZ":this._x=u*c*h+l*d*p,this._y=l*d*h-u*c*p,this._z=l*c*p-u*d*h,this._w=l*c*h+u*d*p;break;case"ZXY":this._x=u*c*h-l*d*p,this._y=l*d*h+u*c*p,this._z=l*c*p+u*d*h,this._w=l*c*h-u*d*p;break;case"ZYX":this._x=u*c*h-l*d*p,this._y=l*d*h+u*c*p,this._z=l*c*p-u*d*h,this._w=l*c*h+u*d*p;break;case"YZX":this._x=u*c*h+l*d*p,this._y=l*d*h+u*c*p,this._z=l*c*p-u*d*h,this._w=l*c*h-u*d*p;break;case"XZY":this._x=u*c*h-l*d*p,this._y=l*d*h-u*c*p,this._z=l*c*p+u*d*h,this._w=l*c*h+u*d*p;break;default:console.warn("THREE.Quaternion: .setFromEuler() encountered an unknown order: "+s)}return!0===e&&this._onChangeCallback(),this}setFromAxisAngle(t,e){const n=e/2,i=Math.sin(n);return this._x=t.x*i,this._y=t.y*i,this._z=t.z*i,this._w=Math.cos(n),this._onChangeCallback(),this}setFromRotationMatrix(t){const e=t.elements,n=e[0],i=e[4],r=e[8],s=e[1],a=e[5],o=e[9],l=e[2],c=e[6],h=e[10],u=n+a+h;if(u>0){const t=.5/Math.sqrt(u+1);this._w=.25/t,this._x=(c-o)*t,this._y=(r-l)*t,this._z=(s-i)*t}else if(n>a&&n>h){const t=2*Math.sqrt(1+n-a-h);this._w=(c-o)/t,this._x=.25*t,this._y=(i+s)/t,this._z=(r+l)/t}else if(a>h){const t=2*Math.sqrt(1+a-n-h);this._w=(r-l)/t,this._x=(i+s)/t,this._y=.25*t,this._z=(o+c)/t}else{const t=2*Math.sqrt(1+h-n-a);this._w=(s-i)/t,this._x=(r+l)/t,this._y=(o+c)/t,this._z=.25*t}return this._onChangeCallback(),this}setFromUnitVectors(t,e){let n=t.dot(e)+1;return nMath.abs(t.z)?(this._x=-t.y,this._y=t.x,this._z=0,this._w=n):(this._x=0,this._y=-t.z,this._z=t.y,this._w=n)):(this._x=t.y*e.z-t.z*e.y,this._y=t.z*e.x-t.x*e.z,this._z=t.x*e.y-t.y*e.x,this._w=n),this.normalize()}angleTo(t){return 2*Math.acos(Math.abs(Gn(this.dot(t),-1,1)))}rotateTowards(t,e){const n=this.angleTo(t);if(0===n)return this;const i=Math.min(1,e/n);return this.slerp(t,i),this}identity(){return this.set(0,0,0,1)}invert(){return this.conjugate()}conjugate(){return this._x*=-1,this._y*=-1,this._z*=-1,this._onChangeCallback(),this}dot(t){return this._x*t._x+this._y*t._y+this._z*t._z+this._w*t._w}lengthSq(){return this._x*this._x+this._y*this._y+this._z*this._z+this._w*this._w}length(){return Math.sqrt(this._x*this._x+this._y*this._y+this._z*this._z+this._w*this._w)}normalize(){let t=this.length();return 0===t?(this._x=0,this._y=0,this._z=0,this._w=1):(t=1/t,this._x=this._x*t,this._y=this._y*t,this._z=this._z*t,this._w=this._w*t),this._onChangeCallback(),this}multiply(t){return this.multiplyQuaternions(this,t)}premultiply(t){return this.multiplyQuaternions(t,this)}multiplyQuaternions(t,e){const n=t._x,i=t._y,r=t._z,s=t._w,a=e._x,o=e._y,l=e._z,c=e._w;return this._x=n*c+s*a+i*l-r*o,this._y=i*c+s*o+r*a-n*l,this._z=r*c+s*l+n*o-i*a,this._w=s*c-n*a-i*o-r*l,this._onChangeCallback(),this}slerp(t,e){if(0===e)return this;if(1===e)return this.copy(t);const n=this._x,i=this._y,r=this._z,s=this._w;let a=s*t._w+n*t._x+i*t._y+r*t._z;if(a<0?(this._w=-t._w,this._x=-t._x,this._y=-t._y,this._z=-t._z,a=-a):this.copy(t),a>=1)return this._w=s,this._x=n,this._y=i,this._z=r,this;const o=1-a*a;if(o<=Number.EPSILON){const t=1-e;return this._w=t*s+e*this._w,this._x=t*n+e*this._x,this._y=t*i+e*this._y,this._z=t*r+e*this._z,this.normalize(),this}const l=Math.sqrt(o),c=Math.atan2(l,a),h=Math.sin((1-e)*c)/l,u=Math.sin(e*c)/l;return this._w=s*h+this._w*u,this._x=n*h+this._x*u,this._y=i*h+this._y*u,this._z=r*h+this._z*u,this._onChangeCallback(),this}slerpQuaternions(t,e,n){return this.copy(t).slerp(e,n)}random(){const t=Math.random(),e=Math.sqrt(1-t),n=Math.sqrt(t),i=2*Math.PI*Math.random(),r=2*Math.PI*Math.random();return this.set(e*Math.cos(i),n*Math.sin(r),n*Math.cos(r),e*Math.sin(i))}equals(t){return t._x===this._x&&t._y===this._y&&t._z===this._z&&t._w===this._w}fromArray(t,e=0){return this._x=t[e],this._y=t[e+1],this._z=t[e+2],this._w=t[e+3],this._onChangeCallback(),this}toArray(t=[],e=0){return t[e]=this._x,t[e+1]=this._y,t[e+2]=this._z,t[e+3]=this._w,t}fromBufferAttribute(t,e){return this._x=t.getX(e),this._y=t.getY(e),this._z=t.getZ(e),this._w=t.getW(e),this._onChangeCallback(),this}toJSON(){return this.toArray()}_onChange(t){return this._onChangeCallback=t,this}_onChangeCallback(){}*[Symbol.iterator](){yield this._x,yield this._y,yield this._z,yield this._w}}class Pi{constructor(t=0,e=0,n=0){Pi.prototype.isVector3=!0,this.x=t,this.y=e,this.z=n}set(t,e,n){return void 0===n&&(n=this.z),this.x=t,this.y=e,this.z=n,this}setScalar(t){return this.x=t,this.y=t,this.z=t,this}setX(t){return this.x=t,this}setY(t){return this.y=t,this}setZ(t){return this.z=t,this}setComponent(t,e){switch(t){case 0:this.x=e;break;case 1:this.y=e;break;case 2:this.z=e;break;default:throw new Error("index is out of range: "+t)}return this}getComponent(t){switch(t){case 0:return this.x;case 1:return this.y;case 2:return this.z;default:throw new Error("index is out of range: "+t)}}clone(){return new this.constructor(this.x,this.y,this.z)}copy(t){return this.x=t.x,this.y=t.y,this.z=t.z,this}add(t){return this.x+=t.x,this.y+=t.y,this.z+=t.z,this}addScalar(t){return this.x+=t,this.y+=t,this.z+=t,this}addVectors(t,e){return this.x=t.x+e.x,this.y=t.y+e.y,this.z=t.z+e.z,this}addScaledVector(t,e){return this.x+=t.x*e,this.y+=t.y*e,this.z+=t.z*e,this}sub(t){return this.x-=t.x,this.y-=t.y,this.z-=t.z,this}subScalar(t){return this.x-=t,this.y-=t,this.z-=t,this}subVectors(t,e){return this.x=t.x-e.x,this.y=t.y-e.y,this.z=t.z-e.z,this}multiply(t){return this.x*=t.x,this.y*=t.y,this.z*=t.z,this}multiplyScalar(t){return this.x*=t,this.y*=t,this.z*=t,this}multiplyVectors(t,e){return this.x=t.x*e.x,this.y=t.y*e.y,this.z=t.z*e.z,this}applyEuler(t){return this.applyQuaternion(Ii.setFromEuler(t))}applyAxisAngle(t,e){return this.applyQuaternion(Ii.setFromAxisAngle(t,e))}applyMatrix3(t){const e=this.x,n=this.y,i=this.z,r=t.elements;return this.x=r[0]*e+r[3]*n+r[6]*i,this.y=r[1]*e+r[4]*n+r[7]*i,this.z=r[2]*e+r[5]*n+r[8]*i,this}applyNormalMatrix(t){return this.applyMatrix3(t).normalize()}applyMatrix4(t){const e=this.x,n=this.y,i=this.z,r=t.elements,s=1/(r[3]*e+r[7]*n+r[11]*i+r[15]);return this.x=(r[0]*e+r[4]*n+r[8]*i+r[12])*s,this.y=(r[1]*e+r[5]*n+r[9]*i+r[13])*s,this.z=(r[2]*e+r[6]*n+r[10]*i+r[14])*s,this}applyQuaternion(t){const e=this.x,n=this.y,i=this.z,r=t.x,s=t.y,a=t.z,o=t.w,l=2*(s*i-a*n),c=2*(a*e-r*i),h=2*(r*n-s*e);return this.x=e+o*l+s*h-a*c,this.y=n+o*c+a*l-r*h,this.z=i+o*h+r*c-s*l,this}project(t){return this.applyMatrix4(t.matrixWorldInverse).applyMatrix4(t.projectionMatrix)}unproject(t){return this.applyMatrix4(t.projectionMatrixInverse).applyMatrix4(t.matrixWorld)}transformDirection(t){const e=this.x,n=this.y,i=this.z,r=t.elements;return this.x=r[0]*e+r[4]*n+r[8]*i,this.y=r[1]*e+r[5]*n+r[9]*i,this.z=r[2]*e+r[6]*n+r[10]*i,this.normalize()}divide(t){return this.x/=t.x,this.y/=t.y,this.z/=t.z,this}divideScalar(t){return this.multiplyScalar(1/t)}min(t){return this.x=Math.min(this.x,t.x),this.y=Math.min(this.y,t.y),this.z=Math.min(this.z,t.z),this}max(t){return this.x=Math.max(this.x,t.x),this.y=Math.max(this.y,t.y),this.z=Math.max(this.z,t.z),this}clamp(t,e){return this.x=Math.max(t.x,Math.min(e.x,this.x)),this.y=Math.max(t.y,Math.min(e.y,this.y)),this.z=Math.max(t.z,Math.min(e.z,this.z)),this}clampScalar(t,e){return this.x=Math.max(t,Math.min(e,this.x)),this.y=Math.max(t,Math.min(e,this.y)),this.z=Math.max(t,Math.min(e,this.z)),this}clampLength(t,e){const n=this.length();return this.divideScalar(n||1).multiplyScalar(Math.max(t,Math.min(e,n)))}floor(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this.z=Math.floor(this.z),this}ceil(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this.z=Math.ceil(this.z),this}round(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this.z=Math.round(this.z),this}roundToZero(){return this.x=Math.trunc(this.x),this.y=Math.trunc(this.y),this.z=Math.trunc(this.z),this}negate(){return this.x=-this.x,this.y=-this.y,this.z=-this.z,this}dot(t){return this.x*t.x+this.y*t.y+this.z*t.z}lengthSq(){return this.x*this.x+this.y*this.y+this.z*this.z}length(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z)}manhattanLength(){return Math.abs(this.x)+Math.abs(this.y)+Math.abs(this.z)}normalize(){return this.divideScalar(this.length()||1)}setLength(t){return this.normalize().multiplyScalar(t)}lerp(t,e){return this.x+=(t.x-this.x)*e,this.y+=(t.y-this.y)*e,this.z+=(t.z-this.z)*e,this}lerpVectors(t,e,n){return this.x=t.x+(e.x-t.x)*n,this.y=t.y+(e.y-t.y)*n,this.z=t.z+(e.z-t.z)*n,this}cross(t){return this.crossVectors(this,t)}crossVectors(t,e){const n=t.x,i=t.y,r=t.z,s=e.x,a=e.y,o=e.z;return this.x=i*o-r*a,this.y=r*s-n*o,this.z=n*a-i*s,this}projectOnVector(t){const e=t.lengthSq();if(0===e)return this.set(0,0,0);const n=t.dot(this)/e;return this.copy(t).multiplyScalar(n)}projectOnPlane(t){return Li.copy(this).projectOnVector(t),this.sub(Li)}reflect(t){return this.sub(Li.copy(t).multiplyScalar(2*this.dot(t)))}angleTo(t){const e=Math.sqrt(this.lengthSq()*t.lengthSq());if(0===e)return Math.PI/2;const n=this.dot(t)/e;return Math.acos(Gn(n,-1,1))}distanceTo(t){return Math.sqrt(this.distanceToSquared(t))}distanceToSquared(t){const e=this.x-t.x,n=this.y-t.y,i=this.z-t.z;return e*e+n*n+i*i}manhattanDistanceTo(t){return Math.abs(this.x-t.x)+Math.abs(this.y-t.y)+Math.abs(this.z-t.z)}setFromSpherical(t){return this.setFromSphericalCoords(t.radius,t.phi,t.theta)}setFromSphericalCoords(t,e,n){const i=Math.sin(e)*t;return this.x=i*Math.sin(n),this.y=Math.cos(e)*t,this.z=i*Math.cos(n),this}setFromCylindrical(t){return this.setFromCylindricalCoords(t.radius,t.theta,t.y)}setFromCylindricalCoords(t,e,n){return this.x=t*Math.sin(e),this.y=n,this.z=t*Math.cos(e),this}setFromMatrixPosition(t){const e=t.elements;return this.x=e[12],this.y=e[13],this.z=e[14],this}setFromMatrixScale(t){const e=this.setFromMatrixColumn(t,0).length(),n=this.setFromMatrixColumn(t,1).length(),i=this.setFromMatrixColumn(t,2).length();return this.x=e,this.y=n,this.z=i,this}setFromMatrixColumn(t,e){return this.fromArray(t.elements,4*e)}setFromMatrix3Column(t,e){return this.fromArray(t.elements,3*e)}setFromEuler(t){return this.x=t._x,this.y=t._y,this.z=t._z,this}setFromColor(t){return this.x=t.r,this.y=t.g,this.z=t.b,this}equals(t){return t.x===this.x&&t.y===this.y&&t.z===this.z}fromArray(t,e=0){return this.x=t[e],this.y=t[e+1],this.z=t[e+2],this}toArray(t=[],e=0){return t[e]=this.x,t[e+1]=this.y,t[e+2]=this.z,t}fromBufferAttribute(t,e){return this.x=t.getX(e),this.y=t.getY(e),this.z=t.getZ(e),this}random(){return this.x=Math.random(),this.y=Math.random(),this.z=Math.random(),this}randomDirection(){const t=2*(Math.random()-.5),e=Math.random()*Math.PI*2,n=Math.sqrt(1-t**2);return this.x=n*Math.cos(e),this.y=n*Math.sin(e),this.z=t,this}*[Symbol.iterator](){yield this.x,yield this.y,yield this.z}}const Li=new Pi,Ii=new Ci;class Ui{constructor(t=new Pi(1/0,1/0,1/0),e=new Pi(-1/0,-1/0,-1/0)){this.isBox3=!0,this.min=t,this.max=e}set(t,e){return this.min.copy(t),this.max.copy(e),this}setFromArray(t){this.makeEmpty();for(let e=0,n=t.length;ethis.max.x||t.ythis.max.y||t.zthis.max.z)}containsBox(t){return this.min.x<=t.min.x&&t.max.x<=this.max.x&&this.min.y<=t.min.y&&t.max.y<=this.max.y&&this.min.z<=t.min.z&&t.max.z<=this.max.z}getParameter(t,e){return e.set((t.x-this.min.x)/(this.max.x-this.min.x),(t.y-this.min.y)/(this.max.y-this.min.y),(t.z-this.min.z)/(this.max.z-this.min.z))}intersectsBox(t){return!(t.max.xthis.max.x||t.max.ythis.max.y||t.max.zthis.max.z)}intersectsSphere(t){return this.clampPoint(t.center,Di),Di.distanceToSquared(t.center)<=t.radius*t.radius}intersectsPlane(t){let e,n;return t.normal.x>0?(e=t.normal.x*this.min.x,n=t.normal.x*this.max.x):(e=t.normal.x*this.max.x,n=t.normal.x*this.min.x),t.normal.y>0?(e+=t.normal.y*this.min.y,n+=t.normal.y*this.max.y):(e+=t.normal.y*this.max.y,n+=t.normal.y*this.min.y),t.normal.z>0?(e+=t.normal.z*this.min.z,n+=t.normal.z*this.max.z):(e+=t.normal.z*this.max.z,n+=t.normal.z*this.min.z),e<=-t.constant&&n>=-t.constant}intersectsTriangle(t){if(this.isEmpty())return!1;this.getCenter(Gi),Wi.subVectors(this.max,Gi),Fi.subVectors(t.a,Gi),Bi.subVectors(t.b,Gi),zi.subVectors(t.c,Gi),Hi.subVectors(Bi,Fi),Vi.subVectors(zi,Bi),ki.subVectors(Fi,zi);let e=[0,-Hi.z,Hi.y,0,-Vi.z,Vi.y,0,-ki.z,ki.y,Hi.z,0,-Hi.x,Vi.z,0,-Vi.x,ki.z,0,-ki.x,-Hi.y,Hi.x,0,-Vi.y,Vi.x,0,-ki.y,ki.x,0];return!!qi(e,Fi,Bi,zi,Wi)&&(e=[1,0,0,0,1,0,0,0,1],!!qi(e,Fi,Bi,zi,Wi)&&(Xi.crossVectors(Hi,Vi),e=[Xi.x,Xi.y,Xi.z],qi(e,Fi,Bi,zi,Wi)))}clampPoint(t,e){return e.copy(t).clamp(this.min,this.max)}distanceToPoint(t){return this.clampPoint(t,Di).distanceTo(t)}getBoundingSphere(t){return this.isEmpty()?t.makeEmpty():(this.getCenter(t.center),t.radius=.5*this.getSize(Di).length()),t}intersect(t){return this.min.max(t.min),this.max.min(t.max),this.isEmpty()&&this.makeEmpty(),this}union(t){return this.min.min(t.min),this.max.max(t.max),this}applyMatrix4(t){return this.isEmpty()||(Ni[0].set(this.min.x,this.min.y,this.min.z).applyMatrix4(t),Ni[1].set(this.min.x,this.min.y,this.max.z).applyMatrix4(t),Ni[2].set(this.min.x,this.max.y,this.min.z).applyMatrix4(t),Ni[3].set(this.min.x,this.max.y,this.max.z).applyMatrix4(t),Ni[4].set(this.max.x,this.min.y,this.min.z).applyMatrix4(t),Ni[5].set(this.max.x,this.min.y,this.max.z).applyMatrix4(t),Ni[6].set(this.max.x,this.max.y,this.min.z).applyMatrix4(t),Ni[7].set(this.max.x,this.max.y,this.max.z).applyMatrix4(t),this.setFromPoints(Ni)),this}translate(t){return this.min.add(t),this.max.add(t),this}equals(t){return t.min.equals(this.min)&&t.max.equals(this.max)}}const Ni=[new Pi,new Pi,new Pi,new Pi,new Pi,new Pi,new Pi,new Pi],Di=new Pi,Oi=new Ui,Fi=new Pi,Bi=new Pi,zi=new Pi,Hi=new Pi,Vi=new Pi,ki=new Pi,Gi=new Pi,Wi=new Pi,Xi=new Pi,ji=new Pi;function qi(t,e,n,i,r){for(let s=0,a=t.length-3;s<=a;s+=3){ji.fromArray(t,s);const a=r.x*Math.abs(ji.x)+r.y*Math.abs(ji.y)+r.z*Math.abs(ji.z),o=e.dot(ji),l=n.dot(ji),c=i.dot(ji);if(Math.max(-Math.max(o,l,c),Math.min(o,l,c))>a)return!1}return!0}const Yi=new Ui,Zi=new Pi,Ji=new Pi;class Ki{constructor(t=new Pi,e=-1){this.isSphere=!0,this.center=t,this.radius=e}set(t,e){return this.center.copy(t),this.radius=e,this}setFromPoints(t,e){const n=this.center;void 0!==e?n.copy(e):Yi.setFromPoints(t).getCenter(n);let i=0;for(let e=0,r=t.length;ethis.radius*this.radius&&(e.sub(this.center).normalize(),e.multiplyScalar(this.radius).add(this.center)),e}getBoundingBox(t){return this.isEmpty()?(t.makeEmpty(),t):(t.set(this.center,this.center),t.expandByScalar(this.radius),t)}applyMatrix4(t){return this.center.applyMatrix4(t),this.radius=this.radius*t.getMaxScaleOnAxis(),this}translate(t){return this.center.add(t),this}expandByPoint(t){if(this.isEmpty())return this.center.copy(t),this.radius=0,this;Zi.subVectors(t,this.center);const e=Zi.lengthSq();if(e>this.radius*this.radius){const t=Math.sqrt(e),n=.5*(t-this.radius);this.center.addScaledVector(Zi,n/t),this.radius+=n}return this}union(t){return t.isEmpty()?this:this.isEmpty()?(this.copy(t),this):(!0===this.center.equals(t.center)?this.radius=Math.max(this.radius,t.radius):(Ji.subVectors(t.center,this.center).setLength(t.radius),this.expandByPoint(Zi.copy(t.center).add(Ji)),this.expandByPoint(Zi.copy(t.center).sub(Ji))),this)}equals(t){return t.center.equals(this.center)&&t.radius===this.radius}clone(){return(new this.constructor).copy(this)}}const $i=new Pi,Qi=new Pi,tr=new Pi,er=new Pi,nr=new Pi,ir=new Pi,rr=new Pi;class sr{constructor(t=new Pi,e=new Pi(0,0,-1)){this.origin=t,this.direction=e}set(t,e){return this.origin.copy(t),this.direction.copy(e),this}copy(t){return this.origin.copy(t.origin),this.direction.copy(t.direction),this}at(t,e){return e.copy(this.origin).addScaledVector(this.direction,t)}lookAt(t){return this.direction.copy(t).sub(this.origin).normalize(),this}recast(t){return this.origin.copy(this.at(t,$i)),this}closestPointToPoint(t,e){e.subVectors(t,this.origin);const n=e.dot(this.direction);return n<0?e.copy(this.origin):e.copy(this.origin).addScaledVector(this.direction,n)}distanceToPoint(t){return Math.sqrt(this.distanceSqToPoint(t))}distanceSqToPoint(t){const e=$i.subVectors(t,this.origin).dot(this.direction);return e<0?this.origin.distanceToSquared(t):($i.copy(this.origin).addScaledVector(this.direction,e),$i.distanceToSquared(t))}distanceSqToSegment(t,e,n,i){Qi.copy(t).add(e).multiplyScalar(.5),tr.copy(e).sub(t).normalize(),er.copy(this.origin).sub(Qi);const r=.5*t.distanceTo(e),s=-this.direction.dot(tr),a=er.dot(this.direction),o=-er.dot(tr),l=er.lengthSq(),c=Math.abs(1-s*s);let h,u,d,p;if(c>0)if(h=s*o-a,u=s*a-o,p=r*c,h>=0)if(u>=-p)if(u<=p){const t=1/c;h*=t,u*=t,d=h*(h+s*u+2*a)+u*(s*h+u+2*o)+l}else u=r,h=Math.max(0,-(s*u+a)),d=-h*h+u*(u+2*o)+l;else u=-r,h=Math.max(0,-(s*u+a)),d=-h*h+u*(u+2*o)+l;else u<=-p?(h=Math.max(0,-(-s*r+a)),u=h>0?-r:Math.min(Math.max(-r,-o),r),d=-h*h+u*(u+2*o)+l):u<=p?(h=0,u=Math.min(Math.max(-r,-o),r),d=u*(u+2*o)+l):(h=Math.max(0,-(s*r+a)),u=h>0?r:Math.min(Math.max(-r,-o),r),d=-h*h+u*(u+2*o)+l);else u=s>0?-r:r,h=Math.max(0,-(s*u+a)),d=-h*h+u*(u+2*o)+l;return n&&n.copy(this.origin).addScaledVector(this.direction,h),i&&i.copy(Qi).addScaledVector(tr,u),d}intersectSphere(t,e){$i.subVectors(t.center,this.origin);const n=$i.dot(this.direction),i=$i.dot($i)-n*n,r=t.radius*t.radius;if(i>r)return null;const s=Math.sqrt(r-i),a=n-s,o=n+s;return o<0?null:a<0?this.at(o,e):this.at(a,e)}intersectsSphere(t){return this.distanceSqToPoint(t.center)<=t.radius*t.radius}distanceToPlane(t){const e=t.normal.dot(this.direction);if(0===e)return 0===t.distanceToPoint(this.origin)?0:null;const n=-(this.origin.dot(t.normal)+t.constant)/e;return n>=0?n:null}intersectPlane(t,e){const n=this.distanceToPlane(t);return null===n?null:this.at(n,e)}intersectsPlane(t){const e=t.distanceToPoint(this.origin);if(0===e)return!0;return t.normal.dot(this.direction)*e<0}intersectBox(t,e){let n,i,r,s,a,o;const l=1/this.direction.x,c=1/this.direction.y,h=1/this.direction.z,u=this.origin;return l>=0?(n=(t.min.x-u.x)*l,i=(t.max.x-u.x)*l):(n=(t.max.x-u.x)*l,i=(t.min.x-u.x)*l),c>=0?(r=(t.min.y-u.y)*c,s=(t.max.y-u.y)*c):(r=(t.max.y-u.y)*c,s=(t.min.y-u.y)*c),n>s||r>i?null:((r>n||isNaN(n))&&(n=r),(s=0?(a=(t.min.z-u.z)*h,o=(t.max.z-u.z)*h):(a=(t.max.z-u.z)*h,o=(t.min.z-u.z)*h),n>o||a>i?null:((a>n||n!=n)&&(n=a),(o=0?n:i,e)))}intersectsBox(t){return null!==this.intersectBox(t,$i)}intersectTriangle(t,e,n,i,r){nr.subVectors(e,t),ir.subVectors(n,t),rr.crossVectors(nr,ir);let s,a=this.direction.dot(rr);if(a>0){if(i)return null;s=1}else{if(!(a<0))return null;s=-1,a=-a}er.subVectors(this.origin,t);const o=s*this.direction.dot(ir.crossVectors(er,ir));if(o<0)return null;const l=s*this.direction.dot(nr.cross(er));if(l<0)return null;if(o+l>a)return null;const c=-s*er.dot(rr);return c<0?null:this.at(c/a,r)}applyMatrix4(t){return this.origin.applyMatrix4(t),this.direction.transformDirection(t),this}equals(t){return t.origin.equals(this.origin)&&t.direction.equals(this.direction)}clone(){return(new this.constructor).copy(this)}}class ar{constructor(t,e,n,i,r,s,a,o,l,c,h,u,d,p,m,f){ar.prototype.isMatrix4=!0,this.elements=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],void 0!==t&&this.set(t,e,n,i,r,s,a,o,l,c,h,u,d,p,m,f)}set(t,e,n,i,r,s,a,o,l,c,h,u,d,p,m,f){const g=this.elements;return g[0]=t,g[4]=e,g[8]=n,g[12]=i,g[1]=r,g[5]=s,g[9]=a,g[13]=o,g[2]=l,g[6]=c,g[10]=h,g[14]=u,g[3]=d,g[7]=p,g[11]=m,g[15]=f,this}identity(){return this.set(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1),this}clone(){return(new ar).fromArray(this.elements)}copy(t){const e=this.elements,n=t.elements;return e[0]=n[0],e[1]=n[1],e[2]=n[2],e[3]=n[3],e[4]=n[4],e[5]=n[5],e[6]=n[6],e[7]=n[7],e[8]=n[8],e[9]=n[9],e[10]=n[10],e[11]=n[11],e[12]=n[12],e[13]=n[13],e[14]=n[14],e[15]=n[15],this}copyPosition(t){const e=this.elements,n=t.elements;return e[12]=n[12],e[13]=n[13],e[14]=n[14],this}setFromMatrix3(t){const e=t.elements;return this.set(e[0],e[3],e[6],0,e[1],e[4],e[7],0,e[2],e[5],e[8],0,0,0,0,1),this}extractBasis(t,e,n){return t.setFromMatrixColumn(this,0),e.setFromMatrixColumn(this,1),n.setFromMatrixColumn(this,2),this}makeBasis(t,e,n){return this.set(t.x,e.x,n.x,0,t.y,e.y,n.y,0,t.z,e.z,n.z,0,0,0,0,1),this}extractRotation(t){const e=this.elements,n=t.elements,i=1/or.setFromMatrixColumn(t,0).length(),r=1/or.setFromMatrixColumn(t,1).length(),s=1/or.setFromMatrixColumn(t,2).length();return e[0]=n[0]*i,e[1]=n[1]*i,e[2]=n[2]*i,e[3]=0,e[4]=n[4]*r,e[5]=n[5]*r,e[6]=n[6]*r,e[7]=0,e[8]=n[8]*s,e[9]=n[9]*s,e[10]=n[10]*s,e[11]=0,e[12]=0,e[13]=0,e[14]=0,e[15]=1,this}makeRotationFromEuler(t){const e=this.elements,n=t.x,i=t.y,r=t.z,s=Math.cos(n),a=Math.sin(n),o=Math.cos(i),l=Math.sin(i),c=Math.cos(r),h=Math.sin(r);if("XYZ"===t.order){const t=s*c,n=s*h,i=a*c,r=a*h;e[0]=o*c,e[4]=-o*h,e[8]=l,e[1]=n+i*l,e[5]=t-r*l,e[9]=-a*o,e[2]=r-t*l,e[6]=i+n*l,e[10]=s*o}else if("YXZ"===t.order){const t=o*c,n=o*h,i=l*c,r=l*h;e[0]=t+r*a,e[4]=i*a-n,e[8]=s*l,e[1]=s*h,e[5]=s*c,e[9]=-a,e[2]=n*a-i,e[6]=r+t*a,e[10]=s*o}else if("ZXY"===t.order){const t=o*c,n=o*h,i=l*c,r=l*h;e[0]=t-r*a,e[4]=-s*h,e[8]=i+n*a,e[1]=n+i*a,e[5]=s*c,e[9]=r-t*a,e[2]=-s*l,e[6]=a,e[10]=s*o}else if("ZYX"===t.order){const t=s*c,n=s*h,i=a*c,r=a*h;e[0]=o*c,e[4]=i*l-n,e[8]=t*l+r,e[1]=o*h,e[5]=r*l+t,e[9]=n*l-i,e[2]=-l,e[6]=a*o,e[10]=s*o}else if("YZX"===t.order){const t=s*o,n=s*l,i=a*o,r=a*l;e[0]=o*c,e[4]=r-t*h,e[8]=i*h+n,e[1]=h,e[5]=s*c,e[9]=-a*c,e[2]=-l*c,e[6]=n*h+i,e[10]=t-r*h}else if("XZY"===t.order){const t=s*o,n=s*l,i=a*o,r=a*l;e[0]=o*c,e[4]=-h,e[8]=l*c,e[1]=t*h+r,e[5]=s*c,e[9]=n*h-i,e[2]=i*h-n,e[6]=a*c,e[10]=r*h+t}return e[3]=0,e[7]=0,e[11]=0,e[12]=0,e[13]=0,e[14]=0,e[15]=1,this}makeRotationFromQuaternion(t){return this.compose(cr,t,hr)}lookAt(t,e,n){const i=this.elements;return pr.subVectors(t,e),0===pr.lengthSq()&&(pr.z=1),pr.normalize(),ur.crossVectors(n,pr),0===ur.lengthSq()&&(1===Math.abs(n.z)?pr.x+=1e-4:pr.z+=1e-4,pr.normalize(),ur.crossVectors(n,pr)),ur.normalize(),dr.crossVectors(pr,ur),i[0]=ur.x,i[4]=dr.x,i[8]=pr.x,i[1]=ur.y,i[5]=dr.y,i[9]=pr.y,i[2]=ur.z,i[6]=dr.z,i[10]=pr.z,this}multiply(t){return this.multiplyMatrices(this,t)}premultiply(t){return this.multiplyMatrices(t,this)}multiplyMatrices(t,e){const n=t.elements,i=e.elements,r=this.elements,s=n[0],a=n[4],o=n[8],l=n[12],c=n[1],h=n[5],u=n[9],d=n[13],p=n[2],m=n[6],f=n[10],g=n[14],_=n[3],v=n[7],x=n[11],y=n[15],M=i[0],S=i[4],b=i[8],E=i[12],T=i[1],w=i[5],A=i[9],R=i[13],C=i[2],P=i[6],L=i[10],I=i[14],U=i[3],N=i[7],D=i[11],O=i[15];return r[0]=s*M+a*T+o*C+l*U,r[4]=s*S+a*w+o*P+l*N,r[8]=s*b+a*A+o*L+l*D,r[12]=s*E+a*R+o*I+l*O,r[1]=c*M+h*T+u*C+d*U,r[5]=c*S+h*w+u*P+d*N,r[9]=c*b+h*A+u*L+d*D,r[13]=c*E+h*R+u*I+d*O,r[2]=p*M+m*T+f*C+g*U,r[6]=p*S+m*w+f*P+g*N,r[10]=p*b+m*A+f*L+g*D,r[14]=p*E+m*R+f*I+g*O,r[3]=_*M+v*T+x*C+y*U,r[7]=_*S+v*w+x*P+y*N,r[11]=_*b+v*A+x*L+y*D,r[15]=_*E+v*R+x*I+y*O,this}multiplyScalar(t){const e=this.elements;return e[0]*=t,e[4]*=t,e[8]*=t,e[12]*=t,e[1]*=t,e[5]*=t,e[9]*=t,e[13]*=t,e[2]*=t,e[6]*=t,e[10]*=t,e[14]*=t,e[3]*=t,e[7]*=t,e[11]*=t,e[15]*=t,this}determinant(){const t=this.elements,e=t[0],n=t[4],i=t[8],r=t[12],s=t[1],a=t[5],o=t[9],l=t[13],c=t[2],h=t[6],u=t[10],d=t[14];return t[3]*(+r*o*h-i*l*h-r*a*u+n*l*u+i*a*d-n*o*d)+t[7]*(+e*o*d-e*l*u+r*s*u-i*s*d+i*l*c-r*o*c)+t[11]*(+e*l*h-e*a*d-r*s*h+n*s*d+r*a*c-n*l*c)+t[15]*(-i*a*c-e*o*h+e*a*u+i*s*h-n*s*u+n*o*c)}transpose(){const t=this.elements;let e;return e=t[1],t[1]=t[4],t[4]=e,e=t[2],t[2]=t[8],t[8]=e,e=t[6],t[6]=t[9],t[9]=e,e=t[3],t[3]=t[12],t[12]=e,e=t[7],t[7]=t[13],t[13]=e,e=t[11],t[11]=t[14],t[14]=e,this}setPosition(t,e,n){const i=this.elements;return t.isVector3?(i[12]=t.x,i[13]=t.y,i[14]=t.z):(i[12]=t,i[13]=e,i[14]=n),this}invert(){const t=this.elements,e=t[0],n=t[1],i=t[2],r=t[3],s=t[4],a=t[5],o=t[6],l=t[7],c=t[8],h=t[9],u=t[10],d=t[11],p=t[12],m=t[13],f=t[14],g=t[15],_=h*f*l-m*u*l+m*o*d-a*f*d-h*o*g+a*u*g,v=p*u*l-c*f*l-p*o*d+s*f*d+c*o*g-s*u*g,x=c*m*l-p*h*l+p*a*d-s*m*d-c*a*g+s*h*g,y=p*h*o-c*m*o-p*a*u+s*m*u+c*a*f-s*h*f,M=e*_+n*v+i*x+r*y;if(0===M)return this.set(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);const S=1/M;return t[0]=_*S,t[1]=(m*u*r-h*f*r-m*i*d+n*f*d+h*i*g-n*u*g)*S,t[2]=(a*f*r-m*o*r+m*i*l-n*f*l-a*i*g+n*o*g)*S,t[3]=(h*o*r-a*u*r-h*i*l+n*u*l+a*i*d-n*o*d)*S,t[4]=v*S,t[5]=(c*f*r-p*u*r+p*i*d-e*f*d-c*i*g+e*u*g)*S,t[6]=(p*o*r-s*f*r-p*i*l+e*f*l+s*i*g-e*o*g)*S,t[7]=(s*u*r-c*o*r+c*i*l-e*u*l-s*i*d+e*o*d)*S,t[8]=x*S,t[9]=(p*h*r-c*m*r-p*n*d+e*m*d+c*n*g-e*h*g)*S,t[10]=(s*m*r-p*a*r+p*n*l-e*m*l-s*n*g+e*a*g)*S,t[11]=(c*a*r-s*h*r-c*n*l+e*h*l+s*n*d-e*a*d)*S,t[12]=y*S,t[13]=(c*m*i-p*h*i+p*n*u-e*m*u-c*n*f+e*h*f)*S,t[14]=(p*a*i-s*m*i-p*n*o+e*m*o+s*n*f-e*a*f)*S,t[15]=(s*h*i-c*a*i+c*n*o-e*h*o-s*n*u+e*a*u)*S,this}scale(t){const e=this.elements,n=t.x,i=t.y,r=t.z;return e[0]*=n,e[4]*=i,e[8]*=r,e[1]*=n,e[5]*=i,e[9]*=r,e[2]*=n,e[6]*=i,e[10]*=r,e[3]*=n,e[7]*=i,e[11]*=r,this}getMaxScaleOnAxis(){const t=this.elements,e=t[0]*t[0]+t[1]*t[1]+t[2]*t[2],n=t[4]*t[4]+t[5]*t[5]+t[6]*t[6],i=t[8]*t[8]+t[9]*t[9]+t[10]*t[10];return Math.sqrt(Math.max(e,n,i))}makeTranslation(t,e,n){return t.isVector3?this.set(1,0,0,t.x,0,1,0,t.y,0,0,1,t.z,0,0,0,1):this.set(1,0,0,t,0,1,0,e,0,0,1,n,0,0,0,1),this}makeRotationX(t){const e=Math.cos(t),n=Math.sin(t);return this.set(1,0,0,0,0,e,-n,0,0,n,e,0,0,0,0,1),this}makeRotationY(t){const e=Math.cos(t),n=Math.sin(t);return this.set(e,0,n,0,0,1,0,0,-n,0,e,0,0,0,0,1),this}makeRotationZ(t){const e=Math.cos(t),n=Math.sin(t);return this.set(e,-n,0,0,n,e,0,0,0,0,1,0,0,0,0,1),this}makeRotationAxis(t,e){const n=Math.cos(e),i=Math.sin(e),r=1-n,s=t.x,a=t.y,o=t.z,l=r*s,c=r*a;return this.set(l*s+n,l*a-i*o,l*o+i*a,0,l*a+i*o,c*a+n,c*o-i*s,0,l*o-i*a,c*o+i*s,r*o*o+n,0,0,0,0,1),this}makeScale(t,e,n){return this.set(t,0,0,0,0,e,0,0,0,0,n,0,0,0,0,1),this}makeShear(t,e,n,i,r,s){return this.set(1,n,r,0,t,1,s,0,e,i,1,0,0,0,0,1),this}compose(t,e,n){const i=this.elements,r=e._x,s=e._y,a=e._z,o=e._w,l=r+r,c=s+s,h=a+a,u=r*l,d=r*c,p=r*h,m=s*c,f=s*h,g=a*h,_=o*l,v=o*c,x=o*h,y=n.x,M=n.y,S=n.z;return i[0]=(1-(m+g))*y,i[1]=(d+x)*y,i[2]=(p-v)*y,i[3]=0,i[4]=(d-x)*M,i[5]=(1-(u+g))*M,i[6]=(f+_)*M,i[7]=0,i[8]=(p+v)*S,i[9]=(f-_)*S,i[10]=(1-(u+m))*S,i[11]=0,i[12]=t.x,i[13]=t.y,i[14]=t.z,i[15]=1,this}decompose(t,e,n){const i=this.elements;let r=or.set(i[0],i[1],i[2]).length();const s=or.set(i[4],i[5],i[6]).length(),a=or.set(i[8],i[9],i[10]).length();this.determinant()<0&&(r=-r),t.x=i[12],t.y=i[13],t.z=i[14],lr.copy(this);const o=1/r,l=1/s,c=1/a;return lr.elements[0]*=o,lr.elements[1]*=o,lr.elements[2]*=o,lr.elements[4]*=l,lr.elements[5]*=l,lr.elements[6]*=l,lr.elements[8]*=c,lr.elements[9]*=c,lr.elements[10]*=c,e.setFromRotationMatrix(lr),n.x=r,n.y=s,n.z=a,this}makePerspective(t,e,n,i,r,s,a=2e3){const o=this.elements,l=2*r/(e-t),c=2*r/(n-i),h=(e+t)/(e-t),u=(n+i)/(n-i);let d,p;if(a===Dn)d=-(s+r)/(s-r),p=-2*s*r/(s-r);else{if(a!==On)throw new Error("THREE.Matrix4.makePerspective(): Invalid coordinate system: "+a);d=-s/(s-r),p=-s*r/(s-r)}return o[0]=l,o[4]=0,o[8]=h,o[12]=0,o[1]=0,o[5]=c,o[9]=u,o[13]=0,o[2]=0,o[6]=0,o[10]=d,o[14]=p,o[3]=0,o[7]=0,o[11]=-1,o[15]=0,this}makeOrthographic(t,e,n,i,r,s,a=2e3){const o=this.elements,l=1/(e-t),c=1/(n-i),h=1/(s-r),u=(e+t)*l,d=(n+i)*c;let p,m;if(a===Dn)p=(s+r)*h,m=-2*h;else{if(a!==On)throw new Error("THREE.Matrix4.makeOrthographic(): Invalid coordinate system: "+a);p=r*h,m=-1*h}return o[0]=2*l,o[4]=0,o[8]=0,o[12]=-u,o[1]=0,o[5]=2*c,o[9]=0,o[13]=-d,o[2]=0,o[6]=0,o[10]=m,o[14]=-p,o[3]=0,o[7]=0,o[11]=0,o[15]=1,this}equals(t){const e=this.elements,n=t.elements;for(let t=0;t<16;t++)if(e[t]!==n[t])return!1;return!0}fromArray(t,e=0){for(let n=0;n<16;n++)this.elements[n]=t[n+e];return this}toArray(t=[],e=0){const n=this.elements;return t[e]=n[0],t[e+1]=n[1],t[e+2]=n[2],t[e+3]=n[3],t[e+4]=n[4],t[e+5]=n[5],t[e+6]=n[6],t[e+7]=n[7],t[e+8]=n[8],t[e+9]=n[9],t[e+10]=n[10],t[e+11]=n[11],t[e+12]=n[12],t[e+13]=n[13],t[e+14]=n[14],t[e+15]=n[15],t}}const or=new Pi,lr=new ar,cr=new Pi(0,0,0),hr=new Pi(1,1,1),ur=new Pi,dr=new Pi,pr=new Pi,mr=new ar,fr=new Ci;class gr{constructor(t=0,e=0,n=0,i=gr.DEFAULT_ORDER){this.isEuler=!0,this._x=t,this._y=e,this._z=n,this._order=i}get x(){return this._x}set x(t){this._x=t,this._onChangeCallback()}get y(){return this._y}set y(t){this._y=t,this._onChangeCallback()}get z(){return this._z}set z(t){this._z=t,this._onChangeCallback()}get order(){return this._order}set order(t){this._order=t,this._onChangeCallback()}set(t,e,n,i=this._order){return this._x=t,this._y=e,this._z=n,this._order=i,this._onChangeCallback(),this}clone(){return new this.constructor(this._x,this._y,this._z,this._order)}copy(t){return this._x=t._x,this._y=t._y,this._z=t._z,this._order=t._order,this._onChangeCallback(),this}setFromRotationMatrix(t,e=this._order,n=!0){const i=t.elements,r=i[0],s=i[4],a=i[8],o=i[1],l=i[5],c=i[9],h=i[2],u=i[6],d=i[10];switch(e){case"XYZ":this._y=Math.asin(Gn(a,-1,1)),Math.abs(a)<.9999999?(this._x=Math.atan2(-c,d),this._z=Math.atan2(-s,r)):(this._x=Math.atan2(u,l),this._z=0);break;case"YXZ":this._x=Math.asin(-Gn(c,-1,1)),Math.abs(c)<.9999999?(this._y=Math.atan2(a,d),this._z=Math.atan2(o,l)):(this._y=Math.atan2(-h,r),this._z=0);break;case"ZXY":this._x=Math.asin(Gn(u,-1,1)),Math.abs(u)<.9999999?(this._y=Math.atan2(-h,d),this._z=Math.atan2(-s,l)):(this._y=0,this._z=Math.atan2(o,r));break;case"ZYX":this._y=Math.asin(-Gn(h,-1,1)),Math.abs(h)<.9999999?(this._x=Math.atan2(u,d),this._z=Math.atan2(o,r)):(this._x=0,this._z=Math.atan2(-s,l));break;case"YZX":this._z=Math.asin(Gn(o,-1,1)),Math.abs(o)<.9999999?(this._x=Math.atan2(-c,l),this._y=Math.atan2(-h,r)):(this._x=0,this._y=Math.atan2(a,d));break;case"XZY":this._z=Math.asin(-Gn(s,-1,1)),Math.abs(s)<.9999999?(this._x=Math.atan2(u,l),this._y=Math.atan2(a,r)):(this._x=Math.atan2(-c,d),this._y=0);break;default:console.warn("THREE.Euler: .setFromRotationMatrix() encountered an unknown order: "+e)}return this._order=e,!0===n&&this._onChangeCallback(),this}setFromQuaternion(t,e,n){return mr.makeRotationFromQuaternion(t),this.setFromRotationMatrix(mr,e,n)}setFromVector3(t,e=this._order){return this.set(t.x,t.y,t.z,e)}reorder(t){return fr.setFromEuler(this),this.setFromQuaternion(fr,t)}equals(t){return t._x===this._x&&t._y===this._y&&t._z===this._z&&t._order===this._order}fromArray(t){return this._x=t[0],this._y=t[1],this._z=t[2],void 0!==t[3]&&(this._order=t[3]),this._onChangeCallback(),this}toArray(t=[],e=0){return t[e]=this._x,t[e+1]=this._y,t[e+2]=this._z,t[e+3]=this._order,t}_onChange(t){return this._onChangeCallback=t,this}_onChangeCallback(){}*[Symbol.iterator](){yield this._x,yield this._y,yield this._z,yield this._order}}gr.DEFAULT_ORDER="XYZ";class _r{constructor(){this.mask=1}set(t){this.mask=(1<>>0}enable(t){this.mask|=1<1){for(let t=0;t1){for(let t=0;t0&&(i.userData=this.userData),i.layers=this.layers.mask,i.matrix=this.matrix.toArray(),i.up=this.up.toArray(),!1===this.matrixAutoUpdate&&(i.matrixAutoUpdate=!1),this.isInstancedMesh&&(i.type="InstancedMesh",i.count=this.count,i.instanceMatrix=this.instanceMatrix.toJSON(),null!==this.instanceColor&&(i.instanceColor=this.instanceColor.toJSON())),this.isBatchedMesh&&(i.type="BatchedMesh",i.perObjectFrustumCulled=this.perObjectFrustumCulled,i.sortObjects=this.sortObjects,i.drawRanges=this._drawRanges,i.reservedRanges=this._reservedRanges,i.visibility=this._visibility,i.active=this._active,i.bounds=this._bounds.map((t=>({boxInitialized:t.boxInitialized,boxMin:t.box.min.toArray(),boxMax:t.box.max.toArray(),sphereInitialized:t.sphereInitialized,sphereRadius:t.sphere.radius,sphereCenter:t.sphere.center.toArray()}))),i.maxGeometryCount=this._maxGeometryCount,i.maxVertexCount=this._maxVertexCount,i.maxIndexCount=this._maxIndexCount,i.geometryInitialized=this._geometryInitialized,i.geometryCount=this._geometryCount,i.matricesTexture=this._matricesTexture.toJSON(t),null!==this.boundingSphere&&(i.boundingSphere={center:i.boundingSphere.center.toArray(),radius:i.boundingSphere.radius}),null!==this.boundingBox&&(i.boundingBox={min:i.boundingBox.min.toArray(),max:i.boundingBox.max.toArray()})),this.isScene)this.background&&(this.background.isColor?i.background=this.background.toJSON():this.background.isTexture&&(i.background=this.background.toJSON(t).uuid)),this.environment&&this.environment.isTexture&&!0!==this.environment.isRenderTargetTexture&&(i.environment=this.environment.toJSON(t).uuid);else if(this.isMesh||this.isLine||this.isPoints){i.geometry=r(t.geometries,this.geometry);const e=this.geometry.parameters;if(void 0!==e&&void 0!==e.shapes){const n=e.shapes;if(Array.isArray(n))for(let e=0,i=n.length;e0){i.children=[];for(let e=0;e0){i.animations=[];for(let e=0;e0&&(n.geometries=e),i.length>0&&(n.materials=i),r.length>0&&(n.textures=r),a.length>0&&(n.images=a),o.length>0&&(n.shapes=o),l.length>0&&(n.skeletons=l),c.length>0&&(n.animations=c),h.length>0&&(n.nodes=h)}return n.object=i,n;function s(t){const e=[];for(const n in t){const i=t[n];delete i.metadata,e.push(i)}return e}}clone(t){return(new this.constructor).copy(this,t)}copy(t,e=!0){if(this.name=t.name,this.up.copy(t.up),this.position.copy(t.position),this.rotation.order=t.rotation.order,this.quaternion.copy(t.quaternion),this.scale.copy(t.scale),this.matrix.copy(t.matrix),this.matrixWorld.copy(t.matrixWorld),this.matrixAutoUpdate=t.matrixAutoUpdate,this.matrixWorldAutoUpdate=t.matrixWorldAutoUpdate,this.matrixWorldNeedsUpdate=t.matrixWorldNeedsUpdate,this.layers.mask=t.layers.mask,this.visible=t.visible,this.castShadow=t.castShadow,this.receiveShadow=t.receiveShadow,this.frustumCulled=t.frustumCulled,this.renderOrder=t.renderOrder,this.animations=t.animations.slice(),this.userData=JSON.parse(JSON.stringify(t.userData)),!0===e)for(let e=0;e0?i.multiplyScalar(1/Math.sqrt(r)):i.set(0,0,0)}static getBarycoord(t,e,n,i,r){Ir.subVectors(i,e),Ur.subVectors(n,e),Nr.subVectors(t,e);const s=Ir.dot(Ir),a=Ir.dot(Ur),o=Ir.dot(Nr),l=Ur.dot(Ur),c=Ur.dot(Nr),h=s*l-a*a;if(0===h)return r.set(0,0,0),null;const u=1/h,d=(l*o-a*c)*u,p=(s*c-a*o)*u;return r.set(1-d-p,p,d)}static containsPoint(t,e,n,i){return null!==this.getBarycoord(t,e,n,i,Dr)&&(Dr.x>=0&&Dr.y>=0&&Dr.x+Dr.y<=1)}static getInterpolation(t,e,n,i,r,s,a,o){return null===this.getBarycoord(t,e,n,i,Dr)?(o.x=0,o.y=0,"z"in o&&(o.z=0),"w"in o&&(o.w=0),null):(o.setScalar(0),o.addScaledVector(r,Dr.x),o.addScaledVector(s,Dr.y),o.addScaledVector(a,Dr.z),o)}static isFrontFacing(t,e,n,i){return Ir.subVectors(n,e),Ur.subVectors(t,e),Ir.cross(Ur).dot(i)<0}set(t,e,n){return this.a.copy(t),this.b.copy(e),this.c.copy(n),this}setFromPointsAndIndices(t,e,n,i){return this.a.copy(t[e]),this.b.copy(t[n]),this.c.copy(t[i]),this}setFromAttributeAndIndices(t,e,n,i){return this.a.fromBufferAttribute(t,e),this.b.fromBufferAttribute(t,n),this.c.fromBufferAttribute(t,i),this}clone(){return(new this.constructor).copy(this)}copy(t){return this.a.copy(t.a),this.b.copy(t.b),this.c.copy(t.c),this}getArea(){return Ir.subVectors(this.c,this.b),Ur.subVectors(this.a,this.b),.5*Ir.cross(Ur).length()}getMidpoint(t){return t.addVectors(this.a,this.b).add(this.c).multiplyScalar(1/3)}getNormal(t){return kr.getNormal(this.a,this.b,this.c,t)}getPlane(t){return t.setFromCoplanarPoints(this.a,this.b,this.c)}getBarycoord(t,e){return kr.getBarycoord(t,this.a,this.b,this.c,e)}getInterpolation(t,e,n,i,r){return kr.getInterpolation(t,this.a,this.b,this.c,e,n,i,r)}containsPoint(t){return kr.containsPoint(t,this.a,this.b,this.c)}isFrontFacing(t){return kr.isFrontFacing(this.a,this.b,this.c,t)}intersectsBox(t){return t.intersectsTriangle(this)}closestPointToPoint(t,e){const n=this.a,i=this.b,r=this.c;let s,a;Or.subVectors(i,n),Fr.subVectors(r,n),zr.subVectors(t,n);const o=Or.dot(zr),l=Fr.dot(zr);if(o<=0&&l<=0)return e.copy(n);Hr.subVectors(t,i);const c=Or.dot(Hr),h=Fr.dot(Hr);if(c>=0&&h<=c)return e.copy(i);const u=o*h-c*l;if(u<=0&&o>=0&&c<=0)return s=o/(o-c),e.copy(n).addScaledVector(Or,s);Vr.subVectors(t,r);const d=Or.dot(Vr),p=Fr.dot(Vr);if(p>=0&&d<=p)return e.copy(r);const m=d*l-o*p;if(m<=0&&l>=0&&p<=0)return a=l/(l-p),e.copy(n).addScaledVector(Fr,a);const f=c*p-d*h;if(f<=0&&h-c>=0&&d-p>=0)return Br.subVectors(r,i),a=(h-c)/(h-c+(d-p)),e.copy(i).addScaledVector(Br,a);const g=1/(f+m+u);return s=m*g,a=u*g,e.copy(n).addScaledVector(Or,s).addScaledVector(Fr,a)}equals(t){return t.a.equals(this.a)&&t.b.equals(this.b)&&t.c.equals(this.c)}}const Gr={aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074},Wr={h:0,s:0,l:0},Xr={h:0,s:0,l:0};function jr(t,e,n){return n<0&&(n+=1),n>1&&(n-=1),n<1/6?t+6*(e-t)*n:n<.5?e:n<2/3?t+6*(e-t)*(2/3-n):t}class qr{constructor(t,e,n){return this.isColor=!0,this.r=1,this.g=1,this.b=1,this.set(t,e,n)}set(t,e,n){if(void 0===e&&void 0===n){const e=t;e&&e.isColor?this.copy(e):"number"==typeof e?this.setHex(e):"string"==typeof e&&this.setStyle(e)}else this.setRGB(t,e,n);return this}setScalar(t){return this.r=t,this.g=t,this.b=t,this}setHex(t,e=We){return t=Math.floor(t),this.r=(t>>16&255)/255,this.g=(t>>8&255)/255,this.b=(255&t)/255,ui.toWorkingColorSpace(this,e),this}setRGB(t,e,n,i=ui.workingColorSpace){return this.r=t,this.g=e,this.b=n,ui.toWorkingColorSpace(this,i),this}setHSL(t,e,n,i=ui.workingColorSpace){if(t=Wn(t,1),e=Gn(e,0,1),n=Gn(n,0,1),0===e)this.r=this.g=this.b=n;else{const i=n<=.5?n*(1+e):n+e-n*e,r=2*n-i;this.r=jr(r,i,t+1/3),this.g=jr(r,i,t),this.b=jr(r,i,t-1/3)}return ui.toWorkingColorSpace(this,i),this}setStyle(t,e=We){function n(e){void 0!==e&&parseFloat(e)<1&&console.warn("THREE.Color: Alpha component of "+t+" will be ignored.")}let i;if(i=/^(\w+)\(([^\)]*)\)/.exec(t)){let r;const s=i[1],a=i[2];switch(s){case"rgb":case"rgba":if(r=/^\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(a))return n(r[4]),this.setRGB(Math.min(255,parseInt(r[1],10))/255,Math.min(255,parseInt(r[2],10))/255,Math.min(255,parseInt(r[3],10))/255,e);if(r=/^\s*(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(a))return n(r[4]),this.setRGB(Math.min(100,parseInt(r[1],10))/100,Math.min(100,parseInt(r[2],10))/100,Math.min(100,parseInt(r[3],10))/100,e);break;case"hsl":case"hsla":if(r=/^\s*(\d*\.?\d+)\s*,\s*(\d*\.?\d+)\%\s*,\s*(\d*\.?\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(a))return n(r[4]),this.setHSL(parseFloat(r[1])/360,parseFloat(r[2])/100,parseFloat(r[3])/100,e);break;default:console.warn("THREE.Color: Unknown color model "+t)}}else if(i=/^\#([A-Fa-f\d]+)$/.exec(t)){const n=i[1],r=n.length;if(3===r)return this.setRGB(parseInt(n.charAt(0),16)/15,parseInt(n.charAt(1),16)/15,parseInt(n.charAt(2),16)/15,e);if(6===r)return this.setHex(parseInt(n,16),e);console.warn("THREE.Color: Invalid hex color "+t)}else if(t&&t.length>0)return this.setColorName(t,e);return this}setColorName(t,e=We){const n=Gr[t.toLowerCase()];return void 0!==n?this.setHex(n,e):console.warn("THREE.Color: Unknown color "+t),this}clone(){return new this.constructor(this.r,this.g,this.b)}copy(t){return this.r=t.r,this.g=t.g,this.b=t.b,this}copySRGBToLinear(t){return this.r=di(t.r),this.g=di(t.g),this.b=di(t.b),this}copyLinearToSRGB(t){return this.r=pi(t.r),this.g=pi(t.g),this.b=pi(t.b),this}convertSRGBToLinear(){return this.copySRGBToLinear(this),this}convertLinearToSRGB(){return this.copyLinearToSRGB(this),this}getHex(t=We){return ui.fromWorkingColorSpace(Yr.copy(this),t),65536*Math.round(Gn(255*Yr.r,0,255))+256*Math.round(Gn(255*Yr.g,0,255))+Math.round(Gn(255*Yr.b,0,255))}getHexString(t=We){return("000000"+this.getHex(t).toString(16)).slice(-6)}getHSL(t,e=ui.workingColorSpace){ui.fromWorkingColorSpace(Yr.copy(this),e);const n=Yr.r,i=Yr.g,r=Yr.b,s=Math.max(n,i,r),a=Math.min(n,i,r);let o,l;const c=(a+s)/2;if(a===s)o=0,l=0;else{const t=s-a;switch(l=c<=.5?t/(s+a):t/(2-s-a),s){case n:o=(i-r)/t+(i0!=t>0&&this.version++,this._alphaTest=t}onBuild(){}onBeforeRender(){}onBeforeCompile(){}customProgramCacheKey(){return this.onBeforeCompile.toString()}setValues(t){if(void 0!==t)for(const e in t){const n=t[e];if(void 0===n){console.warn(`THREE.Material: parameter '${e}' has value of undefined.`);continue}const i=this[e];void 0!==i?i&&i.isColor?i.set(n):i&&i.isVector3&&n&&n.isVector3?i.copy(n):this[e]=n:console.warn(`THREE.Material: '${e}' is not a property of THREE.${this.type}.`)}}toJSON(t){const e=void 0===t||"string"==typeof t;e&&(t={textures:{},images:{}});const n={metadata:{version:4.6,type:"Material",generator:"Material.toJSON"}};function i(t){const e=[];for(const n in t){const i=t[n];delete i.metadata,e.push(i)}return e}if(n.uuid=this.uuid,n.type=this.type,""!==this.name&&(n.name=this.name),this.color&&this.color.isColor&&(n.color=this.color.getHex()),void 0!==this.roughness&&(n.roughness=this.roughness),void 0!==this.metalness&&(n.metalness=this.metalness),void 0!==this.sheen&&(n.sheen=this.sheen),this.sheenColor&&this.sheenColor.isColor&&(n.sheenColor=this.sheenColor.getHex()),void 0!==this.sheenRoughness&&(n.sheenRoughness=this.sheenRoughness),this.emissive&&this.emissive.isColor&&(n.emissive=this.emissive.getHex()),this.emissiveIntensity&&1!==this.emissiveIntensity&&(n.emissiveIntensity=this.emissiveIntensity),this.specular&&this.specular.isColor&&(n.specular=this.specular.getHex()),void 0!==this.specularIntensity&&(n.specularIntensity=this.specularIntensity),this.specularColor&&this.specularColor.isColor&&(n.specularColor=this.specularColor.getHex()),void 0!==this.shininess&&(n.shininess=this.shininess),void 0!==this.clearcoat&&(n.clearcoat=this.clearcoat),void 0!==this.clearcoatRoughness&&(n.clearcoatRoughness=this.clearcoatRoughness),this.clearcoatMap&&this.clearcoatMap.isTexture&&(n.clearcoatMap=this.clearcoatMap.toJSON(t).uuid),this.clearcoatRoughnessMap&&this.clearcoatRoughnessMap.isTexture&&(n.clearcoatRoughnessMap=this.clearcoatRoughnessMap.toJSON(t).uuid),this.clearcoatNormalMap&&this.clearcoatNormalMap.isTexture&&(n.clearcoatNormalMap=this.clearcoatNormalMap.toJSON(t).uuid,n.clearcoatNormalScale=this.clearcoatNormalScale.toArray()),void 0!==this.iridescence&&(n.iridescence=this.iridescence),void 0!==this.iridescenceIOR&&(n.iridescenceIOR=this.iridescenceIOR),void 0!==this.iridescenceThicknessRange&&(n.iridescenceThicknessRange=this.iridescenceThicknessRange),this.iridescenceMap&&this.iridescenceMap.isTexture&&(n.iridescenceMap=this.iridescenceMap.toJSON(t).uuid),this.iridescenceThicknessMap&&this.iridescenceThicknessMap.isTexture&&(n.iridescenceThicknessMap=this.iridescenceThicknessMap.toJSON(t).uuid),void 0!==this.anisotropy&&(n.anisotropy=this.anisotropy),void 0!==this.anisotropyRotation&&(n.anisotropyRotation=this.anisotropyRotation),this.anisotropyMap&&this.anisotropyMap.isTexture&&(n.anisotropyMap=this.anisotropyMap.toJSON(t).uuid),this.map&&this.map.isTexture&&(n.map=this.map.toJSON(t).uuid),this.matcap&&this.matcap.isTexture&&(n.matcap=this.matcap.toJSON(t).uuid),this.alphaMap&&this.alphaMap.isTexture&&(n.alphaMap=this.alphaMap.toJSON(t).uuid),this.lightMap&&this.lightMap.isTexture&&(n.lightMap=this.lightMap.toJSON(t).uuid,n.lightMapIntensity=this.lightMapIntensity),this.aoMap&&this.aoMap.isTexture&&(n.aoMap=this.aoMap.toJSON(t).uuid,n.aoMapIntensity=this.aoMapIntensity),this.bumpMap&&this.bumpMap.isTexture&&(n.bumpMap=this.bumpMap.toJSON(t).uuid,n.bumpScale=this.bumpScale),this.normalMap&&this.normalMap.isTexture&&(n.normalMap=this.normalMap.toJSON(t).uuid,n.normalMapType=this.normalMapType,n.normalScale=this.normalScale.toArray()),this.displacementMap&&this.displacementMap.isTexture&&(n.displacementMap=this.displacementMap.toJSON(t).uuid,n.displacementScale=this.displacementScale,n.displacementBias=this.displacementBias),this.roughnessMap&&this.roughnessMap.isTexture&&(n.roughnessMap=this.roughnessMap.toJSON(t).uuid),this.metalnessMap&&this.metalnessMap.isTexture&&(n.metalnessMap=this.metalnessMap.toJSON(t).uuid),this.emissiveMap&&this.emissiveMap.isTexture&&(n.emissiveMap=this.emissiveMap.toJSON(t).uuid),this.specularMap&&this.specularMap.isTexture&&(n.specularMap=this.specularMap.toJSON(t).uuid),this.specularIntensityMap&&this.specularIntensityMap.isTexture&&(n.specularIntensityMap=this.specularIntensityMap.toJSON(t).uuid),this.specularColorMap&&this.specularColorMap.isTexture&&(n.specularColorMap=this.specularColorMap.toJSON(t).uuid),this.envMap&&this.envMap.isTexture&&(n.envMap=this.envMap.toJSON(t).uuid,void 0!==this.combine&&(n.combine=this.combine)),void 0!==this.envMapIntensity&&(n.envMapIntensity=this.envMapIntensity),void 0!==this.reflectivity&&(n.reflectivity=this.reflectivity),void 0!==this.refractionRatio&&(n.refractionRatio=this.refractionRatio),this.gradientMap&&this.gradientMap.isTexture&&(n.gradientMap=this.gradientMap.toJSON(t).uuid),void 0!==this.transmission&&(n.transmission=this.transmission),this.transmissionMap&&this.transmissionMap.isTexture&&(n.transmissionMap=this.transmissionMap.toJSON(t).uuid),void 0!==this.thickness&&(n.thickness=this.thickness),this.thicknessMap&&this.thicknessMap.isTexture&&(n.thicknessMap=this.thicknessMap.toJSON(t).uuid),void 0!==this.attenuationDistance&&this.attenuationDistance!==1/0&&(n.attenuationDistance=this.attenuationDistance),void 0!==this.attenuationColor&&(n.attenuationColor=this.attenuationColor.getHex()),void 0!==this.size&&(n.size=this.size),null!==this.shadowSide&&(n.shadowSide=this.shadowSide),void 0!==this.sizeAttenuation&&(n.sizeAttenuation=this.sizeAttenuation),1!==this.blending&&(n.blending=this.blending),this.side!==u&&(n.side=this.side),!0===this.vertexColors&&(n.vertexColors=!0),this.opacity<1&&(n.opacity=this.opacity),!0===this.transparent&&(n.transparent=!0),this.blendSrc!==C&&(n.blendSrc=this.blendSrc),this.blendDst!==P&&(n.blendDst=this.blendDst),this.blendEquation!==y&&(n.blendEquation=this.blendEquation),null!==this.blendSrcAlpha&&(n.blendSrcAlpha=this.blendSrcAlpha),null!==this.blendDstAlpha&&(n.blendDstAlpha=this.blendDstAlpha),null!==this.blendEquationAlpha&&(n.blendEquationAlpha=this.blendEquationAlpha),this.blendColor&&this.blendColor.isColor&&(n.blendColor=this.blendColor.getHex()),0!==this.blendAlpha&&(n.blendAlpha=this.blendAlpha),3!==this.depthFunc&&(n.depthFunc=this.depthFunc),!1===this.depthTest&&(n.depthTest=this.depthTest),!1===this.depthWrite&&(n.depthWrite=this.depthWrite),!1===this.colorWrite&&(n.colorWrite=this.colorWrite),255!==this.stencilWriteMask&&(n.stencilWriteMask=this.stencilWriteMask),519!==this.stencilFunc&&(n.stencilFunc=this.stencilFunc),0!==this.stencilRef&&(n.stencilRef=this.stencilRef),255!==this.stencilFuncMask&&(n.stencilFuncMask=this.stencilFuncMask),this.stencilFail!==Qe&&(n.stencilFail=this.stencilFail),this.stencilZFail!==Qe&&(n.stencilZFail=this.stencilZFail),this.stencilZPass!==Qe&&(n.stencilZPass=this.stencilZPass),!0===this.stencilWrite&&(n.stencilWrite=this.stencilWrite),void 0!==this.rotation&&0!==this.rotation&&(n.rotation=this.rotation),!0===this.polygonOffset&&(n.polygonOffset=!0),0!==this.polygonOffsetFactor&&(n.polygonOffsetFactor=this.polygonOffsetFactor),0!==this.polygonOffsetUnits&&(n.polygonOffsetUnits=this.polygonOffsetUnits),void 0!==this.linewidth&&1!==this.linewidth&&(n.linewidth=this.linewidth),void 0!==this.dashSize&&(n.dashSize=this.dashSize),void 0!==this.gapSize&&(n.gapSize=this.gapSize),void 0!==this.scale&&(n.scale=this.scale),!0===this.dithering&&(n.dithering=!0),this.alphaTest>0&&(n.alphaTest=this.alphaTest),!0===this.alphaHash&&(n.alphaHash=!0),!0===this.alphaToCoverage&&(n.alphaToCoverage=!0),!0===this.premultipliedAlpha&&(n.premultipliedAlpha=!0),!0===this.forceSinglePass&&(n.forceSinglePass=!0),!0===this.wireframe&&(n.wireframe=!0),this.wireframeLinewidth>1&&(n.wireframeLinewidth=this.wireframeLinewidth),"round"!==this.wireframeLinecap&&(n.wireframeLinecap=this.wireframeLinecap),"round"!==this.wireframeLinejoin&&(n.wireframeLinejoin=this.wireframeLinejoin),!0===this.flatShading&&(n.flatShading=!0),!1===this.visible&&(n.visible=!1),!1===this.toneMapped&&(n.toneMapped=!1),!1===this.fog&&(n.fog=!1),Object.keys(this.userData).length>0&&(n.userData=this.userData),e){const e=i(t.textures),r=i(t.images);e.length>0&&(n.textures=e),r.length>0&&(n.images=r)}return n}clone(){return(new this.constructor).copy(this)}copy(t){this.name=t.name,this.blending=t.blending,this.side=t.side,this.vertexColors=t.vertexColors,this.opacity=t.opacity,this.transparent=t.transparent,this.blendSrc=t.blendSrc,this.blendDst=t.blendDst,this.blendEquation=t.blendEquation,this.blendSrcAlpha=t.blendSrcAlpha,this.blendDstAlpha=t.blendDstAlpha,this.blendEquationAlpha=t.blendEquationAlpha,this.blendColor.copy(t.blendColor),this.blendAlpha=t.blendAlpha,this.depthFunc=t.depthFunc,this.depthTest=t.depthTest,this.depthWrite=t.depthWrite,this.stencilWriteMask=t.stencilWriteMask,this.stencilFunc=t.stencilFunc,this.stencilRef=t.stencilRef,this.stencilFuncMask=t.stencilFuncMask,this.stencilFail=t.stencilFail,this.stencilZFail=t.stencilZFail,this.stencilZPass=t.stencilZPass,this.stencilWrite=t.stencilWrite;const e=t.clippingPlanes;let n=null;if(null!==e){const t=e.length;n=new Array(t);for(let i=0;i!==t;++i)n[i]=e[i].clone()}return this.clippingPlanes=n,this.clipIntersection=t.clipIntersection,this.clipShadows=t.clipShadows,this.shadowSide=t.shadowSide,this.colorWrite=t.colorWrite,this.precision=t.precision,this.polygonOffset=t.polygonOffset,this.polygonOffsetFactor=t.polygonOffsetFactor,this.polygonOffsetUnits=t.polygonOffsetUnits,this.dithering=t.dithering,this.alphaTest=t.alphaTest,this.alphaHash=t.alphaHash,this.alphaToCoverage=t.alphaToCoverage,this.premultipliedAlpha=t.premultipliedAlpha,this.forceSinglePass=t.forceSinglePass,this.visible=t.visible,this.toneMapped=t.toneMapped,this.userData=JSON.parse(JSON.stringify(t.userData)),this}dispose(){this.dispatchEvent({type:"dispose"})}set needsUpdate(t){!0===t&&this.version++}}class Kr extends Jr{constructor(t){super(),this.isMeshBasicMaterial=!0,this.type="MeshBasicMaterial",this.color=new qr(16777215),this.map=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.specularMap=null,this.alphaMap=null,this.envMap=null,this.combine=Y,this.reflectivity=1,this.refractionRatio=.98,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.fog=!0,this.setValues(t)}copy(t){return super.copy(t),this.color.copy(t.color),this.map=t.map,this.lightMap=t.lightMap,this.lightMapIntensity=t.lightMapIntensity,this.aoMap=t.aoMap,this.aoMapIntensity=t.aoMapIntensity,this.specularMap=t.specularMap,this.alphaMap=t.alphaMap,this.envMap=t.envMap,this.combine=t.combine,this.reflectivity=t.reflectivity,this.refractionRatio=t.refractionRatio,this.wireframe=t.wireframe,this.wireframeLinewidth=t.wireframeLinewidth,this.wireframeLinecap=t.wireframeLinecap,this.wireframeLinejoin=t.wireframeLinejoin,this.fog=t.fog,this}}const $r=Qr();function Qr(){const t=new ArrayBuffer(4),e=new Float32Array(t),n=new Uint32Array(t),i=new Uint32Array(512),r=new Uint32Array(512);for(let t=0;t<256;++t){const e=t-127;e<-27?(i[t]=0,i[256|t]=32768,r[t]=24,r[256|t]=24):e<-14?(i[t]=1024>>-e-14,i[256|t]=1024>>-e-14|32768,r[t]=-e-1,r[256|t]=-e-1):e<=15?(i[t]=e+15<<10,i[256|t]=e+15<<10|32768,r[t]=13,r[256|t]=13):e<128?(i[t]=31744,i[256|t]=64512,r[t]=24,r[256|t]=24):(i[t]=31744,i[256|t]=64512,r[t]=13,r[256|t]=13)}const s=new Uint32Array(2048),a=new Uint32Array(64),o=new Uint32Array(64);for(let t=1;t<1024;++t){let e=t<<13,n=0;for(;0==(8388608&e);)e<<=1,n-=8388608;e&=-8388609,n+=947912704,s[t]=e|n}for(let t=1024;t<2048;++t)s[t]=939524096+(t-1024<<13);for(let t=1;t<31;++t)a[t]=t<<23;a[31]=1199570944,a[32]=2147483648;for(let t=33;t<63;++t)a[t]=2147483648+(t-32<<23);a[63]=3347054592;for(let t=1;t<64;++t)32!==t&&(o[t]=1024);return{floatView:e,uint32View:n,baseTable:i,shiftTable:r,mantissaTable:s,exponentTable:a,offsetTable:o}}function ts(t){Math.abs(t)>65504&&console.warn("THREE.DataUtils.toHalfFloat(): Value out of range."),t=Gn(t,-65504,65504),$r.floatView[0]=t;const e=$r.uint32View[0],n=e>>23&511;return $r.baseTable[n]+((8388607&e)>>$r.shiftTable[n])}function es(t){const e=t>>10;return $r.uint32View[0]=$r.mantissaTable[$r.offsetTable[e]+(1023&t)]+$r.exponentTable[e],$r.floatView[0]}const ns={toHalfFloat:ts,fromHalfFloat:es},is=new Pi,rs=new Kn;class ss{constructor(t,e,n=!1){if(Array.isArray(t))throw new TypeError("THREE.BufferAttribute: array should be a Typed Array.");this.isBufferAttribute=!0,this.name="",this.array=t,this.itemSize=e,this.count=void 0!==t?t.length/e:0,this.normalized=n,this.usage=bn,this._updateRange={offset:0,count:-1},this.updateRanges=[],this.gpuType=Lt,this.version=0}onUploadCallback(){}set needsUpdate(t){!0===t&&this.version++}get updateRange(){return ai("THREE.BufferAttribute: updateRange() is deprecated and will be removed in r169. Use addUpdateRange() instead."),this._updateRange}setUsage(t){return this.usage=t,this}addUpdateRange(t,e){this.updateRanges.push({start:t,count:e})}clearUpdateRanges(){this.updateRanges.length=0}copy(t){return this.name=t.name,this.array=new t.array.constructor(t.array),this.itemSize=t.itemSize,this.count=t.count,this.normalized=t.normalized,this.usage=t.usage,this.gpuType=t.gpuType,this}copyAt(t,e,n){t*=this.itemSize,n*=e.itemSize;for(let i=0,r=this.itemSize;i0&&(t.userData=this.userData),void 0!==this.parameters){const e=this.parameters;for(const n in e)void 0!==e[n]&&(t[n]=e[n]);return t}t.data={attributes:{}};const e=this.index;null!==e&&(t.data.index={type:e.array.constructor.name,array:Array.prototype.slice.call(e.array)});const n=this.attributes;for(const e in n){const i=n[e];t.data.attributes[e]=i.toJSON(t.data)}const i={};let r=!1;for(const e in this.morphAttributes){const n=this.morphAttributes[e],s=[];for(let e=0,i=n.length;e0&&(i[e]=s,r=!0)}r&&(t.data.morphAttributes=i,t.data.morphTargetsRelative=this.morphTargetsRelative);const s=this.groups;s.length>0&&(t.data.groups=JSON.parse(JSON.stringify(s)));const a=this.boundingSphere;return null!==a&&(t.data.boundingSphere={center:a.center.toArray(),radius:a.radius}),t}clone(){return(new this.constructor).copy(this)}copy(t){this.index=null,this.attributes={},this.morphAttributes={},this.groups=[],this.boundingBox=null,this.boundingSphere=null;const e={};this.name=t.name;const n=t.index;null!==n&&this.setIndex(n.clone(e));const i=t.attributes;for(const t in i){const n=i[t];this.setAttribute(t,n.clone(e))}const r=t.morphAttributes;for(const t in r){const n=[],i=r[t];for(let t=0,r=i.length;t0){const n=t[e[0]];if(void 0!==n){this.morphTargetInfluences=[],this.morphTargetDictionary={};for(let t=0,e=n.length;t(t.far-t.near)**2)return}Es.copy(r).invert(),Ts.copy(t.ray).applyMatrix4(Es),null!==n.boundingBox&&!1===Ts.intersectsBox(n.boundingBox)||this._computeIntersections(t,e,Ts)}}_computeIntersections(t,e,n){let i;const r=this.geometry,s=this.material,a=r.index,o=r.attributes.position,l=r.attributes.uv,c=r.attributes.uv1,h=r.attributes.normal,u=r.groups,d=r.drawRange;if(null!==a)if(Array.isArray(s))for(let r=0,o=u.length;rn.far?null:{distance:c,point:Hs.clone(),object:t}}(t,e,n,i,Rs,Cs,Ps,zs);if(h){r&&(Us.fromBufferAttribute(r,o),Ns.fromBufferAttribute(r,l),Ds.fromBufferAttribute(r,c),h.uv=kr.getInterpolation(zs,Rs,Cs,Ps,Us,Ns,Ds,new Kn)),s&&(Us.fromBufferAttribute(s,o),Ns.fromBufferAttribute(s,l),Ds.fromBufferAttribute(s,c),h.uv1=kr.getInterpolation(zs,Rs,Cs,Ps,Us,Ns,Ds,new Kn)),a&&(Os.fromBufferAttribute(a,o),Fs.fromBufferAttribute(a,l),Bs.fromBufferAttribute(a,c),h.normal=kr.getInterpolation(zs,Rs,Cs,Ps,Os,Fs,Bs,new Pi),h.normal.dot(i.direction)>0&&h.normal.multiplyScalar(-1));const t={a:o,b:l,c:c,normal:new Pi,materialIndex:0};kr.getNormal(Rs,Cs,Ps,t.normal),h.face=t}return h}class Gs extends bs{constructor(t=1,e=1,n=1,i=1,r=1,s=1){super(),this.type="BoxGeometry",this.parameters={width:t,height:e,depth:n,widthSegments:i,heightSegments:r,depthSegments:s};const a=this;i=Math.floor(i),r=Math.floor(r),s=Math.floor(s);const o=[],l=[],c=[],h=[];let u=0,d=0;function p(t,e,n,i,r,s,p,m,f,g,_){const v=s/f,x=p/g,y=s/2,M=p/2,S=m/2,b=f+1,E=g+1;let T=0,w=0;const A=new Pi;for(let s=0;s0?1:-1,c.push(A.x,A.y,A.z),h.push(o/f),h.push(1-s/g),T+=1}}for(let t=0;t0&&(e.defines=this.defines),e.vertexShader=this.vertexShader,e.fragmentShader=this.fragmentShader,e.lights=this.lights,e.clipping=this.clipping;const n={};for(const t in this.extensions)!0===this.extensions[t]&&(n[t]=!0);return Object.keys(n).length>0&&(e.extensions=n),e}}class Zs extends Lr{constructor(){super(),this.isCamera=!0,this.type="Camera",this.matrixWorldInverse=new ar,this.projectionMatrix=new ar,this.projectionMatrixInverse=new ar,this.coordinateSystem=Dn}copy(t,e){return super.copy(t,e),this.matrixWorldInverse.copy(t.matrixWorldInverse),this.projectionMatrix.copy(t.projectionMatrix),this.projectionMatrixInverse.copy(t.projectionMatrixInverse),this.coordinateSystem=t.coordinateSystem,this}getWorldDirection(t){return super.getWorldDirection(t).negate()}updateMatrixWorld(t){super.updateMatrixWorld(t),this.matrixWorldInverse.copy(this.matrixWorld).invert()}updateWorldMatrix(t,e){super.updateWorldMatrix(t,e),this.matrixWorldInverse.copy(this.matrixWorld).invert()}clone(){return(new this.constructor).copy(this)}}const Js=new Pi,Ks=new Kn,$s=new Kn;class Qs extends Zs{constructor(t=50,e=1,n=.1,i=2e3){super(),this.isPerspectiveCamera=!0,this.type="PerspectiveCamera",this.fov=t,this.zoom=1,this.near=n,this.far=i,this.focus=10,this.aspect=e,this.view=null,this.filmGauge=35,this.filmOffset=0,this.updateProjectionMatrix()}copy(t,e){return super.copy(t,e),this.fov=t.fov,this.zoom=t.zoom,this.near=t.near,this.far=t.far,this.focus=t.focus,this.aspect=t.aspect,this.view=null===t.view?null:Object.assign({},t.view),this.filmGauge=t.filmGauge,this.filmOffset=t.filmOffset,this}setFocalLength(t){const e=.5*this.getFilmHeight()/t;this.fov=2*Vn*Math.atan(e),this.updateProjectionMatrix()}getFocalLength(){const t=Math.tan(.5*Hn*this.fov);return.5*this.getFilmHeight()/t}getEffectiveFOV(){return 2*Vn*Math.atan(Math.tan(.5*Hn*this.fov)/this.zoom)}getFilmWidth(){return this.filmGauge*Math.min(this.aspect,1)}getFilmHeight(){return this.filmGauge/Math.max(this.aspect,1)}getViewBounds(t,e,n){Js.set(-1,-1,.5).applyMatrix4(this.projectionMatrixInverse),e.set(Js.x,Js.y).multiplyScalar(-t/Js.z),Js.set(1,1,.5).applyMatrix4(this.projectionMatrixInverse),n.set(Js.x,Js.y).multiplyScalar(-t/Js.z)}getViewSize(t,e){return this.getViewBounds(t,Ks,$s),e.subVectors($s,Ks)}setViewOffset(t,e,n,i,r,s){this.aspect=t/e,null===this.view&&(this.view={enabled:!0,fullWidth:1,fullHeight:1,offsetX:0,offsetY:0,width:1,height:1}),this.view.enabled=!0,this.view.fullWidth=t,this.view.fullHeight=e,this.view.offsetX=n,this.view.offsetY=i,this.view.width=r,this.view.height=s,this.updateProjectionMatrix()}clearViewOffset(){null!==this.view&&(this.view.enabled=!1),this.updateProjectionMatrix()}updateProjectionMatrix(){const t=this.near;let e=t*Math.tan(.5*Hn*this.fov)/this.zoom,n=2*e,i=this.aspect*n,r=-.5*i;const s=this.view;if(null!==this.view&&this.view.enabled){const t=s.fullWidth,a=s.fullHeight;r+=s.offsetX*i/t,e-=s.offsetY*n/a,i*=s.width/t,n*=s.height/a}const a=this.filmOffset;0!==a&&(r+=t*a/this.getFilmWidth()),this.projectionMatrix.makePerspective(r,r+i,e,e-n,t,this.far,this.coordinateSystem),this.projectionMatrixInverse.copy(this.projectionMatrix).invert()}toJSON(t){const e=super.toJSON(t);return e.object.fov=this.fov,e.object.zoom=this.zoom,e.object.near=this.near,e.object.far=this.far,e.object.focus=this.focus,e.object.aspect=this.aspect,null!==this.view&&(e.object.view=Object.assign({},this.view)),e.object.filmGauge=this.filmGauge,e.object.filmOffset=this.filmOffset,e}}const ta=-90;class ea extends Lr{constructor(t,e,n){super(),this.type="CubeCamera",this.renderTarget=n,this.coordinateSystem=null,this.activeMipmapLevel=0;const i=new Qs(ta,1,t,e);i.layers=this.layers,this.add(i);const r=new Qs(ta,1,t,e);r.layers=this.layers,this.add(r);const s=new Qs(ta,1,t,e);s.layers=this.layers,this.add(s);const a=new Qs(ta,1,t,e);a.layers=this.layers,this.add(a);const o=new Qs(ta,1,t,e);o.layers=this.layers,this.add(o);const l=new Qs(ta,1,t,e);l.layers=this.layers,this.add(l)}updateCoordinateSystem(){const t=this.coordinateSystem,e=this.children.concat(),[n,i,r,s,a,o]=e;for(const t of e)this.remove(t);if(t===Dn)n.up.set(0,1,0),n.lookAt(1,0,0),i.up.set(0,1,0),i.lookAt(-1,0,0),r.up.set(0,0,-1),r.lookAt(0,1,0),s.up.set(0,0,1),s.lookAt(0,-1,0),a.up.set(0,1,0),a.lookAt(0,0,1),o.up.set(0,1,0),o.lookAt(0,0,-1);else{if(t!==On)throw new Error("THREE.CubeCamera.updateCoordinateSystem(): Invalid coordinate system: "+t);n.up.set(0,-1,0),n.lookAt(-1,0,0),i.up.set(0,-1,0),i.lookAt(1,0,0),r.up.set(0,0,1),r.lookAt(0,1,0),s.up.set(0,0,-1),s.lookAt(0,-1,0),a.up.set(0,-1,0),a.lookAt(0,0,1),o.up.set(0,-1,0),o.lookAt(0,0,-1)}for(const t of e)this.add(t),t.updateMatrixWorld()}update(t,e){null===this.parent&&this.updateMatrixWorld();const{renderTarget:n,activeMipmapLevel:i}=this;this.coordinateSystem!==t.coordinateSystem&&(this.coordinateSystem=t.coordinateSystem,this.updateCoordinateSystem());const[r,s,a,o,l,c]=this.children,h=t.getRenderTarget(),u=t.getActiveCubeFace(),d=t.getActiveMipmapLevel(),p=t.xr.enabled;t.xr.enabled=!1;const m=n.texture.generateMipmaps;n.texture.generateMipmaps=!1,t.setRenderTarget(n,0,i),t.render(e,r),t.setRenderTarget(n,1,i),t.render(e,s),t.setRenderTarget(n,2,i),t.render(e,a),t.setRenderTarget(n,3,i),t.render(e,o),t.setRenderTarget(n,4,i),t.render(e,l),n.texture.generateMipmaps=m,t.setRenderTarget(n,5,i),t.render(e,c),t.setRenderTarget(h,u,d),t.xr.enabled=p,n.texture.needsPMREMUpdate=!0}}class na extends yi{constructor(t,e,n,i,r,s,a,o,l,c){super(t=void 0!==t?t:[],e=void 0!==e?e:ot,n,i,r,s,a,o,l,c),this.isCubeTexture=!0,this.flipY=!1}get images(){return this.image}set images(t){this.image=t}}class ia extends bi{constructor(t=1,e={}){super(t,t,e),this.isWebGLCubeRenderTarget=!0;const n={width:t,height:t,depth:1},i=[n,n,n,n,n,n];this.texture=new na(i,e.mapping,e.wrapS,e.wrapT,e.magFilter,e.minFilter,e.format,e.type,e.anisotropy,e.colorSpace),this.texture.isRenderTargetTexture=!0,this.texture.generateMipmaps=void 0!==e.generateMipmaps&&e.generateMipmaps,this.texture.minFilter=void 0!==e.minFilter?e.minFilter:yt}fromEquirectangularTexture(t,e){this.texture.type=e.type,this.texture.colorSpace=e.colorSpace,this.texture.generateMipmaps=e.generateMipmaps,this.texture.minFilter=e.minFilter,this.texture.magFilter=e.magFilter;const n={uniforms:{tEquirect:{value:null}},vertexShader:"\n\n\t\t\t\tvarying vec3 vWorldDirection;\n\n\t\t\t\tvec3 transformDirection( in vec3 dir, in mat4 matrix ) {\n\n\t\t\t\t\treturn normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );\n\n\t\t\t\t}\n\n\t\t\t\tvoid main() {\n\n\t\t\t\t\tvWorldDirection = transformDirection( position, modelMatrix );\n\n\t\t\t\t\t#include \n\t\t\t\t\t#include \n\n\t\t\t\t}\n\t\t\t",fragmentShader:"\n\n\t\t\t\tuniform sampler2D tEquirect;\n\n\t\t\t\tvarying vec3 vWorldDirection;\n\n\t\t\t\t#include \n\n\t\t\t\tvoid main() {\n\n\t\t\t\t\tvec3 direction = normalize( vWorldDirection );\n\n\t\t\t\t\tvec2 sampleUV = equirectUv( direction );\n\n\t\t\t\t\tgl_FragColor = texture2D( tEquirect, sampleUV );\n\n\t\t\t\t}\n\t\t\t"},i=new Gs(5,5,5),r=new Ys({name:"CubemapFromEquirect",uniforms:Ws(n.uniforms),vertexShader:n.vertexShader,fragmentShader:n.fragmentShader,side:d,blending:0});r.uniforms.tEquirect.value=e;const s=new Vs(i,r),a=e.minFilter;e.minFilter===bt&&(e.minFilter=yt);return new ea(1,10,this).update(t,s),e.minFilter=a,s.geometry.dispose(),s.material.dispose(),this}clear(t,e,n,i){const r=t.getRenderTarget();for(let r=0;r<6;r++)t.setRenderTarget(this,r),t.clear(e,n,i);t.setRenderTarget(r)}}const ra=new Pi,sa=new Pi,aa=new $n;class oa{constructor(t=new Pi(1,0,0),e=0){this.isPlane=!0,this.normal=t,this.constant=e}set(t,e){return this.normal.copy(t),this.constant=e,this}setComponents(t,e,n,i){return this.normal.set(t,e,n),this.constant=i,this}setFromNormalAndCoplanarPoint(t,e){return this.normal.copy(t),this.constant=-e.dot(this.normal),this}setFromCoplanarPoints(t,e,n){const i=ra.subVectors(n,e).cross(sa.subVectors(t,e)).normalize();return this.setFromNormalAndCoplanarPoint(i,t),this}copy(t){return this.normal.copy(t.normal),this.constant=t.constant,this}normalize(){const t=1/this.normal.length();return this.normal.multiplyScalar(t),this.constant*=t,this}negate(){return this.constant*=-1,this.normal.negate(),this}distanceToPoint(t){return this.normal.dot(t)+this.constant}distanceToSphere(t){return this.distanceToPoint(t.center)-t.radius}projectPoint(t,e){return e.copy(t).addScaledVector(this.normal,-this.distanceToPoint(t))}intersectLine(t,e){const n=t.delta(ra),i=this.normal.dot(n);if(0===i)return 0===this.distanceToPoint(t.start)?e.copy(t.start):null;const r=-(t.start.dot(this.normal)+this.constant)/i;return r<0||r>1?null:e.copy(t.start).addScaledVector(n,r)}intersectsLine(t){const e=this.distanceToPoint(t.start),n=this.distanceToPoint(t.end);return e<0&&n>0||n<0&&e>0}intersectsBox(t){return t.intersectsPlane(this)}intersectsSphere(t){return t.intersectsPlane(this)}coplanarPoint(t){return t.copy(this.normal).multiplyScalar(-this.constant)}applyMatrix4(t,e){const n=e||aa.getNormalMatrix(t),i=this.coplanarPoint(ra).applyMatrix4(t),r=this.normal.applyMatrix3(n).normalize();return this.constant=-i.dot(r),this}translate(t){return this.constant-=t.dot(this.normal),this}equals(t){return t.normal.equals(this.normal)&&t.constant===this.constant}clone(){return(new this.constructor).copy(this)}}const la=new Ki,ca=new Pi;class ha{constructor(t=new oa,e=new oa,n=new oa,i=new oa,r=new oa,s=new oa){this.planes=[t,e,n,i,r,s]}set(t,e,n,i,r,s){const a=this.planes;return a[0].copy(t),a[1].copy(e),a[2].copy(n),a[3].copy(i),a[4].copy(r),a[5].copy(s),this}copy(t){const e=this.planes;for(let n=0;n<6;n++)e[n].copy(t.planes[n]);return this}setFromProjectionMatrix(t,e=2e3){const n=this.planes,i=t.elements,r=i[0],s=i[1],a=i[2],o=i[3],l=i[4],c=i[5],h=i[6],u=i[7],d=i[8],p=i[9],m=i[10],f=i[11],g=i[12],_=i[13],v=i[14],x=i[15];if(n[0].setComponents(o-r,u-l,f-d,x-g).normalize(),n[1].setComponents(o+r,u+l,f+d,x+g).normalize(),n[2].setComponents(o+s,u+c,f+p,x+_).normalize(),n[3].setComponents(o-s,u-c,f-p,x-_).normalize(),n[4].setComponents(o-a,u-h,f-m,x-v).normalize(),e===Dn)n[5].setComponents(o+a,u+h,f+m,x+v).normalize();else{if(e!==On)throw new Error("THREE.Frustum.setFromProjectionMatrix(): Invalid coordinate system: "+e);n[5].setComponents(a,h,m,v).normalize()}return this}intersectsObject(t){if(void 0!==t.boundingSphere)null===t.boundingSphere&&t.computeBoundingSphere(),la.copy(t.boundingSphere).applyMatrix4(t.matrixWorld);else{const e=t.geometry;null===e.boundingSphere&&e.computeBoundingSphere(),la.copy(e.boundingSphere).applyMatrix4(t.matrixWorld)}return this.intersectsSphere(la)}intersectsSprite(t){return la.center.set(0,0,0),la.radius=.7071067811865476,la.applyMatrix4(t.matrixWorld),this.intersectsSphere(la)}intersectsSphere(t){const e=this.planes,n=t.center,i=-t.radius;for(let t=0;t<6;t++){if(e[t].distanceToPoint(n)0?t.max.x:t.min.x,ca.y=i.normal.y>0?t.max.y:t.min.y,ca.z=i.normal.z>0?t.max.z:t.min.z,i.distanceToPoint(ca)<0)return!1}return!0}containsPoint(t){const e=this.planes;for(let n=0;n<6;n++)if(e[n].distanceToPoint(t)<0)return!1;return!0}clone(){return(new this.constructor).copy(this)}}function ua(){let t=null,e=!1,n=null,i=null;function r(e,s){n(e,s),i=t.requestAnimationFrame(r)}return{start:function(){!0!==e&&null!==n&&(i=t.requestAnimationFrame(r),e=!0)},stop:function(){t.cancelAnimationFrame(i),e=!1},setAnimationLoop:function(t){n=t},setContext:function(e){t=e}}}function da(t,e){const n=e.isWebGL2,i=new WeakMap;return{get:function(t){return t.isInterleavedBufferAttribute&&(t=t.data),i.get(t)},remove:function(e){e.isInterleavedBufferAttribute&&(e=e.data);const n=i.get(e);n&&(t.deleteBuffer(n.buffer),i.delete(e))},update:function(e,r){if(e.isGLBufferAttribute){const t=i.get(e);return void((!t||t.version 0\n\tvec4 plane;\n\t#ifdef ALPHA_TO_COVERAGE\n\t\tfloat distanceToPlane, distanceGradient;\n\t\tfloat clipOpacity = 1.0;\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < UNION_CLIPPING_PLANES; i ++ ) {\n\t\t\tplane = clippingPlanes[ i ];\n\t\t\tdistanceToPlane = - dot( vClipPosition, plane.xyz ) + plane.w;\n\t\t\tdistanceGradient = fwidth( distanceToPlane ) / 2.0;\n\t\t\tclipOpacity *= smoothstep( - distanceGradient, distanceGradient, distanceToPlane );\n\t\t\tif ( clipOpacity == 0.0 ) discard;\n\t\t}\n\t\t#pragma unroll_loop_end\n\t\t#if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES\n\t\t\tfloat unionClipOpacity = 1.0;\n\t\t\t#pragma unroll_loop_start\n\t\t\tfor ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; i ++ ) {\n\t\t\t\tplane = clippingPlanes[ i ];\n\t\t\t\tdistanceToPlane = - dot( vClipPosition, plane.xyz ) + plane.w;\n\t\t\t\tdistanceGradient = fwidth( distanceToPlane ) / 2.0;\n\t\t\t\tunionClipOpacity *= 1.0 - smoothstep( - distanceGradient, distanceGradient, distanceToPlane );\n\t\t\t}\n\t\t\t#pragma unroll_loop_end\n\t\t\tclipOpacity *= 1.0 - unionClipOpacity;\n\t\t#endif\n\t\tdiffuseColor.a *= clipOpacity;\n\t\tif ( diffuseColor.a == 0.0 ) discard;\n\t#else\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < UNION_CLIPPING_PLANES; i ++ ) {\n\t\t\tplane = clippingPlanes[ i ];\n\t\t\tif ( dot( vClipPosition, plane.xyz ) > plane.w ) discard;\n\t\t}\n\t\t#pragma unroll_loop_end\n\t\t#if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES\n\t\t\tbool clipped = true;\n\t\t\t#pragma unroll_loop_start\n\t\t\tfor ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; i ++ ) {\n\t\t\t\tplane = clippingPlanes[ i ];\n\t\t\t\tclipped = ( dot( vClipPosition, plane.xyz ) > plane.w ) && clipped;\n\t\t\t}\n\t\t\t#pragma unroll_loop_end\n\t\t\tif ( clipped ) discard;\n\t\t#endif\n\t#endif\n#endif",clipping_planes_pars_fragment:"#if NUM_CLIPPING_PLANES > 0\n\tvarying vec3 vClipPosition;\n\tuniform vec4 clippingPlanes[ NUM_CLIPPING_PLANES ];\n#endif",clipping_planes_pars_vertex:"#if NUM_CLIPPING_PLANES > 0\n\tvarying vec3 vClipPosition;\n#endif",clipping_planes_vertex:"#if NUM_CLIPPING_PLANES > 0\n\tvClipPosition = - mvPosition.xyz;\n#endif",color_fragment:"#if defined( USE_COLOR_ALPHA )\n\tdiffuseColor *= vColor;\n#elif defined( USE_COLOR )\n\tdiffuseColor.rgb *= vColor;\n#endif",color_pars_fragment:"#if defined( USE_COLOR_ALPHA )\n\tvarying vec4 vColor;\n#elif defined( USE_COLOR )\n\tvarying vec3 vColor;\n#endif",color_pars_vertex:"#if defined( USE_COLOR_ALPHA )\n\tvarying vec4 vColor;\n#elif defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR )\n\tvarying vec3 vColor;\n#endif",color_vertex:"#if defined( USE_COLOR_ALPHA )\n\tvColor = vec4( 1.0 );\n#elif defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR )\n\tvColor = vec3( 1.0 );\n#endif\n#ifdef USE_COLOR\n\tvColor *= color;\n#endif\n#ifdef USE_INSTANCING_COLOR\n\tvColor.xyz *= instanceColor.xyz;\n#endif",common:"#define PI 3.141592653589793\n#define PI2 6.283185307179586\n#define PI_HALF 1.5707963267948966\n#define RECIPROCAL_PI 0.3183098861837907\n#define RECIPROCAL_PI2 0.15915494309189535\n#define EPSILON 1e-6\n#ifndef saturate\n#define saturate( a ) clamp( a, 0.0, 1.0 )\n#endif\n#define whiteComplement( a ) ( 1.0 - saturate( a ) )\nfloat pow2( const in float x ) { return x*x; }\nvec3 pow2( const in vec3 x ) { return x*x; }\nfloat pow3( const in float x ) { return x*x*x; }\nfloat pow4( const in float x ) { float x2 = x*x; return x2*x2; }\nfloat max3( const in vec3 v ) { return max( max( v.x, v.y ), v.z ); }\nfloat average( const in vec3 v ) { return dot( v, vec3( 0.3333333 ) ); }\nhighp float rand( const in vec2 uv ) {\n\tconst highp float a = 12.9898, b = 78.233, c = 43758.5453;\n\thighp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI );\n\treturn fract( sin( sn ) * c );\n}\n#ifdef HIGH_PRECISION\n\tfloat precisionSafeLength( vec3 v ) { return length( v ); }\n#else\n\tfloat precisionSafeLength( vec3 v ) {\n\t\tfloat maxComponent = max3( abs( v ) );\n\t\treturn length( v / maxComponent ) * maxComponent;\n\t}\n#endif\nstruct IncidentLight {\n\tvec3 color;\n\tvec3 direction;\n\tbool visible;\n};\nstruct ReflectedLight {\n\tvec3 directDiffuse;\n\tvec3 directSpecular;\n\tvec3 indirectDiffuse;\n\tvec3 indirectSpecular;\n};\n#ifdef USE_ALPHAHASH\n\tvarying vec3 vPosition;\n#endif\nvec3 transformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );\n}\nvec3 inverseTransformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( vec4( dir, 0.0 ) * matrix ).xyz );\n}\nmat3 transposeMat3( const in mat3 m ) {\n\tmat3 tmp;\n\ttmp[ 0 ] = vec3( m[ 0 ].x, m[ 1 ].x, m[ 2 ].x );\n\ttmp[ 1 ] = vec3( m[ 0 ].y, m[ 1 ].y, m[ 2 ].y );\n\ttmp[ 2 ] = vec3( m[ 0 ].z, m[ 1 ].z, m[ 2 ].z );\n\treturn tmp;\n}\nfloat luminance( const in vec3 rgb ) {\n\tconst vec3 weights = vec3( 0.2126729, 0.7151522, 0.0721750 );\n\treturn dot( weights, rgb );\n}\nbool isPerspectiveMatrix( mat4 m ) {\n\treturn m[ 2 ][ 3 ] == - 1.0;\n}\nvec2 equirectUv( in vec3 dir ) {\n\tfloat u = atan( dir.z, dir.x ) * RECIPROCAL_PI2 + 0.5;\n\tfloat v = asin( clamp( dir.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;\n\treturn vec2( u, v );\n}\nvec3 BRDF_Lambert( const in vec3 diffuseColor ) {\n\treturn RECIPROCAL_PI * diffuseColor;\n}\nvec3 F_Schlick( const in vec3 f0, const in float f90, const in float dotVH ) {\n\tfloat fresnel = exp2( ( - 5.55473 * dotVH - 6.98316 ) * dotVH );\n\treturn f0 * ( 1.0 - fresnel ) + ( f90 * fresnel );\n}\nfloat F_Schlick( const in float f0, const in float f90, const in float dotVH ) {\n\tfloat fresnel = exp2( ( - 5.55473 * dotVH - 6.98316 ) * dotVH );\n\treturn f0 * ( 1.0 - fresnel ) + ( f90 * fresnel );\n} // validated",cube_uv_reflection_fragment:"#ifdef ENVMAP_TYPE_CUBE_UV\n\t#define cubeUV_minMipLevel 4.0\n\t#define cubeUV_minTileSize 16.0\n\tfloat getFace( vec3 direction ) {\n\t\tvec3 absDirection = abs( direction );\n\t\tfloat face = - 1.0;\n\t\tif ( absDirection.x > absDirection.z ) {\n\t\t\tif ( absDirection.x > absDirection.y )\n\t\t\t\tface = direction.x > 0.0 ? 0.0 : 3.0;\n\t\t\telse\n\t\t\t\tface = direction.y > 0.0 ? 1.0 : 4.0;\n\t\t} else {\n\t\t\tif ( absDirection.z > absDirection.y )\n\t\t\t\tface = direction.z > 0.0 ? 2.0 : 5.0;\n\t\t\telse\n\t\t\t\tface = direction.y > 0.0 ? 1.0 : 4.0;\n\t\t}\n\t\treturn face;\n\t}\n\tvec2 getUV( vec3 direction, float face ) {\n\t\tvec2 uv;\n\t\tif ( face == 0.0 ) {\n\t\t\tuv = vec2( direction.z, direction.y ) / abs( direction.x );\n\t\t} else if ( face == 1.0 ) {\n\t\t\tuv = vec2( - direction.x, - direction.z ) / abs( direction.y );\n\t\t} else if ( face == 2.0 ) {\n\t\t\tuv = vec2( - direction.x, direction.y ) / abs( direction.z );\n\t\t} else if ( face == 3.0 ) {\n\t\t\tuv = vec2( - direction.z, direction.y ) / abs( direction.x );\n\t\t} else if ( face == 4.0 ) {\n\t\t\tuv = vec2( - direction.x, direction.z ) / abs( direction.y );\n\t\t} else {\n\t\t\tuv = vec2( direction.x, direction.y ) / abs( direction.z );\n\t\t}\n\t\treturn 0.5 * ( uv + 1.0 );\n\t}\n\tvec3 bilinearCubeUV( sampler2D envMap, vec3 direction, float mipInt ) {\n\t\tfloat face = getFace( direction );\n\t\tfloat filterInt = max( cubeUV_minMipLevel - mipInt, 0.0 );\n\t\tmipInt = max( mipInt, cubeUV_minMipLevel );\n\t\tfloat faceSize = exp2( mipInt );\n\t\thighp vec2 uv = getUV( direction, face ) * ( faceSize - 2.0 ) + 1.0;\n\t\tif ( face > 2.0 ) {\n\t\t\tuv.y += faceSize;\n\t\t\tface -= 3.0;\n\t\t}\n\t\tuv.x += face * faceSize;\n\t\tuv.x += filterInt * 3.0 * cubeUV_minTileSize;\n\t\tuv.y += 4.0 * ( exp2( CUBEUV_MAX_MIP ) - faceSize );\n\t\tuv.x *= CUBEUV_TEXEL_WIDTH;\n\t\tuv.y *= CUBEUV_TEXEL_HEIGHT;\n\t\t#ifdef texture2DGradEXT\n\t\t\treturn texture2DGradEXT( envMap, uv, vec2( 0.0 ), vec2( 0.0 ) ).rgb;\n\t\t#else\n\t\t\treturn texture2D( envMap, uv ).rgb;\n\t\t#endif\n\t}\n\t#define cubeUV_r0 1.0\n\t#define cubeUV_m0 - 2.0\n\t#define cubeUV_r1 0.8\n\t#define cubeUV_m1 - 1.0\n\t#define cubeUV_r4 0.4\n\t#define cubeUV_m4 2.0\n\t#define cubeUV_r5 0.305\n\t#define cubeUV_m5 3.0\n\t#define cubeUV_r6 0.21\n\t#define cubeUV_m6 4.0\n\tfloat roughnessToMip( float roughness ) {\n\t\tfloat mip = 0.0;\n\t\tif ( roughness >= cubeUV_r1 ) {\n\t\t\tmip = ( cubeUV_r0 - roughness ) * ( cubeUV_m1 - cubeUV_m0 ) / ( cubeUV_r0 - cubeUV_r1 ) + cubeUV_m0;\n\t\t} else if ( roughness >= cubeUV_r4 ) {\n\t\t\tmip = ( cubeUV_r1 - roughness ) * ( cubeUV_m4 - cubeUV_m1 ) / ( cubeUV_r1 - cubeUV_r4 ) + cubeUV_m1;\n\t\t} else if ( roughness >= cubeUV_r5 ) {\n\t\t\tmip = ( cubeUV_r4 - roughness ) * ( cubeUV_m5 - cubeUV_m4 ) / ( cubeUV_r4 - cubeUV_r5 ) + cubeUV_m4;\n\t\t} else if ( roughness >= cubeUV_r6 ) {\n\t\t\tmip = ( cubeUV_r5 - roughness ) * ( cubeUV_m6 - cubeUV_m5 ) / ( cubeUV_r5 - cubeUV_r6 ) + cubeUV_m5;\n\t\t} else {\n\t\t\tmip = - 2.0 * log2( 1.16 * roughness );\t\t}\n\t\treturn mip;\n\t}\n\tvec4 textureCubeUV( sampler2D envMap, vec3 sampleDir, float roughness ) {\n\t\tfloat mip = clamp( roughnessToMip( roughness ), cubeUV_m0, CUBEUV_MAX_MIP );\n\t\tfloat mipF = fract( mip );\n\t\tfloat mipInt = floor( mip );\n\t\tvec3 color0 = bilinearCubeUV( envMap, sampleDir, mipInt );\n\t\tif ( mipF == 0.0 ) {\n\t\t\treturn vec4( color0, 1.0 );\n\t\t} else {\n\t\t\tvec3 color1 = bilinearCubeUV( envMap, sampleDir, mipInt + 1.0 );\n\t\t\treturn vec4( mix( color0, color1, mipF ), 1.0 );\n\t\t}\n\t}\n#endif",defaultnormal_vertex:"vec3 transformedNormal = objectNormal;\n#ifdef USE_TANGENT\n\tvec3 transformedTangent = objectTangent;\n#endif\n#ifdef USE_BATCHING\n\tmat3 bm = mat3( batchingMatrix );\n\ttransformedNormal /= vec3( dot( bm[ 0 ], bm[ 0 ] ), dot( bm[ 1 ], bm[ 1 ] ), dot( bm[ 2 ], bm[ 2 ] ) );\n\ttransformedNormal = bm * transformedNormal;\n\t#ifdef USE_TANGENT\n\t\ttransformedTangent = bm * transformedTangent;\n\t#endif\n#endif\n#ifdef USE_INSTANCING\n\tmat3 im = mat3( instanceMatrix );\n\ttransformedNormal /= vec3( dot( im[ 0 ], im[ 0 ] ), dot( im[ 1 ], im[ 1 ] ), dot( im[ 2 ], im[ 2 ] ) );\n\ttransformedNormal = im * transformedNormal;\n\t#ifdef USE_TANGENT\n\t\ttransformedTangent = im * transformedTangent;\n\t#endif\n#endif\ntransformedNormal = normalMatrix * transformedNormal;\n#ifdef FLIP_SIDED\n\ttransformedNormal = - transformedNormal;\n#endif\n#ifdef USE_TANGENT\n\ttransformedTangent = ( modelViewMatrix * vec4( transformedTangent, 0.0 ) ).xyz;\n\t#ifdef FLIP_SIDED\n\t\ttransformedTangent = - transformedTangent;\n\t#endif\n#endif",displacementmap_pars_vertex:"#ifdef USE_DISPLACEMENTMAP\n\tuniform sampler2D displacementMap;\n\tuniform float displacementScale;\n\tuniform float displacementBias;\n#endif",displacementmap_vertex:"#ifdef USE_DISPLACEMENTMAP\n\ttransformed += normalize( objectNormal ) * ( texture2D( displacementMap, vDisplacementMapUv ).x * displacementScale + displacementBias );\n#endif",emissivemap_fragment:"#ifdef USE_EMISSIVEMAP\n\tvec4 emissiveColor = texture2D( emissiveMap, vEmissiveMapUv );\n\ttotalEmissiveRadiance *= emissiveColor.rgb;\n#endif",emissivemap_pars_fragment:"#ifdef USE_EMISSIVEMAP\n\tuniform sampler2D emissiveMap;\n#endif",colorspace_fragment:"gl_FragColor = linearToOutputTexel( gl_FragColor );",colorspace_pars_fragment:"\nconst mat3 LINEAR_SRGB_TO_LINEAR_DISPLAY_P3 = mat3(\n\tvec3( 0.8224621, 0.177538, 0.0 ),\n\tvec3( 0.0331941, 0.9668058, 0.0 ),\n\tvec3( 0.0170827, 0.0723974, 0.9105199 )\n);\nconst mat3 LINEAR_DISPLAY_P3_TO_LINEAR_SRGB = mat3(\n\tvec3( 1.2249401, - 0.2249404, 0.0 ),\n\tvec3( - 0.0420569, 1.0420571, 0.0 ),\n\tvec3( - 0.0196376, - 0.0786361, 1.0982735 )\n);\nvec4 LinearSRGBToLinearDisplayP3( in vec4 value ) {\n\treturn vec4( value.rgb * LINEAR_SRGB_TO_LINEAR_DISPLAY_P3, value.a );\n}\nvec4 LinearDisplayP3ToLinearSRGB( in vec4 value ) {\n\treturn vec4( value.rgb * LINEAR_DISPLAY_P3_TO_LINEAR_SRGB, value.a );\n}\nvec4 LinearTransferOETF( in vec4 value ) {\n\treturn value;\n}\nvec4 sRGBTransferOETF( in vec4 value ) {\n\treturn vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.a );\n}\nvec4 LinearToLinear( in vec4 value ) {\n\treturn value;\n}\nvec4 LinearTosRGB( in vec4 value ) {\n\treturn sRGBTransferOETF( value );\n}",envmap_fragment:"#ifdef USE_ENVMAP\n\t#ifdef ENV_WORLDPOS\n\t\tvec3 cameraToFrag;\n\t\tif ( isOrthographic ) {\n\t\t\tcameraToFrag = normalize( vec3( - viewMatrix[ 0 ][ 2 ], - viewMatrix[ 1 ][ 2 ], - viewMatrix[ 2 ][ 2 ] ) );\n\t\t} else {\n\t\t\tcameraToFrag = normalize( vWorldPosition - cameraPosition );\n\t\t}\n\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvec3 reflectVec = reflect( cameraToFrag, worldNormal );\n\t\t#else\n\t\t\tvec3 reflectVec = refract( cameraToFrag, worldNormal, refractionRatio );\n\t\t#endif\n\t#else\n\t\tvec3 reflectVec = vReflect;\n\t#endif\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tvec4 envColor = textureCube( envMap, vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\n\t#else\n\t\tvec4 envColor = vec4( 0.0 );\n\t#endif\n\t#ifdef ENVMAP_BLENDING_MULTIPLY\n\t\toutgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_MIX )\n\t\toutgoingLight = mix( outgoingLight, envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_ADD )\n\t\toutgoingLight += envColor.xyz * specularStrength * reflectivity;\n\t#endif\n#endif",envmap_common_pars_fragment:"#ifdef USE_ENVMAP\n\tuniform float envMapIntensity;\n\tuniform float flipEnvMap;\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tuniform samplerCube envMap;\n\t#else\n\t\tuniform sampler2D envMap;\n\t#endif\n\t\n#endif",envmap_pars_fragment:"#ifdef USE_ENVMAP\n\tuniform float reflectivity;\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) || defined( LAMBERT )\n\t\t#define ENV_WORLDPOS\n\t#endif\n\t#ifdef ENV_WORLDPOS\n\t\tvarying vec3 vWorldPosition;\n\t\tuniform float refractionRatio;\n\t#else\n\t\tvarying vec3 vReflect;\n\t#endif\n#endif",envmap_pars_vertex:"#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) || defined( LAMBERT )\n\t\t#define ENV_WORLDPOS\n\t#endif\n\t#ifdef ENV_WORLDPOS\n\t\t\n\t\tvarying vec3 vWorldPosition;\n\t#else\n\t\tvarying vec3 vReflect;\n\t\tuniform float refractionRatio;\n\t#endif\n#endif",envmap_physical_pars_fragment:"#ifdef USE_ENVMAP\n\tvec3 getIBLIrradiance( const in vec3 normal ) {\n\t\t#ifdef ENVMAP_TYPE_CUBE_UV\n\t\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, worldNormal, 1.0 );\n\t\t\treturn PI * envMapColor.rgb * envMapIntensity;\n\t\t#else\n\t\t\treturn vec3( 0.0 );\n\t\t#endif\n\t}\n\tvec3 getIBLRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness ) {\n\t\t#ifdef ENVMAP_TYPE_CUBE_UV\n\t\t\tvec3 reflectVec = reflect( - viewDir, normal );\n\t\t\treflectVec = normalize( mix( reflectVec, normal, roughness * roughness) );\n\t\t\treflectVec = inverseTransformDirection( reflectVec, viewMatrix );\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, reflectVec, roughness );\n\t\t\treturn envMapColor.rgb * envMapIntensity;\n\t\t#else\n\t\t\treturn vec3( 0.0 );\n\t\t#endif\n\t}\n\t#ifdef USE_ANISOTROPY\n\t\tvec3 getIBLAnisotropyRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness, const in vec3 bitangent, const in float anisotropy ) {\n\t\t\t#ifdef ENVMAP_TYPE_CUBE_UV\n\t\t\t\tvec3 bentNormal = cross( bitangent, viewDir );\n\t\t\t\tbentNormal = normalize( cross( bentNormal, bitangent ) );\n\t\t\t\tbentNormal = normalize( mix( bentNormal, normal, pow2( pow2( 1.0 - anisotropy * ( 1.0 - roughness ) ) ) ) );\n\t\t\t\treturn getIBLRadiance( viewDir, bentNormal, roughness );\n\t\t\t#else\n\t\t\t\treturn vec3( 0.0 );\n\t\t\t#endif\n\t\t}\n\t#endif\n#endif",envmap_vertex:"#ifdef USE_ENVMAP\n\t#ifdef ENV_WORLDPOS\n\t\tvWorldPosition = worldPosition.xyz;\n\t#else\n\t\tvec3 cameraToVertex;\n\t\tif ( isOrthographic ) {\n\t\t\tcameraToVertex = normalize( vec3( - viewMatrix[ 0 ][ 2 ], - viewMatrix[ 1 ][ 2 ], - viewMatrix[ 2 ][ 2 ] ) );\n\t\t} else {\n\t\t\tcameraToVertex = normalize( worldPosition.xyz - cameraPosition );\n\t\t}\n\t\tvec3 worldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvReflect = reflect( cameraToVertex, worldNormal );\n\t\t#else\n\t\t\tvReflect = refract( cameraToVertex, worldNormal, refractionRatio );\n\t\t#endif\n\t#endif\n#endif",fog_vertex:"#ifdef USE_FOG\n\tvFogDepth = - mvPosition.z;\n#endif",fog_pars_vertex:"#ifdef USE_FOG\n\tvarying float vFogDepth;\n#endif",fog_fragment:"#ifdef USE_FOG\n\t#ifdef FOG_EXP2\n\t\tfloat fogFactor = 1.0 - exp( - fogDensity * fogDensity * vFogDepth * vFogDepth );\n\t#else\n\t\tfloat fogFactor = smoothstep( fogNear, fogFar, vFogDepth );\n\t#endif\n\tgl_FragColor.rgb = mix( gl_FragColor.rgb, fogColor, fogFactor );\n#endif",fog_pars_fragment:"#ifdef USE_FOG\n\tuniform vec3 fogColor;\n\tvarying float vFogDepth;\n\t#ifdef FOG_EXP2\n\t\tuniform float fogDensity;\n\t#else\n\t\tuniform float fogNear;\n\t\tuniform float fogFar;\n\t#endif\n#endif",gradientmap_pars_fragment:"#ifdef USE_GRADIENTMAP\n\tuniform sampler2D gradientMap;\n#endif\nvec3 getGradientIrradiance( vec3 normal, vec3 lightDirection ) {\n\tfloat dotNL = dot( normal, lightDirection );\n\tvec2 coord = vec2( dotNL * 0.5 + 0.5, 0.0 );\n\t#ifdef USE_GRADIENTMAP\n\t\treturn vec3( texture2D( gradientMap, coord ).r );\n\t#else\n\t\tvec2 fw = fwidth( coord ) * 0.5;\n\t\treturn mix( vec3( 0.7 ), vec3( 1.0 ), smoothstep( 0.7 - fw.x, 0.7 + fw.x, coord.x ) );\n\t#endif\n}",lightmap_fragment:"#ifdef USE_LIGHTMAP\n\tvec4 lightMapTexel = texture2D( lightMap, vLightMapUv );\n\tvec3 lightMapIrradiance = lightMapTexel.rgb * lightMapIntensity;\n\treflectedLight.indirectDiffuse += lightMapIrradiance;\n#endif",lightmap_pars_fragment:"#ifdef USE_LIGHTMAP\n\tuniform sampler2D lightMap;\n\tuniform float lightMapIntensity;\n#endif",lights_lambert_fragment:"LambertMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularStrength = specularStrength;",lights_lambert_pars_fragment:"varying vec3 vViewPosition;\nstruct LambertMaterial {\n\tvec3 diffuseColor;\n\tfloat specularStrength;\n};\nvoid RE_Direct_Lambert( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in LambertMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometryNormal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Lambert( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in LambertMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_Lambert\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Lambert",lights_pars_begin:"uniform bool receiveShadow;\nuniform vec3 ambientLightColor;\n#if defined( USE_LIGHT_PROBES )\n\tuniform vec3 lightProbe[ 9 ];\n#endif\nvec3 shGetIrradianceAt( in vec3 normal, in vec3 shCoefficients[ 9 ] ) {\n\tfloat x = normal.x, y = normal.y, z = normal.z;\n\tvec3 result = shCoefficients[ 0 ] * 0.886227;\n\tresult += shCoefficients[ 1 ] * 2.0 * 0.511664 * y;\n\tresult += shCoefficients[ 2 ] * 2.0 * 0.511664 * z;\n\tresult += shCoefficients[ 3 ] * 2.0 * 0.511664 * x;\n\tresult += shCoefficients[ 4 ] * 2.0 * 0.429043 * x * y;\n\tresult += shCoefficients[ 5 ] * 2.0 * 0.429043 * y * z;\n\tresult += shCoefficients[ 6 ] * ( 0.743125 * z * z - 0.247708 );\n\tresult += shCoefficients[ 7 ] * 2.0 * 0.429043 * x * z;\n\tresult += shCoefficients[ 8 ] * 0.429043 * ( x * x - y * y );\n\treturn result;\n}\nvec3 getLightProbeIrradiance( const in vec3 lightProbe[ 9 ], const in vec3 normal ) {\n\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\tvec3 irradiance = shGetIrradianceAt( worldNormal, lightProbe );\n\treturn irradiance;\n}\nvec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) {\n\tvec3 irradiance = ambientLightColor;\n\treturn irradiance;\n}\nfloat getDistanceAttenuation( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) {\n\t#if defined ( LEGACY_LIGHTS )\n\t\tif ( cutoffDistance > 0.0 && decayExponent > 0.0 ) {\n\t\t\treturn pow( saturate( - lightDistance / cutoffDistance + 1.0 ), decayExponent );\n\t\t}\n\t\treturn 1.0;\n\t#else\n\t\tfloat distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 );\n\t\tif ( cutoffDistance > 0.0 ) {\n\t\t\tdistanceFalloff *= pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );\n\t\t}\n\t\treturn distanceFalloff;\n\t#endif\n}\nfloat getSpotAttenuation( const in float coneCosine, const in float penumbraCosine, const in float angleCosine ) {\n\treturn smoothstep( coneCosine, penumbraCosine, angleCosine );\n}\n#if NUM_DIR_LIGHTS > 0\n\tstruct DirectionalLight {\n\t\tvec3 direction;\n\t\tvec3 color;\n\t};\n\tuniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ];\n\tvoid getDirectionalLightInfo( const in DirectionalLight directionalLight, out IncidentLight light ) {\n\t\tlight.color = directionalLight.color;\n\t\tlight.direction = directionalLight.direction;\n\t\tlight.visible = true;\n\t}\n#endif\n#if NUM_POINT_LIGHTS > 0\n\tstruct PointLight {\n\t\tvec3 position;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t};\n\tuniform PointLight pointLights[ NUM_POINT_LIGHTS ];\n\tvoid getPointLightInfo( const in PointLight pointLight, const in vec3 geometryPosition, out IncidentLight light ) {\n\t\tvec3 lVector = pointLight.position - geometryPosition;\n\t\tlight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tlight.color = pointLight.color;\n\t\tlight.color *= getDistanceAttenuation( lightDistance, pointLight.distance, pointLight.decay );\n\t\tlight.visible = ( light.color != vec3( 0.0 ) );\n\t}\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\tstruct SpotLight {\n\t\tvec3 position;\n\t\tvec3 direction;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t\tfloat coneCos;\n\t\tfloat penumbraCos;\n\t};\n\tuniform SpotLight spotLights[ NUM_SPOT_LIGHTS ];\n\tvoid getSpotLightInfo( const in SpotLight spotLight, const in vec3 geometryPosition, out IncidentLight light ) {\n\t\tvec3 lVector = spotLight.position - geometryPosition;\n\t\tlight.direction = normalize( lVector );\n\t\tfloat angleCos = dot( light.direction, spotLight.direction );\n\t\tfloat spotAttenuation = getSpotAttenuation( spotLight.coneCos, spotLight.penumbraCos, angleCos );\n\t\tif ( spotAttenuation > 0.0 ) {\n\t\t\tfloat lightDistance = length( lVector );\n\t\t\tlight.color = spotLight.color * spotAttenuation;\n\t\t\tlight.color *= getDistanceAttenuation( lightDistance, spotLight.distance, spotLight.decay );\n\t\t\tlight.visible = ( light.color != vec3( 0.0 ) );\n\t\t} else {\n\t\t\tlight.color = vec3( 0.0 );\n\t\t\tlight.visible = false;\n\t\t}\n\t}\n#endif\n#if NUM_RECT_AREA_LIGHTS > 0\n\tstruct RectAreaLight {\n\t\tvec3 color;\n\t\tvec3 position;\n\t\tvec3 halfWidth;\n\t\tvec3 halfHeight;\n\t};\n\tuniform sampler2D ltc_1;\tuniform sampler2D ltc_2;\n\tuniform RectAreaLight rectAreaLights[ NUM_RECT_AREA_LIGHTS ];\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\tstruct HemisphereLight {\n\t\tvec3 direction;\n\t\tvec3 skyColor;\n\t\tvec3 groundColor;\n\t};\n\tuniform HemisphereLight hemisphereLights[ NUM_HEMI_LIGHTS ];\n\tvec3 getHemisphereLightIrradiance( const in HemisphereLight hemiLight, const in vec3 normal ) {\n\t\tfloat dotNL = dot( normal, hemiLight.direction );\n\t\tfloat hemiDiffuseWeight = 0.5 * dotNL + 0.5;\n\t\tvec3 irradiance = mix( hemiLight.groundColor, hemiLight.skyColor, hemiDiffuseWeight );\n\t\treturn irradiance;\n\t}\n#endif",lights_toon_fragment:"ToonMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;",lights_toon_pars_fragment:"varying vec3 vViewPosition;\nstruct ToonMaterial {\n\tvec3 diffuseColor;\n};\nvoid RE_Direct_Toon( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in ToonMaterial material, inout ReflectedLight reflectedLight ) {\n\tvec3 irradiance = getGradientIrradiance( geometryNormal, directLight.direction ) * directLight.color;\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Toon( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in ToonMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_Toon\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Toon",lights_phong_fragment:"BlinnPhongMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularColor = specular;\nmaterial.specularShininess = shininess;\nmaterial.specularStrength = specularStrength;",lights_phong_pars_fragment:"varying vec3 vViewPosition;\nstruct BlinnPhongMaterial {\n\tvec3 diffuseColor;\n\tvec3 specularColor;\n\tfloat specularShininess;\n\tfloat specularStrength;\n};\nvoid RE_Direct_BlinnPhong( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometryNormal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n\treflectedLight.directSpecular += irradiance * BRDF_BlinnPhong( directLight.direction, geometryViewDir, geometryNormal, material.specularColor, material.specularShininess ) * material.specularStrength;\n}\nvoid RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_BlinnPhong\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_BlinnPhong",lights_physical_fragment:"PhysicalMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb * ( 1.0 - metalnessFactor );\nvec3 dxy = max( abs( dFdx( nonPerturbedNormal ) ), abs( dFdy( nonPerturbedNormal ) ) );\nfloat geometryRoughness = max( max( dxy.x, dxy.y ), dxy.z );\nmaterial.roughness = max( roughnessFactor, 0.0525 );material.roughness += geometryRoughness;\nmaterial.roughness = min( material.roughness, 1.0 );\n#ifdef IOR\n\tmaterial.ior = ior;\n\t#ifdef USE_SPECULAR\n\t\tfloat specularIntensityFactor = specularIntensity;\n\t\tvec3 specularColorFactor = specularColor;\n\t\t#ifdef USE_SPECULAR_COLORMAP\n\t\t\tspecularColorFactor *= texture2D( specularColorMap, vSpecularColorMapUv ).rgb;\n\t\t#endif\n\t\t#ifdef USE_SPECULAR_INTENSITYMAP\n\t\t\tspecularIntensityFactor *= texture2D( specularIntensityMap, vSpecularIntensityMapUv ).a;\n\t\t#endif\n\t\tmaterial.specularF90 = mix( specularIntensityFactor, 1.0, metalnessFactor );\n\t#else\n\t\tfloat specularIntensityFactor = 1.0;\n\t\tvec3 specularColorFactor = vec3( 1.0 );\n\t\tmaterial.specularF90 = 1.0;\n\t#endif\n\tmaterial.specularColor = mix( min( pow2( ( material.ior - 1.0 ) / ( material.ior + 1.0 ) ) * specularColorFactor, vec3( 1.0 ) ) * specularIntensityFactor, diffuseColor.rgb, metalnessFactor );\n#else\n\tmaterial.specularColor = mix( vec3( 0.04 ), diffuseColor.rgb, metalnessFactor );\n\tmaterial.specularF90 = 1.0;\n#endif\n#ifdef USE_CLEARCOAT\n\tmaterial.clearcoat = clearcoat;\n\tmaterial.clearcoatRoughness = clearcoatRoughness;\n\tmaterial.clearcoatF0 = vec3( 0.04 );\n\tmaterial.clearcoatF90 = 1.0;\n\t#ifdef USE_CLEARCOATMAP\n\t\tmaterial.clearcoat *= texture2D( clearcoatMap, vClearcoatMapUv ).x;\n\t#endif\n\t#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\t\tmaterial.clearcoatRoughness *= texture2D( clearcoatRoughnessMap, vClearcoatRoughnessMapUv ).y;\n\t#endif\n\tmaterial.clearcoat = saturate( material.clearcoat );\tmaterial.clearcoatRoughness = max( material.clearcoatRoughness, 0.0525 );\n\tmaterial.clearcoatRoughness += geometryRoughness;\n\tmaterial.clearcoatRoughness = min( material.clearcoatRoughness, 1.0 );\n#endif\n#ifdef USE_IRIDESCENCE\n\tmaterial.iridescence = iridescence;\n\tmaterial.iridescenceIOR = iridescenceIOR;\n\t#ifdef USE_IRIDESCENCEMAP\n\t\tmaterial.iridescence *= texture2D( iridescenceMap, vIridescenceMapUv ).r;\n\t#endif\n\t#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\t\tmaterial.iridescenceThickness = (iridescenceThicknessMaximum - iridescenceThicknessMinimum) * texture2D( iridescenceThicknessMap, vIridescenceThicknessMapUv ).g + iridescenceThicknessMinimum;\n\t#else\n\t\tmaterial.iridescenceThickness = iridescenceThicknessMaximum;\n\t#endif\n#endif\n#ifdef USE_SHEEN\n\tmaterial.sheenColor = sheenColor;\n\t#ifdef USE_SHEEN_COLORMAP\n\t\tmaterial.sheenColor *= texture2D( sheenColorMap, vSheenColorMapUv ).rgb;\n\t#endif\n\tmaterial.sheenRoughness = clamp( sheenRoughness, 0.07, 1.0 );\n\t#ifdef USE_SHEEN_ROUGHNESSMAP\n\t\tmaterial.sheenRoughness *= texture2D( sheenRoughnessMap, vSheenRoughnessMapUv ).a;\n\t#endif\n#endif\n#ifdef USE_ANISOTROPY\n\t#ifdef USE_ANISOTROPYMAP\n\t\tmat2 anisotropyMat = mat2( anisotropyVector.x, anisotropyVector.y, - anisotropyVector.y, anisotropyVector.x );\n\t\tvec3 anisotropyPolar = texture2D( anisotropyMap, vAnisotropyMapUv ).rgb;\n\t\tvec2 anisotropyV = anisotropyMat * normalize( 2.0 * anisotropyPolar.rg - vec2( 1.0 ) ) * anisotropyPolar.b;\n\t#else\n\t\tvec2 anisotropyV = anisotropyVector;\n\t#endif\n\tmaterial.anisotropy = length( anisotropyV );\n\tif( material.anisotropy == 0.0 ) {\n\t\tanisotropyV = vec2( 1.0, 0.0 );\n\t} else {\n\t\tanisotropyV /= material.anisotropy;\n\t\tmaterial.anisotropy = saturate( material.anisotropy );\n\t}\n\tmaterial.alphaT = mix( pow2( material.roughness ), 1.0, pow2( material.anisotropy ) );\n\tmaterial.anisotropyT = tbn[ 0 ] * anisotropyV.x + tbn[ 1 ] * anisotropyV.y;\n\tmaterial.anisotropyB = tbn[ 1 ] * anisotropyV.x - tbn[ 0 ] * anisotropyV.y;\n#endif",lights_physical_pars_fragment:"struct PhysicalMaterial {\n\tvec3 diffuseColor;\n\tfloat roughness;\n\tvec3 specularColor;\n\tfloat specularF90;\n\t#ifdef USE_CLEARCOAT\n\t\tfloat clearcoat;\n\t\tfloat clearcoatRoughness;\n\t\tvec3 clearcoatF0;\n\t\tfloat clearcoatF90;\n\t#endif\n\t#ifdef USE_IRIDESCENCE\n\t\tfloat iridescence;\n\t\tfloat iridescenceIOR;\n\t\tfloat iridescenceThickness;\n\t\tvec3 iridescenceFresnel;\n\t\tvec3 iridescenceF0;\n\t#endif\n\t#ifdef USE_SHEEN\n\t\tvec3 sheenColor;\n\t\tfloat sheenRoughness;\n\t#endif\n\t#ifdef IOR\n\t\tfloat ior;\n\t#endif\n\t#ifdef USE_TRANSMISSION\n\t\tfloat transmission;\n\t\tfloat transmissionAlpha;\n\t\tfloat thickness;\n\t\tfloat attenuationDistance;\n\t\tvec3 attenuationColor;\n\t#endif\n\t#ifdef USE_ANISOTROPY\n\t\tfloat anisotropy;\n\t\tfloat alphaT;\n\t\tvec3 anisotropyT;\n\t\tvec3 anisotropyB;\n\t#endif\n};\nvec3 clearcoatSpecularDirect = vec3( 0.0 );\nvec3 clearcoatSpecularIndirect = vec3( 0.0 );\nvec3 sheenSpecularDirect = vec3( 0.0 );\nvec3 sheenSpecularIndirect = vec3(0.0 );\nvec3 Schlick_to_F0( const in vec3 f, const in float f90, const in float dotVH ) {\n float x = clamp( 1.0 - dotVH, 0.0, 1.0 );\n float x2 = x * x;\n float x5 = clamp( x * x2 * x2, 0.0, 0.9999 );\n return ( f - vec3( f90 ) * x5 ) / ( 1.0 - x5 );\n}\nfloat V_GGX_SmithCorrelated( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\tfloat gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\treturn 0.5 / max( gv + gl, EPSILON );\n}\nfloat D_GGX( const in float alpha, const in float dotNH ) {\n\tfloat a2 = pow2( alpha );\n\tfloat denom = pow2( dotNH ) * ( a2 - 1.0 ) + 1.0;\n\treturn RECIPROCAL_PI * a2 / pow2( denom );\n}\n#ifdef USE_ANISOTROPY\n\tfloat V_GGX_SmithCorrelated_Anisotropic( const in float alphaT, const in float alphaB, const in float dotTV, const in float dotBV, const in float dotTL, const in float dotBL, const in float dotNV, const in float dotNL ) {\n\t\tfloat gv = dotNL * length( vec3( alphaT * dotTV, alphaB * dotBV, dotNV ) );\n\t\tfloat gl = dotNV * length( vec3( alphaT * dotTL, alphaB * dotBL, dotNL ) );\n\t\tfloat v = 0.5 / ( gv + gl );\n\t\treturn saturate(v);\n\t}\n\tfloat D_GGX_Anisotropic( const in float alphaT, const in float alphaB, const in float dotNH, const in float dotTH, const in float dotBH ) {\n\t\tfloat a2 = alphaT * alphaB;\n\t\thighp vec3 v = vec3( alphaB * dotTH, alphaT * dotBH, a2 * dotNH );\n\t\thighp float v2 = dot( v, v );\n\t\tfloat w2 = a2 / v2;\n\t\treturn RECIPROCAL_PI * a2 * pow2 ( w2 );\n\t}\n#endif\n#ifdef USE_CLEARCOAT\n\tvec3 BRDF_GGX_Clearcoat( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in PhysicalMaterial material) {\n\t\tvec3 f0 = material.clearcoatF0;\n\t\tfloat f90 = material.clearcoatF90;\n\t\tfloat roughness = material.clearcoatRoughness;\n\t\tfloat alpha = pow2( roughness );\n\t\tvec3 halfDir = normalize( lightDir + viewDir );\n\t\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\t\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\t\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\t\tfloat dotVH = saturate( dot( viewDir, halfDir ) );\n\t\tvec3 F = F_Schlick( f0, f90, dotVH );\n\t\tfloat V = V_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\t\tfloat D = D_GGX( alpha, dotNH );\n\t\treturn F * ( V * D );\n\t}\n#endif\nvec3 BRDF_GGX( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in PhysicalMaterial material ) {\n\tvec3 f0 = material.specularColor;\n\tfloat f90 = material.specularF90;\n\tfloat roughness = material.roughness;\n\tfloat alpha = pow2( roughness );\n\tvec3 halfDir = normalize( lightDir + viewDir );\n\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat dotVH = saturate( dot( viewDir, halfDir ) );\n\tvec3 F = F_Schlick( f0, f90, dotVH );\n\t#ifdef USE_IRIDESCENCE\n\t\tF = mix( F, material.iridescenceFresnel, material.iridescence );\n\t#endif\n\t#ifdef USE_ANISOTROPY\n\t\tfloat dotTL = dot( material.anisotropyT, lightDir );\n\t\tfloat dotTV = dot( material.anisotropyT, viewDir );\n\t\tfloat dotTH = dot( material.anisotropyT, halfDir );\n\t\tfloat dotBL = dot( material.anisotropyB, lightDir );\n\t\tfloat dotBV = dot( material.anisotropyB, viewDir );\n\t\tfloat dotBH = dot( material.anisotropyB, halfDir );\n\t\tfloat V = V_GGX_SmithCorrelated_Anisotropic( material.alphaT, alpha, dotTV, dotBV, dotTL, dotBL, dotNV, dotNL );\n\t\tfloat D = D_GGX_Anisotropic( material.alphaT, alpha, dotNH, dotTH, dotBH );\n\t#else\n\t\tfloat V = V_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\t\tfloat D = D_GGX( alpha, dotNH );\n\t#endif\n\treturn F * ( V * D );\n}\nvec2 LTC_Uv( const in vec3 N, const in vec3 V, const in float roughness ) {\n\tconst float LUT_SIZE = 64.0;\n\tconst float LUT_SCALE = ( LUT_SIZE - 1.0 ) / LUT_SIZE;\n\tconst float LUT_BIAS = 0.5 / LUT_SIZE;\n\tfloat dotNV = saturate( dot( N, V ) );\n\tvec2 uv = vec2( roughness, sqrt( 1.0 - dotNV ) );\n\tuv = uv * LUT_SCALE + LUT_BIAS;\n\treturn uv;\n}\nfloat LTC_ClippedSphereFormFactor( const in vec3 f ) {\n\tfloat l = length( f );\n\treturn max( ( l * l + f.z ) / ( l + 1.0 ), 0.0 );\n}\nvec3 LTC_EdgeVectorFormFactor( const in vec3 v1, const in vec3 v2 ) {\n\tfloat x = dot( v1, v2 );\n\tfloat y = abs( x );\n\tfloat a = 0.8543985 + ( 0.4965155 + 0.0145206 * y ) * y;\n\tfloat b = 3.4175940 + ( 4.1616724 + y ) * y;\n\tfloat v = a / b;\n\tfloat theta_sintheta = ( x > 0.0 ) ? v : 0.5 * inversesqrt( max( 1.0 - x * x, 1e-7 ) ) - v;\n\treturn cross( v1, v2 ) * theta_sintheta;\n}\nvec3 LTC_Evaluate( const in vec3 N, const in vec3 V, const in vec3 P, const in mat3 mInv, const in vec3 rectCoords[ 4 ] ) {\n\tvec3 v1 = rectCoords[ 1 ] - rectCoords[ 0 ];\n\tvec3 v2 = rectCoords[ 3 ] - rectCoords[ 0 ];\n\tvec3 lightNormal = cross( v1, v2 );\n\tif( dot( lightNormal, P - rectCoords[ 0 ] ) < 0.0 ) return vec3( 0.0 );\n\tvec3 T1, T2;\n\tT1 = normalize( V - N * dot( V, N ) );\n\tT2 = - cross( N, T1 );\n\tmat3 mat = mInv * transposeMat3( mat3( T1, T2, N ) );\n\tvec3 coords[ 4 ];\n\tcoords[ 0 ] = mat * ( rectCoords[ 0 ] - P );\n\tcoords[ 1 ] = mat * ( rectCoords[ 1 ] - P );\n\tcoords[ 2 ] = mat * ( rectCoords[ 2 ] - P );\n\tcoords[ 3 ] = mat * ( rectCoords[ 3 ] - P );\n\tcoords[ 0 ] = normalize( coords[ 0 ] );\n\tcoords[ 1 ] = normalize( coords[ 1 ] );\n\tcoords[ 2 ] = normalize( coords[ 2 ] );\n\tcoords[ 3 ] = normalize( coords[ 3 ] );\n\tvec3 vectorFormFactor = vec3( 0.0 );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 0 ], coords[ 1 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 1 ], coords[ 2 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 2 ], coords[ 3 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 3 ], coords[ 0 ] );\n\tfloat result = LTC_ClippedSphereFormFactor( vectorFormFactor );\n\treturn vec3( result );\n}\n#if defined( USE_SHEEN )\nfloat D_Charlie( float roughness, float dotNH ) {\n\tfloat alpha = pow2( roughness );\n\tfloat invAlpha = 1.0 / alpha;\n\tfloat cos2h = dotNH * dotNH;\n\tfloat sin2h = max( 1.0 - cos2h, 0.0078125 );\n\treturn ( 2.0 + invAlpha ) * pow( sin2h, invAlpha * 0.5 ) / ( 2.0 * PI );\n}\nfloat V_Neubelt( float dotNV, float dotNL ) {\n\treturn saturate( 1.0 / ( 4.0 * ( dotNL + dotNV - dotNL * dotNV ) ) );\n}\nvec3 BRDF_Sheen( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, vec3 sheenColor, const in float sheenRoughness ) {\n\tvec3 halfDir = normalize( lightDir + viewDir );\n\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat D = D_Charlie( sheenRoughness, dotNH );\n\tfloat V = V_Neubelt( dotNV, dotNL );\n\treturn sheenColor * ( D * V );\n}\n#endif\nfloat IBLSheenBRDF( const in vec3 normal, const in vec3 viewDir, const in float roughness ) {\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat r2 = roughness * roughness;\n\tfloat a = roughness < 0.25 ? -339.2 * r2 + 161.4 * roughness - 25.9 : -8.48 * r2 + 14.3 * roughness - 9.95;\n\tfloat b = roughness < 0.25 ? 44.0 * r2 - 23.7 * roughness + 3.26 : 1.97 * r2 - 3.27 * roughness + 0.72;\n\tfloat DG = exp( a * dotNV + b ) + ( roughness < 0.25 ? 0.0 : 0.1 * ( roughness - 0.25 ) );\n\treturn saturate( DG * RECIPROCAL_PI );\n}\nvec2 DFGApprox( const in vec3 normal, const in vec3 viewDir, const in float roughness ) {\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tconst vec4 c0 = vec4( - 1, - 0.0275, - 0.572, 0.022 );\n\tconst vec4 c1 = vec4( 1, 0.0425, 1.04, - 0.04 );\n\tvec4 r = roughness * c0 + c1;\n\tfloat a004 = min( r.x * r.x, exp2( - 9.28 * dotNV ) ) * r.x + r.y;\n\tvec2 fab = vec2( - 1.04, 1.04 ) * a004 + r.zw;\n\treturn fab;\n}\nvec3 EnvironmentBRDF( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float roughness ) {\n\tvec2 fab = DFGApprox( normal, viewDir, roughness );\n\treturn specularColor * fab.x + specularF90 * fab.y;\n}\n#ifdef USE_IRIDESCENCE\nvoid computeMultiscatteringIridescence( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float iridescence, const in vec3 iridescenceF0, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter ) {\n#else\nvoid computeMultiscattering( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter ) {\n#endif\n\tvec2 fab = DFGApprox( normal, viewDir, roughness );\n\t#ifdef USE_IRIDESCENCE\n\t\tvec3 Fr = mix( specularColor, iridescenceF0, iridescence );\n\t#else\n\t\tvec3 Fr = specularColor;\n\t#endif\n\tvec3 FssEss = Fr * fab.x + specularF90 * fab.y;\n\tfloat Ess = fab.x + fab.y;\n\tfloat Ems = 1.0 - Ess;\n\tvec3 Favg = Fr + ( 1.0 - Fr ) * 0.047619;\tvec3 Fms = FssEss * Favg / ( 1.0 - Ems * Favg );\n\tsingleScatter += FssEss;\n\tmultiScatter += Fms * Ems;\n}\n#if NUM_RECT_AREA_LIGHTS > 0\n\tvoid RE_Direct_RectArea_Physical( const in RectAreaLight rectAreaLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\t\tvec3 normal = geometryNormal;\n\t\tvec3 viewDir = geometryViewDir;\n\t\tvec3 position = geometryPosition;\n\t\tvec3 lightPos = rectAreaLight.position;\n\t\tvec3 halfWidth = rectAreaLight.halfWidth;\n\t\tvec3 halfHeight = rectAreaLight.halfHeight;\n\t\tvec3 lightColor = rectAreaLight.color;\n\t\tfloat roughness = material.roughness;\n\t\tvec3 rectCoords[ 4 ];\n\t\trectCoords[ 0 ] = lightPos + halfWidth - halfHeight;\t\trectCoords[ 1 ] = lightPos - halfWidth - halfHeight;\n\t\trectCoords[ 2 ] = lightPos - halfWidth + halfHeight;\n\t\trectCoords[ 3 ] = lightPos + halfWidth + halfHeight;\n\t\tvec2 uv = LTC_Uv( normal, viewDir, roughness );\n\t\tvec4 t1 = texture2D( ltc_1, uv );\n\t\tvec4 t2 = texture2D( ltc_2, uv );\n\t\tmat3 mInv = mat3(\n\t\t\tvec3( t1.x, 0, t1.y ),\n\t\t\tvec3( 0, 1, 0 ),\n\t\t\tvec3( t1.z, 0, t1.w )\n\t\t);\n\t\tvec3 fresnel = ( material.specularColor * t2.x + ( vec3( 1.0 ) - material.specularColor ) * t2.y );\n\t\treflectedLight.directSpecular += lightColor * fresnel * LTC_Evaluate( normal, viewDir, position, mInv, rectCoords );\n\t\treflectedLight.directDiffuse += lightColor * material.diffuseColor * LTC_Evaluate( normal, viewDir, position, mat3( 1.0 ), rectCoords );\n\t}\n#endif\nvoid RE_Direct_Physical( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometryNormal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\t#ifdef USE_CLEARCOAT\n\t\tfloat dotNLcc = saturate( dot( geometryClearcoatNormal, directLight.direction ) );\n\t\tvec3 ccIrradiance = dotNLcc * directLight.color;\n\t\tclearcoatSpecularDirect += ccIrradiance * BRDF_GGX_Clearcoat( directLight.direction, geometryViewDir, geometryClearcoatNormal, material );\n\t#endif\n\t#ifdef USE_SHEEN\n\t\tsheenSpecularDirect += irradiance * BRDF_Sheen( directLight.direction, geometryViewDir, geometryNormal, material.sheenColor, material.sheenRoughness );\n\t#endif\n\treflectedLight.directSpecular += irradiance * BRDF_GGX( directLight.direction, geometryViewDir, geometryNormal, material );\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Physical( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 irradiance, const in vec3 clearcoatRadiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight) {\n\t#ifdef USE_CLEARCOAT\n\t\tclearcoatSpecularIndirect += clearcoatRadiance * EnvironmentBRDF( geometryClearcoatNormal, geometryViewDir, material.clearcoatF0, material.clearcoatF90, material.clearcoatRoughness );\n\t#endif\n\t#ifdef USE_SHEEN\n\t\tsheenSpecularIndirect += irradiance * material.sheenColor * IBLSheenBRDF( geometryNormal, geometryViewDir, material.sheenRoughness );\n\t#endif\n\tvec3 singleScattering = vec3( 0.0 );\n\tvec3 multiScattering = vec3( 0.0 );\n\tvec3 cosineWeightedIrradiance = irradiance * RECIPROCAL_PI;\n\t#ifdef USE_IRIDESCENCE\n\t\tcomputeMultiscatteringIridescence( geometryNormal, geometryViewDir, material.specularColor, material.specularF90, material.iridescence, material.iridescenceFresnel, material.roughness, singleScattering, multiScattering );\n\t#else\n\t\tcomputeMultiscattering( geometryNormal, geometryViewDir, material.specularColor, material.specularF90, material.roughness, singleScattering, multiScattering );\n\t#endif\n\tvec3 totalScattering = singleScattering + multiScattering;\n\tvec3 diffuse = material.diffuseColor * ( 1.0 - max( max( totalScattering.r, totalScattering.g ), totalScattering.b ) );\n\treflectedLight.indirectSpecular += radiance * singleScattering;\n\treflectedLight.indirectSpecular += multiScattering * cosineWeightedIrradiance;\n\treflectedLight.indirectDiffuse += diffuse * cosineWeightedIrradiance;\n}\n#define RE_Direct\t\t\t\tRE_Direct_Physical\n#define RE_Direct_RectArea\t\tRE_Direct_RectArea_Physical\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Physical\n#define RE_IndirectSpecular\t\tRE_IndirectSpecular_Physical\nfloat computeSpecularOcclusion( const in float dotNV, const in float ambientOcclusion, const in float roughness ) {\n\treturn saturate( pow( dotNV + ambientOcclusion, exp2( - 16.0 * roughness - 1.0 ) ) - 1.0 + ambientOcclusion );\n}",lights_fragment_begin:"\nvec3 geometryPosition = - vViewPosition;\nvec3 geometryNormal = normal;\nvec3 geometryViewDir = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( vViewPosition );\nvec3 geometryClearcoatNormal = vec3( 0.0 );\n#ifdef USE_CLEARCOAT\n\tgeometryClearcoatNormal = clearcoatNormal;\n#endif\n#ifdef USE_IRIDESCENCE\n\tfloat dotNVi = saturate( dot( normal, geometryViewDir ) );\n\tif ( material.iridescenceThickness == 0.0 ) {\n\t\tmaterial.iridescence = 0.0;\n\t} else {\n\t\tmaterial.iridescence = saturate( material.iridescence );\n\t}\n\tif ( material.iridescence > 0.0 ) {\n\t\tmaterial.iridescenceFresnel = evalIridescence( 1.0, material.iridescenceIOR, dotNVi, material.iridescenceThickness, material.specularColor );\n\t\tmaterial.iridescenceF0 = Schlick_to_F0( material.iridescenceFresnel, 1.0, dotNVi );\n\t}\n#endif\nIncidentLight directLight;\n#if ( NUM_POINT_LIGHTS > 0 ) && defined( RE_Direct )\n\tPointLight pointLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_POINT_LIGHT_SHADOWS > 0\n\tPointLightShadow pointLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tpointLight = pointLights[ i ];\n\t\tgetPointLightInfo( pointLight, geometryPosition, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_POINT_LIGHT_SHADOWS )\n\t\tpointLightShadow = pointLightShadows[ i ];\n\t\tdirectLight.color *= ( directLight.visible && receiveShadow ) ? getPointShadow( pointShadowMap[ i ], pointLightShadow.shadowMapSize, pointLightShadow.shadowBias, pointLightShadow.shadowRadius, vPointShadowCoord[ i ], pointLightShadow.shadowCameraNear, pointLightShadow.shadowCameraFar ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct )\n\tSpotLight spotLight;\n\tvec4 spotColor;\n\tvec3 spotLightCoord;\n\tbool inSpotLightMap;\n\t#if defined( USE_SHADOWMAP ) && NUM_SPOT_LIGHT_SHADOWS > 0\n\tSpotLightShadow spotLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tspotLight = spotLights[ i ];\n\t\tgetSpotLightInfo( spotLight, geometryPosition, directLight );\n\t\t#if ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS )\n\t\t#define SPOT_LIGHT_MAP_INDEX UNROLLED_LOOP_INDEX\n\t\t#elif ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\t#define SPOT_LIGHT_MAP_INDEX NUM_SPOT_LIGHT_MAPS\n\t\t#else\n\t\t#define SPOT_LIGHT_MAP_INDEX ( UNROLLED_LOOP_INDEX - NUM_SPOT_LIGHT_SHADOWS + NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS )\n\t\t#endif\n\t\t#if ( SPOT_LIGHT_MAP_INDEX < NUM_SPOT_LIGHT_MAPS )\n\t\t\tspotLightCoord = vSpotLightCoord[ i ].xyz / vSpotLightCoord[ i ].w;\n\t\t\tinSpotLightMap = all( lessThan( abs( spotLightCoord * 2. - 1. ), vec3( 1.0 ) ) );\n\t\t\tspotColor = texture2D( spotLightMap[ SPOT_LIGHT_MAP_INDEX ], spotLightCoord.xy );\n\t\t\tdirectLight.color = inSpotLightMap ? directLight.color * spotColor.rgb : directLight.color;\n\t\t#endif\n\t\t#undef SPOT_LIGHT_MAP_INDEX\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\tspotLightShadow = spotLightShadows[ i ];\n\t\tdirectLight.color *= ( directLight.visible && receiveShadow ) ? getShadow( spotShadowMap[ i ], spotLightShadow.shadowMapSize, spotLightShadow.shadowBias, spotLightShadow.shadowRadius, vSpotLightCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_DIR_LIGHTS > 0 ) && defined( RE_Direct )\n\tDirectionalLight directionalLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_DIR_LIGHT_SHADOWS > 0\n\tDirectionalLightShadow directionalLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tdirectionalLight = directionalLights[ i ];\n\t\tgetDirectionalLightInfo( directionalLight, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_DIR_LIGHT_SHADOWS )\n\t\tdirectionalLightShadow = directionalLightShadows[ i ];\n\t\tdirectLight.color *= ( directLight.visible && receiveShadow ) ? getShadow( directionalShadowMap[ i ], directionalLightShadow.shadowMapSize, directionalLightShadow.shadowBias, directionalLightShadow.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_RECT_AREA_LIGHTS > 0 ) && defined( RE_Direct_RectArea )\n\tRectAreaLight rectAreaLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_RECT_AREA_LIGHTS; i ++ ) {\n\t\trectAreaLight = rectAreaLights[ i ];\n\t\tRE_Direct_RectArea( rectAreaLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if defined( RE_IndirectDiffuse )\n\tvec3 iblIrradiance = vec3( 0.0 );\n\tvec3 irradiance = getAmbientLightIrradiance( ambientLightColor );\n\t#if defined( USE_LIGHT_PROBES )\n\t\tirradiance += getLightProbeIrradiance( lightProbe, geometryNormal );\n\t#endif\n\t#if ( NUM_HEMI_LIGHTS > 0 )\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\t\tirradiance += getHemisphereLightIrradiance( hemisphereLights[ i ], geometryNormal );\n\t\t}\n\t\t#pragma unroll_loop_end\n\t#endif\n#endif\n#if defined( RE_IndirectSpecular )\n\tvec3 radiance = vec3( 0.0 );\n\tvec3 clearcoatRadiance = vec3( 0.0 );\n#endif",lights_fragment_maps:"#if defined( RE_IndirectDiffuse )\n\t#ifdef USE_LIGHTMAP\n\t\tvec4 lightMapTexel = texture2D( lightMap, vLightMapUv );\n\t\tvec3 lightMapIrradiance = lightMapTexel.rgb * lightMapIntensity;\n\t\tirradiance += lightMapIrradiance;\n\t#endif\n\t#if defined( USE_ENVMAP ) && defined( STANDARD ) && defined( ENVMAP_TYPE_CUBE_UV )\n\t\tiblIrradiance += getIBLIrradiance( geometryNormal );\n\t#endif\n#endif\n#if defined( USE_ENVMAP ) && defined( RE_IndirectSpecular )\n\t#ifdef USE_ANISOTROPY\n\t\tradiance += getIBLAnisotropyRadiance( geometryViewDir, geometryNormal, material.roughness, material.anisotropyB, material.anisotropy );\n\t#else\n\t\tradiance += getIBLRadiance( geometryViewDir, geometryNormal, material.roughness );\n\t#endif\n\t#ifdef USE_CLEARCOAT\n\t\tclearcoatRadiance += getIBLRadiance( geometryViewDir, geometryClearcoatNormal, material.clearcoatRoughness );\n\t#endif\n#endif",lights_fragment_end:"#if defined( RE_IndirectDiffuse )\n\tRE_IndirectDiffuse( irradiance, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n#endif\n#if defined( RE_IndirectSpecular )\n\tRE_IndirectSpecular( radiance, iblIrradiance, clearcoatRadiance, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n#endif",logdepthbuf_fragment:"#if defined( USE_LOGDEPTHBUF ) && defined( USE_LOGDEPTHBUF_EXT )\n\tgl_FragDepthEXT = vIsPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;\n#endif",logdepthbuf_pars_fragment:"#if defined( USE_LOGDEPTHBUF ) && defined( USE_LOGDEPTHBUF_EXT )\n\tuniform float logDepthBufFC;\n\tvarying float vFragDepth;\n\tvarying float vIsPerspective;\n#endif",logdepthbuf_pars_vertex:"#ifdef USE_LOGDEPTHBUF\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvarying float vFragDepth;\n\t\tvarying float vIsPerspective;\n\t#else\n\t\tuniform float logDepthBufFC;\n\t#endif\n#endif",logdepthbuf_vertex:"#ifdef USE_LOGDEPTHBUF\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvFragDepth = 1.0 + gl_Position.w;\n\t\tvIsPerspective = float( isPerspectiveMatrix( projectionMatrix ) );\n\t#else\n\t\tif ( isPerspectiveMatrix( projectionMatrix ) ) {\n\t\t\tgl_Position.z = log2( max( EPSILON, gl_Position.w + 1.0 ) ) * logDepthBufFC - 1.0;\n\t\t\tgl_Position.z *= gl_Position.w;\n\t\t}\n\t#endif\n#endif",map_fragment:"#ifdef USE_MAP\n\tvec4 sampledDiffuseColor = texture2D( map, vMapUv );\n\t#ifdef DECODE_VIDEO_TEXTURE\n\t\tsampledDiffuseColor = vec4( mix( pow( sampledDiffuseColor.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), sampledDiffuseColor.rgb * 0.0773993808, vec3( lessThanEqual( sampledDiffuseColor.rgb, vec3( 0.04045 ) ) ) ), sampledDiffuseColor.w );\n\t\n\t#endif\n\tdiffuseColor *= sampledDiffuseColor;\n#endif",map_pars_fragment:"#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif",map_particle_fragment:"#if defined( USE_MAP ) || defined( USE_ALPHAMAP )\n\t#if defined( USE_POINTS_UV )\n\t\tvec2 uv = vUv;\n\t#else\n\t\tvec2 uv = ( uvTransform * vec3( gl_PointCoord.x, 1.0 - gl_PointCoord.y, 1 ) ).xy;\n\t#endif\n#endif\n#ifdef USE_MAP\n\tdiffuseColor *= texture2D( map, uv );\n#endif\n#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, uv ).g;\n#endif",map_particle_pars_fragment:"#if defined( USE_POINTS_UV )\n\tvarying vec2 vUv;\n#else\n\t#if defined( USE_MAP ) || defined( USE_ALPHAMAP )\n\t\tuniform mat3 uvTransform;\n\t#endif\n#endif\n#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif\n#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif",metalnessmap_fragment:"float metalnessFactor = metalness;\n#ifdef USE_METALNESSMAP\n\tvec4 texelMetalness = texture2D( metalnessMap, vMetalnessMapUv );\n\tmetalnessFactor *= texelMetalness.b;\n#endif",metalnessmap_pars_fragment:"#ifdef USE_METALNESSMAP\n\tuniform sampler2D metalnessMap;\n#endif",morphcolor_vertex:"#if defined( USE_MORPHCOLORS ) && defined( MORPHTARGETS_TEXTURE )\n\tvColor *= morphTargetBaseInfluence;\n\tfor ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) {\n\t\t#if defined( USE_COLOR_ALPHA )\n\t\t\tif ( morphTargetInfluences[ i ] != 0.0 ) vColor += getMorph( gl_VertexID, i, 2 ) * morphTargetInfluences[ i ];\n\t\t#elif defined( USE_COLOR )\n\t\t\tif ( morphTargetInfluences[ i ] != 0.0 ) vColor += getMorph( gl_VertexID, i, 2 ).rgb * morphTargetInfluences[ i ];\n\t\t#endif\n\t}\n#endif",morphnormal_vertex:"#ifdef USE_MORPHNORMALS\n\tobjectNormal *= morphTargetBaseInfluence;\n\t#ifdef MORPHTARGETS_TEXTURE\n\t\tfor ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) {\n\t\t\tif ( morphTargetInfluences[ i ] != 0.0 ) objectNormal += getMorph( gl_VertexID, i, 1 ).xyz * morphTargetInfluences[ i ];\n\t\t}\n\t#else\n\t\tobjectNormal += morphNormal0 * morphTargetInfluences[ 0 ];\n\t\tobjectNormal += morphNormal1 * morphTargetInfluences[ 1 ];\n\t\tobjectNormal += morphNormal2 * morphTargetInfluences[ 2 ];\n\t\tobjectNormal += morphNormal3 * morphTargetInfluences[ 3 ];\n\t#endif\n#endif",morphtarget_pars_vertex:"#ifdef USE_MORPHTARGETS\n\tuniform float morphTargetBaseInfluence;\n\t#ifdef MORPHTARGETS_TEXTURE\n\t\tuniform float morphTargetInfluences[ MORPHTARGETS_COUNT ];\n\t\tuniform sampler2DArray morphTargetsTexture;\n\t\tuniform ivec2 morphTargetsTextureSize;\n\t\tvec4 getMorph( const in int vertexIndex, const in int morphTargetIndex, const in int offset ) {\n\t\t\tint texelIndex = vertexIndex * MORPHTARGETS_TEXTURE_STRIDE + offset;\n\t\t\tint y = texelIndex / morphTargetsTextureSize.x;\n\t\t\tint x = texelIndex - y * morphTargetsTextureSize.x;\n\t\t\tivec3 morphUV = ivec3( x, y, morphTargetIndex );\n\t\t\treturn texelFetch( morphTargetsTexture, morphUV, 0 );\n\t\t}\n\t#else\n\t\t#ifndef USE_MORPHNORMALS\n\t\t\tuniform float morphTargetInfluences[ 8 ];\n\t\t#else\n\t\t\tuniform float morphTargetInfluences[ 4 ];\n\t\t#endif\n\t#endif\n#endif",morphtarget_vertex:"#ifdef USE_MORPHTARGETS\n\ttransformed *= morphTargetBaseInfluence;\n\t#ifdef MORPHTARGETS_TEXTURE\n\t\tfor ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) {\n\t\t\tif ( morphTargetInfluences[ i ] != 0.0 ) transformed += getMorph( gl_VertexID, i, 0 ).xyz * morphTargetInfluences[ i ];\n\t\t}\n\t#else\n\t\ttransformed += morphTarget0 * morphTargetInfluences[ 0 ];\n\t\ttransformed += morphTarget1 * morphTargetInfluences[ 1 ];\n\t\ttransformed += morphTarget2 * morphTargetInfluences[ 2 ];\n\t\ttransformed += morphTarget3 * morphTargetInfluences[ 3 ];\n\t\t#ifndef USE_MORPHNORMALS\n\t\t\ttransformed += morphTarget4 * morphTargetInfluences[ 4 ];\n\t\t\ttransformed += morphTarget5 * morphTargetInfluences[ 5 ];\n\t\t\ttransformed += morphTarget6 * morphTargetInfluences[ 6 ];\n\t\t\ttransformed += morphTarget7 * morphTargetInfluences[ 7 ];\n\t\t#endif\n\t#endif\n#endif",normal_fragment_begin:"float faceDirection = gl_FrontFacing ? 1.0 : - 1.0;\n#ifdef FLAT_SHADED\n\tvec3 fdx = dFdx( vViewPosition );\n\tvec3 fdy = dFdy( vViewPosition );\n\tvec3 normal = normalize( cross( fdx, fdy ) );\n#else\n\tvec3 normal = normalize( vNormal );\n\t#ifdef DOUBLE_SIDED\n\t\tnormal *= faceDirection;\n\t#endif\n#endif\n#if defined( USE_NORMALMAP_TANGENTSPACE ) || defined( USE_CLEARCOAT_NORMALMAP ) || defined( USE_ANISOTROPY )\n\t#ifdef USE_TANGENT\n\t\tmat3 tbn = mat3( normalize( vTangent ), normalize( vBitangent ), normal );\n\t#else\n\t\tmat3 tbn = getTangentFrame( - vViewPosition, normal,\n\t\t#if defined( USE_NORMALMAP )\n\t\t\tvNormalMapUv\n\t\t#elif defined( USE_CLEARCOAT_NORMALMAP )\n\t\t\tvClearcoatNormalMapUv\n\t\t#else\n\t\t\tvUv\n\t\t#endif\n\t\t);\n\t#endif\n\t#if defined( DOUBLE_SIDED ) && ! defined( FLAT_SHADED )\n\t\ttbn[0] *= faceDirection;\n\t\ttbn[1] *= faceDirection;\n\t#endif\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\t#ifdef USE_TANGENT\n\t\tmat3 tbn2 = mat3( normalize( vTangent ), normalize( vBitangent ), normal );\n\t#else\n\t\tmat3 tbn2 = getTangentFrame( - vViewPosition, normal, vClearcoatNormalMapUv );\n\t#endif\n\t#if defined( DOUBLE_SIDED ) && ! defined( FLAT_SHADED )\n\t\ttbn2[0] *= faceDirection;\n\t\ttbn2[1] *= faceDirection;\n\t#endif\n#endif\nvec3 nonPerturbedNormal = normal;",normal_fragment_maps:"#ifdef USE_NORMALMAP_OBJECTSPACE\n\tnormal = texture2D( normalMap, vNormalMapUv ).xyz * 2.0 - 1.0;\n\t#ifdef FLIP_SIDED\n\t\tnormal = - normal;\n\t#endif\n\t#ifdef DOUBLE_SIDED\n\t\tnormal = normal * faceDirection;\n\t#endif\n\tnormal = normalize( normalMatrix * normal );\n#elif defined( USE_NORMALMAP_TANGENTSPACE )\n\tvec3 mapN = texture2D( normalMap, vNormalMapUv ).xyz * 2.0 - 1.0;\n\tmapN.xy *= normalScale;\n\tnormal = normalize( tbn * mapN );\n#elif defined( USE_BUMPMAP )\n\tnormal = perturbNormalArb( - vViewPosition, normal, dHdxy_fwd(), faceDirection );\n#endif",normal_pars_fragment:"#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n\t#ifdef USE_TANGENT\n\t\tvarying vec3 vTangent;\n\t\tvarying vec3 vBitangent;\n\t#endif\n#endif",normal_pars_vertex:"#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n\t#ifdef USE_TANGENT\n\t\tvarying vec3 vTangent;\n\t\tvarying vec3 vBitangent;\n\t#endif\n#endif",normal_vertex:"#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n\t#ifdef USE_TANGENT\n\t\tvTangent = normalize( transformedTangent );\n\t\tvBitangent = normalize( cross( vNormal, vTangent ) * tangent.w );\n\t#endif\n#endif",normalmap_pars_fragment:"#ifdef USE_NORMALMAP\n\tuniform sampler2D normalMap;\n\tuniform vec2 normalScale;\n#endif\n#ifdef USE_NORMALMAP_OBJECTSPACE\n\tuniform mat3 normalMatrix;\n#endif\n#if ! defined ( USE_TANGENT ) && ( defined ( USE_NORMALMAP_TANGENTSPACE ) || defined ( USE_CLEARCOAT_NORMALMAP ) || defined( USE_ANISOTROPY ) )\n\tmat3 getTangentFrame( vec3 eye_pos, vec3 surf_norm, vec2 uv ) {\n\t\tvec3 q0 = dFdx( eye_pos.xyz );\n\t\tvec3 q1 = dFdy( eye_pos.xyz );\n\t\tvec2 st0 = dFdx( uv.st );\n\t\tvec2 st1 = dFdy( uv.st );\n\t\tvec3 N = surf_norm;\n\t\tvec3 q1perp = cross( q1, N );\n\t\tvec3 q0perp = cross( N, q0 );\n\t\tvec3 T = q1perp * st0.x + q0perp * st1.x;\n\t\tvec3 B = q1perp * st0.y + q0perp * st1.y;\n\t\tfloat det = max( dot( T, T ), dot( B, B ) );\n\t\tfloat scale = ( det == 0.0 ) ? 0.0 : inversesqrt( det );\n\t\treturn mat3( T * scale, B * scale, N );\n\t}\n#endif",clearcoat_normal_fragment_begin:"#ifdef USE_CLEARCOAT\n\tvec3 clearcoatNormal = nonPerturbedNormal;\n#endif",clearcoat_normal_fragment_maps:"#ifdef USE_CLEARCOAT_NORMALMAP\n\tvec3 clearcoatMapN = texture2D( clearcoatNormalMap, vClearcoatNormalMapUv ).xyz * 2.0 - 1.0;\n\tclearcoatMapN.xy *= clearcoatNormalScale;\n\tclearcoatNormal = normalize( tbn2 * clearcoatMapN );\n#endif",clearcoat_pars_fragment:"#ifdef USE_CLEARCOATMAP\n\tuniform sampler2D clearcoatMap;\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\tuniform sampler2D clearcoatNormalMap;\n\tuniform vec2 clearcoatNormalScale;\n#endif\n#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\tuniform sampler2D clearcoatRoughnessMap;\n#endif",iridescence_pars_fragment:"#ifdef USE_IRIDESCENCEMAP\n\tuniform sampler2D iridescenceMap;\n#endif\n#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\tuniform sampler2D iridescenceThicknessMap;\n#endif",opaque_fragment:"#ifdef OPAQUE\ndiffuseColor.a = 1.0;\n#endif\n#ifdef USE_TRANSMISSION\ndiffuseColor.a *= material.transmissionAlpha;\n#endif\ngl_FragColor = vec4( outgoingLight, diffuseColor.a );",packing:"vec3 packNormalToRGB( const in vec3 normal ) {\n\treturn normalize( normal ) * 0.5 + 0.5;\n}\nvec3 unpackRGBToNormal( const in vec3 rgb ) {\n\treturn 2.0 * rgb.xyz - 1.0;\n}\nconst float PackUpscale = 256. / 255.;const float UnpackDownscale = 255. / 256.;\nconst vec3 PackFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );\nconst vec4 UnpackFactors = UnpackDownscale / vec4( PackFactors, 1. );\nconst float ShiftRight8 = 1. / 256.;\nvec4 packDepthToRGBA( const in float v ) {\n\tvec4 r = vec4( fract( v * PackFactors ), v );\n\tr.yzw -= r.xyz * ShiftRight8;\treturn r * PackUpscale;\n}\nfloat unpackRGBAToDepth( const in vec4 v ) {\n\treturn dot( v, UnpackFactors );\n}\nvec2 packDepthToRG( in highp float v ) {\n\treturn packDepthToRGBA( v ).yx;\n}\nfloat unpackRGToDepth( const in highp vec2 v ) {\n\treturn unpackRGBAToDepth( vec4( v.xy, 0.0, 0.0 ) );\n}\nvec4 pack2HalfToRGBA( vec2 v ) {\n\tvec4 r = vec4( v.x, fract( v.x * 255.0 ), v.y, fract( v.y * 255.0 ) );\n\treturn vec4( r.x - r.y / 255.0, r.y, r.z - r.w / 255.0, r.w );\n}\nvec2 unpackRGBATo2Half( vec4 v ) {\n\treturn vec2( v.x + ( v.y / 255.0 ), v.z + ( v.w / 255.0 ) );\n}\nfloat viewZToOrthographicDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn ( viewZ + near ) / ( near - far );\n}\nfloat orthographicDepthToViewZ( const in float depth, const in float near, const in float far ) {\n\treturn depth * ( near - far ) - near;\n}\nfloat viewZToPerspectiveDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn ( ( near + viewZ ) * far ) / ( ( far - near ) * viewZ );\n}\nfloat perspectiveDepthToViewZ( const in float depth, const in float near, const in float far ) {\n\treturn ( near * far ) / ( ( far - near ) * depth - far );\n}",premultiplied_alpha_fragment:"#ifdef PREMULTIPLIED_ALPHA\n\tgl_FragColor.rgb *= gl_FragColor.a;\n#endif",project_vertex:"vec4 mvPosition = vec4( transformed, 1.0 );\n#ifdef USE_BATCHING\n\tmvPosition = batchingMatrix * mvPosition;\n#endif\n#ifdef USE_INSTANCING\n\tmvPosition = instanceMatrix * mvPosition;\n#endif\nmvPosition = modelViewMatrix * mvPosition;\ngl_Position = projectionMatrix * mvPosition;",dithering_fragment:"#ifdef DITHERING\n\tgl_FragColor.rgb = dithering( gl_FragColor.rgb );\n#endif",dithering_pars_fragment:"#ifdef DITHERING\n\tvec3 dithering( vec3 color ) {\n\t\tfloat grid_position = rand( gl_FragCoord.xy );\n\t\tvec3 dither_shift_RGB = vec3( 0.25 / 255.0, -0.25 / 255.0, 0.25 / 255.0 );\n\t\tdither_shift_RGB = mix( 2.0 * dither_shift_RGB, -2.0 * dither_shift_RGB, grid_position );\n\t\treturn color + dither_shift_RGB;\n\t}\n#endif",roughnessmap_fragment:"float roughnessFactor = roughness;\n#ifdef USE_ROUGHNESSMAP\n\tvec4 texelRoughness = texture2D( roughnessMap, vRoughnessMapUv );\n\troughnessFactor *= texelRoughness.g;\n#endif",roughnessmap_pars_fragment:"#ifdef USE_ROUGHNESSMAP\n\tuniform sampler2D roughnessMap;\n#endif",shadowmap_pars_fragment:"#if NUM_SPOT_LIGHT_COORDS > 0\n\tvarying vec4 vSpotLightCoord[ NUM_SPOT_LIGHT_COORDS ];\n#endif\n#if NUM_SPOT_LIGHT_MAPS > 0\n\tuniform sampler2D spotLightMap[ NUM_SPOT_LIGHT_MAPS ];\n#endif\n#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D directionalShadowMap[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tstruct DirectionalLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D spotShadowMap[ NUM_SPOT_LIGHT_SHADOWS ];\n\t\tstruct SpotLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D pointShadowMap[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tstruct PointLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t\tfloat shadowCameraNear;\n\t\t\tfloat shadowCameraFar;\n\t\t};\n\t\tuniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ];\n\t#endif\n\tfloat texture2DCompare( sampler2D depths, vec2 uv, float compare ) {\n\t\treturn step( compare, unpackRGBAToDepth( texture2D( depths, uv ) ) );\n\t}\n\tvec2 texture2DDistribution( sampler2D shadow, vec2 uv ) {\n\t\treturn unpackRGBATo2Half( texture2D( shadow, uv ) );\n\t}\n\tfloat VSMShadow (sampler2D shadow, vec2 uv, float compare ){\n\t\tfloat occlusion = 1.0;\n\t\tvec2 distribution = texture2DDistribution( shadow, uv );\n\t\tfloat hard_shadow = step( compare , distribution.x );\n\t\tif (hard_shadow != 1.0 ) {\n\t\t\tfloat distance = compare - distribution.x ;\n\t\t\tfloat variance = max( 0.00000, distribution.y * distribution.y );\n\t\t\tfloat softness_probability = variance / (variance + distance * distance );\t\t\tsoftness_probability = clamp( ( softness_probability - 0.3 ) / ( 0.95 - 0.3 ), 0.0, 1.0 );\t\t\tocclusion = clamp( max( hard_shadow, softness_probability ), 0.0, 1.0 );\n\t\t}\n\t\treturn occlusion;\n\t}\n\tfloat getShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord ) {\n\t\tfloat shadow = 1.0;\n\t\tshadowCoord.xyz /= shadowCoord.w;\n\t\tshadowCoord.z += shadowBias;\n\t\tbool inFrustum = shadowCoord.x >= 0.0 && shadowCoord.x <= 1.0 && shadowCoord.y >= 0.0 && shadowCoord.y <= 1.0;\n\t\tbool frustumTest = inFrustum && shadowCoord.z <= 1.0;\n\t\tif ( frustumTest ) {\n\t\t#if defined( SHADOWMAP_TYPE_PCF )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx0 = - texelSize.x * shadowRadius;\n\t\t\tfloat dy0 = - texelSize.y * shadowRadius;\n\t\t\tfloat dx1 = + texelSize.x * shadowRadius;\n\t\t\tfloat dy1 = + texelSize.y * shadowRadius;\n\t\t\tfloat dx2 = dx0 / 2.0;\n\t\t\tfloat dy2 = dy0 / 2.0;\n\t\t\tfloat dx3 = dx1 / 2.0;\n\t\t\tfloat dy3 = dy1 / 2.0;\n\t\t\tshadow = (\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )\n\t\t\t) * ( 1.0 / 17.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_PCF_SOFT )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx = texelSize.x;\n\t\t\tfloat dy = texelSize.y;\n\t\t\tvec2 uv = shadowCoord.xy;\n\t\t\tvec2 f = fract( uv * shadowMapSize + 0.5 );\n\t\t\tuv -= f * texelSize;\n\t\t\tshadow = (\n\t\t\t\ttexture2DCompare( shadowMap, uv, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + vec2( dx, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + vec2( 0.0, dy ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + texelSize, shadowCoord.z ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( -dx, 0.0 ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 0.0 ), shadowCoord.z ),\n\t\t\t\t\t f.x ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( -dx, dy ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, dy ), shadowCoord.z ),\n\t\t\t\t\t f.x ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( 0.0, -dy ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 0.0, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t f.y ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( dx, -dy ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t f.y ) +\n\t\t\t\tmix( mix( texture2DCompare( shadowMap, uv + vec2( -dx, -dy ), shadowCoord.z ),\n\t\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, -dy ), shadowCoord.z ),\n\t\t\t\t\t\t f.x ),\n\t\t\t\t\t mix( texture2DCompare( shadowMap, uv + vec2( -dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t\t f.x ),\n\t\t\t\t\t f.y )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_VSM )\n\t\t\tshadow = VSMShadow( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#else\n\t\t\tshadow = texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#endif\n\t\t}\n\t\treturn shadow;\n\t}\n\tvec2 cubeToUV( vec3 v, float texelSizeY ) {\n\t\tvec3 absV = abs( v );\n\t\tfloat scaleToCube = 1.0 / max( absV.x, max( absV.y, absV.z ) );\n\t\tabsV *= scaleToCube;\n\t\tv *= scaleToCube * ( 1.0 - 2.0 * texelSizeY );\n\t\tvec2 planar = v.xy;\n\t\tfloat almostATexel = 1.5 * texelSizeY;\n\t\tfloat almostOne = 1.0 - almostATexel;\n\t\tif ( absV.z >= almostOne ) {\n\t\t\tif ( v.z > 0.0 )\n\t\t\t\tplanar.x = 4.0 - v.x;\n\t\t} else if ( absV.x >= almostOne ) {\n\t\t\tfloat signX = sign( v.x );\n\t\t\tplanar.x = v.z * signX + 2.0 * signX;\n\t\t} else if ( absV.y >= almostOne ) {\n\t\t\tfloat signY = sign( v.y );\n\t\t\tplanar.x = v.x + 2.0 * signY + 2.0;\n\t\t\tplanar.y = v.z * signY - 2.0;\n\t\t}\n\t\treturn vec2( 0.125, 0.25 ) * planar + vec2( 0.375, 0.75 );\n\t}\n\tfloat getPointShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord, float shadowCameraNear, float shadowCameraFar ) {\n\t\tvec2 texelSize = vec2( 1.0 ) / ( shadowMapSize * vec2( 4.0, 2.0 ) );\n\t\tvec3 lightToPosition = shadowCoord.xyz;\n\t\tfloat dp = ( length( lightToPosition ) - shadowCameraNear ) / ( shadowCameraFar - shadowCameraNear );\t\tdp += shadowBias;\n\t\tvec3 bd3D = normalize( lightToPosition );\n\t\t#if defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_PCF_SOFT ) || defined( SHADOWMAP_TYPE_VSM )\n\t\t\tvec2 offset = vec2( - 1, 1 ) * shadowRadius * texelSize.y;\n\t\t\treturn (\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxx, texelSize.y ), dp )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#else\n\t\t\treturn texture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp );\n\t\t#endif\n\t}\n#endif",shadowmap_pars_vertex:"#if NUM_SPOT_LIGHT_COORDS > 0\n\tuniform mat4 spotLightMatrix[ NUM_SPOT_LIGHT_COORDS ];\n\tvarying vec4 vSpotLightCoord[ NUM_SPOT_LIGHT_COORDS ];\n#endif\n#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\tuniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tstruct DirectionalLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t\tstruct SpotLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\tuniform mat4 pointShadowMatrix[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tstruct PointLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t\tfloat shadowCameraNear;\n\t\t\tfloat shadowCameraFar;\n\t\t};\n\t\tuniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ];\n\t#endif\n#endif",shadowmap_vertex:"#if ( defined( USE_SHADOWMAP ) && ( NUM_DIR_LIGHT_SHADOWS > 0 || NUM_POINT_LIGHT_SHADOWS > 0 ) ) || ( NUM_SPOT_LIGHT_COORDS > 0 )\n\tvec3 shadowWorldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\n\tvec4 shadowWorldPosition;\n#endif\n#if defined( USE_SHADOWMAP )\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {\n\t\t\tshadowWorldPosition = worldPosition + vec4( shadowWorldNormal * directionalLightShadows[ i ].shadowNormalBias, 0 );\n\t\t\tvDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * shadowWorldPosition;\n\t\t}\n\t\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {\n\t\t\tshadowWorldPosition = worldPosition + vec4( shadowWorldNormal * pointLightShadows[ i ].shadowNormalBias, 0 );\n\t\t\tvPointShadowCoord[ i ] = pointShadowMatrix[ i ] * shadowWorldPosition;\n\t\t}\n\t\t#pragma unroll_loop_end\n\t#endif\n#endif\n#if NUM_SPOT_LIGHT_COORDS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHT_COORDS; i ++ ) {\n\t\tshadowWorldPosition = worldPosition;\n\t\t#if ( defined( USE_SHADOWMAP ) && UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\t\tshadowWorldPosition.xyz += shadowWorldNormal * spotLightShadows[ i ].shadowNormalBias;\n\t\t#endif\n\t\tvSpotLightCoord[ i ] = spotLightMatrix[ i ] * shadowWorldPosition;\n\t}\n\t#pragma unroll_loop_end\n#endif",shadowmask_pars_fragment:"float getShadowMask() {\n\tfloat shadow = 1.0;\n\t#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\tDirectionalLightShadow directionalLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {\n\t\tdirectionalLight = directionalLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\tSpotLightShadow spotLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHT_SHADOWS; i ++ ) {\n\t\tspotLight = spotLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotLightCoord[ i ] ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\tPointLightShadow pointLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {\n\t\tpointLight = pointLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ], pointLight.shadowCameraNear, pointLight.shadowCameraFar ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#endif\n\treturn shadow;\n}",skinbase_vertex:"#ifdef USE_SKINNING\n\tmat4 boneMatX = getBoneMatrix( skinIndex.x );\n\tmat4 boneMatY = getBoneMatrix( skinIndex.y );\n\tmat4 boneMatZ = getBoneMatrix( skinIndex.z );\n\tmat4 boneMatW = getBoneMatrix( skinIndex.w );\n#endif",skinning_pars_vertex:"#ifdef USE_SKINNING\n\tuniform mat4 bindMatrix;\n\tuniform mat4 bindMatrixInverse;\n\tuniform highp sampler2D boneTexture;\n\tmat4 getBoneMatrix( const in float i ) {\n\t\tint size = textureSize( boneTexture, 0 ).x;\n\t\tint j = int( i ) * 4;\n\t\tint x = j % size;\n\t\tint y = j / size;\n\t\tvec4 v1 = texelFetch( boneTexture, ivec2( x, y ), 0 );\n\t\tvec4 v2 = texelFetch( boneTexture, ivec2( x + 1, y ), 0 );\n\t\tvec4 v3 = texelFetch( boneTexture, ivec2( x + 2, y ), 0 );\n\t\tvec4 v4 = texelFetch( boneTexture, ivec2( x + 3, y ), 0 );\n\t\treturn mat4( v1, v2, v3, v4 );\n\t}\n#endif",skinning_vertex:"#ifdef USE_SKINNING\n\tvec4 skinVertex = bindMatrix * vec4( transformed, 1.0 );\n\tvec4 skinned = vec4( 0.0 );\n\tskinned += boneMatX * skinVertex * skinWeight.x;\n\tskinned += boneMatY * skinVertex * skinWeight.y;\n\tskinned += boneMatZ * skinVertex * skinWeight.z;\n\tskinned += boneMatW * skinVertex * skinWeight.w;\n\ttransformed = ( bindMatrixInverse * skinned ).xyz;\n#endif",skinnormal_vertex:"#ifdef USE_SKINNING\n\tmat4 skinMatrix = mat4( 0.0 );\n\tskinMatrix += skinWeight.x * boneMatX;\n\tskinMatrix += skinWeight.y * boneMatY;\n\tskinMatrix += skinWeight.z * boneMatZ;\n\tskinMatrix += skinWeight.w * boneMatW;\n\tskinMatrix = bindMatrixInverse * skinMatrix * bindMatrix;\n\tobjectNormal = vec4( skinMatrix * vec4( objectNormal, 0.0 ) ).xyz;\n\t#ifdef USE_TANGENT\n\t\tobjectTangent = vec4( skinMatrix * vec4( objectTangent, 0.0 ) ).xyz;\n\t#endif\n#endif",specularmap_fragment:"float specularStrength;\n#ifdef USE_SPECULARMAP\n\tvec4 texelSpecular = texture2D( specularMap, vSpecularMapUv );\n\tspecularStrength = texelSpecular.r;\n#else\n\tspecularStrength = 1.0;\n#endif",specularmap_pars_fragment:"#ifdef USE_SPECULARMAP\n\tuniform sampler2D specularMap;\n#endif",tonemapping_fragment:"#if defined( TONE_MAPPING )\n\tgl_FragColor.rgb = toneMapping( gl_FragColor.rgb );\n#endif",tonemapping_pars_fragment:"#ifndef saturate\n#define saturate( a ) clamp( a, 0.0, 1.0 )\n#endif\nuniform float toneMappingExposure;\nvec3 LinearToneMapping( vec3 color ) {\n\treturn saturate( toneMappingExposure * color );\n}\nvec3 ReinhardToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\treturn saturate( color / ( vec3( 1.0 ) + color ) );\n}\nvec3 OptimizedCineonToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\tcolor = max( vec3( 0.0 ), color - 0.004 );\n\treturn pow( ( color * ( 6.2 * color + 0.5 ) ) / ( color * ( 6.2 * color + 1.7 ) + 0.06 ), vec3( 2.2 ) );\n}\nvec3 RRTAndODTFit( vec3 v ) {\n\tvec3 a = v * ( v + 0.0245786 ) - 0.000090537;\n\tvec3 b = v * ( 0.983729 * v + 0.4329510 ) + 0.238081;\n\treturn a / b;\n}\nvec3 ACESFilmicToneMapping( vec3 color ) {\n\tconst mat3 ACESInputMat = mat3(\n\t\tvec3( 0.59719, 0.07600, 0.02840 ),\t\tvec3( 0.35458, 0.90834, 0.13383 ),\n\t\tvec3( 0.04823, 0.01566, 0.83777 )\n\t);\n\tconst mat3 ACESOutputMat = mat3(\n\t\tvec3( 1.60475, -0.10208, -0.00327 ),\t\tvec3( -0.53108, 1.10813, -0.07276 ),\n\t\tvec3( -0.07367, -0.00605, 1.07602 )\n\t);\n\tcolor *= toneMappingExposure / 0.6;\n\tcolor = ACESInputMat * color;\n\tcolor = RRTAndODTFit( color );\n\tcolor = ACESOutputMat * color;\n\treturn saturate( color );\n}\nconst mat3 LINEAR_REC2020_TO_LINEAR_SRGB = mat3(\n\tvec3( 1.6605, - 0.1246, - 0.0182 ),\n\tvec3( - 0.5876, 1.1329, - 0.1006 ),\n\tvec3( - 0.0728, - 0.0083, 1.1187 )\n);\nconst mat3 LINEAR_SRGB_TO_LINEAR_REC2020 = mat3(\n\tvec3( 0.6274, 0.0691, 0.0164 ),\n\tvec3( 0.3293, 0.9195, 0.0880 ),\n\tvec3( 0.0433, 0.0113, 0.8956 )\n);\nvec3 agxDefaultContrastApprox( vec3 x ) {\n\tvec3 x2 = x * x;\n\tvec3 x4 = x2 * x2;\n\treturn + 15.5 * x4 * x2\n\t\t- 40.14 * x4 * x\n\t\t+ 31.96 * x4\n\t\t- 6.868 * x2 * x\n\t\t+ 0.4298 * x2\n\t\t+ 0.1191 * x\n\t\t- 0.00232;\n}\nvec3 AgXToneMapping( vec3 color ) {\n\tconst mat3 AgXInsetMatrix = mat3(\n\t\tvec3( 0.856627153315983, 0.137318972929847, 0.11189821299995 ),\n\t\tvec3( 0.0951212405381588, 0.761241990602591, 0.0767994186031903 ),\n\t\tvec3( 0.0482516061458583, 0.101439036467562, 0.811302368396859 )\n\t);\n\tconst mat3 AgXOutsetMatrix = mat3(\n\t\tvec3( 1.1271005818144368, - 0.1413297634984383, - 0.14132976349843826 ),\n\t\tvec3( - 0.11060664309660323, 1.157823702216272, - 0.11060664309660294 ),\n\t\tvec3( - 0.016493938717834573, - 0.016493938717834257, 1.2519364065950405 )\n\t);\n\tconst float AgxMinEv = - 12.47393;\tconst float AgxMaxEv = 4.026069;\n\tcolor *= toneMappingExposure;\n\tcolor = LINEAR_SRGB_TO_LINEAR_REC2020 * color;\n\tcolor = AgXInsetMatrix * color;\n\tcolor = max( color, 1e-10 );\tcolor = log2( color );\n\tcolor = ( color - AgxMinEv ) / ( AgxMaxEv - AgxMinEv );\n\tcolor = clamp( color, 0.0, 1.0 );\n\tcolor = agxDefaultContrastApprox( color );\n\tcolor = AgXOutsetMatrix * color;\n\tcolor = pow( max( vec3( 0.0 ), color ), vec3( 2.2 ) );\n\tcolor = LINEAR_REC2020_TO_LINEAR_SRGB * color;\n\tcolor = clamp( color, 0.0, 1.0 );\n\treturn color;\n}\nvec3 CustomToneMapping( vec3 color ) { return color; }",transmission_fragment:"#ifdef USE_TRANSMISSION\n\tmaterial.transmission = transmission;\n\tmaterial.transmissionAlpha = 1.0;\n\tmaterial.thickness = thickness;\n\tmaterial.attenuationDistance = attenuationDistance;\n\tmaterial.attenuationColor = attenuationColor;\n\t#ifdef USE_TRANSMISSIONMAP\n\t\tmaterial.transmission *= texture2D( transmissionMap, vTransmissionMapUv ).r;\n\t#endif\n\t#ifdef USE_THICKNESSMAP\n\t\tmaterial.thickness *= texture2D( thicknessMap, vThicknessMapUv ).g;\n\t#endif\n\tvec3 pos = vWorldPosition;\n\tvec3 v = normalize( cameraPosition - pos );\n\tvec3 n = inverseTransformDirection( normal, viewMatrix );\n\tvec4 transmitted = getIBLVolumeRefraction(\n\t\tn, v, material.roughness, material.diffuseColor, material.specularColor, material.specularF90,\n\t\tpos, modelMatrix, viewMatrix, projectionMatrix, material.ior, material.thickness,\n\t\tmaterial.attenuationColor, material.attenuationDistance );\n\tmaterial.transmissionAlpha = mix( material.transmissionAlpha, transmitted.a, material.transmission );\n\ttotalDiffuse = mix( totalDiffuse, transmitted.rgb, material.transmission );\n#endif",transmission_pars_fragment:"#ifdef USE_TRANSMISSION\n\tuniform float transmission;\n\tuniform float thickness;\n\tuniform float attenuationDistance;\n\tuniform vec3 attenuationColor;\n\t#ifdef USE_TRANSMISSIONMAP\n\t\tuniform sampler2D transmissionMap;\n\t#endif\n\t#ifdef USE_THICKNESSMAP\n\t\tuniform sampler2D thicknessMap;\n\t#endif\n\tuniform vec2 transmissionSamplerSize;\n\tuniform sampler2D transmissionSamplerMap;\n\tuniform mat4 modelMatrix;\n\tuniform mat4 projectionMatrix;\n\tvarying vec3 vWorldPosition;\n\tfloat w0( float a ) {\n\t\treturn ( 1.0 / 6.0 ) * ( a * ( a * ( - a + 3.0 ) - 3.0 ) + 1.0 );\n\t}\n\tfloat w1( float a ) {\n\t\treturn ( 1.0 / 6.0 ) * ( a * a * ( 3.0 * a - 6.0 ) + 4.0 );\n\t}\n\tfloat w2( float a ){\n\t\treturn ( 1.0 / 6.0 ) * ( a * ( a * ( - 3.0 * a + 3.0 ) + 3.0 ) + 1.0 );\n\t}\n\tfloat w3( float a ) {\n\t\treturn ( 1.0 / 6.0 ) * ( a * a * a );\n\t}\n\tfloat g0( float a ) {\n\t\treturn w0( a ) + w1( a );\n\t}\n\tfloat g1( float a ) {\n\t\treturn w2( a ) + w3( a );\n\t}\n\tfloat h0( float a ) {\n\t\treturn - 1.0 + w1( a ) / ( w0( a ) + w1( a ) );\n\t}\n\tfloat h1( float a ) {\n\t\treturn 1.0 + w3( a ) / ( w2( a ) + w3( a ) );\n\t}\n\tvec4 bicubic( sampler2D tex, vec2 uv, vec4 texelSize, float lod ) {\n\t\tuv = uv * texelSize.zw + 0.5;\n\t\tvec2 iuv = floor( uv );\n\t\tvec2 fuv = fract( uv );\n\t\tfloat g0x = g0( fuv.x );\n\t\tfloat g1x = g1( fuv.x );\n\t\tfloat h0x = h0( fuv.x );\n\t\tfloat h1x = h1( fuv.x );\n\t\tfloat h0y = h0( fuv.y );\n\t\tfloat h1y = h1( fuv.y );\n\t\tvec2 p0 = ( vec2( iuv.x + h0x, iuv.y + h0y ) - 0.5 ) * texelSize.xy;\n\t\tvec2 p1 = ( vec2( iuv.x + h1x, iuv.y + h0y ) - 0.5 ) * texelSize.xy;\n\t\tvec2 p2 = ( vec2( iuv.x + h0x, iuv.y + h1y ) - 0.5 ) * texelSize.xy;\n\t\tvec2 p3 = ( vec2( iuv.x + h1x, iuv.y + h1y ) - 0.5 ) * texelSize.xy;\n\t\treturn g0( fuv.y ) * ( g0x * textureLod( tex, p0, lod ) + g1x * textureLod( tex, p1, lod ) ) +\n\t\t\tg1( fuv.y ) * ( g0x * textureLod( tex, p2, lod ) + g1x * textureLod( tex, p3, lod ) );\n\t}\n\tvec4 textureBicubic( sampler2D sampler, vec2 uv, float lod ) {\n\t\tvec2 fLodSize = vec2( textureSize( sampler, int( lod ) ) );\n\t\tvec2 cLodSize = vec2( textureSize( sampler, int( lod + 1.0 ) ) );\n\t\tvec2 fLodSizeInv = 1.0 / fLodSize;\n\t\tvec2 cLodSizeInv = 1.0 / cLodSize;\n\t\tvec4 fSample = bicubic( sampler, uv, vec4( fLodSizeInv, fLodSize ), floor( lod ) );\n\t\tvec4 cSample = bicubic( sampler, uv, vec4( cLodSizeInv, cLodSize ), ceil( lod ) );\n\t\treturn mix( fSample, cSample, fract( lod ) );\n\t}\n\tvec3 getVolumeTransmissionRay( const in vec3 n, const in vec3 v, const in float thickness, const in float ior, const in mat4 modelMatrix ) {\n\t\tvec3 refractionVector = refract( - v, normalize( n ), 1.0 / ior );\n\t\tvec3 modelScale;\n\t\tmodelScale.x = length( vec3( modelMatrix[ 0 ].xyz ) );\n\t\tmodelScale.y = length( vec3( modelMatrix[ 1 ].xyz ) );\n\t\tmodelScale.z = length( vec3( modelMatrix[ 2 ].xyz ) );\n\t\treturn normalize( refractionVector ) * thickness * modelScale;\n\t}\n\tfloat applyIorToRoughness( const in float roughness, const in float ior ) {\n\t\treturn roughness * clamp( ior * 2.0 - 2.0, 0.0, 1.0 );\n\t}\n\tvec4 getTransmissionSample( const in vec2 fragCoord, const in float roughness, const in float ior ) {\n\t\tfloat lod = log2( transmissionSamplerSize.x ) * applyIorToRoughness( roughness, ior );\n\t\treturn textureBicubic( transmissionSamplerMap, fragCoord.xy, lod );\n\t}\n\tvec3 volumeAttenuation( const in float transmissionDistance, const in vec3 attenuationColor, const in float attenuationDistance ) {\n\t\tif ( isinf( attenuationDistance ) ) {\n\t\t\treturn vec3( 1.0 );\n\t\t} else {\n\t\t\tvec3 attenuationCoefficient = -log( attenuationColor ) / attenuationDistance;\n\t\t\tvec3 transmittance = exp( - attenuationCoefficient * transmissionDistance );\t\t\treturn transmittance;\n\t\t}\n\t}\n\tvec4 getIBLVolumeRefraction( const in vec3 n, const in vec3 v, const in float roughness, const in vec3 diffuseColor,\n\t\tconst in vec3 specularColor, const in float specularF90, const in vec3 position, const in mat4 modelMatrix,\n\t\tconst in mat4 viewMatrix, const in mat4 projMatrix, const in float ior, const in float thickness,\n\t\tconst in vec3 attenuationColor, const in float attenuationDistance ) {\n\t\tvec3 transmissionRay = getVolumeTransmissionRay( n, v, thickness, ior, modelMatrix );\n\t\tvec3 refractedRayExit = position + transmissionRay;\n\t\tvec4 ndcPos = projMatrix * viewMatrix * vec4( refractedRayExit, 1.0 );\n\t\tvec2 refractionCoords = ndcPos.xy / ndcPos.w;\n\t\trefractionCoords += 1.0;\n\t\trefractionCoords /= 2.0;\n\t\tvec4 transmittedLight = getTransmissionSample( refractionCoords, roughness, ior );\n\t\tvec3 transmittance = diffuseColor * volumeAttenuation( length( transmissionRay ), attenuationColor, attenuationDistance );\n\t\tvec3 attenuatedColor = transmittance * transmittedLight.rgb;\n\t\tvec3 F = EnvironmentBRDF( n, v, specularColor, specularF90, roughness );\n\t\tfloat transmittanceFactor = ( transmittance.r + transmittance.g + transmittance.b ) / 3.0;\n\t\treturn vec4( ( 1.0 - F ) * attenuatedColor, 1.0 - ( 1.0 - transmittedLight.a ) * transmittanceFactor );\n\t}\n#endif",uv_pars_fragment:"#if defined( USE_UV ) || defined( USE_ANISOTROPY )\n\tvarying vec2 vUv;\n#endif\n#ifdef USE_MAP\n\tvarying vec2 vMapUv;\n#endif\n#ifdef USE_ALPHAMAP\n\tvarying vec2 vAlphaMapUv;\n#endif\n#ifdef USE_LIGHTMAP\n\tvarying vec2 vLightMapUv;\n#endif\n#ifdef USE_AOMAP\n\tvarying vec2 vAoMapUv;\n#endif\n#ifdef USE_BUMPMAP\n\tvarying vec2 vBumpMapUv;\n#endif\n#ifdef USE_NORMALMAP\n\tvarying vec2 vNormalMapUv;\n#endif\n#ifdef USE_EMISSIVEMAP\n\tvarying vec2 vEmissiveMapUv;\n#endif\n#ifdef USE_METALNESSMAP\n\tvarying vec2 vMetalnessMapUv;\n#endif\n#ifdef USE_ROUGHNESSMAP\n\tvarying vec2 vRoughnessMapUv;\n#endif\n#ifdef USE_ANISOTROPYMAP\n\tvarying vec2 vAnisotropyMapUv;\n#endif\n#ifdef USE_CLEARCOATMAP\n\tvarying vec2 vClearcoatMapUv;\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\tvarying vec2 vClearcoatNormalMapUv;\n#endif\n#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\tvarying vec2 vClearcoatRoughnessMapUv;\n#endif\n#ifdef USE_IRIDESCENCEMAP\n\tvarying vec2 vIridescenceMapUv;\n#endif\n#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\tvarying vec2 vIridescenceThicknessMapUv;\n#endif\n#ifdef USE_SHEEN_COLORMAP\n\tvarying vec2 vSheenColorMapUv;\n#endif\n#ifdef USE_SHEEN_ROUGHNESSMAP\n\tvarying vec2 vSheenRoughnessMapUv;\n#endif\n#ifdef USE_SPECULARMAP\n\tvarying vec2 vSpecularMapUv;\n#endif\n#ifdef USE_SPECULAR_COLORMAP\n\tvarying vec2 vSpecularColorMapUv;\n#endif\n#ifdef USE_SPECULAR_INTENSITYMAP\n\tvarying vec2 vSpecularIntensityMapUv;\n#endif\n#ifdef USE_TRANSMISSIONMAP\n\tuniform mat3 transmissionMapTransform;\n\tvarying vec2 vTransmissionMapUv;\n#endif\n#ifdef USE_THICKNESSMAP\n\tuniform mat3 thicknessMapTransform;\n\tvarying vec2 vThicknessMapUv;\n#endif",uv_pars_vertex:"#if defined( USE_UV ) || defined( USE_ANISOTROPY )\n\tvarying vec2 vUv;\n#endif\n#ifdef USE_MAP\n\tuniform mat3 mapTransform;\n\tvarying vec2 vMapUv;\n#endif\n#ifdef USE_ALPHAMAP\n\tuniform mat3 alphaMapTransform;\n\tvarying vec2 vAlphaMapUv;\n#endif\n#ifdef USE_LIGHTMAP\n\tuniform mat3 lightMapTransform;\n\tvarying vec2 vLightMapUv;\n#endif\n#ifdef USE_AOMAP\n\tuniform mat3 aoMapTransform;\n\tvarying vec2 vAoMapUv;\n#endif\n#ifdef USE_BUMPMAP\n\tuniform mat3 bumpMapTransform;\n\tvarying vec2 vBumpMapUv;\n#endif\n#ifdef USE_NORMALMAP\n\tuniform mat3 normalMapTransform;\n\tvarying vec2 vNormalMapUv;\n#endif\n#ifdef USE_DISPLACEMENTMAP\n\tuniform mat3 displacementMapTransform;\n\tvarying vec2 vDisplacementMapUv;\n#endif\n#ifdef USE_EMISSIVEMAP\n\tuniform mat3 emissiveMapTransform;\n\tvarying vec2 vEmissiveMapUv;\n#endif\n#ifdef USE_METALNESSMAP\n\tuniform mat3 metalnessMapTransform;\n\tvarying vec2 vMetalnessMapUv;\n#endif\n#ifdef USE_ROUGHNESSMAP\n\tuniform mat3 roughnessMapTransform;\n\tvarying vec2 vRoughnessMapUv;\n#endif\n#ifdef USE_ANISOTROPYMAP\n\tuniform mat3 anisotropyMapTransform;\n\tvarying vec2 vAnisotropyMapUv;\n#endif\n#ifdef USE_CLEARCOATMAP\n\tuniform mat3 clearcoatMapTransform;\n\tvarying vec2 vClearcoatMapUv;\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\tuniform mat3 clearcoatNormalMapTransform;\n\tvarying vec2 vClearcoatNormalMapUv;\n#endif\n#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\tuniform mat3 clearcoatRoughnessMapTransform;\n\tvarying vec2 vClearcoatRoughnessMapUv;\n#endif\n#ifdef USE_SHEEN_COLORMAP\n\tuniform mat3 sheenColorMapTransform;\n\tvarying vec2 vSheenColorMapUv;\n#endif\n#ifdef USE_SHEEN_ROUGHNESSMAP\n\tuniform mat3 sheenRoughnessMapTransform;\n\tvarying vec2 vSheenRoughnessMapUv;\n#endif\n#ifdef USE_IRIDESCENCEMAP\n\tuniform mat3 iridescenceMapTransform;\n\tvarying vec2 vIridescenceMapUv;\n#endif\n#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\tuniform mat3 iridescenceThicknessMapTransform;\n\tvarying vec2 vIridescenceThicknessMapUv;\n#endif\n#ifdef USE_SPECULARMAP\n\tuniform mat3 specularMapTransform;\n\tvarying vec2 vSpecularMapUv;\n#endif\n#ifdef USE_SPECULAR_COLORMAP\n\tuniform mat3 specularColorMapTransform;\n\tvarying vec2 vSpecularColorMapUv;\n#endif\n#ifdef USE_SPECULAR_INTENSITYMAP\n\tuniform mat3 specularIntensityMapTransform;\n\tvarying vec2 vSpecularIntensityMapUv;\n#endif\n#ifdef USE_TRANSMISSIONMAP\n\tuniform mat3 transmissionMapTransform;\n\tvarying vec2 vTransmissionMapUv;\n#endif\n#ifdef USE_THICKNESSMAP\n\tuniform mat3 thicknessMapTransform;\n\tvarying vec2 vThicknessMapUv;\n#endif",uv_vertex:"#if defined( USE_UV ) || defined( USE_ANISOTROPY )\n\tvUv = vec3( uv, 1 ).xy;\n#endif\n#ifdef USE_MAP\n\tvMapUv = ( mapTransform * vec3( MAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_ALPHAMAP\n\tvAlphaMapUv = ( alphaMapTransform * vec3( ALPHAMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_LIGHTMAP\n\tvLightMapUv = ( lightMapTransform * vec3( LIGHTMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_AOMAP\n\tvAoMapUv = ( aoMapTransform * vec3( AOMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_BUMPMAP\n\tvBumpMapUv = ( bumpMapTransform * vec3( BUMPMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_NORMALMAP\n\tvNormalMapUv = ( normalMapTransform * vec3( NORMALMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_DISPLACEMENTMAP\n\tvDisplacementMapUv = ( displacementMapTransform * vec3( DISPLACEMENTMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_EMISSIVEMAP\n\tvEmissiveMapUv = ( emissiveMapTransform * vec3( EMISSIVEMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_METALNESSMAP\n\tvMetalnessMapUv = ( metalnessMapTransform * vec3( METALNESSMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_ROUGHNESSMAP\n\tvRoughnessMapUv = ( roughnessMapTransform * vec3( ROUGHNESSMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_ANISOTROPYMAP\n\tvAnisotropyMapUv = ( anisotropyMapTransform * vec3( ANISOTROPYMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_CLEARCOATMAP\n\tvClearcoatMapUv = ( clearcoatMapTransform * vec3( CLEARCOATMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\tvClearcoatNormalMapUv = ( clearcoatNormalMapTransform * vec3( CLEARCOAT_NORMALMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\tvClearcoatRoughnessMapUv = ( clearcoatRoughnessMapTransform * vec3( CLEARCOAT_ROUGHNESSMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_IRIDESCENCEMAP\n\tvIridescenceMapUv = ( iridescenceMapTransform * vec3( IRIDESCENCEMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\tvIridescenceThicknessMapUv = ( iridescenceThicknessMapTransform * vec3( IRIDESCENCE_THICKNESSMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_SHEEN_COLORMAP\n\tvSheenColorMapUv = ( sheenColorMapTransform * vec3( SHEEN_COLORMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_SHEEN_ROUGHNESSMAP\n\tvSheenRoughnessMapUv = ( sheenRoughnessMapTransform * vec3( SHEEN_ROUGHNESSMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_SPECULARMAP\n\tvSpecularMapUv = ( specularMapTransform * vec3( SPECULARMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_SPECULAR_COLORMAP\n\tvSpecularColorMapUv = ( specularColorMapTransform * vec3( SPECULAR_COLORMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_SPECULAR_INTENSITYMAP\n\tvSpecularIntensityMapUv = ( specularIntensityMapTransform * vec3( SPECULAR_INTENSITYMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_TRANSMISSIONMAP\n\tvTransmissionMapUv = ( transmissionMapTransform * vec3( TRANSMISSIONMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_THICKNESSMAP\n\tvThicknessMapUv = ( thicknessMapTransform * vec3( THICKNESSMAP_UV, 1 ) ).xy;\n#endif",worldpos_vertex:"#if defined( USE_ENVMAP ) || defined( DISTANCE ) || defined ( USE_SHADOWMAP ) || defined ( USE_TRANSMISSION ) || NUM_SPOT_LIGHT_COORDS > 0\n\tvec4 worldPosition = vec4( transformed, 1.0 );\n\t#ifdef USE_BATCHING\n\t\tworldPosition = batchingMatrix * worldPosition;\n\t#endif\n\t#ifdef USE_INSTANCING\n\t\tworldPosition = instanceMatrix * worldPosition;\n\t#endif\n\tworldPosition = modelMatrix * worldPosition;\n#endif",background_vert:"varying vec2 vUv;\nuniform mat3 uvTransform;\nvoid main() {\n\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n\tgl_Position = vec4( position.xy, 1.0, 1.0 );\n}",background_frag:"uniform sampler2D t2D;\nuniform float backgroundIntensity;\nvarying vec2 vUv;\nvoid main() {\n\tvec4 texColor = texture2D( t2D, vUv );\n\t#ifdef DECODE_VIDEO_TEXTURE\n\t\ttexColor = vec4( mix( pow( texColor.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), texColor.rgb * 0.0773993808, vec3( lessThanEqual( texColor.rgb, vec3( 0.04045 ) ) ) ), texColor.w );\n\t#endif\n\ttexColor.rgb *= backgroundIntensity;\n\tgl_FragColor = texColor;\n\t#include \n\t#include \n}",backgroundCube_vert:"varying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n\tgl_Position.z = gl_Position.w;\n}",backgroundCube_frag:"#ifdef ENVMAP_TYPE_CUBE\n\tuniform samplerCube envMap;\n#elif defined( ENVMAP_TYPE_CUBE_UV )\n\tuniform sampler2D envMap;\n#endif\nuniform float flipEnvMap;\nuniform float backgroundBlurriness;\nuniform float backgroundIntensity;\nvarying vec3 vWorldDirection;\n#include \nvoid main() {\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tvec4 texColor = textureCube( envMap, vec3( flipEnvMap * vWorldDirection.x, vWorldDirection.yz ) );\n\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\tvec4 texColor = textureCubeUV( envMap, vWorldDirection, backgroundBlurriness );\n\t#else\n\t\tvec4 texColor = vec4( 0.0, 0.0, 0.0, 1.0 );\n\t#endif\n\ttexColor.rgb *= backgroundIntensity;\n\tgl_FragColor = texColor;\n\t#include \n\t#include \n}",cube_vert:"varying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n\tgl_Position.z = gl_Position.w;\n}",cube_frag:"uniform samplerCube tCube;\nuniform float tFlip;\nuniform float opacity;\nvarying vec3 vWorldDirection;\nvoid main() {\n\tvec4 texColor = textureCube( tCube, vec3( tFlip * vWorldDirection.x, vWorldDirection.yz ) );\n\tgl_FragColor = texColor;\n\tgl_FragColor.a *= opacity;\n\t#include \n\t#include \n}",depth_vert:"#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvarying vec2 vHighPrecisionZW;\nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include \n\t\t#include \n\t\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvHighPrecisionZW = gl_Position.zw;\n}",depth_frag:"#if DEPTH_PACKING == 3200\n\tuniform float opacity;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvarying vec2 vHighPrecisionZW;\nvoid main() {\n\tvec4 diffuseColor = vec4( 1.0 );\n\t#include \n\t#if DEPTH_PACKING == 3200\n\t\tdiffuseColor.a = opacity;\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tfloat fragCoordZ = 0.5 * vHighPrecisionZW[0] / vHighPrecisionZW[1] + 0.5;\n\t#if DEPTH_PACKING == 3200\n\t\tgl_FragColor = vec4( vec3( 1.0 - fragCoordZ ), opacity );\n\t#elif DEPTH_PACKING == 3201\n\t\tgl_FragColor = packDepthToRGBA( fragCoordZ );\n\t#endif\n}",distanceRGBA_vert:"#define DISTANCE\nvarying vec3 vWorldPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include \n\t\t#include \n\t\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvWorldPosition = worldPosition.xyz;\n}",distanceRGBA_frag:"#define DISTANCE\nuniform vec3 referencePosition;\nuniform float nearDistance;\nuniform float farDistance;\nvarying vec3 vWorldPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main () {\n\tvec4 diffuseColor = vec4( 1.0 );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tfloat dist = length( vWorldPosition - referencePosition );\n\tdist = ( dist - nearDistance ) / ( farDistance - nearDistance );\n\tdist = saturate( dist );\n\tgl_FragColor = packDepthToRGBA( dist );\n}",equirect_vert:"varying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n}",equirect_frag:"uniform sampler2D tEquirect;\nvarying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvec3 direction = normalize( vWorldDirection );\n\tvec2 sampleUV = equirectUv( direction );\n\tgl_FragColor = texture2D( tEquirect, sampleUV );\n\t#include \n\t#include \n}",linedashed_vert:"uniform float scale;\nattribute float lineDistance;\nvarying float vLineDistance;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvLineDistance = scale * lineDistance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",linedashed_frag:"uniform vec3 diffuse;\nuniform float opacity;\nuniform float dashSize;\nuniform float totalSize;\nvarying float vLineDistance;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\tif ( mod( vLineDistance, totalSize ) > dashSize ) {\n\t\tdiscard;\n\t}\n\tvec3 outgoingLight = vec3( 0.0 );\n\t#include \n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",meshbasic_vert:"#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#if defined ( USE_ENVMAP ) || defined ( USE_SKINNING )\n\t\t#include \n\t\t#include \n\t\t#include \n\t\t#include \n\t\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",meshbasic_frag:"uniform vec3 diffuse;\nuniform float opacity;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\t#ifdef USE_LIGHTMAP\n\t\tvec4 lightMapTexel = texture2D( lightMap, vLightMapUv );\n\t\treflectedLight.indirectDiffuse += lightMapTexel.rgb * lightMapIntensity * RECIPROCAL_PI;\n\t#else\n\t\treflectedLight.indirectDiffuse += vec3( 1.0 );\n\t#endif\n\t#include \n\treflectedLight.indirectDiffuse *= diffuseColor.rgb;\n\tvec3 outgoingLight = reflectedLight.indirectDiffuse;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",meshlambert_vert:"#define LAMBERT\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n\t#include \n}",meshlambert_frag:"#define LAMBERT\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",meshmatcap_vert:"#define MATCAP\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n}",meshmatcap_frag:"#define MATCAP\nuniform vec3 diffuse;\nuniform float opacity;\nuniform sampler2D matcap;\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 viewDir = normalize( vViewPosition );\n\tvec3 x = normalize( vec3( viewDir.z, 0.0, - viewDir.x ) );\n\tvec3 y = cross( viewDir, x );\n\tvec2 uv = vec2( dot( x, normal ), dot( y, normal ) ) * 0.495 + 0.5;\n\t#ifdef USE_MATCAP\n\t\tvec4 matcapColor = texture2D( matcap, uv );\n\t#else\n\t\tvec4 matcapColor = vec4( vec3( mix( 0.2, 0.8, uv.y ) ), 1.0 );\n\t#endif\n\tvec3 outgoingLight = diffuseColor.rgb * matcapColor.rgb;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",meshnormal_vert:"#define NORMAL\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP_TANGENTSPACE )\n\tvarying vec3 vViewPosition;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP_TANGENTSPACE )\n\tvViewPosition = - mvPosition.xyz;\n#endif\n}",meshnormal_frag:"#define NORMAL\nuniform float opacity;\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP_TANGENTSPACE )\n\tvarying vec3 vViewPosition;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvec4 diffuseColor = vec4( 0.0, 0.0, 0.0, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\tgl_FragColor = vec4( packNormalToRGB( normal ), diffuseColor.a );\n\t#ifdef OPAQUE\n\t\tgl_FragColor.a = 1.0;\n\t#endif\n}",meshphong_vert:"#define PHONG\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n\t#include \n}",meshphong_frag:"#define PHONG\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform vec3 specular;\nuniform float shininess;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",meshphysical_vert:"#define STANDARD\nvarying vec3 vViewPosition;\n#ifdef USE_TRANSMISSION\n\tvarying vec3 vWorldPosition;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n#ifdef USE_TRANSMISSION\n\tvWorldPosition = worldPosition.xyz;\n#endif\n}",meshphysical_frag:"#define STANDARD\n#ifdef PHYSICAL\n\t#define IOR\n\t#define USE_SPECULAR\n#endif\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float roughness;\nuniform float metalness;\nuniform float opacity;\n#ifdef IOR\n\tuniform float ior;\n#endif\n#ifdef USE_SPECULAR\n\tuniform float specularIntensity;\n\tuniform vec3 specularColor;\n\t#ifdef USE_SPECULAR_COLORMAP\n\t\tuniform sampler2D specularColorMap;\n\t#endif\n\t#ifdef USE_SPECULAR_INTENSITYMAP\n\t\tuniform sampler2D specularIntensityMap;\n\t#endif\n#endif\n#ifdef USE_CLEARCOAT\n\tuniform float clearcoat;\n\tuniform float clearcoatRoughness;\n#endif\n#ifdef USE_IRIDESCENCE\n\tuniform float iridescence;\n\tuniform float iridescenceIOR;\n\tuniform float iridescenceThicknessMinimum;\n\tuniform float iridescenceThicknessMaximum;\n#endif\n#ifdef USE_SHEEN\n\tuniform vec3 sheenColor;\n\tuniform float sheenRoughness;\n\t#ifdef USE_SHEEN_COLORMAP\n\t\tuniform sampler2D sheenColorMap;\n\t#endif\n\t#ifdef USE_SHEEN_ROUGHNESSMAP\n\t\tuniform sampler2D sheenRoughnessMap;\n\t#endif\n#endif\n#ifdef USE_ANISOTROPY\n\tuniform vec2 anisotropyVector;\n\t#ifdef USE_ANISOTROPYMAP\n\t\tuniform sampler2D anisotropyMap;\n\t#endif\n#endif\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 totalDiffuse = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse;\n\tvec3 totalSpecular = reflectedLight.directSpecular + reflectedLight.indirectSpecular;\n\t#include \n\tvec3 outgoingLight = totalDiffuse + totalSpecular + totalEmissiveRadiance;\n\t#ifdef USE_SHEEN\n\t\tfloat sheenEnergyComp = 1.0 - 0.157 * max3( material.sheenColor );\n\t\toutgoingLight = outgoingLight * sheenEnergyComp + sheenSpecularDirect + sheenSpecularIndirect;\n\t#endif\n\t#ifdef USE_CLEARCOAT\n\t\tfloat dotNVcc = saturate( dot( geometryClearcoatNormal, geometryViewDir ) );\n\t\tvec3 Fcc = F_Schlick( material.clearcoatF0, material.clearcoatF90, dotNVcc );\n\t\toutgoingLight = outgoingLight * ( 1.0 - material.clearcoat * Fcc ) + ( clearcoatSpecularDirect + clearcoatSpecularIndirect ) * material.clearcoat;\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",meshtoon_vert:"#define TOON\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n}",meshtoon_frag:"#define TOON\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",points_vert:"uniform float size;\nuniform float scale;\n#include \n#include \n#include \n#include \n#include \n#include \n#ifdef USE_POINTS_UV\n\tvarying vec2 vUv;\n\tuniform mat3 uvTransform;\n#endif\nvoid main() {\n\t#ifdef USE_POINTS_UV\n\t\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tgl_PointSize = size;\n\t#ifdef USE_SIZEATTENUATION\n\t\tbool isPerspective = isPerspectiveMatrix( projectionMatrix );\n\t\tif ( isPerspective ) gl_PointSize *= ( scale / - mvPosition.z );\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n}",points_frag:"uniform vec3 diffuse;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\tvec3 outgoingLight = vec3( 0.0 );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",shadow_vert:"#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",shadow_frag:"uniform vec3 color;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tgl_FragColor = vec4( color, opacity * ( 1.0 - getShadowMask() ) );\n\t#include \n\t#include \n\t#include \n}",sprite_vert:"uniform float rotation;\nuniform vec2 center;\n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 mvPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );\n\tvec2 scale;\n\tscale.x = length( vec3( modelMatrix[ 0 ].x, modelMatrix[ 0 ].y, modelMatrix[ 0 ].z ) );\n\tscale.y = length( vec3( modelMatrix[ 1 ].x, modelMatrix[ 1 ].y, modelMatrix[ 1 ].z ) );\n\t#ifndef USE_SIZEATTENUATION\n\t\tbool isPerspective = isPerspectiveMatrix( projectionMatrix );\n\t\tif ( isPerspective ) scale *= - mvPosition.z;\n\t#endif\n\tvec2 alignedPosition = ( position.xy - ( center - vec2( 0.5 ) ) ) * scale;\n\tvec2 rotatedPosition;\n\trotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;\n\trotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;\n\tmvPosition.xy += rotatedPosition;\n\tgl_Position = projectionMatrix * mvPosition;\n\t#include \n\t#include \n\t#include \n}",sprite_frag:"uniform vec3 diffuse;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\tvec3 outgoingLight = vec3( 0.0 );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\t#include \n\t#include \n\t#include \n\t#include \n}"},fa={common:{diffuse:{value:new qr(16777215)},opacity:{value:1},map:{value:null},mapTransform:{value:new $n},alphaMap:{value:null},alphaMapTransform:{value:new $n},alphaTest:{value:0}},specularmap:{specularMap:{value:null},specularMapTransform:{value:new $n}},envmap:{envMap:{value:null},flipEnvMap:{value:-1},reflectivity:{value:1},ior:{value:1.5},refractionRatio:{value:.98}},aomap:{aoMap:{value:null},aoMapIntensity:{value:1},aoMapTransform:{value:new $n}},lightmap:{lightMap:{value:null},lightMapIntensity:{value:1},lightMapTransform:{value:new $n}},bumpmap:{bumpMap:{value:null},bumpMapTransform:{value:new $n},bumpScale:{value:1}},normalmap:{normalMap:{value:null},normalMapTransform:{value:new $n},normalScale:{value:new Kn(1,1)}},displacementmap:{displacementMap:{value:null},displacementMapTransform:{value:new $n},displacementScale:{value:1},displacementBias:{value:0}},emissivemap:{emissiveMap:{value:null},emissiveMapTransform:{value:new $n}},metalnessmap:{metalnessMap:{value:null},metalnessMapTransform:{value:new $n}},roughnessmap:{roughnessMap:{value:null},roughnessMapTransform:{value:new $n}},gradientmap:{gradientMap:{value:null}},fog:{fogDensity:{value:25e-5},fogNear:{value:1},fogFar:{value:2e3},fogColor:{value:new qr(16777215)}},lights:{ambientLightColor:{value:[]},lightProbe:{value:[]},directionalLights:{value:[],properties:{direction:{},color:{}}},directionalLightShadows:{value:[],properties:{shadowBias:{},shadowNormalBias:{},shadowRadius:{},shadowMapSize:{}}},directionalShadowMap:{value:[]},directionalShadowMatrix:{value:[]},spotLights:{value:[],properties:{color:{},position:{},direction:{},distance:{},coneCos:{},penumbraCos:{},decay:{}}},spotLightShadows:{value:[],properties:{shadowBias:{},shadowNormalBias:{},shadowRadius:{},shadowMapSize:{}}},spotLightMap:{value:[]},spotShadowMap:{value:[]},spotLightMatrix:{value:[]},pointLights:{value:[],properties:{color:{},position:{},decay:{},distance:{}}},pointLightShadows:{value:[],properties:{shadowBias:{},shadowNormalBias:{},shadowRadius:{},shadowMapSize:{},shadowCameraNear:{},shadowCameraFar:{}}},pointShadowMap:{value:[]},pointShadowMatrix:{value:[]},hemisphereLights:{value:[],properties:{direction:{},skyColor:{},groundColor:{}}},rectAreaLights:{value:[],properties:{color:{},position:{},width:{},height:{}}},ltc_1:{value:null},ltc_2:{value:null}},points:{diffuse:{value:new qr(16777215)},opacity:{value:1},size:{value:1},scale:{value:1},map:{value:null},alphaMap:{value:null},alphaMapTransform:{value:new $n},alphaTest:{value:0},uvTransform:{value:new $n}},sprite:{diffuse:{value:new qr(16777215)},opacity:{value:1},center:{value:new Kn(.5,.5)},rotation:{value:0},map:{value:null},mapTransform:{value:new $n},alphaMap:{value:null},alphaMapTransform:{value:new $n},alphaTest:{value:0}}},ga={basic:{uniforms:Xs([fa.common,fa.specularmap,fa.envmap,fa.aomap,fa.lightmap,fa.fog]),vertexShader:ma.meshbasic_vert,fragmentShader:ma.meshbasic_frag},lambert:{uniforms:Xs([fa.common,fa.specularmap,fa.envmap,fa.aomap,fa.lightmap,fa.emissivemap,fa.bumpmap,fa.normalmap,fa.displacementmap,fa.fog,fa.lights,{emissive:{value:new qr(0)}}]),vertexShader:ma.meshlambert_vert,fragmentShader:ma.meshlambert_frag},phong:{uniforms:Xs([fa.common,fa.specularmap,fa.envmap,fa.aomap,fa.lightmap,fa.emissivemap,fa.bumpmap,fa.normalmap,fa.displacementmap,fa.fog,fa.lights,{emissive:{value:new qr(0)},specular:{value:new qr(1118481)},shininess:{value:30}}]),vertexShader:ma.meshphong_vert,fragmentShader:ma.meshphong_frag},standard:{uniforms:Xs([fa.common,fa.envmap,fa.aomap,fa.lightmap,fa.emissivemap,fa.bumpmap,fa.normalmap,fa.displacementmap,fa.roughnessmap,fa.metalnessmap,fa.fog,fa.lights,{emissive:{value:new qr(0)},roughness:{value:1},metalness:{value:0},envMapIntensity:{value:1}}]),vertexShader:ma.meshphysical_vert,fragmentShader:ma.meshphysical_frag},toon:{uniforms:Xs([fa.common,fa.aomap,fa.lightmap,fa.emissivemap,fa.bumpmap,fa.normalmap,fa.displacementmap,fa.gradientmap,fa.fog,fa.lights,{emissive:{value:new qr(0)}}]),vertexShader:ma.meshtoon_vert,fragmentShader:ma.meshtoon_frag},matcap:{uniforms:Xs([fa.common,fa.bumpmap,fa.normalmap,fa.displacementmap,fa.fog,{matcap:{value:null}}]),vertexShader:ma.meshmatcap_vert,fragmentShader:ma.meshmatcap_frag},points:{uniforms:Xs([fa.points,fa.fog]),vertexShader:ma.points_vert,fragmentShader:ma.points_frag},dashed:{uniforms:Xs([fa.common,fa.fog,{scale:{value:1},dashSize:{value:1},totalSize:{value:2}}]),vertexShader:ma.linedashed_vert,fragmentShader:ma.linedashed_frag},depth:{uniforms:Xs([fa.common,fa.displacementmap]),vertexShader:ma.depth_vert,fragmentShader:ma.depth_frag},normal:{uniforms:Xs([fa.common,fa.bumpmap,fa.normalmap,fa.displacementmap,{opacity:{value:1}}]),vertexShader:ma.meshnormal_vert,fragmentShader:ma.meshnormal_frag},sprite:{uniforms:Xs([fa.sprite,fa.fog]),vertexShader:ma.sprite_vert,fragmentShader:ma.sprite_frag},background:{uniforms:{uvTransform:{value:new $n},t2D:{value:null},backgroundIntensity:{value:1}},vertexShader:ma.background_vert,fragmentShader:ma.background_frag},backgroundCube:{uniforms:{envMap:{value:null},flipEnvMap:{value:-1},backgroundBlurriness:{value:0},backgroundIntensity:{value:1}},vertexShader:ma.backgroundCube_vert,fragmentShader:ma.backgroundCube_frag},cube:{uniforms:{tCube:{value:null},tFlip:{value:-1},opacity:{value:1}},vertexShader:ma.cube_vert,fragmentShader:ma.cube_frag},equirect:{uniforms:{tEquirect:{value:null}},vertexShader:ma.equirect_vert,fragmentShader:ma.equirect_frag},distanceRGBA:{uniforms:Xs([fa.common,fa.displacementmap,{referencePosition:{value:new Pi},nearDistance:{value:1},farDistance:{value:1e3}}]),vertexShader:ma.distanceRGBA_vert,fragmentShader:ma.distanceRGBA_frag},shadow:{uniforms:Xs([fa.lights,fa.fog,{color:{value:new qr(0)},opacity:{value:1}}]),vertexShader:ma.shadow_vert,fragmentShader:ma.shadow_frag}};ga.physical={uniforms:Xs([ga.standard.uniforms,{clearcoat:{value:0},clearcoatMap:{value:null},clearcoatMapTransform:{value:new $n},clearcoatNormalMap:{value:null},clearcoatNormalMapTransform:{value:new $n},clearcoatNormalScale:{value:new Kn(1,1)},clearcoatRoughness:{value:0},clearcoatRoughnessMap:{value:null},clearcoatRoughnessMapTransform:{value:new $n},iridescence:{value:0},iridescenceMap:{value:null},iridescenceMapTransform:{value:new $n},iridescenceIOR:{value:1.3},iridescenceThicknessMinimum:{value:100},iridescenceThicknessMaximum:{value:400},iridescenceThicknessMap:{value:null},iridescenceThicknessMapTransform:{value:new $n},sheen:{value:0},sheenColor:{value:new qr(0)},sheenColorMap:{value:null},sheenColorMapTransform:{value:new $n},sheenRoughness:{value:1},sheenRoughnessMap:{value:null},sheenRoughnessMapTransform:{value:new $n},transmission:{value:0},transmissionMap:{value:null},transmissionMapTransform:{value:new $n},transmissionSamplerSize:{value:new Kn},transmissionSamplerMap:{value:null},thickness:{value:0},thicknessMap:{value:null},thicknessMapTransform:{value:new $n},attenuationDistance:{value:0},attenuationColor:{value:new qr(0)},specularColor:{value:new qr(1,1,1)},specularColorMap:{value:null},specularColorMapTransform:{value:new $n},specularIntensity:{value:1},specularIntensityMap:{value:null},specularIntensityMapTransform:{value:new $n},anisotropyVector:{value:new Kn},anisotropyMap:{value:null},anisotropyMapTransform:{value:new $n}}]),vertexShader:ma.meshphysical_vert,fragmentShader:ma.meshphysical_frag};const _a={r:0,b:0,g:0};function va(t,e,n,i,r,s,a){const o=new qr(0);let l,c,h=!0===s?0:1,p=null,m=0,f=null;function g(e,n){e.getRGB(_a,js(t)),i.buffers.color.setClear(_a.r,_a.g,_a.b,n,a)}return{getClearColor:function(){return o},setClearColor:function(t,e=1){o.set(t),h=e,g(o,h)},getClearAlpha:function(){return h},setClearAlpha:function(t){h=t,g(o,h)},render:function(s,_){let v=!1,x=!0===_.isScene?_.background:null;if(x&&x.isTexture){x=(_.backgroundBlurriness>0?n:e).get(x)}null===x?g(o,h):x&&x.isColor&&(g(x,1),v=!0);const y=t.xr.getEnvironmentBlendMode();"additive"===y?i.buffers.color.setClear(0,0,0,1,a):"alpha-blend"===y&&i.buffers.color.setClear(0,0,0,0,a),(t.autoClear||v)&&t.clear(t.autoClearColor,t.autoClearDepth,t.autoClearStencil),x&&(x.isCubeTexture||x.mapping===ut)?(void 0===c&&(c=new Vs(new Gs(1,1,1),new Ys({name:"BackgroundCubeMaterial",uniforms:Ws(ga.backgroundCube.uniforms),vertexShader:ga.backgroundCube.vertexShader,fragmentShader:ga.backgroundCube.fragmentShader,side:d,depthTest:!1,depthWrite:!1,fog:!1})),c.geometry.deleteAttribute("normal"),c.geometry.deleteAttribute("uv"),c.onBeforeRender=function(t,e,n){this.matrixWorld.copyPosition(n.matrixWorld)},Object.defineProperty(c.material,"envMap",{get:function(){return this.uniforms.envMap.value}}),r.update(c)),c.material.uniforms.envMap.value=x,c.material.uniforms.flipEnvMap.value=x.isCubeTexture&&!1===x.isRenderTargetTexture?-1:1,c.material.uniforms.backgroundBlurriness.value=_.backgroundBlurriness,c.material.uniforms.backgroundIntensity.value=_.backgroundIntensity,c.material.toneMapped=ui.getTransfer(x.colorSpace)!==Ze,p===x&&m===x.version&&f===t.toneMapping||(c.material.needsUpdate=!0,p=x,m=x.version,f=t.toneMapping),c.layers.enableAll(),s.unshift(c,c.geometry,c.material,0,0,null)):x&&x.isTexture&&(void 0===l&&(l=new Vs(new pa(2,2),new Ys({name:"BackgroundMaterial",uniforms:Ws(ga.background.uniforms),vertexShader:ga.background.vertexShader,fragmentShader:ga.background.fragmentShader,side:u,depthTest:!1,depthWrite:!1,fog:!1})),l.geometry.deleteAttribute("normal"),Object.defineProperty(l.material,"map",{get:function(){return this.uniforms.t2D.value}}),r.update(l)),l.material.uniforms.t2D.value=x,l.material.uniforms.backgroundIntensity.value=_.backgroundIntensity,l.material.toneMapped=ui.getTransfer(x.colorSpace)!==Ze,!0===x.matrixAutoUpdate&&x.updateMatrix(),l.material.uniforms.uvTransform.value.copy(x.matrix),p===x&&m===x.version&&f===t.toneMapping||(l.material.needsUpdate=!0,p=x,m=x.version,f=t.toneMapping),l.layers.enableAll(),s.unshift(l,l.geometry,l.material,0,0,null))}}}function xa(t,e,n,i){const r=t.getParameter(t.MAX_VERTEX_ATTRIBS),s=i.isWebGL2?null:e.get("OES_vertex_array_object"),a=i.isWebGL2||null!==s,o={},l=p(null);let c=l,h=!1;function u(e){return i.isWebGL2?t.bindVertexArray(e):s.bindVertexArrayOES(e)}function d(e){return i.isWebGL2?t.deleteVertexArray(e):s.deleteVertexArrayOES(e)}function p(t){const e=[],n=[],i=[];for(let t=0;t=0){const n=r[e];let i=s[e];if(void 0===i&&("instanceMatrix"===e&&t.instanceMatrix&&(i=t.instanceMatrix),"instanceColor"===e&&t.instanceColor&&(i=t.instanceColor)),void 0===n)return!0;if(n.attribute!==i)return!0;if(i&&n.data!==i.data)return!0;a++}}return c.attributesNum!==a||c.index!==i}(r,x,d,y),M&&function(t,e,n,i){const r={},s=e.attributes;let a=0;const o=n.getAttributes();for(const e in o){if(o[e].location>=0){let n=s[e];void 0===n&&("instanceMatrix"===e&&t.instanceMatrix&&(n=t.instanceMatrix),"instanceColor"===e&&t.instanceColor&&(n=t.instanceColor));const i={};i.attribute=n,n&&n.data&&(i.data=n.data),r[e]=i,a++}}c.attributes=r,c.attributesNum=a,c.index=i}(r,x,d,y)}else{const t=!0===l.wireframe;c.geometry===x.id&&c.program===d.id&&c.wireframe===t||(c.geometry=x.id,c.program=d.id,c.wireframe=t,M=!0)}null!==y&&n.update(y,t.ELEMENT_ARRAY_BUFFER),(M||h)&&(h=!1,function(r,s,a,o){if(!1===i.isWebGL2&&(r.isInstancedMesh||o.isInstancedBufferGeometry)&&null===e.get("ANGLE_instanced_arrays"))return;m();const l=o.attributes,c=a.getAttributes(),h=s.defaultAttributeValues;for(const e in c){const s=c[e];if(s.location>=0){let a=l[e];if(void 0===a&&("instanceMatrix"===e&&r.instanceMatrix&&(a=r.instanceMatrix),"instanceColor"===e&&r.instanceColor&&(a=r.instanceColor)),void 0!==a){const e=a.normalized,l=a.itemSize,c=n.get(a);if(void 0===c)continue;const h=c.buffer,u=c.type,d=c.bytesPerElement,p=!0===i.isWebGL2&&(u===t.INT||u===t.UNSIGNED_INT||a.gpuType===Ct);if(a.isInterleavedBufferAttribute){const n=a.data,i=n.stride,c=a.offset;if(n.isInstancedInterleavedBuffer){for(let t=0;t0&&t.getShaderPrecisionFormat(t.FRAGMENT_SHADER,t.HIGH_FLOAT).precision>0)return"highp";e="mediump"}return"mediump"===e&&t.getShaderPrecisionFormat(t.VERTEX_SHADER,t.MEDIUM_FLOAT).precision>0&&t.getShaderPrecisionFormat(t.FRAGMENT_SHADER,t.MEDIUM_FLOAT).precision>0?"mediump":"lowp"}const s="undefined"!=typeof WebGL2RenderingContext&&"WebGL2RenderingContext"===t.constructor.name;let a=void 0!==n.precision?n.precision:"highp";const o=r(a);o!==a&&(console.warn("THREE.WebGLRenderer:",a,"not supported, using",o,"instead."),a=o);const l=s||e.has("WEBGL_draw_buffers"),c=!0===n.logarithmicDepthBuffer,h=t.getParameter(t.MAX_TEXTURE_IMAGE_UNITS),u=t.getParameter(t.MAX_VERTEX_TEXTURE_IMAGE_UNITS),d=t.getParameter(t.MAX_TEXTURE_SIZE),p=t.getParameter(t.MAX_CUBE_MAP_TEXTURE_SIZE),m=t.getParameter(t.MAX_VERTEX_ATTRIBS),f=t.getParameter(t.MAX_VERTEX_UNIFORM_VECTORS),g=t.getParameter(t.MAX_VARYING_VECTORS),_=t.getParameter(t.MAX_FRAGMENT_UNIFORM_VECTORS),v=u>0,x=s||e.has("OES_texture_float");return{isWebGL2:s,drawBuffers:l,getMaxAnisotropy:function(){if(void 0!==i)return i;if(!0===e.has("EXT_texture_filter_anisotropic")){const n=e.get("EXT_texture_filter_anisotropic");i=t.getParameter(n.MAX_TEXTURE_MAX_ANISOTROPY_EXT)}else i=0;return i},getMaxPrecision:r,precision:a,logarithmicDepthBuffer:c,maxTextures:h,maxVertexTextures:u,maxTextureSize:d,maxCubemapSize:p,maxAttributes:m,maxVertexUniforms:f,maxVaryings:g,maxFragmentUniforms:_,vertexTextures:v,floatFragmentTextures:x,floatVertexTextures:v&&x,maxSamples:s?t.getParameter(t.MAX_SAMPLES):0}}function Sa(t){const e=this;let n=null,i=0,r=!1,s=!1;const a=new oa,o=new $n,l={value:null,needsUpdate:!1};function c(t,n,i,r){const s=null!==t?t.length:0;let c=null;if(0!==s){if(c=l.value,!0!==r||null===c){const e=i+4*s,r=n.matrixWorldInverse;o.getNormalMatrix(r),(null===c||c.length0);e.numPlanes=i,e.numIntersection=0}();else{const t=s?0:i,e=4*t;let r=m.clippingState||null;l.value=r,r=c(u,o,e,h);for(let t=0;t!==e;++t)r[t]=n[t];m.clippingState=r,this.numIntersection=d?this.numPlanes:0,this.numPlanes+=t}}}function ba(t){let e=new WeakMap;function n(t,e){return e===ct?t.mapping=ot:e===ht&&(t.mapping=lt),t}function i(t){const n=t.target;n.removeEventListener("dispose",i);const r=e.get(n);void 0!==r&&(e.delete(n),r.dispose())}return{get:function(r){if(r&&r.isTexture){const s=r.mapping;if(s===ct||s===ht){if(e.has(r)){return n(e.get(r).texture,r.mapping)}{const s=r.image;if(s&&s.height>0){const a=new ia(s.height);return a.fromEquirectangularTexture(t,r),e.set(r,a),r.addEventListener("dispose",i),n(a.texture,r.mapping)}return null}}}return r},dispose:function(){e=new WeakMap}}}class Ea extends Zs{constructor(t=-1,e=1,n=1,i=-1,r=.1,s=2e3){super(),this.isOrthographicCamera=!0,this.type="OrthographicCamera",this.zoom=1,this.view=null,this.left=t,this.right=e,this.top=n,this.bottom=i,this.near=r,this.far=s,this.updateProjectionMatrix()}copy(t,e){return super.copy(t,e),this.left=t.left,this.right=t.right,this.top=t.top,this.bottom=t.bottom,this.near=t.near,this.far=t.far,this.zoom=t.zoom,this.view=null===t.view?null:Object.assign({},t.view),this}setViewOffset(t,e,n,i,r,s){null===this.view&&(this.view={enabled:!0,fullWidth:1,fullHeight:1,offsetX:0,offsetY:0,width:1,height:1}),this.view.enabled=!0,this.view.fullWidth=t,this.view.fullHeight=e,this.view.offsetX=n,this.view.offsetY=i,this.view.width=r,this.view.height=s,this.updateProjectionMatrix()}clearViewOffset(){null!==this.view&&(this.view.enabled=!1),this.updateProjectionMatrix()}updateProjectionMatrix(){const t=(this.right-this.left)/(2*this.zoom),e=(this.top-this.bottom)/(2*this.zoom),n=(this.right+this.left)/2,i=(this.top+this.bottom)/2;let r=n-t,s=n+t,a=i+e,o=i-e;if(null!==this.view&&this.view.enabled){const t=(this.right-this.left)/this.view.fullWidth/this.zoom,e=(this.top-this.bottom)/this.view.fullHeight/this.zoom;r+=t*this.view.offsetX,s=r+t*this.view.width,a-=e*this.view.offsetY,o=a-e*this.view.height}this.projectionMatrix.makeOrthographic(r,s,a,o,this.near,this.far,this.coordinateSystem),this.projectionMatrixInverse.copy(this.projectionMatrix).invert()}toJSON(t){const e=super.toJSON(t);return e.object.zoom=this.zoom,e.object.left=this.left,e.object.right=this.right,e.object.top=this.top,e.object.bottom=this.bottom,e.object.near=this.near,e.object.far=this.far,null!==this.view&&(e.object.view=Object.assign({},this.view)),e}}const Ta=[.125,.215,.35,.446,.526,.582],wa=20,Aa=new Ea,Ra=new qr;let Ca=null,Pa=0,La=0;const Ia=(1+Math.sqrt(5))/2,Ua=1/Ia,Na=[new Pi(1,1,1),new Pi(-1,1,1),new Pi(1,1,-1),new Pi(-1,1,-1),new Pi(0,Ia,Ua),new Pi(0,Ia,-Ua),new Pi(Ua,0,Ia),new Pi(-Ua,0,Ia),new Pi(Ia,Ua,0),new Pi(-Ia,Ua,0)];class Da{constructor(t){this._renderer=t,this._pingPongRenderTarget=null,this._lodMax=0,this._cubeSize=0,this._lodPlanes=[],this._sizeLods=[],this._sigmas=[],this._blurMaterial=null,this._cubemapMaterial=null,this._equirectMaterial=null,this._compileMaterial(this._blurMaterial)}fromScene(t,e=0,n=.1,i=100){Ca=this._renderer.getRenderTarget(),Pa=this._renderer.getActiveCubeFace(),La=this._renderer.getActiveMipmapLevel(),this._setSize(256);const r=this._allocateTargets();return r.depthBuffer=!0,this._sceneToCubeUV(t,n,i,r),e>0&&this._blur(r,0,0,e),this._applyPMREM(r),this._cleanup(r),r}fromEquirectangular(t,e=null){return this._fromTexture(t,e)}fromCubemap(t,e=null){return this._fromTexture(t,e)}compileCubemapShader(){null===this._cubemapMaterial&&(this._cubemapMaterial=za(),this._compileMaterial(this._cubemapMaterial))}compileEquirectangularShader(){null===this._equirectMaterial&&(this._equirectMaterial=Ba(),this._compileMaterial(this._equirectMaterial))}dispose(){this._dispose(),null!==this._cubemapMaterial&&this._cubemapMaterial.dispose(),null!==this._equirectMaterial&&this._equirectMaterial.dispose()}_setSize(t){this._lodMax=Math.floor(Math.log2(t)),this._cubeSize=Math.pow(2,this._lodMax)}_dispose(){null!==this._blurMaterial&&this._blurMaterial.dispose(),null!==this._pingPongRenderTarget&&this._pingPongRenderTarget.dispose();for(let t=0;tt-4?o=Ta[a-t+4-1]:0===a&&(o=0),i.push(o);const l=1/(s-2),c=-l,h=1+l,u=[c,c,h,c,h,h,c,c,h,h,c,h],d=6,p=6,m=3,f=2,g=1,_=new Float32Array(m*p*d),v=new Float32Array(f*p*d),x=new Float32Array(g*p*d);for(let t=0;t2?0:-1,i=[e,n,0,e+2/3,n,0,e+2/3,n+1,0,e,n,0,e+2/3,n+1,0,e,n+1,0];_.set(i,m*p*t),v.set(u,f*p*t);const r=[t,t,t,t,t,t];x.set(r,g*p*t)}const y=new bs;y.setAttribute("position",new ss(_,m)),y.setAttribute("uv",new ss(v,f)),y.setAttribute("faceIndex",new ss(x,g)),e.push(y),r>4&&r--}return{lodPlanes:e,sizeLods:n,sigmas:i}}(i)),this._blurMaterial=function(t,e,n){const i=new Float32Array(wa),r=new Pi(0,1,0),s=new Ys({name:"SphericalGaussianBlur",defines:{n:wa,CUBEUV_TEXEL_WIDTH:1/e,CUBEUV_TEXEL_HEIGHT:1/n,CUBEUV_MAX_MIP:`${t}.0`},uniforms:{envMap:{value:null},samples:{value:1},weights:{value:i},latitudinal:{value:!1},dTheta:{value:0},mipInt:{value:0},poleAxis:{value:r}},vertexShader:Ha(),fragmentShader:"\n\n\t\t\tprecision mediump float;\n\t\t\tprecision mediump int;\n\n\t\t\tvarying vec3 vOutputDirection;\n\n\t\t\tuniform sampler2D envMap;\n\t\t\tuniform int samples;\n\t\t\tuniform float weights[ n ];\n\t\t\tuniform bool latitudinal;\n\t\t\tuniform float dTheta;\n\t\t\tuniform float mipInt;\n\t\t\tuniform vec3 poleAxis;\n\n\t\t\t#define ENVMAP_TYPE_CUBE_UV\n\t\t\t#include \n\n\t\t\tvec3 getSample( float theta, vec3 axis ) {\n\n\t\t\t\tfloat cosTheta = cos( theta );\n\t\t\t\t// Rodrigues' axis-angle rotation\n\t\t\t\tvec3 sampleDirection = vOutputDirection * cosTheta\n\t\t\t\t\t+ cross( axis, vOutputDirection ) * sin( theta )\n\t\t\t\t\t+ axis * dot( axis, vOutputDirection ) * ( 1.0 - cosTheta );\n\n\t\t\t\treturn bilinearCubeUV( envMap, sampleDirection, mipInt );\n\n\t\t\t}\n\n\t\t\tvoid main() {\n\n\t\t\t\tvec3 axis = latitudinal ? poleAxis : cross( poleAxis, vOutputDirection );\n\n\t\t\t\tif ( all( equal( axis, vec3( 0.0 ) ) ) ) {\n\n\t\t\t\t\taxis = vec3( vOutputDirection.z, 0.0, - vOutputDirection.x );\n\n\t\t\t\t}\n\n\t\t\t\taxis = normalize( axis );\n\n\t\t\t\tgl_FragColor = vec4( 0.0, 0.0, 0.0, 1.0 );\n\t\t\t\tgl_FragColor.rgb += weights[ 0 ] * getSample( 0.0, axis );\n\n\t\t\t\tfor ( int i = 1; i < n; i++ ) {\n\n\t\t\t\t\tif ( i >= samples ) {\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tfloat theta = dTheta * float( i );\n\t\t\t\t\tgl_FragColor.rgb += weights[ i ] * getSample( -1.0 * theta, axis );\n\t\t\t\t\tgl_FragColor.rgb += weights[ i ] * getSample( theta, axis );\n\n\t\t\t\t}\n\n\t\t\t}\n\t\t",blending:0,depthTest:!1,depthWrite:!1});return s}(i,t,e)}return i}_compileMaterial(t){const e=new Vs(this._lodPlanes[0],t);this._renderer.compile(e,Aa)}_sceneToCubeUV(t,e,n,i){const r=new Qs(90,1,e,n),s=[1,-1,1,1,1,1],a=[1,1,1,-1,-1,-1],o=this._renderer,l=o.autoClear,c=o.toneMapping;o.getClearColor(Ra),o.toneMapping=K,o.autoClear=!1;const h=new Kr({name:"PMREM.Background",side:d,depthWrite:!1,depthTest:!1}),u=new Vs(new Gs,h);let p=!1;const m=t.background;m?m.isColor&&(h.color.copy(m),t.background=null,p=!0):(h.color.copy(Ra),p=!0);for(let e=0;e<6;e++){const n=e%3;0===n?(r.up.set(0,s[e],0),r.lookAt(a[e],0,0)):1===n?(r.up.set(0,0,s[e]),r.lookAt(0,a[e],0)):(r.up.set(0,s[e],0),r.lookAt(0,0,a[e]));const l=this._cubeSize;Fa(i,n*l,e>2?l:0,l,l),o.setRenderTarget(i),p&&o.render(u,r),o.render(t,r)}u.geometry.dispose(),u.material.dispose(),o.toneMapping=c,o.autoClear=l,t.background=m}_textureToCubeUV(t,e){const n=this._renderer,i=t.mapping===ot||t.mapping===lt;i?(null===this._cubemapMaterial&&(this._cubemapMaterial=za()),this._cubemapMaterial.uniforms.flipEnvMap.value=!1===t.isRenderTargetTexture?-1:1):null===this._equirectMaterial&&(this._equirectMaterial=Ba());const r=i?this._cubemapMaterial:this._equirectMaterial,s=new Vs(this._lodPlanes[0],r);r.uniforms.envMap.value=t;const a=this._cubeSize;Fa(e,0,0,3*a,2*a),n.setRenderTarget(e),n.render(s,Aa)}_applyPMREM(t){const e=this._renderer,n=e.autoClear;e.autoClear=!1;for(let e=1;ewa&&console.warn(`sigmaRadians, ${r}, is too large and will clip, as it requested ${m} samples when the maximum is set to 20`);const f=[];let g=0;for(let t=0;t_-4?i-_+4:0),4*(this._cubeSize-v),3*v,2*v),o.setRenderTarget(e),o.render(c,Aa)}}function Oa(t,e,n){const i=new bi(t,e,n);return i.texture.mapping=ut,i.texture.name="PMREM.cubeUv",i.scissorTest=!0,i}function Fa(t,e,n,i,r){t.viewport.set(e,n,i,r),t.scissor.set(e,n,i,r)}function Ba(){return new Ys({name:"EquirectangularToCubeUV",uniforms:{envMap:{value:null}},vertexShader:Ha(),fragmentShader:"\n\n\t\t\tprecision mediump float;\n\t\t\tprecision mediump int;\n\n\t\t\tvarying vec3 vOutputDirection;\n\n\t\t\tuniform sampler2D envMap;\n\n\t\t\t#include \n\n\t\t\tvoid main() {\n\n\t\t\t\tvec3 outputDirection = normalize( vOutputDirection );\n\t\t\t\tvec2 uv = equirectUv( outputDirection );\n\n\t\t\t\tgl_FragColor = vec4( texture2D ( envMap, uv ).rgb, 1.0 );\n\n\t\t\t}\n\t\t",blending:0,depthTest:!1,depthWrite:!1})}function za(){return new Ys({name:"CubemapToCubeUV",uniforms:{envMap:{value:null},flipEnvMap:{value:-1}},vertexShader:Ha(),fragmentShader:"\n\n\t\t\tprecision mediump float;\n\t\t\tprecision mediump int;\n\n\t\t\tuniform float flipEnvMap;\n\n\t\t\tvarying vec3 vOutputDirection;\n\n\t\t\tuniform samplerCube envMap;\n\n\t\t\tvoid main() {\n\n\t\t\t\tgl_FragColor = textureCube( envMap, vec3( flipEnvMap * vOutputDirection.x, vOutputDirection.yz ) );\n\n\t\t\t}\n\t\t",blending:0,depthTest:!1,depthWrite:!1})}function Ha(){return"\n\n\t\tprecision mediump float;\n\t\tprecision mediump int;\n\n\t\tattribute float faceIndex;\n\n\t\tvarying vec3 vOutputDirection;\n\n\t\t// RH coordinate system; PMREM face-indexing convention\n\t\tvec3 getDirection( vec2 uv, float face ) {\n\n\t\t\tuv = 2.0 * uv - 1.0;\n\n\t\t\tvec3 direction = vec3( uv, 1.0 );\n\n\t\t\tif ( face == 0.0 ) {\n\n\t\t\t\tdirection = direction.zyx; // ( 1, v, u ) pos x\n\n\t\t\t} else if ( face == 1.0 ) {\n\n\t\t\t\tdirection = direction.xzy;\n\t\t\t\tdirection.xz *= -1.0; // ( -u, 1, -v ) pos y\n\n\t\t\t} else if ( face == 2.0 ) {\n\n\t\t\t\tdirection.x *= -1.0; // ( -u, v, 1 ) pos z\n\n\t\t\t} else if ( face == 3.0 ) {\n\n\t\t\t\tdirection = direction.zyx;\n\t\t\t\tdirection.xz *= -1.0; // ( -1, v, -u ) neg x\n\n\t\t\t} else if ( face == 4.0 ) {\n\n\t\t\t\tdirection = direction.xzy;\n\t\t\t\tdirection.xy *= -1.0; // ( -u, -1, v ) neg y\n\n\t\t\t} else if ( face == 5.0 ) {\n\n\t\t\t\tdirection.z *= -1.0; // ( u, v, -1 ) neg z\n\n\t\t\t}\n\n\t\t\treturn direction;\n\n\t\t}\n\n\t\tvoid main() {\n\n\t\t\tvOutputDirection = getDirection( uv, faceIndex );\n\t\t\tgl_Position = vec4( position, 1.0 );\n\n\t\t}\n\t"}function Va(t){let e=new WeakMap,n=null;function i(t){const n=t.target;n.removeEventListener("dispose",i);const r=e.get(n);void 0!==r&&(e.delete(n),r.dispose())}return{get:function(r){if(r&&r.isTexture){const s=r.mapping,a=s===ct||s===ht,o=s===ot||s===lt;if(a||o){if(r.isRenderTargetTexture&&!0===r.needsPMREMUpdate){r.needsPMREMUpdate=!1;let i=e.get(r);return null===n&&(n=new Da(t)),i=a?n.fromEquirectangular(r,i):n.fromCubemap(r,i),e.set(r,i),i.texture}if(e.has(r))return e.get(r).texture;{const s=r.image;if(a&&s&&s.height>0||o&&s&&function(t){let e=0;const n=6;for(let i=0;ie.maxTextureSize&&(T=Math.ceil(E/e.maxTextureSize),E=e.maxTextureSize);const w=new Float32Array(E*T*4*p),A=new Ei(w,E,T,p);A.type=Lt,A.needsUpdate=!0;const R=4*b;for(let P=0;P0)return t;const r=e*n;let s=no[r];if(void 0===s&&(s=new Float32Array(r),no[r]=s),0!==e){i.toArray(s,0);for(let i=1,r=0;i!==e;++i)r+=n,t[i].toArray(s,r)}return s}function lo(t,e){if(t.length!==e.length)return!1;for(let n=0,i=t.length;n":" "} ${r}: ${n[t]}`)}return i.join("\n")}(t.getShaderSource(e),i)}return r}function ol(t,e){const n=function(t){const e=ui.getPrimaries(ui.workingColorSpace),n=ui.getPrimaries(t);let i;switch(e===n?i="":e===Ke&&n===Je?i="LinearDisplayP3ToLinearSRGB":e===Je&&n===Ke&&(i="LinearSRGBToLinearDisplayP3"),t){case Xe:case qe:return[i,"LinearTransferOETF"];case We:case je:return[i,"sRGBTransferOETF"];default:return console.warn("THREE.WebGLProgram: Unsupported color space:",t),[i,"LinearTransferOETF"]}}(e);return`vec4 ${t}( vec4 value ) { return ${n[0]}( ${n[1]}( value ) ); }`}function ll(t,e){let n;switch(e){case $:n="Linear";break;case Q:n="Reinhard";break;case tt:n="OptimizedCineon";break;case et:n="ACESFilmic";break;case it:n="AgX";break;case nt:n="Custom";break;default:console.warn("THREE.WebGLProgram: Unsupported toneMapping:",e),n="Linear"}return"vec3 "+t+"( vec3 color ) { return "+n+"ToneMapping( color ); }"}function cl(t){return""!==t}function hl(t,e){const n=e.numSpotLightShadows+e.numSpotLightMaps-e.numSpotLightShadowsWithMaps;return t.replace(/NUM_DIR_LIGHTS/g,e.numDirLights).replace(/NUM_SPOT_LIGHTS/g,e.numSpotLights).replace(/NUM_SPOT_LIGHT_MAPS/g,e.numSpotLightMaps).replace(/NUM_SPOT_LIGHT_COORDS/g,n).replace(/NUM_RECT_AREA_LIGHTS/g,e.numRectAreaLights).replace(/NUM_POINT_LIGHTS/g,e.numPointLights).replace(/NUM_HEMI_LIGHTS/g,e.numHemiLights).replace(/NUM_DIR_LIGHT_SHADOWS/g,e.numDirLightShadows).replace(/NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS/g,e.numSpotLightShadowsWithMaps).replace(/NUM_SPOT_LIGHT_SHADOWS/g,e.numSpotLightShadows).replace(/NUM_POINT_LIGHT_SHADOWS/g,e.numPointLightShadows)}function ul(t,e){return t.replace(/NUM_CLIPPING_PLANES/g,e.numClippingPlanes).replace(/UNION_CLIPPING_PLANES/g,e.numClippingPlanes-e.numClipIntersection)}const dl=/^[ \t]*#include +<([\w\d./]+)>/gm;function pl(t){return t.replace(dl,fl)}const ml=new Map([["encodings_fragment","colorspace_fragment"],["encodings_pars_fragment","colorspace_pars_fragment"],["output_fragment","opaque_fragment"]]);function fl(t,e){let n=ma[e];if(void 0===n){const t=ml.get(e);if(void 0===t)throw new Error("Can not resolve #include <"+e+">");n=ma[t],console.warn('THREE.WebGLRenderer: Shader chunk "%s" has been deprecated. Use "%s" instead.',e,t)}return pl(n)}const gl=/#pragma unroll_loop_start\s+for\s*\(\s*int\s+i\s*=\s*(\d+)\s*;\s*i\s*<\s*(\d+)\s*;\s*i\s*\+\+\s*\)\s*{([\s\S]+?)}\s+#pragma unroll_loop_end/g;function _l(t){return t.replace(gl,vl)}function vl(t,e,n,i){let r="";for(let t=parseInt(e);t0&&(y+="\n"),M=[g,"#define SHADER_TYPE "+n.shaderType,"#define SHADER_NAME "+n.shaderName,v].filter(cl).join("\n"),M.length>0&&(M+="\n")):(y=[xl(n),"#define SHADER_TYPE "+n.shaderType,"#define SHADER_NAME "+n.shaderName,v,n.extensionClipCullDistance?"#define USE_CLIP_DISTANCE":"",n.batching?"#define USE_BATCHING":"",n.instancing?"#define USE_INSTANCING":"",n.instancingColor?"#define USE_INSTANCING_COLOR":"",n.useFog&&n.fog?"#define USE_FOG":"",n.useFog&&n.fogExp2?"#define FOG_EXP2":"",n.map?"#define USE_MAP":"",n.envMap?"#define USE_ENVMAP":"",n.envMap?"#define "+p:"",n.lightMap?"#define USE_LIGHTMAP":"",n.aoMap?"#define USE_AOMAP":"",n.bumpMap?"#define USE_BUMPMAP":"",n.normalMap?"#define USE_NORMALMAP":"",n.normalMapObjectSpace?"#define USE_NORMALMAP_OBJECTSPACE":"",n.normalMapTangentSpace?"#define USE_NORMALMAP_TANGENTSPACE":"",n.displacementMap?"#define USE_DISPLACEMENTMAP":"",n.emissiveMap?"#define USE_EMISSIVEMAP":"",n.anisotropy?"#define USE_ANISOTROPY":"",n.anisotropyMap?"#define USE_ANISOTROPYMAP":"",n.clearcoatMap?"#define USE_CLEARCOATMAP":"",n.clearcoatRoughnessMap?"#define USE_CLEARCOAT_ROUGHNESSMAP":"",n.clearcoatNormalMap?"#define USE_CLEARCOAT_NORMALMAP":"",n.iridescenceMap?"#define USE_IRIDESCENCEMAP":"",n.iridescenceThicknessMap?"#define USE_IRIDESCENCE_THICKNESSMAP":"",n.specularMap?"#define USE_SPECULARMAP":"",n.specularColorMap?"#define USE_SPECULAR_COLORMAP":"",n.specularIntensityMap?"#define USE_SPECULAR_INTENSITYMAP":"",n.roughnessMap?"#define USE_ROUGHNESSMAP":"",n.metalnessMap?"#define USE_METALNESSMAP":"",n.alphaMap?"#define USE_ALPHAMAP":"",n.alphaHash?"#define USE_ALPHAHASH":"",n.transmission?"#define USE_TRANSMISSION":"",n.transmissionMap?"#define USE_TRANSMISSIONMAP":"",n.thicknessMap?"#define USE_THICKNESSMAP":"",n.sheenColorMap?"#define USE_SHEEN_COLORMAP":"",n.sheenRoughnessMap?"#define USE_SHEEN_ROUGHNESSMAP":"",n.mapUv?"#define MAP_UV "+n.mapUv:"",n.alphaMapUv?"#define ALPHAMAP_UV "+n.alphaMapUv:"",n.lightMapUv?"#define LIGHTMAP_UV "+n.lightMapUv:"",n.aoMapUv?"#define AOMAP_UV "+n.aoMapUv:"",n.emissiveMapUv?"#define EMISSIVEMAP_UV "+n.emissiveMapUv:"",n.bumpMapUv?"#define BUMPMAP_UV "+n.bumpMapUv:"",n.normalMapUv?"#define NORMALMAP_UV "+n.normalMapUv:"",n.displacementMapUv?"#define DISPLACEMENTMAP_UV "+n.displacementMapUv:"",n.metalnessMapUv?"#define METALNESSMAP_UV "+n.metalnessMapUv:"",n.roughnessMapUv?"#define ROUGHNESSMAP_UV "+n.roughnessMapUv:"",n.anisotropyMapUv?"#define ANISOTROPYMAP_UV "+n.anisotropyMapUv:"",n.clearcoatMapUv?"#define CLEARCOATMAP_UV "+n.clearcoatMapUv:"",n.clearcoatNormalMapUv?"#define CLEARCOAT_NORMALMAP_UV "+n.clearcoatNormalMapUv:"",n.clearcoatRoughnessMapUv?"#define CLEARCOAT_ROUGHNESSMAP_UV "+n.clearcoatRoughnessMapUv:"",n.iridescenceMapUv?"#define IRIDESCENCEMAP_UV "+n.iridescenceMapUv:"",n.iridescenceThicknessMapUv?"#define IRIDESCENCE_THICKNESSMAP_UV "+n.iridescenceThicknessMapUv:"",n.sheenColorMapUv?"#define SHEEN_COLORMAP_UV "+n.sheenColorMapUv:"",n.sheenRoughnessMapUv?"#define SHEEN_ROUGHNESSMAP_UV "+n.sheenRoughnessMapUv:"",n.specularMapUv?"#define SPECULARMAP_UV "+n.specularMapUv:"",n.specularColorMapUv?"#define SPECULAR_COLORMAP_UV "+n.specularColorMapUv:"",n.specularIntensityMapUv?"#define SPECULAR_INTENSITYMAP_UV "+n.specularIntensityMapUv:"",n.transmissionMapUv?"#define TRANSMISSIONMAP_UV "+n.transmissionMapUv:"",n.thicknessMapUv?"#define THICKNESSMAP_UV "+n.thicknessMapUv:"",n.vertexTangents&&!1===n.flatShading?"#define USE_TANGENT":"",n.vertexColors?"#define USE_COLOR":"",n.vertexAlphas?"#define USE_COLOR_ALPHA":"",n.vertexUv1s?"#define USE_UV1":"",n.vertexUv2s?"#define USE_UV2":"",n.vertexUv3s?"#define USE_UV3":"",n.pointsUvs?"#define USE_POINTS_UV":"",n.flatShading?"#define FLAT_SHADED":"",n.skinning?"#define USE_SKINNING":"",n.morphTargets?"#define USE_MORPHTARGETS":"",n.morphNormals&&!1===n.flatShading?"#define USE_MORPHNORMALS":"",n.morphColors&&n.isWebGL2?"#define USE_MORPHCOLORS":"",n.morphTargetsCount>0&&n.isWebGL2?"#define MORPHTARGETS_TEXTURE":"",n.morphTargetsCount>0&&n.isWebGL2?"#define MORPHTARGETS_TEXTURE_STRIDE "+n.morphTextureStride:"",n.morphTargetsCount>0&&n.isWebGL2?"#define MORPHTARGETS_COUNT "+n.morphTargetsCount:"",n.doubleSided?"#define DOUBLE_SIDED":"",n.flipSided?"#define FLIP_SIDED":"",n.shadowMapEnabled?"#define USE_SHADOWMAP":"",n.shadowMapEnabled?"#define "+u:"",n.sizeAttenuation?"#define USE_SIZEATTENUATION":"",n.numLightProbes>0?"#define USE_LIGHT_PROBES":"",n.useLegacyLights?"#define LEGACY_LIGHTS":"",n.logarithmicDepthBuffer?"#define USE_LOGDEPTHBUF":"",n.logarithmicDepthBuffer&&n.rendererExtensionFragDepth?"#define USE_LOGDEPTHBUF_EXT":"","uniform mat4 modelMatrix;","uniform mat4 modelViewMatrix;","uniform mat4 projectionMatrix;","uniform mat4 viewMatrix;","uniform mat3 normalMatrix;","uniform vec3 cameraPosition;","uniform bool isOrthographic;","#ifdef USE_INSTANCING","\tattribute mat4 instanceMatrix;","#endif","#ifdef USE_INSTANCING_COLOR","\tattribute vec3 instanceColor;","#endif","attribute vec3 position;","attribute vec3 normal;","attribute vec2 uv;","#ifdef USE_UV1","\tattribute vec2 uv1;","#endif","#ifdef USE_UV2","\tattribute vec2 uv2;","#endif","#ifdef USE_UV3","\tattribute vec2 uv3;","#endif","#ifdef USE_TANGENT","\tattribute vec4 tangent;","#endif","#if defined( USE_COLOR_ALPHA )","\tattribute vec4 color;","#elif defined( USE_COLOR )","\tattribute vec3 color;","#endif","#if ( defined( USE_MORPHTARGETS ) && ! defined( MORPHTARGETS_TEXTURE ) )","\tattribute vec3 morphTarget0;","\tattribute vec3 morphTarget1;","\tattribute vec3 morphTarget2;","\tattribute vec3 morphTarget3;","\t#ifdef USE_MORPHNORMALS","\t\tattribute vec3 morphNormal0;","\t\tattribute vec3 morphNormal1;","\t\tattribute vec3 morphNormal2;","\t\tattribute vec3 morphNormal3;","\t#else","\t\tattribute vec3 morphTarget4;","\t\tattribute vec3 morphTarget5;","\t\tattribute vec3 morphTarget6;","\t\tattribute vec3 morphTarget7;","\t#endif","#endif","#ifdef USE_SKINNING","\tattribute vec4 skinIndex;","\tattribute vec4 skinWeight;","#endif","\n"].filter(cl).join("\n"),M=[g,xl(n),"#define SHADER_TYPE "+n.shaderType,"#define SHADER_NAME "+n.shaderName,v,n.useFog&&n.fog?"#define USE_FOG":"",n.useFog&&n.fogExp2?"#define FOG_EXP2":"",n.alphaToCoverage?"#define ALPHA_TO_COVERAGE":"",n.map?"#define USE_MAP":"",n.matcap?"#define USE_MATCAP":"",n.envMap?"#define USE_ENVMAP":"",n.envMap?"#define "+d:"",n.envMap?"#define "+p:"",n.envMap?"#define "+m:"",f?"#define CUBEUV_TEXEL_WIDTH "+f.texelWidth:"",f?"#define CUBEUV_TEXEL_HEIGHT "+f.texelHeight:"",f?"#define CUBEUV_MAX_MIP "+f.maxMip+".0":"",n.lightMap?"#define USE_LIGHTMAP":"",n.aoMap?"#define USE_AOMAP":"",n.bumpMap?"#define USE_BUMPMAP":"",n.normalMap?"#define USE_NORMALMAP":"",n.normalMapObjectSpace?"#define USE_NORMALMAP_OBJECTSPACE":"",n.normalMapTangentSpace?"#define USE_NORMALMAP_TANGENTSPACE":"",n.emissiveMap?"#define USE_EMISSIVEMAP":"",n.anisotropy?"#define USE_ANISOTROPY":"",n.anisotropyMap?"#define USE_ANISOTROPYMAP":"",n.clearcoat?"#define USE_CLEARCOAT":"",n.clearcoatMap?"#define USE_CLEARCOATMAP":"",n.clearcoatRoughnessMap?"#define USE_CLEARCOAT_ROUGHNESSMAP":"",n.clearcoatNormalMap?"#define USE_CLEARCOAT_NORMALMAP":"",n.iridescence?"#define USE_IRIDESCENCE":"",n.iridescenceMap?"#define USE_IRIDESCENCEMAP":"",n.iridescenceThicknessMap?"#define USE_IRIDESCENCE_THICKNESSMAP":"",n.specularMap?"#define USE_SPECULARMAP":"",n.specularColorMap?"#define USE_SPECULAR_COLORMAP":"",n.specularIntensityMap?"#define USE_SPECULAR_INTENSITYMAP":"",n.roughnessMap?"#define USE_ROUGHNESSMAP":"",n.metalnessMap?"#define USE_METALNESSMAP":"",n.alphaMap?"#define USE_ALPHAMAP":"",n.alphaTest?"#define USE_ALPHATEST":"",n.alphaHash?"#define USE_ALPHAHASH":"",n.sheen?"#define USE_SHEEN":"",n.sheenColorMap?"#define USE_SHEEN_COLORMAP":"",n.sheenRoughnessMap?"#define USE_SHEEN_ROUGHNESSMAP":"",n.transmission?"#define USE_TRANSMISSION":"",n.transmissionMap?"#define USE_TRANSMISSIONMAP":"",n.thicknessMap?"#define USE_THICKNESSMAP":"",n.vertexTangents&&!1===n.flatShading?"#define USE_TANGENT":"",n.vertexColors||n.instancingColor?"#define USE_COLOR":"",n.vertexAlphas?"#define USE_COLOR_ALPHA":"",n.vertexUv1s?"#define USE_UV1":"",n.vertexUv2s?"#define USE_UV2":"",n.vertexUv3s?"#define USE_UV3":"",n.pointsUvs?"#define USE_POINTS_UV":"",n.gradientMap?"#define USE_GRADIENTMAP":"",n.flatShading?"#define FLAT_SHADED":"",n.doubleSided?"#define DOUBLE_SIDED":"",n.flipSided?"#define FLIP_SIDED":"",n.shadowMapEnabled?"#define USE_SHADOWMAP":"",n.shadowMapEnabled?"#define "+u:"",n.premultipliedAlpha?"#define PREMULTIPLIED_ALPHA":"",n.numLightProbes>0?"#define USE_LIGHT_PROBES":"",n.useLegacyLights?"#define LEGACY_LIGHTS":"",n.decodeVideoTexture?"#define DECODE_VIDEO_TEXTURE":"",n.logarithmicDepthBuffer?"#define USE_LOGDEPTHBUF":"",n.logarithmicDepthBuffer&&n.rendererExtensionFragDepth?"#define USE_LOGDEPTHBUF_EXT":"","uniform mat4 viewMatrix;","uniform vec3 cameraPosition;","uniform bool isOrthographic;",n.toneMapping!==K?"#define TONE_MAPPING":"",n.toneMapping!==K?ma.tonemapping_pars_fragment:"",n.toneMapping!==K?ll("toneMapping",n.toneMapping):"",n.dithering?"#define DITHERING":"",n.opaque?"#define OPAQUE":"",ma.colorspace_pars_fragment,ol("linearToOutputTexel",n.outputColorSpace),n.useDepthPacking?"#define DEPTH_PACKING "+n.depthPacking:"","\n"].filter(cl).join("\n")),a=pl(a),a=hl(a,n),a=ul(a,n),o=pl(o),o=hl(o,n),o=ul(o,n),a=_l(a),o=_l(o),n.isWebGL2&&!0!==n.isRawShaderMaterial&&(S="#version 300 es\n",y=[_,"precision mediump sampler2DArray;","#define attribute in","#define varying out","#define texture2D texture"].join("\n")+"\n"+y,M=["precision mediump sampler2DArray;","#define varying in",n.glslVersion===Un?"":"layout(location = 0) out highp vec4 pc_fragColor;",n.glslVersion===Un?"":"#define gl_FragColor pc_fragColor","#define gl_FragDepthEXT gl_FragDepth","#define texture2D texture","#define textureCube texture","#define texture2DProj textureProj","#define texture2DLodEXT textureLod","#define texture2DProjLodEXT textureProjLod","#define textureCubeLodEXT textureLod","#define texture2DGradEXT textureGrad","#define texture2DProjGradEXT textureProjGrad","#define textureCubeGradEXT textureGrad"].join("\n")+"\n"+M);const b=S+y+a,E=S+M+o,T=il(r,r.VERTEX_SHADER,b),w=il(r,r.FRAGMENT_SHADER,E);function A(e){if(t.debug.checkShaderErrors){const n=r.getProgramInfoLog(x).trim(),i=r.getShaderInfoLog(T).trim(),s=r.getShaderInfoLog(w).trim();let a=!0,o=!0;if(!1===r.getProgramParameter(x,r.LINK_STATUS))if(a=!1,"function"==typeof t.debug.onShaderError)t.debug.onShaderError(r,x,T,w);else{const t=al(r,T,"vertex"),i=al(r,w,"fragment");console.error("THREE.WebGLProgram: Shader Error "+r.getError()+" - VALIDATE_STATUS "+r.getProgramParameter(x,r.VALIDATE_STATUS)+"\n\nMaterial Name: "+e.name+"\nMaterial Type: "+e.type+"\n\nProgram Info Log: "+n+"\n"+t+"\n"+i)}else""!==n?console.warn("THREE.WebGLProgram: Program Info Log:",n):""!==i&&""!==s||(o=!1);o&&(e.diagnostics={runnable:a,programLog:n,vertexShader:{log:i,prefix:y},fragmentShader:{log:s,prefix:M}})}r.deleteShader(T),r.deleteShader(w),R=new nl(r,x),C=function(t,e){const n={},i=t.getProgramParameter(e,t.ACTIVE_ATTRIBUTES);for(let r=0;r0,Y=s.clearcoat>0,Z=s.iridescence>0,J=s.sheen>0,$=s.transmission>0,Q=q&&!!s.anisotropyMap,tt=Y&&!!s.clearcoatMap,et=Y&&!!s.clearcoatNormalMap,nt=Y&&!!s.clearcoatRoughnessMap,it=Z&&!!s.iridescenceMap,rt=Z&&!!s.iridescenceThicknessMap,st=J&&!!s.sheenColorMap,at=J&&!!s.sheenRoughnessMap,ot=!!s.specularMap,lt=!!s.specularColorMap,ct=!!s.specularIntensityMap,ht=$&&!!s.transmissionMap,dt=$&&!!s.thicknessMap,pt=!!s.gradientMap,mt=!!s.alphaMap,ft=s.alphaTest>0,gt=!!s.alphaHash,_t=!!s.extensions;let vt=K;s.toneMapped&&(null!==U&&!0!==U.isXRRenderTarget||(vt=t.toneMapping));const xt={isWebGL2:u,shaderID:T,shaderType:s.type,shaderName:s.name,vertexShader:R,fragmentShader:C,defines:s.defines,customVertexShaderID:P,customFragmentShaderID:L,isRawShaderMaterial:!0===s.isRawShaderMaterial,glslVersion:s.glslVersion,precision:f,batching:D,instancing:N,instancingColor:N&&null!==x.instanceColor,supportsVertexTextures:m,outputColorSpace:null===U?t.outputColorSpace:!0===U.isXRRenderTarget?U.texture.colorSpace:Xe,alphaToCoverage:!!s.alphaToCoverage,map:O,matcap:F,envMap:B,envMapMode:B&&b.mapping,envMapCubeUVHeight:E,aoMap:z,lightMap:H,bumpMap:V,normalMap:k,displacementMap:m&&G,emissiveMap:W,normalMapObjectSpace:k&&1===s.normalMapType,normalMapTangentSpace:k&&0===s.normalMapType,metalnessMap:X,roughnessMap:j,anisotropy:q,anisotropyMap:Q,clearcoat:Y,clearcoatMap:tt,clearcoatNormalMap:et,clearcoatRoughnessMap:nt,iridescence:Z,iridescenceMap:it,iridescenceThicknessMap:rt,sheen:J,sheenColorMap:st,sheenRoughnessMap:at,specularMap:ot,specularColorMap:lt,specularIntensityMap:ct,transmission:$,transmissionMap:ht,thicknessMap:dt,gradientMap:pt,opaque:!1===s.transparent&&1===s.blending&&!1===s.alphaToCoverage,alphaMap:mt,alphaTest:ft,alphaHash:gt,combine:s.combine,mapUv:O&&_(s.map.channel),aoMapUv:z&&_(s.aoMap.channel),lightMapUv:H&&_(s.lightMap.channel),bumpMapUv:V&&_(s.bumpMap.channel),normalMapUv:k&&_(s.normalMap.channel),displacementMapUv:G&&_(s.displacementMap.channel),emissiveMapUv:W&&_(s.emissiveMap.channel),metalnessMapUv:X&&_(s.metalnessMap.channel),roughnessMapUv:j&&_(s.roughnessMap.channel),anisotropyMapUv:Q&&_(s.anisotropyMap.channel),clearcoatMapUv:tt&&_(s.clearcoatMap.channel),clearcoatNormalMapUv:et&&_(s.clearcoatNormalMap.channel),clearcoatRoughnessMapUv:nt&&_(s.clearcoatRoughnessMap.channel),iridescenceMapUv:it&&_(s.iridescenceMap.channel),iridescenceThicknessMapUv:rt&&_(s.iridescenceThicknessMap.channel),sheenColorMapUv:st&&_(s.sheenColorMap.channel),sheenRoughnessMapUv:at&&_(s.sheenRoughnessMap.channel),specularMapUv:ot&&_(s.specularMap.channel),specularColorMapUv:lt&&_(s.specularColorMap.channel),specularIntensityMapUv:ct&&_(s.specularIntensityMap.channel),transmissionMapUv:ht&&_(s.transmissionMap.channel),thicknessMapUv:dt&&_(s.thicknessMap.channel),alphaMapUv:mt&&_(s.alphaMap.channel),vertexTangents:!!M.attributes.tangent&&(k||q),vertexColors:s.vertexColors,vertexAlphas:!0===s.vertexColors&&!!M.attributes.color&&4===M.attributes.color.itemSize,pointsUvs:!0===x.isPoints&&!!M.attributes.uv&&(O||mt),fog:!!y,useFog:!0===s.fog,fogExp2:!!y&&y.isFogExp2,flatShading:!0===s.flatShading,sizeAttenuation:!0===s.sizeAttenuation,logarithmicDepthBuffer:p,skinning:!0===x.isSkinnedMesh,morphTargets:void 0!==M.morphAttributes.position,morphNormals:void 0!==M.morphAttributes.normal,morphColors:void 0!==M.morphAttributes.color,morphTargetsCount:A,morphTextureStride:I,numDirLights:o.directional.length,numPointLights:o.point.length,numSpotLights:o.spot.length,numSpotLightMaps:o.spotLightMap.length,numRectAreaLights:o.rectArea.length,numHemiLights:o.hemi.length,numDirLightShadows:o.directionalShadowMap.length,numPointLightShadows:o.pointShadowMap.length,numSpotLightShadows:o.spotShadowMap.length,numSpotLightShadowsWithMaps:o.numSpotLightShadowsWithMaps,numLightProbes:o.numLightProbes,numClippingPlanes:a.numPlanes,numClipIntersection:a.numIntersection,dithering:s.dithering,shadowMapEnabled:t.shadowMap.enabled&&h.length>0,shadowMapType:t.shadowMap.type,toneMapping:vt,useLegacyLights:t._useLegacyLights,decodeVideoTexture:O&&!0===s.map.isVideoTexture&&ui.getTransfer(s.map.colorSpace)===Ze,premultipliedAlpha:s.premultipliedAlpha,doubleSided:2===s.side,flipSided:s.side===d,useDepthPacking:s.depthPacking>=0,depthPacking:s.depthPacking||0,index0AttributeName:s.index0AttributeName,extensionDerivatives:_t&&!0===s.extensions.derivatives,extensionFragDepth:_t&&!0===s.extensions.fragDepth,extensionDrawBuffers:_t&&!0===s.extensions.drawBuffers,extensionShaderTextureLOD:_t&&!0===s.extensions.shaderTextureLOD,extensionClipCullDistance:_t&&!0===s.extensions.clipCullDistance&&i.has("WEBGL_clip_cull_distance"),extensionMultiDraw:_t&&!0===s.extensions.multiDraw&&i.has("WEBGL_multi_draw"),rendererExtensionFragDepth:u||i.has("EXT_frag_depth"),rendererExtensionDrawBuffers:u||i.has("WEBGL_draw_buffers"),rendererExtensionShaderTextureLod:u||i.has("EXT_shader_texture_lod"),rendererExtensionParallelShaderCompile:i.has("KHR_parallel_shader_compile"),customProgramCacheKey:s.customProgramCacheKey()};return xt.vertexUv1s=c.has(1),xt.vertexUv2s=c.has(2),xt.vertexUv3s=c.has(3),c.clear(),xt},getProgramCacheKey:function(e){const n=[];if(e.shaderID?n.push(e.shaderID):(n.push(e.customVertexShaderID),n.push(e.customFragmentShaderID)),void 0!==e.defines)for(const t in e.defines)n.push(t),n.push(e.defines[t]);return!1===e.isRawShaderMaterial&&(!function(t,e){t.push(e.precision),t.push(e.outputColorSpace),t.push(e.envMapMode),t.push(e.envMapCubeUVHeight),t.push(e.mapUv),t.push(e.alphaMapUv),t.push(e.lightMapUv),t.push(e.aoMapUv),t.push(e.bumpMapUv),t.push(e.normalMapUv),t.push(e.displacementMapUv),t.push(e.emissiveMapUv),t.push(e.metalnessMapUv),t.push(e.roughnessMapUv),t.push(e.anisotropyMapUv),t.push(e.clearcoatMapUv),t.push(e.clearcoatNormalMapUv),t.push(e.clearcoatRoughnessMapUv),t.push(e.iridescenceMapUv),t.push(e.iridescenceThicknessMapUv),t.push(e.sheenColorMapUv),t.push(e.sheenRoughnessMapUv),t.push(e.specularMapUv),t.push(e.specularColorMapUv),t.push(e.specularIntensityMapUv),t.push(e.transmissionMapUv),t.push(e.thicknessMapUv),t.push(e.combine),t.push(e.fogExp2),t.push(e.sizeAttenuation),t.push(e.morphTargetsCount),t.push(e.morphAttributeCount),t.push(e.numDirLights),t.push(e.numPointLights),t.push(e.numSpotLights),t.push(e.numSpotLightMaps),t.push(e.numHemiLights),t.push(e.numRectAreaLights),t.push(e.numDirLightShadows),t.push(e.numPointLightShadows),t.push(e.numSpotLightShadows),t.push(e.numSpotLightShadowsWithMaps),t.push(e.numLightProbes),t.push(e.shadowMapType),t.push(e.toneMapping),t.push(e.numClippingPlanes),t.push(e.numClipIntersection),t.push(e.depthPacking)}(n,e),function(t,e){o.disableAll(),e.isWebGL2&&o.enable(0);e.supportsVertexTextures&&o.enable(1);e.instancing&&o.enable(2);e.instancingColor&&o.enable(3);e.matcap&&o.enable(4);e.envMap&&o.enable(5);e.normalMapObjectSpace&&o.enable(6);e.normalMapTangentSpace&&o.enable(7);e.clearcoat&&o.enable(8);e.iridescence&&o.enable(9);e.alphaTest&&o.enable(10);e.vertexColors&&o.enable(11);e.vertexAlphas&&o.enable(12);e.vertexUv1s&&o.enable(13);e.vertexUv2s&&o.enable(14);e.vertexUv3s&&o.enable(15);e.vertexTangents&&o.enable(16);e.anisotropy&&o.enable(17);e.alphaHash&&o.enable(18);e.batching&&o.enable(19);t.push(o.mask),o.disableAll(),e.fog&&o.enable(0);e.useFog&&o.enable(1);e.flatShading&&o.enable(2);e.logarithmicDepthBuffer&&o.enable(3);e.skinning&&o.enable(4);e.morphTargets&&o.enable(5);e.morphNormals&&o.enable(6);e.morphColors&&o.enable(7);e.premultipliedAlpha&&o.enable(8);e.shadowMapEnabled&&o.enable(9);e.useLegacyLights&&o.enable(10);e.doubleSided&&o.enable(11);e.flipSided&&o.enable(12);e.useDepthPacking&&o.enable(13);e.dithering&&o.enable(14);e.transmission&&o.enable(15);e.sheen&&o.enable(16);e.opaque&&o.enable(17);e.pointsUvs&&o.enable(18);e.decodeVideoTexture&&o.enable(19);e.alphaToCoverage&&o.enable(20);t.push(o.mask)}(n,e),n.push(t.outputColorSpace)),n.push(e.customProgramCacheKey),n.join()},getUniforms:function(t){const e=g[t.type];let n;if(e){const t=ga[e];n=qs.clone(t.uniforms)}else n=t.uniforms;return n},acquireProgram:function(e,n){let i;for(let t=0,e=h.length;t0?i.push(h):!0===a.transparent?r.push(h):n.push(h)},unshift:function(t,e,a,o,l,c){const h=s(t,e,a,o,l,c);a.transmission>0?i.unshift(h):!0===a.transparent?r.unshift(h):n.unshift(h)},finish:function(){for(let n=e,i=t.length;n1&&n.sort(t||wl),i.length>1&&i.sort(e||Al),r.length>1&&r.sort(e||Al)}}}function Cl(){let t=new WeakMap;return{get:function(e,n){const i=t.get(e);let r;return void 0===i?(r=new Rl,t.set(e,[r])):n>=i.length?(r=new Rl,i.push(r)):r=i[n],r},dispose:function(){t=new WeakMap}}}function Pl(){const t={};return{get:function(e){if(void 0!==t[e.id])return t[e.id];let n;switch(e.type){case"DirectionalLight":n={direction:new Pi,color:new qr};break;case"SpotLight":n={position:new Pi,direction:new Pi,color:new qr,distance:0,coneCos:0,penumbraCos:0,decay:0};break;case"PointLight":n={position:new Pi,color:new qr,distance:0,decay:0};break;case"HemisphereLight":n={direction:new Pi,skyColor:new qr,groundColor:new qr};break;case"RectAreaLight":n={color:new qr,position:new Pi,halfWidth:new Pi,halfHeight:new Pi}}return t[e.id]=n,n}}}let Ll=0;function Il(t,e){return(e.castShadow?2:0)-(t.castShadow?2:0)+(e.map?1:0)-(t.map?1:0)}function Ul(t,e){const n=new Pl,i=function(){const t={};return{get:function(e){if(void 0!==t[e.id])return t[e.id];let n;switch(e.type){case"DirectionalLight":case"SpotLight":n={shadowBias:0,shadowNormalBias:0,shadowRadius:1,shadowMapSize:new Kn};break;case"PointLight":n={shadowBias:0,shadowNormalBias:0,shadowRadius:1,shadowMapSize:new Kn,shadowCameraNear:1,shadowCameraFar:1e3}}return t[e.id]=n,n}}}(),r={version:0,hash:{directionalLength:-1,pointLength:-1,spotLength:-1,rectAreaLength:-1,hemiLength:-1,numDirectionalShadows:-1,numPointShadows:-1,numSpotShadows:-1,numSpotMaps:-1,numLightProbes:-1},ambient:[0,0,0],probe:[],directional:[],directionalShadow:[],directionalShadowMap:[],directionalShadowMatrix:[],spot:[],spotLightMap:[],spotShadow:[],spotShadowMap:[],spotLightMatrix:[],rectArea:[],rectAreaLTC1:null,rectAreaLTC2:null,point:[],pointShadow:[],pointShadowMap:[],pointShadowMatrix:[],hemi:[],numSpotLightShadowsWithMaps:0,numLightProbes:0};for(let t=0;t<9;t++)r.probe.push(new Pi);const s=new Pi,a=new ar,o=new ar;return{setup:function(s,a){let o=0,l=0,c=0;for(let t=0;t<9;t++)r.probe[t].set(0,0,0);let h=0,u=0,d=0,p=0,m=0,f=0,g=0,_=0,v=0,x=0,y=0;s.sort(Il);const M=!0===a?Math.PI:1;for(let t=0,e=s.length;t0&&(e.isWebGL2?!0===t.has("OES_texture_float_linear")?(r.rectAreaLTC1=fa.LTC_FLOAT_1,r.rectAreaLTC2=fa.LTC_FLOAT_2):(r.rectAreaLTC1=fa.LTC_HALF_1,r.rectAreaLTC2=fa.LTC_HALF_2):!0===t.has("OES_texture_float_linear")?(r.rectAreaLTC1=fa.LTC_FLOAT_1,r.rectAreaLTC2=fa.LTC_FLOAT_2):!0===t.has("OES_texture_half_float_linear")?(r.rectAreaLTC1=fa.LTC_HALF_1,r.rectAreaLTC2=fa.LTC_HALF_2):console.error("THREE.WebGLRenderer: Unable to use RectAreaLight. Missing WebGL extensions.")),r.ambient[0]=o,r.ambient[1]=l,r.ambient[2]=c;const S=r.hash;S.directionalLength===h&&S.pointLength===u&&S.spotLength===d&&S.rectAreaLength===p&&S.hemiLength===m&&S.numDirectionalShadows===f&&S.numPointShadows===g&&S.numSpotShadows===_&&S.numSpotMaps===v&&S.numLightProbes===y||(r.directional.length=h,r.spot.length=d,r.rectArea.length=p,r.point.length=u,r.hemi.length=m,r.directionalShadow.length=f,r.directionalShadowMap.length=f,r.pointShadow.length=g,r.pointShadowMap.length=g,r.spotShadow.length=_,r.spotShadowMap.length=_,r.directionalShadowMatrix.length=f,r.pointShadowMatrix.length=g,r.spotLightMatrix.length=_+v-x,r.spotLightMap.length=v,r.numSpotLightShadowsWithMaps=x,r.numLightProbes=y,S.directionalLength=h,S.pointLength=u,S.spotLength=d,S.rectAreaLength=p,S.hemiLength=m,S.numDirectionalShadows=f,S.numPointShadows=g,S.numSpotShadows=_,S.numSpotMaps=v,S.numLightProbes=y,r.version=Ll++)},setupView:function(t,e){let n=0,i=0,l=0,c=0,h=0;const u=e.matrixWorldInverse;for(let e=0,d=t.length;e=s.length?(a=new Nl(t,e),s.push(a)):a=s[r],a},dispose:function(){n=new WeakMap}}}class Ol extends Jr{constructor(t){super(),this.isMeshDepthMaterial=!0,this.type="MeshDepthMaterial",this.depthPacking=3200,this.map=null,this.alphaMap=null,this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.wireframe=!1,this.wireframeLinewidth=1,this.setValues(t)}copy(t){return super.copy(t),this.depthPacking=t.depthPacking,this.map=t.map,this.alphaMap=t.alphaMap,this.displacementMap=t.displacementMap,this.displacementScale=t.displacementScale,this.displacementBias=t.displacementBias,this.wireframe=t.wireframe,this.wireframeLinewidth=t.wireframeLinewidth,this}}class Fl extends Jr{constructor(t){super(),this.isMeshDistanceMaterial=!0,this.type="MeshDistanceMaterial",this.map=null,this.alphaMap=null,this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.setValues(t)}copy(t){return super.copy(t),this.map=t.map,this.alphaMap=t.alphaMap,this.displacementMap=t.displacementMap,this.displacementScale=t.displacementScale,this.displacementBias=t.displacementBias,this}}function Bl(t,e,n){let i=new ha;const r=new Kn,s=new Kn,a=new Mi,o=new Ol({depthPacking:3201}),c=new Fl,p={},m=n.maxTextureSize,f={[u]:d,[d]:u,2:2},g=new Ys({defines:{VSM_SAMPLES:8},uniforms:{shadow_pass:{value:null},resolution:{value:new Kn},radius:{value:4}},vertexShader:"void main() {\n\tgl_Position = vec4( position, 1.0 );\n}",fragmentShader:"uniform sampler2D shadow_pass;\nuniform vec2 resolution;\nuniform float radius;\n#include \nvoid main() {\n\tconst float samples = float( VSM_SAMPLES );\n\tfloat mean = 0.0;\n\tfloat squared_mean = 0.0;\n\tfloat uvStride = samples <= 1.0 ? 0.0 : 2.0 / ( samples - 1.0 );\n\tfloat uvStart = samples <= 1.0 ? 0.0 : - 1.0;\n\tfor ( float i = 0.0; i < samples; i ++ ) {\n\t\tfloat uvOffset = uvStart + i * uvStride;\n\t\t#ifdef HORIZONTAL_PASS\n\t\t\tvec2 distribution = unpackRGBATo2Half( texture2D( shadow_pass, ( gl_FragCoord.xy + vec2( uvOffset, 0.0 ) * radius ) / resolution ) );\n\t\t\tmean += distribution.x;\n\t\t\tsquared_mean += distribution.y * distribution.y + distribution.x * distribution.x;\n\t\t#else\n\t\t\tfloat depth = unpackRGBAToDepth( texture2D( shadow_pass, ( gl_FragCoord.xy + vec2( 0.0, uvOffset ) * radius ) / resolution ) );\n\t\t\tmean += depth;\n\t\t\tsquared_mean += depth * depth;\n\t\t#endif\n\t}\n\tmean = mean / samples;\n\tsquared_mean = squared_mean / samples;\n\tfloat std_dev = sqrt( squared_mean - mean * mean );\n\tgl_FragColor = pack2HalfToRGBA( vec2( mean, std_dev ) );\n}"}),_=g.clone();_.defines.HORIZONTAL_PASS=1;const v=new bs;v.setAttribute("position",new ss(new Float32Array([-1,-1,.5,3,-1,.5,-1,3,.5]),3));const x=new Vs(v,g),y=this;this.enabled=!1,this.autoUpdate=!0,this.needsUpdate=!1,this.type=l;let M=this.type;function S(n,i){const s=e.update(x);g.defines.VSM_SAMPLES!==n.blurSamples&&(g.defines.VSM_SAMPLES=n.blurSamples,_.defines.VSM_SAMPLES=n.blurSamples,g.needsUpdate=!0,_.needsUpdate=!0),null===n.mapPass&&(n.mapPass=new bi(r.x,r.y)),g.uniforms.shadow_pass.value=n.map.texture,g.uniforms.resolution.value=n.mapSize,g.uniforms.radius.value=n.radius,t.setRenderTarget(n.mapPass),t.clear(),t.renderBufferDirect(i,null,s,g,x,null),_.uniforms.shadow_pass.value=n.mapPass.texture,_.uniforms.resolution.value=n.mapSize,_.uniforms.radius.value=n.radius,t.setRenderTarget(n.map),t.clear(),t.renderBufferDirect(i,null,s,_,x,null)}function b(e,n,i,r){let s=null;const a=!0===i.isPointLight?e.customDistanceMaterial:e.customDepthMaterial;if(void 0!==a)s=a;else if(s=!0===i.isPointLight?c:o,t.localClippingEnabled&&!0===n.clipShadows&&Array.isArray(n.clippingPlanes)&&0!==n.clippingPlanes.length||n.displacementMap&&0!==n.displacementScale||n.alphaMap&&n.alphaTest>0||n.map&&n.alphaTest>0){const t=s.uuid,e=n.uuid;let i=p[t];void 0===i&&(i={},p[t]=i);let r=i[e];void 0===r&&(r=s.clone(),i[e]=r,n.addEventListener("dispose",T)),s=r}if(s.visible=n.visible,s.wireframe=n.wireframe,s.side=r===h?null!==n.shadowSide?n.shadowSide:n.side:null!==n.shadowSide?n.shadowSide:f[n.side],s.alphaMap=n.alphaMap,s.alphaTest=n.alphaTest,s.map=n.map,s.clipShadows=n.clipShadows,s.clippingPlanes=n.clippingPlanes,s.clipIntersection=n.clipIntersection,s.displacementMap=n.displacementMap,s.displacementScale=n.displacementScale,s.displacementBias=n.displacementBias,s.wireframeLinewidth=n.wireframeLinewidth,s.linewidth=n.linewidth,!0===i.isPointLight&&!0===s.isMeshDistanceMaterial){t.properties.get(s).light=i}return s}function E(n,r,s,a,o){if(!1===n.visible)return;if(n.layers.test(r.layers)&&(n.isMesh||n.isLine||n.isPoints)&&(n.castShadow||n.receiveShadow&&o===h)&&(!n.frustumCulled||i.intersectsObject(n))){n.modelViewMatrix.multiplyMatrices(s.matrixWorldInverse,n.matrixWorld);const i=e.update(n),l=n.material;if(Array.isArray(l)){const e=i.groups;for(let c=0,h=e.length;cm||r.y>m)&&(r.x>m&&(s.x=Math.floor(m/g.x),r.x=s.x*g.x,u.mapSize.x=s.x),r.y>m&&(s.y=Math.floor(m/g.y),r.y=s.y*g.y,u.mapSize.y=s.y)),null===u.map||!0===p||!0===f){const t=this.type!==h?{minFilter:ft,magFilter:ft}:{};null!==u.map&&u.map.dispose(),u.map=new bi(r.x,r.y,t),u.map.texture.name=c.name+".shadowMap",u.camera.updateProjectionMatrix()}t.setRenderTarget(u.map),t.clear();const _=u.getViewportCount();for(let t=0;t<_;t++){const e=u.getViewport(t);a.set(s.x*e.x,s.y*e.y,s.x*e.z,s.y*e.w),d.viewport(a),u.updateMatrices(c,t),i=u.getFrustum(),E(n,o,u.camera,c,this.type)}!0!==u.isPointLightShadow&&this.type===h&&S(u,o),u.needsUpdate=!1}M=this.type,y.needsUpdate=!1,t.setRenderTarget(l,c,u)}}function zl(t,e,n){const i=n.isWebGL2;const r=new function(){let e=!1;const n=new Mi;let i=null;const r=new Mi(0,0,0,0);return{setMask:function(n){i===n||e||(t.colorMask(n,n,n,n),i=n)},setLocked:function(t){e=t},setClear:function(e,i,s,a,o){!0===o&&(e*=a,i*=a,s*=a),n.set(e,i,s,a),!1===r.equals(n)&&(t.clearColor(e,i,s,a),r.copy(n))},reset:function(){e=!1,i=null,r.set(-1,0,0,0)}}},s=new function(){let e=!1,n=null,i=null,r=null;return{setTest:function(e){e?j(t.DEPTH_TEST):q(t.DEPTH_TEST)},setMask:function(i){n===i||e||(t.depthMask(i),n=i)},setFunc:function(e){if(i!==e){switch(e){case 0:t.depthFunc(t.NEVER);break;case 1:t.depthFunc(t.ALWAYS);break;case 2:t.depthFunc(t.LESS);break;case 3:default:t.depthFunc(t.LEQUAL);break;case 4:t.depthFunc(t.EQUAL);break;case 5:t.depthFunc(t.GEQUAL);break;case 6:t.depthFunc(t.GREATER);break;case 7:t.depthFunc(t.NOTEQUAL)}i=e}},setLocked:function(t){e=t},setClear:function(e){r!==e&&(t.clearDepth(e),r=e)},reset:function(){e=!1,n=null,i=null,r=null}}},a=new function(){let e=!1,n=null,i=null,r=null,s=null,a=null,o=null,l=null,c=null;return{setTest:function(n){e||(n?j(t.STENCIL_TEST):q(t.STENCIL_TEST))},setMask:function(i){n===i||e||(t.stencilMask(i),n=i)},setFunc:function(e,n,a){i===e&&r===n&&s===a||(t.stencilFunc(e,n,a),i=e,r=n,s=a)},setOp:function(e,n,i){a===e&&o===n&&l===i||(t.stencilOp(e,n,i),a=e,o=n,l=i)},setLocked:function(t){e=t},setClear:function(e){c!==e&&(t.clearStencil(e),c=e)},reset:function(){e=!1,n=null,i=null,r=null,s=null,a=null,o=null,l=null,c=null}}},o=new WeakMap,l=new WeakMap;let c={},h={},u=new WeakMap,p=[],m=null,f=!1,g=null,_=null,v=null,x=null,M=null,S=null,b=null,E=new qr(0,0,0),T=0,w=!1,A=null,R=null,L=null,I=null,U=null;const N=t.getParameter(t.MAX_COMBINED_TEXTURE_IMAGE_UNITS);let D=!1,O=0;const F=t.getParameter(t.VERSION);-1!==F.indexOf("WebGL")?(O=parseFloat(/^WebGL (\d)/.exec(F)[1]),D=O>=1):-1!==F.indexOf("OpenGL ES")&&(O=parseFloat(/^OpenGL ES (\d)/.exec(F)[1]),D=O>=2);let B=null,z={};const H=t.getParameter(t.SCISSOR_BOX),V=t.getParameter(t.VIEWPORT),k=(new Mi).fromArray(H),G=(new Mi).fromArray(V);function W(e,n,r,s){const a=new Uint8Array(4),o=t.createTexture();t.bindTexture(e,o),t.texParameteri(e,t.TEXTURE_MIN_FILTER,t.NEAREST),t.texParameteri(e,t.TEXTURE_MAG_FILTER,t.NEAREST);for(let o=0;oi||t.height>i)&&(r=i/Math.max(t.width,t.height)),r<1||!0===e){if("undefined"!=typeof HTMLImageElement&&t instanceof HTMLImageElement||"undefined"!=typeof HTMLCanvasElement&&t instanceof HTMLCanvasElement||"undefined"!=typeof ImageBitmap&&t instanceof ImageBitmap){const i=e?qn:Math.floor,s=i(r*t.width),a=i(r*t.height);void 0===u&&(u=m(s,a));const o=n?m(s,a):u;o.width=s,o.height=a;return o.getContext("2d").drawImage(t,0,0,s,a),console.warn("THREE.WebGLRenderer: Texture has been resized from ("+t.width+"x"+t.height+") to ("+s+"x"+a+")."),o}return"data"in t&&console.warn("THREE.WebGLRenderer: Image in DataTexture is too big ("+t.width+"x"+t.height+")."),t}return t}function g(t){return jn(t.width)&&jn(t.height)}function _(t,e){return t.generateMipmaps&&e&&t.minFilter!==ft&&t.minFilter!==yt}function v(e){t.generateMipmap(e)}function x(n,i,r,s,a=!1){if(!1===o)return i;if(null!==n){if(void 0!==t[n])return t[n];console.warn("THREE.WebGLRenderer: Attempt to use non-existing WebGL internal format '"+n+"'")}let l=i;if(i===t.RED&&(r===t.FLOAT&&(l=t.R32F),r===t.HALF_FLOAT&&(l=t.R16F),r===t.UNSIGNED_BYTE&&(l=t.R8)),i===t.RED_INTEGER&&(r===t.UNSIGNED_BYTE&&(l=t.R8UI),r===t.UNSIGNED_SHORT&&(l=t.R16UI),r===t.UNSIGNED_INT&&(l=t.R32UI),r===t.BYTE&&(l=t.R8I),r===t.SHORT&&(l=t.R16I),r===t.INT&&(l=t.R32I)),i===t.RG&&(r===t.FLOAT&&(l=t.RG32F),r===t.HALF_FLOAT&&(l=t.RG16F),r===t.UNSIGNED_BYTE&&(l=t.RG8)),i===t.RGBA){const e=a?Ye:ui.getTransfer(s);r===t.FLOAT&&(l=t.RGBA32F),r===t.HALF_FLOAT&&(l=t.RGBA16F),r===t.UNSIGNED_BYTE&&(l=e===Ze?t.SRGB8_ALPHA8:t.RGBA8),r===t.UNSIGNED_SHORT_4_4_4_4&&(l=t.RGBA4),r===t.UNSIGNED_SHORT_5_5_5_1&&(l=t.RGB5_A1)}return l!==t.R16F&&l!==t.R32F&&l!==t.RG16F&&l!==t.RG32F&&l!==t.RGBA16F&&l!==t.RGBA32F||e.get("EXT_color_buffer_float"),l}function y(t,e,n){return!0===_(t,n)||t.isFramebufferTexture&&t.minFilter!==ft&&t.minFilter!==yt?Math.log2(Math.max(e.width,e.height))+1:void 0!==t.mipmaps&&t.mipmaps.length>0?t.mipmaps.length:t.isCompressedTexture&&Array.isArray(t.image)?e.mipmaps.length:1}function M(e){return e===ft||e===gt||e===vt?t.NEAREST:t.LINEAR}function S(t){const e=t.target;e.removeEventListener("dispose",S),function(t){const e=i.get(t);if(void 0===e.__webglInit)return;const n=t.source,r=d.get(n);if(r){const i=r[e.__cacheKey];i.usedTimes--,0===i.usedTimes&&E(t),0===Object.keys(r).length&&d.delete(n)}i.remove(t)}(e),e.isVideoTexture&&h.delete(e)}function b(e){const n=e.target;n.removeEventListener("dispose",b),function(e){const n=e.texture,r=i.get(e),s=i.get(n);void 0!==s.__webglTexture&&(t.deleteTexture(s.__webglTexture),a.memory.textures--);e.depthTexture&&e.depthTexture.dispose();if(e.isWebGLCubeRenderTarget)for(let e=0;e<6;e++){if(Array.isArray(r.__webglFramebuffer[e]))for(let n=0;n0&&s.__version!==e.version){const t=e.image;if(null===t)console.warn("THREE.WebGLRenderer: Texture marked for update but no image data found.");else{if(!1!==t.complete)return void I(s,e,r);console.warn("THREE.WebGLRenderer: Texture marked for update but image is incomplete")}}n.bindTexture(t.TEXTURE_2D,s.__webglTexture,t.TEXTURE0+r)}const A={[dt]:t.REPEAT,[pt]:t.CLAMP_TO_EDGE,[mt]:t.MIRRORED_REPEAT},R={[ft]:t.NEAREST,[gt]:t.NEAREST_MIPMAP_NEAREST,[vt]:t.NEAREST_MIPMAP_LINEAR,[yt]:t.LINEAR,[Mt]:t.LINEAR_MIPMAP_NEAREST,[bt]:t.LINEAR_MIPMAP_LINEAR},C={512:t.NEVER,519:t.ALWAYS,513:t.LESS,515:t.LEQUAL,514:t.EQUAL,518:t.GEQUAL,516:t.GREATER,517:t.NOTEQUAL};function P(n,s,a){if(s.type!==Lt||!1!==e.has("OES_texture_float_linear")||s.magFilter!==yt&&s.magFilter!==Mt&&s.magFilter!==vt&&s.magFilter!==bt&&s.minFilter!==yt&&s.minFilter!==Mt&&s.minFilter!==vt&&s.minFilter!==bt||console.warn("THREE.WebGLRenderer: Unable to use linear filtering with floating point textures. OES_texture_float_linear not supported on this device."),a?(t.texParameteri(n,t.TEXTURE_WRAP_S,A[s.wrapS]),t.texParameteri(n,t.TEXTURE_WRAP_T,A[s.wrapT]),n!==t.TEXTURE_3D&&n!==t.TEXTURE_2D_ARRAY||t.texParameteri(n,t.TEXTURE_WRAP_R,A[s.wrapR]),t.texParameteri(n,t.TEXTURE_MAG_FILTER,R[s.magFilter]),t.texParameteri(n,t.TEXTURE_MIN_FILTER,R[s.minFilter])):(t.texParameteri(n,t.TEXTURE_WRAP_S,t.CLAMP_TO_EDGE),t.texParameteri(n,t.TEXTURE_WRAP_T,t.CLAMP_TO_EDGE),n!==t.TEXTURE_3D&&n!==t.TEXTURE_2D_ARRAY||t.texParameteri(n,t.TEXTURE_WRAP_R,t.CLAMP_TO_EDGE),s.wrapS===pt&&s.wrapT===pt||console.warn("THREE.WebGLRenderer: Texture is not power of two. Texture.wrapS and Texture.wrapT should be set to THREE.ClampToEdgeWrapping."),t.texParameteri(n,t.TEXTURE_MAG_FILTER,M(s.magFilter)),t.texParameteri(n,t.TEXTURE_MIN_FILTER,M(s.minFilter)),s.minFilter!==ft&&s.minFilter!==yt&&console.warn("THREE.WebGLRenderer: Texture is not power of two. Texture.minFilter should be set to THREE.NearestFilter or THREE.LinearFilter.")),s.compareFunction&&(t.texParameteri(n,t.TEXTURE_COMPARE_MODE,t.COMPARE_REF_TO_TEXTURE),t.texParameteri(n,t.TEXTURE_COMPARE_FUNC,C[s.compareFunction])),!0===e.has("EXT_texture_filter_anisotropic")){const a=e.get("EXT_texture_filter_anisotropic");if(s.magFilter===ft)return;if(s.minFilter!==vt&&s.minFilter!==bt)return;if(s.type===Lt&&!1===e.has("OES_texture_float_linear"))return;if(!1===o&&s.type===It&&!1===e.has("OES_texture_half_float_linear"))return;(s.anisotropy>1||i.get(s).__currentAnisotropy)&&(t.texParameterf(n,a.TEXTURE_MAX_ANISOTROPY_EXT,Math.min(s.anisotropy,r.getMaxAnisotropy())),i.get(s).__currentAnisotropy=s.anisotropy)}}function L(e,n){let i=!1;void 0===e.__webglInit&&(e.__webglInit=!0,n.addEventListener("dispose",S));const r=n.source;let s=d.get(r);void 0===s&&(s={},d.set(r,s));const o=function(t){const e=[];return e.push(t.wrapS),e.push(t.wrapT),e.push(t.wrapR||0),e.push(t.magFilter),e.push(t.minFilter),e.push(t.anisotropy),e.push(t.internalFormat),e.push(t.format),e.push(t.type),e.push(t.generateMipmaps),e.push(t.premultiplyAlpha),e.push(t.flipY),e.push(t.unpackAlignment),e.push(t.colorSpace),e.join()}(n);if(o!==e.__cacheKey){void 0===s[o]&&(s[o]={texture:t.createTexture(),usedTimes:0},a.memory.textures++,i=!0),s[o].usedTimes++;const r=s[e.__cacheKey];void 0!==r&&(s[e.__cacheKey].usedTimes--,0===r.usedTimes&&E(n)),e.__cacheKey=o,e.__webglTexture=s[o].texture}return i}function I(e,a,l){let c=t.TEXTURE_2D;(a.isDataArrayTexture||a.isCompressedArrayTexture)&&(c=t.TEXTURE_2D_ARRAY),a.isData3DTexture&&(c=t.TEXTURE_3D);const h=L(e,a),u=a.source;n.bindTexture(c,e.__webglTexture,t.TEXTURE0+l);const d=i.get(u);if(u.version!==d.__version||!0===h){n.activeTexture(t.TEXTURE0+l);const e=ui.getPrimaries(ui.workingColorSpace),i=a.colorSpace===Ge?null:ui.getPrimaries(a.colorSpace),p=a.colorSpace===Ge||e===i?t.NONE:t.BROWSER_DEFAULT_WEBGL;t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,a.flipY),t.pixelStorei(t.UNPACK_PREMULTIPLY_ALPHA_WEBGL,a.premultiplyAlpha),t.pixelStorei(t.UNPACK_ALIGNMENT,a.unpackAlignment),t.pixelStorei(t.UNPACK_COLORSPACE_CONVERSION_WEBGL,p);const m=function(t){return!o&&(t.wrapS!==pt||t.wrapT!==pt||t.minFilter!==ft&&t.minFilter!==yt)}(a)&&!1===g(a.image);let M=f(a.image,m,!1,r.maxTextureSize);M=B(a,M);const S=g(M)||o,b=s.convert(a.format,a.colorSpace);let E,T=s.convert(a.type),w=x(a.internalFormat,b,T,a.colorSpace,a.isVideoTexture);P(c,a,S);const A=a.mipmaps,R=o&&!0!==a.isVideoTexture&&w!==ee,C=void 0===d.__version||!0===h,L=u.dataReady,I=y(a,M,S);if(a.isDepthTexture)w=t.DEPTH_COMPONENT,o?w=a.type===Lt?t.DEPTH_COMPONENT32F:a.type===Pt?t.DEPTH_COMPONENT24:a.type===Dt?t.DEPTH24_STENCIL8:t.DEPTH_COMPONENT16:a.type===Lt&&console.error("WebGLRenderer: Floating point depth texture requires WebGL2."),a.format===Ht&&w===t.DEPTH_COMPONENT&&a.type!==Rt&&a.type!==Pt&&(console.warn("THREE.WebGLRenderer: Use UnsignedShortType or UnsignedIntType for DepthFormat DepthTexture."),a.type=Pt,T=s.convert(a.type)),a.format===Vt&&w===t.DEPTH_COMPONENT&&(w=t.DEPTH_STENCIL,a.type!==Dt&&(console.warn("THREE.WebGLRenderer: Use UnsignedInt248Type for DepthStencilFormat DepthTexture."),a.type=Dt,T=s.convert(a.type))),C&&(R?n.texStorage2D(t.TEXTURE_2D,1,w,M.width,M.height):n.texImage2D(t.TEXTURE_2D,0,w,M.width,M.height,0,b,T,null));else if(a.isDataTexture)if(A.length>0&&S){R&&C&&n.texStorage2D(t.TEXTURE_2D,I,w,A[0].width,A[0].height);for(let e=0,i=A.length;e>=1,i>>=1}}else if(A.length>0&&S){R&&C&&n.texStorage2D(t.TEXTURE_2D,I,w,A[0].width,A[0].height);for(let e=0,i=A.length;e>h),i=Math.max(1,r.height>>h);c===t.TEXTURE_3D||c===t.TEXTURE_2D_ARRAY?n.texImage3D(c,h,p,e,i,r.depth,0,u,d,null):n.texImage2D(c,h,p,e,i,0,u,d,null)}n.bindFramebuffer(t.FRAMEBUFFER,e),F(r)?l.framebufferTexture2DMultisampleEXT(t.FRAMEBUFFER,o,c,i.get(a).__webglTexture,0,O(r)):(c===t.TEXTURE_2D||c>=t.TEXTURE_CUBE_MAP_POSITIVE_X&&c<=t.TEXTURE_CUBE_MAP_NEGATIVE_Z)&&t.framebufferTexture2D(t.FRAMEBUFFER,o,c,i.get(a).__webglTexture,h),n.bindFramebuffer(t.FRAMEBUFFER,null)}function N(e,n,i){if(t.bindRenderbuffer(t.RENDERBUFFER,e),n.depthBuffer&&!n.stencilBuffer){let r=!0===o?t.DEPTH_COMPONENT24:t.DEPTH_COMPONENT16;if(i||F(n)){const e=n.depthTexture;e&&e.isDepthTexture&&(e.type===Lt?r=t.DEPTH_COMPONENT32F:e.type===Pt&&(r=t.DEPTH_COMPONENT24));const i=O(n);F(n)?l.renderbufferStorageMultisampleEXT(t.RENDERBUFFER,i,r,n.width,n.height):t.renderbufferStorageMultisample(t.RENDERBUFFER,i,r,n.width,n.height)}else t.renderbufferStorage(t.RENDERBUFFER,r,n.width,n.height);t.framebufferRenderbuffer(t.FRAMEBUFFER,t.DEPTH_ATTACHMENT,t.RENDERBUFFER,e)}else if(n.depthBuffer&&n.stencilBuffer){const r=O(n);i&&!1===F(n)?t.renderbufferStorageMultisample(t.RENDERBUFFER,r,t.DEPTH24_STENCIL8,n.width,n.height):F(n)?l.renderbufferStorageMultisampleEXT(t.RENDERBUFFER,r,t.DEPTH24_STENCIL8,n.width,n.height):t.renderbufferStorage(t.RENDERBUFFER,t.DEPTH_STENCIL,n.width,n.height),t.framebufferRenderbuffer(t.FRAMEBUFFER,t.DEPTH_STENCIL_ATTACHMENT,t.RENDERBUFFER,e)}else{const e=!0===n.isWebGLMultipleRenderTargets?n.texture:[n.texture];for(let r=0;r0&&!0===e.has("WEBGL_multisampled_render_to_texture")&&!1!==n.__useRenderToTexture}function B(t,n){const i=t.colorSpace,r=t.format,s=t.type;return!0===t.isCompressedTexture||!0===t.isVideoTexture||t.format===Nn||i!==Xe&&i!==Ge&&(ui.getTransfer(i)===Ze?!1===o?!0===e.has("EXT_sRGB")&&r===Ft?(t.format=Nn,t.minFilter=yt,t.generateMipmaps=!1):n=fi.sRGBToLinear(n):r===Ft&&s===Tt||console.warn("THREE.WebGLTextures: sRGB encoded textures have to use RGBAFormat and UnsignedByteType."):console.error("THREE.WebGLTextures: Unsupported texture color space:",i)),n}this.allocateTextureUnit=function(){const t=T;return t>=r.maxTextures&&console.warn("THREE.WebGLTextures: Trying to use "+t+" texture units while this GPU supports only "+r.maxTextures),T+=1,t},this.resetTextureUnits=function(){T=0},this.setTexture2D=w,this.setTexture2DArray=function(e,r){const s=i.get(e);e.version>0&&s.__version!==e.version?I(s,e,r):n.bindTexture(t.TEXTURE_2D_ARRAY,s.__webglTexture,t.TEXTURE0+r)},this.setTexture3D=function(e,r){const s=i.get(e);e.version>0&&s.__version!==e.version?I(s,e,r):n.bindTexture(t.TEXTURE_3D,s.__webglTexture,t.TEXTURE0+r)},this.setTextureCube=function(e,a){const l=i.get(e);e.version>0&&l.__version!==e.version?function(e,a,l){if(6!==a.image.length)return;const c=L(e,a),h=a.source;n.bindTexture(t.TEXTURE_CUBE_MAP,e.__webglTexture,t.TEXTURE0+l);const u=i.get(h);if(h.version!==u.__version||!0===c){n.activeTexture(t.TEXTURE0+l);const e=ui.getPrimaries(ui.workingColorSpace),i=a.colorSpace===Ge?null:ui.getPrimaries(a.colorSpace),d=a.colorSpace===Ge||e===i?t.NONE:t.BROWSER_DEFAULT_WEBGL;t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,a.flipY),t.pixelStorei(t.UNPACK_PREMULTIPLY_ALPHA_WEBGL,a.premultiplyAlpha),t.pixelStorei(t.UNPACK_ALIGNMENT,a.unpackAlignment),t.pixelStorei(t.UNPACK_COLORSPACE_CONVERSION_WEBGL,d);const p=a.isCompressedTexture||a.image[0].isCompressedTexture,m=a.image[0]&&a.image[0].isDataTexture,M=[];for(let t=0;t<6;t++)M[t]=p||m?m?a.image[t].image:a.image[t]:f(a.image[t],!1,!0,r.maxCubemapSize),M[t]=B(a,M[t]);const S=M[0],b=g(S)||o,E=s.convert(a.format,a.colorSpace),T=s.convert(a.type),w=x(a.internalFormat,E,T,a.colorSpace),A=o&&!0!==a.isVideoTexture,R=void 0===u.__version||!0===c,C=h.dataReady;let L,I=y(a,S,b);if(P(t.TEXTURE_CUBE_MAP,a,b),p){A&&R&&n.texStorage2D(t.TEXTURE_CUBE_MAP,I,w,S.width,S.height);for(let e=0;e<6;e++){L=M[e].mipmaps;for(let i=0;i0&&I++,n.texStorage2D(t.TEXTURE_CUBE_MAP,I,w,M[0].width,M[0].height));for(let e=0;e<6;e++)if(m){A?C&&n.texSubImage2D(t.TEXTURE_CUBE_MAP_POSITIVE_X+e,0,0,0,M[e].width,M[e].height,E,T,M[e].data):n.texImage2D(t.TEXTURE_CUBE_MAP_POSITIVE_X+e,0,w,M[e].width,M[e].height,0,E,T,M[e].data);for(let i=0;i0){c.__webglFramebuffer[e]=[];for(let n=0;n0){c.__webglFramebuffer=[];for(let e=0;e0&&!1===F(e)){const i=d?l:[l];c.__webglMultisampledFramebuffer=t.createFramebuffer(),c.__webglColorRenderbuffer=[],n.bindFramebuffer(t.FRAMEBUFFER,c.__webglMultisampledFramebuffer);for(let n=0;n0)for(let i=0;i0)for(let n=0;n0&&!1===F(e)){const r=e.isWebGLMultipleRenderTargets?e.texture:[e.texture],s=e.width,a=e.height;let o=t.COLOR_BUFFER_BIT;const l=[],h=e.stencilBuffer?t.DEPTH_STENCIL_ATTACHMENT:t.DEPTH_ATTACHMENT,u=i.get(e),d=!0===e.isWebGLMultipleRenderTargets;if(d)for(let e=0;eo+c?(l.inputState.pinching=!1,this.dispatchEvent({type:"pinchend",handedness:t.handedness,target:this})):!l.inputState.pinching&&a<=o-c&&(l.inputState.pinching=!0,this.dispatchEvent({type:"pinchstart",handedness:t.handedness,target:this}))}else null!==o&&t.gripSpace&&(r=e.getPose(t.gripSpace,n),null!==r&&(o.matrix.fromArray(r.transform.matrix),o.matrix.decompose(o.position,o.rotation,o.scale),o.matrixWorldNeedsUpdate=!0,r.linearVelocity?(o.hasLinearVelocity=!0,o.linearVelocity.copy(r.linearVelocity)):o.hasLinearVelocity=!1,r.angularVelocity?(o.hasAngularVelocity=!0,o.angularVelocity.copy(r.angularVelocity)):o.hasAngularVelocity=!1));null!==a&&(i=e.getPose(t.targetRaySpace,n),null===i&&null!==r&&(i=r),null!==i&&(a.matrix.fromArray(i.transform.matrix),a.matrix.decompose(a.position,a.rotation,a.scale),a.matrixWorldNeedsUpdate=!0,i.linearVelocity?(a.hasLinearVelocity=!0,a.linearVelocity.copy(i.linearVelocity)):a.hasLinearVelocity=!1,i.angularVelocity?(a.hasAngularVelocity=!0,a.angularVelocity.copy(i.angularVelocity)):a.hasAngularVelocity=!1,this.dispatchEvent(Wl)))}return null!==a&&(a.visible=null!==i),null!==o&&(o.visible=null!==r),null!==l&&(l.visible=null!==s),this}_getHandJoint(t,e){if(void 0===t.joints[e.jointName]){const n=new Gl;n.matrixAutoUpdate=!1,n.visible=!1,t.joints[e.jointName]=n,t.add(n)}return t.joints[e.jointName]}}class jl{constructor(){this.texture=null,this.mesh=null,this.depthNear=0,this.depthFar=0}init(t,e,n){if(null===this.texture){const i=new yi;t.properties.get(i).__webglTexture=e.texture,e.depthNear==n.depthNear&&e.depthFar==n.depthFar||(this.depthNear=e.depthNear,this.depthFar=e.depthFar),this.texture=i}}render(t,e){if(null!==this.texture){if(null===this.mesh){const t=e.cameras[0].viewport,n=new Ys({extensions:{fragDepth:!0},vertexShader:"\nvoid main() {\n\n\tgl_Position = vec4( position, 1.0 );\n\n}",fragmentShader:"\nuniform sampler2DArray depthColor;\nuniform float depthWidth;\nuniform float depthHeight;\n\nvoid main() {\n\n\tvec2 coord = vec2( gl_FragCoord.x / depthWidth, gl_FragCoord.y / depthHeight );\n\n\tif ( coord.x >= 1.0 ) {\n\n\t\tgl_FragDepthEXT = texture( depthColor, vec3( coord.x - 1.0, coord.y, 1 ) ).r;\n\n\t} else {\n\n\t\tgl_FragDepthEXT = texture( depthColor, vec3( coord.x, coord.y, 0 ) ).r;\n\n\t}\n\n}",uniforms:{depthColor:{value:this.texture},depthWidth:{value:t.z},depthHeight:{value:t.w}}});this.mesh=new Vs(new pa(20,20),n)}t.render(this.mesh,e)}}reset(){this.texture=null,this.mesh=null}}class ql extends Fn{constructor(t,e){super();const n=this;let i=null,r=1,s=null,a="local-floor",o=1,l=null,c=null,h=null,u=null,d=null,p=null;const m=new jl,f=e.getContextAttributes();let g=null,_=null;const v=[],x=[],y=new Kn;let M=null;const S=new Qs;S.layers.enable(1),S.viewport=new Mi;const b=new Qs;b.layers.enable(2),b.viewport=new Mi;const E=[S,b],T=new kl;T.layers.enable(1),T.layers.enable(2);let w=null,A=null;function R(t){const e=x.indexOf(t.inputSource);if(-1===e)return;const n=v[e];void 0!==n&&(n.update(t.inputSource,t.frame,l||s),n.dispatchEvent({type:t.type,data:t.inputSource}))}function C(){i.removeEventListener("select",R),i.removeEventListener("selectstart",R),i.removeEventListener("selectend",R),i.removeEventListener("squeeze",R),i.removeEventListener("squeezestart",R),i.removeEventListener("squeezeend",R),i.removeEventListener("end",C),i.removeEventListener("inputsourceschange",P);for(let t=0;t=0&&(x[i]=null,v[i].disconnect(n))}for(let e=0;e=x.length){x.push(n),i=t;break}if(null===x[t]){x[t]=n,i=t;break}}if(-1===i)break}const r=v[i];r&&r.connect(n)}}this.cameraAutoUpdate=!0,this.enabled=!1,this.isPresenting=!1,this.getController=function(t){let e=v[t];return void 0===e&&(e=new Xl,v[t]=e),e.getTargetRaySpace()},this.getControllerGrip=function(t){let e=v[t];return void 0===e&&(e=new Xl,v[t]=e),e.getGripSpace()},this.getHand=function(t){let e=v[t];return void 0===e&&(e=new Xl,v[t]=e),e.getHandSpace()},this.setFramebufferScaleFactor=function(t){r=t,!0===n.isPresenting&&console.warn("THREE.WebXRManager: Cannot change framebuffer scale while presenting.")},this.setReferenceSpaceType=function(t){a=t,!0===n.isPresenting&&console.warn("THREE.WebXRManager: Cannot change reference space type while presenting.")},this.getReferenceSpace=function(){return l||s},this.setReferenceSpace=function(t){l=t},this.getBaseLayer=function(){return null!==u?u:d},this.getBinding=function(){return h},this.getFrame=function(){return p},this.getSession=function(){return i},this.setSession=async function(c){if(i=c,null!==i){if(g=t.getRenderTarget(),i.addEventListener("select",R),i.addEventListener("selectstart",R),i.addEventListener("selectend",R),i.addEventListener("squeeze",R),i.addEventListener("squeezestart",R),i.addEventListener("squeezeend",R),i.addEventListener("end",C),i.addEventListener("inputsourceschange",P),!0!==f.xrCompatible&&await e.makeXRCompatible(),M=t.getPixelRatio(),t.getSize(y),void 0===i.renderState.layers||!1===t.capabilities.isWebGL2){const n={antialias:void 0!==i.renderState.layers||f.antialias,alpha:!0,depth:f.depth,stencil:f.stencil,framebufferScaleFactor:r};d=new XRWebGLLayer(i,e,n),i.updateRenderState({baseLayer:d}),t.setPixelRatio(1),t.setSize(d.framebufferWidth,d.framebufferHeight,!1),_=new bi(d.framebufferWidth,d.framebufferHeight,{format:Ft,type:Tt,colorSpace:t.outputColorSpace,stencilBuffer:f.stencil})}else{let n=null,s=null,a=null;f.depth&&(a=f.stencil?e.DEPTH24_STENCIL8:e.DEPTH_COMPONENT24,n=f.stencil?Vt:Ht,s=f.stencil?Dt:Pt);const o={colorFormat:e.RGBA8,depthFormat:a,scaleFactor:r};h=new XRWebGLBinding(i,e),u=h.createProjectionLayer(o),i.updateRenderState({layers:[u]}),t.setPixelRatio(1),t.setSize(u.textureWidth,u.textureHeight,!1),_=new bi(u.textureWidth,u.textureHeight,{format:Ft,type:Tt,depthTexture:new Ja(u.textureWidth,u.textureHeight,s,void 0,void 0,void 0,void 0,void 0,void 0,n),stencilBuffer:f.stencil,colorSpace:t.outputColorSpace,samples:f.antialias?4:0});t.properties.get(_).__ignoreDepthValues=u.ignoreDepthValues}_.isXRRenderTarget=!0,this.setFoveation(o),l=null,s=await i.requestReferenceSpace(a),D.setContext(i),D.start(),n.isPresenting=!0,n.dispatchEvent({type:"sessionstart"})}},this.getEnvironmentBlendMode=function(){if(null!==i)return i.environmentBlendMode};const L=new Pi,I=new Pi;function U(t,e){null===e?t.matrixWorld.copy(t.matrix):t.matrixWorld.multiplyMatrices(e.matrixWorld,t.matrix),t.matrixWorldInverse.copy(t.matrixWorld).invert()}this.updateCamera=function(t){if(null===i)return;null!==m.texture&&(t.near=m.depthNear,t.far=m.depthFar),T.near=b.near=S.near=t.near,T.far=b.far=S.far=t.far,w===T.near&&A===T.far||(i.updateRenderState({depthNear:T.near,depthFar:T.far}),w=T.near,A=T.far,S.near=w,S.far=A,b.near=w,b.far=A,S.updateProjectionMatrix(),b.updateProjectionMatrix(),t.updateProjectionMatrix());const e=t.parent,n=T.cameras;U(T,e);for(let t=0;t0&&(i.alphaTest.value=r.alphaTest);const s=e.get(r).envMap;if(s&&(i.envMap.value=s,i.flipEnvMap.value=s.isCubeTexture&&!1===s.isRenderTargetTexture?-1:1,i.reflectivity.value=r.reflectivity,i.ior.value=r.ior,i.refractionRatio.value=r.refractionRatio),r.lightMap){i.lightMap.value=r.lightMap;const e=!0===t._useLegacyLights?Math.PI:1;i.lightMapIntensity.value=r.lightMapIntensity*e,n(r.lightMap,i.lightMapTransform)}r.aoMap&&(i.aoMap.value=r.aoMap,i.aoMapIntensity.value=r.aoMapIntensity,n(r.aoMap,i.aoMapTransform))}return{refreshFogUniforms:function(e,n){n.color.getRGB(e.fogColor.value,js(t)),n.isFog?(e.fogNear.value=n.near,e.fogFar.value=n.far):n.isFogExp2&&(e.fogDensity.value=n.density)},refreshMaterialUniforms:function(t,r,s,a,o){r.isMeshBasicMaterial||r.isMeshLambertMaterial?i(t,r):r.isMeshToonMaterial?(i(t,r),function(t,e){e.gradientMap&&(t.gradientMap.value=e.gradientMap)}(t,r)):r.isMeshPhongMaterial?(i(t,r),function(t,e){t.specular.value.copy(e.specular),t.shininess.value=Math.max(e.shininess,1e-4)}(t,r)):r.isMeshStandardMaterial?(i(t,r),function(t,i){t.metalness.value=i.metalness,i.metalnessMap&&(t.metalnessMap.value=i.metalnessMap,n(i.metalnessMap,t.metalnessMapTransform));t.roughness.value=i.roughness,i.roughnessMap&&(t.roughnessMap.value=i.roughnessMap,n(i.roughnessMap,t.roughnessMapTransform));const r=e.get(i).envMap;r&&(t.envMapIntensity.value=i.envMapIntensity)}(t,r),r.isMeshPhysicalMaterial&&function(t,e,i){t.ior.value=e.ior,e.sheen>0&&(t.sheenColor.value.copy(e.sheenColor).multiplyScalar(e.sheen),t.sheenRoughness.value=e.sheenRoughness,e.sheenColorMap&&(t.sheenColorMap.value=e.sheenColorMap,n(e.sheenColorMap,t.sheenColorMapTransform)),e.sheenRoughnessMap&&(t.sheenRoughnessMap.value=e.sheenRoughnessMap,n(e.sheenRoughnessMap,t.sheenRoughnessMapTransform)));e.clearcoat>0&&(t.clearcoat.value=e.clearcoat,t.clearcoatRoughness.value=e.clearcoatRoughness,e.clearcoatMap&&(t.clearcoatMap.value=e.clearcoatMap,n(e.clearcoatMap,t.clearcoatMapTransform)),e.clearcoatRoughnessMap&&(t.clearcoatRoughnessMap.value=e.clearcoatRoughnessMap,n(e.clearcoatRoughnessMap,t.clearcoatRoughnessMapTransform)),e.clearcoatNormalMap&&(t.clearcoatNormalMap.value=e.clearcoatNormalMap,n(e.clearcoatNormalMap,t.clearcoatNormalMapTransform),t.clearcoatNormalScale.value.copy(e.clearcoatNormalScale),e.side===d&&t.clearcoatNormalScale.value.negate()));e.iridescence>0&&(t.iridescence.value=e.iridescence,t.iridescenceIOR.value=e.iridescenceIOR,t.iridescenceThicknessMinimum.value=e.iridescenceThicknessRange[0],t.iridescenceThicknessMaximum.value=e.iridescenceThicknessRange[1],e.iridescenceMap&&(t.iridescenceMap.value=e.iridescenceMap,n(e.iridescenceMap,t.iridescenceMapTransform)),e.iridescenceThicknessMap&&(t.iridescenceThicknessMap.value=e.iridescenceThicknessMap,n(e.iridescenceThicknessMap,t.iridescenceThicknessMapTransform)));e.transmission>0&&(t.transmission.value=e.transmission,t.transmissionSamplerMap.value=i.texture,t.transmissionSamplerSize.value.set(i.width,i.height),e.transmissionMap&&(t.transmissionMap.value=e.transmissionMap,n(e.transmissionMap,t.transmissionMapTransform)),t.thickness.value=e.thickness,e.thicknessMap&&(t.thicknessMap.value=e.thicknessMap,n(e.thicknessMap,t.thicknessMapTransform)),t.attenuationDistance.value=e.attenuationDistance,t.attenuationColor.value.copy(e.attenuationColor));e.anisotropy>0&&(t.anisotropyVector.value.set(e.anisotropy*Math.cos(e.anisotropyRotation),e.anisotropy*Math.sin(e.anisotropyRotation)),e.anisotropyMap&&(t.anisotropyMap.value=e.anisotropyMap,n(e.anisotropyMap,t.anisotropyMapTransform)));t.specularIntensity.value=e.specularIntensity,t.specularColor.value.copy(e.specularColor),e.specularColorMap&&(t.specularColorMap.value=e.specularColorMap,n(e.specularColorMap,t.specularColorMapTransform));e.specularIntensityMap&&(t.specularIntensityMap.value=e.specularIntensityMap,n(e.specularIntensityMap,t.specularIntensityMapTransform))}(t,r,o)):r.isMeshMatcapMaterial?(i(t,r),function(t,e){e.matcap&&(t.matcap.value=e.matcap)}(t,r)):r.isMeshDepthMaterial?i(t,r):r.isMeshDistanceMaterial?(i(t,r),function(t,n){const i=e.get(n).light;t.referencePosition.value.setFromMatrixPosition(i.matrixWorld),t.nearDistance.value=i.shadow.camera.near,t.farDistance.value=i.shadow.camera.far}(t,r)):r.isMeshNormalMaterial?i(t,r):r.isLineBasicMaterial?(function(t,e){t.diffuse.value.copy(e.color),t.opacity.value=e.opacity,e.map&&(t.map.value=e.map,n(e.map,t.mapTransform))}(t,r),r.isLineDashedMaterial&&function(t,e){t.dashSize.value=e.dashSize,t.totalSize.value=e.dashSize+e.gapSize,t.scale.value=e.scale}(t,r)):r.isPointsMaterial?function(t,e,i,r){t.diffuse.value.copy(e.color),t.opacity.value=e.opacity,t.size.value=e.size*i,t.scale.value=.5*r,e.map&&(t.map.value=e.map,n(e.map,t.uvTransform));e.alphaMap&&(t.alphaMap.value=e.alphaMap,n(e.alphaMap,t.alphaMapTransform));e.alphaTest>0&&(t.alphaTest.value=e.alphaTest)}(t,r,s,a):r.isSpriteMaterial?function(t,e){t.diffuse.value.copy(e.color),t.opacity.value=e.opacity,t.rotation.value=e.rotation,e.map&&(t.map.value=e.map,n(e.map,t.mapTransform));e.alphaMap&&(t.alphaMap.value=e.alphaMap,n(e.alphaMap,t.alphaMapTransform));e.alphaTest>0&&(t.alphaTest.value=e.alphaTest)}(t,r):r.isShadowMaterial?(t.color.value.copy(r.color),t.opacity.value=r.opacity):r.isShaderMaterial&&(r.uniformsNeedUpdate=!1)}}}function Zl(t,e,n,i){let r={},s={},a=[];const o=n.isWebGL2?t.getParameter(t.MAX_UNIFORM_BUFFER_BINDINGS):0;function l(t,e,n,i){const r=t.value,s=e+"_"+n;if(void 0===i[s])return i[s]="number"==typeof r||"boolean"==typeof r?r:r.clone(),!0;{const t=i[s];if("number"==typeof r||"boolean"==typeof r){if(t!==r)return i[s]=r,!0}else if(!1===t.equals(r))return t.copy(r),!0}return!1}function c(t){const e={boundary:0,storage:0};return"number"==typeof t||"boolean"==typeof t?(e.boundary=4,e.storage=4):t.isVector2?(e.boundary=8,e.storage=8):t.isVector3||t.isColor?(e.boundary=16,e.storage=12):t.isVector4?(e.boundary=16,e.storage=16):t.isMatrix3?(e.boundary=48,e.storage=48):t.isMatrix4?(e.boundary=64,e.storage=64):t.isTexture?console.warn("THREE.WebGLRenderer: Texture samplers can not be part of an uniforms group."):console.warn("THREE.WebGLRenderer: Unsupported uniform value type.",t),e}function h(e){const n=e.target;n.removeEventListener("dispose",h);const i=a.indexOf(n.__bindingPointIndex);a.splice(i,1),t.deleteBuffer(r[n.id]),delete r[n.id],delete s[n.id]}return{bind:function(t,e){const n=e.program;i.uniformBlockBinding(t,n)},update:function(n,u){let d=r[n.id];void 0===d&&(!function(t){const e=t.uniforms;let n=0;const i=16;for(let t=0,r=e.length;t0&&(n+=i-r);t.__size=n,t.__cache={}}(n),d=function(e){const n=function(){for(let t=0;t0),u=!!n.morphAttributes.position,d=!!n.morphAttributes.normal,p=!!n.morphAttributes.color;let m=K;i.toneMapped&&(null!==T&&!0!==T.isXRRenderTarget||(m=M.toneMapping));const f=n.morphAttributes.position||n.morphAttributes.normal||n.morphAttributes.color,g=void 0!==f?f.length:0,_=et.get(i),x=v.state.lights;if(!0===k&&(!0===G||t!==A)){const e=t===A&&i.id===w;dt.setState(i,t,e)}let y=!1;i.version===_.__version?_.needsLights&&_.lightsStateVersion!==x.state.version||_.outputColorSpace!==o||r.isBatchedMesh&&!1===_.batching?y=!0:r.isBatchedMesh||!0!==_.batching?r.isInstancedMesh&&!1===_.instancing?y=!0:r.isInstancedMesh||!0!==_.instancing?r.isSkinnedMesh&&!1===_.skinning?y=!0:r.isSkinnedMesh||!0!==_.skinning?r.isInstancedMesh&&!0===_.instancingColor&&null===r.instanceColor||r.isInstancedMesh&&!1===_.instancingColor&&null!==r.instanceColor||_.envMap!==l||!0===i.fog&&_.fog!==s?y=!0:void 0===_.numClippingPlanes||_.numClippingPlanes===dt.numPlanes&&_.numIntersection===dt.numIntersection?(_.vertexAlphas!==c||_.vertexTangents!==h||_.morphTargets!==u||_.morphNormals!==d||_.morphColors!==p||_.toneMapping!==m||!0===$.isWebGL2&&_.morphTargetsCount!==g)&&(y=!0):y=!0:y=!0:y=!0:y=!0:(y=!0,_.__version=i.version);let S=_.currentProgram;!0===y&&(S=Kt(i,e,r));let b=!1,E=!1,R=!1;const C=S.getUniforms(),P=_.uniforms;Q.useProgram(S.program)&&(b=!0,E=!0,R=!0);i.id!==w&&(w=i.id,E=!0);if(b||A!==t){C.setValue(Mt,"projectionMatrix",t.projectionMatrix),C.setValue(Mt,"viewMatrix",t.matrixWorldInverse);const e=C.map.cameraPosition;void 0!==e&&e.setValue(Mt,q.setFromMatrixPosition(t.matrixWorld)),$.logarithmicDepthBuffer&&C.setValue(Mt,"logDepthBufFC",2/(Math.log(t.far+1)/Math.LN2)),(i.isMeshPhongMaterial||i.isMeshToonMaterial||i.isMeshLambertMaterial||i.isMeshBasicMaterial||i.isMeshStandardMaterial||i.isShaderMaterial)&&C.setValue(Mt,"isOrthographic",!0===t.isOrthographicCamera),A!==t&&(A=t,E=!0,R=!0)}if(r.isSkinnedMesh){C.setOptional(Mt,r,"bindMatrix"),C.setOptional(Mt,r,"bindMatrixInverse");const t=r.skeleton;t&&($.floatVertexTextures?(null===t.boneTexture&&t.computeBoneTexture(),C.setValue(Mt,"boneTexture",t.boneTexture,nt)):console.warn("THREE.WebGLRenderer: SkinnedMesh can only be used with WebGL 2. With WebGL 1 OES_texture_float and vertex textures support is required."))}r.isBatchedMesh&&(C.setOptional(Mt,r,"batchingTexture"),C.setValue(Mt,"batchingTexture",r._matricesTexture,nt));const L=n.morphAttributes;(void 0!==L.position||void 0!==L.normal||void 0!==L.color&&!0===$.isWebGL2)&&ft.update(r,n,S);(E||_.receiveShadow!==r.receiveShadow)&&(_.receiveShadow=r.receiveShadow,C.setValue(Mt,"receiveShadow",r.receiveShadow));i.isMeshGouraudMaterial&&null!==i.envMap&&(P.envMap.value=l,P.flipEnvMap.value=l.isCubeTexture&&!1===l.isRenderTargetTexture?-1:1);E&&(C.setValue(Mt,"toneMappingExposure",M.toneMappingExposure),_.needsLights&&(U=R,(I=P).ambientLightColor.needsUpdate=U,I.lightProbe.needsUpdate=U,I.directionalLights.needsUpdate=U,I.directionalLightShadows.needsUpdate=U,I.pointLights.needsUpdate=U,I.pointLightShadows.needsUpdate=U,I.spotLights.needsUpdate=U,I.spotLightShadows.needsUpdate=U,I.rectAreaLights.needsUpdate=U,I.hemisphereLights.needsUpdate=U),s&&!0===i.fog&&ct.refreshFogUniforms(P,s),ct.refreshMaterialUniforms(P,i,D,N,W),nl.upload(Mt,$t(_),P,nt));var I,U;i.isShaderMaterial&&!0===i.uniformsNeedUpdate&&(nl.upload(Mt,$t(_),P,nt),i.uniformsNeedUpdate=!1);i.isSpriteMaterial&&C.setValue(Mt,"center",r.center);if(C.setValue(Mt,"modelViewMatrix",r.modelViewMatrix),C.setValue(Mt,"normalMatrix",r.normalMatrix),C.setValue(Mt,"modelMatrix",r.matrixWorld),i.isShaderMaterial||i.isRawShaderMaterial){const t=i.uniformsGroups;for(let e=0,n=t.length;e{function n(){i.forEach((function(t){et.get(t).currentProgram.isReady()&&i.delete(t)})),0!==i.size?setTimeout(n,10):e(t)}null!==J.get("KHR_parallel_shader_compile")?n():setTimeout(n,10)}))};let Ht=null;function Vt(){Wt.stop()}function kt(){Wt.start()}const Wt=new ua;function qt(t,e,n,i){if(!1===t.visible)return;if(t.layers.test(e.layers))if(t.isGroup)n=t.renderOrder;else if(t.isLOD)!0===t.autoUpdate&&t.update(e);else if(t.isLight)v.pushLight(t),t.castShadow&&v.pushShadow(t);else if(t.isSprite){if(!t.frustumCulled||V.intersectsSprite(t)){i&&q.setFromMatrixPosition(t.matrixWorld).applyMatrix4(X);const e=ot.update(t),r=t.material;r.visible&&_.push(t,e,r,n,q.z,null)}}else if((t.isMesh||t.isLine||t.isPoints)&&(!t.frustumCulled||V.intersectsObject(t))){const e=ot.update(t),r=t.material;if(i&&(void 0!==t.boundingSphere?(null===t.boundingSphere&&t.computeBoundingSphere(),q.copy(t.boundingSphere.center)):(null===e.boundingSphere&&e.computeBoundingSphere(),q.copy(e.boundingSphere.center)),q.applyMatrix4(t.matrixWorld).applyMatrix4(X)),Array.isArray(r)){const i=e.groups;for(let s=0,a=i.length;s0&&function(t,e,n,i){const r=!0===n.isScene?n.overrideMaterial:null;if(null!==r)return;const s=$.isWebGL2;null===W&&(W=new bi(1,1,{generateMipmaps:!0,type:J.has("EXT_color_buffer_half_float")?It:Tt,minFilter:bt,samples:s?4:0}));M.getDrawingBufferSize(j),s?W.setSize(j.x,j.y):W.setSize(qn(j.x),qn(j.y));const a=M.getRenderTarget();M.setRenderTarget(W),M.getClearColor(L),I=M.getClearAlpha(),I<1&&M.setClearColor(16777215,.5);M.clear();const o=M.toneMapping;M.toneMapping=K,Zt(t,n,i),nt.updateMultisampleRenderTarget(W),nt.updateRenderTargetMipmap(W);let l=!1;for(let t=0,r=e.length;t0&&Zt(r,e,n),s.length>0&&Zt(s,e,n),a.length>0&&Zt(a,e,n),Q.buffers.depth.setTest(!0),Q.buffers.depth.setMask(!0),Q.buffers.color.setMask(!0),Q.setPolygonOffset(!1)}function Zt(t,e,n){const i=!0===e.isScene?e.overrideMaterial:null;for(let r=0,s=t.length;r0?y[y.length-1]:null,x.pop(),_=x.length>0?x[x.length-1]:null},this.getActiveCubeFace=function(){return b},this.getActiveMipmapLevel=function(){return E},this.getRenderTarget=function(){return T},this.setRenderTargetTextures=function(t,e,n){et.get(t.texture).__webglTexture=e,et.get(t.depthTexture).__webglTexture=n;const i=et.get(t);i.__hasExternalTextures=!0,i.__hasExternalTextures&&(i.__autoAllocateDepthBuffer=void 0===n,i.__autoAllocateDepthBuffer||!0===J.has("WEBGL_multisampled_render_to_texture")&&(console.warn("THREE.WebGLRenderer: Render-to-texture extension was disabled because an external texture was provided"),i.__useRenderToTexture=!1))},this.setRenderTargetFramebuffer=function(t,e){const n=et.get(t);n.__webglFramebuffer=e,n.__useDefaultFramebuffer=void 0===e},this.setRenderTarget=function(t,e=0,n=0){T=t,b=e,E=n;let i=!0,r=null,s=!1,a=!1;if(t){const o=et.get(t);void 0!==o.__useDefaultFramebuffer?(Q.bindFramebuffer(Mt.FRAMEBUFFER,null),i=!1):void 0===o.__webglFramebuffer?nt.setupRenderTarget(t):o.__hasExternalTextures&&nt.rebindTextures(t,et.get(t.texture).__webglTexture,et.get(t.depthTexture).__webglTexture);const l=t.texture;(l.isData3DTexture||l.isDataArrayTexture||l.isCompressedArrayTexture)&&(a=!0);const c=et.get(t).__webglFramebuffer;t.isWebGLCubeRenderTarget?(r=Array.isArray(c[e])?c[e][n]:c[e],s=!0):r=$.isWebGL2&&t.samples>0&&!1===nt.useMultisampledRTT(t)?et.get(t).__webglMultisampledFramebuffer:Array.isArray(c)?c[n]:c,R.copy(t.viewport),C.copy(t.scissor),P=t.scissorTest}else R.copy(B).multiplyScalar(D).floor(),C.copy(z).multiplyScalar(D).floor(),P=H;if(Q.bindFramebuffer(Mt.FRAMEBUFFER,r)&&$.drawBuffers&&i&&Q.drawBuffers(t,r),Q.viewport(R),Q.scissor(C),Q.setScissorTest(P),s){const i=et.get(t.texture);Mt.framebufferTexture2D(Mt.FRAMEBUFFER,Mt.COLOR_ATTACHMENT0,Mt.TEXTURE_CUBE_MAP_POSITIVE_X+e,i.__webglTexture,n)}else if(a){const i=et.get(t.texture),r=e||0;Mt.framebufferTextureLayer(Mt.FRAMEBUFFER,Mt.COLOR_ATTACHMENT0,i.__webglTexture,n||0,r)}w=-1},this.readRenderTargetPixels=function(t,e,n,i,r,s,a){if(!t||!t.isWebGLRenderTarget)return void console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.");let o=et.get(t).__webglFramebuffer;if(t.isWebGLCubeRenderTarget&&void 0!==a&&(o=o[a]),o){Q.bindFramebuffer(Mt.FRAMEBUFFER,o);try{const a=t.texture,o=a.format,l=a.type;if(o!==Ft&&vt.convert(o)!==Mt.getParameter(Mt.IMPLEMENTATION_COLOR_READ_FORMAT))return void console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.");const c=l===It&&(J.has("EXT_color_buffer_half_float")||$.isWebGL2&&J.has("EXT_color_buffer_float"));if(!(l===Tt||vt.convert(l)===Mt.getParameter(Mt.IMPLEMENTATION_COLOR_READ_TYPE)||l===Lt&&($.isWebGL2||J.has("OES_texture_float")||J.has("WEBGL_color_buffer_float"))||c))return void console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.");e>=0&&e<=t.width-i&&n>=0&&n<=t.height-r&&Mt.readPixels(e,n,i,r,vt.convert(o),vt.convert(l),s)}finally{const t=null!==T?et.get(T).__webglFramebuffer:null;Q.bindFramebuffer(Mt.FRAMEBUFFER,t)}}},this.copyFramebufferToTexture=function(t,e,n=0){const i=Math.pow(2,-n),r=Math.floor(e.image.width*i),s=Math.floor(e.image.height*i);nt.setTexture2D(e,0),Mt.copyTexSubImage2D(Mt.TEXTURE_2D,n,0,0,t.x,t.y,r,s),Q.unbindTexture()},this.copyTextureToTexture=function(t,e,n,i=0){const r=e.image.width,s=e.image.height,a=vt.convert(n.format),o=vt.convert(n.type);nt.setTexture2D(n,0),Mt.pixelStorei(Mt.UNPACK_FLIP_Y_WEBGL,n.flipY),Mt.pixelStorei(Mt.UNPACK_PREMULTIPLY_ALPHA_WEBGL,n.premultiplyAlpha),Mt.pixelStorei(Mt.UNPACK_ALIGNMENT,n.unpackAlignment),e.isDataTexture?Mt.texSubImage2D(Mt.TEXTURE_2D,i,t.x,t.y,r,s,a,o,e.image.data):e.isCompressedTexture?Mt.compressedTexSubImage2D(Mt.TEXTURE_2D,i,t.x,t.y,e.mipmaps[0].width,e.mipmaps[0].height,a,e.mipmaps[0].data):Mt.texSubImage2D(Mt.TEXTURE_2D,i,t.x,t.y,a,o,e.image),0===i&&n.generateMipmaps&&Mt.generateMipmap(Mt.TEXTURE_2D),Q.unbindTexture()},this.copyTextureToTexture3D=function(t,e,n,i,r=0){if(M.isWebGL1Renderer)return void console.warn("THREE.WebGLRenderer.copyTextureToTexture3D: can only be used with WebGL2.");const s=t.max.x-t.min.x+1,a=t.max.y-t.min.y+1,o=t.max.z-t.min.z+1,l=vt.convert(i.format),c=vt.convert(i.type);let h;if(i.isData3DTexture)nt.setTexture3D(i,0),h=Mt.TEXTURE_3D;else{if(!i.isDataArrayTexture&&!i.isCompressedArrayTexture)return void console.warn("THREE.WebGLRenderer.copyTextureToTexture3D: only supports THREE.DataTexture3D and THREE.DataTexture2DArray.");nt.setTexture2DArray(i,0),h=Mt.TEXTURE_2D_ARRAY}Mt.pixelStorei(Mt.UNPACK_FLIP_Y_WEBGL,i.flipY),Mt.pixelStorei(Mt.UNPACK_PREMULTIPLY_ALPHA_WEBGL,i.premultiplyAlpha),Mt.pixelStorei(Mt.UNPACK_ALIGNMENT,i.unpackAlignment);const u=Mt.getParameter(Mt.UNPACK_ROW_LENGTH),d=Mt.getParameter(Mt.UNPACK_IMAGE_HEIGHT),p=Mt.getParameter(Mt.UNPACK_SKIP_PIXELS),m=Mt.getParameter(Mt.UNPACK_SKIP_ROWS),f=Mt.getParameter(Mt.UNPACK_SKIP_IMAGES),g=n.isCompressedTexture?n.mipmaps[r]:n.image;Mt.pixelStorei(Mt.UNPACK_ROW_LENGTH,g.width),Mt.pixelStorei(Mt.UNPACK_IMAGE_HEIGHT,g.height),Mt.pixelStorei(Mt.UNPACK_SKIP_PIXELS,t.min.x),Mt.pixelStorei(Mt.UNPACK_SKIP_ROWS,t.min.y),Mt.pixelStorei(Mt.UNPACK_SKIP_IMAGES,t.min.z),n.isDataTexture||n.isData3DTexture?Mt.texSubImage3D(h,r,e.x,e.y,e.z,s,a,o,l,c,g.data):n.isCompressedArrayTexture?(console.warn("THREE.WebGLRenderer.copyTextureToTexture3D: untested support for compressed srcTexture."),Mt.compressedTexSubImage3D(h,r,e.x,e.y,e.z,s,a,o,l,g.data)):Mt.texSubImage3D(h,r,e.x,e.y,e.z,s,a,o,l,c,g),Mt.pixelStorei(Mt.UNPACK_ROW_LENGTH,u),Mt.pixelStorei(Mt.UNPACK_IMAGE_HEIGHT,d),Mt.pixelStorei(Mt.UNPACK_SKIP_PIXELS,p),Mt.pixelStorei(Mt.UNPACK_SKIP_ROWS,m),Mt.pixelStorei(Mt.UNPACK_SKIP_IMAGES,f),0===r&&i.generateMipmaps&&Mt.generateMipmap(h),Q.unbindTexture()},this.initTexture=function(t){t.isCubeTexture?nt.setTextureCube(t,0):t.isData3DTexture?nt.setTexture3D(t,0):t.isDataArrayTexture||t.isCompressedArrayTexture?nt.setTexture2DArray(t,0):nt.setTexture2D(t,0),Q.unbindTexture()},this.resetState=function(){b=0,E=0,T=null,Q.reset(),xt.reset()},"undefined"!=typeof __THREE_DEVTOOLS__&&__THREE_DEVTOOLS__.dispatchEvent(new CustomEvent("observe",{detail:this}))}get coordinateSystem(){return Dn}get outputColorSpace(){return this._outputColorSpace}set outputColorSpace(t){this._outputColorSpace=t;const e=this.getContext();e.drawingBufferColorSpace=t===je?"display-p3":"srgb",e.unpackColorSpace=ui.workingColorSpace===qe?"display-p3":"srgb"}get useLegacyLights(){return console.warn("THREE.WebGLRenderer: The property .useLegacyLights has been deprecated. Migrate your lighting according to the following guide: https://discourse.threejs.org/t/updates-to-lighting-in-three-js-r155/53733."),this._useLegacyLights}set useLegacyLights(t){console.warn("THREE.WebGLRenderer: The property .useLegacyLights has been deprecated. Migrate your lighting according to the following guide: https://discourse.threejs.org/t/updates-to-lighting-in-three-js-r155/53733."),this._useLegacyLights=t}}class Kl extends Jl{}Kl.prototype.isWebGL1Renderer=!0;class $l{constructor(t,e=25e-5){this.isFogExp2=!0,this.name="",this.color=new qr(t),this.density=e}clone(){return new $l(this.color,this.density)}toJSON(){return{type:"FogExp2",name:this.name,color:this.color.getHex(),density:this.density}}}class Ql{constructor(t,e=1,n=1e3){this.isFog=!0,this.name="",this.color=new qr(t),this.near=e,this.far=n}clone(){return new Ql(this.color,this.near,this.far)}toJSON(){return{type:"Fog",name:this.name,color:this.color.getHex(),near:this.near,far:this.far}}}class tc extends Lr{constructor(){super(),this.isScene=!0,this.type="Scene",this.background=null,this.environment=null,this.fog=null,this.backgroundBlurriness=0,this.backgroundIntensity=1,this.overrideMaterial=null,"undefined"!=typeof __THREE_DEVTOOLS__&&__THREE_DEVTOOLS__.dispatchEvent(new CustomEvent("observe",{detail:this}))}copy(t,e){return super.copy(t,e),null!==t.background&&(this.background=t.background.clone()),null!==t.environment&&(this.environment=t.environment.clone()),null!==t.fog&&(this.fog=t.fog.clone()),this.backgroundBlurriness=t.backgroundBlurriness,this.backgroundIntensity=t.backgroundIntensity,null!==t.overrideMaterial&&(this.overrideMaterial=t.overrideMaterial.clone()),this.matrixAutoUpdate=t.matrixAutoUpdate,this}toJSON(t){const e=super.toJSON(t);return null!==this.fog&&(e.object.fog=this.fog.toJSON()),this.backgroundBlurriness>0&&(e.object.backgroundBlurriness=this.backgroundBlurriness),1!==this.backgroundIntensity&&(e.object.backgroundIntensity=this.backgroundIntensity),e}}class ec{constructor(t,e){this.isInterleavedBuffer=!0,this.array=t,this.stride=e,this.count=void 0!==t?t.length/e:0,this.usage=bn,this._updateRange={offset:0,count:-1},this.updateRanges=[],this.version=0,this.uuid=kn()}onUploadCallback(){}set needsUpdate(t){!0===t&&this.version++}get updateRange(){return ai("THREE.InterleavedBuffer: updateRange() is deprecated and will be removed in r169. Use addUpdateRange() instead."),this._updateRange}setUsage(t){return this.usage=t,this}addUpdateRange(t,e){this.updateRanges.push({start:t,count:e})}clearUpdateRanges(){this.updateRanges.length=0}copy(t){return this.array=new t.array.constructor(t.array),this.count=t.count,this.stride=t.stride,this.usage=t.usage,this}copyAt(t,e,n){t*=this.stride,n*=e.stride;for(let i=0,r=this.stride;it.far||e.push({distance:o,point:ac.clone(),uv:kr.getInterpolation(ac,dc,pc,mc,fc,gc,_c,new Kn),face:null,object:this})}copy(t,e){return super.copy(t,e),void 0!==t.center&&this.center.copy(t.center),this.material=t.material,this}}function xc(t,e,n,i,r,s){cc.subVectors(t,n).addScalar(.5).multiply(i),void 0!==r?(hc.x=s*cc.x-r*cc.y,hc.y=r*cc.x+s*cc.y):hc.copy(cc),t.copy(e),t.x+=hc.x,t.y+=hc.y,t.applyMatrix4(uc)}const yc=new Pi,Mc=new Pi;class Sc extends Lr{constructor(){super(),this._currentLevel=0,this.type="LOD",Object.defineProperties(this,{levels:{enumerable:!0,value:[]},isLOD:{value:!0}}),this.autoUpdate=!0}copy(t){super.copy(t,!1);const e=t.levels;for(let t=0,n=e.length;t0){let n,i;for(n=1,i=e.length;n0){yc.setFromMatrixPosition(this.matrixWorld);const n=t.ray.origin.distanceTo(yc);this.getObjectForDistance(n).raycast(t,e)}}update(t){const e=this.levels;if(e.length>1){yc.setFromMatrixPosition(t.matrixWorld),Mc.setFromMatrixPosition(this.matrixWorld);const n=yc.distanceTo(Mc)/t.zoom;let i,r;for(e[0].object.visible=!0,i=1,r=e.length;i=t))break;e[i-1].object.visible=!1,e[i].object.visible=!0}for(this._currentLevel=i-1;i=n.length&&n.push({start:-1,count:-1,z:-1});const r=n[this.index];i.push(r),this.index++,r.start=t.start,r.count=t.count,r.z=e}reset(){this.list.length=0,this.index=0}}const Jc="batchId",Kc=new ar,$c=new ar,Qc=new ar,th=new ar,eh=new ha,nh=new Ui,ih=new Ki,rh=new Pi,sh=new Zc,ah=new Vs,oh=[];function lh(t,e,n=0){const i=e.itemSize;if(t.isInterleavedBufferAttribute||t.array.constructor!==e.array.constructor){const r=t.count;for(let s=0;s65536?new Uint32Array(r):new Uint16Array(r);e.setIndex(new ss(t,1))}const s=i>65536?new Uint32Array(n):new Uint16Array(n);e.setAttribute(Jc,new ss(s,1)),this._geometryInitialized=!0}}_validateGeometry(t){if(t.getAttribute(Jc))throw new Error(`BatchedMesh: Geometry cannot use attribute "${Jc}"`);const e=this.geometry;if(Boolean(t.getIndex())!==Boolean(e.getIndex()))throw new Error('BatchedMesh: All geometries must consistently have "index".');for(const n in e.attributes){if(n===Jc)continue;if(!t.hasAttribute(n))throw new Error(`BatchedMesh: Added geometry missing "${n}". All geometries must have consistent attributes.`);const i=t.getAttribute(n),r=e.getAttribute(n);if(i.itemSize!==r.itemSize||i.normalized!==r.normalized)throw new Error("BatchedMesh: All attributes must have a consistent itemSize and normalized value.")}}setCustomSort(t){return this.customSort=t,this}computeBoundingBox(){null===this.boundingBox&&(this.boundingBox=new Ui);const t=this._geometryCount,e=this.boundingBox,n=this._active;e.makeEmpty();for(let i=0;i=this._maxGeometryCount)throw new Error("BatchedMesh: Maximum geometry count reached.");const i={vertexStart:-1,vertexCount:-1,indexStart:-1,indexCount:-1};let r=null;const s=this._reservedRanges,a=this._drawRanges,o=this._bounds;0!==this._geometryCount&&(r=s[s.length-1]),i.vertexCount=-1===e?t.getAttribute("position").count:e,i.vertexStart=null===r?0:r.vertexStart+r.vertexCount;const l=t.getIndex(),c=null!==l;if(c&&(i.indexCount=-1===n?l.count:n,i.indexStart=null===r?0:r.indexStart+r.indexCount),-1!==i.indexStart&&i.indexStart+i.indexCount>this._maxIndexCount||i.vertexStart+i.vertexCount>this._maxVertexCount)throw new Error("BatchedMesh: Reserved space request exceeds the maximum buffer size.");const h=this._visibility,u=this._active,d=this._matricesTexture,p=this._matricesTexture.image.data;h.push(!0),u.push(!0);const m=this._geometryCount;this._geometryCount++,Qc.toArray(p,16*m),d.needsUpdate=!0,s.push(i),a.push({start:c?i.indexStart:i.vertexStart,count:-1}),o.push({boxInitialized:!1,box:new Ui,sphereInitialized:!1,sphere:new Ki});const f=this.geometry.getAttribute(Jc);for(let t=0;t=this._geometryCount)throw new Error("BatchedMesh: Maximum geometry count reached.");this._validateGeometry(e);const n=this.geometry,i=null!==n.getIndex(),r=n.getIndex(),s=e.getIndex(),a=this._reservedRanges[t];if(i&&s.count>a.indexCount||e.attributes.position.count>a.vertexCount)throw new Error("BatchedMesh: Reserved space not large enough for provided geometry.");const o=a.vertexStart,l=a.vertexCount;for(const t in n.attributes){if(t===Jc)continue;const i=e.getAttribute(t),r=n.getAttribute(t);lh(i,r,o);const s=i.itemSize;for(let t=i.count,e=l;t=e.length||!1===e[t]||(e[t]=!1,this._visibilityChanged=!0),this}getBoundingBoxAt(t,e){if(!1===this._active[t])return null;const n=this._bounds[t],i=n.box,r=this.geometry;if(!1===n.boxInitialized){i.makeEmpty();const e=r.index,s=r.attributes.position,a=this._drawRanges[t];for(let t=a.start,n=a.start+a.count;t=this._geometryCount||!1===n[t]||(e.toArray(r,16*t),i.needsUpdate=!0),this}getMatrixAt(t,e){const n=this._active,i=this._matricesTexture.image.data;return t>=this._geometryCount||!1===n[t]?null:e.fromArray(i,16*t)}setVisibleAt(t,e){const n=this._visibility,i=this._active;return t>=this._geometryCount||!1===i[t]||n[t]===e||(n[t]=e,this._visibilityChanged=!0),this}getVisibleAt(t){const e=this._visibility,n=this._active;return!(t>=this._geometryCount||!1===n[t])&&e[t]}raycast(t,e){const n=this._visibility,i=this._active,r=this._drawRanges,s=this._geometryCount,a=this.matrixWorld,o=this.geometry;ah.material=this.material,ah.geometry.index=o.index,ah.geometry.attributes=o.attributes,null===ah.geometry.boundingBox&&(ah.geometry.boundingBox=new Ui),null===ah.geometry.boundingSphere&&(ah.geometry.boundingSphere=new Ki);for(let o=0;o({...t}))),this._reservedRanges=t._reservedRanges.map((t=>({...t}))),this._visibility=t._visibility.slice(),this._active=t._active.slice(),this._bounds=t._bounds.map((t=>({boxInitialized:t.boxInitialized,box:t.box.clone(),sphereInitialized:t.sphereInitialized,sphere:t.sphere.clone()}))),this._maxGeometryCount=t._maxGeometryCount,this._maxVertexCount=t._maxVertexCount,this._maxIndexCount=t._maxIndexCount,this._geometryInitialized=t._geometryInitialized,this._geometryCount=t._geometryCount,this._multiDrawCounts=t._multiDrawCounts.slice(),this._multiDrawStarts=t._multiDrawStarts.slice(),this._matricesTexture=t._matricesTexture.clone(),this._matricesTexture.image.data=this._matricesTexture.image.slice(),this}dispose(){return this.geometry.dispose(),this._matricesTexture.dispose(),this._matricesTexture=null,this}onBeforeRender(t,e,n,i,r){if(!this._visibilityChanged&&!this.perObjectFrustumCulled&&!this.sortObjects)return;const s=i.getIndex(),a=null===s?1:s.array.BYTES_PER_ELEMENT,o=this._active,l=this._visibility,c=this._multiDrawStarts,h=this._multiDrawCounts,u=this._drawRanges,d=this.perObjectFrustumCulled;d&&(th.multiplyMatrices(n.projectionMatrix,n.matrixWorldInverse).multiply(this.matrixWorld),eh.setFromProjectionMatrix(th,t.coordinateSystem));let p=0;if(this.sortObjects){$c.copy(this.matrixWorld).invert(),rh.setFromMatrixPosition(n.matrixWorld).applyMatrix4($c);for(let t=0,e=l.length;to)continue;u.applyMatrix4(this.matrixWorld);const s=t.ray.origin.distanceTo(u);st.far||e.push({distance:s,point:h.clone().applyMatrix4(this.matrixWorld),index:n,face:null,faceIndex:null,object:this})}}else{for(let n=Math.max(0,s.start),i=Math.min(m.count,s.start+s.count)-1;no)continue;u.applyMatrix4(this.matrixWorld);const i=t.ray.origin.distanceTo(u);it.far||e.push({distance:i,point:h.clone().applyMatrix4(this.matrixWorld),index:n,face:null,faceIndex:null,object:this})}}}updateMorphTargets(){const t=this.geometry.morphAttributes,e=Object.keys(t);if(e.length>0){const n=t[e[0]];if(void 0!==n){this.morphTargetInfluences=[],this.morphTargetDictionary={};for(let t=0,e=n.length;t0){const n=t[e[0]];if(void 0!==n){this.morphTargetInfluences=[],this.morphTargetDictionary={};for(let t=0,e=n.length;tr.far)return;s.push({distance:l,distanceToRay:Math.sqrt(o),point:n,index:e,face:null,object:a})}}class Rh extends yi{constructor(t,e,n,i,r,s,a,o,l){super(t,e,n,i,r,s,a,o,l),this.isVideoTexture=!0,this.minFilter=void 0!==s?s:yt,this.magFilter=void 0!==r?r:yt,this.generateMipmaps=!1;const c=this;"requestVideoFrameCallback"in t&&t.requestVideoFrameCallback((function e(){c.needsUpdate=!0,t.requestVideoFrameCallback(e)}))}clone(){return new this.constructor(this.image).copy(this)}update(){const t=this.image;!1==="requestVideoFrameCallback"in t&&t.readyState>=t.HAVE_CURRENT_DATA&&(this.needsUpdate=!0)}}class Ch extends yi{constructor(t,e){super({width:t,height:e}),this.isFramebufferTexture=!0,this.magFilter=ft,this.minFilter=ft,this.generateMipmaps=!1,this.needsUpdate=!0}}class Ph extends yi{constructor(t,e,n,i,r,s,a,o,l,c,h,u){super(null,s,a,o,l,c,i,r,h,u),this.isCompressedTexture=!0,this.image={width:e,height:n},this.mipmaps=t,this.flipY=!1,this.generateMipmaps=!1}}class Lh extends Ph{constructor(t,e,n,i,r,s){super(t,e,n,r,s),this.isCompressedArrayTexture=!0,this.image.depth=i,this.wrapR=pt}}class Ih extends Ph{constructor(t,e,n){super(void 0,t[0].width,t[0].height,e,n,ot),this.isCompressedCubeTexture=!0,this.isCubeTexture=!0,this.image=t}}class Uh extends yi{constructor(t,e,n,i,r,s,a,o,l){super(t,e,n,i,r,s,a,o,l),this.isCanvasTexture=!0,this.needsUpdate=!0}}class Nh{constructor(){this.type="Curve",this.arcLengthDivisions=200}getPoint(){return console.warn("THREE.Curve: .getPoint() not implemented."),null}getPointAt(t,e){const n=this.getUtoTmapping(t);return this.getPoint(n,e)}getPoints(t=5){const e=[];for(let n=0;n<=t;n++)e.push(this.getPoint(n/t));return e}getSpacedPoints(t=5){const e=[];for(let n=0;n<=t;n++)e.push(this.getPointAt(n/t));return e}getLength(){const t=this.getLengths();return t[t.length-1]}getLengths(t=this.arcLengthDivisions){if(this.cacheArcLengths&&this.cacheArcLengths.length===t+1&&!this.needsUpdate)return this.cacheArcLengths;this.needsUpdate=!1;const e=[];let n,i=this.getPoint(0),r=0;e.push(0);for(let s=1;s<=t;s++)n=this.getPoint(s/t),r+=n.distanceTo(i),e.push(r),i=n;return this.cacheArcLengths=e,e}updateArcLengths(){this.needsUpdate=!0,this.getLengths()}getUtoTmapping(t,e){const n=this.getLengths();let i=0;const r=n.length;let s;s=e||t*n[r-1];let a,o=0,l=r-1;for(;o<=l;)if(i=Math.floor(o+(l-o)/2),a=n[i]-s,a<0)o=i+1;else{if(!(a>0)){l=i;break}l=i-1}if(i=l,n[i]===s)return i/(r-1);const c=n[i];return(i+(s-c)/(n[i+1]-c))/(r-1)}getTangent(t,e){const n=1e-4;let i=t-n,r=t+n;i<0&&(i=0),r>1&&(r=1);const s=this.getPoint(i),a=this.getPoint(r),o=e||(s.isVector2?new Kn:new Pi);return o.copy(a).sub(s).normalize(),o}getTangentAt(t,e){const n=this.getUtoTmapping(t);return this.getTangent(n,e)}computeFrenetFrames(t,e){const n=new Pi,i=[],r=[],s=[],a=new Pi,o=new ar;for(let e=0;e<=t;e++){const n=e/t;i[e]=this.getTangentAt(n,new Pi)}r[0]=new Pi,s[0]=new Pi;let l=Number.MAX_VALUE;const c=Math.abs(i[0].x),h=Math.abs(i[0].y),u=Math.abs(i[0].z);c<=l&&(l=c,n.set(1,0,0)),h<=l&&(l=h,n.set(0,1,0)),u<=l&&n.set(0,0,1),a.crossVectors(i[0],n).normalize(),r[0].crossVectors(i[0],a),s[0].crossVectors(i[0],r[0]);for(let e=1;e<=t;e++){if(r[e]=r[e-1].clone(),s[e]=s[e-1].clone(),a.crossVectors(i[e-1],i[e]),a.length()>Number.EPSILON){a.normalize();const t=Math.acos(Gn(i[e-1].dot(i[e]),-1,1));r[e].applyMatrix4(o.makeRotationAxis(a,t))}s[e].crossVectors(i[e],r[e])}if(!0===e){let e=Math.acos(Gn(r[0].dot(r[t]),-1,1));e/=t,i[0].dot(a.crossVectors(r[0],r[t]))>0&&(e=-e);for(let n=1;n<=t;n++)r[n].applyMatrix4(o.makeRotationAxis(i[n],e*n)),s[n].crossVectors(i[n],r[n])}return{tangents:i,normals:r,binormals:s}}clone(){return(new this.constructor).copy(this)}copy(t){return this.arcLengthDivisions=t.arcLengthDivisions,this}toJSON(){const t={metadata:{version:4.6,type:"Curve",generator:"Curve.toJSON"}};return t.arcLengthDivisions=this.arcLengthDivisions,t.type=this.type,t}fromJSON(t){return this.arcLengthDivisions=t.arcLengthDivisions,this}}class Dh extends Nh{constructor(t=0,e=0,n=1,i=1,r=0,s=2*Math.PI,a=!1,o=0){super(),this.isEllipseCurve=!0,this.type="EllipseCurve",this.aX=t,this.aY=e,this.xRadius=n,this.yRadius=i,this.aStartAngle=r,this.aEndAngle=s,this.aClockwise=a,this.aRotation=o}getPoint(t,e){const n=e||new Kn,i=2*Math.PI;let r=this.aEndAngle-this.aStartAngle;const s=Math.abs(r)i;)r-=i;r0?0:(Math.floor(Math.abs(l)/r)+1)*r:0===c&&l===r-1&&(l=r-2,c=1),this.closed||l>0?a=i[(l-1)%r]:(Bh.subVectors(i[0],i[1]).add(i[0]),a=Bh);const h=i[l%r],u=i[(l+1)%r];if(this.closed||l+2i.length-2?i.length-1:s+1],h=i[s>i.length-3?i.length-1:s+2];return n.set(Gh(a,o.x,l.x,c.x,h.x),Gh(a,o.y,l.y,c.y,h.y)),n}copy(t){super.copy(t),this.points=[];for(let e=0,n=t.points.length;e=n){const t=i[r]-n,s=this.curves[r],a=s.getLength(),o=0===a?0:1-t/a;return s.getPointAt(o,e)}r++}return null}getLength(){const t=this.getCurveLengths();return t[t.length-1]}updateArcLengths(){this.needsUpdate=!0,this.cacheLengths=null,this.getCurveLengths()}getCurveLengths(){if(this.cacheLengths&&this.cacheLengths.length===this.curves.length)return this.cacheLengths;const t=[];let e=0;for(let n=0,i=this.curves.length;n1&&!e[e.length-1].equals(e[0])&&e.push(e[0]),e}copy(t){super.copy(t),this.curves=[];for(let e=0,n=t.curves.length;e0){const t=l.getPoint(0);t.equals(this.currentPoint)||this.lineTo(t.x,t.y)}this.curves.push(l);const c=l.getPoint(1);return this.currentPoint.copy(c),this}copy(t){return super.copy(t),this.currentPoint.copy(t.currentPoint),this}toJSON(){const t=super.toJSON();return t.currentPoint=this.currentPoint.toArray(),t}fromJSON(t){return super.fromJSON(t),this.currentPoint.fromArray(t.currentPoint),this}}class nu extends bs{constructor(t=[new Kn(0,-.5),new Kn(.5,0),new Kn(0,.5)],e=12,n=0,i=2*Math.PI){super(),this.type="LatheGeometry",this.parameters={points:t,segments:e,phiStart:n,phiLength:i},e=Math.floor(e),i=Gn(i,0,2*Math.PI);const r=[],s=[],a=[],o=[],l=[],c=1/e,h=new Pi,u=new Kn,d=new Pi,p=new Pi,m=new Pi;let f=0,g=0;for(let e=0;e<=t.length-1;e++)switch(e){case 0:f=t[e+1].x-t[e].x,g=t[e+1].y-t[e].y,d.x=1*g,d.y=-f,d.z=0*g,m.copy(d),d.normalize(),o.push(d.x,d.y,d.z);break;case t.length-1:o.push(m.x,m.y,m.z);break;default:f=t[e+1].x-t[e].x,g=t[e+1].y-t[e].y,d.x=1*g,d.y=-f,d.z=0*g,p.copy(d),d.x+=m.x,d.y+=m.y,d.z+=m.z,d.normalize(),o.push(d.x,d.y,d.z),m.copy(p)}for(let r=0;r<=e;r++){const d=n+r*c*i,p=Math.sin(d),m=Math.cos(d);for(let n=0;n<=t.length-1;n++){h.x=t[n].x*p,h.y=t[n].y,h.z=t[n].x*m,s.push(h.x,h.y,h.z),u.x=r/e,u.y=n/(t.length-1),a.push(u.x,u.y);const i=o[3*n+0]*p,c=o[3*n+1],d=o[3*n+0]*m;l.push(i,c,d)}}for(let n=0;n0&&_(!0),e>0&&_(!1)),this.setIndex(c),this.setAttribute("position",new ms(h,3)),this.setAttribute("normal",new ms(u,3)),this.setAttribute("uv",new ms(d,2))}copy(t){return super.copy(t),this.parameters=Object.assign({},t.parameters),this}static fromJSON(t){return new su(t.radiusTop,t.radiusBottom,t.height,t.radialSegments,t.heightSegments,t.openEnded,t.thetaStart,t.thetaLength)}}class au extends su{constructor(t=1,e=1,n=32,i=1,r=!1,s=0,a=2*Math.PI){super(0,t,e,n,i,r,s,a),this.type="ConeGeometry",this.parameters={radius:t,height:e,radialSegments:n,heightSegments:i,openEnded:r,thetaStart:s,thetaLength:a}}static fromJSON(t){return new au(t.radius,t.height,t.radialSegments,t.heightSegments,t.openEnded,t.thetaStart,t.thetaLength)}}class ou extends bs{constructor(t=[],e=[],n=1,i=0){super(),this.type="PolyhedronGeometry",this.parameters={vertices:t,indices:e,radius:n,detail:i};const r=[],s=[];function a(t,e,n,i){const r=i+1,s=[];for(let i=0;i<=r;i++){s[i]=[];const a=t.clone().lerp(n,i/r),o=e.clone().lerp(n,i/r),l=r-i;for(let t=0;t<=l;t++)s[i][t]=0===t&&i===r?a:a.clone().lerp(o,t/l)}for(let t=0;t.9&&a<.1&&(e<.2&&(s[t+0]+=1),n<.2&&(s[t+2]+=1),i<.2&&(s[t+4]+=1))}}()}(),this.setAttribute("position",new ms(r,3)),this.setAttribute("normal",new ms(r.slice(),3)),this.setAttribute("uv",new ms(s,2)),0===i?this.computeVertexNormals():this.normalizeNormals()}copy(t){return super.copy(t),this.parameters=Object.assign({},t.parameters),this}static fromJSON(t){return new ou(t.vertices,t.indices,t.radius,t.details)}}class lu extends ou{constructor(t=1,e=0){const n=(1+Math.sqrt(5))/2,i=1/n;super([-1,-1,-1,-1,-1,1,-1,1,-1,-1,1,1,1,-1,-1,1,-1,1,1,1,-1,1,1,1,0,-i,-n,0,-i,n,0,i,-n,0,i,n,-i,-n,0,-i,n,0,i,-n,0,i,n,0,-n,0,-i,n,0,-i,-n,0,i,n,0,i],[3,11,7,3,7,15,3,15,13,7,19,17,7,17,6,7,6,15,17,4,8,17,8,10,17,10,6,8,0,16,8,16,2,8,2,10,0,12,1,0,1,18,0,18,16,6,10,2,6,2,13,6,13,15,2,16,18,2,18,3,2,3,13,18,1,9,18,9,11,18,11,3,4,14,12,4,12,0,4,0,8,11,9,5,11,5,19,11,19,7,19,5,14,19,14,4,19,4,17,1,12,14,1,14,5,1,5,9],t,e),this.type="DodecahedronGeometry",this.parameters={radius:t,detail:e}}static fromJSON(t){return new lu(t.radius,t.detail)}}const cu=new Pi,hu=new Pi,uu=new Pi,du=new kr;class pu extends bs{constructor(t=null,e=1){if(super(),this.type="EdgesGeometry",this.parameters={geometry:t,thresholdAngle:e},null!==t){const n=4,i=Math.pow(10,n),r=Math.cos(Hn*e),s=t.getIndex(),a=t.getAttribute("position"),o=s?s.count:a.count,l=[0,0,0],c=["a","b","c"],h=new Array(3),u={},d=[];for(let t=0;t80*n){o=c=t[0],l=h=t[1];for(let e=n;ec&&(c=u),d>h&&(h=d);p=Math.max(c-o,h-l),p=0!==p?32767/p:0}return vu(s,a,n,o,l,p,0),a};function gu(t,e,n,i,r){let s,a;if(r===function(t,e,n,i){let r=0;for(let s=e,a=n-i;s0)for(s=e;s=e;s-=i)a=Fu(s,t[s],t[s+1],a);return a&&Lu(a,a.next)&&(Bu(a),a=a.next),a}function _u(t,e){if(!t)return t;e||(e=t);let n,i=t;do{if(n=!1,i.steiner||!Lu(i,i.next)&&0!==Pu(i.prev,i,i.next))i=i.next;else{if(Bu(i),i=e=i.prev,i===i.next)break;n=!0}}while(n||i!==e);return e}function vu(t,e,n,i,r,s,a){if(!t)return;!a&&s&&function(t,e,n,i){let r=t;do{0===r.z&&(r.z=wu(r.x,r.y,e,n,i)),r.prevZ=r.prev,r.nextZ=r.next,r=r.next}while(r!==t);r.prevZ.nextZ=null,r.prevZ=null,function(t){let e,n,i,r,s,a,o,l,c=1;do{for(n=t,t=null,s=null,a=0;n;){for(a++,i=n,o=0,e=0;e0||l>0&&i;)0!==o&&(0===l||!i||n.z<=i.z)?(r=n,n=n.nextZ,o--):(r=i,i=i.nextZ,l--),s?s.nextZ=r:t=r,r.prevZ=s,s=r;n=i}s.nextZ=null,c*=2}while(a>1)}(r)}(t,i,r,s);let o,l,c=t;for(;t.prev!==t.next;)if(o=t.prev,l=t.next,s?yu(t,i,r,s):xu(t))e.push(o.i/n|0),e.push(t.i/n|0),e.push(l.i/n|0),Bu(t),t=l.next,c=l.next;else if((t=l)===c){a?1===a?vu(t=Mu(_u(t),e,n),e,n,i,r,s,2):2===a&&Su(t,e,n,i,r,s):vu(_u(t),e,n,i,r,s,1);break}}function xu(t){const e=t.prev,n=t,i=t.next;if(Pu(e,n,i)>=0)return!1;const r=e.x,s=n.x,a=i.x,o=e.y,l=n.y,c=i.y,h=rs?r>a?r:a:s>a?s:a,p=o>l?o>c?o:c:l>c?l:c;let m=i.next;for(;m!==e;){if(m.x>=h&&m.x<=d&&m.y>=u&&m.y<=p&&Ru(r,o,s,l,a,c,m.x,m.y)&&Pu(m.prev,m,m.next)>=0)return!1;m=m.next}return!0}function yu(t,e,n,i){const r=t.prev,s=t,a=t.next;if(Pu(r,s,a)>=0)return!1;const o=r.x,l=s.x,c=a.x,h=r.y,u=s.y,d=a.y,p=ol?o>c?o:c:l>c?l:c,g=h>u?h>d?h:d:u>d?u:d,_=wu(p,m,e,n,i),v=wu(f,g,e,n,i);let x=t.prevZ,y=t.nextZ;for(;x&&x.z>=_&&y&&y.z<=v;){if(x.x>=p&&x.x<=f&&x.y>=m&&x.y<=g&&x!==r&&x!==a&&Ru(o,h,l,u,c,d,x.x,x.y)&&Pu(x.prev,x,x.next)>=0)return!1;if(x=x.prevZ,y.x>=p&&y.x<=f&&y.y>=m&&y.y<=g&&y!==r&&y!==a&&Ru(o,h,l,u,c,d,y.x,y.y)&&Pu(y.prev,y,y.next)>=0)return!1;y=y.nextZ}for(;x&&x.z>=_;){if(x.x>=p&&x.x<=f&&x.y>=m&&x.y<=g&&x!==r&&x!==a&&Ru(o,h,l,u,c,d,x.x,x.y)&&Pu(x.prev,x,x.next)>=0)return!1;x=x.prevZ}for(;y&&y.z<=v;){if(y.x>=p&&y.x<=f&&y.y>=m&&y.y<=g&&y!==r&&y!==a&&Ru(o,h,l,u,c,d,y.x,y.y)&&Pu(y.prev,y,y.next)>=0)return!1;y=y.nextZ}return!0}function Mu(t,e,n){let i=t;do{const r=i.prev,s=i.next.next;!Lu(r,s)&&Iu(r,i,i.next,s)&&Du(r,s)&&Du(s,r)&&(e.push(r.i/n|0),e.push(i.i/n|0),e.push(s.i/n|0),Bu(i),Bu(i.next),i=t=s),i=i.next}while(i!==t);return _u(i)}function Su(t,e,n,i,r,s){let a=t;do{let t=a.next.next;for(;t!==a.prev;){if(a.i!==t.i&&Cu(a,t)){let o=Ou(a,t);return a=_u(a,a.next),o=_u(o,o.next),vu(a,e,n,i,r,s,0),void vu(o,e,n,i,r,s,0)}t=t.next}a=a.next}while(a!==t)}function bu(t,e){return t.x-e.x}function Eu(t,e){const n=function(t,e){let n,i=e,r=-1/0;const s=t.x,a=t.y;do{if(a<=i.y&&a>=i.next.y&&i.next.y!==i.y){const t=i.x+(a-i.y)*(i.next.x-i.x)/(i.next.y-i.y);if(t<=s&&t>r&&(r=t,n=i.x=i.x&&i.x>=l&&s!==i.x&&Ru(an.x||i.x===n.x&&Tu(n,i)))&&(n=i,u=h)),i=i.next}while(i!==o);return n}(t,e);if(!n)return e;const i=Ou(n,t);return _u(i,i.next),_u(n,n.next)}function Tu(t,e){return Pu(t.prev,t,e.prev)<0&&Pu(e.next,t,t.next)<0}function wu(t,e,n,i,r){return(t=1431655765&((t=858993459&((t=252645135&((t=16711935&((t=(t-n)*r|0)|t<<8))|t<<4))|t<<2))|t<<1))|(e=1431655765&((e=858993459&((e=252645135&((e=16711935&((e=(e-i)*r|0)|e<<8))|e<<4))|e<<2))|e<<1))<<1}function Au(t){let e=t,n=t;do{(e.x=(t-a)*(s-o)&&(t-a)*(i-o)>=(n-a)*(e-o)&&(n-a)*(s-o)>=(r-a)*(i-o)}function Cu(t,e){return t.next.i!==e.i&&t.prev.i!==e.i&&!function(t,e){let n=t;do{if(n.i!==t.i&&n.next.i!==t.i&&n.i!==e.i&&n.next.i!==e.i&&Iu(n,n.next,t,e))return!0;n=n.next}while(n!==t);return!1}(t,e)&&(Du(t,e)&&Du(e,t)&&function(t,e){let n=t,i=!1;const r=(t.x+e.x)/2,s=(t.y+e.y)/2;do{n.y>s!=n.next.y>s&&n.next.y!==n.y&&r<(n.next.x-n.x)*(s-n.y)/(n.next.y-n.y)+n.x&&(i=!i),n=n.next}while(n!==t);return i}(t,e)&&(Pu(t.prev,t,e.prev)||Pu(t,e.prev,e))||Lu(t,e)&&Pu(t.prev,t,t.next)>0&&Pu(e.prev,e,e.next)>0)}function Pu(t,e,n){return(e.y-t.y)*(n.x-e.x)-(e.x-t.x)*(n.y-e.y)}function Lu(t,e){return t.x===e.x&&t.y===e.y}function Iu(t,e,n,i){const r=Nu(Pu(t,e,n)),s=Nu(Pu(t,e,i)),a=Nu(Pu(n,i,t)),o=Nu(Pu(n,i,e));return r!==s&&a!==o||(!(0!==r||!Uu(t,n,e))||(!(0!==s||!Uu(t,i,e))||(!(0!==a||!Uu(n,t,i))||!(0!==o||!Uu(n,e,i)))))}function Uu(t,e,n){return e.x<=Math.max(t.x,n.x)&&e.x>=Math.min(t.x,n.x)&&e.y<=Math.max(t.y,n.y)&&e.y>=Math.min(t.y,n.y)}function Nu(t){return t>0?1:t<0?-1:0}function Du(t,e){return Pu(t.prev,t,t.next)<0?Pu(t,e,t.next)>=0&&Pu(t,t.prev,e)>=0:Pu(t,e,t.prev)<0||Pu(t,t.next,e)<0}function Ou(t,e){const n=new zu(t.i,t.x,t.y),i=new zu(e.i,e.x,e.y),r=t.next,s=e.prev;return t.next=e,e.prev=t,n.next=r,r.prev=n,i.next=n,n.prev=i,s.next=i,i.prev=s,i}function Fu(t,e,n,i){const r=new zu(t,e,n);return i?(r.next=i.next,r.prev=i,i.next.prev=r,i.next=r):(r.prev=r,r.next=r),r}function Bu(t){t.next.prev=t.prev,t.prev.next=t.next,t.prevZ&&(t.prevZ.nextZ=t.nextZ),t.nextZ&&(t.nextZ.prevZ=t.prevZ)}function zu(t,e,n){this.i=t,this.x=e,this.y=n,this.prev=null,this.next=null,this.z=0,this.prevZ=null,this.nextZ=null,this.steiner=!1}class Hu{static area(t){const e=t.length;let n=0;for(let i=e-1,r=0;r2&&t[e-1].equals(t[0])&&t.pop()}function ku(t,e){for(let n=0;nNumber.EPSILON){const u=Math.sqrt(h),d=Math.sqrt(l*l+c*c),p=e.x-o/u,m=e.y+a/u,f=((n.x-c/d-p)*c-(n.y+l/d-m)*l)/(a*c-o*l);i=p+a*f-t.x,r=m+o*f-t.y;const g=i*i+r*r;if(g<=2)return new Kn(i,r);s=Math.sqrt(g/2)}else{let t=!1;a>Number.EPSILON?l>Number.EPSILON&&(t=!0):a<-Number.EPSILON?l<-Number.EPSILON&&(t=!0):Math.sign(o)===Math.sign(c)&&(t=!0),t?(i=-o,r=a,s=Math.sqrt(h)):(i=a,r=o,s=Math.sqrt(h/2))}return new Kn(i/s,r/s)}const L=[];for(let t=0,e=w.length,n=e-1,i=t+1;t=0;t--){const e=t/p,n=h*Math.cos(e*Math.PI/2),i=u*Math.sin(e*Math.PI/2)+d;for(let t=0,e=w.length;t=0;){const i=n;let r=n-1;r<0&&(r=t.length-1);for(let t=0,n=o+2*p;t0)&&d.push(e,r,l),(t!==n-1||o0!=t>0&&this.version++,this._anisotropy=t}get clearcoat(){return this._clearcoat}set clearcoat(t){this._clearcoat>0!=t>0&&this.version++,this._clearcoat=t}get iridescence(){return this._iridescence}set iridescence(t){this._iridescence>0!=t>0&&this.version++,this._iridescence=t}get sheen(){return this._sheen}set sheen(t){this._sheen>0!=t>0&&this.version++,this._sheen=t}get transmission(){return this._transmission}set transmission(t){this._transmission>0!=t>0&&this.version++,this._transmission=t}copy(t){return super.copy(t),this.defines={STANDARD:"",PHYSICAL:""},this.anisotropy=t.anisotropy,this.anisotropyRotation=t.anisotropyRotation,this.anisotropyMap=t.anisotropyMap,this.clearcoat=t.clearcoat,this.clearcoatMap=t.clearcoatMap,this.clearcoatRoughness=t.clearcoatRoughness,this.clearcoatRoughnessMap=t.clearcoatRoughnessMap,this.clearcoatNormalMap=t.clearcoatNormalMap,this.clearcoatNormalScale.copy(t.clearcoatNormalScale),this.ior=t.ior,this.iridescence=t.iridescence,this.iridescenceMap=t.iridescenceMap,this.iridescenceIOR=t.iridescenceIOR,this.iridescenceThicknessRange=[...t.iridescenceThicknessRange],this.iridescenceThicknessMap=t.iridescenceThicknessMap,this.sheen=t.sheen,this.sheenColor.copy(t.sheenColor),this.sheenColorMap=t.sheenColorMap,this.sheenRoughness=t.sheenRoughness,this.sheenRoughnessMap=t.sheenRoughnessMap,this.transmission=t.transmission,this.transmissionMap=t.transmissionMap,this.thickness=t.thickness,this.thicknessMap=t.thicknessMap,this.attenuationDistance=t.attenuationDistance,this.attenuationColor.copy(t.attenuationColor),this.specularIntensity=t.specularIntensity,this.specularIntensityMap=t.specularIntensityMap,this.specularColor.copy(t.specularColor),this.specularColorMap=t.specularColorMap,this}}class od extends Jr{constructor(t){super(),this.isMeshPhongMaterial=!0,this.type="MeshPhongMaterial",this.color=new qr(16777215),this.specular=new qr(1118481),this.shininess=30,this.map=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.emissive=new qr(0),this.emissiveIntensity=1,this.emissiveMap=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=0,this.normalScale=new Kn(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.specularMap=null,this.alphaMap=null,this.envMap=null,this.combine=Y,this.reflectivity=1,this.refractionRatio=.98,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.flatShading=!1,this.fog=!0,this.setValues(t)}copy(t){return super.copy(t),this.color.copy(t.color),this.specular.copy(t.specular),this.shininess=t.shininess,this.map=t.map,this.lightMap=t.lightMap,this.lightMapIntensity=t.lightMapIntensity,this.aoMap=t.aoMap,this.aoMapIntensity=t.aoMapIntensity,this.emissive.copy(t.emissive),this.emissiveMap=t.emissiveMap,this.emissiveIntensity=t.emissiveIntensity,this.bumpMap=t.bumpMap,this.bumpScale=t.bumpScale,this.normalMap=t.normalMap,this.normalMapType=t.normalMapType,this.normalScale.copy(t.normalScale),this.displacementMap=t.displacementMap,this.displacementScale=t.displacementScale,this.displacementBias=t.displacementBias,this.specularMap=t.specularMap,this.alphaMap=t.alphaMap,this.envMap=t.envMap,this.combine=t.combine,this.reflectivity=t.reflectivity,this.refractionRatio=t.refractionRatio,this.wireframe=t.wireframe,this.wireframeLinewidth=t.wireframeLinewidth,this.wireframeLinecap=t.wireframeLinecap,this.wireframeLinejoin=t.wireframeLinejoin,this.flatShading=t.flatShading,this.fog=t.fog,this}}class ld extends Jr{constructor(t){super(),this.isMeshToonMaterial=!0,this.defines={TOON:""},this.type="MeshToonMaterial",this.color=new qr(16777215),this.map=null,this.gradientMap=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.emissive=new qr(0),this.emissiveIntensity=1,this.emissiveMap=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=0,this.normalScale=new Kn(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.alphaMap=null,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.fog=!0,this.setValues(t)}copy(t){return super.copy(t),this.color.copy(t.color),this.map=t.map,this.gradientMap=t.gradientMap,this.lightMap=t.lightMap,this.lightMapIntensity=t.lightMapIntensity,this.aoMap=t.aoMap,this.aoMapIntensity=t.aoMapIntensity,this.emissive.copy(t.emissive),this.emissiveMap=t.emissiveMap,this.emissiveIntensity=t.emissiveIntensity,this.bumpMap=t.bumpMap,this.bumpScale=t.bumpScale,this.normalMap=t.normalMap,this.normalMapType=t.normalMapType,this.normalScale.copy(t.normalScale),this.displacementMap=t.displacementMap,this.displacementScale=t.displacementScale,this.displacementBias=t.displacementBias,this.alphaMap=t.alphaMap,this.wireframe=t.wireframe,this.wireframeLinewidth=t.wireframeLinewidth,this.wireframeLinecap=t.wireframeLinecap,this.wireframeLinejoin=t.wireframeLinejoin,this.fog=t.fog,this}}class cd extends Jr{constructor(t){super(),this.isMeshNormalMaterial=!0,this.type="MeshNormalMaterial",this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=0,this.normalScale=new Kn(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.wireframe=!1,this.wireframeLinewidth=1,this.flatShading=!1,this.setValues(t)}copy(t){return super.copy(t),this.bumpMap=t.bumpMap,this.bumpScale=t.bumpScale,this.normalMap=t.normalMap,this.normalMapType=t.normalMapType,this.normalScale.copy(t.normalScale),this.displacementMap=t.displacementMap,this.displacementScale=t.displacementScale,this.displacementBias=t.displacementBias,this.wireframe=t.wireframe,this.wireframeLinewidth=t.wireframeLinewidth,this.flatShading=t.flatShading,this}}class hd extends Jr{constructor(t){super(),this.isMeshLambertMaterial=!0,this.type="MeshLambertMaterial",this.color=new qr(16777215),this.map=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.emissive=new qr(0),this.emissiveIntensity=1,this.emissiveMap=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=0,this.normalScale=new Kn(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.specularMap=null,this.alphaMap=null,this.envMap=null,this.combine=Y,this.reflectivity=1,this.refractionRatio=.98,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.flatShading=!1,this.fog=!0,this.setValues(t)}copy(t){return super.copy(t),this.color.copy(t.color),this.map=t.map,this.lightMap=t.lightMap,this.lightMapIntensity=t.lightMapIntensity,this.aoMap=t.aoMap,this.aoMapIntensity=t.aoMapIntensity,this.emissive.copy(t.emissive),this.emissiveMap=t.emissiveMap,this.emissiveIntensity=t.emissiveIntensity,this.bumpMap=t.bumpMap,this.bumpScale=t.bumpScale,this.normalMap=t.normalMap,this.normalMapType=t.normalMapType,this.normalScale.copy(t.normalScale),this.displacementMap=t.displacementMap,this.displacementScale=t.displacementScale,this.displacementBias=t.displacementBias,this.specularMap=t.specularMap,this.alphaMap=t.alphaMap,this.envMap=t.envMap,this.combine=t.combine,this.reflectivity=t.reflectivity,this.refractionRatio=t.refractionRatio,this.wireframe=t.wireframe,this.wireframeLinewidth=t.wireframeLinewidth,this.wireframeLinecap=t.wireframeLinecap,this.wireframeLinejoin=t.wireframeLinejoin,this.flatShading=t.flatShading,this.fog=t.fog,this}}class ud extends Jr{constructor(t){super(),this.isMeshMatcapMaterial=!0,this.defines={MATCAP:""},this.type="MeshMatcapMaterial",this.color=new qr(16777215),this.matcap=null,this.map=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=0,this.normalScale=new Kn(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.alphaMap=null,this.flatShading=!1,this.fog=!0,this.setValues(t)}copy(t){return super.copy(t),this.defines={MATCAP:""},this.color.copy(t.color),this.matcap=t.matcap,this.map=t.map,this.bumpMap=t.bumpMap,this.bumpScale=t.bumpScale,this.normalMap=t.normalMap,this.normalMapType=t.normalMapType,this.normalScale.copy(t.normalScale),this.displacementMap=t.displacementMap,this.displacementScale=t.displacementScale,this.displacementBias=t.displacementBias,this.alphaMap=t.alphaMap,this.flatShading=t.flatShading,this.fog=t.fog,this}}class dd extends hh{constructor(t){super(),this.isLineDashedMaterial=!0,this.type="LineDashedMaterial",this.scale=1,this.dashSize=3,this.gapSize=1,this.setValues(t)}copy(t){return super.copy(t),this.scale=t.scale,this.dashSize=t.dashSize,this.gapSize=t.gapSize,this}}function pd(t,e,n){return!t||!n&&t.constructor===e?t:"number"==typeof e.BYTES_PER_ELEMENT?new e(t):Array.prototype.slice.call(t)}function md(t){return ArrayBuffer.isView(t)&&!(t instanceof DataView)}function fd(t){const e=t.length,n=new Array(e);for(let t=0;t!==e;++t)n[t]=t;return n.sort((function(e,n){return t[e]-t[n]})),n}function gd(t,e,n){const i=t.length,r=new t.constructor(i);for(let s=0,a=0;a!==i;++s){const i=n[s]*e;for(let n=0;n!==e;++n)r[a++]=t[i+n]}return r}function _d(t,e,n,i){let r=1,s=t[0];for(;void 0!==s&&void 0===s[i];)s=t[r++];if(void 0===s)return;let a=s[i];if(void 0!==a)if(Array.isArray(a))do{a=s[i],void 0!==a&&(e.push(s.time),n.push.apply(n,a)),s=t[r++]}while(void 0!==s);else if(void 0!==a.toArray)do{a=s[i],void 0!==a&&(e.push(s.time),a.toArray(n,n.length)),s=t[r++]}while(void 0!==s);else do{a=s[i],void 0!==a&&(e.push(s.time),n.push(a)),s=t[r++]}while(void 0!==s)}const vd={convertArray:pd,isTypedArray:md,getKeyframeOrder:fd,sortedArray:gd,flattenJSON:_d,subclip:function(t,e,n,i,r=30){const s=t.clone();s.name=e;const a=[];for(let t=0;t=i)){l.push(e.times[t]);for(let n=0;ns.tracks[t].times[0]&&(o=s.tracks[t].times[0]);for(let t=0;t=i.times[u]){const t=u*l+o,e=t+l-o;d=i.values.slice(t,e)}else{const t=i.createInterpolant(),e=o,n=l-o;t.evaluate(s),d=t.resultBuffer.slice(e,n)}if("quaternion"===r){(new Ci).fromArray(d).normalize().conjugate().toArray(d)}const p=a.times.length;for(let t=0;t=r)break t;{const a=e[1];t=r)break e}s=n,n=0}}for(;n>>1;te;)--s;if(++s,0!==r||s!==i){r>=s&&(s=Math.max(s,1),r=s-1);const t=this.getValueSize();this.times=n.slice(r,s),this.values=this.values.slice(r*t,s*t)}return this}validate(){let t=!0;const e=this.getValueSize();e-Math.floor(e)!=0&&(console.error("THREE.KeyframeTrack: Invalid value size in track.",this),t=!1);const n=this.times,i=this.values,r=n.length;0===r&&(console.error("THREE.KeyframeTrack: Track is empty.",this),t=!1);let s=null;for(let e=0;e!==r;e++){const i=n[e];if("number"==typeof i&&isNaN(i)){console.error("THREE.KeyframeTrack: Time is not a valid number.",this,e,i),t=!1;break}if(null!==s&&s>i){console.error("THREE.KeyframeTrack: Out of order keys.",this,e,i,s),t=!1;break}s=i}if(void 0!==i&&md(i))for(let e=0,n=i.length;e!==n;++e){const n=i[e];if(isNaN(n)){console.error("THREE.KeyframeTrack: Value is not a valid number.",this,e,n),t=!1;break}}return t}optimize(){const t=this.times.slice(),e=this.values.slice(),n=this.getValueSize(),i=this.getInterpolation()===Pe,r=t.length-1;let s=1;for(let a=1;a0){t[s]=t[r];for(let t=r*n,i=s*n,a=0;a!==n;++a)e[i+a]=e[t+a];++s}return s!==t.length?(this.times=t.slice(0,s),this.values=e.slice(0,s*n)):(this.times=t,this.values=e),this}clone(){const t=this.times.slice(),e=this.values.slice(),n=new(0,this.constructor)(this.name,t,e);return n.createInterpolant=this.createInterpolant,n}}bd.prototype.TimeBufferType=Float32Array,bd.prototype.ValueBufferType=Float32Array,bd.prototype.DefaultInterpolation=Ce;class Ed extends bd{}Ed.prototype.ValueTypeName="bool",Ed.prototype.ValueBufferType=Array,Ed.prototype.DefaultInterpolation=Re,Ed.prototype.InterpolantFactoryMethodLinear=void 0,Ed.prototype.InterpolantFactoryMethodSmooth=void 0;class Td extends bd{}Td.prototype.ValueTypeName="color";class wd extends bd{}wd.prototype.ValueTypeName="number";class Ad extends xd{constructor(t,e,n,i){super(t,e,n,i)}interpolate_(t,e,n,i){const r=this.resultBuffer,s=this.sampleValues,a=this.valueSize,o=(n-e)/(i-e);let l=t*a;for(let t=l+a;l!==t;l+=4)Ci.slerpFlat(r,0,s,l-a,s,l,o);return r}}class Rd extends bd{InterpolantFactoryMethodLinear(t){return new Ad(this.times,this.values,this.getValueSize(),t)}}Rd.prototype.ValueTypeName="quaternion",Rd.prototype.DefaultInterpolation=Ce,Rd.prototype.InterpolantFactoryMethodSmooth=void 0;class Cd extends bd{}Cd.prototype.ValueTypeName="string",Cd.prototype.ValueBufferType=Array,Cd.prototype.DefaultInterpolation=Re,Cd.prototype.InterpolantFactoryMethodLinear=void 0,Cd.prototype.InterpolantFactoryMethodSmooth=void 0;class Pd extends bd{}Pd.prototype.ValueTypeName="vector";class Ld{constructor(t,e=-1,n,i=2500){this.name=t,this.tracks=n,this.duration=e,this.blendMode=i,this.uuid=kn(),this.duration<0&&this.resetDuration()}static parse(t){const e=[],n=t.tracks,i=1/(t.fps||1);for(let t=0,r=n.length;t!==r;++t)e.push(Id(n[t]).scale(i));const r=new this(t.name,t.duration,e,t.blendMode);return r.uuid=t.uuid,r}static toJSON(t){const e=[],n=t.tracks,i={name:t.name,duration:t.duration,tracks:e,uuid:t.uuid,blendMode:t.blendMode};for(let t=0,i=n.length;t!==i;++t)e.push(bd.toJSON(n[t]));return i}static CreateFromMorphTargetSequence(t,e,n,i){const r=e.length,s=[];for(let t=0;t1){const t=s[1];let e=i[t];e||(i[t]=e=[]),e.push(n)}}const s=[];for(const t in i)s.push(this.CreateFromMorphTargetSequence(t,i[t],e,n));return s}static parseAnimation(t,e){if(!t)return console.error("THREE.AnimationClip: No animation in JSONLoader data."),null;const n=function(t,e,n,i,r){if(0!==n.length){const s=[],a=[];_d(n,s,a,i),0!==s.length&&r.push(new t(e,s,a))}},i=[],r=t.name||"default",s=t.fps||30,a=t.blendMode;let o=t.length||-1;const l=t.hierarchy||[];for(let t=0;t{e&&e(r),this.manager.itemEnd(t)}),0),r;if(void 0!==Fd[t])return void Fd[t].push({onLoad:e,onProgress:n,onError:i});Fd[t]=[],Fd[t].push({onLoad:e,onProgress:n,onError:i});const s=new Request(t,{headers:new Headers(this.requestHeader),credentials:this.withCredentials?"include":"same-origin"}),a=this.mimeType,o=this.responseType;fetch(s).then((e=>{if(200===e.status||0===e.status){if(0===e.status&&console.warn("THREE.FileLoader: HTTP Status 0 received."),"undefined"==typeof ReadableStream||void 0===e.body||void 0===e.body.getReader)return e;const n=Fd[t],i=e.body.getReader(),r=e.headers.get("Content-Length")||e.headers.get("X-File-Size"),s=r?parseInt(r):0,a=0!==s;let o=0;const l=new ReadableStream({start(t){!function e(){i.read().then((({done:i,value:r})=>{if(i)t.close();else{o+=r.byteLength;const i=new ProgressEvent("progress",{lengthComputable:a,loaded:o,total:s});for(let t=0,e=n.length;t{switch(o){case"arraybuffer":return t.arrayBuffer();case"blob":return t.blob();case"document":return t.text().then((t=>(new DOMParser).parseFromString(t,a)));case"json":return t.json();default:if(void 0===a)return t.text();{const e=/charset="?([^;"\s]*)"?/i.exec(a),n=e&&e[1]?e[1].toLowerCase():void 0,i=new TextDecoder(n);return t.arrayBuffer().then((t=>i.decode(t)))}}})).then((e=>{Ud.add(t,e);const n=Fd[t];delete Fd[t];for(let t=0,i=n.length;t{const n=Fd[t];if(void 0===n)throw this.manager.itemError(t),e;delete Fd[t];for(let t=0,i=n.length;t{this.manager.itemEnd(t)})),this.manager.itemStart(t)}setResponseType(t){return this.responseType=t,this}setMimeType(t){return this.mimeType=t,this}}class Hd extends Od{constructor(t){super(t)}load(t,e,n,i){const r=this,s=new zd(this.manager);s.setPath(this.path),s.setRequestHeader(this.requestHeader),s.setWithCredentials(this.withCredentials),s.load(t,(function(n){try{e(r.parse(JSON.parse(n)))}catch(e){i?i(e):console.error(e),r.manager.itemError(t)}}),n,i)}parse(t){const e=[];for(let n=0;n0:i.vertexColors=t.vertexColors),void 0!==t.uniforms)for(const e in t.uniforms){const r=t.uniforms[e];switch(i.uniforms[e]={},r.type){case"t":i.uniforms[e].value=n(r.value);break;case"c":i.uniforms[e].value=(new qr).setHex(r.value);break;case"v2":i.uniforms[e].value=(new Kn).fromArray(r.value);break;case"v3":i.uniforms[e].value=(new Pi).fromArray(r.value);break;case"v4":i.uniforms[e].value=(new Mi).fromArray(r.value);break;case"m3":i.uniforms[e].value=(new $n).fromArray(r.value);break;case"m4":i.uniforms[e].value=(new ar).fromArray(r.value);break;default:i.uniforms[e].value=r.value}}if(void 0!==t.defines&&(i.defines=t.defines),void 0!==t.vertexShader&&(i.vertexShader=t.vertexShader),void 0!==t.fragmentShader&&(i.fragmentShader=t.fragmentShader),void 0!==t.glslVersion&&(i.glslVersion=t.glslVersion),void 0!==t.extensions)for(const e in t.extensions)i.extensions[e]=t.extensions[e];if(void 0!==t.lights&&(i.lights=t.lights),void 0!==t.clipping&&(i.clipping=t.clipping),void 0!==t.size&&(i.size=t.size),void 0!==t.sizeAttenuation&&(i.sizeAttenuation=t.sizeAttenuation),void 0!==t.map&&(i.map=n(t.map)),void 0!==t.matcap&&(i.matcap=n(t.matcap)),void 0!==t.alphaMap&&(i.alphaMap=n(t.alphaMap)),void 0!==t.bumpMap&&(i.bumpMap=n(t.bumpMap)),void 0!==t.bumpScale&&(i.bumpScale=t.bumpScale),void 0!==t.normalMap&&(i.normalMap=n(t.normalMap)),void 0!==t.normalMapType&&(i.normalMapType=t.normalMapType),void 0!==t.normalScale){let e=t.normalScale;!1===Array.isArray(e)&&(e=[e,e]),i.normalScale=(new Kn).fromArray(e)}return void 0!==t.displacementMap&&(i.displacementMap=n(t.displacementMap)),void 0!==t.displacementScale&&(i.displacementScale=t.displacementScale),void 0!==t.displacementBias&&(i.displacementBias=t.displacementBias),void 0!==t.roughnessMap&&(i.roughnessMap=n(t.roughnessMap)),void 0!==t.metalnessMap&&(i.metalnessMap=n(t.metalnessMap)),void 0!==t.emissiveMap&&(i.emissiveMap=n(t.emissiveMap)),void 0!==t.emissiveIntensity&&(i.emissiveIntensity=t.emissiveIntensity),void 0!==t.specularMap&&(i.specularMap=n(t.specularMap)),void 0!==t.specularIntensityMap&&(i.specularIntensityMap=n(t.specularIntensityMap)),void 0!==t.specularColorMap&&(i.specularColorMap=n(t.specularColorMap)),void 0!==t.envMap&&(i.envMap=n(t.envMap)),void 0!==t.envMapIntensity&&(i.envMapIntensity=t.envMapIntensity),void 0!==t.reflectivity&&(i.reflectivity=t.reflectivity),void 0!==t.refractionRatio&&(i.refractionRatio=t.refractionRatio),void 0!==t.lightMap&&(i.lightMap=n(t.lightMap)),void 0!==t.lightMapIntensity&&(i.lightMapIntensity=t.lightMapIntensity),void 0!==t.aoMap&&(i.aoMap=n(t.aoMap)),void 0!==t.aoMapIntensity&&(i.aoMapIntensity=t.aoMapIntensity),void 0!==t.gradientMap&&(i.gradientMap=n(t.gradientMap)),void 0!==t.clearcoatMap&&(i.clearcoatMap=n(t.clearcoatMap)),void 0!==t.clearcoatRoughnessMap&&(i.clearcoatRoughnessMap=n(t.clearcoatRoughnessMap)),void 0!==t.clearcoatNormalMap&&(i.clearcoatNormalMap=n(t.clearcoatNormalMap)),void 0!==t.clearcoatNormalScale&&(i.clearcoatNormalScale=(new Kn).fromArray(t.clearcoatNormalScale)),void 0!==t.iridescenceMap&&(i.iridescenceMap=n(t.iridescenceMap)),void 0!==t.iridescenceThicknessMap&&(i.iridescenceThicknessMap=n(t.iridescenceThicknessMap)),void 0!==t.transmissionMap&&(i.transmissionMap=n(t.transmissionMap)),void 0!==t.thicknessMap&&(i.thicknessMap=n(t.thicknessMap)),void 0!==t.anisotropyMap&&(i.anisotropyMap=n(t.anisotropyMap)),void 0!==t.sheenColorMap&&(i.sheenColorMap=n(t.sheenColorMap)),void 0!==t.sheenRoughnessMap&&(i.sheenRoughnessMap=n(t.sheenRoughnessMap)),i}setTextures(t){return this.textures=t,this}static createMaterialFromType(t){return new{ShadowMaterial:id,SpriteMaterial:rc,RawShaderMaterial:rd,ShaderMaterial:Ys,PointsMaterial:Mh,MeshPhysicalMaterial:ad,MeshStandardMaterial:sd,MeshPhongMaterial:od,MeshToonMaterial:ld,MeshNormalMaterial:cd,MeshLambertMaterial:hd,MeshDepthMaterial:Ol,MeshDistanceMaterial:Fl,MeshBasicMaterial:Kr,MeshMatcapMaterial:ud,LineDashedMaterial:dd,LineBasicMaterial:hh,Material:Jr}[t]}}class dp{static decodeText(t){if("undefined"!=typeof TextDecoder)return(new TextDecoder).decode(t);let e="";for(let n=0,i=t.length;n0){const n=new Nd(e);r=new kd(n),r.setCrossOrigin(this.crossOrigin);for(let e=0,n=t.length;e0){i=new kd(this.manager),i.setCrossOrigin(this.crossOrigin);for(let e=0,i=t.length;e{const e=new Ui;e.min.fromArray(t.boxMin),e.max.fromArray(t.boxMax);const n=new Ki;return n.radius=t.sphereRadius,n.center.fromArray(t.sphereCenter),{boxInitialized:t.boxInitialized,box:e,sphereInitialized:t.sphereInitialized,sphere:n}})),s._maxGeometryCount=t.maxGeometryCount,s._maxVertexCount=t.maxVertexCount,s._maxIndexCount=t.maxIndexCount,s._geometryInitialized=t.geometryInitialized,s._geometryCount=t.geometryCount,s._matricesTexture=h(t.matricesTexture.uuid);break;case"LOD":s=new Sc;break;case"Line":s=new gh(l(t.geometry),c(t.material));break;case"LineLoop":s=new yh(l(t.geometry),c(t.material));break;case"LineSegments":s=new xh(l(t.geometry),c(t.material));break;case"PointCloud":case"Points":s=new wh(l(t.geometry),c(t.material));break;case"Sprite":s=new vc(c(t.material));break;case"Group":s=new Gl;break;case"Bone":s=new Uc;break;default:s=new Lr}if(s.uuid=t.uuid,void 0!==t.name&&(s.name=t.name),void 0!==t.matrix?(s.matrix.fromArray(t.matrix),void 0!==t.matrixAutoUpdate&&(s.matrixAutoUpdate=t.matrixAutoUpdate),s.matrixAutoUpdate&&s.matrix.decompose(s.position,s.quaternion,s.scale)):(void 0!==t.position&&s.position.fromArray(t.position),void 0!==t.rotation&&s.rotation.fromArray(t.rotation),void 0!==t.quaternion&&s.quaternion.fromArray(t.quaternion),void 0!==t.scale&&s.scale.fromArray(t.scale)),void 0!==t.up&&s.up.fromArray(t.up),void 0!==t.castShadow&&(s.castShadow=t.castShadow),void 0!==t.receiveShadow&&(s.receiveShadow=t.receiveShadow),t.shadow&&(void 0!==t.shadow.bias&&(s.shadow.bias=t.shadow.bias),void 0!==t.shadow.normalBias&&(s.shadow.normalBias=t.shadow.normalBias),void 0!==t.shadow.radius&&(s.shadow.radius=t.shadow.radius),void 0!==t.shadow.mapSize&&s.shadow.mapSize.fromArray(t.shadow.mapSize),void 0!==t.shadow.camera&&(s.shadow.camera=this.parseObject(t.shadow.camera))),void 0!==t.visible&&(s.visible=t.visible),void 0!==t.frustumCulled&&(s.frustumCulled=t.frustumCulled),void 0!==t.renderOrder&&(s.renderOrder=t.renderOrder),void 0!==t.userData&&(s.userData=t.userData),void 0!==t.layers&&(s.layers.mask=t.layers),void 0!==t.children){const a=t.children;for(let t=0;t{e&&e(n),r.manager.itemEnd(t)})).catch((t=>{i&&i(t)})):(setTimeout((function(){e&&e(s),r.manager.itemEnd(t)}),0),s);const a={};a.credentials="anonymous"===this.crossOrigin?"same-origin":"include",a.headers=this.requestHeader;const o=fetch(t,a).then((function(t){return t.blob()})).then((function(t){return createImageBitmap(t,Object.assign(r.options,{colorSpaceConversion:"none"}))})).then((function(n){return Ud.add(t,n),e&&e(n),r.manager.itemEnd(t),n})).catch((function(e){i&&i(e),Ud.remove(t),r.manager.itemError(t),r.manager.itemEnd(t)}));Ud.add(t,o),r.manager.itemStart(t)}}let yp;class Mp{static getContext(){return void 0===yp&&(yp=new(window.AudioContext||window.webkitAudioContext)),yp}static setContext(t){yp=t}}class Sp extends Od{constructor(t){super(t)}load(t,e,n,i){const r=this,s=new zd(this.manager);function a(e){i?i(e):console.error(e),r.manager.itemError(t)}s.setResponseType("arraybuffer"),s.setPath(this.path),s.setRequestHeader(this.requestHeader),s.setWithCredentials(this.withCredentials),s.load(t,(function(t){try{const n=t.slice(0);Mp.getContext().decodeAudioData(n,(function(t){e(t)})).catch(a)}catch(t){a(t)}}),n,i)}}const bp=new ar,Ep=new ar,Tp=new ar;class wp{constructor(){this.type="StereoCamera",this.aspect=1,this.eyeSep=.064,this.cameraL=new Qs,this.cameraL.layers.enable(1),this.cameraL.matrixAutoUpdate=!1,this.cameraR=new Qs,this.cameraR.layers.enable(2),this.cameraR.matrixAutoUpdate=!1,this._cache={focus:null,fov:null,aspect:null,near:null,far:null,zoom:null,eyeSep:null}}update(t){const e=this._cache;if(e.focus!==t.focus||e.fov!==t.fov||e.aspect!==t.aspect*this.aspect||e.near!==t.near||e.far!==t.far||e.zoom!==t.zoom||e.eyeSep!==this.eyeSep){e.focus=t.focus,e.fov=t.fov,e.aspect=t.aspect*this.aspect,e.near=t.near,e.far=t.far,e.zoom=t.zoom,e.eyeSep=this.eyeSep,Tp.copy(t.projectionMatrix);const n=e.eyeSep/2,i=n*e.near/e.focus,r=e.near*Math.tan(Hn*e.fov*.5)/e.zoom;let s,a;Ep.elements[12]=-n,bp.elements[12]=n,s=-r*e.aspect+i,a=r*e.aspect+i,Tp.elements[0]=2*e.near/(a-s),Tp.elements[8]=(a+s)/(a-s),this.cameraL.projectionMatrix.copy(Tp),s=-r*e.aspect-i,a=r*e.aspect-i,Tp.elements[0]=2*e.near/(a-s),Tp.elements[8]=(a+s)/(a-s),this.cameraR.projectionMatrix.copy(Tp)}this.cameraL.matrixWorld.copy(t.matrixWorld).multiply(Ep),this.cameraR.matrixWorld.copy(t.matrixWorld).multiply(bp)}}class Ap{constructor(t=!0){this.autoStart=t,this.startTime=0,this.oldTime=0,this.elapsedTime=0,this.running=!1}start(){this.startTime=Rp(),this.oldTime=this.startTime,this.elapsedTime=0,this.running=!0}stop(){this.getElapsedTime(),this.running=!1,this.autoStart=!1}getElapsedTime(){return this.getDelta(),this.elapsedTime}getDelta(){let t=0;if(this.autoStart&&!this.running)return this.start(),0;if(this.running){const e=Rp();t=(e-this.oldTime)/1e3,this.oldTime=e,this.elapsedTime+=t}return t}}function Rp(){return("undefined"==typeof performance?Date:performance).now()}const Cp=new Pi,Pp=new Ci,Lp=new Pi,Ip=new Pi;class Up extends Lr{constructor(){super(),this.type="AudioListener",this.context=Mp.getContext(),this.gain=this.context.createGain(),this.gain.connect(this.context.destination),this.filter=null,this.timeDelta=0,this._clock=new Ap}getInput(){return this.gain}removeFilter(){return null!==this.filter&&(this.gain.disconnect(this.filter),this.filter.disconnect(this.context.destination),this.gain.connect(this.context.destination),this.filter=null),this}getFilter(){return this.filter}setFilter(t){return null!==this.filter?(this.gain.disconnect(this.filter),this.filter.disconnect(this.context.destination)):this.gain.disconnect(this.context.destination),this.filter=t,this.gain.connect(this.filter),this.filter.connect(this.context.destination),this}getMasterVolume(){return this.gain.gain.value}setMasterVolume(t){return this.gain.gain.setTargetAtTime(t,this.context.currentTime,.01),this}updateMatrixWorld(t){super.updateMatrixWorld(t);const e=this.context.listener,n=this.up;if(this.timeDelta=this._clock.getDelta(),this.matrixWorld.decompose(Cp,Pp,Lp),Ip.set(0,0,-1).applyQuaternion(Pp),e.positionX){const t=this.context.currentTime+this.timeDelta;e.positionX.linearRampToValueAtTime(Cp.x,t),e.positionY.linearRampToValueAtTime(Cp.y,t),e.positionZ.linearRampToValueAtTime(Cp.z,t),e.forwardX.linearRampToValueAtTime(Ip.x,t),e.forwardY.linearRampToValueAtTime(Ip.y,t),e.forwardZ.linearRampToValueAtTime(Ip.z,t),e.upX.linearRampToValueAtTime(n.x,t),e.upY.linearRampToValueAtTime(n.y,t),e.upZ.linearRampToValueAtTime(n.z,t)}else e.setPosition(Cp.x,Cp.y,Cp.z),e.setOrientation(Ip.x,Ip.y,Ip.z,n.x,n.y,n.z)}}class Np extends Lr{constructor(t){super(),this.type="Audio",this.listener=t,this.context=t.context,this.gain=this.context.createGain(),this.gain.connect(t.getInput()),this.autoplay=!1,this.buffer=null,this.detune=0,this.loop=!1,this.loopStart=0,this.loopEnd=0,this.offset=0,this.duration=void 0,this.playbackRate=1,this.isPlaying=!1,this.hasPlaybackControl=!0,this.source=null,this.sourceType="empty",this._startedAt=0,this._progress=0,this._connected=!1,this.filters=[]}getOutput(){return this.gain}setNodeSource(t){return this.hasPlaybackControl=!1,this.sourceType="audioNode",this.source=t,this.connect(),this}setMediaElementSource(t){return this.hasPlaybackControl=!1,this.sourceType="mediaNode",this.source=this.context.createMediaElementSource(t),this.connect(),this}setMediaStreamSource(t){return this.hasPlaybackControl=!1,this.sourceType="mediaStreamNode",this.source=this.context.createMediaStreamSource(t),this.connect(),this}setBuffer(t){return this.buffer=t,this.sourceType="buffer",this.autoplay&&this.play(),this}play(t=0){if(!0===this.isPlaying)return void console.warn("THREE.Audio: Audio is already playing.");if(!1===this.hasPlaybackControl)return void console.warn("THREE.Audio: this Audio has no playback control.");this._startedAt=this.context.currentTime+t;const e=this.context.createBufferSource();return e.buffer=this.buffer,e.loop=this.loop,e.loopStart=this.loopStart,e.loopEnd=this.loopEnd,e.onended=this.onEnded.bind(this),e.start(this._startedAt,this._progress+this.offset,this.duration),this.isPlaying=!0,this.source=e,this.setDetune(this.detune),this.setPlaybackRate(this.playbackRate),this.connect()}pause(){if(!1!==this.hasPlaybackControl)return!0===this.isPlaying&&(this._progress+=Math.max(this.context.currentTime-this._startedAt,0)*this.playbackRate,!0===this.loop&&(this._progress=this._progress%(this.duration||this.buffer.duration)),this.source.stop(),this.source.onended=null,this.isPlaying=!1),this;console.warn("THREE.Audio: this Audio has no playback control.")}stop(){if(!1!==this.hasPlaybackControl)return this._progress=0,null!==this.source&&(this.source.stop(),this.source.onended=null),this.isPlaying=!1,this;console.warn("THREE.Audio: this Audio has no playback control.")}connect(){if(this.filters.length>0){this.source.connect(this.filters[0]);for(let t=1,e=this.filters.length;t0){this.source.disconnect(this.filters[0]);for(let t=1,e=this.filters.length;t0&&this._mixBufferRegionAdditive(n,i,this._addIndex*e,1,e);for(let t=e,r=e+e;t!==r;++t)if(n[t]!==n[t+e]){a.setValue(n,i);break}}saveOriginalState(){const t=this.binding,e=this.buffer,n=this.valueSize,i=n*this._origIndex;t.getValue(e,i);for(let t=n,r=i;t!==r;++t)e[t]=e[i+t%n];this._setIdentity(),this.cumulativeWeight=0,this.cumulativeWeightAdditive=0}restoreOriginalState(){const t=3*this.valueSize;this.binding.setValue(this.buffer,t)}_setAdditiveIdentityNumeric(){const t=this._addIndex*this.valueSize,e=t+this.valueSize;for(let n=t;n=.5)for(let i=0;i!==r;++i)t[e+i]=t[n+i]}_slerp(t,e,n,i){Ci.slerpFlat(t,e,t,e,t,n,i)}_slerpAdditive(t,e,n,i,r){const s=this._workIndex*r;Ci.multiplyQuaternionsFlat(t,s,t,e,t,n),Ci.slerpFlat(t,e,t,e,t,s,i)}_lerp(t,e,n,i,r){const s=1-i;for(let a=0;a!==r;++a){const r=e+a;t[r]=t[r]*s+t[n+a]*i}}_lerpAdditive(t,e,n,i,r){for(let s=0;s!==r;++s){const r=e+s;t[r]=t[r]+t[n+s]*i}}}const kp="\\[\\]\\.:\\/",Gp=new RegExp("["+kp+"]","g"),Wp="[^"+kp+"]",Xp="[^"+kp.replace("\\.","")+"]",jp=new RegExp("^"+/((?:WC+[\/:])*)/.source.replace("WC",Wp)+/(WCOD+)?/.source.replace("WCOD",Xp)+/(?:\.(WC+)(?:\[(.+)\])?)?/.source.replace("WC",Wp)+/\.(WC+)(?:\[(.+)\])?/.source.replace("WC",Wp)+"$"),qp=["material","materials","bones","map"];class Yp{constructor(t,e,n){this.path=e,this.parsedPath=n||Yp.parseTrackName(e),this.node=Yp.findNode(t,this.parsedPath.nodeName),this.rootNode=t,this.getValue=this._getValue_unbound,this.setValue=this._setValue_unbound}static create(t,e,n){return t&&t.isAnimationObjectGroup?new Yp.Composite(t,e,n):new Yp(t,e,n)}static sanitizeNodeName(t){return t.replace(/\s/g,"_").replace(Gp,"")}static parseTrackName(t){const e=jp.exec(t);if(null===e)throw new Error("PropertyBinding: Cannot parse trackName: "+t);const n={nodeName:e[2],objectName:e[3],objectIndex:e[4],propertyName:e[5],propertyIndex:e[6]},i=n.nodeName&&n.nodeName.lastIndexOf(".");if(void 0!==i&&-1!==i){const t=n.nodeName.substring(i+1);-1!==qp.indexOf(t)&&(n.nodeName=n.nodeName.substring(0,i),n.objectName=t)}if(null===n.propertyName||0===n.propertyName.length)throw new Error("PropertyBinding: can not parse propertyName from trackName: "+t);return n}static findNode(t,e){if(void 0===e||""===e||"."===e||-1===e||e===t.name||e===t.uuid)return t;if(t.skeleton){const n=t.skeleton.getBoneByName(e);if(void 0!==n)return n}if(t.children){const n=function(t){for(let i=0;i=r){const s=r++,c=t[s];e[c.uuid]=l,t[l]=c,e[o]=s,t[s]=a;for(let t=0,e=i;t!==e;++t){const e=n[t],i=e[s],r=e[l];e[l]=i,e[s]=r}}}this.nCachedObjects_=r}uncache(){const t=this._objects,e=this._indicesByUUID,n=this._bindings,i=n.length;let r=this.nCachedObjects_,s=t.length;for(let a=0,o=arguments.length;a!==o;++a){const o=arguments[a].uuid,l=e[o];if(void 0!==l)if(delete e[o],l0&&(e[a.uuid]=l),t[l]=a,t.pop();for(let t=0,e=i;t!==e;++t){const e=n[t];e[l]=e[r],e.pop()}}}this.nCachedObjects_=r}subscribe_(t,e){const n=this._bindingsIndicesByPath;let i=n[t];const r=this._bindings;if(void 0!==i)return r[i];const s=this._paths,a=this._parsedPaths,o=this._objects,l=o.length,c=this.nCachedObjects_,h=new Array(l);i=r.length,n[t]=i,s.push(t),a.push(e),r.push(h);for(let n=c,i=o.length;n!==i;++n){const i=o[n];h[n]=new Yp(i,t,e)}return h}unsubscribe_(t){const e=this._bindingsIndicesByPath,n=e[t];if(void 0!==n){const i=this._paths,r=this._parsedPaths,s=this._bindings,a=s.length-1,o=s[a];e[t[a]]=n,s[n]=o,s.pop(),r[n]=r[a],r.pop(),i[n]=i[a],i.pop()}}}class Jp{constructor(t,e,n=null,i=e.blendMode){this._mixer=t,this._clip=e,this._localRoot=n,this.blendMode=i;const r=e.tracks,s=r.length,a=new Array(s),o={endingStart:Le,endingEnd:Le};for(let t=0;t!==s;++t){const e=r[t].createInterpolant(null);a[t]=e,e.settings=o}this._interpolantSettings=o,this._interpolants=a,this._propertyBindings=new Array(s),this._cacheIndex=null,this._byClipCacheIndex=null,this._timeScaleInterpolant=null,this._weightInterpolant=null,this.loop=2201,this._loopCount=-1,this._startTime=null,this.time=0,this.timeScale=1,this._effectiveTimeScale=1,this.weight=1,this._effectiveWeight=1,this.repetitions=1/0,this.paused=!1,this.enabled=!0,this.clampWhenFinished=!1,this.zeroSlopeAtStart=!0,this.zeroSlopeAtEnd=!0}play(){return this._mixer._activateAction(this),this}stop(){return this._mixer._deactivateAction(this),this.reset()}reset(){return this.paused=!1,this.enabled=!0,this.time=0,this._loopCount=-1,this._startTime=null,this.stopFading().stopWarping()}isRunning(){return this.enabled&&!this.paused&&0!==this.timeScale&&null===this._startTime&&this._mixer._isActiveAction(this)}isScheduled(){return this._mixer._isActiveAction(this)}startAt(t){return this._startTime=t,this}setLoop(t,e){return this.loop=t,this.repetitions=e,this}setEffectiveWeight(t){return this.weight=t,this._effectiveWeight=this.enabled?t:0,this.stopFading()}getEffectiveWeight(){return this._effectiveWeight}fadeIn(t){return this._scheduleFading(t,0,1)}fadeOut(t){return this._scheduleFading(t,1,0)}crossFadeFrom(t,e,n){if(t.fadeOut(e),this.fadeIn(e),n){const n=this._clip.duration,i=t._clip.duration,r=i/n,s=n/i;t.warp(1,r,e),this.warp(s,1,e)}return this}crossFadeTo(t,e,n){return t.crossFadeFrom(this,e,n)}stopFading(){const t=this._weightInterpolant;return null!==t&&(this._weightInterpolant=null,this._mixer._takeBackControlInterpolant(t)),this}setEffectiveTimeScale(t){return this.timeScale=t,this._effectiveTimeScale=this.paused?0:t,this.stopWarping()}getEffectiveTimeScale(){return this._effectiveTimeScale}setDuration(t){return this.timeScale=this._clip.duration/t,this.stopWarping()}syncWith(t){return this.time=t.time,this.timeScale=t.timeScale,this.stopWarping()}halt(t){return this.warp(this._effectiveTimeScale,0,t)}warp(t,e,n){const i=this._mixer,r=i.time,s=this.timeScale;let a=this._timeScaleInterpolant;null===a&&(a=i._lendControlInterpolant(),this._timeScaleInterpolant=a);const o=a.parameterPositions,l=a.sampleValues;return o[0]=r,o[1]=r+n,l[0]=t/s,l[1]=e/s,this}stopWarping(){const t=this._timeScaleInterpolant;return null!==t&&(this._timeScaleInterpolant=null,this._mixer._takeBackControlInterpolant(t)),this}getMixer(){return this._mixer}getClip(){return this._clip}getRoot(){return this._localRoot||this._mixer._root}_update(t,e,n,i){if(!this.enabled)return void this._updateWeight(t);const r=this._startTime;if(null!==r){const i=(t-r)*n;i<0||0===n?e=0:(this._startTime=null,e=n*i)}e*=this._updateTimeScale(t);const s=this._updateTime(e),a=this._updateWeight(t);if(a>0){const t=this._interpolants,e=this._propertyBindings;if(this.blendMode===De)for(let n=0,i=t.length;n!==i;++n)t[n].evaluate(s),e[n].accumulateAdditive(a);else for(let n=0,r=t.length;n!==r;++n)t[n].evaluate(s),e[n].accumulate(i,a)}}_updateWeight(t){let e=0;if(this.enabled){e=this.weight;const n=this._weightInterpolant;if(null!==n){const i=n.evaluate(t)[0];e*=i,t>n.parameterPositions[1]&&(this.stopFading(),0===i&&(this.enabled=!1))}}return this._effectiveWeight=e,e}_updateTimeScale(t){let e=0;if(!this.paused){e=this.timeScale;const n=this._timeScaleInterpolant;if(null!==n){e*=n.evaluate(t)[0],t>n.parameterPositions[1]&&(this.stopWarping(),0===e?this.paused=!0:this.timeScale=e)}}return this._effectiveTimeScale=e,e}_updateTime(t){const e=this._clip.duration,n=this.loop;let i=this.time+t,r=this._loopCount;const s=2202===n;if(0===t)return-1===r?i:s&&1==(1&r)?e-i:i;if(2200===n){-1===r&&(this._loopCount=0,this._setEndings(!0,!0,!1));t:{if(i>=e)i=e;else{if(!(i<0)){this.time=i;break t}i=0}this.clampWhenFinished?this.paused=!0:this.enabled=!1,this.time=i,this._mixer.dispatchEvent({type:"finished",action:this,direction:t<0?-1:1})}}else{if(-1===r&&(t>=0?(r=0,this._setEndings(!0,0===this.repetitions,s)):this._setEndings(0===this.repetitions,!0,s)),i>=e||i<0){const n=Math.floor(i/e);i-=e*n,r+=Math.abs(n);const a=this.repetitions-r;if(a<=0)this.clampWhenFinished?this.paused=!0:this.enabled=!1,i=t>0?e:0,this.time=i,this._mixer.dispatchEvent({type:"finished",action:this,direction:t>0?1:-1});else{if(1===a){const e=t<0;this._setEndings(e,!e,s)}else this._setEndings(!1,!1,s);this._loopCount=r,this.time=i,this._mixer.dispatchEvent({type:"loop",action:this,loopDelta:n})}}else this.time=i;if(s&&1==(1&r))return e-i}return i}_setEndings(t,e,n){const i=this._interpolantSettings;n?(i.endingStart=Ie,i.endingEnd=Ie):(i.endingStart=t?this.zeroSlopeAtStart?Ie:Le:Ue,i.endingEnd=e?this.zeroSlopeAtEnd?Ie:Le:Ue)}_scheduleFading(t,e,n){const i=this._mixer,r=i.time;let s=this._weightInterpolant;null===s&&(s=i._lendControlInterpolant(),this._weightInterpolant=s);const a=s.parameterPositions,o=s.sampleValues;return a[0]=r,o[0]=e,a[1]=r+t,o[1]=n,this}}const Kp=new Float32Array(1);class $p extends Fn{constructor(t){super(),this._root=t,this._initMemoryManager(),this._accuIndex=0,this.time=0,this.timeScale=1}_bindAction(t,e){const n=t._localRoot||this._root,i=t._clip.tracks,r=i.length,s=t._propertyBindings,a=t._interpolants,o=n.uuid,l=this._bindingsByRootAndName;let c=l[o];void 0===c&&(c={},l[o]=c);for(let t=0;t!==r;++t){const r=i[t],l=r.name;let h=c[l];if(void 0!==h)++h.referenceCount,s[t]=h;else{if(h=s[t],void 0!==h){null===h._cacheIndex&&(++h.referenceCount,this._addInactiveBinding(h,o,l));continue}const i=e&&e._propertyBindings[t].binding.parsedPath;h=new Vp(Yp.create(n,l,i),r.ValueTypeName,r.getValueSize()),++h.referenceCount,this._addInactiveBinding(h,o,l),s[t]=h}a[t].resultBuffer=h.buffer}}_activateAction(t){if(!this._isActiveAction(t)){if(null===t._cacheIndex){const e=(t._localRoot||this._root).uuid,n=t._clip.uuid,i=this._actionsByClip[n];this._bindAction(t,i&&i.knownActions[0]),this._addInactiveAction(t,n,e)}const e=t._propertyBindings;for(let t=0,n=e.length;t!==n;++t){const n=e[t];0==n.useCount++&&(this._lendBinding(n),n.saveOriginalState())}this._lendAction(t)}}_deactivateAction(t){if(this._isActiveAction(t)){const e=t._propertyBindings;for(let t=0,n=e.length;t!==n;++t){const n=e[t];0==--n.useCount&&(n.restoreOriginalState(),this._takeBackBinding(n))}this._takeBackAction(t)}}_initMemoryManager(){this._actions=[],this._nActiveActions=0,this._actionsByClip={},this._bindings=[],this._nActiveBindings=0,this._bindingsByRootAndName={},this._controlInterpolants=[],this._nActiveControlInterpolants=0;const t=this;this.stats={actions:{get total(){return t._actions.length},get inUse(){return t._nActiveActions}},bindings:{get total(){return t._bindings.length},get inUse(){return t._nActiveBindings}},controlInterpolants:{get total(){return t._controlInterpolants.length},get inUse(){return t._nActiveControlInterpolants}}}}_isActiveAction(t){const e=t._cacheIndex;return null!==e&&e=0;--e)t[e].stop();return this}update(t){t*=this.timeScale;const e=this._actions,n=this._nActiveActions,i=this.time+=t,r=Math.sign(t),s=this._accuIndex^=1;for(let a=0;a!==n;++a){e[a]._update(i,t,r,s)}const a=this._bindings,o=this._nActiveBindings;for(let t=0;t!==o;++t)a[t].apply(s);return this}setTime(t){this.time=0;for(let t=0;tthis.max.x||t.ythis.max.y)}containsBox(t){return this.min.x<=t.min.x&&t.max.x<=this.max.x&&this.min.y<=t.min.y&&t.max.y<=this.max.y}getParameter(t,e){return e.set((t.x-this.min.x)/(this.max.x-this.min.x),(t.y-this.min.y)/(this.max.y-this.min.y))}intersectsBox(t){return!(t.max.xthis.max.x||t.max.ythis.max.y)}clampPoint(t,e){return e.copy(t).clamp(this.min,this.max)}distanceToPoint(t){return this.clampPoint(t,cm).distanceTo(t)}intersect(t){return this.min.max(t.min),this.max.min(t.max),this.isEmpty()&&this.makeEmpty(),this}union(t){return this.min.min(t.min),this.max.max(t.max),this}translate(t){return this.min.add(t),this.max.add(t),this}equals(t){return t.min.equals(this.min)&&t.max.equals(this.max)}}const um=new Pi,dm=new Pi;class pm{constructor(t=new Pi,e=new Pi){this.start=t,this.end=e}set(t,e){return this.start.copy(t),this.end.copy(e),this}copy(t){return this.start.copy(t.start),this.end.copy(t.end),this}getCenter(t){return t.addVectors(this.start,this.end).multiplyScalar(.5)}delta(t){return t.subVectors(this.end,this.start)}distanceSq(){return this.start.distanceToSquared(this.end)}distance(){return this.start.distanceTo(this.end)}at(t,e){return this.delta(e).multiplyScalar(t).add(this.start)}closestPointToPointParameter(t,e){um.subVectors(t,this.start),dm.subVectors(this.end,this.start);const n=dm.dot(dm);let i=dm.dot(um)/n;return e&&(i=Gn(i,0,1)),i}closestPointToPoint(t,e,n){const i=this.closestPointToPointParameter(t,e);return this.delta(n).multiplyScalar(i).add(this.start)}applyMatrix4(t){return this.start.applyMatrix4(t),this.end.applyMatrix4(t),this}equals(t){return t.start.equals(this.start)&&t.end.equals(this.end)}clone(){return(new this.constructor).copy(this)}}const mm=new Pi;class fm extends Lr{constructor(t,e){super(),this.light=t,this.matrix=t.matrixWorld,this.matrixAutoUpdate=!1,this.color=e,this.type="SpotLightHelper";const n=new bs,i=[0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,-1,0,1,0,0,0,0,1,1,0,0,0,0,-1,1];for(let t=0,e=1,n=32;t1)for(let n=0;n.99999)this.quaternion.set(0,0,0,1);else if(t.y<-.99999)this.quaternion.set(1,0,0,0);else{Hm.set(t.z,0,-t.x).normalize();const e=Math.acos(t.y);this.quaternion.setFromAxisAngle(Hm,e)}}setLength(t,e=.2*t,n=.2*e){this.line.scale.set(1,Math.max(1e-4,t-e),1),this.line.updateMatrix(),this.cone.scale.set(n,e,n),this.cone.position.y=t,this.cone.updateMatrix()}setColor(t){this.line.material.color.set(t),this.cone.material.color.set(t)}copy(t){return super.copy(t,!1),this.line.copy(t.line),this.cone.copy(t.cone),this}dispose(){this.line.geometry.dispose(),this.line.material.dispose(),this.cone.geometry.dispose(),this.cone.material.dispose()}}class Wm extends xh{constructor(t=1){const e=[0,0,0,t,0,0,0,0,0,0,t,0,0,0,0,0,0,t],n=new bs;n.setAttribute("position",new ms(e,3)),n.setAttribute("color",new ms([1,0,0,1,.6,0,0,1,0,.6,1,0,0,0,1,0,.6,1],3));super(n,new hh({vertexColors:!0,toneMapped:!1})),this.type="AxesHelper"}setColors(t,e,n){const i=new qr,r=this.geometry.attributes.color.array;return i.set(t),i.toArray(r,0),i.toArray(r,3),i.set(e),i.toArray(r,6),i.toArray(r,9),i.set(n),i.toArray(r,12),i.toArray(r,15),this.geometry.attributes.color.needsUpdate=!0,this}dispose(){this.geometry.dispose(),this.material.dispose()}}class Xm{constructor(){this.type="ShapePath",this.color=new qr,this.subPaths=[],this.currentPath=null}moveTo(t,e){return this.currentPath=new eu,this.subPaths.push(this.currentPath),this.currentPath.moveTo(t,e),this}lineTo(t,e){return this.currentPath.lineTo(t,e),this}quadraticCurveTo(t,e,n,i){return this.currentPath.quadraticCurveTo(t,e,n,i),this}bezierCurveTo(t,e,n,i,r,s){return this.currentPath.bezierCurveTo(t,e,n,i,r,s),this}splineThru(t){return this.currentPath.splineThru(t),this}toShapes(t){function e(t,e){const n=e.length;let i=!1;for(let r=n-1,s=0;sNumber.EPSILON){if(l<0&&(n=e[s],o=-o,a=e[r],l=-l),t.ya.y)continue;if(t.y===n.y){if(t.x===n.x)return!0}else{const e=l*(t.x-n.x)-o*(t.y-n.y);if(0===e)return!0;if(e<0)continue;i=!i}}else{if(t.y!==n.y)continue;if(a.x<=t.x&&t.x<=n.x||n.x<=t.x&&t.x<=a.x)return!0}}return i}const n=Hu.isClockWise,i=this.subPaths;if(0===i.length)return[];let r,s,a;const o=[];if(1===i.length)return s=i[0],a=new mu,a.curves=s.curves,o.push(a),o;let l=!n(i[0].getPoints());l=t?!l:l;const c=[],h=[];let u,d,p=[],m=0;h[m]=void 0,p[m]=[];for(let e=0,a=i.length;e1){let t=!1,n=0;for(let t=0,e=h.length;t0&&!1===t&&(p=c)}for(let t=0,e=h.length;t 0 ) { + + const object = _intersections[ 0 ].object; + + _plane.setFromNormalAndCoplanarPoint( _camera.getWorldDirection( _plane.normal ), _worldPosition.setFromMatrixPosition( object.matrixWorld ) ); + + if ( _hovered !== object && _hovered !== null ) { + + scope.dispatchEvent( { type: 'hoveroff', object: _hovered } ); + + _domElement.style.cursor = 'auto'; + _hovered = null; + + } + + if ( _hovered !== object ) { + + scope.dispatchEvent( { type: 'hoveron', object: object } ); + + _domElement.style.cursor = 'pointer'; + _hovered = object; + + } + + } else { + + if ( _hovered !== null ) { + + scope.dispatchEvent( { type: 'hoveroff', object: _hovered } ); + + _domElement.style.cursor = 'auto'; + _hovered = null; + + } + + } + + } + } + + function onPointerDown( event ) { + + if ( scope.enabled === false ) return; + + updatePointer( event ); + + _intersections.length = 0; + + _raycaster.setFromCamera( _pointer, _camera ); + _raycaster.intersectObjects( _objects, scope.recursive, _intersections ); + + if ( _intersections.length > 0 ) { + + _selected = _intersections[ 0 ].object; + + _plane.setFromNormalAndCoplanarPoint( _camera.getWorldDirection( _plane.normal ), _worldPosition.setFromMatrixPosition( _selected.matrixWorld ) ); + + if ( _raycaster.ray.intersectPlane( _plane, _intersection ) ) { + + _up.set(0,1,0).applyQuaternion(_camera.quaternion).normalize(); + _horizen.set(1,0,0).applyQuaternion(_camera.quaternion).normalize(); + _lookAt.set(0,0,-1).applyQuaternion(_camera.quaternion).normalize(); + + } + + _domElement.style.cursor = 'move'; + + scope.dispatchEvent( { type: 'rotatestart', object: _selected } ); + + } + } + + function onPointerCancel() { + if ( scope.enabled === false ) return; + + if ( _selected ) { + + scope.dispatchEvent( { type: 'rotateend', object: _selected } ); + + _selected = null; + + } + + _domElement.style.cursor = _hovered ? 'pointer' : 'auto'; + + } + + function updatePointer( event ) { + + const rect = _domElement.getBoundingClientRect(); + + _pointer.x = ( event.clientX - rect.left ) / rect.width * 2 - 1; + _pointer.y = - ( event.clientY - rect.top ) / rect.height * 2 + 1; + + } + + activate(); + + // API + + this.enabled = true; + this.recursive = true; + + this.activate = activate; + this.deactivate = deactivate; + this.dispose = dispose; + this.getObjects = getObjects; + this.getRaycaster = getRaycaster; + } +} + +export {RotateControls}; \ No newline at end of file